From chaoyi.chen at rock-chips.com  Mon Dec  1 00:10:29 2025
From: chaoyi.chen at rock-chips.com (Chaoyi Chen)
Date: Mon, 1 Dec 2025 16:10:29 +0800
Subject: [PATCH v2 1/2] dt-bindings: iommu: rockchip: Add support for
 multiple interface clocks
In-Reply-To: <96958186-0e46-4606-ae36-239112eb31ea@kernel.org>
References: <20251128071322.92-1-kernel@airkyi.com>
 <20251128071322.92-2-kernel@airkyi.com>
 <96958186-0e46-4606-ae36-239112eb31ea@kernel.org>
Message-ID: <98a847f7-0880-4e5b-a946-26dc81fde5d2@rock-chips.com>

Hi Krzysztof,

On 12/1/2025 3:55 PM, Krzysztof Kozlowski wrote:
> On 28/11/2025 08:13, Chaoyi Chen wrote:
>> From: Chaoyi Chen <chaoyi.chen at rock-chips.com>
>>
>> The iommu found on RK3576 NPU and RK3576 RKVDEC have 4 clock instead of
>> 2 clock. Their clock names might differ, but I don't think that matters
>> much.
>>
>> Add support for them.
>>
>> Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
>> ---
>>
>> Changes in v2:
>> - Rewrite dt binding.
>>
>>  .../bindings/iommu/rockchip,iommu.yaml        | 52 ++++++++++++++++---
>>  1 file changed, 46 insertions(+), 6 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/iommu/rockchip,iommu.yaml b/Documentation/devicetree/bindings/iommu/rockchip,iommu.yaml
>> index 6ce41d11ff5e..dfa5e25476d9 100644
>> --- a/Documentation/devicetree/bindings/iommu/rockchip,iommu.yaml
>> +++ b/Documentation/devicetree/bindings/iommu/rockchip,iommu.yaml
>> @@ -27,6 +27,8 @@ properties:
>>            - enum:
>>                - rockchip,rk3576-iommu
>>                - rockchip,rk3588-iommu
>> +              - rockchip,rk3576-npu-iommu
>> +              - rockchip,rk3576-rkvdec-iommu
>>            - const: rockchip,rk3568-iommu
>>  
>>    reg:
>> @@ -42,14 +44,12 @@ properties:
>>      minItems: 1
>>  
>>    clocks:
>> -    items:
>> -      - description: Core clock
>> -      - description: Interface clock
> 
> These go to specific variant if:then.
> 
>> +    minItems: 2
>> +    maxItems: 4
>>  
>>    clock-names:
>> -    items:
>> -      - const: aclk
>> -      - const: iface
>> +    minItems: 2
>> +    maxItems: 4
> 
> So you just allow any names, like pink-pony.
> 
> No, define common list here. Actually same for clocks.

Will fix in v3.

> 
>>  
>>    "#iommu-cells":
>>      const: 0
>> @@ -64,6 +64,46 @@ properties:
>>        Some mmu instances may produce unexpected results
>>        when the reset operation is used.
>>  
>> +allOf:
>> +  - if:
>> +      properties:
>> +        compatible:
>> +          contains:
>> +            enum:
>> +              - rockchip,rk3576-npu-iommu
>> +              - rockchip,rk3576-rkvdec-iommu
>> +    then:
>> +      properties:
>> +        clocks:
>> +          minItems: 4
>> +        clock-names:
>> +          minItems: 4
>> +  - if:
>> +      properties:
>> +        compatible:
>> +          items:
>> +            - const: rockchip,iommu
>> +            - const: rockchip,rk3568-iommu
>> +    then:
>> +      properties:
>> +        clocks:
>> +          maxItems: 2
> 
> Why this is unspecific now? Please look at other examples how it is
> done, e.g. Samsung clocks.

I looked at some examples. Maybe it need to set both minItems and 
maxItems here? I'm not sure I understood your point.

> 
> 
> Best regards,
> Krzysztof
> 
> 

-- 
Best, 
Chaoyi


From horatiu.vultur at microchip.com  Mon Dec  1 00:26:27 2025
From: horatiu.vultur at microchip.com (Horatiu Vultur)
Date: Mon, 1 Dec 2025 09:26:27 +0100
Subject: [PATCH v4 0/2] ARM: add support for pcb8385
Message-ID: <20251201082629.2326339-1-horatiu.vultur@microchip.com>

Add pcb8385 and the documentation for it.
This is a moduler board on which it can add different daughter cards.

v3->v4:
- override i2c0 using labels instead of having it under flx0
- override usart3 using labels instead of having it under flx3

v2->v3:
- remove the linux,default-trigger properties

v1->v2:
- sort nodes in alphanumerical order
- move the eeprom nodes under i2c0

Horatiu Vultur (2):
  dt-bindings: arm: at91: add lan966 pcb8385 board
  ARM: dts: Add support for pcb8385

 .../devicetree/bindings/arm/atmel-at91.yaml   |   6 +-
 arch/arm/boot/dts/microchip/Makefile          |   3 +-
 .../boot/dts/microchip/lan966x-pcb8385.dts    | 131 ++++++++++++++++++
 3 files changed, 137 insertions(+), 3 deletions(-)
 create mode 100644 arch/arm/boot/dts/microchip/lan966x-pcb8385.dts

-- 
2.34.1



From horatiu.vultur at microchip.com  Mon Dec  1 00:26:28 2025
From: horatiu.vultur at microchip.com (Horatiu Vultur)
Date: Mon, 1 Dec 2025 09:26:28 +0100
Subject: [PATCH v4 1/2] dt-bindings: arm: at91: add lan966 pcb8385 board
In-Reply-To: <20251201082629.2326339-1-horatiu.vultur@microchip.com>
References: <20251201082629.2326339-1-horatiu.vultur@microchip.com>
Message-ID: <20251201082629.2326339-2-horatiu.vultur@microchip.com>

Add documentation for Microchip LAN9668 PCB8385

Acked-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Horatiu Vultur <horatiu.vultur at microchip.com>
---
 Documentation/devicetree/bindings/arm/atmel-at91.yaml | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.yaml b/Documentation/devicetree/bindings/arm/atmel-at91.yaml
index 3a34b7a2e8d4e..68d306d17c2a1 100644
--- a/Documentation/devicetree/bindings/arm/atmel-at91.yaml
+++ b/Documentation/devicetree/bindings/arm/atmel-at91.yaml
@@ -235,9 +235,11 @@ properties:
           - const: microchip,lan9662
           - const: microchip,lan966
 
-      - description: Microchip LAN9668 PCB8290 Evaluation Board.
+      - description: Microchip LAN9668 Evaluation Board.
         items:
-          - const: microchip,lan9668-pcb8290
+          - enum:
+              - microchip,lan9668-pcb8290
+              - microchip,lan9668-pcb8385
           - const: microchip,lan9668
           - const: microchip,lan966
 
-- 
2.34.1



From horatiu.vultur at microchip.com  Mon Dec  1 00:26:29 2025
From: horatiu.vultur at microchip.com (Horatiu Vultur)
Date: Mon, 1 Dec 2025 09:26:29 +0100
Subject: [PATCH v4 2/2] ARM: dts: Add support for pcb8385
In-Reply-To: <20251201082629.2326339-1-horatiu.vultur@microchip.com>
References: <20251201082629.2326339-1-horatiu.vultur@microchip.com>
Message-ID: <20251201082629.2326339-3-horatiu.vultur@microchip.com>

Add basic support for pcb8385 [1]. It is a modular board which allows
to add different daughter cards on which there are different PHYs.
This adds support for UART, LEDs and I2C.

[1] https://www.microchip.com/en-us/development-tool/ev83e85a

Signed-off-by: Horatiu Vultur <horatiu.vultur at microchip.com>
---
 arch/arm/boot/dts/microchip/Makefile          |   3 +-
 .../boot/dts/microchip/lan966x-pcb8385.dts    | 131 ++++++++++++++++++
 2 files changed, 133 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/boot/dts/microchip/lan966x-pcb8385.dts

diff --git a/arch/arm/boot/dts/microchip/Makefile b/arch/arm/boot/dts/microchip/Makefile
index 79cd38fdc7dab..08986c24a4700 100644
--- a/arch/arm/boot/dts/microchip/Makefile
+++ b/arch/arm/boot/dts/microchip/Makefile
@@ -102,4 +102,5 @@ dtb-$(CONFIG_SOC_LAN966) += \
 	lan966x-kontron-kswitch-d10-mmt-8g.dtb \
 	lan966x-pcb8290.dtb \
 	lan966x-pcb8291.dtb \
-	lan966x-pcb8309.dtb
+	lan966x-pcb8309.dtb \
+	lan966x-pcb8385.dtb
diff --git a/arch/arm/boot/dts/microchip/lan966x-pcb8385.dts b/arch/arm/boot/dts/microchip/lan966x-pcb8385.dts
new file mode 100644
index 0000000000000..6bbe1222f9106
--- /dev/null
+++ b/arch/arm/boot/dts/microchip/lan966x-pcb8385.dts
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * lan966x-pcb8385.dts - Device Tree file for PCB8385
+ */
+/dts-v1/;
+
+#include "lan966x.dtsi"
+#include "dt-bindings/phy/phy-lan966x-serdes.h"
+
+/ {
+	model = "Microchip EVB - LAN9668";
+	compatible = "microchip,lan9668-pcb8385", "microchip,lan9668", "microchip,lan966";
+
+	aliases {
+		serial0 = &usart3;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	gpio-restart {
+		compatible = "gpio-restart";
+		gpios = <&gpio 59 GPIO_ACTIVE_LOW>;
+		open-source;
+		priority = <200>;
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		led-p1-green {
+			label = "cu0:green";
+			gpios = <&sgpio_out 2 0 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-p1-yellow {
+			label = "cu0:yellow";
+			gpios = <&sgpio_out 2 1 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-p2-green {
+			label = "cu1:green";
+			gpios = <&sgpio_out 3 0 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-p2-yellow {
+			label = "cu1:yellow";
+			gpios = <&sgpio_out 3 1 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+	};
+};
+
+&aes {
+	status = "disabled"; /* Reserved by secure OS */
+};
+
+&flx0 {
+	atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_TWI>;
+	status = "okay";
+};
+
+&flx3 {
+	atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_USART>;
+	status = "okay";
+};
+
+&gpio {
+	fc0_b_pins: fc0-b-pins {
+		/* SCL, SDA */
+		pins = "GPIO_25", "GPIO_26";
+		function = "fc0_b";
+	};
+
+	fc3_b_pins: fc3-b-pins {
+		/* RX, TX */
+		pins = "GPIO_52", "GPIO_53";
+		function = "fc3_b";
+	};
+
+	sgpio_a_pins: sgpio-a-pins {
+		/* SCK, D0, D1, LD */
+		pins = "GPIO_32", "GPIO_33", "GPIO_34", "GPIO_35";
+		function = "sgpio_a";
+	};
+};
+
+&i2c0 {
+	pinctrl-0 = <&fc0_b_pins>;
+	pinctrl-names = "default";
+	dmas = <0>, <0>;
+	i2c-analog-filter;
+	i2c-digital-filter;
+	i2c-digital-filter-width-ns = <35>;
+	i2c-sda-hold-time-ns = <1500>;
+	status = "okay";
+
+	eeprom at 54 {
+		compatible = "atmel,24c01";
+		reg = <0x54>;
+	};
+
+	eeprom at 55 {
+		compatible = "atmel,24c01";
+		reg = <0x55>;
+	};
+};
+
+&sgpio {
+	pinctrl-0 = <&sgpio_a_pins>;
+	pinctrl-names = "default";
+	microchip,sgpio-port-ranges = <0 3>;
+	status = "okay";
+
+	gpio at 0 {
+		ngpios = <64>;
+	};
+	gpio at 1 {
+		ngpios = <64>;
+	};
+};
+
+&usart3 {
+	pinctrl-0 = <&fc3_b_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
-- 
2.34.1



From vkoul at kernel.org  Mon Dec  1 00:37:58 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Mon, 1 Dec 2025 14:07:58 +0530
Subject: [PATCH net-next 5/9] phy: add phy_get_rx_polarity() and
 phy_get_tx_polarity()
In-Reply-To: <20251124200121.5b82f09e@kernel.org>
References: <20251122193341.332324-1-vladimir.oltean@nxp.com>
 <20251122193341.332324-6-vladimir.oltean@nxp.com>
 <20251124200121.5b82f09e@kernel.org>
Message-ID: <aS1T5i3pCHsNVql6@vaman>

On 24-11-25, 20:01, Jakub Kicinski wrote:
> On Sat, 22 Nov 2025 21:33:37 +0200 Vladimir Oltean wrote:
> > Add helpers in the generic PHY folder which can be used using 'select
> > GENERIC_PHY_COMMON_PROPS' from Kconfig, without otherwise needing to
> > enable GENERIC_PHY.
> > 
> > These helpers need to deal with the slight messiness of the fact that
> > the polarity properties are arrays per protocol, and with the fact that
> > there is no default value mandated by the standard properties, all
> > default values depend on driver and protocol (PHY_POL_NORMAL may be a
> > good default for SGMII, whereas PHY_POL_AUTO may be a good default for
> > PCIe).
> > 
> > Push the supported mask of polarities to these helpers, to simplify
> > drivers such that they don't need to validate what's in the device tree
> > (or other firmware description).
> > 
> > The proposed maintainership model is joint custody between netdev and
> > linux-phy, because of the fact that these properties can be applied to
> > Ethernet PCS blocks just as well as Generic PHY devices. I've added as
> > maintainers those from "ETHERNET PHY LIBRARY", "NETWORKING DRIVERS" and
> > "GENERIC PHY FRAMEWORK".
> 
> I dunno.. ain't no such thing as "joint custody" maintainership.
> We have to pick one tree. Given the set of Ms here, I suspect 
> the best course of action may be to bubble this up to its own tree.
> Ask Konstantin for a tree in k.org, then you can "co-post" the patches
> for review + PR link in the cover letter (e.g. how Tony from Intel
> submits their patches). This way not networking and PHY can pull
> the shared changes with stable commit IDs.

How much is the volume of the changes that we are talking about, we can
always ack and pull into each other trees..?

BR
-- 
~Vinod


From krzk at kernel.org  Mon Dec  1 00:39:09 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 1 Dec 2025 09:39:09 +0100
Subject: [PATCH v2 1/2] dt-bindings: iommu: rockchip: Add support for
 multiple interface clocks
In-Reply-To: <98a847f7-0880-4e5b-a946-26dc81fde5d2@rock-chips.com>
References: <20251128071322.92-1-kernel@airkyi.com>
 <20251128071322.92-2-kernel@airkyi.com>
 <96958186-0e46-4606-ae36-239112eb31ea@kernel.org>
 <98a847f7-0880-4e5b-a946-26dc81fde5d2@rock-chips.com>
Message-ID: <491560f1-ee50-43ef-b258-adb5859cb05a@kernel.org>

On 01/12/2025 09:10, Chaoyi Chen wrote:
>>> +  - if:
>>> +      properties:
>>> +        compatible:
>>> +          items:
>>> +            - const: rockchip,iommu
>>> +            - const: rockchip,rk3568-iommu
>>> +    then:
>>> +      properties:
>>> +        clocks:
>>> +          maxItems: 2
>>
>> Why this is unspecific now? Please look at other examples how it is
>> done, e.g. Samsung clocks.
> 
> I looked at some examples. Maybe it need to set both minItems and 
> maxItems here? I'm not sure I understood your point.

Individual items were described before. Now they are not, so first item
can be anything.

You need to define the list. If the devices have completely different
clocks, then you would go with Samsung approach. But devices should not
have completely different clocks, so you should define common parts in
top-level and just narrow number of items here. maxItems is enough in
such case.
Best regards,
Krzysztof


From krzk at kernel.org  Mon Dec  1 00:41:21 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 1 Dec 2025 09:41:21 +0100
Subject: [PATCH net-next 5/9] phy: add phy_get_rx_polarity() and
 phy_get_tx_polarity()
In-Reply-To: <aS1T5i3pCHsNVql6@vaman>
References: <20251122193341.332324-1-vladimir.oltean@nxp.com>
 <20251122193341.332324-6-vladimir.oltean@nxp.com>
 <20251124200121.5b82f09e@kernel.org> <aS1T5i3pCHsNVql6@vaman>
Message-ID: <69ac21ea-eed2-449a-b231-c43e3cd0bdc0@kernel.org>

On 01/12/2025 09:37, Vinod Koul wrote:
> On 24-11-25, 20:01, Jakub Kicinski wrote:
>> On Sat, 22 Nov 2025 21:33:37 +0200 Vladimir Oltean wrote:
>>> Add helpers in the generic PHY folder which can be used using 'select
>>> GENERIC_PHY_COMMON_PROPS' from Kconfig, without otherwise needing to
>>> enable GENERIC_PHY.
>>>
>>> These helpers need to deal with the slight messiness of the fact that
>>> the polarity properties are arrays per protocol, and with the fact that
>>> there is no default value mandated by the standard properties, all
>>> default values depend on driver and protocol (PHY_POL_NORMAL may be a
>>> good default for SGMII, whereas PHY_POL_AUTO may be a good default for
>>> PCIe).
>>>
>>> Push the supported mask of polarities to these helpers, to simplify
>>> drivers such that they don't need to validate what's in the device tree
>>> (or other firmware description).
>>>
>>> The proposed maintainership model is joint custody between netdev and
>>> linux-phy, because of the fact that these properties can be applied to
>>> Ethernet PCS blocks just as well as Generic PHY devices. I've added as
>>> maintainers those from "ETHERNET PHY LIBRARY", "NETWORKING DRIVERS" and
>>> "GENERIC PHY FRAMEWORK".
>>
>> I dunno.. ain't no such thing as "joint custody" maintainership.
>> We have to pick one tree. Given the set of Ms here, I suspect 
>> the best course of action may be to bubble this up to its own tree.
>> Ask Konstantin for a tree in k.org, then you can "co-post" the patches
>> for review + PR link in the cover letter (e.g. how Tony from Intel
>> submits their patches). This way not networking and PHY can pull
>> the shared changes with stable commit IDs.
> 
> How much is the volume of the changes that we are talking about, we can
> always ack and pull into each other trees..?

That's just one C file, isn't it? Having dedicated tree for one file
feels like huge overhead.


Best regards,
Krzysztof


From bisson.gary at gmail.com  Mon Dec  1 00:41:37 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Mon,  1 Dec 2025 09:41:37 +0100
Subject: [PATCH 2/5] dt-bindings: arm: mediatek: Add ezurio,mt8370-tungsten-smarc
In-Reply-To: <20251201084140.376058-1-bisson.gary@gmail.com>
References: <20251201084140.376058-1-bisson.gary@gmail.com>
Message-ID: <20251201084140.376058-3-bisson.gary@gmail.com>

Add device tree bindings support for the Ezurio Tungsten 510 (MT8370)
SMARC SOM [1] + Universal SMARC carrier board [2].

[1] https://www.ezurio.com/product/tungsten510-smarc
[2]
https://www.ezurio.com/system-on-module/accessories/universal-smarc-carrier

Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
---
Cc: robh at kernel.org
Cc: krzk+dt at kernel.org
Cc: conor+dt at kernel.org
Cc: matthias.bgg at gmail.com
---
 Documentation/devicetree/bindings/arm/mediatek.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/arm/mediatek.yaml b/Documentation/devicetree/bindings/arm/mediatek.yaml
index f04277873694..301f9a1e041c 100644
--- a/Documentation/devicetree/bindings/arm/mediatek.yaml
+++ b/Documentation/devicetree/bindings/arm/mediatek.yaml
@@ -431,6 +431,7 @@ properties:
           - const: mediatek,mt8365
       - items:
           - enum:
+              - ezurio,mt8370-tungsten-smarc
               - grinn,genio-510-sbc
               - mediatek,mt8370-evk
           - const: mediatek,mt8370
-- 
2.43.0



From bisson.gary at gmail.com  Mon Dec  1 00:41:35 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Mon,  1 Dec 2025 09:41:35 +0100
Subject: [PATCH 0/5] Add support for Ezurio MediaTek platforms
Message-ID: <20251201084140.376058-1-bisson.gary@gmail.com>

This series adds support for Ezurio MediaTek platforms called
"Tungsten". It includes support for MT8370-based Tungsten 510 and
MT8390-based Tungsten 700 SOMs.

Regards,

Gary Bisson (5):
  dt-bindings: vendor-prefixes: Add Ezurio LLC
  dt-bindings: arm: mediatek: Add ezurio,mt8370-tungsten-smarc
  dt-bindings: arm: mediatek: Add ezurio,mt8390-tungsten-smarc
  arm64: dts: mediatek: add device tree for Tungsten 510 board
  arm64: dts: mediatek: add device tree for Tungsten 700 board

 .../devicetree/bindings/arm/mediatek.yaml     |    2 +
 .../devicetree/bindings/vendor-prefixes.yaml  |    2 +
 arch/arm64/boot/dts/mediatek/Makefile         |    2 +
 .../dts/mediatek/mt8370-tungsten-smarc.dts    |   14 +
 .../dts/mediatek/mt8390-tungsten-smarc.dts    |   22 +
 .../dts/mediatek/mt83x0-tungsten-smarc.dtsi   | 1481 +++++++++++++++++
 6 files changed, 1523 insertions(+)
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts
 create mode 100644 arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi

-- 
2.43.0



From bisson.gary at gmail.com  Mon Dec  1 00:41:38 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Mon,  1 Dec 2025 09:41:38 +0100
Subject: [PATCH 3/5] dt-bindings: arm: mediatek: Add ezurio,mt8390-tungsten-smarc
In-Reply-To: <20251201084140.376058-1-bisson.gary@gmail.com>
References: <20251201084140.376058-1-bisson.gary@gmail.com>
Message-ID: <20251201084140.376058-4-bisson.gary@gmail.com>

Add device tree bindings support for the Ezurio Tungsten 700 (MT8390)
SMARC SOM [1] + Universal SMARC carrier board [2].

[1] https://www.ezurio.com/product/tungsten700-smarc
[2]
https://www.ezurio.com/system-on-module/accessories/universal-smarc-carrier

Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
---
Cc: robh at kernel.org
Cc: krzk+dt at kernel.org
Cc: conor+dt at kernel.org
Cc: matthias.bgg at gmail.com
---
 Documentation/devicetree/bindings/arm/mediatek.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/arm/mediatek.yaml b/Documentation/devicetree/bindings/arm/mediatek.yaml
index 301f9a1e041c..cffb0f6ac690 100644
--- a/Documentation/devicetree/bindings/arm/mediatek.yaml
+++ b/Documentation/devicetree/bindings/arm/mediatek.yaml
@@ -438,6 +438,7 @@ properties:
           - const: mediatek,mt8188
       - items:
           - enum:
+              - ezurio,mt8390-tungsten-smarc
               - grinn,genio-700-sbc
               - mediatek,mt8390-evk
           - const: mediatek,mt8390
-- 
2.43.0



From bisson.gary at gmail.com  Mon Dec  1 00:41:36 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Mon,  1 Dec 2025 09:41:36 +0100
Subject: [PATCH 1/5] dt-bindings: vendor-prefixes: Add Ezurio LLC
In-Reply-To: <20251201084140.376058-1-bisson.gary@gmail.com>
References: <20251201084140.376058-1-bisson.gary@gmail.com>
Message-ID: <20251201084140.376058-2-bisson.gary@gmail.com>

Ezurio is the new name of Laird Connectivity after it acquired Boundary
Devices.

Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
---
Cc: robh at kernel.org
Cc: krzk+dt at kernel.org
---
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index f1d1882009ba..e76e6c5be726 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -547,6 +547,8 @@ patternProperties:
     description: Exegin Technologies Limited
   "^ezchip,.*":
     description: EZchip Semiconductor
+  "^ezurio,.*":
+    description: Ezurio LLC
   "^facebook,.*":
     description: Facebook
   "^fairchild,.*":
-- 
2.43.0



From bisson.gary at gmail.com  Mon Dec  1 00:41:40 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Mon,  1 Dec 2025 09:41:40 +0100
Subject: [PATCH 5/5] arm64: dts: mediatek: add device tree for Tungsten 700 board
In-Reply-To: <20251201084140.376058-1-bisson.gary@gmail.com>
References: <20251201084140.376058-1-bisson.gary@gmail.com>
Message-ID: <20251201084140.376058-6-bisson.gary@gmail.com>

Add device tree to support Ezurio Tungsten 700 (MT8390) SMARC SOM [1] +
Universal SMARC carrier board [2].
It includes support for the MIPI-DSI BD070LIC3 display which uses the
Tianma TM070JDHG30 panel + TI SN65DSI84 MIPI-DSI to LVDS bridge [3].

[1] https://www.ezurio.com/product/tungsten700-smarc
[2]
https://www.ezurio.com/system-on-module/accessories/universal-smarc-carrier
[3] https://www.ezurio.com/product/bd070lic3-7-touchscreen-display

Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
---
Cc: angelogioacchino.delregno at collabora.com
Cc: robh at kernel.org
Cc: krzk+dt at kernel.org
Cc: conor+dt at kernel.org
Cc: matthias.bgg at gmail.com
---
 arch/arm64/boot/dts/mediatek/Makefile         |  1 +
 .../dts/mediatek/mt8390-tungsten-smarc.dts    | 22 +++++++++++++++++++
 2 files changed, 23 insertions(+)
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts

diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile
index 30d169a31b10..85f338344dd3 100644
--- a/arch/arm64/boot/dts/mediatek/Makefile
+++ b/arch/arm64/boot/dts/mediatek/Makefile
@@ -102,6 +102,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-genio-510-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-tungsten-smarc.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-genio-1200-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-genio-700-evk.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-tungsten-smarc.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-kontron-3-5-sbc-i1200.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-radxa-nio-12l.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-radxa-nio-12l-8-hd-panel.dtbo
diff --git a/arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts b/arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts
new file mode 100644
index 000000000000..f1cf2821107f
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2025 Ezurio LLC
+ * Author: Gary Bisson <bisson.gary at gmail.com>
+ */
+/dts-v1/;
+#include "mt8188.dtsi"
+#include "mt83x0-tungsten-smarc.dtsi"
+
+/ {
+	model = "Ezurio Tungsten700 SMARC (MT8390)";
+	compatible = "ezurio,mt8390-tungsten-smarc", "mediatek,mt8390",
+		     "mediatek,mt8188";
+};
+
+&cpu4 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};
+
+&cpu5 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};
-- 
2.43.0



From bisson.gary at gmail.com  Mon Dec  1 00:41:39 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Mon,  1 Dec 2025 09:41:39 +0100
Subject: [PATCH 4/5] arm64: dts: mediatek: add device tree for Tungsten 510 board
In-Reply-To: <20251201084140.376058-1-bisson.gary@gmail.com>
References: <20251201084140.376058-1-bisson.gary@gmail.com>
Message-ID: <20251201084140.376058-5-bisson.gary@gmail.com>

Add device tree to support Ezurio Tungsten 510 (MT8370) SMARC SOM [1] +
Universal SMARC carrier board [2].
It includes support for the MIPI-DSI BD070LIC3 display which uses the
Tianma TM070JDHG30 panel + TI SN65DSI84 MIPI-DSI to LVDS bridge [3].

[1] https://www.ezurio.com/product/tungsten510-smarc
[2]
https://www.ezurio.com/system-on-module/accessories/universal-smarc-carrier
[3] https://www.ezurio.com/product/bd070lic3-7-touchscreen-display

Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
---
Cc: angelogioacchino.delregno at collabora.com
Cc: robh at kernel.org
Cc: krzk+dt at kernel.org
Cc: conor+dt at kernel.org
Cc: matthias.bgg at gmail.com
---
 arch/arm64/boot/dts/mediatek/Makefile         |    1 +
 .../dts/mediatek/mt8370-tungsten-smarc.dts    |   14 +
 .../dts/mediatek/mt83x0-tungsten-smarc.dtsi   | 1481 +++++++++++++++++
 3 files changed, 1496 insertions(+)
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts
 create mode 100644 arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi

diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile
index a4df4c21399e..30d169a31b10 100644
--- a/arch/arm64/boot/dts/mediatek/Makefile
+++ b/arch/arm64/boot/dts/mediatek/Makefile
@@ -99,6 +99,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8195-demo.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8195-evb.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8365-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-genio-510-evk.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-tungsten-smarc.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-genio-1200-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-genio-700-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-kontron-3-5-sbc-i1200.dtb
diff --git a/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts b/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts
new file mode 100644
index 000000000000..d713ef77df3a
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2025 Ezurio LLC
+ * Author: Gary Bisson <bisson.gary at gmail.com>
+ */
+/dts-v1/;
+#include "mt8370.dtsi"
+#include "mt83x0-tungsten-smarc.dtsi"
+
+/ {
+	model = "Ezurio Tungsten510 SMARC (MT8370)";
+	compatible = "ezurio,mt8370-tungsten-smarc", "mediatek,mt8370",
+		     "mediatek,mt8188";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi b/arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi
new file mode 100644
index 000000000000..acdafd4936fe
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi
@@ -0,0 +1,1481 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2025 Ezurio LLC
+ * Author: Gary Bisson <bisson.gary at gmail.com>
+ */
+
+#include "mt6359.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/net/microchip-lan78xx.h>
+#include <dt-bindings/pinctrl/mediatek,mt8188-pinfunc.h>
+#include <dt-bindings/usb/pd.h>
+
+/ {
+	aliases {
+		dsi0 = &disp_dsi0;
+		ethernet0 = &eth;
+		i2c0 = &i2c0;
+		i2c1 = &i2c1;
+		i2c2 = &i2c2;
+		i2c3 = &i2c3;
+		i2c4 = &i2c4;
+		i2c5 = &i2c5;
+		i2c6 = &i2c6;
+		mmc0 = &mmc0;
+		mmc1 = &mmc1;
+		mmc2 = &mmc2;
+		rtc0 = &rv3028;
+		rtc1 = &mt6359rtc;
+		serial0 = &uart0;
+	};
+
+	backlight_lcd0: backlight-lcd0 {
+		compatible = "pwm-backlight";
+		brightness-levels = <0 1023>;
+		default-brightness-level = <768>;
+		num-interpolated-steps = <1023>;
+		enable-gpios = <&pio 30 GPIO_ACTIVE_HIGH>;
+		pwms = <&disp_pwm0 0 30000>;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	firmware {
+		optee {
+			compatible = "linaro,optee-tz";
+			method = "smc";
+		};
+	};
+
+	memory at 40000000 {
+		device_type = "memory";
+		reg = <0 0x40000000 0x1 0x00000000>;
+	};
+
+	panel-dsi0 {
+		compatible = "tianma,tm070jdhg30";
+		backlight = <&backlight_lcd0>;
+
+		port {
+			dsi0_panel_in: endpoint {
+				remote-endpoint = <&sn65dsi84_bridge_out>;
+			};
+		};
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		/*
+		 * 12 MiB reserved for OP-TEE (BL32)
+		 * +-----------------------+ 0x43e0_0000
+		 * |      SHMEM 2MiB       |
+		 * +-----------------------+ 0x43c0_0000
+		 * |        | TA_RAM  8MiB |
+		 * + TZDRAM +--------------+ 0x4340_0000
+		 * |        | TEE_RAM 2MiB |
+		 * +-----------------------+ 0x4320_0000
+		 */
+		optee_reserved: optee at 43200000 {
+			no-map;
+			reg = <0 0x43200000 0 0x00c00000>;
+		};
+
+		scp_mem: memory at 50000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x50000000 0 0x2900000>;
+			no-map;
+		};
+
+		/* 2 MiB reserved for ARM Trusted Firmware (BL31) */
+		bl31_secmon_reserved: memory at 54600000 {
+			no-map;
+			reg = <0 0x54600000 0x0 0x200000>;
+		};
+
+		apu_mem: memory at 55000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x55000000 0 0x1400000>; /* 20 MB */
+		};
+
+		vpu_mem: memory at 57000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x57000000 0 0x1400000>; /* 20 MB */
+		};
+
+		adsp_mem: memory at 60000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x60000000 0 0xf00000>;
+			no-map;
+		};
+
+		afe_dma_mem: memory at 60f00000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x60f00000 0 0x100000>;
+			no-map;
+		};
+
+		adsp_dma_mem: memory at 61000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x61000000 0 0x100000>;
+			no-map;
+		};
+	};
+
+	regulator-efuse {
+		compatible = "regulator-output";
+		vout-supply = <&mt6359_vefuse_ldo_reg>;
+	};
+
+	sdcard_en_3v3: regulator-sdcard-en {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-name = "sdcard_en_3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&pio 111 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	usb_p0_vbus: regulator-usb-p0-vbus {
+		compatible = "regulator-fixed";
+		regulator-name = "vbus_p0";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&pio 84 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	usb_p1_vbus: regulator-usb-p1-vbus {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&usb1_hub_pins>;
+		regulator-name = "vbus_p1";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		gpio = <&pio 147 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	usb_p2_vbus: regulator-usb-p2-vbus {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&usb2_eth_pins>;
+		regulator-name = "vbus_p2";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		gpio = <&pio 80 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	wifi_pwrseq: wifi-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		pinctrl-names = "default";
+		pinctrl-0 = <&wifi_pwrseq_pins>;
+		post-power-on-delay-ms = <200>;
+		reset-gpios = <&pio 89 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&adsp {
+	memory-region = <&adsp_dma_mem>, <&adsp_mem>;
+	status = "okay";
+};
+
+&afe {
+	memory-region = <&afe_dma_mem>;
+	status = "okay";
+};
+
+&cpu0 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};
+
+&cpu1 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};
+
+&cpu2 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};
+
+&cpu3 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};
+
+&cpu6 {
+	cpu-supply = <&mt6315_6_vbuck1>;
+};
+
+&cpu7 {
+	cpu-supply = <&mt6315_6_vbuck1>;
+};
+
+&disp_pwm0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&disp_pwm0_pins>;
+	status = "okay";
+};
+
+&disp_dsi0 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			reg = <0>;
+			dsi0_in: endpoint {
+				remote-endpoint = <&dither0_out>;
+			};
+		};
+
+		port at 1 {
+			reg = <1>;
+			dsi0_out: endpoint {
+				remote-endpoint = <&sn65dsi84_bridge_in>;
+			};
+		};
+	};
+};
+
+&dither0_in {
+	remote-endpoint = <&postmask0_out>;
+};
+
+&dither0_out {
+	remote-endpoint = <&dsi0_in>;
+};
+
+&eth {
+	phy-mode ="rgmii-id";
+	phy-handle = <&ethernet_phy0>;
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&eth_default_pins>;
+	pinctrl-1 = <&eth_sleep_pins>;
+	mediatek,mac-wol;
+	snps,reset-gpio = <&pio 27 GPIO_ACTIVE_LOW>;
+	snps,reset-active-low;
+	snps,reset-delays-us = <0 11000 1000>;
+	status = "okay";
+};
+
+&eth_mdio {
+	ethernet_phy0: ethernet-phy at 7 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <0x7>;
+		interrupts-extended = <&pio 148 IRQ_TYPE_LEVEL_LOW>;
+	};
+};
+
+&gamma0_out {
+	remote-endpoint = <&postmask0_in>;
+};
+
+&gpu {
+	mali-supply = <&mt6359_vproc2_buck_reg>;
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default", "gpio";
+	pinctrl-0 = <&i2c0_pins>;
+	pinctrl-1 = <&i2c0_gpio_pins>;
+	scl-gpios = <&pio 55 GPIO_OPEN_DRAIN>;
+	sda-gpios = <&pio 56 GPIO_OPEN_DRAIN>;
+	clock-frequency = <100000>;
+	status = "okay";
+
+	i2c-mux-gp at 73 {
+		compatible = "nxp,pca9546";
+		reg = <0x73>;
+		reset-gpios = <&pio 6 GPIO_ACTIVE_LOW>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		i2c_mux_gp_0: i2cmux-gp at 0 {
+			clock-frequency = <100000>;
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_gp_1: i2cmux-gp at 1 {
+			clock-frequency = <100000>;
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_gp_2: i2cmux-gp at 2 {
+			clock-frequency = <100000>;
+			reg = <2>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_gp_3: i2cmux-gp at 3 {
+			clock-frequency = <100000>;
+			reg = <3>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	clock-frequency = <400000>;
+	status = "okay";
+};
+
+&i2c2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_pins>;
+	clock-frequency = <400000>;
+	status = "okay";
+
+	i2c-mux-lcd at 73 {
+		compatible = "nxp,pca9546";
+		pinctrl-names = "default";
+		pinctrl-0 = <&i2c_mux_smarc_lcd_pins>;
+		reg = <0x73>;
+		reset-gpios = <&pio 5 GPIO_ACTIVE_LOW>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		i2c_mux_lcd_0: i2cmux-lcd at 0 {
+			clock-frequency = <100000>;
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_lcd_1: i2cmux-lcd at 1 {
+			clock-frequency = <100000>;
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_lcd_2: i2cmux-lcd at 2 {
+			clock-frequency = <100000>;
+			reg = <2>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_lcd_3: i2cmux-lcd at 3 {
+			clock-frequency = <100000>;
+			reg = <3>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+};
+
+&i2c3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c3_pins>;
+	clock-frequency = <400000>;
+	status = "okay";
+};
+
+&i2c4 {
+	pinctrl-names = "default", "default";
+	pinctrl-0 = <&i2c4_pins>;
+	clock-frequency = <400000>;
+	status = "okay";
+};
+
+&i2c_mux_gp_0 {
+	rv3028: rtc at 52 {
+		compatible = "microcrystal,rv3028";
+		reg = <0x52>;
+		interrupts-extended = <&pio 42 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&rv3028_pins>;
+		#clock-cells = <0>;
+		wakeup-source;
+	};
+};
+
+&i2c_mux_gp_1 {
+	typec at 60 {
+		compatible = "ti,hd3ss3220";
+		interrupts-extended = <&pio 45 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&hd3ss3220_pins>;
+		reg = <0x60>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+				hd3ss3220_in_ep: endpoint {
+					remote-endpoint = <&ss_ep>;
+				};
+			};
+
+			port at 1 {
+				reg = <1>;
+				hd3ss3220_out_ep: endpoint {
+					remote-endpoint = <&usb_role_switch>;
+				};
+			};
+		};
+	};
+};
+
+&i2c_mux_gp_2 {
+	codec at 1a {
+		#sound-dai-cells = <0>;
+		clocks = <&topckgen CLK_TOP_I2SO1>;
+		compatible = "wlf,wm8962";
+		gpio-cfg = <
+			0x0000 /* n/c */
+			0x0000 /* gpio2: */
+			0x0000 /* gpio3: */
+			0x0000 /* n/c */
+			0x8081 /* gpio5:HP detect */
+			0x8095 /* gpio6:Mic detect */
+		>;
+		reg = <0x1a>;
+	};
+};
+
+&i2c_mux_lcd_2 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	bridge at 2c {
+		compatible = "ti,sn65dsi84";
+		reg = <0x2c>;
+		enable-gpios = <&pio 25 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&dsi0_sn65dsi84_pins>;
+		status = "okay";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+
+				sn65dsi84_bridge_in: endpoint {
+					remote-endpoint = <&dsi0_out>;
+					data-lanes = <1 2 3 4>;
+				};
+			};
+
+			port at 2 {
+				reg = <2>;
+
+				sn65dsi84_bridge_out: endpoint {
+					remote-endpoint = <&dsi0_panel_in>;
+				};
+			};
+		};
+	};
+
+	touchscren at 5d {
+		compatible = "goodix,gt911";
+		reg = <0x5d>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&ts_dsi0_goodix_pins>;
+		interrupts-extended = <&pio 146 IRQ_TYPE_LEVEL_HIGH>;
+		irq-gpios = <&pio 146 GPIO_ACTIVE_HIGH>;
+		reset-gpios = <&pio 7 GPIO_ACTIVE_HIGH>;
+	};
+};
+
+&mfg0 {
+	domain-supply = <&mt6359_vproc2_buck_reg>;
+};
+
+&mfg1 {
+	domain-supply = <&mt6359_vsram_others_ldo_reg>;
+};
+
+&mmc0 {
+	status = "okay";
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc0_default_pins>;
+	pinctrl-1 = <&mmc0_uhs_pins>;
+	bus-width = <8>;
+	max-frequency = <200000000>;
+	cap-mmc-highspeed;
+	cap-mmc-hw-reset;
+	mmc-hs200-1_8v;
+	mmc-hs400-1_8v;
+	supports-cqe;
+	cap-mmc-hw-reset;
+	no-sdio;
+	no-sd;
+	hs400-ds-delay = <0x1481b>;
+	vmmc-supply = <&mt6359_vemc_1_ldo_reg>;
+	vqmmc-supply = <&mt6359_vufs_ldo_reg>;
+	non-removable;
+};
+
+&mmc1 {
+	status = "okay";
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc1_default_pins>;
+	pinctrl-1 = <&mmc1_uhs_pins>;
+	bus-width = <4>;
+	max-frequency = <200000000>;
+	cap-sd-highspeed;
+	sd-uhs-sdr50;
+	sd-uhs-sdr104;
+	cd-gpios = <&pio 2 GPIO_ACTIVE_LOW>;
+	vqmmc-supply = <&mt6359_vsim1_ldo_reg>;
+	vmmc-supply = <&sdcard_en_3v3>;
+};
+
+&mmc2 {
+	status = "okay";
+	pinctrl-names = "default", "state_uhs", "state_eint";
+	pinctrl-0 = <&mmc2_default_pins>;
+	pinctrl-1 = <&mmc2_uhs_pins>;
+	pinctrl-2 = <&mmc2_eint_pins>;
+	eint-gpios = <&pio 172 0>;
+	bus-width = <4>;
+	max-frequency = <200000000>;
+	cap-sd-highspeed;
+	sd-uhs-sdr104;
+	keep-power-in-suspend;
+	enable-sdio-wakeup;
+	cap-sdio-async-int;
+	cap-sdio-irq;
+	no-mmc;
+	no-sd;
+	non-removable;
+	vmmc-supply = <&mt6359_vcn33_2_bt_ldo_reg>;
+	vqmmc-supply = <&mt6359_vcn18_ldo_reg>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+};
+
+&mipi_tx_config0 {
+	status = "okay";
+};
+
+&mt6359codec {
+	mediatek,mic-type-0 = <1>;
+	mediatek,mic-type-1 = <3>;
+	mediatek,mic-type-2 = <0>;
+	mediatek,dmic-mode = <0>;
+};
+
+&mt6359_vbbck_ldo_reg {
+	regulator-always-on;
+};
+
+&mt6359_vcn18_ldo_reg {
+	regulator-name = "vcn18_pmu";
+	regulator-always-on;
+	regulator-boot-on;
+};
+
+&mt6359_vcn33_1_bt_ldo_reg {
+	regulator-name = "vcn33_1_pmu";
+	regulator-always-on;
+};
+
+&mt6359_vcn33_2_bt_ldo_reg {
+	regulator-name = "vcn33_2_pmu";
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-always-on;
+	regulator-boot-on;
+};
+
+&mt6359_vcore_buck_reg {
+	regulator-name = "dvdd_proc_l";
+	regulator-always-on;
+};
+
+&mt6359_vemc_1_ldo_reg {
+	regulator-always-on;
+};
+
+&mt6359_vgpu11_buck_reg {
+	regulator-name = "dvdd_core";
+	regulator-always-on;
+};
+
+&mt6359_vmodem_buck_reg {
+	regulator-always-on;
+};
+
+&mt6359_vpa_buck_reg {
+	regulator-name = "vpa_pmu";
+	regulator-always-on;
+};
+
+&mt6359_vproc2_buck_reg {
+	/* The name "vgpu" is required by mtk-regulator-coupler */
+	regulator-name = "vgpu";
+	regulator-min-microvolt = <550000>;
+	regulator-max-microvolt = <800000>;
+	regulator-coupled-with = <&mt6359_vsram_others_ldo_reg>;
+	regulator-coupled-max-spread = <225000>;
+	regulator-always-on;
+};
+
+&mt6359_vs2_buck_reg {
+	regulator-min-microvolt = <1600000>;
+	regulator-boot-on;
+};
+
+&mt6359_vpu_buck_reg {
+	regulator-name = "dvdd_adsp";
+	regulator-always-on;
+};
+
+&mt6359_vrf12_ldo_reg {
+	regulator-name = "va12_abb2_pmu";
+	regulator-always-on;
+};
+
+&mt6359_vsram_md_ldo_reg {
+	regulator-always-on;
+};
+
+&mt6359_vsram_others_ldo_reg {
+	/* The name "vsram_gpu" is required by mtk-regulator-coupler */
+	regulator-name = "vsram_gpu";
+	regulator-min-microvolt = <750000>;
+	regulator-max-microvolt = <800000>;
+	regulator-coupled-with = <&mt6359_vproc2_buck_reg>;
+	regulator-coupled-max-spread = <225000>;
+	regulator-always-on;
+};
+
+&mt6359_vsim1_ldo_reg {
+	regulator-name = "vsim1_pmu";
+	regulator-max-microvolt = <1800000>;
+	regulator-enable-ramp-delay = <480>;
+};
+
+&mt6359_vufs_ldo_reg {
+	regulator-name = "vufs18_pmu";
+	regulator-always-on;
+};
+
+&ovl0_in {
+	remote-endpoint = <&vdosys0_ep_main>;
+};
+
+&pcie {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie_default_pins>;
+	status = "okay";
+};
+
+&pciephy {
+	status = "okay";
+};
+
+&pmic {
+	interrupt-parent = <&pio>;
+	interrupts = <222 IRQ_TYPE_LEVEL_HIGH>;
+
+	mt6359keys: keys {
+		compatible = "mediatek,mt6359-keys";
+		mediatek,long-press-mode = <1>;
+		power-off-time-sec = <0>;
+
+		power-key {
+			linux,keycodes = <116>;
+			wakeup-source;
+		};
+	};
+};
+
+&postmask0_in {
+	remote-endpoint = <&gamma0_out>;
+};
+
+&postmask0_out {
+	remote-endpoint = <&dither0_in>;
+};
+
+&scp_cluster {
+	status = "okay";
+};
+
+&scp_c0 {
+	firmware-name = "mediatek/mt8188/scp.img";
+	memory-region = <&scp_mem>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-0 = <&spi0_pins>;
+	pinctrl-names = "default";
+	mediatek,pad-select = <0>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+};
+
+&spi1 {
+	pinctrl-0 = <&spi1_pins>;
+	pinctrl-names = "default";
+	mediatek,pad-select = <0>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+};
+
+&spmi {
+	#address-cells = <1>;
+	#size-cells = <2>;
+
+	mt6315_6: mt6315 at 6 {
+		compatible = "mediatek,mt6315-regulator";
+		reg = <0x6 0 0xb>;
+
+		regulators {
+			mt6315_6_vbuck1: vbuck1 {
+				regulator-compatible = "vbuck1";
+				regulator-name = "vbuck1";
+				regulator-min-microvolt = <300000>;
+				regulator-max-microvolt = <1193750>;
+				regulator-enable-ramp-delay = <256>;
+				regulator-allowed-modes = <0 1 2>;
+				regulator-always-on;
+				mtk,combined-regulator = <2>;
+			};
+
+			mt6315_6_vbuck3: vbuck3 {
+				regulator-compatible = "vbuck3";
+				regulator-name = "vbuck3";
+				regulator-min-microvolt = <300000>;
+				regulator-max-microvolt = <1193750>;
+				regulator-enable-ramp-delay = <256>;
+				regulator-allowed-modes = <0 1 2>;
+				regulator-always-on;
+			};
+
+			mt6315_6_vbuck4: vbuck4 {
+				regulator-compatible = "vbuck4";
+				regulator-name = "vbuck4";
+				regulator-min-microvolt = <1193750>;
+				regulator-max-microvolt = <1193750>;
+				regulator-enable-ramp-delay = <256>;
+				regulator-allowed-modes = <0 1 2>;
+				regulator-always-on;
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1193750>;
+				};
+			};
+		};
+	};
+};
+
+&uart0 {
+	pinctrl-0 = <&uart0_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-0 = <&uart1_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-0 = <&uart2_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&ssusb0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&usbotg_pins>;
+	maximum-speed = "high-speed";
+	usb-role-switch;
+	dr_mode = "otg";
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	wakeup-source;
+	status = "okay";
+
+	connector {
+		compatible = "usb-c-connector";
+		label = "USB-C";
+		data-role = "dual";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+				hs_ep: endpoint {
+					remote-endpoint = <&usb_hs_ep>;
+				};
+			};
+
+			port at 1 {
+				reg = <1>;
+				ss_ep: endpoint {
+					remote-endpoint = <&hd3ss3220_in_ep>;
+				};
+			};
+		};
+	};
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			reg = <0>;
+			usb_hs_ep: endpoint {
+				remote-endpoint = <&hs_ep>;
+			};
+		};
+
+		port at 1 {
+			reg = <1>;
+			usb_role_switch: endpoint {
+				remote-endpoint = <&hd3ss3220_out_ep>;
+			};
+		};
+	};
+};
+
+&u2port0 {
+	status = "okay";
+};
+
+&u3phy0 {
+	status = "okay";
+};
+
+&xhci0 {
+	vbus-supply = <&usb_p0_vbus>;
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	status = "okay";
+};
+
+&ssusb1 {
+	pinctrl-0 = <&usb1_pins>;
+	pinctrl-names = "default";
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	dr_mode = "host";
+	wakeup-source;
+	status = "okay";
+};
+
+&u2port1 {
+	status = "okay";
+};
+
+&u3port1 {
+	status = "okay";
+};
+
+&u3phy1 {
+	status = "okay";
+};
+
+&xhci1 {
+	vbus-supply = <&usb_p1_vbus>;
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	status = "okay";
+};
+
+&ssusb2 {
+	maximum-speed = "high-speed";
+	dr_mode = "host";
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	status = "okay";
+	wakeup-source;
+};
+
+&u2port2 {
+	status = "okay";
+};
+
+&u3phy2 {
+	status = "okay";
+};
+
+&xhci2 {
+	vbus-supply = <&usb_p2_vbus>;
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+
+	ethernet at 1 {
+		compatible = "usb424,7850";
+		reg = <1>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		mdio {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			ethernet-phy at 1 {
+				reg = <1>;
+				microchip,led-modes = <
+					LAN78XX_LINK_1000_ACTIVITY
+					LAN78XX_LINK_10_ACTIVITY
+					LAN78XX_LINK_10_100_ACTIVITY
+					LAN78XX_LINK_ACTIVITY
+				>;
+			};
+		};
+	};
+};
+
+&vdosys0 {
+	port {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		vdosys0_ep_main: endpoint at 0 {
+			reg = <0>;
+			remote-endpoint = <&ovl0_in>;
+		};
+	};
+};
+
+&watchdog {
+	pinctrl-names = "default";
+	pinctrl-0 = <&watchdog_pins>;
+};
+
+&pio {
+	audio_pins: audio-pins {
+		pins-aud-pmic {
+			pinmux = <
+				PINMUX_GPIO101__FUNC_O_AUD_CLK_MOSI
+				PINMUX_GPIO102__FUNC_O_AUD_SYNC_MOSI
+				PINMUX_GPIO103__FUNC_O_AUD_DAT_MOSI0
+				PINMUX_GPIO104__FUNC_O_AUD_DAT_MOSI1
+				PINMUX_GPIO105__FUNC_I0_AUD_DAT_MISO0
+				PINMUX_GPIO106__FUNC_I0_AUD_DAT_MISO1
+			>;
+		};
+
+		pins-pcm-wifi {
+			pinmux = <
+				PINMUX_GPIO121__FUNC_B0_PCM_CLK
+				PINMUX_GPIO122__FUNC_B0_PCM_SYNC
+				PINMUX_GPIO123__FUNC_O_PCM_DO
+				PINMUX_GPIO124__FUNC_I0_PCM_DI
+			>;
+		};
+
+		pins-i2s {
+			pinmux = <
+				PINMUX_GPIO119__FUNC_O_I2SO1_MCK
+				PINMUX_GPIO112__FUNC_O_I2SO1_WS
+				PINMUX_GPIO120__FUNC_O_I2SO1_BCK
+				PINMUX_GPIO113__FUNC_O_I2SO1_D0
+				PINMUX_GPIO110__FUNC_I0_I2SIN_D0
+			>;
+		};
+	};
+
+	disp_pwm0_pins: disp-pwm0-pins {
+		pins {
+			pinmux = <PINMUX_GPIO29__FUNC_O_DISP_PWM0>;
+			bias-pull-down;
+		};
+	};
+
+	dsi0_sn65dsi84_pins: dsi0-sn65dsi84-pins {
+		pins-irq {
+			pinmux = <PINMUX_GPIO128__FUNC_B_GPIO128>;
+			bias-pull-down;
+			input-enable;
+		};
+
+		pins-enable {
+			pinmux = <PINMUX_GPIO25__FUNC_B_GPIO25>;
+			bias-pull-down;
+		};
+	};
+
+	eth_default_pins: eth-default-pins {
+		pins-txd {
+			pinmux = <PINMUX_GPIO131__FUNC_O_GBE_TXD3>,
+				 <PINMUX_GPIO132__FUNC_O_GBE_TXD2>,
+				 <PINMUX_GPIO133__FUNC_O_GBE_TXD1>,
+				 <PINMUX_GPIO134__FUNC_O_GBE_TXD0>;
+			drive-strength = <MTK_DRIVE_8mA>;
+		};
+		pins-cc {
+			pinmux = <PINMUX_GPIO139__FUNC_B0_GBE_TXC>,
+				 <PINMUX_GPIO142__FUNC_O_GBE_TXEN>,
+				 <PINMUX_GPIO141__FUNC_I0_GBE_RXDV>;
+			drive-strength = <MTK_DRIVE_8mA>;
+		};
+		pins-rxd {
+			pinmux = <PINMUX_GPIO135__FUNC_I0_GBE_RXD3>,
+				 <PINMUX_GPIO136__FUNC_I0_GBE_RXD2>,
+				 <PINMUX_GPIO137__FUNC_I0_GBE_RXD1>,
+				 <PINMUX_GPIO138__FUNC_I0_GBE_RXD0>,
+				 <PINMUX_GPIO140__FUNC_I0_GBE_RXC>;
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
+		};
+		pins-mdio {
+			pinmux = <PINMUX_GPIO143__FUNC_O_GBE_MDC>,
+				 <PINMUX_GPIO144__FUNC_B1_GBE_MDIO>;
+			drive-strength = <MTK_DRIVE_8mA>;
+			input-enable;
+		};
+		pins-power {
+			pinmux = <PINMUX_GPIO27__FUNC_B_GPIO27>; /* GP_EQOS_RESET */
+			output-high;
+		};
+		pins-intr {
+			pinmux = <PINMUX_GPIO148__FUNC_B_GPIO148>; /* GPIRQ_EQOS_PHY */
+			bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
+			input-enable;
+		};
+	};
+
+	eth_sleep_pins: eth-sleep-pins {
+		pins-txd {
+			pinmux = <PINMUX_GPIO131__FUNC_B_GPIO131>,
+				 <PINMUX_GPIO132__FUNC_B_GPIO132>,
+				 <PINMUX_GPIO133__FUNC_B_GPIO133>,
+				 <PINMUX_GPIO134__FUNC_B_GPIO134>;
+		};
+		pins-cc {
+			pinmux = <PINMUX_GPIO139__FUNC_B_GPIO139>,
+				 <PINMUX_GPIO142__FUNC_B_GPIO142>,
+				 <PINMUX_GPIO141__FUNC_B_GPIO141>,
+				 <PINMUX_GPIO140__FUNC_B_GPIO140>;
+		};
+		pins-rxd {
+			pinmux = <PINMUX_GPIO135__FUNC_B_GPIO135>,
+				 <PINMUX_GPIO136__FUNC_B_GPIO136>,
+				 <PINMUX_GPIO137__FUNC_B_GPIO137>,
+				 <PINMUX_GPIO138__FUNC_B_GPIO138>;
+		};
+		pins-mdio {
+			pinmux = <PINMUX_GPIO143__FUNC_B_GPIO143>,
+				 <PINMUX_GPIO144__FUNC_B_GPIO144>;
+			input-disable;
+			bias-disable;
+		};
+	};
+
+	gpio_keys_pins: gpio-keys-pins {
+		pins-keys {
+			pinmux = <PINMUX_GPIO129__FUNC_B_GPIO129>,
+				 <PINMUX_GPIO65__FUNC_B_GPIO65>,
+				 <PINMUX_GPIO66__FUNC_B_GPIO66>;
+			bias-pull-up;
+		};
+	};
+
+	hd3ss3220_pins: hd3ss3320-pins {
+		pins-irq {
+			pinmux = <PINMUX_GPIO45__FUNC_B_GPIO45>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+			input-enable;
+		};
+	};
+
+	hdmi_vreg_pins: hdmi-vreg-pins {
+		pins-pwr {
+			pinmux = <PINMUX_GPIO50__FUNC_O_HDMITX20_PWR5V>;
+			bias-disable;
+		};
+	};
+
+	hdmi_pins: hdmi-pins {
+		pins-hotplug {
+			pinmux = <PINMUX_GPIO51__FUNC_I0_HDMITX20_HTPLG>;
+			bias-pull-down;
+		};
+
+		pins-cec {
+			pinmux = <PINMUX_GPIO52__FUNC_B1_HDMITX20_CEC>;
+			bias-disable;
+		};
+
+		pins-ddc {
+			pinmux = <PINMUX_GPIO53__FUNC_B1_HDMITX20_SCL>,
+				 <PINMUX_GPIO54__FUNC_B1_HDMITX20_SDA>;
+			drive-strength = <10>;
+		};
+	};
+
+	i2c0_pins: i2c0-pins {
+		pins-bus {
+			pinmux = <PINMUX_GPIO56__FUNC_B1_SDA0>,
+				 <PINMUX_GPIO55__FUNC_B1_SCL0>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c0_gpio_pins: i2c0-gpio-pins {
+		pins-gpio {
+			pinmux = <PINMUX_GPIO6__FUNC_B_GPIO6>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c1_pins: i2c1-pins {
+		pins-bus {
+			pinmux = <PINMUX_GPIO58__FUNC_B1_SDA1>,
+				 <PINMUX_GPIO57__FUNC_B1_SCL1>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c2_pins: i2c2-pins {
+		pins-bus {
+			pinmux = <PINMUX_GPIO60__FUNC_B1_SDA2>,
+				 <PINMUX_GPIO59__FUNC_B1_SCL2>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c3_pins: i2c3-pins {
+		pins-bus {
+			pinmux = <PINMUX_GPIO62__FUNC_B1_SDA3>,
+				 <PINMUX_GPIO61__FUNC_B1_SCL3>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c4_pins: i2c4-pins {
+		pins-bus {
+			pinmux = <PINMUX_GPIO64__FUNC_B1_SDA4>,
+				 <PINMUX_GPIO63__FUNC_B1_SCL4>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c_mux_smarc_lcd_pins: i2c-mux-smarc-lcd-pins {
+		pins-reset {
+			pinmux = <PINMUX_GPIO5__FUNC_B_GPIO5>;
+			bias-pull-down;
+		};
+	};
+
+	mmc0_default_pins: mmc0-default-pins {
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO161__FUNC_B1_MSDC0_DAT0>,
+				 <PINMUX_GPIO160__FUNC_B1_MSDC0_DAT1>,
+				 <PINMUX_GPIO159__FUNC_B1_MSDC0_DAT2>,
+				 <PINMUX_GPIO158__FUNC_B1_MSDC0_DAT3>,
+				 <PINMUX_GPIO154__FUNC_B1_MSDC0_DAT4>,
+				 <PINMUX_GPIO153__FUNC_B1_MSDC0_DAT5>,
+				 <PINMUX_GPIO152__FUNC_B1_MSDC0_DAT6>,
+				 <PINMUX_GPIO151__FUNC_B1_MSDC0_DAT7>,
+				 <PINMUX_GPIO156__FUNC_B1_MSDC0_CMD>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins-clk {
+			pinmux = <PINMUX_GPIO157__FUNC_B1_MSDC0_CLK>;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-rst {
+			pinmux = <PINMUX_GPIO155__FUNC_O_MSDC0_RSTB>;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+
+	mmc0_uhs_pins: mmc0-uhs-pins {
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO161__FUNC_B1_MSDC0_DAT0>,
+				 <PINMUX_GPIO160__FUNC_B1_MSDC0_DAT1>,
+				 <PINMUX_GPIO159__FUNC_B1_MSDC0_DAT2>,
+				 <PINMUX_GPIO158__FUNC_B1_MSDC0_DAT3>,
+				 <PINMUX_GPIO154__FUNC_B1_MSDC0_DAT4>,
+				 <PINMUX_GPIO153__FUNC_B1_MSDC0_DAT5>,
+				 <PINMUX_GPIO152__FUNC_B1_MSDC0_DAT6>,
+				 <PINMUX_GPIO151__FUNC_B1_MSDC0_DAT7>,
+				 <PINMUX_GPIO156__FUNC_B1_MSDC0_CMD>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins-clk {
+			pinmux = <PINMUX_GPIO157__FUNC_B1_MSDC0_CLK>;
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-ds {
+			pinmux = <PINMUX_GPIO162__FUNC_B0_MSDC0_DSL>;
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-rst {
+			pinmux = <PINMUX_GPIO155__FUNC_O_MSDC0_RSTB>;
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+
+	mmc1_default_pins: mmc1-default-pins {
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO163__FUNC_B1_MSDC1_CMD>,
+				 <PINMUX_GPIO165__FUNC_B1_MSDC1_DAT0>,
+				 <PINMUX_GPIO166__FUNC_B1_MSDC1_DAT1>,
+				 <PINMUX_GPIO167__FUNC_B1_MSDC1_DAT2>,
+				 <PINMUX_GPIO168__FUNC_B1_MSDC1_DAT3>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins-pwr {
+			pinmux = <PINMUX_GPIO111__FUNC_B_GPIO111>;
+			bias-pull-down;
+		};
+
+		pins-pullup {
+			pinmux = <PINMUX_GPIO11__FUNC_B_GPIO11>;
+			bias-pull-up;
+		};
+
+		pins-clk {
+			pinmux = <PINMUX_GPIO164__FUNC_B1_MSDC1_CLK>;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-insert {
+			pinmux = <PINMUX_GPIO2__FUNC_B_GPIO2>;
+			bias-pull-up;
+		};
+	};
+
+	mmc1_uhs_pins: mmc1-uhs-pins {
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO163__FUNC_B1_MSDC1_CMD>,
+				 <PINMUX_GPIO165__FUNC_B1_MSDC1_DAT0>,
+				 <PINMUX_GPIO166__FUNC_B1_MSDC1_DAT1>,
+				 <PINMUX_GPIO167__FUNC_B1_MSDC1_DAT2>,
+				 <PINMUX_GPIO168__FUNC_B1_MSDC1_DAT3>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins-clk {
+			pinmux = <PINMUX_GPIO164__FUNC_B1_MSDC1_CLK>;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+	};
+
+	mmc2_default_pins: mmc2-default-pins {
+		pins-clk {
+			pinmux = <PINMUX_GPIO170__FUNC_B1_MSDC2_CLK>;
+			drive-strength = <MTK_DRIVE_4mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO169__FUNC_B1_MSDC2_CMD>,
+				 <PINMUX_GPIO171__FUNC_B1_MSDC2_DAT0>,
+				 <PINMUX_GPIO172__FUNC_B1_MSDC2_DAT1>,
+				 <PINMUX_GPIO173__FUNC_B1_MSDC2_DAT2>,
+				 <PINMUX_GPIO174__FUNC_B1_MSDC2_DAT3>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+
+	mmc2_uhs_pins: mmc2-uhs-pins {
+		pins-clk {
+			pinmux = <PINMUX_GPIO170__FUNC_B1_MSDC2_CLK>;
+			drive-strength = <MTK_DRIVE_4mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO169__FUNC_B1_MSDC2_CMD>,
+				 <PINMUX_GPIO171__FUNC_B1_MSDC2_DAT0>,
+				 <PINMUX_GPIO172__FUNC_B1_MSDC2_DAT1>,
+				 <PINMUX_GPIO173__FUNC_B1_MSDC2_DAT2>,
+				 <PINMUX_GPIO174__FUNC_B1_MSDC2_DAT3>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+
+	mmc2_eint_pins: mmc2-eint-pins {
+		pins-dat1 {
+			pinmux = <PINMUX_GPIO172__FUNC_B_GPIO172>;
+			input-enable;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+
+	rv3028_pins: rv3028-pins {
+		pins-irq {
+			pinmux = <PINMUX_GPIO42__FUNC_B_GPIO42>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+			input-enable;
+		};
+	};
+
+	spi0_pins: spi0-pins {
+		pins-spi {
+			pinmux = <PINMUX_GPIO69__FUNC_O_SPIM0_CSB>,
+				<PINMUX_GPIO70__FUNC_O_SPIM0_CLK>,
+				<PINMUX_GPIO71__FUNC_B0_SPIM0_MOSI>,
+				<PINMUX_GPIO72__FUNC_B0_SPIM0_MISO>;
+			bias-disable;
+		};
+	};
+
+	spi1_pins: spi1-pins {
+		pins-spi {
+			pinmux = <PINMUX_GPIO75__FUNC_O_SPIM1_CSB>,
+				<PINMUX_GPIO76__FUNC_O_SPIM1_CLK>,
+				<PINMUX_GPIO77__FUNC_B0_SPIM1_MOSI>,
+				<PINMUX_GPIO78__FUNC_B0_SPIM1_MISO>;
+			bias-disable;
+		};
+	};
+
+	pcie_default_pins: pcie-default-pins {
+		pins {
+			pinmux = <PINMUX_GPIO47__FUNC_I1_WAKEN>,
+				 <PINMUX_GPIO48__FUNC_O_PERSTN>,
+				 <PINMUX_GPIO49__FUNC_B1_CLKREQN>;
+			bias-pull-up;
+		};
+	};
+
+	ts_dsi0_goodix_pins: ts-dsi0-goodix-pins {
+		pins-irq {
+			pinmux = <PINMUX_GPIO146__FUNC_B_GPIO146>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+			input-enable;
+		};
+
+		pins-reset {
+			pinmux = <PINMUX_GPIO7__FUNC_B_GPIO7>;
+			bias-pull-down;
+		};
+	};
+
+	uart0_pins: uart0-pins {
+		pins {
+			pinmux = <PINMUX_GPIO31__FUNC_O_UTXD0>,
+				 <PINMUX_GPIO32__FUNC_I1_URXD0>;
+			bias-pull-up;
+		};
+	};
+
+	uart1_pins: uart1-pins {
+		pins {
+			pinmux = <PINMUX_GPIO33__FUNC_O_UTXD1>,
+				 <PINMUX_GPIO34__FUNC_I1_URXD1>;
+			bias-pull-up;
+		};
+	};
+
+	uart2_pins: uart2-pins {
+		pins {
+			pinmux = <PINMUX_GPIO35__FUNC_O_UTXD2>,
+				 <PINMUX_GPIO36__FUNC_I1_URXD2>;
+			bias-pull-up;
+		};
+	};
+
+	usbotg_pins: usbotg-pins {
+		pins-iddig {
+			pinmux = <PINMUX_GPIO83__FUNC_B_GPIO83>;
+			input-enable;
+			bias-pull-up;
+		};
+
+		pins-valid {
+			pinmux = <PINMUX_GPIO85__FUNC_I0_VBUSVALID>;
+			input-enable;
+		};
+
+		pins-vbus {
+			pinmux = <PINMUX_GPIO84__FUNC_O_USB_DRVVBUS>;
+			output-high;
+		};
+	};
+
+	usb1_hub_pins: usb1-hub-pins {
+		pins {
+			pinmux = <PINMUX_GPIO147__FUNC_B_GPIO147>;
+			output-low;
+		};
+	};
+
+	usb1_pins: usb1-pins {
+		pins {
+			pinmux = <PINMUX_GPIO88__FUNC_I0_VBUSVALID_1P>;
+			input-enable;
+		};
+	};
+
+	usb2_eth_pins: usb2-eth-pins {
+		pins {
+			pinmux = <PINMUX_GPIO80__FUNC_B_GPIO80>;
+			output-low;
+		};
+	};
+
+	wifi_pwrseq_pins: wifi-pwrseq-pins {
+		pins {
+			pinmux = <PINMUX_GPIO89__FUNC_B_GPIO89>;
+			output-low;
+		};
+	};
+
+	watchdog_pins: watchdog-pins {
+		pins {
+			pinmux = <PINMUX_GPIO100__FUNC_O_WATCHDOG>;
+			bias-pull-up;
+		};
+	};
+};
-- 
2.43.0



From ying.huang at linux.alibaba.com  Mon Dec  1 00:42:50 2025
From: ying.huang at linux.alibaba.com (Huang, Ying)
Date: Mon, 01 Dec 2025 16:42:50 +0800
Subject: [PATCH] arm64: mm: Fix kexec failure after pte_mkwrite_novma()
 change
In-Reply-To: <ac172927-1475-464c-b925-5fec2cfa1b1e@windriver.com> (Jianpeng
	Chang's message of "Mon, 1 Dec 2025 15:54:37 +0800")
References: <20251127034350.3600454-1-jianpeng.chang.cn@windriver.com>
	<87qztiec4e.fsf@DESKTOP-5N7EMDA>
	<ac172927-1475-464c-b925-5fec2cfa1b1e@windriver.com>
Message-ID: <87v7iqh9th.fsf@DESKTOP-5N7EMDA>

Jianpeng Chang <jianpeng.chang.cn at windriver.com> writes:

> On 11/28/25 5:32 PM, Huang, Ying wrote:
>> CAUTION: This email comes from a non Wind River email account!
>> Do not click links or open attachments unless you recognize the sender and know the content is safe.
>>
>> Hi, Jianpeng,
>>
>> Jianpeng Chang <jianpeng.chang.cn at windriver.com> writes:
>>
>>> Commit 143937ca51cc ("arm64, mm: avoid always making PTE dirty in
>>> pte_mkwrite()") modified pte_mkwrite_novma() to only clear PTE_RDONLY
>>> when the page is already dirty (PTE_DIRTY is set). While this optimization
>>> prevents unnecessary dirty page marking in normal memory management paths,
>>> it breaks kexec on some platforms like NXP LS1043.
>>>
>>> The issue occurs in the kexec code path:
>>> 1. machine_kexec_post_load() calls trans_pgd_create_copy() to create a
>>>     writable copy of the linear mapping
>>> 2. _copy_pte() calls pte_mkwrite_novma() to ensure all pages in the copy
>>>     are writable for the new kernel image copying
>>> 3. With the new logic, clean pages (without PTE_DIRTY) remain read-only
>>> 4. When kexec tries to copy the new kernel image through the linear
>>>     mapping, it fails on read-only pages, causing the system to hang
>>>     after "Bye!"
>>>
>>> The same issue affects hibernation which uses the same trans_pgd code path.
>>>
>>> Fix this by explicitly clearing PTE_RDONLY in _copy_pte() for both
>>> kexec and hibernation, ensuring all pages in the temporary mapping are
>>> writable regardless of their dirty state. This preserves the original
>>> commit's optimization for normal memory management while fixing the
>>> kexec/hibernation regression.
>>>
>>> Fixes: 143937ca51cc ("arm64, mm: avoid always making PTE dirty in pte_mkwrite()")
>> IMHO, this isn't the right "Fixes" tag.  The original _copy_pte() code
>> should be the fixing target.
>
> Hi Ying,
>
> According to my understanding, the Fixes tag should point to the
> commit that directly
>
> introduced the issue. While _copy_pte() was introduced with
> pte_mkwrite_novma() in
>
> commit 6ecc21bb432d, at that time pte_mkwrite_novma() always cleared
> the PTE_RDONLY

Per my understanding, that is not correct to clearing PTE_RDONLY in
pte_mkwrite_novma() in the first place.

However, "Fixes" flag is used for patch backporting too.  For that, the
original tag is better.  So, It's OK for me now.

> bit unconditionally, and kexec worked correctly. Should we blame a
> change that was
>
> working properly at the time, or am I missing something here?
>
>>
>>> Signed-off-by: Jianpeng Chang <jianpeng.chang.cn at windriver.com>
>>> ---
>>>   arch/arm64/mm/trans_pgd.c | 12 ++++++++++--
>>>   1 file changed, 10 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/arch/arm64/mm/trans_pgd.c b/arch/arm64/mm/trans_pgd.c
>>> index 18543b603c77..ad4e5e4fcc91 100644
>>> --- a/arch/arm64/mm/trans_pgd.c
>>> +++ b/arch/arm64/mm/trans_pgd.c
>>> @@ -40,8 +40,13 @@ static void _copy_pte(pte_t *dst_ptep, pte_t *src_ptep, unsigned long addr)
>>>                 * Resume will overwrite areas that may be marked
>>>                 * read only (code, rodata). Clear the RDONLY bit from
>>>                 * the temporary mappings we use during restore.
>>> +              *
>>> +              * For kexec/hibernation, we need writable access regardless
>>> +              * of the page's dirty state, so force clear PTE_RDONLY.
>>>                 */
>>> -             __set_pte(dst_ptep, pte_mkwrite_novma(pte));
>>> +             pte = set_pte_bit(pte, __pgprot(PTE_WRITE));
>>> +             pte = clear_pte_bit(pte, __pgprot(PTE_RDONLY));
>>> +             __set_pte(dst_ptep, pte);
>> Why not
>>
>>          __set_pte(dst_ptep, pte_mkwrite_novma(pte_mkdirty(pte));
> I agree that using pte_mkdirty() is indeed better, makes the
> modification clearer and avoids the helper function. I will change it.

Thanks!

>> ?
>>
>>>        } else if (!pte_none(pte)) {
>>>                /*
>>>                 * debug_pagealloc will removed the PTE_VALID bit if
>>> @@ -57,7 +62,10 @@ static void _copy_pte(pte_t *dst_ptep, pte_t *src_ptep, unsigned long addr)
>>>                 */
>>>                BUG_ON(!pfn_valid(pte_pfn(pte)));
>>>
>>> -             __set_pte(dst_ptep, pte_mkvalid(pte_mkwrite_novma(pte)));
>>> +             pte = pte_mkvalid(pte);
>>> +             pte = set_pte_bit(pte, __pgprot(PTE_WRITE));
>>> +             pte = clear_pte_bit(pte, __pgprot(PTE_RDONLY));
>>> +             __set_pte(dst_ptep, pte);
>>>        }
>>>   }

---
Best Regards,
Huang, Ying


From krzk at kernel.org  Mon Dec  1 00:50:07 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 1 Dec 2025 09:50:07 +0100
Subject: [PATCH 1/5] dt-bindings: vendor-prefixes: Add Ezurio LLC
In-Reply-To: <20251201084140.376058-2-bisson.gary@gmail.com>
References: <20251201084140.376058-1-bisson.gary@gmail.com>
 <20251201084140.376058-2-bisson.gary@gmail.com>
Message-ID: <f9e30721-a636-41dc-93ab-ca960e0415ab@kernel.org>

On 01/12/2025 09:41, Gary Bisson wrote:
> Ezurio is the new name of Laird Connectivity after it acquired Boundary
> Devices.
> 
> Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
> ---
> Cc: robh at kernel.org
> Cc: krzk+dt at kernel.org

Why only two of us? Please don't work on old kernels, some ancient code.

Please use scripts/get_maintainers.pl to get a list of necessary people
and lists to CC (and consider --no-git-fallback argument, so you will
not CC people just because they made one commit years ago). It might
happen, that command when run on an older kernel, gives you outdated
entries. Therefore please be sure you base your patches on recent Linux
kernel.

Tools like b4 or scripts/get_maintainer.pl provide you proper list of
people, so fix your workflow. Tools might also fail if you work on some
ancient tree (don't, instead use mainline) or work on fork of kernel
(don't, instead use mainline). Just use b4 and everything should be
fine, although remember about `b4 prep --auto-to-cc` if you added new
patches to the patchset.

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>



Best regards,
Krzysztof


From krzk at kernel.org  Mon Dec  1 00:51:04 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 1 Dec 2025 09:51:04 +0100
Subject: [PATCH 2/5] dt-bindings: arm: mediatek: Add
 ezurio,mt8370-tungsten-smarc
In-Reply-To: <20251201084140.376058-3-bisson.gary@gmail.com>
References: <20251201084140.376058-1-bisson.gary@gmail.com>
 <20251201084140.376058-3-bisson.gary@gmail.com>
Message-ID: <c6397239-2882-486d-a6e9-b8117a5c2fc6@kernel.org>

On 01/12/2025 09:41, Gary Bisson wrote:
> Add device tree bindings support for the Ezurio Tungsten 510 (MT8370)
> SMARC SOM [1] + Universal SMARC carrier board [2].
> 
> [1] https://www.ezurio.com/product/tungsten510-smarc
> [2]

Don't wrap lines

> https://www.ezurio.com/system-on-module/accessories/universal-smarc-carrier
> 
> Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
> ---
> Cc: robh at kernel.org
> Cc: krzk+dt at kernel.org
> Cc: conor+dt at kernel.org

And here Conor? Just use b4.

Anyway, please squash this and 3/5, it's just churn if boards are
per-commit.


Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof


From krzk at kernel.org  Mon Dec  1 00:53:03 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 1 Dec 2025 09:53:03 +0100
Subject: [PATCH 4/5] arm64: dts: mediatek: add device tree for Tungsten
 510 board
In-Reply-To: <20251201084140.376058-5-bisson.gary@gmail.com>
References: <20251201084140.376058-1-bisson.gary@gmail.com>
 <20251201084140.376058-5-bisson.gary@gmail.com>
Message-ID: <29ad8354-231d-470e-a899-cb7c42754c8c@kernel.org>

On 01/12/2025 09:41, Gary Bisson wrote:
> +
> +&i2c_mux_lcd_2 {
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +
> +	bridge at 2c {
> +		compatible = "ti,sn65dsi84";
> +		reg = <0x2c>;
> +		enable-gpios = <&pio 25 GPIO_ACTIVE_HIGH>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&dsi0_sn65dsi84_pins>;
> +		status = "okay";

Did you disable it anywhere?


...


> +
> +&spmi {
> +	#address-cells = <1>;
> +	#size-cells = <2>;
> +
> +	mt6315_6: mt6315 at 6 {

Node names should be generic. See also an explanation and list of
examples (not exhaustive) in DT specification:
https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation
If you cannot find a name matching your device, please check in kernel
sources for similar cases or you can grow the spec (via pull request to
DT spec repo).

e.g. pmic

> +		compatible = "mediatek,mt6315-regulator";
> +		reg = <0x6 0 0xb>;



Best regards,
Krzysztof


From chaoyi.chen at rock-chips.com  Mon Dec  1 00:54:20 2025
From: chaoyi.chen at rock-chips.com (Chaoyi Chen)
Date: Mon, 1 Dec 2025 16:54:20 +0800
Subject: [PATCH v2 1/2] dt-bindings: iommu: rockchip: Add support for
 multiple interface clocks
In-Reply-To: <491560f1-ee50-43ef-b258-adb5859cb05a@kernel.org>
References: <20251128071322.92-1-kernel@airkyi.com>
 <20251128071322.92-2-kernel@airkyi.com>
 <96958186-0e46-4606-ae36-239112eb31ea@kernel.org>
 <98a847f7-0880-4e5b-a946-26dc81fde5d2@rock-chips.com>
 <491560f1-ee50-43ef-b258-adb5859cb05a@kernel.org>
Message-ID: <8ac259e2-c075-4a29-827e-315ad84c6363@rock-chips.com>

On 12/1/2025 4:39 PM, Krzysztof Kozlowski wrote:
> On 01/12/2025 09:10, Chaoyi Chen wrote:
>>>> +  - if:
>>>> +      properties:
>>>> +        compatible:
>>>> +          items:
>>>> +            - const: rockchip,iommu
>>>> +            - const: rockchip,rk3568-iommu
>>>> +    then:
>>>> +      properties:
>>>> +        clocks:
>>>> +          maxItems: 2
>>>
>>> Why this is unspecific now? Please look at other examples how it is
>>> done, e.g. Samsung clocks.
>>
>> I looked at some examples. Maybe it need to set both minItems and 
>> maxItems here? I'm not sure I understood your point.
> 
> Individual items were described before. Now they are not, so first item
> can be anything.
> 
> You need to define the list. If the devices have completely different
> clocks, then you would go with Samsung approach. But devices should not
> have completely different clocks, so you should define common parts in
> top-level and just narrow number of items here. maxItems is enough in
> such case.

Ah, it looks like Samsung's clock bindings rarely have common parts.
At present, there are indeed some common parts for the IOMMU clock,
but I'm not sure how other variants will change. 

I'll give this a try, thank you!

-- 
Best, 
Chaoyi


From bisson.gary at gmail.com  Mon Dec  1 00:59:55 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Mon, 1 Dec 2025 09:59:55 +0100
Subject: [PATCH 1/5] dt-bindings: vendor-prefixes: Add Ezurio LLC
In-Reply-To: <f9e30721-a636-41dc-93ab-ca960e0415ab@kernel.org>
References: <20251201084140.376058-1-bisson.gary@gmail.com>
 <20251201084140.376058-2-bisson.gary@gmail.com>
 <f9e30721-a636-41dc-93ab-ca960e0415ab@kernel.org>
Message-ID: <aS1ZCy2G03zZLH6D@owl5>

Hi,

On Mon, Dec 01, 2025 at 09:50:07AM +0100, Krzysztof Kozlowski wrote:
> On 01/12/2025 09:41, Gary Bisson wrote:
> > Ezurio is the new name of Laird Connectivity after it acquired Boundary
> > Devices.
> > 
> > Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
> > ---
> > Cc: robh at kernel.org
> > Cc: krzk+dt at kernel.org
> 
> Why only two of us? Please don't work on old kernels, some ancient code.
> 
> Please use scripts/get_maintainers.pl to get a list of necessary people
> and lists to CC (and consider --no-git-fallback argument, so you will
> not CC people just because they made one commit years ago). It might
> happen, that command when run on an older kernel, gives you outdated
> entries. Therefore please be sure you base your patches on recent Linux
> kernel.

Actually I'm using master so the get_maintainer.pl output is fine, just
wasn't using b4 and addding the CC myself, will resend with b4 and will
update the patches per your review.

> Tools like b4 or scripts/get_maintainer.pl provide you proper list of
> people, so fix your workflow. Tools might also fail if you work on some
> ancient tree (don't, instead use mainline) or work on fork of kernel
> (don't, instead use mainline). Just use b4 and everything should be
> fine, although remember about `b4 prep --auto-to-cc` if you added new
> patches to the patchset.
> 
> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Thanks for the quick review of the series.

Regards,
Gary


From christianshewitt at gmail.com  Mon Dec  1 01:03:36 2025
From: christianshewitt at gmail.com (Christian Hewitt)
Date: Mon,  1 Dec 2025 09:03:36 +0000
Subject: [PATCH] wifi: mt7601u: check multiple firmware paths
Message-ID: <20251201090336.1157193-1-christianshewitt@gmail.com>

The linux-firmware repo moved mt7601u.bin from the root folder to
the mediatek sub-folder some time ago, but not all distros create
symlinks to the old location the driver checks. Update the driver
to check for firmware in both old and new locations.

With firmware in /usr/lib/firmware/mediatek/mt7601u.bin):

kernel: mt7601u 1-1.3:1.0: ASIC revision: 76010001 MAC revision: 76010500
kernel: mt7601u 1-1.3:1.0: Direct firmware load for mt7601u.bin failed with error -2
kernel: mt7601u 1-1.3:1.0: probe with driver mt7601u failed with error -2

And with the patch:

kernel: mt7601u 1-1.3:1.0: ASIC revision: 76010001 MAC revision: 76010500
kernel: mt7601u 1-1.3:1.0: Firmware Version: 0.1.00 Build: 7640 Build time: 201302052146
kernel: mt7601u 1-1.3:1.0: EEPROM ver:0c fae:00

Signed-off-by: Christian Hewitt <christianshewitt at gmail.com>
---
The firmware was moved in [0]. Changes were requested to a previous
patch [1] but I wasn't able to find a follow-up submission from the
original author. So here's my novice attempt at the improvement.

[0] https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/commit/?id=8451c2b1d529dc1a49328ac9235d3cf5bb8a8fcb
[1] https://patchwork.kernel.org/project/linux-wireless/patch/fefcbf36f13873ae0d97438a0156b87e7e1ae64e.1684191377.git.daniel at makrotopia.org/

 drivers/net/wireless/mediatek/mt7601u/mcu.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt7601u/mcu.c b/drivers/net/wireless/mediatek/mt7601u/mcu.c
index 1b5cc271a9e1..c771bbf7952c 100644
--- a/drivers/net/wireless/mediatek/mt7601u/mcu.c
+++ b/drivers/net/wireless/mediatek/mt7601u/mcu.c
@@ -409,6 +409,11 @@ static int mt7601u_load_firmware(struct mt7601u_dev *dev)
 	const struct mt76_fw_header *hdr;
 	int len, ret;
 	u32 val;
+	const char *fw_paths[] = {
+		"mediatek/" MT7601U_FIRMWARE,
+		MT7601U_FIRMWARE,
+	};
+	int i;
 
 	mt7601u_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN |
 					 MT_USB_DMA_CFG_TX_BULK_EN));
@@ -416,7 +421,14 @@ static int mt7601u_load_firmware(struct mt7601u_dev *dev)
 	if (firmware_running(dev))
 		return firmware_request_cache(dev->dev, MT7601U_FIRMWARE);
 
-	ret = request_firmware(&fw, MT7601U_FIRMWARE, dev->dev);
+	/* Try loading firmware from multiple locations */
+	fw = NULL;
+	for (i = 0; i < ARRAY_SIZE(fw_paths); i++) {
+		ret = request_firmware(&fw, fw_paths[i], dev->dev);
+		if (ret == 0)
+			break;
+	}
+
 	if (ret)
 		return ret;
 
-- 
2.34.1


From robh at kernel.org  Mon Dec  1 01:18:30 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Mon, 01 Dec 2025 03:18:30 -0600
Subject: [PATCH v4 1/2] dt-bindings: arm: at91: add lan966 pcb8385
 board
In-Reply-To: <20251201082629.2326339-2-horatiu.vultur@microchip.com>
References: <20251201082629.2326339-1-horatiu.vultur@microchip.com>
 <20251201082629.2326339-2-horatiu.vultur@microchip.com>
Message-ID: <176458071087.2473678.8963589050190334759.robh@kernel.org>


On Mon, 01 Dec 2025 09:26:28 +0100, Horatiu Vultur wrote:
> Add documentation for Microchip LAN9668 PCB8385
> 
> Acked-by: Rob Herring (Arm) <robh at kernel.org>
> Signed-off-by: Horatiu Vultur <horatiu.vultur at microchip.com>
> ---
>  Documentation/devicetree/bindings/arm/atmel-at91.yaml | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:
Documentation/devicetree/bindings/thermal/thermal-zones.example.dtb: /example-0/soc/thermal-sensor at c263000: failed to match any schema with compatible: ['qcom,sdm845-tsens', 'qcom,tsens-v2']
Documentation/devicetree/bindings/thermal/thermal-zones.example.dtb: /example-0/soc/thermal-sensor at c263000: failed to match any schema with compatible: ['qcom,sdm845-tsens', 'qcom,tsens-v2']
Documentation/devicetree/bindings/thermal/thermal-zones.example.dtb: /example-0/soc/thermal-sensor at c265000: failed to match any schema with compatible: ['qcom,sdm845-tsens', 'qcom,tsens-v2']
Documentation/devicetree/bindings/thermal/thermal-zones.example.dtb: /example-0/soc/thermal-sensor at c265000: failed to match any schema with compatible: ['qcom,sdm845-tsens', 'qcom,tsens-v2']
Documentation/devicetree/bindings/thermal/thermal-sensor.example.dtb: /example-0/soc/thermal-sensor at c263000: failed to match any schema with compatible: ['qcom,sdm845-tsens', 'qcom,tsens-v2']
Documentation/devicetree/bindings/thermal/thermal-sensor.example.dtb: /example-0/soc/thermal-sensor at c263000: failed to match any schema with compatible: ['qcom,sdm845-tsens', 'qcom,tsens-v2']
Documentation/devicetree/bindings/thermal/thermal-sensor.example.dtb: /example-0/soc/thermal-sensor at c265000: failed to match any schema with compatible: ['qcom,sdm845-tsens', 'qcom,tsens-v2']
Documentation/devicetree/bindings/thermal/thermal-sensor.example.dtb: /example-0/soc/thermal-sensor at c265000: failed to match any schema with compatible: ['qcom,sdm845-tsens', 'qcom,tsens-v2']

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20251201082629.2326339-2-horatiu.vultur at microchip.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.



From maz at kernel.org  Mon Dec  1 01:19:17 2025
From: maz at kernel.org (Marc Zyngier)
Date: Mon, 01 Dec 2025 09:19:17 +0000
Subject: [PATCH 0/4] KVM: arm64: nv: HAF fixes
In-Reply-To: <87a503fyw2.wl-maz@kernel.org>
References: <20251128100946.74210-1-alexandru.elisei@arm.com>
	<87a503fyw2.wl-maz@kernel.org>
Message-ID: <86qztepnje.wl-maz@kernel.org>

On Sun, 30 Nov 2025 13:11:57 +0000,
Marc Zyngier <maz at kernel.org> wrote:
> 
> On Fri, 28 Nov 2025 10:09:42 +0000,
> Alexandru Elisei <alexandru.elisei at arm.com> wrote:
> > 
> > Based on kvmarm's next branch.
> > 
> > HAF support for the software translation table walker was merged while I
> > was in the process of reading the patches, so instead of comments I have
> > these few fixes.
> > 
> > One thing I didn't touch is this sequence in hyp_set_prot_attr():
> > 
> > 	if (prot & KVM_PGTABLE_PROT_X) {
> > 		/* don't set the XN bit */
> > 	} else {
> > 		attr |= KVM_PTE_LEAF_ATTR_HI_S1_XN;
> > 	}
> > 
> > If the caller is executing in nVHE mode, the translation regime is EL2,
> > which has only PrivExecute permission. Since KVM_PGTABLE_PROT_X is now the
> > union of PrivExecute and UnprivExecute, if the caller requests only the
> > UnprivExecute permission, but no PrivExecute permission, the function does
> > not return an error code and sets the PrivExecute permission.
> 
> I don't think this is a huge problem *right now*, as long as we don't
> have anything that looks like "hvhe hypervisor userspace" (yes, I
> proposed that a while ago, and haven't completely dropped the
> idea). But at the same time, the page-table code should probably be
> built to the architecture and not to the use cases.
> 
> But it also outlines a rather bad bug in the hVHE case, where we set
> the UXN bit instead of the PXN bit...
> 
> What I have in mind is something like this, untested. Thoughts?
> 
> 	M.
> 
> diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h
> index d57c12f074a40..48305118ba3c5 100644
> --- a/arch/arm64/include/asm/kvm_pgtable.h
> +++ b/arch/arm64/include/asm/kvm_pgtable.h
> @@ -88,6 +88,8 @@ typedef u64 kvm_pte_t;
>  #define KVM_PTE_LEAF_ATTR_HI_SW		GENMASK(58, 55)
>  
>  #define KVM_PTE_LEAF_ATTR_HI_S1_XN	BIT(54)
> +#define KVM_PTE_LEAF_ATTR_HI_S1_UXN	BIT(54)
> +#define KVM_PTE_LEAF_ATTR_HI_S1_PXN	BIT(53)
>  
>  #define KVM_PTE_LEAF_ATTR_HI_S2_XN	GENMASK(54, 53)
>  
> diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
> index e0bd6a0172729..cbf9b6b58e284 100644
> --- a/arch/arm64/kvm/hyp/pgtable.c
> +++ b/arch/arm64/kvm/hyp/pgtable.c
> @@ -330,6 +330,11 @@ struct hyp_map_data {
>  	kvm_pte_t			attr;
>  };
>  
> +static bool el2_nvhe(void)
> +{
> +	return !has_vhe() && !cpus_have_final_cap(ARM64_KVM_PROTECTED_MODE);

Obviously, this should read ARM64_KVM_HVHE, not PROTECTED_MODE...

	M.

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


From kevin.brodsky at arm.com  Mon Dec  1 01:19:41 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Mon, 1 Dec 2025 10:19:41 +0100
Subject: [RFC PATCH v5 11/18] mm: Introduce kpkeys_hardened_pgtables
In-Reply-To: <aSnRVJwuRWPmPxqN@e129823.arm.com>
References: <20250815085512.2182322-1-kevin.brodsky@arm.com>
 <20250815085512.2182322-12-kevin.brodsky@arm.com>
 <aSnRVJwuRWPmPxqN@e129823.arm.com>
Message-ID: <c1226873-c790-49bd-876d-4539f95b4caf@arm.com>

On 28/11/2025 17:44, Yeoreum Yun wrote:
>> +int kpkeys_protect_pgtable_memory(struct folio *folio)
>> +{
>> +	unsigned long addr = (unsigned long)folio_address(folio);
> I think it might need to use untagged_addr()?

I've never seen untagged_addr() used on folio_address()/page_address()
(see for instance set_direct_map_valid_noflush() and
__kernel_map_pages() in arch/arm64/mm/pageattr.c).

It does seem that page_to_virt() sets the tag if KASAN is enabled
though... I'm not sure what to think, is there a wider issue here? We
might just be lucky and the sort of pages that these functions are
called on don't have their KASAN tag set.

- Kevin


From yury.khrustalev at arm.com  Mon Dec  1 01:19:18 2025
From: yury.khrustalev at arm.com (Yury Khrustalev)
Date: Mon, 1 Dec 2025 09:19:18 +0000
Subject: [PATCH] arm64/gcs: Flush the GCS locking state on exec
In-Reply-To: <20251129-arm64-gcs-flush-lock-v1-1-902b3ba6f39d@kernel.org>
References: <20251129-arm64-gcs-flush-lock-v1-1-902b3ba6f39d@kernel.org>
Message-ID: <aS1dlsDcV9cpD76z@arm.com>

On Sat, Nov 29, 2025 at 12:48:45AM +0000, Mark Brown wrote:
> When we exec a new task we forget to flush the set of locked GCS mode bits.
> Since we do flush the rest of the state this means that if GCS is locked
> the new task will be unable to enable GCS, it will be locked as being
> disabled. Add the expected flush.
> 
> Fixes: fc84bc5378a8 ("arm64/gcs: Context switch GCS state for EL0")
> Reported-by: Yury Khrustalev <Yury.Khrustalev at arm.com>
> Signed-off-by: Mark Brown <broonie at kernel.org>

Thanks! I've tested this patch and it works as expected.

Tested-by: Yury Khrustalev <yury.khrustalev at arm.com>

> ---
>  arch/arm64/kernel/process.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
> index fba7ca102a8c..489554931231 100644
> --- a/arch/arm64/kernel/process.c
> +++ b/arch/arm64/kernel/process.c
> @@ -292,6 +292,7 @@ static void flush_gcs(void)
>  	current->thread.gcs_base = 0;
>  	current->thread.gcs_size = 0;
>  	current->thread.gcs_el0_mode = 0;
> +	current->thread.gcs_el0_locked = 0;
>  	write_sysreg_s(GCSCRE0_EL1_nTR, SYS_GCSCRE0_EL1);
>  	write_sysreg_s(0, SYS_GCSPR_EL0);
>  }
> 
> ---
> base-commit: ac3fd01e4c1efce8f2c054cdeb2ddd2fc0fb150d
> change-id: 20251128-arm64-gcs-flush-lock-163eab9c22f4
> 
> Best regards,
> --  
> Mark Brown <broonie at kernel.org>
> 


From robh at kernel.org  Mon Dec  1 01:33:40 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Mon, 01 Dec 2025 03:33:40 -0600
Subject: [PATCH 1/5] dt-bindings: vendor-prefixes: Add Ezurio LLC
In-Reply-To: <20251201084140.376058-2-bisson.gary@gmail.com>
References: <20251201084140.376058-1-bisson.gary@gmail.com>
 <20251201084140.376058-2-bisson.gary@gmail.com>
Message-ID: <176458161856.2489196.6170126310129033736.robh@kernel.org>


On Mon, 01 Dec 2025 09:41:36 +0100, Gary Bisson wrote:
> Ezurio is the new name of Laird Connectivity after it acquired Boundary
> Devices.
> 
> Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
> ---
> Cc: robh at kernel.org
> Cc: krzk+dt at kernel.org
> ---
>  Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
>  1 file changed, 2 insertions(+)
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:
Traceback (most recent call last):
  File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 428, in get_or_retrieve
    resource = registry._retrieve(uri)
  File "/usr/local/lib/python3.13/dist-packages/dtschema/validator.py", line 426, in retrieve
    return DRAFT201909.create_resource(self.schemas[uri])
                                       ~~~~~~~~~~~~^^^^^
KeyError: 'http://devicetree.org/schemas/thermal/qcom-tsens.yaml'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 682, in lookup
    retrieved = self._registry.get_or_retrieve(uri)
  File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 435, in get_or_retrieve
    raise exceptions.Unretrievable(ref=uri) from error
referencing.exceptions.Unretrievable: 'http://devicetree.org/schemas/thermal/qcom-tsens.yaml'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/local/lib/python3.13/dist-packages/jsonschema/validators.py", line 463, in _validate_reference
    resolved = self._resolver.lookup(ref)
  File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 686, in lookup
    raise exceptions.Unresolvable(ref=ref) from error
referencing.exceptions.Unresolvable: /schemas/thermal/qcom-tsens.yaml#

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/local/bin/dt-validate", line 8, in <module>
    sys.exit(main())
             ~~~~^^
  File "/usr/local/lib/python3.13/dist-packages/dtschema/dtb_validate.py", line 158, in main
    sg.check_dtb(filename)
    ~~~~~~~~~~~~^^^^^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/dtschema/dtb_validate.py", line 95, in check_dtb
    self.check_subtree(dt, subtree, False, "/", "/", filename)
    ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/dtschema/dtb_validate.py", line 88, in check_subtree
    self.check_subtree(tree, value, disabled, name, fullname + name, filename)
    ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/dtschema/dtb_validate.py", line 88, in check_subtree
    self.check_subtree(tree, value, disabled, name, fullname + name, filename)
    ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/dtschema/dtb_validate.py", line 83, in check_subtree
    self.check_node(tree, subtree, disabled, nodename, fullname, filename)
    ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/dtschema/dtb_validate.py", line 34, in check_node
    for error in self.validator.iter_errors(node, filter=match_schema_file,
                 ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                            compatible_match=compatible_match):
                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/dtschema/validator.py", line 448, in iter_errors
    for error in self.DtValidator(schema, registry=self.registry).iter_errors(instance):
                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/jsonschema/validators.py", line 384, in iter_errors
    for error in errors:
                 ^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/jsonschema/_keywords.py", line 296, in properties
    yield from validator.descend(
    ...<4 lines>...
    )
  File "/usr/local/lib/python3.13/dist-packages/jsonschema/validators.py", line 432, in descend
    for error in errors:
                 ^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/jsonschema/_keywords.py", line 275, in ref
    yield from validator._validate_reference(ref=ref, instance=instance)
               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/jsonschema/validators.py", line 465, in _validate_reference
    raise exceptions._WrappedReferencingError(err) from err
jsonschema.exceptions._WrappedReferencingError: Unresolvable: /schemas/thermal/qcom-tsens.yaml#
Traceback (most recent call last):
  File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 428, in get_or_retrieve
    resource = registry._retrieve(uri)
  File "/usr/local/lib/python3.13/dist-packages/dtschema/validator.py", line 426, in retrieve
    return DRAFT201909.create_resource(self.schemas[uri])
                                       ~~~~~~~~~~~~^^^^^
KeyError: 'http://devicetree.org/schemas/thermal/qcom-tsens.yaml'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 682, in lookup
    retrieved = self._registry.get_or_retrieve(uri)
  File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 435, in get_or_retrieve
    raise exceptions.Unretrievable(ref=uri) from error
referencing.exceptions.Unretrievable: 'http://devicetree.org/schemas/thermal/qcom-tsens.yaml'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/local/lib/python3.13/dist-packages/jsonschema/validators.py", line 463, in _validate_reference
    resolved = self._resolver.lookup(ref)
  File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 686, in lookup
    raise exceptions.Unresolvable(ref=ref) from error
referencing.exceptions.Unresolvable: /schemas/thermal/qcom-tsens.yaml#

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/local/bin/dt-validate", line 8, in <module>
    sys.exit(main())
             ~~~~^^
  File "/usr/local/lib/python3.13/dist-packages/dtschema/dtb_validate.py", line 158, in main
    sg.check_dtb(filename)
    ~~~~~~~~~~~~^^^^^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/dtschema/dtb_validate.py", line 95, in check_dtb
    self.check_subtree(dt, subtree, False, "/", "/", filename)
    ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/dtschema/dtb_validate.py", line 88, in check_subtree
    self.check_subtree(tree, value, disabled, name, fullname + name, filename)
    ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/dtschema/dtb_validate.py", line 88, in check_subtree
    self.check_subtree(tree, value, disabled, name, fullname + name, filename)
    ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/dtschema/dtb_validate.py", line 83, in check_subtree
    self.check_node(tree, subtree, disabled, nodename, fullname, filename)
    ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/dtschema/dtb_validate.py", line 34, in check_node
    for error in self.validator.iter_errors(node, filter=match_schema_file,
                 ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                            compatible_match=compatible_match):
                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/dtschema/validator.py", line 448, in iter_errors
    for error in self.DtValidator(schema, registry=self.registry).iter_errors(instance):
                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/jsonschema/validators.py", line 384, in iter_errors
    for error in errors:
                 ^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/jsonschema/_keywords.py", line 296, in properties
    yield from validator.descend(
    ...<4 lines>...
    )
  File "/usr/local/lib/python3.13/dist-packages/jsonschema/validators.py", line 432, in descend
    for error in errors:
                 ^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/jsonschema/_keywords.py", line 334, in allOf
    yield from validator.descend(instance, subschema, schema_path=index)
  File "/usr/local/lib/python3.13/dist-packages/jsonschema/validators.py", line 432, in descend
    for error in errors:
                 ^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/jsonschema/_keywords.py", line 275, in ref
    yield from validator._validate_reference(ref=ref, instance=instance)
               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/jsonschema/validators.py", line 465, in _validate_reference
    raise exceptions._WrappedReferencingError(err) from err
jsonschema.exceptions._WrappedReferencingError: Unresolvable: /schemas/thermal/qcom-tsens.yaml#

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20251201084140.376058-2-bisson.gary at gmail.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.



From robh at kernel.org  Mon Dec  1 01:33:42 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Mon, 01 Dec 2025 03:33:42 -0600
Subject: [PATCH 2/5] dt-bindings: arm: mediatek: Add
 ezurio,mt8370-tungsten-smarc
In-Reply-To: <20251201084140.376058-3-bisson.gary@gmail.com>
References: <20251201084140.376058-1-bisson.gary@gmail.com>
 <20251201084140.376058-3-bisson.gary@gmail.com>
Message-ID: <176458161959.2489238.15712230014248139528.robh@kernel.org>


On Mon, 01 Dec 2025 09:41:37 +0100, Gary Bisson wrote:
> Add device tree bindings support for the Ezurio Tungsten 510 (MT8370)
> SMARC SOM [1] + Universal SMARC carrier board [2].
> 
> [1] https://www.ezurio.com/product/tungsten510-smarc
> [2]
> https://www.ezurio.com/system-on-module/accessories/universal-smarc-carrier
> 
> Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
> ---
> Cc: robh at kernel.org
> Cc: krzk+dt at kernel.org
> Cc: conor+dt at kernel.org
> Cc: matthias.bgg at gmail.com
> ---
>  Documentation/devicetree/bindings/arm/mediatek.yaml | 1 +
>  1 file changed, 1 insertion(+)
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:


doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20251201084140.376058-3-bisson.gary at gmail.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.



From robh at kernel.org  Mon Dec  1 01:33:44 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Mon, 01 Dec 2025 03:33:44 -0600
Subject: [PATCH 3/5] dt-bindings: arm: mediatek: Add
 ezurio,mt8390-tungsten-smarc
In-Reply-To: <20251201084140.376058-4-bisson.gary@gmail.com>
References: <20251201084140.376058-1-bisson.gary@gmail.com>
 <20251201084140.376058-4-bisson.gary@gmail.com>
Message-ID: <176458162056.2489271.8926442564760324805.robh@kernel.org>


On Mon, 01 Dec 2025 09:41:38 +0100, Gary Bisson wrote:
> Add device tree bindings support for the Ezurio Tungsten 700 (MT8390)
> SMARC SOM [1] + Universal SMARC carrier board [2].
> 
> [1] https://www.ezurio.com/product/tungsten700-smarc
> [2]
> https://www.ezurio.com/system-on-module/accessories/universal-smarc-carrier
> 
> Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
> ---
> Cc: robh at kernel.org
> Cc: krzk+dt at kernel.org
> Cc: conor+dt at kernel.org
> Cc: matthias.bgg at gmail.com
> ---
>  Documentation/devicetree/bindings/arm/mediatek.yaml | 1 +
>  1 file changed, 1 insertion(+)
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:


doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20251201084140.376058-4-bisson.gary at gmail.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.



From amhetre at nvidia.com  Mon Dec  1 01:36:55 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Mon, 1 Dec 2025 15:06:55 +0530
Subject: [PATCH V2 3/3] arm64: dts: nvidia: Add nodes for CMDQV
In-Reply-To: <dff3a962-82dd-4aac-ae11-69f0e95ba04d@nvidia.com>
References: <20251125071659.3048659-1-amhetre@nvidia.com>
 <20251125071659.3048659-4-amhetre@nvidia.com>
 <dff3a962-82dd-4aac-ae11-69f0e95ba04d@nvidia.com>
Message-ID: <acae92d8-3394-436c-be8e-8bed7a923e85@nvidia.com>


On 11/25/2025 3:52 PM, Jon Hunter wrote:
>
>
> On 25/11/2025 07:16, Ashish Mhetre wrote:
>> The Command Queue Virtualization (CMDQV) hardware is part of the
>> SMMUv3 implementation on NVIDIA Tegra SoCs. It assists in
>> virtualizing the command queue for the SMMU.
>>
>> Update SMMU compatible strings to use nvidia,tegra264-smmu to enable
>> CMDQV support. Add device tree nodes for the CMDQV hardware and enable
>> them on the tegra264-p3834 platform where SMMUs are enabled. Each SMMU
>> instance is paired with its corresponding CMDQV instance via the
>> nvidia,cmdqv property.
>>
>> Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
>> ---
>> ? .../arm64/boot/dts/nvidia/tegra264-p3834.dtsi |? 8 +++
>> ? arch/arm64/boot/dts/nvidia/tegra264.dtsi????? | 55 +++++++++++++++++--
>> ? 2 files changed, 58 insertions(+), 5 deletions(-)
>>
>> diff --git a/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi 
>> b/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
>> index 06795c82427a..375d122b92fa 100644
>> --- a/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
>> +++ b/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
>> @@ -26,5 +26,13 @@ iommu at 5000000 {
>> ????????? iommu at 6000000 {
>> ????????????? status = "okay";
>> ????????? };
>> +
>> +??????? cmdqv at 5200000 {
>> +??????????? status = "okay";
>> +??????? };
>
> This needs to be ordered in the file according to its address.

Hi Jon, Thanks for the review.
cmdqv nodes follow same ordering as its corresponding iommu nodes.
I have added them immediately after corresponding iommu nodes.
Can you please check and see if it's fine? Same applies to your
similar comments below as well.

>
>> +
>> +??????? cmdqv at 6200000 {
>> +??????????? status = "okay";
>> +??????? };
>> ????? };
>> ? };
>> diff --git a/arch/arm64/boot/dts/nvidia/tegra264.dtsi 
>> b/arch/arm64/boot/dts/nvidia/tegra264.dtsi
>> index f137565da804..d8287b95221e 100644
>> --- a/arch/arm64/boot/dts/nvidia/tegra264.dtsi
>> +++ b/arch/arm64/boot/dts/nvidia/tegra264.dtsi
>> @@ -3361,7 +3361,7 @@ bus at 8100000000 {
>> ?????????????? <0x02 0x00000000 0xd0 0x00000000 0x08 0x80000000>; /* 
>> ECAM, prefetchable memory, I/O */
>> ? ????????? smmu1: iommu at 5000000 {
>> -??????????? compatible = "arm,smmu-v3";
>> +??????????? compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
>> ????????????? reg = <0x00 0x5000000 0x0 0x200000>;
>> ????????????? interrupts = <GIC_SPI 12 IRQ_TYPE_EDGE_RISING>,
>> ?????????????????????? <GIC_SPI 13 IRQ_TYPE_EDGE_RISING>;
>> @@ -3370,10 +3370,11 @@ smmu1: iommu at 5000000 {
>> ? ????????????? #iommu-cells = <1>;
>> ????????????? dma-coherent;
>> +??????????? nvidia,cmdqv = <&cmdqv1>;
>> ????????? };
>> ? ????????? smmu2: iommu at 6000000 {
>> -??????????? compatible = "arm,smmu-v3";
>> +??????????? compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
>> ????????????? reg = <0x00 0x6000000 0x0 0x200000>;
>> ????????????? interrupts = <GIC_SPI 1 IRQ_TYPE_EDGE_RISING>,
>> ?????????????????????? <GIC_SPI 2 IRQ_TYPE_EDGE_RISING>;
>> @@ -3382,6 +3383,23 @@ smmu2: iommu at 6000000 {
>> ? ????????????? #iommu-cells = <1>;
>> ????????????? dma-coherent;
>> +??????????? nvidia,cmdqv = <&cmdqv2>;
>> +??????? };
>> +
>> +??????? cmdqv1: cmdqv at 5200000 {
>
> Same here. Please order according to the address.
>
>> +??????????? compatible = "nvidia,tegra264-cmdqv";
>> +??????????? status = "disabled";
>> +
>> +??????????? reg = <0x00 0x5200000 0x0 0x830000>;
>> +??????????? interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
>> +??????? };
>> +
>> +??????? cmdqv2: cmdqv at 6200000 {
>> +??????????? compatible = "nvidia,tegra264-cmdqv";
>> +??????????? status = "disabled";
>> +
>> +??????????? reg = <0x00 0x6200000 0x0 0x830000>;
>> +??????????? interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
>> ????????? };
>> ? ????????? mc: memory-controller at 8020000 {
>> @@ -3437,7 +3455,7 @@ emc: external-memory-controller at 8800000 {
>> ????????? };
>> ? ????????? smmu0: iommu at a000000 {
>> -??????????? compatible = "arm,smmu-v3";
>> +??????????? compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
>> ????????????? reg = <0x00 0xa000000 0x0 0x200000>;
>> ????????????? interrupts = <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>,
>> ?????????????????????? <GIC_SPI 22 IRQ_TYPE_EDGE_RISING>;
>> @@ -3446,10 +3464,11 @@ smmu0: iommu at a000000 {
>> ? ????????????? #iommu-cells = <1>;
>> ????????????? dma-coherent;
>> +??????????? nvidia,cmdqv = <&cmdqv0>;
>> ????????? };
>> ? ????????? smmu4: iommu at b000000 {
>> -??????????? compatible = "arm,smmu-v3";
>> +??????????? compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
>> ????????????? reg = <0x00 0xb000000 0x0 0x200000>;
>> ????????????? interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
>> ?????????????????????? <GIC_SPI 31 IRQ_TYPE_EDGE_RISING>;
>> @@ -3458,6 +3477,23 @@ smmu4: iommu at b000000 {
>> ? ????????????? #iommu-cells = <1>;
>> ????????????? dma-coherent;
>> +??????????? nvidia,cmdqv = <&cmdqv4>;
>> +??????? };
>> +
>> +??????? cmdqv0: cmdqv at a200000 {
>
> And here.
>
>> +??????????? compatible = "nvidia,tegra264-cmdqv";
>> +??????????? status = "disabled";
>> +
>> +??????????? reg = <0x00 0xa200000 0x0 0x830000>;
>> +??????????? interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
>> +??????? };
>> +
>> +??????? cmdqv4: cmdqv at b200000 {
>> +??????????? compatible = "nvidia,tegra264-cmdqv";
>> +??????????? status = "disabled";
>> +
>> +??????????? reg = <0x00 0xb200000 0x0 0x830000>;
>> +??????????? interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
>> ????????? };
>> ? ????????? i2c14: i2c at c410000 {
>> @@ -3690,7 +3726,7 @@ bus at 8800000000 {
>> ????????? ranges = <0x00 0x00000000 0x88 0x00000000 0x01 0x00000000>;
>> ? ????????? smmu3: iommu at 6000000 {
>> -??????????? compatible = "arm,smmu-v3";
>> +??????????? compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
>> ????????????? reg = <0x00 0x6000000 0x0 0x200000>;
>> ????????????? interrupts = <GIC_SPI 225 IRQ_TYPE_EDGE_RISING>,
>> ?????????????????????? <GIC_SPI 226 IRQ_TYPE_EDGE_RISING>;
>> @@ -3699,6 +3735,15 @@ smmu3: iommu at 6000000 {
>> ? ????????????? #iommu-cells = <1>;
>> ????????????? dma-coherent;
>> +??????????? nvidia,cmdqv = <&cmdqv3>;
>> +??????? };
>> +
>> +??????? cmdqv3: cmdqv at 6200000 {
>> +??????????? compatible = "nvidia,tegra264-cmdqv";
>> +??????????? status = "disabled";
>> +
>> +??????????? reg = <0x00 0x6200000 0x0 0x830000>;
>> +??????????? interrupts = <GIC_SPI 232 IRQ_TYPE_LEVEL_HIGH>;
>> ????????? };
>> ? ????????? hda at 90b0000 {
>


From visitorckw at gmail.com  Mon Dec  1 01:52:28 2025
From: visitorckw at gmail.com (Kuan-Wei Chiu)
Date: Mon,  1 Dec 2025 09:52:28 +0000
Subject: [PATCH v2] coresight: etm3x: Fix cntr_val_show() to match cntr_val_store() behavior
Message-ID: <20251201095228.1905489-1-visitorckw@gmail.com>

The cntr_val_show() function was intended to print the values of all
counters using a loop. However, due to a buffer overwrite issue with
sprintf(), it effectively only displayed the value of the last counter.

The companion function, cntr_val_store(), allows users to modify a
specific counter selected by 'cntr_idx'. To maintain consistency
between read and write operations and to align with the ETM4x driver
behavior, modify cntr_val_show() to report only the value of the
currently selected counter.

This change removes the loop and the "counter %d:" prefix, printing
only the hexadecimal value. It also adopts sysfs_emit() for standard
sysfs output formatting.

Fixes: a939fc5a71ad ("coresight-etm: add CoreSight ETM/PTM driver")
Signed-off-by: Kuan-Wei Chiu <visitorckw at gmail.com>
---
Build test only.

Changes in v2:
- Redesigned the fix to match cntr_val_store() logic (display only the
  currently selected counter) instead of attempting to list all
  counters.
- Removed the loop and the "counter %d:" prefix.
- Switched from sprintf() to sysfs_emit().
- Refactored control flow to use a single return point.

v1: https://lore.kernel.org/lkml/20251121002350.1166758-1-visitorckw at gmail.com/

 .../hwtracing/coresight/coresight-etm3x-sysfs.c   | 15 ++++-----------
 1 file changed, 4 insertions(+), 11 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
index 762109307b86..a6a650331196 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
@@ -717,26 +717,19 @@ static DEVICE_ATTR_RW(cntr_rld_event);
 static ssize_t cntr_val_show(struct device *dev,
 			     struct device_attribute *attr, char *buf)
 {
-	int i, ret = 0;
 	u32 val;
 	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	struct etm_config *config = &drvdata->config;
 
 	if (!coresight_get_mode(drvdata->csdev)) {
 		spin_lock(&drvdata->spinlock);
-		for (i = 0; i < drvdata->nr_cntr; i++)
-			ret += sprintf(buf, "counter %d: %x\n",
-				       i, config->cntr_val[i]);
+		val = config->cntr_val[config->cntr_idx];
 		spin_unlock(&drvdata->spinlock);
-		return ret;
-	}
-
-	for (i = 0; i < drvdata->nr_cntr; i++) {
-		val = etm_readl(drvdata, ETMCNTVRn(i));
-		ret += sprintf(buf, "counter %d: %x\n", i, val);
+	} else {
+		val = etm_readl(drvdata, ETMCNTVRn(config->cntr_idx));
 	}
 
-	return ret;
+	return sysfs_emit(buf, "%x\n", val);
 }
 
 static ssize_t cntr_val_store(struct device *dev,
-- 
2.52.0.487.g5c8c507ade-goog



From youngmin.nam at samsung.com  Mon Dec  1 01:54:59 2025
From: youngmin.nam at samsung.com (Youngmin Nam)
Date: Mon, 1 Dec 2025 18:54:59 +0900
Subject: [PATCH v7 RESEND 2/3] thermal: exynos_tmu: Support new hardware
 and update TMU interface
In-Reply-To: <401ed9b9-19a4-4a19-b397-0f353e9f0c97@linaro.org>
References: <20251113064022.2701578-1-shin.son@samsung.com>
	<CGME20251113064044epcas2p1b87addb21473eca7cc52052e4e2e9237@epcas2p1.samsung.com>
	<20251113064022.2701578-3-shin.son@samsung.com>
	<5a6a749b-b2b7-41bb-bcb4-a2342e7f4e98@linaro.org>
	<015501dc5ea5$0c7dd460$25797d20$@samsung.com>
	<401ed9b9-19a4-4a19-b397-0f353e9f0c97@linaro.org>
Message-ID: <c3cc4b6f-ac75-448e-9fdf-c3c45e2ceed7@samsung.com>

On 11/26/25 18:21, Tudor Ambarus wrote:
> Hi, Shin Son,
> 
> On 11/26/25 9:19 AM, ?? wrote:
>>> Looking at the exynosautov9 registers that you described and comparing
>>> them with
>>> gs101 I see just 2 differences:
>>> 1/ exnosautov2 has a TRIMINFO_CONFIG2 register, while gs101 doesn't 2/
>>> EXYNOSAUTOV920_PEND register fields differ from GS101
>> TRIMINFO_CONFIG2 doesn't exist on eav920 either; I simply misnamed it.
>> However, the PEND register indeed differs from GS101.
>>
>>> Given the similarities, and considering the EXYNOS9_ registers rename from:
>>> https://lore.kernel.org/linux-samsung-soc/20251117074140.4090939-5-
>>> youngmin.nam at samsung.com/
>>> would it make sense to use the SoC-era name instead of specific SoC, i.e.
>>> s/EXYNOSAUTOV920_/EXYNOS9_ and use the latter for both exynosautov9 and
>>> gs101?
>>>
>> First of all, as far as I know, EXYNOS9 is not the same as exynosautov9, and exynosautov920 also differs from exynosautov9.
> 
> See also see this patch, or maybe the entire patch set:
> https://lore.kernel.org/linux-samsung-soc/20251117074140.4090939-2-youngmin.nam at samsung.com/
> 
> It's not just autov9 and gs101 that have similar TMU registers (with the two
> exceptions AFAICT), it's also exynos850 that seems identical with autov9.
> 
> All seem to be part of the same "Exynos9-era" SoCs. Let's think about how
> gs101/exynos850 TMU addition will follow. Shall one use the EXYNOSAUTOV920
> registers? That seems misleading. Shall one redefine the entire register set?
> That won't fly because of the code duplication.
> 
> Thus I propose to use the EXYNOS9 prefix for the register definitions, and if
> there are SoCs with slight differences, that can be handled with compatible
> match data and specific SoC definitions, but only where things differ.
> 
>> So while sharing a common prefix is a good suggestion in general, I believe it's not appropriate here
>> Because the register definitions are not fully compatible across these SoCs. Using a common name array may introduce confusion later.
> 
> Please reconsider this. Maybe Youngmin Nam or others can intervene.
> 
> Thanks!
> ta
> 
Hi Tudor,

First, thank you for referencing my pinctrl patch and asking for my input.
Yes. That's exactly my intent. Use the EXYNOS9 prefix to minimize fragmentation.

Even if some registers aren't fully compatible,
I'd prefer to maximize the common EXYNOS9 definitions and handle SoC-specific differences via match data or small deltas,
rather than introducing SoC-specific register names.

Hi Shin Son,
if possible, please consider this approach as well.

Thanks,
Youngmin


From leitao at debian.org  Mon Dec  1 01:53:30 2025
From: leitao at debian.org (Breno Leitao)
Date: Mon, 1 Dec 2025 01:53:30 -0800
Subject: [PATCH] arm64: kernel: initialize missing kexec_buf->random field
In-Reply-To: <aS0Ch3hrYPDXomDC@MiWiFi-R3L-srv>
References: <20251127182644.1577592-1-yeoreum.yun@arm.com>
 <20251127113706.d89a84f277dab3ad273dde75@linux-foundation.org>
 <aSjqEQDv7V79V3Na@MiWiFi-R3L-srv>
 <5wel6vqjwwf25hryvg6s7z6aaog7xc3zxjevupt3jn4gntme6d@74wwwmhvvelt>
 <aSmrUGnZp0UeTp1E@J2N7QTR9R3>
 <aS0Ch3hrYPDXomDC@MiWiFi-R3L-srv>
Message-ID: <j2ilxmuhlgu5dwswl3qk7rbzmbk25qn4s2tidhdy4uy7dzfcnn@6ulgmdw4effw>

On Mon, Dec 01, 2025 at 10:50:47AM +0800, Baoquan He wrote:
> On 11/28/25 at 02:01pm, Mark Rutland wrote:
> > FWIW, I completey agree; your proposal is a much better solution.
> 
> Yes, maybe Yeoreum or Breno can post a new version to fix it on arm64.

Yeoreum, would you be ok doing the patch? If you are busy, I can do it.

Thanks
--breno


From mark.rutland at arm.com  Mon Dec  1 01:54:25 2025
From: mark.rutland at arm.com (Mark Rutland)
Date: Mon, 1 Dec 2025 09:54:25 +0000
Subject: [PATCH] arm64: kernel: initialize missing kexec_buf->random field
In-Reply-To: <aS0Ch3hrYPDXomDC@MiWiFi-R3L-srv>
References: <20251127182644.1577592-1-yeoreum.yun@arm.com>
 <20251127113706.d89a84f277dab3ad273dde75@linux-foundation.org>
 <aSjqEQDv7V79V3Na@MiWiFi-R3L-srv>
 <5wel6vqjwwf25hryvg6s7z6aaog7xc3zxjevupt3jn4gntme6d@74wwwmhvvelt>
 <aSmrUGnZp0UeTp1E@J2N7QTR9R3>
 <aS0Ch3hrYPDXomDC@MiWiFi-R3L-srv>
Message-ID: <aS1l0QqJSebgCg6f@J2N7QTR9R3>

On Mon, Dec 01, 2025 at 10:50:47AM +0800, Baoquan He wrote:
> On 11/28/25 at 02:01pm, Mark Rutland wrote:
> > On Fri, Nov 28, 2025 at 05:55:05AM -0800, Breno Leitao wrote:
> > > 
> > > On Fri, Nov 28, 2025 at 08:17:21AM +0800, Baoquan He wrote:
> > > > On 11/27/25 at 11:37am, Andrew Morton wrote:
> > > > > On Thu, 27 Nov 2025 18:26:44 +0000 Yeoreum Yun <yeoreum.yun at arm.com> wrote:
> > > > > 
> > > > > > Commit bf454ec31add ("kexec_file: allow to place kexec_buf randomly")
> > > > > > introduced the kexec_buf->random field to enable random placement of
> > > > > > kexec_buf.
> > > > > > 
> > > > > > However, this field was never properly initialized for kexec images
> > > > > > that do not need to be placed randomly, leading to the following UBSAN
> > > > > > warning:
> > > > > > 
> > > > > > [  +0.364528] ------------[ cut here ]------------
> > > > > > [  +0.000019] UBSAN: invalid-load in ./include/linux/kexec.h:210:12
> > > > > > [  +0.000131] load of value 2 is not a valid value for type 'bool' (aka '_Bool')
> > > > > > [  +0.000003] CPU: 4 UID: 0 PID: 927 Comm: kexec Not tainted 6.18.0-rc7+ #3 PREEMPT(full)
> > > > > > [  +0.000002] Hardware name: QEMU QEMU Virtual Machine, BIOS 0.0.0 02/06/2015
> > > > > > [  +0.000000] Call trace:
> > > > > > [  +0.000001]  show_stack+0x24/0x40 (C)
> > > > > > [  +0.000006]  __dump_stack+0x28/0x48
> > > > > > [  +0.000002]  dump_stack_lvl+0x7c/0xb0
> > > > > > [  +0.000002]  dump_stack+0x18/0x34
> > > > > > [  +0.000001]  ubsan_epilogue+0x10/0x50
> > > > > > [  +0.000002]  __ubsan_handle_load_invalid_value+0xc8/0xd0
> > > > > > [  +0.000003]  locate_mem_hole_callback+0x28c/0x2a0
> > > > > > [  +0.000003]  kexec_locate_mem_hole+0xf4/0x2f0
> > > > > > [  +0.000001]  kexec_add_buffer+0xa8/0x178
> > > > > > [  +0.000002]  image_load+0xf0/0x258
> > > > > > [  +0.000001]  __arm64_sys_kexec_file_load+0x510/0x718
> > > > > > [  +0.000002]  invoke_syscall+0x68/0xe8
> > > > > > [  +0.000001]  el0_svc_common+0xb0/0xf8
> > > > > > [  +0.000002]  do_el0_svc+0x28/0x48
> > > > > > [  +0.000001]  el0_svc+0x40/0xe8
> > > > > > [  +0.000002]  el0t_64_sync_handler+0x84/0x140
> > > > > > [  +0.000002]  el0t_64_sync+0x1bc/0x1c0
> > > > > > 
> > > > > > To address this, initialise kexec_buf->random field properly.
> > > > > > 
> > > > > > Fixes: bf454ec31add ("kexec_file: allow to place kexec_buf randomly")
> > > > > 
> > > > > Thanks, I'll add a cc:stable to this.
> > > > 
> > > > This has been fixed in below series from Breno Leitao.
> > > > 
> > > > [PATCH 0/3] kexec: Fix invalid field access
> > > > https://lore.kernel.org/all/20250827-kbuf_all-v1-0-1df9882bb01a at debian.org/T/#u
> > > 
> > > Right, these fixes are on 6.18 since day one.
> > > 
> > > Yeoreum is hitting another code path that I haven't fixed, it seems
> > > (through image_load()).
> > > 
> > > That said, I think the fix should be similar to commit 04d3cd43700 ("arm64:
> > > kexec: initialize kexec_buf struct in load_other_segments()"). I.e:
> > > 
> > > 	--- a/arch/arm64/kernel/kexec_image.c
> > > 	+++ b/arch/arm64/kernel/kexec_image.c
> > > 	@@ -41,7 +41,7 @@ static void *image_load(struct kimage *image,
> > > 		struct arm64_image_header *h;
> > > 		u64 flags, value;
> > > 		bool be_image, be_kernel;
> > > 	-       struct kexec_buf kbuf;
> > > 	+       struct kexec_buf kbuf = {};
> > > 		unsigned long text_offset, kernel_segment_number;
> > > 		struct kexec_segment *kernel_segment;
> > > 		int ret;
> > 
> > FWIW, I completey agree; your proposal is a much better solution.
> 
> Yes, maybe Yeoreum or Breno can post a new version to fix it on arm64.

Yep; I hope that Yeoreum will spin a v2 to that effect.

> > From a quick scan, it looks like loongarch also has some more dodgy
> > instances:
> 
> In the latest mainline kernel, the problem on loongarch has gone.

Ah, yep, all the loongarch instances were fixed in v6.18-rc6 by commit:

  df16b8956cae9700 ("LoongArch: kexec: Initialize the kexec_buf structure")

Mark.


From ian.ray at gehealthcare.com  Mon Dec  1 01:56:05 2025
From: ian.ray at gehealthcare.com (Ian Ray)
Date: Mon,  1 Dec 2025 11:56:05 +0200
Subject: [PATCH] ARM: dts: imx6q-ba16: fix RTC interrupt level
Message-ID: <20251201095606.990-1-ian.ray@gehealthcare.com>

RTC interrupt level should be set to "LOW". This was revealed by the
introduction of commit:

  f181987ef477 ("rtc: m41t80: use IRQ flags obtained from fwnode")

which changed the way IRQ type is obtained.

Fixes: 56c27310c1b4 ("ARM: dts: imx: Add Advantech BA-16 Qseven module")
Signed-off-by: Ian Ray <ian.ray at gehealthcare.com>
---
 arch/arm/boot/dts/nxp/imx/imx6q-ba16.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-ba16.dtsi b/arch/arm/boot/dts/nxp/imx/imx6q-ba16.dtsi
index 53013b12c2ec..02d66523668d 100644
--- a/arch/arm/boot/dts/nxp/imx/imx6q-ba16.dtsi
+++ b/arch/arm/boot/dts/nxp/imx/imx6q-ba16.dtsi
@@ -337,7 +337,7 @@ rtc at 32 {
 		pinctrl-0 = <&pinctrl_rtc>;
 		reg = <0x32>;
 		interrupt-parent = <&gpio4>;
-		interrupts = <10 IRQ_TYPE_LEVEL_HIGH>;
+		interrupts = <10 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
 
-- 
2.47.3



From amadeus at jmu.edu.cn  Mon Dec  1 02:00:04 2025
From: amadeus at jmu.edu.cn (Chukun Pan)
Date: Mon,  1 Dec 2025 18:00:04 +0800
Subject: [PATCH 0/4] arm64: dts: rockchip: Add H28K and M28K
Message-ID: <20251201100008.206524-1-amadeus@jmu.edu.cn>

Both the HINLINK H28K and MangoPi M28K are development boards based
on the Rockchip RK3528 SoC, and their configurations are similar.

The U-Boot patch will be sent after the kernel device tree is merged.

There is a version that SeeedStudio distributes called LinkStar-H28K.
It's no different from the HINLINK H28K. The schematic can be found here:

https://www.hinlink.cn/wp-content/uploads/2024/03/20240428015024130824.pdf
https://files.seeedstudio.com/wiki/H28K/Open_source/H28K-SCH.zip

Information about the MangoPi M28K is here: https://widora.cn/m28k

MangoPi also has a version called "M28K Pro", which replaces the
RTL8111H with the RTL8125B.

Chukun Pan (4):
  dt-bindings: arm: rockchip: Add HINLINK H28K
  arm64: dts: rockchip: Add HINLINK H28K
  dt-bindings: arm: rockchip: Add MangoPi M28K
  arm64: dts: rockchip: Add MangoPi M28K

 .../devicetree/bindings/arm/rockchip.yaml     |  10 +
 arch/arm64/boot/dts/rockchip/Makefile         |   2 +
 .../boot/dts/rockchip/rk3528-hinlink-h28k.dts | 301 ++++++++++++++
 .../boot/dts/rockchip/rk3528-mangopi-m28k.dts | 381 ++++++++++++++++++
 4 files changed, 694 insertions(+)
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3528-hinlink-h28k.dts
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3528-mangopi-m28k.dts

-- 
2.25.1



From amadeus at jmu.edu.cn  Mon Dec  1 02:00:05 2025
From: amadeus at jmu.edu.cn (Chukun Pan)
Date: Mon,  1 Dec 2025 18:00:05 +0800
Subject: [PATCH 1/4] dt-bindings: arm: rockchip: Add HINLINK H28K
In-Reply-To: <20251201100008.206524-1-amadeus@jmu.edu.cn>
References: <20251201100008.206524-1-amadeus@jmu.edu.cn>
Message-ID: <20251201100008.206524-2-amadeus@jmu.edu.cn>

The HINLINK H28K is a dual-gigabit SBC based on the RK3528 SoC.
Add devicetree binding documentation for it.

Signed-off-by: Chukun Pan <amadeus at jmu.edu.cn>
---
 Documentation/devicetree/bindings/arm/rockchip.yaml | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/rockchip.yaml b/Documentation/devicetree/bindings/arm/rockchip.yaml
index d496421dbd87..8d6e2b28e51a 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.yaml
+++ b/Documentation/devicetree/bindings/arm/rockchip.yaml
@@ -718,6 +718,11 @@ properties:
           - const: hardkernel,odroid-m2
           - const: rockchip,rk3588s
 
+      - description: HINLINK H28K
+        items:
+          - const: hinlink,h28k
+          - const: rockchip,rk3528
+
       - description: HINLINK H66K / H68K
         items:
           - enum:
-- 
2.25.1



From amadeus at jmu.edu.cn  Mon Dec  1 02:00:06 2025
From: amadeus at jmu.edu.cn (Chukun Pan)
Date: Mon,  1 Dec 2025 18:00:06 +0800
Subject: [PATCH 2/4] arm64: dts: rockchip: Add HINLINK H28K
In-Reply-To: <20251201100008.206524-1-amadeus@jmu.edu.cn>
References: <20251201100008.206524-1-amadeus@jmu.edu.cn>
Message-ID: <20251201100008.206524-3-amadeus@jmu.edu.cn>

The HINLINK H28K is a development board with the
Rockchip RK3528 SoC. It has the following features:

- 1x USB 2.0
- 8/32GB eMMC
- 1/2/4GB LPDDR4
- MicroSD card slot
- 1x 1GbE RTL8111H Ethernet
- 1x 1GbE RTL8211F Ethernet

Signed-off-by: Chukun Pan <amadeus at jmu.edu.cn>
---
 arch/arm64/boot/dts/rockchip/Makefile         |   1 +
 .../boot/dts/rockchip/rk3528-hinlink-h28k.dts | 301 ++++++++++++++++++
 2 files changed, 302 insertions(+)
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3528-hinlink-h28k.dts

diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index dbdda9783e93..8ccf72c2e31e 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -90,6 +90,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-sapphire.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-sapphire-excavator.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399pro-rock-pi-n10.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3528-armsom-sige1.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3528-hinlink-h28k.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3528-nanopi-zero2.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3528-radxa-e20c.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3528-rock-2a.dtb
diff --git a/arch/arm64/boot/dts/rockchip/rk3528-hinlink-h28k.dts b/arch/arm64/boot/dts/rockchip/rk3528-hinlink-h28k.dts
new file mode 100644
index 000000000000..4685db24a560
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3528-hinlink-h28k.dts
@@ -0,0 +1,301 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/dts-v1/;
+
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/pwm/pwm.h>
+#include "rk3528.dtsi"
+
+/ {
+	model = "HINLINK H28K";
+	compatible = "hinlink,h28k", "rockchip,rk3528";
+
+	aliases {
+		ethernet0 = &gmac1;
+		mmc0 = &sdhci;
+		mmc1 = &sdmmc;
+		serial0 = &uart0;
+	};
+
+	chosen {
+		stdout-path = "serial0:1500000n8";
+	};
+
+	keys {
+		compatible = "adc-keys";
+		io-channels = <&saradc 0>;
+		io-channel-names = "buttons";
+		keyup-threshold-microvolt = <1800000>;
+		poll-interval = <100>;
+
+		button-boot {
+			label = "BOOT";
+			linux,code = <KEY_SETUP>;
+			press-threshold-microvolt = <0>;
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&lan_led>, <&wan_led>, <&work_led>;
+
+		led-0 {
+			color = <LED_COLOR_ID_AMBER>;
+			function = LED_FUNCTION_LAN;
+			gpios = <&gpio4 RK_PC1 GPIO_ACTIVE_LOW>;
+			linux,default-trigger = "netdev";
+		};
+
+		led-1 {
+			color = <LED_COLOR_ID_BLUE>;
+			function = LED_FUNCTION_WAN;
+			gpios = <&gpio4 RK_PC0 GPIO_ACTIVE_LOW>;
+			linux,default-trigger = "netdev";
+		};
+
+		led-2 {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_STATUS;
+			gpios = <&gpio4 RK_PB7 GPIO_ACTIVE_LOW>;
+			linux,default-trigger = "default-on";
+		};
+	};
+
+	vdd_0v9: regulator-0v9-vdd {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd_0v9";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <900000>;
+		regulator-max-microvolt = <900000>;
+		vin-supply = <&vcc5v0_sys>;
+	};
+
+	vcc_ddr: regulator-1v1-vcc-ddr {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_ddr";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <1100000>;
+		regulator-max-microvolt = <1100000>;
+		vin-supply = <&vcc5v0_sys>;
+	};
+
+	vcc_1v8: regulator-1v8-vcc {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_1v8";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		vin-supply = <&vcc_3v3>;
+	};
+
+	vcc_3v3: regulator-3v3-vcc {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_3v3";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		vin-supply = <&vcc5v0_sys>;
+	};
+
+	vcc3v3_sd: regulator-3v3-vcc-sd {
+		compatible = "regulator-fixed";
+		gpios = <&gpio4 RK_PA1 GPIO_ACTIVE_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&sdmmc_pwren_l>;
+		regulator-name = "vcc3v3_sd";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		vin-supply = <&vcc_3v3>;
+	};
+
+	vcc5v0_sys: regulator-5v0-vcc-sys {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc5v0_sys";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+	};
+
+	vccio_sd: regulator-vccio-sd {
+		compatible = "regulator-gpio";
+		gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&sdmmc_vol_ctrl_h>;
+		regulator-name = "vccio_sd";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <3300000>;
+		states = <1800000 0x0>, <3300000 0x1>;
+		vin-supply = <&vcc5v0_sys>;
+	};
+
+	vdd_arm: regulator-vdd-arm {
+		compatible = "pwm-regulator";
+		pwms = <&pwm1 0 5000 PWM_POLARITY_INVERTED>;
+		pwm-supply = <&vcc5v0_sys>;
+		regulator-name = "vdd_arm";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <746000>;
+		regulator-max-microvolt = <1201000>;
+		regulator-settling-time-up-us = <250>;
+	};
+
+	vdd_logic: regulator-vdd-logic {
+		compatible = "pwm-regulator";
+		pwms = <&pwm2 0 5000 PWM_POLARITY_INVERTED>;
+		pwm-supply = <&vcc5v0_sys>;
+		regulator-name = "vdd_logic";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <705000>;
+		regulator-max-microvolt = <1006000>;
+		regulator-settling-time-up-us = <250>;
+	};
+};
+
+&combphy {
+	status = "okay";
+};
+
+&cpu0 {
+	cpu-supply = <&vdd_arm>;
+};
+
+&cpu1 {
+	cpu-supply = <&vdd_arm>;
+};
+
+&cpu2 {
+	cpu-supply = <&vdd_arm>;
+};
+
+&cpu3 {
+	cpu-supply = <&vdd_arm>;
+};
+
+&gmac1 {
+	clock_in_out = "output";
+	phy-handle = <&rgmii_phy>;
+	phy-mode = "rgmii-id";
+	phy-supply = <&vcc_3v3>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&rgmii_miim>,
+		    <&rgmii_tx_bus2>,
+		    <&rgmii_rx_bus2>,
+		    <&rgmii_rgmii_clk>,
+		    <&rgmii_rgmii_bus>;
+	status = "okay";
+};
+
+&gpu {
+	mali-supply = <&vdd_logic>;
+	status = "okay";
+};
+
+&mdio1 {
+	rgmii_phy: ethernet-phy at 1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <0x1>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&gmac1_rstn_l>;
+		reset-assert-us = <20000>;
+		reset-deassert-us = <100000>;
+		reset-gpios = <&gpio4 RK_PC2 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&pcie {
+	pinctrl-names = "default";
+	pinctrl-0 = <&rtl8111hs_isolateb_l>;
+	reset-gpios = <&gpio4 RK_PA3 GPIO_ACTIVE_HIGH>;
+	vpcie3v3-supply = <&vcc_3v3>;
+	status = "okay";
+};
+
+&pinctrl {
+	gmac {
+		gmac1_rstn_l: gmac1-rstn-l {
+			rockchip,pins = <4 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	leds {
+		lan_led: lan-led {
+			rockchip,pins = <4 RK_PC1 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		wan_led: wan-led {
+			rockchip,pins = <4 RK_PC0 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		work_led: work-led {
+			rockchip,pins = <4 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	pcie {
+		rtl8111hs_isolateb_l: rtl8111hs-isolateb-l {
+			rockchip,pins = <4 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	sdmmc {
+		sdmmc_pwren_l: sdmmc-pwren-l {
+			rockchip,pins = <4 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		sdmmc_vol_ctrl_h: sdmmc-vol-ctrl-h {
+			rockchip,pins = <4 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+};
+
+&pwm1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm1m0_pins>;
+	status = "okay";
+};
+
+&pwm2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm2m0_pins>;
+	status = "okay";
+};
+
+&saradc {
+	vref-supply = <&vcc_1v8>;
+	status = "okay";
+};
+
+&sdhci {
+	bus-width = <8>;
+	cap-mmc-highspeed;
+	mmc-hs200-1_8v;
+	non-removable;
+	vmmc-supply = <&vcc_3v3>;
+	vqmmc-supply = <&vcc_1v8>;
+	status = "okay";
+};
+
+&sdmmc {
+	bus-width = <4>;
+	cap-sd-highspeed;
+	disable-wp;
+	sd-uhs-sdr104;
+	vmmc-supply = <&vcc3v3_sd>;
+	vqmmc-supply = <&vccio_sd>;
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0m0_xfer>;
+	status = "okay";
+};
-- 
2.25.1



From amadeus at jmu.edu.cn  Mon Dec  1 02:00:07 2025
From: amadeus at jmu.edu.cn (Chukun Pan)
Date: Mon,  1 Dec 2025 18:00:07 +0800
Subject: [PATCH 3/4] dt-bindings: arm: rockchip: Add MangoPi M28K
In-Reply-To: <20251201100008.206524-1-amadeus@jmu.edu.cn>
References: <20251201100008.206524-1-amadeus@jmu.edu.cn>
Message-ID: <20251201100008.206524-4-amadeus@jmu.edu.cn>

The MangoPi M28K is a dual-gigabit SBC developed by Widora based
on the RK3528 SoC. Add devicetree binding documentation for it.

Signed-off-by: Chukun Pan <amadeus at jmu.edu.cn>
---
 Documentation/devicetree/bindings/arm/rockchip.yaml | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/rockchip.yaml b/Documentation/devicetree/bindings/arm/rockchip.yaml
index 8d6e2b28e51a..8fef370b637c 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.yaml
+++ b/Documentation/devicetree/bindings/arm/rockchip.yaml
@@ -1269,6 +1269,11 @@ properties:
           - const: turing,rk1
           - const: rockchip,rk3588
 
+      - description: MangoPi M28K
+        items:
+          - const: widora,mangopi-m28k
+          - const: rockchip,rk3528
+
       - description: WolfVision PF5 mainboard
         items:
           - const: wolfvision,rk3568-pf5
-- 
2.25.1



From amadeus at jmu.edu.cn  Mon Dec  1 02:00:08 2025
From: amadeus at jmu.edu.cn (Chukun Pan)
Date: Mon,  1 Dec 2025 18:00:08 +0800
Subject: [PATCH 4/4] arm64: dts: rockchip: Add MangoPi M28K
In-Reply-To: <20251201100008.206524-1-amadeus@jmu.edu.cn>
References: <20251201100008.206524-1-amadeus@jmu.edu.cn>
Message-ID: <20251201100008.206524-5-amadeus@jmu.edu.cn>

The MangoPi M28K is a development board with the
Rockchip RK3528 SoC. It has the following features:

- 2x USB 2.0
- 1x mini-HDMI
- 1/2/4GB LPDDR4
- AIC8800 WiFi/BT
- MicroSD card slot
- Optional 16/32GB eMMC
- 1x 1GbE RTL8111H Ethernet
- 1x 1GbE RTL8211F Ethernet

Signed-off-by: Chukun Pan <amadeus at jmu.edu.cn>
---
 arch/arm64/boot/dts/rockchip/Makefile         |   1 +
 .../boot/dts/rockchip/rk3528-mangopi-m28k.dts | 381 ++++++++++++++++++
 2 files changed, 382 insertions(+)
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3528-mangopi-m28k.dts

diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index 8ccf72c2e31e..d666ef62f5f4 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -91,6 +91,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-sapphire-excavator.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399pro-rock-pi-n10.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3528-armsom-sige1.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3528-hinlink-h28k.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3528-mangopi-m28k.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3528-nanopi-zero2.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3528-radxa-e20c.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3528-rock-2a.dtb
diff --git a/arch/arm64/boot/dts/rockchip/rk3528-mangopi-m28k.dts b/arch/arm64/boot/dts/rockchip/rk3528-mangopi-m28k.dts
new file mode 100644
index 000000000000..e99a83553910
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3528-mangopi-m28k.dts
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/dts-v1/;
+
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/pwm/pwm.h>
+#include "rk3528.dtsi"
+
+/ {
+	model = "MangoPi M28K";
+	compatible = "widora,mangopi-m28k", "rockchip,rk3528";
+
+	aliases {
+		ethernet0 = &gmac1;
+		i2c6 = &i2c6;
+		mmc0 = &sdhci;
+		mmc1 = &sdmmc;
+		mmc2 = &sdio0;
+		serial0 = &uart0;
+		serial2 = &uart2;
+		serial3 = &uart3;
+	};
+
+	chosen {
+		stdout-path = "serial0:1500000n8";
+	};
+
+	ir-receiver {
+		compatible = "gpio-ir-receiver";
+		gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pwm3_m0_ir_rx>;
+	};
+
+	keys-0 {
+		compatible = "adc-keys";
+		io-channels = <&saradc 0>;
+		io-channel-names = "buttons";
+		keyup-threshold-microvolt = <1800000>;
+		poll-interval = <100>;
+
+		button-boot {
+			label = "BOOT";
+			linux,code = <KEY_SETUP>;
+			press-threshold-microvolt = <0>;
+		};
+	};
+
+	keys-1 {
+		compatible = "adc-keys";
+		io-channels = <&saradc 1>;
+		io-channel-names = "buttons";
+		keyup-threshold-microvolt = <1800000>;
+		poll-interval = <100>;
+
+		button-recover {
+			label = "RECOVER";
+			linux,code = <KEY_VENDOR>;
+			press-threshold-microvolt = <0>;
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&lan_led>, <&wan_led>, <&work_led>;
+
+		led-0 {
+			color = <LED_COLOR_ID_WHITE>;
+			function = LED_FUNCTION_LAN;
+			gpios = <&gpio4 RK_PB5 GPIO_ACTIVE_LOW>;
+			linux,default-trigger = "netdev";
+		};
+
+		led-1 {
+			color = <LED_COLOR_ID_WHITE>;
+			function = LED_FUNCTION_WAN;
+			gpios = <&gpio4 RK_PC0 GPIO_ACTIVE_LOW>;
+			linux,default-trigger = "netdev";
+		};
+
+		led-2 {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_STATUS;
+			gpios = <&gpio4 RK_PB7 GPIO_ACTIVE_LOW>;
+			linux,default-trigger = "default-on";
+		};
+	};
+
+	vdd_0v9: regulator-0v9-vdd {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd_0v9";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <900000>;
+		regulator-max-microvolt = <900000>;
+		vin-supply = <&vcc_sys>;
+	};
+
+	vcc_ddr: regulator-1v1-vcc-ddr {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_ddr";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <1100000>;
+		regulator-max-microvolt = <1100000>;
+		vin-supply = <&vcc_sys>;
+	};
+
+	vcc_1v8: regulator-1v8-vcc {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_1v8";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		vin-supply = <&vcc_3v3>;
+	};
+
+	vcc_3v3: regulator-3v3-vcc {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_3v3";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		vin-supply = <&vcc_sys>;
+	};
+
+	vcc3v3_sd: regulator-3v3-vcc-sd {
+		compatible = "regulator-fixed";
+		gpios = <&gpio4 RK_PA1 GPIO_ACTIVE_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&sdmmc_pwren_l>;
+		regulator-name = "vcc3v3_sd";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		vin-supply = <&vcc_3v3>;
+	};
+
+	vcc_sys: regulator-5v0-vcc-sys {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_sys";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+	};
+
+	vccio_sd: regulator-vccio-sd {
+		compatible = "regulator-gpio";
+		gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&sdmmc_vol_ctrl_h>;
+		regulator-name = "vccio_sd";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <3300000>;
+		states = <1800000 0x0>, <3300000 0x1>;
+		vin-supply = <&vcc_sys>;
+	};
+
+	vdd_arm: regulator-vdd-arm {
+		compatible = "pwm-regulator";
+		pwms = <&pwm1 0 5000 PWM_POLARITY_INVERTED>;
+		pwm-supply = <&vcc_sys>;
+		regulator-name = "vdd_arm";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <746000>;
+		regulator-max-microvolt = <1201000>;
+		regulator-settling-time-up-us = <250>;
+	};
+
+	vdd_logic: regulator-vdd-logic {
+		compatible = "pwm-regulator";
+		pwms = <&pwm2 0 5000 PWM_POLARITY_INVERTED>;
+		pwm-supply = <&vcc_sys>;
+		regulator-name = "vdd_logic";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <705000>;
+		regulator-max-microvolt = <1006000>;
+		regulator-settling-time-up-us = <250>;
+	};
+
+	sdio_pwrseq: sdio-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		pinctrl-names = "default";
+		pinctrl-0 = <&wifi_reg_on_h>;
+		post-power-on-delay-ms = <100>;
+		power-off-delay-us = <5000000>;
+		reset-gpios = <&gpio1 RK_PA6 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&combphy {
+	status = "okay";
+};
+
+&cpu0 {
+	cpu-supply = <&vdd_arm>;
+};
+
+&cpu1 {
+	cpu-supply = <&vdd_arm>;
+};
+
+&cpu2 {
+	cpu-supply = <&vdd_arm>;
+};
+
+&cpu3 {
+	cpu-supply = <&vdd_arm>;
+};
+
+&gmac1 {
+	clock_in_out = "output";
+	phy-handle = <&rgmii_phy>;
+	phy-mode = "rgmii-id";
+	phy-supply = <&vcc_3v3>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&rgmii_miim>,
+		    <&rgmii_tx_bus2>,
+		    <&rgmii_rx_bus2>,
+		    <&rgmii_rgmii_clk>,
+		    <&rgmii_rgmii_bus>;
+	status = "okay";
+};
+
+&gpu {
+	mali-supply = <&vdd_logic>;
+	status = "okay";
+};
+
+&i2c6 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c6m0_xfer>;
+	status = "okay";
+};
+
+&mdio1 {
+	rgmii_phy: ethernet-phy at 1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <0x1>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&gmac1_rstn_l>;
+		reset-assert-us = <20000>;
+		reset-deassert-us = <100000>;
+		reset-gpios = <&gpio4 RK_PC2 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&pcie {
+	pinctrl-names = "default";
+	pinctrl-0 = <&rtl8111hs_isolateb_l>;
+	reset-gpios = <&gpio4 RK_PA3 GPIO_ACTIVE_HIGH>;
+	vpcie3v3-supply = <&vcc_3v3>;
+	status = "okay";
+};
+
+&pinctrl {
+	gmac {
+		gmac1_rstn_l: gmac1-rstn-l {
+			rockchip,pins = <4 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	ir {
+		pwm3_m0_ir_rx: pwm3-m0-ir-rx {
+			rockchip,pins = <4 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	leds {
+		lan_led: lan-led {
+			rockchip,pins = <4 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		wan_led: wan-led {
+			rockchip,pins = <4 RK_PC0 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		work_led: work-led {
+			rockchip,pins = <4 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	pcie {
+		rtl8111hs_isolateb_l: rtl8111hs-isolateb-l {
+			rockchip,pins = <4 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	sdmmc {
+		sdmmc_pwren_l: sdmmc-pwren-l {
+			rockchip,pins = <4 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		sdmmc_vol_ctrl_h: sdmmc-vol-ctrl-h {
+			rockchip,pins = <4 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	wifi {
+		wifi_reg_on_h: wifi-reg-on-h {
+			rockchip,pins = <1 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		wifi_wake_host_h: wifi-wake-host-h {
+			rockchip,pins = <1 RK_PA7 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+	};
+};
+
+&pwm1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm1m0_pins>;
+	status = "okay";
+};
+
+&pwm2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm2m0_pins>;
+	status = "okay";
+};
+
+&saradc {
+	vref-supply = <&vcc_1v8>;
+	status = "okay";
+};
+
+&sdhci {
+	bus-width = <8>;
+	cap-mmc-highspeed;
+	mmc-hs200-1_8v;
+	non-removable;
+	vmmc-supply = <&vcc_3v3>;
+	vqmmc-supply = <&vcc_1v8>;
+	status = "okay";
+};
+
+&sdio0 {
+	bus-width = <4>;
+	cap-sd-highspeed;
+	cap-sdio-irq;
+	keep-power-in-suspend;
+	mmc-pwrseq = <&sdio_pwrseq>;
+	non-removable;
+	sd-uhs-sdr104;
+	status = "okay";
+};
+
+&sdmmc {
+	bus-width = <4>;
+	cap-sd-highspeed;
+	disable-wp;
+	sd-uhs-sdr104;
+	vmmc-supply = <&vcc3v3_sd>;
+	vqmmc-supply = <&vccio_sd>;
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0m0_xfer>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2m1_ctsn>, <&uart2m1_rtsn>, <&uart2m1_xfer>;
+	uart-has-rtscts;
+	status = "okay";
+};
+
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart3m0_xfer>;
+	status = "disabled";
+};
-- 
2.25.1



From anshuld at ti.com  Mon Dec  1 02:02:55 2025
From: anshuld at ti.com (Anshul Dalal)
Date: Mon, 1 Dec 2025 15:32:55 +0530
Subject: [PATCH v3] dt-bindings: arm: keystone: add boot_* mboxes to
 ti,sci
In-Reply-To: <20251112152806.zsinwwzaht2ws2wh@headpiece>
References: <20251112-k3_syscon_add_boot_mailboxes-v3-1-66155a4236dc@ti.com>
 <20251112152806.zsinwwzaht2ws2wh@headpiece>
Message-ID: <DEMSLNLDXSNY.2CMMGUMUOYA9T@ti.com>

On Wed Nov 12, 2025 at 8:58 PM IST, Nishanth Menon wrote:
> On 15:54-20251112, Anshul Dalal wrote:
>> The bootloader on K3 devices makes use of mailboxes as per the ROM spec
>> which might be different than one's available to the kernel (firmware
>> spec).
>> 
>> Therefore, this patch adds the missing mailbox entries to the DT binding
>> to represent the mailboxes exposed by the hardware during boot for the
>> purpose of loading the firmware.
>> 
>> Signed-off-by: Anshul Dalal <anshuld at ti.com>
>> ---
>> Changes in v3:
>> - Drop [1/2] of the last patch series
>> - Update existing example with boot_* mailboxes instead of adding a new one
>> - Link to v2: https://lore.kernel.org/r/20251112-k3_syscon_add_boot_mailboxes-v2-0-aebc1e47b391 at ti.com
>> 
>> Changes in v2:
>> - Remove maxItems entry
>> - Remove RFC tag from patch (added by mistake in v1)
>> - Document the new mailboxes in mboxes instead of mbox-names
>> - Provide example with all the mailboxes set
>> - Update commit title to have "ti,sci"
>> - Split into two patches
>> - Link to v1: https://lore.kernel.org/r/20251111-k3_syscon_add_boot_mailboxes-v1-1-529a27f21076 at ti.com
>> ---
>>  .../devicetree/bindings/arm/keystone/ti,sci.yaml      | 19 ++++++++++++++++---
>>  1 file changed, 16 insertions(+), 3 deletions(-)
>> 
>> diff --git a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
>> index 25a2b42105e541cb3c8ad12a0dfec1af038fa907..be8a5b2b051b441884795059c70892910d981130 100644
>> --- a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
>> +++ b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
>> @@ -51,15 +51,27 @@ properties:
>>      minItems: 1
>>  
>>    mbox-names:
>> +    minItems: 2
>>      description: |
>>        Specifies the mailboxes used to communicate with TI-SCI Controller
>>        made available from TI-SCI controller.
>>      items:
>>        - const: rx
>>        - const: tx
>> +      - const: notify
>> +      - const: boot_rx
>> +      - const: boot_tx
>> +      - const: boot_notify
>
> Sorry for joining the party late.. just saw the thread while happening
> to glance at the pending list..
>
> k2g does not use boot_* mboxes, the load mechanism doesn't involve
> ROM talking over mboxes, we load the pmmc on that SoC! ti,am654-sci
> onwards does. This would be a good case for adding a conditional
> property, IMHO. That said majority of the K3 dts entries still use
> k2g-sci for k3 (#facepalm.. i should have caught it, but missed).. but
> that cleanup is for follow on patches that could fix.. driver seems to
> be able to handle the same.
>

Should we therefore have the new mboxes be conditional on "ti,am654-sci"
while k2g continues to use the existing "rx" and "tx" mboxes?

Something similar to:

	if:
	  properties:
	    compatible:
	      contains:
		const: ti,am654-sci
	then:
	  properties:
	    mbox-names:
	      minItems: 2
	      items:
		- const: rx
		- const: tx
		- const: notify
		- const: boot_rx
		- const: boot_tx
		- const: boot_notify
	    mboxes:
	      minItems: 2
	      items:
		- description: RX thread
		- description: TX thread
		- description: Notify thread
		- description: boot stage RX thread
		- description: boot stage TX thread
		- description: boot stage Notify thread
	else:
	  properties:
	    mbox-names:
	      items:
		- const: rx
		- const: tx
	    mboxes:
	      maxItems: 2

With the top level mbox* having a minItems of 2 and max of 6.

Regards,
Anshul

>>  
>>    mboxes:
>>      minItems: 2
>> +    items:
>> +      - description: RX thread
>> +      - description: TX thread
>> +      - description: Notify thread
>> +      - description: boot stage RX thread
>> +      - description: boot stage TX thread
>> +      - description: boot stage Notify thread
>>  
>>    ti,host-id:
>>      $ref: /schemas/types.yaml#/definitions/uint32
>> @@ -90,9 +102,10 @@ examples:
>>    - |
>>      pmmc: system-controller at 2921800 {
>>        compatible = "ti,k2g-sci";
>> -      mbox-names = "rx", "tx";
>> -      mboxes = <&msgmgr 5 2>,
>> -               <&msgmgr 0 0>;
>> +      mbox-names = "rx", "tx", "notify", "boot_rx", "boot_tx", "boot_notify";
>> +      mboxes = <&secure_proxy_mcu 8>, <&secure_proxy_mcu 6>,
>> +        <&secure_proxy_mcu 5>, <&secure_proxy_mcu 4>,
>> +        <&secure_proxy_mcu 5>, <&secure_proxy_sa3 5>;
>
>
>>        reg-names = "debug_messages";
>>        reg = <0x02921800 0x800>;
>>      };
>> 
>> ---
>> base-commit: 4427259cc7f7571a157fbc9b5011e1ef6fe0a4a8
>> change-id: 20251105-k3_syscon_add_boot_mailboxes-8452bdd98962
>> 
>> Best regards,
>> -- 
>> Anshul Dalal <anshuld at ti.com>
>> 



From bisson.gary at gmail.com  Mon Dec  1 02:04:50 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Mon, 1 Dec 2025 11:04:50 +0100
Subject: [PATCH 1/5] dt-bindings: vendor-prefixes: Add Ezurio LLC
In-Reply-To: <176458161856.2489196.6170126310129033736.robh@kernel.org>
References: <20251201084140.376058-1-bisson.gary@gmail.com>
 <20251201084140.376058-2-bisson.gary@gmail.com>
 <176458161856.2489196.6170126310129033736.robh@kernel.org>
Message-ID: <aS1oQonkuFpyqSI2@owl5>

Hi,

On Mon, Dec 01, 2025 at 03:33:40AM -0600, Rob Herring (Arm) wrote:
> 
> On Mon, 01 Dec 2025 09:41:36 +0100, Gary Bisson wrote:
> > Ezurio is the new name of Laird Connectivity after it acquired Boundary
> > Devices.
> > 
> > Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
> > ---
> > Cc: robh at kernel.org
> > Cc: krzk+dt at kernel.org
> > ---
> >  Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
> >  1 file changed, 2 insertions(+)
> > 
> 
> My bot found errors running 'make dt_binding_check' on your patch:
> 
> yamllint warnings/errors:
> 
> dtschema/dtc warnings/errors:
> Traceback (most recent call last):
>   File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 428, in get_or_retrieve
>     resource = registry._retrieve(uri)
>   File "/usr/local/lib/python3.13/dist-packages/dtschema/validator.py", line 426, in retrieve
>     return DRAFT201909.create_resource(self.schemas[uri])
>                                        ~~~~~~~~~~~~^^^^^
> KeyError: 'http://devicetree.org/schemas/thermal/qcom-tsens.yaml'
> 
> The above exception was the direct cause of the following exception:
> 
> Traceback (most recent call last):
>   File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 682, in lookup
>     retrieved = self._registry.get_or_retrieve(uri)
>   File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 435, in get_or_retrieve
>     raise exceptions.Unretrievable(ref=uri) from error
> referencing.exceptions.Unretrievable: 'http://devicetree.org/schemas/thermal/qcom-tsens.yaml'
> 
> The above exception was the direct cause of the following exception:
> 
> Traceback (most recent call last):
>   File "/usr/local/lib/python3.13/dist-packages/jsonschema/validators.py", line 463, in _validate_reference
>     resolved = self._resolver.lookup(ref)
>   File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 686, in lookup
>     raise exceptions.Unresolvable(ref=ref) from error
> referencing.exceptions.Unresolvable: /schemas/thermal/qcom-tsens.yaml#
> 
> The above exception was the direct cause of the following exception:
> 
> Traceback (most recent call last):
>   File "/usr/local/bin/dt-validate", line 8, in <module>
>     sys.exit(main())
>              ~~~~^^
>   File "/usr/local/lib/python3.13/dist-packages/dtschema/dtb_validate.py", line 158, in main
>     sg.check_dtb(filename)
>     ~~~~~~~~~~~~^^^^^^^^^^
>   File "/usr/local/lib/python3.13/dist-packages/dtschema/dtb_validate.py", line 95, in check_dtb
>     self.check_subtree(dt, subtree, False, "/", "/", filename)
>     ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>   File "/usr/local/lib/python3.13/dist-packages/dtschema/dtb_validate.py", line 88, in check_subtree
>     self.check_subtree(tree, value, disabled, name, fullname + name, filename)
>     ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>   File "/usr/local/lib/python3.13/dist-packages/dtschema/dtb_validate.py", line 88, in check_subtree
>     self.check_subtree(tree, value, disabled, name, fullname + name, filename)
>     ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>   File "/usr/local/lib/python3.13/dist-packages/dtschema/dtb_validate.py", line 83, in check_subtree
>     self.check_node(tree, subtree, disabled, nodename, fullname, filename)
>     ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>   File "/usr/local/lib/python3.13/dist-packages/dtschema/dtb_validate.py", line 34, in check_node
>     for error in self.validator.iter_errors(node, filter=match_schema_file,
>                  ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>                                             compatible_match=compatible_match):
>                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>   File "/usr/local/lib/python3.13/dist-packages/dtschema/validator.py", line 448, in iter_errors
>     for error in self.DtValidator(schema, registry=self.registry).iter_errors(instance):
>                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^
>   File "/usr/local/lib/python3.13/dist-packages/jsonschema/validators.py", line 384, in iter_errors
>     for error in errors:
>                  ^^^^^^
>   File "/usr/local/lib/python3.13/dist-packages/jsonschema/_keywords.py", line 296, in properties
>     yield from validator.descend(
>     ...<4 lines>...
>     )
>   File "/usr/local/lib/python3.13/dist-packages/jsonschema/validators.py", line 432, in descend
>     for error in errors:
>                  ^^^^^^
>   File "/usr/local/lib/python3.13/dist-packages/jsonschema/_keywords.py", line 275, in ref
>     yield from validator._validate_reference(ref=ref, instance=instance)
>                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>   File "/usr/local/lib/python3.13/dist-packages/jsonschema/validators.py", line 465, in _validate_reference
>     raise exceptions._WrappedReferencingError(err) from err
> jsonschema.exceptions._WrappedReferencingError: Unresolvable: /schemas/thermal/qcom-tsens.yaml#
> Traceback (most recent call last):
>   File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 428, in get_or_retrieve
>     resource = registry._retrieve(uri)
>   File "/usr/local/lib/python3.13/dist-packages/dtschema/validator.py", line 426, in retrieve
>     return DRAFT201909.create_resource(self.schemas[uri])
>                                        ~~~~~~~~~~~~^^^^^
> KeyError: 'http://devicetree.org/schemas/thermal/qcom-tsens.yaml'
> 
> The above exception was the direct cause of the following exception:
> 
> Traceback (most recent call last):
>   File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 682, in lookup
>     retrieved = self._registry.get_or_retrieve(uri)
>   File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 435, in get_or_retrieve
>     raise exceptions.Unretrievable(ref=uri) from error
> referencing.exceptions.Unretrievable: 'http://devicetree.org/schemas/thermal/qcom-tsens.yaml'
> 
> The above exception was the direct cause of the following exception:
> 
> Traceback (most recent call last):
>   File "/usr/local/lib/python3.13/dist-packages/jsonschema/validators.py", line 463, in _validate_reference
>     resolved = self._resolver.lookup(ref)
>   File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 686, in lookup
>     raise exceptions.Unresolvable(ref=ref) from error
> referencing.exceptions.Unresolvable: /schemas/thermal/qcom-tsens.yaml#
> 
> The above exception was the direct cause of the following exception:
> 
> Traceback (most recent call last):
>   File "/usr/local/bin/dt-validate", line 8, in <module>
>     sys.exit(main())
>              ~~~~^^
>   File "/usr/local/lib/python3.13/dist-packages/dtschema/dtb_validate.py", line 158, in main
>     sg.check_dtb(filename)
>     ~~~~~~~~~~~~^^^^^^^^^^
>   File "/usr/local/lib/python3.13/dist-packages/dtschema/dtb_validate.py", line 95, in check_dtb
>     self.check_subtree(dt, subtree, False, "/", "/", filename)
>     ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>   File "/usr/local/lib/python3.13/dist-packages/dtschema/dtb_validate.py", line 88, in check_subtree
>     self.check_subtree(tree, value, disabled, name, fullname + name, filename)
>     ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>   File "/usr/local/lib/python3.13/dist-packages/dtschema/dtb_validate.py", line 88, in check_subtree
>     self.check_subtree(tree, value, disabled, name, fullname + name, filename)
>     ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>   File "/usr/local/lib/python3.13/dist-packages/dtschema/dtb_validate.py", line 83, in check_subtree
>     self.check_node(tree, subtree, disabled, nodename, fullname, filename)
>     ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>   File "/usr/local/lib/python3.13/dist-packages/dtschema/dtb_validate.py", line 34, in check_node
>     for error in self.validator.iter_errors(node, filter=match_schema_file,
>                  ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>                                             compatible_match=compatible_match):
>                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>   File "/usr/local/lib/python3.13/dist-packages/dtschema/validator.py", line 448, in iter_errors
>     for error in self.DtValidator(schema, registry=self.registry).iter_errors(instance):
>                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^
>   File "/usr/local/lib/python3.13/dist-packages/jsonschema/validators.py", line 384, in iter_errors
>     for error in errors:
>                  ^^^^^^
>   File "/usr/local/lib/python3.13/dist-packages/jsonschema/_keywords.py", line 296, in properties
>     yield from validator.descend(
>     ...<4 lines>...
>     )
>   File "/usr/local/lib/python3.13/dist-packages/jsonschema/validators.py", line 432, in descend
>     for error in errors:
>                  ^^^^^^
>   File "/usr/local/lib/python3.13/dist-packages/jsonschema/_keywords.py", line 334, in allOf
>     yield from validator.descend(instance, subschema, schema_path=index)
>   File "/usr/local/lib/python3.13/dist-packages/jsonschema/validators.py", line 432, in descend
>     for error in errors:
>                  ^^^^^^
>   File "/usr/local/lib/python3.13/dist-packages/jsonschema/_keywords.py", line 275, in ref
>     yield from validator._validate_reference(ref=ref, instance=instance)
>                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>   File "/usr/local/lib/python3.13/dist-packages/jsonschema/validators.py", line 465, in _validate_reference
>     raise exceptions._WrappedReferencingError(err) from err
> jsonschema.exceptions._WrappedReferencingError: Unresolvable: /schemas/thermal/qcom-tsens.yaml#
> 
> doc reference errors (make refcheckdocs):
> 
> See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20251201084140.376058-2-bisson.gary at gmail.com

This link gives me a 404 error, is it expected?

> 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.

Couldn't reproduce, I can't seem to see any error/warning that would be
introduced by this patch, can the above be discarded then?

Regards,
Gary


From hanchien.lin at mediatek.com  Mon Dec  1 02:06:18 2025
From: hanchien.lin at mediatek.com (Hanchien Lin)
Date: Mon, 1 Dec 2025 18:06:18 +0800
Subject: [PATCH v2 0/2] arm64: dts/thermal: Add MT8189 thermal controller and driver support
Message-ID: <20251201100620.1557608-1-hanchien.lin@mediatek.com>

This patch series adds support for the thermal controller on MediaTek MT8189 SoC.

Patch 1 adds the device tree node for the MT8189 thermal controller.
Patch 2 adds MT8189 support to the LVTS thermal driver.

Link to v1: https://lore.kernel.org/all/20251110094113.3965182-1-hanchien.lin at mediatek.com/

Changes in v2:
- Change reset functions from devm_reset_control_get_by_index to devm_reset_control_get_exclusive from reviewers comment.
- Change some use of line breaks and commas for coding style from other mediatek drivers.

Hanchien Lin (2):
  arm64: dts: mediatek: mt8189: Add thermal controller node
  thermal/drivers/mediatek/lvts_thermal: Add MT8189 support

 .../thermal/mediatek,lvts-thermal.yaml        |  27 +++-
 drivers/thermal/mediatek/lvts_thermal.c       | 151 ++++++++++++++++--
 .../thermal/mediatek,lvts-thermal.h           |  20 +++
 3 files changed, 185 insertions(+), 13 deletions(-)

-- 
2.45.2

Thanks,
Hanchien Lin <hanchien.lin at mediatek.com>


From hanchien.lin at mediatek.com  Mon Dec  1 02:06:20 2025
From: hanchien.lin at mediatek.com (Hanchien Lin)
Date: Mon, 1 Dec 2025 18:06:20 +0800
Subject: [PATCH v2 2/2] thermal/drivers/mediatek/lvts_thermal: Add MT8189 support
In-Reply-To: <20251201100620.1557608-1-hanchien.lin@mediatek.com>
References: <20251201100620.1557608-1-hanchien.lin@mediatek.com>
Message-ID: <20251201100620.1557608-3-hanchien.lin@mediatek.com>

Changes in v2:
- Change reset functions from devm_reset_control_get_by_index to devm_reset_control_get_exclusive from reviewers comment.
- Change some use of line breaks and commas for coding style from other mediatek drivers.

Add support for the MediaTek MT8189 SoC to the LVTS thermal driver.

Signed-off-by: Hanchien Lin <hanchien.lin at mediatek.com>
---
 drivers/thermal/mediatek/lvts_thermal.c | 151 ++++++++++++++++++++++--
 1 file changed, 140 insertions(+), 11 deletions(-)

diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c
index ab55b20cda47..c1eee0c2167f 100644
--- a/drivers/thermal/mediatek/lvts_thermal.c
+++ b/drivers/thermal/mediatek/lvts_thermal.c
@@ -65,6 +65,7 @@
 #define LVTS_HW_FILTER				0x0
 #define LVTS_TSSEL_CONF				0x13121110
 #define LVTS_CALSCALE_CONF			0x300
+#define LVTS_MONINT_CONF_STAGE3		BIT(31)
 
 #define LVTS_MONINT_OFFSET_HIGH_INTEN_SENSOR0		BIT(3)
 #define LVTS_MONINT_OFFSET_HIGH_INTEN_SENSOR1		BIT(8)
@@ -107,6 +108,7 @@ struct lvts_sensor_data {
 struct lvts_ctrl_data {
 	struct lvts_sensor_data lvts_sensor[LVTS_SENSOR_MAX];
 	u8 valid_sensor_mask;
+	int hw_tshut_temp;
 	int offset;
 	int mode;
 };
@@ -134,6 +136,9 @@ struct lvts_data {
 	int temp_offset;
 	int gt_calib_bit_offset;
 	unsigned int def_calibration;
+	bool clock_gate_no_need;
+	bool reset_no_need;
+	bool conf_stage3_need;
 };
 
 struct lvts_sensor {
@@ -150,6 +155,7 @@ struct lvts_ctrl {
 	struct lvts_sensor sensors[LVTS_SENSOR_MAX];
 	const struct lvts_data *lvts_data;
 	u32 calibration[LVTS_SENSOR_MAX];
+	u32 hw_tshut_raw_temp;
 	u8 valid_sensor_mask;
 	int mode;
 	void __iomem *base;
@@ -859,6 +865,14 @@ static int lvts_ctrl_init(struct device *dev, struct lvts_domain *lvts_td,
 		 */
 		lvts_ctrl[i].mode = lvts_data->lvts_ctrl[i].mode;
 
+		/*
+		 * The temperature to raw temperature must be done
+		 * after initializing the calibration.
+		 */
+		lvts_ctrl[i].hw_tshut_raw_temp =
+			lvts_temp_to_raw(lvts_data->lvts_ctrl[i].hw_tshut_temp,
+					 lvts_data->temp_factor);
+
 		lvts_ctrl[i].low_thresh = INT_MIN;
 		lvts_ctrl[i].high_thresh = INT_MIN;
 	}
@@ -919,7 +933,7 @@ static void lvts_write_config(struct lvts_ctrl *lvts_ctrl, const u32 *cmds, int
 	}
 }
 
-static int lvts_irq_init(struct lvts_ctrl *lvts_ctrl)
+static int lvts_irq_init(struct lvts_ctrl *lvts_ctrl, const struct lvts_data *lvts_data)
 {
 	/*
 	 * LVTS_PROTCTL : Thermal Protection Sensor Selection
@@ -947,6 +961,7 @@ static int lvts_irq_init(struct lvts_ctrl *lvts_ctrl)
 	 * writel(0x0, LVTS_PROTTB(lvts_ctrl->base));
 	 * writel(0x0, LVTS_PROTTC(lvts_ctrl->base));
 	 */
+	writel(lvts_ctrl->hw_tshut_raw_temp, LVTS_PROTTC(lvts_ctrl->base));
 
 	/*
 	 * LVTS_MONINT : Interrupt configuration register
@@ -954,7 +969,10 @@ static int lvts_irq_init(struct lvts_ctrl *lvts_ctrl)
 	 * The LVTS_MONINT register layout is the same as the LVTS_MONINTSTS
 	 * register, except we set the bits to enable the interrupt.
 	 */
-	writel(0, LVTS_MONINT(lvts_ctrl->base));
+	if (lvts_data->conf_stage3_need)
+		writel(LVTS_MONINT_CONF_STAGE3, LVTS_MONINT(lvts_ctrl->base));
+	else
+		writel(0, LVTS_MONINT(lvts_ctrl->base));
 
 	return 0;
 }
@@ -1041,7 +1059,8 @@ static int lvts_ctrl_calibrate(struct device *dev, struct lvts_ctrl *lvts_ctrl)
 	return 0;
 }
 
-static int lvts_ctrl_configure(struct device *dev, struct lvts_ctrl *lvts_ctrl)
+static int lvts_ctrl_configure(struct device *dev, struct lvts_ctrl *lvts_ctrl,
+			       const struct lvts_data *lvts_data)
 {
 	u32 value;
 
@@ -1143,7 +1162,7 @@ static int lvts_ctrl_configure(struct device *dev, struct lvts_ctrl *lvts_ctrl)
 	value = LVTS_FILTER_INTERVAL << 16 | LVTS_SENSOR_INTERVAL;
 	writel(value, LVTS_MONCTL2(lvts_ctrl->base));
 
-	return lvts_irq_init(lvts_ctrl);
+	return lvts_irq_init(lvts_ctrl, lvts_data);
 }
 
 static int lvts_ctrl_start(struct device *dev, struct lvts_ctrl *lvts_ctrl)
@@ -1290,7 +1309,7 @@ static int lvts_domain_init(struct device *dev, struct lvts_domain *lvts_td,
 			return ret;
 		}
 
-		ret = lvts_ctrl_configure(dev, lvts_ctrl);
+		ret = lvts_ctrl_configure(dev, lvts_ctrl, lvts_data);
 		if (ret) {
 			dev_dbg(dev, "Failed to configure controller");
 			return ret;
@@ -1322,9 +1341,13 @@ static int lvts_probe(struct platform_device *pdev)
 	if (!lvts_data)
 		return -ENODEV;
 
-	lvts_td->clk = devm_clk_get_enabled(dev, NULL);
-	if (IS_ERR(lvts_td->clk))
-		return dev_err_probe(dev, PTR_ERR(lvts_td->clk), "Failed to retrieve clock\n");
+	if (!lvts_data->clock_gate_no_need) {
+		lvts_td->clk = devm_clk_get_enabled(dev, NULL);
+		if (IS_ERR(lvts_td->clk))
+			return dev_err_probe(dev,
+					     PTR_ERR(lvts_td->clk),
+					     "Failed to retrieve clock\n");
+	}
 
 	res = platform_get_mem_or_io(pdev, 0);
 	if (!res)
@@ -1334,9 +1357,13 @@ static int lvts_probe(struct platform_device *pdev)
 	if (IS_ERR(lvts_td->base))
 		return dev_err_probe(dev, PTR_ERR(lvts_td->base), "Failed to map io resource\n");
 
-	lvts_td->reset = devm_reset_control_get_by_index(dev, 0);
-	if (IS_ERR(lvts_td->reset))
-		return dev_err_probe(dev, PTR_ERR(lvts_td->reset), "Failed to get reset control\n");
+	if (!lvts_data->reset_no_need) {
+		lvts_td->reset = devm_reset_control_get_exclusive(dev, NULL);
+		if (IS_ERR(lvts_td->reset))
+			return dev_err_probe(dev,
+					     PTR_ERR(lvts_td->reset),
+					     "Failed to get reset control\n");
+	}
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0)
@@ -1586,6 +1613,78 @@ static const struct lvts_ctrl_data mt8188_lvts_ap_data_ctrl[] = {
 	}
 };
 
+static const struct lvts_ctrl_data mt8189_lvts_mcu_data_ctrl[] = {
+	{
+		.lvts_sensor = {
+			{ .dt_id = MT8189_MCU_LITTLE_CPU1,
+			  .cal_offsets = { 4, 5, 6 } },
+			{ .dt_id = MT8189_MCU_LITTLE_CPU2,
+			  .cal_offsets = { 8, 9, 10 } },
+			{ .dt_id = MT8189_MCU_LITTLE_CPU3,
+			  .cal_offsets = { 12, 13, 14 } },
+			{ .dt_id = MT8189_MCU_LITTLE_CPU4,
+			  .cal_offsets = { 16, 17, 18 } }
+		},
+		VALID_SENSOR_MAP(1, 1, 1, 1),
+		.offset = 0x0,
+	},
+	{
+		.lvts_sensor = {
+			{ .dt_id = MT8189_MCU_LITTLE_CPU5,
+			  .cal_offsets = { 24, 25, 26 } },
+			{ .dt_id = MT8189_MCU_LITTLE_CPU6,
+			  .cal_offsets = { 28, 29, 30 } },
+			{ .dt_id = MT8189_MCU_LITTLE_CPU7,
+			  .cal_offsets = { 32, 33, 34 } },
+			{ .dt_id = MT8189_MCU_LITTLE_CPU8,
+			  .cal_offsets = { 36, 37, 38 } }
+		},
+		VALID_SENSOR_MAP(1, 1, 1, 1),
+		.offset = 0x100,
+	},
+	{
+		.lvts_sensor = {
+			{ .dt_id = MT8189_MCU_BIG_CPU1,
+			  .cal_offsets = { 44, 45, 46 } },
+			{ .dt_id = MT8189_MCU_BIG_CPU2,
+			  .cal_offsets = { 48, 49, 50 } },
+			{ .dt_id = MT8189_MCU_BIG_CPU3,
+			  .cal_offsets = { 52, 53, 54 } },
+			{ .dt_id = MT8189_MCU_BIG_CPU4,
+			  .cal_offsets = { 56, 57, 58 } }
+		},
+		VALID_SENSOR_MAP(1, 1, 1, 1),
+		.offset = 0x200,
+	}
+};
+
+static const struct lvts_ctrl_data mt8189_lvts_ap_data_ctrl[] = {
+	{
+		.lvts_sensor = {
+			{ .dt_id = MT8189_AP_SOC1,
+			  .cal_offsets = { 64, 65, 66 } },
+			{ .dt_id = MT8189_AP_SOC2,
+			  .cal_offsets = { 68, 69, 70 } },
+			{ .dt_id = MT8189_AP_SOC3,
+			  .cal_offsets = { 72, 73, 74 } },
+			{ .dt_id = MT8189_AP_APU,
+			  .cal_offsets = { 76, 77, 78 } }
+		},
+		VALID_SENSOR_MAP(1, 1, 1, 1),
+		.offset = 0x0,
+	},
+	{
+		.lvts_sensor = {
+			{ .dt_id = MT8189_AP_GPU1,
+			  .cal_offsets = { 84, 85, 86 } },
+			{ .dt_id = MT8189_AP_GPU2,
+			  .cal_offsets = { 88, 89, 90 } }
+		},
+		VALID_SENSOR_MAP(1, 1, 0, 0),
+		.offset = 0x100,
+	}
+};
+
 static const struct lvts_ctrl_data mt8192_lvts_mcu_data_ctrl[] = {
 	{
 		.lvts_sensor = {
@@ -1804,6 +1903,34 @@ static const struct lvts_data mt8188_lvts_ap_data = {
 	.def_calibration = 35000,
 };
 
+static const struct lvts_data mt8189_lvts_ap_data = {
+	.lvts_ctrl		= mt8189_lvts_ap_data_ctrl,
+	.conn_cmd		= default_conn_cmds,
+	.init_cmd		= default_init_cmds,
+	.num_lvts_ctrl		= ARRAY_SIZE(mt8189_lvts_ap_data_ctrl),
+	.num_conn_cmd		= ARRAY_SIZE(default_conn_cmds),
+	.num_init_cmd		= ARRAY_SIZE(default_init_cmds),
+	.temp_factor		= LVTS_COEFF_A_MT8195,
+	.temp_offset		= LVTS_COEFF_B_MT8195,
+	.gt_calib_bit_offset	= 0,
+	.def_calibration	= 35000,
+	.clock_gate_no_need	= true,
+	.reset_no_need		= true,
+	.conf_stage3_need	= true,
+};
+
+static const struct lvts_data mt8189_lvts_mcu_data = {
+	.lvts_ctrl		= mt8189_lvts_mcu_data_ctrl,
+	.num_lvts_ctrl		= ARRAY_SIZE(mt8189_lvts_mcu_data_ctrl),
+	.temp_factor		= LVTS_COEFF_A_MT8195,
+	.temp_offset		= LVTS_COEFF_B_MT8195,
+	.gt_calib_bit_offset	= 0,
+	.def_calibration	= 35000,
+	.clock_gate_no_need	= true,
+	.reset_no_need		= true,
+	.conf_stage3_need	= true,
+};
+
 static const struct lvts_data mt8192_lvts_mcu_data = {
 	.lvts_ctrl	= mt8192_lvts_mcu_data_ctrl,
 	.conn_cmd	= default_conn_cmds,
@@ -1861,6 +1988,8 @@ static const struct of_device_id lvts_of_match[] = {
 	{ .compatible = "mediatek,mt8186-lvts", .data = &mt8186_lvts_data },
 	{ .compatible = "mediatek,mt8188-lvts-mcu", .data = &mt8188_lvts_mcu_data },
 	{ .compatible = "mediatek,mt8188-lvts-ap", .data = &mt8188_lvts_ap_data },
+	{ .compatible = "mediatek,mt8189-lvts-mcu", .data = &mt8189_lvts_mcu_data },
+	{ .compatible = "mediatek,mt8189-lvts-ap", .data = &mt8189_lvts_ap_data },
 	{ .compatible = "mediatek,mt8192-lvts-mcu", .data = &mt8192_lvts_mcu_data },
 	{ .compatible = "mediatek,mt8192-lvts-ap", .data = &mt8192_lvts_ap_data },
 	{ .compatible = "mediatek,mt8195-lvts-mcu", .data = &mt8195_lvts_mcu_data },
-- 
2.45.2



From hanchien.lin at mediatek.com  Mon Dec  1 02:06:19 2025
From: hanchien.lin at mediatek.com (Hanchien Lin)
Date: Mon, 1 Dec 2025 18:06:19 +0800
Subject: [PATCH v2 1/2] arm64: dts: mediatek: mt8189: Add thermal controller node
In-Reply-To: <20251201100620.1557608-1-hanchien.lin@mediatek.com>
References: <20251201100620.1557608-1-hanchien.lin@mediatek.com>
Message-ID: <20251201100620.1557608-2-hanchien.lin@mediatek.com>

Add device tree node for the thermal controller on MediaTek MT8189 SoC.

Signed-off-by: Hanchien Lin <hanchien.lin at mediatek.com>
---
 .../thermal/mediatek,lvts-thermal.yaml        | 27 +++++++++++++++++--
 .../thermal/mediatek,lvts-thermal.h           | 20 ++++++++++++++
 2 files changed, 45 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml b/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml
index 0259cd3ce9c5..0f7fd69f5fdf 100644
--- a/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml
+++ b/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml
@@ -22,6 +22,8 @@ properties:
       - mediatek,mt8186-lvts
       - mediatek,mt8188-lvts-ap
       - mediatek,mt8188-lvts-mcu
+      - mediatek,mt8189-lvts-ap
+      - mediatek,mt8189-lvts-mcu
       - mediatek,mt8192-lvts-ap
       - mediatek,mt8192-lvts-mcu
       - mediatek,mt8195-lvts-ap
@@ -58,6 +60,21 @@ properties:
 allOf:
   - $ref: thermal-sensor.yaml#
 
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - mediatek,mt8189-lvts-ap
+              - mediatek,mt8189-lvts-mcu
+    then:
+      properties:
+        nvmem-cells:
+          minItems: 2
+
+        nvmem-cell-names:
+          minItems: 2
+
   - if:
       properties:
         compatible:
@@ -75,6 +92,10 @@ allOf:
         nvmem-cell-names:
           maxItems: 1
 
+      required:
+        - clocks
+        - resets
+
   - if:
       properties:
         compatible:
@@ -91,12 +112,14 @@ allOf:
         nvmem-cell-names:
           minItems: 2
 
+      required:
+        - clocks
+        - resets
+
 required:
   - compatible
   - reg
   - interrupts
-  - clocks
-  - resets
   - nvmem-cells
   - nvmem-cell-names
 
diff --git a/include/dt-bindings/thermal/mediatek,lvts-thermal.h b/include/dt-bindings/thermal/mediatek,lvts-thermal.h
index ddc7302a510a..6c9103dfdc2d 100644
--- a/include/dt-bindings/thermal/mediatek,lvts-thermal.h
+++ b/include/dt-bindings/thermal/mediatek,lvts-thermal.h
@@ -42,6 +42,26 @@
 #define MT8188_AP_CAM1		6
 #define MT8188_AP_CAM2		7
 
+#define MT8189_MCU_BIG_CPU1     0
+#define MT8189_MCU_BIG_CPU2     1
+#define MT8189_MCU_BIG_CPU3     2
+#define MT8189_MCU_BIG_CPU4     3
+#define MT8189_MCU_LITTLE_CPU1  4
+#define MT8189_MCU_LITTLE_CPU2  5
+#define MT8189_MCU_LITTLE_CPU3  6
+#define MT8189_MCU_LITTLE_CPU4  7
+#define MT8189_MCU_LITTLE_CPU5  8
+#define MT8189_MCU_LITTLE_CPU6  9
+#define MT8189_MCU_LITTLE_CPU7  10
+#define MT8189_MCU_LITTLE_CPU8  11
+
+#define MT8189_AP_SOC1          12
+#define MT8189_AP_SOC2          13
+#define MT8189_AP_SOC3          14
+#define MT8189_AP_APU           15
+#define MT8189_AP_GPU1          16
+#define MT8189_AP_GPU2          17
+
 #define MT8195_MCU_BIG_CPU0     0
 #define MT8195_MCU_BIG_CPU1     1
 #define MT8195_MCU_BIG_CPU2     2
-- 
2.45.2



From krzk at kernel.org  Mon Dec  1 02:09:41 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 1 Dec 2025 11:09:41 +0100
Subject: [PATCH v2 1/2] arm64: dts: mediatek: mt8189: Add thermal
 controller node
In-Reply-To: <20251201100620.1557608-2-hanchien.lin@mediatek.com>
References: <20251201100620.1557608-1-hanchien.lin@mediatek.com>
 <20251201100620.1557608-2-hanchien.lin@mediatek.com>
Message-ID: <ea8e4201-f1c2-41cc-83ff-b509fd22bca2@kernel.org>

On 01/12/2025 11:06, Hanchien Lin wrote:
> Add device tree node for the thermal controller on MediaTek MT8189 SoC.
> 
> Signed-off-by: Hanchien Lin <hanchien.lin at mediatek.com>


Nothing improved. You just completely ignored feedback expecting
reviewers to repeat themself.

NAK

Best regards,
Krzysztof


From krzk at kernel.org  Mon Dec  1 02:10:47 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 1 Dec 2025 11:10:47 +0100
Subject: [PATCH 1/5] dt-bindings: vendor-prefixes: Add Ezurio LLC
In-Reply-To: <aS1oQonkuFpyqSI2@owl5>
References: <20251201084140.376058-1-bisson.gary@gmail.com>
 <20251201084140.376058-2-bisson.gary@gmail.com>
 <176458161856.2489196.6170126310129033736.robh@kernel.org>
 <aS1oQonkuFpyqSI2@owl5>
Message-ID: <98e46b8e-e70f-4edb-ab59-f83e19bf01ec@kernel.org>

On 01/12/2025 11:04, Gary Bisson wrote:
>>
>> 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.
> 
> Couldn't reproduce, I can't seem to see any error/warning that would be
> introduced by this patch, can the above be discarded then?


Bot has a hiccup, you can ignore reports.

Best regards,
Krzysztof


From krzk at kernel.org  Mon Dec  1 02:12:12 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 1 Dec 2025 11:12:12 +0100
Subject: [PATCH 1/4] dt-bindings: arm: rockchip: Add HINLINK H28K
In-Reply-To: <20251201100008.206524-2-amadeus@jmu.edu.cn>
References: <20251201100008.206524-1-amadeus@jmu.edu.cn>
 <20251201100008.206524-2-amadeus@jmu.edu.cn>
Message-ID: <f27dc5ef-1c60-4724-8e18-33bbc4230d3e@kernel.org>

On 01/12/2025 11:00, Chukun Pan wrote:
> The HINLINK H28K is a dual-gigabit SBC based on the RK3528 SoC.
> Add devicetree binding documentation for it.
> 
> Signed-off-by: Chukun Pan <amadeus at jmu.edu.cn>
> ---
>  Documentation/devicetree/bindings/arm/rockchip.yaml | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/arm/rockchip.yaml b/Documentation/devicetree/bindings/arm/rockchip.yaml
> index d496421dbd87..8d6e2b28e51a 100644
> --- a/Documentation/devicetree/bindings/arm/rockchip.yaml
> +++ b/Documentation/devicetree/bindings/arm/rockchip.yaml
> @@ -718,6 +718,11 @@ properties:
>            - const: hardkernel,odroid-m2
>            - const: rockchip,rk3588s
>  
> +      - description: HINLINK H28K
> +        items:
> +          - const: hinlink,h28k
> +          - const: rockchip,rk3528
> +

Just squash these two binding patches. Way too much churn. Anyway, looks
like duplicate - two devices with same model name. You have entire
commit msg to explain that.

Best regards,
Krzysztof


From mark.rutland at arm.com  Mon Dec  1 02:13:54 2025
From: mark.rutland at arm.com (Mark Rutland)
Date: Mon, 1 Dec 2025 10:13:54 +0000
Subject: [PATCH 2/2] arm64: Avoid memcpy() for syscall_get_arguments()
In-Reply-To: <20251127123630.4149828-3-ruanjinjie@huawei.com>
References: <20251127123630.4149828-1-ruanjinjie@huawei.com>
 <20251127123630.4149828-3-ruanjinjie@huawei.com>
Message-ID: <aS1qYhHhZK3CD_bU@J2N7QTR9R3>

On Thu, Nov 27, 2025 at 08:36:30PM +0800, Jinjie Ruan wrote:
> Do not use memcpy() to extract syscall arguments from struct pt_regs
> but rather just perform direct assignments.
> 
> The performance benchmarks with Generic Entry patch[1] with audit on
> from perf bench basic syscall on kunpeng920 gives roughly a 1%
> performance uplift and also aligns the implementation with
> x86 and RISC-V.
> 
> | Metric     | W/O this patch | With this patch | Change    |
> | ---------- | -------------- | --------------- | --------- |
> | Total time | 2.241 [sec]    | 2.211 [sec]     |  ?1.36%   |
> | usecs/op   | 0.224157       | 0.221146        |  ?1.36%   |
> | ops/sec    | 4,461,157      | 4,501,409       |  ?0.9%    |
> 
> Before:
> <syscall_get_arguments.constprop.0>:
>        aa0103e2        mov     x2, x1
>        91002003        add     x3, x0, #0x8
>        f9408804        ldr     x4, [x0, #272]
>        f8008444        str     x4, [x2], #8
>        a9409404        ldp     x4, x5, [x0, #8]
>        a9009424        stp     x4, x5, [x1, #8]
>        a9418400        ldp     x0, x1, [x0, #24]
>        a9010440        stp     x0, x1, [x2, #16]
>        f9401060        ldr     x0, [x3, #32]
>        f9001040        str     x0, [x2, #32]
>        d65f03c0        ret
>        d503201f        nop
> 
> After:
>        a9408e82        ldp     x2, x3, [x20, #8]
>        2a1603e0        mov     w0, w22
>        f9400e84        ldr     x4, [x20, #24]
>        f9408a81        ldr     x1, [x20, #272]
>        9401c4ba        bl      ffff800080215ca8 <__audit_syscall_entry>

It's probably worth noting that __audit_syscall_entry() only takes 4
syscall arguments, and hence the compiler has elided the copy of
regs->regs[4] and regs->regs[5], which it apparently couldn't manage
before.

> [1]: https://lore.kernel.org/all/20251126071446.3234218-1-ruanjinjie at huawei.com/
> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
> ---
>  arch/arm64/include/asm/syscall.h | 8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
> index f3853047c28e..f3564ba97f7e 100644
> --- a/arch/arm64/include/asm/syscall.h
> +++ b/arch/arm64/include/asm/syscall.h
> @@ -82,9 +82,11 @@ static inline void syscall_get_arguments(struct task_struct *task,
>  					 unsigned long *args)
>  {
>  	args[0] = regs->orig_x0;
> -	args++;
> -
> -	memcpy(args, &regs->regs[1], 5 * sizeof(args[0]));
> +	args[1] = regs->regs[1];
> +	args[2] = regs->regs[2];
> +	args[3] = regs->regs[3];
> +	args[4] = regs->regs[4];
> +	args[5] = regs->regs[5];
>  }

FWIW, I think this is clearer than the 'args++' and the memcpy(), so I'm
happy with this regardless of the performance concern.

However, as Dmitry says, we should keep this structurally the same as
syscall_set_arguments(), and so we should update that in the same way.

Mark.


From gregkh at linuxfoundation.org  Mon Dec  1 02:14:03 2025
From: gregkh at linuxfoundation.org (Greg KH)
Date: Mon, 1 Dec 2025 11:14:03 +0100
Subject: [PATCH v2] coresight: etm3x: Fix cntr_val_show() to match
 cntr_val_store() behavior
In-Reply-To: <20251201095228.1905489-1-visitorckw@gmail.com>
References: <20251201095228.1905489-1-visitorckw@gmail.com>
Message-ID: <2025120149-broadways-upon-ad72@gregkh>

On Mon, Dec 01, 2025 at 09:52:28AM +0000, Kuan-Wei Chiu wrote:
> The cntr_val_show() function was intended to print the values of all
> counters using a loop. However, due to a buffer overwrite issue with
> sprintf(), it effectively only displayed the value of the last counter.
> 
> The companion function, cntr_val_store(), allows users to modify a
> specific counter selected by 'cntr_idx'. To maintain consistency
> between read and write operations and to align with the ETM4x driver
> behavior, modify cntr_val_show() to report only the value of the
> currently selected counter.
> 
> This change removes the loop and the "counter %d:" prefix, printing
> only the hexadecimal value. It also adopts sysfs_emit() for standard
> sysfs output formatting.
> 
> Fixes: a939fc5a71ad ("coresight-etm: add CoreSight ETM/PTM driver")
> Signed-off-by: Kuan-Wei Chiu <visitorckw at gmail.com>
> ---
> Build test only.
> 
> Changes in v2:
> - Redesigned the fix to match cntr_val_store() logic (display only the
>   currently selected counter) instead of attempting to list all
>   counters.
> - Removed the loop and the "counter %d:" prefix.
> - Switched from sprintf() to sysfs_emit().
> - Refactored control flow to use a single return point.
> 
> v1: https://lore.kernel.org/lkml/20251121002350.1166758-1-visitorckw at gmail.com/
> 
>  .../hwtracing/coresight/coresight-etm3x-sysfs.c   | 15 ++++-----------
>  1 file changed, 4 insertions(+), 11 deletions(-)
> 

Hi,

This is the friendly patch-bot of Greg Kroah-Hartman.  You have sent him
a patch that has triggered this response.  He used to manually respond
to these common problems, but in order to save his sanity (he kept
writing the same thing over and over, yet to different people), I was
created.  Hopefully you will not take offence and will fix the problem
in your patch and resubmit it so that it can be accepted into the Linux
kernel tree.

You are receiving this message because of the following common error(s)
as indicated below:

- You have marked a patch with a "Fixes:" tag for a commit that is in an
  older released kernel, yet you do not have a cc: stable line in the
  signed-off-by area at all, which means that the patch will not be
  applied to any older kernel releases.  To properly fix this, please
  follow the documented rules in the
  Documentation/process/stable-kernel-rules.rst file for how to resolve
  this.

If you wish to discuss this problem further, or you have questions about
how to resolve this issue, please feel free to respond to this email and
Greg will reply once he has dug out from the pending patches received
from other developers.

thanks,

greg k-h's patch email bot


From kevin.brodsky at arm.com  Mon Dec  1 02:17:52 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Mon, 1 Dec 2025 11:17:52 +0100
Subject: [PATCH v8 11/12] arm64: entry: Convert to generic entry
In-Reply-To: <0e65df65-c454-df7f-0685-42e9c0f0f9e3@huawei.com>
References: <20251126071446.3234218-1-ruanjinjie@huawei.com>
 <20251126071446.3234218-12-ruanjinjie@huawei.com>
 <c6cf8755-34d0-468d-99c4-ac6d266f9efb@arm.com>
 <bfdd914c-4c3a-9af7-d530-f57f3532c3d5@huawei.com>
 <8c55c2a1-995e-44a1-8d48-b7d794f5176f@arm.com>
 <0e65df65-c454-df7f-0685-42e9c0f0f9e3@huawei.com>
Message-ID: <65c7307b-1f4e-4ae7-8bcf-8bfd9a9186fb@arm.com>

On 29/11/2025 02:23, Jinjie Ruan wrote:
>>>>>  #define TIF_UPROBE		5	/* uprobe breakpoint or singlestep */
>>>>>  #define TIF_MTE_ASYNC_FAULT	6	/* MTE Asynchronous Tag Check Fault */
>>>>>  #define TIF_NOTIFY_SIGNAL	7	/* signal notifications exist */
>>>>> -#define TIF_SYSCALL_TRACE	8	/* syscall trace active */
>>>>> -#define TIF_SYSCALL_AUDIT	9	/* syscall auditing */
>>>>> -#define TIF_SYSCALL_TRACEPOINT	10	/* syscall tracepoint for ftrace */
>>>>> -#define TIF_SECCOMP		11	/* syscall secure computing */
>>>>> -#define TIF_SYSCALL_EMU		12	/* syscall emulation active */
>>>>> +#define TIF_SECCOMP		11      /* syscall secure computing */
>>>>> +#define TIF_SYSCALL_EMU		12      /* syscall emulation active */
>>>> These seem to have reappeared in v8 for some reason?
>>> v8 add "ARCH_SYSCALL_WORK_EXIT" to be defined as "SECCOMP | SYSCALL_EMU"
>>>   to keep the arm64 behaviour unchanged as mentioned in v7.
>> Ah then that is where the issue is, I missed that: surely switching to
>> generic entry means that we are using SYSCALL_WORK_BIT_* rather than
>> TIF_* for all these flags?
> I think they may be the same thing as you mentioned in v7?neither
> SYSCALL_WORK_EXIT nor report_single_step() excluded SYSCALL_EMU, maybe
> we should clarify them for arm64 together in a separate patch.

These two might indeed be related. On second thoughts, while waiting for
more knowledgeable arm64 reviewers, I would suggest aligning arm64 with
the generic entry. Which means...

> 1?"The generic report_single_step() always returns false if SYSCALL_EMU
> is set."

... replicating this behaviour on arm64 (in a separate patch), and...

> 2?"
>      > -void syscall_exit_to_user_mode_prepare(struct pt_regs *regs)
>      > -{
>      > -	unsigned long flags = read_thread_flags();
>      > -
>      > -	rseq_syscall(regs);
>      > -
>      > -	if (has_syscall_work(flags) || flags & _TIF_SINGLESTEP)
>
>      I believe switching to the generic function introduces a change
>      here: syscall_exit_work() is only called if a flag in
> SYSCALL_WORK_EXIT is set, and this set does not include SYSCALL_EMU and
>     SECCOMP. Practically this means that audit_syscall_exit() will no
>     longer be called if only SECCOMP and/or SYSCALL_EMU is set.
>
>    It doesn't feel like a major behaviour change, but it should be
>    pointed out."

... replicating this on arm64 as well, i.e. introducing a separate set
of flags for syscall exit. This should be a patch of its own, as it
isn't directly related to the report_single_step() behaviour (especially
since it concerns SECCOMP as well). It would also be an occasion to get
rid of has_syscall_work(), in preparation to the move to generic entry.

- Kevin


From bisson.gary at gmail.com  Mon Dec  1 02:23:14 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Mon, 01 Dec 2025 11:23:14 +0100
Subject: [PATCH v2 0/4] Add support for Ezurio MediaTek platforms
Message-ID: <20251201-review-v2-0-dc2df44eec7e@gmail.com>

This series adds support for Ezurio MediaTek platforms called
"Tungsten". It includes support for MT8370-based Tungsten 510 and
MT8390-based Tungsten 700 SOMs.

Changelog v1 -> v2:
- use b4 to cc all maintainers properly
- squashed patches 2/3 together
- updated node names to be generic (pmic)

Couldn't repro the schema issues sent by the bots.

Regards,

Gary Bisson (4):
  dt-bindings: vendor-prefixes: Add Ezurio LLC
  dt-bindings: arm: mediatek: Add Ezurio Tungsten entries
  arm64: dts: mediatek: add device tree for Tungsten 510 board
  arm64: dts: mediatek: add device tree for Tungsten 700 board

 .../devicetree/bindings/arm/mediatek.yaml     |    2 +
 .../devicetree/bindings/vendor-prefixes.yaml  |    2 +
 arch/arm64/boot/dts/mediatek/Makefile         |    2 +
 .../dts/mediatek/mt8370-tungsten-smarc.dts    |   14 +
 .../dts/mediatek/mt8390-tungsten-smarc.dts    |   22 +
 .../dts/mediatek/mt83x0-tungsten-smarc.dtsi   | 1481 +++++++++++++++++
 6 files changed, 1523 insertions(+)
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts
 create mode 100644 arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi

--
2.43.0

---
Gary Bisson (4):
      dt-bindings: vendor-prefixes: Add Ezurio LLC
      dt-bindings: arm: mediatek: Add Ezurio Tungsten entries
      arm64: dts: mediatek: add device tree for Tungsten 510 board
      arm64: dts: mediatek: add device tree for Tungsten 700 board

 .../devicetree/bindings/arm/mediatek.yaml          |    2 +
 .../devicetree/bindings/vendor-prefixes.yaml       |    2 +
 arch/arm64/boot/dts/mediatek/Makefile              |    2 +
 .../boot/dts/mediatek/mt8370-tungsten-smarc.dts    |   14 +
 .../boot/dts/mediatek/mt8390-tungsten-smarc.dts    |   22 +
 .../boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi   | 1481 ++++++++++++++++++++
 6 files changed, 1523 insertions(+)
---
base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
change-id: 20251201-review-750072579991

Best regards,
-- 
Gary Bisson <bisson.gary at gmail.com>



From bisson.gary at gmail.com  Mon Dec  1 02:23:17 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Mon, 01 Dec 2025 11:23:17 +0100
Subject: [PATCH v2 3/4] arm64: dts: mediatek: add device tree for Tungsten
 510 board
In-Reply-To: <20251201-review-v2-0-dc2df44eec7e@gmail.com>
References: <20251201-review-v2-0-dc2df44eec7e@gmail.com>
Message-ID: <20251201-review-v2-3-dc2df44eec7e@gmail.com>

Add device tree to support Ezurio Tungsten 510 (MT8370) SMARC SOM [1] +
Universal SMARC carrier board [2].
It includes support for the MIPI-DSI BD070LIC3 display which uses the
Tianma TM070JDHG30 panel + TI SN65DSI84 MIPI-DSI to LVDS bridge [3].

[1] https://www.ezurio.com/product/tungsten510-smarc
[2] https://www.ezurio.com/system-on-module/accessories/universal-smarc-carrier
[3] https://www.ezurio.com/product/bd070lic3-7-touchscreen-display

Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
---
 arch/arm64/boot/dts/mediatek/Makefile              |    1 +
 .../boot/dts/mediatek/mt8370-tungsten-smarc.dts    |   14 +
 .../boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi   | 1481 ++++++++++++++++++++
 3 files changed, 1496 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile
index a4df4c21399e..30d169a31b10 100644
--- a/arch/arm64/boot/dts/mediatek/Makefile
+++ b/arch/arm64/boot/dts/mediatek/Makefile
@@ -99,6 +99,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8195-demo.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8195-evb.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8365-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-genio-510-evk.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-tungsten-smarc.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-genio-1200-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-genio-700-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-kontron-3-5-sbc-i1200.dtb
diff --git a/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts b/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts
new file mode 100644
index 000000000000..d713ef77df3a
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2025 Ezurio LLC
+ * Author: Gary Bisson <bisson.gary at gmail.com>
+ */
+/dts-v1/;
+#include "mt8370.dtsi"
+#include "mt83x0-tungsten-smarc.dtsi"
+
+/ {
+	model = "Ezurio Tungsten510 SMARC (MT8370)";
+	compatible = "ezurio,mt8370-tungsten-smarc", "mediatek,mt8370",
+		     "mediatek,mt8188";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi b/arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi
new file mode 100644
index 000000000000..77e8dbea335a
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi
@@ -0,0 +1,1481 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2025 Ezurio LLC
+ * Author: Gary Bisson <bisson.gary at gmail.com>
+ */
+
+#include "mt6359.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/net/microchip-lan78xx.h>
+#include <dt-bindings/pinctrl/mediatek,mt8188-pinfunc.h>
+#include <dt-bindings/usb/pd.h>
+
+/ {
+	aliases {
+		dsi0 = &disp_dsi0;
+		ethernet0 = &eth;
+		i2c0 = &i2c0;
+		i2c1 = &i2c1;
+		i2c2 = &i2c2;
+		i2c3 = &i2c3;
+		i2c4 = &i2c4;
+		i2c5 = &i2c5;
+		i2c6 = &i2c6;
+		mmc0 = &mmc0;
+		mmc1 = &mmc1;
+		mmc2 = &mmc2;
+		rtc0 = &rv3028;
+		rtc1 = &mt6359rtc;
+		serial0 = &uart0;
+	};
+
+	backlight_lcd0: backlight-lcd0 {
+		compatible = "pwm-backlight";
+		brightness-levels = <0 1023>;
+		default-brightness-level = <768>;
+		num-interpolated-steps = <1023>;
+		enable-gpios = <&pio 30 GPIO_ACTIVE_HIGH>;
+		pwms = <&disp_pwm0 0 30000>;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	firmware {
+		optee {
+			compatible = "linaro,optee-tz";
+			method = "smc";
+		};
+	};
+
+	memory at 40000000 {
+		device_type = "memory";
+		reg = <0 0x40000000 0x1 0x00000000>;
+	};
+
+	panel-dsi0 {
+		compatible = "tianma,tm070jdhg30";
+		backlight = <&backlight_lcd0>;
+
+		port {
+			dsi0_panel_in: endpoint {
+				remote-endpoint = <&sn65dsi84_bridge_out>;
+			};
+		};
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		/*
+		 * 12 MiB reserved for OP-TEE (BL32)
+		 * +-----------------------+ 0x43e0_0000
+		 * |      SHMEM 2MiB       |
+		 * +-----------------------+ 0x43c0_0000
+		 * |        | TA_RAM  8MiB |
+		 * + TZDRAM +--------------+ 0x4340_0000
+		 * |        | TEE_RAM 2MiB |
+		 * +-----------------------+ 0x4320_0000
+		 */
+		optee_reserved: optee at 43200000 {
+			no-map;
+			reg = <0 0x43200000 0 0x00c00000>;
+		};
+
+		scp_mem: memory at 50000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x50000000 0 0x2900000>;
+			no-map;
+		};
+
+		/* 2 MiB reserved for ARM Trusted Firmware (BL31) */
+		bl31_secmon_reserved: memory at 54600000 {
+			no-map;
+			reg = <0 0x54600000 0x0 0x200000>;
+		};
+
+		apu_mem: memory at 55000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x55000000 0 0x1400000>; /* 20 MB */
+		};
+
+		vpu_mem: memory at 57000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x57000000 0 0x1400000>; /* 20 MB */
+		};
+
+		adsp_mem: memory at 60000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x60000000 0 0xf00000>;
+			no-map;
+		};
+
+		afe_dma_mem: memory at 60f00000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x60f00000 0 0x100000>;
+			no-map;
+		};
+
+		adsp_dma_mem: memory at 61000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x61000000 0 0x100000>;
+			no-map;
+		};
+	};
+
+	regulator-efuse {
+		compatible = "regulator-output";
+		vout-supply = <&mt6359_vefuse_ldo_reg>;
+	};
+
+	sdcard_en_3v3: regulator-sdcard-en {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-name = "sdcard_en_3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&pio 111 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	usb_p0_vbus: regulator-usb-p0-vbus {
+		compatible = "regulator-fixed";
+		regulator-name = "vbus_p0";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&pio 84 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	usb_p1_vbus: regulator-usb-p1-vbus {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&usb1_hub_pins>;
+		regulator-name = "vbus_p1";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		gpio = <&pio 147 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	usb_p2_vbus: regulator-usb-p2-vbus {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&usb2_eth_pins>;
+		regulator-name = "vbus_p2";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		gpio = <&pio 80 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	wifi_pwrseq: wifi-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		pinctrl-names = "default";
+		pinctrl-0 = <&wifi_pwrseq_pins>;
+		post-power-on-delay-ms = <200>;
+		reset-gpios = <&pio 89 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&adsp {
+	memory-region = <&adsp_dma_mem>, <&adsp_mem>;
+	status = "okay";
+};
+
+&afe {
+	memory-region = <&afe_dma_mem>;
+	status = "okay";
+};
+
+&cpu0 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};
+
+&cpu1 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};
+
+&cpu2 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};
+
+&cpu3 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};
+
+&cpu6 {
+	cpu-supply = <&mt6315_6_vbuck1>;
+};
+
+&cpu7 {
+	cpu-supply = <&mt6315_6_vbuck1>;
+};
+
+&disp_pwm0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&disp_pwm0_pins>;
+	status = "okay";
+};
+
+&disp_dsi0 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			reg = <0>;
+			dsi0_in: endpoint {
+				remote-endpoint = <&dither0_out>;
+			};
+		};
+
+		port at 1 {
+			reg = <1>;
+			dsi0_out: endpoint {
+				remote-endpoint = <&sn65dsi84_bridge_in>;
+			};
+		};
+	};
+};
+
+&dither0_in {
+	remote-endpoint = <&postmask0_out>;
+};
+
+&dither0_out {
+	remote-endpoint = <&dsi0_in>;
+};
+
+&eth {
+	phy-mode ="rgmii-id";
+	phy-handle = <&ethernet_phy0>;
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&eth_default_pins>;
+	pinctrl-1 = <&eth_sleep_pins>;
+	mediatek,mac-wol;
+	snps,reset-gpio = <&pio 27 GPIO_ACTIVE_LOW>;
+	snps,reset-active-low;
+	snps,reset-delays-us = <0 11000 1000>;
+	status = "okay";
+};
+
+&eth_mdio {
+	ethernet_phy0: ethernet-phy at 7 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <0x7>;
+		interrupts-extended = <&pio 148 IRQ_TYPE_LEVEL_LOW>;
+	};
+};
+
+&gamma0_out {
+	remote-endpoint = <&postmask0_in>;
+};
+
+&gpu {
+	mali-supply = <&mt6359_vproc2_buck_reg>;
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default", "gpio";
+	pinctrl-0 = <&i2c0_pins>;
+	pinctrl-1 = <&i2c0_gpio_pins>;
+	scl-gpios = <&pio 55 GPIO_OPEN_DRAIN>;
+	sda-gpios = <&pio 56 GPIO_OPEN_DRAIN>;
+	clock-frequency = <100000>;
+	status = "okay";
+
+	i2c-mux at 73 {
+		compatible = "nxp,pca9546";
+		reg = <0x73>;
+		reset-gpios = <&pio 6 GPIO_ACTIVE_LOW>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		i2c_mux_gp_0: i2c at 0 {
+			clock-frequency = <100000>;
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_gp_1: i2c at 1 {
+			clock-frequency = <100000>;
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_gp_2: i2c at 2 {
+			clock-frequency = <100000>;
+			reg = <2>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_gp_3: i2c at 3 {
+			clock-frequency = <100000>;
+			reg = <3>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	clock-frequency = <400000>;
+	status = "okay";
+};
+
+&i2c2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_pins>;
+	clock-frequency = <400000>;
+	status = "okay";
+
+	i2c-mux at 73 {
+		compatible = "nxp,pca9546";
+		pinctrl-names = "default";
+		pinctrl-0 = <&i2c_mux_smarc_lcd_pins>;
+		reg = <0x73>;
+		reset-gpios = <&pio 5 GPIO_ACTIVE_LOW>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		i2c_mux_lcd_0: i2c at 0 {
+			clock-frequency = <100000>;
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_lcd_1: i2c at 1 {
+			clock-frequency = <100000>;
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_lcd_2: i2c at 2 {
+			clock-frequency = <100000>;
+			reg = <2>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_lcd_3: i2c at 3 {
+			clock-frequency = <100000>;
+			reg = <3>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+};
+
+&i2c3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c3_pins>;
+	clock-frequency = <400000>;
+	status = "okay";
+};
+
+&i2c4 {
+	pinctrl-names = "default", "default";
+	pinctrl-0 = <&i2c4_pins>;
+	clock-frequency = <400000>;
+	status = "okay";
+};
+
+&i2c_mux_gp_0 {
+	rv3028: rtc at 52 {
+		compatible = "microcrystal,rv3028";
+		reg = <0x52>;
+		interrupts-extended = <&pio 42 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&rv3028_pins>;
+		#clock-cells = <0>;
+		wakeup-source;
+	};
+};
+
+&i2c_mux_gp_1 {
+	usb-typec at 60 {
+		compatible = "ti,hd3ss3220";
+		interrupts-extended = <&pio 45 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&hd3ss3220_pins>;
+		reg = <0x60>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+				hd3ss3220_in_ep: endpoint {
+					remote-endpoint = <&ss_ep>;
+				};
+			};
+
+			port at 1 {
+				reg = <1>;
+				hd3ss3220_out_ep: endpoint {
+					remote-endpoint = <&usb_role_switch>;
+				};
+			};
+		};
+	};
+};
+
+&i2c_mux_gp_2 {
+	codec at 1a {
+		#sound-dai-cells = <0>;
+		clocks = <&topckgen CLK_TOP_I2SO1>;
+		compatible = "wlf,wm8962";
+		gpio-cfg = <
+			0x0000 /* n/c */
+			0x0000 /* gpio2: */
+			0x0000 /* gpio3: */
+			0x0000 /* n/c */
+			0x8081 /* gpio5:HP detect */
+			0x8095 /* gpio6:Mic detect */
+		>;
+		reg = <0x1a>;
+	};
+};
+
+&i2c_mux_lcd_2 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	bridge at 2c {
+		compatible = "ti,sn65dsi84";
+		reg = <0x2c>;
+		enable-gpios = <&pio 25 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&dsi0_sn65dsi84_pins>;
+		status = "okay";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+
+				sn65dsi84_bridge_in: endpoint {
+					remote-endpoint = <&dsi0_out>;
+					data-lanes = <1 2 3 4>;
+				};
+			};
+
+			port at 2 {
+				reg = <2>;
+
+				sn65dsi84_bridge_out: endpoint {
+					remote-endpoint = <&dsi0_panel_in>;
+				};
+			};
+		};
+	};
+
+	touchscren at 5d {
+		compatible = "goodix,gt911";
+		reg = <0x5d>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&ts_dsi0_goodix_pins>;
+		interrupts-extended = <&pio 146 IRQ_TYPE_LEVEL_HIGH>;
+		irq-gpios = <&pio 146 GPIO_ACTIVE_HIGH>;
+		reset-gpios = <&pio 7 GPIO_ACTIVE_HIGH>;
+	};
+};
+
+&mfg0 {
+	domain-supply = <&mt6359_vproc2_buck_reg>;
+};
+
+&mfg1 {
+	domain-supply = <&mt6359_vsram_others_ldo_reg>;
+};
+
+&mmc0 {
+	status = "okay";
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc0_default_pins>;
+	pinctrl-1 = <&mmc0_uhs_pins>;
+	bus-width = <8>;
+	max-frequency = <200000000>;
+	cap-mmc-highspeed;
+	cap-mmc-hw-reset;
+	mmc-hs200-1_8v;
+	mmc-hs400-1_8v;
+	supports-cqe;
+	cap-mmc-hw-reset;
+	no-sdio;
+	no-sd;
+	hs400-ds-delay = <0x1481b>;
+	vmmc-supply = <&mt6359_vemc_1_ldo_reg>;
+	vqmmc-supply = <&mt6359_vufs_ldo_reg>;
+	non-removable;
+};
+
+&mmc1 {
+	status = "okay";
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc1_default_pins>;
+	pinctrl-1 = <&mmc1_uhs_pins>;
+	bus-width = <4>;
+	max-frequency = <200000000>;
+	cap-sd-highspeed;
+	sd-uhs-sdr50;
+	sd-uhs-sdr104;
+	cd-gpios = <&pio 2 GPIO_ACTIVE_LOW>;
+	vqmmc-supply = <&mt6359_vsim1_ldo_reg>;
+	vmmc-supply = <&sdcard_en_3v3>;
+};
+
+&mmc2 {
+	status = "okay";
+	pinctrl-names = "default", "state_uhs", "state_eint";
+	pinctrl-0 = <&mmc2_default_pins>;
+	pinctrl-1 = <&mmc2_uhs_pins>;
+	pinctrl-2 = <&mmc2_eint_pins>;
+	eint-gpios = <&pio 172 0>;
+	bus-width = <4>;
+	max-frequency = <200000000>;
+	cap-sd-highspeed;
+	sd-uhs-sdr104;
+	keep-power-in-suspend;
+	enable-sdio-wakeup;
+	cap-sdio-async-int;
+	cap-sdio-irq;
+	no-mmc;
+	no-sd;
+	non-removable;
+	vmmc-supply = <&mt6359_vcn33_2_bt_ldo_reg>;
+	vqmmc-supply = <&mt6359_vcn18_ldo_reg>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+};
+
+&mipi_tx_config0 {
+	status = "okay";
+};
+
+&mt6359codec {
+	mediatek,mic-type-0 = <1>;
+	mediatek,mic-type-1 = <3>;
+	mediatek,mic-type-2 = <0>;
+	mediatek,dmic-mode = <0>;
+};
+
+&mt6359_vbbck_ldo_reg {
+	regulator-always-on;
+};
+
+&mt6359_vcn18_ldo_reg {
+	regulator-name = "vcn18_pmu";
+	regulator-always-on;
+	regulator-boot-on;
+};
+
+&mt6359_vcn33_1_bt_ldo_reg {
+	regulator-name = "vcn33_1_pmu";
+	regulator-always-on;
+};
+
+&mt6359_vcn33_2_bt_ldo_reg {
+	regulator-name = "vcn33_2_pmu";
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-always-on;
+	regulator-boot-on;
+};
+
+&mt6359_vcore_buck_reg {
+	regulator-name = "dvdd_proc_l";
+	regulator-always-on;
+};
+
+&mt6359_vemc_1_ldo_reg {
+	regulator-always-on;
+};
+
+&mt6359_vgpu11_buck_reg {
+	regulator-name = "dvdd_core";
+	regulator-always-on;
+};
+
+&mt6359_vmodem_buck_reg {
+	regulator-always-on;
+};
+
+&mt6359_vpa_buck_reg {
+	regulator-name = "vpa_pmu";
+	regulator-always-on;
+};
+
+&mt6359_vproc2_buck_reg {
+	/* The name "vgpu" is required by mtk-regulator-coupler */
+	regulator-name = "vgpu";
+	regulator-min-microvolt = <550000>;
+	regulator-max-microvolt = <800000>;
+	regulator-coupled-with = <&mt6359_vsram_others_ldo_reg>;
+	regulator-coupled-max-spread = <225000>;
+	regulator-always-on;
+};
+
+&mt6359_vs2_buck_reg {
+	regulator-min-microvolt = <1600000>;
+	regulator-boot-on;
+};
+
+&mt6359_vpu_buck_reg {
+	regulator-name = "dvdd_adsp";
+	regulator-always-on;
+};
+
+&mt6359_vrf12_ldo_reg {
+	regulator-name = "va12_abb2_pmu";
+	regulator-always-on;
+};
+
+&mt6359_vsram_md_ldo_reg {
+	regulator-always-on;
+};
+
+&mt6359_vsram_others_ldo_reg {
+	/* The name "vsram_gpu" is required by mtk-regulator-coupler */
+	regulator-name = "vsram_gpu";
+	regulator-min-microvolt = <750000>;
+	regulator-max-microvolt = <800000>;
+	regulator-coupled-with = <&mt6359_vproc2_buck_reg>;
+	regulator-coupled-max-spread = <225000>;
+	regulator-always-on;
+};
+
+&mt6359_vsim1_ldo_reg {
+	regulator-name = "vsim1_pmu";
+	regulator-max-microvolt = <1800000>;
+	regulator-enable-ramp-delay = <480>;
+};
+
+&mt6359_vufs_ldo_reg {
+	regulator-name = "vufs18_pmu";
+	regulator-always-on;
+};
+
+&ovl0_in {
+	remote-endpoint = <&vdosys0_ep_main>;
+};
+
+&pcie {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie_default_pins>;
+	status = "okay";
+};
+
+&pciephy {
+	status = "okay";
+};
+
+&pmic {
+	interrupt-parent = <&pio>;
+	interrupts = <222 IRQ_TYPE_LEVEL_HIGH>;
+
+	keys {
+		compatible = "mediatek,mt6359-keys";
+		mediatek,long-press-mode = <1>;
+		power-off-time-sec = <0>;
+
+		power-key {
+			linux,keycodes = <116>;
+			wakeup-source;
+		};
+	};
+};
+
+&postmask0_in {
+	remote-endpoint = <&gamma0_out>;
+};
+
+&postmask0_out {
+	remote-endpoint = <&dither0_in>;
+};
+
+&scp_cluster {
+	status = "okay";
+};
+
+&scp_c0 {
+	firmware-name = "mediatek/mt8188/scp.img";
+	memory-region = <&scp_mem>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-0 = <&spi0_pins>;
+	pinctrl-names = "default";
+	mediatek,pad-select = <0>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+};
+
+&spi1 {
+	pinctrl-0 = <&spi1_pins>;
+	pinctrl-names = "default";
+	mediatek,pad-select = <0>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+};
+
+&spmi {
+	#address-cells = <1>;
+	#size-cells = <2>;
+
+	mt6315_6: pmic at 6 {
+		compatible = "mediatek,mt6315-regulator";
+		reg = <0x6 0 0xb>;
+
+		regulators {
+			mt6315_6_vbuck1: vbuck1 {
+				regulator-compatible = "vbuck1";
+				regulator-name = "vbuck1";
+				regulator-min-microvolt = <300000>;
+				regulator-max-microvolt = <1193750>;
+				regulator-enable-ramp-delay = <256>;
+				regulator-allowed-modes = <0 1 2>;
+				regulator-always-on;
+				mtk,combined-regulator = <2>;
+			};
+
+			mt6315_6_vbuck3: vbuck3 {
+				regulator-compatible = "vbuck3";
+				regulator-name = "vbuck3";
+				regulator-min-microvolt = <300000>;
+				regulator-max-microvolt = <1193750>;
+				regulator-enable-ramp-delay = <256>;
+				regulator-allowed-modes = <0 1 2>;
+				regulator-always-on;
+			};
+
+			mt6315_6_vbuck4: vbuck4 {
+				regulator-compatible = "vbuck4";
+				regulator-name = "vbuck4";
+				regulator-min-microvolt = <1193750>;
+				regulator-max-microvolt = <1193750>;
+				regulator-enable-ramp-delay = <256>;
+				regulator-allowed-modes = <0 1 2>;
+				regulator-always-on;
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1193750>;
+				};
+			};
+		};
+	};
+};
+
+&uart0 {
+	pinctrl-0 = <&uart0_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-0 = <&uart1_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-0 = <&uart2_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&ssusb0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&usbotg_pins>;
+	maximum-speed = "high-speed";
+	usb-role-switch;
+	dr_mode = "otg";
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	wakeup-source;
+	status = "okay";
+
+	connector {
+		compatible = "usb-c-connector";
+		label = "USB-C";
+		data-role = "dual";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+				hs_ep: endpoint {
+					remote-endpoint = <&usb_hs_ep>;
+				};
+			};
+
+			port at 1 {
+				reg = <1>;
+				ss_ep: endpoint {
+					remote-endpoint = <&hd3ss3220_in_ep>;
+				};
+			};
+		};
+	};
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			reg = <0>;
+			usb_hs_ep: endpoint {
+				remote-endpoint = <&hs_ep>;
+			};
+		};
+
+		port at 1 {
+			reg = <1>;
+			usb_role_switch: endpoint {
+				remote-endpoint = <&hd3ss3220_out_ep>;
+			};
+		};
+	};
+};
+
+&u2port0 {
+	status = "okay";
+};
+
+&u3phy0 {
+	status = "okay";
+};
+
+&xhci0 {
+	vbus-supply = <&usb_p0_vbus>;
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	status = "okay";
+};
+
+&ssusb1 {
+	pinctrl-0 = <&usb1_pins>;
+	pinctrl-names = "default";
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	dr_mode = "host";
+	wakeup-source;
+	status = "okay";
+};
+
+&u2port1 {
+	status = "okay";
+};
+
+&u3port1 {
+	status = "okay";
+};
+
+&u3phy1 {
+	status = "okay";
+};
+
+&xhci1 {
+	vbus-supply = <&usb_p1_vbus>;
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	status = "okay";
+};
+
+&ssusb2 {
+	maximum-speed = "high-speed";
+	dr_mode = "host";
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	status = "okay";
+	wakeup-source;
+};
+
+&u2port2 {
+	status = "okay";
+};
+
+&u3phy2 {
+	status = "okay";
+};
+
+&xhci2 {
+	vbus-supply = <&usb_p2_vbus>;
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+
+	ethernet at 1 {
+		compatible = "usb424,7850";
+		reg = <1>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		mdio {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			ethernet-phy at 1 {
+				reg = <1>;
+				microchip,led-modes = <
+					LAN78XX_LINK_1000_ACTIVITY
+					LAN78XX_LINK_10_ACTIVITY
+					LAN78XX_LINK_10_100_ACTIVITY
+					LAN78XX_LINK_ACTIVITY
+				>;
+			};
+		};
+	};
+};
+
+&vdosys0 {
+	port {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		vdosys0_ep_main: endpoint at 0 {
+			reg = <0>;
+			remote-endpoint = <&ovl0_in>;
+		};
+	};
+};
+
+&watchdog {
+	pinctrl-names = "default";
+	pinctrl-0 = <&watchdog_pins>;
+};
+
+&pio {
+	audio_pins: audio-pins {
+		pins-aud-pmic {
+			pinmux = <
+				PINMUX_GPIO101__FUNC_O_AUD_CLK_MOSI
+				PINMUX_GPIO102__FUNC_O_AUD_SYNC_MOSI
+				PINMUX_GPIO103__FUNC_O_AUD_DAT_MOSI0
+				PINMUX_GPIO104__FUNC_O_AUD_DAT_MOSI1
+				PINMUX_GPIO105__FUNC_I0_AUD_DAT_MISO0
+				PINMUX_GPIO106__FUNC_I0_AUD_DAT_MISO1
+			>;
+		};
+
+		pins-pcm-wifi {
+			pinmux = <
+				PINMUX_GPIO121__FUNC_B0_PCM_CLK
+				PINMUX_GPIO122__FUNC_B0_PCM_SYNC
+				PINMUX_GPIO123__FUNC_O_PCM_DO
+				PINMUX_GPIO124__FUNC_I0_PCM_DI
+			>;
+		};
+
+		pins-i2s {
+			pinmux = <
+				PINMUX_GPIO119__FUNC_O_I2SO1_MCK
+				PINMUX_GPIO112__FUNC_O_I2SO1_WS
+				PINMUX_GPIO120__FUNC_O_I2SO1_BCK
+				PINMUX_GPIO113__FUNC_O_I2SO1_D0
+				PINMUX_GPIO110__FUNC_I0_I2SIN_D0
+			>;
+		};
+	};
+
+	disp_pwm0_pins: disp-pwm0-pins {
+		pins {
+			pinmux = <PINMUX_GPIO29__FUNC_O_DISP_PWM0>;
+			bias-pull-down;
+		};
+	};
+
+	dsi0_sn65dsi84_pins: dsi0-sn65dsi84-pins {
+		pins-irq {
+			pinmux = <PINMUX_GPIO128__FUNC_B_GPIO128>;
+			bias-pull-down;
+			input-enable;
+		};
+
+		pins-enable {
+			pinmux = <PINMUX_GPIO25__FUNC_B_GPIO25>;
+			bias-pull-down;
+		};
+	};
+
+	eth_default_pins: eth-default-pins {
+		pins-txd {
+			pinmux = <PINMUX_GPIO131__FUNC_O_GBE_TXD3>,
+				 <PINMUX_GPIO132__FUNC_O_GBE_TXD2>,
+				 <PINMUX_GPIO133__FUNC_O_GBE_TXD1>,
+				 <PINMUX_GPIO134__FUNC_O_GBE_TXD0>;
+			drive-strength = <MTK_DRIVE_8mA>;
+		};
+		pins-cc {
+			pinmux = <PINMUX_GPIO139__FUNC_B0_GBE_TXC>,
+				 <PINMUX_GPIO142__FUNC_O_GBE_TXEN>,
+				 <PINMUX_GPIO141__FUNC_I0_GBE_RXDV>;
+			drive-strength = <MTK_DRIVE_8mA>;
+		};
+		pins-rxd {
+			pinmux = <PINMUX_GPIO135__FUNC_I0_GBE_RXD3>,
+				 <PINMUX_GPIO136__FUNC_I0_GBE_RXD2>,
+				 <PINMUX_GPIO137__FUNC_I0_GBE_RXD1>,
+				 <PINMUX_GPIO138__FUNC_I0_GBE_RXD0>,
+				 <PINMUX_GPIO140__FUNC_I0_GBE_RXC>;
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
+		};
+		pins-mdio {
+			pinmux = <PINMUX_GPIO143__FUNC_O_GBE_MDC>,
+				 <PINMUX_GPIO144__FUNC_B1_GBE_MDIO>;
+			drive-strength = <MTK_DRIVE_8mA>;
+			input-enable;
+		};
+		pins-power {
+			pinmux = <PINMUX_GPIO27__FUNC_B_GPIO27>; /* GP_EQOS_RESET */
+			output-high;
+		};
+		pins-intr {
+			pinmux = <PINMUX_GPIO148__FUNC_B_GPIO148>; /* GPIRQ_EQOS_PHY */
+			bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
+			input-enable;
+		};
+	};
+
+	eth_sleep_pins: eth-sleep-pins {
+		pins-txd {
+			pinmux = <PINMUX_GPIO131__FUNC_B_GPIO131>,
+				 <PINMUX_GPIO132__FUNC_B_GPIO132>,
+				 <PINMUX_GPIO133__FUNC_B_GPIO133>,
+				 <PINMUX_GPIO134__FUNC_B_GPIO134>;
+		};
+		pins-cc {
+			pinmux = <PINMUX_GPIO139__FUNC_B_GPIO139>,
+				 <PINMUX_GPIO142__FUNC_B_GPIO142>,
+				 <PINMUX_GPIO141__FUNC_B_GPIO141>,
+				 <PINMUX_GPIO140__FUNC_B_GPIO140>;
+		};
+		pins-rxd {
+			pinmux = <PINMUX_GPIO135__FUNC_B_GPIO135>,
+				 <PINMUX_GPIO136__FUNC_B_GPIO136>,
+				 <PINMUX_GPIO137__FUNC_B_GPIO137>,
+				 <PINMUX_GPIO138__FUNC_B_GPIO138>;
+		};
+		pins-mdio {
+			pinmux = <PINMUX_GPIO143__FUNC_B_GPIO143>,
+				 <PINMUX_GPIO144__FUNC_B_GPIO144>;
+			input-disable;
+			bias-disable;
+		};
+	};
+
+	gpio_keys_pins: gpio-keys-pins {
+		pins-keys {
+			pinmux = <PINMUX_GPIO129__FUNC_B_GPIO129>,
+				 <PINMUX_GPIO65__FUNC_B_GPIO65>,
+				 <PINMUX_GPIO66__FUNC_B_GPIO66>;
+			bias-pull-up;
+		};
+	};
+
+	hd3ss3220_pins: hd3ss3320-pins {
+		pins-irq {
+			pinmux = <PINMUX_GPIO45__FUNC_B_GPIO45>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+			input-enable;
+		};
+	};
+
+	hdmi_vreg_pins: hdmi-vreg-pins {
+		pins-pwr {
+			pinmux = <PINMUX_GPIO50__FUNC_O_HDMITX20_PWR5V>;
+			bias-disable;
+		};
+	};
+
+	hdmi_pins: hdmi-pins {
+		pins-hotplug {
+			pinmux = <PINMUX_GPIO51__FUNC_I0_HDMITX20_HTPLG>;
+			bias-pull-down;
+		};
+
+		pins-cec {
+			pinmux = <PINMUX_GPIO52__FUNC_B1_HDMITX20_CEC>;
+			bias-disable;
+		};
+
+		pins-ddc {
+			pinmux = <PINMUX_GPIO53__FUNC_B1_HDMITX20_SCL>,
+				 <PINMUX_GPIO54__FUNC_B1_HDMITX20_SDA>;
+			drive-strength = <10>;
+		};
+	};
+
+	i2c0_pins: i2c0-pins {
+		pins-bus {
+			pinmux = <PINMUX_GPIO56__FUNC_B1_SDA0>,
+				 <PINMUX_GPIO55__FUNC_B1_SCL0>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c0_gpio_pins: i2c0-gpio-pins {
+		pins-gpio {
+			pinmux = <PINMUX_GPIO6__FUNC_B_GPIO6>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c1_pins: i2c1-pins {
+		pins-bus {
+			pinmux = <PINMUX_GPIO58__FUNC_B1_SDA1>,
+				 <PINMUX_GPIO57__FUNC_B1_SCL1>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c2_pins: i2c2-pins {
+		pins-bus {
+			pinmux = <PINMUX_GPIO60__FUNC_B1_SDA2>,
+				 <PINMUX_GPIO59__FUNC_B1_SCL2>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c3_pins: i2c3-pins {
+		pins-bus {
+			pinmux = <PINMUX_GPIO62__FUNC_B1_SDA3>,
+				 <PINMUX_GPIO61__FUNC_B1_SCL3>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c4_pins: i2c4-pins {
+		pins-bus {
+			pinmux = <PINMUX_GPIO64__FUNC_B1_SDA4>,
+				 <PINMUX_GPIO63__FUNC_B1_SCL4>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c_mux_smarc_lcd_pins: i2c-mux-smarc-lcd-pins {
+		pins-reset {
+			pinmux = <PINMUX_GPIO5__FUNC_B_GPIO5>;
+			bias-pull-down;
+		};
+	};
+
+	mmc0_default_pins: mmc0-default-pins {
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO161__FUNC_B1_MSDC0_DAT0>,
+				 <PINMUX_GPIO160__FUNC_B1_MSDC0_DAT1>,
+				 <PINMUX_GPIO159__FUNC_B1_MSDC0_DAT2>,
+				 <PINMUX_GPIO158__FUNC_B1_MSDC0_DAT3>,
+				 <PINMUX_GPIO154__FUNC_B1_MSDC0_DAT4>,
+				 <PINMUX_GPIO153__FUNC_B1_MSDC0_DAT5>,
+				 <PINMUX_GPIO152__FUNC_B1_MSDC0_DAT6>,
+				 <PINMUX_GPIO151__FUNC_B1_MSDC0_DAT7>,
+				 <PINMUX_GPIO156__FUNC_B1_MSDC0_CMD>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins-clk {
+			pinmux = <PINMUX_GPIO157__FUNC_B1_MSDC0_CLK>;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-rst {
+			pinmux = <PINMUX_GPIO155__FUNC_O_MSDC0_RSTB>;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+
+	mmc0_uhs_pins: mmc0-uhs-pins {
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO161__FUNC_B1_MSDC0_DAT0>,
+				 <PINMUX_GPIO160__FUNC_B1_MSDC0_DAT1>,
+				 <PINMUX_GPIO159__FUNC_B1_MSDC0_DAT2>,
+				 <PINMUX_GPIO158__FUNC_B1_MSDC0_DAT3>,
+				 <PINMUX_GPIO154__FUNC_B1_MSDC0_DAT4>,
+				 <PINMUX_GPIO153__FUNC_B1_MSDC0_DAT5>,
+				 <PINMUX_GPIO152__FUNC_B1_MSDC0_DAT6>,
+				 <PINMUX_GPIO151__FUNC_B1_MSDC0_DAT7>,
+				 <PINMUX_GPIO156__FUNC_B1_MSDC0_CMD>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins-clk {
+			pinmux = <PINMUX_GPIO157__FUNC_B1_MSDC0_CLK>;
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-ds {
+			pinmux = <PINMUX_GPIO162__FUNC_B0_MSDC0_DSL>;
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-rst {
+			pinmux = <PINMUX_GPIO155__FUNC_O_MSDC0_RSTB>;
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+
+	mmc1_default_pins: mmc1-default-pins {
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO163__FUNC_B1_MSDC1_CMD>,
+				 <PINMUX_GPIO165__FUNC_B1_MSDC1_DAT0>,
+				 <PINMUX_GPIO166__FUNC_B1_MSDC1_DAT1>,
+				 <PINMUX_GPIO167__FUNC_B1_MSDC1_DAT2>,
+				 <PINMUX_GPIO168__FUNC_B1_MSDC1_DAT3>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins-pwr {
+			pinmux = <PINMUX_GPIO111__FUNC_B_GPIO111>;
+			bias-pull-down;
+		};
+
+		pins-pullup {
+			pinmux = <PINMUX_GPIO11__FUNC_B_GPIO11>;
+			bias-pull-up;
+		};
+
+		pins-clk {
+			pinmux = <PINMUX_GPIO164__FUNC_B1_MSDC1_CLK>;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-insert {
+			pinmux = <PINMUX_GPIO2__FUNC_B_GPIO2>;
+			bias-pull-up;
+		};
+	};
+
+	mmc1_uhs_pins: mmc1-uhs-pins {
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO163__FUNC_B1_MSDC1_CMD>,
+				 <PINMUX_GPIO165__FUNC_B1_MSDC1_DAT0>,
+				 <PINMUX_GPIO166__FUNC_B1_MSDC1_DAT1>,
+				 <PINMUX_GPIO167__FUNC_B1_MSDC1_DAT2>,
+				 <PINMUX_GPIO168__FUNC_B1_MSDC1_DAT3>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins-clk {
+			pinmux = <PINMUX_GPIO164__FUNC_B1_MSDC1_CLK>;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+	};
+
+	mmc2_default_pins: mmc2-default-pins {
+		pins-clk {
+			pinmux = <PINMUX_GPIO170__FUNC_B1_MSDC2_CLK>;
+			drive-strength = <MTK_DRIVE_4mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO169__FUNC_B1_MSDC2_CMD>,
+				 <PINMUX_GPIO171__FUNC_B1_MSDC2_DAT0>,
+				 <PINMUX_GPIO172__FUNC_B1_MSDC2_DAT1>,
+				 <PINMUX_GPIO173__FUNC_B1_MSDC2_DAT2>,
+				 <PINMUX_GPIO174__FUNC_B1_MSDC2_DAT3>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+
+	mmc2_uhs_pins: mmc2-uhs-pins {
+		pins-clk {
+			pinmux = <PINMUX_GPIO170__FUNC_B1_MSDC2_CLK>;
+			drive-strength = <MTK_DRIVE_4mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO169__FUNC_B1_MSDC2_CMD>,
+				 <PINMUX_GPIO171__FUNC_B1_MSDC2_DAT0>,
+				 <PINMUX_GPIO172__FUNC_B1_MSDC2_DAT1>,
+				 <PINMUX_GPIO173__FUNC_B1_MSDC2_DAT2>,
+				 <PINMUX_GPIO174__FUNC_B1_MSDC2_DAT3>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+
+	mmc2_eint_pins: mmc2-eint-pins {
+		pins-dat1 {
+			pinmux = <PINMUX_GPIO172__FUNC_B_GPIO172>;
+			input-enable;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+
+	rv3028_pins: rv3028-pins {
+		pins-irq {
+			pinmux = <PINMUX_GPIO42__FUNC_B_GPIO42>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+			input-enable;
+		};
+	};
+
+	spi0_pins: spi0-pins {
+		pins-spi {
+			pinmux = <PINMUX_GPIO69__FUNC_O_SPIM0_CSB>,
+				<PINMUX_GPIO70__FUNC_O_SPIM0_CLK>,
+				<PINMUX_GPIO71__FUNC_B0_SPIM0_MOSI>,
+				<PINMUX_GPIO72__FUNC_B0_SPIM0_MISO>;
+			bias-disable;
+		};
+	};
+
+	spi1_pins: spi1-pins {
+		pins-spi {
+			pinmux = <PINMUX_GPIO75__FUNC_O_SPIM1_CSB>,
+				<PINMUX_GPIO76__FUNC_O_SPIM1_CLK>,
+				<PINMUX_GPIO77__FUNC_B0_SPIM1_MOSI>,
+				<PINMUX_GPIO78__FUNC_B0_SPIM1_MISO>;
+			bias-disable;
+		};
+	};
+
+	pcie_default_pins: pcie-default-pins {
+		pins {
+			pinmux = <PINMUX_GPIO47__FUNC_I1_WAKEN>,
+				 <PINMUX_GPIO48__FUNC_O_PERSTN>,
+				 <PINMUX_GPIO49__FUNC_B1_CLKREQN>;
+			bias-pull-up;
+		};
+	};
+
+	ts_dsi0_goodix_pins: ts-dsi0-goodix-pins {
+		pins-irq {
+			pinmux = <PINMUX_GPIO146__FUNC_B_GPIO146>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+			input-enable;
+		};
+
+		pins-reset {
+			pinmux = <PINMUX_GPIO7__FUNC_B_GPIO7>;
+			bias-pull-down;
+		};
+	};
+
+	uart0_pins: uart0-pins {
+		pins {
+			pinmux = <PINMUX_GPIO31__FUNC_O_UTXD0>,
+				 <PINMUX_GPIO32__FUNC_I1_URXD0>;
+			bias-pull-up;
+		};
+	};
+
+	uart1_pins: uart1-pins {
+		pins {
+			pinmux = <PINMUX_GPIO33__FUNC_O_UTXD1>,
+				 <PINMUX_GPIO34__FUNC_I1_URXD1>;
+			bias-pull-up;
+		};
+	};
+
+	uart2_pins: uart2-pins {
+		pins {
+			pinmux = <PINMUX_GPIO35__FUNC_O_UTXD2>,
+				 <PINMUX_GPIO36__FUNC_I1_URXD2>;
+			bias-pull-up;
+		};
+	};
+
+	usbotg_pins: usbotg-pins {
+		pins-iddig {
+			pinmux = <PINMUX_GPIO83__FUNC_B_GPIO83>;
+			input-enable;
+			bias-pull-up;
+		};
+
+		pins-valid {
+			pinmux = <PINMUX_GPIO85__FUNC_I0_VBUSVALID>;
+			input-enable;
+		};
+
+		pins-vbus {
+			pinmux = <PINMUX_GPIO84__FUNC_O_USB_DRVVBUS>;
+			output-high;
+		};
+	};
+
+	usb1_hub_pins: usb1-hub-pins {
+		pins {
+			pinmux = <PINMUX_GPIO147__FUNC_B_GPIO147>;
+			output-low;
+		};
+	};
+
+	usb1_pins: usb1-pins {
+		pins {
+			pinmux = <PINMUX_GPIO88__FUNC_I0_VBUSVALID_1P>;
+			input-enable;
+		};
+	};
+
+	usb2_eth_pins: usb2-eth-pins {
+		pins {
+			pinmux = <PINMUX_GPIO80__FUNC_B_GPIO80>;
+			output-low;
+		};
+	};
+
+	wifi_pwrseq_pins: wifi-pwrseq-pins {
+		pins {
+			pinmux = <PINMUX_GPIO89__FUNC_B_GPIO89>;
+			output-low;
+		};
+	};
+
+	watchdog_pins: watchdog-pins {
+		pins {
+			pinmux = <PINMUX_GPIO100__FUNC_O_WATCHDOG>;
+			bias-pull-up;
+		};
+	};
+};

-- 
2.43.0



From bisson.gary at gmail.com  Mon Dec  1 02:23:16 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Mon, 01 Dec 2025 11:23:16 +0100
Subject: [PATCH v2 2/4] dt-bindings: arm: mediatek: Add Ezurio Tungsten
 entries
In-Reply-To: <20251201-review-v2-0-dc2df44eec7e@gmail.com>
References: <20251201-review-v2-0-dc2df44eec7e@gmail.com>
Message-ID: <20251201-review-v2-2-dc2df44eec7e@gmail.com>

Add device tree bindings support for the Ezurio Tungsten 510 (MT8370)
SMARC [1] / Ezurio Tungsten 700 (MT8390) SMARC [2] + Universal SMARC
carrier board [3].

[1] https://www.ezurio.com/product/tungsten510-smarc
[2] https://www.ezurio.com/product/tungsten700-smarc
[3] https://www.ezurio.com/system-on-module/accessories/universal-smarc-carrier

Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
---
 Documentation/devicetree/bindings/arm/mediatek.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/mediatek.yaml b/Documentation/devicetree/bindings/arm/mediatek.yaml
index f04277873694..cffb0f6ac690 100644
--- a/Documentation/devicetree/bindings/arm/mediatek.yaml
+++ b/Documentation/devicetree/bindings/arm/mediatek.yaml
@@ -431,12 +431,14 @@ properties:
           - const: mediatek,mt8365
       - items:
           - enum:
+              - ezurio,mt8370-tungsten-smarc
               - grinn,genio-510-sbc
               - mediatek,mt8370-evk
           - const: mediatek,mt8370
           - const: mediatek,mt8188
       - items:
           - enum:
+              - ezurio,mt8390-tungsten-smarc
               - grinn,genio-700-sbc
               - mediatek,mt8390-evk
           - const: mediatek,mt8390

-- 
2.43.0



From bisson.gary at gmail.com  Mon Dec  1 02:23:15 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Mon, 01 Dec 2025 11:23:15 +0100
Subject: [PATCH v2 1/4] dt-bindings: vendor-prefixes: Add Ezurio LLC
In-Reply-To: <20251201-review-v2-0-dc2df44eec7e@gmail.com>
References: <20251201-review-v2-0-dc2df44eec7e@gmail.com>
Message-ID: <20251201-review-v2-1-dc2df44eec7e@gmail.com>

Ezurio is the new name of Laird Connectivity after it acquired Boundary
Devices.

Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
---
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index f1d1882009ba..e76e6c5be726 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -547,6 +547,8 @@ patternProperties:
     description: Exegin Technologies Limited
   "^ezchip,.*":
     description: EZchip Semiconductor
+  "^ezurio,.*":
+    description: Ezurio LLC
   "^facebook,.*":
     description: Facebook
   "^fairchild,.*":

-- 
2.43.0



From bisson.gary at gmail.com  Mon Dec  1 02:23:18 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Mon, 01 Dec 2025 11:23:18 +0100
Subject: [PATCH v2 4/4] arm64: dts: mediatek: add device tree for Tungsten
 700 board
In-Reply-To: <20251201-review-v2-0-dc2df44eec7e@gmail.com>
References: <20251201-review-v2-0-dc2df44eec7e@gmail.com>
Message-ID: <20251201-review-v2-4-dc2df44eec7e@gmail.com>

Add device tree to support Ezurio Tungsten 700 (MT8390) SMARC SOM [1] +
Universal SMARC carrier board [2].
It includes support for the MIPI-DSI BD070LIC3 display which uses the
Tianma TM070JDHG30 panel + TI SN65DSI84 MIPI-DSI to LVDS bridge [3].

[1] https://www.ezurio.com/product/tungsten700-smarc
[2] https://www.ezurio.com/system-on-module/accessories/universal-smarc-carrier
[3] https://www.ezurio.com/product/bd070lic3-7-touchscreen-display

Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
---
 arch/arm64/boot/dts/mediatek/Makefile              |  1 +
 .../boot/dts/mediatek/mt8390-tungsten-smarc.dts    | 22 ++++++++++++++++++++++
 2 files changed, 23 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile
index 30d169a31b10..85f338344dd3 100644
--- a/arch/arm64/boot/dts/mediatek/Makefile
+++ b/arch/arm64/boot/dts/mediatek/Makefile
@@ -102,6 +102,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-genio-510-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-tungsten-smarc.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-genio-1200-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-genio-700-evk.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-tungsten-smarc.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-kontron-3-5-sbc-i1200.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-radxa-nio-12l.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-radxa-nio-12l-8-hd-panel.dtbo
diff --git a/arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts b/arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts
new file mode 100644
index 000000000000..f1cf2821107f
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2025 Ezurio LLC
+ * Author: Gary Bisson <bisson.gary at gmail.com>
+ */
+/dts-v1/;
+#include "mt8188.dtsi"
+#include "mt83x0-tungsten-smarc.dtsi"
+
+/ {
+	model = "Ezurio Tungsten700 SMARC (MT8390)";
+	compatible = "ezurio,mt8390-tungsten-smarc", "mediatek,mt8390",
+		     "mediatek,mt8188";
+};
+
+&cpu4 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};
+
+&cpu5 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};

-- 
2.43.0



From james.clark at linaro.org  Mon Dec  1 02:25:25 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 1 Dec 2025 10:25:25 +0000
Subject: [PATCH v2] coresight: etm3x: Fix cntr_val_show() to match
 cntr_val_store() behavior
In-Reply-To: <20251201095228.1905489-1-visitorckw@gmail.com>
References: <20251201095228.1905489-1-visitorckw@gmail.com>
Message-ID: <d7c17bc4-a7dd-42fa-8dd3-16a404a6d713@linaro.org>



On 01/12/2025 9:52 am, Kuan-Wei Chiu wrote:
> The cntr_val_show() function was intended to print the values of all
> counters using a loop. However, due to a buffer overwrite issue with
> sprintf(), it effectively only displayed the value of the last counter.
> 
> The companion function, cntr_val_store(), allows users to modify a
> specific counter selected by 'cntr_idx'. To maintain consistency
> between read and write operations and to align with the ETM4x driver
> behavior, modify cntr_val_show() to report only the value of the
> currently selected counter.
> 
> This change removes the loop and the "counter %d:" prefix, printing
> only the hexadecimal value. It also adopts sysfs_emit() for standard
> sysfs output formatting.
> 
> Fixes: a939fc5a71ad ("coresight-etm: add CoreSight ETM/PTM driver")
> Signed-off-by: Kuan-Wei Chiu <visitorckw at gmail.com>
> ---
> Build test only.
> 
> Changes in v2:
> - Redesigned the fix to match cntr_val_store() logic (display only the
>    currently selected counter) instead of attempting to list all
>    counters.
> - Removed the loop and the "counter %d:" prefix.
> - Switched from sprintf() to sysfs_emit().
> - Refactored control flow to use a single return point.
> 
> v1: https://lore.kernel.org/lkml/20251121002350.1166758-1-visitorckw at gmail.com/
> 
>   .../hwtracing/coresight/coresight-etm3x-sysfs.c   | 15 ++++-----------
>   1 file changed, 4 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
> index 762109307b86..a6a650331196 100644
> --- a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
> +++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
> @@ -717,26 +717,19 @@ static DEVICE_ATTR_RW(cntr_rld_event);
>   static ssize_t cntr_val_show(struct device *dev,
>   			     struct device_attribute *attr, char *buf)
>   {
> -	int i, ret = 0;
>   	u32 val;
>   	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
>   	struct etm_config *config = &drvdata->config;
>   
>   	if (!coresight_get_mode(drvdata->csdev)) {
>   		spin_lock(&drvdata->spinlock);
> -		for (i = 0; i < drvdata->nr_cntr; i++)
> -			ret += sprintf(buf, "counter %d: %x\n",
> -				       i, config->cntr_val[i]);
> +		val = config->cntr_val[config->cntr_idx];
>   		spin_unlock(&drvdata->spinlock);
> -		return ret;
> -	}
> -
> -	for (i = 0; i < drvdata->nr_cntr; i++) {
> -		val = etm_readl(drvdata, ETMCNTVRn(i));
> -		ret += sprintf(buf, "counter %d: %x\n", i, val);
> +	} else {
> +		val = etm_readl(drvdata, ETMCNTVRn(config->cntr_idx));
>   	}
>   
> -	return ret;
> +	return sysfs_emit(buf, "%x\n", val);

Sorry I missed this on the previous version, but this should be %#x to 
add the "0x" prefix. All the other ones in this file have it. Otherwise 
you can't tell the difference between decimal and hex.

>   }
>   
>   static ssize_t cntr_val_store(struct device *dev,



From david.laight at runbox.com  Mon Dec  1 02:26:33 2025
From: david.laight at runbox.com (david laight)
Date: Mon, 1 Dec 2025 10:26:33 +0000
Subject: [PATCH 2/2] arm64: Avoid memcpy() for syscall_get_arguments()
In-Reply-To: <aS1qYhHhZK3CD_bU@J2N7QTR9R3>
References: <20251127123630.4149828-1-ruanjinjie@huawei.com>
	<20251127123630.4149828-3-ruanjinjie@huawei.com>
	<aS1qYhHhZK3CD_bU@J2N7QTR9R3>
Message-ID: <20251201102633.17a99afc@pumpkin>

On Mon, 1 Dec 2025 10:13:54 +0000
Mark Rutland <mark.rutland at arm.com> wrote:

> On Thu, Nov 27, 2025 at 08:36:30PM +0800, Jinjie Ruan wrote:
> > Do not use memcpy() to extract syscall arguments from struct pt_regs
> > but rather just perform direct assignments.
> > 
> > The performance benchmarks with Generic Entry patch[1] with audit on
> > from perf bench basic syscall on kunpeng920 gives roughly a 1%
> > performance uplift and also aligns the implementation with
> > x86 and RISC-V.
> > 
> > | Metric     | W/O this patch | With this patch | Change    |
> > | ---------- | -------------- | --------------- | --------- |
> > | Total time | 2.241 [sec]    | 2.211 [sec]     |  ?1.36%   |
> > | usecs/op   | 0.224157       | 0.221146        |  ?1.36%   |
> > | ops/sec    | 4,461,157      | 4,501,409       |  ?0.9%    |
> > 
> > Before:
> > <syscall_get_arguments.constprop.0>:
> >        aa0103e2        mov     x2, x1
> >        91002003        add     x3, x0, #0x8
> >        f9408804        ldr     x4, [x0, #272]
> >        f8008444        str     x4, [x2], #8
> >        a9409404        ldp     x4, x5, [x0, #8]
> >        a9009424        stp     x4, x5, [x1, #8]
> >        a9418400        ldp     x0, x1, [x0, #24]
> >        a9010440        stp     x0, x1, [x2, #16]
> >        f9401060        ldr     x0, [x3, #32]
> >        f9001040        str     x0, [x2, #32]
> >        d65f03c0        ret
> >        d503201f        nop
> > 
> > After:
> >        a9408e82        ldp     x2, x3, [x20, #8]
> >        2a1603e0        mov     w0, w22
> >        f9400e84        ldr     x4, [x20, #24]
> >        f9408a81        ldr     x1, [x20, #272]
> >        9401c4ba        bl      ffff800080215ca8 <__audit_syscall_entry>  
> 
> It's probably worth noting that __audit_syscall_entry() only takes 4
> syscall arguments, and hence the compiler has elided the copy of
> regs->regs[4] and regs->regs[5], which it apparently couldn't manage
> before.

Hasn't it actually inlined it and completely optimised away the regs[] array?
It looks (from the asm) as though syscall_get_arguments() is followed by:
	fn(regs[0], regs[1], regs[2], regs[3])

    David

> 
> > [1]: https://lore.kernel.org/all/20251126071446.3234218-1-ruanjinjie at huawei.com/
> > Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
> > ---
> >  arch/arm64/include/asm/syscall.h | 8 +++++---
> >  1 file changed, 5 insertions(+), 3 deletions(-)
> > 
> > diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
> > index f3853047c28e..f3564ba97f7e 100644
> > --- a/arch/arm64/include/asm/syscall.h
> > +++ b/arch/arm64/include/asm/syscall.h
> > @@ -82,9 +82,11 @@ static inline void syscall_get_arguments(struct task_struct *task,
> >  					 unsigned long *args)
> >  {
> >  	args[0] = regs->orig_x0;
> > -	args++;
> > -
> > -	memcpy(args, &regs->regs[1], 5 * sizeof(args[0]));
> > +	args[1] = regs->regs[1];
> > +	args[2] = regs->regs[2];
> > +	args[3] = regs->regs[3];
> > +	args[4] = regs->regs[4];
> > +	args[5] = regs->regs[5];
> >  }  
> 
> FWIW, I think this is clearer than the 'args++' and the memcpy(), so I'm
> happy with this regardless of the performance concern.
> 
> However, as Dmitry says, we should keep this structurally the same as
> syscall_set_arguments(), and so we should update that in the same way.
> 
> Mark.
> 



From mark.rutland at arm.com  Mon Dec  1 02:30:16 2025
From: mark.rutland at arm.com (Mark Rutland)
Date: Mon, 1 Dec 2025 10:30:16 +0000
Subject: [PATCH 2/2] arm64: Avoid memcpy() for syscall_get_arguments()
In-Reply-To: <20251201102633.17a99afc@pumpkin>
References: <20251127123630.4149828-1-ruanjinjie@huawei.com>
 <20251127123630.4149828-3-ruanjinjie@huawei.com>
 <aS1qYhHhZK3CD_bU@J2N7QTR9R3>
 <20251201102633.17a99afc@pumpkin>
Message-ID: <aS1uOGm7cQf1euIw@J2N7QTR9R3>

On Mon, Dec 01, 2025 at 10:26:33AM +0000, david laight wrote:
> On Mon, 1 Dec 2025 10:13:54 +0000
> Mark Rutland <mark.rutland at arm.com> wrote:
> > On Thu, Nov 27, 2025 at 08:36:30PM +0800, Jinjie Ruan wrote:
> > > Before:
> > > <syscall_get_arguments.constprop.0>:
> > >        aa0103e2        mov     x2, x1
> > >        91002003        add     x3, x0, #0x8
> > >        f9408804        ldr     x4, [x0, #272]
> > >        f8008444        str     x4, [x2], #8
> > >        a9409404        ldp     x4, x5, [x0, #8]
> > >        a9009424        stp     x4, x5, [x1, #8]
> > >        a9418400        ldp     x0, x1, [x0, #24]
> > >        a9010440        stp     x0, x1, [x2, #16]
> > >        f9401060        ldr     x0, [x3, #32]
> > >        f9001040        str     x0, [x2, #32]
> > >        d65f03c0        ret
> > >        d503201f        nop
> > > 
> > > After:
> > >        a9408e82        ldp     x2, x3, [x20, #8]
> > >        2a1603e0        mov     w0, w22
> > >        f9400e84        ldr     x4, [x20, #24]
> > >        f9408a81        ldr     x1, [x20, #272]
> > >        9401c4ba        bl      ffff800080215ca8 <__audit_syscall_entry>  
> > 
> > It's probably worth noting that __audit_syscall_entry() only takes 4
> > syscall arguments, and hence the compiler has elided the copy of
> > regs->regs[4] and regs->regs[5], which it apparently couldn't manage
> > before.
> 
> Hasn't it actually inlined it and completely optimised away the regs[] array?
> It looks (from the asm) as though syscall_get_arguments() is followed by:
> 	fn(regs[0], regs[1], regs[2], regs[3])

Yes; I was assuming that people could infer that.

I was poining out that the elision of copies/loads of regs->regs[4] and
regs->regs[5] in particular was not a bug.

Mark.


From krzk at kernel.org  Mon Dec  1 02:30:36 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 1 Dec 2025 11:30:36 +0100
Subject: [PATCH v2 1/4] dt-bindings: vendor-prefixes: Add Ezurio LLC
In-Reply-To: <20251201-review-v2-1-dc2df44eec7e@gmail.com>
References: <20251201-review-v2-0-dc2df44eec7e@gmail.com>
 <20251201-review-v2-1-dc2df44eec7e@gmail.com>
Message-ID: <cb79c1a0-f61f-4ab8-b5de-c81e8a61e8d1@kernel.org>

On 01/12/2025 11:23, Gary Bisson wrote:
> Ezurio is the new name of Laird Connectivity after it acquired Boundary
> Devices.
> 
> Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
> ---
>  Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
>  1 file changed, 2 insertions(+)



<form letter>
This is a friendly reminder during the review process.

It looks like you received a tag and forgot to add it.

If you do not know the process, here is a short explanation:
Please add Acked-by/Reviewed-by/Tested-by tags when posting new versions
of patchset, under or above your Signed-off-by tag, unless patch changed
significantly (e.g. new properties added to the DT bindings). Tag is
"received", when provided in a message replied to you on the mailing
list. Tools like b4 can help here. However, there's no need to repost
patches *only* to add the tags. The upstream maintainer will do that for
tags received on the version they apply.

Please read:
https://elixir.bootlin.com/linux/v6.12-rc3/source/Documentation/process/submitting-patches.rst#L577

If a tag was not added on purpose, please state why and what changed.
</form letter>

Best regards,
Krzysztof


From yeoreum.yun at arm.com  Mon Dec  1 02:36:37 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Mon, 1 Dec 2025 10:36:37 +0000
Subject: [PATCH] arm64: kernel: initialize missing kexec_buf->random field
In-Reply-To: <j2ilxmuhlgu5dwswl3qk7rbzmbk25qn4s2tidhdy4uy7dzfcnn@6ulgmdw4effw>
References: <20251127182644.1577592-1-yeoreum.yun@arm.com>
 <20251127113706.d89a84f277dab3ad273dde75@linux-foundation.org>
 <aSjqEQDv7V79V3Na@MiWiFi-R3L-srv>
 <5wel6vqjwwf25hryvg6s7z6aaog7xc3zxjevupt3jn4gntme6d@74wwwmhvvelt>
 <aSmrUGnZp0UeTp1E@J2N7QTR9R3>
 <aS0Ch3hrYPDXomDC@MiWiFi-R3L-srv>
 <j2ilxmuhlgu5dwswl3qk7rbzmbk25qn4s2tidhdy4uy7dzfcnn@6ulgmdw4effw>
Message-ID: <aS1vtct8p6+P6GbU@e129823.arm.com>

Hi Breno,

> On Mon, Dec 01, 2025 at 10:50:47AM +0800, Baoquan He wrote:
> > On 11/28/25 at 02:01pm, Mark Rutland wrote:
> > > FWIW, I completey agree; your proposal is a much better solution.
> >
> > Yes, maybe Yeoreum or Breno can post a new version to fix it on arm64.
>
> Yeoreum, would you be ok doing the patch? If you are busy, I can do it.

Sorry to late answer. and Thanks for pointing this :)
I'll send quickly spin 2 following your suggsetion.

Thanks!

--
Sincerely,
Yeoreum Yun


From hverkuil+cisco at kernel.org  Mon Dec  1 02:38:56 2025
From: hverkuil+cisco at kernel.org (Hans Verkuil)
Date: Mon, 1 Dec 2025 11:38:56 +0100
Subject: [PATCH v4 1/5] media: mc: add manual request completion
In-Reply-To: <20251128-sebastianfricke-vcodec_manual_request_completion_with_state_machine-v4-1-c166bdd4625c@collabora.com>
References: <20251128-sebastianfricke-vcodec_manual_request_completion_with_state_machine-v4-0-c166bdd4625c@collabora.com>
 <20251128-sebastianfricke-vcodec_manual_request_completion_with_state_machine-v4-1-c166bdd4625c@collabora.com>
Message-ID: <fcfe2672-b546-4f3f-8418-71ee8ce1fb5d@kernel.org>

Hi Nicolas,

On 28/11/2025 20:16, Nicolas Dufresne wrote:
> From: Hans Verkuil <hverkuil at kernel.org>
> 
> By default when the last request object is completed, the whole
> request completes as well.
> 
> But sometimes you want to delay this completion to an arbitrary point in
> time so add a manual complete mode for this.
> 
> In req_queue the driver marks the request for manual completion by
> calling media_request_mark_manual_completion, and when the driver
> wants to manually complete the request it calls
> media_request_manual_complete().
> 
> Signed-off-by: Hans Verkuil <hverkuil-cisco at xs4all.nl>

For this patch and the other patches with this xs4all SoB, can you replace it with:

Signed-off-by: Hans Verkuil <hverkuil+cisco at kernel.org>

Much appreciated,

	Hans

> Signed-off-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
> ---
>  drivers/media/mc/mc-request.c | 41 +++++++++++++++++++++++++++++++++++++++--
>  include/media/media-request.h | 38 +++++++++++++++++++++++++++++++++++++-
>  2 files changed, 76 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/media/mc/mc-request.c b/drivers/media/mc/mc-request.c
> index f66f728b1b43dcd1cf51de46e828bf806f014f8d..512e6969152792558537dd8a0736df82847ae210 100644
> --- a/drivers/media/mc/mc-request.c
> +++ b/drivers/media/mc/mc-request.c
> @@ -54,6 +54,7 @@ static void media_request_clean(struct media_request *req)
>  	req->access_count = 0;
>  	WARN_ON(req->num_incomplete_objects);
>  	req->num_incomplete_objects = 0;
> +	req->manual_completion = false;
>  	wake_up_interruptible_all(&req->poll_wait);
>  }
>  
> @@ -313,6 +314,7 @@ int media_request_alloc(struct media_device *mdev, int *alloc_fd)
>  	req->mdev = mdev;
>  	req->state = MEDIA_REQUEST_STATE_IDLE;
>  	req->num_incomplete_objects = 0;
> +	req->manual_completion = false;
>  	kref_init(&req->kref);
>  	INIT_LIST_HEAD(&req->objects);
>  	spin_lock_init(&req->lock);
> @@ -459,7 +461,7 @@ void media_request_object_unbind(struct media_request_object *obj)
>  
>  	req->num_incomplete_objects--;
>  	if (req->state == MEDIA_REQUEST_STATE_QUEUED &&
> -	    !req->num_incomplete_objects) {
> +	    !req->num_incomplete_objects && !req->manual_completion) {
>  		req->state = MEDIA_REQUEST_STATE_COMPLETE;
>  		completed = true;
>  		wake_up_interruptible_all(&req->poll_wait);
> @@ -488,7 +490,7 @@ void media_request_object_complete(struct media_request_object *obj)
>  	    WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED))
>  		goto unlock;
>  
> -	if (!--req->num_incomplete_objects) {
> +	if (!--req->num_incomplete_objects && !req->manual_completion) {
>  		req->state = MEDIA_REQUEST_STATE_COMPLETE;
>  		wake_up_interruptible_all(&req->poll_wait);
>  		completed = true;
> @@ -499,3 +501,38 @@ void media_request_object_complete(struct media_request_object *obj)
>  		media_request_put(req);
>  }
>  EXPORT_SYMBOL_GPL(media_request_object_complete);
> +
> +void media_request_manual_complete(struct media_request *req)
> +{
> +	bool completed = false;
> +	unsigned long flags;
> +
> +	if (WARN_ON_ONCE(!req))
> +		return;
> +
> +	spin_lock_irqsave(&req->lock, flags);
> +
> +	if (WARN_ON_ONCE(!req->manual_completion))
> +		goto unlock;
> +
> +	if (WARN_ON_ONCE(req->state != MEDIA_REQUEST_STATE_QUEUED))
> +		goto unlock;
> +
> +	req->manual_completion = false;
> +	/*
> +	 * It is expected that all other objects in this request are
> +	 * completed when this function is called. WARN if that is
> +	 * not the case.
> +	 */
> +	if (!WARN_ON(req->num_incomplete_objects)) {
> +		req->state = MEDIA_REQUEST_STATE_COMPLETE;
> +		wake_up_interruptible_all(&req->poll_wait);
> +		completed = true;
> +	}
> +
> +unlock:
> +	spin_unlock_irqrestore(&req->lock, flags);
> +	if (completed)
> +		media_request_put(req);
> +}
> +EXPORT_SYMBOL_GPL(media_request_manual_complete);
> diff --git a/include/media/media-request.h b/include/media/media-request.h
> index bb500b2f9da46f5a9a84272759a137720b094a80..3256fcf3709da58878a59d90722bee3224d97af6 100644
> --- a/include/media/media-request.h
> +++ b/include/media/media-request.h
> @@ -56,6 +56,9 @@ struct media_request_object;
>   * @access_count: count the number of request accesses that are in progress
>   * @objects: List of @struct media_request_object request objects
>   * @num_incomplete_objects: The number of incomplete objects in the request
> + * @manual_completion: if true, then the request won't be marked as completed
> + * when @num_incomplete_objects reaches 0. Call media_request_manual_complete()
> + * to complete the request after @num_incomplete_objects == 0.
>   * @poll_wait: Wait queue for poll
>   * @lock: Serializes access to this struct
>   */
> @@ -68,6 +71,7 @@ struct media_request {
>  	unsigned int access_count;
>  	struct list_head objects;
>  	unsigned int num_incomplete_objects;
> +	bool manual_completion;
>  	wait_queue_head_t poll_wait;
>  	spinlock_t lock;
>  };
> @@ -218,6 +222,38 @@ media_request_get_by_fd(struct media_device *mdev, int request_fd);
>  int media_request_alloc(struct media_device *mdev,
>  			int *alloc_fd);
>  
> +/**
> + * media_request_mark_manual_completion - Enable manual completion
> + *
> + * @req: The request
> + *
> + * Mark that the request has to be manually completed by calling
> + * media_request_manual_complete().
> + *
> + * This function shall be called in the req_queue callback.
> + */
> +static inline void
> +media_request_mark_manual_completion(struct media_request *req)
> +{
> +	req->manual_completion = true;
> +}
> +
> +/**
> + * media_request_manual_complete - Mark the request as completed
> + *
> + * @req: The request
> + *
> + * This function completes a request that was marked for manual completion by an
> + * earlier call to media_request_mark_manual_completion(). The request's
> + * @manual_completion field is reset to false.
> + *
> + * All objects contained in the request must have been completed previously. It
> + * is an error to call this function otherwise. If such an error occurred, the
> + * function will WARN and the object completion will be delayed until
> + * @num_incomplete_objects is 0.
> + */
> +void media_request_manual_complete(struct media_request *req);
> +
>  #else
>  
>  static inline void media_request_get(struct media_request *req)
> @@ -336,7 +372,7 @@ void media_request_object_init(struct media_request_object *obj);
>   * @req: The media request
>   * @ops: The object ops for this object
>   * @priv: A driver-specific priv pointer associated with this object
> - * @is_buffer: Set to true if the object a buffer object.
> + * @is_buffer: Set to true if the object is a buffer object.
>   * @obj: The object
>   *
>   * Bind this object to the request and set the ops and priv values of
> 



From visitorckw at gmail.com  Mon Dec  1 02:39:05 2025
From: visitorckw at gmail.com (Kuan-Wei Chiu)
Date: Mon, 1 Dec 2025 18:39:05 +0800
Subject: [PATCH v2] coresight: etm3x: Fix cntr_val_show() to match
 cntr_val_store() behavior
In-Reply-To: <d7c17bc4-a7dd-42fa-8dd3-16a404a6d713@linaro.org>
References: <20251201095228.1905489-1-visitorckw@gmail.com>
 <d7c17bc4-a7dd-42fa-8dd3-16a404a6d713@linaro.org>
Message-ID: <aS1wSVFnOE906wLc@google.com>

On Mon, Dec 01, 2025 at 10:25:25AM +0000, James Clark wrote:
> 
> 
> On 01/12/2025 9:52 am, Kuan-Wei Chiu wrote:
> > The cntr_val_show() function was intended to print the values of all
> > counters using a loop. However, due to a buffer overwrite issue with
> > sprintf(), it effectively only displayed the value of the last counter.
> > 
> > The companion function, cntr_val_store(), allows users to modify a
> > specific counter selected by 'cntr_idx'. To maintain consistency
> > between read and write operations and to align with the ETM4x driver
> > behavior, modify cntr_val_show() to report only the value of the
> > currently selected counter.
> > 
> > This change removes the loop and the "counter %d:" prefix, printing
> > only the hexadecimal value. It also adopts sysfs_emit() for standard
> > sysfs output formatting.
> > 
> > Fixes: a939fc5a71ad ("coresight-etm: add CoreSight ETM/PTM driver")
> > Signed-off-by: Kuan-Wei Chiu <visitorckw at gmail.com>
> > ---
> > Build test only.
> > 
> > Changes in v2:
> > - Redesigned the fix to match cntr_val_store() logic (display only the
> >    currently selected counter) instead of attempting to list all
> >    counters.
> > - Removed the loop and the "counter %d:" prefix.
> > - Switched from sprintf() to sysfs_emit().
> > - Refactored control flow to use a single return point.
> > 
> > v1: https://lore.kernel.org/lkml/20251121002350.1166758-1-visitorckw at gmail.com/
> > 
> >   .../hwtracing/coresight/coresight-etm3x-sysfs.c   | 15 ++++-----------
> >   1 file changed, 4 insertions(+), 11 deletions(-)
> > 
> > diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
> > index 762109307b86..a6a650331196 100644
> > --- a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
> > +++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
> > @@ -717,26 +717,19 @@ static DEVICE_ATTR_RW(cntr_rld_event);
> >   static ssize_t cntr_val_show(struct device *dev,
> >   			     struct device_attribute *attr, char *buf)
> >   {
> > -	int i, ret = 0;
> >   	u32 val;
> >   	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
> >   	struct etm_config *config = &drvdata->config;
> >   	if (!coresight_get_mode(drvdata->csdev)) {
> >   		spin_lock(&drvdata->spinlock);
> > -		for (i = 0; i < drvdata->nr_cntr; i++)
> > -			ret += sprintf(buf, "counter %d: %x\n",
> > -				       i, config->cntr_val[i]);
> > +		val = config->cntr_val[config->cntr_idx];
> >   		spin_unlock(&drvdata->spinlock);
> > -		return ret;
> > -	}
> > -
> > -	for (i = 0; i < drvdata->nr_cntr; i++) {
> > -		val = etm_readl(drvdata, ETMCNTVRn(i));
> > -		ret += sprintf(buf, "counter %d: %x\n", i, val);
> > +	} else {
> > +		val = etm_readl(drvdata, ETMCNTVRn(config->cntr_idx));
> >   	}
> > -	return ret;
> > +	return sysfs_emit(buf, "%x\n", val);
> 
> Sorry I missed this on the previous version, but this should be %#x to add
> the "0x" prefix. All the other ones in this file have it. Otherwise you
> can't tell the difference between decimal and hex.
> 

Thanks for catching that. I will fix it in v3.

I'll wait a day or two to see if there are any other comments, and then
respin with the Cc stable tag.

Regards,
Kuan-Wei

> >   }
> >   static ssize_t cntr_val_store(struct device *dev,
> 


From bisson.gary at gmail.com  Mon Dec  1 02:45:16 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Mon, 01 Dec 2025 11:45:16 +0100
Subject: [PATCH v3 0/4] Add support for Ezurio MediaTek platforms
Message-ID: <20251201-review-v3-0-07f9af7341fd@gmail.com>

This series adds support for Ezurio MediaTek platforms called
"Tungsten". It includes support for MT8370-based Tungsten 510 and
MT8390-based Tungsten 700 SOMs.

Changes in v2:
- Use b4 to cc all maintainers properly
- Squashed patches 2/3 together
- Updated dts node names to be generic

Changes in v3:
- Added per-commit changelog
- Added missing Acked-by on 1st patch
- Link to v2: https://lore.kernel.org/r/20251201-review-v2-0-dc2df44eec7e at gmail.com

Regards,

Gary Bisson (4):
  dt-bindings: vendor-prefixes: Add Ezurio LLC
  dt-bindings: arm: mediatek: Add Ezurio Tungsten entries
  arm64: dts: mediatek: add device tree for Tungsten 510 board
  arm64: dts: mediatek: add device tree for Tungsten 700 board

 .../devicetree/bindings/arm/mediatek.yaml     |    2 +
 .../devicetree/bindings/vendor-prefixes.yaml  |    2 +
 arch/arm64/boot/dts/mediatek/Makefile         |    2 +
 .../dts/mediatek/mt8370-tungsten-smarc.dts    |   14 +
 .../dts/mediatek/mt8390-tungsten-smarc.dts    |   22 +
 .../dts/mediatek/mt83x0-tungsten-smarc.dtsi   | 1481 +++++++++++++++++
 6 files changed, 1523 insertions(+)
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts
 create mode 100644 arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi

--
2.43.0

---
To: Rob Herring <robh at kernel.org>
To: Krzysztof Kozlowski <krzk+dt at kernel.org>
To: Conor Dooley <conor+dt at kernel.org>
To: Matthias Brugger <matthias.bgg at gmail.com>
To: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
To: Sean Wang <sean.wang at mediatek.com>
Cc: devicetree at vger.kernel.org
Cc: linux-kernel at vger.kernel.org
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-mediatek at lists.infradead.org

---
Gary Bisson (4):
      dt-bindings: vendor-prefixes: Add Ezurio LLC
      dt-bindings: arm: mediatek: Add Ezurio Tungsten entries
      arm64: dts: mediatek: add device tree for Tungsten 510 board
      arm64: dts: mediatek: add device tree for Tungsten 700 board

 .../devicetree/bindings/arm/mediatek.yaml          |    2 +
 .../devicetree/bindings/vendor-prefixes.yaml       |    2 +
 arch/arm64/boot/dts/mediatek/Makefile              |    2 +
 .../boot/dts/mediatek/mt8370-tungsten-smarc.dts    |   14 +
 .../boot/dts/mediatek/mt8390-tungsten-smarc.dts    |   22 +
 .../boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi   | 1481 ++++++++++++++++++++
 6 files changed, 1523 insertions(+)
---
base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
change-id: 20251201-review-750072579991

Best regards,
-- 
Gary Bisson <bisson.gary at gmail.com>



From bisson.gary at gmail.com  Mon Dec  1 02:45:18 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Mon, 01 Dec 2025 11:45:18 +0100
Subject: [PATCH v3 2/4] dt-bindings: arm: mediatek: Add Ezurio Tungsten
 entries
In-Reply-To: <20251201-review-v3-0-07f9af7341fd@gmail.com>
References: <20251201-review-v3-0-07f9af7341fd@gmail.com>
Message-ID: <20251201-review-v3-2-07f9af7341fd@gmail.com>

Add device tree bindings support for the Ezurio Tungsten 510 (MT8370)
SMARC [1] / Ezurio Tungsten 700 (MT8390) SMARC [2] + Universal SMARC
carrier board [3].

[1] https://www.ezurio.com/product/tungsten510-smarc
[2] https://www.ezurio.com/product/tungsten700-smarc
[3] https://www.ezurio.com/system-on-module/accessories/universal-smarc-carrier

Signed-off-by: Gary Bisson <bisson.gary at gmail.com>

---
Changes in v2:
- Squashed both entries into 1 commit
Changed in v3:
- None
---
 Documentation/devicetree/bindings/arm/mediatek.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/mediatek.yaml b/Documentation/devicetree/bindings/arm/mediatek.yaml
index f04277873694..cffb0f6ac690 100644
--- a/Documentation/devicetree/bindings/arm/mediatek.yaml
+++ b/Documentation/devicetree/bindings/arm/mediatek.yaml
@@ -431,12 +431,14 @@ properties:
           - const: mediatek,mt8365
       - items:
           - enum:
+              - ezurio,mt8370-tungsten-smarc
               - grinn,genio-510-sbc
               - mediatek,mt8370-evk
           - const: mediatek,mt8370
           - const: mediatek,mt8188
       - items:
           - enum:
+              - ezurio,mt8390-tungsten-smarc
               - grinn,genio-700-sbc
               - mediatek,mt8390-evk
           - const: mediatek,mt8390

-- 
2.43.0



From bisson.gary at gmail.com  Mon Dec  1 02:45:17 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Mon, 01 Dec 2025 11:45:17 +0100
Subject: [PATCH v3 1/4] dt-bindings: vendor-prefixes: Add Ezurio LLC
In-Reply-To: <20251201-review-v3-0-07f9af7341fd@gmail.com>
References: <20251201-review-v3-0-07f9af7341fd@gmail.com>
Message-ID: <20251201-review-v3-1-07f9af7341fd@gmail.com>

Ezurio is the new name of Laird Connectivity after it acquired Boundary
Devices.

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
Signed-off-by: Gary Bisson <bisson.gary at gmail.com>

---
Changes in v2:
- none
Changes in v3:
- Added missing Acked-by from Krzysztof
---
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index f1d1882009ba..e76e6c5be726 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -547,6 +547,8 @@ patternProperties:
     description: Exegin Technologies Limited
   "^ezchip,.*":
     description: EZchip Semiconductor
+  "^ezurio,.*":
+    description: Ezurio LLC
   "^facebook,.*":
     description: Facebook
   "^fairchild,.*":

-- 
2.43.0



From bisson.gary at gmail.com  Mon Dec  1 02:45:20 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Mon, 01 Dec 2025 11:45:20 +0100
Subject: [PATCH v3 4/4] arm64: dts: mediatek: add device tree for Tungsten
 700 board
In-Reply-To: <20251201-review-v3-0-07f9af7341fd@gmail.com>
References: <20251201-review-v3-0-07f9af7341fd@gmail.com>
Message-ID: <20251201-review-v3-4-07f9af7341fd@gmail.com>

Add device tree to support Ezurio Tungsten 700 (MT8390) SMARC SOM [1] +
Universal SMARC carrier board [2].
It includes support for the MIPI-DSI BD070LIC3 display which uses the
Tianma TM070JDHG30 panel + TI SN65DSI84 MIPI-DSI to LVDS bridge [3].

[1] https://www.ezurio.com/product/tungsten700-smarc
[2] https://www.ezurio.com/system-on-module/accessories/universal-smarc-carrier
[3] https://www.ezurio.com/product/bd070lic3-7-touchscreen-display

Signed-off-by: Gary Bisson <bisson.gary at gmail.com>

---
Changes in v2:
- None
Changed in v3:
- None
---
 arch/arm64/boot/dts/mediatek/Makefile              |  1 +
 .../boot/dts/mediatek/mt8390-tungsten-smarc.dts    | 22 ++++++++++++++++++++++
 2 files changed, 23 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile
index 30d169a31b10..85f338344dd3 100644
--- a/arch/arm64/boot/dts/mediatek/Makefile
+++ b/arch/arm64/boot/dts/mediatek/Makefile
@@ -102,6 +102,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-genio-510-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-tungsten-smarc.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-genio-1200-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-genio-700-evk.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-tungsten-smarc.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-kontron-3-5-sbc-i1200.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-radxa-nio-12l.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-radxa-nio-12l-8-hd-panel.dtbo
diff --git a/arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts b/arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts
new file mode 100644
index 000000000000..f1cf2821107f
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2025 Ezurio LLC
+ * Author: Gary Bisson <bisson.gary at gmail.com>
+ */
+/dts-v1/;
+#include "mt8188.dtsi"
+#include "mt83x0-tungsten-smarc.dtsi"
+
+/ {
+	model = "Ezurio Tungsten700 SMARC (MT8390)";
+	compatible = "ezurio,mt8390-tungsten-smarc", "mediatek,mt8390",
+		     "mediatek,mt8188";
+};
+
+&cpu4 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};
+
+&cpu5 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};

-- 
2.43.0



From bisson.gary at gmail.com  Mon Dec  1 02:45:19 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Mon, 01 Dec 2025 11:45:19 +0100
Subject: [PATCH v3 3/4] arm64: dts: mediatek: add device tree for Tungsten
 510 board
In-Reply-To: <20251201-review-v3-0-07f9af7341fd@gmail.com>
References: <20251201-review-v3-0-07f9af7341fd@gmail.com>
Message-ID: <20251201-review-v3-3-07f9af7341fd@gmail.com>

Add device tree to support Ezurio Tungsten 510 (MT8370) SMARC SOM [1] +
Universal SMARC carrier board [2].
It includes support for the MIPI-DSI BD070LIC3 display which uses the
Tianma TM070JDHG30 panel + TI SN65DSI84 MIPI-DSI to LVDS bridge [3].

[1] https://www.ezurio.com/product/tungsten510-smarc
[2] https://www.ezurio.com/system-on-module/accessories/universal-smarc-carrier
[3] https://www.ezurio.com/product/bd070lic3-7-touchscreen-display

Signed-off-by: Gary Bisson <bisson.gary at gmail.com>

---
Changes in v2:
- Updated nodes to be generic (pmic, i2c, usb-typec)
Changed in v3:
- None
---
 arch/arm64/boot/dts/mediatek/Makefile              |    1 +
 .../boot/dts/mediatek/mt8370-tungsten-smarc.dts    |   14 +
 .../boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi   | 1481 ++++++++++++++++++++
 3 files changed, 1496 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile
index a4df4c21399e..30d169a31b10 100644
--- a/arch/arm64/boot/dts/mediatek/Makefile
+++ b/arch/arm64/boot/dts/mediatek/Makefile
@@ -99,6 +99,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8195-demo.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8195-evb.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8365-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-genio-510-evk.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-tungsten-smarc.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-genio-1200-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-genio-700-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-kontron-3-5-sbc-i1200.dtb
diff --git a/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts b/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts
new file mode 100644
index 000000000000..d713ef77df3a
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2025 Ezurio LLC
+ * Author: Gary Bisson <bisson.gary at gmail.com>
+ */
+/dts-v1/;
+#include "mt8370.dtsi"
+#include "mt83x0-tungsten-smarc.dtsi"
+
+/ {
+	model = "Ezurio Tungsten510 SMARC (MT8370)";
+	compatible = "ezurio,mt8370-tungsten-smarc", "mediatek,mt8370",
+		     "mediatek,mt8188";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi b/arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi
new file mode 100644
index 000000000000..77e8dbea335a
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi
@@ -0,0 +1,1481 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2025 Ezurio LLC
+ * Author: Gary Bisson <bisson.gary at gmail.com>
+ */
+
+#include "mt6359.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/net/microchip-lan78xx.h>
+#include <dt-bindings/pinctrl/mediatek,mt8188-pinfunc.h>
+#include <dt-bindings/usb/pd.h>
+
+/ {
+	aliases {
+		dsi0 = &disp_dsi0;
+		ethernet0 = &eth;
+		i2c0 = &i2c0;
+		i2c1 = &i2c1;
+		i2c2 = &i2c2;
+		i2c3 = &i2c3;
+		i2c4 = &i2c4;
+		i2c5 = &i2c5;
+		i2c6 = &i2c6;
+		mmc0 = &mmc0;
+		mmc1 = &mmc1;
+		mmc2 = &mmc2;
+		rtc0 = &rv3028;
+		rtc1 = &mt6359rtc;
+		serial0 = &uart0;
+	};
+
+	backlight_lcd0: backlight-lcd0 {
+		compatible = "pwm-backlight";
+		brightness-levels = <0 1023>;
+		default-brightness-level = <768>;
+		num-interpolated-steps = <1023>;
+		enable-gpios = <&pio 30 GPIO_ACTIVE_HIGH>;
+		pwms = <&disp_pwm0 0 30000>;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	firmware {
+		optee {
+			compatible = "linaro,optee-tz";
+			method = "smc";
+		};
+	};
+
+	memory at 40000000 {
+		device_type = "memory";
+		reg = <0 0x40000000 0x1 0x00000000>;
+	};
+
+	panel-dsi0 {
+		compatible = "tianma,tm070jdhg30";
+		backlight = <&backlight_lcd0>;
+
+		port {
+			dsi0_panel_in: endpoint {
+				remote-endpoint = <&sn65dsi84_bridge_out>;
+			};
+		};
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		/*
+		 * 12 MiB reserved for OP-TEE (BL32)
+		 * +-----------------------+ 0x43e0_0000
+		 * |      SHMEM 2MiB       |
+		 * +-----------------------+ 0x43c0_0000
+		 * |        | TA_RAM  8MiB |
+		 * + TZDRAM +--------------+ 0x4340_0000
+		 * |        | TEE_RAM 2MiB |
+		 * +-----------------------+ 0x4320_0000
+		 */
+		optee_reserved: optee at 43200000 {
+			no-map;
+			reg = <0 0x43200000 0 0x00c00000>;
+		};
+
+		scp_mem: memory at 50000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x50000000 0 0x2900000>;
+			no-map;
+		};
+
+		/* 2 MiB reserved for ARM Trusted Firmware (BL31) */
+		bl31_secmon_reserved: memory at 54600000 {
+			no-map;
+			reg = <0 0x54600000 0x0 0x200000>;
+		};
+
+		apu_mem: memory at 55000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x55000000 0 0x1400000>; /* 20 MB */
+		};
+
+		vpu_mem: memory at 57000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x57000000 0 0x1400000>; /* 20 MB */
+		};
+
+		adsp_mem: memory at 60000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x60000000 0 0xf00000>;
+			no-map;
+		};
+
+		afe_dma_mem: memory at 60f00000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x60f00000 0 0x100000>;
+			no-map;
+		};
+
+		adsp_dma_mem: memory at 61000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x61000000 0 0x100000>;
+			no-map;
+		};
+	};
+
+	regulator-efuse {
+		compatible = "regulator-output";
+		vout-supply = <&mt6359_vefuse_ldo_reg>;
+	};
+
+	sdcard_en_3v3: regulator-sdcard-en {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-name = "sdcard_en_3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&pio 111 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	usb_p0_vbus: regulator-usb-p0-vbus {
+		compatible = "regulator-fixed";
+		regulator-name = "vbus_p0";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&pio 84 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	usb_p1_vbus: regulator-usb-p1-vbus {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&usb1_hub_pins>;
+		regulator-name = "vbus_p1";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		gpio = <&pio 147 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	usb_p2_vbus: regulator-usb-p2-vbus {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&usb2_eth_pins>;
+		regulator-name = "vbus_p2";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		gpio = <&pio 80 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	wifi_pwrseq: wifi-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		pinctrl-names = "default";
+		pinctrl-0 = <&wifi_pwrseq_pins>;
+		post-power-on-delay-ms = <200>;
+		reset-gpios = <&pio 89 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&adsp {
+	memory-region = <&adsp_dma_mem>, <&adsp_mem>;
+	status = "okay";
+};
+
+&afe {
+	memory-region = <&afe_dma_mem>;
+	status = "okay";
+};
+
+&cpu0 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};
+
+&cpu1 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};
+
+&cpu2 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};
+
+&cpu3 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};
+
+&cpu6 {
+	cpu-supply = <&mt6315_6_vbuck1>;
+};
+
+&cpu7 {
+	cpu-supply = <&mt6315_6_vbuck1>;
+};
+
+&disp_pwm0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&disp_pwm0_pins>;
+	status = "okay";
+};
+
+&disp_dsi0 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			reg = <0>;
+			dsi0_in: endpoint {
+				remote-endpoint = <&dither0_out>;
+			};
+		};
+
+		port at 1 {
+			reg = <1>;
+			dsi0_out: endpoint {
+				remote-endpoint = <&sn65dsi84_bridge_in>;
+			};
+		};
+	};
+};
+
+&dither0_in {
+	remote-endpoint = <&postmask0_out>;
+};
+
+&dither0_out {
+	remote-endpoint = <&dsi0_in>;
+};
+
+&eth {
+	phy-mode ="rgmii-id";
+	phy-handle = <&ethernet_phy0>;
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&eth_default_pins>;
+	pinctrl-1 = <&eth_sleep_pins>;
+	mediatek,mac-wol;
+	snps,reset-gpio = <&pio 27 GPIO_ACTIVE_LOW>;
+	snps,reset-active-low;
+	snps,reset-delays-us = <0 11000 1000>;
+	status = "okay";
+};
+
+&eth_mdio {
+	ethernet_phy0: ethernet-phy at 7 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <0x7>;
+		interrupts-extended = <&pio 148 IRQ_TYPE_LEVEL_LOW>;
+	};
+};
+
+&gamma0_out {
+	remote-endpoint = <&postmask0_in>;
+};
+
+&gpu {
+	mali-supply = <&mt6359_vproc2_buck_reg>;
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default", "gpio";
+	pinctrl-0 = <&i2c0_pins>;
+	pinctrl-1 = <&i2c0_gpio_pins>;
+	scl-gpios = <&pio 55 GPIO_OPEN_DRAIN>;
+	sda-gpios = <&pio 56 GPIO_OPEN_DRAIN>;
+	clock-frequency = <100000>;
+	status = "okay";
+
+	i2c-mux at 73 {
+		compatible = "nxp,pca9546";
+		reg = <0x73>;
+		reset-gpios = <&pio 6 GPIO_ACTIVE_LOW>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		i2c_mux_gp_0: i2c at 0 {
+			clock-frequency = <100000>;
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_gp_1: i2c at 1 {
+			clock-frequency = <100000>;
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_gp_2: i2c at 2 {
+			clock-frequency = <100000>;
+			reg = <2>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_gp_3: i2c at 3 {
+			clock-frequency = <100000>;
+			reg = <3>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	clock-frequency = <400000>;
+	status = "okay";
+};
+
+&i2c2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_pins>;
+	clock-frequency = <400000>;
+	status = "okay";
+
+	i2c-mux at 73 {
+		compatible = "nxp,pca9546";
+		pinctrl-names = "default";
+		pinctrl-0 = <&i2c_mux_smarc_lcd_pins>;
+		reg = <0x73>;
+		reset-gpios = <&pio 5 GPIO_ACTIVE_LOW>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		i2c_mux_lcd_0: i2c at 0 {
+			clock-frequency = <100000>;
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_lcd_1: i2c at 1 {
+			clock-frequency = <100000>;
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_lcd_2: i2c at 2 {
+			clock-frequency = <100000>;
+			reg = <2>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_lcd_3: i2c at 3 {
+			clock-frequency = <100000>;
+			reg = <3>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+};
+
+&i2c3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c3_pins>;
+	clock-frequency = <400000>;
+	status = "okay";
+};
+
+&i2c4 {
+	pinctrl-names = "default", "default";
+	pinctrl-0 = <&i2c4_pins>;
+	clock-frequency = <400000>;
+	status = "okay";
+};
+
+&i2c_mux_gp_0 {
+	rv3028: rtc at 52 {
+		compatible = "microcrystal,rv3028";
+		reg = <0x52>;
+		interrupts-extended = <&pio 42 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&rv3028_pins>;
+		#clock-cells = <0>;
+		wakeup-source;
+	};
+};
+
+&i2c_mux_gp_1 {
+	usb-typec at 60 {
+		compatible = "ti,hd3ss3220";
+		interrupts-extended = <&pio 45 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&hd3ss3220_pins>;
+		reg = <0x60>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+				hd3ss3220_in_ep: endpoint {
+					remote-endpoint = <&ss_ep>;
+				};
+			};
+
+			port at 1 {
+				reg = <1>;
+				hd3ss3220_out_ep: endpoint {
+					remote-endpoint = <&usb_role_switch>;
+				};
+			};
+		};
+	};
+};
+
+&i2c_mux_gp_2 {
+	codec at 1a {
+		#sound-dai-cells = <0>;
+		clocks = <&topckgen CLK_TOP_I2SO1>;
+		compatible = "wlf,wm8962";
+		gpio-cfg = <
+			0x0000 /* n/c */
+			0x0000 /* gpio2: */
+			0x0000 /* gpio3: */
+			0x0000 /* n/c */
+			0x8081 /* gpio5:HP detect */
+			0x8095 /* gpio6:Mic detect */
+		>;
+		reg = <0x1a>;
+	};
+};
+
+&i2c_mux_lcd_2 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	bridge at 2c {
+		compatible = "ti,sn65dsi84";
+		reg = <0x2c>;
+		enable-gpios = <&pio 25 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&dsi0_sn65dsi84_pins>;
+		status = "okay";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+
+				sn65dsi84_bridge_in: endpoint {
+					remote-endpoint = <&dsi0_out>;
+					data-lanes = <1 2 3 4>;
+				};
+			};
+
+			port at 2 {
+				reg = <2>;
+
+				sn65dsi84_bridge_out: endpoint {
+					remote-endpoint = <&dsi0_panel_in>;
+				};
+			};
+		};
+	};
+
+	touchscren at 5d {
+		compatible = "goodix,gt911";
+		reg = <0x5d>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&ts_dsi0_goodix_pins>;
+		interrupts-extended = <&pio 146 IRQ_TYPE_LEVEL_HIGH>;
+		irq-gpios = <&pio 146 GPIO_ACTIVE_HIGH>;
+		reset-gpios = <&pio 7 GPIO_ACTIVE_HIGH>;
+	};
+};
+
+&mfg0 {
+	domain-supply = <&mt6359_vproc2_buck_reg>;
+};
+
+&mfg1 {
+	domain-supply = <&mt6359_vsram_others_ldo_reg>;
+};
+
+&mmc0 {
+	status = "okay";
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc0_default_pins>;
+	pinctrl-1 = <&mmc0_uhs_pins>;
+	bus-width = <8>;
+	max-frequency = <200000000>;
+	cap-mmc-highspeed;
+	cap-mmc-hw-reset;
+	mmc-hs200-1_8v;
+	mmc-hs400-1_8v;
+	supports-cqe;
+	cap-mmc-hw-reset;
+	no-sdio;
+	no-sd;
+	hs400-ds-delay = <0x1481b>;
+	vmmc-supply = <&mt6359_vemc_1_ldo_reg>;
+	vqmmc-supply = <&mt6359_vufs_ldo_reg>;
+	non-removable;
+};
+
+&mmc1 {
+	status = "okay";
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc1_default_pins>;
+	pinctrl-1 = <&mmc1_uhs_pins>;
+	bus-width = <4>;
+	max-frequency = <200000000>;
+	cap-sd-highspeed;
+	sd-uhs-sdr50;
+	sd-uhs-sdr104;
+	cd-gpios = <&pio 2 GPIO_ACTIVE_LOW>;
+	vqmmc-supply = <&mt6359_vsim1_ldo_reg>;
+	vmmc-supply = <&sdcard_en_3v3>;
+};
+
+&mmc2 {
+	status = "okay";
+	pinctrl-names = "default", "state_uhs", "state_eint";
+	pinctrl-0 = <&mmc2_default_pins>;
+	pinctrl-1 = <&mmc2_uhs_pins>;
+	pinctrl-2 = <&mmc2_eint_pins>;
+	eint-gpios = <&pio 172 0>;
+	bus-width = <4>;
+	max-frequency = <200000000>;
+	cap-sd-highspeed;
+	sd-uhs-sdr104;
+	keep-power-in-suspend;
+	enable-sdio-wakeup;
+	cap-sdio-async-int;
+	cap-sdio-irq;
+	no-mmc;
+	no-sd;
+	non-removable;
+	vmmc-supply = <&mt6359_vcn33_2_bt_ldo_reg>;
+	vqmmc-supply = <&mt6359_vcn18_ldo_reg>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+};
+
+&mipi_tx_config0 {
+	status = "okay";
+};
+
+&mt6359codec {
+	mediatek,mic-type-0 = <1>;
+	mediatek,mic-type-1 = <3>;
+	mediatek,mic-type-2 = <0>;
+	mediatek,dmic-mode = <0>;
+};
+
+&mt6359_vbbck_ldo_reg {
+	regulator-always-on;
+};
+
+&mt6359_vcn18_ldo_reg {
+	regulator-name = "vcn18_pmu";
+	regulator-always-on;
+	regulator-boot-on;
+};
+
+&mt6359_vcn33_1_bt_ldo_reg {
+	regulator-name = "vcn33_1_pmu";
+	regulator-always-on;
+};
+
+&mt6359_vcn33_2_bt_ldo_reg {
+	regulator-name = "vcn33_2_pmu";
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-always-on;
+	regulator-boot-on;
+};
+
+&mt6359_vcore_buck_reg {
+	regulator-name = "dvdd_proc_l";
+	regulator-always-on;
+};
+
+&mt6359_vemc_1_ldo_reg {
+	regulator-always-on;
+};
+
+&mt6359_vgpu11_buck_reg {
+	regulator-name = "dvdd_core";
+	regulator-always-on;
+};
+
+&mt6359_vmodem_buck_reg {
+	regulator-always-on;
+};
+
+&mt6359_vpa_buck_reg {
+	regulator-name = "vpa_pmu";
+	regulator-always-on;
+};
+
+&mt6359_vproc2_buck_reg {
+	/* The name "vgpu" is required by mtk-regulator-coupler */
+	regulator-name = "vgpu";
+	regulator-min-microvolt = <550000>;
+	regulator-max-microvolt = <800000>;
+	regulator-coupled-with = <&mt6359_vsram_others_ldo_reg>;
+	regulator-coupled-max-spread = <225000>;
+	regulator-always-on;
+};
+
+&mt6359_vs2_buck_reg {
+	regulator-min-microvolt = <1600000>;
+	regulator-boot-on;
+};
+
+&mt6359_vpu_buck_reg {
+	regulator-name = "dvdd_adsp";
+	regulator-always-on;
+};
+
+&mt6359_vrf12_ldo_reg {
+	regulator-name = "va12_abb2_pmu";
+	regulator-always-on;
+};
+
+&mt6359_vsram_md_ldo_reg {
+	regulator-always-on;
+};
+
+&mt6359_vsram_others_ldo_reg {
+	/* The name "vsram_gpu" is required by mtk-regulator-coupler */
+	regulator-name = "vsram_gpu";
+	regulator-min-microvolt = <750000>;
+	regulator-max-microvolt = <800000>;
+	regulator-coupled-with = <&mt6359_vproc2_buck_reg>;
+	regulator-coupled-max-spread = <225000>;
+	regulator-always-on;
+};
+
+&mt6359_vsim1_ldo_reg {
+	regulator-name = "vsim1_pmu";
+	regulator-max-microvolt = <1800000>;
+	regulator-enable-ramp-delay = <480>;
+};
+
+&mt6359_vufs_ldo_reg {
+	regulator-name = "vufs18_pmu";
+	regulator-always-on;
+};
+
+&ovl0_in {
+	remote-endpoint = <&vdosys0_ep_main>;
+};
+
+&pcie {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie_default_pins>;
+	status = "okay";
+};
+
+&pciephy {
+	status = "okay";
+};
+
+&pmic {
+	interrupt-parent = <&pio>;
+	interrupts = <222 IRQ_TYPE_LEVEL_HIGH>;
+
+	keys {
+		compatible = "mediatek,mt6359-keys";
+		mediatek,long-press-mode = <1>;
+		power-off-time-sec = <0>;
+
+		power-key {
+			linux,keycodes = <116>;
+			wakeup-source;
+		};
+	};
+};
+
+&postmask0_in {
+	remote-endpoint = <&gamma0_out>;
+};
+
+&postmask0_out {
+	remote-endpoint = <&dither0_in>;
+};
+
+&scp_cluster {
+	status = "okay";
+};
+
+&scp_c0 {
+	firmware-name = "mediatek/mt8188/scp.img";
+	memory-region = <&scp_mem>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-0 = <&spi0_pins>;
+	pinctrl-names = "default";
+	mediatek,pad-select = <0>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+};
+
+&spi1 {
+	pinctrl-0 = <&spi1_pins>;
+	pinctrl-names = "default";
+	mediatek,pad-select = <0>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+};
+
+&spmi {
+	#address-cells = <1>;
+	#size-cells = <2>;
+
+	mt6315_6: pmic at 6 {
+		compatible = "mediatek,mt6315-regulator";
+		reg = <0x6 0 0xb>;
+
+		regulators {
+			mt6315_6_vbuck1: vbuck1 {
+				regulator-compatible = "vbuck1";
+				regulator-name = "vbuck1";
+				regulator-min-microvolt = <300000>;
+				regulator-max-microvolt = <1193750>;
+				regulator-enable-ramp-delay = <256>;
+				regulator-allowed-modes = <0 1 2>;
+				regulator-always-on;
+				mtk,combined-regulator = <2>;
+			};
+
+			mt6315_6_vbuck3: vbuck3 {
+				regulator-compatible = "vbuck3";
+				regulator-name = "vbuck3";
+				regulator-min-microvolt = <300000>;
+				regulator-max-microvolt = <1193750>;
+				regulator-enable-ramp-delay = <256>;
+				regulator-allowed-modes = <0 1 2>;
+				regulator-always-on;
+			};
+
+			mt6315_6_vbuck4: vbuck4 {
+				regulator-compatible = "vbuck4";
+				regulator-name = "vbuck4";
+				regulator-min-microvolt = <1193750>;
+				regulator-max-microvolt = <1193750>;
+				regulator-enable-ramp-delay = <256>;
+				regulator-allowed-modes = <0 1 2>;
+				regulator-always-on;
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1193750>;
+				};
+			};
+		};
+	};
+};
+
+&uart0 {
+	pinctrl-0 = <&uart0_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-0 = <&uart1_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-0 = <&uart2_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&ssusb0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&usbotg_pins>;
+	maximum-speed = "high-speed";
+	usb-role-switch;
+	dr_mode = "otg";
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	wakeup-source;
+	status = "okay";
+
+	connector {
+		compatible = "usb-c-connector";
+		label = "USB-C";
+		data-role = "dual";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+				hs_ep: endpoint {
+					remote-endpoint = <&usb_hs_ep>;
+				};
+			};
+
+			port at 1 {
+				reg = <1>;
+				ss_ep: endpoint {
+					remote-endpoint = <&hd3ss3220_in_ep>;
+				};
+			};
+		};
+	};
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			reg = <0>;
+			usb_hs_ep: endpoint {
+				remote-endpoint = <&hs_ep>;
+			};
+		};
+
+		port at 1 {
+			reg = <1>;
+			usb_role_switch: endpoint {
+				remote-endpoint = <&hd3ss3220_out_ep>;
+			};
+		};
+	};
+};
+
+&u2port0 {
+	status = "okay";
+};
+
+&u3phy0 {
+	status = "okay";
+};
+
+&xhci0 {
+	vbus-supply = <&usb_p0_vbus>;
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	status = "okay";
+};
+
+&ssusb1 {
+	pinctrl-0 = <&usb1_pins>;
+	pinctrl-names = "default";
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	dr_mode = "host";
+	wakeup-source;
+	status = "okay";
+};
+
+&u2port1 {
+	status = "okay";
+};
+
+&u3port1 {
+	status = "okay";
+};
+
+&u3phy1 {
+	status = "okay";
+};
+
+&xhci1 {
+	vbus-supply = <&usb_p1_vbus>;
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	status = "okay";
+};
+
+&ssusb2 {
+	maximum-speed = "high-speed";
+	dr_mode = "host";
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	status = "okay";
+	wakeup-source;
+};
+
+&u2port2 {
+	status = "okay";
+};
+
+&u3phy2 {
+	status = "okay";
+};
+
+&xhci2 {
+	vbus-supply = <&usb_p2_vbus>;
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+
+	ethernet at 1 {
+		compatible = "usb424,7850";
+		reg = <1>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		mdio {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			ethernet-phy at 1 {
+				reg = <1>;
+				microchip,led-modes = <
+					LAN78XX_LINK_1000_ACTIVITY
+					LAN78XX_LINK_10_ACTIVITY
+					LAN78XX_LINK_10_100_ACTIVITY
+					LAN78XX_LINK_ACTIVITY
+				>;
+			};
+		};
+	};
+};
+
+&vdosys0 {
+	port {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		vdosys0_ep_main: endpoint at 0 {
+			reg = <0>;
+			remote-endpoint = <&ovl0_in>;
+		};
+	};
+};
+
+&watchdog {
+	pinctrl-names = "default";
+	pinctrl-0 = <&watchdog_pins>;
+};
+
+&pio {
+	audio_pins: audio-pins {
+		pins-aud-pmic {
+			pinmux = <
+				PINMUX_GPIO101__FUNC_O_AUD_CLK_MOSI
+				PINMUX_GPIO102__FUNC_O_AUD_SYNC_MOSI
+				PINMUX_GPIO103__FUNC_O_AUD_DAT_MOSI0
+				PINMUX_GPIO104__FUNC_O_AUD_DAT_MOSI1
+				PINMUX_GPIO105__FUNC_I0_AUD_DAT_MISO0
+				PINMUX_GPIO106__FUNC_I0_AUD_DAT_MISO1
+			>;
+		};
+
+		pins-pcm-wifi {
+			pinmux = <
+				PINMUX_GPIO121__FUNC_B0_PCM_CLK
+				PINMUX_GPIO122__FUNC_B0_PCM_SYNC
+				PINMUX_GPIO123__FUNC_O_PCM_DO
+				PINMUX_GPIO124__FUNC_I0_PCM_DI
+			>;
+		};
+
+		pins-i2s {
+			pinmux = <
+				PINMUX_GPIO119__FUNC_O_I2SO1_MCK
+				PINMUX_GPIO112__FUNC_O_I2SO1_WS
+				PINMUX_GPIO120__FUNC_O_I2SO1_BCK
+				PINMUX_GPIO113__FUNC_O_I2SO1_D0
+				PINMUX_GPIO110__FUNC_I0_I2SIN_D0
+			>;
+		};
+	};
+
+	disp_pwm0_pins: disp-pwm0-pins {
+		pins {
+			pinmux = <PINMUX_GPIO29__FUNC_O_DISP_PWM0>;
+			bias-pull-down;
+		};
+	};
+
+	dsi0_sn65dsi84_pins: dsi0-sn65dsi84-pins {
+		pins-irq {
+			pinmux = <PINMUX_GPIO128__FUNC_B_GPIO128>;
+			bias-pull-down;
+			input-enable;
+		};
+
+		pins-enable {
+			pinmux = <PINMUX_GPIO25__FUNC_B_GPIO25>;
+			bias-pull-down;
+		};
+	};
+
+	eth_default_pins: eth-default-pins {
+		pins-txd {
+			pinmux = <PINMUX_GPIO131__FUNC_O_GBE_TXD3>,
+				 <PINMUX_GPIO132__FUNC_O_GBE_TXD2>,
+				 <PINMUX_GPIO133__FUNC_O_GBE_TXD1>,
+				 <PINMUX_GPIO134__FUNC_O_GBE_TXD0>;
+			drive-strength = <MTK_DRIVE_8mA>;
+		};
+		pins-cc {
+			pinmux = <PINMUX_GPIO139__FUNC_B0_GBE_TXC>,
+				 <PINMUX_GPIO142__FUNC_O_GBE_TXEN>,
+				 <PINMUX_GPIO141__FUNC_I0_GBE_RXDV>;
+			drive-strength = <MTK_DRIVE_8mA>;
+		};
+		pins-rxd {
+			pinmux = <PINMUX_GPIO135__FUNC_I0_GBE_RXD3>,
+				 <PINMUX_GPIO136__FUNC_I0_GBE_RXD2>,
+				 <PINMUX_GPIO137__FUNC_I0_GBE_RXD1>,
+				 <PINMUX_GPIO138__FUNC_I0_GBE_RXD0>,
+				 <PINMUX_GPIO140__FUNC_I0_GBE_RXC>;
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
+		};
+		pins-mdio {
+			pinmux = <PINMUX_GPIO143__FUNC_O_GBE_MDC>,
+				 <PINMUX_GPIO144__FUNC_B1_GBE_MDIO>;
+			drive-strength = <MTK_DRIVE_8mA>;
+			input-enable;
+		};
+		pins-power {
+			pinmux = <PINMUX_GPIO27__FUNC_B_GPIO27>; /* GP_EQOS_RESET */
+			output-high;
+		};
+		pins-intr {
+			pinmux = <PINMUX_GPIO148__FUNC_B_GPIO148>; /* GPIRQ_EQOS_PHY */
+			bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
+			input-enable;
+		};
+	};
+
+	eth_sleep_pins: eth-sleep-pins {
+		pins-txd {
+			pinmux = <PINMUX_GPIO131__FUNC_B_GPIO131>,
+				 <PINMUX_GPIO132__FUNC_B_GPIO132>,
+				 <PINMUX_GPIO133__FUNC_B_GPIO133>,
+				 <PINMUX_GPIO134__FUNC_B_GPIO134>;
+		};
+		pins-cc {
+			pinmux = <PINMUX_GPIO139__FUNC_B_GPIO139>,
+				 <PINMUX_GPIO142__FUNC_B_GPIO142>,
+				 <PINMUX_GPIO141__FUNC_B_GPIO141>,
+				 <PINMUX_GPIO140__FUNC_B_GPIO140>;
+		};
+		pins-rxd {
+			pinmux = <PINMUX_GPIO135__FUNC_B_GPIO135>,
+				 <PINMUX_GPIO136__FUNC_B_GPIO136>,
+				 <PINMUX_GPIO137__FUNC_B_GPIO137>,
+				 <PINMUX_GPIO138__FUNC_B_GPIO138>;
+		};
+		pins-mdio {
+			pinmux = <PINMUX_GPIO143__FUNC_B_GPIO143>,
+				 <PINMUX_GPIO144__FUNC_B_GPIO144>;
+			input-disable;
+			bias-disable;
+		};
+	};
+
+	gpio_keys_pins: gpio-keys-pins {
+		pins-keys {
+			pinmux = <PINMUX_GPIO129__FUNC_B_GPIO129>,
+				 <PINMUX_GPIO65__FUNC_B_GPIO65>,
+				 <PINMUX_GPIO66__FUNC_B_GPIO66>;
+			bias-pull-up;
+		};
+	};
+
+	hd3ss3220_pins: hd3ss3320-pins {
+		pins-irq {
+			pinmux = <PINMUX_GPIO45__FUNC_B_GPIO45>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+			input-enable;
+		};
+	};
+
+	hdmi_vreg_pins: hdmi-vreg-pins {
+		pins-pwr {
+			pinmux = <PINMUX_GPIO50__FUNC_O_HDMITX20_PWR5V>;
+			bias-disable;
+		};
+	};
+
+	hdmi_pins: hdmi-pins {
+		pins-hotplug {
+			pinmux = <PINMUX_GPIO51__FUNC_I0_HDMITX20_HTPLG>;
+			bias-pull-down;
+		};
+
+		pins-cec {
+			pinmux = <PINMUX_GPIO52__FUNC_B1_HDMITX20_CEC>;
+			bias-disable;
+		};
+
+		pins-ddc {
+			pinmux = <PINMUX_GPIO53__FUNC_B1_HDMITX20_SCL>,
+				 <PINMUX_GPIO54__FUNC_B1_HDMITX20_SDA>;
+			drive-strength = <10>;
+		};
+	};
+
+	i2c0_pins: i2c0-pins {
+		pins-bus {
+			pinmux = <PINMUX_GPIO56__FUNC_B1_SDA0>,
+				 <PINMUX_GPIO55__FUNC_B1_SCL0>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c0_gpio_pins: i2c0-gpio-pins {
+		pins-gpio {
+			pinmux = <PINMUX_GPIO6__FUNC_B_GPIO6>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c1_pins: i2c1-pins {
+		pins-bus {
+			pinmux = <PINMUX_GPIO58__FUNC_B1_SDA1>,
+				 <PINMUX_GPIO57__FUNC_B1_SCL1>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c2_pins: i2c2-pins {
+		pins-bus {
+			pinmux = <PINMUX_GPIO60__FUNC_B1_SDA2>,
+				 <PINMUX_GPIO59__FUNC_B1_SCL2>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c3_pins: i2c3-pins {
+		pins-bus {
+			pinmux = <PINMUX_GPIO62__FUNC_B1_SDA3>,
+				 <PINMUX_GPIO61__FUNC_B1_SCL3>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c4_pins: i2c4-pins {
+		pins-bus {
+			pinmux = <PINMUX_GPIO64__FUNC_B1_SDA4>,
+				 <PINMUX_GPIO63__FUNC_B1_SCL4>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c_mux_smarc_lcd_pins: i2c-mux-smarc-lcd-pins {
+		pins-reset {
+			pinmux = <PINMUX_GPIO5__FUNC_B_GPIO5>;
+			bias-pull-down;
+		};
+	};
+
+	mmc0_default_pins: mmc0-default-pins {
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO161__FUNC_B1_MSDC0_DAT0>,
+				 <PINMUX_GPIO160__FUNC_B1_MSDC0_DAT1>,
+				 <PINMUX_GPIO159__FUNC_B1_MSDC0_DAT2>,
+				 <PINMUX_GPIO158__FUNC_B1_MSDC0_DAT3>,
+				 <PINMUX_GPIO154__FUNC_B1_MSDC0_DAT4>,
+				 <PINMUX_GPIO153__FUNC_B1_MSDC0_DAT5>,
+				 <PINMUX_GPIO152__FUNC_B1_MSDC0_DAT6>,
+				 <PINMUX_GPIO151__FUNC_B1_MSDC0_DAT7>,
+				 <PINMUX_GPIO156__FUNC_B1_MSDC0_CMD>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins-clk {
+			pinmux = <PINMUX_GPIO157__FUNC_B1_MSDC0_CLK>;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-rst {
+			pinmux = <PINMUX_GPIO155__FUNC_O_MSDC0_RSTB>;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+
+	mmc0_uhs_pins: mmc0-uhs-pins {
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO161__FUNC_B1_MSDC0_DAT0>,
+				 <PINMUX_GPIO160__FUNC_B1_MSDC0_DAT1>,
+				 <PINMUX_GPIO159__FUNC_B1_MSDC0_DAT2>,
+				 <PINMUX_GPIO158__FUNC_B1_MSDC0_DAT3>,
+				 <PINMUX_GPIO154__FUNC_B1_MSDC0_DAT4>,
+				 <PINMUX_GPIO153__FUNC_B1_MSDC0_DAT5>,
+				 <PINMUX_GPIO152__FUNC_B1_MSDC0_DAT6>,
+				 <PINMUX_GPIO151__FUNC_B1_MSDC0_DAT7>,
+				 <PINMUX_GPIO156__FUNC_B1_MSDC0_CMD>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins-clk {
+			pinmux = <PINMUX_GPIO157__FUNC_B1_MSDC0_CLK>;
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-ds {
+			pinmux = <PINMUX_GPIO162__FUNC_B0_MSDC0_DSL>;
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-rst {
+			pinmux = <PINMUX_GPIO155__FUNC_O_MSDC0_RSTB>;
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+
+	mmc1_default_pins: mmc1-default-pins {
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO163__FUNC_B1_MSDC1_CMD>,
+				 <PINMUX_GPIO165__FUNC_B1_MSDC1_DAT0>,
+				 <PINMUX_GPIO166__FUNC_B1_MSDC1_DAT1>,
+				 <PINMUX_GPIO167__FUNC_B1_MSDC1_DAT2>,
+				 <PINMUX_GPIO168__FUNC_B1_MSDC1_DAT3>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins-pwr {
+			pinmux = <PINMUX_GPIO111__FUNC_B_GPIO111>;
+			bias-pull-down;
+		};
+
+		pins-pullup {
+			pinmux = <PINMUX_GPIO11__FUNC_B_GPIO11>;
+			bias-pull-up;
+		};
+
+		pins-clk {
+			pinmux = <PINMUX_GPIO164__FUNC_B1_MSDC1_CLK>;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-insert {
+			pinmux = <PINMUX_GPIO2__FUNC_B_GPIO2>;
+			bias-pull-up;
+		};
+	};
+
+	mmc1_uhs_pins: mmc1-uhs-pins {
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO163__FUNC_B1_MSDC1_CMD>,
+				 <PINMUX_GPIO165__FUNC_B1_MSDC1_DAT0>,
+				 <PINMUX_GPIO166__FUNC_B1_MSDC1_DAT1>,
+				 <PINMUX_GPIO167__FUNC_B1_MSDC1_DAT2>,
+				 <PINMUX_GPIO168__FUNC_B1_MSDC1_DAT3>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins-clk {
+			pinmux = <PINMUX_GPIO164__FUNC_B1_MSDC1_CLK>;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+	};
+
+	mmc2_default_pins: mmc2-default-pins {
+		pins-clk {
+			pinmux = <PINMUX_GPIO170__FUNC_B1_MSDC2_CLK>;
+			drive-strength = <MTK_DRIVE_4mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO169__FUNC_B1_MSDC2_CMD>,
+				 <PINMUX_GPIO171__FUNC_B1_MSDC2_DAT0>,
+				 <PINMUX_GPIO172__FUNC_B1_MSDC2_DAT1>,
+				 <PINMUX_GPIO173__FUNC_B1_MSDC2_DAT2>,
+				 <PINMUX_GPIO174__FUNC_B1_MSDC2_DAT3>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+
+	mmc2_uhs_pins: mmc2-uhs-pins {
+		pins-clk {
+			pinmux = <PINMUX_GPIO170__FUNC_B1_MSDC2_CLK>;
+			drive-strength = <MTK_DRIVE_4mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO169__FUNC_B1_MSDC2_CMD>,
+				 <PINMUX_GPIO171__FUNC_B1_MSDC2_DAT0>,
+				 <PINMUX_GPIO172__FUNC_B1_MSDC2_DAT1>,
+				 <PINMUX_GPIO173__FUNC_B1_MSDC2_DAT2>,
+				 <PINMUX_GPIO174__FUNC_B1_MSDC2_DAT3>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+
+	mmc2_eint_pins: mmc2-eint-pins {
+		pins-dat1 {
+			pinmux = <PINMUX_GPIO172__FUNC_B_GPIO172>;
+			input-enable;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+
+	rv3028_pins: rv3028-pins {
+		pins-irq {
+			pinmux = <PINMUX_GPIO42__FUNC_B_GPIO42>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+			input-enable;
+		};
+	};
+
+	spi0_pins: spi0-pins {
+		pins-spi {
+			pinmux = <PINMUX_GPIO69__FUNC_O_SPIM0_CSB>,
+				<PINMUX_GPIO70__FUNC_O_SPIM0_CLK>,
+				<PINMUX_GPIO71__FUNC_B0_SPIM0_MOSI>,
+				<PINMUX_GPIO72__FUNC_B0_SPIM0_MISO>;
+			bias-disable;
+		};
+	};
+
+	spi1_pins: spi1-pins {
+		pins-spi {
+			pinmux = <PINMUX_GPIO75__FUNC_O_SPIM1_CSB>,
+				<PINMUX_GPIO76__FUNC_O_SPIM1_CLK>,
+				<PINMUX_GPIO77__FUNC_B0_SPIM1_MOSI>,
+				<PINMUX_GPIO78__FUNC_B0_SPIM1_MISO>;
+			bias-disable;
+		};
+	};
+
+	pcie_default_pins: pcie-default-pins {
+		pins {
+			pinmux = <PINMUX_GPIO47__FUNC_I1_WAKEN>,
+				 <PINMUX_GPIO48__FUNC_O_PERSTN>,
+				 <PINMUX_GPIO49__FUNC_B1_CLKREQN>;
+			bias-pull-up;
+		};
+	};
+
+	ts_dsi0_goodix_pins: ts-dsi0-goodix-pins {
+		pins-irq {
+			pinmux = <PINMUX_GPIO146__FUNC_B_GPIO146>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+			input-enable;
+		};
+
+		pins-reset {
+			pinmux = <PINMUX_GPIO7__FUNC_B_GPIO7>;
+			bias-pull-down;
+		};
+	};
+
+	uart0_pins: uart0-pins {
+		pins {
+			pinmux = <PINMUX_GPIO31__FUNC_O_UTXD0>,
+				 <PINMUX_GPIO32__FUNC_I1_URXD0>;
+			bias-pull-up;
+		};
+	};
+
+	uart1_pins: uart1-pins {
+		pins {
+			pinmux = <PINMUX_GPIO33__FUNC_O_UTXD1>,
+				 <PINMUX_GPIO34__FUNC_I1_URXD1>;
+			bias-pull-up;
+		};
+	};
+
+	uart2_pins: uart2-pins {
+		pins {
+			pinmux = <PINMUX_GPIO35__FUNC_O_UTXD2>,
+				 <PINMUX_GPIO36__FUNC_I1_URXD2>;
+			bias-pull-up;
+		};
+	};
+
+	usbotg_pins: usbotg-pins {
+		pins-iddig {
+			pinmux = <PINMUX_GPIO83__FUNC_B_GPIO83>;
+			input-enable;
+			bias-pull-up;
+		};
+
+		pins-valid {
+			pinmux = <PINMUX_GPIO85__FUNC_I0_VBUSVALID>;
+			input-enable;
+		};
+
+		pins-vbus {
+			pinmux = <PINMUX_GPIO84__FUNC_O_USB_DRVVBUS>;
+			output-high;
+		};
+	};
+
+	usb1_hub_pins: usb1-hub-pins {
+		pins {
+			pinmux = <PINMUX_GPIO147__FUNC_B_GPIO147>;
+			output-low;
+		};
+	};
+
+	usb1_pins: usb1-pins {
+		pins {
+			pinmux = <PINMUX_GPIO88__FUNC_I0_VBUSVALID_1P>;
+			input-enable;
+		};
+	};
+
+	usb2_eth_pins: usb2-eth-pins {
+		pins {
+			pinmux = <PINMUX_GPIO80__FUNC_B_GPIO80>;
+			output-low;
+		};
+	};
+
+	wifi_pwrseq_pins: wifi-pwrseq-pins {
+		pins {
+			pinmux = <PINMUX_GPIO89__FUNC_B_GPIO89>;
+			output-low;
+		};
+	};
+
+	watchdog_pins: watchdog-pins {
+		pins {
+			pinmux = <PINMUX_GPIO100__FUNC_O_WATCHDOG>;
+			bias-pull-up;
+		};
+	};
+};

-- 
2.43.0



From yeoreum.yun at arm.com  Mon Dec  1 02:51:18 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Mon,  1 Dec 2025 10:51:18 +0000
Subject: [PATCH v2] arm64: kernel: initialize missing kexec_buf->random field
Message-ID: <20251201105118.2786335-1-yeoreum.yun@arm.com>

Commit bf454ec31add ("kexec_file: allow to place kexec_buf randomly")
introduced the kexec_buf->random field to enable random placement of
kexec_buf.

However, this field was never properly initialized for kexec images
that do not need to be placed randomly, leading to the following UBSAN
warning:

[  +0.364528] ------------[ cut here ]------------
[  +0.000019] UBSAN: invalid-load in ./include/linux/kexec.h:210:12
[  +0.000131] load of value 2 is not a valid value for type 'bool' (aka '_Bool')
[  +0.000003] CPU: 4 UID: 0 PID: 927 Comm: kexec Not tainted 6.18.0-rc7+ #3 PREEMPT(full)
[  +0.000002] Hardware name: QEMU QEMU Virtual Machine, BIOS 0.0.0 02/06/2015
[  +0.000000] Call trace:
[  +0.000001]  show_stack+0x24/0x40 (C)
[  +0.000006]  __dump_stack+0x28/0x48
[  +0.000002]  dump_stack_lvl+0x7c/0xb0
[  +0.000002]  dump_stack+0x18/0x34
[  +0.000001]  ubsan_epilogue+0x10/0x50
[  +0.000002]  __ubsan_handle_load_invalid_value+0xc8/0xd0
[  +0.000003]  locate_mem_hole_callback+0x28c/0x2a0
[  +0.000003]  kexec_locate_mem_hole+0xf4/0x2f0
[  +0.000001]  kexec_add_buffer+0xa8/0x178
[  +0.000002]  image_load+0xf0/0x258
[  +0.000001]  __arm64_sys_kexec_file_load+0x510/0x718
[  +0.000002]  invoke_syscall+0x68/0xe8
[  +0.000001]  el0_svc_common+0xb0/0xf8
[  +0.000002]  do_el0_svc+0x28/0x48
[  +0.000001]  el0_svc+0x40/0xe8
[  +0.000002]  el0t_64_sync_handler+0x84/0x140
[  +0.000002]  el0t_64_sync+0x1bc/0x1c0

To address this, initialise kexec_buf->random field properly.

Fixes: bf454ec31add ("kexec_file: allow to place kexec_buf randomly")
Suggested-by: Breno Leitao <leitao at debian.org>
Cc: <stable at vger.kernel.org>
Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
---
 arch/arm64/kernel/kexec_image.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/kexec_image.c b/arch/arm64/kernel/kexec_image.c
index 532d72ea42ee..b70f4df15a1a 100644
--- a/arch/arm64/kernel/kexec_image.c
+++ b/arch/arm64/kernel/kexec_image.c
@@ -41,7 +41,7 @@ static void *image_load(struct kimage *image,
 	struct arm64_image_header *h;
 	u64 flags, value;
 	bool be_image, be_kernel;
-	struct kexec_buf kbuf;
+	struct kexec_buf kbuf = {};
 	unsigned long text_offset, kernel_segment_number;
 	struct kexec_segment *kernel_segment;
 	int ret;
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



From alexander.stein at ew.tq-group.com  Mon Dec  1 02:51:41 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Mon,  1 Dec 2025 11:51:41 +0100
Subject: [RFC PATCH 2/3] irqchip/ls-extirq: Use managed resources
In-Reply-To: <20251201105144.539450-1-alexander.stein@ew.tq-group.com>
References: <20251201105144.539450-1-alexander.stein@ew.tq-group.com>
Message-ID: <20251201105144.539450-3-alexander.stein@ew.tq-group.com>

This simplifies the error handling and probe is straight forward.
Also use dev_err_probe for even more simplification.

Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 drivers/irqchip/irq-ls-extirq.c | 37 ++++++++-------------------------
 1 file changed, 9 insertions(+), 28 deletions(-)

diff --git a/drivers/irqchip/irq-ls-extirq.c b/drivers/irqchip/irq-ls-extirq.c
index cb7db9ae79087..52b8b9fc17621 100644
--- a/drivers/irqchip/irq-ls-extirq.c
+++ b/drivers/irqchip/irq-ls-extirq.c
@@ -192,26 +192,17 @@ static int ls_extirq_probe(struct platform_device *pdev)
 	if (!parent_domain)
 		return dev_err_probe(dev, -EPROBE_DEFER, "Cannot find parent domain\n");
 
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	if (!priv) {
-		ret = -ENOMEM;
-		goto err_alloc_priv;
-	}
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
 
-	/*
-	 * All extirq OF nodes are under a scfg/syscon node with
-	 * the 'ranges' property
-	 */
-	priv->intpcr = of_iomap(node, 0);
-	if (!priv->intpcr) {
-		dev_err(dev, "Cannot ioremap OF node %pOF\n", node);
-		ret = -ENOMEM;
-		goto err_iomap;
-	}
+	priv->intpcr = devm_of_iomap(dev, node, 0, NULL);
+	if (!priv->intpcr)
+		return dev_err_probe(dev, -ENOMEM, "Cannot ioremap OF node %pOF\n", node);
 
 	ret = ls_extirq_parse_map(priv, node);
 	if (ret)
-		goto err_parse_map;
+		return dev_err_probe(dev, ret, "Failed to parse IRQ map\n");
 
 	priv->big_endian = of_device_is_big_endian(node->parent);
 	priv->is_ls1021a_or_ls1043a = of_device_is_compatible(node, "fsl,ls1021a-extirq") ||
@@ -220,20 +211,10 @@ static int ls_extirq_probe(struct platform_device *pdev)
 
 	domain = irq_domain_create_hierarchy(parent_domain, 0, priv->nirq, of_fwnode_handle(node),
 					     &extirq_domain_ops, priv);
-	if (!domain) {
-		ret = -ENOMEM;
-		goto err_add_hierarchy;
-	}
+	if (!domain)
+		return dev_err_probe(dev, -ENOMEM, "Failed to add IRQ domain\n");
 
 	return 0;
-
-err_add_hierarchy:
-err_parse_map:
-	iounmap(priv->intpcr);
-err_iomap:
-	kfree(priv);
-err_alloc_priv:
-	return ret;
 }
 
 static struct platform_driver ls_extirq_driver = {
-- 
2.43.0



From alexander.stein at ew.tq-group.com  Mon Dec  1 02:51:42 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Mon,  1 Dec 2025 11:51:42 +0100
Subject: [RFC PATCH 3/3] arm64: dts: ls1088a: Move extirq outside of syscon
In-Reply-To: <20251201105144.539450-1-alexander.stein@ew.tq-group.com>
References: <20251201105144.539450-1-alexander.stein@ew.tq-group.com>
Message-ID: <20251201105144.539450-4-alexander.stein@ew.tq-group.com>

To make fsl,ls1088a-extirq a dedicated platform device this needs to
moved outside the syscon node.

Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 .../arm64/boot/dts/freescale/fsl-ls1088a.dtsi | 42 +++++++++----------
 1 file changed, 21 insertions(+), 21 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
index b2f6cd237be04..6eafd86459c7a 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
@@ -246,28 +246,28 @@ isc: syscon at 1f70000 {
 			#address-cells = <1>;
 			#size-cells = <1>;
 			ranges = <0x0 0x0 0x1f70000 0x10000>;
+		};
 
-			extirq: interrupt-controller at 14 {
-				compatible = "fsl,ls1088a-extirq";
-				#interrupt-cells = <2>;
-				#address-cells = <0>;
-				interrupt-controller;
-				reg = <0x14 4>;
-				interrupt-map =
-					<0 0 &gic GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
-					<1 0 &gic GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
-					<2 0 &gic GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
-					<3 0 &gic GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
-					<4 0 &gic GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
-					<5 0 &gic GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
-					<6 0 &gic GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>,
-					<7 0 &gic GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
-					<8 0 &gic GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
-					<9 0 &gic GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
-					<10 0 &gic GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
-					<11 0 &gic GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
-				interrupt-map-mask = <0xf 0x0>;
-			};
+		extirq: interrupt-controller at 1f70014 {
+			compatible = "fsl,ls1088a-extirq";
+			reg = <0x0 0x1f70014 0x0 0x4>;
+			#interrupt-cells = <2>;
+			#address-cells = <0>;
+			interrupt-controller;
+			interrupt-map =
+				<0 0 &gic GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+				<1 0 &gic GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
+				<2 0 &gic GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
+				<3 0 &gic GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+				<4 0 &gic GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
+				<5 0 &gic GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
+				<6 0 &gic GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>,
+				<7 0 &gic GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
+				<8 0 &gic GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+				<9 0 &gic GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
+				<10 0 &gic GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
+				<11 0 &gic GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-map-mask = <0xf 0x0>;
 		};
 
 		sfp: efuse at 1e80000 {
-- 
2.43.0



From alexander.stein at ew.tq-group.com  Mon Dec  1 02:51:39 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Mon,  1 Dec 2025 11:51:39 +0100
Subject: [RFC PATCH 0/3] ls-extirq platform device conversion
Message-ID: <20251201105144.539450-1-alexander.stein@ew.tq-group.com>

Hi,

this RFC tried to address the problem that sometimes at time of probing the
parent IRQ domain is not yet ready. This results in the error message:
> irq-ls-extirq: Cannot find parent domain
> OF: of_irq_init: Failed to init /soc/syscon at 1f70000/interrupt-controller at 14
>  ((____ptrval____)), parent 0000000000000000

Probe deferral is only possible having a platform device so the driver is
converted accordingly. It is inspired by commit 8ec99b033147e
("irqchip/sifive-plic: Convert PLIC driver into a platform driver").

Because the interrupt-controller at 1f70014 is a child of a syscon node, it is
not probed after platform device conversion. So it has to be moved outside.
This DT change has to be done for all layerscape SoC .dtsi
This is an incompatible change and I don't really know how to address that for
now. I've done it for LS1088A as a proof-of-concept for now.

Comments if this is the way to go or a different approach is more suitable
are very much welcome.

Best regards,
Alexander

Alexander Stein (3):
  irqchip/ls-extirq: Convert to platform driver
  irqchip/ls-extirq: Use managed resources
  arm64: dts: ls1088a: Move extirq outside of syscon

 .../arm64/boot/dts/freescale/fsl-ls1088a.dtsi | 42 +++++------
 drivers/irqchip/irq-ls-extirq.c               | 75 +++++++++----------
 2 files changed, 56 insertions(+), 61 deletions(-)

-- 
2.43.0



From alexander.stein at ew.tq-group.com  Mon Dec  1 02:51:40 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Mon,  1 Dec 2025 11:51:40 +0100
Subject: [RFC PATCH 1/3] irqchip/ls-extirq: Convert to platform driver
In-Reply-To: <20251201105144.539450-1-alexander.stein@ew.tq-group.com>
References: <20251201105144.539450-1-alexander.stein@ew.tq-group.com>
Message-ID: <20251201105144.539450-2-alexander.stein@ew.tq-group.com>

extirq maps to gic which might not be present yet when this driver is
initialized. Convert it to platform driver in order to allow probe
deferral.

Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 drivers/irqchip/irq-ls-extirq.c | 40 ++++++++++++++++++++++-----------
 1 file changed, 27 insertions(+), 13 deletions(-)

diff --git a/drivers/irqchip/irq-ls-extirq.c b/drivers/irqchip/irq-ls-extirq.c
index 50a7b38381b98..cb7db9ae79087 100644
--- a/drivers/irqchip/irq-ls-extirq.c
+++ b/drivers/irqchip/irq-ls-extirq.c
@@ -168,19 +168,29 @@ ls_extirq_parse_map(struct ls_extirq_data *priv, struct device_node *node)
 	return 0;
 }
 
-static int __init
-ls_extirq_of_init(struct device_node *node, struct device_node *parent)
+static const struct of_device_id ls_extirq_match[] = {
+	{ .compatible = "fsl,ls1021a-extirq" },
+	{ .compatible = "fsl,ls1043a-extirq" },
+	{ .compatible = "fsl,ls1088a-extirq" },
+	{}
+};
+
+static int ls_extirq_probe(struct platform_device *pdev)
 {
+	struct device_node *node = pdev->dev.of_node;
 	struct irq_domain *domain, *parent_domain;
+	struct device *dev = &pdev->dev;
+	struct device_node *irq_parent;
 	struct ls_extirq_data *priv;
 	int ret;
 
-	parent_domain = irq_find_host(parent);
-	if (!parent_domain) {
-		pr_err("Cannot find parent domain\n");
-		ret = -ENODEV;
-		goto err_irq_find_host;
-	}
+	irq_parent = of_irq_find_parent(dev->of_node);
+	if (!irq_parent)
+		return -ENODEV;
+
+	parent_domain = irq_find_host(irq_parent);
+	if (!parent_domain)
+		return dev_err_probe(dev, -EPROBE_DEFER, "Cannot find parent domain\n");
 
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv) {
@@ -194,7 +204,7 @@ ls_extirq_of_init(struct device_node *node, struct device_node *parent)
 	 */
 	priv->intpcr = of_iomap(node, 0);
 	if (!priv->intpcr) {
-		pr_err("Cannot ioremap OF node %pOF\n", node);
+		dev_err(dev, "Cannot ioremap OF node %pOF\n", node);
 		ret = -ENOMEM;
 		goto err_iomap;
 	}
@@ -223,10 +233,14 @@ ls_extirq_of_init(struct device_node *node, struct device_node *parent)
 err_iomap:
 	kfree(priv);
 err_alloc_priv:
-err_irq_find_host:
 	return ret;
 }
 
-IRQCHIP_DECLARE(ls1021a_extirq, "fsl,ls1021a-extirq", ls_extirq_of_init);
-IRQCHIP_DECLARE(ls1043a_extirq, "fsl,ls1043a-extirq", ls_extirq_of_init);
-IRQCHIP_DECLARE(ls1088a_extirq, "fsl,ls1088a-extirq", ls_extirq_of_init);
+static struct platform_driver ls_extirq_driver = {
+	.driver = {
+		.name		= "irq-ls-extirq",
+		.of_match_table	= ls_extirq_match,
+	},
+	.probe = ls_extirq_probe,
+};
+builtin_platform_driver(ls_extirq_driver);
-- 
2.43.0



From horms at kernel.org  Mon Dec  1 03:13:02 2025
From: horms at kernel.org (Simon Horman)
Date: Mon, 1 Dec 2025 11:13:02 +0000
Subject: [PATCH] net: stmmac: Modify the judgment condition of "tx_avail"
 from 1 to 2
In-Reply-To: <tencent_22959DC8315158E23D77C14B9B33C97EA60A@qq.com>
References: <tencent_22959DC8315158E23D77C14B9B33C97EA60A@qq.com>
Message-ID: <aS14PnwjbFcD_J70@horms.kernel.org>

On Mon, Dec 01, 2025 at 10:57:01AM +0800, 2694439648 at qq.com wrote:
> From: "hailong.fan" <hailong.fan at siengine.com>
> 
>     Under certain conditions, a WARN_ON will be triggered
>     if avail equals 1.
> 
>     For example, when a VLAN packet is to send,
>     stmmac_vlan_insert consumes one unit of space,
>     and the data itself consumes another.
>     actually requiring 2 units of space in total.

Hi,

I am wondering if there are other cases where an extra
descriptor is needed. And if so, can multiple such conditions
occur at the same time?

I am also wondering if the VLAN condition can be detected,
so a descriptor is only reserved for VLAN use if it will
actually be used for a VLAN.

And I think it would be worth noting how this problem was discovered
e.g. by inspection, using tooling (static analysis, AI, ...).
And how it has been tested e.g. On real HW, compile tested only.


As this is a fix for Networking code present in the net tree
it should be based on that tree. And targeted at that tree like this:

Subject: [PATCH net] ...

Also, as a fix for net, it should have a fixes tag.
Generally, this should denote the first patch where the problem would
manifest. In this case this seems to be a likely candidate:

Fixes: 30d932279dc2 ("net: stmmac: Add support for VLAN Insertion Offload")

The tag should go immediately above other tags, in this case your
Signed-off-by line, without any blank lines in between. And, like other
tags, it should not be line-wrapped.

For more information on the workflow for Networking changes please see:
https://docs.kernel.org/process/maintainer-netdev.html

> 
> Signed-off-by: hailong.fan <hailong.fan at siengine.com>


From leo.yan at arm.com  Mon Dec  1 03:21:50 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 01 Dec 2025 11:21:50 +0000
Subject: [PATCH 00/19] coresight: trbe: Support trigger and circle buffer
 modes
Message-ID: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>

The current TRBE driver operates only in fill mode, where tracing stops
at the top of buffer and a maintenance interrupt is raised.  Due to
interrupt latency, tracing is halted while the program continues to run,
resulting in trace data lose.

This series enhances the driver for the trigger mode to mitigate trace
discontinuity.  The circle buffer mode is introduced to avoid any
maintenance interrupts during the snapshot session.

It can be divided into three parts for easier review:

  Patches 01~05: Minor refactoring for disabling operations and
                 clearing status.
  Patches 06~12: Refactor fault action and trace size calculation.
  Patches 13~19: Support trigger and circle modes. To better utilize the
                 new buffer modes, perf sets the watermark to
		 one-quarter of the buffer size.

This series is applied on coresight-next branch and has been validated
on Orion O6 board:

  1) The trigger count and wrap mode are verified using Ftrace logs.
  2) A new kunit test module verifies limit and count calculations.
  3) Basic perf record / script commands and module load/unload have
     been tested successfully.

Signed-off-by: Leo Yan <leo.yan at arm.com>
---
Leo Yan (19):
      coresight: trbe: Use helpers for checking errata
      coresight: trbe: Remove redundant disable operation
      coresight: trbe: Remove buffer disabling in trbe_handle_overflow()
      coresight: trbe: Remove set_trbe_disabled() from the enable flow
      coresight: trbe: Refactor status clearing
      coresight: trbe: Refactor syndrome decoding
      coresight: trbe: Refactor AUX flag setting
      coresight: trbe: Use PERF_AUX_FLAG_PARTIAL instead of PERF_AUX_FLAG_COLLISION
      coresight: trbe: Add fault action argument to trbe_handle_overflow()
      coresight: trbe: Always check fault action when updating buffer
      coresight: trbe: Apply overwrite erratum for only wrap event
      coresight: trbe: Calculate size for buffer wrapping
      coresight: trbe: Remove misleading comment
      coresight: trbe: Refactor compute_trbe_buffer_limit()
      coresight: trbe: Add static key for bypassing trigger mode
      coresight: trbe: Support trigger mode
      coresight: trbe: Enable circle mode for snapshot
      coresight: trbe: Add kunit tests
      perf: cs-etm: Set watermark for AUX trace

 drivers/hwtracing/coresight/Kconfig                |   9 +
 drivers/hwtracing/coresight/Makefile               |   1 +
 .../coresight/coresight-trbe-kunit-tests.c         | 536 +++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-trbe.c       | 440 +++++++++--------
 drivers/hwtracing/coresight/coresight-trbe.h       | 111 ++++-
 tools/perf/arch/arm/util/cs-etm.c                  |   7 +
 6 files changed, 896 insertions(+), 208 deletions(-)
---
base-commit: 9e9182cab5ebc3ee7544e60ef08ba19fdf216920
change-id: 20251120-trbe_buffer_refactor_v1-1-8f8023105469

Best regards,
-- 
Leo Yan <leo.yan at arm.com>



From leo.yan at arm.com  Mon Dec  1 03:21:51 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 01 Dec 2025 11:21:51 +0000
Subject: [PATCH 01/19] coresight: trbe: Use helpers for checking errata
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
Message-ID: <20251201-trbe_buffer_refactor_v1-1-v1-1-7da32b076b28@arm.com>

Use the existed helpers for checking errata instead of open coded
equivalent.

Signed-off-by: Leo Yan <leo.yan at arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 293715b4ff0eb0abe30f9b477700ca94f81cd4a2..0ddb3db0213cf0014e29decfb79da68b0a351b31 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -723,7 +723,7 @@ static unsigned long trbe_get_trace_size(struct perf_output_handle *handle,
 	 * the space we skipped with IGNORE packets. And we are always
 	 * guaranteed to have at least a PAGE_SIZE space in the buffer.
 	 */
-	if (trbe_has_erratum(buf->cpudata, TRBE_WORKAROUND_OVERWRITE_FILL_MODE) &&
+	if (trbe_may_overwrite_in_fill_mode(buf->cpudata) &&
 	    !WARN_ON(size < overwrite_skip))
 		__trbe_pad_buf(buf, start_off, overwrite_skip);
 
@@ -946,7 +946,7 @@ static int trbe_apply_work_around_before_enable(struct trbe_buf *buf)
 	 *  - At trace collection:
 	 *     - Pad the 256bytes skipped above again with IGNORE packets.
 	 */
-	if (trbe_has_erratum(buf->cpudata, TRBE_WORKAROUND_OVERWRITE_FILL_MODE)) {
+	if (trbe_may_overwrite_in_fill_mode(buf->cpudata)) {
 		if (WARN_ON(!IS_ALIGNED(buf->trbe_write, PAGE_SIZE)))
 			return -EINVAL;
 		buf->trbe_hw_base = buf->trbe_write;
@@ -970,7 +970,7 @@ static int trbe_apply_work_around_before_enable(struct trbe_buf *buf)
 	 *     - Adjust the TRBLIMITR.LIMIT to leave the extra PAGE outside
 	 *       the TRBE's range (i.e [TRBBASER, TRBLIMITR.LIMI] ).
 	 */
-	if (trbe_has_erratum(buf->cpudata, TRBE_WORKAROUND_WRITE_OUT_OF_RANGE)) {
+	if (trbe_may_write_out_of_range(buf->cpudata)) {
 		s64 space = buf->trbe_limit - buf->trbe_write;
 		/*
 		 * We must have more than a PAGE_SIZE worth space in the proposed

-- 
2.34.1



From leo.yan at arm.com  Mon Dec  1 03:21:52 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 01 Dec 2025 11:21:52 +0000
Subject: [PATCH 02/19] coresight: trbe: Remove redundant disable operation
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
Message-ID: <20251201-trbe_buffer_refactor_v1-1-v1-2-7da32b076b28@arm.com>

The trace unit is already disabled when trbe_stop_and_truncate_event()
is called, so draining and stopping the buffer in the function is
redundant.

Remove the unnecessary disable operation and rename the function to
trbe_truncate_event() to better reflect its purpose.

Signed-off-by: Leo Yan <leo.yan at arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 14 +++-----------
 1 file changed, 3 insertions(+), 11 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 0ddb3db0213cf0014e29decfb79da68b0a351b31..2f44e4a65e0ee2b2c8fdd06a51ab01fc57f44a4e 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -284,18 +284,10 @@ static void trbe_report_wrap_event(struct perf_output_handle *handle)
 	perf_aux_output_flag(handle, PERF_AUX_FLAG_COLLISION);
 }
 
-static void trbe_stop_and_truncate_event(struct perf_output_handle *handle)
+static void trbe_truncate_event(struct perf_output_handle *handle)
 {
 	struct trbe_buf *buf = etm_perf_sink_config(handle);
 
-	/*
-	 * We cannot proceed with the buffer collection and we
-	 * do not have any data for the current session. The
-	 * etm_perf driver expects to close out the aux_buffer
-	 * at event_stop(). So disable the TRBE here and leave
-	 * the update_buffer() to return a 0 size.
-	 */
-	trbe_drain_and_disable_local(buf->cpudata);
 	perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED);
 	perf_aux_output_end(handle, 0);
 	*this_cpu_ptr(buf->cpudata->drvdata->handle) = NULL;
@@ -1008,7 +1000,7 @@ static int __arm_trbe_enable(struct trbe_buf *buf,
 	trbe_enable_hw(buf);
 	return 0;
 err:
-	trbe_stop_and_truncate_event(handle);
+	trbe_truncate_event(handle);
 	return ret;
 }
 
@@ -1169,7 +1161,7 @@ static irqreturn_t arm_trbe_irq_handler(int irq, void *dev)
 		trbe_handle_spurious(handle);
 		break;
 	case TRBE_FAULT_ACT_FATAL:
-		trbe_stop_and_truncate_event(handle);
+		trbe_truncate_event(handle);
 		truncated = true;
 		break;
 	}

-- 
2.34.1



From leo.yan at arm.com  Mon Dec  1 03:21:53 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 01 Dec 2025 11:21:53 +0000
Subject: [PATCH 03/19] coresight: trbe: Remove buffer disabling in
 trbe_handle_overflow()
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
Message-ID: <20251201-trbe_buffer_refactor_v1-1-v1-3-7da32b076b28@arm.com>

When trbe_handle_overflow() runs, the buffer has already been disabled
and drained, so the duplicate operation is unnecessary.  Remove it.

Signed-off-by: Leo Yan <leo.yan at arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 2f44e4a65e0ee2b2c8fdd06a51ab01fc57f44a4e..f5597bd9b5fba9a8f5053d5823b03380fd468b5c 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -1077,7 +1077,6 @@ static int trbe_handle_overflow(struct perf_output_handle *handle)
 		 * is able to detect this with a disconnected handle
 		 * (handle->event = NULL).
 		 */
-		trbe_drain_and_disable_local(buf->cpudata);
 		*this_cpu_ptr(buf->cpudata->drvdata->handle) = NULL;
 		return -EINVAL;
 	}

-- 
2.34.1



From leo.yan at arm.com  Mon Dec  1 03:21:54 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 01 Dec 2025 11:21:54 +0000
Subject: [PATCH 04/19] coresight: trbe: Remove set_trbe_disabled() from the
 enable flow
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
Message-ID: <20251201-trbe_buffer_refactor_v1-1-v1-4-7da32b076b28@arm.com>

set_trbe_disabled() should never appear in the enable flow, otherwise,
it may potentially hide bugs in the disable flow.

Remove set_trbe_disabled() from the enable path.

Signed-off-by: Leo Yan <leo.yan at arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index f5597bd9b5fba9a8f5053d5823b03380fd468b5c..e426991e2c2c398a9d3982e9d0f7f542e404cbab 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -629,7 +629,6 @@ static void trbe_enable_hw(struct trbe_buf *buf)
 	WARN_ON(buf->trbe_hw_base < buf->trbe_base);
 	WARN_ON(buf->trbe_write < buf->trbe_hw_base);
 	WARN_ON(buf->trbe_write >= buf->trbe_limit);
-	set_trbe_disabled(buf->cpudata);
 	clr_trbe_status();
 	set_trbe_base_pointer(buf->trbe_hw_base);
 	set_trbe_write_pointer(buf->trbe_write);

-- 
2.34.1



From leo.yan at arm.com  Mon Dec  1 03:21:55 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 01 Dec 2025 11:21:55 +0000
Subject: [PATCH 05/19] coresight: trbe: Refactor status clearing
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
Message-ID: <20251201-trbe_buffer_refactor_v1-1-v1-5-7da32b076b28@arm.com>

If the driver does not clear the status when disabling the trace buffer
unit, stale state will carry over to the next enable, though the driver
clears it again on enable.

Explicitly clear status after the trace is disabled in the interrupt
handling and when a perf session ends.  Keep the status for spurious
interrupts for continuous tracing.

Signed-off-by: Leo Yan <leo.yan at arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index e426991e2c2c398a9d3982e9d0f7f542e404cbab..9e565122816949b37b8ff5e4ba04cfbc317c6f25 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -629,7 +629,6 @@ static void trbe_enable_hw(struct trbe_buf *buf)
 	WARN_ON(buf->trbe_hw_base < buf->trbe_base);
 	WARN_ON(buf->trbe_write < buf->trbe_hw_base);
 	WARN_ON(buf->trbe_write >= buf->trbe_limit);
-	clr_trbe_status();
 	set_trbe_base_pointer(buf->trbe_hw_base);
 	set_trbe_write_pointer(buf->trbe_write);
 
@@ -1036,6 +1035,8 @@ static int arm_trbe_disable(struct coresight_device *csdev)
 		return -EINVAL;
 
 	trbe_drain_and_disable_local(cpudata);
+	clr_trbe_status();
+
 	buf->cpudata = NULL;
 	cpudata->buf = NULL;
 	cpudata->mode = CS_MODE_DISABLED;
@@ -1151,6 +1152,10 @@ static irqreturn_t arm_trbe_irq_handler(int irq, void *dev)
 		return IRQ_NONE;
 
 	act = trbe_get_fault_act(handle, status);
+
+	if (act != TRBE_FAULT_ACT_SPURIOUS)
+		clr_trbe_status();
+
 	switch (act) {
 	case TRBE_FAULT_ACT_WRAP:
 		truncated = !!trbe_handle_overflow(handle);

-- 
2.34.1



From leo.yan at arm.com  Mon Dec  1 03:21:56 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 01 Dec 2025 11:21:56 +0000
Subject: [PATCH 06/19] coresight: trbe: Refactor syndrome decoding
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
Message-ID: <20251201-trbe_buffer_refactor_v1-1-v1-6-7da32b076b28@arm.com>

It gives priority to TRBSR_EL1.EA (external abort); an external abort
will immediately bail out and return an error.

Next, the syndrome decoding is refactored based on two levels of
information: the EC (Event Class) bits and the BSC (Trace Buffer Status
Code) bits.

If TRBSR_EL1.EC==0b000000, the driver continues parsing TRBSR_EL1.BSC to
identify the specific trace buffer event.  Otherwise, any non-zero
TRBSR_EL1.EC is treated as an error.

For error cases, the driver prints an error string and dumps registers
for debugging.

No additional checks are required for wrap mode beyond verifying the
TRBSR_EL1.WRAP bit, even on units with overwrite errata, as this bit
reliably indicates a buffer wrap.

Signed-off-by: Leo Yan <leo.yan at arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 60 +++++++++++++++++++++-------
 drivers/hwtracing/coresight/coresight-trbe.h |  8 ++--
 2 files changed, 51 insertions(+), 17 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 9e565122816949b37b8ff5e4ba04cfbc317c6f25..28e2bfa68074f19ccaa4a737d00af577aea818fe 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -643,29 +643,61 @@ static void trbe_enable_hw(struct trbe_buf *buf)
 static enum trbe_fault_action trbe_get_fault_act(struct perf_output_handle *handle,
 						 u64 trbsr)
 {
+	const char *err_str;
 	int ec = get_trbe_ec(trbsr);
 	int bsc = get_trbe_bsc(trbsr);
-	struct trbe_buf *buf = etm_perf_sink_config(handle);
-	struct trbe_cpudata *cpudata = buf->cpudata;
 
 	WARN_ON(is_trbe_running(trbsr));
-	if (is_trbe_trg(trbsr) || is_trbe_abort(trbsr))
-		return TRBE_FAULT_ACT_FATAL;
 
-	if ((ec == TRBE_EC_STAGE1_ABORT) || (ec == TRBE_EC_STAGE2_ABORT))
-		return TRBE_FAULT_ACT_FATAL;
+	if (is_trbe_abort(trbsr)) {
+		err_str = "External abort";
+		goto out_fatal;
+	}
 
-	/*
-	 * If the trbe is affected by TRBE_WORKAROUND_OVERWRITE_FILL_MODE,
-	 * it might write data after a WRAP event in the fill mode.
-	 * Thus the check TRBPTR == TRBBASER will not be honored.
-	 */
-	if ((is_trbe_wrap(trbsr) && (ec == TRBE_EC_OTHERS) && (bsc == TRBE_BSC_FILLED)) &&
-	    (trbe_may_overwrite_in_fill_mode(cpudata) ||
-	     get_trbe_write_pointer() == get_trbe_base_pointer()))
+	switch (ec) {
+	case TRBE_EC_OTHERS:
+		break;
+	case TRBE_EC_BUF_MGMT_IMPL:
+		err_str = "Unexpected implemented management";
+		goto out_fatal;
+	case TRBE_EC_GP_CHECK_FAULT:
+		err_str = "Granule Protection Check fault";
+		goto out_fatal;
+	case TRBE_EC_STAGE1_ABORT:
+		err_str = "Stage 1 data abort";
+		goto out_fatal;
+	case TRBE_EC_STAGE2_ABORT:
+		err_str = "Stage 2 data abort";
+		goto out_fatal;
+	default:
+		err_str = "Unknown error code";
+		goto out_fatal;
+	}
+
+	switch (bsc) {
+	case TRBE_BSC_NOT_STOPPED:
+		break;
+	case TRBE_BSC_FILLED:
+		break;
+	case TRBE_BSC_TRIGGERED:
+		err_str = "Unexpected trigger status";
+		goto out_fatal;
+	default:
+		err_str = "Unexpected buffer status code";
+		goto out_fatal;
+	}
+
+	if (is_trbe_wrap(trbsr))
 		return TRBE_FAULT_ACT_WRAP;
 
 	return TRBE_FAULT_ACT_SPURIOUS;
+
+out_fatal:
+	pr_err_ratelimited("%s on CPU %d [TRBSR=0x%016llx, TRBPTR=0x%016llx, TRBLIMITR=0x%016llx]\n",
+			   err_str, smp_processor_id(), trbsr,
+			   read_sysreg_s(SYS_TRBPTR_EL1),
+			   read_sysreg_s(SYS_TRBLIMITR_EL1));
+	return TRBE_FAULT_ACT_FATAL;
 }
 
 static unsigned long trbe_get_trace_size(struct perf_output_handle *handle,
diff --git a/drivers/hwtracing/coresight/coresight-trbe.h b/drivers/hwtracing/coresight/coresight-trbe.h
index 45202c48accec7c86ba56130e2737bc2d1830fae..d7f7cd763c0c7139cf322b7336ee563073e3bea0 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.h
+++ b/drivers/hwtracing/coresight/coresight-trbe.h
@@ -35,9 +35,11 @@ static inline bool is_trbe_enabled(void)
 	return trblimitr & TRBLIMITR_EL1_E;
 }
 
-#define TRBE_EC_OTHERS		0
-#define TRBE_EC_STAGE1_ABORT	36
-#define TRBE_EC_STAGE2_ABORT	37
+#define TRBE_EC_OTHERS			0x0
+#define TRBE_EC_GP_CHECK_FAULT		0X1e
+#define TRBE_EC_BUF_MGMT_IMPL		0x1f
+#define TRBE_EC_STAGE1_ABORT		0x24
+#define TRBE_EC_STAGE2_ABORT		0x25
 
 static inline int get_trbe_ec(u64 trbsr)
 {

-- 
2.34.1



From leo.yan at arm.com  Mon Dec  1 03:21:57 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 01 Dec 2025 11:21:57 +0000
Subject: [PATCH 07/19] coresight: trbe: Refactor AUX flag setting
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
Message-ID: <20251201-trbe_buffer_refactor_v1-1-v1-7-7da32b076b28@arm.com>

Rather than spreading AUX flag setting in different functions, use
trbe_get_fault_act() as a central place for setting the flag.

Later we will support WRAP mode with continuous trace, so the WRAP
event does not necessarily cause the trace discontinuity, change to
check the stop status instead.

Signed-off-by: Leo Yan <leo.yan at arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 38 +++++++++++++---------------
 1 file changed, 17 insertions(+), 21 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 28e2bfa68074f19ccaa4a737d00af577aea818fe..b06885a08e082fd34f68d9588518807b5c47c86e 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -265,25 +265,6 @@ static void trbe_reset_local(struct trbe_cpudata *cpudata)
 	write_sysreg_s(0, SYS_TRBSR_EL1);
 }
 
-static void trbe_report_wrap_event(struct perf_output_handle *handle)
-{
-	/*
-	 * Mark the buffer to indicate that there was a WRAP event by
-	 * setting the COLLISION flag. This indicates to the user that
-	 * the TRBE trace collection was stopped without stopping the
-	 * ETE and thus there might be some amount of trace that was
-	 * lost between the time the WRAP was detected and the IRQ
-	 * was consumed by the CPU.
-	 *
-	 * Setting the TRUNCATED flag would move the event to STOPPED
-	 * state unnecessarily, even when there is space left in the
-	 * ring buffer. Using the COLLISION flag doesn't have this side
-	 * effect. We only set TRUNCATED flag when there is no space
-	 * left in the ring buffer.
-	 */
-	perf_aux_output_flag(handle, PERF_AUX_FLAG_COLLISION);
-}
-
 static void trbe_truncate_event(struct perf_output_handle *handle)
 {
 	struct trbe_buf *buf = etm_perf_sink_config(handle);
@@ -687,6 +668,23 @@ static enum trbe_fault_action trbe_get_fault_act(struct perf_output_handle *hand
 		goto out_fatal;
 	}
 
+	/*
+	 * Mark the buffer to indicate that there was a WRAP event by
+	 * setting the COLLISION flag. This indicates to the user that
+	 * the TRBE trace collection was stopped without stopping the
+	 * ETE and thus there might be some amount of trace that was
+	 * lost between the time the WRAP was detected and the IRQ
+	 * was consumed by the CPU.
+	 *
+	 * Setting the TRUNCATED flag would move the event to STOPPED
+	 * state unnecessarily, even when there is space left in the
+	 * ring buffer. Using the COLLISION flag doesn't have this side
+	 * effect. We only set TRUNCATED flag when there is no space
+	 * left in the ring buffer.
+	 */
+	if (!is_trbe_running(trbsr))
+		perf_aux_output_flag(handle, PERF_AUX_FLAG_COLLISION);
+
 	if (is_trbe_wrap(trbsr))
 		return TRBE_FAULT_ACT_WRAP;
 
@@ -878,7 +876,6 @@ static unsigned long arm_trbe_update_buffer(struct coresight_device *csdev,
 			goto done;
 		}
 
-		trbe_report_wrap_event(handle);
 		wrap = true;
 	}
 
@@ -1099,7 +1096,6 @@ static int trbe_handle_overflow(struct perf_output_handle *handle)
 	if (buf->snapshot)
 		handle->head += size;
 
-	trbe_report_wrap_event(handle);
 	perf_aux_output_end(handle, size);
 	event_data = perf_aux_output_begin(handle, event);
 	if (!event_data) {

-- 
2.34.1



From leo.yan at arm.com  Mon Dec  1 03:21:58 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 01 Dec 2025 11:21:58 +0000
Subject: [PATCH 08/19] coresight: trbe: Use PERF_AUX_FLAG_PARTIAL instead
 of PERF_AUX_FLAG_COLLISION
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
Message-ID: <20251201-trbe_buffer_refactor_v1-1-v1-8-7da32b076b28@arm.com>

When tracing stops, there is no collision with other samples, so using
PERF_AUX_FLAG_COLLISION does not accurately reflect the trace state and
may mislead userspace.

Use PERF_AUX_FLAG_PARTIAL instead to indicate that tracing stopped and
the record may contain gaps.

Signed-off-by: Leo Yan <leo.yan at arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 19 ++++++-------------
 1 file changed, 6 insertions(+), 13 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index b06885a08e082fd34f68d9588518807b5c47c86e..0caa4a6b437a3aa39fc6bcc72a23711b54f7c598 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -669,21 +669,14 @@ static enum trbe_fault_action trbe_get_fault_act(struct perf_output_handle *hand
 	}
 
 	/*
-	 * Mark the buffer to indicate that there was a WRAP event by
-	 * setting the COLLISION flag. This indicates to the user that
-	 * the TRBE trace collection was stopped without stopping the
-	 * ETE and thus there might be some amount of trace that was
-	 * lost between the time the WRAP was detected and the IRQ
-	 * was consumed by the CPU.
-	 *
-	 * Setting the TRUNCATED flag would move the event to STOPPED
-	 * state unnecessarily, even when there is space left in the
-	 * ring buffer. Using the COLLISION flag doesn't have this side
-	 * effect. We only set TRUNCATED flag when there is no space
-	 * left in the ring buffer.
+	 * Mark the buffer to indicate that the trace is stopped by setting
+	 * the PARTIAL flag. This indicates to the user that the TRBE trace
+	 * collection was stopped without stopping the ETE and thus there
+	 * might be some amount of trace that was lost between the time the
+	 * TRBE event was detected and the IRQ was consumed by the CPU.
 	 */
 	if (!is_trbe_running(trbsr))
-		perf_aux_output_flag(handle, PERF_AUX_FLAG_COLLISION);
+		perf_aux_output_flag(handle, PERF_AUX_FLAG_PARTIAL);
 
 	if (is_trbe_wrap(trbsr))
 		return TRBE_FAULT_ACT_WRAP;

-- 
2.34.1



From leo.yan at arm.com  Mon Dec  1 03:21:59 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 01 Dec 2025 11:21:59 +0000
Subject: [PATCH 09/19] coresight: trbe: Add fault action argument to
 trbe_handle_overflow()
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
Message-ID: <20251201-trbe_buffer_refactor_v1-1-v1-9-7da32b076b28@arm.com>

Add a new argument to trbe_handle_overflow() for the fault action, which
is used to compare the wrap event for trace size calculation.

No functional change intended; this is preparation for a later update.

Signed-off-by: Leo Yan <leo.yan at arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 0caa4a6b437a3aa39fc6bcc72a23711b54f7c598..f56ecdeaa6596afb440e4d53732e08a85f9bf89d 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -1078,14 +1078,15 @@ static void trbe_handle_spurious(struct perf_output_handle *handle)
 	set_trbe_enabled(buf->cpudata, trblimitr);
 }
 
-static int trbe_handle_overflow(struct perf_output_handle *handle)
+static int trbe_handle_overflow(struct perf_output_handle *handle,
+				enum trbe_fault_action act)
 {
 	struct perf_event *event = handle->event;
 	struct trbe_buf *buf = etm_perf_sink_config(handle);
 	unsigned long size;
 	struct etm_event_data *event_data;
 
-	size = trbe_get_trace_size(handle, buf, true);
+	size = trbe_get_trace_size(handle, buf, act == TRBE_FAULT_ACT_WRAP);
 	if (buf->snapshot)
 		handle->head += size;
 
@@ -1179,7 +1180,7 @@ static irqreturn_t arm_trbe_irq_handler(int irq, void *dev)
 
 	switch (act) {
 	case TRBE_FAULT_ACT_WRAP:
-		truncated = !!trbe_handle_overflow(handle);
+		truncated = !!trbe_handle_overflow(handle, act);
 		break;
 	case TRBE_FAULT_ACT_SPURIOUS:
 		trbe_handle_spurious(handle);

-- 
2.34.1



From leo.yan at arm.com  Mon Dec  1 03:22:00 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 01 Dec 2025 11:22:00 +0000
Subject: [PATCH 10/19] coresight: trbe: Always check fault action when
 updating buffer
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
Message-ID: <20251201-trbe_buffer_refactor_v1-1-v1-10-7da32b076b28@arm.com>

The current code checks the fault action only via the IRQ status bit,
which is unreliable due to possible hardware latency.

Move the fault action check out of the IRQ status condition.  This also
causes the buffer size to be calculated for non-WRAP and fault cases,
which is fine since the write pointer is trusted for the calculation.

Signed-off-by: Leo Yan <leo.yan at arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 17 +++--------------
 1 file changed, 3 insertions(+), 14 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index f56ecdeaa6596afb440e4d53732e08a85f9bf89d..e579ea98523c24d23a0cd265dcdd0a46b52b52da 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -806,7 +806,6 @@ static unsigned long arm_trbe_update_buffer(struct coresight_device *csdev,
 	enum trbe_fault_action act;
 	unsigned long size, status;
 	unsigned long flags;
-	bool wrap = false;
 
 	WARN_ON(buf->cpudata != cpudata);
 	WARN_ON(cpudata->cpu != smp_processor_id());
@@ -858,21 +857,11 @@ static unsigned long arm_trbe_update_buffer(struct coresight_device *csdev,
 		 */
 		clr_trbe_irq();
 		isb();
-
-		act = trbe_get_fault_act(handle, status);
-		/*
-		 * If this was not due to a WRAP event, we have some
-		 * errors and as such buffer is empty.
-		 */
-		if (act != TRBE_FAULT_ACT_WRAP) {
-			size = 0;
-			goto done;
-		}
-
-		wrap = true;
 	}
 
-	size = trbe_get_trace_size(handle, buf, wrap);
+	act = trbe_get_fault_act(handle, status);
+
+	size = trbe_get_trace_size(handle, buf, act == TRBE_FAULT_ACT_WRAP);
 
 done:
 	local_irq_restore(flags);

-- 
2.34.1



From leo.yan at arm.com  Mon Dec  1 03:22:01 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 01 Dec 2025 11:22:01 +0000
Subject: [PATCH 11/19] coresight: trbe: Apply overwrite erratum for only
 wrap event
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
Message-ID: <20251201-trbe_buffer_refactor_v1-1-v1-11-7da32b076b28@arm.com>

The overwrite erratum occurs only on wrap events, so apply the extra
wrap condition check in the workaround.

Signed-off-by: Leo Yan <leo.yan at arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index e579ea98523c24d23a0cd265dcdd0a46b52b52da..2600af12a8fb94bb8c74efda2a101aacd01b0b34 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -714,7 +714,7 @@ static unsigned long trbe_get_trace_size(struct perf_output_handle *handle,
 	 * 64bytes. Thus we ignore the potential triggering of the erratum
 	 * on WRAP and limit the data to LIMIT.
 	 */
-	if (wrap)
+	if (wrap && trbe_may_overwrite_in_fill_mode(buf->cpudata))
 		write = get_trbe_limit_pointer();
 	else
 		write = get_trbe_write_pointer();
@@ -736,7 +736,7 @@ static unsigned long trbe_get_trace_size(struct perf_output_handle *handle,
 	 * the space we skipped with IGNORE packets. And we are always
 	 * guaranteed to have at least a PAGE_SIZE space in the buffer.
 	 */
-	if (trbe_may_overwrite_in_fill_mode(buf->cpudata) &&
+	if (wrap && trbe_may_overwrite_in_fill_mode(buf->cpudata) &&
 	    !WARN_ON(size < overwrite_skip))
 		__trbe_pad_buf(buf, start_off, overwrite_skip);
 

-- 
2.34.1



From leo.yan at arm.com  Mon Dec  1 03:22:02 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 01 Dec 2025 11:22:02 +0000
Subject: [PATCH 12/19] coresight: trbe: Calculate size for buffer wrapping
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
Message-ID: <20251201-trbe_buffer_refactor_v1-1-v1-12-7da32b076b28@arm.com>

Calculate the wrapped size when the end position is less than the start.

If the start equals the end, the "wrap" flag is used to decide whether
the buffer is full or empty.

Signed-off-by: Leo Yan <leo.yan at arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 2600af12a8fb94bb8c74efda2a101aacd01b0b34..48bc03bd339908b5eac9466dc60325ff1b238976 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -696,7 +696,7 @@ static unsigned long trbe_get_trace_size(struct perf_output_handle *handle,
 {
 	u64 write;
 	u64 start_off, end_off;
-	u64 size;
+	u64 size, buf_size;
 	u64 overwrite_skip = TRBE_WORKAROUND_OVERWRITE_FILL_MODE_SKIP_BYTES;
 
 	/*
@@ -726,11 +726,18 @@ static unsigned long trbe_get_trace_size(struct perf_output_handle *handle,
 	 */
 	end_off = write - buf->trbe_base;
 	start_off = PERF_IDX2OFF(handle->head, buf);
+	buf_size = buf->trbe_limit - buf->trbe_base;
+
+	if (end_off > start_off)
+		size = end_off - start_off;
+	else if (end_off < start_off)
+		size = end_off + buf_size - start_off;
+	else if (wrap)
+		/* The start is the same as the end, just wrapped */
+		size = buf_size;
+	else
+		size = 0;
 
-	if (WARN_ON_ONCE(end_off < start_off))
-		return 0;
-
-	size = end_off - start_off;
 	/*
 	 * If the TRBE is affected by the following erratum, we must fill
 	 * the space we skipped with IGNORE packets. And we are always

-- 
2.34.1



From leo.yan at arm.com  Mon Dec  1 03:22:03 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 01 Dec 2025 11:22:03 +0000
Subject: [PATCH 13/19] coresight: trbe: Remove misleading comment
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
Message-ID: <20251201-trbe_buffer_refactor_v1-1-v1-13-7da32b076b28@arm.com>

Since the rounded-up wakeup address is always higher than the head, the
limit cannot be less than the head caused by wakeup capping.

The described scenario is never valid caused by wakeup capping, remove
the comment to avoid confusion.

Signed-off-by: Leo Yan <leo.yan at arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 16 ++--------------
 1 file changed, 2 insertions(+), 14 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 48bc03bd339908b5eac9466dc60325ff1b238976..206eaf103cd94f36220cb6bddd1a78012f5de35a 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -488,10 +488,10 @@ static unsigned long __trbe_normal_offset(struct perf_output_handle *handle)
 		limit = min(limit, round_up(wakeup, PAGE_SIZE));
 
 	/*
-	 * There are two situation when this can happen i.e limit is before
+	 * There is a situation when this can happen i.e limit is before
 	 * the head and hence TRBE cannot be configured.
 	 *
-	 * 1) head < tail (aligned down with PAGE_SIZE) and also they are both
+	 * head < tail (aligned down with PAGE_SIZE) and also they are both
 	 * within the same PAGE size range.
 	 *
 	 *			PAGE_SIZE
@@ -502,18 +502,6 @@ static unsigned long __trbe_normal_offset(struct perf_output_handle *handle)
 	 * |$$$$$$$$$$$$$$$$$$$|========|$$$$$$$|
 	 * +------------|------|--------|-------+
 	 * trbe_base				trbe_base + nr_pages
-	 *
-	 * 2) head < wakeup (aligned up with PAGE_SIZE) < tail and also both
-	 * head and wakeup are within same PAGE size range.
-	 *
-	 *		PAGE_SIZE
-	 *	|----------------------|
-	 *
-	 *	limit	head	wakeup  tail
-	 * +----|------|-------|--------|-------+
-	 * |$$$$$$$$$$$|=======|========|$$$$$$$|
-	 * +----|------|-------|--------|-------+
-	 * trbe_base				trbe_base + nr_pages
 	 */
 	if (limit > head)
 		return limit;

-- 
2.34.1



From leo.yan at arm.com  Mon Dec  1 03:22:04 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 01 Dec 2025 11:22:04 +0000
Subject: [PATCH 14/19] coresight: trbe: Refactor
 compute_trbe_buffer_limit()
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
Message-ID: <20251201-trbe_buffer_refactor_v1-1-v1-14-7da32b076b28@arm.com>

Refactor compute_trbe_buffer_limit() to perform the computation and
handle failures. The return type is changed from a limit offset to an
error number (0 is for success).

This refactoring is for future extensions, such as calculating
additional values (e.g., the trigger count). No functional changes are
introduced.

Signed-off-by: Leo Yan <leo.yan at arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 44 +++++++++++++++++-----------
 1 file changed, 27 insertions(+), 17 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 206eaf103cd94f36220cb6bddd1a78012f5de35a..941aa46e9b11f60c707eb40093964de454a3fd83 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -332,7 +332,7 @@ static void trbe_pad_buf(struct perf_output_handle *handle, int len)
 		perf_aux_output_skip(handle, len);
 }
 
-static unsigned long trbe_snapshot_offset(struct perf_output_handle *handle)
+static int trbe_snapshot_offset(struct perf_output_handle *handle)
 {
 	struct trbe_buf *buf = etm_perf_sink_config(handle);
 
@@ -341,7 +341,8 @@ static unsigned long trbe_snapshot_offset(struct perf_output_handle *handle)
 	 * the decoder to reset in case of an overflow or corruption.
 	 * So we can use the entire buffer for the snapshot mode.
 	 */
-	return buf->nr_pages * PAGE_SIZE;
+	buf->trbe_limit = buf->trbe_base + buf->nr_pages * PAGE_SIZE;
+	return 0;
 }
 
 static u64 trbe_min_trace_buf_size(struct perf_output_handle *handle)
@@ -510,7 +511,7 @@ static unsigned long __trbe_normal_offset(struct perf_output_handle *handle)
 	return 0;
 }
 
-static unsigned long trbe_normal_offset(struct perf_output_handle *handle)
+static int trbe_normal_offset(struct perf_output_handle *handle)
 {
 	struct trbe_buf *buf = etm_perf_sink_config(handle);
 	u64 limit = __trbe_normal_offset(handle);
@@ -529,19 +530,34 @@ static unsigned long trbe_normal_offset(struct perf_output_handle *handle)
 		limit = __trbe_normal_offset(handle);
 		head = PERF_IDX2OFF(handle->head, buf);
 	}
-	return limit;
+
+	if (!limit)
+		return -ENOSPC;
+
+	buf->trbe_limit = buf->trbe_base + limit;
+	return 0;
 }
 
-static unsigned long compute_trbe_buffer_limit(struct perf_output_handle *handle)
+static int trbe_compute_next(struct perf_output_handle *handle)
 {
 	struct trbe_buf *buf = etm_perf_sink_config(handle);
-	unsigned long offset;
+	int ret;
+
+	perf_aux_output_flag(handle, PERF_AUX_FLAG_CORESIGHT_FORMAT_RAW);
 
 	if (buf->snapshot)
-		offset = trbe_snapshot_offset(handle);
+		ret = trbe_snapshot_offset(handle);
 	else
-		offset = trbe_normal_offset(handle);
-	return buf->trbe_base + offset;
+		ret = trbe_normal_offset(handle);
+
+	if (ret)
+		return ret;
+
+	buf->trbe_write = buf->trbe_base + PERF_IDX2OFF(handle->head, buf);
+
+	/* Set the base of the TRBE to the buffer base */
+	buf->trbe_hw_base = buf->trbe_base;
+	return 0;
 }
 
 static void clr_trbe_status(void)
@@ -986,15 +1002,9 @@ static int __arm_trbe_enable(struct trbe_buf *buf,
 {
 	int ret = 0;
 
-	perf_aux_output_flag(handle, PERF_AUX_FLAG_CORESIGHT_FORMAT_RAW);
-	buf->trbe_limit = compute_trbe_buffer_limit(handle);
-	buf->trbe_write = buf->trbe_base + PERF_IDX2OFF(handle->head, buf);
-	if (buf->trbe_limit == buf->trbe_base) {
-		ret = -ENOSPC;
+	ret = trbe_compute_next(handle);
+	if (ret)
 		goto err;
-	}
-	/* Set the base of the TRBE to the buffer base */
-	buf->trbe_hw_base = buf->trbe_base;
 
 	ret = trbe_apply_work_around_before_enable(buf);
 	if (ret)

-- 
2.34.1



From leo.yan at arm.com  Mon Dec  1 03:22:05 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 01 Dec 2025 11:22:05 +0000
Subject: [PATCH 15/19] coresight: trbe: Add static key for bypassing
 trigger mode
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
Message-ID: <20251201-trbe_buffer_refactor_v1-1-v1-15-7da32b076b28@arm.com>

To avoid complexity, if any CPU in the system has the fill mode erratum,
the driver will not use trigger mode, it simply rolls back to fill mode
only and apply the workaround on it.

Add a static key to control trigger mode bypassing.  During each CPU
probe, the key is enabled when the relevant erratum is detected.

Signed-off-by: Leo Yan <leo.yan at arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 941aa46e9b11f60c707eb40093964de454a3fd83..8390d0a8fe23d35945610df15f21751279ee37ee 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -17,6 +17,7 @@
 
 #include <asm/barrier.h>
 #include <asm/cpufeature.h>
+#include <linux/jump_label.h>
 #include <linux/kvm_host.h>
 #include <linux/vmalloc.h>
 
@@ -147,6 +148,12 @@ struct trbe_drvdata {
 	struct platform_device *pdev;
 };
 
+DEFINE_STATIC_KEY_FALSE(trbe_trigger_mode_bypass);
+
+#define trbe_trigger_mode_need_bypass(cpudata)		\
+	(trbe_may_overwrite_in_fill_mode((cpudata)) ||	\
+	 trbe_may_write_out_of_range((cpudata)))
+
 static void trbe_check_errata(struct trbe_cpudata *cpudata)
 {
 	int i;
@@ -1306,6 +1313,14 @@ static void arm_trbe_register_coresight_cpu(struct trbe_drvdata *drvdata, int cp
 
 	dev_set_drvdata(&trbe_csdev->dev, cpudata);
 	coresight_set_percpu_sink(cpu, trbe_csdev);
+
+	/*
+	 * If any CPU cannot use trigger mode, bypass the mode globally for
+	 * consistent tracing behaviour.
+	 */
+	if (trbe_trigger_mode_need_bypass(cpudata))
+		static_branch_enable(&trbe_trigger_mode_bypass);
+
 	return;
 cpu_clear:
 	cpumask_clear_cpu(cpu, &drvdata->supported_cpus);

-- 
2.34.1



From leo.yan at arm.com  Mon Dec  1 03:22:06 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 01 Dec 2025 11:22:06 +0000
Subject: [PATCH 16/19] coresight: trbe: Support trigger mode
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
Message-ID: <20251201-trbe_buffer_refactor_v1-1-v1-16-7da32b076b28@arm.com>

The buffer currently operates in fill mode, where tracing stops when it
reaches the end of the buffer and a maintenance interrupt is raised.
However, due to IRQ latency, trace data may be lost during the window in
which tracing is halted but the program continues to run.

To mitigate the issue, this commit enables the trigger count to support
buffer maintenance without disabling tracing.  This is fulfilled with
two modes:

1) Set a trigger count as a watermark and use fill mode to prevent the
   buffer from being overwritten.  Once the count is decremented to
   zero, an interrupt is raised for buffer maintenance, but the hardware
   continues collecting trace data until limit.

          head            watermark tail
     +----+---------------+---------+-------+
     |$$$$|               |         |$$$$$$$|
     +----+---------------+---------+-------+
     base `---- count ----'         limit   base + nr_pages

     $$$ : Filled trace data

2) Use wrap mode so that tracing continues when reach the top of the
   buffer.  The trigger count is configured as "Stop on trigger" to
   guard the trace data not to be overwritten.

              watermark   tail      head
     +--------+-----------+---------+-------+
     |        |           |$$$$$$$$$|       |
     +--------+-----------+---------+-------+
     base                                   base + nr_pages
                                            limit

                                    `------->
     >-- counter ---------'

     $$$ : Filled trace data

The modes are selected by comparing the limit with the trigger position.

An extra TRBE_FAULT_ACT_TRIG state is introduced for fault action, it is
used to distinguish the trigger event from the WRAP event.

Signed-off-by: Leo Yan <leo.yan at arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 101 +++++++++++++++++++++------
 drivers/hwtracing/coresight/coresight-trbe.h |  14 ++++
 2 files changed, 94 insertions(+), 21 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 8390d0a8fe23d35945610df15f21751279ee37ee..0551ea9b4f8286c156e3c9c7ac94e2ecd3b9dc3f 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -48,6 +48,7 @@
 #define TRBE_TRACE_MIN_BUF_SIZE		64
 
 enum trbe_fault_action {
+	TRBE_FAULT_ACT_TRIG,
 	TRBE_FAULT_ACT_WRAP,
 	TRBE_FAULT_ACT_SPURIOUS,
 	TRBE_FAULT_ACT_FATAL,
@@ -67,6 +68,7 @@ struct trbe_buf {
 	unsigned long trbe_hw_base;
 	unsigned long trbe_limit;
 	unsigned long trbe_write;
+	unsigned long trbe_count;
 	int nr_pages;
 	void **pages;
 	bool snapshot;
@@ -478,6 +480,10 @@ static unsigned long __trbe_normal_offset(struct perf_output_handle *handle)
 	if (head < tail)
 		limit = round_down(tail, PAGE_SIZE);
 
+	/* If trigger mode is enabled, no need to use limit for watermark */
+	if (!static_branch_unlikely(&trbe_trigger_mode_bypass))
+		goto out;
+
 	/*
 	 * Wakeup may be arbitrarily far into the future. If it's not in the
 	 * current generation, either we'll wrap before hitting it, or it's
@@ -495,6 +501,7 @@ static unsigned long __trbe_normal_offset(struct perf_output_handle *handle)
 	if (handle->wakeup < (handle->head + handle->size) && head <= wakeup)
 		limit = min(limit, round_up(wakeup, PAGE_SIZE));
 
+out:
 	/*
 	 * There is a situation when this can happen i.e limit is before
 	 * the head and hence TRBE cannot be configured.
@@ -518,6 +525,39 @@ static unsigned long __trbe_normal_offset(struct perf_output_handle *handle)
 	return 0;
 }
 
+static u64 __trbe_normal_trigger_count(struct perf_output_handle *handle)
+{
+	struct trbe_buf *buf = etm_perf_sink_config(handle);
+	struct trbe_cpudata *cpudata = buf->cpudata;
+	u64 limit, head, wakeup;
+	u64 count = 0;
+
+	if (static_branch_unlikely(&trbe_trigger_mode_bypass))
+		return 0;
+
+	limit = buf->trbe_limit - buf->trbe_base;
+	head = PERF_IDX2OFF(handle->head, buf);
+	wakeup = PERF_IDX2OFF(handle->wakeup, buf);
+
+	/* Set the count to guard the end of free buffer after wrap around */
+	if (limit == buf->nr_pages * PAGE_SIZE && (head + handle->size) > limit)
+		count = handle->size;
+
+	/*
+	 * If the watermark is less than the limit, use the trigger count for
+	 * the watermark maintenance.
+	 */
+	if (handle->wakeup < (handle->head + handle->size) && head <= wakeup) {
+		u64 wakeup_count =
+			round_up(wakeup - head, cpudata->trbe_hw_align);
+
+		if (head + wakeup_count < limit)
+			count = wakeup_count;
+	}
+
+	return count;
+}
+
 static int trbe_normal_offset(struct perf_output_handle *handle)
 {
 	struct trbe_buf *buf = etm_perf_sink_config(handle);
@@ -542,6 +582,7 @@ static int trbe_normal_offset(struct perf_output_handle *handle)
 		return -ENOSPC;
 
 	buf->trbe_limit = buf->trbe_base + limit;
+	buf->trbe_count = __trbe_normal_trigger_count(handle);
 	return 0;
 }
 
@@ -594,24 +635,40 @@ static void set_trbe_limit_pointer_enabled(struct trbe_buf *buf)
 	trblimitr &= ~TRBLIMITR_EL1_TM_MASK;
 	trblimitr &= ~TRBLIMITR_EL1_LIMIT_MASK;
 
-	/*
-	 * Fill trace buffer mode is used here while configuring the
-	 * TRBE for trace capture. In this particular mode, the trace
-	 * collection is stopped and a maintenance interrupt is raised
-	 * when the current write pointer wraps. This pause in trace
-	 * collection gives the software an opportunity to capture the
-	 * trace data in the interrupt handler, before reconfiguring
-	 * the TRBE.
-	 */
-	trblimitr |= (TRBLIMITR_EL1_FM_FILL << TRBLIMITR_EL1_FM_SHIFT) &
-		     TRBLIMITR_EL1_FM_MASK;
+	if (!buf->trbe_count ||
+	    buf->trbe_write + buf->trbe_count == buf->trbe_limit) {
+		/*
+		 * Fill trace buffer mode is used here while configuring the
+		 * TRBE for trace capture. In this particular mode, the trace
+		 * collection is stopped and a maintenance interrupt is raised
+		 * when the current write pointer wraps. This pause in trace
+		 * collection gives the software an opportunity to capture the
+		 * trace data in the interrupt handler, before reconfiguring
+		 * the TRBE.
+		 */
+		trblimitr |= FIELD_PREP(TRBLIMITR_EL1_FM_MASK, TRBLIMITR_EL1_FM_FILL) |
+			     FIELD_PREP(TRBLIMITR_EL1_TM_MASK, TRBLIMITR_EL1_TM_IGNR);
+	} else if (buf->trbe_write + buf->trbe_count < buf->trbe_limit) {
+		/*
+		 * Fill mode is used here to stop trace collection and prevent
+		 * the buffer from being overwritten. Trigger mode continues
+		 * trace collection and raises a maintenance interrupt on a
+		 * trigger event, which acts as a watermark for notifying
+		 * userspace.
+		 */
+		trblimitr |= FIELD_PREP(TRBLIMITR_EL1_FM_MASK, TRBLIMITR_EL1_FM_FILL) |
+			     FIELD_PREP(TRBLIMITR_EL1_TM_MASK, TRBLIMITR_EL1_TM_IRQ);
+	} else if (buf->trbe_write + buf->trbe_count > buf->trbe_limit) {
+		/*
+		 * Wrap buffer mode continues trace collection and raises
+		 * maintenance interrupt on buffer wrap. Trigger mode stops
+		 * trace on trigger event to guard the buffer from being
+		 * overwritten.
+		 */
+		trblimitr |= FIELD_PREP(TRBLIMITR_EL1_FM_MASK, TRBLIMITR_EL1_FM_WRAP) |
+			     FIELD_PREP(TRBLIMITR_EL1_TM_MASK, TRBLIMITR_EL1_TM_STOP);
+	}
 
-	/*
-	 * Trigger mode is not used here while configuring the TRBE for
-	 * the trace capture. Hence just keep this in the ignore mode.
-	 */
-	trblimitr |= (TRBLIMITR_EL1_TM_IGNR << TRBLIMITR_EL1_TM_SHIFT) &
-		     TRBLIMITR_EL1_TM_MASK;
 	trblimitr |= (addr & PAGE_MASK);
 	set_trbe_enabled(buf->cpudata, trblimitr);
 }
@@ -623,6 +680,7 @@ static void trbe_enable_hw(struct trbe_buf *buf)
 	WARN_ON(buf->trbe_write >= buf->trbe_limit);
 	set_trbe_base_pointer(buf->trbe_hw_base);
 	set_trbe_write_pointer(buf->trbe_write);
+	set_trbe_trigger_count(buf->trbe_count);
 
 	/*
 	 * Synchronize all the register updates
@@ -639,8 +697,6 @@ static enum trbe_fault_action trbe_get_fault_act(struct perf_output_handle *hand
 	int ec = get_trbe_ec(trbsr);
 	int bsc = get_trbe_bsc(trbsr);
 
-	WARN_ON(is_trbe_running(trbsr));
-
 	if (is_trbe_abort(trbsr)) {
 		err_str = "External abort";
 		goto out_fatal;
@@ -672,8 +728,7 @@ static enum trbe_fault_action trbe_get_fault_act(struct perf_output_handle *hand
 	case TRBE_BSC_FILLED:
 		break;
 	case TRBE_BSC_TRIGGERED:
-		err_str = "Unexpected trigger status";
-		goto out_fatal;
+		break;
 	default:
 		err_str = "Unexpected buffer status code";
 		goto out_fatal;
@@ -692,6 +747,9 @@ static enum trbe_fault_action trbe_get_fault_act(struct perf_output_handle *hand
 	if (is_trbe_wrap(trbsr))
 		return TRBE_FAULT_ACT_WRAP;
 
+	if (is_trbe_trg(trbsr))
+		return TRBE_FAULT_ACT_TRIG;
+
 	return TRBE_FAULT_ACT_SPURIOUS;
 
 out_fatal:
@@ -1180,6 +1238,7 @@ static irqreturn_t arm_trbe_irq_handler(int irq, void *dev)
 		clr_trbe_status();
 
 	switch (act) {
+	case TRBE_FAULT_ACT_TRIG:
 	case TRBE_FAULT_ACT_WRAP:
 		truncated = !!trbe_handle_overflow(handle, act);
 		break;
diff --git a/drivers/hwtracing/coresight/coresight-trbe.h b/drivers/hwtracing/coresight/coresight-trbe.h
index d7f7cd763c0c7139cf322b7336ee563073e3bea0..4c65d164a946ec9860825e7564196745b60d730b 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.h
+++ b/drivers/hwtracing/coresight/coresight-trbe.h
@@ -114,6 +114,20 @@ static inline void set_trbe_write_pointer(unsigned long addr)
 	write_sysreg_s(addr, SYS_TRBPTR_EL1);
 }
 
+static inline void set_trbe_trigger_count(unsigned long count)
+{
+	u64 trbsr;
+
+	write_sysreg_s(count, SYS_TRBTRG_EL1);
+
+	/* TRBSR_EL1.TRG has been cleared in clr_trbe_status() */
+	if (!count)
+		return;
+
+	trbsr = read_sysreg_s(SYS_TRBSR_EL1);
+	write_sysreg_s(trbsr | TRBSR_EL1_TRG, SYS_TRBSR_EL1);
+}
+
 static inline unsigned long get_trbe_limit_pointer(void)
 {
 	u64 trblimitr = read_sysreg_s(SYS_TRBLIMITR_EL1);

-- 
2.34.1



From leo.yan at arm.com  Mon Dec  1 03:22:07 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 01 Dec 2025 11:22:07 +0000
Subject: [PATCH 17/19] coresight: trbe: Enable circle mode for snapshot
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
Message-ID: <20251201-trbe_buffer_refactor_v1-1-v1-17-7da32b076b28@arm.com>

A snapshot session captures trace data only when userspace receives a
signal and disables tracing. Before disabling, enable circle mode
instead of fill mode to avoid unnecessary interrupt handling.

Signed-off-by: Leo Yan <leo.yan at arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 0551ea9b4f8286c156e3c9c7ac94e2ecd3b9dc3f..ee9993d518d2a41f0d709b7d0690b2dfe0bef2d9 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -635,6 +635,12 @@ static void set_trbe_limit_pointer_enabled(struct trbe_buf *buf)
 	trblimitr &= ~TRBLIMITR_EL1_TM_MASK;
 	trblimitr &= ~TRBLIMITR_EL1_LIMIT_MASK;
 
+	if (buf->snapshot) {
+		trblimitr |= FIELD_PREP(TRBLIMITR_EL1_FM_MASK, TRBLIMITR_EL1_FM_CBUF) |
+			     FIELD_PREP(TRBLIMITR_EL1_TM_MASK, TRBLIMITR_EL1_TM_IGNR);
+		goto enable_trace_buf;
+	}
+
 	if (!buf->trbe_count ||
 	    buf->trbe_write + buf->trbe_count == buf->trbe_limit) {
 		/*
@@ -669,6 +675,7 @@ static void set_trbe_limit_pointer_enabled(struct trbe_buf *buf)
 			     FIELD_PREP(TRBLIMITR_EL1_TM_MASK, TRBLIMITR_EL1_TM_STOP);
 	}
 
+enable_trace_buf:
 	trblimitr |= (addr & PAGE_MASK);
 	set_trbe_enabled(buf->cpudata, trblimitr);
 }

-- 
2.34.1



From leo.yan at arm.com  Mon Dec  1 03:22:08 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 01 Dec 2025 11:22:08 +0000
Subject: [PATCH 18/19] coresight: trbe: Add kunit tests
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
Message-ID: <20251201-trbe_buffer_refactor_v1-1-v1-18-7da32b076b28@arm.com>

Add tests to verify the calculation of the limit and trigger count.

Because trigger mode can be disabled, provide two test suites: one with
trigger mode enabled and one with it disabled.

The cpudata structure is initialized by the test stub, so move its
definition into the header for including.

Signed-off-by: Leo Yan <leo.yan at arm.com>
---
 drivers/hwtracing/coresight/Kconfig                |   9 +
 drivers/hwtracing/coresight/Makefile               |   1 +
 .../coresight/coresight-trbe-kunit-tests.c         | 536 +++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-trbe.c       | 112 +----
 drivers/hwtracing/coresight/coresight-trbe.h       |  89 ++++
 5 files changed, 660 insertions(+), 87 deletions(-)

diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig
index 6a4239ebb582e95f0ebe8e9c8738a726f27f60a1..f5758563c0090141cdca67f16e7b7b32e7c75bb8 100644
--- a/drivers/hwtracing/coresight/Kconfig
+++ b/drivers/hwtracing/coresight/Kconfig
@@ -214,6 +214,15 @@ config CORESIGHT_TRBE
 	  To compile this driver as a module, choose M here: the module will be
 	  called coresight-trbe.
 
+config CORESIGHT_TRBE_KUNIT_TESTS
+	tristate "Enable Coresight TRBE unit tests"
+	depends on KUNIT
+	depends on CORESIGHT_TRBE
+	default KUNIT_ALL_TESTS
+	help
+	  Enable Coresight TRBE unit tests. Only useful for development and not
+	  intended for production.
+
 config ULTRASOC_SMB
 	tristate "Ultrasoc system memory buffer drivers"
 	depends on ACPI || COMPILE_TEST
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile
index ab16d06783a572ea1308dfb3a30c96df9e5ffdb7..f8961f6883d167bc2c4bca8008eceb08c3c3a0e9 100644
--- a/drivers/hwtracing/coresight/Makefile
+++ b/drivers/hwtracing/coresight/Makefile
@@ -57,3 +57,4 @@ obj-$(CONFIG_CORESIGHT_DUMMY) += coresight-dummy.o
 obj-$(CONFIG_CORESIGHT_CTCU) += coresight-ctcu.o
 coresight-ctcu-y := coresight-ctcu-core.o
 obj-$(CONFIG_CORESIGHT_KUNIT_TESTS) += coresight-kunit-tests.o
+obj-$(CONFIG_CORESIGHT_TRBE_KUNIT_TESTS) += coresight-trbe-kunit-tests.o
diff --git a/drivers/hwtracing/coresight/coresight-trbe-kunit-tests.c b/drivers/hwtracing/coresight/coresight-trbe-kunit-tests.c
new file mode 100644
index 0000000000000000000000000000000000000000..836f76dce155d533f9076e85dc97ba25221b7bbf
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-trbe-kunit-tests.c
@@ -0,0 +1,536 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <kunit/test.h>
+#include <kunit/device.h>
+#include <linux/coresight.h>
+
+#include "coresight-priv.h"
+#include "coresight-trbe.h"
+
+MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
+
+static void test_compute_offset(struct kunit *test)
+{
+	struct perf_output_handle handle = { 0 };
+	struct trbe_buf buf = { 0 };
+	struct trbe_cpudata cpudata = { .trbe_align = PAGE_SIZE };
+	unsigned long limit;
+
+	if (!static_branch_unlikely(&trbe_trigger_mode_bypass))
+		return;
+
+	cpudata.trbe_hw_align = 1;
+
+	buf.nr_pages = SZ_1M / SZ_4K;
+	buf.cpudata = &cpudata;
+
+	handle.rb = (void *)&buf;
+
+	/*
+	 * ### : Free space, $$$ : Filled space
+	 *
+	 * |################|################|
+	 * `head            `wakeup
+	 * `tail            `limit
+	 */
+	handle.head = 0;
+	handle.size = SZ_1M;
+	handle.wakeup = SZ_1M / 2;
+
+	limit = __trbe_normal_offset(&handle);
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M / 2);
+
+	/*
+	 * |################|################|
+	 * `head            `wakeup         `tail
+	 *                  `limit
+	 */
+	handle.head = 0;
+	handle.size = SZ_1M - 1;
+	handle.wakeup = SZ_1M / 2;
+
+	limit = __trbe_normal_offset(&handle);
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M / 2);
+
+	/*
+	 * |#################################|
+	 * `head                            `tail
+	 * `wakeup                         `limit
+	 */
+	handle.head = 0;
+	handle.size = SZ_1M - 1;
+	handle.wakeup = 0;
+
+	limit = __trbe_normal_offset(&handle);
+	KUNIT_ASSERT_EQ(test, limit, 0);
+
+	/*
+	 * |#################################|
+	 * `head                            `tail
+	 *                                   `wakeup
+	 *                                 `limit
+	 */
+	handle.head = 0;
+	handle.size = SZ_1M - 1;
+	handle.wakeup = SZ_1M;
+
+	limit = __trbe_normal_offset(&handle);
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M - SZ_4K);
+
+	/*
+	 * |$$$$$$$$$$$$$$$$|########|#######|
+	 *                  `head           `tail
+	 *                           `wakeup
+	 *                                 `limit
+	 */
+	handle.head = SZ_1M / 2;
+	handle.size = SZ_1M / 2 - 1;
+	handle.wakeup = SZ_1M * 3 / 4;
+
+	limit = __trbe_normal_offset(&handle);
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M * 3 / 4);
+
+	/*
+	 * |$$$$$$$$|$$$$$$$|################|
+	 *                  `head           `tail
+	 *          `wakeup
+	 *                                 `limit
+	 */
+	handle.head = SZ_1M / 2;
+	handle.size = SZ_1M / 2 - 1;
+	handle.wakeup = SZ_1M * 1 / 4;
+
+	limit = __trbe_normal_offset(&handle);
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M - SZ_4K);
+
+	/*
+	 * |$$$$$$$$$$$$$$$$|################|
+	 *                  `head           `tail
+	 *                                  `wakeup
+	 *                                 `limit
+	 */
+	handle.head = SZ_1M / 2;
+	handle.size = SZ_1M / 2 - 1;
+	handle.wakeup = SZ_1M - 1;
+
+	limit = __trbe_normal_offset(&handle);
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M - SZ_4K);
+
+	/*
+	 * |#########|$$$$$$$$$$|########|###|
+	 *           `tail      `head    `wakeup
+	 *                                   `limit
+	 */
+	handle.head = SZ_1M * 3 / 4;
+	handle.size = SZ_1M / 2;
+	handle.wakeup = handle.head + SZ_1M / 8;
+
+	limit = __trbe_normal_offset(&handle);
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M * 7 / 8);
+
+	/*
+	 * |####|####|$$$$$$$$$$|############|
+	 *           `tail      `head
+	 *      `wakeup
+	 *                                   `limit
+	 */
+	handle.head = SZ_1M * 3 / 4;
+	handle.size = SZ_1M / 2;
+	handle.wakeup = SZ_1M + SZ_1M / 8;
+
+	limit = __trbe_normal_offset(&handle);
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M);
+
+	/*
+	 * |#######|########|$$$$$$$$$$$$$$$$|
+	 * `head   `wakeup  `>tail
+	 *         `limit
+	 */
+	handle.head = SZ_1M;
+	handle.wakeup = SZ_1M + SZ_1M / 8;
+	handle.size = SZ_1M / 2;
+
+	limit = __trbe_normal_offset(&handle);
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M / 8);
+
+	/*
+	 * |#######|$$$$$$$$$$$$$$$$$|#######|
+	 *         `tail             `head
+	 *         `wakeup
+	 *                                   `limit
+	 */
+	handle.head = SZ_1M * 3 / 4;
+	handle.size = SZ_1M / 2;
+	handle.wakeup = SZ_1M + SZ_1M / 4;
+
+	limit = __trbe_normal_offset(&handle);
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M);
+
+	/*
+	 * |#######|$$$$$$$$|$$$$$$$$|#######|
+	 *         `tail    `wakeup  `head
+	 *                                   `limit
+	 */
+	handle.head = SZ_1M * 3 / 4;
+	handle.size = SZ_1M / 2;
+	handle.wakeup = SZ_1M + SZ_1M / 2;
+
+	limit = __trbe_normal_offset(&handle);
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M);
+
+	/*
+	 * |$$$$$$$|########|########|$$$$$$$|
+	 *         `head    `wakeup  `tail
+	 *                           `limit
+	 */
+	handle.head = SZ_1M / 4;
+	handle.size = SZ_1M / 2;
+	handle.wakeup = SZ_1M / 2;
+
+	limit = __trbe_normal_offset(&handle);
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M / 2);
+
+	/*
+	 * |$$$$$$$|#################|$$$$$$$|
+	 *         `head             `tail
+	 *                           `wakeup
+	 *                           `limit
+	 */
+	handle.head = SZ_1M / 4;
+	handle.size = SZ_1M / 2;
+	handle.wakeup = SZ_1M * 3 / 4;
+
+	limit = __trbe_normal_offset(&handle);
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M * 3 / 4);
+
+	/*
+	 * |$$$$$$$|#################|$$$$$$$|
+	 * `wakeup `head             `tail
+	 *                           `limit
+	 */
+	handle.head = SZ_1M / 4;
+	handle.size = SZ_1M / 2;
+	handle.wakeup = 0;
+
+	limit = __trbe_normal_offset(&handle);
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M * 3 / 4);
+
+	/*
+	 * |$$$$$$|$$$$$$$$$$$$$$$$$$$$$$$$$$|
+	 *        `head
+	 *        `tail
+	 */
+	handle.head = SZ_1M / 4;
+	handle.size = 0;
+
+	limit = __trbe_normal_offset(&handle);
+	KUNIT_ASSERT_EQ(test, limit, 0);
+
+	/*
+	 * |$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$|#$|
+	 *                                `head
+	 *                                  `tail
+	 */
+	handle.head = SZ_1M - SZ_1K * 2;
+	handle.size = SZ_1K;
+	handle.wakeup = 0;
+
+	limit = __trbe_normal_offset(&handle);
+	KUNIT_ASSERT_EQ(test, limit, 0);
+}
+
+static void test_compute_offset_and_counter(struct kunit *test)
+{
+	struct perf_output_handle handle = { 0 };
+	struct trbe_buf buf = { 0 };
+	struct trbe_cpudata cpudata = { .trbe_align = PAGE_SIZE };
+	unsigned long limit;
+	u64 count;
+
+	if (static_branch_unlikely(&trbe_trigger_mode_bypass))
+		return;
+
+	cpudata.trbe_hw_align = 1;
+
+	buf.nr_pages = SZ_1M / SZ_4K;
+	buf.cpudata = &cpudata;
+
+	handle.rb = (void *)&buf;
+
+	/*
+	 * ### : Free space, $$$ : Filled space
+	 *
+	 * |################|################|
+	 * `head            `wakeup          `limit
+	 * `tail
+	 * `----- count ----'
+	 */
+	handle.head = 0;
+	handle.size = SZ_1M;
+	handle.wakeup = SZ_1M / 2;
+
+	limit = __trbe_normal_offset(&handle);
+	buf.trbe_limit = limit;
+	count = __trbe_normal_trigger_count(&handle);
+
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M);
+	KUNIT_ASSERT_EQ(test, count, SZ_1M / 2);
+
+	/*
+	 * |################|################|
+	 * `head            `wakeup         `tail
+	 *                                 `limit
+	 * `----- count ----'
+	 */
+	handle.head = 0;
+	handle.size = SZ_1M - 1;
+	handle.wakeup = SZ_1M / 2;
+
+	limit = __trbe_normal_offset(&handle);
+	buf.trbe_limit = limit;
+	count = __trbe_normal_trigger_count(&handle);
+
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M - SZ_4K);
+	KUNIT_ASSERT_EQ(test, count, SZ_1M / 2);
+
+	/*
+	 * |#################################|
+	 * `head                            `tail
+	 * `wakeup                         `limit
+	 */
+	handle.head = 0;
+	handle.size = SZ_1M - 1;
+	handle.wakeup = 0;
+
+	limit = __trbe_normal_offset(&handle);
+	buf.trbe_limit = limit;
+	count = __trbe_normal_trigger_count(&handle);
+
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M - SZ_4K);
+	KUNIT_ASSERT_EQ(test, count, 0);
+
+	/*
+	 * |#################################|
+	 * `head                            `tail
+	 *                                   `wakeup
+	 *                                 `limit
+	 */
+	handle.head = 0;
+	handle.size = SZ_1M - 1;
+	handle.wakeup = SZ_1M;
+
+	limit = __trbe_normal_offset(&handle);
+	buf.trbe_limit = limit;
+	count = __trbe_normal_trigger_count(&handle);
+
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M - SZ_4K);
+	KUNIT_ASSERT_EQ(test, count, 0);
+
+	/*
+	 * |$$$$$$$$$$$$$$$$|########|#######|
+	 *                  `head           `tail
+	 *                           `wakeup
+	 *                                 `limit
+	 *                  [  count ]
+	 */
+	handle.head = SZ_1M / 2;
+	handle.size = SZ_1M / 2 - 1;
+	handle.wakeup = SZ_1M * 3 / 4;
+
+	limit = __trbe_normal_offset(&handle);
+	buf.trbe_limit = limit;
+	count = __trbe_normal_trigger_count(&handle);
+
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M - SZ_4K);
+	KUNIT_ASSERT_EQ(test, count, SZ_1M / 4);
+
+	/*
+	 * |$$$$$$$$|$$$$$$$|################|
+	 *                  `head           `tail
+	 *          `wakeup
+	 *                                 `limit
+	 */
+	handle.head = SZ_1M / 2;
+	handle.size = SZ_1M / 2 - 1;
+	handle.wakeup = SZ_1M * 1 / 4;
+
+	limit = __trbe_normal_offset(&handle);
+	buf.trbe_limit = limit;
+	count = __trbe_normal_trigger_count(&handle);
+
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M - SZ_4K);
+	KUNIT_ASSERT_EQ(test, count, 0);
+
+	/*
+	 * |$$$$$$$$$$$$$$$$|################|
+	 *                  `head           `tail
+	 *                                  `wakeup
+	 *                                 `limit
+	 */
+	handle.head = SZ_1M / 2;
+	handle.size = SZ_1M / 2 - 1;
+	handle.wakeup = SZ_1M - 1;
+
+	limit = __trbe_normal_offset(&handle);
+	buf.trbe_limit = limit;
+	count = __trbe_normal_trigger_count(&handle);
+
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M - SZ_4K);
+	KUNIT_ASSERT_EQ(test, count, 0);
+
+	/*
+	 * |#########|$$$$$$$$$$|########|###|
+	 *           `tail      `head    `wakeup
+	 *                                   `limit
+	 *                      [  count ]
+	 */
+	handle.head = SZ_1M * 3 / 4;
+	handle.size = SZ_1M / 2;
+	handle.wakeup = handle.head + SZ_1M / 8;
+
+	limit = __trbe_normal_offset(&handle);
+	buf.trbe_limit = limit;
+	count = __trbe_normal_trigger_count(&handle);
+
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M);
+	KUNIT_ASSERT_EQ(test, count, SZ_1M / 8);
+
+	/*
+	 * |####|####|$$$$$$$$$$|############|
+	 *           `tail      `head
+	 *      `wakeup
+	 *                                   `limit
+	 *                      [   count  >>>
+	 * >>>       ]
+	 */
+	handle.head = SZ_1M * 3 / 4;
+	handle.size = SZ_1M / 2;
+	handle.wakeup = SZ_1M + SZ_1M / 8;
+
+	limit = __trbe_normal_offset(&handle);
+	buf.trbe_limit = limit;
+	count = __trbe_normal_trigger_count(&handle);
+
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M);
+	KUNIT_ASSERT_EQ(test, count, SZ_1M / 2);
+
+	/*
+	 * |#######|########|$$$$$$$$$$$$$$$$|
+	 * `head   `wakeup  `>tail
+	 *                  `limit
+	 * [ count ]
+	 */
+	handle.head = SZ_1M;
+	handle.wakeup = SZ_1M + SZ_1M / 8;
+	handle.size = SZ_1M / 2;
+
+	limit = __trbe_normal_offset(&handle);
+	buf.trbe_limit = limit;
+	count = __trbe_normal_trigger_count(&handle);
+
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M / 2);
+	KUNIT_ASSERT_EQ(test, count, SZ_1M / 8);
+
+	/*
+	 * |#######|$$$$$$$$$$$$$$$$$|#######|
+	 *         `tail             `head
+	 *         `wakeup
+	 *                                   `limit
+	 *                           [ count >
+	 * >>>     ]
+	 */
+	handle.head = SZ_1M * 3 / 4;
+	handle.size = SZ_1M / 2;
+	handle.wakeup = SZ_1M + SZ_1M / 4;
+
+	limit = __trbe_normal_offset(&handle);
+	buf.trbe_limit = limit;
+	count = __trbe_normal_trigger_count(&handle);
+
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M);
+	KUNIT_ASSERT_EQ(test, count, SZ_1M / 2);
+
+	/*
+	 * |#######|$$$$$$$$|$$$$$$$$|#######|
+	 *         `tail    `wakeup  `head
+	 *                                   `limit
+	 *                           [ count >
+	 * >>>     ]
+	 */
+	handle.head = SZ_1M * 3 / 4;
+	handle.size = SZ_1M / 2;
+	handle.wakeup = SZ_1M + SZ_1M / 2;
+
+	limit = __trbe_normal_offset(&handle);
+	buf.trbe_limit = limit;
+	count = __trbe_normal_trigger_count(&handle);
+
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M);
+	KUNIT_ASSERT_EQ(test, count, SZ_1M / 2);
+
+	/*
+	 * |$$$$$$$|########|########|$$$$$$$|
+	 *         `head    `wakeup  `tail
+	 *                           `limit
+	 *         [ count  ]
+	 */
+	handle.head = SZ_1M / 4;
+	handle.size = SZ_1M / 2;
+	handle.wakeup = SZ_1M / 2;
+
+	limit = __trbe_normal_offset(&handle);
+	buf.trbe_limit = limit;
+	count = __trbe_normal_trigger_count(&handle);
+
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M * 3 / 4);
+	KUNIT_ASSERT_EQ(test, count, SZ_1M / 4);
+
+	/*
+	 * |$$$$$$$|#################|$$$$$$$|
+	 *         `head             `tail
+	 *                           `wakeup
+	 *                           `limit
+	 */
+	handle.head = SZ_1M / 4;
+	handle.size = SZ_1M / 2;
+	handle.wakeup = SZ_1M * 3 / 4;
+
+	limit = __trbe_normal_offset(&handle);
+	buf.trbe_limit = limit;
+	count = __trbe_normal_trigger_count(&handle);
+
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M * 3 / 4);
+	KUNIT_ASSERT_EQ(test, count, 0);
+
+	/*
+	 * |$$$$$$$|#################|$$$$$$$|
+	 * `wakeup `head             `tail
+	 *                           `limit
+	 */
+	handle.head = SZ_1M / 4;
+	handle.size = SZ_1M / 2;
+	handle.wakeup = 0;
+
+	limit = __trbe_normal_offset(&handle);
+	buf.trbe_limit = limit;
+	count = __trbe_normal_trigger_count(&handle);
+
+	KUNIT_ASSERT_EQ(test, limit, SZ_1M * 3 / 4);
+	KUNIT_ASSERT_EQ(test, count, 0);
+}
+
+static struct kunit_case coresight_trbe_testcases[] = {
+	KUNIT_CASE(test_compute_offset),
+	KUNIT_CASE(test_compute_offset_and_counter),
+	{}
+};
+
+static struct kunit_suite coresight_trbe_test_suite = {
+	.name = "coresight_trbe_test_suite",
+	.test_cases = coresight_trbe_testcases,
+};
+
+kunit_test_suites(&coresight_trbe_test_suite);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Leo Yan <leo.yan at arm.com>");
+MODULE_DESCRIPTION("Arm CoreSight TRBE KUnit tests");
diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index ee9993d518d2a41f0d709b7d0690b2dfe0bef2d9..25d42683ab74b55efa2e19a2d77ab8ae2d68d228 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -54,92 +54,12 @@ enum trbe_fault_action {
 	TRBE_FAULT_ACT_FATAL,
 };
 
-struct trbe_buf {
-	/*
-	 * Even though trbe_base represents vmap()
-	 * mapped allocated buffer's start address,
-	 * it's being as unsigned long for various
-	 * arithmetic and comparision operations &
-	 * also to be consistent with trbe_write &
-	 * trbe_limit sibling pointers.
-	 */
-	unsigned long trbe_base;
-	/* The base programmed into the TRBE */
-	unsigned long trbe_hw_base;
-	unsigned long trbe_limit;
-	unsigned long trbe_write;
-	unsigned long trbe_count;
-	int nr_pages;
-	void **pages;
-	bool snapshot;
-	struct trbe_cpudata *cpudata;
-};
-
-/*
- * TRBE erratum list
- *
- * The errata are defined in arm64 generic cpu_errata framework.
- * Since the errata work arounds could be applied individually
- * to the affected CPUs inside the TRBE driver, we need to know if
- * a given CPU is affected by the erratum. Unlike the other erratum
- * work arounds, TRBE driver needs to check multiple times during
- * a trace session. Thus we need a quicker access to per-CPU
- * errata and not issue costly this_cpu_has_cap() everytime.
- * We keep a set of the affected errata in trbe_cpudata, per TRBE.
- *
- * We rely on the corresponding cpucaps to be defined for a given
- * TRBE erratum. We map the given cpucap into a TRBE internal number
- * to make the tracking of the errata lean.
- *
- * This helps in :
- *   - Not duplicating the detection logic
- *   - Streamlined detection of erratum across the system
- */
-#define TRBE_WORKAROUND_OVERWRITE_FILL_MODE	0
-#define TRBE_WORKAROUND_WRITE_OUT_OF_RANGE	1
-#define TRBE_NEEDS_DRAIN_AFTER_DISABLE		2
-#define TRBE_NEEDS_CTXT_SYNC_AFTER_ENABLE	3
-#define TRBE_IS_BROKEN				4
-
-static int trbe_errata_cpucaps[] = {
-	[TRBE_WORKAROUND_OVERWRITE_FILL_MODE] = ARM64_WORKAROUND_TRBE_OVERWRITE_FILL_MODE,
-	[TRBE_WORKAROUND_WRITE_OUT_OF_RANGE] = ARM64_WORKAROUND_TRBE_WRITE_OUT_OF_RANGE,
-	[TRBE_NEEDS_DRAIN_AFTER_DISABLE] = ARM64_WORKAROUND_2064142,
-	[TRBE_NEEDS_CTXT_SYNC_AFTER_ENABLE] = ARM64_WORKAROUND_2038923,
-	[TRBE_IS_BROKEN] = ARM64_WORKAROUND_1902691,
-	-1,		/* Sentinel, must be the last entry */
-};
-
-/* The total number of listed errata in trbe_errata_cpucaps */
-#define TRBE_ERRATA_MAX			(ARRAY_SIZE(trbe_errata_cpucaps) - 1)
-
 /*
  * Safe limit for the number of bytes that may be overwritten
  * when ARM64_WORKAROUND_TRBE_OVERWRITE_FILL_MODE is triggered.
  */
 #define TRBE_WORKAROUND_OVERWRITE_FILL_MODE_SKIP_BYTES	256
 
-/*
- * struct trbe_cpudata: TRBE instance specific data
- * @trbe_flag		- TRBE dirty/access flag support
- * @trbe_hw_align	- Actual TRBE alignment required for TRBPTR_EL1.
- * @trbe_align		- Software alignment used for the TRBPTR_EL1.
- * @cpu			- CPU this TRBE belongs to.
- * @mode		- Mode of current operation. (perf/disabled)
- * @drvdata		- TRBE specific drvdata
- * @errata		- Bit map for the errata on this TRBE.
- */
-struct trbe_cpudata {
-	bool trbe_flag;
-	u64 trbe_hw_align;
-	u64 trbe_align;
-	int cpu;
-	enum cs_mode mode;
-	struct trbe_buf *buf;
-	struct trbe_drvdata *drvdata;
-	DECLARE_BITMAP(errata, TRBE_ERRATA_MAX);
-};
-
 struct trbe_drvdata {
 	struct trbe_cpudata __percpu *cpudata;
 	struct perf_output_handle * __percpu *handle;
@@ -150,7 +70,8 @@ struct trbe_drvdata {
 	struct platform_device *pdev;
 };
 
-DEFINE_STATIC_KEY_FALSE(trbe_trigger_mode_bypass);
+VISIBLE_IF_KUNIT DEFINE_STATIC_KEY_FALSE(trbe_trigger_mode_bypass);
+EXPORT_SYMBOL_IF_KUNIT(trbe_trigger_mode_bypass);
 
 #define trbe_trigger_mode_need_bypass(cpudata)		\
 	(trbe_may_overwrite_in_fill_mode((cpudata)) ||	\
@@ -333,8 +254,17 @@ static void __trbe_pad_buf(struct trbe_buf *buf, u64 offset, int len)
 
 static void trbe_pad_buf(struct perf_output_handle *handle, int len)
 {
-	struct trbe_buf *buf = etm_perf_sink_config(handle);
-	u64 head = PERF_IDX2OFF(handle->head, buf);
+	struct trbe_buf *buf;
+	u64 head;
+
+	if (kunit_get_current_test()) {
+		handle->head += len;
+		handle->size -= len;
+		return;
+	}
+
+	buf = etm_perf_sink_config(handle);
+	head = PERF_IDX2OFF(handle->head, buf);
 
 	__trbe_pad_buf(buf, head, len);
 	if (!buf->snapshot)
@@ -383,9 +313,11 @@ static u64 trbe_min_trace_buf_size(struct perf_output_handle *handle)
  * %%%% - Free area, disabled, trace will not be written
  * ==== - Free area, padded with ETE_IGNORE_PACKET, trace will be skipped
  */
-static unsigned long __trbe_normal_offset(struct perf_output_handle *handle)
+VISIBLE_IF_KUNIT
+unsigned long __trbe_normal_offset(struct perf_output_handle *handle)
 {
-	struct trbe_buf *buf = etm_perf_sink_config(handle);
+	struct trbe_buf *buf =
+		kunit_get_current_test() ? handle->rb : etm_perf_sink_config(handle);
 	struct trbe_cpudata *cpudata = buf->cpudata;
 	const u64 bufsize = buf->nr_pages * PAGE_SIZE;
 	u64 limit = bufsize;
@@ -525,9 +457,13 @@ static unsigned long __trbe_normal_offset(struct perf_output_handle *handle)
 	return 0;
 }
 
-static u64 __trbe_normal_trigger_count(struct perf_output_handle *handle)
+EXPORT_SYMBOL_IF_KUNIT(__trbe_normal_offset);
+
+VISIBLE_IF_KUNIT
+u64 __trbe_normal_trigger_count(struct perf_output_handle *handle)
 {
-	struct trbe_buf *buf = etm_perf_sink_config(handle);
+	struct trbe_buf *buf =
+		kunit_get_current_test() ? handle->rb : etm_perf_sink_config(handle);
 	struct trbe_cpudata *cpudata = buf->cpudata;
 	u64 limit, head, wakeup;
 	u64 count = 0;
@@ -558,6 +494,8 @@ static u64 __trbe_normal_trigger_count(struct perf_output_handle *handle)
 	return count;
 }
 
+EXPORT_SYMBOL_IF_KUNIT(__trbe_normal_trigger_count);
+
 static int trbe_normal_offset(struct perf_output_handle *handle)
 {
 	struct trbe_buf *buf = etm_perf_sink_config(handle);
diff --git a/drivers/hwtracing/coresight/coresight-trbe.h b/drivers/hwtracing/coresight/coresight-trbe.h
index 4c65d164a946ec9860825e7564196745b60d730b..8f90836b5f71d44213699ec1915d59864863a4db 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.h
+++ b/drivers/hwtracing/coresight/coresight-trbe.h
@@ -17,8 +17,91 @@
 #include <linux/platform_device.h>
 #include <linux/smp.h>
 
+#include <kunit/test-bug.h>
+#include <kunit/visibility.h>
+
 #include "coresight-etm-perf.h"
 
+struct trbe_buf {
+	/*
+	 * Even though trbe_base represents vmap()
+	 * mapped allocated buffer's start address,
+	 * it's being as unsigned long for various
+	 * arithmetic and comparision operations &
+	 * also to be consistent with trbe_write &
+	 * trbe_limit sibling pointers.
+	 */
+	unsigned long trbe_base;
+	/* The base programmed into the TRBE */
+	unsigned long trbe_hw_base;
+	unsigned long trbe_limit;
+	unsigned long trbe_write;
+	unsigned long trbe_count;
+	int nr_pages;
+	void **pages;
+	bool snapshot;
+	struct trbe_cpudata *cpudata;
+};
+
+/*
+ * TRBE erratum list
+ *
+ * The errata are defined in arm64 generic cpu_errata framework.
+ * Since the errata work arounds could be applied individually
+ * to the affected CPUs inside the TRBE driver, we need to know if
+ * a given CPU is affected by the erratum. Unlike the other erratum
+ * work arounds, TRBE driver needs to check multiple times during
+ * a trace session. Thus we need a quicker access to per-CPU
+ * errata and not issue costly this_cpu_has_cap() everytime.
+ * We keep a set of the affected errata in trbe_cpudata, per TRBE.
+ *
+ * We rely on the corresponding cpucaps to be defined for a given
+ * TRBE erratum. We map the given cpucap into a TRBE internal number
+ * to make the tracking of the errata lean.
+ *
+ * This helps in :
+ *   - Not duplicating the detection logic
+ *   - Streamlined detection of erratum across the system
+ */
+#define TRBE_WORKAROUND_OVERWRITE_FILL_MODE	0
+#define TRBE_WORKAROUND_WRITE_OUT_OF_RANGE	1
+#define TRBE_NEEDS_DRAIN_AFTER_DISABLE		2
+#define TRBE_NEEDS_CTXT_SYNC_AFTER_ENABLE	3
+#define TRBE_IS_BROKEN				4
+
+static int trbe_errata_cpucaps[] = {
+	[TRBE_WORKAROUND_OVERWRITE_FILL_MODE] = ARM64_WORKAROUND_TRBE_OVERWRITE_FILL_MODE,
+	[TRBE_WORKAROUND_WRITE_OUT_OF_RANGE] = ARM64_WORKAROUND_TRBE_WRITE_OUT_OF_RANGE,
+	[TRBE_NEEDS_DRAIN_AFTER_DISABLE] = ARM64_WORKAROUND_2064142,
+	[TRBE_NEEDS_CTXT_SYNC_AFTER_ENABLE] = ARM64_WORKAROUND_2038923,
+	[TRBE_IS_BROKEN] = ARM64_WORKAROUND_1902691,
+	-1,		/* Sentinel, must be the last entry */
+};
+
+/* The total number of listed errata in trbe_errata_cpucaps */
+#define TRBE_ERRATA_MAX			(ARRAY_SIZE(trbe_errata_cpucaps) - 1)
+
+/*
+ * struct trbe_cpudata: TRBE instance specific data
+ * @trbe_flag		- TRBE dirty/access flag support
+ * @trbe_hw_align	- Actual TRBE alignment required for TRBPTR_EL1.
+ * @trbe_align		- Software alignment used for the TRBPTR_EL1.
+ * @cpu			- CPU this TRBE belongs to.
+ * @mode		- Mode of current operation. (perf/disabled)
+ * @drvdata		- TRBE specific drvdata
+ * @errata		- Bit map for the errata on this TRBE.
+ */
+struct trbe_cpudata {
+	bool trbe_flag;
+	u64 trbe_hw_align;
+	u64 trbe_align;
+	int cpu;
+	enum cs_mode mode;
+	struct trbe_buf *buf;
+	struct trbe_drvdata *drvdata;
+	DECLARE_BITMAP(errata, TRBE_ERRATA_MAX);
+};
+
 static inline bool is_trbe_available(void)
 {
 	u64 aa64dfr0 = read_sysreg_s(SYS_ID_AA64DFR0_EL1);
@@ -153,3 +236,9 @@ static inline void set_trbe_base_pointer(unsigned long addr)
 	WARN_ON(!IS_ALIGNED(addr, PAGE_SIZE));
 	write_sysreg_s(addr, SYS_TRBBASER_EL1);
 }
+
+#if IS_ENABLED(CONFIG_KUNIT)
+DECLARE_STATIC_KEY_FALSE(trbe_trigger_mode_bypass);
+unsigned long __trbe_normal_offset(struct perf_output_handle *handle);
+u64 __trbe_normal_trigger_count(struct perf_output_handle *handle);
+#endif

-- 
2.34.1



From leo.yan at arm.com  Mon Dec  1 03:22:09 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 01 Dec 2025 11:22:09 +0000
Subject: [PATCH 19/19] perf: cs-etm: Set watermark for AUX trace
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
Message-ID: <20251201-trbe_buffer_refactor_v1-1-v1-19-7da32b076b28@arm.com>

The default watermark is half of the total buffer size. In many cases,
the tool can not be notified with sufficient free space, especially when
profiling with small AUX buffer (e.g., 64KiB).

Setting watermark to quarter of the buffer to notifies the tool to read
data earlier and prevents the data loss.

Signed-off-by: Leo Yan <leo.yan at arm.com>
---
 tools/perf/arch/arm/util/cs-etm.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
index ea891d12f8f40beebf8dee1d3db71cad701f5666..649b8b0d0f92b4af45fb97db9da3c5ccf24a978b 100644
--- a/tools/perf/arch/arm/util/cs-etm.c
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -424,6 +424,13 @@ static int cs_etm_recording_options(struct auxtrace_record *itr,
 		pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME,
 			  opts->auxtrace_snapshot_size);
 
+	if (!opts->auxtrace_snapshot_mode && !opts->auxtrace_sample_mode) {
+		size_t aw = opts->auxtrace_mmap_pages * (size_t)page_size / 4;
+		u32 aux_watermark = aw > UINT_MAX ? UINT_MAX : aw;
+
+		cs_etm_evsel->core.attr.aux_watermark = aux_watermark;
+	}
+
 	/*
 	 * To obtain the auxtrace buffer file descriptor, the auxtrace
 	 * event must come first.

-- 
2.34.1



From alchark at gmail.com  Mon Dec  1 03:35:38 2025
From: alchark at gmail.com (Alexey Charkov)
Date: Mon, 01 Dec 2025 15:35:38 +0400
Subject: [PATCH v2] arm64: dts: rockchip: enable UFS controller on
 FriendlyElec NanoPi M5
Message-ID: <20251201-nanopi-m5-ufs-v2-1-ece9c0ee17c4@gmail.com>

The NanoPi M5 board supports pluggable UFS modules using the UFSHC
inside its Rockchip RK3576 SoC.

Enable the respective devicetree node and add its supply regulators.

Link: https://wiki.friendlyelec.com/wiki/images/9/97/NanoPi_M5_LP5_2411_SCH.pdf
Signed-off-by: Alexey Charkov <alchark at gmail.com>
---
Changes in v2:
- Describe UFS supply regulators
- Add link to schematic
- Link to v1: https://lore.kernel.org/r/20251127-nanopi-m5-ufs-v1-1-0d28d157712c at gmail.com
---
 arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts | 27 +++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts b/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts
index cce34c541f7c..4f2930cff70a 100644
--- a/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts
@@ -110,6 +110,24 @@ vcc12v_dcin: regulator-vcc12v-dcin {
 		regulator-name = "vcc12v_dcin";
 	};
 
+	vcc1v2_ufs_vccq: regulator-vcc1v2-ufs-vccq {
+		compatible = "regulator-fixed";
+		regulator-min-microvolt = <1200000>;
+		regulator-max-microvolt = <1200000>;
+		regulator-name = "vcc1v2_ufs_vccq";
+		vin-supply = <&vcc5v0_sys_s5>;
+		en-supply = <&vcc_3v3_s3>;
+	};
+
+	vcc1v8_ufs_vccq2: regulator-vcc1v8-ufs-vccq2 {
+		compatible = "regulator-fixed";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-name = "vcc1v8_ufs_vccq2";
+		vin-supply = <&vcc_1v8_s3>;
+		en-supply = <&vdda_1v2_s0>;
+	};
+
 	vcc3v3_m2_keym: regulator-vcc3v3-m2-keym {
 		compatible = "regulator-fixed";
 		enable-active-high;
@@ -906,6 +924,15 @@ &uart0 {
 	status = "okay";
 };
 
+&ufshc {
+	vcc-supply = <&vcc_3v3_s3>;
+	vccq-supply = <&vcc1v2_ufs_vccq>;
+	vccq2-supply = <&vcc1v8_ufs_vccq2>;
+	vdd-hba-supply = <&vdda_1v2_s0>;
+
+	status = "okay";
+};
+
 &usbdp_phy {
 	status = "okay";
 };

---
base-commit: 7d31f578f3230f3b7b33b0930b08f9afd8429817
change-id: 20251127-nanopi-m5-ufs-52f2c5070167

Best regards,
-- 
Alexey Charkov <alchark at gmail.com>



From leitao at debian.org  Mon Dec  1 03:41:08 2025
From: leitao at debian.org (Breno Leitao)
Date: Mon, 1 Dec 2025 03:41:08 -0800
Subject: [PATCH v2] arm64: kernel: initialize missing kexec_buf->random
 field
In-Reply-To: <20251201105118.2786335-1-yeoreum.yun@arm.com>
References: <20251201105118.2786335-1-yeoreum.yun@arm.com>
Message-ID: <guxpoj5tie3qunqn5vsqbc5mtmcq5a77acbwl6wmdbyxf7gjls@m2dlxkiiysl4>

On Mon, Dec 01, 2025 at 10:51:18AM +0000, Yeoreum Yun wrote:
> Commit bf454ec31add ("kexec_file: allow to place kexec_buf randomly")
> introduced the kexec_buf->random field to enable random placement of
> kexec_buf.
> 
> However, this field was never properly initialized for kexec images
> that do not need to be placed randomly, leading to the following UBSAN
> warning:
> 
> [  +0.364528] ------------[ cut here ]------------
> [  +0.000019] UBSAN: invalid-load in ./include/linux/kexec.h:210:12
> [  +0.000131] load of value 2 is not a valid value for type 'bool' (aka '_Bool')
> [  +0.000003] CPU: 4 UID: 0 PID: 927 Comm: kexec Not tainted 6.18.0-rc7+ #3 PREEMPT(full)
> [  +0.000002] Hardware name: QEMU QEMU Virtual Machine, BIOS 0.0.0 02/06/2015
> [  +0.000000] Call trace:
> [  +0.000001]  show_stack+0x24/0x40 (C)
> [  +0.000006]  __dump_stack+0x28/0x48
> [  +0.000002]  dump_stack_lvl+0x7c/0xb0
> [  +0.000002]  dump_stack+0x18/0x34
> [  +0.000001]  ubsan_epilogue+0x10/0x50
> [  +0.000002]  __ubsan_handle_load_invalid_value+0xc8/0xd0
> [  +0.000003]  locate_mem_hole_callback+0x28c/0x2a0
> [  +0.000003]  kexec_locate_mem_hole+0xf4/0x2f0
> [  +0.000001]  kexec_add_buffer+0xa8/0x178
> [  +0.000002]  image_load+0xf0/0x258
> [  +0.000001]  __arm64_sys_kexec_file_load+0x510/0x718
> [  +0.000002]  invoke_syscall+0x68/0xe8
> [  +0.000001]  el0_svc_common+0xb0/0xf8
> [  +0.000002]  do_el0_svc+0x28/0x48
> [  +0.000001]  el0_svc+0x40/0xe8
> [  +0.000002]  el0t_64_sync_handler+0x84/0x140
> [  +0.000002]  el0t_64_sync+0x1bc/0x1c0
> 
> To address this, initialise kexec_buf->random field properly.
> 
> Fixes: bf454ec31add ("kexec_file: allow to place kexec_buf randomly")
> Suggested-by: Breno Leitao <leitao at debian.org>
> Cc: <stable at vger.kernel.org>
> Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>

Reviewed-by: Breno Leitao <leitao at debian.org>

Thanks for the fix,
--breno


From mani at kernel.org  Mon Dec  1 03:51:33 2025
From: mani at kernel.org (Manivannan Sadhasivam)
Date: Mon, 1 Dec 2025 17:21:33 +0530
Subject: [PATCH v9 4/4] PCI: dwc: Support ECAM mechanism by enabling iATU
 'CFG Shift Feature'
In-Reply-To: <alpine.DEB.2.21.2511290428340.36486@angie.orcam.me.uk>
References: <20250909-controller-dwc-ecam-v9-0-7d5b651840dd@kernel.org>
 <20250909-controller-dwc-ecam-v9-4-7d5b651840dd@kernel.org>
 <alpine.DEB.2.21.2511280256260.36486@angie.orcam.me.uk>
 <c7aea2b3-6984-40f5-8234-14d265dabefc@oss.qualcomm.com>
 <alpine.DEB.2.21.2511280755440.36486@angie.orcam.me.uk>
 <cabf4c20-095b-4579-adc1-146a566b19b9@oss.qualcomm.com>
 <alpine.DEB.2.21.2511281714030.36486@angie.orcam.me.uk>
 <a4c6d47f-28b5-40d3-bc82-10aeb14f8e78@oss.qualcomm.com>
 <alpine.DEB.2.21.2511290428340.36486@angie.orcam.me.uk>
Message-ID: <h7pgm3lqolm53sb4wrcpcurk4ghz4tulqnr7vgd7rzxy4hscue@jcn5tepevlwl>

On Sat, Nov 29, 2025 at 06:04:24AM +0000, Maciej W. Rozycki wrote:
> On Sat, 29 Nov 2025, Krishna Chaitanya Chundru wrote:
> 
> > > > Hi Maciej, Can you try attached patch and let me know if that is helping
> > > > you
> > > > or not. - Krishna Chaitanya.
> > >   No change, it's still broken, sorry.
> > HI Maciej,
> > For the previous patch can you apply this diff and share me dmesg o/p
> 
>  Your patch came though garbled, likely due to:
> 
> Content-Type: text/plain; charset=UTF-8; format=flowed
> 
> Please refer Documentation/process/email-clients.rst and reconfigure your 
> e-mail client if possible.
> 
>  Regardless, I've fixed it up by hand and the only difference in the log, 
> except for usual noise which I removed, is this:
> 
> --- dmesg-bad.log	2025-11-28 03:47:29.582049781 +0100
> +++ dmesg-debug.log	2025-11-29 05:41:23.384645926 +0100
> @@ -164,6 +164,8 @@
>  fu740-pcie e00000000.pcie: ECAM at [mem 0xdf0000000-0xdffffffff] for [bus 00-ff]
>  fu740-pcie e00000000.pcie: Using 256 MSI vectors
>  fu740-pcie e00000000.pcie: iATU: unroll T, 8 ob, 8 ib, align 4K, limit 4096G
> +fu740-pcie e00000000.pcie: Current iATU OB index 2
> +fu740-pcie e00000000.pcie: Current iATU OB index 4
>  fu740-pcie e00000000.pcie: cap_exp at 70
>  fu740-pcie e00000000.pcie: PCIe Gen.1 x8 link up
>  fu740-pcie e00000000.pcie: changing speed back to original
> 
> I've attached a full copy of the debug log too.  I hope this helps you 
> narrow the issue down or otherwise let me know what to try next.
> 
>  NB I note that code you've been poking at only refers resources of the 
> IORESOURCE_MEM type.  What about IORESOURCE_IO, which seems more relevant 
> here?
> 
>  Also as a quick check I've now reconfigured the defxx driver for PCI port 
> I/O (which is a one-liner; the mapping used to be selectable by hand, but 
> distributions got it wrong for systems w/o PCI port I/O, so I switched the 
> driver to an automatic choice a few years ago, but the logic remains):
> 
> # cat /proc/ioports
> 00000000-0000ffff : pcie at e00000000
>   00001000-00002fff : PCI Bus 0000:01
>     00001000-00002fff : PCI Bus 0000:02
>       00001000-00002fff : PCI Bus 0000:05
>         00001000-00002fff : PCI Bus 0000:06
>           00001000-00001fff : PCI Bus 0000:07
>           00001000-00001007 : 0000:07:00.0
>           00001000-00001002 : parport0
>           00001003-00001007 : parport0
>           00001008-0000100b : 0000:07:00.0
>           00001008-0000100a : parport0
>           00002000-00002fff : PCI Bus 0000:08
>           00002000-00002fff : PCI Bus 0000:09
>           00002000-000020ff : 0000:09:01.0
>           00002100-0000217f : 0000:09:02.0
>           00002100-0000217f : defxx
> # 
> 
> and:
> 
> defxx 0000:09:02.0: assign IRQ: got 40
> defxx: v1.12 2021/03/10  Lawrence V. Stefani and others
> defxx 0000:09:02.0: enabling device (0000 -> 0003)
> defxx 0000:09:02.0: enabling bus mastering
> 0000:09:02.0: DEFPA at I/O addr = 0x2100, IRQ = 40, Hardware addr = 00-60-6d-xx-xx-xx
> 0000:09:02.0: registered as fddi0
> 
> (as at commit 4660e50cf818) and likewise it has stopped working here from 
> commit 0da48c5b2fa7 onwards:
> 
> defxx 0000:09:02.0: assign IRQ: got 40
> defxx: v1.12 2021/03/10  Lawrence V. Stefani and others
> defxx 0000:09:02.0: enabling device (0000 -> 0003)
> defxx 0000:09:02.0: enabling bus mastering
> 0000:09:02.0: Could not read adapter factory MAC address!
> 
> So it's definitely nothing specific to the parport driver, but rather a 
> general issue with PCI/e port I/O not working anymore.  I do hope these 
> observations will let you address the issue now.  You might be able to 
> reproduce it with hardware you have available even.
> 

Yes, looks like the I/O port access is not working with the CFG Shift feature.
The spec says that both I/O and MEM TLPs should be handled by this feature, so
we are currently unsure why MEM works, but not I/O.

The issue you reported with parport_pc driver is that the driver gets probed,
but it fails to detect the parallel ports on the device. More precisely, it
fails due to the parport_SPP_supported() check in drivers/parport/parport_pc.c.
This function performs some read/write checks to make sure that the port exists,
but most likely the read value doesn't match the written one. And since there is
no log printed in this function, it just failed silently.

We will check why I/O access fails with ECAM mode and revert back asap. Since
the merge window is now open, it becomes difficult to revert the CFG shift
feature cleanly. The timing of the report also made it difficult to fix the
issue in v6.18. Hopefully, we can backport the fix once we identify the culprit.

Sorry for the inconvenience!

- Mani

-- 
????????? ????????


From devnull+maudspierings.gocontroll.com at kernel.org  Mon Dec  1 03:53:19 2025
From: devnull+maudspierings.gocontroll.com at kernel.org (Maud Spierings via B4 Relay)
Date: Mon, 01 Dec 2025 12:53:19 +0100
Subject: [PATCH v6 0/4] backlight: add new max25014 backlight driver
Message-ID: <20251201-max25014-v6-0-88e3ac8112ff@gocontroll.com>

The Maxim MAX25014 is an automotive grade backlight driver IC. Its
datasheet can be found at [1].

With its integrated boost controller, it can power 4 channels (led
strings) and has a number of different modes using pwm and or i2c.
Currently implemented is only i2c control.

link: https://www.analog.com/media/en/technical-documentation/data-sheets/MAX25014.pdf [1]

Signed-off-by: Maud Spierings <maudspierings at gocontroll.com>
---
Changes in v6:
- fixup changes in v4 where default brightness handling was changed but
  not noted
- remove leftover comment about initializing brightness
- use BIT definitions for fields in the DIAG register
- apply reverse christmas tree initialization of local variables
- remove !=0 from checks, just check if (ret)
- remove > 0 from checks, just check if (val)
- use dev_err_probe() more
- set enable gpio high in the get() instead of seperately calling set()
- change usleep_range() to fsleep()
- remove null checks when setting gpio value
- get regular regulator, not optional to avoid further NULL checks in
  case none is provided
- introduce max25014_initial_power_state() to check if the bootloader
  has already initialized the backlight and to correctly set props.power
- squash max25014_register_control() into max25014_update_status()
- in max25014_configure() perform extra checking on the DISABLE register
  now that the state from the bootloader is taken into account
- Link to v5: https://lore.kernel.org/r/20251107-max25014-v5-0-9a6aa57306bf at gocontroll.com

Changes in v5:
- moved comment about current functions of the driver to the actual
  comment section of the commit
- fixed the led at 0 property, regex patternProperty is not needed as of
  now
- added extra clarification about the ISET field/register
- moved #address-cells and #size-cells to the correct location
- remove leftover default-brightness in backlight nodes
- Link to v4: https://lore.kernel.org/r/20251009-max25014-v4-0-6adb2a0aa35f at gocontroll.com

Changes in v4:
- remove setting default brightness, let backlight core take care of it
- use a led node to describe the backlight
- use led-sources to enable specific channels
- also wait 2ms when there is a supply but no enable
- change dev_warn() to dev_err() in error path in max25014_check_errors()
- set backlight_properties.scale to BACKLIGHT_SCALE_LINEAR
- rebase latest next
- add address-cells and size-cells to i2c4 in av101hdt-a10.dtso
- Link to v3: https://lore.kernel.org/r/20250911-max25014-v3-0-d03f4eba375e at gocontroll.com

Changes in v3:
- fixed commit message type intgrated -> integrated
- added maximum and description to maxim,iset-property
- dropped unused labels and pinctrl in bindings example
- put the compatible first in the bindings example and dts
- removed brackets around defines
- removed the leftover pdata struct field
- removed the initial_brightness struct field
- Link to v2: https://lore.kernel.org/r/20250819-max25014-v2-0-5fd7aeb141ea at gocontroll.com

Changes in v2:
- Remove leftover unused property from the bindings example
- Complete the bindings example with all properties
- Remove some double info from the maxim,iset property
- Remove platform_data header, fold its data into the max25014 struct
- Don't force defines to be unsigned
- Remove stray struct max25014 declaration
- Remove chipname and device from the max25014 struct
- Inline the max25014_backlight_register() and strings_mask() functions
- Remove CONFIG_OF ifdef
- Link to v1: https://lore.kernel.org/r/20250725-max25014-v1-0-0e8cce92078e at gocontroll.com

---
Maud Spierings (4):
      dt-bindings: backlight: Add max25014 support
      backlight: add max25014atg backlight
      arm64: dts: freescale: moduline-display-av101hdt-a10: add backlight
      arm64: dts: freescale: moduline-display-av123z7m-n17: add backlight

 .../bindings/leds/backlight/maxim,max25014.yaml    | 107 ++++++
 MAINTAINERS                                        |   6 +
 ...x8p-ml81-moduline-display-106-av101hdt-a10.dtso |  30 ++
 ...x8p-ml81-moduline-display-106-av123z7m-n17.dtso |  25 +-
 drivers/video/backlight/Kconfig                    |   7 +
 drivers/video/backlight/Makefile                   |   1 +
 drivers/video/backlight/max25014.c                 | 419 +++++++++++++++++++++
 7 files changed, 594 insertions(+), 1 deletion(-)
---
base-commit: 9c0826a5d9aa4d52206dd89976858457a2a8a7ed
change-id: 20250626-max25014-4207591e1af5

Best regards,
-- 
Maud Spierings <maudspierings at gocontroll.com>




From devnull+maudspierings.gocontroll.com at kernel.org  Mon Dec  1 03:53:20 2025
From: devnull+maudspierings.gocontroll.com at kernel.org (Maud Spierings via B4 Relay)
Date: Mon, 01 Dec 2025 12:53:20 +0100
Subject: [PATCH v6 1/4] dt-bindings: backlight: Add max25014 support
In-Reply-To: <20251201-max25014-v6-0-88e3ac8112ff@gocontroll.com>
References: <20251201-max25014-v6-0-88e3ac8112ff@gocontroll.com>
Message-ID: <20251201-max25014-v6-1-88e3ac8112ff@gocontroll.com>

From: Maud Spierings <maudspierings at gocontroll.com>

The Maxim MAX25014 is a 4-channel automotive grade backlight driver IC
with integrated boost controller.

Signed-off-by: Maud Spierings <maudspierings at gocontroll.com>

---

In the current implementation the control registers for channel 1,
control all channels. So only one led subnode with led-sources is
supported right now. If at some point the driver functionality is
expanded the bindings can be easily extended with it.
---
 .../bindings/leds/backlight/maxim,max25014.yaml    | 107 +++++++++++++++++++++
 MAINTAINERS                                        |   5 +
 2 files changed, 112 insertions(+)

diff --git a/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml b/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
new file mode 100644
index 000000000000..e83723224b07
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
@@ -0,0 +1,107 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/leds/backlight/maxim,max25014.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Maxim max25014 backlight controller
+
+maintainers:
+  - Maud Spierings <maudspierings at gocontroll.com>
+
+properties:
+  compatible:
+    enum:
+      - maxim,max25014
+
+  reg:
+    maxItems: 1
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+  enable-gpios:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  power-supply:
+    description: Regulator which controls the boost converter input rail.
+
+  pwms:
+    maxItems: 1
+
+  maxim,iset:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 15
+    default: 11
+    description:
+      Value of the ISET field in the ISET register. This controls the current
+      scale of the outputs, a higher number means more current.
+
+  led at 0:
+    type: object
+    description: Properties for a string of connected LEDs.
+    $ref: common.yaml#
+
+    properties:
+      reg:
+        const: 0
+
+      led-sources:
+        allOf:
+          - minItems: 1
+            maxItems: 4
+            items:
+              minimum: 0
+              maximum: 3
+            default: [0, 1, 2, 3]
+
+      default-brightness:
+        minimum: 0
+        maximum: 100
+        default: 50
+
+    required:
+      - reg
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        backlight at 6f {
+            compatible = "maxim,max25014";
+            reg = <0x6f>;
+            #address-cells = <1>;
+            #size-cells = <0>;
+            enable-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
+            interrupt-parent = <&gpio1>;
+            interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
+            power-supply = <&reg_backlight>;
+            pwms = <&pwm1>;
+            maxim,iset = <7>;
+
+            led at 0 {
+                reg = <0>;
+                led-sources = <0 1 2 3>;
+                default-brightness = <50>;
+            };
+        };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index 58c7e3f678d8..606ce086f758 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15261,6 +15261,11 @@ F:	Documentation/userspace-api/media/drivers/max2175.rst
 F:	drivers/media/i2c/max2175*
 F:	include/uapi/linux/max2175.h
 
+MAX25014 BACKLIGHT DRIVER
+M:	Maud Spierings <maudspierings at gocontroll.com>
+S:	Maintained
+F:	Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
+
 MAX31335 RTC DRIVER
 M:	Antoniu Miclaus <antoniu.miclaus at analog.com>
 L:	linux-rtc at vger.kernel.org

-- 
2.52.0




From devnull+maudspierings.gocontroll.com at kernel.org  Mon Dec  1 03:53:21 2025
From: devnull+maudspierings.gocontroll.com at kernel.org (Maud Spierings via B4 Relay)
Date: Mon, 01 Dec 2025 12:53:21 +0100
Subject: [PATCH v6 2/4] backlight: add max25014atg backlight
In-Reply-To: <20251201-max25014-v6-0-88e3ac8112ff@gocontroll.com>
References: <20251201-max25014-v6-0-88e3ac8112ff@gocontroll.com>
Message-ID: <20251201-max25014-v6-2-88e3ac8112ff@gocontroll.com>

From: Maud Spierings <maudspierings at gocontroll.com>

The Maxim MAX25014 is a 4-channel automotive grade backlight driver IC
with integrated boost controller.

Signed-off-by: Maud Spierings <maudspierings at gocontroll.com>
---
 MAINTAINERS                        |   1 +
 drivers/video/backlight/Kconfig    |   7 +
 drivers/video/backlight/Makefile   |   1 +
 drivers/video/backlight/max25014.c | 419 +++++++++++++++++++++++++++++++++++++
 4 files changed, 428 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 606ce086f758..d082d3f8cfae 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15265,6 +15265,7 @@ MAX25014 BACKLIGHT DRIVER
 M:	Maud Spierings <maudspierings at gocontroll.com>
 S:	Maintained
 F:	Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
+F:	drivers/video/backlight/max25014.c
 
 MAX31335 RTC DRIVER
 M:	Antoniu Miclaus <antoniu.miclaus at analog.com>
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index d9374d208cee..d3bb6ccd4185 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -262,6 +262,13 @@ config BACKLIGHT_DA9052
 	help
 	  Enable the Backlight Driver for DA9052-BC and DA9053-AA/Bx PMICs.
 
+config BACKLIGHT_MAX25014
+	tristate "Backlight driver for the Maxim MAX25014 chip"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  If you are using a MAX25014 chip as a backlight driver say Y to enable it.
+
 config BACKLIGHT_MAX8925
 	tristate "Backlight driver for MAX8925"
 	depends on MFD_MAX8925
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index dfbb169bf6ea..1170d9ec40b8 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_BACKLIGHT_LOCOMO)		+= locomolcd.o
 obj-$(CONFIG_BACKLIGHT_LP855X)		+= lp855x_bl.o
 obj-$(CONFIG_BACKLIGHT_LP8788)		+= lp8788_bl.o
 obj-$(CONFIG_BACKLIGHT_LV5207LP)	+= lv5207lp.o
+obj-$(CONFIG_BACKLIGHT_MAX25014)	+= max25014.o
 obj-$(CONFIG_BACKLIGHT_MAX8925)		+= max8925_bl.o
 obj-$(CONFIG_BACKLIGHT_MP3309C)		+= mp3309c.o
 obj-$(CONFIG_BACKLIGHT_MT6370)		+= mt6370-backlight.o
diff --git a/drivers/video/backlight/max25014.c b/drivers/video/backlight/max25014.c
new file mode 100644
index 000000000000..7000225752c3
--- /dev/null
+++ b/drivers/video/backlight/max25014.c
@@ -0,0 +1,419 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Backlight driver for Maxim MAX25014
+ *
+ * Copyright (C) 2025 GOcontroll B.V.
+ * Author: Maud Spierings <maudspierings at gocontroll.com>
+ */
+
+#include <linux/backlight.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define MAX25014_ISET_DEFAULT_100 11
+#define MAX_BRIGHTNESS            100
+#define MIN_BRIGHTNESS            0
+#define TON_MAX                   130720 /* @153Hz */
+#define TON_STEP                  1307 /* @153Hz */
+#define TON_MIN                   0
+
+#define MAX25014_DEV_ID           0x00
+#define MAX25014_REV_ID           0x01
+#define MAX25014_ISET             0x02
+#define MAX25014_IMODE            0x03
+#define MAX25014_TON1H            0x04
+#define MAX25014_TON1L            0x05
+#define MAX25014_TON2H            0x06
+#define MAX25014_TON2L            0x07
+#define MAX25014_TON3H            0x08
+#define MAX25014_TON3L            0x09
+#define MAX25014_TON4H            0x0A
+#define MAX25014_TON4L            0x0B
+#define MAX25014_TON_1_4_LSB      0x0C
+#define MAX25014_SETTING          0x12
+#define MAX25014_DISABLE          0x13
+#define MAX25014_BSTMON           0x14
+#define MAX25014_IOUT1            0x15
+#define MAX25014_IOUT2            0x16
+#define MAX25014_IOUT3            0x17
+#define MAX25014_IOUT4            0x18
+#define MAX25014_OPEN             0x1B
+#define MAX25014_SHORT_GND        0x1C
+#define MAX25014_SHORT_LED        0x1D
+#define MAX25014_MASK             0x1E
+#define MAX25014_DIAG             0x1F
+
+#define MAX25014_ISET_ENA         BIT(5)
+#define MAX25014_ISET_PSEN        BIT(4)
+#define MAX25014_IMODE_HDIM       BIT(2)
+#define MAX25014_SETTING_FPWM     GENMASK(6, 4)
+#define MAX25014_DISABLE_DIS_MASK GENMASK(3, 0)
+#define MAX25014_DIAG_OT          BIT(0)
+#define MAX25014_DIAG_OTW         BIT(1)
+#define MAX25014_DIAG_HW_RST      BIT(2)
+#define MAX25014_DIAG_BSTOV       BIT(3)
+#define MAX25014_DIAG_BSTUV       BIT(4)
+#define MAX25014_DIAG_IREFOOR     BIT(5)
+
+struct max25014 {
+	struct i2c_client *client;
+	struct backlight_device *bl;
+	struct regmap *regmap;
+	struct gpio_desc *enable;
+	struct regulator *vin; /* regulator for boost converter Vin rail */
+	uint32_t iset;
+	uint8_t strings_mask;
+};
+
+static const struct regmap_config max25014_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = MAX25014_DIAG,
+};
+
+static int max25014_initial_power_state(struct max25014 *maxim)
+{
+	uint32_t val;
+	int ret;
+
+	ret = regmap_read(maxim->regmap, MAX25014_ISET, &val);
+	if (ret)
+		return ret;
+
+	return val & MAX25014_ISET_ENA ? BACKLIGHT_POWER_ON : BACKLIGHT_POWER_OFF;
+}
+
+static int max25014_check_errors(struct max25014 *maxim)
+{
+	uint32_t val;
+	uint8_t i;
+	int ret;
+
+	ret = regmap_read(maxim->regmap, MAX25014_OPEN, &val);
+	if (ret)
+		return ret;
+	if (val) {
+		dev_err(&maxim->client->dev, "Open led strings detected on:\n");
+		for (i = 0; i < 4; i++) {
+			if (val & 1 << i)
+				dev_err(&maxim->client->dev, "string %d\n", i + 1);
+		}
+		return -EIO;
+	}
+
+	ret = regmap_read(maxim->regmap, MAX25014_SHORT_GND, &val);
+	if (ret)
+		return ret;
+	if (val) {
+		dev_err(&maxim->client->dev, "Short to ground detected on:\n");
+		for (i = 0; i < 4; i++) {
+			if (val & 1 << i)
+				dev_err(&maxim->client->dev, "string %d\n", i + 1);
+		}
+		return -EIO;
+	}
+
+	ret = regmap_read(maxim->regmap, MAX25014_SHORT_GND, &val);
+	if (ret)
+		return ret;
+	if (val) {
+		dev_err(&maxim->client->dev, "Shorted led detected on:\n");
+		for (i = 0; i < 4; i++) {
+			if (val & 1 << i)
+				dev_err(&maxim->client->dev, "string %d\n", i + 1);
+		}
+		return -EIO;
+	}
+
+	ret = regmap_read(maxim->regmap, MAX25014_DIAG, &val);
+	if (ret)
+		return ret;
+	/*
+	 * The HW_RST bit always starts at 1 after power up.
+	 * It is reset on first read, does not indicate an error.
+	 */
+	if (val && val != MAX25014_DIAG_HW_RST) {
+		if (val & MAX25014_DIAG_OT)
+			dev_err(&maxim->client->dev,
+				"Overtemperature shutdown\n");
+		if (val & MAX25014_DIAG_OTW)
+			dev_err(&maxim->client->dev,
+				 "Chip is getting too hot (>125C)\n");
+		if (val & MAX25014_DIAG_BSTOV)
+			dev_err(&maxim->client->dev,
+				"Boost converter overvoltage\n");
+		if (val & MAX25014_DIAG_BSTUV)
+			dev_err(&maxim->client->dev,
+				"Boost converter undervoltage\n");
+		if (val & MAX25014_DIAG_IREFOOR)
+			dev_err(&maxim->client->dev, "IREF out of range\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+/*
+ * 1. disable unused strings
+ * 2. set dim mode
+ * 3. set setting register
+ * 4. enable the backlight
+ */
+static int max25014_configure(struct max25014 *maxim, int initial_state)
+{
+	uint32_t val;
+	int ret;
+
+	/*
+	 * Strings can only be disabled when MAX25014_ISET_ENA == 0, check if
+	 * it needs to be changed at all to prevent the backlight flashing when
+	 * it is configured correctly by the bootloader
+	 */
+	ret = regmap_read(maxim->regmap, MAX25014_DISABLE, &val);
+	if (ret)
+		return ret;
+
+	if (!((val & MAX25014_DISABLE_DIS_MASK) == maxim->strings_mask)) {
+		if (initial_state == BACKLIGHT_POWER_ON) {
+			ret = regmap_write(maxim->regmap, MAX25014_ISET, 0);
+			if (ret)
+				return ret;
+		}
+		ret = regmap_write(maxim->regmap, MAX25014_DISABLE, maxim->strings_mask);
+		if (ret)
+			return ret;
+	}
+
+	ret = regmap_write(maxim->regmap, MAX25014_IMODE, MAX25014_IMODE_HDIM);
+	if (ret)
+		return ret;
+
+	ret = regmap_read(maxim->regmap, MAX25014_SETTING, &val);
+	if (ret)
+		return ret;
+
+	ret = regmap_write(maxim->regmap, MAX25014_SETTING,
+			   val & ~MAX25014_SETTING_FPWM);
+	if (ret)
+		return ret;
+
+	ret = regmap_write(maxim->regmap, MAX25014_ISET,
+			   maxim->iset | MAX25014_ISET_ENA |
+			   MAX25014_ISET_PSEN);
+	return ret;
+}
+
+static int max25014_update_status(struct backlight_device *bl_dev)
+{
+	struct max25014 *maxim = bl_get_data(bl_dev);
+	uint32_t reg;
+	int ret;
+
+	if (backlight_is_blank(maxim->bl))
+		bl_dev->props.brightness = 0;
+
+	reg  = TON_STEP * bl_dev->props.brightness;
+
+	/*
+	 * 18 bit number lowest, 2 bits in first register,
+	 * next lowest 8 in the L register, next 8 in the H register
+	 * Seemingly setting the strength of only one string controls all of
+	 * them, individual settings don't affect the outcome.
+	 */
+
+	ret = regmap_write(maxim->regmap, MAX25014_TON_1_4_LSB, reg & 0b00000011);
+	if (ret != 0)
+		return ret;
+	ret = regmap_write(maxim->regmap, MAX25014_TON1L, (reg >> 2) & 0b11111111);
+	if (ret != 0)
+		return ret;
+	return regmap_write(maxim->regmap, MAX25014_TON1H, (reg >> 10) & 0b11111111);
+}
+
+static const struct backlight_ops max25014_bl_ops = {
+	.options = BL_CORE_SUSPENDRESUME,
+	.update_status = max25014_update_status,
+};
+
+static int max25014_parse_dt(struct max25014 *maxim,
+			     uint32_t *initial_brightness)
+{
+	struct device *dev = &maxim->client->dev;
+	struct device_node *node = dev->of_node;
+	struct fwnode_handle *child;
+	uint32_t strings[4];
+	int res, i;
+
+	if (!node)
+		return dev_err_probe(dev, -EINVAL, "no platform data\n");
+
+	child = device_get_next_child_node(dev, NULL);
+	if (child) {
+		res = fwnode_property_count_u32(child, "led-sources");
+		if (res > 0) {
+			fwnode_property_read_u32_array(child, "led-sources",
+						       strings, res);
+
+			/* set all strings as disabled, then enable those in led-sources*/
+			maxim->strings_mask = 0xf;
+			for (i = 0; i < res; i++) {
+				if (strings[i] <= 4)
+					maxim->strings_mask &= ~BIT(strings[i]);
+			}
+		}
+
+		fwnode_property_read_u32(child, "default-brightness",
+					 initial_brightness);
+
+		fwnode_handle_put(child);
+	}
+
+	maxim->iset = MAX25014_ISET_DEFAULT_100;
+	of_property_read_u32(node, "maxim,iset", &maxim->iset);
+
+	if (maxim->iset > 15)
+		return dev_err_probe(dev, -EINVAL,
+				     "Invalid iset, should be a value from 0-15, entered was %d\n",
+				     maxim->iset);
+
+	if (*initial_brightness > 100)
+		return dev_err_probe(dev, -EINVAL,
+				     "Invalid initial brightness, should be a value from 0-100, entered was %d\n",
+				     *initial_brightness);
+
+	return 0;
+}
+
+static int max25014_probe(struct i2c_client *cl)
+{
+	const struct i2c_device_id *id = i2c_client_get_device_id(cl);
+	struct backlight_properties props;
+	uint32_t initial_brightness = 50;
+	struct backlight_device *bl;
+	struct max25014 *maxim;
+	int ret;
+
+	maxim = devm_kzalloc(&cl->dev, sizeof(struct max25014), GFP_KERNEL);
+	if (!maxim)
+		return -ENOMEM;
+
+	maxim->client = cl;
+
+	ret = max25014_parse_dt(maxim, &initial_brightness);
+	if (ret)
+		return ret;
+
+	maxim->vin = devm_regulator_get(&maxim->client->dev, "power");
+	if (IS_ERR(maxim->vin)) {
+		return dev_err_probe(&maxim->client->dev, PTR_ERR(maxim->vin),
+				     "failed to get power-supply");
+	}
+
+	ret = regulator_enable(maxim->vin);
+	if (ret)
+		return dev_err_probe(&maxim->client->dev, ret,
+			"failed to enable power-supply\n");
+
+	maxim->enable = devm_gpiod_get_optional(&maxim->client->dev, "enable",
+						GPIOD_OUT_HIGH);
+	if (IS_ERR(maxim->enable)) {
+		ret = dev_err_probe(&maxim->client->dev, PTR_ERR(maxim->enable),
+				    "failed to get enable gpio\n");
+		goto disable_vin;
+	}
+
+	/* Datasheet Electrical Characteristics tSTARTUP 2ms */
+	fsleep(2000);
+
+	maxim->regmap = devm_regmap_init_i2c(cl, &max25014_regmap_config);
+	if (IS_ERR(maxim->regmap)) {
+		ret = dev_err_probe(&maxim->client->dev, PTR_ERR(maxim->regmap),
+			"failed to initialize the i2c regmap\n");
+		goto disable_full;
+	}
+
+	i2c_set_clientdata(cl, maxim);
+
+	ret = max25014_check_errors(maxim);
+	if (ret) { /* error is already reported in the above function */
+		goto disable_full;
+	}
+
+	ret = max25014_initial_power_state(maxim);
+	if (ret < 0) {
+		dev_err_probe(&maxim->client->dev, ret, "Could not get enabled state\n");
+		goto disable_full;
+	}
+
+	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_PLATFORM;
+	props.max_brightness = MAX_BRIGHTNESS;
+	props.brightness = initial_brightness;
+	props.scale = BACKLIGHT_SCALE_LINEAR;
+	props.power = ret;
+
+	ret = max25014_configure(maxim, ret);
+	if (ret) {
+		dev_err_probe(&maxim->client->dev, ret, "device config error");
+		goto disable_full;
+	}
+
+	bl = devm_backlight_device_register(&maxim->client->dev, id->name,
+					    &maxim->client->dev, maxim,
+					    &max25014_bl_ops, &props);
+	if (IS_ERR(bl)) {
+		ret = dev_err_probe(&maxim->client->dev, PTR_ERR(bl),
+				    "failed to register backlight\n");
+		goto disable_full;
+	}
+
+	maxim->bl = bl;
+
+	backlight_update_status(maxim->bl);
+
+	return 0;
+
+disable_full:
+	gpiod_set_value_cansleep(maxim->enable, 0);
+disable_vin:
+	regulator_disable(maxim->vin);
+	return ret;
+}
+
+static void max25014_remove(struct i2c_client *cl)
+{
+	struct max25014 *maxim = i2c_get_clientdata(cl);
+
+	maxim->bl->props.brightness = 0;
+	max25014_update_status(maxim->bl);
+	gpiod_set_value_cansleep(maxim->enable, 0);
+	regulator_disable(maxim->vin);
+}
+
+static const struct of_device_id max25014_dt_ids[] = {
+	{ .compatible = "maxim,max25014", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, max25014_dt_ids);
+
+static const struct i2c_device_id max25014_ids[] = {
+	{ "max25014" },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max25014_ids);
+
+static struct i2c_driver max25014_driver = {
+	.driver = {
+		.name = KBUILD_MODNAME,
+		.of_match_table = of_match_ptr(max25014_dt_ids),
+	},
+	.probe = max25014_probe,
+	.remove = max25014_remove,
+	.id_table = max25014_ids,
+};
+module_i2c_driver(max25014_driver);
+
+MODULE_DESCRIPTION("Maxim MAX25014 backlight driver");
+MODULE_AUTHOR("Maud Spierings <maudspierings at gocontroll.com>");
+MODULE_LICENSE("GPL");

-- 
2.52.0




From devnull+maudspierings.gocontroll.com at kernel.org  Mon Dec  1 03:53:23 2025
From: devnull+maudspierings.gocontroll.com at kernel.org (Maud Spierings via B4 Relay)
Date: Mon, 01 Dec 2025 12:53:23 +0100
Subject: [PATCH v6 4/4] arm64: dts: freescale:
 moduline-display-av123z7m-n17: add backlight
In-Reply-To: <20251201-max25014-v6-0-88e3ac8112ff@gocontroll.com>
References: <20251201-max25014-v6-0-88e3ac8112ff@gocontroll.com>
Message-ID: <20251201-max25014-v6-4-88e3ac8112ff@gocontroll.com>

From: Maud Spierings <maudspierings at gocontroll.com>

Add the missing backlight.

Signed-off-by: Maud Spierings <maudspierings at gocontroll.com>
---
 ...x8p-ml81-moduline-display-106-av123z7m-n17.dtso | 25 +++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106-av123z7m-n17.dtso b/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106-av123z7m-n17.dtso
index 3eb665ce9d5d..786a04ef40c8 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106-av123z7m-n17.dtso
+++ b/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106-av123z7m-n17.dtso
@@ -16,6 +16,7 @@
 
 	panel {
 		compatible = "boe,av123z7m-n17";
+		backlight = <&backlight>;
 		enable-gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
 		pinctrl-0 = <&pinctrl_panel>;
 		pinctrl-names = "default";
@@ -91,10 +92,32 @@ lvds1_out: endpoint {
 		};
 	};
 
-	/* max25014 @ 0x6f */
+	backlight: backlight at 6f {
+		compatible = "maxim,max25014";
+		reg = <0x6f>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		enable-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_backlight>;
+		maxim,iset = <7>;
+
+		led at 0 {
+			reg = <0>;
+			led-sources = <0 1 2 3>;
+			default-brightness = <50>;
+		};
+	};
 };
 
 &iomuxc {
+	pinctrl_backlight: backlightgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO04__GPIO1_IO04
+				(MX8MP_PULL_UP | MX8MP_PULL_ENABLE)
+		>;
+	};
+
 	pinctrl_lvds_bridge: lvdsbridgegrp {
 		fsl,pins = <
 			MX8MP_IOMUXC_SAI1_TXD2__GPIO4_IO14

-- 
2.52.0




From devnull+maudspierings.gocontroll.com at kernel.org  Mon Dec  1 03:53:22 2025
From: devnull+maudspierings.gocontroll.com at kernel.org (Maud Spierings via B4 Relay)
Date: Mon, 01 Dec 2025 12:53:22 +0100
Subject: [PATCH v6 3/4] arm64: dts: freescale:
 moduline-display-av101hdt-a10: add backlight
In-Reply-To: <20251201-max25014-v6-0-88e3ac8112ff@gocontroll.com>
References: <20251201-max25014-v6-0-88e3ac8112ff@gocontroll.com>
Message-ID: <20251201-max25014-v6-3-88e3ac8112ff@gocontroll.com>

From: Maud Spierings <maudspierings at gocontroll.com>

Add the missing backlight driver.

Signed-off-by: Maud Spierings <maudspierings at gocontroll.com>
---
 ...x8p-ml81-moduline-display-106-av101hdt-a10.dtso | 30 ++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106-av101hdt-a10.dtso b/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106-av101hdt-a10.dtso
index e3965caca6be..0e2914861154 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106-av101hdt-a10.dtso
+++ b/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106-av101hdt-a10.dtso
@@ -17,6 +17,7 @@
 
 	panel {
 		compatible = "boe,av101hdt-a10";
+		backlight = <&backlight>;
 		enable-gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
 		pinctrl-0 = <&pinctrl_panel>;
 		pinctrl-names = "default";
@@ -40,7 +41,36 @@ reg_vbus: regulator-vbus {
 	};
 };
 
+&i2c4 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	backlight: backlight at 6f {
+		compatible = "maxim,max25014";
+		reg = <0x6f>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		enable-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_backlight>;
+		maxim,iset = <7>;
+
+		led at 0 {
+			reg = <0>;
+			led-sources = <0 1 2>;
+			default-brightness = <50>;
+		};
+	};
+};
+
 &iomuxc {
+	pinctrl_backlight: backlightgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO04__GPIO1_IO04
+				(MX8MP_PULL_UP | MX8MP_PULL_ENABLE)
+		>;
+	};
+
 	pinctrl_panel: panelgrp {
 		fsl,pins = <
 			MX8MP_IOMUXC_GPIO1_IO07__GPIO1_IO07

-- 
2.52.0




From devnull+maudspierings.gocontroll.com at kernel.org  Mon Dec  1 03:56:49 2025
From: devnull+maudspierings.gocontroll.com at kernel.org (Maud Spierings via B4 Relay)
Date: Mon, 01 Dec 2025 12:56:49 +0100
Subject: [PATCH v2 0/3] arm64: dts: freescale: moduline-display: several
 fixes
Message-ID: <20251201-disp_fix-v2-0-9b03026311b6@gocontroll.com>

A couple of issues where discovered:
- compatibles should integrate the SoM
- the eqos mac address is stored in eth_mac1

The first one is breaking, but it is early enough that it can be
corrected without causing any issues.

Signed-off-by: Maud Spierings <maudspierings at gocontroll.com>
---
Changes in v2:
- re-add the old compatible to fsl.yaml
- expand the reasoning for these changes in the commit messages
- Link to v1: https://lore.kernel.org/r/20251114-disp_fix-v1-0-49cbe826afc2 at gocontroll.com

---
Maud Spierings (3):
      dt-bindings: arm: fsl: moduline-display: fix compatible
      arm64: dts: freescale: moduline-display: fix compatible
      arm64: dts: freescale: tx8p-ml81: fix eqos nvmem-cells

 Documentation/devicetree/bindings/arm/fsl.yaml                   | 9 ++++++++-
 .../boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106.dts | 2 +-
 arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81.dtsi              | 5 +++++
 3 files changed, 14 insertions(+), 2 deletions(-)
---
base-commit: 0f2995693867bfb26197b117cd55624ddc57582f
change-id: 20251114-disp_fix-2c90d35ab0dd

Best regards,
-- 
Maud Spierings <maudspierings at gocontroll.com>




From devnull+maudspierings.gocontroll.com at kernel.org  Mon Dec  1 03:56:50 2025
From: devnull+maudspierings.gocontroll.com at kernel.org (Maud Spierings via B4 Relay)
Date: Mon, 01 Dec 2025 12:56:50 +0100
Subject: [PATCH v2 1/3] dt-bindings: arm: fsl: moduline-display: fix
 compatible
In-Reply-To: <20251201-disp_fix-v2-0-9b03026311b6@gocontroll.com>
References: <20251201-disp_fix-v2-0-9b03026311b6@gocontroll.com>
Message-ID: <20251201-disp_fix-v2-1-9b03026311b6@gocontroll.com>

From: Maud Spierings <maudspierings at gocontroll.com>

The compatibles should include the SoM compatible, this board is based
on the Ka-Ro TX8P-ML81 SoM, so add it to allow using shared code in the
bootloader which uses upstream Linux devicetrees as a base.

Also add the hardware revision to the board compatible to handle
revision specific quirks in the bootloader/userspace.

This is a breaking change, but it is early enough that it can be
corrected without causing any issues.

Fixes: 24e67d28ef95 ("dt-bindings: arm: fsl: Add GOcontroll Moduline Display")
Signed-off-by: Maud Spierings <maudspierings at gocontroll.com>
---
 Documentation/devicetree/bindings/arm/fsl.yaml | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
index 21b7168d61f5..0aeac16843b5 100644
--- a/Documentation/devicetree/bindings/arm/fsl.yaml
+++ b/Documentation/devicetree/bindings/arm/fsl.yaml
@@ -1105,7 +1105,6 @@ properties:
               - gateworks,imx8mp-gw74xx   # i.MX8MP Gateworks Board
               - gateworks,imx8mp-gw75xx-2x # i.MX8MP Gateworks Board
               - gateworks,imx8mp-gw82xx-2x # i.MX8MP Gateworks Board
-              - gocontroll,moduline-display # GOcontroll Moduline Display controller
               - prt,prt8ml             # Protonic PRT8ML
               - skov,imx8mp-skov-basic # SKOV i.MX8MP baseboard without frontplate
               - skov,imx8mp-skov-revb-hdmi # SKOV i.MX8MP climate control without panel
@@ -1163,6 +1162,14 @@ properties:
           - const: engicam,icore-mx8mp             # i.MX8MP Engicam i.Core MX8M Plus SoM
           - const: fsl,imx8mp
 
+      - description: Ka-Ro TX8P-ML81 SoM based boards
+        items:
+          - enum:
+              - gocontroll,moduline-display
+              - gocontroll,moduline-display-106
+          - const: karo,tx8p-ml81
+          - const: fsl,imx8mp
+
       - description: Kontron i.MX8MP OSM-S SoM based Boards
         items:
           - const: kontron,imx8mp-bl-osm-s  # Kontron BL i.MX8MP OSM-S Board

-- 
2.52.0




From devnull+maudspierings.gocontroll.com at kernel.org  Mon Dec  1 03:56:52 2025
From: devnull+maudspierings.gocontroll.com at kernel.org (Maud Spierings via B4 Relay)
Date: Mon, 01 Dec 2025 12:56:52 +0100
Subject: [PATCH v2 3/3] arm64: dts: freescale: tx8p-ml81: fix eqos
 nvmem-cells
In-Reply-To: <20251201-disp_fix-v2-0-9b03026311b6@gocontroll.com>
References: <20251201-disp_fix-v2-0-9b03026311b6@gocontroll.com>
Message-ID: <20251201-disp_fix-v2-3-9b03026311b6@gocontroll.com>

From: Maud Spierings <maudspierings at gocontroll.com>

On this SoM eqos is the primary ethernet interface, Ka-Ro fuses the
address for it in eth_mac1, eth_mac2 seems to be left unfused. In their
downstream u-boot they fetch it from eth_mac1 [1][2], by setting alias
of eqos to ethernet0, the driver then fetches the mac address based on
the alias number.

Set eqos to read from eth_mac1 instead of eth_mac2. Also set fec to
point at eth_mac2 as it may be fused later even though it is disabled
by default.

With this changed barebox is now capable of loading the correct address.

Link: https://github.com/karo-electronics/karo-tx-uboot/blob/380543278410bbf04264d80a3bfbe340b8e62439/drivers/net/dwc_eth_qos.c#L1167 [1]
Link: https://github.com/karo-electronics/karo-tx-uboot/blob/380543278410bbf04264d80a3bfbe340b8e62439/arch/arm/dts/imx8mp-karo.dtsi#L12 [2]

Fixes: bac63d7c5f46 ("arm64: dts: freescale: add Ka-Ro Electronics tx8p-ml81 COM")
Signed-off-by: Maud Spierings <maudspierings at gocontroll.com>
---
 arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81.dtsi | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81.dtsi
index fe8ba16eb40e..761ee046eb72 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81.dtsi
@@ -47,6 +47,7 @@ &eqos {
 				 <&clk IMX8MP_SYS_PLL2_100M>,
 				 <&clk IMX8MP_SYS_PLL2_50M>;
 	assigned-clock-rates = <266000000>, <100000000>, <50000000>;
+	nvmem-cells = <&eth_mac1>;
 	phy-handle = <&ethphy0>;
 	phy-mode = "rmii";
 	pinctrl-0 = <&pinctrl_eqos>;
@@ -75,6 +76,10 @@ ethphy0: ethernet-phy at 0 {
 	};
 };
 
+&fec {
+	nvmem-cells = <&eth_mac2>;
+};
+
 &gpio1 {
 	gpio-line-names = "SODIMM_152",
 			  "SODIMM_42",

-- 
2.52.0




From devnull+maudspierings.gocontroll.com at kernel.org  Mon Dec  1 03:56:51 2025
From: devnull+maudspierings.gocontroll.com at kernel.org (Maud Spierings via B4 Relay)
Date: Mon, 01 Dec 2025 12:56:51 +0100
Subject: [PATCH v2 2/3] arm64: dts: freescale: moduline-display: fix
 compatible
In-Reply-To: <20251201-disp_fix-v2-0-9b03026311b6@gocontroll.com>
References: <20251201-disp_fix-v2-0-9b03026311b6@gocontroll.com>
Message-ID: <20251201-disp_fix-v2-2-9b03026311b6@gocontroll.com>

From: Maud Spierings <maudspierings at gocontroll.com>

The compatibles should include the SoM compatible, this board is based
on the Ka-Ro TX8P-ML81 SoM, so add it to allow using shared code in the
bootloader which uses upstream Linux devicetrees as a base.

Also add the hardware revision to the board compatible to handle
revision specific quirks in the bootloader/userspace.

This is a breaking change, but it is early enough that it can be
corrected without causing any issues.

Fixes: 03f07be54cdc ("arm64: dts: freescale: Add the GOcontroll Moduline Display baseboard")
Signed-off-by: Maud Spierings <maudspierings at gocontroll.com>
---
 arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106.dts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106.dts b/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106.dts
index 88ad422c2760..399230144ce3 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106.dts
@@ -9,7 +9,7 @@
 #include "imx8mp-tx8p-ml81.dtsi"
 
 / {
-	compatible = "gocontroll,moduline-display", "fsl,imx8mp";
+	compatible = "gocontroll,moduline-display-106", "karo,tx8p-ml81", "fsl,imx8mp";
 	chassis-type = "embedded";
 	hardware = "Moduline Display V1.06";
 	model = "GOcontroll Moduline Display baseboard";

-- 
2.52.0




From ruanjinjie at huawei.com  Mon Dec  1 04:06:32 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Dec 2025 20:06:32 +0800
Subject: [PATCH v2 1/2] syscall.h: Remove unused SYSCALL_MAX_ARGS
In-Reply-To: <20251201120633.1193122-1-ruanjinjie@huawei.com>
References: <20251201120633.1193122-1-ruanjinjie@huawei.com>
Message-ID: <20251201120633.1193122-2-ruanjinjie@huawei.com>

The "SYSCALL_MAX_ARGS" appears to have been unused since
commit 32d92586629a ("syscalls: Remove start and number from
syscall_set_arguments() args"), so remove it.

Fixes: 32d92586629a ("syscalls: Remove start and number from syscall_set_arguments() args")
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm/include/asm/syscall.h    | 2 --
 arch/arm64/include/asm/syscall.h  | 2 --
 arch/xtensa/include/asm/syscall.h | 1 -
 3 files changed, 5 deletions(-)

diff --git a/arch/arm/include/asm/syscall.h b/arch/arm/include/asm/syscall.h
index 18b102a30741..574bbcc55382 100644
--- a/arch/arm/include/asm/syscall.h
+++ b/arch/arm/include/asm/syscall.h
@@ -92,8 +92,6 @@ static inline void syscall_set_nr(struct task_struct *task,
 		(nr & __NR_SYSCALL_MASK);
 }
 
-#define SYSCALL_MAX_ARGS 7
-
 static inline void syscall_get_arguments(struct task_struct *task,
 					 struct pt_regs *regs,
 					 unsigned long *args)
diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
index 712daa90e643..f3853047c28e 100644
--- a/arch/arm64/include/asm/syscall.h
+++ b/arch/arm64/include/asm/syscall.h
@@ -77,8 +77,6 @@ static inline void syscall_set_nr(struct task_struct *task,
 	}
 }
 
-#define SYSCALL_MAX_ARGS 6
-
 static inline void syscall_get_arguments(struct task_struct *task,
 					 struct pt_regs *regs,
 					 unsigned long *args)
diff --git a/arch/xtensa/include/asm/syscall.h b/arch/xtensa/include/asm/syscall.h
index 7db3b489c8ad..bab7cdd96cbe 100644
--- a/arch/xtensa/include/asm/syscall.h
+++ b/arch/xtensa/include/asm/syscall.h
@@ -61,7 +61,6 @@ static inline void syscall_set_return_value(struct task_struct *task,
 	regs->areg[2] = (long) error ? error : val;
 }
 
-#define SYSCALL_MAX_ARGS 6
 #define XTENSA_SYSCALL_ARGUMENT_REGS {6, 3, 4, 5, 8, 9}
 
 static inline void syscall_get_arguments(struct task_struct *task,
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Dec  1 04:06:33 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Dec 2025 20:06:33 +0800
Subject: [PATCH v2 2/2] arm64: Avoid memcpy() for syscall_get_arguments()
In-Reply-To: <20251201120633.1193122-1-ruanjinjie@huawei.com>
References: <20251201120633.1193122-1-ruanjinjie@huawei.com>
Message-ID: <20251201120633.1193122-3-ruanjinjie@huawei.com>

Do not use memcpy() to extract syscall arguments from struct pt_regs
but rather just perform direct assignments.

Update syscall_set_arguments() too to keep syscall_get_arguments()
and syscall_set_arguments() in sync.

With Generic Entry patch[1] and turn on audit, the performance
benchmarks from perf bench basic syscall on kunpeng920 gives roughly
a 1% performance uplift.

| Metric     | W/O this patch | With this patch | Change    |
| ---------- | -------------- | --------------- | --------- |
| Total time | 2.241 [sec]    | 2.211 [sec]     |  ?1.36%   |
| usecs/op   | 0.224157       | 0.221146        |  ?1.36%   |
| ops/sec    | 4,461,157      | 4,501,409       |  ?0.9%    |

Disassembly shows that using direct assignment causes
syscall_set_arguments() to be inlined and cuts the instruction count by
five or six compared to memcpy(). Because __audit_syscall_entry() only
uses four syscall arguments, the compiler has also elided the copy of
regs->regs[4] and regs->regs[5].

Before:
<syscall_get_arguments.constprop.0>:
       aa0103e2        mov     x2, x1
       91002003        add     x3, x0, #0x8
       f9408804        ldr     x4, [x0, #272]
       f8008444        str     x4, [x2], #8
       a9409404        ldp     x4, x5, [x0, #8]
       a9009424        stp     x4, x5, [x1, #8]
       a9418400        ldp     x0, x1, [x0, #24]
       a9010440        stp     x0, x1, [x2, #16]
       f9401060        ldr     x0, [x3, #32]
       f9001040        str     x0, [x2, #32]
       d65f03c0        ret
       d503201f        nop

After:
       a9408e82        ldp     x2, x3, [x20, #8]
       2a1603e0        mov     w0, w22
       f9400e84        ldr     x4, [x20, #24]
       f9408a81        ldr     x1, [x20, #272]
       9401c4ba        bl      ffff800080215ca8 <__audit_syscall_entry>

This also aligns the implementation with x86 and RISC-V.

[1]: https://lore.kernel.org/all/20251126071446.3234218-1-ruanjinjie at huawei.com/
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
v2:
- Also update syscall_set_arguments().
- Udpate the commit message.
---
 arch/arm64/include/asm/syscall.h | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
index f3853047c28e..5e4c7fc44f73 100644
--- a/arch/arm64/include/asm/syscall.h
+++ b/arch/arm64/include/asm/syscall.h
@@ -82,16 +82,24 @@ static inline void syscall_get_arguments(struct task_struct *task,
 					 unsigned long *args)
 {
 	args[0] = regs->orig_x0;
-	args++;
-
-	memcpy(args, &regs->regs[1], 5 * sizeof(args[0]));
+	args[1] = regs->regs[1];
+	args[2] = regs->regs[2];
+	args[3] = regs->regs[3];
+	args[4] = regs->regs[4];
+	args[5] = regs->regs[5];
 }
 
 static inline void syscall_set_arguments(struct task_struct *task,
 					 struct pt_regs *regs,
 					 const unsigned long *args)
 {
-	memcpy(&regs->regs[0], args, 6 * sizeof(args[0]));
+	regs->regs[0] = args[0];
+	regs->regs[1] = args[1];
+	regs->regs[2] = args[2];
+	regs->regs[3] = args[3];
+	regs->regs[4] = args[4];
+	regs->regs[5] = args[5];
+
 	/*
 	 * Also copy the first argument into orig_x0
 	 * so that syscall_get_arguments() would return it
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Dec  1 04:06:31 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Dec 2025 20:06:31 +0800
Subject: [PATCH v2 0/2] syscall: Cleanup and improve syscall_get_arguments()
Message-ID: <20251201120633.1193122-1-ruanjinjie@huawei.com>

Remove unused SYSCALL_MAX_ARGS and avoid memcpy() for
syscall_get_arguments() for arm64.

Jinjie Ruan (2):
  syscall.h: Remove unused SYSCALL_MAX_ARGS
  arm64: Avoid memcpy() for syscall_get_arguments()

 arch/arm/include/asm/syscall.h    |  2 --
 arch/arm64/include/asm/syscall.h  | 18 ++++++++++++------
 arch/xtensa/include/asm/syscall.h |  1 -
 3 files changed, 12 insertions(+), 9 deletions(-)

-- 
2.34.1



From tomi.valkeinen at ideasonboard.com  Mon Dec  1 04:18:43 2025
From: tomi.valkeinen at ideasonboard.com (Tomi Valkeinen)
Date: Mon, 01 Dec 2025 14:18:43 +0200
Subject: [PATCH v7 01/11] drm/fourcc: Add warning for bad bpp
In-Reply-To: <20251201-xilinx-formats-v7-0-1e1558adfefc@ideasonboard.com>
References: <20251201-xilinx-formats-v7-0-1e1558adfefc@ideasonboard.com>
Message-ID: <20251201-xilinx-formats-v7-1-1e1558adfefc@ideasonboard.com>

drm_format_info_bpp() cannot be used for formats which do not have an
integer bits-per-pixel in a pixel block.

E.g. DRM_FORMAT_XV15's (not yet in upstream) plane 0 has three 10-bit
pixels (Y components), and two padding bits, in a 4 byte block. That is
10.666... bits per pixel when considering the whole 4 byte block, which
is what drm_format_info_bpp() does. Thus a driver that supports such
formats cannot use drm_format_info_bpp(),

It is a driver bug if this happens, but so handle wrong calls by
printing a warning and returning 0.

Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
---
 drivers/gpu/drm/drm_fourcc.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
index e0d533611040..e662aea9d105 100644
--- a/drivers/gpu/drm/drm_fourcc.c
+++ b/drivers/gpu/drm/drm_fourcc.c
@@ -491,12 +491,20 @@ EXPORT_SYMBOL(drm_format_info_block_height);
  */
 unsigned int drm_format_info_bpp(const struct drm_format_info *info, int plane)
 {
+	unsigned int block_size;
+
 	if (!info || plane < 0 || plane >= info->num_planes)
 		return 0;
 
-	return info->char_per_block[plane] * 8 /
-	       (drm_format_info_block_width(info, plane) *
-		drm_format_info_block_height(info, plane));
+	block_size = drm_format_info_block_width(info, plane) *
+		     drm_format_info_block_height(info, plane);
+
+	if (info->char_per_block[plane] * 8 % block_size) {
+		pr_warn("unable to return an integer bpp\n");
+		return 0;
+	}
+
+	return info->char_per_block[plane] * 8 / block_size;
 }
 EXPORT_SYMBOL(drm_format_info_bpp);
 

-- 
2.43.0



From tomi.valkeinen at ideasonboard.com  Mon Dec  1 04:18:42 2025
From: tomi.valkeinen at ideasonboard.com (Tomi Valkeinen)
Date: Mon, 01 Dec 2025 14:18:42 +0200
Subject: [PATCH v7 00/11] drm: Add new pixel formats for Xilinx Zynqmp
Message-ID: <20251201-xilinx-formats-v7-0-1e1558adfefc@ideasonboard.com>

Add new DRM pixel formats and add support for those in the Xilinx zynqmp
display driver.

All other formats except XVUY2101010 are already supported in upstream
gstreamer, but gstreamer's kmssink does not have the support yet, as it
obviously cannot support the formats without kernel having the formats.

Xilinx has support for these formats in their BSP kernel, and Xilinx has
a branch here, adding the support to gstreamer kmssink:

https://github.com/Xilinx/gst-plugins-bad.git xlnx-rebase-v1.18.5

New formats added:

DRM_FORMAT_Y8
- 8-bit Y-only
- fourcc: "GREY"
- gstreamer: GRAY8

DRM_FORMAT_Y10_P32
- 10-bit Y-only, three pixels packed into 32-bits
- fourcc: "YPA4"
- gstreamer: GRAY10_LE32

DRM_FORMAT_XV15
- Like NV12, but with 10-bit components
- fourcc: "XV15"
- gstreamer: NV12_10LE32

DRM_FORMAT_XV20
- Like NV16, but with 10-bit components
- fourcc: "XV20"
- gstreamer: NV16_10LE32

DRM_FORMAT_X403
- 10-bit planar 4:4:4, with three samples packed into 32-bits
- fourcc: "X403"
- gstreamer: Y444_10LE32

XVUY2101010
- 10-bit 4:4:4, one pixel in 32 bits
- fourcc: "XY30"

Some notes:

I know the 8-bit greyscale format has been discussed before, and the
guidance was to use DRM_FORMAT_R8. While I'm not totally against that, I
would argue that adding DRM_FORMAT_Y8 makes sense, as:

1) We can mark it as 'is_yuv' in the drm_format_info, and this can help
   the drivers handle e.g. full/limited range. Probably some hardware
   handles grayscale as a value used for all RGB components, in which case
   R8 makes sense, but when the hardware handles the Y-only pixels as YCbCr,
   where Cb and Cr are "neutral", it makes more sense to consider the
   format as an YUV format rather than RGB.

2) We can have the same fourcc as in v4l2. While not strictly necessary,
   it's a constant source of confusion when the fourccs differ.

3) It (possibly) makes more sense for the user to use Y8/GREY format
   instead of R8, as, in my experience, the documentation usually refers
   to gray(scale) format or Y-only format.

As we add new Y-only formats, it makes sense to have similar terms, so
we need to adjust the Y10_P32 format name accordingly.

I have made some adjustments to the formats compared to the Xilinx's
branch. E.g. The DRM_FORMAT_Y10_P32 format in Xilinx's kmssink uses
fourcc "Y10 ", and DRM_FORMAT_Y10. I didn't like those, as the format is
a packed format, three 10-bit pixels in a 32-bit container, and I think
Y10 means a 10-bit pixel in a 16-bit container.

Generally speaking, if someone has good ideas for the format define
names or fourccs, speak up, as it's not easy to invent good names =).
That said, keeping them the same as in the Xilinx trees will, of course,
be slightly easier for the users of Xilinx platforms.

I made WIP additions to modetest to support most of these formats,
partially based on Xilinx's code:

https://github.com/tomba/libdrm.git xilinx

A few thoughts about that:

modetest uses bo_create_dumb(), and as highlighted in recent discussions
in the kernel list [1], dumb buffers are only for RGB formats. They may
work for non-RGB formats, but that's platform specific. None of the
formats I add here are RGB formats. Do we want to go this way with
modetest?

I also feel that the current structure of modetest is not well suited to
more complicated formats. Both the buffer allocation is a bit more
difficult (see "Add virtual_width and pixels_per_container"), and the
drawing is complicated (see, e.g., "Add support for DRM_FORMAT_XV15 &
DRM_FORMAT_XV20").

I have recently added support for these Xilinx formats to both kms++ [2] and
pykms/pixutils [3][4] (WIP), and it's not been easy... But I have to say I
think I like the template based version in kms++. That won't work in
modetest, of course, but a non-templated version might be implementable,
but probably much slower.

In any case, I slighly feel it's not worth merging the modetest patches
I have for these formats: they complicate the code quite a bit, break
the RGB-only rule, and I'm not sure if there really are (m)any users. If
we want to add support to modetest, I think a bigger rewrite of the test
pattern code might be in order.

[1] https://lore.kernel.org/all/20250109150310.219442-26-tzimmermann%40suse.de/
[2] git at github.com:tomba/kmsxx.git xilinx
[3] git at github.com:tomba/pykms.git xilinx
[4] git at github.com:tomba/pixutils.git xilinx

Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
---
Changes in v7:
- Added Reviewed-bys
- Rebased on v6.18
- Link to v6: https://lore.kernel.org/r/20251001-xilinx-formats-v6-0-014b076b542a at ideasonboard.com

Changes in v6:
- Added tags for reviews
- Rebased on v6.17
- Link to v5: https://lore.kernel.org/r/20250425-xilinx-formats-v5-0-c74263231630 at ideasonboard.com

Changes in v5:
- Add comment about Y-only formats, clarifying how the display pipeline
  handles them (they're handled as YCbCr, with Cb and Cr as "neutral")
- Clarify X403 format in the patch description
- Set unused Y-only CSC offsets to 0 (instead of 0x1800).
- Add R-bs
- Link to v4: https://lore.kernel.org/r/20250326-xilinx-formats-v4-0-322a300c6d72 at ideasonboard.com

Changes in v4:
- Reformat the drm_format_info entries a bit
- Calculate block size only once in drm_format_info_bpp()
- Declare local variables in separate lines
- Add review tags
- Fix commit message referring to Y10_LE32 (should be Y10_P32)
- Link to v3: https://lore.kernel.org/r/20250212-xilinx-formats-v3-0-90d0fe106995 at ideasonboard.com

Changes in v3:
- Drop "drm: xlnx: zynqmp: Fix max dma segment size". It is already
  pushed.
- Add XVUY2101010 format.
- Rename DRM_FORMAT_Y10_LE32 to DRM_FORMAT_Y10_P32.
- Link to v2: https://lore.kernel.org/r/20250115-xilinx-formats-v2-0-160327ca652a at ideasonboard.com

Changes in v2:
- I noticed V4L2 already has fourcc Y10P, referring to MIPI-style packed
  Y10 format. So I changed Y10_LE32 fourcc to YPA4. If logic has any
  relevance here, P means packed, A means 10, 4 means "in 4 bytes".
- Added tags to "Fix max dma segment size" patch
- Updated description for "Add warning for bad bpp"
- Link to v1: https://lore.kernel.org/r/20241204-xilinx-formats-v1-0-0bf2c5147db1 at ideasonboard.com

---
Tomi Valkeinen (11):
      drm/fourcc: Add warning for bad bpp
      drm/fourcc: Add DRM_FORMAT_XV15/XV20
      drm/fourcc: Add DRM_FORMAT_Y8
      drm/fourcc: Add DRM_FORMAT_Y10_P32
      drm/fourcc: Add DRM_FORMAT_X403
      drm/fourcc: Add DRM_FORMAT_XVUY2101010
      drm: xlnx: zynqmp: Use drm helpers when calculating buffer sizes
      drm: xlnx: zynqmp: Add support for XV15 & XV20
      drm: xlnx: zynqmp: Add support for Y8 and Y10_P32
      drm: xlnx: zynqmp: Add support for X403
      drm: xlnx: zynqmp: Add support for XVUY2101010

 drivers/gpu/drm/drm_fourcc.c       | 28 ++++++++++++++++---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 55 +++++++++++++++++++++++++++++++++++---
 include/uapi/drm/drm_fourcc.h      | 29 ++++++++++++++++++++
 3 files changed, 105 insertions(+), 7 deletions(-)
---
base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
change-id: 20241120-xilinx-formats-f71901621833

Best regards,
-- 
Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>



From tomi.valkeinen at ideasonboard.com  Mon Dec  1 04:18:45 2025
From: tomi.valkeinen at ideasonboard.com (Tomi Valkeinen)
Date: Mon, 01 Dec 2025 14:18:45 +0200
Subject: [PATCH v7 03/11] drm/fourcc: Add DRM_FORMAT_Y8
In-Reply-To: <20251201-xilinx-formats-v7-0-1e1558adfefc@ideasonboard.com>
References: <20251201-xilinx-formats-v7-0-1e1558adfefc@ideasonboard.com>
Message-ID: <20251201-xilinx-formats-v7-3-1e1558adfefc@ideasonboard.com>

Add greyscale Y8 format.

Acked-by: Dmitry Baryshkov <dmitry.baryshkov at linaro.org>
Reviewed-by: Pekka Paalanen <pekka.paalanen at collabora.com>
Reviewed-by: Vishal Sagar <vishal.sagar at amd.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
---
 drivers/gpu/drm/drm_fourcc.c  |  1 +
 include/uapi/drm/drm_fourcc.h | 10 ++++++++++
 2 files changed, 11 insertions(+)

diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
index b22ef86428a1..a39b9d7a5b62 100644
--- a/drivers/gpu/drm/drm_fourcc.c
+++ b/drivers/gpu/drm/drm_fourcc.c
@@ -275,6 +275,7 @@ const struct drm_format_info *__drm_format_info(u32 format)
 		{ .format = DRM_FORMAT_YVU422,		.depth = 0,  .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 1, .is_yuv = true },
 		{ .format = DRM_FORMAT_YUV444,		.depth = 0,  .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 1, .vsub = 1, .is_yuv = true },
 		{ .format = DRM_FORMAT_YVU444,		.depth = 0,  .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 1, .vsub = 1, .is_yuv = true },
+		{ .format = DRM_FORMAT_Y8,		.depth = 8,  .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true },
 		{ .format = DRM_FORMAT_NV12,		.depth = 0,  .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2, .is_yuv = true },
 		{ .format = DRM_FORMAT_NV21,		.depth = 0,  .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2, .is_yuv = true },
 		{ .format = DRM_FORMAT_NV16,		.depth = 0,  .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
index 6c786701238e..5cfc188c4e72 100644
--- a/include/uapi/drm/drm_fourcc.h
+++ b/include/uapi/drm/drm_fourcc.h
@@ -459,6 +459,16 @@ extern "C" {
 #define DRM_FORMAT_YUV444	fourcc_code('Y', 'U', '2', '4') /* non-subsampled Cb (1) and Cr (2) planes */
 #define DRM_FORMAT_YVU444	fourcc_code('Y', 'V', '2', '4') /* non-subsampled Cr (1) and Cb (2) planes */
 
+/*
+ * Y-only (greyscale) formats
+ *
+ * The Y-only formats are handled similarly to the YCbCr formats in the display
+ * pipeline, with the Cb and Cr implicitly neutral (0.0 in nominal values). This
+ * also means that COLOR_RANGE property applies to the Y-only formats.
+ *
+ */
+
+#define DRM_FORMAT_Y8		fourcc_code('G', 'R', 'E', 'Y')  /* 8-bit Y-only */
 
 /*
  * Format Modifiers:

-- 
2.43.0



From tomi.valkeinen at ideasonboard.com  Mon Dec  1 04:18:44 2025
From: tomi.valkeinen at ideasonboard.com (Tomi Valkeinen)
Date: Mon, 01 Dec 2025 14:18:44 +0200
Subject: [PATCH v7 02/11] drm/fourcc: Add DRM_FORMAT_XV15/XV20
In-Reply-To: <20251201-xilinx-formats-v7-0-1e1558adfefc@ideasonboard.com>
References: <20251201-xilinx-formats-v7-0-1e1558adfefc@ideasonboard.com>
Message-ID: <20251201-xilinx-formats-v7-2-1e1558adfefc@ideasonboard.com>

Add two new pixel formats:

DRM_FORMAT_XV15 ("XV15")
DRM_FORMAT_XV20 ("XV20")

The formats are 2 plane 10 bit per component YCbCr, with the XV15 2x2
subsampled whereas XV20 is 2x1 subsampled.

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at linaro.org>
Reviewed-by: Vishal Sagar <vishal.sagar at amd.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
---
 drivers/gpu/drm/drm_fourcc.c  | 6 ++++++
 include/uapi/drm/drm_fourcc.h | 8 ++++++++
 2 files changed, 14 insertions(+)

diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
index e662aea9d105..b22ef86428a1 100644
--- a/drivers/gpu/drm/drm_fourcc.c
+++ b/drivers/gpu/drm/drm_fourcc.c
@@ -381,6 +381,12 @@ const struct drm_format_info *__drm_format_info(u32 format)
 		{ .format = DRM_FORMAT_S416,            .depth = 0,  .num_planes = 3,
 		  .char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 },
 		  .hsub = 1, .vsub = 1, .is_yuv = true},
+		{ .format = DRM_FORMAT_XV15,		.depth = 0,  .num_planes = 2,
+		  .char_per_block = { 4, 8, 0 }, .block_w = { 3, 3, 0 }, .block_h = { 1, 1, 0 },
+		  .hsub = 2, .vsub = 2, .is_yuv = true },
+		{ .format = DRM_FORMAT_XV20,		.depth = 0,  .num_planes = 2,
+		  .char_per_block = { 4, 8, 0 }, .block_w = { 3, 3, 0 }, .block_h = { 1, 1, 0 },
+		  .hsub = 2, .vsub = 1, .is_yuv = true },
 	};
 
 	unsigned int i;
diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
index e527b24bd824..6c786701238e 100644
--- a/include/uapi/drm/drm_fourcc.h
+++ b/include/uapi/drm/drm_fourcc.h
@@ -322,6 +322,14 @@ extern "C" {
 #define DRM_FORMAT_RGB565_A8	fourcc_code('R', '5', 'A', '8')
 #define DRM_FORMAT_BGR565_A8	fourcc_code('B', '5', 'A', '8')
 
+/*
+ * 2 plane 10 bit per component YCrCb
+ * index 0 = Y plane, [31:0] x:Y2:Y1:Y0 2:10:10:10 little endian
+ * index 1 = Cb:Cr plane, [63:0] x:Cr2:Cb2:Cr1:x:Cb1:Cr0:Cb0 2:10:10:10:2:10:10:10 little endian
+ */
+#define DRM_FORMAT_XV15		fourcc_code('X', 'V', '1', '5') /* 2x2 subsampled Cr:Cb plane 2:10:10:10 */
+#define DRM_FORMAT_XV20		fourcc_code('X', 'V', '2', '0') /* 2x1 subsampled Cr:Cb plane 2:10:10:10 */
+
 /*
  * 2 plane YCbCr
  * index 0 = Y plane, [7:0] Y

-- 
2.43.0



From tomi.valkeinen at ideasonboard.com  Mon Dec  1 04:18:46 2025
From: tomi.valkeinen at ideasonboard.com (Tomi Valkeinen)
Date: Mon, 01 Dec 2025 14:18:46 +0200
Subject: [PATCH v7 04/11] drm/fourcc: Add DRM_FORMAT_Y10_P32
In-Reply-To: <20251201-xilinx-formats-v7-0-1e1558adfefc@ideasonboard.com>
References: <20251201-xilinx-formats-v7-0-1e1558adfefc@ideasonboard.com>
Message-ID: <20251201-xilinx-formats-v7-4-1e1558adfefc@ideasonboard.com>

Add Y10_P32, a 10 bit greyscale format, with 3 pixels packed into
32-bit container.

The fourcc for the format is 'YPA4', which comes from Y - Y only, P -
packed, A - 10 (as in 0xA), 4 - 4 bytes.

Reviewed-by: Vishal Sagar <vishal.sagar at amd.com>
Reviewed-by: Pekka Paalanen <pekka.paalanen at collabora.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
---
 drivers/gpu/drm/drm_fourcc.c  | 3 +++
 include/uapi/drm/drm_fourcc.h | 1 +
 2 files changed, 4 insertions(+)

diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
index a39b9d7a5b62..0d222f6c1a30 100644
--- a/drivers/gpu/drm/drm_fourcc.c
+++ b/drivers/gpu/drm/drm_fourcc.c
@@ -388,6 +388,9 @@ const struct drm_format_info *__drm_format_info(u32 format)
 		{ .format = DRM_FORMAT_XV20,		.depth = 0,  .num_planes = 2,
 		  .char_per_block = { 4, 8, 0 }, .block_w = { 3, 3, 0 }, .block_h = { 1, 1, 0 },
 		  .hsub = 2, .vsub = 1, .is_yuv = true },
+		{ .format = DRM_FORMAT_Y10_P32,		.depth = 0,  .num_planes = 1,
+		  .char_per_block = { 4, 0, 0 }, .block_w = { 3, 0, 0 }, .block_h = { 1, 0, 0 },
+		  .hsub = 1, .vsub = 1, .is_yuv = true },
 	};
 
 	unsigned int i;
diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
index 5cfc188c4e72..0fd99ae32a06 100644
--- a/include/uapi/drm/drm_fourcc.h
+++ b/include/uapi/drm/drm_fourcc.h
@@ -469,6 +469,7 @@ extern "C" {
  */
 
 #define DRM_FORMAT_Y8		fourcc_code('G', 'R', 'E', 'Y')  /* 8-bit Y-only */
+#define DRM_FORMAT_Y10_P32	fourcc_code('Y', 'P', 'A', '4')  /* [31:0] x:Y2:Y1:Y0 2:10:10:10 little endian */
 
 /*
  * Format Modifiers:

-- 
2.43.0



From tomi.valkeinen at ideasonboard.com  Mon Dec  1 04:18:48 2025
From: tomi.valkeinen at ideasonboard.com (Tomi Valkeinen)
Date: Mon, 01 Dec 2025 14:18:48 +0200
Subject: [PATCH v7 06/11] drm/fourcc: Add DRM_FORMAT_XVUY2101010
In-Reply-To: <20251201-xilinx-formats-v7-0-1e1558adfefc@ideasonboard.com>
References: <20251201-xilinx-formats-v7-0-1e1558adfefc@ideasonboard.com>
Message-ID: <20251201-xilinx-formats-v7-6-1e1558adfefc@ideasonboard.com>

Add XVUY2101010, a 10 bits per component YCbCr format in a 32 bit
container.

Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
Reviewed-by: Vishal Sagar <vishal.sagar at amd.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
---
 drivers/gpu/drm/drm_fourcc.c  | 1 +
 include/uapi/drm/drm_fourcc.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
index ab643dedd6d4..a736df2de3fc 100644
--- a/drivers/gpu/drm/drm_fourcc.c
+++ b/drivers/gpu/drm/drm_fourcc.c
@@ -288,6 +288,7 @@ const struct drm_format_info *__drm_format_info(u32 format)
 		{ .format = DRM_FORMAT_VYUY,		.depth = 0,  .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
 		{ .format = DRM_FORMAT_XYUV8888,	.depth = 0,  .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true },
 		{ .format = DRM_FORMAT_VUY888,          .depth = 0,  .num_planes = 1, .cpp = { 3, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true },
+		{ .format = DRM_FORMAT_XVUY2101010,     .depth = 0,  .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true },
 		{ .format = DRM_FORMAT_AYUV,		.depth = 0,  .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true, .is_yuv = true },
 		{ .format = DRM_FORMAT_Y210,            .depth = 0,  .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
 		{ .format = DRM_FORMAT_Y212,            .depth = 0,  .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
index abe6af8b5ac4..ce28faf7ad75 100644
--- a/include/uapi/drm/drm_fourcc.h
+++ b/include/uapi/drm/drm_fourcc.h
@@ -264,6 +264,7 @@ extern "C" {
 #define DRM_FORMAT_XVUY8888	fourcc_code('X', 'V', 'U', 'Y') /* [31:0] X:Cr:Cb:Y 8:8:8:8 little endian */
 #define DRM_FORMAT_VUY888	fourcc_code('V', 'U', '2', '4') /* [23:0] Cr:Cb:Y 8:8:8 little endian */
 #define DRM_FORMAT_VUY101010	fourcc_code('V', 'U', '3', '0') /* Y followed by U then V, 10:10:10. Non-linear modifier only */
+#define DRM_FORMAT_XVUY2101010	fourcc_code('X', 'Y', '3', '0') /* [31:0] x:Cr:Cb:Y 2:10:10:10 little endian */
 
 /*
  * packed Y2xx indicate for each component, xx valid data occupy msb

-- 
2.43.0



From tomi.valkeinen at ideasonboard.com  Mon Dec  1 04:18:50 2025
From: tomi.valkeinen at ideasonboard.com (Tomi Valkeinen)
Date: Mon, 01 Dec 2025 14:18:50 +0200
Subject: [PATCH v7 08/11] drm: xlnx: zynqmp: Add support for XV15 & XV20
In-Reply-To: <20251201-xilinx-formats-v7-0-1e1558adfefc@ideasonboard.com>
References: <20251201-xilinx-formats-v7-0-1e1558adfefc@ideasonboard.com>
Message-ID: <20251201-xilinx-formats-v7-8-1e1558adfefc@ideasonboard.com>

Add support for XV15 & XV20 formats.

Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
Reviewed-by: Vishal Sagar <vishal.sagar at amd.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index b9883ea2d03e..1dc77f2e4262 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -297,6 +297,16 @@ static const struct zynqmp_disp_format avbuf_vid_fmts[] = {
 		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI_420,
 		.swap		= true,
 		.sf		= scaling_factors_888,
+	}, {
+		.drm_fmt	= DRM_FORMAT_XV15,
+		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI_420_10,
+		.swap		= false,
+		.sf		= scaling_factors_101010,
+	}, {
+		.drm_fmt	= DRM_FORMAT_XV20,
+		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI_10,
+		.swap		= false,
+		.sf		= scaling_factors_101010,
 	},
 };
 

-- 
2.43.0



From tomi.valkeinen at ideasonboard.com  Mon Dec  1 04:18:49 2025
From: tomi.valkeinen at ideasonboard.com (Tomi Valkeinen)
Date: Mon, 01 Dec 2025 14:18:49 +0200
Subject: [PATCH v7 07/11] drm: xlnx: zynqmp: Use drm helpers when
 calculating buffer sizes
In-Reply-To: <20251201-xilinx-formats-v7-0-1e1558adfefc@ideasonboard.com>
References: <20251201-xilinx-formats-v7-0-1e1558adfefc@ideasonboard.com>
Message-ID: <20251201-xilinx-formats-v7-7-1e1558adfefc@ideasonboard.com>

Use drm helpers, drm_format_info_plane_width(),
drm_format_info_plane_height() and drm_format_info_min_pitch() to
calculate sizes for the DMA.

This cleans up the code, but also makes it possible to support more
complex formats (like XV15, XV20).

Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index 80d1e499a18d..b9883ea2d03e 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -1116,16 +1116,19 @@ int zynqmp_disp_layer_update(struct zynqmp_disp_layer *layer,
 		return 0;
 
 	for (i = 0; i < info->num_planes; i++) {
-		unsigned int width = state->crtc_w / (i ? info->hsub : 1);
-		unsigned int height = state->crtc_h / (i ? info->vsub : 1);
 		struct zynqmp_disp_layer_dma *dma = &layer->dmas[i];
 		struct dma_async_tx_descriptor *desc;
 		dma_addr_t dma_addr;
+		unsigned int width;
+		unsigned int height;
+
+		width = drm_format_info_plane_width(info, state->crtc_w, i);
+		height = drm_format_info_plane_height(info, state->crtc_h, i);
 
 		dma_addr = drm_fb_dma_get_gem_addr(state->fb, state, i);
 
 		dma->xt.numf = height;
-		dma->sgl.size = width * info->cpp[i];
+		dma->sgl.size = drm_format_info_min_pitch(info, i, width);
 		dma->sgl.icg = state->fb->pitches[i] - dma->sgl.size;
 		dma->xt.src_start = dma_addr;
 		dma->xt.frame_size = 1;

-- 
2.43.0



From tomi.valkeinen at ideasonboard.com  Mon Dec  1 04:18:52 2025
From: tomi.valkeinen at ideasonboard.com (Tomi Valkeinen)
Date: Mon, 01 Dec 2025 14:18:52 +0200
Subject: [PATCH v7 10/11] drm: xlnx: zynqmp: Add support for X403
In-Reply-To: <20251201-xilinx-formats-v7-0-1e1558adfefc@ideasonboard.com>
References: <20251201-xilinx-formats-v7-0-1e1558adfefc@ideasonboard.com>
Message-ID: <20251201-xilinx-formats-v7-10-1e1558adfefc@ideasonboard.com>

Add support for X403 format.

Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
Reviewed-by: Vishal Sagar <vishal.sagar at amd.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index fe111fa8cc13..b7cc7a7581ad 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -317,6 +317,11 @@ static const struct zynqmp_disp_format avbuf_vid_fmts[] = {
 		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YONLY_10,
 		.swap		= false,
 		.sf		= scaling_factors_101010,
+	}, {
+		.drm_fmt	= DRM_FORMAT_X403,
+		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV24_10,
+		.swap		= false,
+		.sf		= scaling_factors_101010,
 	},
 };
 

-- 
2.43.0



From tomi.valkeinen at ideasonboard.com  Mon Dec  1 04:18:51 2025
From: tomi.valkeinen at ideasonboard.com (Tomi Valkeinen)
Date: Mon, 01 Dec 2025 14:18:51 +0200
Subject: [PATCH v7 09/11] drm: xlnx: zynqmp: Add support for Y8 and Y10_P32
In-Reply-To: <20251201-xilinx-formats-v7-0-1e1558adfefc@ideasonboard.com>
References: <20251201-xilinx-formats-v7-0-1e1558adfefc@ideasonboard.com>
Message-ID: <20251201-xilinx-formats-v7-9-1e1558adfefc@ideasonboard.com>

Add support for Y8 and Y10_P32 formats. We also need to add new csc
matrices for the y-only formats.

Reviewed-by: Vishal Sagar <vishal.sagar at amd.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 26 +++++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index 1dc77f2e4262..fe111fa8cc13 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -307,6 +307,16 @@ static const struct zynqmp_disp_format avbuf_vid_fmts[] = {
 		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI_10,
 		.swap		= false,
 		.sf		= scaling_factors_101010,
+	}, {
+		.drm_fmt	= DRM_FORMAT_Y8,
+		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_MONO,
+		.swap		= false,
+		.sf		= scaling_factors_888,
+	}, {
+		.drm_fmt	= DRM_FORMAT_Y10_P32,
+		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YONLY_10,
+		.swap		= false,
+		.sf		= scaling_factors_101010,
 	},
 };
 
@@ -697,6 +707,16 @@ static const u32 csc_sdtv_to_rgb_offsets[] = {
 	0x0, 0x1800, 0x1800
 };
 
+static const u16 csc_sdtv_to_rgb_yonly_matrix[] = {
+	0x0, 0x0, 0x1000,
+	0x0, 0x0, 0x1000,
+	0x0, 0x0, 0x1000,
+};
+
+static const u32 csc_sdtv_to_rgb_yonly_offsets[] = {
+	0x0, 0x0, 0x0
+};
+
 /**
  * zynqmp_disp_blend_set_output_format - Set the output format of the blender
  * @disp: Display controller
@@ -846,7 +866,11 @@ static void zynqmp_disp_blend_layer_enable(struct zynqmp_disp *disp,
 				ZYNQMP_DISP_V_BLEND_LAYER_CONTROL(layer->id),
 				val);
 
-	if (layer->drm_fmt->is_yuv) {
+	if (layer->drm_fmt->format == DRM_FORMAT_Y8 ||
+	    layer->drm_fmt->format == DRM_FORMAT_Y10_P32) {
+		coeffs = csc_sdtv_to_rgb_yonly_matrix;
+		offsets = csc_sdtv_to_rgb_yonly_offsets;
+	} else if (layer->drm_fmt->is_yuv) {
 		coeffs = csc_sdtv_to_rgb_matrix;
 		offsets = csc_sdtv_to_rgb_offsets;
 	} else {

-- 
2.43.0



From tomi.valkeinen at ideasonboard.com  Mon Dec  1 04:18:53 2025
From: tomi.valkeinen at ideasonboard.com (Tomi Valkeinen)
Date: Mon, 01 Dec 2025 14:18:53 +0200
Subject: [PATCH v7 11/11] drm: xlnx: zynqmp: Add support for XVUY2101010
In-Reply-To: <20251201-xilinx-formats-v7-0-1e1558adfefc@ideasonboard.com>
References: <20251201-xilinx-formats-v7-0-1e1558adfefc@ideasonboard.com>
Message-ID: <20251201-xilinx-formats-v7-11-1e1558adfefc@ideasonboard.com>

Add support for XVUY2101010 format.

Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
Reviewed-by: Vishal Sagar <vishal.sagar at amd.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index b7cc7a7581ad..f548f375750e 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -322,6 +322,11 @@ static const struct zynqmp_disp_format avbuf_vid_fmts[] = {
 		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV24_10,
 		.swap		= false,
 		.sf		= scaling_factors_101010,
+	}, {
+		.drm_fmt	= DRM_FORMAT_XVUY2101010,
+		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YUV444_10,
+		.swap		= false,
+		.sf		= scaling_factors_101010,
 	},
 };
 

-- 
2.43.0



From tomi.valkeinen at ideasonboard.com  Mon Dec  1 04:18:47 2025
From: tomi.valkeinen at ideasonboard.com (Tomi Valkeinen)
Date: Mon, 01 Dec 2025 14:18:47 +0200
Subject: [PATCH v7 05/11] drm/fourcc: Add DRM_FORMAT_X403
In-Reply-To: <20251201-xilinx-formats-v7-0-1e1558adfefc@ideasonboard.com>
References: <20251201-xilinx-formats-v7-0-1e1558adfefc@ideasonboard.com>
Message-ID: <20251201-xilinx-formats-v7-5-1e1558adfefc@ideasonboard.com>

Add X403, a 3 plane 10 bits per component non-subsampled YCbCr format.

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Reviewed-by: Vishal Sagar <vishal.sagar at amd.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
---
 drivers/gpu/drm/drm_fourcc.c  | 3 +++
 include/uapi/drm/drm_fourcc.h | 9 +++++++++
 2 files changed, 12 insertions(+)

diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
index 0d222f6c1a30..ab643dedd6d4 100644
--- a/drivers/gpu/drm/drm_fourcc.c
+++ b/drivers/gpu/drm/drm_fourcc.c
@@ -391,6 +391,9 @@ const struct drm_format_info *__drm_format_info(u32 format)
 		{ .format = DRM_FORMAT_Y10_P32,		.depth = 0,  .num_planes = 1,
 		  .char_per_block = { 4, 0, 0 }, .block_w = { 3, 0, 0 }, .block_h = { 1, 0, 0 },
 		  .hsub = 1, .vsub = 1, .is_yuv = true },
+		{ .format = DRM_FORMAT_X403,		.depth = 0,  .num_planes = 3,
+		  .char_per_block = { 4, 4, 4 }, .block_w = { 3, 3, 3 }, .block_h = { 1, 1, 1 },
+		  .hsub = 1, .vsub = 1, .is_yuv = true },
 	};
 
 	unsigned int i;
diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
index 0fd99ae32a06..abe6af8b5ac4 100644
--- a/include/uapi/drm/drm_fourcc.h
+++ b/include/uapi/drm/drm_fourcc.h
@@ -403,6 +403,15 @@ extern "C" {
  */
 #define DRM_FORMAT_Q401		fourcc_code('Q', '4', '0', '1')
 
+/*
+ * 3 plane non-subsampled (444) YCbCr
+ * 10 bpc, 30 bits per sample image data in a single contiguous buffer.
+ * index 0: Y plane,  [31:0] x:Y2:Y1:Y0    [2:10:10:10] little endian
+ * index 1: Cb plane, [31:0] x:Cb2:Cb1:Cb0 [2:10:10:10] little endian
+ * index 2: Cr plane, [31:0] x:Cr2:Cr1:Cr0 [2:10:10:10] little endian
+ */
+#define DRM_FORMAT_X403		fourcc_code('X', '4', '0', '3')
+
 /*
  * 3 plane YCbCr LSB aligned
  * In order to use these formats in a similar fashion to MSB aligned ones

-- 
2.43.0



From edumazet at google.com  Mon Dec  1 04:21:11 2025
From: edumazet at google.com (Eric Dumazet)
Date: Mon, 1 Dec 2025 04:21:11 -0800
Subject: [PATCH] net: stmmac: Modify the judgment condition of "tx_avail"
 from 1 to 2
In-Reply-To: <tencent_22959DC8315158E23D77C14B9B33C97EA60A@qq.com>
References: <tencent_22959DC8315158E23D77C14B9B33C97EA60A@qq.com>
Message-ID: <CANn89iLW+68YE9s9dChEcQYbmwXSBzWRPzFH50+--Kw3XNZXEQ@mail.gmail.com>

On Sun, Nov 30, 2025 at 6:57?PM <2694439648 at qq.com> wrote:
>
> From: "hailong.fan" <hailong.fan at siengine.com>
>
>     Under certain conditions, a WARN_ON will be triggered
>     if avail equals 1.
>
>     For example, when a VLAN packet is to send,
>     stmmac_vlan_insert consumes one unit of space,
>     and the data itself consumes another.
>     actually requiring 2 units of space in total.
>
> Signed-off-by: hailong.fan <hailong.fan at siengine.com>
> ---
>  drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index 7b90ecd3a..b575384cd 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -4529,7 +4529,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
>                 }
>         }
>
> -       if (unlikely(stmmac_tx_avail(priv, queue) < nfrags + 1)) {
> +       if (unlikely(stmmac_tx_avail(priv, queue) < nfrags + 2)) {
>                 if (!netif_tx_queue_stopped(netdev_get_tx_queue(dev, queue))) {
>                         netif_tx_stop_queue(netdev_get_tx_queue(priv->dev,
>                                                                 queue));

Drivers should stop their queues earlier.

NETDEV_TX_BUSY is almost always wrong.

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 7b90ecd3a55e600458b0c87d6125831626f4683d..6dcc7b84a8759763b6471a48a6c80b1f17cd937c
100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -4675,7 +4675,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff
*skb, struct net_device *dev)
                print_pkt(skb->data, skb->len);
        }

-       if (unlikely(stmmac_tx_avail(priv, queue) <= (MAX_SKB_FRAGS + 1))) {
+       if (unlikely(stmmac_tx_avail(priv, queue) <= (MAX_SKB_FRAGS + 2))) {
                netif_dbg(priv, hw, priv->dev, "%s: stop transmitted packets\n",
                          __func__);
                netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, queue));


From robh at kernel.org  Mon Dec  1 04:27:01 2025
From: robh at kernel.org (Rob Herring)
Date: Mon, 01 Dec 2025 06:27:01 -0600
Subject: [PATCH v4 0/2] ARM: add support for pcb8385
In-Reply-To: <20251201082629.2326339-1-horatiu.vultur@microchip.com>
References: <20251201082629.2326339-1-horatiu.vultur@microchip.com>
Message-ID: <176459099710.2909214.17458039501550116582.robh@kernel.org>


On Mon, 01 Dec 2025 09:26:27 +0100, Horatiu Vultur wrote:
> Add pcb8385 and the documentation for it.
> This is a moduler board on which it can add different daughter cards.
> 
> v3->v4:
> - override i2c0 using labels instead of having it under flx0
> - override usart3 using labels instead of having it under flx3
> 
> v2->v3:
> - remove the linux,default-trigger properties
> 
> v1->v2:
> - sort nodes in alphanumerical order
> - move the eeprom nodes under i2c0
> 
> Horatiu Vultur (2):
>   dt-bindings: arm: at91: add lan966 pcb8385 board
>   ARM: dts: Add support for pcb8385
> 
>  .../devicetree/bindings/arm/atmel-at91.yaml   |   6 +-
>  arch/arm/boot/dts/microchip/Makefile          |   3 +-
>  .../boot/dts/microchip/lan966x-pcb8385.dts    | 131 ++++++++++++++++++
>  3 files changed, 137 insertions(+), 3 deletions(-)
>  create mode 100644 arch/arm/boot/dts/microchip/lan966x-pcb8385.dts
> 
> --
> 2.34.1
> 
> 
> 


My bot found new DTB warnings on the .dts files added or changed in this
series.

Some warnings may be from an existing SoC .dtsi. Or perhaps the warnings
are fixed by another series. Ultimately, it is up to the platform
maintainer whether these warnings are acceptable or not. No need to reply
unless the platform maintainer has comments.

If you already ran DT checks and didn't see these error(s), then
make sure dt-schema is up to date:

  pip3 install dtschema --upgrade


This patch series was applied (using b4) to base:
 Base: attempting to guess base-commit...
 Base: tags/next-20251201 (exact match)
 Base: tags/next-20251201 (use --merge-base to override)

If this is not the correct base, please add 'base-commit' tag
(or use b4 which does this automatically)

New warnings running 'make CHECK_DTBS=y for arch/arm/boot/dts/microchip/' for 20251201082629.2326339-1-horatiu.vultur at microchip.com:

arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: /soc/usb at 200000: failed to match any schema with compatible: ['microchip,lan9662-udc', 'atmel,sama5d3-udc']
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: /soc/usb at 200000: failed to match any schema with compatible: ['microchip,lan9662-udc', 'atmel,sama5d3-udc']
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: serial at 200 (atmel,at91sam9260-usart): $nodename:0: 'serial at 200' does not match '^spi(@.*|-([0-9]|[1-9][0-9]+))?$'
	from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: serial at 200 (atmel,at91sam9260-usart): False schema does not allow 32
	from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: serial at 200 (atmel,at91sam9260-usart): $nodename:0: 'serial at 200' does not match '^spi(@.*|-([0-9]|[1-9][0-9]+))?$'
	from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: serial at 200 (atmel,at91sam9260-usart): False schema does not allow 32
	from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: rng at e0048000 (atmel,at91sam9g45-trng): 'oneOf' conditional failed, one must be fixed:
	'interrupts' is a required property
	'interrupts-extended' is a required property
	from schema $id: http://devicetree.org/schemas/rng/atmel,at91-trng.yaml
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: serial at 200 (atmel,at91sam9260-usart): $nodename:0: 'serial at 200' does not match '^spi(@.*|-([0-9]|[1-9][0-9]+))?$'
	from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: serial at 200 (atmel,at91sam9260-usart): False schema does not allow 32
	from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: serial at 200 (atmel,at91sam9260-usart): $nodename:0: 'serial at 200' does not match '^spi(@.*|-([0-9]|[1-9][0-9]+))?$'
	from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: serial at 200 (atmel,at91sam9260-usart): False schema does not allow 32
	from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: serial at 200 (atmel,at91sam9260-usart): '#size-cells' is a required property
	from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: serial at 200 (atmel,at91sam9260-usart): '#address-cells' is a required property
	from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: serial at 200 (atmel,at91sam9260-usart): 'atmel,usart-mode' is a required property
	from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: serial at 200 (atmel,at91sam9260-usart): $nodename:0: 'serial at 200' does not match '^spi(@.*|-([0-9]|[1-9][0-9]+))?$'
	from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: serial at 200 (atmel,at91sam9260-usart): False schema does not allow 32
	from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml







From robh at kernel.org  Mon Dec  1 04:27:02 2025
From: robh at kernel.org (Rob Herring)
Date: Mon, 01 Dec 2025 06:27:02 -0600
Subject: [PATCH v2 0/4] Add support for Ezurio MediaTek platforms
In-Reply-To: <20251201-review-v2-0-dc2df44eec7e@gmail.com>
References: <20251201-review-v2-0-dc2df44eec7e@gmail.com>
Message-ID: <176459099842.2909480.6224244901963014446.robh@kernel.org>


On Mon, 01 Dec 2025 11:23:14 +0100, Gary Bisson wrote:
> This series adds support for Ezurio MediaTek platforms called
> "Tungsten". It includes support for MT8370-based Tungsten 510 and
> MT8390-based Tungsten 700 SOMs.
> 
> Changelog v1 -> v2:
> - use b4 to cc all maintainers properly
> - squashed patches 2/3 together
> - updated node names to be generic (pmic)
> 
> Couldn't repro the schema issues sent by the bots.
> 
> Regards,
> 
> Gary Bisson (4):
>   dt-bindings: vendor-prefixes: Add Ezurio LLC
>   dt-bindings: arm: mediatek: Add Ezurio Tungsten entries
>   arm64: dts: mediatek: add device tree for Tungsten 510 board
>   arm64: dts: mediatek: add device tree for Tungsten 700 board
> 
>  .../devicetree/bindings/arm/mediatek.yaml     |    2 +
>  .../devicetree/bindings/vendor-prefixes.yaml  |    2 +
>  arch/arm64/boot/dts/mediatek/Makefile         |    2 +
>  .../dts/mediatek/mt8370-tungsten-smarc.dts    |   14 +
>  .../dts/mediatek/mt8390-tungsten-smarc.dts    |   22 +
>  .../dts/mediatek/mt83x0-tungsten-smarc.dtsi   | 1481 +++++++++++++++++
>  6 files changed, 1523 insertions(+)
>  create mode 100644 arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts
>  create mode 100644 arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts
>  create mode 100644 arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi
> 
> --
> 2.43.0
> 
> ---
> Gary Bisson (4):
>       dt-bindings: vendor-prefixes: Add Ezurio LLC
>       dt-bindings: arm: mediatek: Add Ezurio Tungsten entries
>       arm64: dts: mediatek: add device tree for Tungsten 510 board
>       arm64: dts: mediatek: add device tree for Tungsten 700 board
> 
>  .../devicetree/bindings/arm/mediatek.yaml          |    2 +
>  .../devicetree/bindings/vendor-prefixes.yaml       |    2 +
>  arch/arm64/boot/dts/mediatek/Makefile              |    2 +
>  .../boot/dts/mediatek/mt8370-tungsten-smarc.dts    |   14 +
>  .../boot/dts/mediatek/mt8390-tungsten-smarc.dts    |   22 +
>  .../boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi   | 1481 ++++++++++++++++++++
>  6 files changed, 1523 insertions(+)
> ---
> base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
> change-id: 20251201-review-750072579991
> 
> Best regards,
> --
> Gary Bisson <bisson.gary at gmail.com>
> 
> 
> 


My bot found new DTB warnings on the .dts files added or changed in this
series.

Some warnings may be from an existing SoC .dtsi. Or perhaps the warnings
are fixed by another series. Ultimately, it is up to the platform
maintainer whether these warnings are acceptable or not. No need to reply
unless the platform maintainer has comments.

If you already ran DT checks and didn't see these error(s), then
make sure dt-schema is up to date:

  pip3 install dtschema --upgrade


This patch series was applied (using b4) to base:
 Base: base-commit 7d0a66e4bb9081d75c82ec4957c50034cb0ea449 not known, ignoring
 Base: attempting to guess base-commit...
 Base: tags/v6.18-rc3 (exact match)
 Base: tags/v6.18-rc3 (use --merge-base to override)

If this is not the correct base, please add 'base-commit' tag
(or use b4 which does this automatically)

New warnings running 'make CHECK_DTBS=y for arch/arm64/boot/dts/mediatek/' for 20251201-review-v2-0-dc2df44eec7e at gmail.com:

arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: i2c0-gpio-pins: pins-gpio: {'pinmux': [1536], 'bias-pull-up': 203, 'drive-strength-microamp': [1000]} is not of type 'array'
	from schema $id: http://devicetree.org/schemas/gpio/gpio-consumer.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: pmic (mediatek,mt6359): '#sound-dai-cells' does not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/mfd/mediatek,mt6397.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): pmic at 6:reg:0: [6, 0, 11] is too long
	from schema $id: http://devicetree.org/schemas/spmi/mtk,spmi-mtk-pmif.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): #address-cells: 2 was expected
	from schema $id: http://devicetree.org/schemas/spmi/mtk,spmi-mtk-pmif.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): #size-cells: 0 was expected
	from schema $id: http://devicetree.org/schemas/spmi/mtk,spmi-mtk-pmif.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): Unevaluated properties are not allowed ('#address-cells', '#size-cells', 'pmic at 6' were unexpected)
	from schema $id: http://devicetree.org/schemas/spmi/mtk,spmi-mtk-pmif.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): pmic at 6:reg:0: [6, 0, 11] is too long
	from schema $id: http://devicetree.org/schemas/spmi/spmi.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): #address-cells: 2 was expected
	from schema $id: http://devicetree.org/schemas/spmi/spmi.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): #size-cells: 0 was expected
	from schema $id: http://devicetree.org/schemas/spmi/spmi.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: pmic at 6 (mediatek,mt6315-regulator): regulators:vbuck1: Unevaluated properties are not allowed ('mtk,combined-regulator', 'regulator-compatible' were unexpected)
	from schema $id: http://devicetree.org/schemas/regulator/mt6315-regulator.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: pmic at 6 (mediatek,mt6315-regulator): regulators:vbuck3: Unevaluated properties are not allowed ('regulator-compatible' was unexpected)
	from schema $id: http://devicetree.org/schemas/regulator/mt6315-regulator.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: pmic at 6 (mediatek,mt6315-regulator): regulators:vbuck4: Unevaluated properties are not allowed ('regulator-compatible' was unexpected)
	from schema $id: http://devicetree.org/schemas/regulator/mt6315-regulator.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: vbuck1: 'mtk,combined-regulator' does not match any of the regexes: '^#.*', '^(at25|bm|devbus|dmacap|dsa|exynos|fsi[ab]|gpio-fan|gpio-key|gpio|gpmc|hdmi|i2c-gpio),.*', '^(keypad|m25p|max8952|max8997|max8998|mpmc),.*', '^(pciclass|pinctrl-single|#pinctrl-single|PowerPC),.*', '^(pl022|pxa-mmc|rcar_sound|rotary-encoder|s5m8767|sdhci),.*', '^(simple-audio-card|st-plgpio|st-spics|ts),.*', '^100ask,.*', '^70mai,.*', '^8dev,.*', '^GEFanuc,.*', '^IBM,.*', '^ORCL,.*', '^SUNW,.*', '^[a-zA-Z0-9#_][a-zA-Z0-9#+\-._@]{0,63}$', '^[a-zA-Z0-9+\-._]*@[0-9a-zA-Z,]*$', '^abb,.*', '^abilis,.*', '^abracon,.*', '^abt,.*', '^acbel,.*', '^acelink,.*', '^acer,.*', '^acme,.*', '^actions,.*', '^actiontec,.*', '^active-semi,.*', '^ad,.*', '^adafruit,.*', '^adapteva,.*', '^adaptrum,.*', '^adh,.*', '^adi,.*', '^adieng,.*', '^admatec,.*', '^advantech,.*', '^aeroflexgaisler,.*', '^aesop,.*', '^airoha,.*', '^al,.*', '^alcatel,.*', '^aldec,.*', '^alfa-network,.*'
 , '^allegro,.*', '^allegromicro,.*', '^alliedtelesis,.*', '^alliedvision,.*', '^allo,.*', '^allwinner,.*', '^alphascale,.*', '^alps,.*', '^alt,.*', '^altr,.*', '^amarula,.*', '^amazon,.*', '^amcc,.*', '^amd,.*', '^amediatech,.*', '^amlogic,.*', '^ampere,.*', '^amphenol,.*', '^ampire,.*', '^ams,.*', '^amstaos,.*', '^analogix,.*', '^anbernic,.*', '^andestech,.*', '^anvo,.*', '^aoly,.*', '^aosong,.*', '^apm,.*', '^apple,.*', '^aptina,.*', '^arasan,.*', '^archermind,.*', '^arcom,.*', '^arctic,.*', '^arcx,.*', '^argon40,.*', '^ariaboard,.*', '^aries,.*', '^arm,.*', '^armadeus,.*', '^armsom,.*', '^arrow,.*', '^artesyn,.*', '^asahi-kasei,.*', '^asc,.*', '^asix,.*', '^aspeed,.*', '^asrock,.*', '^asteralabs,.*', '^asus,.*', '^atheros,.*', '^atlas,.*', '^atmel,.*', '^auo,.*', '^auvidea,.*', '^avago,.*', '^avia,.*', '^avic,.*', '^avnet,.*', '^awinic,.*', '^axentia,.*', '^axiado,.*', '^axis,.*', '^azoteq,.*', '^azw,.*', '^baikal,.*', '^bananapi,.*', '^beacon,.*', '^beagle,.*', '^belling,.*', '^
 bestar,.*', '^bhf,.*', '^bigtreetech,.*', '^bitmain,.*', '^blaize,.*', '^bluegiga,.*', '^blutek,.*', '^boe,.*', '^bosch,.*', '^boundary,.*', '^brcm,.*', '^broadmobi,.*', '^bsh,.*', '^bticino,.*', '^buffalo,.*', '^buglabs,.*', '^bur,.*', '^bytedance,.*', '^calamp,.*', '^calao,.*', '^calaosystems,.*', '^calxeda,.*', '^cameo,.*', '^canaan,.*', '^caninos,.*', '^capella,.*', '^cascoda,.*', '^catalyst,.*', '^cavium,.*', '^cct,.*', '^cdns,.*', '^cdtech,.*', '^cellwise,.*', '^ceva,.*', '^chargebyte,.*', '^checkpoint,.*', '^chefree,.*', '^chipidea,.*', '^chipone,.*', '^chipspark,.*', '^chongzhou,.*', '^chrontel,.*', '^chrp,.*', '^chunghwa,.*', '^chuwi,.*', '^ciaa,.*', '^cirrus,.*', '^cisco,.*', '^cix,.*', '^clockwork,.*', '^cloos,.*', '^cloudengines,.*', '^cnm,.*', '^cnxt,.*', '^colorfly,.*', '^compal,.*', '^compulab,.*', '^comvetia,.*', '^congatec,.*', '^coolpi,.*', '^coreriver,.*', '^corpro,.*', '^cortina,.*', '^cosmic,.*', '^crane,.*', '^creative,.*', '^crystalfontz,.*', '^csky,.*', '^cso
 t,.*', '^csq,.*', '^csr,.*', '^ctera,.*', '^ctu,.*', '^cubietech,.*', '^cudy,.*', '^cui,.*', '^cypress,.*', '^cyx,.*', '^cznic,.*', '^dallas,.*', '^dataimage,.*', '^davicom,.*', '^deepcomputing,.*', '^dell,.*', '^delta,.*', '^densitron,.*', '^denx,.*', '^devantech,.*', '^dfi,.*', '^dfrobot,.*', '^dh,.*', '^difrnce,.*', '^digi,.*', '^digilent,.*', '^dimonoff,.*', '^diodes,.*', '^dioo,.*', '^djn,.*', '^dlc,.*', '^dlg,.*', '^dlink,.*', '^dmo,.*', '^domintech,.*', '^dongwoon,.*', '^dptechnics,.*', '^dragino,.*', '^dream,.*', '^ds,.*', '^dserve,.*', '^dynaimage,.*', '^ea,.*', '^ebang,.*', '^ebbg,.*', '^ebs-systart,.*', '^ebv,.*', '^eckelmann,.*', '^econet,.*', '^edgeble,.*', '^edimax,.*', '^edt,.*', '^ees,.*', '^eeti,.*', '^egnite,.*', '^einfochips,.*', '^eink,.*', '^elan,.*', '^element14,.*', '^elgin,.*', '^elida,.*', '^elimo,.*', '^elpida,.*', '^embedfire,.*', '^embest,.*', '^emcraft,.*', '^emlid,.*', '^emmicro,.*', '^empire-electronix,.*', '^emtrion,.*', '^enbw,.*', '^enclustra,.*', '
 ^endian,.*', '^endless,.*', '^ene,.*', '^energymicro,.*', '^engicam,.*', '^engleder,.*', '^epcos,.*', '^epfl,.*', '^epson,.*', '^esp,.*', '^est,.*', '^eswin,.*', '^ettus,.*', '^eukrea,.*', '^everest,.*', '^everspin,.*', '^evervision,.*', '^exar,.*', '^excito,.*', '^exegin,.*', '^ezchip,.*', '^ezurio,.*', '^facebook,.*', '^fairchild,.*', '^fairphone,.*', '^faraday,.*', '^fascontek,.*', '^fastrax,.*', '^fcs,.*', '^feixin,.*', '^feiyang,.*', '^fii,.*', '^firefly,.*', '^flipkart,.*', '^focaltech,.*', '^forlinx,.*', '^foursemi,.*', '^foxlink,.*', '^freebox,.*', '^freecom,.*', '^frida,.*', '^friendlyarm,.*', '^fsl,.*', '^fujitsu,.*', '^fxtec,.*', '^galaxycore,.*', '^gameforce,.*', '^gardena,.*', '^gateway,.*', '^gateworks,.*', '^gcw,.*', '^ge,.*', '^geekbuying,.*', '^gef,.*', '^gehc,.*', '^gemei,.*', '^gemtek,.*', '^genesys,.*', '^genexis,.*', '^geniatech,.*', '^giantec,.*', '^giantplus,.*', '^glinet,.*', '^globalscale,.*', '^globaltop,.*', '^gmt,.*', '^gocontroll,.*', '^goldelico,.*', '^
 goodix,.*', '^google,.*', '^goramo,.*', '^gplus,.*', '^grinn,.*', '^grmn,.*', '^gumstix,.*', '^gw,.*', '^hannstar,.*', '^haochuangyi,.*', '^haoyu,.*', '^hardkernel,.*', '^hce,.*', '^headacoustics,.*', '^hechuang,.*', '^hideep,.*', '^himax,.*', '^hinlink,.*', '^hirschmann,.*', '^hisi,.*', '^hisilicon,.*', '^hit,.*', '^hitex,.*', '^holt,.*', '^holtek,.*', '^honestar,.*', '^honeywell,.*', '^hoperf,.*', '^hoperun,.*', '^hp,.*', '^hpe,.*', '^hsg,.*', '^htc,.*', '^huawei,.*', '^hugsun,.*', '^huiling,.*', '^hwacom,.*', '^hxt,.*', '^hycon,.*', '^hydis,.*', '^hynitron,.*', '^hynix,.*', '^hyundai,.*', '^i2se,.*', '^ibm,.*', '^icplus,.*', '^idt,.*', '^iei,.*', '^ifi,.*', '^ilitek,.*', '^imagis,.*', '^img,.*', '^imi,.*', '^inanbo,.*', '^incircuit,.*', '^incostartec,.*', '^indiedroid,.*', '^inet-tek,.*', '^infineon,.*', '^inforce,.*', '^ingenic,.*', '^ingrasys,.*', '^injoinic,.*', '^innocomm,.*', '^innolux,.*', '^inside-secure,.*', '^insignal,.*', '^inspur,.*', '^intel,.*', '^intercontrol,.*', '
 ^invensense,.*', '^inventec,.*', '^inversepath,.*', '^iom,.*', '^irondevice,.*', '^isee,.*', '^isil,.*', '^issi,.*', '^ite,.*', '^itead,.*', '^itian,.*', '^ivo,.*', '^iwave,.*', '^jadard,.*', '^jasonic,.*', '^jdi,.*', '^jedec,.*', '^jenson,.*', '^jesurun,.*', '^jethome,.*', '^jianda,.*', '^jide,.*', '^joz,.*', '^jty,.*', '^kam,.*', '^karo,.*', '^keithkoep,.*', '^keymile,.*', '^khadas,.*', '^kiebackpeter,.*', '^kinetic,.*', '^kingdisplay,.*', '^kingnovel,.*', '^kionix,.*', '^kobo,.*', '^kobol,.*', '^koe,.*', '^kontron,.*', '^kosagi,.*', '^kvg,.*', '^kyo,.*', '^lacie,.*', '^laird,.*', '^lamobo,.*', '^lantiq,.*', '^lattice,.*', '^lckfb,.*', '^lctech,.*', '^leadtek,.*', '^leez,.*', '^lego,.*', '^lemaker,.*', '^lenovo,.*', '^lg,.*', '^lgphilips,.*', '^libretech,.*', '^licheepi,.*', '^linaro,.*', '^lincolntech,.*', '^lineartechnology,.*', '^linksprite,.*', '^linksys,.*', '^linutronix,.*', '^linux,.*', '^linx,.*', '^liontron,.*', '^liteon,.*', '^litex,.*', '^lltc,.*', '^logicpd,.*', '^logi
 ctechno,.*', '^longcheer,.*', '^lontium,.*', '^loongmasses,.*', '^loongson,.*', '^lsi,.*', '^luckfox,.*', '^lunzn,.*', '^luxul,.*', '^lwn,.*', '^lxa,.*', '^m5stack,.*', '^macnica,.*', '^mantix,.*', '^mapleboard,.*', '^marantec,.*', '^marvell,.*', '^maxbotix,.*', '^maxim,.*', '^maxlinear,.*', '^maxtor,.*', '^mayqueen,.*', '^mbvl,.*', '^mcube,.*', '^meas,.*', '^mecer,.*', '^mediatek,.*', '^megachips,.*', '^mele,.*', '^melexis,.*', '^melfas,.*', '^mellanox,.*', '^memsensing,.*', '^memsic,.*', '^menlo,.*', '^mentor,.*', '^meraki,.*', '^merrii,.*', '^methode,.*', '^micrel,.*', '^microchip,.*', '^microcrystal,.*', '^micron,.*', '^microsoft,.*', '^microsys,.*', '^microtips,.*', '^mikroe,.*', '^mikrotik,.*', '^milkv,.*', '^miniand,.*', '^minix,.*', '^mips,.*', '^miramems,.*', '^mitsubishi,.*', '^mitsumi,.*', '^mixel,.*', '^miyoo,.*', '^mntre,.*', '^mobileye,.*', '^modtronix,.*', '^moortec,.*', '^mosaixtech,.*', '^motorcomm,.*', '^motorola,.*', '^moxa,.*', '^mpl,.*', '^mps,.*', '^mqmaker,.*'
 , '^mrvl,.*', '^mscc,.*', '^msi,.*', '^mstar,.*', '^mti,.*', '^multi-inno,.*', '^mundoreader,.*', '^murata,.*', '^mxic,.*', '^mxicy,.*', '^myir,.*', '^national,.*', '^neardi,.*', '^nec,.*', '^neofidelity,.*', '^neonode,.*', '^netcube,.*', '^netgear,.*', '^netlogic,.*', '^netron-dy,.*', '^netronix,.*', '^netxeon,.*', '^neweast,.*', '^newhaven,.*', '^newvision,.*', '^nexbox,.*', '^nextthing,.*', '^ni,.*', '^nicera,.*', '^nintendo,.*', '^nlt,.*', '^nokia,.*', '^nordic,.*', '^nothing,.*', '^novatech,.*', '^novatek,.*', '^novtech,.*', '^numonyx,.*', '^nutsboard,.*', '^nuvoton,.*', '^nvd,.*', '^nvidia,.*', '^nxp,.*', '^oceanic,.*', '^ocs,.*', '^oct,.*', '^okaya,.*', '^oki,.*', '^olimex,.*', '^olpc,.*', '^oneplus,.*', '^onie,.*', '^onion,.*', '^onnn,.*', '^ontat,.*', '^opalkelly,.*', '^openailab,.*', '^opencores,.*', '^openembed,.*', '^openpandora,.*', '^openrisc,.*', '^openwrt,.*', '^option,.*', '^oranth,.*', '^orisetech,.*', '^ortustech,.*', '^osddisplays,.*', '^osmc,.*', '^ouya,.*', '^o
 verkiz,.*', '^ovti,.*', '^oxsemi,.*', '^ozzmaker,.*', '^panasonic,.*', '^parade,.*', '^parallax,.*', '^particle,.*', '^pda,.*', '^pegatron,.*', '^pericom,.*', '^pervasive,.*', '^phicomm,.*', '^phontech,.*', '^phytec,.*', '^picochip,.*', '^pinctrl-[0-9]+$', '^pine64,.*', '^pineriver,.*', '^pixcir,.*', '^plantower,.*', '^plathome,.*', '^plda,.*', '^plx,.*', '^ply,.*', '^pni,.*', '^pocketbook,.*', '^polaroid,.*', '^polyhex,.*', '^pool[0-3],.*', '^portwell,.*', '^poslab,.*', '^pov,.*', '^powertip,.*', '^powervr,.*', '^powkiddy,.*', '^pri,.*', '^primeview,.*', '^primux,.*', '^probox2,.*', '^prt,.*', '^pulsedlight,.*', '^purism,.*', '^puya,.*', '^qca,.*', '^qcom,.*', '^qemu,.*', '^qi,.*', '^qiaodian,.*', '^qihua,.*', '^qishenglong,.*', '^qnap,.*', '^quanta,.*', '^radxa,.*', '^raidsonic,.*', '^ralink,.*', '^ramtron,.*', '^raspberrypi,.*', '^raumfeld,.*', '^raydium,.*', '^rda,.*', '^realtek,.*', '^relfor,.*', '^remarkable,.*', '^renesas,.*', '^rervision,.*', '^retronix,.*', '^revotics,.*', 
 '^rex,.*', '^richtek,.*', '^ricoh,.*', '^rikomagic,.*', '^riot,.*', '^riscv,.*', '^rockchip,.*', '^rocktech,.*', '^rohm,.*', '^ronbo,.*', '^ronetix,.*', '^roofull,.*', '^roseapplepi,.*', '^rve,.*', '^saef,.*', '^sakurapi,.*', '^samsung,.*', '^samtec,.*', '^sancloud,.*', '^sandisk,.*', '^satoz,.*', '^sbs,.*', '^schindler,.*', '^schneider,.*', '^schulercontrol,.*', '^sciosense,.*', '^sdmc,.*', '^seagate,.*', '^seeed,.*', '^seirobotics,.*', '^semtech,.*', '^senseair,.*', '^sensirion,.*', '^sensortek,.*', '^sercomm,.*', '^sff,.*', '^sgd,.*', '^sgmicro,.*', '^sgx,.*', '^sharp,.*', '^shift,.*', '^shimafuji,.*', '^shineworld,.*', '^shiratech,.*', '^si-en,.*', '^si-linux,.*', '^sielaff,.*', '^siemens,.*', '^sifive,.*', '^siflower,.*', '^sigma,.*', '^sii,.*', '^sil,.*', '^silabs,.*', '^silan,.*', '^silead,.*', '^silergy,.*', '^silex-insight,.*', '^siliconfile,.*', '^siliconmitus,.*', '^silvaco,.*', '^simtek,.*', '^sinlinx,.*', '^sinovoip,.*', '^sinowealth,.*', '^sipeed,.*', '^sirf,.*', '^sis
 ,.*', '^sitronix,.*', '^skov,.*', '^skyworks,.*', '^smartfiber,.*', '^smartlabs,.*', '^smartrg,.*', '^smi,.*', '^smsc,.*', '^snps,.*', '^sochip,.*', '^socionext,.*', '^solidrun,.*', '^solomon,.*', '^somfy,.*', '^sony,.*', '^sophgo,.*', '^sourceparts,.*', '^spacemit,.*', '^spansion,.*', '^sparkfun,.*', '^spinalhdl,.*', '^sprd,.*', '^square,.*', '^ssi,.*', '^sst,.*', '^sstar,.*', '^st,.*', '^st-ericsson,.*', '^starfive,.*', '^starry,.*', '^startek,.*', '^starterkit,.*', '^ste,.*', '^stericsson,.*', '^storlink,.*', '^storm,.*', '^storopack,.*', '^summit,.*', '^sunchip,.*', '^sundance,.*', '^sunplus,.*', '^supermicro,.*', '^swir,.*', '^syna,.*', '^synaptics,.*', '^synology,.*', '^synopsys,.*', '^taos,.*', '^tbs,.*', '^tbs-biometrics,.*', '^tcg,.*', '^tcl,.*', '^tcs,.*', '^tcu,.*', '^tdo,.*', '^team-source-display,.*', '^technexion,.*', '^technologic,.*', '^techstar,.*', '^techwell,.*', '^teejet,.*', '^teltonika,.*', '^tempo,.*', '^tenda,.*', '^terasic,.*', '^tesla,.*', '^test,.*', '^tfc
 ,.*', '^thead,.*', '^thine,.*', '^thingyjp,.*', '^thundercomm,.*', '^thwc,.*', '^ti,.*', '^tianma,.*', '^tlm,.*', '^tmt,.*', '^topeet,.*', '^topic,.*', '^topland,.*', '^toppoly,.*', '^topwise,.*', '^toradex,.*', '^toshiba,.*', '^toumaz,.*', '^tpk,.*', '^tplink,.*', '^tpo,.*', '^tq,.*', '^transpeed,.*', '^traverse,.*', '^tronfy,.*', '^tronsmart,.*', '^truly,.*', '^tsd,.*', '^turing,.*', '^tyan,.*', '^tyhx,.*', '^u-blox,.*', '^u-boot,.*', '^ubnt,.*', '^ucrobotics,.*', '^udoo,.*', '^ufispace,.*', '^ugoos,.*', '^ultratronik,.*', '^uni-t,.*', '^uniwest,.*', '^upisemi,.*', '^urt,.*', '^usi,.*', '^usr,.*', '^utoo,.*', '^v3,.*', '^vaisala,.*', '^valve,.*', '^vamrs,.*', '^variscite,.*', '^vdl,.*', '^vertexcom,.*', '^via,.*', '^vialab,.*', '^vicor,.*', '^videostrong,.*', '^virtio,.*', '^virtual,.*', '^vishay,.*', '^visionox,.*', '^vitesse,.*', '^vivante,.*', '^vivax,.*', '^vocore,.*', '^voipac,.*', '^voltafield,.*', '^vot,.*', '^vscom,.*', '^vxt,.*', '^wacom,.*', '^wanchanglong,.*', '^wand,.*
 ', '^waveshare,.*', '^wd,.*', '^we,.*', '^welltech,.*', '^wetek,.*', '^wexler,.*', '^whwave,.*', '^wi2wi,.*', '^widora,.*', '^wiligear,.*', '^willsemi,.*', '^winbond,.*', '^wingtech,.*', '^winlink,.*', '^winsen,.*', '^winstar,.*', '^wirelesstag,.*', '^wits,.*', '^wlf,.*', '^wm,.*', '^wobo,.*', '^wolfvision,.*', '^x-powers,.*', '^xen,.*', '^xes,.*', '^xiaomi,.*', '^xicor,.*', '^xillybus,.*', '^xingbangda,.*', '^xinpeng,.*', '^xiphera,.*', '^xlnx,.*', '^xnano,.*', '^xunlong,.*', '^xylon,.*', '^yadro,.*', '^yamaha,.*', '^yes-optoelectronics,.*', '^yic,.*', '^yiming,.*', '^ylm,.*', '^yna,.*', '^yones-toptech,.*', '^ys,.*', '^ysoft,.*', '^yuridenki,.*', '^yuzukihd,.*', '^zarlink,.*', '^zealz,.*', '^zeitec,.*', '^zidoo,.*', '^zii,.*', '^zinitix,.*', '^zkmagic,.*', '^zte,.*', '^zyxel,.*'
	from schema $id: http://devicetree.org/schemas/vendor-prefixes.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: scp at 10720000 (mediatek,mt8188-scp-dual): reg-names: ['cfg'] is too short
	from schema $id: http://devicetree.org/schemas/remoteproc/mtk,scp.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: scp at 10720000 (mediatek,mt8188-scp-dual): reg: [[0, 275906560, 0, 917504]] is too short
	from schema $id: http://devicetree.org/schemas/remoteproc/mtk,scp.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: scp at 10720000 (mediatek,mt8188-scp-dual): reg-names: ['cfg'] is too short
	from schema $id: http://devicetree.org/schemas/remoteproc/mtk,scp.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: mmc at 11250000 (mediatek,mt8188-mmc): Unevaluated properties are not allowed ('cap-sdio-async-int', 'eint-gpios', 'enable-sdio-wakeup' were unexpected)
	from schema $id: http://devicetree.org/schemas/mmc/mtk-sd.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'AVDD-supply' is a required property
	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'CPVDD-supply' is a required property
	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'DBVDD-supply' is a required property
	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'DCVDD-supply' is a required property
	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'MICVDD-supply' is a required property
	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'PLLVDD-supply' is a required property
	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'SPKVDD1-supply' is a required property
	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'SPKVDD2-supply' is a required property
	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: i2c at 11e01000 (mediatek,mt8188-i2c): pinctrl-names: ['default', 'default'] has non-unique elements
	from schema $id: http://devicetree.org/schemas/pinctrl/pinctrl-consumer.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: panel-dsi0 (tianma,tm070jdhg30): 'power-supply' is a required property
	from schema $id: http://devicetree.org/schemas/display/panel/panel-simple.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: i2c0-gpio-pins: pins-gpio: {'pinmux': [1536], 'bias-pull-up': 203, 'drive-strength-microamp': [1000]} is not of type 'array'
	from schema $id: http://devicetree.org/schemas/gpio/gpio-consumer.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: pmic (mediatek,mt6359): '#sound-dai-cells' does not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/mfd/mediatek,mt6397.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): pmic at 6:reg:0: [6, 0, 11] is too long
	from schema $id: http://devicetree.org/schemas/spmi/mtk,spmi-mtk-pmif.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): #address-cells: 2 was expected
	from schema $id: http://devicetree.org/schemas/spmi/mtk,spmi-mtk-pmif.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): #size-cells: 0 was expected
	from schema $id: http://devicetree.org/schemas/spmi/mtk,spmi-mtk-pmif.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): Unevaluated properties are not allowed ('#address-cells', '#size-cells', 'pmic at 6' were unexpected)
	from schema $id: http://devicetree.org/schemas/spmi/mtk,spmi-mtk-pmif.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): pmic at 6:reg:0: [6, 0, 11] is too long
	from schema $id: http://devicetree.org/schemas/spmi/spmi.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): #address-cells: 2 was expected
	from schema $id: http://devicetree.org/schemas/spmi/spmi.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): #size-cells: 0 was expected
	from schema $id: http://devicetree.org/schemas/spmi/spmi.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: pmic at 6 (mediatek,mt6315-regulator): regulators:vbuck1: Unevaluated properties are not allowed ('mtk,combined-regulator', 'regulator-compatible' were unexpected)
	from schema $id: http://devicetree.org/schemas/regulator/mt6315-regulator.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: pmic at 6 (mediatek,mt6315-regulator): regulators:vbuck3: Unevaluated properties are not allowed ('regulator-compatible' was unexpected)
	from schema $id: http://devicetree.org/schemas/regulator/mt6315-regulator.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: pmic at 6 (mediatek,mt6315-regulator): regulators:vbuck4: Unevaluated properties are not allowed ('regulator-compatible' was unexpected)
	from schema $id: http://devicetree.org/schemas/regulator/mt6315-regulator.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: vbuck1: 'mtk,combined-regulator' does not match any of the regexes: '^#.*', '^(at25|bm|devbus|dmacap|dsa|exynos|fsi[ab]|gpio-fan|gpio-key|gpio|gpmc|hdmi|i2c-gpio),.*', '^(keypad|m25p|max8952|max8997|max8998|mpmc),.*', '^(pciclass|pinctrl-single|#pinctrl-single|PowerPC),.*', '^(pl022|pxa-mmc|rcar_sound|rotary-encoder|s5m8767|sdhci),.*', '^(simple-audio-card|st-plgpio|st-spics|ts),.*', '^100ask,.*', '^70mai,.*', '^8dev,.*', '^GEFanuc,.*', '^IBM,.*', '^ORCL,.*', '^SUNW,.*', '^[a-zA-Z0-9#_][a-zA-Z0-9#+\-._@]{0,63}$', '^[a-zA-Z0-9+\-._]*@[0-9a-zA-Z,]*$', '^abb,.*', '^abilis,.*', '^abracon,.*', '^abt,.*', '^acbel,.*', '^acelink,.*', '^acer,.*', '^acme,.*', '^actions,.*', '^actiontec,.*', '^active-semi,.*', '^ad,.*', '^adafruit,.*', '^adapteva,.*', '^adaptrum,.*', '^adh,.*', '^adi,.*', '^adieng,.*', '^admatec,.*', '^advantech,.*', '^aeroflexgaisler,.*', '^aesop,.*', '^airoha,.*', '^al,.*', '^alcatel,.*', '^aldec,.*', '^alfa-network,.*'
 , '^allegro,.*', '^allegromicro,.*', '^alliedtelesis,.*', '^alliedvision,.*', '^allo,.*', '^allwinner,.*', '^alphascale,.*', '^alps,.*', '^alt,.*', '^altr,.*', '^amarula,.*', '^amazon,.*', '^amcc,.*', '^amd,.*', '^amediatech,.*', '^amlogic,.*', '^ampere,.*', '^amphenol,.*', '^ampire,.*', '^ams,.*', '^amstaos,.*', '^analogix,.*', '^anbernic,.*', '^andestech,.*', '^anvo,.*', '^aoly,.*', '^aosong,.*', '^apm,.*', '^apple,.*', '^aptina,.*', '^arasan,.*', '^archermind,.*', '^arcom,.*', '^arctic,.*', '^arcx,.*', '^argon40,.*', '^ariaboard,.*', '^aries,.*', '^arm,.*', '^armadeus,.*', '^armsom,.*', '^arrow,.*', '^artesyn,.*', '^asahi-kasei,.*', '^asc,.*', '^asix,.*', '^aspeed,.*', '^asrock,.*', '^asteralabs,.*', '^asus,.*', '^atheros,.*', '^atlas,.*', '^atmel,.*', '^auo,.*', '^auvidea,.*', '^avago,.*', '^avia,.*', '^avic,.*', '^avnet,.*', '^awinic,.*', '^axentia,.*', '^axiado,.*', '^axis,.*', '^azoteq,.*', '^azw,.*', '^baikal,.*', '^bananapi,.*', '^beacon,.*', '^beagle,.*', '^belling,.*', '^
 bestar,.*', '^bhf,.*', '^bigtreetech,.*', '^bitmain,.*', '^blaize,.*', '^bluegiga,.*', '^blutek,.*', '^boe,.*', '^bosch,.*', '^boundary,.*', '^brcm,.*', '^broadmobi,.*', '^bsh,.*', '^bticino,.*', '^buffalo,.*', '^buglabs,.*', '^bur,.*', '^bytedance,.*', '^calamp,.*', '^calao,.*', '^calaosystems,.*', '^calxeda,.*', '^cameo,.*', '^canaan,.*', '^caninos,.*', '^capella,.*', '^cascoda,.*', '^catalyst,.*', '^cavium,.*', '^cct,.*', '^cdns,.*', '^cdtech,.*', '^cellwise,.*', '^ceva,.*', '^chargebyte,.*', '^checkpoint,.*', '^chefree,.*', '^chipidea,.*', '^chipone,.*', '^chipspark,.*', '^chongzhou,.*', '^chrontel,.*', '^chrp,.*', '^chunghwa,.*', '^chuwi,.*', '^ciaa,.*', '^cirrus,.*', '^cisco,.*', '^cix,.*', '^clockwork,.*', '^cloos,.*', '^cloudengines,.*', '^cnm,.*', '^cnxt,.*', '^colorfly,.*', '^compal,.*', '^compulab,.*', '^comvetia,.*', '^congatec,.*', '^coolpi,.*', '^coreriver,.*', '^corpro,.*', '^cortina,.*', '^cosmic,.*', '^crane,.*', '^creative,.*', '^crystalfontz,.*', '^csky,.*', '^cso
 t,.*', '^csq,.*', '^csr,.*', '^ctera,.*', '^ctu,.*', '^cubietech,.*', '^cudy,.*', '^cui,.*', '^cypress,.*', '^cyx,.*', '^cznic,.*', '^dallas,.*', '^dataimage,.*', '^davicom,.*', '^deepcomputing,.*', '^dell,.*', '^delta,.*', '^densitron,.*', '^denx,.*', '^devantech,.*', '^dfi,.*', '^dfrobot,.*', '^dh,.*', '^difrnce,.*', '^digi,.*', '^digilent,.*', '^dimonoff,.*', '^diodes,.*', '^dioo,.*', '^djn,.*', '^dlc,.*', '^dlg,.*', '^dlink,.*', '^dmo,.*', '^domintech,.*', '^dongwoon,.*', '^dptechnics,.*', '^dragino,.*', '^dream,.*', '^ds,.*', '^dserve,.*', '^dynaimage,.*', '^ea,.*', '^ebang,.*', '^ebbg,.*', '^ebs-systart,.*', '^ebv,.*', '^eckelmann,.*', '^econet,.*', '^edgeble,.*', '^edimax,.*', '^edt,.*', '^ees,.*', '^eeti,.*', '^egnite,.*', '^einfochips,.*', '^eink,.*', '^elan,.*', '^element14,.*', '^elgin,.*', '^elida,.*', '^elimo,.*', '^elpida,.*', '^embedfire,.*', '^embest,.*', '^emcraft,.*', '^emlid,.*', '^emmicro,.*', '^empire-electronix,.*', '^emtrion,.*', '^enbw,.*', '^enclustra,.*', '
 ^endian,.*', '^endless,.*', '^ene,.*', '^energymicro,.*', '^engicam,.*', '^engleder,.*', '^epcos,.*', '^epfl,.*', '^epson,.*', '^esp,.*', '^est,.*', '^eswin,.*', '^ettus,.*', '^eukrea,.*', '^everest,.*', '^everspin,.*', '^evervision,.*', '^exar,.*', '^excito,.*', '^exegin,.*', '^ezchip,.*', '^ezurio,.*', '^facebook,.*', '^fairchild,.*', '^fairphone,.*', '^faraday,.*', '^fascontek,.*', '^fastrax,.*', '^fcs,.*', '^feixin,.*', '^feiyang,.*', '^fii,.*', '^firefly,.*', '^flipkart,.*', '^focaltech,.*', '^forlinx,.*', '^foursemi,.*', '^foxlink,.*', '^freebox,.*', '^freecom,.*', '^frida,.*', '^friendlyarm,.*', '^fsl,.*', '^fujitsu,.*', '^fxtec,.*', '^galaxycore,.*', '^gameforce,.*', '^gardena,.*', '^gateway,.*', '^gateworks,.*', '^gcw,.*', '^ge,.*', '^geekbuying,.*', '^gef,.*', '^gehc,.*', '^gemei,.*', '^gemtek,.*', '^genesys,.*', '^genexis,.*', '^geniatech,.*', '^giantec,.*', '^giantplus,.*', '^glinet,.*', '^globalscale,.*', '^globaltop,.*', '^gmt,.*', '^gocontroll,.*', '^goldelico,.*', '^
 goodix,.*', '^google,.*', '^goramo,.*', '^gplus,.*', '^grinn,.*', '^grmn,.*', '^gumstix,.*', '^gw,.*', '^hannstar,.*', '^haochuangyi,.*', '^haoyu,.*', '^hardkernel,.*', '^hce,.*', '^headacoustics,.*', '^hechuang,.*', '^hideep,.*', '^himax,.*', '^hinlink,.*', '^hirschmann,.*', '^hisi,.*', '^hisilicon,.*', '^hit,.*', '^hitex,.*', '^holt,.*', '^holtek,.*', '^honestar,.*', '^honeywell,.*', '^hoperf,.*', '^hoperun,.*', '^hp,.*', '^hpe,.*', '^hsg,.*', '^htc,.*', '^huawei,.*', '^hugsun,.*', '^huiling,.*', '^hwacom,.*', '^hxt,.*', '^hycon,.*', '^hydis,.*', '^hynitron,.*', '^hynix,.*', '^hyundai,.*', '^i2se,.*', '^ibm,.*', '^icplus,.*', '^idt,.*', '^iei,.*', '^ifi,.*', '^ilitek,.*', '^imagis,.*', '^img,.*', '^imi,.*', '^inanbo,.*', '^incircuit,.*', '^incostartec,.*', '^indiedroid,.*', '^inet-tek,.*', '^infineon,.*', '^inforce,.*', '^ingenic,.*', '^ingrasys,.*', '^injoinic,.*', '^innocomm,.*', '^innolux,.*', '^inside-secure,.*', '^insignal,.*', '^inspur,.*', '^intel,.*', '^intercontrol,.*', '
 ^invensense,.*', '^inventec,.*', '^inversepath,.*', '^iom,.*', '^irondevice,.*', '^isee,.*', '^isil,.*', '^issi,.*', '^ite,.*', '^itead,.*', '^itian,.*', '^ivo,.*', '^iwave,.*', '^jadard,.*', '^jasonic,.*', '^jdi,.*', '^jedec,.*', '^jenson,.*', '^jesurun,.*', '^jethome,.*', '^jianda,.*', '^jide,.*', '^joz,.*', '^jty,.*', '^kam,.*', '^karo,.*', '^keithkoep,.*', '^keymile,.*', '^khadas,.*', '^kiebackpeter,.*', '^kinetic,.*', '^kingdisplay,.*', '^kingnovel,.*', '^kionix,.*', '^kobo,.*', '^kobol,.*', '^koe,.*', '^kontron,.*', '^kosagi,.*', '^kvg,.*', '^kyo,.*', '^lacie,.*', '^laird,.*', '^lamobo,.*', '^lantiq,.*', '^lattice,.*', '^lckfb,.*', '^lctech,.*', '^leadtek,.*', '^leez,.*', '^lego,.*', '^lemaker,.*', '^lenovo,.*', '^lg,.*', '^lgphilips,.*', '^libretech,.*', '^licheepi,.*', '^linaro,.*', '^lincolntech,.*', '^lineartechnology,.*', '^linksprite,.*', '^linksys,.*', '^linutronix,.*', '^linux,.*', '^linx,.*', '^liontron,.*', '^liteon,.*', '^litex,.*', '^lltc,.*', '^logicpd,.*', '^logi
 ctechno,.*', '^longcheer,.*', '^lontium,.*', '^loongmasses,.*', '^loongson,.*', '^lsi,.*', '^luckfox,.*', '^lunzn,.*', '^luxul,.*', '^lwn,.*', '^lxa,.*', '^m5stack,.*', '^macnica,.*', '^mantix,.*', '^mapleboard,.*', '^marantec,.*', '^marvell,.*', '^maxbotix,.*', '^maxim,.*', '^maxlinear,.*', '^maxtor,.*', '^mayqueen,.*', '^mbvl,.*', '^mcube,.*', '^meas,.*', '^mecer,.*', '^mediatek,.*', '^megachips,.*', '^mele,.*', '^melexis,.*', '^melfas,.*', '^mellanox,.*', '^memsensing,.*', '^memsic,.*', '^menlo,.*', '^mentor,.*', '^meraki,.*', '^merrii,.*', '^methode,.*', '^micrel,.*', '^microchip,.*', '^microcrystal,.*', '^micron,.*', '^microsoft,.*', '^microsys,.*', '^microtips,.*', '^mikroe,.*', '^mikrotik,.*', '^milkv,.*', '^miniand,.*', '^minix,.*', '^mips,.*', '^miramems,.*', '^mitsubishi,.*', '^mitsumi,.*', '^mixel,.*', '^miyoo,.*', '^mntre,.*', '^mobileye,.*', '^modtronix,.*', '^moortec,.*', '^mosaixtech,.*', '^motorcomm,.*', '^motorola,.*', '^moxa,.*', '^mpl,.*', '^mps,.*', '^mqmaker,.*'
 , '^mrvl,.*', '^mscc,.*', '^msi,.*', '^mstar,.*', '^mti,.*', '^multi-inno,.*', '^mundoreader,.*', '^murata,.*', '^mxic,.*', '^mxicy,.*', '^myir,.*', '^national,.*', '^neardi,.*', '^nec,.*', '^neofidelity,.*', '^neonode,.*', '^netcube,.*', '^netgear,.*', '^netlogic,.*', '^netron-dy,.*', '^netronix,.*', '^netxeon,.*', '^neweast,.*', '^newhaven,.*', '^newvision,.*', '^nexbox,.*', '^nextthing,.*', '^ni,.*', '^nicera,.*', '^nintendo,.*', '^nlt,.*', '^nokia,.*', '^nordic,.*', '^nothing,.*', '^novatech,.*', '^novatek,.*', '^novtech,.*', '^numonyx,.*', '^nutsboard,.*', '^nuvoton,.*', '^nvd,.*', '^nvidia,.*', '^nxp,.*', '^oceanic,.*', '^ocs,.*', '^oct,.*', '^okaya,.*', '^oki,.*', '^olimex,.*', '^olpc,.*', '^oneplus,.*', '^onie,.*', '^onion,.*', '^onnn,.*', '^ontat,.*', '^opalkelly,.*', '^openailab,.*', '^opencores,.*', '^openembed,.*', '^openpandora,.*', '^openrisc,.*', '^openwrt,.*', '^option,.*', '^oranth,.*', '^orisetech,.*', '^ortustech,.*', '^osddisplays,.*', '^osmc,.*', '^ouya,.*', '^o
 verkiz,.*', '^ovti,.*', '^oxsemi,.*', '^ozzmaker,.*', '^panasonic,.*', '^parade,.*', '^parallax,.*', '^particle,.*', '^pda,.*', '^pegatron,.*', '^pericom,.*', '^pervasive,.*', '^phicomm,.*', '^phontech,.*', '^phytec,.*', '^picochip,.*', '^pinctrl-[0-9]+$', '^pine64,.*', '^pineriver,.*', '^pixcir,.*', '^plantower,.*', '^plathome,.*', '^plda,.*', '^plx,.*', '^ply,.*', '^pni,.*', '^pocketbook,.*', '^polaroid,.*', '^polyhex,.*', '^pool[0-3],.*', '^portwell,.*', '^poslab,.*', '^pov,.*', '^powertip,.*', '^powervr,.*', '^powkiddy,.*', '^pri,.*', '^primeview,.*', '^primux,.*', '^probox2,.*', '^prt,.*', '^pulsedlight,.*', '^purism,.*', '^puya,.*', '^qca,.*', '^qcom,.*', '^qemu,.*', '^qi,.*', '^qiaodian,.*', '^qihua,.*', '^qishenglong,.*', '^qnap,.*', '^quanta,.*', '^radxa,.*', '^raidsonic,.*', '^ralink,.*', '^ramtron,.*', '^raspberrypi,.*', '^raumfeld,.*', '^raydium,.*', '^rda,.*', '^realtek,.*', '^relfor,.*', '^remarkable,.*', '^renesas,.*', '^rervision,.*', '^retronix,.*', '^revotics,.*', 
 '^rex,.*', '^richtek,.*', '^ricoh,.*', '^rikomagic,.*', '^riot,.*', '^riscv,.*', '^rockchip,.*', '^rocktech,.*', '^rohm,.*', '^ronbo,.*', '^ronetix,.*', '^roofull,.*', '^roseapplepi,.*', '^rve,.*', '^saef,.*', '^sakurapi,.*', '^samsung,.*', '^samtec,.*', '^sancloud,.*', '^sandisk,.*', '^satoz,.*', '^sbs,.*', '^schindler,.*', '^schneider,.*', '^schulercontrol,.*', '^sciosense,.*', '^sdmc,.*', '^seagate,.*', '^seeed,.*', '^seirobotics,.*', '^semtech,.*', '^senseair,.*', '^sensirion,.*', '^sensortek,.*', '^sercomm,.*', '^sff,.*', '^sgd,.*', '^sgmicro,.*', '^sgx,.*', '^sharp,.*', '^shift,.*', '^shimafuji,.*', '^shineworld,.*', '^shiratech,.*', '^si-en,.*', '^si-linux,.*', '^sielaff,.*', '^siemens,.*', '^sifive,.*', '^siflower,.*', '^sigma,.*', '^sii,.*', '^sil,.*', '^silabs,.*', '^silan,.*', '^silead,.*', '^silergy,.*', '^silex-insight,.*', '^siliconfile,.*', '^siliconmitus,.*', '^silvaco,.*', '^simtek,.*', '^sinlinx,.*', '^sinovoip,.*', '^sinowealth,.*', '^sipeed,.*', '^sirf,.*', '^sis
 ,.*', '^sitronix,.*', '^skov,.*', '^skyworks,.*', '^smartfiber,.*', '^smartlabs,.*', '^smartrg,.*', '^smi,.*', '^smsc,.*', '^snps,.*', '^sochip,.*', '^socionext,.*', '^solidrun,.*', '^solomon,.*', '^somfy,.*', '^sony,.*', '^sophgo,.*', '^sourceparts,.*', '^spacemit,.*', '^spansion,.*', '^sparkfun,.*', '^spinalhdl,.*', '^sprd,.*', '^square,.*', '^ssi,.*', '^sst,.*', '^sstar,.*', '^st,.*', '^st-ericsson,.*', '^starfive,.*', '^starry,.*', '^startek,.*', '^starterkit,.*', '^ste,.*', '^stericsson,.*', '^storlink,.*', '^storm,.*', '^storopack,.*', '^summit,.*', '^sunchip,.*', '^sundance,.*', '^sunplus,.*', '^supermicro,.*', '^swir,.*', '^syna,.*', '^synaptics,.*', '^synology,.*', '^synopsys,.*', '^taos,.*', '^tbs,.*', '^tbs-biometrics,.*', '^tcg,.*', '^tcl,.*', '^tcs,.*', '^tcu,.*', '^tdo,.*', '^team-source-display,.*', '^technexion,.*', '^technologic,.*', '^techstar,.*', '^techwell,.*', '^teejet,.*', '^teltonika,.*', '^tempo,.*', '^tenda,.*', '^terasic,.*', '^tesla,.*', '^test,.*', '^tfc
 ,.*', '^thead,.*', '^thine,.*', '^thingyjp,.*', '^thundercomm,.*', '^thwc,.*', '^ti,.*', '^tianma,.*', '^tlm,.*', '^tmt,.*', '^topeet,.*', '^topic,.*', '^topland,.*', '^toppoly,.*', '^topwise,.*', '^toradex,.*', '^toshiba,.*', '^toumaz,.*', '^tpk,.*', '^tplink,.*', '^tpo,.*', '^tq,.*', '^transpeed,.*', '^traverse,.*', '^tronfy,.*', '^tronsmart,.*', '^truly,.*', '^tsd,.*', '^turing,.*', '^tyan,.*', '^tyhx,.*', '^u-blox,.*', '^u-boot,.*', '^ubnt,.*', '^ucrobotics,.*', '^udoo,.*', '^ufispace,.*', '^ugoos,.*', '^ultratronik,.*', '^uni-t,.*', '^uniwest,.*', '^upisemi,.*', '^urt,.*', '^usi,.*', '^usr,.*', '^utoo,.*', '^v3,.*', '^vaisala,.*', '^valve,.*', '^vamrs,.*', '^variscite,.*', '^vdl,.*', '^vertexcom,.*', '^via,.*', '^vialab,.*', '^vicor,.*', '^videostrong,.*', '^virtio,.*', '^virtual,.*', '^vishay,.*', '^visionox,.*', '^vitesse,.*', '^vivante,.*', '^vivax,.*', '^vocore,.*', '^voipac,.*', '^voltafield,.*', '^vot,.*', '^vscom,.*', '^vxt,.*', '^wacom,.*', '^wanchanglong,.*', '^wand,.*
 ', '^waveshare,.*', '^wd,.*', '^we,.*', '^welltech,.*', '^wetek,.*', '^wexler,.*', '^whwave,.*', '^wi2wi,.*', '^widora,.*', '^wiligear,.*', '^willsemi,.*', '^winbond,.*', '^wingtech,.*', '^winlink,.*', '^winsen,.*', '^winstar,.*', '^wirelesstag,.*', '^wits,.*', '^wlf,.*', '^wm,.*', '^wobo,.*', '^wolfvision,.*', '^x-powers,.*', '^xen,.*', '^xes,.*', '^xiaomi,.*', '^xicor,.*', '^xillybus,.*', '^xingbangda,.*', '^xinpeng,.*', '^xiphera,.*', '^xlnx,.*', '^xnano,.*', '^xunlong,.*', '^xylon,.*', '^yadro,.*', '^yamaha,.*', '^yes-optoelectronics,.*', '^yic,.*', '^yiming,.*', '^ylm,.*', '^yna,.*', '^yones-toptech,.*', '^ys,.*', '^ysoft,.*', '^yuridenki,.*', '^yuzukihd,.*', '^zarlink,.*', '^zealz,.*', '^zeitec,.*', '^zidoo,.*', '^zii,.*', '^zinitix,.*', '^zkmagic,.*', '^zte,.*', '^zyxel,.*'
	from schema $id: http://devicetree.org/schemas/vendor-prefixes.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: scp at 10720000 (mediatek,mt8188-scp-dual): reg-names: ['cfg'] is too short
	from schema $id: http://devicetree.org/schemas/remoteproc/mtk,scp.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: scp at 10720000 (mediatek,mt8188-scp-dual): reg: [[0, 275906560, 0, 917504]] is too short
	from schema $id: http://devicetree.org/schemas/remoteproc/mtk,scp.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: scp at 10720000 (mediatek,mt8188-scp-dual): reg-names: ['cfg'] is too short
	from schema $id: http://devicetree.org/schemas/remoteproc/mtk,scp.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: mmc at 11250000 (mediatek,mt8188-mmc): Unevaluated properties are not allowed ('cap-sdio-async-int', 'eint-gpios', 'enable-sdio-wakeup' were unexpected)
	from schema $id: http://devicetree.org/schemas/mmc/mtk-sd.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'AVDD-supply' is a required property
	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'CPVDD-supply' is a required property
	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'DBVDD-supply' is a required property
	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'DCVDD-supply' is a required property
	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'MICVDD-supply' is a required property
	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'PLLVDD-supply' is a required property
	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'SPKVDD1-supply' is a required property
	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'SPKVDD2-supply' is a required property
	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: i2c at 11e01000 (mediatek,mt8188-i2c): pinctrl-names: ['default', 'default'] has non-unique elements
	from schema $id: http://devicetree.org/schemas/pinctrl/pinctrl-consumer.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: panel-dsi0 (tianma,tm070jdhg30): 'power-supply' is a required property
	from schema $id: http://devicetree.org/schemas/display/panel/panel-simple.yaml







From s-vadapalli at ti.com  Mon Dec  1 04:38:07 2025
From: s-vadapalli at ti.com (Siddharth Vadapalli)
Date: Mon, 1 Dec 2025 18:08:07 +0530
Subject: [PATCH] spi: cadence-quadspi: Fix cqspi_probe() error handling
 for runtime pm
In-Reply-To: <20251201074320.GA8737@francesco-nb>
References: <20251119152545.2591651-1-s-vadapalli@ti.com>
	 <20251201072844.GA6785@francesco-nb> <20251201074320.GA8737@francesco-nb>
Message-ID: <dfbbd5ce209fac9a556c200748d8c521d0d4f450.camel@ti.com>

On Mon, 2025-12-01 at 08:43 +0100, Francesco Dolcini wrote:
> On Mon, Dec 01, 2025 at 08:28:44AM +0100, Francesco Dolcini wrote:
> > Hello Siddharth, Mark,
> > 
> > On Wed, Nov 19, 2025 at 08:53:53PM +0530, Siddharth Vadapalli wrote:
> > > Commit f1eb4e792bb1 ("spi: spi-cadence-quadspi: Enable pm runtime earlier
> > > to avoid imbalance") relocated code but missed updating the error handling
> > > path associated with it.
> > > 
> > > Prior to the relocation, runtime pm was enabled after the code-block
> > > associated with 'cqspi_request_mmap_dma()', due to which, the error
> > > handling for the same didn't require invoking 'pm_runtime_disable()'.
> > > 
> > > Post refactoring, runtime pm has been enabled before the code-block and
> > > when an error is encountered, jumping to 'probe_dma_failed' doesn't
> > > invoke 'pm_runtime_disable()'. This leads to a race condition wherein
> > > 'cqspi_runtime_suspend()' is invoked while the error handling path executes
> > > in parallel. The resulting error is the following:
> > > 
> > >   clk:103:0 already disabled
> > >   WARNING: drivers/clk/clk.c:1188 at clk_core_disable+0x80/0xa0, CPU#1: kworker/u8:0/12
> > >   [TRIMMED]
> > >   pstate: 600000c5 (nZCv daIF -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
> > >   pc : clk_core_disable+0x80/0xa0
> > >   lr : clk_core_disable+0x80/0xa0
> > >   [TRIMMED]
> > >   Call trace:
> > >    clk_core_disable+0x80/0xa0 (P)
> > >    clk_core_disable_lock+0x88/0x10c
> > >    clk_disable+0x24/0x30
> > >    cqspi_probe+0xa3c/0xae8
> > >   [TRIMMED]
> > > 
> > > The error is due to the second invocation of 'clk_disable_unprepare()' on
> > > 'cqspi->clk' in the error handling within 'cqspi_probe()', with the first
> > > invocation being within 'cqspi_runtime_suspend()'.
> > > 
> > > Fix this by correcting the error handling.
> > > 
> > > Fixes: f1eb4e792bb1 ("spi: spi-cadence-quadspi: Enable pm runtime earlier to avoid imbalance")
> > > Signed-off-by: Siddharth Vadapalli <s-vadapalli at ti.com>
> > 
> > Our CI just hit this WARNING with 6.18 kernel, on verdin-am62. To me it's a
> > regression from v6.18, specifically from spi-fix-v6.18-rc7, we did not
> > had any such WARNING with the master build we did run last Friday.
> > 
> > 
> > [    8.648915] cadence-qspi fc40000.spi: No flash device declared
> > [    8.675671] cadence-qspi fc40000.spi: failed to setup flash parameters -19
> > [    8.693691] ------------[ cut here ]------------
> > [    8.693719] clk:75:7 already disabled
> > [    8.693791] WARNING: CPU: 1 PID: 185 at /usr/src/kernel/drivers/clk/clk.c:1188 clk_core_disable+0xa0/0xb4
> > [    8.693822] Modules linked in: gf128mul(+) snd_soc_simple_card(+) snd_soc_simple_card_utils spi_cadence_quadspi(+) optee tee usb_conn_gpio gpio_keys display_connector roles dwc3_am62 rtc_ti_k3 ti_k3_r5_remoteproc k3_j72xx_bandgap ti_k3_m4_remoteproc ti_k3_common tidss sa2ul sha512 snd_soc_davinci_mcasp drm_display_helper libsha512 snd_soc_ti_udma sha256 sha1 cec snd_soc_ti_edma pruss omap_mailbox snd_soc_ti_sdma omap_hwspinlock authenc bluetooth ecdh_generic ecc ina2xx tpm_tis_i2c rfkill snd_soc_wm8904 libaes lm75 lontium_lt8912b crc_ccitt i3c ti_ads1015 tpm_tis_core industrialio_triggered_buffer kfifo_buf tps65219_pwrbutton tpm rng_core m_can_platform m_can tc358768 can_dev spi_omap2_mcspi pwm_tiehrpwm loop fuse ipv6 libsha1 autofs4
> > [    8.694064] CPU: 1 UID: 0 PID: 185 Comm: (udev-worker) Not tainted 6.18.0-0.0.0-devel #1 PREEMPT
> > [    8.694076] Hardware name: Toradex Verdin AM62 on Dahlia Board (DT)
> 
> Same on verdin-am62p

Could you please check if the driver's suspend callback has executed before
the above? The patch intended to fix the very issue being reported.
Therefore, the commit corresponding to the current patch might still
trigger the issue. Ideally, reverting the commit for the current patch and
the commit under Fixes (f1eb4e792bb1 ("spi: spi-cadence-quadspi: Enable pm
runtime earlier to avoid imbalance"))
should prevent the issue.

Please let me know.

Regards,
Siddharth.


From alchark at gmail.com  Mon Dec  1 04:37:54 2025
From: alchark at gmail.com (Alexey Charkov)
Date: Mon, 01 Dec 2025 16:37:54 +0400
Subject: [PATCH] arm64: dts: rockchip: Add overlay for the PCIe slot on
 RK3576 EVB1
Message-ID: <20251201-evb1-pcie1-v1-1-c62bba5c1167@gmail.com>

Rockchip RK3576 EVB1 has an onboard PCIe slot (PCIe 2.1, x4 mechanically,
x1 electrically), but it shares pins and PHY with the only USB3 Type-A
port.

There is a physical switch next to the slot to transfer respective pins
connection from the USB3 port to the PCIe slot, but apart from flipping
the switch one must also disable the USB3 host controller to prevent it
from claiming the PHY before the PCIe slot can become usable.

Add an overlay to disable the USB3 host port and instead enable the
PCIe slot, along with its pin configs. The physical switch must still be
flipped to the "ON - PCIe1" position for this to work.

Signed-off-by: Alexey Charkov <alchark at gmail.com>
---
 arch/arm64/boot/dts/rockchip/Makefile              |  4 +++
 .../boot/dts/rockchip/rk3576-evb1-v10-pcie1.dtso   | 31 ++++++++++++++++++++++
 2 files changed, 35 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index ad684e3831bc..63198a618a2b 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -252,6 +252,10 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-armsom-sige5-v1.2-wifibt.dtb
 rk3576-armsom-sige5-v1.2-wifibt-dtbs := rk3576-armsom-sige5.dtb \
 	rk3576-armsom-sige5-v1.2-wifibt.dtbo
 
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-evb1-v10-pcie1.dtb
+rk3576-evb1-v10-pcie1-dtbs := rk3576-evb1-v10.dtb \
+	rk3576-evb1-v10-pcie1.dtbo
+
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-edgeble-neu6a-wifi.dtb
 rk3588-edgeble-neu6a-wifi-dtbs := rk3588-edgeble-neu6a-io.dtb \
 	rk3588-edgeble-neu6a-wifi.dtbo
diff --git a/arch/arm64/boot/dts/rockchip/rk3576-evb1-v10-pcie1.dtso b/arch/arm64/boot/dts/rockchip/rk3576-evb1-v10-pcie1.dtso
new file mode 100644
index 000000000000..dccf4a5debdb
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3576-evb1-v10-pcie1.dtso
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * DT-overlay to enable the onboard PCIe x1 slot, which shares pins and the PHY
+ * with the USB3 host port.
+ * To use the PCIe slot, apply this overlay and flip the Dial_Switch_1 right
+ * next to the PCIe slot to low state (labeled "ON - PCIe1"). USB3 host port
+ * will be unusable (not even in 2.0 mode)
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/pinctrl/rockchip.h>
+
+&pcie1 {
+	pinctrl-0 = <&pcie1m0_pins &pcie1_rst>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&pinctrl {
+	pcie1 {
+		pcie1_rst: pcie1-rst {
+			rockchip,pins = <4 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+};
+
+&usb_drd1_dwc3 {
+	status = "disabled";
+};

---
base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
change-id: 20251128-evb1-pcie1-ade389a4d590

Best regards,
-- 
Alexey Charkov <alchark at gmail.com>



From josua at solid-run.com  Mon Dec  1 04:38:53 2025
From: josua at solid-run.com (Josua Mayer)
Date: Mon, 1 Dec 2025 12:38:53 +0000
Subject: [PATCH v3 04/11] Input: ilitek_ts_i2c: fix warning with gpio
 controllers that sleep
In-Reply-To: <rifyic7w2zyjupbmzwcewcslryqiyexxdvbgcuxtkw3trmtulw@y4otarfyvgm7>
References: <20251117-imx8mp-hb-iiot-v3-0-bf1a4cf5fa8e@solid-run.com>
 <20251117-imx8mp-hb-iiot-v3-4-bf1a4cf5fa8e@solid-run.com>
 <rifyic7w2zyjupbmzwcewcslryqiyexxdvbgcuxtkw3trmtulw@y4otarfyvgm7>
Message-ID: <020ff4f6-b7dc-4507-b910-a629fd0a755d@solid-run.com>

Am 18.11.25 um 20:22 schrieb Dmitry Torokhov:
> Hi Josua,
>
> On Mon, Nov 17, 2025 at 01:28:46PM +0100, Josua Mayer wrote:
>> The ilitek touchscreen driver uses the non-sleeping gpiod_set_value
>> function for reset.
>>
>> Switch to using gpiod_set_value_cansleep() when controlling reset_gpio to
>> support GPIO providers that may sleep, such as I2C GPIO expanders.
>>
>> This fixes noisy complaints in kernel log for gpio providers that do
>> sleep.
>>
>> Signed-off-by: Josua Mayer <josua at solid-run.com>
>> ---
>>  drivers/input/touchscreen/ilitek_ts_i2c.c | 4 ++--
>>  1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/input/touchscreen/ilitek_ts_i2c.c b/drivers/input/touchscreen/ilitek_ts_i2c.c
>> index 0dd632724a003..8c5a54b336816 100644
>> --- a/drivers/input/touchscreen/ilitek_ts_i2c.c
>> +++ b/drivers/input/touchscreen/ilitek_ts_i2c.c
>> @@ -396,9 +396,9 @@ static const struct ilitek_protocol_map ptl_func_map[] = {
>>  static void ilitek_reset(struct ilitek_ts_data *ts, int delay)
>>  {
>>  	if (ts->reset_gpio) {
>> -		gpiod_set_value(ts->reset_gpio, 1);
>> +		gpiod_set_value_cansleep(ts->reset_gpio, 1);
>>  		mdelay(10);
> This (and below) should be usleep_range/msleep/fsleep.

True ....

So I will change it since I am areadly changing the code next to it.

>
>> -		gpiod_set_value(ts->reset_gpio, 0);
>> +		gpiod_set_value_cansleep(ts->reset_gpio, 0);
>>  		mdelay(delay);
>>  	}
>>  }
>>
> Thanks.
>

From tomas.melin at vaisala.com  Mon Dec  1 04:50:25 2025
From: tomas.melin at vaisala.com (Tomas Melin)
Date: Mon, 01 Dec 2025 12:50:25 +0000
Subject: [PATCH 0/4] rtc: zynqmp: fixes for read and set offset
Message-ID: <20251201-zynqmp-rtc-updates-v1-0-33875c1e385b@vaisala.com>

Add improvements for read and set offset functions.
The basic functionality is still the same, but offset correction values
are now updated to match with expected.

The RTC calibration value operates with full ticks,
and fractional ticks which are a 1/16 of a full tick.
The 16 lowest bits in the calibration registers are for the full ticks
and value matches the external oscillator in Hz. Through that,
the maximum and minimum offset values can be calculated dynamically,
as they depend on the input frequency used.

For docs on the calibration register, see
https://docs.amd.com/r/en-US/ug1087-zynq-ultrascale-registers/CALIB_READ-RTC-Register

Signed-off-by: Tomas Melin <tomas.melin at vaisala.com>
---
Tomas Melin (4):
      rtc: zynqmp: correct frequency value
      rtc: zynqmp: rework read_offset
      rtc: zynqmp: rework set_offset
      rtc: zynqmp: use dynamic max and min offset ranges

 drivers/rtc/rtc-zynqmp.c | 65 ++++++++++++++++++++++++------------------------
 1 file changed, 33 insertions(+), 32 deletions(-)
---
base-commit: cd635e33b0113287c94021be53d2a7c61a1614e9
change-id: 20251201-zynqmp-rtc-updates-d260364cc01b

Best regards,
-- 
Tomas Melin <tomas.melin at vaisala.com>



From tomas.melin at vaisala.com  Mon Dec  1 04:50:26 2025
From: tomas.melin at vaisala.com (Tomas Melin)
Date: Mon, 01 Dec 2025 12:50:26 +0000
Subject: [PATCH 1/4] rtc: zynqmp: correct frequency value
In-Reply-To: <20251201-zynqmp-rtc-updates-v1-0-33875c1e385b@vaisala.com>
References: <20251201-zynqmp-rtc-updates-v1-0-33875c1e385b@vaisala.com>
Message-ID: <20251201-zynqmp-rtc-updates-v1-1-33875c1e385b@vaisala.com>

Fix calibration value in case a clock reference is provided.
The actual calibration value written into register is
frequency - 1.

Signed-off-by: Tomas Melin <tomas.melin at vaisala.com>
---
 drivers/rtc/rtc-zynqmp.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c
index 3baa2b481d9f2008750046005283b98a0d546c5c..856bc1678e7d31144f320ae9f75fc58c742a2a64 100644
--- a/drivers/rtc/rtc-zynqmp.c
+++ b/drivers/rtc/rtc-zynqmp.c
@@ -345,7 +345,10 @@ static int xlnx_rtc_probe(struct platform_device *pdev)
 					   &xrtcdev->freq);
 		if (ret)
 			xrtcdev->freq = RTC_CALIB_DEF;
+	} else {
+		xrtcdev->freq--;
 	}
+
 	ret = readl(xrtcdev->reg_base + RTC_CALIB_RD);
 	if (!ret)
 		writel(xrtcdev->freq, (xrtcdev->reg_base + RTC_CALIB_WR));

-- 
2.47.3



From tomas.melin at vaisala.com  Mon Dec  1 04:50:27 2025
From: tomas.melin at vaisala.com (Tomas Melin)
Date: Mon, 01 Dec 2025 12:50:27 +0000
Subject: [PATCH 2/4] rtc: zynqmp: rework read_offset
In-Reply-To: <20251201-zynqmp-rtc-updates-v1-0-33875c1e385b@vaisala.com>
References: <20251201-zynqmp-rtc-updates-v1-0-33875c1e385b@vaisala.com>
Message-ID: <20251201-zynqmp-rtc-updates-v1-2-33875c1e385b@vaisala.com>

read_offset() was using static frequency for determining
the tick offset. It was also using remainder from do_div()
operation as tick_mult value which caused the offset to be
incorrect.

At the same time, rework function to improve readability.

Signed-off-by: Tomas Melin <tomas.melin at vaisala.com>
---
 drivers/rtc/rtc-zynqmp.c | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c
index 856bc1678e7d31144f320ae9f75fc58c742a2a64..7af5f6f99538f961a53ff56bfc656c907611b900 100644
--- a/drivers/rtc/rtc-zynqmp.c
+++ b/drivers/rtc/rtc-zynqmp.c
@@ -178,21 +178,28 @@ static void xlnx_init_rtc(struct xlnx_rtc_dev *xrtcdev)
 static int xlnx_rtc_read_offset(struct device *dev, long *offset)
 {
 	struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
-	unsigned long long rtc_ppb = RTC_PPB;
-	unsigned int tick_mult = do_div(rtc_ppb, xrtcdev->freq);
-	unsigned int calibval;
+	unsigned int calibval, fract_data, fract_part;
+	int max_tick, tick_mult;
+	int freq = xrtcdev->freq;
 	long offset_val;
 
+	/* ticks to reach RTC_PPB */
+	tick_mult = DIV_ROUND_CLOSEST(RTC_PPB, freq);
+
 	calibval = readl(xrtcdev->reg_base + RTC_CALIB_RD);
 	/* Offset with seconds ticks */
-	offset_val = calibval & RTC_TICK_MASK;
-	offset_val = offset_val - RTC_CALIB_DEF;
-	offset_val = offset_val * tick_mult;
+	max_tick = calibval & RTC_TICK_MASK;
+	offset_val = max_tick - freq;
+	/* Convert to ppb */
+	offset_val *= tick_mult;
 
 	/* Offset with fractional ticks */
-	if (calibval & RTC_FR_EN)
-		offset_val += ((calibval & RTC_FR_MASK) >> RTC_FR_DATSHIFT)
-			* (tick_mult / RTC_FR_MAX_TICKS);
+	if (calibval & RTC_FR_EN) {
+		fract_data = (calibval & RTC_FR_MASK) >> RTC_FR_DATSHIFT;
+		fract_part = DIV_ROUND_UP(tick_mult, RTC_FR_MAX_TICKS);
+		offset_val += (fract_part * fract_data);
+	}
+
 	*offset = offset_val;
 
 	return 0;

-- 
2.47.3



From tomas.melin at vaisala.com  Mon Dec  1 04:50:28 2025
From: tomas.melin at vaisala.com (Tomas Melin)
Date: Mon, 01 Dec 2025 12:50:28 +0000
Subject: [PATCH 3/4] rtc: zynqmp: rework set_offset
In-Reply-To: <20251201-zynqmp-rtc-updates-v1-0-33875c1e385b@vaisala.com>
References: <20251201-zynqmp-rtc-updates-v1-0-33875c1e385b@vaisala.com>
Message-ID: <20251201-zynqmp-rtc-updates-v1-3-33875c1e385b@vaisala.com>

set_offset was using remainder of do_div as tick_mult which resulted in
wrong offset. Calibration value also assumed builtin calibration default.
Update fract_offset to correctly calculate the value for
negative offset and replace the for loop with division.

Signed-off-by: Tomas Melin <tomas.melin at vaisala.com>
---
 drivers/rtc/rtc-zynqmp.c | 29 +++++++++++------------------
 1 file changed, 11 insertions(+), 18 deletions(-)

diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c
index 7af5f6f99538f961a53ff56bfc656c907611b900..3bc8831ba2c4c4c701a49506b67ae6174f3ade3d 100644
--- a/drivers/rtc/rtc-zynqmp.c
+++ b/drivers/rtc/rtc-zynqmp.c
@@ -208,13 +208,13 @@ static int xlnx_rtc_read_offset(struct device *dev, long *offset)
 static int xlnx_rtc_set_offset(struct device *dev, long offset)
 {
 	struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
-	unsigned long long rtc_ppb = RTC_PPB;
-	unsigned int tick_mult = do_div(rtc_ppb, xrtcdev->freq);
+	unsigned int calibval, tick_mult, fract_part;
 	unsigned char fract_tick = 0;
-	unsigned int calibval;
-	short int  max_tick;
-	int fract_offset;
+	int freq = xrtcdev->freq;
+	int max_tick, fract_offset;
 
+	/* ticks to reach RTC_PPB */
+	tick_mult = DIV_ROUND_CLOSEST(RTC_PPB, xrtcdev->freq);
 	if (offset < RTC_MIN_OFFSET || offset > RTC_MAX_OFFSET)
 		return -ERANGE;
 
@@ -223,29 +223,22 @@ static int xlnx_rtc_set_offset(struct device *dev, long offset)
 
 	/* Number fractional ticks for given offset */
 	if (fract_offset) {
+		/* round up here so we stay below a full tick */
+		fract_part = DIV_ROUND_UP(tick_mult, RTC_FR_MAX_TICKS);
 		if (fract_offset < 0) {
-			fract_offset = fract_offset + tick_mult;
+			fract_offset += (fract_part * RTC_FR_MAX_TICKS);
 			max_tick--;
 		}
-		if (fract_offset > (tick_mult / RTC_FR_MAX_TICKS)) {
-			for (fract_tick = 1; fract_tick < 16; fract_tick++) {
-				if (fract_offset <=
-				    (fract_tick *
-				     (tick_mult / RTC_FR_MAX_TICKS)))
-					break;
-			}
-		}
+		fract_tick = fract_offset / fract_part;
 	}
 
 	/* Zynqmp RTC uses second and fractional tick
 	 * counters for compensation
 	 */
-	calibval = max_tick + RTC_CALIB_DEF;
+	calibval = max_tick + freq;
 
 	if (fract_tick)
-		calibval |= RTC_FR_EN;
-
-	calibval |= (fract_tick << RTC_FR_DATSHIFT);
+		calibval |= (RTC_FR_EN | (fract_tick << RTC_FR_DATSHIFT));
 
 	writel(calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
 

-- 
2.47.3



From tomas.melin at vaisala.com  Mon Dec  1 04:50:29 2025
From: tomas.melin at vaisala.com (Tomas Melin)
Date: Mon, 01 Dec 2025 12:50:29 +0000
Subject: [PATCH 4/4] rtc: zynqmp: use dynamic max and min offset ranges
In-Reply-To: <20251201-zynqmp-rtc-updates-v1-0-33875c1e385b@vaisala.com>
References: <20251201-zynqmp-rtc-updates-v1-0-33875c1e385b@vaisala.com>
Message-ID: <20251201-zynqmp-rtc-updates-v1-4-33875c1e385b@vaisala.com>

Maximum and minimum offsets in ppb that can be handled are dependent on
the rtc clock frequency and what can fit in the 16-bit register field.

Signed-off-by: Tomas Melin <tomas.melin at vaisala.com>
---
 drivers/rtc/rtc-zynqmp.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c
index 3bc8831ba2c4c4c701a49506b67ae6174f3ade3d..0cebc99b15a6de2440a60afc2bd1769eccfa84b3 100644
--- a/drivers/rtc/rtc-zynqmp.c
+++ b/drivers/rtc/rtc-zynqmp.c
@@ -44,8 +44,6 @@
 #define RTC_FR_MASK		0xF0000
 #define RTC_FR_MAX_TICKS	16
 #define RTC_PPB			1000000000LL
-#define RTC_MIN_OFFSET		-32768000
-#define RTC_MAX_OFFSET		32767000
 
 struct xlnx_rtc_dev {
 	struct rtc_device	*rtc;
@@ -215,12 +213,12 @@ static int xlnx_rtc_set_offset(struct device *dev, long offset)
 
 	/* ticks to reach RTC_PPB */
 	tick_mult = DIV_ROUND_CLOSEST(RTC_PPB, xrtcdev->freq);
-	if (offset < RTC_MIN_OFFSET || offset > RTC_MAX_OFFSET)
-		return -ERANGE;
-
 	/* Number ticks for given offset */
 	max_tick = div_s64_rem(offset, tick_mult, &fract_offset);
 
+	if (freq + max_tick > RTC_TICK_MASK || (freq + max_tick < 1))
+		return -ERANGE;
+
 	/* Number fractional ticks for given offset */
 	if (fract_offset) {
 		/* round up here so we stay below a full tick */

-- 
2.47.3



From john.ogness at linutronix.de  Mon Dec  1 04:58:49 2025
From: john.ogness at linutronix.de (John Ogness)
Date: Mon, 01 Dec 2025 14:04:49 +0106
Subject: CSD lockup during kexec due to unbounded busy-wait in
 pl011_console_write_atomic (arm64)
In-Reply-To: <aSnI8UQRNICSKxAb@pathway.suse.cz>
References: <sqwajvt7utnt463tzxgwu2yctyn5m6bjwrslsnupfexeml6hkd@v6sqmpbu3vvu>
 <aSnI8UQRNICSKxAb@pathway.suse.cz>
Message-ID: <87ecpefjee.fsf@jogness.linutronix.de>

On 2025-11-28, Petr Mladek <pmladek at suse.com> wrote:

> On Tue 2025-11-25 08:02:16, Breno Leitao wrote:
>> Hello,
>> 
>> I am reporting a CSD lockup issue that occurs during kexec on ARM64 hosts,
>> which I have traced to the amba-pl011 serial driver waiting for hardware with
>> IRQs disabled in the nbcon atomic write path.
>> 
>> 
>> PROBLEM SUMMARY:
>> ================
>> During kexec, a CSD lockup occurs when pl011_console_write_atomic() performs
>> an unbounded busy-wait for hardware synchronization while IRQs are disabled.
>> This blocks other CPUs for extended periods (>11 seconds observed), triggering
>> CSD lock timeouts.
>
> I do _not_ think that the CPU was waiting in pl011_console_write_atomic() in the
> the following cycle the entire 11 secs:
>
> 	while ((pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr) & uap->vendor->fr_busy)
> 		cpu_relax();
>
> A more likely scenario was that pl011_console_write_atomic() was
> called several times during this period because there were more
> pending messages.
>
> See below.
>
>> KERNEL VERSION:
>> ===============
>> Observed on kernel 6.13, but the code path appears similar in upstream.
>> 
>> 
>> ERROR MESSAGE:
>> ==============
>>   mlx5_core 0000:03:00.0: Shutdown was called
>>   kvm: exiting hardware virtualization
>>   arm-smmu-v3 arm-smmu-v3.10.auto: CMD_SYNC timeout at 0x00000103 [hwprod 0x00000104, hwcons 0x00000102]
>>   smp: csd: Detected non-responsive CSD lock (#1) on CPU#4, waiting 5000000032 ns for CPU#00 do_nothing (kernel/smp.c:1057)
>>   smp:     csd: CSD lock (#1) unresponsive.
>>   Sending NMI from CPU 4 to CPUs 0:
>>   NMI backtrace for cpu 0
>>   pstate: 03401009 (nzcv daif +PAN -UAO +TCO +DIT +SSBS BTYPE=--)
>>   pc : pl011_console_write_atomic (./arch/arm64/include/asm/vdso/processor.h:12 drivers/tty/serial/amba-pl011.c:2540)
>
> This seems to be the cycle:
>
> 	while ((pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr) & uap->vendor->fr_busy)
> 		cpu_relax();
>
>>   lr : pl011_console_write_atomic (drivers/tty/serial/amba-pl011.c:292 drivers/tty/serial/amba-pl011.c:298 drivers/tty/serial/amba-pl011.c:2539)
>>   sp : ffff80010e26fae0
>>   pmr: 000000c0
>>   x29: ffff80010e26fae0 x28: ffff800082ddb000 x27: 00000000000000e0
>>   x26: 0000000000000001 x25: ffff8000826a8de8 x24: 00000000000008eb
>>   x23: 0000000000000000 x22: 0000000000000001 x21: 0000000000000000
>>   x20: ffff00009c19c880 x19: ffff80010e26fb88 x18: 0000000000000018
>>   x17: 696f70646e452065 x16: 4943502032303830 x15: 3130783020737361
>>   x14: 6c63203030206570 x13: 746e696f70646e45 x12: 0000000000000000
>>   x11: 0000000000000008 x10: 0000000000000000 x9 : ffff800081888d80
>>   x8 : 0000000000000018 x7 : 205d313332363336 x6 : 362e31202020205b
>>   x5 : ffff000097d4700f x4 : ffff80010e26f99f x3 : ffff800081125220
>>   x2 : 0000000000000052 x1 : 000000000000000a x0 : ffff00009c19c880
>>   Call trace:
>>   pl011_console_write_atomic (./arch/arm64/include/asm/vdso/processor.h:12 drivers/tty/serial/amba-pl011.c:2540) (P)
>>   nbcon_emit_next_record (kernel/printk/nbcon.c:1049)
>>   __nbcon_atomic_flush_pending_con (kernel/printk/nbcon.c:1517)
>>   __nbcon_atomic_flush_pending.llvm.15488114865160659019 (./arch/arm64/include/asm/alternative-macros.h:254 ./arch/arm64/include/asm/cpufeature.h:808 ./arch/arm64/include/asm/irqflags.h:192 kernel/printk/nbcon.c:1562 kernel/printk/nbcon.c:1612)
>>   nbcon_atomic_flush_pending (kernel/printk/nbcon.c:1629)
>
> This code looks like:
>
> static void nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq,
> 					   bool allow_unsafe_takeover)
> {
> [...]
> 	/*
> 	 * Atomic flushing does not use console driver synchronization (i.e.
> 	 * it does not hold the port lock for uart consoles). Therefore IRQs
> 	 * must be disabled to avoid being interrupted and then calling into
> 	 * a driver that will deadlock trying to acquire console ownership.
> 	 */
> 	local_irq_save(flags);
>
> 	err = __nbcon_atomic_flush_pending_con(con, stop_seq, allow_unsafe_takeover);
>
> 	local_irq_restore(flags);
> [...]
> }
>
> It means that IRQs are disabled until all pending messages are flushed.
>
>>   printk_kthreads_shutdown (kernel/printk/printk.c:?)
>
> But the function seems be called with IRQs enabled. So that it might
> help to restore IRQs after each flushed message.
>
>>   syscore_shutdown (drivers/base/syscore.c:120)
>>   kernel_kexec (kernel/kexec_core.c:1045)
>> 
>> NOTES:
>> ======
>> 
>> This is slightly similar to a report I gave a while ago [1] that got
>> fixed by Petr's a7df4ed0af77 ("printk: Allow to use the printk kthread
>> immediately even for 1st nbcon")
>> 
>> https://lore.kernel.org/all/aGVn%2FSnOvwWewkOW at gmail.com/
>> 
>> QUESTION
>> ========
>> 
>> 1) Should nbcon wait for hardware synchronizations with IRQ disabled?
>> 2) Can the hardware synchronization be moved of the IRQ disabled path?
>
> This would be complicated because the nbcon console ownership has
> to be acquired with IRQs disabled. Otherwise, it might cause a
> deadlock because uart_port_lock() has to acquire the nbcon console
> as well.
>
> But we could extend the existing commit d5d399efff6577 ("printk/nbcon:
> Release nbcon consoles ownership in atomic flush after each emitted
> record") and restore IRQs after each emitted record.
>
> I wonder if the following patch would help in this scenario.
> It is made on top of "for-next" branch in printk/linux.git.
> But the most important pre-requisite is the above mentioned commit
> in the branch "rework/atomic-flush-hardlockup".
>
> Note that the patch is only compile tested.
>
> From 6173069ae66fbb3b903cbc3798c16d3b8046da08 Mon Sep 17 00:00:00 2001
> From: Petr Mladek <pmladek at suse.com>
> Date: Fri, 28 Nov 2025 16:16:19 +0100
> Subject: [RFC] printk/nbcon: Restore IRQ in atomic flush after each emitted
>  record
>
> The commit d5d399efff6577 ("printk/nbcon: Release nbcon consoles ownership
> in atomic flush after each emitted record") prevented stall of a CPU
> which lost nbcon console ownership because another CPU entered
> an emergency flush.
>
> But there is still the problem that the CPU doing the emergency flush
> might cause a stall on its own.
>
> Let's go even further and restore IRQ in the atomic flush after
> each emitted record.
>
> It is not a complete solution. The interrupts and/or scheduling might
> still be blocked when the emergency atomic flush was called with
> IRQs and/or scheduling disabled. But it should remove the following
> lockup:
>
>   mlx5_core 0000:03:00.0: Shutdown was called
>   kvm: exiting hardware virtualization
>   arm-smmu-v3 arm-smmu-v3.10.auto: CMD_SYNC timeout at 0x00000103 [hwprod 0x00000104, hwcons 0x00000102]
>   smp: csd: Detected non-responsive CSD lock (#1) on CPU#4, waiting 5000000032 ns for CPU#00 do_nothing (kernel/smp.c:1057)
>   smp:     csd: CSD lock (#1) unresponsive.
>   [...]
>   Call trace:
>   pl011_console_write_atomic (./arch/arm64/include/asm/vdso/processor.h:12 drivers/tty/serial/amba-pl011.c:2540) (P)
>   nbcon_emit_next_record (kernel/printk/nbcon.c:1049)
>   __nbcon_atomic_flush_pending_con (kernel/printk/nbcon.c:1517)
>   __nbcon_atomic_flush_pending.llvm.15488114865160659019 (./arch/arm64/include/asm/alternative-macros.h:254 ./arch/arm64/include/asm/cpufeature.h:808 ./arch/arm64/include/asm/irqflags.h:192 kernel/printk/nbcon.c:1562 kernel/printk/nbcon.c:1612)
>   nbcon_atomic_flush_pending (kernel/printk/nbcon.c:1629)
>   printk_kthreads_shutdown (kernel/printk/printk.c:?)
>   syscore_shutdown (drivers/base/syscore.c:120)
>   kernel_kexec (kernel/kexec_core.c:1045)
>   __arm64_sys_reboot (kernel/reboot.c:794 kernel/reboot.c:722 kernel/reboot.c:722)
>   invoke_syscall (arch/arm64/kernel/syscall.c:50)
>   el0_svc_common.llvm.14158405452757855239 (arch/arm64/kernel/syscall.c:?)
>   do_el0_svc (arch/arm64/kernel/syscall.c:152)
>   el0_svc (./arch/arm64/include/asm/alternative-macros.h:254 ./arch/arm64/include/asm/cpufeature.h:808 ./arch/arm64/include/asm/irqflags.h:73 arch/arm64/kernel/entry-common.c:169 arch/arm64/kernel/entry-common.c:182 arch/arm64/kernel/entry-common.c:749)
>   el0t_64_sync_handler (arch/arm64/kernel/entry-common.c:820)
>   el0t_64_sync (arch/arm64/kernel/entry.S:600)
>
> In this case, nbcon_atomic_flush_pending() is called from
> printk_kthreads_shutdown() with IRQs and scheduling enabled.
>
> An ultimate solution would be touching the watchdog. But it would hide
> all problems. Let's do it later when anyone reports a stall which does
> not have a better solution.
>
> Closes: https://lore.kernel.org/r/sqwajvt7utnt463tzxgwu2yctyn5m6bjwrslsnupfexeml6hkd at v6sqmpbu3vvu
> Signed-off-by: Petr Mladek <pmladek at suse.com>
> ---
>  kernel/printk/nbcon.c | 29 ++++++++++++++++-------------
>  1 file changed, 16 insertions(+), 13 deletions(-)
>
> diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
> index 3fa403f9831f..6b8becb6ecd9 100644
> --- a/kernel/printk/nbcon.c
> +++ b/kernel/printk/nbcon.c
> @@ -1549,6 +1549,7 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
>  {
>  	struct nbcon_write_context wctxt = { };
>  	struct nbcon_context *ctxt = &ACCESS_PRIVATE(&wctxt, ctxt);
> +	unsigned long flags;
>  	int err = 0;
>  
>  	ctxt->console			= con;
> @@ -1557,18 +1558,31 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
>  	ctxt->allow_unsafe_takeover	= nbcon_allow_unsafe_takeover();
>  
>  	while (nbcon_seq_read(con) < stop_seq) {
> -		if (!nbcon_context_try_acquire(ctxt, false))
> +		/*
> +		 * Atomic flushing does not use console driver synchronization
> +		 * (i.e. it does not hold the port lock for uart consoles).
> +		 * Therefore IRQs must be disabled to avoid being interrupted
> +		 * and then calling into a driver that will deadlock trying
> +		 * to acquire console ownership.
> +		 */
> +		local_irq_save(flags);
> +		if (!nbcon_context_try_acquire(ctxt, false)) {
> +			local_irq_restore(flags);
>  			return -EPERM;
> +		}
>  
>  		/*
>  		 * nbcon_emit_next_record() returns false when the console was
>  		 * handed over or taken over. In both cases the context is no
>  		 * longer valid.
>  		 */
> -		if (!nbcon_emit_next_record(&wctxt, true))
> +		if (!nbcon_emit_next_record(&wctxt, true)) {
> +			local_irq_restore(flags);
>  			return -EAGAIN;
> +		}
>  
>  		nbcon_context_release(ctxt);
> +		local_irq_restore(flags);

Using local_irq_save()/_restore() here is not acceptable for PREEMPT_RT
because __nbcon_atomic_flush_pending_con() is also used by
nbcon_device_release().

Using local_lock_irqsave()/_irqrestore() instead is also not acceptable
because __nbcon_atomic_flush_pending_con() is called by vprintk_emit(),
which can be a context that does not allow sleeping locks.

If we want this kind of a solution, nbcon_device_release() will need an
atomic flushing variant that does not explicitly disable interrupts.

John Ogness


From robh at kernel.org  Mon Dec  1 04:59:34 2025
From: robh at kernel.org (Rob Herring)
Date: Mon, 1 Dec 2025 06:59:34 -0600
Subject: [PATCH v5 0/3] drm/vc4: Fixup DT and DT binding issues from
 recent patchset
In-Reply-To: <20241220-dt-bcm2712-fixes-v5-0-cbbf13d2e97a@raspberrypi.com>
References: <20241220-dt-bcm2712-fixes-v5-0-cbbf13d2e97a@raspberrypi.com>
Message-ID: <20251201125934.GA3004948-robh@kernel.org>

On Fri, Dec 20, 2024 at 06:11:10PM +0000, Dave Stevenson wrote:
> I missed the DT errors from the recent patchset[1] (DT patches
> in linux-next via Florian, DRM bindings patches on dri-misc-next)
> as Rob's bot report got spam filtered, so this is a fixup set.
> 
> Largely it was changes to number of interrupts or clocks in the
> bindings, so those are now covered.
> 
> I've fixed up the missing "interrupt-controller" flags for 2711
> and 2712 whilst here.

I found this is still warning a year later, so I fixed up the commit 
messages and applied.

The comments were a bit nitpicky for a v5 version IMO. However, you went 
to the trouble of preparing 5 versions of the series and we spent our 
time reviewing them, so why abandon them? 

It would be nice if the Broadcom folks spent some effort fixing the 
remaining DT warnings. I see little progress.

> 
> I can't get my head around what is meant to happen with ranges:
> "soc at 107c000000: firmware: 'ranges' is a required property"
> The meaning seems obvious.

Adding "ranges" is probably not correct. Generally, 'firmware' is not 
MMIO and should not be under an MMIO bus (i.e. simple-bus).

> 
> However if I add it then I get:
> "firmware: '#address-cells', '#size-cells', 'dma-ranges', 'ranges' do
> not match any of the regexes: 'pinctrl-[0-9]+'
> from schema $id: http://devicetree.org/schemas/arm/bcm/raspberrypi,bcm2835-firmware.yaml#

If you add properties to the 'firmware' node, then you need to add those 
properties to its schema.

> 
> There's obviously some other flag I need to set in the bindings,
> but I can't work it out. We have similar errors for all the Pi
> platforms for one or more nodes.
> Please advise and I'll happily fix them all.


From amadeus at jmu.edu.cn  Mon Dec  1 05:01:06 2025
From: amadeus at jmu.edu.cn (Chukun Pan)
Date: Mon,  1 Dec 2025 21:01:06 +0800
Subject: [PATCH 1/4] dt-bindings: arm: rockchip: Add HINLINK H28K
In-Reply-To: <f27dc5ef-1c60-4724-8e18-33bbc4230d3e@kernel.org>
References: <f27dc5ef-1c60-4724-8e18-33bbc4230d3e@kernel.org>
Message-ID: <20251201130106.236903-1-amadeus@jmu.edu.cn>

Hi,

> Just squash these two binding patches. Way too much churn.

However, they are different SBCs manufactured by different companies:

HINLINK H28K - Shenzhen HINLINK manufactures
MangoPi M28K - Beijing Widora manufactures

So should I squash them into a patch?

> Anyway, looks like duplicate - two devices with same model name.

These two SBCs are indeed very similar, both in name and configuration.
So I put them in one series. Perhaps splitting them into two series to
avoid confusion would have been better?

> You have entire commit msg to explain that.

Thanks,
Chukun


From broonie at kernel.org  Mon Dec  1 05:06:49 2025
From: broonie at kernel.org (Mark Brown)
Date: Mon, 1 Dec 2025 13:06:49 +0000
Subject: [PATCH] spi: cadence-quadspi: Fix cqspi_probe() error handling
 for runtime pm
In-Reply-To: <20251201072844.GA6785@francesco-nb>
References: <20251119152545.2591651-1-s-vadapalli@ti.com>
 <20251201072844.GA6785@francesco-nb>
Message-ID: <e7ccef20-a490-45cf-9e55-16c9b2e01f44@sirena.org.uk>

On Mon, Dec 01, 2025 at 08:28:44AM +0100, Francesco Dolcini wrote:
> On Wed, Nov 19, 2025 at 08:53:53PM +0530, Siddharth Vadapalli wrote:

> > Commit f1eb4e792bb1 ("spi: spi-cadence-quadspi: Enable pm runtime earlier
> > to avoid imbalance") relocated code but missed updating the error handling
> > path associated with it.

> Our CI just hit this WARNING with 6.18 kernel, on verdin-am62. To me it's a
> regression from v6.18, specifically from spi-fix-v6.18-rc7, we did not
> had any such WARNING with the master build we did run last Friday.

Does this fix the issues you're seeing:

    https://lore.kernel.org/r/20251130091251.12120-1-alitariq45892 at gmail.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251201/33f58ba5/attachment.sig>

From josua at solid-run.com  Mon Dec  1 05:07:20 2025
From: josua at solid-run.com (Josua Mayer)
Date: Mon, 01 Dec 2025 14:07:20 +0100
Subject: [PATCH v4 1/8] dt-bindings: arm: fsl: Add various solidrun i.mx8m
 boards
In-Reply-To: <20251201-imx8mp-hb-iiot-v4-0-53a4cd6c21bf@solid-run.com>
References: <20251201-imx8mp-hb-iiot-v4-0-53a4cd6c21bf@solid-run.com>
Message-ID: <20251201-imx8mp-hb-iiot-v4-1-53a4cd6c21bf@solid-run.com>

Add bindings for various SolidRun boards:

- i.MX8MP HummingBoard IIoT - based on the SolidRun i.MX8M Plus SoM
- SolidSense N8 - single-board design with i.MX8M Nano
- i.MX8M Mini System on Module
- i.MX8M Mini HummingBoard Ripple

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
Signed-off-by: Josua Mayer <josua at solid-run.com>
---
 Documentation/devicetree/bindings/arm/fsl.yaml | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
index 00cdf490b0620..f70b933ce3746 100644
--- a/Documentation/devicetree/bindings/arm/fsl.yaml
+++ b/Documentation/devicetree/bindings/arm/fsl.yaml
@@ -1041,6 +1041,13 @@ properties:
           - const: phytec,imx8mm-phycore-som        # phyCORE-i.MX8MM SoM
           - const: fsl,imx8mm
 
+      - description: SolidRun i.MX8MM SoM based boards
+        items:
+          - enum:
+              - solidrun,imx8mm-hummingboard-ripple # SolidRun i.MX8MM SoM on HummingBoard Ripple
+          - const: solidrun,imx8mm-sr-som
+          - const: fsl,imx8mm
+
       - description: Variscite VAR-SOM-MX8MM based boards
         items:
           - const: variscite,var-som-mx8mm-symphony
@@ -1069,6 +1076,7 @@ properties:
               - fsl,imx8mn-ddr4-evk       # i.MX8MN DDR4 EVK Board
               - fsl,imx8mn-evk            # i.MX8MN LPDDR4 EVK Board
               - gw,imx8mn-gw7902          # i.MX8MM Gateworks Board
+              - solidrun,solidsense-n8-compact # SolidRun SolidSense N8 Compact
           - const: fsl,imx8mn
 
       - description: Variscite VAR-SOM-MX8MN based boards
@@ -1205,6 +1213,7 @@ properties:
         items:
           - enum:
               - solidrun,imx8mp-cubox-m             # SolidRun i.MX8MP SoM on CuBox-M
+              - solidrun,imx8mp-hummingboard-iiot   # SolidRun i.MX8MP SoM on HummingBoard IIoT
               - solidrun,imx8mp-hummingboard-mate   # SolidRun i.MX8MP SoM on HummingBoard Mate
               - solidrun,imx8mp-hummingboard-pro    # SolidRun i.MX8MP SoM on HummingBoard Pro
               - solidrun,imx8mp-hummingboard-pulse  # SolidRun i.MX8MP SoM on HummingBoard Pulse

-- 
2.51.0




From josua at solid-run.com  Mon Dec  1 05:07:21 2025
From: josua at solid-run.com (Josua Mayer)
Date: Mon, 01 Dec 2025 14:07:21 +0100
Subject: [PATCH v4 2/8] Input: ilitek_ts_i2c: fix warning with gpio
 controllers that sleep
In-Reply-To: <20251201-imx8mp-hb-iiot-v4-0-53a4cd6c21bf@solid-run.com>
References: <20251201-imx8mp-hb-iiot-v4-0-53a4cd6c21bf@solid-run.com>
Message-ID: <20251201-imx8mp-hb-iiot-v4-2-53a4cd6c21bf@solid-run.com>

The ilitek touchscreen driver uses the non-sleeping gpiod_set_value
function for reset.

Switch to using gpiod_set_value_cansleep() when controlling reset_gpio to
support GPIO providers that may sleep, such as I2C GPIO expanders.

Further switch the mdelay calls on the reset path to fsleep (preferred
in non-atomic contexts).

This fixes noisy complaints in kernel log for gpio providers that do
sleep.

Signed-off-by: Josua Mayer <josua at solid-run.com>
---
 drivers/input/touchscreen/ilitek_ts_i2c.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/input/touchscreen/ilitek_ts_i2c.c b/drivers/input/touchscreen/ilitek_ts_i2c.c
index 0dd632724a003..10e5530d6a5d0 100644
--- a/drivers/input/touchscreen/ilitek_ts_i2c.c
+++ b/drivers/input/touchscreen/ilitek_ts_i2c.c
@@ -396,10 +396,10 @@ static const struct ilitek_protocol_map ptl_func_map[] = {
 static void ilitek_reset(struct ilitek_ts_data *ts, int delay)
 {
 	if (ts->reset_gpio) {
-		gpiod_set_value(ts->reset_gpio, 1);
-		mdelay(10);
-		gpiod_set_value(ts->reset_gpio, 0);
-		mdelay(delay);
+		gpiod_set_value_cansleep(ts->reset_gpio, 1);
+		fsleep(10000);
+		gpiod_set_value_cansleep(ts->reset_gpio, 0);
+		fsleep(delay * 1000);
 	}
 }
 

-- 
2.51.0




From josua at solid-run.com  Mon Dec  1 05:07:19 2025
From: josua at solid-run.com (Josua Mayer)
Date: Mon, 01 Dec 2025 14:07:19 +0100
Subject: [PATCH v4 0/8] arm64: dts: add description for solidrun imx8mp
 hummingboard-iiot
Message-ID: <20251201-imx8mp-hb-iiot-v4-0-53a4cd6c21bf@solid-run.com>

This patchset mainly adds description for 3 SolidRun boards:
- i.MX8MP Hummingboard IIoT
- SolidSense N8 Compact
- i.MX8MM Hummingboard Ripple

This includes dt bindings and a range of bug-fixes:

- dt bindings for the boards
- fix to dsi panel bindings referncing panel-common and adding port
  property
- cosmetic fix to some  solidrun imx8mp boards for regulator gpio
   polarity
- fix dsi hdmi bridge on hummingboard pulse
- compile dtbs with symbols to support overlays
- gpiod_set_value _can_sleep conversion for panel and touchscreen
   drivers

Open Questions:

- How to describe HX3 USB-2.0/3.0 Hub placed on a USB-2.0-only Bus
  (affects imx8mm-hummingboard-ripple.dts)
- Is "description for" implied not only on dt-bindings patches, but also
  dts? E.g. is this commit subject acceptable?:
  "arm64: dts: add solidrun solidsense-n8 board"

Signed-off-by: Josua Mayer <josua at solid-run.com>
---
Changes in v4:
- EDITME: describe what is new in this series revision.
- EDITME: use bulletpoints and terse descriptions.
- dropped patches already picked into drm-misc-next
- ronbo panel: picked up reviewed-by tag
  (Reviewed-by: Neil Armstrong <neil.armstrong at linaro.org>)
- ilitek-ts: changed mdelay calls on reset path to fsleep
  (Note Dmitry requested msleep/usleep_range)
  (Reported-by: Dmitry Torokhov <dmitry.torokhov at gmail.com>)
- changed hummingboard-iiot tpm irq type to level
- Link to v3: https://lore.kernel.org/r/20251117-imx8mp-hb-iiot-v3-0-bf1a4cf5fa8e at solid-run.com

Changes in v3:
- sinmplified language in gpiod_can_sleep patches.
  (Reported-By: Frank Li <Frank.li at nxp.com>)
- collected ack on winstar lvds panel binding
  (Acked-by: Conor Dooley <conor.dooley at microchip.com>)
- Link to v2: https://lore.kernel.org/r/20251107-imx8mp-hb-iiot-v2-0-d8233ded999e at solid-run.com

Changes in v2:
- fix spelling mistakes in commit descriptions.
- remove redundant "binding for" from subject:
  https://elixir.bootlin.com/linux/v6.17-rc3/source/Documentation/devicetree/bindings/submitting-patches.rst
  (Reported-by: Krzysztof Kozlowski <krzk at kernel.org>)
- remove one useless comment from imx8mm-sr-som.dtsi to fix long line
  warning.
- change ronbo panel binding to inherit panel-common and switch
  additionalProperties to unevaluatedProperties.
  (Reported-by: Krzysztof Kozlowski <krzk at kernel.org>)
- add dt binding for winstar lvds panel
- fix dtbs_check for dsi & lvds panel addons
- change n8 board dts comment-style in header
- collected ack on solidrun boards bindings patch (patch 1 in the series)
  (Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>)
- added standard led label property to hb-iiot multi-purpose leds
  ensuring consistent names in case lp5562 driver starts using it.
- Link to v1: https://lore.kernel.org/r/20251027-imx8mp-hb-iiot-v1-0-683f86357818 at solid-run.com

---
Josua Mayer (8):
      dt-bindings: arm: fsl: Add various solidrun i.mx8m boards
      Input: ilitek_ts_i2c: fix warning with gpio controllers that sleep
      arm64: dts: imx8mp-hummingboard-pulse/cubox-m: fix vmmc gpio polarity
      arm64: dts: imx8mp-hummingboard-pulse: fix mini-hdmi dsi port reference
      arm64: dts: imx8mp-sr-som: build dtbs with symbols for overlay support
      arm64: dts: add description for solidrun imx8mp hummingboard-iiot
      arm64: dts: add description for solidrun solidsense-n8 board
      arm64: dts: add description for solidrun i.mx8mm som and evb

 Documentation/devicetree/bindings/arm/fsl.yaml     |   9 +
 arch/arm64/boot/dts/freescale/Makefile             |  15 +
 .../dts/freescale/imx8mm-hummingboard-ripple.dts   | 335 ++++++++
 arch/arm64/boot/dts/freescale/imx8mm-sr-som.dtsi   | 395 ++++++++++
 .../dts/freescale/imx8mn-solidsense-n8-compact.dts | 853 +++++++++++++++++++++
 arch/arm64/boot/dts/freescale/imx8mp-cubox-m.dts   |   2 +-
 ...hummingboard-iiot-panel-dsi-WJ70N3TYJHMNG0.dtso |  69 ++
 ...ummingboard-iiot-panel-lvds-WF70A8SYJHLNGA.dtso | 105 +++
 .../imx8mp-hummingboard-iiot-rs485-a.dtso          |  18 +
 .../imx8mp-hummingboard-iiot-rs485-b.dtso          |  18 +
 .../dts/freescale/imx8mp-hummingboard-iiot.dts     | 713 +++++++++++++++++
 .../imx8mp-hummingboard-pulse-common.dtsi          |   2 +-
 .../imx8mp-hummingboard-pulse-mini-hdmi.dtsi       |  11 +-
 drivers/input/touchscreen/ilitek_ts_i2c.c          |   8 +-
 14 files changed, 2540 insertions(+), 13 deletions(-)
---
base-commit: 45a477d545205afbb4753a4a3371a16136ded2d1
change-id: 20251026-imx8mp-hb-iiot-525b03beea62

Best regards,
-- 
Josua Mayer <josua at solid-run.com>




From josua at solid-run.com  Mon Dec  1 05:07:23 2025
From: josua at solid-run.com (Josua Mayer)
Date: Mon, 01 Dec 2025 14:07:23 +0100
Subject: [PATCH v4 4/8] arm64: dts: imx8mp-hummingboard-pulse: fix
 mini-hdmi dsi port reference
In-Reply-To: <20251201-imx8mp-hb-iiot-v4-0-53a4cd6c21bf@solid-run.com>
References: <20251201-imx8mp-hb-iiot-v4-0-53a4cd6c21bf@solid-run.com>
Message-ID: <20251201-imx8mp-hb-iiot-v4-4-53a4cd6c21bf@solid-run.com>

imx8mp.dtsi includes a default port at 1 node with an empty placeholder
endpoint intended for linking to a dsi bridge or panel.
HummingBoard Pulse mini-hdmi dtsi added and linked hdmi brodge to yet
another endpoint.

This duplicate endpoint can cause dsi_attach to fail.

Remove the duplicate node and link to the one defined in soc dtsi.
Further remove the unnecessary attach-bridge property.

Fixes: 2a222aa2bee9 ("arm64: dts: add description for solidrun imx8mp hummingboard variants")
Signed-off-by Josua Mayer <josua at solid-run.com>
---
 .../dts/freescale/imx8mp-hummingboard-pulse-mini-hdmi.dtsi    | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-mini-hdmi.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-mini-hdmi.dtsi
index 46916ddc05335..0e5f4607c7c1b 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-mini-hdmi.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-mini-hdmi.dtsi
@@ -41,7 +41,7 @@ port at 0 {
 				reg = <0>;
 
 				adv7535_from_dsim: endpoint {
-					remote-endpoint = <&dsim_to_adv7535>;
+					remote-endpoint = <&mipi_dsi_out>;
 				};
 			};
 
@@ -71,11 +71,8 @@ &lcdif1 {
 &mipi_dsi {
 	samsung,esc-clock-frequency = <10000000>;
 	status = "okay";
+};
 
-	port at 1 {
-		dsim_to_adv7535: endpoint {
-			remote-endpoint = <&adv7535_from_dsim>;
-			attach-bridge;
-		};
-	};
+&mipi_dsi_out {
+	remote-endpoint = <&adv7535_from_dsim>;
 };

-- 
2.51.0




From josua at solid-run.com  Mon Dec  1 05:07:25 2025
From: josua at solid-run.com (Josua Mayer)
Date: Mon, 01 Dec 2025 14:07:25 +0100
Subject: [PATCH v4 6/8] arm64: dts: add description for solidrun imx8mp
 hummingboard-iiot
In-Reply-To: <20251201-imx8mp-hb-iiot-v4-0-53a4cd6c21bf@solid-run.com>
References: <20251201-imx8mp-hb-iiot-v4-0-53a4cd6c21bf@solid-run.com>
Message-ID: <20251201-imx8mp-hb-iiot-v4-6-53a4cd6c21bf@solid-run.com>

Add description for the SolidRun i.MX8MP HummingBoard IIoT.
The board is a new design around the i.MX8MP System on Module, not
sharing much with previous HummingBoards.

It comes with some common features:
- 3x USB-3.0 Type A connector
- 2x 1Gbps RJ45 Ethernet
- USB Type-C Console Port
- microSD connector
- RTC with backup battery
- RGB Status LED
- 1x M.2 M-Key connector with PCI-E Gen. 3 x1
- 1x M.2 B-Key connector with USB-2.0/3.0 + SIM card holder
- 1x LVDS Display Connector
- 1x DSI Display Connector
- GPIO header
- 2x RS232/RS485 ports (configurable)
- 2x CAN

In addition there is a board-to-board expansion connector to support
custom daughter boards with access to SPI, a range of GPIOs and -
notably - CAN and UART. Both 2x CAN and 2x UART can be muxed either
to this b2b connector, or a termianl block connector on the base board.

The routing choice for UART and CAN is expressed through gpio
mux-controllers in DT and can be changed by applying dtb addons.

Four dtb addons are provided:

- dsi panel Winstar WJ70N3TYJHMNG0
- lvds panel Winstar WF70A8SYJHLNGA
- RS485 on UART port "A" (default rs232)
- RS485 on UART port "B" (default rs232)

Signed-off-by: Josua Mayer <josua at solid-run.com>
---
 arch/arm64/boot/dts/freescale/Makefile             |   6 +
 ...hummingboard-iiot-panel-dsi-WJ70N3TYJHMNG0.dtso |  69 ++
 ...ummingboard-iiot-panel-lvds-WF70A8SYJHLNGA.dtso | 105 +++
 .../imx8mp-hummingboard-iiot-rs485-a.dtso          |  18 +
 .../imx8mp-hummingboard-iiot-rs485-b.dtso          |  18 +
 .../dts/freescale/imx8mp-hummingboard-iiot.dts     | 713 +++++++++++++++++++++
 6 files changed, 929 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index 8bda6fb0ff9c1..d414d0efe5e74 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -207,6 +207,12 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mp-dhcom-pdk3.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-dhcom-picoitx.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-edm-g-wb.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-iiot.dtb
+DTC_FLAGS_imx8mp-hummingboard-iiot := -@
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-iiot-panel-dsi-WJ70N3TYJHMNG0.dtbo
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-iiot-panel-lvds-WF70A8SYJHLNGA.dtbo
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-iiot-rs485-a.dtbo
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-iiot-rs485-b.dtbo
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-mate.dtb
 DTC_FLAGS_imx8mp-hummingboard-mate := -@
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-pro.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-panel-dsi-WJ70N3TYJHMNG0.dtso b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-panel-dsi-WJ70N3TYJHMNG0.dtso
new file mode 100644
index 0000000000000..e66ee2ce69d8d
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-panel-dsi-WJ70N3TYJHMNG0.dtso
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2025 Josua Mayer <josua at solid-run.com>
+ *
+ * Overlay for enabling HummingBoard IIoT MIPI-DSI connector
+ * with Winstar WJ70N3TYJHMNG0 panel.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+&{/} {
+	dsi_backlight: dsi-backlight {
+		compatible = "gpio-backlight";
+		gpios = <&tca6408_u48 3 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&i2c_dsi {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	touchscreen at 41 {
+		compatible = "ilitek,ili2130";
+		reg = <0x41>;
+		reset-gpios = <&tca6408_u48 6 GPIO_ACTIVE_LOW>;
+		interrupts-extended = <&tca6416_u21 13 IRQ_TYPE_LEVEL_LOW>;
+	};
+};
+
+&lcdif1 {
+	status = "okay";
+};
+
+&mipi_dsi {
+	samsung,esc-clock-frequency = <10000000>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+
+	panel at 0 {
+		/* This is a Winstar panel, but the ronbo panel uses same controls. */
+		compatible = "ronbo,rb070d30";
+		reg = <0>;
+		vcc-lcd-supply = <&reg_dsi_panel>;
+		power-gpios = <&tca6408_u48 2 GPIO_ACTIVE_HIGH>;
+		/* reset is active-low but driver inverts it internally */
+		reset-gpios = <&tca6408_u48 1 GPIO_ACTIVE_HIGH>;
+		updn-gpios = <&tca6408_u48 5 GPIO_ACTIVE_HIGH>;
+		shlr-gpios = <&tca6408_u48 4 GPIO_ACTIVE_LOW>;
+		backlight = <&dsi_backlight>;
+
+		port {
+			panel_from_dsim: endpoint {
+				remote-endpoint = <&dsim_to_panel>;
+			};
+		};
+	};
+
+	port at 1 {
+		dsim_to_panel: endpoint {
+			remote-endpoint = <&panel_from_dsim>;
+			data-lanes = <1 2 3 4>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-panel-lvds-WF70A8SYJHLNGA.dtso b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-panel-lvds-WF70A8SYJHLNGA.dtso
new file mode 100644
index 0000000000000..f8fb7fd0e4e49
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-panel-lvds-WF70A8SYJHLNGA.dtso
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2025 Josua Mayer <josua at solid-run.com>
+ *
+ * Overlay for enabling HummingBoard IIoT LVDS connector
+ * with Winstar WF70A8SYJHLNGA panel.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+&{/} {
+	lvds_backlight: lvds-backlight {
+		compatible = "gpio-backlight";
+		gpios = <&tca6408_u37 3 GPIO_ACTIVE_LOW>;
+	};
+
+	panel-lvds {
+		compatible = "winstar,wf70a8syjhlnga", "panel-lvds";
+		backlight = <&lvds_backlight>;
+		power-supply = <&reg_dsi_panel>;
+		enable-gpios = <&tca6408_u37 2 GPIO_ACTIVE_HIGH>;
+		reset-gpios = <&tca6408_u37 1 GPIO_ACTIVE_HIGH>;
+		data-mapping = "vesa-24";
+		width-mm = <154>;
+		height-mm = <86>;
+
+		panel-timing {
+			/*
+			 * Note: NXP BSP hard-codes 74MHz clock in ldb driver:
+			 * drivers/gpu/drm/imx/imx8mp-ldb.c
+			 * SolidRun BSP carries patch.
+			 */
+			clock-frequency = <49500000>;
+			hactive = <1024>;
+			vactive = <600>;
+			hfront-porch = <40>;
+			hback-porch = <144>;
+			hsync-len = <104>;
+			hsync-active = <0>;
+			vfront-porch = <3>;
+			vback-porch = <11>;
+			vsync-len = <10>;
+			vsync-active = <1>;
+			de-active = <1>;
+		};
+
+		port {
+			panel_from_lvds: endpoint {
+				remote-endpoint = <&lvds_ch0_out>;
+			};
+		};
+	};
+};
+
+&i2c_lvds {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	touchscreen at 41 {
+		compatible = "ilitek,ili2130";
+		reg = <0x41>;
+		reset-gpios = <&tca6408_u37 6 GPIO_ACTIVE_LOW>;
+		interrupts-extended = <&tca6416_u21 13 IRQ_TYPE_LEVEL_LOW>;
+	};
+};
+
+&lcdif2 {
+	status = "okay";
+};
+
+&lvds_bridge {
+	status = "okay";
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "okay";
+
+		port at 1 {
+			lvds_ch0_out: endpoint {
+				remote-endpoint = <&panel_from_lvds>;
+			};
+		};
+	};
+};
+
+&tca6408_u37 {
+	lvds-lr-hog {
+		gpio-hog;
+		gpios = <4 GPIO_ACTIVE_HIGH>;
+		output-high;
+		line-name = "lvds-l/r";
+	};
+
+	lvds-ud-hog {
+		gpio-hog;
+		gpios = <5 GPIO_ACTIVE_HIGH>;
+		output-high;
+		line-name = "lvds-u/d";
+	};
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-rs485-a.dtso b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-rs485-a.dtso
new file mode 100644
index 0000000000000..7bbf800b78fb1
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-rs485-a.dtso
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2025 Josua Mayer <josua at solid-run.com>
+ *
+ * Overlay for enabling HummingBoard IIoT on-board RS485 Port A on connector J5004.
+ */
+
+/dts-v1/;
+/plugin/;
+
+&uart3_rs_232_485_mux {
+	/* select rs485 */
+	idle-state = <1>;
+};
+
+&uart3 {
+	linux,rs485-enabled-at-boot-time;
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-rs485-b.dtso b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-rs485-b.dtso
new file mode 100644
index 0000000000000..d4bfea886ad12
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-rs485-b.dtso
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2025 Josua Mayer <josua at solid-run.com>
+ *
+ * Overlay for enabling HummingBoard IIoT on-board RS485 Port B on connector J5004.
+ */
+
+/dts-v1/;
+/plugin/;
+
+&uart4_rs_232_485_mux {
+	/* select rs485 */
+	idle-state = <1>;
+};
+
+&uart4 {
+	linux,rs485-enabled-at-boot-time;
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot.dts b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot.dts
new file mode 100644
index 0000000000000..070f03e5abab9
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot.dts
@@ -0,0 +1,713 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2024 Yazan Shhady <yazan.shhady at solid-run.com>
+ * Copyright 2025 Josua Mayer <josua at solid-run.com>
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/phy/phy-imx8-pcie.h>
+
+#include "imx8mp-sr-som.dtsi"
+
+/ {
+	model = "SolidRun i.MX8MP HummingBoard IIoT";
+	compatible = "solidrun,imx8mp-hummingboard-iiot",
+		     "solidrun,imx8mp-sr-som", "fsl,imx8mp";
+
+	aliases {
+		ethernet0 = &eqos; /* J10 */
+		ethernet1 = &fec; /* J11 */
+		rtc0 = &carrier_rtc;
+		rtc1 = &snvs_rtc;
+		gpio5 = &tca6408_u48;
+		gpio6 = &tca6408_u37;
+		gpio7 = &tca6416_u20;
+		gpio8 = &tca6416_u21;
+		i2c6 = &i2c_exp;
+		i2c7 = &i2c_csi;
+		i2c8 = &i2c_dsi;
+		i2c9 = &i2c_lvds;
+	};
+
+	v_1_2: regulator-1-2 {
+		compatible = "regulator-fixed";
+		regulator-name = "1v2";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	reg_dsi_panel: regulator-dsi-panel {
+		compatible = "regulator-fixed";
+		regulator-name = "dsi-panel";
+		regulator-min-microvolt = <11200000>;
+		regulator-max-microvolt = <11200000>;
+		gpios = <&tca6416_u20 15 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	/* power for M.2 B-Key connector (J6) */
+	regulator-m2-b {
+		compatible = "regulator-fixed";
+		regulator-name = "m2-b";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpios = <&tca6416_u20 5 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-always-on;
+	};
+
+	/* power for M.2 M-Key connector (J4) */
+	regulator-m2-m {
+		compatible = "regulator-fixed";
+		regulator-name = "m2-m";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpios = <&tca6416_u20 6 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-always-on;
+	};
+
+	vmmc: regulator-mmc {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&vmmc_pins>;
+		regulator-name = "vmmc";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio2 19 GPIO_ACTIVE_LOW>;
+		enable-active-high;
+		startup-delay-us = <250>;
+	};
+
+	/* power for USB-A J5003 */
+	vbus1: regulator-vbus-1 {
+		compatible = "regulator-fixed";
+		regulator-name = "vbus1";
+		gpio = <&tca6416_u20 14 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+	};
+
+	/* power for USB-A J27 behind USB Hub Port 3 */
+	regulator-vbus-2 {
+		compatible = "regulator-fixed";
+		regulator-name = "vbus2";
+		gpio = <&tca6416_u20 12 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+	};
+
+	/* power for USB-A J27 behind USB Hub Port 4 */
+	regulator-vbus-3 {
+		compatible = "regulator-fixed";
+		regulator-name = "vbus3";
+		gpio = <&tca6416_u20 13 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+	};
+
+	rfkill-m2-b-gnss {
+		compatible = "rfkill-gpio";
+		label = "m2-b gnss";
+		radio-type = "gps";
+		/* rfkill-gpio inverts internally */
+		shutdown-gpios = <&tca6416_u20 10 GPIO_ACTIVE_HIGH>;
+	};
+
+	rfkill-m2-b-wwan {
+		compatible = "rfkill-gpio";
+		label = "m2-b radio";
+		radio-type = "wwan";
+		/* rfkill-gpio inverts internally */
+		shutdown-gpios = <&tca6416_u20 9 GPIO_ACTIVE_HIGH>;
+	};
+
+	flexcan1_flexcan2_b2b_mux: mux-controller-0 {
+		compatible = "gpio-mux";
+		#mux-control-cells = <0>;
+		/*
+		 * Mux switches both flexcan1 and flexcan2 tx/rx between
+		 * expansion connector (J22) and on-board transceivers
+		 * using one GPIO: 0 = on-board, 1 connector.
+		 */
+		mux-gpios = <&tca6416_u20 3 GPIO_ACTIVE_HIGH>;
+		/* default on-board */
+		idle-state = <0>;
+	};
+
+	mux-controller-1 {
+		compatible = "gpio-mux";
+		#mux-control-cells = <0>;
+		/*
+		 * Mux switches can bus between different SoM board-to-board
+		 * connector pins which is used to support different SoMs.
+		 * i.MX8M Plus uses J7-12/16 and J9-54/56 for 2x flexcan.
+		 */
+		mux-gpios = <&tca6416_u20 4 GPIO_ACTIVE_HIGH>;
+		idle-state = <1>;
+	};
+
+	spi_mux: mux-controller-2 {
+		compatible = "gpio-mux";
+		#mux-control-cells = <0>;
+		/*
+		 * Mux switches spi bus between on-board tpm
+		 * and expansion connector (J22).
+		 */
+		mux-gpios = <&tca6416_u21 0 GPIO_ACTIVE_HIGH>;
+		/* default on-board */
+		idle-state = <0>;
+	};
+
+	uart3_uart4_b2b_mux: mux-controller-3 {
+		compatible = "gpio-mux";
+		#mux-control-cells = <0>;
+		/*
+		 * Mux switches both uart3 and uart4 tx/rx between expansion
+		 * connector (J22) and on-board rs232/rs485 transceivers
+		 * using one GPIO: 0 = on-board, 1 connector.
+		 */
+		mux-gpios = <&tca6416_u20 0 GPIO_ACTIVE_HIGH>;
+		/* default on-board */
+		idle-state = <0>;
+	};
+
+	uart3_rs_232_485_mux: mux-controller-4 {
+		compatible = "gpio-mux";
+		#mux-control-cells = <0>;
+		/*
+		 * Mux switches uart3 tx/rx between rs232 and rs485
+		 * transceivers. using one GPIO: 0 = rs232; 1 = rs485.
+		 */
+		mux-gpios = <&tca6416_u20 1 GPIO_ACTIVE_HIGH>;
+		/* default rs232 */
+		idle-state = <0>;
+	};
+
+	uart4_rs_232_485_mux: mux-controller-5 {
+		compatible = "gpio-mux";
+		#mux-control-cells = <0>;
+		/*
+		 * Mux switches uart4 tx/rx between rs232 and rs485
+		 * transceivers. using one GPIO: 0 = rs232; 1 = rs485.
+		 */
+		mux-gpios = <&tca6416_u20 2 GPIO_ACTIVE_HIGH>;
+		/* default rs232 */
+		idle-state = <0>;
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		wakeup-event {
+			label = "m2-m-wakeup";
+			interrupts-extended = <&tca6416_u21 11 IRQ_TYPE_EDGE_FALLING>;
+			linux,code = <KEY_WAKEUP>;
+			wakeup-source;
+		};
+	};
+};
+
+&ecspi2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&ecspi2_pins>;
+	num-cs = <1>;
+	cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	ecspi2_muxed: spi at 0 {
+		compatible = "spi-mux";
+		reg = <0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		/* mux bandwidth is 2GHz, soc max. spi clock is 166MHz */
+		spi-max-frequency = <166000000>;
+		mux-controls = <&spi_mux>;
+
+		tpm at 0 {
+			compatible = "infineon,slb9670", "tcg,tpm_tis-spi";
+			reg = <0>;
+			spi-max-frequency = <43000000>;
+			reset-gpios = <&tca6416_u21 1 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>;
+			interrupts-extended = <&tca6416_u21 9 IRQ_TYPE_LEVEL_LOW>;
+		};
+	};
+};
+
+&flexcan1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&can1_pins>;
+	status = "okay";
+
+	can-transceiver {
+		max-bitrate = <8000000>;
+	};
+};
+
+&flexcan2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&can2_pins>;
+	status = "okay";
+
+	can-transceiver {
+		max-bitrate = <8000000>;
+	};
+};
+
+&i2c2 {
+	i2c-mux at 70 {
+		compatible = "nxp,pca9546";
+		reg = <0x70>;
+		/*
+		 * This reset is open drain,
+		 * but reset core does not support GPIO_OPEN_DRAIN flag.
+		 */
+		reset-gpios = <&tca6416_u21 2 GPIO_ACTIVE_LOW>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		/* channel 0 routed to expansion connector (J22) */
+		i2c_exp: i2c at 0 {
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		/* channel 1 routed to mipi-csi connector (J23) */
+		i2c_csi: i2c at 1 {
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		/* channel 2 routed to mipi-dsi connector (J25) */
+		i2c_dsi: i2c at 2 {
+			reg = <2>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			tca6408_u48: gpio at 21 {
+				compatible = "ti,tca6408";
+				reg = <0x21>;
+				/*
+				 * reset shared between U37 and U48, to be
+				 * supported once gpio-pca953x switches to
+				 * reset framework.
+				 *
+				 * reset-gpios = <&tca6416_u21 4 (GPIO_ACTIVE_LOW|GPIO_PULL_UP|GPIO_OPEN_DRAIN)>;
+				 */
+				gpio-controller;
+				#gpio-cells = <2>;
+				gpio-line-names = "CAM_RST#", "DSI_RESET",
+						  "DSI_STBYB", "DSI_PWM_BL",
+						  "DSI_L/R", "DSI_U/D",
+						  "DSI_CTP_/RST", "CAM_TRIG";
+			};
+		};
+
+		/* channel 2 routed to lvds connector (J24) */
+		i2c_lvds: i2c at 3 {
+			reg = <3>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			tca6408_u37: gpio at 20 {
+				compatible = "ti,tca6408";
+				reg = <0x20>;
+				/*
+				 * reset shared between U37 and U48, to be
+				 * supported once gpio-pca953x switches to
+				 * reset framework.
+				 *
+				 * reset-gpios = <&tca6416_u21 4 (GPIO_ACTIVE_LOW|GPIO_PULL_UP|GPIO_OPEN_DRAIN)>;
+				 */
+				gpio-controller;
+				#gpio-cells = <2>;
+				gpio-line-names = "SELB", "LVDS_RESET",
+						  "LVDS_STBYB", "LVDS_PWM_BL",
+						  "LVDS_L/R", "LVDS_U/D",
+						  "LVDS_CTP_/RST", "";
+			};
+		};
+	};
+};
+
+&i2c3 {
+	/* highest i2c clock supported by all peripherals is 400kHz */
+	clock-frequency = <400000>;
+
+	tca6416_u20: gpio at 20 {
+		/*
+		 * This is a TI TCAL6416 using same programming model as
+		 * NXP PCAL6416, not to be confused with TI TCA6416.
+		 */
+		compatible = "nxp,pcal6416";
+		reg = <0x20>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		gpio-line-names = "TCA_INT/EXT_UART", "TCA_UARTA_232/485",
+				  "TCA_UARTB_232/485", "TCA_INT/EXT_CAN",
+				  "TCA_NXP/REN", "TCA_M.2B_3V3_EN",
+				  "TCA_M.2M_3V3_EN", "TCA_M.2M_RESET#",
+				  "TCA_M.2B_RESET#", "TCA_M.2B_W_DIS#",
+				  "TCA_M.2B_GPS_EN#", "TCA_USB-HUB_RST#",
+				  "TCA_USB_HUB3_PWR_EN", "TCA_USB_HUB4_PWR_EN",
+				  "TCA_USB1_PWR_EN", "TCA_VIDEO_PWR_EN";
+
+		m2-b-reset-hog {
+			gpio-hog;
+			gpios = <8 GPIO_ACTIVE_LOW>;
+			output-low;
+			line-name = "m2-b-reset";
+		};
+	};
+
+	tca6416_u21: gpio at 21 {
+		/*
+		 * This is a TI TCAL6416 using same programming model as
+		 * NXP PCAL6416, not to be confused with TI TCA6416.
+		 */
+		compatible = "nxp,pcal6416";
+		reg = <0x21>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&tca6416_u21_int_pins>;
+		interrupts-extended = <&gpio1 15 IRQ_TYPE_EDGE_FALLING>;
+		gpio-line-names = "TCA_SPI_TPM/EXT", "TCA_TPM_RST#",
+				  "TCA_I2C_RST", "TCA_RS232_SHTD#",
+				  "TCA_LCD_I2C_RST", "TCA_DIG_OUT1",
+				  "TCA_bDIG_IN1", "TCA_SENS_INT",
+				  "TCA_ALERT#", "TCA_TPM_PIRQ#",
+				  "TCA_RTC_INT", "TCA_M.2M_WAKW_ON_LAN",
+				  "TCA_M.2M_CLKREQ#", "TCA_LVDS_INT#",
+				  "", "TCA_POE_AT";
+
+		rs232_shutdown: rs232-shutdown-hog {
+			gpio-hog;
+			gpios = <3 GPIO_ACTIVE_LOW>;
+			output-low;
+			line-name = "rs232-shutdown";
+		};
+
+		lcd-i2c-reset-hog {
+			/*
+			 * reset shared between U37 and U48, to be
+			 * supported once gpio-pca953x switches to
+			 * reset framework.
+			 */
+			gpio-hog;
+			gpios = <4 (GPIO_ACTIVE_LOW|GPIO_PULL_UP|GPIO_OPEN_DRAIN)>;
+			output-low;
+			line-name = "lcd-i2c-reset";
+		};
+
+		m2-m-clkreq-hog {
+			gpio-hog;
+			gpios = <12 GPIO_ACTIVE_LOW>;
+			input;
+			line-name = "m2-m-clkreq";
+		};
+	};
+
+	led-controller at 30 {
+		compatible = "ti,lp5562";
+		reg = <0x30>;
+		/* use internal clock, could use external generated by rtc */
+		clock-mode = /bits/ 8 <1>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		multi-led at 0 {
+			reg = <0x0>;
+			label = "D7";
+			color = <LED_COLOR_ID_RGB>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			led at 0 {
+				reg = <0x0>;
+				color = <LED_COLOR_ID_RED>;
+				led-cur = /bits/ 8 <0x32>;
+				max-cur = /bits/ 8 <0x64>;
+			};
+
+			led at 1 {
+				reg = <0x1>;
+				color = <LED_COLOR_ID_GREEN>;
+				led-cur = /bits/ 8 <0x19>;
+				max-cur = /bits/ 8 <0x32>;
+			};
+
+			led at 2 {
+				reg = <0x2>;
+				color = <LED_COLOR_ID_BLUE>;
+				led-cur = /bits/ 8 <0x19>;
+				max-cur = /bits/ 8 <0x32>;
+			};
+		};
+
+		led at 3 {
+			reg = <3>;
+			chan-name = "D8";
+			label = "D8";
+			color = <LED_COLOR_ID_GREEN>;
+			led-cur = /bits/ 8 <0x19>;
+			max-cur = /bits/ 8 <0x64>;
+		};
+	};
+
+	light-sensor at 44 {
+		compatible = "isil,isl29023";
+		reg = <0x44>;
+		/* IRQ shared between accelerometer, light-sensor and Tamper input (J5007) */
+		interrupts-extended = <&tca6416_u21 7 IRQ_TYPE_EDGE_FALLING>;
+	};
+
+	accelerometer at 53 {
+		compatible = "adi,adxl345";
+		reg = <0x53>;
+		/* IRQ shared between accelerometer, light-sensor and Tamper input (J5007) */
+		interrupt-names = "INT1";
+		interrupts-extended = <&tca6416_u21 7 IRQ_TYPE_EDGE_FALLING>;
+	};
+
+	carrier_eeprom: eeprom at 57{
+		compatible = "atmel,24c02";
+		reg = <0x57>;
+		pagesize = <8>;
+	};
+
+	carrier_rtc: rtc at 69 {
+		compatible = "abracon,ab1805";
+		reg = <0x69>;
+		abracon,tc-diode = "schottky";
+		abracon,tc-resistor = <3>;
+		interrupts-extended = <&tca6416_u21 10 IRQ_TYPE_EDGE_FALLING>;
+	};
+};
+
+&iomuxc {
+	can1_pins: pinctrl-can1-grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SPDIF_RX__CAN1_RX			0x154
+			MX8MP_IOMUXC_SPDIF_TX__CAN1_TX			0x154
+		>;
+	};
+
+	can2_pins: pinctrl-can2-grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI5_MCLK__CAN2_RX			0x154
+			MX8MP_IOMUXC_SAI5_RXD3__CAN2_TX			0x154
+		>;
+	};
+
+	ecspi2_pins: pinctrl-ecspi2-grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_ECSPI2_SCLK__ECSPI2_SCLK		0x140
+			MX8MP_IOMUXC_ECSPI2_MOSI__ECSPI2_MOSI		0x140
+			MX8MP_IOMUXC_ECSPI2_MISO__ECSPI2_MISO		0x140
+			MX8MP_IOMUXC_ECSPI2_SS0__GPIO5_IO13		0x140
+		>;
+	};
+
+	tca6416_u21_int_pins: pinctrl-tca6416-u21-int-grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO15__GPIO1_IO15		0x0
+		>;
+	};
+
+	/* UARTA */
+	uart3_pins: pinctrl-uart3-grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_ECSPI1_SCLK__UART3_DCE_RX		0x140
+			MX8MP_IOMUXC_ECSPI1_MOSI__UART3_DCE_TX		0x140
+			MX8MP_IOMUXC_ECSPI1_SS0__GPIO5_IO09		0x140
+		>;
+	};
+
+	/* UARTB */
+	uart4_pins: pinctrl-uart4-grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_NAND_DATA00__UART4_DCE_RX		0x140
+			MX8MP_IOMUXC_NAND_DATA01__UART4_DCE_TX		0x140
+			MX8MP_IOMUXC_ECSPI1_MISO__GPIO5_IO08		0x140
+		>;
+	};
+
+	usdhc2_pins: pinctrl-usdhc2-grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK		0x190
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD		0x1d0
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0		0x1d0
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1		0x1d0
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2		0x1d0
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3		0x1d0
+			MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT		0x140
+			MX8MP_IOMUXC_SD2_CD_B__USDHC2_CD_B		0x140
+		>;
+	};
+
+	usdhc2_100mhz_pins: pinctrl-usdhc2-100mhz-grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK		0x194
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD		0x1d4
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0		0x1d4
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1		0x1d4
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2		0x1d4
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3		0x1d4
+			MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT		0x140
+			MX8MP_IOMUXC_SD2_CD_B__USDHC2_CD_B		0x140
+		>;
+	};
+
+	usdhc2_200mhz_pins: pinctrl-usdhc2-200mhz-grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK		0x196
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD		0x1d6
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0		0x1d6
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1		0x1d6
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2		0x1d6
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3		0x1d6
+			MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT		0x140
+			MX8MP_IOMUXC_SD2_CD_B__USDHC2_CD_B		0x140
+		>;
+	};
+
+	vmmc_pins: pinctrl-vmmc-grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19		0x0
+		>;
+	};
+};
+
+&pcie {
+	reset-gpio = <&tca6416_u20 7 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+/* M.2 M-Key (J4) */
+&pcie_phy {
+	clocks = <&hsio_blk_ctrl>;
+	clock-names = "ref";
+	fsl,clkreq-unsupported;
+	fsl,refclk-pad-mode = <IMX8_PCIE_REFCLK_PAD_OUTPUT>;
+	status = "okay";
+};
+
+&phy0 {
+	leds {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		/* ADIN1300 LED_0 pin */
+		led at 0 {
+			reg = <0>;
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_LAN;
+			default-state = "keep";
+		};
+	};
+};
+
+&phy1 {
+	leds {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		/* ADIN1300 LED_0 pin */
+		led at 0 {
+			reg = <0>;
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_LAN;
+			default-state = "keep";
+		};
+	};
+};
+
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart3_pins>;
+	rts-gpios = <&gpio5 9 GPIO_ACTIVE_HIGH>;
+	/* select 80MHz parent clock to support maximum baudrate 4Mbps */
+	assigned-clocks = <&clk IMX8MP_CLK_UART3>;
+	assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_80M>;
+	status = "okay";
+};
+
+&uart4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart4_pins>;
+	rts-gpios = <&gpio5 8 GPIO_ACTIVE_HIGH>;
+	/* select 80MHz parent clock to support maximum baudrate 4Mbps */
+	assigned-clocks = <&clk IMX8MP_CLK_UART4>;
+	assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_80M>;
+	status = "okay";
+};
+
+&usb3_phy0 {
+	fsl,phy-tx-preemp-amp-tune-microamp = <1200>;
+	vbus-supply = <&vbus1>;
+	status = "okay";
+};
+
+&usb3_0 {
+	status = "okay";
+};
+
+&usb3_phy1 {
+	status = "okay";
+};
+
+&usb3_1 {
+	status = "okay";
+};
+
+&usb_dwc3_0 {
+	dr_mode = "host";
+};
+
+&usb_dwc3_1 {
+	dr_mode = "host";
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	hub_2_0: hub at 1 {
+		compatible = "usb4b4,6502", "usb4b4,6506";
+		reg = <1>;
+		peer-hub = <&hub_3_0>;
+		reset-gpios = <&tca6416_u20 11 GPIO_ACTIVE_LOW>;
+		vdd-supply = <&v_1_2>;
+		vdd2-supply = <&v_3_3>;
+	};
+
+	hub_3_0: hub at 2 {
+		compatible = "usb4b4,6500", "usb4b4,6504";
+		reg = <2>;
+		peer-hub = <&hub_2_0>;
+		reset-gpios = <&tca6416_u20 11 GPIO_ACTIVE_LOW>;
+		vdd-supply = <&v_1_2>;
+		vdd2-supply = <&v_3_3>;
+	};
+};
+
+&usdhc2 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&usdhc2_pins>;
+	pinctrl-1 = <&usdhc2_100mhz_pins>;
+	pinctrl-2 = <&usdhc2_200mhz_pins>;
+	vmmc-supply = <&vmmc>;
+	bus-width = <4>;
+	cap-power-off-card;
+	full-pwr-cycle;
+	status = "okay";
+};

-- 
2.51.0




From josua at solid-run.com  Mon Dec  1 05:07:22 2025
From: josua at solid-run.com (Josua Mayer)
Date: Mon, 01 Dec 2025 14:07:22 +0100
Subject: [PATCH v4 3/8] arm64: dts: imx8mp-hummingboard-pulse/cubox-m: fix
 vmmc gpio polarity
In-Reply-To: <20251201-imx8mp-hb-iiot-v4-0-53a4cd6c21bf@solid-run.com>
References: <20251201-imx8mp-hb-iiot-v4-0-53a4cd6c21bf@solid-run.com>
Message-ID: <20251201-imx8mp-hb-iiot-v4-3-53a4cd6c21bf@solid-run.com>

Fix the polarity in vmmc regulator node for the gpio from active-high to
active-low. This is a cosmetic change as regulator default to active-low
unless property enable-active-high was also specified - ignoring the
flag on gpio handle.

Fixes: a009c0c66ecb ("arm64: dts: add description for solidrun imx8mp som and cubox-m")
Fixes: 2a222aa2bee9 ("arm64: dts: add description for solidrun imx8mp hummingboard variants")
Signed-off-by: Josua Mayer <josua at solid-run.com>
---
 arch/arm64/boot/dts/freescale/imx8mp-cubox-m.dts                    | 2 +-
 arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-common.dtsi | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-cubox-m.dts b/arch/arm64/boot/dts/freescale/imx8mp-cubox-m.dts
index 8290f187b79fd..7bc213499f094 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-cubox-m.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-cubox-m.dts
@@ -68,7 +68,7 @@ vmmc: regulator-mmc {
 		regulator-name = "vmmc";
 		regulator-min-microvolt = <3300000>;
 		regulator-max-microvolt = <3300000>;
-		gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+		gpio = <&gpio2 19 GPIO_ACTIVE_LOW>;
 		startup-delay-us = <250>;
 	};
 };
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-common.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-common.dtsi
index 825ad6a2ba14e..5b8c8489713c4 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-common.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-common.dtsi
@@ -73,7 +73,7 @@ vmmc: regulator-mmc {
 		regulator-name = "vmmc";
 		regulator-min-microvolt = <3300000>;
 		regulator-max-microvolt = <3300000>;
-		gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+		gpio = <&gpio2 19 GPIO_ACTIVE_LOW>;
 		startup-delay-us = <250>;
 	};
 

-- 
2.51.0




From josua at solid-run.com  Mon Dec  1 05:07:24 2025
From: josua at solid-run.com (Josua Mayer)
Date: Mon, 01 Dec 2025 14:07:24 +0100
Subject: [PATCH v4 5/8] arm64: dts: imx8mp-sr-som: build dtbs with symbols
 for overlay support
In-Reply-To: <20251201-imx8mp-hb-iiot-v4-0-53a4cd6c21bf@solid-run.com>
References: <20251201-imx8mp-hb-iiot-v4-0-53a4cd6c21bf@solid-run.com>
Message-ID: <20251201-imx8mp-hb-iiot-v4-5-53a4cd6c21bf@solid-run.com>

Build all dtbs based on SolidRun i.MX8MP SoM with symbols (adding -@ to
dtc flags) to enable support for device-tree addons.

The SoM has a camera connector for basler cameras that can be enabled by
downstream dtbo.
Hence by extension all boards based on this SoM should support addons.

Signed-off-by: Josua Mayer <josua at solid-run.com>
---
 arch/arm64/boot/dts/freescale/Makefile | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index 525ef180481d3..8bda6fb0ff9c1 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -197,6 +197,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mp-aristainetos3-helios-lvds.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-aristainetos3-proton2s.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-beacon-kit.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-cubox-m.dtb
+DTC_FLAGS_imx8mp-cubox-m := -@
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-data-modul-edm-sbc.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-debix-model-a.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-debix-som-a-bmb-08.dtb
@@ -207,9 +208,13 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mp-dhcom-picoitx.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-edm-g-wb.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-mate.dtb
+DTC_FLAGS_imx8mp-hummingboard-mate := -@
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-pro.dtb
+DTC_FLAGS_imx8mp-hummingboard-pro := -@
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-pulse.dtb
+DTC_FLAGS_imx8mp-hummingboard-pulse := -@
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-ripple.dtb
+DTC_FLAGS_imx8mp-hummingboard-ripple := -@
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-icore-mx8mp-edimm2.2.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-iota2-lumpy.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-kontron-bl-osm-s.dtb

-- 
2.51.0




From josua at solid-run.com  Mon Dec  1 05:07:26 2025
From: josua at solid-run.com (Josua Mayer)
Date: Mon, 01 Dec 2025 14:07:26 +0100
Subject: [PATCH v4 7/8] arm64: dts: add description for solidrun
 solidsense-n8 board
In-Reply-To: <20251201-imx8mp-hb-iiot-v4-0-53a4cd6c21bf@solid-run.com>
References: <20251201-imx8mp-hb-iiot-v4-0-53a4cd6c21bf@solid-run.com>
Message-ID: <20251201-imx8mp-hb-iiot-v4-7-53a4cd6c21bf@solid-run.com>

Add description for the SolidRun SolidSense N8 Compact.
The board is designed around the i.MX8MN SoC and comes as a complete
product including enclosure and labels.

Features:
- USB-2.0 Type A connector
- 1Gbps RJ45 Ethernet with PoE
- microSD connector
- eMMC
- Cellular Modem + SIM holder
- WiFi + Bluetooth
- RS485
- CAN
- 802.15.1 radio
- supercapacitor backup power supply

This is a headless design without display.
The board includes an internal expansion connector for daughterboards
which may be described by dt addon.

The supercap is not currently described due to lack of suitable bindings.
Vendor BSP uses gpio-keys driver to trigger shutdown on power loss.

Signed-off-by: Josua Mayer <josua at solid-run.com>
---
 arch/arm64/boot/dts/freescale/Makefile             |   2 +
 .../dts/freescale/imx8mn-solidsense-n8-compact.dts | 853 +++++++++++++++++++++
 2 files changed, 855 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index d414d0efe5e74..c56137097da3b 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -181,6 +181,8 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mn-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-ddr3l-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-ddr4-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-rve-gateway.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mn-solidsense-n8-compact.dtb
+DTC_FLAGS_imx8mn-solidsense-n8-compact += -@
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-tqma8mqnl-mba8mx.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-var-som-symphony.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-venice-gw7902.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-solidsense-n8-compact.dts b/arch/arm64/boot/dts/freescale/imx8mn-solidsense-n8-compact.dts
new file mode 100644
index 0000000000000..93396e22ba409
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mn-solidsense-n8-compact.dts
@@ -0,0 +1,853 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Device Tree file for SolidSense N8 Compact
+ *
+ * Copyright 2024 Josua Mayer <josua at solid-run.com>
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/leds/common.h>
+
+#include "imx8mn.dtsi"
+
+/ {
+	model = "SolidRun SolidSense N8 Compact";
+	compatible = "solidrun,solidsense-n8-compact", "fsl,imx8mn";
+
+	aliases {
+		gpio5 = &expander;
+		rtc0 = &rtc;
+		rtc1 = &snvs_rtc;
+		usb0 = &usbotg1;
+		watchdog0 = &wdog1;
+		watchdog1 = &rtc;
+	};
+
+	chosen {
+		stdout-path = &uart2;
+	};
+
+	/* LED labels based on enclosure, schematic names differ. */
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&led_pins>;
+
+		/* D20 */
+		led1 {
+			label = "led1";
+			gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>;
+			default-state = "off";
+		};
+
+		/* D18 */
+		led2 {
+			label = "led2";
+			gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>;
+			default-state = "off";
+		};
+
+		/* D19 */
+		led3 {
+			label = "led3";
+			gpios = <&gpio1 12 GPIO_ACTIVE_HIGH>;
+			default-state = "off";
+		};
+	};
+
+	memory at 40000000 {
+		reg = <0x0 0x40000000 0 0x80000000>;
+		device_type = "memory";
+	};
+
+	reg_modem_vbat: regulator-modem-vbat {
+		compatible = "regulator-fixed";
+		regulator-name = "modem-vbat";
+		pinctrl-names = "default";
+		pinctrl-0 = <&regulator_modem_vbat_pins>;
+		regulator-min-microvolt = <3800000>;
+		regulator-max-microvolt = <3800000>;
+		gpio = <&gpio3 25 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-always-on;
+	};
+
+	/* power to lte modems behind hub ports 2/3 */
+	reg_modem_vbus: regulator-modem-vbus {
+		compatible = "regulator-fixed";
+		regulator-name = "modem-vbus";
+		pinctrl-names = "default";
+		pinctrl-0 = <&regulator_modem_vbus_pins>;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&gpio5 4 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-always-on;
+	};
+
+	/* power to usb hub, and type-a behind hub port 1 */
+	reg_usb1_vbus: regulator-usb1-vbus {
+		compatible = "regulator-fixed";
+		regulator-name = "usb1-vbus";
+		pinctrl-names = "default";
+		pinctrl-0 = <&regulator_usb1_vbus_pins>;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&gpio5 5 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_vdd_1v8: regulator-vdd-1v8 {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd-1v8";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	reg_vdd_3v3: regulator-vdd-3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd-3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	reg_usdhc2_vmmc: regulator-usdhc2-vmmc {
+		compatible = "regulator-fixed";
+		regulator-name = "usdhc2-vmmc";
+		pinctrl-names = "default";
+		pinctrl-0 = <&regulator_usdhc2_vmmc_pins>;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		vin-supply = <&reg_vdd_3v3>;
+		gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		off-on-delay-us = <250>;
+	};
+
+	rfkill {
+		compatible = "rfkill-gpio";
+		label = "rfkill-wwan";
+		radio-type = "wwan";
+		pinctrl-names = "default";
+		pinctrl-0 = <&modem_pins>;
+		/* rfkill-gpio inverts internally */
+		shutdown-gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
+	};
+
+	usdhc1_pwrseq: usdhc1-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&A53_0 {
+	cpu-supply = <&buck2_reg>;
+};
+
+&A53_1 {
+	cpu-supply = <&buck2_reg>;
+};
+
+&A53_2 {
+	cpu-supply = <&buck2_reg>;
+};
+
+&A53_3 {
+	cpu-supply = <&buck2_reg>;
+};
+
+&ddrc {
+	operating-points-v2 = <&ddrc_opp_table>;
+
+	ddrc_opp_table: opp-table {
+		compatible = "operating-points-v2";
+
+		opp-266500000 {
+			opp-hz = /bits/ 64 <266500000>;
+		};
+
+		opp-600000000 {
+			opp-hz = /bits/ 64 <600000000>;
+		};
+	};
+};
+
+&ecspi2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&ecspi2_pins>;
+	/* native chip-select causes reading 0xffffffff */
+	cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
+	num-cs = <1>;
+	status = "okay";
+
+	can at 0 {
+		compatible = "microchip,mcp2518fd";
+		reg = <0>;
+		spi-max-frequency = <20000000>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&can_pins>;
+		interrupt-parent = <&gpio5>;
+		interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
+		clocks = <&clk IMX8MN_CLK_CLKOUT1>;
+		/* generate 8MHz clock from soc-internal 24mhz reference */
+		assigned-clocks = <&clk IMX8MN_CLK_CLKOUT1_SEL>,
+			  <&clk IMX8MN_CLK_CLKOUT1_DIV>;
+		assigned-clock-rates = <0>, <8000000>;
+		assigned-clock-parents = <&clk IMX8MN_CLK_24M>, <0>;
+	};
+};
+
+&fec1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&fec1_pins>;
+	phy-mode = "rgmii-id";
+	phy-handle = <&phy4>;
+	local-mac-address = [00 00 00 00 00 00];
+	fsl,magic-packet;
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		/*
+		 * Depending on board revision two different phys are used:
+		 * - v1.1: atheros phy at address 4
+		 * - v1.2+: analog devices phy at address 0
+		 * Configure first version by default.
+		 * On v1.2 and later, U-Boot will enable the correct phy
+		 * based on runtime detection and patch dtb accordingly.
+		 */
+
+		/* ADIN1300 */
+		phy0: ethernet-phy at 0 {
+			reg = <0>;
+			reset-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>;
+			reset-assert-us = <10>;
+			reset-deassert-us = <5000>;
+			interrupt-parent = <&gpio1>;
+			interrupts = <10 IRQ_TYPE_LEVEL_LOW>;
+			adi,link-st-polarity = <GPIO_ACTIVE_LOW>;
+			adi,led-polarity = <GPIO_ACTIVE_LOW>;
+			status = "disabled";
+
+			leds {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				led at 0 {
+					reg = <0>;
+					color = <LED_COLOR_ID_YELLOW>;
+					function = LED_FUNCTION_LAN;
+					default-state = "keep";
+					active-low;
+				};
+			};
+		};
+
+		/* AR8035 */
+		phy4: ethernet-phy at 4 {
+			reg = <4>;
+			reset-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>;
+			reset-assert-us = <10000>;
+			status = "okay";
+		};
+	};
+};
+
+&gpio5 {
+	usb-hub-reset-hog {
+		gpio-hog;
+		gpios = <3 GPIO_ACTIVE_LOW>;
+		output-low; /* deasserted */
+		line-name = "usb-hub-reset";
+	};
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	status = "okay";
+
+	pmic at 4b {
+		compatible = "rohm,bd71847";
+		reg = <0x4b>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pmic_pins>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+		rohm,reset-snvs-powered;
+
+		#clock-cells = <0>;
+		clocks = <&osc_32k>;
+		clock-output-names = "clk-32k-out";
+
+		regulators {
+			BUCK1 {
+				// supplies soc vdd, soc mipi vdd @ 0.9V
+				regulator-name = "buck1";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <1250>;
+				rohm,dvs-run-voltage = <850000>;
+				rohm,dvs-suspend-voltage = <750000>;
+			};
+
+			buck2_reg: BUCK2 {
+				regulator-name = "buck2";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <1250>;
+				rohm,dvs-run-voltage = <1000000>;
+				rohm,dvs-idle-voltage = <900000>;
+				rohm,dvs-suspend-voltage = <0>;
+			};
+
+			BUCK3 {
+				// BUCK5 in datasheet
+				// output floating
+				regulator-name = "buck3";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1350000>;
+			};
+
+			BUCK4 {
+				// BUCK6 in datasheet
+				// supplies ldo3, ldo5, muxsw
+				regulator-name = "buck4";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			BUCK5 {
+				// BUCK7 in datasheet
+				// supplies ldo4, ldo6, muxsw
+				// enables dram vpp @ 2.5V
+				regulator-name = "buck5";
+				regulator-min-microvolt = <1605000>;
+				regulator-max-microvolt = <1995000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			BUCK6 {
+				// BUCK8 in datasheet
+				// supplies dram @ 1.2V
+				regulator-name = "buck6";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1400000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			LDO1 {
+				// supplies soc snvs @ 1.8V
+				regulator-name = "ldo1";
+				regulator-min-microvolt = <1600000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			LDO2 {
+				// supplies soc snvs @ 0.8V
+				regulator-name = "ldo2";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <900000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			LDO3 {
+				// supplies soc vdd @ 1.8V
+				regulator-name = "ldo3";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			LDO4 {
+				// output floating
+				regulator-name = "ldo4";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1800000>;
+			};
+
+			LDO5 {
+				// output floating
+				regulator-name = "ldo5";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <3300000>;
+			};
+
+			LDO6 {
+				// supplies soc vdd mipi @ 1.2V
+				regulator-name = "ldo6";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+		};
+	};
+};
+
+&i2c2 {
+	/*
+	 * routed to various connectors:
+	 * - basler camera (CON2)
+	 * - touchscreen (J3)
+	 * - expansion connector (J14)
+	 */
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_pins>;
+	status = "okay";
+};
+
+&i2c3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c3_pins>;
+	status = "okay";
+
+	expander: gpio at 20 {
+		compatible = "ti,tca6408";
+		reg = <0x20>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&gpio_expander_pins>;
+		reset-gpios = <&gpio3 16 GPIO_ACTIVE_LOW>;
+		interrupt-parent = <&gpio2>;
+		interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		gpio-line-names = "SYSGD", "PFO#", "CAPGD", "CAPFLT#",
+				  "CHGEN#", "BSTEN#", "", "";
+	};
+
+	light-sensor at 44 {
+		compatible = "isil,isl29023";
+		reg = <0x44>;
+	};
+
+	accelerometer at 53 {
+		compatible = "adi,adxl345";
+		reg = <0x53>;
+	};
+
+	/* battery-charger at 68 */
+
+	rtc: rtc at 69 {
+		compatible = "abracon,abx80x";
+		reg = <0x69>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&rtc_pins>;
+		abracon,tc-diode = "schottky";
+		abracon,tc-resistor = <3>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
+	};
+};
+
+&i2c4 {
+	/* routed to expansion connector (J14) */
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c4_pins>;
+	status = "okay";
+};
+
+&iomuxc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&tamper_pins>, <&usb_hub_pins>;
+
+	ieee802151_radio_pins: pinctrl-ieee802151-radio-grp {
+		fsl,pins = <
+			/* RESETN */
+			MX8MN_IOMUXC_GPIO1_IO05_GPIO1_IO5	0x0
+			/* VDD_EN */
+			MX8MN_IOMUXC_GPIO1_IO06_GPIO1_IO6	0x0
+			/* SWDCLK */
+			MX8MN_IOMUXC_GPIO1_IO14_GPIO1_IO14	0x0
+			/* SDIO */
+			MX8MN_IOMUXC_GPIO1_IO15_GPIO1_IO15	0x0
+		>;
+	};
+
+	can_pins: pinctrl-can-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SAI3_TXD_GPIO5_IO1		0x140
+		>;
+	};
+
+	ecspi2_pins: pinctrl-ecspi2-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_ECSPI2_SCLK_ECSPI2_SCLK	0x96
+			MX8MN_IOMUXC_ECSPI2_MOSI_ECSPI2_MOSI	0x1d6
+			MX8MN_IOMUXC_ECSPI2_MISO_ECSPI2_MISO	0x1d6
+			MX8MN_IOMUXC_ECSPI2_SS0_GPIO5_IO13	0x1d6
+		>;
+	};
+
+	fec1_pins: pinctrl-fec1-grp {
+		/*
+		 * Some pins are sampled at phy reset to apply configuration:
+		 * - AR803x PHY (revision 1.1)
+		 *   - RXD[1:0]: phy address bits [1:0]
+		 *   - RXD[3:2],RX_CTL: mac interface select bits 3,1,0
+		 * - ADIN1300 PHY (revision 1.2 or later)
+		 *   - RXD[3:0]: phy address bits [3:0]
+		 *   - RX_CTL,RXC: mac interface select bits 1,0
+		 * SoC enables pull-down at reset, PHYs have internal
+		 * pull-down, so pinmux may unset pull-enable.
+		 */
+		fsl,pins = <
+			MX8MN_IOMUXC_ENET_MDC_ENET1_MDC			0x2
+			MX8MN_IOMUXC_ENET_MDIO_ENET1_MDIO		0x2
+			MX8MN_IOMUXC_ENET_TD3_ENET1_RGMII_TD3		0x1e
+			MX8MN_IOMUXC_ENET_TD2_ENET1_RGMII_TD2		0x1e
+			MX8MN_IOMUXC_ENET_TD1_ENET1_RGMII_TD1		0x1e
+			MX8MN_IOMUXC_ENET_TD0_ENET1_RGMII_TD0		0x1e
+			/* RD[3:0] sampled at phy reset for address bits [3:0] */
+			MX8MN_IOMUXC_ENET_RD3_ENET1_RGMII_RD3		0x90
+			MX8MN_IOMUXC_ENET_RD2_ENET1_RGMII_RD2		0x90
+			MX8MN_IOMUXC_ENET_RD1_ENET1_RGMII_RD1		0x90
+			MX8MN_IOMUXC_ENET_RD0_ENET1_RGMII_RD0		0x90
+			MX8MN_IOMUXC_ENET_TXC_ENET1_RGMII_TXC		0x10
+			MX8MN_IOMUXC_ENET_RXC_ENET1_RGMII_RXC		0x90
+			MX8MN_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x90
+			MX8MN_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x10
+			/* phy reset */
+			MX8MN_IOMUXC_SAI5_RXFS_GPIO3_IO19		0x0
+			/* phy interrupt */
+			MX8MN_IOMUXC_GPIO1_IO10_GPIO1_IO10		0x140
+		>;
+	};
+
+	gpio_expander_pins: pinctrl-gpio-expander-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_NAND_READY_B_GPIO3_IO16	0x140
+			MX8MN_IOMUXC_SD1_STROBE_GPIO2_IO11	0x140
+		>;
+	};
+
+	i2c1_pins: pinctrl-i2c1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C1_SCL_I2C1_SCL		0x400001c2
+			MX8MN_IOMUXC_I2C1_SDA_I2C1_SDA		0x400001c2
+		>;
+	};
+
+	i2c2_pins: pinctrl-i2c2-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C2_SCL_I2C2_SCL		0x400001c2
+			MX8MN_IOMUXC_I2C2_SDA_I2C2_SDA		0x400001c2
+		>;
+	};
+
+	i2c3_pins: pinctrl-i2c3-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C3_SCL_I2C3_SCL		0x400001c2
+			MX8MN_IOMUXC_I2C3_SDA_I2C3_SDA		0x400001c2
+		>;
+	};
+
+	i2c4_pins: pinctrl-i2c4-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C4_SCL_I2C4_SCL		0x400001c2
+			MX8MN_IOMUXC_I2C4_SDA_I2C4_SDA		0x400001c2
+		>;
+	};
+
+	led_pins: pinctrl-led-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_GPIO1_IO11_GPIO1_IO11	0x100
+			MX8MN_IOMUXC_GPIO1_IO12_GPIO1_IO12	0x100
+			MX8MN_IOMUXC_GPIO1_IO13_GPIO1_IO13	0x100
+		>;
+	};
+
+	modem_pins: pinctrl-modem-grp {
+		fsl,pins = <
+			/* RESET_N: modem-internal pull-down */
+			MX8MN_IOMUXC_GPIO1_IO07_GPIO1_IO7	0x0
+			/* PWRKEY: pull-down ensures always-on */
+			MX8MN_IOMUXC_GPIO1_IO08_GPIO1_IO8	0x100
+		>;
+	};
+
+	pmic_pins: pinctrl-pmic-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_GPIO1_IO03_GPIO1_IO3	0x140
+		>;
+	};
+
+	regulator_modem_vbat_pins: pinctrl-regulator-modem-vbat-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SAI5_MCLK_GPIO3_IO25	0x0
+		>;
+	};
+
+	regulator_modem_vbus_pins: pinctrl-regulator-modem-vbus-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SPDIF_RX_GPIO5_IO4		0x0
+		>;
+	};
+
+	regulator_usb1_vbus_pins: pinctrl-regulator-usb1-vbus-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SPDIF_EXT_CLK_GPIO5_IO5	0x0
+		>;
+	};
+
+	regulator_usdhc2_vmmc_pins: pinctrl-regulator-usdhc2-vmmc-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD2_RESET_B_GPIO2_IO19	0x0
+		>;
+	};
+
+	rtc_pins: pinctrl-rtc-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_GPIO1_IO01_GPIO1_IO1	0x140
+			MX8MN_IOMUXC_SAI3_RXFS_GPIO4_IO28	0x100
+		>;
+	};
+
+	tamper_pins: pinctrl-tamper-grp {
+		/*
+		 * Routed to physical tamper input (J12),
+		 * accelerometer and light-sensor interrupts.
+		 */
+		fsl,pins = <
+			MX8MN_IOMUXC_GPIO1_IO09_GPIO1_IO9	0x140
+		>;
+	};
+
+	uart1_pins: pinctrl-uart1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_UART1_RXD_UART1_DCE_RX	0x140
+			MX8MN_IOMUXC_UART1_TXD_UART1_DCE_TX	0x140
+			MX8MN_IOMUXC_UART3_RXD_UART1_DCE_CTS_B	0x140
+			MX8MN_IOMUXC_UART3_TXD_UART1_DCE_RTS_B	0x140
+			/* BT_REG_ON */
+			MX8MN_IOMUXC_SD1_DATA4_GPIO2_IO6	0x0
+			/* BT_WAKE_DEV */
+			MX8MN_IOMUXC_SD1_DATA5_GPIO2_IO7	0x0
+			/* BT_WAKE_HOST */
+			MX8MN_IOMUXC_SD1_DATA6_GPIO2_IO8	0x100
+		>;
+	};
+
+	uart2_pins: pinctrl-uart2-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_UART2_RXD_UART2_DCE_RX	0x140
+			MX8MN_IOMUXC_UART2_TXD_UART2_DCE_TX	0x140
+		>;
+	};
+
+	uart3_pins: pinctrl-uart3-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_ECSPI1_MOSI_UART3_DTE_RX	0x140
+			MX8MN_IOMUXC_ECSPI1_SCLK_UART3_DTE_TX	0x140
+			MX8MN_IOMUXC_ECSPI1_MISO_UART3_DTE_RTS_B	0x140
+			MX8MN_IOMUXC_ECSPI1_SS0_UART3_DTE_CTS_B	0x140
+		>;
+	};
+
+	uart4_pins: pinctrl-uart4-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_UART4_RXD_UART4_DCE_RX	0x140
+			MX8MN_IOMUXC_UART4_TXD_UART4_DCE_TX	0x140
+		>;
+	};
+
+	usb_hub_pins: pinctrl-usb-hub-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SPDIF_TX_GPIO5_IO3		0x0
+		>;
+	};
+
+	usdhc1_pins: pinctrl-usdhc1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD1_CLK_USDHC1_CLK		0x190
+			MX8MN_IOMUXC_SD1_CMD_USDHC1_CMD		0x1d0
+			MX8MN_IOMUXC_SD1_DATA0_USDHC1_DATA0	0x1d0
+			MX8MN_IOMUXC_SD1_DATA1_USDHC1_DATA1	0x1d0
+			MX8MN_IOMUXC_SD1_DATA2_USDHC1_DATA2	0x1d0
+			MX8MN_IOMUXC_SD1_DATA3_USDHC1_DATA3	0x1d0
+			/* wifi refclk */
+			MX8MN_IOMUXC_GPIO1_IO00_ANAMIX_REF_CLK_32K	0x0
+			/* WL_WAKE_HOST */
+			MX8MN_IOMUXC_SD1_DATA7_GPIO2_IO9	0x100
+			/* WL_REG_ON */
+			MX8MN_IOMUXC_SD1_RESET_B_GPIO2_IO10	0x0
+		>;
+	};
+
+	usdhc2_pins: pinctrl-usdhc2-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD2_CLK_USDHC2_CLK		0x190
+			MX8MN_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d0
+			MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d0
+			MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d0
+			MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d0
+			MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d0
+			MX8MN_IOMUXC_SD2_CD_B_USDHC2_CD_B	0x0
+			/* usdhc2 signalling voltage pmic control */
+			MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x140
+		>;
+	};
+
+	usdhc2_100mhz_pins: pinctrl-usdhc2-100mhz-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD2_CLK_USDHC2_CLK		0x194
+			MX8MN_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d4
+			MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d4
+			MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d4
+			MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d4
+			MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d4
+			MX8MN_IOMUXC_SD2_CD_B_USDHC2_CD_B	0x0
+			/* usdhc2 signalling voltage pmic control */
+			MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x140
+		>;
+	};
+
+	usdhc2_200mhz_pins: pinctrl-usdhc2-100mhz-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD2_CLK_USDHC2_CLK		0x196
+			MX8MN_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d6
+			MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d6
+			MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d6
+			MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d6
+			MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d6
+			MX8MN_IOMUXC_SD2_CD_B_USDHC2_CD_B	0x0
+			/* usdhc2 signalling voltage pmic control */
+			MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x140
+		>;
+	};
+
+	usdhc3_pins: pinctrl-usdhc3-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK	0x190
+			MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD	0x1d0
+			MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0	0x1d0
+			MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1	0x1d0
+			MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2	0x1d0
+			MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3	0x1d0
+			MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4	0x1d0
+			MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5	0x1d0
+			MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6	0x1d0
+			MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7	0x1d0
+			MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE	0x190
+		>;
+	};
+
+	wdog1_pins: pinctrl-wdog1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B	0x140
+		>;
+	};
+};
+
+/* Bluetooth */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	uart-has-rtscts;
+	/* select 80MHz parent clock to support maximum baudrate 4Mbps */
+	assigned-clocks = <&clk IMX8MN_CLK_UART1>;
+	assigned-clock-parents = <&clk IMX8MN_SYS_PLL1_80M>;
+	status = "okay";
+
+	bluetooth {
+		compatible = "brcm,bcm4330-bt";
+		device-wakeup-gpios = <&gpio2 7 GPIO_ACTIVE_HIGH>;
+		host-wakeup-gpios = <&gpio2 8 GPIO_ACTIVE_HIGH>;
+		shutdown-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>;
+		max-speed = <3000000>;
+	};
+};
+
+/* console */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "okay";
+};
+
+/* RS485 */
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart3_pins>;
+	uart-has-rtscts;
+	linux,rs485-enabled-at-boot-time;
+	fsl,dte-mode;
+	status = "okay";
+};
+
+/* 802.15.1 radio */
+&uart4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart4_pins &ieee802151_radio_pins>;
+	status = "okay";
+};
+
+&usbotg1 {
+	vbus-supply = <&reg_usb1_vbus>;
+	dr_mode = "host";
+	disable-over-current;
+	status  = "okay";
+};
+
+/* WiFi */
+&usdhc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&usdhc1_pins>;
+	vmmc-supply = <&reg_vdd_3v3>;
+	vqmmc-supply = <&reg_vdd_1v8>;
+	bus-width = <4>;
+	mmc-pwrseq = <&usdhc1_pwrseq>;
+	status = "okay";
+};
+
+/* microSD */
+&usdhc2 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&usdhc2_pins>;
+	pinctrl-1 = <&usdhc2_100mhz_pins>;
+	pinctrl-2 = <&usdhc2_200mhz_pins>;
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	bus-width = <4>;
+	broken-cd;
+	status = "okay";
+};
+
+/* eMMC */
+&usdhc3 {
+	/*
+	 * Use lowest drive strength for all high-speed modes to minimise
+	 * electro-magnetic emissions.
+	 * In this particular design HS-400 still works okay, no extra
+	 * pinctrl for 100mhz and 200mhz are required.
+	 */
+	pinctrl-names = "default";
+	pinctrl-0 = <&usdhc3_pins>;
+	vmmc-supply = <&reg_vdd_3v3>;
+	vqmmc-supply = <&reg_vdd_1v8>;
+	bus-width = <8>;
+	non-removable;
+	status = "okay";
+};
+
+&wdog1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&wdog1_pins>;
+	status = "okay";
+};

-- 
2.51.0




From josua at solid-run.com  Mon Dec  1 05:07:27 2025
From: josua at solid-run.com (Josua Mayer)
Date: Mon, 01 Dec 2025 14:07:27 +0100
Subject: [PATCH v4 8/8] arm64: dts: add description for solidrun i.mx8mm
 som and evb
In-Reply-To: <20251201-imx8mp-hb-iiot-v4-0-53a4cd6c21bf@solid-run.com>
References: <20251201-imx8mp-hb-iiot-v4-0-53a4cd6c21bf@solid-run.com>
Message-ID: <20251201-imx8mp-hb-iiot-v4-8-53a4cd6c21bf@solid-run.com>

Add description for the SolidRun i.MX8M Mini SoM on HummingBoard Ripple.

The SoM features:
- 1Gbps Ethernet with PHY
- eMMC
- 1/2GB DDR
- NPU (assembly option)
- WiFi + Bluetooth

The HummingBoard Ripple features:
- 2x USB-2.0 Type-A connector
- 1Gbps RJ45 Ethernet with PoE
- microSD connector
- microHDMI connector
- mpcie connector with USB-2.0 interface + SIM card holder
- microUSB connector for console (using fdtdi chip)
- RTC with backup battery

Signed-off-by: Josua Mayer <josua at solid-run.com>
---
 arch/arm64/boot/dts/freescale/Makefile             |   2 +
 .../dts/freescale/imx8mm-hummingboard-ripple.dts   | 335 +++++++++++++++++
 arch/arm64/boot/dts/freescale/imx8mm-sr-som.dtsi   | 395 +++++++++++++++++++++
 3 files changed, 732 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index c56137097da3b..3fbc8a1a1bf6e 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -124,6 +124,8 @@ imx8mm-evk-pcie-ep-dtbs += imx8mm-evk.dtb imx-pcie0-ep.dtbo
 imx8mm-evkb-pcie-ep-dtbs += imx8mm-evkb.dtb imx-pcie0-ep.dtbo
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-evk-pcie-ep.dtb imx8mm-evkb-pcie-ep.dtb
 
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-hummingboard-ripple.dtb
+DTC_FLAGS_imx8mm-hummingboard-ripple += -@
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-icore-mx8mm-ctouch2.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-icore-mx8mm-edimm2.2.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-iot-gateway.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-hummingboard-ripple.dts b/arch/arm64/boot/dts/freescale/imx8mm-hummingboard-ripple.dts
new file mode 100644
index 0000000000000..110e7ff1ff135
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mm-hummingboard-ripple.dts
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2025 Josua Mayer <josua at solid-run.com>
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/leds/common.h>
+
+#include "imx8mm-sr-som.dtsi"
+
+/ {
+	model = "SolidRun i.MX8MM HummingBoard Ripple";
+	compatible = "solidrun,imx8mm-hummingboard-ripple",
+		     "solidrun,imx8mm-sr-som", "fsl,imx8mm";
+
+	aliases {
+		rtc0 = &carrier_rtc;
+		rtc1 = &snvs_rtc;
+	};
+
+	hdmi-connector {
+		compatible = "hdmi-connector";
+		label = "hdmi";
+		type = "c";
+
+		port {
+			hdmi_connector_in: endpoint {
+				remote-endpoint = <&adv7535_out>;
+			};
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&led_pins>;
+
+		led-0 {
+			label = "D30";
+			color = <LED_COLOR_ID_GREEN>;
+			gpios = <&gpio5 29 GPIO_ACTIVE_LOW>;
+			default-state = "on";
+		};
+
+		led-1 {
+			label = "D31";
+			color = <LED_COLOR_ID_GREEN>;
+			gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
+			default-state = "on";
+		};
+
+		led-2 {
+			label = "D32";
+			color = <LED_COLOR_ID_GREEN>;
+			gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
+			default-state = "on";
+		};
+
+		led-3 {
+			label = "D33";
+			color = <LED_COLOR_ID_GREEN>;
+			gpios = <&gpio5 7 GPIO_ACTIVE_LOW>;
+			default-state = "on";
+		};
+
+		led-4 {
+			label = "D34";
+			color = <LED_COLOR_ID_GREEN>;
+			gpios = <&gpio5 6 GPIO_ACTIVE_LOW>;
+			default-state = "on";
+		};
+	};
+
+	rfkill-mpcie-wifi {
+		compatible = "rfkill-gpio";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pcie_rfkill_pins>;
+		label = "mpcie WiFi";
+		radio-type = "wlan";
+		/* rfkill-gpio inverts internally */
+		shutdown-gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>;
+	};
+
+	vmmc: regulator-mmc {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&vmmc_pins>;
+		regulator-name = "vmmc";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio2 19 GPIO_ACTIVE_LOW>;
+		startup-delay-us = <250>;
+	};
+
+	vbus1: regulator-vbus-1 {
+		compatible = "regulator-fixed";
+		regulator-name = "vbus1";
+		gpio = <&gpio2 11 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		pinctrl-names = "default";
+		pinctrl-0 = <&vbus1_pins>;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+	};
+
+	vbus2: regulator-vbus-2 {
+		compatible = "regulator-fixed";
+		regulator-name = "vbus2";
+		gpio = <&gpio4 21 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		pinctrl-names = "default";
+		pinctrl-0 = <&vbus2_pins>;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+	};
+
+	v_1_2: regulator-1-2 {
+		compatible = "regulator-fixed";
+		regulator-name = "1v2";
+		regulator-min-microvolt = <1200000>;
+		regulator-max-microvolt = <1200000>;
+	};
+};
+
+&i2c3 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c3_pins>;
+	status = "okay";
+
+	carrier_rtc: rtc at 69 {
+		compatible = "abracon,ab1805";
+		reg = <0x69>;
+		abracon,tc-diode = "schottky";
+		abracon,tc-resistor = <3>;
+	};
+
+	carrier_eeprom: eeprom at 57{
+		compatible = "st,24c02", "atmel,24c02";
+		reg = <0x57>;
+		pagesize = <16>;
+	};
+
+	hdmi at 3d {
+		compatible = "adi,adv7535";
+		reg = <0x3d>, <0x3f>, <0x3c>, <0x38>;
+		reg-names = "main", "edid", "cec", "packet";
+		adi,dsi-lanes = <4>;
+		avdd-supply = <&v_1_8>;
+		dvdd-supply = <&v_1_8>;
+		pvdd-supply = <&v_1_8>;
+		a2vdd-supply = <&v_1_8>;
+		v3p3-supply = <&v_3_3>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&hdmi_pins>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
+		pd-gpios = <&gpio3 22 GPIO_ACTIVE_LOW>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+
+				adv7535_from_dsim: endpoint {
+					remote-endpoint = <&mipi_dsi_out>;
+				};
+			};
+
+			port at 1 {
+				reg = <1>;
+
+				adv7535_out: endpoint {
+					remote-endpoint = <&hdmi_connector_in>;
+				};
+			};
+		};
+	};
+};
+
+&iomuxc {
+	hdmi_pins: pinctrl-hdmi-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_GPIO1_IO07_GPIO1_IO7	0x0
+			MX8MM_IOMUXC_SAI5_RXD1_GPIO3_IO22	0x0
+		>;
+	};
+
+	i2c3_pins: pinctrl-i2c3-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_I2C3_SCL_I2C3_SCL		0x400001c3
+			MX8MM_IOMUXC_I2C3_SDA_I2C3_SDA		0x400001c3
+		>;
+	};
+
+	led_pins: pinctrl-led-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_UART4_TXD_GPIO5_IO29	0x0
+			MX8MM_IOMUXC_ECSPI1_SS0_GPIO5_IO9	0x0
+			MX8MM_IOMUXC_ECSPI1_MISO_GPIO5_IO8	0x0
+			MX8MM_IOMUXC_ECSPI1_MOSI_GPIO5_IO7	0x0
+			MX8MM_IOMUXC_ECSPI1_SCLK_GPIO5_IO6	0x0
+		>;
+	};
+
+	pcie_rfkill_pins: pinctrl-pcie-rfkill-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SD2_WP_GPIO2_IO20		0x0
+		>;
+	};
+
+	usb_hub_pins: pinctrl-usb-hub-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SAI3_RXD_GPIO4_IO30	0x0
+		>;
+	};
+
+	usdhc2_pins: pinctrl-usdhc2-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK		0x190
+			MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d0
+			MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d0
+			MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d0
+			MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d0
+			MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d0
+			MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x140
+			MX8MM_IOMUXC_SD2_CD_B_USDHC2_CD_B	0x0
+		>;
+	};
+
+	usdhc2_100mhz_pins: pinctrl-usdhc2-100mhz-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK		0x194
+			MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d4
+			MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d4
+			MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d4
+			MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d4
+			MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d4
+			MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x140
+			MX8MM_IOMUXC_SD2_CD_B_USDHC2_CD_B	0x0
+		>;
+	};
+
+	usdhc2_200mhz_pins: pinctrl-usdhc2-100mhz-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK		0x196
+			MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d6
+			MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d6
+			MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d6
+			MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d6
+			MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d6
+			MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x140
+			MX8MM_IOMUXC_SD2_CD_B_USDHC2_CD_B	0x0
+		>;
+	};
+
+	vbus1_pins: pinctrl-vbus-1-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SD1_STROBE_GPIO2_IO11	0x20
+		>;
+	};
+
+	vbus2_pins: pinctrl-vbus-2-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SAI2_RXFS_GPIO4_IO21	0x20
+		>;
+	};
+
+	vmmc_pins: pinctrl-vmmc-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SD2_RESET_B_GPIO2_IO19	0x41
+		>;
+	};
+};
+
+&lcdif {
+	status = "okay";
+};
+
+&mipi_dsi {
+	samsung,esc-clock-frequency = <10000000>;
+	status = "okay";
+};
+
+&mipi_dsi_out {
+	remote-endpoint = <&adv7535_from_dsim>;
+};
+
+&usbotg1 {
+	dr_mode = "host";
+	vbus-supply = <&vbus2>;
+	status = "okay";
+};
+
+&usbotg2 {
+	status = "okay";
+	dr_mode = "host";
+	vbus-supply = <&vbus1>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&usb_hub_pins>;
+
+	hub_2_0: hub at 1 {
+		compatible = "usb4b4,6502", "usb4b4,6506";
+		reg = <1>;
+		peer-hub = <&hub_3_0>;
+		reset-gpios = <&gpio4 30 GPIO_ACTIVE_LOW>;
+		vdd-supply = <&v_1_2>;
+		vdd2-supply = <&v_3_3>;
+	};
+
+	/* this device is not visible because host supports 2.0 only */
+	hub_3_0: hub at 2 {
+		compatible = "usb4b4,6500", "usb4b4,6504";
+		reg = <2>;
+		peer-hub = <&hub_2_0>;
+		reset-gpios = <&gpio4 30 GPIO_ACTIVE_LOW>;
+		vdd-supply = <&v_1_2>;
+		vdd2-supply = <&v_3_3>;
+	};
+};
+
+&usdhc2 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&usdhc2_pins>;
+	pinctrl-1 = <&usdhc2_100mhz_pins>;
+	pinctrl-2 = <&usdhc2_200mhz_pins>;
+	vmmc-supply = <&vmmc>;
+	bus-width = <4>;
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-sr-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-sr-som.dtsi
new file mode 100644
index 0000000000000..04c16475e64a8
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mm-sr-som.dtsi
@@ -0,0 +1,395 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2025 Josua Mayer <josua at solid-run.com>
+ */
+
+#include <dt-bindings/phy/phy-imx8-pcie.h>
+
+#include "imx8mm.dtsi"
+
+/ {
+	model = "SolidRun i.MX8MM SoM";
+	compatible = "solidrun,imx8mm-sr-som", "fsl,imx8mm";
+
+	chosen {
+		bootargs = "earlycon=ec_imx6q,0x30890000,115200";
+		stdout-path = &uart2;
+	};
+
+	memory at 40000000 {
+		device_type = "memory";
+		reg = <0x0 0x40000000 0 0x80000000>;
+	};
+
+	usdhc1_pwrseq: usdhc1-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>;
+	};
+
+	v_1_8: regulator-1-8 {
+		compatible = "regulator-fixed";
+		regulator-name = "1v8";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	v_3_3: regulator-3-3 {
+		compatible = "regulator-fixed";
+		regulator-name = "3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+};
+
+&fec1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&fec1_pins>;
+	phy-mode = "rgmii-id";
+	phy = <&phy0>;
+	fsl,magic-packet;
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy0: ethernet-phy at 4 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <0x4>;
+			reset-gpios = <&gpio4 22 GPIO_ACTIVE_LOW>;
+			phy-reset-duration = <10>;
+			qca,smarteee-tw-us-1g = <24>;
+			vddio-supply = <&vddio>;
+
+			vddio: vddio-regulator {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+		};
+	};
+};
+
+&i2c1 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	status = "okay";
+
+	som_eeprom: eeprom at 50{
+		compatible = "st,24c01", "atmel,24c01";
+		reg = <0x50>;
+		pagesize = <16>;
+	};
+
+	pmic at 4b {
+		compatible = "rohm,bd71847";
+		reg = <0x4b>;
+		pinctrl-0 = <&pmic_pins>;
+		pinctrl-names = "default";
+		interrupt-parent = <&gpio1>;
+		interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+		rohm,reset-snvs-powered;
+
+		#clock-cells = <0>;
+		clocks = <&osc_32k>;
+		clock-output-names = "clk-32k-out";
+
+		regulators {
+			buck1_reg: BUCK1 {
+				regulator-name = "buck1";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <1250>;
+			};
+
+			buck2_reg: BUCK2 {
+				regulator-name = "buck2";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <1250>;
+				rohm,dvs-run-voltage = <1000000>;
+				rohm,dvs-idle-voltage = <900000>;
+			};
+
+			buck3_reg: BUCK3 {
+				// BUCK5 in datasheet
+				regulator-name = "buck3";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			buck4_reg: BUCK4 {
+				// BUCK6 in datasheet
+				regulator-name = "buck4";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			buck5_reg: BUCK5 {
+				// BUCK7 in datasheet
+				regulator-name = "buck5";
+				regulator-min-microvolt = <1605000>;
+				regulator-max-microvolt = <1995000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			buck6_reg: BUCK6 {
+				// BUCK8 in datasheet
+				regulator-name = "buck6";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1400000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo1_reg: LDO1 {
+				regulator-name = "ldo1";
+				regulator-min-microvolt = <1600000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo2_reg: LDO2 {
+				regulator-name = "ldo2";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <900000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo3_reg: LDO3 {
+				regulator-name = "ldo3";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo4_reg: LDO4 {
+				regulator-name = "ldo4";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo6_reg: LDO6 {
+				regulator-name = "ldo6";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+		};
+	};
+};
+
+&iomuxc {
+	fec1_pins: pinctrl-fec1-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_ENET_MDC_ENET1_MDC			0x3
+			MX8MM_IOMUXC_ENET_MDIO_ENET1_MDIO		0x3
+			MX8MM_IOMUXC_ENET_TD3_ENET1_RGMII_TD3		0x1f
+			MX8MM_IOMUXC_ENET_TD2_ENET1_RGMII_TD2		0x1f
+			MX8MM_IOMUXC_ENET_TD1_ENET1_RGMII_TD1		0x1f
+			MX8MM_IOMUXC_ENET_TD0_ENET1_RGMII_TD0		0x1f
+			MX8MM_IOMUXC_ENET_RD3_ENET1_RGMII_RD3		0x91
+			MX8MM_IOMUXC_ENET_RD2_ENET1_RGMII_RD2		0x91
+			MX8MM_IOMUXC_ENET_RD1_ENET1_RGMII_RD1		0x91
+			MX8MM_IOMUXC_ENET_RD0_ENET1_RGMII_RD0		0x91
+			MX8MM_IOMUXC_ENET_TXC_ENET1_RGMII_TXC		0x1f
+			MX8MM_IOMUXC_ENET_RXC_ENET1_RGMII_RXC		0x91
+			MX8MM_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x91
+			MX8MM_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x1f
+			MX8MM_IOMUXC_SAI2_RXC_GPIO4_IO22		0x19
+		>;
+	};
+
+	i2c1_pins: pinctrl-i2c1-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_I2C1_SCL_I2C1_SCL			0x400001c3
+			MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA			0x400001c3
+		>;
+	};
+
+	pcie_pins: pinctrl-pcie-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_GPIO1_IO15_GPIO1_IO15		0x0
+		>;
+	};
+
+	pmic_pins: pinctrl-pmic-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3		0x140
+		>;
+	};
+
+	uart1_pins: pinctrl-uart1-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_UART1_RXD_UART1_DCE_RX	0x140
+			MX8MM_IOMUXC_UART1_TXD_UART1_DCE_TX	0x140
+			MX8MM_IOMUXC_UART3_RXD_UART1_DCE_CTS_B	0x140
+			MX8MM_IOMUXC_UART3_TXD_UART1_DCE_RTS_B	0x140
+			/* BT_REG_ON */
+			MX8MM_IOMUXC_SD1_DATA4_GPIO2_IO6	0x0
+			/* BT_WAKE_DEV */
+			MX8MM_IOMUXC_SD1_DATA5_GPIO2_IO7	0x0
+			/* BT_WAKE_HOST */
+			MX8MM_IOMUXC_SD1_DATA6_GPIO2_IO8	0x100
+		>;
+	};
+
+	uart2_pins: pinctrl-uart2-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_UART2_RXD_UART2_DCE_RX		0x140
+			MX8MM_IOMUXC_UART2_TXD_UART2_DCE_TX		0x140
+		>;
+	};
+
+	usdhc1_pins: pinctrl-usdhc1-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SD1_CLK_USDHC1_CLK			0x190
+			MX8MM_IOMUXC_SD1_CMD_USDHC1_CMD			0x1d0
+			MX8MM_IOMUXC_SD1_DATA0_USDHC1_DATA0		0x1d0
+			MX8MM_IOMUXC_SD1_DATA1_USDHC1_DATA1		0x1d0
+			MX8MM_IOMUXC_SD1_DATA2_USDHC1_DATA2		0x1d0
+			MX8MM_IOMUXC_SD1_DATA3_USDHC1_DATA3		0x1d0
+			/* wifi refclk */
+			MX8MM_IOMUXC_GPIO1_IO00_ANAMIX_REF_CLK_32K	0x0
+			/* WL_REG_ON */
+			MX8MM_IOMUXC_SD1_RESET_B_GPIO2_IO10		0x0
+			/* WL_WAKE_HOST */
+			MX8MM_IOMUXC_SD1_DATA7_GPIO2_IO9		0x100
+		>;
+	};
+
+	usdhc3_pins: pinctrl-usdhc3-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK		0x190
+			MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d0
+			MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d0
+			MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d0
+			MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d0
+			MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d0
+			MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d0
+			MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d0
+			MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d0
+			MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d0
+			MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x190
+		>;
+	};
+
+	usdhc3_100mhz_pins: pinctrl-usdhc3-100mhz-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK		0x194
+			MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d4
+			MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d4
+			MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d4
+			MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d4
+			MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d4
+			MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d4
+			MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d4
+			MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d4
+			MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d4
+			MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x194
+		>;
+	};
+
+	usdhc3_200mhz_pins: pinctrl-usdhc3-200mhz-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK		0x196
+			MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d6
+			MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d6
+			MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d6
+			MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d6
+			MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d6
+			MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d6
+			MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d6
+			MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d6
+			MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d6
+			MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x196
+		>;
+	};
+
+	wdog1_pins: pinctrl-wdog1-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B	0x140
+		>;
+	};
+};
+
+&pcie_phy {
+	fsl,clkreq-unsupported;
+	fsl,refclk-pad-mode = <IMX8_PCIE_REFCLK_PAD_OUTPUT>;
+	status = "okay";
+};
+
+/* assembly-option for AI accelerator on SoM, otherwise routed to carrier */
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie_pins>;
+	reset-gpios = <&gpio1 15 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>;
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	uart-has-rtscts;
+	/* select 80MHz parent clock to support maximum baudrate 4Mbps */
+	assigned-clocks = <&clk IMX8MM_CLK_UART1>;
+	assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_80M>;
+	status = "okay";
+
+	bluetooth {
+		compatible = "brcm,bcm4330-bt";
+		device-wakeup-gpios = <&gpio2 7 GPIO_ACTIVE_HIGH>;
+		host-wakeup-gpios = <&gpio2 8 GPIO_ACTIVE_HIGH>;
+		shutdown-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>;
+		max-speed = <3000000>;
+	};
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "okay";
+};
+
+&usdhc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&usdhc1_pins>;
+	vmmc-supply = <&v_3_3>;
+	vqmmc-supply = <&v_1_8>;
+	bus-width = <4>;
+	mmc-pwrseq = <&usdhc1_pwrseq>;
+	status = "okay";
+};
+
+&usdhc3 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&usdhc3_pins>;
+	pinctrl-1 = <&usdhc3_100mhz_pins>;
+	pinctrl-2 = <&usdhc3_200mhz_pins>;
+	vmmc-supply = <&v_3_3>;
+	vqmmc-supply = <&v_1_8>;
+	bus-width = <8>;
+	non-removable;
+	status = "okay";
+};
+
+&wdog1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&wdog1_pins>;
+	status = "okay";
+};

-- 
2.51.0




From dan.carpenter at linaro.org  Mon Dec  1 05:08:14 2025
From: dan.carpenter at linaro.org (Dan Carpenter)
Date: Mon, 1 Dec 2025 16:08:14 +0300
Subject: [PATCH 0/4] s32g: Use a syscon for GPR
Message-ID: <cover.1764592300.git.dan.carpenter@linaro.org>

*** BLURB HERE ***

Dan Carpenter (4):
  net: stmmac: s32: use the syscon interface PHY_INTF_SEL_RGMII
  dt-bindings: mfd: syscon: Document the GPR syscon for the NXP S32 SoCs
  dt-bindings: net: nxp,s32-dwmac: Use the GPR syscon
  dts: s32g: Add GPR syscon region

 .../devicetree/bindings/mfd/syscon.yaml       |  2 ++
 .../bindings/net/nxp,s32-dwmac.yaml           |  6 +++++
 arch/arm64/boot/dts/freescale/s32g2.dtsi      |  8 +++++++
 arch/arm64/boot/dts/freescale/s32g3.dtsi      |  8 +++++++
 .../net/ethernet/stmicro/stmmac/dwmac-s32.c   | 23 +++++++++++++++----
 5 files changed, 42 insertions(+), 5 deletions(-)

-- 
2.51.0



From dan.carpenter at linaro.org  Mon Dec  1 05:08:20 2025
From: dan.carpenter at linaro.org (Dan Carpenter)
Date: Mon, 1 Dec 2025 16:08:20 +0300
Subject: [PATCH 1/4] net: stmmac: s32: use the syscon interface
 PHY_INTF_SEL_RGMII
In-Reply-To: <cover.1764592300.git.dan.carpenter@linaro.org>
References: <cover.1764592300.git.dan.carpenter@linaro.org>
Message-ID: <6275e666a7ef78bd4c758d3f7f6fb6f30407393e.1764592300.git.dan.carpenter@linaro.org>

On the s32 chipset the GMAC_0_CTRL_STS register is in GPR region.
Originally, accessing this register was done in a sort of ad-hoc way,
but we want to use the syscon interface to do it.

This is a little bit uglier because we to maintain backwards compatibility
to the old device trees so we have to support both ways to access this
register.

Signed-off-by: Dan Carpenter <dan.carpenter at linaro.org>
---
 .../net/ethernet/stmicro/stmmac/dwmac-s32.c   | 23 +++++++++++++++----
 1 file changed, 18 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c
index 5a485ee98fa7..20de761b7d28 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c
@@ -11,12 +11,14 @@
 #include <linux/device.h>
 #include <linux/ethtool.h>
 #include <linux/io.h>
+#include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of_mdio.h>
 #include <linux/of_address.h>
 #include <linux/phy.h>
 #include <linux/phylink.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/stmmac.h>
 
 #include "stmmac_platform.h"
@@ -32,6 +34,8 @@
 struct s32_priv_data {
 	void __iomem *ioaddr;
 	void __iomem *ctrl_sts;
+	struct regmap *sts_regmap;
+	unsigned int sts_offset;
 	struct device *dev;
 	phy_interface_t *intf_mode;
 	struct clk *tx_clk;
@@ -40,7 +44,10 @@ struct s32_priv_data {
 
 static int s32_gmac_write_phy_intf_select(struct s32_priv_data *gmac)
 {
-	writel(S32_PHY_INTF_SEL_RGMII, gmac->ctrl_sts);
+	if (gmac->ctrl_sts)
+		writel(S32_PHY_INTF_SEL_RGMII, gmac->ctrl_sts);
+	else
+		regmap_write(gmac->sts_regmap, gmac->sts_offset, PHY_INTF_SEL_RGMII);
 
 	dev_dbg(gmac->dev, "PHY mode set to %s\n", phy_modes(*gmac->intf_mode));
 
@@ -125,10 +132,16 @@ static int s32_dwmac_probe(struct platform_device *pdev)
 				     "dt configuration failed\n");
 
 	/* PHY interface mode control reg */
-	gmac->ctrl_sts = devm_platform_get_and_ioremap_resource(pdev, 1, NULL);
-	if (IS_ERR(gmac->ctrl_sts))
-		return dev_err_probe(dev, PTR_ERR(gmac->ctrl_sts),
-				     "S32CC config region is missing\n");
+	gmac->sts_regmap = syscon_regmap_lookup_by_phandle_args(dev->of_node,
+					"phy-sel", 1, &gmac->sts_offset);
+	if (gmac->sts_regmap == ERR_PTR(-EPROBE_DEFER))
+		return PTR_ERR(gmac->sts_regmap);
+	if (IS_ERR(gmac->sts_regmap)) {
+		gmac->ctrl_sts = devm_platform_get_and_ioremap_resource(pdev, 1, NULL);
+		if (IS_ERR(gmac->ctrl_sts))
+			return dev_err_probe(dev, PTR_ERR(gmac->ctrl_sts),
+					     "S32CC config region is missing\n");
+	}
 
 	/* tx clock */
 	gmac->tx_clk = devm_clk_get(&pdev->dev, "tx");
-- 
2.51.0



From dan.carpenter at linaro.org  Mon Dec  1 05:08:33 2025
From: dan.carpenter at linaro.org (Dan Carpenter)
Date: Mon, 1 Dec 2025 16:08:33 +0300
Subject: [PATCH 4/4] dts: s32g: Add GPR syscon region
In-Reply-To: <cover.1764592300.git.dan.carpenter@linaro.org>
References: <cover.1764592300.git.dan.carpenter@linaro.org>
Message-ID: <c8302f53fcbb5cb5afe42cdb15aba7e2e6ed7338.1764592300.git.dan.carpenter@linaro.org>

Add the GPR syscon region for the s32 chipset.

Signed-off-by: Dan Carpenter <dan.carpenter at linaro.org>
---
 arch/arm64/boot/dts/freescale/s32g2.dtsi | 8 ++++++++
 arch/arm64/boot/dts/freescale/s32g3.dtsi | 8 ++++++++
 2 files changed, 16 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/s32g2.dtsi b/arch/arm64/boot/dts/freescale/s32g2.dtsi
index 51d00dac12de..3c9472f6c174 100644
--- a/arch/arm64/boot/dts/freescale/s32g2.dtsi
+++ b/arch/arm64/boot/dts/freescale/s32g2.dtsi
@@ -325,6 +325,13 @@ usdhc0-200mhz-grp4 {
 			};
 		};
 
+		gpr: syscon at 4007c000 {
+			compatible = "nxp,s32-gpr", "syscon";
+			reg = <0x4007c000 0x3000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+		};
+
 		ocotp: nvmem at 400a4000 {
 			compatible = "nxp,s32g2-ocotp";
 			reg = <0x400a4000 0x400>;
@@ -731,6 +738,7 @@ gmac0: ethernet at 4033c000 {
 			compatible = "nxp,s32g2-dwmac";
 			reg = <0x4033c000 0x2000>, /* gmac IP */
 			      <0x4007c004 0x4>;    /* GMAC_0_CTRL_STS */
+			phy-sel = <&gpr 0x4>;
 			interrupt-parent = <&gic>;
 			interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
 			interrupt-names = "macirq";
diff --git a/arch/arm64/boot/dts/freescale/s32g3.dtsi b/arch/arm64/boot/dts/freescale/s32g3.dtsi
index eff7673e7f34..0ceca3caf133 100644
--- a/arch/arm64/boot/dts/freescale/s32g3.dtsi
+++ b/arch/arm64/boot/dts/freescale/s32g3.dtsi
@@ -383,6 +383,13 @@ usdhc0-200mhz-grp4 {
 			};
 		};
 
+		gpr: syscon at 4007c000 {
+			compatible = "nxp,s32-gpr", "syscon";
+			reg = <0x4007c000 0x3000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+		};
+
 		ocotp: nvmem at 400a4000 {
 			compatible = "nxp,s32g3-ocotp", "nxp,s32g2-ocotp";
 			reg = <0x400a4000 0x400>;
@@ -808,6 +815,7 @@ gmac0: ethernet at 4033c000 {
 			compatible = "nxp,s32g2-dwmac";
 			reg = <0x4033c000 0x2000>, /* gmac IP */
 			      <0x4007c004 0x4>;    /* GMAC_0_CTRL_STS */
+			phy-sel = <&gpr 0x4>;
 			interrupt-parent = <&gic>;
 			interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
 			interrupt-names = "macirq";
-- 
2.51.0



From huyuye812 at 163.com  Mon Dec  1 05:07:55 2025
From: huyuye812 at 163.com (huyuye)
Date: Mon,  1 Dec 2025 21:07:55 +0800
Subject: [PATCH v7 08/17] ACPI: pci_link: Clear the dependencies after probe
In-Reply-To: <20240729142241.733357-9-sunilvl@ventanamicro.com>
References: <20240729142241.733357-9-sunilvl@ventanamicro.com>
Message-ID: <20251201130757.7032-1-huyuye812@163.com>

Hi, sunilvl

Based on the above patch, I understand that you previously resolved dependencies between Link devices and PCI Host Bridges by calling acpi_dev_clear_dependencies(device). I would like to ask: on RISC?V platforms, if we need to manage dependencies between multiple PCI Host Bridges, could this be addressed by adding a call to acpi_dev_clear_dependencies(device) at the end of the acpi_pci_root_add enumeration function?

Initialization order dependencies can be defined via the ACPI _DEP method in the DSDT. For example, if host bridge B depends on host bridge A, bridge B should not be enumerated until bridge A is fully initialized.

Best regards,
Yuye



From konrad.dybcio at oss.qualcomm.com  Mon Dec  1 05:15:42 2025
From: konrad.dybcio at oss.qualcomm.com (Konrad Dybcio)
Date: Mon, 1 Dec 2025 14:15:42 +0100
Subject: [PATCH v2 10/11] clk: qcom: Add support for VideoCC driver for
 Kaanapali
In-Reply-To: <20251125-kaanapali-mmcc-v2-v2-10-fb44e78f300b@oss.qualcomm.com>
References: <20251125-kaanapali-mmcc-v2-v2-0-fb44e78f300b@oss.qualcomm.com>
 <20251125-kaanapali-mmcc-v2-v2-10-fb44e78f300b@oss.qualcomm.com>
Message-ID: <850c172d-66e0-4d28-903d-fbcef7ad7444@oss.qualcomm.com>

On 11/25/25 6:45 PM, Taniya Das wrote:
> Enable Kaanapali video clock driver for video SW to be able to control
> the clocks from the Video SW driver.
> 
> Signed-off-by: Taniya Das <taniya.das at oss.qualcomm.com>
> ---

[...]

> +static struct clk_mem_branch video_cc_mvs0_freerun_clk = {
> +	.mem_enable_reg = 0x80E4,
> +	.mem_ack_reg =  0x80E4,

hex must be lowercase

> +	.mem_enable_mask = BIT(3),
> +	.mem_enable_ack_mask = 0xc00,

GENMASK(11, 10)

> +	.mem_enable_invert = true,
> +	.branch = {
> +		.halt_reg = 0x80e0,
> +		.halt_check = BRANCH_HALT,
> +		.clkr = {
> +			.enable_reg = 0x80e0,
> +			.enable_mask = BIT(0),
> +			.hw.init = &(const struct clk_init_data) {
> +				.name = "video_cc_mvs0_freerun_clk",
> +				.parent_hws = (const struct clk_hw*[]) {
> +					&video_cc_mvs0_clk_src.clkr.hw,
> +				},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +			},

The indentation is a little malformed 


> +static void clk_kaanapali_regs_configure(struct device *dev, struct regmap *regmap)
> +{
> +	/*
> +	 * Enable clk_on sync for MVS0 and VPP clocks via VIDEO_CC_SPARE1
> +	 * during core reset by default.
> +	 */
> +	regmap_update_bits(regmap, 0x9f24, BIT(0), BIT(0));

regmap_set_bits()

lgtm otherwise

Konrad


From konrad.dybcio at oss.qualcomm.com  Mon Dec  1 05:20:44 2025
From: konrad.dybcio at oss.qualcomm.com (Konrad Dybcio)
Date: Mon, 1 Dec 2025 14:20:44 +0100
Subject: [PATCH v2 08/11] clk: qcom: dispcc: Add support for display clock
 controller Kaanapali
In-Reply-To: <w3ezxipjucswfswfg2z7b7uyu55bssqatdnbxa6jflii4j7nym@lxsnidrewepu>
References: <20251125-kaanapali-mmcc-v2-v2-0-fb44e78f300b@oss.qualcomm.com>
 <20251125-kaanapali-mmcc-v2-v2-8-fb44e78f300b@oss.qualcomm.com>
 <w3ezxipjucswfswfg2z7b7uyu55bssqatdnbxa6jflii4j7nym@lxsnidrewepu>
Message-ID: <8d0ec7fc-6eb0-4b71-8e0f-3deaf1f489d6@oss.qualcomm.com>

On 11/26/25 1:09 AM, Dmitry Baryshkov wrote:
> On Tue, Nov 25, 2025 at 11:15:17PM +0530, Taniya Das wrote:
>> Support the clock controller driver for Kaanapali to enable display SW to
>> be able to control the clocks.
>>
>> Signed-off-by: Taniya Das <taniya.das at oss.qualcomm.com>
>> ---

[...]

>> +/* 257.142858 MHz Configuration */
> 
> This is a bit strange frequency for the boot config.

The frequency map lists this odd cookie as the lowest predefined config,
perhaps it was pulled from there.

More interestingly, the only consumer of this PLL (MDP_CLK_SRC) makes no
effort to use the m/n/d registers, instead relying on the PLL to re-clock
for its ratesetting with a fixed divider of 3 (and div1 @ XO rate).

257.142858 * 3 = 771.428574 over-drives MDP_CLK_SRC, FWIW.

Taniya, we've seen something like this in camera too. Is there a reason
the frequency is being set this way?

Konrad

> 
>> +static const struct alpha_pll_config disp_cc_pll0_config = {
>> +	.l = 0xd,
>> +	.cal_l = 0x48,
>> +	.alpha = 0x6492,
>> +	.config_ctl_val = 0x25c400e7,
>> +	.config_ctl_hi_val = 0x0a8062e0,
>> +	.config_ctl_hi1_val = 0xf51dea20,
>> +	.user_ctl_val = 0x00000008,
>> +	.user_ctl_hi_val = 0x00000002,
>> +};
>> +
> 


From john.ogness at linutronix.de  Mon Dec  1 05:21:32 2025
From: john.ogness at linutronix.de (John Ogness)
Date: Mon, 01 Dec 2025 14:27:32 +0106
Subject: CSD lockup during kexec due to unbounded busy-wait in
 pl011_console_write_atomic (arm64)
In-Reply-To: <87ecpefjee.fsf@jogness.linutronix.de>
References: <sqwajvt7utnt463tzxgwu2yctyn5m6bjwrslsnupfexeml6hkd@v6sqmpbu3vvu>
 <aSnI8UQRNICSKxAb@pathway.suse.cz> <87ecpefjee.fsf@jogness.linutronix.de>
Message-ID: <87bjkificj.fsf@jogness.linutronix.de>

On 2025-12-01, John Ogness <john.ogness at linutronix.de> wrote:
>> diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
>> index 3fa403f9831f..6b8becb6ecd9 100644
>> --- a/kernel/printk/nbcon.c
>> +++ b/kernel/printk/nbcon.c
>> @@ -1549,6 +1549,7 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
>>  {
>>  	struct nbcon_write_context wctxt = { };
>>  	struct nbcon_context *ctxt = &ACCESS_PRIVATE(&wctxt, ctxt);
>> +	unsigned long flags;
>>  	int err = 0;
>>  
>>  	ctxt->console			= con;
>> @@ -1557,18 +1558,31 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
>>  	ctxt->allow_unsafe_takeover	= nbcon_allow_unsafe_takeover();
>>  
>>  	while (nbcon_seq_read(con) < stop_seq) {
>> -		if (!nbcon_context_try_acquire(ctxt, false))
>> +		/*
>> +		 * Atomic flushing does not use console driver synchronization
>> +		 * (i.e. it does not hold the port lock for uart consoles).
>> +		 * Therefore IRQs must be disabled to avoid being interrupted
>> +		 * and then calling into a driver that will deadlock trying
>> +		 * to acquire console ownership.
>> +		 */
>> +		local_irq_save(flags);
>> +		if (!nbcon_context_try_acquire(ctxt, false)) {
>> +			local_irq_restore(flags);
>>  			return -EPERM;
>> +		}
>>  
>>  		/*
>>  		 * nbcon_emit_next_record() returns false when the console was
>>  		 * handed over or taken over. In both cases the context is no
>>  		 * longer valid.
>>  		 */
>> -		if (!nbcon_emit_next_record(&wctxt, true))
>> +		if (!nbcon_emit_next_record(&wctxt, true)) {
>> +			local_irq_restore(flags);
>>  			return -EAGAIN;
>> +		}
>>  
>>  		nbcon_context_release(ctxt);
>> +		local_irq_restore(flags);
>
> Using local_irq_save()/_restore() here is not acceptable for PREEMPT_RT
> because __nbcon_atomic_flush_pending_con() is also used by
> nbcon_device_release().

After thinking about this more, this would be acceptable. If
printk_get_console_flush_type() is reporting nbcon_atomic==true, then
the system is in a state where latencies are irrelevant.

John Ogness


From krzk at kernel.org  Mon Dec  1 05:25:41 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 1 Dec 2025 14:25:41 +0100
Subject: [PATCH 1/4] dt-bindings: arm: rockchip: Add HINLINK H28K
In-Reply-To: <20251201130106.236903-1-amadeus@jmu.edu.cn>
References: <f27dc5ef-1c60-4724-8e18-33bbc4230d3e@kernel.org>
 <20251201130106.236903-1-amadeus@jmu.edu.cn>
Message-ID: <531f4d52-a48d-498a-861c-f15d0f5b456c@kernel.org>

On 01/12/2025 14:01, Chukun Pan wrote:
> Hi,
> 
>> Just squash these two binding patches. Way too much churn.
> 
> However, they are different SBCs manufactured by different companies:

Does not matter, you update same file doing almost the same.

> 
> HINLINK H28K - Shenzhen HINLINK manufactures
> MangoPi M28K - Beijing Widora manufactures
> 
> So should I squash them into a patch?
> 
>> Anyway, looks like duplicate - two devices with same model name.
> 
> These two SBCs are indeed very similar, both in name and configuration.
> So I put them in one series. Perhaps splitting them into two series to
> avoid confusion would have been better?

No, even more confusion. Look what I wrote:

"You have entire commit msg to explain that."

Best regards,
Krzysztof


From will at kernel.org  Mon Dec  1 05:28:13 2025
From: will at kernel.org (Will Deacon)
Date: Mon, 1 Dec 2025 13:28:13 +0000
Subject: [Bug report] hash_name() may cross page boundary and trigger
 sleep in RCU context
In-Reply-To: <CAHk-=wh+cFLLi2x6u61pvL07phSyHPVBTo9Lac2uuqK4eRG_=w@mail.gmail.com>
References: <20251126090505.3057219-1-wozizhi@huaweicloud.com>
 <33ab4aef-020e-49e7-8539-31bf78dac61a@huaweicloud.com>
 <CAHk-=wh1Wfwt9OFB4AfBbjyeu4JVZuSWQ4A8OoT3W6x9btddfw@mail.gmail.com>
 <aSgut4QcBsbXDEo9@shell.armlinux.org.uk>
 <CAHk-=wh+cFLLi2x6u61pvL07phSyHPVBTo9Lac2uuqK4eRG_=w@mail.gmail.com>
Message-ID: <aS2X7cIiRnR26hyg@willie-the-truck>

On Fri, Nov 28, 2025 at 09:06:50AM -0800, Linus Torvalds wrote:
> On Thu, 27 Nov 2025 at 02:58, Russell King (Oracle)
> <linux at armlinux.org.uk> wrote:
> >
> > Ha!
> >
> > As said elsewhere, it looks like 32-bit ARM has been missing updates to
> > the fault handler since pre-git history - this was modelled in the dim
> > and distant i386 handling, and it just hasn't kept up.
> 
> I actually have this dim memory of having seen something along these
> lines before, and I just had never realized how it could happen,
> because that call to do_page_fault() in do_translation_fault()
> visually *looks* like the only call-site, and so that
> 
>         if (addr < TASK_SIZE)
>                 return do_page_fault(addr, fsr, regs);
> 
> looks like it does everything correctly. That "do_page_fault()"
> function is static to the arch/arm/mm/fault.c file, and that's the
> only place that appears to call it.
> 
> The operative word being "appears".
> 
> Becuse I had never before realized that that fault.c then also does that
> 
>   #include "fsr-2level.c"
> 
> and then that do_page_fault() function is exposed through those
> fsr_info[] operation arrays.
> 
> Anyway, I don't think that the ARM fault handling is all *that* bad.
> Sure, it might be worth double-checking, but it *has* been converted
> to the generic accounting helpers a few years ago and to the stack
> growing fixes.
> 
> I think the fix here may be as simple as this trivial patch:
> 
>   diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
>   index 2bc828a1940c..27024ec2d46d 100644
>   --- a/arch/arm/mm/fault.c
>   +++ b/arch/arm/mm/fault.c
>   @@ -277,6 +277,10 @@ do_page_fault(unsigned long addr, ...
>         if (interrupts_enabled(regs))
>                 local_irq_enable();
> 
>   +     /* non-user address faults never have context */
>   +     if (addr >= TASK_SIZE)
>   +             goto no_context;
>   +
>         /*
>          * If we're in an interrupt or have no user
>          * context, we must not take the fault..
> 
> but I really haven't thought much about it.

In the hack I posted [1], I deliberately avoided modifying
do_page_fault() as it's used on the permission fault path. With your
change above, I'm worried that userspace could simply try to access a
kernel address and that would lead to a panic.

Will

[1] https://lore.kernel.org/all/aShLKpTBr9akSuUG at willie-the-truck/


From sunilvl at ventanamicro.com  Mon Dec  1 05:33:09 2025
From: sunilvl at ventanamicro.com (Sunil V L)
Date: Mon, 1 Dec 2025 19:03:09 +0530
Subject: [PATCH v7 08/17] ACPI: pci_link: Clear the dependencies after
 probe
In-Reply-To: <20251201130757.7032-1-huyuye812@163.com>
References: <20240729142241.733357-9-sunilvl@ventanamicro.com>
 <20251201130757.7032-1-huyuye812@163.com>
Message-ID: <aS2ZFdMFMwdlLHA2@sunil-laptop>

On Mon, Dec 01, 2025 at 09:07:55PM +0800, huyuye wrote:
> Hi, sunilvl
> 
> Based on the above patch, I understand that you previously resolved dependencies between Link devices and PCI Host Bridges by calling acpi_dev_clear_dependencies(device). I would like to ask: on RISC?V platforms, if we need to manage dependencies between multiple PCI Host Bridges, could this be addressed by adding a call to acpi_dev_clear_dependencies(device) at the end of the acpi_pci_root_add enumeration function?
> 
> Initialization order dependencies can be defined via the ACPI _DEP method in the DSDT. For example, if host bridge B depends on host bridge A, bridge B should not be enumerated until bridge A is fully initialized.
> 
Yes, that should work.

Regards,
Sunil


From konrad.dybcio at oss.qualcomm.com  Mon Dec  1 05:35:44 2025
From: konrad.dybcio at oss.qualcomm.com (Konrad Dybcio)
Date: Mon, 1 Dec 2025 14:35:44 +0100
Subject: [PATCH v2 2/3] arm64: dts: qcom: lemans: add mdss1 display device
 nodes
In-Reply-To: <20251125105622.1755651-3-quic_mkuntuma@quicinc.com>
References: <20251125105622.1755651-1-quic_mkuntuma@quicinc.com>
 <20251125105622.1755651-3-quic_mkuntuma@quicinc.com>
Message-ID: <32f013e7-ce2a-484b-8575-e98f2d23f59b@oss.qualcomm.com>

On 11/25/25 11:56 AM, Mani Chandana Ballary Kuntumalla wrote:
> Add devicetree changes to enable second Mobile Display Subsystem (mdss1),
> Display Processing Unit(DPU), Display Port(DP) controllers and eDP PHYs
> on the Qualcomm Lemans platform.
> 
> Signed-off-by: Mahadevan P <mahadevan.p at oss.qualcomm.com>
> Signed-off-by: Mani Chandana Ballary Kuntumalla <quic_mkuntuma at quicinc.com>
> ---

[...]

> +			mdss1_dp1: displayport-controller at 2215c000 {
> +				compatible = "qcom,sa8775p-dp";
> +
> +				reg = <0x0 0x2215c000 0x0 0x104>,
> +				      <0x0 0x2215c200 0x0 0x0c0>,
> +				      <0x0 0x2215d000 0x0 0x770>,
> +				      <0x0 0x2215e000 0x0 0x09c>,
> +				      <0x0 0x2215f000 0x0 0x09c>,
> +				      <0x0 0x22160000 0x0 0x09c>,
> +				      <0x0 0x22161000 0x0 0x09c>,
> +				      <0x0 0x22162000 0x0 0x23c>,
> +				      <0x0 0x22163000 0x0 0x23c>;

The last two regions still happen not to exist

https://lore.kernel.org/all/vc2hen5r7xdaj4nepkoy7pk2jmj4y4hgog5o2nfndrff4yti2m at g46svhsdyy7m/

Konrad




From andrew at lunn.ch  Mon Dec  1 05:49:06 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Mon, 1 Dec 2025 14:49:06 +0100
Subject: [PATCH v4 7/8] arm64: dts: add description for solidrun
 solidsense-n8 board
In-Reply-To: <20251201-imx8mp-hb-iiot-v4-7-53a4cd6c21bf@solid-run.com>
References: <20251201-imx8mp-hb-iiot-v4-0-53a4cd6c21bf@solid-run.com>
 <20251201-imx8mp-hb-iiot-v4-7-53a4cd6c21bf@solid-run.com>
Message-ID: <c06e5a6b-6150-4771-8ff6-b2cda0863a21@lunn.ch>

> +&fec1 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&fec1_pins>;
> +	phy-mode = "rgmii-id";
> +	phy-handle = <&phy4>;
> +	local-mac-address = [00 00 00 00 00 00];
> +	fsl,magic-packet;

Has WoL been tested, or is this copy/paste from the binding
documentation?

> +	status = "okay";
> +
> +	mdio {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		/*
> +		 * Depending on board revision two different phys are used:
> +		 * - v1.1: atheros phy at address 4
> +		 * - v1.2+: analog devices phy at address 0
> +		 * Configure first version by default.
> +		 * On v1.2 and later, U-Boot will enable the correct phy
> +		 * based on runtime detection and patch dtb accordingly.
> +		 */
> +
> +		/* ADIN1300 */
> +		phy0: ethernet-phy at 0 {
> +			reg = <0>;
> +			reset-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>;
> +			reset-assert-us = <10>;
> +			reset-deassert-us = <5000>;
> +			interrupt-parent = <&gpio1>;
> +			interrupts = <10 IRQ_TYPE_LEVEL_LOW>;

The analog devices PHY has interrupts, so can it implement WoL? Has
this been tested?

> +		/* AR8035 */
> +		phy4: ethernet-phy at 4 {
> +			reg = <4>;
> +			reset-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>;
> +			reset-assert-us = <10000>;
> +			status = "okay";

The Atheros PHY does not interrupts, so i assume it cannot support
WoL? You only have MAC WoL?

     Andrew


From thierry.reding at gmail.com  Mon Dec  1 06:11:00 2025
From: thierry.reding at gmail.com (Thierry Reding)
Date: Mon, 1 Dec 2025 15:11:00 +0100
Subject: [PATCH V2 3/3] arm64: dts: nvidia: Add nodes for CMDQV
In-Reply-To: <acae92d8-3394-436c-be8e-8bed7a923e85@nvidia.com>
References: <20251125071659.3048659-1-amhetre@nvidia.com>
 <20251125071659.3048659-4-amhetre@nvidia.com>
 <dff3a962-82dd-4aac-ae11-69f0e95ba04d@nvidia.com>
 <acae92d8-3394-436c-be8e-8bed7a923e85@nvidia.com>
Message-ID: <r2mkiktazyn3nvhirbs2ac7n5ymdw62ueutpxt55cnivdi7pdn@6i4hjtvxp2ph>

On Mon, Dec 01, 2025 at 03:06:55PM +0530, Ashish Mhetre wrote:
> 
> On 11/25/2025 3:52 PM, Jon Hunter wrote:
> > 
> > 
> > On 25/11/2025 07:16, Ashish Mhetre wrote:
> > > The Command Queue Virtualization (CMDQV) hardware is part of the
> > > SMMUv3 implementation on NVIDIA Tegra SoCs. It assists in
> > > virtualizing the command queue for the SMMU.
> > > 
> > > Update SMMU compatible strings to use nvidia,tegra264-smmu to enable
> > > CMDQV support. Add device tree nodes for the CMDQV hardware and enable
> > > them on the tegra264-p3834 platform where SMMUs are enabled. Each SMMU
> > > instance is paired with its corresponding CMDQV instance via the
> > > nvidia,cmdqv property.
> > > 
> > > Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
> > > ---
> > > ? .../arm64/boot/dts/nvidia/tegra264-p3834.dtsi |? 8 +++
> > > ? arch/arm64/boot/dts/nvidia/tegra264.dtsi????? | 55 +++++++++++++++++--
> > > ? 2 files changed, 58 insertions(+), 5 deletions(-)
> > > 
> > > diff --git a/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
> > > b/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
> > > index 06795c82427a..375d122b92fa 100644
> > > --- a/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
> > > +++ b/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
> > > @@ -26,5 +26,13 @@ iommu at 5000000 {
> > > ????????? iommu at 6000000 {
> > > ????????????? status = "okay";
> > > ????????? };
> > > +
> > > +??????? cmdqv at 5200000 {
> > > +??????????? status = "okay";
> > > +??????? };
> > 
> > This needs to be ordered in the file according to its address.
> 
> Hi Jon, Thanks for the review.
> cmdqv nodes follow same ordering as its corresponding iommu nodes.
> I have added them immediately after corresponding iommu nodes.

No, you didn't. It seems like you sorted by type and then address. But
we always sort by address first. Type doesn't matter.

This node belongs above the iommu at 6000000 node and after iommu at 5000000.
The same ordering should be respected in the DTS include.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251201/f864b193/attachment.sig>

From robin.murphy at arm.com  Mon Dec  1 06:13:00 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Mon, 1 Dec 2025 14:13:00 +0000
Subject: [PATCH V2 3/3] arm64: dts: nvidia: Add nodes for CMDQV
In-Reply-To: <acae92d8-3394-436c-be8e-8bed7a923e85@nvidia.com>
References: <20251125071659.3048659-1-amhetre@nvidia.com>
 <20251125071659.3048659-4-amhetre@nvidia.com>
 <dff3a962-82dd-4aac-ae11-69f0e95ba04d@nvidia.com>
 <acae92d8-3394-436c-be8e-8bed7a923e85@nvidia.com>
Message-ID: <b66e1993-fe07-4826-9bf4-728e640ccacd@arm.com>

On 2025-12-01 9:36 am, Ashish Mhetre wrote:
> 
> On 11/25/2025 3:52 PM, Jon Hunter wrote:
>>
>>
>> On 25/11/2025 07:16, Ashish Mhetre wrote:
>>> The Command Queue Virtualization (CMDQV) hardware is part of the
>>> SMMUv3 implementation on NVIDIA Tegra SoCs. It assists in
>>> virtualizing the command queue for the SMMU.
>>>
>>> Update SMMU compatible strings to use nvidia,tegra264-smmu to enable
>>> CMDQV support. Add device tree nodes for the CMDQV hardware and enable
>>> them on the tegra264-p3834 platform where SMMUs are enabled. Each SMMU
>>> instance is paired with its corresponding CMDQV instance via the
>>> nvidia,cmdqv property.
>>>
>>> Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
>>> ---
>>> ? .../arm64/boot/dts/nvidia/tegra264-p3834.dtsi |? 8 +++
>>> ? arch/arm64/boot/dts/nvidia/tegra264.dtsi????? | 55 +++++++++++++++++--
>>> ? 2 files changed, 58 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi b/arch/ 
>>> arm64/boot/dts/nvidia/tegra264-p3834.dtsi
>>> index 06795c82427a..375d122b92fa 100644
>>> --- a/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
>>> +++ b/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
>>> @@ -26,5 +26,13 @@ iommu at 5000000 {
>>> ????????? iommu at 6000000 {
>>> ????????????? status = "okay";
>>> ????????? };
>>> +
>>> +??????? cmdqv at 5200000 {
>>> +??????????? status = "okay";
>>> +??????? };
>>
>> This needs to be ordered in the file according to its address.
> 
> Hi Jon, Thanks for the review.
> cmdqv nodes follow same ordering as its corresponding iommu nodes.
> I have added them immediately after corresponding iommu nodes.
> Can you please check and see if it's fine? Same applies to your
> similar comments below as well.

It's fairly standard practice to order DT nodes by unit address where 
applicable (and alphabetically by node name otherwise). The platform 
maintainers aren't necessarily familiar with the intended usage of every 
individual node when they have to resolve merge conflicts etc., so 
maintaining a straightforward consistent pattern is generally easier for 
everyone.

Thanks,
Robin.


From tomi.valkeinen at ideasonboard.com  Mon Dec  1 06:13:16 2025
From: tomi.valkeinen at ideasonboard.com (Tomi Valkeinen)
Date: Mon, 1 Dec 2025 16:13:16 +0200
Subject: [PATCH 05/21] ARM: dts: omap: Bind panel to panel-dpi instead of
 ti,tilcdc,panel driver
In-Reply-To: <20251126-feature_tilcdc-v1-5-49b9ef2e3aa0@bootlin.com>
References: <20251126-feature_tilcdc-v1-0-49b9ef2e3aa0@bootlin.com>
 <20251126-feature_tilcdc-v1-5-49b9ef2e3aa0@bootlin.com>
Message-ID: <96b1b7bf-ddbe-4213-a201-dc89cf2998dd@ideasonboard.com>

Hi Kory,

On 26/11/2025 19:35, Kory Maincent (TI.com) wrote:
> Use panel-dpi driver instead of the deprecated tilcdc-panel driver in
> preparation for removing the tilcdc-panel driver and binding.
> 
> Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
> ---
> 
> This patch is not tested. It would be nice if someone with one of this
> board could test and validate it.
> ---
>  arch/arm/boot/dts/ti/davinci/da850-evm.dts    | 26 +++++++++++++-------------
>  arch/arm/boot/dts/ti/omap/am335x-guardian.dts | 25 +++++++++----------------
>  arch/arm/boot/dts/ti/omap/am335x-pdu001.dts   | 21 ++++++++++-----------
>  arch/arm/boot/dts/ti/omap/am335x-pepper.dts   | 22 +++++++++++-----------
>  arch/arm/boot/dts/ti/omap/am335x-sbc-t335.dts | 25 +++++++++++++------------
>  arch/arm/boot/dts/ti/omap/am335x-sl50.dts     | 25 ++++++++++++-------------
>  6 files changed, 68 insertions(+), 76 deletions(-)
> 

Doesn't this, or rather the following patches, break DTB compatibility
with all the above boards?

 Tomi

> diff --git a/arch/arm/boot/dts/ti/davinci/da850-evm.dts b/arch/arm/boot/dts/ti/davinci/da850-evm.dts
> index 38a191fb04149..79cca1f6205ef 100644
> --- a/arch/arm/boot/dts/ti/davinci/da850-evm.dts
> +++ b/arch/arm/boot/dts/ti/davinci/da850-evm.dts
> @@ -40,7 +40,7 @@ backlight: backlight-pwm {
>  	};
>  
>  	panel {
> -		compatible = "ti,tilcdc,panel";
> +		compatible = "panel-dpi";
>  		pinctrl-names = "default";
>  		pinctrl-0 = <&lcd_pins>;
>  		/*
> @@ -50,17 +50,10 @@ panel {
>  		 */
>  		status = "okay";
>  		enable-gpios = <&gpio 40 GPIO_ACTIVE_HIGH>; /* lcd_panel_pwr */
> -
> -		panel-info {
> -			ac-bias = <255>;
> -			ac-bias-intrpt = <0>;
> -			dma-burst-sz = <16>;
> -			bpp = <16>;
> -			fdd = <0x80>;
> -			sync-edge = <0>;
> -			sync-ctrl = <1>;
> -			raster-order = <0>;
> -			fifo-th = <1>;
> +		port {
> +			panel_in: endpoint {
> +				remote-endpoint = <&lcdc_out>;
> +			};
>  		};
>  
>  		display-timings {
> @@ -222,6 +215,13 @@ &rtc0 {
>  };
>  
>  &lcdc {
> +	fifo-threshold = <16>;
> +
> +	port {
> +		lcdc_out: endpoint {
> +			remote-endpoint = <&panel_in>;
> +		};
> +	};
>  	status = "okay";
>  };
>  
> @@ -459,7 +459,7 @@ &vpif {
>  	pinctrl-0 = <&vpif_capture_pins>, <&vpif_display_pins>;
>  	/*
>  	 * The vpif and the LCD are mutually exclusive.
> -	 * To enable VPIF, disable the ti,tilcdc,panel then
> +	 * To enable VPIF, disable the panel-dpi then
>  	 * change the status below to 'okay'
>  	 */
>  	status = "disabled";
> diff --git a/arch/arm/boot/dts/ti/omap/am335x-guardian.dts b/arch/arm/boot/dts/ti/omap/am335x-guardian.dts
> index 4b070e634b281..f38ce9be2c106 100644
> --- a/arch/arm/boot/dts/ti/omap/am335x-guardian.dts
> +++ b/arch/arm/boot/dts/ti/omap/am335x-guardian.dts
> @@ -68,10 +68,15 @@ gpio-poweroff {
>  	};
>  
>  	panel {
> -		compatible = "ti,tilcdc,panel";
> +		compatible = "panel-dpi";
>  		pinctrl-names = "default", "sleep";
>  		pinctrl-0 = <&lcd_pins_default &lcd_disen_pins>;
>  		pinctrl-1 = <&lcd_pins_sleep>;
> +		port {
> +			panel_in: endpoint {
> +				remote-endpoint = <&lcdc_out>;
> +			};
> +		};
>  
>  		display-timings {
>  			timing-320x240 {
> @@ -86,21 +91,9 @@ timing-320x240 {
>  				clock-frequency = <9000000>;
>  				hsync-active    = <0>;
>  				vsync-active    = <0>;
> +				pixelclk-active = <1>;
>  			};
>  		};
> -		panel-info {
> -			ac-bias           = <255>;
> -			ac-bias-intrpt    = <0>;
> -			dma-burst-sz      = <16>;
> -			bpp               = <24>;
> -			bus-width         = <16>;
> -			fdd               = <0x80>;
> -			sync-edge         = <0>;
> -			sync-ctrl         = <1>;
> -			raster-order      = <0>;
> -			fifo-th           = <0>;
> -		};
> -
>  	};
>  
>  	guardian_beeper: pwm-7 {
> @@ -265,8 +258,8 @@ &lcdc {
>  	blue-and-red-wiring = "crossed";
>  	status = "okay";
>  	port {
> -		lcdc_0: endpoint at 0 {
> -			remote-endpoint = <0>;
> +		lcdc_out: endpoint at 0 {
> +			remote-endpoint = <&panel_in>;
>  		};
>  	};
>  };
> diff --git a/arch/arm/boot/dts/ti/omap/am335x-pdu001.dts b/arch/arm/boot/dts/ti/omap/am335x-pdu001.dts
> index c9ccb9de21ad7..2c5229d05ade7 100644
> --- a/arch/arm/boot/dts/ti/omap/am335x-pdu001.dts
> +++ b/arch/arm/boot/dts/ti/omap/am335x-pdu001.dts
> @@ -50,20 +50,14 @@ lis3_reg: fixedregulator at 1 {
>  	};
>  
>  	panel {
> -		compatible = "ti,tilcdc,panel";
> +		compatible = "panel-dpi";
>  		status = "okay";
>  		pinctrl-names = "default";
>  		pinctrl-0 = <&lcd_pins_s0>;
> -		panel-info {
> -			ac-bias           = <255>;
> -			ac-bias-intrpt    = <0>;
> -			dma-burst-sz      = <16>;
> -			bpp               = <16>;
> -			fdd               = <0x80>;
> -			sync-edge         = <0>;
> -			sync-ctrl         = <1>;
> -			raster-order      = <0>;
> -			fifo-th           = <0>;
> +		port {
> +			panel_in: endpoint {
> +				remote-endpoint = <&lcdc_out>;
> +			};
>  		};
>  
>  		display-timings {
> @@ -395,6 +389,11 @@ &rtc {
>  
>  &lcdc {
>  	status = "okay";
> +	port {
> +		lcdc_out: endpoint {
> +			remote-endpoint = <&panel_in>;
> +		};
> +	};
>  };
>  
>  &elm {
> diff --git a/arch/arm/boot/dts/ti/omap/am335x-pepper.dts b/arch/arm/boot/dts/ti/omap/am335x-pepper.dts
> index e7d561a527fdd..2760c0eab50c2 100644
> --- a/arch/arm/boot/dts/ti/omap/am335x-pepper.dts
> +++ b/arch/arm/boot/dts/ti/omap/am335x-pepper.dts
> @@ -31,7 +31,7 @@ leds: user-leds-pins {
>  	};
>  
>  	panel: lcd_panel {
> -		compatible = "ti,tilcdc,panel";
> +		compatible = "panel-dpi";
>  	};
>  
>  	sound: sound_iface {
> @@ -189,16 +189,10 @@ &panel {
>  	status = "okay";
>  	pinctrl-names = "default";
>  	pinctrl-0 = <&lcd_pins>;
> -	panel-info {
> -		ac-bias = <255>;
> -		ac-bias-intrpt = <0>;
> -		dma-burst-sz = <16>;
> -		bpp = <32>;
> -		fdd = <0x80>;
> -		sync-edge = <0>;
> -		sync-ctrl = <1>;
> -		raster-order = <0>;
> -		fifo-th = <0>;
> +	port {
> +		panel_in: endpoint {
> +			remote-endpoint = <&lcdc_out>;
> +		};
>  	};
>  	display-timings {
>  		native-mode = <&timing0>;
> @@ -214,12 +208,18 @@ timing0: timing-480x272 {
>  			vsync-len = <10>;
>  			hsync-active = <1>;
>  			vsync-active = <1>;
> +			pixelclk-active = <1>;
>  		};
>  	};
>  };
>  
>  &lcdc {
>  	status = "okay";
> +	port {
> +		lcdc_out: endpoint {
> +			remote-endpoint = <&panel_in>;
> +		};
> +	};
>  };
>  
>  &am33xx_pinmux {
> diff --git a/arch/arm/boot/dts/ti/omap/am335x-sbc-t335.dts b/arch/arm/boot/dts/ti/omap/am335x-sbc-t335.dts
> index 2841e95d9a094..25ee855dd21a7 100644
> --- a/arch/arm/boot/dts/ti/omap/am335x-sbc-t335.dts
> +++ b/arch/arm/boot/dts/ti/omap/am335x-sbc-t335.dts
> @@ -13,23 +13,17 @@ / {
>  
>  	/* DRM display driver */
>  	panel {
> -		compatible = "ti,tilcdc,panel";
> +		compatible = "panel-dpi";
>  		status = "okay";
>  		pinctrl-names = "default", "sleep";
>  		pinctrl-0 = <&lcd_pins_default>;
>  		pinctrl-1 = <&lcd_pins_sleep>;
> -
> -		panel-info {
> -			ac-bias           = <255>;
> -			ac-bias-intrpt    = <0>;
> -			dma-burst-sz      = <16>;
> -			bpp               = <32>;
> -			fdd               = <0x80>;
> -			sync-edge         = <0>;
> -			sync-ctrl         = <1>;
> -			raster-order      = <0>;
> -			fifo-th           = <0>;
> +		port {
> +			panel_in: endpoint {
> +				remote-endpoint = <&lcdc_out>;
> +			};
>  		};
> +
>  		display-timings {
>  			/* Timing selection performed by U-Boot */
>  			timing0: lcd {/* 800x480p62 */
> @@ -44,6 +38,7 @@ timing0: lcd {/* 800x480p62 */
>  				vsync-len = <2>;
>  				hsync-active = <1>;
>  				vsync-active = <1>;
> +				pixelclk-active = <1>;
>  			};
>  			timing1: dvi { /* 1024x768p60 */
>  				clock-frequency = <65000000>;
> @@ -57,6 +52,7 @@ timing1: dvi { /* 1024x768p60 */
>  				vsync-len = <6>;
>  				hsync-active = <0>;
>  				vsync-active = <0>;
> +				pixelclk-active = <1>;
>  			};
>  		};
>  	};
> @@ -173,4 +169,9 @@ lcd-ena-hog {
>  /* Display */
>  &lcdc {
>  	status = "okay";
> +	port {
> +		lcdc_out: endpoint {
> +			remote-endpoint = <&panel_in>;
> +		};
> +	};
>  };
> diff --git a/arch/arm/boot/dts/ti/omap/am335x-sl50.dts b/arch/arm/boot/dts/ti/omap/am335x-sl50.dts
> index f3524e5ee43e2..b4b2b6d18d646 100644
> --- a/arch/arm/boot/dts/ti/omap/am335x-sl50.dts
> +++ b/arch/arm/boot/dts/ti/omap/am335x-sl50.dts
> @@ -123,22 +123,14 @@ audio_mclk: audio_mclk_gate at 0 {
>  	};
>  
>  	panel: lcd_panel {
> -		compatible = "ti,tilcdc,panel";
> +		compatible = "panel-dpi";
>  		pinctrl-names = "default";
>  		pinctrl-0 = <&lcd_pins>;
>  
> -		panel-info {
> -			ac-bias = <255>;
> -			ac-bias-intrpt = <0>;
> -			dma-burst-sz = <16>;
> -			bpp = <16>;
> -			fdd = <0x80>;
> -			tft-alt-mode = <0>;
> -			mono-8bit-mode = <0>;
> -			sync-edge = <0>;
> -			sync-ctrl = <1>;
> -			raster-order = <0>;
> -			fifo-th = <0>;
> +		port {
> +			panel_in: endpoint {
> +				remote-endpoint = <&lcdc_out>;
> +			};
>  		};
>  
>  		display-timings {
> @@ -157,6 +149,8 @@ timing0: 960x128 {
>  				vfront-porch = <8>;
>  				vsync-len = <4>;
>  				vsync-active = <0>;
> +
> +				pixelclk-active = <1>;
>  			};
>  		};
>  	};
> @@ -711,6 +705,11 @@ &ehrpwm1 {
>  
>  &lcdc {
>  	status = "okay";
> +	port {
> +		lcdc_out: endpoint {
> +			remote-endpoint = <&panel_in>;
> +		};
> +	};
>  };
>  
>  &tscadc {
> 



From huyuye812 at 163.com  Mon Dec  1 06:12:29 2025
From: huyuye812 at 163.com (huyuye)
Date: Mon,  1 Dec 2025 22:12:29 +0800
Subject: [PATCH v7 08/17] ACPI: pci_link: Clear the dependencies after probe
In-Reply-To: <20240729142241.733357-9-sunilvl@ventanamicro.com>
References: <20240729142241.733357-9-sunilvl@ventanamicro.com>
Message-ID: <20251201141230.12656-1-huyuye812@163.com>

> Hi, sunilvl

> Based on the above patch, I understand that you previously >resolved dependencies between Link devices and PCI Host Bridges by >calling acpi_dev_clear_dependencies(device). I would like to ask: >on RISC?V platforms, if we need to manage dependencies between >multiple PCI Host Bridges, could this be addressed by adding a >call to acpi_dev_clear_dependencies(device) at the end of the >acpi_pci_root_add enumeration function?

> Initialization order dependencies can be defined via the ACPI >_DEP method in the DSDT. For example, if host bridge B depends on >host bridge A, bridge B should not be enumerated until bridge A is >fully initialized.

> Yes, that should work.
> Regards,
> Sunil

Hi,Sunil

I'm truly honored by your affirmation of my answer.Do you think this solution has a chance of being accepted into the upstream kernel? Are there any unintended side effects we may have overlooked?

Regards,
Yuye



From dan.carpenter at linaro.org  Mon Dec  1 06:31:38 2025
From: dan.carpenter at linaro.org (Dan Carpenter)
Date: Mon, 1 Dec 2025 17:31:38 +0300
Subject: [PATCH 0/4] s32g: Use a syscon for GPR
In-Reply-To: <cover.1764592300.git.dan.carpenter@linaro.org>
References: <cover.1764592300.git.dan.carpenter@linaro.org>
Message-ID: <aS2myhp8asABFyLt@stanley.mountain>

On Mon, Dec 01, 2025 at 04:08:14PM +0300, Dan Carpenter wrote:
> *** BLURB HERE ***
> 

Sorry, I obviously meant to write a message here.

The s32g devices have a GPR register region which could be accessed
via a syscon.  Currently only the stmmac/dwmac-s32.c uses anything
from there and we just add a line to the device tree to access
that GMAC_0_CTRL_STS register:

			reg = <0x4033c000 0x2000>, /* gmac IP */
			      <0x4007c004 0x4>;    /* GMAC_0_CTRL_STS */

But it would be better to have a syscon instead of adding each
register to the device tree like this.

We still have to maintain backwards compatibility to this format,
of course.

regards,
dan carpenter



From mani at kernel.org  Mon Dec  1 06:38:12 2025
From: mani at kernel.org (Manivannan Sadhasivam)
Date: Mon, 1 Dec 2025 20:08:12 +0530
Subject: [PATCH v9 4/4] PCI: dwc: Support ECAM mechanism by enabling iATU
 'CFG Shift Feature'
In-Reply-To: <h7pgm3lqolm53sb4wrcpcurk4ghz4tulqnr7vgd7rzxy4hscue@jcn5tepevlwl>
References: <20250909-controller-dwc-ecam-v9-0-7d5b651840dd@kernel.org>
 <20250909-controller-dwc-ecam-v9-4-7d5b651840dd@kernel.org>
 <alpine.DEB.2.21.2511280256260.36486@angie.orcam.me.uk>
 <c7aea2b3-6984-40f5-8234-14d265dabefc@oss.qualcomm.com>
 <alpine.DEB.2.21.2511280755440.36486@angie.orcam.me.uk>
 <cabf4c20-095b-4579-adc1-146a566b19b9@oss.qualcomm.com>
 <alpine.DEB.2.21.2511281714030.36486@angie.orcam.me.uk>
 <a4c6d47f-28b5-40d3-bc82-10aeb14f8e78@oss.qualcomm.com>
 <alpine.DEB.2.21.2511290428340.36486@angie.orcam.me.uk>
 <h7pgm3lqolm53sb4wrcpcurk4ghz4tulqnr7vgd7rzxy4hscue@jcn5tepevlwl>
Message-ID: <syg7vpbt3w53s24hgl7b6w64odmif5bq557lwlvzlbvgkukwcn@66jtzzc3vtiu>

On Mon, Dec 01, 2025 at 05:21:50PM +0530, Manivannan Sadhasivam wrote:
> On Sat, Nov 29, 2025 at 06:04:24AM +0000, Maciej W. Rozycki wrote:
> > On Sat, 29 Nov 2025, Krishna Chaitanya Chundru wrote:
> > 
> > > > > Hi Maciej, Can you try attached patch and let me know if that is helping
> > > > > you
> > > > > or not. - Krishna Chaitanya.
> > > >   No change, it's still broken, sorry.
> > > HI Maciej,
> > > For the previous patch can you apply this diff and share me dmesg o/p
> > 
> >  Your patch came though garbled, likely due to:
> > 
> > Content-Type: text/plain; charset=UTF-8; format=flowed
> > 
> > Please refer Documentation/process/email-clients.rst and reconfigure your 
> > e-mail client if possible.
> > 
> >  Regardless, I've fixed it up by hand and the only difference in the log, 
> > except for usual noise which I removed, is this:
> > 
> > --- dmesg-bad.log	2025-11-28 03:47:29.582049781 +0100
> > +++ dmesg-debug.log	2025-11-29 05:41:23.384645926 +0100
> > @@ -164,6 +164,8 @@
> >  fu740-pcie e00000000.pcie: ECAM at [mem 0xdf0000000-0xdffffffff] for [bus 00-ff]
> >  fu740-pcie e00000000.pcie: Using 256 MSI vectors
> >  fu740-pcie e00000000.pcie: iATU: unroll T, 8 ob, 8 ib, align 4K, limit 4096G
> > +fu740-pcie e00000000.pcie: Current iATU OB index 2
> > +fu740-pcie e00000000.pcie: Current iATU OB index 4
> >  fu740-pcie e00000000.pcie: cap_exp at 70
> >  fu740-pcie e00000000.pcie: PCIe Gen.1 x8 link up
> >  fu740-pcie e00000000.pcie: changing speed back to original
> > 
> > I've attached a full copy of the debug log too.  I hope this helps you 
> > narrow the issue down or otherwise let me know what to try next.
> > 
> >  NB I note that code you've been poking at only refers resources of the 
> > IORESOURCE_MEM type.  What about IORESOURCE_IO, which seems more relevant 
> > here?
> > 
> >  Also as a quick check I've now reconfigured the defxx driver for PCI port 
> > I/O (which is a one-liner; the mapping used to be selectable by hand, but 
> > distributions got it wrong for systems w/o PCI port I/O, so I switched the 
> > driver to an automatic choice a few years ago, but the logic remains):
> > 
> > # cat /proc/ioports
> > 00000000-0000ffff : pcie at e00000000
> >   00001000-00002fff : PCI Bus 0000:01
> >     00001000-00002fff : PCI Bus 0000:02
> >       00001000-00002fff : PCI Bus 0000:05
> >         00001000-00002fff : PCI Bus 0000:06
> >           00001000-00001fff : PCI Bus 0000:07
> >           00001000-00001007 : 0000:07:00.0
> >           00001000-00001002 : parport0
> >           00001003-00001007 : parport0
> >           00001008-0000100b : 0000:07:00.0
> >           00001008-0000100a : parport0
> >           00002000-00002fff : PCI Bus 0000:08
> >           00002000-00002fff : PCI Bus 0000:09
> >           00002000-000020ff : 0000:09:01.0
> >           00002100-0000217f : 0000:09:02.0
> >           00002100-0000217f : defxx
> > # 
> > 
> > and:
> > 
> > defxx 0000:09:02.0: assign IRQ: got 40
> > defxx: v1.12 2021/03/10  Lawrence V. Stefani and others
> > defxx 0000:09:02.0: enabling device (0000 -> 0003)
> > defxx 0000:09:02.0: enabling bus mastering
> > 0000:09:02.0: DEFPA at I/O addr = 0x2100, IRQ = 40, Hardware addr = 00-60-6d-xx-xx-xx
> > 0000:09:02.0: registered as fddi0
> > 
> > (as at commit 4660e50cf818) and likewise it has stopped working here from 
> > commit 0da48c5b2fa7 onwards:
> > 
> > defxx 0000:09:02.0: assign IRQ: got 40
> > defxx: v1.12 2021/03/10  Lawrence V. Stefani and others
> > defxx 0000:09:02.0: enabling device (0000 -> 0003)
> > defxx 0000:09:02.0: enabling bus mastering
> > 0000:09:02.0: Could not read adapter factory MAC address!
> > 
> > So it's definitely nothing specific to the parport driver, but rather a 
> > general issue with PCI/e port I/O not working anymore.  I do hope these 
> > observations will let you address the issue now.  You might be able to 
> > reproduce it with hardware you have available even.
> > 
> 
> Yes, looks like the I/O port access is not working with the CFG Shift feature.
> The spec says that both I/O and MEM TLPs should be handled by this feature, so
> we are currently unsure why MEM works, but not I/O.
> 
> The issue you reported with parport_pc driver is that the driver gets probed,
> but it fails to detect the parallel ports on the device. More precisely, it
> fails due to the parport_SPP_supported() check in drivers/parport/parport_pc.c.
> This function performs some read/write checks to make sure that the port exists,
> but most likely the read value doesn't match the written one. And since there is
> no log printed in this function, it just failed silently.
> 
> We will check why I/O access fails with ECAM mode and revert back asap. Since
> the merge window is now open, it becomes difficult to revert the CFG shift
> feature cleanly. The timing of the report also made it difficult to fix the
> issue in v6.18. Hopefully, we can backport the fix once we identify the culprit.
> 

Can you try the attached patch? It is a reworked version of Krishna's patch. I
just moved things around to check potential override issue.

- Mani

-- 
????????? ????????
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-PCI-qcom-Enable-iATU-mapping-for-memory-IO-regions.patch
Type: text/x-diff
Size: 5467 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251201/63d34be8/attachment-0001.bin>

From quentin.schulz at cherry.de  Mon Dec  1 06:45:24 2025
From: quentin.schulz at cherry.de (Quentin Schulz)
Date: Mon, 1 Dec 2025 15:45:24 +0100
Subject: [PATCH 1/3] arm64: dts: rockchip: add gmac reset property to
 rk3368
In-Reply-To: <20251020100757.3669681-2-heiko@sntech.de>
References: <20251020100757.3669681-1-heiko@sntech.de>
 <20251020100757.3669681-2-heiko@sntech.de>
Message-ID: <5c96a972-68d8-4d68-b0f0-29dc1b18dfd9@cherry.de>

Hi Heiko,

On 10/20/25 12:07 PM, Heiko Stuebner wrote:
> From: Heiko Stuebner <heiko.stuebner at cherry.de>
> 
> Add the reset of the gmac controller block.
> 
> Signed-off-by: Heiko Stuebner <heiko.stuebner at cherry.de>

Reviewed-by: Quentin Schulz <quentin.schulz at cherry.de>

Thanks!
Quentin


From linux at armlinux.org.uk  Mon Dec  1 06:49:56 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 1 Dec 2025 14:49:56 +0000
Subject: [PATCH RFC net-next 00/15] net: stmmac: rk: cleanups galore
Message-ID: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>

This is work in progress, cleaning up the excessively large Rockchip
glue driver somewhat. This series as it currently stands removes
approximately 200 lines from this file, while adding slightly to its
flexibility.

A brief overview of the changes:

- similar to previous commits, it seems the RGMII clock field follows
  a common pattern irrespective of the SoC.
- update rk3328 to use the ->id mechanism rather than guessing from
  the PHY interface mode and whether the PHY is integrated.
- switch to wm16 based masking, providing the lower-16 bits of the
  mask to indicate appropriate fields, and use this to construct the
  values to write to the registers.
- convert px30 to these methods.
- since many set_to_rmii() methods are now empty, add flags to indicate
  whether RMII / RGMII are supported.
- clear RGMII where the specific SoC's GMAC instance doesn't support
  this.

I've spent quite a while mulling over how to deal with these "wm16"
registers, none of the kernel bitfield macros (not even the
hw_bitfield.h macros) allow for what I present here, because the
masks are not constant.

One of the interesting things is that this appears to deal with RGMII
delays at the MAC end of the link, but there's no way to tell phylib
that's the case. I've not looked deeply into what is going on there,
but it is surprising that the driver insists that the delays (in
register values?) are provided, but then ignores them depending on the
exact RGMII mode selected.

One outstanding issue with these patches: RK3528_GMAC0_CLK_RMII_DIV2
remains, although I deleted its definition, so there's build errors
in this series. Before I do anything about that, I would like to hear
from the Rockchip guys whether it is necessary for rk3528_set_to_rmii()
to set the clock rate, given that rk_set_clk_tx_rate() will do this
when the link comes up. Does it matter whether it was set to 2.5MHz
(/ 20) or 25MHz (/ 2) when we switch to RMII mode?

 drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c | 968 ++++++++++---------------
 1 file changed, 382 insertions(+), 586 deletions(-)

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From rmk+kernel at armlinux.org.uk  Mon Dec  1 06:50:47 2025
From: rmk+kernel at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 01 Dec 2025 14:50:47 +0000
Subject: [PATCH RFC net-next 01/15] net: stmmac: rk: add GMAC_CLK_xx
 constants, simplify RGMII definitions
In-Reply-To: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
References: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
Message-ID: <E1vQ5El-0000000GNvU-2sXL@rmk-PC.armlinux.org.uk>

All the definitions of the RGMII related xxx_GMAC_CLK_xxx definitions
use the same field values to select the clock rate. Provide common
defintions for these field values, passing them in to a single macro
for each variant that generates the appropriate values for the speed
register.

No change to produced code on aarch64.

Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
---
 .../net/ethernet/stmicro/stmmac/dwmac-rk.c    | 108 ++++++++----------
 1 file changed, 45 insertions(+), 63 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
index 0a95f54e725e..3679081047e0 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -91,6 +91,10 @@ struct rk_priv_data {
 	struct regmap *php_grf;
 };
 
+#define GMAC_CLK_DIV1_125M		0
+#define GMAC_CLK_DIV50_2_5M		2
+#define GMAC_CLK_DIV5_25M		3
+
 static int rk_set_reg_speed(struct rk_priv_data *bsp_priv,
 			    const struct rk_reg_speed_data *rsd,
 			    unsigned int reg, phy_interface_t interface,
@@ -297,9 +301,7 @@ static const struct rk_gmac_ops px30_ops = {
 #define RK3128_GMAC_SPEED_100M         GRF_BIT(10)
 #define RK3128_GMAC_RMII_CLK_25M       GRF_BIT(11)
 #define RK3128_GMAC_RMII_CLK_2_5M      GRF_CLR_BIT(11)
-#define RK3128_GMAC_CLK_125M           GRF_FIELD_CONST(13, 12, 0)
-#define RK3128_GMAC_CLK_25M            GRF_FIELD_CONST(13, 12, 3)
-#define RK3128_GMAC_CLK_2_5M           GRF_FIELD_CONST(13, 12, 2)
+#define RK3128_GMAC_CLK(val)           GRF_FIELD_CONST(13, 12, val)
 #define RK3128_GMAC_RMII_MODE          GRF_BIT(14)
 #define RK3128_GMAC_RMII_MODE_CLR      GRF_CLR_BIT(14)
 
@@ -323,9 +325,9 @@ static void rk3128_set_to_rmii(struct rk_priv_data *bsp_priv)
 }
 
 static const struct rk_reg_speed_data rk3128_reg_speed_data = {
-	.rgmii_10 = RK3128_GMAC_CLK_2_5M,
-	.rgmii_100 = RK3128_GMAC_CLK_25M,
-	.rgmii_1000 = RK3128_GMAC_CLK_125M,
+	.rgmii_10 = RK3128_GMAC_CLK(GMAC_CLK_DIV50_2_5M),
+	.rgmii_100 = RK3128_GMAC_CLK(GMAC_CLK_DIV5_25M),
+	.rgmii_1000 = RK3128_GMAC_CLK(GMAC_CLK_DIV1_125M),
 	.rmii_10 = RK3128_GMAC_RMII_CLK_2_5M | RK3128_GMAC_SPEED_10M,
 	.rmii_100 = RK3128_GMAC_RMII_CLK_25M | RK3128_GMAC_SPEED_100M,
 };
@@ -360,9 +362,7 @@ static const struct rk_gmac_ops rk3128_ops = {
 #define RK3228_GMAC_SPEED_100M		GRF_BIT(2)
 #define RK3228_GMAC_RMII_CLK_25M	GRF_BIT(7)
 #define RK3228_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(7)
-#define RK3228_GMAC_CLK_125M		GRF_FIELD_CONST(9, 8, 0)
-#define RK3228_GMAC_CLK_25M		GRF_FIELD_CONST(9, 8, 3)
-#define RK3228_GMAC_CLK_2_5M		GRF_FIELD_CONST(9, 8, 2)
+#define RK3228_GMAC_CLK(val)		GRF_FIELD_CONST(9, 8, val)
 #define RK3228_GMAC_RMII_MODE		GRF_BIT(10)
 #define RK3228_GMAC_RMII_MODE_CLR	GRF_CLR_BIT(10)
 #define RK3228_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(0)
@@ -397,9 +397,9 @@ static void rk3228_set_to_rmii(struct rk_priv_data *bsp_priv)
 }
 
 static const struct rk_reg_speed_data rk3228_reg_speed_data = {
-	.rgmii_10 = RK3228_GMAC_CLK_2_5M,
-	.rgmii_100 = RK3228_GMAC_CLK_25M,
-	.rgmii_1000 = RK3228_GMAC_CLK_125M,
+	.rgmii_10 = RK3228_GMAC_CLK(GMAC_CLK_DIV50_2_5M),
+	.rgmii_100 = RK3228_GMAC_CLK(GMAC_CLK_DIV5_25M),
+	.rgmii_1000 = RK3228_GMAC_CLK(GMAC_CLK_DIV1_125M),
 	.rmii_10 = RK3228_GMAC_RMII_CLK_2_5M | RK3228_GMAC_SPEED_10M,
 	.rmii_100 = RK3228_GMAC_RMII_CLK_25M | RK3228_GMAC_SPEED_100M,
 };
@@ -438,9 +438,7 @@ static const struct rk_gmac_ops rk3228_ops = {
 #define RK3288_GMAC_SPEED_100M		GRF_BIT(10)
 #define RK3288_GMAC_RMII_CLK_25M	GRF_BIT(11)
 #define RK3288_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(11)
-#define RK3288_GMAC_CLK_125M		GRF_FIELD_CONST(13, 12, 0)
-#define RK3288_GMAC_CLK_25M		GRF_FIELD_CONST(13, 12, 3)
-#define RK3288_GMAC_CLK_2_5M		GRF_FIELD_CONST(13, 12, 2)
+#define RK3288_GMAC_CLK(val)		GRF_FIELD_CONST(13, 12, val)
 #define RK3288_GMAC_RMII_MODE		GRF_BIT(14)
 #define RK3288_GMAC_RMII_MODE_CLR	GRF_CLR_BIT(14)
 
@@ -472,9 +470,9 @@ static void rk3288_set_to_rmii(struct rk_priv_data *bsp_priv)
 }
 
 static const struct rk_reg_speed_data rk3288_reg_speed_data = {
-	.rgmii_10 = RK3288_GMAC_CLK_2_5M,
-	.rgmii_100 = RK3288_GMAC_CLK_25M,
-	.rgmii_1000 = RK3288_GMAC_CLK_125M,
+	.rgmii_10 = RK3288_GMAC_CLK(GMAC_CLK_DIV50_2_5M),
+	.rgmii_100 = RK3288_GMAC_CLK(GMAC_CLK_DIV5_25M),
+	.rgmii_1000 = RK3288_GMAC_CLK(GMAC_CLK_DIV1_125M),
 	.rmii_10 = RK3288_GMAC_RMII_CLK_2_5M | RK3288_GMAC_SPEED_10M,
 	.rmii_100 = RK3288_GMAC_RMII_CLK_25M | RK3288_GMAC_SPEED_100M,
 };
@@ -541,9 +539,7 @@ static const struct rk_gmac_ops rk3308_ops = {
 #define RK3328_GMAC_SPEED_100M		GRF_BIT(2)
 #define RK3328_GMAC_RMII_CLK_25M	GRF_BIT(7)
 #define RK3328_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(7)
-#define RK3328_GMAC_CLK_125M		GRF_FIELD_CONST(12, 11, 0)
-#define RK3328_GMAC_CLK_25M		GRF_FIELD_CONST(12, 11, 3)
-#define RK3328_GMAC_CLK_2_5M		GRF_FIELD_CONST(12, 11, 2)
+#define RK3328_GMAC_CLK(val)		GRF_FIELD_CONST(12, 11, val)
 #define RK3328_GMAC_RMII_MODE		GRF_BIT(9)
 #define RK3328_GMAC_RMII_MODE_CLR	GRF_CLR_BIT(9)
 #define RK3328_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(0)
@@ -579,9 +575,9 @@ static void rk3328_set_to_rmii(struct rk_priv_data *bsp_priv)
 }
 
 static const struct rk_reg_speed_data rk3328_reg_speed_data = {
-	.rgmii_10 = RK3328_GMAC_CLK_2_5M,
-	.rgmii_100 = RK3328_GMAC_CLK_25M,
-	.rgmii_1000 = RK3328_GMAC_CLK_125M,
+	.rgmii_10 = RK3328_GMAC_CLK(GMAC_CLK_DIV50_2_5M),
+	.rgmii_100 = RK3328_GMAC_CLK(GMAC_CLK_DIV5_25M),
+	.rgmii_1000 = RK3328_GMAC_CLK(GMAC_CLK_DIV1_125M),
 	.rmii_10 = RK3328_GMAC_RMII_CLK_2_5M | RK3328_GMAC_SPEED_10M,
 	.rmii_100 = RK3328_GMAC_RMII_CLK_25M | RK3328_GMAC_SPEED_100M,
 };
@@ -627,9 +623,7 @@ static const struct rk_gmac_ops rk3328_ops = {
 #define RK3366_GMAC_SPEED_100M		GRF_BIT(7)
 #define RK3366_GMAC_RMII_CLK_25M	GRF_BIT(3)
 #define RK3366_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(3)
-#define RK3366_GMAC_CLK_125M		GRF_FIELD_CONST(5, 4, 0)
-#define RK3366_GMAC_CLK_25M		GRF_FIELD_CONST(5, 4, 3)
-#define RK3366_GMAC_CLK_2_5M		GRF_FIELD_CONST(5, 4, 2)
+#define RK3366_GMAC_CLK(val)		GRF_FIELD_CONST(5, 4, val)
 #define RK3366_GMAC_RMII_MODE		GRF_BIT(6)
 #define RK3366_GMAC_RMII_MODE_CLR	GRF_CLR_BIT(6)
 
@@ -661,9 +655,9 @@ static void rk3366_set_to_rmii(struct rk_priv_data *bsp_priv)
 }
 
 static const struct rk_reg_speed_data rk3366_reg_speed_data = {
-	.rgmii_10 = RK3366_GMAC_CLK_2_5M,
-	.rgmii_100 = RK3366_GMAC_CLK_25M,
-	.rgmii_1000 = RK3366_GMAC_CLK_125M,
+	.rgmii_10 = RK3366_GMAC_CLK(GMAC_CLK_DIV50_2_5M),
+	.rgmii_100 = RK3366_GMAC_CLK(GMAC_CLK_DIV5_25M),
+	.rgmii_1000 = RK3366_GMAC_CLK(GMAC_CLK_DIV1_125M),
 	.rmii_10 = RK3366_GMAC_RMII_CLK_2_5M | RK3366_GMAC_SPEED_10M,
 	.rmii_100 = RK3366_GMAC_RMII_CLK_25M | RK3366_GMAC_SPEED_100M,
 };
@@ -692,9 +686,7 @@ static const struct rk_gmac_ops rk3366_ops = {
 #define RK3368_GMAC_SPEED_100M		GRF_BIT(7)
 #define RK3368_GMAC_RMII_CLK_25M	GRF_BIT(3)
 #define RK3368_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(3)
-#define RK3368_GMAC_CLK_125M		GRF_FIELD_CONST(5, 4, 0)
-#define RK3368_GMAC_CLK_25M		GRF_FIELD_CONST(5, 4, 3)
-#define RK3368_GMAC_CLK_2_5M		GRF_FIELD_CONST(5, 4, 2)
+#define RK3368_GMAC_CLK(val)		GRF_FIELD_CONST(5, 4, val)
 #define RK3368_GMAC_RMII_MODE		GRF_BIT(6)
 #define RK3368_GMAC_RMII_MODE_CLR	GRF_CLR_BIT(6)
 
@@ -726,9 +718,9 @@ static void rk3368_set_to_rmii(struct rk_priv_data *bsp_priv)
 }
 
 static const struct rk_reg_speed_data rk3368_reg_speed_data = {
-	.rgmii_10 = RK3368_GMAC_CLK_2_5M,
-	.rgmii_100 = RK3368_GMAC_CLK_25M,
-	.rgmii_1000 = RK3368_GMAC_CLK_125M,
+	.rgmii_10 = RK3368_GMAC_CLK(GMAC_CLK_DIV50_2_5M),
+	.rgmii_100 = RK3368_GMAC_CLK(GMAC_CLK_DIV5_25M),
+	.rgmii_1000 = RK3368_GMAC_CLK(GMAC_CLK_DIV1_125M),
 	.rmii_10 = RK3368_GMAC_RMII_CLK_2_5M | RK3368_GMAC_SPEED_10M,
 	.rmii_100 = RK3368_GMAC_RMII_CLK_25M | RK3368_GMAC_SPEED_100M,
 };
@@ -757,9 +749,7 @@ static const struct rk_gmac_ops rk3368_ops = {
 #define RK3399_GMAC_SPEED_100M		GRF_BIT(7)
 #define RK3399_GMAC_RMII_CLK_25M	GRF_BIT(3)
 #define RK3399_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(3)
-#define RK3399_GMAC_CLK_125M		GRF_FIELD_CONST(5, 4, 0)
-#define RK3399_GMAC_CLK_25M		GRF_FIELD_CONST(5, 4, 3)
-#define RK3399_GMAC_CLK_2_5M		GRF_FIELD_CONST(5, 4, 2)
+#define RK3399_GMAC_CLK(val)		GRF_FIELD_CONST(5, 4, val)
 #define RK3399_GMAC_RMII_MODE		GRF_BIT(6)
 #define RK3399_GMAC_RMII_MODE_CLR	GRF_CLR_BIT(6)
 
@@ -791,9 +781,9 @@ static void rk3399_set_to_rmii(struct rk_priv_data *bsp_priv)
 }
 
 static const struct rk_reg_speed_data rk3399_reg_speed_data = {
-	.rgmii_10 = RK3399_GMAC_CLK_2_5M,
-	.rgmii_100 = RK3399_GMAC_CLK_25M,
-	.rgmii_1000 = RK3399_GMAC_CLK_125M,
+	.rgmii_10 = RK3399_GMAC_CLK(GMAC_CLK_DIV50_2_5M),
+	.rgmii_100 = RK3399_GMAC_CLK(GMAC_CLK_DIV5_25M),
+	.rgmii_1000 = RK3399_GMAC_CLK(GMAC_CLK_DIV1_125M),
 	.rmii_10 = RK3399_GMAC_RMII_CLK_2_5M | RK3399_GMAC_SPEED_10M,
 	.rmii_100 = RK3399_GMAC_RMII_CLK_25M | RK3399_GMAC_SPEED_100M,
 };
@@ -900,9 +890,7 @@ static const struct rk_gmac_ops rk3506_ops = {
 #define RK3528_GMAC1_CLK_RMII_DIV2	GRF_BIT(10)
 #define RK3528_GMAC1_CLK_RMII_DIV20	GRF_CLR_BIT(10)
 
-#define RK3528_GMAC1_CLK_RGMII_DIV1	GRF_FIELD_CONST(11, 10, 0)
-#define RK3528_GMAC1_CLK_RGMII_DIV5	GRF_FIELD_CONST(11, 10, 3)
-#define RK3528_GMAC1_CLK_RGMII_DIV50	GRF_FIELD_CONST(11, 10, 2)
+#define RK3528_GMAC1_CLK_RGMII(val)	GRF_FIELD_CONST(11, 10, val)
 
 #define RK3528_GMAC0_CLK_RMII_GATE	GRF_BIT(2)
 #define RK3528_GMAC0_CLK_RMII_NOGATE	GRF_CLR_BIT(2)
@@ -940,9 +928,9 @@ static const struct rk_reg_speed_data rk3528_gmac0_reg_speed_data = {
 };
 
 static const struct rk_reg_speed_data rk3528_gmac1_reg_speed_data = {
-	.rgmii_10 = RK3528_GMAC1_CLK_RGMII_DIV50,
-	.rgmii_100 = RK3528_GMAC1_CLK_RGMII_DIV5,
-	.rgmii_1000 = RK3528_GMAC1_CLK_RGMII_DIV1,
+	.rgmii_10 = RK3528_GMAC1_CLK_RGMII(GMAC_CLK_DIV50_2_5M),
+	.rgmii_100 = RK3528_GMAC1_CLK_RGMII(GMAC_CLK_DIV5_25M),
+	.rgmii_1000 = RK3528_GMAC1_CLK_RGMII(GMAC_CLK_DIV1_125M),
 	.rmii_10 = RK3528_GMAC1_CLK_RMII_DIV20,
 	.rmii_100 = RK3528_GMAC1_CLK_RMII_DIV2,
 };
@@ -1094,9 +1082,7 @@ static const struct rk_gmac_ops rk3568_ops = {
 #define RK3576_GMAC_CLK_RMII_DIV2		GRF_BIT(5)
 #define RK3576_GMAC_CLK_RMII_DIV20		GRF_CLR_BIT(5)
 
-#define RK3576_GMAC_CLK_RGMII_DIV1		GRF_FIELD_CONST(6, 5, 0)
-#define RK3576_GMAC_CLK_RGMII_DIV5		GRF_FIELD_CONST(6, 5, 3)
-#define RK3576_GMAC_CLK_RGMII_DIV50		GRF_FIELD_CONST(6, 5, 2)
+#define RK3576_GMAC_CLK_RGMII(val)		GRF_FIELD_CONST(6, 5, val)
 
 #define RK3576_GMAC_CLK_RMII_GATE		GRF_BIT(4)
 #define RK3576_GMAC_CLK_RMII_NOGATE		GRF_CLR_BIT(4)
@@ -1140,9 +1126,9 @@ static void rk3576_set_to_rmii(struct rk_priv_data *bsp_priv)
 }
 
 static const struct rk_reg_speed_data rk3578_reg_speed_data = {
-	.rgmii_10 = RK3576_GMAC_CLK_RGMII_DIV50,
-	.rgmii_100 = RK3576_GMAC_CLK_RGMII_DIV5,
-	.rgmii_1000 = RK3576_GMAC_CLK_RGMII_DIV1,
+	.rgmii_10 = RK3576_GMAC_CLK_RGMII(GMAC_CLK_DIV50_2_5M),
+	.rgmii_100 = RK3576_GMAC_CLK_RGMII(GMAC_CLK_DIV5_25M),
+	.rgmii_1000 = RK3576_GMAC_CLK_RGMII(GMAC_CLK_DIV1_125M),
 	.rmii_10 = RK3576_GMAC_CLK_RMII_DIV20,
 	.rmii_100 = RK3576_GMAC_CLK_RMII_DIV2,
 };
@@ -1218,12 +1204,8 @@ static const struct rk_gmac_ops rk3576_ops = {
 #define RK3588_GMA_CLK_RMII_DIV2(id)		GRF_BIT(5 * (id) + 2)
 #define RK3588_GMA_CLK_RMII_DIV20(id)		GRF_CLR_BIT(5 * (id) + 2)
 
-#define RK3588_GMAC_CLK_RGMII_DIV1(id)		\
-	(GRF_FIELD_CONST(3, 2, 0) << ((id) * 5))
-#define RK3588_GMAC_CLK_RGMII_DIV5(id)		\
-	(GRF_FIELD_CONST(3, 2, 3) << ((id) * 5))
-#define RK3588_GMAC_CLK_RGMII_DIV50(id)		\
-	(GRF_FIELD_CONST(3, 2, 2) << ((id) * 5))
+#define RK3588_GMAC_CLK_RGMII(id, val)		\
+	(GRF_FIELD_CONST(3, 2, val) << ((id) * 5))
 
 #define RK3588_GMAC_CLK_RMII_GATE(id)		GRF_BIT(5 * (id) + 1)
 #define RK3588_GMAC_CLK_RMII_NOGATE(id)		GRF_CLR_BIT(5 * (id) + 1)
@@ -1270,17 +1252,17 @@ static int rk3588_set_gmac_speed(struct rk_priv_data *bsp_priv,
 		if (interface == PHY_INTERFACE_MODE_RMII)
 			val = RK3588_GMA_CLK_RMII_DIV20(id);
 		else
-			val = RK3588_GMAC_CLK_RGMII_DIV50(id);
+			val = RK3588_GMAC_CLK_RGMII(id, GMAC_CLK_DIV50_2_5M);
 		break;
 	case 100:
 		if (interface == PHY_INTERFACE_MODE_RMII)
 			val = RK3588_GMA_CLK_RMII_DIV2(id);
 		else
-			val = RK3588_GMAC_CLK_RGMII_DIV5(id);
+			val = RK3588_GMAC_CLK_RGMII(id, GMAC_CLK_DIV5_25M);
 		break;
 	case 1000:
 		if (interface != PHY_INTERFACE_MODE_RMII)
-			val = RK3588_GMAC_CLK_RGMII_DIV1(id);
+			val = RK3588_GMAC_CLK_RGMII(id, GMAC_CLK_DIV1_125M);
 		else
 			goto err;
 		break;
-- 
2.47.3



From rmk+kernel at armlinux.org.uk  Mon Dec  1 06:50:52 2025
From: rmk+kernel at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 01 Dec 2025 14:50:52 +0000
Subject: [PATCH RFC net-next 02/15] net: stmmac: rk: convert rk3328 to use
 bsp_priv->id
In-Reply-To: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
References: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
Message-ID: <E1vQ5Eq-0000000GNva-3OiR@rmk-PC.armlinux.org.uk>

rk3328 contains two GMAC instances - gmac2io and gmac2phy. The gmac2io
instance can be connected to an external PHY, whereas gmac2phy is
connected via RMII to an on-SoC integrated PHY. This configuration can
not be changed.

The driver tests for the gmac2phy instance by checking
bsp_priv->integrated_phy (determined from the PHY's phy-is-integrated
property) and sometimes that the interface mode is RMII. This works
because the rk3328.dtsi has:

        gmac2phy: ethernet at ff550000 {
                compatible = "rockchip,rk3328-gmac";
                phy-mode = "rmii";

                mdio {
                        phy: ethernet-phy at 0 {
                                phy-is-integrated;
                        };
                };
        };

The driver contains a mechanism to look up the MMIO address in a table
to determine bsp_priv->id, which is used for every other Rockchip
device. Switch rk3328 to use this mechanism to determine bsp_priv->id
and use that to select which GRF register is used for configuration.

Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
---
 drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
index 3679081047e0..f9bc9b145ff4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -566,8 +566,7 @@ static void rk3328_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
 	unsigned int reg;
 
-	reg = bsp_priv->integrated_phy ? RK3328_GRF_MAC_CON2 :
-		  RK3328_GRF_MAC_CON1;
+	reg = bsp_priv->id ? RK3328_GRF_MAC_CON2 : RK3328_GRF_MAC_CON1;
 
 	regmap_write(bsp_priv->grf, reg,
 		     RK3328_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII) |
@@ -587,10 +586,7 @@ static int rk3328_set_speed(struct rk_priv_data *bsp_priv,
 {
 	unsigned int reg;
 
-	if (interface == PHY_INTERFACE_MODE_RMII && bsp_priv->integrated_phy)
-		reg = RK3328_GRF_MAC_CON2;
-	else
-		reg = RK3328_GRF_MAC_CON1;
+	reg = bsp_priv->id ? RK3328_GRF_MAC_CON2 : RK3328_GRF_MAC_CON1;
 
 	return rk_set_reg_speed(bsp_priv, &rk3328_reg_speed_data, reg,
 				interface, speed);
@@ -610,6 +606,13 @@ static const struct rk_gmac_ops rk3328_ops = {
 	.set_speed = rk3328_set_speed,
 	.integrated_phy_powerup = rk3328_integrated_phy_powerup,
 	.integrated_phy_powerdown = rk_gmac_integrated_ephy_powerdown,
+
+	.regs_valid = true,
+	.regs = {
+		0xff540000, /* gmac2io */
+		0xff550000, /* gmac2phy */
+		0, /* sentinel */
+	},
 };
 
 #define RK3366_GRF_SOC_CON6	0x0418
-- 
2.47.3



From rmk+kernel at armlinux.org.uk  Mon Dec  1 06:50:57 2025
From: rmk+kernel at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 01 Dec 2025 14:50:57 +0000
Subject: [PATCH RFC net-next 03/15] net: stmmac: rk: add SoC specific ->init()
 method
In-Reply-To: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
References: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
Message-ID: <E1vQ5Ev-0000000GNvg-3uGh@rmk-PC.armlinux.org.uk>

Add a SoC specific init method.

Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
---
 drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
index f9bc9b145ff4..e9f531d6c22a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -35,6 +35,7 @@ struct rk_reg_speed_data {
 };
 
 struct rk_gmac_ops {
+	int (*init)(struct rk_priv_data *bsp_priv);
 	void (*set_to_rgmii)(struct rk_priv_data *bsp_priv,
 			     int tx_delay, int rx_delay);
 	void (*set_to_rmii)(struct rk_priv_data *bsp_priv);
@@ -1613,6 +1614,14 @@ static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,
 
 	bsp_priv->dev = dev;
 
+	if (ops->init) {
+		ret = ops->init(bsp_priv);
+		if (ret) {
+			dev_err_probe(dev, ret, "failed to init BSP\n");
+			return ERR_PTR(ret);
+		}
+	}
+
 	return bsp_priv;
 }
 
-- 
2.47.3



From rmk+kernel at armlinux.org.uk  Mon Dec  1 06:51:03 2025
From: rmk+kernel at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 01 Dec 2025 14:51:03 +0000
Subject: [PATCH RFC net-next 04/15] net: stmmac: rk: convert to mask-based
 interface mode configuration
In-Reply-To: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
References: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
Message-ID: <E1vQ5F1-0000000GNvm-0EON@rmk-PC.armlinux.org.uk>

Most of the Rockchip implementations use the phy_intf_sel values for
interface mode configuration, but the register and field within that
register vary between each SoC. They also have a RMII mode bit, which
is in the same register but a different bit position.

Rather than having each and every Rockchip implementation cope with
this using code, add struct members to specify the regmap register
offset, and the bitfield masks for these two parameters.

Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
---
 .../net/ethernet/stmicro/stmmac/dwmac-rk.c    | 281 +++++++++++-------
 1 file changed, 171 insertions(+), 110 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
index e9f531d6c22a..369792b62c5e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -45,6 +45,11 @@ struct rk_gmac_ops {
 				    bool enable);
 	void (*integrated_phy_powerup)(struct rk_priv_data *bsp_priv);
 	void (*integrated_phy_powerdown)(struct rk_priv_data *bsp_priv);
+
+	u16 phy_intf_sel_grf_reg;
+	u16 phy_intf_sel_mask;
+	u16 rmii_mode_mask;
+
 	bool php_grf_required;
 	bool regs_valid;
 	u32 regs[];
@@ -90,12 +95,37 @@ struct rk_priv_data {
 
 	struct regmap *grf;
 	struct regmap *php_grf;
+
+	u16 phy_intf_sel_grf_reg;
+	u16 phy_intf_sel_mask;
+	u16 rmii_mode_mask;
 };
 
 #define GMAC_CLK_DIV1_125M		0
 #define GMAC_CLK_DIV50_2_5M		2
 #define GMAC_CLK_DIV5_25M		3
 
+static int rk_get_phy_intf_sel(phy_interface_t interface)
+{
+	int ret = stmmac_get_phy_intf_sel(interface);
+
+	/* Only RGMII and RMII are supported */
+	if (ret != PHY_INTF_SEL_RGMII && ret != PHY_INTF_SEL_RMII)
+		ret = -EINVAL;
+
+	return ret;
+}
+
+static u32 rk_encode_wm16(u16 val, u16 mask)
+{
+	u32 reg_val = mask << 16;
+
+	if (mask)
+		reg_val |= mask & (val << (ffs(mask) - 1));
+
+	return reg_val;
+}
+
 static int rk_set_reg_speed(struct rk_priv_data *bsp_priv,
 			    const struct rk_reg_speed_data *rsd,
 			    unsigned int reg, phy_interface_t interface,
@@ -239,14 +269,11 @@ static void rk_gmac_integrated_fephy_powerdown(struct rk_priv_data *priv,
 #define PX30_GRF_GMAC_CON1		0x0904
 
 /* PX30_GRF_GMAC_CON1 */
-#define PX30_GMAC_PHY_INTF_SEL(val)	GRF_FIELD(6, 4, val)
 #define PX30_GMAC_SPEED_10M		GRF_CLR_BIT(2)
 #define PX30_GMAC_SPEED_100M		GRF_BIT(2)
 
 static void px30_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
-	regmap_write(bsp_priv->grf, PX30_GRF_GMAC_CON1,
-		     PX30_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII));
 }
 
 static int px30_set_speed(struct rk_priv_data *bsp_priv,
@@ -281,6 +308,9 @@ static int px30_set_speed(struct rk_priv_data *bsp_priv,
 static const struct rk_gmac_ops px30_ops = {
 	.set_to_rmii = px30_set_to_rmii,
 	.set_speed = px30_set_speed,
+
+	.phy_intf_sel_grf_reg = PX30_GRF_GMAC_CON1,
+	.phy_intf_sel_mask = GENMASK_U16(6, 4),
 };
 
 #define RK3128_GRF_MAC_CON0	0x0168
@@ -295,7 +325,6 @@ static const struct rk_gmac_ops px30_ops = {
 #define RK3128_GMAC_CLK_TX_DL_CFG(val) GRF_FIELD(6, 0, val)
 
 /* RK3128_GRF_MAC_CON1 */
-#define RK3128_GMAC_PHY_INTF_SEL(val)  GRF_FIELD(8, 6, val)
 #define RK3128_GMAC_FLOW_CTRL          GRF_BIT(9)
 #define RK3128_GMAC_FLOW_CTRL_CLR      GRF_CLR_BIT(9)
 #define RK3128_GMAC_SPEED_10M          GRF_CLR_BIT(10)
@@ -303,15 +332,10 @@ static const struct rk_gmac_ops px30_ops = {
 #define RK3128_GMAC_RMII_CLK_25M       GRF_BIT(11)
 #define RK3128_GMAC_RMII_CLK_2_5M      GRF_CLR_BIT(11)
 #define RK3128_GMAC_CLK(val)           GRF_FIELD_CONST(13, 12, val)
-#define RK3128_GMAC_RMII_MODE          GRF_BIT(14)
-#define RK3128_GMAC_RMII_MODE_CLR      GRF_CLR_BIT(14)
 
 static void rk3128_set_to_rgmii(struct rk_priv_data *bsp_priv,
 				int tx_delay, int rx_delay)
 {
-	regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON1,
-		     RK3128_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) |
-		     RK3128_GMAC_RMII_MODE_CLR);
 	regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON0,
 		     DELAY_ENABLE(RK3128, tx_delay, rx_delay) |
 		     RK3128_GMAC_CLK_RX_DL_CFG(rx_delay) |
@@ -320,9 +344,6 @@ static void rk3128_set_to_rgmii(struct rk_priv_data *bsp_priv,
 
 static void rk3128_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
-	regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON1,
-		     RK3128_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII) |
-		     RK3128_GMAC_RMII_MODE);
 }
 
 static const struct rk_reg_speed_data rk3128_reg_speed_data = {
@@ -344,6 +365,10 @@ static const struct rk_gmac_ops rk3128_ops = {
 	.set_to_rgmii = rk3128_set_to_rgmii,
 	.set_to_rmii = rk3128_set_to_rmii,
 	.set_speed = rk3128_set_speed,
+
+	.phy_intf_sel_grf_reg = RK3128_GRF_MAC_CON1,
+	.phy_intf_sel_mask = GENMASK_U16(8, 6),
+	.rmii_mode_mask = BIT_U16(14),
 };
 
 #define RK3228_GRF_MAC_CON0	0x0900
@@ -356,7 +381,6 @@ static const struct rk_gmac_ops rk3128_ops = {
 #define RK3228_GMAC_CLK_TX_DL_CFG(val)	GRF_FIELD(6, 0, val)
 
 /* RK3228_GRF_MAC_CON1 */
-#define RK3228_GMAC_PHY_INTF_SEL(val)	GRF_FIELD(6, 4, val)
 #define RK3228_GMAC_FLOW_CTRL		GRF_BIT(3)
 #define RK3228_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(3)
 #define RK3228_GMAC_SPEED_10M		GRF_CLR_BIT(2)
@@ -364,8 +388,6 @@ static const struct rk_gmac_ops rk3128_ops = {
 #define RK3228_GMAC_RMII_CLK_25M	GRF_BIT(7)
 #define RK3228_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(7)
 #define RK3228_GMAC_CLK(val)		GRF_FIELD_CONST(9, 8, val)
-#define RK3228_GMAC_RMII_MODE		GRF_BIT(10)
-#define RK3228_GMAC_RMII_MODE_CLR	GRF_CLR_BIT(10)
 #define RK3228_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(0)
 #define RK3228_GMAC_TXCLK_DLY_DISABLE	GRF_CLR_BIT(0)
 #define RK3228_GMAC_RXCLK_DLY_ENABLE	GRF_BIT(1)
@@ -378,8 +400,6 @@ static void rk3228_set_to_rgmii(struct rk_priv_data *bsp_priv,
 				int tx_delay, int rx_delay)
 {
 	regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1,
-		     RK3228_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) |
-		     RK3228_GMAC_RMII_MODE_CLR |
 		     DELAY_ENABLE(RK3228, tx_delay, rx_delay));
 
 	regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON0,
@@ -389,10 +409,6 @@ static void rk3228_set_to_rgmii(struct rk_priv_data *bsp_priv,
 
 static void rk3228_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
-	regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1,
-		     RK3228_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII) |
-		     RK3228_GMAC_RMII_MODE);
-
 	/* set MAC to RMII mode */
 	regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1, GRF_BIT(11));
 }
@@ -426,13 +442,17 @@ static const struct rk_gmac_ops rk3228_ops = {
 	.set_speed = rk3228_set_speed,
 	.integrated_phy_powerup = rk3228_integrated_phy_powerup,
 	.integrated_phy_powerdown = rk_gmac_integrated_ephy_powerdown,
+
+	.phy_intf_sel_grf_reg = RK3228_GRF_MAC_CON1,
+	.phy_intf_sel_mask = GENMASK_U16(6, 4),
+	.rmii_mode_mask = BIT_U16(10),
+
 };
 
 #define RK3288_GRF_SOC_CON1	0x0248
 #define RK3288_GRF_SOC_CON3	0x0250
 
 /*RK3288_GRF_SOC_CON1*/
-#define RK3288_GMAC_PHY_INTF_SEL(val)	GRF_FIELD(8, 6, val)
 #define RK3288_GMAC_FLOW_CTRL		GRF_BIT(9)
 #define RK3288_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(9)
 #define RK3288_GMAC_SPEED_10M		GRF_CLR_BIT(10)
@@ -440,8 +460,6 @@ static const struct rk_gmac_ops rk3228_ops = {
 #define RK3288_GMAC_RMII_CLK_25M	GRF_BIT(11)
 #define RK3288_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(11)
 #define RK3288_GMAC_CLK(val)		GRF_FIELD_CONST(13, 12, val)
-#define RK3288_GMAC_RMII_MODE		GRF_BIT(14)
-#define RK3288_GMAC_RMII_MODE_CLR	GRF_CLR_BIT(14)
 
 /*RK3288_GRF_SOC_CON3*/
 #define RK3288_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(14)
@@ -454,9 +472,6 @@ static const struct rk_gmac_ops rk3228_ops = {
 static void rk3288_set_to_rgmii(struct rk_priv_data *bsp_priv,
 				int tx_delay, int rx_delay)
 {
-	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
-		     RK3288_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) |
-		     RK3288_GMAC_RMII_MODE_CLR);
 	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3,
 		     DELAY_ENABLE(RK3288, tx_delay, rx_delay) |
 		     RK3288_GMAC_CLK_RX_DL_CFG(rx_delay) |
@@ -465,9 +480,6 @@ static void rk3288_set_to_rgmii(struct rk_priv_data *bsp_priv,
 
 static void rk3288_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
-	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
-		     RK3288_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII) |
-		     RK3288_GMAC_RMII_MODE);
 }
 
 static const struct rk_reg_speed_data rk3288_reg_speed_data = {
@@ -489,12 +501,15 @@ static const struct rk_gmac_ops rk3288_ops = {
 	.set_to_rgmii = rk3288_set_to_rgmii,
 	.set_to_rmii = rk3288_set_to_rmii,
 	.set_speed = rk3288_set_speed,
+
+	.phy_intf_sel_grf_reg = RK3288_GRF_SOC_CON1,
+	.phy_intf_sel_mask = GENMASK_U16(8, 6),
+	.rmii_mode_mask = BIT_U16(14),
 };
 
 #define RK3308_GRF_MAC_CON0		0x04a0
 
 /* RK3308_GRF_MAC_CON0 */
-#define RK3308_GMAC_PHY_INTF_SEL(val)	GRF_FIELD(4, 2, val)
 #define RK3308_GMAC_FLOW_CTRL		GRF_BIT(3)
 #define RK3308_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(3)
 #define RK3308_GMAC_SPEED_10M		GRF_CLR_BIT(0)
@@ -502,8 +517,6 @@ static const struct rk_gmac_ops rk3288_ops = {
 
 static void rk3308_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
-	regmap_write(bsp_priv->grf, RK3308_GRF_MAC_CON0,
-		     RK3308_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII));
 }
 
 static const struct rk_reg_speed_data rk3308_reg_speed_data = {
@@ -521,6 +534,9 @@ static int rk3308_set_speed(struct rk_priv_data *bsp_priv,
 static const struct rk_gmac_ops rk3308_ops = {
 	.set_to_rmii = rk3308_set_to_rmii,
 	.set_speed = rk3308_set_speed,
+
+	.phy_intf_sel_grf_reg = RK3308_GRF_MAC_CON0,
+	.phy_intf_sel_mask = GENMASK_U16(4, 2),
 };
 
 #define RK3328_GRF_MAC_CON0	0x0900
@@ -533,7 +549,6 @@ static const struct rk_gmac_ops rk3308_ops = {
 #define RK3328_GMAC_CLK_TX_DL_CFG(val)	GRF_FIELD(6, 0, val)
 
 /* RK3328_GRF_MAC_CON1 */
-#define RK3328_GMAC_PHY_INTF_SEL(val)	GRF_FIELD(6, 4, val)
 #define RK3328_GMAC_FLOW_CTRL		GRF_BIT(3)
 #define RK3328_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(3)
 #define RK3328_GMAC_SPEED_10M		GRF_CLR_BIT(2)
@@ -541,20 +556,32 @@ static const struct rk_gmac_ops rk3308_ops = {
 #define RK3328_GMAC_RMII_CLK_25M	GRF_BIT(7)
 #define RK3328_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(7)
 #define RK3328_GMAC_CLK(val)		GRF_FIELD_CONST(12, 11, val)
-#define RK3328_GMAC_RMII_MODE		GRF_BIT(9)
-#define RK3328_GMAC_RMII_MODE_CLR	GRF_CLR_BIT(9)
 #define RK3328_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(0)
 #define RK3328_GMAC_RXCLK_DLY_ENABLE	GRF_BIT(1)
 
 /* RK3328_GRF_MACPHY_CON1 */
 #define RK3328_MACPHY_RMII_MODE		GRF_BIT(9)
 
+static int rk3328_init(struct rk_priv_data *bsp_priv)
+{
+	switch (bsp_priv->id) {
+	case 0: /* gmac2io */
+		bsp_priv->phy_intf_sel_grf_reg = RK3328_GRF_MAC_CON1;
+		return 0;
+
+	case 1: /* gmac2phy */
+		bsp_priv->phy_intf_sel_grf_reg = RK3328_GRF_MAC_CON2;
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
 static void rk3328_set_to_rgmii(struct rk_priv_data *bsp_priv,
 				int tx_delay, int rx_delay)
 {
 	regmap_write(bsp_priv->grf, RK3328_GRF_MAC_CON1,
-		     RK3328_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) |
-		     RK3328_GMAC_RMII_MODE_CLR |
 		     RK3328_GMAC_RXCLK_DLY_ENABLE |
 		     RK3328_GMAC_TXCLK_DLY_ENABLE);
 
@@ -565,13 +592,6 @@ static void rk3328_set_to_rgmii(struct rk_priv_data *bsp_priv,
 
 static void rk3328_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
-	unsigned int reg;
-
-	reg = bsp_priv->id ? RK3328_GRF_MAC_CON2 : RK3328_GRF_MAC_CON1;
-
-	regmap_write(bsp_priv->grf, reg,
-		     RK3328_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII) |
-		     RK3328_GMAC_RMII_MODE);
 }
 
 static const struct rk_reg_speed_data rk3328_reg_speed_data = {
@@ -602,12 +622,16 @@ static void rk3328_integrated_phy_powerup(struct rk_priv_data *priv)
 }
 
 static const struct rk_gmac_ops rk3328_ops = {
+	.init = rk3328_init,
 	.set_to_rgmii = rk3328_set_to_rgmii,
 	.set_to_rmii = rk3328_set_to_rmii,
 	.set_speed = rk3328_set_speed,
 	.integrated_phy_powerup = rk3328_integrated_phy_powerup,
 	.integrated_phy_powerdown = rk_gmac_integrated_ephy_powerdown,
 
+	.phy_intf_sel_mask = GENMASK_U16(6, 4),
+	.rmii_mode_mask = BIT_U16(9),
+
 	.regs_valid = true,
 	.regs = {
 		0xff540000, /* gmac2io */
@@ -620,7 +644,6 @@ static const struct rk_gmac_ops rk3328_ops = {
 #define RK3366_GRF_SOC_CON7	0x041c
 
 /* RK3366_GRF_SOC_CON6 */
-#define RK3366_GMAC_PHY_INTF_SEL(val)	GRF_FIELD(11, 9, val)
 #define RK3366_GMAC_FLOW_CTRL		GRF_BIT(8)
 #define RK3366_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(8)
 #define RK3366_GMAC_SPEED_10M		GRF_CLR_BIT(7)
@@ -628,8 +651,6 @@ static const struct rk_gmac_ops rk3328_ops = {
 #define RK3366_GMAC_RMII_CLK_25M	GRF_BIT(3)
 #define RK3366_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(3)
 #define RK3366_GMAC_CLK(val)		GRF_FIELD_CONST(5, 4, val)
-#define RK3366_GMAC_RMII_MODE		GRF_BIT(6)
-#define RK3366_GMAC_RMII_MODE_CLR	GRF_CLR_BIT(6)
 
 /* RK3366_GRF_SOC_CON7 */
 #define RK3366_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(7)
@@ -642,9 +663,6 @@ static const struct rk_gmac_ops rk3328_ops = {
 static void rk3366_set_to_rgmii(struct rk_priv_data *bsp_priv,
 				int tx_delay, int rx_delay)
 {
-	regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON6,
-		     RK3366_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) |
-		     RK3366_GMAC_RMII_MODE_CLR);
 	regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON7,
 		     DELAY_ENABLE(RK3366, tx_delay, rx_delay) |
 		     RK3366_GMAC_CLK_RX_DL_CFG(rx_delay) |
@@ -653,9 +671,6 @@ static void rk3366_set_to_rgmii(struct rk_priv_data *bsp_priv,
 
 static void rk3366_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
-	regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON6,
-		     RK3366_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII) |
-		     RK3366_GMAC_RMII_MODE);
 }
 
 static const struct rk_reg_speed_data rk3366_reg_speed_data = {
@@ -677,13 +692,16 @@ static const struct rk_gmac_ops rk3366_ops = {
 	.set_to_rgmii = rk3366_set_to_rgmii,
 	.set_to_rmii = rk3366_set_to_rmii,
 	.set_speed = rk3366_set_speed,
+
+	.phy_intf_sel_grf_reg = RK3366_GRF_SOC_CON6,
+	.phy_intf_sel_mask = GENMASK_U16(11, 9),
+	.rmii_mode_mask = BIT_U16(6),
 };
 
 #define RK3368_GRF_SOC_CON15	0x043c
 #define RK3368_GRF_SOC_CON16	0x0440
 
 /* RK3368_GRF_SOC_CON15 */
-#define RK3368_GMAC_PHY_INTF_SEL(val)	GRF_FIELD(11, 9, val)
 #define RK3368_GMAC_FLOW_CTRL		GRF_BIT(8)
 #define RK3368_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(8)
 #define RK3368_GMAC_SPEED_10M		GRF_CLR_BIT(7)
@@ -691,8 +709,6 @@ static const struct rk_gmac_ops rk3366_ops = {
 #define RK3368_GMAC_RMII_CLK_25M	GRF_BIT(3)
 #define RK3368_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(3)
 #define RK3368_GMAC_CLK(val)		GRF_FIELD_CONST(5, 4, val)
-#define RK3368_GMAC_RMII_MODE		GRF_BIT(6)
-#define RK3368_GMAC_RMII_MODE_CLR	GRF_CLR_BIT(6)
 
 /* RK3368_GRF_SOC_CON16 */
 #define RK3368_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(7)
@@ -705,9 +721,6 @@ static const struct rk_gmac_ops rk3366_ops = {
 static void rk3368_set_to_rgmii(struct rk_priv_data *bsp_priv,
 				int tx_delay, int rx_delay)
 {
-	regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
-		     RK3368_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) |
-		     RK3368_GMAC_RMII_MODE_CLR);
 	regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON16,
 		     DELAY_ENABLE(RK3368, tx_delay, rx_delay) |
 		     RK3368_GMAC_CLK_RX_DL_CFG(rx_delay) |
@@ -716,9 +729,6 @@ static void rk3368_set_to_rgmii(struct rk_priv_data *bsp_priv,
 
 static void rk3368_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
-	regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
-		     RK3368_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII) |
-		     RK3368_GMAC_RMII_MODE);
 }
 
 static const struct rk_reg_speed_data rk3368_reg_speed_data = {
@@ -740,13 +750,16 @@ static const struct rk_gmac_ops rk3368_ops = {
 	.set_to_rgmii = rk3368_set_to_rgmii,
 	.set_to_rmii = rk3368_set_to_rmii,
 	.set_speed = rk3368_set_speed,
+
+	.phy_intf_sel_grf_reg = RK3368_GRF_SOC_CON15,
+	.phy_intf_sel_mask = GENMASK_U16(11, 9),
+	.rmii_mode_mask = BIT_U16(6),
 };
 
 #define RK3399_GRF_SOC_CON5	0xc214
 #define RK3399_GRF_SOC_CON6	0xc218
 
 /* RK3399_GRF_SOC_CON5 */
-#define RK3399_GMAC_PHY_INTF_SEL(val)	GRF_FIELD(11, 9, val)
 #define RK3399_GMAC_FLOW_CTRL		GRF_BIT(8)
 #define RK3399_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(8)
 #define RK3399_GMAC_SPEED_10M		GRF_CLR_BIT(7)
@@ -754,8 +767,6 @@ static const struct rk_gmac_ops rk3368_ops = {
 #define RK3399_GMAC_RMII_CLK_25M	GRF_BIT(3)
 #define RK3399_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(3)
 #define RK3399_GMAC_CLK(val)		GRF_FIELD_CONST(5, 4, val)
-#define RK3399_GMAC_RMII_MODE		GRF_BIT(6)
-#define RK3399_GMAC_RMII_MODE_CLR	GRF_CLR_BIT(6)
 
 /* RK3399_GRF_SOC_CON6 */
 #define RK3399_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(7)
@@ -768,9 +779,6 @@ static const struct rk_gmac_ops rk3368_ops = {
 static void rk3399_set_to_rgmii(struct rk_priv_data *bsp_priv,
 				int tx_delay, int rx_delay)
 {
-	regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON5,
-		     RK3399_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) |
-		     RK3399_GMAC_RMII_MODE_CLR);
 	regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON6,
 		     DELAY_ENABLE(RK3399, tx_delay, rx_delay) |
 		     RK3399_GMAC_CLK_RX_DL_CFG(rx_delay) |
@@ -779,9 +787,6 @@ static void rk3399_set_to_rgmii(struct rk_priv_data *bsp_priv,
 
 static void rk3399_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
-	regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON5,
-		     RK3399_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII) |
-		     RK3399_GMAC_RMII_MODE);
 }
 
 static const struct rk_reg_speed_data rk3399_reg_speed_data = {
@@ -803,6 +808,10 @@ static const struct rk_gmac_ops rk3399_ops = {
 	.set_to_rgmii = rk3399_set_to_rgmii,
 	.set_to_rmii = rk3399_set_to_rmii,
 	.set_speed = rk3399_set_speed,
+
+	.phy_intf_sel_grf_reg = RK3399_GRF_SOC_CON5,
+	.phy_intf_sel_mask = GENMASK_U16(11, 9),
+	.rmii_mode_mask = BIT_U16(6),
 };
 
 #define RK3506_GRF_SOC_CON8		0x0020
@@ -1005,7 +1014,6 @@ static const struct rk_gmac_ops rk3528_ops = {
 #define RK3568_GRF_GMAC1_CON1		0x038c
 
 /* RK3568_GRF_GMAC0_CON1 && RK3568_GRF_GMAC1_CON1 */
-#define RK3568_GMAC_PHY_INTF_SEL(val)	GRF_FIELD(6, 4, val)
 #define RK3568_GMAC_FLOW_CTRL			GRF_BIT(3)
 #define RK3568_GMAC_FLOW_CTRL_CLR		GRF_CLR_BIT(3)
 #define RK3568_GMAC_RXCLK_DLY_ENABLE		GRF_BIT(1)
@@ -1017,6 +1025,22 @@ static const struct rk_gmac_ops rk3528_ops = {
 #define RK3568_GMAC_CLK_RX_DL_CFG(val)	GRF_FIELD(14, 8, val)
 #define RK3568_GMAC_CLK_TX_DL_CFG(val)	GRF_FIELD(6, 0, val)
 
+static int rk3568_init(struct rk_priv_data *bsp_priv)
+{
+	switch (bsp_priv->id) {
+	case 0:
+		bsp_priv->phy_intf_sel_grf_reg = RK3568_GRF_GMAC0_CON1;
+		return 0;
+
+	case 1:
+		bsp_priv->phy_intf_sel_grf_reg = RK3568_GRF_GMAC1_CON1;
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
 static void rk3568_set_to_rgmii(struct rk_priv_data *bsp_priv,
 				int tx_delay, int rx_delay)
 {
@@ -1032,25 +1056,22 @@ static void rk3568_set_to_rgmii(struct rk_priv_data *bsp_priv,
 		     RK3568_GMAC_CLK_TX_DL_CFG(tx_delay));
 
 	regmap_write(bsp_priv->grf, con1,
-		     RK3568_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) |
 		     RK3568_GMAC_RXCLK_DLY_ENABLE |
 		     RK3568_GMAC_TXCLK_DLY_ENABLE);
 }
 
 static void rk3568_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
-	u32 con1;
-
-	con1 = (bsp_priv->id == 1) ? RK3568_GRF_GMAC1_CON1 :
-				     RK3568_GRF_GMAC0_CON1;
-	regmap_write(bsp_priv->grf, con1,
-		     RK3568_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII));
 }
 
 static const struct rk_gmac_ops rk3568_ops = {
+	.init = rk3568_init,
 	.set_to_rgmii = rk3568_set_to_rgmii,
 	.set_to_rmii = rk3568_set_to_rmii,
 	.set_speed = rk_set_clk_mac_speed,
+
+	.phy_intf_sel_mask = GENMASK_U16(6, 4),
+
 	.regs_valid = true,
 	.regs = {
 		0xfe2a0000, /* gmac0 */
@@ -1077,9 +1098,6 @@ static const struct rk_gmac_ops rk3568_ops = {
 #define RK3576_GRF_GMAC_CON0			0X0020
 #define RK3576_GRF_GMAC_CON1			0X0024
 
-#define RK3576_GMAC_RMII_MODE			GRF_BIT(3)
-#define RK3576_GMAC_RGMII_MODE			GRF_CLR_BIT(3)
-
 #define RK3576_GMAC_CLK_SELECT_IO		GRF_BIT(7)
 #define RK3576_GMAC_CLK_SELECT_CRU		GRF_CLR_BIT(7)
 
@@ -1091,16 +1109,27 @@ static const struct rk_gmac_ops rk3568_ops = {
 #define RK3576_GMAC_CLK_RMII_GATE		GRF_BIT(4)
 #define RK3576_GMAC_CLK_RMII_NOGATE		GRF_CLR_BIT(4)
 
+static int rk3576_init(struct rk_priv_data *bsp_priv)
+{
+	switch (bsp_priv->id) {
+	case 0:
+		bsp_priv->phy_intf_sel_grf_reg = RK3576_GRF_GMAC_CON0;
+		return 0;
+
+	case 1:
+		bsp_priv->phy_intf_sel_grf_reg = RK3576_GRF_GMAC_CON1;
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
 static void rk3576_set_to_rgmii(struct rk_priv_data *bsp_priv,
 				int tx_delay, int rx_delay)
 {
 	unsigned int offset_con;
 
-	offset_con = bsp_priv->id == 1 ? RK3576_GRF_GMAC_CON1 :
-					 RK3576_GRF_GMAC_CON0;
-
-	regmap_write(bsp_priv->grf, offset_con, RK3576_GMAC_RGMII_MODE);
-
 	offset_con = bsp_priv->id == 1 ? RK3576_VCCIO0_1_3_IOC_CON4 :
 					 RK3576_VCCIO0_1_3_IOC_CON2;
 
@@ -1121,12 +1150,6 @@ static void rk3576_set_to_rgmii(struct rk_priv_data *bsp_priv,
 
 static void rk3576_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
-	unsigned int offset_con;
-
-	offset_con = bsp_priv->id == 1 ? RK3576_GRF_GMAC_CON1 :
-					 RK3576_GRF_GMAC_CON0;
-
-	regmap_write(bsp_priv->grf, offset_con, RK3576_GMAC_RMII_MODE);
 }
 
 static const struct rk_reg_speed_data rk3578_reg_speed_data = {
@@ -1166,10 +1189,14 @@ static void rk3576_set_clock_selection(struct rk_priv_data *bsp_priv, bool input
 }
 
 static const struct rk_gmac_ops rk3576_ops = {
+	.init = rk3576_init,
 	.set_to_rgmii = rk3576_set_to_rgmii,
 	.set_to_rmii = rk3576_set_to_rmii,
 	.set_speed = rk3576_set_gmac_speed,
 	.set_clock_selection = rk3576_set_clock_selection,
+
+	.rmii_mode_mask = BIT_U16(3),
+
 	.php_grf_required = true,
 	.regs_valid = true,
 	.regs = {
@@ -1196,9 +1223,6 @@ static const struct rk_gmac_ops rk3576_ops = {
 #define RK3588_GRF_GMAC_CON0			0X0008
 #define RK3588_GRF_CLK_CON1			0X0070
 
-#define RK3588_GMAC_PHY_INTF_SEL(id, val)	\
-	(GRF_FIELD(5, 3, val) << ((id) * 6))
-
 #define RK3588_GMAC_CLK_RMII_MODE(id)		GRF_BIT(5 * (id))
 #define RK3588_GMAC_CLK_RGMII_MODE(id)		GRF_CLR_BIT(5 * (id))
 
@@ -1214,6 +1238,22 @@ static const struct rk_gmac_ops rk3576_ops = {
 #define RK3588_GMAC_CLK_RMII_GATE(id)		GRF_BIT(5 * (id) + 1)
 #define RK3588_GMAC_CLK_RMII_NOGATE(id)		GRF_CLR_BIT(5 * (id) + 1)
 
+static int rk3588_init(struct rk_priv_data *bsp_priv)
+{
+	switch (bsp_priv->id) {
+	case 0:
+		bsp_priv->phy_intf_sel_mask = GENMASK_U16(5, 3);
+		return 0;
+
+	case 1:
+		bsp_priv->phy_intf_sel_mask = GENMASK_U16(11, 9);
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
 static void rk3588_set_to_rgmii(struct rk_priv_data *bsp_priv,
 				int tx_delay, int rx_delay)
 {
@@ -1222,9 +1262,6 @@ static void rk3588_set_to_rgmii(struct rk_priv_data *bsp_priv,
 	offset_con = bsp_priv->id == 1 ? RK3588_GRF_GMAC_CON9 :
 					 RK3588_GRF_GMAC_CON8;
 
-	regmap_write(bsp_priv->php_grf, RK3588_GRF_GMAC_CON0,
-		     RK3588_GMAC_PHY_INTF_SEL(id, PHY_INTF_SEL_RGMII));
-
 	regmap_write(bsp_priv->php_grf, RK3588_GRF_CLK_CON1,
 		     RK3588_GMAC_CLK_RGMII_MODE(id));
 
@@ -1239,9 +1276,6 @@ static void rk3588_set_to_rgmii(struct rk_priv_data *bsp_priv,
 
 static void rk3588_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
-	regmap_write(bsp_priv->php_grf, RK3588_GRF_GMAC_CON0,
-		     RK3588_GMAC_PHY_INTF_SEL(bsp_priv->id, PHY_INTF_SEL_RMII));
-
 	regmap_write(bsp_priv->php_grf, RK3588_GRF_CLK_CON1,
 		     RK3588_GMAC_CLK_RMII_MODE(bsp_priv->id));
 }
@@ -1294,10 +1328,14 @@ static void rk3588_set_clock_selection(struct rk_priv_data *bsp_priv, bool input
 }
 
 static const struct rk_gmac_ops rk3588_ops = {
+	.init = rk3588_init,
 	.set_to_rgmii = rk3588_set_to_rgmii,
 	.set_to_rmii = rk3588_set_to_rmii,
 	.set_speed = rk3588_set_gmac_speed,
 	.set_clock_selection = rk3588_set_clock_selection,
+
+	.phy_intf_sel_grf_reg = RK3588_GRF_GMAC_CON0,
+
 	.php_grf_required = true,
 	.regs_valid = true,
 	.regs = {
@@ -1310,7 +1348,6 @@ static const struct rk_gmac_ops rk3588_ops = {
 #define RV1108_GRF_GMAC_CON0		0X0900
 
 /* RV1108_GRF_GMAC_CON0 */
-#define RV1108_GMAC_PHY_INTF_SEL(val)	GRF_FIELD(6, 4, val)
 #define RV1108_GMAC_FLOW_CTRL		GRF_BIT(3)
 #define RV1108_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(3)
 #define RV1108_GMAC_SPEED_10M		GRF_CLR_BIT(2)
@@ -1320,8 +1357,6 @@ static const struct rk_gmac_ops rk3588_ops = {
 
 static void rv1108_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
-	regmap_write(bsp_priv->grf, RV1108_GRF_GMAC_CON0,
-		     RV1108_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII));
 }
 
 static const struct rk_reg_speed_data rv1108_reg_speed_data = {
@@ -1339,6 +1374,9 @@ static int rv1108_set_speed(struct rk_priv_data *bsp_priv,
 static const struct rk_gmac_ops rv1108_ops = {
 	.set_to_rmii = rv1108_set_to_rmii,
 	.set_speed = rv1108_set_speed,
+
+	.phy_intf_sel_grf_reg = RV1108_GRF_GMAC_CON0,
+	.phy_intf_sel_mask = GENMASK_U16(6, 4),
 };
 
 #define RV1126_GRF_GMAC_CON0		0X0070
@@ -1346,7 +1384,6 @@ static const struct rk_gmac_ops rv1108_ops = {
 #define RV1126_GRF_GMAC_CON2		0X0078
 
 /* RV1126_GRF_GMAC_CON0 */
-#define RV1126_GMAC_PHY_INTF_SEL(val)	GRF_FIELD(6, 4, val)
 #define RV1126_GMAC_FLOW_CTRL			GRF_BIT(7)
 #define RV1126_GMAC_FLOW_CTRL_CLR		GRF_CLR_BIT(7)
 #define RV1126_GMAC_M0_RXCLK_DLY_ENABLE		GRF_BIT(1)
@@ -1369,7 +1406,6 @@ static void rv1126_set_to_rgmii(struct rk_priv_data *bsp_priv,
 				int tx_delay, int rx_delay)
 {
 	regmap_write(bsp_priv->grf, RV1126_GRF_GMAC_CON0,
-		     RV1126_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) |
 		     RV1126_GMAC_M0_RXCLK_DLY_ENABLE |
 		     RV1126_GMAC_M0_TXCLK_DLY_ENABLE |
 		     RV1126_GMAC_M1_RXCLK_DLY_ENABLE |
@@ -1386,14 +1422,15 @@ static void rv1126_set_to_rgmii(struct rk_priv_data *bsp_priv,
 
 static void rv1126_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
-	regmap_write(bsp_priv->grf, RV1126_GRF_GMAC_CON0,
-		     RV1126_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII));
 }
 
 static const struct rk_gmac_ops rv1126_ops = {
 	.set_to_rgmii = rv1126_set_to_rgmii,
 	.set_to_rmii = rv1126_set_to_rmii,
 	.set_speed = rk_set_clk_mac_speed,
+
+	.phy_intf_sel_grf_reg = RV1126_GRF_GMAC_CON0,
+	.phy_intf_sel_mask = GENMASK_U16(6, 4),
 };
 
 static int rk_gmac_clk_init(struct plat_stmmacenet_data *plat)
@@ -1614,6 +1651,11 @@ static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,
 
 	bsp_priv->dev = dev;
 
+	/* Set the default phy_intf_sel and RMII mode register parameters. */
+	bsp_priv->phy_intf_sel_grf_reg = ops->phy_intf_sel_grf_reg;
+	bsp_priv->phy_intf_sel_mask = ops->phy_intf_sel_mask;
+	bsp_priv->rmii_mode_mask = ops->rmii_mode_mask;
+
 	if (ops->init) {
 		ret = ops->init(bsp_priv);
 		if (ret) {
@@ -1649,6 +1691,7 @@ static int rk_gmac_check_ops(struct rk_priv_data *bsp_priv)
 static int rk_gmac_powerup(struct rk_priv_data *bsp_priv)
 {
 	struct device *dev = bsp_priv->dev;
+	u32 val;
 	int ret;
 
 	ret = rk_gmac_check_ops(bsp_priv);
@@ -1659,6 +1702,24 @@ static int rk_gmac_powerup(struct rk_priv_data *bsp_priv)
 	if (ret)
 		return ret;
 
+	ret = rk_get_phy_intf_sel(bsp_priv->phy_iface);
+	if (ret < 0)
+		return ret;
+
+	if (bsp_priv->phy_intf_sel_mask) {
+		/* Encode the phy_intf_sel value */
+		val = rk_encode_wm16(ret, bsp_priv->phy_intf_sel_mask);
+
+		/* If defined, encode the RMII mode mask setting. */
+		val |= rk_encode_wm16(ret == PHY_INTF_SEL_RMII,
+				      bsp_priv->rmii_mode_mask);
+
+		ret = regmap_write(bsp_priv->grf,
+				   bsp_priv->phy_intf_sel_grf_reg, val);
+		if (ret < 0)
+			return ret;
+	}
+
 	/*rmii or rgmii*/
 	switch (bsp_priv->phy_iface) {
 	case PHY_INTERFACE_MODE_RGMII:
-- 
2.47.3



From rmk+kernel at armlinux.org.uk  Mon Dec  1 06:51:13 2025
From: rmk+kernel at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 01 Dec 2025 14:51:13 +0000
Subject: [PATCH RFC net-next 06/15] net: stmmac: rk: convert rk3588 to
 rk_set_reg_speed()
In-Reply-To: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
References: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
Message-ID: <E1vQ5FB-0000000GNvz-1f66@rmk-PC.armlinux.org.uk>

Update rk_set_reg_speed() to use either the grf or php_grf regmap
depending on the SoC's requirements and convert rk3588, removing
its custom code.

Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
---
 .../net/ethernet/stmicro/stmmac/dwmac-rk.c    | 62 ++++++++++---------
 1 file changed, 33 insertions(+), 29 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
index e2c5bfbeadc5..2061ced12d6c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -52,6 +52,7 @@ struct rk_gmac_ops {
 
 	u16 speed_grf_reg;
 
+	bool speed_reg_php_grf;
 	bool php_grf_required;
 	bool regs_valid;
 	u32 regs[];
@@ -134,6 +135,7 @@ static int rk_set_reg_speed(struct rk_priv_data *bsp_priv,
 			    const struct rk_reg_speed_data *rsd,
 			    phy_interface_t interface, int speed)
 {
+	struct regmap *regmap;
 	unsigned int val;
 
 	if (phy_interface_mode_is_rgmii(interface)) {
@@ -168,7 +170,12 @@ static int rk_set_reg_speed(struct rk_priv_data *bsp_priv,
 		return -EINVAL;
 	}
 
-	regmap_write(bsp_priv->grf, bsp_priv->speed_grf_reg, val);
+	if (bsp_priv->ops->speed_reg_php_grf)
+		regmap = bsp_priv->php_grf;
+	else
+		regmap = bsp_priv->grf;
+
+	regmap_write(regmap, bsp_priv->speed_grf_reg, val);
 
 	return 0;
 
@@ -1318,39 +1325,33 @@ static void rk3588_set_to_rmii(struct rk_priv_data *bsp_priv)
 		     RK3588_GMAC_CLK_RMII_MODE(bsp_priv->id));
 }
 
+static const struct rk_reg_speed_data rk3588_gmac0_speed_data = {
+	.rgmii_10 = RK3588_GMAC_CLK_RGMII(0, GMAC_CLK_DIV50_2_5M),
+	.rgmii_100 = RK3588_GMAC_CLK_RGMII(0, GMAC_CLK_DIV5_25M),
+	.rgmii_1000 = RK3588_GMAC_CLK_RGMII(0, GMAC_CLK_DIV1_125M),
+	.rmii_10 = RK3588_GMA_CLK_RMII_DIV20(0),
+	.rmii_100 = RK3588_GMA_CLK_RMII_DIV2(0),
+};
+
+static const struct rk_reg_speed_data rk3588_gmac1_speed_data = {
+	.rgmii_10 = RK3588_GMAC_CLK_RGMII(1, GMAC_CLK_DIV50_2_5M),
+	.rgmii_100 = RK3588_GMAC_CLK_RGMII(1, GMAC_CLK_DIV5_25M),
+	.rgmii_1000 = RK3588_GMAC_CLK_RGMII(1, GMAC_CLK_DIV1_125M),
+	.rmii_10 = RK3588_GMA_CLK_RMII_DIV20(1),
+	.rmii_100 = RK3588_GMA_CLK_RMII_DIV2(1),
+};
+
 static int rk3588_set_gmac_speed(struct rk_priv_data *bsp_priv,
 				 phy_interface_t interface, int speed)
 {
-	unsigned int val = 0, id = bsp_priv->id;
-
-	switch (speed) {
-	case 10:
-		if (interface == PHY_INTERFACE_MODE_RMII)
-			val = RK3588_GMA_CLK_RMII_DIV20(id);
-		else
-			val = RK3588_GMAC_CLK_RGMII(id, GMAC_CLK_DIV50_2_5M);
-		break;
-	case 100:
-		if (interface == PHY_INTERFACE_MODE_RMII)
-			val = RK3588_GMA_CLK_RMII_DIV2(id);
-		else
-			val = RK3588_GMAC_CLK_RGMII(id, GMAC_CLK_DIV5_25M);
-		break;
-	case 1000:
-		if (interface != PHY_INTERFACE_MODE_RMII)
-			val = RK3588_GMAC_CLK_RGMII(id, GMAC_CLK_DIV1_125M);
-		else
-			goto err;
-		break;
-	default:
-		goto err;
-	}
+	const struct rk_reg_speed_data *rsd;
 
-	regmap_write(bsp_priv->php_grf, RK3588_GRF_CLK_CON1, val);
+	if (bsp_priv->id == 0)
+		rsd = &rk3588_gmac0_speed_data;
+	else
+		rsd = &rk3588_gmac1_speed_data;
 
-	return 0;
-err:
-	return -EINVAL;
+	return rk_set_reg_speed(bsp_priv, rsd, interface, speed);
 }
 
 static void rk3588_set_clock_selection(struct rk_priv_data *bsp_priv, bool input,
@@ -1374,6 +1375,9 @@ static const struct rk_gmac_ops rk3588_ops = {
 
 	.phy_intf_sel_grf_reg = RK3588_GRF_GMAC_CON0,
 
+	.speed_reg_php_grf = true,
+	.speed_grf_reg = RK3588_GRF_CLK_CON1,
+
 	.php_grf_required = true,
 	.regs_valid = true,
 	.regs = {
-- 
2.47.3



From rmk+kernel at armlinux.org.uk  Mon Dec  1 06:51:08 2025
From: rmk+kernel at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 01 Dec 2025 14:51:08 +0000
Subject: [PATCH RFC net-next 05/15] net: stmmac: rk: move speed GRF register
 offset to private data
In-Reply-To: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
References: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
Message-ID: <E1vQ5F6-0000000GNvt-0nam@rmk-PC.armlinux.org.uk>

Move the speed/clocking related GRF register offset into the driver
private data, convert rk_set_reg_speed() to use it and initialise this
member either from the corresponding member in struct rk_gmac_ops, or
the SoC specific initialisation function.

Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
---
 .../net/ethernet/stmicro/stmmac/dwmac-rk.c    | 109 ++++++++++++------
 1 file changed, 76 insertions(+), 33 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
index 369792b62c5e..e2c5bfbeadc5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -50,6 +50,8 @@ struct rk_gmac_ops {
 	u16 phy_intf_sel_mask;
 	u16 rmii_mode_mask;
 
+	u16 speed_grf_reg;
+
 	bool php_grf_required;
 	bool regs_valid;
 	u32 regs[];
@@ -99,6 +101,8 @@ struct rk_priv_data {
 	u16 phy_intf_sel_grf_reg;
 	u16 phy_intf_sel_mask;
 	u16 rmii_mode_mask;
+
+	u16 speed_grf_reg;
 };
 
 #define GMAC_CLK_DIV1_125M		0
@@ -128,8 +132,7 @@ static u32 rk_encode_wm16(u16 val, u16 mask)
 
 static int rk_set_reg_speed(struct rk_priv_data *bsp_priv,
 			    const struct rk_reg_speed_data *rsd,
-			    unsigned int reg, phy_interface_t interface,
-			    int speed)
+			    phy_interface_t interface, int speed)
 {
 	unsigned int val;
 
@@ -165,7 +168,7 @@ static int rk_set_reg_speed(struct rk_priv_data *bsp_priv,
 		return -EINVAL;
 	}
 
-	regmap_write(bsp_priv->grf, reg, val);
+	regmap_write(bsp_priv->grf, bsp_priv->speed_grf_reg, val);
 
 	return 0;
 
@@ -358,7 +361,7 @@ static int rk3128_set_speed(struct rk_priv_data *bsp_priv,
 			    phy_interface_t interface, int speed)
 {
 	return rk_set_reg_speed(bsp_priv, &rk3128_reg_speed_data,
-				RK3128_GRF_MAC_CON1, interface, speed);
+				interface, speed);
 }
 
 static const struct rk_gmac_ops rk3128_ops = {
@@ -369,6 +372,8 @@ static const struct rk_gmac_ops rk3128_ops = {
 	.phy_intf_sel_grf_reg = RK3128_GRF_MAC_CON1,
 	.phy_intf_sel_mask = GENMASK_U16(8, 6),
 	.rmii_mode_mask = BIT_U16(14),
+
+	.speed_grf_reg = RK3128_GRF_MAC_CON1,
 };
 
 #define RK3228_GRF_MAC_CON0	0x0900
@@ -425,7 +430,7 @@ static int rk3228_set_speed(struct rk_priv_data *bsp_priv,
 			    phy_interface_t interface, int speed)
 {
 	return rk_set_reg_speed(bsp_priv, &rk3228_reg_speed_data,
-				RK3228_GRF_MAC_CON1, interface, speed);
+				interface, speed);
 }
 
 static void rk3228_integrated_phy_powerup(struct rk_priv_data *priv)
@@ -447,6 +452,7 @@ static const struct rk_gmac_ops rk3228_ops = {
 	.phy_intf_sel_mask = GENMASK_U16(6, 4),
 	.rmii_mode_mask = BIT_U16(10),
 
+	.speed_grf_reg = RK3228_GRF_MAC_CON1,
 };
 
 #define RK3288_GRF_SOC_CON1	0x0248
@@ -494,7 +500,7 @@ static int rk3288_set_speed(struct rk_priv_data *bsp_priv,
 			    phy_interface_t interface, int speed)
 {
 	return rk_set_reg_speed(bsp_priv, &rk3288_reg_speed_data,
-				RK3288_GRF_SOC_CON1, interface, speed);
+				interface, speed);
 }
 
 static const struct rk_gmac_ops rk3288_ops = {
@@ -505,6 +511,8 @@ static const struct rk_gmac_ops rk3288_ops = {
 	.phy_intf_sel_grf_reg = RK3288_GRF_SOC_CON1,
 	.phy_intf_sel_mask = GENMASK_U16(8, 6),
 	.rmii_mode_mask = BIT_U16(14),
+
+	.speed_grf_reg = RK3288_GRF_SOC_CON1,
 };
 
 #define RK3308_GRF_MAC_CON0		0x04a0
@@ -528,7 +536,7 @@ static int rk3308_set_speed(struct rk_priv_data *bsp_priv,
 			    phy_interface_t interface, int speed)
 {
 	return rk_set_reg_speed(bsp_priv, &rk3308_reg_speed_data,
-				RK3308_GRF_MAC_CON0, interface, speed);
+				interface, speed);
 }
 
 static const struct rk_gmac_ops rk3308_ops = {
@@ -537,6 +545,8 @@ static const struct rk_gmac_ops rk3308_ops = {
 
 	.phy_intf_sel_grf_reg = RK3308_GRF_MAC_CON0,
 	.phy_intf_sel_mask = GENMASK_U16(4, 2),
+
+	.speed_grf_reg = RK3308_GRF_MAC_CON0,
 };
 
 #define RK3328_GRF_MAC_CON0	0x0900
@@ -567,10 +577,12 @@ static int rk3328_init(struct rk_priv_data *bsp_priv)
 	switch (bsp_priv->id) {
 	case 0: /* gmac2io */
 		bsp_priv->phy_intf_sel_grf_reg = RK3328_GRF_MAC_CON1;
+		bsp_priv->speed_grf_reg = RK3328_GRF_MAC_CON1;
 		return 0;
 
 	case 1: /* gmac2phy */
 		bsp_priv->phy_intf_sel_grf_reg = RK3328_GRF_MAC_CON2;
+		bsp_priv->speed_grf_reg = RK3328_GRF_MAC_CON2;
 		return 0;
 
 	default:
@@ -605,11 +617,7 @@ static const struct rk_reg_speed_data rk3328_reg_speed_data = {
 static int rk3328_set_speed(struct rk_priv_data *bsp_priv,
 			    phy_interface_t interface, int speed)
 {
-	unsigned int reg;
-
-	reg = bsp_priv->id ? RK3328_GRF_MAC_CON2 : RK3328_GRF_MAC_CON1;
-
-	return rk_set_reg_speed(bsp_priv, &rk3328_reg_speed_data, reg,
+	return rk_set_reg_speed(bsp_priv, &rk3328_reg_speed_data,
 				interface, speed);
 }
 
@@ -685,7 +693,7 @@ static int rk3366_set_speed(struct rk_priv_data *bsp_priv,
 			    phy_interface_t interface, int speed)
 {
 	return rk_set_reg_speed(bsp_priv, &rk3366_reg_speed_data,
-				RK3366_GRF_SOC_CON6, interface, speed);
+				interface, speed);
 }
 
 static const struct rk_gmac_ops rk3366_ops = {
@@ -696,6 +704,8 @@ static const struct rk_gmac_ops rk3366_ops = {
 	.phy_intf_sel_grf_reg = RK3366_GRF_SOC_CON6,
 	.phy_intf_sel_mask = GENMASK_U16(11, 9),
 	.rmii_mode_mask = BIT_U16(6),
+
+	.speed_grf_reg = RK3366_GRF_SOC_CON6,
 };
 
 #define RK3368_GRF_SOC_CON15	0x043c
@@ -743,7 +753,7 @@ static int rk3368_set_speed(struct rk_priv_data *bsp_priv,
 			    phy_interface_t interface, int speed)
 {
 	return rk_set_reg_speed(bsp_priv, &rk3368_reg_speed_data,
-				RK3368_GRF_SOC_CON15, interface, speed);
+				interface, speed);
 }
 
 static const struct rk_gmac_ops rk3368_ops = {
@@ -754,6 +764,8 @@ static const struct rk_gmac_ops rk3368_ops = {
 	.phy_intf_sel_grf_reg = RK3368_GRF_SOC_CON15,
 	.phy_intf_sel_mask = GENMASK_U16(11, 9),
 	.rmii_mode_mask = BIT_U16(6),
+
+	.speed_grf_reg = RK3368_GRF_SOC_CON15,
 };
 
 #define RK3399_GRF_SOC_CON5	0xc214
@@ -801,7 +813,7 @@ static int rk3399_set_speed(struct rk_priv_data *bsp_priv,
 			    phy_interface_t interface, int speed)
 {
 	return rk_set_reg_speed(bsp_priv, &rk3399_reg_speed_data,
-				RK3399_GRF_SOC_CON5, interface, speed);
+				interface, speed);
 }
 
 static const struct rk_gmac_ops rk3399_ops = {
@@ -812,6 +824,8 @@ static const struct rk_gmac_ops rk3399_ops = {
 	.phy_intf_sel_grf_reg = RK3399_GRF_SOC_CON5,
 	.phy_intf_sel_mask = GENMASK_U16(11, 9),
 	.rmii_mode_mask = BIT_U16(6),
+
+	.speed_grf_reg = RK3399_GRF_SOC_CON5,
 };
 
 #define RK3506_GRF_SOC_CON8		0x0020
@@ -828,6 +842,22 @@ static const struct rk_gmac_ops rk3399_ops = {
 #define RK3506_GMAC_CLK_RMII_GATE	GRF_BIT(2)
 #define RK3506_GMAC_CLK_RMII_NOGATE	GRF_CLR_BIT(2)
 
+static int rk3506_init(struct rk_priv_data *bsp_priv)
+{
+	switch (bsp_priv->id) {
+	case 0:
+		bsp_priv->speed_grf_reg = RK3506_GRF_SOC_CON8;
+		return 0;
+
+	case 1:
+		bsp_priv->speed_grf_reg = RK3506_GRF_SOC_CON11;
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
 static void rk3506_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
 	unsigned int id = bsp_priv->id, offset;
@@ -844,11 +874,8 @@ static const struct rk_reg_speed_data rk3506_reg_speed_data = {
 static int rk3506_set_speed(struct rk_priv_data *bsp_priv,
 			    phy_interface_t interface, int speed)
 {
-	unsigned int id = bsp_priv->id, offset;
-
-	offset = (id == 1) ? RK3506_GRF_SOC_CON11 : RK3506_GRF_SOC_CON8;
 	return rk_set_reg_speed(bsp_priv, &rk3506_reg_speed_data,
-				offset, interface, speed);
+				interface, speed);
 }
 
 static void rk3506_set_clock_selection(struct rk_priv_data *bsp_priv,
@@ -866,6 +893,7 @@ static void rk3506_set_clock_selection(struct rk_priv_data *bsp_priv,
 }
 
 static const struct rk_gmac_ops rk3506_ops = {
+	.init = rk3506_init,
 	.set_to_rmii = rk3506_set_to_rmii,
 	.set_speed = rk3506_set_speed,
 	.set_clock_selection = rk3506_set_clock_selection,
@@ -910,6 +938,22 @@ static const struct rk_gmac_ops rk3506_ops = {
 #define RK3528_GMAC1_CLK_RMII_GATE	GRF_BIT(9)
 #define RK3528_GMAC1_CLK_RMII_NOGATE	GRF_CLR_BIT(9)
 
+static int rk3528_init(struct rk_priv_data *bsp_priv)
+{
+	switch (bsp_priv->id) {
+	case 0:
+		bsp_priv->speed_grf_reg = RK3528_VO_GRF_GMAC_CON;
+		return 0;
+
+	case 1:
+		bsp_priv->speed_grf_reg = RK3528_VPU_GRF_GMAC_CON5;
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
 static void rk3528_set_to_rgmii(struct rk_priv_data *bsp_priv,
 				int tx_delay, int rx_delay)
 {
@@ -952,17 +996,13 @@ static int rk3528_set_speed(struct rk_priv_data *bsp_priv,
 			    phy_interface_t interface, int speed)
 {
 	const struct rk_reg_speed_data *rsd;
-	unsigned int reg;
 
-	if (bsp_priv->id == 1) {
+	if (bsp_priv->id == 1)
 		rsd = &rk3528_gmac1_reg_speed_data;
-		reg = RK3528_VPU_GRF_GMAC_CON5;
-	} else {
+	else
 		rsd = &rk3528_gmac0_reg_speed_data;
-		reg = RK3528_VO_GRF_GMAC_CON;
-	}
 
-	return rk_set_reg_speed(bsp_priv, rsd, reg, interface, speed);
+	return rk_set_reg_speed(bsp_priv, rsd, interface, speed);
 }
 
 static void rk3528_set_clock_selection(struct rk_priv_data *bsp_priv,
@@ -994,6 +1034,7 @@ static void rk3528_integrated_phy_powerdown(struct rk_priv_data *bsp_priv)
 }
 
 static const struct rk_gmac_ops rk3528_ops = {
+	.init = rk3528_init,
 	.set_to_rgmii = rk3528_set_to_rgmii,
 	.set_to_rmii = rk3528_set_to_rmii,
 	.set_speed = rk3528_set_speed,
@@ -1114,10 +1155,12 @@ static int rk3576_init(struct rk_priv_data *bsp_priv)
 	switch (bsp_priv->id) {
 	case 0:
 		bsp_priv->phy_intf_sel_grf_reg = RK3576_GRF_GMAC_CON0;
+		bsp_priv->speed_grf_reg = RK3576_GRF_GMAC_CON0;
 		return 0;
 
 	case 1:
 		bsp_priv->phy_intf_sel_grf_reg = RK3576_GRF_GMAC_CON1;
+		bsp_priv->speed_grf_reg = RK3576_GRF_GMAC_CON1;
 		return 0;
 
 	default:
@@ -1163,12 +1206,7 @@ static const struct rk_reg_speed_data rk3578_reg_speed_data = {
 static int rk3576_set_gmac_speed(struct rk_priv_data *bsp_priv,
 				 phy_interface_t interface, int speed)
 {
-	unsigned int offset_con;
-
-	offset_con = bsp_priv->id == 1 ? RK3576_GRF_GMAC_CON1 :
-					 RK3576_GRF_GMAC_CON0;
-
-	return rk_set_reg_speed(bsp_priv, &rk3578_reg_speed_data, offset_con,
+	return rk_set_reg_speed(bsp_priv, &rk3578_reg_speed_data,
 				interface, speed);
 }
 
@@ -1368,7 +1406,7 @@ static int rv1108_set_speed(struct rk_priv_data *bsp_priv,
 			    phy_interface_t interface, int speed)
 {
 	return rk_set_reg_speed(bsp_priv, &rv1108_reg_speed_data,
-				RV1108_GRF_GMAC_CON0, interface, speed);
+				interface, speed);
 }
 
 static const struct rk_gmac_ops rv1108_ops = {
@@ -1377,6 +1415,8 @@ static const struct rk_gmac_ops rv1108_ops = {
 
 	.phy_intf_sel_grf_reg = RV1108_GRF_GMAC_CON0,
 	.phy_intf_sel_mask = GENMASK_U16(6, 4),
+
+	.speed_grf_reg = RV1108_GRF_GMAC_CON0,
 };
 
 #define RV1126_GRF_GMAC_CON0		0X0070
@@ -1656,6 +1696,9 @@ static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,
 	bsp_priv->phy_intf_sel_mask = ops->phy_intf_sel_mask;
 	bsp_priv->rmii_mode_mask = ops->rmii_mode_mask;
 
+	/* Set the default speed related parameters */
+	bsp_priv->speed_grf_reg = ops->speed_grf_reg;
+
 	if (ops->init) {
 		ret = ops->init(bsp_priv);
 		if (ret) {
-- 
2.47.3



From rmk+kernel at armlinux.org.uk  Mon Dec  1 06:51:18 2025
From: rmk+kernel at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 01 Dec 2025 14:51:18 +0000
Subject: [PATCH RFC net-next 07/15] net: stmmac: rk: use rk_encode_wm16() for
 RGMII clocks
In-Reply-To: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
References: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
Message-ID: <E1vQ5FG-0000000GNw5-2Apg@rmk-PC.armlinux.org.uk>

As all of the RGMII clock selection bitfields (gmii_clk_sel) use the
same encoding, parameterise this by providing the bitfield mask in
the BSP private data.

One additional change is for RK3328 - as only gmac2io supports RGMII,
only initialise the mask for this instance.

Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
---
 .../net/ethernet/stmicro/stmmac/dwmac-rk.c    | 94 +++++++------------
 1 file changed, 32 insertions(+), 62 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
index 2061ced12d6c..d11a58d7f24b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -27,9 +27,6 @@
 struct rk_priv_data;
 
 struct rk_reg_speed_data {
-	unsigned int rgmii_10;
-	unsigned int rgmii_100;
-	unsigned int rgmii_1000;
 	unsigned int rmii_10;
 	unsigned int rmii_100;
 };
@@ -51,6 +48,7 @@ struct rk_gmac_ops {
 	u16 rmii_mode_mask;
 
 	u16 speed_grf_reg;
+	u16 gmii_clk_sel_mask;
 
 	bool speed_reg_php_grf;
 	bool php_grf_required;
@@ -104,12 +102,24 @@ struct rk_priv_data {
 	u16 rmii_mode_mask;
 
 	u16 speed_grf_reg;
+	u16 gmii_clk_sel_mask;
 };
 
 #define GMAC_CLK_DIV1_125M		0
 #define GMAC_CLK_DIV50_2_5M		2
 #define GMAC_CLK_DIV5_25M		3
 
+static int rk_gmac_rgmii_clk_div(int speed)
+{
+	if (speed == SPEED_10)
+		return GMAC_CLK_DIV50_2_5M;
+	if (speed == SPEED_100)
+		return GMAC_CLK_DIV5_25M;
+	if (speed == SPEED_1000)
+		return GMAC_CLK_DIV1_125M;
+	return -EINVAL;
+}
+
 static int rk_get_phy_intf_sel(phy_interface_t interface)
 {
 	int ret = stmmac_get_phy_intf_sel(interface);
@@ -137,20 +147,14 @@ static int rk_set_reg_speed(struct rk_priv_data *bsp_priv,
 {
 	struct regmap *regmap;
 	unsigned int val;
+	int ret;
 
 	if (phy_interface_mode_is_rgmii(interface)) {
-		if (speed == SPEED_10) {
-			val = rsd->rgmii_10;
-		} else if (speed == SPEED_100) {
-			val = rsd->rgmii_100;
-		} else if (speed == SPEED_1000) {
-			val = rsd->rgmii_1000;
-		} else {
-			/* Phylink will not allow inappropriate speeds for
-			 * interface modes, so this should never happen.
-			 */
-			return -EINVAL;
-		}
+		ret = rk_gmac_rgmii_clk_div(speed);
+		if (ret < 0)
+			return ret;
+
+		val = rk_encode_wm16(ret, bsp_priv->gmii_clk_sel_mask);
 	} else if (interface == PHY_INTERFACE_MODE_RMII) {
 		if (speed == SPEED_10) {
 			val = rsd->rmii_10;
@@ -341,7 +345,6 @@ static const struct rk_gmac_ops px30_ops = {
 #define RK3128_GMAC_SPEED_100M         GRF_BIT(10)
 #define RK3128_GMAC_RMII_CLK_25M       GRF_BIT(11)
 #define RK3128_GMAC_RMII_CLK_2_5M      GRF_CLR_BIT(11)
-#define RK3128_GMAC_CLK(val)           GRF_FIELD_CONST(13, 12, val)
 
 static void rk3128_set_to_rgmii(struct rk_priv_data *bsp_priv,
 				int tx_delay, int rx_delay)
@@ -357,9 +360,6 @@ static void rk3128_set_to_rmii(struct rk_priv_data *bsp_priv)
 }
 
 static const struct rk_reg_speed_data rk3128_reg_speed_data = {
-	.rgmii_10 = RK3128_GMAC_CLK(GMAC_CLK_DIV50_2_5M),
-	.rgmii_100 = RK3128_GMAC_CLK(GMAC_CLK_DIV5_25M),
-	.rgmii_1000 = RK3128_GMAC_CLK(GMAC_CLK_DIV1_125M),
 	.rmii_10 = RK3128_GMAC_RMII_CLK_2_5M | RK3128_GMAC_SPEED_10M,
 	.rmii_100 = RK3128_GMAC_RMII_CLK_25M | RK3128_GMAC_SPEED_100M,
 };
@@ -381,6 +381,7 @@ static const struct rk_gmac_ops rk3128_ops = {
 	.rmii_mode_mask = BIT_U16(14),
 
 	.speed_grf_reg = RK3128_GRF_MAC_CON1,
+	.gmii_clk_sel_mask = GENMASK_U16(13, 12),
 };
 
 #define RK3228_GRF_MAC_CON0	0x0900
@@ -399,7 +400,6 @@ static const struct rk_gmac_ops rk3128_ops = {
 #define RK3228_GMAC_SPEED_100M		GRF_BIT(2)
 #define RK3228_GMAC_RMII_CLK_25M	GRF_BIT(7)
 #define RK3228_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(7)
-#define RK3228_GMAC_CLK(val)		GRF_FIELD_CONST(9, 8, val)
 #define RK3228_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(0)
 #define RK3228_GMAC_TXCLK_DLY_DISABLE	GRF_CLR_BIT(0)
 #define RK3228_GMAC_RXCLK_DLY_ENABLE	GRF_BIT(1)
@@ -426,9 +426,6 @@ static void rk3228_set_to_rmii(struct rk_priv_data *bsp_priv)
 }
 
 static const struct rk_reg_speed_data rk3228_reg_speed_data = {
-	.rgmii_10 = RK3228_GMAC_CLK(GMAC_CLK_DIV50_2_5M),
-	.rgmii_100 = RK3228_GMAC_CLK(GMAC_CLK_DIV5_25M),
-	.rgmii_1000 = RK3228_GMAC_CLK(GMAC_CLK_DIV1_125M),
 	.rmii_10 = RK3228_GMAC_RMII_CLK_2_5M | RK3228_GMAC_SPEED_10M,
 	.rmii_100 = RK3228_GMAC_RMII_CLK_25M | RK3228_GMAC_SPEED_100M,
 };
@@ -460,6 +457,7 @@ static const struct rk_gmac_ops rk3228_ops = {
 	.rmii_mode_mask = BIT_U16(10),
 
 	.speed_grf_reg = RK3228_GRF_MAC_CON1,
+	.gmii_clk_sel_mask = GENMASK_U16(9, 8),
 };
 
 #define RK3288_GRF_SOC_CON1	0x0248
@@ -472,7 +470,6 @@ static const struct rk_gmac_ops rk3228_ops = {
 #define RK3288_GMAC_SPEED_100M		GRF_BIT(10)
 #define RK3288_GMAC_RMII_CLK_25M	GRF_BIT(11)
 #define RK3288_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(11)
-#define RK3288_GMAC_CLK(val)		GRF_FIELD_CONST(13, 12, val)
 
 /*RK3288_GRF_SOC_CON3*/
 #define RK3288_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(14)
@@ -496,9 +493,6 @@ static void rk3288_set_to_rmii(struct rk_priv_data *bsp_priv)
 }
 
 static const struct rk_reg_speed_data rk3288_reg_speed_data = {
-	.rgmii_10 = RK3288_GMAC_CLK(GMAC_CLK_DIV50_2_5M),
-	.rgmii_100 = RK3288_GMAC_CLK(GMAC_CLK_DIV5_25M),
-	.rgmii_1000 = RK3288_GMAC_CLK(GMAC_CLK_DIV1_125M),
 	.rmii_10 = RK3288_GMAC_RMII_CLK_2_5M | RK3288_GMAC_SPEED_10M,
 	.rmii_100 = RK3288_GMAC_RMII_CLK_25M | RK3288_GMAC_SPEED_100M,
 };
@@ -520,6 +514,7 @@ static const struct rk_gmac_ops rk3288_ops = {
 	.rmii_mode_mask = BIT_U16(14),
 
 	.speed_grf_reg = RK3288_GRF_SOC_CON1,
+	.gmii_clk_sel_mask = GENMASK_U16(13, 12),
 };
 
 #define RK3308_GRF_MAC_CON0		0x04a0
@@ -572,7 +567,6 @@ static const struct rk_gmac_ops rk3308_ops = {
 #define RK3328_GMAC_SPEED_100M		GRF_BIT(2)
 #define RK3328_GMAC_RMII_CLK_25M	GRF_BIT(7)
 #define RK3328_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(7)
-#define RK3328_GMAC_CLK(val)		GRF_FIELD_CONST(12, 11, val)
 #define RK3328_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(0)
 #define RK3328_GMAC_RXCLK_DLY_ENABLE	GRF_BIT(1)
 
@@ -585,6 +579,7 @@ static int rk3328_init(struct rk_priv_data *bsp_priv)
 	case 0: /* gmac2io */
 		bsp_priv->phy_intf_sel_grf_reg = RK3328_GRF_MAC_CON1;
 		bsp_priv->speed_grf_reg = RK3328_GRF_MAC_CON1;
+		bsp_priv->gmii_clk_sel_mask = GENMASK_U16(12, 11);
 		return 0;
 
 	case 1: /* gmac2phy */
@@ -614,9 +609,6 @@ static void rk3328_set_to_rmii(struct rk_priv_data *bsp_priv)
 }
 
 static const struct rk_reg_speed_data rk3328_reg_speed_data = {
-	.rgmii_10 = RK3328_GMAC_CLK(GMAC_CLK_DIV50_2_5M),
-	.rgmii_100 = RK3328_GMAC_CLK(GMAC_CLK_DIV5_25M),
-	.rgmii_1000 = RK3328_GMAC_CLK(GMAC_CLK_DIV1_125M),
 	.rmii_10 = RK3328_GMAC_RMII_CLK_2_5M | RK3328_GMAC_SPEED_10M,
 	.rmii_100 = RK3328_GMAC_RMII_CLK_25M | RK3328_GMAC_SPEED_100M,
 };
@@ -665,7 +657,6 @@ static const struct rk_gmac_ops rk3328_ops = {
 #define RK3366_GMAC_SPEED_100M		GRF_BIT(7)
 #define RK3366_GMAC_RMII_CLK_25M	GRF_BIT(3)
 #define RK3366_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(3)
-#define RK3366_GMAC_CLK(val)		GRF_FIELD_CONST(5, 4, val)
 
 /* RK3366_GRF_SOC_CON7 */
 #define RK3366_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(7)
@@ -689,9 +680,6 @@ static void rk3366_set_to_rmii(struct rk_priv_data *bsp_priv)
 }
 
 static const struct rk_reg_speed_data rk3366_reg_speed_data = {
-	.rgmii_10 = RK3366_GMAC_CLK(GMAC_CLK_DIV50_2_5M),
-	.rgmii_100 = RK3366_GMAC_CLK(GMAC_CLK_DIV5_25M),
-	.rgmii_1000 = RK3366_GMAC_CLK(GMAC_CLK_DIV1_125M),
 	.rmii_10 = RK3366_GMAC_RMII_CLK_2_5M | RK3366_GMAC_SPEED_10M,
 	.rmii_100 = RK3366_GMAC_RMII_CLK_25M | RK3366_GMAC_SPEED_100M,
 };
@@ -713,6 +701,7 @@ static const struct rk_gmac_ops rk3366_ops = {
 	.rmii_mode_mask = BIT_U16(6),
 
 	.speed_grf_reg = RK3366_GRF_SOC_CON6,
+	.gmii_clk_sel_mask = GENMASK_U16(5, 4),
 };
 
 #define RK3368_GRF_SOC_CON15	0x043c
@@ -725,7 +714,6 @@ static const struct rk_gmac_ops rk3366_ops = {
 #define RK3368_GMAC_SPEED_100M		GRF_BIT(7)
 #define RK3368_GMAC_RMII_CLK_25M	GRF_BIT(3)
 #define RK3368_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(3)
-#define RK3368_GMAC_CLK(val)		GRF_FIELD_CONST(5, 4, val)
 
 /* RK3368_GRF_SOC_CON16 */
 #define RK3368_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(7)
@@ -749,9 +737,6 @@ static void rk3368_set_to_rmii(struct rk_priv_data *bsp_priv)
 }
 
 static const struct rk_reg_speed_data rk3368_reg_speed_data = {
-	.rgmii_10 = RK3368_GMAC_CLK(GMAC_CLK_DIV50_2_5M),
-	.rgmii_100 = RK3368_GMAC_CLK(GMAC_CLK_DIV5_25M),
-	.rgmii_1000 = RK3368_GMAC_CLK(GMAC_CLK_DIV1_125M),
 	.rmii_10 = RK3368_GMAC_RMII_CLK_2_5M | RK3368_GMAC_SPEED_10M,
 	.rmii_100 = RK3368_GMAC_RMII_CLK_25M | RK3368_GMAC_SPEED_100M,
 };
@@ -773,6 +758,7 @@ static const struct rk_gmac_ops rk3368_ops = {
 	.rmii_mode_mask = BIT_U16(6),
 
 	.speed_grf_reg = RK3368_GRF_SOC_CON15,
+	.gmii_clk_sel_mask = GENMASK_U16(5, 4),
 };
 
 #define RK3399_GRF_SOC_CON5	0xc214
@@ -785,7 +771,6 @@ static const struct rk_gmac_ops rk3368_ops = {
 #define RK3399_GMAC_SPEED_100M		GRF_BIT(7)
 #define RK3399_GMAC_RMII_CLK_25M	GRF_BIT(3)
 #define RK3399_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(3)
-#define RK3399_GMAC_CLK(val)		GRF_FIELD_CONST(5, 4, val)
 
 /* RK3399_GRF_SOC_CON6 */
 #define RK3399_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(7)
@@ -809,9 +794,6 @@ static void rk3399_set_to_rmii(struct rk_priv_data *bsp_priv)
 }
 
 static const struct rk_reg_speed_data rk3399_reg_speed_data = {
-	.rgmii_10 = RK3399_GMAC_CLK(GMAC_CLK_DIV50_2_5M),
-	.rgmii_100 = RK3399_GMAC_CLK(GMAC_CLK_DIV5_25M),
-	.rgmii_1000 = RK3399_GMAC_CLK(GMAC_CLK_DIV1_125M),
 	.rmii_10 = RK3399_GMAC_RMII_CLK_2_5M | RK3399_GMAC_SPEED_10M,
 	.rmii_100 = RK3399_GMAC_RMII_CLK_25M | RK3399_GMAC_SPEED_100M,
 };
@@ -833,6 +815,7 @@ static const struct rk_gmac_ops rk3399_ops = {
 	.rmii_mode_mask = BIT_U16(6),
 
 	.speed_grf_reg = RK3399_GRF_SOC_CON5,
+	.gmii_clk_sel_mask = GENMASK_U16(5, 4),
 };
 
 #define RK3506_GRF_SOC_CON8		0x0020
@@ -938,8 +921,6 @@ static const struct rk_gmac_ops rk3506_ops = {
 #define RK3528_GMAC1_CLK_RMII_DIV2	GRF_BIT(10)
 #define RK3528_GMAC1_CLK_RMII_DIV20	GRF_CLR_BIT(10)
 
-#define RK3528_GMAC1_CLK_RGMII(val)	GRF_FIELD_CONST(11, 10, val)
-
 #define RK3528_GMAC0_CLK_RMII_GATE	GRF_BIT(2)
 #define RK3528_GMAC0_CLK_RMII_NOGATE	GRF_CLR_BIT(2)
 #define RK3528_GMAC1_CLK_RMII_GATE	GRF_BIT(9)
@@ -954,6 +935,7 @@ static int rk3528_init(struct rk_priv_data *bsp_priv)
 
 	case 1:
 		bsp_priv->speed_grf_reg = RK3528_VPU_GRF_GMAC_CON5;
+		bsp_priv->gmii_clk_sel_mask = GENMASK_U16(11, 10);
 		return 0;
 
 	default:
@@ -992,9 +974,6 @@ static const struct rk_reg_speed_data rk3528_gmac0_reg_speed_data = {
 };
 
 static const struct rk_reg_speed_data rk3528_gmac1_reg_speed_data = {
-	.rgmii_10 = RK3528_GMAC1_CLK_RGMII(GMAC_CLK_DIV50_2_5M),
-	.rgmii_100 = RK3528_GMAC1_CLK_RGMII(GMAC_CLK_DIV5_25M),
-	.rgmii_1000 = RK3528_GMAC1_CLK_RGMII(GMAC_CLK_DIV1_125M),
 	.rmii_10 = RK3528_GMAC1_CLK_RMII_DIV20,
 	.rmii_100 = RK3528_GMAC1_CLK_RMII_DIV2,
 };
@@ -1152,8 +1131,6 @@ static const struct rk_gmac_ops rk3568_ops = {
 #define RK3576_GMAC_CLK_RMII_DIV2		GRF_BIT(5)
 #define RK3576_GMAC_CLK_RMII_DIV20		GRF_CLR_BIT(5)
 
-#define RK3576_GMAC_CLK_RGMII(val)		GRF_FIELD_CONST(6, 5, val)
-
 #define RK3576_GMAC_CLK_RMII_GATE		GRF_BIT(4)
 #define RK3576_GMAC_CLK_RMII_NOGATE		GRF_CLR_BIT(4)
 
@@ -1203,9 +1180,6 @@ static void rk3576_set_to_rmii(struct rk_priv_data *bsp_priv)
 }
 
 static const struct rk_reg_speed_data rk3578_reg_speed_data = {
-	.rgmii_10 = RK3576_GMAC_CLK_RGMII(GMAC_CLK_DIV50_2_5M),
-	.rgmii_100 = RK3576_GMAC_CLK_RGMII(GMAC_CLK_DIV5_25M),
-	.rgmii_1000 = RK3576_GMAC_CLK_RGMII(GMAC_CLK_DIV1_125M),
 	.rmii_10 = RK3576_GMAC_CLK_RMII_DIV20,
 	.rmii_100 = RK3576_GMAC_CLK_RMII_DIV2,
 };
@@ -1242,6 +1216,8 @@ static const struct rk_gmac_ops rk3576_ops = {
 
 	.rmii_mode_mask = BIT_U16(3),
 
+	.gmii_clk_sel_mask = GENMASK_U16(6, 5),
+
 	.php_grf_required = true,
 	.regs_valid = true,
 	.regs = {
@@ -1277,9 +1253,6 @@ static const struct rk_gmac_ops rk3576_ops = {
 #define RK3588_GMA_CLK_RMII_DIV2(id)		GRF_BIT(5 * (id) + 2)
 #define RK3588_GMA_CLK_RMII_DIV20(id)		GRF_CLR_BIT(5 * (id) + 2)
 
-#define RK3588_GMAC_CLK_RGMII(id, val)		\
-	(GRF_FIELD_CONST(3, 2, val) << ((id) * 5))
-
 #define RK3588_GMAC_CLK_RMII_GATE(id)		GRF_BIT(5 * (id) + 1)
 #define RK3588_GMAC_CLK_RMII_NOGATE(id)		GRF_CLR_BIT(5 * (id) + 1)
 
@@ -1288,10 +1261,12 @@ static int rk3588_init(struct rk_priv_data *bsp_priv)
 	switch (bsp_priv->id) {
 	case 0:
 		bsp_priv->phy_intf_sel_mask = GENMASK_U16(5, 3);
+		bsp_priv->gmii_clk_sel_mask = GENMASK_U16(3, 2);
 		return 0;
 
 	case 1:
 		bsp_priv->phy_intf_sel_mask = GENMASK_U16(11, 9);
+		bsp_priv->gmii_clk_sel_mask = GENMASK_U16(8, 7);
 		return 0;
 
 	default:
@@ -1326,17 +1301,11 @@ static void rk3588_set_to_rmii(struct rk_priv_data *bsp_priv)
 }
 
 static const struct rk_reg_speed_data rk3588_gmac0_speed_data = {
-	.rgmii_10 = RK3588_GMAC_CLK_RGMII(0, GMAC_CLK_DIV50_2_5M),
-	.rgmii_100 = RK3588_GMAC_CLK_RGMII(0, GMAC_CLK_DIV5_25M),
-	.rgmii_1000 = RK3588_GMAC_CLK_RGMII(0, GMAC_CLK_DIV1_125M),
 	.rmii_10 = RK3588_GMA_CLK_RMII_DIV20(0),
 	.rmii_100 = RK3588_GMA_CLK_RMII_DIV2(0),
 };
 
 static const struct rk_reg_speed_data rk3588_gmac1_speed_data = {
-	.rgmii_10 = RK3588_GMAC_CLK_RGMII(1, GMAC_CLK_DIV50_2_5M),
-	.rgmii_100 = RK3588_GMAC_CLK_RGMII(1, GMAC_CLK_DIV5_25M),
-	.rgmii_1000 = RK3588_GMAC_CLK_RGMII(1, GMAC_CLK_DIV1_125M),
 	.rmii_10 = RK3588_GMA_CLK_RMII_DIV20(1),
 	.rmii_100 = RK3588_GMA_CLK_RMII_DIV2(1),
 };
@@ -1702,6 +1671,7 @@ static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,
 
 	/* Set the default speed related parameters */
 	bsp_priv->speed_grf_reg = ops->speed_grf_reg;
+	bsp_priv->gmii_clk_sel_mask = ops->gmii_clk_sel_mask;
 
 	if (ops->init) {
 		ret = ops->init(bsp_priv);
-- 
2.47.3



From rmk+kernel at armlinux.org.uk  Mon Dec  1 06:51:23 2025
From: rmk+kernel at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 01 Dec 2025 14:51:23 +0000
Subject: [PATCH RFC net-next 08/15] net: stmmac: rk: use rk_encode_wm16() for
 RMII speed
In-Reply-To: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
References: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
Message-ID: <E1vQ5FL-0000000GNwB-2ckX@rmk-PC.armlinux.org.uk>

Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
---
 .../net/ethernet/stmicro/stmmac/dwmac-rk.c    | 71 +++++++++----------
 1 file changed, 33 insertions(+), 38 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
index d11a58d7f24b..5f586782d595 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -49,6 +49,7 @@ struct rk_gmac_ops {
 
 	u16 speed_grf_reg;
 	u16 gmii_clk_sel_mask;
+	u16 mac_speed_mask;
 
 	bool speed_reg_php_grf;
 	bool php_grf_required;
@@ -103,6 +104,7 @@ struct rk_priv_data {
 
 	u16 speed_grf_reg;
 	u16 gmii_clk_sel_mask;
+	u16 mac_speed_mask;
 };
 
 #define GMAC_CLK_DIV1_125M		0
@@ -156,10 +158,12 @@ static int rk_set_reg_speed(struct rk_priv_data *bsp_priv,
 
 		val = rk_encode_wm16(ret, bsp_priv->gmii_clk_sel_mask);
 	} else if (interface == PHY_INTERFACE_MODE_RMII) {
+		val = rk_encode_wm16(speed == SPEED_100,
+				     bsp_priv->mac_speed_mask);
 		if (speed == SPEED_10) {
-			val = rsd->rmii_10;
+			val |= rsd->rmii_10;
 		} else if (speed == SPEED_100) {
-			val = rsd->rmii_100;
+			val |= rsd->rmii_100;
 		} else {
 			/* Phylink will not allow inappropriate speeds for
 			 * interface modes, so this should never happen.
@@ -341,8 +345,6 @@ static const struct rk_gmac_ops px30_ops = {
 /* RK3128_GRF_MAC_CON1 */
 #define RK3128_GMAC_FLOW_CTRL          GRF_BIT(9)
 #define RK3128_GMAC_FLOW_CTRL_CLR      GRF_CLR_BIT(9)
-#define RK3128_GMAC_SPEED_10M          GRF_CLR_BIT(10)
-#define RK3128_GMAC_SPEED_100M         GRF_BIT(10)
 #define RK3128_GMAC_RMII_CLK_25M       GRF_BIT(11)
 #define RK3128_GMAC_RMII_CLK_2_5M      GRF_CLR_BIT(11)
 
@@ -360,8 +362,8 @@ static void rk3128_set_to_rmii(struct rk_priv_data *bsp_priv)
 }
 
 static const struct rk_reg_speed_data rk3128_reg_speed_data = {
-	.rmii_10 = RK3128_GMAC_RMII_CLK_2_5M | RK3128_GMAC_SPEED_10M,
-	.rmii_100 = RK3128_GMAC_RMII_CLK_25M | RK3128_GMAC_SPEED_100M,
+	.rmii_10 = RK3128_GMAC_RMII_CLK_2_5M,
+	.rmii_100 = RK3128_GMAC_RMII_CLK_25M,
 };
 
 static int rk3128_set_speed(struct rk_priv_data *bsp_priv,
@@ -382,6 +384,7 @@ static const struct rk_gmac_ops rk3128_ops = {
 
 	.speed_grf_reg = RK3128_GRF_MAC_CON1,
 	.gmii_clk_sel_mask = GENMASK_U16(13, 12),
+	.mac_speed_mask = BIT_U16(10),
 };
 
 #define RK3228_GRF_MAC_CON0	0x0900
@@ -396,8 +399,6 @@ static const struct rk_gmac_ops rk3128_ops = {
 /* RK3228_GRF_MAC_CON1 */
 #define RK3228_GMAC_FLOW_CTRL		GRF_BIT(3)
 #define RK3228_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(3)
-#define RK3228_GMAC_SPEED_10M		GRF_CLR_BIT(2)
-#define RK3228_GMAC_SPEED_100M		GRF_BIT(2)
 #define RK3228_GMAC_RMII_CLK_25M	GRF_BIT(7)
 #define RK3228_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(7)
 #define RK3228_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(0)
@@ -426,8 +427,8 @@ static void rk3228_set_to_rmii(struct rk_priv_data *bsp_priv)
 }
 
 static const struct rk_reg_speed_data rk3228_reg_speed_data = {
-	.rmii_10 = RK3228_GMAC_RMII_CLK_2_5M | RK3228_GMAC_SPEED_10M,
-	.rmii_100 = RK3228_GMAC_RMII_CLK_25M | RK3228_GMAC_SPEED_100M,
+	.rmii_10 = RK3228_GMAC_RMII_CLK_2_5M,
+	.rmii_100 = RK3228_GMAC_RMII_CLK_25M,
 };
 
 static int rk3228_set_speed(struct rk_priv_data *bsp_priv,
@@ -458,6 +459,7 @@ static const struct rk_gmac_ops rk3228_ops = {
 
 	.speed_grf_reg = RK3228_GRF_MAC_CON1,
 	.gmii_clk_sel_mask = GENMASK_U16(9, 8),
+	.mac_speed_mask = BIT_U16(2),
 };
 
 #define RK3288_GRF_SOC_CON1	0x0248
@@ -466,8 +468,6 @@ static const struct rk_gmac_ops rk3228_ops = {
 /*RK3288_GRF_SOC_CON1*/
 #define RK3288_GMAC_FLOW_CTRL		GRF_BIT(9)
 #define RK3288_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(9)
-#define RK3288_GMAC_SPEED_10M		GRF_CLR_BIT(10)
-#define RK3288_GMAC_SPEED_100M		GRF_BIT(10)
 #define RK3288_GMAC_RMII_CLK_25M	GRF_BIT(11)
 #define RK3288_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(11)
 
@@ -493,8 +493,8 @@ static void rk3288_set_to_rmii(struct rk_priv_data *bsp_priv)
 }
 
 static const struct rk_reg_speed_data rk3288_reg_speed_data = {
-	.rmii_10 = RK3288_GMAC_RMII_CLK_2_5M | RK3288_GMAC_SPEED_10M,
-	.rmii_100 = RK3288_GMAC_RMII_CLK_25M | RK3288_GMAC_SPEED_100M,
+	.rmii_10 = RK3288_GMAC_RMII_CLK_2_5M,
+	.rmii_100 = RK3288_GMAC_RMII_CLK_25M,
 };
 
 static int rk3288_set_speed(struct rk_priv_data *bsp_priv,
@@ -515,6 +515,7 @@ static const struct rk_gmac_ops rk3288_ops = {
 
 	.speed_grf_reg = RK3288_GRF_SOC_CON1,
 	.gmii_clk_sel_mask = GENMASK_U16(13, 12),
+	.mac_speed_mask = BIT_U16(10),
 };
 
 #define RK3308_GRF_MAC_CON0		0x04a0
@@ -522,16 +523,12 @@ static const struct rk_gmac_ops rk3288_ops = {
 /* RK3308_GRF_MAC_CON0 */
 #define RK3308_GMAC_FLOW_CTRL		GRF_BIT(3)
 #define RK3308_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(3)
-#define RK3308_GMAC_SPEED_10M		GRF_CLR_BIT(0)
-#define RK3308_GMAC_SPEED_100M		GRF_BIT(0)
 
 static void rk3308_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
 }
 
 static const struct rk_reg_speed_data rk3308_reg_speed_data = {
-	.rmii_10 = RK3308_GMAC_SPEED_10M,
-	.rmii_100 = RK3308_GMAC_SPEED_100M,
 };
 
 static int rk3308_set_speed(struct rk_priv_data *bsp_priv,
@@ -549,6 +546,7 @@ static const struct rk_gmac_ops rk3308_ops = {
 	.phy_intf_sel_mask = GENMASK_U16(4, 2),
 
 	.speed_grf_reg = RK3308_GRF_MAC_CON0,
+	.mac_speed_mask = BIT_U16(0),
 };
 
 #define RK3328_GRF_MAC_CON0	0x0900
@@ -563,8 +561,6 @@ static const struct rk_gmac_ops rk3308_ops = {
 /* RK3328_GRF_MAC_CON1 */
 #define RK3328_GMAC_FLOW_CTRL		GRF_BIT(3)
 #define RK3328_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(3)
-#define RK3328_GMAC_SPEED_10M		GRF_CLR_BIT(2)
-#define RK3328_GMAC_SPEED_100M		GRF_BIT(2)
 #define RK3328_GMAC_RMII_CLK_25M	GRF_BIT(7)
 #define RK3328_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(7)
 #define RK3328_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(0)
@@ -609,8 +605,8 @@ static void rk3328_set_to_rmii(struct rk_priv_data *bsp_priv)
 }
 
 static const struct rk_reg_speed_data rk3328_reg_speed_data = {
-	.rmii_10 = RK3328_GMAC_RMII_CLK_2_5M | RK3328_GMAC_SPEED_10M,
-	.rmii_100 = RK3328_GMAC_RMII_CLK_25M | RK3328_GMAC_SPEED_100M,
+	.rmii_10 = RK3328_GMAC_RMII_CLK_2_5M,
+	.rmii_100 = RK3328_GMAC_RMII_CLK_25M,
 };
 
 static int rk3328_set_speed(struct rk_priv_data *bsp_priv,
@@ -639,6 +635,8 @@ static const struct rk_gmac_ops rk3328_ops = {
 	.phy_intf_sel_mask = GENMASK_U16(6, 4),
 	.rmii_mode_mask = BIT_U16(9),
 
+	.mac_speed_mask = BIT_U16(2),
+
 	.regs_valid = true,
 	.regs = {
 		0xff540000, /* gmac2io */
@@ -653,8 +651,6 @@ static const struct rk_gmac_ops rk3328_ops = {
 /* RK3366_GRF_SOC_CON6 */
 #define RK3366_GMAC_FLOW_CTRL		GRF_BIT(8)
 #define RK3366_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(8)
-#define RK3366_GMAC_SPEED_10M		GRF_CLR_BIT(7)
-#define RK3366_GMAC_SPEED_100M		GRF_BIT(7)
 #define RK3366_GMAC_RMII_CLK_25M	GRF_BIT(3)
 #define RK3366_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(3)
 
@@ -680,8 +676,8 @@ static void rk3366_set_to_rmii(struct rk_priv_data *bsp_priv)
 }
 
 static const struct rk_reg_speed_data rk3366_reg_speed_data = {
-	.rmii_10 = RK3366_GMAC_RMII_CLK_2_5M | RK3366_GMAC_SPEED_10M,
-	.rmii_100 = RK3366_GMAC_RMII_CLK_25M | RK3366_GMAC_SPEED_100M,
+	.rmii_10 = RK3366_GMAC_RMII_CLK_2_5M,
+	.rmii_100 = RK3366_GMAC_RMII_CLK_25M,
 };
 
 static int rk3366_set_speed(struct rk_priv_data *bsp_priv,
@@ -702,6 +698,7 @@ static const struct rk_gmac_ops rk3366_ops = {
 
 	.speed_grf_reg = RK3366_GRF_SOC_CON6,
 	.gmii_clk_sel_mask = GENMASK_U16(5, 4),
+	.mac_speed_mask = BIT_U16(7),
 };
 
 #define RK3368_GRF_SOC_CON15	0x043c
@@ -710,8 +707,6 @@ static const struct rk_gmac_ops rk3366_ops = {
 /* RK3368_GRF_SOC_CON15 */
 #define RK3368_GMAC_FLOW_CTRL		GRF_BIT(8)
 #define RK3368_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(8)
-#define RK3368_GMAC_SPEED_10M		GRF_CLR_BIT(7)
-#define RK3368_GMAC_SPEED_100M		GRF_BIT(7)
 #define RK3368_GMAC_RMII_CLK_25M	GRF_BIT(3)
 #define RK3368_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(3)
 
@@ -737,8 +732,8 @@ static void rk3368_set_to_rmii(struct rk_priv_data *bsp_priv)
 }
 
 static const struct rk_reg_speed_data rk3368_reg_speed_data = {
-	.rmii_10 = RK3368_GMAC_RMII_CLK_2_5M | RK3368_GMAC_SPEED_10M,
-	.rmii_100 = RK3368_GMAC_RMII_CLK_25M | RK3368_GMAC_SPEED_100M,
+	.rmii_10 = RK3368_GMAC_RMII_CLK_2_5M,
+	.rmii_100 = RK3368_GMAC_RMII_CLK_25M,
 };
 
 static int rk3368_set_speed(struct rk_priv_data *bsp_priv,
@@ -759,6 +754,7 @@ static const struct rk_gmac_ops rk3368_ops = {
 
 	.speed_grf_reg = RK3368_GRF_SOC_CON15,
 	.gmii_clk_sel_mask = GENMASK_U16(5, 4),
+	.mac_speed_mask = BIT_U16(7),
 };
 
 #define RK3399_GRF_SOC_CON5	0xc214
@@ -767,8 +763,6 @@ static const struct rk_gmac_ops rk3368_ops = {
 /* RK3399_GRF_SOC_CON5 */
 #define RK3399_GMAC_FLOW_CTRL		GRF_BIT(8)
 #define RK3399_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(8)
-#define RK3399_GMAC_SPEED_10M		GRF_CLR_BIT(7)
-#define RK3399_GMAC_SPEED_100M		GRF_BIT(7)
 #define RK3399_GMAC_RMII_CLK_25M	GRF_BIT(3)
 #define RK3399_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(3)
 
@@ -794,8 +788,8 @@ static void rk3399_set_to_rmii(struct rk_priv_data *bsp_priv)
 }
 
 static const struct rk_reg_speed_data rk3399_reg_speed_data = {
-	.rmii_10 = RK3399_GMAC_RMII_CLK_2_5M | RK3399_GMAC_SPEED_10M,
-	.rmii_100 = RK3399_GMAC_RMII_CLK_25M | RK3399_GMAC_SPEED_100M,
+	.rmii_10 = RK3399_GMAC_RMII_CLK_2_5M,
+	.rmii_100 = RK3399_GMAC_RMII_CLK_25M,
 };
 
 static int rk3399_set_speed(struct rk_priv_data *bsp_priv,
@@ -816,6 +810,7 @@ static const struct rk_gmac_ops rk3399_ops = {
 
 	.speed_grf_reg = RK3399_GRF_SOC_CON5,
 	.gmii_clk_sel_mask = GENMASK_U16(5, 4),
+	.mac_speed_mask = BIT_U16(7),
 };
 
 #define RK3506_GRF_SOC_CON8		0x0020
@@ -1361,8 +1356,6 @@ static const struct rk_gmac_ops rk3588_ops = {
 /* RV1108_GRF_GMAC_CON0 */
 #define RV1108_GMAC_FLOW_CTRL		GRF_BIT(3)
 #define RV1108_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(3)
-#define RV1108_GMAC_SPEED_10M		GRF_CLR_BIT(2)
-#define RV1108_GMAC_SPEED_100M		GRF_BIT(2)
 #define RV1108_GMAC_RMII_CLK_25M	GRF_BIT(7)
 #define RV1108_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(7)
 
@@ -1371,8 +1364,8 @@ static void rv1108_set_to_rmii(struct rk_priv_data *bsp_priv)
 }
 
 static const struct rk_reg_speed_data rv1108_reg_speed_data = {
-	.rmii_10 = RV1108_GMAC_RMII_CLK_2_5M | RV1108_GMAC_SPEED_10M,
-	.rmii_100 = RV1108_GMAC_RMII_CLK_25M | RV1108_GMAC_SPEED_100M,
+	.rmii_10 = RV1108_GMAC_RMII_CLK_2_5M,
+	.rmii_100 = RV1108_GMAC_RMII_CLK_25M,
 };
 
 static int rv1108_set_speed(struct rk_priv_data *bsp_priv,
@@ -1390,6 +1383,7 @@ static const struct rk_gmac_ops rv1108_ops = {
 	.phy_intf_sel_mask = GENMASK_U16(6, 4),
 
 	.speed_grf_reg = RV1108_GRF_GMAC_CON0,
+	.mac_speed_mask = BIT_U16(2),
 };
 
 #define RV1126_GRF_GMAC_CON0		0X0070
@@ -1672,6 +1666,7 @@ static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,
 	/* Set the default speed related parameters */
 	bsp_priv->speed_grf_reg = ops->speed_grf_reg;
 	bsp_priv->gmii_clk_sel_mask = ops->gmii_clk_sel_mask;
+	bsp_priv->mac_speed_mask = ops->mac_speed_mask;
 
 	if (ops->init) {
 		ret = ops->init(bsp_priv);
-- 
2.47.3



From quentin.schulz at cherry.de  Mon Dec  1 06:51:44 2025
From: quentin.schulz at cherry.de (Quentin Schulz)
Date: Mon, 1 Dec 2025 15:51:44 +0100
Subject: [PATCH 2/3] arm64: dts: rockchip: add mdio subnode to gmac on
 rk3368
In-Reply-To: <20251020100757.3669681-3-heiko@sntech.de>
References: <20251020100757.3669681-1-heiko@sntech.de>
 <20251020100757.3669681-3-heiko@sntech.de>
Message-ID: <3b497181-6d8a-4c45-b5bd-29415d273f3f@cherry.de>

Hi Heiko,

On 10/20/25 12:07 PM, Heiko Stuebner wrote:
> From: Heiko Stuebner <heiko.stuebner at cherry.de>
> 
> This is needed to actually describe the per-board phys connected
> to the gmac when needed.
> 
> Signed-off-by: Heiko Stuebner <heiko.stuebner at cherry.de>

Reviewed-by: Quentin Schulz <quentin.schulz at cherry.de>

Thanks!
Quentin


From rmk+kernel at armlinux.org.uk  Mon Dec  1 06:51:28 2025
From: rmk+kernel at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 01 Dec 2025 14:51:28 +0000
Subject: [PATCH RFC net-next 09/15] net: stmmac: rk: use rk_encode_wm16() for
 RMII clock
In-Reply-To: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
References: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
Message-ID: <E1vQ5FQ-0000000GNwH-37za@rmk-PC.armlinux.org.uk>

Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
---
 .../net/ethernet/stmicro/stmmac/dwmac-rk.c    | 187 ++++--------------
 1 file changed, 34 insertions(+), 153 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
index 5f586782d595..a77ce36e0da6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -26,11 +26,6 @@
 
 struct rk_priv_data;
 
-struct rk_reg_speed_data {
-	unsigned int rmii_10;
-	unsigned int rmii_100;
-};
-
 struct rk_gmac_ops {
 	int (*init)(struct rk_priv_data *bsp_priv);
 	void (*set_to_rgmii)(struct rk_priv_data *bsp_priv,
@@ -49,6 +44,7 @@ struct rk_gmac_ops {
 
 	u16 speed_grf_reg;
 	u16 gmii_clk_sel_mask;
+	u16 rmii_clk_sel_mask;
 	u16 mac_speed_mask;
 
 	bool speed_reg_php_grf;
@@ -104,6 +100,7 @@ struct rk_priv_data {
 
 	u16 speed_grf_reg;
 	u16 gmii_clk_sel_mask;
+	u16 rmii_clk_sel_mask;
 	u16 mac_speed_mask;
 };
 
@@ -144,7 +141,6 @@ static u32 rk_encode_wm16(u16 val, u16 mask)
 }
 
 static int rk_set_reg_speed(struct rk_priv_data *bsp_priv,
-			    const struct rk_reg_speed_data *rsd,
 			    phy_interface_t interface, int speed)
 {
 	struct regmap *regmap;
@@ -159,17 +155,9 @@ static int rk_set_reg_speed(struct rk_priv_data *bsp_priv,
 		val = rk_encode_wm16(ret, bsp_priv->gmii_clk_sel_mask);
 	} else if (interface == PHY_INTERFACE_MODE_RMII) {
 		val = rk_encode_wm16(speed == SPEED_100,
-				     bsp_priv->mac_speed_mask);
-		if (speed == SPEED_10) {
-			val |= rsd->rmii_10;
-		} else if (speed == SPEED_100) {
-			val |= rsd->rmii_100;
-		} else {
-			/* Phylink will not allow inappropriate speeds for
-			 * interface modes, so this should never happen.
-			 */
-			return -EINVAL;
-		}
+				     bsp_priv->mac_speed_mask) |
+		      rk_encode_wm16(speed == SPEED_100,
+				     bsp_priv->rmii_clk_sel_mask);
 	} else {
 		/* This should never happen, as .get_interfaces() limits
 		 * the interface modes that are supported to RGMII and/or
@@ -345,8 +333,6 @@ static const struct rk_gmac_ops px30_ops = {
 /* RK3128_GRF_MAC_CON1 */
 #define RK3128_GMAC_FLOW_CTRL          GRF_BIT(9)
 #define RK3128_GMAC_FLOW_CTRL_CLR      GRF_CLR_BIT(9)
-#define RK3128_GMAC_RMII_CLK_25M       GRF_BIT(11)
-#define RK3128_GMAC_RMII_CLK_2_5M      GRF_CLR_BIT(11)
 
 static void rk3128_set_to_rgmii(struct rk_priv_data *bsp_priv,
 				int tx_delay, int rx_delay)
@@ -361,16 +347,10 @@ static void rk3128_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
 }
 
-static const struct rk_reg_speed_data rk3128_reg_speed_data = {
-	.rmii_10 = RK3128_GMAC_RMII_CLK_2_5M,
-	.rmii_100 = RK3128_GMAC_RMII_CLK_25M,
-};
-
 static int rk3128_set_speed(struct rk_priv_data *bsp_priv,
 			    phy_interface_t interface, int speed)
 {
-	return rk_set_reg_speed(bsp_priv, &rk3128_reg_speed_data,
-				interface, speed);
+	return rk_set_reg_speed(bsp_priv, interface, speed);
 }
 
 static const struct rk_gmac_ops rk3128_ops = {
@@ -384,6 +364,7 @@ static const struct rk_gmac_ops rk3128_ops = {
 
 	.speed_grf_reg = RK3128_GRF_MAC_CON1,
 	.gmii_clk_sel_mask = GENMASK_U16(13, 12),
+	.rmii_clk_sel_mask = BIT_U16(11),
 	.mac_speed_mask = BIT_U16(10),
 };
 
@@ -399,8 +380,6 @@ static const struct rk_gmac_ops rk3128_ops = {
 /* RK3228_GRF_MAC_CON1 */
 #define RK3228_GMAC_FLOW_CTRL		GRF_BIT(3)
 #define RK3228_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(3)
-#define RK3228_GMAC_RMII_CLK_25M	GRF_BIT(7)
-#define RK3228_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(7)
 #define RK3228_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(0)
 #define RK3228_GMAC_TXCLK_DLY_DISABLE	GRF_CLR_BIT(0)
 #define RK3228_GMAC_RXCLK_DLY_ENABLE	GRF_BIT(1)
@@ -426,16 +405,10 @@ static void rk3228_set_to_rmii(struct rk_priv_data *bsp_priv)
 	regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1, GRF_BIT(11));
 }
 
-static const struct rk_reg_speed_data rk3228_reg_speed_data = {
-	.rmii_10 = RK3228_GMAC_RMII_CLK_2_5M,
-	.rmii_100 = RK3228_GMAC_RMII_CLK_25M,
-};
-
 static int rk3228_set_speed(struct rk_priv_data *bsp_priv,
 			    phy_interface_t interface, int speed)
 {
-	return rk_set_reg_speed(bsp_priv, &rk3228_reg_speed_data,
-				interface, speed);
+	return rk_set_reg_speed(bsp_priv, interface, speed);
 }
 
 static void rk3228_integrated_phy_powerup(struct rk_priv_data *priv)
@@ -459,6 +432,7 @@ static const struct rk_gmac_ops rk3228_ops = {
 
 	.speed_grf_reg = RK3228_GRF_MAC_CON1,
 	.gmii_clk_sel_mask = GENMASK_U16(9, 8),
+	.rmii_clk_sel_mask = BIT_U16(7),
 	.mac_speed_mask = BIT_U16(2),
 };
 
@@ -468,8 +442,6 @@ static const struct rk_gmac_ops rk3228_ops = {
 /*RK3288_GRF_SOC_CON1*/
 #define RK3288_GMAC_FLOW_CTRL		GRF_BIT(9)
 #define RK3288_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(9)
-#define RK3288_GMAC_RMII_CLK_25M	GRF_BIT(11)
-#define RK3288_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(11)
 
 /*RK3288_GRF_SOC_CON3*/
 #define RK3288_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(14)
@@ -492,16 +464,10 @@ static void rk3288_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
 }
 
-static const struct rk_reg_speed_data rk3288_reg_speed_data = {
-	.rmii_10 = RK3288_GMAC_RMII_CLK_2_5M,
-	.rmii_100 = RK3288_GMAC_RMII_CLK_25M,
-};
-
 static int rk3288_set_speed(struct rk_priv_data *bsp_priv,
 			    phy_interface_t interface, int speed)
 {
-	return rk_set_reg_speed(bsp_priv, &rk3288_reg_speed_data,
-				interface, speed);
+	return rk_set_reg_speed(bsp_priv, interface, speed);
 }
 
 static const struct rk_gmac_ops rk3288_ops = {
@@ -515,6 +481,7 @@ static const struct rk_gmac_ops rk3288_ops = {
 
 	.speed_grf_reg = RK3288_GRF_SOC_CON1,
 	.gmii_clk_sel_mask = GENMASK_U16(13, 12),
+	.rmii_clk_sel_mask = BIT_U16(11),
 	.mac_speed_mask = BIT_U16(10),
 };
 
@@ -561,8 +528,6 @@ static const struct rk_gmac_ops rk3308_ops = {
 /* RK3328_GRF_MAC_CON1 */
 #define RK3328_GMAC_FLOW_CTRL		GRF_BIT(3)
 #define RK3328_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(3)
-#define RK3328_GMAC_RMII_CLK_25M	GRF_BIT(7)
-#define RK3328_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(7)
 #define RK3328_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(0)
 #define RK3328_GMAC_RXCLK_DLY_ENABLE	GRF_BIT(1)
 
@@ -604,16 +569,10 @@ static void rk3328_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
 }
 
-static const struct rk_reg_speed_data rk3328_reg_speed_data = {
-	.rmii_10 = RK3328_GMAC_RMII_CLK_2_5M,
-	.rmii_100 = RK3328_GMAC_RMII_CLK_25M,
-};
-
 static int rk3328_set_speed(struct rk_priv_data *bsp_priv,
 			    phy_interface_t interface, int speed)
 {
-	return rk_set_reg_speed(bsp_priv, &rk3328_reg_speed_data,
-				interface, speed);
+	return rk_set_reg_speed(bsp_priv, interface, speed);
 }
 
 static void rk3328_integrated_phy_powerup(struct rk_priv_data *priv)
@@ -635,6 +594,7 @@ static const struct rk_gmac_ops rk3328_ops = {
 	.phy_intf_sel_mask = GENMASK_U16(6, 4),
 	.rmii_mode_mask = BIT_U16(9),
 
+	.rmii_clk_sel_mask = BIT_U16(7),
 	.mac_speed_mask = BIT_U16(2),
 
 	.regs_valid = true,
@@ -651,8 +611,6 @@ static const struct rk_gmac_ops rk3328_ops = {
 /* RK3366_GRF_SOC_CON6 */
 #define RK3366_GMAC_FLOW_CTRL		GRF_BIT(8)
 #define RK3366_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(8)
-#define RK3366_GMAC_RMII_CLK_25M	GRF_BIT(3)
-#define RK3366_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(3)
 
 /* RK3366_GRF_SOC_CON7 */
 #define RK3366_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(7)
@@ -675,16 +633,10 @@ static void rk3366_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
 }
 
-static const struct rk_reg_speed_data rk3366_reg_speed_data = {
-	.rmii_10 = RK3366_GMAC_RMII_CLK_2_5M,
-	.rmii_100 = RK3366_GMAC_RMII_CLK_25M,
-};
-
 static int rk3366_set_speed(struct rk_priv_data *bsp_priv,
 			    phy_interface_t interface, int speed)
 {
-	return rk_set_reg_speed(bsp_priv, &rk3366_reg_speed_data,
-				interface, speed);
+	return rk_set_reg_speed(bsp_priv, interface, speed);
 }
 
 static const struct rk_gmac_ops rk3366_ops = {
@@ -698,6 +650,7 @@ static const struct rk_gmac_ops rk3366_ops = {
 
 	.speed_grf_reg = RK3366_GRF_SOC_CON6,
 	.gmii_clk_sel_mask = GENMASK_U16(5, 4),
+	.rmii_clk_sel_mask = BIT_U16(3),
 	.mac_speed_mask = BIT_U16(7),
 };
 
@@ -707,8 +660,6 @@ static const struct rk_gmac_ops rk3366_ops = {
 /* RK3368_GRF_SOC_CON15 */
 #define RK3368_GMAC_FLOW_CTRL		GRF_BIT(8)
 #define RK3368_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(8)
-#define RK3368_GMAC_RMII_CLK_25M	GRF_BIT(3)
-#define RK3368_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(3)
 
 /* RK3368_GRF_SOC_CON16 */
 #define RK3368_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(7)
@@ -731,16 +682,10 @@ static void rk3368_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
 }
 
-static const struct rk_reg_speed_data rk3368_reg_speed_data = {
-	.rmii_10 = RK3368_GMAC_RMII_CLK_2_5M,
-	.rmii_100 = RK3368_GMAC_RMII_CLK_25M,
-};
-
 static int rk3368_set_speed(struct rk_priv_data *bsp_priv,
 			    phy_interface_t interface, int speed)
 {
-	return rk_set_reg_speed(bsp_priv, &rk3368_reg_speed_data,
-				interface, speed);
+	return rk_set_reg_speed(bsp_priv, interface, speed);
 }
 
 static const struct rk_gmac_ops rk3368_ops = {
@@ -754,6 +699,7 @@ static const struct rk_gmac_ops rk3368_ops = {
 
 	.speed_grf_reg = RK3368_GRF_SOC_CON15,
 	.gmii_clk_sel_mask = GENMASK_U16(5, 4),
+	.rmii_clk_sel_mask = BIT_U16(3),
 	.mac_speed_mask = BIT_U16(7),
 };
 
@@ -763,8 +709,6 @@ static const struct rk_gmac_ops rk3368_ops = {
 /* RK3399_GRF_SOC_CON5 */
 #define RK3399_GMAC_FLOW_CTRL		GRF_BIT(8)
 #define RK3399_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(8)
-#define RK3399_GMAC_RMII_CLK_25M	GRF_BIT(3)
-#define RK3399_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(3)
 
 /* RK3399_GRF_SOC_CON6 */
 #define RK3399_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(7)
@@ -787,16 +731,10 @@ static void rk3399_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
 }
 
-static const struct rk_reg_speed_data rk3399_reg_speed_data = {
-	.rmii_10 = RK3399_GMAC_RMII_CLK_2_5M,
-	.rmii_100 = RK3399_GMAC_RMII_CLK_25M,
-};
-
 static int rk3399_set_speed(struct rk_priv_data *bsp_priv,
 			    phy_interface_t interface, int speed)
 {
-	return rk_set_reg_speed(bsp_priv, &rk3399_reg_speed_data,
-				interface, speed);
+	return rk_set_reg_speed(bsp_priv, interface, speed);
 }
 
 static const struct rk_gmac_ops rk3399_ops = {
@@ -810,6 +748,7 @@ static const struct rk_gmac_ops rk3399_ops = {
 
 	.speed_grf_reg = RK3399_GRF_SOC_CON5,
 	.gmii_clk_sel_mask = GENMASK_U16(5, 4),
+	.rmii_clk_sel_mask = BIT_U16(3),
 	.mac_speed_mask = BIT_U16(7),
 };
 
@@ -818,9 +757,6 @@ static const struct rk_gmac_ops rk3399_ops = {
 
 #define RK3506_GMAC_RMII_MODE		GRF_BIT(1)
 
-#define RK3506_GMAC_CLK_RMII_DIV2	GRF_BIT(3)
-#define RK3506_GMAC_CLK_RMII_DIV20	GRF_CLR_BIT(3)
-
 #define RK3506_GMAC_CLK_SELECT_CRU	GRF_CLR_BIT(5)
 #define RK3506_GMAC_CLK_SELECT_IO	GRF_BIT(5)
 
@@ -851,16 +787,10 @@ static void rk3506_set_to_rmii(struct rk_priv_data *bsp_priv)
 	regmap_write(bsp_priv->grf, offset, RK3506_GMAC_RMII_MODE);
 }
 
-static const struct rk_reg_speed_data rk3506_reg_speed_data = {
-	.rmii_10 = RK3506_GMAC_CLK_RMII_DIV20,
-	.rmii_100 = RK3506_GMAC_CLK_RMII_DIV2,
-};
-
 static int rk3506_set_speed(struct rk_priv_data *bsp_priv,
 			    phy_interface_t interface, int speed)
 {
-	return rk_set_reg_speed(bsp_priv, &rk3506_reg_speed_data,
-				interface, speed);
+	return rk_set_reg_speed(bsp_priv, interface, speed);
 }
 
 static void rk3506_set_clock_selection(struct rk_priv_data *bsp_priv,
@@ -882,6 +812,9 @@ static const struct rk_gmac_ops rk3506_ops = {
 	.set_to_rmii = rk3506_set_to_rmii,
 	.set_speed = rk3506_set_speed,
 	.set_clock_selection = rk3506_set_clock_selection,
+
+	.rmii_clk_sel_mask = BIT_U16(3),
+
 	.regs_valid = true,
 	.regs = {
 		0xff4c8000, /* gmac0 */
@@ -911,11 +844,6 @@ static const struct rk_gmac_ops rk3506_ops = {
 #define RK3528_GMAC1_CLK_SELECT_CRU	GRF_CLR_BIT(12)
 #define RK3528_GMAC1_CLK_SELECT_IO	GRF_BIT(12)
 
-#define RK3528_GMAC0_CLK_RMII_DIV2	GRF_BIT(3)
-#define RK3528_GMAC0_CLK_RMII_DIV20	GRF_CLR_BIT(3)
-#define RK3528_GMAC1_CLK_RMII_DIV2	GRF_BIT(10)
-#define RK3528_GMAC1_CLK_RMII_DIV20	GRF_CLR_BIT(10)
-
 #define RK3528_GMAC0_CLK_RMII_GATE	GRF_BIT(2)
 #define RK3528_GMAC0_CLK_RMII_NOGATE	GRF_CLR_BIT(2)
 #define RK3528_GMAC1_CLK_RMII_GATE	GRF_BIT(9)
@@ -926,11 +854,13 @@ static int rk3528_init(struct rk_priv_data *bsp_priv)
 	switch (bsp_priv->id) {
 	case 0:
 		bsp_priv->speed_grf_reg = RK3528_VO_GRF_GMAC_CON;
+		bsp_priv->rmii_clk_sel_mask = BIT_U16(3);
 		return 0;
 
 	case 1:
 		bsp_priv->speed_grf_reg = RK3528_VPU_GRF_GMAC_CON5;
 		bsp_priv->gmii_clk_sel_mask = GENMASK_U16(11, 10);
+		bsp_priv->rmii_clk_sel_mask = BIT_U16(10);
 		return 0;
 
 	default:
@@ -963,27 +893,10 @@ static void rk3528_set_to_rmii(struct rk_priv_data *bsp_priv)
 			     RK3528_GMAC0_CLK_RMII_DIV2);
 }
 
-static const struct rk_reg_speed_data rk3528_gmac0_reg_speed_data = {
-	.rmii_10 = RK3528_GMAC0_CLK_RMII_DIV20,
-	.rmii_100 = RK3528_GMAC0_CLK_RMII_DIV2,
-};
-
-static const struct rk_reg_speed_data rk3528_gmac1_reg_speed_data = {
-	.rmii_10 = RK3528_GMAC1_CLK_RMII_DIV20,
-	.rmii_100 = RK3528_GMAC1_CLK_RMII_DIV2,
-};
-
 static int rk3528_set_speed(struct rk_priv_data *bsp_priv,
 			    phy_interface_t interface, int speed)
 {
-	const struct rk_reg_speed_data *rsd;
-
-	if (bsp_priv->id == 1)
-		rsd = &rk3528_gmac1_reg_speed_data;
-	else
-		rsd = &rk3528_gmac0_reg_speed_data;
-
-	return rk_set_reg_speed(bsp_priv, rsd, interface, speed);
+	return rk_set_reg_speed(bsp_priv, interface, speed);
 }
 
 static void rk3528_set_clock_selection(struct rk_priv_data *bsp_priv,
@@ -1123,9 +1036,6 @@ static const struct rk_gmac_ops rk3568_ops = {
 #define RK3576_GMAC_CLK_SELECT_IO		GRF_BIT(7)
 #define RK3576_GMAC_CLK_SELECT_CRU		GRF_CLR_BIT(7)
 
-#define RK3576_GMAC_CLK_RMII_DIV2		GRF_BIT(5)
-#define RK3576_GMAC_CLK_RMII_DIV20		GRF_CLR_BIT(5)
-
 #define RK3576_GMAC_CLK_RMII_GATE		GRF_BIT(4)
 #define RK3576_GMAC_CLK_RMII_NOGATE		GRF_CLR_BIT(4)
 
@@ -1174,16 +1084,10 @@ static void rk3576_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
 }
 
-static const struct rk_reg_speed_data rk3578_reg_speed_data = {
-	.rmii_10 = RK3576_GMAC_CLK_RMII_DIV20,
-	.rmii_100 = RK3576_GMAC_CLK_RMII_DIV2,
-};
-
 static int rk3576_set_gmac_speed(struct rk_priv_data *bsp_priv,
 				 phy_interface_t interface, int speed)
 {
-	return rk_set_reg_speed(bsp_priv, &rk3578_reg_speed_data,
-				interface, speed);
+	return rk_set_reg_speed(bsp_priv, interface, speed);
 }
 
 static void rk3576_set_clock_selection(struct rk_priv_data *bsp_priv, bool input,
@@ -1212,6 +1116,7 @@ static const struct rk_gmac_ops rk3576_ops = {
 	.rmii_mode_mask = BIT_U16(3),
 
 	.gmii_clk_sel_mask = GENMASK_U16(6, 5),
+	.rmii_clk_sel_mask = BIT_U16(5),
 
 	.php_grf_required = true,
 	.regs_valid = true,
@@ -1245,9 +1150,6 @@ static const struct rk_gmac_ops rk3576_ops = {
 #define RK3588_GMAC_CLK_SELECT_CRU(id)		GRF_BIT(5 * (id) + 4)
 #define RK3588_GMAC_CLK_SELECT_IO(id)		GRF_CLR_BIT(5 * (id) + 4)
 
-#define RK3588_GMA_CLK_RMII_DIV2(id)		GRF_BIT(5 * (id) + 2)
-#define RK3588_GMA_CLK_RMII_DIV20(id)		GRF_CLR_BIT(5 * (id) + 2)
-
 #define RK3588_GMAC_CLK_RMII_GATE(id)		GRF_BIT(5 * (id) + 1)
 #define RK3588_GMAC_CLK_RMII_NOGATE(id)		GRF_CLR_BIT(5 * (id) + 1)
 
@@ -1257,11 +1159,13 @@ static int rk3588_init(struct rk_priv_data *bsp_priv)
 	case 0:
 		bsp_priv->phy_intf_sel_mask = GENMASK_U16(5, 3);
 		bsp_priv->gmii_clk_sel_mask = GENMASK_U16(3, 2);
+		bsp_priv->rmii_clk_sel_mask = BIT_U16(2);
 		return 0;
 
 	case 1:
 		bsp_priv->phy_intf_sel_mask = GENMASK_U16(11, 9);
 		bsp_priv->gmii_clk_sel_mask = GENMASK_U16(8, 7);
+		bsp_priv->rmii_clk_sel_mask = BIT_U16(7);
 		return 0;
 
 	default:
@@ -1295,27 +1199,10 @@ static void rk3588_set_to_rmii(struct rk_priv_data *bsp_priv)
 		     RK3588_GMAC_CLK_RMII_MODE(bsp_priv->id));
 }
 
-static const struct rk_reg_speed_data rk3588_gmac0_speed_data = {
-	.rmii_10 = RK3588_GMA_CLK_RMII_DIV20(0),
-	.rmii_100 = RK3588_GMA_CLK_RMII_DIV2(0),
-};
-
-static const struct rk_reg_speed_data rk3588_gmac1_speed_data = {
-	.rmii_10 = RK3588_GMA_CLK_RMII_DIV20(1),
-	.rmii_100 = RK3588_GMA_CLK_RMII_DIV2(1),
-};
-
 static int rk3588_set_gmac_speed(struct rk_priv_data *bsp_priv,
 				 phy_interface_t interface, int speed)
 {
-	const struct rk_reg_speed_data *rsd;
-
-	if (bsp_priv->id == 0)
-		rsd = &rk3588_gmac0_speed_data;
-	else
-		rsd = &rk3588_gmac1_speed_data;
-
-	return rk_set_reg_speed(bsp_priv, rsd, interface, speed);
+	return rk_set_reg_speed(bsp_priv, interface, speed);
 }
 
 static void rk3588_set_clock_selection(struct rk_priv_data *bsp_priv, bool input,
@@ -1356,23 +1243,15 @@ static const struct rk_gmac_ops rk3588_ops = {
 /* RV1108_GRF_GMAC_CON0 */
 #define RV1108_GMAC_FLOW_CTRL		GRF_BIT(3)
 #define RV1108_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(3)
-#define RV1108_GMAC_RMII_CLK_25M	GRF_BIT(7)
-#define RV1108_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(7)
 
 static void rv1108_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
 }
 
-static const struct rk_reg_speed_data rv1108_reg_speed_data = {
-	.rmii_10 = RV1108_GMAC_RMII_CLK_2_5M,
-	.rmii_100 = RV1108_GMAC_RMII_CLK_25M,
-};
-
 static int rv1108_set_speed(struct rk_priv_data *bsp_priv,
 			    phy_interface_t interface, int speed)
 {
-	return rk_set_reg_speed(bsp_priv, &rv1108_reg_speed_data,
-				interface, speed);
+	return rk_set_reg_speed(bsp_priv, interface, speed);
 }
 
 static const struct rk_gmac_ops rv1108_ops = {
@@ -1383,6 +1262,7 @@ static const struct rk_gmac_ops rv1108_ops = {
 	.phy_intf_sel_mask = GENMASK_U16(6, 4),
 
 	.speed_grf_reg = RV1108_GRF_GMAC_CON0,
+	.rmii_clk_sel_mask = BIT_U16(7),
 	.mac_speed_mask = BIT_U16(2),
 };
 
@@ -1666,6 +1546,7 @@ static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,
 	/* Set the default speed related parameters */
 	bsp_priv->speed_grf_reg = ops->speed_grf_reg;
 	bsp_priv->gmii_clk_sel_mask = ops->gmii_clk_sel_mask;
+	bsp_priv->rmii_clk_sel_mask = ops->rmii_clk_sel_mask;
 	bsp_priv->mac_speed_mask = ops->mac_speed_mask;
 
 	if (ops->init) {
-- 
2.47.3



From rmk+kernel at armlinux.org.uk  Mon Dec  1 06:51:38 2025
From: rmk+kernel at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 01 Dec 2025 14:51:38 +0000
Subject: [PATCH RFC net-next 11/15] net: stmmac: rk: convert px30
In-Reply-To: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
References: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
Message-ID: <E1vQ5Fa-0000000GNwT-48iR@rmk-PC.armlinux.org.uk>

Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
---
 .../net/ethernet/stmicro/stmmac/dwmac-rk.c    | 38 ++-----------------
 1 file changed, 4 insertions(+), 34 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
index c26bd22658c6..4c80a73bbf74 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -237,49 +237,19 @@ static void rk_gmac_integrated_fephy_powerdown(struct rk_priv_data *priv,
 
 #define PX30_GRF_GMAC_CON1		0x0904
 
-/* PX30_GRF_GMAC_CON1 */
-#define PX30_GMAC_SPEED_10M		GRF_CLR_BIT(2)
-#define PX30_GMAC_SPEED_100M		GRF_BIT(2)
-
 static void px30_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
 }
 
-static int px30_set_speed(struct rk_priv_data *bsp_priv,
-			  phy_interface_t interface, int speed)
-{
-	struct clk *clk_mac_speed = bsp_priv->clks[RK_CLK_MAC_SPEED].clk;
-	struct device *dev = bsp_priv->dev;
-	unsigned int con1;
-	long rate;
-
-	if (!clk_mac_speed) {
-		dev_err(dev, "%s: Missing clk_mac_speed clock\n", __func__);
-		return -EINVAL;
-	}
-
-	if (speed == 10) {
-		con1 = PX30_GMAC_SPEED_10M;
-		rate = 2500000;
-	} else if (speed == 100) {
-		con1 = PX30_GMAC_SPEED_100M;
-		rate = 25000000;
-	} else {
-		dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
-		return -EINVAL;
-	}
-
-	regmap_write(bsp_priv->grf, PX30_GRF_GMAC_CON1, con1);
-
-	return clk_set_rate(clk_mac_speed, rate);
-}
-
 static const struct rk_gmac_ops px30_ops = {
 	.set_to_rmii = px30_set_to_rmii,
-	.set_speed = px30_set_speed,
+	.set_speed = rk_set_clk_mac_speed,
 
 	.phy_intf_sel_grf_reg = PX30_GRF_GMAC_CON1,
 	.phy_intf_sel_mask = GENMASK_U16(6, 4),
+
+	.speed_grf_reg = PX30_GRF_GMAC_CON1,
+	.mac_speed_mask = BIT_U16(2),
 };
 
 #define RK3128_GRF_MAC_CON0	0x0168
-- 
2.47.3



From rmk+kernel at armlinux.org.uk  Mon Dec  1 06:51:33 2025
From: rmk+kernel at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 01 Dec 2025 14:51:33 +0000
Subject: [PATCH RFC net-next 10/15] net: stmmac: rk: move speed register into
 bsp_priv
In-Reply-To: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
References: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
Message-ID: <E1vQ5FV-0000000GNwO-3br0@rmk-PC.armlinux.org.uk>

Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
---
 .../net/ethernet/stmicro/stmmac/dwmac-rk.c    | 169 ++++--------------
 1 file changed, 34 insertions(+), 135 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
index a77ce36e0da6..c26bd22658c6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -140,43 +140,6 @@ static u32 rk_encode_wm16(u16 val, u16 mask)
 	return reg_val;
 }
 
-static int rk_set_reg_speed(struct rk_priv_data *bsp_priv,
-			    phy_interface_t interface, int speed)
-{
-	struct regmap *regmap;
-	unsigned int val;
-	int ret;
-
-	if (phy_interface_mode_is_rgmii(interface)) {
-		ret = rk_gmac_rgmii_clk_div(speed);
-		if (ret < 0)
-			return ret;
-
-		val = rk_encode_wm16(ret, bsp_priv->gmii_clk_sel_mask);
-	} else if (interface == PHY_INTERFACE_MODE_RMII) {
-		val = rk_encode_wm16(speed == SPEED_100,
-				     bsp_priv->mac_speed_mask) |
-		      rk_encode_wm16(speed == SPEED_100,
-				     bsp_priv->rmii_clk_sel_mask);
-	} else {
-		/* This should never happen, as .get_interfaces() limits
-		 * the interface modes that are supported to RGMII and/or
-		 * RMII.
-		 */
-		return -EINVAL;
-	}
-
-	if (bsp_priv->ops->speed_reg_php_grf)
-		regmap = bsp_priv->php_grf;
-	else
-		regmap = bsp_priv->grf;
-
-	regmap_write(regmap, bsp_priv->speed_grf_reg, val);
-
-	return 0;
-
-}
-
 static int rk_set_clk_mac_speed(struct rk_priv_data *bsp_priv,
 				phy_interface_t interface, int speed)
 {
@@ -347,16 +310,9 @@ static void rk3128_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
 }
 
-static int rk3128_set_speed(struct rk_priv_data *bsp_priv,
-			    phy_interface_t interface, int speed)
-{
-	return rk_set_reg_speed(bsp_priv, interface, speed);
-}
-
 static const struct rk_gmac_ops rk3128_ops = {
 	.set_to_rgmii = rk3128_set_to_rgmii,
 	.set_to_rmii = rk3128_set_to_rmii,
-	.set_speed = rk3128_set_speed,
 
 	.phy_intf_sel_grf_reg = RK3128_GRF_MAC_CON1,
 	.phy_intf_sel_mask = GENMASK_U16(8, 6),
@@ -405,12 +361,6 @@ static void rk3228_set_to_rmii(struct rk_priv_data *bsp_priv)
 	regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1, GRF_BIT(11));
 }
 
-static int rk3228_set_speed(struct rk_priv_data *bsp_priv,
-			    phy_interface_t interface, int speed)
-{
-	return rk_set_reg_speed(bsp_priv, interface, speed);
-}
-
 static void rk3228_integrated_phy_powerup(struct rk_priv_data *priv)
 {
 	regmap_write(priv->grf, RK3228_GRF_CON_MUX,
@@ -422,7 +372,6 @@ static void rk3228_integrated_phy_powerup(struct rk_priv_data *priv)
 static const struct rk_gmac_ops rk3228_ops = {
 	.set_to_rgmii = rk3228_set_to_rgmii,
 	.set_to_rmii = rk3228_set_to_rmii,
-	.set_speed = rk3228_set_speed,
 	.integrated_phy_powerup = rk3228_integrated_phy_powerup,
 	.integrated_phy_powerdown = rk_gmac_integrated_ephy_powerdown,
 
@@ -464,16 +413,9 @@ static void rk3288_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
 }
 
-static int rk3288_set_speed(struct rk_priv_data *bsp_priv,
-			    phy_interface_t interface, int speed)
-{
-	return rk_set_reg_speed(bsp_priv, interface, speed);
-}
-
 static const struct rk_gmac_ops rk3288_ops = {
 	.set_to_rgmii = rk3288_set_to_rgmii,
 	.set_to_rmii = rk3288_set_to_rmii,
-	.set_speed = rk3288_set_speed,
 
 	.phy_intf_sel_grf_reg = RK3288_GRF_SOC_CON1,
 	.phy_intf_sel_mask = GENMASK_U16(8, 6),
@@ -495,19 +437,8 @@ static void rk3308_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
 }
 
-static const struct rk_reg_speed_data rk3308_reg_speed_data = {
-};
-
-static int rk3308_set_speed(struct rk_priv_data *bsp_priv,
-			    phy_interface_t interface, int speed)
-{
-	return rk_set_reg_speed(bsp_priv, &rk3308_reg_speed_data,
-				interface, speed);
-}
-
 static const struct rk_gmac_ops rk3308_ops = {
 	.set_to_rmii = rk3308_set_to_rmii,
-	.set_speed = rk3308_set_speed,
 
 	.phy_intf_sel_grf_reg = RK3308_GRF_MAC_CON0,
 	.phy_intf_sel_mask = GENMASK_U16(4, 2),
@@ -569,12 +500,6 @@ static void rk3328_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
 }
 
-static int rk3328_set_speed(struct rk_priv_data *bsp_priv,
-			    phy_interface_t interface, int speed)
-{
-	return rk_set_reg_speed(bsp_priv, interface, speed);
-}
-
 static void rk3328_integrated_phy_powerup(struct rk_priv_data *priv)
 {
 	regmap_write(priv->grf, RK3328_GRF_MACPHY_CON1,
@@ -587,7 +512,6 @@ static const struct rk_gmac_ops rk3328_ops = {
 	.init = rk3328_init,
 	.set_to_rgmii = rk3328_set_to_rgmii,
 	.set_to_rmii = rk3328_set_to_rmii,
-	.set_speed = rk3328_set_speed,
 	.integrated_phy_powerup = rk3328_integrated_phy_powerup,
 	.integrated_phy_powerdown = rk_gmac_integrated_ephy_powerdown,
 
@@ -633,16 +557,9 @@ static void rk3366_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
 }
 
-static int rk3366_set_speed(struct rk_priv_data *bsp_priv,
-			    phy_interface_t interface, int speed)
-{
-	return rk_set_reg_speed(bsp_priv, interface, speed);
-}
-
 static const struct rk_gmac_ops rk3366_ops = {
 	.set_to_rgmii = rk3366_set_to_rgmii,
 	.set_to_rmii = rk3366_set_to_rmii,
-	.set_speed = rk3366_set_speed,
 
 	.phy_intf_sel_grf_reg = RK3366_GRF_SOC_CON6,
 	.phy_intf_sel_mask = GENMASK_U16(11, 9),
@@ -682,16 +599,9 @@ static void rk3368_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
 }
 
-static int rk3368_set_speed(struct rk_priv_data *bsp_priv,
-			    phy_interface_t interface, int speed)
-{
-	return rk_set_reg_speed(bsp_priv, interface, speed);
-}
-
 static const struct rk_gmac_ops rk3368_ops = {
 	.set_to_rgmii = rk3368_set_to_rgmii,
 	.set_to_rmii = rk3368_set_to_rmii,
-	.set_speed = rk3368_set_speed,
 
 	.phy_intf_sel_grf_reg = RK3368_GRF_SOC_CON15,
 	.phy_intf_sel_mask = GENMASK_U16(11, 9),
@@ -731,16 +641,9 @@ static void rk3399_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
 }
 
-static int rk3399_set_speed(struct rk_priv_data *bsp_priv,
-			    phy_interface_t interface, int speed)
-{
-	return rk_set_reg_speed(bsp_priv, interface, speed);
-}
-
 static const struct rk_gmac_ops rk3399_ops = {
 	.set_to_rgmii = rk3399_set_to_rgmii,
 	.set_to_rmii = rk3399_set_to_rmii,
-	.set_speed = rk3399_set_speed,
 
 	.phy_intf_sel_grf_reg = RK3399_GRF_SOC_CON5,
 	.phy_intf_sel_mask = GENMASK_U16(11, 9),
@@ -787,12 +690,6 @@ static void rk3506_set_to_rmii(struct rk_priv_data *bsp_priv)
 	regmap_write(bsp_priv->grf, offset, RK3506_GMAC_RMII_MODE);
 }
 
-static int rk3506_set_speed(struct rk_priv_data *bsp_priv,
-			    phy_interface_t interface, int speed)
-{
-	return rk_set_reg_speed(bsp_priv, interface, speed);
-}
-
 static void rk3506_set_clock_selection(struct rk_priv_data *bsp_priv,
 				       bool input, bool enable)
 {
@@ -810,7 +707,6 @@ static void rk3506_set_clock_selection(struct rk_priv_data *bsp_priv,
 static const struct rk_gmac_ops rk3506_ops = {
 	.init = rk3506_init,
 	.set_to_rmii = rk3506_set_to_rmii,
-	.set_speed = rk3506_set_speed,
 	.set_clock_selection = rk3506_set_clock_selection,
 
 	.rmii_clk_sel_mask = BIT_U16(3),
@@ -893,12 +789,6 @@ static void rk3528_set_to_rmii(struct rk_priv_data *bsp_priv)
 			     RK3528_GMAC0_CLK_RMII_DIV2);
 }
 
-static int rk3528_set_speed(struct rk_priv_data *bsp_priv,
-			    phy_interface_t interface, int speed)
-{
-	return rk_set_reg_speed(bsp_priv, interface, speed);
-}
-
 static void rk3528_set_clock_selection(struct rk_priv_data *bsp_priv,
 				       bool input, bool enable)
 {
@@ -931,7 +821,6 @@ static const struct rk_gmac_ops rk3528_ops = {
 	.init = rk3528_init,
 	.set_to_rgmii = rk3528_set_to_rgmii,
 	.set_to_rmii = rk3528_set_to_rmii,
-	.set_speed = rk3528_set_speed,
 	.set_clock_selection = rk3528_set_clock_selection,
 	.integrated_phy_powerup = rk3528_integrated_phy_powerup,
 	.integrated_phy_powerdown = rk3528_integrated_phy_powerdown,
@@ -1084,12 +973,6 @@ static void rk3576_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
 }
 
-static int rk3576_set_gmac_speed(struct rk_priv_data *bsp_priv,
-				 phy_interface_t interface, int speed)
-{
-	return rk_set_reg_speed(bsp_priv, interface, speed);
-}
-
 static void rk3576_set_clock_selection(struct rk_priv_data *bsp_priv, bool input,
 				       bool enable)
 {
@@ -1110,7 +993,6 @@ static const struct rk_gmac_ops rk3576_ops = {
 	.init = rk3576_init,
 	.set_to_rgmii = rk3576_set_to_rgmii,
 	.set_to_rmii = rk3576_set_to_rmii,
-	.set_speed = rk3576_set_gmac_speed,
 	.set_clock_selection = rk3576_set_clock_selection,
 
 	.rmii_mode_mask = BIT_U16(3),
@@ -1199,12 +1081,6 @@ static void rk3588_set_to_rmii(struct rk_priv_data *bsp_priv)
 		     RK3588_GMAC_CLK_RMII_MODE(bsp_priv->id));
 }
 
-static int rk3588_set_gmac_speed(struct rk_priv_data *bsp_priv,
-				 phy_interface_t interface, int speed)
-{
-	return rk_set_reg_speed(bsp_priv, interface, speed);
-}
-
 static void rk3588_set_clock_selection(struct rk_priv_data *bsp_priv, bool input,
 				       bool enable)
 {
@@ -1221,7 +1097,6 @@ static const struct rk_gmac_ops rk3588_ops = {
 	.init = rk3588_init,
 	.set_to_rgmii = rk3588_set_to_rgmii,
 	.set_to_rmii = rk3588_set_to_rmii,
-	.set_speed = rk3588_set_gmac_speed,
 	.set_clock_selection = rk3588_set_clock_selection,
 
 	.phy_intf_sel_grf_reg = RK3588_GRF_GMAC_CON0,
@@ -1248,15 +1123,8 @@ static void rv1108_set_to_rmii(struct rk_priv_data *bsp_priv)
 {
 }
 
-static int rv1108_set_speed(struct rk_priv_data *bsp_priv,
-			    phy_interface_t interface, int speed)
-{
-	return rk_set_reg_speed(bsp_priv, interface, speed);
-}
-
 static const struct rk_gmac_ops rv1108_ops = {
 	.set_to_rmii = rv1108_set_to_rmii,
-	.set_speed = rv1108_set_speed,
 
 	.phy_intf_sel_grf_reg = RV1108_GRF_GMAC_CON0,
 	.phy_intf_sel_mask = GENMASK_U16(6, 4),
@@ -1681,11 +1549,42 @@ static int rk_set_clk_tx_rate(void *bsp_priv_, struct clk *clk_tx_i,
 			      phy_interface_t interface, int speed)
 {
 	struct rk_priv_data *bsp_priv = bsp_priv_;
+	struct regmap *regmap;
+	int ret = -EINVAL;
+	bool is_100m;
+	u32 val;
 
-	if (bsp_priv->ops->set_speed)
-		return bsp_priv->ops->set_speed(bsp_priv, interface, speed);
+	if (bsp_priv->ops->set_speed) {
+		ret = bsp_priv->ops->set_speed(bsp_priv, interface, speed);
+		if (ret < 0)
+			return ret;
+	}
 
-	return -EINVAL;
+	if (bsp_priv->ops->speed_reg_php_grf)
+		regmap = bsp_priv->php_grf;
+	else
+		regmap = bsp_priv->grf;
+
+	if (phy_interface_mode_is_rgmii(interface) &&
+	    bsp_priv->gmii_clk_sel_mask) {
+		ret = rk_gmac_rgmii_clk_div(speed);
+		if (ret < 0)
+			return ret;
+
+		val = rk_encode_wm16(ret, bsp_priv->gmii_clk_sel_mask);
+
+		ret = regmap_write(regmap, bsp_priv->speed_grf_reg, val);
+	} else if (interface == PHY_INTERFACE_MODE_RMII &&
+		   (bsp_priv->rmii_clk_sel_mask ||
+		    bsp_priv->mac_speed_mask)) {
+		is_100m = speed == SPEED_100;
+		val = rk_encode_wm16(is_100m, bsp_priv->mac_speed_mask) |
+		      rk_encode_wm16(is_100m, bsp_priv->rmii_clk_sel_mask);
+
+		ret = regmap_write(regmap, bsp_priv->speed_grf_reg, val);
+	}
+
+	return ret;
 }
 
 static int rk_gmac_suspend(struct device *dev, void *bsp_priv_)
-- 
2.47.3



From rmk+kernel at armlinux.org.uk  Mon Dec  1 06:51:44 2025
From: rmk+kernel at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 01 Dec 2025 14:51:44 +0000
Subject: [PATCH RFC net-next 12/15] net: stmmac: rk: introduce flags
 indicating support for RGMII/RMII
In-Reply-To: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
References: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
Message-ID: <E1vQ5Fg-0000000GNwZ-0aYc@rmk-PC.armlinux.org.uk>

Introduce two boolean flags into struct rk_priv_data indicating
whether RGMII and/or RMII is supported for this instance. Use these
to configure the supported_interfaces mask for phylink, validate the
interface mode. Initialise these from equivalent flags in the
rk_gmac_ops or depending on the presence of the ops->set_to_rgmii and
ops->set_to_mii methods. Finally, make ops->set_to_* optional.

This will allow us to get rid of empty set_to_rmii() methods.

Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
---
 .../net/ethernet/stmicro/stmmac/dwmac-rk.c    | 35 +++++++++++++------
 1 file changed, 25 insertions(+), 10 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
index 4c80a73bbf74..fbc0e50519f6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -48,6 +48,8 @@ struct rk_gmac_ops {
 	u16 mac_speed_mask;
 
 	bool speed_reg_php_grf;
+	bool supports_rgmii;
+	bool supports_rmii;
 	bool php_grf_required;
 	bool regs_valid;
 	u32 regs[];
@@ -81,6 +83,8 @@ struct rk_priv_data {
 	bool clk_enabled;
 	bool clock_input;
 	bool integrated_phy;
+	bool supports_rgmii;
+	bool supports_rmii;
 
 	struct clk_bulk_data *clks;
 	int num_clks;
@@ -1387,6 +1391,9 @@ static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,
 	bsp_priv->rmii_clk_sel_mask = ops->rmii_clk_sel_mask;
 	bsp_priv->mac_speed_mask = ops->mac_speed_mask;
 
+	bsp_priv->supports_rgmii = ops->supports_rgmii || !!ops->set_to_rgmii;
+	bsp_priv->supports_rmii = ops->supports_rmii || !!ops->set_to_rmii;
+
 	if (ops->init) {
 		ret = ops->init(bsp_priv);
 		if (ret) {
@@ -1405,11 +1412,11 @@ static int rk_gmac_check_ops(struct rk_priv_data *bsp_priv)
 	case PHY_INTERFACE_MODE_RGMII_ID:
 	case PHY_INTERFACE_MODE_RGMII_RXID:
 	case PHY_INTERFACE_MODE_RGMII_TXID:
-		if (!bsp_priv->ops->set_to_rgmii)
+		if (!bsp_priv->supports_rgmii)
 			return -EINVAL;
 		break;
 	case PHY_INTERFACE_MODE_RMII:
-		if (!bsp_priv->ops->set_to_rmii)
+		if (!bsp_priv->supports_rmii)
 			return -EINVAL;
 		break;
 	default:
@@ -1455,24 +1462,32 @@ static int rk_gmac_powerup(struct rk_priv_data *bsp_priv)
 	switch (bsp_priv->phy_iface) {
 	case PHY_INTERFACE_MODE_RGMII:
 		dev_info(dev, "init for RGMII\n");
-		bsp_priv->ops->set_to_rgmii(bsp_priv, bsp_priv->tx_delay,
-					    bsp_priv->rx_delay);
+		if (bsp_priv->ops->set_to_rgmii)
+			bsp_priv->ops->set_to_rgmii(bsp_priv,
+						    bsp_priv->tx_delay,
+						    bsp_priv->rx_delay);
 		break;
 	case PHY_INTERFACE_MODE_RGMII_ID:
 		dev_info(dev, "init for RGMII_ID\n");
-		bsp_priv->ops->set_to_rgmii(bsp_priv, 0, 0);
+		if (bsp_priv->ops->set_to_rgmii)
+			bsp_priv->ops->set_to_rgmii(bsp_priv, 0, 0);
 		break;
 	case PHY_INTERFACE_MODE_RGMII_RXID:
 		dev_info(dev, "init for RGMII_RXID\n");
-		bsp_priv->ops->set_to_rgmii(bsp_priv, bsp_priv->tx_delay, 0);
+		if (bsp_priv->ops->set_to_rgmii)
+			bsp_priv->ops->set_to_rgmii(bsp_priv,
+						    bsp_priv->tx_delay, 0);
 		break;
 	case PHY_INTERFACE_MODE_RGMII_TXID:
 		dev_info(dev, "init for RGMII_TXID\n");
-		bsp_priv->ops->set_to_rgmii(bsp_priv, 0, bsp_priv->rx_delay);
+		if (bsp_priv->ops->set_to_rgmii)
+			bsp_priv->ops->set_to_rgmii(bsp_priv,
+						    0, bsp_priv->rx_delay);
 		break;
 	case PHY_INTERFACE_MODE_RMII:
 		dev_info(dev, "init for RMII\n");
-		bsp_priv->ops->set_to_rmii(bsp_priv);
+		if (bsp_priv->ops->set_to_rmii)
+			bsp_priv->ops->set_to_rmii(bsp_priv);
 		break;
 	default:
 		dev_err(dev, "NO interface defined!\n");
@@ -1508,10 +1523,10 @@ static void rk_get_interfaces(struct stmmac_priv *priv, void *bsp_priv,
 {
 	struct rk_priv_data *rk = bsp_priv;
 
-	if (rk->ops->set_to_rgmii)
+	if (rk->supports_rgmii)
 		phy_interface_set_rgmii(interfaces);
 
-	if (rk->ops->set_to_rmii)
+	if (rk->supports_rmii)
 		__set_bit(PHY_INTERFACE_MODE_RMII, interfaces);
 }
 
-- 
2.47.3



From quentin.schulz at cherry.de  Mon Dec  1 06:54:18 2025
From: quentin.schulz at cherry.de (Quentin Schulz)
Date: Mon, 1 Dec 2025 15:54:18 +0100
Subject: [PATCH 3/3] arm64: dts: rockchip: Correctly describe the ethernet
 phy on rk3368-lion
In-Reply-To: <20251020100757.3669681-4-heiko@sntech.de>
References: <20251020100757.3669681-1-heiko@sntech.de>
 <20251020100757.3669681-4-heiko@sntech.de>
Message-ID: <54b26cfa-e231-494b-aa7e-cd21069c95a4@cherry.de>

Hi Heiko,

On 10/20/25 12:07 PM, Heiko Stuebner wrote:
> From: Heiko Stuebner <heiko.stuebner at cherry.de>
> 
> So far, the board used the phy implicitly using the deprecated snps reset
> properties. Improve that and describe the PHY correctly under the new
> mdio node.
> 

Reviewed-by: Quentin Schulz <quentin.schulz at cherry.de>

Thanks!
Quentin


From rmk+kernel at armlinux.org.uk  Mon Dec  1 06:51:59 2025
From: rmk+kernel at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 01 Dec 2025 14:51:59 +0000
Subject: [PATCH RFC net-next 15/15] net: stmmac: rk: rk3528: gmac0 only
 supports RMII
In-Reply-To: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
References: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
Message-ID: <E1vQ5Fv-0000000GNwr-1xfQ@rmk-PC.armlinux.org.uk>

RK3528 gmac0 dtsi contains:

                gmac0: ethernet at ffbd0000 {
                        phy-handle = <&rmii0_phy>;
                        phy-mode = "rmii";

                        mdio0: mdio {
                                rmii0_phy: ethernet-phy at 2 {
                                        phy-is-integrated;
                                };
                        };
                };

This follows the same pattern as rk3328, where this gmac instance
only supports RMII. Disable RGMII in phylink's supported_interfaces
mask for this gmac instance.

Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
---
 drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
index c04a115beb98..290fd5f06267 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -701,6 +701,7 @@ static int rk3528_init(struct rk_priv_data *bsp_priv)
 	case 0:
 		bsp_priv->speed_grf_reg = RK3528_VO_GRF_GMAC_CON;
 		bsp_priv->rmii_clk_sel_mask = BIT_U16(3);
+		bsp_priv->supports_rgmii = false;
 		return 0;
 
 	case 1:
-- 
2.47.3



From konrad.dybcio at oss.qualcomm.com  Mon Dec  1 06:58:47 2025
From: konrad.dybcio at oss.qualcomm.com (Konrad Dybcio)
Date: Mon, 1 Dec 2025 15:58:47 +0100
Subject: [PATCH v6 2/3] arm64: dts: qcom: qcs8300: Add CCI definitions
In-Reply-To: <20251126081057.4191122-3-quic_vikramsa@quicinc.com>
References: <20251126081057.4191122-1-quic_vikramsa@quicinc.com>
 <20251126081057.4191122-3-quic_vikramsa@quicinc.com>
Message-ID: <e65c9149-47c7-49a4-8076-0b8ef161997d@oss.qualcomm.com>

On 11/26/25 9:10 AM, Vikram Sharma wrote:
> From: Nihal Kumar Gupta <quic_nihalkum at quicinc.com>
> 
> Qualcomm QCS8300 SoC contains three Camera Control Interface (CCI).
> Compared to Lemans, the key difference is in SDA/SCL GPIO assignments
> and number of CCIs.

[...]

> @@ -5071,6 +5182,240 @@ tlmm: pinctrl at f100000 {
>  			#interrupt-cells = <2>;
>  			wakeup-parent = <&pdc>;
>  
> +			cam0_avdd_2v8_en_default: cam0-avdd-2v8-en-state {
> +				pins = "gpio73";
> +				function = "gpio";
> +				drive-strength = <2>;
> +				bias-disable;
> +			};

I'm not sure whether I was unclear, but my intention was to ask
you to move the MCLK pin definitions to the SoC DTSI, because that
comes from the design of the platform and doesn't vary between end
products.

GPIO_73 being related to a voltage regulator is strictly a property
of the EVK.

Konrad


From rmk+kernel at armlinux.org.uk  Mon Dec  1 06:51:49 2025
From: rmk+kernel at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 01 Dec 2025 14:51:49 +0000
Subject: [PATCH RFC net-next 13/15] net: stmmac: rk: replace empty
 set_to_rmii() with supports_rmii
In-Reply-To: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
References: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
Message-ID: <E1vQ5Fl-0000000GNwf-16ec@rmk-PC.armlinux.org.uk>

Rather than providing a now-empty set_to_rmii() method to indicate
that RMII is supported, switch to setting ops->supports_rmii instead.

Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
---
 .../net/ethernet/stmicro/stmmac/dwmac-rk.c    | 86 ++++++-------------
 1 file changed, 24 insertions(+), 62 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
index fbc0e50519f6..c9a915b2cb84 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -241,12 +241,7 @@ static void rk_gmac_integrated_fephy_powerdown(struct rk_priv_data *priv,
 
 #define PX30_GRF_GMAC_CON1		0x0904
 
-static void px30_set_to_rmii(struct rk_priv_data *bsp_priv)
-{
-}
-
 static const struct rk_gmac_ops px30_ops = {
-	.set_to_rmii = px30_set_to_rmii,
 	.set_speed = rk_set_clk_mac_speed,
 
 	.phy_intf_sel_grf_reg = PX30_GRF_GMAC_CON1,
@@ -254,6 +249,8 @@ static const struct rk_gmac_ops px30_ops = {
 
 	.speed_grf_reg = PX30_GRF_GMAC_CON1,
 	.mac_speed_mask = BIT_U16(2),
+
+	.supports_rmii = true,
 };
 
 #define RK3128_GRF_MAC_CON0	0x0168
@@ -280,13 +277,8 @@ static void rk3128_set_to_rgmii(struct rk_priv_data *bsp_priv,
 		     RK3128_GMAC_CLK_TX_DL_CFG(tx_delay));
 }
 
-static void rk3128_set_to_rmii(struct rk_priv_data *bsp_priv)
-{
-}
-
 static const struct rk_gmac_ops rk3128_ops = {
 	.set_to_rgmii = rk3128_set_to_rgmii,
-	.set_to_rmii = rk3128_set_to_rmii,
 
 	.phy_intf_sel_grf_reg = RK3128_GRF_MAC_CON1,
 	.phy_intf_sel_mask = GENMASK_U16(8, 6),
@@ -296,6 +288,8 @@ static const struct rk_gmac_ops rk3128_ops = {
 	.gmii_clk_sel_mask = GENMASK_U16(13, 12),
 	.rmii_clk_sel_mask = BIT_U16(11),
 	.mac_speed_mask = BIT_U16(10),
+
+	.supports_rmii = true,
 };
 
 #define RK3228_GRF_MAC_CON0	0x0900
@@ -383,13 +377,8 @@ static void rk3288_set_to_rgmii(struct rk_priv_data *bsp_priv,
 		     RK3288_GMAC_CLK_TX_DL_CFG(tx_delay));
 }
 
-static void rk3288_set_to_rmii(struct rk_priv_data *bsp_priv)
-{
-}
-
 static const struct rk_gmac_ops rk3288_ops = {
 	.set_to_rgmii = rk3288_set_to_rgmii,
-	.set_to_rmii = rk3288_set_to_rmii,
 
 	.phy_intf_sel_grf_reg = RK3288_GRF_SOC_CON1,
 	.phy_intf_sel_mask = GENMASK_U16(8, 6),
@@ -399,6 +388,8 @@ static const struct rk_gmac_ops rk3288_ops = {
 	.gmii_clk_sel_mask = GENMASK_U16(13, 12),
 	.rmii_clk_sel_mask = BIT_U16(11),
 	.mac_speed_mask = BIT_U16(10),
+
+	.supports_rmii = true,
 };
 
 #define RK3308_GRF_MAC_CON0		0x04a0
@@ -407,18 +398,14 @@ static const struct rk_gmac_ops rk3288_ops = {
 #define RK3308_GMAC_FLOW_CTRL		GRF_BIT(3)
 #define RK3308_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(3)
 
-static void rk3308_set_to_rmii(struct rk_priv_data *bsp_priv)
-{
-}
-
 static const struct rk_gmac_ops rk3308_ops = {
-	.set_to_rmii = rk3308_set_to_rmii,
-
 	.phy_intf_sel_grf_reg = RK3308_GRF_MAC_CON0,
 	.phy_intf_sel_mask = GENMASK_U16(4, 2),
 
 	.speed_grf_reg = RK3308_GRF_MAC_CON0,
 	.mac_speed_mask = BIT_U16(0),
+
+	.supports_rmii = true,
 };
 
 #define RK3328_GRF_MAC_CON0	0x0900
@@ -470,10 +457,6 @@ static void rk3328_set_to_rgmii(struct rk_priv_data *bsp_priv,
 		     RK3328_GMAC_CLK_TX_DL_CFG(tx_delay));
 }
 
-static void rk3328_set_to_rmii(struct rk_priv_data *bsp_priv)
-{
-}
-
 static void rk3328_integrated_phy_powerup(struct rk_priv_data *priv)
 {
 	regmap_write(priv->grf, RK3328_GRF_MACPHY_CON1,
@@ -485,7 +468,6 @@ static void rk3328_integrated_phy_powerup(struct rk_priv_data *priv)
 static const struct rk_gmac_ops rk3328_ops = {
 	.init = rk3328_init,
 	.set_to_rgmii = rk3328_set_to_rgmii,
-	.set_to_rmii = rk3328_set_to_rmii,
 	.integrated_phy_powerup = rk3328_integrated_phy_powerup,
 	.integrated_phy_powerdown = rk_gmac_integrated_ephy_powerdown,
 
@@ -495,6 +477,8 @@ static const struct rk_gmac_ops rk3328_ops = {
 	.rmii_clk_sel_mask = BIT_U16(7),
 	.mac_speed_mask = BIT_U16(2),
 
+	.supports_rmii = true,
+
 	.regs_valid = true,
 	.regs = {
 		0xff540000, /* gmac2io */
@@ -527,13 +511,8 @@ static void rk3366_set_to_rgmii(struct rk_priv_data *bsp_priv,
 		     RK3366_GMAC_CLK_TX_DL_CFG(tx_delay));
 }
 
-static void rk3366_set_to_rmii(struct rk_priv_data *bsp_priv)
-{
-}
-
 static const struct rk_gmac_ops rk3366_ops = {
 	.set_to_rgmii = rk3366_set_to_rgmii,
-	.set_to_rmii = rk3366_set_to_rmii,
 
 	.phy_intf_sel_grf_reg = RK3366_GRF_SOC_CON6,
 	.phy_intf_sel_mask = GENMASK_U16(11, 9),
@@ -543,6 +522,8 @@ static const struct rk_gmac_ops rk3366_ops = {
 	.gmii_clk_sel_mask = GENMASK_U16(5, 4),
 	.rmii_clk_sel_mask = BIT_U16(3),
 	.mac_speed_mask = BIT_U16(7),
+
+	.supports_rmii = true,
 };
 
 #define RK3368_GRF_SOC_CON15	0x043c
@@ -569,13 +550,8 @@ static void rk3368_set_to_rgmii(struct rk_priv_data *bsp_priv,
 		     RK3368_GMAC_CLK_TX_DL_CFG(tx_delay));
 }
 
-static void rk3368_set_to_rmii(struct rk_priv_data *bsp_priv)
-{
-}
-
 static const struct rk_gmac_ops rk3368_ops = {
 	.set_to_rgmii = rk3368_set_to_rgmii,
-	.set_to_rmii = rk3368_set_to_rmii,
 
 	.phy_intf_sel_grf_reg = RK3368_GRF_SOC_CON15,
 	.phy_intf_sel_mask = GENMASK_U16(11, 9),
@@ -585,6 +561,8 @@ static const struct rk_gmac_ops rk3368_ops = {
 	.gmii_clk_sel_mask = GENMASK_U16(5, 4),
 	.rmii_clk_sel_mask = BIT_U16(3),
 	.mac_speed_mask = BIT_U16(7),
+
+	.supports_rmii = true,
 };
 
 #define RK3399_GRF_SOC_CON5	0xc214
@@ -611,13 +589,8 @@ static void rk3399_set_to_rgmii(struct rk_priv_data *bsp_priv,
 		     RK3399_GMAC_CLK_TX_DL_CFG(tx_delay));
 }
 
-static void rk3399_set_to_rmii(struct rk_priv_data *bsp_priv)
-{
-}
-
 static const struct rk_gmac_ops rk3399_ops = {
 	.set_to_rgmii = rk3399_set_to_rgmii,
-	.set_to_rmii = rk3399_set_to_rmii,
 
 	.phy_intf_sel_grf_reg = RK3399_GRF_SOC_CON5,
 	.phy_intf_sel_mask = GENMASK_U16(11, 9),
@@ -627,6 +600,8 @@ static const struct rk_gmac_ops rk3399_ops = {
 	.gmii_clk_sel_mask = GENMASK_U16(5, 4),
 	.rmii_clk_sel_mask = BIT_U16(3),
 	.mac_speed_mask = BIT_U16(7),
+
+	.supports_rmii = true,
 };
 
 #define RK3506_GRF_SOC_CON8		0x0020
@@ -858,18 +833,15 @@ static void rk3568_set_to_rgmii(struct rk_priv_data *bsp_priv,
 		     RK3568_GMAC_TXCLK_DLY_ENABLE);
 }
 
-static void rk3568_set_to_rmii(struct rk_priv_data *bsp_priv)
-{
-}
-
 static const struct rk_gmac_ops rk3568_ops = {
 	.init = rk3568_init,
 	.set_to_rgmii = rk3568_set_to_rgmii,
-	.set_to_rmii = rk3568_set_to_rmii,
 	.set_speed = rk_set_clk_mac_speed,
 
 	.phy_intf_sel_mask = GENMASK_U16(6, 4),
 
+	.supports_rmii = true,
+
 	.regs_valid = true,
 	.regs = {
 		0xfe2a0000, /* gmac0 */
@@ -943,10 +915,6 @@ static void rk3576_set_to_rgmii(struct rk_priv_data *bsp_priv,
 		     RK3576_GMAC_CLK_RX_DL_CFG(rx_delay));
 }
 
-static void rk3576_set_to_rmii(struct rk_priv_data *bsp_priv)
-{
-}
-
 static void rk3576_set_clock_selection(struct rk_priv_data *bsp_priv, bool input,
 				       bool enable)
 {
@@ -966,7 +934,6 @@ static void rk3576_set_clock_selection(struct rk_priv_data *bsp_priv, bool input
 static const struct rk_gmac_ops rk3576_ops = {
 	.init = rk3576_init,
 	.set_to_rgmii = rk3576_set_to_rgmii,
-	.set_to_rmii = rk3576_set_to_rmii,
 	.set_clock_selection = rk3576_set_clock_selection,
 
 	.rmii_mode_mask = BIT_U16(3),
@@ -974,6 +941,8 @@ static const struct rk_gmac_ops rk3576_ops = {
 	.gmii_clk_sel_mask = GENMASK_U16(6, 5),
 	.rmii_clk_sel_mask = BIT_U16(5),
 
+	.supports_rmii = true,
+
 	.php_grf_required = true,
 	.regs_valid = true,
 	.regs = {
@@ -1093,19 +1062,15 @@ static const struct rk_gmac_ops rk3588_ops = {
 #define RV1108_GMAC_FLOW_CTRL		GRF_BIT(3)
 #define RV1108_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(3)
 
-static void rv1108_set_to_rmii(struct rk_priv_data *bsp_priv)
-{
-}
-
 static const struct rk_gmac_ops rv1108_ops = {
-	.set_to_rmii = rv1108_set_to_rmii,
-
 	.phy_intf_sel_grf_reg = RV1108_GRF_GMAC_CON0,
 	.phy_intf_sel_mask = GENMASK_U16(6, 4),
 
 	.speed_grf_reg = RV1108_GRF_GMAC_CON0,
 	.rmii_clk_sel_mask = BIT_U16(7),
 	.mac_speed_mask = BIT_U16(2),
+
+	.supports_rmii = true,
 };
 
 #define RV1126_GRF_GMAC_CON0		0X0070
@@ -1149,17 +1114,14 @@ static void rv1126_set_to_rgmii(struct rk_priv_data *bsp_priv,
 		     RV1126_GMAC_M1_CLK_TX_DL_CFG(tx_delay));
 }
 
-static void rv1126_set_to_rmii(struct rk_priv_data *bsp_priv)
-{
-}
-
 static const struct rk_gmac_ops rv1126_ops = {
 	.set_to_rgmii = rv1126_set_to_rgmii,
-	.set_to_rmii = rv1126_set_to_rmii,
 	.set_speed = rk_set_clk_mac_speed,
 
 	.phy_intf_sel_grf_reg = RV1126_GRF_GMAC_CON0,
 	.phy_intf_sel_mask = GENMASK_U16(6, 4),
+
+	.supports_rmii = true,
 };
 
 static int rk_gmac_clk_init(struct plat_stmmacenet_data *plat)
-- 
2.47.3



From rmk+kernel at armlinux.org.uk  Mon Dec  1 06:51:54 2025
From: rmk+kernel at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 01 Dec 2025 14:51:54 +0000
Subject: [PATCH RFC net-next 14/15] net: stmmac: rk: rk3328: gmac2phy only
 supports RMII
In-Reply-To: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
References: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
Message-ID: <E1vQ5Fq-0000000GNwl-1aSe@rmk-PC.armlinux.org.uk>

As detailed in a previous commit ("net: stmmac: rk: convert rk3328 to
use bsp_priv->id") rk3328 gmac2phy only supports RMII, whereas gmac2io
supports both RMII and RGMII. Clear supports_rgmii for gmac2phy.

Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
---
 drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
index c9a915b2cb84..c04a115beb98 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -438,6 +438,7 @@ static int rk3328_init(struct rk_priv_data *bsp_priv)
 	case 1: /* gmac2phy */
 		bsp_priv->phy_intf_sel_grf_reg = RK3328_GRF_MAC_CON2;
 		bsp_priv->speed_grf_reg = RK3328_GRF_MAC_CON2;
+		bsp_priv->supports_rgmii = false;
 		return 0;
 
 	default:
-- 
2.47.3



From quentin.schulz at cherry.de  Mon Dec  1 07:23:46 2025
From: quentin.schulz at cherry.de (Quentin Schulz)
Date: Mon, 1 Dec 2025 16:23:46 +0100
Subject: [PATCH v2 4/9] arm64: dts: rockchip: Add power-domain to RK3368
 DSI controller
In-Reply-To: <20251021074254.87065-5-heiko@sntech.de>
References: <20251021074254.87065-1-heiko@sntech.de>
 <20251021074254.87065-5-heiko@sntech.de>
Message-ID: <19a9498e-c8d1-4e1c-b89d-8d1a7e6aa54a@cherry.de>

Hi Heiko,

On 10/21/25 9:42 AM, Heiko Stuebner wrote:
> From: Heiko Stuebner <heiko.stuebner at cherry.de>
> 
> The DSI controller is also part of the VIO power-domain and it
> definitely needs to be on when accessing it to not cause SError
> faults, so add the power-domains property to it.
> 
> Fixes: 5023d0cd6183 ("arm64: dts: rockchip: Add DSI for RK3368")
> Signed-off-by: Heiko Stuebner <heiko.stuebner at cherry.de>
> ---
>   arch/arm64/boot/dts/rockchip/rk3368.dtsi | 1 +
>   1 file changed, 1 insertion(+)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3368.dtsi b/arch/arm64/boot/dts/rockchip/rk3368.dtsi
> index 8f0216203241..5b2cbb3003b6 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3368.dtsi
> +++ b/arch/arm64/boot/dts/rockchip/rk3368.dtsi
> @@ -896,6 +896,7 @@ mipi_dsi: dsi at ff960000 {
>   		clock-names = "pclk";
>   		phys = <&dphy>;
>   		phy-names = "dphy";
> +		power-domains = <&power RK3368_PD_VIO>;

Shouldn't we have the same for the PHY as well?

It's not entirely clear to me as pclk_dphytx0_phy seems to belong to 
PD_ALIVE according to page 62 of TRM v1.1, but Table 4-1 RK3368 Power 
Domain and Voltage Domain Summary doesn't seem to confirm that.

Cheers,
Quentin


From linux at armlinux.org.uk  Mon Dec  1 07:24:05 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 1 Dec 2025 15:24:05 +0000
Subject: [PATCH v2 1/2] syscall.h: Remove unused SYSCALL_MAX_ARGS
In-Reply-To: <20251201120633.1193122-2-ruanjinjie@huawei.com>
References: <20251201120633.1193122-1-ruanjinjie@huawei.com>
 <20251201120633.1193122-2-ruanjinjie@huawei.com>
Message-ID: <aS2zFVPAzMNQnfTF@shell.armlinux.org.uk>

On Mon, Dec 01, 2025 at 08:06:32PM +0800, Jinjie Ruan wrote:
> The "SYSCALL_MAX_ARGS" appears to have been unused since
> commit 32d92586629a ("syscalls: Remove start and number from
> syscall_set_arguments() args"), so remove it.
> 
> Fixes: 32d92586629a ("syscalls: Remove start and number from syscall_set_arguments() args")
> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>

Reviewed-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>

Thanks!

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From beata.michalska at arm.com  Mon Dec  1 07:27:12 2025
From: beata.michalska at arm.com (Beata Michalska)
Date: Mon, 1 Dec 2025 16:27:12 +0100
Subject: [PATCH v6 0/3] arm64: topology: Handle AMU FIE setup on CPU
 hotplug
In-Reply-To: <20251119081356.2495290-1-zhenglifeng1@huawei.com>
References: <20251119081356.2495290-1-zhenglifeng1@huawei.com>
Message-ID: <aS2z0EURwHbbGZab@arm.com>

Hi,

Apologies for the delay in reviewing this - currently in progress....
Out of curiosity: what's the cpufreq driver used for testing this series ?

---
BR
Beata
On Wed, Nov 19, 2025 at 04:13:53PM +0800, Lifeng Zheng wrote:
> Solve a problem that causes CPUs Setup AMU FIE failed in a corner case,
> even though they're eligible.
> 
> Changelog:
> 
> v6:
> 
>  - discard the modifications in cpufreq.c, and instead, make
>    supports_scale_freq_counters() checks that at least one CPU in the
>    policy supports AMU FIE, instead of all
>  - based on Beata's feedback, optimize cpuhp_topology_online() to make it
>    more readable
>  - use pr_warn instead of WARN_ON to show warning message when the
>    freq_counters_valid() check fails in cpuhp_topology_online()
>  - modify commit message as Beata and Rafael suggested
> 
> v5:
> 
>  - add a default implementation for cpufreq_cpu_policy() when
>    CONFIG_CPU_FREQ is not defined
> 
> v4:
> 
>  - change the function's name in patch 2 from
>    'cpufreq_cpu_get_raw_no_check' to 'cpufreq_cpu_policy'
>  - use only one line in the function body of cpufreq_cpu_policy()
>  - use cpus mask instead of related_cpus when calling arch_set_freq_scale()
>    in cpufreq.c
>  - add a warning when the freq_counters_valid() check fails in
>    cpuhp_topology_online()
> 
> v3:
> 
>  - add a patch to optimize amu_fie_setup()
>  - add a patch to add a function to get cpufreq policy without checking if
>    the CPU is online
>  - discard the reuse of amu_fie_setup() in cpuhp_topology_online() and keep
>    all the new logic in cpuhp_topology_online()
>  - test only the CPU which is going online in cpuhp_topology_online()
>  - when the freq_counters_valid() check fails, not only clear the scale
>    freq source but also clear all the related CPUs from amu_fie_cpus mask
>  - add some comments
> 
> v2:
> 
>  - keep init_amu_fie_notifier for setting up AMU FIE when the cpufreq
>    policy is being created
>  - set up AMU FIE only for online CPUs instead of related_cpus in
>    init_amu_fie_callback()
>  - check and set all the online CPUs in the same policy when hotplug one
>  - clear scale freq source for all the online CPUs in the same policy to
>    avoid using different source of the freq scale
> 
> ---
> Discussions of previous version:
> v1: https://lore.kernel.org/all/20250607094533.416368-1-zhenglifeng1 at huawei.com/
> v2: https://lore.kernel.org/all/20250725102813.1404322-1-zhenglifeng1 at huawei.com/
> v3: https://lore.kernel.org/all/20250805093330.3715444-1-zhenglifeng1 at huawei.com/
> v4: https://lore.kernel.org/all/20250814072853.3426386-1-zhenglifeng1 at huawei.com/
> v5: https://lore.kernel.org/all/20250819072931.1647431-1-zhenglifeng1 at huawei.com/
> 
> Lifeng Zheng (3):
>   arm64: topology: Skip already covered CPUs when setting freq source
>   cpufreq: Add new helper function returning cpufreq policy
>   arm64: topology: Handle AMU FIE setup on CPU hotplug
> 
>  arch/arm64/kernel/topology.c | 67 ++++++++++++++++++++++++++++++++++--
>  drivers/base/arch_topology.c |  9 ++++-
>  drivers/cpufreq/cpufreq.c    |  6 ++++
>  include/linux/cpufreq.h      |  5 +++
>  4 files changed, 83 insertions(+), 4 deletions(-)
> 
> -- 
> 2.33.0
> 


From quentin.schulz at cherry.de  Mon Dec  1 07:38:59 2025
From: quentin.schulz at cherry.de (Quentin Schulz)
Date: Mon, 1 Dec 2025 16:38:59 +0100
Subject: [PATCH v2 5/9] arm64: dts: rockchip: Add power-domain to RK3368
 VOP controller
In-Reply-To: <20251021074254.87065-6-heiko@sntech.de>
References: <20251021074254.87065-1-heiko@sntech.de>
 <20251021074254.87065-6-heiko@sntech.de>
Message-ID: <d10fde2d-9575-4e8a-a46f-4af1e44592f5@cherry.de>

Hi Heiko,

On 10/21/25 9:42 AM, Heiko Stuebner wrote:
> From: Heiko Stuebner <heiko.stuebner at cherry.de>
> 
> The VOP is also part of the VIO power-domain and it definitely needs to
> be on when accessing it to not cause SError faults, so add the
> power-domains property to it.
> 
> Fixes: ef06b5ddee1e ("arm64: dts: rockchip: Add display subsystem for RK3368")

Reviewed-by: Quentin Schulz <quentin.schulz at cherry.de>

Thanks!
Quentin


From quentin.schulz at cherry.de  Mon Dec  1 07:41:28 2025
From: quentin.schulz at cherry.de (Quentin Schulz)
Date: Mon, 1 Dec 2025 16:41:28 +0100
Subject: [PATCH v2 6/9] arm64: dts: rockchip: Use phandle for i2c_lvds_blc
 on rk3368-lion haikou
In-Reply-To: <20251021074254.87065-7-heiko@sntech.de>
References: <20251021074254.87065-1-heiko@sntech.de>
 <20251021074254.87065-7-heiko@sntech.de>
Message-ID: <efb64744-c140-4421-b72e-6ead771548c9@cherry.de>

Hi Heiko,

On 10/21/25 9:42 AM, Heiko Stuebner wrote:
> From: Heiko Stuebner <heiko.stuebner at cherry.de>
> 
> i2c at 0 on i2cmux2 does already have a phandle i2c_lvds_blc defined.
> 
> Use this one instead of replicating the hierarchy again, as this might
> result in strange errors if the lion dtsi is changed at some point
> in the future.
> 

Reviewed-by: Quentin Schulz <quentin.schulz at cherry.de>

Thanks!
Quentin


From shenwei.wang at nxp.com  Mon Dec  1 07:50:40 2025
From: shenwei.wang at nxp.com (Shenwei Wang)
Date: Mon, 1 Dec 2025 15:50:40 +0000
Subject: [PATCH v5 2/5] remoteproc: imx_rproc: Populate devices under
 "rpmsg" subnode
In-Reply-To: <aSh67mvFB_00PywW@p14s>
References: <20251104203315.85706-1-shenwei.wang@nxp.com>
 <20251104203315.85706-3-shenwei.wang@nxp.com> <aSdMufLCeqvVyKsp@p14s>
 <PAXPR04MB91857863B163B3F38A26647389DEA@PAXPR04MB9185.eurprd04.prod.outlook.com>
 <aSh67mvFB_00PywW@p14s>
Message-ID: <PAXPR04MB91853C6A0BA9BC556A09EB2789DBA@PAXPR04MB9185.eurprd04.prod.outlook.com>



> -----Original Message-----
> From: Mathieu Poirier <mathieu.poirier at linaro.org>
> Sent: Thursday, November 27, 2025 10:23 AM
> To: Shenwei Wang <shenwei.wang at nxp.com>
> Cc: Bjorn Andersson <andersson at kernel.org>; Rob Herring <robh at kernel.org>;
> Krzysztof Kozlowski <krzk+dt at kernel.org>; Conor Dooley
> <conor+dt at kernel.org>; Shawn Guo <shawnguo at kernel.org>; Sascha Hauer
> <s.hauer at pengutronix.de>; Jonathan Corbet <corbet at lwn.net>; Linus Walleij
> <linus.walleij at linaro.org>; Bartosz Golaszewski <brgl at bgdev.pl>; Pengutronix
> Kernel Team <kernel at pengutronix.de>; Fabio Estevam <festevam at gmail.com>;
> Peng Fan <peng.fan at nxp.com>; linux-remoteproc at vger.kernel.org;
> devicetree at vger.kernel.org; imx at lists.linux.dev; linux-arm-
> kernel at lists.infradead.org; linux-kernel at vger.kernel.org; linux-
> doc at vger.kernel.org; dl-linux-imx <linux-imx at nxp.com>
> Subject: [EXT] Re: [PATCH v5 2/5] remoteproc: imx_rproc: Populate devices
> under "rpmsg" subnode
> > > > +static void imx_rpmsg_endpoint_remove(struct rpmsg_device *rpdev) {
> > > > +     of_platform_depopulate(&rpdev->dev);
> > > > +}
> > > > +
> > > > +static int imx_rpmsg_endpoint_probe(struct rpmsg_device *rpdev) {
> > >
> > > Where does the rpmsg_device come from?  Usually there is a call to
> > > rpmsg_register_device() and I don't see it anywhere in this
> > > patchset.  I also don't see a link to the remote processor.  I can't
> > > continue with this set for as long as I don't have this information.
> > >
> >
> > It is in the function below named imx_of_rpmsg_register_rpdriver.
> >
> 
> The function below calls register_rpmsg_driver(), not rpmsg_register_device().
> I still don't know where @rpdev comes from.
> 

The rpdev device is created by the rpmsg bus driver. On i.MX platforms, this is handled by the virtio_rpmsg_bus driver. 
When the remote firmware sends a channel announcement, the bus driver creates the corresponding rpdev device.

This patch implements the driver for the interested rpdev device.

Thanks,
Shenwei

> > Thanks,
> > Shenwei
> >
> > > > +
> > > > +static int imx_of_rpmsg_register_rpdriver(struct device_node *channel,
> > > > +                                       struct device *dev, int idx) {
> > > > +     struct imx_rpmsg_driver_data *driver_data;
> > > > +     struct imx_rpmsg_driver *rp_driver;
> > > > +     struct rpmsg_device_id *rpdev_id;
> > > > +
> > > > +     rpdev_id = devm_kzalloc(dev, sizeof(*rpdev_id) * 2, GFP_KERNEL);
> > > > +     if (!rpdev_id)
> > > > +             return -ENOMEM;
> > > > +
> > > > +     strscpy(rpdev_id[0].name, channel_device_map[idx][0],
> > > > + RPMSG_NAME_SIZE);
> > > > +
> > > > +     rp_driver = devm_kzalloc(dev, sizeof(*rp_driver), GFP_KERNEL);
> > > > +     if (!rp_driver)
> > > > +             return -ENOMEM;
> > > > +
> > > > +     driver_data = devm_kzalloc(dev, sizeof(*driver_data), GFP_KERNEL);
> > > > +     if (!driver_data)
> > > > +             return -ENOMEM;
> > > > +
> > > > +     driver_data->rproc_name = dev->of_node->name;
> > > > +     driver_data->channel_node = channel;
> > > > +     driver_data->map_idx = idx;
> > > > +
> > > > +     rp_driver->rpdrv.drv.name = channel_device_map[idx][0];
> > > > +     rp_driver->rpdrv.id_table = rpdev_id;
> > > > +     rp_driver->rpdrv.probe = imx_rpmsg_endpoint_probe;
> > > > +     rp_driver->rpdrv.remove = imx_rpmsg_endpoint_remove;
> > > > +     rp_driver->rpdrv.callback = imx_rpmsg_endpoint_cb;
> > > > +     rp_driver->driver_data = driver_data;
> > > > +
> > > > +     register_rpmsg_driver(&rp_driver->rpdrv);
> > > > +
> > > > +     return 0;
> > > > +}


From amhetre at nvidia.com  Mon Dec  1 07:54:07 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Mon, 1 Dec 2025 21:24:07 +0530
Subject: [PATCH V2 3/3] arm64: dts: nvidia: Add nodes for CMDQV
In-Reply-To: <r2mkiktazyn3nvhirbs2ac7n5ymdw62ueutpxt55cnivdi7pdn@6i4hjtvxp2ph>
References: <20251125071659.3048659-1-amhetre@nvidia.com>
 <20251125071659.3048659-4-amhetre@nvidia.com>
 <dff3a962-82dd-4aac-ae11-69f0e95ba04d@nvidia.com>
 <acae92d8-3394-436c-be8e-8bed7a923e85@nvidia.com>
 <r2mkiktazyn3nvhirbs2ac7n5ymdw62ueutpxt55cnivdi7pdn@6i4hjtvxp2ph>
Message-ID: <cfc91cbd-e5bf-4e1c-aeb9-795e5b621910@nvidia.com>


On 12/1/2025 7:41 PM, Thierry Reding wrote:
> On Mon, Dec 01, 2025 at 03:06:55PM +0530, Ashish Mhetre wrote:
>> On 11/25/2025 3:52 PM, Jon Hunter wrote:
>>>
>>> On 25/11/2025 07:16, Ashish Mhetre wrote:
>>>> The Command Queue Virtualization (CMDQV) hardware is part of the
>>>> SMMUv3 implementation on NVIDIA Tegra SoCs. It assists in
>>>> virtualizing the command queue for the SMMU.
>>>>
>>>> Update SMMU compatible strings to use nvidia,tegra264-smmu to enable
>>>> CMDQV support. Add device tree nodes for the CMDQV hardware and enable
>>>> them on the tegra264-p3834 platform where SMMUs are enabled. Each SMMU
>>>> instance is paired with its corresponding CMDQV instance via the
>>>> nvidia,cmdqv property.
>>>>
>>>> Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
>>>> ---
>>>>  ? .../arm64/boot/dts/nvidia/tegra264-p3834.dtsi |? 8 +++
>>>>  ? arch/arm64/boot/dts/nvidia/tegra264.dtsi????? | 55 +++++++++++++++++--
>>>>  ? 2 files changed, 58 insertions(+), 5 deletions(-)
>>>>
>>>> diff --git a/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
>>>> b/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
>>>> index 06795c82427a..375d122b92fa 100644
>>>> --- a/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
>>>> +++ b/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
>>>> @@ -26,5 +26,13 @@ iommu at 5000000 {
>>>>  ????????? iommu at 6000000 {
>>>>  ????????????? status = "okay";
>>>>  ????????? };
>>>> +
>>>> +??????? cmdqv at 5200000 {
>>>> +??????????? status = "okay";
>>>> +??????? };
>>> This needs to be ordered in the file according to its address.
>> Hi Jon, Thanks for the review.
>> cmdqv nodes follow same ordering as its corresponding iommu nodes.
>> I have added them immediately after corresponding iommu nodes.
> No, you didn't. It seems like you sorted by type and then address. But
> we always sort by address first. Type doesn't matter.
>
> This node belongs above the iommu at 6000000 node and after iommu at 5000000.
> The same ordering should be respected in the DTS include.
>
> Thierry

Oh, I got it. Thanks for clarification. I'll make these changes in v3.



From amhetre at nvidia.com  Mon Dec  1 07:55:08 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Mon, 1 Dec 2025 21:25:08 +0530
Subject: [PATCH V2 1/3] iommu/arm-smmu-v3: Add device-tree support for
 CMDQV driver
In-Reply-To: <b0f94951-2896-49a2-ac19-b885903067ad@arm.com>
References: <20251125071659.3048659-1-amhetre@nvidia.com>
 <20251125071659.3048659-2-amhetre@nvidia.com>
 <b0f94951-2896-49a2-ac19-b885903067ad@arm.com>
Message-ID: <42dfb0ed-33ef-4fb3-90be-82be77f3f642@nvidia.com>


On 11/25/2025 10:55 PM, Robin Murphy wrote:
> External email: Use caution opening links or attachments
>
>
> On 2025-11-25 7:16 am, Ashish Mhetre wrote:
>> Add device tree support to the CMDQV driver to enable usage on Tegra264
>> SoCs. The implementation parses the nvidia,cmdqv phandle from the SMMU
>> device tree node to associate each SMMU with its corresponding CMDQV
>> instance.
>>
>> Update the dependency from Kconfig as the driver now supports both
>> ACPI and device tree initialization through conditional compilation.
>>
>> Add nvidia,tegra264-smmu to the arm-smmu-v3 device tree match table to
>> enable device tree based probing on Nvidia Tegra264 platforms and
>> restrict CMDQV usage to other vendors.
>>
>> Reviewed-by: Nicolin Chen <nicolinc at nvidia.com>
>> Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
>> ---
>> ? drivers/iommu/arm/Kconfig???????????????????? |? 2 +-
>> ? drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c?? | 32 ++++++++++++++
>> ? .../iommu/arm/arm-smmu-v3/tegra241-cmdqv.c??? | 43 ++++++++++++++++++-
>> ? 3 files changed, 75 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/iommu/arm/Kconfig b/drivers/iommu/arm/Kconfig
>> index ef42bbe07dbe..168ada9c3d68 100644
>> --- a/drivers/iommu/arm/Kconfig
>> +++ b/drivers/iommu/arm/Kconfig
>> @@ -121,7 +121,7 @@ config ARM_SMMU_V3_KUNIT_TEST
>>
>> ? config TEGRA241_CMDQV
>> ????? bool "NVIDIA Tegra241 CMDQ-V extension support for ARM SMMUv3"
>> -???? depends on ACPI
>> +???? depends on OF || ACPI
>
> This now does nothing, since ARM_SMMU_V3 depends on ARM64 which already
> implies at least OF anyway.
>

Acknowledged, I will remove the dependency.

>> ????? help
>> ??????? Support for NVIDIA CMDQ-Virtualization extension for ARM 
>> SMMUv3. The
>> ??????? CMDQ-V extension is similar to v3.3 ECMDQ for multi command 
>> queues
>> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c 
>> b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> index a33fbd12a0dd..2eec7cd4f3de 100644
>> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> @@ -4530,6 +4530,34 @@ static int arm_smmu_device_hw_probe(struct 
>> arm_smmu_device *smmu)
>> ????? return 0;
>> ? }
>>
>> +#ifdef CONFIG_TEGRA241_CMDQV
>> +static void tegra_cmdqv_dt_probe(struct device_node *smmu_node,
>> +????????????????????????????? struct arm_smmu_device *smmu)
>> +{
>> +???? struct platform_device *pdev;
>> +???? struct device_node *np;
>> +
>> +???? np = of_parse_phandle(smmu_node, "nvidia,cmdqv", 0);
>> +???? if (!np)
>> +???????????? return;
>> +
>> +???? pdev = of_find_device_by_node(np);
>> +???? of_node_put(np);
>> +???? if (!pdev)
>> +???????????? return;
>> +
>
> You need to drop the reference on the platform device too.
>

Yes, I will fix this in next revision.

>> +???? smmu->impl_dev = &pdev->dev;
>> +???? smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
>> +???? dev_info(smmu->dev, "found companion CMDQV device: %s\n",
>> +????????????? dev_name(smmu->impl_dev));
>> +}
>> +#else
>> +static void tegra_cmdqv_dt_probe(struct device_node *smmu_node,
>> +????????????????????????????? struct arm_smmu_device *smmu)
>> +{
>> +}
>> +#endif
>> +
>> ? #ifdef CONFIG_ACPI
>> ? #ifdef CONFIG_TEGRA241_CMDQV
>> ? static void acpi_smmu_dsdt_probe_tegra241_cmdqv(struct 
>> acpi_iort_node *node,
>> @@ -4634,6 +4662,9 @@ static int arm_smmu_device_dt_probe(struct 
>> platform_device *pdev,
>> ????? if (of_dma_is_coherent(dev->of_node))
>> ????????????? smmu->features |= ARM_SMMU_FEAT_COHERENCY;
>>
>> +???? if (of_device_is_compatible(dev->of_node, "nvidia,tegra264-smmu"))
>> +???????????? tegra_cmdqv_dt_probe(dev->of_node, smmu);
>> +
>> ????? return ret;
>> ? }
>>
>> @@ -4867,6 +4898,7 @@ static void arm_smmu_device_shutdown(struct 
>> platform_device *pdev)
>>
>> ? static const struct of_device_id arm_smmu_of_match[] = {
>> ????? { .compatible = "arm,smmu-v3", },
>> +???? { .compatible = "nvidia,tegra264-smmu", },
>
> Since you're not using match data, this is pointless, as anything with
> this compatible must still also match the generic compatible anyway.
>

Sure, I'll remove "nvidia,tegra264-smmu" in next version.

> Thanks,
> Robin.
>
>> ????? { },
>> ? };
>> ? MODULE_DEVICE_TABLE(of, arm_smmu_of_match);
>> diff --git a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c 
>> b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
>> index 378104cd395e..2608bf6518b4 100644
>> --- a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
>> +++ b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
>> @@ -11,6 +11,8 @@
>> ? #include <linux/iommufd.h>
>> ? #include <linux/iopoll.h>
>> ? #include <uapi/linux/iommufd.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/platform_device.h>
>>
>> ? #include <acpi/acpixf.h>
>>
>> @@ -917,6 +919,26 @@ tegra241_cmdqv_find_acpi_resource(struct device 
>> *dev, int *irq)
>> ????? return res;
>> ? }
>>
>> +static struct resource *
>> +tegra241_cmdqv_find_dt_resource(struct device *dev, int *irq)
>> +{
>> +???? struct platform_device *pdev = to_platform_device(dev);
>> +???? struct resource *res;
>> +
>> +???? res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +???? if (!res) {
>> +???????????? dev_err(dev, "no memory resource found for CMDQV\n");
>> +???????????? return NULL;
>> +???? }
>> +
>> +???? if (irq)
>> +???????????? *irq = platform_get_irq_optional(pdev, 0);
>> +???? if (!irq || *irq <= 0)
>> +???????????? dev_warn(dev, "no interrupt. errors will not be 
>> reported\n");
>> +
>> +???? return res;
>> +}
>> +
>> ? static int tegra241_cmdqv_init_structures(struct arm_smmu_device 
>> *smmu)
>> ? {
>> ????? struct tegra241_cmdqv *cmdqv =
>> @@ -1048,11 +1070,14 @@ struct arm_smmu_device 
>> *tegra241_cmdqv_probe(struct arm_smmu_device *smmu)
>>
>> ????? if (!smmu->dev->of_node)
>> ????????????? res = tegra241_cmdqv_find_acpi_resource(smmu->impl_dev, 
>> &irq);
>> +???? else
>> +???????????? res = tegra241_cmdqv_find_dt_resource(smmu->impl_dev, 
>> &irq);
>> ????? if (!res)
>> ????????????? goto out_fallback;
>>
>> ????? new_smmu = __tegra241_cmdqv_probe(smmu, res, irq);
>> -???? kfree(res);
>> +???? if (!smmu->dev->of_node)
>> +???????????? kfree(res);
>>
>> ????? if (new_smmu)
>> ????????????? return new_smmu;
>> @@ -1346,4 +1371,20 @@ tegra241_cmdqv_init_vintf_user(struct 
>> arm_vsmmu *vsmmu,
>> ????? return ret;
>> ? }
>>
>> +static const struct of_device_id tegra241_cmdqv_of_match[] = {
>> +???? { .compatible = "nvidia,tegra264-cmdqv" },
>> +???? { /* sentinel */ }
>> +};
>> +MODULE_DEVICE_TABLE(of, tegra241_cmdqv_of_match);
>> +
>> +static struct platform_driver tegra241_cmdqv_driver = {
>> +???? .driver = {
>> +???????????? .name = "tegra241-cmdqv",
>> +???????????? .of_match_table = tegra241_cmdqv_of_match,
>> +???? },
>> +};
>> +module_platform_driver(tegra241_cmdqv_driver);
>> +
>> +MODULE_DESCRIPTION("NVIDIA Tegra241 Command Queue Virtualization 
>> Driver");
>> +MODULE_LICENSE("GPL");
>> ? MODULE_IMPORT_NS("IOMMUFD");


From andrew at lunn.ch  Mon Dec  1 07:55:21 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Mon, 1 Dec 2025 16:55:21 +0100
Subject: [PATCH RFC net-next 00/15] net: stmmac: rk: cleanups galore
In-Reply-To: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
References: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
Message-ID: <05db9d3e-88fa-42db-8731-b77039c60efa@lunn.ch>

> One of the interesting things is that this appears to deal with RGMII
> delays at the MAC end of the link, but there's no way to tell phylib
> that's the case. I've not looked deeply into what is going on there,
> but it is surprising that the driver insists that the delays (in
> register values?) are provided, but then ignores them depending on the
> exact RGMII mode selected.

Yes, many Rockchip .dts files use phy-mode = 'rgmii', and then do the
delays in the MAC. I've been pushing back on this for a while now, and
in most cases, it is possible to set the delays to 0, and use
'rgmii-id'.

Unfortunately, the vendor version of the driver comes with a debugfs
interface which puts the PHY into loopback, and then steps through the
different delay values to find the range of values which result in no
packet loss. The vendor documentation then recommends
phy-mode='rgmii', and set the delays to the middle value for this
range. So the vendor is leading developers up the garden path.

These delay values also appear to be magical. There has been at least
one attempt to reverse engineer the values back to ns, but it was not
possible to get consistent results across a collection of boards.

       Andrew


From vdonnefort at google.com  Mon Dec  1 08:04:07 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Mon, 1 Dec 2025 16:04:07 +0000
Subject: [PATCH v8 26/28] KVM: arm64: Add hyp_enter/hyp_exit events to
 pKVM hyp
In-Reply-To: <87345vfiqj.wl-maz@kernel.org>
References: <20251107093840.3779150-1-vdonnefort@google.com>
 <20251107093840.3779150-27-vdonnefort@google.com>
 <87345vfiqj.wl-maz@kernel.org>
Message-ID: <aS28dyrKgZaOmMNr@google.com>

On Sun, Nov 30, 2025 at 07:00:52PM +0000, Marc Zyngier wrote:
> On Fri, 07 Nov 2025 09:38:38 +0000,
> Vincent Donnefort <vdonnefort at google.com> wrote:
> > 
> > The hyp_enter and hyp_exit events are logged by the hypervisor any time
> > it is entered and exited.
> > 
> > Signed-off-by: Vincent Donnefort <vdonnefort at google.com>
> > 
> > diff --git a/arch/arm64/include/asm/kvm_hypevents.h b/arch/arm64/include/asm/kvm_hypevents.h
> > index d6e033c96c52..ce3953bc884a 100644
> > --- a/arch/arm64/include/asm/kvm_hypevents.h
> > +++ b/arch/arm64/include/asm/kvm_hypevents.h
> > @@ -7,4 +7,21 @@
> >  #include <nvhe/trace.h>
> >  #endif
> >  
> > +HYP_EVENT(hyp_enter,
> > +	HE_PROTO(void),
> > +	HE_STRUCT(
> > +	),
> > +	HE_ASSIGN(
> > +	),
> > +	HE_PRINTK()
> > +);
> > +
> > +HYP_EVENT(hyp_exit,
> > +	HE_PROTO(void),
> > +	HE_STRUCT(
> > +	),
> > +	HE_ASSIGN(
> > +	),
> > +	HE_PRINTK()
> > +);
> >  #endif
> > diff --git a/arch/arm64/kvm/hyp/include/nvhe/arm-smccc.h b/arch/arm64/kvm/hyp/include/nvhe/arm-smccc.h
> > new file mode 100644
> > index 000000000000..4b69d33e4f2d
> > --- /dev/null
> > +++ b/arch/arm64/kvm/hyp/include/nvhe/arm-smccc.h
> > @@ -0,0 +1,13 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +
> > +#include <asm/kvm_hypevents.h>
> > +
> > +#include <linux/arm-smccc.h>
> > +
> > +#undef arm_smccc_1_1_smc
> > +#define arm_smccc_1_1_smc(...)					\
> > +	do {							\
> > +		trace_hyp_exit();				\
> > +		__arm_smccc_1_1(SMCCC_SMC_INST, __VA_ARGS__);	\
> > +		trace_hyp_enter();				\
> > +	} while (0)
> 
> Huh. No, please. Don't override existing kernel constructs behind
> everybody's back. I know that tracing folks love to play that sort of
> game, but I really don't want any of that here.

And you haven't seen what I had for arm_smccc_1_2_smc()

> 
> Just define a wrapper that is KVM-specific, and use that.
> 
> Then from a semantic perspective, an SMC call, an ERET back to EL1
> host, and an ERET back to EL1 guest are all very different events that
> you lump under the "exit" category. That's not right. Same thing for
> "enter".

The idea of those events is just to know when we enter and exit the hypervisor,
purely from a timing point of view. In ACK, we already have other separated
events that can give the "cause" for entering or exiting the hypervisor. I
haven't added them to that series because I thought it was big enough.

So happy to add now or do a follow-up, once we're done with that one?

> 
> Thanks,
> 
> 	M.
> 
> -- 
> Jazz isn't dead. It just smells funny.


From mathieu.poirier at linaro.org  Mon Dec  1 08:20:35 2025
From: mathieu.poirier at linaro.org (Mathieu Poirier)
Date: Mon, 1 Dec 2025 09:20:35 -0700
Subject: [PATCH 0/4] ASoC / rpmsg / remoteproc / soc: qcom: Constify
 buffer passed to send functions
In-Reply-To: <20251130-rpmsg-send-const-v1-0-cb11c7e0a024@oss.qualcomm.com>
References: <20251130-rpmsg-send-const-v1-0-cb11c7e0a024@oss.qualcomm.com>
Message-ID: <aS3AU0gEEOvWs4Uw@p14s>

On Sun, Nov 30, 2025 at 01:36:07PM +0100, Krzysztof Kozlowski wrote:
> Dependencies / merging
> ======================
> Entire patchset is one logical chain, all further patches depend on
> previous ones, thus everything should be taken via same tree or shared
> between trees with tags.  Probably everything should go via ASoC with
> necessary acks.
> 
> Also, first patch or two patches could be taken now for this merge
> window...
> 
> Description
> ===========
> The remoteproc and rpmsg send-like functions should not modify data
> being sent, so buffer should be marked as pointer to const.  This is not
> only self-documenting code but actually increases the actual safety and
> clearly documents who is the owner of passed buffer.
> 
> Best regards,
> Krzysztof
> 
> ---
> Krzysztof Kozlowski (4):
>       remoteproc: mtp_scp_ipi: Constify buffer passed to scp_ipi_send()
>       remoteproc: mtp_scp: Constify buffer passed to scp_send_ipi()
>       rpmsg: Constify buffer passed to send API
>       ASoC: qcom:: Constify GPR packet being send over GPR interface
> 
>  drivers/remoteproc/mtk_scp.c       |  2 +-
>  drivers/remoteproc/mtk_scp_ipi.c   |  2 +-
>  drivers/rpmsg/mtk_rpmsg.c          |  4 ++--
>  drivers/rpmsg/qcom_glink_native.c  | 13 ++++++++-----
>  drivers/rpmsg/qcom_smd.c           | 10 ++++++----
>  drivers/rpmsg/rpmsg_core.c         |  8 ++++----
>  drivers/rpmsg/rpmsg_internal.h     |  8 ++++----
>  drivers/rpmsg/virtio_rpmsg_bus.c   | 24 +++++++++++++-----------
>  drivers/soc/qcom/apr.c             |  8 ++++----
>  include/linux/remoteproc/mtk_scp.h |  2 +-
>  include/linux/rpmsg.h              | 17 +++++++++--------
>  include/linux/rpmsg/mtk_rpmsg.h    |  2 +-
>  include/linux/soc/qcom/apr.h       |  4 ++--

Acked-by: Mathieu Poirier <mathieuu.poirier at linaro.org>

I'll let Bjorn decide if he wants to include this in his upcoming pull request.

Thanks,
Mathieu

>  sound/soc/qcom/qdsp6/audioreach.c  |  6 +++---
>  sound/soc/qcom/qdsp6/audioreach.h  |  4 ++--
>  sound/soc/qcom/qdsp6/q6apm.c       |  3 ++-
>  sound/soc/qcom/qdsp6/q6apm.h       |  2 +-
>  17 files changed, 64 insertions(+), 55 deletions(-)
> ---
> base-commit: 7a9e871ce4c7c8a7d75eaef8407083a0525de2dd
> change-id: 20251130-rpmsg-send-const-ae216a1fbd8f
> 
> Best regards,
> -- 
> Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
> 


From david at kernel.org  Mon Dec  1 08:23:13 2025
From: david at kernel.org (David Hildenbrand (Red Hat))
Date: Mon, 1 Dec 2025 17:23:13 +0100
Subject: [PATCH 0/2] support batched checks of the references for large
 folios
In-Reply-To: <cover.1763976541.git.baolin.wang@linux.alibaba.com>
References: <cover.1763976541.git.baolin.wang@linux.alibaba.com>
Message-ID: <341d1aed-13ad-41ee-ad30-487c5baec399@kernel.org>

On 11/25/25 01:56, Baolin Wang wrote:
> Currently, folio_referenced_one() always checks the young flag for each PTE
> sequentially, which is inefficient for large folios. This inefficiency is
> especially noticeable when reclaiming clean file-backed large folios, where
> folio_referenced() is observed as a significant performance hotspot.
> 
> Moreover, on Arm architecture, which supports contiguous PTEs, there is already
> an optimization to clear the young flags for PTEs within a contiguous range.
> However, this is not sufficient. We can extend this to perform batched operations
> for the entire large folio (which might exceed the contiguous range: CONT_PTE_SIZE).
> 
> By supporting batched checking of the young flags and flushing TLB entries,
> I observed a 33% performance improvement in my file-backed folios reclaim tests.

Can you point at the benchmark or briefly explain what it does? What 
exactly are we measuring that improves by 33%?

-- 
Cheers

David


From balejk at matfyz.cz  Mon Dec  1 08:25:27 2025
From: balejk at matfyz.cz (Karel Balej)
Date: Mon, 01 Dec 2025 17:25:27 +0100
Subject: [DONOTAPPLY RFC PATCH v2 0/4] WiFi support for
 samsung,coreprimevelte
In-Reply-To: <aSnWYS2g5slVFaSk@gaggiata.pivistrello.it>
References: <20251026182602.26464-1-balejk@matfyz.cz>
 <DEJL1ATTQMVE.120JV9YW59I27@matfyz.cz>
 <aSnWYS2g5slVFaSk@gaggiata.pivistrello.it>
Message-ID: <DEN0QJT6O8BU.3INUCXH1I0P0F@matfyz.cz>

Hello, Francesco,

Francesco Dolcini, 2025-11-28T18:05:37+01:00:
> On Thu, Nov 27, 2025 at 04:29:12PM +0100, Karel Balej wrote:
>> To reiterate, the firmware is generally available but is not part of
>> linux-firmware and the entire process of upstreaming the chipset support is
>> stuck on that.
>
> I'll try to see if any of my contact in NXP Wi-Fi group is able to help. Give
> me a few days.

that's great, thank you very much!

I have received a reply from Jeff in the meantime who has discussed the
matter with his managers and unfortunately, they are not interested in
supporting this chip as it's considered outdated and would pose
maintainance burden.

Jeff however thinks that you as their customer may perhaps have more
luck when talking to them.

I am also still trying to find out whether upstreaming the old firmware
version (available as part of the stock Android) would be an acceptable
compromise for them - I never really intended for this to be supported
officially and I wasn't too hopeful about getting an up to date version
of the firmware either (although it would be very useful as it would
likely solve the issue I'm hacking around in the third patch of this
series), I mainly just want to upstream the support for the chipset as
far as possible.

Please let me know when you have some news.

Thanks again and best regards,
K. B.


From quentin.schulz at cherry.de  Mon Dec  1 08:31:44 2025
From: quentin.schulz at cherry.de (Quentin Schulz)
Date: Mon, 1 Dec 2025 17:31:44 +0100
Subject: [PATCH v2 8/9] arm64: dts: rockchip: Enable HDMI output on
 RK3368-Lion-Haikou
In-Reply-To: <20251021074254.87065-9-heiko@sntech.de>
References: <20251021074254.87065-1-heiko@sntech.de>
 <20251021074254.87065-9-heiko@sntech.de>
Message-ID: <f8af1ebc-c002-4f14-95bc-082474d8f187@cherry.de>

Hi Heiko,

On 10/21/25 9:42 AM, Heiko Stuebner wrote:
> From: Heiko Stuebner <heiko.stuebner at cherry.de>
> 
> Enable the VOP and HDMI controller on the Lion-Haikou board.
> 
> Signed-off-by: Heiko Stuebner <heiko.stuebner at cherry.de>
> ---
>   .../boot/dts/rockchip/rk3368-lion-haikou.dts   | 18 ++++++++++++++++++
>   1 file changed, 18 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts b/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts
> index abd1af97456a..a8eb4e9c2778 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts
> +++ b/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts
> @@ -58,6 +58,16 @@ vcc5v0_otg: regulator-vcc5v0-otg {
>   	};
>   };
>   
> +&display_subsystem {
> +	status = "okay";
> +};
> +
> +&hdmi {
> +	avdd-0v9-supply = <&vdd10_video>;
> +	avdd-1v8-supply = <&vcc18_video>;
> +	status = "okay";
> +};
> +
>   &i2c_lvds_blc {
>   	eeprom: eeprom at 50 {
>   		compatible = "atmel,24c01";
> @@ -101,6 +111,14 @@ &uart1 {
>   	status = "disabled";
>   };
>   
> +&vop {
> +	status = "okay";
> +};
> +
> +&vop_mmu {
> +	status = "okay";
> +};
> +

This isn't alphabetically sorted (see &pinctrl right after) but I think 
it's rather pinctrl being in the wrong location than vop* as all the 
other nodes seem to be sorted properly, thus:

Reviewed-by: Quentin Schulz <quentin.schulz at cherry.de>

Thanks!
Quentin


From amhetre at nvidia.com  Mon Dec  1 08:32:16 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Mon, 1 Dec 2025 16:32:16 +0000
Subject: [PATCH V3 0/3] Add device tree support for NVIDIA Tegra CMDQV
Message-ID: <20251201163219.3237266-1-amhetre@nvidia.com>

This series adds device tree support for the CMDQ-Virtualization (CMDQV)
hardware on NVIDIA Tegra264 SoCs.

CMDQV is a hardware block that works alongside the ARM SMMUv3 to assist in
virtualizing the command queue. It was previously only supported through
ACPI on Tegra241. This series extends the existing driver to support device
tree based initialization, which is required for Tegra264 platforms.

The series is structured as follows:

Patch 1: Extends the tegra241-cmdqv driver to support device tree probing
         alongside the existing ACPI support. The SMMU driver now parses
         the nvidia,cmdqv phandle to associate each SMMU with its
         corresponding CMDQV instance.

Patch 2: Adds device tree binding documentation for nvidia,tegra264-cmdqv
         and extends the arm,smmu-v3 binding with an optional nvidia,cmdqv
         property.

Patch 3: Adds CMDQV device nodes to the Tegra264 device tree and enables
         them on the tegra264-p3834 platform.

The implementation follows the existing ACPI probe path to minimize code
divergence and maintain consistency with Tegra241 support.

Changes in V3:
- Remove the Kconfig dependency for CONFIG_TEGRA241_CMDQV
- Drop the reference on the platform device after getting it from
  of_find_device_by_node()
- Remove the unnecessary "nvidia,tegra264-smmu" compatible string from
  arm-smmu-v3 match table
- Order CMDQV nodes in device tree files according to its address

Changes in V2:
- Updated dependency for CONFIG_TEGRA241_CMDQV on OF || ACPI
- Changed maintainer to Nicolin Chen
- Removed interrupt-names property
- Added nvidia,tegra264-smmu to compatible enum for arm-smmu-v3
- Added allOf constraint to restrict nvidia,cmdqv property to
  nvidia,tegra264-smmu only
- Updated SMMU nodes in device tree to use nvidia,tegra264-smmu compatible
  string

Ashish Mhetre (3):
  iommu/arm-smmu-v3: Add device-tree support for CMDQV driver
  dt-bindings: iommu: Add NVIDIA Tegra CMDQV support
  arm64: dts: nvidia: Add nodes for CMDQV

 .../bindings/iommu/arm,smmu-v3.yaml           | 30 +++++++++-
 .../bindings/iommu/nvidia,tegra264-cmdqv.yaml | 42 ++++++++++++++
 .../arm64/boot/dts/nvidia/tegra264-p3834.dtsi |  8 +++
 arch/arm64/boot/dts/nvidia/tegra264.dtsi      | 55 +++++++++++++++++--
 drivers/iommu/arm/Kconfig                     |  1 -
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 32 +++++++++++
 .../iommu/arm/arm-smmu-v3/tegra241-cmdqv.c    | 43 ++++++++++++++-
 7 files changed, 202 insertions(+), 9 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/iommu/nvidia,tegra264-cmdqv.yaml

-- 
2.25.1



From amhetre at nvidia.com  Mon Dec  1 08:32:17 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Mon, 1 Dec 2025 16:32:17 +0000
Subject: [PATCH V3 1/3] iommu/arm-smmu-v3: Add device-tree support for CMDQV driver
In-Reply-To: <20251201163219.3237266-1-amhetre@nvidia.com>
References: <20251201163219.3237266-1-amhetre@nvidia.com>
Message-ID: <20251201163219.3237266-2-amhetre@nvidia.com>

Add device tree support to the CMDQV driver to enable usage on Tegra264
SoCs. The implementation parses the nvidia,cmdqv phandle from the SMMU
device tree node to associate each SMMU with its corresponding CMDQV
instance based on compatible string.

Remove the dependency from Kconfig as the driver now supports both ACPI
and device tree initialization through conditional compilation and
ARM_SMMU_V3 depends on ARM64 which implies at least OF.

Reviewed-by: Nicolin Chen <nicolinc at nvidia.com>
Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
---
 drivers/iommu/arm/Kconfig                     |  1 -
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 32 ++++++++++++++
 .../iommu/arm/arm-smmu-v3/tegra241-cmdqv.c    | 43 ++++++++++++++++++-
 3 files changed, 74 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/arm/Kconfig b/drivers/iommu/arm/Kconfig
index ef42bbe07dbe..5fac08b89dee 100644
--- a/drivers/iommu/arm/Kconfig
+++ b/drivers/iommu/arm/Kconfig
@@ -121,7 +121,6 @@ config ARM_SMMU_V3_KUNIT_TEST
 
 config TEGRA241_CMDQV
 	bool "NVIDIA Tegra241 CMDQ-V extension support for ARM SMMUv3"
-	depends on ACPI
 	help
 	  Support for NVIDIA CMDQ-Virtualization extension for ARM SMMUv3. The
 	  CMDQ-V extension is similar to v3.3 ECMDQ for multi command queues
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index a33fbd12a0dd..206dffabc9c0 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -4530,6 +4530,35 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
 	return 0;
 }
 
+#ifdef CONFIG_TEGRA241_CMDQV
+static void tegra_cmdqv_dt_probe(struct device_node *smmu_node,
+				 struct arm_smmu_device *smmu)
+{
+	struct platform_device *pdev;
+	struct device_node *np;
+
+	np = of_parse_phandle(smmu_node, "nvidia,cmdqv", 0);
+	if (!np)
+		return;
+
+	pdev = of_find_device_by_node(np);
+	of_node_put(np);
+	if (!pdev)
+		return;
+
+	smmu->impl_dev = &pdev->dev;
+	smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
+	dev_info(smmu->dev, "found companion CMDQV device: %s\n",
+		 dev_name(smmu->impl_dev));
+	put_device(&pdev->dev);
+}
+#else
+static void tegra_cmdqv_dt_probe(struct device_node *smmu_node,
+				 struct arm_smmu_device *smmu)
+{
+}
+#endif
+
 #ifdef CONFIG_ACPI
 #ifdef CONFIG_TEGRA241_CMDQV
 static void acpi_smmu_dsdt_probe_tegra241_cmdqv(struct acpi_iort_node *node,
@@ -4634,6 +4663,9 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev,
 	if (of_dma_is_coherent(dev->of_node))
 		smmu->features |= ARM_SMMU_FEAT_COHERENCY;
 
+	if (of_device_is_compatible(dev->of_node, "nvidia,tegra264-smmu"))
+		tegra_cmdqv_dt_probe(dev->of_node, smmu);
+
 	return ret;
 }
 
diff --git a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
index 378104cd395e..2608bf6518b4 100644
--- a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
+++ b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
@@ -11,6 +11,8 @@
 #include <linux/iommufd.h>
 #include <linux/iopoll.h>
 #include <uapi/linux/iommufd.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
 
 #include <acpi/acpixf.h>
 
@@ -917,6 +919,26 @@ tegra241_cmdqv_find_acpi_resource(struct device *dev, int *irq)
 	return res;
 }
 
+static struct resource *
+tegra241_cmdqv_find_dt_resource(struct device *dev, int *irq)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "no memory resource found for CMDQV\n");
+		return NULL;
+	}
+
+	if (irq)
+		*irq = platform_get_irq_optional(pdev, 0);
+	if (!irq || *irq <= 0)
+		dev_warn(dev, "no interrupt. errors will not be reported\n");
+
+	return res;
+}
+
 static int tegra241_cmdqv_init_structures(struct arm_smmu_device *smmu)
 {
 	struct tegra241_cmdqv *cmdqv =
@@ -1048,11 +1070,14 @@ struct arm_smmu_device *tegra241_cmdqv_probe(struct arm_smmu_device *smmu)
 
 	if (!smmu->dev->of_node)
 		res = tegra241_cmdqv_find_acpi_resource(smmu->impl_dev, &irq);
+	else
+		res = tegra241_cmdqv_find_dt_resource(smmu->impl_dev, &irq);
 	if (!res)
 		goto out_fallback;
 
 	new_smmu = __tegra241_cmdqv_probe(smmu, res, irq);
-	kfree(res);
+	if (!smmu->dev->of_node)
+		kfree(res);
 
 	if (new_smmu)
 		return new_smmu;
@@ -1346,4 +1371,20 @@ tegra241_cmdqv_init_vintf_user(struct arm_vsmmu *vsmmu,
 	return ret;
 }
 
+static const struct of_device_id tegra241_cmdqv_of_match[] = {
+	{ .compatible = "nvidia,tegra264-cmdqv" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, tegra241_cmdqv_of_match);
+
+static struct platform_driver tegra241_cmdqv_driver = {
+	.driver = {
+		.name = "tegra241-cmdqv",
+		.of_match_table = tegra241_cmdqv_of_match,
+	},
+};
+module_platform_driver(tegra241_cmdqv_driver);
+
+MODULE_DESCRIPTION("NVIDIA Tegra241 Command Queue Virtualization Driver");
+MODULE_LICENSE("GPL");
 MODULE_IMPORT_NS("IOMMUFD");
-- 
2.25.1



From amhetre at nvidia.com  Mon Dec  1 08:32:18 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Mon, 1 Dec 2025 16:32:18 +0000
Subject: [PATCH V3 2/3] dt-bindings: iommu: Add NVIDIA Tegra CMDQV support
In-Reply-To: <20251201163219.3237266-1-amhetre@nvidia.com>
References: <20251201163219.3237266-1-amhetre@nvidia.com>
Message-ID: <20251201163219.3237266-3-amhetre@nvidia.com>

The Command Queue Virtualization (CMDQV) hardware is part of the
SMMUv3 implementation on NVIDIA Tegra SoCs. It assists in
virtualizing the command queue for the SMMU.

Add a new device tree binding document for nvidia,tegra264-cmdqv.

Also update the arm,smmu-v3 binding to include an optional nvidia,cmdqv
property. This property is a phandle to the CMDQV device node, allowing
the SMMU driver to associate with its corresponding CMDQV instance.
Restrict this property usage to Nvidia Tegra264 only.

Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
---
 .../bindings/iommu/arm,smmu-v3.yaml           | 30 ++++++++++++-
 .../bindings/iommu/nvidia,tegra264-cmdqv.yaml | 42 +++++++++++++++++++
 2 files changed, 70 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/iommu/nvidia,tegra264-cmdqv.yaml

diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
index 75fcf4cb52d9..1c03482e4c61 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
@@ -20,7 +20,12 @@ properties:
   $nodename:
     pattern: "^iommu@[0-9a-f]*"
   compatible:
-    const: arm,smmu-v3
+    oneOf:
+      - const: arm,smmu-v3
+      - items:
+          - enum:
+              - nvidia,tegra264-smmu
+          - const: arm,smmu-v3
 
   reg:
     maxItems: 1
@@ -58,6 +63,15 @@ properties:
 
   msi-parent: true
 
+  nvidia,cmdqv:
+    description: |
+      A phandle to its pairing CMDQV extension for an implementation on NVIDIA
+      Tegra SoC.
+
+      If this property is absent, CMDQ-Virtualization won't be used and SMMU
+      will only use its own CMDQ.
+    $ref: /schemas/types.yaml#/definitions/phandle
+
   hisilicon,broken-prefetch-cmd:
     type: boolean
     description: Avoid sending CMD_PREFETCH_* commands to the SMMU.
@@ -69,6 +83,17 @@ properties:
       register access with page 0 offsets. Set for Cavium ThunderX2 silicon that
       doesn't support SMMU page1 register space.
 
+allOf:
+  - if:
+      not:
+        properties:
+          compatible:
+            contains:
+              const: nvidia,tegra264-smmu
+    then:
+      properties:
+        nvidia,cmdqv: false
+
 required:
   - compatible
   - reg
@@ -82,7 +107,7 @@ examples:
     #include <dt-bindings/interrupt-controller/irq.h>
 
     iommu at 2b400000 {
-            compatible = "arm,smmu-v3";
+            compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
             reg = <0x2b400000 0x20000>;
             interrupts = <GIC_SPI 74 IRQ_TYPE_EDGE_RISING>,
                          <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>,
@@ -92,4 +117,5 @@ examples:
             dma-coherent;
             #iommu-cells = <1>;
             msi-parent = <&its 0xff0000>;
+            nvidia,cmdqv = <&cmdqv>;
     };
diff --git a/Documentation/devicetree/bindings/iommu/nvidia,tegra264-cmdqv.yaml b/Documentation/devicetree/bindings/iommu/nvidia,tegra264-cmdqv.yaml
new file mode 100644
index 000000000000..3f5006a59805
--- /dev/null
+++ b/Documentation/devicetree/bindings/iommu/nvidia,tegra264-cmdqv.yaml
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iommu/nvidia,tegra264-cmdqv.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra264 CMDQV
+
+description:
+  The CMDQ-Virtualization hardware block is part of the SMMUv3 implementation
+  on Tegra264 SoCs. It assists in virtualizing the command queue for the SMMU.
+
+maintainers:
+  - Nicolin Chen <nicolinc at nvidia.com>
+
+properties:
+  compatible:
+    const: nvidia,tegra264-cmdqv
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    cmdqv at 5200000 {
+            compatible = "nvidia,tegra264-cmdqv";
+            reg = <0x5200000 0x830000>;
+            interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+    };
-- 
2.25.1



From amhetre at nvidia.com  Mon Dec  1 08:32:19 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Mon, 1 Dec 2025 16:32:19 +0000
Subject: [PATCH V3 3/3] arm64: dts: nvidia: Add nodes for CMDQV
In-Reply-To: <20251201163219.3237266-1-amhetre@nvidia.com>
References: <20251201163219.3237266-1-amhetre@nvidia.com>
Message-ID: <20251201163219.3237266-4-amhetre@nvidia.com>

The Command Queue Virtualization (CMDQV) hardware is part of the
SMMUv3 implementation on NVIDIA Tegra SoCs. It assists in
virtualizing the command queue for the SMMU.

Update SMMU compatible strings to use nvidia,tegra264-smmu to enable
CMDQV support. Add device tree nodes for the CMDQV hardware and enable
them on the tegra264-p3834 platform where SMMUs are enabled. Each SMMU
instance is paired with its corresponding CMDQV instance via the
nvidia,cmdqv property.

Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
---
 .../arm64/boot/dts/nvidia/tegra264-p3834.dtsi |  8 +++
 arch/arm64/boot/dts/nvidia/tegra264.dtsi      | 55 +++++++++++++++++--
 2 files changed, 58 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi b/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
index 06795c82427a..7e2c3e66c2ab 100644
--- a/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
@@ -23,8 +23,16 @@ iommu at 5000000 {
 			status = "okay";
 		};
 
+		cmdqv at 5200000 {
+			status = "okay";
+		};
+
 		iommu at 6000000 {
 			status = "okay";
 		};
+
+		cmdqv at 6200000 {
+			status = "okay";
+		};
 	};
 };
diff --git a/arch/arm64/boot/dts/nvidia/tegra264.dtsi b/arch/arm64/boot/dts/nvidia/tegra264.dtsi
index f137565da804..5124715caeb3 100644
--- a/arch/arm64/boot/dts/nvidia/tegra264.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra264.dtsi
@@ -3361,7 +3361,7 @@ bus at 8100000000 {
 			 <0x02 0x00000000 0xd0 0x00000000 0x08 0x80000000>; /* ECAM, prefetchable memory, I/O */
 
 		smmu1: iommu at 5000000 {
-			compatible = "arm,smmu-v3";
+			compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
 			reg = <0x00 0x5000000 0x0 0x200000>;
 			interrupts = <GIC_SPI 12 IRQ_TYPE_EDGE_RISING>,
 				     <GIC_SPI 13 IRQ_TYPE_EDGE_RISING>;
@@ -3370,10 +3370,19 @@ smmu1: iommu at 5000000 {
 
 			#iommu-cells = <1>;
 			dma-coherent;
+			nvidia,cmdqv = <&cmdqv1>;
+		};
+
+		cmdqv1: cmdqv at 5200000 {
+			compatible = "nvidia,tegra264-cmdqv";
+			status = "disabled";
+
+			reg = <0x00 0x5200000 0x0 0x830000>;
+			interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
 		};
 
 		smmu2: iommu at 6000000 {
-			compatible = "arm,smmu-v3";
+			compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
 			reg = <0x00 0x6000000 0x0 0x200000>;
 			interrupts = <GIC_SPI 1 IRQ_TYPE_EDGE_RISING>,
 				     <GIC_SPI 2 IRQ_TYPE_EDGE_RISING>;
@@ -3382,6 +3391,15 @@ smmu2: iommu at 6000000 {
 
 			#iommu-cells = <1>;
 			dma-coherent;
+			nvidia,cmdqv = <&cmdqv2>;
+		};
+
+		cmdqv2: cmdqv at 6200000 {
+			compatible = "nvidia,tegra264-cmdqv";
+			status = "disabled";
+
+			reg = <0x00 0x6200000 0x0 0x830000>;
+			interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
 		};
 
 		mc: memory-controller at 8020000 {
@@ -3437,7 +3455,7 @@ emc: external-memory-controller at 8800000 {
 		};
 
 		smmu0: iommu at a000000 {
-			compatible = "arm,smmu-v3";
+			compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
 			reg = <0x00 0xa000000 0x0 0x200000>;
 			interrupts = <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>,
 				     <GIC_SPI 22 IRQ_TYPE_EDGE_RISING>;
@@ -3446,10 +3464,19 @@ smmu0: iommu at a000000 {
 
 			#iommu-cells = <1>;
 			dma-coherent;
+			nvidia,cmdqv = <&cmdqv0>;
+		};
+
+		cmdqv0: cmdqv at a200000 {
+			compatible = "nvidia,tegra264-cmdqv";
+			status = "disabled";
+
+			reg = <0x00 0xa200000 0x0 0x830000>;
+			interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
 		};
 
 		smmu4: iommu at b000000 {
-			compatible = "arm,smmu-v3";
+			compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
 			reg = <0x00 0xb000000 0x0 0x200000>;
 			interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
 				     <GIC_SPI 31 IRQ_TYPE_EDGE_RISING>;
@@ -3458,6 +3485,15 @@ smmu4: iommu at b000000 {
 
 			#iommu-cells = <1>;
 			dma-coherent;
+			nvidia,cmdqv = <&cmdqv4>;
+		};
+
+		cmdqv4: cmdqv at b200000 {
+			compatible = "nvidia,tegra264-cmdqv";
+			status = "disabled";
+
+			reg = <0x00 0xb200000 0x0 0x830000>;
+			interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
 		};
 
 		i2c14: i2c at c410000 {
@@ -3690,7 +3726,7 @@ bus at 8800000000 {
 		ranges = <0x00 0x00000000 0x88 0x00000000 0x01 0x00000000>;
 
 		smmu3: iommu at 6000000 {
-			compatible = "arm,smmu-v3";
+			compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
 			reg = <0x00 0x6000000 0x0 0x200000>;
 			interrupts = <GIC_SPI 225 IRQ_TYPE_EDGE_RISING>,
 				     <GIC_SPI 226 IRQ_TYPE_EDGE_RISING>;
@@ -3699,6 +3735,15 @@ smmu3: iommu at 6000000 {
 
 			#iommu-cells = <1>;
 			dma-coherent;
+			nvidia,cmdqv = <&cmdqv3>;
+		};
+
+		cmdqv3: cmdqv at 6200000 {
+			compatible = "nvidia,tegra264-cmdqv";
+			status = "disabled";
+
+			reg = <0x00 0x6200000 0x0 0x830000>;
+			interrupts = <GIC_SPI 232 IRQ_TYPE_LEVEL_HIGH>;
 		};
 
 		hda at 90b0000 {
-- 
2.25.1



From maz at kernel.org  Mon Dec  1 08:33:28 2025
From: maz at kernel.org (Marc Zyngier)
Date: Mon, 01 Dec 2025 16:33:28 +0000
Subject: [PATCH v8 26/28] KVM: arm64: Add hyp_enter/hyp_exit events to pKVM hyp
In-Reply-To: <aS28dyrKgZaOmMNr@google.com>
References: <20251107093840.3779150-1-vdonnefort@google.com>
	<20251107093840.3779150-27-vdonnefort@google.com>
	<87345vfiqj.wl-maz@kernel.org>
	<aS28dyrKgZaOmMNr@google.com>
Message-ID: <86o6oip3fr.wl-maz@kernel.org>

On Mon, 01 Dec 2025 16:04:07 +0000,
Vincent Donnefort <vdonnefort at google.com> wrote:
> 
> On Sun, Nov 30, 2025 at 07:00:52PM +0000, Marc Zyngier wrote:
> > On Fri, 07 Nov 2025 09:38:38 +0000,
> > Vincent Donnefort <vdonnefort at google.com> wrote:
> > > 
> > > The hyp_enter and hyp_exit events are logged by the hypervisor any time
> > > it is entered and exited.
> > > 
> > > Signed-off-by: Vincent Donnefort <vdonnefort at google.com>
> > > 
> > > diff --git a/arch/arm64/include/asm/kvm_hypevents.h b/arch/arm64/include/asm/kvm_hypevents.h
> > > index d6e033c96c52..ce3953bc884a 100644
> > > --- a/arch/arm64/include/asm/kvm_hypevents.h
> > > +++ b/arch/arm64/include/asm/kvm_hypevents.h
> > > @@ -7,4 +7,21 @@
> > >  #include <nvhe/trace.h>
> > >  #endif
> > >  
> > > +HYP_EVENT(hyp_enter,
> > > +	HE_PROTO(void),
> > > +	HE_STRUCT(
> > > +	),
> > > +	HE_ASSIGN(
> > > +	),
> > > +	HE_PRINTK()
> > > +);
> > > +
> > > +HYP_EVENT(hyp_exit,
> > > +	HE_PROTO(void),
> > > +	HE_STRUCT(
> > > +	),
> > > +	HE_ASSIGN(
> > > +	),
> > > +	HE_PRINTK()
> > > +);
> > >  #endif
> > > diff --git a/arch/arm64/kvm/hyp/include/nvhe/arm-smccc.h b/arch/arm64/kvm/hyp/include/nvhe/arm-smccc.h
> > > new file mode 100644
> > > index 000000000000..4b69d33e4f2d
> > > --- /dev/null
> > > +++ b/arch/arm64/kvm/hyp/include/nvhe/arm-smccc.h
> > > @@ -0,0 +1,13 @@
> > > +/* SPDX-License-Identifier: GPL-2.0-only */
> > > +
> > > +#include <asm/kvm_hypevents.h>
> > > +
> > > +#include <linux/arm-smccc.h>
> > > +
> > > +#undef arm_smccc_1_1_smc
> > > +#define arm_smccc_1_1_smc(...)					\
> > > +	do {							\
> > > +		trace_hyp_exit();				\
> > > +		__arm_smccc_1_1(SMCCC_SMC_INST, __VA_ARGS__);	\
> > > +		trace_hyp_enter();				\
> > > +	} while (0)
> > 
> > Huh. No, please. Don't override existing kernel constructs behind
> > everybody's back. I know that tracing folks love to play that sort of
> > game, but I really don't want any of that here.
> 
> And you haven't seen what I had for arm_smccc_1_2_smc()

I have the feeling that I don't want to see it at all!

> > Just define a wrapper that is KVM-specific, and use that.
> > 
> > Then from a semantic perspective, an SMC call, an ERET back to EL1
> > host, and an ERET back to EL1 guest are all very different events that
> > you lump under the "exit" category. That's not right. Same thing for
> > "enter".
> 
> The idea of those events is just to know when we enter and exit the hypervisor,
> purely from a timing point of view. In ACK, we already have other separated
> events that can give the "cause" for entering or exiting the hypervisor. I
> haven't added them to that series because I thought it was big enough.
> 
> So happy to add now or do a follow-up, once we're done with that one?

Fixed trace points are ABI AFAIC, so I'd rather we make them useful
from the very start. What you have here is not very interesting,
because it makes all entry and exit points equal -- they very much
aren't.

So get rid of these and implement the real thing.

Thanks,

	M.

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


From linux at armlinux.org.uk  Mon Dec  1 08:38:22 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 1 Dec 2025 16:38:22 +0000
Subject: [PATCH RFC net-next 00/15] net: stmmac: rk: cleanups galore
In-Reply-To: <05db9d3e-88fa-42db-8731-b77039c60efa@lunn.ch>
References: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
 <05db9d3e-88fa-42db-8731-b77039c60efa@lunn.ch>
Message-ID: <aS3EfuypsaGK6Ww_@shell.armlinux.org.uk>

On Mon, Dec 01, 2025 at 04:55:21PM +0100, Andrew Lunn wrote:
> > One of the interesting things is that this appears to deal with RGMII
> > delays at the MAC end of the link, but there's no way to tell phylib
> > that's the case. I've not looked deeply into what is going on there,
> > but it is surprising that the driver insists that the delays (in
> > register values?) are provided, but then ignores them depending on the
> > exact RGMII mode selected.
> 
> Yes, many Rockchip .dts files use phy-mode = 'rgmii', and then do the
> delays in the MAC. I've been pushing back on this for a while now, and
> in most cases, it is possible to set the delays to 0, and use
> 'rgmii-id'.
> 
> Unfortunately, the vendor version of the driver comes with a debugfs
> interface which puts the PHY into loopback, and then steps through the
> different delay values to find the range of values which result in no
> packet loss. The vendor documentation then recommends
> phy-mode='rgmii', and set the delays to the middle value for this
> range. So the vendor is leading developers up the garden path.
> 
> These delay values also appear to be magical. There has been at least
> one attempt to reverse engineer the values back to ns, but it was not
> possible to get consistent results across a collection of boards.

Oh yes, I remember that. I also remember that I had asked for the
re-use of "phy_power_on()" to be fixed:

https://lore.kernel.org/netdev/aDne1Ybuvbk0AwG0 at shell.armlinux.org.uk/

but that never happened... which makes me wonder whether we *shouldn't*
have applied "sensor101"'s patch until such a requested patch was
available. In my experience, this is the standard behaviour - as a
reviewer, you ask a contributor to do something as part of their
patch submission, and as long as their patch gets merged, they
couldn't give a monkeys about your request.

So, in future, I'm going to take the attitude that I will NAK
contributions if I think there's a side issue that the contributor
should also be addressing until that side issue is addressed.

This shouldn't be necessary, I wish this weren't necessary, and I wish
people could be relied upon to do the right thing, but apparently it is
going to take a stick (not merging their patches) to get them to co-
operate. More fool me for trusting someone to do something.

I now have a couple of extra patches addressing my point raised in
that email... which I myself shouldn't have had to write.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From james.clark at linaro.org  Mon Dec  1 08:41:03 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 01 Dec 2025 16:41:03 +0000
Subject: [PATCH 0/7] perf cs-etm/arm-spe: Remove hard coded config fields
Message-ID: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>

The specific config field that an event format attribute is in is
consistently hard coded, even though the API is supposed to be that the
driver publishes the config field name. To stop this pattern from being
copy pasted and causing problems in the future, replace them all with
calls to a new helper that returns the value that a user set.

The existing evsel__set_config_if_unset() also has a similar problem
that it hard codes attr.config, so fix that too.

There are no functional changes here because all the fields touched are
in attr.config and not config1 or config2 etc. Although this may not be
the case for new fields.

Signed-off-by: James Clark <james.clark at linaro.org>
---
James Clark (7):
      perf tools: Track all user changed config bits
      perf tools: apply evsel__set_config_if_unset() to all config fields
      perf cs-etm: Make a helper to find the Coresight evsel
      perf cs-etm: Don't use hard coded config bits when setting up ETMCR
      perf cs-etm: Don't use hard coded config bits when setting up TRCCONFIGR
      perf cs-etm: Don't hard code config attribute when configuring the event
      perf arm-spe: Don't hard code config attribute

 tools/perf/arch/arm/util/cs-etm.c    | 202 ++++++++++++++++++++---------------
 tools/perf/arch/arm64/util/arm-spe.c |  15 +--
 tools/perf/util/evsel.c              |   6 +-
 tools/perf/util/evsel.h              |   2 +
 tools/perf/util/evsel_config.h       |   6 +-
 tools/perf/util/parse-events.c       |  89 +++++++--------
 tools/perf/util/pmu.c                |  93 +++++++++++++---
 7 files changed, 251 insertions(+), 162 deletions(-)
---
base-commit: 834ebb5678d75d844f5d4f44ede78724d8c96630
change-id: 20251112-james-perf-config-bits-bee7106f0f00

Best regards,
-- 
James Clark <james.clark at linaro.org>



From james.clark at linaro.org  Mon Dec  1 08:41:04 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 01 Dec 2025 16:41:04 +0000
Subject: [PATCH 1/7] perf tools: Track all user changed config bits
In-Reply-To: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
References: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
Message-ID: <20251201-james-perf-config-bits-v1-1-22ecbbf8007c@linaro.org>

Currently we only track which bits were set by the user in attr->config.
But all configN fields should be treated equally as they can all have
default and user overridden values.

Track them all by making get_config_chgs() generic and calling it once
for each config value.

Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/util/evsel.c        |  6 ++-
 tools/perf/util/evsel_config.h |  6 ++-
 tools/perf/util/parse-events.c | 89 +++++++++++++++++-------------------------
 tools/perf/util/pmu.c          |  2 +-
 4 files changed, 47 insertions(+), 56 deletions(-)

diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index aee42666e882..40d68f346007 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1238,7 +1238,11 @@ static void evsel__apply_config_terms(struct evsel *evsel,
 		case EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE:
 			/* Already applied by auxtrace */
 			break;
-		case EVSEL__CONFIG_TERM_CFG_CHG:
+		case EVSEL__CONFIG_TERM_USR_CHG_CONFIG:
+		case EVSEL__CONFIG_TERM_USR_CHG_CONFIG1:
+		case EVSEL__CONFIG_TERM_USR_CHG_CONFIG2:
+		case EVSEL__CONFIG_TERM_USR_CHG_CONFIG3:
+		case EVSEL__CONFIG_TERM_USR_CHG_CONFIG4:
 			break;
 		case EVSEL__CONFIG_TERM_RATIO_TO_PREV:
 			rtp_buf = term->val.str;
diff --git a/tools/perf/util/evsel_config.h b/tools/perf/util/evsel_config.h
index bcd3a978f0c4..b38190dc5a40 100644
--- a/tools/perf/util/evsel_config.h
+++ b/tools/perf/util/evsel_config.h
@@ -27,7 +27,11 @@ enum evsel_term_type {
 	EVSEL__CONFIG_TERM_AUX_OUTPUT,
 	EVSEL__CONFIG_TERM_AUX_ACTION,
 	EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE,
-	EVSEL__CONFIG_TERM_CFG_CHG,
+	EVSEL__CONFIG_TERM_USR_CHG_CONFIG,
+	EVSEL__CONFIG_TERM_USR_CHG_CONFIG1,
+	EVSEL__CONFIG_TERM_USR_CHG_CONFIG2,
+	EVSEL__CONFIG_TERM_USR_CHG_CONFIG3,
+	EVSEL__CONFIG_TERM_USR_CHG_CONFIG4,
 	EVSEL__CONFIG_TERM_RATIO_TO_PREV,
 };
 
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 17c1c36a7bf9..f1cc6e96a371 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1235,63 +1235,46 @@ do {								\
 	return 0;
 }
 
+#define ADD_CONFIG_CHG(format_type, term_type, new_term)		\
+{									\
+	struct parse_events_term *term;					\
+	u64 bits = 0;							\
+	int type;							\
+									\
+	list_for_each_entry(term, &head_config->terms, list) {		\
+		if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER) {  \
+			type = perf_pmu__format_type(pmu, term->config);\
+			if (type != format_type)			\
+				continue;				\
+			bits |= perf_pmu__format_bits(pmu, term->config); \
+		} else if (term->type_term == term_type) {		\
+			bits = ~(u64)0;					\
+		}							\
+	}								\
+									\
+	if (bits)							\
+		ADD_CONFIG_TERM_VAL(new_term, cfg_chg, bits, false);	\
+	return 0;							\
+}
+
 /*
- * Add EVSEL__CONFIG_TERM_CFG_CHG where cfg_chg will have a bit set for
- * each bit of attr->config that the user has changed.
+ * Add EVSEL__CONFIG_TERM_USR_CFG_CONFIGn where cfg_chg will have a bit set for
+ * each bit of attr->configN that the user has changed.
  */
-static int get_config_chgs(struct perf_pmu *pmu, struct parse_events_terms *head_config,
+static int get_config_chgs(struct perf_pmu *pmu,
+			   struct parse_events_terms *head_config,
 			   struct list_head *head_terms)
 {
-	struct parse_events_term *term;
-	u64 bits = 0;
-	int type;
-
-	list_for_each_entry(term, &head_config->terms, list) {
-		switch (term->type_term) {
-		case PARSE_EVENTS__TERM_TYPE_USER:
-			type = perf_pmu__format_type(pmu, term->config);
-			if (type != PERF_PMU_FORMAT_VALUE_CONFIG)
-				continue;
-			bits |= perf_pmu__format_bits(pmu, term->config);
-			break;
-		case PARSE_EVENTS__TERM_TYPE_CONFIG:
-			bits = ~(u64)0;
-			break;
-		case PARSE_EVENTS__TERM_TYPE_CONFIG1:
-		case PARSE_EVENTS__TERM_TYPE_CONFIG2:
-		case PARSE_EVENTS__TERM_TYPE_CONFIG3:
-		case PARSE_EVENTS__TERM_TYPE_CONFIG4:
-		case PARSE_EVENTS__TERM_TYPE_LEGACY_HARDWARE_CONFIG:
-		case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE_CONFIG:
-		case PARSE_EVENTS__TERM_TYPE_NAME:
-		case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
-		case PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ:
-		case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
-		case PARSE_EVENTS__TERM_TYPE_TIME:
-		case PARSE_EVENTS__TERM_TYPE_CALLGRAPH:
-		case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
-		case PARSE_EVENTS__TERM_TYPE_NOINHERIT:
-		case PARSE_EVENTS__TERM_TYPE_INHERIT:
-		case PARSE_EVENTS__TERM_TYPE_MAX_STACK:
-		case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS:
-		case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE:
-		case PARSE_EVENTS__TERM_TYPE_OVERWRITE:
-		case PARSE_EVENTS__TERM_TYPE_DRV_CFG:
-		case PARSE_EVENTS__TERM_TYPE_PERCORE:
-		case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT:
-		case PARSE_EVENTS__TERM_TYPE_AUX_ACTION:
-		case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE:
-		case PARSE_EVENTS__TERM_TYPE_METRIC_ID:
-		case PARSE_EVENTS__TERM_TYPE_RAW:
-		case PARSE_EVENTS__TERM_TYPE_CPU:
-		case PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV:
-		default:
-			break;
-		}
-	}
-
-	if (bits)
-		ADD_CONFIG_TERM_VAL(CFG_CHG, cfg_chg, bits, false);
+	ADD_CONFIG_CHG(PERF_PMU_FORMAT_VALUE_CONFIG,
+		       PARSE_EVENTS__TERM_TYPE_CONFIG, USR_CHG_CONFIG);
+	ADD_CONFIG_CHG(PERF_PMU_FORMAT_VALUE_CONFIG1,
+		       PARSE_EVENTS__TERM_TYPE_CONFIG1, USR_CHG_CONFIG1);
+	ADD_CONFIG_CHG(PERF_PMU_FORMAT_VALUE_CONFIG2,
+		       PARSE_EVENTS__TERM_TYPE_CONFIG2, USR_CHG_CONFIG2);
+	ADD_CONFIG_CHG(PERF_PMU_FORMAT_VALUE_CONFIG3,
+		       PARSE_EVENTS__TERM_TYPE_CONFIG3, USR_CHG_CONFIG3);
+	ADD_CONFIG_CHG(PERF_PMU_FORMAT_VALUE_CONFIG4,
+		       PARSE_EVENTS__TERM_TYPE_CONFIG4, USR_CHG_CONFIG4);
 
 #undef ADD_CONFIG_TERM
 	return 0;
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 1b7c712d8f99..7a7db31be70d 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -1384,7 +1384,7 @@ void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
 				const char *config_name, u64 val)
 {
 	u64 user_bits = 0, bits;
-	struct evsel_config_term *term = evsel__get_config_term(evsel, CFG_CHG);
+	struct evsel_config_term *term = evsel__get_config_term(evsel, USR_CHG_CONFIG);
 
 	if (term)
 		user_bits = term->val.cfg_chg;

-- 
2.34.1



From james.clark at linaro.org  Mon Dec  1 08:41:05 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 01 Dec 2025 16:41:05 +0000
Subject: [PATCH 2/7] perf tools: apply evsel__set_config_if_unset() to all
 config fields
In-Reply-To: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
References: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
Message-ID: <20251201-james-perf-config-bits-v1-2-22ecbbf8007c@linaro.org>

Misleadingly, evsel__set_config_if_unset() only works with the config
field and not config1, config2, etc. This is fine at the moment because
all users of it happen to operate on bits that are in that config field.
Fix it before there are any new users of the function which operate on
bits in different config fields.

In theory it's also possible for a driver to move an existing bit to
another config field and this fixes that scenario too, although this
hasn't happened yet either.

Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/util/pmu.c | 60 +++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 44 insertions(+), 16 deletions(-)

diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 7a7db31be70d..c8968cddc0a9 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/list.h>
+#include <linux/bitfield.h>
 #include <linux/compiler.h>
 #include <linux/string.h>
 #include <linux/zalloc.h>
@@ -1371,6 +1372,18 @@ bool evsel__is_aux_event(const struct evsel *evsel)
 	return pmu && pmu->auxtrace;
 }
 
+static struct perf_pmu_format *
+pmu_find_format(const struct list_head *formats, const char *name)
+{
+	struct perf_pmu_format *format;
+
+	list_for_each_entry(format, formats, list)
+		if (!strcmp(format->name, name))
+			return format;
+
+	return NULL;
+}
+
 /*
  * Set @config_name to @val as long as the user hasn't already set or cleared it
  * by passing a config term on the command line.
@@ -1379,12 +1392,39 @@ bool evsel__is_aux_event(const struct evsel *evsel)
  * the bit pattern. It is shifted into position by this function, so to set
  * something to true, pass 1 for val rather than a pre shifted value.
  */
-#define field_prep(_mask, _val) (((_val) << (ffsll(_mask) - 1)) & (_mask))
 void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
 				const char *config_name, u64 val)
 {
 	u64 user_bits = 0, bits;
-	struct evsel_config_term *term = evsel__get_config_term(evsel, USR_CHG_CONFIG);
+	struct evsel_config_term *term;
+	struct perf_pmu_format *format = pmu_find_format(&pmu->format, config_name);
+	__u64 *vp;
+
+	switch (format->value) {
+	case PERF_PMU_FORMAT_VALUE_CONFIG:
+		term = evsel__get_config_term(evsel, USR_CHG_CONFIG);
+		vp = &evsel->core.attr.config;
+		break;
+	case PERF_PMU_FORMAT_VALUE_CONFIG1:
+		term = evsel__get_config_term(evsel, USR_CHG_CONFIG1);
+		vp = &evsel->core.attr.config1;
+		break;
+	case PERF_PMU_FORMAT_VALUE_CONFIG2:
+		term = evsel__get_config_term(evsel, USR_CHG_CONFIG2);
+		vp = &evsel->core.attr.config2;
+		break;
+	case PERF_PMU_FORMAT_VALUE_CONFIG3:
+		term = evsel__get_config_term(evsel, USR_CHG_CONFIG3);
+		vp = &evsel->core.attr.config3;
+		break;
+	case PERF_PMU_FORMAT_VALUE_CONFIG4:
+		term = evsel__get_config_term(evsel, USR_CHG_CONFIG4);
+		vp = &evsel->core.attr.config4;
+		break;
+	default:
+		pr_err("Unknown format value: %d\n", format->value);
+		return;
+	}
 
 	if (term)
 		user_bits = term->val.cfg_chg;
@@ -1396,20 +1436,8 @@ void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
 		return;
 
 	/* Otherwise replace it */
-	evsel->core.attr.config &= ~bits;
-	evsel->core.attr.config |= field_prep(bits, val);
-}
-
-static struct perf_pmu_format *
-pmu_find_format(const struct list_head *formats, const char *name)
-{
-	struct perf_pmu_format *format;
-
-	list_for_each_entry(format, formats, list)
-		if (!strcmp(format->name, name))
-			return format;
-
-	return NULL;
+	*vp &= ~bits;
+	*vp |= FIELD_PREP(bits, val);
 }
 
 __u64 perf_pmu__format_bits(struct perf_pmu *pmu, const char *name)

-- 
2.34.1



From james.clark at linaro.org  Mon Dec  1 08:41:06 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 01 Dec 2025 16:41:06 +0000
Subject: [PATCH 3/7] perf cs-etm: Make a helper to find the Coresight evsel
In-Reply-To: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
References: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
Message-ID: <20251201-james-perf-config-bits-v1-3-22ecbbf8007c@linaro.org>

This pattern occurs a few times and we'll add another one later, so add
a helper function for it.

Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/arch/arm/util/cs-etm.c | 50 +++++++++++++++++++++------------------
 1 file changed, 27 insertions(+), 23 deletions(-)

diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
index ea891d12f8f4..22c6272e8c36 100644
--- a/tools/perf/arch/arm/util/cs-etm.c
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -302,6 +302,19 @@ static int cs_etm_set_sink_attr(struct perf_pmu *pmu,
 	return 0;
 }
 
+static struct evsel *cs_etm_get_evsel(struct evlist *evlist,
+				      struct perf_pmu *cs_etm_pmu)
+{
+	struct evsel *evsel;
+
+	evlist__for_each_entry(evlist, evsel) {
+		if (evsel->core.attr.type == cs_etm_pmu->type)
+			return evsel;
+	}
+
+	return NULL;
+}
+
 static int cs_etm_recording_options(struct auxtrace_record *itr,
 				    struct evlist *evlist,
 				    struct record_opts *opts)
@@ -476,29 +489,21 @@ static int cs_etm_recording_options(struct auxtrace_record *itr,
 
 static u64 cs_etm_get_config(struct auxtrace_record *itr)
 {
-	u64 config = 0;
 	struct cs_etm_recording *ptr =
 			container_of(itr, struct cs_etm_recording, itr);
 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
 	struct evlist *evlist = ptr->evlist;
-	struct evsel *evsel;
+	struct evsel *evsel = cs_etm_get_evsel(evlist, cs_etm_pmu);
 
-	evlist__for_each_entry(evlist, evsel) {
-		if (evsel->core.attr.type == cs_etm_pmu->type) {
-			/*
-			 * Variable perf_event_attr::config is assigned to
-			 * ETMv3/PTM.  The bit fields have been made to match
-			 * the ETMv3.5 ETRMCR register specification.  See the
-			 * PMU_FORMAT_ATTR() declarations in
-			 * drivers/hwtracing/coresight/coresight-perf.c for
-			 * details.
-			 */
-			config = evsel->core.attr.config;
-			break;
-		}
-	}
-
-	return config;
+	/*
+	 * Variable perf_event_attr::config is assigned to
+	 * ETMv3/PTM.  The bit fields have been made to match
+	 * the ETMv3.5 ETRMCR register specification.  See the
+	 * PMU_FORMAT_ATTR() declarations in
+	 * drivers/hwtracing/coresight/coresight-perf.c for
+	 * details.
+	 */
+	return evsel ? evsel->core.attr.config : 0;
 }
 
 #ifndef BIT
@@ -832,12 +837,11 @@ static int cs_etm_snapshot_start(struct auxtrace_record *itr)
 {
 	struct cs_etm_recording *ptr =
 			container_of(itr, struct cs_etm_recording, itr);
-	struct evsel *evsel;
+	struct evsel *evsel = cs_etm_get_evsel(ptr->evlist, ptr->cs_etm_pmu);
+
+	if (evsel)
+		return evsel__disable(evsel);
 
-	evlist__for_each_entry(ptr->evlist, evsel) {
-		if (evsel->core.attr.type == ptr->cs_etm_pmu->type)
-			return evsel__disable(evsel);
-	}
 	return -EINVAL;
 }
 

-- 
2.34.1



From james.clark at linaro.org  Mon Dec  1 08:41:07 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 01 Dec 2025 16:41:07 +0000
Subject: [PATCH 4/7] perf cs-etm: Don't use hard coded config bits when
 setting up ETMCR
In-Reply-To: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
References: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
Message-ID: <20251201-james-perf-config-bits-v1-4-22ecbbf8007c@linaro.org>

Perf only looks at attr.config when determining what was programmed into
ETMCR. These bits could theoretically be in any of the config fields.
Add a generic helper to find the value of any named format field in any
config field and then use it to get the attributes relevant to ETMCR.

The kernel will also stop publishing the ETMCR register bits in a header
[1] so preempt that by defining them here.

[1]: https://lore.kernel.org/linux-arm-kernel/20251128-james-cs-syncfreq-v8-10-4d319764cc58 at linaro.org/
Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/arch/arm/util/cs-etm.c | 35 ++++++++++++++++++++++++++++++++++-
 tools/perf/util/evsel.h           |  2 ++
 tools/perf/util/pmu.c             | 33 +++++++++++++++++++++++++++++++++
 3 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
index 22c6272e8c36..414cafb21c98 100644
--- a/tools/perf/arch/arm/util/cs-etm.c
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -68,6 +68,12 @@ static const char * const metadata_ete_ro[] = {
 
 enum cs_etm_version { CS_NOT_PRESENT, CS_ETMV3, CS_ETMV4, CS_ETE };
 
+
+/* ETMv3 ETMCR register bits */
+#define ETMCR_CYC_ACC		BIT(12)
+#define ETMCR_TIMESTAMP_EN	BIT(28)
+#define ETMCR_RETURN_STACK	BIT(29)
+
 static bool cs_etm_is_ete(struct perf_pmu *cs_etm_pmu, struct perf_cpu cpu);
 static int cs_etm_get_ro(struct perf_pmu *pmu, struct perf_cpu cpu, const char *path, __u64 *val);
 static bool cs_etm_pmu_path_exists(struct perf_pmu *pmu, struct perf_cpu cpu, const char *path);
@@ -487,6 +493,33 @@ static int cs_etm_recording_options(struct auxtrace_record *itr,
 	return err;
 }
 
+static u64 cs_etm_guess_etmcr(struct auxtrace_record *itr)
+{
+	struct cs_etm_recording *ptr =
+		container_of(itr, struct cs_etm_recording, itr);
+	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
+	struct evsel *evsel = cs_etm_get_evsel(ptr->evlist, cs_etm_pmu);
+	u64 etmcr = 0;
+	u64 val;
+
+	if (!evsel)
+		return 0;
+
+	/*
+	 * Roughly guess what the kernel programmed into ETMCR based on
+	 * what options the event was opened with. This doesn't have to be
+	 * complete or 100% accurate, not all bits used by OpenCSD anyway.
+	 */
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "cycacc", &val) && val)
+		etmcr |= ETMCR_CYC_ACC;
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "timestamp", &val) && val)
+		etmcr |= ETMCR_TIMESTAMP_EN;
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "retstack", &val) && val)
+		etmcr |= ETMCR_RETURN_STACK;
+
+	return etmcr;
+}
+
 static u64 cs_etm_get_config(struct auxtrace_record *itr)
 {
 	struct cs_etm_recording *ptr =
@@ -746,7 +779,7 @@ static void cs_etm_get_metadata(struct perf_cpu cpu, u32 *offset,
 	case CS_ETMV3:
 		magic = __perf_cs_etmv3_magic;
 		/* Get configuration register */
-		info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr);
+		info->priv[*offset + CS_ETM_ETMCR] = cs_etm_guess_etmcr(itr);
 		/* traceID set to legacy value in case new perf running on old system */
 		info->priv[*offset + CS_ETM_ETMTRACEIDR] = cs_etm_get_legacy_trace_id(cpu);
 		/* Get read-only information from sysFS */
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 3ae4ac8f9a37..1c567cc70a82 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -574,6 +574,8 @@ void evsel__uniquify_counter(struct evsel *counter);
 	((((src) >> (pos)) & ((1ull << (size)) - 1)) << (63 - ((pos) + (size) - 1)))
 
 u64 evsel__bitfield_swap_branch_flags(u64 value);
+int evsel__get_config_val(struct perf_pmu *pmu, struct evsel *evsel,
+			  const char *config_name, u64 *val);
 void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
 				const char *config_name, u64 val);
 
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index c8968cddc0a9..5501b0230097 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -1384,6 +1384,39 @@ pmu_find_format(const struct list_head *formats, const char *name)
 	return NULL;
 }
 
+int evsel__get_config_val(struct perf_pmu *pmu, struct evsel *evsel,
+			  const char *config_name, u64 *val)
+{
+	struct perf_pmu_format *format = pmu_find_format(&pmu->format, config_name);
+	u64 bits = perf_pmu__format_bits(pmu, config_name);
+
+	if (!format || !bits) {
+		pr_err("Unknown/empty format name: %s\n", config_name);
+		return -EINVAL;
+	}
+
+	switch (format->value) {
+	case PERF_PMU_FORMAT_VALUE_CONFIG:
+		*val = FIELD_GET(bits, evsel->core.attr.config);
+		return 0;
+	case PERF_PMU_FORMAT_VALUE_CONFIG1:
+		*val = FIELD_GET(bits, evsel->core.attr.config1);
+		return 0;
+	case PERF_PMU_FORMAT_VALUE_CONFIG2:
+		*val = FIELD_GET(bits, evsel->core.attr.config2);
+		return 0;
+	case PERF_PMU_FORMAT_VALUE_CONFIG3:
+		*val = FIELD_GET(bits, evsel->core.attr.config3);
+		return 0;
+	case PERF_PMU_FORMAT_VALUE_CONFIG4:
+		*val = FIELD_GET(bits, evsel->core.attr.config4);
+		return 0;
+	default:
+		pr_err("Unknown format value: %d\n", format->value);
+		return -EINVAL;
+	}
+}
+
 /*
  * Set @config_name to @val as long as the user hasn't already set or cleared it
  * by passing a config term on the command line.

-- 
2.34.1



From james.clark at linaro.org  Mon Dec  1 08:41:08 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 01 Dec 2025 16:41:08 +0000
Subject: [PATCH 5/7] perf cs-etm: Don't use hard coded config bits when
 setting up TRCCONFIGR
In-Reply-To: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
References: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
Message-ID: <20251201-james-perf-config-bits-v1-5-22ecbbf8007c@linaro.org>

Perf only looks at attr.config when determining what was programmed into
TRCCONFIGR. These bits could theoretically be in any of the config
fields. Use the evsel__get_config_val() helper so it's agnostic to
which config field they are in.

The kernel will also stop publishing the TRCCONFIGR register bits in a
header [1] so preempt that by defining them here.

[1]: https://lore.kernel.org/linux-arm-kernel/20251128-james-cs-syncfreq-v8-10-4d319764cc58 at linaro.org/
Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/arch/arm/util/cs-etm.c | 79 +++++++++++++++++----------------------
 1 file changed, 34 insertions(+), 45 deletions(-)

diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
index 414cafb21c98..51ca8fa66ef8 100644
--- a/tools/perf/arch/arm/util/cs-etm.c
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -68,6 +68,14 @@ static const char * const metadata_ete_ro[] = {
 
 enum cs_etm_version { CS_NOT_PRESENT, CS_ETMV3, CS_ETMV4, CS_ETE };
 
+/* ETMv4 CONFIGR register bits */
+#define TRCCONFIGR_BB		BIT(3)
+#define TRCCONFIGR_CCI		BIT(4)
+#define TRCCONFIGR_CID		BIT(6)
+#define TRCCONFIGR_VMID		BIT(7)
+#define TRCCONFIGR_TS		BIT(11)
+#define TRCCONFIGR_RS		BIT(12)
+#define TRCCONFIGR_VMIDOPT	BIT(15)
 
 /* ETMv3 ETMCR register bits */
 #define ETMCR_CYC_ACC		BIT(12)
@@ -520,56 +528,37 @@ static u64 cs_etm_guess_etmcr(struct auxtrace_record *itr)
 	return etmcr;
 }
 
-static u64 cs_etm_get_config(struct auxtrace_record *itr)
+static u64 cs_etmv4_guess_trcconfigr(struct auxtrace_record *itr)
 {
+	u64 trcconfigr = 0;
 	struct cs_etm_recording *ptr =
-			container_of(itr, struct cs_etm_recording, itr);
+		container_of(itr, struct cs_etm_recording, itr);
 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
-	struct evlist *evlist = ptr->evlist;
-	struct evsel *evsel = cs_etm_get_evsel(evlist, cs_etm_pmu);
-
-	/*
-	 * Variable perf_event_attr::config is assigned to
-	 * ETMv3/PTM.  The bit fields have been made to match
-	 * the ETMv3.5 ETRMCR register specification.  See the
-	 * PMU_FORMAT_ATTR() declarations in
-	 * drivers/hwtracing/coresight/coresight-perf.c for
-	 * details.
-	 */
-	return evsel ? evsel->core.attr.config : 0;
-}
-
-#ifndef BIT
-#define BIT(N) (1UL << (N))
-#endif
+	struct evsel *evsel = cs_etm_get_evsel(ptr->evlist, cs_etm_pmu);
+	u64 val;
 
-static u64 cs_etmv4_get_config(struct auxtrace_record *itr)
-{
-	u64 config = 0;
-	u64 config_opts = 0;
+	if (!evsel)
+		return 0;
 
 	/*
-	 * The perf event variable config bits represent both
-	 * the command line options and register programming
-	 * bits in ETMv3/PTM. For ETMv4 we must remap options
-	 * to real bits
+	 * Roughly guess what the kernel programmed into TRCCONFIGR based on
+	 * what options the event was opened with. This doesn't have to be
+	 * complete or 100% accurate, not all bits used by OpenCSD anyway.
 	 */
-	config_opts = cs_etm_get_config(itr);
-	if (config_opts & BIT(ETM_OPT_CYCACC))
-		config |= BIT(ETM4_CFG_BIT_CYCACC);
-	if (config_opts & BIT(ETM_OPT_CTXTID))
-		config |= BIT(ETM4_CFG_BIT_CTXTID);
-	if (config_opts & BIT(ETM_OPT_TS))
-		config |= BIT(ETM4_CFG_BIT_TS);
-	if (config_opts & BIT(ETM_OPT_RETSTK))
-		config |= BIT(ETM4_CFG_BIT_RETSTK);
-	if (config_opts & BIT(ETM_OPT_CTXTID2))
-		config |= BIT(ETM4_CFG_BIT_VMID) |
-			  BIT(ETM4_CFG_BIT_VMID_OPT);
-	if (config_opts & BIT(ETM_OPT_BRANCH_BROADCAST))
-		config |= BIT(ETM4_CFG_BIT_BB);
-
-	return config;
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "cycacc", &val) && val)
+		trcconfigr |= TRCCONFIGR_CCI;
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "contextid1", &val) && val)
+		trcconfigr |= TRCCONFIGR_CID;
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "timestamp", &val) && val)
+		trcconfigr |= TRCCONFIGR_TS;
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "retstack", &val) && val)
+		trcconfigr |= TRCCONFIGR_RS;
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "contextid2", &val) && val)
+		trcconfigr |= TRCCONFIGR_VMID | TRCCONFIGR_VMIDOPT;
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "branch_broadcast", &val) && val)
+		trcconfigr |= TRCCONFIGR_BB;
+
+	return trcconfigr;
 }
 
 static size_t
@@ -691,7 +680,7 @@ static void cs_etm_save_etmv4_header(__u64 data[], struct auxtrace_record *itr,
 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
 
 	/* Get trace configuration register */
-	data[CS_ETMV4_TRCCONFIGR] = cs_etmv4_get_config(itr);
+	data[CS_ETMV4_TRCCONFIGR] = cs_etmv4_guess_trcconfigr(itr);
 	/* traceID set to legacy version, in case new perf running on older system */
 	data[CS_ETMV4_TRCTRACEIDR] = cs_etm_get_legacy_trace_id(cpu);
 
@@ -723,7 +712,7 @@ static void cs_etm_save_ete_header(__u64 data[], struct auxtrace_record *itr, st
 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
 
 	/* Get trace configuration register */
-	data[CS_ETE_TRCCONFIGR] = cs_etmv4_get_config(itr);
+	data[CS_ETE_TRCCONFIGR] = cs_etmv4_guess_trcconfigr(itr);
 	/* traceID set to legacy version, in case new perf running on older system */
 	data[CS_ETE_TRCTRACEIDR] = cs_etm_get_legacy_trace_id(cpu);
 

-- 
2.34.1



From james.clark at linaro.org  Mon Dec  1 08:41:09 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 01 Dec 2025 16:41:09 +0000
Subject: [PATCH 6/7] perf cs-etm: Don't hard code config attribute when
 configuring the event
In-Reply-To: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
References: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
Message-ID: <20251201-james-perf-config-bits-v1-6-22ecbbf8007c@linaro.org>

These instances of hard coded config attributes are used for configuring
and validating the event options. Use the config attribute that's
published by the driver by replacing the open coded operations with
evsel__get_config_val() and evsel__set_config_if_unset().

Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/arch/arm/util/cs-etm.c | 66 ++++++++++++++++++++++-----------------
 1 file changed, 37 insertions(+), 29 deletions(-)

diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
index 51ca8fa66ef8..52e304584095 100644
--- a/tools/perf/arch/arm/util/cs-etm.c
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -103,13 +103,20 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
 				      struct perf_cpu cpu)
 {
 	int err;
-	__u64 val;
-	u64 contextid = evsel->core.attr.config &
-		(perf_pmu__format_bits(cs_etm_pmu, "contextid") |
-		 perf_pmu__format_bits(cs_etm_pmu, "contextid1") |
-		 perf_pmu__format_bits(cs_etm_pmu, "contextid2"));
+	u64 ctxt, ctxt1, ctxt2;
+	__u64 trcidr2;
 
-	if (!contextid)
+	err = evsel__get_config_val(cs_etm_pmu, evsel, "contextid", &ctxt);
+	if (err)
+		return err;
+	err = evsel__get_config_val(cs_etm_pmu, evsel, "contextid1", &ctxt1);
+	if (err)
+		return err;
+	err = evsel__get_config_val(cs_etm_pmu, evsel, "contextid2", &ctxt2);
+	if (err)
+		return err;
+
+	if (!ctxt && !ctxt1 && !ctxt2)
 		return 0;
 
 	/* Not supported in etmv3 */
@@ -120,12 +127,11 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
 	}
 
 	/* Get a handle on TRCIDR2 */
-	err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2], &val);
+	err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2], &trcidr2);
 	if (err)
 		return err;
 
-	if (contextid &
-	    perf_pmu__format_bits(cs_etm_pmu, "contextid1")) {
+	if (ctxt1) {
 		/*
 		 * TRCIDR2.CIDSIZE, bit [9-5], indicates whether contextID
 		 * tracing is supported:
@@ -133,15 +139,14 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
 		 *  0b00100 Maximum of 32-bit Context ID size.
 		 *  All other values are reserved.
 		 */
-		if (BMVAL(val, 5, 9) != 0x4) {
+		if (BMVAL(trcidr2, 5, 9) != 0x4) {
 			pr_err("%s: CONTEXTIDR_EL1 isn't supported, disable with %s/contextid1=0/\n",
 			       CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME);
 			return -EINVAL;
 		}
 	}
 
-	if (contextid &
-	    perf_pmu__format_bits(cs_etm_pmu, "contextid2")) {
+	if (ctxt2) {
 		/*
 		 * TRCIDR2.VMIDOPT[30:29] != 0 and
 		 * TRCIDR2.VMIDSIZE[14:10] == 0b00100 (32bit virtual contextid)
@@ -149,7 +154,7 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
 		 * virtual context id is < 32bit.
 		 * Any value of VMIDSIZE >= 4 (i.e, > 32bit) is fine for us.
 		 */
-		if (!BMVAL(val, 29, 30) || BMVAL(val, 10, 14) < 4) {
+		if (!BMVAL(trcidr2, 29, 30) || BMVAL(trcidr2, 10, 14) < 4) {
 			pr_err("%s: CONTEXTIDR_EL2 isn't supported, disable with %s/contextid2=0/\n",
 			       CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME);
 			return -EINVAL;
@@ -163,10 +168,14 @@ static int cs_etm_validate_timestamp(struct perf_pmu *cs_etm_pmu, struct evsel *
 				     struct perf_cpu cpu)
 {
 	int err;
-	__u64 val;
+	u64 val;
+	__u64 trcidr0;
 
-	if (!(evsel->core.attr.config &
-	      perf_pmu__format_bits(cs_etm_pmu, "timestamp")))
+	err = evsel__get_config_val(cs_etm_pmu, evsel, "timestamp", &val);
+	if (err)
+		return err;
+
+	if (!val)
 		return 0;
 
 	if (cs_etm_get_version(cs_etm_pmu, cpu) == CS_ETMV3) {
@@ -176,7 +185,7 @@ static int cs_etm_validate_timestamp(struct perf_pmu *cs_etm_pmu, struct evsel *
 	}
 
 	/* Get a handle on TRCIRD0 */
-	err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0], &val);
+	err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0], &trcidr0);
 	if (err)
 		return err;
 
@@ -187,10 +196,9 @@ static int cs_etm_validate_timestamp(struct perf_pmu *cs_etm_pmu, struct evsel *
 	 *  0b00110 Implementation supports a maximum timestamp of 48bits.
 	 *  0b01000 Implementation supports a maximum timestamp of 64bits.
 	 */
-	val &= GENMASK(28, 24);
-	if (!val) {
+	trcidr0 &= GENMASK(28, 24);
+	if (!trcidr0)
 		return -EINVAL;
-	}
 
 	return 0;
 }
@@ -273,16 +281,20 @@ static int cs_etm_parse_snapshot_options(struct auxtrace_record *itr,
 	return 0;
 }
 
+/*
+ * The sink name format "@sink_name" is used, lookup the sink by name to convert
+ * to "sinkid=sink_hash" format.
+ *
+ * If the user has already manually provided a hash then "sinkid" isn't
+ * overwritten. If neither are provided then the driver will pick the best sink.
+ */
 static int cs_etm_set_sink_attr(struct perf_pmu *pmu,
 				struct evsel *evsel)
 {
 	char msg[BUFSIZ], path[PATH_MAX], *sink;
 	struct evsel_config_term *term;
-	int ret = -EINVAL;
 	u32 hash;
-
-	if (evsel->core.attr.config2 & GENMASK(31, 0))
-		return 0;
+	int ret;
 
 	list_for_each_entry(term, &evsel->config_terms, list) {
 		if (term->type != EVSEL__CONFIG_TERM_DRV_CFG)
@@ -305,14 +317,10 @@ static int cs_etm_set_sink_attr(struct perf_pmu *pmu,
 			return ret;
 		}
 
-		evsel->core.attr.config2 |= hash;
+		evsel__set_config_if_unset(pmu, evsel, "sinkid", hash);
 		return 0;
 	}
 
-	/*
-	 * No sink was provided on the command line - allow the CoreSight
-	 * system to look for a default
-	 */
 	return 0;
 }
 

-- 
2.34.1



From james.clark at linaro.org  Mon Dec  1 08:41:10 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 01 Dec 2025 16:41:10 +0000
Subject: [PATCH 7/7] perf arm-spe: Don't hard code config attribute
In-Reply-To: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
References: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
Message-ID: <20251201-james-perf-config-bits-v1-7-22ecbbf8007c@linaro.org>

Use the config attribute that's published by the driver instead of
hard coding "attr.config".

Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/arch/arm64/util/arm-spe.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c
index d5ec1408d0ae..6c3dc97fde30 100644
--- a/tools/perf/arch/arm64/util/arm-spe.c
+++ b/tools/perf/arch/arm64/util/arm-spe.c
@@ -256,7 +256,7 @@ static __u64 arm_spe_pmu__sample_period(const struct perf_pmu *arm_spe_pmu)
 
 static void arm_spe_setup_evsel(struct evsel *evsel, struct perf_cpu_map *cpus)
 {
-	u64 bit;
+	u64 pa_enable_bit;
 
 	evsel->core.attr.freq = 0;
 	evsel->core.attr.sample_period = arm_spe_pmu__sample_period(evsel->pmu);
@@ -288,9 +288,10 @@ static void arm_spe_setup_evsel(struct evsel *evsel, struct perf_cpu_map *cpus)
 	 * inform that the resulting output's SPE samples contain physical addresses
 	 * where applicable.
 	 */
-	bit = perf_pmu__format_bits(evsel->pmu, "pa_enable");
-	if (evsel->core.attr.config & bit)
-		evsel__set_sample_bit(evsel, PHYS_ADDR);
+
+	if (!evsel__get_config_val(evsel->pmu, evsel, "pa_enable", &pa_enable_bit))
+		if (pa_enable_bit)
+			evsel__set_sample_bit(evsel, PHYS_ADDR);
 }
 
 static int arm_spe_setup_aux_buffer(struct record_opts *opts)
@@ -397,6 +398,7 @@ static int arm_spe_recording_options(struct auxtrace_record *itr,
 	struct perf_cpu_map *cpus = evlist->core.user_requested_cpus;
 	bool discard = false;
 	int err;
+	u64 discard_bit;
 
 	sper->evlist = evlist;
 
@@ -425,9 +427,8 @@ static int arm_spe_recording_options(struct auxtrace_record *itr,
 	evlist__for_each_entry_safe(evlist, tmp, evsel) {
 		if (evsel__is_aux_event(evsel)) {
 			arm_spe_setup_evsel(evsel, cpus);
-			if (evsel->core.attr.config &
-			    perf_pmu__format_bits(evsel->pmu, "discard"))
-				discard = true;
+			if (!evsel__get_config_val(evsel->pmu, evsel, "discard", &discard_bit))
+				discard = !!discard_bit;
 		}
 	}
 

-- 
2.34.1



From Frank.li at nxp.com  Mon Dec  1 08:42:00 2025
From: Frank.li at nxp.com (Frank Li)
Date: Mon, 1 Dec 2025 11:42:00 -0500
Subject: [PATCH 4/4] dts: s32g: Add GPR syscon region
In-Reply-To: <c8302f53fcbb5cb5afe42cdb15aba7e2e6ed7338.1764592300.git.dan.carpenter@linaro.org>
References: <cover.1764592300.git.dan.carpenter@linaro.org>
 <c8302f53fcbb5cb5afe42cdb15aba7e2e6ed7338.1764592300.git.dan.carpenter@linaro.org>
Message-ID: <aS3FWLWQ1g4YQjFi@lizhi-Precision-Tower-5810>

On Mon, Dec 01, 2025 at 04:08:33PM +0300, Dan Carpenter wrote:
> Add the GPR syscon region for the s32 chipset.
>
> Signed-off-by: Dan Carpenter <dan.carpenter at linaro.org>
> ---
>  arch/arm64/boot/dts/freescale/s32g2.dtsi | 8 ++++++++
>  arch/arm64/boot/dts/freescale/s32g3.dtsi | 8 ++++++++
>  2 files changed, 16 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/freescale/s32g2.dtsi b/arch/arm64/boot/dts/freescale/s32g2.dtsi
> index 51d00dac12de..3c9472f6c174 100644
> --- a/arch/arm64/boot/dts/freescale/s32g2.dtsi
> +++ b/arch/arm64/boot/dts/freescale/s32g2.dtsi
> @@ -325,6 +325,13 @@ usdhc0-200mhz-grp4 {
>  			};
>  		};
>
> +		gpr: syscon at 4007c000 {
> +			compatible = "nxp,s32-gpr", "syscon";
> +			reg = <0x4007c000 0x3000>;
> +			#address-cells = <1>;
> +			#size-cells = <1>;
> +		};
> +

Please cc whole thread to imx at lists.linux.dev.

I think it is not good method by using syscon here.

Suppose using standard phy interface or mux controller interface.

Frank

>  		ocotp: nvmem at 400a4000 {
>  			compatible = "nxp,s32g2-ocotp";
>  			reg = <0x400a4000 0x400>;
> @@ -731,6 +738,7 @@ gmac0: ethernet at 4033c000 {
>  			compatible = "nxp,s32g2-dwmac";
>  			reg = <0x4033c000 0x2000>, /* gmac IP */
>  			      <0x4007c004 0x4>;    /* GMAC_0_CTRL_STS */
> +			phy-sel = <&gpr 0x4>;
>  			interrupt-parent = <&gic>;
>  			interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
>  			interrupt-names = "macirq";
> diff --git a/arch/arm64/boot/dts/freescale/s32g3.dtsi b/arch/arm64/boot/dts/freescale/s32g3.dtsi
> index eff7673e7f34..0ceca3caf133 100644
> --- a/arch/arm64/boot/dts/freescale/s32g3.dtsi
> +++ b/arch/arm64/boot/dts/freescale/s32g3.dtsi
> @@ -383,6 +383,13 @@ usdhc0-200mhz-grp4 {
>  			};
>  		};
>
> +		gpr: syscon at 4007c000 {
> +			compatible = "nxp,s32-gpr", "syscon";
> +			reg = <0x4007c000 0x3000>;
> +			#address-cells = <1>;
> +			#size-cells = <1>;
> +		};
> +
>  		ocotp: nvmem at 400a4000 {
>  			compatible = "nxp,s32g3-ocotp", "nxp,s32g2-ocotp";
>  			reg = <0x400a4000 0x400>;
> @@ -808,6 +815,7 @@ gmac0: ethernet at 4033c000 {
>  			compatible = "nxp,s32g2-dwmac";
>  			reg = <0x4033c000 0x2000>, /* gmac IP */
>  			      <0x4007c004 0x4>;    /* GMAC_0_CTRL_STS */
> +			phy-sel = <&gpr 0x4>;
>  			interrupt-parent = <&gic>;
>  			interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
>  			interrupt-names = "macirq";
> --
> 2.51.0
>


From macro at orcam.me.uk  Mon Dec  1 08:42:42 2025
From: macro at orcam.me.uk (Maciej W. Rozycki)
Date: Mon, 1 Dec 2025 16:42:42 +0000 (GMT)
Subject: [PATCH v9 4/4] PCI: dwc: Support ECAM mechanism by enabling iATU
 'CFG Shift Feature'
In-Reply-To: <syg7vpbt3w53s24hgl7b6w64odmif5bq557lwlvzlbvgkukwcn@66jtzzc3vtiu>
References: <20250909-controller-dwc-ecam-v9-0-7d5b651840dd@kernel.org> <20250909-controller-dwc-ecam-v9-4-7d5b651840dd@kernel.org> <alpine.DEB.2.21.2511280256260.36486@angie.orcam.me.uk> <c7aea2b3-6984-40f5-8234-14d265dabefc@oss.qualcomm.com>
 <alpine.DEB.2.21.2511280755440.36486@angie.orcam.me.uk> <cabf4c20-095b-4579-adc1-146a566b19b9@oss.qualcomm.com> <alpine.DEB.2.21.2511281714030.36486@angie.orcam.me.uk> <a4c6d47f-28b5-40d3-bc82-10aeb14f8e78@oss.qualcomm.com> <alpine.DEB.2.21.2511290428340.36486@angie.orcam.me.uk>
 <h7pgm3lqolm53sb4wrcpcurk4ghz4tulqnr7vgd7rzxy4hscue@jcn5tepevlwl> <syg7vpbt3w53s24hgl7b6w64odmif5bq557lwlvzlbvgkukwcn@66jtzzc3vtiu>
Message-ID: <alpine.DEB.2.21.2512011617250.49654@angie.orcam.me.uk>

On Mon, 1 Dec 2025, Manivannan Sadhasivam wrote:

> > > So it's definitely nothing specific to the parport driver, but rather a 
> > > general issue with PCI/e port I/O not working anymore.  I do hope these 
> > > observations will let you address the issue now.  You might be able to 
> > > reproduce it with hardware you have available even.
> > > 
> > 
> > Yes, looks like the I/O port access is not working with the CFG Shift feature.
> > The spec says that both I/O and MEM TLPs should be handled by this feature, so
> > we are currently unsure why MEM works, but not I/O.

 As I say, last time I checked (for another reason) documentation was not 
available to the general public, so I can't help with that.

> > The issue you reported with parport_pc driver is that the driver gets probed,
> > but it fails to detect the parallel ports on the device. More precisely, it
> > fails due to the parport_SPP_supported() check in drivers/parport/parport_pc.c.
> > This function performs some read/write checks to make sure that the port exists,
> > but most likely the read value doesn't match the written one. And since there is
> > no log printed in this function, it just failed silently.

 Whatever the exact transaction conditions are port I/O TLPs seem not to 
make it through to the requested target device anymore.

 FWIW the defxx driver issues a command to the device's command register 
and wants to see a successful completion status in the status register 
before retrieving the MAC address via the data register.  So it's not a 
simple case of poking at a register and reading it back, but the end 
result is the same: the device cannot be talked to.

> > We will check why I/O access fails with ECAM mode and revert back asap. Since
> > the merge window is now open, it becomes difficult to revert the CFG shift
> > feature cleanly. The timing of the report also made it difficult to fix the
> > issue in v6.18. Hopefully, we can backport the fix once we identify the culprit.

 No worries, I've been around for long enough (short of 30 years) to know 
the process.

 FWIW the original change would've best been reverted for 6.18 as a fatal 
regression, however port I/O is uncommon enough nowadays we can defer any 
final decision to 6.19 I suppose.  I'm glad I've tripped over this in the 
first place as I'm not eager to upgrade all my lab devices all the time, 
and it was owing to another issue only that I chose this moment to move 
forward, not so long after the original commit.

> Can you try the attached patch? It is a reworked version of Krishna's patch. I
> just moved things around to check potential override issue.

 No change in behaviour, sorry.  I suppose it's this range of host address 
decoding:

fu740-pcie e00000000.pcie:       IO 0x0060080000..0x006008ffff -> 0x0060080000

aka:

pci_bus 0000:00: root bus resource [io  0x0000-0xffff] (bus address [0x60080000-0x6008ffff])

that you're after.  Are you sure your code discovers it correctly?  As I 
say I can only see IORESOURCE_MEM references and no IORESOURCE_IO ones as 
would be appropriate for the root bus resource quoted.

  Maciej


From linux at armlinux.org.uk  Mon Dec  1 08:44:15 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 1 Dec 2025 16:44:15 +0000
Subject: [PATCH RFC net-next 00/15] net: stmmac: rk: cleanups galore
In-Reply-To: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
References: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
Message-ID: <aS3F36UAkeLfFeHx@shell.armlinux.org.uk>

On Mon, Dec 01, 2025 at 02:49:56PM +0000, Russell King (Oracle) wrote:
> This is work in progress, cleaning up the excessively large Rockchip
> glue driver somewhat. This series as it currently stands removes
> approximately 200 lines from this file, while adding slightly to its
> flexibility.
> 
> A brief overview of the changes:
> 
> - similar to previous commits, it seems the RGMII clock field follows
>   a common pattern irrespective of the SoC.
> - update rk3328 to use the ->id mechanism rather than guessing from
>   the PHY interface mode and whether the PHY is integrated.
> - switch to wm16 based masking, providing the lower-16 bits of the
>   mask to indicate appropriate fields, and use this to construct the
>   values to write to the registers.
> - convert px30 to these methods.
> - since many set_to_rmii() methods are now empty, add flags to indicate
>   whether RMII / RGMII are supported.
> - clear RGMII where the specific SoC's GMAC instance doesn't support
>   this.
> 
> I've spent quite a while mulling over how to deal with these "wm16"
> registers, none of the kernel bitfield macros (not even the
> hw_bitfield.h macros) allow for what I present here, because the
> masks are not constant.
> 
> One of the interesting things is that this appears to deal with RGMII
> delays at the MAC end of the link, but there's no way to tell phylib
> that's the case. I've not looked deeply into what is going on there,
> but it is surprising that the driver insists that the delays (in
> register values?) are provided, but then ignores them depending on the
> exact RGMII mode selected.
> 
> One outstanding issue with these patches: RK3528_GMAC0_CLK_RMII_DIV2
> remains, although I deleted its definition, so there's build errors
> in this series. Before I do anything about that, I would like to hear
> from the Rockchip guys whether it is necessary for rk3528_set_to_rmii()
> to set the clock rate, given that rk_set_clk_tx_rate() will do this
> when the link comes up. Does it matter whether it was set to 2.5MHz
> (/ 20) or 25MHz (/ 2) when we switch to RMII mode?

Another issue has come up while looking at this driver -
gmac_clk_enable() is buggy.

If clk_bulk_prepare_enable() succeeds, but then the following
clk_prepare_enable() fails, we simply return its error code, failing
gmac_clk_enable(, true), leaving the bulk clocks prepared and enabled.

Calling this with "false" to disable clocks won't - because we never
get as far as setting bsp_priv->clk_enabled, and even if we did, we'd
disable and unprepare clk_phy which failed to prepare/enable.

Again, I don't like this foo_enable() / foo_power_on() pattern with
a true/false argument - when false, the function is not enabling
nor "on"-ing, but disabling or "off"-ing. So, gmac_clk_enable() is
going to get split up and renamed.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From linux at armlinux.org.uk  Mon Dec  1 08:48:12 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 1 Dec 2025 16:48:12 +0000
Subject: [PATCH 1/4] net: stmmac: s32: use the syscon interface
 PHY_INTF_SEL_RGMII
In-Reply-To: <6275e666a7ef78bd4c758d3f7f6fb6f30407393e.1764592300.git.dan.carpenter@linaro.org>
References: <cover.1764592300.git.dan.carpenter@linaro.org>
 <6275e666a7ef78bd4c758d3f7f6fb6f30407393e.1764592300.git.dan.carpenter@linaro.org>
Message-ID: <aS3GzJljbfp2xJmW@shell.armlinux.org.uk>

On Mon, Dec 01, 2025 at 04:08:20PM +0300, Dan Carpenter wrote:
> On the s32 chipset the GMAC_0_CTRL_STS register is in GPR region.
> Originally, accessing this register was done in a sort of ad-hoc way,
> but we want to use the syscon interface to do it.
> 
> This is a little bit uglier because we to maintain backwards compatibility
> to the old device trees so we have to support both ways to access this
> register.
> 
> Signed-off-by: Dan Carpenter <dan.carpenter at linaro.org>
> ---
>  .../net/ethernet/stmicro/stmmac/dwmac-s32.c   | 23 +++++++++++++++----
>  1 file changed, 18 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c
> index 5a485ee98fa7..20de761b7d28 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c
> @@ -11,12 +11,14 @@
>  #include <linux/device.h>
>  #include <linux/ethtool.h>
>  #include <linux/io.h>
> +#include <linux/mfd/syscon.h>
>  #include <linux/module.h>
>  #include <linux/of_mdio.h>
>  #include <linux/of_address.h>
>  #include <linux/phy.h>
>  #include <linux/phylink.h>
>  #include <linux/platform_device.h>
> +#include <linux/regmap.h>
>  #include <linux/stmmac.h>
>  
>  #include "stmmac_platform.h"
> @@ -32,6 +34,8 @@
>  struct s32_priv_data {
>  	void __iomem *ioaddr;
>  	void __iomem *ctrl_sts;
> +	struct regmap *sts_regmap;
> +	unsigned int sts_offset;
>  	struct device *dev;
>  	phy_interface_t *intf_mode;
>  	struct clk *tx_clk;
> @@ -40,7 +44,10 @@ struct s32_priv_data {
>  
>  static int s32_gmac_write_phy_intf_select(struct s32_priv_data *gmac)
>  {
> -	writel(S32_PHY_INTF_SEL_RGMII, gmac->ctrl_sts);
> +	if (gmac->ctrl_sts)
> +		writel(S32_PHY_INTF_SEL_RGMII, gmac->ctrl_sts);
> +	else
> +		regmap_write(gmac->sts_regmap, gmac->sts_offset, PHY_INTF_SEL_RGMII);

Sorry, but even if that regmap_write() is targetting the exact same
register, these are not identical.

S32_PHY_INTF_SEL_RGMII, which is a S32-specific value, takes the value 2.
PHY_INTF_SEL_RGMII is the dwmac specific value, and takes the value 1.

If this targets the same register, then by writing PHY_INTF_SEL_RGMII,
you are in effect writing the equivalent of S32_PHY_INTF_SEL_SGMII to
it. This seems like a bug.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From Frank.li at nxp.com  Mon Dec  1 08:52:38 2025
From: Frank.li at nxp.com (Frank Li)
Date: Mon, 1 Dec 2025 11:52:38 -0500
Subject: [PATCH v6 1/4] dt-bindings: backlight: Add max25014 support
In-Reply-To: <20251201-max25014-v6-1-88e3ac8112ff@gocontroll.com>
References: <20251201-max25014-v6-0-88e3ac8112ff@gocontroll.com>
 <20251201-max25014-v6-1-88e3ac8112ff@gocontroll.com>
Message-ID: <aS3H1qzSMKHamqpP@lizhi-Precision-Tower-5810>

On Mon, Dec 01, 2025 at 12:53:20PM +0100, Maud Spierings via B4 Relay wrote:
> From: Maud Spierings <maudspierings at gocontroll.com>
>
> The Maxim MAX25014 is a 4-channel automotive grade backlight driver IC
> with integrated boost controller.
>
> Signed-off-by: Maud Spierings <maudspierings at gocontroll.com>
>
> ---
>
> In the current implementation the control registers for channel 1,
> control all channels. So only one led subnode with led-sources is
> supported right now. If at some point the driver functionality is
> expanded the bindings can be easily extended with it.
> ---
>  .../bindings/leds/backlight/maxim,max25014.yaml    | 107 +++++++++++++++++++++
>  MAINTAINERS                                        |   5 +
>  2 files changed, 112 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml b/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
> new file mode 100644
> index 000000000000..e83723224b07
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
> @@ -0,0 +1,107 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/leds/backlight/maxim,max25014.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Maxim max25014 backlight controller
> +
> +maintainers:
> +  - Maud Spierings <maudspierings at gocontroll.com>
> +
> +properties:
> +  compatible:
> +    enum:
> +      - maxim,max25014
> +
> +  reg:
> +    maxItems: 1
> +
> +  "#address-cells":
> +    const: 1
> +
> +  "#size-cells":
> +    const: 0
> +
> +  enable-gpios:
> +    maxItems: 1
> +
> +  interrupts:
> +    maxItems: 1
> +
> +  power-supply:
> +    description: Regulator which controls the boost converter input rail.
> +
> +  pwms:
> +    maxItems: 1
> +
> +  maxim,iset:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    maximum: 15
> +    default: 11
> +    description:
> +      Value of the ISET field in the ISET register. This controls the current
> +      scale of the outputs, a higher number means more current.
> +
> +  led at 0:

define whole binding, allow 0-3. binding is not related with driver's
implement.

it'd better put unders leds.


> +    type: object
> +    description: Properties for a string of connected LEDs.
> +    $ref: common.yaml#
> +
> +    properties:
> +      reg:
> +        const: 0
> +
> +      led-sources:
> +        allOf:
> +          - minItems: 1
> +            maxItems: 4
> +            items:
> +              minimum: 0
> +              maximum: 3
> +            default: [0, 1, 2, 3]
> +
> +      default-brightness:
> +        minimum: 0
> +        maximum: 100
> +        default: 50
> +
> +    required:
> +      - reg
> +
> +    additionalProperties: false

unevaluatedProperties: false because ref to common.yaml

Frank

> +
> +required:
> +  - compatible
> +  - reg
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/gpio/gpio.h>
> +    #include <dt-bindings/interrupt-controller/irq.h>
> +
> +    i2c {
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +
> +        backlight at 6f {
> +            compatible = "maxim,max25014";
> +            reg = <0x6f>;
> +            #address-cells = <1>;
> +            #size-cells = <0>;
> +            enable-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
> +            interrupt-parent = <&gpio1>;
> +            interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
> +            power-supply = <&reg_backlight>;
> +            pwms = <&pwm1>;
> +            maxim,iset = <7>;
> +
> +            led at 0 {
> +                reg = <0>;
> +                led-sources = <0 1 2 3>;
> +                default-brightness = <50>;
> +            };
> +        };
> +    };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 58c7e3f678d8..606ce086f758 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -15261,6 +15261,11 @@ F:	Documentation/userspace-api/media/drivers/max2175.rst
>  F:	drivers/media/i2c/max2175*
>  F:	include/uapi/linux/max2175.h
>
> +MAX25014 BACKLIGHT DRIVER
> +M:	Maud Spierings <maudspierings at gocontroll.com>
> +S:	Maintained
> +F:	Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
> +
>  MAX31335 RTC DRIVER
>  M:	Antoniu Miclaus <antoniu.miclaus at analog.com>
>  L:	linux-rtc at vger.kernel.org
>
> --
> 2.52.0
>
>


From Frank.li at nxp.com  Mon Dec  1 08:54:36 2025
From: Frank.li at nxp.com (Frank Li)
Date: Mon, 1 Dec 2025 11:54:36 -0500
Subject: [PATCH 1/2] arm64: dts: imx93-14x14-evk: Add bt-sco sound card
 support
In-Reply-To: <20251201065844.3823323-2-chancel.liu@nxp.com>
References: <20251201065844.3823323-1-chancel.liu@nxp.com>
 <20251201065844.3823323-2-chancel.liu@nxp.com>
Message-ID: <aS3ITHKoLF0ecw2o@lizhi-Precision-Tower-5810>

On Mon, Dec 01, 2025 at 03:58:43PM +0900, Chancel Liu wrote:
> Add bt-sco sound card, which is used by BT HFP case.
> It supports wb profile as default.
>
> Signed-off-by: Chancel Liu <chancel.liu at nxp.com>
> ---

Reviewed-by: Frank Li <Frank.Li at nxp.com>

>  .../boot/dts/freescale/imx93-14x14-evk.dts    | 43 +++++++++++++++++++
>  1 file changed, 43 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/freescale/imx93-14x14-evk.dts b/arch/arm64/boot/dts/freescale/imx93-14x14-evk.dts
> index f9eebd27d640..e47fee24471a 100644
> --- a/arch/arm64/boot/dts/freescale/imx93-14x14-evk.dts
> +++ b/arch/arm64/boot/dts/freescale/imx93-14x14-evk.dts
> @@ -27,6 +27,11 @@ aliases {
>  		serial0 = &lpuart1;
>  	};
>
> +	bt_sco_codec: bt-sco-codec {
> +		compatible = "linux,bt-sco";
> +		#sound-dai-cells = <1>;
> +	};
> +
>  	chosen {
>  		stdout-path = &lpuart1;
>  	};
> @@ -168,6 +173,25 @@ reg_vref_1v8: regulator-adc-vref {
>  		regulator-max-microvolt = <1800000>;
>  	};
>
> +	sound-bt-sco {
> +		compatible = "simple-audio-card";
> +		simple-audio-card,name = "bt-sco-audio";
> +		simple-audio-card,format = "dsp_a";
> +		simple-audio-card,bitclock-inversion;
> +		simple-audio-card,frame-master = <&btcpu>;
> +		simple-audio-card,bitclock-master = <&btcpu>;
> +
> +		simple-audio-card,codec {
> +			sound-dai = <&bt_sco_codec 1>;
> +		};
> +
> +		btcpu: simple-audio-card,cpu {
> +			sound-dai = <&sai1>;
> +			dai-tdm-slot-num = <2>;
> +			dai-tdm-slot-width = <16>;
> +		};
> +	};
> +
>  	usdhc3_pwrseq: usdhc3_pwrseq {
>  		compatible = "mmc-pwrseq-simple";
>  		reset-gpios = <&pcal6524 12 GPIO_ACTIVE_LOW>;
> @@ -371,6 +395,16 @@ &mu2 {
>  	status = "okay";
>  };
>
> +&sai1 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_sai1>;
> +	assigned-clocks = <&clk IMX93_CLK_SAI1>;
> +	assigned-clock-parents = <&clk IMX93_CLK_AUDIO_PLL>;
> +	assigned-clock-rates = <12288000>;
> +	fsl,sai-mclk-direction-output;
> +	status = "okay";
> +};
> +
>  &usbotg1 {
>  	dr_mode = "otg";
>  	hnp-disable;
> @@ -568,6 +602,15 @@ MX93_PAD_SD2_RESET_B__GPIO3_IO07	0x31e
>  		>;
>  	};
>
> +	pinctrl_sai1: sai1grp {
> +		fsl,pins = <
> +			MX93_PAD_SAI1_TXC__SAI1_TX_BCLK		0x31e
> +			MX93_PAD_SAI1_TXFS__SAI1_TX_SYNC	0x31e
> +			MX93_PAD_SAI1_TXD0__SAI1_TX_DATA00	0x31e
> +			MX93_PAD_SAI1_RXD0__SAI1_RX_DATA00	0x31e
> +		>;
> +	};
> +
>  	pinctrl_usdhc2_gpio: usdhc2gpiogrp {
>  		fsl,pins = <
>  			MX93_PAD_SD2_CD_B__GPIO3_IO00		0x31e
> --
> 2.50.1
>


From linux at armlinux.org.uk  Mon Dec  1 08:55:02 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 1 Dec 2025 16:55:02 +0000
Subject: [PATCH 4/4] dts: s32g: Add GPR syscon region
In-Reply-To: <aS3FWLWQ1g4YQjFi@lizhi-Precision-Tower-5810>
References: <cover.1764592300.git.dan.carpenter@linaro.org>
 <c8302f53fcbb5cb5afe42cdb15aba7e2e6ed7338.1764592300.git.dan.carpenter@linaro.org>
 <aS3FWLWQ1g4YQjFi@lizhi-Precision-Tower-5810>
Message-ID: <aS3IZlGBQyvXNVOe@shell.armlinux.org.uk>

On Mon, Dec 01, 2025 at 11:42:00AM -0500, Frank Li wrote:
> On Mon, Dec 01, 2025 at 04:08:33PM +0300, Dan Carpenter wrote:
> > Add the GPR syscon region for the s32 chipset.
> >
> > Signed-off-by: Dan Carpenter <dan.carpenter at linaro.org>
> > ---
> >  arch/arm64/boot/dts/freescale/s32g2.dtsi | 8 ++++++++
> >  arch/arm64/boot/dts/freescale/s32g3.dtsi | 8 ++++++++
> >  2 files changed, 16 insertions(+)
> >
> > diff --git a/arch/arm64/boot/dts/freescale/s32g2.dtsi b/arch/arm64/boot/dts/freescale/s32g2.dtsi
> > index 51d00dac12de..3c9472f6c174 100644
> > --- a/arch/arm64/boot/dts/freescale/s32g2.dtsi
> > +++ b/arch/arm64/boot/dts/freescale/s32g2.dtsi
> > @@ -325,6 +325,13 @@ usdhc0-200mhz-grp4 {
> >  			};
> >  		};
> >
> > +		gpr: syscon at 4007c000 {
> > +			compatible = "nxp,s32-gpr", "syscon";
> > +			reg = <0x4007c000 0x3000>;
> > +			#address-cells = <1>;
> > +			#size-cells = <1>;
> > +		};
> > +
> 
> Please cc whole thread to imx at lists.linux.dev.
> 
> I think it is not good method by using syscon here.
> 
> Suppose using standard phy interface or mux controller interface.

I rather disagree, but I would like to see the definition of the
"ctrl_sts" register. The driver defines:

/* SoC PHY interface control register */
#define S32_PHY_INTF_SEL_MII    0x00
#define S32_PHY_INTF_SEL_SGMII  0x01
#define S32_PHY_INTF_SEL_RGMII  0x02
#define S32_PHY_INTF_SEL_RMII   0x08

This is mostly equivalent to the phy_intf_sel_i[2:0] input to the GMAC
block, who's bit combinations are defined by the PHY_INTF_SEL_xxx
constants. These seem to correspond to register bits 3:1, but with
the GMAC being configured for MII mode with an external SGMII PCS
when bit 0 is set.

If this is true, then no, there is no "phy" as such, and if we go
down the route of modelling the GMAC's phy_intf_sel_i[2:0] inputs
as a "phy" then we're going to end up with something that's a
drivers/phy PHY before a real seperate PHY for providing the
SGMII/1000BASE-X signalling. This falls into the category of needless
over-complication with no benefit.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From Frank.li at nxp.com  Mon Dec  1 08:56:22 2025
From: Frank.li at nxp.com (Frank Li)
Date: Mon, 1 Dec 2025 11:56:22 -0500
Subject: [PATCH 2/2] arm64: dts: imx93-14x14-evk: Add audio XCVR sound
 card
In-Reply-To: <20251201065844.3823323-3-chancel.liu@nxp.com>
References: <20251201065844.3823323-1-chancel.liu@nxp.com>
 <20251201065844.3823323-3-chancel.liu@nxp.com>
Message-ID: <aS3ItlvCiaqBbsxd@lizhi-Precision-Tower-5810>

On Mon, Dec 01, 2025 at 03:58:44PM +0900, Chancel Liu wrote:
> Add audio XCVR sound card, which supports SPDIF TX & RX only,
> eARC RX, ARC RX are not supported.

nit: next time, wrap at 75 char.

Reviewed-by: Frank Li <Frank.Li at nxp.com>

>
> Signed-off-by: Chancel Liu <chancel.liu at nxp.com>
> ---
>  .../boot/dts/freescale/imx93-14x14-evk.dts    | 31 +++++++++++++++++++
>  1 file changed, 31 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/freescale/imx93-14x14-evk.dts b/arch/arm64/boot/dts/freescale/imx93-14x14-evk.dts
> index e47fee24471a..61843b2c1b1b 100644
> --- a/arch/arm64/boot/dts/freescale/imx93-14x14-evk.dts
> +++ b/arch/arm64/boot/dts/freescale/imx93-14x14-evk.dts
> @@ -192,6 +192,19 @@ btcpu: simple-audio-card,cpu {
>  		};
>  	};
>
> +	sound-xcvr {
> +		compatible = "fsl,imx-audio-card";
> +		model = "imx-audio-xcvr";
> +
> +		pri-dai-link {
> +			link-name = "XCVR PCM";
> +
> +			cpu {
> +				sound-dai = <&xcvr>;
> +			};
> +		};
> +	};
> +
>  	usdhc3_pwrseq: usdhc3_pwrseq {
>  		compatible = "mmc-pwrseq-simple";
>  		reset-gpios = <&pcal6524 12 GPIO_ACTIVE_LOW>;
> @@ -468,6 +481,17 @@ &wdog3 {
>  	status = "okay";
>  };
>
> +&xcvr {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_spdif>;
> +	assigned-clocks = <&clk IMX93_CLK_SPDIF>,
> +			  <&clk IMX93_CLK_AUDIO_XCVR>;
> +	assigned-clock-parents = <&clk IMX93_CLK_AUDIO_PLL>,
> +				 <&clk IMX93_CLK_SYS_PLL_PFD1_DIV2>;
> +	assigned-clock-rates = <12288000>, <200000000>;
> +	status = "okay";
> +};
> +
>  &iomuxc {
>  	pinctrl_flexcan1: flexcan1grp {
>  		fsl,pins = <
> @@ -611,6 +635,13 @@ MX93_PAD_SAI1_RXD0__SAI1_RX_DATA00	0x31e
>  		>;
>  	};
>
> +	pinctrl_spdif: spdifgrp {
> +		fsl,pins = <
> +			MX93_PAD_GPIO_IO22__SPDIF_IN		0x31e
> +			MX93_PAD_GPIO_IO23__SPDIF_OUT		0x31e
> +		>;
> +	};
> +
>  	pinctrl_usdhc2_gpio: usdhc2gpiogrp {
>  		fsl,pins = <
>  			MX93_PAD_SD2_CD_B__GPIO3_IO00		0x31e
> --
> 2.50.1
>


From mripard at kernel.org  Mon Dec  1 09:01:56 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Mon, 1 Dec 2025 18:01:56 +0100
Subject: [PATCH v3 00/11] drm/connector: hdmi: limit infoframes per
 driver capabilities
In-Reply-To: <cgzclxjubj5oca3rdnv44qwrkmpddxve4tlz76cc6p3b4hz3oc@3l7mt5ha7do6>
References: <20250925-fervent-merry-beagle-2baba3@penduick>
 <qx5ashx62pufott6hnsfna3qntnoyvxwxze4rihhuxcsdxi37s@bbdvc3sfsgne>
 <20250929-gregarious-worm-of-memory-c5354d@houat>
 <itgffxygopi7etkt7xhvmyuvyl5ad3k43nsxvjzw3ubtwiikn7@ocugfdaigtu7>
 <20251003-uptight-echidna-of-stamina-815305@houat>
 <zpygq4kapil3swsmhhqkdwny4ry2dznnzixsw5rkza5p2kqnvp@abvf2vxlbwif>
 <2a5fitdzr2bz235fj6rvqzxr6ckszkjbazjfszlvnizdh2cvbt@w3ypjo7vahhs>
 <pibxhl5hlcpuk3zsgyienfdlda5cwuxrnofwlw356scuzzplqy@zw3ofelgvwik>
 <bsoqyzxi45i67jpzhwr2d4illufa5ghqf25z6flbp67lsbvh22@rrlcihp2oxea>
 <cgzclxjubj5oca3rdnv44qwrkmpddxve4tlz76cc6p3b4hz3oc@3l7mt5ha7do6>
Message-ID: <20251201-enlightened-zebu-from-asgard-5a20be@houat>

On Fri, Nov 21, 2025 at 07:09:01PM +0200, Dmitry Baryshkov wrote:
> > So it's not really impossible, you just need some hardware and a day's
> > worth of work.
> > 
> > There's no reason these should get a pass, it's breaking the spec for no
> > reason.
> > 
> > > > For SPD, It's really not clear to me why atomic_check should do that in
> > > > the first place. Your initial concern was about exposing infoframes in
> > > > debugfs that wouldn't be used by the driver.
> > > > 
> > > > If the driver doesn't register a debugfs file for SPD, and ignores
> > > > whatever is in the atomic state, what's should we force drivers to do
> > > > that?
> > > 
> > > I really don't think that drivers should mess up with debugfs on their
> > > own. Making atomic_check() disable the unsupported InfoFrames makes the
> > > picture perfect: the DRM no longer tries to program them to the
> > > hardware, DebugFS files stay empty, so the whole state becomes
> > > consistent.
> > 
> > In the "bridge has no access to infoframes" case, there's really no
> > infoframe. An empty file is "the infoframe can be there but isn't used",
> > not "we don't have access to it and can't report them". Only drivers
> > have those infos.
> > 
> > If we do split up write_infoframe into multiple functions though, I
> > guess we could create the debugfs file only if the function pointer is
> > set, which removes drivers' involvement if you don't like that.
> 
> I'm fine with not using HDMI connector framework for lt9611uxc.
> Likewise, I think, it's fine to have empty files for the infoframes
> which are not being sent over the wire for any reason (hw not supporting
> it is one of the reasons).

I can't think of any other example in the kernel where an empty file
means that the driver doesn't support something.

Maxime
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 273 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251201/16c7a055/attachment.sig>

From leitao at debian.org  Mon Dec  1 09:04:07 2025
From: leitao at debian.org (Breno Leitao)
Date: Mon, 1 Dec 2025 09:04:07 -0800
Subject: CSD lockup during kexec due to unbounded busy-wait in
 pl011_console_write_atomic (arm64)
In-Reply-To: <aSnI8UQRNICSKxAb@pathway.suse.cz>
References: <sqwajvt7utnt463tzxgwu2yctyn5m6bjwrslsnupfexeml6hkd@v6sqmpbu3vvu>
 <aSnI8UQRNICSKxAb@pathway.suse.cz>
Message-ID: <qluelhof4piilyqbyanflp3qdljxak73kt2yvahkaby6vmyzzu@qgvqej7kdio5>

Hello Petr,

On Fri, Nov 28, 2025 at 05:08:17PM +0100, Petr Mladek wrote:
> On Tue 2025-11-25 08:02:16, Breno Leitao wrote:
>
> I do _not_ think that the CPU was waiting in pl011_console_write_atomic() in the
> the following cycle the entire 11 secs:
> 
> 	while ((pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr) & uap->vendor->fr_busy)
> 		cpu_relax();
> 
> A more likely scenario was that pl011_console_write_atomic() was
> called several times during this period because there were more
> pending messages.

Probably. Most of the messages are coming from CPU being powered off:

	[   44.119433] psci: CPU1 killed (polled 0 ms)
	[   44.146057] psci: CPU2 killed (polled 0 ms)
	[   44.182058] psci: CPU3 killed (polled 0 ms)
	[   44.218031] psci: CPU4 killed (polled 0 ms)
	[   44.252962] psci: CPU5 killed (polled 0 ms)
	[   44.276939] psci: CPU6 killed (polled 0 ms)
	[   44.296152] psci: CPU7 killed (polled 1 ms)
	....

And this only happens on "large" machines, thus, the host is flushing
a lot of messages during kexec turn down time.

> >   printk_kthreads_shutdown (kernel/printk/printk.c:?)
> 
> But the function seems be called with IRQs enabled. So that it might
> help to restore IRQs after each flushed message.

Agree. This would make the irq-disabled sections much smaller, with
a higher changes of IPIs and NMIs (on arm64 hosts without FEAT_NMI).

> But we could extend the existing commit d5d399efff6577 ("printk/nbcon:
> Release nbcon consoles ownership in atomic flush after each emitted
> record") and restore IRQs after each emitted record.
> 
> I wonder if the following patch would help in this scenario.
> It is made on top of "for-next" branch in printk/linux.git.
> But the most important pre-requisite is the above mentioned commit
> in the branch "rework/atomic-flush-hardlockup".
> 
> Note that the patch is only compile tested.

I've tested the patch and I don't see the CSD lockups anymore.
Thanks for the quick fix.

> Closes: https://lore.kernel.org/r/sqwajvt7utnt463tzxgwu2yctyn5m6bjwrslsnupfexeml6hkd at v6sqmpbu3vvu
> Signed-off-by: Petr Mladek <pmladek at suse.com>

Tested-by: Breno Leitao <leitao at debian.org>

Thanks for all people involved in here. With this last patch (that makes
the irq-disbled section smaller), and kfence not IPIing during kexec
time, I consider this issue closed. 

--breno


From Frank.li at nxp.com  Mon Dec  1 09:10:01 2025
From: Frank.li at nxp.com (Frank Li)
Date: Mon, 1 Dec 2025 12:10:01 -0500
Subject: [PATCH] arm64: dts: imx93-9x9-qsb: add CAN support
In-Reply-To: <DU0PR04MB94968BBFFF9FC757C177C14E90DFA@DU0PR04MB9496.eurprd04.prod.outlook.com>
References: <20251126-b4-9391-can-dts-v1-1-c23145f0d2db@nxp.com>
 <aScpNjZNU5MtfVRc@lizhi-Precision-Tower-5810>
 <DU0PR04MB94968BBFFF9FC757C177C14E90DFA@DU0PR04MB9496.eurprd04.prod.outlook.com>
Message-ID: <aS3L6cPxHE11FF4p@lizhi-Precision-Tower-5810>

On Thu, Nov 27, 2025 at 02:01:47AM +0000, Bough Chen wrote:
> > -----Original Message-----
> > From: Frank Li <frank.li at nxp.com>
> > Sent: 2025?11?27? 0:22
> > To: Bough Chen <haibo.chen at nxp.com>
> > Cc: Shawn Guo <shawnguo at kernel.org>; Sascha Hauer
> > <s.hauer at pengutronix.de>; Pengutronix Kernel Team
> > <kernel at pengutronix.de>; Fabio Estevam <festevam at gmail.com>; Rob
> > Herring <robh at kernel.org>; Krzysztof Kozlowski <krzk+dt at kernel.org>; Conor
> > Dooley <conor+dt at kernel.org>; imx at lists.linux.dev;
> > linux-arm-kernel at lists.infradead.org; devicetree at vger.kernel.org;
> > linux-kernel at vger.kernel.org
> > Subject: Re: [PATCH] arm64: dts: imx93-9x9-qsb: add CAN support
> >
> > On Wed, Nov 26, 2025 at 02:20:07PM +0800, Haibo Chen wrote:
> >
> > subject suggested,  add CAN support overlay file
> >
> > > CAN1 and Micfil share pins on imx93-9x9-qsb board, use TMUX1574RSVR to
> > > control the connection: put sel to high, select CAN1, put sel to low,
> > > select Micfil. In default, sel keep low.
> > >
> > > To support CAN1, need to put the sel to high. Besides, CAN1 use phy
> > > TJA1057GT/3.
> > >
> > > ---
> > > Signed-off-by: Haibo Chen <haibo.chen at nxp.com>
> > > ---
> > >  arch/arm64/boot/dts/freescale/Makefile             |  2 +
> > >  .../boot/dts/freescale/imx93-9x9-qsb-can1.dtso     | 63
> > ++++++++++++++++++++++
> > >  2 files changed, 65 insertions(+)
> > >
> > > diff --git a/arch/arm64/boot/dts/freescale/Makefile
> > > b/arch/arm64/boot/dts/freescale/Makefile
> > > index
> > >
> > f30d3fd724d0ce6b38f7bef10e3970ac34f70f4a..1142d3312c8651b4292837bce3
> > cb
> > > e46ab95f7e09 100644
> > > --- a/arch/arm64/boot/dts/freescale/Makefile
> > > +++ b/arch/arm64/boot/dts/freescale/Makefile
> > > @@ -373,7 +373,9 @@ dtb-$(CONFIG_ARCH_MXC) +=
> > > imx91-tqma9131-mba91xxca.dtb
> > >  dtb-$(CONFIG_ARCH_MXC) += imx93-9x9-qsb.dtb
> > >
> > >  imx93-9x9-qsb-i3c-dtbs += imx93-9x9-qsb.dtb imx93-9x9-qsb-i3c.dtbo
> > > +imx93-9x9-qsb-can1-dtbs += imx93-9x9-qsb.dtb imx93-9x9-qsb-can1.dtbo
> >
> > Keep order by alphabet.
> >
> > >  dtb-$(CONFIG_ARCH_MXC) += imx93-9x9-qsb-i3c.dtb
> > > +dtb-$(CONFIG_ARCH_MXC) += imx93-9x9-qsb-can1.dtb
> >
> > the same here
> >
> > can1 should before i3c.
>
> Okay
>
> >
> > >
> > >  dtb-$(CONFIG_ARCH_MXC) += imx93-11x11-evk.dtb
> > >  dtb-$(CONFIG_ARCH_MXC) += imx93-14x14-evk.dtb diff --git
> > > a/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-can1.dtso
> > > b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-can1.dtso
> > > new file mode 100644
> > > index
> > >
> > 0000000000000000000000000000000000000000..62d4fa6c21d794f91da59f51
> > 1d6f
> > > 0162037e9271
> > > --- /dev/null
> > > +++ b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-can1.dtso
> > > @@ -0,0 +1,63 @@
> > ...
> > > +
> > > +&pcal6524 {
> > > +	/*
> > > +	 * mic-can-sel-hog have property 'output-low', dt overlay don't
> > > +	 * support /delete-property/. Both 'output-low' and 'output-high'
> > > +	 * will be exist under hog nodes if overlay file set 'output-high'.
> > > +	 * Workaround is disable this hog and create new hog with
> > > +	 * 'output-high'.
> > > +	 */
> > > +	mic-can-sel-hog {
> > > +		status = "disabled";
> > > +	};
> >
> > are you sure 'status' work for hogs?
>
> Yes, I test on board, this method works.
>

Okay, I just want to make sure it works.

Frank

> Any better solution?
>
> Regards
> Haibo Chen
> >
> > Frank
> > > +
> > > +	/*
> > > +	 * Config the MIC/CAN_SEL to high, chose B
> > > +	 * port, connect to CAN.
> > > +	 */
> > > +	mic-can-high-sel-hog {
> > > +		gpio-hog;
> > > +		gpios = <0x11 0x00>;
> > > +		output-high;
> > > +	};
> > > +};
> > >
> > > ---
> > > base-commit: 422f3140bbcb657e1b86c484296972ab76f6d1ff
> > > change-id: 20251125-b4-9391-can-dts-2f4849978fc2
> > >
> > > Best regards,
> > > --
> > > Haibo Chen <haibo.chen at nxp.com>
> > >


From m.felsch at pengutronix.de  Mon Dec  1 09:12:05 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Mon, 01 Dec 2025 18:12:05 +0100
Subject: [PATCH 1/3] pmdomain: imx93-blk-ctrl: cleanup error path
In-Reply-To: <20251201-v6-18-topic-imx93-blkctrl-v1-0-b57a72e60105@pengutronix.de>
References: <20251201-v6-18-topic-imx93-blkctrl-v1-0-b57a72e60105@pengutronix.de>
Message-ID: <20251201-v6-18-topic-imx93-blkctrl-v1-1-b57a72e60105@pengutronix.de>

Call dev_err_probe() directly during return to make the code more
compact.

Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
---
 drivers/pmdomain/imx/imx93-blk-ctrl.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/pmdomain/imx/imx93-blk-ctrl.c b/drivers/pmdomain/imx/imx93-blk-ctrl.c
index e094fe5a42bf646c712f3eca4e66a313fa5a914c..2aa163aef8de4ee901b9cde76ce2aad246c8c08a 100644
--- a/drivers/pmdomain/imx/imx93-blk-ctrl.c
+++ b/drivers/pmdomain/imx/imx93-blk-ctrl.c
@@ -240,10 +240,8 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
 	bc->num_clks = bc_data->num_clks;
 
 	ret = devm_clk_bulk_get(dev, bc->num_clks, bc->clks);
-	if (ret) {
-		dev_err_probe(dev, ret, "failed to get bus clock\n");
-		return ret;
-	}
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to get bus clock\n");
 
 	for (i = 0; i < bc_data->num_domains; i++) {
 		const struct imx93_blk_ctrl_domain_data *data = &bc_data->domains[i];

-- 
2.47.3



From m.felsch at pengutronix.de  Mon Dec  1 09:12:07 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Mon, 01 Dec 2025 18:12:07 +0100
Subject: [PATCH 3/3] pmdomain: imx93-blk-ctrl: add support for optional
 subnodes
In-Reply-To: <20251201-v6-18-topic-imx93-blkctrl-v1-0-b57a72e60105@pengutronix.de>
References: <20251201-v6-18-topic-imx93-blkctrl-v1-0-b57a72e60105@pengutronix.de>
Message-ID: <20251201-v6-18-topic-imx93-blkctrl-v1-3-b57a72e60105@pengutronix.de>

This particular block can have DT subnodes describing the LVDS LDB, MIPI
DSI and parallel DPI bridge.

Scan for possible sub-devices within the driver, instead of misusing the
simple-bus to perform the scan.

Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
---
 drivers/pmdomain/imx/imx93-blk-ctrl.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/pmdomain/imx/imx93-blk-ctrl.c b/drivers/pmdomain/imx/imx93-blk-ctrl.c
index 13b0de6dd689cf944e034f7666a4e97b0118e3bd..8f79cabe07face872cb396bfb7329c230c4a97fe 100644
--- a/drivers/pmdomain/imx/imx93-blk-ctrl.c
+++ b/drivers/pmdomain/imx/imx93-blk-ctrl.c
@@ -7,6 +7,7 @@
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/pm_domain.h>
 #include <linux/pm_runtime.h>
@@ -311,6 +312,10 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
 	if (ret)
 		return dev_err_probe(dev, ret, "failed to add genpd_provider release callback\n");
 
+	ret = devm_of_platform_populate(dev);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to populate blk-ctrl sub-devices\n");
+
 	return 0;
 }
 

-- 
2.47.3



From m.felsch at pengutronix.de  Mon Dec  1 09:12:06 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Mon, 01 Dec 2025 18:12:06 +0100
Subject: [PATCH 2/3] pmdomain: imx93-blk-ctrl: convert to devm_* only
In-Reply-To: <20251201-v6-18-topic-imx93-blkctrl-v1-0-b57a72e60105@pengutronix.de>
References: <20251201-v6-18-topic-imx93-blkctrl-v1-0-b57a72e60105@pengutronix.de>
Message-ID: <20251201-v6-18-topic-imx93-blkctrl-v1-2-b57a72e60105@pengutronix.de>

Some APIs used by this driver don't have devm_ helpers yet. Instead of
using the devm_add_action_or_reset() the current driver is based on hand
crafted error goto paths and a .remove() callback.

Convert the driver to devm_ APIs only by making use of
devm_add_action_or_reset() and devm_pm_runtime_enable() to simplify the
release and error path.

Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
---
 drivers/pmdomain/imx/imx93-blk-ctrl.c | 64 +++++++++++++++--------------------
 1 file changed, 27 insertions(+), 37 deletions(-)

diff --git a/drivers/pmdomain/imx/imx93-blk-ctrl.c b/drivers/pmdomain/imx/imx93-blk-ctrl.c
index 2aa163aef8de4ee901b9cde76ce2aad246c8c08a..13b0de6dd689cf944e034f7666a4e97b0118e3bd 100644
--- a/drivers/pmdomain/imx/imx93-blk-ctrl.c
+++ b/drivers/pmdomain/imx/imx93-blk-ctrl.c
@@ -188,6 +188,20 @@ static int imx93_blk_ctrl_power_off(struct generic_pm_domain *genpd)
 	return 0;
 }
 
+static void imx93_release_genpd_provider(void *data)
+{
+	struct device_node *of_node = data;
+
+	of_genpd_del_provider(of_node);
+}
+
+static void imx93_release_pm_genpd(void *data)
+{
+	struct generic_pm_domain *genpd = data;
+
+	pm_genpd_remove(genpd);
+}
+
 static struct lock_class_key blk_ctrl_genpd_lock_class;
 
 static int imx93_blk_ctrl_probe(struct platform_device *pdev)
@@ -256,10 +270,8 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
 			domain->clks[j].id = data->clk_names[j];
 
 		ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks);
-		if (ret) {
-			dev_err_probe(dev, ret, "failed to get clock\n");
-			goto cleanup_pds;
-		}
+		if (ret)
+			return dev_err_probe(dev, ret, "failed to get clock\n");
 
 		domain->genpd.name = data->name;
 		domain->genpd.power_on = imx93_blk_ctrl_power_on;
@@ -267,11 +279,12 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
 		domain->bc = bc;
 
 		ret = pm_genpd_init(&domain->genpd, NULL, true);
-		if (ret) {
-			dev_err_probe(dev, ret, "failed to init power domain\n");
-			goto cleanup_pds;
-		}
+		if (ret)
+			return dev_err_probe(dev, ret, "failed to init power domain\n");
 
+		ret = devm_add_action_or_reset(dev, imx93_release_pm_genpd, &domain->genpd);
+		if (ret)
+			return dev_err_probe(dev, ret, "failed to add pm_genpd release callback\n");
 		/*
 		 * We use runtime PM to trigger power on/off of the upstream GPC
 		 * domain, as a strict hierarchical parent/child power domain
@@ -288,39 +301,17 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
 		bc->onecell_data.domains[i] = &domain->genpd;
 	}
 
-	pm_runtime_enable(dev);
+	devm_pm_runtime_enable(dev);
 
 	ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data);
-	if (ret) {
-		dev_err_probe(dev, ret, "failed to add power domain provider\n");
-		goto cleanup_pds;
-	}
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to add power domain provider\n");
 
-	dev_set_drvdata(dev, bc);
+	ret = devm_add_action_or_reset(dev, imx93_release_genpd_provider, dev->of_node);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to add genpd_provider release callback\n");
 
 	return 0;
-
-cleanup_pds:
-	for (i--; i >= 0; i--)
-		pm_genpd_remove(&bc->domains[i].genpd);
-
-	return ret;
-}
-
-static void imx93_blk_ctrl_remove(struct platform_device *pdev)
-{
-	struct imx93_blk_ctrl *bc = dev_get_drvdata(&pdev->dev);
-	int i;
-
-	of_genpd_del_provider(pdev->dev.of_node);
-
-	pm_runtime_disable(&pdev->dev);
-
-	for (i = 0; i < bc->onecell_data.num_domains; i++) {
-		struct imx93_blk_ctrl_domain *domain = &bc->domains[i];
-
-		pm_genpd_remove(&domain->genpd);
-	}
 }
 
 static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] = {
@@ -455,7 +446,6 @@ MODULE_DEVICE_TABLE(of, imx93_blk_ctrl_of_match);
 
 static struct platform_driver imx93_blk_ctrl_driver = {
 	.probe = imx93_blk_ctrl_probe,
-	.remove = imx93_blk_ctrl_remove,
 	.driver = {
 		.name = "imx93-blk-ctrl",
 		.of_match_table = imx93_blk_ctrl_of_match,

-- 
2.47.3



From m.felsch at pengutronix.de  Mon Dec  1 09:12:04 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Mon, 01 Dec 2025 18:12:04 +0100
Subject: [PATCH 0/3] i.MX91/93 BLK-CTRL improvements
Message-ID: <20251201-v6-18-topic-imx93-blkctrl-v1-0-b57a72e60105@pengutronix.de>

Hi,

there were several approaches to bring the sub-devices population
mainline [1,2] but non of them made it upstream. Both approaches were
part of either the i.MX93 LVDS or MIPI-CSI enablement.

This small patchset decouples the blk-ctrl changes which allows the
MIPI-CSI and LVDS patchstack to be rebased ontop of this patchset.

Before adding the sub-device supprt, I converted the driver to devm_*
only API.

Regards,
  Marco

[1] https://lore.kernel.org/all/20250701-95_cam-v1-3-c5172bab387b at nxp.com/
[2] https://lore.kernel.org/all/20250304154929.1785200-4-alexander.stein at ew.tq-group.com/

Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
---
Marco Felsch (3):
      pmdomain: imx93-blk-ctrl: cleanup error path
      pmdomain: imx93-blk-ctrl: convert to devm_* only
      pmdomain: imx93-blk-ctrl: add support for optional subnodes

 drivers/pmdomain/imx/imx93-blk-ctrl.c | 75 ++++++++++++++++-------------------
 1 file changed, 34 insertions(+), 41 deletions(-)
---
base-commit: 3a8660878839faadb4f1a6dd72c3179c1df56787
change-id: 20251201-v6-18-topic-imx93-blkctrl-341220f7084d

Best regards,
-- 
Marco Felsch <m.felsch at pengutronix.de>



From m.felsch at pengutronix.de  Mon Dec  1 09:15:19 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Mon, 01 Dec 2025 18:15:19 +0100
Subject: [PATCH v6 0/3] Add i.MX91/93 parallel display support
Message-ID: <20251201-v6-18-topic-imx93-parallel-display-v6-0-7b056e1e5b1e@pengutronix.de>

Hi,

this patchset adds the driver, dt-bindings and dt integration required
to drive a parallel display on the i.MX93.

Since the i.MX91 register layout equals the one from the i.MX93, I added
the support for both but tested only the i.MX93 use-case.

This patchset depends on:
 - https://lore.kernel.org/all/20251201-v6-18-topic-imx93-blkctrl-v1-0-b57a72e60105 at pengutronix.de/

@Conor Dooley
I dropped your r-b tag since I added the 'bus-width' property.

Regards,
  Marco

Changelog:
v5:
- https://lore.kernel.org/all/20250304082434.834031-1-victor.liu at nxp.com/
- Add bus-width support
- rebase onto v6.18-rc1
- add review feedback (Alexander)
- driver license "GPL v2" -> "GPL" (checkpatch)
- make use of reg of-property
- fix to short Kconfig description (checkpath)
- add OF integration

Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
---
Liu Ying (2):
      dt-bindings: soc: imx93-media-blk-ctrl: Add PDFC subnode to schema and example
      drm/bridge: imx: Add i.MX93 parallel display format configuration support

Marco Felsch (1):
      arm64: dts: imx93: Add parallel display output nodes

 .../bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml |  92 +++++++++
 arch/arm64/boot/dts/freescale/imx91_93_common.dtsi |  57 ++++++
 arch/arm64/boot/dts/freescale/imx93.dtsi           |  12 ++
 drivers/gpu/drm/bridge/imx/Kconfig                 |  11 +
 drivers/gpu/drm/bridge/imx/Makefile                |   1 +
 drivers/gpu/drm/bridge/imx/imx93-pdfc.c            | 225 +++++++++++++++++++++
 6 files changed, 398 insertions(+)
---
base-commit: 3a8660878839faadb4f1a6dd72c3179c1df56787
change-id: 20251201-v6-18-topic-imx93-parallel-display-95f9234bf6cc

Best regards,
-- 
Marco Felsch <m.felsch at pengutronix.de>



From m.felsch at pengutronix.de  Mon Dec  1 09:15:20 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Mon, 01 Dec 2025 18:15:20 +0100
Subject: [PATCH v6 1/3] dt-bindings: soc: imx93-media-blk-ctrl: Add PDFC
 subnode to schema and example
In-Reply-To: <20251201-v6-18-topic-imx93-parallel-display-v6-0-7b056e1e5b1e@pengutronix.de>
References: <20251201-v6-18-topic-imx93-parallel-display-v6-0-7b056e1e5b1e@pengutronix.de>
Message-ID: <20251201-v6-18-topic-imx93-parallel-display-v6-1-7b056e1e5b1e@pengutronix.de>

From: Liu Ying <victor.liu at nxp.com>

i.MX93 SoC mediamix blk-ctrl contains one DISPLAY_MUX register which
configures parallel display format by using the "PARALLEL_DISP_FORMAT"
field. Document the Parallel Display Format Configuration(PDFC) subnode
and add the subnode to example.

Signed-off-by: Liu Ying <victor.liu at nxp.com>
[m.felsch at pengutronix.de: port to v6.18-rc1]
[m.felsch at pengutronix.de: add bus-width]
Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
---
 .../bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml | 92 ++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
index 34aea58094e55365a2f9c86092f637e533f954ff..6e2d86d9341c75108b492bcbabc8a560d8e707cd 100644
--- a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
+++ b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
@@ -26,6 +26,12 @@ properties:
   reg:
     maxItems: 1
 
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 1
+
   '#power-domain-cells':
     const: 1
 
@@ -40,6 +46,60 @@ properties:
     minItems: 8
     maxItems: 10
 
+  bridge at 60:
+    type: object
+    additionalProperties: false
+
+    properties:
+      compatible:
+        const: nxp,imx93-pdfc
+
+      reg:
+        maxItems: 1
+
+      ports:
+        $ref: /schemas/graph.yaml#/properties/ports
+
+        properties:
+          port at 0:
+            $ref: /schemas/graph.yaml#/properties/port
+            description: Input port node to receive pixel data.
+
+          port at 1:
+            $ref: /schemas/graph.yaml#/$defs/port-base
+            unevaluatedProperties: false
+            description: Output port node to downstream pixel data receivers.
+
+            properties:
+              endpoint:
+                $ref: /schemas/graph.yaml#/$defs/endpoint-base
+                unevaluatedProperties: false
+
+                properties:
+                  bus-width:
+                    enum: [ 16, 18, 24 ]
+                    description:
+                      Specify the physical parallel bus width.
+
+                      This property is optional if the display bus-width
+                      matches the SoC bus-width, e.g. a 18-bit RGB666 (display)
+                      is connected and all 18-bit data lanes are muxed to the
+                      parallel-output pads.
+
+                      This property must be set to 18 to cut only the LSBs
+                      instead of the MSBs in case a 24-bit RGB888 display is
+                      connected and only the lower 18-bit data lanes are muxed
+                      to the parallel-output pads.
+
+        required:
+          - port at 0
+          - port at 1
+
+    required:
+      - compatible
+      - reg
+      - ports
+
 allOf:
   - if:
       properties:
@@ -81,9 +141,12 @@ allOf:
             - const: isi
             - const: csi
             - const: dsi
+
 required:
   - compatible
   - reg
+  - '#address-cells'
+  - '#size-cells'
   - power-domains
   - clocks
   - clock-names
@@ -112,4 +175,33 @@ examples:
                clock-names = "apb", "axi", "nic", "disp", "cam",
                              "pxp", "lcdif", "isi", "csi", "dsi";
       #power-domain-cells = <1>;
+      #address-cells = <1>;
+      #size-cells = <1>;
+
+      bridge at 60 {
+        compatible = "nxp,imx93-pdfc";
+        reg = <0x60 0x4>;
+
+        ports {
+          #address-cells = <1>;
+          #size-cells = <0>;
+
+          port at 0 {
+            reg = <0>;
+
+            pdfc_from_lcdif: endpoint {
+              remote-endpoint = <&lcdif_to_pdfc>;
+            };
+          };
+
+          port at 1 {
+            reg = <1>;
+
+            pdfc_to_panel: endpoint {
+              remote-endpoint = <&panel_from_pdfc>;
+              bus-width = <18>;
+            };
+          };
+        };
+      };
     };

-- 
2.47.3



From m.felsch at pengutronix.de  Mon Dec  1 09:15:22 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Mon, 01 Dec 2025 18:15:22 +0100
Subject: [PATCH v6 3/3] arm64: dts: imx93: Add parallel display output
 nodes
In-Reply-To: <20251201-v6-18-topic-imx93-parallel-display-v6-0-7b056e1e5b1e@pengutronix.de>
References: <20251201-v6-18-topic-imx93-parallel-display-v6-0-7b056e1e5b1e@pengutronix.de>
Message-ID: <20251201-v6-18-topic-imx93-parallel-display-v6-3-7b056e1e5b1e@pengutronix.de>

Add required OF nodes to support the i.MX93 parallel output (DPI) path.

On the i.MX93 a single LCDIF is connected to three bridges: DPI, LVDS
LDB and the MIPI-DSI whereas the i.MX91 support only the DPI bridge.

Map endpoint at 0 as DPI bridge output since the i.MX93 TRM (Figure 485.
MEDIAMIX block diagram) doesn't mention any port-number <-> bridge
combination.

Set the MEDIA-AXI and MEDIA-APB clocks to the overdrive (OD) values
since the i.MX93 and i.MX91 use the overdrive (OD) clk settings per
default.

Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
---
 arch/arm64/boot/dts/freescale/imx91_93_common.dtsi | 57 ++++++++++++++++++++++
 arch/arm64/boot/dts/freescale/imx93.dtsi           | 12 +++++
 2 files changed, 69 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx91_93_common.dtsi b/arch/arm64/boot/dts/freescale/imx91_93_common.dtsi
index 52da571f26c4e8a2703e4476b5541fa7aca52f10..6dc01a76c68425bb65576712bfd98950d662bd38 100644
--- a/arch/arm64/boot/dts/freescale/imx91_93_common.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx91_93_common.dtsi
@@ -1122,8 +1122,65 @@ media_blk_ctrl: system-controller at 4ac10000 {
 				 <&clk IMX93_CLK_MIPI_DSI_GATE>;
 			clock-names = "apb", "axi", "nic", "disp", "cam",
 				      "pxp", "lcdif", "isi", "csi", "dsi";
+			assigned-clocks = <&clk IMX93_CLK_MEDIA_AXI>,
+					  <&clk IMX93_CLK_MEDIA_APB>,
+					  <&clk IMX93_CLK_MEDIA_DISP_PIX>;
+			assigned-clock-parents = <&clk IMX93_CLK_SYS_PLL_PFD1>,
+						 <&clk IMX93_CLK_SYS_PLL_PFD1_DIV2>,
+						 <&clk IMX93_CLK_VIDEO_PLL>;
+			assigned-clock-rates = <400000000>, <133333333>;
 			#power-domain-cells = <1>;
+			#address-cells = <1>;
+			#size-cells = <1>;
 			status = "disabled";
+
+			dpi_bridge: bridge at 60 {
+				compatible = "nxp,imx93-pdfc";
+				reg = <0x60 0x4>;
+				status = "disabled";
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port at 0 {
+						reg = <0>;
+
+						dpi_from_lcdif: endpoint {
+							remote-endpoint = <&lcdif_to_dpi>;
+						};
+					};
+
+					port at 1 {
+						reg = <1>;
+
+						dpi_to_panel: endpoint {
+						};
+					};
+				};
+			};
+		};
+
+		lcdif: display-controller at 4ae30000 {
+			compatible = "fsl,imx93-lcdif";
+			reg = <0x4ae30000 0x23c>;
+			interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clk IMX93_CLK_MEDIA_DISP_PIX>,
+				 <&clk IMX93_CLK_LCDIF_GATE>,
+				 <&clk IMX93_CLK_MEDIA_AXI>;
+			clock-names = "pix", "axi", "disp_axi";
+			power-domains = <&media_blk_ctrl IMX93_MEDIABLK_PD_LCDIF>;
+			status = "disabled";
+
+			port {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				lcdif_to_dpi: endpoint at 0 {
+					reg = <0>;
+					remote-endpoint = <&dpi_from_lcdif>;
+				};
+			};
 		};
 
 		usbotg1: usb at 4c100000 {
diff --git a/arch/arm64/boot/dts/freescale/imx93.dtsi b/arch/arm64/boot/dts/freescale/imx93.dtsi
index 7b27012dfcb564650882dc8c40e836e797b2fda1..5436b48b30e89eb1f939b398ce1bf105abe7e34b 100644
--- a/arch/arm64/boot/dts/freescale/imx93.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx93.dtsi
@@ -150,6 +150,18 @@ l3_cache: l3-cache {
 	};
 };
 
+&lcdif {
+	port {
+		lcdif_to_ldb: endpoint at 1 {
+			reg = <1>;
+		};
+
+		lcdif_to_dsi: endpoint at 2 {
+			reg = <2>;
+		};
+	};
+};
+
 &src {
 	mlmix: power-domain at 44461800 {
 		compatible = "fsl,imx93-src-slice";

-- 
2.47.3



From m.felsch at pengutronix.de  Mon Dec  1 09:15:21 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Mon, 01 Dec 2025 18:15:21 +0100
Subject: [PATCH v6 2/3] drm/bridge: imx: Add i.MX93 parallel display format
 configuration support
In-Reply-To: <20251201-v6-18-topic-imx93-parallel-display-v6-0-7b056e1e5b1e@pengutronix.de>
References: <20251201-v6-18-topic-imx93-parallel-display-v6-0-7b056e1e5b1e@pengutronix.de>
Message-ID: <20251201-v6-18-topic-imx93-parallel-display-v6-2-7b056e1e5b1e@pengutronix.de>

From: Liu Ying <victor.liu at nxp.com>

NXP i.MX93 mediamix blk-ctrl contains one DISPLAY_MUX register which
configures parallel display format by using the "PARALLEL_DISP_FORMAT"
field. Add a DRM bridge driver to support the display format configuration.

Signed-off-by: Liu Ying <victor.liu at nxp.com>
[m.felsch at pengutronix.de: port to v6.18-rc1]
[m.felsch at pengutronix.de: add review feedback (Alexander)]
[m.felsch at pengutronix.de: fix to short Kconfig description (checkpath)]
[m.felsch at pengutronix.de: use "GPL" instead of "GPL v2" (checkpatch)]
[m.felsch at pengutronix.de: make use of reg property]
[m.felsch at pengutronix.de: add bus-width support]
Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
---
 drivers/gpu/drm/bridge/imx/Kconfig      |  11 ++
 drivers/gpu/drm/bridge/imx/Makefile     |   1 +
 drivers/gpu/drm/bridge/imx/imx93-pdfc.c | 225 ++++++++++++++++++++++++++++++++
 3 files changed, 237 insertions(+)

diff --git a/drivers/gpu/drm/bridge/imx/Kconfig b/drivers/gpu/drm/bridge/imx/Kconfig
index 9a480c6abb856276df9b71d23b39a43b3a9c542d..28fd7a00473a0ec50bf0ffb5d50972abc209ceec 100644
--- a/drivers/gpu/drm/bridge/imx/Kconfig
+++ b/drivers/gpu/drm/bridge/imx/Kconfig
@@ -88,4 +88,15 @@ config DRM_IMX93_MIPI_DSI
 	  Choose this to enable MIPI DSI controller found in Freescale i.MX93
 	  processor.
 
+config DRM_IMX93_PARALLEL_DISP_FMT_CONFIG
+	tristate "NXP i.MX91/i.MX93 parallel display format configuration"
+	depends on OF
+	select DRM_KMS_HELPER
+	help
+	  On i.MX93 and i.MX91 SoCs the parallel display format output is
+	  controlled via the MEDIAMIX BLK-CTRL DISPLAY_MUX.
+
+	  Say 'Y' or 'M' if you use the parallel display output path on a
+	  i.MX93 or i.MX91 SoC.
+
 endif # ARCH_MXC || COMPILE_TEST
diff --git a/drivers/gpu/drm/bridge/imx/Makefile b/drivers/gpu/drm/bridge/imx/Makefile
index dd5d4858480663bade98bd58039d1cb6f8aa18da..f4ccc5cbef72a576443d5fecf666b76dfba8aa94 100644
--- a/drivers/gpu/drm/bridge/imx/Makefile
+++ b/drivers/gpu/drm/bridge/imx/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_DRM_IMX8QXP_PIXEL_COMBINER) += imx8qxp-pixel-combiner.o
 obj-$(CONFIG_DRM_IMX8QXP_PIXEL_LINK) += imx8qxp-pixel-link.o
 obj-$(CONFIG_DRM_IMX8QXP_PIXEL_LINK_TO_DPI) += imx8qxp-pxl2dpi.o
 obj-$(CONFIG_DRM_IMX93_MIPI_DSI) += imx93-mipi-dsi.o
+obj-$(CONFIG_DRM_IMX93_PARALLEL_DISP_FMT_CONFIG) += imx93-pdfc.o
diff --git a/drivers/gpu/drm/bridge/imx/imx93-pdfc.c b/drivers/gpu/drm/bridge/imx/imx93-pdfc.c
new file mode 100644
index 0000000000000000000000000000000000000000..8923012108ab9794c74813c1c58c1b4ab36cb5ae
--- /dev/null
+++ b/drivers/gpu/drm/bridge/imx/imx93-pdfc.c
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/*
+ * Copyright 2022-2025 NXP
+ */
+
+#include <linux/media-bus-format.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_print.h>
+
+#define PARALLEL_DISP_FORMAT		GENMASK(10, 8)
+#define FORMAT_RGB888_TO_RGB888		FIELD_PREP(PARALLEL_DISP_FORMAT, 0)
+#define FORMAT_RGB888_TO_RGB666		FIELD_PREP(PARALLEL_DISP_FORMAT, 1)
+#define FORMAT_RGB565_TO_RGB565		FIELD_PREP(PARALLEL_DISP_FORMAT, 2)
+
+struct imx93_pdfc {
+	struct drm_bridge bridge;
+	struct drm_bridge *next_bridge;
+	struct device *dev;
+	struct regmap *regmap;
+	u64 disp_mux_reg_off;
+	u32 phy_bus_width;
+};
+
+static int
+imx93_pdfc_bridge_attach(struct drm_bridge *bridge, struct drm_encoder *encoder,
+			 enum drm_bridge_attach_flags flags)
+{
+	struct imx93_pdfc *pdfc = bridge->driver_private;
+
+	return drm_bridge_attach(bridge->encoder, pdfc->next_bridge, bridge, flags);
+}
+
+static void imx93_pdfc_bridge_atomic_enable(struct drm_bridge *bridge,
+					    struct drm_atomic_state *state)
+{
+	struct imx93_pdfc *pdfc = bridge->driver_private;
+	const struct drm_bridge_state *bridge_state;
+	unsigned int mask = PARALLEL_DISP_FORMAT;
+	unsigned int val;
+
+	bridge_state = drm_atomic_get_new_bridge_state(state, bridge);
+
+	switch (bridge_state->output_bus_cfg.format) {
+	case MEDIA_BUS_FMT_RGB888_1X24:
+		val = FORMAT_RGB888_TO_RGB888;
+		if (pdfc->phy_bus_width == 18) {
+			/*
+			 * Can be valid if physical bus limitation exist,
+			 * therefore use dev_dbg().
+			 */
+			dev_dbg(pdfc->dev, "Truncate two LSBs from each color\n");
+			val = FORMAT_RGB888_TO_RGB666;
+		}
+		break;
+	case MEDIA_BUS_FMT_RGB666_1X18:
+		val = FORMAT_RGB888_TO_RGB666;
+		break;
+	case MEDIA_BUS_FMT_RGB565_1X16:
+		val = FORMAT_RGB565_TO_RGB565;
+		break;
+	}
+
+	regmap_update_bits(pdfc->regmap, pdfc->disp_mux_reg_off, mask, val);
+}
+
+static const u32 imx93_pdfc_bus_output_fmts[] = {
+	MEDIA_BUS_FMT_RGB888_1X24,
+	MEDIA_BUS_FMT_RGB666_1X18,
+	MEDIA_BUS_FMT_RGB565_1X16,
+	MEDIA_BUS_FMT_FIXED
+};
+
+static bool imx93_pdfc_bus_output_fmt_supported(u32 fmt)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(imx93_pdfc_bus_output_fmts); i++) {
+		if (imx93_pdfc_bus_output_fmts[i] == fmt)
+			return true;
+	}
+
+	return false;
+}
+
+static u32 *
+imx93_pdfc_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
+					    struct drm_bridge_state *bridge_state,
+					    struct drm_crtc_state *crtc_state,
+					    struct drm_connector_state *conn_state,
+					    u32 output_fmt,
+					    unsigned int *num_input_fmts)
+{
+	u32 *input_fmts;
+
+	*num_input_fmts = 0;
+
+	if (!imx93_pdfc_bus_output_fmt_supported(output_fmt))
+		return NULL;
+
+	input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
+	if (!input_fmts)
+		return NULL;
+
+	switch (output_fmt) {
+	case MEDIA_BUS_FMT_RGB888_1X24:
+	case MEDIA_BUS_FMT_RGB565_1X16:
+		input_fmts[0] = output_fmt;
+		break;
+	case MEDIA_BUS_FMT_RGB666_1X18:
+	case MEDIA_BUS_FMT_FIXED:
+		input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24;
+		break;
+	}
+
+	*num_input_fmts = 1;
+
+	return input_fmts;
+}
+
+static int imx93_pdfc_bridge_atomic_check(struct drm_bridge *bridge,
+					  struct drm_bridge_state *bridge_state,
+					  struct drm_crtc_state *crtc_state,
+					  struct drm_connector_state *conn_state)
+{
+	struct imx93_pdfc *pdfc = bridge->driver_private;
+
+	switch (bridge_state->output_bus_cfg.format) {
+	case MEDIA_BUS_FMT_RGB888_1X24:
+	case MEDIA_BUS_FMT_RGB666_1X18:
+	case MEDIA_BUS_FMT_RGB565_1X16:
+		return 0;
+	default:
+		dev_warn(pdfc->dev, "Unsupported output bus format: 0x%x\n",
+			 bridge_state->output_bus_cfg.format);
+		return -EINVAL;
+	}
+}
+
+static const struct drm_bridge_funcs funcs = {
+	.attach			= imx93_pdfc_bridge_attach,
+	.atomic_enable		= imx93_pdfc_bridge_atomic_enable,
+	.atomic_duplicate_state	= drm_atomic_helper_bridge_duplicate_state,
+	.atomic_destroy_state	= drm_atomic_helper_bridge_destroy_state,
+	.atomic_get_input_bus_fmts	= imx93_pdfc_bridge_atomic_get_input_bus_fmts,
+	.atomic_check		= imx93_pdfc_bridge_atomic_check,
+	.atomic_reset		= drm_atomic_helper_bridge_reset,
+};
+
+static int imx93_pdfc_bridge_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct imx93_pdfc *pdfc;
+	struct device_node *ep;
+	int err;
+
+	pdfc = devm_drm_bridge_alloc(dev, struct imx93_pdfc, bridge, &funcs);
+	if (IS_ERR(pdfc))
+		return PTR_ERR(pdfc);
+
+	pdfc->regmap = syscon_node_to_regmap(dev->of_node->parent);
+	if (IS_ERR(pdfc->regmap))
+		return dev_err_probe(dev, PTR_ERR(pdfc->regmap),
+				     "failed to get regmap\n");
+
+	err = of_property_read_reg(dev->of_node, 0, &pdfc->disp_mux_reg_off, NULL);
+	if (err)
+		return dev_err_probe(dev, err,
+				     "failed to get display-mux reg\n");
+
+	/* No limits per default */
+	pdfc->phy_bus_width = 24;
+
+	/* Get output ep (port1/endpoint0) */
+	ep = of_graph_get_endpoint_by_regs(dev->of_node, 1, 0);
+	if (ep) {
+		err = of_property_read_u32(ep, "bus-width", &pdfc->phy_bus_width);
+		of_node_put(ep);
+
+		/* bus-width is optional but it must have valid data if present */
+		if (err && err != -EINVAL)
+			return dev_err_probe(dev, err,
+					     "failed to query bus-width\n");
+	}
+
+	pdfc->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
+	if (IS_ERR(pdfc->next_bridge))
+		return dev_err_probe(dev, PTR_ERR(pdfc->next_bridge),
+				     "failed to get next bridge\n");
+
+	pdfc->dev = dev;
+	pdfc->bridge.driver_private = pdfc;
+	pdfc->bridge.of_node = dev->of_node;
+	pdfc->bridge.type = DRM_MODE_CONNECTOR_DPI;
+
+	return devm_drm_bridge_add(dev, &pdfc->bridge);
+}
+
+static const struct of_device_id imx93_pdfc_dt_ids[] = {
+	{ .compatible = "nxp,imx93-pdfc", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx93_pdfc_dt_ids);
+
+static struct platform_driver imx93_pdfc_bridge_driver = {
+	.probe	= imx93_pdfc_bridge_probe,
+	.driver	= {
+		.of_match_table = imx93_pdfc_dt_ids,
+		.name = "imx93_pdfc",
+	},
+};
+module_platform_driver(imx93_pdfc_bridge_driver);
+
+MODULE_DESCRIPTION("NXP i.MX93 parallel display format configuration driver");
+MODULE_AUTHOR("Liu Ying <victor.liu at nxp.com>");
+MODULE_LICENSE("GPL");

-- 
2.47.3



From helgaas at kernel.org  Mon Dec  1 09:23:11 2025
From: helgaas at kernel.org (Bjorn Helgaas)
Date: Mon, 1 Dec 2025 11:23:11 -0600
Subject: linux-next: Tree for Nov 28
 (drivers/pci/controller/dwc/pcie-nxp-s32g.o)
In-Reply-To: <63e1daf7-f9a3-463e-8a1b-e9b72581c7af@infradead.org>
Message-ID: <20251201172311.GA3019571@bhelgaas>

On Sat, Nov 29, 2025 at 07:00:04PM -0800, Randy Dunlap wrote:
> On 11/27/25 9:29 PM, Stephen Rothwell wrote:
> > Hi all,
> > 
> > Changes since 20251127:
> > 
> 
> on i386 (allmodconfig):
> 
> WARNING: modpost: vmlinux: section mismatch in reference: s32g_init_pcie_controller+0x2b (section: .text) -> memblock_start_of_DRAM (section: .init.text)

Thanks, I'll drop the pci/controller/s32g branch until this is
resolved.


From alchark at gmail.com  Mon Dec  1 09:35:07 2025
From: alchark at gmail.com (Alexey Charkov)
Date: Mon, 1 Dec 2025 21:35:07 +0400
Subject: [PATCH] arm64: dts: rockchip: Add overlay for the PCIe slot on
 RK3576 EVB1
In-Reply-To: <20251201-evb1-pcie1-v1-1-c62bba5c1167@gmail.com>
References: <20251201-evb1-pcie1-v1-1-c62bba5c1167@gmail.com>
Message-ID: <CABjd4YxiOsw0_vR=igLhGkXUp4kSfx_eWv6j=FrsX-qo5sR2hw@mail.gmail.com>

On Mon, Dec 1, 2025 at 4:37?PM Alexey Charkov <alchark at gmail.com> wrote:
>
> Rockchip RK3576 EVB1 has an onboard PCIe slot (PCIe 2.1, x4 mechanically,
> x1 electrically), but it shares pins and PHY with the only USB3 Type-A
> port.
>
> There is a physical switch next to the slot to transfer respective pins
> connection from the USB3 port to the PCIe slot, but apart from flipping
> the switch one must also disable the USB3 host controller to prevent it
> from claiming the PHY before the PCIe slot can become usable.
>
> Add an overlay to disable the USB3 host port and instead enable the
> PCIe slot, along with its pin configs. The physical switch must still be
> flipped to the "ON - PCIe1" position for this to work.
>
> Signed-off-by: Alexey Charkov <alchark at gmail.com>
> ---
>  arch/arm64/boot/dts/rockchip/Makefile              |  4 +++
>  .../boot/dts/rockchip/rk3576-evb1-v10-pcie1.dtso   | 31 ++++++++++++++++++++++
>  2 files changed, 35 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
> index ad684e3831bc..63198a618a2b 100644
> --- a/arch/arm64/boot/dts/rockchip/Makefile
> +++ b/arch/arm64/boot/dts/rockchip/Makefile
> @@ -252,6 +252,10 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-armsom-sige5-v1.2-wifibt.dtb
>  rk3576-armsom-sige5-v1.2-wifibt-dtbs := rk3576-armsom-sige5.dtb \
>         rk3576-armsom-sige5-v1.2-wifibt.dtbo
>
> +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-evb1-v10-pcie1.dtb
> +rk3576-evb1-v10-pcie1-dtbs := rk3576-evb1-v10.dtb \
> +       rk3576-evb1-v10-pcie1.dtbo

Missed the separate .dtbo target. Will amend in v2. Should have
something like this further up in the Makefile:
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-evb1-v10-pcie1.dtbo

Best regards,
Alexey


From dianders at chromium.org  Mon Dec  1 09:42:40 2025
From: dianders at chromium.org (Doug Anderson)
Date: Mon, 1 Dec 2025 09:42:40 -0800
Subject: Proposal: Officially allow "incomplete" trees as a base
In-Reply-To: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
References: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
Message-ID: <CAD=FV=UbejKdD2q2Z3RuYH0Ooc6XRb0oynchDsqnq7GzM6ah0w@mail.gmail.com>

Hi,

On Tue, Nov 18, 2025 at 2:43?PM Doug Anderson <dianders at chromium.org> wrote:
>
> This is a continuation of the discussion that started in reply to my
> patch adding basic device trees for Pixel 10 phones [1].
>
>
> Problem statement:
> ------------------
>
> We would like an officially accepted scheme that lets us more
> efficiently ship compiled device trees for a handful of related
> products by breaking the device trees up into a common "base" device
> tree and then applying "overlay" device trees atop the base to make a
> full and complete device tree.
>
> To make it more concrete, we'd like to build a "base" device tree that
> describes a SoC and then have the overlays be enough to make a full
> description of a board. In theory, one could also imagine wanting to
> expand this to 3 or more levels (perhaps SoC, baseboard, derived
> boards), though this is not planned at this time.
>
> The primary reason for wanting to break device trees like this is
> efficiency of the shipped binary device trees. A large portion of a
> final device tree just describes the SoC. We save space in the final
> compiled device trees if they don't need to contain as much duplicated
> information.
>
> A secondary reason for wanting to break device trees like this is to
> more nicely handle when a board has a socketed SoC that can be
> replaced with a finite (and small) number of different SoCs (usually
> revisions of the same SoC). Even if this secondary reason is
> considered invalid or too difficult, the primary reason still
> describes a compelling need.
>
> In order to make this proposal work, it's expected that a bootloader
> will understand the scheme and will know how to combine the overlay
> atop the base before passing a complete device tree to the main OS.

It's been roughly two weeks since I sent out this proposal. Do DT
folks have any comments? Are the goals I have stated understood? Do
people agree that these goals are reasonable? Is there any question
that there is a need to solve these problems not just for Google, but
for the community as a whole? I'm happy to reach out to people and
have them reply "yes, I have this problem too" if it would somehow
help. I don't doubt that there are still people at Qualcomm who would
like a solution even if I think Elliot isn't driving it there
anymore...

How do we make forward progress? Does anyone have any comments on
Julius's reply? At the moment, I think there are some conflicts with
what Julius would like to see (no changes to the rules for how
overlays are applied) and what Rob said previously (we need to find
some way to combine the compatible strings). Did I misunderstand? Can
we find a common ground?

Thanks!

-Doug


From ulf.hansson at linaro.org  Mon Dec  1 09:51:25 2025
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Mon,  1 Dec 2025 18:51:25 +0100
Subject: [GIT PULL] pmdomain/cpuidle-psci updates for v6.19
Message-ID: <20251201175125.34284-1-ulf.hansson@linaro.org>

Hi Linus,

Here's the pull-request with pmdomain and cpuidle-psci updates for v6.19.
Details about the highlights are as usual found in the signed tag.

Please pull this in!

Kind regards
Ulf Hansson


The following changes since commit c98c99d5dbdf9fb0063650594edfd7d49b5f4e29:

  pmdomain: tegra: Add GENPD_FLAG_NO_STAY_ON flag (2025-11-24 11:14:01 +0100)

are available in the Git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm.git tags/pmdomain-v6.19

for you to fetch changes up to 1f67707fafa598e2338dba08e3de0db3e468afd1:

  pmdomain: Merge branch fixes into next (2025-11-24 11:14:36 +0100)

----------------------------------------------------------------
pmdomain core:
 - Allow power-off for out-of-band wakeup-capable devices
 - Drop the redundant call to dev_pm_domain_detach() for the amba bus
 - Extend the genpd governor for CPUs to account for IPIs

pmdomain providers:
 - bcm: Add support for BCM2712
 - mediatek: Add support for MFlexGraphics power domains
 - mediatek: Add support for MT8196 power domains
 - qcom: Add RPMh power domain support for Kaanapali
 - rockchip: Add support for RV1126B

pmdomain consumers:
 - usb: dwc3: Enable out of band wakeup for i.MX95
 - usb: chipidea: Enable out of band wakeup for i.MX95

----------------------------------------------------------------
AngeloGioacchino Del Regno (5):
      dt-bindings: power: Add support for MT8196 power controllers
      pmdomain: mediatek: Add support for Hardware Voter power domains
      pmdomain: mediatek: Add support for secure HWCCF infra power on
      pmdomain: mediatek: Add support for MT8196 SCPSYS power domains
      pmdomain: mediatek: Add support for MT8196 HFRPSYS power domains

Brian Masney (1):
      pmdomain: mediatek: convert from clk round_rate() to determine_rate()

Claudiu Beznea (1):
      amba: bus: Drop dev_pm_domain_detach() call

Finley Xiao (2):
      dt-bindings: power: rockchip: Add support for RV1126B
      pmdomain: rockchip: Add support for RV1126B

Jishnu Prakash (3):
      dt-bindings: power: qcom,rpmpd: document the Kaanapali RPMh Power Domains
      dt-bindings: power: qcom,rpmpd: add new RPMH levels
      pmdomain: qcom: rpmhpd: Add RPMh power domain support for Kaanapali

Nicolas Frattaroli (3):
      dt-bindings: power: Add MT8196 GPU frequency control binding
      pmdomain: mediatek: Add support for MFlexGraphics
      pmdomain: mediatek: mtk-mfg: select MAILBOX in Kconfig

Peng Fan (4):
      PM: wakeup: Add out-of-band system wakeup support for devices
      pmdomain: core: Allow power-off for out-of-band wakeup-capable devices
      usb: chipidea: ci_hdrc_imx: Set out of band wakeup for i.MX95
      usb: dwc3: imx8mp: Set out of band wakeup for i.MX95

Stanimir Varbanov (2):
      dt-bindings: soc: bcm: Add bcm2712 compatible
      pmdomain: bcm: bcm2835-power: Prepare to support BCM2712

Thorsten Blum (1):
      cpuidle: psci: Replace deprecated strcpy in psci_idle_init_cpu

Ulf Hansson (5):
      pmdomain: Merge branch dt into next
      pmdomain: mediatek: Fix build-errors
      smp: Introduce a helper function to check for pending IPIs
      pmdomain: Extend the genpd governor for CPUs to account for IPIs
      pmdomain: Merge branch fixes into next

Xu Yang (1):
      usb: chipidea: core: detach power domain for ci_hdrc platform device

 .../bindings/power/mediatek,mt8196-gpufreq.yaml    |  117 +++
 .../bindings/power/mediatek,power-controller.yaml  |    4 +
 .../devicetree/bindings/power/qcom,rpmpd.yaml      |    1 +
 .../bindings/power/rockchip,power-controller.yaml  |    2 +
 .../bindings/soc/bcm/brcm,bcm2835-pm.yaml          |   38 +-
 drivers/amba/bus.c                                 |    9 +-
 drivers/base/power/main.c                          |    1 +
 drivers/cpuidle/cpuidle-psci.c                     |    4 +-
 drivers/pmdomain/bcm/bcm2835-power.c               |   17 +-
 drivers/pmdomain/core.c                            |    6 +-
 drivers/pmdomain/governor.c                        |   20 +-
 drivers/pmdomain/mediatek/Kconfig                  |   17 +
 drivers/pmdomain/mediatek/Makefile                 |    1 +
 drivers/pmdomain/mediatek/mt8196-pm-domains.h      |  625 ++++++++++++
 drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c       | 1044 ++++++++++++++++++++
 drivers/pmdomain/mediatek/mtk-pm-domains.c         |  306 +++++-
 drivers/pmdomain/mediatek/mtk-pm-domains.h         |   49 +-
 drivers/pmdomain/qcom/rpmhpd.c                     |   28 +-
 drivers/pmdomain/rockchip/pm-domains.c             |   41 +
 drivers/usb/chipidea/ci_hdrc_imx.c                 |   11 +-
 drivers/usb/chipidea/core.c                        |    3 +
 drivers/usb/dwc3/dwc3-imx8mp.c                     |    9 +-
 include/dt-bindings/power/mediatek,mt8196-power.h  |   58 ++
 include/dt-bindings/power/qcom,rpmhpd.h            |    3 +
 .../power/rockchip,rv1126b-power-controller.h      |   17 +
 include/linux/pm.h                                 |    1 +
 include/linux/pm_wakeup.h                          |   17 +
 include/linux/smp.h                                |    5 +
 include/linux/usb/chipidea.h                       |    1 +
 kernel/smp.c                                       |   22 +
 30 files changed, 2417 insertions(+), 60 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/power/mediatek,mt8196-gpufreq.yaml
 create mode 100644 drivers/pmdomain/mediatek/mt8196-pm-domains.h
 create mode 100644 drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c
 create mode 100644 include/dt-bindings/power/mediatek,mt8196-power.h
 create mode 100644 include/dt-bindings/power/rockchip,rv1126b-power-controller.h


From Frank.li at nxp.com  Mon Dec  1 09:59:25 2025
From: Frank.li at nxp.com (Frank Li)
Date: Mon, 1 Dec 2025 12:59:25 -0500
Subject: [PATCH v2 2/3] media: rockchip: add driver for the rockchip mipi
 csi-2 receiver
In-Reply-To: <20251201033700.GB21943@pendragon.ideasonboard.com>
References: <20251114-rockchip-mipi-receiver-v2-0-eb9b43377fc4@collabora.com>
 <20251114-rockchip-mipi-receiver-v2-2-eb9b43377fc4@collabora.com>
 <aRyplYZOrGsSxSlp@lizhi-Precision-Tower-5810>
 <554971e1-6fde-4b2c-a2de-fe178358a4e3@collabora.com>
 <aRzub5Ak6DZpO5f/@lizhi-Precision-Tower-5810>
 <87049b4c-df7d-454b-a7f4-073975a7ee94@collabora.com>
 <20251201033700.GB21943@pendragon.ideasonboard.com>
Message-ID: <aS3XfZFF8rmt8ZT6@lizhi-Precision-Tower-5810>

On Mon, Dec 01, 2025 at 12:37:00PM +0900, Laurent Pinchart wrote:
> Hello,
>
> On Wed, Nov 26, 2025 at 09:57:31PM +0100, Michael Riesch wrote:
> > On 11/18/25 23:08, Frank Li wrote:
> > > On Tue, Nov 18, 2025 at 07:59:14PM +0100, Michael Riesch wrote:
> > >> On 11/18/25 18:15, Frank Li wrote:
> > >>> On Tue, Nov 18, 2025 at 12:12:26PM +0100, Michael Riesch via B4 Relay wrote:
> > >>>> From: Michael Riesch <michael.riesch at collabora.com>
> > >>>>
> > >>>> [...]
> > >>>> +#define CSI2HOST_N_LANES     0x04
> > >>>> +#define CSI2HOST_CSI2_RESETN 0x10
> > >>>> +#define CSI2HOST_PHY_STATE   0x14
> > >>>> +#define CSI2HOST_ERR1	     0x20
> > >>>> +#define CSI2HOST_ERR2	     0x24
> > >>>> +#define CSI2HOST_MSK1	     0x28
> > >>>> +#define CSI2HOST_MSK2	     0x2c
> > >>>> +#define CSI2HOST_CONTROL     0x40
> > >>>
> > >>> Look like that is designware CSI2 controller, can we build common library
> > >>> for all dwc csi2 controller, instead of every vendor create individual one.
> > >>>
> > >>> First try at
> > >>> https://lore.kernel.org/linux-media/20250821-95_cam-v3-21-c9286fbb34b9 at nxp.com/
> > >>>
> > >>> Toshiba have similar patch
> > >>> https://lore.kernel.org/linux-media/aPZd39riAxqfw3mT at lizhi-Precision-Tower-5810/
> > >>>
> > >>> Frank
> > >>
> > >> This has been discussed already a while ago:
> > >> https://lore.kernel.org/all/20250507083837.GA11152 at pendragon.ideasonboard.com/
> > >
> > > https://lore.kernel.org/all/20250702093806.GF16835 at pendragon.ideasonboard.com/
> > >
> > > Laurent Pinchart prevent imx93 DWC CSI2 driver at Jul, your discussion at
> > > May, I think Laurent Pinchart change the mind.
> > >
> > > We can choose not base on imx6, but we should create a standard dwc2 under
> > > drivers/media/platform/synopsys/
> >
> > In principle, I agree with refactoring out common code. However, I am
> > not sure how similar these IP cores really are. Again, the answer I
> > received from Rockchip states that this is *not* a Synopsys IP core.
>
> That's what I based my opinion on. If we're dealing with different IP
> cores from different vendors, we can have separate drivers. Even within
> the family of CSI-2 receivers from Synopsys, I'm fine having different
> drivers if the version differ significantly enough that using a single
> driver would cause more pain than gain.

Laurent Pinchart:

	We need use unified standard for every one. In the patch below patch
is enough show the difference between Sysnopsys version.

media: synopsys: csi2: Add basic v150* version register
https://lore.kernel.org/imx/20250821-95_cam-v3-20-c9286fbb34b9 at nxp.com/

	The register layout is differense, most field defination are the
same and some changed.

	I know it is hard to define how much pain and gain.

	But I think this one is closer to imx6's version even though they
claim NOT DWC CSI2 IP than imx93 v150 dwc CSI2 version. (for example, many
iio sensor/gpio expandor use the same set of register define for difference
vendor, but still use one driver for these).

https://lore.kernel.org/all/20250702093806.GF16835 at pendragon.ideasonboard.com/#t

"This seems to be at least the third instance of a driver for the CSI-2
receiver, the first two being
drivers/media/platform/raspberrypi/rp1-cfe/dphy.c and the second one
drivers/media/platform/renesas/rcar-csi2.c (the latter seems to support
multiple CSI-2 receivers). drivers/staging/media/imx/imx6-mipi-csi2.c
seem related too, likely for an old version of the IP.

Could we please try to avoid code duplication ?
"

	Or do you think I should go through this ways (direct create one
dwc for v150) instead base on imx6 one to enable imx93's dwc CSI2?

>
> To explain this differently, for Synopsys CSI-2 receivers, I would like
> to try and support multiple IP cores integrated in different SoCs in a
> single driver. If, during that development, we find good reasons to use
> separate drivers, then we can do so.

I think if reviewing and landing process could go through smooth, imx6 can
support this device with a little bit modify. There are not technology's
bar so far.

I split to more simple patches from big 32 patch serises.

https://lore.kernel.org/imx/20251111-stage-csi2-cleanup-v2-0-371bb951776f at nxp.com/

Only comments change

https://lore.kernel.org/linux-media/20251105195808.297645-1-Frank.Li at nxp.com/

Frank

>
> > Can you maybe test whether the Rockchip MIPI CSI-2 Receiver driver in
> > this series works on your hardware? Then we will know if (and what)
> > parts can be shared.
> >
> > > Laurent Pinchart:
> > >
> > > 	Can you provide direction?
> > >
> > >> Bottom line from Laurent:
> > >>
> > >> "Let's keep this driver Rockchip-specific then. Thanks for checking."
> > >>
> > >>>  [...]
>
> --
> Regards,
>
> Laurent Pinchart


From ptosi at google.com  Mon Dec  1 10:19:52 2025
From: ptosi at google.com (=?utf-8?q?Pierre-Cl=C3=A9ment_Tosi?=)
Date: Mon, 01 Dec 2025 18:19:52 +0000
Subject: [PATCH] KVM: arm64: Prevent FWD_TO_USER of SMCCC to pKVM
Message-ID: <20251201-smccc-filter-v1-1-b4831416f8a3@google.com>

With protected VMs, forwarding guest HVC/SMCs happens at two interfaces:

     pKVM [EL2] <--> KVM [EL1] <--> VMM [EL0]

so it might be possible for EL0 to successfully register with EL1 to
handle guest SMCCC calls but never see the KVM_EXIT_HYPERCALL, even if
the calls are properly issued by the guest, due to EL2 handling them so
that (host) EL1 never gets a chance to exit to EL0.

Instead, avoid that confusing situation and make userspace fail early by
disallowing KVM_ARM_VM_SMCCC_FILTER-ing calls from protected guests in
the KVM FID range (which pKVM re-uses).

DEN0028 defines 65536 "Vendor Specific Hypervisor Service Calls":

- the first ARM_SMCCC_KVM_NUM_FUNCS (128) can be custom-defined
- the following 3 are currently standardized
- the rest is "reserved for future expansion"

so reserve them all, like commit 821d935c87bc ("KVM: arm64: Introduce
support for userspace SMCCC filtering") with the Arm Architecture Calls.

Alternatively, we could have only reserved the ARM_SMCCC_KVM_NUM_FUNCS
(or even a subset of it) and the "Call UID Query" but that would have
risked future conflicts between that uAPI and an extension of the SMCCC
or of the pKVM ABI.

Signed-off-by: Pierre-Cl?ment Tosi <ptosi at google.com>
---
 Documentation/virt/kvm/devices/vm.rst | 11 ++++++++++
 arch/arm64/kvm/hypercalls.c           | 39 +++++++++++++++++++++++++++++++++++
 2 files changed, 50 insertions(+)

diff --git a/Documentation/virt/kvm/devices/vm.rst b/Documentation/virt/kvm/devices/vm.rst
index a4d39fa1b0834b090318250db3b670b0b3174259..9ed4b7afe022023346d4835d33a901e557fc4765 100644
--- a/Documentation/virt/kvm/devices/vm.rst
+++ b/Documentation/virt/kvm/devices/vm.rst
@@ -400,3 +400,14 @@ will reject attempts to define a filter for any portion of these ranges:
         0x8000_0000 0x8000_FFFF
         0xC000_0000 0xC000_FFFF
         =========== ===============
+
+Protected KVM (pKVM) reserves the 'Vendor Specific Hypervisor Service Calls'
+range of function IDs and will reject attempts to define a filter for any
+portion of these ranges for a protected VM (``KVM_VM_TYPE_ARM_PROTECTED``):
+
+        =========== ===============
+        Start       End (inclusive)
+        =========== ===============
+        0x8600_0000 0x8600_FFFF
+        0xC600_0000 0xC600_FFFF
+        =========== ===============
diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
index 58c5fe7d757274d9079606fcc378485980c6c0f8..5ddcdd70a6b280914048e7683dafb778d0f24658 100644
--- a/arch/arm64/kvm/hypercalls.c
+++ b/arch/arm64/kvm/hypercalls.c
@@ -135,6 +135,21 @@ static bool kvm_smccc_test_fw_bmap(struct kvm_vcpu *vcpu, u32 func_id)
 						   ARM_SMCCC_SMC_64,		\
 						   0, ARM_SMCCC_FUNC_MASK)
 
+#define SMC32_VHYP_RANGE_BEGIN	ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID
+#define SMC32_VHYP_RANGE_END	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,		\
+						   ARM_SMCCC_SMC_32,		\
+						   ARM_SMCCC_OWNER_VENDOR_HYP,	\
+						   ARM_SMCCC_FUNC_MASK)
+
+#define SMC64_VHYP_RANGE_BEGIN	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,		\
+						   ARM_SMCCC_SMC_64,		\
+						   ARM_SMCCC_OWNER_VENDOR_HYP,	\
+						   0)
+#define SMC64_VHYP_RANGE_END	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,		\
+						   ARM_SMCCC_SMC_64,		\
+						   ARM_SMCCC_OWNER_VENDOR_HYP,	\
+						   ARM_SMCCC_FUNC_MASK)
+
 static int kvm_smccc_filter_insert_reserved(struct kvm *kvm)
 {
 	int r;
@@ -158,6 +173,30 @@ static int kvm_smccc_filter_insert_reserved(struct kvm *kvm)
 	if (r)
 		goto out_destroy;
 
+	/*
+	 * Prevent userspace from registering to handle any SMCCC call in the
+	 * vendor hypervisor range for pVMs, avoiding the confusion of guest
+	 * calls seemingly not resulting in KVM_RUN exits because pKVM handles
+	 * them without ever returning to the host. This is NOT for security.
+	 */
+	if (kvm_vm_is_protected(kvm)) {
+		r = mtree_insert_range(&kvm->arch.smccc_filter,
+				       SMC32_VHYP_RANGE_BEGIN,
+				       SMC32_VHYP_RANGE_END,
+				       xa_mk_value(KVM_SMCCC_FILTER_HANDLE),
+				       GFP_KERNEL_ACCOUNT);
+		if (r)
+			goto out_destroy;
+
+		r = mtree_insert_range(&kvm->arch.smccc_filter,
+				       SMC64_VHYP_RANGE_BEGIN,
+				       SMC64_VHYP_RANGE_END,
+				       xa_mk_value(KVM_SMCCC_FILTER_HANDLE),
+				       GFP_KERNEL_ACCOUNT);
+		if (r)
+			goto out_destroy;
+	}
+
 	return 0;
 out_destroy:
 	mtree_destroy(&kvm->arch.smccc_filter);

---
base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
change-id: 20251201-smccc-filter-588ddf12b355

Best regards,
-- 
Pierre-Cl?ment Tosi <ptosi at google.com>



From ryan.roberts at arm.com  Mon Dec  1 10:20:24 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Mon, 1 Dec 2025 18:20:24 +0000
Subject: [RFC PATCH v1 2/2] randomize_kstack: Unify random source across
 arches
In-Reply-To: <CAMj1kXFY1RXk8T4f46bkm_sr0nJfBoO+ii68JK4+CsRiDwKdCg@mail.gmail.com>
References: <20251127105958.2427758-1-ryan.roberts@arm.com>
 <20251127105958.2427758-3-ryan.roberts@arm.com>
 <CAMj1kXFY1RXk8T4f46bkm_sr0nJfBoO+ii68JK4+CsRiDwKdCg@mail.gmail.com>
Message-ID: <9097505d-b18b-4f85-a02c-7f2865ad8bca@arm.com>

On 28/11/2025 11:01, Ard Biesheuvel wrote:
> On Thu, 27 Nov 2025 at 12:00, Ryan Roberts <ryan.roberts at arm.com> wrote:
>>
>> Previously different architectures were using random sources of
>> differing strength and cost to decide the random kstack offset. A number
>> of architectures (loongarch, powerpc, s390, x86) were using their
>> timestamp counter, at whatever the frequency happened to be. Other
>> arches (arm64, riscv) were using entropy from the crng via
>> get_random_u16().
>>
>> There have been concerns that in some cases the timestamp counters may
>> be too weak, because they can be easily guessed or influenced by user
>> space. And get_random_u16() has been shown to be too costly for the
>> level of protection kstack offset randomization provides.
>>
>> So let's use a common, architecture-agnostic source of entropy; a
>> per-task prng, seeded at fork-time from the crng. This has a few
>> benefits:
>>
>>   - We can remove choose_random_kstack_offset(); That was only there to
>>     try to make the timestamp counter value a bit harder to influence
>>     from user space.
>>
>>   - The architecture code is simplified. All it has to do now is call
>>     add_random_kstack_offset() in the syscall path.
>>
>>   - The strength of the randomness can be reasoned about independently
>>     of the architecture.
>>
>>   - Arches previously using get_random_u16() now have much faster
>>     syscall paths, see below results.
>>
>> There have been some claims that a prng may be less strong than the
>> timestamp counter if not regularly reseeded. But the prng has a period
>> of about 2^113. So as long as the prng state remains secret, it should
>> not be possible to guess. If the prng state can be accessed, we have
>> bigger problems.
>>
>> Additionally, we are only consuming 6 bits to randomize the stack, so
>> there are only 64 possible random offsets. I assert that it would be
>> trivial for an attacker to brute force by repeating their attack and
>> waiting for the random stack offset to be the desired one. The prng
>> approach seems entirely proportional to this level of protection.
>>
>> Performance data are provided below. The baseline is v6.18-rc5 with
>> rndstack on for each respective arch. (I)/(R) indicate statistically
>> significant improvement/regression. arm64 platform is AWS Graviton3.
>> x86_64 platform is AWS Sapphire Rapids:
>>
>> +-----------------+--------------+---------------+---------------+
>> | Benchmark       | Result Class | per-task-prng | per-task-prng |
>> |                 |              |         arm64 |        x86_64 |
>> +=================+==============+===============+===============+
>> | syscall/getpid  | mean (ns)    |   (I) -10.54% |    (I) -7.69% |
>> |                 | p99 (ns)     |   (I) -59.53% |         4.14% |
>> |                 | p99.9 (ns)   |   (I) -59.90% |         2.68% |
>> +-----------------+--------------+---------------+---------------+
>> | syscall/getppid | mean (ns)    |   (I) -10.49% |    (I) -5.98% |
>> |                 | p99 (ns)     |   (I) -59.83% |        -3.11% |
>> |                 | p99.9 (ns)   |   (I) -59.88% |     (R) 9.84% |
>> +-----------------+--------------+---------------+---------------+
>> | syscall/invalid | mean (ns)    |    (I) -9.28% |    (I) -6.94% |
>> |                 | p99 (ns)     |   (I) -61.06% |    (I) -5.57% |
>> |                 | p99.9 (ns)   |   (I) -61.40% |    (R) 10.53% |
>> +-----------------+--------------+---------------+---------------+
>>
>> Signed-off-by: Ryan Roberts <ryan.roberts at arm.com>
>> ---
>>  arch/Kconfig                         |  5 ++--
>>  arch/arm64/kernel/syscall.c          | 11 -------
>>  arch/loongarch/kernel/syscall.c      | 11 -------
>>  arch/powerpc/kernel/syscall.c        | 12 --------
>>  arch/riscv/kernel/traps.c            | 12 --------
>>  arch/s390/include/asm/entry-common.h |  8 ------
>>  arch/x86/include/asm/entry-common.h  | 12 --------
>>  include/linux/prandom.h              |  7 ++++-
>>  include/linux/randomize_kstack.h     | 43 ++++++++--------------------
>>  include/linux/sched.h                |  3 +-
>>  10 files changed, 22 insertions(+), 102 deletions(-)
>>
> 
> I think this is a substantial improvement over the status quo,
> especially with all the dodgy uses of monotonic counters with
> unspecified granularity.
> 
> So with two comments below:
> 
> Reviewed-by: Ard Biesheuvel <ardb at kernel.org>

Thanks!

I shall plan to re-post without the RFC tag against -rc1 then, and we will see
if anyone pushes back.

> 
>> diff --git a/arch/Kconfig b/arch/Kconfig
>> index 61130b88964b..b2c70c9dc098 100644
>> --- a/arch/Kconfig
>> +++ b/arch/Kconfig
>> @@ -1519,9 +1519,8 @@ config HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET
>>         def_bool n
>>         help
>>           An arch should select this symbol if it can support kernel stack
>> -         offset randomization with calls to add_random_kstack_offset()
>> -         during syscall entry and choose_random_kstack_offset() during
>> -         syscall exit. Careful removal of -fstack-protector-strong and
>> +         offset randomization with a call to add_random_kstack_offset()
>> +         during syscall entry. Careful removal of -fstack-protector-strong and
>>           -fstack-protector should also be applied to the entry code and
>>           closely examined, as the artificial stack bump looks like an array
>>           to the compiler, so it will attempt to add canary checks regardless
>> diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
>> index aba7ca6bca2d..957c4ccd5d14 100644
>> --- a/arch/arm64/kernel/syscall.c
>> +++ b/arch/arm64/kernel/syscall.c
>> @@ -52,17 +52,6 @@ static void invoke_syscall(struct pt_regs *regs, unsigned int scno,
>>         }
>>
>>         syscall_set_return_value(current, regs, 0, ret);
>> -
>> -       /*
>> -        * This value will get limited by KSTACK_OFFSET_MAX(), which is 10
>> -        * bits. The actual entropy will be further reduced by the compiler
>> -        * when applying stack alignment constraints: the AAPCS mandates a
>> -        * 16-byte aligned SP at function boundaries, which will remove the
>> -        * 4 low bits from any entropy chosen here.
>> -        *
>> -        * The resulting 6 bits of entropy is seen in SP[9:4].
>> -        */
>> -       choose_random_kstack_offset(get_random_u16());
>>  }
>>
>>  static inline bool has_syscall_work(unsigned long flags)
>> diff --git a/arch/loongarch/kernel/syscall.c b/arch/loongarch/kernel/syscall.c
>> index 168bd97540f8..80544a5ec6e1 100644
>> --- a/arch/loongarch/kernel/syscall.c
>> +++ b/arch/loongarch/kernel/syscall.c
>> @@ -66,16 +66,5 @@ void noinstr __no_stack_protector do_syscall(struct pt_regs *regs)
>>                                            regs->regs[7], regs->regs[8], regs->regs[9]);
>>         }
>>
>> -       /*
>> -        * This value will get limited by KSTACK_OFFSET_MAX(), which is 10
>> -        * bits. The actual entropy will be further reduced by the compiler
>> -        * when applying stack alignment constraints: 16-bytes (i.e. 4-bits)
>> -        * aligned, which will remove the 4 low bits from any entropy chosen
>> -        * here.
>> -        *
>> -        * The resulting 6 bits of entropy is seen in SP[9:4].
>> -        */
>> -       choose_random_kstack_offset(drdtime());
>> -
>>         syscall_exit_to_user_mode(regs);
>>  }
>> diff --git a/arch/powerpc/kernel/syscall.c b/arch/powerpc/kernel/syscall.c
>> index be159ad4b77b..b3d8b0f9823b 100644
>> --- a/arch/powerpc/kernel/syscall.c
>> +++ b/arch/powerpc/kernel/syscall.c
>> @@ -173,17 +173,5 @@ notrace long system_call_exception(struct pt_regs *regs, unsigned long r0)
>>         }
>>  #endif
>>
>> -       /*
>> -        * Ultimately, this value will get limited by KSTACK_OFFSET_MAX(),
>> -        * so the maximum stack offset is 1k bytes (10 bits).
>> -        *
>> -        * The actual entropy will be further reduced by the compiler when
>> -        * applying stack alignment constraints: the powerpc architecture
>> -        * may have two kinds of stack alignment (16-bytes and 8-bytes).
>> -        *
>> -        * So the resulting 6 or 7 bits of entropy is seen in SP[9:4] or SP[9:3].
>> -        */
>> -       choose_random_kstack_offset(mftb());
>> -
>>         return ret;
>>  }
>> diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c
>> index 80230de167de..79b285bdfd1a 100644
>> --- a/arch/riscv/kernel/traps.c
>> +++ b/arch/riscv/kernel/traps.c
>> @@ -342,18 +342,6 @@ void do_trap_ecall_u(struct pt_regs *regs)
>>                 if (syscall >= 0 && syscall < NR_syscalls)
>>                         syscall_handler(regs, syscall);
>>
>> -               /*
>> -                * Ultimately, this value will get limited by KSTACK_OFFSET_MAX(),
>> -                * so the maximum stack offset is 1k bytes (10 bits).
>> -                *
>> -                * The actual entropy will be further reduced by the compiler when
>> -                * applying stack alignment constraints: 16-byte (i.e. 4-bit) aligned
>> -                * for RV32I or RV64I.
>> -                *
>> -                * The resulting 6 bits of entropy is seen in SP[9:4].
>> -                */
>> -               choose_random_kstack_offset(get_random_u16());
>> -
>>                 syscall_exit_to_user_mode(regs);
>>         } else {
>>                 irqentry_state_t state = irqentry_nmi_enter(regs);
>> diff --git a/arch/s390/include/asm/entry-common.h b/arch/s390/include/asm/entry-common.h
>> index 979af986a8fe..35450a485323 100644
>> --- a/arch/s390/include/asm/entry-common.h
>> +++ b/arch/s390/include/asm/entry-common.h
>> @@ -51,14 +51,6 @@ static __always_inline void arch_exit_to_user_mode(void)
>>
>>  #define arch_exit_to_user_mode arch_exit_to_user_mode
>>
>> -static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs,
>> -                                                 unsigned long ti_work)
>> -{
>> -       choose_random_kstack_offset(get_tod_clock_fast());
>> -}
>> -
>> -#define arch_exit_to_user_mode_prepare arch_exit_to_user_mode_prepare
>> -
>>  static __always_inline bool arch_in_rcu_eqs(void)
>>  {
>>         if (IS_ENABLED(CONFIG_KVM))
>> diff --git a/arch/x86/include/asm/entry-common.h b/arch/x86/include/asm/entry-common.h
>> index ce3eb6d5fdf9..7535131c711b 100644
>> --- a/arch/x86/include/asm/entry-common.h
>> +++ b/arch/x86/include/asm/entry-common.h
>> @@ -82,18 +82,6 @@ static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs,
>>         current_thread_info()->status &= ~(TS_COMPAT | TS_I386_REGS_POKED);
>>  #endif
>>
>> -       /*
>> -        * This value will get limited by KSTACK_OFFSET_MAX(), which is 10
>> -        * bits. The actual entropy will be further reduced by the compiler
>> -        * when applying stack alignment constraints (see cc_stack_align4/8 in
>> -        * arch/x86/Makefile), which will remove the 3 (x86_64) or 2 (ia32)
>> -        * low bits from any entropy chosen here.
>> -        *
>> -        * Therefore, final stack offset entropy will be 7 (x86_64) or
>> -        * 8 (ia32) bits.
>> -        */
>> -       choose_random_kstack_offset(rdtsc());
>> -
>>         /* Avoid unnecessary reads of 'x86_ibpb_exit_to_user' */
>>         if (cpu_feature_enabled(X86_FEATURE_IBPB_EXIT_TO_USER) &&
>>             this_cpu_read(x86_ibpb_exit_to_user)) {
>> diff --git a/include/linux/prandom.h b/include/linux/prandom.h
>> index f2ed5b72b3d6..827edde11cb9 100644
>> --- a/include/linux/prandom.h
>> +++ b/include/linux/prandom.h
>> @@ -10,13 +10,18 @@
>>
>>  #include <linux/types.h>
>>  #include <linux/once.h>
>> -#include <linux/percpu.h>
>>  #include <linux/random.h>
>>
>>  struct rnd_state {
>>         __u32 s1, s2, s3, s4;
>>  };
>>
>> +/*
>> + * percpu.h includes sched.h, which requires struct rnd_state. So defer until
>> + * after struct rnd_state is defined.
>> + */
>> +#include <linux/percpu.h>
>> +
> 
> Yuck. Is this the best we can do to disentangle this?

I think I might be able to remove some stuff out of sched.h into alloc_tag.h
(looks to me like it should have been there all along). And that will allow
removing the sched.h include from percpu.h. I think that will solve it.


> 
>>  u32 prandom_u32_state(struct rnd_state *state);
>>  void prandom_bytes_state(struct rnd_state *state, void *buf, size_t nbytes);
>>  void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state);
>> diff --git a/include/linux/randomize_kstack.h b/include/linux/randomize_kstack.h
>> index 089b1432f7e6..83c7e6710f6d 100644
>> --- a/include/linux/randomize_kstack.h
>> +++ b/include/linux/randomize_kstack.h
>> @@ -6,6 +6,7 @@
>>  #include <linux/kernel.h>
>>  #include <linux/jump_label.h>
>>  #include <linux/percpu-defs.h>
>> +#include <linux/prandom.h>
>>
>>  DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
>>                          randomize_kstack_offset);
>> @@ -45,9 +46,13 @@ DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
>>  #define KSTACK_OFFSET_MAX(x)   ((x) & 0b1111111100)
>>  #endif
>>
>> +static __always_inline u32 get_update_kstack_offset(void)
>> +{
>> +       return prandom_u32_state(&current->kstack_rnd_state);

I've got bot warnings because this is being called from noinstr code. I guess
the best option is to just move add_random_kstack_offset() to after
instrumentation is enabled for the affected arches.

>> +}
>> +
>>  /**
>> - * add_random_kstack_offset - Increase stack utilization by previously
>> - *                           chosen random offset
>> + * add_random_kstack_offset - Increase stack utilization by a random offset.
>>   *
>>   * This should be used in the syscall entry path after user registers have been
>>   * stored to the stack. Preemption may be enabled. For testing the resulting
>> @@ -56,46 +61,22 @@ DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
>>  #define add_random_kstack_offset() do {                                        \
>>         if (static_branch_maybe(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT, \
>>                                 &randomize_kstack_offset)) {            \
>> -               u32 offset = current->kstack_offset;                    \
>> +               u32 offset = get_update_kstack_offset();                \
>>                 u8 *ptr = __kstack_alloca(KSTACK_OFFSET_MAX(offset));   \
>>                 /* Keep allocation even after "ptr" loses scope. */     \
>>                 asm volatile("" :: "r"(ptr) : "memory");                \
>>         }                                                               \
>>  } while (0)
>>
>> -/**
>> - * choose_random_kstack_offset - Choose the random offset for the next
>> - *                              add_random_kstack_offset()
>> - *
>> - * This should only be used during syscall exit. Preemption may be enabled. This
>> - * position in the syscall flow is done to frustrate attacks from userspace
>> - * attempting to learn the next offset:
>> - * - Maximize the timing uncertainty visible from userspace: if the
>> - *   offset is chosen at syscall entry, userspace has much more control
>> - *   over the timing between choosing offsets. "How long will we be in
>> - *   kernel mode?" tends to be more difficult to predict than "how long
>> - *   will we be in user mode?"
>> - * - Reduce the lifetime of the new offset sitting in memory during
>> - *   kernel mode execution. Exposure of "thread-local" memory content
>> - *   (e.g. current, percpu, etc) tends to be easier than arbitrary
>> - *   location memory exposure.
>> - */
>> -#define choose_random_kstack_offset(rand) do {                         \
>> -       if (static_branch_maybe(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT, \
>> -                               &randomize_kstack_offset)) {            \
>> -               u32 offset = current->kstack_offset;                    \
>> -               offset = ror32(offset, 5) ^ (rand);                     \
>> -               current->kstack_offset = offset;                        \
>> -       }                                                               \
>> -} while (0)
>> -
>>  static inline void random_kstack_task_init(struct task_struct *tsk)
>>  {
>> -       current->kstack_offset = 0;
>> +       if (static_branch_maybe(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
>> +                               &randomize_kstack_offset)) {
>> +               prandom_seed_state(&tsk->kstack_rnd_state, get_random_u64());
> 
> We should either fix prandom_seed_state() not to truncate the u64 to
> u32, or even better, refactor prandom_seed_full_state() so we can
> reuse it here, and use a 128-bit seed directly.

How about something like this:


---8<---
diff --git a/include/linux/prandom.h b/include/linux/prandom.h
index f2ed5b72b3d6..9b651c9b3448 100644
--- a/include/linux/prandom.h
+++ b/include/linux/prandom.h
@@ -19,10 +19,11 @@ struct rnd_state {

 u32 prandom_u32_state(struct rnd_state *state);
 void prandom_bytes_state(struct rnd_state *state, void *buf, size_t nbytes);
-void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state);
+void prandom_seed_full_state_one(struct rnd_state *state);
+void prandom_seed_full_state_all(struct rnd_state __percpu *pcpu_state);

 #define prandom_init_once(pcpu_state)			\
-	DO_ONCE(prandom_seed_full_state, (pcpu_state))
+	DO_ONCE(prandom_seed_full_state_all, (pcpu_state))

 /*
  * Handle minimum values for seeds
diff --git a/lib/random32.c b/lib/random32.c
index 24e7acd9343f..50d8f5f9fca7 100644
--- a/lib/random32.c
+++ b/lib/random32.c
@@ -107,24 +107,28 @@ static void prandom_warmup(struct rnd_state *state)
 	prandom_u32_state(state);
 }

-void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state)
+void prandom_seed_full_state_one(struct rnd_state *state)
 {
-	int i;
+	u32 seeds[4];

-	for_each_possible_cpu(i) {
-		struct rnd_state *state = per_cpu_ptr(pcpu_state, i);
-		u32 seeds[4];
+	get_random_bytes(&seeds, sizeof(seeds));
+	state->s1 = __seed(seeds[0],   2U);
+	state->s2 = __seed(seeds[1],   8U);
+	state->s3 = __seed(seeds[2],  16U);
+	state->s4 = __seed(seeds[3], 128U);

-		get_random_bytes(&seeds, sizeof(seeds));
-		state->s1 = __seed(seeds[0],   2U);
-		state->s2 = __seed(seeds[1],   8U);
-		state->s3 = __seed(seeds[2],  16U);
-		state->s4 = __seed(seeds[3], 128U);
+	prandom_warmup(state);
+}
+EXPORT_SYMBOL(prandom_seed_full_state_one);

-		prandom_warmup(state);
-	}
+void prandom_seed_full_state_all(struct rnd_state __percpu *pcpu_state)
+{
+	int i;
+
+	for_each_possible_cpu(i)
+		prandom_seed_full_state_one(per_cpu_ptr(pcpu_state, i));
 }
-EXPORT_SYMBOL(prandom_seed_full_state);
+EXPORT_SYMBOL(prandom_seed_full_state_all);

 #ifdef CONFIG_RANDOM32_SELFTEST
 static struct prandom_test1 {
---8<---


> 
>> +       }
>>  }
>>  #else /* CONFIG_RANDOMIZE_KSTACK_OFFSET */
>>  #define add_random_kstack_offset()             do { } while (0)
>> -#define choose_random_kstack_offset(rand)      do { } while (0)
>>  #define random_kstack_task_init(tsk)           do { } while (0)
>>  #endif /* CONFIG_RANDOMIZE_KSTACK_OFFSET */
>>
>> diff --git a/include/linux/sched.h b/include/linux/sched.h
>> index dae227d217ef..ac0402c2b988 100644
>> --- a/include/linux/sched.h
>> +++ b/include/linux/sched.h
>> @@ -34,6 +34,7 @@
>>  #include <linux/sched/prio.h>
>>  #include <linux/sched/types.h>
>>  #include <linux/signal_types.h>
>> +#include <linux/prandom.h>
>>  #include <linux/spinlock.h>
>>  #include <linux/syscall_user_dispatch_types.h>
>>  #include <linux/mm_types_task.h>
>> @@ -1614,7 +1615,7 @@ struct task_struct {
>>  #endif
>>
>>  #ifdef CONFIG_RANDOMIZE_KSTACK_OFFSET
>> -       u32                             kstack_offset;
>> +       struct rnd_state                kstack_rnd_state;
>>  #endif
>>
>>  #ifdef CONFIG_X86_MCE
>> --
>> 2.43.0
>>
>>



From ptosi at google.com  Mon Dec  1 10:21:09 2025
From: ptosi at google.com (=?utf-8?q?Pierre-Cl=C3=A9ment_Tosi?=)
Date: Mon, 01 Dec 2025 18:21:09 +0000
Subject: [PATCH] KVM: arm64: Use ARM_SMCCC_OWNER_ARCH in place of 0
Message-ID: <20251201-arm-smccc-owner-arch-v1-1-71f7d75f97a4@google.com>

Trivial change to use the appropriate self-documenting macro.

Signed-off-by: Pierre-Cl?ment Tosi <ptosi at google.com>
---
 arch/arm64/kvm/hypercalls.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
index 58c5fe7d757274d9079606fcc378485980c6c0f8..3e7fdbcc6411f658f5cec818bfad2e97711d37a7 100644
--- a/arch/arm64/kvm/hypercalls.c
+++ b/arch/arm64/kvm/hypercalls.c
@@ -126,14 +126,17 @@ static bool kvm_smccc_test_fw_bmap(struct kvm_vcpu *vcpu, u32 func_id)
 #define SMC32_ARCH_RANGE_BEGIN	ARM_SMCCC_VERSION_FUNC_ID
 #define SMC32_ARCH_RANGE_END	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,		\
 						   ARM_SMCCC_SMC_32,		\
-						   0, ARM_SMCCC_FUNC_MASK)
+						   ARM_SMCCC_OWNER_ARCH,	\
+						   ARM_SMCCC_FUNC_MASK)
 
 #define SMC64_ARCH_RANGE_BEGIN	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,		\
 						   ARM_SMCCC_SMC_64,		\
-						   0, 0)
+						   ARM_SMCCC_OWNER_ARCH,	\
+						   0)
 #define SMC64_ARCH_RANGE_END	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,		\
 						   ARM_SMCCC_SMC_64,		\
-						   0, ARM_SMCCC_FUNC_MASK)
+						   ARM_SMCCC_OWNER_ARCH,	\
+						   ARM_SMCCC_FUNC_MASK)
 
 static int kvm_smccc_filter_insert_reserved(struct kvm *kvm)
 {

---
base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
change-id: 20251201-arm-smccc-owner-arch-cdf29f22a06f

Best regards,
-- 
Pierre-Cl?ment Tosi <ptosi at google.com>



From linux at armlinux.org.uk  Mon Dec  1 10:28:44 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 1 Dec 2025 18:28:44 +0000
Subject: Proposal: Officially allow "incomplete" trees as a base
In-Reply-To: <CAD=FV=UbejKdD2q2Z3RuYH0Ooc6XRb0oynchDsqnq7GzM6ah0w@mail.gmail.com>
References: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
 <CAD=FV=UbejKdD2q2Z3RuYH0Ooc6XRb0oynchDsqnq7GzM6ah0w@mail.gmail.com>
Message-ID: <aS3eXBDtaoNLfxZy@shell.armlinux.org.uk>

On Mon, Dec 01, 2025 at 09:42:40AM -0800, Doug Anderson wrote:
> Hi,
> 
> On Tue, Nov 18, 2025 at 2:43?PM Doug Anderson <dianders at chromium.org> wrote:
> >
> > This is a continuation of the discussion that started in reply to my
> > patch adding basic device trees for Pixel 10 phones [1].
> >
> >
> > Problem statement:
> > ------------------
> >
> > We would like an officially accepted scheme that lets us more
> > efficiently ship compiled device trees for a handful of related
> > products by breaking the device trees up into a common "base" device
> > tree and then applying "overlay" device trees atop the base to make a
> > full and complete device tree.
> >
> > To make it more concrete, we'd like to build a "base" device tree that
> > describes a SoC and then have the overlays be enough to make a full
> > description of a board. In theory, one could also imagine wanting to
> > expand this to 3 or more levels (perhaps SoC, baseboard, derived
> > boards), though this is not planned at this time.
> >
> > The primary reason for wanting to break device trees like this is
> > efficiency of the shipped binary device trees. A large portion of a
> > final device tree just describes the SoC. We save space in the final
> > compiled device trees if they don't need to contain as much duplicated
> > information.
> >
> > A secondary reason for wanting to break device trees like this is to
> > more nicely handle when a board has a socketed SoC that can be
> > replaced with a finite (and small) number of different SoCs (usually
> > revisions of the same SoC). Even if this secondary reason is
> > considered invalid or too difficult, the primary reason still
> > describes a compelling need.
> >
> > In order to make this proposal work, it's expected that a bootloader
> > will understand the scheme and will know how to combine the overlay
> > atop the base before passing a complete device tree to the main OS.
> 
> It's been roughly two weeks since I sent out this proposal. Do DT
> folks have any comments? Are the goals I have stated understood? Do
> people agree that these goals are reasonable? Is there any question
> that there is a need to solve these problems not just for Google, but
> for the community as a whole? I'm happy to reach out to people and
> have them reply "yes, I have this problem too" if it would somehow
> help. I don't doubt that there are still people at Qualcomm who would
> like a solution even if I think Elliot isn't driving it there
> anymore...
> 
> How do we make forward progress? Does anyone have any comments on
> Julius's reply? At the moment, I think there are some conflicts with
> what Julius would like to see (no changes to the rules for how
> overlays are applied) and what Rob said previously (we need to find
> some way to combine the compatible strings). Did I misunderstand? Can
> we find a common ground?

My feeling on this (and I don't have much time to consider it tonight)
is that this isn't going to get a quick answer.

This answer is based on my authorship of various device trees, and is
solely my own opinion, and in no way represents any position by my
employer.

While the DT files are dual-licensed, the license that applies to the
copy in the kernel is GPL v2, because the kernel as a whole is GPL v2
licensed. The dual-licensing of the DT files is to permit them to be
taken from the kernel and used in e.g. boot loaders etc.

However, as the license that applies to the kernel copy is GPL v2, and
GPL v2 requires distribution in source code form, or an offer valid
for two years of the corresponding source code etc (check the GPL v2
for the exact terms) it could be inappropriate for the kernel tree
to distribute binary DT blobs without their corresponding source.

It seems to me that this is a problem for lawyers, and you're probably
not going to get a quick answer on it.

So, I'd suggest patience, and don't expect this topic to move quickly.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From kuba at kernel.org  Mon Dec  1 10:35:29 2025
From: kuba at kernel.org (Jakub Kicinski)
Date: Mon, 1 Dec 2025 10:35:29 -0800
Subject: [PATCH] wifi: mt7601u: check multiple firmware paths
In-Reply-To: <20251201090336.1157193-1-christianshewitt@gmail.com>
References: <20251201090336.1157193-1-christianshewitt@gmail.com>
Message-ID: <20251201103529.1874a869@kernel.org>

On Mon,  1 Dec 2025 09:03:36 +0000 Christian Hewitt wrote:
> The linux-firmware repo moved mt7601u.bin from the root folder to
> the mediatek sub-folder some time ago, but not all distros create
> symlinks to the old location the driver checks. Update the driver
> to check for firmware in both old and new locations.

IDK.. 2.5 years ago.. how long is too long to wait for the distros 
to update their linux-firmware?


From maz at kernel.org  Mon Dec  1 10:48:48 2025
From: maz at kernel.org (Marc Zyngier)
Date: Mon, 01 Dec 2025 18:48:48 +0000
Subject: [PATCH] KVM: arm64: Prevent FWD_TO_USER of SMCCC to pKVM
In-Reply-To: <20251201-smccc-filter-v1-1-b4831416f8a3@google.com>
References: <20251201-smccc-filter-v1-1-b4831416f8a3@google.com>
Message-ID: <86ms42ox67.wl-maz@kernel.org>

On Mon, 01 Dec 2025 18:19:52 +0000,
"=?utf-8?q?Pierre-Cl=C3=A9ment_Tosi?=" <ptosi at google.com> wrote:
> 
> With protected VMs, forwarding guest HVC/SMCs happens at two interfaces:
> 
>      pKVM [EL2] <--> KVM [EL1] <--> VMM [EL0]
> 
> so it might be possible for EL0 to successfully register with EL1 to
> handle guest SMCCC calls but never see the KVM_EXIT_HYPERCALL, even if
> the calls are properly issued by the guest, due to EL2 handling them so
> that (host) EL1 never gets a chance to exit to EL0.
> 
> Instead, avoid that confusing situation and make userspace fail early by
> disallowing KVM_ARM_VM_SMCCC_FILTER-ing calls from protected guests in
> the KVM FID range (which pKVM re-uses).
> 
> DEN0028 defines 65536 "Vendor Specific Hypervisor Service Calls":
> 
> - the first ARM_SMCCC_KVM_NUM_FUNCS (128) can be custom-defined
> - the following 3 are currently standardized
> - the rest is "reserved for future expansion"
> 
> so reserve them all, like commit 821d935c87bc ("KVM: arm64: Introduce
> support for userspace SMCCC filtering") with the Arm Architecture Calls.

I don't think preventing all hypercalls from reaching userspace is
acceptable from an API perspective. For example, it is highly expected
that the hypercall that exposes the various MIDR/REVIDR/AIDR that the
guest can be expected to run on is handled in userspace.

Given that this hypercall is critical to the correct behaviour of a
guest in an asymmetric system, you can't really forbid it. If you
don't want it, that's fine -- don't implement it in your VMM.

But I fully expect pKVM to inherit the existing APIs by virtue of
being a KVM backend.

> Alternatively, we could have only reserved the ARM_SMCCC_KVM_NUM_FUNCS
> (or even a subset of it) and the "Call UID Query" but that would have
> risked future conflicts between that uAPI and an extension of the SMCCC
> or of the pKVM ABI.

I disagree. The only ones you can legitimately block are the ones that
are earmarked for pKVM itself (2-63), and only these. Everything else
should make it to userspace if the guest and the VMM agree to do so.

This is part of the KVM ABI, and pKVM should be fixed.

Thanks,

	M.

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


From kuba at kernel.org  Mon Dec  1 11:03:58 2025
From: kuba at kernel.org (Jakub Kicinski)
Date: Mon, 1 Dec 2025 11:03:58 -0800
Subject: [PATCH net-next 5/9] phy: add phy_get_rx_polarity() and
 phy_get_tx_polarity()
In-Reply-To: <aS1T5i3pCHsNVql6@vaman>
References: <20251122193341.332324-1-vladimir.oltean@nxp.com>
	<20251122193341.332324-6-vladimir.oltean@nxp.com>
	<20251124200121.5b82f09e@kernel.org>
	<aS1T5i3pCHsNVql6@vaman>
Message-ID: <20251201110358.7618fee2@kernel.org>

On Mon, 1 Dec 2025 14:07:58 +0530 Vinod Koul wrote:
> > > Push the supported mask of polarities to these helpers, to simplify
> > > drivers such that they don't need to validate what's in the device tree
> > > (or other firmware description).
> > > 
> > > The proposed maintainership model is joint custody between netdev and
> > > linux-phy, because of the fact that these properties can be applied to
> > > Ethernet PCS blocks just as well as Generic PHY devices. I've added as
> > > maintainers those from "ETHERNET PHY LIBRARY", "NETWORKING DRIVERS" and
> > > "GENERIC PHY FRAMEWORK".  
> > 
> > I dunno.. ain't no such thing as "joint custody" maintainership.
> > We have to pick one tree. Given the set of Ms here, I suspect 
> > the best course of action may be to bubble this up to its own tree.
> > Ask Konstantin for a tree in k.org, then you can "co-post" the patches
> > for review + PR link in the cover letter (e.g. how Tony from Intel
> > submits their patches). This way not networking and PHY can pull
> > the shared changes with stable commit IDs.  
> 
> How much is the volume of the changes that we are talking about, we can
> always ack and pull into each other trees..?

We have such ad-hoc situations with multiple subsystems. Letting
Vladimir and co create their own tree is basically shifting the 
work of managing the stable branches from netdev maintainers
downstream. I'd strongly prefer that we lean on git in this way, 
rather than reenact the 3 spiderman meme multiple times in each
release.


From ptosi at google.com  Mon Dec  1 11:58:13 2025
From: ptosi at google.com (=?utf-8?Q?Pierre-Cl=C3=A9ment?= Tosi)
Date: Mon, 1 Dec 2025 19:58:13 +0000
Subject: [PATCH] KVM: arm64: Prevent FWD_TO_USER of SMCCC to pKVM
In-Reply-To: <86ms42ox67.wl-maz@kernel.org>
References: <20251201-smccc-filter-v1-1-b4831416f8a3@google.com>
 <86ms42ox67.wl-maz@kernel.org>
Message-ID: <oim4q3obyy7jh2juw2qngl4xti6hjg6pavfnm3u3fppa4ao6dq@x7sanj32ttsi>

Hi Marc,

Thanks for your quick review!

On Mon, Dec 01, 2025 at 06:48:48PM +0000, Marc Zyngier wrote:
> On Mon, 01 Dec 2025 18:19:52 +0000,
> "=?utf-8?q?Pierre-Cl=C3=A9ment_Tosi?=" <ptosi at google.com> wrote:
> > 
> > With protected VMs, forwarding guest HVC/SMCs happens at two interfaces:
> > 
> >      pKVM [EL2] <--> KVM [EL1] <--> VMM [EL0]
> > 
> > so it might be possible for EL0 to successfully register with EL1 to
> > handle guest SMCCC calls but never see the KVM_EXIT_HYPERCALL, even if
> > the calls are properly issued by the guest, due to EL2 handling them so
> > that (host) EL1 never gets a chance to exit to EL0.
> > 
> > Instead, avoid that confusing situation and make userspace fail early by
> > disallowing KVM_ARM_VM_SMCCC_FILTER-ing calls from protected guests in
> > the KVM FID range (which pKVM re-uses).
> > 
> > DEN0028 defines 65536 "Vendor Specific Hypervisor Service Calls":
> > 
> > - the first ARM_SMCCC_KVM_NUM_FUNCS (128) can be custom-defined
> > - the following 3 are currently standardized
> > - the rest is "reserved for future expansion"
> > 
> > so reserve them all, like commit 821d935c87bc ("KVM: arm64: Introduce
> > support for userspace SMCCC filtering") with the Arm Architecture Calls.
> 
> I don't think preventing all hypercalls from reaching userspace is
> acceptable from an API perspective. For example, it is highly expected
> that the hypercall that exposes the various MIDR/REVIDR/AIDR that the
> guest can be expected to run on is handled in userspace.
> 
> Given that this hypercall is critical to the correct behaviour of a
> guest in an asymmetric system, you can't really forbid it. If you
> don't want it, that's fine -- don't implement it in your VMM.
> 
> But I fully expect pKVM to inherit the existing APIs by virtue of
> being a KVM backend.
> 
> > Alternatively, we could have only reserved the ARM_SMCCC_KVM_NUM_FUNCS
> > (or even a subset of it) and the "Call UID Query" but that would have
> > risked future conflicts between that uAPI and an extension of the SMCCC
> > or of the pKVM ABI.
> 
> I disagree. The only ones you can legitimately block are the ones that
> are earmarked for pKVM itself (2-63), and only these. Everything else
> should make it to userspace if the guest and the VMM agree to do so.

Sounds good, I'll limit v2 to these FIDs and the "Call UID Query" (unavoidable).

> 
> This is part of the KVM ABI, and pKVM should be fixed.

I agree. In particular on not restricting {S,G}ET_ONE_REG to a point where the
KVM uAPI for SMCCC filtering can't be supported, as some experimental Linux
forks might [1] have done! I couldn't find the corresponding patches on LKML to
contribute this feedback to, so something to keep in mind when they come in :)

[1]: https://r.android.com/q/I1c7bc93ebe0bfb597cca5c4284ceb7fd53e4713c

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

Thanks!

-- 
Pierre


From rui.wang at ideasonboard.com  Mon Dec  1 12:50:54 2025
From: rui.wang at ideasonboard.com (Rui Wang)
Date: Mon,  1 Dec 2025 15:50:54 -0500
Subject: No subject
Message-ID: <20251201205309.528858-1-rui.wang@ideasonboard.com>

Hi,

This series contains a single patch that fixes an issue in the rkisp1
filter mode configuration logic.

The rkisp1_flt_config() function performs a direct write to the
FILT_MODE register before the read/modify/write update. This write
does not include the RKISP1_CIF_ISP_FLT_ENA bit, which clears the
enable bit in hardware. After that, the read/modify/write sequence
cannot restore the original enable state, causing the filter to be
disabled unintentionally.

The patch removes the redundant direct write. The remaining
read/modify/write sequence correctly updates the mode fields while
preserving the existing enable bit.

Please review.

Thanks,
Rui Wang



From rui.wang at ideasonboard.com  Mon Dec  1 12:50:55 2025
From: rui.wang at ideasonboard.com (Rui Wang)
Date: Mon,  1 Dec 2025 15:50:55 -0500
Subject: [PATCH v3] media: rkisp1: Fix filter mode register configuration
In-Reply-To: <20251201205309.528858-1-rui.wang@ideasonboard.com>
References: <20251201205309.528858-1-rui.wang@ideasonboard.com>
Message-ID: <20251201205309.528858-2-rui.wang@ideasonboard.com>

The rkisp1_flt_config() function performs an initial direct write to
RKISP1_CIF_ISP_FILT_MODE without including the RKISP1_CIF_ISP_FLT_ENA
bit, which clears the filter enable bit in the hardware.

The subsequent read/modify/write sequence then reads back the register
with the enable bit already cleared and cannot restore it, resulting in
the filter being inadvertently disabled.

Remove the redundant direct write. The read/modify/write sequence alone
correctly preserves the existing enable bit state while updating the
DNR mode and filter configuration bits.

Signed-off-by: Rui Wang <rui.wang at ideasonboard.com>
---
 drivers/media/platform/rockchip/rkisp1/rkisp1-params.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
index c9f88635224c..6442436a5e42 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
@@ -411,12 +411,6 @@ static void rkisp1_flt_config(struct rkisp1_params *params,
 	rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_LUM_WEIGHT,
 		     arg->lum_weight);
 
-	rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_MODE,
-		     (arg->mode ? RKISP1_CIF_ISP_FLT_MODE_DNR : 0) |
-		     RKISP1_CIF_ISP_FLT_CHROMA_V_MODE(arg->chr_v_mode) |
-		     RKISP1_CIF_ISP_FLT_CHROMA_H_MODE(arg->chr_h_mode) |
-		     RKISP1_CIF_ISP_FLT_GREEN_STAGE1(arg->grn_stage1));
-
 	/* avoid to override the old enable value */
 	filt_mode = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_FILT_MODE);
 	filt_mode &= RKISP1_CIF_ISP_FLT_ENA;
-- 
2.43.0



From dianders at chromium.org  Mon Dec  1 12:58:57 2025
From: dianders at chromium.org (Doug Anderson)
Date: Mon, 1 Dec 2025 12:58:57 -0800
Subject: Proposal: Officially allow "incomplete" trees as a base
In-Reply-To: <aS3eXBDtaoNLfxZy@shell.armlinux.org.uk>
References: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
 <CAD=FV=UbejKdD2q2Z3RuYH0Ooc6XRb0oynchDsqnq7GzM6ah0w@mail.gmail.com> <aS3eXBDtaoNLfxZy@shell.armlinux.org.uk>
Message-ID: <CAD=FV=WBbqSDghm+o2ZVa4-AbL4aggFQO0xdtmZNrYOQRjF5Vw@mail.gmail.com>

Hi,

On Mon, Dec 1, 2025 at 10:28?AM Russell King (Oracle)
<linux at armlinux.org.uk> wrote:
>
> On Mon, Dec 01, 2025 at 09:42:40AM -0800, Doug Anderson wrote:
> > Hi,
> >
> > On Tue, Nov 18, 2025 at 2:43?PM Doug Anderson <dianders at chromium.org> wrote:
> > >
> > > This is a continuation of the discussion that started in reply to my
> > > patch adding basic device trees for Pixel 10 phones [1].
> > >
> > >
> > > Problem statement:
> > > ------------------
> > >
> > > We would like an officially accepted scheme that lets us more
> > > efficiently ship compiled device trees for a handful of related
> > > products by breaking the device trees up into a common "base" device
> > > tree and then applying "overlay" device trees atop the base to make a
> > > full and complete device tree.
> > >
> > > To make it more concrete, we'd like to build a "base" device tree that
> > > describes a SoC and then have the overlays be enough to make a full
> > > description of a board. In theory, one could also imagine wanting to
> > > expand this to 3 or more levels (perhaps SoC, baseboard, derived
> > > boards), though this is not planned at this time.
> > >
> > > The primary reason for wanting to break device trees like this is
> > > efficiency of the shipped binary device trees. A large portion of a
> > > final device tree just describes the SoC. We save space in the final
> > > compiled device trees if they don't need to contain as much duplicated
> > > information.
> > >
> > > A secondary reason for wanting to break device trees like this is to
> > > more nicely handle when a board has a socketed SoC that can be
> > > replaced with a finite (and small) number of different SoCs (usually
> > > revisions of the same SoC). Even if this secondary reason is
> > > considered invalid or too difficult, the primary reason still
> > > describes a compelling need.
> > >
> > > In order to make this proposal work, it's expected that a bootloader
> > > will understand the scheme and will know how to combine the overlay
> > > atop the base before passing a complete device tree to the main OS.
> >
> > It's been roughly two weeks since I sent out this proposal. Do DT
> > folks have any comments? Are the goals I have stated understood? Do
> > people agree that these goals are reasonable? Is there any question
> > that there is a need to solve these problems not just for Google, but
> > for the community as a whole? I'm happy to reach out to people and
> > have them reply "yes, I have this problem too" if it would somehow
> > help. I don't doubt that there are still people at Qualcomm who would
> > like a solution even if I think Elliot isn't driving it there
> > anymore...
> >
> > How do we make forward progress? Does anyone have any comments on
> > Julius's reply? At the moment, I think there are some conflicts with
> > what Julius would like to see (no changes to the rules for how
> > overlays are applied) and what Rob said previously (we need to find
> > some way to combine the compatible strings). Did I misunderstand? Can
> > we find a common ground?
>
> My feeling on this (and I don't have much time to consider it tonight)
> is that this isn't going to get a quick answer.
>
> This answer is based on my authorship of various device trees, and is
> solely my own opinion, and in no way represents any position by my
> employer.
>
> While the DT files are dual-licensed, the license that applies to the
> copy in the kernel is GPL v2, because the kernel as a whole is GPL v2
> licensed. The dual-licensing of the DT files is to permit them to be
> taken from the kernel and used in e.g. boot loaders etc.
>
> However, as the license that applies to the kernel copy is GPL v2, and
> GPL v2 requires distribution in source code form, or an offer valid
> for two years of the corresponding source code etc (check the GPL v2
> for the exact terms) it could be inappropriate for the kernel tree
> to distribute binary DT blobs without their corresponding source.
>
> It seems to me that this is a problem for lawyers, and you're probably
> not going to get a quick answer on it.
>
> So, I'd suggest patience, and don't expect this topic to move quickly.

It seems like perhaps I wasn't clear enough in my description of the
problem I'm trying to solve. I'm not trying to change anything about
the licensing or where the device tree source is stored / distributed.
This is all about packaging. As you can see further in the original
patch series I pointed at [1] that I include both the base and the
overlay source code [2]. I just want to organize things such that
SoC-related nodes and properties are in the base device tree (whether
"dts" or "dtb") and then we use an overlay ("dtso" or "dtbo") to end
up with a combined device tree that represents a complete board.

Today, there are no technical reasons stopping people from doing this
and many phones (including Google Pixel phones) ship their device
trees like this.

That being said, we can't land device trees like this upstream because
the base device tree for the SoC is not "complete" and can't pass yaml
validation.

According to Krzysztof, this is simply policy. As he says: "SoC does
not meet this criteria, therefore it is not suitable for DTS" [3]

If I read his response properly, Rob wasn't dead-set on this being
against policy. He said "I think it is worth having the discussion"
[4]. He was concerned that the final compatible string needed to be a
combination of the base and the overlay.

My goal is to find a solution where upstream would accept device trees
that are split into a base for the SoC and an overlay to "complete"
the board..

There are no legal questions here. I don't even believe that there is
any true technical complexity, really. There are a few small
differences in the way we can slice a solution and how we do it will
certainly have impacts, but I don't believe that some magic solution
is going to come up and make everyone happy (someone should feel free
to prove me wrong, though!). This means we have to either decide this
isn't a problem worth solving or we have to pick some compromise about
how this works. At this point, I'm fine with any answer (even a
definitive statement that this isn't a problem that upstream wants to
solve). I'm not terribly happy with just ignoring it for another year
or three.

[1] https://lore.kernel.org/r/20251111112158.1.I72a0b72562b85d02fee424fed939fea9049ddda9 at changeid
[2] https://lore.kernel.org/r/20251111112158.4.I5032910018cdd7d6be7aea78870d04c0dc381d6e at changeid/
[3] https://lore.kernel.org/all/20251114-elite-refined-yak-bf9e64 at kuoka/
[4] https://lore.kernel.org/all/20251113022719.GA2281498-robh at kernel.org/

-Doug


From ptosi at google.com  Mon Dec  1 13:26:42 2025
From: ptosi at google.com (=?utf-8?q?Pierre-Cl=C3=A9ment_Tosi?=)
Date: Mon, 01 Dec 2025 21:26:42 +0000
Subject: [PATCH v2] KVM: arm64: Prevent FWD_TO_USER of SMCCC to pKVM
Message-ID: <20251201-smccc-filter-v2-1-03dab737a14d@google.com>

With protected VMs, forwarding guest HVC/SMCs happens at two interfaces:

     pKVM [EL2] <--> KVM [EL1] <--> VMM [EL0]

so it might be possible for EL0 to successfully register with EL1 to
handle guest SMCCC calls but never see the KVM_EXIT_HYPERCALL, even if
the calls are properly issued by the guest, due to EL2 handling them so
that (host) EL1 never gets a chance to exit to EL0.

Instead, avoid that confusing situation and make userspace fail early by
disallowing KVM_ARM_VM_SMCCC_FILTER-ing calls from protected guests in
the pKVM FID range.

Similarly, reserve the "Call UID Query" to ensure that a malicious host
can't mislead a protected guest into misusing the pKVM ABI, under the
premise that it would be interacting with a different hypervisor ABI, as
hypervisors share the same FID space.

Signed-off-by: Pierre-Cl?ment Tosi <ptosi at google.com>
---
Changes in v2:
- Restricted the range to pKVM HVCs & the "Call UID Query"
- Updated docs & removed mention of KVM_VM_TYPE_ARM_PROTECTED
- Link to v1: https://lore.kernel.org/r/20251201-smccc-filter-v1-1-b4831416f8a3 at google.com
---
 Documentation/virt/kvm/devices/vm.rst | 10 ++++++++++
 arch/arm64/kvm/hypercalls.c           | 29 +++++++++++++++++++++++++++++
 2 files changed, 39 insertions(+)

diff --git a/Documentation/virt/kvm/devices/vm.rst b/Documentation/virt/kvm/devices/vm.rst
index a4d39fa1b0834b090318250db3b670b0b3174259..28ab2629e7e8f166def6f9efd18e8408ab4a8e63 100644
--- a/Documentation/virt/kvm/devices/vm.rst
+++ b/Documentation/virt/kvm/devices/vm.rst
@@ -400,3 +400,13 @@ will reject attempts to define a filter for any portion of these ranges:
         0x8000_0000 0x8000_FFFF
         0xC000_0000 0xC000_FFFF
         =========== ===============
+
+Protected KVM (pKVM) handles some calls directly and will reject attempts to
+define a filter for a protected VM for any portion of these ranges:
+
+        =========== ===============
+        Start       End (inclusive)
+        =========== ===============
+        0x8600_FF01 0x8600_FF01
+        0xC600_0002 0xC600_003F
+        =========== ===============
diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
index 58c5fe7d757274d9079606fcc378485980c6c0f8..5329772f228d356322863a7150ffa40c25ea1ee2 100644
--- a/arch/arm64/kvm/hypercalls.c
+++ b/arch/arm64/kvm/hypercalls.c
@@ -135,6 +135,12 @@ static bool kvm_smccc_test_fw_bmap(struct kvm_vcpu *vcpu, u32 func_id)
 						   ARM_SMCCC_SMC_64,		\
 						   0, ARM_SMCCC_FUNC_MASK)
 
+#define SMC64_PKVM_RANGE_BEGIN	ARM_SMCCC_VENDOR_HYP_KVM_HYP_MEMINFO_FUNC_ID
+#define SMC64_PKVM_RANGE_END	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,		\
+						   ARM_SMCCC_SMC_64,		\
+						   ARM_SMCCC_OWNER_VENDOR_HYP,	\
+						   ARM_SMCCC_KVM_FUNC_PKVM_RESV_63)
+
 static int kvm_smccc_filter_insert_reserved(struct kvm *kvm)
 {
 	int r;
@@ -158,6 +164,29 @@ static int kvm_smccc_filter_insert_reserved(struct kvm *kvm)
 	if (r)
 		goto out_destroy;
 
+	/*
+	 * Prevent userspace from registering to handle any SMCCC call in the
+	 * vendor hypervisor range for pVMs, avoiding the confusion of guest
+	 * calls seemingly not resulting in KVM_RUN exits because pKVM handles
+	 * them without ever returning to the host. This is NOT for security.
+	 */
+	if (kvm_vm_is_protected(kvm)) {
+		r = mtree_insert(&kvm->arch.smccc_filter,
+				ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID,
+				xa_mk_value(KVM_SMCCC_FILTER_HANDLE),
+				GFP_KERNEL_ACCOUNT);
+		if (r)
+			goto out_destroy;
+
+		r = mtree_insert_range(&kvm->arch.smccc_filter,
+				       SMC64_PKVM_RANGE_BEGIN,
+				       SMC64_PKVM_RANGE_END,
+				       xa_mk_value(KVM_SMCCC_FILTER_HANDLE),
+				       GFP_KERNEL_ACCOUNT);
+		if (r)
+			goto out_destroy;
+	}
+
 	return 0;
 out_destroy:
 	mtree_destroy(&kvm->arch.smccc_filter);

---
base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
change-id: 20251201-smccc-filter-588ddf12b355

Best regards,
-- 
Pierre-Cl?ment Tosi <ptosi at google.com>



From krzk at kernel.org  Mon Dec  1 13:46:01 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 1 Dec 2025 22:46:01 +0100
Subject: [PATCH 05/21] ARM: dts: omap: Bind panel to panel-dpi instead of
 ti,tilcdc,panel driver
In-Reply-To: <96b1b7bf-ddbe-4213-a201-dc89cf2998dd@ideasonboard.com>
References: <20251126-feature_tilcdc-v1-0-49b9ef2e3aa0@bootlin.com>
 <20251126-feature_tilcdc-v1-5-49b9ef2e3aa0@bootlin.com>
 <96b1b7bf-ddbe-4213-a201-dc89cf2998dd@ideasonboard.com>
Message-ID: <3bc5bf92-05c3-4841-ab28-9bab2bb31cd5@kernel.org>

On 01/12/2025 15:13, Tomi Valkeinen wrote:
> Hi Kory,
> 
> On 26/11/2025 19:35, Kory Maincent (TI.com) wrote:
>> Use panel-dpi driver instead of the deprecated tilcdc-panel driver in
>> preparation for removing the tilcdc-panel driver and binding.
>>
>> Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
>> ---
>>
>> This patch is not tested. It would be nice if someone with one of this
>> board could test and validate it.
>> ---
>>  arch/arm/boot/dts/ti/davinci/da850-evm.dts    | 26 +++++++++++++-------------
>>  arch/arm/boot/dts/ti/omap/am335x-guardian.dts | 25 +++++++++----------------
>>  arch/arm/boot/dts/ti/omap/am335x-pdu001.dts   | 21 ++++++++++-----------
>>  arch/arm/boot/dts/ti/omap/am335x-pepper.dts   | 22 +++++++++++-----------
>>  arch/arm/boot/dts/ti/omap/am335x-sbc-t335.dts | 25 +++++++++++++------------
>>  arch/arm/boot/dts/ti/omap/am335x-sl50.dts     | 25 ++++++++++++-------------
>>  6 files changed, 68 insertions(+), 76 deletions(-)
>>
> 
> Doesn't this, or rather the following patches, break DTB compatibility
> with all the above boards?

Stuffing DTS change in the middle of the driver change tries to hide
impact, which is not nice on its own.

Please follow soc maintainer profile and submitting patches in DT
regarding DTS patches.

Best regards,
Krzysztof


From kuba at kernel.org  Mon Dec  1 14:16:38 2025
From: kuba at kernel.org (Jakub Kicinski)
Date: Mon, 1 Dec 2025 14:16:38 -0800
Subject: [PATCH net-next v8 2/3] net: ti: icssm-prueth: Add switchdev
 support for icssm_prueth driver
In-Reply-To: <20251126163056.2697668-3-parvathi@couthit.com>
References: <20251126163056.2697668-1-parvathi@couthit.com>
	<20251126163056.2697668-3-parvathi@couthit.com>
Message-ID: <20251201141638.00a986dd@kernel.org>

On Wed, 26 Nov 2025 21:57:13 +0530 Parvathi Pudi wrote:
> + */
> +static void icssm_prueth_sw_switchdev_event_work(struct work_struct *work)
> +{
> +	struct icssm_prueth_sw_switchdev_event_work *switchdev_work =
> +		container_of(work,
> +			     struct icssm_prueth_sw_switchdev_event_work, work);

Consider using shorter type names.

> +	struct prueth_emac *emac = switchdev_work->emac;
> +	struct switchdev_notifier_fdb_info *fdb;
> +	struct prueth *prueth = emac->prueth;
> +	int port = emac->port_id;
> +
> +	rtnl_lock();
> +
> +	/* Interface is not up */
> +	if (!emac->prueth->fdb_tbl) {
> +		rtnl_unlock();

Are you not leaking the device reference here?

> +		return;
> +	}
> +
> +	switch (switchdev_work->event) {
> +	case SWITCHDEV_FDB_ADD_TO_DEVICE:
> +		fdb = &switchdev_work->fdb_info;
> +		dev_dbg(prueth->dev,
> +			"prueth fdb add: MACID = %pM vid = %u flags = %u -- port %d\n",
> +			fdb->addr, fdb->vid, fdb->added_by_user, port);
> +
> +		if (!fdb->added_by_user)
> +			break;
> +
> +		if (fdb->is_local)
> +			break;
> +
> +		icssm_prueth_sw_fdb_add(emac, fdb);
> +		icssm_prueth_sw_fdb_offload_notify(emac->ndev, fdb);
> +		break;
> +	case SWITCHDEV_FDB_DEL_TO_DEVICE:
> +		fdb = &switchdev_work->fdb_info;
> +		dev_dbg(prueth->dev,
> +			"prueth fdb del: MACID = %pM vid = %u flags = %u -- port %d\n",
> +			fdb->addr, fdb->vid, fdb->added_by_user, port);
> +
> +		if (fdb->is_local)
> +			break;
> +
> +		icssm_prueth_sw_fdb_del(emac, fdb);
> +		break;
> +	default:
> +		break;
> +	}
> +	rtnl_unlock();
> +
> +	netdev_put(emac->ndev, &switchdev_work->ndev_tracker);
> +	kfree(switchdev_work->fdb_info.addr);
> +	kfree(switchdev_work);
-- 
pw-bot: cr


From kuba at kernel.org  Mon Dec  1 14:18:58 2025
From: kuba at kernel.org (Jakub Kicinski)
Date: Mon, 1 Dec 2025 14:18:58 -0800
Subject: [PATCH net-next v8 1/3] net: ti: icssm-prueth: Add helper
 functions to configure and maintain FDB
In-Reply-To: <20251126163056.2697668-2-parvathi@couthit.com>
References: <20251126163056.2697668-1-parvathi@couthit.com>
	<20251126163056.2697668-2-parvathi@couthit.com>
Message-ID: <20251201141858.399fff62@kernel.org>

On Wed, 26 Nov 2025 21:57:12 +0530 Parvathi Pudi wrote:
> +	u8 hash_val, mac_tbl_idx;

Using narrow types is generally quite counter productive.
It can easily mask out-of-range accesses and subtle errors,
given that max is outside of the range of the u8 type:

+#define FDB_INDEX_TBL_MAX_ENTRIES     256
+#define FDB_MAC_TBL_MAX_ENTRIES       256

You should consider changing all the local variables to unsigned int.


From Frank.li at nxp.com  Mon Dec  1 14:29:36 2025
From: Frank.li at nxp.com (Frank Li)
Date: Mon, 1 Dec 2025 17:29:36 -0500
Subject: [PATCH 1/4] net: stmmac: s32: use the syscon interface
 PHY_INTF_SEL_RGMII
In-Reply-To: <6275e666a7ef78bd4c758d3f7f6fb6f30407393e.1764592300.git.dan.carpenter@linaro.org>
References: <cover.1764592300.git.dan.carpenter@linaro.org>
 <6275e666a7ef78bd4c758d3f7f6fb6f30407393e.1764592300.git.dan.carpenter@linaro.org>
Message-ID: <aS4W0M+ZkQzuUjtT@lizhi-Precision-Tower-5810>

On Mon, Dec 01, 2025 at 04:08:20PM +0300, Dan Carpenter wrote:
> On the s32 chipset the GMAC_0_CTRL_STS register is in GPR region.
> Originally, accessing this register was done in a sort of ad-hoc way,
> but we want to use the syscon interface to do it.

What's benefit by use syscon interface here? syscon have not much
well consided funcitonal abstraction.

Frank

>
> This is a little bit uglier because we to maintain backwards compatibility
> to the old device trees so we have to support both ways to access this
> register.
>
> Signed-off-by: Dan Carpenter <dan.carpenter at linaro.org>
> ---
>  .../net/ethernet/stmicro/stmmac/dwmac-s32.c   | 23 +++++++++++++++----
>  1 file changed, 18 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c
> index 5a485ee98fa7..20de761b7d28 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c
> @@ -11,12 +11,14 @@
>  #include <linux/device.h>
>  #include <linux/ethtool.h>
>  #include <linux/io.h>
> +#include <linux/mfd/syscon.h>
>  #include <linux/module.h>
>  #include <linux/of_mdio.h>
>  #include <linux/of_address.h>
>  #include <linux/phy.h>
>  #include <linux/phylink.h>
>  #include <linux/platform_device.h>
> +#include <linux/regmap.h>
>  #include <linux/stmmac.h>
>
>  #include "stmmac_platform.h"
> @@ -32,6 +34,8 @@
>  struct s32_priv_data {
>  	void __iomem *ioaddr;
>  	void __iomem *ctrl_sts;
> +	struct regmap *sts_regmap;
> +	unsigned int sts_offset;
>  	struct device *dev;
>  	phy_interface_t *intf_mode;
>  	struct clk *tx_clk;
> @@ -40,7 +44,10 @@ struct s32_priv_data {
>
>  static int s32_gmac_write_phy_intf_select(struct s32_priv_data *gmac)
>  {
> -	writel(S32_PHY_INTF_SEL_RGMII, gmac->ctrl_sts);
> +	if (gmac->ctrl_sts)
> +		writel(S32_PHY_INTF_SEL_RGMII, gmac->ctrl_sts);
> +	else
> +		regmap_write(gmac->sts_regmap, gmac->sts_offset, PHY_INTF_SEL_RGMII);
>
>  	dev_dbg(gmac->dev, "PHY mode set to %s\n", phy_modes(*gmac->intf_mode));
>
> @@ -125,10 +132,16 @@ static int s32_dwmac_probe(struct platform_device *pdev)
>  				     "dt configuration failed\n");
>
>  	/* PHY interface mode control reg */
> -	gmac->ctrl_sts = devm_platform_get_and_ioremap_resource(pdev, 1, NULL);
> -	if (IS_ERR(gmac->ctrl_sts))
> -		return dev_err_probe(dev, PTR_ERR(gmac->ctrl_sts),
> -				     "S32CC config region is missing\n");
> +	gmac->sts_regmap = syscon_regmap_lookup_by_phandle_args(dev->of_node,
> +					"phy-sel", 1, &gmac->sts_offset);
> +	if (gmac->sts_regmap == ERR_PTR(-EPROBE_DEFER))
> +		return PTR_ERR(gmac->sts_regmap);
> +	if (IS_ERR(gmac->sts_regmap)) {
> +		gmac->ctrl_sts = devm_platform_get_and_ioremap_resource(pdev, 1, NULL);
> +		if (IS_ERR(gmac->ctrl_sts))
> +			return dev_err_probe(dev, PTR_ERR(gmac->ctrl_sts),
> +					     "S32CC config region is missing\n");
> +	}
>
>  	/* tx clock */
>  	gmac->tx_clk = devm_clk_get(&pdev->dev, "tx");
> --
> 2.51.0
>


From Frank.li at nxp.com  Mon Dec  1 14:37:01 2025
From: Frank.li at nxp.com (Frank Li)
Date: Mon, 1 Dec 2025 17:37:01 -0500
Subject: [PATCH 1/3] pmdomain: imx93-blk-ctrl: cleanup error path
In-Reply-To: <20251201-v6-18-topic-imx93-blkctrl-v1-1-b57a72e60105@pengutronix.de>
References: <20251201-v6-18-topic-imx93-blkctrl-v1-0-b57a72e60105@pengutronix.de>
 <20251201-v6-18-topic-imx93-blkctrl-v1-1-b57a72e60105@pengutronix.de>
Message-ID: <aS4YjQOpvkQSkC6j@lizhi-Precision-Tower-5810>

On Mon, Dec 01, 2025 at 06:12:05PM +0100, Marco Felsch wrote:
> Call dev_err_probe() directly during return to make the code more
> compact.
>
> Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
> ---
Reviewed-by: Frank Li <Frank.Li at nxp.com>

>  drivers/pmdomain/imx/imx93-blk-ctrl.c | 6 ++----
>  1 file changed, 2 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/pmdomain/imx/imx93-blk-ctrl.c b/drivers/pmdomain/imx/imx93-blk-ctrl.c
> index e094fe5a42bf646c712f3eca4e66a313fa5a914c..2aa163aef8de4ee901b9cde76ce2aad246c8c08a 100644
> --- a/drivers/pmdomain/imx/imx93-blk-ctrl.c
> +++ b/drivers/pmdomain/imx/imx93-blk-ctrl.c
> @@ -240,10 +240,8 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
>  	bc->num_clks = bc_data->num_clks;
>
>  	ret = devm_clk_bulk_get(dev, bc->num_clks, bc->clks);
> -	if (ret) {
> -		dev_err_probe(dev, ret, "failed to get bus clock\n");
> -		return ret;
> -	}
> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to get bus clock\n");
>
>  	for (i = 0; i < bc_data->num_domains; i++) {
>  		const struct imx93_blk_ctrl_domain_data *data = &bc_data->domains[i];
>
> --
> 2.47.3
>


From Frank.li at nxp.com  Mon Dec  1 14:41:43 2025
From: Frank.li at nxp.com (Frank Li)
Date: Mon, 1 Dec 2025 17:41:43 -0500
Subject: [PATCH 2/3] pmdomain: imx93-blk-ctrl: convert to devm_* only
In-Reply-To: <20251201-v6-18-topic-imx93-blkctrl-v1-2-b57a72e60105@pengutronix.de>
References: <20251201-v6-18-topic-imx93-blkctrl-v1-0-b57a72e60105@pengutronix.de>
 <20251201-v6-18-topic-imx93-blkctrl-v1-2-b57a72e60105@pengutronix.de>
Message-ID: <aS4ZpyhrJ1IpUCKv@lizhi-Precision-Tower-5810>

On Mon, Dec 01, 2025 at 06:12:06PM +0100, Marco Felsch wrote:
> Some APIs used by this driver don't have devm_ helpers yet. Instead of
> using the devm_add_action_or_reset() the current driver is based on hand
> crafted error goto paths and a .remove() callback.
>
> Convert the driver to devm_ APIs only by making use of
> devm_add_action_or_reset() and devm_pm_runtime_enable() to simplify the
> release and error path.

Nit: I think keep this paragaph should be enough.

>
> Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
> ---
>  drivers/pmdomain/imx/imx93-blk-ctrl.c | 64 +++++++++++++++--------------------
>  1 file changed, 27 insertions(+), 37 deletions(-)
>
> diff --git a/drivers/pmdomain/imx/imx93-blk-ctrl.c b/drivers/pmdomain/imx/imx93-blk-ctrl.c
> index 2aa163aef8de4ee901b9cde76ce2aad246c8c08a..13b0de6dd689cf944e034f7666a4e97b0118e3bd 100644
> --- a/drivers/pmdomain/imx/imx93-blk-ctrl.c
> +++ b/drivers/pmdomain/imx/imx93-blk-ctrl.c
> @@ -188,6 +188,20 @@ static int imx93_blk_ctrl_power_off(struct generic_pm_domain *genpd)
>  	return 0;
>  }
>
...
>  static struct lock_class_key blk_ctrl_genpd_lock_class;
>
>  static int imx93_blk_ctrl_probe(struct platform_device *pdev)
> @@ -256,10 +270,8 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
>  			domain->clks[j].id = data->clk_names[j];
>
>  		ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks);
> -		if (ret) {
> -			dev_err_probe(dev, ret, "failed to get clock\n");
> -			goto cleanup_pds;
> -		}
> +		if (ret)
> +			return dev_err_probe(dev, ret, "failed to get clock\n");
>
>  		domain->genpd.name = data->name;
>  		domain->genpd.power_on = imx93_blk_ctrl_power_on;
> @@ -267,11 +279,12 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
>  		domain->bc = bc;
>
>  		ret = pm_genpd_init(&domain->genpd, NULL, true);
> -		if (ret) {
> -			dev_err_probe(dev, ret, "failed to init power domain\n");
> -			goto cleanup_pds;
> -		}
> +		if (ret)
> +			return dev_err_probe(dev, ret, "failed to init power domain\n");
>
> +		ret = devm_add_action_or_reset(dev, imx93_release_pm_genpd, &domain->genpd);
> +		if (ret)
> +			return dev_err_probe(dev, ret, "failed to add pm_genpd release callback\n");
>  		/*
>  		 * We use runtime PM to trigger power on/off of the upstream GPC
>  		 * domain, as a strict hierarchical parent/child power domain
> @@ -288,39 +301,17 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
>  		bc->onecell_data.domains[i] = &domain->genpd;
>  	}
>
> -	pm_runtime_enable(dev);
> +	devm_pm_runtime_enable(dev);

Need check return value

>
>  	ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data);
> -	if (ret) {
> -		dev_err_probe(dev, ret, "failed to add power domain provider\n");
> -		goto cleanup_pds;
> -	}
> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to add power domain provider\n");
>
> -	dev_set_drvdata(dev, bc);

why remove dev_set_drvdata(dev, bc)

Frank
> +	ret = devm_add_action_or_reset(dev, imx93_release_genpd_provider, dev->of_node);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to add genpd_provider release callback\n");
>
>  	return 0;
> -
> -cleanup_pds:
> -	for (i--; i >= 0; i--)
> -		pm_genpd_remove(&bc->domains[i].genpd);
> -
> -	return ret;
> -}
> -
> -static void imx93_blk_ctrl_remove(struct platform_device *pdev)
> -{
> -	struct imx93_blk_ctrl *bc = dev_get_drvdata(&pdev->dev);
> -	int i;
> -
> -	of_genpd_del_provider(pdev->dev.of_node);
> -
> -	pm_runtime_disable(&pdev->dev);
> -
> -	for (i = 0; i < bc->onecell_data.num_domains; i++) {
> -		struct imx93_blk_ctrl_domain *domain = &bc->domains[i];
> -
> -		pm_genpd_remove(&domain->genpd);
> -	}
>  }
>
>  static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] = {
> @@ -455,7 +446,6 @@ MODULE_DEVICE_TABLE(of, imx93_blk_ctrl_of_match);
>
>  static struct platform_driver imx93_blk_ctrl_driver = {
>  	.probe = imx93_blk_ctrl_probe,
> -	.remove = imx93_blk_ctrl_remove,
>  	.driver = {
>  		.name = "imx93-blk-ctrl",
>  		.of_match_table = imx93_blk_ctrl_of_match,
>
> --
> 2.47.3
>


From Frank.li at nxp.com  Mon Dec  1 14:42:45 2025
From: Frank.li at nxp.com (Frank Li)
Date: Mon, 1 Dec 2025 17:42:45 -0500
Subject: [PATCH 3/3] pmdomain: imx93-blk-ctrl: add support for optional
 subnodes
In-Reply-To: <20251201-v6-18-topic-imx93-blkctrl-v1-3-b57a72e60105@pengutronix.de>
References: <20251201-v6-18-topic-imx93-blkctrl-v1-0-b57a72e60105@pengutronix.de>
 <20251201-v6-18-topic-imx93-blkctrl-v1-3-b57a72e60105@pengutronix.de>
Message-ID: <aS4Z5QS9VBU6ObVF@lizhi-Precision-Tower-5810>

On Mon, Dec 01, 2025 at 06:12:07PM +0100, Marco Felsch wrote:
> This particular block can have DT subnodes describing the LVDS LDB, MIPI
> DSI and parallel DPI bridge.
>
> Scan for possible sub-devices within the driver, instead of misusing the
> simple-bus to perform the scan.
>
> Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
> ---

Reviewed-by: Frank Li <Frank.Li at nxp.com>

>  drivers/pmdomain/imx/imx93-blk-ctrl.c | 5 +++++
>  1 file changed, 5 insertions(+)
>
> diff --git a/drivers/pmdomain/imx/imx93-blk-ctrl.c b/drivers/pmdomain/imx/imx93-blk-ctrl.c
> index 13b0de6dd689cf944e034f7666a4e97b0118e3bd..8f79cabe07face872cb396bfb7329c230c4a97fe 100644
> --- a/drivers/pmdomain/imx/imx93-blk-ctrl.c
> +++ b/drivers/pmdomain/imx/imx93-blk-ctrl.c
> @@ -7,6 +7,7 @@
>  #include <linux/device.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
> +#include <linux/of_platform.h>
>  #include <linux/platform_device.h>
>  #include <linux/pm_domain.h>
>  #include <linux/pm_runtime.h>
> @@ -311,6 +312,10 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
>  	if (ret)
>  		return dev_err_probe(dev, ret, "failed to add genpd_provider release callback\n");
>
> +	ret = devm_of_platform_populate(dev);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to populate blk-ctrl sub-devices\n");
> +
>  	return 0;
>  }
>
>
> --
> 2.47.3
>


From linusw at kernel.org  Mon Dec  1 15:52:25 2025
From: linusw at kernel.org (Linus Walleij)
Date: Tue, 2 Dec 2025 00:52:25 +0100
Subject: Proposal: Officially allow "incomplete" trees as a base
In-Reply-To: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
References: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
Message-ID: <CAD++jLkuRQKoiEN928GtAj7wUts5PxH905bLp6ZhKsJ3NnenEA@mail.gmail.com>

Hi Dough,

thanks for your mail!

Let me just see if I understand correctly what you're trying to
do  (and apparently actively doing in production):

On Tue, Nov 18, 2025 at 11:43?PM Doug Anderson <dianders at chromium.org> wrote:

> We would like an officially accepted scheme that lets us more
> efficiently ship compiled device trees for a handful of related
> products by breaking the device trees up into a common "base" device
> tree and then applying "overlay" device trees atop the base to make a
> full and complete device tree.
(...)
> In Android, we do a pretty good job of solving the stated problem
> using device tree overlays. We describe the SoCs in "dts" files and
> compile them into "dtb"s. We describe boards in "dtso" files and
> compile them into "dtbo" files. A bootloader can handle identifying
> the correct base and overlay (the scheme for doing this is a separate
> but related topic) and applying the overlay atop the base "dtb". This
> solution is fully implemented downstream for Android phones and is
> well documented [2].

So in the kernel we have several arch/*/boot/dts/vendor/ folders
where they have:

soc.dtsi included by board.dtsi included by system.dts
and the top system.dts is all that get compiled.

So what you say is that you do the same thing but at runtime?

Can you just describe why this is done like this with
overlays?

I can only guess that you have one bootloader that needs
to compose device trees to many systems and the bootloader
only discovers the system it is running on and its constraints
at runtime, so shipping the static system.dtb as many people
do is not an option for you?

And the reason the bootloader doesn't already know what
it is running on and doesn't just pass that one device tree
or is just prepared with that one device tree has something
to do with manufacturing or so?

Sorry it just evades me.

Probably becayse even U-Boot these days use the provided
device tree dtb, for the system targeted, to initialize itself. I
suppose your bootloader is generic enough to avoid that
chicken-and-egg problem, right?

I guess if I had this problem:

soc.dtsi
board-a.dtsi
board-b.dtsi
system-board-a-v1.dts
system-board-a-v2.dts
system-board-b-v1.dts

etc having to be combined at runtime, in a bootloader, I would
consider shipping exactly these files in a memory-based
filesystem in my bootloader, and bake a DTS compiler into
my bootloader so it can just build a device tree for what
it detects.

But I guess you didn't want to hear that :D

Anyway, please describe how you ended up in this situation,
I'm trying to understand this.

It is quite clear that device tree overlays were intended for
say plug-n-play additions and minor fragments to be added
to a basically complete device tree, what you are doing was
probably not how it was intended. (Or let's see if someone
proves me wrong on that.)

Yours,
Linus Walleij


From Thinh.Nguyen at synopsys.com  Mon Dec  1 16:00:16 2025
From: Thinh.Nguyen at synopsys.com (Thinh Nguyen)
Date: Tue, 2 Dec 2025 00:00:16 +0000
Subject: [PATCH 2/2] usb: dwc3: imx8mp: disable auto suspend for host role
In-Reply-To: <bj6hroepwqflz5z3wabxacfhxltt2u6x274gd5v66rihosy3my@pzgq2e4v45fx>
References: <20251105074504.1427926-1-xu.yang_2@nxp.com>
 <20251105074504.1427926-2-xu.yang_2@nxp.com>
 <20251113230541.wbzt6xbine5gdmpp@synopsys.com>
 <7kpf7gnftumdwdowutryjz73nkap4vp3cfisrigt6def4f36vg@ijlj2eqwzsip>
 <20251121003742.q54ouezxhghmpwgn@synopsys.com>
 <bj6hroepwqflz5z3wabxacfhxltt2u6x274gd5v66rihosy3my@pzgq2e4v45fx>
Message-ID: <20251202000013.qnv3nkhyr7gtlu6n@synopsys.com>

On Tue, Nov 25, 2025, Xu Yang wrote:
> On Fri, Nov 21, 2025 at 12:37:47AM +0000, Thinh Nguyen wrote:
> > On Mon, Nov 17, 2025, Xu Yang wrote:
> > > On Thu, Nov 13, 2025 at 11:05:43PM +0000, Thinh Nguyen wrote:
> > > > On Wed, Nov 05, 2025, Xu Yang wrote:
> > > > > Do dwc3 core auto suspend enable for device and disable for host
> > > > > , this can make sure dwc3 core device auto suspend setting is
> > > > > correct all the time, the background of disable dwc3 core device
> > > > > auto suspend is to make its parent device suspend immediately
> > > > > (so wakeup enable can be enabled) after xhci-plat device suspended,
> > > > > for device mode, we keep the dwc3 core device auto suspend is to
> > > > > give some wait for gadget to be enumerated.
> > > > > 
> > > > > Signed-off-by: Xu Yang <xu.yang_2 at nxp.com>
> > > > > ---
> > > > >  drivers/usb/dwc3/dwc3-imx8mp.c | 31 +++++++++++++++++++++++++++++++
> > > > >  1 file changed, 31 insertions(+)
> > > > > 
> > > > > diff --git a/drivers/usb/dwc3/dwc3-imx8mp.c b/drivers/usb/dwc3/dwc3-imx8mp.c
> > > > > index bce6af82f54c..80a431cb6fed 100644
> > > > > --- a/drivers/usb/dwc3/dwc3-imx8mp.c
> > > > > +++ b/drivers/usb/dwc3/dwc3-imx8mp.c
> > > > > @@ -158,11 +158,31 @@ static irqreturn_t dwc3_imx8mp_interrupt(int irq, void *_dwc3_imx)
> > > > >  	return IRQ_HANDLED;
> > > > >  }
> > > > >  
> > > > > +static void dwc3_imx_pre_set_role(struct dwc3 *dwc, enum usb_role role)
> > > > > +{
> > > > > +	if (role == USB_ROLE_HOST)
> > > > > +		/*
> > > > > +		 * For xhci host, we need disable dwc core auto
> > > > > +		 * suspend, because during this auto suspend delay(5s),
> > > > > +		 * xhci host RUN_STOP is cleared and wakeup is not
> > > > > +		 * enabled, if device is inserted, xhci host can't
> > > > > +		 * response the connection.
> > > > > +		 */
> > > > > +		pm_runtime_dont_use_autosuspend(dwc->dev);
> > > > > +	else
> > > > > +		pm_runtime_use_autosuspend(dwc->dev);
> > > > 
> > > > Would this override the user setting everytime there's a role switch?
> > > 
> > > From what I know, the user can't control whether to enable or disable
> > > autosuspend feature. So there should be no overriding problem. When
> > > user change autosuspend_delay_ms, the delay setting will be kept
> > > everytime there's a role switch.
> > 
> > Should we set pm_runtime_mark_last_busy()?
> 
> I think we needn't explicitly call pm_runtime_mark_last_busy().
> Since commit "08071e64cb64 PM: runtime: Mark last busy stamp in pm_runtime_autosuspend()",
> pm_runtime_autosuspend() will do that thing automatically once dwc3 device is idle.

Ok.

> 
> > 
> > Also, if pm_runtime_use_autosuspend() is set, make sure to unwind with
> > pm_runtime_dont_use_autosuspend() on remove.
> > 
> > > 
> > > > 
> > > > > +}
> > > > > +
> > > > > +struct dwc3_glue_ops dwc3_imx_glue_ops = {
> > > > > +	.pre_set_role   = dwc3_imx_pre_set_role,
> > > > > +};
> > > > > +
> > > > >  static int dwc3_imx8mp_probe(struct platform_device *pdev)
> > > > >  {
> > > > >  	struct device		*dev = &pdev->dev;
> > > > >  	struct device_node	*node = dev->of_node;
> > > > >  	struct dwc3_imx8mp	*dwc3_imx;
> > > > > +	struct dwc3		*dwc3;
> > > > >  	struct resource		*res;
> > > > >  	int			err, irq;
> > > > >  
> > > > > @@ -240,6 +260,17 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev)
> > > > >  		goto depopulate;
> > > > >  	}
> > > > >  
> > > > > +	dwc3 = platform_get_drvdata(dwc3_imx->dwc3);
> > > > 
> > > > It's confusing how dwc3_imx->dwc3 is also named dwc3...
> > > 
> > > I will rename it later.
> > > 
> > > > 
> > > > > +	if (!dwc3) {
> > > > > +		err = dev_err_probe(dev, -EPROBE_DEFER, "failed to get dwc3 platform data\n");
> > > > > +		goto depopulate;
> > > > > +	}
> > > > > +
> > > > > +	dwc3->glue_ops = &dwc3_imx_glue_ops;
> > > > 
> > > > If you want to use glue_ops, please use the new flatten model. I
> > > > don't want dwc3 to be initialized again after of_platform_populate().
> > > 
> > > I understand the new flatten model is a more suitable way. Considering that
> > > many i.MX devices are using this legacy unflatten model, do you mind allow
> > > this change firstly and we will switch to the new flatten model in the future?
> > > 
> > 
> > Do you have plans for this transition? Perhaps this is a good time to
> > initiate the process so to avoid having and maintaining this improper
> > code while we still don't have it yet.
> 
> OK. It's a trend to use new flatten model. I do have plan for it. I'll
> prepare for it later.
> 

Ok. Can we add a note that this is a temporary solution until we switch
to using the new model in the commit message.

Thanks,
Thinh

From shin.son at samsung.com  Mon Dec  1 16:31:29 2025
From: shin.son at samsung.com (=?UTF-8?B?7IaQ7Iug?=)
Date: Tue, 2 Dec 2025 09:31:29 +0900
Subject: [PATCH v7 RESEND 2/3] thermal: exynos_tmu: Support new hardware
 and update TMU interface
In-Reply-To: <c3cc4b6f-ac75-448e-9fdf-c3c45e2ceed7@samsung.com>
References: <20251113064022.2701578-1-shin.son@samsung.com>
	<CGME20251113064044epcas2p1b87addb21473eca7cc52052e4e2e9237@epcas2p1.samsung.com>
	<20251113064022.2701578-3-shin.son@samsung.com>
	<5a6a749b-b2b7-41bb-bcb4-a2342e7f4e98@linaro.org>
	<015501dc5ea5$0c7dd460$25797d20$@samsung.com>
	<401ed9b9-19a4-4a19-b397-0f353e9f0c97@linaro.org>
	<c3cc4b6f-ac75-448e-9fdf-c3c45e2ceed7@samsung.com>
Message-ID: <022e01dc6323$028136a0$0783a3e0$@samsung.com>

Hello, Youngmin Nam.

> Hi Shin Son,
> if possible, please consider this approach as well.
> 
> Thanks,
> Youngmin


Ok, Understood. When I resume this task, I'll CC you.
Thank you for your opinion.

Best regards,
Shin Son



From leo.yeo at luaberry.com  Mon Dec  1 16:42:23 2025
From: leo.yeo at luaberry.com (Jeongin Yeo)
Date: Tue,  2 Dec 2025 00:42:23 +0000
Subject: [PATCH] arm64: mm: prevent context switching during idmap is mapped
Message-ID: <20251202004223.108388-1-leo.yeo@luaberry.com>

 cpu_install_idmap replaces ttbr0 to install idmap. replace_phys uses
 idmap_cpu_replace_ttbr1 which is located in idmap,
 thus it requires ttbr0 to point idmap. 
 
 However, if a kernel task has switched out right after
 cpu_install_idmap, when kernel task is loaded, its ttbr0 is
 mapped to reserved_pg_dir which doesn't contain any idmap
 functions.
 Therefore, the kernel task cannot find any functions to run,
 causing memory fault.
 
 As far as I can verify from the current arm64 tree,
 no in-tree caller invokes this function from a preemptible context.
 
 Nevertheless, future work might allow this function to be called in
 preemptive state. Encapsulating the idmap sequence with
 preempt_disable() and preempt_enable() prevents this possible problem.

Signed-off-by: Jeongin Yeo <leo.yeo at luaberry.com>
---
 arch/arm64/mm/mmu.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 2ba01dc8ef82..c3da836ebe8d 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -29,6 +29,7 @@
 #include <linux/mm_inline.h>
 #include <linux/pagewalk.h>
 #include <linux/stop_machine.h>
+#include <linux/preempt.h>
 
 #include <asm/barrier.h>
 #include <asm/cputype.h>
@@ -2136,7 +2137,7 @@ void __cpu_replace_ttbr1(pgd_t *pgdp, bool cnp)
 		ttbr1 |= TTBR_CNP_BIT;
 
 	replace_phys = (void *)__pa_symbol(idmap_cpu_replace_ttbr1);
-
+	preempt_disable();
 	cpu_install_idmap();
 
 	/*
@@ -2148,6 +2149,7 @@ void __cpu_replace_ttbr1(pgd_t *pgdp, bool cnp)
 	local_daif_restore(daif);
 
 	cpu_uninstall_idmap();
+	preempt_enable();
 }
 
 #ifdef CONFIG_ARCH_HAS_PKEYS
-- 
2.43.0



From robh at kernel.org  Mon Dec  1 16:48:33 2025
From: robh at kernel.org (Rob Herring)
Date: Mon, 1 Dec 2025 18:48:33 -0600
Subject: Proposal: Officially allow "incomplete" trees as a base
In-Reply-To: <CAODwPW_51fKOfDQbTUFCum13M621Uxi2Zw2YHng0DrrwwvZhRQ@mail.gmail.com>
References: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
 <CAODwPW_51fKOfDQbTUFCum13M621Uxi2Zw2YHng0DrrwwvZhRQ@mail.gmail.com>
Message-ID: <CAL_JsqJz8D53OF8PGaq+o6X5zfE1Y4NrH+BpYPEo6OENviJvbg@mail.gmail.com>

On Tue, Nov 18, 2025 at 5:48?PM Julius Werner <jwerner at chromium.org> wrote:
>
> > 4. When applying an overlay to a device tree that's "incomplete", the
> > top level overlay will be merged instead of replaced.
> >
> > Example for 2 levels:
> >
> > base (incomplete) compatible: "socvendor,mysoc-rev1", "socvendor,mysoc";
> > overlay compatible: "boardvendor,myboard-rev1", "boardvendor,myboard";
> > merged compatible: "boardvendor,myboard-rev1", "boardvendor,myboard",
> >                    "socvendor,mysoc-rev1", "socvendor,mysoc";
> >
> > Possible example if we support 3 levels:
> >
> > SoC (incomplete) compatible: "socvendor,mysoc-rev1", "socvendor,mysoc"
> > overlay1 (incomplete) compatible: "referencevendor,referencecodename";

I don't understand this one...

> > overlay2 compatible: "boardvendor,myboard-rev1", "boardvendor,myboard"
> > merged compatible: "boardvendor,myboard-rev1", "boardvendor,myboard",
> >                    "referencevendor,reference-codename",
> >                     , "socvendor,mysoc";
>
> Sorry, I only cursorily followed the previous discussion so I may have
> missed the exact need for this part. But I would caution against any
> proposal that changes the basic rules of how an overlay is applied.
> The definition of how overlays work has (I think?) been stable for
> over a decade now, and is implemented in bootloaders that often cannot
> easily be updated. I absolutely support your effort to get more
> upstream standardization for managing base device trees and overlays
> (which I think need to be flexible for arbitrary layers, not just SoC
> and board), but let's not break the overlay code in old bootloaders
> while doing it.

I think merging compatibles is orthogonal to splitting SoC and board
DTs. Doug needs to merge because there is more than 1 SoC version or
base DT to pick. In many cases (SoC revision compatibles are the
exception upstream), there is only 1 SoC DT and N board DTs. So we
should consider both and define them separately. In the simple case,
you'd have something like:

SoC (incomplete) compatible: "socvendor,mysoc"
Board overlay compatible: "boardvendor,myboard-rev1",
"boardvendor,myboard", "socvendor,mysoc"

Then you just apply the overlay and it overwrites the incomplete
compatible. That works with existing overlay applying (overwriting)
for multiple steps as long as each step is a superset (compatible
list) of the prior steps.

In Doug's case, I think you need code to decide which base to pick and
then fixup the final compatible.

SoC (incomplete) compatible: "socvendor,mysoc-rev1", "socvendor,mysoc"
Board overlay compatible: "boardvendor,myboard-rev1",
"boardvendor,myboard", "socvendor,mysoc"

And then after applying, you do the merge to insert the SoC rev compatible:

"boardvendor,myboard-rev1", "boardvendor,myboard",
"socvendor,mysoc-rev1", "socvendor,mysoc"

You need SoC specific code to know what SoC revision you are running
on, so SoC specific post apply code should be fine too. There's not
any existing bootloader problem because you need code to handle this.

Maybe that fixup will end up being generic enough that it's not
platform specific, but that's an optimization of the implementation.

> Is there really a need to merge the compatible strings in your case?

Well, you could just require duplicating an overlay N times for N
bases, but that doesn't scale

> I
> think in the vast majority of platform identification cases, code only
> cares about matching the most precise string (i.e.
> "boardvendor,myboard-rev1"). If we do feel like having the whole chain
> of identification is necessary, it could be achieved by just
> copy&pasting the extra strings into the overlay file. If we have
> cross-validation between base and overlay source files we could also
> have the validation check that the overlays correctly contain all
> compatible strings from their base tree. If we know that the base
> trees aren't standalone anyway, we could also just invent other
> property names that identify them (e.g. `soc-compatible =
> "socvendor,mysoc";`). Anything other than breaking the overlay format
> would be preferable in my opinion.

There's also a use case I'm aware of where the base DT is just for a
SoM and then the bootloader applies an expansion board overlay. So it
is not always "not standalone". And of course, this could be combined
with what Doug wants to do.

Note that for any new property (or an incomplete compatible) like
soc-compatible, you will need to consider how we validate it.

> I also feel like we need a better standardized way to tie base device
> trees to overlays, like your `/loaders` node proposal in an earlier
> email, although maybe that's an orthogonal discussion (but related,
> especially if there's supposed to be cross-validation between base
> trees and overlays). The compatible string is just not a scalable way
> for bootloaders to make this determination, there may be a lot more
> differentiation than just "SoC" and "board", and the scheme almost
> certainly needs to be platform/bootloader-specific because every
> hardware vendor has their own ideas about how to group and reuse parts
> of a platform. This information doesn't necessarily need to be *in*
> the device tree, it could also just be in a separate YAML file in the
> same repo (since bootloaders will almost certainly want to have it
> transformed into their own out-of-band descriptor at build-time
> anyway, so that they can compress the device tree itself and don't
> have to decompress each one for matching), but it needs to be
> somewhere.

There is a proposal here[1]. It's simple, but I do wonder if looking
at the root compatible only is too narrow of a view. An overlay could
target a connector compatible for example.

We kind of have this information in the kernel build already as well.
The requirement for overlays in the kernel tree is overlays get
applied to at least one target at build time. It would be nice for any
solution to this problem to replace those build rules.

Rob

[1] https://lore.kernel.org/all/20250911151436.2467758-1-raymond.mao at linaro.org/


From dianders at chromium.org  Mon Dec  1 16:44:08 2025
From: dianders at chromium.org (Doug Anderson)
Date: Mon, 1 Dec 2025 16:44:08 -0800
Subject: Proposal: Officially allow "incomplete" trees as a base
In-Reply-To: <CAD++jLkuRQKoiEN928GtAj7wUts5PxH905bLp6ZhKsJ3NnenEA@mail.gmail.com>
References: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
 <CAD++jLkuRQKoiEN928GtAj7wUts5PxH905bLp6ZhKsJ3NnenEA@mail.gmail.com>
Message-ID: <CAD=FV=X5=AK4XMANv+fatn3d9Y5vo9AXsHWb_47HmNaMWUtMwA@mail.gmail.com>

Hi,

On Mon, Dec 1, 2025 at 3:52?PM Linus Walleij <linusw at kernel.org> wrote:
>
> Hi Dough,
>
> thanks for your mail!
>
> Let me just see if I understand correctly what you're trying to
> do  (and apparently actively doing in production):

Thanks for your thoughts. Just to be clear, even though I've dealt
with device trees on a lot of ChromeOS boards, this is something that
_Android_ phones are doing in production and is what I'm focusing on
here. The whole scheme is at least roughly documented at:

https://source.android.com/docs/core/architecture/dto/partitions

This is all stuff that predates me looking at Android. I'm just coming
in and trying to make sense of what's there and trying to upstream
what I can.

Separately, it can be noted that we always _wanted_ a similar solution
for ChromeOS, but we never quite got there... ;-)


> On Tue, Nov 18, 2025 at 11:43?PM Doug Anderson <dianders at chromium.org> wrote:
>
> > We would like an officially accepted scheme that lets us more
> > efficiently ship compiled device trees for a handful of related
> > products by breaking the device trees up into a common "base" device
> > tree and then applying "overlay" device trees atop the base to make a
> > full and complete device tree.
> (...)
> > In Android, we do a pretty good job of solving the stated problem
> > using device tree overlays. We describe the SoCs in "dts" files and
> > compile them into "dtb"s. We describe boards in "dtso" files and
> > compile them into "dtbo" files. A bootloader can handle identifying
> > the correct base and overlay (the scheme for doing this is a separate
> > but related topic) and applying the overlay atop the base "dtb". This
> > solution is fully implemented downstream for Android phones and is
> > well documented [2].
>
> So in the kernel we have several arch/*/boot/dts/vendor/ folders
> where they have:
>
> soc.dtsi included by board.dtsi included by system.dts
> and the top system.dts is all that get compiled.
>
> So what you say is that you do the same thing but at runtime?

Essentially. In this case, we don't ship the device tree _sources_ but
ship _compiled_ device tree. We compile the SoC into a "dtb" and then
combine anything above the SoC into a single "dtbo". We ship several
"dtb" files and several "dtbo" files and combine them at runtime after
we identify which hardware we're running on.


> Can you just describe why this is done like this with
> overlays?
>
> I can only guess that you have one bootloader that needs
> to compose device trees to many systems and the bootloader
> only discovers the system it is running on and its constraints
> at runtime, so shipping the static system.dtb as many people
> do is not an option for you?
>
> And the reason the bootloader doesn't already know what
> it is running on and doesn't just pass that one device tree
> or is just prepared with that one device tree has something
> to do with manufacturing or so?
>
> Sorry it just evades me.

Our builder creates a single "image" that can be flashed onto any
number of devices. Users (or manufacturers) can download and install
this single image and it will work on a wide variety of devices. So
you can download a single "Pixel 10" image that can be installed on
any of the Pixel 10 devices (Pixel 10, Pixel 10 Pro, and Pixel 10 Pro
XL). It will also work on our development board and early
pre-production variants of those boards.

In order for this to work, we need a lot of device trees and
_something_ needs to pick the correct one. Right now, the bootloader
is in charge of this task.

If we had less variety of products that we needed to ship then, yes,
we could just ship the one device tree and have a separate build for
each product. ...but that doesn't scale terribly well.


> Probably becayse even U-Boot these days use the provided
> device tree dtb, for the system targeted, to initialize itself. I
> suppose your bootloader is generic enough to avoid that
> chicken-and-egg problem, right?

FWIW: I believe even U-boot supports shipping a pile of device trees
and detecting things at runtime. See the "FIT" image:

https://docs.u-boot.org/en/latest/usage/fit/index.html


> I guess if I had this problem:
>
> soc.dtsi
> board-a.dtsi
> board-b.dtsi
> system-board-a-v1.dts
> system-board-a-v2.dts
> system-board-b-v1.dts
>
> etc having to be combined at runtime, in a bootloader, I would
> consider shipping exactly these files in a memory-based
> filesystem in my bootloader, and bake a DTS compiler into
> my bootloader so it can just build a device tree for what
> it detects.
>
> But I guess you didn't want to hear that :D

You're saying to just ship device tree source instead of binary? Hmmm,
it's an interesting idea. It wouldn't be _terrible_ since "dtb" stores
a lot of strings to begin with, but I think it would still add enough
of a bloat to make it a no-go for us... I would also imagine it would
be a pain to deal with #include of header files with #defines. Do we
somehow partially pre-process the device tree files but don't apply
the #include files. It might be possible to solve some specific cases,
but having this work in a generic way seems miserable.


> Anyway, please describe how you ended up in this situation,
> I'm trying to understand this.

The main goal is just building/shipping one image to support a variety
of similar products and trying to save space by not repeating the SoC
bits over and over again.


> It is quite clear that device tree overlays were intended for
> say plug-n-play additions and minor fragments to be added
> to a basically complete device tree, what you are doing was
> probably not how it was intended. (Or let's see if someone
> proves me wrong on that.)

Not sure what makes that so clear, since it's not clear to me. In any
case, even if device tree overlays weren't intended for such a usage,
they actually seem to work fairly well for it, even if upstream
currently rejects device tree usage like this.

FWIW, the fact that bootloaders (like U-Boot) have the ability to
apply overlays makes me think that _someone_ intended them to be used
similar to how Android is using them. ;-) If it was just expansion
cards then (presumably) someone would boot to Linux and just apply
overlays from there. See:

https://docs.u-boot.org/en/latest/usage/fit/overlay-fdt-boot.html


-Doug


From robh at kernel.org  Mon Dec  1 17:07:37 2025
From: robh at kernel.org (Rob Herring)
Date: Mon, 1 Dec 2025 19:07:37 -0600
Subject: Proposal: Officially allow "incomplete" trees as a base
In-Reply-To: <CAD++jLkuRQKoiEN928GtAj7wUts5PxH905bLp6ZhKsJ3NnenEA@mail.gmail.com>
References: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
 <CAD++jLkuRQKoiEN928GtAj7wUts5PxH905bLp6ZhKsJ3NnenEA@mail.gmail.com>
Message-ID: <CAL_Jsq+uVyGzi+TniwJQEOFDm=L9=S-aLWfvyDmY-GQD5iAEOA@mail.gmail.com>

On Mon, Dec 1, 2025 at 5:52?PM Linus Walleij <linusw at kernel.org> wrote:
>
> Hi Dough,
>
> thanks for your mail!
>
> Let me just see if I understand correctly what you're trying to
> do  (and apparently actively doing in production):
>
> On Tue, Nov 18, 2025 at 11:43?PM Doug Anderson <dianders at chromium.org> wrote:
>
> > We would like an officially accepted scheme that lets us more
> > efficiently ship compiled device trees for a handful of related
> > products by breaking the device trees up into a common "base" device
> > tree and then applying "overlay" device trees atop the base to make a
> > full and complete device tree.
> (...)
> > In Android, we do a pretty good job of solving the stated problem
> > using device tree overlays. We describe the SoCs in "dts" files and
> > compile them into "dtb"s. We describe boards in "dtso" files and
> > compile them into "dtbo" files. A bootloader can handle identifying
> > the correct base and overlay (the scheme for doing this is a separate
> > but related topic) and applying the overlay atop the base "dtb". This
> > solution is fully implemented downstream for Android phones and is
> > well documented [2].
>
> So in the kernel we have several arch/*/boot/dts/vendor/ folders
> where they have:
>
> soc.dtsi included by board.dtsi included by system.dts
> and the top system.dts is all that get compiled.
>
> So what you say is that you do the same thing but at runtime?
>
> Can you just describe why this is done like this with
> overlays?
>
> I can only guess that you have one bootloader that needs
> to compose device trees to many systems and the bootloader
> only discovers the system it is running on and its constraints
> at runtime, so shipping the static system.dtb as many people
> do is not an option for you?
>
> And the reason the bootloader doesn't already know what
> it is running on and doesn't just pass that one device tree
> or is just prepared with that one device tree has something
> to do with manufacturing or so?
>
> Sorry it just evades me.
>
> Probably becayse even U-Boot these days use the provided
> device tree dtb, for the system targeted, to initialize itself. I
> suppose your bootloader is generic enough to avoid that
> chicken-and-egg problem, right?
>
> I guess if I had this problem:
>
> soc.dtsi
> board-a.dtsi
> board-b.dtsi
> system-board-a-v1.dts
> system-board-a-v2.dts
> system-board-b-v1.dts

This is the easy case. The harder one is you have soc-rev1.dtsi and
soc-rev2.dtsi and you just doubled the combinations.

> etc having to be combined at runtime, in a bootloader, I would
> consider shipping exactly these files in a memory-based
> filesystem in my bootloader, and bake a DTS compiler into
> my bootloader so it can just build a device tree for what
> it detects.

We don't want to do that for the same reasons we don't pass a dts to
the kernel...


> But I guess you didn't want to hear that :D
>
> Anyway, please describe how you ended up in this situation,
> I'm trying to understand this.
>
> It is quite clear that device tree overlays were intended for
> say plug-n-play additions and minor fragments to be added
> to a basically complete device tree, what you are doing was
> probably not how it was intended. (Or let's see if someone
> proves me wrong on that.)

Board DTs are relatively minor compared to the SoC DT.

I would be interested in some experiments around making this change
with existing DTs. Take a board DT and add the overlay boilerplate
(that may be nothing more than add '/plugin/') and remove the SoC
include. Does that apply to a compiled SoC DTB and is the result the
same as before?

Think of it as moving from building C code using a #include of every
.c file to build a single .o to linking multiple individual .o files.
No one would argue the former is better.

Rob


From hailong.fan at siengine.com  Mon Dec  1 17:24:35 2025
From: hailong.fan at siengine.com (=?utf-8?B?RmFuIEhhaWxvbmcv6IyD5rW36b6Z?=)
Date: Tue, 2 Dec 2025 01:24:35 +0000
Subject: =?utf-8?B?5Zue5aSNOiBbUEFUQ0hdIG5ldDogc3RtbWFjOiBNb2RpZnkgdGhlIGp1ZGdt?=
 =?utf-8?Q?ent_condition_of_"tx=5Favail"_from_1_to_2?=
In-Reply-To: <CANn89iLW+68YE9s9dChEcQYbmwXSBzWRPzFH50+--Kw3XNZXEQ@mail.gmail.com>
References: <tencent_22959DC8315158E23D77C14B9B33C97EA60A@qq.com>
 <CANn89iLW+68YE9s9dChEcQYbmwXSBzWRPzFH50+--Kw3XNZXEQ@mail.gmail.com>
Message-ID: <addd14c84f164e4e90e35e8dc4121dd4@siengine.com>

Hi Eric

You are right, I will follow your advice to modify the relevant code.

Regards
Hailong


-----????-----
???: Eric Dumazet <edumazet at google.com> 
????: 2025?12?1? 20:21
???: 2694439648 at qq.com
??: andrew+netdev at lunn.ch; davem at davemloft.net; kuba at kernel.org; pabeni at redhat.com; mcoquelin.stm32 at gmail.com; alexandre.torgue at foss.st.com; Fan Hailong/??? <hailong.fan at siengine.com>; netdev at vger.kernel.org; linux-stm32 at st-md-mailman.stormreply.com; linux-arm-kernel at lists.infradead.org; inux-kernel at vger.kernel.org
??: Re: [PATCH] net: stmmac: Modify the judgment condition of "tx_avail" from 1 to 2

On Sun, Nov 30, 2025 at 6:57?PM <2694439648 at qq.com> wrote:
>
> From: "hailong.fan" <hailong.fan at siengine.com>
>
>     Under certain conditions, a WARN_ON will be triggered
>     if avail equals 1.
>
>     For example, when a VLAN packet is to send,
>     stmmac_vlan_insert consumes one unit of space,
>     and the data itself consumes another.
>     actually requiring 2 units of space in total.
>
> Signed-off-by: hailong.fan <hailong.fan at siengine.com>
> ---
>  drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c 
> b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index 7b90ecd3a..b575384cd 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -4529,7 +4529,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
>                 }
>         }
>
> -       if (unlikely(stmmac_tx_avail(priv, queue) < nfrags + 1)) {
> +       if (unlikely(stmmac_tx_avail(priv, queue) < nfrags + 2)) {
>                 if (!netif_tx_queue_stopped(netdev_get_tx_queue(dev, queue))) {
>                         netif_tx_stop_queue(netdev_get_tx_queue(priv->dev,
>                                                                 
> queue));

Drivers should stop their queues earlier.

NETDEV_TX_BUSY is almost always wrong.

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 7b90ecd3a55e600458b0c87d6125831626f4683d..6dcc7b84a8759763b6471a48a6c80b1f17cd937c
100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -4675,7 +4675,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
                print_pkt(skb->data, skb->len);
        }

-       if (unlikely(stmmac_tx_avail(priv, queue) <= (MAX_SKB_FRAGS + 1))) {
+       if (unlikely(stmmac_tx_avail(priv, queue) <= (MAX_SKB_FRAGS + 
+ 2))) {
                netif_dbg(priv, hw, priv->dev, "%s: stop transmitted packets\n",
                          __func__);
                netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, queue));

From 2694439648 at qq.com  Mon Dec  1 17:25:39 2025
From: 2694439648 at qq.com (2694439648 at qq.com)
Date: Tue,  2 Dec 2025 09:25:39 +0800
Subject: [PATCH v1] net: stmmac: Modify the judgment condition of "tx_avail" from 1 to 2
Message-ID: <tencent_A2BE4EE4983E2DD19E67E0D5CC6564D1D309@qq.com>

From: "hailong.fan" <hailong.fan at siengine.com>

    Under certain conditions, a WARN_ON will be triggered
    if avail equals 1.

    For example, when a VLAN packet is to send,
    stmmac_vlan_insert consumes one unit of space,
    and the data itself consumes another.
    actually requiring 2 units of space in total.

    ---
    V0-V1:
       1. Stop their queues earlier

Signed-off-by: hailong.fan <hailong.fan at siengine.com>
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 7b90ecd3a..738a0c94d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -4529,7 +4529,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 		}
 	}
 
-	if (unlikely(stmmac_tx_avail(priv, queue) < nfrags + 1)) {
+	if (unlikely(stmmac_tx_avail(priv, queue) < nfrags + 2)) {
 		if (!netif_tx_queue_stopped(netdev_get_tx_queue(dev, queue))) {
 			netif_tx_stop_queue(netdev_get_tx_queue(priv->dev,
 								queue));
@@ -4675,7 +4675,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 		print_pkt(skb->data, skb->len);
 	}
 
-	if (unlikely(stmmac_tx_avail(priv, queue) <= (MAX_SKB_FRAGS + 1))) {
+	if (unlikely(stmmac_tx_avail(priv, queue) <= (MAX_SKB_FRAGS + 2))) {
 		netif_dbg(priv, hw, priv->dev, "%s: stop transmitted packets\n",
 			  __func__);
 		netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, queue));
-- 
2.34.1



From rui.wang at ideasonboard.com  Mon Dec  1 17:50:24 2025
From: rui.wang at ideasonboard.com (Rui Wang)
Date: Mon,  1 Dec 2025 20:50:24 -0500
Subject: [PATCH v1 0/1] Fix filter mode register issue
Message-ID: <20251202015025.601549-1-rui.wang@ideasonboard.com>

Hi,

This series contains a single patch that fixes an issue in the rkisp1
filter mode configuration logic.

The rkisp1_flt_config() function performs a direct write to the
FILT_MODE register before the read/modify/write update. This write
does not include the RKISP1_CIF_ISP_FLT_ENA bit, which clears the
enable bit in hardware. After that, the read/modify/write sequence
cannot restore the original enable state, causing the filter to be
disabled unintentionally.

The patch removes the redundant direct write. The remaining
read/modify/write sequence correctly updates the mode fields while
preserving the existing enable bit.

Please review.

Thanks,
Rui Wang

Rui Wang (1):
  media: rkisp1: Fix filter mode register configuration

 drivers/media/platform/rockchip/rkisp1/rkisp1-params.c | 6 ------
 1 file changed, 6 deletions(-)

-- 
2.43.0



From rui.wang at ideasonboard.com  Mon Dec  1 17:50:25 2025
From: rui.wang at ideasonboard.com (Rui Wang)
Date: Mon,  1 Dec 2025 20:50:25 -0500
Subject: [PATCH v1 1/1] media: rkisp1: Fix filter mode register configuration
In-Reply-To: <20251202015025.601549-1-rui.wang@ideasonboard.com>
References: <20251202015025.601549-1-rui.wang@ideasonboard.com>
Message-ID: <20251202015025.601549-2-rui.wang@ideasonboard.com>

The rkisp1_flt_config() function performs an initial direct write to
RKISP1_CIF_ISP_FILT_MODE without including the RKISP1_CIF_ISP_FLT_ENA
bit, which clears the filter enable bit in the hardware.

The subsequent read/modify/write sequence then reads back the register
with the enable bit already cleared and cannot restore it, resulting in
the filter being inadvertently disabled.

Remove the redundant direct write. The read/modify/write sequence alone
correctly preserves the existing enable bit state while updating the
DNR mode and filter configuration bits.

Signed-off-by: Rui Wang <rui.wang at ideasonboard.com>
---
 drivers/media/platform/rockchip/rkisp1/rkisp1-params.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
index c9f88635224c..6442436a5e42 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
@@ -411,12 +411,6 @@ static void rkisp1_flt_config(struct rkisp1_params *params,
 	rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_LUM_WEIGHT,
 		     arg->lum_weight);
 
-	rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_MODE,
-		     (arg->mode ? RKISP1_CIF_ISP_FLT_MODE_DNR : 0) |
-		     RKISP1_CIF_ISP_FLT_CHROMA_V_MODE(arg->chr_v_mode) |
-		     RKISP1_CIF_ISP_FLT_CHROMA_H_MODE(arg->chr_h_mode) |
-		     RKISP1_CIF_ISP_FLT_GREEN_STAGE1(arg->grn_stage1));
-
 	/* avoid to override the old enable value */
 	filt_mode = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_FILT_MODE);
 	filt_mode &= RKISP1_CIF_ISP_FLT_ENA;
-- 
2.43.0



From jianpeng.chang.cn at windriver.com  Mon Dec  1 18:27:07 2025
From: jianpeng.chang.cn at windriver.com (Jianpeng Chang)
Date: Tue, 2 Dec 2025 10:27:07 +0800
Subject: [v2 PATCH] arm64: mm: Fix kexec failure after pte_mkwrite_novma() change
Message-ID: <20251202022707.2720933-1-jianpeng.chang.cn@windriver.com>

Commit 143937ca51cc ("arm64, mm: avoid always making PTE dirty in
pte_mkwrite()") modified pte_mkwrite_novma() to only clear PTE_RDONLY
when the page is already dirty (PTE_DIRTY is set). While this optimization
prevents unnecessary dirty page marking in normal memory management paths,
it breaks kexec on some platforms like NXP LS1043.

The issue occurs in the kexec code path:
1. machine_kexec_post_load() calls trans_pgd_create_copy() to create a
   writable copy of the linear mapping
2. _copy_pte() calls pte_mkwrite_novma() to ensure all pages in the copy
   are writable for the new kernel image copying
3. With the new logic, clean pages (without PTE_DIRTY) remain read-only
4. When kexec tries to copy the new kernel image through the linear
   mapping, it fails on read-only pages, causing the system to hang
   after "Bye!"

The same issue affects hibernation which uses the same trans_pgd code path.

Fix this by explicitly clearing PTE_RDONLY in _copy_pte() for both
kexec and hibernation, ensuring all pages in the temporary mapping are
writable regardless of their dirty state. This preserves the original
commit's optimization for normal memory management while fixing the
kexec/hibernation regression.

Fixes: 143937ca51cc ("arm64, mm: avoid always making PTE dirty in pte_mkwrite()")
Signed-off-by: Jianpeng Chang <jianpeng.chang.cn at windriver.com>
---
v2:
  - Use pte_mkwrite_novma(pte_mkdirty(pte)) instead of manual bit manipulation
  - Updated comments to clarify pte_mkwrite_novma() alone cannot be used
v1: https://lore.kernel.org/all/20251127034350.3600454-1-jianpeng.chang.cn at windriver.com/

 arch/arm64/mm/trans_pgd.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/mm/trans_pgd.c b/arch/arm64/mm/trans_pgd.c
index 18543b603c77..08f5ee6643e1 100644
--- a/arch/arm64/mm/trans_pgd.c
+++ b/arch/arm64/mm/trans_pgd.c
@@ -40,8 +40,13 @@ static void _copy_pte(pte_t *dst_ptep, pte_t *src_ptep, unsigned long addr)
 		 * Resume will overwrite areas that may be marked
 		 * read only (code, rodata). Clear the RDONLY bit from
 		 * the temporary mappings we use during restore.
+		 *
+		 * For kexec/hibernation, we need writable access to all
+		 * pages in the linear mapping to copy the new kernel image.
+		 * Mark pages dirty first to ensure pte_mkwrite_novma()
+		 * clears PTE_RDONLY.
 		 */
-		__set_pte(dst_ptep, pte_mkwrite_novma(pte));
+		__set_pte(dst_ptep, pte_mkwrite_novma(pte_mkdirty(pte)));
 	} else if (!pte_none(pte)) {
 		/*
 		 * debug_pagealloc will removed the PTE_VALID bit if
@@ -57,7 +62,7 @@ static void _copy_pte(pte_t *dst_ptep, pte_t *src_ptep, unsigned long addr)
 		 */
 		BUG_ON(!pfn_valid(pte_pfn(pte)));
 
-		__set_pte(dst_ptep, pte_mkvalid(pte_mkwrite_novma(pte)));
+		__set_pte(dst_ptep, pte_mkvalid(pte_mkwrite_novma(pte_mkdirty(pte))));
 	}
 }
 
-- 
2.51.2



From jzhang918 at gmail.com  Mon Dec  1 18:54:16 2025
From: jzhang918 at gmail.com (Jie Zhang)
Date: Mon,  1 Dec 2025 21:54:16 -0500
Subject: [PATCH] net: stmmac: fix oops when split header is enabled
Message-ID: <20251202025421.4560-1-jie.zhang@analog.com>

For GMAC4, when split header is enabled, in some rare cases, the
hardware does not fill buf2 of the first descriptor with payload.
Thus we cannot assume buf2 is always fully filled if it is not
the last descriptor. Otherwise, the length of buf2 of the second
descriptor will be calculated wrong and cause an oops:

Unable to handle kernel paging request at virtual address ffff00019246bfc0
Mem abort info:
  ESR = 0x0000000096000145
  EC = 0x25: DABT (current EL), IL = 32 bits
  SET = 0, FnV = 0
  EA = 0, S1PTW = 0
  FSC = 0x05: level 1 translation fault
Data abort info:
  ISV = 0, ISS = 0x00000145, ISS2 = 0x00000000
  CM = 1, WnR = 1, TnD = 0, TagAccess = 0
  GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
swapper pgtable: 4k pages, 48-bit VAs, pgdp=0000000090d8b000
[ffff00019246bfc0] pgd=180000009dfff403, p4d=180000009dfff403, pud=0000000000000000
Internal error: Oops: 0000000096000145 [#1]  SMP
Modules linked in:
CPU: 0 UID: 0 PID: 157 Comm: iperf3 Not tainted 6.18.0-rc6 #1 PREEMPT
Hardware name: ADI 64-bit SC598 SOM EZ Kit (DT)
pstate: 00400009 (nzcv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
pc : dcache_inval_poc+0x28/0x58
lr : arch_sync_dma_for_cpu+0x28/0x34
sp : ffff800080dcbc40
x29: ffff800080dcbc40 x28: 0000000000000008 x27: ffff000091c50980
x26: ffff000091c50980 x25: 0000000000000000 x24: ffff000092a5fb00
x23: ffff000092768f28 x22: 000000009246c000 x21: 0000000000000002
x20: 00000000ffffffdc x19: ffff000091844c10 x18: 0000000000000000
x17: ffff80001d308000 x16: ffff800080dc8000 x15: ffff0000929fb034
x14: 70f709157374dd21 x13: ffff000092812ec0 x12: 0000000000000000
x11: 000000000000dd86 x10: 0000000000000040 x9 : 0000000000000600
x8 : ffff000092a5fbac x7 : 0000000000000001 x6 : 0000000000004240
x5 : 000000009246c000 x4 : ffff000091844c10 x3 : 000000000000003f
x2 : 0000000000000040 x1 : ffff00019246bfc0 x0 : ffff00009246c000
Call trace:
 dcache_inval_poc+0x28/0x58 (P)
 dma_direct_sync_single_for_cpu+0x38/0x6c
 __dma_sync_single_for_cpu+0x34/0x6c
 stmmac_napi_poll_rx+0x8f0/0xb60
 __napi_poll.constprop.0+0x30/0x144
 net_rx_action+0x160/0x274
 handle_softirqs+0x1b8/0x1fc
 __do_softirq+0x10/0x18
 ____do_softirq+0xc/0x14
 call_on_irq_stack+0x30/0x48
 do_softirq_own_stack+0x18/0x20
 __irq_exit_rcu+0x64/0xe8
 irq_exit_rcu+0xc/0x14
 el1_interrupt+0x3c/0x58
 el1h_64_irq_handler+0x14/0x1c
 el1h_64_irq+0x6c/0x70
 __arch_copy_to_user+0xbc/0x240 (P)
 simple_copy_to_iter+0x28/0x30
 __skb_datagram_iter+0x1bc/0x268
 skb_copy_datagram_iter+0x1c/0x24
 tcp_recvmsg_locked+0x3ec/0x778
 tcp_recvmsg+0x10c/0x194
 inet_recvmsg+0x64/0xa0
 sock_recvmsg_nosec+0x1c/0x24
 sock_read_iter+0x8c/0xdc
 vfs_read+0x144/0x1a0
 ksys_read+0x74/0xdc
 __arm64_sys_read+0x14/0x1c
 invoke_syscall+0x60/0xe4
 el0_svc_common.constprop.0+0xb0/0xcc
 do_el0_svc+0x18/0x20
 el0_svc+0x80/0xc8
 el0t_64_sync_handler+0x58/0x134
 el0t_64_sync+0x170/0x174
Code: d1000443 ea03003f 8a230021 54000040 (d50b7e21)
---[ end trace 0000000000000000 ]---
Kernel panic - not syncing: Oops: Fatal exception in interrupt
Kernel Offset: disabled
CPU features: 0x080000,00008000,08006281,0400520b
Memory Limit: none
---[ end Kernel panic - not syncing: Oops: Fatal exception in interrupt ]---

To fix this, the PL bit-field in RDES3 register is used for all
descriptors, whether it is the last descriptor or not.

Signed-off-by: Jie Zhang <jie.zhang at analog.com>
---
 .../net/ethernet/stmicro/stmmac/stmmac_main.c | 20 ++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 7b90ecd3a55e..848b1769c573 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -4878,13 +4878,27 @@ static unsigned int stmmac_rx_buf2_len(struct stmmac_priv *priv,
 	if (!priv->sph)
 		return 0;
 
-	/* Not last descriptor */
-	if (status & rx_not_ls)
+	/* For GMAC4, when split header is enabled, in some rare cases, the
+	 * hardware does not fill buf2 of the first descriptor with payload.
+	 * Thus we cannot assume buf2 is always fully filled if it is not
+	 * the last descriptor. Otherwise, the length of buf2 of the second
+	 * descriptor will be calculated wrong and cause an oops.
+	 *
+	 * If this is the last descriptor, 'plen' is the length of the
+	 * received packet that was transferred to system memory.
+	 * Otherwise, it is the accumulated number of bytes that have been
+	 * transferred for the current packet.
+	 *
+	 * Thus 'plen - len' always gives the correct length of buf2.
+	 */
+
+	/* Not GMAC4 and not last descriptor */
+	if (!priv->plat->has_gmac4 && (status & rx_not_ls))
 		return priv->dma_conf.dma_buf_sz;
 
+	/* GMAC4 or last descriptor */
 	plen = stmmac_get_rx_frame_len(priv, p, coe);
 
-	/* Last descriptor */
 	return plen - len;
 }
 
-- 
2.47.3



From zhenglifeng1 at huawei.com  Mon Dec  1 19:05:25 2025
From: zhenglifeng1 at huawei.com (zhenglifeng (A))
Date: Tue, 2 Dec 2025 11:05:25 +0800
Subject: [PATCH v6 0/3] arm64: topology: Handle AMU FIE setup on CPU
 hotplug
In-Reply-To: <aS2z0EURwHbbGZab@arm.com>
References: <20251119081356.2495290-1-zhenglifeng1@huawei.com>
 <aS2z0EURwHbbGZab@arm.com>
Message-ID: <9b6882dc-a91a-42d6-bf76-347338930d71@huawei.com>

On 2025/12/1 23:27, Beata Michalska wrote:
> Hi,
> 
> Apologies for the delay in reviewing this - currently in progress....
> Out of curiosity: what's the cpufreq driver used for testing this series ?

I used cppc_cpufreq for testing this. But with some modifications in
processor_driver.c, or you'll find that the driver will fail to load with
maxcpus set. The modification below is only a temporary solution. I'm still
working on that.

---
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index 5d824435b26b..2f286a1b0b02 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -33,6 +33,7 @@ MODULE_AUTHOR("Paul Diefenbaugh");
 MODULE_DESCRIPTION("ACPI Processor Driver");
 MODULE_LICENSE("GPL");
 
+static int acpi_processor_start(struct device *dev);
 static int acpi_processor_stop(struct device *dev);
 
 static const struct acpi_device_id processor_device_ids[] = {
@@ -46,6 +47,7 @@ static struct device_driver acpi_processor_driver = {
 	.name = "processor",
 	.bus = &cpu_subsys,
 	.acpi_match_table = processor_device_ids,
+	.probe = acpi_processor_start,
 	.remove = acpi_processor_stop,
 };
 
@@ -191,6 +193,21 @@ static int __acpi_processor_start(struct acpi_device *device)
 	return result;
 }
 
+static int acpi_processor_start(struct device *dev)
+{
+	struct acpi_device *device = ACPI_COMPANION(dev);
+	int ret;
+
+	if (!device)
+		return -ENODEV;
+
+	/* Protect against concurrent CPU hotplug operations */
+	cpu_hotplug_disable();
+	ret = __acpi_processor_start(device);
+	cpu_hotplug_enable();
+	return ret;
+}
+
 static int acpi_processor_stop(struct device *dev)
 {
 	struct acpi_device *device = ACPI_COMPANION(dev);
@@ -264,9 +281,9 @@ static int __init acpi_processor_driver_init(void)
 
 	acpi_processor_register_idle_driver();
 
-	result = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
-				   "acpi/cpu-drv:online",
-				   acpi_soft_cpu_online, NULL);
+	result = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
+					   "acpi/cpu-drv:online",
+					   acpi_soft_cpu_online, NULL);
 	if (result < 0)
 		goto err;
 	hp_online = result;

> 
> ---
> BR
> Beata
> On Wed, Nov 19, 2025 at 04:13:53PM +0800, Lifeng Zheng wrote:
>> Solve a problem that causes CPUs Setup AMU FIE failed in a corner case,
>> even though they're eligible.
>>
>>
> 



From zhenglifeng1 at huawei.com  Mon Dec  1 19:08:05 2025
From: zhenglifeng1 at huawei.com (zhenglifeng (A))
Date: Tue, 2 Dec 2025 11:08:05 +0800
Subject: [PATCH v6 0/3] arm64: topology: Handle AMU FIE setup on CPU
 hotplug
In-Reply-To: <9b6882dc-a91a-42d6-bf76-347338930d71@huawei.com>
References: <20251119081356.2495290-1-zhenglifeng1@huawei.com>
 <aS2z0EURwHbbGZab@arm.com> <9b6882dc-a91a-42d6-bf76-347338930d71@huawei.com>
Message-ID: <246a9483-850c-4c06-ac48-d03e0ae0bcec@huawei.com>

On 2025/12/2 11:05, zhenglifeng (A) wrote:
> On 2025/12/1 23:27, Beata Michalska wrote:
>> Hi,
>>
>> Apologies for the delay in reviewing this - currently in progress....
>> Out of curiosity: what's the cpufreq driver used for testing this series ?
> 
> I used cppc_cpufreq for testing this. But with some modifications in
> processor_driver.c, or you'll find that the driver will fail to load with
> maxcpus set. The modification below is only a temporary solution. I'm still
> working on that.

In addition, I exposed some sysfs interfaces for easily checking freq scale
and source as below when testing. Hope this helps.

---
diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
index 331a0654f3dc..ba15c90cf908 100644
--- a/drivers/base/arch_topology.c
+++ b/drivers/base/arch_topology.c
@@ -98,6 +98,23 @@ void topology_set_scale_freq_source(struct scale_freq_data *data,
 }
 EXPORT_SYMBOL_GPL(topology_set_scale_freq_source);
 
+int topology_get_scale_freq_source(int cpu)
+{
+	struct scale_freq_data *sfd;
+	int scale_freq_source;
+
+	rcu_read_lock();
+
+	sfd = rcu_dereference(*per_cpu_ptr(&sft_data, cpu));
+	if (sfd)
+		scale_freq_source = sfd->source;
+
+	rcu_read_unlock();
+
+	return scale_freq_source;
+}
+EXPORT_SYMBOL_GPL(topology_get_scale_freq_source);
+
 void topology_clear_scale_freq_source(enum scale_freq_source source,
 				      const struct cpumask *cpus)
 {
diff --git a/drivers/base/topology.c b/drivers/base/topology.c
index c890e2a5b428..79c0dc8d5361 100644
--- a/drivers/base/topology.c
+++ b/drivers/base/topology.c
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/hardirq.h>
 #include <linux/topology.h>
+#include <linux/arch_topology.h>
 
 #define define_id_show_func(name, fmt)					\
 static ssize_t name##_show(struct device *dev,				\
@@ -226,7 +227,27 @@ static ssize_t cpu_capacity_show(struct device *dev,
 	return sysfs_emit(buf, "%lu\n", topology_get_cpu_scale(cpu->dev.id));
 }
 
+static ssize_t arch_freq_scale_show(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	struct cpu *cpu = container_of(dev, struct cpu, dev);
+
+	return sysfs_emit(buf, "%lu\n", topology_get_freq_scale(cpu->dev.id));
+}
+
+static ssize_t scale_freq_source_show(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	struct cpu *cpu = container_of(dev, struct cpu, dev);
+
+	return sysfs_emit(buf, "%d\n", topology_get_scale_freq_source(cpu->dev.id));
+}
+
 static DEVICE_ATTR_RO(cpu_capacity);
+static DEVICE_ATTR_RO(arch_freq_scale);
+static DEVICE_ATTR_RO(scale_freq_source);
 
 static int cpu_capacity_sysctl_add(unsigned int cpu)
 {
@@ -236,6 +257,8 @@ static int cpu_capacity_sysctl_add(unsigned int cpu)
 		return -ENOENT;
 
 	device_create_file(cpu_dev, &dev_attr_cpu_capacity);
+	device_create_file(cpu_dev, &dev_attr_arch_freq_scale);
+	device_create_file(cpu_dev, &dev_attr_scale_freq_source);
 
 	return 0;
 }
@@ -248,6 +271,8 @@ static int cpu_capacity_sysctl_remove(unsigned int cpu)
 		return -ENOENT;
 
 	device_remove_file(cpu_dev, &dev_attr_cpu_capacity);
+	device_remove_file(cpu_dev, &dev_attr_arch_freq_scale);
+	device_remove_file(cpu_dev, &dev_attr_scale_freq_source);
 
 	return 0;
 }
diff --git a/include/linux/arch_topology.h b/include/linux/arch_topology.h
index d72d6e5aa200..0149aef7b684 100644
--- a/include/linux/arch_topology.h
+++ b/include/linux/arch_topology.h
@@ -47,6 +47,7 @@ struct scale_freq_data {
 
 void topology_scale_freq_tick(void);
 void topology_set_scale_freq_source(struct scale_freq_data *data, const struct cpumask *cpus);
+int topology_get_scale_freq_source(int cpu);
 void topology_clear_scale_freq_source(enum scale_freq_source source, const struct cpumask *cpus);
 
 DECLARE_PER_CPU(unsigned long, hw_pressure);



From wenst at chromium.org  Mon Dec  1 19:31:19 2025
From: wenst at chromium.org (Chen-Yu Tsai)
Date: Tue, 2 Dec 2025 11:31:19 +0800
Subject: Proposal: Officially allow "incomplete" trees as a base
In-Reply-To: <CAD=FV=X5=AK4XMANv+fatn3d9Y5vo9AXsHWb_47HmNaMWUtMwA@mail.gmail.com>
References: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
 <CAD++jLkuRQKoiEN928GtAj7wUts5PxH905bLp6ZhKsJ3NnenEA@mail.gmail.com> <CAD=FV=X5=AK4XMANv+fatn3d9Y5vo9AXsHWb_47HmNaMWUtMwA@mail.gmail.com>
Message-ID: <CAGXv+5HyMYgKmLc+jmkj-gytm9SNVg9dS7Vn3dQ-dsH8Wo+4sg@mail.gmail.com>

On Tue, Dec 2, 2025 at 8:44?AM Doug Anderson <dianders at chromium.org> wrote:
>
> Hi,
>
> On Mon, Dec 1, 2025 at 3:52?PM Linus Walleij <linusw at kernel.org> wrote:
> >
> > Hi Dough,
> >
> > thanks for your mail!
> >
> > Let me just see if I understand correctly what you're trying to
> > do  (and apparently actively doing in production):
>
> Thanks for your thoughts. Just to be clear, even though I've dealt
> with device trees on a lot of ChromeOS boards, this is something that
> _Android_ phones are doing in production and is what I'm focusing on
> here. The whole scheme is at least roughly documented at:
>
> https://source.android.com/docs/core/architecture/dto/partitions
>
> This is all stuff that predates me looking at Android. I'm just coming
> in and trying to make sense of what's there and trying to upstream
> what I can.
>
> Separately, it can be noted that we always _wanted_ a similar solution
> for ChromeOS, but we never quite got there... ;-)

FTR ChromeOS is moving in that direction: splitting SKU differences
based on components into overlays that get applied to the base by the
bootloader.

In the simplest example we could have one base dts and two overlays
for two different DSI panel models:

  - base.dtb
    - panel-model-a.dtbo
    - panel-model-b.dtbo

The problem we then run into is that the base.dtb will only have the
generic model compatible "google,foo", not the sku and revision
specific ones like "google,foo-sku1-rev2".

And we'd really like to avoid having _more_ overlays just to add the
final specific compatible string, as that kind of defeats the purpose
of using overlays to reduce the number of dts files.

I proposed internally maybe having the bootloader fix up the final
compatible string, but I think we need some rough consensus upstream
whether this is acceptable or not.


> > On Tue, Nov 18, 2025 at 11:43?PM Doug Anderson <dianders at chromium.org> wrote:
> >
> > > We would like an officially accepted scheme that lets us more
> > > efficiently ship compiled device trees for a handful of related
> > > products by breaking the device trees up into a common "base" device
> > > tree and then applying "overlay" device trees atop the base to make a
> > > full and complete device tree.
> > (...)
> > > In Android, we do a pretty good job of solving the stated problem
> > > using device tree overlays. We describe the SoCs in "dts" files and
> > > compile them into "dtb"s. We describe boards in "dtso" files and
> > > compile them into "dtbo" files. A bootloader can handle identifying
> > > the correct base and overlay (the scheme for doing this is a separate
> > > but related topic) and applying the overlay atop the base "dtb". This
> > > solution is fully implemented downstream for Android phones and is
> > > well documented [2].
> >
> > So in the kernel we have several arch/*/boot/dts/vendor/ folders
> > where they have:
> >
> > soc.dtsi included by board.dtsi included by system.dts
> > and the top system.dts is all that get compiled.
> >
> > So what you say is that you do the same thing but at runtime?
>
> Essentially. In this case, we don't ship the device tree _sources_ but
> ship _compiled_ device tree. We compile the SoC into a "dtb" and then
> combine anything above the SoC into a single "dtbo". We ship several
> "dtb" files and several "dtbo" files and combine them at runtime after
> we identify which hardware we're running on.
>
>
> > Can you just describe why this is done like this with
> > overlays?
> >
> > I can only guess that you have one bootloader that needs
> > to compose device trees to many systems and the bootloader
> > only discovers the system it is running on and its constraints
> > at runtime, so shipping the static system.dtb as many people
> > do is not an option for you?
> >
> > And the reason the bootloader doesn't already know what
> > it is running on and doesn't just pass that one device tree
> > or is just prepared with that one device tree has something
> > to do with manufacturing or so?
> >
> > Sorry it just evades me.
>
> Our builder creates a single "image" that can be flashed onto any
> number of devices. Users (or manufacturers) can download and install
> this single image and it will work on a wide variety of devices. So
> you can download a single "Pixel 10" image that can be installed on
> any of the Pixel 10 devices (Pixel 10, Pixel 10 Pro, and Pixel 10 Pro
> XL). It will also work on our development board and early
> pre-production variants of those boards.
>
> In order for this to work, we need a lot of device trees and
> _something_ needs to pick the correct one. Right now, the bootloader
> is in charge of this task.
>
> If we had less variety of products that we needed to ship then, yes,
> we could just ship the one device tree and have a separate build for
> each product. ...but that doesn't scale terribly well.
>
>
> > Probably becayse even U-Boot these days use the provided
> > device tree dtb, for the system targeted, to initialize itself. I
> > suppose your bootloader is generic enough to avoid that
> > chicken-and-egg problem, right?
>
> FWIW: I believe even U-boot supports shipping a pile of device trees
> and detecting things at runtime. See the "FIT" image:
>
> https://docs.u-boot.org/en/latest/usage/fit/index.html
>
>
> > I guess if I had this problem:
> >
> > soc.dtsi
> > board-a.dtsi
> > board-b.dtsi
> > system-board-a-v1.dts
> > system-board-a-v2.dts
> > system-board-b-v1.dts
> >
> > etc having to be combined at runtime, in a bootloader, I would
> > consider shipping exactly these files in a memory-based
> > filesystem in my bootloader, and bake a DTS compiler into
> > my bootloader so it can just build a device tree for what
> > it detects.
> >
> > But I guess you didn't want to hear that :D
>
> You're saying to just ship device tree source instead of binary? Hmmm,
> it's an interesting idea. It wouldn't be _terrible_ since "dtb" stores
> a lot of strings to begin with, but I think it would still add enough
> of a bloat to make it a no-go for us... I would also imagine it would
> be a pain to deal with #include of header files with #defines. Do we
> somehow partially pre-process the device tree files but don't apply
> the #include files. It might be possible to solve some specific cases,
> but having this work in a generic way seems miserable.
>
>
> > Anyway, please describe how you ended up in this situation,
> > I'm trying to understand this.
>
> The main goal is just building/shipping one image to support a variety
> of similar products and trying to save space by not repeating the SoC
> bits over and over again.

I think that's a valid goal. ChromeOS ships all DTBs for the same SoC
in a unified kernel FIT image. It used to be all DTBs for the same SoC
vendor (arch/arm64/boot/dts/mediatek/*.dtb), but we ran out of space
on an old device that had a pretty small kernel image partition.

And given that the devices built on one SoC are mostly derived from the
same reference hardware design, maybe 90~95% of the resulting DTBs are
the same. It would be nice to even have the reference design as the base
DTB, but again that would require either having a bunch of DTBOs just
to fix the board compatible, or have the bootloader fix it up.

> > It is quite clear that device tree overlays were intended for
> > say plug-n-play additions and minor fragments to be added
> > to a basically complete device tree, what you are doing was
> > probably not how it was intended. (Or let's see if someone
> > proves me wrong on that.)
>
> Not sure what makes that so clear, since it's not clear to me. In any
> case, even if device tree overlays weren't intended for such a usage,
> they actually seem to work fairly well for it, even if upstream
> currently rejects device tree usage like this.
>
> FWIW, the fact that bootloaders (like U-Boot) have the ability to
> apply overlays makes me think that _someone_ intended them to be used
> similar to how Android is using them. ;-) If it was just expansion
> cards then (presumably) someone would boot to Linux and just apply
> overlays from there. See:
>
> https://docs.u-boot.org/en/latest/usage/fit/overlay-fdt-boot.html

FWIW Simon also mentioned this as a possibility in his "FIT support for
extension boards / overlays" proposal [1], but maybe I'm misreading it.


Thanks
ChenYu

[1] https://lore.kernel.org/all/CAPnjgZ06s64C2ux1rABNAnMv3q4W++sjhNGCO_uPMH_9sTF7Mw at mail.gmail.com/


From mani at kernel.org  Mon Dec  1 20:24:13 2025
From: mani at kernel.org (Manivannan Sadhasivam)
Date: Tue, 2 Dec 2025 09:54:13 +0530
Subject: linux-next: Tree for Nov 28
 (drivers/pci/controller/dwc/pcie-nxp-s32g.o)
In-Reply-To: <63e1daf7-f9a3-463e-8a1b-e9b72581c7af@infradead.org>
References: <20251128162928.36eec2d6@canb.auug.org.au>
 <63e1daf7-f9a3-463e-8a1b-e9b72581c7af@infradead.org>
Message-ID: <ykmo5qv46mo7f3srblxoi2fvghz722fj7kpm77ozpflaqup6rk@ttvhbw445pgu>

+ Vincent

On Sat, Nov 29, 2025 at 07:00:04PM -0800, Randy Dunlap wrote:
> 
> 
> On 11/27/25 9:29 PM, Stephen Rothwell wrote:
> > Hi all,
> > 
> > Changes since 20251127:
> > 
> 
> on i386 (allmodconfig):
> 
> WARNING: modpost: vmlinux: section mismatch in reference: s32g_init_pcie_controller+0x2b (section: .text) -> memblock_start_of_DRAM (section: .init.text)
> 
> 
> -- 
> ~Randy
> 
> 

-- 
????????? ????????


From sunilvl at ventanamicro.com  Mon Dec  1 20:28:11 2025
From: sunilvl at ventanamicro.com (Sunil V L)
Date: Tue, 2 Dec 2025 09:58:11 +0530
Subject: [PATCH v7 08/17] ACPI: pci_link: Clear the dependencies after
 probe
In-Reply-To: <20251201141230.12656-1-huyuye812@163.com>
References: <20240729142241.733357-9-sunilvl@ventanamicro.com>
 <20251201141230.12656-1-huyuye812@163.com>
Message-ID: <aS5q28HPYLzK6h8r@sunil-laptop>

On Mon, Dec 01, 2025 at 10:12:29PM +0800, huyuye wrote:
> > Hi, sunilvl
> 
> > Based on the above patch, I understand that you previously >resolved dependencies between Link devices and PCI Host Bridges by >calling acpi_dev_clear_dependencies(device). I would like to ask: >on RISC?V platforms, if we need to manage dependencies between >multiple PCI Host Bridges, could this be addressed by adding a >call to acpi_dev_clear_dependencies(device) at the end of the >acpi_pci_root_add enumeration function?
> 
> > Initialization order dependencies can be defined via the ACPI >_DEP method in the DSDT. For example, if host bridge B depends on >host bridge A, bridge B should not be enumerated until bridge A is >fully initialized.
> 
> > Yes, that should work.
> > Regards,
> > Sunil
> 
> Hi,Sunil
> 
> I'm truly honored by your affirmation of my answer.Do you think this solution has a chance of being accepted into the upstream kernel? Are there any unintended side effects we may have overlooked?
> 
Acceptance of this solution depends on the PCI/ACPI maintainers. To help
them evaluate it, you should clearly describe why your platform requires
this dependency in the patch.

Regards
Sunil


From christianshewitt at gmail.com  Mon Dec  1 20:40:47 2025
From: christianshewitt at gmail.com (Christian Hewitt)
Date: Tue, 2 Dec 2025 08:40:47 +0400
Subject: [PATCH] wifi: mt7601u: check multiple firmware paths
In-Reply-To: <20251201103529.1874a869@kernel.org>
References: <20251201090336.1157193-1-christianshewitt@gmail.com>
 <20251201103529.1874a869@kernel.org>
Message-ID: <CD5CBB8A-2829-4436-9DA0-D1A88D594E92@gmail.com>

> On 1 Dec 2025, at 10:35?pm, Jakub Kicinski <kuba at kernel.org> wrote:
> 
> On Mon,  1 Dec 2025 09:03:36 +0000 Christian Hewitt wrote:
>> The linux-firmware repo moved mt7601u.bin from the root folder to
>> the mediatek sub-folder some time ago, but not all distros create
>> symlinks to the old location the driver checks. Update the driver
>> to check for firmware in both old and new locations.
> 
> IDK.. 2.5 years ago.. how long is too long to wait for the distros 
> to update their linux-firmware?


If compatibility with older firmware locations is no longer a concern the
previous patch submitted by Daniel is valid. If compatibility is desirable
this patch is valid. I?m not fussed which one gets merged, as long as
one of them is so the distro I maintain doesn?t need to patch the driver
to use the ?new? location (our buildsystem doesn?t process WHENCE
which adds a symlink back to the old location the driver still uses).

Christian

From youngmin.nam at samsung.com  Mon Dec  1 21:23:25 2025
From: youngmin.nam at samsung.com (Youngmin Nam)
Date: Tue, 2 Dec 2025 14:23:25 +0900
Subject: [RFT PATCH v2 0/5] pinctrl: samsung: exynos9 cleanups and fixes
In-Reply-To: <CADrjBPrPpgy93At1bBanBoka14eyRbAArep5zuvbGWcOEnOuRQ@mail.gmail.com>
References: <CGME20251117073601epcas2p2c72bdd8689a69b35b988894653300c75@epcas2p2.samsung.com>
	<20251117074140.4090939-1-youngmin.nam@samsung.com>
	<CADrjBPrPpgy93At1bBanBoka14eyRbAArep5zuvbGWcOEnOuRQ@mail.gmail.com>
Message-ID: <833ba1e9-bf5e-41f1-a319-06521d598e5c@samsung.com>

On 11/25/25 02:42, Peter Griffin wrote:
> Hi Youngmin,
> 
> On Mon, 17 Nov 2025 at 07:36, Youngmin Nam <youngmin.nam at samsung.com> wrote:
>>
>> Several SoCs carried near-duplicate pin bank macro families, making
>> tables verbose and hard to share when only the bank type (alive/off)
>> differs.
>>
>> GS101 had its own helpers even though the newer EXYNOS9_* helpers cover
>> the same semantics, including per-bank filter control (FLTCON) offsets.
>>
>> Some pin-bank tables didn't match the SoC TRMs (bank type, EINT class,
>> or bank names), and FLTCON wasn't always at a contiguous offset from
>> EINT.
>>
>> This series does
>> - Consolidate on EXYNOS9_* pin-bank macros. Pass bank_type explicitly.
>> - Fix table errors on Exynos2200/7885/8890/8895 per TRM.
>> - Add explicit per-bank FLTCON offsets and update affected tables.
>> - Drop GS101-specific macros in favor of EXYNOS9_*.
>> - Rename gs101_pinctrl_{suspend,resume} ->
>>   exynos9_pinctrl_{suspend,resume}.
>>
>> This series was based on the pinctrl/samsung tree [1].
>>
>> I tested on Exynos850 through boot and verified the pin values as
>> follows:
> 
> One thing I just noticed is exynos850_pin_ctrl isn't actually setting
> the .suspend and .resume callbacks so some of this code won't be
> executed there (specifically saving/restoring the fltcon register). If
> you're using e850 platform to test this series, you likely want to set
> 
> .suspend = exynos9_pinctrl_suspend,
> .resume = exynos9_pinctrl_resume,
> 
> in exynos850_pin_ctrl for the alive bank
> 
> You can then #define DEBUG in drivers/pinctrl/samsung/pinctrl-exynos.c
> 
> Recompile, and do
> 
> echo platform > /sys/power/pm_test
> echo mem > /sys/power/state
> 
> and you should see all the debug from the newly enabled exynos9
> suspend/resume callbacks
> 
> [  871.104840][  T741] gph2: save     con 0x00000000
> [  871.104932][  T741] gph2: save fltcon0 0x00000000
> [  871.105022][  T741] gph2: save fltcon1 0x00000000
> [  871.105109][  T741] gph2: save    mask 0x0000003f
> <snip>
> 
> Prior to adding fltcon_offset and the gs101 (now exynos9) specific
> suspend/resume callbacks this would generate a SError on gs101
> 
> Thanks,
> 
> Peter

Hi Peter,

Thanks for the review and testing.
Your tips on suspend/resume for Exynos850 and the GS101 details are very helpful.
After this series is merged, I will add the exynos9_pinctrl_suspend and _resume hooks for Exynos850 and run the tests you suggested.

Thanks,
Youngmin
 


From baolin.wang at linux.alibaba.com  Mon Dec  1 21:37:59 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Tue, 2 Dec 2025 13:37:59 +0800
Subject: [PATCH 0/2] support batched checks of the references for large
 folios
In-Reply-To: <341d1aed-13ad-41ee-ad30-487c5baec399@kernel.org>
References: <cover.1763976541.git.baolin.wang@linux.alibaba.com>
 <341d1aed-13ad-41ee-ad30-487c5baec399@kernel.org>
Message-ID: <a2b43faf-cf33-41e5-8997-e4a0471ec3ec@linux.alibaba.com>



On 2025/12/2 00:23, David Hildenbrand (Red Hat) wrote:
> On 11/25/25 01:56, Baolin Wang wrote:
>> Currently, folio_referenced_one() always checks the young flag for 
>> each PTE
>> sequentially, which is inefficient for large folios. This inefficiency is
>> especially noticeable when reclaiming clean file-backed large folios, 
>> where
>> folio_referenced() is observed as a significant performance hotspot.
>>
>> Moreover, on Arm architecture, which supports contiguous PTEs, there 
>> is already
>> an optimization to clear the young flags for PTEs within a contiguous 
>> range.
>> However, this is not sufficient. We can extend this to perform batched 
>> operations
>> for the entire large folio (which might exceed the contiguous range: 
>> CONT_PTE_SIZE).
>>
>> By supporting batched checking of the young flags and flushing TLB 
>> entries,
>> I observed a 33% performance improvement in my file-backed folios 
>> reclaim tests.
> 
> Can you point at the benchmark or briefly explain what it does? What 
> exactly are we measuring that improves by 33%?

Sorry for not being clear. I've described the performance test in patch 
2, and I should have copied it to the cover letter:

"
Performance testing:
Allocate 10G clean file-backed folios by mmap() in a memory cgroup, and 
try to reclaim 8G file-backed folios via the memory.reclaim interface. I 
can observe 33% performance improvement on my Arm64 32-core server (and 
10%+ improvement on my X86 machine). Meanwhile, the hotspot 
folio_check_references() dropped from approximately 35% to around 5%.

W/o patchset:
real	0m1.518s
user	0m0.000s
sys	0m1.518s

W/ patchset:
real	0m1.018s
user	0m0.000s
sys	0m1.018s
"


From ying.huang at linux.alibaba.com  Mon Dec  1 21:42:17 2025
From: ying.huang at linux.alibaba.com (Huang, Ying)
Date: Tue, 02 Dec 2025 13:42:17 +0800
Subject: [v2 PATCH] arm64: mm: Fix kexec failure after
 pte_mkwrite_novma() change
In-Reply-To: <20251202022707.2720933-1-jianpeng.chang.cn@windriver.com>
	(Jianpeng Chang's message of "Tue, 2 Dec 2025 10:27:07 +0800")
References: <20251202022707.2720933-1-jianpeng.chang.cn@windriver.com>
Message-ID: <87qztdh22u.fsf@DESKTOP-5N7EMDA>

Jianpeng Chang <jianpeng.chang.cn at windriver.com> writes:

> Commit 143937ca51cc ("arm64, mm: avoid always making PTE dirty in
> pte_mkwrite()") modified pte_mkwrite_novma() to only clear PTE_RDONLY
> when the page is already dirty (PTE_DIRTY is set). While this optimization
> prevents unnecessary dirty page marking in normal memory management paths,
> it breaks kexec on some platforms like NXP LS1043.
>
> The issue occurs in the kexec code path:
> 1. machine_kexec_post_load() calls trans_pgd_create_copy() to create a
>    writable copy of the linear mapping
> 2. _copy_pte() calls pte_mkwrite_novma() to ensure all pages in the copy
>    are writable for the new kernel image copying
> 3. With the new logic, clean pages (without PTE_DIRTY) remain read-only
> 4. When kexec tries to copy the new kernel image through the linear
>    mapping, it fails on read-only pages, causing the system to hang
>    after "Bye!"
>
> The same issue affects hibernation which uses the same trans_pgd code path.
>
> Fix this by explicitly clearing PTE_RDONLY in _copy_pte() for both
> kexec and hibernation, ensuring all pages in the temporary mapping are
> writable regardless of their dirty state. This preserves the original
> commit's optimization for normal memory management while fixing the
> kexec/hibernation regression.
>
> Fixes: 143937ca51cc ("arm64, mm: avoid always making PTE dirty in pte_mkwrite()")
> Signed-off-by: Jianpeng Chang <jianpeng.chang.cn at windriver.com>

LGTM, Thanks!  Feel free to add my

Reviewed-by: Huang Ying <ying.huang at linux.alibaba.com>

in the future versions.

> ---
> v2:
>   - Use pte_mkwrite_novma(pte_mkdirty(pte)) instead of manual bit manipulation
>   - Updated comments to clarify pte_mkwrite_novma() alone cannot be used
> v1: https://lore.kernel.org/all/20251127034350.3600454-1-jianpeng.chang.cn at windriver.com/
>
>  arch/arm64/mm/trans_pgd.c | 9 +++++++--
>  1 file changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm64/mm/trans_pgd.c b/arch/arm64/mm/trans_pgd.c
> index 18543b603c77..08f5ee6643e1 100644
> --- a/arch/arm64/mm/trans_pgd.c
> +++ b/arch/arm64/mm/trans_pgd.c
> @@ -40,8 +40,13 @@ static void _copy_pte(pte_t *dst_ptep, pte_t *src_ptep, unsigned long addr)
>  		 * Resume will overwrite areas that may be marked
>  		 * read only (code, rodata). Clear the RDONLY bit from
>  		 * the temporary mappings we use during restore.
> +		 *
> +		 * For kexec/hibernation, we need writable access to all
> +		 * pages in the linear mapping to copy the new kernel image.
> +		 * Mark pages dirty first to ensure pte_mkwrite_novma()
> +		 * clears PTE_RDONLY.
>  		 */
> -		__set_pte(dst_ptep, pte_mkwrite_novma(pte));
> +		__set_pte(dst_ptep, pte_mkwrite_novma(pte_mkdirty(pte)));
>  	} else if (!pte_none(pte)) {
>  		/*
>  		 * debug_pagealloc will removed the PTE_VALID bit if
> @@ -57,7 +62,7 @@ static void _copy_pte(pte_t *dst_ptep, pte_t *src_ptep, unsigned long addr)
>  		 */
>  		BUG_ON(!pfn_valid(pte_pfn(pte)));
>  
> -		__set_pte(dst_ptep, pte_mkvalid(pte_mkwrite_novma(pte)));
> +		__set_pte(dst_ptep, pte_mkvalid(pte_mkwrite_novma(pte_mkdirty(pte))));
>  	}
>  }

---
Best Regards,
Huang, Ying


From haibo.chen at nxp.com  Mon Dec  1 22:04:33 2025
From: haibo.chen at nxp.com (Haibo Chen)
Date: Tue, 02 Dec 2025 14:04:33 +0800
Subject: [PATCH v2] arm64: dts: imx93-9x9-qsb: add CAN support overlay file
Message-ID: <20251202-b4-9391-can-dts-v2-1-edab562615a7@nxp.com>

CAN1 and Micfil share pins on imx93-9x9-qsb board, use TMUX1574RSVR
to control the connection: put sel to high, select CAN1, put sel to
low, select Micfil. In default, sel keep low.

To support CAN1, need to put the sel to high. Besides, CAN1 use phy
TJA1057GT/3.

---
Signed-off-by: Haibo Chen <haibo.chen at nxp.com>
---
Changes in v2:
- change commit title
- Keep order by alphabet in Makefile
- Link to v1: https://lore.kernel.org/r/20251126-b4-9391-can-dts-v1-1-c23145f0d2db at nxp.com
---
 arch/arm64/boot/dts/freescale/Makefile             |  2 +
 .../boot/dts/freescale/imx93-9x9-qsb-can1.dtso     | 63 ++++++++++++++++++++++
 2 files changed, 65 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index f30d3fd724d0ce6b38f7bef10e3970ac34f70f4a..e15a7b216c5c6753c39ab02801d82f23255b8e63 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -372,7 +372,9 @@ dtb-$(CONFIG_ARCH_MXC) += imx91-phyboard-segin.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx91-tqma9131-mba91xxca.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx93-9x9-qsb.dtb
 
+imx93-9x9-qsb-can1-dtbs += imx93-9x9-qsb.dtb imx93-9x9-qsb-can1.dtbo
 imx93-9x9-qsb-i3c-dtbs += imx93-9x9-qsb.dtb imx93-9x9-qsb-i3c.dtbo
+dtb-$(CONFIG_ARCH_MXC) += imx93-9x9-qsb-can1.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx93-9x9-qsb-i3c.dtb
 
 dtb-$(CONFIG_ARCH_MXC) += imx93-11x11-evk.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-can1.dtso b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-can1.dtso
new file mode 100644
index 0000000000000000000000000000000000000000..0bf1e9d4bad2ec540d71470fcebc64a82072b41d
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-can1.dtso
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2025 NXP
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include "imx93-pinfunc.h"
+
+/dts-v1/;
+/plugin/;
+
+&{/} {
+	flexcan_phy: can-phy {
+		compatible = "nxp,tja1057";
+		#phy-cells = <0>;
+		max-bitrate = <5000000>;
+		silent-gpios = <&pcal6524 23 GPIO_ACTIVE_HIGH>;
+	};
+};
+
+&flexcan1 {
+	phys = <&flexcan_phy>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_flexcan1>;
+	status = "okay";
+};
+
+&iomuxc {
+	pinctrl_flexcan1: flexcan1grp {
+		fsl,pins = <
+			MX93_PAD_PDM_CLK__CAN1_TX		0x139e
+			MX93_PAD_PDM_BIT_STREAM0__CAN1_RX	0x139e
+		>;
+	};
+};
+
+/* micfi1 use the A port, conflict with can1 */
+&micfil {
+	status = "disabled";
+};
+
+&pcal6524 {
+	/*
+	 * mic-can-sel-hog have property 'output-low', dt overlay don't
+	 * support /delete-property/. Both 'output-low' and 'output-high'
+	 * will be exist under hog nodes if overlay file set 'output-high'.
+	 * Workaround is disable this hog and create new hog with
+	 * 'output-high'.
+	 */
+	mic-can-sel-hog {
+		status = "disabled";
+	};
+
+	/*
+	 * Config the MIC/CAN_SEL to high, chose B
+	 * port, connect to CAN.
+	 */
+	mic-can-high-sel-hog {
+		gpio-hog;
+		gpios = <0x11 0x00>;
+		output-high;
+	};
+};

---
base-commit: 422f3140bbcb657e1b86c484296972ab76f6d1ff
change-id: 20251125-b4-9391-can-dts-2f4849978fc2

Best regards,
-- 
Haibo Chen <haibo.chen at nxp.com>



From wangmin at phytium.com.cn  Mon Dec  1 22:39:27 2025
From: wangmin at phytium.com.cn (=?UTF-8?B?546L5pWP?=)
Date: Tue, 2 Dec 2025 14:39:27 +0800 (GMT+08:00)
Subject: [PATCH] media: aspeed: Fix dram hang at res-change
In-Reply-To: <TYZPR06MB656876892F6046F22AD87073F1DBA@TYZPR06MB6568.apcprd06.prod.outlook.com>
References: <20251124-video_dram_reset-v1-1-9d37229e4ec5@aspeedtech.com>
 <120162b9.3256.19aca13d4e0.Coremail.wangmin@phytium.com.cn>
 <TYZPR06MB656876892F6046F22AD87073F1DBA@TYZPR06MB6568.apcprd06.prod.outlook.com>
Message-ID: <720c855b.36b0.19addc99578.Coremail.wangmin@phytium.com.cn>




> -----????-----
> ???: "Jammy Huang" <jammy_huang at aspeedtech.com>
> ????:2025-12-01 09:34:25 (???)
> ???: ?? <wangmin at phytium.com.cn>
> ??: "Eddie James" <eajames at linux.ibm.com>, "Mauro Carvalho Chehab" <mchehab at kernel.org>, "Joel Stanley" <joel at jms.id.au>, "Andrew Jeffery" <andrew at codeconstruct.com.au>, "Philipp Zabel" <p.zabel at pengutronix.de>, "linux-media at vger.kernel.org" <linux-media at vger.kernel.org>, "openbmc at lists.ozlabs.org" <openbmc at lists.ozlabs.org>, "linux-arm-kernel at lists.infradead.org" <linux-arm-kernel at lists.infradead.org>, "linux-aspeed at lists.ozlabs.org" <linux-aspeed at lists.ozlabs.org>, "linux-kernel at vger.kernel.org" <linux-kernel at vger.kernel.org>, ??? <shuyiqi at phytium.com.cn>
> ??: RE: [PATCH] media: aspeed: Fix dram hang at res-change
> 
> Hi Wang,
> 
> Thanks for your feedback.
> 
> Regards,
> Jammy Huang
> 
> > >
> > > Dram hang could happen in the steps below:
> > > 1. start capture/compression
> > > 2. out-of-lock watchdog raise irq because of res-change.
> > > 3. aspeed_video_irq_res_change do clk-off
> > >
> > > At step3, capture/compression could be not accomplished yet. If
> > > clk-off in the middle of video operation, dram controller could hang at
> > ast2500.
> > >
> > > Use reset rather than clk-off/on to avoid this problem.
> > >
> > > Signed-off-by: Jammy Huang <jammy_huang at aspeedtech.com>
> > > ---
> > > On Aspeed KVM testing, we found it could lead to dram-hang if
> > > res-change. Although the issue rarely happens, the impact is serious.
> > 
> > Capturing and compressing the video stream takes longer than the video
> > engine?s idle period.
> Sorry, but this is not what I mean. The issue happens because video engine's clk
> is turned off during capture/compression.
> 
> > If this is not the intended behavior, please increase the frame rate. This makes
> > resolution switches more prone to happen when the video engine is working.
> > However, according to your email, this issue rarely occurs. Is there a similar
> > issue on the AST2600 SoC?
> Increase frame rate would not helpful. This is a video compression engine. The time taken
> for each frame's capture/compression is the same. The way to reproduce this issue
> we did is continuously resolution-switch.
>
Thank you for the clarification.

I am encountering another issue related to resolution switching on the AST2500 SoC. 
When repeatedly switching from other resolutions to 1680x1050, or from 1680x1050 to 
other resolutions, there is a high likelihood that either the BMC OS will hang or 
the KVM screen will experience tearing. Could you please attempt to reproduce this 
issue and provide a resolution?

> > 
> > >
> > > To avoid this issue, we use reset only rathar than clk-off/on in
> > > res-change to avoid this issue.
> > > ---
> > >  drivers/media/platform/aspeed/aspeed-video.c | 22
> > > +++++++++++++++++++---
> > >  1 file changed, 19 insertions(+), 3 deletions(-)
> > >
> > > diff --git a/drivers/media/platform/aspeed/aspeed-video.c
> > > b/drivers/media/platform/aspeed/aspeed-video.c
> > > index b83e432452..41cb96f601 100644
> > > --- a/drivers/media/platform/aspeed/aspeed-video.c
> > > +++ b/drivers/media/platform/aspeed/aspeed-video.c
> > > @@ -26,6 +26,7 @@
> > >  #include <linux/workqueue.h>
> > >  #include <linux/debugfs.h>
> > >  #include <linux/ktime.h>
> > > +#include <linux/reset.h>
> > >  #include <linux/regmap.h>
> > >  #include <linux/mfd/syscon.h>
> > >  #include <media/v4l2-ctrls.h>
> > > @@ -310,6 +311,7 @@ struct aspeed_video {
> > >  	void __iomem *base;
> > >  	struct clk *eclk;
> > >  	struct clk *vclk;
> > > +	struct reset_control *reset;
> > >
> > >  	struct device *dev;
> > >  	struct v4l2_ctrl_handler ctrl_handler; @@ -720,6 +722,13 @@ static
> > > void aspeed_video_on(struct aspeed_video *video)
> > >  	set_bit(VIDEO_CLOCKS_ON, &video->flags);  }
> > >
> > > +static void aspeed_video_reset(struct aspeed_video *v) {
> > > +	reset_control_assert(v->reset);
> > > +	usleep_range(100, 150);
> > > +	reset_control_deassert(v->reset);
> > > +}
> > > +
> > >  static void aspeed_video_bufs_done(struct aspeed_video *video,
> > >  				   enum vb2_buffer_state state)
> > >  {
> > > @@ -742,7 +751,9 @@ static void aspeed_video_irq_res_change(struct
> > > aspeed_video *video, ulong delay)
> > >
> > >  	video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL;
> > >
> > > -	aspeed_video_off(video);
> > > +	aspeed_video_write(video, VE_INTERRUPT_CTRL, 0);
> > > +	aspeed_video_write(video, VE_INTERRUPT_STATUS, 0xffffffff);
> > > +	aspeed_video_reset(video);
> > >  	aspeed_video_bufs_done(video, VB2_BUF_STATE_ERROR);
> > >
> > >  	schedule_delayed_work(&video->res_work, delay); @@ -1984,8 +1995,7
> > > @@ static void aspeed_video_stop_streaming(struct vb2_queue *q)
> > >  		 * Need to force stop any DMA and try and get HW into a good
> > >  		 * state for future calls to start streaming again.
> > >  		 */
> > > -		aspeed_video_off(video);
> > > -		aspeed_video_on(video);
> > > +		aspeed_video_reset(video);
> > >
> > >  		aspeed_video_init_regs(video);
> > >
> > > @@ -2230,6 +2240,12 @@ static int aspeed_video_init(struct aspeed_video
> > *video)
> > >  	}
> > >  	dev_info(video->dev, "irq %d\n", irq);
> > >
> > > +	video->reset = devm_reset_control_get(dev, NULL);
> > > +	if (IS_ERR(video->reset)) {
> > > +		dev_err(dev, "Unable to get reset\n");
> > > +		return PTR_ERR(video->reset);
> > > +	}
> > > +
> > >  	video->eclk = devm_clk_get(dev, "eclk");
> > >  	if (IS_ERR(video->eclk)) {
> > >  		dev_err(dev, "Unable to get ECLK\n");
> > >
> > > ---
> > > base-commit: ac3fd01e4c1efce8f2c054cdeb2ddd2fc0fb150d
> > > change-id: 20251124-video_dram_reset-c531f6ba573f
> > >
> > > Best regards,
> > > --
> > > Jammy Huang <jammy_huang at aspeedtech.com>
> > >
> > 


????????????????????????,??????????????????????????,?????????,???????????????????????
Information Security Notice: The information contained in this mail is solely property of the sender's organization.This mail communication is confidential.Recipients named above are obligated to maintain secrecy and are not permitted to disclose the contents of this communication to others.

From stefan.klug at ideasonboard.com  Mon Dec  1 22:42:36 2025
From: stefan.klug at ideasonboard.com (Stefan Klug)
Date: Tue, 02 Dec 2025 07:42:36 +0100
Subject: [PATCH v1 1/1] media: rkisp1: Fix filter mode register configuration
In-Reply-To: <20251202015025.601549-2-rui.wang@ideasonboard.com>
References: <20251202015025.601549-1-rui.wang@ideasonboard.com> <20251202015025.601549-2-rui.wang@ideasonboard.com>
Message-ID: <176465775606.135635.13034018447792643478@localhost>

Hi Rui,

Thank you for the patch.

Quoting Rui Wang (2025-12-02 02:50:25)
> The rkisp1_flt_config() function performs an initial direct write to
> RKISP1_CIF_ISP_FILT_MODE without including the RKISP1_CIF_ISP_FLT_ENA
> bit, which clears the filter enable bit in the hardware.

That sentence is a bit hard for me to understand. Maybe:

"The rkisp1_flt_config() function overwrites RKISP1_CIF_ISP_FILT_MODE
without preserving the RKISP1_CIF_ISP_FLT_ENA bit thereby unconditionally
disabling the hardware block on reconfiguration.

But as I'm no native speaker you could maybe wait for feedback from a
native speaker.

Functionality wise the change is correct.

Reviewed-by: Stefan Klug <stefan.klug at ideasonboard.com>

Best regards,
Stefan

> 
> The subsequent read/modify/write sequence then reads back the register
> with the enable bit already cleared and cannot restore it, resulting in
> the filter being inadvertently disabled.
> 
> Remove the redundant direct write. The read/modify/write sequence alone
> correctly preserves the existing enable bit state while updating the
> DNR mode and filter configuration bits.
> 
> Signed-off-by: Rui Wang <rui.wang at ideasonboard.com>
> ---
>  drivers/media/platform/rockchip/rkisp1/rkisp1-params.c | 6 ------
>  1 file changed, 6 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
> index c9f88635224c..6442436a5e42 100644
> --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
> +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
> @@ -411,12 +411,6 @@ static void rkisp1_flt_config(struct rkisp1_params *params,
>         rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_LUM_WEIGHT,
>                      arg->lum_weight);
>  
> -       rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_MODE,
> -                    (arg->mode ? RKISP1_CIF_ISP_FLT_MODE_DNR : 0) |
> -                    RKISP1_CIF_ISP_FLT_CHROMA_V_MODE(arg->chr_v_mode) |
> -                    RKISP1_CIF_ISP_FLT_CHROMA_H_MODE(arg->chr_h_mode) |
> -                    RKISP1_CIF_ISP_FLT_GREEN_STAGE1(arg->grn_stage1));
> -
>         /* avoid to override the old enable value */
>         filt_mode = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_FILT_MODE);
>         filt_mode &= RKISP1_CIF_ISP_FLT_ENA;
> -- 
> 2.43.0
>


From yingchao.deng at oss.qualcomm.com  Mon Dec  1 22:42:19 2025
From: yingchao.deng at oss.qualcomm.com (Yingchao Deng)
Date: Tue, 02 Dec 2025 14:42:19 +0800
Subject: [PATCH v6 0/2] Add Qualcomm extended CTI support
Message-ID: <20251202-extended_cti-v6-0-ab68bb15c4f5@oss.qualcomm.com>

The QCOM extended CTI is a heavily parameterized version of ARM?s CSCTI.
It allows a debugger to send to trigger events to a processor or to send
a trigger event to one or more processors when a trigger event occurs on
another processor on the same SoC, or even between SoCs.

QCOM extended CTI supports up to 128 triggers. And some of the register
offsets are changed.

The commands to configure CTI triggers are the same as ARM's CTI.

Changes in v6:
1. Rename regs_idx to ext_reg_sel and add information in documentation
   file.
2. Reset CLAIMSET to zero for qcom-cti during probe.
3. Retrieve idx value under spinlock.
4. Use yearless copyright for qcom-cti.h.
Link to v5 - https://lore.kernel.org/all/20251020-extended_cti-v5-0-6f193da2d467 at oss.qualcomm.com/

Changes in v5:
1. Move common part in qcom-cti.h to coresight-cti.h.
2. Convert trigger usage fields to dynamic bitmaps and arrays.
3. Fix holes in struct cti_config to save some space.
4. Revert the previous changes related to the claim tag in
   cti_enable/disable_hw.
Link to v4 - https://lore.kernel.org/linux-arm-msm/20250902-extended_cti-v4-1-7677de04b416 at oss.qualcomm.com/

Changes in v4:
1. Read the DEVARCH registers to identify Qualcomm CTI.
2. Add a reg_idx node, and refactor the coresight_cti_reg_show() and
coresight_cti_reg_store() functions accordingly.
3. The register offsets specific to Qualcomm CTI are moved to qcom_cti.h.
Link to v3 - https://lore.kernel.org/linux-arm-msm/20250722081405.2947294-1-quic_jinlmao at quicinc.com/

Changes in v3:
1. Rename is_extended_cti() to of_is_extended_cti().
2. Add the missing 'i' when write the CTI trigger registers.
3. Convert the multi-line output in sysfs to single line.
4. Initialize offset arrays using designated initializer.
Link to V2 - https://lore.kernel.org/all/20250429071841.1158315-3-quic_jinlmao at quicinc.com/

Changes in V2:
1. Add enum for compatible items.
2. Move offset arrays to coresight-cti-core

Signed-off-by: Jinlong Mao <jinlong.mao at oss.qualcomm.com>
Signed-off-by: Yingchao Deng <yingchao.deng at oss.qualcomm.com>
---
Yingchao Deng (2):
      coresight: cti: Convert trigger usage fields to dynamic bitmaps and arrays
      coresight: cti: Add Qualcomm extended CTI support

 .../ABI/testing/sysfs-bus-coresight-devices-cti    |  11 ++
 drivers/hwtracing/coresight/coresight-cti-core.c   | 153 ++++++++++++++---
 .../hwtracing/coresight/coresight-cti-platform.c   |  16 +-
 drivers/hwtracing/coresight/coresight-cti-sysfs.c  | 187 ++++++++++++++++-----
 drivers/hwtracing/coresight/coresight-cti.h        |  60 ++++++-
 drivers/hwtracing/coresight/qcom-cti.h             |  29 ++++
 6 files changed, 369 insertions(+), 87 deletions(-)
---
base-commit: 7d31f578f3230f3b7b33b0930b08f9afd8429817
change-id: 20251128-extended_cti-3ba8576629f7

Best regards,
-- 
Yingchao Deng <yingchao.deng at oss.qualcomm.com>



From yingchao.deng at oss.qualcomm.com  Mon Dec  1 22:42:20 2025
From: yingchao.deng at oss.qualcomm.com (Yingchao Deng)
Date: Tue, 02 Dec 2025 14:42:20 +0800
Subject: [PATCH v6 1/2] coresight: cti: Convert trigger usage fields to
 dynamic bitmaps and arrays
In-Reply-To: <20251202-extended_cti-v6-0-ab68bb15c4f5@oss.qualcomm.com>
References: <20251202-extended_cti-v6-0-ab68bb15c4f5@oss.qualcomm.com>
Message-ID: <20251202-extended_cti-v6-1-ab68bb15c4f5@oss.qualcomm.com>

Replace the fixed-size u32 fields in the cti_config and cti_trig_grp
structure with dynamically allocated bitmaps and arrays. This allows
memory to be allocated based on the actual number of triggers during probe
time, reducing memory footprint and improving scalability for platforms
with varying trigger counts.
Additionally, repack struct cti_config to reduce its size from 80 bytes to
72 bytes.

Signed-off-by: Yingchao Deng <yingchao.deng at oss.qualcomm.com>
---
 drivers/hwtracing/coresight/coresight-cti-core.c   | 58 ++++++++++++++++------
 .../hwtracing/coresight/coresight-cti-platform.c   | 16 +++---
 drivers/hwtracing/coresight/coresight-cti-sysfs.c  | 10 ++--
 drivers/hwtracing/coresight/coresight-cti.h        | 17 ++++---
 4 files changed, 65 insertions(+), 36 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c
index bfbc365bb2ef..f9970e40dd59 100644
--- a/drivers/hwtracing/coresight/coresight-cti-core.c
+++ b/drivers/hwtracing/coresight/coresight-cti-core.c
@@ -214,8 +214,8 @@ void cti_write_intack(struct device *dev, u32 ackval)
 /* DEVID[19:16] - number of CTM channels */
 #define CTI_DEVID_CTMCHANNELS(devid_val) ((int) BMVAL(devid_val, 16, 19))
 
-static void cti_set_default_config(struct device *dev,
-				   struct cti_drvdata *drvdata)
+static int cti_set_default_config(struct device *dev,
+				  struct cti_drvdata *drvdata)
 {
 	struct cti_config *config = &drvdata->config;
 	u32 devid;
@@ -234,12 +234,33 @@ static void cti_set_default_config(struct device *dev,
 		config->nr_trig_max = CTIINOUTEN_MAX;
 	}
 
+	config->trig_in_use = devm_bitmap_zalloc(dev, config->nr_trig_max, GFP_KERNEL);
+	if (!config->trig_in_use)
+		return -ENOMEM;
+
+	config->trig_out_use = devm_bitmap_zalloc(dev, config->nr_trig_max, GFP_KERNEL);
+	if (!config->trig_out_use)
+		return -ENOMEM;
+
+	config->trig_out_filter = devm_bitmap_zalloc(dev, config->nr_trig_max, GFP_KERNEL);
+	if (!config->trig_out_filter)
+		return -ENOMEM;
+
+	config->ctiinen = devm_kcalloc(dev, config->nr_trig_max, sizeof(u32), GFP_KERNEL);
+	if (!config->ctiinen)
+		return -ENOMEM;
+
+	config->ctiouten = devm_kcalloc(dev, config->nr_trig_max, sizeof(u32), GFP_KERNEL);
+	if (!config->ctiouten)
+		return -ENOMEM;
+
 	config->nr_ctm_channels = CTI_DEVID_CTMCHANNELS(devid);
 
 	/* Most regs default to 0 as zalloc'ed except...*/
 	config->trig_filter_enable = true;
 	config->ctigate = GENMASK(config->nr_ctm_channels - 1, 0);
 	config->enable_req_count = 0;
+	return 0;
 }
 
 /*
@@ -270,8 +291,10 @@ int cti_add_connection_entry(struct device *dev, struct cti_drvdata *drvdata,
 	cti_dev->nr_trig_con++;
 
 	/* add connection usage bit info to overall info */
-	drvdata->config.trig_in_use |= tc->con_in->used_mask;
-	drvdata->config.trig_out_use |= tc->con_out->used_mask;
+	bitmap_or(drvdata->config.trig_in_use, drvdata->config.trig_in_use,
+		  tc->con_in->used_mask, drvdata->config.nr_trig_max);
+	bitmap_or(drvdata->config.trig_out_use, drvdata->config.trig_out_use,
+		  tc->con_out->used_mask, drvdata->config.nr_trig_max);
 
 	return 0;
 }
@@ -293,12 +316,20 @@ struct cti_trig_con *cti_allocate_trig_con(struct device *dev, int in_sigs,
 	if (!in)
 		return NULL;
 
+	in->used_mask = devm_bitmap_alloc(dev, in_sigs, GFP_KERNEL);
+	if (!in->used_mask)
+		return NULL;
+
 	out = devm_kzalloc(dev,
 			   offsetof(struct cti_trig_grp, sig_types[out_sigs]),
 			   GFP_KERNEL);
 	if (!out)
 		return NULL;
 
+	out->used_mask = devm_bitmap_alloc(dev, out_sigs, GFP_KERNEL);
+	if (!out->used_mask)
+		return NULL;
+
 	tc->con_in = in;
 	tc->con_out = out;
 	tc->con_in->nr_sigs = in_sigs;
@@ -314,7 +345,6 @@ int cti_add_default_connection(struct device *dev, struct cti_drvdata *drvdata)
 {
 	int ret = 0;
 	int n_trigs = drvdata->config.nr_trig_max;
-	u32 n_trig_mask = GENMASK(n_trigs - 1, 0);
 	struct cti_trig_con *tc = NULL;
 
 	/*
@@ -325,8 +355,9 @@ int cti_add_default_connection(struct device *dev, struct cti_drvdata *drvdata)
 	if (!tc)
 		return -ENOMEM;
 
-	tc->con_in->used_mask = n_trig_mask;
-	tc->con_out->used_mask = n_trig_mask;
+	bitmap_fill(tc->con_in->used_mask, n_trigs);
+	bitmap_fill(tc->con_out->used_mask, n_trigs);
+
 	ret = cti_add_connection_entry(dev, drvdata, tc, NULL, "default");
 	return ret;
 }
@@ -339,7 +370,6 @@ int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,
 {
 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	struct cti_config *config = &drvdata->config;
-	u32 trig_bitmask;
 	u32 chan_bitmask;
 	u32 reg_value;
 	int reg_offset;
@@ -349,18 +379,16 @@ int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,
 	   (trigger_idx >= config->nr_trig_max))
 		return -EINVAL;
 
-	trig_bitmask = BIT(trigger_idx);
-
 	/* ensure registered triggers and not out filtered */
 	if (direction == CTI_TRIG_IN)	{
-		if (!(trig_bitmask & config->trig_in_use))
+		if (!(test_bit(trigger_idx, config->trig_in_use)))
 			return -EINVAL;
 	} else {
-		if (!(trig_bitmask & config->trig_out_use))
+		if (!(test_bit(trigger_idx, config->trig_out_use)))
 			return -EINVAL;
 
 		if ((config->trig_filter_enable) &&
-		    (config->trig_out_filter & trig_bitmask))
+		    test_bit(trigger_idx, config->trig_out_filter))
 			return -EINVAL;
 	}
 
@@ -892,7 +920,9 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id)
 	raw_spin_lock_init(&drvdata->spinlock);
 
 	/* initialise CTI driver config values */
-	cti_set_default_config(dev, drvdata);
+	ret = cti_set_default_config(dev, drvdata);
+	if (ret)
+		return ret;
 
 	pdata = coresight_cti_get_platform_data(dev);
 	if (IS_ERR(pdata)) {
diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c
index d0ae10bf6128..4bef860a0484 100644
--- a/drivers/hwtracing/coresight/coresight-cti-platform.c
+++ b/drivers/hwtracing/coresight/coresight-cti-platform.c
@@ -136,8 +136,8 @@ static int cti_plat_create_v8_etm_connection(struct device *dev,
 		goto create_v8_etm_out;
 
 	/* build connection data */
-	tc->con_in->used_mask = 0xF0; /* sigs <4,5,6,7> */
-	tc->con_out->used_mask = 0xF0; /* sigs <4,5,6,7> */
+	bitmap_set(tc->con_in->used_mask, 4, 4); /* sigs <4,5,6,7> */
+	bitmap_set(tc->con_out->used_mask, 4, 4); /* sigs <4,5,6,7> */
 
 	/*
 	 * The EXTOUT type signals from the ETM are connected to a set of input
@@ -194,10 +194,10 @@ static int cti_plat_create_v8_connections(struct device *dev,
 		goto of_create_v8_out;
 
 	/* Set the v8 PE CTI connection data */
-	tc->con_in->used_mask = 0x3; /* sigs <0 1> */
+	bitmap_set(tc->con_in->used_mask, 0, 2); /* sigs <0 1> */
 	tc->con_in->sig_types[0] = PE_DBGTRIGGER;
 	tc->con_in->sig_types[1] = PE_PMUIRQ;
-	tc->con_out->used_mask = 0x7; /* sigs <0 1 2 > */
+	bitmap_set(tc->con_out->used_mask, 0, 3); /* sigs <0 1 2 > */
 	tc->con_out->sig_types[0] = PE_EDBGREQ;
 	tc->con_out->sig_types[1] = PE_DBGRESTART;
 	tc->con_out->sig_types[2] = PE_CTIIRQ;
@@ -213,7 +213,7 @@ static int cti_plat_create_v8_connections(struct device *dev,
 		goto of_create_v8_out;
 
 	/* filter pe_edbgreq - PE trigout sig <0> */
-	drvdata->config.trig_out_filter |= 0x1;
+	set_bit(0, drvdata->config.trig_out_filter);
 
 of_create_v8_out:
 	return ret;
@@ -257,7 +257,7 @@ static int cti_plat_read_trig_group(struct cti_trig_grp *tgrp,
 	if (!err) {
 		/* set the signal usage mask */
 		for (idx = 0; idx < tgrp->nr_sigs; idx++)
-			tgrp->used_mask |= BIT(values[idx]);
+			set_bit(values[idx], tgrp->used_mask);
 	}
 
 	kfree(values);
@@ -331,7 +331,9 @@ static int cti_plat_process_filter_sigs(struct cti_drvdata *drvdata,
 
 	err = cti_plat_read_trig_group(tg, fwnode, CTI_DT_FILTER_OUT_SIGS);
 	if (!err)
-		drvdata->config.trig_out_filter |= tg->used_mask;
+		bitmap_or(drvdata->config.trig_out_filter,
+			  drvdata->config.trig_out_filter,
+			  tg->used_mask, drvdata->config.nr_trig_max);
 
 	kfree(tg);
 	return err;
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
index 572b80ee96fb..a9df77215141 100644
--- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
@@ -711,10 +711,8 @@ static ssize_t trigout_filtered_show(struct device *dev,
 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	struct cti_config *cfg = &drvdata->config;
 	int size = 0, nr_trig_max = cfg->nr_trig_max;
-	unsigned long mask = cfg->trig_out_filter;
 
-	if (mask)
-		size = bitmap_print_to_pagebuf(true, buf, &mask, nr_trig_max);
+	size = bitmap_print_to_pagebuf(true, buf, cfg->trig_out_filter, nr_trig_max);
 	return size;
 }
 static DEVICE_ATTR_RO(trigout_filtered);
@@ -926,9 +924,8 @@ static ssize_t trigin_sig_show(struct device *dev,
 	struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	struct cti_config *cfg = &drvdata->config;
-	unsigned long mask = con->con_in->used_mask;
 
-	return bitmap_print_to_pagebuf(true, buf, &mask, cfg->nr_trig_max);
+	return bitmap_print_to_pagebuf(true, buf, con->con_in->used_mask, cfg->nr_trig_max);
 }
 
 static ssize_t trigout_sig_show(struct device *dev,
@@ -940,9 +937,8 @@ static ssize_t trigout_sig_show(struct device *dev,
 	struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	struct cti_config *cfg = &drvdata->config;
-	unsigned long mask = con->con_out->used_mask;
 
-	return bitmap_print_to_pagebuf(true, buf, &mask, cfg->nr_trig_max);
+	return bitmap_print_to_pagebuf(true, buf, con->con_out->used_mask, cfg->nr_trig_max);
 }
 
 /* convert a sig type id to a name */
diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h
index 4f89091ee93f..e7b88b07cffe 100644
--- a/drivers/hwtracing/coresight/coresight-cti.h
+++ b/drivers/hwtracing/coresight/coresight-cti.h
@@ -68,7 +68,7 @@ struct fwnode_handle;
  */
 struct cti_trig_grp {
 	int nr_sigs;
-	u32 used_mask;
+	unsigned long *used_mask;
 	int sig_types[];
 };
 
@@ -146,20 +146,21 @@ struct cti_config {
 	bool hw_enabled;
 	bool hw_powered;
 
-	/* registered triggers and filtering */
-	u32 trig_in_use;
-	u32 trig_out_use;
-	u32 trig_out_filter;
 	bool trig_filter_enable;
 	u8 xtrig_rchan_sel;
 
 	/* cti cross trig programmable regs */
-	u32 ctiappset;
 	u8 ctiinout_sel;
-	u32 ctiinen[CTIINOUTEN_MAX];
-	u32 ctiouten[CTIINOUTEN_MAX];
+	u32 ctiappset;
 	u32 ctigate;
 	u32 asicctl;
+	u32 *ctiinen;
+	u32 *ctiouten;
+
+	/* registered triggers and filtering */
+	unsigned long *trig_in_use;
+	unsigned long *trig_out_use;
+	unsigned long *trig_out_filter;
 };
 
 /**

-- 
2.43.0



From yingchao.deng at oss.qualcomm.com  Mon Dec  1 22:42:21 2025
From: yingchao.deng at oss.qualcomm.com (Yingchao Deng)
Date: Tue, 02 Dec 2025 14:42:21 +0800
Subject: [PATCH v6 2/2] coresight: cti: Add Qualcomm extended CTI support
In-Reply-To: <20251202-extended_cti-v6-0-ab68bb15c4f5@oss.qualcomm.com>
References: <20251202-extended_cti-v6-0-ab68bb15c4f5@oss.qualcomm.com>
Message-ID: <20251202-extended_cti-v6-2-ab68bb15c4f5@oss.qualcomm.com>

The QCOM extended CTI is a heavily parameterized version of ARM?s CSCTI.
It allows a debugger to send to trigger events to a processor or to send
a trigger event to one or more processors when a trigger event occurs
on another processor on the same SoC, or even between SoCs. Qualcomm CTI
implementation differs from the standard CTI in the following aspects:

1. The number of supported triggers is extended to 128.
2. Several register offsets differ from the CoreSight specification.

Co-developed-by: Jinlong Mao <jinlong.mao at oss.qualcomm.com>
Signed-off-by: Jinlong Mao <jinlong.mao at oss.qualcomm.com>
Signed-off-by: Yingchao Deng <yingchao.deng at oss.qualcomm.com>
---
 .../ABI/testing/sysfs-bus-coresight-devices-cti    |  11 ++
 drivers/hwtracing/coresight/coresight-cti-core.c   |  95 +++++++++--
 drivers/hwtracing/coresight/coresight-cti-sysfs.c  | 177 ++++++++++++++++-----
 drivers/hwtracing/coresight/coresight-cti.h        |  43 ++++-
 drivers/hwtracing/coresight/qcom-cti.h             |  29 ++++
 5 files changed, 304 insertions(+), 51 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-cti b/Documentation/ABI/testing/sysfs-bus-coresight-devices-cti
index a2aef7f5a6d7..9478dfcee03b 100644
--- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-cti
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-cti
@@ -245,3 +245,14 @@ Date:           Aug 2025
 KernelVersion   6.18
 Contact:        Mao Jinlong <quic_jinlmao at quicinc.com>
 Description:    (Read) Show hardware context information of device.
+
+What:           /sys/bus/coresight/devices/<cti-name>/regs/ext_reg_sel
+Date:           Dec 2025
+KernelVersion:  6.19
+Contact:        Mao Jinlong <jinlong.mao at oss.qualcomm.com>
+Description:    (RW) Select the index for extended registers.
+		QCOM CTI supports up to 128 triggers, there are 6 registers
+		need to be expanded to up to 4 instances:
+		CTITRIGINSTATUS, CTITRIGOUTSTATUS,
+		ITTRIGIN, ITTRIGOUT,
+		ITTRIGINACK, ITTRIGOUTACK.
diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c
index f9970e40dd59..51b3644e97c4 100644
--- a/drivers/hwtracing/coresight/coresight-cti-core.c
+++ b/drivers/hwtracing/coresight/coresight-cti-core.c
@@ -21,6 +21,55 @@
 
 #include "coresight-priv.h"
 #include "coresight-cti.h"
+#include "qcom-cti.h"
+
+static const u32 cti_normal_offset[] = {
+	[INDEX_CTIINTACK]		= CTIINTACK,
+	[INDEX_CTIAPPSET]		= CTIAPPSET,
+	[INDEX_CTIAPPCLEAR]		= CTIAPPCLEAR,
+	[INDEX_CTIAPPPULSE]		= CTIAPPPULSE,
+	[INDEX_CTIINEN]			= CTIINEN(0),
+	[INDEX_CTIOUTEN]		= CTIOUTEN(0),
+	[INDEX_CTITRIGINSTATUS]		= CTITRIGINSTATUS,
+	[INDEX_CTITRIGOUTSTATUS]	= CTITRIGOUTSTATUS,
+	[INDEX_CTICHINSTATUS]		= CTICHINSTATUS,
+	[INDEX_CTICHOUTSTATUS]		= CTICHOUTSTATUS,
+	[INDEX_CTIGATE]			= CTIGATE,
+	[INDEX_ASICCTL]			= ASICCTL,
+	[INDEX_ITCHINACK]		= ITCHINACK,
+	[INDEX_ITTRIGINACK]		= ITTRIGINACK,
+	[INDEX_ITCHOUT]			= ITCHOUT,
+	[INDEX_ITTRIGOUT]		= ITTRIGOUT,
+	[INDEX_ITCHOUTACK]		= ITCHOUTACK,
+	[INDEX_ITTRIGOUTACK]		= ITTRIGOUTACK,
+	[INDEX_ITCHIN]			= ITCHIN,
+	[INDEX_ITTRIGIN]		= ITTRIGIN,
+	[INDEX_ITCTRL]			= CORESIGHT_ITCTRL,
+};
+
+static const u32 cti_extended_offset[] = {
+	[INDEX_CTIINTACK]		= QCOM_CTIINTACK,
+	[INDEX_CTIAPPSET]		= QCOM_CTIAPPSET,
+	[INDEX_CTIAPPCLEAR]		= QCOM_CTIAPPCLEAR,
+	[INDEX_CTIAPPPULSE]		= QCOM_CTIAPPPULSE,
+	[INDEX_CTIINEN]			= QCOM_CTIINEN,
+	[INDEX_CTIOUTEN]		= QCOM_CTIOUTEN,
+	[INDEX_CTITRIGINSTATUS]		= QCOM_CTITRIGINSTATUS,
+	[INDEX_CTITRIGOUTSTATUS]	= QCOM_CTITRIGOUTSTATUS,
+	[INDEX_CTICHINSTATUS]		= QCOM_CTICHINSTATUS,
+	[INDEX_CTICHOUTSTATUS]		= QCOM_CTICHOUTSTATUS,
+	[INDEX_CTIGATE]			= QCOM_CTIGATE,
+	[INDEX_ASICCTL]			= QCOM_ASICCTL,
+	[INDEX_ITCHINACK]		= QCOM_ITCHINACK,
+	[INDEX_ITTRIGINACK]		= QCOM_ITTRIGINACK,
+	[INDEX_ITCHOUT]			= QCOM_ITCHOUT,
+	[INDEX_ITTRIGOUT]		= QCOM_ITTRIGOUT,
+	[INDEX_ITCHOUTACK]		= QCOM_ITCHOUTACK,
+	[INDEX_ITTRIGOUTACK]		= QCOM_ITTRIGOUTACK,
+	[INDEX_ITCHIN]			= QCOM_ITCHIN,
+	[INDEX_ITTRIGIN]		= QCOM_ITTRIGIN,
+	[INDEX_ITCTRL]			= CORESIGHT_ITCTRL,
+};
 
 /*
  * CTI devices can be associated with a PE, or be connected to CoreSight
@@ -70,15 +119,16 @@ void cti_write_all_hw_regs(struct cti_drvdata *drvdata)
 
 	/* write the CTI trigger registers */
 	for (i = 0; i < config->nr_trig_max; i++) {
-		writel_relaxed(config->ctiinen[i], drvdata->base + CTIINEN(i));
+		writel_relaxed(config->ctiinen[i],
+			       drvdata->base + cti_offset(drvdata, INDEX_CTIINEN, i));
 		writel_relaxed(config->ctiouten[i],
-			       drvdata->base + CTIOUTEN(i));
+			       drvdata->base + cti_offset(drvdata, INDEX_CTIOUTEN, i));
 	}
 
 	/* other regs */
-	writel_relaxed(config->ctigate, drvdata->base + CTIGATE);
-	writel_relaxed(config->asicctl, drvdata->base + ASICCTL);
-	writel_relaxed(config->ctiappset, drvdata->base + CTIAPPSET);
+	writel_relaxed(config->ctigate, drvdata->base + cti_offset(drvdata, INDEX_CTIGATE, 0));
+	writel_relaxed(config->asicctl, drvdata->base + cti_offset(drvdata, INDEX_ASICCTL, 0));
+	writel_relaxed(config->ctiappset, drvdata->base + cti_offset(drvdata, INDEX_CTIAPPSET, 0));
 
 	/* re-enable CTI */
 	writel_relaxed(1, drvdata->base + CTICONTROL);
@@ -214,6 +264,9 @@ void cti_write_intack(struct device *dev, u32 ackval)
 /* DEVID[19:16] - number of CTM channels */
 #define CTI_DEVID_CTMCHANNELS(devid_val) ((int) BMVAL(devid_val, 16, 19))
 
+/* DEVARCH[31:21] - ARCHITECT */
+#define CTI_DEVARCH_ARCHITECT(devarch_val) ((int)BMVAL(devarch_val, 21, 31))
+
 static int cti_set_default_config(struct device *dev,
 				  struct cti_drvdata *drvdata)
 {
@@ -394,8 +447,8 @@ int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,
 
 	/* update the local register values */
 	chan_bitmask = BIT(channel_idx);
-	reg_offset = (direction == CTI_TRIG_IN ? CTIINEN(trigger_idx) :
-		      CTIOUTEN(trigger_idx));
+	reg_offset = (direction == CTI_TRIG_IN ? cti_offset(drvdata, INDEX_CTIINEN, trigger_idx) :
+			cti_offset(drvdata, INDEX_CTIOUTEN, trigger_idx));
 
 	raw_spin_lock(&drvdata->spinlock);
 
@@ -479,19 +532,19 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op,
 	case CTI_CHAN_SET:
 		config->ctiappset |= chan_bitmask;
 		reg_value  = config->ctiappset;
-		reg_offset = CTIAPPSET;
+		reg_offset = cti_offset(drvdata, INDEX_CTIAPPSET, 0);
 		break;
 
 	case CTI_CHAN_CLR:
 		config->ctiappset &= ~chan_bitmask;
 		reg_value = chan_bitmask;
-		reg_offset = CTIAPPCLEAR;
+		reg_offset = cti_offset(drvdata, INDEX_CTIAPPCLEAR, 0);
 		break;
 
 	case CTI_CHAN_PULSE:
 		config->ctiappset &= ~chan_bitmask;
 		reg_value = chan_bitmask;
-		reg_offset = CTIAPPPULSE;
+		reg_offset = cti_offset(drvdata, INDEX_CTIAPPPULSE, 0);
 		break;
 
 	default:
@@ -895,6 +948,7 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id)
 	struct coresight_desc cti_desc;
 	struct coresight_platform_data *pdata = NULL;
 	struct resource *res = &adev->res;
+	u32 devarch;
 
 	/* driver data*/
 	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
@@ -981,9 +1035,28 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id)
 	drvdata->csdev_release = drvdata->csdev->dev.release;
 	drvdata->csdev->dev.release = cti_device_release;
 
+	/* check architect value*/
+	devarch = readl_relaxed(drvdata->base + CORESIGHT_DEVARCH);
+	if (CTI_DEVARCH_ARCHITECT(devarch) == ARCHITECT_QCOM) {
+		drvdata->subtype = QCOM_CTI;
+		drvdata->offsets = cti_extended_offset;
+		/*
+		 * QCOM CTI does not implement Claimtag functionality as
+		 * per CoreSight specification, but its CLAIMSET register
+		 * is incorrectly initialized to 0xF. This can mislead
+		 * tools or drivers into thinking the component is claimed.
+		 *
+		 * Reset CLAIMSET to 0 to reflect that no claims are active.
+		 */
+		writel_relaxed(0, drvdata->base + CORESIGHT_CLAIMSET);
+	} else {
+		drvdata->subtype = ARM_STD_CTI;
+		drvdata->offsets = cti_normal_offset;
+	}
+
 	/* all done - dec pm refcount */
 	pm_runtime_put(&adev->dev);
-	dev_info(&drvdata->csdev->dev, "CTI initialized\n");
+	dev_info(&drvdata->csdev->dev, "CTI initialized; subtype=%d\n", drvdata->subtype);
 	return 0;
 
 pm_release:
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
index a9df77215141..12a495382999 100644
--- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
@@ -172,9 +172,8 @@ static struct attribute *coresight_cti_attrs[] = {
 
 /* register based attributes */
 
-/* Read registers with power check only (no enable check). */
-static ssize_t coresight_cti_reg_show(struct device *dev,
-			   struct device_attribute *attr, char *buf)
+static ssize_t coresight_cti_mgmt_reg_show(struct device *dev,
+					   struct device_attribute *attr, char *buf)
 {
 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	struct cs_off_attribute *cti_attr = container_of(attr, struct cs_off_attribute, attr);
@@ -189,6 +188,40 @@ static ssize_t coresight_cti_reg_show(struct device *dev,
 	return sysfs_emit(buf, "0x%x\n", val);
 }
 
+/* Read registers with power check only (no enable check). */
+static ssize_t coresight_cti_reg_show(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	struct cs_off_attribute *cti_attr = container_of(attr, struct cs_off_attribute, attr);
+	u32 idx, val = 0;
+
+	pm_runtime_get_sync(dev->parent);
+	raw_spin_lock(&drvdata->spinlock);
+	idx = drvdata->config.ext_reg_sel;
+	if (drvdata->config.hw_powered) {
+		switch (cti_attr->off) {
+		case INDEX_CTITRIGINSTATUS:
+		case INDEX_CTITRIGOUTSTATUS:
+		case INDEX_ITTRIGINACK:
+		case INDEX_ITTRIGOUT:
+		case INDEX_ITTRIGOUTACK:
+		case INDEX_ITTRIGIN:
+			val = readl_relaxed(drvdata->base +
+					    cti_offset(drvdata, cti_attr->off, idx));
+			break;
+
+		default:
+			val = readl_relaxed(drvdata->base + cti_offset(drvdata, cti_attr->off, 0));
+			break;
+		}
+	}
+
+	raw_spin_unlock(&drvdata->spinlock);
+	pm_runtime_put_sync(dev->parent);
+	return sysfs_emit(buf, "0x%x\n", val);
+}
+
 /* Write registers with power check only (no enable check). */
 static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,
 						      struct device_attribute *attr,
@@ -197,19 +230,39 @@ static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,
 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	struct cs_off_attribute *cti_attr = container_of(attr, struct cs_off_attribute, attr);
 	unsigned long val = 0;
+	u32 idx;
 
 	if (kstrtoul(buf, 0, &val))
 		return -EINVAL;
 
 	pm_runtime_get_sync(dev->parent);
 	raw_spin_lock(&drvdata->spinlock);
-	if (drvdata->config.hw_powered)
-		cti_write_single_reg(drvdata, cti_attr->off, val);
+	idx = drvdata->config.ext_reg_sel;
+	if (drvdata->config.hw_powered) {
+		switch (cti_attr->off) {
+		case INDEX_ITTRIGINACK:
+		case INDEX_ITTRIGOUT:
+			cti_write_single_reg(drvdata, cti_offset(drvdata, cti_attr->off, idx), val);
+			break;
+
+		default:
+			cti_write_single_reg(drvdata, cti_offset(drvdata, cti_attr->off, 0), val);
+			break;
+		}
+	}
 	raw_spin_unlock(&drvdata->spinlock);
 	pm_runtime_put_sync(dev->parent);
 	return size;
 }
 
+#define coresight_cti_mgmt_reg(name, offset)	                        \
+	(&((struct cs_off_attribute[]) {                                \
+	   {                                                            \
+		__ATTR(name, 0444, coresight_cti_mgmt_reg_show, NULL),  \
+		offset							\
+	   }								\
+	})[0].attr.attr)
+
 #define coresight_cti_reg(name, offset)					\
 	(&((struct cs_off_attribute[]) {				\
 	   {								\
@@ -237,17 +290,17 @@ static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,
 
 /* coresight management registers */
 static struct attribute *coresight_cti_mgmt_attrs[] = {
-	coresight_cti_reg(devaff0, CTIDEVAFF0),
-	coresight_cti_reg(devaff1, CTIDEVAFF1),
-	coresight_cti_reg(authstatus, CORESIGHT_AUTHSTATUS),
-	coresight_cti_reg(devarch, CORESIGHT_DEVARCH),
-	coresight_cti_reg(devid, CORESIGHT_DEVID),
-	coresight_cti_reg(devtype, CORESIGHT_DEVTYPE),
-	coresight_cti_reg(pidr0, CORESIGHT_PERIPHIDR0),
-	coresight_cti_reg(pidr1, CORESIGHT_PERIPHIDR1),
-	coresight_cti_reg(pidr2, CORESIGHT_PERIPHIDR2),
-	coresight_cti_reg(pidr3, CORESIGHT_PERIPHIDR3),
-	coresight_cti_reg(pidr4, CORESIGHT_PERIPHIDR4),
+	coresight_cti_mgmt_reg(devaff0, CTIDEVAFF0),
+	coresight_cti_mgmt_reg(devaff1, CTIDEVAFF1),
+	coresight_cti_mgmt_reg(authstatus, CORESIGHT_AUTHSTATUS),
+	coresight_cti_mgmt_reg(devarch, CORESIGHT_DEVARCH),
+	coresight_cti_mgmt_reg(devid, CORESIGHT_DEVID),
+	coresight_cti_mgmt_reg(devtype, CORESIGHT_DEVTYPE),
+	coresight_cti_mgmt_reg(pidr0, CORESIGHT_PERIPHIDR0),
+	coresight_cti_mgmt_reg(pidr1, CORESIGHT_PERIPHIDR1),
+	coresight_cti_mgmt_reg(pidr2, CORESIGHT_PERIPHIDR2),
+	coresight_cti_mgmt_reg(pidr3, CORESIGHT_PERIPHIDR3),
+	coresight_cti_mgmt_reg(pidr4, CORESIGHT_PERIPHIDR4),
 	NULL,
 };
 
@@ -258,13 +311,15 @@ static struct attribute *coresight_cti_mgmt_attrs[] = {
  * If inaccessible & pcached_val not NULL then show cached value.
  */
 static ssize_t cti_reg32_show(struct device *dev, char *buf,
-			      u32 *pcached_val, int reg_offset)
+			      u32 *pcached_val, int index)
 {
 	u32 val = 0;
 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	struct cti_config *config = &drvdata->config;
+	int reg_offset;
 
 	raw_spin_lock(&drvdata->spinlock);
+	reg_offset = cti_offset(drvdata, index, 0);
 	if ((reg_offset >= 0) && cti_active(config)) {
 		CS_UNLOCK(drvdata->base);
 		val = readl_relaxed(drvdata->base + reg_offset);
@@ -284,11 +339,12 @@ static ssize_t cti_reg32_show(struct device *dev, char *buf,
  * if reg_offset >= 0 then write through if enabled.
  */
 static ssize_t cti_reg32_store(struct device *dev, const char *buf,
-			       size_t size, u32 *pcached_val, int reg_offset)
+			       size_t size, u32 *pcached_val, int index)
 {
 	unsigned long val;
 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	struct cti_config *config = &drvdata->config;
+	int reg_offset;
 
 	if (kstrtoul(buf, 0, &val))
 		return -EINVAL;
@@ -298,6 +354,7 @@ static ssize_t cti_reg32_store(struct device *dev, const char *buf,
 	if (pcached_val)
 		*pcached_val = (u32)val;
 
+	reg_offset = cti_offset(drvdata, index, 0);
 	/* write through if offset and enabled */
 	if ((reg_offset >= 0) && cti_active(config))
 		cti_write_single_reg(drvdata, reg_offset, val);
@@ -306,14 +363,14 @@ static ssize_t cti_reg32_store(struct device *dev, const char *buf,
 }
 
 /* Standard macro for simple rw cti config registers */
-#define cti_config_reg32_rw(name, cfgname, offset)			\
+#define cti_config_reg32_rw(name, cfgname, index)			\
 static ssize_t name##_show(struct device *dev,				\
 			   struct device_attribute *attr,		\
 			   char *buf)					\
 {									\
 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);	\
 	return cti_reg32_show(dev, buf,					\
-			      &drvdata->config.cfgname, offset);	\
+			      &drvdata->config.cfgname, index);		\
 }									\
 									\
 static ssize_t name##_store(struct device *dev,				\
@@ -322,7 +379,7 @@ static ssize_t name##_store(struct device *dev,				\
 {									\
 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);	\
 	return cti_reg32_store(dev, buf, size,				\
-			       &drvdata->config.cfgname, offset);	\
+			       &drvdata->config.cfgname, index);	\
 }									\
 static DEVICE_ATTR_RW(name)
 
@@ -356,6 +413,46 @@ static ssize_t inout_sel_store(struct device *dev,
 }
 static DEVICE_ATTR_RW(inout_sel);
 
+/*
+ * QCOM CTI supports up to 128 triggers, there are 6 registers need to be
+ * expanded to up to 4 instances, and ext_reg_sel can be used to indicate
+ * which one is in use.
+ * CTITRIGINSTATUS, CTITRIGOUTSTATUS,
+ * ITTRIGIN, ITTRIGOUT,
+ * ITTRIGINACK, ITTRIGOUTACK.
+ */
+static ssize_t ext_reg_sel_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	u32 val;
+	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	raw_spin_lock(&drvdata->spinlock);
+	val = drvdata->config.ext_reg_sel;
+	raw_spin_unlock(&drvdata->spinlock);
+	return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t ext_reg_sel_store(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf, size_t size)
+{
+	unsigned long val;
+	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	if (kstrtoul(buf, 0, &val))
+		return -EINVAL;
+	if (val > ((drvdata->config.nr_trig_max + 31) / 32 - 1))
+		return -EINVAL;
+
+	raw_spin_lock(&drvdata->spinlock);
+	drvdata->config.ext_reg_sel = val;
+	raw_spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR_RW(ext_reg_sel);
+
 static ssize_t inen_show(struct device *dev,
 			 struct device_attribute *attr,
 			 char *buf)
@@ -389,7 +486,7 @@ static ssize_t inen_store(struct device *dev,
 
 	/* write through if enabled */
 	if (cti_active(config))
-		cti_write_single_reg(drvdata, CTIINEN(index), val);
+		cti_write_single_reg(drvdata, cti_offset(drvdata, INDEX_CTIINEN, index), val);
 	raw_spin_unlock(&drvdata->spinlock);
 	return size;
 }
@@ -428,7 +525,7 @@ static ssize_t outen_store(struct device *dev,
 
 	/* write through if enabled */
 	if (cti_active(config))
-		cti_write_single_reg(drvdata, CTIOUTEN(index), val);
+		cti_write_single_reg(drvdata, cti_offset(drvdata, INDEX_CTIOUTEN, index), val);
 	raw_spin_unlock(&drvdata->spinlock);
 	return size;
 }
@@ -448,9 +545,9 @@ static ssize_t intack_store(struct device *dev,
 }
 static DEVICE_ATTR_WO(intack);
 
-cti_config_reg32_rw(gate, ctigate, CTIGATE);
-cti_config_reg32_rw(asicctl, asicctl, ASICCTL);
-cti_config_reg32_rw(appset, ctiappset, CTIAPPSET);
+cti_config_reg32_rw(gate, ctigate, INDEX_CTIGATE);
+cti_config_reg32_rw(asicctl, asicctl, INDEX_ASICCTL);
+cti_config_reg32_rw(appset, ctiappset, INDEX_CTIAPPSET);
 
 static ssize_t appclear_store(struct device *dev,
 			      struct device_attribute *attr,
@@ -504,6 +601,7 @@ static DEVICE_ATTR_WO(apppulse);
  */
 static struct attribute *coresight_cti_regs_attrs[] = {
 	&dev_attr_inout_sel.attr,
+	&dev_attr_ext_reg_sel.attr,
 	&dev_attr_inen.attr,
 	&dev_attr_outen.attr,
 	&dev_attr_gate.attr,
@@ -512,20 +610,20 @@ static struct attribute *coresight_cti_regs_attrs[] = {
 	&dev_attr_appset.attr,
 	&dev_attr_appclear.attr,
 	&dev_attr_apppulse.attr,
-	coresight_cti_reg(triginstatus, CTITRIGINSTATUS),
-	coresight_cti_reg(trigoutstatus, CTITRIGOUTSTATUS),
-	coresight_cti_reg(chinstatus, CTICHINSTATUS),
-	coresight_cti_reg(choutstatus, CTICHOUTSTATUS),
+	coresight_cti_reg(triginstatus, INDEX_CTITRIGINSTATUS),
+	coresight_cti_reg(trigoutstatus, INDEX_CTITRIGOUTSTATUS),
+	coresight_cti_reg(chinstatus, INDEX_CTICHINSTATUS),
+	coresight_cti_reg(choutstatus, INDEX_CTICHOUTSTATUS),
 #ifdef CONFIG_CORESIGHT_CTI_INTEGRATION_REGS
-	coresight_cti_reg_rw(itctrl, CORESIGHT_ITCTRL),
-	coresight_cti_reg(ittrigin, ITTRIGIN),
-	coresight_cti_reg(itchin, ITCHIN),
-	coresight_cti_reg_rw(ittrigout, ITTRIGOUT),
-	coresight_cti_reg_rw(itchout, ITCHOUT),
-	coresight_cti_reg(itchoutack, ITCHOUTACK),
-	coresight_cti_reg(ittrigoutack, ITTRIGOUTACK),
-	coresight_cti_reg_wo(ittriginack, ITTRIGINACK),
-	coresight_cti_reg_wo(itchinack, ITCHINACK),
+	coresight_cti_reg_rw(itctrl, INDEX_ITCTRL),
+	coresight_cti_reg(ittrigin, INDEX_ITTRIGIN),
+	coresight_cti_reg(itchin, INDEX_ITCHIN),
+	coresight_cti_reg_rw(ittrigout, INDEX_ITTRIGOUT),
+	coresight_cti_reg_rw(itchout, INDEX_ITCHOUT),
+	coresight_cti_reg(itchoutack, INDEX_ITCHOUTACK),
+	coresight_cti_reg(ittrigoutack, INDEX_ITTRIGOUTACK),
+	coresight_cti_reg_wo(ittriginack, INDEX_ITTRIGINACK),
+	coresight_cti_reg_wo(itchinack, INDEX_ITCHINACK),
 #endif
 	NULL,
 };
@@ -740,6 +838,7 @@ static ssize_t chan_xtrigs_reset_store(struct device *dev,
 	config->ctiappset = 0;
 	config->ctiinout_sel = 0;
 	config->xtrig_rchan_sel = 0;
+	config->ext_reg_sel = 0;
 
 	/* if enabled then write through */
 	if (cti_active(config))
diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h
index e7b88b07cffe..fdd6d8892a95 100644
--- a/drivers/hwtracing/coresight/coresight-cti.h
+++ b/drivers/hwtracing/coresight/coresight-cti.h
@@ -57,7 +57,38 @@ struct fwnode_handle;
  * Max of in and out defined in the DEVID register.
  * - pick up actual number used from .dts parameters if present.
  */
-#define CTIINOUTEN_MAX		32
+#define CTIINOUTEN_MAX		128
+
+/* Qcom CTI supports up to 128 triggers*/
+enum cti_subtype {
+	ARM_STD_CTI,
+	QCOM_CTI,
+};
+
+/* These registers are remapped in Qcom CTI*/
+enum cti_offset_index {
+	INDEX_CTIINTACK,
+	INDEX_CTIAPPSET,
+	INDEX_CTIAPPCLEAR,
+	INDEX_CTIAPPPULSE,
+	INDEX_CTIINEN,
+	INDEX_CTIOUTEN,
+	INDEX_CTITRIGINSTATUS,
+	INDEX_CTITRIGOUTSTATUS,
+	INDEX_CTICHINSTATUS,
+	INDEX_CTICHOUTSTATUS,
+	INDEX_CTIGATE,
+	INDEX_ASICCTL,
+	INDEX_ITCHINACK,
+	INDEX_ITTRIGINACK,
+	INDEX_ITCHOUT,
+	INDEX_ITTRIGOUT,
+	INDEX_ITCHOUTACK,
+	INDEX_ITTRIGOUTACK,
+	INDEX_ITCHIN,
+	INDEX_ITTRIGIN,
+	INDEX_ITCTRL,
+};
 
 /**
  * Group of related trigger signals
@@ -149,6 +180,9 @@ struct cti_config {
 	bool trig_filter_enable;
 	u8 xtrig_rchan_sel;
 
+	/* qcom_cti regs' index */
+	u8 ext_reg_sel;
+
 	/* cti cross trig programmable regs */
 	u8 ctiinout_sel;
 	u32 ctiappset;
@@ -181,6 +215,8 @@ struct cti_drvdata {
 	struct cti_config config;
 	struct list_head node;
 	void (*csdev_release)(struct device *dev);
+	enum cti_subtype subtype;
+	const u32 *offsets;
 };
 
 /*
@@ -235,6 +271,11 @@ struct coresight_platform_data *
 coresight_cti_get_platform_data(struct device *dev);
 const char *cti_plat_get_node_name(struct fwnode_handle *fwnode);
 
+static inline u32 cti_offset(struct cti_drvdata *drvdata, int index, int num)
+{
+	return drvdata->offsets[index] + 4 * num;
+}
+
 /* cti powered and enabled */
 static inline bool cti_active(struct cti_config *cfg)
 {
diff --git a/drivers/hwtracing/coresight/qcom-cti.h b/drivers/hwtracing/coresight/qcom-cti.h
new file mode 100644
index 000000000000..3c46317dd81f
--- /dev/null
+++ b/drivers/hwtracing/coresight/qcom-cti.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#define ARCHITECT_QCOM 0x477
+
+/* CTI programming registers */
+#define	QCOM_CTIINTACK		0x020
+#define	QCOM_CTIAPPSET		0x004
+#define	QCOM_CTIAPPCLEAR	0x008
+#define	QCOM_CTIAPPPULSE	0x00C
+#define	QCOM_CTIINEN		0x400
+#define	QCOM_CTIOUTEN		0x800
+#define	QCOM_CTITRIGINSTATUS	0x040
+#define	QCOM_CTITRIGOUTSTATUS	0x060
+#define	QCOM_CTICHINSTATUS	0x080
+#define	QCOM_CTICHOUTSTATUS	0x084
+#define	QCOM_CTIGATE		0x088
+#define	QCOM_ASICCTL		0x08c
+/* Integration test registers */
+#define	QCOM_ITCHINACK		0xE70
+#define	QCOM_ITTRIGINACK	0xE80
+#define	QCOM_ITCHOUT		0xE74
+#define	QCOM_ITTRIGOUT		0xEA0
+#define	QCOM_ITCHOUTACK		0xE78
+#define	QCOM_ITTRIGOUTACK	0xEC0
+#define	QCOM_ITCHIN		0xE7C
+#define	QCOM_ITTRIGIN		0xEE0

-- 
2.43.0



From zhengtian10 at huawei.com  Mon Dec  1 22:51:42 2025
From: zhengtian10 at huawei.com (Tian Zheng)
Date: Tue, 2 Dec 2025 14:51:42 +0800
Subject: [PATCH v2 1/5] arm64/sysreg: Add HDBSS related register
 information
In-Reply-To: <86wm3iqlz8.wl-maz@kernel.org>
References: <20251121092342.3393318-1-zhengtian10@huawei.com>
 <20251121092342.3393318-2-zhengtian10@huawei.com>
 <86wm3iqlz8.wl-maz@kernel.org>
Message-ID: <3b41d540-37d1-4b92-91a3-f4094f7ad792@huawei.com>



? 2025/11/22 20:40, Marc Zyngier ??:
> On Fri, 21 Nov 2025 09:23:38 +0000,
> Tian Zheng <zhengtian10 at huawei.com> wrote:
>>
>> From: eillon <yezhenyu2 at huawei.com>
>>
>> The ARM architecture added the HDBSS feature and descriptions of
>> related registers (HDBSSBR/HDBSSPROD) in the DDI0601(ID121123) version,
>> add them to Linux.
>>
>> Signed-off-by: eillon <yezhenyu2 at huawei.com>
>> Signed-off-by: Tian Zheng <zhengtian10 at huawei.com>
>> ---
>>   arch/arm64/include/asm/esr.h     |  2 ++
>>   arch/arm64/include/asm/kvm_arm.h |  1 +
>>   arch/arm64/tools/sysreg          | 28 ++++++++++++++++++++++++++++
>>   3 files changed, 31 insertions(+)
>>
>> diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h
>> index e1deed824464..a6f3cf0b9b86 100644
>> --- a/arch/arm64/include/asm/esr.h
>> +++ b/arch/arm64/include/asm/esr.h
>> @@ -159,6 +159,8 @@
>>   #define ESR_ELx_CM 		(UL(1) << ESR_ELx_CM_SHIFT)
>>
>>   /* ISS2 field definitions for Data Aborts */
>> +#define ESR_ELx_HDBSSF_SHIFT	(11)
>> +#define ESR_ELx_HDBSSF		(UL(1) << ESR_ELx_HDBSSF_SHIFT)
>>   #define ESR_ELx_TnD_SHIFT	(10)
>>   #define ESR_ELx_TnD 		(UL(1) << ESR_ELx_TnD_SHIFT)
>>   #define ESR_ELx_TagAccess_SHIFT	(9)
>> diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
>> index 1da290aeedce..b71122680a03 100644
>> --- a/arch/arm64/include/asm/kvm_arm.h
>> +++ b/arch/arm64/include/asm/kvm_arm.h
>> @@ -124,6 +124,7 @@
>>   			 TCR_EL2_ORGN0_MASK | TCR_EL2_IRGN0_MASK)
>>
>>   /* VTCR_EL2 Registers bits */
>> +#define VTCR_EL2_HDBSS		(1UL << 45)
> 
> I think it is time to convert VTCR_EL2 to the sysreg infrastructure
> instead of adding extra bits here.
> 

Hello Marc, I noticed you added VTCR_EL2 to the sysreg infrastructure in 
this patch:

https://lore.kernel.org/linux-arm-kernel/20251129144525.2609207-3-maz at kernel.org/

Once this patch is merged upstream, I will remove my local definition.

> 	M.
> 



From jacky_chou at aspeedtech.com  Mon Dec  1 22:53:21 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Tue, 2 Dec 2025 06:53:21 +0000
Subject: [PATCH net-next v4 4/4] net: ftgmac100: Add RGMII delay support for
 AST2600
In-Reply-To: <SEYPR06MB513424DDB2D32ADB9C30B5119DDFA@SEYPR06MB5134.apcprd06.prod.outlook.com>
References: <20251110-rgmii_delay_2600-v4-0-5cad32c766f7@aspeedtech.com>
 <20251110-rgmii_delay_2600-v4-4-5cad32c766f7@aspeedtech.com>
 <68f10ee1-d4c8-4498-88b0-90c26d606466@lunn.ch>
 <SEYPR06MB5134EBA2235B3D4BE39B19359DCCA@SEYPR06MB5134.apcprd06.prod.outlook.com>
 <3af52caa-88a7-4b88-bd92-fd47421cc81a@lunn.ch>
 <SEYPR06MB51342977EC2246163D14BDC19DCDA@SEYPR06MB5134.apcprd06.prod.outlook.com>
 <041e23a2-67e6-4ebb-aee5-14400491f99c@lunn.ch>
 <SEYPR06MB5134BC17E80DB66DD385024D9DD1A@SEYPR06MB5134.apcprd06.prod.outlook.com>
 <1c2ace4e-f3bb-4efa-a621-53c3711f46cb@lunn.ch> <aSbA8i5S36GeryXc@fedora>
 <SEYPR06MB513424DDB2D32ADB9C30B5119DDFA@SEYPR06MB5134.apcprd06.prod.outlook.com>
Message-ID: <SEYPR06MB5134A5D1603F39E6025629A19DD8A@SEYPR06MB5134.apcprd06.prod.outlook.com>

> > > How many different boards do you have you can test with? Do you only
> > > have access to RDKs? Or do you have a test farm of customer boards
> > > for regression testing. I would throw the patchset at as many boards
> > > as you can to make sure there are no regressions.
> >
> > I synced with Jacky offline a few times, and I'm happy to test the
> > patches on my Facebook Network OpenBMC platforms.
> >
> > Hi Jacky,
> >
> > Looking forward to your v5, and please don't hesitate to ping me
> > offline if you need more info about my test hardware.
> >
> >
> 
> Hi Andrew,
> 
> Thank you for your suggestions and feedback.
> I will update the patches based on our discussion in the next version.
> 
> Hi Tao,
> 
> Thank you for your support.
> Once I have version 5 ready, I will reach out to you. I appreciate your help in
> verifying the patches on your hardware.
> 

Hi Andrew,

I miss one condition is using fixed-link property.
In ftgmac100, there are RGMII, NC-SI and fixed-link property.
On RGMII, we have solution on dedicated PHY, but there is an issue on fixed-link
property.

Example on dedicated PHY.
The driver can pass the "rgmii-id" to tell PHY driver to enable the internal delay on
PHY side. Therefore, we can force to disable RGMII delay on MAC side.
But there is not any driver when using fixed-link property, which means
no body can tell the outside device, like switch or MAC-to-MAC, to enable the internal
delay on them. Also mean the phy-mode in fixed-link case is not used.

Therefore, could we ignore the RGMII delay on MAC side when the ftgmac100 driver gets
the fixed-link property? Just keep the original delay value?

Thanks,
Jacky



From anshuman.khandual at arm.com  Mon Dec  1 22:57:01 2025
From: anshuman.khandual at arm.com (Anshuman Khandual)
Date: Tue, 2 Dec 2025 12:27:01 +0530
Subject: [v2 PATCH] arm64: mm: Fix kexec failure after pte_mkwrite_novma()
 change
In-Reply-To: <20251202022707.2720933-1-jianpeng.chang.cn@windriver.com>
References: <20251202022707.2720933-1-jianpeng.chang.cn@windriver.com>
Message-ID: <381a3974-aafa-419f-a7ad-ed6e4c1671f0@arm.com>



On 02/12/25 7:57 AM, Jianpeng Chang wrote:
> Commit 143937ca51cc ("arm64, mm: avoid always making PTE dirty in
> pte_mkwrite()") modified pte_mkwrite_novma() to only clear PTE_RDONLY
> when the page is already dirty (PTE_DIRTY is set). While this optimization
> prevents unnecessary dirty page marking in normal memory management paths,
> it breaks kexec on some platforms like NXP LS1043.
> 
> The issue occurs in the kexec code path:
> 1. machine_kexec_post_load() calls trans_pgd_create_copy() to create a
>    writable copy of the linear mapping
> 2. _copy_pte() calls pte_mkwrite_novma() to ensure all pages in the copy
>    are writable for the new kernel image copying
> 3. With the new logic, clean pages (without PTE_DIRTY) remain read-only
> 4. When kexec tries to copy the new kernel image through the linear
>    mapping, it fails on read-only pages, causing the system to hang
>    after "Bye!"
> 
> The same issue affects hibernation which uses the same trans_pgd code path.
> 
> Fix this by explicitly clearing PTE_RDONLY in _copy_pte() for both

via pte_mkdirty() ?

> kexec and hibernation, ensuring all pages in the temporary mapping are
> writable regardless of their dirty state. This preserves the original
> commit's optimization for normal memory management while fixing the
> kexec/hibernation regression.
> 
> Fixes: 143937ca51cc ("arm64, mm: avoid always making PTE dirty in pte_mkwrite()")
> Signed-off-by: Jianpeng Chang <jianpeng.chang.cn at windriver.com>
> ---
> v2:
>   - Use pte_mkwrite_novma(pte_mkdirty(pte)) instead of manual bit manipulation
>   - Updated comments to clarify pte_mkwrite_novma() alone cannot be used
> v1: https://lore.kernel.org/all/20251127034350.3600454-1-jianpeng.chang.cn at windriver.com/
> 
>  arch/arm64/mm/trans_pgd.c | 9 +++++++--
>  1 file changed, 7 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/mm/trans_pgd.c b/arch/arm64/mm/trans_pgd.c
> index 18543b603c77..08f5ee6643e1 100644
> --- a/arch/arm64/mm/trans_pgd.c
> +++ b/arch/arm64/mm/trans_pgd.c
> @@ -40,8 +40,13 @@ static void _copy_pte(pte_t *dst_ptep, pte_t *src_ptep, unsigned long addr)
>  		 * Resume will overwrite areas that may be marked
>  		 * read only (code, rodata). Clear the RDONLY bit from
>  		 * the temporary mappings we use during restore.
> +		 *
> +		 * For kexec/hibernation, we need writable access to all
> +		 * pages in the linear mapping to copy the new kernel image.
> +		 * Mark pages dirty first to ensure pte_mkwrite_novma()
> +		 * clears PTE_RDONLY.
>  		 */

	       /*
		* For both kexec and hibernation, writable accesses are required
		* for all pages in the linear map to copy over new kernel image. 
		* Hence mark these pages dirty first via pte_mkdirty() to ensure
		* pte_mkwrite_novma() subsequently clears PTE_RDONLY - providing
		* required write access for the pages.
		*/

> -		__set_pte(dst_ptep, pte_mkwrite_novma(pte));
> +		__set_pte(dst_ptep, pte_mkwrite_novma(pte_mkdirty(pte)));
>  	} else if (!pte_none(pte)) {
>  		/*
>  		 * debug_pagealloc will removed the PTE_VALID bit if
> @@ -57,7 +62,7 @@ static void _copy_pte(pte_t *dst_ptep, pte_t *src_ptep, unsigned long addr)
>  		 */
>  		BUG_ON(!pfn_valid(pte_pfn(pte)));
>  

The comments should be replicated here as well given the same special situation.

> -		__set_pte(dst_ptep, pte_mkvalid(pte_mkwrite_novma(pte)));
> +		__set_pte(dst_ptep, pte_mkvalid(pte_mkwrite_novma(pte_mkdirty(pte))));
>  	}
>  }
>

static inline pte_t pte_mkwrite_novma(pte_t pte)
{
	pte = set_pte_bit(pte, __pgprot(PTE_WRITE));
	if (pte_sw_dirty(pte))
		pte = clear_pte_bit(pte, __pgprot(PTE_RDONLY));
	return pte;
}

static inline pte_t pte_mkdirty(pte_t pte)
{
	pte = set_pte_bit(pte, __pgprot(PTE_DIRTY));

	if (pte_write(pte))
		pte = clear_pte_bit(pte, __pgprot(PTE_RDONLY));

	return pte;
}

So if pte_write() is true, there will be a redundant PTE_RDONLY clearing which is OK.
Should this be mentioned in the commit message ?


From chaoyi.chen at rock-chips.com  Mon Dec  1 23:00:25 2025
From: chaoyi.chen at rock-chips.com (Chaoyi Chen)
Date: Tue, 2 Dec 2025 15:00:25 +0800
Subject: Issues with DRM_ACCEL_ROCKET (Oops, power-domain, probe-ordering)
In-Reply-To: <77685900-2c34-49b8-8c7e-14718841ef17@rock-chips.com>
References: <0b20d760-ad4f-41c0-b733-39db10d6cc41@cherry.de>
 <77685900-2c34-49b8-8c7e-14718841ef17@rock-chips.com>
Message-ID: <fa82d11f-ce11-4feb-bdb4-c31d360a2a62@rock-chips.com>

Hi Quentin,

I finally had time to look into this today, and I think I've run into
the same issue you did. Please see the comment below :)

On 12/1/2025 2:24 PM, Chaoyi Chen wrote:
> Hi Quentin,
> 
> On 11/29/2025 2:41 AM, Quentin Schulz wrote:
>> Hi all,
>>
>> I've finally found the time to test the RK3588 NPU (aka Rocket, upstream) on our products and I've been hit with Oopses when loosely following the instructions from https://docs.mesa3d.org/teflon.html. After debugging for a while this is often (not always!) reproducible when DRM_ACCEL_ROCKET=y (but not when built as a module!). The fact it's "not always" is a dead giveaway timing or probe order is involved, more later on that.
>>
> 
> This looks like a power domain problem. What would happen if you tried
> enabling the regulator for the NPU power domain in U-Boot?
> 
> Or did you properly configure the corresponding regulator supply in
> the power domain?
> 
> 
>> I don't think the Oops is important as I believe it's a symptom of other issues, so I won't post it.
>>
>> I'll list the issue I've identified so far, some seem easier to fix than others (the biggest issue of course being the hardest to fix).
>>
>> 1. https://elixir.bootlin.com/linux/v6.18-rc7/source/drivers/accel/rocket/rocket_core.c#L79
>>
>> The error path after a failed pm_runtime_resume_and_get() probably should be calling rocket_core_fini(core) and not rocket_job_fini() (the former calls the latter) as to unwind everything that's been done in rocket_core_init() before this failed.
>>
>> The PM core complains about unbalanced something when the core fails to init and is retried later.
>>
>> I suggest the following:
>>
>> """
>> diff --git a/drivers/accel/rocket/rocket_core.c b/drivers/accel/rocket/rocket_core.c
>> index abe7719c1db46..95a732ab418c3 100644
>> --- a/drivers/accel/rocket/rocket_core.c
>> +++ b/drivers/accel/rocket/rocket_core.c
>> @@ -76,7 +76,7 @@ int rocket_core_init(struct rocket_core *core)
>>
>>      err = pm_runtime_resume_and_get(dev);
>>      if (err) {
>> -        rocket_job_fini(core);
>> +        rocket_core_fini(core);
>>          return err;
>>      }
>>

pm_runtime_resume_and_get() will fail here because the pmdomain
isn't ready yet.

I think we should return -EPROBE_DEFER in this case.

>> """
>>
>> I can send a patch for that.
>>
>> 2. rocket_probe() (https://elixir.bootlin.com/linux/v6.18-rc7/source/drivers/accel/rocket/rocket_drv.c#L159) can result in out-of-bounds access when rocket_core_init() fails as rdev is a global variable (so rdev->num_cores persists between tries). Considering rdev->cores is allocated based on the number of available nodes in the DTB with the rknn compatible, if rocket_probe() is called more than the number of available nodes, rdev->cores[core] will result in out-of-bounds access.
>>
>> I believe we could do:
>>
>> """
>> diff --git a/drivers/accel/rocket/rocket_drv.c b/drivers/accel/rocket/rocket_drv.c
>> index 5c0b63f0a8f00..ad602ebd17c44 100644
>> --- a/drivers/accel/rocket/rocket_drv.c
>> +++ b/drivers/accel/rocket/rocket_drv.c
>> @@ -158,6 +158,8 @@ static const struct drm_driver rocket_drm_driver = {
>>
>>  static int rocket_probe(struct platform_device *pdev)
>>  {
>> +    int ret;
>> +
>>      if (rdev == NULL) {
>>          /* First core probing, initialize DRM device. */
>>          rdev = rocket_device_init(drm_dev, &rocket_drm_driver);
>> @@ -177,7 +179,15 @@ static int rocket_probe(struct platform_device *pdev)
>>
>>      rdev->num_cores++;
>>
>> -    return rocket_core_init(&rdev->cores[core]);
>> +    ret = rocket_core_init(&rdev->cores[core]);
>> +    if (ret) {
>> +        rdev->num_cores--;
>> +        if (rdev->num_cores == 0) {
>> +            rocket_device_fini(rdev);
>> +        }
>> +    }
>> +
>> +    return ret;
>>  }
>>
>>  static void rocket_remove(struct platform_device *pdev)
>>
>> """
>>
> 
> It seems hacky. I'm not sure whether this would be better
> implemented as a component driver.
>

When I was looking at this code, it hadn't been merged yet,
and there is a core0 device called "rknn_top". Likewise, there's 
a component over there. But in the latest version, it's gone :(

And yes, core 0 is special [0]. So I think this change is make sense.
But that's still not enough, because we may need to defer the probe.
We have to make sure that when we probe next time, core 0 still gets
index 0 here.

[0] https://lore.kernel.org/all/20250721-6-10-rocket-v9-8-77ebd484941e at tomeuvizoso.net/

>> I can send a patch for that.
>>
>> 3. I believe (but I may be wrong) that core 0 is special (do we need to schedule through core 0 maybe?). There's a hardcoded fetch of the device associated with core 0 via rocket_iommu_domain_create(rdev->cores[0].dev); (https://elixir.bootlin.com/linux/v6.18-rc7/source/drivers/accel/rocket/rocket_drv.c#L88). The issue is that this assumes that core 0 is always rdev->cores[0], which may not be true as it depends on the probe order (which is not guaranteed), which can be exacerbated by core 0 (HW index) probe being deferred for some reason. Is it necessary for core 0 to be the one initializing the DRM device or could we simply use any core for that (just the first to probe, whichever it actually is HW-wise)?

I agree with you about the probe order problem. As I mentioned, 
in earlier versions core 0 was still "rknn_top". It looks like this
would address many of the problem you raised. I don't know why 
that was dropped in the merged version.

> 
> I think this is because multiple cores share the same IOMMU device.
> 
>>
>> If there's a need to know which of the three cores is core 0, we can have a vendor property for it or maybe aliases for the cores? We can also do a check on the base register address of the core in DT and then do a mapping in the driver. Any other suggestion?
>>
>> 4. The actual issue I'm unable to suggest something for comes now. The following is all happening in the context of DRM_ACCEL_ROCKET being built-in (that is DRM_ACCEL_ROCKET=y). You can use aarch64's default defconfig, then DRM=y, DRM_ACCEL=y and DRM_ACCEL_ROCKET=y via menuconfig. Remember that this is not 100% reproducible (more often happening than not).
>>
>> Points 1, 2 and 3 only are an issue if you hit some error-path during the probe of one of the cores, which is triggered by this point 4 here.
>>
>> rknn_core_0 depends on rknn_mmu_0 as highlighted by the iommus phandle property. rknn_mmu_0 depends on RK3588_PD_NPUTOP power-domain. The parent domain (RK3588_PD_NPU) of RK3588_PD_NPUTOP power-domain has a domain-supply on a regulator on i2c (i2c0 at 42 for Jaguar, patches on the ML at https://lore.kernel.org/linux-rockchip/20250812085213.1071106-2-heiko at sntech.de/). When the rocket driver calls platform_driver_register() in its module_init() function, the kernel core will try to probe the associated device, via driver_probe_device(), then __driver_probe_device() and more specifically pm_runtime_get_suppliers(dev) in there (https://elixir.bootlin.com/linux/v6.18-rc7/source/drivers/base/dd.c#L793). Then this calls pm_runtime_get_sync() on all links, c.f. https://elixir.bootlin.com/linux/v6.18-rc7/source/drivers/base/power/runtime.c#L1914. Note that pm_runtime_get_suppliers() returns void. One of the links is the rknn_mmu_0.
>>
>> Follow the next series of function calls, pm_runtime_get_sync() on rknn_mmu_0, rpm_resume(), rpm_callback(), __rpm_callback(). This then calls cb(). cb() is set via RPM_GET_CALLBACK(dev, runtime_resume). Due to rknn_mmu_0 device being probed with dev_pm_domain_attach() attaching the power-domain device to iommu via the pm_domain member, genpd_runtime_resume() (which goes to rockchip_pd_power_on()) is actually called. This then calls rockchip_pd_regulator_enable() which returns -EPROBE_DEFER. Going up in the call stack up to rpm_callback() you can see that retval = __rpm_callback(cb, dev); now is EPROBE_DEFER and thus, dev->power.runtime_error = EPROBE_DEFER at the end of the function.
>>
>> Then once pm_runtime_resume_and_get(dev); is called in rocket_core_init() during probe of the rocket device, it'll call into rpm_get_suppliers() in __rpm_callback() which in turn will call pm_runtime_get_sync() on rknn_mmu_0 which will go up to rpm_resume() where dev->power.runtime_error will be checked and if non-zero will return -EINVAL, effectively eating -EPROBE_DEFER and failing the probe of the rocket device instead of deferring the probe.
>>
>> Applying the below patch:
>>
>> """
>> diff --git a/drivers/accel/rocket/rocket_core.c b/drivers/accel/rocket/rocket_core.c
>> index abe7719c1db46..c4692189bbfc6 100644
>> --- a/drivers/accel/rocket/rocket_core.c
>> +++ b/drivers/accel/rocket/rocket_core.c
>> @@ -72,22 +72,9 @@ int rocket_core_init(struct rocket_core *core)
>>       */
>>      pm_runtime_set_autosuspend_delay(dev, 50);
>>
>> +    pm_runtime_set_suspended(dev);
>>      pm_runtime_enable(dev);
>>
>> -    err = pm_runtime_resume_and_get(dev);
>> -    if (err) {
>> -        rocket_job_fini(core);
>> -        return err;
>> -    }
>> -
>> -    version = rocket_pc_readl(core, VERSION);
>> -    version += rocket_pc_readl(core, VERSION_NUM) & 0xffff;
>> -
>> -    pm_runtime_mark_last_busy(dev);
>> -    pm_runtime_put_autosuspend(dev);
>> -
>> -    dev_info(dev, "Rockchip NPU core %d version: %d\n", core->index, version);
>> -
>>      return 0;
>>  }
>>
>> """
>>

I believe that once the problems above are resolved, the complexity
around point 4 will disappear as well.

>> seems to make it possible to run mesa's example. If pm_runtime_set_suspended(dev); isn't added, we'll only ever get job timeouts.
>>
>> Note that I'm pretty sure this isn't the proper way to do it but wanted to give some of my debugging attempts at that.
>>
>> I'm not sure how much further I can go and specifically I have no clue how to handle that properly. Please also verify all the claims I'm making, I'm not entirely sure I got every call stack right, it is quite convoluted and I don't have experience with those frameworks.
>>
>> Does anyone have a clue how we can deal with that?
>>
>> The driver built as a module doesn't have this issue because the regulator has enough time to probe so that PD doesn't return EPROBE_DEFER when the rocket device gets probed once reaching userspace (where the module is). I'm not entirely sure if this could be reproduced by having the regulator driver as a module too for example?
>>
>> Cheers,
>> Quentin
>>
>> _______________________________________________
>> Linux-rockchip mailing list
>> Linux-rockchip at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-rockchip
> 

-- 
Best, 
Chaoyi


From carlos.song at nxp.com  Mon Dec  1 23:00:58 2025
From: carlos.song at nxp.com (Carlos Song)
Date: Tue, 2 Dec 2025 07:00:58 +0000
Subject: [PATCH 6/6] spi: imx: enable DMA mode for target operation
In-Reply-To: <aSXT5tzhfHYVUrGy@lizhi-Precision-Tower-5810>
References: <20251125100618.2159770-1-carlos.song@nxp.com>
 <20251125100618.2159770-7-carlos.song@nxp.com>
 <aSXT5tzhfHYVUrGy@lizhi-Precision-Tower-5810>
Message-ID: <VI2PR04MB11147D35A22A7B29384468B21E8D8A@VI2PR04MB11147.eurprd04.prod.outlook.com>



> -----Original Message-----
> From: Frank Li <frank.li at nxp.com>
> Sent: Wednesday, November 26, 2025 12:06 AM
> To: Carlos Song <carlos.song at nxp.com>
> Cc: broonie at kernel.org; hawnguo at kernel.org; s.hauer at pengutronix.de;
> kernel at pengutronix.de; festevam at gmail.com; linux-spi at vger.kernel.org;
> imx at lists.linux.dev; linux-arm-kernel at lists.infradead.org;
> linux-kernel at vger.kernel.org
> Subject: Re: [PATCH 6/6] spi: imx: enable DMA mode for target operation
> 
> On Tue, Nov 25, 2025 at 06:06:18PM +0800, Carlos Song wrote:
> > Enable DMA mode for SPI IMX in target mode.
> > Disable the word delay feature for target mode, because target mode
> > should always keep high performance to make sure it can follow the
> > master. Target mode continues to operate in dynamic burst mode.
> 
> If two paragraph, need extra empty line. If one parapraph, move to previous
> line.
> 
> >
> > Signed-off-by: Carlos Song <carlos.song at nxp.com>
> > ---
> >  drivers/spi/spi-imx.c | 78
> > +++++++++++++++++++++++++++++++------------
> >  1 file changed, 56 insertions(+), 22 deletions(-)
> >
> ...
> >
> > @@ -1756,23 +1753,51 @@ static int spi_imx_dma_submit(struct
> > spi_imx_data *spi_imx,
> >
> >  	transfer_timeout = spi_imx_calculate_timeout(spi_imx,
> > transfer->len);
> >
> > -	/* Wait SDMA to finish the data transfer.*/
> > -	time_left = wait_for_completion_timeout(&spi_imx->dma_tx_completion,
> > -						transfer_timeout);
> > -	if (!time_left) {
> > -		dev_err(spi_imx->dev, "I/O Error in DMA TX\n");
> > -		dmaengine_terminate_all(controller->dma_tx);
> > -		dmaengine_terminate_all(controller->dma_rx);
> > -		return -ETIMEDOUT;
> > -	}
> > +	if (!spi_imx->target_mode) {
> > +		/* Wait SDMA to finish the data transfer.*/
> > +		time_left =
> wait_for_completion_timeout(&spi_imx->dma_tx_completion,
> > +							transfer_timeout);
> > +		if (!time_left) {
> > +			dev_err(spi_imx->dev, "I/O Error in DMA TX\n");
> > +			dmaengine_terminate_all(controller->dma_tx);
> > +			dmaengine_terminate_all(controller->dma_rx);
> > +			return -ETIMEDOUT;
> > +		}
> >
> > -	time_left = wait_for_completion_timeout(&spi_imx->dma_rx_completion,
> > -						transfer_timeout);
> > -	if (!time_left) {
> > -		dev_err(&controller->dev, "I/O Error in DMA RX\n");
> > -		spi_imx->devtype_data->reset(spi_imx);
> > -		dmaengine_terminate_all(controller->dma_rx);
> > -		return -ETIMEDOUT;
> > +		time_left =
> wait_for_completion_timeout(&spi_imx->dma_rx_completion,
> > +							transfer_timeout);
> > +		if (!time_left) {
> > +			dev_err(&controller->dev, "I/O Error in DMA RX\n");
> > +			spi_imx->devtype_data->reset(spi_imx);
> > +			dmaengine_terminate_all(controller->dma_rx);
> > +			return -ETIMEDOUT;
> > +		}
> > +	} else {
> > +		spi_imx->target_aborted = false;
> > +
> > +		if (wait_for_completion_interruptible(&spi_imx->dma_tx_completion)
> ||
> > +		    spi_imx->target_aborted) {
> 
Hi, Frank
Sorry missing these questions:

> Suppose somewhere set target_aborted to true. I think here should use
> READ_ONCE() to make sure read from memory.
> 

Will do this in V2.

> Not sure why here use wait_for_completion_interruptible() but at master mode
> use wait_for_completion_timeout().
>

Because target should support ctrl+c to stop this transfer(need interruptible) and target will keep waiting until the master clocks coming to shift out/in data(don't need timeout).
So use wait_for_completion_interruptible() for target mode

> > +			dev_dbg(spi_imx->dev, "I/O Error in DMA TX interrupted\n");
> > +			dmaengine_terminate_all(controller->dma_tx);
> > +			dmaengine_terminate_all(controller->dma_rx);
> > +			return -EINTR;
> > +		}
> > +
> > +		if (wait_for_completion_interruptible(&spi_imx->dma_rx_completion)
> ||
> > +		    spi_imx->target_aborted) {
> > +			dev_dbg(spi_imx->dev, "I/O Error in DMA RX interrupted\n");
> > +			dmaengine_terminate_all(controller->dma_rx);
> > +			return -EINTR;
> > +		}
> > +
> > +		/*
> > +		 * ECSPI has a HW issue when works in Target mode, after 64 words
> > +		 * writtern to TXFIFO, even TXFIFO becomes empty, ECSPI_TXDATA
> keeps
> > +		 * shift out the last word data, so we have to disable ECSPI when in
> > +		 * target mode after the transfer completes.
> > +		 */
> > +		if (spi_imx->devtype_data->disable)
> > +			spi_imx->devtype_data->disable(spi_imx);
> >  	}
> >
> >  	return 0;
> > @@ -1895,10 +1920,16 @@ static int spi_imx_dma_package_transfer(struct
> > spi_imx_data *spi_imx,  static int spi_imx_dma_transfer(struct spi_imx_data
> *spi_imx,
> >  				struct spi_transfer *transfer)
> >  {
> > -	bool word_delay = transfer->word_delay.value != 0;
> > +	bool word_delay = transfer->word_delay.value != 0 &&
> > +!spi_imx->target_mode;
> >  	int ret;
> >  	int i;
> >
> > +	if (transfer->len > MX53_MAX_TRANSFER_BYTES &&
> spi_imx->target_mode)
> > +{
> 
> why only target have len limiation?
> 
> Frank

This is a errata:
Due to Freescale errata ERR003775 "eCSPI: Burst completion by Chip Select (SS) signal in Slave mode is not functional" burst size must be set exactly to the size of the transfer.
This limit SPI transaction with maximum 2^12 bits.

So I add a limit for this. I will comment at V2.

Carlos
> > +		dev_err(spi_imx->dev, "Transaction too big, max size is %d bytes\n",
> > +			MX53_MAX_TRANSFER_BYTES);
> > +		return -EMSGSIZE;
> > +	}
> > +
> >  	ret = spi_imx_dma_data_prepare(spi_imx, transfer, word_delay);
> >  	if (ret < 0) {
> >  		transfer->error |= SPI_TRANS_FAIL_NO_START; @@ -2104,7 +2135,7
> @@
> > static int spi_imx_transfer_one(struct spi_controller *controller,
> >  	while (spi_imx->devtype_data->rx_available(spi_imx))
> >  		readl(spi_imx->base + MXC_CSPIRXDATA);
> >
> > -	if (spi_imx->target_mode)
> > +	if (spi_imx->target_mode && !spi_imx->usedma)
> >  		return spi_imx_pio_transfer_target(spi, transfer);
> >
> >  	/*
> > @@ -2116,7 +2147,10 @@ static int spi_imx_transfer_one(struct
> spi_controller *controller,
> >  		ret = spi_imx_dma_transfer(spi_imx, transfer);
> >  		if (transfer->error & SPI_TRANS_FAIL_NO_START) {
> >  			spi_imx->usedma = false;
> > -			return spi_imx_pio_transfer(spi, transfer);
> > +			if (spi_imx->target_mode)
> > +				return spi_imx_pio_transfer_target(spi, transfer);
> > +			else
> > +				return spi_imx_pio_transfer(spi, transfer);
> >  		}
> >  		return ret;
> >  	}
> > --
> > 2.34.1
> >


From jammy_huang at aspeedtech.com  Mon Dec  1 23:15:55 2025
From: jammy_huang at aspeedtech.com (Jammy Huang)
Date: Tue, 2 Dec 2025 07:15:55 +0000
Subject: [PATCH] media: aspeed: Fix dram hang at res-change
In-Reply-To: <720c855b.36b0.19addc99578.Coremail.wangmin@phytium.com.cn>
References: <20251124-video_dram_reset-v1-1-9d37229e4ec5@aspeedtech.com>
 <120162b9.3256.19aca13d4e0.Coremail.wangmin@phytium.com.cn>
 <TYZPR06MB656876892F6046F22AD87073F1DBA@TYZPR06MB6568.apcprd06.prod.outlook.com>
 <720c855b.36b0.19addc99578.Coremail.wangmin@phytium.com.cn>
Message-ID: <TYZPR06MB65685571EFD73A850A452A71F1D8A@TYZPR06MB6568.apcprd06.prod.outlook.com>

Hi Wang,

This mail thread is not for product support but for linux kernel upstream.

If you encounter some issue using ASPEED product, please contact our sales who
will provide proper response for your issue.


> >
> > Hi Wang,
> >
> > Thanks for your feedback.
> >
> > Regards,
> > Jammy Huang
> >
> > > >
> > > > Dram hang could happen in the steps below:
> > > > 1. start capture/compression
> > > > 2. out-of-lock watchdog raise irq because of res-change.
> > > > 3. aspeed_video_irq_res_change do clk-off
> > > >
> > > > At step3, capture/compression could be not accomplished yet. If
> > > > clk-off in the middle of video operation, dram controller could
> > > > hang at
> > > ast2500.
> > > >
> > > > Use reset rather than clk-off/on to avoid this problem.
> > > >
> > > > Signed-off-by: Jammy Huang <jammy_huang at aspeedtech.com>
> > > > ---
> > > > On Aspeed KVM testing, we found it could lead to dram-hang if
> > > > res-change. Although the issue rarely happens, the impact is serious.
> > >
> > > Capturing and compressing the video stream takes longer than the
> > > video engine?s idle period.
> > Sorry, but this is not what I mean. The issue happens because video
> > engine's clk is turned off during capture/compression.
> >
> > > If this is not the intended behavior, please increase the frame
> > > rate. This makes resolution switches more prone to happen when the video
> engine is working.
> > > However, according to your email, this issue rarely occurs. Is there
> > > a similar issue on the AST2600 SoC?
> > Increase frame rate would not helpful. This is a video compression
> > engine. The time taken for each frame's capture/compression is the
> > same. The way to reproduce this issue we did is continuously
> resolution-switch.
> >
> Thank you for the clarification.
> 
> I am encountering another issue related to resolution switching on the
> AST2500 SoC.
> When repeatedly switching from other resolutions to 1680x1050, or from
> 1680x1050 to other resolutions, there is a high likelihood that either the BMC
> OS will hang or the KVM screen will experience tearing. Could you please
> attempt to reproduce this issue and provide a resolution?
> 
> > >
> > > >
> > > > To avoid this issue, we use reset only rathar than clk-off/on in
> > > > res-change to avoid this issue.
> > > > ---
> > > >  drivers/media/platform/aspeed/aspeed-video.c | 22
> > > > +++++++++++++++++++---
> > > >  1 file changed, 19 insertions(+), 3 deletions(-)
> > > >
> > > > diff --git a/drivers/media/platform/aspeed/aspeed-video.c
> > > > b/drivers/media/platform/aspeed/aspeed-video.c
> > > > index b83e432452..41cb96f601 100644
> > > > --- a/drivers/media/platform/aspeed/aspeed-video.c
> > > > +++ b/drivers/media/platform/aspeed/aspeed-video.c
> > > > @@ -26,6 +26,7 @@
> > > >  #include <linux/workqueue.h>
> > > >  #include <linux/debugfs.h>
> > > >  #include <linux/ktime.h>
> > > > +#include <linux/reset.h>
> > > >  #include <linux/regmap.h>
> > > >  #include <linux/mfd/syscon.h>
> > > >  #include <media/v4l2-ctrls.h>
> > > > @@ -310,6 +311,7 @@ struct aspeed_video {
> > > >  	void __iomem *base;
> > > >  	struct clk *eclk;
> > > >  	struct clk *vclk;
> > > > +	struct reset_control *reset;
> > > >
> > > >  	struct device *dev;
> > > >  	struct v4l2_ctrl_handler ctrl_handler; @@ -720,6 +722,13 @@
> > > > static void aspeed_video_on(struct aspeed_video *video)
> > > >  	set_bit(VIDEO_CLOCKS_ON, &video->flags);  }
> > > >
> > > > +static void aspeed_video_reset(struct aspeed_video *v) {
> > > > +	reset_control_assert(v->reset);
> > > > +	usleep_range(100, 150);
> > > > +	reset_control_deassert(v->reset); }
> > > > +
> > > >  static void aspeed_video_bufs_done(struct aspeed_video *video,
> > > >  				   enum vb2_buffer_state state)  { @@ -742,7
> +751,9 @@ static
> > > > void aspeed_video_irq_res_change(struct
> > > > aspeed_video *video, ulong delay)
> > > >
> > > >  	video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL;
> > > >
> > > > -	aspeed_video_off(video);
> > > > +	aspeed_video_write(video, VE_INTERRUPT_CTRL, 0);
> > > > +	aspeed_video_write(video, VE_INTERRUPT_STATUS, 0xffffffff);
> > > > +	aspeed_video_reset(video);
> > > >  	aspeed_video_bufs_done(video, VB2_BUF_STATE_ERROR);
> > > >
> > > >  	schedule_delayed_work(&video->res_work, delay); @@ -1984,8
> > > > +1995,7 @@ static void aspeed_video_stop_streaming(struct vb2_queue
> *q)
> > > >  		 * Need to force stop any DMA and try and get HW into a good
> > > >  		 * state for future calls to start streaming again.
> > > >  		 */
> > > > -		aspeed_video_off(video);
> > > > -		aspeed_video_on(video);
> > > > +		aspeed_video_reset(video);
> > > >
> > > >  		aspeed_video_init_regs(video);
> > > >
> > > > @@ -2230,6 +2240,12 @@ static int aspeed_video_init(struct
> > > > aspeed_video
> > > *video)
> > > >  	}
> > > >  	dev_info(video->dev, "irq %d\n", irq);
> > > >
> > > > +	video->reset = devm_reset_control_get(dev, NULL);
> > > > +	if (IS_ERR(video->reset)) {
> > > > +		dev_err(dev, "Unable to get reset\n");
> > > > +		return PTR_ERR(video->reset);
> > > > +	}
> > > > +
> > > >  	video->eclk = devm_clk_get(dev, "eclk");
> > > >  	if (IS_ERR(video->eclk)) {
> > > >  		dev_err(dev, "Unable to get ECLK\n");
> > > >
> > > > ---
> > > > base-commit: ac3fd01e4c1efce8f2c054cdeb2ddd2fc0fb150d
> > > > change-id: 20251124-video_dram_reset-c531f6ba573f
> > > >
> > > > Best regards,
> > > > --
> > > > Jammy Huang <jammy_huang at aspeedtech.com>
> > > >
> > >
> 
> 
> ????????????????????????,????????
> ??????????????????,?????????,?????
> ??????????????????
> Information Security Notice: The information contained in this mail is solely
> property of the sender's organization.This mail communication is
> confidential.Recipients named above are obligated to maintain secrecy and are
> not permitted to disclose the contents of this communication to others.

From wangmin at phytium.com.cn  Mon Dec  1 23:28:46 2025
From: wangmin at phytium.com.cn (=?UTF-8?B?546L5pWP?=)
Date: Tue, 2 Dec 2025 15:28:46 +0800 (GMT+08:00)
Subject: [PATCH] media: aspeed: Fix dram hang at res-change
In-Reply-To: <TYZPR06MB65685571EFD73A850A452A71F1D8A@TYZPR06MB6568.apcprd06.prod.outlook.com>
References: <20251124-video_dram_reset-v1-1-9d37229e4ec5@aspeedtech.com>
 <120162b9.3256.19aca13d4e0.Coremail.wangmin@phytium.com.cn>
 <TYZPR06MB656876892F6046F22AD87073F1DBA@TYZPR06MB6568.apcprd06.prod.outlook.com>
 <720c855b.36b0.19addc99578.Coremail.wangmin@phytium.com.cn>
 <TYZPR06MB65685571EFD73A850A452A71F1D8A@TYZPR06MB6568.apcprd06.prod.outlook.com>
Message-ID: <7ecc072f.36ed.19addf6bbe6.Coremail.wangmin@phytium.com.cn>




> -----????-----
> ???: "Jammy Huang" <jammy_huang at aspeedtech.com>
> ????:2025-12-02 15:15:55 (???)
> ???: ?? <wangmin at phytium.com.cn>, "openbmc at lists.ozlabs.org" <openbmc at lists.ozlabs.org>
> ??: "Eddie James" <eajames at linux.ibm.com>, "Mauro Carvalho Chehab" <mchehab at kernel.org>, "Joel Stanley" <joel at jms.id.au>, "Andrew Jeffery" <andrew at codeconstruct.com.au>, "Philipp Zabel" <p.zabel at pengutronix.de>, "linux-media at vger.kernel.org" <linux-media at vger.kernel.org>, "linux-arm-kernel at lists.infradead.org" <linux-arm-kernel at lists.infradead.org>, "linux-aspeed at lists.ozlabs.org" <linux-aspeed at lists.ozlabs.org>, "linux-kernel at vger.kernel.org" <linux-kernel at vger.kernel.org>, ??? <shuyiqi at phytium.com.cn>
> ??: RE: RE: [PATCH] media: aspeed: Fix dram hang at res-change
> 
> Hi Wang,
> 
> This mail thread is not for product support but for linux kernel upstream.
> 
> If you encounter some issue using ASPEED product, please contact our sales who
> will provide proper response for your issue.
> 
Got it. Appreciate your quick response.
> > >
> > > Hi Wang,
> > >
> > > Thanks for your feedback.
> > >
> > > Regards,
> > > Jammy Huang
> > >
> > > > >
> > > > > Dram hang could happen in the steps below:
> > > > > 1. start capture/compression
> > > > > 2. out-of-lock watchdog raise irq because of res-change.
> > > > > 3. aspeed_video_irq_res_change do clk-off
> > > > >
> > > > > At step3, capture/compression could be not accomplished yet. If
> > > > > clk-off in the middle of video operation, dram controller could
> > > > > hang at
> > > > ast2500.
> > > > >
> > > > > Use reset rather than clk-off/on to avoid this problem.
> > > > >
> > > > > Signed-off-by: Jammy Huang <jammy_huang at aspeedtech.com>
> > > > > ---
> > > > > On Aspeed KVM testing, we found it could lead to dram-hang if
> > > > > res-change. Although the issue rarely happens, the impact is serious.
> > > >
> > > > Capturing and compressing the video stream takes longer than the
> > > > video engine?s idle period.
> > > Sorry, but this is not what I mean. The issue happens because video
> > > engine's clk is turned off during capture/compression.
> > >
> > > > If this is not the intended behavior, please increase the frame
> > > > rate. This makes resolution switches more prone to happen when the video
> > engine is working.
> > > > However, according to your email, this issue rarely occurs. Is there
> > > > a similar issue on the AST2600 SoC?
> > > Increase frame rate would not helpful. This is a video compression
> > > engine. The time taken for each frame's capture/compression is the
> > > same. The way to reproduce this issue we did is continuously
> > resolution-switch.
> > >
> > Thank you for the clarification.
> > 
> > I am encountering another issue related to resolution switching on the
> > AST2500 SoC.
> > When repeatedly switching from other resolutions to 1680x1050, or from
> > 1680x1050 to other resolutions, there is a high likelihood that either the BMC
> > OS will hang or the KVM screen will experience tearing. Could you please
> > attempt to reproduce this issue and provide a resolution?
> > 
> > > >
> > > > >
> > > > > To avoid this issue, we use reset only rathar than clk-off/on in
> > > > > res-change to avoid this issue.
> > > > > ---
> > > > >  drivers/media/platform/aspeed/aspeed-video.c | 22
> > > > > +++++++++++++++++++---
> > > > >  1 file changed, 19 insertions(+), 3 deletions(-)
> > > > >
> > > > > diff --git a/drivers/media/platform/aspeed/aspeed-video.c
> > > > > b/drivers/media/platform/aspeed/aspeed-video.c
> > > > > index b83e432452..41cb96f601 100644
> > > > > --- a/drivers/media/platform/aspeed/aspeed-video.c
> > > > > +++ b/drivers/media/platform/aspeed/aspeed-video.c
> > > > > @@ -26,6 +26,7 @@
> > > > >  #include <linux/workqueue.h>
> > > > >  #include <linux/debugfs.h>
> > > > >  #include <linux/ktime.h>
> > > > > +#include <linux/reset.h>
> > > > >  #include <linux/regmap.h>
> > > > >  #include <linux/mfd/syscon.h>
> > > > >  #include <media/v4l2-ctrls.h>
> > > > > @@ -310,6 +311,7 @@ struct aspeed_video {
> > > > >  	void __iomem *base;
> > > > >  	struct clk *eclk;
> > > > >  	struct clk *vclk;
> > > > > +	struct reset_control *reset;
> > > > >
> > > > >  	struct device *dev;
> > > > >  	struct v4l2_ctrl_handler ctrl_handler; @@ -720,6 +722,13 @@
> > > > > static void aspeed_video_on(struct aspeed_video *video)
> > > > >  	set_bit(VIDEO_CLOCKS_ON, &video->flags);  }
> > > > >
> > > > > +static void aspeed_video_reset(struct aspeed_video *v) {
> > > > > +	reset_control_assert(v->reset);
> > > > > +	usleep_range(100, 150);
> > > > > +	reset_control_deassert(v->reset); }
> > > > > +
> > > > >  static void aspeed_video_bufs_done(struct aspeed_video *video,
> > > > >  				   enum vb2_buffer_state state)  { @@ -742,7
> > +751,9 @@ static
> > > > > void aspeed_video_irq_res_change(struct
> > > > > aspeed_video *video, ulong delay)
> > > > >
> > > > >  	video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL;
> > > > >
> > > > > -	aspeed_video_off(video);
> > > > > +	aspeed_video_write(video, VE_INTERRUPT_CTRL, 0);
> > > > > +	aspeed_video_write(video, VE_INTERRUPT_STATUS, 0xffffffff);
> > > > > +	aspeed_video_reset(video);
> > > > >  	aspeed_video_bufs_done(video, VB2_BUF_STATE_ERROR);
> > > > >
> > > > >  	schedule_delayed_work(&video->res_work, delay); @@ -1984,8
> > > > > +1995,7 @@ static void aspeed_video_stop_streaming(struct vb2_queue
> > *q)
> > > > >  		 * Need to force stop any DMA and try and get HW into a good
> > > > >  		 * state for future calls to start streaming again.
> > > > >  		 */
> > > > > -		aspeed_video_off(video);
> > > > > -		aspeed_video_on(video);
> > > > > +		aspeed_video_reset(video);
> > > > >
> > > > >  		aspeed_video_init_regs(video);
> > > > >
> > > > > @@ -2230,6 +2240,12 @@ static int aspeed_video_init(struct
> > > > > aspeed_video
> > > > *video)
> > > > >  	}
> > > > >  	dev_info(video->dev, "irq %d\n", irq);
> > > > >
> > > > > +	video->reset = devm_reset_control_get(dev, NULL);
> > > > > +	if (IS_ERR(video->reset)) {
> > > > > +		dev_err(dev, "Unable to get reset\n");
> > > > > +		return PTR_ERR(video->reset);
> > > > > +	}
> > > > > +
> > > > >  	video->eclk = devm_clk_get(dev, "eclk");
> > > > >  	if (IS_ERR(video->eclk)) {
> > > > >  		dev_err(dev, "Unable to get ECLK\n");
> > > > >
> > > > > ---
> > > > > base-commit: ac3fd01e4c1efce8f2c054cdeb2ddd2fc0fb150d
> > > > > change-id: 20251124-video_dram_reset-c531f6ba573f
> > > > >
> > > > > Best regards,
> > > > > --
> > > > > Jammy Huang <jammy_huang at aspeedtech.com>
> > > > >
> > > >
> > 
> > 
> > ????????????????????????,????????
> > ??????????????????,?????????,?????
> > ??????????????????
> > Information Security Notice: The information contained in this mail is solely
> > property of the sender's organization.This mail communication is
> > confidential.Recipients named above are obligated to maintain secrecy and are
> > not permitted to disclose the contents of this communication to others.



????????????????????????,??????????????????????????,?????????,???????????????????????
Information Security Notice: The information contained in this mail is solely property of the sender's organization.This mail communication is confidential.Recipients named above are obligated to maintain secrecy and are not permitted to disclose the contents of this communication to others.

From hch at infradead.org  Mon Dec  1 23:35:10 2025
From: hch at infradead.org (Christoph Hellwig)
Date: Mon, 1 Dec 2025 23:35:10 -0800
Subject: KASAN triggering on generic/475 on aarch64?
In-Reply-To: <20251202005911.GF89472@frogsfrogsfrogs>
References: <20251202005911.GF89472@frogsfrogsfrogs>
Message-ID: <aS6Wrmz74IMh_NtW@infradead.org>

On Mon, Dec 01, 2025 at 04:59:11PM -0800, Darrick J. Wong wrote:
> Hi everyone,
> 
> Does anyone else see weird warnings and crashes in the kernel timer code
> when running generic/475 for a couple of hours on arm64?

I'm pretty the population of folks running generic/475 for a few hours
on arm is rather low :)  But given that this is low-level arm stuff
adding the arm list might make sense.

> I turned on
> KASAN and got the following report:
> 
> [ 1080.098534] XFS (dm-0): EXPERIMENTAL metadata directory tree feature enabled.  Use at your own risk!
> [ 1080.101096] XFS (dm-0): Mounting V5 Filesystem 056cb806-0bb7-401d-a116-1bc85c6026b5
> [ 1080.190389] XFS (dm-0): Starting recovery (logdev: internal)
> [ 1080.292266] XFS (dm-0): Ending recovery (logdev: internal)
> [ 1081.456848] iomap_finish_ioend_buffered: 26 callbacks suppressed
> [ 1081.456867] dm-0: writeback error on inode 70234311, offset 1073152, sector 38493904
> [ 1081.456954] XFS (dm-0): log I/O error -5
> [ 1081.456960] XFS (dm-0): Filesystem has been shut down due to log error (0x2).
> [ 1081.456963] XFS (dm-0): Please unmount the filesystem and rectify the problem(s).
> [ 1081.456967] CPU: 1 UID: 0 PID: 111 Comm: 1:1H Not tainted 6.18.0-xfsa #5 PREEMPTLAZY  aa447adfe084b5fbc6023ad319929e88e68ca52d
> [ 1081.456973] Hardware name: QEMU KVM Virtual Machine, BIOS 1.6.6 08/22/2023
> [ 1081.456975] Workqueue: xfs-log/dm-0 xlog_ioend_work [xfs]
> [ 1081.466571] Call trace:
> [ 1081.466573]  show_stack+0x20/0x40 (C)
> [ 1081.466580]  dump_stack_lvl+0x60/0x80
> [ 1081.466585]  dump_stack+0x1c/0x28
> [ 1081.466588]  xlog_force_shutdown+0x36c/0x400 [xfs 7a664e8b2565bbf246e2d705932ac3446adc6009]
> [ 1081.473209]  xlog_ioend_work+0xe8/0x1a0 [xfs 7a664e8b2565bbf246e2d705932ac3446adc6009]
> [ 1081.473414]  process_one_work+0x564/0xfb8
> [ 1081.473421]  worker_thread+0x4e0/0xc90
> [ 1081.473425]  kthread+0x350/0x630
> [ 1081.473429]  ret_from_fork+0x10/0x20
> [ 1081.479204] dm-0: writeback error on inode 3338862, offset 23678976, sector 20967632
> [ 1081.484022] buffer_io_error: 502 callbacks suppressed
> [ 1081.484053] Buffer I/O error on dev dm-0, logical block 0, async page read
> [ 1081.484069] Buffer I/O error on dev dm-0, logical block 1, async page read
> [ 1081.484080] Buffer I/O error on dev dm-0, logical block 2, async page read
> [ 1081.484088] Buffer I/O error on dev dm-0, logical block 3, async page read
> [ 1081.484097] Buffer I/O error on dev dm-0, logical block 4, async page read
> [ 1081.484106] Buffer I/O error on dev dm-0, logical block 5, async page read
> [ 1081.484114] Buffer I/O error on dev dm-0, logical block 6, async page read
> [ 1081.498036] Buffer I/O error on dev dm-0, logical block 7, async page read
> [ 1081.498058] Buffer I/O error on dev dm-0, logical block 8, async page read
> [ 1081.498069] Buffer I/O error on dev dm-0, logical block 9, async page read
> [ 1081.594384] XFS (dm-0): Unmounting Filesystem 056cb806-0bb7-401d-a116-1bc85c6026b5
> [ 1081.738455] XFS (dm-0): EXPERIMENTAL metadata directory tree feature enabled.  Use at your own risk!
> [ 1081.741840] XFS (dm-0): Mounting V5 Filesystem 056cb806-0bb7-401d-a116-1bc85c6026b5
> [ 1082.351959] XFS (dm-0): Starting recovery (logdev: internal)
> [ 1082.699264] XFS (dm-0): Ending recovery (logdev: internal)
> [ 1084.392933] ==================================================================
> [ 1084.392951] BUG: KASAN: slab-use-after-free in __run_timers+0x7e8/0x8a0
> [ 1084.392962] Write of size 8 at addr fffffc014647a7a8 by task fsstress/29105
> [ 1084.392966] 
> [ 1084.392970] CPU: 0 UID: 0 PID: 29105 Comm: fsstress Not tainted 6.18.0-xfsa #5 PREEMPTLAZY  aa447adfe084b5fbc6023ad319929e88e68ca52d
> [ 1084.392975] Hardware name: QEMU KVM Virtual Machine, BIOS 1.6.6 08/22/2023
> [ 1084.392977] Call trace:
> [ 1084.392978]  show_stack+0x20/0x40 (C)
> [ 1084.392984]  dump_stack_lvl+0x60/0x80
> [ 1084.392988]  print_report+0x160/0x4c0
> [ 1084.392992]  kasan_report+0xb0/0xf8
> [ 1084.392997]  __asan_report_store8_noabort+0x20/0x30
> [ 1084.393002]  __run_timers+0x7e8/0x8a0
> [ 1084.393006]  run_timer_base+0xf8/0x148
> [ 1084.393009]  run_timer_softirq+0x24/0x50
> [ 1084.393014]  handle_softirqs+0x2b0/0xa60
> [ 1084.393017]  __do_softirq+0x1c/0x28
> [ 1084.393020]  ____do_softirq+0x18/0x30
> [ 1084.393024]  call_on_irq_stack+0x30/0x80
> [ 1084.393027]  do_softirq_own_stack+0x24/0x50
> [ 1084.393031]  __irq_exit_rcu+0x1f8/0x310
> [ 1084.393034]  irq_exit_rcu+0x18/0x30
> [ 1084.393037]  el1_interrupt+0x40/0x60
> [ 1084.393042]  el1h_64_irq_handler+0x18/0x28
> [ 1084.393046]  el1h_64_irq+0x6c/0x70
> [ 1084.393049]  kasan_check_range+0xcc/0x190 (P)
> [ 1084.393053]  do_raw_spin_unlock+0x16c/0x260
> [ 1084.393057]  _raw_spin_unlock+0x1c/0x80
> [ 1084.393062]  xfs_iget+0xb94/0x2358 [xfs 7a664e8b2565bbf246e2d705932ac3446adc6009]
> [ 1084.393722]  xfs_bulkstat_one_int+0x104/0x1300 [xfs 7a664e8b2565bbf246e2d705932ac3446adc6009]
> [ 1084.394622]  xfs_bulkstat_iwalk+0x70/0xc0 [xfs 7a664e8b2565bbf246e2d705932ac3446adc6009]
> [ 1084.394827]  xfs_iwalk_ag_recs+0x2d4/0x5f0 [xfs 7a664e8b2565bbf246e2d705932ac3446adc6009]
> [ 1084.395027]  xfs_iwalk_run_callbacks+0x238/0x548 [xfs 7a664e8b2565bbf246e2d705932ac3446adc6009]
> [ 1084.395227]  xfs_iwalk_ag+0x43c/0x808 [xfs 7a664e8b2565bbf246e2d705932ac3446adc6009]
> [ 1084.395604]  xfs_iwalk_args.constprop.0+0x170/0x310 [xfs 7a664e8b2565bbf246e2d705932ac3446adc6009]
> [ 1084.395803]  xfs_iwalk+0x118/0x170 [xfs 7a664e8b2565bbf246e2d705932ac3446adc6009]
> [ 1084.396001]  xfs_bulkstat+0x2b4/0x418 [xfs 7a664e8b2565bbf246e2d705932ac3446adc6009]
> [ 1084.396244]  xfs_ioc_fsbulkstat.isra.0+0x1a0/0x428 [xfs 7a664e8b2565bbf246e2d705932ac3446adc6009]
> [ 1084.396442]  xfs_file_ioctl+0x1c0/0x1d40 [xfs 7a664e8b2565bbf246e2d705932ac3446adc6009]
> [ 1084.396639]  __arm64_sys_ioctl+0x74c/0x1598
> [ 1084.396645]  do_el0_svc+0x114/0x280
> [ 1084.396650]  el0_svc+0x40/0xf8
> [ 1084.396655]  el0t_64_sync_handler+0xa0/0xe8
> [ 1084.396659]  el0t_64_sync+0x198/0x1a0
> [ 1084.396663] 
> [ 1084.396664] Allocated by task 29104:
> [ 1084.396668]  kasan_save_stack+0x3c/0x70
> [ 1084.396673]  kasan_save_track+0x20/0x40
> [ 1084.396676]  kasan_save_alloc_info+0x40/0x58
> [ 1084.396679]  __kasan_kmalloc+0xd4/0xe0
> [ 1084.396682]  __kmalloc_noprof+0x1f8/0x728
> [ 1084.396685]  xlog_cil_commit+0x5c8/0x2b40 [xfs]
> [ 1084.396882]  __xfs_trans_commit+0x298/0xb10 [xfs]
> [ 1084.397091]  xfs_trans_roll+0xd0/0x3a0 [xfs]
> [ 1084.397286]  xfs_defer_trans_roll+0xd8/0x458 [xfs]
> [ 1084.397486]  xfs_defer_finish_noroll+0x5a0/0xe80 [xfs]
> [ 1084.397684]  xfs_trans_commit+0x158/0x1a0 [xfs]
> [ 1084.397880]  xfs_bmapi_convert_one_delalloc+0x740/0x9a0 [xfs]
> [ 1084.398078]  xfs_bmapi_convert_delalloc+0x98/0xf8 [xfs]
> [ 1084.398277]  xfs_buffered_write_iomap_begin+0x1698/0x1d48 [xfs]
> [ 1084.398472]  iomap_iter+0x360/0xcc0
> [ 1084.398478]  iomap_zero_range+0x298/0x4a0
> [ 1084.398481]  xfs_zero_range+0x98/0xf8 [xfs]
> [ 1084.398676]  xfs_file_write_checks+0x380/0x790 [xfs]
> [ 1084.398871]  xfs_file_buffered_write+0x228/0x870 [xfs]
> [ 1084.399065]  xfs_file_write_iter+0x378/0x890 [xfs]
> [ 1084.399259]  vfs_write+0x48c/0x8d8
> [ 1084.399264]  ksys_write+0xf8/0x1f0
> [ 1084.399267]  __arm64_sys_write+0x74/0xb0
> [ 1084.399270]  do_el0_svc+0x114/0x280
> [ 1084.399273]  el0_svc+0x40/0xf8
> [ 1084.399276]  el0t_64_sync_handler+0xa0/0xe8
> [ 1084.399280]  el0t_64_sync+0x198/0x1a0
> [ 1084.399282] 
> [ 1084.399283] Freed by task 44:
> [ 1084.399286]  kasan_save_stack+0x3c/0x70
> [ 1084.399289]  kasan_save_track+0x20/0x40
> [ 1084.399291]  __kasan_save_free_info+0x4c/0x80
> [ 1084.399295]  __kasan_slab_free+0x88/0xb8
> [ 1084.399298]  kfree+0x114/0x500
> [ 1084.399301]  kvfree+0x44/0x60
> [ 1084.399304]  xlog_cil_committed+0x288/0x4e8 [xfs]
> [ 1084.399498]  xlog_cil_process_committed+0xe4/0x190 [xfs]
> [ 1084.399692]  xlog_state_do_callback+0x3cc/0x930 [xfs]
> [ 1084.399886]  xlog_state_done_syncing+0x134/0x318 [xfs]
> [ 1084.400079]  xlog_ioend_work+0xf0/0x1a0 [xfs]
> [ 1084.400317]  process_one_work+0x564/0xfb8
> [ 1084.400323]  worker_thread+0x4e0/0xc90
> [ 1084.400326]  kthread+0x350/0x630
> [ 1084.400329]  ret_from_fork+0x10/0x20
> [ 1084.400333] 
> [ 1084.400335] The buggy address belongs to the object at fffffc014647a000
> [ 1084.400335]  which belongs to the cache kmalloc-4k of size 4096
> [ 1084.400338] The buggy address is located 1960 bytes inside of
> [ 1084.400338]  freed 4096-byte region [fffffc014647a000, fffffc014647b000)
> [ 1084.400341] 
> [ 1084.400342] The buggy address belongs to the physical page:
> [ 1084.400345] page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x18646
> [ 1084.400348] head: order:1 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
> [ 1084.400351] anon flags: 0x1ffe000000000040(head|node=0|zone=1|lastcpupid=0x7ff)
> [ 1084.400356] page_type: f5(slab)
> [ 1084.400360] raw: 1ffe000000000040 fffffc00e0011040 0000000000000000 dead000000000001
> [ 1084.400363] raw: 0000000000000000 0000000000100010 00000000f5000000 0000000000000000
> [ 1084.400365] head: 1ffe000000000040 fffffc00e0011040 0000000000000000 dead000000000001
> [ 1084.400368] head: 0000000000000000 0000000000100010 00000000f5000000 0000000000000000
> [ 1084.400370] head: 1ffe000000000001 ffffffff40519181 00000000ffffffff 00000000ffffffff
> [ 1084.400372] head: ffffffffffffffff 0000000000000000 00000000ffffffff 0000000000000002
> [ 1084.400374] page dumped because: kasan: bad access detected
> [ 1084.400375] 
> [ 1084.400376] Memory state around the buggy address:
> [ 1084.400378]  fffffc014647a680: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> [ 1084.400380]  fffffc014647a700: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> [ 1084.400382] >fffffc014647a780: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> [ 1084.400383]                                   ^
> [ 1084.400385]  fffffc014647a800: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> [ 1084.400387]  fffffc014647a880: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> [ 1084.400388] ==================================================================
> [ 1084.400390] Disabling lock debugging due to kernel taint
> [ 1084.400397] Unable to handle kernel paging request at virtual address e0fffe000c7480c1
> [ 1084.400400] KASAN: maybe wild-memory-access in range [0x0800000063a40608-0x0800000063a4060f]
> [ 1084.400402] Mem abort info:
> [ 1084.400404]   ESR = 0x0000000096000006
> [ 1084.400405]   EC = 0x25: DABT (current EL), IL = 32 bits
> [ 1084.400407]   SET = 0, FnV = 0
> [ 1084.400409]   EA = 0, S1PTW = 0
> [ 1084.400410]   FSC = 0x06: level 2 translation fault
> [ 1084.400412] Data abort info:
> [ 1084.400413]   ISV = 0, ISS = 0x00000006, ISS2 = 0x00000000
> [ 1084.400414]   CM = 0, WnR = 0, TnD = 0, TagAccess = 0
> [ 1084.400416]   GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
> [ 1084.400418] [e0fffe000c7480c1] address between user and kernel address ranges
> [ 1084.400422] Internal error: Oops: 0000000096000006 [#1]  SMP
> [ 1084.527749] Dumping ftrace buffer:
> [ 1084.528246]    (ftrace buffer empty)
> [ 1084.528716] Modules linked in: xfs rpcsec_gss_krb5 auth_rpcgss nft_chain_nat xt_REDIRECT nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 ip6t_REJECT nf_reject_ipv6 ipt_REJECT nf_reject_ipv4 xt_tcpudp ip_set_hash_ip ip_set_hash_net xt_set nft_compat x_tables ip_set_hash_mac nf_tables bfq sch_fq_codel fuse configfs efivarfs overlay nfsv4
> [ 1084.548848] CPU: 0 UID: 0 PID: 29105 Comm: fsstress Tainted: G    B               6.18.0-xfsa #5 PREEMPTLAZY  aa447adfe084b5fbc6023ad319929e88e68ca52d
> [ 1084.569541] Tainted: [B]=BAD_PAGE
> [ 1084.574702] Hardware name: QEMU KVM Virtual Machine, BIOS 1.6.6 08/22/2023
> [ 1084.578232] pstate: 404010c5 (nZcv daIF +PAN -UAO -TCO -DIT +SSBS BTYPE=--)
> [ 1084.579170] pc : __run_timers+0x414/0x8a0
> [ 1084.579706] lr : __run_timers+0x60c/0x8a0
> [ 1084.580253] sp : fffffe0082defc80
> [ 1084.580682] x29: fffffe0082defde0 x28: dffffe0000000000 x27: fffffc014647a7a0
> [ 1084.589758] x26: dffffe0000000000 x25: fffffc014d52b040 x24: 0800000063a40600
> [ 1084.595175] x23: 000000010002fe00 x22: 1fffff803797a5e3 x21: 1fffffc0105bdfaa
> [ 1084.596172] x20: fffffe0082defd50 x19: fffffc01bcbd2f00 x18: 0000000000000000
> [ 1084.597122] x17: 3d3d3d3d3d3d3d3d x16: 3d3d3d3d3d3d3d3d x15: 3d3d3d3d3d3d3d3d
> [ 1084.599965] x14: 3d3d3d3d3d3d3d3d x13: 00000000000f7588 x12: fffffdc01053a965
> [ 1084.609386] x11: 1fffffc01053a964 x10: fffffdc01053a964 x9 : fffffe00802a6d40
> [ 1084.620436] x8 : fffffe0082defc70 x7 : 0000000000000000 x6 : 0000000000000001
> [ 1084.631299] x5 : 010000000c7480c1 x4 : 0000000000000000 x3 : 0000000000000020
> [ 1084.643080] x2 : fffffe0082defd50 x1 : fffffe0082a02920 x0 : 0800000063a40608
> [ 1084.653742] Call trace:
> [ 1084.657493]  __run_timers+0x414/0x8a0 (P)
> [ 1084.663591]  run_timer_base+0xf8/0x148
> [ 1084.669316]  run_timer_softirq+0x24/0x50
> [ 1084.675362]  handle_softirqs+0x2b0/0xa60
> [ 1084.681433]  __do_softirq+0x1c/0x28
> [ 1084.686871]  ____do_softirq+0x18/0x30
> [ 1084.692642]  call_on_irq_stack+0x30/0x80
> [ 1084.698699]  do_softirq_own_stack+0x24/0x50
> [ 1084.705185]  __irq_exit_rcu+0x1f8/0x310
> [ 1084.711045]  irq_exit_rcu+0x18/0x30
> [ 1084.716410]  el1_interrupt+0x40/0x60
> [ 1084.721853]  el1h_64_irq_handler+0x18/0x28
> [ 1084.727848]  el1h_64_irq+0x6c/0x70
> [ 1084.732975]  kasan_check_range+0xcc/0x190 (P)
> [ 1084.738896]  do_raw_spin_unlock+0x16c/0x260
> [ 1084.745084]  _raw_spin_unlock+0x1c/0x80
> [ 1084.750697]  xfs_iget+0xb94/0x2358 [xfs 7a664e8b2565bbf246e2d705932ac3446adc6009]
> [ 1084.762064]  xfs_bulkstat_one_int+0x104/0x1300 [xfs 7a664e8b2565bbf246e2d705932ac3446adc6009]
> [ 1084.775161]  xfs_bulkstat_iwalk+0x70/0xc0 [xfs 7a664e8b2565bbf246e2d705932ac3446adc6009]
> [ 1084.787709]  xfs_iwalk_ag_recs+0x2d4/0x5f0 [xfs 7a664e8b2565bbf246e2d705932ac3446adc6009]
> [ 1084.800602]  xfs_iwalk_run_callbacks+0x238/0x548 [xfs 7a664e8b2565bbf246e2d705932ac3446adc6009]
> [ 1084.814206]  xfs_iwalk_ag+0x43c/0x808 [xfs 7a664e8b2565bbf246e2d705932ac3446adc6009]
> [ 1084.826326]  xfs_iwalk_args.constprop.0+0x170/0x310 [xfs 7a664e8b2565bbf246e2d705932ac3446adc6009]
> [ 1084.841182]  xfs_iwalk+0x118/0x170 [xfs 7a664e8b2565bbf246e2d705932ac3446adc6009]
> [ 1084.852948]  xfs_bulkstat+0x2b4/0x418 [xfs 7a664e8b2565bbf246e2d705932ac3446adc6009]
> [ 1084.864605]  xfs_ioc_fsbulkstat.isra.0+0x1a0/0x428 [xfs 7a664e8b2565bbf246e2d705932ac3446adc6009]
> [ 1084.878410]  xfs_file_ioctl+0x1c0/0x1d40 [xfs 7a664e8b2565bbf246e2d705932ac3446adc6009]
> [ 1084.891037]  __arm64_sys_ioctl+0x74c/0x1598
> [ 1084.897397]  do_el0_svc+0x114/0x280
> [ 1084.902617]  el0_svc+0x40/0xf8
> [ 1084.907180]  el0t_64_sync_handler+0xa0/0xe8
> [ 1084.913489]  el0t_64_sync+0x198/0x1a0
> [ 1084.918999] Code: f9000058 b40000d8 91002300 d343fc05 (38fc68a5) 
> [ 1084.928221] ---[ end trace 0000000000000000 ]---
> [ 1084.935096] Kernel panic - not syncing: Oops: Fatal exception in interrupt
> [ 1084.943330] SMP: stopping secondary CPUs
> [ 1084.945640] Dumping ftrace buffer:
> [ 1084.947807]    (ftrace buffer empty)
> [ 1084.949888] Kernel Offset: disabled
> [ 1084.952106] CPU features: 0x100000,0000e000,40006281,0441700b
> [ 1084.955826] Memory Limit: none
> [ 1084.957847] ---[ end Kernel panic - not syncing: Oops: Fatal exception in interrupt ]---
> 
> This is a weird report -- the timer code reports what looks like garbage
> in a timer_list object, but the KASAN report reports to the most recent
> allocation being the xlog_kvmalloc call in xlog_cil_alloc_shadow_bufs
> and the corresponding kvfree of that shadow buffer.
> 
> My guess is that someone created a timer, queued it somewhere, freed the
> timer, and later on the CIL stumbled onto the same memory and that's why
> there's a bunch of kaboom.
> 
> Coincidentally generic/656 on a different (but otherwise identical)
> arm64 VM coughed this up:
> 
> [ 8707.815539] ------------[ cut here ]------------
> [ 8707.815546] workqueue: cannot queue xfs_reclaim_worker [xfs] on wq \xd8f\xee\xed
> [ 8707.815680] WARNING: CPU: 0 PID: 0 at kernel/workqueue.c:2257 __queue_work+0x460/0x5f8
> [ 8707.827486] Modules linked in: ext2 mbcache dm_thin_pool dm_persistent_data dm_bio_prison dm_bufio dm_flakey loop xfs rpcsec_gss_krb5 auth_rpcgss nft_chain_nat xt_REDIRECT nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 ip6t_REJECT nf_reject_ipv6 ipt_REJECT nf_reject_ipv4 xt_tcpudp ip_set_hash_ip ip_set_hash_net xt_set nft_compat x_tables ip_set_hash_mac nf_tables bfq sch_fq_codel fuse configfs efivarfs overlay nfsv4
> [ 8707.852559] CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Tainted: G        W           6.18.0-acha #1 PREEMPTLAZY  36e54c0b238dbd4929d429645e39497dd45df6eb
> [ 8707.861584] Tainted: [W]=WARN
> [ 8707.863400] Hardware name: QEMU KVM Virtual Machine, BIOS 1.6.6 08/22/2023
> [ 8707.867278] pstate: 604010c5 (nZCv daIF +PAN -UAO -TCO -DIT +SSBS BTYPE=--)
> [ 8707.871956] pc : __queue_work+0x460/0x5f8
> [ 8707.874232] lr : __queue_work+0x460/0x5f8
> [ 8707.875944] sp : fffffe00813afd70
> [ 8707.877382] x29: fffffe00813afd70 x28: fffffe0080097b48 x27: fffffe008127e888
> [ 8707.880626] x26: fffffc00edee3400 x25: fffffe0081175d78 x24: 0000000000000001
> [ 8707.884868] x23: 0000000000000101 x22: 00000001002012c0 x21: fffffe0080097b48
> [ 8707.889942] x20: 0000000000000008 x19: fffffc00c5470780 x18: 0000000000000000
> [ 8707.894895] x17: fffffe017e420000 x16: fffffe00813a0000 x15: 0000000000000000
> [ 8707.899722] x14: 0000000000000000 x13: 2065756575712074 x12: fffffe008119c138
> [ 8707.904676] x11: fffffe00811999b0 x10: fffffe00811a49b0 x9 : fffffe00800fa598
> [ 8707.909402] x8 : 00000000001ad848 x7 : 0000000000000ac8 x6 : c000000100005a73
> [ 8707.912864] x5 : 000000000000a42a x4 : 0000000000000001 x3 : fffffe008117e080
> [ 8707.916207] x2 : 0000000000000000 x1 : 0000000000000000 x0 : fffffe008117e080
> [ 8707.919499] Call trace:
> [ 8707.920601]  __queue_work+0x460/0x5f8 (P)
> [ 8707.922478]  delayed_work_timer_fn+0x24/0x40
> [ 8707.924584]  call_timer_fn+0x3c/0x1a8
> [ 8707.927048]  __run_timers+0x204/0x318
> [ 8707.929416]  run_timer_base+0x64/0x88
> [ 8707.931964]  run_timer_softirq+0x24/0x50
> [ 8707.934504]  handle_softirqs+0x15c/0x398
> [ 8707.937631]  __do_softirq+0x1c/0x28
> [ 8707.940076]  ____do_softirq+0x18/0x30
> [ 8707.942424]  call_on_irq_stack+0x30/0x78
> [ 8707.945418]  do_softirq_own_stack+0x24/0x50
> [ 8707.948320]  __irq_exit_rcu+0xf0/0x168
> [ 8707.951297]  irq_exit_rcu+0x18/0x38
> [ 8707.953762]  el1_interrupt+0x40/0x60
> [ 8707.955889]  el1h_64_irq_handler+0x18/0x28
> [ 8707.958503]  el1h_64_irq+0x6c/0x70
> [ 8707.960990]  default_idle_call+0x38/0x178 (P)
> [ 8707.963907]  do_idle+0x214/0x280
> [ 8707.966232]  cpu_startup_entry+0x3c/0x50
> [ 8707.969031]  rest_init+0xf0/0x100
> [ 8707.971311]  start_kernel+0x764/0x770
> [ 8707.973854]  __primary_switched+0x88/0x98
> [ 8707.976703] ---[ end trace 0000000000000000 ]---
> 
> Which makes me wonder if the delayed reclaim work is not being cancelled
> properly?  <shrug> will keep looking...
> 
> --D
> 
---end quoted text---


From quic_nihalkum at quicinc.com  Mon Dec  1 23:35:35 2025
From: quic_nihalkum at quicinc.com (Nihal Kumar Gupta)
Date: Tue, 2 Dec 2025 13:05:35 +0530
Subject: [PATCH v6 2/3] arm64: dts: qcom: qcs8300: Add CCI definitions
In-Reply-To: <d49920eb-0b4e-4042-b0c6-28d1ba348ddc@quicinc.com>
References: <DS0PR02MB11311CE33DFFE0739BE747590E3D8A@DS0PR02MB11311.namprd02.prod.outlook.com>
 <d49920eb-0b4e-4042-b0c6-28d1ba348ddc@quicinc.com>
Message-ID: <3f1dbf91-f967-44dc-bb21-25fdcbbc8db2@quicinc.com>



On 11/26/25 9:10 AM, Vikram Sharma wrote:
>> From: Nihal Kumar Gupta <quic_nihalkum at quicinc.com>
>>
>> Qualcomm QCS8300 SoC contains three Camera Control Interface (CCI).
>> Compared to Lemans, the key difference is in SDA/SCL GPIO assignments
>> and number of CCIs.
> [...]
> 
>> @@ -5071,6 +5182,240 @@ tlmm: pinctrl at f100000 {
>>                       #interrupt-cells = <2>;
>>                       wakeup-parent = <&pdc>;
>>
>> +                     cam0_avdd_2v8_en_default: cam0-avdd-2v8-en-state {
>> +                             pins = "gpio73";
>> +                             function = "gpio";
>> +                             drive-strength = <2>;
>> +                             bias-disable;
>> +                     };
> I'm not sure whether I was unclear, but my intention was to ask you to move the MCLK pin definitions to the SoC DTSI, because that comes from the design of the platform and doesn't vary between end products.
> 
> GPIO_73 being related to a voltage regulator is strictly a property of the EVK.

MCLK pin definitions are already present under the tlmm block in SoC dtsi(monaco.dtsi) as required by the pinctrl subsystem(qcom,qcs8300-tlmm.yaml).
Are you suggesting they shouldn?t be part of TLMM in the SoC DTSI? This doesn?t align with the YAML file.

Regarding GPIO_73: Noted. I will move it to monaco-evk.dts under the tlmm section.

Below are the example snippets:
In monaco.dtsi (SoC level):
tlmm: pinctrl at ... {
    cam_mclk0_default: cam-mclk0-default-state {
        pins = "gpio67"; 
        function = "cam_mclk";
        drive-strength = <2>;
    };
    ....
};

In monaco-evk.dts (Board level):
&tlmm {
    cam0_avdd_2v8_en_default: cam0-avdd-2v8-en-state {
        pins = "gpio73";
        function = "gpio";
        drive-strength = <2>;
        bias-disable;
    };
    ...
};

-- 
Regards,
Nihal Kumar Gupta



From kyrie.wu at mediatek.com  Mon Dec  1 23:40:27 2025
From: kyrie.wu at mediatek.com (Kyrie Wu)
Date: Tue, 2 Dec 2025 15:40:27 +0800
Subject: [PATCH v6 00/10] Enable video decoder & encoder for MT8189
Message-ID: <20251202074038.3173-1-kyrie.wu@mediatek.com>

This series have the follow changing:
Firstly add mt8189 video decoder compatible, profile and level to support
MT8189 kernel driver.
Secondly fix some bugs, including vp 4K profile2 and media device node
number bug.
Lastly, add mt8189 video encoder compatible.

This series has been tested with MT8189 tast test.
Encoding and decoding worked for this chip.

Patches 1-2 Add decoder compatible.
Patches 3 Add profile and level supporting.
Patches 4 Add core-only VP9 decoding supporting.
Patches 5-6 fix some bugs.
Patches 7-8 Adds encoder compatible.

---
H264 test results:
./fluster.py run -d GStreamer-H.264-V4L2SL-Gst1.0 -j2 -t 90
    JVT-AVC_V1	Ran 96/135 tests successfully

VP9 test results:
./fluster.py run -d GStreamer-VP9-V4L2SL-Gst1.0 -j2 -t 90
	VP9-TEST-VECTORS	Ran 276/305 tests successfully

v4l2-compliance test results:
Compliance test for mtk-vcodec-enc device /dev/video2:
Total for mtk-vcodec-enc device /dev/video2: 47, Succeeded: 46, Failed: 1, Warnings: 0
Compliance test for mtk-vcodec-dec device /dev/video3:
Total for mtk-vcodec-dec device /dev/video3: 48, Succeeded: 48, Failed: 0, Warnings: 0

scp upstream link:
https://patchwork.kernel.org/project/linux-mediatek/patch/20250811015922.32680-1-huayu.zong at mediatek.com/
dtsi upstream link:
https://lore.kernel.org/linux-mediatek/20251030134541.784011-12-jh.hsu at mediatek.com/T/#m847e35de0a5b18fac0ca0624a8559d84964ad5c7

Changes compared with v5:
--move default decoder parameters to compatible data structure
--add reviewer to commit messages
--Rebased on top of the latest media tree

Changes compared with v4:
--update H264 & vp9 fluster test results
--update vp9 single core decoder prob size setting and commit messages

Changes compared with v3:
--add reviewer to commit messages
--Rebased on top of the latest media tree

Changes compared with v2:
--add H264 fluster test results
--reorder compatible string for dt-bindings

Changes compared with v1:
--add v4l2-compliance test results
--add scp upstream link
--add HW difference discriptions for dt-bindings commit messages

This series patches dependent on:
[1]
https://patchwork.linuxtv.org/project/linux-media/cover/20250510075357.11761-1-yunfei.dong at mediatek.com/
[2]
https://patchwork.linuxtv.org/project/linux-media/cover/20250814085642.17343-1-kyrie.wu at mediatek.com/

Kyrie Wu (10):
  dt-bindings: media: mediatek: decoder: Add MT8189
    mediatek,vcodec-decoder
  media: mediatek: decoder: Add a new platform data member
  media: mediatek: vcodec: add decoder compatible to support MT8189
  media: mediatek: vcodec: add profile and level supporting for MT8189
  media: mediatek: vcodec: refactor setup dst buffer metadata interface
    for VP9 decoder
  media: mediatek: vcodec: Add 4K prob size supporting for VP9 decoder
  media: mediatek: vcodec: Fix vp9 4096x2176 fail for profile2
  media: mediatek: vcodec: Fix media device node number
  dt-bindings: media: Add MT8189 mediatek,vcodec-encoder
  media: mediatek: encoder: Add MT8189 encoder compatible data

 .../media/mediatek,vcodec-encoder.yaml        |   2 +
 .../media/mediatek,vcodec-subdev-decoder.yaml |   5 +-
 .../mediatek/vcodec/decoder/mtk_vcodec_dec.h  |   6 +
 .../vcodec/decoder/mtk_vcodec_dec_drv.c       |  42 +--
 .../vcodec/decoder/mtk_vcodec_dec_drv.h       |  33 +-
 .../vcodec/decoder/mtk_vcodec_dec_hw.c        |   2 +-
 .../vcodec/decoder/mtk_vcodec_dec_stateful.c  |  14 +
 .../vcodec/decoder/mtk_vcodec_dec_stateless.c | 293 +++++++++++++-----
 .../vcodec/decoder/vdec/vdec_vp9_req_lat_if.c |  35 ++-
 .../vcodec/encoder/mtk_vcodec_enc_drv.c       |  14 +
 10 files changed, 314 insertions(+), 132 deletions(-)

-- 
2.45.2



From kyrie.wu at mediatek.com  Mon Dec  1 23:40:28 2025
From: kyrie.wu at mediatek.com (Kyrie Wu)
Date: Tue, 2 Dec 2025 15:40:28 +0800
Subject: [PATCH v6 01/10] dt-bindings: media: mediatek: decoder: Add MT8189 mediatek,vcodec-decoder
In-Reply-To: <20251202074038.3173-1-kyrie.wu@mediatek.com>
References: <20251202074038.3173-1-kyrie.wu@mediatek.com>
Message-ID: <20251202074038.3173-2-kyrie.wu@mediatek.com>

Add compatible for video decoder on MT8189 platform. Compared with
former ICs, the MT8189 decoder use iommu to instead of smmu, and
use scp architecture, the frequency is only 406MHZ, and cannot reach
more than 700MHZ. It used only one clock. At the same time, the decoder
supports the vp9 decoding protocol for the first time in single IC.

Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
Acked-by: Rob Herring (Arm) <robh at kernel.org>
---
 .../bindings/media/mediatek,vcodec-subdev-decoder.yaml       | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/media/mediatek,vcodec-subdev-decoder.yaml b/Documentation/devicetree/bindings/media/mediatek,vcodec-subdev-decoder.yaml
index 74e1d88d3056..ee2bbbdb2d50 100644
--- a/Documentation/devicetree/bindings/media/mediatek,vcodec-subdev-decoder.yaml
+++ b/Documentation/devicetree/bindings/media/mediatek,vcodec-subdev-decoder.yaml
@@ -75,6 +75,7 @@ properties:
       - mediatek,mt8192-vcodec-dec
       - mediatek,mt8186-vcodec-dec
       - mediatek,mt8188-vcodec-dec
+      - mediatek,mt8189-vcodec-dec
       - mediatek,mt8195-vcodec-dec
       - mediatek,mt8196-vcodec-dec
 
@@ -132,11 +133,11 @@ patternProperties:
           Refer to bindings/iommu/mediatek,iommu.yaml.
 
       clocks:
-        minItems: 4
+        minItems: 1
         maxItems: 5
 
       clock-names:
-        minItems: 4
+        minItems: 1
         maxItems: 5
 
       assigned-clocks:
-- 
2.45.2



From kyrie.wu at mediatek.com  Mon Dec  1 23:40:29 2025
From: kyrie.wu at mediatek.com (Kyrie Wu)
Date: Tue, 2 Dec 2025 15:40:29 +0800
Subject: [PATCH v6 02/10] media: mediatek: decoder: Add a new platform data member
In-Reply-To: <20251202074038.3173-1-kyrie.wu@mediatek.com>
References: <20251202074038.3173-1-kyrie.wu@mediatek.com>
Message-ID: <20251202074038.3173-3-kyrie.wu@mediatek.com>

Add a new platform data member to indicate each decoder IC
to avoid the chip name definition keep growing.

Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
---
 .../mediatek/vcodec/decoder/mtk_vcodec_dec.h  |   5 +
 .../vcodec/decoder/mtk_vcodec_dec_drv.c       |  35 +----
 .../vcodec/decoder/mtk_vcodec_dec_drv.h       |  15 +-
 .../vcodec/decoder/mtk_vcodec_dec_hw.c        |   2 +-
 .../vcodec/decoder/mtk_vcodec_dec_stateful.c  |   1 +
 .../vcodec/decoder/mtk_vcodec_dec_stateless.c | 137 +++++++++++++++---
 6 files changed, 131 insertions(+), 64 deletions(-)

diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.h b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.h
index 1af075fc0194..80cb46f1cded 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.h
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.h
@@ -69,6 +69,11 @@ extern const struct v4l2_m2m_ops mtk_vdec_m2m_ops;
 extern const struct media_device_ops mtk_vcodec_media_ops;
 extern const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata;
 extern const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata;
+extern const struct mtk_vcodec_dec_pdata mtk_vdec_8186_pdata;
+extern const struct mtk_vcodec_dec_pdata mtk_vdec_8188_pdata;
+extern const struct mtk_vcodec_dec_pdata mtk_vdec_8192_pdata;
+extern const struct mtk_vcodec_dec_pdata mtk_vdec_8195_pdata;
+extern const struct mtk_vcodec_dec_pdata mtk_vdec_8196_pdata;
 extern const struct mtk_vcodec_dec_pdata mtk_lat_sig_core_pdata;
 extern const struct mtk_vcodec_dec_pdata mtk_vdec_single_core_pdata;
 
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
index 6fb05bb00641..d7a269045fd6 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
@@ -331,24 +331,7 @@ static const struct v4l2_file_operations mtk_vcodec_fops = {
 
 static void mtk_vcodec_dec_get_chip_name(struct mtk_vcodec_dec_dev *vdec_dev)
 {
-	struct device *dev = &vdec_dev->plat_dev->dev;
-
-	if (of_device_is_compatible(dev->of_node, "mediatek,mt8173-vcodec-dec"))
-		vdec_dev->chip_name = MTK_VDEC_MT8173;
-	else if (of_device_is_compatible(dev->of_node, "mediatek,mt8183-vcodec-dec"))
-		vdec_dev->chip_name = MTK_VDEC_MT8183;
-	else if (of_device_is_compatible(dev->of_node, "mediatek,mt8192-vcodec-dec"))
-		vdec_dev->chip_name = MTK_VDEC_MT8192;
-	else if (of_device_is_compatible(dev->of_node, "mediatek,mt8195-vcodec-dec"))
-		vdec_dev->chip_name = MTK_VDEC_MT8195;
-	else if (of_device_is_compatible(dev->of_node, "mediatek,mt8186-vcodec-dec"))
-		vdec_dev->chip_name = MTK_VDEC_MT8186;
-	else if (of_device_is_compatible(dev->of_node, "mediatek,mt8188-vcodec-dec"))
-		vdec_dev->chip_name = MTK_VDEC_MT8188;
-	else if (of_device_is_compatible(dev->of_node, "mediatek,mt8196-vcodec-dec"))
-		vdec_dev->chip_name = MTK_VDEC_MT8196;
-	else
-		vdec_dev->chip_name = MTK_VDEC_INVAL;
+	vdec_dev->chip_name = vdec_dev->vdec_pdata->chip_name;
 }
 
 static int mtk_vcodec_probe(struct platform_device *pdev)
@@ -367,10 +350,6 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
 	dev->plat_dev = pdev;
 
 	mtk_vcodec_dec_get_chip_name(dev);
-	if (dev->chip_name == MTK_VDEC_INVAL) {
-		dev_err(&pdev->dev, "Failed to get decoder chip name");
-		return -EINVAL;
-	}
 
 	dev->vdec_pdata = of_device_get_match_data(&pdev->dev);
 	if (!of_property_read_u32(pdev->dev.of_node, "mediatek,vpu",
@@ -387,7 +366,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
 		return -ENODEV;
 	}
 	dma_set_max_seg_size(&pdev->dev, UINT_MAX);
-	if (dev->chip_name == MTK_VDEC_MT8196) {
+	if (dev->chip_name == 8196) {
 		ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(36));
 		if (ret) {
 			dev_err(&pdev->dev, "Failed to enable 36-bit DMA: %d\n", ret);
@@ -556,23 +535,23 @@ static const struct of_device_id mtk_vcodec_match[] = {
 	},
 	{
 		.compatible = "mediatek,mt8192-vcodec-dec",
-		.data = &mtk_lat_sig_core_pdata,
+		.data = &mtk_vdec_8192_pdata,
 	},
 	{
 		.compatible = "mediatek,mt8186-vcodec-dec",
-		.data = &mtk_vdec_single_core_pdata,
+		.data = &mtk_vdec_8186_pdata,
 	},
 	{
 		.compatible = "mediatek,mt8195-vcodec-dec",
-		.data = &mtk_lat_sig_core_pdata,
+		.data = &mtk_vdec_8195_pdata,
 	},
 	{
 		.compatible = "mediatek,mt8188-vcodec-dec",
-		.data = &mtk_lat_sig_core_pdata,
+		.data = &mtk_vdec_8188_pdata,
 	},
 	{
 		.compatible = "mediatek,mt8196-vcodec-dec",
-		.data = &mtk_lat_sig_core_pdata,
+		.data = &mtk_vdec_8196_pdata,
 	},
 	{},
 };
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h
index 429b32952194..2dbde8d00e6f 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h
@@ -19,17 +19,6 @@
 #define IS_VDEC_INNER_RACING(capability) ((capability) & MTK_VCODEC_INNER_RACING)
 #define IS_VDEC_SUPPORT_EXT(capability) ((capability) & MTK_VDEC_IS_SUPPORT_EXT)
 
-enum mtk_vcodec_dec_chip_name {
-	MTK_VDEC_INVAL = 0,
-	MTK_VDEC_MT8173 = 8173,
-	MTK_VDEC_MT8183 = 8183,
-	MTK_VDEC_MT8186 = 8186,
-	MTK_VDEC_MT8188 = 8188,
-	MTK_VDEC_MT8192 = 8192,
-	MTK_VDEC_MT8195 = 8195,
-	MTK_VDEC_MT8196 = 8196,
-};
-
 /*
  * enum mtk_vdec_format_types - Structure used to get supported
  *		  format types according to decoder capability
@@ -106,6 +95,7 @@ struct vdec_pic_info {
  *
  * @is_subdev_supported: whether support parent-node architecture(subdev)
  * @uses_stateless_api: whether the decoder uses the stateless API with requests
+ * @chip_name: platforms configuration values
  */
 struct mtk_vcodec_dec_pdata {
 	void (*init_vdec_params)(struct mtk_vcodec_dec_ctx *ctx);
@@ -127,6 +117,7 @@ struct mtk_vcodec_dec_pdata {
 
 	bool is_subdev_supported;
 	bool uses_stateless_api;
+	unsigned int chip_name;
 };
 
 /**
@@ -307,7 +298,7 @@ struct mtk_vcodec_dec_dev {
 	struct mutex dec_racing_info_mutex;
 	struct mtk_vcodec_dbgfs dbgfs;
 
-	enum mtk_vcodec_dec_chip_name chip_name;
+	unsigned int chip_name;
 };
 
 static inline struct mtk_vcodec_dec_ctx *fh_to_dec_ctx(struct v4l2_fh *fh)
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_hw.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_hw.c
index e4e527fe54dc..a926dc14d39d 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_hw.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_hw.c
@@ -76,7 +76,7 @@ static void mtk_vdec_hw_clean_xpc(struct mtk_vdec_hw_dev *dev)
 {
 	u32 val, mask, addr = VDEC_XPC_CLEAN_ADDR;
 
-	if (dev->main_dev->chip_name != MTK_VDEC_MT8196)
+	if (dev->main_dev->chip_name != 8196)
 		return;
 
 	val = dev->hw_idx == MTK_VDEC_LAT0 ? VDEC_XPC_LAT_VAL : VDEC_XPC_CORE_VAL;
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c
index aa9bdee7a96c..8ddb61670dc6 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c
@@ -618,4 +618,5 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata = {
 	.flush_decoder = mtk_vdec_flush_decoder,
 	.is_subdev_supported = false,
 	.hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
+	.chip_name = 8173,
 };
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
index c1cef78471a9..d249a8774948 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
@@ -550,16 +550,16 @@ static void mtk_vcodec_dec_fill_h264_level(struct v4l2_ctrl_config *cfg,
 					   struct mtk_vcodec_dec_ctx *ctx)
 {
 	switch (ctx->dev->chip_name) {
-	case MTK_VDEC_MT8192:
-	case MTK_VDEC_MT8188:
+	case 8192:
+	case 8188:
 		cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_5_2;
 		break;
-	case MTK_VDEC_MT8195:
-	case MTK_VDEC_MT8196:
+	case 8195:
+	case 8196:
 		cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_6_0;
 		break;
-	case MTK_VDEC_MT8183:
-	case MTK_VDEC_MT8186:
+	case 8183:
+	case 8186:
 		cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_4_2;
 		break;
 	default:
@@ -572,9 +572,9 @@ static void mtk_vcodec_dec_fill_h264_profile(struct v4l2_ctrl_config *cfg,
 					     struct mtk_vcodec_dec_ctx *ctx)
 {
 	switch (ctx->dev->chip_name) {
-	case MTK_VDEC_MT8188:
-	case MTK_VDEC_MT8195:
-	case MTK_VDEC_MT8196:
+	case 8188:
+	case 8195:
+	case 8196:
 		cfg->max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10;
 		break;
 	default:
@@ -587,11 +587,11 @@ static void mtk_vcodec_dec_fill_h265_level(struct v4l2_ctrl_config *cfg,
 					   struct mtk_vcodec_dec_ctx *ctx)
 {
 	switch (ctx->dev->chip_name) {
-	case MTK_VDEC_MT8188:
+	case 8188:
 		cfg->max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1;
 		break;
-	case MTK_VDEC_MT8195:
-	case MTK_VDEC_MT8196:
+	case 8195:
+	case 8196:
 		cfg->max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2;
 		break;
 	default:
@@ -604,9 +604,9 @@ static void mtk_vcodec_dec_fill_h265_profile(struct v4l2_ctrl_config *cfg,
 					     struct mtk_vcodec_dec_ctx *ctx)
 {
 	switch (ctx->dev->chip_name) {
-	case MTK_VDEC_MT8188:
-	case MTK_VDEC_MT8195:
-	case MTK_VDEC_MT8196:
+	case 8188:
+	case 8195:
+	case 8196:
 		cfg->max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10;
 		break;
 	default:
@@ -619,15 +619,15 @@ static void mtk_vcodec_dec_fill_vp9_level(struct v4l2_ctrl_config *cfg,
 					  struct mtk_vcodec_dec_ctx *ctx)
 {
 	switch (ctx->dev->chip_name) {
-	case MTK_VDEC_MT8192:
-	case MTK_VDEC_MT8188:
+	case 8192:
+	case 8188:
 		cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_5_1;
 		break;
-	case MTK_VDEC_MT8195:
-	case MTK_VDEC_MT8196:
+	case 8195:
+	case 8196:
 		cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2;
 		break;
-	case MTK_VDEC_MT8186:
+	case 8186:
 		cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_4_1;
 		break;
 	default:
@@ -640,9 +640,9 @@ static void mtk_vcodec_dec_fill_vp9_profile(struct v4l2_ctrl_config *cfg,
 					    struct mtk_vcodec_dec_ctx *ctx)
 {
 	switch (ctx->dev->chip_name) {
-	case MTK_VDEC_MT8188:
-	case MTK_VDEC_MT8195:
-	case MTK_VDEC_MT8196:
+	case 8188:
+	case 8195:
+	case 8196:
 		cfg->max = V4L2_MPEG_VIDEO_VP9_PROFILE_2;
 		break;
 	default:
@@ -886,6 +886,7 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata = {
 	.get_cap_buffer = vdec_get_cap_buffer,
 	.is_subdev_supported = false,
 	.hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
+	.chip_name = 8183,
 };
 
 /* This platform data is used for one lat and one core architecture. */
@@ -906,6 +907,78 @@ const struct mtk_vcodec_dec_pdata mtk_lat_sig_core_pdata = {
 	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
 };
 
+const struct mtk_vcodec_dec_pdata mtk_vdec_8188_pdata = {
+	.init_vdec_params = mtk_init_vdec_params,
+	.ctrls_setup = mtk_vcodec_dec_ctrls_setup,
+	.vdec_vb2_ops = &mtk_vdec_request_vb2_ops,
+	.vdec_formats = mtk_video_formats,
+	.num_formats = &num_formats,
+	.default_out_fmt = &default_out_format,
+	.default_cap_fmt = &default_cap_format,
+	.uses_stateless_api = true,
+	.worker = mtk_vdec_worker,
+	.flush_decoder = mtk_vdec_flush_decoder,
+	.cap_to_disp = mtk_vdec_stateless_cap_to_disp,
+	.get_cap_buffer = vdec_get_cap_buffer,
+	.is_subdev_supported = true,
+	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
+	.chip_name = 8188,
+};
+
+const struct mtk_vcodec_dec_pdata mtk_vdec_8192_pdata = {
+	.init_vdec_params = mtk_init_vdec_params,
+	.ctrls_setup = mtk_vcodec_dec_ctrls_setup,
+	.vdec_vb2_ops = &mtk_vdec_request_vb2_ops,
+	.vdec_formats = mtk_video_formats,
+	.num_formats = &num_formats,
+	.default_out_fmt = &default_out_format,
+	.default_cap_fmt = &default_cap_format,
+	.uses_stateless_api = true,
+	.worker = mtk_vdec_worker,
+	.flush_decoder = mtk_vdec_flush_decoder,
+	.cap_to_disp = mtk_vdec_stateless_cap_to_disp,
+	.get_cap_buffer = vdec_get_cap_buffer,
+	.is_subdev_supported = true,
+	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
+	.chip_name = 8192,
+};
+
+const struct mtk_vcodec_dec_pdata mtk_vdec_8195_pdata = {
+	.init_vdec_params = mtk_init_vdec_params,
+	.ctrls_setup = mtk_vcodec_dec_ctrls_setup,
+	.vdec_vb2_ops = &mtk_vdec_request_vb2_ops,
+	.vdec_formats = mtk_video_formats,
+	.num_formats = &num_formats,
+	.default_out_fmt = &default_out_format,
+	.default_cap_fmt = &default_cap_format,
+	.uses_stateless_api = true,
+	.worker = mtk_vdec_worker,
+	.flush_decoder = mtk_vdec_flush_decoder,
+	.cap_to_disp = mtk_vdec_stateless_cap_to_disp,
+	.get_cap_buffer = vdec_get_cap_buffer,
+	.is_subdev_supported = true,
+	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
+	.chip_name = 8195,
+};
+
+const struct mtk_vcodec_dec_pdata mtk_vdec_8196_pdata = {
+	.init_vdec_params = mtk_init_vdec_params,
+	.ctrls_setup = mtk_vcodec_dec_ctrls_setup,
+	.vdec_vb2_ops = &mtk_vdec_request_vb2_ops,
+	.vdec_formats = mtk_video_formats,
+	.num_formats = &num_formats,
+	.default_out_fmt = &default_out_format,
+	.default_cap_fmt = &default_cap_format,
+	.uses_stateless_api = true,
+	.worker = mtk_vdec_worker,
+	.flush_decoder = mtk_vdec_flush_decoder,
+	.cap_to_disp = mtk_vdec_stateless_cap_to_disp,
+	.get_cap_buffer = vdec_get_cap_buffer,
+	.is_subdev_supported = true,
+	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
+	.chip_name = 8196,
+};
+
 const struct mtk_vcodec_dec_pdata mtk_vdec_single_core_pdata = {
 	.init_vdec_params = mtk_init_vdec_params,
 	.ctrls_setup = mtk_vcodec_dec_ctrls_setup,
@@ -922,3 +995,21 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_single_core_pdata = {
 	.is_subdev_supported = true,
 	.hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
 };
+
+const struct mtk_vcodec_dec_pdata mtk_vdec_8186_pdata = {
+	.init_vdec_params = mtk_init_vdec_params,
+	.ctrls_setup = mtk_vcodec_dec_ctrls_setup,
+	.vdec_vb2_ops = &mtk_vdec_request_vb2_ops,
+	.vdec_formats = mtk_video_formats,
+	.num_formats = &num_formats,
+	.default_out_fmt = &default_out_format,
+	.default_cap_fmt = &default_cap_format,
+	.uses_stateless_api = true,
+	.worker = mtk_vdec_worker,
+	.flush_decoder = mtk_vdec_flush_decoder,
+	.cap_to_disp = mtk_vdec_stateless_cap_to_disp,
+	.get_cap_buffer = vdec_get_cap_buffer,
+	.is_subdev_supported = true,
+	.hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
+	.chip_name = 8186,
+};
-- 
2.45.2



From kyrie.wu at mediatek.com  Mon Dec  1 23:40:30 2025
From: kyrie.wu at mediatek.com (Kyrie Wu)
Date: Tue, 2 Dec 2025 15:40:30 +0800
Subject: [PATCH v6 03/10] media: mediatek: vcodec: add decoder compatible to support MT8189
In-Reply-To: <20251202074038.3173-1-kyrie.wu@mediatek.com>
References: <20251202074038.3173-1-kyrie.wu@mediatek.com>
Message-ID: <20251202074038.3173-4-kyrie.wu@mediatek.com>

MT8189 is pure single core architecture. Add its compatible to
initialize platform data.

Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
---
 .../mediatek/vcodec/decoder/mtk_vcodec_dec.h   |  1 +
 .../vcodec/decoder/mtk_vcodec_dec_drv.c        |  4 ++++
 .../vcodec/decoder/mtk_vcodec_dec_stateless.c  | 18 ++++++++++++++++++
 3 files changed, 23 insertions(+)

diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.h b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.h
index 80cb46f1cded..2bde871c0224 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.h
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.h
@@ -71,6 +71,7 @@ extern const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata;
 extern const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata;
 extern const struct mtk_vcodec_dec_pdata mtk_vdec_8186_pdata;
 extern const struct mtk_vcodec_dec_pdata mtk_vdec_8188_pdata;
+extern const struct mtk_vcodec_dec_pdata mtk_vdec_8189_pdata;
 extern const struct mtk_vcodec_dec_pdata mtk_vdec_8192_pdata;
 extern const struct mtk_vcodec_dec_pdata mtk_vdec_8195_pdata;
 extern const struct mtk_vcodec_dec_pdata mtk_vdec_8196_pdata;
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
index d7a269045fd6..2d1a545e727c 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
@@ -553,6 +553,10 @@ static const struct of_device_id mtk_vcodec_match[] = {
 		.compatible = "mediatek,mt8196-vcodec-dec",
 		.data = &mtk_vdec_8196_pdata,
 	},
+	{
+		.compatible = "mediatek,mt8189-vcodec-dec",
+		.data = &mtk_vdec_8189_pdata,
+	},
 	{},
 };
 
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
index d249a8774948..9e43c54f8c4d 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
@@ -1013,3 +1013,21 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8186_pdata = {
 	.hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
 	.chip_name = 8186,
 };
+
+const struct mtk_vcodec_dec_pdata mtk_vdec_8189_pdata = {
+	.init_vdec_params = mtk_init_vdec_params,
+	.ctrls_setup = mtk_vcodec_dec_ctrls_setup,
+	.vdec_vb2_ops = &mtk_vdec_request_vb2_ops,
+	.vdec_formats = mtk_video_formats,
+	.num_formats = &num_formats,
+	.default_out_fmt = &default_out_format,
+	.default_cap_fmt = &default_cap_format,
+	.uses_stateless_api = true,
+	.worker = mtk_vdec_worker,
+	.flush_decoder = mtk_vdec_flush_decoder,
+	.cap_to_disp = mtk_vdec_stateless_cap_to_disp,
+	.get_cap_buffer = vdec_get_cap_buffer,
+	.is_subdev_supported = true,
+	.hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
+	.chip_name = 8189,
+};
-- 
2.45.2



From kyrie.wu at mediatek.com  Mon Dec  1 23:40:33 2025
From: kyrie.wu at mediatek.com (Kyrie Wu)
Date: Tue, 2 Dec 2025 15:40:33 +0800
Subject: [PATCH v6 06/10] media: mediatek: vcodec: Add 4K prob size supporting for VP9 decoder
In-Reply-To: <20251202074038.3173-1-kyrie.wu@mediatek.com>
References: <20251202074038.3173-1-kyrie.wu@mediatek.com>
Message-ID: <20251202074038.3173-7-kyrie.wu@mediatek.com>

From: Kyrie Wu <kyrie.wu at mediatek.corp-partner.google.com>

add config to support prob size both 3840 and 2560.

Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.corp-partner.google.com>
---
 .../platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h  | 2 ++
 .../mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c      | 1 +
 .../mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c     | 7 +++++++
 .../mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c     | 4 ++--
 4 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h
index a8baeab98477..ecf0d7ad0d54 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h
@@ -80,10 +80,12 @@ struct vdec_pic_info {
  * struct mtk_vcodec_dec_params - decoder supported parameters
  * @level: decoder supported vcodec level
  * @profile: decoder supported vcodec profile
+ * @prob_size: vp9 decoder prob size
  */
 struct mtk_vcodec_dec_params {
 	s64 level;
 	s64 profile;
+	size_t prob_size;
 };
 
 /**
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c
index a47906b9d717..99c252e0a2e1 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c
@@ -630,5 +630,6 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata = {
 	.vp9_params = {
 		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_4_0,
 		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_1,
+		.prob_size = 2560,
 	},
 };
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
index dc3e9a2ccc2c..f18aafd08c76 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
@@ -841,6 +841,7 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata = {
 	.vp9_params = {
 		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_4_0,
 		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_1,
+		.prob_size = 2560,
 	},
 };
 
@@ -889,6 +890,7 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8188_pdata = {
 	.vp9_params = {
 		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_1,
 		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
+		.prob_size = 2560,
 	},
 };
 
@@ -919,6 +921,7 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8192_pdata = {
 	.vp9_params = {
 		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_1,
 		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_1,
+		.prob_size = 2560,
 	},
 };
 
@@ -949,6 +952,7 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8195_pdata = {
 	.vp9_params = {
 		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2,
 		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
+		.prob_size = 2560,
 	},
 };
 
@@ -979,6 +983,7 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8196_pdata = {
 	.vp9_params = {
 		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2,
 		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
+		.prob_size = 3840,
 	},
 };
 
@@ -1026,6 +1031,7 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8186_pdata = {
 	.vp9_params = {
 		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_4_1,
 		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_1,
+		.prob_size = 2560,
 	},
 };
 
@@ -1056,5 +1062,6 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8189_pdata = {
 	.vp9_params = {
 		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2,
 		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
+		.prob_size = 3840,
 	},
 };
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
index 9513ddde7c7c..36a87b455d11 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
@@ -22,7 +22,6 @@
 #define VP9_RESET_FRAME_CONTEXT_ALL 3
 
 #define VP9_TILE_BUF_SIZE 4096
-#define VP9_PROB_BUF_SIZE 2560
 #define VP9_COUNTS_BUF_SIZE 16384
 
 #define HDR_FLAG(x) (!!((hdr)->flags & V4L2_VP9_FRAME_FLAG_##x))
@@ -546,6 +545,7 @@ static int vdec_vp9_slice_alloc_working_buffer(struct vdec_vp9_slice_instance *i
 					       struct vdec_vp9_slice_vsi *vsi)
 {
 	struct mtk_vcodec_dec_ctx *ctx = instance->ctx;
+	struct mtk_vcodec_dec_dev *pdev = ctx->dev;
 	enum vdec_vp9_slice_resolution_level level;
 	/* super blocks */
 	unsigned int max_sb_w;
@@ -616,7 +616,7 @@ static int vdec_vp9_slice_alloc_working_buffer(struct vdec_vp9_slice_instance *i
 	}
 
 	if (!instance->prob.va) {
-		instance->prob.size = VP9_PROB_BUF_SIZE;
+		instance->prob.size = pdev->vdec_pdata->vp9_params.prob_size;
 		if (mtk_vcodec_mem_alloc(ctx, &instance->prob))
 			goto err;
 	}
-- 
2.45.2



From kyrie.wu at mediatek.com  Mon Dec  1 23:40:32 2025
From: kyrie.wu at mediatek.com (Kyrie Wu)
Date: Tue, 2 Dec 2025 15:40:32 +0800
Subject: [PATCH v6 05/10] media: mediatek: vcodec: refactor setup dst buffer metadata interface for VP9 decoder
In-Reply-To: <20251202074038.3173-1-kyrie.wu@mediatek.com>
References: <20251202074038.3173-1-kyrie.wu@mediatek.com>
Message-ID: <20251202074038.3173-6-kyrie.wu@mediatek.com>

Previously, calling vdec_vp9_slice_setup_single_from_src_to_dst
with v4l2_m2m_next_src_buf to obtain both buffers resulted in -EINVAL,
interrupting the decoding process. To resolve this,
the interface should be updated to set both src and dst buffers
for metadata configuration.

Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
---
 .../vcodec/decoder/vdec/vdec_vp9_req_lat_if.c | 21 ++++++++++---------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
index fa0f406f7726..9513ddde7c7c 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
@@ -696,21 +696,22 @@ static int vdec_vp9_slice_tile_offset(int idx, int mi_num, int tile_log2)
 	return min(offset, mi_num);
 }
 
-static
-int vdec_vp9_slice_setup_single_from_src_to_dst(struct vdec_vp9_slice_instance *instance)
+static int vdec_vp9_slice_setup_single_from_src_to_dst(struct vdec_vp9_slice_instance *instance,
+						       struct mtk_vcodec_mem *bs,
+						       struct vdec_fb *fb)
 {
-	struct vb2_v4l2_buffer *src;
-	struct vb2_v4l2_buffer *dst;
+	struct mtk_video_dec_buf *src_buf_info;
+	struct mtk_video_dec_buf *dst_buf_info;
 
-	src = v4l2_m2m_next_src_buf(instance->ctx->m2m_ctx);
-	if (!src)
+	src_buf_info = container_of(bs, struct mtk_video_dec_buf, bs_buffer);
+	if (!src_buf_info)
 		return -EINVAL;
 
-	dst = v4l2_m2m_next_dst_buf(instance->ctx->m2m_ctx);
-	if (!dst)
+	dst_buf_info = container_of(fb, struct mtk_video_dec_buf, frame_buffer);
+	if (!dst_buf_info)
 		return -EINVAL;
 
-	v4l2_m2m_buf_copy_metadata(src, dst, true);
+	v4l2_m2m_buf_copy_metadata(&src_buf_info->m2m_buf.vb, &dst_buf_info->m2m_buf.vb, true);
 
 	return 0;
 }
@@ -1800,7 +1801,7 @@ static int vdec_vp9_slice_setup_single(struct vdec_vp9_slice_instance *instance,
 	struct vdec_vp9_slice_vsi *vsi = &pfc->vsi;
 	int ret;
 
-	ret = vdec_vp9_slice_setup_single_from_src_to_dst(instance);
+	ret = vdec_vp9_slice_setup_single_from_src_to_dst(instance, bs, fb);
 	if (ret)
 		goto err;
 
-- 
2.45.2



From kyrie.wu at mediatek.com  Mon Dec  1 23:40:31 2025
From: kyrie.wu at mediatek.com (Kyrie Wu)
Date: Tue, 2 Dec 2025 15:40:31 +0800
Subject: [PATCH v6 04/10] media: mediatek: vcodec: add profile and level supporting for MT8189
In-Reply-To: <20251202074038.3173-1-kyrie.wu@mediatek.com>
References: <20251202074038.3173-1-kyrie.wu@mediatek.com>
Message-ID: <20251202074038.3173-5-kyrie.wu@mediatek.com>

add profile and level supporting for H264 and vp9 of MT8189

Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
---
 .../vcodec/decoder/mtk_vcodec_dec_drv.h       |  16 ++
 .../vcodec/decoder/mtk_vcodec_dec_stateful.c  |  12 ++
 .../vcodec/decoder/mtk_vcodec_dec_stateless.c | 177 ++++++++++--------
 3 files changed, 130 insertions(+), 75 deletions(-)

diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h
index 2dbde8d00e6f..a8baeab98477 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h
@@ -76,6 +76,16 @@ struct vdec_pic_info {
 	unsigned int reserved;
 };
 
+/**
+ * struct mtk_vcodec_dec_params - decoder supported parameters
+ * @level: decoder supported vcodec level
+ * @profile: decoder supported vcodec profile
+ */
+struct mtk_vcodec_dec_params {
+	s64 level;
+	s64 profile;
+};
+
 /**
  * struct mtk_vcodec_dec_pdata - compatible data for each IC
  * @init_vdec_params: init vdec params
@@ -96,6 +106,9 @@ struct vdec_pic_info {
  * @is_subdev_supported: whether support parent-node architecture(subdev)
  * @uses_stateless_api: whether the decoder uses the stateless API with requests
  * @chip_name: platforms configuration values
+ * @h264_params: H264 decoder default supported params
+ * @h265_params: H265 decoder default supported params
+ * @vp9_params: VP9 decoder default supported params
  */
 struct mtk_vcodec_dec_pdata {
 	void (*init_vdec_params)(struct mtk_vcodec_dec_ctx *ctx);
@@ -118,6 +131,9 @@ struct mtk_vcodec_dec_pdata {
 	bool is_subdev_supported;
 	bool uses_stateless_api;
 	unsigned int chip_name;
+	struct mtk_vcodec_dec_params h264_params;
+	struct mtk_vcodec_dec_params h265_params;
+	struct mtk_vcodec_dec_params vp9_params;
 };
 
 /**
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c
index 8ddb61670dc6..a47906b9d717 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c
@@ -619,4 +619,16 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata = {
 	.is_subdev_supported = false,
 	.hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
 	.chip_name = 8173,
+	.h264_params = {
+		.level = V4L2_MPEG_VIDEO_H264_LEVEL_4_1,
+		.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
+	},
+	.h265_params = {
+		.level = V4L2_MPEG_VIDEO_HEVC_LEVEL_4,
+		.profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE,
+	},
+	.vp9_params = {
+		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_4_0,
+		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_1,
+	},
 };
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
index 9e43c54f8c4d..dc3e9a2ccc2c 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
@@ -549,106 +549,49 @@ static const struct v4l2_ctrl_ops mtk_vcodec_dec_ctrl_ops = {
 static void mtk_vcodec_dec_fill_h264_level(struct v4l2_ctrl_config *cfg,
 					   struct mtk_vcodec_dec_ctx *ctx)
 {
-	switch (ctx->dev->chip_name) {
-	case 8192:
-	case 8188:
-		cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_5_2;
-		break;
-	case 8195:
-	case 8196:
-		cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_6_0;
-		break;
-	case 8183:
-	case 8186:
-		cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_4_2;
-		break;
-	default:
-		cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_4_1;
-		break;
-	}
+	struct mtk_vcodec_dec_dev *pdev = ctx->dev;
+
+	cfg->max = pdev->vdec_pdata->h264_params.level;
 }
 
 static void mtk_vcodec_dec_fill_h264_profile(struct v4l2_ctrl_config *cfg,
 					     struct mtk_vcodec_dec_ctx *ctx)
 {
-	switch (ctx->dev->chip_name) {
-	case 8188:
-	case 8195:
-	case 8196:
-		cfg->max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10;
-		break;
-	default:
-		cfg->max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH;
-		break;
-	}
+	struct mtk_vcodec_dec_dev *pdev = ctx->dev;
+
+	cfg->max = pdev->vdec_pdata->h264_params.profile;
 }
 
 static void mtk_vcodec_dec_fill_h265_level(struct v4l2_ctrl_config *cfg,
 					   struct mtk_vcodec_dec_ctx *ctx)
 {
-	switch (ctx->dev->chip_name) {
-	case 8188:
-		cfg->max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1;
-		break;
-	case 8195:
-	case 8196:
-		cfg->max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2;
-		break;
-	default:
-		cfg->max = V4L2_MPEG_VIDEO_HEVC_LEVEL_4;
-		break;
-	}
+	struct mtk_vcodec_dec_dev *pdev = ctx->dev;
+
+	cfg->max = pdev->vdec_pdata->h265_params.level;
 }
 
 static void mtk_vcodec_dec_fill_h265_profile(struct v4l2_ctrl_config *cfg,
 					     struct mtk_vcodec_dec_ctx *ctx)
 {
-	switch (ctx->dev->chip_name) {
-	case 8188:
-	case 8195:
-	case 8196:
-		cfg->max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10;
-		break;
-	default:
-		cfg->max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE;
-		break;
-	}
+	struct mtk_vcodec_dec_dev *pdev = ctx->dev;
+
+	cfg->max = pdev->vdec_pdata->h265_params.profile;
 }
 
 static void mtk_vcodec_dec_fill_vp9_level(struct v4l2_ctrl_config *cfg,
 					  struct mtk_vcodec_dec_ctx *ctx)
 {
-	switch (ctx->dev->chip_name) {
-	case 8192:
-	case 8188:
-		cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_5_1;
-		break;
-	case 8195:
-	case 8196:
-		cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2;
-		break;
-	case 8186:
-		cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_4_1;
-		break;
-	default:
-		cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_4_0;
-		break;
-	}
+	struct mtk_vcodec_dec_dev *pdev = ctx->dev;
+
+	cfg->max = pdev->vdec_pdata->vp9_params.level;
 }
 
 static void mtk_vcodec_dec_fill_vp9_profile(struct v4l2_ctrl_config *cfg,
 					    struct mtk_vcodec_dec_ctx *ctx)
 {
-	switch (ctx->dev->chip_name) {
-	case 8188:
-	case 8195:
-	case 8196:
-		cfg->max = V4L2_MPEG_VIDEO_VP9_PROFILE_2;
-		break;
-	default:
-		cfg->max = V4L2_MPEG_VIDEO_VP9_PROFILE_1;
-		break;
-	}
+	struct mtk_vcodec_dec_dev *pdev = ctx->dev;
+
+	cfg->max = pdev->vdec_pdata->vp9_params.profile;
 }
 
 static void mtk_vcodec_dec_reset_controls(struct v4l2_ctrl_config *cfg,
@@ -887,6 +830,18 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata = {
 	.is_subdev_supported = false,
 	.hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
 	.chip_name = 8183,
+	.h264_params = {
+		.level = V4L2_MPEG_VIDEO_H264_LEVEL_4_2,
+		.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
+	},
+	.h265_params = {
+		.level = V4L2_MPEG_VIDEO_HEVC_LEVEL_4,
+		.profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE,
+	},
+	.vp9_params = {
+		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_4_0,
+		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_1,
+	},
 };
 
 /* This platform data is used for one lat and one core architecture. */
@@ -923,6 +878,18 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8188_pdata = {
 	.is_subdev_supported = true,
 	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
 	.chip_name = 8188,
+	.h264_params = {
+		.level = V4L2_MPEG_VIDEO_H264_LEVEL_5_2,
+		.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10,
+	},
+	.h265_params = {
+		.level = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1,
+		.profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
+	},
+	.vp9_params = {
+		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_1,
+		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
+	},
 };
 
 const struct mtk_vcodec_dec_pdata mtk_vdec_8192_pdata = {
@@ -941,6 +908,18 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8192_pdata = {
 	.is_subdev_supported = true,
 	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
 	.chip_name = 8192,
+	.h264_params = {
+		.level = V4L2_MPEG_VIDEO_H264_LEVEL_5_2,
+		.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
+	},
+	.h265_params = {
+		.level = V4L2_MPEG_VIDEO_HEVC_LEVEL_4,
+		.profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE,
+	},
+	.vp9_params = {
+		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_1,
+		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_1,
+	},
 };
 
 const struct mtk_vcodec_dec_pdata mtk_vdec_8195_pdata = {
@@ -959,6 +938,18 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8195_pdata = {
 	.is_subdev_supported = true,
 	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
 	.chip_name = 8195,
+	.h264_params = {
+		.level = V4L2_MPEG_VIDEO_H264_LEVEL_6_0,
+		.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10,
+	},
+	.h265_params = {
+		.level = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2,
+		.profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
+	},
+	.vp9_params = {
+		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2,
+		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
+	},
 };
 
 const struct mtk_vcodec_dec_pdata mtk_vdec_8196_pdata = {
@@ -977,6 +968,18 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8196_pdata = {
 	.is_subdev_supported = true,
 	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
 	.chip_name = 8196,
+	.h264_params = {
+		.level = V4L2_MPEG_VIDEO_H264_LEVEL_6_0,
+		.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10,
+	},
+	.h265_params = {
+		.level = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2,
+		.profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
+	},
+	.vp9_params = {
+		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2,
+		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
+	},
 };
 
 const struct mtk_vcodec_dec_pdata mtk_vdec_single_core_pdata = {
@@ -1012,6 +1015,18 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8186_pdata = {
 	.is_subdev_supported = true,
 	.hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
 	.chip_name = 8186,
+	.h264_params = {
+		.level = V4L2_MPEG_VIDEO_H264_LEVEL_4_2,
+		.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
+	},
+	.h265_params = {
+		.level = V4L2_MPEG_VIDEO_HEVC_LEVEL_4,
+		.profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE,
+	},
+	.vp9_params = {
+		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_4_1,
+		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_1,
+	},
 };
 
 const struct mtk_vcodec_dec_pdata mtk_vdec_8189_pdata = {
@@ -1030,4 +1045,16 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8189_pdata = {
 	.is_subdev_supported = true,
 	.hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
 	.chip_name = 8189,
+	.h264_params = {
+		.level = V4L2_MPEG_VIDEO_H264_LEVEL_5_2,
+		.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10,
+	},
+	.h265_params = {
+		.level = V4L2_MPEG_VIDEO_HEVC_LEVEL_4,
+		.profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE,
+	},
+	.vp9_params = {
+		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2,
+		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
+	},
 };
-- 
2.45.2



From kyrie.wu at mediatek.com  Mon Dec  1 23:40:34 2025
From: kyrie.wu at mediatek.com (Kyrie Wu)
Date: Tue, 2 Dec 2025 15:40:34 +0800
Subject: [PATCH v6 07/10] media: mediatek: vcodec: Fix vp9 4096x2176 fail for profile2
In-Reply-To: <20251202074038.3173-1-kyrie.wu@mediatek.com>
References: <20251202074038.3173-1-kyrie.wu@mediatek.com>
Message-ID: <20251202074038.3173-8-kyrie.wu@mediatek.com>

The DRAM address of the VP9 decoder tile info buffers may require
as much as 36bits for 4096x2176 resolution. Fold the 4 most significant
bits into the lower (padding) four bits of address.

Fixes: 5d418351ca8f1 ("media: mediatek: vcodec: support stateless VP9 decoding")

Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
---
 .../mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
index 36a87b455d11..eca6280098be 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
@@ -1134,9 +1134,17 @@ static int vdec_vp9_slice_setup_tile_buffer(struct vdec_vp9_slice_instance *inst
 					return -EINVAL;
 			}
 			tiles->size[i][j] = size;
+			/*
+			 * If the system supports 64-bit DMA addresses, the upper 4 bits
+			 * of the address are also encoded into the buffer entry.
+			 * The buffer pointer (tb) is incremented after each entry is written.
+			 */
 			if (tiles->mi_rows[i]) {
 				*tb++ = (size << 3) + ((offset << 3) & 0x7f);
-				*tb++ = pa & ~0xf;
+				*tb = pa & GENMASK(31, 4);
+				if (IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT))
+					*tb |= (pa >> 32) & GENMASK(3, 0);
+				tb++;
 				*tb++ = (pa << 3) & 0x7f;
 				mi_row = (tiles->mi_rows[i] - 1) & 0x1ff;
 				mi_col = (tiles->mi_cols[j] - 1) & 0x3f;
-- 
2.45.2



From kyrie.wu at mediatek.com  Mon Dec  1 23:40:35 2025
From: kyrie.wu at mediatek.com (Kyrie Wu)
Date: Tue, 2 Dec 2025 15:40:35 +0800
Subject: [PATCH v6 08/10] media: mediatek: vcodec: Fix media device node number
In-Reply-To: <20251202074038.3173-1-kyrie.wu@mediatek.com>
References: <20251202074038.3173-1-kyrie.wu@mediatek.com>
Message-ID: <20251202074038.3173-9-kyrie.wu@mediatek.com>

change media register device node number to a correct value.
The vfd minor is used to record the number of registered
video device nodes. The mdev_dec.devnode minor counter is
used to record the number of registered media device nodes.

Fixes: 41f03c673cb7b ("media: mediatek: vcodec: replace pr_* with dev_* for v4l2 debug message")

Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
---
 .../platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c      | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
index 2d1a545e727c..bf6e792283a1 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
@@ -493,7 +493,8 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
 			goto err_media_reg;
 		}
 
-		dev_dbg(&pdev->dev, "media registered as /dev/media%d", vfd_dec->minor);
+		dev_dbg(&pdev->dev, "media registered as /dev/media%d",
+			dev->mdev_dec.devnode->minor);
 	}
 
 	mtk_vcodec_dbgfs_init(dev, false);
-- 
2.45.2



From kyrie.wu at mediatek.com  Mon Dec  1 23:40:36 2025
From: kyrie.wu at mediatek.com (Kyrie Wu)
Date: Tue, 2 Dec 2025 15:40:36 +0800
Subject: [PATCH v6 09/10] dt-bindings: media: Add MT8189 mediatek,vcodec-encoder
In-Reply-To: <20251202074038.3173-1-kyrie.wu@mediatek.com>
References: <20251202074038.3173-1-kyrie.wu@mediatek.com>
Message-ID: <20251202074038.3173-10-kyrie.wu@mediatek.com>

Add MT8189 encoder compatible string to distinguish former ICs
MTK's. Compared with MT8196, the maximum resolution of MT8189
encoder is only 4K, and the fps is only 30, which cannot reach
the highest parameter of MT8196: level6.2, 8K at 60fps.
Compared with MT8188, the level can only support 5.1, which is less
than 5.2 of MT8188. But the maximum bitrate is 100Mbps, which is twice
that of MT8188. And MT8189 could support NBM mode.

Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
---
 .../devicetree/bindings/media/mediatek,vcodec-encoder.yaml      | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/media/mediatek,vcodec-encoder.yaml b/Documentation/devicetree/bindings/media/mediatek,vcodec-encoder.yaml
index bb4dbf23ccc5..7f355470b63c 100644
--- a/Documentation/devicetree/bindings/media/mediatek,vcodec-encoder.yaml
+++ b/Documentation/devicetree/bindings/media/mediatek,vcodec-encoder.yaml
@@ -22,6 +22,7 @@ properties:
               - mediatek,mt8173-vcodec-enc
               - mediatek,mt8183-vcodec-enc
               - mediatek,mt8188-vcodec-enc
+              - mediatek,mt8189-vcodec-enc
               - mediatek,mt8192-vcodec-enc
               - mediatek,mt8195-vcodec-enc
               - mediatek,mt8196-vcodec-enc
@@ -100,6 +101,7 @@ allOf:
             enum:
               - mediatek,mt8183-vcodec-enc
               - mediatek,mt8188-vcodec-enc
+              - mediatek,mt8189-vcodec-enc
               - mediatek,mt8192-vcodec-enc
               - mediatek,mt8195-vcodec-enc
 
-- 
2.45.2



From kyrie.wu at mediatek.com  Mon Dec  1 23:40:37 2025
From: kyrie.wu at mediatek.com (Kyrie Wu)
Date: Tue, 2 Dec 2025 15:40:37 +0800
Subject: [PATCH v6 10/10] media: mediatek: encoder: Add MT8189 encoder compatible data
In-Reply-To: <20251202074038.3173-1-kyrie.wu@mediatek.com>
References: <20251202074038.3173-1-kyrie.wu@mediatek.com>
Message-ID: <20251202074038.3173-11-kyrie.wu@mediatek.com>

add MT8189 compatible data to initialize platform data for encoder.

Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
---
 .../mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c   | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c
index 6b3d2e72fad9..2cc92a8f7a0d 100644
--- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c
+++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c
@@ -467,6 +467,19 @@ static const struct mtk_vcodec_enc_pdata mt8196_pdata = {
 	.set_dma_bit_mask = true,
 };
 
+static const struct mtk_vcodec_enc_pdata mt8189_pdata = {
+	.venc_model_num = 8189,
+	.capture_formats = mtk_video_formats_capture_h264,
+	.num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264),
+	.output_formats = mtk_video_formats_output,
+	.num_output_formats = ARRAY_SIZE(mtk_video_formats_output),
+	.min_bitrate = 64,
+	.max_bitrate = 100000000,
+	.core_id = VENC_SYS,
+	.uses_common_fw_iface = true,
+	.set_dma_bit_mask = true,
+};
+
 static const struct of_device_id mtk_vcodec_enc_match[] = {
 	{.compatible = "mediatek,mt8173-vcodec-enc",
 			.data = &mt8173_avc_pdata},
@@ -477,6 +490,7 @@ static const struct of_device_id mtk_vcodec_enc_match[] = {
 	{.compatible = "mediatek,mt8192-vcodec-enc", .data = &mt8192_pdata},
 	{.compatible = "mediatek,mt8195-vcodec-enc", .data = &mt8195_pdata},
 	{.compatible = "mediatek,mt8196-vcodec-enc", .data = &mt8196_pdata},
+	{.compatible = "mediatek,mt8189-vcodec-enc", .data = &mt8189_pdata},
 	{},
 };
 MODULE_DEVICE_TABLE(of, mtk_vcodec_enc_match);
-- 
2.45.2



From 2694439648 at qq.com  Mon Dec  1 23:43:59 2025
From: 2694439648 at qq.com (2694439648 at qq.com)
Date: Tue,  2 Dec 2025 15:43:59 +0800
Subject: [PATCH v2] net: stmmac: Modify the judgment condition of "tx_avail" from 1 to 2
Message-ID: <tencent_4A0CBC92B9B22C699AC2890E139565FCB306@qq.com>

From: "hailong.fan" <hailong.fan at siengine.com>

    Under certain conditions, a WARN_ON will be triggered
    if avail equals 1.

    For example, when a VLAN packet is to send,
    stmmac_vlan_insert consumes one unit of space,
    and the data itself consumes another.
    actually requiring 2 units of space in total.

    ---
    V0-V1:
       1. Stop their queues earlier
    V2-V1:
       1. add fixes tag
       2. Add stmmac_extra_space to count the additional required space

Fixes: 30d932279dc2 ("net: stmmac: Add support for VLAN Insertion Offload")
Signed-off-by: hailong.fan <hailong.fan at siengine.com>
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 7b90ecd3a..9a665a3b2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -4476,6 +4476,15 @@ static bool stmmac_has_ip_ethertype(struct sk_buff *skb)
 		(proto == htons(ETH_P_IP) || proto == htons(ETH_P_IPV6));
 }
 
+static inline int stmmac_extra_space(struct stmmac_priv *priv,
+				     struct sk_buff *skb)
+{
+	if (!priv->dma_cap.vlins || !skb_vlan_tag_present(skb))
+		return 0;
+
+	return 1;
+}
+
 /**
  *  stmmac_xmit - Tx entry point of the driver
  *  @skb : the socket buffer
@@ -4529,7 +4538,8 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 		}
 	}
 
-	if (unlikely(stmmac_tx_avail(priv, queue) < nfrags + 1)) {
+	if (unlikely(stmmac_tx_avail(priv, queue) <
+		nfrags + 1 + stmmac_extra_space(priv, skb))) {
 		if (!netif_tx_queue_stopped(netdev_get_tx_queue(dev, queue))) {
 			netif_tx_stop_queue(netdev_get_tx_queue(priv->dev,
 								queue));
@@ -4675,7 +4685,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 		print_pkt(skb->data, skb->len);
 	}
 
-	if (unlikely(stmmac_tx_avail(priv, queue) <= (MAX_SKB_FRAGS + 1))) {
+	if (unlikely(stmmac_tx_avail(priv, queue) <= (MAX_SKB_FRAGS + 2))) {
 		netif_dbg(priv, hw, priv->dev, "%s: stop transmitted packets\n",
 			  __func__);
 		netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, queue));
-- 
2.34.1



From maudspierings at gocontroll.com  Mon Dec  1 23:46:21 2025
From: maudspierings at gocontroll.com (Maud Spierings)
Date: Tue, 2 Dec 2025 08:46:21 +0100
Subject: [PATCH v6 1/4] dt-bindings: backlight: Add max25014 support
In-Reply-To: <aS3H1qzSMKHamqpP@lizhi-Precision-Tower-5810>
References: <20251201-max25014-v6-0-88e3ac8112ff@gocontroll.com>
 <20251201-max25014-v6-1-88e3ac8112ff@gocontroll.com>
 <aS3H1qzSMKHamqpP@lizhi-Precision-Tower-5810>
Message-ID: <b9fe6df7-fdc6-4a32-919b-8f3b44eace7d@gocontroll.com>

On 12/1/25 17:52, Frank Li wrote:
> On Mon, Dec 01, 2025 at 12:53:20PM +0100, Maud Spierings via B4 Relay wrote:
>> From: Maud Spierings <maudspierings at gocontroll.com>
>>
>> The Maxim MAX25014 is a 4-channel automotive grade backlight driver IC
>> with integrated boost controller.
>>
>> Signed-off-by: Maud Spierings <maudspierings at gocontroll.com>
>>
>> ---
>>
>> In the current implementation the control registers for channel 1,
>> control all channels. So only one led subnode with led-sources is
>> supported right now. If at some point the driver functionality is
>> expanded the bindings can be easily extended with it.
>> ---
>>   .../bindings/leds/backlight/maxim,max25014.yaml    | 107 +++++++++++++++++++++
>>   MAINTAINERS                                        |   5 +
>>   2 files changed, 112 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml b/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
>> new file mode 100644
>> index 000000000000..e83723224b07
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
>> @@ -0,0 +1,107 @@
>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/leds/backlight/maxim,max25014.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Maxim max25014 backlight controller
>> +
>> +maintainers:
>> +  - Maud Spierings <maudspierings at gocontroll.com>
>> +
>> +properties:
>> +  compatible:
>> +    enum:
>> +      - maxim,max25014
>> +
>> +  reg:
>> +    maxItems: 1
>> +
>> +  "#address-cells":
>> +    const: 1
>> +
>> +  "#size-cells":
>> +    const: 0
>> +
>> +  enable-gpios:
>> +    maxItems: 1
>> +
>> +  interrupts:
>> +    maxItems: 1
>> +
>> +  power-supply:
>> +    description: Regulator which controls the boost converter input rail.
>> +
>> +  pwms:
>> +    maxItems: 1
>> +
>> +  maxim,iset:
>> +    $ref: /schemas/types.yaml#/definitions/uint32
>> +    maximum: 15
>> +    default: 11
>> +    description:
>> +      Value of the ISET field in the ISET register. This controls the current
>> +      scale of the outputs, a higher number means more current.
>> +
>> +  led at 0:
> 
> define whole binding, allow 0-3. binding is not related with driver's
> implement.
> 
> it'd better put unders leds.
>

so like:

backlight: backlight at 6f {
	compatible = "maxim,max25014";
	reg = <0x6f>;
	enable-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_backlight>;
	maxim,iset = <7>;

	leds {
		#address-cells = <1>;
		#size-cells = <0>;

		led at 0 {
			reg = <0>;
			led-sources = <0 1 2>;
			default-brightness = <50>;
		};

		optional led@#....
	};
};

right?

Kind regards,
Maud

> 
>> +    type: object
>> +    description: Properties for a string of connected LEDs.
>> +    $ref: common.yaml#
>> +
>> +    properties:
>> +      reg:
>> +        const: 0
>> +
>> +      led-sources:
>> +        allOf:
>> +          - minItems: 1
>> +            maxItems: 4
>> +            items:
>> +              minimum: 0
>> +              maximum: 3
>> +            default: [0, 1, 2, 3]
>> +
>> +      default-brightness:
>> +        minimum: 0
>> +        maximum: 100
>> +        default: 50
>> +
>> +    required:
>> +      - reg
>> +
>> +    additionalProperties: false
> 
> unevaluatedProperties: false because ref to common.yaml
> 
> Frank
> 




From alexander.stein at ew.tq-group.com  Mon Dec  1 23:48:54 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Tue, 02 Dec 2025 08:48:54 +0100
Subject: [PATCH 1/3] pmdomain: imx93-blk-ctrl: cleanup error path
In-Reply-To: <20251201-v6-18-topic-imx93-blkctrl-v1-1-b57a72e60105@pengutronix.de>
References: <20251201-v6-18-topic-imx93-blkctrl-v1-0-b57a72e60105@pengutronix.de>
 <20251201-v6-18-topic-imx93-blkctrl-v1-1-b57a72e60105@pengutronix.de>
Message-ID: <2812632.mvXUDI8C0e@steina-w>

Am Montag, 1. Dezember 2025, 18:12:05 CET schrieb Marco Felsch:
> Call dev_err_probe() directly during return to make the code more
> compact.
> 
> Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>

Reviewed-by: Alexander Stein <alexander.stein at ew.tq-group.com>

> ---
>  drivers/pmdomain/imx/imx93-blk-ctrl.c | 6 ++----
>  1 file changed, 2 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/pmdomain/imx/imx93-blk-ctrl.c b/drivers/pmdomain/imx/imx93-blk-ctrl.c
> index e094fe5a42bf646c712f3eca4e66a313fa5a914c..2aa163aef8de4ee901b9cde76ce2aad246c8c08a 100644
> --- a/drivers/pmdomain/imx/imx93-blk-ctrl.c
> +++ b/drivers/pmdomain/imx/imx93-blk-ctrl.c
> @@ -240,10 +240,8 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
>  	bc->num_clks = bc_data->num_clks;
>  
>  	ret = devm_clk_bulk_get(dev, bc->num_clks, bc->clks);
> -	if (ret) {
> -		dev_err_probe(dev, ret, "failed to get bus clock\n");
> -		return ret;
> -	}
> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to get bus clock\n");
>  
>  	for (i = 0; i < bc_data->num_domains; i++) {
>  		const struct imx93_blk_ctrl_domain_data *data = &bc_data->domains[i];
> 
> 


-- 
TQ-Systems GmbH | M?hlstra?e 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht M?nchen, HRB 105018
Gesch?ftsf?hrer: Detlef Schneider, R?diger Stahl, Stefan Schneider
http://www.tq-group.com/




From alexander.stein at ew.tq-group.com  Mon Dec  1 23:49:01 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Tue, 02 Dec 2025 08:49:01 +0100
Subject: [PATCH 3/3] pmdomain: imx93-blk-ctrl: add support for optional subnodes
In-Reply-To: <20251201-v6-18-topic-imx93-blkctrl-v1-3-b57a72e60105@pengutronix.de>
References: <20251201-v6-18-topic-imx93-blkctrl-v1-0-b57a72e60105@pengutronix.de>
 <20251201-v6-18-topic-imx93-blkctrl-v1-3-b57a72e60105@pengutronix.de>
Message-ID: <5948751.DvuYhMxLoT@steina-w>

Am Montag, 1. Dezember 2025, 18:12:07 CET schrieb Marco Felsch:
> This particular block can have DT subnodes describing the LVDS LDB, MIPI
> DSI and parallel DPI bridge.
> 
> Scan for possible sub-devices within the driver, instead of misusing the
> simple-bus to perform the scan.
> 
> Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>

Reviewed-by: Alexander Stein <alexander.stein at ew.tq-group.com>

> ---
>  drivers/pmdomain/imx/imx93-blk-ctrl.c | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/drivers/pmdomain/imx/imx93-blk-ctrl.c b/drivers/pmdomain/imx/imx93-blk-ctrl.c
> index 13b0de6dd689cf944e034f7666a4e97b0118e3bd..8f79cabe07face872cb396bfb7329c230c4a97fe 100644
> --- a/drivers/pmdomain/imx/imx93-blk-ctrl.c
> +++ b/drivers/pmdomain/imx/imx93-blk-ctrl.c
> @@ -7,6 +7,7 @@
>  #include <linux/device.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
> +#include <linux/of_platform.h>
>  #include <linux/platform_device.h>
>  #include <linux/pm_domain.h>
>  #include <linux/pm_runtime.h>
> @@ -311,6 +312,10 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
>  	if (ret)
>  		return dev_err_probe(dev, ret, "failed to add genpd_provider release callback\n");
>  
> +	ret = devm_of_platform_populate(dev);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to populate blk-ctrl sub-devices\n");
> +
>  	return 0;
>  }
>  
> 
> 


-- 
TQ-Systems GmbH | M?hlstra?e 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht M?nchen, HRB 105018
Gesch?ftsf?hrer: Detlef Schneider, R?diger Stahl, Stefan Schneider
http://www.tq-group.com/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251202/94ebe89b/attachment.sig>

From carlos.song at nxp.com  Mon Dec  1 23:54:57 2025
From: carlos.song at nxp.com (Carlos Song)
Date: Tue,  2 Dec 2025 15:54:57 +0800
Subject: [PATCH v2 0/6] Support ECSPI dynamic burst feature for DMA mode
Message-ID: <20251202075503.2448339-1-carlos.song@nxp.com>

ECSPI has a low throughput because of no dynamic burst support, it
transfers only one word per frame in DMA mode, causing SCLK stalls
between words due to BURST_LENGTH updates.

This patch set is to support ECSPI dynamic burst feature to help improve
the ECSPI DMA mode performance.

Performance test (spidev_test @10MHz, 4KB):
  Before: tx/rx ~6651.9 kbps
  After:  tx/rx ~9922.2 kbps (~50% improvement)

For compatibility with slow SPI devices, add configurable word delay in
DMA mode. When word delay is set, dynamic burst is disabled and
BURST_LENGTH equals word length.

Also support target DMA mode with enabled dynamic burst.

Changes since v1:
* Patch1~3:
* Add review-by tag
* Patch4:
  * Add review-by tag
  * Improve patch commit log
* Patch5:
  * Clean up tab instead of space for dma_tx_addr and dma_rx_addr
  * Add  __counted_by(dma_package_num) for dma_data_package *dma_data
  * Move temp and bytes_per_word to if()
  * Add comment for spi_imx_dma_rx_data_handle() and
    spi_imx_dma_tx_data_handle()
  * Use kzalloc instead of kmalloc(x, x | __GFP_ZERO)
  * Use sizeof(*temp) instead of BYTES_PER_32BITS_WORD in suitable place
  * Add comments and fix comments according to discussion
  * Propagate the error value of dma_mapping_error()
  * Use round_down() to replace DIV_ROUND_DOWN_ULL()
  * Improve transfer->error |= SPI_TRANS_FAIL_NO_START judgment for
    better readability
* Patch6:
  * Improve patch commit log
  * Add READ_ONCE for spi_imx->target_aborted
  * Add comments for data length limit
  * Move data length limit to spi_imx_can_dma()

Carlos Song (6):
  spi: imx: group spi_imx_dma_configure() with spi_imx_dma_transfer()
  spi: imx: introduce helper to clear DMA mode logic
  spi: imx: avoid dmaengine_terminate_all() on TX prep failure
  spi: imx: handle DMA submission errors with dma_submit_error()
  spi: imx: support dynamic burst length for ECSPI DMA mode
  spi: imx: enable DMA mode for target operation

 drivers/spi/spi-imx.c | 625 +++++++++++++++++++++++++++++++++++-------
 1 file changed, 519 insertions(+), 106 deletions(-)

-- 
2.34.1



From carlos.song at nxp.com  Mon Dec  1 23:54:58 2025
From: carlos.song at nxp.com (Carlos Song)
Date: Tue,  2 Dec 2025 15:54:58 +0800
Subject: [PATCH v2 1/6] spi: imx: group spi_imx_dma_configure() with spi_imx_dma_transfer()
In-Reply-To: <20251202075503.2448339-1-carlos.song@nxp.com>
References: <20251202075503.2448339-1-carlos.song@nxp.com>
Message-ID: <20251202075503.2448339-2-carlos.song@nxp.com>

Relocate spi_imx_dma_configure() next to spi_imx_dma_transfer() so that
all DMA-related functions are grouped together for better readability.
No functional changes.

Signed-off-by: Carlos Song <carlos.song at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/spi/spi-imx.c | 88 +++++++++++++++++++++----------------------
 1 file changed, 44 insertions(+), 44 deletions(-)

diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index b8b79bb7fec3..e78e02a84b50 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -1282,50 +1282,6 @@ static irqreturn_t spi_imx_isr(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-static int spi_imx_dma_configure(struct spi_controller *controller)
-{
-	int ret;
-	enum dma_slave_buswidth buswidth;
-	struct dma_slave_config rx = {}, tx = {};
-	struct spi_imx_data *spi_imx = spi_controller_get_devdata(controller);
-
-	switch (spi_imx_bytes_per_word(spi_imx->bits_per_word)) {
-	case 4:
-		buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
-		break;
-	case 2:
-		buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
-		break;
-	case 1:
-		buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	tx.direction = DMA_MEM_TO_DEV;
-	tx.dst_addr = spi_imx->base_phys + MXC_CSPITXDATA;
-	tx.dst_addr_width = buswidth;
-	tx.dst_maxburst = spi_imx->wml;
-	ret = dmaengine_slave_config(controller->dma_tx, &tx);
-	if (ret) {
-		dev_err(spi_imx->dev, "TX dma configuration failed with %d\n", ret);
-		return ret;
-	}
-
-	rx.direction = DMA_DEV_TO_MEM;
-	rx.src_addr = spi_imx->base_phys + MXC_CSPIRXDATA;
-	rx.src_addr_width = buswidth;
-	rx.src_maxburst = spi_imx->wml;
-	ret = dmaengine_slave_config(controller->dma_rx, &rx);
-	if (ret) {
-		dev_err(spi_imx->dev, "RX dma configuration failed with %d\n", ret);
-		return ret;
-	}
-
-	return 0;
-}
-
 static int spi_imx_setupxfer(struct spi_device *spi,
 				 struct spi_transfer *t)
 {
@@ -1481,6 +1437,50 @@ static int spi_imx_calculate_timeout(struct spi_imx_data *spi_imx, int size)
 	return secs_to_jiffies(2 * timeout);
 }
 
+static int spi_imx_dma_configure(struct spi_controller *controller)
+{
+	int ret;
+	enum dma_slave_buswidth buswidth;
+	struct dma_slave_config rx = {}, tx = {};
+	struct spi_imx_data *spi_imx = spi_controller_get_devdata(controller);
+
+	switch (spi_imx_bytes_per_word(spi_imx->bits_per_word)) {
+	case 4:
+		buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		break;
+	case 2:
+		buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
+		break;
+	case 1:
+		buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	tx.direction = DMA_MEM_TO_DEV;
+	tx.dst_addr = spi_imx->base_phys + MXC_CSPITXDATA;
+	tx.dst_addr_width = buswidth;
+	tx.dst_maxburst = spi_imx->wml;
+	ret = dmaengine_slave_config(controller->dma_tx, &tx);
+	if (ret) {
+		dev_err(spi_imx->dev, "TX dma configuration failed with %d\n", ret);
+		return ret;
+	}
+
+	rx.direction = DMA_DEV_TO_MEM;
+	rx.src_addr = spi_imx->base_phys + MXC_CSPIRXDATA;
+	rx.src_addr_width = buswidth;
+	rx.src_maxburst = spi_imx->wml;
+	ret = dmaengine_slave_config(controller->dma_rx, &rx);
+	if (ret) {
+		dev_err(spi_imx->dev, "RX dma configuration failed with %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
 static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
 				struct spi_transfer *transfer)
 {
-- 
2.34.1



From carlos.song at nxp.com  Mon Dec  1 23:54:59 2025
From: carlos.song at nxp.com (Carlos Song)
Date: Tue,  2 Dec 2025 15:54:59 +0800
Subject: [PATCH v2 2/6] spi: imx: introduce helper to clear DMA mode logic
In-Reply-To: <20251202075503.2448339-1-carlos.song@nxp.com>
References: <20251202075503.2448339-1-carlos.song@nxp.com>
Message-ID: <20251202075503.2448339-3-carlos.song@nxp.com>

Add a helper function to handle clearing DMA mode, including getting the
maximum watermark length and submitting the DMA request. This refactoring
makes the code more concise and improves readability.
No functional changes.

Signed-off-by: Carlos Song <carlos.song at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/spi/spi-imx.c | 164 +++++++++++++++++++++++-------------------
 1 file changed, 92 insertions(+), 72 deletions(-)

diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index e78e02a84b50..012f5bcbf73f 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -1437,6 +1437,94 @@ static int spi_imx_calculate_timeout(struct spi_imx_data *spi_imx, int size)
 	return secs_to_jiffies(2 * timeout);
 }
 
+static int spi_imx_dma_submit(struct spi_imx_data *spi_imx,
+			      struct spi_transfer *transfer)
+{
+	struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg;
+	struct spi_controller *controller = spi_imx->controller;
+	struct dma_async_tx_descriptor *desc_tx, *desc_rx;
+	unsigned long transfer_timeout;
+	unsigned long time_left;
+
+	/*
+	 * The TX DMA setup starts the transfer, so make sure RX is configured
+	 * before TX.
+	 */
+	desc_rx = dmaengine_prep_slave_sg(controller->dma_rx,
+					  rx->sgl, rx->nents, DMA_DEV_TO_MEM,
+					  DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	if (!desc_rx) {
+		transfer->error |= SPI_TRANS_FAIL_NO_START;
+		return -EINVAL;
+	}
+
+	desc_rx->callback = spi_imx_dma_rx_callback;
+	desc_rx->callback_param = (void *)spi_imx;
+	dmaengine_submit(desc_rx);
+	reinit_completion(&spi_imx->dma_rx_completion);
+	dma_async_issue_pending(controller->dma_rx);
+
+	desc_tx = dmaengine_prep_slave_sg(controller->dma_tx,
+					  tx->sgl, tx->nents, DMA_MEM_TO_DEV,
+					  DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	if (!desc_tx) {
+		dmaengine_terminate_all(controller->dma_tx);
+		dmaengine_terminate_all(controller->dma_rx);
+		return -EINVAL;
+	}
+
+	desc_tx->callback = spi_imx_dma_tx_callback;
+	desc_tx->callback_param = (void *)spi_imx;
+	dmaengine_submit(desc_tx);
+	reinit_completion(&spi_imx->dma_tx_completion);
+	dma_async_issue_pending(controller->dma_tx);
+
+	spi_imx->devtype_data->trigger(spi_imx);
+
+	transfer_timeout = spi_imx_calculate_timeout(spi_imx, transfer->len);
+
+	/* Wait SDMA to finish the data transfer.*/
+	time_left = wait_for_completion_timeout(&spi_imx->dma_tx_completion,
+						transfer_timeout);
+	if (!time_left) {
+		dev_err(spi_imx->dev, "I/O Error in DMA TX\n");
+		dmaengine_terminate_all(controller->dma_tx);
+		dmaengine_terminate_all(controller->dma_rx);
+		return -ETIMEDOUT;
+	}
+
+	time_left = wait_for_completion_timeout(&spi_imx->dma_rx_completion,
+						transfer_timeout);
+	if (!time_left) {
+		dev_err(&controller->dev, "I/O Error in DMA RX\n");
+		spi_imx->devtype_data->reset(spi_imx);
+		dmaengine_terminate_all(controller->dma_rx);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static void spi_imx_dma_max_wml_find(struct spi_imx_data *spi_imx,
+				     struct spi_transfer *transfer)
+{
+	struct sg_table *rx = &transfer->rx_sg;
+	struct scatterlist *last_sg = sg_last(rx->sgl, rx->nents);
+	unsigned int bytes_per_word, i;
+
+	/* Get the right burst length from the last sg to ensure no tail data */
+	bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word);
+	for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) {
+		if (!(sg_dma_len(last_sg) % (i * bytes_per_word)))
+			break;
+	}
+	/* Use 1 as wml in case no available burst length got */
+	if (i == 0)
+		i = 1;
+
+	spi_imx->wml = i;
+}
+
 static int spi_imx_dma_configure(struct spi_controller *controller)
 {
 	int ret;
@@ -1484,26 +1572,10 @@ static int spi_imx_dma_configure(struct spi_controller *controller)
 static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
 				struct spi_transfer *transfer)
 {
-	struct dma_async_tx_descriptor *desc_tx, *desc_rx;
-	unsigned long transfer_timeout;
-	unsigned long time_left;
 	struct spi_controller *controller = spi_imx->controller;
-	struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg;
-	struct scatterlist *last_sg = sg_last(rx->sgl, rx->nents);
-	unsigned int bytes_per_word, i;
 	int ret;
 
-	/* Get the right burst length from the last sg to ensure no tail data */
-	bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word);
-	for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) {
-		if (!(sg_dma_len(last_sg) % (i * bytes_per_word)))
-			break;
-	}
-	/* Use 1 as wml in case no available burst length got */
-	if (i == 0)
-		i = 1;
-
-	spi_imx->wml =  i;
+	spi_imx_dma_max_wml_find(spi_imx, transfer);
 
 	ret = spi_imx_dma_configure(controller);
 	if (ret)
@@ -1516,61 +1588,9 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
 	}
 	spi_imx->devtype_data->setup_wml(spi_imx);
 
-	/*
-	 * The TX DMA setup starts the transfer, so make sure RX is configured
-	 * before TX.
-	 */
-	desc_rx = dmaengine_prep_slave_sg(controller->dma_rx,
-				rx->sgl, rx->nents, DMA_DEV_TO_MEM,
-				DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-	if (!desc_rx) {
-		ret = -EINVAL;
-		goto dma_failure_no_start;
-	}
-
-	desc_rx->callback = spi_imx_dma_rx_callback;
-	desc_rx->callback_param = (void *)spi_imx;
-	dmaengine_submit(desc_rx);
-	reinit_completion(&spi_imx->dma_rx_completion);
-	dma_async_issue_pending(controller->dma_rx);
-
-	desc_tx = dmaengine_prep_slave_sg(controller->dma_tx,
-				tx->sgl, tx->nents, DMA_MEM_TO_DEV,
-				DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-	if (!desc_tx) {
-		dmaengine_terminate_all(controller->dma_tx);
-		dmaengine_terminate_all(controller->dma_rx);
-		return -EINVAL;
-	}
-
-	desc_tx->callback = spi_imx_dma_tx_callback;
-	desc_tx->callback_param = (void *)spi_imx;
-	dmaengine_submit(desc_tx);
-	reinit_completion(&spi_imx->dma_tx_completion);
-	dma_async_issue_pending(controller->dma_tx);
-
-	spi_imx->devtype_data->trigger(spi_imx);
-
-	transfer_timeout = spi_imx_calculate_timeout(spi_imx, transfer->len);
-
-	/* Wait SDMA to finish the data transfer.*/
-	time_left = wait_for_completion_timeout(&spi_imx->dma_tx_completion,
-						transfer_timeout);
-	if (!time_left) {
-		dev_err(spi_imx->dev, "I/O Error in DMA TX\n");
-		dmaengine_terminate_all(controller->dma_tx);
-		dmaengine_terminate_all(controller->dma_rx);
-		return -ETIMEDOUT;
-	}
-
-	time_left = wait_for_completion_timeout(&spi_imx->dma_rx_completion,
-						transfer_timeout);
-	if (!time_left) {
-		dev_err(&controller->dev, "I/O Error in DMA RX\n");
-		spi_imx->devtype_data->reset(spi_imx);
-		dmaengine_terminate_all(controller->dma_rx);
-		return -ETIMEDOUT;
-	}
+	ret = spi_imx_dma_submit(spi_imx, transfer);
+	if (ret)
+		return ret;
 
 	return 0;
 /* fallback to pio */
-- 
2.34.1



From carlos.song at nxp.com  Mon Dec  1 23:55:00 2025
From: carlos.song at nxp.com (Carlos Song)
Date: Tue,  2 Dec 2025 15:55:00 +0800
Subject: [PATCH v2 3/6] spi: imx: avoid dmaengine_terminate_all() on TX prep failure
In-Reply-To: <20251202075503.2448339-1-carlos.song@nxp.com>
References: <20251202075503.2448339-1-carlos.song@nxp.com>
Message-ID: <20251202075503.2448339-4-carlos.song@nxp.com>

If dmaengine_prep_slave_sg() fails, no descriptor is submitted to the TX
channel and DMA is never started. Therefore, calling
dmaengine_terminate_all() for the TX DMA channel is unnecessary.

Signed-off-by: Carlos Song <carlos.song at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/spi/spi-imx.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 012f5bcbf73f..186963d3d2e0 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -1468,7 +1468,6 @@ static int spi_imx_dma_submit(struct spi_imx_data *spi_imx,
 					  tx->sgl, tx->nents, DMA_MEM_TO_DEV,
 					  DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!desc_tx) {
-		dmaengine_terminate_all(controller->dma_tx);
 		dmaengine_terminate_all(controller->dma_rx);
 		return -EINVAL;
 	}
-- 
2.34.1



From carlos.song at nxp.com  Mon Dec  1 23:55:01 2025
From: carlos.song at nxp.com (Carlos Song)
Date: Tue,  2 Dec 2025 15:55:01 +0800
Subject: [PATCH v2 4/6] spi: imx: handle DMA submission errors with dma_submit_error()
In-Reply-To: <20251202075503.2448339-1-carlos.song@nxp.com>
References: <20251202075503.2448339-1-carlos.song@nxp.com>
Message-ID: <20251202075503.2448339-5-carlos.song@nxp.com>

Add error handling for DMA request submission by checking the return
cookie with dma_submit_error(). This prevents propagating submission
failures through the DMA transfer process, which could lead to
unexpected behavior.

Signed-off-by: Carlos Song <carlos.song at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/spi/spi-imx.c | 28 ++++++++++++++++++++++------
 1 file changed, 22 insertions(+), 6 deletions(-)

diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 186963d3d2e0..42f64d9535c9 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -1445,6 +1445,7 @@ static int spi_imx_dma_submit(struct spi_imx_data *spi_imx,
 	struct dma_async_tx_descriptor *desc_tx, *desc_rx;
 	unsigned long transfer_timeout;
 	unsigned long time_left;
+	dma_cookie_t cookie;
 
 	/*
 	 * The TX DMA setup starts the transfer, so make sure RX is configured
@@ -1460,21 +1461,29 @@ static int spi_imx_dma_submit(struct spi_imx_data *spi_imx,
 
 	desc_rx->callback = spi_imx_dma_rx_callback;
 	desc_rx->callback_param = (void *)spi_imx;
-	dmaengine_submit(desc_rx);
+	cookie = dmaengine_submit(desc_rx);
+	if (dma_submit_error(cookie)) {
+		dev_err(spi_imx->dev, "submitting DMA RX failed\n");
+		transfer->error |= SPI_TRANS_FAIL_NO_START;
+		goto dmaengine_terminate_rx;
+	}
+
 	reinit_completion(&spi_imx->dma_rx_completion);
 	dma_async_issue_pending(controller->dma_rx);
 
 	desc_tx = dmaengine_prep_slave_sg(controller->dma_tx,
 					  tx->sgl, tx->nents, DMA_MEM_TO_DEV,
 					  DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-	if (!desc_tx) {
-		dmaengine_terminate_all(controller->dma_rx);
-		return -EINVAL;
-	}
+	if (!desc_tx)
+		goto dmaengine_terminate_rx;
 
 	desc_tx->callback = spi_imx_dma_tx_callback;
 	desc_tx->callback_param = (void *)spi_imx;
-	dmaengine_submit(desc_tx);
+	cookie = dmaengine_submit(desc_tx);
+	if (dma_submit_error(cookie)) {
+		dev_err(spi_imx->dev, "submitting DMA TX failed\n");
+		goto dmaengine_terminate_tx;
+	}
 	reinit_completion(&spi_imx->dma_tx_completion);
 	dma_async_issue_pending(controller->dma_tx);
 
@@ -1502,6 +1511,13 @@ static int spi_imx_dma_submit(struct spi_imx_data *spi_imx,
 	}
 
 	return 0;
+
+dmaengine_terminate_tx:
+	dmaengine_terminate_all(controller->dma_tx);
+dmaengine_terminate_rx:
+	dmaengine_terminate_all(controller->dma_rx);
+
+	return -EINVAL;
 }
 
 static void spi_imx_dma_max_wml_find(struct spi_imx_data *spi_imx,
-- 
2.34.1



From carlos.song at nxp.com  Mon Dec  1 23:55:02 2025
From: carlos.song at nxp.com (Carlos Song)
Date: Tue,  2 Dec 2025 15:55:02 +0800
Subject: [PATCH v2 5/6] spi: imx: support dynamic burst length for ECSPI DMA mode
In-Reply-To: <20251202075503.2448339-1-carlos.song@nxp.com>
References: <20251202075503.2448339-1-carlos.song@nxp.com>
Message-ID: <20251202075503.2448339-6-carlos.song@nxp.com>

ECSPI transfers only one word per frame in DMA mode, causing SCLK stalls
between words due to BURST_LENGTH updates, which significantly impacts
performance.

To improve throughput, configure BURST_LENGTH as large as possible (up to
512 bytes per frame) instead of word length. This avoids delays between
words. When transfer length is not 4-byte aligned, use bounce buffers to
align data for DMA. TX uses aligned words for TXFIFO, while RX trims DMA
buffer data after transfer completion.

Introduce a new dma_package structure to store:
  1. BURST_LENGTH values for each DMA request
  2. Variables for DMA submission
  3. DMA transmission length and actual data length

Handle three cases:
  - len <= 512 bytes: one package, BURST_LENGTH = len * 8 - 1
  - len > 512 and aligned: one package, BURST_LENGTH = max (512 bytes)
  - len > 512 and unaligned: two packages, second for tail data

Performance test (spidev_test @10MHz, 4KB):
  Before: tx/rx ~6651.9 kbps
  After:  tx/rx ~9922.2 kbps (~50% improvement)

For compatibility with slow SPI devices, add configurable word delay in
DMA mode. When word delay is set, dynamic burst is disabled and
BURST_LENGTH equals word length.

Signed-off-by: Carlos Song <carlos.song at nxp.com>
---
 drivers/spi/spi-imx.c | 413 ++++++++++++++++++++++++++++++++++++++----
 1 file changed, 377 insertions(+), 36 deletions(-)

diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 42f64d9535c9..045f4ffd680a 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -60,6 +60,7 @@ MODULE_PARM_DESC(polling_limit_us,
 #define MX51_ECSPI_CTRL_MAX_BURST	512
 /* The maximum bytes that IMX53_ECSPI can transfer in target mode.*/
 #define MX53_MAX_TRANSFER_BYTES		512
+#define BYTES_PER_32BITS_WORD		4
 
 enum spi_imx_devtype {
 	IMX1_CSPI,
@@ -95,6 +96,16 @@ struct spi_imx_devtype_data {
 	enum spi_imx_devtype devtype;
 };
 
+struct dma_data_package {
+	u32 cmd_word;
+	void *dma_rx_buf;
+	void *dma_tx_buf;
+	dma_addr_t dma_tx_addr;
+	dma_addr_t dma_rx_addr;
+	int dma_len;
+	int data_len;
+};
+
 struct spi_imx_data {
 	struct spi_controller *controller;
 	struct device *dev;
@@ -130,6 +141,9 @@ struct spi_imx_data {
 	u32 wml;
 	struct completion dma_rx_completion;
 	struct completion dma_tx_completion;
+	size_t dma_package_num;
+	struct dma_data_package *dma_data __counted_by(dma_package_num);
+	int rx_offset;
 
 	const struct spi_imx_devtype_data *devtype_data;
 };
@@ -189,6 +203,9 @@ MXC_SPI_BUF_TX(u16)
 MXC_SPI_BUF_RX(u32)
 MXC_SPI_BUF_TX(u32)
 
+/* Align to cache line to avoid swiotlo bounce */
+#define DMA_CACHE_ALIGNED_LEN(x) ALIGN((x), dma_get_cache_alignment())
+
 /* First entry is reserved, second entry is valid only if SDHC_SPIEN is set
  * (which is currently not the case in this driver)
  */
@@ -253,6 +270,14 @@ static bool spi_imx_can_dma(struct spi_controller *controller, struct spi_device
 	if (transfer->len < spi_imx->devtype_data->fifo_size)
 		return false;
 
+	/* DMA only can transmit data in bytes */
+	if (spi_imx->bits_per_word != 8 && spi_imx->bits_per_word != 16 &&
+	    spi_imx->bits_per_word != 32)
+		return false;
+
+	if (transfer->len >= MAX_SDMA_BD_BYTES)
+		return false;
+
 	spi_imx->dynamic_burst = 0;
 
 	return true;
@@ -1398,8 +1423,6 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
 
 	init_completion(&spi_imx->dma_rx_completion);
 	init_completion(&spi_imx->dma_tx_completion);
-	controller->can_dma = spi_imx_can_dma;
-	controller->max_dma_len = MAX_SDMA_BD_BYTES;
 	spi_imx->controller->flags = SPI_CONTROLLER_MUST_RX |
 					 SPI_CONTROLLER_MUST_TX;
 
@@ -1437,10 +1460,259 @@ static int spi_imx_calculate_timeout(struct spi_imx_data *spi_imx, int size)
 	return secs_to_jiffies(2 * timeout);
 }
 
+static void spi_imx_dma_unmap(struct spi_imx_data *spi_imx,
+			      struct dma_data_package *dma_data)
+{
+	struct device *tx_dev = spi_imx->controller->dma_tx->device->dev;
+	struct device *rx_dev = spi_imx->controller->dma_rx->device->dev;
+
+	dma_unmap_single(tx_dev, dma_data->dma_tx_addr,
+			 DMA_CACHE_ALIGNED_LEN(dma_data->dma_len),
+			 DMA_TO_DEVICE);
+	dma_unmap_single(rx_dev, dma_data->dma_rx_addr,
+			 DMA_CACHE_ALIGNED_LEN(dma_data->dma_len),
+			 DMA_FROM_DEVICE);
+}
+
+static void spi_imx_dma_rx_data_handle(struct spi_imx_data *spi_imx,
+				       struct dma_data_package *dma_data, void *rx_buf,
+				       bool word_delay)
+{
+	void *copy_ptr;
+	int unaligned;
+
+	/*
+	 * On little-endian CPUs, adjust byte order:
+	 * - Swap bytes when bpw = 8
+	 * - Swap half-words when bpw = 16
+	 * This ensures correct data ordering for DMA transfers.
+	 */
+#ifdef __LITTLE_ENDIAN
+	if (!word_delay) {
+		unsigned int bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
+		u32 *temp = dma_data->dma_rx_buf;
+
+		for (int i = 0; i < DIV_ROUND_UP(dma_data->dma_len, sizeof(*temp)); i++) {
+			if (bytes_per_word == 1)
+				swab32s(temp + i);
+			else if (bytes_per_word == 2)
+				swahw32s(temp + i);
+		}
+	}
+#endif
+
+	/*
+	 * When dynamic burst enabled, DMA RX always receives 32-bit words from RXFIFO with
+	 * buswidth = 4, but when data_len is not 4-bytes alignment, the RM shows when
+	 * burst length = 32*n + m bits, a SPI burst contains the m LSB in first word and all
+	 * 32 bits in other n words. So if garbage bytes in the first word, trim first word then
+	 * copy the actual data to rx_buf.
+	 */
+	if (dma_data->data_len % BYTES_PER_32BITS_WORD && !word_delay) {
+		unaligned = dma_data->data_len % BYTES_PER_32BITS_WORD;
+		copy_ptr = (u8 *)dma_data->dma_rx_buf + BYTES_PER_32BITS_WORD - unaligned;
+	} else {
+		copy_ptr = dma_data->dma_rx_buf;
+	}
+
+	memcpy(rx_buf, copy_ptr, dma_data->data_len);
+}
+
+static int spi_imx_dma_map(struct spi_imx_data *spi_imx,
+			   struct dma_data_package *dma_data)
+{
+	struct spi_controller *controller = spi_imx->controller;
+	struct device *tx_dev = controller->dma_tx->device->dev;
+	struct device *rx_dev = controller->dma_rx->device->dev;
+	int ret;
+
+	dma_data->dma_tx_addr = dma_map_single(tx_dev, dma_data->dma_tx_buf,
+					       DMA_CACHE_ALIGNED_LEN(dma_data->dma_len),
+					       DMA_TO_DEVICE);
+	ret = dma_mapping_error(tx_dev, dma_data->dma_tx_addr);
+	if (ret < 0) {
+		dev_err(spi_imx->dev, "DMA TX map failed %d\n", ret);
+		return ret;
+	}
+
+	dma_data->dma_rx_addr = dma_map_single(rx_dev, dma_data->dma_rx_buf,
+					       DMA_CACHE_ALIGNED_LEN(dma_data->dma_len),
+					       DMA_FROM_DEVICE);
+	ret = dma_mapping_error(rx_dev, dma_data->dma_rx_addr);
+	if (ret < 0) {
+		dev_err(spi_imx->dev, "DMA RX map failed %d\n", ret);
+		dma_unmap_single(tx_dev, dma_data->dma_tx_addr,
+				 DMA_CACHE_ALIGNED_LEN(dma_data->dma_len),
+				 DMA_TO_DEVICE);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int spi_imx_dma_tx_data_handle(struct spi_imx_data *spi_imx,
+				      struct dma_data_package *dma_data,
+				      const void *tx_buf,
+				      bool word_delay)
+{
+	void *copy_ptr;
+	int unaligned;
+
+	if (word_delay) {
+		dma_data->dma_len = dma_data->data_len;
+	} else {
+		/*
+		 * As per the reference manual, when burst length = 32*n + m bits, ECSPI
+		 * sends m LSB bits in the first word, followed by n full 32-bit words.
+		 * Since actual data may not be 4-byte aligned, allocate DMA TX/RX buffers
+		 * to ensure alignment. For TX, DMA pushes 4-byte aligned words to TXFIFO,
+		 * while ECSPI uses BURST_LENGTH settings to maintain correct bit count.
+		 * For RX, DMA always receives 32-bit words from RXFIFO, when data len is
+		 * not 4-byte aligned, trim the first word to drop garbage bytes, then group
+		 * all transfer DMA bounse buffer and copy all valid data to rx_buf.
+		 */
+		dma_data->dma_len = ALIGN(dma_data->data_len, BYTES_PER_32BITS_WORD);
+	}
+
+	dma_data->dma_tx_buf = kzalloc(dma_data->dma_len, GFP_KERNEL);
+	if (!dma_data->dma_tx_buf)
+		return -ENOMEM;
+
+	dma_data->dma_rx_buf = kzalloc(dma_data->dma_len, GFP_KERNEL);
+	if (!dma_data->dma_rx_buf) {
+		kfree(dma_data->dma_tx_buf);
+		return -ENOMEM;
+	}
+
+	if (dma_data->data_len % BYTES_PER_32BITS_WORD && !word_delay) {
+		unaligned = dma_data->data_len % BYTES_PER_32BITS_WORD;
+		copy_ptr = (u8 *)dma_data->dma_tx_buf + BYTES_PER_32BITS_WORD - unaligned;
+	} else {
+		copy_ptr = dma_data->dma_tx_buf;
+	}
+
+	memcpy(copy_ptr, tx_buf, dma_data->data_len);
+
+	/*
+	 * When word_delay is enabled, DMA transfers an entire word in one minor loop.
+	 * In this case, no data requires additional handling.
+	 */
+	if (word_delay)
+		return 0;
+
+#ifdef __LITTLE_ENDIAN
+	/*
+	 * On little-endian CPUs, adjust byte order:
+	 * - Swap bytes when bpw = 8
+	 * - Swap half-words when bpw = 16
+	 * This ensures correct data ordering for DMA transfers.
+	 */
+	unsigned int bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
+	u32 *temp = dma_data->dma_tx_buf;
+
+	for (int i = 0; i < DIV_ROUND_UP(dma_data->dma_len, sizeof(*temp)); i++) {
+		if (bytes_per_word == 1)
+			swab32s(temp + i);
+		else if (bytes_per_word == 2)
+			swahw32s(temp + i);
+	}
+#endif
+
+	return 0;
+}
+
+static int spi_imx_dma_data_prepare(struct spi_imx_data *spi_imx,
+				    struct spi_transfer *transfer,
+				    bool word_delay)
+{
+	u32 pre_bl, tail_bl;
+	u32 ctrl;
+	int ret;
+
+	/*
+	 * ECSPI supports a maximum burst of 512 bytes. When xfer->len exceeds 512
+	 * and is not a multiple of 512, a tail transfer is required. BURST_LEGTH
+	 * is used for SPI HW to maintain correct bit count. BURST_LENGTH should
+	 * update with data length. After DMA request submit, SPI can not update the
+	 * BURST_LENGTH, in this case, we must split two package, update the register
+	 * then setup second DMA transfer.
+	 */
+	ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL);
+	if (word_delay) {
+		/*
+		 * When SPI IMX need to support word delay, according to "Sample Period Control
+		 * Register" shows, The Sample Period Control Register (ECSPI_PERIODREG)
+		 * provides software a way to insert delays (wait states) between consecutive
+		 * SPI transfers. As a result, ECSPI can only transfer one word per frame, and
+		 * the delay occurs between frames.
+		 */
+		spi_imx->dma_package_num = 1;
+		pre_bl = spi_imx->bits_per_word - 1;
+	} else if (transfer->len <= MX51_ECSPI_CTRL_MAX_BURST) {
+		spi_imx->dma_package_num = 1;
+		pre_bl = transfer->len * BITS_PER_BYTE - 1;
+	} else if (!(transfer->len % MX51_ECSPI_CTRL_MAX_BURST)) {
+		spi_imx->dma_package_num = 1;
+		pre_bl = MX51_ECSPI_CTRL_MAX_BURST * BITS_PER_BYTE - 1;
+	} else {
+		spi_imx->dma_package_num = 2;
+		pre_bl = MX51_ECSPI_CTRL_MAX_BURST * BITS_PER_BYTE - 1;
+		tail_bl = (transfer->len % MX51_ECSPI_CTRL_MAX_BURST) * BITS_PER_BYTE - 1;
+	}
+
+	spi_imx->dma_data = kmalloc_array(spi_imx->dma_package_num,
+					  sizeof(struct dma_data_package),
+					  GFP_KERNEL | __GFP_ZERO);
+	if (!spi_imx->dma_data) {
+		dev_err(spi_imx->dev, "Failed to allocate DMA package buffer!\n");
+		return -ENOMEM;
+	}
+
+	if (spi_imx->dma_package_num == 1) {
+		ctrl &= ~MX51_ECSPI_CTRL_BL_MASK;
+		ctrl |= pre_bl << MX51_ECSPI_CTRL_BL_OFFSET;
+		spi_imx->dma_data[0].cmd_word = ctrl;
+		spi_imx->dma_data[0].data_len = transfer->len;
+		ret = spi_imx_dma_tx_data_handle(spi_imx, &spi_imx->dma_data[0], transfer->tx_buf,
+						 word_delay);
+		if (ret) {
+			kfree(spi_imx->dma_data);
+			return ret;
+		}
+	} else {
+		ctrl &= ~MX51_ECSPI_CTRL_BL_MASK;
+		ctrl |= pre_bl << MX51_ECSPI_CTRL_BL_OFFSET;
+		spi_imx->dma_data[0].cmd_word = ctrl;
+		spi_imx->dma_data[0].data_len = round_down(transfer->len,
+							   MX51_ECSPI_CTRL_MAX_BURST);
+		ret = spi_imx_dma_tx_data_handle(spi_imx, &spi_imx->dma_data[0], transfer->tx_buf,
+						 false);
+		if (ret) {
+			kfree(spi_imx->dma_data);
+			return ret;
+		}
+
+		ctrl &= ~MX51_ECSPI_CTRL_BL_MASK;
+		ctrl |= tail_bl << MX51_ECSPI_CTRL_BL_OFFSET;
+		spi_imx->dma_data[1].cmd_word = ctrl;
+		spi_imx->dma_data[1].data_len = transfer->len % MX51_ECSPI_CTRL_MAX_BURST;
+		ret = spi_imx_dma_tx_data_handle(spi_imx, &spi_imx->dma_data[1],
+						 transfer->tx_buf + spi_imx->dma_data[0].data_len,
+						 false);
+		if (ret) {
+			kfree(spi_imx->dma_data[0].dma_tx_buf);
+			kfree(spi_imx->dma_data[0].dma_rx_buf);
+			kfree(spi_imx->dma_data);
+		}
+	}
+
+	return 0;
+}
+
 static int spi_imx_dma_submit(struct spi_imx_data *spi_imx,
+			      struct dma_data_package *dma_data,
 			      struct spi_transfer *transfer)
 {
-	struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg;
 	struct spi_controller *controller = spi_imx->controller;
 	struct dma_async_tx_descriptor *desc_tx, *desc_rx;
 	unsigned long transfer_timeout;
@@ -1451,9 +1723,9 @@ static int spi_imx_dma_submit(struct spi_imx_data *spi_imx,
 	 * The TX DMA setup starts the transfer, so make sure RX is configured
 	 * before TX.
 	 */
-	desc_rx = dmaengine_prep_slave_sg(controller->dma_rx,
-					  rx->sgl, rx->nents, DMA_DEV_TO_MEM,
-					  DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	desc_rx = dmaengine_prep_slave_single(controller->dma_rx, dma_data->dma_rx_addr,
+					      dma_data->dma_len, DMA_DEV_TO_MEM,
+					      DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!desc_rx) {
 		transfer->error |= SPI_TRANS_FAIL_NO_START;
 		return -EINVAL;
@@ -1471,9 +1743,9 @@ static int spi_imx_dma_submit(struct spi_imx_data *spi_imx,
 	reinit_completion(&spi_imx->dma_rx_completion);
 	dma_async_issue_pending(controller->dma_rx);
 
-	desc_tx = dmaengine_prep_slave_sg(controller->dma_tx,
-					  tx->sgl, tx->nents, DMA_MEM_TO_DEV,
-					  DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	desc_tx = dmaengine_prep_slave_single(controller->dma_tx, dma_data->dma_tx_addr,
+					      dma_data->dma_len, DMA_MEM_TO_DEV,
+					      DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!desc_tx)
 		goto dmaengine_terminate_rx;
 
@@ -1521,16 +1793,16 @@ static int spi_imx_dma_submit(struct spi_imx_data *spi_imx,
 }
 
 static void spi_imx_dma_max_wml_find(struct spi_imx_data *spi_imx,
-				     struct spi_transfer *transfer)
+				     struct dma_data_package *dma_data,
+				     bool word_delay)
 {
-	struct sg_table *rx = &transfer->rx_sg;
-	struct scatterlist *last_sg = sg_last(rx->sgl, rx->nents);
-	unsigned int bytes_per_word, i;
+	unsigned int bytes_per_word = word_delay ?
+				      spi_imx_bytes_per_word(spi_imx->bits_per_word) :
+				      BYTES_PER_32BITS_WORD;
+	unsigned int i;
 
-	/* Get the right burst length from the last sg to ensure no tail data */
-	bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word);
 	for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) {
-		if (!(sg_dma_len(last_sg) % (i * bytes_per_word)))
+		if (!dma_data->dma_len % (i * bytes_per_word))
 			break;
 	}
 	/* Use 1 as wml in case no available burst length got */
@@ -1540,25 +1812,29 @@ static void spi_imx_dma_max_wml_find(struct spi_imx_data *spi_imx,
 	spi_imx->wml = i;
 }
 
-static int spi_imx_dma_configure(struct spi_controller *controller)
+static int spi_imx_dma_configure(struct spi_controller *controller, bool word_delay)
 {
 	int ret;
 	enum dma_slave_buswidth buswidth;
 	struct dma_slave_config rx = {}, tx = {};
 	struct spi_imx_data *spi_imx = spi_controller_get_devdata(controller);
 
-	switch (spi_imx_bytes_per_word(spi_imx->bits_per_word)) {
-	case 4:
+	if (word_delay) {
+		switch (spi_imx_bytes_per_word(spi_imx->bits_per_word)) {
+		case 4:
+			buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
+			break;
+		case 2:
+			buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
+			break;
+		case 1:
+			buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else {
 		buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
-		break;
-	case 2:
-		buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
-		break;
-	case 1:
-		buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
-		break;
-	default:
-		return -EINVAL;
 	}
 
 	tx.direction = DMA_MEM_TO_DEV;
@@ -1584,15 +1860,17 @@ static int spi_imx_dma_configure(struct spi_controller *controller)
 	return 0;
 }
 
-static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
-				struct spi_transfer *transfer)
+static int spi_imx_dma_package_transfer(struct spi_imx_data *spi_imx,
+					struct dma_data_package *dma_data,
+					struct spi_transfer *transfer,
+					bool word_delay)
 {
 	struct spi_controller *controller = spi_imx->controller;
 	int ret;
 
-	spi_imx_dma_max_wml_find(spi_imx, transfer);
+	spi_imx_dma_max_wml_find(spi_imx, dma_data, word_delay);
 
-	ret = spi_imx_dma_configure(controller);
+	ret = spi_imx_dma_configure(controller, word_delay);
 	if (ret)
 		goto dma_failure_no_start;
 
@@ -1603,10 +1881,17 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
 	}
 	spi_imx->devtype_data->setup_wml(spi_imx);
 
-	ret = spi_imx_dma_submit(spi_imx, transfer);
+	ret = spi_imx_dma_submit(spi_imx, dma_data, transfer);
 	if (ret)
 		return ret;
 
+	/* Trim the DMA RX buffer and copy the actual data to rx_buf */
+	dma_sync_single_for_cpu(controller->dma_rx->device->dev, dma_data->dma_rx_addr,
+				dma_data->dma_len, DMA_FROM_DEVICE);
+	spi_imx_dma_rx_data_handle(spi_imx, dma_data, transfer->rx_buf + spi_imx->rx_offset,
+				   word_delay);
+	spi_imx->rx_offset += dma_data->data_len;
+
 	return 0;
 /* fallback to pio */
 dma_failure_no_start:
@@ -1614,6 +1899,57 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
 	return ret;
 }
 
+static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
+				struct spi_transfer *transfer)
+{
+	bool word_delay = transfer->word_delay.value != 0;
+	int ret;
+	int i;
+
+	ret = spi_imx_dma_data_prepare(spi_imx, transfer, word_delay);
+	if (ret < 0) {
+		transfer->error |= SPI_TRANS_FAIL_NO_START;
+		dev_err(spi_imx->dev, "DMA data prepare fail\n");
+		goto fallback_pio;
+	}
+
+	spi_imx->rx_offset = 0;
+
+	/* Each dma_package performs a separate DMA transfer once */
+	for (i = 0; i < spi_imx->dma_package_num; i++) {
+		ret = spi_imx_dma_map(spi_imx, &spi_imx->dma_data[i]);
+		if (ret < 0) {
+			if (i == 0)
+				transfer->error |= SPI_TRANS_FAIL_NO_START;
+			dev_err(spi_imx->dev, "DMA map fail\n");
+			break;
+		}
+
+		/* Update the CTRL register BL field */
+		writel(spi_imx->dma_data[i].cmd_word, spi_imx->base + MX51_ECSPI_CTRL);
+
+		ret = spi_imx_dma_package_transfer(spi_imx, &spi_imx->dma_data[i],
+						   transfer, word_delay);
+
+		/* Whether the dma transmission is successful or not, dma unmap is necessary */
+		spi_imx_dma_unmap(spi_imx, &spi_imx->dma_data[i]);
+
+		if (ret < 0) {
+			dev_dbg(spi_imx->dev, "DMA %d transfer not really finish\n", i);
+			break;
+		}
+	}
+
+	for (int j = 0; j < spi_imx->dma_package_num; j++) {
+		kfree(spi_imx->dma_data[j].dma_tx_buf);
+		kfree(spi_imx->dma_data[j].dma_rx_buf);
+	}
+	kfree(spi_imx->dma_data);
+
+fallback_pio:
+	return ret;
+}
+
 static int spi_imx_pio_transfer(struct spi_device *spi,
 				struct spi_transfer *transfer)
 {
@@ -1780,9 +2116,14 @@ static int spi_imx_transfer_one(struct spi_controller *controller,
 	 * transfer, the SPI transfer has already been mapped, so we
 	 * have to do the DMA transfer here.
 	 */
-	if (spi_imx->usedma)
-		return spi_imx_dma_transfer(spi_imx, transfer);
-
+	if (spi_imx->usedma) {
+		ret = spi_imx_dma_transfer(spi_imx, transfer);
+		if (transfer->error & SPI_TRANS_FAIL_NO_START) {
+			spi_imx->usedma = false;
+			return spi_imx_pio_transfer(spi, transfer);
+		}
+		return ret;
+	}
 	/* run in polling mode for short transfers */
 	if (transfer->len == 1 || (polling_limit_us &&
 				   spi_imx_transfer_estimate_time_us(transfer) < polling_limit_us))
-- 
2.34.1



From carlos.song at nxp.com  Mon Dec  1 23:55:03 2025
From: carlos.song at nxp.com (Carlos Song)
Date: Tue,  2 Dec 2025 15:55:03 +0800
Subject: [PATCH v2 6/6] spi: imx: enable DMA mode for target operation
In-Reply-To: <20251202075503.2448339-1-carlos.song@nxp.com>
References: <20251202075503.2448339-1-carlos.song@nxp.com>
Message-ID: <20251202075503.2448339-7-carlos.song@nxp.com>

Enable DMA mode for SPI IMX in target mode. Disable the word delay feature
for target mode, because target mode should always keep high performance
to make sure it can follow the master. Target mode continues to operate in
dynamic burst mode.

Signed-off-by: Carlos Song <carlos.song at nxp.com>
---
 drivers/spi/spi-imx.c | 77 ++++++++++++++++++++++++++++++++-----------
 1 file changed, 57 insertions(+), 20 deletions(-)

diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 045f4ffd680a..e37d786a5276 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -264,7 +264,13 @@ static bool spi_imx_can_dma(struct spi_controller *controller, struct spi_device
 	if (!controller->dma_rx)
 		return false;
 
-	if (spi_imx->target_mode)
+	/*
+	 * Due to Freescale errata ERR003775 "eCSPI: Burst completion by Chip
+	 * Select (SS) signal in Slave mode is not functional" burst size must
+	 * be set exactly to the size of the transfer. This limit SPI transaction
+	 * with maximum 2^12 bits.
+	 */
+	if (transfer->len > MX53_MAX_TRANSFER_BYTES && spi_imx->target_mode)
 		return false;
 
 	if (transfer->len < spi_imx->devtype_data->fifo_size)
@@ -1763,23 +1769,51 @@ static int spi_imx_dma_submit(struct spi_imx_data *spi_imx,
 
 	transfer_timeout = spi_imx_calculate_timeout(spi_imx, transfer->len);
 
-	/* Wait SDMA to finish the data transfer.*/
-	time_left = wait_for_completion_timeout(&spi_imx->dma_tx_completion,
-						transfer_timeout);
-	if (!time_left) {
-		dev_err(spi_imx->dev, "I/O Error in DMA TX\n");
-		dmaengine_terminate_all(controller->dma_tx);
-		dmaengine_terminate_all(controller->dma_rx);
-		return -ETIMEDOUT;
-	}
+	if (!spi_imx->target_mode) {
+		/* Wait SDMA to finish the data transfer.*/
+		time_left = wait_for_completion_timeout(&spi_imx->dma_tx_completion,
+							transfer_timeout);
+		if (!time_left) {
+			dev_err(spi_imx->dev, "I/O Error in DMA TX\n");
+			dmaengine_terminate_all(controller->dma_tx);
+			dmaengine_terminate_all(controller->dma_rx);
+			return -ETIMEDOUT;
+		}
 
-	time_left = wait_for_completion_timeout(&spi_imx->dma_rx_completion,
-						transfer_timeout);
-	if (!time_left) {
-		dev_err(&controller->dev, "I/O Error in DMA RX\n");
-		spi_imx->devtype_data->reset(spi_imx);
-		dmaengine_terminate_all(controller->dma_rx);
-		return -ETIMEDOUT;
+		time_left = wait_for_completion_timeout(&spi_imx->dma_rx_completion,
+							transfer_timeout);
+		if (!time_left) {
+			dev_err(&controller->dev, "I/O Error in DMA RX\n");
+			spi_imx->devtype_data->reset(spi_imx);
+			dmaengine_terminate_all(controller->dma_rx);
+			return -ETIMEDOUT;
+		}
+	} else {
+		spi_imx->target_aborted = false;
+
+		if (wait_for_completion_interruptible(&spi_imx->dma_tx_completion) ||
+		    READ_ONCE(spi_imx->target_aborted)) {
+			dev_dbg(spi_imx->dev, "I/O Error in DMA TX interrupted\n");
+			dmaengine_terminate_all(controller->dma_tx);
+			dmaengine_terminate_all(controller->dma_rx);
+			return -EINTR;
+		}
+
+		if (wait_for_completion_interruptible(&spi_imx->dma_rx_completion) ||
+		    READ_ONCE(spi_imx->target_aborted)) {
+			dev_dbg(spi_imx->dev, "I/O Error in DMA RX interrupted\n");
+			dmaengine_terminate_all(controller->dma_rx);
+			return -EINTR;
+		}
+
+		/*
+		 * ECSPI has a HW issue when works in Target mode, after 64 words
+		 * writtern to TXFIFO, even TXFIFO becomes empty, ECSPI_TXDATA keeps
+		 * shift out the last word data, so we have to disable ECSPI when in
+		 * target mode after the transfer completes.
+		 */
+		if (spi_imx->devtype_data->disable)
+			spi_imx->devtype_data->disable(spi_imx);
 	}
 
 	return 0;
@@ -1902,7 +1936,7 @@ static int spi_imx_dma_package_transfer(struct spi_imx_data *spi_imx,
 static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
 				struct spi_transfer *transfer)
 {
-	bool word_delay = transfer->word_delay.value != 0;
+	bool word_delay = transfer->word_delay.value != 0 && !spi_imx->target_mode;
 	int ret;
 	int i;
 
@@ -2108,7 +2142,7 @@ static int spi_imx_transfer_one(struct spi_controller *controller,
 	while (spi_imx->devtype_data->rx_available(spi_imx))
 		readl(spi_imx->base + MXC_CSPIRXDATA);
 
-	if (spi_imx->target_mode)
+	if (spi_imx->target_mode && !spi_imx->usedma)
 		return spi_imx_pio_transfer_target(spi, transfer);
 
 	/*
@@ -2120,7 +2154,10 @@ static int spi_imx_transfer_one(struct spi_controller *controller,
 		ret = spi_imx_dma_transfer(spi_imx, transfer);
 		if (transfer->error & SPI_TRANS_FAIL_NO_START) {
 			spi_imx->usedma = false;
-			return spi_imx_pio_transfer(spi, transfer);
+			if (spi_imx->target_mode)
+				return spi_imx_pio_transfer_target(spi, transfer);
+			else
+				return spi_imx_pio_transfer(spi, transfer);
 		}
 		return ret;
 	}
-- 
2.34.1



From jianpeng.chang.cn at windriver.com  Mon Dec  1 23:55:48 2025
From: jianpeng.chang.cn at windriver.com (Jianpeng Chang)
Date: Tue, 2 Dec 2025 15:55:48 +0800
Subject: [v2 PATCH] arm64: mm: Fix kexec failure after pte_mkwrite_novma()
 change
In-Reply-To: <381a3974-aafa-419f-a7ad-ed6e4c1671f0@arm.com>
References: <20251202022707.2720933-1-jianpeng.chang.cn@windriver.com>
 <381a3974-aafa-419f-a7ad-ed6e4c1671f0@arm.com>
Message-ID: <58d796ec-b430-4fc0-9a1c-8f1a6150f051@windriver.com>


On 12/2/25 2:57 PM, Anshuman Khandual wrote:
> CAUTION: This email comes from a non Wind River email account!
> Do not click links or open attachments unless you recognize the sender and know the content is safe.
>
> On 02/12/25 7:57 AM, Jianpeng Chang wrote:
>> Commit 143937ca51cc ("arm64, mm: avoid always making PTE dirty in
>> pte_mkwrite()") modified pte_mkwrite_novma() to only clear PTE_RDONLY
>> when the page is already dirty (PTE_DIRTY is set). While this optimization
>> prevents unnecessary dirty page marking in normal memory management paths,
>> it breaks kexec on some platforms like NXP LS1043.
>>
>> The issue occurs in the kexec code path:
>> 1. machine_kexec_post_load() calls trans_pgd_create_copy() to create a
>>    writable copy of the linear mapping
>> 2. _copy_pte() calls pte_mkwrite_novma() to ensure all pages in the copy
>>    are writable for the new kernel image copying
>> 3. With the new logic, clean pages (without PTE_DIRTY) remain read-only
>> 4. When kexec tries to copy the new kernel image through the linear
>>    mapping, it fails on read-only pages, causing the system to hang
>>    after "Bye!"
>>
>> The same issue affects hibernation which uses the same trans_pgd code path.
>>
>> Fix this by explicitly clearing PTE_RDONLY in _copy_pte() for both
> via pte_mkdirty() ?
Sorry, for this.

Fix this by marking pages dirty with pte_mkdirty() in _copy_pte(), which
ensures pte_mkwrite_novma() clears PTE_RDONLY for both kexec and
hibernation, making all pages in the temporary mapping writable
regardless of their dirty state.
>
>> kexec and hibernation, ensuring all pages in the temporary mapping are
>> writable regardless of their dirty state. This preserves the original
>> commit's optimization for normal memory management while fixing the
>> kexec/hibernation regression.
>>
>> Fixes: 143937ca51cc ("arm64, mm: avoid always making PTE dirty in pte_mkwrite()")
>> Signed-off-by: Jianpeng Chang <jianpeng.chang.cn at windriver.com>
>> ---
>> v2:
>>   - Use pte_mkwrite_novma(pte_mkdirty(pte)) instead of manual bit manipulation
>>   - Updated comments to clarify pte_mkwrite_novma() alone cannot be used
>> v1: https://lore.kernel.org/all/20251127034350.3600454-1-jianpeng.chang.cn at windriver.com/
>>
>>  arch/arm64/mm/trans_pgd.c | 9 +++++++--
>>  1 file changed, 7 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/arm64/mm/trans_pgd.c b/arch/arm64/mm/trans_pgd.c
>> index 18543b603c77..08f5ee6643e1 100644
>> --- a/arch/arm64/mm/trans_pgd.c
>> +++ b/arch/arm64/mm/trans_pgd.c
>> @@ -40,8 +40,13 @@ static void _copy_pte(pte_t *dst_ptep, pte_t *src_ptep, unsigned long addr)
>>                * Resume will overwrite areas that may be marked
>>                * read only (code, rodata). Clear the RDONLY bit from
>>                * the temporary mappings we use during restore.
>> +              *
>> +              * For kexec/hibernation, we need writable access to all
>> +              * pages in the linear mapping to copy the new kernel image.
>> +              * Mark pages dirty first to ensure pte_mkwrite_novma()
>> +              * clears PTE_RDONLY.
>>                */
>                /*
>                 * For both kexec and hibernation, writable accesses are required
>                 * for all pages in the linear map to copy over new kernel image.
>                 * Hence mark these pages dirty first via pte_mkdirty() to ensure
>                 * pte_mkwrite_novma() subsequently clears PTE_RDONLY - providing
>                 * required write access for the pages.
>                 */
I will change it.
>
>> -             __set_pte(dst_ptep, pte_mkwrite_novma(pte));
>> +             __set_pte(dst_ptep, pte_mkwrite_novma(pte_mkdirty(pte)));
>>       } else if (!pte_none(pte)) {
>>               /*
>>                * debug_pagealloc will removed the PTE_VALID bit if
>> @@ -57,7 +62,7 @@ static void _copy_pte(pte_t *dst_ptep, pte_t *src_ptep, unsigned long addr)
>>                */
>>               BUG_ON(!pfn_valid(pte_pfn(pte)));
>>
> The comments should be replicated here as well given the same special situation.
I will change it.
>
>> -             __set_pte(dst_ptep, pte_mkvalid(pte_mkwrite_novma(pte)));
>> +             __set_pte(dst_ptep, pte_mkvalid(pte_mkwrite_novma(pte_mkdirty(pte))));
>>       }
>>  }
>>
> static inline pte_t pte_mkwrite_novma(pte_t pte)
> {
>         pte = set_pte_bit(pte, __pgprot(PTE_WRITE));
>         if (pte_sw_dirty(pte))
>                 pte = clear_pte_bit(pte, __pgprot(PTE_RDONLY));
>         return pte;
> }
>
> static inline pte_t pte_mkdirty(pte_t pte)
> {
>         pte = set_pte_bit(pte, __pgprot(PTE_DIRTY));
>
>         if (pte_write(pte))
>                 pte = clear_pte_bit(pte, __pgprot(PTE_RDONLY));
>
>         return pte;
> }
>
> So if pte_write() is true, there will be a redundant PTE_RDONLY clearing which is OK.
> Should this be mentioned in the commit message ?
TBH, I don't have a better idea - any suggestions?

Or, let's add some lines:

Using pte_mkdirty() causes redundant bit operations, but this is
acceptable since it's not a hot path.


From m.felsch at pengutronix.de  Mon Dec  1 23:57:23 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Tue, 2 Dec 2025 08:57:23 +0100
Subject: [PATCH 2/3] pmdomain: imx93-blk-ctrl: convert to devm_* only
In-Reply-To: <aS4ZpyhrJ1IpUCKv@lizhi-Precision-Tower-5810>
References: <20251201-v6-18-topic-imx93-blkctrl-v1-0-b57a72e60105@pengutronix.de>
 <20251201-v6-18-topic-imx93-blkctrl-v1-2-b57a72e60105@pengutronix.de>
 <aS4ZpyhrJ1IpUCKv@lizhi-Precision-Tower-5810>
Message-ID: <20251202075723.myevt4wa2kpyehdd@pengutronix.de>

On 25-12-01, Frank Li wrote:
> On Mon, Dec 01, 2025 at 06:12:06PM +0100, Marco Felsch wrote:
> > Some APIs used by this driver don't have devm_ helpers yet. Instead of
> > using the devm_add_action_or_reset() the current driver is based on hand
> > crafted error goto paths and a .remove() callback.
> >
> > Convert the driver to devm_ APIs only by making use of
> > devm_add_action_or_reset() and devm_pm_runtime_enable() to simplify the
> > release and error path.
> 
> Nit: I think keep this paragaph should be enough.

I can re-phrase it.

> > Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
> > ---
> >  drivers/pmdomain/imx/imx93-blk-ctrl.c | 64 +++++++++++++++--------------------
> >  1 file changed, 27 insertions(+), 37 deletions(-)
> >
> > diff --git a/drivers/pmdomain/imx/imx93-blk-ctrl.c b/drivers/pmdomain/imx/imx93-blk-ctrl.c
> > index 2aa163aef8de4ee901b9cde76ce2aad246c8c08a..13b0de6dd689cf944e034f7666a4e97b0118e3bd 100644
> > --- a/drivers/pmdomain/imx/imx93-blk-ctrl.c
> > +++ b/drivers/pmdomain/imx/imx93-blk-ctrl.c
> > @@ -188,6 +188,20 @@ static int imx93_blk_ctrl_power_off(struct generic_pm_domain *genpd)
> >  	return 0;
> >  }
> >
> ...
> >  static struct lock_class_key blk_ctrl_genpd_lock_class;
> >
> >  static int imx93_blk_ctrl_probe(struct platform_device *pdev)
> > @@ -256,10 +270,8 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
> >  			domain->clks[j].id = data->clk_names[j];
> >
> >  		ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks);
> > -		if (ret) {
> > -			dev_err_probe(dev, ret, "failed to get clock\n");
> > -			goto cleanup_pds;
> > -		}
> > +		if (ret)
> > +			return dev_err_probe(dev, ret, "failed to get clock\n");
> >
> >  		domain->genpd.name = data->name;
> >  		domain->genpd.power_on = imx93_blk_ctrl_power_on;
> > @@ -267,11 +279,12 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
> >  		domain->bc = bc;
> >
> >  		ret = pm_genpd_init(&domain->genpd, NULL, true);
> > -		if (ret) {
> > -			dev_err_probe(dev, ret, "failed to init power domain\n");
> > -			goto cleanup_pds;
> > -		}
> > +		if (ret)
> > +			return dev_err_probe(dev, ret, "failed to init power domain\n");
> >
> > +		ret = devm_add_action_or_reset(dev, imx93_release_pm_genpd, &domain->genpd);
> > +		if (ret)
> > +			return dev_err_probe(dev, ret, "failed to add pm_genpd release callback\n");
> >  		/*
> >  		 * We use runtime PM to trigger power on/off of the upstream GPC
> >  		 * domain, as a strict hierarchical parent/child power domain
> > @@ -288,39 +301,17 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
> >  		bc->onecell_data.domains[i] = &domain->genpd;
> >  	}
> >
> > -	pm_runtime_enable(dev);
> > +	devm_pm_runtime_enable(dev);
> 
> Need check return value

Missed this one, thanks.

> >  	ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data);
> > -	if (ret) {
> > -		dev_err_probe(dev, ret, "failed to add power domain provider\n");
> > -		goto cleanup_pds;
> > -	}
> > +	if (ret)
> > +		return dev_err_probe(dev, ret, "failed to add power domain provider\n");
> >
> > -	dev_set_drvdata(dev, bc);
> 
> why remove dev_set_drvdata(dev, bc)

Because it's no longer needed, it was required due to the .remove()
callback. I wasn't sure if I should mention this within the commit
message. I'm going to add it to the commit message since you asked.

Regards,
  Marco

> 
> Frank
> > +	ret = devm_add_action_or_reset(dev, imx93_release_genpd_provider, dev->of_node);
> > +	if (ret)
> > +		return dev_err_probe(dev, ret, "failed to add genpd_provider release callback\n");
> >
> >  	return 0;
> > -
> > -cleanup_pds:
> > -	for (i--; i >= 0; i--)
> > -		pm_genpd_remove(&bc->domains[i].genpd);
> > -
> > -	return ret;
> > -}
> > -
> > -static void imx93_blk_ctrl_remove(struct platform_device *pdev)
> > -{
> > -	struct imx93_blk_ctrl *bc = dev_get_drvdata(&pdev->dev);
> > -	int i;
> > -
> > -	of_genpd_del_provider(pdev->dev.of_node);
> > -
> > -	pm_runtime_disable(&pdev->dev);
> > -
> > -	for (i = 0; i < bc->onecell_data.num_domains; i++) {
> > -		struct imx93_blk_ctrl_domain *domain = &bc->domains[i];
> > -
> > -		pm_genpd_remove(&domain->genpd);
> > -	}
> >  }
> >
> >  static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] = {
> > @@ -455,7 +446,6 @@ MODULE_DEVICE_TABLE(of, imx93_blk_ctrl_of_match);
> >
> >  static struct platform_driver imx93_blk_ctrl_driver = {
> >  	.probe = imx93_blk_ctrl_probe,
> > -	.remove = imx93_blk_ctrl_remove,
> >  	.driver = {
> >  		.name = "imx93-blk-ctrl",
> >  		.of_match_table = imx93_blk_ctrl_of_match,
> >
> > --
> > 2.47.3
> >
> 

-- 
#gernperDu 
#CallMeByMyFirstName

Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | https://www.pengutronix.de/ |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-9    |


From Hanchien.Lin at mediatek.com  Tue Dec  2 00:02:07 2025
From: Hanchien.Lin at mediatek.com (=?big5?B?SGFuY2hpZW4gTGluICiqTL+rwb4p?=)
Date: Tue, 2 Dec 2025 08:02:07 +0000
Subject: [PATCH 1/2] arm64: dts: mediatek: mt8189: Add thermal controller
 node
In-Reply-To: <20251110-vagueness-waggle-50b8efe728a8@spud>
References: <20251110094113.3965182-1-hanchien.lin@mediatek.com>
 <20251110094113.3965182-2-hanchien.lin@mediatek.com>
 <20251110-vagueness-waggle-50b8efe728a8@spud>
Message-ID: <TY2PPF3CC6FBD4C175126F814E558772D20E0D8A@TY2PPF3CC6FBD4C.apcprd03.prod.outlook.com>

Hi Conor,

Thanks for your feedback. Sorry for overlooking this part. I will update the patch subject and include the missing content in v3.

Best regards,
Hanchien Lin.

-----Original Message-----
From: Conor Dooley <conor at kernel.org> 
Sent: Tuesday, November 11, 2025 2:45 AM
To: Hanchien Lin (???) <Hanchien.Lin at mediatek.com>
Cc: Rafael J . Wysocki <rafael at kernel.org>; Daniel Lezcano <daniel.lezcano at linaro.org>; Zhang Rui <rui.zhang at intel.com>; Lukasz Luba <lukasz.luba at arm.com>; Rob Herring <robh at kernel.org>; Krzysztof Kozlowski <krzk+dt at kernel.org>; Conor Dooley <conor+dt at kernel.org>; Philipp Zabel <p.zabel at pengutronix.de>; Matthias Brugger <matthias.bgg at gmail.com>; AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>; Balsam CHIHI <bchihi at baylibre.com>; linux-pm at vger.kernel.org; devicetree at vger.kernel.org; linux-kernel at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux-mediatek at lists.infradead.org; Project_Global_Chrome_Upstream_Group <Project_Global_Chrome_Upstream_Group at mediatek.com>; Raymond Sun (???) <Raymond.Sun at mediatek.com>; Irving-CH Lin (???) <Irving-CH.Lin at mediatek.com>
Subject: Re: [PATCH 1/2] arm64: dts: mediatek: mt8189: Add thermal controller node

On Mon, Nov 10, 2025 at 05:40:38PM +0800, Hanchien Lin wrote:
> Add device tree node for the thermal controller on MediaTek MT8189 SoC.

$subject is incorrect for a binding change.
pw-bot: changes-requested

> 
> Signed-off-by: Hanchien Lin <hanchien.lin at mediatek.com>
> ---
>  .../thermal/mediatek,lvts-thermal.yaml        | 27 +++++++++++++++++--
>  .../thermal/mediatek,lvts-thermal.h           | 20 ++++++++++++++
>  2 files changed, 45 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml b/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml
> index 0259cd3ce9c5..0f7fd69f5fdf 100644
> --- a/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml
> +++ b/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml
> @@ -22,6 +22,8 @@ properties:
>        - mediatek,mt8186-lvts
>        - mediatek,mt8188-lvts-ap
>        - mediatek,mt8188-lvts-mcu
> +      - mediatek,mt8189-lvts-ap
> +      - mediatek,mt8189-lvts-mcu
>        - mediatek,mt8192-lvts-ap
>        - mediatek,mt8192-lvts-mcu
>        - mediatek,mt8195-lvts-ap
> @@ -58,6 +60,21 @@ properties:
>  allOf:
>    - $ref: thermal-sensor.yaml#
>  
> +  - if:
> +      properties:
> +        compatible:
> +          contains:
> +            enum:
> +              - mediatek,mt8189-lvts-ap
> +              - mediatek,mt8189-lvts-mcu
> +    then:
> +      properties:
> +        nvmem-cells:
> +          minItems: 2
> +
> +        nvmem-cell-names:
> +          minItems: 2
> +
>    - if:
>        properties:
>          compatible:
> @@ -75,6 +92,10 @@ allOf:
>          nvmem-cell-names:
>            maxItems: 1
>  
> +      required:
> +        - clocks
> +        - resets
> +
>    - if:
>        properties:
>          compatible:
> @@ -91,12 +112,14 @@ allOf:
>          nvmem-cell-names:
>            minItems: 2
>  
> +      required:
> +        - clocks
> +        - resets
> +
>  required:
>    - compatible
>    - reg
>    - interrupts
> -  - clocks
> -  - resets
>    - nvmem-cells
>    - nvmem-cell-names
>  
> diff --git a/include/dt-bindings/thermal/mediatek,lvts-thermal.h b/include/dt-bindings/thermal/mediatek,lvts-thermal.h
> index ddc7302a510a..6c9103dfdc2d 100644
> --- a/include/dt-bindings/thermal/mediatek,lvts-thermal.h
> +++ b/include/dt-bindings/thermal/mediatek,lvts-thermal.h
> @@ -42,6 +42,26 @@
>  #define MT8188_AP_CAM1		6
>  #define MT8188_AP_CAM2		7
>  
> +#define MT8189_MCU_BIG_CPU1     0
> +#define MT8189_MCU_BIG_CPU2     1
> +#define MT8189_MCU_BIG_CPU3     2
> +#define MT8189_MCU_BIG_CPU4     3
> +#define MT8189_MCU_LITTLE_CPU1  4
> +#define MT8189_MCU_LITTLE_CPU2  5
> +#define MT8189_MCU_LITTLE_CPU3  6
> +#define MT8189_MCU_LITTLE_CPU4  7
> +#define MT8189_MCU_LITTLE_CPU5  8
> +#define MT8189_MCU_LITTLE_CPU6  9
> +#define MT8189_MCU_LITTLE_CPU7  10
> +#define MT8189_MCU_LITTLE_CPU8  11
> +
> +#define MT8189_AP_SOC1          12
> +#define MT8189_AP_SOC2          13
> +#define MT8189_AP_SOC3          14
> +#define MT8189_AP_APU           15
> +#define MT8189_AP_GPU1          16
> +#define MT8189_AP_GPU2          17
> +
>  #define MT8195_MCU_BIG_CPU0     0
>  #define MT8195_MCU_BIG_CPU1     1
>  #define MT8195_MCU_BIG_CPU2     2
> -- 
> 2.45.2
> 

From Hanchien.Lin at mediatek.com  Tue Dec  2 00:03:13 2025
From: Hanchien.Lin at mediatek.com (=?utf-8?B?SGFuY2hpZW4gTGluICjmnpfnv7DorJkp?=)
Date: Tue, 2 Dec 2025 08:03:13 +0000
Subject: [PATCH v2 1/2] arm64: dts: mediatek: mt8189: Add thermal
 controller node
In-Reply-To: <ea8e4201-f1c2-41cc-83ff-b509fd22bca2@kernel.org>
References: <20251201100620.1557608-1-hanchien.lin@mediatek.com>
 <20251201100620.1557608-2-hanchien.lin@mediatek.com>
 <ea8e4201-f1c2-41cc-83ff-b509fd22bca2@kernel.org>
Message-ID: <TY2PPF3CC6FBD4CC72C1EDEF5130C36D83BE0D8A@TY2PPF3CC6FBD4C.apcprd03.prod.outlook.com>

Hi Krzysztof,

Thank you for your feedback, and I apologize for missing your previous comments. I will carefully review all the feedback and make the necessary changes in the next version of the patch.

Sorry for the inconvenience caused.

Best regards,
Hanchien Lin.

-----Original Message-----
From: Krzysztof Kozlowski <krzk at kernel.org> 
Sent: Monday, December 1, 2025 6:10 PM
To: Hanchien Lin (???) <Hanchien.Lin at mediatek.com>; Rafael J . Wysocki <rafael at kernel.org>; Daniel Lezcano <daniel.lezcano at linaro.org>; Zhang Rui <rui.zhang at intel.com>; Lukasz Luba <lukasz.luba at arm.com>; Rob Herring <robh at kernel.org>; Krzysztof Kozlowski <krzk+dt at kernel.org>; Conor Dooley <conor+dt at kernel.org>; Philipp Zabel <p.zabel at pengutronix.de>; Matthias Brugger <matthias.bgg at gmail.com>; AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>; Balsam CHIHI <bchihi at baylibre.com>
Cc: Irving-CH Lin (???) <Irving-CH.Lin at mediatek.com>; Jh Hsu (???) <Jh.Hsu at mediatek.com>; WH Wu (???) <vincent.wu at mediatek.com>; Raymond Sun (???) <Raymond.Sun at mediatek.com>; Sirius Wang (???) <Sirius.Wang at mediatek.com>; linux-pm at vger.kernel.org; devicetree at vger.kernel.org; linux-kernel at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux-mediatek at lists.infradead.org; Project_Global_Chrome_Upstream_Group <Project_Global_Chrome_Upstream_Group at mediatek.com>
Subject: Re: [PATCH v2 1/2] arm64: dts: mediatek: mt8189: Add thermal controller node


External email : Please do not click links or open attachments until you have verified the sender or the content.


On 01/12/2025 11:06, Hanchien Lin wrote:
> Add device tree node for the thermal controller on MediaTek MT8189 SoC.
>
> Signed-off-by: Hanchien Lin <hanchien.lin at mediatek.com>


Nothing improved. You just completely ignored feedback expecting reviewers to repeat themself.

NAK

Best regards,
Krzysztof

From marcus.folkesson at gmail.com  Tue Dec  2 00:09:47 2025
From: marcus.folkesson at gmail.com (Marcus Folkesson)
Date: Tue, 02 Dec 2025 09:09:47 +0100
Subject: [PATCH RESEND v3 0/5] I2C Mux per channel bus speed
Message-ID: <20251202-i2c-mux-v3-0-877dcf478a9f@gmail.com>

This was a RFC on how to implement a feature to have different bus
speeds on different channels with an I2C multiplexer/switch.
As no major complaints on the design came up during the review, I
decided to submit the series without the RFC tag.

The benefit with this feature is that you may group devices after
the fastest bus speed they can handle.
A real-world example is that you could have e.g. a display running @400kHz
and a smart battery running @100kHz using the same I2C controller.

There are many corner cases where this may cause a problem for some
hardware topologies. I've tried to describe those I could think of
in the documentation, see Patch #5.

E.g. one risk is that if the mux driver does not disconnect channels
when Idle, this may cause a higher frequency to "leak" through to
devices that are supposed to run at lower bus speed.
This is not only a "problem" for changing bus speed but could also be
an issue for potential address conflicts.

The implementation is split up into several patches:

Patch #1 Introduce a callback for the i2c controller to set bus speed
Patch #2 Introduce functionality to adjust bus speed depending on mux
         channel.
Patch #3 Cleanup i2c-davinci driver a bit to prepare it for set_clk_freq
Parch #4 Implement set_clk_freq for the i2c-davinci driver
Parch #5 Update documentation with this feature

Signed-off-by: Marcus Folkesson <marcus.folkesson at gmail.com>
---
Changes in v3:
- Return -EINVAL if channel is faster than parent (kernel test robot)
- Link to v2: https://lore.kernel.org/r/20251002-i2c-mux-v2-0-b698564cd956 at gmail.com

Changes in v2:
- Changed bus_freq field to bus_freq_hz in davinci_i2c_dev (Bartosz Golaszewski)
- Removed idle_state from mux core (Peter Rosin)
- Link to v1: https://lore.kernel.org/r/20250922-i2c-mux-v1-0-28c94a610930 at gmail.com

---
Marcus Folkesson (5):
      i2c: core: add callback to change bus frequency
      i2c: mux: add support for per channel bus frequency
      i2c: davinci: calculate bus freq from Hz instead of kHz
      i2c: davinci: add support for setting bus frequency
      docs: i2c: i2c-topology: add section about bus speed

 Documentation/i2c/i2c-topology.rst | 176 +++++++++++++++++++++++++++++++++++++
 drivers/i2c/busses/i2c-davinci.c   |  41 ++++++---
 drivers/i2c/i2c-mux.c              | 116 +++++++++++++++++++++---
 include/linux/i2c.h                |  13 +++
 4 files changed, 324 insertions(+), 22 deletions(-)
---
base-commit: 22f20375f5b71f30c0d6896583b93b6e4bba7279
change-id: 20250913-i2c-mux-b0063de2ae4d

Best regards,
-- 
Marcus Folkesson <marcus.folkesson at gmail.com>



From marcus.folkesson at gmail.com  Tue Dec  2 00:09:48 2025
From: marcus.folkesson at gmail.com (Marcus Folkesson)
Date: Tue, 02 Dec 2025 09:09:48 +0100
Subject: [PATCH RESEND v3 1/5] i2c: core: add callback to change bus
 frequency
In-Reply-To: <20251202-i2c-mux-v3-0-877dcf478a9f@gmail.com>
References: <20251202-i2c-mux-v3-0-877dcf478a9f@gmail.com>
Message-ID: <20251202-i2c-mux-v3-1-877dcf478a9f@gmail.com>

All devices on the same I2C bus share the same clock line and the bus
frequency has therefor be chosen so that all attached devices are able
to tolarate that clock rate. IOW, the bus speed must be set for the
slowest attached device.

With I2C multiplexers/switches on the other hand, it would be possible
to have different "domains" that runs with different speeds.

Prepare for such a feature by provide an optional callback function to
change bus frequency.

Signed-off-by: Marcus Folkesson <marcus.folkesson at gmail.com>
---
 include/linux/i2c.h | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 20fd41b51d5c..d147e388dbab 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -742,6 +742,8 @@ struct i2c_adapter {
 	struct rt_mutex mux_lock;
 
 	int timeout;			/* in jiffies */
+	int clock_hz;
+	int (*set_clk_freq)(struct i2c_adapter *adap, u32 clock_hz); /* Optional */
 	int retries;
 	struct device dev;		/* the adapter device */
 	unsigned long locked_flags;	/* owned by the I2C core */
@@ -835,6 +837,17 @@ i2c_unlock_bus(struct i2c_adapter *adapter, unsigned int flags)
 	adapter->lock_ops->unlock_bus(adapter, flags);
 }
 
+static inline int
+i2c_adapter_set_clk_freq(struct i2c_adapter *adapter, u32 clock_hz)
+{
+	int ret = -EOPNOTSUPP;
+
+	if (adapter->set_clk_freq)
+		ret = adapter->set_clk_freq(adapter, clock_hz);
+
+	return ret;
+}
+
 /**
  * i2c_mark_adapter_suspended - Report suspended state of the adapter to the core
  * @adap: Adapter to mark as suspended

-- 
2.51.2



From marcus.folkesson at gmail.com  Tue Dec  2 00:09:49 2025
From: marcus.folkesson at gmail.com (Marcus Folkesson)
Date: Tue, 02 Dec 2025 09:09:49 +0100
Subject: [PATCH RESEND v3 2/5] i2c: mux: add support for per channel bus
 frequency
In-Reply-To: <20251202-i2c-mux-v3-0-877dcf478a9f@gmail.com>
References: <20251202-i2c-mux-v3-0-877dcf478a9f@gmail.com>
Message-ID: <20251202-i2c-mux-v3-2-877dcf478a9f@gmail.com>

There may be several reasons why you may need to use a certain speed
on an I2C bus. E.g.

- When several devices are attached to the bus, the speed must be
  selected according to the slowest device.

- Electrical conditions may limit the usuable speed on the bus for
  different reasons.

With an I2C multiplexer, it is possible to group the attached devices
after their preferred speed by e.g. put all "slow" devices on a separate
channel on the multiplexer.

Consider the following topology:

                      .----------. 100kHz .--------.
    .--------. 400kHz |          |--------| dev D1 |
    |  root  |--+-----| I2C MUX  |        '--------'
    '--------'  |     |          |--. 400kHz .--------.
                |     '----------'  '-------| dev D2 |
                |  .--------.               '--------'
                '--| dev D3 |
                   '--------'

One requirement with this design is that a multiplexer may only use the
same or lower bus speed as its parent.
Otherwise, if the multiplexer would have to increase the bus frequency,
then all siblings (D3 in this case) would run into a clock speed it may
not support.

The bus frequency for each channel is set in the devicetree. As the
i2c-mux bindings import the i2c-controller schema, the clock-frequency
property is already allowed.
If no clock-frequency property is set, the channel inherit their parent
bus speed.

The following example uses dt bindings to illustrate the topology above:

    i2c {
	clock-frequency = <400000>;

        i2c-mux {
            i2c at 0 {
                clock-frequency = <100000>;

                D1 {
                    ...
                };
            };

            i2c at 1 {
                D2 {
                  ...
                };
            };
        };

        D3 {
            ...
        }
    };

Signed-off-by: Marcus Folkesson <marcus.folkesson at gmail.com>
---
 drivers/i2c/i2c-mux.c | 116 ++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 104 insertions(+), 12 deletions(-)

diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 4d8690981a55..67ba33a13dde 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -36,6 +36,72 @@ struct i2c_mux_priv {
 	u32 chan_id;
 };
 
+static int i2c_mux_select_chan(struct i2c_adapter *adap, u32 chan_id)
+{
+	struct i2c_mux_priv *priv = adap->algo_data;
+	struct i2c_mux_core *muxc = priv->muxc;
+	struct i2c_adapter *parent = muxc->parent;
+	struct i2c_adapter *root;
+	int ret;
+
+	if (priv->adap.clock_hz && priv->adap.clock_hz != parent->clock_hz) {
+		root = i2c_root_adapter(&adap->dev);
+
+		/* if we are parent-locked and the root adapter is our parent,
+		 * we already have the lock we need. Otherwise take the bus lock for the root
+		 * adaper before changing bus clock.
+		 */
+		if ((root != parent && !muxc->mux_locked) || muxc->mux_locked)
+			i2c_lock_bus(parent, I2C_LOCK_ROOT_ADAPTER);
+
+		ret = i2c_adapter_set_clk_freq(root, priv->adap.clock_hz);
+
+		if ((root != parent && !muxc->mux_locked) || muxc->mux_locked)
+			i2c_unlock_bus(parent, I2C_LOCK_ROOT_ADAPTER);
+
+		if (ret < 0) {
+			dev_err(&adap->dev,
+				"Failed to set clock frequency %dHz on root adapter %s: %d\n",
+				priv->adap.clock_hz, root->name, ret);
+
+			return ret;
+		}
+	}
+
+	return muxc->select(muxc, priv->chan_id);
+}
+
+static void i2c_mux_deselect_chan(struct i2c_adapter *adap, u32 chan_id)
+{
+	struct i2c_mux_priv *priv = adap->algo_data;
+	struct i2c_mux_core *muxc = priv->muxc;
+	struct i2c_adapter *parent = muxc->parent;
+	struct i2c_adapter *root;
+	int ret;
+
+	if (parent->clock_hz && parent->clock_hz != priv->adap.clock_hz) {
+		root = i2c_root_adapter(&parent->dev);
+
+		/* if we are parent-locked and the root adapter is our parent,
+		 * we already have the lock we need. Otherwise take the bus lock for the root
+		 * adaper before changing bus clock.
+		 */
+		if ((root != parent && !muxc->mux_locked) || muxc->mux_locked)
+			i2c_lock_bus(parent, I2C_LOCK_ROOT_ADAPTER);
+
+		ret = i2c_adapter_set_clk_freq(root, parent->clock_hz);
+
+		if ((root != parent && !muxc->mux_locked) || muxc->mux_locked)
+			i2c_unlock_bus(parent, I2C_LOCK_ROOT_ADAPTER);
+
+		if (ret < 0)
+			return;
+	}
+
+	if (muxc->deselect)
+		muxc->deselect(muxc, priv->chan_id);
+}
+
 static int __i2c_mux_master_xfer(struct i2c_adapter *adap,
 				 struct i2c_msg msgs[], int num)
 {
@@ -46,11 +112,11 @@ static int __i2c_mux_master_xfer(struct i2c_adapter *adap,
 
 	/* Switch to the right mux port and perform the transfer. */
 
-	ret = muxc->select(muxc, priv->chan_id);
+	ret = i2c_mux_select_chan(adap, priv->chan_id);
 	if (ret >= 0)
 		ret = __i2c_transfer(parent, msgs, num);
-	if (muxc->deselect)
-		muxc->deselect(muxc, priv->chan_id);
+
+	i2c_mux_deselect_chan(adap, priv->chan_id);
 
 	return ret;
 }
@@ -65,11 +131,11 @@ static int i2c_mux_master_xfer(struct i2c_adapter *adap,
 
 	/* Switch to the right mux port and perform the transfer. */
 
-	ret = muxc->select(muxc, priv->chan_id);
+	ret = i2c_mux_select_chan(adap, priv->chan_id);
 	if (ret >= 0)
 		ret = i2c_transfer(parent, msgs, num);
-	if (muxc->deselect)
-		muxc->deselect(muxc, priv->chan_id);
+
+	i2c_mux_deselect_chan(adap, priv->chan_id);
 
 	return ret;
 }
@@ -86,12 +152,12 @@ static int __i2c_mux_smbus_xfer(struct i2c_adapter *adap,
 
 	/* Select the right mux port and perform the transfer. */
 
-	ret = muxc->select(muxc, priv->chan_id);
+	ret = i2c_mux_select_chan(adap, priv->chan_id);
 	if (ret >= 0)
 		ret = __i2c_smbus_xfer(parent, addr, flags,
 				       read_write, command, size, data);
-	if (muxc->deselect)
-		muxc->deselect(muxc, priv->chan_id);
+
+	i2c_mux_deselect_chan(adap, priv->chan_id);
 
 	return ret;
 }
@@ -108,12 +174,12 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
 
 	/* Select the right mux port and perform the transfer. */
 
-	ret = muxc->select(muxc, priv->chan_id);
+	ret = i2c_mux_select_chan(adap, priv->chan_id);
 	if (ret >= 0)
 		ret = i2c_smbus_xfer(parent, addr, flags,
 				     read_write, command, size, data);
-	if (muxc->deselect)
-		muxc->deselect(muxc, priv->chan_id);
+
+	i2c_mux_deselect_chan(adap, priv->chan_id);
 
 	return ret;
 }
@@ -365,6 +431,32 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
 			}
 		}
 
+		of_property_read_u32(child, "clock-frequency", &priv->adap.clock_hz);
+
+		/*
+		 * Warn if the mux adapter is not parent-locked as
+		 * this may cause issues for some hardware topologies.
+		 */
+		if ((priv->adap.clock_hz < parent->clock_hz) && muxc->mux_locked)
+			dev_warn(muxc->dev,
+				 "channel %u is slower than parent on a non parent-locked mux\n",
+				 chan_id);
+
+		/* If the mux adapter has no clock-frequency property, inherit from parent */
+		if (!priv->adap.clock_hz)
+			priv->adap.clock_hz = parent->clock_hz;
+
+		/* We don't support mux adapters faster than their parent */
+		if (priv->adap.clock_hz > parent->clock_hz) {
+			dev_err(muxc->dev,
+				"channel (%u) is faster (%u) than parent (%u)\n",
+				chan_id, priv->adap.clock_hz, parent->clock_hz);
+
+			of_node_put(mux_node);
+			ret = -EINVAL;
+			goto err_free_priv;
+		}
+
 		priv->adap.dev.of_node = child;
 		of_node_put(mux_node);
 	}

-- 
2.51.2



From marcus.folkesson at gmail.com  Tue Dec  2 00:09:50 2025
From: marcus.folkesson at gmail.com (Marcus Folkesson)
Date: Tue, 02 Dec 2025 09:09:50 +0100
Subject: [PATCH RESEND v3 3/5] i2c: davinci: calculate bus freq from Hz
 instead of kHz
In-Reply-To: <20251202-i2c-mux-v3-0-877dcf478a9f@gmail.com>
References: <20251202-i2c-mux-v3-0-877dcf478a9f@gmail.com>
Message-ID: <20251202-i2c-mux-v3-3-877dcf478a9f@gmail.com>

The bus frequency is unnecessarily converted between Hz and kHz in
several places.
This is probably an old legacy from the old times (pre-devicetrees)
when the davinci_i2c_platform_data took the bus_freq in kHz.

Stick to Hz.

Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski at linaro.org>
Signed-off-by: Marcus Folkesson <marcus.folkesson at gmail.com>
---
 drivers/i2c/busses/i2c-davinci.c | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index 6a3d4e9e07f4..82f295619c4d 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -117,8 +117,6 @@
 /* timeout for pm runtime autosuspend */
 #define DAVINCI_I2C_PM_TIMEOUT	1000	/* ms */
 
-#define DAVINCI_I2C_DEFAULT_BUS_FREQ	100
-
 struct davinci_i2c_dev {
 	struct device           *dev;
 	void __iomem		*base;
@@ -134,8 +132,8 @@ struct davinci_i2c_dev {
 #ifdef CONFIG_CPU_FREQ
 	struct notifier_block	freq_transition;
 #endif
-	/* standard bus frequency (kHz) */
-	unsigned int		bus_freq;
+	/* standard bus frequency */
+	unsigned int		bus_freq_hz;
 	/* Chip has a ICPFUNC register */
 	bool			has_pfunc;
 };
@@ -209,16 +207,16 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
 	if (device_is_compatible(dev->dev, "ti,keystone-i2c"))
 		d = 6;
 
-	clk = ((input_clock / (psc + 1)) / (dev->bus_freq * 1000));
+	clk = ((input_clock / (psc + 1)) / (dev->bus_freq_hz));
 	/* Avoid driving the bus too fast because of rounding errors above */
-	if (input_clock / (psc + 1) / clk > dev->bus_freq * 1000)
+	if (input_clock / (psc + 1) / clk > dev->bus_freq_hz)
 		clk++;
 	/*
 	 * According to I2C-BUS Spec 2.1, in FAST-MODE LOW period should be at
 	 * least 1.3uS, which is not the case with 50% duty cycle. Driving HIGH
 	 * to LOW ratio as 1 to 2 is more safe.
 	 */
-	if (dev->bus_freq > 100)
+	if (dev->bus_freq_hz > 100000)
 		clkl = (clk << 1) / 3;
 	else
 		clkl = (clk >> 1);
@@ -269,7 +267,7 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev)
 		davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKL_REG));
 	dev_dbg(dev->dev, "CLKH = %d\n",
 		davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKH_REG));
-	dev_dbg(dev->dev, "bus_freq = %dkHz\n", dev->bus_freq);
+	dev_dbg(dev->dev, "bus_freq_hz = %dHz\n", dev->bus_freq_hz);
 
 
 	/* Take the I2C module out of reset: */
@@ -761,9 +759,9 @@ static int davinci_i2c_probe(struct platform_device *pdev)
 
 	r = device_property_read_u32(&pdev->dev, "clock-frequency", &prop);
 	if (r)
-		prop = DAVINCI_I2C_DEFAULT_BUS_FREQ;
+		prop = I2C_MAX_STANDARD_MODE_FREQ;
 
-	dev->bus_freq = prop / 1000;
+	dev->bus_freq_hz = prop;
 
 	dev->has_pfunc = device_property_present(&pdev->dev, "ti,has-pfunc");
 

-- 
2.51.2



From marcus.folkesson at gmail.com  Tue Dec  2 00:09:51 2025
From: marcus.folkesson at gmail.com (Marcus Folkesson)
Date: Tue, 02 Dec 2025 09:09:51 +0100
Subject: [PATCH RESEND v3 4/5] i2c: davinci: add support for setting bus
 frequency
In-Reply-To: <20251202-i2c-mux-v3-0-877dcf478a9f@gmail.com>
References: <20251202-i2c-mux-v3-0-877dcf478a9f@gmail.com>
Message-ID: <20251202-i2c-mux-v3-4-877dcf478a9f@gmail.com>

Populate adapter with clock_hz and set_clk_freq to enable support for
dynamic bus frequency.

Acked-by: Bartosz Golaszewski <bartosz.golaszewski at linaro.org>
Signed-off-by: Marcus Folkesson <marcus.folkesson at gmail.com>
---
 drivers/i2c/busses/i2c-davinci.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index 82f295619c4d..fdde573eb59d 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -279,6 +279,27 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev)
 	return 0;
 }
 
+static int davinci_i2c_set_clk(struct i2c_adapter *adap, u32 clock_hz)
+{
+	struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+
+	if (dev->bus_freq_hz == clock_hz)
+		return 0;
+
+	dev->bus_freq_hz = clock_hz;
+
+	/* put I2C into reset */
+	davinci_i2c_reset_ctrl(dev, 0);
+
+	/* compute clock dividers */
+	i2c_davinci_calc_clk_dividers(dev);
+
+	/* Take the I2C module out of reset: */
+	davinci_i2c_reset_ctrl(dev, 1);
+
+	return 0;
+}
+
 /*
  * This routine does i2c bus recovery by using i2c_generic_scl_recovery
  * which is provided by I2C Bus recovery infrastructure.
@@ -810,6 +831,8 @@ static int davinci_i2c_probe(struct platform_device *pdev)
 	adap->dev.parent = &pdev->dev;
 	adap->timeout = DAVINCI_I2C_TIMEOUT;
 	adap->dev.of_node = dev_of_node(&pdev->dev);
+	adap->clock_hz = dev->bus_freq_hz;
+	adap->set_clk_freq = davinci_i2c_set_clk;
 
 	if (dev->has_pfunc)
 		adap->bus_recovery_info = &davinci_i2c_scl_recovery_info;

-- 
2.51.2



From marcus.folkesson at gmail.com  Tue Dec  2 00:09:52 2025
From: marcus.folkesson at gmail.com (Marcus Folkesson)
Date: Tue, 02 Dec 2025 09:09:52 +0100
Subject: [PATCH RESEND v3 5/5] docs: i2c: i2c-topology: add section about
 bus speed
In-Reply-To: <20251202-i2c-mux-v3-0-877dcf478a9f@gmail.com>
References: <20251202-i2c-mux-v3-0-877dcf478a9f@gmail.com>
Message-ID: <20251202-i2c-mux-v3-5-877dcf478a9f@gmail.com>

Describe what needs to be consideraed and taken into account
when using different bus speeds for different mux channels.

Signed-off-by: Marcus Folkesson <marcus.folkesson at gmail.com>
---
 Documentation/i2c/i2c-topology.rst | 176 +++++++++++++++++++++++++++++++++++++
 1 file changed, 176 insertions(+)

diff --git a/Documentation/i2c/i2c-topology.rst b/Documentation/i2c/i2c-topology.rst
index 48fce0f7491b..2c4a1364ce82 100644
--- a/Documentation/i2c/i2c-topology.rst
+++ b/Documentation/i2c/i2c-topology.rst
@@ -367,6 +367,182 @@ When D1 or D2 are accessed, accesses to D3 and D4 are locked out while
 accesses to D5 may interleave. When D3 or D4 are accessed, accesses to
 all other devices are locked out.
 
+Bus Speed and I2C Multiplexers
+================================
+
+I2C bus multiplexers allows multiple downstream channels to be exposed
+as separate I2C adapters which also could set their own bus speed.
+
+The multiplexer itself cannot change the bus speed as it use the upstream
+clock and data lines to communicate with the downstream devices. The speed
+is therfor changed in the root adapter resulting in that the whole bus is
+affected.
+
+This increases the complexity of the topology and some considerations must
+be taken into.
+
+Bus speed
+----------
+
+Downstream channels of an I2C multiplexer can only operate at the same or
+lower bus speed as the upstream bus. This is because the upstream bus may
+have devices that cannot operate at higher speeds and those will be affected
+by the speed change.
+
+The example below illustrates the problem.
+The root adapter is operating at 100kHz. D2 can only operate with 100kHz,
+but D2 can operate at 400kHz. When D1 is selected, the bus speed of the
+root adapter would have to be is set to 400kHz, a speed that D2 may not support.
+
+This topology is therefor not allowed: ::
+
+                          .----------. 400kHz .--------.
+        .--------. 100kHz |   mux-   |--------| dev D1 |
+        |  root  |--+-----|  locked  |        '--------'
+        '--------'  |     |  mux M1  |
+                    |     '----------'
+                    |  .--------.
+                    '--| dev D2 |
+                       '--------'
+
+
+This topology is allowed: ::
+
+                          .----------. 100kHz .--------.
+        .--------. 400kHz |   mux-   |--------| dev D2 |
+        |  root  |--+-----|  locked  |        '--------'
+        '--------'        |  mux M1  |--. 400kHz .--------.
+                          '----------'  '--------| dev D1 |
+                                                 '--------'
+
+Preferred topology
+-------------------
+
+The preferred topology when using different bus speeds is to have the multiplexer
+connected directly to the root adapter without any devices as siblings.
+By this arrangement, the bus speed can be changed without affecting any other devices
+and many of the caveats are avoided.
+
+Other multiplexers in parallell is still okay as those are locked out during transfers.
+
+This is the preferred topology: ::
+
+                          .----------. 100kHz .--------.
+        .--------. 400kHz |   mux-   |--------| dev D2 |
+        |  root  |--+-----|  locked  |        '--------'
+        '--------'        |  mux M1  |--. 400kHz .--------.
+                          '----------'  '--------| dev D1 |
+                                                 '--------'
+Locking
+--------
+
+If the multiplexer is mux-locked, transfers to D3 may interleave between the
+select-transfer-deselect to D1 or D2.
+This results in a situation where the bus speed to D3 may be lower than it
+is supposed to be. This is usually not a problem.
+
+This topology is allowed but some transfers to D3 may be at 100kHz: ::
+
+                          .----------. 100kHz .--------.
+        .--------. 400kHz |   mux-   |--------| dev D1 |
+        |  root  |--+-----|  locked  |        '--------'
+        '--------'  |     |  mux M1  |--. 400kHz .--------.
+                    |     '----------'  '--------| dev D2 |
+                    |  .--------.                '--------'
+                    '--| dev D3 |
+                       '--------'
+
+Multiple muxes in series
+--------------------------
+
+When multiple muxes are used in series the same rules applies.
+
+Transfers to D3 may interleave between select-transfer-deselect to D1, which
+results that the bus speed to D2 or D3 will be at 100KHz.
+
+Transfers to D2 may interleave between select-transfer-deselect to D1, which
+results in that the bus speed to D1 may be at 400kHz as the transfer to D2
+will set the bus speed to before the transfer to D1 starts.
+
+This is probably a bad topology ::
+
+                     .----------. 400kHz .----------. 100kHz .--------.
+    .--------.400kHz |   mux-   |--------|   mux-   |--------| dev D1 |
+    |  root  |--+----|  locked  | 400kHz |  locked  |        '--------'
+    '--------'  |    |  mux M1  |--.     |  mux M2  |
+                |    '----------'  |     '----------'
+                |  .--------.      |  .--------.
+                '--| dev D3 |      '--| dev D2 |
+                   '--------'         '--------'
+
+Multiple muxes in parallell
+----------------------------
+
+When multiple muxes are used in parallell all access to other muxes are locked out
+so this is not a problem.
+
+If the muxes are mux-locked, access to D3 may still interleave though.
+
+In the example below, D3 may not interleave between select-transfer-deselect for D1
+or D2 as both muxes are parent-locked: ::
+
+
+                   .----------. 100kHz   .--------.
+                   |  parent- |----------| dev D1 |
+                .--|  locked  |          '--------'
+                |  |  mux M1  |
+                |  '----------'
+                |      .----------. 400KHz  .--------.
+    .--------. 400kHz  |  parent- |---------| dev D2 |
+    |  root  |--+------|  locked  |         '--------'
+    '--------'  |      |  mux M2  |
+                |      '----------'
+                |  .--------.
+                '--| dev D3 |
+                   '--------'
+
+Idle state
+-----------
+
+Muxes have an idle state, which is the state the channels is put into when no channel
+is active. The state is typically one of the following:
+
+- All channels are disconnected
+- The last selected channel is left as-is
+- A predefined channel is selected
+
+Muxes that support an idle state where all channels are disconnected are preferred when using
+different bus speeds. Otherwise high bus speeds may "leak" through to devices that
+may not support that higher speed.
+
+Consider the following example: ::
+
+                          .----------. 100kHz .--------.
+        .--------. 400kHz |   mux-   |--------| dev D1 |
+        |  root  |--+-----|  locked  |        '--------'
+        '--------'  |     |  mux M1  |--. 400kHz .--------.
+                    |     '----------'  '--------| dev D2 |
+                    |  .--------.                '--------'
+                    '--| dev D3 |
+                       '--------'
+
+If the idle state of M1 is:
+- All channels disconnected: No problem, D1 and D2 are not affected by communication
+  to D3.
+- Last selected channel: Problem if D1 was the last selected channel. High speed
+  communication to D3 will be "leaked" to D1.
+- Predefined channel: Problem, if the predefined channel D1. Set predefined channel
+  to D2 as D2 may handle 400kHz.
+
+Supported controllers
+-----------------------
+
+Not all I2C controllers support setting the bus speed dynamically.
+At the time of writint, the following controllers has support:
+
+============================   =============================================
+i2c-davinci                    Supports dynamic bus speed
+============================   =============================================
 
 Mux type of existing device drivers
 ===================================

-- 
2.51.2



From visitorckw at gmail.com  Tue Dec  2 00:26:13 2025
From: visitorckw at gmail.com (Kuan-Wei Chiu)
Date: Tue,  2 Dec 2025 08:26:13 +0000
Subject: [PATCH v3] coresight: etm3x: Fix cntr_val_show() to match cntr_val_store() behavior
Message-ID: <20251202082613.3265761-1-visitorckw@gmail.com>

The cntr_val_show() function was intended to print the values of all
counters using a loop. However, due to a buffer overwrite issue with
sprintf(), it effectively only displayed the value of the last counter.

The companion function, cntr_val_store(), allows users to modify a
specific counter selected by 'cntr_idx'. To maintain consistency
between read and write operations and to align with the ETM4x driver
behavior, modify cntr_val_show() to report only the value of the
currently selected counter.

This change removes the loop and the "counter %d:" prefix, printing
only the hexadecimal value. It also adopts sysfs_emit() for standard
sysfs output formatting.

Fixes: a939fc5a71ad ("coresight-etm: add CoreSight ETM/PTM driver")
Cc: stable at vger.kernel.org
Signed-off-by: Kuan-Wei Chiu <visitorckw at gmail.com>
---
Build test only.

Changes in v3:
- Switch format specifier to %#x to include the 0x prefix.
- Add Cc stable

v2: https://lore.kernel.org/lkml/20251201095228.1905489-1-visitorckw at gmail.com/

 .../hwtracing/coresight/coresight-etm3x-sysfs.c   | 15 ++++-----------
 1 file changed, 4 insertions(+), 11 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
index 762109307b86..b3c67e96a82a 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
@@ -717,26 +717,19 @@ static DEVICE_ATTR_RW(cntr_rld_event);
 static ssize_t cntr_val_show(struct device *dev,
 			     struct device_attribute *attr, char *buf)
 {
-	int i, ret = 0;
 	u32 val;
 	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	struct etm_config *config = &drvdata->config;
 
 	if (!coresight_get_mode(drvdata->csdev)) {
 		spin_lock(&drvdata->spinlock);
-		for (i = 0; i < drvdata->nr_cntr; i++)
-			ret += sprintf(buf, "counter %d: %x\n",
-				       i, config->cntr_val[i]);
+		val = config->cntr_val[config->cntr_idx];
 		spin_unlock(&drvdata->spinlock);
-		return ret;
-	}
-
-	for (i = 0; i < drvdata->nr_cntr; i++) {
-		val = etm_readl(drvdata, ETMCNTVRn(i));
-		ret += sprintf(buf, "counter %d: %x\n", i, val);
+	} else {
+		val = etm_readl(drvdata, ETMCNTVRn(config->cntr_idx));
 	}
 
-	return ret;
+	return sysfs_emit(buf, "%#x\n", val);
 }
 
 static ssize_t cntr_val_store(struct device *dev,
-- 
2.52.0.158.g65b55ccf14-goog



From piotr.oniszczuk at gmail.com  Tue Dec  2 00:29:07 2025
From: piotr.oniszczuk at gmail.com (Piotr Oniszczuk)
Date: Tue, 2 Dec 2025 09:29:07 +0100
Subject: [PATCH 01/11] dt-bindings: display: meson-dw-hdmi: Add compatible
 for S4 HDMI controller
In-Reply-To: <a71f24c9-1f40-45a1-8fdb-6075bbf89930@amlogic.com>
References: <20250110-drm-s4-v1-0-cbc2d5edaae8@amlogic.com>
 <20250110-drm-s4-v1-1-cbc2d5edaae8@amlogic.com>
 <3AC316FA-A633-4B6C-81BA-CCCA290E7F03@gmail.com>
 <8c3b9fa4-326e-4791-8154-07b268faa132@amlogic.com>
 <7703796D-35D4-4AD2-B7F8-B75D2BE0F7AD@gmail.com>
 <a71f24c9-1f40-45a1-8fdb-6075bbf89930@amlogic.com>
Message-ID: <F04DC684-AD64-447F-87EC-F503D411F25D@gmail.com>

Ao,
Any chance for updated s4 hdmi series for 6.18?
 

> Wiadomo?? napisana przez Ao Xu <ao.xu at amlogic.com> w dniu 21 lis 2025, o godz. 03:55:
> 
> Hi Piotr?
> 
>     I will check this issue
> 
> ? 2025/11/19 18:27, Piotr Oniszczuk ??:
>> [You don't often get email from piotr.oniszczuk at gmail.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
>> 
>> [ EXTERNAL EMAIL ]
>> 
>> Pls see inline
>> 
>>> Wiadomo?? napisana przez Chuan Liu <chuan.liu at amlogic.com> w dniu 19 lis 2025, o godz. 03:57:
>>> 
>>> Hi Piotr,
>>> 
>>> 
>>> On 11/18/2025 10:50 PM, Piotr Oniszczuk wrote:
>>>> [You don't often get email from piotr.oniszczuk at gmail.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
>>>> [ EXTERNAL EMAIL ]
>>>> Ao,
>>>> Is there any chance to get this s4 drm hdmi series for current 6.18?
>>>> (i tried backport this series to 6.18 but have some issues with reparent vpu_0_sel to sysclk_b_sel)
>>> Why do we need to reparent vpu_0_sel to sysclk_b_sel? is there any
>>> background here?
>> Well - it looks it is because bug....
>> Martin Blumenstingl had perfect eye and catch typo in patch https://lore.kernel.org/all/20250110-drm-s4-v1-11-cbc2d5edaae8 at amlogic.com/:
>> 
>> By replacing:
>> assigned-clock-parents = <&clkc_periphs CLKID_FCLK_DIV3>,
>> <0>, /* Do Nothing */
>> <&clkc_periphs CLKID_VPU_0>,
>> <&clkc_periphs CLKID_FCLK_DIV4>,
>> <0>, /* Do Nothing */
>> <&clkc_periphs CLKID_VAPB_0>;
>> 
>> with:
>> assigned-clock-parents = <&clkc_pll CLKID_FCLK_DIV3>,
>> <0>, /* Do Nothing */
>> <&clkc_periphs CLKID_VPU_0>,
>> <&clkc_pll CLKID_FCLK_DIV4>,
>> <0>, /* Do Nothing */
>> <&clkc_periphs CLKID_VAPB_0>;
>> 
>> dmesg is like this https://termbin.com/6020
>> 
>> So i'm getting hdmi working - but only when device boots _without_ connected hdmi at boot (and connected later)
>> If hdmi is connected at boot - boot hangs at:
>> 
>>     0.341676] meson-dw-hdmi fe300000.hdmi-tx: Detected HDMI TX controller v2.01a with HDCP (meson_dw_hdmi_phy)
>> [    0.342750] meson-dw-hdmi fe300000.hdmi-tx: registered DesignWare HDMI I2C bus driver
>> [    0.343660] meson-drm ff000000.vpu: bound fe300000.hdmi-tx (ops meson_dw_hdmi_ops)
>> [    0.344832] [drm] Initialized meson 1.0.0 for ff000000.vpu on minor 0
>> 
>> FYI: It is after applying https://patchwork.kernel.org/project/linux-amlogic/cover/20250110-drm-s4-v1-0-cbc2d5edaae8 at amlogic.com/ on mainline 6.18 (with some my adjustments on this series required by changes in 6.18).
>> For VPU clk changes see https://github.com/warpme/minimyth2/blob/master/script/kernel/linux-6.18/files/0312-drm-meson-add-vpu-clk-setting-for-S4.patch
>> It is 6.18 adaptation of https://patchwork.kernel.org/project/linux-amlogic/patch/20250110-drm-s4-v1-9-cbc2d5edaae8 at amlogic.com/
>> 
>> As kernel hangs - i have limited caps to drill where root cause is.
>> 
>> Maybe above hang is reason of my backports or missing any pre-req required to get s4 drm working?
>> Anyway - it will be good to test with updated to 6.18 series of Add DRM support for Amlogic S4 (plus info about any pre-req required to get s4 drm working)
>> 
>> 
>>> The vpu_clk on S4 doesn't support sysclk_b_sel as one of its
>>> selectable clock sources, so this reparent operation will definitely
>>> fail. This has nothing to do with the kernel version.
>>> 
>>>>> Wiadomo?? napisana przez Ao Xu via B4 Relay <devnull+ao.xu.amlogic.com at kernel.org> w dniu 10 sty 2025, o godz. 06:39:
>>>>> 
>>>>> From: Ao Xu <ao.xu at amlogic.com>
>>>>> 
>>>>> Add devicetree document for S4 HDMI controller
>>>>> 
>>>>> Signed-off-by: Ao Xu <ao.xu at amlogic.com>
>>>>> ---
>>>>> Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml | 1 +
>>>>> 1 file changed, 1 insertion(+)
>>>>> 
>>>>> diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml
>>>>> index 84d68b8cfccc86fd87a6a0fd2b70af12e51eb8a4..6e0a8369eee915fab55af24d450a6c40e08def38 100644
>>>>> --- a/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml
>>>>> +++ b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml
>>>>> @@ -55,6 +55,7 @@ properties:
>>>>>           - const: amlogic,meson-gx-dw-hdmi
>>>>>       - enum:
>>>>>           - amlogic,meson-g12a-dw-hdmi # G12A (S905X2, S905Y2, S905D2)
>>>>> +          - amlogic,meson-s4-dw-hdmi # S4 (S905Y4)
>>>>> 
>>>>>   reg:
>>>>>     maxItems: 1
>>>>> 
>>>>> --
>>>>> 2.43.0
>>>>> 
>>>>> 
>>>>> 
>>>>> _______________________________________________
>>>>> linux-amlogic mailing list
>>>>> linux-amlogic at lists.infradead.org
>>>>> http://lists.infradead.org/mailman/listinfo/linux-amlogic
>>>> _______________________________________________
>>>> linux-amlogic mailing list
>>>> linux-amlogic at lists.infradead.org
>>>> http://lists.infradead.org/mailman/listinfo/linux-amlogic



From royluo at google.com  Tue Dec  2 00:35:00 2025
From: royluo at google.com (Roy Luo)
Date: Tue, 2 Dec 2025 02:35:00 -0600
Subject: [PATCH v8 2/2] usb: dwc3: Add Google Tensor SoC DWC3 glue driver
In-Reply-To: <CADrjBPqPsPBBSbhx8ZFreFWX2tRxaATT=azS-b1H2b=TJoVAAw@mail.gmail.com>
References: <20251122-controller-v8-0-e7562e0df658@google.com>
 <20251122-controller-v8-2-e7562e0df658@google.com> <CADrjBPqPsPBBSbhx8ZFreFWX2tRxaATT=azS-b1H2b=TJoVAAw@mail.gmail.com>
Message-ID: <CA+zupgyopHGCCb-HcNvyi4m5-UDerYZFmT7S0cNYLYONz-wzwg@mail.gmail.com>

On Sat, Nov 22, 2025 at 7:58?PM Peter Griffin <peter.griffin at linaro.org> wrote:
>
> Hi Roy,
>
> Thanks for your patch. It's great to see Laguna support being added upstream.
>
> On Sat, 22 Nov 2025 at 09:32, Roy Luo <royluo at google.com> wrote:
> >
> > Add support for the DWC3 USB controller found on Google Tensor G5
> > (codename: laguna). The controller features dual-role functionality
> > and hibernation.
> >
> > The primary focus is implementing hibernation support in host mode,
> > enabling the controller to enter a low-power state (D3). This is
> > particularly relevant during system power state transition and
> > runtime power management for power efficiency.
> > Highlights:
> > - Align suspend callback with dwc3_suspend_common() for deciding
> >   between a full teardown and hibernation in host mode.
> > - Integration with `psw` (power switchable) and `top` power domains,
> >   managing their states and device links to support hibernation.
> > - A notifier callback dwc3_google_usb_psw_pd_notifier() for
> >   `psw` power domain events to manage controller state
> >   transitions to/from D3.
> > - Coordination of the `non_sticky` reset during power state
> >   transitions, asserting it on D3 entry and deasserting on D0 entry
> >   in hibernation scenario.
> > - Handling of high-speed and super-speed PME interrupts
> >   that are generated by remote wakeup during hibernation.
> >
> > Co-developed-by: Joy Chakraborty <joychakr at google.com>
> > Signed-off-by: Joy Chakraborty <joychakr at google.com>
> > Co-developed-by: Naveen Kumar <mnkumar at google.com>
> > Signed-off-by: Naveen Kumar <mnkumar at google.com>
> > Signed-off-by: Roy Luo <royluo at google.com>
> > ---
> >  drivers/usb/dwc3/Kconfig       |  13 +
> >  drivers/usb/dwc3/Makefile      |   1 +
> >  drivers/usb/dwc3/dwc3-google.c | 628 +++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 642 insertions(+)
> >
> > diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
> > index 4925d15084f816d3ff92059b476ebcc799b56b51..f58c70dabf108878cbefe0abea88572d9ae81e26 100644
> > --- a/drivers/usb/dwc3/Kconfig
> > +++ b/drivers/usb/dwc3/Kconfig
> > @@ -200,4 +200,17 @@ config USB_DWC3_GENERIC_PLAT
> >           the dwc3 child node in the device tree.
> >           Say 'Y' or 'M' here if your platform integrates DWC3 in a similar way.
> >
> > +config USB_DWC3_GOOGLE
> > +       tristate "Google Platform"
> > +       depends on COMPILE_TEST
> > +       depends on OF && COMMON_CLK && RESET_CONTROLLER
> > +       help
> > +         Support the DesignWare Core USB3 IP found on Google Tensor
> > +         SoCs, starting with the G5 generation. This driver includes
>
> consider adding: (Laguna)

Ack, will add it in the next revision.

>
> > +         support for hibernation in host mode.
> > +         Say 'Y' or 'M' if you have one such device.
> > +
> > +         To compile this driver as a module, choose M here: the
> > +         module will be called dwc3-google.ko.
> > +
> >  endif
> > diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
> > index 96469e48ff9d189cc8d0b65e65424eae2158bcfe..cf1cd408d938b3ac26d58b9be7fcc5af3ee82660 100644
> > --- a/drivers/usb/dwc3/Makefile
> > +++ b/drivers/usb/dwc3/Makefile
> > @@ -58,3 +58,4 @@ obj-$(CONFIG_USB_DWC3_XILINX)         += dwc3-xilinx.o
> >  obj-$(CONFIG_USB_DWC3_OCTEON)          += dwc3-octeon.o
> >  obj-$(CONFIG_USB_DWC3_RTK)             += dwc3-rtk.o
> >  obj-$(CONFIG_USB_DWC3_GENERIC_PLAT)    += dwc3-generic-plat.o
> > +obj-$(CONFIG_USB_DWC3_GOOGLE)          += dwc3-google.o
> > diff --git a/drivers/usb/dwc3/dwc3-google.c b/drivers/usb/dwc3/dwc3-google.c
> > new file mode 100644
> > index 0000000000000000000000000000000000000000..53e04a5409d8a11eb025b0f5cd351cb1b33281ab
> > --- /dev/null
> > +++ b/drivers/usb/dwc3/dwc3-google.c
> > @@ -0,0 +1,628 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * dwc3-google.c - Google DWC3 Specific Glue Layer
> > + *
> > + * Copyright (c) 2025, Google LLC
> > + * Author: Roy Luo <royluo at google.com>
> > + */
> > +
> > +#include <linux/of.h>
> > +#include <linux/bitfield.h>
> > +#include <linux/irq.h>
> > +#include <linux/clk.h>
> > +#include <linux/module.h>
> > +#include <linux/kernel.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/reset.h>
> > +#include <linux/pm_domain.h>
> > +#include <linux/iopoll.h>
> > +#include <linux/regmap.h>
> > +#include <linux/mfd/syscon.h>
>
> Please sort the headers alphabetically. It helps avoid duplicates and
> is easier when adding new headers.

As Greg pointed out, no such requirement exists for usb drivers, but
if it makes things look nicer, why not?
Will sort the headers alphabetically in the next revision.

>
> Also can you add this file, and the bindings patch to the Tensor SoC
> MAINTAINERS entry, so it's easier to review future patches?

Sure! Will update MAITAINERS in the next revision.
Appreciate the review!

Thanks,
Roy Luo


>
> With those nits  addressed:
> Reviewed-by: Peter Griffin <peter.griffin at linaro.org>
>
> regards,
>
> Peter.


From changyuanl at google.com  Tue Dec  2 00:35:50 2025
From: changyuanl at google.com (Changyuan Lyu)
Date: Tue,  2 Dec 2025 00:35:50 -0800
Subject: [PATCH v2 2/2] KVM: arm64: vgic: Hoist SGI/PPI alloc from
 vgic_init() to kvm_create_vgic()
In-Reply-To: <20250212182558.2865232-3-maz@kernel.org>
References: <20250212182558.2865232-3-maz@kernel.org>
Message-ID: <20251202083550.88668-1-changyuanl@google.com>

Hi Marc,

On Wed, Feb 12, 2025 at 18:25:58 +0000, Marc Zyngier <maz at kernel.org> wrote:
> If userspace creates vcpus, then a vgic, we end-up in a situation
> where irqchip_in_kernel() will return true, but no private interrupt
> has been allocated for these vcpus. This situation will continue
> until userspace initialises the vgic, at which point we fix the
> early vcpus. Should a vcpu run or be initialised in the interval,
> bad things may happen.
>
> An obvious solution is to move this fix-up phase to the point where
> the vgic is created. This ensures that from that point onwards,
> all vcpus have their private interrupts, as new vcpus will directly
> allocate them.

I have a concern that this patch might cause an issue if userspace creates
VCPUs *after* a VGIC is created but *before* it has been initialized via
`KVM_DEV_ARM_VGIC_CTRL_INIT`.

For example, consider the following call sequence:

1.  Create VGIC via `KVM_CREATE_DEVICE`.
2.  Create all VCPUs.
3.  Issue `KVM_ARM_VCPU_INIT` to all VCPUs.
4.  Issue `KVM_DEV_ARM_VGIC_CTRL_INIT` to the VGIC.

> With that, we have the invariant that when irqchip_in_kernel() is
> true, all vcpus have their private interrupts.
>
> Reported-by: Alexander Potapenko <glider at google.com>
> Signed-off-by: Marc Zyngier <maz at kernel.org>
> ---
>  arch/arm64/kvm/vgic/vgic-init.c | 74 ++++++++++++++++-----------------
>  1 file changed, 37 insertions(+), 37 deletions(-)
>
> diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
> index bc7e22ab5d812..775461cf2d2db 100644
> --- a/arch/arm64/kvm/vgic/vgic-init.c
> +++ b/arch/arm64/kvm/vgic/vgic-init.c
> [...]
>
> -static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu)
> +static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu, u32 type)
>  {
>  	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>  	int i;
> @@ -218,17 +236,28 @@ static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu)
>  			/* PPIs */
>  			irq->config = VGIC_CONFIG_LEVEL;
>  		}
> +
> +		switch (type) {
> +		case KVM_DEV_TYPE_ARM_VGIC_V3:
> +			irq->group = 1;
> +			irq->mpidr = kvm_vcpu_get_mpidr_aff(vcpu);
> +			break;

`vgic_allocate_private_irqs_locked()` appears to be called in two scenarios:

a) When the VGIC is created, in `kvm_vgic_create()`.
b) When a VCPU is created, in `kvm_vm_ioctl_create_vcpu()`.

For scenario (b), the call path is:

`kvm_vm_ioctl_create_vcpu()`
-> `kvm_arch_vcpu_create()`
  -> `kvm_vgic_vcpu_init()`
    -> `vgic_allocate_private_irqs()`
      -> `vgic_allocate_private_irqs_locked()`

However, since the VCPU has just been created, its `MPIDR_EL1` register
value has not been assigned at this point. The VCPU's `MPIDR_EL1`
register is populated later when `KVM_ARM_VCPU_INIT` is issued, via
the following call path:

`kvm_arch_vcpu_ioctl_vcpu_init()`
-> `kvm_vcpu_set_target()`
  -> `__kvm_vcpu_set_target()`
    -> `kvm_reset_vcpu()`
      -> `kvm_reset_sys_regs()`
        -> `reset_mpidr()`

Therefore, with the call sequence I mentioned at the beginning,
`irq->mpidr` would be assigned an uninitialized value. This suggests that
for `irq->mpidr = kvm_vcpu_get_mpidr_aff(vcpu)` to work correctly, we
must rely on the code path from scenario (a). This would imply that
with this patch, all VCPUs must be created and initialized before the
VGIC is created.

> +		case KVM_DEV_TYPE_ARM_VGIC_V2:
> +			irq->group = 0;
> +			irq->targets = BIT(vcpu->vcpu_id);
> +			break;
> +		}
>  	}
>
>  	return 0;
>  }
>
> -static int vgic_allocate_private_irqs(struct kvm_vcpu *vcpu)
> +static int vgic_allocate_private_irqs(struct kvm_vcpu *vcpu, u32 type)
>  {
>  	int ret;
>
>  	mutex_lock(&vcpu->kvm->arch.config_lock);
> -	ret = vgic_allocate_private_irqs_locked(vcpu);
> +	ret = vgic_allocate_private_irqs_locked(vcpu, type);
>  	mutex_unlock(&vcpu->kvm->arch.config_lock);
>
>  	return ret;
> @@ -258,7 +287,7 @@ int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
>  	if (!irqchip_in_kernel(vcpu->kvm))
>  		return 0;
>
> -	ret = vgic_allocate_private_irqs(vcpu);
> +	ret = vgic_allocate_private_irqs(vcpu, dist->vgic_model);
>  	if (ret)
>  		return ret;
>
> [...]

Please let me know if my understanding is incorrect. Thank you!

Best,
Changyuan


From vincent.guittot at linaro.org  Tue Dec  2 00:54:24 2025
From: vincent.guittot at linaro.org (Vincent Guittot)
Date: Tue, 2 Dec 2025 09:54:24 +0100
Subject: linux-next: Tree for Nov 28 (drivers/pci/controller/dwc/pcie-nxp-s32g.o)
In-Reply-To: <ykmo5qv46mo7f3srblxoi2fvghz722fj7kpm77ozpflaqup6rk@ttvhbw445pgu>
References: <20251128162928.36eec2d6@canb.auug.org.au> <63e1daf7-f9a3-463e-8a1b-e9b72581c7af@infradead.org>
 <ykmo5qv46mo7f3srblxoi2fvghz722fj7kpm77ozpflaqup6rk@ttvhbw445pgu>
Message-ID: <CAKfTPtA-wir5GzU7aTywe7SZG18Aj8Z9g1wjV-Y8vKoyKF1Mkg@mail.gmail.com>

On Tue, 2 Dec 2025 at 05:24, Manivannan Sadhasivam <mani at kernel.org> wrote:
>
> + Vincent

Thanks for looping me in.
>
> On Sat, Nov 29, 2025 at 07:00:04PM -0800, Randy Dunlap wrote:
> >
> >
> > On 11/27/25 9:29 PM, Stephen Rothwell wrote:
> > > Hi all,
> > >
> > > Changes since 20251127:
> > >
> >
> > on i386 (allmodconfig):
> >
> > WARNING: modpost: vmlinux: section mismatch in reference: s32g_init_pcie_controller+0x2b (section: .text) -> memblock_start_of_DRAM (section: .init.text)

Are there details to reproduce the warning ? I don't have such warning
when compiling allmodconfig locally

s32 pcie can only be built in but I may have to use
builtin_platform_driver_probe() instead of builtin_platform_driver()

> >
> >
> > --
> > ~Randy
> >
> >
>
> --
> ????????? ????????


From royluo at google.com  Tue Dec  2 01:01:13 2025
From: royluo at google.com (Roy Luo)
Date: Tue, 2 Dec 2025 03:01:13 -0600
Subject: [PATCH v8 2/2] usb: dwc3: Add Google Tensor SoC DWC3 glue driver
In-Reply-To: <2025112226-heave-refrain-53e6@gregkh>
References: <20251122-controller-v8-0-e7562e0df658@google.com>
 <20251122-controller-v8-2-e7562e0df658@google.com> <2025112226-heave-refrain-53e6@gregkh>
Message-ID: <CA+zupgwzQ5r=-_L79D74=9VRqRO94N0yTApHChM+Nu0cn1ss3w@mail.gmail.com>

On Sat, Nov 22, 2025 at 8:59?PM Greg Kroah-Hartman
<gregkh at linuxfoundation.org> wrote:
>
> On Sat, Nov 22, 2025 at 09:32:06AM +0000, Roy Luo wrote:
> > Add support for the DWC3 USB controller found on Google Tensor G5
> > (codename: laguna). The controller features dual-role functionality
> > and hibernation.
> >
> > The primary focus is implementing hibernation support in host mode,
> > enabling the controller to enter a low-power state (D3). This is
> > particularly relevant during system power state transition and
> > runtime power management for power efficiency.
> > Highlights:
> > - Align suspend callback with dwc3_suspend_common() for deciding
> >   between a full teardown and hibernation in host mode.
> > - Integration with `psw` (power switchable) and `top` power domains,
> >   managing their states and device links to support hibernation.
> > - A notifier callback dwc3_google_usb_psw_pd_notifier() for
> >   `psw` power domain events to manage controller state
> >   transitions to/from D3.
> > - Coordination of the `non_sticky` reset during power state
> >   transitions, asserting it on D3 entry and deasserting on D0 entry
> >   in hibernation scenario.
> > - Handling of high-speed and super-speed PME interrupts
> >   that are generated by remote wakeup during hibernation.
> >
> > Co-developed-by: Joy Chakraborty <joychakr at google.com>
> > Signed-off-by: Joy Chakraborty <joychakr at google.com>
> > Co-developed-by: Naveen Kumar <mnkumar at google.com>
> > Signed-off-by: Naveen Kumar <mnkumar at google.com>
> > Signed-off-by: Roy Luo <royluo at google.com>
> > ---
> >  drivers/usb/dwc3/Kconfig       |  13 +
> >  drivers/usb/dwc3/Makefile      |   1 +
> >  drivers/usb/dwc3/dwc3-google.c | 628 +++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 642 insertions(+)
> >
> > diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
> > index 4925d15084f816d3ff92059b476ebcc799b56b51..f58c70dabf108878cbefe0abea88572d9ae81e26 100644
> > --- a/drivers/usb/dwc3/Kconfig
> > +++ b/drivers/usb/dwc3/Kconfig
> > @@ -200,4 +200,17 @@ config USB_DWC3_GENERIC_PLAT
> >         the dwc3 child node in the device tree.
> >         Say 'Y' or 'M' here if your platform integrates DWC3 in a similar way.
> >
> > +config USB_DWC3_GOOGLE
> > +     tristate "Google Platform"
> > +     depends on COMPILE_TEST
> > +     depends on OF && COMMON_CLK && RESET_CONTROLLER
>
> Shouldn't this be:
>         depends on (OF && COMMON_CLK && RESET_CONTROLLER) || COMPILE_TEST
>
> I shouldn't have to enable those options to just get a build test here,
> the apis should be properly stubbed out if those options are not
> enabled, right?
>
> thanks,
>
> greg k-h

Hi Greg,

I agree with your interpretation of COMPILE_TEST but it doesn't
seem to align with upstream convention. I found the following pattern
in several device driver Kconfig files (including but not limited to usb,
pinctrl and phy).

    depends on COMPILE_TEST || ARCH_XXX
    depends on CONFIG_A && CONFIG_B...

For this patch, the APIs exposed by OF, COMMON_CLK
and RESET_CONTROLLER are properly stubbed out so
I'm all good to go with your suggestion, but I'd like to make
sure this approach is conventional.

I plan to add ARCH_GOOGLE as a dependency in the next
version per [1], so the "depends on" would probably look like
the following per your suggestion:

    depends on (OF && COMMON_CLK && RESET_CONTROLLER && ARCH_GOOGLE)
|| COMPILE_TEST

Please let me know your thoughts.
[1] https://lore.kernel.org/linux-phy/1a53d473-fc13-4ac5-ba52-4701d95e3073 at kernel.org/

Thanks,
Roy Luo


From hanchien.lin at mediatek.com  Tue Dec  2 01:10:54 2025
From: hanchien.lin at mediatek.com (Hanchien Lin)
Date: Tue, 2 Dec 2025 17:10:54 +0800
Subject: [PATCH v3 0/2] dt-bindings/thermal: Add MT8189 LVTS support
Message-ID: <20251202091056.1761229-1-hanchien.lin@mediatek.com>

This patch series adds support for the MediaTek MT8189 SoC to the LVTS thermal controller bindings and driver.
Patch 1 updates the device tree bindings to include MT8189 LVTS thermal controller support.
Patch 2 adds MT8189 support to the LVTS thermal driver.

Changes in v3:
- Update patch 1 subject to reflect binding changes (per Conor Dooley's feedback).
- No changes to patch 2.

Changes in v2:
- Addressed function changes as requested by Krzysztof Kozlowski.

Thanks to Conor Dooley and Krzysztof Kozlowski for their valuable feedback.

Best regards,
Hanchien Lin

Link to v2:
https://lore.kernel.org/linux-mediatek/20251201100620.1557608-1-hanchien.lin at mediatek.com/T/#t

Hanchien Lin (2):
  dt-bindings: thermal: mediatek: Add MT8189 LVTS thermal controller
    bindings
  thermal/drivers/mediatek/lvts_thermal: Add MT8189 support

 .../thermal/mediatek,lvts-thermal.yaml        |  27 +++-
 drivers/thermal/mediatek/lvts_thermal.c       | 151 ++++++++++++++++--
 .../thermal/mediatek,lvts-thermal.h           |  20 +++
 3 files changed, 185 insertions(+), 13 deletions(-)

-- 
2.45.2



From hanchien.lin at mediatek.com  Tue Dec  2 01:10:55 2025
From: hanchien.lin at mediatek.com (Hanchien Lin)
Date: Tue, 2 Dec 2025 17:10:55 +0800
Subject: [PATCH v3 1/2] dt-bindings: thermal: mediatek: Add MT8189 LVTS thermal controller bindings
In-Reply-To: <20251202091056.1761229-1-hanchien.lin@mediatek.com>
References: <20251202091056.1761229-1-hanchien.lin@mediatek.com>
Message-ID: <20251202091056.1761229-2-hanchien.lin@mediatek.com>

Add support for the MediaTek MT8189 LVTS thermal controller to the device tree bindings.
This includes new compatible strings and required properties for MT8189.

Signed-off-by: Hanchien Lin <hanchien.lin at mediatek.com>
---
 .../thermal/mediatek,lvts-thermal.yaml        | 27 +++++++++++++++++--
 .../thermal/mediatek,lvts-thermal.h           | 20 ++++++++++++++
 2 files changed, 45 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml b/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml
index 0259cd3ce9c5..0f7fd69f5fdf 100644
--- a/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml
+++ b/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml
@@ -22,6 +22,8 @@ properties:
       - mediatek,mt8186-lvts
       - mediatek,mt8188-lvts-ap
       - mediatek,mt8188-lvts-mcu
+      - mediatek,mt8189-lvts-ap
+      - mediatek,mt8189-lvts-mcu
       - mediatek,mt8192-lvts-ap
       - mediatek,mt8192-lvts-mcu
       - mediatek,mt8195-lvts-ap
@@ -58,6 +60,21 @@ properties:
 allOf:
   - $ref: thermal-sensor.yaml#
 
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - mediatek,mt8189-lvts-ap
+              - mediatek,mt8189-lvts-mcu
+    then:
+      properties:
+        nvmem-cells:
+          minItems: 2
+
+        nvmem-cell-names:
+          minItems: 2
+
   - if:
       properties:
         compatible:
@@ -75,6 +92,10 @@ allOf:
         nvmem-cell-names:
           maxItems: 1
 
+      required:
+        - clocks
+        - resets
+
   - if:
       properties:
         compatible:
@@ -91,12 +112,14 @@ allOf:
         nvmem-cell-names:
           minItems: 2
 
+      required:
+        - clocks
+        - resets
+
 required:
   - compatible
   - reg
   - interrupts
-  - clocks
-  - resets
   - nvmem-cells
   - nvmem-cell-names
 
diff --git a/include/dt-bindings/thermal/mediatek,lvts-thermal.h b/include/dt-bindings/thermal/mediatek,lvts-thermal.h
index ddc7302a510a..6c9103dfdc2d 100644
--- a/include/dt-bindings/thermal/mediatek,lvts-thermal.h
+++ b/include/dt-bindings/thermal/mediatek,lvts-thermal.h
@@ -42,6 +42,26 @@
 #define MT8188_AP_CAM1		6
 #define MT8188_AP_CAM2		7
 
+#define MT8189_MCU_BIG_CPU1     0
+#define MT8189_MCU_BIG_CPU2     1
+#define MT8189_MCU_BIG_CPU3     2
+#define MT8189_MCU_BIG_CPU4     3
+#define MT8189_MCU_LITTLE_CPU1  4
+#define MT8189_MCU_LITTLE_CPU2  5
+#define MT8189_MCU_LITTLE_CPU3  6
+#define MT8189_MCU_LITTLE_CPU4  7
+#define MT8189_MCU_LITTLE_CPU5  8
+#define MT8189_MCU_LITTLE_CPU6  9
+#define MT8189_MCU_LITTLE_CPU7  10
+#define MT8189_MCU_LITTLE_CPU8  11
+
+#define MT8189_AP_SOC1          12
+#define MT8189_AP_SOC2          13
+#define MT8189_AP_SOC3          14
+#define MT8189_AP_APU           15
+#define MT8189_AP_GPU1          16
+#define MT8189_AP_GPU2          17
+
 #define MT8195_MCU_BIG_CPU0     0
 #define MT8195_MCU_BIG_CPU1     1
 #define MT8195_MCU_BIG_CPU2     2
-- 
2.45.2



From hanchien.lin at mediatek.com  Tue Dec  2 01:10:56 2025
From: hanchien.lin at mediatek.com (Hanchien Lin)
Date: Tue, 2 Dec 2025 17:10:56 +0800
Subject: [PATCH v3 2/2] thermal/drivers/mediatek/lvts_thermal: Add MT8189 support
In-Reply-To: <20251202091056.1761229-1-hanchien.lin@mediatek.com>
References: <20251202091056.1761229-1-hanchien.lin@mediatek.com>
Message-ID: <20251202091056.1761229-3-hanchien.lin@mediatek.com>

Add support for the MediaTek MT8189 SoC to the LVTS thermal driver.

Signed-off-by: Hanchien Lin <hanchien.lin at mediatek.com>
---
 drivers/thermal/mediatek/lvts_thermal.c | 151 ++++++++++++++++++++++--
 1 file changed, 140 insertions(+), 11 deletions(-)

diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c
index ab55b20cda47..c1eee0c2167f 100644
--- a/drivers/thermal/mediatek/lvts_thermal.c
+++ b/drivers/thermal/mediatek/lvts_thermal.c
@@ -65,6 +65,7 @@
 #define LVTS_HW_FILTER				0x0
 #define LVTS_TSSEL_CONF				0x13121110
 #define LVTS_CALSCALE_CONF			0x300
+#define LVTS_MONINT_CONF_STAGE3		BIT(31)
 
 #define LVTS_MONINT_OFFSET_HIGH_INTEN_SENSOR0		BIT(3)
 #define LVTS_MONINT_OFFSET_HIGH_INTEN_SENSOR1		BIT(8)
@@ -107,6 +108,7 @@ struct lvts_sensor_data {
 struct lvts_ctrl_data {
 	struct lvts_sensor_data lvts_sensor[LVTS_SENSOR_MAX];
 	u8 valid_sensor_mask;
+	int hw_tshut_temp;
 	int offset;
 	int mode;
 };
@@ -134,6 +136,9 @@ struct lvts_data {
 	int temp_offset;
 	int gt_calib_bit_offset;
 	unsigned int def_calibration;
+	bool clock_gate_no_need;
+	bool reset_no_need;
+	bool conf_stage3_need;
 };
 
 struct lvts_sensor {
@@ -150,6 +155,7 @@ struct lvts_ctrl {
 	struct lvts_sensor sensors[LVTS_SENSOR_MAX];
 	const struct lvts_data *lvts_data;
 	u32 calibration[LVTS_SENSOR_MAX];
+	u32 hw_tshut_raw_temp;
 	u8 valid_sensor_mask;
 	int mode;
 	void __iomem *base;
@@ -859,6 +865,14 @@ static int lvts_ctrl_init(struct device *dev, struct lvts_domain *lvts_td,
 		 */
 		lvts_ctrl[i].mode = lvts_data->lvts_ctrl[i].mode;
 
+		/*
+		 * The temperature to raw temperature must be done
+		 * after initializing the calibration.
+		 */
+		lvts_ctrl[i].hw_tshut_raw_temp =
+			lvts_temp_to_raw(lvts_data->lvts_ctrl[i].hw_tshut_temp,
+					 lvts_data->temp_factor);
+
 		lvts_ctrl[i].low_thresh = INT_MIN;
 		lvts_ctrl[i].high_thresh = INT_MIN;
 	}
@@ -919,7 +933,7 @@ static void lvts_write_config(struct lvts_ctrl *lvts_ctrl, const u32 *cmds, int
 	}
 }
 
-static int lvts_irq_init(struct lvts_ctrl *lvts_ctrl)
+static int lvts_irq_init(struct lvts_ctrl *lvts_ctrl, const struct lvts_data *lvts_data)
 {
 	/*
 	 * LVTS_PROTCTL : Thermal Protection Sensor Selection
@@ -947,6 +961,7 @@ static int lvts_irq_init(struct lvts_ctrl *lvts_ctrl)
 	 * writel(0x0, LVTS_PROTTB(lvts_ctrl->base));
 	 * writel(0x0, LVTS_PROTTC(lvts_ctrl->base));
 	 */
+	writel(lvts_ctrl->hw_tshut_raw_temp, LVTS_PROTTC(lvts_ctrl->base));
 
 	/*
 	 * LVTS_MONINT : Interrupt configuration register
@@ -954,7 +969,10 @@ static int lvts_irq_init(struct lvts_ctrl *lvts_ctrl)
 	 * The LVTS_MONINT register layout is the same as the LVTS_MONINTSTS
 	 * register, except we set the bits to enable the interrupt.
 	 */
-	writel(0, LVTS_MONINT(lvts_ctrl->base));
+	if (lvts_data->conf_stage3_need)
+		writel(LVTS_MONINT_CONF_STAGE3, LVTS_MONINT(lvts_ctrl->base));
+	else
+		writel(0, LVTS_MONINT(lvts_ctrl->base));
 
 	return 0;
 }
@@ -1041,7 +1059,8 @@ static int lvts_ctrl_calibrate(struct device *dev, struct lvts_ctrl *lvts_ctrl)
 	return 0;
 }
 
-static int lvts_ctrl_configure(struct device *dev, struct lvts_ctrl *lvts_ctrl)
+static int lvts_ctrl_configure(struct device *dev, struct lvts_ctrl *lvts_ctrl,
+			       const struct lvts_data *lvts_data)
 {
 	u32 value;
 
@@ -1143,7 +1162,7 @@ static int lvts_ctrl_configure(struct device *dev, struct lvts_ctrl *lvts_ctrl)
 	value = LVTS_FILTER_INTERVAL << 16 | LVTS_SENSOR_INTERVAL;
 	writel(value, LVTS_MONCTL2(lvts_ctrl->base));
 
-	return lvts_irq_init(lvts_ctrl);
+	return lvts_irq_init(lvts_ctrl, lvts_data);
 }
 
 static int lvts_ctrl_start(struct device *dev, struct lvts_ctrl *lvts_ctrl)
@@ -1290,7 +1309,7 @@ static int lvts_domain_init(struct device *dev, struct lvts_domain *lvts_td,
 			return ret;
 		}
 
-		ret = lvts_ctrl_configure(dev, lvts_ctrl);
+		ret = lvts_ctrl_configure(dev, lvts_ctrl, lvts_data);
 		if (ret) {
 			dev_dbg(dev, "Failed to configure controller");
 			return ret;
@@ -1322,9 +1341,13 @@ static int lvts_probe(struct platform_device *pdev)
 	if (!lvts_data)
 		return -ENODEV;
 
-	lvts_td->clk = devm_clk_get_enabled(dev, NULL);
-	if (IS_ERR(lvts_td->clk))
-		return dev_err_probe(dev, PTR_ERR(lvts_td->clk), "Failed to retrieve clock\n");
+	if (!lvts_data->clock_gate_no_need) {
+		lvts_td->clk = devm_clk_get_enabled(dev, NULL);
+		if (IS_ERR(lvts_td->clk))
+			return dev_err_probe(dev,
+					     PTR_ERR(lvts_td->clk),
+					     "Failed to retrieve clock\n");
+	}
 
 	res = platform_get_mem_or_io(pdev, 0);
 	if (!res)
@@ -1334,9 +1357,13 @@ static int lvts_probe(struct platform_device *pdev)
 	if (IS_ERR(lvts_td->base))
 		return dev_err_probe(dev, PTR_ERR(lvts_td->base), "Failed to map io resource\n");
 
-	lvts_td->reset = devm_reset_control_get_by_index(dev, 0);
-	if (IS_ERR(lvts_td->reset))
-		return dev_err_probe(dev, PTR_ERR(lvts_td->reset), "Failed to get reset control\n");
+	if (!lvts_data->reset_no_need) {
+		lvts_td->reset = devm_reset_control_get_exclusive(dev, NULL);
+		if (IS_ERR(lvts_td->reset))
+			return dev_err_probe(dev,
+					     PTR_ERR(lvts_td->reset),
+					     "Failed to get reset control\n");
+	}
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0)
@@ -1586,6 +1613,78 @@ static const struct lvts_ctrl_data mt8188_lvts_ap_data_ctrl[] = {
 	}
 };
 
+static const struct lvts_ctrl_data mt8189_lvts_mcu_data_ctrl[] = {
+	{
+		.lvts_sensor = {
+			{ .dt_id = MT8189_MCU_LITTLE_CPU1,
+			  .cal_offsets = { 4, 5, 6 } },
+			{ .dt_id = MT8189_MCU_LITTLE_CPU2,
+			  .cal_offsets = { 8, 9, 10 } },
+			{ .dt_id = MT8189_MCU_LITTLE_CPU3,
+			  .cal_offsets = { 12, 13, 14 } },
+			{ .dt_id = MT8189_MCU_LITTLE_CPU4,
+			  .cal_offsets = { 16, 17, 18 } }
+		},
+		VALID_SENSOR_MAP(1, 1, 1, 1),
+		.offset = 0x0,
+	},
+	{
+		.lvts_sensor = {
+			{ .dt_id = MT8189_MCU_LITTLE_CPU5,
+			  .cal_offsets = { 24, 25, 26 } },
+			{ .dt_id = MT8189_MCU_LITTLE_CPU6,
+			  .cal_offsets = { 28, 29, 30 } },
+			{ .dt_id = MT8189_MCU_LITTLE_CPU7,
+			  .cal_offsets = { 32, 33, 34 } },
+			{ .dt_id = MT8189_MCU_LITTLE_CPU8,
+			  .cal_offsets = { 36, 37, 38 } }
+		},
+		VALID_SENSOR_MAP(1, 1, 1, 1),
+		.offset = 0x100,
+	},
+	{
+		.lvts_sensor = {
+			{ .dt_id = MT8189_MCU_BIG_CPU1,
+			  .cal_offsets = { 44, 45, 46 } },
+			{ .dt_id = MT8189_MCU_BIG_CPU2,
+			  .cal_offsets = { 48, 49, 50 } },
+			{ .dt_id = MT8189_MCU_BIG_CPU3,
+			  .cal_offsets = { 52, 53, 54 } },
+			{ .dt_id = MT8189_MCU_BIG_CPU4,
+			  .cal_offsets = { 56, 57, 58 } }
+		},
+		VALID_SENSOR_MAP(1, 1, 1, 1),
+		.offset = 0x200,
+	}
+};
+
+static const struct lvts_ctrl_data mt8189_lvts_ap_data_ctrl[] = {
+	{
+		.lvts_sensor = {
+			{ .dt_id = MT8189_AP_SOC1,
+			  .cal_offsets = { 64, 65, 66 } },
+			{ .dt_id = MT8189_AP_SOC2,
+			  .cal_offsets = { 68, 69, 70 } },
+			{ .dt_id = MT8189_AP_SOC3,
+			  .cal_offsets = { 72, 73, 74 } },
+			{ .dt_id = MT8189_AP_APU,
+			  .cal_offsets = { 76, 77, 78 } }
+		},
+		VALID_SENSOR_MAP(1, 1, 1, 1),
+		.offset = 0x0,
+	},
+	{
+		.lvts_sensor = {
+			{ .dt_id = MT8189_AP_GPU1,
+			  .cal_offsets = { 84, 85, 86 } },
+			{ .dt_id = MT8189_AP_GPU2,
+			  .cal_offsets = { 88, 89, 90 } }
+		},
+		VALID_SENSOR_MAP(1, 1, 0, 0),
+		.offset = 0x100,
+	}
+};
+
 static const struct lvts_ctrl_data mt8192_lvts_mcu_data_ctrl[] = {
 	{
 		.lvts_sensor = {
@@ -1804,6 +1903,34 @@ static const struct lvts_data mt8188_lvts_ap_data = {
 	.def_calibration = 35000,
 };
 
+static const struct lvts_data mt8189_lvts_ap_data = {
+	.lvts_ctrl		= mt8189_lvts_ap_data_ctrl,
+	.conn_cmd		= default_conn_cmds,
+	.init_cmd		= default_init_cmds,
+	.num_lvts_ctrl		= ARRAY_SIZE(mt8189_lvts_ap_data_ctrl),
+	.num_conn_cmd		= ARRAY_SIZE(default_conn_cmds),
+	.num_init_cmd		= ARRAY_SIZE(default_init_cmds),
+	.temp_factor		= LVTS_COEFF_A_MT8195,
+	.temp_offset		= LVTS_COEFF_B_MT8195,
+	.gt_calib_bit_offset	= 0,
+	.def_calibration	= 35000,
+	.clock_gate_no_need	= true,
+	.reset_no_need		= true,
+	.conf_stage3_need	= true,
+};
+
+static const struct lvts_data mt8189_lvts_mcu_data = {
+	.lvts_ctrl		= mt8189_lvts_mcu_data_ctrl,
+	.num_lvts_ctrl		= ARRAY_SIZE(mt8189_lvts_mcu_data_ctrl),
+	.temp_factor		= LVTS_COEFF_A_MT8195,
+	.temp_offset		= LVTS_COEFF_B_MT8195,
+	.gt_calib_bit_offset	= 0,
+	.def_calibration	= 35000,
+	.clock_gate_no_need	= true,
+	.reset_no_need		= true,
+	.conf_stage3_need	= true,
+};
+
 static const struct lvts_data mt8192_lvts_mcu_data = {
 	.lvts_ctrl	= mt8192_lvts_mcu_data_ctrl,
 	.conn_cmd	= default_conn_cmds,
@@ -1861,6 +1988,8 @@ static const struct of_device_id lvts_of_match[] = {
 	{ .compatible = "mediatek,mt8186-lvts", .data = &mt8186_lvts_data },
 	{ .compatible = "mediatek,mt8188-lvts-mcu", .data = &mt8188_lvts_mcu_data },
 	{ .compatible = "mediatek,mt8188-lvts-ap", .data = &mt8188_lvts_ap_data },
+	{ .compatible = "mediatek,mt8189-lvts-mcu", .data = &mt8189_lvts_mcu_data },
+	{ .compatible = "mediatek,mt8189-lvts-ap", .data = &mt8189_lvts_ap_data },
 	{ .compatible = "mediatek,mt8192-lvts-mcu", .data = &mt8192_lvts_mcu_data },
 	{ .compatible = "mediatek,mt8192-lvts-ap", .data = &mt8192_lvts_ap_data },
 	{ .compatible = "mediatek,mt8195-lvts-mcu", .data = &mt8195_lvts_mcu_data },
-- 
2.45.2



From ardb at kernel.org  Tue Dec  2 01:15:22 2025
From: ardb at kernel.org (Ard Biesheuvel)
Date: Tue, 2 Dec 2025 10:15:22 +0100
Subject: [RFC PATCH v1 2/2] randomize_kstack: Unify random source across arches
In-Reply-To: <9097505d-b18b-4f85-a02c-7f2865ad8bca@arm.com>
References: <20251127105958.2427758-1-ryan.roberts@arm.com>
 <20251127105958.2427758-3-ryan.roberts@arm.com> <CAMj1kXFY1RXk8T4f46bkm_sr0nJfBoO+ii68JK4+CsRiDwKdCg@mail.gmail.com>
 <9097505d-b18b-4f85-a02c-7f2865ad8bca@arm.com>
Message-ID: <CAMj1kXHX1W2Kz5NJehtzDhOCKWEd6y1sp8+ViOMHGsq9e8=7Pw@mail.gmail.com>

On Mon, 1 Dec 2025 at 19:20, Ryan Roberts <ryan.roberts at arm.com> wrote:
>
> On 28/11/2025 11:01, Ard Biesheuvel wrote:
> > On Thu, 27 Nov 2025 at 12:00, Ryan Roberts <ryan.roberts at arm.com> wrote:
> >>
> >> Previously different architectures were using random sources of
> >> differing strength and cost to decide the random kstack offset. A number
> >> of architectures (loongarch, powerpc, s390, x86) were using their
> >> timestamp counter, at whatever the frequency happened to be. Other
> >> arches (arm64, riscv) were using entropy from the crng via
> >> get_random_u16().
> >>
> >> There have been concerns that in some cases the timestamp counters may
> >> be too weak, because they can be easily guessed or influenced by user
> >> space. And get_random_u16() has been shown to be too costly for the
> >> level of protection kstack offset randomization provides.
> >>
> >> So let's use a common, architecture-agnostic source of entropy; a
> >> per-task prng, seeded at fork-time from the crng. This has a few
> >> benefits:
> >>
> >>   - We can remove choose_random_kstack_offset(); That was only there to
> >>     try to make the timestamp counter value a bit harder to influence
> >>     from user space.
> >>
> >>   - The architecture code is simplified. All it has to do now is call
> >>     add_random_kstack_offset() in the syscall path.
> >>
> >>   - The strength of the randomness can be reasoned about independently
> >>     of the architecture.
> >>
> >>   - Arches previously using get_random_u16() now have much faster
> >>     syscall paths, see below results.
> >>
> >> There have been some claims that a prng may be less strong than the
> >> timestamp counter if not regularly reseeded. But the prng has a period
> >> of about 2^113. So as long as the prng state remains secret, it should
> >> not be possible to guess. If the prng state can be accessed, we have
> >> bigger problems.
> >>
> >> Additionally, we are only consuming 6 bits to randomize the stack, so
> >> there are only 64 possible random offsets. I assert that it would be
> >> trivial for an attacker to brute force by repeating their attack and
> >> waiting for the random stack offset to be the desired one. The prng
> >> approach seems entirely proportional to this level of protection.
> >>
> >> Performance data are provided below. The baseline is v6.18-rc5 with
> >> rndstack on for each respective arch. (I)/(R) indicate statistically
> >> significant improvement/regression. arm64 platform is AWS Graviton3.
> >> x86_64 platform is AWS Sapphire Rapids:
> >>
> >> +-----------------+--------------+---------------+---------------+
> >> | Benchmark       | Result Class | per-task-prng | per-task-prng |
> >> |                 |              |         arm64 |        x86_64 |
> >> +=================+==============+===============+===============+
> >> | syscall/getpid  | mean (ns)    |   (I) -10.54% |    (I) -7.69% |
> >> |                 | p99 (ns)     |   (I) -59.53% |         4.14% |
> >> |                 | p99.9 (ns)   |   (I) -59.90% |         2.68% |
> >> +-----------------+--------------+---------------+---------------+
> >> | syscall/getppid | mean (ns)    |   (I) -10.49% |    (I) -5.98% |
> >> |                 | p99 (ns)     |   (I) -59.83% |        -3.11% |
> >> |                 | p99.9 (ns)   |   (I) -59.88% |     (R) 9.84% |
> >> +-----------------+--------------+---------------+---------------+
> >> | syscall/invalid | mean (ns)    |    (I) -9.28% |    (I) -6.94% |
> >> |                 | p99 (ns)     |   (I) -61.06% |    (I) -5.57% |
> >> |                 | p99.9 (ns)   |   (I) -61.40% |    (R) 10.53% |
> >> +-----------------+--------------+---------------+---------------+
> >>
> >> Signed-off-by: Ryan Roberts <ryan.roberts at arm.com>
> >> ---
> >>  arch/Kconfig                         |  5 ++--
> >>  arch/arm64/kernel/syscall.c          | 11 -------
> >>  arch/loongarch/kernel/syscall.c      | 11 -------
> >>  arch/powerpc/kernel/syscall.c        | 12 --------
> >>  arch/riscv/kernel/traps.c            | 12 --------
> >>  arch/s390/include/asm/entry-common.h |  8 ------
> >>  arch/x86/include/asm/entry-common.h  | 12 --------
> >>  include/linux/prandom.h              |  7 ++++-
> >>  include/linux/randomize_kstack.h     | 43 ++++++++--------------------
> >>  include/linux/sched.h                |  3 +-
> >>  10 files changed, 22 insertions(+), 102 deletions(-)
> >>
> >
> > I think this is a substantial improvement over the status quo,
> > especially with all the dodgy uses of monotonic counters with
> > unspecified granularity.
> >
> > So with two comments below:
> >
> > Reviewed-by: Ard Biesheuvel <ardb at kernel.org>
>
> Thanks!
>
> I shall plan to re-post without the RFC tag against -rc1 then, and we will see
> if anyone pushes back.
>

Sounds good.

...
> >> diff --git a/include/linux/prandom.h b/include/linux/prandom.h
> >> index f2ed5b72b3d6..827edde11cb9 100644
> >> --- a/include/linux/prandom.h
> >> +++ b/include/linux/prandom.h
> >> @@ -10,13 +10,18 @@
> >>
> >>  #include <linux/types.h>
> >>  #include <linux/once.h>
> >> -#include <linux/percpu.h>
> >>  #include <linux/random.h>
> >>
> >>  struct rnd_state {
> >>         __u32 s1, s2, s3, s4;
> >>  };
> >>
> >> +/*
> >> + * percpu.h includes sched.h, which requires struct rnd_state. So defer until
> >> + * after struct rnd_state is defined.
> >> + */
> >> +#include <linux/percpu.h>
> >> +
> >
> > Yuck. Is this the best we can do to disentangle this?
>
> I think I might be able to remove some stuff out of sched.h into alloc_tag.h
> (looks to me like it should have been there all along). And that will allow
> removing the sched.h include from percpu.h. I think that will solve it.
>

OK.

> >> diff --git a/include/linux/randomize_kstack.h b/include/linux/randomize_kstack.h
> >> index 089b1432f7e6..83c7e6710f6d 100644
> >> --- a/include/linux/randomize_kstack.h
> >> +++ b/include/linux/randomize_kstack.h
> >> @@ -6,6 +6,7 @@
> >>  #include <linux/kernel.h>
> >>  #include <linux/jump_label.h>
> >>  #include <linux/percpu-defs.h>
> >> +#include <linux/prandom.h>
> >>
> >>  DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
> >>                          randomize_kstack_offset);
> >> @@ -45,9 +46,13 @@ DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
> >>  #define KSTACK_OFFSET_MAX(x)   ((x) & 0b1111111100)
> >>  #endif
> >>
> >> +static __always_inline u32 get_update_kstack_offset(void)
> >> +{
> >> +       return prandom_u32_state(&current->kstack_rnd_state);
>
> I've got bot warnings because this is being called from noinstr code. I guess
> the best option is to just move add_random_kstack_offset() to after
> instrumentation is enabled for the affected arches.
>

Just put instrumentation_begin()/instrumentation_end() around the call
to prandom_u32_state() - that seems to be the common approach for
punching holes into the 'noinstr' validation.


> >> +}
> >> +
> >>  /**
> >> - * add_random_kstack_offset - Increase stack utilization by previously
> >> - *                           chosen random offset
> >> + * add_random_kstack_offset - Increase stack utilization by a random offset.
> >>   *
> >>   * This should be used in the syscall entry path after user registers have been
> >>   * stored to the stack. Preemption may be enabled. For testing the resulting
> >> @@ -56,46 +61,22 @@ DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
> >>  #define add_random_kstack_offset() do {                                        \
> >>         if (static_branch_maybe(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT, \
> >>                                 &randomize_kstack_offset)) {            \
> >> -               u32 offset = current->kstack_offset;                    \
> >> +               u32 offset = get_update_kstack_offset();                \
> >>                 u8 *ptr = __kstack_alloca(KSTACK_OFFSET_MAX(offset));   \
> >>                 /* Keep allocation even after "ptr" loses scope. */     \
> >>                 asm volatile("" :: "r"(ptr) : "memory");                \
> >>         }                                                               \
> >>  } while (0)
> >>
> >> -/**
> >> - * choose_random_kstack_offset - Choose the random offset for the next
> >> - *                              add_random_kstack_offset()
> >> - *
> >> - * This should only be used during syscall exit. Preemption may be enabled. This
> >> - * position in the syscall flow is done to frustrate attacks from userspace
> >> - * attempting to learn the next offset:
> >> - * - Maximize the timing uncertainty visible from userspace: if the
> >> - *   offset is chosen at syscall entry, userspace has much more control
> >> - *   over the timing between choosing offsets. "How long will we be in
> >> - *   kernel mode?" tends to be more difficult to predict than "how long
> >> - *   will we be in user mode?"
> >> - * - Reduce the lifetime of the new offset sitting in memory during
> >> - *   kernel mode execution. Exposure of "thread-local" memory content
> >> - *   (e.g. current, percpu, etc) tends to be easier than arbitrary
> >> - *   location memory exposure.
> >> - */
> >> -#define choose_random_kstack_offset(rand) do {                         \
> >> -       if (static_branch_maybe(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT, \
> >> -                               &randomize_kstack_offset)) {            \
> >> -               u32 offset = current->kstack_offset;                    \
> >> -               offset = ror32(offset, 5) ^ (rand);                     \
> >> -               current->kstack_offset = offset;                        \
> >> -       }                                                               \
> >> -} while (0)
> >> -
> >>  static inline void random_kstack_task_init(struct task_struct *tsk)
> >>  {
> >> -       current->kstack_offset = 0;
> >> +       if (static_branch_maybe(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
> >> +                               &randomize_kstack_offset)) {
> >> +               prandom_seed_state(&tsk->kstack_rnd_state, get_random_u64());
> >
> > We should either fix prandom_seed_state() not to truncate the u64 to
> > u32, or even better, refactor prandom_seed_full_state() so we can
> > reuse it here, and use a 128-bit seed directly.
>
> How about something like this:
>

Looks good to me, but it does make we wonder why a full prandom state
(i.e., one per cpu) isn't sufficient here, and why we are putting one
in every task. Is it just to avoid the overhead of dis/enabling
preemption on every syscall entry?





>
> ---8<---
> diff --git a/include/linux/prandom.h b/include/linux/prandom.h
> index f2ed5b72b3d6..9b651c9b3448 100644
> --- a/include/linux/prandom.h
> +++ b/include/linux/prandom.h
> @@ -19,10 +19,11 @@ struct rnd_state {
>
>  u32 prandom_u32_state(struct rnd_state *state);
>  void prandom_bytes_state(struct rnd_state *state, void *buf, size_t nbytes);
> -void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state);
> +void prandom_seed_full_state_one(struct rnd_state *state);
> +void prandom_seed_full_state_all(struct rnd_state __percpu *pcpu_state);
>
>  #define prandom_init_once(pcpu_state)                  \
> -       DO_ONCE(prandom_seed_full_state, (pcpu_state))
> +       DO_ONCE(prandom_seed_full_state_all, (pcpu_state))
>
>  /*
>   * Handle minimum values for seeds
> diff --git a/lib/random32.c b/lib/random32.c
> index 24e7acd9343f..50d8f5f9fca7 100644
> --- a/lib/random32.c
> +++ b/lib/random32.c
> @@ -107,24 +107,28 @@ static void prandom_warmup(struct rnd_state *state)
>         prandom_u32_state(state);
>  }
>
> -void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state)
> +void prandom_seed_full_state_one(struct rnd_state *state)
>  {
> -       int i;
> +       u32 seeds[4];
>
> -       for_each_possible_cpu(i) {
> -               struct rnd_state *state = per_cpu_ptr(pcpu_state, i);
> -               u32 seeds[4];
> +       get_random_bytes(&seeds, sizeof(seeds));
> +       state->s1 = __seed(seeds[0],   2U);
> +       state->s2 = __seed(seeds[1],   8U);
> +       state->s3 = __seed(seeds[2],  16U);
> +       state->s4 = __seed(seeds[3], 128U);
>
> -               get_random_bytes(&seeds, sizeof(seeds));
> -               state->s1 = __seed(seeds[0],   2U);
> -               state->s2 = __seed(seeds[1],   8U);
> -               state->s3 = __seed(seeds[2],  16U);
> -               state->s4 = __seed(seeds[3], 128U);
> +       prandom_warmup(state);
> +}
> +EXPORT_SYMBOL(prandom_seed_full_state_one);
>
> -               prandom_warmup(state);
> -       }
> +void prandom_seed_full_state_all(struct rnd_state __percpu *pcpu_state)
> +{
> +       int i;
> +
> +       for_each_possible_cpu(i)
> +               prandom_seed_full_state_one(per_cpu_ptr(pcpu_state, i));
>  }
> -EXPORT_SYMBOL(prandom_seed_full_state);
> +EXPORT_SYMBOL(prandom_seed_full_state_all);
>
>  #ifdef CONFIG_RANDOM32_SELFTEST
>  static struct prandom_test1 {
> ---8<---
>


From james.clark at linaro.org  Tue Dec  2 01:26:19 2025
From: james.clark at linaro.org (James Clark)
Date: Tue, 2 Dec 2025 09:26:19 +0000
Subject: [PATCH v3] coresight: etm3x: Fix cntr_val_show() to match
 cntr_val_store() behavior
In-Reply-To: <20251202082613.3265761-1-visitorckw@gmail.com>
References: <20251202082613.3265761-1-visitorckw@gmail.com>
Message-ID: <3bec7ceb-61a8-4b38-a794-02ee2fc9e68c@linaro.org>



On 02/12/2025 8:26 am, Kuan-Wei Chiu wrote:
> The cntr_val_show() function was intended to print the values of all
> counters using a loop. However, due to a buffer overwrite issue with
> sprintf(), it effectively only displayed the value of the last counter.
> 
> The companion function, cntr_val_store(), allows users to modify a
> specific counter selected by 'cntr_idx'. To maintain consistency
> between read and write operations and to align with the ETM4x driver
> behavior, modify cntr_val_show() to report only the value of the
> currently selected counter.
> 
> This change removes the loop and the "counter %d:" prefix, printing
> only the hexadecimal value. It also adopts sysfs_emit() for standard
> sysfs output formatting.
> 
> Fixes: a939fc5a71ad ("coresight-etm: add CoreSight ETM/PTM driver")
> Cc: stable at vger.kernel.org
> Signed-off-by: Kuan-Wei Chiu <visitorckw at gmail.com>
> ---
> Build test only.
> 
> Changes in v3:
> - Switch format specifier to %#x to include the 0x prefix.
> - Add Cc stable
> 
> v2: https://lore.kernel.org/lkml/20251201095228.1905489-1-visitorckw at gmail.com/
> 
>   .../hwtracing/coresight/coresight-etm3x-sysfs.c   | 15 ++++-----------
>   1 file changed, 4 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
> index 762109307b86..b3c67e96a82a 100644
> --- a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
> +++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
> @@ -717,26 +717,19 @@ static DEVICE_ATTR_RW(cntr_rld_event);
>   static ssize_t cntr_val_show(struct device *dev,
>   			     struct device_attribute *attr, char *buf)
>   {
> -	int i, ret = 0;
>   	u32 val;
>   	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
>   	struct etm_config *config = &drvdata->config;
>   
>   	if (!coresight_get_mode(drvdata->csdev)) {
>   		spin_lock(&drvdata->spinlock);
> -		for (i = 0; i < drvdata->nr_cntr; i++)
> -			ret += sprintf(buf, "counter %d: %x\n",
> -				       i, config->cntr_val[i]);
> +		val = config->cntr_val[config->cntr_idx];
>   		spin_unlock(&drvdata->spinlock);
> -		return ret;
> -	}
> -
> -	for (i = 0; i < drvdata->nr_cntr; i++) {
> -		val = etm_readl(drvdata, ETMCNTVRn(i));
> -		ret += sprintf(buf, "counter %d: %x\n", i, val);
> +	} else {
> +		val = etm_readl(drvdata, ETMCNTVRn(config->cntr_idx));
>   	}
>   
> -	return ret;
> +	return sysfs_emit(buf, "%#x\n", val);
>   }
>   
>   static ssize_t cntr_val_store(struct device *dev,

Reviewed-by: James Clark <james.clark at linaro.org>



From gregkh at linuxfoundation.org  Tue Dec  2 01:27:38 2025
From: gregkh at linuxfoundation.org (Greg Kroah-Hartman)
Date: Tue, 2 Dec 2025 10:27:38 +0100
Subject: [PATCH v8 2/2] usb: dwc3: Add Google Tensor SoC DWC3 glue driver
In-Reply-To: <CA+zupgwzQ5r=-_L79D74=9VRqRO94N0yTApHChM+Nu0cn1ss3w@mail.gmail.com>
References: <20251122-controller-v8-0-e7562e0df658@google.com>
 <20251122-controller-v8-2-e7562e0df658@google.com>
 <2025112226-heave-refrain-53e6@gregkh>
 <CA+zupgwzQ5r=-_L79D74=9VRqRO94N0yTApHChM+Nu0cn1ss3w@mail.gmail.com>
Message-ID: <2025120209-unstylish-john-2a6c@gregkh>

On Tue, Dec 02, 2025 at 03:01:13AM -0600, Roy Luo wrote:
> On Sat, Nov 22, 2025 at 8:59?PM Greg Kroah-Hartman
> <gregkh at linuxfoundation.org> wrote:
> >
> > On Sat, Nov 22, 2025 at 09:32:06AM +0000, Roy Luo wrote:
> > > Add support for the DWC3 USB controller found on Google Tensor G5
> > > (codename: laguna). The controller features dual-role functionality
> > > and hibernation.
> > >
> > > The primary focus is implementing hibernation support in host mode,
> > > enabling the controller to enter a low-power state (D3). This is
> > > particularly relevant during system power state transition and
> > > runtime power management for power efficiency.
> > > Highlights:
> > > - Align suspend callback with dwc3_suspend_common() for deciding
> > >   between a full teardown and hibernation in host mode.
> > > - Integration with `psw` (power switchable) and `top` power domains,
> > >   managing their states and device links to support hibernation.
> > > - A notifier callback dwc3_google_usb_psw_pd_notifier() for
> > >   `psw` power domain events to manage controller state
> > >   transitions to/from D3.
> > > - Coordination of the `non_sticky` reset during power state
> > >   transitions, asserting it on D3 entry and deasserting on D0 entry
> > >   in hibernation scenario.
> > > - Handling of high-speed and super-speed PME interrupts
> > >   that are generated by remote wakeup during hibernation.
> > >
> > > Co-developed-by: Joy Chakraborty <joychakr at google.com>
> > > Signed-off-by: Joy Chakraborty <joychakr at google.com>
> > > Co-developed-by: Naveen Kumar <mnkumar at google.com>
> > > Signed-off-by: Naveen Kumar <mnkumar at google.com>
> > > Signed-off-by: Roy Luo <royluo at google.com>
> > > ---
> > >  drivers/usb/dwc3/Kconfig       |  13 +
> > >  drivers/usb/dwc3/Makefile      |   1 +
> > >  drivers/usb/dwc3/dwc3-google.c | 628 +++++++++++++++++++++++++++++++++++++++++
> > >  3 files changed, 642 insertions(+)
> > >
> > > diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
> > > index 4925d15084f816d3ff92059b476ebcc799b56b51..f58c70dabf108878cbefe0abea88572d9ae81e26 100644
> > > --- a/drivers/usb/dwc3/Kconfig
> > > +++ b/drivers/usb/dwc3/Kconfig
> > > @@ -200,4 +200,17 @@ config USB_DWC3_GENERIC_PLAT
> > >         the dwc3 child node in the device tree.
> > >         Say 'Y' or 'M' here if your platform integrates DWC3 in a similar way.
> > >
> > > +config USB_DWC3_GOOGLE
> > > +     tristate "Google Platform"
> > > +     depends on COMPILE_TEST
> > > +     depends on OF && COMMON_CLK && RESET_CONTROLLER
> >
> > Shouldn't this be:
> >         depends on (OF && COMMON_CLK && RESET_CONTROLLER) || COMPILE_TEST
> >
> > I shouldn't have to enable those options to just get a build test here,
> > the apis should be properly stubbed out if those options are not
> > enabled, right?
> >
> > thanks,
> >
> > greg k-h
> 
> Hi Greg,
> 
> I agree with your interpretation of COMPILE_TEST but it doesn't
> seem to align with upstream convention. I found the following pattern
> in several device driver Kconfig files (including but not limited to usb,
> pinctrl and phy).
> 
>     depends on COMPILE_TEST || ARCH_XXX
>     depends on CONFIG_A && CONFIG_B...
> 
> For this patch, the APIs exposed by OF, COMMON_CLK
> and RESET_CONTROLLER are properly stubbed out so
> I'm all good to go with your suggestion, but I'd like to make
> sure this approach is conventional.

Whatever works for building properly, as-is, what you have in this patch
didn't work for my systems at all.

> I plan to add ARCH_GOOGLE as a dependency in the next
> version per [1], so the "depends on" would probably look like
> the following per your suggestion:

But "Google" is not an arch :(

And really, the whole "only have a sub-arch symbol" is something that
personally, I think is totally wrong and prevents kernel images from
being built for more than one "arch".  As an example, the Android GKI
kernel has to support more than one of these, so what does putting this
behind a symbol that no one will actually use mean anything?  Android
will never be only building a ARCH_GOOGLE kernel.

>     depends on (OF && COMMON_CLK && RESET_CONTROLLER && ARCH_GOOGLE)
> || COMPILE_TEST
> 
> Please let me know your thoughts.
> [1] https://lore.kernel.org/linux-phy/1a53d473-fc13-4ac5-ba52-4701d95e3073 at kernel.org/

Again, I hate the ARCH_ stuff, but Krzysztof does seem to like it for
some reason, so I'll defer to others here.  But note, as someone who
helps maintain a "generic" ARM64 kernel, these ARCH_* usages for
different platforms do nothing at all to help anyone out.

thanks,

greg k-h


From youngmin.nam at samsung.com  Tue Dec  2 01:36:07 2025
From: youngmin.nam at samsung.com (Youngmin Nam)
Date: Tue,  2 Dec 2025 18:36:07 +0900
Subject: [PATCH v3 0/5] pinctrl: samsung: exynos9 cleanups and fixes
References: <CGME20251202093024epcas2p1567dddf09e3599867e9dc14a9a234d38@epcas2p1.samsung.com>
Message-ID: <20251202093613.852109-1-youngmin.nam@samsung.com>

Several SoCs carried near-duplicate pin bank macro families, making
tables verbose and hard to share when only the bank type (alive/off)
differs.

GS101 had its own helpers even though the newer EXYNOS9_* helpers cover
the same semantics, including per-bank filter control (FLTCON) offsets.

Some pin-bank tables didn't match the SoC TRMs (bank type, EINT class,
or bank names), and FLTCON wasn't always at a contiguous offset from
EINT.

This series does
- Consolidate on EXYNOS9_* pin-bank macros. Pass bank_type explicitly.
- Fix table errors on Exynos2200/7885/8890/8895 per TRM.
- Add explicit per-bank FLTCON offsets and update affected tables.
- Drop GS101-specific macros in favor of EXYNOS9_*.
- Rename gs101_pinctrl_{suspend,resume} ->
  exynos9_pinctrl_{suspend,resume}.

This series was based on the pinctrl/samsung tree [1].

I tested on Exynos850 through boot and verified the pin values as
follows:

$:/sys/kernel/debug/pinctrl/139b0000.pinctrl-samsung-pinctrl# cat pins
registered pins: 42
pin 0 (gpg0-0) 0:gpg0 CON(0x0) DAT(0x0) PUD(0x1) DRV(0x2) CON_PDN(0x2) PUD_PDN(0x1)
pin 1 (gpg0-1) 1:gpg0 CON(0x0) DAT(0x0) PUD(0x1) DRV(0x2) CON_PDN(0x2) PUD_PDN(0x1)
...

Additional testing on the affected Exynos9-era platforms would be
appreciated.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/samsung.git

Changes in v2:
  - Added base tree for this series (pinctrl/samsung).
  - Renamed the macro parameter from 'types' to 'bank_type' for clarity
    (struct member remains 'type').
  - Reflowed commit messages (wrap at ~72 cols).
  - Replaced non-ASCII characters with ASCII equivalents.
  - Collected tags:
      Reviewed-by: Sam Protsenko <semen.protsenko at linaro.org>
      Tested-by: Sam Protsenko <semen.protsenko at linaro.org>
  - Normalized hex literals to lowercase and removed double spaces.
  - Aligned backslashes in macro definitions to form a vertical column
    for readability.
  - Added missing mailing lists (including linux-kernel) to Cc per
    scripts/get_maintainer.pl.

Changes in v3:
  - Collected tags:
      Reviewed-by: Peter Griffin <peter.griffin at linaro.org>
      Tested-by: Peter Griffin <peter.griffin at linaro.org> (tested on Pixel6/gs101)

Youngmin Nam (5):
  pinctrl: samsung: Consolidate pin-bank macros under EXYNOS9_* and pass
    bank_type explicitly
  pinctrl: samsung: fix incorrect pin-bank entries on
    Exynos2200/7885/8890/8895
  pinctrl: samsung: add per-bank FLTCON offset to EXYNOS9_PIN_BANK_* and
    fix tables
  pinctrl: samsung: fold GS101 pin-bank macros into EXYNOS9_*
  pinctrl: samsung: rename gs101_pinctrl_* to exynos9_pinctrl_*

 .../pinctrl/samsung/pinctrl-exynos-arm64.c    | 1069 ++++++++---------
 drivers/pinctrl/samsung/pinctrl-exynos.c      |    4 +-
 drivers/pinctrl/samsung/pinctrl-exynos.h      |   97 +-
 drivers/pinctrl/samsung/pinctrl-samsung.h     |    4 +-
 4 files changed, 562 insertions(+), 612 deletions(-)

-- 
2.52.0



From youngmin.nam at samsung.com  Tue Dec  2 01:36:08 2025
From: youngmin.nam at samsung.com (Youngmin Nam)
Date: Tue,  2 Dec 2025 18:36:08 +0900
Subject: [PATCH v3 1/5] pinctrl: samsung: Consolidate pin-bank macros under
 EXYNOS9_* and pass bank_type explicitly
In-Reply-To: <20251202093613.852109-1-youngmin.nam@samsung.com>
References: <20251202093613.852109-1-youngmin.nam@samsung.com>
	<CGME20251202093026epcas2p28ddfd32305695df996841fd73b231b6b@epcas2p2.samsung.com>
Message-ID: <20251202093613.852109-2-youngmin.nam@samsung.com>

Modern Exynos platforms have several near-duplicate pin-bank macro
families (EXYNOS850_*, EXYNOS8895_*, EXYNOS7870_*), which makes
tables verbose and harder to share across SoCs that differ only by
bank_type (alive/off) layout.

This patch unifies them into one EXYNOS9_* macro family and makes the
bank_type an explicit argument. The common 850-era bank types are also
renamed to 'exynos9_bank_type_{alive,off}' to reflect their reuse on
later Exynos 9xxx-generation parts.

Naming rationale:
- Use of the EXYNOS9_* prefix indicates that these macros target
  current Exynos generations sharing the same register layout and
  EINT wiring model. Compared to SoC-specific prefixes
  (EXYNOS850_*, EXYNOS8895_*),
  EXYNOS9_* is clearer and more future-proof for modern parts.

Key changes:
- Introduce:
  - 'EXYNOS9_PIN_BANK_EINTN(bank_type, pins, reg, id)'
  - 'EXYNOS9_PIN_BANK_EINTG(bank_type, pins, reg, id, offs)'
  - 'EXYNOS9_PIN_BANK_EINTW(bank_type, pins, reg, id, offs)'
- Rename:
  - 'exynos850_bank_type_alive'-> 'exynos9_bank_type_alive'
  - 'exynos850_bank_type_off'  -> 'exynos9_bank_type_off'
- Convert pin-bank tables for:
  - Exynos2200, 7870, 7885, 850, 990, 9810, 8890, 8895,
    AutoV9, AutoV920, FSD
- Update GS101/EXYNOSV920 helpers to reference 'exynos9_bank_type_*'
  instead of the old exynos850 names.
- Standardize on EXYNOS9_* macros while keeping SoC-specific
  '*_bank_type_*' when layouts differ (e.g., 7870/8895).

No functional change intended.

Signed-off-by: Youngmin Nam <youngmin.nam at samsung.com>
Reviewed-by: Sam Protsenko <semen.protsenko at linaro.org>
Tested-by: Sam Protsenko <semen.protsenko at linaro.org>
---
 .../pinctrl/samsung/pinctrl-exynos-arm64.c    | 785 +++++++++---------
 drivers/pinctrl/samsung/pinctrl-exynos.h      |  49 +-
 2 files changed, 402 insertions(+), 432 deletions(-)

diff --git a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
index 627dca504d7a..d11b2d4ca913 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
+++ b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
@@ -53,7 +53,7 @@ static const struct samsung_pin_bank_type exynos7870_bank_type_alive = {
  * Bank type for non-alive type. Bit fields:
  * CON: 4, DAT: 1, PUD: 4, DRV: 4, CONPDN: 2, PUDPDN: 4
  */
-static const struct samsung_pin_bank_type exynos850_bank_type_off  = {
+static const struct samsung_pin_bank_type exynos9_bank_type_off = {
 	.fld_width = { 4, 1, 4, 4, 2, 4, },
 	.reg_offset = { 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, },
 };
@@ -62,7 +62,7 @@ static const struct samsung_pin_bank_type exynos850_bank_type_off  = {
  * Bank type for alive type. Bit fields:
  * CON: 4, DAT: 1, PUD: 4, DRV: 4
  */
-static const struct samsung_pin_bank_type exynos850_bank_type_alive = {
+static const struct samsung_pin_bank_type exynos9_bank_type_alive = {
 	.fld_width = { 4, 1, 4, 4, },
 	.reg_offset = { 0x00, 0x04, 0x08, 0x0c, },
 };
@@ -90,11 +90,11 @@ static atomic_t exynos_shared_retention_refcnt;
 
 /* pin banks of exynos2200 pin-controller - ALIVE */
 static const struct samsung_pin_bank_data exynos2200_pin_banks0[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTW(8, 0x0, "gpa0", 0x00),
-	EXYNOS850_PIN_BANK_EINTW(8, 0x20, "gpa1", 0x04),
-	EXYNOS850_PIN_BANK_EINTW(8, 0x40, "gpa2", 0x08),
-	EXYNOS850_PIN_BANK_EINTW(8, 0x60, "gpa3", 0x0c),
-	EXYNOS850_PIN_BANK_EINTW(2, 0x80, "gpa4", 0x10),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x0, "gpa0", 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x20, "gpa1", 0x04),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x40, "gpa2", 0x08),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x60, "gpa3", 0x0c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x80, "gpa4", 0x10),
 	EXYNOS_PIN_BANK_EINTN(4, 0xa0, "gpq0"),
 	EXYNOS_PIN_BANK_EINTN(2, 0xc0, "gpq1"),
 	EXYNOS_PIN_BANK_EINTN(2, 0xe0, "gpq2"),
@@ -102,90 +102,90 @@ static const struct samsung_pin_bank_data exynos2200_pin_banks0[] __initconst =
 
 /* pin banks of exynos2200 pin-controller - CMGP */
 static const struct samsung_pin_bank_data exynos2200_pin_banks1[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTW(2, 0x0, "gpm0", 0x00),
-	EXYNOS850_PIN_BANK_EINTW(2, 0x20, "gpm1", 0x04),
-	EXYNOS850_PIN_BANK_EINTW(2, 0x40, "gpm2", 0x08),
-	EXYNOS850_PIN_BANK_EINTW(2, 0x60, "gpm3", 0x0c),
-	EXYNOS850_PIN_BANK_EINTW(2, 0x80, "gpm4", 0x10),
-	EXYNOS850_PIN_BANK_EINTW(2, 0xa0, "gpm5", 0x14),
-	EXYNOS850_PIN_BANK_EINTW(2, 0xc0, "gpm6", 0x18),
-	EXYNOS850_PIN_BANK_EINTW(2, 0xe0, "gpm7", 0x1c),
-	EXYNOS850_PIN_BANK_EINTW(2, 0x100, "gpm8", 0x20),
-	EXYNOS850_PIN_BANK_EINTW(2, 0x120, "gpm9", 0x24),
-	EXYNOS850_PIN_BANK_EINTW(2, 0x140, "gpm10", 0x28),
-	EXYNOS850_PIN_BANK_EINTW(2, 0x160, "gpm11", 0x2c),
-	EXYNOS850_PIN_BANK_EINTW(2, 0x180, "gpm12", 0x30),
-	EXYNOS850_PIN_BANK_EINTW(2, 0x1a0, "gpm13", 0x34),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x1c0, "gpm14", 0x38),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x1e0, "gpm15", 0x3c),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x200, "gpm16", 0x40),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x220, "gpm17", 0x44),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x240, "gpm20", 0x48),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x260, "gpm21", 0x4c),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x280, "gpm22", 0x50),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x2a0, "gpm23", 0x54),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x2c0, "gpm24", 0x58),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x0, "gpm0", 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x20, "gpm1", 0x04),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x40, "gpm2", 0x08),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x60, "gpm3", 0x0c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x80, "gpm4", 0x10),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0xa0, "gpm5", 0x14),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0xc0, "gpm6", 0x18),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0xe0, "gpm7", 0x1c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x100, "gpm8", 0x20),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x120, "gpm9", 0x24),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x140, "gpm10", 0x28),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x160, "gpm11", 0x2c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x180, "gpm12", 0x30),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x1a0, "gpm13", 0x34),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x1c0, "gpm14", 0x38),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x1e0, "gpm15", 0x3c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x200, "gpm16", 0x40),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x220, "gpm17", 0x44),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x240, "gpm20", 0x48),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x260, "gpm21", 0x4c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x280, "gpm22", 0x50),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x2a0, "gpm23", 0x54),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x2c0, "gpm24", 0x58),
 };
 
 /* pin banks of exynos2200 pin-controller - HSI1 */
 static const struct samsung_pin_bank_data exynos2200_pin_banks2[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTG(4, 0x0, "gpf0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0, "gpf0", 0x00),
 };
 
 /* pin banks of exynos2200 pin-controller - UFS */
 static const struct samsung_pin_bank_data exynos2200_pin_banks3[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTG(7, 0x0, "gpf1", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x0, "gpf1", 0x00),
 };
 
 /* pin banks of exynos2200 pin-controller - HSI1UFS */
 static const struct samsung_pin_bank_data exynos2200_pin_banks4[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTG(2, 0x0, "gpf2", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x0, "gpf2", 0x00),
 };
 
 /* pin banks of exynos2200 pin-controller - PERIC0 */
 static const struct samsung_pin_bank_data exynos2200_pin_banks5[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTG(4, 0x0, "gpb0",  0x00),
-	EXYNOS850_PIN_BANK_EINTG(4, 0x20, "gpb1",  0x04),
-	EXYNOS850_PIN_BANK_EINTG(4, 0x40, "gpb2",  0x08),
-	EXYNOS850_PIN_BANK_EINTG(4, 0x60, "gpb3",  0x0c),
-	EXYNOS850_PIN_BANK_EINTG(4, 0x80, "gpp4",  0x10),
-	EXYNOS850_PIN_BANK_EINTG(2, 0xa0, "gpc0",  0x14),
-	EXYNOS850_PIN_BANK_EINTG(2, 0xc0, "gpc1",  0x18),
-	EXYNOS850_PIN_BANK_EINTG(2, 0xe0, "gpc2",  0x1c),
-	EXYNOS850_PIN_BANK_EINTG(7, 0x100, "gpg1",  0x20),
-	EXYNOS850_PIN_BANK_EINTG(2, 0x120, "gpg2",  0x24),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0, "gpb0",  0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x20, "gpb1",  0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x40, "gpb2",  0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x60, "gpb3",  0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x80, "gpp4",  0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0xa0, "gpc0",  0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0xc0, "gpc1",  0x18),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0xe0, "gpc2",  0x1c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x100, "gpg1",  0x20),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x120, "gpg2",  0x24),
 };
 
 /* pin banks of exynos2200 pin-controller - PERIC1 */
 static const struct samsung_pin_bank_data exynos2200_pin_banks6[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTG(4, 0x0,  "gpp7",  0x00),
-	EXYNOS850_PIN_BANK_EINTG(4, 0x20, "gpp8",  0x04),
-	EXYNOS850_PIN_BANK_EINTG(4, 0x40, "gpp9",  0x08),
-	EXYNOS850_PIN_BANK_EINTG(4, 0x60, "gpp10", 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0,  "gpp7",  0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x20, "gpp8",  0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x40, "gpp9",  0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x60, "gpp10", 0x0c),
 };
 
 /* pin banks of exynos2200 pin-controller - PERIC2 */
 static const struct samsung_pin_bank_data exynos2200_pin_banks7[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTG(4, 0x0, "gpp0",  0x00),
-	EXYNOS850_PIN_BANK_EINTG(4, 0x20, "gpp1",  0x04),
-	EXYNOS850_PIN_BANK_EINTG(4, 0x40, "gpp2",  0x08),
-	EXYNOS850_PIN_BANK_EINTG(4, 0x60, "gpp3",  0x0c),
-	EXYNOS850_PIN_BANK_EINTG(4, 0x80, "gpp5",  0x10),
-	EXYNOS850_PIN_BANK_EINTG(4, 0xa0, "gpp6",  0x14),
-	EXYNOS850_PIN_BANK_EINTG(4, 0xc0, "gpp11", 0x18),
-	EXYNOS850_PIN_BANK_EINTG(2, 0xe0, "gpc3",  0x1c),
-	EXYNOS850_PIN_BANK_EINTG(2, 0x100, "gpc4",  0x20),
-	EXYNOS850_PIN_BANK_EINTG(2, 0x120, "gpc5",  0x24),
-	EXYNOS850_PIN_BANK_EINTG(2, 0x140, "gpc6",  0x28),
-	EXYNOS850_PIN_BANK_EINTG(2, 0x160, "gpc7",  0x2c),
-	EXYNOS850_PIN_BANK_EINTG(2, 0x180, "gpc8",  0x30),
-	EXYNOS850_PIN_BANK_EINTG(2, 0x1a0, "gpc9",  0x34),
-	EXYNOS850_PIN_BANK_EINTG(5, 0x1c0, "gpg0",  0x38),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0, "gpp0",  0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x20, "gpp1",  0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x40, "gpp2",  0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x60, "gpp3",  0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x80, "gpp5",  0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0xa0, "gpp6",  0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0xc0, "gpp11", 0x18),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0xe0, "gpc3",  0x1c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x100, "gpc4",  0x20),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x120, "gpc5",  0x24),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x140, "gpc6",  0x28),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x160, "gpc7",  0x2c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x180, "gpc8",  0x30),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x1a0, "gpc9",  0x34),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x1c0, "gpg0",  0x38),
 };
 
 /* pin banks of exynos2200 pin-controller - VTS */
 static const struct samsung_pin_bank_data exynos2200_pin_banks8[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTG(7, 0x0, "gpv0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x0, "gpv0", 0x00),
 };
 
 static const struct samsung_pin_ctrl exynos2200_pin_ctrl[] = {
@@ -638,70 +638,70 @@ const struct samsung_pinctrl_of_match_data exynos7_of_data __initconst = {
 
 /* pin banks of exynos7870 pin-controller 0 (ALIVE) */
 static const struct samsung_pin_bank_data exynos7870_pin_banks0[] __initconst = {
-	EXYNOS7870_PIN_BANK_EINTN(6, 0x000, "etc0"),
-	EXYNOS7870_PIN_BANK_EINTN(3, 0x020, "etc1"),
-	EXYNOS7870_PIN_BANK_EINTW(8, 0x040, "gpa0", 0x00),
-	EXYNOS7870_PIN_BANK_EINTW(8, 0x060, "gpa1", 0x04),
-	EXYNOS7870_PIN_BANK_EINTW(8, 0x080, "gpa2", 0x08),
-	EXYNOS7870_PIN_BANK_EINTN(2, 0x0c0, "gpq0"),
+	EXYNOS9_PIN_BANK_EINTN(exynos7870_bank_type_alive, 6, 0x000, "etc0"),
+	EXYNOS9_PIN_BANK_EINTN(exynos7870_bank_type_alive, 3, 0x020, "etc1"),
+	EXYNOS9_PIN_BANK_EINTW(exynos7870_bank_type_alive, 8, 0x040, "gpa0", 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos7870_bank_type_alive, 8, 0x060, "gpa1", 0x04),
+	EXYNOS9_PIN_BANK_EINTW(exynos7870_bank_type_alive, 8, 0x080, "gpa2", 0x08),
+	EXYNOS9_PIN_BANK_EINTN(exynos7870_bank_type_alive, 2, 0x0c0, "gpq0"),
 };
 
 /* pin banks of exynos7870 pin-controller 1 (DISPAUD) */
 static const struct samsung_pin_bank_data exynos7870_pin_banks1[] __initconst = {
-	EXYNOS8895_PIN_BANK_EINTG(4, 0x000, "gpz0", 0x00),
-	EXYNOS8895_PIN_BANK_EINTG(6, 0x020, "gpz1", 0x04),
-	EXYNOS8895_PIN_BANK_EINTG(4, 0x040, "gpz2", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x000, "gpz0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 6, 0x020, "gpz1", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x040, "gpz2", 0x08),
 };
 
 /* pin banks of exynos7870 pin-controller 2 (ESE) */
 static const struct samsung_pin_bank_data exynos7870_pin_banks2[] __initconst = {
-	EXYNOS8895_PIN_BANK_EINTG(5, 0x000, "gpc7", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 5, 0x000, "gpc7", 0x00),
 };
 
 /* pin banks of exynos7870 pin-controller 3 (FSYS) */
 static const struct samsung_pin_bank_data exynos7870_pin_banks3[] __initconst = {
-	EXYNOS8895_PIN_BANK_EINTG(3, 0x000, "gpr0", 0x00),
-	EXYNOS8895_PIN_BANK_EINTG(8, 0x020, "gpr1", 0x04),
-	EXYNOS8895_PIN_BANK_EINTG(2, 0x040, "gpr2", 0x08),
-	EXYNOS8895_PIN_BANK_EINTG(4, 0x060, "gpr3", 0x0c),
-	EXYNOS8895_PIN_BANK_EINTG(6, 0x080, "gpr4", 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x000, "gpr0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x020, "gpr1", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x040, "gpr2", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x060, "gpr3", 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 6, 0x080, "gpr4", 0x10),
 };
 
 /* pin banks of exynos7870 pin-controller 4 (MIF) */
 static const struct samsung_pin_bank_data exynos7870_pin_banks4[] __initconst = {
-	EXYNOS8895_PIN_BANK_EINTG(2, 0x000, "gpm0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x000, "gpm0", 0x00),
 };
 
 /* pin banks of exynos7870 pin-controller 5 (NFC) */
 static const struct samsung_pin_bank_data exynos7870_pin_banks5[] __initconst = {
-	EXYNOS8895_PIN_BANK_EINTG(4, 0x000, "gpc2", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x000, "gpc2", 0x00),
 };
 
 /* pin banks of exynos7870 pin-controller 6 (TOP) */
 static const struct samsung_pin_bank_data exynos7870_pin_banks6[] __initconst = {
-	EXYNOS8895_PIN_BANK_EINTG(4, 0x000, "gpb0", 0x00),
-	EXYNOS8895_PIN_BANK_EINTG(3, 0x020, "gpc0", 0x04),
-	EXYNOS8895_PIN_BANK_EINTG(4, 0x040, "gpc1", 0x08),
-	EXYNOS8895_PIN_BANK_EINTG(4, 0x060, "gpc4", 0x0c),
-	EXYNOS8895_PIN_BANK_EINTG(2, 0x080, "gpc5", 0x10),
-	EXYNOS8895_PIN_BANK_EINTG(4, 0x0a0, "gpc6", 0x14),
-	EXYNOS8895_PIN_BANK_EINTG(2, 0x0c0, "gpc8", 0x18),
-	EXYNOS8895_PIN_BANK_EINTG(2, 0x0e0, "gpc9", 0x1c),
-	EXYNOS8895_PIN_BANK_EINTG(7, 0x100, "gpd1", 0x20),
-	EXYNOS8895_PIN_BANK_EINTG(6, 0x120, "gpd2", 0x24),
-	EXYNOS8895_PIN_BANK_EINTG(8, 0x140, "gpd3", 0x28),
-	EXYNOS8895_PIN_BANK_EINTG(7, 0x160, "gpd4", 0x2c),
-	EXYNOS8895_PIN_BANK_EINTG(3, 0x1a0, "gpe0", 0x34),
-	EXYNOS8895_PIN_BANK_EINTG(4, 0x1c0, "gpf0", 0x38),
-	EXYNOS8895_PIN_BANK_EINTG(2, 0x1e0, "gpf1", 0x3c),
-	EXYNOS8895_PIN_BANK_EINTG(2, 0x200, "gpf2", 0x40),
-	EXYNOS8895_PIN_BANK_EINTG(4, 0x220, "gpf3", 0x44),
-	EXYNOS8895_PIN_BANK_EINTG(5, 0x240, "gpf4", 0x48),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x000, "gpb0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x020, "gpc0", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x040, "gpc1", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x060, "gpc4", 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x080, "gpc5", 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x0a0, "gpc6", 0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x0c0, "gpc8", 0x18),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x0e0, "gpc9", 0x1c),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 7, 0x100, "gpd1", 0x20),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 6, 0x120, "gpd2", 0x24),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x140, "gpd3", 0x28),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 7, 0x160, "gpd4", 0x2c),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x1a0, "gpe0", 0x34),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x1c0, "gpf0", 0x38),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x1e0, "gpf1", 0x3c),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x200, "gpf2", 0x40),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x220, "gpf3", 0x44),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 5, 0x240, "gpf4", 0x48),
 };
 
 /* pin banks of exynos7870 pin-controller 7 (TOUCH) */
 static const struct samsung_pin_bank_data exynos7870_pin_banks7[] __initconst = {
-	EXYNOS8895_PIN_BANK_EINTG(3, 0x000, "gpc3", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x000, "gpc3", 0x00),
 };
 
 static const struct samsung_pin_ctrl exynos7870_pin_ctrl[] __initconst = {
@@ -770,46 +770,46 @@ const struct samsung_pinctrl_of_match_data exynos7870_of_data __initconst = {
 static const struct samsung_pin_bank_data exynos7885_pin_banks0[] __initconst = {
 	EXYNOS_PIN_BANK_EINTN(3, 0x000, "etc0"),
 	EXYNOS_PIN_BANK_EINTN(3, 0x020, "etc1"),
-	EXYNOS850_PIN_BANK_EINTW(8, 0x040, "gpa0", 0x00),
-	EXYNOS850_PIN_BANK_EINTW(8, 0x060, "gpa1", 0x04),
-	EXYNOS850_PIN_BANK_EINTW(8, 0x080, "gpa2", 0x08),
-	EXYNOS850_PIN_BANK_EINTW(5, 0x0a0, "gpq0", 0x0c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x040, "gpa0", 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x060, "gpa1", 0x04),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x080, "gpa2", 0x08),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 5, 0x0a0, "gpq0", 0x0c),
 };
 
 /* pin banks of exynos7885 pin-controller 1 (DISPAUD) */
 static const struct samsung_pin_bank_data exynos7885_pin_banks1[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTG(5, 0x000, "gpb0", 0x00),
-	EXYNOS850_PIN_BANK_EINTG(4, 0x020, "gpb1", 0x04),
-	EXYNOS850_PIN_BANK_EINTG(5, 0x040, "gpb2", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x000, "gpb0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x020, "gpb1", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x040, "gpb2", 0x08),
 };
 
 /* pin banks of exynos7885 pin-controller 2 (FSYS) */
 static const struct samsung_pin_bank_data exynos7885_pin_banks2[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTG(4, 0x000, "gpf0", 0x00),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x020, "gpf2", 0x04),
-	EXYNOS850_PIN_BANK_EINTG(6, 0x040, "gpf3", 0x08),
-	EXYNOS850_PIN_BANK_EINTG(6, 0x060, "gpf4", 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x000, "gpf0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpf2", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x040, "gpf3", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x060, "gpf4", 0x0c),
 };
 
 /* pin banks of exynos7885 pin-controller 3 (TOP) */
 static const struct samsung_pin_bank_data exynos7885_pin_banks3[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTG(4, 0x000, "gpp0", 0x00),
-	EXYNOS850_PIN_BANK_EINTG(3, 0x020, "gpg0", 0x04),
-	EXYNOS850_PIN_BANK_EINTG(4, 0x040, "gpp1", 0x08),
-	EXYNOS850_PIN_BANK_EINTG(4, 0x060, "gpp2", 0x0c),
-	EXYNOS850_PIN_BANK_EINTG(3, 0x080, "gpp3", 0x10),
-	EXYNOS850_PIN_BANK_EINTG(6, 0x0a0, "gpp4", 0x14),
-	EXYNOS850_PIN_BANK_EINTG(4, 0x0c0, "gpp5", 0x18),
-	EXYNOS850_PIN_BANK_EINTG(5, 0x0e0, "gpp6", 0x1c),
-	EXYNOS850_PIN_BANK_EINTG(2, 0x100, "gpp7", 0x20),
-	EXYNOS850_PIN_BANK_EINTG(2, 0x120, "gpp8", 0x24),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x140, "gpg1", 0x28),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x160, "gpg2", 0x2c),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x180, "gpg3", 0x30),
-	EXYNOS850_PIN_BANK_EINTG(2, 0x1a0, "gpg4", 0x34),
-	EXYNOS850_PIN_BANK_EINTG(4, 0x1c0, "gpc0", 0x38),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x1e0, "gpc1", 0x3c),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x200, "gpc2", 0x40),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x000, "gpp0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 3, 0x020, "gpg0", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x040, "gpp1", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x060, "gpp2", 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 3, 0x080, "gpp3", 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x0a0, "gpp4", 0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0c0, "gpp5", 0x18),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x0e0, "gpp6", 0x1c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x100, "gpp7", 0x20),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x120, "gpp8", 0x24),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x140, "gpg1", 0x28),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x160, "gpg2", 0x2c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x180, "gpg3", 0x30),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x1a0, "gpg4", 0x34),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x1c0, "gpc0", 0x38),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x1e0, "gpc1", 0x3c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x200, "gpc2", 0x40),
 };
 
 static const struct samsung_pin_ctrl exynos7885_pin_ctrl[] __initconst = {
@@ -850,59 +850,59 @@ const struct samsung_pinctrl_of_match_data exynos7885_of_data __initconst = {
 /* pin banks of exynos850 pin-controller 0 (ALIVE) */
 static const struct samsung_pin_bank_data exynos850_pin_banks0[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS850_PIN_BANK_EINTW(8, 0x000, "gpa0", 0x00),
-	EXYNOS850_PIN_BANK_EINTW(8, 0x020, "gpa1", 0x04),
-	EXYNOS850_PIN_BANK_EINTW(8, 0x040, "gpa2", 0x08),
-	EXYNOS850_PIN_BANK_EINTW(8, 0x060, "gpa3", 0x0c),
-	EXYNOS850_PIN_BANK_EINTW(4, 0x080, "gpa4", 0x10),
-	EXYNOS850_PIN_BANK_EINTN(3, 0x0a0, "gpq0"),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x000, "gpa0", 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x020, "gpa1", 0x04),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x040, "gpa2", 0x08),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x060, "gpa3", 0x0c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 4, 0x080, "gpa4", 0x10),
+	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 3, 0x0a0, "gpq0"),
 };
 
 /* pin banks of exynos850 pin-controller 1 (CMGP) */
 static const struct samsung_pin_bank_data exynos850_pin_banks1[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS850_PIN_BANK_EINTW(1, 0x000, "gpm0", 0x00),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x020, "gpm1", 0x04),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x040, "gpm2", 0x08),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x060, "gpm3", 0x0c),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x080, "gpm4", 0x10),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x0a0, "gpm5", 0x14),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x0c0, "gpm6", 0x18),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x0e0, "gpm7", 0x1c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x000, "gpm0", 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x020, "gpm1", 0x04),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x040, "gpm2", 0x08),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x060, "gpm3", 0x0c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x080, "gpm4", 0x10),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0a0, "gpm5", 0x14),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0c0, "gpm6", 0x18),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0e0, "gpm7", 0x1c),
 };
 
 /* pin banks of exynos850 pin-controller 2 (AUD) */
 static const struct samsung_pin_bank_data exynos850_pin_banks2[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS850_PIN_BANK_EINTG(5, 0x000, "gpb0", 0x00),
-	EXYNOS850_PIN_BANK_EINTG(5, 0x020, "gpb1", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x000, "gpb0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x020, "gpb1", 0x04),
 };
 
 /* pin banks of exynos850 pin-controller 3 (HSI) */
 static const struct samsung_pin_bank_data exynos850_pin_banks3[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS850_PIN_BANK_EINTG(6, 0x000, "gpf2", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x000, "gpf2", 0x00),
 };
 
 /* pin banks of exynos850 pin-controller 4 (CORE) */
 static const struct samsung_pin_bank_data exynos850_pin_banks4[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS850_PIN_BANK_EINTG(4, 0x000, "gpf0", 0x00),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x020, "gpf1", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x000, "gpf0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpf1", 0x04),
 };
 
 /* pin banks of exynos850 pin-controller 5 (PERI) */
 static const struct samsung_pin_bank_data exynos850_pin_banks5[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS850_PIN_BANK_EINTG(2, 0x000, "gpg0", 0x00),
-	EXYNOS850_PIN_BANK_EINTG(6, 0x020, "gpp0", 0x04),
-	EXYNOS850_PIN_BANK_EINTG(4, 0x040, "gpp1", 0x08),
-	EXYNOS850_PIN_BANK_EINTG(4, 0x060, "gpp2", 0x0c),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x080, "gpg1", 0x10),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x0a0, "gpg2", 0x14),
-	EXYNOS850_PIN_BANK_EINTG(1, 0x0c0, "gpg3", 0x18),
-	EXYNOS850_PIN_BANK_EINTG(3, 0x0e0, "gpc0", 0x1c),
-	EXYNOS850_PIN_BANK_EINTG(6, 0x100, "gpc1", 0x20),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x000, "gpg0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x020, "gpp0", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x040, "gpp1", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x060, "gpp2", 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x080, "gpg1", 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x0a0, "gpg2", 0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 1, 0x0c0, "gpg3", 0x18),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 3, 0x0e0, "gpc0", 0x1c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x100, "gpc1", 0x20),
 };
 
 static const struct samsung_pin_ctrl exynos850_pin_ctrl[] __initconst = {
@@ -946,98 +946,97 @@ const struct samsung_pinctrl_of_match_data exynos850_of_data __initconst = {
 /* pin banks of exynos990 pin-controller 0 (ALIVE) */
 static struct samsung_pin_bank_data exynos990_pin_banks0[] = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS850_PIN_BANK_EINTW(8, 0x000, "gpa0", 0x00),
-	EXYNOS850_PIN_BANK_EINTW(8, 0x020, "gpa1", 0x04),
-	EXYNOS850_PIN_BANK_EINTW(8, 0x040, "gpa2", 0x08),
-	EXYNOS850_PIN_BANK_EINTW(8, 0x060, "gpa3", 0x0c),
-	EXYNOS850_PIN_BANK_EINTW(2, 0x080, "gpa4", 0x10),
-	EXYNOS850_PIN_BANK_EINTN(7, 0x0A0, "gpq0"),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x000, "gpa0", 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x020, "gpa1", 0x04),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x040, "gpa2", 0x08),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x060, "gpa3", 0x0c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x080, "gpa4", 0x10),
+	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 7, 0x0a0, "gpq0"),
 };
 
 /* pin banks of exynos990 pin-controller 1 (CMGP) */
 static struct samsung_pin_bank_data exynos990_pin_banks1[] = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS850_PIN_BANK_EINTN(1, 0x000, "gpm0"),
-	EXYNOS850_PIN_BANK_EINTN(1, 0x020, "gpm1"),
-	EXYNOS850_PIN_BANK_EINTN(1, 0x040, "gpm2"),
-	EXYNOS850_PIN_BANK_EINTN(1, 0x060, "gpm3"),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x080, "gpm4", 0x00),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x0A0, "gpm5", 0x04),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x0C0, "gpm6", 0x08),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x0E0, "gpm7", 0x0c),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x100, "gpm8", 0x10),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x120, "gpm9", 0x14),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x140, "gpm10", 0x18),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x160, "gpm11", 0x1c),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x180, "gpm12", 0x20),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x1A0, "gpm13", 0x24),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x1C0, "gpm14", 0x28),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x1E0, "gpm15", 0x2c),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x200, "gpm16", 0x30),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x220, "gpm17", 0x34),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x240, "gpm18", 0x38),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x260, "gpm19", 0x3c),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x280, "gpm20", 0x40),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x2A0, "gpm21", 0x44),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x2C0, "gpm22", 0x48),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x2E0, "gpm23", 0x4c),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x300, "gpm24", 0x50),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x320, "gpm25", 0x54),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x340, "gpm26", 0x58),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x360, "gpm27", 0x5c),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x380, "gpm28", 0x60),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x3A0, "gpm29", 0x64),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x3C0, "gpm30", 0x68),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x3E0, "gpm31", 0x6c),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x400, "gpm32", 0x70),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x420, "gpm33", 0x74),
-
+	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 1, 0x000, "gpm0"),
+	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 1, 0x020, "gpm1"),
+	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 1, 0x040, "gpm2"),
+	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 1, 0x060, "gpm3"),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x080, "gpm4", 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0a0, "gpm5", 0x04),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0c0, "gpm6", 0x08),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0e0, "gpm7", 0x0c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x100, "gpm8", 0x10),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x120, "gpm9", 0x14),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x140, "gpm10", 0x18),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x160, "gpm11", 0x1c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x180, "gpm12", 0x20),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x1a0, "gpm13", 0x24),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x1c0, "gpm14", 0x28),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x1e0, "gpm15", 0x2c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x200, "gpm16", 0x30),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x220, "gpm17", 0x34),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x240, "gpm18", 0x38),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x260, "gpm19", 0x3c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x280, "gpm20", 0x40),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x2a0, "gpm21", 0x44),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x2c0, "gpm22", 0x48),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x2e0, "gpm23", 0x4c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x300, "gpm24", 0x50),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x320, "gpm25", 0x54),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x340, "gpm26", 0x58),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x360, "gpm27", 0x5c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x380, "gpm28", 0x60),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x3a0, "gpm29", 0x64),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x3c0, "gpm30", 0x68),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x3e0, "gpm31", 0x6c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x400, "gpm32", 0x70),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x420, "gpm33", 0x74),
 };
 
 /* pin banks of exynos990 pin-controller 2 (HSI1) */
 static struct samsung_pin_bank_data exynos990_pin_banks2[] = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS850_PIN_BANK_EINTG(4, 0x000, "gpf0", 0x00),
-	EXYNOS850_PIN_BANK_EINTG(6, 0x020, "gpf1", 0x04),
-	EXYNOS850_PIN_BANK_EINTG(3, 0x040, "gpf2", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x000, "gpf0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x020, "gpf1", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 3, 0x040, "gpf2", 0x08),
 };
 
 /* pin banks of exynos990 pin-controller 3 (HSI2) */
 static struct samsung_pin_bank_data exynos990_pin_banks3[] = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS850_PIN_BANK_EINTG(2, 0x000, "gpf3", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x000, "gpf3", 0x00),
 };
 
 /* pin banks of exynos990 pin-controller 4 (PERIC0) */
 static struct samsung_pin_bank_data exynos990_pin_banks4[] = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS850_PIN_BANK_EINTG(8, 0x000, "gpp0", 0x00),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x020, "gpp1", 0x04),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x040, "gpp2", 0x08),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x060, "gpp3", 0x0C),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x080, "gpp4", 0x10),
-	EXYNOS850_PIN_BANK_EINTG(2, 0x0A0, "gpg0", 0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x000, "gpp0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpp1", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x040, "gpp2", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x060, "gpp3", 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x080, "gpp4", 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x0a0, "gpg0", 0x14),
 };
 
 /* pin banks of exynos990 pin-controller 5 (PERIC1) */
 static struct samsung_pin_bank_data exynos990_pin_banks5[] = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS850_PIN_BANK_EINTG(8, 0x000, "gpp5", 0x00),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x020, "gpp6", 0x04),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x040, "gpp7", 0x08),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x060, "gpp8", 0x0C),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x080, "gpp9", 0x10),
-	EXYNOS850_PIN_BANK_EINTG(6, 0x0A0, "gpc0", 0x14),
-	EXYNOS850_PIN_BANK_EINTG(4, 0x0C0, "gpg1", 0x18),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x0E0, "gpb0", 0x1C),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x100, "gpb1", 0x20),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x120, "gpb2", 0x24),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x000, "gpp5", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpp6", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x040, "gpp7", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x060, "gpp8", 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x080, "gpp9", 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x0a0, "gpc0", 0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0c0, "gpg1", 0x18),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x0e0, "gpb0", 0x1c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x100, "gpb1", 0x20),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x120, "gpb2", 0x24),
 };
 
 /* pin banks of exynos990 pin-controller 6 (VTS) */
 static struct samsung_pin_bank_data exynos990_pin_banks6[] = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS850_PIN_BANK_EINTG(7, 0x000, "gpv0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x000, "gpv0", 0x00),
 };
 
 static const struct samsung_pin_ctrl exynos990_pin_ctrl[] __initconst = {
@@ -1085,88 +1084,88 @@ const struct samsung_pinctrl_of_match_data exynos990_of_data __initconst = {
 
 /* pin banks of exynos9810 pin-controller 0 (ALIVE) */
 static const struct samsung_pin_bank_data exynos9810_pin_banks0[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTN(6, 0x000, "etc1"),
-	EXYNOS850_PIN_BANK_EINTW(8, 0x020, "gpa0", 0x00),
-	EXYNOS850_PIN_BANK_EINTW(8, 0x040, "gpa1", 0x04),
-	EXYNOS850_PIN_BANK_EINTW(8, 0x060, "gpa2", 0x08),
-	EXYNOS850_PIN_BANK_EINTW(8, 0x080, "gpa3", 0x0c),
-	EXYNOS850_PIN_BANK_EINTN(6, 0x0A0, "gpq0"),
-	EXYNOS850_PIN_BANK_EINTW(2, 0x0C0, "gpa4", 0x10),
+	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 6, 0x000, "etc1"),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x020, "gpa0", 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x040, "gpa1", 0x04),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x060, "gpa2", 0x08),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x080, "gpa3", 0x0c),
+	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 6, 0x0a0, "gpq0"),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x0c0, "gpa4", 0x10),
 };
 
 /* pin banks of exynos9810 pin-controller 1 (AUD) */
 static const struct samsung_pin_bank_data exynos9810_pin_banks1[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTG(5, 0x000, "gpb0", 0x00),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x020, "gpb1", 0x04),
-	EXYNOS850_PIN_BANK_EINTG(4, 0x040, "gpb2", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x000, "gpb0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpb1", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x040, "gpb2", 0x08),
 };
 
 /* pin banks of exynos9810 pin-controller 2 (CHUB) */
 static const struct samsung_pin_bank_data exynos9810_pin_banks2[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTG(8, 0x000, "gph0", 0x00),
-	EXYNOS850_PIN_BANK_EINTG(5, 0x020, "gph1", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x000, "gph0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x020, "gph1", 0x04),
 };
 
 /* pin banks of exynos9810 pin-controller 3 (CMGP) */
 static const struct samsung_pin_bank_data exynos9810_pin_banks3[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTW(1, 0x000, "gpm0", 0x00),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x020, "gpm1", 0x04),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x040, "gpm2", 0x08),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x060, "gpm3", 0x0C),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x080, "gpm4", 0x10),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x0A0, "gpm5", 0x14),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x0C0, "gpm6", 0x18),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x0E0, "gpm7", 0x1C),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x100, "gpm10", 0x20),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x120, "gpm11", 0x24),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x140, "gpm12", 0x28),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x160, "gpm13", 0x2C),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x180, "gpm14", 0x30),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x1A0, "gpm15", 0x34),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x1C0, "gpm16", 0x38),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x1E0, "gpm17", 0x3C),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x200, "gpm40", 0x40),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x220, "gpm41", 0x44),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x240, "gpm42", 0x48),
-	EXYNOS850_PIN_BANK_EINTW(1, 0x260, "gpm43", 0x4C),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x000, "gpm0", 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x020, "gpm1", 0x04),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x040, "gpm2", 0x08),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x060, "gpm3", 0x0c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x080, "gpm4", 0x10),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0a0, "gpm5", 0x14),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0c0, "gpm6", 0x18),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0e0, "gpm7", 0x1c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x100, "gpm10", 0x20),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x120, "gpm11", 0x24),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x140, "gpm12", 0x28),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x160, "gpm13", 0x2c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x180, "gpm14", 0x30),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x1a0, "gpm15", 0x34),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x1c0, "gpm16", 0x38),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x1e0, "gpm17", 0x3c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x200, "gpm40", 0x40),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x220, "gpm41", 0x44),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x240, "gpm42", 0x48),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x260, "gpm43", 0x4c),
 };
 
 /* pin banks of exynos9810 pin-controller 4 (FSYS0) */
 static const struct samsung_pin_bank_data exynos9810_pin_banks4[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTG(2, 0x000, "gpf0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x000, "gpf0", 0x00),
 };
 
 /* pin banks of exynos9810 pin-controller 5 (FSYS1) */
 static const struct samsung_pin_bank_data exynos9810_pin_banks5[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTG(7, 0x000, "gpf1", 0x00),
-	EXYNOS850_PIN_BANK_EINTG(6, 0x020, "gpf2", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x000, "gpf1", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x020, "gpf2", 0x04),
 };
 
 /* pin banks of exynos9810 pin-controller 6 (PERIC0) */
 static const struct samsung_pin_bank_data exynos9810_pin_banks6[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTG(8, 0x000, "gpp0", 0x00),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x020, "gpp1", 0x04),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x040, "gpp2", 0x08),
-	EXYNOS850_PIN_BANK_EINTG(4, 0x060, "gpp3", 0x0C),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x080, "gpg0", 0x10),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x0A0, "gpg1", 0x14),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x0C0, "gpg2", 0x18),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x000, "gpp0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpp1", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x040, "gpp2", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x060, "gpp3", 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x080, "gpg0", 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x0a0, "gpg1", 0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x0c0, "gpg2", 0x18),
 };
 
 /* pin banks of exynos9810 pin-controller 7 (PERIC1) */
 static const struct samsung_pin_bank_data exynos9810_pin_banks7[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTG(8, 0x000, "gpp4", 0x00),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x020, "gpp5", 0x04),
-	EXYNOS850_PIN_BANK_EINTG(4, 0x040, "gpp6", 0x08),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x060, "gpc0", 0x0C),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x080, "gpc1", 0x10),
-	EXYNOS850_PIN_BANK_EINTG(4, 0x0A0, "gpd0", 0x14),
-	EXYNOS850_PIN_BANK_EINTG(7, 0x0C0, "gpg3", 0x18),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x000, "gpp4", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpp5", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x040, "gpp6", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x060, "gpc0", 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x080, "gpc1", 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0a0, "gpd0", 0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x0c0, "gpg3", 0x18),
 };
 
 /* pin banks of exynos9810 pin-controller 8 (VTS) */
 static const struct samsung_pin_bank_data exynos9810_pin_banks8[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTG(3, 0x000, "gpt0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 3, 0x000, "gpt0", 0x00),
 };
 
 static const struct samsung_pin_ctrl exynos9810_pin_ctrl[] __initconst = {
@@ -1239,55 +1238,55 @@ const struct samsung_pinctrl_of_match_data exynos9810_of_data __initconst = {
 
 /* pin banks of exynosautov9 pin-controller 0 (ALIVE) */
 static const struct samsung_pin_bank_data exynosautov9_pin_banks0[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTW(8, 0x000, "gpa0", 0x00),
-	EXYNOS850_PIN_BANK_EINTW(2, 0x020, "gpa1", 0x04),
-	EXYNOS850_PIN_BANK_EINTN(2, 0x040, "gpq0"),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x000, "gpa0", 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x020, "gpa1", 0x04),
+	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 2, 0x040, "gpq0"),
 };
 
 /* pin banks of exynosautov9 pin-controller 1 (AUD) */
 static const struct samsung_pin_bank_data exynosautov9_pin_banks1[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTG(5, 0x000, "gpb0", 0x00),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x020, "gpb1", 0x04),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x040, "gpb2", 0x08),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x060, "gpb3", 0x0C),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x000, "gpb0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpb1", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x040, "gpb2", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x060, "gpb3", 0x0c),
 };
 
 /* pin banks of exynosautov9 pin-controller 2 (FSYS0) */
 static const struct samsung_pin_bank_data exynosautov9_pin_banks2[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTG(6, 0x000, "gpf0", 0x00),
-	EXYNOS850_PIN_BANK_EINTG(6, 0x020, "gpf1", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x000, "gpf0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x020, "gpf1", 0x04),
 };
 
 /* pin banks of exynosautov9 pin-controller 3 (FSYS1) */
 static const struct samsung_pin_bank_data exynosautov9_pin_banks3[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTG(6, 0x000, "gpf8", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x000, "gpf8", 0x00),
 };
 
 /* pin banks of exynosautov9 pin-controller 4 (FSYS2) */
 static const struct samsung_pin_bank_data exynosautov9_pin_banks4[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTG(4, 0x000, "gpf2", 0x00),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x020, "gpf3", 0x04),
-	EXYNOS850_PIN_BANK_EINTG(7, 0x040, "gpf4", 0x08),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x060, "gpf5", 0x0C),
-	EXYNOS850_PIN_BANK_EINTG(7, 0x080, "gpf6", 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x000, "gpf2", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpf3", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x040, "gpf4", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x060, "gpf5", 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x080, "gpf6", 0x10),
 };
 
 /* pin banks of exynosautov9 pin-controller 5 (PERIC0) */
 static const struct samsung_pin_bank_data exynosautov9_pin_banks5[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTG(8, 0x000, "gpp0", 0x00),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x020, "gpp1", 0x04),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x040, "gpp2", 0x08),
-	EXYNOS850_PIN_BANK_EINTG(5, 0x060, "gpg0", 0x0C),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x000, "gpp0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpp1", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x040, "gpp2", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x060, "gpg0", 0x0c),
 };
 
 /* pin banks of exynosautov9 pin-controller 6 (PERIC1) */
 static const struct samsung_pin_bank_data exynosautov9_pin_banks6[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTG(8, 0x000, "gpp3", 0x00),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x020, "gpp4", 0x04),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x040, "gpp5", 0x08),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x060, "gpg1", 0x0C),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x080, "gpg2", 0x10),
-	EXYNOS850_PIN_BANK_EINTG(4, 0x0A0, "gpg3", 0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x000, "gpp3", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpp4", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x040, "gpp5", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x060, "gpg1", 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x080, "gpg2", 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0a0, "gpg3", 0x14),
 };
 
 static const struct samsung_pin_ctrl exynosautov9_pin_ctrl[] __initconst = {
@@ -1349,7 +1348,7 @@ const struct samsung_pinctrl_of_match_data exynosautov9_of_data __initconst = {
 static const struct samsung_pin_bank_data exynosautov920_pin_banks0[] = {
 	EXYNOSV920_PIN_BANK_EINTW(8, 0x0000, "gpa0", 0x18, 0x24, 0x28),
 	EXYNOSV920_PIN_BANK_EINTW(2, 0x1000, "gpa1", 0x18, 0x20, 0x24),
-	EXYNOS850_PIN_BANK_EINTN(2, 0x2000, "gpq0"),
+	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 2, 0x2000, "gpq0"),
 };
 
 /* pin banks of exynosautov920 pin-controller 1 (AUD) */
@@ -1488,94 +1487,94 @@ const struct samsung_pinctrl_of_match_data exynosautov920_of_data __initconst =
 /* pin banks of exynos8890 pin-controller 0 (ALIVE) */
 static const struct samsung_pin_bank_data exynos8890_pin_banks0[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS7870_PIN_BANK_EINTW(8, 0x000, "gpa0", 0x00),
-	EXYNOS7870_PIN_BANK_EINTW(8, 0x020, "gpa1", 0x04),
-	EXYNOS7870_PIN_BANK_EINTW(8, 0x040, "gpa2", 0x08),
-	EXYNOS7870_PIN_BANK_EINTW(8, 0x060, "gpa3", 0x0c),
+	EXYNOS9_PIN_BANK_EINTW(exynos7870_bank_type_alive, 8, 0x000, "gpa0", 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos7870_bank_type_alive, 8, 0x020, "gpa1", 0x04),
+	EXYNOS9_PIN_BANK_EINTW(exynos7870_bank_type_alive, 8, 0x040, "gpa2", 0x08),
+	EXYNOS9_PIN_BANK_EINTW(exynos7870_bank_type_alive, 8, 0x060, "gpa3", 0x0c),
 };
 
 /* pin banks of exynos8890 pin-controller 1 (AUD) */
 static const struct samsung_pin_bank_data exynos8890_pin_banks1[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS8895_PIN_BANK_EINTG(7, 0x000, "gph0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 7, 0x000, "gph0", 0x00),
 };
 
 /* pin banks of exynos8890 pin-controller 2 (CCORE) */
 static const struct samsung_pin_bank_data exynos8890_pin_banks2[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS8895_PIN_BANK_EINTG(2, 0x000, "etc0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x000, "etc0", 0x00),
 };
 
 /* pin banks of exynos8890 pin-controller 3 (ESE) */
 static const struct samsung_pin_bank_data exynos8890_pin_banks3[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS8895_PIN_BANK_EINTG(5, 0x000, "gpf3", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 5, 0x000, "gpf3", 0x00),
 };
 
 /* pin banks of exynos8890 pin-controller 4 (FP) */
 static const struct samsung_pin_bank_data exynos8890_pin_banks4[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS8895_PIN_BANK_EINTG(4, 0x000, "gpf2", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x000, "gpf2", 0x00),
 };
 
 /* pin banks of exynos8890 pin-controller 5 (FSYS0) */
 static const struct samsung_pin_bank_data exynos8890_pin_banks5[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS8895_PIN_BANK_EINTG(4, 0x000, "gpi1", 0x00),
-	EXYNOS8895_PIN_BANK_EINTG(8, 0x020, "gpi2", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x000, "gpi1", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x020, "gpi2", 0x04),
 };
 
 /* pin banks of exynos8890 pin-controller 6 (FSYS1) */
 static const struct samsung_pin_bank_data exynos8890_pin_banks6[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS8895_PIN_BANK_EINTG(7, 0x000, "gpj0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 7, 0x000, "gpj0", 0x00),
 };
 
 /* pin banks of exynos8890 pin-controller 7 (NFC) */
 static const struct samsung_pin_bank_data exynos8890_pin_banks7[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS8895_PIN_BANK_EINTG(3, 0x000, "gpf0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x000, "gpf0", 0x00),
 };
 
 /* pin banks of exynos8890 pin-controller 8 (PERIC0) */
 static const struct samsung_pin_bank_data exynos8890_pin_banks8[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS8895_PIN_BANK_EINTG(6, 0x000, "gpi0", 0x00),
-	EXYNOS8895_PIN_BANK_EINTG(8, 0x020, "gpd0", 0x04),
-	EXYNOS8895_PIN_BANK_EINTG(6, 0x040, "gpd1", 0x08),
-	EXYNOS8895_PIN_BANK_EINTG(4, 0x060, "gpd2", 0x0c),
-	EXYNOS8895_PIN_BANK_EINTG(4, 0x080, "gpd3", 0x10),
-	EXYNOS8895_PIN_BANK_EINTG(2, 0x0A0, "gpb1", 0x14),
-	EXYNOS8895_PIN_BANK_EINTG(2, 0x0C0, "gpb2", 0x18),
-	EXYNOS8895_PIN_BANK_EINTG(3, 0x0E0, "gpb0", 0x1c),
-	EXYNOS8895_PIN_BANK_EINTG(5, 0x100, "gpc0", 0x20),
-	EXYNOS8895_PIN_BANK_EINTG(5, 0x120, "gpc1", 0x24),
-	EXYNOS8895_PIN_BANK_EINTG(6, 0x140, "gpc2", 0x28),
-	EXYNOS8895_PIN_BANK_EINTG(8, 0x160, "gpc3", 0x2c),
-	EXYNOS8895_PIN_BANK_EINTG(4, 0x180, "gpk0", 0x30),
-	EXYNOS8895_PIN_BANK_EINTG(7, 0x1A0, "etc1", 0x34),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 6, 0x000, "gpi0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x020, "gpd0", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 6, 0x040, "gpd1", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x060, "gpd2", 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x080, "gpd3", 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x0A0, "gpb1", 0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x0C0, "gpb2", 0x18),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x0E0, "gpb0", 0x1c),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 5, 0x100, "gpc0", 0x20),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 5, 0x120, "gpc1", 0x24),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 6, 0x140, "gpc2", 0x28),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x160, "gpc3", 0x2c),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x180, "gpk0", 0x30),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 7, 0x1A0, "etc1", 0x34),
 };
 
 /* pin banks of exynos8890 pin-controller 9 (PERIC1) */
 static const struct samsung_pin_bank_data exynos8890_pin_banks9[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS8895_PIN_BANK_EINTG(8, 0x000, "gpe0", 0x00),
-	EXYNOS8895_PIN_BANK_EINTG(8, 0x020, "gpe5", 0x04),
-	EXYNOS8895_PIN_BANK_EINTG(8, 0x040, "gpe6", 0x08),
-	EXYNOS8895_PIN_BANK_EINTG(8, 0x060, "gpj1", 0x0c),
-	EXYNOS8895_PIN_BANK_EINTG(2, 0x080, "gpj2", 0x10),
-	EXYNOS8895_PIN_BANK_EINTG(8, 0x0A0, "gpe2", 0x14),
-	EXYNOS8895_PIN_BANK_EINTG(8, 0x0C0, "gpe3", 0x18),
-	EXYNOS8895_PIN_BANK_EINTG(8, 0x0E0, "gpe4", 0x1c),
-	EXYNOS8895_PIN_BANK_EINTG(8, 0x100, "gpe1", 0x20),
-	EXYNOS8895_PIN_BANK_EINTG(4, 0x120, "gpe7", 0x24),
-	EXYNOS8895_PIN_BANK_EINTG(3, 0x140, "gpg0", 0x28),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x000, "gpe0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x020, "gpe5", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x040, "gpe6", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x060, "gpj1", 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x080, "gpj2", 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x0A0, "gpe2", 0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x0C0, "gpe3", 0x18),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x0E0, "gpe4", 0x1c),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x100, "gpe1", 0x20),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x120, "gpe7", 0x24),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x140, "gpg0", 0x28),
 };
 
 /* pin banks of exynos8890 pin-controller 10 (TOUCH) */
 static const struct samsung_pin_bank_data exynos8890_pin_banks10[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS8895_PIN_BANK_EINTG(3, 0x000, "gpf1", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x000, "gpf1", 0x00),
 };
 
 static const struct samsung_pin_ctrl exynos8890_pin_ctrl[] __initconst = {
@@ -1644,69 +1643,69 @@ const struct samsung_pinctrl_of_match_data exynos8890_of_data __initconst = {
 
 /* pin banks of exynos8895 pin-controller 0 (ALIVE) */
 static const struct samsung_pin_bank_data exynos8895_pin_banks0[] __initconst = {
-	EXYNOS_PIN_BANK_EINTW(8, 0x020, "gpa0", 0x00),
-	EXYNOS_PIN_BANK_EINTW(8, 0x040, "gpa1", 0x04),
-	EXYNOS_PIN_BANK_EINTW(8, 0x060, "gpa2", 0x08),
-	EXYNOS_PIN_BANK_EINTW(8, 0x080, "gpa3", 0x0c),
-	EXYNOS_PIN_BANK_EINTW(7, 0x0a0, "gpa4", 0x24),
+	EXYNOS9_PIN_BANK_EINTW(bank_type_alive, 8, 0x020, "gpa0", 0x00),
+	EXYNOS9_PIN_BANK_EINTW(bank_type_alive, 8, 0x040, "gpa1", 0x04),
+	EXYNOS9_PIN_BANK_EINTW(bank_type_alive, 8, 0x060, "gpa2", 0x08),
+	EXYNOS9_PIN_BANK_EINTW(bank_type_alive, 8, 0x080, "gpa3", 0x0c),
+	EXYNOS9_PIN_BANK_EINTW(bank_type_alive, 7, 0x0a0, "gpa4", 0x24),
 };
 
 /* pin banks of exynos8895 pin-controller 1 (ABOX) */
 static const struct samsung_pin_bank_data exynos8895_pin_banks1[] __initconst = {
-	EXYNOS_PIN_BANK_EINTG(8, 0x000, "gph0", 0x00),
-	EXYNOS_PIN_BANK_EINTG(7, 0x020, "gph1", 0x04),
-	EXYNOS_PIN_BANK_EINTG(4, 0x040, "gph3", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x000, "gph0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 7, 0x020, "gph1", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 4, 0x040, "gph3", 0x08),
 };
 
 /* pin banks of exynos8895 pin-controller 2 (VTS) */
 static const struct samsung_pin_bank_data exynos8895_pin_banks2[] __initconst = {
-	EXYNOS_PIN_BANK_EINTG(3, 0x000, "gph2", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 3, 0x000, "gph2", 0x00),
 };
 
 /* pin banks of exynos8895 pin-controller 3 (FSYS0) */
 static const struct samsung_pin_bank_data exynos8895_pin_banks3[] __initconst = {
-	EXYNOS8895_PIN_BANK_EINTG(3, 0x000, "gpi0", 0x00),
-	EXYNOS8895_PIN_BANK_EINTG(8, 0x020, "gpi1", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x000, "gpi0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x020, "gpi1", 0x04),
 };
 
 /* pin banks of exynos8895 pin-controller 4 (FSYS1) */
 static const struct samsung_pin_bank_data exynos8895_pin_banks4[] __initconst = {
-	EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpj1", 0x00),
-	EXYNOS_PIN_BANK_EINTG(7, 0x020, "gpj0", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x000, "gpj1", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 7, 0x020, "gpj0", 0x04),
 };
 
 /* pin banks of exynos8895 pin-controller 5 (BUSC) */
 static const struct samsung_pin_bank_data exynos8895_pin_banks5[] __initconst = {
-	EXYNOS_PIN_BANK_EINTG(2, 0x000, "gpb2", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 2, 0x000, "gpb2", 0x00),
 };
 
 /* pin banks of exynos8895 pin-controller 6 (PERIC0) */
 static const struct samsung_pin_bank_data exynos8895_pin_banks6[] __initconst = {
-	EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpd0", 0x00),
-	EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpd1", 0x04),
-	EXYNOS_PIN_BANK_EINTG(4, 0x040, "gpd2", 0x08),
-	EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpd3", 0x0C),
-	EXYNOS_PIN_BANK_EINTG(4, 0x080, "gpb1", 0x10),
-	EXYNOS_PIN_BANK_EINTG(8, 0x0a0, "gpe7", 0x14),
-	EXYNOS_PIN_BANK_EINTG(8, 0x0c0, "gpf1", 0x18),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x000, "gpd0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x020, "gpd1", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 4, 0x040, "gpd2", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 5, 0x060, "gpd3", 0x0C),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 4, 0x080, "gpb1", 0x10),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x0a0, "gpe7", 0x14),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x0c0, "gpf1", 0x18),
 };
 
 /* pin banks of exynos8895 pin-controller 7 (PERIC1) */
 static const struct samsung_pin_bank_data exynos8895_pin_banks7[] __initconst = {
-	EXYNOS_PIN_BANK_EINTG(3, 0x000, "gpb0", 0x00),
-	EXYNOS_PIN_BANK_EINTG(5, 0x020, "gpc0", 0x04),
-	EXYNOS_PIN_BANK_EINTG(5, 0x040, "gpc1", 0x08),
-	EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpc2", 0x0C),
-	EXYNOS_PIN_BANK_EINTG(8, 0x080, "gpc3", 0x10),
-	EXYNOS_PIN_BANK_EINTG(4, 0x0a0, "gpk0", 0x14),
-	EXYNOS_PIN_BANK_EINTG(8, 0x0c0, "gpe5", 0x18),
-	EXYNOS_PIN_BANK_EINTG(8, 0x0e0, "gpe6", 0x1C),
-	EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpe2", 0x20),
-	EXYNOS_PIN_BANK_EINTG(8, 0x120, "gpe3", 0x24),
-	EXYNOS_PIN_BANK_EINTG(8, 0x140, "gpe4", 0x28),
-	EXYNOS_PIN_BANK_EINTG(4, 0x160, "gpf0", 0x2C),
-	EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpe1", 0x30),
-	EXYNOS_PIN_BANK_EINTG(2, 0x1a0, "gpg0", 0x34),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 3, 0x000, "gpb0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 5, 0x020, "gpc0", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 5, 0x040, "gpc1", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x060, "gpc2", 0x0C),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x080, "gpc3", 0x10),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 4, 0x0a0, "gpk0", 0x14),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x0c0, "gpe5", 0x18),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x0e0, "gpe6", 0x1C),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x100, "gpe2", 0x20),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x120, "gpe3", 0x24),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x140, "gpe4", 0x28),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 4, 0x160, "gpf0", 0x2C),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x180, "gpe1", 0x30),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 2, 0x1a0, "gpg0", 0x34),
 };
 
 static const struct samsung_pin_ctrl exynos8895_pin_ctrl[] __initconst = {
@@ -1777,41 +1776,41 @@ const struct samsung_pinctrl_of_match_data exynos8895_of_data __initconst = {
 
 /* pin banks of FSD pin-controller 0 (FSYS) */
 static const struct samsung_pin_bank_data fsd_pin_banks0[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTG(7, 0x00, "gpf0", 0x00),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x20, "gpf1", 0x04),
-	EXYNOS850_PIN_BANK_EINTG(3, 0x40, "gpf6", 0x08),
-	EXYNOS850_PIN_BANK_EINTG(2, 0x60, "gpf4", 0x0c),
-	EXYNOS850_PIN_BANK_EINTG(6, 0x80, "gpf5", 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x00, "gpf0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x20, "gpf1", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 3, 0x40, "gpf6", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x60, "gpf4", 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x80, "gpf5", 0x10),
 };
 
 /* pin banks of FSD pin-controller 1 (PERIC) */
 static const struct samsung_pin_bank_data fsd_pin_banks1[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTG(4, 0x000, "gpc8", 0x00),
-	EXYNOS850_PIN_BANK_EINTG(7, 0x020, "gpf2", 0x04),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x040, "gpf3", 0x08),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x060, "gpd0", 0x0c),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x080, "gpb0", 0x10),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x0a0, "gpb1", 0x14),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x0c0, "gpb4", 0x18),
-	EXYNOS850_PIN_BANK_EINTG(4, 0x0e0, "gpb5", 0x1c),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x100, "gpb6", 0x20),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x120, "gpb7", 0x24),
-	EXYNOS850_PIN_BANK_EINTG(5, 0x140, "gpd1", 0x28),
-	EXYNOS850_PIN_BANK_EINTG(5, 0x160, "gpd2", 0x2c),
-	EXYNOS850_PIN_BANK_EINTG(7, 0x180, "gpd3", 0x30),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x1a0, "gpg0", 0x34),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x1c0, "gpg1", 0x38),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x1e0, "gpg2", 0x3c),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x200, "gpg3", 0x40),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x220, "gpg4", 0x44),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x240, "gpg5", 0x48),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x260, "gpg6", 0x4c),
-	EXYNOS850_PIN_BANK_EINTG(8, 0x280, "gpg7", 0x50),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x000, "gpc8", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x020, "gpf2", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x040, "gpf3", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x060, "gpd0", 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x080, "gpb0", 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x0a0, "gpb1", 0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x0c0, "gpb4", 0x18),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0e0, "gpb5", 0x1c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x100, "gpb6", 0x20),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x120, "gpb7", 0x24),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x140, "gpd1", 0x28),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x160, "gpd2", 0x2c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x180, "gpd3", 0x30),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x1a0, "gpg0", 0x34),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x1c0, "gpg1", 0x38),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x1e0, "gpg2", 0x3c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x200, "gpg3", 0x40),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x220, "gpg4", 0x44),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x240, "gpg5", 0x48),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x260, "gpg6", 0x4c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x280, "gpg7", 0x50),
 };
 
 /* pin banks of FSD pin-controller 2 (PMU) */
 static const struct samsung_pin_bank_data fsd_pin_banks2[] __initconst = {
-	EXYNOS850_PIN_BANK_EINTN(3, 0x00, "gpq0"),
+	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 3, 0x00, "gpq0"),
 };
 
 static const struct samsung_pin_ctrl fsd_pin_ctrl[] __initconst = {
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.h b/drivers/pinctrl/samsung/pinctrl-exynos.h
index c9c38f8988dd..41cec8408d0d 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos.h
+++ b/drivers/pinctrl/samsung/pinctrl-exynos.h
@@ -132,37 +132,18 @@
 		.pctl_res_idx   = pctl_idx,			\
 	}							\
 
-#define EXYNOS7870_PIN_BANK_EINTN(pins, reg, id)		\
+#define EXYNOS9_PIN_BANK_EINTN(bank_type, pins, reg, id)	\
 	{							\
-		.type		= &exynos7870_bank_type_alive,	\
+		.type		= &bank_type,			\
 		.pctl_offset	= reg,				\
 		.nr_pins	= pins,				\
 		.eint_type	= EINT_TYPE_NONE,		\
 		.name		= id				\
 	}
 
-#define EXYNOS7870_PIN_BANK_EINTW(pins, reg, id, offs)		\
+#define EXYNOS9_PIN_BANK_EINTG(bank_type, pins, reg, id, offs)	\
 	{							\
-		.type		= &exynos7870_bank_type_alive,	\
-		.pctl_offset	= reg,				\
-		.nr_pins	= pins,				\
-		.eint_type	= EINT_TYPE_WKUP,		\
-		.eint_offset	= offs,				\
-		.name		= id				\
-	}
-
-#define EXYNOS850_PIN_BANK_EINTN(pins, reg, id)			\
-	{							\
-		.type		= &exynos850_bank_type_alive,	\
-		.pctl_offset	= reg,				\
-		.nr_pins	= pins,				\
-		.eint_type	= EINT_TYPE_NONE,		\
-		.name		= id				\
-	}
-
-#define EXYNOS850_PIN_BANK_EINTG(pins, reg, id, offs)		\
-	{							\
-		.type		= &exynos850_bank_type_off,	\
+		.type		= &bank_type,			\
 		.pctl_offset	= reg,				\
 		.nr_pins	= pins,				\
 		.eint_type	= EINT_TYPE_GPIO,		\
@@ -170,9 +151,9 @@
 		.name		= id				\
 	}
 
-#define EXYNOS850_PIN_BANK_EINTW(pins, reg, id, offs)		\
+#define EXYNOS9_PIN_BANK_EINTW(bank_type, pins, reg, id, offs)	\
 	{							\
-		.type		= &exynos850_bank_type_alive,	\
+		.type		= &bank_type,			\
 		.pctl_offset	= reg,				\
 		.nr_pins	= pins,				\
 		.eint_type	= EINT_TYPE_WKUP,		\
@@ -180,19 +161,9 @@
 		.name		= id				\
 	}
 
-#define EXYNOS8895_PIN_BANK_EINTG(pins, reg, id, offs)		\
-	{							\
-		.type		= &exynos8895_bank_type_off,	\
-		.pctl_offset	= reg,				\
-		.nr_pins	= pins,				\
-		.eint_type	= EINT_TYPE_GPIO,		\
-		.eint_offset	= offs,				\
-		.name		= id				\
-	}
-
 #define EXYNOSV920_PIN_BANK_EINTG(pins, reg, id, con_offs, mask_offs, pend_offs)	\
 	{							\
-		.type			= &exynos850_bank_type_off,	\
+		.type			= &exynos9_bank_type_off,	\
 		.pctl_offset		= reg,				\
 		.nr_pins		= pins,				\
 		.eint_type		= EINT_TYPE_GPIO,		\
@@ -204,7 +175,7 @@
 
 #define EXYNOSV920_PIN_BANK_EINTW(pins, reg, id, con_offs, mask_offs, pend_offs)	\
 	{							\
-		.type			= &exynos850_bank_type_alive,	\
+		.type			= &exynos9_bank_type_alive,	\
 		.pctl_offset		= reg,				\
 		.nr_pins		= pins,				\
 		.eint_type		= EINT_TYPE_WKUP,		\
@@ -216,7 +187,7 @@
 
 #define GS101_PIN_BANK_EINTG(pins, reg, id, offs, fltcon_offs) \
 	{							\
-		.type			= &exynos850_bank_type_off,	\
+		.type			= &exynos9_bank_type_off,	\
 		.pctl_offset		= reg,			\
 		.nr_pins		= pins,			\
 		.eint_type		= EINT_TYPE_GPIO,	\
@@ -227,7 +198,7 @@
 
 #define GS101_PIN_BANK_EINTW(pins, reg, id, offs, fltcon_offs) \
 	{								\
-		.type			= &exynos850_bank_type_alive,	\
+		.type			= &exynos9_bank_type_alive,	\
 		.pctl_offset		= reg,				\
 		.nr_pins		= pins,				\
 		.eint_type		= EINT_TYPE_WKUP,		\
-- 
2.52.0



From youngmin.nam at samsung.com  Tue Dec  2 01:36:11 2025
From: youngmin.nam at samsung.com (Youngmin Nam)
Date: Tue,  2 Dec 2025 18:36:11 +0900
Subject: [PATCH v3 4/5] pinctrl: samsung: fold GS101 pin-bank macros into
 EXYNOS9_*
In-Reply-To: <20251202093613.852109-1-youngmin.nam@samsung.com>
References: <20251202093613.852109-1-youngmin.nam@samsung.com>
	<CGME20251202093028epcas2p1955176332d21ce4cadf7ed8894c5c1fa@epcas2p1.samsung.com>
Message-ID: <20251202093613.852109-5-youngmin.nam@samsung.com>

GS101 had dedicated GS101_PIN_BANK_EINT{G,W} helpers, but they are
redundant with EXYNOS9_PIN_BANK_EINT{G,W} (same semantics, including
the per-bank .eint_fltcon_offset).
This change removes the GS101_* macros and switches the GS101 pin-bank
tables to the EXYNOS9_* helpers with exynos9_bank_type_{alive,off}.
While here, update the struct comment to note FLTCON is Exynos9-specific
(not 'GS101-specific').

One macro family for all Exynos9-era SoCs (incl. GS101) reduces
copy-paste drift and keeps the FLTCON handling consistent.
There is no functional change.

Signed-off-by: Youngmin Nam <youngmin.nam at samsung.com>
Reviewed-by: Sam Protsenko <semen.protsenko at linaro.org>
Reviewed-by: Peter Griffin <peter.griffin at linaro.org>
Tested-by: Sam Protsenko <semen.protsenko at linaro.org>
Tested-by: Peter Griffin <peter.griffin at linaro.org> (tested on Pixel6/gs101)
---
 .../pinctrl/samsung/pinctrl-exynos-arm64.c    | 98 +++++++++----------
 drivers/pinctrl/samsung/pinctrl-exynos.h      | 22 -----
 drivers/pinctrl/samsung/pinctrl-samsung.h     |  4 +-
 3 files changed, 51 insertions(+), 73 deletions(-)

diff --git a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
index 92ae1bc80f9c..f473a576f58c 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
+++ b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
@@ -1842,83 +1842,83 @@ const struct samsung_pinctrl_of_match_data fsd_of_data __initconst = {
 
 /* pin banks of gs101 pin-controller (ALIVE) */
 static const struct samsung_pin_bank_data gs101_pin_alive[] = {
-	GS101_PIN_BANK_EINTW(8, 0x0, "gpa0", 0x00, 0x00),
-	GS101_PIN_BANK_EINTW(7, 0x20, "gpa1", 0x04, 0x08),
-	GS101_PIN_BANK_EINTW(5, 0x40, "gpa2", 0x08, 0x10),
-	GS101_PIN_BANK_EINTW(4, 0x60, "gpa3", 0x0c, 0x18),
-	GS101_PIN_BANK_EINTW(4, 0x80, "gpa4", 0x10, 0x1c),
-	GS101_PIN_BANK_EINTW(7, 0xa0, "gpa5", 0x14, 0x20),
-	GS101_PIN_BANK_EINTW(8, 0xc0, "gpa9", 0x18, 0x28),
-	GS101_PIN_BANK_EINTW(2, 0xe0, "gpa10", 0x1c, 0x30),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x0, "gpa0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 7, 0x20, "gpa1", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 5, 0x40, "gpa2", 0x08, 0x10),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 4, 0x60, "gpa3", 0x0c, 0x18),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 4, 0x80, "gpa4", 0x10, 0x1c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 7, 0xa0, "gpa5", 0x14, 0x20),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0xc0, "gpa9", 0x18, 0x28),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0xe0, "gpa10", 0x1c, 0x30),
 };
 
 /* pin banks of gs101 pin-controller (FAR_ALIVE) */
 static const struct samsung_pin_bank_data gs101_pin_far_alive[] = {
-	GS101_PIN_BANK_EINTW(8, 0x0, "gpa6", 0x00, 0x00),
-	GS101_PIN_BANK_EINTW(4, 0x20, "gpa7", 0x04, 0x08),
-	GS101_PIN_BANK_EINTW(8, 0x40, "gpa8", 0x08, 0x0c),
-	GS101_PIN_BANK_EINTW(2, 0x60, "gpa11", 0x0c, 0x14),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x0, "gpa6", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 4, 0x20, "gpa7", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x40, "gpa8", 0x08, 0x0c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x60, "gpa11", 0x0c, 0x14),
 };
 
 /* pin banks of gs101 pin-controller (GSACORE) */
 static const struct samsung_pin_bank_data gs101_pin_gsacore[] = {
-	GS101_PIN_BANK_EINTG(2, 0x0, "gps0", 0x00, 0x00),
-	GS101_PIN_BANK_EINTG(8, 0x20, "gps1", 0x04, 0x04),
-	GS101_PIN_BANK_EINTG(3, 0x40, "gps2", 0x08, 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x0, "gps0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x20, "gps1", 0x04, 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 3, 0x40, "gps2", 0x08, 0x0c),
 };
 
 /* pin banks of gs101 pin-controller (GSACTRL) */
 static const struct samsung_pin_bank_data gs101_pin_gsactrl[] = {
-	GS101_PIN_BANK_EINTW(6, 0x0, "gps3", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 6, 0x0, "gps3", 0x00, 0x00),
 };
 
 /* pin banks of gs101 pin-controller (PERIC0) */
 static const struct samsung_pin_bank_data gs101_pin_peric0[] = {
-	GS101_PIN_BANK_EINTG(5, 0x0, "gpp0", 0x00, 0x00),
-	GS101_PIN_BANK_EINTG(4, 0x20, "gpp1", 0x04, 0x08),
-	GS101_PIN_BANK_EINTG(4, 0x40, "gpp2", 0x08, 0x0c),
-	GS101_PIN_BANK_EINTG(2, 0x60, "gpp3", 0x0c, 0x10),
-	GS101_PIN_BANK_EINTG(4, 0x80, "gpp4", 0x10, 0x14),
-	GS101_PIN_BANK_EINTG(2, 0xa0, "gpp5", 0x14, 0x18),
-	GS101_PIN_BANK_EINTG(4, 0xc0, "gpp6", 0x18, 0x1c),
-	GS101_PIN_BANK_EINTG(2, 0xe0, "gpp7", 0x1c, 0x20),
-	GS101_PIN_BANK_EINTG(4, 0x100, "gpp8", 0x20, 0x24),
-	GS101_PIN_BANK_EINTG(2, 0x120, "gpp9", 0x24, 0x28),
-	GS101_PIN_BANK_EINTG(4, 0x140, "gpp10", 0x28, 0x2c),
-	GS101_PIN_BANK_EINTG(2, 0x160, "gpp11", 0x2c, 0x30),
-	GS101_PIN_BANK_EINTG(4, 0x180, "gpp12", 0x30, 0x34),
-	GS101_PIN_BANK_EINTG(2, 0x1a0, "gpp13", 0x34, 0x38),
-	GS101_PIN_BANK_EINTG(4, 0x1c0, "gpp14", 0x38, 0x3c),
-	GS101_PIN_BANK_EINTG(2, 0x1e0, "gpp15", 0x3c, 0x40),
-	GS101_PIN_BANK_EINTG(4, 0x200, "gpp16", 0x40, 0x44),
-	GS101_PIN_BANK_EINTG(2, 0x220, "gpp17", 0x44, 0x48),
-	GS101_PIN_BANK_EINTG(4, 0x240, "gpp18", 0x48, 0x4c),
-	GS101_PIN_BANK_EINTG(4, 0x260, "gpp19", 0x4c, 0x50),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x0, "gpp0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x20, "gpp1", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x40, "gpp2", 0x08, 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x60, "gpp3", 0x0c, 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x80, "gpp4", 0x10, 0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0xa0, "gpp5", 0x14, 0x18),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0xc0, "gpp6", 0x18, 0x1c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0xe0, "gpp7", 0x1c, 0x20),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x100, "gpp8", 0x20, 0x24),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x120, "gpp9", 0x24, 0x28),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x140, "gpp10", 0x28, 0x2c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x160, "gpp11", 0x2c, 0x30),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x180, "gpp12", 0x30, 0x34),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x1a0, "gpp13", 0x34, 0x38),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x1c0, "gpp14", 0x38, 0x3c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x1e0, "gpp15", 0x3c, 0x40),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x200, "gpp16", 0x40, 0x44),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x220, "gpp17", 0x44, 0x48),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x240, "gpp18", 0x48, 0x4c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x260, "gpp19", 0x4c, 0x50),
 };
 
 /* pin banks of gs101 pin-controller (PERIC1) */
 static const struct samsung_pin_bank_data gs101_pin_peric1[] = {
-	GS101_PIN_BANK_EINTG(8, 0x0, "gpp20", 0x00, 0x00),
-	GS101_PIN_BANK_EINTG(4, 0x20, "gpp21", 0x04, 0x08),
-	GS101_PIN_BANK_EINTG(2, 0x40, "gpp22", 0x08, 0x0c),
-	GS101_PIN_BANK_EINTG(8, 0x60, "gpp23", 0x0c, 0x10),
-	GS101_PIN_BANK_EINTG(4, 0x80, "gpp24", 0x10, 0x18),
-	GS101_PIN_BANK_EINTG(4, 0xa0, "gpp25", 0x14, 0x1c),
-	GS101_PIN_BANK_EINTG(5, 0xc0, "gpp26", 0x18, 0x20),
-	GS101_PIN_BANK_EINTG(4, 0xe0, "gpp27", 0x1c, 0x28),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x0, "gpp20", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x20, "gpp21", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x40, "gpp22", 0x08, 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x60, "gpp23", 0x0c, 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x80, "gpp24", 0x10, 0x18),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0xa0, "gpp25", 0x14, 0x1c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0xc0, "gpp26", 0x18, 0x20),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0xe0, "gpp27", 0x1c, 0x28),
 };
 
 /* pin banks of gs101 pin-controller (HSI1) */
 static const struct samsung_pin_bank_data gs101_pin_hsi1[] = {
-	GS101_PIN_BANK_EINTG(6, 0x0, "gph0", 0x00, 0x00),
-	GS101_PIN_BANK_EINTG(7, 0x20, "gph1", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x0, "gph0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x20, "gph1", 0x04, 0x08),
 };
 
 /* pin banks of gs101 pin-controller (HSI2) */
 static const struct samsung_pin_bank_data gs101_pin_hsi2[] = {
-	GS101_PIN_BANK_EINTG(6, 0x0, "gph2", 0x00, 0x00),
-	GS101_PIN_BANK_EINTG(2, 0x20, "gph3", 0x04, 0x08),
-	GS101_PIN_BANK_EINTG(6, 0x40, "gph4", 0x08, 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x0, "gph2", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x20, "gph3", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x40, "gph4", 0x08, 0x0c),
 };
 
 static const struct samsung_pin_ctrl gs101_pin_ctrl[] __initconst = {
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.h b/drivers/pinctrl/samsung/pinctrl-exynos.h
index 7ebfdcaf2781..24f85ff5ed30 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos.h
+++ b/drivers/pinctrl/samsung/pinctrl-exynos.h
@@ -187,28 +187,6 @@
 		.name			= id				\
 	}
 
-#define GS101_PIN_BANK_EINTG(pins, reg, id, offs, fltcon_offs) \
-	{							\
-		.type			= &exynos9_bank_type_off,	\
-		.pctl_offset		= reg,			\
-		.nr_pins		= pins,			\
-		.eint_type		= EINT_TYPE_GPIO,	\
-		.eint_offset		= offs,			\
-		.eint_fltcon_offset	= fltcon_offs,		\
-		.name			= id			\
-	}
-
-#define GS101_PIN_BANK_EINTW(pins, reg, id, offs, fltcon_offs) \
-	{								\
-		.type			= &exynos9_bank_type_alive,	\
-		.pctl_offset		= reg,				\
-		.nr_pins		= pins,				\
-		.eint_type		= EINT_TYPE_WKUP,		\
-		.eint_offset		= offs,				\
-		.eint_fltcon_offset	= fltcon_offs,			\
-		.name			= id				\
-	}
-
 #define ARTPEC_PIN_BANK_EINTG(pins, reg, id, offs)			\
 	{								\
 		.type			= &artpec_bank_type_off,	\
diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h
index 0f7b2ea98158..0209c2d28858 100644
--- a/drivers/pinctrl/samsung/pinctrl-samsung.h
+++ b/drivers/pinctrl/samsung/pinctrl-samsung.h
@@ -145,7 +145,7 @@ struct samsung_pin_bank_type {
  * @eint_con_offset: ExynosAuto SoC-specific EINT control register offset of bank.
  * @eint_mask_offset: ExynosAuto SoC-specific EINT mask register offset of bank.
  * @eint_pend_offset: ExynosAuto SoC-specific EINT pend register offset of bank.
- * @eint_fltcon_offset: GS101 SoC-specific EINT filter config register offset.
+ * @eint_fltcon_offset: Exynos9 SoC-specific EINT filter config register offset.
  * @name: name to be prefixed for each pin in this pin bank.
  */
 struct samsung_pin_bank_data {
@@ -180,7 +180,7 @@ struct samsung_pin_bank_data {
  * @eint_con_offset: ExynosAuto SoC-specific EINT register or interrupt offset of bank.
  * @eint_mask_offset: ExynosAuto SoC-specific EINT mask register offset of bank.
  * @eint_pend_offset: ExynosAuto SoC-specific EINT pend register offset of bank.
- * @eint_fltcon_offset: GS101 SoC-specific EINT filter config register offset.
+ * @eint_fltcon_offset: Exynos9 SoC-specific EINT filter config register offset.
  * @name: name to be prefixed for each pin in this pin bank.
  * @id: id of the bank, propagated to the pin range.
  * @pin_base: starting pin number of the bank.
-- 
2.52.0



From youngmin.nam at samsung.com  Tue Dec  2 01:36:12 2025
From: youngmin.nam at samsung.com (Youngmin Nam)
Date: Tue,  2 Dec 2025 18:36:12 +0900
Subject: [PATCH v3 5/5] pinctrl: samsung: rename gs101_pinctrl_* to
 exynos9_pinctrl_*
In-Reply-To: <20251202093613.852109-1-youngmin.nam@samsung.com>
References: <20251202093613.852109-1-youngmin.nam@samsung.com>
	<CGME20251202093029epcas2p19224bab81f8ed2b9f63613fdd010ab57@epcas2p1.samsung.com>
Message-ID: <20251202093613.852109-6-youngmin.nam@samsung.com>

The suspend/resume helpers named gs101_pinctrl_{suspend,resume} are not
GS101-specific. They implement the generic save/restore sequence used by
Exynos9-style controllers that have EINT filter configuration
(eint_fltcon) to preserve.

Rename them to exynos9_pinctrl_{suspend,resume} and update all users:
  - exynos2200, exynos9810, exynos8895, exynos7885, exynos7870,
    exynosautov9, fsd, and gs101 controller tables
  - prototypes in pinctrl-exynos.h
  - definitions in pinctrl-exynos.c

This aligns naming with the earlier macro/doc cleanups (e.g. using
EXYNOS9_PIN_BANK_* and describing eint_fltcon as Exynos9-specific) and
makes the helpers clearly reusable by other Exynos9-like SoCs.

Signed-off-by: Youngmin Nam <youngmin.nam at samsung.com>
Reviewed-by: Sam Protsenko <semen.protsenko at linaro.org>
Reviewed-by: Peter Griffin <peter.griffin at linaro.org>
Tested-by: Peter Griffin <peter.griffin at linaro.org> (tested on Pixel6/gs101)
---
 .../pinctrl/samsung/pinctrl-exynos-arm64.c    | 176 +++++++++---------
 drivers/pinctrl/samsung/pinctrl-exynos.c      |   4 +-
 drivers/pinctrl/samsung/pinctrl-exynos.h      |   4 +-
 3 files changed, 92 insertions(+), 92 deletions(-)

diff --git a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
index f473a576f58c..3839256ebf80 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
+++ b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
@@ -195,16 +195,16 @@ static const struct samsung_pin_ctrl exynos2200_pin_ctrl[] = {
 		.nr_banks	= ARRAY_SIZE(exynos2200_pin_banks0),
 		.eint_gpio_init = exynos_eint_gpio_init,
 		.eint_wkup_init = exynos_eint_wkup_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 1 CMGP data */
 		.pin_banks	= exynos2200_pin_banks1,
 		.nr_banks	= ARRAY_SIZE(exynos2200_pin_banks1),
 		.eint_gpio_init = exynos_eint_gpio_init,
 		.eint_wkup_init = exynos_eint_wkup_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 2 HSI1 data */
 		.pin_banks	= exynos2200_pin_banks2,
@@ -214,36 +214,36 @@ static const struct samsung_pin_ctrl exynos2200_pin_ctrl[] = {
 		.pin_banks	= exynos2200_pin_banks3,
 		.nr_banks	= ARRAY_SIZE(exynos2200_pin_banks3),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 4 HSI1UFS data */
 		.pin_banks	= exynos2200_pin_banks4,
 		.nr_banks	= ARRAY_SIZE(exynos2200_pin_banks4),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 5 PERIC0 data */
 		.pin_banks	= exynos2200_pin_banks5,
 		.nr_banks	= ARRAY_SIZE(exynos2200_pin_banks5),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 6 PERIC1 data */
 		.pin_banks	= exynos2200_pin_banks6,
 		.nr_banks	= ARRAY_SIZE(exynos2200_pin_banks6),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 7 PERIC2 data */
 		.pin_banks	= exynos2200_pin_banks7,
 		.nr_banks	= ARRAY_SIZE(exynos2200_pin_banks7),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 8 VTS data */
 		.pin_banks	= exynos2200_pin_banks8,
@@ -710,8 +710,8 @@ static const struct samsung_pin_ctrl exynos7870_pin_ctrl[] __initconst = {
 		.pin_banks	= exynos7870_pin_banks0,
 		.nr_banks	= ARRAY_SIZE(exynos7870_pin_banks0),
 		.eint_wkup_init = exynos_eint_wkup_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 1 DISPAUD data */
 		.pin_banks	= exynos7870_pin_banks1,
@@ -721,43 +721,43 @@ static const struct samsung_pin_ctrl exynos7870_pin_ctrl[] __initconst = {
 		.pin_banks	= exynos7870_pin_banks2,
 		.nr_banks	= ARRAY_SIZE(exynos7870_pin_banks2),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 3 FSYS data */
 		.pin_banks	= exynos7870_pin_banks3,
 		.nr_banks	= ARRAY_SIZE(exynos7870_pin_banks3),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 4 MIF data */
 		.pin_banks	= exynos7870_pin_banks4,
 		.nr_banks	= ARRAY_SIZE(exynos7870_pin_banks4),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 5 NFC data */
 		.pin_banks	= exynos7870_pin_banks5,
 		.nr_banks	= ARRAY_SIZE(exynos7870_pin_banks5),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 6 TOP data */
 		.pin_banks	= exynos7870_pin_banks6,
 		.nr_banks	= ARRAY_SIZE(exynos7870_pin_banks6),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 7 TOUCH data */
 		.pin_banks	= exynos7870_pin_banks7,
 		.nr_banks	= ARRAY_SIZE(exynos7870_pin_banks7),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	},
 };
 
@@ -819,8 +819,8 @@ static const struct samsung_pin_ctrl exynos7885_pin_ctrl[] __initconst = {
 		.nr_banks	= ARRAY_SIZE(exynos7885_pin_banks0),
 		.eint_gpio_init = exynos_eint_gpio_init,
 		.eint_wkup_init = exynos_eint_wkup_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 1 DISPAUD data */
 		.pin_banks	= exynos7885_pin_banks1,
@@ -830,15 +830,15 @@ static const struct samsung_pin_ctrl exynos7885_pin_ctrl[] __initconst = {
 		.pin_banks	= exynos7885_pin_banks2,
 		.nr_banks	= ARRAY_SIZE(exynos7885_pin_banks2),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 3 TOP data */
 		.pin_banks	= exynos7885_pin_banks3,
 		.nr_banks	= ARRAY_SIZE(exynos7885_pin_banks3),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	},
 };
 
@@ -1175,8 +1175,8 @@ static const struct samsung_pin_ctrl exynos9810_pin_ctrl[] __initconst = {
 		.nr_banks       = ARRAY_SIZE(exynos9810_pin_banks0),
 		.eint_wkup_init = exynos_eint_wkup_init,
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend        = exynos_pinctrl_suspend,
-		.resume         = exynos_pinctrl_resume,
+		.suspend        = exynos9_pinctrl_suspend,
+		.resume         = exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 1 AUD data */
 		.pin_banks      = exynos9810_pin_banks1,
@@ -1186,44 +1186,44 @@ static const struct samsung_pin_ctrl exynos9810_pin_ctrl[] __initconst = {
 		.pin_banks      = exynos9810_pin_banks2,
 		.nr_banks       = ARRAY_SIZE(exynos9810_pin_banks2),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend        = exynos_pinctrl_suspend,
-		.resume         = exynos_pinctrl_resume,
+		.suspend        = exynos9_pinctrl_suspend,
+		.resume         = exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 3 CMGP data */
 		.pin_banks      = exynos9810_pin_banks3,
 		.nr_banks       = ARRAY_SIZE(exynos9810_pin_banks3),
 		.eint_wkup_init = exynos_eint_wkup_init,
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend        = exynos_pinctrl_suspend,
-		.resume         = exynos_pinctrl_resume,
+		.suspend        = exynos9_pinctrl_suspend,
+		.resume         = exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 4 FSYS0 data */
 		.pin_banks      = exynos9810_pin_banks4,
 		.nr_banks       = ARRAY_SIZE(exynos9810_pin_banks4),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend        = exynos_pinctrl_suspend,
-		.resume         = exynos_pinctrl_resume,
+		.suspend        = exynos9_pinctrl_suspend,
+		.resume         = exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 5 FSYS1 data */
 		.pin_banks      = exynos9810_pin_banks5,
 		.nr_banks       = ARRAY_SIZE(exynos9810_pin_banks5),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend        = exynos_pinctrl_suspend,
-		.resume         = exynos_pinctrl_resume,
+		.suspend        = exynos9_pinctrl_suspend,
+		.resume         = exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 6 PERIC0 data */
 		.pin_banks      = exynos9810_pin_banks6,
 		.nr_banks       = ARRAY_SIZE(exynos9810_pin_banks6),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend        = exynos_pinctrl_suspend,
-		.resume         = exynos_pinctrl_resume,
+		.suspend        = exynos9_pinctrl_suspend,
+		.resume         = exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 7 PERIC1 data */
 		.pin_banks      = exynos9810_pin_banks7,
 		.nr_banks       = ARRAY_SIZE(exynos9810_pin_banks7),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend        = exynos_pinctrl_suspend,
-		.resume         = exynos_pinctrl_resume,
+		.suspend        = exynos9_pinctrl_suspend,
+		.resume         = exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 8 VTS data */
 		.pin_banks      = exynos9810_pin_banks8,
@@ -1295,8 +1295,8 @@ static const struct samsung_pin_ctrl exynosautov9_pin_ctrl[] __initconst = {
 		.pin_banks      = exynosautov9_pin_banks0,
 		.nr_banks       = ARRAY_SIZE(exynosautov9_pin_banks0),
 		.eint_wkup_init = exynos_eint_wkup_init,
-		.suspend        = exynos_pinctrl_suspend,
-		.resume         = exynos_pinctrl_resume,
+		.suspend        = exynos9_pinctrl_suspend,
+		.resume         = exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 1 AUD data */
 		.pin_banks      = exynosautov9_pin_banks1,
@@ -1306,36 +1306,36 @@ static const struct samsung_pin_ctrl exynosautov9_pin_ctrl[] __initconst = {
 		.pin_banks      = exynosautov9_pin_banks2,
 		.nr_banks       = ARRAY_SIZE(exynosautov9_pin_banks2),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend        = exynos_pinctrl_suspend,
-		.resume         = exynos_pinctrl_resume,
+		.suspend        = exynos9_pinctrl_suspend,
+		.resume         = exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 3 FSYS1 data */
 		.pin_banks      = exynosautov9_pin_banks3,
 		.nr_banks       = ARRAY_SIZE(exynosautov9_pin_banks3),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend        = exynos_pinctrl_suspend,
-		.resume         = exynos_pinctrl_resume,
+		.suspend        = exynos9_pinctrl_suspend,
+		.resume         = exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 4 FSYS2 data */
 		.pin_banks      = exynosautov9_pin_banks4,
 		.nr_banks       = ARRAY_SIZE(exynosautov9_pin_banks4),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend        = exynos_pinctrl_suspend,
-		.resume         = exynos_pinctrl_resume,
+		.suspend        = exynos9_pinctrl_suspend,
+		.resume         = exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 5 PERIC0 data */
 		.pin_banks      = exynosautov9_pin_banks5,
 		.nr_banks       = ARRAY_SIZE(exynosautov9_pin_banks5),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend        = exynos_pinctrl_suspend,
-		.resume         = exynos_pinctrl_resume,
+		.suspend        = exynos9_pinctrl_suspend,
+		.resume         = exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 6 PERIC1 data */
 		.pin_banks      = exynosautov9_pin_banks6,
 		.nr_banks       = ARRAY_SIZE(exynosautov9_pin_banks6),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend        = exynos_pinctrl_suspend,
-		.resume         = exynos_pinctrl_resume,
+		.suspend        = exynos9_pinctrl_suspend,
+		.resume         = exynos9_pinctrl_resume,
 	},
 };
 
@@ -1715,8 +1715,8 @@ static const struct samsung_pin_ctrl exynos8895_pin_ctrl[] __initconst = {
 		.nr_banks	= ARRAY_SIZE(exynos8895_pin_banks0),
 		.eint_gpio_init = exynos_eint_gpio_init,
 		.eint_wkup_init = exynos_eint_wkup_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 1 ABOX data */
 		.pin_banks	= exynos8895_pin_banks1,
@@ -1731,36 +1731,36 @@ static const struct samsung_pin_ctrl exynos8895_pin_ctrl[] __initconst = {
 		.pin_banks	= exynos8895_pin_banks3,
 		.nr_banks	= ARRAY_SIZE(exynos8895_pin_banks3),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 4 FSYS1 data */
 		.pin_banks	= exynos8895_pin_banks4,
 		.nr_banks	= ARRAY_SIZE(exynos8895_pin_banks4),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 5 BUSC data */
 		.pin_banks	= exynos8895_pin_banks5,
 		.nr_banks	= ARRAY_SIZE(exynos8895_pin_banks5),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 6 PERIC0 data */
 		.pin_banks	= exynos8895_pin_banks6,
 		.nr_banks	= ARRAY_SIZE(exynos8895_pin_banks6),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 7 PERIC1 data */
 		.pin_banks	= exynos8895_pin_banks7,
 		.nr_banks	= ARRAY_SIZE(exynos8895_pin_banks7),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	},
 };
 
@@ -1819,15 +1819,15 @@ static const struct samsung_pin_ctrl fsd_pin_ctrl[] __initconst = {
 		.pin_banks	= fsd_pin_banks0,
 		.nr_banks	= ARRAY_SIZE(fsd_pin_banks0),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 1 PERIC data */
 		.pin_banks	= fsd_pin_banks1,
 		.nr_banks	= ARRAY_SIZE(fsd_pin_banks1),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	}, {
 		/* pin-controller instance 2 PMU data */
 		.pin_banks	= fsd_pin_banks2,
@@ -1927,16 +1927,16 @@ static const struct samsung_pin_ctrl gs101_pin_ctrl[] __initconst = {
 		.pin_banks	= gs101_pin_alive,
 		.nr_banks	= ARRAY_SIZE(gs101_pin_alive),
 		.eint_wkup_init = exynos_eint_wkup_init,
-		.suspend	= gs101_pinctrl_suspend,
-		.resume		= gs101_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 		.retention_data = &no_retention_data,
 	}, {
 		/* pin banks of gs101 pin-controller (FAR_ALIVE) */
 		.pin_banks	= gs101_pin_far_alive,
 		.nr_banks	= ARRAY_SIZE(gs101_pin_far_alive),
 		.eint_wkup_init = exynos_eint_wkup_init,
-		.suspend	= gs101_pinctrl_suspend,
-		.resume		= gs101_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 		.retention_data = &no_retention_data,
 	}, {
 		/* pin banks of gs101 pin-controller (GSACORE) */
@@ -1951,29 +1951,29 @@ static const struct samsung_pin_ctrl gs101_pin_ctrl[] __initconst = {
 		.pin_banks	= gs101_pin_peric0,
 		.nr_banks	= ARRAY_SIZE(gs101_pin_peric0),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend	= gs101_pinctrl_suspend,
-		.resume		= gs101_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	}, {
 		/* pin banks of gs101 pin-controller (PERIC1) */
 		.pin_banks	= gs101_pin_peric1,
 		.nr_banks	= ARRAY_SIZE(gs101_pin_peric1),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend	= gs101_pinctrl_suspend,
-		.resume		= gs101_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	}, {
 		/* pin banks of gs101 pin-controller (HSI1) */
 		.pin_banks	= gs101_pin_hsi1,
 		.nr_banks	= ARRAY_SIZE(gs101_pin_hsi1),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend	= gs101_pinctrl_suspend,
-		.resume		= gs101_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	}, {
 		/* pin banks of gs101 pin-controller (HSI2) */
 		.pin_banks	= gs101_pin_hsi2,
 		.nr_banks	= ARRAY_SIZE(gs101_pin_hsi2),
 		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend	= gs101_pinctrl_suspend,
-		.resume		= gs101_pinctrl_resume,
+		.suspend	= exynos9_pinctrl_suspend,
+		.resume		= exynos9_pinctrl_resume,
 	},
 };
 
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c
index 81fe0b08a9af..a6dd0fa59230 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos.c
+++ b/drivers/pinctrl/samsung/pinctrl-exynos.c
@@ -906,7 +906,7 @@ void exynos_pinctrl_suspend(struct samsung_pin_bank *bank)
 	}
 }
 
-void gs101_pinctrl_suspend(struct samsung_pin_bank *bank)
+void exynos9_pinctrl_suspend(struct samsung_pin_bank *bank)
 {
 	struct exynos_eint_gpio_save *save = bank->soc_priv;
 	const void __iomem *regs = bank->eint_base;
@@ -961,7 +961,7 @@ void exynosautov920_pinctrl_suspend(struct samsung_pin_bank *bank)
 	}
 }
 
-void gs101_pinctrl_resume(struct samsung_pin_bank *bank)
+void exynos9_pinctrl_resume(struct samsung_pin_bank *bank)
 {
 	struct exynos_eint_gpio_save *save = bank->soc_priv;
 
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.h b/drivers/pinctrl/samsung/pinctrl-exynos.h
index 24f85ff5ed30..612d9a7e8577 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos.h
+++ b/drivers/pinctrl/samsung/pinctrl-exynos.h
@@ -225,8 +225,8 @@ void exynosautov920_pinctrl_resume(struct samsung_pin_bank *bank);
 void exynosautov920_pinctrl_suspend(struct samsung_pin_bank *bank);
 void exynos_pinctrl_suspend(struct samsung_pin_bank *bank);
 void exynos_pinctrl_resume(struct samsung_pin_bank *bank);
-void gs101_pinctrl_suspend(struct samsung_pin_bank *bank);
-void gs101_pinctrl_resume(struct samsung_pin_bank *bank);
+void exynos9_pinctrl_suspend(struct samsung_pin_bank *bank);
+void exynos9_pinctrl_resume(struct samsung_pin_bank *bank);
 struct samsung_retention_ctrl *
 exynos_retention_init(struct samsung_pinctrl_drv_data *drvdata,
 		      const struct samsung_retention_data *data);
-- 
2.52.0



From youngmin.nam at samsung.com  Tue Dec  2 01:36:09 2025
From: youngmin.nam at samsung.com (Youngmin Nam)
Date: Tue,  2 Dec 2025 18:36:09 +0900
Subject: [PATCH v3 2/5] pinctrl: samsung: fix incorrect pin-bank entries on
 Exynos2200/7885/8890/8895
In-Reply-To: <20251202093613.852109-1-youngmin.nam@samsung.com>
References: <20251202093613.852109-1-youngmin.nam@samsung.com>
	<CGME20251202093027epcas2p24adbd3226dd50b2780baceee6588f3ba@epcas2p2.samsung.com>
Message-ID: <20251202093613.852109-3-youngmin.nam@samsung.com>

This patch corrects wrong pin bank table definitions for 4 SoCs based on
their TRMs.

Exynos2200
- gpq0/1/2 were using EXYNOS_PIN_BANK_EINTN(), which implies a
  'bank_type_off' layout (.fld_width = {4,1,2,2,2,2}).
- Per the SoC TRM these banks must use the 'alive' layout
  (.fld_width = {4,1,4,4}).
- Switch them to EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, ...).

Exynos7885
- etc0, etc1: update bank type to match the SoC TRM.
- gpq0 is a non-wakeup interrupt bank; change EINTW -> EINTN accordingly.

Exynos8890
- Per the SoC TRM, rename bank ect0 to gpb3 and mark it as
  a non-external interrupt bank.
- gpi1, gpi2: update bank type to match the SoC TRM.
  exynos8895_bank_type_off (.fld_width = {4,1,2,3,2,2}) ->
  exynos5433_bank_type_off (.fld_width = {4,1,2,4,2,2})
- Per the SoC TRM, mark etc1 as a non-external interrupt bank.
- apply lower case style for hex numbers.

Exynos8895
- gpa4 is a non-wakeup interrupt bank per the SoC TRM.
  change EINTW -> EINTN. (The bank_type itself was correct and is kept
  unchanged.)
- apply lower case style for hex numbers.

This aligns the pin-bank tables with the documented bitfield layouts and
wakeup domains. No DT/ABI change.

Signed-off-by: Youngmin Nam <youngmin.nam at samsung.com>
Reviewed-by: Sam Protsenko <semen.protsenko at linaro.org>
Reviewed-by: Ivaylo Ivanov <ivo.ivanov.ivanov1 at gmail.com>
Tested-by: Sam Protsenko <semen.protsenko at linaro.org>
---
 .../pinctrl/samsung/pinctrl-exynos-arm64.c    | 40 +++++++++----------
 1 file changed, 20 insertions(+), 20 deletions(-)

diff --git a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
index d11b2d4ca913..b4a7d86b82fe 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
+++ b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
@@ -95,9 +95,9 @@ static const struct samsung_pin_bank_data exynos2200_pin_banks0[] __initconst =
 	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x40, "gpa2", 0x08),
 	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x60, "gpa3", 0x0c),
 	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x80, "gpa4", 0x10),
-	EXYNOS_PIN_BANK_EINTN(4, 0xa0, "gpq0"),
-	EXYNOS_PIN_BANK_EINTN(2, 0xc0, "gpq1"),
-	EXYNOS_PIN_BANK_EINTN(2, 0xe0, "gpq2"),
+	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 4, 0xa0, "gpq0"),
+	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 2, 0xc0, "gpq1"),
+	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 2, 0xe0, "gpq2"),
 };
 
 /* pin banks of exynos2200 pin-controller - CMGP */
@@ -768,12 +768,12 @@ const struct samsung_pinctrl_of_match_data exynos7870_of_data __initconst = {
 
 /* pin banks of exynos7885 pin-controller 0 (ALIVE) */
 static const struct samsung_pin_bank_data exynos7885_pin_banks0[] __initconst = {
-	EXYNOS_PIN_BANK_EINTN(3, 0x000, "etc0"),
-	EXYNOS_PIN_BANK_EINTN(3, 0x020, "etc1"),
+	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 3, 0x000, "etc0"),
+	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 3, 0x020, "etc1"),
 	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x040, "gpa0", 0x00),
 	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x060, "gpa1", 0x04),
 	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x080, "gpa2", 0x08),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 5, 0x0a0, "gpq0", 0x0c),
+	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 5, 0x0a0, "gpq0"),
 };
 
 /* pin banks of exynos7885 pin-controller 1 (DISPAUD) */
@@ -1502,7 +1502,7 @@ static const struct samsung_pin_bank_data exynos8890_pin_banks1[] __initconst =
 /* pin banks of exynos8890 pin-controller 2 (CCORE) */
 static const struct samsung_pin_bank_data exynos8890_pin_banks2[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x000, "etc0", 0x00),
+	EXYNOS9_PIN_BANK_EINTN(exynos8895_bank_type_off, 2, 0x000, "gpb3"),
 };
 
 /* pin banks of exynos8890 pin-controller 3 (ESE) */
@@ -1520,8 +1520,8 @@ static const struct samsung_pin_bank_data exynos8890_pin_banks4[] __initconst =
 /* pin banks of exynos8890 pin-controller 5 (FSYS0) */
 static const struct samsung_pin_bank_data exynos8890_pin_banks5[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x000, "gpi1", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x020, "gpi2", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos5433_bank_type_off, 4, 0x000, "gpi1", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos5433_bank_type_off, 8, 0x020, "gpi2", 0x04),
 };
 
 /* pin banks of exynos8890 pin-controller 6 (FSYS1) */
@@ -1544,15 +1544,15 @@ static const struct samsung_pin_bank_data exynos8890_pin_banks8[] __initconst =
 	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 6, 0x040, "gpd1", 0x08),
 	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x060, "gpd2", 0x0c),
 	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x080, "gpd3", 0x10),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x0A0, "gpb1", 0x14),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x0C0, "gpb2", 0x18),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x0E0, "gpb0", 0x1c),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x0a0, "gpb1", 0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x0c0, "gpb2", 0x18),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x0e0, "gpb0", 0x1c),
 	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 5, 0x100, "gpc0", 0x20),
 	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 5, 0x120, "gpc1", 0x24),
 	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 6, 0x140, "gpc2", 0x28),
 	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x160, "gpc3", 0x2c),
 	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x180, "gpk0", 0x30),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 7, 0x1A0, "etc1", 0x34),
+	EXYNOS9_PIN_BANK_EINTN(exynos8895_bank_type_off, 7, 0x1a0, "etc1"),
 };
 
 /* pin banks of exynos8890 pin-controller 9 (PERIC1) */
@@ -1563,9 +1563,9 @@ static const struct samsung_pin_bank_data exynos8890_pin_banks9[] __initconst =
 	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x040, "gpe6", 0x08),
 	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x060, "gpj1", 0x0c),
 	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x080, "gpj2", 0x10),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x0A0, "gpe2", 0x14),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x0C0, "gpe3", 0x18),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x0E0, "gpe4", 0x1c),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x0a0, "gpe2", 0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x0c0, "gpe3", 0x18),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x0e0, "gpe4", 0x1c),
 	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x100, "gpe1", 0x20),
 	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x120, "gpe7", 0x24),
 	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x140, "gpg0", 0x28),
@@ -1647,7 +1647,7 @@ static const struct samsung_pin_bank_data exynos8895_pin_banks0[] __initconst =
 	EXYNOS9_PIN_BANK_EINTW(bank_type_alive, 8, 0x040, "gpa1", 0x04),
 	EXYNOS9_PIN_BANK_EINTW(bank_type_alive, 8, 0x060, "gpa2", 0x08),
 	EXYNOS9_PIN_BANK_EINTW(bank_type_alive, 8, 0x080, "gpa3", 0x0c),
-	EXYNOS9_PIN_BANK_EINTW(bank_type_alive, 7, 0x0a0, "gpa4", 0x24),
+	EXYNOS9_PIN_BANK_EINTN(bank_type_alive, 7, 0x0a0, "gpa4"),
 };
 
 /* pin banks of exynos8895 pin-controller 1 (ABOX) */
@@ -1695,15 +1695,15 @@ static const struct samsung_pin_bank_data exynos8895_pin_banks7[] __initconst =
 	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 3, 0x000, "gpb0", 0x00),
 	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 5, 0x020, "gpc0", 0x04),
 	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 5, 0x040, "gpc1", 0x08),
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x060, "gpc2", 0x0C),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x060, "gpc2", 0x0c),
 	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x080, "gpc3", 0x10),
 	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 4, 0x0a0, "gpk0", 0x14),
 	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x0c0, "gpe5", 0x18),
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x0e0, "gpe6", 0x1C),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x0e0, "gpe6", 0x1c),
 	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x100, "gpe2", 0x20),
 	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x120, "gpe3", 0x24),
 	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x140, "gpe4", 0x28),
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 4, 0x160, "gpf0", 0x2C),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 4, 0x160, "gpf0", 0x2c),
 	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x180, "gpe1", 0x30),
 	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 2, 0x1a0, "gpg0", 0x34),
 };
-- 
2.52.0



From youngmin.nam at samsung.com  Tue Dec  2 01:36:10 2025
From: youngmin.nam at samsung.com (Youngmin Nam)
Date: Tue,  2 Dec 2025 18:36:10 +0900
Subject: [PATCH v3 3/5] pinctrl: samsung: add per-bank FLTCON offset to
 EXYNOS9_PIN_BANK_* and fix tables
In-Reply-To: <20251202093613.852109-1-youngmin.nam@samsung.com>
References: <20251202093613.852109-1-youngmin.nam@samsung.com>
	<CGME20251202093028epcas2p456b6a2bfebfc76384f706a9962266fcf@epcas2p4.samsung.com>
Message-ID: <20251202093613.852109-4-youngmin.nam@samsung.com>

Several Exynos9-era pin-bank tables were implicitly assuming that the
filter control (FLTCON) registers are laid out contiguously from the
EINT base offset. Per the TRMs this is not always true. FLTCON can live
at a separate per-bank offset, and the current tables cause the driver
to program the wrong FLTCON addresses for some banks.

- Extends EXYNOS9_PIN_BANK_EINTG()/EINTW() to take an explicit
  .eint_fltcon_offset parameter.
- Updates pin-bank tables with the correct FLTCON offsets for:
  Exynos2200 (ALIVE/CMGP/HSI1/UFS/HSI1UFS/PERIC0/1/2/VTS),
  Exynos7870 (ALIVE/DISPAUD/ESE/FSYS/MIF/NFC/TOP/TOUCH),
  Exynos7885 (ALIVE/DISPAUD/FSYS/TOP),
  Exynos850  (ALIVE/CMGP/AUD/HSI/CORE/PERI),
  Exynos990  (ALIVE/CMGP/HSI1/HSI2/PERIC0/1/VTS),
  Exynos9810 (ALIVE/AUD/CHUB/CMGP/FSYS0/FSYS1/PERIC0/1/VTS),
  ExynosAuto v9 (ALIVE/AUD/FSYS0/1/2/PERIC0/1),
  Exynos8890 (ALIVE/AUD/CCORE/ESE/FP/FSYS0/1/NFC/PERIC0/1/TOUCH),
  Exynos8895 (ALIVE/ABOX/VTS/FSYS0/1/BUSC/PERIC0/1),
  and FSD (FSYS/PERIC).

Notes:
- GS101 already programs per-bank filter control registers. This change
  aligns the Exynos9 path with that model.
- Banks without filters (EINTN) are unaffected.

Signed-off-by: Youngmin Nam <youngmin.nam at samsung.com>
Reviewed-by: Sam Protsenko <semen.protsenko at linaro.org>
Tested-by: Sam Protsenko <semen.protsenko at linaro.org>
---
 .../pinctrl/samsung/pinctrl-exynos-arm64.c    | 744 +++++++++---------
 drivers/pinctrl/samsung/pinctrl-exynos.h      |  34 +-
 2 files changed, 390 insertions(+), 388 deletions(-)

diff --git a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
index b4a7d86b82fe..92ae1bc80f9c 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
+++ b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
@@ -90,11 +90,11 @@ static atomic_t exynos_shared_retention_refcnt;
 
 /* pin banks of exynos2200 pin-controller - ALIVE */
 static const struct samsung_pin_bank_data exynos2200_pin_banks0[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x0, "gpa0", 0x00),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x20, "gpa1", 0x04),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x40, "gpa2", 0x08),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x60, "gpa3", 0x0c),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x80, "gpa4", 0x10),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x0, "gpa0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x20, "gpa1", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x40, "gpa2", 0x08, 0x10),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x60, "gpa3", 0x0c, 0x18),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x80, "gpa4", 0x10, 0x20),
 	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 4, 0xa0, "gpq0"),
 	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 2, 0xc0, "gpq1"),
 	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 2, 0xe0, "gpq2"),
@@ -102,90 +102,90 @@ static const struct samsung_pin_bank_data exynos2200_pin_banks0[] __initconst =
 
 /* pin banks of exynos2200 pin-controller - CMGP */
 static const struct samsung_pin_bank_data exynos2200_pin_banks1[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x0, "gpm0", 0x00),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x20, "gpm1", 0x04),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x40, "gpm2", 0x08),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x60, "gpm3", 0x0c),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x80, "gpm4", 0x10),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0xa0, "gpm5", 0x14),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0xc0, "gpm6", 0x18),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0xe0, "gpm7", 0x1c),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x100, "gpm8", 0x20),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x120, "gpm9", 0x24),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x140, "gpm10", 0x28),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x160, "gpm11", 0x2c),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x180, "gpm12", 0x30),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x1a0, "gpm13", 0x34),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x1c0, "gpm14", 0x38),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x1e0, "gpm15", 0x3c),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x200, "gpm16", 0x40),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x220, "gpm17", 0x44),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x240, "gpm20", 0x48),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x260, "gpm21", 0x4c),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x280, "gpm22", 0x50),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x2a0, "gpm23", 0x54),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x2c0, "gpm24", 0x58),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x0, "gpm0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x20, "gpm1", 0x04, 0x04),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x40, "gpm2", 0x08, 0x08),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x60, "gpm3", 0x0c, 0x0c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x80, "gpm4", 0x10, 0x10),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0xa0, "gpm5", 0x14, 0x14),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0xc0, "gpm6", 0x18, 0x18),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0xe0, "gpm7", 0x1c, 0x1c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x100, "gpm8", 0x20, 0x20),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x120, "gpm9", 0x24, 0x24),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x140, "gpm10", 0x28, 0x28),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x160, "gpm11", 0x2c, 0x2c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x180, "gpm12", 0x30, 0x30),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x1a0, "gpm13", 0x34, 0x34),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x1c0, "gpm14", 0x38, 0x38),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x1e0, "gpm15", 0x3c, 0x3c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x200, "gpm16", 0x40, 0x40),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x220, "gpm17", 0x44, 0x44),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x240, "gpm20", 0x48, 0x48),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x260, "gpm21", 0x4c, 0x4c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x280, "gpm22", 0x50, 0x50),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x2a0, "gpm23", 0x54, 0x54),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x2c0, "gpm24", 0x58, 0x58),
 };
 
 /* pin banks of exynos2200 pin-controller - HSI1 */
 static const struct samsung_pin_bank_data exynos2200_pin_banks2[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0, "gpf0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0, "gpf0", 0x00, 0x00),
 };
 
 /* pin banks of exynos2200 pin-controller - UFS */
 static const struct samsung_pin_bank_data exynos2200_pin_banks3[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x0, "gpf1", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x0, "gpf1", 0x00, 0x00),
 };
 
 /* pin banks of exynos2200 pin-controller - HSI1UFS */
 static const struct samsung_pin_bank_data exynos2200_pin_banks4[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x0, "gpf2", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x0, "gpf2", 0x00, 0x00),
 };
 
 /* pin banks of exynos2200 pin-controller - PERIC0 */
 static const struct samsung_pin_bank_data exynos2200_pin_banks5[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0, "gpb0",  0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x20, "gpb1",  0x04),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x40, "gpb2",  0x08),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x60, "gpb3",  0x0c),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x80, "gpp4",  0x10),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0xa0, "gpc0",  0x14),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0xc0, "gpc1",  0x18),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0xe0, "gpc2",  0x1c),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x100, "gpg1",  0x20),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x120, "gpg2",  0x24),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0, "gpb0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x20, "gpb1", 0x04, 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x40, "gpb2", 0x08, 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x60, "gpb3", 0x0c, 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x80, "gpp4", 0x10, 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0xa0, "gpc0", 0x14, 0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0xc0, "gpc1", 0x18, 0x18),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0xe0, "gpc2", 0x1c, 0x1c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x100, "gpg1", 0x20, 0x20),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x120, "gpg2", 0x24, 0x24),
 };
 
 /* pin banks of exynos2200 pin-controller - PERIC1 */
 static const struct samsung_pin_bank_data exynos2200_pin_banks6[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0,  "gpp7",  0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x20, "gpp8",  0x04),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x40, "gpp9",  0x08),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x60, "gpp10", 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0, "gpp7", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x20, "gpp8", 0x04, 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x40, "gpp9", 0x08, 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x60, "gpp10", 0x0c, 0x0c),
 };
 
 /* pin banks of exynos2200 pin-controller - PERIC2 */
 static const struct samsung_pin_bank_data exynos2200_pin_banks7[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0, "gpp0",  0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x20, "gpp1",  0x04),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x40, "gpp2",  0x08),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x60, "gpp3",  0x0c),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x80, "gpp5",  0x10),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0xa0, "gpp6",  0x14),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0xc0, "gpp11", 0x18),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0xe0, "gpc3",  0x1c),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x100, "gpc4",  0x20),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x120, "gpc5",  0x24),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x140, "gpc6",  0x28),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x160, "gpc7",  0x2c),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x180, "gpc8",  0x30),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x1a0, "gpc9",  0x34),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x1c0, "gpg0",  0x38),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0, "gpp0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x20, "gpp1", 0x04, 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x40, "gpp2", 0x08, 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x60, "gpp3", 0x0c, 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x80, "gpp5", 0x10, 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0xa0, "gpp6", 0x14, 0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0xc0, "gpp11", 0x18, 0x18),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0xe0, "gpc3", 0x1c, 0x1c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x100, "gpc4", 0x20, 0x20),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x120, "gpc5", 0x24, 0x24),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x140, "gpc6", 0x28, 0x28),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x160, "gpc7", 0x2c, 0x2c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x180, "gpc8", 0x30, 0x30),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x1a0, "gpc9", 0x34, 0x34),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x1c0, "gpg0", 0x38, 0x38),
 };
 
 /* pin banks of exynos2200 pin-controller - VTS */
 static const struct samsung_pin_bank_data exynos2200_pin_banks8[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x0, "gpv0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x0, "gpv0", 0x00, 0x00),
 };
 
 static const struct samsung_pin_ctrl exynos2200_pin_ctrl[] = {
@@ -640,68 +640,68 @@ const struct samsung_pinctrl_of_match_data exynos7_of_data __initconst = {
 static const struct samsung_pin_bank_data exynos7870_pin_banks0[] __initconst = {
 	EXYNOS9_PIN_BANK_EINTN(exynos7870_bank_type_alive, 6, 0x000, "etc0"),
 	EXYNOS9_PIN_BANK_EINTN(exynos7870_bank_type_alive, 3, 0x020, "etc1"),
-	EXYNOS9_PIN_BANK_EINTW(exynos7870_bank_type_alive, 8, 0x040, "gpa0", 0x00),
-	EXYNOS9_PIN_BANK_EINTW(exynos7870_bank_type_alive, 8, 0x060, "gpa1", 0x04),
-	EXYNOS9_PIN_BANK_EINTW(exynos7870_bank_type_alive, 8, 0x080, "gpa2", 0x08),
+	EXYNOS9_PIN_BANK_EINTW(exynos7870_bank_type_alive, 8, 0x040, "gpa0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos7870_bank_type_alive, 8, 0x060, "gpa1", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTW(exynos7870_bank_type_alive, 8, 0x080, "gpa2", 0x08, 0x10),
 	EXYNOS9_PIN_BANK_EINTN(exynos7870_bank_type_alive, 2, 0x0c0, "gpq0"),
 };
 
 /* pin banks of exynos7870 pin-controller 1 (DISPAUD) */
 static const struct samsung_pin_bank_data exynos7870_pin_banks1[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x000, "gpz0", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 6, 0x020, "gpz1", 0x04),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x040, "gpz2", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x000, "gpz0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 6, 0x020, "gpz1", 0x04, 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x040, "gpz2", 0x08, 0x0c),
 };
 
 /* pin banks of exynos7870 pin-controller 2 (ESE) */
 static const struct samsung_pin_bank_data exynos7870_pin_banks2[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 5, 0x000, "gpc7", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 5, 0x000, "gpc7", 0x00, 0x00),
 };
 
 /* pin banks of exynos7870 pin-controller 3 (FSYS) */
 static const struct samsung_pin_bank_data exynos7870_pin_banks3[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x000, "gpr0", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x020, "gpr1", 0x04),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x040, "gpr2", 0x08),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x060, "gpr3", 0x0c),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 6, 0x080, "gpr4", 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x000, "gpr0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x020, "gpr1", 0x04, 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x040, "gpr2", 0x08, 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x060, "gpr3", 0x0c, 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 6, 0x080, "gpr4", 0x10, 0x14),
 };
 
 /* pin banks of exynos7870 pin-controller 4 (MIF) */
 static const struct samsung_pin_bank_data exynos7870_pin_banks4[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x000, "gpm0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x000, "gpm0", 0x00, 0x00),
 };
 
 /* pin banks of exynos7870 pin-controller 5 (NFC) */
 static const struct samsung_pin_bank_data exynos7870_pin_banks5[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x000, "gpc2", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x000, "gpc2", 0x00, 0x00),
 };
 
 /* pin banks of exynos7870 pin-controller 6 (TOP) */
 static const struct samsung_pin_bank_data exynos7870_pin_banks6[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x000, "gpb0", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x020, "gpc0", 0x04),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x040, "gpc1", 0x08),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x060, "gpc4", 0x0c),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x080, "gpc5", 0x10),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x0a0, "gpc6", 0x14),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x0c0, "gpc8", 0x18),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x0e0, "gpc9", 0x1c),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 7, 0x100, "gpd1", 0x20),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 6, 0x120, "gpd2", 0x24),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x140, "gpd3", 0x28),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 7, 0x160, "gpd4", 0x2c),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x1a0, "gpe0", 0x34),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x1c0, "gpf0", 0x38),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x1e0, "gpf1", 0x3c),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x200, "gpf2", 0x40),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x220, "gpf3", 0x44),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 5, 0x240, "gpf4", 0x48),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x000, "gpb0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x020, "gpc0", 0x04, 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x040, "gpc1", 0x08, 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x060, "gpc4", 0x0c, 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x080, "gpc5", 0x10, 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x0a0, "gpc6", 0x14, 0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x0c0, "gpc8", 0x18, 0x18),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x0e0, "gpc9", 0x1c, 0x1c),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 7, 0x100, "gpd1", 0x20, 0x20),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 6, 0x120, "gpd2", 0x24, 0x28),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x140, "gpd3", 0x28, 0x30),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 7, 0x160, "gpd4", 0x2c, 0x38),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x1a0, "gpe0", 0x34, 0x48),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x1c0, "gpf0", 0x38, 0x4c),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x1e0, "gpf1", 0x3c, 0x50),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x200, "gpf2", 0x40, 0x54),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x220, "gpf3", 0x44, 0x58),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 5, 0x240, "gpf4", 0x48, 0x5c),
 };
 
 /* pin banks of exynos7870 pin-controller 7 (TOUCH) */
 static const struct samsung_pin_bank_data exynos7870_pin_banks7[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x000, "gpc3", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x000, "gpc3", 0x00, 0x00),
 };
 
 static const struct samsung_pin_ctrl exynos7870_pin_ctrl[] __initconst = {
@@ -770,46 +770,46 @@ const struct samsung_pinctrl_of_match_data exynos7870_of_data __initconst = {
 static const struct samsung_pin_bank_data exynos7885_pin_banks0[] __initconst = {
 	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 3, 0x000, "etc0"),
 	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 3, 0x020, "etc1"),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x040, "gpa0", 0x00),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x060, "gpa1", 0x04),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x080, "gpa2", 0x08),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x040, "gpa0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x060, "gpa1", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x080, "gpa2", 0x08, 0x10),
 	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 5, 0x0a0, "gpq0"),
 };
 
 /* pin banks of exynos7885 pin-controller 1 (DISPAUD) */
 static const struct samsung_pin_bank_data exynos7885_pin_banks1[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x000, "gpb0", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x020, "gpb1", 0x04),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x040, "gpb2", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x000, "gpb0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x020, "gpb1", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x040, "gpb2", 0x08, 0x0c),
 };
 
 /* pin banks of exynos7885 pin-controller 2 (FSYS) */
 static const struct samsung_pin_bank_data exynos7885_pin_banks2[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x000, "gpf0", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpf2", 0x04),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x040, "gpf3", 0x08),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x060, "gpf4", 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x000, "gpf0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpf2", 0x04, 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x040, "gpf3", 0x08, 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x060, "gpf4", 0x0c, 0x14),
 };
 
 /* pin banks of exynos7885 pin-controller 3 (TOP) */
 static const struct samsung_pin_bank_data exynos7885_pin_banks3[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x000, "gpp0", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 3, 0x020, "gpg0", 0x04),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x040, "gpp1", 0x08),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x060, "gpp2", 0x0c),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 3, 0x080, "gpp3", 0x10),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x0a0, "gpp4", 0x14),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0c0, "gpp5", 0x18),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x0e0, "gpp6", 0x1c),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x100, "gpp7", 0x20),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x120, "gpp8", 0x24),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x140, "gpg1", 0x28),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x160, "gpg2", 0x2c),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x180, "gpg3", 0x30),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x1a0, "gpg4", 0x34),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x1c0, "gpc0", 0x38),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x1e0, "gpc1", 0x3c),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x200, "gpc2", 0x40),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x000, "gpp0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 3, 0x020, "gpg0", 0x04, 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x040, "gpp1", 0x08, 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x060, "gpp2", 0x0c, 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 3, 0x080, "gpp3", 0x10, 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x0a0, "gpp4", 0x14, 0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0c0, "gpp5", 0x18, 0x1c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x0e0, "gpp6", 0x1c, 0x20),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x100, "gpp7", 0x20, 0x28),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x120, "gpp8", 0x24, 0x2c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x140, "gpg1", 0x28, 0x30),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x160, "gpg2", 0x2c, 0x38),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x180, "gpg3", 0x30, 0x40),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x1a0, "gpg4", 0x34, 0x48),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x1c0, "gpc0", 0x38, 0x4c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x1e0, "gpc1", 0x3c, 0x50),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x200, "gpc2", 0x40, 0x58),
 };
 
 static const struct samsung_pin_ctrl exynos7885_pin_ctrl[] __initconst = {
@@ -850,59 +850,59 @@ const struct samsung_pinctrl_of_match_data exynos7885_of_data __initconst = {
 /* pin banks of exynos850 pin-controller 0 (ALIVE) */
 static const struct samsung_pin_bank_data exynos850_pin_banks0[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x000, "gpa0", 0x00),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x020, "gpa1", 0x04),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x040, "gpa2", 0x08),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x060, "gpa3", 0x0c),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 4, 0x080, "gpa4", 0x10),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x000, "gpa0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x020, "gpa1", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x040, "gpa2", 0x08, 0x10),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x060, "gpa3", 0x0c, 0x18),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 4, 0x080, "gpa4", 0x10, 0x20),
 	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 3, 0x0a0, "gpq0"),
 };
 
 /* pin banks of exynos850 pin-controller 1 (CMGP) */
 static const struct samsung_pin_bank_data exynos850_pin_banks1[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x000, "gpm0", 0x00),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x020, "gpm1", 0x04),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x040, "gpm2", 0x08),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x060, "gpm3", 0x0c),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x080, "gpm4", 0x10),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0a0, "gpm5", 0x14),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0c0, "gpm6", 0x18),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0e0, "gpm7", 0x1c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x000, "gpm0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x020, "gpm1", 0x04, 0x04),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x040, "gpm2", 0x08, 0x08),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x060, "gpm3", 0x0c, 0x0c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x080, "gpm4", 0x10, 0x10),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0a0, "gpm5", 0x14, 0x14),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0c0, "gpm6", 0x18, 0x18),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0e0, "gpm7", 0x1c, 0x1c),
 };
 
 /* pin banks of exynos850 pin-controller 2 (AUD) */
 static const struct samsung_pin_bank_data exynos850_pin_banks2[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x000, "gpb0", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x020, "gpb1", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x000, "gpb0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x020, "gpb1", 0x04, 0x08),
 };
 
 /* pin banks of exynos850 pin-controller 3 (HSI) */
 static const struct samsung_pin_bank_data exynos850_pin_banks3[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x000, "gpf2", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x000, "gpf2", 0x00, 0x00),
 };
 
 /* pin banks of exynos850 pin-controller 4 (CORE) */
 static const struct samsung_pin_bank_data exynos850_pin_banks4[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x000, "gpf0", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpf1", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x000, "gpf0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpf1", 0x04, 0x04),
 };
 
 /* pin banks of exynos850 pin-controller 5 (PERI) */
 static const struct samsung_pin_bank_data exynos850_pin_banks5[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x000, "gpg0", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x020, "gpp0", 0x04),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x040, "gpp1", 0x08),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x060, "gpp2", 0x0c),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x080, "gpg1", 0x10),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x0a0, "gpg2", 0x14),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 1, 0x0c0, "gpg3", 0x18),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 3, 0x0e0, "gpc0", 0x1c),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x100, "gpc1", 0x20),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x000, "gpg0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x020, "gpp0", 0x04, 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x040, "gpp1", 0x08, 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x060, "gpp2", 0x0c, 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x080, "gpg1", 0x10, 0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x0a0, "gpg2", 0x14, 0x1c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 1, 0x0c0, "gpg3", 0x18, 0x24),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 3, 0x0e0, "gpc0", 0x1c, 0x28),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x100, "gpc1", 0x20, 0x2c),
 };
 
 static const struct samsung_pin_ctrl exynos850_pin_ctrl[] __initconst = {
@@ -946,11 +946,11 @@ const struct samsung_pinctrl_of_match_data exynos850_of_data __initconst = {
 /* pin banks of exynos990 pin-controller 0 (ALIVE) */
 static struct samsung_pin_bank_data exynos990_pin_banks0[] = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x000, "gpa0", 0x00),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x020, "gpa1", 0x04),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x040, "gpa2", 0x08),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x060, "gpa3", 0x0c),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x080, "gpa4", 0x10),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x000, "gpa0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x020, "gpa1", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x040, "gpa2", 0x08, 0x10),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x060, "gpa3", 0x0c, 0x18),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x080, "gpa4", 0x10, 0x20),
 	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 7, 0x0a0, "gpq0"),
 };
 
@@ -961,82 +961,82 @@ static struct samsung_pin_bank_data exynos990_pin_banks1[] = {
 	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 1, 0x020, "gpm1"),
 	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 1, 0x040, "gpm2"),
 	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 1, 0x060, "gpm3"),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x080, "gpm4", 0x00),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0a0, "gpm5", 0x04),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0c0, "gpm6", 0x08),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0e0, "gpm7", 0x0c),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x100, "gpm8", 0x10),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x120, "gpm9", 0x14),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x140, "gpm10", 0x18),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x160, "gpm11", 0x1c),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x180, "gpm12", 0x20),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x1a0, "gpm13", 0x24),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x1c0, "gpm14", 0x28),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x1e0, "gpm15", 0x2c),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x200, "gpm16", 0x30),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x220, "gpm17", 0x34),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x240, "gpm18", 0x38),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x260, "gpm19", 0x3c),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x280, "gpm20", 0x40),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x2a0, "gpm21", 0x44),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x2c0, "gpm22", 0x48),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x2e0, "gpm23", 0x4c),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x300, "gpm24", 0x50),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x320, "gpm25", 0x54),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x340, "gpm26", 0x58),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x360, "gpm27", 0x5c),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x380, "gpm28", 0x60),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x3a0, "gpm29", 0x64),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x3c0, "gpm30", 0x68),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x3e0, "gpm31", 0x6c),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x400, "gpm32", 0x70),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x420, "gpm33", 0x74),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x080, "gpm4", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0a0, "gpm5", 0x04, 0x04),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0c0, "gpm6", 0x08, 0x08),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0e0, "gpm7", 0x0c, 0x0c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x100, "gpm8", 0x10, 0x10),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x120, "gpm9", 0x14, 0x14),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x140, "gpm10", 0x18, 0x18),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x160, "gpm11", 0x1c, 0x1c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x180, "gpm12", 0x20, 0x20),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x1a0, "gpm13", 0x24, 0x24),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x1c0, "gpm14", 0x28, 0x28),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x1e0, "gpm15", 0x2c, 0x2c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x200, "gpm16", 0x30, 0x30),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x220, "gpm17", 0x34, 0x34),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x240, "gpm18", 0x38, 0x38),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x260, "gpm19", 0x3c, 0x3c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x280, "gpm20", 0x40, 0x40),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x2a0, "gpm21", 0x44, 0x44),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x2c0, "gpm22", 0x48, 0x48),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x2e0, "gpm23", 0x4c, 0x4c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x300, "gpm24", 0x50, 0x50),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x320, "gpm25", 0x54, 0x54),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x340, "gpm26", 0x58, 0x58),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x360, "gpm27", 0x5c, 0x5c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x380, "gpm28", 0x60, 0x60),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x3a0, "gpm29", 0x64, 0x64),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x3c0, "gpm30", 0x68, 0x68),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x3e0, "gpm31", 0x6c, 0x6c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x400, "gpm32", 0x70, 0x70),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x420, "gpm33", 0x74, 0x74),
 };
 
 /* pin banks of exynos990 pin-controller 2 (HSI1) */
 static struct samsung_pin_bank_data exynos990_pin_banks2[] = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x000, "gpf0", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x020, "gpf1", 0x04),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 3, 0x040, "gpf2", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x000, "gpf0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x020, "gpf1", 0x04, 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 3, 0x040, "gpf2", 0x08, 0x0c),
 };
 
 /* pin banks of exynos990 pin-controller 3 (HSI2) */
 static struct samsung_pin_bank_data exynos990_pin_banks3[] = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x000, "gpf3", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x000, "gpf3", 0x00, 0x00),
 };
 
 /* pin banks of exynos990 pin-controller 4 (PERIC0) */
 static struct samsung_pin_bank_data exynos990_pin_banks4[] = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x000, "gpp0", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpp1", 0x04),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x040, "gpp2", 0x08),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x060, "gpp3", 0x0c),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x080, "gpp4", 0x10),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x0a0, "gpg0", 0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x000, "gpp0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpp1", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x040, "gpp2", 0x08, 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x060, "gpp3", 0x0c, 0x18),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x080, "gpp4", 0x10, 0x20),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x0a0, "gpg0", 0x14, 0x28),
 };
 
 /* pin banks of exynos990 pin-controller 5 (PERIC1) */
 static struct samsung_pin_bank_data exynos990_pin_banks5[] = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x000, "gpp5", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpp6", 0x04),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x040, "gpp7", 0x08),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x060, "gpp8", 0x0c),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x080, "gpp9", 0x10),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x0a0, "gpc0", 0x14),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0c0, "gpg1", 0x18),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x0e0, "gpb0", 0x1c),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x100, "gpb1", 0x20),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x120, "gpb2", 0x24),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x000, "gpp5", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpp6", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x040, "gpp7", 0x08, 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x060, "gpp8", 0x0c, 0x18),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x080, "gpp9", 0x10, 0x20),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x0a0, "gpc0", 0x14, 0x28),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0c0, "gpg1", 0x18, 0x30),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x0e0, "gpb0", 0x1c, 0x34),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x100, "gpb1", 0x20, 0x3c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x120, "gpb2", 0x24, 0x44),
 };
 
 /* pin banks of exynos990 pin-controller 6 (VTS) */
 static struct samsung_pin_bank_data exynos990_pin_banks6[] = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x000, "gpv0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x000, "gpv0", 0x00, 0x00),
 };
 
 static const struct samsung_pin_ctrl exynos990_pin_ctrl[] __initconst = {
@@ -1085,87 +1085,87 @@ const struct samsung_pinctrl_of_match_data exynos990_of_data __initconst = {
 /* pin banks of exynos9810 pin-controller 0 (ALIVE) */
 static const struct samsung_pin_bank_data exynos9810_pin_banks0[] __initconst = {
 	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 6, 0x000, "etc1"),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x020, "gpa0", 0x00),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x040, "gpa1", 0x04),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x060, "gpa2", 0x08),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x080, "gpa3", 0x0c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x020, "gpa0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x040, "gpa1", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x060, "gpa2", 0x08, 0x10),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x080, "gpa3", 0x0c, 0x18),
 	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 6, 0x0a0, "gpq0"),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x0c0, "gpa4", 0x10),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x0C0, "gpa4", 0x10, 0x20),
 };
 
 /* pin banks of exynos9810 pin-controller 1 (AUD) */
 static const struct samsung_pin_bank_data exynos9810_pin_banks1[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x000, "gpb0", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpb1", 0x04),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x040, "gpb2", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x000, "gpb0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpb1", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x040, "gpb2", 0x08, 0x10),
 };
 
 /* pin banks of exynos9810 pin-controller 2 (CHUB) */
 static const struct samsung_pin_bank_data exynos9810_pin_banks2[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x000, "gph0", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x020, "gph1", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x000, "gph0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x020, "gph1", 0x04, 0x08),
 };
 
 /* pin banks of exynos9810 pin-controller 3 (CMGP) */
 static const struct samsung_pin_bank_data exynos9810_pin_banks3[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x000, "gpm0", 0x00),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x020, "gpm1", 0x04),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x040, "gpm2", 0x08),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x060, "gpm3", 0x0c),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x080, "gpm4", 0x10),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0a0, "gpm5", 0x14),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0c0, "gpm6", 0x18),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0e0, "gpm7", 0x1c),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x100, "gpm10", 0x20),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x120, "gpm11", 0x24),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x140, "gpm12", 0x28),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x160, "gpm13", 0x2c),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x180, "gpm14", 0x30),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x1a0, "gpm15", 0x34),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x1c0, "gpm16", 0x38),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x1e0, "gpm17", 0x3c),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x200, "gpm40", 0x40),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x220, "gpm41", 0x44),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x240, "gpm42", 0x48),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x260, "gpm43", 0x4c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x000, "gpm0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x020, "gpm1", 0x04, 0x04),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x040, "gpm2", 0x08, 0x08),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x060, "gpm3", 0x0c, 0x0c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x080, "gpm4", 0x10, 0x10),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0a0, "gpm5", 0x14, 0x14),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0c0, "gpm6", 0x18, 0x18),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x0e0, "gpm7", 0x1c, 0x1c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x100, "gpm10", 0x20, 0x20),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x120, "gpm11", 0x24, 0x24),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x140, "gpm12", 0x28, 0x28),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x160, "gpm13", 0x2c, 0x2c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x180, "gpm14", 0x30, 0x30),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x1a0, "gpm15", 0x34, 0x34),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x1c0, "gpm16", 0x38, 0x38),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x1e0, "gpm17", 0x3c, 0x3c),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x200, "gpm40", 0x40, 0x40),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x220, "gpm41", 0x44, 0x44),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x240, "gpm42", 0x48, 0x48),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 1, 0x260, "gpm43", 0x4c, 0x4c),
 };
 
 /* pin banks of exynos9810 pin-controller 4 (FSYS0) */
 static const struct samsung_pin_bank_data exynos9810_pin_banks4[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x000, "gpf0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x000, "gpf0", 0x00, 0x00),
 };
 
 /* pin banks of exynos9810 pin-controller 5 (FSYS1) */
 static const struct samsung_pin_bank_data exynos9810_pin_banks5[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x000, "gpf1", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x020, "gpf2", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x000, "gpf1", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x020, "gpf2", 0x04, 0x08),
 };
 
 /* pin banks of exynos9810 pin-controller 6 (PERIC0) */
 static const struct samsung_pin_bank_data exynos9810_pin_banks6[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x000, "gpp0", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpp1", 0x04),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x040, "gpp2", 0x08),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x060, "gpp3", 0x0c),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x080, "gpg0", 0x10),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x0a0, "gpg1", 0x14),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x0c0, "gpg2", 0x18),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x000, "gpp0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpp1", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x040, "gpp2", 0x08, 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x060, "gpp3", 0x0c, 0x18),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x080, "gpg0", 0x10, 0x1c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x0a0, "gpg1", 0x14, 0x24),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x0c0, "gpg2", 0x18, 0x2c),
 };
 
 /* pin banks of exynos9810 pin-controller 7 (PERIC1) */
 static const struct samsung_pin_bank_data exynos9810_pin_banks7[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x000, "gpp4", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpp5", 0x04),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x040, "gpp6", 0x08),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x060, "gpc0", 0x0c),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x080, "gpc1", 0x10),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0a0, "gpd0", 0x14),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x0c0, "gpg3", 0x18),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x000, "gpp4", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpp5", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x040, "gpp6", 0x08, 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x060, "gpc0", 0x0c, 0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x080, "gpc1", 0x10, 0x1c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0a0, "gpd0", 0x14, 0x24),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x0c0, "gpg3", 0x18, 0x28),
 };
 
 /* pin banks of exynos9810 pin-controller 8 (VTS) */
 static const struct samsung_pin_bank_data exynos9810_pin_banks8[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 3, 0x000, "gpt0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 3, 0x000, "gpt0", 0x00, 0x00),
 };
 
 static const struct samsung_pin_ctrl exynos9810_pin_ctrl[] __initconst = {
@@ -1238,55 +1238,55 @@ const struct samsung_pinctrl_of_match_data exynos9810_of_data __initconst = {
 
 /* pin banks of exynosautov9 pin-controller 0 (ALIVE) */
 static const struct samsung_pin_bank_data exynosautov9_pin_banks0[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x000, "gpa0", 0x00),
-	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x020, "gpa1", 0x04),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x000, "gpa0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 2, 0x020, "gpa1", 0x04, 0x08),
 	EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, 2, 0x040, "gpq0"),
 };
 
 /* pin banks of exynosautov9 pin-controller 1 (AUD) */
 static const struct samsung_pin_bank_data exynosautov9_pin_banks1[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x000, "gpb0", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpb1", 0x04),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x040, "gpb2", 0x08),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x060, "gpb3", 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x000, "gpb0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpb1", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x040, "gpb2", 0x08, 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x060, "gpb3", 0x0c, 0x18),
 };
 
 /* pin banks of exynosautov9 pin-controller 2 (FSYS0) */
 static const struct samsung_pin_bank_data exynosautov9_pin_banks2[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x000, "gpf0", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x020, "gpf1", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x000, "gpf0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x020, "gpf1", 0x04, 0x08),
 };
 
 /* pin banks of exynosautov9 pin-controller 3 (FSYS1) */
 static const struct samsung_pin_bank_data exynosautov9_pin_banks3[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x000, "gpf8", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x000, "gpf8", 0x00, 0x00),
 };
 
 /* pin banks of exynosautov9 pin-controller 4 (FSYS2) */
 static const struct samsung_pin_bank_data exynosautov9_pin_banks4[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x000, "gpf2", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpf3", 0x04),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x040, "gpf4", 0x08),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x060, "gpf5", 0x0c),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x080, "gpf6", 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x000, "gpf2", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpf3", 0x04, 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x040, "gpf4", 0x08, 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x060, "gpf5", 0x0c, 0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x080, "gpf6", 0x10, 0x1c),
 };
 
 /* pin banks of exynosautov9 pin-controller 5 (PERIC0) */
 static const struct samsung_pin_bank_data exynosautov9_pin_banks5[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x000, "gpp0", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpp1", 0x04),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x040, "gpp2", 0x08),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x060, "gpg0", 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x000, "gpp0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpp1", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x040, "gpp2", 0x08, 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x060, "gpg0", 0x0c, 0x18),
 };
 
 /* pin banks of exynosautov9 pin-controller 6 (PERIC1) */
 static const struct samsung_pin_bank_data exynosautov9_pin_banks6[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x000, "gpp3", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpp4", 0x04),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x040, "gpp5", 0x08),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x060, "gpg1", 0x0c),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x080, "gpg2", 0x10),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0a0, "gpg3", 0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x000, "gpp3", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x020, "gpp4", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x040, "gpp5", 0x08, 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x060, "gpg1", 0x0c, 0x18),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x080, "gpg2", 0x10, 0x20),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0a0, "gpg3", 0x14, 0x28),
 };
 
 static const struct samsung_pin_ctrl exynosautov9_pin_ctrl[] __initconst = {
@@ -1487,16 +1487,16 @@ const struct samsung_pinctrl_of_match_data exynosautov920_of_data __initconst =
 /* pin banks of exynos8890 pin-controller 0 (ALIVE) */
 static const struct samsung_pin_bank_data exynos8890_pin_banks0[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS9_PIN_BANK_EINTW(exynos7870_bank_type_alive, 8, 0x000, "gpa0", 0x00),
-	EXYNOS9_PIN_BANK_EINTW(exynos7870_bank_type_alive, 8, 0x020, "gpa1", 0x04),
-	EXYNOS9_PIN_BANK_EINTW(exynos7870_bank_type_alive, 8, 0x040, "gpa2", 0x08),
-	EXYNOS9_PIN_BANK_EINTW(exynos7870_bank_type_alive, 8, 0x060, "gpa3", 0x0c),
+	EXYNOS9_PIN_BANK_EINTW(exynos7870_bank_type_alive, 8, 0x000, "gpa0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTW(exynos7870_bank_type_alive, 8, 0x020, "gpa1", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTW(exynos7870_bank_type_alive, 8, 0x040, "gpa2", 0x08, 0x10),
+	EXYNOS9_PIN_BANK_EINTW(exynos7870_bank_type_alive, 8, 0x060, "gpa3", 0x0c, 0x18),
 };
 
 /* pin banks of exynos8890 pin-controller 1 (AUD) */
 static const struct samsung_pin_bank_data exynos8890_pin_banks1[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 7, 0x000, "gph0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 7, 0x000, "gph0", 0x00, 0x00),
 };
 
 /* pin banks of exynos8890 pin-controller 2 (CCORE) */
@@ -1508,73 +1508,73 @@ static const struct samsung_pin_bank_data exynos8890_pin_banks2[] __initconst =
 /* pin banks of exynos8890 pin-controller 3 (ESE) */
 static const struct samsung_pin_bank_data exynos8890_pin_banks3[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 5, 0x000, "gpf3", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 5, 0x000, "gpf3", 0x00, 0x00),
 };
 
 /* pin banks of exynos8890 pin-controller 4 (FP) */
 static const struct samsung_pin_bank_data exynos8890_pin_banks4[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x000, "gpf2", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x000, "gpf2", 0x00, 0x00),
 };
 
 /* pin banks of exynos8890 pin-controller 5 (FSYS0) */
 static const struct samsung_pin_bank_data exynos8890_pin_banks5[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS9_PIN_BANK_EINTG(exynos5433_bank_type_off, 4, 0x000, "gpi1", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos5433_bank_type_off, 8, 0x020, "gpi2", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos5433_bank_type_off, 4, 0x000, "gpi1", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos5433_bank_type_off, 8, 0x020, "gpi2", 0x04, 0x04),
 };
 
 /* pin banks of exynos8890 pin-controller 6 (FSYS1) */
 static const struct samsung_pin_bank_data exynos8890_pin_banks6[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 7, 0x000, "gpj0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 7, 0x000, "gpj0", 0x00, 0x00),
 };
 
 /* pin banks of exynos8890 pin-controller 7 (NFC) */
 static const struct samsung_pin_bank_data exynos8890_pin_banks7[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x000, "gpf0", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x000, "gpf0", 0x00, 0x00),
 };
 
 /* pin banks of exynos8890 pin-controller 8 (PERIC0) */
 static const struct samsung_pin_bank_data exynos8890_pin_banks8[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 6, 0x000, "gpi0", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x020, "gpd0", 0x04),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 6, 0x040, "gpd1", 0x08),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x060, "gpd2", 0x0c),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x080, "gpd3", 0x10),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x0a0, "gpb1", 0x14),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x0c0, "gpb2", 0x18),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x0e0, "gpb0", 0x1c),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 5, 0x100, "gpc0", 0x20),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 5, 0x120, "gpc1", 0x24),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 6, 0x140, "gpc2", 0x28),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x160, "gpc3", 0x2c),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x180, "gpk0", 0x30),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 6, 0x000, "gpi0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x020, "gpd0", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 6, 0x040, "gpd1", 0x08, 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x060, "gpd2", 0x0c, 0x18),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x080, "gpd3", 0x10, 0x1c),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x0a0, "gpb1", 0x14, 0x20),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x0c0, "gpb2", 0x18, 0x24),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x0e0, "gpb0", 0x1c, 0x28),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 5, 0x100, "gpc0", 0x20, 0x2c),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 5, 0x120, "gpc1", 0x24, 0x34),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 6, 0x140, "gpc2", 0x28, 0x3c),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x160, "gpc3", 0x2c, 0x44),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x180, "gpk0", 0x30, 0x4c),
 	EXYNOS9_PIN_BANK_EINTN(exynos8895_bank_type_off, 7, 0x1a0, "etc1"),
 };
 
 /* pin banks of exynos8890 pin-controller 9 (PERIC1) */
 static const struct samsung_pin_bank_data exynos8890_pin_banks9[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x000, "gpe0", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x020, "gpe5", 0x04),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x040, "gpe6", 0x08),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x060, "gpj1", 0x0c),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x080, "gpj2", 0x10),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x0a0, "gpe2", 0x14),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x0c0, "gpe3", 0x18),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x0e0, "gpe4", 0x1c),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x100, "gpe1", 0x20),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x120, "gpe7", 0x24),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x140, "gpg0", 0x28),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x000, "gpe0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x020, "gpe5", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x040, "gpe6", 0x08, 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x060, "gpj1", 0x0c, 0x18),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 2, 0x080, "gpj2", 0x10, 0x20),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x0a0, "gpe2", 0x14, 0x24),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x0c0, "gpe3", 0x18, 0x2c),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x0e0, "gpe4", 0x1c, 0x34),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x100, "gpe1", 0x20, 0x3c),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 4, 0x120, "gpe7", 0x24, 0x44),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x140, "gpg0", 0x28, 0x48),
 };
 
 /* pin banks of exynos8890 pin-controller 10 (TOUCH) */
 static const struct samsung_pin_bank_data exynos8890_pin_banks10[] __initconst = {
 	/* Must start with EINTG banks, ordered by EINT group number. */
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x000, "gpf1", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x000, "gpf1", 0x00, 0x00),
 };
 
 static const struct samsung_pin_ctrl exynos8890_pin_ctrl[] __initconst = {
@@ -1643,69 +1643,69 @@ const struct samsung_pinctrl_of_match_data exynos8890_of_data __initconst = {
 
 /* pin banks of exynos8895 pin-controller 0 (ALIVE) */
 static const struct samsung_pin_bank_data exynos8895_pin_banks0[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTW(bank_type_alive, 8, 0x020, "gpa0", 0x00),
-	EXYNOS9_PIN_BANK_EINTW(bank_type_alive, 8, 0x040, "gpa1", 0x04),
-	EXYNOS9_PIN_BANK_EINTW(bank_type_alive, 8, 0x060, "gpa2", 0x08),
-	EXYNOS9_PIN_BANK_EINTW(bank_type_alive, 8, 0x080, "gpa3", 0x0c),
+	EXYNOS9_PIN_BANK_EINTW(bank_type_alive, 8, 0x020, "gpa0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTW(bank_type_alive, 8, 0x040, "gpa1", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTW(bank_type_alive, 8, 0x060, "gpa2", 0x08, 0x10),
+	EXYNOS9_PIN_BANK_EINTW(bank_type_alive, 8, 0x080, "gpa3", 0x0c, 0x18),
 	EXYNOS9_PIN_BANK_EINTN(bank_type_alive, 7, 0x0a0, "gpa4"),
 };
 
 /* pin banks of exynos8895 pin-controller 1 (ABOX) */
 static const struct samsung_pin_bank_data exynos8895_pin_banks1[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x000, "gph0", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 7, 0x020, "gph1", 0x04),
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 4, 0x040, "gph3", 0x08),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x000, "gph0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 7, 0x020, "gph1", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 4, 0x040, "gph3", 0x08, 0x10),
 };
 
 /* pin banks of exynos8895 pin-controller 2 (VTS) */
 static const struct samsung_pin_bank_data exynos8895_pin_banks2[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 3, 0x000, "gph2", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 3, 0x000, "gph2", 0x00, 0x00),
 };
 
 /* pin banks of exynos8895 pin-controller 3 (FSYS0) */
 static const struct samsung_pin_bank_data exynos8895_pin_banks3[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x000, "gpi0", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x020, "gpi1", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 3, 0x000, "gpi0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos8895_bank_type_off, 8, 0x020, "gpi1", 0x04, 0x04),
 };
 
 /* pin banks of exynos8895 pin-controller 4 (FSYS1) */
 static const struct samsung_pin_bank_data exynos8895_pin_banks4[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x000, "gpj1", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 7, 0x020, "gpj0", 0x04),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x000, "gpj1", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 7, 0x020, "gpj0", 0x04, 0x08),
 };
 
 /* pin banks of exynos8895 pin-controller 5 (BUSC) */
 static const struct samsung_pin_bank_data exynos8895_pin_banks5[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 2, 0x000, "gpb2", 0x00),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 2, 0x000, "gpb2", 0x00, 0x00),
 };
 
 /* pin banks of exynos8895 pin-controller 6 (PERIC0) */
 static const struct samsung_pin_bank_data exynos8895_pin_banks6[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x000, "gpd0", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x020, "gpd1", 0x04),
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 4, 0x040, "gpd2", 0x08),
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 5, 0x060, "gpd3", 0x0C),
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 4, 0x080, "gpb1", 0x10),
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x0a0, "gpe7", 0x14),
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x0c0, "gpf1", 0x18),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x000, "gpd0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x020, "gpd1", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 4, 0x040, "gpd2", 0x08, 0x10),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 5, 0x060, "gpd3", 0x0C, 0x14),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 4, 0x080, "gpb1", 0x10, 0x1c),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x0a0, "gpe7", 0x14, 0x20),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x0c0, "gpf1", 0x18, 0x28),
 };
 
 /* pin banks of exynos8895 pin-controller 7 (PERIC1) */
 static const struct samsung_pin_bank_data exynos8895_pin_banks7[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 3, 0x000, "gpb0", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 5, 0x020, "gpc0", 0x04),
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 5, 0x040, "gpc1", 0x08),
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x060, "gpc2", 0x0c),
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x080, "gpc3", 0x10),
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 4, 0x0a0, "gpk0", 0x14),
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x0c0, "gpe5", 0x18),
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x0e0, "gpe6", 0x1c),
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x100, "gpe2", 0x20),
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x120, "gpe3", 0x24),
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x140, "gpe4", 0x28),
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 4, 0x160, "gpf0", 0x2c),
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x180, "gpe1", 0x30),
-	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 2, 0x1a0, "gpg0", 0x34),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 3, 0x000, "gpb0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 5, 0x020, "gpc0", 0x04, 0x04),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 5, 0x040, "gpc1", 0x08, 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x060, "gpc2", 0x0c, 0x14),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x080, "gpc3", 0x10, 0x1c),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 4, 0x0a0, "gpk0", 0x14, 0x24),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x0c0, "gpe5", 0x18, 0x28),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x0e0, "gpe6", 0x1c, 0x30),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x100, "gpe2", 0x20, 0x38),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x120, "gpe3", 0x24, 0x40),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x140, "gpe4", 0x28, 0x48),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 4, 0x160, "gpf0", 0x2c, 0x50),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 8, 0x180, "gpe1", 0x30, 0x54),
+	EXYNOS9_PIN_BANK_EINTG(bank_type_off, 2, 0x1a0, "gpg0", 0x34, 0x5c),
 };
 
 static const struct samsung_pin_ctrl exynos8895_pin_ctrl[] __initconst = {
@@ -1776,36 +1776,36 @@ const struct samsung_pinctrl_of_match_data exynos8895_of_data __initconst = {
 
 /* pin banks of FSD pin-controller 0 (FSYS) */
 static const struct samsung_pin_bank_data fsd_pin_banks0[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x00, "gpf0", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x20, "gpf1", 0x04),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 3, 0x40, "gpf6", 0x08),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x60, "gpf4", 0x0c),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x80, "gpf5", 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x00, "gpf0", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x20, "gpf1", 0x04, 0x08),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 3, 0x40, "gpf6", 0x08, 0x10),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 2, 0x60, "gpf4", 0x0c, 0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 6, 0x80, "gpf5", 0x10, 0x18),
 };
 
 /* pin banks of FSD pin-controller 1 (PERIC) */
 static const struct samsung_pin_bank_data fsd_pin_banks1[] __initconst = {
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x000, "gpc8", 0x00),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x020, "gpf2", 0x04),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x040, "gpf3", 0x08),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x060, "gpd0", 0x0c),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x080, "gpb0", 0x10),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x0a0, "gpb1", 0x14),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x0c0, "gpb4", 0x18),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0e0, "gpb5", 0x1c),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x100, "gpb6", 0x20),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x120, "gpb7", 0x24),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x140, "gpd1", 0x28),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x160, "gpd2", 0x2c),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x180, "gpd3", 0x30),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x1a0, "gpg0", 0x34),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x1c0, "gpg1", 0x38),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x1e0, "gpg2", 0x3c),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x200, "gpg3", 0x40),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x220, "gpg4", 0x44),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x240, "gpg5", 0x48),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x260, "gpg6", 0x4c),
-	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x280, "gpg7", 0x50),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x000, "gpc8", 0x00, 0x00),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x020, "gpf2", 0x04, 0x04),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x040, "gpf3", 0x08, 0x0c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x060, "gpd0", 0x0c, 0x14),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x080, "gpb0", 0x10, 0x1c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x0a0, "gpb1", 0x14, 0x24),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x0c0, "gpb4", 0x18, 0x2c),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 4, 0x0e0, "gpb5", 0x1c, 0x34),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x100, "gpb6", 0x20, 0x38),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x120, "gpb7", 0x24, 0x40),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x140, "gpd1", 0x28, 0x48),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 5, 0x160, "gpd2", 0x2c, 0x50),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 7, 0x180, "gpd3", 0x30, 0x58),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x1a0, "gpg0", 0x34, 0x60),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x1c0, "gpg1", 0x38, 0x68),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x1e0, "gpg2", 0x3c, 0x70),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x200, "gpg3", 0x40, 0x78),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x220, "gpg4", 0x44, 0x80),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x240, "gpg5", 0x48, 0x88),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x260, "gpg6", 0x4c, 0x90),
+	EXYNOS9_PIN_BANK_EINTG(exynos9_bank_type_off, 8, 0x280, "gpg7", 0x50, 0x98),
 };
 
 /* pin banks of FSD pin-controller 2 (PMU) */
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.h b/drivers/pinctrl/samsung/pinctrl-exynos.h
index 41cec8408d0d..7ebfdcaf2781 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos.h
+++ b/drivers/pinctrl/samsung/pinctrl-exynos.h
@@ -141,24 +141,26 @@
 		.name		= id				\
 	}
 
-#define EXYNOS9_PIN_BANK_EINTG(bank_type, pins, reg, id, offs)	\
-	{							\
-		.type		= &bank_type,			\
-		.pctl_offset	= reg,				\
-		.nr_pins	= pins,				\
-		.eint_type	= EINT_TYPE_GPIO,		\
-		.eint_offset	= offs,				\
-		.name		= id				\
+#define EXYNOS9_PIN_BANK_EINTG(bank_type, pins, reg, id, offs, fltcon_offs)	\
+	{									\
+		.type			= &bank_type,				\
+		.pctl_offset		= reg,					\
+		.nr_pins		= pins,					\
+		.eint_type		= EINT_TYPE_GPIO,			\
+		.eint_offset		= offs,					\
+		.eint_fltcon_offset	= fltcon_offs,				\
+		.name			= id					\
 	}
 
-#define EXYNOS9_PIN_BANK_EINTW(bank_type, pins, reg, id, offs)	\
-	{							\
-		.type		= &bank_type,			\
-		.pctl_offset	= reg,				\
-		.nr_pins	= pins,				\
-		.eint_type	= EINT_TYPE_WKUP,		\
-		.eint_offset	= offs,				\
-		.name		= id				\
+#define EXYNOS9_PIN_BANK_EINTW(bank_type, pins, reg, id, offs, fltcon_offs)	\
+	{									\
+		.type			= &bank_type,				\
+		.pctl_offset		= reg,					\
+		.nr_pins		= pins,					\
+		.eint_type		= EINT_TYPE_WKUP,			\
+		.eint_offset		= offs,					\
+		.eint_fltcon_offset	= fltcon_offs,				\
+		.name			= id					\
 	}
 
 #define EXYNOSV920_PIN_BANK_EINTG(pins, reg, id, con_offs, mask_offs, pend_offs)	\
-- 
2.52.0



From krzk at kernel.org  Tue Dec  2 01:33:14 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 2 Dec 2025 10:33:14 +0100
Subject: [PATCH v8 2/2] usb: dwc3: Add Google Tensor SoC DWC3 glue driver
In-Reply-To: <CA+zupgwzQ5r=-_L79D74=9VRqRO94N0yTApHChM+Nu0cn1ss3w@mail.gmail.com>
References: <20251122-controller-v8-0-e7562e0df658@google.com>
 <20251122-controller-v8-2-e7562e0df658@google.com>
 <2025112226-heave-refrain-53e6@gregkh>
 <CA+zupgwzQ5r=-_L79D74=9VRqRO94N0yTApHChM+Nu0cn1ss3w@mail.gmail.com>
Message-ID: <0039d36f-dfca-44e7-9898-11f9e3eb9b9d@kernel.org>

On 02/12/2025 10:01, Roy Luo wrote:
> On Sat, Nov 22, 2025 at 8:59?PM Greg Kroah-Hartman
> <gregkh at linuxfoundation.org> wrote:
>>
>> On Sat, Nov 22, 2025 at 09:32:06AM +0000, Roy Luo wrote:
>>> Add support for the DWC3 USB controller found on Google Tensor G5
>>> (codename: laguna). The controller features dual-role functionality
>>> and hibernation.
>>>
>>> The primary focus is implementing hibernation support in host mode,
>>> enabling the controller to enter a low-power state (D3). This is
>>> particularly relevant during system power state transition and
>>> runtime power management for power efficiency.
>>> Highlights:
>>> - Align suspend callback with dwc3_suspend_common() for deciding
>>>   between a full teardown and hibernation in host mode.
>>> - Integration with `psw` (power switchable) and `top` power domains,
>>>   managing their states and device links to support hibernation.
>>> - A notifier callback dwc3_google_usb_psw_pd_notifier() for
>>>   `psw` power domain events to manage controller state
>>>   transitions to/from D3.
>>> - Coordination of the `non_sticky` reset during power state
>>>   transitions, asserting it on D3 entry and deasserting on D0 entry
>>>   in hibernation scenario.
>>> - Handling of high-speed and super-speed PME interrupts
>>>   that are generated by remote wakeup during hibernation.
>>>
>>> Co-developed-by: Joy Chakraborty <joychakr at google.com>
>>> Signed-off-by: Joy Chakraborty <joychakr at google.com>
>>> Co-developed-by: Naveen Kumar <mnkumar at google.com>
>>> Signed-off-by: Naveen Kumar <mnkumar at google.com>
>>> Signed-off-by: Roy Luo <royluo at google.com>
>>> ---
>>>  drivers/usb/dwc3/Kconfig       |  13 +
>>>  drivers/usb/dwc3/Makefile      |   1 +
>>>  drivers/usb/dwc3/dwc3-google.c | 628 +++++++++++++++++++++++++++++++++++++++++
>>>  3 files changed, 642 insertions(+)
>>>
>>> diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
>>> index 4925d15084f816d3ff92059b476ebcc799b56b51..f58c70dabf108878cbefe0abea88572d9ae81e26 100644
>>> --- a/drivers/usb/dwc3/Kconfig
>>> +++ b/drivers/usb/dwc3/Kconfig
>>> @@ -200,4 +200,17 @@ config USB_DWC3_GENERIC_PLAT
>>>         the dwc3 child node in the device tree.
>>>         Say 'Y' or 'M' here if your platform integrates DWC3 in a similar way.
>>>
>>> +config USB_DWC3_GOOGLE
>>> +     tristate "Google Platform"
>>> +     depends on COMPILE_TEST
>>> +     depends on OF && COMMON_CLK && RESET_CONTROLLER
>>
>> Shouldn't this be:
>>         depends on (OF && COMMON_CLK && RESET_CONTROLLER) || COMPILE_TEST
>>
>> I shouldn't have to enable those options to just get a build test here,
>> the apis should be properly stubbed out if those options are not
>> enabled, right?
>>
>> thanks,
>>
>> greg k-h
> 
> Hi Greg,
> 
> I agree with your interpretation of COMPILE_TEST but it doesn't
> seem to align with upstream convention. I found the following pattern

The problem is not in Greg's solution but your code:
	depends on COMPILE_TEST

which makes absolutely no sense because it means this cannot be used
anywhere (in reasonable terms).


> in several device driver Kconfig files (including but not limited to usb,
> pinctrl and phy).
> 
>     depends on COMPILE_TEST || ARCH_XXX
>     depends on CONFIG_A && CONFIG_B...
> 
> For this patch, the APIs exposed by OF, COMMON_CLK
> and RESET_CONTROLLER are properly stubbed out so
> I'm all good to go with your suggestion, but I'd like to make
> sure this approach is conventional.
> 
> I plan to add ARCH_GOOGLE as a dependency in the next
> version per [1], so the "depends on" would probably look like
> the following per your suggestion:
> 
>     depends on (OF && COMMON_CLK && RESET_CONTROLLER && ARCH_GOOGLE)
> || COMPILE_TEST
> 


No, instead depends ARCH_foo || COMPILE_TEST

and drop all other dependencies. You don't need them.


Best regards,
Krzysztof


From ryan.roberts at arm.com  Tue Dec  2 01:34:51 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Tue, 2 Dec 2025 09:34:51 +0000
Subject: [RFC PATCH v1 2/2] randomize_kstack: Unify random source across
 arches
In-Reply-To: <CAMj1kXHX1W2Kz5NJehtzDhOCKWEd6y1sp8+ViOMHGsq9e8=7Pw@mail.gmail.com>
References: <20251127105958.2427758-1-ryan.roberts@arm.com>
 <20251127105958.2427758-3-ryan.roberts@arm.com>
 <CAMj1kXFY1RXk8T4f46bkm_sr0nJfBoO+ii68JK4+CsRiDwKdCg@mail.gmail.com>
 <9097505d-b18b-4f85-a02c-7f2865ad8bca@arm.com>
 <CAMj1kXHX1W2Kz5NJehtzDhOCKWEd6y1sp8+ViOMHGsq9e8=7Pw@mail.gmail.com>
Message-ID: <340b05dd-d3d3-48bc-8201-7e4de0c02516@arm.com>

On 02/12/2025 09:15, Ard Biesheuvel wrote:
> On Mon, 1 Dec 2025 at 19:20, Ryan Roberts <ryan.roberts at arm.com> wrote:
>>
>> On 28/11/2025 11:01, Ard Biesheuvel wrote:
>>> On Thu, 27 Nov 2025 at 12:00, Ryan Roberts <ryan.roberts at arm.com> wrote:
>>>>

[...]

>>>>  static inline void random_kstack_task_init(struct task_struct *tsk)
>>>>  {
>>>> -       current->kstack_offset = 0;
>>>> +       if (static_branch_maybe(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
>>>> +                               &randomize_kstack_offset)) {
>>>> +               prandom_seed_state(&tsk->kstack_rnd_state, get_random_u64());
>>>
>>> We should either fix prandom_seed_state() not to truncate the u64 to
>>> u32, or even better, refactor prandom_seed_full_state() so we can
>>> reuse it here, and use a 128-bit seed directly.
>>
>> How about something like this:
>>
> 
> Looks good to me, but it does make we wonder why a full prandom state
> (i.e., one per cpu) isn't sufficient here, and why we are putting one
> in every task. Is it just to avoid the overhead of dis/enabling
> preemption on every syscall entry?

Good point, I'm not sure there is a good reason. It's just the shape I ended up
with after the first patch that fixes the bugs. But given we are removing the
second API call in this patch, the migraiton bug goes away. As you say, we could
disable preemption around the prandom_seed_state() call and it should all be
safe. I'll benchmark it.

> 
> 
> 
> 
> 
>>
>> ---8<---
>> diff --git a/include/linux/prandom.h b/include/linux/prandom.h
>> index f2ed5b72b3d6..9b651c9b3448 100644
>> --- a/include/linux/prandom.h
>> +++ b/include/linux/prandom.h
>> @@ -19,10 +19,11 @@ struct rnd_state {
>>
>>  u32 prandom_u32_state(struct rnd_state *state);
>>  void prandom_bytes_state(struct rnd_state *state, void *buf, size_t nbytes);
>> -void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state);
>> +void prandom_seed_full_state_one(struct rnd_state *state);
>> +void prandom_seed_full_state_all(struct rnd_state __percpu *pcpu_state);
>>
>>  #define prandom_init_once(pcpu_state)                  \
>> -       DO_ONCE(prandom_seed_full_state, (pcpu_state))
>> +       DO_ONCE(prandom_seed_full_state_all, (pcpu_state))
>>
>>  /*
>>   * Handle minimum values for seeds
>> diff --git a/lib/random32.c b/lib/random32.c
>> index 24e7acd9343f..50d8f5f9fca7 100644
>> --- a/lib/random32.c
>> +++ b/lib/random32.c
>> @@ -107,24 +107,28 @@ static void prandom_warmup(struct rnd_state *state)
>>         prandom_u32_state(state);
>>  }
>>
>> -void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state)
>> +void prandom_seed_full_state_one(struct rnd_state *state)
>>  {
>> -       int i;
>> +       u32 seeds[4];
>>
>> -       for_each_possible_cpu(i) {
>> -               struct rnd_state *state = per_cpu_ptr(pcpu_state, i);
>> -               u32 seeds[4];
>> +       get_random_bytes(&seeds, sizeof(seeds));
>> +       state->s1 = __seed(seeds[0],   2U);
>> +       state->s2 = __seed(seeds[1],   8U);
>> +       state->s3 = __seed(seeds[2],  16U);
>> +       state->s4 = __seed(seeds[3], 128U);
>>
>> -               get_random_bytes(&seeds, sizeof(seeds));
>> -               state->s1 = __seed(seeds[0],   2U);
>> -               state->s2 = __seed(seeds[1],   8U);
>> -               state->s3 = __seed(seeds[2],  16U);
>> -               state->s4 = __seed(seeds[3], 128U);
>> +       prandom_warmup(state);
>> +}
>> +EXPORT_SYMBOL(prandom_seed_full_state_one);
>>
>> -               prandom_warmup(state);
>> -       }
>> +void prandom_seed_full_state_all(struct rnd_state __percpu *pcpu_state)
>> +{
>> +       int i;
>> +
>> +       for_each_possible_cpu(i)
>> +               prandom_seed_full_state_one(per_cpu_ptr(pcpu_state, i));
>>  }
>> -EXPORT_SYMBOL(prandom_seed_full_state);
>> +EXPORT_SYMBOL(prandom_seed_full_state_all);
>>
>>  #ifdef CONFIG_RANDOM32_SELFTEST
>>  static struct prandom_test1 {
>> ---8<---
>>



From mark.rutland at arm.com  Tue Dec  2 01:35:40 2025
From: mark.rutland at arm.com (Mark Rutland)
Date: Tue, 2 Dec 2025 09:35:40 +0000
Subject: [RFC PATCH v1 2/2] randomize_kstack: Unify random source across
 arches
In-Reply-To: <CAMj1kXHX1W2Kz5NJehtzDhOCKWEd6y1sp8+ViOMHGsq9e8=7Pw@mail.gmail.com>
References: <20251127105958.2427758-1-ryan.roberts@arm.com>
 <20251127105958.2427758-3-ryan.roberts@arm.com>
 <CAMj1kXFY1RXk8T4f46bkm_sr0nJfBoO+ii68JK4+CsRiDwKdCg@mail.gmail.com>
 <9097505d-b18b-4f85-a02c-7f2865ad8bca@arm.com>
 <CAMj1kXHX1W2Kz5NJehtzDhOCKWEd6y1sp8+ViOMHGsq9e8=7Pw@mail.gmail.com>
Message-ID: <aS6ylpLIyDZOvBDB@J2N7QTR9R3>

On Tue, Dec 02, 2025 at 10:15:22AM +0100, Ard Biesheuvel wrote:
> On Mon, 1 Dec 2025 at 19:20, Ryan Roberts <ryan.roberts at arm.com> wrote:
> > On 28/11/2025 11:01, Ard Biesheuvel wrote:
> > > On Thu, 27 Nov 2025 at 12:00, Ryan Roberts <ryan.roberts at arm.com> wrote:
> > >> diff --git a/include/linux/randomize_kstack.h b/include/linux/randomize_kstack.h
> > >> index 089b1432f7e6..83c7e6710f6d 100644
> > >> --- a/include/linux/randomize_kstack.h
> > >> +++ b/include/linux/randomize_kstack.h
> > >> @@ -6,6 +6,7 @@
> > >>  #include <linux/kernel.h>
> > >>  #include <linux/jump_label.h>
> > >>  #include <linux/percpu-defs.h>
> > >> +#include <linux/prandom.h>
> > >>
> > >>  DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
> > >>                          randomize_kstack_offset);
> > >> @@ -45,9 +46,13 @@ DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
> > >>  #define KSTACK_OFFSET_MAX(x)   ((x) & 0b1111111100)
> > >>  #endif
> > >>
> > >> +static __always_inline u32 get_update_kstack_offset(void)
> > >> +{
> > >> +       return prandom_u32_state(&current->kstack_rnd_state);
> >
> > I've got bot warnings because this is being called from noinstr code. I guess
> > the best option is to just move add_random_kstack_offset() to after
> > instrumentation is enabled for the affected arches.
> 
> Just put instrumentation_begin()/instrumentation_end() around the call
> to prandom_u32_state() - that seems to be the common approach for
> punching holes into the 'noinstr' validation.

That silences the warning, but isn't necessarily safe, so please DO NOT
do that blindly. The instrumentation_{begin,end}() annotations are only
supposed to be used when we know by construction that instrumentation is
safe.

Generally, if you can move this to after instrumentation is already
enabled, that should be safe, and so that'd be the better approach.

Ryan, can you share those warnings (e.g. link to those reports)?

IIUC only x86 has noinstr validation, and from a quick scan, I expect
you see warnings from:

* do_syscall_64()
* do_int80_syscall_32()
* __do_fast_syscall_32()

For all of these, it is not safe to call instrumentable code before the
calls to {syscall_,}enter_from_user_mode{,_prepare}(). You'll need to
move the stack rnadomization after the existing instrumentation_begin()
calls.

We'll need to go check the other architectures similarly.

Mark.


From vdonnefort at google.com  Tue Dec  2 01:35:53 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:35:53 +0000
Subject: [PATCH v9 00/30] Tracefs support for pKVM
Message-ID: <20251202093623.2337860-1-vdonnefort@google.com>

The growing set of features supported by the hypervisor in protected
mode necessitates debugging and profiling tools. Tracefs is the
ideal candidate for this task:

  * It is simple to use and to script.

  * It is supported by various tools, from the trace-cmd CLI to the
    Android web-based perfetto.

  * The ring-buffer, where are stored trace events consists of linked
    pages, making it an ideal structure for sharing between kernel and
    hypervisor.

This series first introduces a new generic way of creating remote events and
remote buffers. Then it adds support to the pKVM hypervisor.

1. ring-buffer
--------------

To setup the per-cpu ring-buffers, a new interface is created:

  ring_buffer_remote:	Describes what the kernel needs to know about the
			remote writer, that is, the set of pages forming the
			ring-buffer and a callback for the reader/head
			swapping (enables consuming read)

  ring_buffer_remote():	Creates a read-only ring-buffer from a
			ring_buffer_remote.

To keep the internals of `struct ring_buffer` in sync with the remote,
the meta-page is used. It was originally introduced to enable user-space
mapping of the ring-buffer [1]. In this case, the kernel is not the
producer anymore but the reader. The function to read that meta-page is:

  ring_buffer_poll_remote():
			Update `struct ring_buffer` based on the remote
			meta-page. Wake-up readers if necessary.

The kernel has to poll the meta-page to be notified of newly written
events.

2. Tracefs
----------

This series introduce a new trace_remote that does the link between
tracefs and the remote ring-buffer.

The interface is found in the remotes/ directory at the root of the
tracefs mount point. Each remote is like an instance and you'll find
there a subset of the regular Tracefs user-space interface:

   remotes/test
	|-- buffer_size_kb
	|-- events
	|   |-- enable
	|   |-- header_event
	|   |-- header_page
	|   `-- test
	|       `-- selftest
	|           |-- enable
	|           |-- format
	|           `-- id
	|-- per_cpu
	|   `-- cpu0
	|       |-- trace
	|       `-- trace_pipe
	|-- trace
	|-- trace_pipe
	|-- tracing_on

Behind the scenes, kernel/trace/trace_remote.c creates this tracefs
hierarchy without relying on kernel/trace/trace.c. This is due to
fundamental differences:

  * Remote tracing doesn't support trace_array's system-specific
    features (snapshots, tracers, etc.).

  * Logged event formats differ (e.g., no PID for remote events).

  * Buffer operations require specific remote interactions.

3. Simple Ring-Buffer
---------------------

As the current ring-buffer.c implementation has too many dependencies to
be used directly by the pKVM hypervisor. A new simple implementation is
created and can be found in kernel/trace/simple-ring-buffer.c.

This implementation is write-only and is used by both the pKVM
hypervisor and a trace_remote test module.

4. Events
---------

A new REMOTE_EVENT() macro is added to simplify the creation of events
on the kernel side. As remote tracing buffer are read only, only the
event structure and a way of printing must be declared. The prototype of
the macro is very similar to the well-known TRACE_EVENT()

 REMOTE_EVENT(my_event, id,
     RE_STRUCT(
         re_field(u64, foobar)
     ),
     RE_PRINTK("foobar=%lld", __entry->foobar)
     )
  )

5. pKVM
-------

The pKVM support simply creates a "hypervisor" trace_remote on the
kernel side and inherits from simple-ring-buffer.c on the hypervisor
side.

A new event macro is created HYP_EVENT() that is under the hood re-using
REMOTE_EVENT() (defined in the previous paragaph) as well as generate
hypervisor specific struct and trace_<event>() functions.

5. Limitations:
---------------

Non-consuming reading of the buffer isn't supported (i.e. cat trace ->
-EPERM) due to current the lack of support in the ring-buffer meta-page.

[1] https://tracingsummit.org/ts/2022/hypervisortracing/
[2] https://lore.kernel.org/all/20240510140435.3550353-1-vdonnefort at google.com/

Changes since v8
  - Do not enable tracing if unstable cnvct (Marc)
  - Add support for nVHE (Marc)
  - Add PKVM_DISABLE_STAGE2_ON_PANIC (Marc)
  - NVHE_EL2_TRACING depends on NVHE_EL2_DEBUG (Marc)
  - Add a reason for hyp_enter/hyp_exit events (Marc)
  - Remove PKVM_SELFTESTS in favour of NVHE_EL2_DEBUG
  - Add wrapper for arm_smccc_1_2, now used in nvhe/ffa.c

Changes since v7
  - Add missing EXPORT_SYMBOL_GPL for remote_test.ko
  - Rebase on 6.18-rc4

Changes since v6

  - Add requires field to the selftest (Masami)
  - Use guard() for ring_buffer_poll_remote (Steven)
  - Rename ring_buffer_remote() to ring_buffer_alloc_remote() (Steven)
  - kerneldoc for trace_buffer_remote and simple_ring_buffer (Steven)
  - Validate trace_buffer_desc size in trace_remote_alloc_buffer
    (Steven)
  - Add non-consuming ring-buffer read (Steven)
  - Add spinning failsafe in simple_ring_buffer (Steven)
  - Range check for hyp_trace_desc::bpages_backing_* in hyp_trace_desc_validate()
  - unsigned int cpu in hyp_trace_desc_validate()
  - Fix event/format file
  - Add tests with an offline CPU
  - Add tests for non-consuming read
  - Add documentation
  - Rebase on 6.17

Changes since v5 (https://lore.kernel.org/all/20250516134031.661124-1-vdonnefort at google.com/)

  - Add tishift lib to the hyp (Aneesh)
  - Rebase on 6.17-rc2

Changes since v4 (https://lore.kernel.org/all/20250506164820.515876-1-vdonnefort at google.com/)

  - Extend meta-page with pages_touched and pages_lost
  - Create ring_buffer_types.h
  - Fix simple_ring_buffer build for 32-bits arch and x86
  - Try unload buffer on reset (+ test)
  - Minor renaming and comments

Changes since v3 (https://lore.kernel.org/all/20250224121353.98697-1-vdonnefort at google.com/)

  - Move tracefs support from kvm/hyp_trace.c into a generic trace_remote.c.
  - Move ring-buffer implementation from nvhe/trace.c into  a generic
    simple-ring-buffer.c
  - Rebase on 6.15-rc4.

Changes since v2 (https://lore.kernel.org/all/20250108114536.627715-1-vdonnefort at google.com/)

  - Fix ring-buffer remote reset
  - Fix fast-forward in rb_page_desc()
  - Refactor nvhe/trace.c
  - struct hyp_buffer_page more compact
  - Add a struct_len to trace_page_desc
  - Extend reset testing
  - Rebase on 6.14-rc3

Changes since v1 (https://lore.kernel.org/all/20240911093029.3279154-1-vdonnefort at google.com/)

  - Add 128-bits mult fallback in the unlikely event of an overflow. (John)
  - Fix ELF section sort.
  - __always_inline trace_* event macros.
  - Fix events/<event>/enable permissions.
  - Rename ring-buffer "writer" to "remote".
  - Rename CONFIG_PROTECTED_NVHE_TESTING to PKVM_SELFTEST to align with
    Quentin's upcoming selftest
  - Rebase on 6.13-rc3.

Changes since RFC (https://lore.kernel.org/all/20240805173234.3542917-1-vdonnefort at google.com/)

  - hypervisor trace clock:
     - mult/shift computed in hyp_trace.c. (John)
     - Update clock when it deviates from kernel boot clock. (John)
     - Add trace_clock file.
     - Separate patch for better readability.
  - Add a proper reset interface which does not need to teardown the
    tracing buffers. (Steven)
  - Return -EPERM on trace access. (Steven)
  - Add per-cpu trace file.
  - Automatically teardown and free the tracing buffer when it is empty,
    without readers and not currently tracing.
  - Show in buffer_size_kb if the buffer is loaded in the hypervisor or
    not.
  - Extend tests to cover reset and unload.
  - CC timekeeping folks on relevant patches (Marc)

Vincent Donnefort (30):
  ring-buffer: Add page statistics to the meta-page
  ring-buffer: Store bpage pointers into subbuf_ids
  ring-buffer: Introduce ring-buffer remotes
  ring-buffer: Add non-consuming read for ring-buffer remotes
  tracing: Introduce trace remotes
  tracing: Add reset to trace remotes
  tracing: Add non-consuming read to trace remotes
  tracing: Add init callback to trace remotes
  tracing: Add events to trace remotes
  tracing: Add events/ root files to trace remotes
  tracing: Add helpers to create trace remote events
  ring-buffer: Export buffer_data_page and macros
  tracing: Introduce simple_ring_buffer
  tracing: Add a trace remote module for testing
  tracing: selftests: Add trace remote tests
  Documentation: tracing: Add tracing remotes
  tracing: load/unload page callbacks for simple_ring_buffer
  tracing: Check for undefined symbols in simple_ring_buffer
  KVM: arm64: Add PKVM_DISABLE_STAGE2_ON_PANIC
  KVM: arm64: Add clock support to nVHE/pKVM hyp
  KVM: arm64: Initialise hyp_nr_cpus for nVHE hyp
  KVM: arm64: Support unaligned fixmap in the pKVM hyp
  KVM: arm64: Add tracing capability for the nVHE/pKVM hyp
  KVM: arm64: Add trace remote for the nVHE/pKVM hyp
  KVM: arm64: Sync boot clock with the nVHE/pKVM hyp
  KVM: arm64: Add trace reset to the nVHE/pKVM hyp
  KVM: arm64: Add event support to the nVHE/pKVM hyp and trace remote
  KVM: arm64: Add hyp_enter/hyp_exit events to nVHE/pKVM hyp
  KVM: arm64: Add selftest event support to nVHE/pKVM hyp
  tracing: selftests: Add hypervisor trace remote tests

 Documentation/trace/index.rst                 |   11 +
 Documentation/trace/remotes.rst               |   59 +
 arch/arm64/include/asm/kvm_asm.h              |    8 +
 arch/arm64/include/asm/kvm_define_hypevents.h |   16 +
 arch/arm64/include/asm/kvm_hyp.h              |    4 +-
 arch/arm64/include/asm/kvm_hypevents.h        |   56 +
 arch/arm64/include/asm/kvm_hyptrace.h         |   26 +
 arch/arm64/kernel/image-vars.h                |    4 +
 arch/arm64/kernel/vmlinux.lds.S               |   18 +
 arch/arm64/kvm/Kconfig                        |   64 +-
 arch/arm64/kvm/Makefile                       |    2 +
 arch/arm64/kvm/arm.c                          |   10 +-
 arch/arm64/kvm/handle_exit.c                  |    2 +-
 arch/arm64/kvm/hyp/include/nvhe/arm-smccc.h   |   23 +
 arch/arm64/kvm/hyp/include/nvhe/clock.h       |   16 +
 .../kvm/hyp/include/nvhe/define_events.h      |   14 +
 arch/arm64/kvm/hyp/include/nvhe/mem_protect.h |    2 -
 arch/arm64/kvm/hyp/include/nvhe/trace.h       |   58 +
 arch/arm64/kvm/hyp/nvhe/Makefile              |    6 +-
 arch/arm64/kvm/hyp/nvhe/clock.c               |   65 +
 arch/arm64/kvm/hyp/nvhe/events.c              |   25 +
 arch/arm64/kvm/hyp/nvhe/ffa.c                 |   28 +-
 arch/arm64/kvm/hyp/nvhe/host.S                |    2 +-
 arch/arm64/kvm/hyp/nvhe/hyp-main.c            |   91 +-
 arch/arm64/kvm/hyp/nvhe/hyp.lds.S             |    6 +
 arch/arm64/kvm/hyp/nvhe/mm.c                  |    4 +-
 arch/arm64/kvm/hyp/nvhe/psci-relay.c          |    7 +-
 arch/arm64/kvm/hyp/nvhe/setup.c               |    4 +-
 arch/arm64/kvm/hyp/nvhe/stacktrace.c          |    6 +-
 arch/arm64/kvm/hyp/nvhe/switch.c              |    5 +-
 arch/arm64/kvm/hyp/nvhe/trace.c               |  306 ++++
 arch/arm64/kvm/hyp_trace.c                    |  445 ++++++
 arch/arm64/kvm/hyp_trace.h                    |   11 +
 arch/arm64/kvm/stacktrace.c                   |    8 +-
 fs/tracefs/inode.c                            |    1 +
 include/linux/ring_buffer.h                   |   58 +
 include/linux/ring_buffer_types.h             |   41 +
 include/linux/simple_ring_buffer.h            |  120 ++
 include/linux/trace_remote.h                  |   92 ++
 include/linux/trace_remote_event.h            |   33 +
 include/trace/define_remote_events.h          |   73 +
 include/uapi/linux/trace_mmap.h               |    8 +-
 kernel/trace/Kconfig                          |   14 +
 kernel/trace/Makefile                         |   20 +
 kernel/trace/remote_test.c                    |  259 ++++
 kernel/trace/remote_test_events.h             |   10 +
 kernel/trace/ring_buffer.c                    |  356 ++++-
 kernel/trace/simple_ring_buffer.c             |  468 ++++++
 kernel/trace/trace.c                          |    2 +-
 kernel/trace/trace.h                          |    6 +
 kernel/trace/trace_remote.c                   | 1318 +++++++++++++++++
 .../ftrace/test.d/remotes/buffer_size.tc      |   25 +
 .../selftests/ftrace/test.d/remotes/functions |   88 ++
 .../test.d/remotes/hypervisor/buffer_size.tc  |   11 +
 .../ftrace/test.d/remotes/hypervisor/reset.tc |   11 +
 .../ftrace/test.d/remotes/hypervisor/trace.tc |   11 +
 .../test.d/remotes/hypervisor/trace_pipe.tc   |   11 +
 .../test.d/remotes/hypervisor/unloading.tc    |   11 +
 .../selftests/ftrace/test.d/remotes/reset.tc  |   90 ++
 .../selftests/ftrace/test.d/remotes/trace.tc  |  127 ++
 .../ftrace/test.d/remotes/trace_pipe.tc       |  127 ++
 .../ftrace/test.d/remotes/unloading.tc        |   41 +
 62 files changed, 4725 insertions(+), 119 deletions(-)
 create mode 100644 Documentation/trace/remotes.rst
 create mode 100644 arch/arm64/include/asm/kvm_define_hypevents.h
 create mode 100644 arch/arm64/include/asm/kvm_hypevents.h
 create mode 100644 arch/arm64/include/asm/kvm_hyptrace.h
 create mode 100644 arch/arm64/kvm/hyp/include/nvhe/arm-smccc.h
 create mode 100644 arch/arm64/kvm/hyp/include/nvhe/clock.h
 create mode 100644 arch/arm64/kvm/hyp/include/nvhe/define_events.h
 create mode 100644 arch/arm64/kvm/hyp/include/nvhe/trace.h
 create mode 100644 arch/arm64/kvm/hyp/nvhe/clock.c
 create mode 100644 arch/arm64/kvm/hyp/nvhe/events.c
 create mode 100644 arch/arm64/kvm/hyp/nvhe/trace.c
 create mode 100644 arch/arm64/kvm/hyp_trace.c
 create mode 100644 arch/arm64/kvm/hyp_trace.h
 create mode 100644 include/linux/ring_buffer_types.h
 create mode 100644 include/linux/simple_ring_buffer.h
 create mode 100644 include/linux/trace_remote.h
 create mode 100644 include/linux/trace_remote_event.h
 create mode 100644 include/trace/define_remote_events.h
 create mode 100644 kernel/trace/remote_test.c
 create mode 100644 kernel/trace/remote_test_events.h
 create mode 100644 kernel/trace/simple_ring_buffer.c
 create mode 100644 kernel/trace/trace_remote.c
 create mode 100644 tools/testing/selftests/ftrace/test.d/remotes/buffer_size.tc
 create mode 100644 tools/testing/selftests/ftrace/test.d/remotes/functions
 create mode 100644 tools/testing/selftests/ftrace/test.d/remotes/hypervisor/buffer_size.tc
 create mode 100644 tools/testing/selftests/ftrace/test.d/remotes/hypervisor/reset.tc
 create mode 100644 tools/testing/selftests/ftrace/test.d/remotes/hypervisor/trace.tc
 create mode 100644 tools/testing/selftests/ftrace/test.d/remotes/hypervisor/trace_pipe.tc
 create mode 100644 tools/testing/selftests/ftrace/test.d/remotes/hypervisor/unloading.tc
 create mode 100644 tools/testing/selftests/ftrace/test.d/remotes/reset.tc
 create mode 100644 tools/testing/selftests/ftrace/test.d/remotes/trace.tc
 create mode 100644 tools/testing/selftests/ftrace/test.d/remotes/trace_pipe.tc
 create mode 100644 tools/testing/selftests/ftrace/test.d/remotes/unloading.tc


base-commit: 30f09200cc4aefbd8385b01e41bde2e4565a6f0e
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:35:54 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:35:54 +0000
Subject: [PATCH v9 01/30] ring-buffer: Add page statistics to the meta-page
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-2-vdonnefort@google.com>

Add two fields pages_touched and pages_lost to the ring-buffer
meta-page. Those fields are useful to get the number of used pages in
the ring-buffer.

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/include/uapi/linux/trace_mmap.h b/include/uapi/linux/trace_mmap.h
index c102ef35d11e..e8185889a1c8 100644
--- a/include/uapi/linux/trace_mmap.h
+++ b/include/uapi/linux/trace_mmap.h
@@ -17,8 +17,8 @@
  * @entries:		Number of entries in the ring-buffer.
  * @overrun:		Number of entries lost in the ring-buffer.
  * @read:		Number of entries that have been read.
- * @Reserved1:		Internal use only.
- * @Reserved2:		Internal use only.
+ * @pages_lost:		Number of pages overwritten by the writer.
+ * @pages_touched:	Number of pages written by the writer.
  */
 struct trace_buffer_meta {
 	__u32		meta_page_size;
@@ -39,8 +39,8 @@ struct trace_buffer_meta {
 	__u64	overrun;
 	__u64	read;
 
-	__u64	Reserved1;
-	__u64	Reserved2;
+	__u64	pages_lost;
+	__u64	pages_touched;
 };
 
 #define TRACE_MMAP_IOCTL_GET_READER		_IO('R', 0x20)
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index afcd3747264d..048dde717b94 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -6113,6 +6113,8 @@ static void rb_update_meta_page(struct ring_buffer_per_cpu *cpu_buffer)
 	meta->entries = local_read(&cpu_buffer->entries);
 	meta->overrun = local_read(&cpu_buffer->overrun);
 	meta->read = cpu_buffer->read;
+	meta->pages_lost = local_read(&cpu_buffer->pages_lost);
+	meta->pages_touched = local_read(&cpu_buffer->pages_touched);
 
 	/* Some archs do not have data cache coherency between kernel and user-space */
 	flush_kernel_vmap_range(cpu_buffer->meta_page, PAGE_SIZE);
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:35:55 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:35:55 +0000
Subject: [PATCH v9 02/30] ring-buffer: Store bpage pointers into subbuf_ids
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-3-vdonnefort@google.com>

The subbuf_ids field allows to point to a specific page from the
ring-buffer based on its ID. As a preparation or the upcoming
ring-buffer remote support, point this array to the buffer_page instead
of the buffer_data_page.

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 048dde717b94..aeff2ce6231a 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -519,7 +519,7 @@ struct ring_buffer_per_cpu {
 	unsigned int			mapped;
 	unsigned int			user_mapped;	/* user space mapping */
 	struct mutex			mapping_lock;
-	unsigned long			*subbuf_ids;	/* ID to subbuf VA */
+	struct buffer_page		**subbuf_ids;	/* ID to subbuf VA */
 	struct trace_buffer_meta	*meta_page;
 	struct ring_buffer_cpu_meta	*ring_meta;
 
@@ -7002,7 +7002,7 @@ static void rb_free_meta_page(struct ring_buffer_per_cpu *cpu_buffer)
 }
 
 static void rb_setup_ids_meta_page(struct ring_buffer_per_cpu *cpu_buffer,
-				   unsigned long *subbuf_ids)
+				   struct buffer_page **subbuf_ids)
 {
 	struct trace_buffer_meta *meta = cpu_buffer->meta_page;
 	unsigned int nr_subbufs = cpu_buffer->nr_pages + 1;
@@ -7011,7 +7011,7 @@ static void rb_setup_ids_meta_page(struct ring_buffer_per_cpu *cpu_buffer,
 	int id = 0;
 
 	id = rb_page_id(cpu_buffer, cpu_buffer->reader_page, id);
-	subbuf_ids[id++] = (unsigned long)cpu_buffer->reader_page->page;
+	subbuf_ids[id++] = cpu_buffer->reader_page;
 	cnt++;
 
 	first_subbuf = subbuf = rb_set_head_page(cpu_buffer);
@@ -7021,7 +7021,7 @@ static void rb_setup_ids_meta_page(struct ring_buffer_per_cpu *cpu_buffer,
 		if (WARN_ON(id >= nr_subbufs))
 			break;
 
-		subbuf_ids[id] = (unsigned long)subbuf->page;
+		subbuf_ids[id] = subbuf;
 
 		rb_inc_page(&subbuf);
 		id++;
@@ -7030,7 +7030,7 @@ static void rb_setup_ids_meta_page(struct ring_buffer_per_cpu *cpu_buffer,
 
 	WARN_ON(cnt != nr_subbufs);
 
-	/* install subbuf ID to kern VA translation */
+	/* install subbuf ID to bpage translation */
 	cpu_buffer->subbuf_ids = subbuf_ids;
 
 	meta->meta_struct_len = sizeof(*meta);
@@ -7186,13 +7186,15 @@ static int __rb_map_vma(struct ring_buffer_per_cpu *cpu_buffer,
 	}
 
 	while (p < nr_pages) {
+		struct buffer_page *subbuf;
 		struct page *page;
 		int off = 0;
 
 		if (WARN_ON_ONCE(s >= nr_subbufs))
 			return -EINVAL;
 
-		page = virt_to_page((void *)cpu_buffer->subbuf_ids[s]);
+		subbuf = cpu_buffer->subbuf_ids[s];
+		page = virt_to_page((void *)subbuf->page);
 
 		for (; off < (1 << (subbuf_order)); off++, page++) {
 			if (p >= nr_pages)
@@ -7219,7 +7221,8 @@ int ring_buffer_map(struct trace_buffer *buffer, int cpu,
 		    struct vm_area_struct *vma)
 {
 	struct ring_buffer_per_cpu *cpu_buffer;
-	unsigned long flags, *subbuf_ids;
+	struct buffer_page **subbuf_ids;
+	unsigned long flags;
 	int err;
 
 	if (!cpumask_test_cpu(cpu, buffer->cpumask))
@@ -7243,7 +7246,7 @@ int ring_buffer_map(struct trace_buffer *buffer, int cpu,
 	if (err)
 		return err;
 
-	/* subbuf_ids include the reader while nr_pages does not */
+	/* subbuf_ids includes the reader while nr_pages does not */
 	subbuf_ids = kcalloc(cpu_buffer->nr_pages + 1, sizeof(*subbuf_ids), GFP_KERNEL);
 	if (!subbuf_ids) {
 		rb_free_meta_page(cpu_buffer);
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:35:56 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:35:56 +0000
Subject: [PATCH v9 03/30] ring-buffer: Introduce ring-buffer remotes
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-4-vdonnefort@google.com>

A ring-buffer remote is an entity outside of the kernel (most likely a
firmware or a hypervisor) capable of writing events in a ring-buffer
following the same format as the tracefs ring-buffer.

To setup the ring-buffer on the kernel side, a description of the pages
forming the ring-buffer (struct trace_buffer_desc) must be given.
Callbacks (swap_reader_page and reset) must also be provided.

It is expected from the remote to keep the meta-page updated.

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h
index 876358cfe1b1..41193c5b0d28 100644
--- a/include/linux/ring_buffer.h
+++ b/include/linux/ring_buffer.h
@@ -250,4 +250,62 @@ int ring_buffer_map(struct trace_buffer *buffer, int cpu,
 		    struct vm_area_struct *vma);
 int ring_buffer_unmap(struct trace_buffer *buffer, int cpu);
 int ring_buffer_map_get_reader(struct trace_buffer *buffer, int cpu);
+
+struct ring_buffer_desc {
+	int		cpu;
+	unsigned int	nr_page_va; /* excludes the meta page */
+	unsigned long	meta_va;
+	unsigned long	page_va[] __counted_by(nr_page_va);
+};
+
+struct trace_buffer_desc {
+	int		nr_cpus;
+	size_t		struct_len;
+	char		__data[]; /* list of ring_buffer_desc */
+};
+
+static inline struct ring_buffer_desc *__next_ring_buffer_desc(struct ring_buffer_desc *desc)
+{
+	size_t len = struct_size(desc, page_va, desc->nr_page_va);
+
+	return (struct ring_buffer_desc *)((void *)desc + len);
+}
+
+static inline struct ring_buffer_desc *__first_ring_buffer_desc(struct trace_buffer_desc *desc)
+{
+	return (struct ring_buffer_desc *)(&desc->__data[0]);
+}
+
+static inline size_t trace_buffer_desc_size(size_t buffer_size, unsigned int nr_cpus)
+{
+	unsigned int nr_pages = max(DIV_ROUND_UP(buffer_size, PAGE_SIZE), 2UL) + 1;
+	struct ring_buffer_desc *rbdesc;
+
+	return size_add(offsetof(struct trace_buffer_desc, __data),
+			size_mul(nr_cpus, struct_size(rbdesc, page_va, nr_pages)));
+}
+
+#define for_each_ring_buffer_desc(__pdesc, __cpu, __trace_pdesc)		\
+	for (__pdesc = __first_ring_buffer_desc(__trace_pdesc), __cpu = 0;	\
+	     (__cpu) < (__trace_pdesc)->nr_cpus;				\
+	     (__cpu)++, __pdesc = __next_ring_buffer_desc(__pdesc))
+
+struct ring_buffer_remote {
+	struct trace_buffer_desc	*desc;
+	int				(*swap_reader_page)(unsigned int cpu, void *priv);
+	int				(*reset)(unsigned int cpu, void *priv);
+	void				*priv;
+};
+
+int ring_buffer_poll_remote(struct trace_buffer *buffer, int cpu);
+
+struct trace_buffer *
+__ring_buffer_alloc_remote(struct ring_buffer_remote *remote,
+			   struct lock_class_key *key);
+
+#define ring_buffer_alloc_remote(remote)			\
+({								\
+	static struct lock_class_key __key;			\
+	__ring_buffer_alloc_remote(remote, &__key);		\
+})
 #endif /* _LINUX_RING_BUFFER_H */
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index aeff2ce6231a..9c6c8e206e04 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -523,6 +523,8 @@ struct ring_buffer_per_cpu {
 	struct trace_buffer_meta	*meta_page;
 	struct ring_buffer_cpu_meta	*ring_meta;
 
+	struct ring_buffer_remote	*remote;
+
 	/* ring buffer pages to update, > 0 to add, < 0 to remove */
 	long				nr_pages_to_update;
 	struct list_head		new_pages; /* new pages to add */
@@ -545,6 +547,8 @@ struct trace_buffer {
 
 	struct ring_buffer_per_cpu	**buffers;
 
+	struct ring_buffer_remote	*remote;
+
 	struct hlist_node		node;
 	u64				(*clock)(void);
 
@@ -2197,6 +2201,40 @@ static void rb_meta_buffer_update(struct ring_buffer_per_cpu *cpu_buffer,
 	}
 }
 
+static struct ring_buffer_desc *ring_buffer_desc(struct trace_buffer_desc *trace_desc, int cpu)
+{
+	struct ring_buffer_desc *desc, *end;
+	size_t len;
+	int i;
+
+	if (!trace_desc)
+		return NULL;
+
+	if (cpu >= trace_desc->nr_cpus)
+		return NULL;
+
+	end = (struct ring_buffer_desc *)((void *)trace_desc + trace_desc->struct_len);
+	desc = __first_ring_buffer_desc(trace_desc);
+	len = struct_size(desc, page_va, desc->nr_page_va);
+	desc = (struct ring_buffer_desc *)((void *)desc + (len * cpu));
+
+	if (desc < end && desc->cpu == cpu)
+		return desc;
+
+	/* Missing CPUs, need to linear search */
+	for_each_ring_buffer_desc(desc, i, trace_desc) {
+		if (desc->cpu == cpu)
+			return desc;
+	}
+
+	return NULL;
+}
+
+static void *ring_buffer_desc_page(struct ring_buffer_desc *desc, int page_id)
+{
+	return page_id > desc->nr_page_va ? NULL : (void *)desc->page_va[page_id];
+}
+
 static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
 		long nr_pages, struct list_head *pages)
 {
@@ -2204,6 +2242,7 @@ static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
 	struct ring_buffer_cpu_meta *meta = NULL;
 	struct buffer_page *bpage, *tmp;
 	bool user_thread = current->mm != NULL;
+	struct ring_buffer_desc *desc = NULL;
 	gfp_t mflags;
 	long i;
 
@@ -2240,6 +2279,12 @@ static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
 	if (buffer->range_addr_start)
 		meta = rb_range_meta(buffer, nr_pages, cpu_buffer->cpu);
 
+	if (buffer->remote) {
+		desc = ring_buffer_desc(buffer->remote->desc, cpu_buffer->cpu);
+		if (!desc || WARN_ON(desc->nr_page_va != (nr_pages + 1)))
+			return -EINVAL;
+	}
+
 	for (i = 0; i < nr_pages; i++) {
 		struct page *page;
 
@@ -2266,6 +2311,16 @@ static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
 				rb_meta_buffer_update(cpu_buffer, bpage);
 			bpage->range = 1;
 			bpage->id = i + 1;
+		} else if (desc) {
+			void *p = ring_buffer_desc_page(desc, i + 1);
+
+			if (WARN_ON(!p))
+				goto free_pages;
+
+			bpage->page = p;
+			bpage->range = 1; /* bpage->page can't be freed */
+			bpage->id = i + 1;
+			cpu_buffer->subbuf_ids[i + 1] = bpage;
 		} else {
 			page = alloc_pages_node(cpu_to_node(cpu_buffer->cpu),
 						mflags | __GFP_COMP | __GFP_ZERO,
@@ -2369,6 +2424,30 @@ rb_allocate_cpu_buffer(struct trace_buffer *buffer, long nr_pages, int cpu)
 		if (cpu_buffer->ring_meta->head_buffer)
 			rb_meta_buffer_update(cpu_buffer, bpage);
 		bpage->range = 1;
+	} else if (buffer->remote) {
+		struct ring_buffer_desc *desc = ring_buffer_desc(buffer->remote->desc, cpu);
+
+		if (!desc)
+			goto fail_free_reader;
+
+		cpu_buffer->remote = buffer->remote;
+		cpu_buffer->meta_page = (struct trace_buffer_meta *)(void *)desc->meta_va;
+		cpu_buffer->nr_pages = nr_pages;
+		cpu_buffer->subbuf_ids = kcalloc(cpu_buffer->nr_pages + 1,
+						 sizeof(*cpu_buffer->subbuf_ids), GFP_KERNEL);
+		if (!cpu_buffer->subbuf_ids)
+			goto fail_free_reader;
+
+		/* Remote buffers are read-only and immutable */
+		atomic_inc(&cpu_buffer->record_disabled);
+		atomic_inc(&cpu_buffer->resize_disabled);
+
+		bpage->page = ring_buffer_desc_page(desc, cpu_buffer->meta_page->reader.id);
+		if (!bpage->page)
+			goto fail_free_reader;
+
+		bpage->range = 1;
+		cpu_buffer->subbuf_ids[0] = bpage;
 	} else {
 		page = alloc_pages_node(cpu_to_node(cpu),
 					GFP_KERNEL | __GFP_COMP | __GFP_ZERO,
@@ -2431,6 +2510,9 @@ static void rb_free_cpu_buffer(struct ring_buffer_per_cpu *cpu_buffer)
 
 	irq_work_sync(&cpu_buffer->irq_work.work);
 
+	if (cpu_buffer->remote)
+		kfree(cpu_buffer->subbuf_ids);
+
 	free_buffer_page(cpu_buffer->reader_page);
 
 	if (head) {
@@ -2453,7 +2535,8 @@ static struct trace_buffer *alloc_buffer(unsigned long size, unsigned flags,
 					 int order, unsigned long start,
 					 unsigned long end,
 					 unsigned long scratch_size,
-					 struct lock_class_key *key)
+					 struct lock_class_key *key,
+					 struct ring_buffer_remote *remote)
 {
 	struct trace_buffer *buffer __free(kfree) = NULL;
 	long nr_pages;
@@ -2493,6 +2576,8 @@ static struct trace_buffer *alloc_buffer(unsigned long size, unsigned flags,
 	if (!buffer->buffers)
 		goto fail_free_cpumask;
 
+	cpu = raw_smp_processor_id();
+
 	/* If start/end are specified, then that overrides size */
 	if (start && end) {
 		unsigned long buffers_start;
@@ -2548,6 +2633,15 @@ static struct trace_buffer *alloc_buffer(unsigned long size, unsigned flags,
 		buffer->range_addr_end = end;
 
 		rb_range_meta_init(buffer, nr_pages, scratch_size);
+	} else if (remote) {
+		struct ring_buffer_desc *desc = ring_buffer_desc(remote->desc, cpu);
+
+		buffer->remote = remote;
+		/* The writer is remote. This ring-buffer is read-only */
+		atomic_inc(&buffer->record_disabled);
+		nr_pages = desc->nr_page_va - 1;
+		if (nr_pages < 2)
+			goto fail_free_buffers;
 	} else {
 
 		/* need at least two pages */
@@ -2556,7 +2650,6 @@ static struct trace_buffer *alloc_buffer(unsigned long size, unsigned flags,
 			nr_pages = 2;
 	}
 
-	cpu = raw_smp_processor_id();
 	cpumask_set_cpu(cpu, buffer->cpumask);
 	buffer->buffers[cpu] = rb_allocate_cpu_buffer(buffer, nr_pages, cpu);
 	if (!buffer->buffers[cpu])
@@ -2598,7 +2691,7 @@ struct trace_buffer *__ring_buffer_alloc(unsigned long size, unsigned flags,
 					struct lock_class_key *key)
 {
 	/* Default buffer page size - one system page */
-	return alloc_buffer(size, flags, 0, 0, 0, 0, key);
+	return alloc_buffer(size, flags, 0, 0, 0, 0, key, NULL);
 
 }
 EXPORT_SYMBOL_GPL(__ring_buffer_alloc);
@@ -2625,7 +2718,18 @@ struct trace_buffer *__ring_buffer_alloc_range(unsigned long size, unsigned flag
 					       struct lock_class_key *key)
 {
 	return alloc_buffer(size, flags, order, start, start + range_size,
-			    scratch_size, key);
+			    scratch_size, key, NULL);
+}
+
+/**
+ * __ring_buffer_alloc_remote - allocate a new ring_buffer from a remote
+ * @remote: Contains a description of the ring-buffer pages and remote callbacks.
+ * @key: ring buffer reader_lock_key.
+ */
+struct trace_buffer *__ring_buffer_alloc_remote(struct ring_buffer_remote *remote,
+						struct lock_class_key *key)
+{
+	return alloc_buffer(0, 0, 0, 0, 0, 0, key, remote);
 }
 
 void *ring_buffer_meta_scratch(struct trace_buffer *buffer, unsigned int *size)
@@ -5233,6 +5337,16 @@ unsigned long ring_buffer_overruns(struct trace_buffer *buffer)
 }
 EXPORT_SYMBOL_GPL(ring_buffer_overruns);
 
+static bool rb_read_remote_meta_page(struct ring_buffer_per_cpu *cpu_buffer)
+{
+	local_set(&cpu_buffer->entries, READ_ONCE(cpu_buffer->meta_page->entries));
+	local_set(&cpu_buffer->overrun, READ_ONCE(cpu_buffer->meta_page->overrun));
+	local_set(&cpu_buffer->pages_touched, READ_ONCE(cpu_buffer->meta_page->pages_touched));
+	local_set(&cpu_buffer->pages_lost, READ_ONCE(cpu_buffer->meta_page->pages_lost));
+
+	return rb_num_of_entries(cpu_buffer);
+}
+
 static void rb_iter_reset(struct ring_buffer_iter *iter)
 {
 	struct ring_buffer_per_cpu *cpu_buffer = iter->cpu_buffer;
@@ -5387,7 +5501,43 @@ rb_update_iter_read_stamp(struct ring_buffer_iter *iter,
 }
 
 static struct buffer_page *
-rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)
+__rb_get_reader_page_from_remote(struct ring_buffer_per_cpu *cpu_buffer)
+{
+	struct buffer_page *new_reader, *prev_reader;
+
+	if (!rb_read_remote_meta_page(cpu_buffer))
+		return NULL;
+
+	/* More to read on the reader page */
+	if (cpu_buffer->reader_page->read < rb_page_size(cpu_buffer->reader_page)) {
+		if (!cpu_buffer->reader_page->read)
+			cpu_buffer->read_stamp = cpu_buffer->reader_page->page->time_stamp;
+		return cpu_buffer->reader_page;
+	}
+
+	prev_reader = cpu_buffer->subbuf_ids[cpu_buffer->meta_page->reader.id];
+
+	WARN_ON_ONCE(cpu_buffer->remote->swap_reader_page(cpu_buffer->cpu,
+							  cpu_buffer->remote->priv));
+	/* nr_pages doesn't include the reader page */
+	if (WARN_ON_ONCE(cpu_buffer->meta_page->reader.id > cpu_buffer->nr_pages))
+		return NULL;
+
+	new_reader = cpu_buffer->subbuf_ids[cpu_buffer->meta_page->reader.id];
+
+	WARN_ON_ONCE(prev_reader == new_reader);
+
+	cpu_buffer->reader_page->page = new_reader->page;
+	cpu_buffer->reader_page->id = new_reader->id;
+	cpu_buffer->reader_page->read = 0;
+	cpu_buffer->read_stamp = cpu_buffer->reader_page->page->time_stamp;
+	cpu_buffer->lost_events = cpu_buffer->meta_page->reader.lost_events;
+
+	return rb_page_size(cpu_buffer->reader_page) ? cpu_buffer->reader_page : NULL;
+}
+
+static struct buffer_page *
+__rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)
 {
 	struct buffer_page *reader = NULL;
 	unsigned long bsize = READ_ONCE(cpu_buffer->buffer->subbuf_size);
@@ -5557,6 +5707,13 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)
 	return reader;
 }
 
+static struct buffer_page *
+rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)
+{
+	return cpu_buffer->remote ? __rb_get_reader_page_from_remote(cpu_buffer) :
+				    __rb_get_reader_page(cpu_buffer);
+}
+
 static void rb_advance_reader(struct ring_buffer_per_cpu *cpu_buffer)
 {
 	struct ring_buffer_event *event;
@@ -5957,7 +6114,7 @@ ring_buffer_read_start(struct trace_buffer *buffer, int cpu, gfp_t flags)
 	struct ring_buffer_per_cpu *cpu_buffer;
 	struct ring_buffer_iter *iter;
 
-	if (!cpumask_test_cpu(cpu, buffer->cpumask))
+	if (!cpumask_test_cpu(cpu, buffer->cpumask) || buffer->remote)
 		return NULL;
 
 	iter = kzalloc(sizeof(*iter), flags);
@@ -6125,6 +6282,23 @@ rb_reset_cpu(struct ring_buffer_per_cpu *cpu_buffer)
 {
 	struct buffer_page *page;
 
+	if (cpu_buffer->remote) {
+		if (!cpu_buffer->remote->reset)
+			return;
+
+		cpu_buffer->remote->reset(cpu_buffer->cpu, cpu_buffer->remote->priv);
+		rb_read_remote_meta_page(cpu_buffer);
+
+		/* Read related values, not covered by the meta-page */
+		local_set(&cpu_buffer->pages_read, 0);
+		cpu_buffer->read = 0;
+		cpu_buffer->read_bytes = 0;
+		cpu_buffer->last_overrun = 0;
+		cpu_buffer->reader_page->read = 0;
+
+		return;
+	}
+
 	rb_head_page_deactivate(cpu_buffer);
 
 	cpu_buffer->head_page
@@ -6355,6 +6529,48 @@ bool ring_buffer_empty_cpu(struct trace_buffer *buffer, int cpu)
 }
 EXPORT_SYMBOL_GPL(ring_buffer_empty_cpu);
 
+int ring_buffer_poll_remote(struct trace_buffer *buffer, int cpu)
+{
+	struct ring_buffer_per_cpu *cpu_buffer;
+
+	if (cpu != RING_BUFFER_ALL_CPUS) {
+		if (!cpumask_test_cpu(cpu, buffer->cpumask))
+			return -EINVAL;
+
+		cpu_buffer = buffer->buffers[cpu];
+
+		guard(raw_spinlock)(&cpu_buffer->reader_lock);
+		if (rb_read_remote_meta_page(cpu_buffer))
+			rb_wakeups(buffer, cpu_buffer);
+
+		return 0;
+	}
+
+	cpus_read_lock();
+
+	/*
+	 * Make sure all the ring buffers are up to date before we start reading
+	 * them.
+	 */
+	for_each_buffer_cpu(buffer, cpu) {
+		cpu_buffer = buffer->buffers[cpu];
+
+		guard(raw_spinlock)(&cpu_buffer->reader_lock);
+		rb_read_remote_meta_page(cpu_buffer);
+	}
+
+	for_each_buffer_cpu(buffer, cpu) {
+		cpu_buffer = buffer->buffers[cpu];
+
+		if (rb_num_of_entries(cpu_buffer))
+			rb_wakeups(buffer, cpu_buffer);
+	}
+
+	cpus_read_unlock();
+
+	return 0;
+}
+
 #ifdef CONFIG_RING_BUFFER_ALLOW_SWAP
 /**
  * ring_buffer_swap_cpu - swap a CPU buffer between two ring buffers
@@ -6600,6 +6816,7 @@ int ring_buffer_read_page(struct trace_buffer *buffer,
 	unsigned int commit;
 	unsigned int read;
 	u64 save_timestamp;
+	bool force_memcpy;
 
 	if (!cpumask_test_cpu(cpu, buffer->cpumask))
 		return -1;
@@ -6637,6 +6854,8 @@ int ring_buffer_read_page(struct trace_buffer *buffer,
 	/* Check if any events were dropped */
 	missed_events = cpu_buffer->lost_events;
 
+	force_memcpy = cpu_buffer->mapped || cpu_buffer->remote;
+
 	/*
 	 * If this page has been partially read or
 	 * if len is not big enough to read the rest of the page or
@@ -6646,7 +6865,7 @@ int ring_buffer_read_page(struct trace_buffer *buffer,
 	 */
 	if (read || (len < (commit - read)) ||
 	    cpu_buffer->reader_page == cpu_buffer->commit_page ||
-	    cpu_buffer->mapped) {
+	    force_memcpy) {
 		struct buffer_data_page *rpage = cpu_buffer->reader_page->page;
 		unsigned int rpos = read;
 		unsigned int pos = 0;
@@ -7225,7 +7444,7 @@ int ring_buffer_map(struct trace_buffer *buffer, int cpu,
 	unsigned long flags;
 	int err;
 
-	if (!cpumask_test_cpu(cpu, buffer->cpumask))
+	if (!cpumask_test_cpu(cpu, buffer->cpumask) || buffer->remote)
 		return -EINVAL;
 
 	cpu_buffer = buffer->buffers[cpu];
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:35:57 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:35:57 +0000
Subject: [PATCH v9 04/30] ring-buffer: Add non-consuming read for ring-buffer remotes
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-5-vdonnefort@google.com>

Hopefully, the remote will only swap pages on the kernel instruction (via
the swap_reader_page() callback). This means we know at what point the
ring-buffer geometry has changed. It is therefore possible to rearrange
the kernel view of that ring-buffer to allow non-consuming read.

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 9c6c8e206e04..cb674a9fc359 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -5347,10 +5347,51 @@ static bool rb_read_remote_meta_page(struct ring_buffer_per_cpu *cpu_buffer)
 	return rb_num_of_entries(cpu_buffer);
 }
 
+static void rb_update_remote_head(struct ring_buffer_per_cpu *cpu_buffer)
+{
+	struct buffer_page *next, *orig;
+	int retry = 3;
+
+	orig = next = cpu_buffer->head_page;
+	rb_inc_page(&next);
+
+	/* Run after the writer */
+	while (cpu_buffer->head_page->page->time_stamp > next->page->time_stamp) {
+		rb_inc_page(&next);
+
+		rb_list_head_clear(cpu_buffer->head_page->list.prev);
+		rb_inc_page(&cpu_buffer->head_page);
+		rb_set_list_to_head(cpu_buffer->head_page->list.prev);
+
+		if (cpu_buffer->head_page == orig) {
+			if (WARN_ON_ONCE(!(--retry)))
+				return;
+		}
+	}
+
+	orig = cpu_buffer->commit_page = cpu_buffer->head_page;
+	retry = 3;
+
+	while (cpu_buffer->commit_page->page->time_stamp < next->page->time_stamp) {
+		rb_inc_page(&next);
+		rb_inc_page(&cpu_buffer->commit_page);
+
+		if (cpu_buffer->commit_page == orig) {
+			if (WARN_ON_ONCE(!(--retry)))
+				return;
+		}
+	}
+}
+
 static void rb_iter_reset(struct ring_buffer_iter *iter)
 {
 	struct ring_buffer_per_cpu *cpu_buffer = iter->cpu_buffer;
 
+	if (cpu_buffer->remote) {
+		rb_read_remote_meta_page(cpu_buffer);
+		rb_update_remote_head(cpu_buffer);
+	}
+
 	/* Iterator usage is expected to have record disabled */
 	iter->head_page = cpu_buffer->reader_page;
 	iter->head = cpu_buffer->reader_page->read;
@@ -5503,7 +5544,7 @@ rb_update_iter_read_stamp(struct ring_buffer_iter *iter,
 static struct buffer_page *
 __rb_get_reader_page_from_remote(struct ring_buffer_per_cpu *cpu_buffer)
 {
-	struct buffer_page *new_reader, *prev_reader;
+	struct buffer_page *new_reader, *prev_reader, *prev_head, *new_head, *last;
 
 	if (!rb_read_remote_meta_page(cpu_buffer))
 		return NULL;
@@ -5527,10 +5568,32 @@ __rb_get_reader_page_from_remote(struct ring_buffer_per_cpu *cpu_buffer)
 
 	WARN_ON_ONCE(prev_reader == new_reader);
 
-	cpu_buffer->reader_page->page = new_reader->page;
-	cpu_buffer->reader_page->id = new_reader->id;
-	cpu_buffer->reader_page->read = 0;
-	cpu_buffer->read_stamp = cpu_buffer->reader_page->page->time_stamp;
+	prev_head = new_reader;  /* New reader was also the previous head */
+	new_head = prev_head;
+	rb_inc_page(&new_head);
+	last = prev_head;
+	rb_dec_page(&last);
+
+	/* Clear the old HEAD flag */
+	rb_list_head_clear(cpu_buffer->head_page->list.prev);
+
+	prev_reader->list.next = prev_head->list.next;
+	prev_reader->list.prev = prev_head->list.prev;
+
+	/* Swap prev_reader with new_reader */
+	last->list.next = &prev_reader->list;
+	new_head->list.prev = &prev_reader->list;
+
+	new_reader->list.prev = &new_reader->list;
+	new_reader->list.next = &new_head->list;
+
+	/* Reactivate the HEAD flag */
+	rb_set_list_to_head(&last->list);
+
+	cpu_buffer->head_page = new_head;
+	cpu_buffer->reader_page = new_reader;
+	cpu_buffer->pages = &new_head->list;
+	cpu_buffer->read_stamp = new_reader->page->time_stamp;
 	cpu_buffer->lost_events = cpu_buffer->meta_page->reader.lost_events;
 
 	return rb_page_size(cpu_buffer->reader_page) ? cpu_buffer->reader_page : NULL;
@@ -6114,7 +6177,7 @@ ring_buffer_read_start(struct trace_buffer *buffer, int cpu, gfp_t flags)
 	struct ring_buffer_per_cpu *cpu_buffer;
 	struct ring_buffer_iter *iter;
 
-	if (!cpumask_test_cpu(cpu, buffer->cpumask) || buffer->remote)
+	if (!cpumask_test_cpu(cpu, buffer->cpumask))
 		return NULL;
 
 	iter = kzalloc(sizeof(*iter), flags);
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:35:59 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:35:59 +0000
Subject: [PATCH v9 06/30] tracing: Add reset to trace remotes
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-7-vdonnefort@google.com>

Allow to reset the trace remote buffer by writing to the Tracefs "trace"
file. This is similar to the regular Tracefs interface.

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/include/linux/trace_remote.h b/include/linux/trace_remote.h
index feb3433c2128..55754ef78104 100644
--- a/include/linux/trace_remote.h
+++ b/include/linux/trace_remote.h
@@ -18,6 +18,8 @@
  *			remote to allow writing.
  * @swap_reader_page:	Called when Tracefs consumes a new page from a
  *			ring-buffer. It is expected from the remote to isolate a
+ * @reset:		Called on `echo 0 > trace`. It is expected from the
+ *			remote to reset all ring-buffer pages.
  *			new reader-page from the @cpu ring-buffer.
  */
 struct trace_remote_callbacks {
@@ -25,6 +27,7 @@ struct trace_remote_callbacks {
 	void	(*unload_trace_buffer)(struct trace_buffer_desc *desc, void *priv);
 	int	(*enable_tracing)(bool enable, void *priv);
 	int	(*swap_reader_page)(unsigned int cpu, void *priv);
+	int	(*reset)(unsigned int cpu, void *priv);
 };
 
 /**
diff --git a/kernel/trace/trace_remote.c b/kernel/trace/trace_remote.c
index 3d80ff98fd90..49c4ae127533 100644
--- a/kernel/trace/trace_remote.c
+++ b/kernel/trace/trace_remote.c
@@ -63,6 +63,7 @@ static int trace_remote_load(struct trace_remote *remote)
 	rb_remote->desc = remote->trace_buffer_desc;
 	rb_remote->swap_reader_page = remote->cbs->swap_reader_page;
 	rb_remote->priv = remote->priv;
+	rb_remote->reset = remote->cbs->reset;
 	remote->trace_buffer = ring_buffer_alloc_remote(rb_remote);
 	if (!remote->trace_buffer) {
 		remote->cbs->unload_trace_buffer(remote->trace_buffer_desc, remote->priv);
@@ -136,6 +137,21 @@ static int trace_remote_disable_tracing(struct trace_remote *remote)
 	return 0;
 }
 
+static void trace_remote_reset(struct trace_remote *remote, int cpu)
+{
+	lockdep_assert_held(&remote->lock);
+
+	if (!trace_remote_loaded(remote))
+		return;
+
+	if (cpu == RING_BUFFER_ALL_CPUS)
+		ring_buffer_reset(remote->trace_buffer);
+	else
+		ring_buffer_reset_cpu(remote->trace_buffer, cpu);
+
+	trace_remote_try_unload(remote);
+}
+
 static ssize_t
 tracing_on_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos)
 {
@@ -410,6 +426,26 @@ static const struct file_operations trace_pipe_fops = {
 	.release	= trace_pipe_release,
 };
 
+static ssize_t trace_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	struct inode *inode = file_inode(filp);
+	struct trace_remote *remote = inode->i_private;
+	int cpu = RING_BUFFER_ALL_CPUS;
+
+	if (inode->i_cdev)
+		cpu = (long)inode->i_cdev - 1;
+
+	guard(mutex)(&remote->lock);
+
+	trace_remote_reset(remote, cpu);
+
+	return cnt;
+}
+
+static const struct file_operations trace_fops = {
+	.write		= trace_write,
+};
+
 static int trace_remote_init_tracefs(const char *name, struct trace_remote *remote)
 {
 	struct dentry *remote_d, *percpu_d;
@@ -440,7 +476,9 @@ static int trace_remote_init_tracefs(const char *name, struct trace_remote *remo
 	    !trace_create_file("buffer_size_kb", TRACEFS_MODE_WRITE, remote_d, remote,
 			       &buffer_size_kb_fops) ||
 	    !trace_create_file("trace_pipe", TRACEFS_MODE_READ, remote_d, remote,
-			       &trace_pipe_fops))
+			       &trace_pipe_fops) ||
+	    !trace_create_file("trace", TRACEFS_MODE_WRITE, remote_d, remote,
+			       &trace_fops))
 		goto err;
 
 	percpu_d = tracefs_create_dir("per_cpu", remote_d);
@@ -462,7 +500,9 @@ static int trace_remote_init_tracefs(const char *name, struct trace_remote *remo
 		}
 
 		if (!trace_create_cpu_file("trace_pipe", TRACEFS_MODE_READ, cpu_d, remote, cpu,
-					   &trace_pipe_fops))
+					   &trace_pipe_fops) ||
+		    !trace_create_cpu_file("trace", TRACEFS_MODE_WRITE, cpu_d, remote, cpu,
+					   &trace_fops))
 			goto err;
 	}
 
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:35:58 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:35:58 +0000
Subject: [PATCH v9 05/30] tracing: Introduce trace remotes
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-6-vdonnefort@google.com>

A trace remote relies on ring-buffer remotes to read and control
compatible tracing buffers, written by entity such as firmware or
hypervisor.

Add a Tracefs directory remotes/ that contains all instances of trace
remotes. Each instance follows the same hierarchy as any other to ease
the support by existing user-space tools.

This currently does not provide any event support, which will come
later.

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/include/linux/trace_remote.h b/include/linux/trace_remote.h
new file mode 100644
index 000000000000..feb3433c2128
--- /dev/null
+++ b/include/linux/trace_remote.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _LINUX_TRACE_REMOTE_H
+#define _LINUX_TRACE_REMOTE_H
+
+#include <linux/ring_buffer.h>
+
+/**
+ * struct trace_remote_callbacks - Callbacks used by Tracefs to control the remote
+ *
+ * @load_trace_buffer:  Called before Tracefs accesses the trace buffer for the first
+ *			time. Must return a &trace_buffer_desc
+ *			(most likely filled with trace_remote_alloc_buffer())
+ * @unload_trace_buffer:
+ *			Called once Tracefs has no use for the trace buffer
+ *			(most likely call trace_remote_free_buffer())
+ * @enable_tracing:	Called on Tracefs tracing_on. It is expected from the
+ *			remote to allow writing.
+ * @swap_reader_page:	Called when Tracefs consumes a new page from a
+ *			ring-buffer. It is expected from the remote to isolate a
+ *			new reader-page from the @cpu ring-buffer.
+ */
+struct trace_remote_callbacks {
+	struct trace_buffer_desc *(*load_trace_buffer)(unsigned long size, void *priv);
+	void	(*unload_trace_buffer)(struct trace_buffer_desc *desc, void *priv);
+	int	(*enable_tracing)(bool enable, void *priv);
+	int	(*swap_reader_page)(unsigned int cpu, void *priv);
+};
+
+/**
+ * trace_remote_register() - Register a Tracefs remote
+ *
+ * A trace remote is an entity, outside of the kernel (most likely firmware or
+ * hypervisor) capable of writing events into a Tracefs compatible ring-buffer.
+ * The kernel would then act as a reader.
+ *
+ * The registered remote will be found under the Tracefs directory
+ * remotes/<name>.
+ *
+ * @name:	Name of the remote, used for the Tracefs remotes/ directory.
+ * @cbs:	Set of callbacks used to control the remote.
+ * @priv:	Private data, passed to each callback from @cbs.
+ * @events:	Array of events. &remote_event.name and &remote_event.id must be
+ *		filled by the caller.
+ * @nr_events:	Number of events in the @events array.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int trace_remote_register(const char *name, struct trace_remote_callbacks *cbs, void *priv);
+
+/**
+ * trace_remote_alloc_buffer() - Dynamically allocate a trace buffer
+ *
+ * Helper to dynamically allocate a set of pages (enough to cover @buffer_size)
+ * for each CPU from @cpumask and fill @desc. Most likely called from
+ * &trace_remote_callbacks.load_trace_buffer.
+ *
+ * @desc:		Uninitialized trace_buffer_desc
+ * @desc_size:		Size of the trace_buffer_desc. Must be at least equal to
+ *			trace_buffer_desc_size()
+ * @buffer_size:	Size in bytes of each per-CPU ring-buffer
+ * @cpumask:		CPUs to allocate a ring-buffer for
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int trace_remote_alloc_buffer(struct trace_buffer_desc *desc, size_t desc_size, size_t buffer_size,
+			      const struct cpumask *cpumask);
+
+/**
+ * trace_remote_free_buffer() - Free trace buffer allocated with
+ *				trace_remote_alloc_buffer()
+ *
+ * Most likely called from &trace_remote_callbacks.unload_trace_buffer.
+ *
+ * @desc:	Descriptor of the per-CPU ring-buffers, originally filled by
+ *		trace_remote_alloc_buffer()
+ */
+void trace_remote_free_buffer(struct trace_buffer_desc *desc);
+
+#endif
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index d2c79da81e4f..99af56d39eaf 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -1238,4 +1238,7 @@ config HIST_TRIGGERS_DEBUG
 
 source "kernel/trace/rv/Kconfig"
 
+config TRACE_REMOTE
+	bool
+
 endif # FTRACE
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index dcb4e02afc5f..6dab341acc46 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -110,4 +110,5 @@ obj-$(CONFIG_FPROBE_EVENTS) += trace_fprobe.o
 obj-$(CONFIG_TRACEPOINT_BENCHMARK) += trace_benchmark.o
 obj-$(CONFIG_RV) += rv/
 
+obj-$(CONFIG_TRACE_REMOTE) += trace_remote.o
 libftrace-y := ftrace.o
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index d1e527cf2aae..5b2313ed1f12 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -9125,7 +9125,7 @@ static struct dentry *tracing_dentry_percpu(struct trace_array *tr, int cpu)
 	return tr->percpu_dir;
 }
 
-static struct dentry *
+struct dentry *
 trace_create_cpu_file(const char *name, umode_t mode, struct dentry *parent,
 		      void *data, long cpu, const struct file_operations *fops)
 {
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 85eabb454bee..9ce2f0ed8f86 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -672,6 +672,12 @@ struct dentry *trace_create_file(const char *name,
 				 struct dentry *parent,
 				 void *data,
 				 const struct file_operations *fops);
+struct dentry *trace_create_cpu_file(const char *name,
+				     umode_t mode,
+				     struct dentry *parent,
+				     void *data,
+				     long cpu,
+				     const struct file_operations *fops);
 
 
 /**
diff --git a/kernel/trace/trace_remote.c b/kernel/trace/trace_remote.c
new file mode 100644
index 000000000000..3d80ff98fd90
--- /dev/null
+++ b/kernel/trace/trace_remote.c
@@ -0,0 +1,570 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025 - Google LLC
+ * Author: Vincent Donnefort <vdonnefort at google.com>
+ */
+
+#include <linux/kstrtox.h>
+#include <linux/lockdep.h>
+#include <linux/mutex.h>
+#include <linux/tracefs.h>
+#include <linux/trace_remote.h>
+#include <linux/trace_seq.h>
+#include <linux/types.h>
+
+#include "trace.h"
+
+#define TRACEFS_DIR		"remotes"
+#define TRACEFS_MODE_WRITE	0640
+#define TRACEFS_MODE_READ	0440
+
+struct trace_remote_iterator {
+	struct trace_remote		*remote;
+	struct trace_seq		seq;
+	struct delayed_work		poll_work;
+	unsigned long			lost_events;
+	u64				ts;
+	int				cpu;
+	int				evt_cpu;
+};
+
+struct trace_remote {
+	struct trace_remote_callbacks	*cbs;
+	void				*priv;
+	struct trace_buffer		*trace_buffer;
+	struct trace_buffer_desc	*trace_buffer_desc;
+	unsigned long			trace_buffer_size;
+	struct ring_buffer_remote	rb_remote;
+	struct mutex			lock;
+	unsigned int			nr_readers;
+	unsigned int			poll_ms;
+	bool				tracing_on;
+};
+
+static bool trace_remote_loaded(struct trace_remote *remote)
+{
+	return remote->trace_buffer;
+}
+
+static int trace_remote_load(struct trace_remote *remote)
+{
+	struct ring_buffer_remote *rb_remote = &remote->rb_remote;
+
+	lockdep_assert_held(&remote->lock);
+
+	if (trace_remote_loaded(remote))
+		return 0;
+
+	remote->trace_buffer_desc = remote->cbs->load_trace_buffer(remote->trace_buffer_size,
+								   remote->priv);
+	if (IS_ERR(remote->trace_buffer_desc))
+		return PTR_ERR(remote->trace_buffer_desc);
+
+	rb_remote->desc = remote->trace_buffer_desc;
+	rb_remote->swap_reader_page = remote->cbs->swap_reader_page;
+	rb_remote->priv = remote->priv;
+	remote->trace_buffer = ring_buffer_alloc_remote(rb_remote);
+	if (!remote->trace_buffer) {
+		remote->cbs->unload_trace_buffer(remote->trace_buffer_desc, remote->priv);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void trace_remote_try_unload(struct trace_remote *remote)
+{
+	lockdep_assert_held(&remote->lock);
+
+	if (!trace_remote_loaded(remote))
+		return;
+
+	/* The buffer is being read or writable */
+	if (remote->nr_readers || remote->tracing_on)
+		return;
+
+	/* The buffer has readable data */
+	if (!ring_buffer_empty(remote->trace_buffer))
+		return;
+
+	ring_buffer_free(remote->trace_buffer);
+	remote->trace_buffer = NULL;
+	remote->cbs->unload_trace_buffer(remote->trace_buffer_desc, remote->priv);
+}
+
+static int trace_remote_enable_tracing(struct trace_remote *remote)
+{
+	int ret;
+
+	lockdep_assert_held(&remote->lock);
+
+	if (remote->tracing_on)
+		return 0;
+
+	ret = trace_remote_load(remote);
+	if (ret)
+		return ret;
+
+	ret = remote->cbs->enable_tracing(true, remote->priv);
+	if (ret) {
+		trace_remote_try_unload(remote);
+		return ret;
+	}
+
+	remote->tracing_on = true;
+
+	return 0;
+}
+
+static int trace_remote_disable_tracing(struct trace_remote *remote)
+{
+	int ret;
+
+	lockdep_assert_held(&remote->lock);
+
+	if (!remote->tracing_on)
+		return 0;
+
+	ret = remote->cbs->enable_tracing(false, remote->priv);
+	if (ret)
+		return ret;
+
+	ring_buffer_poll_remote(remote->trace_buffer, RING_BUFFER_ALL_CPUS);
+	remote->tracing_on = false;
+	trace_remote_try_unload(remote);
+
+	return 0;
+}
+
+static ssize_t
+tracing_on_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	struct trace_remote *remote = filp->private_data;
+	unsigned long val;
+	int ret;
+
+	ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&remote->lock);
+
+	ret = val ? trace_remote_enable_tracing(remote) : trace_remote_disable_tracing(remote);
+	if (ret)
+		return ret;
+
+	return cnt;
+}
+static int tracing_on_show(struct seq_file *s, void *unused)
+{
+	struct trace_remote *remote = s->private;
+
+	seq_printf(s, "%d\n", remote->tracing_on);
+
+	return 0;
+}
+DEFINE_SHOW_STORE_ATTRIBUTE(tracing_on);
+
+static ssize_t buffer_size_kb_write(struct file *filp, const char __user *ubuf, size_t cnt,
+				    loff_t *ppos)
+{
+	struct trace_remote *remote = filp->private_data;
+	unsigned long val;
+	int ret;
+
+	ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
+	if (ret)
+		return ret;
+
+	/* KiB to Bytes */
+	if (!val || check_shl_overflow(val, 10, &val))
+		return -EINVAL;
+
+	guard(mutex)(&remote->lock);
+
+	remote->trace_buffer_size = val;
+
+	return cnt;
+}
+
+static int buffer_size_kb_show(struct seq_file *s, void *unused)
+{
+	struct trace_remote *remote = s->private;
+
+	seq_printf(s, "%lu (%s)\n", remote->trace_buffer_size >> 10,
+		   trace_remote_loaded(remote) ? "loaded" : "unloaded");
+
+	return 0;
+}
+DEFINE_SHOW_STORE_ATTRIBUTE(buffer_size_kb);
+
+static int trace_remote_get(struct trace_remote *remote, int cpu)
+{
+	int ret;
+
+	if (remote->nr_readers == UINT_MAX)
+		return -EBUSY;
+
+	ret = trace_remote_load(remote);
+	if (ret)
+		return ret;
+
+	remote->nr_readers++;
+
+	return 0;
+}
+
+static void trace_remote_put(struct trace_remote *remote)
+{
+	if (WARN_ON(!remote->nr_readers))
+		return;
+
+	remote->nr_readers--;
+	if (remote->nr_readers)
+		return;
+
+	trace_remote_try_unload(remote);
+}
+
+static void __poll_remote(struct work_struct *work)
+{
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct trace_remote_iterator *iter;
+
+	iter = container_of(dwork, struct trace_remote_iterator, poll_work);
+	ring_buffer_poll_remote(iter->remote->trace_buffer, iter->cpu);
+	schedule_delayed_work((struct delayed_work *)work,
+			      msecs_to_jiffies(iter->remote->poll_ms));
+}
+
+static struct trace_remote_iterator
+*trace_remote_iter(struct trace_remote *remote, int cpu, enum tri_type type)
+{
+	struct trace_remote_iterator *iter = NULL;
+	int ret;
+
+	lockdep_assert_held(&remote->lock);
+
+
+	ret = trace_remote_get(remote, cpu);
+	if (ret)
+		return ERR_PTR(ret);
+
+	/* Test the CPU */
+	ret = ring_buffer_poll_remote(remote->trace_buffer, cpu);
+	if (ret)
+		goto err;
+
+	iter = kzalloc(sizeof(*iter), GFP_KERNEL);
+	if (iter) {
+		iter->remote = remote;
+		iter->cpu = cpu;
+		trace_seq_init(&iter->seq);
+		INIT_DELAYED_WORK(&iter->poll_work, __poll_remote);
+		schedule_delayed_work(&iter->poll_work, msecs_to_jiffies(remote->poll_ms));
+
+		return iter;
+	}
+	ret = -ENOMEM;
+
+err:
+	kfree(iter);
+	trace_remote_put(remote);
+
+	return ERR_PTR(ret);
+}
+
+static void trace_remote_iter_free(struct trace_remote_iterator *iter)
+{
+	struct trace_remote *remote;
+
+	if (!iter)
+		return;
+
+	remote = iter->remote;
+
+	lockdep_assert_held(&remote->lock);
+
+	kfree(iter);
+	trace_remote_put(remote);
+}
+
+static bool trace_remote_iter_read_event(struct trace_remote_iterator *iter)
+{
+	struct trace_buffer *trace_buffer = iter->remote->trace_buffer;
+	int cpu = iter->cpu;
+
+	if (cpu != RING_BUFFER_ALL_CPUS) {
+		if (ring_buffer_empty_cpu(trace_buffer, cpu))
+			return false;
+
+		if (!ring_buffer_peek(trace_buffer, cpu, &iter->ts, &iter->lost_events))
+			return false;
+
+		iter->evt_cpu = cpu;
+		return true;
+	}
+
+	iter->ts = U64_MAX;
+	for_each_possible_cpu(cpu) {
+		unsigned long lost_events;
+		u64 ts;
+
+		if (ring_buffer_empty_cpu(trace_buffer, cpu))
+			continue;
+
+		if (!ring_buffer_peek(trace_buffer, cpu, &ts, &lost_events))
+			continue;
+
+		if (ts >= iter->ts)
+			continue;
+
+		iter->ts = ts;
+		iter->evt_cpu = cpu;
+		iter->lost_events = lost_events;
+	}
+
+	return iter->ts != U64_MAX;
+}
+
+static int trace_remote_iter_print(struct trace_remote_iterator *iter)
+{
+	unsigned long usecs_rem;
+	u64 ts = iter->ts;
+
+	if (iter->lost_events)
+		trace_seq_printf(&iter->seq, "CPU:%d [LOST %lu EVENTS]\n",
+				 iter->evt_cpu, iter->lost_events);
+
+	do_div(ts, 1000);
+	usecs_rem = do_div(ts, USEC_PER_SEC);
+
+	trace_seq_printf(&iter->seq, "[%03d]\t%5llu.%06lu: ", iter->evt_cpu,
+			 ts, usecs_rem);
+
+	return trace_seq_has_overflowed(&iter->seq) ? -EOVERFLOW : 0;
+}
+
+static int trace_pipe_open(struct inode *inode, struct file *filp)
+{
+	struct trace_remote *remote = inode->i_private;
+	struct trace_remote_iterator *iter;
+	int cpu = RING_BUFFER_ALL_CPUS;
+
+	if (inode->i_cdev)
+		cpu = (long)inode->i_cdev - 1;
+
+	guard(mutex)(&remote->lock);
+	iter = trace_remote_iter(remote, cpu);
+	filp->private_data = iter;
+
+	return IS_ERR(iter) ? PTR_ERR(iter) : 0;
+}
+
+static int trace_pipe_release(struct inode *inode, struct file *filp)
+{
+	struct trace_remote_iterator *iter = filp->private_data;
+	struct trace_remote *remote = iter->remote;
+
+	guard(mutex)(&remote->lock);
+
+	trace_remote_iter_free(iter);
+
+	return 0;
+}
+
+static ssize_t trace_pipe_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	struct trace_remote_iterator *iter = filp->private_data;
+	struct trace_buffer *trace_buffer = iter->remote->trace_buffer;
+	int ret;
+
+copy_to_user:
+	ret = trace_seq_to_user(&iter->seq, ubuf, cnt);
+	if (ret != -EBUSY)
+		return ret;
+
+	trace_seq_init(&iter->seq);
+
+	ret = ring_buffer_wait(trace_buffer, iter->cpu, 0, NULL, NULL);
+	if (ret < 0)
+		return ret;
+
+	while (trace_remote_iter_read_event(iter)) {
+		int prev_len = iter->seq.seq.len;
+
+		if (trace_remote_iter_print_event(iter)) {
+			iter->seq.seq.len = prev_len;
+			break;
+		}
+
+		ring_buffer_consume(trace_buffer, iter->evt_cpu, NULL, NULL);
+	}
+
+	goto copy_to_user;
+}
+
+static const struct file_operations trace_pipe_fops = {
+	.open		= trace_pipe_open,
+	.read		= trace_pipe_read,
+	.release	= trace_pipe_release,
+};
+
+static int trace_remote_init_tracefs(const char *name, struct trace_remote *remote)
+{
+	struct dentry *remote_d, *percpu_d;
+	static struct dentry *root;
+	static DEFINE_MUTEX(lock);
+	bool root_inited = false;
+	int cpu;
+
+	guard(mutex)(&lock);
+
+	if (!root) {
+		root = tracefs_create_dir(TRACEFS_DIR, NULL);
+		if (!root) {
+			pr_err("Failed to create tracefs dir "TRACEFS_DIR"\n");
+			return -ENOMEM;
+		}
+		root_inited = true;
+	}
+
+	remote_d = tracefs_create_dir(name, root);
+	if (!remote_d) {
+		pr_err("Failed to create tracefs dir "TRACEFS_DIR"%s/\n", name);
+		goto err;
+	}
+
+	if (!trace_create_file("tracing_on", TRACEFS_MODE_WRITE, remote_d, remote,
+			       &tracing_on_fops) ||
+	    !trace_create_file("buffer_size_kb", TRACEFS_MODE_WRITE, remote_d, remote,
+			       &buffer_size_kb_fops) ||
+	    !trace_create_file("trace_pipe", TRACEFS_MODE_READ, remote_d, remote,
+			       &trace_pipe_fops))
+		goto err;
+
+	percpu_d = tracefs_create_dir("per_cpu", remote_d);
+	if (!percpu_d) {
+		pr_err("Failed to create tracefs dir "TRACEFS_DIR"%s/per_cpu/\n", name);
+		goto err;
+	}
+
+	for_each_possible_cpu(cpu) {
+		struct dentry *cpu_d;
+		char cpu_name[16];
+
+		snprintf(cpu_name, sizeof(cpu_name), "cpu%d", cpu);
+		cpu_d = tracefs_create_dir(cpu_name, percpu_d);
+		if (!cpu_d) {
+			pr_err("Failed to create tracefs dir "TRACEFS_DIR"%s/percpu/cpu%d\n",
+			       name, cpu);
+			goto err;
+		}
+
+		if (!trace_create_cpu_file("trace_pipe", TRACEFS_MODE_READ, cpu_d, remote, cpu,
+					   &trace_pipe_fops))
+			goto err;
+	}
+
+	return 0;
+
+err:
+	if (root_inited) {
+		tracefs_remove(root);
+		root = NULL;
+	} else {
+		tracefs_remove(remote_d);
+	}
+
+	return -ENOMEM;
+}
+
+int trace_remote_register(const char *name, struct trace_remote_callbacks *cbs, void *priv)
+{
+	struct trace_remote *remote;
+
+	remote = kzalloc(sizeof(*remote), GFP_KERNEL);
+	if (!remote)
+		return -ENOMEM;
+
+	remote->cbs = cbs;
+	remote->priv = priv;
+	remote->trace_buffer_size = 7 << 10;
+	remote->poll_ms = 100;
+	mutex_init(&remote->lock);
+
+	if (trace_remote_init_tracefs(name, remote)) {
+		kfree(remote);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(trace_remote_register);
+
+void trace_remote_free_buffer(struct trace_buffer_desc *desc)
+{
+	struct ring_buffer_desc *rb_desc;
+	int cpu;
+
+	for_each_ring_buffer_desc(rb_desc, cpu, desc) {
+		unsigned int id;
+
+		free_page(rb_desc->meta_va);
+
+		for (id = 0; id < rb_desc->nr_page_va; id++)
+			free_page(rb_desc->page_va[id]);
+	}
+}
+EXPORT_SYMBOL_GPL(trace_remote_free_buffer);
+
+int trace_remote_alloc_buffer(struct trace_buffer_desc *desc, size_t desc_size, size_t buffer_size,
+			      const struct cpumask *cpumask)
+{
+	unsigned int nr_pages = max(DIV_ROUND_UP(buffer_size, PAGE_SIZE), 2UL) + 1;
+	void *desc_end = desc + desc_size;
+	struct ring_buffer_desc *rb_desc;
+	int cpu, ret = -ENOMEM;
+
+	if (desc_size < struct_size(desc, __data, 0))
+		return -EINVAL;
+
+	desc->nr_cpus = 0;
+	desc->struct_len = struct_size(desc, __data, 0);
+
+	rb_desc = (struct ring_buffer_desc *)&desc->__data[0];
+
+	for_each_cpu(cpu, cpumask) {
+		unsigned int id;
+
+		if ((void *)rb_desc + struct_size(rb_desc, page_va, nr_pages) > desc_end) {
+			ret = -EINVAL;
+			goto err;
+		}
+
+		rb_desc->cpu = cpu;
+		rb_desc->nr_page_va = 0;
+		rb_desc->meta_va = (unsigned long)__get_free_page(GFP_KERNEL);
+		if (!rb_desc->meta_va)
+			goto err;
+
+		for (id = 0; id < nr_pages; id++) {
+			rb_desc->page_va[id] = (unsigned long)__get_free_page(GFP_KERNEL);
+			if (!rb_desc->page_va[id])
+				goto err;
+
+			rb_desc->nr_page_va++;
+		}
+		desc->nr_cpus++;
+		desc->struct_len += offsetof(struct ring_buffer_desc, page_va);
+		desc->struct_len += struct_size(rb_desc, page_va, rb_desc->nr_page_va);
+		rb_desc = __next_ring_buffer_desc(rb_desc);
+	}
+
+	return 0;
+
+err:
+	trace_remote_free_buffer(desc);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(trace_remote_alloc_buffer);
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:36:00 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:36:00 +0000
Subject: [PATCH v9 07/30] tracing: Add non-consuming read to trace remotes
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-8-vdonnefort@google.com>

Allow reading the trace file for trace remotes. This performs a
non-consuming read of the trace buffer.

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/kernel/trace/trace_remote.c b/kernel/trace/trace_remote.c
index 49c4ae127533..a744bbf48e88 100644
--- a/kernel/trace/trace_remote.c
+++ b/kernel/trace/trace_remote.c
@@ -18,14 +18,25 @@
 #define TRACEFS_MODE_WRITE	0640
 #define TRACEFS_MODE_READ	0440
 
+enum tri_type {
+	TRI_CONSUMING,
+	TRI_NONCONSUMING,
+};
+
 struct trace_remote_iterator {
 	struct trace_remote		*remote;
 	struct trace_seq		seq;
 	struct delayed_work		poll_work;
 	unsigned long			lost_events;
 	u64				ts;
+	union {
+		struct ring_buffer_iter	**rb_iters;
+		struct ring_buffer_iter *rb_iter;
+	};
 	int				cpu;
 	int				evt_cpu;
+	loff_t				pos;
+	enum tri_type			type;
 };
 
 struct trace_remote {
@@ -36,6 +47,8 @@ struct trace_remote {
 	unsigned long			trace_buffer_size;
 	struct ring_buffer_remote	rb_remote;
 	struct mutex			lock;
+	struct rw_semaphore		reader_lock;
+	struct rw_semaphore		*pcpu_reader_locks;
 	unsigned int			nr_readers;
 	unsigned int			poll_ms;
 	bool				tracing_on;
@@ -225,6 +238,20 @@ static int trace_remote_get(struct trace_remote *remote, int cpu)
 	if (ret)
 		return ret;
 
+	if (cpu != RING_BUFFER_ALL_CPUS && !remote->pcpu_reader_locks) {
+		int lock_cpu;
+
+		remote->pcpu_reader_locks = kcalloc(nr_cpu_ids, sizeof(*remote->pcpu_reader_locks),
+						    GFP_KERNEL);
+		if (!remote->pcpu_reader_locks) {
+			trace_remote_try_unload(remote);
+			return -ENOMEM;
+		}
+
+		for_each_possible_cpu(lock_cpu)
+			init_rwsem(&remote->pcpu_reader_locks[lock_cpu]);
+	}
+
 	remote->nr_readers++;
 
 	return 0;
@@ -239,6 +266,9 @@ static void trace_remote_put(struct trace_remote *remote)
 	if (remote->nr_readers)
 		return;
 
+	kfree(remote->pcpu_reader_locks);
+	remote->pcpu_reader_locks = NULL;
+
 	trace_remote_try_unload(remote);
 }
 
@@ -253,6 +283,48 @@ static void __poll_remote(struct work_struct *work)
 			      msecs_to_jiffies(iter->remote->poll_ms));
 }
 
+static int __alloc_ring_buffer_iter(struct trace_remote_iterator *iter, int cpu)
+{
+	bool once = false;
+
+	if (cpu != RING_BUFFER_ALL_CPUS) {
+		iter->rb_iter = ring_buffer_read_start(iter->remote->trace_buffer, cpu, GFP_KERNEL);
+
+		return iter->rb_iter ? 0 : -ENOMEM;
+	}
+
+	iter->rb_iters = kcalloc(nr_cpu_ids, sizeof(*iter->rb_iters), GFP_KERNEL);
+	if (!iter->rb_iters)
+		return -ENOMEM;
+
+	for_each_possible_cpu(cpu) {
+		iter->rb_iters[cpu] = ring_buffer_read_start(iter->remote->trace_buffer, cpu,
+							     GFP_KERNEL);
+		if (iter->rb_iters[cpu])
+			once = true;
+	}
+
+	return once ? 0 : -ENOMEM;
+}
+
+static void __free_ring_buffer_iter(struct trace_remote_iterator *iter, int cpu)
+{
+	if (!iter->rb_iter)
+		return;
+
+	if (cpu != RING_BUFFER_ALL_CPUS) {
+		ring_buffer_read_finish(iter->rb_iter);
+		return;
+	}
+
+	for_each_possible_cpu(cpu) {
+		if (iter->rb_iters[cpu])
+			ring_buffer_read_finish(iter->rb_iters[cpu]);
+	}
+
+	kfree(iter->rb_iters);
+}
+
 static struct trace_remote_iterator
 *trace_remote_iter(struct trace_remote *remote, int cpu, enum tri_type type)
 {
@@ -261,6 +333,8 @@ static struct trace_remote_iterator
 
 	lockdep_assert_held(&remote->lock);
 
+	if (type == TRI_NONCONSUMING && !trace_remote_loaded(remote))
+		return NULL;
 
 	ret = trace_remote_get(remote, cpu);
 	if (ret)
@@ -275,9 +349,21 @@ static struct trace_remote_iterator
 	if (iter) {
 		iter->remote = remote;
 		iter->cpu = cpu;
+		iter->type = type;
 		trace_seq_init(&iter->seq);
-		INIT_DELAYED_WORK(&iter->poll_work, __poll_remote);
-		schedule_delayed_work(&iter->poll_work, msecs_to_jiffies(remote->poll_ms));
+
+		switch (type) {
+		case TRI_CONSUMING:
+			INIT_DELAYED_WORK(&iter->poll_work, __poll_remote);
+			schedule_delayed_work(&iter->poll_work, msecs_to_jiffies(remote->poll_ms));
+			break;
+		case TRI_NONCONSUMING:
+			ret = __alloc_ring_buffer_iter(iter, cpu);
+			break;
+		}
+
+		if (ret)
+			goto err;
 
 		return iter;
 	}
@@ -301,10 +387,100 @@ static void trace_remote_iter_free(struct trace_remote_iterator *iter)
 
 	lockdep_assert_held(&remote->lock);
 
+	switch (iter->type) {
+	case TRI_CONSUMING:
+		cancel_delayed_work_sync(&iter->poll_work);
+		break;
+	case TRI_NONCONSUMING:
+		__free_ring_buffer_iter(iter, iter->cpu);
+		break;
+	}
+
 	kfree(iter);
 	trace_remote_put(remote);
 }
 
+static void trace_remote_iter_read_start(struct trace_remote_iterator *iter)
+{
+	struct trace_remote *remote = iter->remote;
+	int cpu = iter->cpu;
+
+	/* Acquire global reader lock */
+	if (cpu == RING_BUFFER_ALL_CPUS && iter->type == TRI_CONSUMING)
+		down_write(&remote->reader_lock);
+	else
+		down_read(&remote->reader_lock);
+
+	if (cpu == RING_BUFFER_ALL_CPUS)
+		return;
+
+	/*
+	 * No need for the remote lock here, iter holds a reference on
+	 * remote->nr_readers
+	 */
+
+	/* Get the per-CPU one */
+	if (WARN_ON_ONCE(!remote->pcpu_reader_locks))
+		return;
+
+	if (iter->type == TRI_CONSUMING)
+		down_write(&remote->pcpu_reader_locks[cpu]);
+	else
+		down_read(&remote->pcpu_reader_locks[cpu]);
+}
+
+static void trace_remote_iter_read_finished(struct trace_remote_iterator *iter)
+{
+	struct trace_remote *remote = iter->remote;
+	int cpu = iter->cpu;
+
+	/* Release per-CPU reader lock */
+	if (cpu != RING_BUFFER_ALL_CPUS) {
+		/*
+		 * No need for the remote lock here, iter holds a reference on
+		 * remote->nr_readers
+		 */
+		if (iter->type == TRI_CONSUMING)
+			up_write(&remote->pcpu_reader_locks[cpu]);
+		else
+			up_read(&remote->pcpu_reader_locks[cpu]);
+	}
+
+	/* Release global reader lock */
+	if (cpu == RING_BUFFER_ALL_CPUS && iter->type == TRI_CONSUMING)
+		up_write(&remote->reader_lock);
+	else
+		up_read(&remote->reader_lock);
+}
+
+static struct ring_buffer_iter *__get_rb_iter(struct trace_remote_iterator *iter, int cpu)
+{
+	return iter->cpu != RING_BUFFER_ALL_CPUS ? iter->rb_iter : iter->rb_iters[cpu];
+}
+
+static struct ring_buffer_event *
+__peek_event(struct trace_remote_iterator *iter, int cpu, u64 *ts, unsigned long *lost_events)
+{
+	struct ring_buffer_event *rb_evt;
+	struct ring_buffer_iter *rb_iter;
+
+	switch (iter->type) {
+	case TRI_CONSUMING:
+		return ring_buffer_peek(iter->remote->trace_buffer, cpu, ts, lost_events);
+	case TRI_NONCONSUMING:
+		rb_iter = __get_rb_iter(iter, cpu);
+		rb_evt = ring_buffer_iter_peek(rb_iter, ts);
+		if (!rb_evt)
+			return NULL;
+
+		*lost_events = ring_buffer_iter_dropped(rb_iter);
+
+		return rb_evt;
+	}
+
+	return NULL;
+}
+
 static bool trace_remote_iter_read_event(struct trace_remote_iterator *iter)
 {
 	struct trace_buffer *trace_buffer = iter->remote->trace_buffer;
@@ -314,7 +490,7 @@ static bool trace_remote_iter_read_event(struct trace_remote_iterator *iter)
 		if (ring_buffer_empty_cpu(trace_buffer, cpu))
 			return false;
 
-		if (!ring_buffer_peek(trace_buffer, cpu, &iter->ts, &iter->lost_events))
+		if (!__peek_event(iter, cpu, &iter->ts, &iter->lost_events))
 			return false;
 
 		iter->evt_cpu = cpu;
@@ -329,7 +505,7 @@ static bool trace_remote_iter_read_event(struct trace_remote_iterator *iter)
 		if (ring_buffer_empty_cpu(trace_buffer, cpu))
 			continue;
 
-		if (!ring_buffer_peek(trace_buffer, cpu, &ts, &lost_events))
+		if (!__peek_event(iter, cpu, &ts, &lost_events))
 			continue;
 
 		if (ts >= iter->ts)
@@ -343,7 +519,21 @@ static bool trace_remote_iter_read_event(struct trace_remote_iterator *iter)
 	return iter->ts != U64_MAX;
 }
 
-static int trace_remote_iter_print(struct trace_remote_iterator *iter)
+static void trace_remote_iter_move(struct trace_remote_iterator *iter)
+{
+	struct trace_buffer *trace_buffer = iter->remote->trace_buffer;
+
+	switch (iter->type) {
+	case TRI_CONSUMING:
+		ring_buffer_consume(trace_buffer, iter->evt_cpu, NULL, NULL);
+		break;
+	case TRI_NONCONSUMING:
+		ring_buffer_iter_advance(__get_rb_iter(iter, iter->evt_cpu));
+		break;
+	}
+}
+
+static int trace_remote_iter_print_event(struct trace_remote_iterator *iter)
 {
 	unsigned long usecs_rem;
 	u64 ts = iter->ts;
@@ -371,7 +561,11 @@ static int trace_pipe_open(struct inode *inode, struct file *filp)
 		cpu = (long)inode->i_cdev - 1;
 
 	guard(mutex)(&remote->lock);
-	iter = trace_remote_iter(remote, cpu);
+
+	iter = trace_remote_iter(remote, cpu, TRI_CONSUMING);
+	if (IS_ERR(iter))
+		return PTR_ERR(iter);
+
 	filp->private_data = iter;
 
 	return IS_ERR(iter) ? PTR_ERR(iter) : 0;
@@ -406,6 +600,8 @@ static ssize_t trace_pipe_read(struct file *filp, char __user *ubuf, size_t cnt,
 	if (ret < 0)
 		return ret;
 
+	trace_remote_iter_read_start(iter);
+
 	while (trace_remote_iter_read_event(iter)) {
 		int prev_len = iter->seq.seq.len;
 
@@ -414,9 +610,11 @@ static ssize_t trace_pipe_read(struct file *filp, char __user *ubuf, size_t cnt,
 			break;
 		}
 
-		ring_buffer_consume(trace_buffer, iter->evt_cpu, NULL, NULL);
+		trace_remote_iter_move(iter);
 	}
 
+	trace_remote_iter_read_finished(iter);
+
 	goto copy_to_user;
 }
 
@@ -426,6 +624,119 @@ static const struct file_operations trace_pipe_fops = {
 	.release	= trace_pipe_release,
 };
 
+static void *trace_seq_start(struct seq_file *m, loff_t *pos)
+{
+	struct trace_remote_iterator *iter = m->private;
+	loff_t i = *pos;
+
+	if (!iter)
+		return NULL;
+
+	if (iter->pos <= *pos) {
+		do {
+			if (!trace_remote_iter_read_event(iter))
+				return NULL;
+
+			trace_remote_iter_move(iter);
+			iter->pos++;
+		} while (i--);
+	}
+
+	return iter;
+}
+
+static void *trace_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	struct trace_remote_iterator *iter = m->private;
+
+	++*pos;
+
+	if (!iter || !trace_remote_iter_read_event(iter))
+		return NULL;
+
+	trace_remote_iter_move(iter);
+	iter->pos++;
+
+	return iter;
+}
+
+static int trace_seq_show(struct seq_file *m, void *v)
+{
+	struct trace_remote_iterator *iter = v;
+
+	trace_seq_init(&iter->seq);
+
+	if (trace_remote_iter_print_event(iter)) {
+		seq_printf(m, "[EVENT %d PRINT TOO BIG]\n", iter->evt->id);
+		return 0;
+	}
+
+	return trace_print_seq(m, &iter->seq);
+}
+
+static void trace_seq_stop(struct seq_file *s, void *v) { }
+
+static const struct seq_operations trace_seq_ops = {
+	.start		= trace_seq_start,
+	.next		= trace_seq_next,
+	.show		= trace_seq_show,
+	.stop		= trace_seq_stop,
+};
+
+static int trace_open(struct inode *inode, struct file *filp)
+{
+	struct trace_remote *remote = inode->i_private;
+	struct trace_remote_iterator *iter = NULL;
+	int cpu = RING_BUFFER_ALL_CPUS;
+	int ret;
+
+	if (!(filp->f_mode & FMODE_READ))
+		return 0;
+
+	if (inode->i_cdev)
+		cpu = (long)inode->i_cdev - 1;
+
+	guard(mutex)(&remote->lock);
+
+	iter = trace_remote_iter(remote, cpu, TRI_NONCONSUMING);
+	if (IS_ERR(iter))
+		return PTR_ERR(iter);
+
+	ret = seq_open(filp, &trace_seq_ops);
+	if (ret) {
+		trace_remote_iter_free(iter);
+		return ret;
+	}
+
+	if (iter)
+		trace_remote_iter_read_start(iter);
+
+	((struct seq_file *)filp->private_data)->private = (void *)iter;
+
+	return 0;
+}
+
+static int trace_release(struct inode *inode, struct file *filp)
+{
+	struct trace_remote_iterator *iter;
+
+	if (!(filp->f_mode & FMODE_READ))
+		return 0;
+
+	iter = ((struct seq_file *)filp->private_data)->private;
+	seq_release(inode, filp);
+
+	if (!iter)
+		return 0;
+
+	guard(mutex)(&iter->remote->lock);
+
+	trace_remote_iter_read_finished(iter);
+	trace_remote_iter_free(iter);
+
+	return 0;
+}
+
 static ssize_t trace_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos)
 {
 	struct inode *inode = file_inode(filp);
@@ -443,7 +754,11 @@ static ssize_t trace_write(struct file *filp, const char __user *ubuf, size_t cn
 }
 
 static const struct file_operations trace_fops = {
+	.open		= trace_open,
 	.write		= trace_write,
+	.read		= seq_read,
+	.read_iter	= seq_read_iter,
+	.release	= trace_release,
 };
 
 static int trace_remote_init_tracefs(const char *name, struct trace_remote *remote)
@@ -532,6 +847,7 @@ int trace_remote_register(const char *name, struct trace_remote_callbacks *cbs,
 	remote->trace_buffer_size = 7 << 10;
 	remote->poll_ms = 100;
 	mutex_init(&remote->lock);
+	init_rwsem(&remote->reader_lock);
 
 	if (trace_remote_init_tracefs(name, remote)) {
 		kfree(remote);
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:36:01 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:36:01 +0000
Subject: [PATCH v9 08/30] tracing: Add init callback to trace remotes
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-9-vdonnefort@google.com>

Add a .init call back so the trace remote callers can add entries to the
tracefs directory.

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/include/linux/trace_remote.h b/include/linux/trace_remote.h
index 55754ef78104..15a579633123 100644
--- a/include/linux/trace_remote.h
+++ b/include/linux/trace_remote.h
@@ -3,11 +3,14 @@
 #ifndef _LINUX_TRACE_REMOTE_H
 #define _LINUX_TRACE_REMOTE_H
 
+#include <linux/dcache.h>
 #include <linux/ring_buffer.h>
 
 /**
  * struct trace_remote_callbacks - Callbacks used by Tracefs to control the remote
  *
+ * @init:		Called once the remote has been registered. Allows the
+ *			caller to extend the Tracefs remote directory
  * @load_trace_buffer:  Called before Tracefs accesses the trace buffer for the first
  *			time. Must return a &trace_buffer_desc
  *			(most likely filled with trace_remote_alloc_buffer())
@@ -23,6 +26,7 @@
  *			new reader-page from the @cpu ring-buffer.
  */
 struct trace_remote_callbacks {
+	int	(*init)(struct dentry *d, void *priv);
 	struct trace_buffer_desc *(*load_trace_buffer)(unsigned long size, void *priv);
 	void	(*unload_trace_buffer)(struct trace_buffer_desc *desc, void *priv);
 	int	(*enable_tracing)(bool enable, void *priv);
diff --git a/kernel/trace/trace_remote.c b/kernel/trace/trace_remote.c
index a744bbf48e88..924e3f3ec6d2 100644
--- a/kernel/trace/trace_remote.c
+++ b/kernel/trace/trace_remote.c
@@ -837,6 +837,7 @@ static int trace_remote_init_tracefs(const char *name, struct trace_remote *remo
 int trace_remote_register(const char *name, struct trace_remote_callbacks *cbs, void *priv)
 {
 	struct trace_remote *remote;
+	int ret;
 
 	remote = kzalloc(sizeof(*remote), GFP_KERNEL);
 	if (!remote)
@@ -854,7 +855,11 @@ int trace_remote_register(const char *name, struct trace_remote_callbacks *cbs,
 		return -ENOMEM;
 	}
 
-	return 0;
+	ret = cbs->init ? cbs->init(remote->dentry, priv) : 0;
+	if (ret)
+		pr_err("Init failed for trace remote '%s' (%d)\n", name, ret);
+
+	return ret;
 }
 EXPORT_SYMBOL_GPL(trace_remote_register);
 
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:36:02 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:36:02 +0000
Subject: [PATCH v9 09/30] tracing: Add events to trace remotes
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-10-vdonnefort@google.com>

An event is predefined point in the writer code that allows to log
data. Following the same scheme as kernel events, add remote events,
described to user-space within the events/ tracefs directory found in
the corresponding trace remote.

Remote events are expected to be described during the trace remote
registration.

Add also a .enable_event callback for trace_remote to toggle the event
logging, if supported.

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/include/linux/trace_remote.h b/include/linux/trace_remote.h
index 15a579633123..456df837fc6b 100644
--- a/include/linux/trace_remote.h
+++ b/include/linux/trace_remote.h
@@ -5,6 +5,7 @@
 
 #include <linux/dcache.h>
 #include <linux/ring_buffer.h>
+#include <linux/trace_remote_event.h>
 
 /**
  * struct trace_remote_callbacks - Callbacks used by Tracefs to control the remote
@@ -24,6 +25,8 @@
  * @reset:		Called on `echo 0 > trace`. It is expected from the
  *			remote to reset all ring-buffer pages.
  *			new reader-page from the @cpu ring-buffer.
+ * @enable_event:	Called on events/event_name/enable. It is expected from
+ *			the remote to allow the writing event @id.
  */
 struct trace_remote_callbacks {
 	int	(*init)(struct dentry *d, void *priv);
@@ -32,6 +35,7 @@ struct trace_remote_callbacks {
 	int	(*enable_tracing)(bool enable, void *priv);
 	int	(*swap_reader_page)(unsigned int cpu, void *priv);
 	int	(*reset)(unsigned int cpu, void *priv);
+	int	(*enable_event)(unsigned short id, bool enable, void *priv);
 };
 
 /**
@@ -53,7 +57,8 @@ struct trace_remote_callbacks {
  *
  * Return: 0 on success, negative error code on failure.
  */
-int trace_remote_register(const char *name, struct trace_remote_callbacks *cbs, void *priv);
+int trace_remote_register(const char *name, struct trace_remote_callbacks *cbs, void *priv,
+			  struct remote_event *events, size_t nr_events);
 
 /**
  * trace_remote_alloc_buffer() - Dynamically allocate a trace buffer
diff --git a/include/linux/trace_remote_event.h b/include/linux/trace_remote_event.h
new file mode 100644
index 000000000000..a4449008a075
--- /dev/null
+++ b/include/linux/trace_remote_event.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _LINUX_TRACE_REMOTE_EVENTS_H
+#define _LINUX_TRACE_REMOTE_EVENTS_H
+
+struct trace_remote;
+struct trace_event_fields;
+
+struct remote_event_hdr {
+	unsigned short	id;
+};
+
+#define REMOTE_EVENT_NAME_MAX 30
+struct remote_event {
+	char				name[REMOTE_EVENT_NAME_MAX];
+	unsigned short			id;
+	bool				enabled;
+	struct trace_remote		*remote;
+	struct trace_event_fields	*fields;
+	char				*print_fmt;
+	void				(*print)(void *evt, struct trace_seq *seq);
+};
+#endif
diff --git a/kernel/trace/trace_remote.c b/kernel/trace/trace_remote.c
index 924e3f3ec6d2..8527804f2d22 100644
--- a/kernel/trace/trace_remote.c
+++ b/kernel/trace/trace_remote.c
@@ -33,6 +33,7 @@ struct trace_remote_iterator {
 		struct ring_buffer_iter	**rb_iters;
 		struct ring_buffer_iter *rb_iter;
 	};
+	struct remote_event_hdr		*evt;
 	int				cpu;
 	int				evt_cpu;
 	loff_t				pos;
@@ -44,6 +45,10 @@ struct trace_remote {
 	void				*priv;
 	struct trace_buffer		*trace_buffer;
 	struct trace_buffer_desc	*trace_buffer_desc;
+	struct dentry			*dentry;
+	struct eventfs_inode		*eventfs;
+	struct remote_event		*events;
+	unsigned long			nr_events;
 	unsigned long			trace_buffer_size;
 	struct ring_buffer_remote	rb_remote;
 	struct mutex			lock;
@@ -168,7 +173,8 @@ static void trace_remote_reset(struct trace_remote *remote, int cpu)
 static ssize_t
 tracing_on_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos)
 {
-	struct trace_remote *remote = filp->private_data;
+	struct seq_file *seq = filp->private_data;
+	struct trace_remote *remote = seq->private;
 	unsigned long val;
 	int ret;
 
@@ -197,7 +203,8 @@ DEFINE_SHOW_STORE_ATTRIBUTE(tracing_on);
 static ssize_t buffer_size_kb_write(struct file *filp, const char __user *ubuf, size_t cnt,
 				    loff_t *ppos)
 {
-	struct trace_remote *remote = filp->private_data;
+	struct seq_file *seq = filp->private_data;
+	struct trace_remote *remote = seq->private;
 	unsigned long val;
 	int ret;
 
@@ -484,16 +491,19 @@ __peek_event(struct trace_remote_iterator *iter, int cpu, u64 *ts, unsigned long
 static bool trace_remote_iter_read_event(struct trace_remote_iterator *iter)
 {
 	struct trace_buffer *trace_buffer = iter->remote->trace_buffer;
+	struct ring_buffer_event *rb_evt;
 	int cpu = iter->cpu;
 
 	if (cpu != RING_BUFFER_ALL_CPUS) {
 		if (ring_buffer_empty_cpu(trace_buffer, cpu))
 			return false;
 
-		if (!__peek_event(iter, cpu, &iter->ts, &iter->lost_events))
+		rb_evt = __peek_event(iter, cpu, &iter->ts, &iter->lost_events);
+		if (!rb_evt)
 			return false;
 
 		iter->evt_cpu = cpu;
+		iter->evt = (struct remote_event_hdr *)ring_buffer_event_data(rb_evt);
 		return true;
 	}
 
@@ -505,7 +515,8 @@ static bool trace_remote_iter_read_event(struct trace_remote_iterator *iter)
 		if (ring_buffer_empty_cpu(trace_buffer, cpu))
 			continue;
 
-		if (!__peek_event(iter, cpu, &ts, &lost_events))
+		rb_evt = __peek_event(iter, cpu, &ts, &lost_events);
+		if (!rb_evt)
 			continue;
 
 		if (ts >= iter->ts)
@@ -513,6 +524,7 @@ static bool trace_remote_iter_read_event(struct trace_remote_iterator *iter)
 
 		iter->ts = ts;
 		iter->evt_cpu = cpu;
+		iter->evt = (struct remote_event_hdr *)ring_buffer_event_data(rb_evt);
 		iter->lost_events = lost_events;
 	}
 
@@ -533,8 +545,11 @@ static void trace_remote_iter_move(struct trace_remote_iterator *iter)
 	}
 }
 
+static struct remote_event *trace_remote_find_event(struct trace_remote *remote, unsigned short id);
+
 static int trace_remote_iter_print_event(struct trace_remote_iterator *iter)
 {
+	struct remote_event *evt;
 	unsigned long usecs_rem;
 	u64 ts = iter->ts;
 
@@ -548,6 +563,12 @@ static int trace_remote_iter_print_event(struct trace_remote_iterator *iter)
 	trace_seq_printf(&iter->seq, "[%03d]\t%5llu.%06lu: ", iter->evt_cpu,
 			 ts, usecs_rem);
 
+	evt = trace_remote_find_event(iter->remote, iter->evt->id);
+	if (!evt)
+		trace_seq_printf(&iter->seq, "UNKNOWN id=%d\n", iter->evt->id);
+	else
+		evt->print(iter->evt, &iter->seq);
+
 	return trace_seq_has_overflowed(&iter->seq) ? -EOVERFLOW : 0;
 }
 
@@ -821,6 +842,8 @@ static int trace_remote_init_tracefs(const char *name, struct trace_remote *remo
 			goto err;
 	}
 
+	remote->dentry = remote_d;
+
 	return 0;
 
 err:
@@ -834,7 +857,11 @@ static int trace_remote_init_tracefs(const char *name, struct trace_remote *remo
 	return -ENOMEM;
 }
 
-int trace_remote_register(const char *name, struct trace_remote_callbacks *cbs, void *priv)
+static int trace_remote_register_events(const char *remote_name, struct trace_remote *remote,
+					struct remote_event *events, size_t nr_events);
+
+int trace_remote_register(const char *name, struct trace_remote_callbacks *cbs, void *priv,
+			  struct remote_event *events, size_t nr_events)
 {
 	struct trace_remote *remote;
 	int ret;
@@ -855,6 +882,13 @@ int trace_remote_register(const char *name, struct trace_remote_callbacks *cbs,
 		return -ENOMEM;
 	}
 
+	ret = trace_remote_register_events(name, remote, events, nr_events);
+	if (ret) {
+		pr_err("Failed to register events for trace remote '%s' (%d)\n",
+		       name, ret);
+		return ret;
+	}
+
 	ret = cbs->init ? cbs->init(remote->dentry, priv) : 0;
 	if (ret)
 		pr_err("Init failed for trace remote '%s' (%d)\n", name, ret);
@@ -929,3 +963,220 @@ int trace_remote_alloc_buffer(struct trace_buffer_desc *desc, size_t desc_size,
 	return ret;
 }
 EXPORT_SYMBOL_GPL(trace_remote_alloc_buffer);
+
+static int
+trace_remote_enable_event(struct trace_remote *remote, struct remote_event *evt, bool enable)
+{
+	int ret;
+
+	lockdep_assert_held(&remote->lock);
+
+	if (evt->enabled == enable)
+		return 0;
+
+	ret = remote->cbs->enable_event(evt->id, enable, remote->priv);
+	if (ret)
+		return ret;
+
+	evt->enabled = enable;
+
+	return 0;
+}
+
+static int remote_event_enable_show(struct seq_file *s, void *unused)
+{
+	struct remote_event *evt = s->private;
+
+	seq_printf(s, "%d\n", evt->enabled);
+
+	return 0;
+}
+
+static ssize_t remote_event_enable_write(struct file *filp, const char __user *ubuf,
+					 size_t count, loff_t *ppos)
+{
+	struct seq_file *seq = filp->private_data;
+	struct remote_event *evt = seq->private;
+	struct trace_remote *remote = evt->remote;
+	u8 enable;
+	int ret;
+
+	ret = kstrtou8_from_user(ubuf, count, 10, &enable);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&remote->lock);
+
+	ret = trace_remote_enable_event(remote, evt, enable);
+	if (ret)
+		return ret;
+
+	return count;
+}
+DEFINE_SHOW_STORE_ATTRIBUTE(remote_event_enable);
+
+static int remote_event_id_show(struct seq_file *s, void *unused)
+{
+	struct remote_event *evt = s->private;
+
+	seq_printf(s, "%d\n", evt->id);
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(remote_event_id);
+
+static int remote_event_format_show(struct seq_file *s, void *unused)
+{
+	size_t offset = sizeof(struct remote_event_hdr);
+	struct remote_event *evt = s->private;
+	struct trace_event_fields *field;
+
+	seq_printf(s, "name: %s\n", evt->name);
+	seq_printf(s, "ID: %d\n", evt->id);
+	seq_puts(s,
+		 "format:\n\tfield:unsigned short common_type;\toffset:0;\tsize:2;\tsigned:0;\n\n");
+
+	field = &evt->fields[0];
+	while (field->name) {
+		seq_printf(s, "\tfield:%s %s;\toffset:%zu;\tsize:%u;\tsigned:%d;\n",
+			   field->type, field->name, offset, field->size,
+			   field->is_signed);
+		offset += field->size;
+		field++;
+	}
+
+	if (field != &evt->fields[0])
+		seq_puts(s, "\n");
+
+	seq_printf(s, "print fmt: %s\n", evt->print_fmt);
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(remote_event_format);
+
+static int remote_event_callback(const char *name, umode_t *mode, void **data,
+				 const struct file_operations **fops)
+{
+	if (!strcmp(name, "enable")) {
+		*mode = TRACEFS_MODE_WRITE;
+		*fops = &remote_event_enable_fops;
+		return 1;
+	}
+
+	if (!strcmp(name, "id")) {
+		*mode = TRACEFS_MODE_READ;
+		*fops = &remote_event_id_fops;
+		return 1;
+	}
+
+	if (!strcmp(name, "format")) {
+		*mode = TRACEFS_MODE_READ;
+		*fops = &remote_event_format_fops;
+		return 1;
+	}
+
+	return 0;
+}
+
+static int trace_remote_init_eventfs(const char *remote_name, struct trace_remote *remote,
+				     struct remote_event *evt)
+{
+	struct eventfs_inode *eventfs = remote->eventfs;
+	static struct eventfs_entry entries[] = {
+		{
+			.name		= "enable",
+			.callback	= remote_event_callback,
+		}, {
+			.name		= "id",
+			.callback	= remote_event_callback,
+		}, {
+			.name		= "format",
+			.callback	= remote_event_callback,
+		}
+	};
+	bool eventfs_create = false;
+
+	if (!eventfs) {
+		eventfs = eventfs_create_events_dir("events", remote->dentry, NULL, 0, NULL);
+		if (IS_ERR(eventfs))
+			return PTR_ERR(eventfs);
+
+		/*
+		 * Create similar hierarchy as local events even if a single system is supported at
+		 * the moment
+		 */
+		eventfs = eventfs_create_dir(remote_name, eventfs, NULL, 0, NULL);
+		if (IS_ERR(eventfs))
+			return PTR_ERR(eventfs);
+
+		remote->eventfs = eventfs;
+		eventfs_create = true;
+	}
+
+	eventfs = eventfs_create_dir(evt->name, eventfs, entries, ARRAY_SIZE(entries), evt);
+	if (IS_ERR(eventfs)) {
+		if (eventfs_create) {
+			eventfs_remove_events_dir(remote->eventfs);
+			remote->eventfs = NULL;
+		}
+		return PTR_ERR(eventfs);
+	}
+
+	return 0;
+}
+
+static int trace_remote_attach_events(struct trace_remote *remote, struct remote_event *events,
+				      size_t nr_events)
+{
+	int i;
+
+	for (i = 0; i < nr_events; i++) {
+		struct remote_event *evt = &events[i];
+
+		if (evt->remote)
+			return -EEXIST;
+
+		evt->remote = remote;
+
+		/* We need events to be sorted for efficient lookup */
+		if (i && evt->id <= events[i - 1].id)
+			return -EINVAL;
+	}
+
+	remote->events = events;
+	remote->nr_events = nr_events;
+
+	return 0;
+}
+
+static int trace_remote_register_events(const char *remote_name, struct trace_remote *remote,
+					struct remote_event *events, size_t nr_events)
+{
+	int i, ret;
+
+	ret = trace_remote_attach_events(remote, events, nr_events);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < nr_events; i++) {
+		struct remote_event *evt = &events[i];
+
+		ret = trace_remote_init_eventfs(remote_name, remote, evt);
+		if (ret)
+			pr_warn("Failed to init eventfs for event '%s' (%d)",
+				evt->name, ret);
+	}
+
+	return 0;
+}
+
+static int __cmp_events(const void *id, const void *evt)
+{
+	return (long)id - ((struct remote_event *)evt)->id;
+}
+
+static struct remote_event *trace_remote_find_event(struct trace_remote *remote, unsigned short id)
+{
+	return bsearch((const void *)(unsigned long)id, remote->events, remote->nr_events,
+		       sizeof(*remote->events), __cmp_events);
+}
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:36:03 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:36:03 +0000
Subject: [PATCH v9 10/30] tracing: Add events/ root files to trace remotes
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-11-vdonnefort@google.com>

Just like for the kernel events directory, add 'enable', 'header_page'
and 'header_event' at the root of the trace remote events/ directory.

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index cb674a9fc359..9f28e7b3058c 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -604,7 +604,8 @@ int ring_buffer_print_page_header(struct trace_buffer *buffer, struct trace_seq
 	trace_seq_printf(s, "\tfield: char data;\t"
 			 "offset:%u;\tsize:%u;\tsigned:%u;\n",
 			 (unsigned int)offsetof(typeof(field), data),
-			 (unsigned int)buffer->subbuf_size,
+			 (unsigned int)(buffer ? buffer->subbuf_size :
+						 PAGE_SIZE - BUF_PAGE_HDR_SIZE),
 			 (unsigned int)is_signed_type(char));
 
 	return !trace_seq_has_overflowed(s);
diff --git a/kernel/trace/trace_remote.c b/kernel/trace/trace_remote.c
index 8527804f2d22..e54cc3e75dc5 100644
--- a/kernel/trace/trace_remote.c
+++ b/kernel/trace/trace_remote.c
@@ -1078,10 +1078,145 @@ static int remote_event_callback(const char *name, umode_t *mode, void **data,
 	return 0;
 }
 
+static ssize_t remote_events_dir_enable_write(struct file *filp, const char __user *ubuf,
+					      size_t count, loff_t *ppos)
+{
+	struct trace_remote *remote = file_inode(filp)->i_private;
+	int i, ret;
+	u8 enable;
+
+	ret = kstrtou8_from_user(ubuf, count, 10, &enable);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&remote->lock);
+
+	for (i = 0; i < remote->nr_events; i++) {
+		struct remote_event *evt = &remote->events[i];
+
+		trace_remote_enable_event(remote, evt, enable);
+	}
+
+	return count;
+}
+
+static ssize_t remote_events_dir_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
+					     loff_t *ppos)
+{
+	struct trace_remote *remote = file_inode(filp)->i_private;
+	const char enabled_char[] = {'0', '1', 'X'};
+	char enabled_str[] = " \n";
+	int i, enabled = -1;
+
+	guard(mutex)(&remote->lock);
+
+	for (i = 0; i < remote->nr_events; i++) {
+		struct remote_event *evt = &remote->events[i];
+
+		if (enabled == -1) {
+			enabled = evt->enabled;
+		} else if (enabled != evt->enabled) {
+			enabled = 2;
+			break;
+		}
+	}
+
+	enabled_str[0] = enabled_char[enabled == -1 ? 0 : enabled];
+
+	return simple_read_from_buffer(ubuf, cnt, ppos, enabled_str, 2);
+}
+
+static const struct file_operations remote_events_dir_enable_fops = {
+	.write = remote_events_dir_enable_write,
+	.read = remote_events_dir_enable_read,
+};
+
+static ssize_t
+remote_events_dir_header_page_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	struct trace_seq *s;
+	int ret;
+
+	s = kmalloc(sizeof(*s), GFP_KERNEL);
+	if (!s)
+		return -ENOMEM;
+
+	trace_seq_init(s);
+
+	ring_buffer_print_page_header(NULL, s);
+	ret = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, trace_seq_used(s));
+	kfree(s);
+
+	return ret;
+}
+
+static const struct file_operations remote_events_dir_header_page_fops = {
+	.read = remote_events_dir_header_page_read,
+};
+
+static ssize_t
+remote_events_dir_header_event_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	struct trace_seq *s;
+	int ret;
+
+	s = kmalloc(sizeof(*s), GFP_KERNEL);
+	if (!s)
+		return -ENOMEM;
+
+	trace_seq_init(s);
+
+	ring_buffer_print_entry_header(s);
+	ret = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, trace_seq_used(s));
+	kfree(s);
+
+	return ret;
+}
+
+static const struct file_operations remote_events_dir_header_event_fops = {
+	.read = remote_events_dir_header_event_read,
+};
+
+static int remote_events_dir_callback(const char *name, umode_t *mode, void **data,
+				      const struct file_operations **fops)
+{
+	if (!strcmp(name, "enable")) {
+		*mode = TRACEFS_MODE_WRITE;
+		*fops = &remote_events_dir_enable_fops;
+		return 1;
+	}
+
+	if (!strcmp(name, "header_page")) {
+		*mode = TRACEFS_MODE_READ;
+		*fops = &remote_events_dir_header_page_fops;
+		return 1;
+	}
+
+	if (!strcmp(name, "header_event")) {
+		*mode = TRACEFS_MODE_READ;
+		*fops = &remote_events_dir_header_event_fops;
+		return 1;
+	}
+
+	return 0;
+}
+
 static int trace_remote_init_eventfs(const char *remote_name, struct trace_remote *remote,
 				     struct remote_event *evt)
 {
 	struct eventfs_inode *eventfs = remote->eventfs;
+	static struct eventfs_entry dir_entries[] = {
+		{
+			.name		= "enable",
+			.callback	= remote_events_dir_callback,
+		}, {
+			.name		= "header_page",
+			.callback	= remote_events_dir_callback,
+		}, {
+			.name		= "header_event",
+			.callback	= remote_events_dir_callback,
+		}
+	};
 	static struct eventfs_entry entries[] = {
 		{
 			.name		= "enable",
@@ -1097,7 +1232,8 @@ static int trace_remote_init_eventfs(const char *remote_name, struct trace_remot
 	bool eventfs_create = false;
 
 	if (!eventfs) {
-		eventfs = eventfs_create_events_dir("events", remote->dentry, NULL, 0, NULL);
+		eventfs = eventfs_create_events_dir("events", remote->dentry, dir_entries,
+						    ARRAY_SIZE(dir_entries), remote);
 		if (IS_ERR(eventfs))
 			return PTR_ERR(eventfs);
 
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:36:04 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:36:04 +0000
Subject: [PATCH v9 11/30] tracing: Add helpers to create trace remote events
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-12-vdonnefort@google.com>

Declaring remote events can be cumbersome let's add a set of macros to
simplify developers life. The declaration of a remote event is very
similar to kernel's events:

 REMOTE_EVENT(name, id,
     RE_STRUCT(
        re_field(u64 foo)
     ),
     RE_PRINTK("foo=%llu", __entry->foo)
 )

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/include/linux/trace_remote_event.h b/include/linux/trace_remote_event.h
index a4449008a075..c8ae1e1f5e72 100644
--- a/include/linux/trace_remote_event.h
+++ b/include/linux/trace_remote_event.h
@@ -5,6 +5,7 @@
 
 struct trace_remote;
 struct trace_event_fields;
+struct trace_seq;
 
 struct remote_event_hdr {
 	unsigned short	id;
@@ -20,4 +21,13 @@ struct remote_event {
 	char				*print_fmt;
 	void				(*print)(void *evt, struct trace_seq *seq);
 };
+
+#define RE_STRUCT(__args...) __args
+#define re_field(__type, __field) __type __field;
+
+#define REMOTE_EVENT_FORMAT(__name, __struct)	\
+	struct remote_event_format_##__name {	\
+		struct remote_event_hdr hdr;	\
+		__struct			\
+	}
 #endif
diff --git a/include/trace/define_remote_events.h b/include/trace/define_remote_events.h
new file mode 100644
index 000000000000..03c9f5515c5a
--- /dev/null
+++ b/include/trace/define_remote_events.h
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <linux/trace_events.h>
+#include <linux/trace_remote_event.h>
+#include <linux/trace_seq.h>
+#include <linux/stringify.h>
+
+#define REMOTE_EVENT_INCLUDE(__file) __stringify(../../__file)
+
+#ifdef REMOTE_EVENT_SECTION
+# define __REMOTE_EVENT_SECTION(__name) __used __section(REMOTE_EVENT_SECTION"."#__name)
+#else
+# define __REMOTE_EVENT_SECTION(__name)
+#endif
+
+#define __REMOTE_PRINTK_COUNT_ARGS(_0, _1, _2, _n, __args...) _n
+#define REMOTE_PRINTK_COUNT_ARGS(__args...) __REMOTE_PRINTK_COUNT_ARGS(, ##__args, 2, 1, 0)
+
+#define __remote_printk0()								\
+	trace_seq_putc(seq, '\n')
+
+#define __remote_printk1(__fmt)								\
+	trace_seq_puts(seq, " " __fmt "\n")						\
+
+#define __remote_printk2(__fmt, __args...)						\
+do {											\
+	trace_seq_putc(seq, ' ');							\
+	trace_seq_printf(seq, __fmt, __args);						\
+	trace_seq_putc(seq, '\n');							\
+} while (0)
+
+/* Apply the appropriate trace_seq sequence according to the number of arguments */
+#define remote_printk(__args...)							\
+	CONCATENATE(__remote_printk, REMOTE_PRINTK_COUNT_ARGS(__args))(__args)
+
+#define RE_PRINTK(__args...) __args
+
+#define REMOTE_EVENT(__name, __id, __struct, __printk)					\
+	REMOTE_EVENT_FORMAT(__name, __struct);						\
+	static void remote_event_print_##__name(void *evt, struct trace_seq *seq)	\
+	{										\
+		struct remote_event_format_##__name __maybe_unused *__entry = evt;	\
+		trace_seq_puts(seq, #__name);						\
+		remote_printk(__printk);						\
+	}
+#include REMOTE_EVENT_INCLUDE(REMOTE_EVENT_INCLUDE_FILE)
+
+#undef REMOTE_EVENT
+#undef RE_PRINTK
+#undef re_field
+#define re_field(__type, __field)							\
+	{										\
+		.type = #__type, .name = #__field,					\
+		.size = sizeof(__type), .align = __alignof__(__type),			\
+		.is_signed = is_signed_type(__type),					\
+	},
+#define __entry REC
+#define RE_PRINTK(__fmt, __args...) "\"" __fmt "\", " __stringify(__args)
+#define REMOTE_EVENT(__name, __id, __struct, __printk)					\
+	static struct trace_event_fields remote_event_fields_##__name[] = {		\
+		__struct								\
+		{}									\
+	};										\
+	static char remote_event_print_fmt_##__name[] = __printk;			\
+	static struct remote_event __REMOTE_EVENT_SECTION(__name)			\
+	remote_event_##__name = {							\
+		.name		= #__name,						\
+		.id		= __id,							\
+		.fields		= remote_event_fields_##__name,				\
+		.print_fmt	= remote_event_print_fmt_##__name,			\
+		.print		= remote_event_print_##__name,				\
+	}
+#include REMOTE_EVENT_INCLUDE(REMOTE_EVENT_INCLUDE_FILE)
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:36:05 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:36:05 +0000
Subject: [PATCH v9 12/30] ring-buffer: Export buffer_data_page and macros
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-13-vdonnefort@google.com>

In preparation for allowing the writing of ring-buffer compliant pages
outside of ring_buffer.c, move buffer_data_page and timestamps encoding
macros into the publicly available ring_buffer_types.h.

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/include/linux/ring_buffer_types.h b/include/linux/ring_buffer_types.h
new file mode 100644
index 000000000000..54577021a49d
--- /dev/null
+++ b/include/linux/ring_buffer_types.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_RING_BUFFER_TYPES_H
+#define _LINUX_RING_BUFFER_TYPES_H
+
+#include <asm/local.h>
+
+#define TS_SHIFT        27
+#define TS_MASK         ((1ULL << TS_SHIFT) - 1)
+#define TS_DELTA_TEST   (~TS_MASK)
+
+/*
+ * We need to fit the time_stamp delta into 27 bits.
+ */
+static inline bool test_time_stamp(u64 delta)
+{
+	return !!(delta & TS_DELTA_TEST);
+}
+
+#define BUF_PAGE_HDR_SIZE offsetof(struct buffer_data_page, data)
+
+#define RB_EVNT_HDR_SIZE (offsetof(struct ring_buffer_event, array))
+#define RB_ALIGNMENT		4U
+#define RB_MAX_SMALL_DATA	(RB_ALIGNMENT * RINGBUF_TYPE_DATA_TYPE_LEN_MAX)
+#define RB_EVNT_MIN_SIZE	8U	/* two 32bit words */
+
+#ifndef CONFIG_HAVE_64BIT_ALIGNED_ACCESS
+# define RB_FORCE_8BYTE_ALIGNMENT	0
+# define RB_ARCH_ALIGNMENT		RB_ALIGNMENT
+#else
+# define RB_FORCE_8BYTE_ALIGNMENT	1
+# define RB_ARCH_ALIGNMENT		8U
+#endif
+
+#define RB_ALIGN_DATA		__aligned(RB_ARCH_ALIGNMENT)
+
+struct buffer_data_page {
+	u64		 time_stamp;	/* page time stamp */
+	local_t		 commit;	/* write committed index */
+	unsigned char	 data[] RB_ALIGN_DATA;	/* data of buffer page */
+};
+#endif
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 9f28e7b3058c..7a1a8d5f3a25 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -4,6 +4,7 @@
  *
  * Copyright (C) 2008 Steven Rostedt <srostedt at redhat.com>
  */
+#include <linux/ring_buffer_types.h>
 #include <linux/trace_recursion.h>
 #include <linux/trace_events.h>
 #include <linux/ring_buffer.h>
@@ -156,23 +157,6 @@ int ring_buffer_print_entry_header(struct trace_seq *s)
 /* Used for individual buffers (after the counter) */
 #define RB_BUFFER_OFF		(1 << 20)
 
-#define BUF_PAGE_HDR_SIZE offsetof(struct buffer_data_page, data)
-
-#define RB_EVNT_HDR_SIZE (offsetof(struct ring_buffer_event, array))
-#define RB_ALIGNMENT		4U
-#define RB_MAX_SMALL_DATA	(RB_ALIGNMENT * RINGBUF_TYPE_DATA_TYPE_LEN_MAX)
-#define RB_EVNT_MIN_SIZE	8U	/* two 32bit words */
-
-#ifndef CONFIG_HAVE_64BIT_ALIGNED_ACCESS
-# define RB_FORCE_8BYTE_ALIGNMENT	0
-# define RB_ARCH_ALIGNMENT		RB_ALIGNMENT
-#else
-# define RB_FORCE_8BYTE_ALIGNMENT	1
-# define RB_ARCH_ALIGNMENT		8U
-#endif
-
-#define RB_ALIGN_DATA		__aligned(RB_ARCH_ALIGNMENT)
-
 /* define RINGBUF_TYPE_DATA for 'case RINGBUF_TYPE_DATA:' */
 #define RINGBUF_TYPE_DATA 0 ... RINGBUF_TYPE_DATA_TYPE_LEN_MAX
 
@@ -315,10 +299,6 @@ EXPORT_SYMBOL_GPL(ring_buffer_event_data);
 #define for_each_online_buffer_cpu(buffer, cpu)		\
 	for_each_cpu_and(cpu, buffer->cpumask, cpu_online_mask)
 
-#define TS_SHIFT	27
-#define TS_MASK		((1ULL << TS_SHIFT) - 1)
-#define TS_DELTA_TEST	(~TS_MASK)
-
 static u64 rb_event_time_stamp(struct ring_buffer_event *event)
 {
 	u64 ts;
@@ -337,12 +317,6 @@ static u64 rb_event_time_stamp(struct ring_buffer_event *event)
 
 #define RB_MISSED_MASK		(3 << 30)
 
-struct buffer_data_page {
-	u64		 time_stamp;	/* page time stamp */
-	local_t		 commit;	/* write committed index */
-	unsigned char	 data[] RB_ALIGN_DATA;	/* data of buffer page */
-};
-
 struct buffer_data_read_page {
 	unsigned		order;	/* order of the page */
 	struct buffer_data_page	*data;	/* actual data, stored in this page */
@@ -401,14 +375,6 @@ static void free_buffer_page(struct buffer_page *bpage)
 	kfree(bpage);
 }
 
-/*
- * We need to fit the time_stamp delta into 27 bits.
- */
-static inline bool test_time_stamp(u64 delta)
-{
-	return !!(delta & TS_DELTA_TEST);
-}
-
 struct rb_irq_work {
 	struct irq_work			work;
 	wait_queue_head_t		waiters;
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:36:06 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:36:06 +0000
Subject: [PATCH v9 13/30] tracing: Introduce simple_ring_buffer
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-14-vdonnefort@google.com>

Add a simple implementation of the kernel ring-buffer. This intends to
be used later by ring-buffer remotes such as the pKVM hypervisor, hence
the need for a cut down version (write only) without any dependency.

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/include/linux/simple_ring_buffer.h b/include/linux/simple_ring_buffer.h
new file mode 100644
index 000000000000..f324df2f875b
--- /dev/null
+++ b/include/linux/simple_ring_buffer.h
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_SIMPLE_RING_BUFFER_H
+#define _LINUX_SIMPLE_RING_BUFFER_H
+
+#include <linux/list.h>
+#include <linux/ring_buffer.h>
+#include <linux/ring_buffer_types.h>
+#include <linux/types.h>
+
+/*
+ * Ideally those struct would stay private but the caller needs to know
+ * the allocation size for simple_ring_buffer_init().
+ */
+struct simple_buffer_page {
+	struct list_head	link;
+	struct buffer_data_page	*page;
+	u64			entries;
+	u32			write;
+	u32			id;
+};
+
+struct simple_rb_per_cpu {
+	struct simple_buffer_page	*tail_page;
+	struct simple_buffer_page	*reader_page;
+	struct simple_buffer_page	*head_page;
+	struct simple_buffer_page	*bpages;
+	struct trace_buffer_meta	*meta;
+	u32				nr_pages;
+
+#define SIMPLE_RB_UNAVAILABLE	0
+#define SIMPLE_RB_READY		1
+#define SIMPLE_RB_WRITING	2
+	u32				status;
+
+	u64				last_overrun;
+	u64				write_stamp;
+
+	struct simple_rb_cbs		*cbs;
+};
+
+/**
+ * simple_ring_buffer_init - Init @cpu_buffer based on @desc
+ *
+ * @cpu_buffer:	A simple_rb_per_cpu buffer to init, allocated by the caller.
+ * @bpages:	Array of simple_buffer_pages, with as many elements as @desc->nr_page_va
+ * @desc:	A ring_buffer_desc
+ *
+ * Returns: 0 on success or -EINVAL if the content of @desc is invalid
+ */
+int simple_ring_buffer_init(struct simple_rb_per_cpu *cpu_buffer, struct simple_buffer_page *bpages,
+			    const struct ring_buffer_desc *desc);
+
+/**
+ * simple_ring_buffer_unload - Prepare @cpu_buffer for deletion
+ *
+ * @cpu_buffer:	A simple_rb_per_cpu that will be deleted.
+ */
+void simple_ring_buffer_unload(struct simple_rb_per_cpu *cpu_buffer);
+
+/**
+ * simple_ring_buffer_reserve - Reserve an entry in @cpu_buffer
+ *
+ * @cpu_buffer:	A simple_rb_per_cpu
+ * @length:	Size of the entry in bytes
+ * @timestamp:	Timestamp of the entry
+ *
+ * Returns the address of the entry where to write data or NULL
+ */
+void *simple_ring_buffer_reserve(struct simple_rb_per_cpu *cpu_buffer, unsigned long length,
+				 u64 timestamp);
+
+/**
+ * simple_ring_buffer_commit - Commit the entry reserved with simple_ring_buffer_reserve()
+ *
+ * @cpu_buffer:	The simple_rb_per_cpu where the entry has been reserved
+ */
+void simple_ring_buffer_commit(struct simple_rb_per_cpu *cpu_buffer);
+
+/**
+ * simple_ring_buffer_enable_tracing - Enable or disable writing to @cpu_buffer
+ *
+ * @cpu_buffer: A simple_rb_per_cpu
+ * @enable:	True to enable tracing, False to disable it
+ *
+ * Returns 0 on success or -ENODEV if @cpu_buffer was unloaded
+ */
+int simple_ring_buffer_enable_tracing(struct simple_rb_per_cpu *cpu_buffer, bool enable);
+
+/**
+ * simple_ring_buffer_reset - Reset @cpu_buffer
+ *
+ * @cpu_buffer: A simple_rb_per_cpu
+ *
+ * This will not clear the content of the data, only reset counters and pointers
+ *
+ * Returns 0 on success or -ENODEV if @cpu_buffer was unloaded.
+ */
+int simple_ring_buffer_reset(struct simple_rb_per_cpu *cpu_buffer);
+
+/**
+ * simple_ring_buffer_swap_reader_page - Swap ring-buffer head with the reader
+ *
+ * This function enables consuming reading. It ensures the current head page will not be overwritten
+ * and can be safely read.
+ *
+ * @cpu_buffer: A simple_rb_per_cpu
+ *
+ * Returns 0 on success, -ENODEV if @cpu_buffer was unloaded or -EBUSY if we failed to catch the
+ * head page.
+ */
+int simple_ring_buffer_swap_reader_page(struct simple_rb_per_cpu *cpu_buffer);
+
+#endif
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index 99af56d39eaf..918afcc1fcaf 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -1241,4 +1241,7 @@ source "kernel/trace/rv/Kconfig"
 config TRACE_REMOTE
 	bool
 
+config SIMPLE_RING_BUFFER
+	bool
+
 endif # FTRACE
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index 6dab341acc46..03d7d80a9436 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -111,4 +111,5 @@ obj-$(CONFIG_TRACEPOINT_BENCHMARK) += trace_benchmark.o
 obj-$(CONFIG_RV) += rv/
 
 obj-$(CONFIG_TRACE_REMOTE) += trace_remote.o
+obj-$(CONFIG_SIMPLE_RING_BUFFER) += simple_ring_buffer.o
 libftrace-y := ftrace.o
diff --git a/kernel/trace/simple_ring_buffer.c b/kernel/trace/simple_ring_buffer.c
new file mode 100644
index 000000000000..1d1f40c8c6d8
--- /dev/null
+++ b/kernel/trace/simple_ring_buffer.c
@@ -0,0 +1,415 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025 - Google LLC
+ * Author: Vincent Donnefort <vdonnefort at google.com>
+ */
+
+#include <linux/atomic.h>
+#include <linux/simple_ring_buffer.h>
+
+#include <asm/barrier.h>
+#include <asm/local.h>
+
+enum simple_rb_link_type {
+	SIMPLE_RB_LINK_NORMAL		= 0,
+	SIMPLE_RB_LINK_HEAD		= 1,
+	SIMPLE_RB_LINK_HEAD_MOVING
+};
+
+#define SIMPLE_RB_LINK_MASK ~(SIMPLE_RB_LINK_HEAD | SIMPLE_RB_LINK_HEAD_MOVING)
+
+static void simple_bpage_set_head_link(struct simple_buffer_page *bpage)
+{
+	unsigned long link = (unsigned long)bpage->link.next;
+
+	link &= SIMPLE_RB_LINK_MASK;
+	link |= SIMPLE_RB_LINK_HEAD;
+
+	/*
+	 * Paired with simple_rb_find_head() to order access between the head
+	 * link and overrun. It ensures we always report an up-to-date value
+	 * after swapping the reader page.
+	 */
+	smp_store_release(&bpage->link.next, (struct list_head *)link);
+}
+
+static bool simple_bpage_unset_head_link(struct simple_buffer_page *bpage,
+					 struct simple_buffer_page *dst,
+					 enum simple_rb_link_type new_type)
+{
+	unsigned long *link = (unsigned long *)(&bpage->link.next);
+	unsigned long old = (*link & SIMPLE_RB_LINK_MASK) | SIMPLE_RB_LINK_HEAD;
+	unsigned long new = (unsigned long)(&dst->link) | new_type;
+
+	return try_cmpxchg(link, &old, new);
+}
+
+static void simple_bpage_set_normal_link(struct simple_buffer_page *bpage)
+{
+	unsigned long link = (unsigned long)bpage->link.next;
+
+	WRITE_ONCE(bpage->link.next, (struct list_head *)(link & SIMPLE_RB_LINK_MASK));
+}
+
+static struct simple_buffer_page *simple_bpage_from_link(struct list_head *link)
+{
+	unsigned long ptr = (unsigned long)link & SIMPLE_RB_LINK_MASK;
+
+	return container_of((struct list_head *)ptr, struct simple_buffer_page, link);
+}
+
+static struct simple_buffer_page *simple_bpage_next_page(struct simple_buffer_page *bpage)
+{
+	return simple_bpage_from_link(bpage->link.next);
+}
+
+static void simple_bpage_reset(struct simple_buffer_page *bpage)
+{
+	bpage->write = 0;
+	bpage->entries = 0;
+
+	local_set(&bpage->page->commit, 0);
+}
+
+static void simple_bpage_init(struct simple_buffer_page *bpage, unsigned long page)
+{
+	INIT_LIST_HEAD(&bpage->link);
+	bpage->page = (struct buffer_data_page *)page;
+
+	simple_bpage_reset(bpage);
+}
+
+#define simple_rb_meta_inc(__meta, __inc)		\
+	WRITE_ONCE((__meta), (__meta + __inc))
+
+static bool simple_rb_loaded(struct simple_rb_per_cpu *cpu_buffer)
+{
+	return !!cpu_buffer->bpages;
+}
+
+static int simple_rb_find_head(struct simple_rb_per_cpu *cpu_buffer)
+{
+	int retry = cpu_buffer->nr_pages * 2;
+	struct simple_buffer_page *head;
+
+	head = cpu_buffer->head_page;
+
+	while (retry--) {
+		unsigned long link;
+
+spin:
+		/* See smp_store_release in simple_bpage_set_head_link() */
+		link = (unsigned long)smp_load_acquire(&head->link.prev->next);
+
+		switch (link & ~SIMPLE_RB_LINK_MASK) {
+		/* Found the head */
+		case SIMPLE_RB_LINK_HEAD:
+			cpu_buffer->head_page = head;
+			return 0;
+		/* The writer caught the head, we can spin, that won't be long */
+		case SIMPLE_RB_LINK_HEAD_MOVING:
+			goto spin;
+		}
+
+		head = simple_bpage_next_page(head);
+	}
+
+	return -EBUSY;
+}
+
+int simple_ring_buffer_swap_reader_page(struct simple_rb_per_cpu *cpu_buffer)
+{
+	struct simple_buffer_page *last, *head, *reader;
+	unsigned long overrun;
+	int retry = 8;
+	int ret;
+
+	if (!simple_rb_loaded(cpu_buffer))
+		return -ENODEV;
+
+	reader = cpu_buffer->reader_page;
+
+	do {
+		/* Run after the writer to find the head */
+		ret = simple_rb_find_head(cpu_buffer);
+		if (ret)
+			return ret;
+
+		head = cpu_buffer->head_page;
+
+		/* Connect the reader page around the header page */
+		reader->link.next = head->link.next;
+		reader->link.prev = head->link.prev;
+
+		/* The last page before the head */
+		last = simple_bpage_from_link(head->link.prev);
+
+		/* The reader page points to the new header page */
+		simple_bpage_set_head_link(reader);
+
+		overrun = cpu_buffer->meta->overrun;
+	} while (!simple_bpage_unset_head_link(last, reader, SIMPLE_RB_LINK_NORMAL) && retry--);
+
+	if (!retry)
+		return -EINVAL;
+
+	cpu_buffer->head_page = simple_bpage_from_link(reader->link.next);
+	cpu_buffer->head_page->link.prev = &reader->link;
+	cpu_buffer->reader_page = head;
+	cpu_buffer->meta->reader.lost_events = overrun - cpu_buffer->last_overrun;
+	cpu_buffer->meta->reader.id = cpu_buffer->reader_page->id;
+	cpu_buffer->last_overrun = overrun;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(simple_ring_buffer_swap_reader_page);
+
+static struct simple_buffer_page *simple_rb_move_tail(struct simple_rb_per_cpu *cpu_buffer)
+{
+	struct simple_buffer_page *tail, *new_tail;
+
+	tail = cpu_buffer->tail_page;
+	new_tail = simple_bpage_next_page(tail);
+
+	if (simple_bpage_unset_head_link(tail, new_tail, SIMPLE_RB_LINK_HEAD_MOVING)) {
+		/*
+		 * Oh no! we've caught the head. There is none anymore and
+		 * swap_reader will spin until we set the new one. Overrun must
+		 * be written first, to make sure we report the correct number
+		 * of lost events.
+		 */
+		simple_rb_meta_inc(cpu_buffer->meta->overrun, new_tail->entries);
+		simple_rb_meta_inc(cpu_buffer->meta->pages_lost, 1);
+
+		simple_bpage_set_head_link(new_tail);
+		simple_bpage_set_normal_link(tail);
+	}
+
+	simple_bpage_reset(new_tail);
+	cpu_buffer->tail_page = new_tail;
+
+	simple_rb_meta_inc(cpu_buffer->meta->pages_touched, 1);
+
+	return new_tail;
+}
+
+static unsigned long rb_event_size(unsigned long length)
+{
+	struct ring_buffer_event *event;
+
+	return length + RB_EVNT_HDR_SIZE + sizeof(event->array[0]);
+}
+
+static struct ring_buffer_event *
+rb_event_add_ts_extend(struct ring_buffer_event *event, u64 delta)
+{
+	event->type_len = RINGBUF_TYPE_TIME_EXTEND;
+	event->time_delta = delta & TS_MASK;
+	event->array[0] = delta >> TS_SHIFT;
+
+	return (struct ring_buffer_event *)((unsigned long)event + 8);
+}
+
+static struct ring_buffer_event *
+simple_rb_reserve_next(struct simple_rb_per_cpu *cpu_buffer, unsigned long length, u64 timestamp)
+{
+	unsigned long ts_ext_size = 0, event_size = rb_event_size(length);
+	struct simple_buffer_page *tail = cpu_buffer->tail_page;
+	struct ring_buffer_event *event;
+	u32 write, prev_write;
+	u64 time_delta;
+
+	time_delta = timestamp - cpu_buffer->write_stamp;
+
+	if (test_time_stamp(time_delta))
+		ts_ext_size = 8;
+
+	prev_write = tail->write;
+	write = prev_write + event_size + ts_ext_size;
+
+	if (unlikely(write > (PAGE_SIZE - BUF_PAGE_HDR_SIZE)))
+		tail = simple_rb_move_tail(cpu_buffer);
+
+	if (!tail->entries) {
+		tail->page->time_stamp = timestamp;
+		time_delta = 0;
+		ts_ext_size = 0;
+		write = event_size;
+		prev_write = 0;
+	}
+
+	tail->write = write;
+	tail->entries++;
+
+	cpu_buffer->write_stamp = timestamp;
+
+	event = (struct ring_buffer_event *)(tail->page->data + prev_write);
+	if (ts_ext_size) {
+		event = rb_event_add_ts_extend(event, time_delta);
+		time_delta = 0;
+	}
+
+	event->type_len = 0;
+	event->time_delta = time_delta;
+	event->array[0] = event_size - RB_EVNT_HDR_SIZE;
+
+	return event;
+}
+
+void *simple_ring_buffer_reserve(struct simple_rb_per_cpu *cpu_buffer, unsigned long length,
+				 u64 timestamp)
+{
+	struct ring_buffer_event *rb_event;
+
+	if (cmpxchg(&cpu_buffer->status, SIMPLE_RB_READY, SIMPLE_RB_WRITING) != SIMPLE_RB_READY)
+		return NULL;
+
+	rb_event = simple_rb_reserve_next(cpu_buffer, length, timestamp);
+
+	return &rb_event->array[1];
+}
+EXPORT_SYMBOL_GPL(simple_ring_buffer_reserve);
+
+void simple_ring_buffer_commit(struct simple_rb_per_cpu *cpu_buffer)
+{
+	local_set(&cpu_buffer->tail_page->page->commit,
+		  cpu_buffer->tail_page->write);
+	simple_rb_meta_inc(cpu_buffer->meta->entries, 1);
+
+	/*
+	 * Paired with simple_rb_enable_tracing() to ensure data is
+	 * written to the ring-buffer before teardown.
+	 */
+	smp_store_release(&cpu_buffer->status, SIMPLE_RB_READY);
+}
+EXPORT_SYMBOL_GPL(simple_ring_buffer_commit);
+
+static u32 simple_rb_enable_tracing(struct simple_rb_per_cpu *cpu_buffer, bool enable)
+{
+	u32 prev_status;
+
+	if (enable)
+		return cmpxchg(&cpu_buffer->status, SIMPLE_RB_UNAVAILABLE, SIMPLE_RB_READY);
+
+	/* Wait for the buffer to be released */
+	do {
+		prev_status = cmpxchg_acquire(&cpu_buffer->status,
+					      SIMPLE_RB_READY,
+					      SIMPLE_RB_UNAVAILABLE);
+	} while (prev_status == SIMPLE_RB_WRITING);
+
+	return prev_status;
+}
+
+int simple_ring_buffer_reset(struct simple_rb_per_cpu *cpu_buffer)
+{
+	struct simple_buffer_page *bpage;
+	u32 prev_status;
+	int ret;
+
+	if (!simple_rb_loaded(cpu_buffer))
+		return -ENODEV;
+
+	prev_status = simple_rb_enable_tracing(cpu_buffer, false);
+
+	ret = simple_rb_find_head(cpu_buffer);
+	if (ret)
+		return ret;
+
+	bpage = cpu_buffer->tail_page = cpu_buffer->head_page;
+	do {
+		simple_bpage_reset(bpage);
+		bpage = simple_bpage_next_page(bpage);
+	} while (bpage != cpu_buffer->head_page);
+
+	simple_bpage_reset(cpu_buffer->reader_page);
+
+	cpu_buffer->last_overrun = 0;
+	cpu_buffer->write_stamp = 0;
+
+	cpu_buffer->meta->reader.read = 0;
+	cpu_buffer->meta->reader.lost_events = 0;
+	cpu_buffer->meta->entries = 0;
+	cpu_buffer->meta->overrun = 0;
+	cpu_buffer->meta->read = 0;
+	cpu_buffer->meta->pages_lost = 0;
+	cpu_buffer->meta->pages_touched = 0;
+
+	if (prev_status == SIMPLE_RB_READY)
+		simple_rb_enable_tracing(cpu_buffer, true);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(simple_ring_buffer_reset);
+
+int simple_ring_buffer_init(struct simple_rb_per_cpu *cpu_buffer, struct simple_buffer_page *bpages,
+			    const struct ring_buffer_desc *desc)
+{
+	struct simple_buffer_page *bpage = bpages;
+	int i;
+
+	/* At least 1 reader page and two pages in the ring-buffer */
+	if (desc->nr_page_va < 3)
+		return -EINVAL;
+
+	memset(cpu_buffer, 0, sizeof(*cpu_buffer));
+
+	cpu_buffer->bpages = bpages;
+
+	cpu_buffer->meta = (void *)desc->meta_va;
+	memset(cpu_buffer->meta, 0, sizeof(*cpu_buffer->meta));
+	cpu_buffer->meta->meta_page_size = PAGE_SIZE;
+	cpu_buffer->meta->nr_subbufs = cpu_buffer->nr_pages;
+
+	/* The reader page is not part of the ring initially */
+	simple_bpage_init(bpage, desc->page_va[0]);
+	bpage->id = 0;
+
+	cpu_buffer->nr_pages = 1;
+
+	cpu_buffer->reader_page = bpage;
+	cpu_buffer->tail_page = bpage + 1;
+	cpu_buffer->head_page = bpage + 1;
+
+	for (i = 1; i < desc->nr_page_va; i++) {
+		simple_bpage_init(++bpage, desc->page_va[i]);
+
+		bpage->link.next = &(bpage + 1)->link;
+		bpage->link.prev = &(bpage - 1)->link;
+		bpage->id = i;
+
+		cpu_buffer->nr_pages = i + 1;
+	}
+
+	/* Close the ring */
+	bpage->link.next = &cpu_buffer->tail_page->link;
+	cpu_buffer->tail_page->link.prev = &bpage->link;
+
+	/* The last init'ed page points to the head page */
+	simple_bpage_set_head_link(bpage);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(simple_ring_buffer_init);
+
+void simple_ring_buffer_unload(struct simple_rb_per_cpu *cpu_buffer)
+{
+	if (!simple_rb_loaded(cpu_buffer))
+		return;
+
+	simple_rb_enable_tracing(cpu_buffer, false);
+
+	cpu_buffer->bpages = NULL;
+}
+EXPORT_SYMBOL_GPL(simple_ring_buffer_unload);
+
+int simple_ring_buffer_enable_tracing(struct simple_rb_per_cpu *cpu_buffer, bool enable)
+{
+	if (!simple_rb_loaded(cpu_buffer))
+		return -ENODEV;
+
+	simple_rb_enable_tracing(cpu_buffer, enable);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(simple_ring_buffer_enable_tracing);
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:36:07 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:36:07 +0000
Subject: [PATCH v9 14/30] tracing: Add a trace remote module for testing
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-15-vdonnefort@google.com>

Add a module to help testing the tracefs support for trace remotes. This
module:

  * Use simple_ring_buffer to write into a ring-buffer.
  * Declare a single "selftest" event that can be triggered from
    user-space.
  * Register a "test" trace remote.

This is intended to be used by trace remote selftests.

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c
index 0c023941a316..aa305be834f9 100644
--- a/fs/tracefs/inode.c
+++ b/fs/tracefs/inode.c
@@ -665,6 +665,7 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode,
 	fsnotify_create(d_inode(dentry->d_parent), dentry);
 	return tracefs_end_creating(dentry);
 }
+EXPORT_SYMBOL_GPL(tracefs_create_file);
 
 static struct dentry *__create_dir(const char *name, struct dentry *parent,
 				   const struct inode_operations *ops)
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index 918afcc1fcaf..52131d89993c 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -1244,4 +1244,12 @@ config TRACE_REMOTE
 config SIMPLE_RING_BUFFER
 	bool
 
+config TRACE_REMOTE_TEST
+	tristate "Test module for remote tracing"
+	select TRACE_REMOTE
+	select SIMPLE_RING_BUFFER
+	help
+	  This trace remote includes a ring-buffer writer implementation using
+	  "simple_ring_buffer". This is solely intending for testing.
+
 endif # FTRACE
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index 03d7d80a9436..53534447e70b 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -112,4 +112,6 @@ obj-$(CONFIG_RV) += rv/
 
 obj-$(CONFIG_TRACE_REMOTE) += trace_remote.o
 obj-$(CONFIG_SIMPLE_RING_BUFFER) += simple_ring_buffer.o
+obj-$(CONFIG_TRACE_REMOTE_TEST) += remote_test.o
+
 libftrace-y := ftrace.o
diff --git a/kernel/trace/remote_test.c b/kernel/trace/remote_test.c
new file mode 100644
index 000000000000..059127489c99
--- /dev/null
+++ b/kernel/trace/remote_test.c
@@ -0,0 +1,259 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025 - Google LLC
+ * Author: Vincent Donnefort <vdonnefort at google.com>
+ */
+
+#include <linux/module.h>
+#include <linux/simple_ring_buffer.h>
+#include <linux/trace_remote.h>
+#include <linux/tracefs.h>
+#include <linux/types.h>
+
+#define REMOTE_EVENT_INCLUDE_FILE kernel/trace/remote_test_events.h
+#include <trace/define_remote_events.h>
+
+static DEFINE_PER_CPU(struct simple_rb_per_cpu *, simple_rbs);
+static struct trace_buffer_desc *remote_test_buffer_desc;
+
+/*
+ * The trace_remote lock already serializes accesses from the trace_remote_callbacks.
+ * However write_event can still race with load/unload.
+ */
+static DEFINE_MUTEX(simple_rbs_lock);
+
+static int remote_test_load_simple_rb(int cpu, struct ring_buffer_desc *rb_desc)
+{
+	struct simple_rb_per_cpu *cpu_buffer;
+	struct simple_buffer_page *bpages;
+	int ret = -ENOMEM;
+
+	cpu_buffer = kmalloc(sizeof(*cpu_buffer), GFP_KERNEL);
+	if (!cpu_buffer)
+		return ret;
+
+	bpages = kmalloc_array(rb_desc->nr_page_va, sizeof(*bpages), GFP_KERNEL);
+	if (!bpages)
+		goto err_free_cpu_buffer;
+
+	ret = simple_ring_buffer_init(cpu_buffer, bpages, rb_desc);
+	if (ret)
+		goto err_free_bpages;
+
+	scoped_guard(mutex, &simple_rbs_lock)
+		*per_cpu_ptr(&simple_rbs, cpu) = cpu_buffer;
+
+	return 0;
+
+err_free_bpages:
+	kfree(bpages);
+
+err_free_cpu_buffer:
+	kfree(cpu_buffer);
+
+	return ret;
+}
+
+static void remote_test_unload_simple_rb(int cpu)
+{
+	struct simple_rb_per_cpu *cpu_buffer = *per_cpu_ptr(&simple_rbs, cpu);
+	struct simple_buffer_page *bpages;
+
+	if (!cpu_buffer)
+		return;
+
+	guard(mutex)(&simple_rbs_lock);
+
+	bpages = cpu_buffer->bpages;
+	simple_ring_buffer_unload(cpu_buffer);
+	kfree(bpages);
+	kfree(cpu_buffer);
+	*per_cpu_ptr(&simple_rbs, cpu) = NULL;
+}
+
+static struct trace_buffer_desc *remote_test_load(unsigned long size, void *unused)
+{
+	struct ring_buffer_desc *rb_desc;
+	struct trace_buffer_desc *desc;
+	size_t desc_size;
+	int cpu, ret;
+
+	if (WARN_ON(remote_test_buffer_desc))
+		return ERR_PTR(-EINVAL);
+
+	desc_size = trace_buffer_desc_size(size, num_possible_cpus());
+	if (desc_size == SIZE_MAX) {
+		ret = -E2BIG;
+		goto err_unlock_cpus;
+	}
+
+	desc = kmalloc(desc_size, GFP_KERNEL);
+	if (!desc) {
+		ret = -ENOMEM;
+		goto err_unlock_cpus;
+	}
+
+	ret = trace_remote_alloc_buffer(desc, desc_size, size, cpu_possible_mask);
+	if (ret)
+		goto err_free_desc;
+
+	for_each_ring_buffer_desc(rb_desc, cpu, desc) {
+		ret = remote_test_load_simple_rb(rb_desc->cpu, rb_desc);
+		if (ret)
+			goto err;
+	}
+
+	remote_test_buffer_desc = desc;
+
+	return remote_test_buffer_desc;
+
+err:
+	for_each_ring_buffer_desc(rb_desc, cpu, remote_test_buffer_desc)
+		remote_test_unload_simple_rb(rb_desc->cpu);
+	trace_remote_free_buffer(remote_test_buffer_desc);
+
+err_free_desc:
+	kfree(desc);
+
+err_unlock_cpus:
+	cpus_read_unlock();
+
+	return ERR_PTR(ret);
+}
+
+static void remote_test_unload(struct trace_buffer_desc *desc, void *unused)
+{
+	struct ring_buffer_desc *rb_desc;
+	int cpu;
+
+	if (WARN_ON(desc != remote_test_buffer_desc))
+		return;
+
+	for_each_ring_buffer_desc(rb_desc, cpu, desc)
+		remote_test_unload_simple_rb(rb_desc->cpu);
+
+	remote_test_buffer_desc = NULL;
+	trace_remote_free_buffer(desc);
+	kfree(desc);
+}
+
+static int remote_test_enable_tracing(bool enable, void *unused)
+{
+	struct ring_buffer_desc *rb_desc;
+	int cpu;
+
+	if (!remote_test_buffer_desc)
+		return -ENODEV;
+
+	for_each_ring_buffer_desc(rb_desc, cpu, remote_test_buffer_desc)
+		WARN_ON(simple_ring_buffer_enable_tracing(*per_cpu_ptr(&simple_rbs, rb_desc->cpu),
+							  enable));
+	return 0;
+}
+
+static int remote_test_swap_reader_page(unsigned int cpu, void *unused)
+{
+	struct simple_rb_per_cpu *cpu_buffer;
+
+	if (cpu >= NR_CPUS)
+		return -EINVAL;
+
+	cpu_buffer = *per_cpu_ptr(&simple_rbs, cpu);
+	if (!cpu_buffer)
+		return -EINVAL;
+
+	return simple_ring_buffer_swap_reader_page(cpu_buffer);
+}
+
+static int remote_test_reset(unsigned int cpu, void *unused)
+{
+	struct simple_rb_per_cpu *cpu_buffer;
+
+	if (cpu >= NR_CPUS)
+		return -EINVAL;
+
+	cpu_buffer = *per_cpu_ptr(&simple_rbs, cpu);
+	if (!cpu_buffer)
+		return -EINVAL;
+
+	return simple_ring_buffer_reset(cpu_buffer);
+}
+
+static int remote_test_enable_event(unsigned short id, bool enable, void *unused)
+{
+	if (id != REMOTE_TEST_EVENT_ID)
+		return -EINVAL;
+
+	/*
+	 * Let's just use the struct remote_event enabled field that is turned on and off by
+	 * trace_remote. This is a bit racy but good enough for a simple test module.
+	 */
+	return 0;
+}
+
+static ssize_t
+write_event_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *pos)
+{
+	struct remote_event_format_selftest *evt_test;
+	struct simple_rb_per_cpu *cpu_buffer;
+	unsigned long val;
+	int ret;
+
+	ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&simple_rbs_lock);
+
+	if (!remote_event_selftest.enabled)
+		return -ENODEV;
+
+	cpu_buffer = *this_cpu_ptr(&simple_rbs);
+	if (!cpu_buffer)
+		return -ENODEV;
+
+	evt_test = simple_ring_buffer_reserve(cpu_buffer,
+					      sizeof(struct remote_event_format_selftest),
+					      trace_clock_global());
+	if (!evt_test)
+		return -ENODEV;
+
+	evt_test->hdr.id = REMOTE_TEST_EVENT_ID;
+	evt_test->id = val;
+
+	simple_ring_buffer_commit(cpu_buffer);
+
+	return cnt;
+}
+
+static const struct file_operations write_event_fops = {
+	.write	= write_event_write,
+};
+
+static int remote_test_init_tracefs(struct dentry *d, void *unused)
+{
+	return tracefs_create_file("write_event", 0200, d, NULL, &write_event_fops) ?
+		0 : -ENOMEM;
+}
+
+static struct trace_remote_callbacks trace_remote_callbacks = {
+	.init			= remote_test_init_tracefs,
+	.load_trace_buffer	= remote_test_load,
+	.unload_trace_buffer	= remote_test_unload,
+	.enable_tracing		= remote_test_enable_tracing,
+	.swap_reader_page	= remote_test_swap_reader_page,
+	.reset			= remote_test_reset,
+	.enable_event		= remote_test_enable_event,
+};
+
+static int __init remote_test_init(void)
+{
+	return trace_remote_register("test", &trace_remote_callbacks, NULL,
+				     &remote_event_selftest, 1);
+}
+
+module_init(remote_test_init);
+
+MODULE_DESCRIPTION("Test module for the trace remote interface");
+MODULE_AUTHOR("Vincent Donnefort");
+MODULE_LICENSE("GPL");
diff --git a/kernel/trace/remote_test_events.h b/kernel/trace/remote_test_events.h
new file mode 100644
index 000000000000..26b93b3406fc
--- /dev/null
+++ b/kernel/trace/remote_test_events.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#define REMOTE_TEST_EVENT_ID 1
+
+REMOTE_EVENT(selftest, REMOTE_TEST_EVENT_ID,
+	RE_STRUCT(
+		re_field(u64, id)
+	),
+	RE_PRINTK("id=%llu", __entry->id)
+);
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:36:09 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:36:09 +0000
Subject: [PATCH v9 16/30] Documentation: tracing: Add tracing remotes
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-17-vdonnefort@google.com>

Add documentation about the newly introduced tracing remotes framework.

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/Documentation/trace/index.rst b/Documentation/trace/index.rst
index b4a429dc4f7a..d77ffb7e2d08 100644
--- a/Documentation/trace/index.rst
+++ b/Documentation/trace/index.rst
@@ -90,6 +90,17 @@ interactions.
    user_events
    uprobetracer
 
+Remote Tracing
+--------------
+
+This section covers the framework to read compatible ring-buffers, written by
+entities outside of the kernel (most likely firmware or hypervisor)
+
+.. toctree::
+   :maxdepth: 1
+
+   remotes
+
 Additional Resources
 --------------------
 
diff --git a/Documentation/trace/remotes.rst b/Documentation/trace/remotes.rst
new file mode 100644
index 000000000000..e7fb3ee96c30
--- /dev/null
+++ b/Documentation/trace/remotes.rst
@@ -0,0 +1,59 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===============
+Tracing Remotes
+===============
+
+:Author: Vincent Donnefort <vdonnefort at google.com>
+
+Overview
+========
+A trace remote relies on ring-buffer remotes to read and control compatible
+tracing buffers, written by entity such as firmware or hypervisor.
+
+Once registered, a tracefs instance will appear for this remote in the Tracefs
+directory **remotes/**. This remote can be read and controlled using the same
+files as regular Tracefs instances such as **trace_pipe**, **tracing_on** or
+**trace**.
+
+Register a remote
+=================
+A remote must provide a set of callbacks `struct trace_remote_callbacks` whom
+description can be found below. Those callbacks allows Tracefs to enable and
+disable tracing and events, to load and unload a tracing buffer (a set of
+ring-buffers) and to swap a reader page with the head page, which enables
+consuming reading.
+
+.. kernel-doc:: include/linux/trace_remote.h
+
+Declare a remote event
+======================
+Macros are provided to ease the declaration of remote events, in a similar
+fashion to in-kernel events. A declaration must provide an ID, a description of
+the event arguments and how to print the event:
+
+.. code-block:: c
+
+	REMOTE_EVENT(foo, EVENT_FOO_ID,
+		RE_STRUCT(
+			re_field(u64, bar)
+		),
+		RE_PRINTK("bar=%lld", __entry->bar)
+	);
+
+Then those events must be declared in a C file with the following:
+
+.. code-block:: c
+
+	#define REMOTE_EVENT_INCLUDE_FILE foo_events.h
+	#include <trace/define_remote_events.h>
+
+This will provide a `struct remote_event remote_event_foo` that can be given to
+`trace_remote_register`.
+
+Simple ring-buffer
+==================
+A simple implementation for a ring-buffer writer can be found in
+kernel/trace/simple_ring_buffer.c.
+
+.. kernel-doc:: include/linux/simple_ring_buffer.h
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:36:08 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:36:08 +0000
Subject: [PATCH v9 15/30] tracing: selftests: Add trace remote tests
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-16-vdonnefort@google.com>

Exercise the tracefs interface for trace remote with a set of tests to
check:

  * loading/unloading (unloading.tc)
  * reset (reset.tc)
  * size changes (buffer_size.tc)
  * consuming read (trace_pipe.tc)
  * non-consuming read (trace.tc)

Cc: Shuah Khan <skhan at linuxfoundation.org>
Cc: linux-kselftest at vger.kernel.org
Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/tools/testing/selftests/ftrace/test.d/remotes/buffer_size.tc b/tools/testing/selftests/ftrace/test.d/remotes/buffer_size.tc
new file mode 100644
index 000000000000..1a43280ffa97
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/remotes/buffer_size.tc
@@ -0,0 +1,25 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Test trace remote buffer size
+# requires: remotes/test
+
+. $TEST_DIR/remotes/functions
+
+test_buffer_size()
+{
+    echo 0 > tracing_on
+    assert_unloaded
+
+    echo 4096 > buffer_size_kb
+    echo 1 > tracing_on
+    assert_loaded
+
+    echo 0 > tracing_on
+    echo 7 > buffer_size_kb
+}
+
+if [ -z "$SOURCE_REMOTE_TEST" ]; then
+    set -e
+    setup_remote_test
+    test_buffer_size
+fi
diff --git a/tools/testing/selftests/ftrace/test.d/remotes/functions b/tools/testing/selftests/ftrace/test.d/remotes/functions
new file mode 100644
index 000000000000..97a09d564a34
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/remotes/functions
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: GPL-2.0
+
+setup_remote()
+{
+	local name=$1
+
+	[ -e $TRACING_DIR/remotes/$name/write_event ] || exit_unresolved
+
+	cd remotes/$name/
+	echo 0 > tracing_on
+	clear_trace
+	echo 7 > buffer_size_kb
+	echo 0 > events/enable
+	echo 1 > events/$name/selftest/enable
+	echo 1 > tracing_on
+}
+
+setup_remote_test()
+{
+	[ -d $TRACING_DIR/remotes/test/ ] || modprobe remote_test || exit_unresolved
+
+	setup_remote "test"
+}
+
+assert_loaded()
+{
+	grep -q "(loaded)" buffer_size_kb
+}
+
+assert_unloaded()
+{
+	grep -q "(unloaded)" buffer_size_kb
+}
+
+dump_trace_pipe()
+{
+    output=$(mktemp $TMPDIR/remote_test.XXXXXX)
+    cat trace_pipe > $output &
+    pid=$!
+    sleep 1
+    kill -1 $pid
+
+    echo $output
+}
+
+check_trace()
+{
+	start_id="$1"
+	end_id="$2"
+	file="$3"
+
+	# Ensure the file is not empty
+	test -n "$(head $file)"
+
+	prev_ts=0
+	id=0
+
+	# Only keep <timestamp> <id>
+	tmp=$(mktemp $TMPDIR/remote_test.XXXXXX)
+	sed -e 's/\[[0-9]*\]\s*\([0-9]*.[0-9]*\): [a-z]* id=\([0-9]*\)/\1 \2/' $file > $tmp
+
+	while IFS= read -r line; do
+		ts=$(echo $line | cut -d ' ' -f 1)
+		id=$(echo $line | cut -d ' ' -f 2)
+
+		test $(echo "$ts>$prev_ts" | bc) -eq 1
+		test $id -eq $start_id
+
+		prev_ts=$ts
+		start_id=$((start_id + 1))
+	done < $tmp
+
+	test $id -eq $end_id
+	rm $tmp
+}
+
+get_cpu_ids()
+{
+    sed -n 's/^processor\s*:\s*\([0-9]\+\).*/\1/p' /proc/cpuinfo
+}
+
+get_page_size() {
+    sed -ne 's/^.*data.*size:\([0-9][0-9]*\).*/\1/p' events/header_page
+}
+
+get_selftest_event_size() {
+    sed -ne 's/^.*field:.*;.*size:\([0-9][0-9]*\);.*/\1/p' events/*/selftest/format | awk '{s+=$1} END {print s}'
+}
diff --git a/tools/testing/selftests/ftrace/test.d/remotes/reset.tc b/tools/testing/selftests/ftrace/test.d/remotes/reset.tc
new file mode 100644
index 000000000000..4d176349b2bc
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/remotes/reset.tc
@@ -0,0 +1,90 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Test trace remote reset
+# requires: remotes/test
+
+. $TEST_DIR/remotes/functions
+
+check_reset()
+{
+    write_event_path="write_event"
+    taskset=""
+
+    clear_trace
+
+    # Is the buffer empty?
+    output=$(dump_trace_pipe)
+    test $(wc -l $output | cut -d ' ' -f1) -eq 0
+
+    if $(echo $(pwd) | grep -q "per_cpu/cpu"); then
+        write_event_path="../../write_event"
+        cpu_id=$(echo $(pwd) | sed -e 's/.*per_cpu\/cpu//')
+        taskset="taskset -c $cpu_id"
+    fi
+    rm $output
+
+    # Can we properly write a new event?
+    $taskset echo 7890 > $write_event_path
+    output=$(dump_trace_pipe)
+    test $(wc -l $output | cut -d ' ' -f1) -eq 1
+    grep -q "id=7890" $output
+    rm $output
+}
+
+test_global_interface()
+{
+    output=$(mktemp $TMPDIR/remote_test.XXXXXX)
+
+    # Confidence check
+    echo 123456 > write_event
+    output=$(dump_trace_pipe)
+    grep -q "id=123456" $output
+    rm $output
+
+    # Reset single event
+    echo 1 > write_event
+    check_reset
+
+    # Reset lost events
+    for i in $(seq 1 10000); do
+        echo 1 > write_event
+    done
+    check_reset
+}
+
+test_percpu_interface()
+{
+    [ "$(get_cpu_ids | wc -l)" -ge 2 ] || return 0
+
+    for cpu in $(get_cpu_ids); do
+        taskset -c $cpu echo 1 > write_event
+    done
+
+    check_non_empty=0
+    for cpu in $(get_cpu_ids); do
+        cd per_cpu/cpu$cpu/
+
+        if [ $check_non_empty -eq 0 ]; then
+            check_reset
+            check_non_empty=1
+        else
+            # Check we have only reset 1 CPU
+            output=$(dump_trace_pipe)
+            test $(wc -l $output | cut -d ' ' -f1) -eq 1
+            rm $output
+        fi
+        cd -
+    done
+}
+
+test_reset()
+{
+    test_global_interface
+    test_percpu_interface
+}
+
+if [ -z "$SOURCE_REMOTE_TEST" ]; then
+    set -e
+    setup_remote_test
+    test_reset
+fi
diff --git a/tools/testing/selftests/ftrace/test.d/remotes/trace.tc b/tools/testing/selftests/ftrace/test.d/remotes/trace.tc
new file mode 100644
index 000000000000..081133ec45ff
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/remotes/trace.tc
@@ -0,0 +1,127 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Test trace remote non-consuming read
+# requires: remotes/test
+
+. $TEST_DIR/remotes/functions
+
+test_trace()
+{
+	echo 0 > tracing_on
+    assert_unloaded
+
+    echo 7 > buffer_size_kb
+    echo 1 > tracing_on
+    assert_loaded
+
+    # Simple test: Emit few events and try to read them
+    for i in $(seq 1 8); do
+        echo $i > write_event
+    done
+
+    check_trace 1 8 trace
+
+    #
+    # Test interaction with consuming read
+    #
+
+    cat trace_pipe > /dev/null &
+    pid=$!
+
+    sleep 1
+    kill $pid
+
+    test $(wc -l < trace) -eq 0
+
+    for i in $(seq 16 32); do
+        echo $i > write_event
+    done
+
+    check_trace 16 32 trace
+
+    #
+    # Test interaction with reset
+    #
+
+    echo 0 > trace
+
+    test $(wc -l < trace) -eq 0
+
+    for i in $(seq 1 8); do
+        echo $i > write_event
+    done
+
+    check_trace 1 8 trace
+
+    #
+    # Test interaction with lost events
+    #
+
+    # Ensure the writer is not on the reader page by reloading the buffer
+    echo 0 > tracing_on
+    echo 0 > trace
+    assert_unloaded
+    echo 1 > tracing_on
+    assert_loaded
+
+    # Ensure ring-buffer overflow by emitting events from the same CPU
+    for cpu in $(get_cpu_ids); do
+        break
+    done
+
+    events_per_page=$(($(get_page_size) / $(get_selftest_event_size))) # Approx: does not take TS into account
+    nr_events=$(($events_per_page * 2))
+    for i in $(seq 1 $nr_events); do
+        taskset -c $cpu echo $i > write_event
+    done
+
+    id=$(sed -n -e '1s/\[[0-9]*\]\s*[0-9]*.[0-9]*: [a-z]* id=\([0-9]*\)/\1/p' trace)
+    test $id -ne 1
+
+    check_trace $id $nr_events trace
+
+    #
+    # Test per-CPU interface
+    #
+    echo 0 > trace
+
+    for cpu in $(get_cpu_ids) ; do
+        taskset -c $cpu echo $cpu > write_event
+    done
+
+    for cpu in $(get_cpu_ids); do
+        cd per_cpu/cpu$cpu/
+
+        check_trace $cpu $cpu trace
+
+        cd - > /dev/null
+    done
+
+    #
+    # Test with hotplug
+    #
+
+    [ "$(get_cpu_ids | wc -l)" -ge 2 ] || return 0
+
+    echo 0 > trace
+
+    for cpu in $(get_cpu_ids); do
+        echo 0 > /sys/devices/system/cpu/cpu$cpu/online
+        break
+    done
+
+    for i in $(seq 1 8); do
+        echo $i > write_event
+    done
+
+    check_trace 1 8 trace
+
+    echo 1 > /sys/devices/system/cpu/cpu$cpu/online
+}
+
+if [ -z "$SOURCE_REMOTE_TEST" ]; then
+    set -e
+
+    setup_remote_test
+    test_trace
+fi
diff --git a/tools/testing/selftests/ftrace/test.d/remotes/trace_pipe.tc b/tools/testing/selftests/ftrace/test.d/remotes/trace_pipe.tc
new file mode 100644
index 000000000000..d28eaee10c7c
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/remotes/trace_pipe.tc
@@ -0,0 +1,127 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Test trace remote consuming read
+# requires: remotes/test
+
+. $TEST_DIR/remotes/functions
+
+test_trace_pipe()
+{
+    echo 0 > tracing_on
+    assert_unloaded
+
+    # Emit events from the same CPU
+    for cpu in $(get_cpu_ids); do
+        break
+    done
+
+    #
+    # Simple test: Emit enough events to fill few pages
+    #
+
+    echo 1024 > buffer_size_kb
+    echo 1 > tracing_on
+    assert_loaded
+
+    events_per_page=$(($(get_page_size) / $(get_selftest_event_size)))
+    nr_events=$(($events_per_page * 4))
+
+    output=$(mktemp $TMPDIR/remote_test.XXXXXX)
+
+    cat trace_pipe > $output &
+    pid=$!
+
+    for i in $(seq 1 $nr_events); do
+        taskset -c $cpu echo $i > write_event
+    done
+
+    echo 0 > tracing_on
+    sleep 1
+    kill $pid
+
+    check_trace 1 $nr_events $output
+
+    rm $output
+
+    #
+    # Test interaction with lost events
+    #
+
+    assert_unloaded
+    echo 7 > buffer_size_kb
+    echo 1 > tracing_on
+    assert_loaded
+
+    nr_events=$((events_per_page * 2))
+    for i in $(seq 1 $nr_events); do
+        taskset -c $cpu echo $i > write_event
+    done
+
+    output=$(dump_trace_pipe)
+
+    lost_events=$(sed -n -e '1s/CPU:.*\[LOST \([0-9]*\) EVENTS\]/\1/p' $output)
+    test -n "$lost_events"
+
+    id=$(sed -n -e '2s/\[[0-9]*\]\s*[0-9]*.[0-9]*: [a-z]* id=\([0-9]*\)/\1/p' $output)
+    test "$id" -eq $(($lost_events + 1))
+
+    # Drop [LOST EVENTS] line
+    sed -i '1d' $output
+
+    check_trace $id $nr_events $output
+
+    rm $output
+
+    #
+    # Test per-CPU interface
+    #
+
+    echo 0 > trace
+    echo 1 > tracing_on
+
+    for cpu in $(get_cpu_ids); do
+        taskset -c $cpu echo $cpu > write_event
+    done
+
+    for cpu in $(get_cpu_ids); do
+        cd per_cpu/cpu$cpu/
+        output=$(dump_trace_pipe)
+
+        check_trace $cpu $cpu $output
+
+        rm $output
+        cd - > /dev/null
+    done
+
+    #
+    # Test interaction with hotplug
+    #
+
+    [ "$(get_cpu_ids | wc -l)" -ge 2 ] || return 0
+
+    echo 0 > trace
+
+    for cpu in $(get_cpu_ids); do
+        echo 0 > /sys/devices/system/cpu/cpu$cpu/online
+        break
+    done
+
+    for i in $(seq 1 8); do
+        echo $i > write_event
+    done
+
+    output=$(dump_trace_pipe)
+
+    check_trace 1 8 $output
+
+    rm $output
+
+    echo 1 > /sys/devices/system/cpu/cpu$cpu/online
+}
+
+if [ -z "$SOURCE_REMOTE_TEST" ]; then
+    set -e
+
+    setup_remote_test
+    test_trace_pipe
+fi
diff --git a/tools/testing/selftests/ftrace/test.d/remotes/unloading.tc b/tools/testing/selftests/ftrace/test.d/remotes/unloading.tc
new file mode 100644
index 000000000000..cac2190183f6
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/remotes/unloading.tc
@@ -0,0 +1,41 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Test trace remote unloading
+# requires: remotes/test
+
+. $TEST_DIR/remotes/functions
+
+test_unloading()
+{
+    # No reader, writing
+    assert_loaded
+
+    # No reader, no writing
+    echo 0 > tracing_on
+    assert_unloaded
+
+    # 1 reader, no writing
+    cat trace_pipe &
+    pid=$!
+    sleep 1
+    assert_loaded
+    kill $pid
+    assert_unloaded
+
+    # No reader, no writing, events
+    echo 1 > tracing_on
+    echo 1 > write_event
+    echo 0 > tracing_on
+    assert_loaded
+
+    # Test reset
+    clear_trace
+    assert_unloaded
+}
+
+if [ -z "$SOURCE_REMOTE_TEST" ]; then
+    set -e
+
+    setup_remote_test
+    test_unloading
+fi
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:36:10 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:36:10 +0000
Subject: [PATCH v9 17/30] tracing: load/unload page callbacks for simple_ring_buffer
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-18-vdonnefort@google.com>

Add load/unload callback used for each admitted page in the ring-buffer.
This will be later useful for the pKVM hypervisor which uses a different
VA space and need to dynamically map/unmap the ring-buffer pages.

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/include/linux/simple_ring_buffer.h b/include/linux/simple_ring_buffer.h
index f324df2f875b..ecd0e988c699 100644
--- a/include/linux/simple_ring_buffer.h
+++ b/include/linux/simple_ring_buffer.h
@@ -110,4 +110,11 @@ int simple_ring_buffer_reset(struct simple_rb_per_cpu *cpu_buffer);
  */
 int simple_ring_buffer_swap_reader_page(struct simple_rb_per_cpu *cpu_buffer);
 
+int __simple_ring_buffer_init(struct simple_rb_per_cpu *cpu_buffer,
+			      struct simple_buffer_page *bpages,
+			      const struct ring_buffer_desc *desc,
+			      void *(*load_page)(unsigned long va),
+			      void (*unload_page)(void *va));
+void __simple_ring_buffer_unload(struct simple_rb_per_cpu *cpu_buffer,
+				 void (*unload_page)(void *));
 #endif
diff --git a/kernel/trace/simple_ring_buffer.c b/kernel/trace/simple_ring_buffer.c
index 1d1f40c8c6d8..f01386975266 100644
--- a/kernel/trace/simple_ring_buffer.c
+++ b/kernel/trace/simple_ring_buffer.c
@@ -71,7 +71,7 @@ static void simple_bpage_reset(struct simple_buffer_page *bpage)
 	local_set(&bpage->page->commit, 0);
 }
 
-static void simple_bpage_init(struct simple_buffer_page *bpage, unsigned long page)
+static void simple_bpage_init(struct simple_buffer_page *bpage, void *page)
 {
 	INIT_LIST_HEAD(&bpage->link);
 	bpage->page = (struct buffer_data_page *)page;
@@ -342,10 +342,15 @@ int simple_ring_buffer_reset(struct simple_rb_per_cpu *cpu_buffer)
 }
 EXPORT_SYMBOL_GPL(simple_ring_buffer_reset);
 
-int simple_ring_buffer_init(struct simple_rb_per_cpu *cpu_buffer, struct simple_buffer_page *bpages,
-			    const struct ring_buffer_desc *desc)
+int __simple_ring_buffer_init(struct simple_rb_per_cpu *cpu_buffer,
+			      struct simple_buffer_page *bpages,
+			      const struct ring_buffer_desc *desc,
+			      void *(*load_page)(unsigned long va),
+			      void (*unload_page)(void *va))
 {
 	struct simple_buffer_page *bpage = bpages;
+	int ret = 0;
+	void *page;
 	int i;
 
 	/* At least 1 reader page and two pages in the ring-buffer */
@@ -354,15 +359,22 @@ int simple_ring_buffer_init(struct simple_rb_per_cpu *cpu_buffer, struct simple_
 
 	memset(cpu_buffer, 0, sizeof(*cpu_buffer));
 
-	cpu_buffer->bpages = bpages;
+	cpu_buffer->meta = load_page(desc->meta_va);
+	if (!cpu_buffer->meta)
+		return -EINVAL;
 
-	cpu_buffer->meta = (void *)desc->meta_va;
 	memset(cpu_buffer->meta, 0, sizeof(*cpu_buffer->meta));
 	cpu_buffer->meta->meta_page_size = PAGE_SIZE;
 	cpu_buffer->meta->nr_subbufs = cpu_buffer->nr_pages;
 
 	/* The reader page is not part of the ring initially */
-	simple_bpage_init(bpage, desc->page_va[0]);
+	page = load_page(desc->page_va[0]);
+	if (!page) {
+		unload_page(cpu_buffer->meta);
+		return -EINVAL;
+	}
+
+	simple_bpage_init(bpage, page);
 	bpage->id = 0;
 
 	cpu_buffer->nr_pages = 1;
@@ -372,7 +384,13 @@ int simple_ring_buffer_init(struct simple_rb_per_cpu *cpu_buffer, struct simple_
 	cpu_buffer->head_page = bpage + 1;
 
 	for (i = 1; i < desc->nr_page_va; i++) {
-		simple_bpage_init(++bpage, desc->page_va[i]);
+		page = load_page(desc->page_va[i]);
+		if (!page) {
+			ret = -EINVAL;
+			break;
+		}
+
+		simple_bpage_init(++bpage, page);
 
 		bpage->link.next = &(bpage + 1)->link;
 		bpage->link.prev = &(bpage - 1)->link;
@@ -381,6 +399,14 @@ int simple_ring_buffer_init(struct simple_rb_per_cpu *cpu_buffer, struct simple_
 		cpu_buffer->nr_pages = i + 1;
 	}
 
+	if (ret) {
+		for (i--; i >= 0; i--)
+			unload_page((void *)desc->page_va[i]);
+		unload_page(cpu_buffer->meta);
+
+		return ret;
+	}
+
 	/* Close the ring */
 	bpage->link.next = &cpu_buffer->tail_page->link;
 	cpu_buffer->tail_page->link.prev = &bpage->link;
@@ -388,21 +414,48 @@ int simple_ring_buffer_init(struct simple_rb_per_cpu *cpu_buffer, struct simple_
 	/* The last init'ed page points to the head page */
 	simple_bpage_set_head_link(bpage);
 
+	cpu_buffer->bpages = bpages;
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(simple_ring_buffer_init);
 
-void simple_ring_buffer_unload(struct simple_rb_per_cpu *cpu_buffer)
+static void *__load_page(unsigned long page)
 {
+	return (void *)page;
+}
+
+static void __unload_page(void *page) { }
+
+int simple_ring_buffer_init(struct simple_rb_per_cpu *cpu_buffer, struct simple_buffer_page *bpages,
+			    const struct ring_buffer_desc *desc)
+{
+	return __simple_ring_buffer_init(cpu_buffer, bpages, desc, __load_page, __unload_page);
+}
+
+void __simple_ring_buffer_unload(struct simple_rb_per_cpu *cpu_buffer,
+				 void (*unload_page)(void *))
+{
+	int p;
+
 	if (!simple_rb_loaded(cpu_buffer))
 		return;
 
 	simple_rb_enable_tracing(cpu_buffer, false);
 
+	unload_page(cpu_buffer->meta);
+	for (p = 0; p < cpu_buffer->nr_pages; p++)
+		unload_page(cpu_buffer->bpages[p].page);
+
 	cpu_buffer->bpages = NULL;
 }
 EXPORT_SYMBOL_GPL(simple_ring_buffer_unload);
 
+void simple_ring_buffer_unload(struct simple_rb_per_cpu *cpu_buffer)
+{
+	return __simple_ring_buffer_unload(cpu_buffer, __unload_page);
+}
+
 int simple_ring_buffer_enable_tracing(struct simple_rb_per_cpu *cpu_buffer, bool enable)
 {
 	if (!simple_rb_loaded(cpu_buffer))
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:36:12 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:36:12 +0000
Subject: [PATCH v9 19/30] KVM: arm64: Add PKVM_DISABLE_STAGE2_ON_PANIC
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-20-vdonnefort@google.com>

On NVHE_EL2_DEBUG, when using pKVM, the host stage-2 is relaxed to grant
the kernel access to the stacktrace, hypervisor bug table and text to
symbolize addresses. This is unsafe for production. In preparation for
adding more debug options to NVHE_EL2_DEBUG, decouple the stage-2
relaxation into a separate option.

While at it, rename PROTECTED_NVHE_STACKTRACE into PKVM_STACKTRACE,
following the same naming scheme as PKVM_DISABLE_STAGE2_ON_PANIC.

Cc: Kalesh Singh <kaleshsingh at google.com>
Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index 4f803fd1c99a..6498dec00fe9 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -43,9 +43,27 @@ menuconfig KVM
 
 	  If unsure, say N.
 
+if KVM
+
+config PTDUMP_STAGE2_DEBUGFS
+	bool "Present the stage-2 pagetables to debugfs"
+	depends on DEBUG_KERNEL
+	depends on DEBUG_FS
+	depends on ARCH_HAS_PTDUMP
+	select PTDUMP
+	default n
+	help
+	  Say Y here if you want to show the stage-2 kernel pagetables
+	  layout in a debugfs file. This information is only useful for kernel developers
+	  who are working in architecture specific areas of the kernel.
+	  It is probably not a good idea to enable this feature in a production
+	  kernel.
+
+	  If in doubt, say N.
+
 config NVHE_EL2_DEBUG
 	bool "Debug mode for non-VHE EL2 object"
-	depends on KVM
+	default n
 	help
 	  Say Y here to enable the debug mode for the non-VHE KVM EL2 object.
 	  Failure reports will BUG() in the hypervisor. This is intended for
@@ -53,10 +71,23 @@ config NVHE_EL2_DEBUG
 
 	  If unsure, say N.
 
-config PROTECTED_NVHE_STACKTRACE
-	bool "Protected KVM hypervisor stacktraces"
-	depends on NVHE_EL2_DEBUG
+if NVHE_EL2_DEBUG
+
+config PKVM_DISABLE_STAGE2_ON_PANIC
+	bool "Disable the host stage-2 on panic"
 	default n
+	help
+	  Relax the host stage-2 on hypervisor panic to allow the kernel to
+	  unwind and symbolize the hypervisor stacktrace. This however tampers
+	  the system security. This is intended for local EL2 hypervisor
+	  development.
+
+	  If unsure, say N.
+
+config PKVM_STACKTRACE
+	bool "Protected KVM hypervisor stacktraces"
+	depends on PKVM_DISABLE_STAGE2_ON_PANIC
+	default y
 	help
 	  Say Y here to enable pKVM hypervisor stacktraces on hyp_panic()
 
@@ -66,21 +97,6 @@ config PROTECTED_NVHE_STACKTRACE
 
 	  If unsure, or not using protected nVHE (pKVM), say N.
 
-config PTDUMP_STAGE2_DEBUGFS
-	bool "Present the stage-2 pagetables to debugfs"
-	depends on KVM
-	depends on DEBUG_KERNEL
-	depends on DEBUG_FS
-	depends on ARCH_HAS_PTDUMP
-	select PTDUMP
-	default n
-	help
-	  Say Y here if you want to show the stage-2 kernel pagetables
-	  layout in a debugfs file. This information is only useful for kernel developers
-	  who are working in architecture specific areas of the kernel.
-	  It is probably not a good idea to enable this feature in a production
-	  kernel.
-
-	  If in doubt, say N.
-
+endif # NVHE_EL2_DEBUG
+endif # KVM
 endif # VIRTUALIZATION
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index cc7d5d1709cb..54aedf93c78b 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -539,7 +539,7 @@ void __noreturn __cold nvhe_hyp_panic_handler(u64 esr, u64 spsr,
 
 		/* All hyp bugs, including warnings, are treated as fatal. */
 		if (!is_protected_kvm_enabled() ||
-		    IS_ENABLED(CONFIG_NVHE_EL2_DEBUG)) {
+		    IS_ENABLED(CONFIG_PKVM_DISABLE_STAGE2_ON_PANIC)) {
 			struct bug_entry *bug = find_bug(elr_in_kimg);
 
 			if (bug)
diff --git a/arch/arm64/kvm/hyp/nvhe/host.S b/arch/arm64/kvm/hyp/nvhe/host.S
index eef15b374abb..3092befcd97c 100644
--- a/arch/arm64/kvm/hyp/nvhe/host.S
+++ b/arch/arm64/kvm/hyp/nvhe/host.S
@@ -120,7 +120,7 @@ SYM_FUNC_START(__hyp_do_panic)
 
 	mov	x29, x0
 
-#ifdef CONFIG_NVHE_EL2_DEBUG
+#ifdef PKVM_DISABLE_STAGE2_ON_PANIC
 	/* Ensure host stage-2 is disabled */
 	mrs	x0, hcr_el2
 	bic	x0, x0, #HCR_VM
diff --git a/arch/arm64/kvm/hyp/nvhe/stacktrace.c b/arch/arm64/kvm/hyp/nvhe/stacktrace.c
index 5b6eeab1a774..7c832d60d22b 100644
--- a/arch/arm64/kvm/hyp/nvhe/stacktrace.c
+++ b/arch/arm64/kvm/hyp/nvhe/stacktrace.c
@@ -34,7 +34,7 @@ static void hyp_prepare_backtrace(unsigned long fp, unsigned long pc)
 	stacktrace_info->pc = pc;
 }
 
-#ifdef CONFIG_PROTECTED_NVHE_STACKTRACE
+#ifdef CONFIG_PKVM_STACKTRACE
 #include <asm/stacktrace/nvhe.h>
 
 DEFINE_PER_CPU(unsigned long [NVHE_STACKTRACE_SIZE/sizeof(long)], pkvm_stacktrace);
@@ -134,11 +134,11 @@ static void pkvm_save_backtrace(unsigned long fp, unsigned long pc)
 
 	unwind(&state, pkvm_save_backtrace_entry, &idx);
 }
-#else /* !CONFIG_PROTECTED_NVHE_STACKTRACE */
+#else /* !CONFIG_PKVM_STACKTRACE */
 static void pkvm_save_backtrace(unsigned long fp, unsigned long pc)
 {
 }
-#endif /* CONFIG_PROTECTED_NVHE_STACKTRACE */
+#endif /* CONFIG_PKVM_STACKTRACE */
 
 /*
  * kvm_nvhe_prepare_backtrace - prepare to dump the nVHE backtrace
diff --git a/arch/arm64/kvm/stacktrace.c b/arch/arm64/kvm/stacktrace.c
index af5eec681127..9724c320126b 100644
--- a/arch/arm64/kvm/stacktrace.c
+++ b/arch/arm64/kvm/stacktrace.c
@@ -197,7 +197,7 @@ static void hyp_dump_backtrace(unsigned long hyp_offset)
 	kvm_nvhe_dump_backtrace_end();
 }
 
-#ifdef CONFIG_PROTECTED_NVHE_STACKTRACE
+#ifdef CONFIG_PKVM_STACKTRACE
 DECLARE_KVM_NVHE_PER_CPU(unsigned long [NVHE_STACKTRACE_SIZE/sizeof(long)],
 			 pkvm_stacktrace);
 
@@ -225,12 +225,12 @@ static void pkvm_dump_backtrace(unsigned long hyp_offset)
 		kvm_nvhe_dump_backtrace_entry((void *)hyp_offset, stacktrace[i]);
 	kvm_nvhe_dump_backtrace_end();
 }
-#else	/* !CONFIG_PROTECTED_NVHE_STACKTRACE */
+#else	/* !CONFIG_PKVM_STACKTRACE */
 static void pkvm_dump_backtrace(unsigned long hyp_offset)
 {
-	kvm_err("Cannot dump pKVM nVHE stacktrace: !CONFIG_PROTECTED_NVHE_STACKTRACE\n");
+	kvm_err("Cannot dump pKVM nVHE stacktrace: !CONFIG_PKVM_STACKTRACE\n");
 }
-#endif /* CONFIG_PROTECTED_NVHE_STACKTRACE */
+#endif /* CONFIG_PKVM_STACKTRACE */
 
 /*
  * kvm_nvhe_dump_backtrace - Dump KVM nVHE hypervisor backtrace.
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:36:11 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:36:11 +0000
Subject: [PATCH v9 18/30] tracing: Check for undefined symbols in simple_ring_buffer
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-19-vdonnefort@google.com>

The simple_ring_buffer implementation must remain simple enough to be
used by the pKVM hypervisor. Prevent the object build if unresolved
symbols are found.

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index 53534447e70b..38523ea2e19b 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -114,4 +114,20 @@ obj-$(CONFIG_TRACE_REMOTE) += trace_remote.o
 obj-$(CONFIG_SIMPLE_RING_BUFFER) += simple_ring_buffer.o
 obj-$(CONFIG_TRACE_REMOTE_TEST) += remote_test.o
 
+#
+# simple_ring_buffer is used by the pKVM hypervisor which does not have access
+# to all kernel symbols. Fail the build if forbidden symbols are found.
+#
+UNDEFINED_ALLOWLIST := memset alt_cb_patch_nops __x86 __ubsan __asan __kasan __gcov __aeabi_unwind
+UNDEFINED_ALLOWLIST += __stack_chk_fail stackleak_track_stack __ref_stack __sanitizer
+UNDEFINED_ALLOWLIST := $(addprefix -e , $(UNDEFINED_ALLOWLIST))
+
+quiet_cmd_check_undefined = NM      $<
+      cmd_check_undefined = test -z "`$(NM) -u $< | grep -v $(UNDEFINED_ALLOWLIST)`"
+
+$(obj)/%.o.checked: $(obj)/%.o FORCE
+	$(call if_changed,check_undefined)
+
+always-$(CONFIG_SIMPLE_RING_BUFFER) += simple_ring_buffer.o.checked
+
 libftrace-y := ftrace.o
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:36:13 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:36:13 +0000
Subject: [PATCH v9 20/30] KVM: arm64: Add clock support to nVHE/pKVM hyp
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-21-vdonnefort@google.com>

In preparation for supporting tracing from the nVHE hyp, add support to
generate timestamps with a clock fed by the CNTCVT counter. The clock
can be kept in sync with the kernel's by updating the slope values. This
will be done later.

As current we do only create a trace clock, make the whole support
dependant on the upcoming CONFIG_NVHE_EL2_TRACING.

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/arch/arm64/kvm/hyp/include/nvhe/clock.h b/arch/arm64/kvm/hyp/include/nvhe/clock.h
new file mode 100644
index 000000000000..9f429f5c0664
--- /dev/null
+++ b/arch/arm64/kvm/hyp/include/nvhe/clock.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ARM64_KVM_HYP_NVHE_CLOCK_H
+#define __ARM64_KVM_HYP_NVHE_CLOCK_H
+#include <linux/types.h>
+
+#include <asm/kvm_hyp.h>
+
+#ifdef CONFIG_NVHE_EL2_TRACING
+void trace_clock_update(u32 mult, u32 shift, u64 epoch_ns, u64 epoch_cyc);
+u64 trace_clock(void);
+#else
+static inline void
+trace_clock_update(u32 mult, u32 shift, u64 epoch_ns, u64 epoch_cyc) { }
+static inline u64 trace_clock(void) { return 0; }
+#endif
+#endif
diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile
index a244ec25f8c5..8dc95257c291 100644
--- a/arch/arm64/kvm/hyp/nvhe/Makefile
+++ b/arch/arm64/kvm/hyp/nvhe/Makefile
@@ -17,7 +17,7 @@ ccflags-y += -fno-stack-protector	\
 hostprogs := gen-hyprel
 HOST_EXTRACFLAGS += -I$(objtree)/include
 
-lib-objs := clear_page.o copy_page.o memcpy.o memset.o
+lib-objs := clear_page.o copy_page.o memcpy.o memset.o tishift.o
 lib-objs := $(addprefix ../../../lib/, $(lib-objs))
 
 CFLAGS_switch.nvhe.o += -Wno-override-init
@@ -29,6 +29,7 @@ hyp-obj-y += ../vgic-v3-sr.o ../aarch32.o ../vgic-v2-cpuif-proxy.o ../entry.o \
 	 ../fpsimd.o ../hyp-entry.o ../exception.o ../pgtable.o
 hyp-obj-y += ../../../kernel/smccc-call.o
 hyp-obj-$(CONFIG_LIST_HARDENED) += list_debug.o
+hyp-obj-$(CONFIG_NVHE_EL2_TRACING) += clock.o
 hyp-obj-y += $(lib-objs)
 
 ##
diff --git a/arch/arm64/kvm/hyp/nvhe/clock.c b/arch/arm64/kvm/hyp/nvhe/clock.c
new file mode 100644
index 000000000000..32fc4313fe43
--- /dev/null
+++ b/arch/arm64/kvm/hyp/nvhe/clock.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025 Google LLC
+ * Author: Vincent Donnefort <vdonnefort at google.com>
+ */
+
+#include <nvhe/clock.h>
+
+#include <asm/arch_timer.h>
+#include <asm/div64.h>
+
+static struct clock_data {
+	struct {
+		u32 mult;
+		u32 shift;
+		u64 epoch_ns;
+		u64 epoch_cyc;
+		u64 cyc_overflow64;
+	} data[2];
+	u64 cur;
+} trace_clock_data;
+
+static u64 __clock_mult_uint128(u64 cyc, u32 mult, u32 shift)
+{
+	__uint128_t ns = (__uint128_t)cyc * mult;
+
+	ns >>= shift;
+
+	return (u64)ns;
+}
+
+/* Does not guarantee no reader on the modified bank. */
+void trace_clock_update(u32 mult, u32 shift, u64 epoch_ns, u64 epoch_cyc)
+{
+	struct clock_data *clock = &trace_clock_data;
+	u64 bank = clock->cur ^ 1;
+
+	clock->data[bank].mult			= mult;
+	clock->data[bank].shift			= shift;
+	clock->data[bank].epoch_ns		= epoch_ns;
+	clock->data[bank].epoch_cyc		= epoch_cyc;
+	clock->data[bank].cyc_overflow64	= ULONG_MAX / mult;
+
+	smp_store_release(&clock->cur, bank);
+}
+
+/* Use untrusted host data */
+u64 trace_clock(void)
+{
+	struct clock_data *clock = &trace_clock_data;
+	u64 bank = smp_load_acquire(&clock->cur);
+	u64 cyc, ns;
+
+	cyc = __arch_counter_get_cntvct() - clock->data[bank].epoch_cyc;
+
+	if (likely(cyc < clock->data[bank].cyc_overflow64)) {
+		ns = cyc * clock->data[bank].mult;
+		ns >>= clock->data[bank].shift;
+	} else {
+		ns = __clock_mult_uint128(cyc, clock->data[bank].mult,
+					  clock->data[bank].shift);
+	}
+
+	return (u64)ns + clock->data[bank].epoch_ns;
+}
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:36:18 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:36:18 +0000
Subject: [PATCH v9 25/30] KVM: arm64: Sync boot clock with the nVHE/pKVM hyp
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-26-vdonnefort@google.com>

Configure the hypervisor tracing clock with the kernel boot clock. For
tracing purposes, the boot clock is interesting: it doesn't stop on
suspend. However, it is corrected on a regular basis, which implies the
need to re-evaluate it every once in a while.

Cc: John Stultz <jstultz at google.com>
Cc: Thomas Gleixner <tglx at linutronix.de>
Cc: Stephen Boyd <sboyd at kernel.org>
Cc: Christopher S. Hall <christopher.s.hall at intel.com>
Cc: Richard Cochran <richardcochran at gmail.com>
Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index f83650a7aad9..375607c67285 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -93,6 +93,7 @@ enum __kvm_host_smccc_func {
 	__KVM_HOST_SMCCC_FUNC___tracing_unload,
 	__KVM_HOST_SMCCC_FUNC___tracing_enable,
 	__KVM_HOST_SMCCC_FUNC___tracing_swap_reader,
+	__KVM_HOST_SMCCC_FUNC___tracing_update_clock,
 };
 
 #define DECLARE_KVM_VHE_SYM(sym)	extern char sym[]
diff --git a/arch/arm64/kvm/hyp/include/nvhe/trace.h b/arch/arm64/kvm/hyp/include/nvhe/trace.h
index 7da8788ce527..fd641e1b1c23 100644
--- a/arch/arm64/kvm/hyp/include/nvhe/trace.h
+++ b/arch/arm64/kvm/hyp/include/nvhe/trace.h
@@ -11,6 +11,7 @@ int __tracing_load(unsigned long desc_va, size_t desc_size);
 void __tracing_unload(void);
 int __tracing_enable(bool enable);
 int __tracing_swap_reader(unsigned int cpu);
+void __tracing_update_clock(u32 mult, u32 shift, u64 epoch_ns, u64 epoch_cyc);
 #else
 static inline void *tracing_reserve_entry(unsigned long length) { return NULL; }
 static inline void tracing_commit_entry(void) { }
@@ -19,5 +20,6 @@ static inline int __tracing_load(unsigned long desc_va, size_t desc_size) { retu
 static inline void __tracing_unload(void) { }
 static inline int __tracing_enable(bool enable) { return -ENODEV; }
 static inline int __tracing_swap_reader(unsigned int cpu) { return -ENODEV; }
+static inline void __tracing_update_clock(u32 mult, u32 shift, u64 epoch_ns, u64 epoch_cyc) { }
 #endif
 #endif
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 8b78b29c2069..45b8f70828de 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -613,6 +613,18 @@ static void handle___tracing_swap_reader(struct kvm_cpu_context *host_ctxt)
 	cpu_reg(host_ctxt, 1) = __tracing_swap_reader(cpu);
 }
 
+static void handle___tracing_update_clock(struct kvm_cpu_context *host_ctxt)
+{
+	DECLARE_REG(u32, mult, host_ctxt, 1);
+	DECLARE_REG(u32, shift, host_ctxt, 2);
+	DECLARE_REG(u64, epoch_ns, host_ctxt, 3);
+	DECLARE_REG(u64, epoch_cyc, host_ctxt, 4);
+
+	__tracing_update_clock(mult, shift, epoch_ns, epoch_cyc);
+
+	cpu_reg(host_ctxt, 1) = 0;
+}
+
 typedef void (*hcall_t)(struct kvm_cpu_context *);
 
 #define HANDLE_FUNC(x)	[__KVM_HOST_SMCCC_FUNC_##x] = (hcall_t)handle_##x
@@ -658,6 +670,7 @@ static const hcall_t host_hcall[] = {
 	HANDLE_FUNC(__tracing_unload),
 	HANDLE_FUNC(__tracing_enable),
 	HANDLE_FUNC(__tracing_swap_reader),
+	HANDLE_FUNC(__tracing_update_clock),
 };
 
 static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
diff --git a/arch/arm64/kvm/hyp/nvhe/trace.c b/arch/arm64/kvm/hyp/nvhe/trace.c
index df9d66fcb3c9..97e9f6c1a52c 100644
--- a/arch/arm64/kvm/hyp/nvhe/trace.c
+++ b/arch/arm64/kvm/hyp/nvhe/trace.c
@@ -271,3 +271,19 @@ int __tracing_swap_reader(unsigned int cpu)
 
 	return ret;
 }
+
+void __tracing_update_clock(u32 mult, u32 shift, u64 epoch_ns, u64 epoch_cyc)
+{
+	int cpu;
+
+	/* After this loop, all CPUs are observing the new bank... */
+	for (cpu = 0; cpu < hyp_nr_cpus; cpu++) {
+		struct simple_rb_per_cpu *simple_rb = per_cpu_ptr(trace_buffer.simple_rbs, cpu);
+
+		while (READ_ONCE(simple_rb->status) == SIMPLE_RB_WRITING)
+			;
+	}
+
+	/* ...we can now override the old one and swap. */
+	trace_clock_update(mult, shift, epoch_ns, epoch_cyc);
+}
diff --git a/arch/arm64/kvm/hyp_trace.c b/arch/arm64/kvm/hyp_trace.c
index 2866effe28ec..1e5fc27f0e9d 100644
--- a/arch/arm64/kvm/hyp_trace.c
+++ b/arch/arm64/kvm/hyp_trace.c
@@ -4,15 +4,133 @@
  * Author: Vincent Donnefort <vdonnefort at google.com>
  */
 
+#include <linux/cpumask.h>
 #include <linux/trace_remote.h>
+#include <linux/tracefs.h>
 #include <linux/simple_ring_buffer.h>
 
+#include <asm/arch_timer.h>
 #include <asm/kvm_host.h>
 #include <asm/kvm_hyptrace.h>
 #include <asm/kvm_mmu.h>
 
 #include "hyp_trace.h"
 
+/* Same 10min used by clocksource when width is more than 32-bits */
+#define CLOCK_MAX_CONVERSION_S	600
+/*
+ * Time to give for the clock init. Long enough to get a good mult/shift
+ * estimation. Short enough to not delay the tracing start too much.
+ */
+#define CLOCK_INIT_MS		100
+/*
+ * Time between clock checks. Must be small enough to catch clock deviation when
+ * it is still tiny.
+ */
+#define CLOCK_UPDATE_MS		500
+
+static struct hyp_trace_clock {
+	u64			cycles;
+	u64			cyc_overflow64;
+	u64			boot;
+	u32			mult;
+	u32			shift;
+	struct delayed_work	work;
+	struct completion	ready;
+	struct mutex		lock;
+	bool			running;
+} hyp_clock;
+
+static void __hyp_clock_work(struct work_struct *work)
+{
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct hyp_trace_clock *hyp_clock;
+	struct system_time_snapshot snap;
+	u64 rate, delta_cycles;
+	u64 boot, delta_boot;
+
+	hyp_clock = container_of(dwork, struct hyp_trace_clock, work);
+
+	ktime_get_snapshot(&snap);
+	boot = ktime_to_ns(snap.boot);
+
+	delta_boot = boot - hyp_clock->boot;
+	delta_cycles = snap.cycles - hyp_clock->cycles;
+
+	/* Compare hyp clock with the kernel boot clock */
+	if (hyp_clock->mult) {
+		u64 err, cur = delta_cycles;
+
+		if (WARN_ON_ONCE(cur >= hyp_clock->cyc_overflow64)) {
+			__uint128_t tmp = (__uint128_t)cur * hyp_clock->mult;
+
+			cur = tmp >> hyp_clock->shift;
+		} else {
+			cur *= hyp_clock->mult;
+			cur >>= hyp_clock->shift;
+		}
+		cur += hyp_clock->boot;
+
+		err = abs_diff(cur, boot);
+		/* No deviation, only update epoch if necessary */
+		if (!err) {
+			if (delta_cycles >= (hyp_clock->cyc_overflow64 >> 1))
+				goto fast_forward;
+
+			goto resched;
+		}
+
+		/* Warn if the error is above tracing precision (1us) */
+		if (err > NSEC_PER_USEC)
+			pr_warn_ratelimited("hyp trace clock off by %lluus\n",
+					    err / NSEC_PER_USEC);
+	}
+
+	rate = div64_u64(delta_cycles * NSEC_PER_SEC, delta_boot);
+
+	clocks_calc_mult_shift(&hyp_clock->mult, &hyp_clock->shift,
+			       rate, NSEC_PER_SEC, CLOCK_MAX_CONVERSION_S);
+
+	/* Add a comfortable 50% margin */
+	hyp_clock->cyc_overflow64 = (U64_MAX / hyp_clock->mult) >> 1;
+
+fast_forward:
+	hyp_clock->cycles = snap.cycles;
+	hyp_clock->boot = boot;
+	kvm_call_hyp_nvhe(__tracing_update_clock, hyp_clock->mult,
+			  hyp_clock->shift, hyp_clock->boot, hyp_clock->cycles);
+	complete(&hyp_clock->ready);
+
+resched:
+	schedule_delayed_work(&hyp_clock->work,
+			      msecs_to_jiffies(CLOCK_UPDATE_MS));
+}
+
+static void hyp_trace_clock_enable(struct hyp_trace_clock *hyp_clock, bool enable)
+{
+	struct system_time_snapshot snap;
+
+	if (hyp_clock->running == enable)
+		return;
+
+	if (!enable) {
+		cancel_delayed_work_sync(&hyp_clock->work);
+		hyp_clock->running = false;
+	}
+
+	ktime_get_snapshot(&snap);
+
+	hyp_clock->boot = ktime_to_ns(snap.boot);
+	hyp_clock->cycles = snap.cycles;
+	hyp_clock->mult = 0;
+
+	init_completion(&hyp_clock->ready);
+	INIT_DELAYED_WORK(&hyp_clock->work, __hyp_clock_work);
+	schedule_delayed_work(&hyp_clock->work, msecs_to_jiffies(CLOCK_INIT_MS));
+	wait_for_completion(&hyp_clock->ready);
+	hyp_clock->running = true;
+}
+
 /* Access to this struct within the trace_remote_callbacks are protected by the trace_remote lock */
 static struct hyp_trace_buffer {
 	struct hyp_trace_desc	*desc;
@@ -183,6 +301,8 @@ static void hyp_trace_unload(struct trace_buffer_desc *desc, void *priv)
 
 static int hyp_trace_enable_tracing(bool enable, void *priv)
 {
+	hyp_trace_clock_enable(&hyp_clock, enable);
+
 	return kvm_call_hyp_nvhe(__tracing_enable, enable);
 }
 
@@ -201,7 +321,22 @@ static int hyp_trace_enable_event(unsigned short id, bool enable, void *priv)
 	return 0;
 }
 
+static int hyp_trace_clock_show(struct seq_file *m, void *v)
+{
+	seq_puts(m, "[boot]\n");
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(hyp_trace_clock);
+
+static int hyp_trace_init_tracefs(struct dentry *d, void *priv)
+{
+	return tracefs_create_file("trace_clock", 0440, d, NULL, &hyp_trace_clock_fops) ?
+		0 : -ENOMEM;
+}
+
 static struct trace_remote_callbacks trace_remote_callbacks = {
+	.init			= hyp_trace_init_tracefs,
 	.load_trace_buffer	= hyp_trace_load,
 	.unload_trace_buffer	= hyp_trace_unload,
 	.enable_tracing		= hyp_trace_enable_tracing,
@@ -212,8 +347,22 @@ static struct trace_remote_callbacks trace_remote_callbacks = {
 
 int __init kvm_hyp_trace_init(void)
 {
+	int cpu;
+
 	if (is_kernel_in_hyp_mode())
 		return 0;
 
+#ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND
+	for_each_possible_cpu(cpu) {
+		const struct arch_timer_erratum_workaround *wa =
+			per_cpu(timer_unstable_counter_workaround, cpu);
+
+		if (wa && wa->read_cntvct_el0) {
+			pr_warn("hyp trace can't handle CNTVCT workaround '%s'\n", wa->desc);
+			return -EOPNOTSUPP;
+		}
+	}
+#endif
+
 	return trace_remote_register("hypervisor", &trace_remote_callbacks, &trace_buffer, NULL, 0);
 }
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:36:14 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:36:14 +0000
Subject: [PATCH v9 21/30] KVM: arm64: Initialise hyp_nr_cpus for nVHE hyp
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-22-vdonnefort@google.com>

Knowing the number of CPUs is necessary for determining the boundaries
of per-cpu variables, which will be used for upcoming hypervisor
tracing. hyp_nr_cpus which stores this value, is only initialised for
the pKVM hypervisor. Make it accessible for the nVHE hypervisor as well.

With the kernel now responsible for initialising hyp_nr_cpus, the
nr_cpus parameter is no longer needed in __pkvm_init.

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index e6be1f5d0967..b169d85458f9 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -128,8 +128,7 @@ void __noreturn __hyp_do_panic(struct kvm_cpu_context *host_ctxt, u64 spsr,
 #ifdef __KVM_NVHE_HYPERVISOR__
 void __pkvm_init_switch_pgd(phys_addr_t pgd, unsigned long sp,
 		void (*fn)(void));
-int __pkvm_init(phys_addr_t phys, unsigned long size, unsigned long nr_cpus,
-		unsigned long *per_cpu_base, u32 hyp_va_bits);
+int __pkvm_init(phys_addr_t phys, unsigned long size, unsigned long *per_cpu_base, u32 hyp_va_bits);
 void __noreturn __host_enter(struct kvm_cpu_context *host_ctxt);
 #endif
 
@@ -146,5 +145,6 @@ extern u64 kvm_nvhe_sym(id_aa64smfr0_el1_sys_val);
 extern unsigned long kvm_nvhe_sym(__icache_flags);
 extern unsigned int kvm_nvhe_sym(kvm_arm_vmid_bits);
 extern unsigned int kvm_nvhe_sym(kvm_host_sve_max_vl);
+extern unsigned long kvm_nvhe_sym(hyp_nr_cpus);
 
 #endif /* __ARM64_KVM_HYP_H__ */
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 052bf0d4d0b0..7ba427f9608c 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -35,6 +35,7 @@
 #include <asm/kvm_arm.h>
 #include <asm/kvm_asm.h>
 #include <asm/kvm_emulate.h>
+#include <asm/kvm_hyp.h>
 #include <asm/kvm_mmu.h>
 #include <asm/kvm_nested.h>
 #include <asm/kvm_pkvm.h>
@@ -2396,7 +2397,7 @@ static int __init do_pkvm_init(u32 hyp_va_bits)
 	preempt_disable();
 	cpu_hyp_init_context();
 	ret = kvm_call_hyp_nvhe(__pkvm_init, hyp_mem_base, hyp_mem_size,
-				num_possible_cpus(), kern_hyp_va(per_cpu_base),
+				kern_hyp_va(per_cpu_base),
 				hyp_va_bits);
 	cpu_hyp_init_features();
 
@@ -2605,6 +2606,8 @@ static int __init init_hyp_mode(void)
 		kvm_nvhe_sym(kvm_arm_hyp_percpu_base)[cpu] = (unsigned long)page_addr;
 	}
 
+	kvm_nvhe_sym(hyp_nr_cpus) = num_possible_cpus();
+
 	/*
 	 * Map the Hyp-code called directly from the host
 	 */
diff --git a/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h b/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h
index 5f9d56754e39..f8a7b8c04c49 100644
--- a/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h
+++ b/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h
@@ -30,8 +30,6 @@ enum pkvm_component_id {
 	PKVM_ID_FFA,
 };
 
-extern unsigned long hyp_nr_cpus;
-
 int __pkvm_prot_finalize(void);
 int __pkvm_host_share_hyp(u64 pfn);
 int __pkvm_host_unshare_hyp(u64 pfn);
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 29430c031095..34546dce57ff 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -482,17 +482,15 @@ static void handle___pkvm_init(struct kvm_cpu_context *host_ctxt)
 {
 	DECLARE_REG(phys_addr_t, phys, host_ctxt, 1);
 	DECLARE_REG(unsigned long, size, host_ctxt, 2);
-	DECLARE_REG(unsigned long, nr_cpus, host_ctxt, 3);
-	DECLARE_REG(unsigned long *, per_cpu_base, host_ctxt, 4);
-	DECLARE_REG(u32, hyp_va_bits, host_ctxt, 5);
+	DECLARE_REG(unsigned long *, per_cpu_base, host_ctxt, 3);
+	DECLARE_REG(u32, hyp_va_bits, host_ctxt, 4);
 
 	/*
 	 * __pkvm_init() will return only if an error occurred, otherwise it
 	 * will tail-call in __pkvm_init_finalise() which will have to deal
 	 * with the host context directly.
 	 */
-	cpu_reg(host_ctxt, 1) = __pkvm_init(phys, size, nr_cpus, per_cpu_base,
-					    hyp_va_bits);
+	cpu_reg(host_ctxt, 1) = __pkvm_init(phys, size, per_cpu_base, hyp_va_bits);
 }
 
 static void handle___pkvm_cpu_set_vector(struct kvm_cpu_context *host_ctxt)
diff --git a/arch/arm64/kvm/hyp/nvhe/setup.c b/arch/arm64/kvm/hyp/nvhe/setup.c
index 90bd014e952f..d8e5b563fd3d 100644
--- a/arch/arm64/kvm/hyp/nvhe/setup.c
+++ b/arch/arm64/kvm/hyp/nvhe/setup.c
@@ -341,8 +341,7 @@ void __noreturn __pkvm_init_finalise(void)
 	__host_enter(host_ctxt);
 }
 
-int __pkvm_init(phys_addr_t phys, unsigned long size, unsigned long nr_cpus,
-		unsigned long *per_cpu_base, u32 hyp_va_bits)
+int __pkvm_init(phys_addr_t phys, unsigned long size, unsigned long *per_cpu_base, u32 hyp_va_bits)
 {
 	struct kvm_nvhe_init_params *params;
 	void *virt = hyp_phys_to_virt(phys);
@@ -355,7 +354,6 @@ int __pkvm_init(phys_addr_t phys, unsigned long size, unsigned long nr_cpus,
 		return -EINVAL;
 
 	hyp_spin_lock_init(&pkvm_pgd_lock);
-	hyp_nr_cpus = nr_cpus;
 
 	ret = divide_memory_pool(virt, size);
 	if (ret)
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:36:15 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:36:15 +0000
Subject: [PATCH v9 22/30] KVM: arm64: Support unaligned fixmap in the pKVM hyp
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-23-vdonnefort@google.com>

Return the fixmap VA with the page offset, instead of the page base
address. This allows to use hyp_fixmap_map() seamlessly regardless of
the address alignment. While at it, do the same for hyp_fixblock_map().

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/arch/arm64/kvm/hyp/nvhe/mm.c b/arch/arm64/kvm/hyp/nvhe/mm.c
index ae8391baebc3..a6eafd72f87c 100644
--- a/arch/arm64/kvm/hyp/nvhe/mm.c
+++ b/arch/arm64/kvm/hyp/nvhe/mm.c
@@ -244,7 +244,7 @@ static void *fixmap_map_slot(struct hyp_fixmap_slot *slot, phys_addr_t phys)
 
 void *hyp_fixmap_map(phys_addr_t phys)
 {
-	return fixmap_map_slot(this_cpu_ptr(&fixmap_slots), phys);
+	return fixmap_map_slot(this_cpu_ptr(&fixmap_slots), phys) + offset_in_page(phys);
 }
 
 static void fixmap_clear_slot(struct hyp_fixmap_slot *slot)
@@ -366,7 +366,7 @@ void *hyp_fixblock_map(phys_addr_t phys, size_t *size)
 #ifdef HAS_FIXBLOCK
 	*size = PMD_SIZE;
 	hyp_spin_lock(&hyp_fixblock_lock);
-	return fixmap_map_slot(&hyp_fixblock_slot, phys);
+	return fixmap_map_slot(&hyp_fixblock_slot, phys) + offset_in_page(phys);
 #else
 	*size = PAGE_SIZE;
 	return hyp_fixmap_map(phys);
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:36:17 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:36:17 +0000
Subject: [PATCH v9 24/30] KVM: arm64: Add trace remote for the nVHE/pKVM hyp
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-25-vdonnefort@google.com>

In both protected and nVHE mode, the hypervisor is capable of writing
events into tracefs compatible ring-buffers. Create a trace remote so
the kernel can read those buffers.

This currently doesn't provide any event support which will come later.

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index c7f50492f2cf..aad0228f24db 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -76,6 +76,7 @@ if NVHE_EL2_DEBUG
 config NVHE_EL2_TRACING
 	bool
 	depends on TRACING
+	select TRACE_REMOTE
 	default y
 
 config PKVM_DISABLE_STAGE2_ON_PANIC
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index 3ebc0570345c..59612d2f277c 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -30,6 +30,8 @@ kvm-$(CONFIG_HW_PERF_EVENTS)  += pmu-emul.o pmu.o
 kvm-$(CONFIG_ARM64_PTR_AUTH)  += pauth.o
 kvm-$(CONFIG_PTDUMP_STAGE2_DEBUGFS) += ptdump.o
 
+kvm-$(CONFIG_NVHE_EL2_TRACING) += hyp_trace.o
+
 always-y := hyp_constants.h hyp-constants.s
 
 define rule_gen_hyp_constants
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 7ba427f9608c..82faad681f81 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -24,6 +24,7 @@
 
 #define CREATE_TRACE_POINTS
 #include "trace_arm.h"
+#include "hyp_trace.h"
 
 #include <linux/uaccess.h>
 #include <asm/ptrace.h>
@@ -2346,6 +2347,10 @@ static int __init init_subsystems(void)
 
 	kvm_register_perf_callbacks(NULL);
 
+	err = kvm_hyp_trace_init();
+	if (err)
+		kvm_err("Failed to initialize Hyp tracing\n");
+
 out:
 	if (err)
 		hyp_cpu_pm_exit();
diff --git a/arch/arm64/kvm/hyp_trace.c b/arch/arm64/kvm/hyp_trace.c
new file mode 100644
index 000000000000..2866effe28ec
--- /dev/null
+++ b/arch/arm64/kvm/hyp_trace.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2025 Google LLC
+ * Author: Vincent Donnefort <vdonnefort at google.com>
+ */
+
+#include <linux/trace_remote.h>
+#include <linux/simple_ring_buffer.h>
+
+#include <asm/kvm_host.h>
+#include <asm/kvm_hyptrace.h>
+#include <asm/kvm_mmu.h>
+
+#include "hyp_trace.h"
+
+/* Access to this struct within the trace_remote_callbacks are protected by the trace_remote lock */
+static struct hyp_trace_buffer {
+	struct hyp_trace_desc	*desc;
+	size_t			desc_size;
+} trace_buffer;
+
+static int __map_hyp(void *start, size_t size)
+{
+	if (is_protected_kvm_enabled())
+		return 0;
+
+	return create_hyp_mappings(start, start + size, PAGE_HYP);
+}
+
+static int __share_page(unsigned long va)
+{
+	return kvm_share_hyp((void *)va, (void *)va + 1);
+}
+
+static void __unshare_page(unsigned long va)
+{
+	kvm_unshare_hyp((void *)va, (void *)va + 1);
+}
+
+static int hyp_trace_buffer_alloc_bpages_backing(struct hyp_trace_buffer *trace_buffer, size_t size)
+{
+	int nr_bpages = (PAGE_ALIGN(size) / PAGE_SIZE) + 1;
+	size_t backing_size;
+	void *start;
+
+	backing_size = PAGE_ALIGN(sizeof(struct simple_buffer_page) * nr_bpages *
+				  num_possible_cpus());
+
+	start = alloc_pages_exact(backing_size, GFP_KERNEL_ACCOUNT);
+	if (!start)
+		return -ENOMEM;
+
+	trace_buffer->desc->bpages_backing_start = (unsigned long)start;
+	trace_buffer->desc->bpages_backing_size = backing_size;
+
+	return __map_hyp(start, backing_size);
+}
+
+static void hyp_trace_buffer_free_bpages_backing(struct hyp_trace_buffer *trace_buffer)
+{
+	free_pages_exact((void *)trace_buffer->desc->bpages_backing_start,
+			 trace_buffer->desc->bpages_backing_size);
+}
+
+static void hyp_trace_buffer_unshare_hyp(struct hyp_trace_buffer *trace_buffer, int last_cpu)
+{
+	struct ring_buffer_desc *rb_desc;
+	int cpu, p;
+
+	for_each_ring_buffer_desc(rb_desc, cpu, &trace_buffer->desc->trace_buffer_desc) {
+		if (cpu > last_cpu)
+			break;
+
+		__share_page(rb_desc->meta_va);
+		for (p = 0; p < rb_desc->nr_page_va; p++)
+			__unshare_page(rb_desc->page_va[p]);
+	}
+}
+
+static int hyp_trace_buffer_share_hyp(struct hyp_trace_buffer *trace_buffer)
+{
+	struct ring_buffer_desc *rb_desc;
+	int cpu, p, ret = 0;
+
+	for_each_ring_buffer_desc(rb_desc, cpu, &trace_buffer->desc->trace_buffer_desc) {
+		ret = __share_page(rb_desc->meta_va);
+		if (ret)
+			break;
+
+		for (p = 0; p < rb_desc->nr_page_va; p++) {
+			ret = __share_page(rb_desc->page_va[p]);
+			if (ret)
+				break;
+		}
+
+		if (ret) {
+			for (p--; p >= 0; p--)
+				__unshare_page(rb_desc->page_va[p]);
+			break;
+		}
+	}
+
+	if (ret)
+		hyp_trace_buffer_unshare_hyp(trace_buffer, cpu--);
+
+	return ret;
+}
+
+static struct trace_buffer_desc *hyp_trace_load(unsigned long size, void *priv)
+{
+	struct hyp_trace_buffer *trace_buffer = priv;
+	struct hyp_trace_desc *desc;
+	size_t desc_size;
+	int ret;
+
+	if (WARN_ON(trace_buffer->desc))
+		return ERR_PTR(-EINVAL);
+
+	desc_size = trace_buffer_desc_size(size, num_possible_cpus());
+	if (desc_size == SIZE_MAX)
+		return ERR_PTR(-E2BIG);
+
+	desc_size = PAGE_ALIGN(desc_size);
+	desc = (struct hyp_trace_desc *)alloc_pages_exact(desc_size, GFP_KERNEL);
+	if (!desc)
+		return ERR_PTR(-ENOMEM);
+
+	ret = __map_hyp(desc, desc_size);
+	if (ret)
+		goto err_free_desc;
+
+	trace_buffer->desc = desc;
+
+	ret = hyp_trace_buffer_alloc_bpages_backing(trace_buffer, size);
+	if (ret)
+		goto err_free_desc;
+
+	ret = trace_remote_alloc_buffer(&desc->trace_buffer_desc, desc_size, size,
+					cpu_possible_mask);
+	if (ret)
+		goto err_free_backing;
+
+	ret = hyp_trace_buffer_share_hyp(trace_buffer);
+	if (ret)
+		goto err_free_buffer;
+
+	ret = kvm_call_hyp_nvhe(__tracing_load, (unsigned long)desc, desc_size);
+	if (ret)
+		goto err_unload_pages;
+
+	return &desc->trace_buffer_desc;
+
+err_unload_pages:
+	hyp_trace_buffer_unshare_hyp(trace_buffer, INT_MAX);
+
+err_free_buffer:
+	trace_remote_free_buffer(&desc->trace_buffer_desc);
+
+err_free_backing:
+	hyp_trace_buffer_free_bpages_backing(trace_buffer);
+
+err_free_desc:
+	free_pages_exact(desc, desc_size);
+	trace_buffer->desc = NULL;
+
+	return ERR_PTR(ret);
+}
+
+static void hyp_trace_unload(struct trace_buffer_desc *desc, void *priv)
+{
+	struct hyp_trace_buffer *trace_buffer = priv;
+
+	if (WARN_ON(desc != &trace_buffer->desc->trace_buffer_desc))
+		return;
+
+	kvm_call_hyp_nvhe(__tracing_unload);
+	hyp_trace_buffer_unshare_hyp(trace_buffer, INT_MAX);
+	trace_remote_free_buffer(desc);
+	hyp_trace_buffer_free_bpages_backing(trace_buffer);
+	free_pages_exact(trace_buffer->desc, trace_buffer->desc_size);
+	trace_buffer->desc = NULL;
+}
+
+static int hyp_trace_enable_tracing(bool enable, void *priv)
+{
+	return kvm_call_hyp_nvhe(__tracing_enable, enable);
+}
+
+static int hyp_trace_swap_reader_page(unsigned int cpu, void *priv)
+{
+	return kvm_call_hyp_nvhe(__tracing_swap_reader, cpu);
+}
+
+static int hyp_trace_reset(unsigned int cpu, void *priv)
+{
+	return 0;
+}
+
+static int hyp_trace_enable_event(unsigned short id, bool enable, void *priv)
+{
+	return 0;
+}
+
+static struct trace_remote_callbacks trace_remote_callbacks = {
+	.load_trace_buffer	= hyp_trace_load,
+	.unload_trace_buffer	= hyp_trace_unload,
+	.enable_tracing		= hyp_trace_enable_tracing,
+	.swap_reader_page	= hyp_trace_swap_reader_page,
+	.reset			= hyp_trace_reset,
+	.enable_event		= hyp_trace_enable_event,
+};
+
+int __init kvm_hyp_trace_init(void)
+{
+	if (is_kernel_in_hyp_mode())
+		return 0;
+
+	return trace_remote_register("hypervisor", &trace_remote_callbacks, &trace_buffer, NULL, 0);
+}
diff --git a/arch/arm64/kvm/hyp_trace.h b/arch/arm64/kvm/hyp_trace.h
new file mode 100644
index 000000000000..c991b1ec65f1
--- /dev/null
+++ b/arch/arm64/kvm/hyp_trace.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __ARM64_KVM_HYP_TRACE_H__
+#define __ARM64_KVM_HYP_TRACE_H__
+
+#ifdef CONFIG_NVHE_EL2_TRACING
+int kvm_hyp_trace_init(void);
+#else
+static inline int kvm_hyp_trace_init(void) { return 0; }
+#endif
+#endif
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:36:19 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:36:19 +0000
Subject: [PATCH v9 26/30] KVM: arm64: Add trace reset to the nVHE/pKVM hyp
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-27-vdonnefort@google.com>

Make the hypervisor reset either the whole tracing buffer or a specific
ring-buffer, on remotes/hypervisor/trace or per_cpu/<cpu>/trace write
access.

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index 375607c67285..a28b072125ec 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -94,6 +94,7 @@ enum __kvm_host_smccc_func {
 	__KVM_HOST_SMCCC_FUNC___tracing_enable,
 	__KVM_HOST_SMCCC_FUNC___tracing_swap_reader,
 	__KVM_HOST_SMCCC_FUNC___tracing_update_clock,
+	__KVM_HOST_SMCCC_FUNC___tracing_reset,
 };
 
 #define DECLARE_KVM_VHE_SYM(sym)	extern char sym[]
diff --git a/arch/arm64/kvm/hyp/include/nvhe/trace.h b/arch/arm64/kvm/hyp/include/nvhe/trace.h
index fd641e1b1c23..44912869d184 100644
--- a/arch/arm64/kvm/hyp/include/nvhe/trace.h
+++ b/arch/arm64/kvm/hyp/include/nvhe/trace.h
@@ -12,6 +12,7 @@ void __tracing_unload(void);
 int __tracing_enable(bool enable);
 int __tracing_swap_reader(unsigned int cpu);
 void __tracing_update_clock(u32 mult, u32 shift, u64 epoch_ns, u64 epoch_cyc);
+int __tracing_reset(unsigned int cpu);
 #else
 static inline void *tracing_reserve_entry(unsigned long length) { return NULL; }
 static inline void tracing_commit_entry(void) { }
@@ -21,5 +22,6 @@ static inline void __tracing_unload(void) { }
 static inline int __tracing_enable(bool enable) { return -ENODEV; }
 static inline int __tracing_swap_reader(unsigned int cpu) { return -ENODEV; }
 static inline void __tracing_update_clock(u32 mult, u32 shift, u64 epoch_ns, u64 epoch_cyc) { }
+static inline int __tracing_reset(unsigned int cpu) { return -ENODEV; }
 #endif
 #endif
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 45b8f70828de..f92e82cbfcb4 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -625,6 +625,13 @@ static void handle___tracing_update_clock(struct kvm_cpu_context *host_ctxt)
 	cpu_reg(host_ctxt, 1) = 0;
 }
 
+static void handle___tracing_reset(struct kvm_cpu_context *host_ctxt)
+{
+	DECLARE_REG(unsigned int, cpu, host_ctxt, 1);
+
+	cpu_reg(host_ctxt, 1) = __tracing_reset(cpu);
+}
+
 typedef void (*hcall_t)(struct kvm_cpu_context *);
 
 #define HANDLE_FUNC(x)	[__KVM_HOST_SMCCC_FUNC_##x] = (hcall_t)handle_##x
@@ -671,6 +678,7 @@ static const hcall_t host_hcall[] = {
 	HANDLE_FUNC(__tracing_enable),
 	HANDLE_FUNC(__tracing_swap_reader),
 	HANDLE_FUNC(__tracing_update_clock),
+	HANDLE_FUNC(__tracing_reset),
 };
 
 static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
diff --git a/arch/arm64/kvm/hyp/nvhe/trace.c b/arch/arm64/kvm/hyp/nvhe/trace.c
index 97e9f6c1a52c..93475cc36640 100644
--- a/arch/arm64/kvm/hyp/nvhe/trace.c
+++ b/arch/arm64/kvm/hyp/nvhe/trace.c
@@ -287,3 +287,20 @@ void __tracing_update_clock(u32 mult, u32 shift, u64 epoch_ns, u64 epoch_cyc)
 	/* ...we can now override the old one and swap. */
 	trace_clock_update(mult, shift, epoch_ns, epoch_cyc);
 }
+
+int __tracing_reset(unsigned int cpu)
+{
+	int ret = -ENODEV;
+
+	if (cpu >= hyp_nr_cpus)
+		return -EINVAL;
+
+	hyp_spin_lock(&trace_buffer.lock);
+
+	if (hyp_trace_buffer_loaded(&trace_buffer))
+		ret = simple_ring_buffer_reset(per_cpu_ptr(trace_buffer.simple_rbs, cpu));
+
+	hyp_spin_unlock(&trace_buffer.lock);
+
+	return ret;
+}
diff --git a/arch/arm64/kvm/hyp_trace.c b/arch/arm64/kvm/hyp_trace.c
index 1e5fc27f0e9d..09bc192e3514 100644
--- a/arch/arm64/kvm/hyp_trace.c
+++ b/arch/arm64/kvm/hyp_trace.c
@@ -313,7 +313,7 @@ static int hyp_trace_swap_reader_page(unsigned int cpu, void *priv)
 
 static int hyp_trace_reset(unsigned int cpu, void *priv)
 {
-	return 0;
+	return kvm_call_hyp_nvhe(__tracing_reset, cpu);
 }
 
 static int hyp_trace_enable_event(unsigned short id, bool enable, void *priv)
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:36:22 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:36:22 +0000
Subject: [PATCH v9 29/30] KVM: arm64: Add selftest event support to nVHE/pKVM hyp
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-30-vdonnefort@google.com>

Add a selftest event that can be triggered from a `write_event` tracefs
file. This intends to be used by trace remote selftests.

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index 37c015b54ff6..e2de7ad64938 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -96,6 +96,7 @@ enum __kvm_host_smccc_func {
 	__KVM_HOST_SMCCC_FUNC___tracing_update_clock,
 	__KVM_HOST_SMCCC_FUNC___tracing_reset,
 	__KVM_HOST_SMCCC_FUNC___tracing_enable_event,
+	__KVM_HOST_SMCCC_FUNC___tracing_write_event,
 };
 
 #define DECLARE_KVM_VHE_SYM(sym)	extern char sym[]
diff --git a/arch/arm64/include/asm/kvm_hypevents.h b/arch/arm64/include/asm/kvm_hypevents.h
index 268b3cd7a1b2..c276fd28e0bf 100644
--- a/arch/arm64/include/asm/kvm_hypevents.h
+++ b/arch/arm64/include/asm/kvm_hypevents.h
@@ -42,4 +42,15 @@ HYP_EVENT(hyp_exit,
 	),
 	HE_PRINTK("reason=%s", __hyp_enter_exit_reason_str(__entry->reason))
 );
+
+HYP_EVENT(selftest,
+	HE_PROTO(u64 id),
+	HE_STRUCT(
+		he_field(u64, id)
+	),
+	HE_ASSIGN(
+		__entry->id = id;
+	),
+	RE_PRINTK("id=%llu", __entry->id)
+);
 #endif
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index ffda4850022f..13a6c5c4fabd 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -641,6 +641,15 @@ static void handle___tracing_enable_event(struct kvm_cpu_context *host_ctxt)
 	cpu_reg(host_ctxt, 1) = __tracing_enable_event(id, enable);
 }
 
+static void handle___tracing_write_event(struct kvm_cpu_context *host_ctxt)
+{
+	DECLARE_REG(u64, id, host_ctxt, 1);
+
+	trace_selftest(id);
+
+	cpu_reg(host_ctxt, 1) = 0;
+}
+
 typedef void (*hcall_t)(struct kvm_cpu_context *);
 
 #define HANDLE_FUNC(x)	[__KVM_HOST_SMCCC_FUNC_##x] = (hcall_t)handle_##x
@@ -689,6 +698,7 @@ static const hcall_t host_hcall[] = {
 	HANDLE_FUNC(__tracing_update_clock),
 	HANDLE_FUNC(__tracing_reset),
 	HANDLE_FUNC(__tracing_enable_event),
+	HANDLE_FUNC(__tracing_write_event),
 };
 
 static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
diff --git a/arch/arm64/kvm/hyp_trace.c b/arch/arm64/kvm/hyp_trace.c
index 1ad6a55ba95c..7b537222f364 100644
--- a/arch/arm64/kvm/hyp_trace.c
+++ b/arch/arm64/kvm/hyp_trace.c
@@ -348,8 +348,32 @@ static int hyp_trace_clock_show(struct seq_file *m, void *v)
 }
 DEFINE_SHOW_ATTRIBUTE(hyp_trace_clock);
 
+static ssize_t hyp_trace_write_event_write(struct file *f, const char __user *ubuf,
+					   size_t cnt, loff_t *pos)
+{
+	unsigned long val;
+	int ret;
+
+	ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
+	if (ret)
+		return ret;
+
+	ret = kvm_call_hyp_nvhe(__tracing_write_event, val);
+	if (ret)
+		return ret;
+
+	return cnt;
+}
+
+static const struct file_operations hyp_trace_write_event_fops = {
+	.write	= hyp_trace_write_event_write,
+};
+
 static int hyp_trace_init_tracefs(struct dentry *d, void *priv)
 {
+	if (!tracefs_create_file("write_event", 0200, d, NULL, &hyp_trace_write_event_fops))
+		return -ENOMEM;
+
 	return tracefs_create_file("trace_clock", 0440, d, NULL, &hyp_trace_clock_fops) ?
 		0 : -ENOMEM;
 }
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:36:16 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:36:16 +0000
Subject: [PATCH v9 23/30] KVM: arm64: Add tracing capability for the nVHE/pKVM hyp
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-24-vdonnefort@google.com>

There is currently no way to inspect or log what's happening at EL2
when the nVHE or pKVM hypervisor is used. With the growing set of
features for pKVM, the need for tooling is more pressing. And tracefs,
by its reliability, versatility and support for user-space is fit for
purpose.

Add support to write into a tracefs compatible ring-buffer. There's no
way the hypervisor could log events directly into the host tracefs
ring-buffers. So instead let's use our own, where the hypervisor is the
writer and the host the reader.

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index 9da54d4ee49e..f83650a7aad9 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -89,6 +89,10 @@ enum __kvm_host_smccc_func {
 	__KVM_HOST_SMCCC_FUNC___pkvm_vcpu_load,
 	__KVM_HOST_SMCCC_FUNC___pkvm_vcpu_put,
 	__KVM_HOST_SMCCC_FUNC___pkvm_tlb_flush_vmid,
+	__KVM_HOST_SMCCC_FUNC___tracing_load,
+	__KVM_HOST_SMCCC_FUNC___tracing_unload,
+	__KVM_HOST_SMCCC_FUNC___tracing_enable,
+	__KVM_HOST_SMCCC_FUNC___tracing_swap_reader,
 };
 
 #define DECLARE_KVM_VHE_SYM(sym)	extern char sym[]
diff --git a/arch/arm64/include/asm/kvm_hyptrace.h b/arch/arm64/include/asm/kvm_hyptrace.h
new file mode 100644
index 000000000000..9c30a479bc36
--- /dev/null
+++ b/arch/arm64/include/asm/kvm_hyptrace.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ARM64_KVM_HYPTRACE_H_
+#define __ARM64_KVM_HYPTRACE_H_
+
+#include <linux/ring_buffer.h>
+
+struct hyp_trace_desc {
+	unsigned long			bpages_backing_start;
+	size_t				bpages_backing_size;
+	struct trace_buffer_desc	trace_buffer_desc;
+
+};
+#endif
diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index 6498dec00fe9..c7f50492f2cf 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -73,6 +73,11 @@ config NVHE_EL2_DEBUG
 
 if NVHE_EL2_DEBUG
 
+config NVHE_EL2_TRACING
+	bool
+	depends on TRACING
+	default y
+
 config PKVM_DISABLE_STAGE2_ON_PANIC
 	bool "Disable the host stage-2 on panic"
 	default n
diff --git a/arch/arm64/kvm/hyp/include/nvhe/trace.h b/arch/arm64/kvm/hyp/include/nvhe/trace.h
new file mode 100644
index 000000000000..7da8788ce527
--- /dev/null
+++ b/arch/arm64/kvm/hyp/include/nvhe/trace.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ARM64_KVM_HYP_NVHE_TRACE_H
+#define __ARM64_KVM_HYP_NVHE_TRACE_H
+#include <asm/kvm_hyptrace.h>
+
+#ifdef CONFIG_NVHE_EL2_TRACING
+void *tracing_reserve_entry(unsigned long length);
+void tracing_commit_entry(void);
+
+int __tracing_load(unsigned long desc_va, size_t desc_size);
+void __tracing_unload(void);
+int __tracing_enable(bool enable);
+int __tracing_swap_reader(unsigned int cpu);
+#else
+static inline void *tracing_reserve_entry(unsigned long length) { return NULL; }
+static inline void tracing_commit_entry(void) { }
+
+static inline int __tracing_load(unsigned long desc_va, size_t desc_size) { return -ENODEV; }
+static inline void __tracing_unload(void) { }
+static inline int __tracing_enable(bool enable) { return -ENODEV; }
+static inline int __tracing_swap_reader(unsigned int cpu) { return -ENODEV; }
+#endif
+#endif
diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile
index 8dc95257c291..f1840628d2d6 100644
--- a/arch/arm64/kvm/hyp/nvhe/Makefile
+++ b/arch/arm64/kvm/hyp/nvhe/Makefile
@@ -29,9 +29,12 @@ hyp-obj-y += ../vgic-v3-sr.o ../aarch32.o ../vgic-v2-cpuif-proxy.o ../entry.o \
 	 ../fpsimd.o ../hyp-entry.o ../exception.o ../pgtable.o
 hyp-obj-y += ../../../kernel/smccc-call.o
 hyp-obj-$(CONFIG_LIST_HARDENED) += list_debug.o
-hyp-obj-$(CONFIG_NVHE_EL2_TRACING) += clock.o
+hyp-obj-$(CONFIG_NVHE_EL2_TRACING) += clock.o trace.o
 hyp-obj-y += $(lib-objs)
 
+# Path to simple_ring_buffer.c
+CFLAGS_trace.nvhe.o += -I$(objtree)/kernel/trace/
+
 ##
 ## Build rules for compiling nVHE hyp code
 ## Output of this folder is `kvm_nvhe.o`, a partially linked object
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 34546dce57ff..8b78b29c2069 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -18,6 +18,7 @@
 #include <nvhe/mem_protect.h>
 #include <nvhe/mm.h>
 #include <nvhe/pkvm.h>
+#include <nvhe/trace.h>
 #include <nvhe/trap_handler.h>
 
 DEFINE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params);
@@ -583,6 +584,35 @@ static void handle___pkvm_teardown_vm(struct kvm_cpu_context *host_ctxt)
 	cpu_reg(host_ctxt, 1) = __pkvm_teardown_vm(handle);
 }
 
+static void handle___tracing_load(struct kvm_cpu_context *host_ctxt)
+{
+	DECLARE_REG(unsigned long, desc_hva, host_ctxt, 1);
+	DECLARE_REG(size_t, desc_size, host_ctxt, 2);
+
+	cpu_reg(host_ctxt, 1) = __tracing_load(desc_hva, desc_size);
+}
+
+static void handle___tracing_unload(struct kvm_cpu_context *host_ctxt)
+{
+	__tracing_unload();
+
+	cpu_reg(host_ctxt, 1) = 0;
+}
+
+static void handle___tracing_enable(struct kvm_cpu_context *host_ctxt)
+{
+	DECLARE_REG(bool, enable, host_ctxt, 1);
+
+	cpu_reg(host_ctxt, 1) = __tracing_enable(enable);
+}
+
+static void handle___tracing_swap_reader(struct kvm_cpu_context *host_ctxt)
+{
+	DECLARE_REG(unsigned int, cpu, host_ctxt, 1);
+
+	cpu_reg(host_ctxt, 1) = __tracing_swap_reader(cpu);
+}
+
 typedef void (*hcall_t)(struct kvm_cpu_context *);
 
 #define HANDLE_FUNC(x)	[__KVM_HOST_SMCCC_FUNC_##x] = (hcall_t)handle_##x
@@ -624,6 +654,10 @@ static const hcall_t host_hcall[] = {
 	HANDLE_FUNC(__pkvm_vcpu_load),
 	HANDLE_FUNC(__pkvm_vcpu_put),
 	HANDLE_FUNC(__pkvm_tlb_flush_vmid),
+	HANDLE_FUNC(__tracing_load),
+	HANDLE_FUNC(__tracing_unload),
+	HANDLE_FUNC(__tracing_enable),
+	HANDLE_FUNC(__tracing_swap_reader),
 };
 
 static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
diff --git a/arch/arm64/kvm/hyp/nvhe/trace.c b/arch/arm64/kvm/hyp/nvhe/trace.c
new file mode 100644
index 000000000000..df9d66fcb3c9
--- /dev/null
+++ b/arch/arm64/kvm/hyp/nvhe/trace.c
@@ -0,0 +1,273 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2025 Google LLC
+ * Author: Vincent Donnefort <vdonnefort at google.com>
+ */
+
+#include <nvhe/clock.h>
+#include <nvhe/mem_protect.h>
+#include <nvhe/mm.h>
+#include <nvhe/trace.h>
+
+#include <asm/percpu.h>
+#include <asm/kvm_mmu.h>
+#include <asm/local.h>
+
+#include "simple_ring_buffer.c"
+
+static DEFINE_PER_CPU(struct simple_rb_per_cpu, __simple_rbs);
+
+static struct hyp_trace_buffer {
+	struct simple_rb_per_cpu __percpu	*simple_rbs;
+	void					*bpages_backing_start;
+	size_t					bpages_backing_size;
+	hyp_spinlock_t				lock;
+} trace_buffer = {
+	.simple_rbs = &__simple_rbs,
+	.lock = __HYP_SPIN_LOCK_UNLOCKED,
+};
+
+static bool hyp_trace_buffer_loaded(struct hyp_trace_buffer *trace_buffer)
+{
+	return trace_buffer->bpages_backing_size > 0;
+}
+
+void *tracing_reserve_entry(unsigned long length)
+{
+	return simple_ring_buffer_reserve(this_cpu_ptr(trace_buffer.simple_rbs), length,
+					  trace_clock());
+}
+
+void tracing_commit_entry(void)
+{
+	simple_ring_buffer_commit(this_cpu_ptr(trace_buffer.simple_rbs));
+}
+
+static int __admit_host_mem(void *start, u64 size)
+{
+	if (!PAGE_ALIGNED(start) || !PAGE_ALIGNED(size) || !size)
+		return -EINVAL;
+
+	if (!is_protected_kvm_enabled())
+		return 0;
+
+	return __pkvm_host_donate_hyp(hyp_virt_to_pfn(start), size >> PAGE_SHIFT);
+}
+
+static void __release_host_mem(void *start, u64 size)
+{
+	if (!is_protected_kvm_enabled())
+		return;
+
+	WARN_ON(__pkvm_hyp_donate_host(hyp_virt_to_pfn(start), size >> PAGE_SHIFT));
+}
+
+static int hyp_trace_buffer_load_bpage_backing(struct hyp_trace_buffer *trace_buffer,
+					       struct hyp_trace_desc *desc)
+{
+	void *start = (void *)kern_hyp_va(desc->bpages_backing_start);
+	size_t size = desc->bpages_backing_size;
+	int ret;
+
+	ret = __admit_host_mem(start, size);
+	if (ret)
+		return ret;
+
+	memset(start, 0, size);
+
+	trace_buffer->bpages_backing_start = start;
+	trace_buffer->bpages_backing_size = size;
+
+	return 0;
+}
+
+static void hyp_trace_buffer_unload_bpage_backing(struct hyp_trace_buffer *trace_buffer)
+{
+	void *start = trace_buffer->bpages_backing_start;
+	size_t size = trace_buffer->bpages_backing_size;
+
+	if (!size)
+		return;
+
+	memset(start, 0, size);
+
+	__release_host_mem(start, size);
+
+	trace_buffer->bpages_backing_start = 0;
+	trace_buffer->bpages_backing_size = 0;
+}
+
+static void *__pin_shared_page(unsigned long kern_va)
+{
+	void *va = kern_hyp_va((void *)kern_va);
+
+	if (!is_protected_kvm_enabled())
+		return va;
+
+	return hyp_pin_shared_mem(va, va + PAGE_SIZE) ? NULL : va;
+}
+
+static void __unpin_shared_page(void *va)
+{
+	if (!is_protected_kvm_enabled())
+		return;
+
+	hyp_unpin_shared_mem(va, va + PAGE_SIZE);
+}
+
+static void hyp_trace_buffer_unload(struct hyp_trace_buffer *trace_buffer)
+{
+	int cpu;
+
+	hyp_assert_lock_held(&trace_buffer->lock);
+
+	if (!hyp_trace_buffer_loaded(trace_buffer))
+		return;
+
+	for (cpu = 0; cpu < hyp_nr_cpus; cpu++)
+		__simple_ring_buffer_unload(per_cpu_ptr(trace_buffer->simple_rbs, cpu),
+					    __unpin_shared_page);
+
+	hyp_trace_buffer_unload_bpage_backing(trace_buffer);
+}
+
+static int hyp_trace_buffer_load(struct hyp_trace_buffer *trace_buffer,
+				 struct hyp_trace_desc *desc)
+{
+	struct simple_buffer_page *bpages;
+	struct ring_buffer_desc *rb_desc;
+	int ret, cpu;
+
+	hyp_assert_lock_held(&trace_buffer->lock);
+
+	if (hyp_trace_buffer_loaded(trace_buffer))
+		return -EINVAL;
+
+	ret = hyp_trace_buffer_load_bpage_backing(trace_buffer, desc);
+	if (ret)
+		return ret;
+
+	bpages = trace_buffer->bpages_backing_start;
+	for_each_ring_buffer_desc(rb_desc, cpu, &desc->trace_buffer_desc) {
+		ret = __simple_ring_buffer_init(per_cpu_ptr(trace_buffer->simple_rbs, cpu),
+						bpages, rb_desc, __pin_shared_page,
+						__unpin_shared_page);
+		if (ret)
+			break;
+
+		bpages += rb_desc->nr_page_va;
+	}
+
+	if (ret)
+		hyp_trace_buffer_unload(trace_buffer);
+
+	return ret;
+}
+
+static bool hyp_trace_desc_validate(struct hyp_trace_desc *desc, size_t desc_size)
+{
+	struct ring_buffer_desc *rb_desc;
+	unsigned int cpu;
+	size_t nr_bpages;
+	void *desc_end;
+
+	/*
+	 * Both desc_size and bpages_backing_size are untrusted host-provided
+	 * values. We rely on __pkvm_host_donate_hyp() to enforce their validity.
+	 */
+	desc_end = (void *)desc + desc_size;
+	nr_bpages = desc->bpages_backing_size / sizeof(struct simple_buffer_page);
+
+	for_each_ring_buffer_desc(rb_desc, cpu, &desc->trace_buffer_desc) {
+		/* Can we read nr_page_va? */
+		if ((void *)rb_desc + struct_size(rb_desc, page_va, 0) > desc_end)
+			return false;
+
+		/* Overflow desc? */
+		if ((void *)rb_desc + struct_size(rb_desc, page_va, rb_desc->nr_page_va) > desc_end)
+			return false;
+
+		/* Overflow bpages backing memory? */
+		if (nr_bpages < rb_desc->nr_page_va)
+			return false;
+
+		if (cpu >= hyp_nr_cpus)
+			return false;
+
+		if (cpu != rb_desc->cpu)
+			return false;
+
+		nr_bpages -= rb_desc->nr_page_va;
+	}
+
+	return true;
+}
+
+int __tracing_load(unsigned long desc_hva, size_t desc_size)
+{
+	struct hyp_trace_desc *desc = (struct hyp_trace_desc *)kern_hyp_va(desc_hva);
+	int ret;
+
+	ret = __admit_host_mem(desc, desc_size);
+	if (ret)
+		return ret;
+
+	if (!hyp_trace_desc_validate(desc, desc_size))
+		goto err_release_desc;
+
+	hyp_spin_lock(&trace_buffer.lock);
+
+	ret = hyp_trace_buffer_load(&trace_buffer, desc);
+
+	hyp_spin_unlock(&trace_buffer.lock);
+
+err_release_desc:
+	__release_host_mem(desc, desc_size);
+	return ret;
+}
+
+void __tracing_unload(void)
+{
+	hyp_spin_lock(&trace_buffer.lock);
+	hyp_trace_buffer_unload(&trace_buffer);
+	hyp_spin_unlock(&trace_buffer.lock);
+}
+
+int __tracing_enable(bool enable)
+{
+	int cpu, ret = enable ? -EINVAL : 0;
+
+	hyp_spin_lock(&trace_buffer.lock);
+
+	if (!hyp_trace_buffer_loaded(&trace_buffer))
+		goto unlock;
+
+	for (cpu = 0; cpu < hyp_nr_cpus; cpu++)
+		simple_ring_buffer_enable_tracing(per_cpu_ptr(trace_buffer.simple_rbs, cpu),
+						  enable);
+
+	ret = 0;
+
+unlock:
+	hyp_spin_unlock(&trace_buffer.lock);
+
+	return ret;
+}
+
+int __tracing_swap_reader(unsigned int cpu)
+{
+	int ret = -ENODEV;
+
+	if (cpu >= hyp_nr_cpus)
+		return -EINVAL;
+
+	hyp_spin_lock(&trace_buffer.lock);
+
+	if (hyp_trace_buffer_loaded(&trace_buffer))
+		ret = simple_ring_buffer_swap_reader_page(
+				per_cpu_ptr(trace_buffer.simple_rbs, cpu));
+
+	hyp_spin_unlock(&trace_buffer.lock);
+
+	return ret;
+}
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:36:23 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:36:23 +0000
Subject: [PATCH v9 30/30] tracing: selftests: Add hypervisor trace remote tests
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-31-vdonnefort@google.com>

Run the trace remote selftests with the trace remote 'hypervisor', This
trace remote is most likely created when the arm64 KVM nVHE/pKVM
hypervisor is in use.

Cc: Shuah Khan <skhan at linuxfoundation.org>
Cc: linux-kselftest at vger.kernel.org
Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/buffer_size.tc b/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/buffer_size.tc
new file mode 100644
index 000000000000..64bf859d6406
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/buffer_size.tc
@@ -0,0 +1,11 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Test hypervisor trace buffer size
+# requires: remotes/hypervisor/write_event
+
+SOURCE_REMOTE_TEST=1
+. $TEST_DIR/remotes/buffer_size.tc
+
+set -e
+setup_remote "hypervisor"
+test_buffer_size
diff --git a/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/reset.tc b/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/reset.tc
new file mode 100644
index 000000000000..7fe3b09b34e3
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/reset.tc
@@ -0,0 +1,11 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Test hypervisor trace buffer reset
+# requires: remotes/hypervisor/write_event
+
+SOURCE_REMOTE_TEST=1
+. $TEST_DIR/remotes/reset.tc
+
+set -e
+setup_remote "hypervisor"
+test_reset
diff --git a/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/trace.tc b/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/trace.tc
new file mode 100644
index 000000000000..b937c19ca7f9
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/trace.tc
@@ -0,0 +1,11 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Test hypervisor non-consuming trace read
+# requires: remotes/hypervisor/write_event
+
+SOURCE_REMOTE_TEST=1
+. $TEST_DIR/remotes/trace.tc
+
+set -e
+setup_remote "hypervisor"
+test_trace
diff --git a/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/trace_pipe.tc b/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/trace_pipe.tc
new file mode 100644
index 000000000000..66aa1b76c147
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/trace_pipe.tc
@@ -0,0 +1,11 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Test hypervisor consuming trace read
+# requires: remotes/hypervisor/write_event
+
+SOURCE_REMOTE_TEST=1
+. $TEST_DIR/remotes/trace_pipe.tc
+
+set -e
+setup_remote "hypervisor"
+test_trace_pipe
diff --git a/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/unloading.tc b/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/unloading.tc
new file mode 100644
index 000000000000..1dafde3414ab
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/unloading.tc
@@ -0,0 +1,11 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Test hypervisor trace buffer unloading
+# requires: remotes/hypervisor/write_event
+
+SOURCE_REMOTE_TEST=1
+. $TEST_DIR/remotes/unloading.tc
+
+set -e
+setup_remote "hypervisor"
+test_unloading
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:36:20 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:36:20 +0000
Subject: [PATCH v9 27/30] KVM: arm64: Add event support to the nVHE/pKVM hyp
 and trace remote
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-28-vdonnefort@google.com>

Allow the creation of hypervisor and trace remote events with a single
macro HYP_EVENT(). That macro expands in the kernel side to add all
the required declarations (based on REMOTE_EVENT()) as well as in the
hypervisor side to create the trace_<event>() function.

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index a28b072125ec..37c015b54ff6 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -95,6 +95,7 @@ enum __kvm_host_smccc_func {
 	__KVM_HOST_SMCCC_FUNC___tracing_swap_reader,
 	__KVM_HOST_SMCCC_FUNC___tracing_update_clock,
 	__KVM_HOST_SMCCC_FUNC___tracing_reset,
+	__KVM_HOST_SMCCC_FUNC___tracing_enable_event,
 };
 
 #define DECLARE_KVM_VHE_SYM(sym)	extern char sym[]
diff --git a/arch/arm64/include/asm/kvm_define_hypevents.h b/arch/arm64/include/asm/kvm_define_hypevents.h
new file mode 100644
index 000000000000..77d6790252a6
--- /dev/null
+++ b/arch/arm64/include/asm/kvm_define_hypevents.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#define REMOTE_EVENT_INCLUDE_FILE arch/arm64/include/asm/kvm_hypevents.h
+
+#define REMOTE_EVENT_SECTION "_hyp_events"
+
+#define HE_STRUCT(__args)		__args
+#define HE_PRINTK(__args...)		__args
+#define he_field			re_field
+
+#define HYP_EVENT(__name, __proto, __struct, __assign, __printk) \
+	REMOTE_EVENT(__name, 0, RE_STRUCT(__struct), RE_PRINTK(__printk))
+
+#define HYP_EVENT_MULTI_READ
+#include <trace/define_remote_events.h>
+#undef HYP_EVENT_MULTI_READ
diff --git a/arch/arm64/include/asm/kvm_hypevents.h b/arch/arm64/include/asm/kvm_hypevents.h
new file mode 100644
index 000000000000..d6e033c96c52
--- /dev/null
+++ b/arch/arm64/include/asm/kvm_hypevents.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#if !defined(__ARM64_KVM_HYPEVENTS_H_) || defined(HYP_EVENT_MULTI_READ)
+#define __ARM64_KVM_HYPEVENTS_H_
+
+#ifdef __KVM_NVHE_HYPERVISOR__
+#include <nvhe/trace.h>
+#endif
+
+#endif
diff --git a/arch/arm64/include/asm/kvm_hyptrace.h b/arch/arm64/include/asm/kvm_hyptrace.h
index 9c30a479bc36..de133b735f72 100644
--- a/arch/arm64/include/asm/kvm_hyptrace.h
+++ b/arch/arm64/include/asm/kvm_hyptrace.h
@@ -10,4 +10,17 @@ struct hyp_trace_desc {
 	struct trace_buffer_desc	trace_buffer_desc;
 
 };
+
+struct hyp_event_id {
+	unsigned short	id;
+	atomic_t	enabled;
+};
+
+extern struct remote_event __hyp_events_start[];
+extern struct remote_event __hyp_events_end[];
+
+/* hyp_event section used by the hypervisor */
+extern struct hyp_event_id __hyp_event_ids_start[];
+extern struct hyp_event_id __hyp_event_ids_end[];
+
 #endif
diff --git a/arch/arm64/kernel/image-vars.h b/arch/arm64/kernel/image-vars.h
index 5369763606e7..872ab7897fce 100644
--- a/arch/arm64/kernel/image-vars.h
+++ b/arch/arm64/kernel/image-vars.h
@@ -137,6 +137,10 @@ KVM_NVHE_ALIAS(__hyp_data_start);
 KVM_NVHE_ALIAS(__hyp_data_end);
 KVM_NVHE_ALIAS(__hyp_rodata_start);
 KVM_NVHE_ALIAS(__hyp_rodata_end);
+#ifdef CONFIG_NVHE_EL2_TRACING
+KVM_NVHE_ALIAS(__hyp_event_ids_start);
+KVM_NVHE_ALIAS(__hyp_event_ids_end);
+#endif
 
 /* pKVM static key */
 KVM_NVHE_ALIAS(kvm_protected_mode_initialized);
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index ad6133b89e7a..273a461c6076 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -13,12 +13,23 @@
 	*(__kvm_ex_table)					\
 	__stop___kvm_ex_table = .;
 
+#ifdef CONFIG_NVHE_EL2_TRACING
+#define HYPERVISOR_EVENT_IDS 					\
+	. = ALIGN(PAGE_SIZE);					\
+	__hyp_event_ids_start = .;				\
+	*(HYP_SECTION_NAME(.event_ids))				\
+	__hyp_event_ids_end = .;
+#else
+#define HYPERVISOR_EVENT_IDS
+#endif
+
 #define HYPERVISOR_RODATA_SECTIONS				\
 	HYP_SECTION_NAME(.rodata) : {				\
 		. = ALIGN(PAGE_SIZE);				\
 		__hyp_rodata_start = .;				\
 		*(HYP_SECTION_NAME(.data..ro_after_init))	\
 		*(HYP_SECTION_NAME(.rodata))			\
+		HYPERVISOR_EVENT_IDS				\
 		. = ALIGN(PAGE_SIZE);				\
 		__hyp_rodata_end = .;				\
 	}
@@ -307,6 +318,13 @@ SECTIONS
 
 	HYPERVISOR_DATA_SECTION
 
+#ifdef CONFIG_NVHE_EL2_TRACING
+	.data.hyp_events : {
+		__hyp_events_start = .;
+		*(SORT(_hyp_events.*))
+		__hyp_events_end = .;
+	}
+#endif
 	/*
 	 * Data written with the MMU off but read with the MMU on requires
 	 * cache lines to be invalidated, discarding up to a Cache Writeback
diff --git a/arch/arm64/kvm/hyp/include/nvhe/define_events.h b/arch/arm64/kvm/hyp/include/nvhe/define_events.h
new file mode 100644
index 000000000000..776d4c6cb702
--- /dev/null
+++ b/arch/arm64/kvm/hyp/include/nvhe/define_events.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#undef HYP_EVENT
+#define HYP_EVENT(__name, __proto, __struct, __assign, __printk)	\
+	struct hyp_event_id hyp_event_id_##__name			\
+	__section(".hyp.event_ids."#__name) = {				\
+		.enabled = ATOMIC_INIT(0),				\
+	}
+
+#define HYP_EVENT_MULTI_READ
+#include <asm/kvm_hypevents.h>
+#undef HYP_EVENT_MULTI_READ
+
+#undef HYP_EVENT
diff --git a/arch/arm64/kvm/hyp/include/nvhe/trace.h b/arch/arm64/kvm/hyp/include/nvhe/trace.h
index 44912869d184..802a18b77c56 100644
--- a/arch/arm64/kvm/hyp/include/nvhe/trace.h
+++ b/arch/arm64/kvm/hyp/include/nvhe/trace.h
@@ -1,9 +1,36 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 #ifndef __ARM64_KVM_HYP_NVHE_TRACE_H
 #define __ARM64_KVM_HYP_NVHE_TRACE_H
+
+#include <linux/trace_remote_event.h>
+
 #include <asm/kvm_hyptrace.h>
 
+#define HE_PROTO(__args...)	__args
+#define HE_ASSIGN(__args...)	__args
+#define HE_STRUCT		RE_STRUCT
+#define he_field		re_field
+
 #ifdef CONFIG_NVHE_EL2_TRACING
+
+#define HYP_EVENT(__name, __proto, __struct, __assign, __printk)		\
+	REMOTE_EVENT_FORMAT(__name, __struct);					\
+	extern struct hyp_event_id hyp_event_id_##__name;			\
+	static __always_inline void trace_##__name(__proto)			\
+	{									\
+		struct remote_event_format_##__name *__entry;			\
+		size_t length = sizeof(*__entry);				\
+										\
+		if (!atomic_read(&hyp_event_id_##__name.enabled))		\
+			return;							\
+		__entry = tracing_reserve_entry(length);			\
+		if (!__entry)							\
+			return;							\
+		__entry->hdr.id = hyp_event_id_##__name.id;			\
+		__assign							\
+		tracing_commit_entry();						\
+	}
+
 void *tracing_reserve_entry(unsigned long length);
 void tracing_commit_entry(void);
 
@@ -13,9 +40,12 @@ int __tracing_enable(bool enable);
 int __tracing_swap_reader(unsigned int cpu);
 void __tracing_update_clock(u32 mult, u32 shift, u64 epoch_ns, u64 epoch_cyc);
 int __tracing_reset(unsigned int cpu);
+int __tracing_enable_event(unsigned short id, bool enable);
 #else
 static inline void *tracing_reserve_entry(unsigned long length) { return NULL; }
 static inline void tracing_commit_entry(void) { }
+#define HYP_EVENT(__name, __proto, __struct, __assign, __printk)      \
+	static inline void trace_##__name(__proto) {}
 
 static inline int __tracing_load(unsigned long desc_va, size_t desc_size) { return -ENODEV; }
 static inline void __tracing_unload(void) { }
@@ -23,5 +53,6 @@ static inline int __tracing_enable(bool enable) { return -ENODEV; }
 static inline int __tracing_swap_reader(unsigned int cpu) { return -ENODEV; }
 static inline void __tracing_update_clock(u32 mult, u32 shift, u64 epoch_ns, u64 epoch_cyc) { }
 static inline int __tracing_reset(unsigned int cpu) { return -ENODEV; }
+static inline int __tracing_enable_event(unsigned short id, bool enable)  { return -ENODEV; }
 #endif
 #endif
diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile
index f1840628d2d6..143d55ec7298 100644
--- a/arch/arm64/kvm/hyp/nvhe/Makefile
+++ b/arch/arm64/kvm/hyp/nvhe/Makefile
@@ -29,7 +29,7 @@ hyp-obj-y += ../vgic-v3-sr.o ../aarch32.o ../vgic-v2-cpuif-proxy.o ../entry.o \
 	 ../fpsimd.o ../hyp-entry.o ../exception.o ../pgtable.o
 hyp-obj-y += ../../../kernel/smccc-call.o
 hyp-obj-$(CONFIG_LIST_HARDENED) += list_debug.o
-hyp-obj-$(CONFIG_NVHE_EL2_TRACING) += clock.o trace.o
+hyp-obj-$(CONFIG_NVHE_EL2_TRACING) += clock.o trace.o events.o
 hyp-obj-y += $(lib-objs)
 
 # Path to simple_ring_buffer.c
diff --git a/arch/arm64/kvm/hyp/nvhe/events.c b/arch/arm64/kvm/hyp/nvhe/events.c
new file mode 100644
index 000000000000..add9383aadb5
--- /dev/null
+++ b/arch/arm64/kvm/hyp/nvhe/events.c
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2025 Google LLC
+ * Author: Vincent Donnefort <vdonnefort at google.com>
+ */
+
+#include <nvhe/mm.h>
+#include <nvhe/trace.h>
+
+#include <nvhe/define_events.h>
+
+int __tracing_enable_event(unsigned short id, bool enable)
+{
+	struct hyp_event_id *event_id = &__hyp_event_ids_start[id];
+	atomic_t *enabled;
+
+	if (event_id >= __hyp_event_ids_end)
+		return -EINVAL;
+
+	enabled = hyp_fixmap_map(__hyp_pa(&event_id->enabled));
+	atomic_set(enabled, enable);
+	hyp_fixmap_unmap();
+
+	return 0;
+}
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index f92e82cbfcb4..446603cdad7b 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -632,6 +632,14 @@ static void handle___tracing_reset(struct kvm_cpu_context *host_ctxt)
 	cpu_reg(host_ctxt, 1) = __tracing_reset(cpu);
 }
 
+static void handle___tracing_enable_event(struct kvm_cpu_context *host_ctxt)
+{
+	DECLARE_REG(unsigned short, id, host_ctxt, 1);
+	DECLARE_REG(bool, enable, host_ctxt, 2);
+
+	cpu_reg(host_ctxt, 1) = __tracing_enable_event(id, enable);
+}
+
 typedef void (*hcall_t)(struct kvm_cpu_context *);
 
 #define HANDLE_FUNC(x)	[__KVM_HOST_SMCCC_FUNC_##x] = (hcall_t)handle_##x
@@ -679,6 +687,7 @@ static const hcall_t host_hcall[] = {
 	HANDLE_FUNC(__tracing_swap_reader),
 	HANDLE_FUNC(__tracing_update_clock),
 	HANDLE_FUNC(__tracing_reset),
+	HANDLE_FUNC(__tracing_enable_event),
 };
 
 static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp.lds.S b/arch/arm64/kvm/hyp/nvhe/hyp.lds.S
index d724f6d69302..7a02837203d1 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp.lds.S
+++ b/arch/arm64/kvm/hyp/nvhe/hyp.lds.S
@@ -16,6 +16,12 @@ SECTIONS {
 	HYP_SECTION(.text)
 	HYP_SECTION(.data..ro_after_init)
 	HYP_SECTION(.rodata)
+#ifdef CONFIG_NVHE_EL2_TRACING
+	. = ALIGN(PAGE_SIZE);
+	BEGIN_HYP_SECTION(.event_ids)
+		*(SORT(.hyp.event_ids.*))
+	END_HYP_SECTION
+#endif
 
 	/*
 	 * .hyp..data..percpu needs to be page aligned to maintain the same
diff --git a/arch/arm64/kvm/hyp_trace.c b/arch/arm64/kvm/hyp_trace.c
index 09bc192e3514..0144cd26703e 100644
--- a/arch/arm64/kvm/hyp_trace.c
+++ b/arch/arm64/kvm/hyp_trace.c
@@ -318,6 +318,25 @@ static int hyp_trace_reset(unsigned int cpu, void *priv)
 
 static int hyp_trace_enable_event(unsigned short id, bool enable, void *priv)
 {
+	struct hyp_event_id *event_id = lm_alias(&__hyp_event_ids_start[id]);
+	struct page *page;
+	atomic_t *enabled;
+	void *map;
+
+	if (is_protected_kvm_enabled())
+		return kvm_call_hyp_nvhe(__tracing_enable_event, id, enable);
+
+	enabled = &event_id->enabled;
+	page = virt_to_page(enabled);
+	map = vmap(&page, 1, VM_MAP, PAGE_KERNEL);
+	if (!map)
+		return -ENOMEM;
+
+	enabled = map + offset_in_page(enabled);
+	atomic_set(enabled, enable);
+
+	vunmap(map);
+
 	return 0;
 }
 
@@ -345,6 +364,19 @@ static struct trace_remote_callbacks trace_remote_callbacks = {
 	.enable_event		= hyp_trace_enable_event,
 };
 
+#include <asm/kvm_define_hypevents.h>
+
+static void __init hyp_trace_init_events(void)
+{
+	struct hyp_event_id *hyp_event_id = __hyp_event_ids_start;
+	struct remote_event *event = __hyp_events_start;
+	int id = 0;
+
+	/* Events on both sides hypervisor are sorted */
+	for (; event < __hyp_events_end; event++, hyp_event_id++, id++)
+		event->id = hyp_event_id->id = id;
+}
+
 int __init kvm_hyp_trace_init(void)
 {
 	int cpu;
@@ -364,5 +396,8 @@ int __init kvm_hyp_trace_init(void)
 	}
 #endif
 
-	return trace_remote_register("hypervisor", &trace_remote_callbacks, &trace_buffer, NULL, 0);
+	hyp_trace_init_events();
+
+	return trace_remote_register("hypervisor", &trace_remote_callbacks, &trace_buffer,
+				     __hyp_events_start, __hyp_events_end - __hyp_events_start);
 }
-- 
2.52.0.107.ga0afd4fd5b-goog



From vdonnefort at google.com  Tue Dec  2 01:36:21 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Tue,  2 Dec 2025 09:36:21 +0000
Subject: [PATCH v9 28/30] KVM: arm64: Add hyp_enter/hyp_exit events to
 nVHE/pKVM hyp
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
References: <20251202093623.2337860-1-vdonnefort@google.com>
Message-ID: <20251202093623.2337860-29-vdonnefort@google.com>

The hyp_enter and hyp_exit events are logged by the hypervisor any time
it is entered and exited.

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

diff --git a/arch/arm64/include/asm/kvm_hypevents.h b/arch/arm64/include/asm/kvm_hypevents.h
index d6e033c96c52..268b3cd7a1b2 100644
--- a/arch/arm64/include/asm/kvm_hypevents.h
+++ b/arch/arm64/include/asm/kvm_hypevents.h
@@ -7,4 +7,39 @@
 #include <nvhe/trace.h>
 #endif
 
+#ifndef __HYP_ENTER_EXIT_REASON
+#define __HYP_ENTER_EXIT_REASON
+enum hyp_enter_exit_reason {
+	HYP_REASON_SMC,
+	HYP_REASON_HVC,
+	HYP_REASON_PSCI,
+	HYP_REASON_HOST_ABORT,
+	HYP_REASON_GUEST_EXIT,
+	HYP_REASON_ERET_HOST,
+	HYP_REASON_ERET_GUEST,
+	HYP_REASON_UNKNOWN	/* Must be last */
+};
+#endif
+
+HYP_EVENT(hyp_enter,
+	HE_PROTO(u8 reason),
+	HE_STRUCT(
+		he_field(u8, reason)
+	),
+	HE_ASSIGN(
+		__entry->reason = reason;
+	),
+	HE_PRINTK("reason=%s", __hyp_enter_exit_reason_str(__entry->reason))
+);
+
+HYP_EVENT(hyp_exit,
+	HE_PROTO(u8 reason),
+	HE_STRUCT(
+		he_field(u8, reason)
+	),
+	HE_ASSIGN(
+		__entry->reason = reason;
+	),
+	HE_PRINTK("reason=%s", __hyp_enter_exit_reason_str(__entry->reason))
+);
 #endif
diff --git a/arch/arm64/kvm/hyp/include/nvhe/arm-smccc.h b/arch/arm64/kvm/hyp/include/nvhe/arm-smccc.h
new file mode 100644
index 000000000000..7cd0f701f3c9
--- /dev/null
+++ b/arch/arm64/kvm/hyp/include/nvhe/arm-smccc.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ARM64_KVM_HYP_NVHE_ARM_SMCCC_H__
+#define __ARM64_KVM_HYP_NVHE_ARM_SMCCC_H__
+
+#include <asm/kvm_hypevents.h>
+
+#include <linux/arm-smccc.h>
+
+#define hyp_smccc_1_1_smc(...)					\
+	do {							\
+		trace_hyp_exit(HYP_REASON_SMC);			\
+		arm_smccc_1_1_smc(__VA_ARGS__);			\
+		trace_hyp_enter(HYP_REASON_SMC);		\
+	} while (0)
+
+#define hyp_smccc_1_2_smc(...)					\
+	do {							\
+		trace_hyp_exit(HYP_REASON_SMC);			\
+		arm_smccc_1_2_smc(__VA_ARGS__);			\
+		trace_hyp_enter(HYP_REASON_SMC);		\
+	} while (0)
+
+#endif /* __ARM64_KVM_HYP_NVHE_ARM_SMCCC_H__ */
diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c
index 58b7d0c477d7..73d79f9de850 100644
--- a/arch/arm64/kvm/hyp/nvhe/ffa.c
+++ b/arch/arm64/kvm/hyp/nvhe/ffa.c
@@ -26,10 +26,10 @@
  * the duration and are therefore serialised.
  */
 
-#include <linux/arm-smccc.h>
 #include <linux/arm_ffa.h>
 #include <asm/kvm_pkvm.h>
 
+#include <nvhe/arm-smccc.h>
 #include <nvhe/ffa.h>
 #include <nvhe/mem_protect.h>
 #include <nvhe/memory.h>
@@ -147,7 +147,7 @@ static int ffa_map_hyp_buffers(u64 ffa_page_count)
 {
 	struct arm_smccc_1_2_regs res;
 
-	arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
+	hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
 		.a0 = FFA_FN64_RXTX_MAP,
 		.a1 = hyp_virt_to_phys(hyp_buffers.tx),
 		.a2 = hyp_virt_to_phys(hyp_buffers.rx),
@@ -161,7 +161,7 @@ static int ffa_unmap_hyp_buffers(void)
 {
 	struct arm_smccc_1_2_regs res;
 
-	arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
+	hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
 		.a0 = FFA_RXTX_UNMAP,
 		.a1 = HOST_FFA_ID,
 	}, &res);
@@ -172,7 +172,7 @@ static int ffa_unmap_hyp_buffers(void)
 static void ffa_mem_frag_tx(struct arm_smccc_1_2_regs *res, u32 handle_lo,
 			     u32 handle_hi, u32 fraglen, u32 endpoint_id)
 {
-	arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
+	hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
 		.a0 = FFA_MEM_FRAG_TX,
 		.a1 = handle_lo,
 		.a2 = handle_hi,
@@ -184,7 +184,7 @@ static void ffa_mem_frag_tx(struct arm_smccc_1_2_regs *res, u32 handle_lo,
 static void ffa_mem_frag_rx(struct arm_smccc_1_2_regs *res, u32 handle_lo,
 			     u32 handle_hi, u32 fragoff)
 {
-	arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
+	hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
 		.a0 = FFA_MEM_FRAG_RX,
 		.a1 = handle_lo,
 		.a2 = handle_hi,
@@ -196,7 +196,7 @@ static void ffa_mem_frag_rx(struct arm_smccc_1_2_regs *res, u32 handle_lo,
 static void ffa_mem_xfer(struct arm_smccc_1_2_regs *res, u64 func_id, u32 len,
 			  u32 fraglen)
 {
-	arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
+	hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
 		.a0 = func_id,
 		.a1 = len,
 		.a2 = fraglen,
@@ -206,7 +206,7 @@ static void ffa_mem_xfer(struct arm_smccc_1_2_regs *res, u64 func_id, u32 len,
 static void ffa_mem_reclaim(struct arm_smccc_1_2_regs *res, u32 handle_lo,
 			     u32 handle_hi, u32 flags)
 {
-	arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
+	hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
 		.a0 = FFA_MEM_RECLAIM,
 		.a1 = handle_lo,
 		.a2 = handle_hi,
@@ -216,7 +216,7 @@ static void ffa_mem_reclaim(struct arm_smccc_1_2_regs *res, u32 handle_lo,
 
 static void ffa_retrieve_req(struct arm_smccc_1_2_regs *res, u32 len)
 {
-	arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
+	hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
 		.a0 = FFA_FN64_MEM_RETRIEVE_REQ,
 		.a1 = len,
 		.a2 = len,
@@ -225,7 +225,7 @@ static void ffa_retrieve_req(struct arm_smccc_1_2_regs *res, u32 len)
 
 static void ffa_rx_release(struct arm_smccc_1_2_regs *res)
 {
-	arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
+	hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
 		.a0 = FFA_RX_RELEASE,
 	}, res);
 }
@@ -728,7 +728,7 @@ static int hyp_ffa_post_init(void)
 	size_t min_rxtx_sz;
 	struct arm_smccc_1_2_regs res;
 
-	arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs){
+	hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs){
 		.a0 = FFA_ID_GET,
 	}, &res);
 	if (res.a0 != FFA_SUCCESS)
@@ -737,7 +737,7 @@ static int hyp_ffa_post_init(void)
 	if (res.a2 != HOST_FFA_ID)
 		return -EINVAL;
 
-	arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs){
+	hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs){
 		.a0 = FFA_FEATURES,
 		.a1 = FFA_FN64_RXTX_MAP,
 	}, &res);
@@ -788,7 +788,7 @@ static void do_ffa_version(struct arm_smccc_1_2_regs *res,
 	 * first if TEE supports it.
 	 */
 	if (FFA_MINOR_VERSION(ffa_req_version) < FFA_MINOR_VERSION(hyp_ffa_version)) {
-		arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
+		hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
 			.a0 = FFA_VERSION,
 			.a1 = ffa_req_version,
 		}, res);
@@ -824,7 +824,7 @@ static void do_ffa_part_get(struct arm_smccc_1_2_regs *res,
 		goto out_unlock;
 	}
 
-	arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
+	hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
 		.a0 = FFA_PARTITION_INFO_GET,
 		.a1 = uuid0,
 		.a2 = uuid1,
@@ -939,7 +939,7 @@ int hyp_ffa_init(void *pages)
 	if (kvm_host_psci_config.smccc_version < ARM_SMCCC_VERSION_1_2)
 		return 0;
 
-	arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
+	hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
 		.a0 = FFA_VERSION,
 		.a1 = FFA_VERSION_1_2,
 	}, &res);
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 446603cdad7b..ffda4850022f 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -12,6 +12,7 @@
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_host.h>
 #include <asm/kvm_hyp.h>
+#include <asm/kvm_hypevents.h>
 #include <asm/kvm_mmu.h>
 
 #include <nvhe/ffa.h>
@@ -728,7 +729,9 @@ static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
 
 static void default_host_smc_handler(struct kvm_cpu_context *host_ctxt)
 {
+	trace_hyp_exit(HYP_REASON_SMC);
 	__kvm_hyp_host_forward_smc(host_ctxt);
+	trace_hyp_enter(HYP_REASON_SMC);
 }
 
 static void handle_host_smc(struct kvm_cpu_context *host_ctxt)
@@ -752,18 +755,24 @@ void handle_trap(struct kvm_cpu_context *host_ctxt)
 {
 	u64 esr = read_sysreg_el2(SYS_ESR);
 
+
 	switch (ESR_ELx_EC(esr)) {
 	case ESR_ELx_EC_HVC64:
+		trace_hyp_enter(HYP_REASON_HVC);
 		handle_host_hcall(host_ctxt);
 		break;
 	case ESR_ELx_EC_SMC64:
+		trace_hyp_enter(HYP_REASON_SMC);
 		handle_host_smc(host_ctxt);
 		break;
 	case ESR_ELx_EC_IABT_LOW:
 	case ESR_ELx_EC_DABT_LOW:
+		trace_hyp_enter(HYP_REASON_HOST_ABORT);
 		handle_host_mem_abort(host_ctxt);
 		break;
 	default:
 		BUG();
 	}
+
+	trace_hyp_exit(HYP_REASON_ERET_HOST);
 }
diff --git a/arch/arm64/kvm/hyp/nvhe/psci-relay.c b/arch/arm64/kvm/hyp/nvhe/psci-relay.c
index c3e196fb8b18..58658e09c372 100644
--- a/arch/arm64/kvm/hyp/nvhe/psci-relay.c
+++ b/arch/arm64/kvm/hyp/nvhe/psci-relay.c
@@ -6,11 +6,12 @@
 
 #include <asm/kvm_asm.h>
 #include <asm/kvm_hyp.h>
+#include <asm/kvm_hypevents.h>
 #include <asm/kvm_mmu.h>
-#include <linux/arm-smccc.h>
 #include <linux/kvm_host.h>
 #include <uapi/linux/psci.h>
 
+#include <nvhe/arm-smccc.h>
 #include <nvhe/memory.h>
 #include <nvhe/trap_handler.h>
 
@@ -65,7 +66,7 @@ static unsigned long psci_call(unsigned long fn, unsigned long arg0,
 {
 	struct arm_smccc_res res;
 
-	arm_smccc_1_1_smc(fn, arg0, arg1, arg2, &res);
+	hyp_smccc_1_1_smc(fn, arg0, arg1, arg2, &res);
 	return res.a0;
 }
 
@@ -205,6 +206,7 @@ asmlinkage void __noreturn __kvm_host_psci_cpu_entry(bool is_cpu_on)
 	struct psci_boot_args *boot_args;
 	struct kvm_cpu_context *host_ctxt;
 
+	trace_hyp_enter(HYP_REASON_PSCI);
 	host_ctxt = host_data_ptr(host_ctxt);
 
 	if (is_cpu_on)
@@ -221,6 +223,7 @@ asmlinkage void __noreturn __kvm_host_psci_cpu_entry(bool is_cpu_on)
 	write_sysreg_el1(INIT_SCTLR_EL1_MMU_OFF, SYS_SCTLR);
 	write_sysreg(INIT_PSTATE_EL1, SPSR_EL2);
 
+	trace_hyp_exit(HYP_REASON_PSCI);
 	__host_enter(host_ctxt);
 }
 
diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c
index d3b9ec8a7c28..3dc2bbab4bfc 100644
--- a/arch/arm64/kvm/hyp/nvhe/switch.c
+++ b/arch/arm64/kvm/hyp/nvhe/switch.c
@@ -7,7 +7,6 @@
 #include <hyp/switch.h>
 #include <hyp/sysreg-sr.h>
 
-#include <linux/arm-smccc.h>
 #include <linux/kvm_host.h>
 #include <linux/types.h>
 #include <linux/jump_label.h>
@@ -21,6 +20,7 @@
 #include <asm/kvm_asm.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_hyp.h>
+#include <asm/kvm_hypevents.h>
 #include <asm/kvm_mmu.h>
 #include <asm/fpsimd.h>
 #include <asm/debug-monitors.h>
@@ -308,10 +308,13 @@ int __kvm_vcpu_run(struct kvm_vcpu *vcpu)
 	__debug_switch_to_guest(vcpu);
 
 	do {
+		trace_hyp_exit(HYP_REASON_ERET_GUEST);
+
 		/* Jump in the fire! */
 		exit_code = __guest_enter(vcpu);
 
 		/* And we're baaack! */
+		trace_hyp_enter(HYP_REASON_GUEST_EXIT);
 	} while (fixup_guest_exit(vcpu, &exit_code));
 
 	__sysreg_save_state_nvhe(guest_ctxt);
diff --git a/arch/arm64/kvm/hyp_trace.c b/arch/arm64/kvm/hyp_trace.c
index 0144cd26703e..1ad6a55ba95c 100644
--- a/arch/arm64/kvm/hyp_trace.c
+++ b/arch/arm64/kvm/hyp_trace.c
@@ -364,8 +364,26 @@ static struct trace_remote_callbacks trace_remote_callbacks = {
 	.enable_event		= hyp_trace_enable_event,
 };
 
+static const char *__hyp_enter_exit_reason_str(u8 reason);
+
 #include <asm/kvm_define_hypevents.h>
 
+static const char *__hyp_enter_exit_reason_str(u8 reason)
+{
+	static const char strs[][12] = {
+		"smc",
+		"hvc",
+		"psci",
+		"host_abort",
+		"guest_exit",
+		"eret_host",
+		"eret_guest",
+		"unknown",
+	};
+
+	return strs[min(reason, HYP_REASON_UNKNOWN)];
+}
+
 static void __init hyp_trace_init_events(void)
 {
 	struct hyp_event_id *hyp_event_id = __hyp_event_ids_start;
-- 
2.52.0.107.ga0afd4fd5b-goog



From ryan.roberts at arm.com  Tue Dec  2 01:39:40 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Tue, 2 Dec 2025 09:39:40 +0000
Subject: [RFC PATCH v1 2/2] randomize_kstack: Unify random source across
 arches
In-Reply-To: <aS6ylpLIyDZOvBDB@J2N7QTR9R3>
References: <20251127105958.2427758-1-ryan.roberts@arm.com>
 <20251127105958.2427758-3-ryan.roberts@arm.com>
 <CAMj1kXFY1RXk8T4f46bkm_sr0nJfBoO+ii68JK4+CsRiDwKdCg@mail.gmail.com>
 <9097505d-b18b-4f85-a02c-7f2865ad8bca@arm.com>
 <CAMj1kXHX1W2Kz5NJehtzDhOCKWEd6y1sp8+ViOMHGsq9e8=7Pw@mail.gmail.com>
 <aS6ylpLIyDZOvBDB@J2N7QTR9R3>
Message-ID: <7da8d5cc-7b67-4f51-8f09-7ca401d06a3d@arm.com>

On 02/12/2025 09:35, Mark Rutland wrote:
> On Tue, Dec 02, 2025 at 10:15:22AM +0100, Ard Biesheuvel wrote:
>> On Mon, 1 Dec 2025 at 19:20, Ryan Roberts <ryan.roberts at arm.com> wrote:
>>> On 28/11/2025 11:01, Ard Biesheuvel wrote:
>>>> On Thu, 27 Nov 2025 at 12:00, Ryan Roberts <ryan.roberts at arm.com> wrote:
>>>>> diff --git a/include/linux/randomize_kstack.h b/include/linux/randomize_kstack.h
>>>>> index 089b1432f7e6..83c7e6710f6d 100644
>>>>> --- a/include/linux/randomize_kstack.h
>>>>> +++ b/include/linux/randomize_kstack.h
>>>>> @@ -6,6 +6,7 @@
>>>>>  #include <linux/kernel.h>
>>>>>  #include <linux/jump_label.h>
>>>>>  #include <linux/percpu-defs.h>
>>>>> +#include <linux/prandom.h>
>>>>>
>>>>>  DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
>>>>>                          randomize_kstack_offset);
>>>>> @@ -45,9 +46,13 @@ DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
>>>>>  #define KSTACK_OFFSET_MAX(x)   ((x) & 0b1111111100)
>>>>>  #endif
>>>>>
>>>>> +static __always_inline u32 get_update_kstack_offset(void)
>>>>> +{
>>>>> +       return prandom_u32_state(&current->kstack_rnd_state);
>>>
>>> I've got bot warnings because this is being called from noinstr code. I guess
>>> the best option is to just move add_random_kstack_offset() to after
>>> instrumentation is enabled for the affected arches.
>>
>> Just put instrumentation_begin()/instrumentation_end() around the call
>> to prandom_u32_state() - that seems to be the common approach for
>> punching holes into the 'noinstr' validation.
> 
> That silences the warning, but isn't necessarily safe, so please DO NOT
> do that blindly. The instrumentation_{begin,end}() annotations are only
> supposed to be used when we know by construction that instrumentation is
> safe.
> 
> Generally, if you can move this to after instrumentation is already
> enabled, that should be safe, and so that'd be the better approach.
> 
> Ryan, can you share those warnings (e.g. link to those reports)?

https://lore.kernel.org/oe-kbuild-all/202511302137.u4iIA2kf-lkp at intel.com/
https://lore.kernel.org/oe-kbuild-all/202511302317.BGFIlAYX-lkp at intel.com/

> 
> IIUC only x86 has noinstr validation, and from a quick scan, I expect
> you see warnings from:
> 
> * do_syscall_64()
> * do_int80_syscall_32()
> * __do_fast_syscall_32()
> 
> For all of these, it is not safe to call instrumentable code before the
> calls to {syscall_,}enter_from_user_mode{,_prepare}(). You'll need to
> move the stack rnadomization after the existing instrumentation_begin()
> calls.
> 
> We'll need to go check the other architectures similarly.

OK understood. I'll do it this way then.

> 
> Mark.



From krzk at kernel.org  Tue Dec  2 01:42:38 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 2 Dec 2025 10:42:38 +0100
Subject: [PATCH v8 2/2] usb: dwc3: Add Google Tensor SoC DWC3 glue driver
In-Reply-To: <2025120209-unstylish-john-2a6c@gregkh>
References: <20251122-controller-v8-0-e7562e0df658@google.com>
 <20251122-controller-v8-2-e7562e0df658@google.com>
 <2025112226-heave-refrain-53e6@gregkh>
 <CA+zupgwzQ5r=-_L79D74=9VRqRO94N0yTApHChM+Nu0cn1ss3w@mail.gmail.com>
 <2025120209-unstylish-john-2a6c@gregkh>
Message-ID: <00d75fd3-a796-402a-a1a3-2172862fcf91@kernel.org>

On 02/12/2025 10:27, Greg Kroah-Hartman wrote:
>>>         depends on (OF && COMMON_CLK && RESET_CONTROLLER) || COMPILE_TEST
>>>
>>> I shouldn't have to enable those options to just get a build test here,
>>> the apis should be properly stubbed out if those options are not
>>> enabled, right?
>>>
>>> thanks,
>>>
>>> greg k-h
>>
>> Hi Greg,
>>
>> I agree with your interpretation of COMPILE_TEST but it doesn't
>> seem to align with upstream convention. I found the following pattern
>> in several device driver Kconfig files (including but not limited to usb,
>> pinctrl and phy).
>>
>>     depends on COMPILE_TEST || ARCH_XXX
>>     depends on CONFIG_A && CONFIG_B...
>>
>> For this patch, the APIs exposed by OF, COMMON_CLK
>> and RESET_CONTROLLER are properly stubbed out so
>> I'm all good to go with your suggestion, but I'd like to make
>> sure this approach is conventional.
> 
> Whatever works for building properly, as-is, what you have in this patch
> didn't work for my systems at all.
> 
>> I plan to add ARCH_GOOGLE as a dependency in the next
>> version per [1], so the "depends on" would probably look like
>> the following per your suggestion:
> 
> But "Google" is not an arch :(
> 
> And really, the whole "only have a sub-arch symbol" is something that
> personally, I think is totally wrong and prevents kernel images from
> being built for more than one "arch".  As an example, the Android GKI

Probably you think ARCH_FOO as arch/FOO/ directory, but this is not the
case. ARCH_FOO in this context is SoC platform, so e.g.
arch/arm64/boot/dts/FOO/.

All of ARCH_FOO build into one image and that's recommended way to limit
unnecessary drivers.

It's just confusing naming for whatever reason.

> kernel has to support more than one of these, so what does putting this
> behind a symbol that no one will actually use mean anything?  Android
> will never be only building a ARCH_GOOGLE kernel.

But distros will be, people will be. OK, maybe not for ARCH_GOOGLE, but
ARCH_QCOM we do for Qualcomm-based laptops and embedded folks even more.

We had this talk in the past. The point is that these drivers here are
unusable outside of that hardware platform, so only when you choose
hardware platform (ARCH_EXYNOS, ARCH_GOOGLE, ARCH_QCOM) you will be able
to choose these drivers.

You can also look at ARCH_FOO a bit orthogonal to actual kernel
architecture, because ARCH_EXYNOS is for both arm (arm32) and arm64. The
drivers should be available for all Exynos-platforms, regardless whether
this is arm32 or arm64.

> 
>>     depends on (OF && COMMON_CLK && RESET_CONTROLLER && ARCH_GOOGLE)
>> || COMPILE_TEST
>>
>> Please let me know your thoughts.
>> [1] https://lore.kernel.org/linux-phy/1a53d473-fc13-4ac5-ba52-4701d95e3073 at kernel.org/
> 
> Again, I hate the ARCH_ stuff, but Krzysztof does seem to like it for
> some reason, so I'll defer to others here.  But note, as someone who
> helps maintain a "generic" ARM64 kernel, these ARCH_* usages for
> different platforms do nothing at all to help anyone out.

True and that's not their goal. The truly generic kernels, like you
mentioned or arch/arm64/configs/defconfig, build everything for arm64.
The entire point is to limit this for actual users wanting much smaller
kernels and distros, which do not need these on for example RISC-V.


Best regards,
Krzysztof


From kory.maincent at bootlin.com  Tue Dec  2 01:42:44 2025
From: kory.maincent at bootlin.com (Kory Maincent)
Date: Tue, 2 Dec 2025 10:42:44 +0100
Subject: [PATCH 05/21] ARM: dts: omap: Bind panel to panel-dpi instead
 of ti,tilcdc,panel driver
In-Reply-To: <3bc5bf92-05c3-4841-ab28-9bab2bb31cd5@kernel.org>
References: <20251126-feature_tilcdc-v1-0-49b9ef2e3aa0@bootlin.com>
	<20251126-feature_tilcdc-v1-5-49b9ef2e3aa0@bootlin.com>
	<96b1b7bf-ddbe-4213-a201-dc89cf2998dd@ideasonboard.com>
	<3bc5bf92-05c3-4841-ab28-9bab2bb31cd5@kernel.org>
Message-ID: <20251202104244.59a9e83d@kmaincent-XPS-13-7390>

On Mon, 1 Dec 2025 22:46:01 +0100
Krzysztof Kozlowski <krzk at kernel.org> wrote:

> On 01/12/2025 15:13, Tomi Valkeinen wrote:
> > Hi Kory,
> > 
> > On 26/11/2025 19:35, Kory Maincent (TI.com) wrote:  
> >> Use panel-dpi driver instead of the deprecated tilcdc-panel driver in
> >> preparation for removing the tilcdc-panel driver and binding.
> >>
> >> Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
> >> ---
> >>
> >> This patch is not tested. It would be nice if someone with one of this
> >> board could test and validate it.
> >> ---
> >>  arch/arm/boot/dts/ti/davinci/da850-evm.dts    | 26
> >> +++++++++++++------------- arch/arm/boot/dts/ti/omap/am335x-guardian.dts |
> >> 25 +++++++++---------------- arch/arm/boot/dts/ti/omap/am335x-pdu001.dts
> >> | 21 ++++++++++----------- arch/arm/boot/dts/ti/omap/am335x-pepper.dts   |
> >> 22 +++++++++++----------- arch/arm/boot/dts/ti/omap/am335x-sbc-t335.dts |
> >> 25 +++++++++++++------------ arch/arm/boot/dts/ti/omap/am335x-sl50.dts
> >> | 25 ++++++++++++------------- 6 files changed, 68 insertions(+), 76
> >> deletions(-) 
> > 
> > Doesn't this, or rather the following patches, break DTB compatibility
> > with all the above boards?  

Yes, I know this but I still wanted to try and begin a discussion on this, as I
really thought it is not a good idea to add and maintain an new non-standard
panel driver solely for this tilcdc panel binding.
I have gathered more arguments on this topic on next patch. 
 
> Stuffing DTS change in the middle of the driver change tries to hide
> impact, which is not nice on its own.

As it needs driver change before the removal for not breaking things it can't
be done at the beginning of the series.

Regards,
-- 
K?ry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com


From ardb at kernel.org  Tue Dec  2 01:47:04 2025
From: ardb at kernel.org (Ard Biesheuvel)
Date: Tue, 2 Dec 2025 10:47:04 +0100
Subject: [RFC PATCH v1 2/2] randomize_kstack: Unify random source across arches
In-Reply-To: <aS6ylpLIyDZOvBDB@J2N7QTR9R3>
References: <20251127105958.2427758-1-ryan.roberts@arm.com>
 <20251127105958.2427758-3-ryan.roberts@arm.com> <CAMj1kXFY1RXk8T4f46bkm_sr0nJfBoO+ii68JK4+CsRiDwKdCg@mail.gmail.com>
 <9097505d-b18b-4f85-a02c-7f2865ad8bca@arm.com> <CAMj1kXHX1W2Kz5NJehtzDhOCKWEd6y1sp8+ViOMHGsq9e8=7Pw@mail.gmail.com>
 <aS6ylpLIyDZOvBDB@J2N7QTR9R3>
Message-ID: <CAMj1kXG=HDVso1xc6TGgSrBpV3Sq2YQLdPKg2dw5z9qdrbdWBw@mail.gmail.com>

On Tue, 2 Dec 2025 at 10:35, Mark Rutland <mark.rutland at arm.com> wrote:
>
> On Tue, Dec 02, 2025 at 10:15:22AM +0100, Ard Biesheuvel wrote:
> > On Mon, 1 Dec 2025 at 19:20, Ryan Roberts <ryan.roberts at arm.com> wrote:
> > > On 28/11/2025 11:01, Ard Biesheuvel wrote:
> > > > On Thu, 27 Nov 2025 at 12:00, Ryan Roberts <ryan.roberts at arm.com> wrote:
> > > >> diff --git a/include/linux/randomize_kstack.h b/include/linux/randomize_kstack.h
> > > >> index 089b1432f7e6..83c7e6710f6d 100644
> > > >> --- a/include/linux/randomize_kstack.h
> > > >> +++ b/include/linux/randomize_kstack.h
> > > >> @@ -6,6 +6,7 @@
> > > >>  #include <linux/kernel.h>
> > > >>  #include <linux/jump_label.h>
> > > >>  #include <linux/percpu-defs.h>
> > > >> +#include <linux/prandom.h>
> > > >>
> > > >>  DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
> > > >>                          randomize_kstack_offset);
> > > >> @@ -45,9 +46,13 @@ DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
> > > >>  #define KSTACK_OFFSET_MAX(x)   ((x) & 0b1111111100)
> > > >>  #endif
> > > >>
> > > >> +static __always_inline u32 get_update_kstack_offset(void)
> > > >> +{
> > > >> +       return prandom_u32_state(&current->kstack_rnd_state);
> > >
> > > I've got bot warnings because this is being called from noinstr code. I guess
> > > the best option is to just move add_random_kstack_offset() to after
> > > instrumentation is enabled for the affected arches.
> >
> > Just put instrumentation_begin()/instrumentation_end() around the call
> > to prandom_u32_state() - that seems to be the common approach for
> > punching holes into the 'noinstr' validation.
>
> That silences the warning, but isn't necessarily safe, so please DO NOT
> do that blindly.

Oops - sorry about that.

> The instrumentation_{begin,end}() annotations are only
> supposed to be used when we know by construction that instrumentation is
> safe.
>
> Generally, if you can move this to after instrumentation is already
> enabled, that should be safe, and so that'd be the better approach.
>
> Ryan, can you share those warnings (e.g. link to those reports)?
>
> IIUC only x86 has noinstr validation, and from a quick scan, I expect
> you see warnings from:
>
> * do_syscall_64()
> * do_int80_syscall_32()
> * __do_fast_syscall_32()
>
> For all of these, it is not safe to call instrumentable code before the
> calls to {syscall_,}enter_from_user_mode{,_prepare}(). You'll need to
> move the stack rnadomization after the existing instrumentation_begin()
> calls.
>
> We'll need to go check the other architectures similarly.
>

Given that prandom_u32_state() does a fairly straight-forward mangle
of 4 32-bit words, might it be better to make that __always_inline
itself?


From kyrie.wu at mediatek.com  Tue Dec  2 01:47:49 2025
From: kyrie.wu at mediatek.com (Kyrie Wu)
Date: Tue, 2 Dec 2025 17:47:49 +0800
Subject: [PATCH v11 01/12] media: mediatek: jpeg: fix jpeg hw count setting
In-Reply-To: <20251202094800.6140-1-kyrie.wu@mediatek.com>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
Message-ID: <20251202094800.6140-2-kyrie.wu@mediatek.com>

Different ICs have different amounts of hardware,
use a variable to set the amount of hardware.

Fixes: 934e8bccac95 ("mtk-jpegenc: support jpegenc multi-hardware")
Fixes: 0fa49df4222f ("media: mtk-jpegdec: support jpegdec multi-hardware")

Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
---
 drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c   | 8 ++++----
 drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h   | 2 ++
 drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c | 1 +
 drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c | 1 +
 4 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
index 6268d651bdcf..6a7e01130f1c 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
@@ -1467,7 +1467,7 @@ static int mtk_jpegenc_get_hw(struct mtk_jpeg_ctx *ctx)
 	int i;
 
 	spin_lock_irqsave(&jpeg->hw_lock, flags);
-	for (i = 0; i < MTK_JPEGENC_HW_MAX; i++) {
+	for (i = 0; i < jpeg->max_hw_count; i++) {
 		comp_jpeg = jpeg->enc_hw_dev[i];
 		if (comp_jpeg->hw_state == MTK_JPEG_HW_IDLE) {
 			hw_id = i;
@@ -1514,7 +1514,7 @@ static int mtk_jpegdec_get_hw(struct mtk_jpeg_ctx *ctx)
 	int i;
 
 	spin_lock_irqsave(&jpeg->hw_lock, flags);
-	for (i = 0; i < MTK_JPEGDEC_HW_MAX; i++) {
+	for (i = 0; i < jpeg->max_hw_count; i++) {
 		comp_jpeg = jpeg->dec_hw_dev[i];
 		if (comp_jpeg->hw_state == MTK_JPEG_HW_IDLE) {
 			hw_id = i;
@@ -1597,7 +1597,7 @@ static void mtk_jpegenc_worker(struct work_struct *work)
 		jpeg_work);
 	struct mtk_jpeg_dev *jpeg = ctx->jpeg;
 
-	for (i = 0; i < MTK_JPEGENC_HW_MAX; i++)
+	for (i = 0; i < jpeg->max_hw_count; i++)
 		comp_jpeg[i] = jpeg->enc_hw_dev[i];
 	i = 0;
 
@@ -1692,7 +1692,7 @@ static void mtk_jpegdec_worker(struct work_struct *work)
 	struct mtk_jpeg_fb fb;
 	unsigned long flags;
 
-	for (i = 0; i < MTK_JPEGDEC_HW_MAX; i++)
+	for (i = 0; i < jpeg->max_hw_count; i++)
 		comp_jpeg[i] = jpeg->dec_hw_dev[i];
 	i = 0;
 
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
index 02ed0ed5b736..6be5cf30dea1 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
@@ -212,6 +212,7 @@ struct mtk_jpegdec_comp_dev {
  * @reg_decbase:	jpg decode register base addr
  * @dec_hw_dev:	jpg decode hardware device
  * @hw_index:		jpg hw index
+ * @max_hw_count:	jpeg hw-core count
  */
 struct mtk_jpeg_dev {
 	struct mutex		lock;
@@ -234,6 +235,7 @@ struct mtk_jpeg_dev {
 	void __iomem *reg_decbase[MTK_JPEGDEC_HW_MAX];
 	struct mtk_jpegdec_comp_dev *dec_hw_dev[MTK_JPEGDEC_HW_MAX];
 	atomic_t hw_index;
+	u32 max_hw_count;
 };
 
 /**
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
index e78e1d11093c..a1e54715cb7e 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
@@ -664,6 +664,7 @@ static int mtk_jpegdec_hw_probe(struct platform_device *pdev)
 	master_dev->dec_hw_dev[i] = dev;
 	master_dev->reg_decbase[i] = dev->reg_base;
 	dev->master_dev = master_dev;
+	master_dev->max_hw_count++;
 
 	platform_set_drvdata(pdev, dev);
 	pm_runtime_enable(&pdev->dev);
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
index 9ab27aee302a..28d05909c96f 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
@@ -386,6 +386,7 @@ static int mtk_jpegenc_hw_probe(struct platform_device *pdev)
 	master_dev->enc_hw_dev[i] = dev;
 	master_dev->reg_encbase[i] = dev->reg_base;
 	dev->master_dev = master_dev;
+	master_dev->max_hw_count++;
 
 	platform_set_drvdata(pdev, dev);
 	pm_runtime_enable(&pdev->dev);
-- 
2.45.2



From kyrie.wu at mediatek.com  Tue Dec  2 01:47:48 2025
From: kyrie.wu at mediatek.com (Kyrie Wu)
Date: Tue, 2 Dec 2025 17:47:48 +0800
Subject: [PATCH v11 00/12] Enable jpeg enc & dec multi-hardwares for MT8196
Message-ID: <20251202094800.6140-1-kyrie.wu@mediatek.com>

This series have the follow changing:
Firstly fix some bugs, including resolution change handleing, stop
streaming sw flow, fix buffer layout and clock setting to support multi-hw
jpeg working and others.
Secondly add mt8196 jpegdec and jpegenc compatible to support MT8196
kernel driver.
Lastly, Add smmu setting to support smmu and iommu at the same time.

This series has been tested with MT8196 tast test.
Encoding and decoding worked for this chip.

Patches 1 fix jpeg hw count setting to support different chips.
Patches 2 fix jpeg buffer payload setting to handle buffer
size bug while resolution changed.
Patches 3 fix jpeg dst buffer layout.
Patches 4 fix multi-core stop streaming flow
Patches 5 fix multi-core clk suspend/resume setting
Patches 6 fix decoding buffer number setting timing issue
Patches 7 fix decoding resolution change operation
Patches 8 fix remove buffer operation
Patches 9-11 Adds jpeg encoder and decoder compatible.
Patches 12 add jpeg smmu sid setting.

---
Changes compared with v10:
--Rebased on top of the latest media tree
--add reviewer to commit messages

Changes compared with v9:
--Rebased on top of the latest media tree

Changes compared with v8:
--Rebased on top of the latest media tree

Changes compared with v7:
--Rebased on top of the latest media tree

Changes compared with v6:
--Rebased on top of the latest media tree

Changes compared with v5:
--reorder the patches set.
--fix commit message of patch 1-8.

Changes compared with v4:
--fix kernel robot build errors for patch 4.
--add reviewer for patch 1 and patch 2.

Changes compared with v3:
--change patch subject of jpeg encoder and decoder compatible.

Changes compared with v2:
--refactor smmu sid setting function interface
--Some modifications for patch v2's review comments.

Changes compared with v1:
--refine jpeg dt-bindings for MT8196
--optimize software code to manage jpeg HW count
--refactor smmu sid setting function interface
--Some modifications for patch v1's review comments.

Kyrie Wu (12):
  media: mediatek: jpeg: fix jpeg hw count setting
  media: mediatek: jpeg: fix jpeg buffer payload setting
  media: mediatek: jpeg: fix jpeg buffer layout
  media: mediatek: jpeg: fix stop streaming flow for multi-core
  media: mediatek: jpeg: fix multi-core clk suspend and resume setting
  media: mediatek: jpeg: fix decoding buffer number setting timing issue
  media: mediatek: jpeg: fix decoding resolution change operation
  media: mediatek: jpeg: fix remove buffer operation for multi-core
  media: dt-bindings: mediatek,jpeg: Add mediatek, mt8196-jpgdec
    compatible
  media: dt-bindings: mediatek,jpeg: Add mediatek, mt8196-jpgenc
    compatible
  media: mediatek: jpeg: add jpeg compatible
  media: mediatek: jpeg: add jpeg smmu sid setting

 .../media/mediatek,mt8195-jpegdec.yaml        |   8 +-
 .../media/mediatek,mt8195-jpegenc.yaml        |   8 +-
 .../platform/mediatek/jpeg/mtk_jpeg_core.c    | 170 +++++++++++++-----
 .../platform/mediatek/jpeg/mtk_jpeg_core.h    |  21 ++-
 .../platform/mediatek/jpeg/mtk_jpeg_dec_hw.c  | 112 +++++++++++-
 .../platform/mediatek/jpeg/mtk_jpeg_enc_hw.c  | 112 +++++++++++-
 6 files changed, 376 insertions(+), 55 deletions(-)

-- 
2.45.2



From kyrie.wu at mediatek.com  Tue Dec  2 01:47:51 2025
From: kyrie.wu at mediatek.com (Kyrie Wu)
Date: Tue, 2 Dec 2025 17:47:51 +0800
Subject: [PATCH v11 03/12] media: mediatek: jpeg: fix jpeg buffer layout
In-Reply-To: <20251202094800.6140-1-kyrie.wu@mediatek.com>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
Message-ID: <20251202094800.6140-4-kyrie.wu@mediatek.com>

For memory alloc operation of jpeg dst buffer: the mallocing
memory function interface use vb2_buffer as the base addr.
If structure mtk_jpeg_src_buf wants to be allocated to memory,
it needs to be placed vb2_v4l2_buffer at the starting position,
because structure vb2_buffer is at the starting position of
vb2_v4l2_buffer, and the allocated size is set to the size of
structure mtk_jpeg_src_buf, so as to ensure that structures
mtk_jpeg_src_buf, vb2_v4l2_buffer and vb2_buffer can all be
allocated memory.

Fixes: 5fb1c2361e56 ("mtk-jpegenc: add jpeg encode worker interface")

Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
---
 drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c | 2 +-
 drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
index 0cf3dc5407e4..bd0afc93d491 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
@@ -1099,7 +1099,7 @@ static int mtk_jpeg_queue_init(void *priv, struct vb2_queue *src_vq,
 	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
 	dst_vq->io_modes = VB2_DMABUF | VB2_MMAP;
 	dst_vq->drv_priv = ctx;
-	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	dst_vq->buf_struct_size = sizeof(struct mtk_jpeg_src_buf);
 	dst_vq->ops = jpeg->variant->qops;
 	dst_vq->mem_ops = &vb2_dma_contig_memops;
 	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
index 6be5cf30dea1..148fd41759b7 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
@@ -85,10 +85,10 @@ struct mtk_jpeg_variant {
 };
 
 struct mtk_jpeg_src_buf {
-	u32 frame_num;
 	struct vb2_v4l2_buffer b;
 	struct list_head list;
 	u32 bs_size;
+	u32 frame_num;
 	struct mtk_jpeg_dec_param dec_param;
 
 	struct mtk_jpeg_ctx *curr_ctx;
-- 
2.45.2



From kyrie.wu at mediatek.com  Tue Dec  2 01:47:50 2025
From: kyrie.wu at mediatek.com (Kyrie Wu)
Date: Tue, 2 Dec 2025 17:47:50 +0800
Subject: [PATCH v11 02/12] media: mediatek: jpeg: fix jpeg buffer payload setting
In-Reply-To: <20251202094800.6140-1-kyrie.wu@mediatek.com>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
Message-ID: <20251202094800.6140-3-kyrie.wu@mediatek.com>

For multi-core jpegdec, if one of hws gets the event of resolution
changing, the payload size, representing the size of Y/C data,
needed to change. But others hws are decoding at the same time and
it can not be changed immediately, which results that the payload
size is not equal to the real buffer length of the hw's, which occurred
resolution changing and a warnning call trace will print.
So the setting of payload size must less than the real buffer length
to remove the warnning logs.

Fixes: 0fa49df4222f ("media: mtk-jpegdec: support jpegdec multi-hardware")

Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
---
 .../platform/mediatek/jpeg/mtk_jpeg_core.c    | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
index 6a7e01130f1c..0cf3dc5407e4 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
@@ -709,6 +709,7 @@ static int mtk_jpeg_buf_prepare(struct vb2_buffer *vb)
 	struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
 	struct mtk_jpeg_q_data *q_data = NULL;
 	struct v4l2_plane_pix_format plane_fmt = {};
+	unsigned long max_size;
 	int i;
 
 	q_data = mtk_jpeg_get_q_data(ctx, vb->vb2_queue->type);
@@ -717,12 +718,20 @@ static int mtk_jpeg_buf_prepare(struct vb2_buffer *vb)
 
 	for (i = 0; i < q_data->fmt->colplanes; i++) {
 		plane_fmt = q_data->pix_mp.plane_fmt[i];
+		max_size = plane_fmt.sizeimage;
+
 		if (ctx->enable_exif &&
-		    q_data->fmt->fourcc == V4L2_PIX_FMT_JPEG)
-			vb2_set_plane_payload(vb, i, plane_fmt.sizeimage +
-					      MTK_JPEG_MAX_EXIF_SIZE);
-		else
-			vb2_set_plane_payload(vb, i,  plane_fmt.sizeimage);
+			q_data->fmt->fourcc == V4L2_PIX_FMT_JPEG) {
+			max_size += MTK_JPEG_MAX_EXIF_SIZE;
+
+			vb2_set_plane_payload(vb, i,
+					      MIN(vb->planes[i].length,
+						  max_size));
+		} else {
+			vb2_set_plane_payload(vb, i,
+					      MIN(plane_fmt.sizeimage,
+						  vb->planes[i].length));
+		}
 	}
 
 	return 0;
-- 
2.45.2



From kyrie.wu at mediatek.com  Tue Dec  2 01:47:52 2025
From: kyrie.wu at mediatek.com (Kyrie Wu)
Date: Tue, 2 Dec 2025 17:47:52 +0800
Subject: [PATCH v11 04/12] media: mediatek: jpeg: fix stop streaming flow for multi-core
In-Reply-To: <20251202094800.6140-1-kyrie.wu@mediatek.com>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
Message-ID: <20251202094800.6140-5-kyrie.wu@mediatek.com>

For jpeg multi-core architecture, if all hardware run at the
same time, some input and output buffers are occupied.
If one hardware is completed firstly, while other hardwares are
still running. The decoding completion signal calls
mtk_jpeg_dec_stop_streaming, and the function of v4l2_m2m_buf_done
is called in mtk_jpeg_dec_stop_streaming to complete all
input/output buffers. However, some buffers are occupied by other
hardwares, resulting in errors. It needs to add a counter to
calculate the used decoding buffer counts, it will increase 1 when
the buffer set to hardware and decrease to 0 until the all buffers
decoded and the function could continue to be executed.

Fixes: 0fa49df4222f ("media: mtk-jpegdec: support jpegdec multi-hardware")
Fixes: dedc21500334 ("media: mtk-jpegdec: add jpeg decode worker interface")
Fixes: 934e8bccac95 ("mtk-jpegenc: support jpegenc multi-hardware")
Fixes: 5fb1c2361e56 ("mtk-jpegenc: add jpeg encode worker interface")

Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
---
 .../media/platform/mediatek/jpeg/mtk_jpeg_core.c | 16 ++++++++++++++++
 .../media/platform/mediatek/jpeg/mtk_jpeg_core.h |  2 ++
 .../platform/mediatek/jpeg/mtk_jpeg_dec_hw.c     |  9 +++++++++
 .../platform/mediatek/jpeg/mtk_jpeg_enc_hw.c     |  9 +++++++++
 4 files changed, 36 insertions(+)

diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
index bd0afc93d491..59fd79c89f88 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
@@ -857,8 +857,12 @@ static struct vb2_v4l2_buffer *mtk_jpeg_buf_remove(struct mtk_jpeg_ctx *ctx,
 static void mtk_jpeg_enc_stop_streaming(struct vb2_queue *q)
 {
 	struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(q);
+	struct mtk_jpeg_dev *jpeg = ctx->jpeg;
 	struct vb2_v4l2_buffer *vb;
 
+	if (jpeg->variant->multi_core)
+		wait_event(jpeg->hw_wq, (atomic_read(&ctx->buf_list_cnt) == 0));
+
 	while ((vb = mtk_jpeg_buf_remove(ctx, q->type)))
 		v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR);
 }
@@ -866,6 +870,7 @@ static void mtk_jpeg_enc_stop_streaming(struct vb2_queue *q)
 static void mtk_jpeg_dec_stop_streaming(struct vb2_queue *q)
 {
 	struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(q);
+	struct mtk_jpeg_dev *jpeg = ctx->jpeg;
 	struct vb2_v4l2_buffer *vb;
 
 	/*
@@ -873,6 +878,9 @@ static void mtk_jpeg_dec_stop_streaming(struct vb2_queue *q)
 	 * Before STREAMOFF, we still have to return the old resolution and
 	 * subsampling. Update capture queue when the stream is off.
 	 */
+	if (jpeg->variant->multi_core)
+		wait_event(jpeg->hw_wq, (atomic_read(&ctx->buf_list_cnt) == 0));
+
 	if (ctx->state == MTK_JPEG_SOURCE_CHANGE &&
 	    V4L2_TYPE_IS_CAPTURE(q->type)) {
 		struct mtk_jpeg_src_buf *src_buf;
@@ -1181,6 +1189,7 @@ static int mtk_jpeg_open(struct file *file)
 	spin_lock_init(&ctx->done_queue_lock);
 	v4l2_fh_init(&ctx->fh, vfd);
 	v4l2_fh_add(&ctx->fh, file);
+	atomic_set(&ctx->buf_list_cnt, 0);
 
 	ctx->jpeg = jpeg;
 	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx,
@@ -1563,6 +1572,11 @@ static int mtk_jpegdec_set_hw_param(struct mtk_jpeg_ctx *ctx,
 	return 0;
 }
 
+static void jpeg_buf_queue_inc(struct mtk_jpeg_ctx *ctx)
+{
+	atomic_inc(&ctx->buf_list_cnt);
+}
+
 static irqreturn_t mtk_jpeg_enc_done(struct mtk_jpeg_dev *jpeg)
 {
 	struct mtk_jpeg_ctx *ctx;
@@ -1671,6 +1685,7 @@ static void mtk_jpegenc_worker(struct work_struct *work)
 			     &src_buf->vb2_buf);
 	mtk_jpeg_set_enc_params(ctx, comp_jpeg[hw_id]->reg_base);
 	mtk_jpeg_enc_start(comp_jpeg[hw_id]->reg_base);
+	jpeg_buf_queue_inc(ctx);
 	v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
 	spin_unlock_irqrestore(&comp_jpeg[hw_id]->hw_lock, flags);
 
@@ -1786,6 +1801,7 @@ static void mtk_jpegdec_worker(struct work_struct *work)
 				&bs,
 				&fb);
 	mtk_jpeg_dec_start(comp_jpeg[hw_id]->reg_base);
+	jpeg_buf_queue_inc(ctx);
 	v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
 	spin_unlock_irqrestore(&comp_jpeg[hw_id]->hw_lock, flags);
 
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
index 148fd41759b7..33f7fbc4ca5e 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
@@ -288,6 +288,7 @@ struct mtk_jpeg_q_data {
  * @dst_done_queue:		encoded frame buffer queue
  * @done_queue_lock:		encoded frame operation spinlock
  * @last_done_frame_num:	the last encoded frame number
+ * @buf_list_cnt:		the frame buffer count own by jpeg driver
  */
 struct mtk_jpeg_ctx {
 	struct mtk_jpeg_dev		*jpeg;
@@ -306,6 +307,7 @@ struct mtk_jpeg_ctx {
 	/* spinlock protecting the encode done buffer */
 	spinlock_t done_queue_lock;
 	u32 last_done_frame_num;
+	atomic_t buf_list_cnt;
 };
 
 #endif /* _MTK_JPEG_CORE_H */
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
index a1e54715cb7e..84d12eea35f7 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
@@ -519,6 +519,11 @@ static void mtk_jpegdec_put_buf(struct mtk_jpegdec_comp_dev *jpeg)
 	spin_unlock_irqrestore(&ctx->done_queue_lock, flags);
 }
 
+static void jpeg_buf_queue_dec(struct mtk_jpeg_ctx *ctx)
+{
+	atomic_dec(&ctx->buf_list_cnt);
+}
+
 static void mtk_jpegdec_timeout_work(struct work_struct *work)
 {
 	enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR;
@@ -527,9 +532,11 @@ static void mtk_jpegdec_timeout_work(struct work_struct *work)
 			     job_timeout_work.work);
 	struct mtk_jpeg_dev *master_jpeg = cjpeg->master_dev;
 	struct vb2_v4l2_buffer *src_buf, *dst_buf;
+	struct mtk_jpeg_ctx *ctx;
 
 	src_buf = cjpeg->hw_param.src_buffer;
 	dst_buf = cjpeg->hw_param.dst_buffer;
+	ctx = cjpeg->hw_param.curr_ctx;
 	v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
 
 	mtk_jpeg_dec_reset(cjpeg->reg_base);
@@ -540,6 +547,7 @@ static void mtk_jpegdec_timeout_work(struct work_struct *work)
 	wake_up(&master_jpeg->hw_wq);
 	v4l2_m2m_buf_done(src_buf, buf_state);
 	mtk_jpegdec_put_buf(cjpeg);
+	jpeg_buf_queue_dec(ctx);
 }
 
 static irqreturn_t mtk_jpegdec_hw_irq_handler(int irq, void *priv)
@@ -580,6 +588,7 @@ static irqreturn_t mtk_jpegdec_hw_irq_handler(int irq, void *priv)
 	buf_state = VB2_BUF_STATE_DONE;
 	v4l2_m2m_buf_done(src_buf, buf_state);
 	mtk_jpegdec_put_buf(jpeg);
+	jpeg_buf_queue_dec(ctx);
 	pm_runtime_put(ctx->jpeg->dev);
 	clk_disable_unprepare(jpeg->jdec_clk.clks->clk);
 
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
index 28d05909c96f..1862444f35f5 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
@@ -248,6 +248,11 @@ static void mtk_jpegenc_put_buf(struct mtk_jpegenc_comp_dev *jpeg)
 	spin_unlock_irqrestore(&ctx->done_queue_lock, flags);
 }
 
+static void jpeg_buf_queue_enc(struct mtk_jpeg_ctx *ctx)
+{
+	atomic_dec(&ctx->buf_list_cnt);
+}
+
 static void mtk_jpegenc_timeout_work(struct work_struct *work)
 {
 	struct delayed_work *dly_work = to_delayed_work(work);
@@ -258,9 +263,11 @@ static void mtk_jpegenc_timeout_work(struct work_struct *work)
 	struct mtk_jpeg_dev *master_jpeg = cjpeg->master_dev;
 	enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR;
 	struct vb2_v4l2_buffer *src_buf, *dst_buf;
+	struct mtk_jpeg_ctx *ctx;
 
 	src_buf = cjpeg->hw_param.src_buffer;
 	dst_buf = cjpeg->hw_param.dst_buffer;
+	ctx = cjpeg->hw_param.curr_ctx;
 	v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
 
 	mtk_jpeg_enc_reset(cjpeg->reg_base);
@@ -271,6 +278,7 @@ static void mtk_jpegenc_timeout_work(struct work_struct *work)
 	wake_up(&master_jpeg->hw_wq);
 	v4l2_m2m_buf_done(src_buf, buf_state);
 	mtk_jpegenc_put_buf(cjpeg);
+	jpeg_buf_queue_enc(ctx);
 }
 
 static irqreturn_t mtk_jpegenc_hw_irq_handler(int irq, void *priv)
@@ -304,6 +312,7 @@ static irqreturn_t mtk_jpegenc_hw_irq_handler(int irq, void *priv)
 	buf_state = VB2_BUF_STATE_DONE;
 	v4l2_m2m_buf_done(src_buf, buf_state);
 	mtk_jpegenc_put_buf(jpeg);
+	jpeg_buf_queue_enc(ctx);
 	pm_runtime_put(ctx->jpeg->dev);
 	clk_disable_unprepare(jpeg->venc_clk.clks->clk);
 
-- 
2.45.2



From kyrie.wu at mediatek.com  Tue Dec  2 01:47:57 2025
From: kyrie.wu at mediatek.com (Kyrie Wu)
Date: Tue, 2 Dec 2025 17:47:57 +0800
Subject: [PATCH v11 09/12] media: dt-bindings: mediatek,jpeg: Add mediatek, mt8196-jpgdec compatible
In-Reply-To: <20251202094800.6140-1-kyrie.wu@mediatek.com>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
Message-ID: <20251202094800.6140-10-kyrie.wu@mediatek.com>

Compared to the previous generation IC, the MT8196 uses SMMU
instead of IOMMU and supports features such as dynamic voltage
and frequency scaling. Therefore, add "mediatek,mt8196-jpgdec"
compatible to the binding document.

Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
---
 .../bindings/media/mediatek,mt8195-jpegdec.yaml           | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegdec.yaml b/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegdec.yaml
index e5448c60e3eb..28a9a9bfdbf8 100644
--- a/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegdec.yaml
+++ b/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegdec.yaml
@@ -14,7 +14,9 @@ description:
 
 properties:
   compatible:
-    const: mediatek,mt8195-jpgdec
+    enum:
+      - mediatek,mt8195-jpgdec
+      - mediatek,mt8196-jpgdec
 
   power-domains:
     maxItems: 1
@@ -44,7 +46,9 @@ patternProperties:
 
     properties:
       compatible:
-        const: mediatek,mt8195-jpgdec-hw
+        enum:
+          - mediatek,mt8195-jpgdec-hw
+          - mediatek,mt8196-jpgdec-hw
 
       reg:
         maxItems: 1
-- 
2.45.2



From kyrie.wu at mediatek.com  Tue Dec  2 01:47:56 2025
From: kyrie.wu at mediatek.com (Kyrie Wu)
Date: Tue, 2 Dec 2025 17:47:56 +0800
Subject: [PATCH v11 08/12] media: mediatek: jpeg: fix remove buffer operation for multi-core
In-Reply-To: <20251202094800.6140-1-kyrie.wu@mediatek.com>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
Message-ID: <20251202094800.6140-9-kyrie.wu@mediatek.com>

move remove buffer code to spinlock protect area for multi-core

Fixes: 86379bd9d399 ("media: mtk-jpeg: Fixes jpeg enc&dec worker sw flow")

Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
---
 drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
index 9233bbfe2d97..da1ca494ed4b 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
@@ -1665,9 +1665,6 @@ static void mtk_jpegenc_worker(struct work_struct *work)
 		goto enc_end;
 	}
 
-	v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
-	v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
-
 	schedule_delayed_work(&comp_jpeg[hw_id]->job_timeout_work,
 			      msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC));
 
@@ -1685,6 +1682,8 @@ static void mtk_jpegenc_worker(struct work_struct *work)
 			     &src_buf->vb2_buf);
 	mtk_jpeg_set_enc_params(ctx, comp_jpeg[hw_id]->reg_base);
 	mtk_jpeg_enc_start(comp_jpeg[hw_id]->reg_base);
+	v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+	v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
 	jpeg_buf_queue_inc(ctx);
 	v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
 	spin_unlock_irqrestore(&comp_jpeg[hw_id]->hw_lock, flags);
@@ -1767,9 +1766,6 @@ static void mtk_jpegdec_worker(struct work_struct *work)
 		goto dec_end;
 	}
 
-	v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
-	v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
-
 	mtk_jpeg_set_dec_src(ctx, &src_buf->vb2_buf, &bs);
 	if (mtk_jpeg_set_dec_dst(ctx,
 				 &jpeg_src_buf->dec_param,
@@ -1794,6 +1790,8 @@ static void mtk_jpegdec_worker(struct work_struct *work)
 				jpeg_src_buf->bs_size,
 				&bs,
 				&fb);
+	v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+	v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
 	mtk_jpeg_dec_start(comp_jpeg[hw_id]->reg_base);
 	jpeg_buf_queue_inc(ctx);
 	v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
-- 
2.45.2



From kyrie.wu at mediatek.com  Tue Dec  2 01:47:54 2025
From: kyrie.wu at mediatek.com (Kyrie Wu)
Date: Tue, 2 Dec 2025 17:47:54 +0800
Subject: [PATCH v11 06/12] media: mediatek: jpeg: fix decoding buffer number setting timing issue
In-Reply-To: <20251202094800.6140-1-kyrie.wu@mediatek.com>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
Message-ID: <20251202094800.6140-7-kyrie.wu@mediatek.com>

move decoding buffer increase code into spinlock
protecting aera for multi-core

Fixes: dedc21500334 ("media: mtk-jpegdec: add jpeg decode worker interface")

Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
---
 drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c   | 9 +++------
 drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c | 1 +
 drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c | 1 +
 3 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
index e45d7e82b8a0..5ffaee4dcd19 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
@@ -1746,7 +1746,6 @@ static void mtk_jpegdec_worker(struct work_struct *work)
 
 	v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
 	jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(&src_buf->vb2_buf);
-	jpeg_dst_buf = mtk_jpeg_vb2_to_srcbuf(&dst_buf->vb2_buf);
 
 	if (mtk_jpeg_check_resolution_change(ctx,
 					     &jpeg_src_buf->dec_param)) {
@@ -1755,11 +1754,6 @@ static void mtk_jpegdec_worker(struct work_struct *work)
 		goto getbuf_fail;
 	}
 
-	jpeg_src_buf->curr_ctx = ctx;
-	jpeg_src_buf->frame_num = ctx->total_frame_num;
-	jpeg_dst_buf->curr_ctx = ctx;
-	jpeg_dst_buf->frame_num = ctx->total_frame_num;
-
 	mtk_jpegdec_set_hw_param(ctx, hw_id, src_buf, dst_buf);
 	ret = pm_runtime_resume_and_get(comp_jpeg[hw_id]->dev);
 	if (ret < 0) {
@@ -1784,6 +1778,9 @@ static void mtk_jpegdec_worker(struct work_struct *work)
 			      msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC));
 
 	spin_lock_irqsave(&comp_jpeg[hw_id]->hw_lock, flags);
+	jpeg_dst_buf = mtk_jpeg_vb2_to_srcbuf(&dst_buf->vb2_buf);
+	jpeg_dst_buf->curr_ctx = ctx;
+	jpeg_dst_buf->frame_num = ctx->total_frame_num;
 	ctx->total_frame_num++;
 	mtk_jpeg_dec_reset(comp_jpeg[hw_id]->reg_base);
 	mtk_jpeg_dec_set_config(comp_jpeg[hw_id]->reg_base,
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
index 5f1557dafad6..b3142dc9be85 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
@@ -513,6 +513,7 @@ static void mtk_jpegdec_put_buf(struct mtk_jpegdec_comp_dev *jpeg)
 				v4l2_m2m_buf_done(&tmp_dst_done_buf->b,
 						  VB2_BUF_STATE_DONE);
 				ctx->last_done_frame_num++;
+				break;
 			}
 		}
 	}
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
index 785db5ba4770..82c971936c4d 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
@@ -242,6 +242,7 @@ static void mtk_jpegenc_put_buf(struct mtk_jpegenc_comp_dev *jpeg)
 				v4l2_m2m_buf_done(&tmp_dst_done_buf->b,
 						  VB2_BUF_STATE_DONE);
 				ctx->last_done_frame_num++;
+				break;
 			}
 		}
 	}
-- 
2.45.2



From kyrie.wu at mediatek.com  Tue Dec  2 01:47:58 2025
From: kyrie.wu at mediatek.com (Kyrie Wu)
Date: Tue, 2 Dec 2025 17:47:58 +0800
Subject: [PATCH v11 10/12] media: dt-bindings: mediatek,jpeg: Add mediatek, mt8196-jpgenc compatible
In-Reply-To: <20251202094800.6140-1-kyrie.wu@mediatek.com>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
Message-ID: <20251202094800.6140-11-kyrie.wu@mediatek.com>

Compared to the previous generation IC, the MT8196 uses SMMU
instead of IOMMU and supports features such as dynamic voltage
and frequency scaling. Therefore, add "mediatek,mt8196-jpgenc"
compatible to the binding document.

Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
---
 .../bindings/media/mediatek,mt8195-jpegenc.yaml           | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegenc.yaml b/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegenc.yaml
index 596186497b68..e2d772ea0fb0 100644
--- a/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegenc.yaml
+++ b/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegenc.yaml
@@ -14,7 +14,9 @@ description:
 
 properties:
   compatible:
-    const: mediatek,mt8195-jpgenc
+    enum:
+      - mediatek,mt8195-jpgenc
+      - mediatek,mt8196-jpgenc
 
   power-domains:
     maxItems: 1
@@ -44,7 +46,9 @@ patternProperties:
 
     properties:
       compatible:
-        const: mediatek,mt8195-jpgenc-hw
+        enum:
+          - mediatek,mt8195-jpgenc-hw
+          - mediatek,mt8196-jpgenc-hw
 
       reg:
         maxItems: 1
-- 
2.45.2



From kyrie.wu at mediatek.com  Tue Dec  2 01:47:53 2025
From: kyrie.wu at mediatek.com (Kyrie Wu)
Date: Tue, 2 Dec 2025 17:47:53 +0800
Subject: [PATCH v11 05/12] media: mediatek: jpeg: fix multi-core clk suspend and resume setting
In-Reply-To: <20251202094800.6140-1-kyrie.wu@mediatek.com>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
Message-ID: <20251202094800.6140-6-kyrie.wu@mediatek.com>

The suspend/resume callback function is defined in the dev_pm_ops
structure, which is defined in platform_driver. For multiple-core
architecture, each hardware driver will register a platform_driver
structure, so it is necessary to add a suspend/resume callback
function for each hardware to support this operation.

Fixes: 934e8bccac95 ("mtk-jpegenc: support jpegenc multi-hardware")
Fixes: 0fa49df4222f ("media: mtk-jpegdec: support jpegdec multi-hardware")

Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
---
 .../platform/mediatek/jpeg/mtk_jpeg_core.c    | 28 +++----
 .../platform/mediatek/jpeg/mtk_jpeg_dec_hw.c  | 75 ++++++++++++++++++-
 .../platform/mediatek/jpeg/mtk_jpeg_enc_hw.c  | 75 ++++++++++++++++++-
 3 files changed, 151 insertions(+), 27 deletions(-)

diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
index 59fd79c89f88..e45d7e82b8a0 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
@@ -1122,6 +1122,9 @@ static void mtk_jpeg_clk_on(struct mtk_jpeg_dev *jpeg)
 {
 	int ret;
 
+	if (jpeg->variant->multi_core)
+		return;
+
 	ret = clk_bulk_prepare_enable(jpeg->variant->num_clks,
 				      jpeg->variant->clks);
 	if (ret)
@@ -1130,6 +1133,9 @@ static void mtk_jpeg_clk_on(struct mtk_jpeg_dev *jpeg)
 
 static void mtk_jpeg_clk_off(struct mtk_jpeg_dev *jpeg)
 {
+	if (jpeg->variant->multi_core)
+		return;
+
 	clk_bulk_disable_unprepare(jpeg->variant->num_clks,
 				   jpeg->variant->clks);
 }
@@ -1658,13 +1664,6 @@ static void mtk_jpegenc_worker(struct work_struct *work)
 		goto enc_end;
 	}
 
-	ret = clk_prepare_enable(comp_jpeg[hw_id]->venc_clk.clks->clk);
-	if (ret) {
-		dev_err(jpeg->dev, "%s : %d, jpegenc clk_prepare_enable fail\n",
-			__func__, __LINE__);
-		goto enc_end;
-	}
-
 	v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
 	v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
 
@@ -1762,20 +1761,13 @@ static void mtk_jpegdec_worker(struct work_struct *work)
 	jpeg_dst_buf->frame_num = ctx->total_frame_num;
 
 	mtk_jpegdec_set_hw_param(ctx, hw_id, src_buf, dst_buf);
-	ret = pm_runtime_get_sync(comp_jpeg[hw_id]->dev);
+	ret = pm_runtime_resume_and_get(comp_jpeg[hw_id]->dev);
 	if (ret < 0) {
 		dev_err(jpeg->dev, "%s : %d, pm_runtime_get_sync fail !!!\n",
 			__func__, __LINE__);
 		goto dec_end;
 	}
 
-	ret = clk_prepare_enable(comp_jpeg[hw_id]->jdec_clk.clks->clk);
-	if (ret) {
-		dev_err(jpeg->dev, "%s : %d, jpegdec clk_prepare_enable fail\n",
-			__func__, __LINE__);
-		goto clk_end;
-	}
-
 	v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
 	v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
 
@@ -1785,7 +1777,7 @@ static void mtk_jpegdec_worker(struct work_struct *work)
 				 &dst_buf->vb2_buf, &fb)) {
 		dev_err(jpeg->dev, "%s : %d, mtk_jpeg_set_dec_dst fail\n",
 			__func__, __LINE__);
-		goto setdst_end;
+		goto set_dst_fail;
 	}
 
 	schedule_delayed_work(&comp_jpeg[hw_id]->job_timeout_work,
@@ -1807,9 +1799,7 @@ static void mtk_jpegdec_worker(struct work_struct *work)
 
 	return;
 
-setdst_end:
-	clk_disable_unprepare(comp_jpeg[hw_id]->jdec_clk.clks->clk);
-clk_end:
+set_dst_fail:
 	pm_runtime_put(comp_jpeg[hw_id]->dev);
 dec_end:
 	v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
index 84d12eea35f7..5f1557dafad6 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
@@ -540,14 +540,13 @@ static void mtk_jpegdec_timeout_work(struct work_struct *work)
 	v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
 
 	mtk_jpeg_dec_reset(cjpeg->reg_base);
-	clk_disable_unprepare(cjpeg->jdec_clk.clks->clk);
-	pm_runtime_put(cjpeg->dev);
 	cjpeg->hw_state = MTK_JPEG_HW_IDLE;
 	atomic_inc(&master_jpeg->hw_rdy);
 	wake_up(&master_jpeg->hw_wq);
 	v4l2_m2m_buf_done(src_buf, buf_state);
 	mtk_jpegdec_put_buf(cjpeg);
 	jpeg_buf_queue_dec(ctx);
+	pm_runtime_put(cjpeg->dev);
 }
 
 static irqreturn_t mtk_jpegdec_hw_irq_handler(int irq, void *priv)
@@ -589,12 +588,11 @@ static irqreturn_t mtk_jpegdec_hw_irq_handler(int irq, void *priv)
 	v4l2_m2m_buf_done(src_buf, buf_state);
 	mtk_jpegdec_put_buf(jpeg);
 	jpeg_buf_queue_dec(ctx);
-	pm_runtime_put(ctx->jpeg->dev);
-	clk_disable_unprepare(jpeg->jdec_clk.clks->clk);
 
 	jpeg->hw_state = MTK_JPEG_HW_IDLE;
 	wake_up(&master_jpeg->hw_wq);
 	atomic_inc(&master_jpeg->hw_rdy);
+	pm_runtime_put(jpeg->dev);
 
 	return IRQ_HANDLED;
 }
@@ -677,15 +675,84 @@ static int mtk_jpegdec_hw_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, dev);
 	pm_runtime_enable(&pdev->dev);
+	ret = devm_clk_bulk_get(dev->dev,
+				jpegdec_clk->clk_num,
+				jpegdec_clk->clks);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to init clk\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static void mtk_jpeg_clk_on(struct mtk_jpegdec_comp_dev *jpeg)
+{
+	int ret;
+
+	ret = clk_bulk_prepare_enable(jpeg->jdec_clk.clk_num,
+				      jpeg->jdec_clk.clks);
+	if (ret)
+		dev_err(jpeg->dev, "%s : %d, jpegdec clk_prepare_enable fail\n",
+			__func__, __LINE__);
+}
+
+static void mtk_jpeg_clk_off(struct mtk_jpegdec_comp_dev *jpeg)
+{
+	clk_bulk_disable_unprepare(jpeg->jdec_clk.clk_num,
+				   jpeg->jdec_clk.clks);
+}
+
+static __maybe_unused int mtk_jpegdec_pm_suspend(struct device *dev)
+{
+	struct mtk_jpegdec_comp_dev *jpeg = dev_get_drvdata(dev);
+
+	mtk_jpeg_clk_off(jpeg);
 
 	return 0;
 }
 
+static __maybe_unused int mtk_jpegdec_pm_resume(struct device *dev)
+{
+	struct mtk_jpegdec_comp_dev *jpeg = dev_get_drvdata(dev);
+
+	mtk_jpeg_clk_on(jpeg);
+
+	return 0;
+}
+
+static __maybe_unused int mtk_jpegdec_suspend(struct device *dev)
+{
+	struct mtk_jpegdec_comp_dev *jpeg = dev_get_drvdata(dev);
+
+	v4l2_m2m_suspend(jpeg->master_dev->m2m_dev);
+	return pm_runtime_force_suspend(dev);
+}
+
+static __maybe_unused int mtk_jpegdec_resume(struct device *dev)
+{
+	struct mtk_jpegdec_comp_dev *jpeg = dev_get_drvdata(dev);
+	int ret;
+
+	ret = pm_runtime_force_resume(dev);
+	if (ret < 0)
+		return ret;
+
+	v4l2_m2m_resume(jpeg->master_dev->m2m_dev);
+	return ret;
+}
+
+static const struct dev_pm_ops mtk_jpegdec_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(mtk_jpegdec_suspend, mtk_jpegdec_resume)
+	SET_RUNTIME_PM_OPS(mtk_jpegdec_pm_suspend, mtk_jpegdec_pm_resume, NULL)
+};
+
 static struct platform_driver mtk_jpegdec_hw_driver = {
 	.probe = mtk_jpegdec_hw_probe,
 	.driver = {
 		.name = "mtk-jpegdec-hw",
 		.of_match_table = mtk_jpegdec_hw_ids,
+		.pm             = &mtk_jpegdec_pm_ops,
 	},
 };
 
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
index 1862444f35f5..785db5ba4770 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
@@ -271,14 +271,13 @@ static void mtk_jpegenc_timeout_work(struct work_struct *work)
 	v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
 
 	mtk_jpeg_enc_reset(cjpeg->reg_base);
-	clk_disable_unprepare(cjpeg->venc_clk.clks->clk);
-	pm_runtime_put(cjpeg->dev);
 	cjpeg->hw_state = MTK_JPEG_HW_IDLE;
 	atomic_inc(&master_jpeg->hw_rdy);
 	wake_up(&master_jpeg->hw_wq);
 	v4l2_m2m_buf_done(src_buf, buf_state);
 	mtk_jpegenc_put_buf(cjpeg);
 	jpeg_buf_queue_enc(ctx);
+	pm_runtime_put(cjpeg->dev);
 }
 
 static irqreturn_t mtk_jpegenc_hw_irq_handler(int irq, void *priv)
@@ -313,12 +312,11 @@ static irqreturn_t mtk_jpegenc_hw_irq_handler(int irq, void *priv)
 	v4l2_m2m_buf_done(src_buf, buf_state);
 	mtk_jpegenc_put_buf(jpeg);
 	jpeg_buf_queue_enc(ctx);
-	pm_runtime_put(ctx->jpeg->dev);
-	clk_disable_unprepare(jpeg->venc_clk.clks->clk);
 
 	jpeg->hw_state = MTK_JPEG_HW_IDLE;
 	wake_up(&master_jpeg->hw_wq);
 	atomic_inc(&master_jpeg->hw_rdy);
+	pm_runtime_put(jpeg->dev);
 
 	return IRQ_HANDLED;
 }
@@ -399,15 +397,84 @@ static int mtk_jpegenc_hw_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, dev);
 	pm_runtime_enable(&pdev->dev);
+	ret = devm_clk_bulk_get(dev->dev,
+				jpegenc_clk->clk_num,
+				jpegenc_clk->clks);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to init clk\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static void mtk_jpeg_clk_on(struct mtk_jpegenc_comp_dev *jpeg)
+{
+	int ret;
+
+	ret = clk_bulk_prepare_enable(jpeg->venc_clk.clk_num,
+				      jpeg->venc_clk.clks);
+	if (ret)
+		dev_err(jpeg->dev, "%s : %d, jpegenc clk_prepare_enable fail\n",
+			__func__, __LINE__);
+}
+
+static void mtk_jpeg_clk_off(struct mtk_jpegenc_comp_dev *jpeg)
+{
+	clk_bulk_disable_unprepare(jpeg->venc_clk.clk_num,
+				   jpeg->venc_clk.clks);
+}
+
+static __maybe_unused int mtk_jpegenc_pm_suspend(struct device *dev)
+{
+	struct mtk_jpegenc_comp_dev *jpeg = dev_get_drvdata(dev);
+
+	mtk_jpeg_clk_off(jpeg);
 
 	return 0;
 }
 
+static __maybe_unused int mtk_jpegenc_pm_resume(struct device *dev)
+{
+	struct mtk_jpegenc_comp_dev *jpeg = dev_get_drvdata(dev);
+
+	mtk_jpeg_clk_on(jpeg);
+
+	return 0;
+}
+
+static __maybe_unused int mtk_jpegenc_suspend(struct device *dev)
+{
+	struct mtk_jpegenc_comp_dev *jpeg = dev_get_drvdata(dev);
+
+	v4l2_m2m_suspend(jpeg->master_dev->m2m_dev);
+	return pm_runtime_force_suspend(dev);
+}
+
+static __maybe_unused int mtk_jpegenc_resume(struct device *dev)
+{
+	struct mtk_jpegenc_comp_dev *jpeg = dev_get_drvdata(dev);
+	int ret;
+
+	ret = pm_runtime_force_resume(dev);
+	if (ret < 0)
+		return ret;
+
+	v4l2_m2m_resume(jpeg->master_dev->m2m_dev);
+	return ret;
+}
+
+static const struct dev_pm_ops mtk_jpegenc_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(mtk_jpegenc_suspend, mtk_jpegenc_resume)
+	SET_RUNTIME_PM_OPS(mtk_jpegenc_pm_suspend, mtk_jpegenc_pm_resume, NULL)
+};
+
 static struct platform_driver mtk_jpegenc_hw_driver = {
 	.probe = mtk_jpegenc_hw_probe,
 	.driver = {
 		.name = "mtk-jpegenc-hw",
 		.of_match_table = mtk_jpegenc_drv_ids,
+		.pm = &mtk_jpegenc_pm_ops,
 	},
 };
 
-- 
2.45.2



From kyrie.wu at mediatek.com  Tue Dec  2 01:47:59 2025
From: kyrie.wu at mediatek.com (Kyrie Wu)
Date: Tue, 2 Dec 2025 17:47:59 +0800
Subject: [PATCH v11 11/12] media: mediatek: jpeg: add jpeg compatible
In-Reply-To: <20251202094800.6140-1-kyrie.wu@mediatek.com>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
Message-ID: <20251202094800.6140-12-kyrie.wu@mediatek.com>

Add jpeg dec and enc compatible for mt8196

Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
---
 .../platform/mediatek/jpeg/mtk_jpeg_core.c    | 34 +++++++++++++++++++
 .../platform/mediatek/jpeg/mtk_jpeg_dec_hw.c  |  3 ++
 .../platform/mediatek/jpeg/mtk_jpeg_enc_hw.c  |  3 ++
 3 files changed, 40 insertions(+)

diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
index da1ca494ed4b..10a588b92e76 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
@@ -1932,6 +1932,19 @@ static struct mtk_jpeg_variant mtk8195_jpegenc_drvdata = {
 	.jpeg_worker = mtk_jpegenc_worker,
 };
 
+static struct mtk_jpeg_variant mtk8196_jpegenc_drvdata = {
+	.formats = mtk_jpeg_enc_formats,
+	.num_formats = MTK_JPEG_ENC_NUM_FORMATS,
+	.qops = &mtk_jpeg_enc_qops,
+	.m2m_ops = &mtk_jpeg_multicore_enc_m2m_ops,
+	.dev_name = "mtk-jpeg-enc",
+	.ioctl_ops = &mtk_jpeg_enc_ioctl_ops,
+	.out_q_default_fourcc = V4L2_PIX_FMT_YUYV,
+	.cap_q_default_fourcc = V4L2_PIX_FMT_JPEG,
+	.multi_core = true,
+	.jpeg_worker = mtk_jpegenc_worker,
+};
+
 static const struct mtk_jpeg_variant mtk8195_jpegdec_drvdata = {
 	.formats = mtk_jpeg_dec_formats,
 	.num_formats = MTK_JPEG_DEC_NUM_FORMATS,
@@ -1945,6 +1958,19 @@ static const struct mtk_jpeg_variant mtk8195_jpegdec_drvdata = {
 	.jpeg_worker = mtk_jpegdec_worker,
 };
 
+static const struct mtk_jpeg_variant mtk8196_jpegdec_drvdata = {
+	.formats = mtk_jpeg_dec_formats,
+	.num_formats = MTK_JPEG_DEC_NUM_FORMATS,
+	.qops = &mtk_jpeg_dec_qops,
+	.m2m_ops = &mtk_jpeg_multicore_dec_m2m_ops,
+	.dev_name = "mtk-jpeg-dec",
+	.ioctl_ops = &mtk_jpeg_dec_ioctl_ops,
+	.out_q_default_fourcc = V4L2_PIX_FMT_JPEG,
+	.cap_q_default_fourcc = V4L2_PIX_FMT_YUV420M,
+	.multi_core = true,
+	.jpeg_worker = mtk_jpegdec_worker,
+};
+
 static const struct of_device_id mtk_jpeg_match[] = {
 	{
 		.compatible = "mediatek,mt8173-jpgdec",
@@ -1966,6 +1992,14 @@ static const struct of_device_id mtk_jpeg_match[] = {
 		.compatible = "mediatek,mt8195-jpgdec",
 		.data = &mtk8195_jpegdec_drvdata,
 	},
+	{
+		.compatible = "mediatek,mt8196-jpgenc",
+		.data = &mtk8196_jpegenc_drvdata,
+	},
+	{
+		.compatible = "mediatek,mt8196-jpgdec",
+		.data = &mtk8196_jpegdec_drvdata,
+	},
 	{},
 };
 
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
index b3142dc9be85..e453a1634f33 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
@@ -45,6 +45,9 @@ static const struct of_device_id mtk_jpegdec_hw_ids[] = {
 	{
 		.compatible = "mediatek,mt8195-jpgdec-hw",
 	},
+	{
+		.compatible = "mediatek,mt8196-jpgdec-hw",
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, mtk_jpegdec_hw_ids);
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
index 82c971936c4d..b30c728c3712 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
@@ -52,6 +52,9 @@ static const struct of_device_id mtk_jpegenc_drv_ids[] = {
 	{
 		.compatible = "mediatek,mt8195-jpgenc-hw",
 	},
+	{
+		.compatible = "mediatek,mt8196-jpgenc-hw",
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, mtk_jpegenc_drv_ids);
-- 
2.45.2



From kyrie.wu at mediatek.com  Tue Dec  2 01:48:00 2025
From: kyrie.wu at mediatek.com (Kyrie Wu)
Date: Tue, 2 Dec 2025 17:48:00 +0800
Subject: [PATCH v11 12/12] media: mediatek: jpeg: add jpeg smmu sid setting
In-Reply-To: <20251202094800.6140-1-kyrie.wu@mediatek.com>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
Message-ID: <20251202094800.6140-13-kyrie.wu@mediatek.com>

Add a configuration to set jpeg dec & enc smmu sid

Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
---
 .../platform/mediatek/jpeg/mtk_jpeg_core.c    | 37 +++++++++++++++++++
 .../platform/mediatek/jpeg/mtk_jpeg_core.h    | 15 ++++++++
 .../platform/mediatek/jpeg/mtk_jpeg_dec_hw.c  | 23 ++++++++++++
 .../platform/mediatek/jpeg/mtk_jpeg_enc_hw.c  | 23 ++++++++++++
 4 files changed, 98 insertions(+)

diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
index 10a588b92e76..625dfa8468e1 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
@@ -15,6 +15,7 @@
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <media/v4l2-event.h>
@@ -1613,6 +1614,20 @@ static irqreturn_t mtk_jpeg_enc_done(struct mtk_jpeg_dev *jpeg)
 	return IRQ_HANDLED;
 }
 
+static void mtk_jpeg_enc_set_smmu_sid(struct mtk_jpegenc_comp_dev *jpeg)
+{
+	struct mtk_jpeg_dev *mjpeg = jpeg->master_dev;
+
+	if (!mjpeg->variant->support_smmu || !jpeg->smmu_regmap)
+		return;
+
+	regmap_update_bits(jpeg->smmu_regmap, JPEG_ENC_SMMU_SID,
+			   JPG_REG_GUSER_ID_MASK <<
+			   JPG_REG_ENC_GUSER_ID_SHIFT,
+			   JPG_REG_GUSER_ID_ENC_SID <<
+			   JPG_REG_ENC_GUSER_ID_SHIFT);
+}
+
 static void mtk_jpegenc_worker(struct work_struct *work)
 {
 	struct mtk_jpegenc_comp_dev *comp_jpeg[MTK_JPEGENC_HW_MAX];
@@ -1674,6 +1689,9 @@ static void mtk_jpegenc_worker(struct work_struct *work)
 	jpeg_dst_buf->frame_num = ctx->total_frame_num;
 	ctx->total_frame_num++;
 	mtk_jpeg_enc_reset(comp_jpeg[hw_id]->reg_base);
+
+	mtk_jpeg_enc_set_smmu_sid(comp_jpeg[hw_id]);
+
 	mtk_jpeg_set_enc_dst(ctx,
 			     comp_jpeg[hw_id]->reg_base,
 			     &dst_buf->vb2_buf);
@@ -1701,6 +1719,20 @@ static void mtk_jpegenc_worker(struct work_struct *work)
 	v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
 }
 
+static void mtk_jpeg_dec_set_smmu_sid(struct mtk_jpegdec_comp_dev *jpeg)
+{
+	struct mtk_jpeg_dev *mjpeg = jpeg->master_dev;
+
+	if (!mjpeg->variant->support_smmu || !jpeg->smmu_regmap)
+		return;
+
+	regmap_update_bits(jpeg->smmu_regmap, JPEG_DEC_SMMU_SID,
+			   JPG_REG_GUSER_ID_MASK <<
+			   JPG_REG_DEC_GUSER_ID_SHIFT,
+			   JPG_REG_GUSER_ID_DEC_SID <<
+			   JPG_REG_DEC_GUSER_ID_SHIFT);
+}
+
 static void mtk_jpegdec_worker(struct work_struct *work)
 {
 	struct mtk_jpeg_ctx *ctx = container_of(work, struct mtk_jpeg_ctx,
@@ -1784,6 +1816,9 @@ static void mtk_jpegdec_worker(struct work_struct *work)
 	jpeg_dst_buf->frame_num = ctx->total_frame_num;
 	ctx->total_frame_num++;
 	mtk_jpeg_dec_reset(comp_jpeg[hw_id]->reg_base);
+
+	mtk_jpeg_dec_set_smmu_sid(comp_jpeg[hw_id]);
+
 	mtk_jpeg_dec_set_config(comp_jpeg[hw_id]->reg_base,
 				jpeg->variant->support_34bit,
 				&jpeg_src_buf->dec_param,
@@ -1943,6 +1978,7 @@ static struct mtk_jpeg_variant mtk8196_jpegenc_drvdata = {
 	.cap_q_default_fourcc = V4L2_PIX_FMT_JPEG,
 	.multi_core = true,
 	.jpeg_worker = mtk_jpegenc_worker,
+	.support_smmu = true,
 };
 
 static const struct mtk_jpeg_variant mtk8195_jpegdec_drvdata = {
@@ -1969,6 +2005,7 @@ static const struct mtk_jpeg_variant mtk8196_jpegdec_drvdata = {
 	.cap_q_default_fourcc = V4L2_PIX_FMT_YUV420M,
 	.multi_core = true,
 	.jpeg_worker = mtk_jpegdec_worker,
+	.support_smmu = true,
 };
 
 static const struct of_device_id mtk_jpeg_match[] = {
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
index 33f7fbc4ca5e..6e8304680393 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
@@ -11,6 +11,7 @@
 
 #include <linux/clk.h>
 #include <linux/interrupt.h>
+#include <linux/mfd/syscon.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-fh.h>
@@ -34,6 +35,14 @@
 
 #define MTK_JPEG_MAX_EXIF_SIZE	(64 * 1024)
 
+#define JPEG_DEC_SMMU_SID				0
+#define JPEG_ENC_SMMU_SID				0
+#define JPG_REG_GUSER_ID_MASK			0x7
+#define JPG_REG_GUSER_ID_DEC_SID		0x4
+#define JPG_REG_GUSER_ID_ENC_SID		0x5
+#define JPG_REG_DEC_GUSER_ID_SHIFT		8
+#define JPG_REG_ENC_GUSER_ID_SHIFT		4
+
 #define MTK_JPEG_ADDR_MASK GENMASK(1, 0)
 
 /**
@@ -65,6 +74,7 @@ enum mtk_jpeg_ctx_state {
  * @multi_core:		mark jpeg hw is multi_core or not
  * @jpeg_worker:		jpeg dec or enc worker
  * @support_34bit:	flag to check support for 34-bit DMA address
+ * @support_smmu:	flag to check if support smmu
  */
 struct mtk_jpeg_variant {
 	struct clk_bulk_data *clks;
@@ -82,6 +92,7 @@ struct mtk_jpeg_variant {
 	bool multi_core;
 	void (*jpeg_worker)(struct work_struct *work);
 	bool support_34bit;
+	bool support_smmu;
 };
 
 struct mtk_jpeg_src_buf {
@@ -150,6 +161,7 @@ struct mtk_jpegdec_clk {
  * @hw_param:		jpeg encode hw parameters
  * @hw_state:		record hw state
  * @hw_lock:		spinlock protecting the hw device resource
+ * @smmu_regmap:	SMMU registers mapping
  */
 struct mtk_jpegenc_comp_dev {
 	struct device *dev;
@@ -163,6 +175,7 @@ struct mtk_jpegenc_comp_dev {
 	enum mtk_jpeg_hw_state hw_state;
 	/* spinlock protecting the hw device resource */
 	spinlock_t hw_lock;
+	struct regmap *smmu_regmap;
 };
 
 /**
@@ -177,6 +190,7 @@ struct mtk_jpegenc_comp_dev {
  * @hw_param:			jpeg decode hw parameters
  * @hw_state:			record hw state
  * @hw_lock:			spinlock protecting hw
+ * @smmu_regmap:		SMMU registers mapping
  */
 struct mtk_jpegdec_comp_dev {
 	struct device *dev;
@@ -190,6 +204,7 @@ struct mtk_jpegdec_comp_dev {
 	enum mtk_jpeg_hw_state hw_state;
 	/* spinlock protecting the hw device resource */
 	spinlock_t hw_lock;
+	struct regmap *smmu_regmap;
 };
 
 /**
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
index e453a1634f33..da753a636eaa 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
@@ -624,6 +624,25 @@ static int mtk_jpegdec_hw_init_irq(struct mtk_jpegdec_comp_dev *dev)
 	return 0;
 }
 
+static int mtk_jpegdec_smmu_init(struct mtk_jpegdec_comp_dev *dev)
+{
+	struct mtk_jpeg_dev *master_dev = dev->master_dev;
+
+	if (!master_dev->variant->support_smmu)
+		return 0;
+
+	dev->smmu_regmap =
+		syscon_regmap_lookup_by_phandle(dev->plat_dev->dev.of_node,
+						"mediatek,smmu-config");
+	if (IS_ERR(dev->smmu_regmap)) {
+		return dev_err_probe(dev->dev, PTR_ERR(dev->smmu_regmap),
+				     "mmap smmu_base failed(%ld)\n",
+				     PTR_ERR(dev->smmu_regmap));
+	}
+
+	return 0;
+}
+
 static int mtk_jpegdec_hw_probe(struct platform_device *pdev)
 {
 	struct mtk_jpegdec_clk *jpegdec_clk;
@@ -677,6 +696,10 @@ static int mtk_jpegdec_hw_probe(struct platform_device *pdev)
 	dev->master_dev = master_dev;
 	master_dev->max_hw_count++;
 
+	ret = mtk_jpegdec_smmu_init(dev);
+	if (ret)
+		return ret;
+
 	platform_set_drvdata(pdev, dev);
 	pm_runtime_enable(&pdev->dev);
 	ret = devm_clk_bulk_get(dev->dev,
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
index b30c728c3712..8a61d5537315 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
@@ -348,6 +348,25 @@ static int mtk_jpegenc_hw_init_irq(struct mtk_jpegenc_comp_dev *dev)
 	return 0;
 }
 
+static int mtk_jpegenc_smmu_init(struct mtk_jpegenc_comp_dev *dev)
+{
+	struct mtk_jpeg_dev *master_dev = dev->master_dev;
+
+	if (!master_dev->variant->support_smmu)
+		return 0;
+
+	dev->smmu_regmap =
+		syscon_regmap_lookup_by_phandle(dev->plat_dev->dev.of_node,
+						"mediatek,smmu-config");
+	if (IS_ERR(dev->smmu_regmap)) {
+		return dev_err_probe(dev->dev, PTR_ERR(dev->smmu_regmap),
+				     "mmap smmu_base failed(%ld)\n",
+				     PTR_ERR(dev->smmu_regmap));
+	}
+
+	return 0;
+}
+
 static int mtk_jpegenc_hw_probe(struct platform_device *pdev)
 {
 	struct mtk_jpegenc_clk *jpegenc_clk;
@@ -399,6 +418,10 @@ static int mtk_jpegenc_hw_probe(struct platform_device *pdev)
 	dev->master_dev = master_dev;
 	master_dev->max_hw_count++;
 
+	ret = mtk_jpegenc_smmu_init(dev);
+	if (ret)
+		return ret;
+
 	platform_set_drvdata(pdev, dev);
 	pm_runtime_enable(&pdev->dev);
 	ret = devm_clk_bulk_get(dev->dev,
-- 
2.45.2



From kyrie.wu at mediatek.com  Tue Dec  2 01:47:55 2025
From: kyrie.wu at mediatek.com (Kyrie Wu)
Date: Tue, 2 Dec 2025 17:47:55 +0800
Subject: [PATCH v11 07/12] media: mediatek: jpeg: fix decoding resolution change operation
In-Reply-To: <20251202094800.6140-1-kyrie.wu@mediatek.com>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
Message-ID: <20251202094800.6140-8-kyrie.wu@mediatek.com>

1.add a judgement for src buffer to avoid kernel crash
in the stop streaming function;
2.When a resolution changing occurs, it needs to set new
resolution parameter immediately and then report this event.
Otherwise, if the original software process is maintained,
the resolution change event is reported firstly, the CPU is
dispatched to the app to process the event, and the driver
does not set a new resolution, which will cause parameter errors.
3.After a resolution change occurred, decoding should not continue,
needs to wait until new buffers are ready and the state machine
changed.

Fixes: dedc21500334 ("media: mtk-jpegdec: add jpeg decode worker interface")

Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
---
 drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
index 5ffaee4dcd19..9233bbfe2d97 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
@@ -887,7 +887,8 @@ static void mtk_jpeg_dec_stop_streaming(struct vb2_queue *q)
 
 		vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
 		src_buf = mtk_jpeg_vb2_to_srcbuf(&vb->vb2_buf);
-		mtk_jpeg_set_queue_data(ctx, &src_buf->dec_param);
+		if (!IS_ERR_OR_NULL(src_buf))
+			mtk_jpeg_set_queue_data(ctx, &src_buf->dec_param);
 		ctx->state = MTK_JPEG_RUNNING;
 	} else if (V4L2_TYPE_IS_OUTPUT(q->type)) {
 		ctx->state = MTK_JPEG_INIT;
@@ -1749,11 +1750,15 @@ static void mtk_jpegdec_worker(struct work_struct *work)
 
 	if (mtk_jpeg_check_resolution_change(ctx,
 					     &jpeg_src_buf->dec_param)) {
-		mtk_jpeg_queue_src_chg_event(ctx);
+		mtk_jpeg_set_queue_data(ctx, &jpeg_src_buf->dec_param);
 		ctx->state = MTK_JPEG_SOURCE_CHANGE;
+		mtk_jpeg_queue_src_chg_event(ctx);
 		goto getbuf_fail;
 	}
 
+	if (ctx->state == MTK_JPEG_SOURCE_CHANGE)
+		goto getbuf_fail;
+
 	mtk_jpegdec_set_hw_param(ctx, hw_id, src_buf, dst_buf);
 	ret = pm_runtime_resume_and_get(comp_jpeg[hw_id]->dev);
 	if (ret < 0) {
-- 
2.45.2



From mark.rutland at arm.com  Tue Dec  2 01:53:09 2025
From: mark.rutland at arm.com (Mark Rutland)
Date: Tue, 2 Dec 2025 09:53:09 +0000
Subject: [RFC PATCH v1 2/2] randomize_kstack: Unify random source across
 arches
In-Reply-To: <7da8d5cc-7b67-4f51-8f09-7ca401d06a3d@arm.com>
References: <20251127105958.2427758-1-ryan.roberts@arm.com>
 <20251127105958.2427758-3-ryan.roberts@arm.com>
 <CAMj1kXFY1RXk8T4f46bkm_sr0nJfBoO+ii68JK4+CsRiDwKdCg@mail.gmail.com>
 <9097505d-b18b-4f85-a02c-7f2865ad8bca@arm.com>
 <CAMj1kXHX1W2Kz5NJehtzDhOCKWEd6y1sp8+ViOMHGsq9e8=7Pw@mail.gmail.com>
 <aS6ylpLIyDZOvBDB@J2N7QTR9R3>
 <7da8d5cc-7b67-4f51-8f09-7ca401d06a3d@arm.com>
Message-ID: <aS63BeFzDCgkVsNy@J2N7QTR9R3>

On Tue, Dec 02, 2025 at 09:39:40AM +0000, Ryan Roberts wrote:
> On 02/12/2025 09:35, Mark Rutland wrote:
> > On Tue, Dec 02, 2025 at 10:15:22AM +0100, Ard Biesheuvel wrote:
> >> On Mon, 1 Dec 2025 at 19:20, Ryan Roberts <ryan.roberts at arm.com> wrote:
> >>> On 28/11/2025 11:01, Ard Biesheuvel wrote:
> >>>> On Thu, 27 Nov 2025 at 12:00, Ryan Roberts <ryan.roberts at arm.com> wrote:
> >>>>> diff --git a/include/linux/randomize_kstack.h b/include/linux/randomize_kstack.h
> >>>>> index 089b1432f7e6..83c7e6710f6d 100644
> >>>>> --- a/include/linux/randomize_kstack.h
> >>>>> +++ b/include/linux/randomize_kstack.h
> >>>>> @@ -6,6 +6,7 @@
> >>>>>  #include <linux/kernel.h>
> >>>>>  #include <linux/jump_label.h>
> >>>>>  #include <linux/percpu-defs.h>
> >>>>> +#include <linux/prandom.h>
> >>>>>
> >>>>>  DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
> >>>>>                          randomize_kstack_offset);
> >>>>> @@ -45,9 +46,13 @@ DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
> >>>>>  #define KSTACK_OFFSET_MAX(x)   ((x) & 0b1111111100)
> >>>>>  #endif
> >>>>>
> >>>>> +static __always_inline u32 get_update_kstack_offset(void)
> >>>>> +{
> >>>>> +       return prandom_u32_state(&current->kstack_rnd_state);
> >>>
> >>> I've got bot warnings because this is being called from noinstr code. I guess
> >>> the best option is to just move add_random_kstack_offset() to after
> >>> instrumentation is enabled for the affected arches.
> >>
> >> Just put instrumentation_begin()/instrumentation_end() around the call
> >> to prandom_u32_state() - that seems to be the common approach for
> >> punching holes into the 'noinstr' validation.
> > 
> > That silences the warning, but isn't necessarily safe, so please DO NOT
> > do that blindly. The instrumentation_{begin,end}() annotations are only
> > supposed to be used when we know by construction that instrumentation is
> > safe.
> > 
> > Generally, if you can move this to after instrumentation is already
> > enabled, that should be safe, and so that'd be the better approach.
> > 
> > Ryan, can you share those warnings (e.g. link to those reports)?
> 
> https://lore.kernel.org/oe-kbuild-all/202511302137.u4iIA2kf-lkp at intel.com/
> https://lore.kernel.org/oe-kbuild-all/202511302317.BGFIlAYX-lkp at intel.com/

Cool, so those are __do_fast_syscall_32() and do_syscall_64(), which I'd
expect (and those are legitimate warnings).

>From a quick scan of v6.18, it looks like arm64, loongarch, powerpc, and
riscv perform all the necessary entry work before calling
add_random_kstack_offset(), and we'll need to change:

* s390's __do_syscall()
* x86's do_syscall_64()
* x86's do_int80_syscall_32()
* x86's __do_fast_syscall_32()

Mark.


From mani at kernel.org  Tue Dec  2 01:53:11 2025
From: mani at kernel.org (Manivannan Sadhasivam)
Date: Tue, 2 Dec 2025 15:23:11 +0530
Subject: linux-next: Tree for Nov 28
 (drivers/pci/controller/dwc/pcie-nxp-s32g.o)
In-Reply-To: <CAKfTPtA-wir5GzU7aTywe7SZG18Aj8Z9g1wjV-Y8vKoyKF1Mkg@mail.gmail.com>
References: <20251128162928.36eec2d6@canb.auug.org.au>
 <63e1daf7-f9a3-463e-8a1b-e9b72581c7af@infradead.org>
 <ykmo5qv46mo7f3srblxoi2fvghz722fj7kpm77ozpflaqup6rk@ttvhbw445pgu>
 <CAKfTPtA-wir5GzU7aTywe7SZG18Aj8Z9g1wjV-Y8vKoyKF1Mkg@mail.gmail.com>
Message-ID: <vb6pcyaue6pqpx626ytfr2aif4luypopywqoazjsvy4crh6zic@gfv75ar7musy>

On Tue, Dec 02, 2025 at 09:54:24AM +0100, Vincent Guittot wrote:
> On Tue, 2 Dec 2025 at 05:24, Manivannan Sadhasivam <mani at kernel.org> wrote:
> >
> > + Vincent
> 
> Thanks for looping me in.
> >
> > On Sat, Nov 29, 2025 at 07:00:04PM -0800, Randy Dunlap wrote:
> > >
> > >
> > > On 11/27/25 9:29 PM, Stephen Rothwell wrote:
> > > > Hi all,
> > > >
> > > > Changes since 20251127:
> > > >
> > >
> > > on i386 (allmodconfig):
> > >
> > > WARNING: modpost: vmlinux: section mismatch in reference: s32g_init_pcie_controller+0x2b (section: .text) -> memblock_start_of_DRAM (section: .init.text)
> 
> Are there details to reproduce the warning ? I don't have such warning
> when compiling allmodconfig locally
> 
> s32 pcie can only be built in but I may have to use
> builtin_platform_driver_probe() instead of builtin_platform_driver()
> 

The is due to calling a function belonging to the __init section from non-init
function. Ideally, functions prefixed with __init like memblock_start_of_DRAM()
should be called from the module init functions.

One way to fix would be to call memblock_start_of_DRAM() in probe(), and
annotate probe() with __init. Since there is no remove, you could use
builtin_platform_driver_probe().

This also makes me wonder if we really should be using memblock_start_of_DRAM()
in the driver. I know that this was suggested to you during reviews, but I would
prefer to avoid it, especially due to this being the __init function.

- Mani

-- 
????????? ????????


From vulab at iscas.ac.cn  Tue Dec  2 01:52:52 2025
From: vulab at iscas.ac.cn (Haotian Zhang)
Date: Tue,  2 Dec 2025 17:52:52 +0800
Subject: [PATCH] staging: vc04_services: vchiq_bus: Check return value of of_dma_configure()
Message-ID: <20251202095253.1640-1-vulab@iscas.ac.cn>

vchiq_device_register() ignores the return value of of_dma_configure(),
which may return -EPROBE_DEFER when the IOMMU is not ready or other error
codes. This allows device registration to proceed with incomplete DMA
configuration.

Check of_dma_configure() return value and fail device registration
on error.

Fixes: 027e5703de6b ("staging: vc04_services: vchiq_arm: Add new bus type and device type")
Signed-off-by: Haotian Zhang <vulab at iscas.ac.cn>
---
 .../staging/vc04_services/interface/vchiq_arm/vchiq_bus.c  | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.c
index 41ece91ab88a..8d920a7a3777 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.c
@@ -80,7 +80,12 @@ vchiq_device_register(struct device *parent, const char *name)
 
 	device->drv_mgmt = dev_get_drvdata(parent);
 
-	of_dma_configure(&device->dev, parent->of_node, true);
+	ret = of_dma_configure(&device->dev, parent->of_node, true);
+	if (ret) {
+		dev_err(parent, "DMA configuration failed for %s: %d\n", name, ret);
+		kfree(device);
+		return NULL;
+	}
 
 	ret = device_register(&device->dev);
 	if (ret) {
-- 
2.50.1.windows.1



From alchark at gmail.com  Tue Dec  2 01:54:31 2025
From: alchark at gmail.com (Alexey Charkov)
Date: Tue, 02 Dec 2025 13:54:31 +0400
Subject: [PATCH v2] arm64: dts: rockchip: Add overlay for the PCIe slot on
 RK3576 EVB1
Message-ID: <20251202-evb1-pcie1-v2-1-810693b1b72f@gmail.com>

Rockchip RK3576 EVB1 has an onboard PCIe slot (PCIe 2.1, x4 mechanically,
x1 electrically), but it shares pins and PHY with the only USB3 Type-A
port.

There is a physical switch next to the slot to transfer respective pins
connection from the USB3 port to the PCIe slot, but apart from flipping
the switch one must also disable the USB3 host controller to prevent it
from claiming the PHY before the PCIe slot can become usable.

Add an overlay to disable the USB3 host port and instead enable the
PCIe slot, along with its pin configs. The physical switch must still be
flipped to the "ON - PCIe1" position for this to work.

Signed-off-by: Alexey Charkov <alchark at gmail.com>
---
Changes in v2:
- Added the standalone .dtbo Makefile target forgotten in v1
- Link to v1: https://lore.kernel.org/r/20251201-evb1-pcie1-v1-1-c62bba5c1167 at gmail.com
---
 arch/arm64/boot/dts/rockchip/Makefile              |  5 ++++
 .../boot/dts/rockchip/rk3576-evb1-v10-pcie1.dtso   | 31 ++++++++++++++++++++++
 2 files changed, 36 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index ad684e3831bc..ecd2dd365e97 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -153,6 +153,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-wolfvision-pf5-io-expander.dtbo
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-armsom-sige5.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-armsom-sige5-v1.2-wifibt.dtbo
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-evb1-v10.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-evb1-v10-pcie1.dtbo
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-luckfox-omni3576.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-nanopi-m5.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-roc-pc.dtb
@@ -252,6 +253,10 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-armsom-sige5-v1.2-wifibt.dtb
 rk3576-armsom-sige5-v1.2-wifibt-dtbs := rk3576-armsom-sige5.dtb \
 	rk3576-armsom-sige5-v1.2-wifibt.dtbo
 
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-evb1-v10-pcie1.dtb
+rk3576-evb1-v10-pcie1-dtbs := rk3576-evb1-v10.dtb \
+	rk3576-evb1-v10-pcie1.dtbo
+
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-edgeble-neu6a-wifi.dtb
 rk3588-edgeble-neu6a-wifi-dtbs := rk3588-edgeble-neu6a-io.dtb \
 	rk3588-edgeble-neu6a-wifi.dtbo
diff --git a/arch/arm64/boot/dts/rockchip/rk3576-evb1-v10-pcie1.dtso b/arch/arm64/boot/dts/rockchip/rk3576-evb1-v10-pcie1.dtso
new file mode 100644
index 000000000000..dccf4a5debdb
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3576-evb1-v10-pcie1.dtso
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * DT-overlay to enable the onboard PCIe x1 slot, which shares pins and the PHY
+ * with the USB3 host port.
+ * To use the PCIe slot, apply this overlay and flip the Dial_Switch_1 right
+ * next to the PCIe slot to low state (labeled "ON - PCIe1"). USB3 host port
+ * will be unusable (not even in 2.0 mode)
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/pinctrl/rockchip.h>
+
+&pcie1 {
+	pinctrl-0 = <&pcie1m0_pins &pcie1_rst>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&pinctrl {
+	pcie1 {
+		pcie1_rst: pcie1-rst {
+			rockchip,pins = <4 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+};
+
+&usb_drd1_dwc3 {
+	status = "disabled";
+};

---
base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
change-id: 20251128-evb1-pcie1-ade389a4d590

Best regards,
-- 
Alexey Charkov <alchark at gmail.com>



From mark.rutland at arm.com  Tue Dec  2 02:02:20 2025
From: mark.rutland at arm.com (Mark Rutland)
Date: Tue, 2 Dec 2025 10:02:20 +0000
Subject: [RFC PATCH v1 2/2] randomize_kstack: Unify random source across
 arches
In-Reply-To: <CAMj1kXG=HDVso1xc6TGgSrBpV3Sq2YQLdPKg2dw5z9qdrbdWBw@mail.gmail.com>
References: <20251127105958.2427758-1-ryan.roberts@arm.com>
 <20251127105958.2427758-3-ryan.roberts@arm.com>
 <CAMj1kXFY1RXk8T4f46bkm_sr0nJfBoO+ii68JK4+CsRiDwKdCg@mail.gmail.com>
 <9097505d-b18b-4f85-a02c-7f2865ad8bca@arm.com>
 <CAMj1kXHX1W2Kz5NJehtzDhOCKWEd6y1sp8+ViOMHGsq9e8=7Pw@mail.gmail.com>
 <aS6ylpLIyDZOvBDB@J2N7QTR9R3>
 <CAMj1kXG=HDVso1xc6TGgSrBpV3Sq2YQLdPKg2dw5z9qdrbdWBw@mail.gmail.com>
Message-ID: <aS65LFUfdgRPKv1l@J2N7QTR9R3>

On Tue, Dec 02, 2025 at 10:47:04AM +0100, Ard Biesheuvel wrote:
> On Tue, 2 Dec 2025 at 10:35, Mark Rutland <mark.rutland at arm.com> wrote:
> > On Tue, Dec 02, 2025 at 10:15:22AM +0100, Ard Biesheuvel wrote:
> > > On Mon, 1 Dec 2025 at 19:20, Ryan Roberts <ryan.roberts at arm.com> wrote:
> > > > I've got bot warnings because this is being called from noinstr code. I guess
> > > > the best option is to just move add_random_kstack_offset() to after
> > > > instrumentation is enabled for the affected arches.
> > >
> > > Just put instrumentation_begin()/instrumentation_end() around the call
> > > to prandom_u32_state() - that seems to be the common approach for
> > > punching holes into the 'noinstr' validation.
> >
> > That silences the warning, but isn't necessarily safe, so please DO NOT
> > do that blindly.
> 
> Oops - sorry about that.

No problem! I just wanted to make sure we didn't start to gain broken
usage that'd need an audit and cleanup.

[...]

> Given that prandom_u32_state() does a fairly straight-forward mangle
> of 4 32-bit words, might it be better to make that __always_inline
> itself?

Possibly! I don't know whether it's better to have prandom_u32_state()
inline or out-of-line.

So long as prandom_u32_state() doesn't call out to instrumented code,
making it an __always_inline function will be safe.

Mark.


From vincent.guittot at linaro.org  Tue Dec  2 02:03:07 2025
From: vincent.guittot at linaro.org (Vincent Guittot)
Date: Tue, 2 Dec 2025 11:03:07 +0100
Subject: linux-next: Tree for Nov 28 (drivers/pci/controller/dwc/pcie-nxp-s32g.o)
In-Reply-To: <vb6pcyaue6pqpx626ytfr2aif4luypopywqoazjsvy4crh6zic@gfv75ar7musy>
References: <20251128162928.36eec2d6@canb.auug.org.au> <63e1daf7-f9a3-463e-8a1b-e9b72581c7af@infradead.org>
 <ykmo5qv46mo7f3srblxoi2fvghz722fj7kpm77ozpflaqup6rk@ttvhbw445pgu>
 <CAKfTPtA-wir5GzU7aTywe7SZG18Aj8Z9g1wjV-Y8vKoyKF1Mkg@mail.gmail.com> <vb6pcyaue6pqpx626ytfr2aif4luypopywqoazjsvy4crh6zic@gfv75ar7musy>
Message-ID: <CAKfTPtCKmj_dHGU-2WPsEevf7CR-isRiyM0+oftCrMy5MswE4A@mail.gmail.com>

On Tue, 2 Dec 2025 at 10:53, Manivannan Sadhasivam <mani at kernel.org> wrote:
>
> On Tue, Dec 02, 2025 at 09:54:24AM +0100, Vincent Guittot wrote:
> > On Tue, 2 Dec 2025 at 05:24, Manivannan Sadhasivam <mani at kernel.org> wrote:
> > >
> > > + Vincent
> >
> > Thanks for looping me in.
> > >
> > > On Sat, Nov 29, 2025 at 07:00:04PM -0800, Randy Dunlap wrote:
> > > >
> > > >
> > > > On 11/27/25 9:29 PM, Stephen Rothwell wrote:
> > > > > Hi all,
> > > > >
> > > > > Changes since 20251127:
> > > > >
> > > >
> > > > on i386 (allmodconfig):
> > > >
> > > > WARNING: modpost: vmlinux: section mismatch in reference: s32g_init_pcie_controller+0x2b (section: .text) -> memblock_start_of_DRAM (section: .init.text)
> >
> > Are there details to reproduce the warning ? I don't have such warning
> > when compiling allmodconfig locally
> >
> > s32 pcie can only be built in but I may have to use
> > builtin_platform_driver_probe() instead of builtin_platform_driver()
> >
>
> The is due to calling a function belonging to the __init section from non-init
> function. Ideally, functions prefixed with __init like memblock_start_of_DRAM()
> should be called from the module init functions.
>
> One way to fix would be to call memblock_start_of_DRAM() in probe(), and
> annotate probe() with __init. Since there is no remove, you could use
> builtin_platform_driver_probe().
>
> This also makes me wonder if we really should be using memblock_start_of_DRAM()
> in the driver. I know that this was suggested to you during reviews, but I would
> prefer to avoid it, especially due to this being the __init function.

yeah, I suppose I can directly define the value in the driver has
there is only one memory config for now anyway

/* Boundary between peripheral space and physical memory space */
#define S32G_MEMORY_BOUNDARY_ADDR 0x80000000

>
> - Mani
>
> --
> ????????? ????????


From lkp at intel.com  Tue Dec  2 02:06:03 2025
From: lkp at intel.com (kernel test robot)
Date: Tue, 2 Dec 2025 18:06:03 +0800
Subject: [PATCH v6 2/3] drm/bridge: imx: Add i.MX93 parallel display
 format configuration support
In-Reply-To: <20251201-v6-18-topic-imx93-parallel-display-v6-2-7b056e1e5b1e@pengutronix.de>
References: <20251201-v6-18-topic-imx93-parallel-display-v6-2-7b056e1e5b1e@pengutronix.de>
Message-ID: <202512021733.cIbkorvY-lkp@intel.com>

Hi Marco,

kernel test robot noticed the following build errors:

[auto build test ERROR on 3a8660878839faadb4f1a6dd72c3179c1df56787]

url:    https://github.com/intel-lab-lkp/linux/commits/Marco-Felsch/dt-bindings-soc-imx93-media-blk-ctrl-Add-PDFC-subnode-to-schema-and-example/20251202-011707
base:   3a8660878839faadb4f1a6dd72c3179c1df56787
patch link:    https://lore.kernel.org/r/20251201-v6-18-topic-imx93-parallel-display-v6-2-7b056e1e5b1e%40pengutronix.de
patch subject: [PATCH v6 2/3] drm/bridge: imx: Add i.MX93 parallel display format configuration support
config: hexagon-allmodconfig (https://download.01.org/0day-ci/archive/20251202/202512021733.cIbkorvY-lkp at intel.com/config)
compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251202/202512021733.cIbkorvY-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512021733.cIbkorvY-lkp at intel.com/

All errors (new ones prefixed by >>):

>> drivers/gpu/drm/bridge/imx/imx93-pdfc.c:55:9: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
      55 |                 val = FORMAT_RGB888_TO_RGB888;
         |                       ^
   drivers/gpu/drm/bridge/imx/imx93-pdfc.c:21:34: note: expanded from macro 'FORMAT_RGB888_TO_RGB888'
      21 | #define FORMAT_RGB888_TO_RGB888         FIELD_PREP(PARALLEL_DISP_FORMAT, 0)
         |                                         ^
   1 error generated.


vim +/FIELD_PREP +55 drivers/gpu/drm/bridge/imx/imx93-pdfc.c

    42	
    43	static void imx93_pdfc_bridge_atomic_enable(struct drm_bridge *bridge,
    44						    struct drm_atomic_state *state)
    45	{
    46		struct imx93_pdfc *pdfc = bridge->driver_private;
    47		const struct drm_bridge_state *bridge_state;
    48		unsigned int mask = PARALLEL_DISP_FORMAT;
    49		unsigned int val;
    50	
    51		bridge_state = drm_atomic_get_new_bridge_state(state, bridge);
    52	
    53		switch (bridge_state->output_bus_cfg.format) {
    54		case MEDIA_BUS_FMT_RGB888_1X24:
  > 55			val = FORMAT_RGB888_TO_RGB888;
    56			if (pdfc->phy_bus_width == 18) {
    57				/*
    58				 * Can be valid if physical bus limitation exist,
    59				 * therefore use dev_dbg().
    60				 */
    61				dev_dbg(pdfc->dev, "Truncate two LSBs from each color\n");
    62				val = FORMAT_RGB888_TO_RGB666;
    63			}
    64			break;
    65		case MEDIA_BUS_FMT_RGB666_1X18:
    66			val = FORMAT_RGB888_TO_RGB666;
    67			break;
    68		case MEDIA_BUS_FMT_RGB565_1X16:
    69			val = FORMAT_RGB565_TO_RGB565;
    70			break;
    71		}
    72	
    73		regmap_update_bits(pdfc->regmap, pdfc->disp_mux_reg_off, mask, val);
    74	}
    75	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From linux at armlinux.org.uk  Tue Dec  2 02:07:21 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Tue, 2 Dec 2025 10:07:21 +0000
Subject: Proposal: Officially allow "incomplete" trees as a base
In-Reply-To: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
References: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
Message-ID: <aS66WcLPm6e5rdyk@shell.armlinux.org.uk>

On Tue, Nov 18, 2025 at 02:43:20PM -0800, Doug Anderson wrote:
> This is a continuation of the discussion that started in reply to my
> patch adding basic device trees for Pixel 10 phones [1].
> 
> 
> Problem statement:
> ------------------
> 
> We would like an officially accepted scheme that lets us more
> efficiently ship compiled device trees for a handful of related
> products by breaking the device trees up into a common "base" device
> tree and then applying "overlay" device trees atop the base to make a
> full and complete device tree.
> 
> To make it more concrete, we'd like to build a "base" device tree that
> describes a SoC and then have the overlays be enough to make a full
> description of a board. In theory, one could also imagine wanting to
> expand this to 3 or more levels (perhaps SoC, baseboard, derived
> boards), though this is not planned at this time.
> 
> The primary reason for wanting to break device trees like this is
> efficiency of the shipped binary device trees. A large portion of a
> final device tree just describes the SoC. We save space in the final
> compiled device trees if they don't need to contain as much duplicated
> information.

Having worked on the SolidRun i.MX6 platforms, I agree with this.
Within these platforms there are:

SoC	SOM		Platform
imx6dl	pre-v1.5	cubox
imx6q	v1.5		hummingboard
	v1.5 + emmc	hummingboard2

On top of these, I have specific "user" extensions for hardware that
I've connected - e.g.
- the NoIR RPi camera needs DT modification.
- for monitoring a mechanical church clock, a "gps" variant that
  allowed PPS to be used with a GPIO pin, and a "capture" variant
  that configured the hardware to allow precise event stamping.
- 1-wire, for ds18b20 temperature sensors.

Without the user extensions, this adds up to 18 DTB files:
arch/arm/boot/dts/nxp/imx/imx6dl-cubox-i-emmc-som-v15.dts
arch/arm/boot/dts/nxp/imx/imx6dl-cubox-i-som-v15.dts
arch/arm/boot/dts/nxp/imx/imx6dl-cubox-i.dts
arch/arm/boot/dts/nxp/imx/imx6dl-hummingboard-emmc-som-v15.dts
arch/arm/boot/dts/nxp/imx/imx6dl-hummingboard-som-v15.dts
arch/arm/boot/dts/nxp/imx/imx6dl-hummingboard.dts
arch/arm/boot/dts/nxp/imx/imx6dl-hummingboard2-emmc-som-v15.dts
arch/arm/boot/dts/nxp/imx/imx6dl-hummingboard2-som-v15.dts
arch/arm/boot/dts/nxp/imx/imx6dl-hummingboard2.dts
arch/arm/boot/dts/nxp/imx/imx6q-cubox-i-emmc-som-v15.dts
arch/arm/boot/dts/nxp/imx/imx6q-cubox-i-som-v15.dts
arch/arm/boot/dts/nxp/imx/imx6q-cubox-i.dts
arch/arm/boot/dts/nxp/imx/imx6q-hummingboard-emmc-som-v15.dts
arch/arm/boot/dts/nxp/imx/imx6q-hummingboard-som-v15.dts
arch/arm/boot/dts/nxp/imx/imx6q-hummingboard.dts
arch/arm/boot/dts/nxp/imx/imx6q-hummingboard2-emmc-som-v15.dts
arch/arm/boot/dts/nxp/imx/imx6q-hummingboard2-som-v15.dts
arch/arm/boot/dts/nxp/imx/imx6q-hummingboard2.dts

basically, every combination needs to be enumerated. So, having two SoC
dt files, three for the SOM, and three for the platform that the boot
loader combines would significantly cut this down - to 8.

However, it isn't that simple. For example, when the Hummingboard2 is
used with the iMX6Q SoC, there's a SATA device present in the SoC level
that needs Hummingboard2 specific properties to tune the signal
waveform. However, iMX6DL doesn't have this SATA device in silicon, so
the node doesn't exist in the base SoC DT file. The situation is the
same for Hummingboard, but the tuning parameters, being board specific,
are different.

This means is that there are DT properties that are dependent on the
SoC DT component and the platform DT component which do not fit with
splitting the DT files into their individual "component" levels.

The other issue would be the /model property - for example:

        model = "SolidRun HummingBoard2 Solo/DualLite";
        model = "SolidRun HummingBoard2 Solo/DualLite (1.5som+emmc)";
        model = "SolidRun HummingBoard2 Solo/DualLite (1.5som)";
        model = "SolidRun HummingBoard Solo/DualLite";
        model = "SolidRun HummingBoard2 Dual/Quad";
        model = "SolidRun Cubox-i Solo/DualLite";

as a set of examples. I don't see a clear way to generate these from
a fragmented scheme. There's a similar problem with the board-level
compatible:

        compatible = "solidrun,cubox-i/dl", "fsl,imx6dl";
        compatible = "solidrun,hummingboard2/dl", "fsl,imx6dl";
        compatible = "solidrun,hummingboard/dl", "fsl,imx6dl";
        compatible = "solidrun,hummingboard2/q", "fsl,imx6q";

These don't include the SoM information.

Maybe what would work would be a high-level DT file that contains
paths to the lower levels that need to be combined, along with
properties that need to be merged. E.g.

/ {
	model = "SolidRun HummingBoard2 Dual/Quad";
	compatible = "solidrun,hummingboard2/q", "fsl,imx6q";

	dts-components {
		compatible = "boot/dt";
		
		component at 1 {
			compatible = "dt";
			path = "imx6q.dtbo";
		};

		component at 2 {
			compatible = "dt";
			path = "imx6qdl-sr-som-v1.5.dtbo";
		};

		component at 3 {
			compatible = "dt";
			path = "imx6qdl-hummingboard2.dtbo";
		};

		component at 4 {
			compatible = "dt";
			path = "imx6ql-hummingboard2-emmc.dtbo";
		};
	};

	soc {
		sata at 2200000 {
			.. sata tuning properties ..
		};
	};
};

Or something similar. However, this would mean we would still need the
18 or so top level DT files, but also each component as well, which
will increase the number of files we're having to manage on a target
platform - so I'm wondering whether it's worth it.

I don't think we'll be able to get away from this problem: it's likely
that there will continue to be properties that are specific across
several "levels" of a split DT setup, and apart from something like the
above, I don't really see a way to handle them.

I also don't see a sensible way without something like the above for a
boot loader to know the filenames of each of the components for a
platform - and it would need to be told the order to glue those
components together.

I would have liked to use overlays for these platforms, but ISTR they
either weren't supported at the time, or frowned upon, and even so I
can only see them working for the simplest of cases due to the issue
I mention above.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From mani at kernel.org  Tue Dec  2 02:12:19 2025
From: mani at kernel.org (Manivannan Sadhasivam)
Date: Tue, 2 Dec 2025 15:42:19 +0530
Subject: linux-next: Tree for Nov 28
 (drivers/pci/controller/dwc/pcie-nxp-s32g.o)
In-Reply-To: <CAKfTPtCKmj_dHGU-2WPsEevf7CR-isRiyM0+oftCrMy5MswE4A@mail.gmail.com>
References: <20251128162928.36eec2d6@canb.auug.org.au>
 <63e1daf7-f9a3-463e-8a1b-e9b72581c7af@infradead.org>
 <ykmo5qv46mo7f3srblxoi2fvghz722fj7kpm77ozpflaqup6rk@ttvhbw445pgu>
 <CAKfTPtA-wir5GzU7aTywe7SZG18Aj8Z9g1wjV-Y8vKoyKF1Mkg@mail.gmail.com>
 <vb6pcyaue6pqpx626ytfr2aif4luypopywqoazjsvy4crh6zic@gfv75ar7musy>
 <CAKfTPtCKmj_dHGU-2WPsEevf7CR-isRiyM0+oftCrMy5MswE4A@mail.gmail.com>
Message-ID: <6ulzkdgd6j35ptu5mesgtgh2xa6fwalcmkgcxr2fdjwwfvzhrf@4dtcadsl2mvm>

On Tue, Dec 02, 2025 at 11:03:07AM +0100, Vincent Guittot wrote:
> On Tue, 2 Dec 2025 at 10:53, Manivannan Sadhasivam <mani at kernel.org> wrote:
> >
> > On Tue, Dec 02, 2025 at 09:54:24AM +0100, Vincent Guittot wrote:
> > > On Tue, 2 Dec 2025 at 05:24, Manivannan Sadhasivam <mani at kernel.org> wrote:
> > > >
> > > > + Vincent
> > >
> > > Thanks for looping me in.
> > > >
> > > > On Sat, Nov 29, 2025 at 07:00:04PM -0800, Randy Dunlap wrote:
> > > > >
> > > > >
> > > > > On 11/27/25 9:29 PM, Stephen Rothwell wrote:
> > > > > > Hi all,
> > > > > >
> > > > > > Changes since 20251127:
> > > > > >
> > > > >
> > > > > on i386 (allmodconfig):
> > > > >
> > > > > WARNING: modpost: vmlinux: section mismatch in reference: s32g_init_pcie_controller+0x2b (section: .text) -> memblock_start_of_DRAM (section: .init.text)
> > >
> > > Are there details to reproduce the warning ? I don't have such warning
> > > when compiling allmodconfig locally
> > >
> > > s32 pcie can only be built in but I may have to use
> > > builtin_platform_driver_probe() instead of builtin_platform_driver()
> > >
> >
> > The is due to calling a function belonging to the __init section from non-init
> > function. Ideally, functions prefixed with __init like memblock_start_of_DRAM()
> > should be called from the module init functions.
> >
> > One way to fix would be to call memblock_start_of_DRAM() in probe(), and
> > annotate probe() with __init. Since there is no remove, you could use
> > builtin_platform_driver_probe().
> >
> > This also makes me wonder if we really should be using memblock_start_of_DRAM()
> > in the driver. I know that this was suggested to you during reviews, but I would
> > prefer to avoid it, especially due to this being the __init function.
> 
> yeah, I suppose I can directly define the value in the driver has
> there is only one memory config for now anyway
> 
> /* Boundary between peripheral space and physical memory space */
> #define S32G_MEMORY_BOUNDARY_ADDR 0x80000000
> 

Ok. I fixed it up myself with below diff:

diff --git a/drivers/pci/controller/dwc/pcie-nxp-s32g.c b/drivers/pci/controller/dwc/pcie-nxp-s32g.c
index eacf0229762c..70b1dc404bbe 100644
--- a/drivers/pci/controller/dwc/pcie-nxp-s32g.c
+++ b/drivers/pci/controller/dwc/pcie-nxp-s32g.c
@@ -7,7 +7,6 @@
 
 #include <linux/interrupt.h>
 #include <linux/io.h>
-#include <linux/memblock.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/of_address.h>
@@ -35,6 +34,9 @@
 #define PCIE_S32G_PE0_INT_STS                  0xE8
 #define HP_INT_STS                             BIT(6)
 
+/* Boundary between peripheral space and physical memory space */
+#define S32G_MEMORY_BOUNDARY_ADDR              0x80000000
+
 struct s32g_pcie_port {
        struct list_head list;
        struct phy *phy;
@@ -99,10 +101,10 @@ static struct dw_pcie_ops s32g_pcie_ops = {
 };
 
 /* Configure the AMBA AXI Coherency Extensions (ACE) interface */
-static void s32g_pcie_reset_mstr_ace(struct dw_pcie *pci, u64 ddr_base_addr)
+static void s32g_pcie_reset_mstr_ace(struct dw_pcie *pci)
 {
-       u32 ddr_base_low = lower_32_bits(ddr_base_addr);
-       u32 ddr_base_high = upper_32_bits(ddr_base_addr);
+       u32 ddr_base_low = lower_32_bits(S32G_MEMORY_BOUNDARY_ADDR);
+       u32 ddr_base_high = upper_32_bits(S32G_MEMORY_BOUNDARY_ADDR);
 
        dw_pcie_dbi_ro_wr_en(pci);
        dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_3_OFF, 0x0);
@@ -149,7 +151,7 @@ static int s32g_init_pcie_controller(struct dw_pcie_rp *pp)
         * Make sure we use the coherency defaults (just in case the settings
         * have been changed from their reset values)
         */
-       s32g_pcie_reset_mstr_ace(pci, memblock_start_of_DRAM());
+       s32g_pcie_reset_mstr_ace(pci);
 
        dw_pcie_dbi_ro_wr_en(pci);

- Mani

-- 
????????? ????????


From linux at armlinux.org.uk  Tue Dec  2 02:13:55 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Tue, 2 Dec 2025 10:13:55 +0000
Subject: Proposal: Officially allow "incomplete" trees as a base
In-Reply-To: <CAD=FV=WBbqSDghm+o2ZVa4-AbL4aggFQO0xdtmZNrYOQRjF5Vw@mail.gmail.com>
References: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
 <CAD=FV=UbejKdD2q2Z3RuYH0Ooc6XRb0oynchDsqnq7GzM6ah0w@mail.gmail.com>
 <aS3eXBDtaoNLfxZy@shell.armlinux.org.uk>
 <CAD=FV=WBbqSDghm+o2ZVa4-AbL4aggFQO0xdtmZNrYOQRjF5Vw@mail.gmail.com>
Message-ID: <aS674_yXxYwJzHX9@shell.armlinux.org.uk>

On Mon, Dec 01, 2025 at 12:58:57PM -0800, Doug Anderson wrote:
> Hi,
> 
> On Mon, Dec 1, 2025 at 10:28?AM Russell King (Oracle)
> <linux at armlinux.org.uk> wrote:
> >
> > On Mon, Dec 01, 2025 at 09:42:40AM -0800, Doug Anderson wrote:
> > > Hi,
> > >
> > > On Tue, Nov 18, 2025 at 2:43?PM Doug Anderson <dianders at chromium.org> wrote:
> > > >
> > > > This is a continuation of the discussion that started in reply to my
> > > > patch adding basic device trees for Pixel 10 phones [1].
> > > >
> > > >
> > > > Problem statement:
> > > > ------------------
> > > >
> > > > We would like an officially accepted scheme that lets us more
> > > > efficiently ship compiled device trees for a handful of related
> > > > products by breaking the device trees up into a common "base" device
> > > > tree and then applying "overlay" device trees atop the base to make a
> > > > full and complete device tree.
> > > >
> > > > To make it more concrete, we'd like to build a "base" device tree that
> > > > describes a SoC and then have the overlays be enough to make a full
> > > > description of a board. In theory, one could also imagine wanting to
> > > > expand this to 3 or more levels (perhaps SoC, baseboard, derived
> > > > boards), though this is not planned at this time.
> > > >
> > > > The primary reason for wanting to break device trees like this is
> > > > efficiency of the shipped binary device trees. A large portion of a
> > > > final device tree just describes the SoC. We save space in the final
> > > > compiled device trees if they don't need to contain as much duplicated
> > > > information.
> > > >
> > > > A secondary reason for wanting to break device trees like this is to
> > > > more nicely handle when a board has a socketed SoC that can be
> > > > replaced with a finite (and small) number of different SoCs (usually
> > > > revisions of the same SoC). Even if this secondary reason is
> > > > considered invalid or too difficult, the primary reason still
> > > > describes a compelling need.
> > > >
> > > > In order to make this proposal work, it's expected that a bootloader
> > > > will understand the scheme and will know how to combine the overlay
> > > > atop the base before passing a complete device tree to the main OS.
> > >
> > > It's been roughly two weeks since I sent out this proposal. Do DT
> > > folks have any comments? Are the goals I have stated understood? Do
> > > people agree that these goals are reasonable? Is there any question
> > > that there is a need to solve these problems not just for Google, but
> > > for the community as a whole? I'm happy to reach out to people and
> > > have them reply "yes, I have this problem too" if it would somehow
> > > help. I don't doubt that there are still people at Qualcomm who would
> > > like a solution even if I think Elliot isn't driving it there
> > > anymore...
> > >
> > > How do we make forward progress? Does anyone have any comments on
> > > Julius's reply? At the moment, I think there are some conflicts with
> > > what Julius would like to see (no changes to the rules for how
> > > overlays are applied) and what Rob said previously (we need to find
> > > some way to combine the compatible strings). Did I misunderstand? Can
> > > we find a common ground?
> >
> > My feeling on this (and I don't have much time to consider it tonight)
> > is that this isn't going to get a quick answer.
> >
> > This answer is based on my authorship of various device trees, and is
> > solely my own opinion, and in no way represents any position by my
> > employer.
> >
> > While the DT files are dual-licensed, the license that applies to the
> > copy in the kernel is GPL v2, because the kernel as a whole is GPL v2
> > licensed. The dual-licensing of the DT files is to permit them to be
> > taken from the kernel and used in e.g. boot loaders etc.
> >
> > However, as the license that applies to the kernel copy is GPL v2, and
> > GPL v2 requires distribution in source code form, or an offer valid
> > for two years of the corresponding source code etc (check the GPL v2
> > for the exact terms) it could be inappropriate for the kernel tree
> > to distribute binary DT blobs without their corresponding source.
> >
> > It seems to me that this is a problem for lawyers, and you're probably
> > not going to get a quick answer on it.
> >
> > So, I'd suggest patience, and don't expect this topic to move quickly.
> 
> It seems like perhaps I wasn't clear enough in my description of the
> problem I'm trying to solve.

I didn't have time last night to properly read your proposal - certainly
not to go back to your original post, but from what I did read in your
follow up, it seemed that you were proposing that e.g. the SoC level
should be in binary form.

The confusion came from "build a "base" device tree" which implied to
me taking the e.g. SoC .dtsi and turning that into its binary form.

Sorry for misunderstanding.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From leo.yan at arm.com  Tue Dec  2 02:15:56 2025
From: leo.yan at arm.com (Leo Yan)
Date: Tue, 2 Dec 2025 10:15:56 +0000
Subject: [PATCH 1/7] perf tools: Track all user changed config bits
In-Reply-To: <20251201-james-perf-config-bits-v1-1-22ecbbf8007c@linaro.org>
References: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
 <20251201-james-perf-config-bits-v1-1-22ecbbf8007c@linaro.org>
Message-ID: <20251202101556.GR724103@e132581.arm.com>

On Mon, Dec 01, 2025 at 04:41:04PM +0000, Coresight ML wrote:

[...]

> +#define ADD_CONFIG_CHG(format_type, term_type, new_term)		\
> +{									\
> +	struct parse_events_term *term;					\
> +	u64 bits = 0;							\
> +	int type;							\
> +									\
> +	list_for_each_entry(term, &head_config->terms, list) {		\
> +		if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER) {  \
> +			type = perf_pmu__format_type(pmu, term->config);\
> +			if (type != format_type)			\
> +				continue;				\
> +			bits |= perf_pmu__format_bits(pmu, term->config); \
> +		} else if (term->type_term == term_type) {		\
> +			bits = ~(u64)0;					\
> +		}							\
> +	}								\
> +									\
> +	if (bits)							\
> +		ADD_CONFIG_TERM_VAL(new_term, cfg_chg, bits, false);	\
> +	return 0;							\

Nitpick: "return 0" is not needed here.  Otherwise:

Reviewed-by: Leo Yan <leo.yan at arm.com>


From wenst at chromium.org  Tue Dec  2 02:17:48 2025
From: wenst at chromium.org (Chen-Yu Tsai)
Date: Tue, 2 Dec 2025 18:17:48 +0800
Subject: [PATCH v6 7/8] scripts/make_fit: Support a few more parallel compressors
In-Reply-To: <20251119181333.991099-8-sjg@chromium.org>
References: <20251119181333.991099-1-sjg@chromium.org> <20251119181333.991099-8-sjg@chromium.org>
Message-ID: <CAGXv+5HiV7EE9CNPRT5EbL8AM8n68Ac1r-=esQL5dgaPDKPTWQ@mail.gmail.com>

On Thu, Nov 20, 2025 at 2:14?AM Simon Glass <sjg at chromium.org> wrote:
>
> Add support for pbzip2 and plzip which can compress in parallel. This
> speeds up the ramdisk compression.
>
> Signed-off-by: Simon Glass <sjg at chromium.org>
> ---
>
> (no changes since v1)
>
>  scripts/make_fit.py | 11 ++++++++---
>  1 file changed, 8 insertions(+), 3 deletions(-)
>
> diff --git a/scripts/make_fit.py b/scripts/make_fit.py
> index 9dfef11fc4b3..64038f17a51e 100755
> --- a/scripts/make_fit.py
> +++ b/scripts/make_fit.py
> @@ -57,10 +57,10 @@ import libfdt
>  CompTool = collections.namedtuple('CompTool', 'ext,tools')
>
>  COMP_TOOLS = {
> -    'bzip2': CompTool('.bz2', 'bzip2'),
> +    'bzip2': CompTool('.bz2', 'pbzip2,bzip2'),
>      'gzip': CompTool('.gz', 'pigz,gzip'),
>      'lz4': CompTool('.lz4', 'lz4'),
> -    'lzma': CompTool('.lzma', 'lzma'),
> +    'lzma': CompTool('.lzma', 'plzip,lzma'),
>      'lzo': CompTool('.lzo', 'lzop'),
>      'zstd': CompTool('.zstd', 'zstd'),
>  }
> @@ -220,7 +220,12 @@ def compress_data(inf, compress):
>              done = False
>              for tool in comp.tools.split(','):
>                  try:
> -                    subprocess.call([tool, '-c'], stdin=inf, stdout=outf)
> +                    # Add parallel flags for tools that support them
> +                    cmd = [tool]
> +                    if tool in ('zstd', 'xz'):

There's no 'xz' tool in the list though.

And this hunk isn't mentioned or explained in the commit message.

> +                        cmd.extend(['-T0'])  # Use all available cores

Zero is already the default for 'xz' in 5.8.1.


ChenYu

> +                    cmd.append('-c')
> +                    subprocess.call(cmd, stdin=inf, stdout=outf)
>                      done = True
>                      break
>                  except FileNotFoundError:
> --
> 2.43.0
>


From dan.carpenter at linaro.org  Tue Dec  2 02:18:10 2025
From: dan.carpenter at linaro.org (Dan Carpenter)
Date: Tue, 2 Dec 2025 13:18:10 +0300
Subject: [PATCH] staging: vc04_services: vchiq_bus: Check return value of
 of_dma_configure()
In-Reply-To: <20251202095253.1640-1-vulab@iscas.ac.cn>
References: <20251202095253.1640-1-vulab@iscas.ac.cn>
Message-ID: <aS684lo6j3ldvrPn@stanley.mountain>

You're not working against the latest tree so this doesn't apply.

On Tue, Dec 02, 2025 at 05:52:52PM +0800, Haotian Zhang wrote:
> vchiq_device_register() ignores the return value of of_dma_configure(),
> which may return -EPROBE_DEFER when the IOMMU is not ready or other error
> codes. This allows device registration to proceed with incomplete DMA
> configuration.
> 

If of_dma_configure() returns -EPROBE_DEFER then this will just fail and
that's not really any better than the existing behavior...

regards,
dan carpenter

> Check of_dma_configure() return value and fail device registration
> on error.
> 
> Fixes: 027e5703de6b ("staging: vc04_services: vchiq_arm: Add new bus type and device type")
> Signed-off-by: Haotian Zhang <vulab at iscas.ac.cn>



From vincent.guittot at linaro.org  Tue Dec  2 02:24:53 2025
From: vincent.guittot at linaro.org (Vincent Guittot)
Date: Tue, 2 Dec 2025 11:24:53 +0100
Subject: linux-next: Tree for Nov 28 (drivers/pci/controller/dwc/pcie-nxp-s32g.o)
In-Reply-To: <6ulzkdgd6j35ptu5mesgtgh2xa6fwalcmkgcxr2fdjwwfvzhrf@4dtcadsl2mvm>
References: <20251128162928.36eec2d6@canb.auug.org.au> <63e1daf7-f9a3-463e-8a1b-e9b72581c7af@infradead.org>
 <ykmo5qv46mo7f3srblxoi2fvghz722fj7kpm77ozpflaqup6rk@ttvhbw445pgu>
 <CAKfTPtA-wir5GzU7aTywe7SZG18Aj8Z9g1wjV-Y8vKoyKF1Mkg@mail.gmail.com>
 <vb6pcyaue6pqpx626ytfr2aif4luypopywqoazjsvy4crh6zic@gfv75ar7musy>
 <CAKfTPtCKmj_dHGU-2WPsEevf7CR-isRiyM0+oftCrMy5MswE4A@mail.gmail.com> <6ulzkdgd6j35ptu5mesgtgh2xa6fwalcmkgcxr2fdjwwfvzhrf@4dtcadsl2mvm>
Message-ID: <CAKfTPtABGj6Nys8J8x8Y-PvybORQUoVN0mGLS=qZ__zXqvCWPQ@mail.gmail.com>

On Tue, 2 Dec 2025 at 11:12, Manivannan Sadhasivam <mani at kernel.org> wrote:
>
> On Tue, Dec 02, 2025 at 11:03:07AM +0100, Vincent Guittot wrote:
> > On Tue, 2 Dec 2025 at 10:53, Manivannan Sadhasivam <mani at kernel.org> wrote:
> > >
> > > On Tue, Dec 02, 2025 at 09:54:24AM +0100, Vincent Guittot wrote:
> > > > On Tue, 2 Dec 2025 at 05:24, Manivannan Sadhasivam <mani at kernel.org> wrote:
> > > > >
> > > > > + Vincent
> > > >
> > > > Thanks for looping me in.
> > > > >
> > > > > On Sat, Nov 29, 2025 at 07:00:04PM -0800, Randy Dunlap wrote:
> > > > > >
> > > > > >
> > > > > > On 11/27/25 9:29 PM, Stephen Rothwell wrote:
> > > > > > > Hi all,
> > > > > > >
> > > > > > > Changes since 20251127:
> > > > > > >
> > > > > >
> > > > > > on i386 (allmodconfig):
> > > > > >
> > > > > > WARNING: modpost: vmlinux: section mismatch in reference: s32g_init_pcie_controller+0x2b (section: .text) -> memblock_start_of_DRAM (section: .init.text)
> > > >
> > > > Are there details to reproduce the warning ? I don't have such warning
> > > > when compiling allmodconfig locally
> > > >
> > > > s32 pcie can only be built in but I may have to use
> > > > builtin_platform_driver_probe() instead of builtin_platform_driver()
> > > >
> > >
> > > The is due to calling a function belonging to the __init section from non-init
> > > function. Ideally, functions prefixed with __init like memblock_start_of_DRAM()
> > > should be called from the module init functions.
> > >
> > > One way to fix would be to call memblock_start_of_DRAM() in probe(), and
> > > annotate probe() with __init. Since there is no remove, you could use
> > > builtin_platform_driver_probe().
> > >
> > > This also makes me wonder if we really should be using memblock_start_of_DRAM()
> > > in the driver. I know that this was suggested to you during reviews, but I would
> > > prefer to avoid it, especially due to this being the __init function.
> >
> > yeah, I suppose I can directly define the value in the driver has
> > there is only one memory config for now anyway
> >
> > /* Boundary between peripheral space and physical memory space */
> > #define S32G_MEMORY_BOUNDARY_ADDR 0x80000000
> >
>
> Ok. I fixed it up myself with below diff:

Thanks !

The change looks good to me

>
> diff --git a/drivers/pci/controller/dwc/pcie-nxp-s32g.c b/drivers/pci/controller/dwc/pcie-nxp-s32g.c
> index eacf0229762c..70b1dc404bbe 100644
> --- a/drivers/pci/controller/dwc/pcie-nxp-s32g.c
> +++ b/drivers/pci/controller/dwc/pcie-nxp-s32g.c
> @@ -7,7 +7,6 @@
>
>  #include <linux/interrupt.h>
>  #include <linux/io.h>
> -#include <linux/memblock.h>
>  #include <linux/module.h>
>  #include <linux/of_device.h>
>  #include <linux/of_address.h>
> @@ -35,6 +34,9 @@
>  #define PCIE_S32G_PE0_INT_STS                  0xE8
>  #define HP_INT_STS                             BIT(6)
>
> +/* Boundary between peripheral space and physical memory space */
> +#define S32G_MEMORY_BOUNDARY_ADDR              0x80000000
> +
>  struct s32g_pcie_port {
>         struct list_head list;
>         struct phy *phy;
> @@ -99,10 +101,10 @@ static struct dw_pcie_ops s32g_pcie_ops = {
>  };
>
>  /* Configure the AMBA AXI Coherency Extensions (ACE) interface */
> -static void s32g_pcie_reset_mstr_ace(struct dw_pcie *pci, u64 ddr_base_addr)
> +static void s32g_pcie_reset_mstr_ace(struct dw_pcie *pci)
>  {
> -       u32 ddr_base_low = lower_32_bits(ddr_base_addr);
> -       u32 ddr_base_high = upper_32_bits(ddr_base_addr);
> +       u32 ddr_base_low = lower_32_bits(S32G_MEMORY_BOUNDARY_ADDR);
> +       u32 ddr_base_high = upper_32_bits(S32G_MEMORY_BOUNDARY_ADDR);
>
>         dw_pcie_dbi_ro_wr_en(pci);
>         dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_3_OFF, 0x0);
> @@ -149,7 +151,7 @@ static int s32g_init_pcie_controller(struct dw_pcie_rp *pp)
>          * Make sure we use the coherency defaults (just in case the settings
>          * have been changed from their reset values)
>          */
> -       s32g_pcie_reset_mstr_ace(pci, memblock_start_of_DRAM());
> +       s32g_pcie_reset_mstr_ace(pci);
>
>         dw_pcie_dbi_ro_wr_en(pci);
>
> - Mani
>
> --
> ????????? ????????


From taniya.das at oss.qualcomm.com  Tue Dec  2 02:26:24 2025
From: taniya.das at oss.qualcomm.com (Taniya Das)
Date: Tue, 02 Dec 2025 15:56:24 +0530
Subject: [PATCH 0/3] Add the support for SM8750 Camera clock controller
Message-ID: <20251202-sm8750_camcc-v1-0-b3f7ef6723f1@oss.qualcomm.com>

Support the Camera clock controller for SM8750 Qualcomm SoC.
 - The camera MCLK BIST clock controller, which is required
   for functional MCLKs.
 - The camera CC (clock controller) for managing camera-related
    clocks.
  - Additionally, the Rivian ELU PLL is utilized within the
    SM8750 clock controller, so support for this PLL is also added.

Signed-off-by: Taniya Das <taniya.das at oss.qualcomm.com>
---
Taniya Das (3):
      clk: qcom: clk-alpha-pll: Add support for Rivian ELU PLL
      dt-bindings: clock: qcom: Add camera clock controller for SM8750 SoC
      clk: qcom: camcc: Add camera clock controller driver for SM8750 SoC

 .../bindings/clock/qcom,sm8450-camcc.yaml          |    5 +
 drivers/clk/qcom/Kconfig                           |   10 +
 drivers/clk/qcom/Makefile                          |    1 +
 drivers/clk/qcom/cambistmclkcc-sm8750.c            |  454 ++++
 drivers/clk/qcom/camcc-sm8750.c                    | 2710 ++++++++++++++++++++
 drivers/clk/qcom/clk-alpha-pll.c                   |   14 +
 drivers/clk/qcom/clk-alpha-pll.h                   |    2 +
 .../dt-bindings/clock/qcom,sm8750-cambistmclkcc.h  |   30 +
 include/dt-bindings/clock/qcom,sm8750-camcc.h      |  151 ++
 9 files changed, 3377 insertions(+)
---
base-commit: 92fd6e84175befa1775e5c0ab682938eca27c0b2
change-id: 20251202-sm8750_camcc-259b232d8560

Best regards,
-- 
Taniya Das <taniya.das at oss.qualcomm.com>



From taniya.das at oss.qualcomm.com  Tue Dec  2 02:26:25 2025
From: taniya.das at oss.qualcomm.com (Taniya Das)
Date: Tue, 02 Dec 2025 15:56:25 +0530
Subject: [PATCH 1/3] clk: qcom: clk-alpha-pll: Add support for Rivian ELU
 PLL
In-Reply-To: <20251202-sm8750_camcc-v1-0-b3f7ef6723f1@oss.qualcomm.com>
References: <20251202-sm8750_camcc-v1-0-b3f7ef6723f1@oss.qualcomm.com>
Message-ID: <20251202-sm8750_camcc-v1-1-b3f7ef6723f1@oss.qualcomm.com>

Add clock ops for Rivian ELU PLL, add the register offsets for supporting
the PLL.

Signed-off-by: Taniya Das <taniya.das at oss.qualcomm.com>
---
 drivers/clk/qcom/clk-alpha-pll.c | 14 ++++++++++++++
 drivers/clk/qcom/clk-alpha-pll.h |  2 ++
 2 files changed, 16 insertions(+)

diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c
index 6aeba40358c11e44c5f39d15f149d62149393cd3..8586649d76f8aef119ed51fbf1ca90bc5e3ce510 100644
--- a/drivers/clk/qcom/clk-alpha-pll.c
+++ b/drivers/clk/qcom/clk-alpha-pll.c
@@ -243,6 +243,19 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = {
 		[PLL_OFF_TEST_CTL] = 0x28,
 		[PLL_OFF_TEST_CTL_U] = 0x2c,
 	},
+	[CLK_ALPHA_PLL_TYPE_RIVIAN_ELU] = {
+		[PLL_OFF_OPMODE] = 0x04,
+		[PLL_OFF_STATUS] = 0x0c,
+		[PLL_OFF_L_VAL] = 0x10,
+		[PLL_OFF_USER_CTL] = 0x14,
+		[PLL_OFF_USER_CTL_U] = 0x18,
+		[PLL_OFF_CONFIG_CTL] = 0x1c,
+		[PLL_OFF_CONFIG_CTL_U] = 0x20,
+		[PLL_OFF_CONFIG_CTL_U1] = 0x24,
+		[PLL_OFF_CONFIG_CTL_U2] = 0x28,
+		[PLL_OFF_TEST_CTL] = 0x2c,
+		[PLL_OFF_TEST_CTL_U] = 0x30,
+	},
 	[CLK_ALPHA_PLL_TYPE_DEFAULT_EVO] = {
 		[PLL_OFF_L_VAL] = 0x04,
 		[PLL_OFF_ALPHA_VAL] = 0x08,
@@ -3002,6 +3015,7 @@ void qcom_clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regm
 		clk_taycan_elu_pll_configure(pll, regmap, pll->config);
 		break;
 	case CLK_ALPHA_PLL_TYPE_RIVIAN_EVO:
+	case CLK_ALPHA_PLL_TYPE_RIVIAN_ELU:
 		clk_rivian_evo_pll_configure(pll, regmap, pll->config);
 		break;
 	case CLK_ALPHA_PLL_TYPE_TRION:
diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h
index 0903a05b18ccc68c9f8de5c7405bb197bf8d3d1d..b4492197419a7f326a4f6e6607ccee58ced509db 100644
--- a/drivers/clk/qcom/clk-alpha-pll.h
+++ b/drivers/clk/qcom/clk-alpha-pll.h
@@ -31,6 +31,7 @@ enum {
 	CLK_ALPHA_PLL_TYPE_TAYCAN_ELU,
 	CLK_ALPHA_PLL_TYPE_TAYCAN_EKO_T = CLK_ALPHA_PLL_TYPE_TAYCAN_ELU,
 	CLK_ALPHA_PLL_TYPE_RIVIAN_EVO,
+	CLK_ALPHA_PLL_TYPE_RIVIAN_ELU,
 	CLK_ALPHA_PLL_TYPE_DEFAULT_EVO,
 	CLK_ALPHA_PLL_TYPE_BRAMMO_EVO,
 	CLK_ALPHA_PLL_TYPE_STROMER,
@@ -208,6 +209,7 @@ extern const struct clk_ops clk_alpha_pll_postdiv_lucid_evo_ops;
 extern const struct clk_ops clk_alpha_pll_pongo_elu_ops;
 extern const struct clk_ops clk_alpha_pll_rivian_evo_ops;
 #define clk_alpha_pll_postdiv_rivian_evo_ops clk_alpha_pll_postdiv_fabia_ops
+#define clk_alpha_pll_rivian_elu_ops clk_alpha_pll_rivian_evo_ops
 
 extern const struct clk_ops clk_alpha_pll_regera_ops;
 extern const struct clk_ops clk_alpha_pll_slew_ops;

-- 
2.34.1



From taniya.das at oss.qualcomm.com  Tue Dec  2 02:26:26 2025
From: taniya.das at oss.qualcomm.com (Taniya Das)
Date: Tue, 02 Dec 2025 15:56:26 +0530
Subject: [PATCH 2/3] dt-bindings: clock: qcom: Add camera clock controller
 for SM8750 SoC
In-Reply-To: <20251202-sm8750_camcc-v1-0-b3f7ef6723f1@oss.qualcomm.com>
References: <20251202-sm8750_camcc-v1-0-b3f7ef6723f1@oss.qualcomm.com>
Message-ID: <20251202-sm8750_camcc-v1-2-b3f7ef6723f1@oss.qualcomm.com>

Add device tree bindings for the camera clock controller on
Qualcomm SM8750 platform. The camera clock controller is split between
camcc and cambist. The cambist controls the mclks of the camera clock
controller.

Signed-off-by: Taniya Das <taniya.das at oss.qualcomm.com>
---
 .../bindings/clock/qcom,sm8450-camcc.yaml          |   5 +
 .../dt-bindings/clock/qcom,sm8750-cambistmclkcc.h  |  30 ++++
 include/dt-bindings/clock/qcom,sm8750-camcc.h      | 151 +++++++++++++++++++++
 3 files changed, 186 insertions(+)

diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml
index c1e06f39431e68a3cd2f6c2dba84be2a3c143bb1..8e3baba5270b384eb03a68b4e47785e6c91ec6f7 100644
--- a/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml
@@ -9,6 +9,7 @@ title: Qualcomm Camera Clock & Reset Controller on SM8450
 maintainers:
   - Vladimir Zapolskiy <vladimir.zapolskiy at linaro.org>
   - Jagadeesh Kona <quic_jkona at quicinc.com>
+  - Taniya Das <taniya.das at oss.qualcomm.com>
 
 description: |
   Qualcomm camera clock control module provides the clocks, resets and power
@@ -18,6 +19,8 @@ description: |
     include/dt-bindings/clock/qcom,sm8450-camcc.h
     include/dt-bindings/clock/qcom,sm8550-camcc.h
     include/dt-bindings/clock/qcom,sm8650-camcc.h
+    include/dt-bindings/clock/qcom,sm8750-cambistmclkcc.h
+    include/dt-bindings/clock/qcom,sm8750-camcc.h
 
 properties:
   compatible:
@@ -26,6 +29,8 @@ properties:
       - qcom,sm8475-camcc
       - qcom,sm8550-camcc
       - qcom,sm8650-camcc
+      - qcom,sm8750-cambistmclkcc
+      - qcom,sm8750-camcc
 
   clocks:
     items:
diff --git a/include/dt-bindings/clock/qcom,sm8750-cambistmclkcc.h b/include/dt-bindings/clock/qcom,sm8750-cambistmclkcc.h
new file mode 100644
index 0000000000000000000000000000000000000000..51615bee307fd9e7f81f7e5c1662535093dd8b55
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,sm8750-cambistmclkcc.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef _DT_BINDINGS_CLK_QCOM_CAM_BIST_MCLK_CC_SM8750_H
+#define _DT_BINDINGS_CLK_QCOM_CAM_BIST_MCLK_CC_SM8750_H
+
+/* CAM_BIST_MCLK_CC clocks */
+#define CAM_BIST_MCLK_CC_MCLK0_CLK				0
+#define CAM_BIST_MCLK_CC_MCLK0_CLK_SRC				1
+#define CAM_BIST_MCLK_CC_MCLK1_CLK				2
+#define CAM_BIST_MCLK_CC_MCLK1_CLK_SRC				3
+#define CAM_BIST_MCLK_CC_MCLK2_CLK				4
+#define CAM_BIST_MCLK_CC_MCLK2_CLK_SRC				5
+#define CAM_BIST_MCLK_CC_MCLK3_CLK				6
+#define CAM_BIST_MCLK_CC_MCLK3_CLK_SRC				7
+#define CAM_BIST_MCLK_CC_MCLK4_CLK				8
+#define CAM_BIST_MCLK_CC_MCLK4_CLK_SRC				9
+#define CAM_BIST_MCLK_CC_MCLK5_CLK				10
+#define CAM_BIST_MCLK_CC_MCLK5_CLK_SRC				11
+#define CAM_BIST_MCLK_CC_MCLK6_CLK				12
+#define CAM_BIST_MCLK_CC_MCLK6_CLK_SRC				13
+#define CAM_BIST_MCLK_CC_MCLK7_CLK				14
+#define CAM_BIST_MCLK_CC_MCLK7_CLK_SRC				15
+#define CAM_BIST_MCLK_CC_PLL0					16
+#define CAM_BIST_MCLK_CC_SLEEP_CLK				17
+#define CAM_BIST_MCLK_CC_SLEEP_CLK_SRC				18
+
+#endif
diff --git a/include/dt-bindings/clock/qcom,sm8750-camcc.h b/include/dt-bindings/clock/qcom,sm8750-camcc.h
new file mode 100644
index 0000000000000000000000000000000000000000..dae788247afe896ef812bef716897c6cf80df2bb
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,sm8750-camcc.h
@@ -0,0 +1,151 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef _DT_BINDINGS_CLK_QCOM_CAM_CC_SM8750_H
+#define _DT_BINDINGS_CLK_QCOM_CAM_CC_SM8750_H
+
+/* CAM_CC clocks */
+#define CAM_CC_CAM_TOP_AHB_CLK					0
+#define CAM_CC_CAM_TOP_FAST_AHB_CLK				1
+#define CAM_CC_CAMNOC_DCD_XO_CLK				2
+#define CAM_CC_CAMNOC_NRT_AXI_CLK				3
+#define CAM_CC_CAMNOC_NRT_CRE_CLK				4
+#define CAM_CC_CAMNOC_NRT_IPE_NPS_CLK				5
+#define CAM_CC_CAMNOC_NRT_OFE_ANCHOR_CLK			6
+#define CAM_CC_CAMNOC_NRT_OFE_HDR_CLK				7
+#define CAM_CC_CAMNOC_NRT_OFE_MAIN_CLK				8
+#define CAM_CC_CAMNOC_RT_AXI_CLK				9
+#define CAM_CC_CAMNOC_RT_AXI_CLK_SRC				10
+#define CAM_CC_CAMNOC_RT_IFE_LITE_CLK				11
+#define CAM_CC_CAMNOC_RT_TFE_0_BAYER_CLK			12
+#define CAM_CC_CAMNOC_RT_TFE_0_MAIN_CLK				13
+#define CAM_CC_CAMNOC_RT_TFE_1_BAYER_CLK			14
+#define CAM_CC_CAMNOC_RT_TFE_1_MAIN_CLK				15
+#define CAM_CC_CAMNOC_RT_TFE_2_BAYER_CLK			16
+#define CAM_CC_CAMNOC_RT_TFE_2_MAIN_CLK				17
+#define CAM_CC_CAMNOC_XO_CLK					18
+#define CAM_CC_CCI_0_CLK					19
+#define CAM_CC_CCI_0_CLK_SRC					20
+#define CAM_CC_CCI_1_CLK					21
+#define CAM_CC_CCI_1_CLK_SRC					22
+#define CAM_CC_CCI_2_CLK					23
+#define CAM_CC_CCI_2_CLK_SRC					24
+#define CAM_CC_CORE_AHB_CLK					25
+#define CAM_CC_CPHY_RX_CLK_SRC					26
+#define CAM_CC_CRE_AHB_CLK					27
+#define CAM_CC_CRE_CLK						28
+#define CAM_CC_CRE_CLK_SRC					29
+#define CAM_CC_CSI0PHYTIMER_CLK					30
+#define CAM_CC_CSI0PHYTIMER_CLK_SRC				31
+#define CAM_CC_CSI1PHYTIMER_CLK					32
+#define CAM_CC_CSI1PHYTIMER_CLK_SRC				33
+#define CAM_CC_CSI2PHYTIMER_CLK					34
+#define CAM_CC_CSI2PHYTIMER_CLK_SRC				35
+#define CAM_CC_CSI3PHYTIMER_CLK					36
+#define CAM_CC_CSI3PHYTIMER_CLK_SRC				37
+#define CAM_CC_CSI4PHYTIMER_CLK					38
+#define CAM_CC_CSI4PHYTIMER_CLK_SRC				39
+#define CAM_CC_CSI5PHYTIMER_CLK					40
+#define CAM_CC_CSI5PHYTIMER_CLK_SRC				41
+#define CAM_CC_CSID_CLK						42
+#define CAM_CC_CSID_CLK_SRC					43
+#define CAM_CC_CSID_CSIPHY_RX_CLK				44
+#define CAM_CC_CSIPHY0_CLK					45
+#define CAM_CC_CSIPHY1_CLK					46
+#define CAM_CC_CSIPHY2_CLK					47
+#define CAM_CC_CSIPHY3_CLK					48
+#define CAM_CC_CSIPHY4_CLK					49
+#define CAM_CC_CSIPHY5_CLK					50
+#define CAM_CC_DRV_AHB_CLK					51
+#define CAM_CC_DRV_XO_CLK					52
+#define CAM_CC_FAST_AHB_CLK_SRC					53
+#define CAM_CC_GDSC_CLK						54
+#define CAM_CC_ICP_0_AHB_CLK					55
+#define CAM_CC_ICP_0_CLK					56
+#define CAM_CC_ICP_0_CLK_SRC					57
+#define CAM_CC_ICP_1_AHB_CLK					58
+#define CAM_CC_ICP_1_CLK					59
+#define CAM_CC_ICP_1_CLK_SRC					60
+#define CAM_CC_IFE_LITE_AHB_CLK					61
+#define CAM_CC_IFE_LITE_CLK					62
+#define CAM_CC_IFE_LITE_CLK_SRC					63
+#define CAM_CC_IFE_LITE_CPHY_RX_CLK				64
+#define CAM_CC_IFE_LITE_CSID_CLK				65
+#define CAM_CC_IFE_LITE_CSID_CLK_SRC				66
+#define CAM_CC_IPE_NPS_AHB_CLK					67
+#define CAM_CC_IPE_NPS_CLK					68
+#define CAM_CC_IPE_NPS_CLK_SRC					69
+#define CAM_CC_IPE_NPS_FAST_AHB_CLK				70
+#define CAM_CC_IPE_PPS_CLK					71
+#define CAM_CC_IPE_PPS_FAST_AHB_CLK				72
+#define CAM_CC_JPEG_0_CLK					73
+#define CAM_CC_JPEG_1_CLK					74
+#define CAM_CC_JPEG_CLK_SRC					75
+#define CAM_CC_OFE_AHB_CLK					76
+#define CAM_CC_OFE_ANCHOR_CLK					77
+#define CAM_CC_OFE_ANCHOR_FAST_AHB_CLK				78
+#define CAM_CC_OFE_CLK_SRC					79
+#define CAM_CC_OFE_HDR_CLK					80
+#define CAM_CC_OFE_HDR_FAST_AHB_CLK				81
+#define CAM_CC_OFE_MAIN_CLK					82
+#define CAM_CC_OFE_MAIN_FAST_AHB_CLK				83
+#define CAM_CC_PLL0						84
+#define CAM_CC_PLL0_OUT_EVEN					85
+#define CAM_CC_PLL0_OUT_ODD					86
+#define CAM_CC_PLL1						87
+#define CAM_CC_PLL1_OUT_EVEN					88
+#define CAM_CC_PLL2						89
+#define CAM_CC_PLL2_OUT_EVEN					90
+#define CAM_CC_PLL3						91
+#define CAM_CC_PLL3_OUT_EVEN					92
+#define CAM_CC_PLL4						93
+#define CAM_CC_PLL4_OUT_EVEN					94
+#define CAM_CC_PLL5						95
+#define CAM_CC_PLL5_OUT_EVEN					96
+#define CAM_CC_PLL6						97
+#define CAM_CC_PLL6_OUT_EVEN					98
+#define CAM_CC_PLL6_OUT_ODD					99
+#define CAM_CC_QDSS_DEBUG_CLK					100
+#define CAM_CC_QDSS_DEBUG_CLK_SRC				101
+#define CAM_CC_QDSS_DEBUG_XO_CLK				102
+#define CAM_CC_SLEEP_CLK					103
+#define CAM_CC_SLEEP_CLK_SRC					104
+#define CAM_CC_SLOW_AHB_CLK_SRC					105
+#define CAM_CC_TFE_0_BAYER_CLK					106
+#define CAM_CC_TFE_0_BAYER_FAST_AHB_CLK				107
+#define CAM_CC_TFE_0_CLK_SRC					108
+#define CAM_CC_TFE_0_MAIN_CLK					109
+#define CAM_CC_TFE_0_MAIN_FAST_AHB_CLK				110
+#define CAM_CC_TFE_1_BAYER_CLK					111
+#define CAM_CC_TFE_1_BAYER_FAST_AHB_CLK				112
+#define CAM_CC_TFE_1_CLK_SRC					113
+#define CAM_CC_TFE_1_MAIN_CLK					114
+#define CAM_CC_TFE_1_MAIN_FAST_AHB_CLK				115
+#define CAM_CC_TFE_2_BAYER_CLK					116
+#define CAM_CC_TFE_2_BAYER_FAST_AHB_CLK				117
+#define CAM_CC_TFE_2_CLK_SRC					118
+#define CAM_CC_TFE_2_MAIN_CLK					119
+#define CAM_CC_TFE_2_MAIN_FAST_AHB_CLK				120
+#define CAM_CC_XO_CLK_SRC					121
+
+/* CAM_CC power domains */
+#define CAM_CC_TITAN_TOP_GDSC					0
+#define CAM_CC_IPE_0_GDSC					1
+#define CAM_CC_OFE_GDSC						2
+#define CAM_CC_TFE_0_GDSC					3
+#define CAM_CC_TFE_1_GDSC					4
+#define CAM_CC_TFE_2_GDSC					5
+
+/* CAM_CC resets */
+#define CAM_CC_DRV_BCR						0
+#define CAM_CC_ICP_BCR						1
+#define CAM_CC_IPE_0_BCR					2
+#define CAM_CC_OFE_BCR						3
+#define CAM_CC_QDSS_DEBUG_BCR					4
+#define CAM_CC_TFE_0_BCR					5
+#define CAM_CC_TFE_1_BCR					6
+#define CAM_CC_TFE_2_BCR					7
+
+#endif

-- 
2.34.1



From taniya.das at oss.qualcomm.com  Tue Dec  2 02:26:27 2025
From: taniya.das at oss.qualcomm.com (Taniya Das)
Date: Tue, 02 Dec 2025 15:56:27 +0530
Subject: [PATCH 3/3] clk: qcom: camcc: Add camera clock controller driver
 for SM8750 SoC
In-Reply-To: <20251202-sm8750_camcc-v1-0-b3f7ef6723f1@oss.qualcomm.com>
References: <20251202-sm8750_camcc-v1-0-b3f7ef6723f1@oss.qualcomm.com>
Message-ID: <20251202-sm8750_camcc-v1-3-b3f7ef6723f1@oss.qualcomm.com>

Add support for the Camera Clock Controller (CAMCC) on the SM8750
platform.

The CAMCC block on SM8750 includes both the primary camera clock
controller and the Camera BIST clock controller, which provides the
functional MCLK required for camera operations.

Signed-off-by: Taniya Das <taniya.das at oss.qualcomm.com>
---
 drivers/clk/qcom/Kconfig                |   10 +
 drivers/clk/qcom/Makefile               |    1 +
 drivers/clk/qcom/cambistmclkcc-sm8750.c |  454 ++++++
 drivers/clk/qcom/camcc-sm8750.c         | 2710 +++++++++++++++++++++++++++++++
 4 files changed, 3175 insertions(+)

diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index a284ba040b78ba2f7b7c7ead14023c0ec637f841..6adcc52a3bf54b3e1dcd209d720ed424a1edc9a2 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -1069,6 +1069,16 @@ config SM_CAMCC_8650
 	  Support for the camera clock controller on SM8650 devices.
 	  Say Y if you want to support camera devices and camera functionality.
 
+config SM_CAMCC_8750
+	tristate "SM8750 Camera Clock Controller"
+	depends on ARM64 || COMPILE_TEST
+	select SM_GCC_8750
+	help
+	  Support for the camera clock controller on SM8750 devices.
+	  The camera clock controller has a separate cambist controller which
+	  controls the mclk of the camera clocks.
+	  Say Y if you want to support camera devices and camera functionality.
+
 config SM_DISPCC_4450
 	tristate "SM4450 Display Clock Controller"
 	depends on ARM64 || COMPILE_TEST
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 0ac8a9055a43230d848c6a0c1ac118c03c3e18d2..42b399c15121484bd1621077efb1fd293bbface9 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -136,6 +136,7 @@ obj-$(CONFIG_SM_CAMCC_8250) += camcc-sm8250.o
 obj-$(CONFIG_SM_CAMCC_8450) += camcc-sm8450.o
 obj-$(CONFIG_SM_CAMCC_8550) += camcc-sm8550.o
 obj-$(CONFIG_SM_CAMCC_8650) += camcc-sm8650.o
+obj-$(CONFIG_SM_CAMCC_8750) += cambistmclkcc-sm8750.o camcc-sm8750.o
 obj-$(CONFIG_SM_CAMCC_MILOS) += camcc-milos.o
 obj-$(CONFIG_SM_DISPCC_4450) += dispcc-sm4450.o
 obj-$(CONFIG_SM_DISPCC_6115) += dispcc-sm6115.o
diff --git a/drivers/clk/qcom/cambistmclkcc-sm8750.c b/drivers/clk/qcom/cambistmclkcc-sm8750.c
new file mode 100644
index 0000000000000000000000000000000000000000..952581f86db5b4aa517d931c794be6ff3b8b11e1
--- /dev/null
+++ b/drivers/clk/qcom/cambistmclkcc-sm8750.c
@@ -0,0 +1,454 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,sm8750-cambistmclkcc.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "common.h"
+#include "reset.h"
+
+enum {
+	DT_IFACE,
+	DT_BI_TCXO,
+	DT_BI_TCXO_AO,
+	DT_SLEEP_CLK,
+};
+
+enum {
+	P_BI_TCXO,
+	P_CAM_BIST_MCLK_CC_PLL0_OUT_EVEN,
+	P_CAM_BIST_MCLK_CC_PLL0_OUT_MAIN,
+	P_SLEEP_CLK,
+};
+
+static const struct pll_vco rivian_elu_vco[] = {
+	{ 833000000, 1125000000, 0 },
+	{ 777000000, 1062000000, 1 },
+};
+
+/* 960.0 MHz Configuration */
+static const struct alpha_pll_config cam_bist_mclk_cc_pll0_config = {
+	.l = 0x32,
+	.alpha = 0x0,
+	.config_ctl_val = 0x12000000,
+	.config_ctl_hi_val = 0x00890263,
+	.config_ctl_hi1_val = 0x1af04237,
+	.config_ctl_hi2_val = 0x00000000,
+};
+
+static struct clk_alpha_pll cam_bist_mclk_cc_pll0 = {
+	.offset = 0x0,
+	.config = &cam_bist_mclk_cc_pll0_config,
+	.vco_table = rivian_elu_vco,
+	.num_vco = ARRAY_SIZE(rivian_elu_vco),
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_RIVIAN_ELU],
+	.clkr = {
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_bist_mclk_cc_pll0",
+			.parent_data = &(const struct clk_parent_data) {
+				.index = DT_BI_TCXO,
+			},
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_rivian_elu_ops,
+		},
+	},
+};
+
+static const struct parent_map cam_bist_mclk_cc_parent_map_0[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_CAM_BIST_MCLK_CC_PLL0_OUT_EVEN, 3 },
+	{ P_CAM_BIST_MCLK_CC_PLL0_OUT_MAIN, 5 },
+};
+
+static const struct clk_parent_data cam_bist_mclk_cc_parent_data_0[] = {
+	{ .index = DT_BI_TCXO },
+	{ .hw = &cam_bist_mclk_cc_pll0.clkr.hw },
+	{ .hw = &cam_bist_mclk_cc_pll0.clkr.hw },
+};
+
+static const struct parent_map cam_bist_mclk_cc_parent_map_1[] = {
+	{ P_SLEEP_CLK, 0 },
+};
+
+static const struct clk_parent_data cam_bist_mclk_cc_parent_data_1[] = {
+	{ .index = DT_SLEEP_CLK },
+};
+
+static const struct freq_tbl ftbl_cam_bist_mclk_cc_mclk0_clk_src[] = {
+	F(12000000, P_CAM_BIST_MCLK_CC_PLL0_OUT_EVEN, 10, 1, 8),
+	F(19200000, P_BI_TCXO, 1, 0, 0),
+	F(24000000, P_CAM_BIST_MCLK_CC_PLL0_OUT_EVEN, 10, 1, 4),
+	F(68571429, P_CAM_BIST_MCLK_CC_PLL0_OUT_MAIN, 14, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 cam_bist_mclk_cc_mclk0_clk_src = {
+	.cmd_rcgr = 0x4000,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = cam_bist_mclk_cc_parent_map_0,
+	.freq_tbl = ftbl_cam_bist_mclk_cc_mclk0_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_bist_mclk_cc_mclk0_clk_src",
+		.parent_data = cam_bist_mclk_cc_parent_data_0,
+		.num_parents = ARRAY_SIZE(cam_bist_mclk_cc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 cam_bist_mclk_cc_mclk1_clk_src = {
+	.cmd_rcgr = 0x401c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = cam_bist_mclk_cc_parent_map_0,
+	.freq_tbl = ftbl_cam_bist_mclk_cc_mclk0_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_bist_mclk_cc_mclk1_clk_src",
+		.parent_data = cam_bist_mclk_cc_parent_data_0,
+		.num_parents = ARRAY_SIZE(cam_bist_mclk_cc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 cam_bist_mclk_cc_mclk2_clk_src = {
+	.cmd_rcgr = 0x4038,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = cam_bist_mclk_cc_parent_map_0,
+	.freq_tbl = ftbl_cam_bist_mclk_cc_mclk0_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_bist_mclk_cc_mclk2_clk_src",
+		.parent_data = cam_bist_mclk_cc_parent_data_0,
+		.num_parents = ARRAY_SIZE(cam_bist_mclk_cc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 cam_bist_mclk_cc_mclk3_clk_src = {
+	.cmd_rcgr = 0x4054,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = cam_bist_mclk_cc_parent_map_0,
+	.freq_tbl = ftbl_cam_bist_mclk_cc_mclk0_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_bist_mclk_cc_mclk3_clk_src",
+		.parent_data = cam_bist_mclk_cc_parent_data_0,
+		.num_parents = ARRAY_SIZE(cam_bist_mclk_cc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 cam_bist_mclk_cc_mclk4_clk_src = {
+	.cmd_rcgr = 0x4070,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = cam_bist_mclk_cc_parent_map_0,
+	.freq_tbl = ftbl_cam_bist_mclk_cc_mclk0_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_bist_mclk_cc_mclk4_clk_src",
+		.parent_data = cam_bist_mclk_cc_parent_data_0,
+		.num_parents = ARRAY_SIZE(cam_bist_mclk_cc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 cam_bist_mclk_cc_mclk5_clk_src = {
+	.cmd_rcgr = 0x408c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = cam_bist_mclk_cc_parent_map_0,
+	.freq_tbl = ftbl_cam_bist_mclk_cc_mclk0_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_bist_mclk_cc_mclk5_clk_src",
+		.parent_data = cam_bist_mclk_cc_parent_data_0,
+		.num_parents = ARRAY_SIZE(cam_bist_mclk_cc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 cam_bist_mclk_cc_mclk6_clk_src = {
+	.cmd_rcgr = 0x40a8,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = cam_bist_mclk_cc_parent_map_0,
+	.freq_tbl = ftbl_cam_bist_mclk_cc_mclk0_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_bist_mclk_cc_mclk6_clk_src",
+		.parent_data = cam_bist_mclk_cc_parent_data_0,
+		.num_parents = ARRAY_SIZE(cam_bist_mclk_cc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 cam_bist_mclk_cc_mclk7_clk_src = {
+	.cmd_rcgr = 0x40c4,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = cam_bist_mclk_cc_parent_map_0,
+	.freq_tbl = ftbl_cam_bist_mclk_cc_mclk0_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_bist_mclk_cc_mclk7_clk_src",
+		.parent_data = cam_bist_mclk_cc_parent_data_0,
+		.num_parents = ARRAY_SIZE(cam_bist_mclk_cc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_cam_bist_mclk_cc_sleep_clk_src[] = {
+	F(32000, P_SLEEP_CLK, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 cam_bist_mclk_cc_sleep_clk_src = {
+	.cmd_rcgr = 0x40e0,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_bist_mclk_cc_parent_map_1,
+	.freq_tbl = ftbl_cam_bist_mclk_cc_sleep_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_bist_mclk_cc_sleep_clk_src",
+		.parent_data = cam_bist_mclk_cc_parent_data_1,
+		.num_parents = ARRAY_SIZE(cam_bist_mclk_cc_parent_data_1),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_branch cam_bist_mclk_cc_mclk0_clk = {
+	.halt_reg = 0x4018,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x4018,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_bist_mclk_cc_mclk0_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_bist_mclk_cc_mclk0_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_bist_mclk_cc_mclk1_clk = {
+	.halt_reg = 0x4034,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x4034,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_bist_mclk_cc_mclk1_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_bist_mclk_cc_mclk1_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_bist_mclk_cc_mclk2_clk = {
+	.halt_reg = 0x4050,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x4050,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_bist_mclk_cc_mclk2_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_bist_mclk_cc_mclk2_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_bist_mclk_cc_mclk3_clk = {
+	.halt_reg = 0x406c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x406c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_bist_mclk_cc_mclk3_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_bist_mclk_cc_mclk3_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_bist_mclk_cc_mclk4_clk = {
+	.halt_reg = 0x4088,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x4088,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_bist_mclk_cc_mclk4_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_bist_mclk_cc_mclk4_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_bist_mclk_cc_mclk5_clk = {
+	.halt_reg = 0x40a4,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x40a4,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_bist_mclk_cc_mclk5_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_bist_mclk_cc_mclk5_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_bist_mclk_cc_mclk6_clk = {
+	.halt_reg = 0x40c0,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x40c0,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_bist_mclk_cc_mclk6_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_bist_mclk_cc_mclk6_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_bist_mclk_cc_mclk7_clk = {
+	.halt_reg = 0x40dc,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x40dc,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_bist_mclk_cc_mclk7_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_bist_mclk_cc_mclk7_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_regmap *cam_bist_mclk_cc_sm8750_clocks[] = {
+	[CAM_BIST_MCLK_CC_MCLK0_CLK] = &cam_bist_mclk_cc_mclk0_clk.clkr,
+	[CAM_BIST_MCLK_CC_MCLK0_CLK_SRC] = &cam_bist_mclk_cc_mclk0_clk_src.clkr,
+	[CAM_BIST_MCLK_CC_MCLK1_CLK] = &cam_bist_mclk_cc_mclk1_clk.clkr,
+	[CAM_BIST_MCLK_CC_MCLK1_CLK_SRC] = &cam_bist_mclk_cc_mclk1_clk_src.clkr,
+	[CAM_BIST_MCLK_CC_MCLK2_CLK] = &cam_bist_mclk_cc_mclk2_clk.clkr,
+	[CAM_BIST_MCLK_CC_MCLK2_CLK_SRC] = &cam_bist_mclk_cc_mclk2_clk_src.clkr,
+	[CAM_BIST_MCLK_CC_MCLK3_CLK] = &cam_bist_mclk_cc_mclk3_clk.clkr,
+	[CAM_BIST_MCLK_CC_MCLK3_CLK_SRC] = &cam_bist_mclk_cc_mclk3_clk_src.clkr,
+	[CAM_BIST_MCLK_CC_MCLK4_CLK] = &cam_bist_mclk_cc_mclk4_clk.clkr,
+	[CAM_BIST_MCLK_CC_MCLK4_CLK_SRC] = &cam_bist_mclk_cc_mclk4_clk_src.clkr,
+	[CAM_BIST_MCLK_CC_MCLK5_CLK] = &cam_bist_mclk_cc_mclk5_clk.clkr,
+	[CAM_BIST_MCLK_CC_MCLK5_CLK_SRC] = &cam_bist_mclk_cc_mclk5_clk_src.clkr,
+	[CAM_BIST_MCLK_CC_MCLK6_CLK] = &cam_bist_mclk_cc_mclk6_clk.clkr,
+	[CAM_BIST_MCLK_CC_MCLK6_CLK_SRC] = &cam_bist_mclk_cc_mclk6_clk_src.clkr,
+	[CAM_BIST_MCLK_CC_MCLK7_CLK] = &cam_bist_mclk_cc_mclk7_clk.clkr,
+	[CAM_BIST_MCLK_CC_MCLK7_CLK_SRC] = &cam_bist_mclk_cc_mclk7_clk_src.clkr,
+	[CAM_BIST_MCLK_CC_PLL0] = &cam_bist_mclk_cc_pll0.clkr,
+	[CAM_BIST_MCLK_CC_SLEEP_CLK_SRC] = &cam_bist_mclk_cc_sleep_clk_src.clkr,
+};
+
+static struct clk_alpha_pll *cam_bist_mclk_cc_sm8750_plls[] = {
+	&cam_bist_mclk_cc_pll0,
+};
+
+static u32 cam_bist_mclk_cc_sm8750_critical_cbcrs[] = {
+	0x40f8, /* CAM_BIST_MCLK_CC_SLEEP_CLK */
+};
+
+static const struct regmap_config cam_bist_mclk_cc_sm8750_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = 0x5010,
+	.fast_io = true,
+};
+
+static struct qcom_cc_driver_data cam_bist_mclk_cc_sm8750_driver_data = {
+	.alpha_plls = cam_bist_mclk_cc_sm8750_plls,
+	.num_alpha_plls = ARRAY_SIZE(cam_bist_mclk_cc_sm8750_plls),
+	.clk_cbcrs = cam_bist_mclk_cc_sm8750_critical_cbcrs,
+	.num_clk_cbcrs = ARRAY_SIZE(cam_bist_mclk_cc_sm8750_critical_cbcrs),
+};
+
+static struct qcom_cc_desc cam_bist_mclk_cc_sm8750_desc = {
+	.config = &cam_bist_mclk_cc_sm8750_regmap_config,
+	.clks = cam_bist_mclk_cc_sm8750_clocks,
+	.num_clks = ARRAY_SIZE(cam_bist_mclk_cc_sm8750_clocks),
+	.use_rpm = true,
+	.driver_data = &cam_bist_mclk_cc_sm8750_driver_data,
+};
+
+static const struct of_device_id cam_bist_mclk_cc_sm8750_match_table[] = {
+	{ .compatible = "qcom,sm8750-cambistmclkcc" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, cam_bist_mclk_cc_sm8750_match_table);
+
+static int cam_bist_mclk_cc_sm8750_probe(struct platform_device *pdev)
+{
+	return qcom_cc_probe(pdev, &cam_bist_mclk_cc_sm8750_desc);
+}
+
+static struct platform_driver cam_bist_mclk_cc_sm8750_driver = {
+	.probe = cam_bist_mclk_cc_sm8750_probe,
+	.driver = {
+		.name = "cambistmclkcc-sm8750",
+		.of_match_table = cam_bist_mclk_cc_sm8750_match_table,
+	},
+};
+
+module_platform_driver(cam_bist_mclk_cc_sm8750_driver);
+
+MODULE_DESCRIPTION("QTI CAMBISTMCLKCC SM8750 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/qcom/camcc-sm8750.c b/drivers/clk/qcom/camcc-sm8750.c
new file mode 100644
index 0000000000000000000000000000000000000000..c09fa75be4576ce510c3a17fe0ddf51b0683b5fe
--- /dev/null
+++ b/drivers/clk/qcom/camcc-sm8750.c
@@ -0,0 +1,2710 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,sm8750-camcc.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "common.h"
+#include "gdsc.h"
+#include "reset.h"
+
+enum {
+	DT_IFACE,
+	DT_BI_TCXO,
+	DT_BI_TCXO_AO,
+	DT_SLEEP_CLK,
+};
+
+enum {
+	P_BI_TCXO,
+	P_BI_TCXO_AO,
+	P_CAM_CC_PLL0_OUT_EVEN,
+	P_CAM_CC_PLL0_OUT_MAIN,
+	P_CAM_CC_PLL0_OUT_ODD,
+	P_CAM_CC_PLL1_OUT_EVEN,
+	P_CAM_CC_PLL2_OUT_EVEN,
+	P_CAM_CC_PLL3_OUT_EVEN,
+	P_CAM_CC_PLL4_OUT_EVEN,
+	P_CAM_CC_PLL5_OUT_EVEN,
+	P_CAM_CC_PLL6_OUT_EVEN,
+	P_CAM_CC_PLL6_OUT_ODD,
+	P_SLEEP_CLK,
+};
+
+static const struct pll_vco taycan_elu_vco[] = {
+	{ 249600000, 2500000000, 0 },
+};
+
+static const struct alpha_pll_config cam_cc_pll0_config = {
+	.l = 0x3e,
+	.alpha = 0x8000,
+	.config_ctl_val = 0x19660387,
+	.config_ctl_hi_val = 0x098060a0,
+	.config_ctl_hi1_val = 0xb416cb20,
+	.user_ctl_val = 0x00008400,
+	.user_ctl_hi_val = 0x00000002,
+};
+
+static struct clk_alpha_pll cam_cc_pll0 = {
+	.offset = 0x0,
+	.config = &cam_cc_pll0_config,
+	.vco_table = taycan_elu_vco,
+	.num_vco = ARRAY_SIZE(taycan_elu_vco),
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_ELU],
+	.clkr = {
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_pll0",
+			.parent_data = &(const struct clk_parent_data) {
+				.index = DT_BI_TCXO,
+			},
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_taycan_elu_ops,
+		},
+	},
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll0_out_even[] = {
+	{ 0x1, 2 },
+	{ }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll0_out_even = {
+	.offset = 0x0,
+	.post_div_shift = 10,
+	.post_div_table = post_div_table_cam_cc_pll0_out_even,
+	.num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll0_out_even),
+	.width = 4,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_ELU],
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_pll0_out_even",
+		.parent_hws = (const struct clk_hw*[]) {
+			&cam_cc_pll0.clkr.hw,
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_alpha_pll_postdiv_taycan_elu_ops,
+	},
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll0_out_odd[] = {
+	{ 0x2, 3 },
+	{ }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll0_out_odd = {
+	.offset = 0x0,
+	.post_div_shift = 14,
+	.post_div_table = post_div_table_cam_cc_pll0_out_odd,
+	.num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll0_out_odd),
+	.width = 4,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_ELU],
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_pll0_out_odd",
+		.parent_hws = (const struct clk_hw*[]) {
+			&cam_cc_pll0.clkr.hw,
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_alpha_pll_postdiv_taycan_elu_ops,
+	},
+};
+
+static const struct alpha_pll_config cam_cc_pll1_config = {
+	.l = 0x22,
+	.alpha = 0xa2aa,
+	.config_ctl_val = 0x19660387,
+	.config_ctl_hi_val = 0x098060a0,
+	.config_ctl_hi1_val = 0xb416cb20,
+	.user_ctl_val = 0x00000400,
+	.user_ctl_hi_val = 0x00000002,
+};
+
+static struct clk_alpha_pll cam_cc_pll1 = {
+	.offset = 0x1000,
+	.config = &cam_cc_pll1_config,
+	.vco_table = taycan_elu_vco,
+	.num_vco = ARRAY_SIZE(taycan_elu_vco),
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_ELU],
+	.clkr = {
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_pll1",
+			.parent_data = &(const struct clk_parent_data) {
+				.index = DT_BI_TCXO,
+			},
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_taycan_elu_ops,
+		},
+	},
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll1_out_even[] = {
+	{ 0x1, 2 },
+	{ }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll1_out_even = {
+	.offset = 0x1000,
+	.post_div_shift = 10,
+	.post_div_table = post_div_table_cam_cc_pll1_out_even,
+	.num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll1_out_even),
+	.width = 4,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_ELU],
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_pll1_out_even",
+		.parent_hws = (const struct clk_hw*[]) {
+			&cam_cc_pll1.clkr.hw,
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_alpha_pll_postdiv_taycan_elu_ops,
+	},
+};
+
+static const struct alpha_pll_config cam_cc_pll2_config = {
+	.l = 0x23,
+	.alpha = 0x4aaa,
+	.config_ctl_val = 0x19660387,
+	.config_ctl_hi_val = 0x098060a0,
+	.config_ctl_hi1_val = 0xb416cb20,
+	.user_ctl_val = 0x00000400,
+	.user_ctl_hi_val = 0x00000002,
+};
+
+static struct clk_alpha_pll cam_cc_pll2 = {
+	.offset = 0x2000,
+	.config = &cam_cc_pll2_config,
+	.vco_table = taycan_elu_vco,
+	.num_vco = ARRAY_SIZE(taycan_elu_vco),
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_ELU],
+	.clkr = {
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_pll2",
+			.parent_data = &(const struct clk_parent_data) {
+				.index = DT_BI_TCXO,
+			},
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_taycan_elu_ops,
+		},
+	},
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll2_out_even[] = {
+	{ 0x1, 2 },
+	{ }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll2_out_even = {
+	.offset = 0x2000,
+	.post_div_shift = 10,
+	.post_div_table = post_div_table_cam_cc_pll2_out_even,
+	.num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll2_out_even),
+	.width = 4,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_ELU],
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_pll2_out_even",
+		.parent_hws = (const struct clk_hw*[]) {
+			&cam_cc_pll2.clkr.hw,
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_alpha_pll_postdiv_taycan_elu_ops,
+	},
+};
+
+static const struct alpha_pll_config cam_cc_pll3_config = {
+	.l = 0x25,
+	.alpha = 0x8777,
+	.config_ctl_val = 0x19660387,
+	.config_ctl_hi_val = 0x098060a0,
+	.config_ctl_hi1_val = 0xb416cb20,
+	.user_ctl_val = 0x00000400,
+	.user_ctl_hi_val = 0x00000002,
+};
+
+static struct clk_alpha_pll cam_cc_pll3 = {
+	.offset = 0x3000,
+	.config = &cam_cc_pll3_config,
+	.vco_table = taycan_elu_vco,
+	.num_vco = ARRAY_SIZE(taycan_elu_vco),
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_ELU],
+	.clkr = {
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_pll3",
+			.parent_data = &(const struct clk_parent_data) {
+				.index = DT_BI_TCXO,
+			},
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_taycan_elu_ops,
+		},
+	},
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll3_out_even[] = {
+	{ 0x1, 2 },
+	{ }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll3_out_even = {
+	.offset = 0x3000,
+	.post_div_shift = 10,
+	.post_div_table = post_div_table_cam_cc_pll3_out_even,
+	.num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll3_out_even),
+	.width = 4,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_ELU],
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_pll3_out_even",
+		.parent_hws = (const struct clk_hw*[]) {
+			&cam_cc_pll3.clkr.hw,
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_alpha_pll_postdiv_taycan_elu_ops,
+	},
+};
+
+static const struct alpha_pll_config cam_cc_pll4_config = {
+	.l = 0x25,
+	.alpha = 0x8777,
+	.config_ctl_val = 0x19660387,
+	.config_ctl_hi_val = 0x098060a0,
+	.config_ctl_hi1_val = 0xb416cb20,
+	.user_ctl_val = 0x00000400,
+	.user_ctl_hi_val = 0x00000002,
+};
+
+static struct clk_alpha_pll cam_cc_pll4 = {
+	.offset = 0x4000,
+	.config = &cam_cc_pll4_config,
+	.vco_table = taycan_elu_vco,
+	.num_vco = ARRAY_SIZE(taycan_elu_vco),
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_ELU],
+	.clkr = {
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_pll4",
+			.parent_data = &(const struct clk_parent_data) {
+				.index = DT_BI_TCXO,
+			},
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_taycan_elu_ops,
+		},
+	},
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll4_out_even[] = {
+	{ 0x1, 2 },
+	{ }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll4_out_even = {
+	.offset = 0x4000,
+	.post_div_shift = 10,
+	.post_div_table = post_div_table_cam_cc_pll4_out_even,
+	.num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll4_out_even),
+	.width = 4,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_ELU],
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_pll4_out_even",
+		.parent_hws = (const struct clk_hw*[]) {
+			&cam_cc_pll4.clkr.hw,
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_alpha_pll_postdiv_taycan_elu_ops,
+	},
+};
+
+static const struct alpha_pll_config cam_cc_pll5_config = {
+	.l = 0x25,
+	.alpha = 0x8777,
+	.config_ctl_val = 0x19660387,
+	.config_ctl_hi_val = 0x098060a0,
+	.config_ctl_hi1_val = 0xb416cb20,
+	.user_ctl_val = 0x00000400,
+	.user_ctl_hi_val = 0x00000002,
+};
+
+static struct clk_alpha_pll cam_cc_pll5 = {
+	.offset = 0x5000,
+	.config = &cam_cc_pll5_config,
+	.vco_table = taycan_elu_vco,
+	.num_vco = ARRAY_SIZE(taycan_elu_vco),
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_ELU],
+	.clkr = {
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_pll5",
+			.parent_data = &(const struct clk_parent_data) {
+				.index = DT_BI_TCXO,
+			},
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_taycan_elu_ops,
+		},
+	},
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll5_out_even[] = {
+	{ 0x1, 2 },
+	{ }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll5_out_even = {
+	.offset = 0x5000,
+	.post_div_shift = 10,
+	.post_div_table = post_div_table_cam_cc_pll5_out_even,
+	.num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll5_out_even),
+	.width = 4,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_ELU],
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_pll5_out_even",
+		.parent_hws = (const struct clk_hw*[]) {
+			&cam_cc_pll5.clkr.hw,
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_alpha_pll_postdiv_taycan_elu_ops,
+	},
+};
+
+static const struct alpha_pll_config cam_cc_pll6_config = {
+	.l = 0x32,
+	.alpha = 0x0,
+	.config_ctl_val = 0x19660387,
+	.config_ctl_hi_val = 0x098060a0,
+	.config_ctl_hi1_val = 0xb416cb20,
+	.user_ctl_val = 0x00008400,
+	.user_ctl_hi_val = 0x00000002,
+};
+
+static struct clk_alpha_pll cam_cc_pll6 = {
+	.offset = 0x6000,
+	.config = &cam_cc_pll6_config,
+	.vco_table = taycan_elu_vco,
+	.num_vco = ARRAY_SIZE(taycan_elu_vco),
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_ELU],
+	.clkr = {
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_pll6",
+			.parent_data = &(const struct clk_parent_data) {
+				.index = DT_BI_TCXO,
+			},
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_taycan_elu_ops,
+		},
+	},
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll6_out_even[] = {
+	{ 0x1, 2 },
+	{ }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll6_out_even = {
+	.offset = 0x6000,
+	.post_div_shift = 10,
+	.post_div_table = post_div_table_cam_cc_pll6_out_even,
+	.num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll6_out_even),
+	.width = 4,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_ELU],
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_pll6_out_even",
+		.parent_hws = (const struct clk_hw*[]) {
+			&cam_cc_pll6.clkr.hw,
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_alpha_pll_postdiv_taycan_elu_ops,
+	},
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll6_out_odd[] = {
+	{ 0x2, 3 },
+	{ }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll6_out_odd = {
+	.offset = 0x6000,
+	.post_div_shift = 14,
+	.post_div_table = post_div_table_cam_cc_pll6_out_odd,
+	.num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll6_out_odd),
+	.width = 4,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_ELU],
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_pll6_out_odd",
+		.parent_hws = (const struct clk_hw*[]) {
+			&cam_cc_pll6.clkr.hw,
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_alpha_pll_postdiv_taycan_elu_ops,
+	},
+};
+
+static const struct parent_map cam_cc_parent_map_0[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_CAM_CC_PLL0_OUT_MAIN, 1 },
+	{ P_CAM_CC_PLL0_OUT_EVEN, 2 },
+	{ P_CAM_CC_PLL0_OUT_ODD, 3 },
+	{ P_CAM_CC_PLL6_OUT_ODD, 4 },
+	{ P_CAM_CC_PLL6_OUT_EVEN, 5 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_0[] = {
+	{ .index = DT_BI_TCXO },
+	{ .hw = &cam_cc_pll0.clkr.hw },
+	{ .hw = &cam_cc_pll0_out_even.clkr.hw },
+	{ .hw = &cam_cc_pll0_out_odd.clkr.hw },
+	{ .hw = &cam_cc_pll6_out_odd.clkr.hw },
+	{ .hw = &cam_cc_pll6_out_even.clkr.hw },
+};
+
+static const struct parent_map cam_cc_parent_map_1[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_CAM_CC_PLL0_OUT_MAIN, 1 },
+	{ P_CAM_CC_PLL0_OUT_EVEN, 2 },
+	{ P_CAM_CC_PLL0_OUT_ODD, 3 },
+	{ P_CAM_CC_PLL6_OUT_ODD, 4 },
+	{ P_CAM_CC_PLL6_OUT_EVEN, 5 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_1[] = {
+	{ .index = DT_BI_TCXO },
+	{ .hw = &cam_cc_pll0.clkr.hw },
+	{ .hw = &cam_cc_pll0_out_even.clkr.hw },
+	{ .hw = &cam_cc_pll0_out_odd.clkr.hw },
+	{ .hw = &cam_cc_pll6_out_odd.clkr.hw },
+	{ .hw = &cam_cc_pll6_out_even.clkr.hw },
+};
+
+static const struct parent_map cam_cc_parent_map_2[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_CAM_CC_PLL1_OUT_EVEN, 4 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_2[] = {
+	{ .index = DT_BI_TCXO },
+	{ .hw = &cam_cc_pll1_out_even.clkr.hw },
+};
+
+static const struct parent_map cam_cc_parent_map_3[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_CAM_CC_PLL2_OUT_EVEN, 5 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_3[] = {
+	{ .index = DT_BI_TCXO },
+	{ .hw = &cam_cc_pll2_out_even.clkr.hw },
+};
+
+static const struct parent_map cam_cc_parent_map_4[] = {
+	{ P_SLEEP_CLK, 0 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_4[] = {
+	{ .index = DT_SLEEP_CLK },
+};
+
+static const struct parent_map cam_cc_parent_map_5[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_CAM_CC_PLL3_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_5[] = {
+	{ .index = DT_BI_TCXO },
+	{ .hw = &cam_cc_pll3_out_even.clkr.hw },
+};
+
+static const struct parent_map cam_cc_parent_map_6[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_CAM_CC_PLL4_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_6[] = {
+	{ .index = DT_BI_TCXO },
+	{ .hw = &cam_cc_pll4_out_even.clkr.hw },
+};
+
+static const struct parent_map cam_cc_parent_map_7[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_CAM_CC_PLL5_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_7[] = {
+	{ .index = DT_BI_TCXO },
+	{ .hw = &cam_cc_pll5_out_even.clkr.hw },
+};
+
+static const struct parent_map cam_cc_parent_map_8_ao[] = {
+	{ P_BI_TCXO_AO, 0 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_8_ao[] = {
+	{ .index = DT_BI_TCXO_AO },
+};
+
+static const struct freq_tbl ftbl_cam_cc_camnoc_rt_axi_clk_src[] = {
+	F(19200000, P_BI_TCXO, 1, 0, 0),
+	F(200000000, P_CAM_CC_PLL0_OUT_EVEN, 3, 0, 0),
+	F(300000000, P_CAM_CC_PLL0_OUT_EVEN, 2, 0, 0),
+	F(400000000, P_CAM_CC_PLL0_OUT_EVEN, 1.5, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 cam_cc_camnoc_rt_axi_clk_src = {
+	.cmd_rcgr = 0x112e8,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_0,
+	.freq_tbl = ftbl_cam_cc_camnoc_rt_axi_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_camnoc_rt_axi_clk_src",
+		.parent_data = cam_cc_parent_data_0,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_cam_cc_cci_0_clk_src[] = {
+	F(37500000, P_CAM_CC_PLL0_OUT_EVEN, 16, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 cam_cc_cci_0_clk_src = {
+	.cmd_rcgr = 0x1126c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_0,
+	.freq_tbl = ftbl_cam_cc_cci_0_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_cci_0_clk_src",
+		.parent_data = cam_cc_parent_data_0,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 cam_cc_cci_1_clk_src = {
+	.cmd_rcgr = 0x11288,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_0,
+	.freq_tbl = ftbl_cam_cc_cci_0_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_cci_1_clk_src",
+		.parent_data = cam_cc_parent_data_0,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 cam_cc_cci_2_clk_src = {
+	.cmd_rcgr = 0x112a4,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_0,
+	.freq_tbl = ftbl_cam_cc_cci_0_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_cci_2_clk_src",
+		.parent_data = cam_cc_parent_data_0,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_cam_cc_cphy_rx_clk_src[] = {
+	F(266666667, P_CAM_CC_PLL0_OUT_MAIN, 4.5, 0, 0),
+	F(400000000, P_CAM_CC_PLL0_OUT_MAIN, 3, 0, 0),
+	F(480000000, P_CAM_CC_PLL0_OUT_MAIN, 2.5, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 cam_cc_cphy_rx_clk_src = {
+	.cmd_rcgr = 0x11068,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_1,
+	.freq_tbl = ftbl_cam_cc_cphy_rx_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_cphy_rx_clk_src",
+		.parent_data = cam_cc_parent_data_1,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_cam_cc_cre_clk_src[] = {
+	F(137142857, P_CAM_CC_PLL6_OUT_EVEN, 3.5, 0, 0),
+	F(200000000, P_CAM_CC_PLL0_OUT_ODD, 2, 0, 0),
+	F(400000000, P_CAM_CC_PLL0_OUT_ODD, 1, 0, 0),
+	F(480000000, P_CAM_CC_PLL6_OUT_EVEN, 1, 0, 0),
+	F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 cam_cc_cre_clk_src = {
+	.cmd_rcgr = 0x111ac,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_0,
+	.freq_tbl = ftbl_cam_cc_cre_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_cre_clk_src",
+		.parent_data = cam_cc_parent_data_0,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_cam_cc_csi0phytimer_clk_src[] = {
+	F(400000000, P_CAM_CC_PLL0_OUT_MAIN, 3, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 cam_cc_csi0phytimer_clk_src = {
+	.cmd_rcgr = 0x10000,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_1,
+	.freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_csi0phytimer_clk_src",
+		.parent_data = cam_cc_parent_data_1,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 cam_cc_csi1phytimer_clk_src = {
+	.cmd_rcgr = 0x10024,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_1,
+	.freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_csi1phytimer_clk_src",
+		.parent_data = cam_cc_parent_data_1,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 cam_cc_csi2phytimer_clk_src = {
+	.cmd_rcgr = 0x10044,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_1,
+	.freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_csi2phytimer_clk_src",
+		.parent_data = cam_cc_parent_data_1,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 cam_cc_csi3phytimer_clk_src = {
+	.cmd_rcgr = 0x10064,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_1,
+	.freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_csi3phytimer_clk_src",
+		.parent_data = cam_cc_parent_data_1,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 cam_cc_csi4phytimer_clk_src = {
+	.cmd_rcgr = 0x10084,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_1,
+	.freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_csi4phytimer_clk_src",
+		.parent_data = cam_cc_parent_data_1,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 cam_cc_csi5phytimer_clk_src = {
+	.cmd_rcgr = 0x100a4,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_1,
+	.freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_csi5phytimer_clk_src",
+		.parent_data = cam_cc_parent_data_1,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 cam_cc_csid_clk_src = {
+	.cmd_rcgr = 0x112c0,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_1,
+	.freq_tbl = ftbl_cam_cc_cphy_rx_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_csid_clk_src",
+		.parent_data = cam_cc_parent_data_1,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_cam_cc_fast_ahb_clk_src[] = {
+	F(213333333, P_CAM_CC_PLL6_OUT_ODD, 1.5, 0, 0),
+	F(300000000, P_CAM_CC_PLL0_OUT_EVEN, 2, 0, 0),
+	F(400000000, P_CAM_CC_PLL0_OUT_MAIN, 3, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 cam_cc_fast_ahb_clk_src = {
+	.cmd_rcgr = 0x100dc,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_0,
+	.freq_tbl = ftbl_cam_cc_fast_ahb_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_fast_ahb_clk_src",
+		.parent_data = cam_cc_parent_data_0,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_cam_cc_icp_0_clk_src[] = {
+	F(300000000, P_CAM_CC_PLL0_OUT_EVEN, 2, 0, 0),
+	F(400000000, P_CAM_CC_PLL0_OUT_ODD, 1, 0, 0),
+	F(480000000, P_CAM_CC_PLL6_OUT_EVEN, 1, 0, 0),
+	F(600000000, P_CAM_CC_PLL0_OUT_MAIN, 2, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 cam_cc_icp_0_clk_src = {
+	.cmd_rcgr = 0x11214,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_0,
+	.freq_tbl = ftbl_cam_cc_icp_0_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_icp_0_clk_src",
+		.parent_data = cam_cc_parent_data_0,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 cam_cc_icp_1_clk_src = {
+	.cmd_rcgr = 0x1123c,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_0,
+	.freq_tbl = ftbl_cam_cc_icp_0_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_icp_1_clk_src",
+		.parent_data = cam_cc_parent_data_0,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 cam_cc_ife_lite_clk_src = {
+	.cmd_rcgr = 0x11150,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_1,
+	.freq_tbl = ftbl_cam_cc_cphy_rx_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_ife_lite_clk_src",
+		.parent_data = cam_cc_parent_data_1,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 cam_cc_ife_lite_csid_clk_src = {
+	.cmd_rcgr = 0x1117c,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_1,
+	.freq_tbl = ftbl_cam_cc_cphy_rx_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_ife_lite_csid_clk_src",
+		.parent_data = cam_cc_parent_data_1,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_cam_cc_ipe_nps_clk_src[] = {
+	F(332500000, P_CAM_CC_PLL1_OUT_EVEN, 1, 0, 0),
+	F(475000000, P_CAM_CC_PLL1_OUT_EVEN, 1, 0, 0),
+	F(575000000, P_CAM_CC_PLL1_OUT_EVEN, 1, 0, 0),
+	F(675000000, P_CAM_CC_PLL1_OUT_EVEN, 1, 0, 0),
+	F(825000000, P_CAM_CC_PLL1_OUT_EVEN, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 cam_cc_ipe_nps_clk_src = {
+	.cmd_rcgr = 0x10190,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_2,
+	.freq_tbl = ftbl_cam_cc_ipe_nps_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_ipe_nps_clk_src",
+		.parent_data = cam_cc_parent_data_2,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_2),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 cam_cc_jpeg_clk_src = {
+	.cmd_rcgr = 0x111d0,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_0,
+	.freq_tbl = ftbl_cam_cc_cre_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_jpeg_clk_src",
+		.parent_data = cam_cc_parent_data_0,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_cam_cc_ofe_clk_src[] = {
+	F(338800000, P_CAM_CC_PLL2_OUT_EVEN, 1, 0, 0),
+	F(484000000, P_CAM_CC_PLL2_OUT_EVEN, 1, 0, 0),
+	F(586000000, P_CAM_CC_PLL2_OUT_EVEN, 1, 0, 0),
+	F(688000000, P_CAM_CC_PLL2_OUT_EVEN, 1, 0, 0),
+	F(841000000, P_CAM_CC_PLL2_OUT_EVEN, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 cam_cc_ofe_clk_src = {
+	.cmd_rcgr = 0x1011c,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_3,
+	.freq_tbl = ftbl_cam_cc_ofe_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_ofe_clk_src",
+		.parent_data = cam_cc_parent_data_3,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_3),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_cam_cc_qdss_debug_clk_src[] = {
+	F(40000000, P_CAM_CC_PLL6_OUT_ODD, 8, 0, 0),
+	F(60000000, P_CAM_CC_PLL6_OUT_EVEN, 8, 0, 0),
+	F(120000000, P_CAM_CC_PLL0_OUT_EVEN, 5, 0, 0),
+	F(240000000, P_CAM_CC_PLL0_OUT_MAIN, 5, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 cam_cc_qdss_debug_clk_src = {
+	.cmd_rcgr = 0x1132c,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_0,
+	.freq_tbl = ftbl_cam_cc_qdss_debug_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_qdss_debug_clk_src",
+		.parent_data = cam_cc_parent_data_0,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_cam_cc_sleep_clk_src[] = {
+	F(32000, P_SLEEP_CLK, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 cam_cc_sleep_clk_src = {
+	.cmd_rcgr = 0x11380,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_4,
+	.freq_tbl = ftbl_cam_cc_sleep_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_sleep_clk_src",
+		.parent_data = cam_cc_parent_data_4,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_4),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_cam_cc_slow_ahb_clk_src[] = {
+	F(56470588, P_CAM_CC_PLL6_OUT_EVEN, 8.5, 0, 0),
+	F(80000000, P_CAM_CC_PLL0_OUT_EVEN, 7.5, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 cam_cc_slow_ahb_clk_src = {
+	.cmd_rcgr = 0x10100,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_0,
+	.freq_tbl = ftbl_cam_cc_slow_ahb_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_slow_ahb_clk_src",
+		.parent_data = cam_cc_parent_data_0,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_cam_cc_tfe_0_clk_src[] = {
+	F(360280000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0),
+	F(480000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0),
+	F(630000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0),
+	F(716000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0),
+	F(833000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 cam_cc_tfe_0_clk_src = {
+	.cmd_rcgr = 0x11018,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_5,
+	.freq_tbl = ftbl_cam_cc_tfe_0_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_tfe_0_clk_src",
+		.parent_data = cam_cc_parent_data_5,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_5),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_cam_cc_tfe_1_clk_src[] = {
+	F(360280000, P_CAM_CC_PLL4_OUT_EVEN, 1, 0, 0),
+	F(480000000, P_CAM_CC_PLL4_OUT_EVEN, 1, 0, 0),
+	F(630000000, P_CAM_CC_PLL4_OUT_EVEN, 1, 0, 0),
+	F(716000000, P_CAM_CC_PLL4_OUT_EVEN, 1, 0, 0),
+	F(833000000, P_CAM_CC_PLL4_OUT_EVEN, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 cam_cc_tfe_1_clk_src = {
+	.cmd_rcgr = 0x11098,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_6,
+	.freq_tbl = ftbl_cam_cc_tfe_1_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_tfe_1_clk_src",
+		.parent_data = cam_cc_parent_data_6,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_6),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_cam_cc_tfe_2_clk_src[] = {
+	F(360280000, P_CAM_CC_PLL5_OUT_EVEN, 1, 0, 0),
+	F(480000000, P_CAM_CC_PLL5_OUT_EVEN, 1, 0, 0),
+	F(630000000, P_CAM_CC_PLL5_OUT_EVEN, 1, 0, 0),
+	F(716000000, P_CAM_CC_PLL5_OUT_EVEN, 1, 0, 0),
+	F(833000000, P_CAM_CC_PLL5_OUT_EVEN, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 cam_cc_tfe_2_clk_src = {
+	.cmd_rcgr = 0x11100,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_7,
+	.freq_tbl = ftbl_cam_cc_tfe_2_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_tfe_2_clk_src",
+		.parent_data = cam_cc_parent_data_7,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_7),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_cam_cc_xo_clk_src[] = {
+	F(19200000, P_BI_TCXO_AO, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 cam_cc_xo_clk_src = {
+	.cmd_rcgr = 0x11364,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_8_ao,
+	.freq_tbl = ftbl_cam_cc_xo_clk_src,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "cam_cc_xo_clk_src",
+		.parent_data = cam_cc_parent_data_8_ao,
+		.num_parents = ARRAY_SIZE(cam_cc_parent_data_8_ao),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_branch cam_cc_cam_top_ahb_clk = {
+	.halt_reg = 0x113ac,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x113ac,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_cam_top_ahb_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_slow_ahb_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_cam_top_fast_ahb_clk = {
+	.halt_reg = 0x1139c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1139c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_cam_top_fast_ahb_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_fast_ahb_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_camnoc_dcd_xo_clk = {
+	.halt_reg = 0x11320,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x11320,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_camnoc_dcd_xo_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_xo_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_camnoc_nrt_axi_clk = {
+	.halt_reg = 0x11310,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x11310,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x11310,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_camnoc_nrt_axi_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_camnoc_rt_axi_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_camnoc_nrt_cre_clk = {
+	.halt_reg = 0x111c8,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x111c8,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_camnoc_nrt_cre_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_cre_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_camnoc_nrt_ipe_nps_clk = {
+	.halt_reg = 0x101b8,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x101b8,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_camnoc_nrt_ipe_nps_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_ipe_nps_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_camnoc_nrt_ofe_anchor_clk = {
+	.halt_reg = 0x10158,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x10158,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_camnoc_nrt_ofe_anchor_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_ofe_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_camnoc_nrt_ofe_hdr_clk = {
+	.halt_reg = 0x1016c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1016c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_camnoc_nrt_ofe_hdr_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_ofe_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_camnoc_nrt_ofe_main_clk = {
+	.halt_reg = 0x10144,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x10144,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_camnoc_nrt_ofe_main_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_ofe_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_camnoc_rt_axi_clk = {
+	.halt_reg = 0x11300,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x11300,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_camnoc_rt_axi_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_camnoc_rt_axi_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_camnoc_rt_ife_lite_clk = {
+	.halt_reg = 0x11178,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x11178,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_camnoc_rt_ife_lite_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_ife_lite_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_camnoc_rt_tfe_0_bayer_clk = {
+	.halt_reg = 0x11054,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x11054,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_camnoc_rt_tfe_0_bayer_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_tfe_0_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_camnoc_rt_tfe_0_main_clk = {
+	.halt_reg = 0x11040,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x11040,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_camnoc_rt_tfe_0_main_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_tfe_0_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_camnoc_rt_tfe_1_bayer_clk = {
+	.halt_reg = 0x110d4,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x110d4,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_camnoc_rt_tfe_1_bayer_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_tfe_1_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_camnoc_rt_tfe_1_main_clk = {
+	.halt_reg = 0x110c0,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x110c0,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_camnoc_rt_tfe_1_main_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_tfe_1_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_camnoc_rt_tfe_2_bayer_clk = {
+	.halt_reg = 0x1113c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1113c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_camnoc_rt_tfe_2_bayer_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_tfe_2_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_camnoc_rt_tfe_2_main_clk = {
+	.halt_reg = 0x11128,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x11128,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_camnoc_rt_tfe_2_main_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_tfe_2_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_camnoc_xo_clk = {
+	.halt_reg = 0x11324,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x11324,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_camnoc_xo_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_xo_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_cci_0_clk = {
+	.halt_reg = 0x11284,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x11284,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_cci_0_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_cci_0_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_cci_1_clk = {
+	.halt_reg = 0x112a0,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x112a0,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_cci_1_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_cci_1_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_cci_2_clk = {
+	.halt_reg = 0x112bc,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x112bc,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_cci_2_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_cci_2_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_core_ahb_clk = {
+	.halt_reg = 0x11360,
+	.halt_check = BRANCH_HALT_DELAY,
+	.clkr = {
+		.enable_reg = 0x11360,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_core_ahb_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_slow_ahb_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_cre_ahb_clk = {
+	.halt_reg = 0x111cc,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x111cc,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_cre_ahb_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_slow_ahb_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_cre_clk = {
+	.halt_reg = 0x111c4,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x111c4,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_cre_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_cre_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_csi0phytimer_clk = {
+	.halt_reg = 0x10018,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x10018,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_csi0phytimer_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_csi0phytimer_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_csi1phytimer_clk = {
+	.halt_reg = 0x1003c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1003c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_csi1phytimer_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_csi1phytimer_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_csi2phytimer_clk = {
+	.halt_reg = 0x1005c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1005c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_csi2phytimer_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_csi2phytimer_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_csi3phytimer_clk = {
+	.halt_reg = 0x1007c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1007c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_csi3phytimer_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_csi3phytimer_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_csi4phytimer_clk = {
+	.halt_reg = 0x1009c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1009c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_csi4phytimer_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_csi4phytimer_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_csi5phytimer_clk = {
+	.halt_reg = 0x100bc,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x100bc,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_csi5phytimer_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_csi5phytimer_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_csid_clk = {
+	.halt_reg = 0x112d8,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x112d8,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_csid_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_csid_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_csid_csiphy_rx_clk = {
+	.halt_reg = 0x10020,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x10020,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_csid_csiphy_rx_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_cphy_rx_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_csiphy0_clk = {
+	.halt_reg = 0x1001c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1001c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_csiphy0_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_cphy_rx_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_csiphy1_clk = {
+	.halt_reg = 0x10040,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x10040,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_csiphy1_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_cphy_rx_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_csiphy2_clk = {
+	.halt_reg = 0x10060,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x10060,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_csiphy2_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_cphy_rx_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_csiphy3_clk = {
+	.halt_reg = 0x10080,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x10080,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_csiphy3_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_cphy_rx_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_csiphy4_clk = {
+	.halt_reg = 0x100a0,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x100a0,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_csiphy4_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_cphy_rx_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_csiphy5_clk = {
+	.halt_reg = 0x100c0,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x100c0,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_csiphy5_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_cphy_rx_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_icp_0_ahb_clk = {
+	.halt_reg = 0x11264,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x11264,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_icp_0_ahb_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_slow_ahb_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_icp_0_clk = {
+	.halt_reg = 0x1122c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1122c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_icp_0_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_icp_0_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_icp_1_ahb_clk = {
+	.halt_reg = 0x11268,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x11268,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_icp_1_ahb_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_slow_ahb_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_icp_1_clk = {
+	.halt_reg = 0x11254,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x11254,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_icp_1_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_icp_1_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_ife_lite_ahb_clk = {
+	.halt_reg = 0x111a8,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x111a8,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_ife_lite_ahb_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_slow_ahb_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_ife_lite_clk = {
+	.halt_reg = 0x11168,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x11168,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_ife_lite_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_ife_lite_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_ife_lite_cphy_rx_clk = {
+	.halt_reg = 0x111a4,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x111a4,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_ife_lite_cphy_rx_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_cphy_rx_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_ife_lite_csid_clk = {
+	.halt_reg = 0x11194,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x11194,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_ife_lite_csid_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_ife_lite_csid_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_ipe_nps_ahb_clk = {
+	.halt_reg = 0x101d4,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x101d4,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_ipe_nps_ahb_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_slow_ahb_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_ipe_nps_clk = {
+	.halt_reg = 0x101a8,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x101a8,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_ipe_nps_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_ipe_nps_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_ipe_nps_fast_ahb_clk = {
+	.halt_reg = 0x101d8,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x101d8,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_ipe_nps_fast_ahb_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_fast_ahb_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_ipe_pps_clk = {
+	.halt_reg = 0x101bc,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x101bc,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_ipe_pps_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_ipe_nps_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_ipe_pps_fast_ahb_clk = {
+	.halt_reg = 0x101dc,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x101dc,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_ipe_pps_fast_ahb_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_fast_ahb_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_jpeg_0_clk = {
+	.halt_reg = 0x111e8,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x111e8,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_jpeg_0_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_jpeg_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_jpeg_1_clk = {
+	.halt_reg = 0x111f8,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x111f8,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_jpeg_1_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_jpeg_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_ofe_ahb_clk = {
+	.halt_reg = 0x10118,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x10118,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_ofe_ahb_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_slow_ahb_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_ofe_anchor_clk = {
+	.halt_reg = 0x10148,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x10148,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_ofe_anchor_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_ofe_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_ofe_anchor_fast_ahb_clk = {
+	.halt_reg = 0x100f8,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x100f8,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_ofe_anchor_fast_ahb_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_fast_ahb_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_ofe_hdr_clk = {
+	.halt_reg = 0x1015c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1015c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_ofe_hdr_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_ofe_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_ofe_hdr_fast_ahb_clk = {
+	.halt_reg = 0x100fc,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x100fc,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_ofe_hdr_fast_ahb_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_fast_ahb_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_ofe_main_clk = {
+	.halt_reg = 0x10134,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x10134,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_ofe_main_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_ofe_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_ofe_main_fast_ahb_clk = {
+	.halt_reg = 0x100f4,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x100f4,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_ofe_main_fast_ahb_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_fast_ahb_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_qdss_debug_clk = {
+	.halt_reg = 0x11344,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x11344,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_qdss_debug_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_qdss_debug_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_qdss_debug_xo_clk = {
+	.halt_reg = 0x11348,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x11348,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_qdss_debug_xo_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_xo_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_tfe_0_bayer_clk = {
+	.halt_reg = 0x11044,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x11044,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_tfe_0_bayer_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_tfe_0_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_tfe_0_bayer_fast_ahb_clk = {
+	.halt_reg = 0x11064,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x11064,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_tfe_0_bayer_fast_ahb_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_fast_ahb_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_tfe_0_main_clk = {
+	.halt_reg = 0x11030,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x11030,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_tfe_0_main_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_tfe_0_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_tfe_0_main_fast_ahb_clk = {
+	.halt_reg = 0x11060,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x11060,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_tfe_0_main_fast_ahb_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_fast_ahb_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_tfe_1_bayer_clk = {
+	.halt_reg = 0x110c4,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x110c4,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_tfe_1_bayer_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_tfe_1_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_tfe_1_bayer_fast_ahb_clk = {
+	.halt_reg = 0x110e4,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x110e4,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_tfe_1_bayer_fast_ahb_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_fast_ahb_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_tfe_1_main_clk = {
+	.halt_reg = 0x110b0,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x110b0,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_tfe_1_main_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_tfe_1_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_tfe_1_main_fast_ahb_clk = {
+	.halt_reg = 0x110e0,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x110e0,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_tfe_1_main_fast_ahb_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_fast_ahb_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_tfe_2_bayer_clk = {
+	.halt_reg = 0x1112c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1112c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_tfe_2_bayer_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_tfe_2_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_tfe_2_bayer_fast_ahb_clk = {
+	.halt_reg = 0x1114c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1114c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_tfe_2_bayer_fast_ahb_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_fast_ahb_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_tfe_2_main_clk = {
+	.halt_reg = 0x11118,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x11118,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_tfe_2_main_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_tfe_2_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch cam_cc_tfe_2_main_fast_ahb_clk = {
+	.halt_reg = 0x11148,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x11148,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "cam_cc_tfe_2_main_fast_ahb_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&cam_cc_fast_ahb_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct gdsc cam_cc_titan_top_gdsc = {
+	.gdscr = 0x1134c,
+	.en_rest_wait_val = 0x2,
+	.en_few_wait_val = 0x2,
+	.clk_dis_wait_val = 0xf,
+	.pd = {
+		.name = "cam_cc_titan_top_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc cam_cc_ipe_0_gdsc = {
+	.gdscr = 0x1017c,
+	.en_rest_wait_val = 0x2,
+	.en_few_wait_val = 0x2,
+	.clk_dis_wait_val = 0xf,
+	.pd = {
+		.name = "cam_cc_ipe_0_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.parent = &cam_cc_titan_top_gdsc.pd,
+	.flags = HW_CTRL_TRIGGER | POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc cam_cc_ofe_gdsc = {
+	.gdscr = 0x100c8,
+	.en_rest_wait_val = 0x2,
+	.en_few_wait_val = 0x2,
+	.clk_dis_wait_val = 0xf,
+	.pd = {
+		.name = "cam_cc_ofe_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.parent = &cam_cc_titan_top_gdsc.pd,
+	.flags = HW_CTRL_TRIGGER | POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc cam_cc_tfe_0_gdsc = {
+	.gdscr = 0x11004,
+	.en_rest_wait_val = 0x2,
+	.en_few_wait_val = 0x2,
+	.clk_dis_wait_val = 0xf,
+	.pd = {
+		.name = "cam_cc_tfe_0_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.parent = &cam_cc_titan_top_gdsc.pd,
+	.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc cam_cc_tfe_1_gdsc = {
+	.gdscr = 0x11084,
+	.en_rest_wait_val = 0x2,
+	.en_few_wait_val = 0x2,
+	.clk_dis_wait_val = 0xf,
+	.pd = {
+		.name = "cam_cc_tfe_1_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.parent = &cam_cc_titan_top_gdsc.pd,
+	.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc cam_cc_tfe_2_gdsc = {
+	.gdscr = 0x110ec,
+	.en_rest_wait_val = 0x2,
+	.en_few_wait_val = 0x2,
+	.clk_dis_wait_val = 0xf,
+	.pd = {
+		.name = "cam_cc_tfe_2_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.parent = &cam_cc_titan_top_gdsc.pd,
+	.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct clk_regmap *cam_cc_sm8750_clocks[] = {
+	[CAM_CC_CAM_TOP_AHB_CLK] = &cam_cc_cam_top_ahb_clk.clkr,
+	[CAM_CC_CAM_TOP_FAST_AHB_CLK] = &cam_cc_cam_top_fast_ahb_clk.clkr,
+	[CAM_CC_CAMNOC_DCD_XO_CLK] = &cam_cc_camnoc_dcd_xo_clk.clkr,
+	[CAM_CC_CAMNOC_NRT_AXI_CLK] = &cam_cc_camnoc_nrt_axi_clk.clkr,
+	[CAM_CC_CAMNOC_NRT_CRE_CLK] = &cam_cc_camnoc_nrt_cre_clk.clkr,
+	[CAM_CC_CAMNOC_NRT_IPE_NPS_CLK] = &cam_cc_camnoc_nrt_ipe_nps_clk.clkr,
+	[CAM_CC_CAMNOC_NRT_OFE_ANCHOR_CLK] = &cam_cc_camnoc_nrt_ofe_anchor_clk.clkr,
+	[CAM_CC_CAMNOC_NRT_OFE_HDR_CLK] = &cam_cc_camnoc_nrt_ofe_hdr_clk.clkr,
+	[CAM_CC_CAMNOC_NRT_OFE_MAIN_CLK] = &cam_cc_camnoc_nrt_ofe_main_clk.clkr,
+	[CAM_CC_CAMNOC_RT_AXI_CLK] = &cam_cc_camnoc_rt_axi_clk.clkr,
+	[CAM_CC_CAMNOC_RT_AXI_CLK_SRC] = &cam_cc_camnoc_rt_axi_clk_src.clkr,
+	[CAM_CC_CAMNOC_RT_IFE_LITE_CLK] = &cam_cc_camnoc_rt_ife_lite_clk.clkr,
+	[CAM_CC_CAMNOC_RT_TFE_0_BAYER_CLK] = &cam_cc_camnoc_rt_tfe_0_bayer_clk.clkr,
+	[CAM_CC_CAMNOC_RT_TFE_0_MAIN_CLK] = &cam_cc_camnoc_rt_tfe_0_main_clk.clkr,
+	[CAM_CC_CAMNOC_RT_TFE_1_BAYER_CLK] = &cam_cc_camnoc_rt_tfe_1_bayer_clk.clkr,
+	[CAM_CC_CAMNOC_RT_TFE_1_MAIN_CLK] = &cam_cc_camnoc_rt_tfe_1_main_clk.clkr,
+	[CAM_CC_CAMNOC_RT_TFE_2_BAYER_CLK] = &cam_cc_camnoc_rt_tfe_2_bayer_clk.clkr,
+	[CAM_CC_CAMNOC_RT_TFE_2_MAIN_CLK] = &cam_cc_camnoc_rt_tfe_2_main_clk.clkr,
+	[CAM_CC_CAMNOC_XO_CLK] = &cam_cc_camnoc_xo_clk.clkr,
+	[CAM_CC_CCI_0_CLK] = &cam_cc_cci_0_clk.clkr,
+	[CAM_CC_CCI_0_CLK_SRC] = &cam_cc_cci_0_clk_src.clkr,
+	[CAM_CC_CCI_1_CLK] = &cam_cc_cci_1_clk.clkr,
+	[CAM_CC_CCI_1_CLK_SRC] = &cam_cc_cci_1_clk_src.clkr,
+	[CAM_CC_CCI_2_CLK] = &cam_cc_cci_2_clk.clkr,
+	[CAM_CC_CCI_2_CLK_SRC] = &cam_cc_cci_2_clk_src.clkr,
+	[CAM_CC_CORE_AHB_CLK] = &cam_cc_core_ahb_clk.clkr,
+	[CAM_CC_CPHY_RX_CLK_SRC] = &cam_cc_cphy_rx_clk_src.clkr,
+	[CAM_CC_CRE_AHB_CLK] = &cam_cc_cre_ahb_clk.clkr,
+	[CAM_CC_CRE_CLK] = &cam_cc_cre_clk.clkr,
+	[CAM_CC_CRE_CLK_SRC] = &cam_cc_cre_clk_src.clkr,
+	[CAM_CC_CSI0PHYTIMER_CLK] = &cam_cc_csi0phytimer_clk.clkr,
+	[CAM_CC_CSI0PHYTIMER_CLK_SRC] = &cam_cc_csi0phytimer_clk_src.clkr,
+	[CAM_CC_CSI1PHYTIMER_CLK] = &cam_cc_csi1phytimer_clk.clkr,
+	[CAM_CC_CSI1PHYTIMER_CLK_SRC] = &cam_cc_csi1phytimer_clk_src.clkr,
+	[CAM_CC_CSI2PHYTIMER_CLK] = &cam_cc_csi2phytimer_clk.clkr,
+	[CAM_CC_CSI2PHYTIMER_CLK_SRC] = &cam_cc_csi2phytimer_clk_src.clkr,
+	[CAM_CC_CSI3PHYTIMER_CLK] = &cam_cc_csi3phytimer_clk.clkr,
+	[CAM_CC_CSI3PHYTIMER_CLK_SRC] = &cam_cc_csi3phytimer_clk_src.clkr,
+	[CAM_CC_CSI4PHYTIMER_CLK] = &cam_cc_csi4phytimer_clk.clkr,
+	[CAM_CC_CSI4PHYTIMER_CLK_SRC] = &cam_cc_csi4phytimer_clk_src.clkr,
+	[CAM_CC_CSI5PHYTIMER_CLK] = &cam_cc_csi5phytimer_clk.clkr,
+	[CAM_CC_CSI5PHYTIMER_CLK_SRC] = &cam_cc_csi5phytimer_clk_src.clkr,
+	[CAM_CC_CSID_CLK] = &cam_cc_csid_clk.clkr,
+	[CAM_CC_CSID_CLK_SRC] = &cam_cc_csid_clk_src.clkr,
+	[CAM_CC_CSID_CSIPHY_RX_CLK] = &cam_cc_csid_csiphy_rx_clk.clkr,
+	[CAM_CC_CSIPHY0_CLK] = &cam_cc_csiphy0_clk.clkr,
+	[CAM_CC_CSIPHY1_CLK] = &cam_cc_csiphy1_clk.clkr,
+	[CAM_CC_CSIPHY2_CLK] = &cam_cc_csiphy2_clk.clkr,
+	[CAM_CC_CSIPHY3_CLK] = &cam_cc_csiphy3_clk.clkr,
+	[CAM_CC_CSIPHY4_CLK] = &cam_cc_csiphy4_clk.clkr,
+	[CAM_CC_CSIPHY5_CLK] = &cam_cc_csiphy5_clk.clkr,
+	[CAM_CC_FAST_AHB_CLK_SRC] = &cam_cc_fast_ahb_clk_src.clkr,
+	[CAM_CC_ICP_0_AHB_CLK] = &cam_cc_icp_0_ahb_clk.clkr,
+	[CAM_CC_ICP_0_CLK] = &cam_cc_icp_0_clk.clkr,
+	[CAM_CC_ICP_0_CLK_SRC] = &cam_cc_icp_0_clk_src.clkr,
+	[CAM_CC_ICP_1_AHB_CLK] = &cam_cc_icp_1_ahb_clk.clkr,
+	[CAM_CC_ICP_1_CLK] = &cam_cc_icp_1_clk.clkr,
+	[CAM_CC_ICP_1_CLK_SRC] = &cam_cc_icp_1_clk_src.clkr,
+	[CAM_CC_IFE_LITE_AHB_CLK] = &cam_cc_ife_lite_ahb_clk.clkr,
+	[CAM_CC_IFE_LITE_CLK] = &cam_cc_ife_lite_clk.clkr,
+	[CAM_CC_IFE_LITE_CLK_SRC] = &cam_cc_ife_lite_clk_src.clkr,
+	[CAM_CC_IFE_LITE_CPHY_RX_CLK] = &cam_cc_ife_lite_cphy_rx_clk.clkr,
+	[CAM_CC_IFE_LITE_CSID_CLK] = &cam_cc_ife_lite_csid_clk.clkr,
+	[CAM_CC_IFE_LITE_CSID_CLK_SRC] = &cam_cc_ife_lite_csid_clk_src.clkr,
+	[CAM_CC_IPE_NPS_AHB_CLK] = &cam_cc_ipe_nps_ahb_clk.clkr,
+	[CAM_CC_IPE_NPS_CLK] = &cam_cc_ipe_nps_clk.clkr,
+	[CAM_CC_IPE_NPS_CLK_SRC] = &cam_cc_ipe_nps_clk_src.clkr,
+	[CAM_CC_IPE_NPS_FAST_AHB_CLK] = &cam_cc_ipe_nps_fast_ahb_clk.clkr,
+	[CAM_CC_IPE_PPS_CLK] = &cam_cc_ipe_pps_clk.clkr,
+	[CAM_CC_IPE_PPS_FAST_AHB_CLK] = &cam_cc_ipe_pps_fast_ahb_clk.clkr,
+	[CAM_CC_JPEG_0_CLK] = &cam_cc_jpeg_0_clk.clkr,
+	[CAM_CC_JPEG_1_CLK] = &cam_cc_jpeg_1_clk.clkr,
+	[CAM_CC_JPEG_CLK_SRC] = &cam_cc_jpeg_clk_src.clkr,
+	[CAM_CC_OFE_AHB_CLK] = &cam_cc_ofe_ahb_clk.clkr,
+	[CAM_CC_OFE_ANCHOR_CLK] = &cam_cc_ofe_anchor_clk.clkr,
+	[CAM_CC_OFE_ANCHOR_FAST_AHB_CLK] = &cam_cc_ofe_anchor_fast_ahb_clk.clkr,
+	[CAM_CC_OFE_CLK_SRC] = &cam_cc_ofe_clk_src.clkr,
+	[CAM_CC_OFE_HDR_CLK] = &cam_cc_ofe_hdr_clk.clkr,
+	[CAM_CC_OFE_HDR_FAST_AHB_CLK] = &cam_cc_ofe_hdr_fast_ahb_clk.clkr,
+	[CAM_CC_OFE_MAIN_CLK] = &cam_cc_ofe_main_clk.clkr,
+	[CAM_CC_OFE_MAIN_FAST_AHB_CLK] = &cam_cc_ofe_main_fast_ahb_clk.clkr,
+	[CAM_CC_PLL0] = &cam_cc_pll0.clkr,
+	[CAM_CC_PLL0_OUT_EVEN] = &cam_cc_pll0_out_even.clkr,
+	[CAM_CC_PLL0_OUT_ODD] = &cam_cc_pll0_out_odd.clkr,
+	[CAM_CC_PLL1] = &cam_cc_pll1.clkr,
+	[CAM_CC_PLL1_OUT_EVEN] = &cam_cc_pll1_out_even.clkr,
+	[CAM_CC_PLL2] = &cam_cc_pll2.clkr,
+	[CAM_CC_PLL2_OUT_EVEN] = &cam_cc_pll2_out_even.clkr,
+	[CAM_CC_PLL3] = &cam_cc_pll3.clkr,
+	[CAM_CC_PLL3_OUT_EVEN] = &cam_cc_pll3_out_even.clkr,
+	[CAM_CC_PLL4] = &cam_cc_pll4.clkr,
+	[CAM_CC_PLL4_OUT_EVEN] = &cam_cc_pll4_out_even.clkr,
+	[CAM_CC_PLL5] = &cam_cc_pll5.clkr,
+	[CAM_CC_PLL5_OUT_EVEN] = &cam_cc_pll5_out_even.clkr,
+	[CAM_CC_PLL6] = &cam_cc_pll6.clkr,
+	[CAM_CC_PLL6_OUT_EVEN] = &cam_cc_pll6_out_even.clkr,
+	[CAM_CC_PLL6_OUT_ODD] = &cam_cc_pll6_out_odd.clkr,
+	[CAM_CC_QDSS_DEBUG_CLK] = &cam_cc_qdss_debug_clk.clkr,
+	[CAM_CC_QDSS_DEBUG_CLK_SRC] = &cam_cc_qdss_debug_clk_src.clkr,
+	[CAM_CC_QDSS_DEBUG_XO_CLK] = &cam_cc_qdss_debug_xo_clk.clkr,
+	[CAM_CC_SLEEP_CLK_SRC] = &cam_cc_sleep_clk_src.clkr,
+	[CAM_CC_SLOW_AHB_CLK_SRC] = &cam_cc_slow_ahb_clk_src.clkr,
+	[CAM_CC_TFE_0_BAYER_CLK] = &cam_cc_tfe_0_bayer_clk.clkr,
+	[CAM_CC_TFE_0_BAYER_FAST_AHB_CLK] = &cam_cc_tfe_0_bayer_fast_ahb_clk.clkr,
+	[CAM_CC_TFE_0_CLK_SRC] = &cam_cc_tfe_0_clk_src.clkr,
+	[CAM_CC_TFE_0_MAIN_CLK] = &cam_cc_tfe_0_main_clk.clkr,
+	[CAM_CC_TFE_0_MAIN_FAST_AHB_CLK] = &cam_cc_tfe_0_main_fast_ahb_clk.clkr,
+	[CAM_CC_TFE_1_BAYER_CLK] = &cam_cc_tfe_1_bayer_clk.clkr,
+	[CAM_CC_TFE_1_BAYER_FAST_AHB_CLK] = &cam_cc_tfe_1_bayer_fast_ahb_clk.clkr,
+	[CAM_CC_TFE_1_CLK_SRC] = &cam_cc_tfe_1_clk_src.clkr,
+	[CAM_CC_TFE_1_MAIN_CLK] = &cam_cc_tfe_1_main_clk.clkr,
+	[CAM_CC_TFE_1_MAIN_FAST_AHB_CLK] = &cam_cc_tfe_1_main_fast_ahb_clk.clkr,
+	[CAM_CC_TFE_2_BAYER_CLK] = &cam_cc_tfe_2_bayer_clk.clkr,
+	[CAM_CC_TFE_2_BAYER_FAST_AHB_CLK] = &cam_cc_tfe_2_bayer_fast_ahb_clk.clkr,
+	[CAM_CC_TFE_2_CLK_SRC] = &cam_cc_tfe_2_clk_src.clkr,
+	[CAM_CC_TFE_2_MAIN_CLK] = &cam_cc_tfe_2_main_clk.clkr,
+	[CAM_CC_TFE_2_MAIN_FAST_AHB_CLK] = &cam_cc_tfe_2_main_fast_ahb_clk.clkr,
+	[CAM_CC_XO_CLK_SRC] = &cam_cc_xo_clk_src.clkr,
+};
+
+static struct gdsc *cam_cc_sm8750_gdscs[] = {
+	[CAM_CC_TITAN_TOP_GDSC] = &cam_cc_titan_top_gdsc,
+	[CAM_CC_IPE_0_GDSC] = &cam_cc_ipe_0_gdsc,
+	[CAM_CC_OFE_GDSC] = &cam_cc_ofe_gdsc,
+	[CAM_CC_TFE_0_GDSC] = &cam_cc_tfe_0_gdsc,
+	[CAM_CC_TFE_1_GDSC] = &cam_cc_tfe_1_gdsc,
+	[CAM_CC_TFE_2_GDSC] = &cam_cc_tfe_2_gdsc,
+};
+
+static const struct qcom_reset_map cam_cc_sm8750_resets[] = {
+	[CAM_CC_DRV_BCR] = { 0x113bc },
+	[CAM_CC_ICP_BCR] = { 0x11210 },
+	[CAM_CC_IPE_0_BCR] = { 0x10178 },
+	[CAM_CC_OFE_BCR] = { 0x100c4 },
+	[CAM_CC_QDSS_DEBUG_BCR] = { 0x11328 },
+	[CAM_CC_TFE_0_BCR] = { 0x11000 },
+	[CAM_CC_TFE_1_BCR] = { 0x11080 },
+	[CAM_CC_TFE_2_BCR] = { 0x110e8 },
+};
+
+static struct clk_alpha_pll *cam_cc_sm8750_plls[] = {
+	&cam_cc_pll0,
+	&cam_cc_pll1,
+	&cam_cc_pll2,
+	&cam_cc_pll3,
+	&cam_cc_pll4,
+	&cam_cc_pll5,
+	&cam_cc_pll6,
+};
+
+static u32 cam_cc_sm8750_critical_cbcrs[] = {
+	0x113c4, /* CAM_CC_DRV_AHB_CLK */
+	0x113c0, /* CAM_CC_DRV_XO_CLK */
+	0x1137c, /* CAM_CC_GDSC_CLK */
+	0x11398, /* CAM_CC_SLEEP_CLK */
+};
+
+static const struct regmap_config cam_cc_sm8750_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = 0x1601c,
+	.fast_io = true,
+};
+
+static struct qcom_cc_driver_data cam_cc_sm8750_driver_data = {
+	.alpha_plls = cam_cc_sm8750_plls,
+	.num_alpha_plls = ARRAY_SIZE(cam_cc_sm8750_plls),
+	.clk_cbcrs = cam_cc_sm8750_critical_cbcrs,
+	.num_clk_cbcrs = ARRAY_SIZE(cam_cc_sm8750_critical_cbcrs),
+};
+
+static struct qcom_cc_desc cam_cc_sm8750_desc = {
+	.config = &cam_cc_sm8750_regmap_config,
+	.clks = cam_cc_sm8750_clocks,
+	.num_clks = ARRAY_SIZE(cam_cc_sm8750_clocks),
+	.resets = cam_cc_sm8750_resets,
+	.num_resets = ARRAY_SIZE(cam_cc_sm8750_resets),
+	.gdscs = cam_cc_sm8750_gdscs,
+	.num_gdscs = ARRAY_SIZE(cam_cc_sm8750_gdscs),
+	.use_rpm = true,
+	.driver_data = &cam_cc_sm8750_driver_data,
+};
+
+static const struct of_device_id cam_cc_sm8750_match_table[] = {
+	{ .compatible = "qcom,sm8750-camcc" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, cam_cc_sm8750_match_table);
+
+static int cam_cc_sm8750_probe(struct platform_device *pdev)
+{
+	return qcom_cc_probe(pdev, &cam_cc_sm8750_desc);
+}
+
+static struct platform_driver cam_cc_sm8750_driver = {
+	.probe = cam_cc_sm8750_probe,
+	.driver = {
+		.name = "camcc-sm8750",
+		.of_match_table = cam_cc_sm8750_match_table,
+	},
+};
+
+module_platform_driver(cam_cc_sm8750_driver);
+
+MODULE_DESCRIPTION("QTI CAMCC SM8750 Driver");
+MODULE_LICENSE("GPL");

-- 
2.34.1



From wenst at chromium.org  Tue Dec  2 02:28:42 2025
From: wenst at chromium.org (Chen-Yu Tsai)
Date: Tue, 2 Dec 2025 18:28:42 +0800
Subject: [PATCH v6 1/8] scripts/make_fit: Speed up operation
In-Reply-To: <20251119181333.991099-2-sjg@chromium.org>
References: <20251119181333.991099-1-sjg@chromium.org> <20251119181333.991099-2-sjg@chromium.org>
Message-ID: <CAGXv+5Fm_jx=shhtfWAjrD_iaRtWQGa9bGdRR_ajXHLrWJg4QA@mail.gmail.com>

On Thu, Nov 20, 2025 at 2:14?AM Simon Glass <sjg at chromium.org> wrote:
>
> The kernel is likely at least 16MB so we may as well use that as a step
> size when reallocating space for the FIT in memory. Pack the FIT at the
> end, so there is no wasted space.
>
> This reduces the time to pack by an order of magnitude, or so.

In my case the time spent compressing the blobs seems to be much
larger than the packing portion, so I couldn't really tell if
this made a difference or not.

Despite that,

> Signed-off-by: Simon Glass <sjg at chromium.org>
> Reviewed-by: Nicolas Schier <nsc at kernel.org>

Tested-by: Chen-Yu Tsai <wenst at chromium.org>


From krzk at kernel.org  Tue Dec  2 02:28:55 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 2 Dec 2025 11:28:55 +0100
Subject: [PATCH 05/21] ARM: dts: omap: Bind panel to panel-dpi instead of
 ti,tilcdc,panel driver
In-Reply-To: <20251202104244.59a9e83d@kmaincent-XPS-13-7390>
References: <20251126-feature_tilcdc-v1-0-49b9ef2e3aa0@bootlin.com>
 <20251126-feature_tilcdc-v1-5-49b9ef2e3aa0@bootlin.com>
 <96b1b7bf-ddbe-4213-a201-dc89cf2998dd@ideasonboard.com>
 <3bc5bf92-05c3-4841-ab28-9bab2bb31cd5@kernel.org>
 <20251202104244.59a9e83d@kmaincent-XPS-13-7390>
Message-ID: <d7515cd3-5488-4d15-82dc-d2b98cfa2bed@kernel.org>

On 02/12/2025 10:42, Kory Maincent wrote:
>  
>> Stuffing DTS change in the middle of the driver change tries to hide
>> impact, which is not nice on its own.
> 
> As it needs driver change before the removal for not breaking things it can't
> be done at the beginning of the series.

And that is the problem which should stop you there and rethink how to
organize it without impacting users. DTS cannot go via DRM. If that was
your intention, that's my:

NAK

Best regards,
Krzysztof


From thomas.weissschuh at linutronix.de  Tue Dec  2 02:31:51 2025
From: thomas.weissschuh at linutronix.de (Thomas =?utf-8?Q?Wei=C3=9Fschuh?=)
Date: Tue, 2 Dec 2025 11:31:51 +0100
Subject: [PATCH v6 6/8] kbuild: Allow adding modules into the FIT ramdisk
In-Reply-To: <28e18785-1336-4fbc-9f2b-69aa6bb06375@pengutronix.de>
References: <20251119181333.991099-1-sjg@chromium.org>
 <20251119181333.991099-7-sjg@chromium.org>
 <20251120084201-53a3c98f-6a3c-4116-8635-be67d58fd57b@linutronix.de>
 <CAFLszTjsgkPV_-Si79RY5T_Fxd5+f-b1VbpG11uS3E9Lk4Ofmg@mail.gmail.com>
 <20251126080620-921e6880-cacf-44c5-bd8b-f380fbb8090a@linutronix.de>
 <28e18785-1336-4fbc-9f2b-69aa6bb06375@pengutronix.de>
Message-ID: <20251202112039-b03af7ec-ae06-41ab-914b-703940cc98a2@linutronix.de>

On Wed, Nov 26, 2025 at 12:26:49PM +0100, Ahmad Fatoum wrote:
> On 11/26/25 8:16 AM, Thomas Wei?schuh wrote:
> > On Tue, Nov 25, 2025 at 02:58:12PM -0700, Simon Glass wrote:
> >> On Thu, 20 Nov 2025 at 00:49, Thomas Wei?schuh
> >> <thomas.weissschuh at linutronix.de> wrote:
> >>>
> >>> On Wed, Nov 19, 2025 at 11:13:27AM -0700, Simon Glass wrote:
> > 
> > (...)
> > 
> >>>>  quiet_cmd_fit = FIT     $@
> >>>>        cmd_fit = $(MAKE_FIT) -o $@ --arch $(UIMAGE_ARCH) --os linux \
> >>>> -             --name '$(UIMAGE_NAME)' \
> >>>> +             --name '$(UIMAGE_NAME)' $(MAKE_FIT_FLAGS) \
> >>>
> >>> Remnant of a previous revision?
> >>
> >> The flags are there to allow extra options to be passed if needed.
> > 
> > Are they necessary for the module functionality added here?
> > If not I'd put them into a dedicated commit.
> > 
> >>>
> >>>>               $(if $(findstring 1,$(KBUILD_VERBOSE)),-v) \
> >>>>               $(if $(FIT_DECOMPOSE_DTBS),--decompose-dtbs) \
> >>>> +             $(if $(FIT_MODULES),--modules @$(objtree)/modules.order) \
> >>>
> >>> I am wondering how module dependencies work without the depmod invocation
> >>> and modules.dep file.
> >>
> >> We have a mechanism to place a pre-build initrd with the filesystem,
> >> etc. into the FIT. But for this particular feature (suggested by Ahmad
> >> Fatoum) we are just providing the raw modules. Presumably another
> >> initrd would be needed to provide the startup files?
> > 
> > modules.dep is more than optional and generic startup files but an integral
> > part of a module tree. Without it, any module depending on another module's
> > symbols will fail to load. Also the modules will be unsigned, potentially
> > making them unloadable.
> 
> I'll use the occasion to elaborate a bit on why I thought adding modules
> is a good idea.
> 
> - You have a system boot from FIT and maybe even a r/o rootfs
> - You want to boot a different kernel without any userspace changes,
> e.g. to bisect
> - Fortunately, you have a build target that generates you a FIT with
> kernel, enabled device trees and all modules (including deps and such)
> - In the bootloader[1], you specify that a CPIO with a minimal init[2]
> that bindmounts /lib/modules in the initramfs over the rootfs modules
> before pivot_root
> 
> and that's it, you are running your new kernel with the old rootfs
> unchanged. I believe this would be really handy, which is why I
> suggested it.

The idea sounds good.

> > Ahmad's patch does produce a complete and fully
> > functional module tree by means of 'make headers_install'.
> 
> I originally thought that we could generate the CPIO normally as part of
> the kernel build and then we can readily depend on it in the rule that
> invokes make_fit.py.

That works, but it is not what the patch under discussion does, or did.

> If this proves to be too cumbersome, I think it's already an improvement
> if the user can manually run make modules-cpio-pkg and then make
> image.fit with the initrd specified. A single target would be neater of
> course, but I didn't intend for this to stall the series.

The single target idea would require 'modules-cpio-pkg' to not be a PHONY
target anymore but to properly track dependencies. Otherwise the CPIO and FIT
image will be rebuilt even if no sources change. Proper dependencies are always
better than PHONY targets, but it will be a bit of additional work.

> It can always follow later.

Yep. But for the patch as it is proposed I am still wondering how it will work
without modules.dep and friends.

(...)


From pmladek at suse.com  Tue Dec  2 02:34:15 2025
From: pmladek at suse.com (Petr Mladek)
Date: Tue, 2 Dec 2025 11:34:15 +0100
Subject: CSD lockup during kexec due to unbounded busy-wait in
 pl011_console_write_atomic (arm64)
In-Reply-To: <87bjkificj.fsf@jogness.linutronix.de>
References: <sqwajvt7utnt463tzxgwu2yctyn5m6bjwrslsnupfexeml6hkd@v6sqmpbu3vvu>
 <aSnI8UQRNICSKxAb@pathway.suse.cz>
 <87ecpefjee.fsf@jogness.linutronix.de>
 <87bjkificj.fsf@jogness.linutronix.de>
Message-ID: <aS7ApzJG8RPhtKh5@pathway.suse.cz>

On Mon 2025-12-01 14:27:32, John Ogness wrote:
> On 2025-12-01, John Ogness <john.ogness at linutronix.de> wrote:
> >> diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
> >> index 3fa403f9831f..6b8becb6ecd9 100644
> >> --- a/kernel/printk/nbcon.c
> >> +++ b/kernel/printk/nbcon.c
> >> @@ -1549,6 +1549,7 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
> >>  {
> >>  	struct nbcon_write_context wctxt = { };
> >>  	struct nbcon_context *ctxt = &ACCESS_PRIVATE(&wctxt, ctxt);
> >> +	unsigned long flags;
> >>  	int err = 0;
> >>  
> >>  	ctxt->console			= con;
> >> @@ -1557,18 +1558,31 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
> >>  	ctxt->allow_unsafe_takeover	= nbcon_allow_unsafe_takeover();
> >>  
> >>  	while (nbcon_seq_read(con) < stop_seq) {
> >> -		if (!nbcon_context_try_acquire(ctxt, false))
> >> +		/*
> >> +		 * Atomic flushing does not use console driver synchronization
> >> +		 * (i.e. it does not hold the port lock for uart consoles).
> >> +		 * Therefore IRQs must be disabled to avoid being interrupted
> >> +		 * and then calling into a driver that will deadlock trying
> >> +		 * to acquire console ownership.
> >> +		 */
> >> +		local_irq_save(flags);
> >> +		if (!nbcon_context_try_acquire(ctxt, false)) {
> >> +			local_irq_restore(flags);
> >>  			return -EPERM;
> >> +		}
> >>  
> >>  		/*
> >>  		 * nbcon_emit_next_record() returns false when the console was
> >>  		 * handed over or taken over. In both cases the context is no
> >>  		 * longer valid.
> >>  		 */
> >> -		if (!nbcon_emit_next_record(&wctxt, true))
> >> +		if (!nbcon_emit_next_record(&wctxt, true)) {
> >> +			local_irq_restore(flags);
> >>  			return -EAGAIN;
> >> +		}
> >>  
> >>  		nbcon_context_release(ctxt);
> >> +		local_irq_restore(flags);
> >
> > Using local_irq_save()/_restore() here is not acceptable for PREEMPT_RT
> > because __nbcon_atomic_flush_pending_con() is also used by
> > nbcon_device_release().

Great catch! I did not think about this code path.

> After thinking about this more, this would be acceptable. If
> printk_get_console_flush_type() is reporting nbcon_atomic==true, then
> the system is in a state where latencies are irrelevant.

I agree. It might be possible to create a special variant for
the nbcon_device_release() code path. But it probably is not
worth it.

I am going to mention this in the commit message and send
it as proper patch.

Thanks a lot for review and feedback.

Best Regards,
Petr


From james.clark at linaro.org  Tue Dec  2 02:40:49 2025
From: james.clark at linaro.org (James Clark)
Date: Tue, 2 Dec 2025 10:40:49 +0000
Subject: [PATCH 1/7] perf tools: Track all user changed config bits
In-Reply-To: <20251202101556.GR724103@e132581.arm.com>
References: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
 <20251201-james-perf-config-bits-v1-1-22ecbbf8007c@linaro.org>
 <20251202101556.GR724103@e132581.arm.com>
Message-ID: <978dd9b1-1cb0-4338-95fa-575a858cea80@linaro.org>



On 02/12/2025 10:15 am, Leo Yan wrote:
> On Mon, Dec 01, 2025 at 04:41:04PM +0000, Coresight ML wrote:
> 
> [...]
> 
>> +#define ADD_CONFIG_CHG(format_type, term_type, new_term)		\
>> +{									\
>> +	struct parse_events_term *term;					\
>> +	u64 bits = 0;							\
>> +	int type;							\
>> +									\
>> +	list_for_each_entry(term, &head_config->terms, list) {		\
>> +		if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER) {  \
>> +			type = perf_pmu__format_type(pmu, term->config);\
>> +			if (type != format_type)			\
>> +				continue;				\
>> +			bits |= perf_pmu__format_bits(pmu, term->config); \
>> +		} else if (term->type_term == term_type) {		\
>> +			bits = ~(u64)0;					\
>> +		}							\
>> +	}								\
>> +									\
>> +	if (bits)							\
>> +		ADD_CONFIG_TERM_VAL(new_term, cfg_chg, bits, false);	\
>> +	return 0;							\
> 
> Nitpick: "return 0" is not needed here.  Otherwise:
> 
> Reviewed-by: Leo Yan <leo.yan at arm.com>

I think it's worse than not needed, it makes it stop collecting the 
changes after the first one.

It was annoying that this had to be a macro instead of a function 
because ADD_CONFIG_TERM_VAL constructs the #define name of the first 
argument.

It's probably worth putting in some effort to make ADD_CONFIG_CHG() a 
function to avoid problems like this and maybe add a test.



From quentin.schulz at cherry.de  Tue Dec  2 02:41:43 2025
From: quentin.schulz at cherry.de (Quentin Schulz)
Date: Tue, 2 Dec 2025 11:41:43 +0100
Subject: [PATCH v2 8/9] arm64: dts: rockchip: Enable HDMI output on
 RK3368-Lion-Haikou
In-Reply-To: <20251021074254.87065-9-heiko@sntech.de>
References: <20251021074254.87065-1-heiko@sntech.de>
 <20251021074254.87065-9-heiko@sntech.de>
Message-ID: <50d9a41c-d35b-4489-af1e-a5f7eef303f1@cherry.de>

Hi Heiko,

On 10/21/25 9:42 AM, Heiko Stuebner wrote:
> From: Heiko Stuebner <heiko.stuebner at cherry.de>
> 
> Enable the VOP and HDMI controller on the Lion-Haikou board.
> 
> Signed-off-by: Heiko Stuebner <heiko.stuebner at cherry.de>
> ---
>   .../boot/dts/rockchip/rk3368-lion-haikou.dts   | 18 ++++++++++++++++++
>   1 file changed, 18 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts b/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts
> index abd1af97456a..a8eb4e9c2778 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts
> +++ b/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts
> @@ -58,6 +58,16 @@ vcc5v0_otg: regulator-vcc5v0-otg {
>   	};
>   };
>   
> +&display_subsystem {
> +	status = "okay";
> +};
> +
> +&hdmi {
> +	avdd-0v9-supply = <&vdd10_video>;
> +	avdd-1v8-supply = <&vcc18_video>;

After a long night of sleep, I believe this should be specified in 
rk3368-lion.dtsi SoM DTSI and not in rk3368-lion-haikou.dts as it's 
SoM-specific.

Cheers,
Quentin


From kory.maincent at bootlin.com  Tue Dec  2 02:44:16 2025
From: kory.maincent at bootlin.com (Kory Maincent)
Date: Tue, 2 Dec 2025 11:44:16 +0100
Subject: [PATCH 05/21] ARM: dts: omap: Bind panel to panel-dpi instead
 of ti,tilcdc,panel driver
In-Reply-To: <d7515cd3-5488-4d15-82dc-d2b98cfa2bed@kernel.org>
References: <20251126-feature_tilcdc-v1-0-49b9ef2e3aa0@bootlin.com>
	<20251126-feature_tilcdc-v1-5-49b9ef2e3aa0@bootlin.com>
	<96b1b7bf-ddbe-4213-a201-dc89cf2998dd@ideasonboard.com>
	<3bc5bf92-05c3-4841-ab28-9bab2bb31cd5@kernel.org>
	<20251202104244.59a9e83d@kmaincent-XPS-13-7390>
	<d7515cd3-5488-4d15-82dc-d2b98cfa2bed@kernel.org>
Message-ID: <20251202114416.09624a4b@kmaincent-XPS-13-7390>

On Tue, 2 Dec 2025 11:28:55 +0100
Krzysztof Kozlowski <krzk at kernel.org> wrote:

> On 02/12/2025 10:42, Kory Maincent wrote:
> >    
> >> Stuffing DTS change in the middle of the driver change tries to hide
> >> impact, which is not nice on its own.  
> > 
> > As it needs driver change before the removal for not breaking things it
> > can't be done at the beginning of the series.  
> 
> And that is the problem which should stop you there and rethink how to
> organize it without impacting users. DTS cannot go via DRM. If that was
> your intention, that's my:
> 
> NAK

My intention was to raise discussion over the ugly and legacy tilcdc-panel
binding and what to do with it. But it seems you don't want to, that's a shame.

Regards,
-- 
K?ry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com


From krzk at kernel.org  Tue Dec  2 02:47:40 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 2 Dec 2025 11:47:40 +0100
Subject: [PATCH 05/21] ARM: dts: omap: Bind panel to panel-dpi instead of
 ti,tilcdc,panel driver
In-Reply-To: <20251202114416.09624a4b@kmaincent-XPS-13-7390>
References: <20251126-feature_tilcdc-v1-0-49b9ef2e3aa0@bootlin.com>
 <20251126-feature_tilcdc-v1-5-49b9ef2e3aa0@bootlin.com>
 <96b1b7bf-ddbe-4213-a201-dc89cf2998dd@ideasonboard.com>
 <3bc5bf92-05c3-4841-ab28-9bab2bb31cd5@kernel.org>
 <20251202104244.59a9e83d@kmaincent-XPS-13-7390>
 <d7515cd3-5488-4d15-82dc-d2b98cfa2bed@kernel.org>
 <20251202114416.09624a4b@kmaincent-XPS-13-7390>
Message-ID: <94e254fa-289d-41ed-909f-1742cfbb2690@kernel.org>

On 02/12/2025 11:44, Kory Maincent wrote:
> On Tue, 2 Dec 2025 11:28:55 +0100
> Krzysztof Kozlowski <krzk at kernel.org> wrote:
> 
>> On 02/12/2025 10:42, Kory Maincent wrote:
>>>    
>>>> Stuffing DTS change in the middle of the driver change tries to hide
>>>> impact, which is not nice on its own.  
>>>
>>> As it needs driver change before the removal for not breaking things it
>>> can't be done at the beginning of the series.  
>>
>> And that is the problem which should stop you there and rethink how to
>> organize it without impacting users. DTS cannot go via DRM. If that was
>> your intention, that's my:
>>
>> NAK
> 
> My intention was to raise discussion over the ugly and legacy tilcdc-panel
> binding and what to do with it. But it seems you don't want to, that's a shame.

I don't see how you get to these conclusions. I comment that putting
here DTS in the middle without any explanation of the impact is not
correct and this one alone I disagree with.

>From that you claim I don't want to fix things...

DTS cannot go to drm, which means you either need to separate the change
and make entire work bisectable and backwards compatible for some time
OR at least document clearly the impact as we always ask.

Best regards,
Krzysztof


From zhuling0805 at proton.me  Tue Dec  2 02:53:24 2025
From: zhuling0805 at proton.me (zhuling0805)
Date: Tue, 02 Dec 2025 10:53:24 +0000
Subject: [PATCH] irqchip/gic: Fix UBSAN shift-out-of-bounds in GIC helpers
Message-ID: <2fJDwUUYdEf2_eaRa041L9xkT8RkSWFeo7euOnqMbbPhUatLlEaAvGfB6sOspDmXaxO87Eh7bQLV9UolyjbMtZBT1wB2UGypjPOo0Z-RC0Q=@proton.me>

Hi,

When running a kernel built with UBSAN enabled, enabling a GPIO
controller that uses a GIC interrupt as its parent triggers several
shift-out-of-bounds warnings in the GIC helpers.

This patch fixes the issue by using unsigned constants so that the
left shifts are well-defined and UBSAN stays quiet.

Thanks,
Zhu Ling

---
From: Zhu Ling <zhuling0805 at proton.me>
Date: Tue, 2 Dec 2025 17:54:10 +0800
Subject: [PATCH] irqchip/gic: Fix UBSAN shift-out-of-bounds in GIC helpers

When running with UBSAN enabled, enabling a GPIO controller that uses
a GIC interrupt as its parent triggers several shift-out-of-bounds
warnings:

  UBSAN: shift-out-of-bounds in drivers/irqchip/irq-gic-common.c:50:21
  left shift of 2 by 30 places cannot be represented in type 'int'

and similar reports in gic_poke_irq() and gic_peek_irq() in
drivers/irqchip/irq-gic-v3.c.

These come from shifting signed integer constants. Use unsigned
constants (0x2U and 1U) so that the behavior is well-defined and the
UBSAN warnings go away.

Signed-off-by: Zhu Ling <zhuling0805 at proton.me>
---
 drivers/irqchip/irq-gic-common.c | 2 +-
 drivers/irqchip/irq-gic-v3.c     | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c
index c776f9142..d4f0afd9e 100644
--- a/drivers/irqchip/irq-gic-common.c
+++ b/drivers/irqchip/irq-gic-common.c
@@ -48,7 +48,7 @@ void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks,
 int gic_configure_irq(unsigned int irq, unsigned int type,
 		       void __iomem *base)
 {
-	u32 confmask = 0x2 << ((irq % 16) * 2);
+	u32 confmask = 0x2U << ((irq % 16) * 2);
 	u32 confoff = (irq / 16) * 4;
 	u32 val, oldval;
 	int ret = 0;
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 3de351e66..f5226c03f 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -457,7 +457,7 @@ static int gic_peek_irq(struct irq_data *d, u32 offset)
 	u32 index, mask;
 
 	offset = convert_offset_index(d, offset, &index);
-	mask = 1 << (index % 32);
+	mask = 1U << (index % 32);
 
 	if (gic_irq_in_rdist(d))
 		base = gic_data_rdist_sgi_base();
@@ -473,7 +473,7 @@ static void gic_poke_irq(struct irq_data *d, u32 offset)
 	u32 index, mask;
 
 	offset = convert_offset_index(d, offset, &index);
-	mask = 1 << (index % 32);
+	mask = 1U << (index % 32);
 
 	if (gic_irq_in_rdist(d))
 		base = gic_data_rdist_sgi_base();
-- 
2.17.1
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-irqchip-gic-Fix-UBSAN-shift-out-of-bounds-in-GIC-hel.patch
Type: application/octet-stream
Size: 2200 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251202/a9289d1f/attachment.obj>

From wenst at chromium.org  Tue Dec  2 02:54:27 2025
From: wenst at chromium.org (Chen-Yu Tsai)
Date: Tue, 2 Dec 2025 18:54:27 +0800
Subject: [PATCH v6 3/8] scripts/make_fit: Move dtb processing into a function
In-Reply-To: <20251119181333.991099-4-sjg@chromium.org>
References: <20251119181333.991099-1-sjg@chromium.org> <20251119181333.991099-4-sjg@chromium.org>
Message-ID: <CAGXv+5GnpoNBLP29i1eWCxu7p-V3+_s70U6H0f5nF89md2=_Eg@mail.gmail.com>

On Thu, Nov 20, 2025 at 2:14?AM Simon Glass <sjg at chromium.org> wrote:
>
> Since build_fit() is getting quite long, move the dtb processing into a
> separate function.
>
> Signed-off-by: Simon Glass <sjg at chromium.org>
> Reviewed-by: Nicolas Schier <nsc at kernel.org>
> ---
>
> (no changes since v1)
>
>  scripts/make_fit.py | 67 +++++++++++++++++++++++++++++----------------
>  1 file changed, 44 insertions(+), 23 deletions(-)
>
> diff --git a/scripts/make_fit.py b/scripts/make_fit.py
> index 984371f505bc..1a74a9dcd85e 100755
> --- a/scripts/make_fit.py
> +++ b/scripts/make_fit.py
> @@ -277,6 +277,47 @@ def process_dtb(fname, args):
>
>      return (model, compat, files)
>
> +
> +def _process_dtbs(args, fsw, entries, fdts):
> +    """Process all DTB files and add them to the FIT
> +
> +    Args:
> +        args: Program arguments
> +        fsw: FIT writer object
> +        entries: List to append entries to
> +        fdts: Dictionary of processed DTBs
> +
> +    Returns:
> +        tuple:
> +            Number of files processed
> +            Total size of files processed
> +    """
> +    seq = 0
> +    size = 0
> +    for fname in args.dtbs:
> +        # Ignore non-DTB (*.dtb) files
> +        if os.path.splitext(fname)[1] != '.dtb':
> +            continue
> +
> +        try:
> +            (model, compat, files) = process_dtb(fname, args)
> +        except Exception as e:
> +            sys.stderr.write(f'Error processing {fname}:\n')

`git diff --color-moved` revealed that this bit was changed from
f"" to f'', which I think is a bit unexpected for pure code movement.

> +            raise e
> +
> +        for fn in files:
> +            if fn not in fdts:
> +                seq += 1
> +                size += os.path.getsize(fn)
> +                output_dtb(fsw, seq, fn, args.arch, args.compress)
> +                fdts[fn] = seq
> +
> +        files_seq = [fdts[fn] for fn in files]
> +        entries.append([model, compat, files_seq])
> +
> +    return seq, size
> +
> +
>  def build_fit(args):
>      """Build the FIT from the provided files and arguments
>
> @@ -289,7 +330,6 @@ def build_fit(args):
>              int: Number of configurations generated
>              size: Total uncompressed size of data
>      """
> -    seq = 0
>      size = 0
>      fsw = libfdt.FdtSw()
>      setup_fit(fsw, args.name)
> @@ -310,34 +350,15 @@ def build_fit(args):
>          size += len(data)
>          write_ramdisk(fsw, data, args)
>
> -    for fname in args.dtbs:
> -        # Ignore non-DTB (*.dtb) files
> -        if os.path.splitext(fname)[1] != '.dtb':
> -            continue
> -
> -        try:
> -            (model, compat, files) = process_dtb(fname, args)
> -        except Exception as e:
> -            sys.stderr.write(f"Error processing {fname}:\n")
> -            raise e
> -
> -        for fn in files:
> -            if fn not in fdts:
> -                seq += 1
> -                size += os.path.getsize(fn)
> -                output_dtb(fsw, seq, fn, args.arch, args.compress)
> -                fdts[fn] = seq
> -
> -        files_seq = [fdts[fn] for fn in files]
> -
> -        entries.append([model, compat, files_seq])
> +    count, fdt_size = _process_dtbs(args, fsw, entries, fdts)
> +    size += fdt_size
>
>      finish_fit(fsw, entries, bool(args.ramdisk))
>
>      # Include the kernel itself in the returned file count
>      fdt = fsw.as_fdt()
>      fdt.pack()
> -    return fdt.as_bytearray(), seq + 1 + bool(args.ramdisk), size
> +    return fdt.as_bytearray(), count + 1 + bool(args.ramdisk), size

Reviewed-by: Chen-Yu Tsai <wenst at chromium.org>

>
>  def run_make_fit():
> --
> 2.43.0
>


From ryan.roberts at arm.com  Tue Dec  2 03:04:09 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Tue, 2 Dec 2025 11:04:09 +0000
Subject: [RFC PATCH v1 2/2] randomize_kstack: Unify random source across
 arches
In-Reply-To: <aS63BeFzDCgkVsNy@J2N7QTR9R3>
References: <20251127105958.2427758-1-ryan.roberts@arm.com>
 <20251127105958.2427758-3-ryan.roberts@arm.com>
 <CAMj1kXFY1RXk8T4f46bkm_sr0nJfBoO+ii68JK4+CsRiDwKdCg@mail.gmail.com>
 <9097505d-b18b-4f85-a02c-7f2865ad8bca@arm.com>
 <CAMj1kXHX1W2Kz5NJehtzDhOCKWEd6y1sp8+ViOMHGsq9e8=7Pw@mail.gmail.com>
 <aS6ylpLIyDZOvBDB@J2N7QTR9R3> <7da8d5cc-7b67-4f51-8f09-7ca401d06a3d@arm.com>
 <aS63BeFzDCgkVsNy@J2N7QTR9R3>
Message-ID: <684115c9-4ca2-485e-94a4-706d075f3f6e@arm.com>

On 02/12/2025 09:53, Mark Rutland wrote:
> On Tue, Dec 02, 2025 at 09:39:40AM +0000, Ryan Roberts wrote:
>> On 02/12/2025 09:35, Mark Rutland wrote:
>>> On Tue, Dec 02, 2025 at 10:15:22AM +0100, Ard Biesheuvel wrote:
>>>> On Mon, 1 Dec 2025 at 19:20, Ryan Roberts <ryan.roberts at arm.com> wrote:
>>>>> On 28/11/2025 11:01, Ard Biesheuvel wrote:
>>>>>> On Thu, 27 Nov 2025 at 12:00, Ryan Roberts <ryan.roberts at arm.com> wrote:
>>>>>>> diff --git a/include/linux/randomize_kstack.h b/include/linux/randomize_kstack.h
>>>>>>> index 089b1432f7e6..83c7e6710f6d 100644
>>>>>>> --- a/include/linux/randomize_kstack.h
>>>>>>> +++ b/include/linux/randomize_kstack.h
>>>>>>> @@ -6,6 +6,7 @@
>>>>>>>  #include <linux/kernel.h>
>>>>>>>  #include <linux/jump_label.h>
>>>>>>>  #include <linux/percpu-defs.h>
>>>>>>> +#include <linux/prandom.h>
>>>>>>>
>>>>>>>  DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
>>>>>>>                          randomize_kstack_offset);
>>>>>>> @@ -45,9 +46,13 @@ DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
>>>>>>>  #define KSTACK_OFFSET_MAX(x)   ((x) & 0b1111111100)
>>>>>>>  #endif
>>>>>>>
>>>>>>> +static __always_inline u32 get_update_kstack_offset(void)
>>>>>>> +{
>>>>>>> +       return prandom_u32_state(&current->kstack_rnd_state);
>>>>>
>>>>> I've got bot warnings because this is being called from noinstr code. I guess
>>>>> the best option is to just move add_random_kstack_offset() to after
>>>>> instrumentation is enabled for the affected arches.
>>>>
>>>> Just put instrumentation_begin()/instrumentation_end() around the call
>>>> to prandom_u32_state() - that seems to be the common approach for
>>>> punching holes into the 'noinstr' validation.
>>>
>>> That silences the warning, but isn't necessarily safe, so please DO NOT
>>> do that blindly. The instrumentation_{begin,end}() annotations are only
>>> supposed to be used when we know by construction that instrumentation is
>>> safe.
>>>
>>> Generally, if you can move this to after instrumentation is already
>>> enabled, that should be safe, and so that'd be the better approach.
>>>
>>> Ryan, can you share those warnings (e.g. link to those reports)?
>>
>> https://lore.kernel.org/oe-kbuild-all/202511302137.u4iIA2kf-lkp at intel.com/
>> https://lore.kernel.org/oe-kbuild-all/202511302317.BGFIlAYX-lkp at intel.com/
> 
> Cool, so those are __do_fast_syscall_32() and do_syscall_64(), which I'd
> expect (and those are legitimate warnings).
> 
> From a quick scan of v6.18, it looks like arm64, loongarch, powerpc, and
> riscv perform all the necessary entry work before calling
> add_random_kstack_offset(), and we'll need to change:
> 
> * s390's __do_syscall()
> * x86's do_syscall_64()
> * x86's do_int80_syscall_32()
> * x86's __do_fast_syscall_32()

Yup. I'll have a play with inline vs outline. If I go with outline, I'll fix
these sites up.

> 
> Mark.



From suzuki.poulose at arm.com  Tue Dec  2 03:06:48 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Tue, 2 Dec 2025 11:06:48 +0000
Subject: [PATCH 06/19] coresight: trbe: Refactor syndrome decoding
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-6-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-6-7da32b076b28@arm.com>
Message-ID: <65c84357-0bda-454f-88c3-623b3ff9d29d@arm.com>

Hi Leo

A couple of minor nits below. Otherwise looks like a nice cleanup


On 01/12/2025 11:21, Leo Yan wrote:
> It gives priority to TRBSR_EL1.EA (external abort); an external abort
> will immediately bail out and return an error.
> 
> Next, the syndrome decoding is refactored based on two levels of
> information: the EC (Event Class) bits and the BSC (Trace Buffer Status
> Code) bits.
> 
> If TRBSR_EL1.EC==0b000000, the driver continues parsing TRBSR_EL1.BSC to
> identify the specific trace buffer event.  Otherwise, any non-zero
> TRBSR_EL1.EC is treated as an error.
> 
> For error cases, the driver prints an error string and dumps registers
> for debugging.

minor nit: Please avoid describing the code, which cod does well.
Briefly mention what you are doing, giving any additional contexts
that may not be evident from the code.

e.g:

"Add support for decoding the syndrome for TRBE, providing a verbose
description of the code for Fatal/unhandled events.
While at it add the new definitions from the latest Arm ARM for
EC and BSC"




> 
> No additional checks are required for wrap mode beyond verifying the
> TRBSR_EL1.WRAP bit, even on units with overwrite errata, as this bit


> reliably indicates a buffer wrap.
> 
> Signed-off-by: Leo Yan <leo.yan at arm.com>
> ---
>   drivers/hwtracing/coresight/coresight-trbe.c | 60 +++++++++++++++++++++-------
>   drivers/hwtracing/coresight/coresight-trbe.h |  8 ++--
>   2 files changed, 51 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
> index 9e565122816949b37b8ff5e4ba04cfbc317c6f25..28e2bfa68074f19ccaa4a737d00af577aea818fe 100644
> --- a/drivers/hwtracing/coresight/coresight-trbe.c
> +++ b/drivers/hwtracing/coresight/coresight-trbe.c
> @@ -643,29 +643,61 @@ static void trbe_enable_hw(struct trbe_buf *buf)
>   static enum trbe_fault_action trbe_get_fault_act(struct perf_output_handle *handle,
>   						 u64 trbsr)
>   {
> +	const char *err_str;
>   	int ec = get_trbe_ec(trbsr);
>   	int bsc = get_trbe_bsc(trbsr);
> -	struct trbe_buf *buf = etm_perf_sink_config(handle);
> -	struct trbe_cpudata *cpudata = buf->cpudata;
>   
>   	WARN_ON(is_trbe_running(trbsr));
> -	if (is_trbe_trg(trbsr) || is_trbe_abort(trbsr))
> -		return TRBE_FAULT_ACT_FATAL;
>   
> -	if ((ec == TRBE_EC_STAGE1_ABORT) || (ec == TRBE_EC_STAGE2_ABORT))
> -		return TRBE_FAULT_ACT_FATAL;
> +	if (is_trbe_abort(trbsr)) {
> +		err_str = "External abort";
> +		goto out_fatal;
> +	}
>   
> -	/*
> -	 * If the trbe is affected by TRBE_WORKAROUND_OVERWRITE_FILL_MODE,
> -	 * it might write data after a WRAP event in the fill mode.
> -	 * Thus the check TRBPTR == TRBBASER will not be honored.
> -	 */
> -	if ((is_trbe_wrap(trbsr) && (ec == TRBE_EC_OTHERS) && (bsc == TRBE_BSC_FILLED)) &&
> -	    (trbe_may_overwrite_in_fill_mode(cpudata) ||
> -	     get_trbe_write_pointer() == get_trbe_base_pointer()))
> +	switch (ec) {
> +	case TRBE_EC_OTHERS:
> +		break;
> +	case TRBE_EC_BUF_MGMT_IMPL:
> +		err_str = "Unexpected implemented management";

minor nit: "Unexpected IMPDEF buffer management event"


Suzuki

> +		goto out_fatal;
> +	case TRBE_EC_GP_CHECK_FAULT:
> +		err_str = "Granule Protection Check fault";
> +		goto out_fatal;
> +	case TRBE_EC_STAGE1_ABORT:
> +		err_str = "Stage 1 data abort";
> +		goto out_fatal;
> +	case TRBE_EC_STAGE2_ABORT:
> +		err_str = "Stage 2 data abort";
> +		goto out_fatal;
> +	default:
> +		err_str = "Unknown error code";
> +		goto out_fatal;
> +	}
> +
> +	switch (bsc) {
> +	case TRBE_BSC_NOT_STOPPED:
> +		break;
> +	case TRBE_BSC_FILLED:
> +		break;
> +	case TRBE_BSC_TRIGGERED:
> +		err_str = "Unexpected trigger status";
> +		goto out_fatal;
> +	default:
> +		err_str = "Unexpected buffer status code";
> +		goto out_fatal;
> +	}
> +
> +	if (is_trbe_wrap(trbsr))
>   		return TRBE_FAULT_ACT_WRAP;
>   
>   	return TRBE_FAULT_ACT_SPURIOUS;
> +
> +out_fatal:
> +	pr_err_ratelimited("%s on CPU %d [TRBSR=0x%016llx, TRBPTR=0x%016llx, TRBLIMITR=0x%016llx]\n",
> +			   err_str, smp_processor_id(), trbsr,
> +			   read_sysreg_s(SYS_TRBPTR_EL1),
> +			   read_sysreg_s(SYS_TRBLIMITR_EL1));
> +	return TRBE_FAULT_ACT_FATAL;
>   }
>   
>   static unsigned long trbe_get_trace_size(struct perf_output_handle *handle,
> diff --git a/drivers/hwtracing/coresight/coresight-trbe.h b/drivers/hwtracing/coresight/coresight-trbe.h
> index 45202c48accec7c86ba56130e2737bc2d1830fae..d7f7cd763c0c7139cf322b7336ee563073e3bea0 100644
> --- a/drivers/hwtracing/coresight/coresight-trbe.h
> +++ b/drivers/hwtracing/coresight/coresight-trbe.h
> @@ -35,9 +35,11 @@ static inline bool is_trbe_enabled(void)
>   	return trblimitr & TRBLIMITR_EL1_E;
>   }
>   
> -#define TRBE_EC_OTHERS		0
> -#define TRBE_EC_STAGE1_ABORT	36
> -#define TRBE_EC_STAGE2_ABORT	37
> +#define TRBE_EC_OTHERS			0x0
> +#define TRBE_EC_GP_CHECK_FAULT		0X1e
> +#define TRBE_EC_BUF_MGMT_IMPL		0x1f
> +#define TRBE_EC_STAGE1_ABORT		0x24
> +#define TRBE_EC_STAGE2_ABORT		0x25
>   
>   static inline int get_trbe_ec(u64 trbsr)
>   {
> 



From leo.yan at arm.com  Tue Dec  2 03:14:03 2025
From: leo.yan at arm.com (Leo Yan)
Date: Tue, 2 Dec 2025 11:14:03 +0000
Subject: [PATCH 2/7] perf tools: apply evsel__set_config_if_unset() to
 all config fields
In-Reply-To: <20251201-james-perf-config-bits-v1-2-22ecbbf8007c@linaro.org>
References: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
 <20251201-james-perf-config-bits-v1-2-22ecbbf8007c@linaro.org>
Message-ID: <20251202111403.GS724103@e132581.arm.com>

On Mon, Dec 01, 2025 at 04:41:05PM +0000, Coresight ML wrote:

[...]

>  void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
>  				const char *config_name, u64 val)
>  {
>  	u64 user_bits = 0, bits;
> -	struct evsel_config_term *term = evsel__get_config_term(evsel, USR_CHG_CONFIG);
> +	struct evsel_config_term *term;
> +	struct perf_pmu_format *format = pmu_find_format(&pmu->format, config_name);
> +	__u64 *vp;

Should check (format == NULL) here and bail out for a unknown config name?

> +
> +	switch (format->value) {
> +	case PERF_PMU_FORMAT_VALUE_CONFIG:
> +		term = evsel__get_config_term(evsel, USR_CHG_CONFIG);
> +		vp = &evsel->core.attr.config;
> +		break;
> +	case PERF_PMU_FORMAT_VALUE_CONFIG1:
> +		term = evsel__get_config_term(evsel, USR_CHG_CONFIG1);
> +		vp = &evsel->core.attr.config1;
> +		break;
> +	case PERF_PMU_FORMAT_VALUE_CONFIG2:
> +		term = evsel__get_config_term(evsel, USR_CHG_CONFIG2);
> +		vp = &evsel->core.attr.config2;
> +		break;
> +	case PERF_PMU_FORMAT_VALUE_CONFIG3:
> +		term = evsel__get_config_term(evsel, USR_CHG_CONFIG3);
> +		vp = &evsel->core.attr.config3;
> +		break;
> +	case PERF_PMU_FORMAT_VALUE_CONFIG4:
> +		term = evsel__get_config_term(evsel, USR_CHG_CONFIG4);
> +		vp = &evsel->core.attr.config4;
> +		break;
> +	default:
> +		pr_err("Unknown format value: %d\n", format->value);
> +		return;
> +	}
>  
>  	if (term)
>  		user_bits = term->val.cfg_chg;
> @@ -1396,20 +1436,8 @@ void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
>  		return;
>  
>  	/* Otherwise replace it */
> -	evsel->core.attr.config &= ~bits;
> -	evsel->core.attr.config |= field_prep(bits, val);
> -}
> -
> -static struct perf_pmu_format *
> -pmu_find_format(const struct list_head *formats, const char *name)
> -{
> -	struct perf_pmu_format *format;
> -
> -	list_for_each_entry(format, formats, list)
> -		if (!strcmp(format->name, name))
> -			return format;
> -
> -	return NULL;
> +	*vp &= ~bits;
> +	*vp |= FIELD_PREP(bits, val);
>  }


From suzuki.poulose at arm.com  Tue Dec  2 03:15:47 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Tue, 2 Dec 2025 11:15:47 +0000
Subject: [PATCH 07/19] coresight: trbe: Refactor AUX flag setting
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-7-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-7-7da32b076b28@arm.com>
Message-ID: <e315b489-2ebf-4ab6-8a60-347f1b1dca16@arm.com>

On 01/12/2025 11:21, Leo Yan wrote:
> Rather than spreading AUX flag setting in different functions, use
> trbe_get_fault_act() as a central place for setting the flag.
> 
> Later we will support WRAP mode with continuous trace, so the WRAP
> event does not necessarily cause the trace discontinuity, change to
> check the stop status instead.
> 
> Signed-off-by: Leo Yan <leo.yan at arm.com>
> ---
>   drivers/hwtracing/coresight/coresight-trbe.c | 38 +++++++++++++---------------
>   1 file changed, 17 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
> index 28e2bfa68074f19ccaa4a737d00af577aea818fe..b06885a08e082fd34f68d9588518807b5c47c86e 100644
> --- a/drivers/hwtracing/coresight/coresight-trbe.c
> +++ b/drivers/hwtracing/coresight/coresight-trbe.c
> @@ -265,25 +265,6 @@ static void trbe_reset_local(struct trbe_cpudata *cpudata)
>   	write_sysreg_s(0, SYS_TRBSR_EL1);
>   }
>   
> -static void trbe_report_wrap_event(struct perf_output_handle *handle)
> -{
> -	/*
> -	 * Mark the buffer to indicate that there was a WRAP event by
> -	 * setting the COLLISION flag. This indicates to the user that
> -	 * the TRBE trace collection was stopped without stopping the
> -	 * ETE and thus there might be some amount of trace that was
> -	 * lost between the time the WRAP was detected and the IRQ
> -	 * was consumed by the CPU.
> -	 *
> -	 * Setting the TRUNCATED flag would move the event to STOPPED
> -	 * state unnecessarily, even when there is space left in the
> -	 * ring buffer. Using the COLLISION flag doesn't have this side
> -	 * effect. We only set TRUNCATED flag when there is no space
> -	 * left in the ring buffer.
> -	 */
> -	perf_aux_output_flag(handle, PERF_AUX_FLAG_COLLISION);
> -}
> -
>   static void trbe_truncate_event(struct perf_output_handle *handle)
>   {
>   	struct trbe_buf *buf = etm_perf_sink_config(handle);
> @@ -687,6 +668,23 @@ static enum trbe_fault_action trbe_get_fault_act(struct perf_output_handle *hand
>   		goto out_fatal;
>   	}
>   
> +	/*
> +	 * Mark the buffer to indicate that there was a WRAP event by
> +	 * setting the COLLISION flag. This indicates to the user that
> +	 * the TRBE trace collection was stopped without stopping the
> +	 * ETE and thus there might be some amount of trace that was
> +	 * lost between the time the WRAP was detected and the IRQ
> +	 * was consumed by the CPU.
> +	 *
> +	 * Setting the TRUNCATED flag would move the event to STOPPED
> +	 * state unnecessarily, even when there is space left in the
> +	 * ring buffer. Using the COLLISION flag doesn't have this side
> +	 * effect. We only set TRUNCATED flag when there is no space
> +	 * left in the ring buffer.
> +	 */
> +	if (!is_trbe_running(trbsr))

Is this really required ? There is a WARN_ON(is_trbe_running(trbsr))
above ?

> +		perf_aux_output_flag(handle, PERF_AUX_FLAG_COLLISION);

Also, setting this would unnecessarily mark COLLISION while stopping the
TRBE buffer normally (when called from arm_trbe_update_buffer), when
there is no WRAP event ?


> +
>   	if (is_trbe_wrap(trbsr))
>   		return TRBE_FAULT_ACT_WRAP;

Couldn't this be :

	/* Move the big fat comment here */
	if (is_trbe_wrap(trbsr)) {
		perf_aux_output_flag(handle, PERF_AUX_FLAG_COLLISION);
		return TRBE_FAULT_ACT_WRAP;
	}

Suzuki




From sherry.sun at nxp.com  Tue Dec  2 03:16:38 2025
From: sherry.sun at nxp.com (Sherry Sun)
Date: Tue,  2 Dec 2025 19:16:38 +0800
Subject: [PATCH] arm64: dts: imx8qm-ss-dma: correct the dma channels of lpuart
Message-ID: <20251202111638.3553-1-sherry.sun@nxp.com>

The commit 616effc0272b5 ("arm64: dts: imx8: Fix lpuart DMA channel
order") swap uart rx and tx channel at common imx8-ss-dma.dtsi. But miss
update imx8qm-ss-dma.dtsi.

The commit 5a8e9b022e569 ("arm64: dts: imx8qm-ss-dma: Pass lpuart
dma-names") just simple add dma-names as binding doc requirement.

Correct lpuart0 - lpuart3 dma rx and tx channels, and use defines for
the FSL_EDMA_RX flag.

Fixes: 616effc0272b5 ("arm64: dts: imx8: Fix lpuart DMA channel order")
Signed-off-by: Sherry Sun <sherry.sun at nxp.com>
---
 arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi
index 5f24850bf322..974e193f8dcb 100644
--- a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi
@@ -172,25 +172,25 @@ &flexcan3 {
 
 &lpuart0 {
 	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
-	dmas = <&edma2 13 0 0>, <&edma2 12 0 1>;
+	dmas = <&edma2 12 0 FSL_EDMA_RX>, <&edma2 13 0 0>;
 	dma-names = "rx","tx";
 };
 
 &lpuart1 {
 	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
-	dmas = <&edma2 15 0 0>, <&edma2 14 0 1>;
+	dmas = <&edma2 14 0 FSL_EDMA_RX>, <&edma2 15 0 0>;
 	dma-names = "rx","tx";
 };
 
 &lpuart2 {
 	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
-	dmas = <&edma2 17 0 0>, <&edma2 16 0 1>;
+	dmas = <&edma2 16 0 FSL_EDMA_RX>, <&edma2 17 0 0>;
 	dma-names = "rx","tx";
 };
 
 &lpuart3 {
 	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
-	dmas = <&edma2 19 0 0>, <&edma2 18 0 1>;
+	dmas = <&edma2 18 0 FSL_EDMA_RX>, <&edma2 19 0 0>;
 	dma-names = "rx","tx";
 };
 
-- 
2.34.1



From kory.maincent at bootlin.com  Tue Dec  2 03:18:56 2025
From: kory.maincent at bootlin.com (Kory Maincent)
Date: Tue, 2 Dec 2025 12:18:56 +0100
Subject: [PATCH 05/21] ARM: dts: omap: Bind panel to panel-dpi instead
 of ti,tilcdc,panel driver
In-Reply-To: <94e254fa-289d-41ed-909f-1742cfbb2690@kernel.org>
References: <20251126-feature_tilcdc-v1-0-49b9ef2e3aa0@bootlin.com>
	<20251126-feature_tilcdc-v1-5-49b9ef2e3aa0@bootlin.com>
	<96b1b7bf-ddbe-4213-a201-dc89cf2998dd@ideasonboard.com>
	<3bc5bf92-05c3-4841-ab28-9bab2bb31cd5@kernel.org>
	<20251202104244.59a9e83d@kmaincent-XPS-13-7390>
	<d7515cd3-5488-4d15-82dc-d2b98cfa2bed@kernel.org>
	<20251202114416.09624a4b@kmaincent-XPS-13-7390>
	<94e254fa-289d-41ed-909f-1742cfbb2690@kernel.org>
Message-ID: <20251202121856.0da62885@kmaincent-XPS-13-7390>

On Tue, 2 Dec 2025 11:47:40 +0100
Krzysztof Kozlowski <krzk at kernel.org> wrote:

> On 02/12/2025 11:44, Kory Maincent wrote:
> > On Tue, 2 Dec 2025 11:28:55 +0100
> > Krzysztof Kozlowski <krzk at kernel.org> wrote:
> >   
> >> On 02/12/2025 10:42, Kory Maincent wrote:  
> >>>      
> >>>> Stuffing DTS change in the middle of the driver change tries to hide
> >>>> impact, which is not nice on its own.    
> >>>
> >>> As it needs driver change before the removal for not breaking things it
> >>> can't be done at the beginning of the series.    
> >>
> >> And that is the problem which should stop you there and rethink how to
> >> organize it without impacting users. DTS cannot go via DRM. If that was
> >> your intention, that's my:
> >>
> >> NAK  
> > 
> > My intention was to raise discussion over the ugly and legacy tilcdc-panel
> > binding and what to do with it. But it seems you don't want to, that's a
> > shame.  
> 
> I don't see how you get to these conclusions. I comment that putting
> here DTS in the middle without any explanation of the impact is not
> correct and this one alone I disagree with.

Because you didn't replied to the first line of my answer:
"Yes, I know this but I still wanted to try and begin a discussion on this, as I
really thought it is not a good idea to add and maintain an new non-standard
panel driver solely for this tilcdc panel binding."

But indeed you are right, I should have put more explanation on why there is DTS
and binding change in the middle of the series. Sorry for that.
 
> From that you claim I don't want to fix things...
> 
> DTS cannot go to drm, which means you either need to separate the change
> and make entire work bisectable and backwards compatible for some time
> OR at least document clearly the impact as we always ask.

The thing is, if I split it, it has to be in 3. One for the of DRM bus flags
support, a second for the the devicetree and binding change and a third for the
whole tilcdc and tda998x cleaning stuff. I think I will go for one series, with
better documentation.

Now, what is your point of view on my question. Will you nak any binding
removal even if the binding is ugly and legacy and imply maintaining an
non-standard tilcdc panel driver? I know it breaks DTB compatibility but there
is several argument to not keep it. See patch 6.

Regards,
-- 
K?ry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com


From leo.yan at arm.com  Tue Dec  2 03:21:47 2025
From: leo.yan at arm.com (Leo Yan)
Date: Tue, 2 Dec 2025 11:21:47 +0000
Subject: [PATCH 1/7] perf tools: Track all user changed config bits
In-Reply-To: <978dd9b1-1cb0-4338-95fa-575a858cea80@linaro.org>
References: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
 <20251201-james-perf-config-bits-v1-1-22ecbbf8007c@linaro.org>
 <20251202101556.GR724103@e132581.arm.com>
 <978dd9b1-1cb0-4338-95fa-575a858cea80@linaro.org>
Message-ID: <20251202112147.GT724103@e132581.arm.com>

On Tue, Dec 02, 2025 at 10:40:49AM +0000, James Clark wrote:
> 
> 
> On 02/12/2025 10:15 am, Leo Yan wrote:
> > On Mon, Dec 01, 2025 at 04:41:04PM +0000, Coresight ML wrote:
> > 
> > [...]
> > 
> > > +#define ADD_CONFIG_CHG(format_type, term_type, new_term)		\
> > > +{									\
> > > +	struct parse_events_term *term;					\
> > > +	u64 bits = 0;							\
> > > +	int type;							\
> > > +									\
> > > +	list_for_each_entry(term, &head_config->terms, list) {		\
> > > +		if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER) {  \
> > > +			type = perf_pmu__format_type(pmu, term->config);\
> > > +			if (type != format_type)			\
> > > +				continue;				\
> > > +			bits |= perf_pmu__format_bits(pmu, term->config); \
> > > +		} else if (term->type_term == term_type) {		\
> > > +			bits = ~(u64)0;					\
> > > +		}							\
> > > +	}								\
> > > +									\
> > > +	if (bits)							\
> > > +		ADD_CONFIG_TERM_VAL(new_term, cfg_chg, bits, false);	\
> > > +	return 0;							\
> > 
> > Nitpick: "return 0" is not needed here.  Otherwise:
> > 
> > Reviewed-by: Leo Yan <leo.yan at arm.com>
> 
> I think it's worse than not needed, it makes it stop collecting the changes
> after the first one.

Just curious how this can happen.

  foo()
  {
      {
          chunk 1;
      }

      {
          chunk 2;
      }
  }

Seem to me, if without "return 0" in chunk 1, it still can continue to
run chunk 2, no?

> It was annoying that this had to be a macro instead of a function because
> ADD_CONFIG_TERM_VAL constructs the #define name of the first argument.
> 
> It's probably worth putting in some effort to make ADD_CONFIG_CHG() a
> function to avoid problems like this and maybe add a test.

This would be fine for me.

Thanks,
Leo


From leo.yan at arm.com  Tue Dec  2 03:24:33 2025
From: leo.yan at arm.com (Leo Yan)
Date: Tue, 2 Dec 2025 11:24:33 +0000
Subject: [PATCH 3/7] perf cs-etm: Make a helper to find the Coresight
 evsel
In-Reply-To: <20251201-james-perf-config-bits-v1-3-22ecbbf8007c@linaro.org>
References: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
 <20251201-james-perf-config-bits-v1-3-22ecbbf8007c@linaro.org>
Message-ID: <20251202112433.GU724103@e132581.arm.com>

On Mon, Dec 01, 2025 at 04:41:06PM +0000, Coresight ML wrote:
> This pattern occurs a few times and we'll add another one later, so add
> a helper function for it.
> 
> Signed-off-by: James Clark <james.clark at linaro.org>

Reviewed-by: Leo Yan <leo.yan at arm.com>


From leo.yan at arm.com  Tue Dec  2 03:43:00 2025
From: leo.yan at arm.com (Leo Yan)
Date: Tue, 2 Dec 2025 11:43:00 +0000
Subject: [PATCH 4/7] perf cs-etm: Don't use hard coded config bits when
 setting up ETMCR
In-Reply-To: <20251201-james-perf-config-bits-v1-4-22ecbbf8007c@linaro.org>
References: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
 <20251201-james-perf-config-bits-v1-4-22ecbbf8007c@linaro.org>
Message-ID: <20251202114300.GV724103@e132581.arm.com>

On Mon, Dec 01, 2025 at 04:41:07PM +0000, Coresight ML wrote:

[...]

> @@ -746,7 +779,7 @@ static void cs_etm_get_metadata(struct perf_cpu cpu, u32 *offset,
>  	case CS_ETMV3:
>  		magic = __perf_cs_etmv3_magic;
>  		/* Get configuration register */
> -		info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr);
> +		info->priv[*offset + CS_ETM_ETMCR] = cs_etm_guess_etmcr(itr);

I still think cs_etm_get_config() is better than cs_etm_guess_etmcr().

For ETMv3, we directly pass CONFIG to the kernel, and after validation
in the dirver, then the value will be set to ETMCR.  If we already know
the config value is consistent between user space and kernel, why
introduce a redundant "guess" operation here?

Thanks,
Leo


From maz at kernel.org  Tue Dec  2 03:44:05 2025
From: maz at kernel.org (Marc Zyngier)
Date: Tue, 02 Dec 2025 11:44:05 +0000
Subject: [PATCH] irqchip/gic: Fix UBSAN shift-out-of-bounds in GIC helpers
In-Reply-To: <2fJDwUUYdEf2_eaRa041L9xkT8RkSWFeo7euOnqMbbPhUatLlEaAvGfB6sOspDmXaxO87Eh7bQLV9UolyjbMtZBT1wB2UGypjPOo0Z-RC0Q=@proton.me>
References: <2fJDwUUYdEf2_eaRa041L9xkT8RkSWFeo7euOnqMbbPhUatLlEaAvGfB6sOspDmXaxO87Eh7bQLV9UolyjbMtZBT1wB2UGypjPOo0Z-RC0Q=@proton.me>
Message-ID: <86ldjlp0qi.wl-maz@kernel.org>

On Tue, 02 Dec 2025 10:53:24 +0000,
zhuling0805 <zhuling0805 at proton.me> wrote:
> 
> Hi,
> 
> When running a kernel built with UBSAN enabled, enabling a GPIO
> controller that uses a GIC interrupt as its parent triggers several
> shift-out-of-bounds warnings in the GIC helpers.
> 
> This patch fixes the issue by using unsigned constants so that the
> left shifts are well-defined and UBSAN stays quiet.

Next time, please put additional notes *after* the commit message. In
this case, you are simply repeating what is already in the commit
message, so just sending the patch without anything else would have
been better.

> 
> Thanks,
> Zhu Ling
> 
> ---
> From: Zhu Ling <zhuling0805 at proton.me>
> Date: Tue, 2 Dec 2025 17:54:10 +0800
> Subject: [PATCH] irqchip/gic: Fix UBSAN shift-out-of-bounds in GIC helpers
> 
> When running with UBSAN enabled, enabling a GPIO controller that uses
> a GIC interrupt as its parent triggers several shift-out-of-bounds
> warnings:
> 
>   UBSAN: shift-out-of-bounds in drivers/irqchip/irq-gic-common.c:50:21
>   left shift of 2 by 30 places cannot be represented in type 'int'
> 
> and similar reports in gic_poke_irq() and gic_peek_irq() in
> drivers/irqchip/irq-gic-v3.c.
> 
> These come from shifting signed integer constants. Use unsigned
> constants (0x2U and 1U) so that the behavior is well-defined and the
> UBSAN warnings go away.

I think a better approach would be to convert all of this to
primitives that are designed for bit mask generation, rather than
reinventing the wheel. See below for some (untested) suggestions.

> 
> Signed-off-by: Zhu Ling <zhuling0805 at proton.me>
> ---
>  drivers/irqchip/irq-gic-common.c | 2 +-
>  drivers/irqchip/irq-gic-v3.c     | 4 ++--
>  2 files changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c
> index c776f9142..d4f0afd9e 100644
> --- a/drivers/irqchip/irq-gic-common.c
> +++ b/drivers/irqchip/irq-gic-common.c
> @@ -48,7 +48,7 @@ void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks,
>  int gic_configure_irq(unsigned int irq, unsigned int type,
>  		       void __iomem *base)
>  {
> -	u32 confmask = 0x2 << ((irq % 16) * 2);
> +	u32 confmask = 0x2U << ((irq % 16) * 2);

This really should be written as:

	u32 confmask = BIT(((irq % 16) * 2) + 1);

>  	u32 confoff = (irq / 16) * 4;
>  	u32 val, oldval;
>  	int ret = 0;
> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
> index 3de351e66..f5226c03f 100644
> --- a/drivers/irqchip/irq-gic-v3.c
> +++ b/drivers/irqchip/irq-gic-v3.c
> @@ -457,7 +457,7 @@ static int gic_peek_irq(struct irq_data *d, u32 offset)
>  	u32 index, mask;
>  
>  	offset = convert_offset_index(d, offset, &index);
> -	mask = 1 << (index % 32);
> +	mask = 1U << (index % 32);

and this as BIT(index % 32).

>  
>  	if (gic_irq_in_rdist(d))
>  		base = gic_data_rdist_sgi_base();
> @@ -473,7 +473,7 @@ static void gic_poke_irq(struct irq_data *d, u32 offset)
>  	u32 index, mask;
>  
>  	offset = convert_offset_index(d, offset, &index);
> -	mask = 1 << (index % 32);
> +	mask = 1U << (index % 32);

Same here.

>  
>  	if (gic_irq_in_rdist(d))
>  		base = gic_data_rdist_sgi_base();

Thanks,

	M.

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


From mani at kernel.org  Tue Dec  2 03:44:31 2025
From: mani at kernel.org (Manivannan Sadhasivam)
Date: Tue, 2 Dec 2025 17:14:31 +0530
Subject: [PATCH v9 4/4] PCI: dwc: Support ECAM mechanism by enabling iATU
 'CFG Shift Feature'
In-Reply-To: <alpine.DEB.2.21.2512011617250.49654@angie.orcam.me.uk>
References: <alpine.DEB.2.21.2511280256260.36486@angie.orcam.me.uk>
 <c7aea2b3-6984-40f5-8234-14d265dabefc@oss.qualcomm.com>
 <alpine.DEB.2.21.2511280755440.36486@angie.orcam.me.uk>
 <cabf4c20-095b-4579-adc1-146a566b19b9@oss.qualcomm.com>
 <alpine.DEB.2.21.2511281714030.36486@angie.orcam.me.uk>
 <a4c6d47f-28b5-40d3-bc82-10aeb14f8e78@oss.qualcomm.com>
 <alpine.DEB.2.21.2511290428340.36486@angie.orcam.me.uk>
 <h7pgm3lqolm53sb4wrcpcurk4ghz4tulqnr7vgd7rzxy4hscue@jcn5tepevlwl>
 <syg7vpbt3w53s24hgl7b6w64odmif5bq557lwlvzlbvgkukwcn@66jtzzc3vtiu>
 <alpine.DEB.2.21.2512011617250.49654@angie.orcam.me.uk>
Message-ID: <ps5jjiqv5mw2g3exzvfcfsa4bcda7hois2h6riarwb2d2son4u@2onu4bibw2hb>

On Mon, Dec 01, 2025 at 04:42:42PM +0000, Maciej W. Rozycki wrote:
> On Mon, 1 Dec 2025, Manivannan Sadhasivam wrote:
> 
> > > > So it's definitely nothing specific to the parport driver, but rather a 
> > > > general issue with PCI/e port I/O not working anymore.  I do hope these 
> > > > observations will let you address the issue now.  You might be able to 
> > > > reproduce it with hardware you have available even.
> > > > 
> > > 
> > > Yes, looks like the I/O port access is not working with the CFG Shift feature.
> > > The spec says that both I/O and MEM TLPs should be handled by this feature, so
> > > we are currently unsure why MEM works, but not I/O.
> 
>  As I say, last time I checked (for another reason) documentation was not 
> available to the general public, so I can't help with that.
> 

Sure. I know that the DWC documentation is well secured behind firewalls. So not
asking for help here.

> > > The issue you reported with parport_pc driver is that the driver gets probed,
> > > but it fails to detect the parallel ports on the device. More precisely, it
> > > fails due to the parport_SPP_supported() check in drivers/parport/parport_pc.c.
> > > This function performs some read/write checks to make sure that the port exists,
> > > but most likely the read value doesn't match the written one. And since there is
> > > no log printed in this function, it just failed silently.
> 
>  Whatever the exact transaction conditions are port I/O TLPs seem not to 
> make it through to the requested target device anymore.
> 
>  FWIW the defxx driver issues a command to the device's command register 
> and wants to see a successful completion status in the status register 
> before retrieving the MAC address via the data register.  So it's not a 
> simple case of poking at a register and reading it back, but the end 
> result is the same: the device cannot be talked to.
> 
> > > We will check why I/O access fails with ECAM mode and revert back asap. Since
> > > the merge window is now open, it becomes difficult to revert the CFG shift
> > > feature cleanly. The timing of the report also made it difficult to fix the
> > > issue in v6.18. Hopefully, we can backport the fix once we identify the culprit.
> 
>  No worries, I've been around for long enough (short of 30 years) to know 
> the process.
> 
>  FWIW the original change would've best been reverted for 6.18 as a fatal 
> regression, however port I/O is uncommon enough nowadays we can defer any 
> final decision to 6.19 I suppose.  I'm glad I've tripped over this in the 
> first place as I'm not eager to upgrade all my lab devices all the time, 
> and it was owing to another issue only that I chose this moment to move 
> forward, not so long after the original commit.
> 
> > Can you try the attached patch? It is a reworked version of Krishna's patch. I
> > just moved things around to check potential override issue.
> 
>  No change in behaviour, sorry.  I suppose it's this range of host address 
> decoding:
> 
> fu740-pcie e00000000.pcie:       IO 0x0060080000..0x006008ffff -> 0x0060080000
> 
> aka:
> 
> pci_bus 0000:00: root bus resource [io  0x0000-0xffff] (bus address [0x60080000-0x6008ffff])
> 
> that you're after.  Are you sure your code discovers it correctly?  As I 
> say I can only see IORESOURCE_MEM references and no IORESOURCE_IO ones as 
> would be appropriate for the root bus resource quoted.
> 

The I/O resource is discovered by the driver correctly as seen from the logs:

pci_bus 0000:00: root bus resource [io  0x0000-0xffff] (bus address [0x60080000-0x6008ffff])
pci_bus 0000:00: root bus resource [mem 0x60090000-0x7fffffff]
pci_bus 0000:00: root bus resource [mem 0x2000000000-0x3fffffffff pref]

But we believe that the iATU is not programmed for the I/O port, resulting in
the I/O access not going out to the device.

Krishna found an issue in the previous patch that got shared. So I've attached a
new one. Could you please try and let us know? If it didn't help, please share
the dmesg log that will have some more info.

- Mani

-- 
????????? ????????
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-PCI-qcom-Enable-iATU-mapping-for-memory-IO-regions.patch
Type: text/x-diff
Size: 5931 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251202/01cbaf27/attachment-0001.bin>

From alexander.stein at ew.tq-group.com  Tue Dec  2 03:48:15 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Tue, 02 Dec 2025 12:48:15 +0100
Subject: [PATCH] arm64: dts: imx8qm-ss-dma: correct the dma channels of lpuart
In-Reply-To: <20251202111638.3553-1-sherry.sun@nxp.com>
References: <20251202111638.3553-1-sherry.sun@nxp.com>
Message-ID: <2395053.ElGaqSPkdT@steina-w>

Hi,

Am Dienstag, 2. Dezember 2025, 12:16:38 CET schrieb Sherry Sun:
> The commit 616effc0272b5 ("arm64: dts: imx8: Fix lpuart DMA channel
> order") swap uart rx and tx channel at common imx8-ss-dma.dtsi. But miss
> update imx8qm-ss-dma.dtsi.
> 
> The commit 5a8e9b022e569 ("arm64: dts: imx8qm-ss-dma: Pass lpuart
> dma-names") just simple add dma-names as binding doc requirement.
> 
> Correct lpuart0 - lpuart3 dma rx and tx channels, and use defines for
> the FSL_EDMA_RX flag.
> 
> Fixes: 616effc0272b5 ("arm64: dts: imx8: Fix lpuart DMA channel order")

I'm wondering if this is actually a fix for 5a8e9b022e569 ("arm64: dts:
imx8qm-ss-dma: Pass lpuart dma-names") instead. 616effc0272b5 just
focuses on the common parts. But I don't have a strong opinion here.

Thanks and best regards,
Alexander

> Signed-off-by: Sherry Sun <sherry.sun at nxp.com>
> ---
>  arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi
> index 5f24850bf322..974e193f8dcb 100644
> --- a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi
> +++ b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi
> @@ -172,25 +172,25 @@ &flexcan3 {
>  
>  &lpuart0 {
>  	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
> -	dmas = <&edma2 13 0 0>, <&edma2 12 0 1>;
> +	dmas = <&edma2 12 0 FSL_EDMA_RX>, <&edma2 13 0 0>;
>  	dma-names = "rx","tx";
>  };
>  
>  &lpuart1 {
>  	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
> -	dmas = <&edma2 15 0 0>, <&edma2 14 0 1>;
> +	dmas = <&edma2 14 0 FSL_EDMA_RX>, <&edma2 15 0 0>;
>  	dma-names = "rx","tx";
>  };
>  
>  &lpuart2 {
>  	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
> -	dmas = <&edma2 17 0 0>, <&edma2 16 0 1>;
> +	dmas = <&edma2 16 0 FSL_EDMA_RX>, <&edma2 17 0 0>;
>  	dma-names = "rx","tx";
>  };
>  
>  &lpuart3 {
>  	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
> -	dmas = <&edma2 19 0 0>, <&edma2 18 0 1>;
> +	dmas = <&edma2 18 0 FSL_EDMA_RX>, <&edma2 19 0 0>;
>  	dma-names = "rx","tx";
>  };
>  
> 


-- 
TQ-Systems GmbH | M?hlstra?e 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht M?nchen, HRB 105018
Gesch?ftsf?hrer: Detlef Schneider, R?diger Stahl, Stefan Schneider
http://www.tq-group.com/




From tomi.valkeinen at ideasonboard.com  Tue Dec  2 03:51:59 2025
From: tomi.valkeinen at ideasonboard.com (Tomi Valkeinen)
Date: Tue, 2 Dec 2025 13:51:59 +0200
Subject: [PATCH 05/21] ARM: dts: omap: Bind panel to panel-dpi instead of
 ti,tilcdc,panel driver
In-Reply-To: <20251202121856.0da62885@kmaincent-XPS-13-7390>
References: <20251126-feature_tilcdc-v1-0-49b9ef2e3aa0@bootlin.com>
 <20251126-feature_tilcdc-v1-5-49b9ef2e3aa0@bootlin.com>
 <96b1b7bf-ddbe-4213-a201-dc89cf2998dd@ideasonboard.com>
 <3bc5bf92-05c3-4841-ab28-9bab2bb31cd5@kernel.org>
 <20251202104244.59a9e83d@kmaincent-XPS-13-7390>
 <d7515cd3-5488-4d15-82dc-d2b98cfa2bed@kernel.org>
 <20251202114416.09624a4b@kmaincent-XPS-13-7390>
 <94e254fa-289d-41ed-909f-1742cfbb2690@kernel.org>
 <20251202121856.0da62885@kmaincent-XPS-13-7390>
Message-ID: <1d9a9269-bfda-4d43-938b-2df6b82b9369@ideasonboard.com>

Hi Kory,

On 02/12/2025 13:18, Kory Maincent wrote:
> On Tue, 2 Dec 2025 11:47:40 +0100
> Krzysztof Kozlowski <krzk at kernel.org> wrote:
> 
>> On 02/12/2025 11:44, Kory Maincent wrote:
>>> On Tue, 2 Dec 2025 11:28:55 +0100
>>> Krzysztof Kozlowski <krzk at kernel.org> wrote:
>>>   
>>>> On 02/12/2025 10:42, Kory Maincent wrote:  
>>>>>      
>>>>>> Stuffing DTS change in the middle of the driver change tries to hide
>>>>>> impact, which is not nice on its own.    
>>>>>
>>>>> As it needs driver change before the removal for not breaking things it
>>>>> can't be done at the beginning of the series.    
>>>>
>>>> And that is the problem which should stop you there and rethink how to
>>>> organize it without impacting users. DTS cannot go via DRM. If that was
>>>> your intention, that's my:
>>>>
>>>> NAK  
>>>
>>> My intention was to raise discussion over the ugly and legacy tilcdc-panel
>>> binding and what to do with it. But it seems you don't want to, that's a
>>> shame.  
>>
>> I don't see how you get to these conclusions. I comment that putting
>> here DTS in the middle without any explanation of the impact is not
>> correct and this one alone I disagree with.
> 
> Because you didn't replied to the first line of my answer:
> "Yes, I know this but I still wanted to try and begin a discussion on this, as I
> really thought it is not a good idea to add and maintain an new non-standard
> panel driver solely for this tilcdc panel binding."
> 
> But indeed you are right, I should have put more explanation on why there is DTS
> and binding change in the middle of the series. Sorry for that.
>  
>> From that you claim I don't want to fix things...
>>
>> DTS cannot go to drm, which means you either need to separate the change
>> and make entire work bisectable and backwards compatible for some time
>> OR at least document clearly the impact as we always ask.
> 
> The thing is, if I split it, it has to be in 3. One for the of DRM bus flags
> support, a second for the the devicetree and binding change and a third for the
> whole tilcdc and tda998x cleaning stuff. I think I will go for one series, with
> better documentation.
> 
> Now, what is your point of view on my question. Will you nak any binding
> removal even if the binding is ugly and legacy and imply maintaining an
> non-standard tilcdc panel driver? I know it breaks DTB compatibility but there
> is several argument to not keep it. See patch 6.
The binding being ugly and having to maintain non-standard tilcdc panel
driver may be nice things for us, the users don't care. The users care
if their board no longer works.

And how does this sync with u-boot? It also has code for at least for a
few of these boards.

Are there even users for these boards? If not, maybe they can be just
removed? I'm personally not familiar with these boards, so I have no
idea of their age or distribution.

One trick that can be done is to modify the loaded DTB at boot time,
detecting the old format, converting it to the new one, so that when the
drivers are probed they only see the new DTB.

 Tomi



From frankwu at gmx.de  Tue Dec  2 03:52:44 2025
From: frankwu at gmx.de (Frank Wunderlich)
Date: Tue, 2 Dec 2025 12:52:44 +0100
Subject: [PATCH v3 2/2] net: dsa: mt7530: Use GPIO polarity to generate
 correct reset sequence
In-Reply-To: <0d85e1e6-ea75-4f20-aef1-90d446b4bfa1@kernel.org>
References: <20251129234603.2544-1-ptpt52@gmail.com>
 <20251129234603.2544-2-ptpt52@gmail.com>
 <0675b35f-217d-4261-9e3f-2eb24753d43c@lunn.ch>
 <20251130080731.ty2dlxaypxvodxiw@skbuf>
 <3fbc4e67-b931-421c-9d83-2214aaa2f6ed@lunn.ch>
 <0d85e1e6-ea75-4f20-aef1-90d446b4bfa1@kernel.org>
Message-ID: <00f308a1-a4b1-4f20-8d8e-459ddf4c39b1@gmx.de>

Hi,

Am 01.12.25 um 08:48 schrieb Krzysztof Kozlowski:
> On 30/11/2025 21:17, Andrew Lunn wrote:
>> On Sun, Nov 30, 2025 at 10:07:31AM +0200, Vladimir Oltean wrote:
>>> On Sun, Nov 30, 2025 at 02:11:05AM +0100, Andrew Lunn wrote:
>>>>> -		gpiod_set_value_cansleep(priv->reset, 0);
>>>>> +		int is_active_low = !!gpiod_is_active_low(priv->reset);
>>>>> +		gpiod_set_value_cansleep(priv->reset, is_active_low);
>>>> I think you did not correctly understand what Russell said. You pass
>>>> the logical value to gpiod_set_value(). If the GPIO has been marked as
>>>> active LOW, the GPIO core will invert the logical values to the raw
>>>> value. You should not be using gpiod_is_active_low().
>>>>
>>>> But as i said to the previous patch, i would just leave everything as
>>>> it is, except document the issue.
>>>>
>>>> 	Andrew
>>>>
>>> It was my suggestion to do it like this (but I don't understand why I'm
>>> again not in CC).
>>>
>>> We _know_ that the reset pin of the switch should be active low. So by
>>> using gpiod_is_active_low(), we can determine whether the device tree is
>>> wrong or not, and we can work with a wrong device tree too (just invert
>>> the logical values).
>> Assuming there is not a NOT gate placed between the GPIO and the reset
>> pin, because the board designer decided to do that for some reason?
jumping in because i prepare mt7987 / BPI-R4Lite dts for upstreaming 
when driver-changes are in.
With current driver i need to define the reset-gpio for mt7531 again 
wrong to get it
working. So to have future dts correct, imho this (or similar) change to 
driver is needed.

Of course we cannot simply say that current value is wrong and just 
invert it because of
possible "external" inversion of reset signal between SoC and switch.
I have to look on schematics for the boards i have (BPI-R64, BPI-R3, 
BPI-R2Pro) if there is such circuit.
Maybe the mt7988 (mt7530-mmio) based boards also affected?
But not changing driver imho results in future broken devicetrees or can 
this
avoided somehow?
Nethertheless the driverchange needs to be done before dts change.

regards Frank
> Yeah, I cannot imagine how this could possibly support old and new DTS
> without breaking some users, unless people over-simplified and discarded
> some cases. But then this should clearly mark these broken cases instead
> of falsely claim that impossible task of rewriting the flag is done
> correctly.
>
> BTW, the code clearly does not handle such cases, so "we can determine
> whether the device tree is wrong or not" statement is obviously not true.
>
> Best regards,
> Krzysztof
>



From james.clark at linaro.org  Tue Dec  2 03:53:32 2025
From: james.clark at linaro.org (James Clark)
Date: Tue, 2 Dec 2025 11:53:32 +0000
Subject: [PATCH 4/7] perf cs-etm: Don't use hard coded config bits when
 setting up ETMCR
In-Reply-To: <20251202114300.GV724103@e132581.arm.com>
References: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
 <20251201-james-perf-config-bits-v1-4-22ecbbf8007c@linaro.org>
 <20251202114300.GV724103@e132581.arm.com>
Message-ID: <53b24702-eb3b-4e08-bca3-70402eaf4db5@linaro.org>



On 02/12/2025 11:43 am, Leo Yan wrote:
> On Mon, Dec 01, 2025 at 04:41:07PM +0000, Coresight ML wrote:
> 
> [...]
> 
>> @@ -746,7 +779,7 @@ static void cs_etm_get_metadata(struct perf_cpu cpu, u32 *offset,
>>   	case CS_ETMV3:
>>   		magic = __perf_cs_etmv3_magic;
>>   		/* Get configuration register */
>> -		info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr);
>> +		info->priv[*offset + CS_ETM_ETMCR] = cs_etm_guess_etmcr(itr);
> 
> I still think cs_etm_get_config() is better than cs_etm_guess_etmcr().
> 
> For ETMv3, we directly pass CONFIG to the kernel, and after validation
> in the dirver, then the value will be set to ETMCR.  If we already know
> the config value is consistent between user space and kernel, why
> introduce a redundant "guess" operation here?
> 
> Thanks,
> Leo

Because userspace doesn't always come up with the same value as the 
driver. For example right now in ETM3, ETMCR_RETURN_STACK isn't set 
depending on certain conditions that userspace doesn't know about.  ETM4 
has the same for TRCCONFIGR_RS and maybe some others. In the future, 
other versions of the driver could do different things as long as we 
don't break decoding.

I didn't want the function name to imply it was doing something it 
wasn't as that confused me a little bit. It's definitely not "getting" 
the value. Maybe "guess" isn't the best it could be, but it's not far off.



From suzuki.poulose at arm.com  Tue Dec  2 04:00:15 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Tue, 2 Dec 2025 12:00:15 +0000
Subject: [PATCH 10/19] coresight: trbe: Always check fault action when
 updating buffer
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-10-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-10-7da32b076b28@arm.com>
Message-ID: <be0b9b11-19d6-4d8c-910c-17773a4a2df0@arm.com>

On 01/12/2025 11:22, Leo Yan wrote:
> The current code checks the fault action only via the IRQ status bit,
> which is unreliable due to possible hardware latency.
> 
> Move the fault action check out of the IRQ status condition.  This also
> causes the buffer size to be calculated for non-WRAP and fault cases,
> which is fine since the write pointer is trusted for the calculation.
> 
> Signed-off-by: Leo Yan <leo.yan at arm.com>
> ---
>   drivers/hwtracing/coresight/coresight-trbe.c | 17 +++--------------
>   1 file changed, 3 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
> index f56ecdeaa6596afb440e4d53732e08a85f9bf89d..e579ea98523c24d23a0cd265dcdd0a46b52b52da 100644
> --- a/drivers/hwtracing/coresight/coresight-trbe.c
> +++ b/drivers/hwtracing/coresight/coresight-trbe.c
> @@ -806,7 +806,6 @@ static unsigned long arm_trbe_update_buffer(struct coresight_device *csdev,
>   	enum trbe_fault_action act;
>   	unsigned long size, status;
>   	unsigned long flags;
> -	bool wrap = false;
>   
>   	WARN_ON(buf->cpudata != cpudata);
>   	WARN_ON(cpudata->cpu != smp_processor_id());
> @@ -858,21 +857,11 @@ static unsigned long arm_trbe_update_buffer(struct coresight_device *csdev,
>   		 */
>   		clr_trbe_irq();
>   		isb();
> -
> -		act = trbe_get_fault_act(handle, status);
> -		/*
> -		 * If this was not due to a WRAP event, we have some
> -		 * errors and as such buffer is empty.
> -		 */
> -		if (act != TRBE_FAULT_ACT_WRAP) {
> -			size = 0;
> -			goto done;
> -		}
> -
> -		wrap = true;
>   	}
>   
> -	size = trbe_get_trace_size(handle, buf, wrap);
> +	act = trbe_get_fault_act(handle, status);

Also act is valid only when there is an IRQ ?

> +
> +	size = trbe_get_trace_size(handle, buf, act == TRBE_FAULT_ACT_WRAP);

We have certain assumptions in trbe_get_trace_size(), which may be
broken with this change.

e.g., if we get a fatal error, we don't detect that the buffer is empty
and may trigger a WARN_ON() on systems with CPU erratum as below ?

>         /*                                                                      
>          * If the TRBE is affected by the following erratum, we must fill           
>          * the space we skipped with IGNORE packets. And we are always          
>          * guaranteed to have at least a PAGE_SIZE space in the buffer.         
>          */                                                                     
>         if (trbe_has_erratum(buf->cpudata, TRBE_WORKAROUND_OVERWRITE_FILL_MODE) &&
>             !WARN_ON(size < overwrite_skip))                                    
>                 __trbe_pad_buf(buf, start_off, overwrite_skip); 



Suzuki


>   
>   done:
>   	local_irq_restore(flags);
> 



From leo.yan at arm.com  Tue Dec  2 04:01:47 2025
From: leo.yan at arm.com (Leo Yan)
Date: Tue, 2 Dec 2025 12:01:47 +0000
Subject: [PATCH 5/7] perf cs-etm: Don't use hard coded config bits when
 setting up TRCCONFIGR
In-Reply-To: <20251201-james-perf-config-bits-v1-5-22ecbbf8007c@linaro.org>
References: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
 <20251201-james-perf-config-bits-v1-5-22ecbbf8007c@linaro.org>
Message-ID: <20251202120147.GW724103@e132581.arm.com>

On Mon, Dec 01, 2025 at 04:41:08PM +0000, Coresight ML wrote:
> Perf only looks at attr.config when determining what was programmed into
> TRCCONFIGR. These bits could theoretically be in any of the config
> fields. Use the evsel__get_config_val() helper so it's agnostic to
> which config field they are in.
> 
> The kernel will also stop publishing the TRCCONFIGR register bits in a
> header [1] so preempt that by defining them here.
> 
> [1]: https://lore.kernel.org/linux-arm-kernel/20251128-james-cs-syncfreq-v8-10-4d319764cc58 at linaro.org/
> Signed-off-by: James Clark <james.clark at linaro.org>

Reviewed-by: Leo Yan <leo.yan at arm.com>


From suzuki.poulose at arm.com  Tue Dec  2 04:05:52 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Tue, 2 Dec 2025 12:05:52 +0000
Subject: [PATCH 11/19] coresight: trbe: Apply overwrite erratum for only
 wrap event
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-11-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-11-7da32b076b28@arm.com>
Message-ID: <cca13ee6-83d9-4478-ace0-1e7bedf79d0e@arm.com>

On 01/12/2025 11:22, Leo Yan wrote:
> The overwrite erratum occurs only on wrap events, so apply the extra
> wrap condition check in the workaround.
> 
> Signed-off-by: Leo Yan <leo.yan at arm.com>
> ---
>   drivers/hwtracing/coresight/coresight-trbe.c | 4 ++--
>   1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
> index e579ea98523c24d23a0cd265dcdd0a46b52b52da..2600af12a8fb94bb8c74efda2a101aacd01b0b34 100644
> --- a/drivers/hwtracing/coresight/coresight-trbe.c
> +++ b/drivers/hwtracing/coresight/coresight-trbe.c
> @@ -714,7 +714,7 @@ static unsigned long trbe_get_trace_size(struct perf_output_handle *handle,
>   	 * 64bytes. Thus we ignore the potential triggering of the erratum
>   	 * on WRAP and limit the data to LIMIT.
>   	 */
> -	if (wrap)
> +	if (wrap && trbe_may_overwrite_in_fill_mode(buf->cpudata))
>   		write = get_trbe_limit_pointer();

This must be trbe_may_write_out_of_range() ?

Suzuki


>   	else
>   		write = get_trbe_write_pointer();
> @@ -736,7 +736,7 @@ static unsigned long trbe_get_trace_size(struct perf_output_handle *handle,
>   	 * the space we skipped with IGNORE packets. And we are always
>   	 * guaranteed to have at least a PAGE_SIZE space in the buffer.
>   	 */
> -	if (trbe_may_overwrite_in_fill_mode(buf->cpudata) &&
> +	if (wrap && trbe_may_overwrite_in_fill_mode(buf->cpudata) &&
>   	    !WARN_ON(size < overwrite_skip))
>   		__trbe_pad_buf(buf, start_off, overwrite_skip);
>   
> 



From suzuki.poulose at arm.com  Tue Dec  2 04:10:22 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Tue, 2 Dec 2025 12:10:22 +0000
Subject: [PATCH 15/19] coresight: trbe: Add static key for bypassing
 trigger mode
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-15-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-15-7da32b076b28@arm.com>
Message-ID: <47da45df-b75f-46e8-9839-97d869b43afc@arm.com>

On 01/12/2025 11:22, Leo Yan wrote:
> To avoid complexity, if any CPU in the system has the fill mode erratum,
> the driver will not use trigger mode, it simply rolls back to fill mode
> only and apply the workaround on it.
> 
> Add a static key to control trigger mode bypassing.  During each CPU
> probe, the key is enabled when the relevant erratum is detected.
> 
> Signed-off-by: Leo Yan <leo.yan at arm.com>
> ---
>   drivers/hwtracing/coresight/coresight-trbe.c | 15 +++++++++++++++
>   1 file changed, 15 insertions(+)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
> index 941aa46e9b11f60c707eb40093964de454a3fd83..8390d0a8fe23d35945610df15f21751279ee37ee 100644
> --- a/drivers/hwtracing/coresight/coresight-trbe.c
> +++ b/drivers/hwtracing/coresight/coresight-trbe.c
> @@ -17,6 +17,7 @@
>   
>   #include <asm/barrier.h>
>   #include <asm/cpufeature.h>
> +#include <linux/jump_label.h>
>   #include <linux/kvm_host.h>
>   #include <linux/vmalloc.h>
>   
> @@ -147,6 +148,12 @@ struct trbe_drvdata {
>   	struct platform_device *pdev;
>   };
>   
> +DEFINE_STATIC_KEY_FALSE(trbe_trigger_mode_bypass);
> +
> +#define trbe_trigger_mode_need_bypass(cpudata)		\
> +	(trbe_may_overwrite_in_fill_mode((cpudata)) ||	\
> +	 trbe_may_write_out_of_range((cpudata)))
> +

Please make that a static inline function.

>   static void trbe_check_errata(struct trbe_cpudata *cpudata)
>   {
>   	int i;
> @@ -1306,6 +1313,14 @@ static void arm_trbe_register_coresight_cpu(struct trbe_drvdata *drvdata, int cp
>   
>   	dev_set_drvdata(&trbe_csdev->dev, cpudata);
>   	coresight_set_percpu_sink(cpu, trbe_csdev);
> +
> +	/*
> +	 * If any CPU cannot use trigger mode, bypass the mode globally for
> +	 * consistent tracing behaviour.
> +	 */
> +	if (trbe_trigger_mode_need_bypass(cpudata))
> +		static_branch_enable(&trbe_trigger_mode_bypass);

You only need to enable this once, not for every CPU.

Suzuki


> +
>   	return;
>   cpu_clear:
>   	cpumask_clear_cpu(cpu, &drvdata->supported_cpus);
> 



From leo.yan at arm.com  Tue Dec  2 04:15:28 2025
From: leo.yan at arm.com (Leo Yan)
Date: Tue, 2 Dec 2025 12:15:28 +0000
Subject: [PATCH 6/7] perf cs-etm: Don't hard code config attribute when
 configuring the event
In-Reply-To: <20251201-james-perf-config-bits-v1-6-22ecbbf8007c@linaro.org>
References: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
 <20251201-james-perf-config-bits-v1-6-22ecbbf8007c@linaro.org>
Message-ID: <20251202121528.GX724103@e132581.arm.com>

On Mon, Dec 01, 2025 at 04:41:09PM +0000, Coresight ML wrote:

[...]

> @@ -103,13 +103,20 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
>  				      struct perf_cpu cpu)
>  {
>  	int err;
> -	__u64 val;
> -	u64 contextid = evsel->core.attr.config &
> -		(perf_pmu__format_bits(cs_etm_pmu, "contextid") |
> -		 perf_pmu__format_bits(cs_etm_pmu, "contextid1") |
> -		 perf_pmu__format_bits(cs_etm_pmu, "contextid2"));
> +	u64 ctxt, ctxt1, ctxt2;
> +	__u64 trcidr2;
>  
> -	if (!contextid)
> +	err = evsel__get_config_val(cs_etm_pmu, evsel, "contextid", &ctxt);
> +	if (err)
> +		return err;
> +	err = evsel__get_config_val(cs_etm_pmu, evsel, "contextid1", &ctxt1);
> +	if (err)
> +		return err;
> +	err = evsel__get_config_val(cs_etm_pmu, evsel, "contextid2", &ctxt2);
> +	if (err)
> +		return err;

Seems to me, this is not right.  The current code checks any context
ID setting but it can tolerate if missing "contexid[*]" format.

After calling evsel__get_config_val(), if any "contextid[*]" format is
missed, it returns error and will diretly bail out.  As a result,
cs_etm_validate_context_id() will always return error.

> +
> +	if (!ctxt && !ctxt1 && !ctxt2)
>  		return 0;
>  
>  	/* Not supported in etmv3 */
> @@ -120,12 +127,11 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
>  	}
>  
>  	/* Get a handle on TRCIDR2 */
> -	err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2], &val);
> +	err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2], &trcidr2);
>  	if (err)
>  		return err;
>  
> -	if (contextid &
> -	    perf_pmu__format_bits(cs_etm_pmu, "contextid1")) {
> +	if (ctxt1) {
>  		/*
>  		 * TRCIDR2.CIDSIZE, bit [9-5], indicates whether contextID
>  		 * tracing is supported:
> @@ -133,15 +139,14 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
>  		 *  0b00100 Maximum of 32-bit Context ID size.
>  		 *  All other values are reserved.
>  		 */
> -		if (BMVAL(val, 5, 9) != 0x4) {
> +		if (BMVAL(trcidr2, 5, 9) != 0x4) {
>  			pr_err("%s: CONTEXTIDR_EL1 isn't supported, disable with %s/contextid1=0/\n",
>  			       CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME);
>  			return -EINVAL;
>  		}
>  	}
>  
> -	if (contextid &
> -	    perf_pmu__format_bits(cs_etm_pmu, "contextid2")) {
> +	if (ctxt2) {
>  		/*
>  		 * TRCIDR2.VMIDOPT[30:29] != 0 and
>  		 * TRCIDR2.VMIDSIZE[14:10] == 0b00100 (32bit virtual contextid)
> @@ -149,7 +154,7 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
>  		 * virtual context id is < 32bit.
>  		 * Any value of VMIDSIZE >= 4 (i.e, > 32bit) is fine for us.
>  		 */
> -		if (!BMVAL(val, 29, 30) || BMVAL(val, 10, 14) < 4) {
> +		if (!BMVAL(trcidr2, 29, 30) || BMVAL(trcidr2, 10, 14) < 4) {
>  			pr_err("%s: CONTEXTIDR_EL2 isn't supported, disable with %s/contextid2=0/\n",
>  			       CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME);
>  			return -EINVAL;
> @@ -163,10 +168,14 @@ static int cs_etm_validate_timestamp(struct perf_pmu *cs_etm_pmu, struct evsel *
>  				     struct perf_cpu cpu)
>  {
>  	int err;
> -	__u64 val;
> +	u64 val;
> +	__u64 trcidr0;
>  
> -	if (!(evsel->core.attr.config &
> -	      perf_pmu__format_bits(cs_etm_pmu, "timestamp")))
> +	err = evsel__get_config_val(cs_etm_pmu, evsel, "timestamp", &val);
> +	if (err)
> +		return err;
> +
> +	if (!val)
>  		return 0;

Similiar issue here.  The current code returns 0 if not find "timestamp"
format.  With this change, it returns error instead.

Thanks,
Leo


From krzk at kernel.org  Tue Dec  2 04:19:08 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 2 Dec 2025 13:19:08 +0100
Subject: [PATCH 05/21] ARM: dts: omap: Bind panel to panel-dpi instead of
 ti,tilcdc,panel driver
In-Reply-To: <20251202121856.0da62885@kmaincent-XPS-13-7390>
References: <20251126-feature_tilcdc-v1-0-49b9ef2e3aa0@bootlin.com>
 <20251126-feature_tilcdc-v1-5-49b9ef2e3aa0@bootlin.com>
 <96b1b7bf-ddbe-4213-a201-dc89cf2998dd@ideasonboard.com>
 <3bc5bf92-05c3-4841-ab28-9bab2bb31cd5@kernel.org>
 <20251202104244.59a9e83d@kmaincent-XPS-13-7390>
 <d7515cd3-5488-4d15-82dc-d2b98cfa2bed@kernel.org>
 <20251202114416.09624a4b@kmaincent-XPS-13-7390>
 <94e254fa-289d-41ed-909f-1742cfbb2690@kernel.org>
 <20251202121856.0da62885@kmaincent-XPS-13-7390>
Message-ID: <c6ae49de-d1e3-4f9c-b9d0-95cf7a9d9815@kernel.org>

On 02/12/2025 12:18, Kory Maincent wrote:
> On Tue, 2 Dec 2025 11:47:40 +0100
> Krzysztof Kozlowski <krzk at kernel.org> wrote:
> 
>> On 02/12/2025 11:44, Kory Maincent wrote:
>>> On Tue, 2 Dec 2025 11:28:55 +0100
>>> Krzysztof Kozlowski <krzk at kernel.org> wrote:
>>>   
>>>> On 02/12/2025 10:42, Kory Maincent wrote:  
>>>>>      
>>>>>> Stuffing DTS change in the middle of the driver change tries to hide
>>>>>> impact, which is not nice on its own.    
>>>>>
>>>>> As it needs driver change before the removal for not breaking things it
>>>>> can't be done at the beginning of the series.    
>>>>
>>>> And that is the problem which should stop you there and rethink how to
>>>> organize it without impacting users. DTS cannot go via DRM. If that was
>>>> your intention, that's my:
>>>>
>>>> NAK  
>>>
>>> My intention was to raise discussion over the ugly and legacy tilcdc-panel
>>> binding and what to do with it. But it seems you don't want to, that's a
>>> shame.  
>>
>> I don't see how you get to these conclusions. I comment that putting
>> here DTS in the middle without any explanation of the impact is not
>> correct and this one alone I disagree with.
> 
> Because you didn't replied to the first line of my answer:
> "Yes, I know this but I still wanted to try and begin a discussion on this, as I
> really thought it is not a good idea to add and maintain an new non-standard
> panel driver solely for this tilcdc panel binding."
> 
> But indeed you are right, I should have put more explanation on why there is DTS
> and binding change in the middle of the series. Sorry for that.
>  
>> From that you claim I don't want to fix things...
>>
>> DTS cannot go to drm, which means you either need to separate the change
>> and make entire work bisectable and backwards compatible for some time
>> OR at least document clearly the impact as we always ask.
> 
> The thing is, if I split it, it has to be in 3. One for the of DRM bus flags
> support, a second for the the devicetree and binding change and a third for the
> whole tilcdc and tda998x cleaning stuff. I think I will go for one series, with
> better documentation.
> 
> Now, what is your point of view on my question. Will you nak any binding
> removal even if the binding is ugly and legacy and imply maintaining an
> non-standard tilcdc panel driver? I know it breaks DTB compatibility but there
> is several argument to not keep it. See patch 6.

I will not NAK, removing bindings and breaking users is under some
conditions acceptable. You just need to come with the reasons and impact.

Reason "is ugly" is usually not good enough. Especially if things were
working.

Best regards,
Krzysztof


From krzk at kernel.org  Tue Dec  2 04:20:26 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 2 Dec 2025 13:20:26 +0100
Subject: [PATCH 05/21] ARM: dts: omap: Bind panel to panel-dpi instead of
 ti,tilcdc,panel driver
In-Reply-To: <1d9a9269-bfda-4d43-938b-2df6b82b9369@ideasonboard.com>
References: <20251126-feature_tilcdc-v1-0-49b9ef2e3aa0@bootlin.com>
 <20251126-feature_tilcdc-v1-5-49b9ef2e3aa0@bootlin.com>
 <96b1b7bf-ddbe-4213-a201-dc89cf2998dd@ideasonboard.com>
 <3bc5bf92-05c3-4841-ab28-9bab2bb31cd5@kernel.org>
 <20251202104244.59a9e83d@kmaincent-XPS-13-7390>
 <d7515cd3-5488-4d15-82dc-d2b98cfa2bed@kernel.org>
 <20251202114416.09624a4b@kmaincent-XPS-13-7390>
 <94e254fa-289d-41ed-909f-1742cfbb2690@kernel.org>
 <20251202121856.0da62885@kmaincent-XPS-13-7390>
 <1d9a9269-bfda-4d43-938b-2df6b82b9369@ideasonboard.com>
Message-ID: <112178ce-189e-4437-b6ae-d54b36b59bb8@kernel.org>

On 02/12/2025 12:51, Tomi Valkeinen wrote:
> Hi Kory,
> 
> On 02/12/2025 13:18, Kory Maincent wrote:
>> On Tue, 2 Dec 2025 11:47:40 +0100
>> Krzysztof Kozlowski <krzk at kernel.org> wrote:
>>
>>> On 02/12/2025 11:44, Kory Maincent wrote:
>>>> On Tue, 2 Dec 2025 11:28:55 +0100
>>>> Krzysztof Kozlowski <krzk at kernel.org> wrote:
>>>>   
>>>>> On 02/12/2025 10:42, Kory Maincent wrote:  
>>>>>>      
>>>>>>> Stuffing DTS change in the middle of the driver change tries to hide
>>>>>>> impact, which is not nice on its own.    
>>>>>>
>>>>>> As it needs driver change before the removal for not breaking things it
>>>>>> can't be done at the beginning of the series.    
>>>>>
>>>>> And that is the problem which should stop you there and rethink how to
>>>>> organize it without impacting users. DTS cannot go via DRM. If that was
>>>>> your intention, that's my:
>>>>>
>>>>> NAK  
>>>>
>>>> My intention was to raise discussion over the ugly and legacy tilcdc-panel
>>>> binding and what to do with it. But it seems you don't want to, that's a
>>>> shame.  
>>>
>>> I don't see how you get to these conclusions. I comment that putting
>>> here DTS in the middle without any explanation of the impact is not
>>> correct and this one alone I disagree with.
>>
>> Because you didn't replied to the first line of my answer:
>> "Yes, I know this but I still wanted to try and begin a discussion on this, as I
>> really thought it is not a good idea to add and maintain an new non-standard
>> panel driver solely for this tilcdc panel binding."
>>
>> But indeed you are right, I should have put more explanation on why there is DTS
>> and binding change in the middle of the series. Sorry for that.
>>  
>>> From that you claim I don't want to fix things...
>>>
>>> DTS cannot go to drm, which means you either need to separate the change
>>> and make entire work bisectable and backwards compatible for some time
>>> OR at least document clearly the impact as we always ask.
>>
>> The thing is, if I split it, it has to be in 3. One for the of DRM bus flags
>> support, a second for the the devicetree and binding change and a third for the
>> whole tilcdc and tda998x cleaning stuff. I think I will go for one series, with
>> better documentation.
>>
>> Now, what is your point of view on my question. Will you nak any binding
>> removal even if the binding is ugly and legacy and imply maintaining an
>> non-standard tilcdc panel driver? I know it breaks DTB compatibility but there
>> is several argument to not keep it. See patch 6.
> The binding being ugly and having to maintain non-standard tilcdc panel
> driver may be nice things for us, the users don't care. The users care
> if their board no longer works.

Exactly.

> 
> And how does this sync with u-boot? It also has code for at least for a
> few of these boards.

+1

> 
> Are there even users for these boards? If not, maybe they can be just
> removed? I'm personally not familiar with these boards, so I have no
> idea of their age or distribution.
> 
> One trick that can be done is to modify the loaded DTB at boot time,
> detecting the old format, converting it to the new one, so that when the
> drivers are probed they only see the new DTB.

Best regards,
Krzysztof


From daniel at makrotopia.org  Tue Dec  2 04:20:31 2025
From: daniel at makrotopia.org (Daniel Golle)
Date: Tue, 2 Dec 2025 12:20:31 +0000
Subject: [PATCH v3 2/2] net: dsa: mt7530: Use GPIO polarity to generate
 correct reset sequence
In-Reply-To: <00f308a1-a4b1-4f20-8d8e-459ddf4c39b1@gmx.de>
References: <20251129234603.2544-1-ptpt52@gmail.com>
 <20251129234603.2544-2-ptpt52@gmail.com>
 <0675b35f-217d-4261-9e3f-2eb24753d43c@lunn.ch>
 <20251130080731.ty2dlxaypxvodxiw@skbuf>
 <3fbc4e67-b931-421c-9d83-2214aaa2f6ed@lunn.ch>
 <0d85e1e6-ea75-4f20-aef1-90d446b4bfa1@kernel.org>
 <00f308a1-a4b1-4f20-8d8e-459ddf4c39b1@gmx.de>
Message-ID: <aS7Zj3AFsSp2CTNv@makrotopia.org>

On Tue, Dec 02, 2025 at 12:52:44PM +0100, Frank Wunderlich wrote:
> Hi,
> 
> Am 01.12.25 um 08:48 schrieb Krzysztof Kozlowski:
> > On 30/11/2025 21:17, Andrew Lunn wrote:
> > > On Sun, Nov 30, 2025 at 10:07:31AM +0200, Vladimir Oltean wrote:
> > > > On Sun, Nov 30, 2025 at 02:11:05AM +0100, Andrew Lunn wrote:
> > > > > > -		gpiod_set_value_cansleep(priv->reset, 0);
> > > > > > +		int is_active_low = !!gpiod_is_active_low(priv->reset);
> > > > > > +		gpiod_set_value_cansleep(priv->reset, is_active_low);
> > > > > I think you did not correctly understand what Russell said. You pass
> > > > > the logical value to gpiod_set_value(). If the GPIO has been marked as
> > > > > active LOW, the GPIO core will invert the logical values to the raw
> > > > > value. You should not be using gpiod_is_active_low().
> > > > > 
> > > > > But as i said to the previous patch, i would just leave everything as
> > > > > it is, except document the issue.
> > > > > 
> > > > > 	Andrew
> > > > > 
> > > > It was my suggestion to do it like this (but I don't understand why I'm
> > > > again not in CC).
> > > > 
> > > > We _know_ that the reset pin of the switch should be active low. So by
> > > > using gpiod_is_active_low(), we can determine whether the device tree is
> > > > wrong or not, and we can work with a wrong device tree too (just invert
> > > > the logical values).
> > > Assuming there is not a NOT gate placed between the GPIO and the reset
> > > pin, because the board designer decided to do that for some reason?
> jumping in because i prepare mt7987 / BPI-R4Lite dts for upstreaming when
> driver-changes are in.
> With current driver i need to define the reset-gpio for mt7531 again wrong
> to get it
> working. So to have future dts correct, imho this (or similar) change to
> driver is needed.
> 
> Of course we cannot simply say that current value is wrong and just invert
> it because of
> possible "external" inversion of reset signal between SoC and switch.
> I have to look on schematics for the boards i have (BPI-R64, BPI-R3,
> BPI-R2Pro) if there is such circuit.

I'm also not aware of any board which doesn't directly connect the
reset of the MT7530 to a GPIO pin of the SoC. For MediaTek's designs
there is often even a specific pin desginated for this purpose and
most vendors do follow this. If they deviate at all, then it's just
that a different pin is used for the switch reset, but I've never
seen any logic between the SoC's GPIO pin and the switch reset.

> Maybe the mt7988 (mt7530-mmio) based boards also affected?

There is no GPIO reset for switches which are integrated in the SoC,
so this only matters for external MT7530 and MT7531 ICs for which an
actual GPIO line connected to the SoC is used to reset the switch.


From s-jain1 at ti.com  Tue Dec  2 04:25:15 2025
From: s-jain1 at ti.com (Swamil Jain)
Date: Tue, 2 Dec 2025 17:55:15 +0530
Subject: [PATCH 00/21] Clean and update tilcdc driver to support
 DRM_BRIDGE_ATTACH_NO_CONNECTOR
In-Reply-To: <20251126-feature_tilcdc-v1-0-49b9ef2e3aa0@bootlin.com>
References: <20251126-feature_tilcdc-v1-0-49b9ef2e3aa0@bootlin.com>
Message-ID: <7b8e22d1-a872-4ea0-8fce-4323d2bf81ff@ti.com>

Hi Kory,
Thanks for the series.

On 11/26/25 23:05, Kory Maincent (TI.com) wrote:
> The starting point for this work was adding support for the HDMI cape:
> https://www.seeedstudio.com/Seeed-Studio-BeagleBone-Green-HDMI-Cape.html
> This will be sent in a later series.
> 
> Initially, Miguel proposed modifying the ite-it66121 bridge to support
> the legacy behavior without the DRM_BRIDGE_ATTACH_NO_CONNECTOR flag:
> https://lore.kernel.org/lkml/20250909-it66121-fix-v1-1-bc79ca83df17 at bootlin.com/
> This patch was NAK'd as we don't want to add more legacy code. Maxime
> requested that the tilcdc driver be updated to use
> DRM_BRIDGE_ATTACH_NO_CONNECTOR instead.
> 
> While working on this update, I discovered that the tilcdc driver
> contained significant amounts of legacy code that needed cleaning.
> Since this driver was developed alongside the tda998x driver for
> several AM335x boards, the tda998x driver also required cleanup and
> support for the DRM_BRIDGE_ATTACH_NO_CONNECTOR flag.
> 
> This series is based on the tilcdc fix sent to mainline:
> https://lore.kernel.org/lkml/20251125090546.137193-1-kory.maincent at bootlin.com/
> 
> Patch 1-7: Convert tilcdc binding to YAML and remove the ti,tilcdc,panel
> 	   sub-binding and driver
> Patch 8-16: Clean up tilcdc driver
> Patch 17-19: Clean up tda998x driver
> Patch 20: Add DRM_BRIDGE_ATTACH_NO_CONNECTOR support to tda998x
> Patch 21: Add DRM_BRIDGE_ATTACH_NO_CONNECTOR support to tilcdc
> 
> Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
> ---
> Kory Maincent (TI.com) (21):
>        dt-bindings: display: tilcdc: Convert to DT schema
>        dt-bindings: display: tilcdc: Add fifo-threshold property
>        drm/tilcdc: Remove simulate_vesa_sync flag
>        drm/tilcdc: Add support for DRM bus flags and simplify panel config
>        ARM: dts: omap: Bind panel to panel-dpi instead of ti,tilcdc,panel driver
>        dt-bindings: display: tilcdc: Remove panel binding
>        drm/tilcdc: Remove tilcdc panel driver
>        drm/tilcdc: Remove component framework support
>        drm/tilcdc: Remove tilcdc_panel_info structure
>        drm/tilcdc: Remove redundant #endif/#ifdef in debugfs code
>        drm/tilcdc: Remove unused encoder and connector tracking arrays
>        drm/tilcdc: Rename external_encoder and external_connector to encoder and connector
>        drm/tilcdc: Rename tilcdc_external to tilcdc_encoder
>        drm/tilcdc: Remove the useless module list support
>        drm/tilcdc: Modernize driver initialization and cleanup paths
>        drm/tilcdc: Remove the use of drm_device private_data
>        drm/bridge: tda998x: Remove component support
>        drm/bridge: tda998x: Move tda998x_create/destroy into probe and remove
>        drm/bridge: tda998x: Remove useless tda998x_connector_destroy wrapper
>        drm/bridge: tda998x: Add support for DRM_BRIDGE_ATTACH_NO_CONNECTOR
>        drm/tilcdc: Add support for DRM_BRIDGE_ATTACH_NO_CONNECTOR
> 
>   .../devicetree/bindings/display/tilcdc/panel.txt   |  66 ---
>   .../devicetree/bindings/display/tilcdc/tilcdc.txt  |  82 ----
>   .../devicetree/bindings/display/tilcdc/tilcdc.yaml | 103 +++++
>   arch/arm/boot/dts/ti/davinci/da850-evm.dts         |  26 +-
>   arch/arm/boot/dts/ti/omap/am335x-guardian.dts      |  25 +-
>   arch/arm/boot/dts/ti/omap/am335x-pdu001.dts        |  21 +-
>   arch/arm/boot/dts/ti/omap/am335x-pepper.dts        |  22 +-
>   arch/arm/boot/dts/ti/omap/am335x-sbc-t335.dts      |  25 +-
>   arch/arm/boot/dts/ti/omap/am335x-sl50.dts          |  25 +-
>   drivers/gpu/drm/bridge/tda998x_drv.c               | 251 ++++++------
>   drivers/gpu/drm/tilcdc/Makefile                    |   3 +-
>   drivers/gpu/drm/tilcdc/tilcdc_crtc.c               | 117 ++----
>   drivers/gpu/drm/tilcdc/tilcdc_drv.c                | 456 +++++++--------------
>   drivers/gpu/drm/tilcdc/tilcdc_drv.h                |  88 +---
>   drivers/gpu/drm/tilcdc/tilcdc_encoder.c            |  93 +++++
>   .../tilcdc/{tilcdc_external.h => tilcdc_encoder.h} |   5 +-
>   drivers/gpu/drm/tilcdc/tilcdc_external.c           | 179 --------
>   drivers/gpu/drm/tilcdc/tilcdc_panel.c              | 408 ------------------
>   drivers/gpu/drm/tilcdc/tilcdc_panel.h              |  15 -
>   drivers/gpu/drm/tilcdc/tilcdc_plane.c              |   2 +-
>   drivers/gpu/drm/tilcdc/tilcdc_regs.h               |   8 +-
>   21 files changed, 589 insertions(+), 1431 deletions(-)
> ---
> base-commit: 670bacfc7579bdd79a3069cfb5ab60a6a7923003

I was trying to test the patches, unable to find the base-commit, are
you using drm-misc-next?

Regards,
Swamil.

> change-id: 20251014-feature_tilcdc-79cd49e67bf9
> 
> Best regards,



From leo.yan at arm.com  Tue Dec  2 04:28:35 2025
From: leo.yan at arm.com (Leo Yan)
Date: Tue, 2 Dec 2025 12:28:35 +0000
Subject: [PATCH 7/7] perf arm-spe: Don't hard code config attribute
In-Reply-To: <20251201-james-perf-config-bits-v1-7-22ecbbf8007c@linaro.org>
References: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
 <20251201-james-perf-config-bits-v1-7-22ecbbf8007c@linaro.org>
Message-ID: <20251202122835.GY724103@e132581.arm.com>

On Mon, Dec 01, 2025 at 04:41:10PM +0000, Coresight ML wrote:
> Use the config attribute that's published by the driver instead of
> hard coding "attr.config".
> 
> Signed-off-by: James Clark <james.clark at linaro.org>
> ---
>  tools/perf/arch/arm64/util/arm-spe.c | 15 ++++++++-------
>  1 file changed, 8 insertions(+), 7 deletions(-)
> 
> diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c
> index d5ec1408d0ae..6c3dc97fde30 100644
> --- a/tools/perf/arch/arm64/util/arm-spe.c
> +++ b/tools/perf/arch/arm64/util/arm-spe.c
> @@ -256,7 +256,7 @@ static __u64 arm_spe_pmu__sample_period(const struct perf_pmu *arm_spe_pmu)
>  
>  static void arm_spe_setup_evsel(struct evsel *evsel, struct perf_cpu_map *cpus)
>  {
> -	u64 bit;
> +	u64 pa_enable_bit;
>  
>  	evsel->core.attr.freq = 0;
>  	evsel->core.attr.sample_period = arm_spe_pmu__sample_period(evsel->pmu);
> @@ -288,9 +288,10 @@ static void arm_spe_setup_evsel(struct evsel *evsel, struct perf_cpu_map *cpus)
>  	 * inform that the resulting output's SPE samples contain physical addresses
>  	 * where applicable.
>  	 */
> -	bit = perf_pmu__format_bits(evsel->pmu, "pa_enable");
> -	if (evsel->core.attr.config & bit)
> -		evsel__set_sample_bit(evsel, PHYS_ADDR);
> +
> +	if (!evsel__get_config_val(evsel->pmu, evsel, "pa_enable", &pa_enable_bit))
> +		if (pa_enable_bit)
> +			evsel__set_sample_bit(evsel, PHYS_ADDR);

Hmm... I am a bit concerned for the evsel__get_config_val() usage
throughout the series.

evsel__get_config_val() returns a whole config value rather than the
bit field specified by the format name.  If other bits (but not the
"pa_enable" bit) are set in the same config set, would it wrongly set
the PHYS_ADDR sample bit?

Seems to me, for reading specific format, perf_pmu__format_bits() is
more suitable than evsel__get_config_val().

Thanks,
Leo


From leo.yan at arm.com  Tue Dec  2 04:36:00 2025
From: leo.yan at arm.com (Leo Yan)
Date: Tue, 2 Dec 2025 12:36:00 +0000
Subject: [PATCH 1/7] perf tools: Track all user changed config bits
In-Reply-To: <20251202112147.GT724103@e132581.arm.com>
References: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
 <20251201-james-perf-config-bits-v1-1-22ecbbf8007c@linaro.org>
 <20251202101556.GR724103@e132581.arm.com>
 <978dd9b1-1cb0-4338-95fa-575a858cea80@linaro.org>
 <20251202112147.GT724103@e132581.arm.com>
Message-ID: <20251202123600.GZ724103@e132581.arm.com>

On Tue, Dec 02, 2025 at 11:21:47AM +0000, Coresight ML wrote:
> On Tue, Dec 02, 2025 at 10:40:49AM +0000, James Clark wrote:
> > 
> > 
> > On 02/12/2025 10:15 am, Leo Yan wrote:
> > > On Mon, Dec 01, 2025 at 04:41:04PM +0000, Coresight ML wrote:
> > > 
> > > [...]
> > > 
> > > > +#define ADD_CONFIG_CHG(format_type, term_type, new_term)		\
> > > > +{									\
> > > > +	struct parse_events_term *term;					\
> > > > +	u64 bits = 0;							\
> > > > +	int type;							\
> > > > +									\
> > > > +	list_for_each_entry(term, &head_config->terms, list) {		\
> > > > +		if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER) {  \
> > > > +			type = perf_pmu__format_type(pmu, term->config);\
> > > > +			if (type != format_type)			\
> > > > +				continue;				\
> > > > +			bits |= perf_pmu__format_bits(pmu, term->config); \
> > > > +		} else if (term->type_term == term_type) {		\
> > > > +			bits = ~(u64)0;					\
> > > > +		}							\
> > > > +	}								\
> > > > +									\
> > > > +	if (bits)							\
> > > > +		ADD_CONFIG_TERM_VAL(new_term, cfg_chg, bits, false);	\
> > > > +	return 0;							\
> > > 
> > > Nitpick: "return 0" is not needed here.  Otherwise:
> > > 
> > > Reviewed-by: Leo Yan <leo.yan at arm.com>
> > 
> > I think it's worse than not needed, it makes it stop collecting the changes
> > after the first one.
> 
> Just curious how this can happen.
> 
>   foo()
>   {
>       {
>           chunk 1;
>       }
> 
>       {
>           chunk 2;
>       }
>   }
> 
> Seem to me, if without "return 0" in chunk 1, it still can continue to
> run chunk 2, no?

Please ignore my question above.  We need to iterate from config to
config4, if return 0 when handling config, then never add other
configs?

Thanks,
Leo


From leo.yan at arm.com  Tue Dec  2 04:42:40 2025
From: leo.yan at arm.com (Leo Yan)
Date: Tue, 2 Dec 2025 12:42:40 +0000
Subject: [PATCH 7/7] perf arm-spe: Don't hard code config attribute
In-Reply-To: <20251202122835.GY724103@e132581.arm.com>
References: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
 <20251201-james-perf-config-bits-v1-7-22ecbbf8007c@linaro.org>
 <20251202122835.GY724103@e132581.arm.com>
Message-ID: <20251202124240.GA724103@e132581.arm.com>

On Tue, Dec 02, 2025 at 12:28:35PM +0000, Coresight ML wrote:
> On Mon, Dec 01, 2025 at 04:41:10PM +0000, Coresight ML wrote:
> > Use the config attribute that's published by the driver instead of
> > hard coding "attr.config".
> > 
> > Signed-off-by: James Clark <james.clark at linaro.org>
> > ---
> >  tools/perf/arch/arm64/util/arm-spe.c | 15 ++++++++-------
> >  1 file changed, 8 insertions(+), 7 deletions(-)
> > 
> > diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c
> > index d5ec1408d0ae..6c3dc97fde30 100644
> > --- a/tools/perf/arch/arm64/util/arm-spe.c
> > +++ b/tools/perf/arch/arm64/util/arm-spe.c
> > @@ -256,7 +256,7 @@ static __u64 arm_spe_pmu__sample_period(const struct perf_pmu *arm_spe_pmu)
> >  
> >  static void arm_spe_setup_evsel(struct evsel *evsel, struct perf_cpu_map *cpus)
> >  {
> > -	u64 bit;
> > +	u64 pa_enable_bit;
> >  
> >  	evsel->core.attr.freq = 0;
> >  	evsel->core.attr.sample_period = arm_spe_pmu__sample_period(evsel->pmu);
> > @@ -288,9 +288,10 @@ static void arm_spe_setup_evsel(struct evsel *evsel, struct perf_cpu_map *cpus)
> >  	 * inform that the resulting output's SPE samples contain physical addresses
> >  	 * where applicable.
> >  	 */
> > -	bit = perf_pmu__format_bits(evsel->pmu, "pa_enable");
> > -	if (evsel->core.attr.config & bit)
> > -		evsel__set_sample_bit(evsel, PHYS_ADDR);
> > +
> > +	if (!evsel__get_config_val(evsel->pmu, evsel, "pa_enable", &pa_enable_bit))
> > +		if (pa_enable_bit)
> > +			evsel__set_sample_bit(evsel, PHYS_ADDR);
> 
> Hmm... I am a bit concerned for the evsel__get_config_val() usage
> throughout the series.
> 
> evsel__get_config_val() returns a whole config value rather than the
> bit field specified by the format name.  If other bits (but not the
> "pa_enable" bit) are set in the same config set, would it wrongly set
> the PHYS_ADDR sample bit?

I saw you used FIELD_GET() to read specific bit field in
evsel__get_config_val().  This is not concerned anymore.

Sorry for noise.

> Seems to me, for reading specific format, perf_pmu__format_bits() is
> more suitable than evsel__get_config_val().

For me, this comment is still valid, given perf_pmu__format_bits()
will always exist.

Thanks,
Leo


From linux at armlinux.org.uk  Tue Dec  2 04:43:32 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Tue, 2 Dec 2025 12:43:32 +0000
Subject: [Bug report] hash_name() may cross page boundary and trigger
 sleep in RCU context
In-Reply-To: <CAHk-=wh+cFLLi2x6u61pvL07phSyHPVBTo9Lac2uuqK4eRG_=w@mail.gmail.com>
References: <20251126090505.3057219-1-wozizhi@huaweicloud.com>
 <33ab4aef-020e-49e7-8539-31bf78dac61a@huaweicloud.com>
 <CAHk-=wh1Wfwt9OFB4AfBbjyeu4JVZuSWQ4A8OoT3W6x9btddfw@mail.gmail.com>
 <aSgut4QcBsbXDEo9@shell.armlinux.org.uk>
 <CAHk-=wh+cFLLi2x6u61pvL07phSyHPVBTo9Lac2uuqK4eRG_=w@mail.gmail.com>
Message-ID: <aS7e9CbQXS27sGcd@shell.armlinux.org.uk>

On Fri, Nov 28, 2025 at 09:06:50AM -0800, Linus Torvalds wrote:
> I don't think it's necessarily all that big of a deal. Yeah, this is
> old code, and yeah, it could probably be cleaned up a bit, but at the
> same time, "old and crusty" also means "fairly well tested". This
> whole fault on a kernel address is a fairly unusual case, and as
> mentioned, I *think* the above fix is sufficient.

We have another issue in the code - which has the branch predictor
hardening for spectre issues, which can be called with interrupts
enabled, causing a kernel warning - obviously not good.

There's another issue which PREEMPT_RT has picked up on - which is
that delivering signals via __do_user_fault() with interrupts disabled
causes spinlocks (which can sleep on PREEMPT_RT) to warn.

What I'm thinking is to address both of these by handling kernel space
page faults (which will be permission or PTE-not-present) separately
(not even build tested):

diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 2bc828a1940c..972bce697c6c 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -175,7 +175,8 @@ __do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
 
 /*
  * Something tried to access memory that isn't in our memory map..
- * User mode accesses just cause a SIGSEGV
+ * User mode accesses just cause a SIGSEGV. Ensure interrupts are enabled
+ * here, which is safe as the fault being handled is from userspace.
  */
 static void
 __do_user_fault(unsigned long addr, unsigned int fsr, unsigned int sig,
@@ -183,8 +184,7 @@ __do_user_fault(unsigned long addr, unsigned int fsr, unsigned int sig,
 {
 	struct task_struct *tsk = current;
 
-	if (addr > TASK_SIZE)
-		harden_branch_predictor();
+	local_irq_enable();
 
 #ifdef CONFIG_DEBUG_USER
 	if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) ||
@@ -259,6 +259,38 @@ static inline bool ttbr0_usermode_access_allowed(struct pt_regs *regs)
 }
 #endif
 
+static int __kprobes
+do_kernel_address_page_fault(unsigned long addr, unsigned int fsr,
+			     struct pt_regs *regs)
+{
+	if (user_mode(regs)) {
+		/*
+		 * Fault from user mode for a kernel space address. User mode
+		 * should not be faulting in kernel space, which includes the
+		 * vector/khelper page. Handle the Spectre issues while
+		 * interrupts are still disabled, then send a SIGSEGV. Note
+		 * that __do_user_fault() will enable interrupts.
+		 */
+		harden_branch_predictor();
+		__do_user_fault(addr, fsr, SIGSEGV, SEGV_MAPERR, regs);
+	} else {
+		/*
+		 * Fault from kernel mode. Enable interrupts if they were
+		 * enabled in the parent context. Section (upper page table)
+		 * translation faults are handled via do_translation_fault(),
+		 * so we will only get here for a non-present kernel space
+		 * PTE or kernel space permission fault. Both of these should
+		 * not happen.
+		 */
+		if (interrupts_enabled(regs))
+			local_irq_enable();
+
+		__do_kernel_fault(mm, addr, fsr, regs);
+	}
+
+	return 0;
+}
+
 static int __kprobes
 do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 {
@@ -272,6 +304,8 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 	if (kprobe_page_fault(regs, fsr))
 		return 0;
 
+	if (addr >= TASK_SIZE)
+		return do_kernel_address_page_fault(addr, fsr, regs);
 
 	/* Enable interrupts if they were enabled in the parent context. */
 	if (interrupts_enabled(regs))

... and I think there was a bug in the branch predictor handling -
addr == TASK_SIZE should have been included.

Does this look sensible?

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From charan.kalla at oss.qualcomm.com  Tue Dec  2 04:54:47 2025
From: charan.kalla at oss.qualcomm.com (Charan Teja Kalla)
Date: Tue,  2 Dec 2025 18:24:47 +0530
Subject: [PATCH V4] iommu/arm-smmu: add actlr settings for mdss on Qualcomm platforms
Message-ID: <20251202125447.2102658-1-charan.kalla@oss.qualcomm.com>

Add ACTLR settings for missing MDSS devices on Qualcomm platforms.

These are QoS settings and are specific to per SoC thus different
settings, eg: some have shallow prefetch while others have no
prefetch.

Aswell, this prefetch feature is not implemented for all the
platforms, capturing to those are implemented to the best of my
knowledge.

Signed-off-by: Charan Teja Kalla <charan.kalla at oss.qualcomm.com>
---
Changes from V3:
 1) Add actlr setting for missing sc8180x & sm6115.
 2) Improved commit message.
https://lore.kernel.org/all/20251124171030.323989-1-charan.kalla at oss.qualcomm.com/

Changes from V2:
 1) Add actlr settings for all the mdss devices on Qualcomm platforms.
 2) Improved the commit message that explain why different ACTLR
    settings
https://lore.kernel.org/lkml/20251118171822.3539062-1-charan.kalla at oss.qualcomm.com/#t

Changes from V1:
  1) Added actlr setting only for MDSS and dropped for fastrpc. --
konrad
  2) ACTLR table is updated per alphanumeric order -- konrad 
  https://lore.kernel.org/all/20251105075307.1658329-1-charan.kalla at oss.qualcomm.com/

 drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 26 ++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
index c21a401c71eb..149da53091de 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
@@ -41,12 +41,38 @@ static const struct of_device_id qcom_smmu_actlr_client_of_match[] = {
 			.data = (const void *) (PREFETCH_DEEP | CPRE | CMTLB) },
 	{ .compatible = "qcom,fastrpc",
 			.data = (const void *) (PREFETCH_DEEP | CPRE | CMTLB) },
+	{ .compatible = "qcom,qcm2290-mdss",
+			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
 	{ .compatible = "qcom,sc7280-mdss",
 			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
 	{ .compatible = "qcom,sc7280-venus",
 			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
+	{ .compatible = "qcom,sc8180x-mdss",
+			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
+	{ .compatible = "qcom,sc8280xp-mdss",
+			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
+	{ .compatible = "qcom,sm6115-mdss",
+			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
+	{ .compatible = "qcom,sm6125-mdss",
+			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
+	{ .compatible = "qcom,sm6350-mdss",
+			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
+	{ .compatible = "qcom,sm8150-mdss",
+			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
+	{ .compatible = "qcom,sm8250-mdss",
+			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
+	{ .compatible = "qcom,sm8350-mdss",
+			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
+	{ .compatible = "qcom,sm8450-mdss",
+			.data = (const void *) (PREFETCH_DEFAULT | CMTLB) },
 	{ .compatible = "qcom,sm8550-mdss",
 			.data = (const void *) (PREFETCH_DEFAULT | CMTLB) },
+	{ .compatible = "qcom,sm8650-mdss",
+			.data = (const void *) (PREFETCH_DEFAULT | CMTLB) },
+	{ .compatible = "qcom,sm8750-mdss",
+			.data = (const void *) (PREFETCH_DEFAULT | CMTLB) },
+	{ .compatible = "qcom,x1e80100-mdss",
+			.data = (const void *) (PREFETCH_DEFAULT | CMTLB) },
 	{ }
 };
 
-- 
2.34.1



From kory.maincent at bootlin.com  Tue Dec  2 04:56:05 2025
From: kory.maincent at bootlin.com (Kory Maincent)
Date: Tue, 2 Dec 2025 13:56:05 +0100
Subject: [PATCH 05/21] ARM: dts: omap: Bind panel to panel-dpi instead
 of ti,tilcdc,panel driver
In-Reply-To: <1d9a9269-bfda-4d43-938b-2df6b82b9369@ideasonboard.com>
References: <20251126-feature_tilcdc-v1-0-49b9ef2e3aa0@bootlin.com>
	<20251126-feature_tilcdc-v1-5-49b9ef2e3aa0@bootlin.com>
	<96b1b7bf-ddbe-4213-a201-dc89cf2998dd@ideasonboard.com>
	<3bc5bf92-05c3-4841-ab28-9bab2bb31cd5@kernel.org>
	<20251202104244.59a9e83d@kmaincent-XPS-13-7390>
	<d7515cd3-5488-4d15-82dc-d2b98cfa2bed@kernel.org>
	<20251202114416.09624a4b@kmaincent-XPS-13-7390>
	<94e254fa-289d-41ed-909f-1742cfbb2690@kernel.org>
	<20251202121856.0da62885@kmaincent-XPS-13-7390>
	<1d9a9269-bfda-4d43-938b-2df6b82b9369@ideasonboard.com>
Message-ID: <20251202135605.053ada96@kmaincent-XPS-13-7390>

On Tue, 2 Dec 2025 13:51:59 +0200
Tomi Valkeinen <tomi.valkeinen at ideasonboard.com> wrote:

> Hi Kory,
> 
> On 02/12/2025 13:18, Kory Maincent wrote:
> > On Tue, 2 Dec 2025 11:47:40 +0100
> > Krzysztof Kozlowski <krzk at kernel.org> wrote:

> I will not NAK, removing bindings and breaking users is under some
> conditions acceptable. You just need to come with the reasons and impact.
> 
> Reason "is ugly" is usually not good enough. Especially if things were
> working.

Thanks for you reply.

> >>
> >> DTS cannot go to drm, which means you either need to separate the change
> >> and make entire work bisectable and backwards compatible for some time
> >> OR at least document clearly the impact as we always ask.  
> > 
> > The thing is, if I split it, it has to be in 3. One for the of DRM bus flags
> > support, a second for the the devicetree and binding change and a third for
> > the whole tilcdc and tda998x cleaning stuff. I think I will go for one
> > series, with better documentation.
> > 
> > Now, what is your point of view on my question. Will you nak any binding
> > removal even if the binding is ugly and legacy and imply maintaining an
> > non-standard tilcdc panel driver? I know it breaks DTB compatibility but
> > there is several argument to not keep it. See patch 6.  
> The binding being ugly and having to maintain non-standard tilcdc panel
> driver may be nice things for us, the users don't care. The users care
> if their board no longer works.

Yes I understand but then I have another question. At what cost should we
continue to support legacy binding?

Just figured out this case already happened, ti,tilcdc,slave binding was
removed from the tilcdc driver:
739acd85ffdb7 ("drm/tilcdc: Remove obsolete "ti,tilcdc,slave" dts binding
support")

Even if there is still one mainline device tree that uses it:
am335x-base0033.dts. :/

> And how does this sync with u-boot? It also has code for at least for a
> few of these boards.

U-boot has indeed a driver for the ti,tilcdc,panel binding.
Changing this devicetree would beak display for these board in U-boot as it
currently does not support the "panel-dpi" binding.

> Are there even users for these boards? If not, maybe they can be just
> removed? I'm personally not familiar with these boards, so I have no
> idea of their age or distribution.

These boards are quite old (>10 years) but I don't know if they are still used
by people. After a quick look they seem not available on the market.

> One trick that can be done is to modify the loaded DTB at boot time,
> detecting the old format, converting it to the new one, so that when the
> drivers are probed they only see the new DTB.

Yes, indeed that could do the trick. The things is, I don't have one of
theses board to test it. I will try to look for an other way to test it.

Regards,
-- 
K?ry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com


From james.clark at linaro.org  Tue Dec  2 04:59:46 2025
From: james.clark at linaro.org (James Clark)
Date: Tue, 2 Dec 2025 12:59:46 +0000
Subject: [PATCH 7/7] perf arm-spe: Don't hard code config attribute
In-Reply-To: <20251202124240.GA724103@e132581.arm.com>
References: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
 <20251201-james-perf-config-bits-v1-7-22ecbbf8007c@linaro.org>
 <20251202122835.GY724103@e132581.arm.com>
 <20251202124240.GA724103@e132581.arm.com>
Message-ID: <653a7555-18e6-4066-993d-412a63a63f51@linaro.org>



On 02/12/2025 12:42 pm, Leo Yan wrote:
> On Tue, Dec 02, 2025 at 12:28:35PM +0000, Coresight ML wrote:
>> On Mon, Dec 01, 2025 at 04:41:10PM +0000, Coresight ML wrote:
>>> Use the config attribute that's published by the driver instead of
>>> hard coding "attr.config".
>>>
>>> Signed-off-by: James Clark <james.clark at linaro.org>
>>> ---
>>>   tools/perf/arch/arm64/util/arm-spe.c | 15 ++++++++-------
>>>   1 file changed, 8 insertions(+), 7 deletions(-)
>>>
>>> diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c
>>> index d5ec1408d0ae..6c3dc97fde30 100644
>>> --- a/tools/perf/arch/arm64/util/arm-spe.c
>>> +++ b/tools/perf/arch/arm64/util/arm-spe.c
>>> @@ -256,7 +256,7 @@ static __u64 arm_spe_pmu__sample_period(const struct perf_pmu *arm_spe_pmu)
>>>   
>>>   static void arm_spe_setup_evsel(struct evsel *evsel, struct perf_cpu_map *cpus)
>>>   {
>>> -	u64 bit;
>>> +	u64 pa_enable_bit;
>>>   
>>>   	evsel->core.attr.freq = 0;
>>>   	evsel->core.attr.sample_period = arm_spe_pmu__sample_period(evsel->pmu);
>>> @@ -288,9 +288,10 @@ static void arm_spe_setup_evsel(struct evsel *evsel, struct perf_cpu_map *cpus)
>>>   	 * inform that the resulting output's SPE samples contain physical addresses
>>>   	 * where applicable.
>>>   	 */
>>> -	bit = perf_pmu__format_bits(evsel->pmu, "pa_enable");
>>> -	if (evsel->core.attr.config & bit)
>>> -		evsel__set_sample_bit(evsel, PHYS_ADDR);
>>> +
>>> +	if (!evsel__get_config_val(evsel->pmu, evsel, "pa_enable", &pa_enable_bit))
>>> +		if (pa_enable_bit)
>>> +			evsel__set_sample_bit(evsel, PHYS_ADDR);
>>
>> Hmm... I am a bit concerned for the evsel__get_config_val() usage
>> throughout the series.
>>
>> evsel__get_config_val() returns a whole config value rather than the
>> bit field specified by the format name.  If other bits (but not the
>> "pa_enable" bit) are set in the same config set, would it wrongly set
>> the PHYS_ADDR sample bit?
> 
> I saw you used FIELD_GET() to read specific bit field in
> evsel__get_config_val().  This is not concerned anymore.
> 
> Sorry for noise.
> 
>> Seems to me, for reading specific format, perf_pmu__format_bits() is
>> more suitable than evsel__get_config_val().
> 
> For me, this comment is still valid, given perf_pmu__format_bits()
> will always exist.
> 

perf_pmu__format_bits() only returns the mask for the format attribute 
that's published by the kernel. It never changes depending on what 
options the user provides and doesn't even say which config field that 
mask applies to. It's fairly useless on its own and should probably be 
made private to pmu.c if we manage to refactor its uses out of 
intel-pt.c. Although they're a bit more involved there than here so I 
won't touch it now.

evsel__get_config_val() returns the value that the user provided for a 
named attribute which is what we need to do here.

> Thanks,
> Leo



From krzk at kernel.org  Tue Dec  2 05:00:39 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 2 Dec 2025 14:00:39 +0100
Subject: [PATCH 1/6] dt-bindings: power: supply: Add Maxim MAX77759
 charger
In-Reply-To: <7ad91325-e881-461d-b39e-6ff15d98b3c5@google.com>
References: <20251123-max77759-charger-v1-0-6b2e4b8f7f54@google.com>
 <20251123-max77759-charger-v1-1-6b2e4b8f7f54@google.com>
 <d4455f4b-2a0f-4bc0-b897-14f2e27af3ea@kernel.org>
 <c9b059f8-9219-4219-95c8-23a3733fea58@google.com>
 <20251125-amorphous-bobcat-of-whirlwind-afdab1@kuoka>
 <7ad91325-e881-461d-b39e-6ff15d98b3c5@google.com>
Message-ID: <076777c3-b238-4d1d-a11b-602027348ee4@kernel.org>

On 26/11/2025 00:48, Amit Sunil Dhamne wrote:
> 
> On 11/25/25 1:56 AM, Krzysztof Kozlowski wrote:
>> On Sun, Nov 23, 2025 at 06:34:05PM -0800, Amit Sunil Dhamne wrote:
>>> Hi Krzysztof,
>>>
>>> On 11/23/25 1:28 AM, Krzysztof Kozlowski wrote:
>>>> On 23/11/2025 09:35, Amit Sunil Dhamne via B4 Relay wrote:
>>>>> From: Amit Sunil Dhamne <amitsd at google.com>
>>>>>
>>>>> Add bindings for Maxim max77759 charger device.
>>>>>
>>>>> Signed-off-by: Amit Sunil Dhamne <amitsd at google.com>
>>>>> ---
>>>>>   .../power/supply/maxim,max77759-charger.yaml       | 36 ++++++++++++++++++++++
>>>>>   1 file changed, 36 insertions(+)
>>>>>
>>>>> diff --git a/Documentation/devicetree/bindings/power/supply/maxim,max77759-charger.yaml b/Documentation/devicetree/bindings/power/supply/maxim,max77759-charger.yaml
>>>>> new file mode 100644
>>>>> index 000000000000..71f866419774
>>>>> --- /dev/null
>>>>> +++ b/Documentation/devicetree/bindings/power/supply/maxim,max77759-charger.yaml
>>>>> @@ -0,0 +1,36 @@
>>>>> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
>>>>> +%YAML 1.2
>>>>> +---
>>>>> +$id: http://devicetree.org/schemas/power/supply/maxim,max77759-charger.yaml#
>>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>>>> +
>>>>> +title: Maxim Integrated MAX77759 Battery charger
>>>>> +
>>>>> +maintainers:
>>>>> +  - Amit Sunil Dhamne <amitsd at google.com>
>>>>> +
>>>>> +description: |
>>>>> +  This module is part of the MAX77759 PMIC. For additional information, see
>>>>> +  Documentation/devicetree/bindings/mfd/maxim,max77759.yaml.
>>>>> +
>>>>> +  The Maxim MAX77759 is a dual input switch mode battery charger for portable
>>>>> +  applications. It supports wired and wireless charging and can operate in buck
>>>>> +  and boost mode.
>>>>> +
>>>>> +allOf:
>>>>> +  - $ref: power-supply.yaml#
>>>>> +
>>>>> +properties:
>>>>> +  compatible:
>>>>> +    const: maxim,max77759-charger
>>>>> +
>>>> This should be just folded into parent node, no need for separate
>>>> charger device or is just incomplete.
>>> Thanks for the review! You are right, the binding is incomplete. This
>>> charger block actually listens on its own I2C address, distinct from the
>>> main PMIC.
>>>
>>> I will update v2 to include the reg property. I will also add the
>> AFAIK, the main (parent) device schema does not reference children via
>> any sort of addressing, so reg here would not be suitable.
> 
> I agree that currently nvmem and gpio devices (which are children of 
> PMIC device) are not referenced using any address. But I was guessing 
> that's because they share the i2c client id with the PMIC and sharing 
> its address space (implied).
> 
> The charger device while being part of the MAX77759 PMIC package has 
> it's own i2c client id and address space that's why I proposed "reg". 
> The underlying assumption I made was separate client id implies that a 
> "reg" property required. But maybe that's incorrect.
> 
> I can understand the argument against having a "reg" property. As the 
> i2c client id will remain same for a max77759 charger device (as it's a 
> chip property and not a board property) it will always remain a 
> constant. I will drop the "reg" proposal.
> 
> 
>>
>>> standard properties `constant-charge-current-max-microamp` and
>>> `constant-charge-voltage-max-microvolt` to configure the hardware
>>> limits, as this charger device does not manage the battery profile
>>> directly (that is handled by a separate fuel gauge).
>> Well, still, what's the benefit for the bindings to have it as a
>> separate child? Kind of depends on your example, which is quite small -
>> one regulator and supply. Grow the example with battery and other
>> independent resources (if they are) to justify it. Or show arguments why
>> this is re-usable.
> 
> The primary reasons for keeping the charger as a distinct child node are 
> to model the hardware topology for the power supply subsystem and to 

You do not need children for that at all.

> house the OTG regulator provided by the charger block.
> The charger needs to be referenced by the Fuel Gauge (which handles the 
> battery profile) via power-supplies. Additionally, the charger block 
> provides a regulator for USB OTG VBUS, which is cleaner to represent as 
> a child node of the charger rather than mixing it into the top-level 
> PMIC node.

Sorry but argument that you need a child device to be able to construct
a phandle is just wrong. You can create phandles on every other way as well.


Best regards,
Krzysztof


From pabeni at redhat.com  Tue Dec  2 05:03:27 2025
From: pabeni at redhat.com (Paolo Abeni)
Date: Tue, 2 Dec 2025 14:03:27 +0100
Subject: [PATCH net-next v21 02/14] net: ethtool: Introduce
 ETHTOOL_LINK_MEDIUM_* values
In-Reply-To: <20251129082228.454678-3-maxime.chevallier@bootlin.com>
References: <20251129082228.454678-1-maxime.chevallier@bootlin.com>
 <20251129082228.454678-3-maxime.chevallier@bootlin.com>
Message-ID: <298e982d-7796-4e46-ad1d-a7f57c573f35@redhat.com>

On 11/29/25 9:22 AM, Maxime Chevallier wrote:
> @@ -298,138 +321,149 @@ static_assert(ARRAY_SIZE(link_mode_names) == __ETHTOOL_LINK_MODE_MASK_NBITS);
>  		.speed	= SPEED_UNKNOWN, \
>  		.lanes	= 0, \
>  		.duplex	= DUPLEX_UNKNOWN, \
> +		.mediums = BIT(ETHTOOL_LINK_MEDIUM_NONE), \
>  	}
>  
>  const struct link_mode_info link_mode_params[] = {
> -	__DEFINE_LINK_MODE_PARAMS(10, T, Half),
> -	__DEFINE_LINK_MODE_PARAMS(10, T, Full),
> -	__DEFINE_LINK_MODE_PARAMS(100, T, Half),
> -	__DEFINE_LINK_MODE_PARAMS(100, T, Full),
> -	__DEFINE_LINK_MODE_PARAMS(1000, T, Half),
> -	__DEFINE_LINK_MODE_PARAMS(1000, T, Full),
> +	__DEFINE_LINK_MODE_PARAMS_PAIRS(10, T, 2, 4, Half, T),
> +	__DEFINE_LINK_MODE_PARAMS_PAIRS(10, T, 2, 4, Full, T),
> +	__DEFINE_LINK_MODE_PARAMS_PAIRS(100, T, 2, 4, Half, T),
> +	__DEFINE_LINK_MODE_PARAMS_PAIRS(100, T, 2, 4, Full, T),
> +	__DEFINE_LINK_MODE_PARAMS_PAIRS(1000, T, 4, 4, Half, T),
> +	__DEFINE_LINK_MODE_PARAMS_PAIRS(1000, T, 4, 4, Full, T),
>  	__DEFINE_SPECIAL_MODE_PARAMS(Autoneg),
>  	__DEFINE_SPECIAL_MODE_PARAMS(TP),
>  	__DEFINE_SPECIAL_MODE_PARAMS(AUI),
>  	__DEFINE_SPECIAL_MODE_PARAMS(MII),
>  	__DEFINE_SPECIAL_MODE_PARAMS(FIBRE),
>  	__DEFINE_SPECIAL_MODE_PARAMS(BNC),
> -	__DEFINE_LINK_MODE_PARAMS(10000, T, Full),
> +	__DEFINE_LINK_MODE_PARAMS_PAIRS(10000, T, 4, 4, Full, T),
>  	__DEFINE_SPECIAL_MODE_PARAMS(Pause),
>  	__DEFINE_SPECIAL_MODE_PARAMS(Asym_Pause),
> -	__DEFINE_LINK_MODE_PARAMS(2500, X, Full),
> +	__DEFINE_LINK_MODE_PARAMS_MEDIUMS(2500, X, Full,
> +					  __MED(C) | __MED(S) | __MED(L)),
>  	__DEFINE_SPECIAL_MODE_PARAMS(Backplane),
> -	__DEFINE_LINK_MODE_PARAMS(1000, KX, Full),
> -	__DEFINE_LINK_MODE_PARAMS(10000, KX4, Full),
> -	__DEFINE_LINK_MODE_PARAMS(10000, KR, Full),
> +	__DEFINE_LINK_MODE_PARAMS(1000, KX, Full, K),
> +	__DEFINE_LINK_MODE_PARAMS(10000, KX4, Full, K),
> +	__DEFINE_LINK_MODE_PARAMS(10000, KR, Full, K),
>  	[ETHTOOL_LINK_MODE_10000baseR_FEC_BIT] = {
>  		.speed	= SPEED_10000,
>  		.lanes	= 1,
>  		.duplex = DUPLEX_FULL,

The AI review points that medium is not initialized here:

https://netdev-ai.bots.linux.dev/ai-review.html?id=437cd013-c6a6-49e1-bec1-de4869930c7a#patch-1

Is that intentional? It should deserve at least an explanation in the
commit message.

Somewhat related, AI raised on the first patch the same question raised
on a previous iteration, and I assumed you considered that valid,
according to:

https://lore.kernel.org/netdev/f753719e-2370-401d-a001-821bdd5ee838 at bootlin.com/

Otherwise I think some wording in the commit message explaining why the
AI feedback is incorrect would be useful.

/P



From xieyuanbin1 at huawei.com  Tue Dec  2 05:02:24 2025
From: xieyuanbin1 at huawei.com (Xie Yuanbin)
Date: Tue, 2 Dec 2025 21:02:24 +0800
Subject: [Bug report] hash_name() may cross page boundary and trigger sleep in RCU context
In-Reply-To: <aS7e9CbQXS27sGcd@shell.armlinux.org.uk>
References: <aS7e9CbQXS27sGcd@shell.armlinux.org.uk>
Message-ID: <20251202130224.16376-1-xieyuanbin1@huawei.com>

On Tue, 2 Dec 2025 12:43:32 +0000, Russell King (Oracle) wrote:
> We have another issue in the code - which has the branch predictor
> hardening for spectre issues, which can be called with interrupts
> enabled, causing a kernel warning - obviously not good.
>
> There's another issue which PREEMPT_RT has picked up on - which is
> that delivering signals via __do_user_fault() with interrupts disabled
> causes spinlocks (which can sleep on PREEMPT_RT) to warn.
>
> What I'm thinking is to address both of these by handling kernel space
> page faults (which will be permission or PTE-not-present) separately
> (not even build tested):
>
> diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
> index 2bc828a1940c..972bce697c6c 100644
> --- a/arch/arm/mm/fault.c
> +++ b/arch/arm/mm/fault.c
> @@ -175,7 +175,8 @@ __do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
>
>  /*
>   * Something tried to access memory that isn't in our memory map..
> - * User mode accesses just cause a SIGSEGV
> + * User mode accesses just cause a SIGSEGV. Ensure interrupts are enabled
> + * here, which is safe as the fault being handled is from userspace.
>   */
>  static void
>  __do_user_fault(unsigned long addr, unsigned int fsr, unsigned int sig,
> @@ -183,8 +184,7 @@ __do_user_fault(unsigned long addr, unsigned int fsr, unsigned int sig,
>  {
>  	struct task_struct *tsk = current;
> 
> -	if (addr > TASK_SIZE)
> -		harden_branch_predictor();
> +	local_irq_enable();
>
>  #ifdef CONFIG_DEBUG_USER
>  	if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) ||
> @@ -259,6 +259,38 @@ static inline bool ttbr0_usermode_access_allowed(struct pt_regs *regs)
>  }
>  #endif
>
> +static int __kprobes
> +do_kernel_address_page_fault(unsigned long addr, unsigned int fsr,
> +			     struct pt_regs *regs)
> +{
> +	if (user_mode(regs)) {
> +		/*
> +		 * Fault from user mode for a kernel space address. User mode
> +		 * should not be faulting in kernel space, which includes the
> +		 * vector/khelper page. Handle the Spectre issues while
> +		 * interrupts are still disabled, then send a SIGSEGV. Note
> +		 * that __do_user_fault() will enable interrupts.
> +		 */
> +		harden_branch_predictor();
> +		__do_user_fault(addr, fsr, SIGSEGV, SEGV_MAPERR, regs);
> +	} else {
> +		/*
> +		 * Fault from kernel mode. Enable interrupts if they were
> +		 * enabled in the parent context. Section (upper page table)
> +		 * translation faults are handled via do_translation_fault(),
> +		 * so we will only get here for a non-present kernel space
> +		 * PTE or kernel space permission fault. Both of these should
> +		 * not happen.
> +		 */
> +		if (interrupts_enabled(regs))
> +			local_irq_enable();
> +
> +		__do_kernel_fault(mm, addr, fsr, regs);
> +	}
> +
> +	return 0;
> +}
> +
>  static int __kprobes
>  do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
>  {
> @@ -272,6 +304,8 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
>  	if (kprobe_page_fault(regs, fsr))
>  		return 0;
>
> +	if (addr >= TASK_SIZE)
> +		return do_kernel_address_page_fault(addr, fsr, regs);
>
>  	/* Enable interrupts if they were enabled in the parent context. */
>  	if (interrupts_enabled(regs))
>
> ... and I think there was a bug in the branch predictor handling -
> addr == TASK_SIZE should have been included.
>
> Does this look sensible?

Hi, Russell King!

This patch removes
```c
	if (addr > TASK_SIZE)
		harden_branch_predictor();
```
from do_user_fault(), and adds it to do_page_fault()->
do_kernel_address_page_fault().

However, do_user_fault() is not only called by do_page_fault(). It is
also called by do_bad_area(), do_sect_fault() and do_translation_fault().
I am not sure that if this will lead to some missing
harden_branch_predictor() mitigation.

What about something like this:
```patch
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 2bc828a1940c..5c58072d8235 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -270,10 +270,15 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 	vm_flags_t vm_flags = VM_ACCESS_FLAGS;

 	if (kprobe_page_fault(regs, fsr))
 		return 0;

+	if (unlikely(addr >= TASK_SIZE)) {
+		fault = 0;
+		code = SEGV_MAPERR;
+		goto bad_area;
+	}

 	/* Enable interrupts if they were enabled in the parent context. */
 	if (interrupts_enabled(regs))
 		local_irq_enable();
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 5c58072d8235..f8ee1854c854 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -184,10 +184,13 @@ __do_user_fault(unsigned long addr, unsigned int fsr, unsigned int sig,
 	struct task_struct *tsk = current;
 
 	if (addr > TASK_SIZE)
 		harden_branch_predictor();
 
+	if (IS_ENABLED(CONFIG_PREEMPT_RT))
+		local_irq_enable();
+
 #ifdef CONFIG_DEBUG_USER
 	if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) ||
 	    ((user_debug & UDBG_BUS)  && (sig == SIGBUS))) {
 		pr_err("8<--- cut here ---\n");
 		pr_err("%s: unhandled page fault (%d) at 0x%08lx, code 0x%03x\n",
```

Thanks very much!

Xie Yuanbin


From marco.crivellari at suse.com  Tue Dec  2 05:18:30 2025
From: marco.crivellari at suse.com (Marco Crivellari)
Date: Tue, 2 Dec 2025 14:18:30 +0100
Subject: [PATCH 0/2] rename system_wq and system_unbound_wq
In-Reply-To: <20251031104846.119503-1-marco.crivellari@suse.com>
References: <20251031104846.119503-1-marco.crivellari@suse.com>
Message-ID: <CAAofZF7BnLm3XKBVsOvAcfON29PgxvA4dfkd4N4+yx40LSTV-A@mail.gmail.com>

Hi,

On Fri, Oct 31, 2025 at 11:48?AM Marco Crivellari
<marco.crivellari at suse.com> wrote:
> Marco Crivellari (2):
>   drm/rockchip: replace use of system_unbound_wq with system_dfl_wq
>   drm/rockchip: replace use of system_wq with system_percpu_wq
>
>  drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 4 ++--
>  drivers/gpu/drm/rockchip/rockchip_drm_vop.c    | 2 +-
>  2 files changed, 3 insertions(+), 3 deletions(-)

Gentle ping about this.

Thanks!

-- 

Marco Crivellari

L3 Support Engineer, Technology & Product


From m.felsch at pengutronix.de  Tue Dec  2 05:21:04 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Tue, 02 Dec 2025 14:21:04 +0100
Subject: [PATCH v2 3/3] pmdomain: imx93-blk-ctrl: add support for optional
 subnodes
In-Reply-To: <20251202-v6-18-topic-imx93-blkctrl-v2-0-e73501034adc@pengutronix.de>
References: <20251202-v6-18-topic-imx93-blkctrl-v2-0-e73501034adc@pengutronix.de>
Message-ID: <20251202-v6-18-topic-imx93-blkctrl-v2-3-e73501034adc@pengutronix.de>

This particular block can have DT subnodes describing the LVDS LDB, MIPI
DSI and parallel DPI bridge.

Scan for possible sub-devices within the driver, instead of misusing the
simple-bus to perform the scan.

Reviewed-by: Alexander Stein <alexander.stein at ew.tq-group.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
---
 drivers/pmdomain/imx/imx93-blk-ctrl.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/pmdomain/imx/imx93-blk-ctrl.c b/drivers/pmdomain/imx/imx93-blk-ctrl.c
index 49610f2389c3bbaf4de4133918fbcacb7924f672..1afc78b034fad8fa09a3e8527586387156fc2543 100644
--- a/drivers/pmdomain/imx/imx93-blk-ctrl.c
+++ b/drivers/pmdomain/imx/imx93-blk-ctrl.c
@@ -7,6 +7,7 @@
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/pm_domain.h>
 #include <linux/pm_runtime.h>
@@ -313,6 +314,10 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
 	if (ret)
 		return dev_err_probe(dev, ret, "failed to add genpd_provider release callback\n");
 
+	ret = devm_of_platform_populate(dev);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to populate blk-ctrl sub-devices\n");
+
 	return 0;
 }
 

-- 
2.47.3



From m.felsch at pengutronix.de  Tue Dec  2 05:21:01 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Tue, 02 Dec 2025 14:21:01 +0100
Subject: [PATCH v2 0/3] i.MX91/93 BLK-CTRL improvements
Message-ID: <20251202-v6-18-topic-imx93-blkctrl-v2-0-e73501034adc@pengutronix.de>

Hi,

there were several approaches to bring the sub-devices population
mainline [1,2] but non of them made it upstream. Both approaches were
part of either the i.MX93 LVDS or MIPI-CSI enablement.

This small patchset decouples the blk-ctrl changes which allows the
MIPI-CSI and LVDS patchstack to be rebased ontop of this patchset.

Before adding the sub-device supprt, I converted the driver to devm_*
only API.

Regards,
  Marco

[1] https://lore.kernel.org/all/20250701-95_cam-v1-3-c5172bab387b at nxp.com/
[2] https://lore.kernel.org/all/20250304154929.1785200-4-alexander.stein at ew.tq-group.com/

---
Changes in v2:
- Link to v1: https://lore.kernel.org/r/20251201-v6-18-topic-imx93-blkctrl-v1-0-b57a72e60105 at pengutronix.de
- Adapt patch2 commit message (Frank)
- Check devm_pm_runtime_enable() return (Frank)
- Add r-b tags (Frank, Alexander)

---
Marco Felsch (3):
      pmdomain: imx93-blk-ctrl: cleanup error path
      pmdomain: imx93-blk-ctrl: convert to devm_* only
      pmdomain: imx93-blk-ctrl: add support for optional subnodes

 drivers/pmdomain/imx/imx93-blk-ctrl.c | 77 ++++++++++++++++-------------------
 1 file changed, 36 insertions(+), 41 deletions(-)
---
base-commit: 3a8660878839faadb4f1a6dd72c3179c1df56787
change-id: 20251201-v6-18-topic-imx93-blkctrl-341220f7084d

Best regards,
-- 
Marco Felsch <m.felsch at pengutronix.de>



From m.felsch at pengutronix.de  Tue Dec  2 05:21:02 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Tue, 02 Dec 2025 14:21:02 +0100
Subject: [PATCH v2 1/3] pmdomain: imx93-blk-ctrl: cleanup error path
In-Reply-To: <20251202-v6-18-topic-imx93-blkctrl-v2-0-e73501034adc@pengutronix.de>
References: <20251202-v6-18-topic-imx93-blkctrl-v2-0-e73501034adc@pengutronix.de>
Message-ID: <20251202-v6-18-topic-imx93-blkctrl-v2-1-e73501034adc@pengutronix.de>

Call dev_err_probe() directly during return to make the code more
compact.

Reviewed-by: Alexander Stein <alexander.stein at ew.tq-group.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
---
 drivers/pmdomain/imx/imx93-blk-ctrl.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/pmdomain/imx/imx93-blk-ctrl.c b/drivers/pmdomain/imx/imx93-blk-ctrl.c
index e094fe5a42bf646c712f3eca4e66a313fa5a914c..2aa163aef8de4ee901b9cde76ce2aad246c8c08a 100644
--- a/drivers/pmdomain/imx/imx93-blk-ctrl.c
+++ b/drivers/pmdomain/imx/imx93-blk-ctrl.c
@@ -240,10 +240,8 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
 	bc->num_clks = bc_data->num_clks;
 
 	ret = devm_clk_bulk_get(dev, bc->num_clks, bc->clks);
-	if (ret) {
-		dev_err_probe(dev, ret, "failed to get bus clock\n");
-		return ret;
-	}
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to get bus clock\n");
 
 	for (i = 0; i < bc_data->num_domains; i++) {
 		const struct imx93_blk_ctrl_domain_data *data = &bc_data->domains[i];

-- 
2.47.3



From m.felsch at pengutronix.de  Tue Dec  2 05:21:03 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Tue, 02 Dec 2025 14:21:03 +0100
Subject: [PATCH v2 2/3] pmdomain: imx93-blk-ctrl: convert to devm_* only
In-Reply-To: <20251202-v6-18-topic-imx93-blkctrl-v2-0-e73501034adc@pengutronix.de>
References: <20251202-v6-18-topic-imx93-blkctrl-v2-0-e73501034adc@pengutronix.de>
Message-ID: <20251202-v6-18-topic-imx93-blkctrl-v2-2-e73501034adc@pengutronix.de>

Convert the driver to devm_ APIs only by making use of
devm_add_action_or_reset() and devm_pm_runtime_enable() to simplify the
probe error path and to drop the .remove() callback. This also ensures
that the device release order equals the device probe error path order.

Furthermore drop the dev_set_drvdata() usage since the only user was the
.remove() callback which is removed by this commit.

Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
---
 drivers/pmdomain/imx/imx93-blk-ctrl.c | 66 +++++++++++++++--------------------
 1 file changed, 29 insertions(+), 37 deletions(-)

diff --git a/drivers/pmdomain/imx/imx93-blk-ctrl.c b/drivers/pmdomain/imx/imx93-blk-ctrl.c
index 2aa163aef8de4ee901b9cde76ce2aad246c8c08a..49610f2389c3bbaf4de4133918fbcacb7924f672 100644
--- a/drivers/pmdomain/imx/imx93-blk-ctrl.c
+++ b/drivers/pmdomain/imx/imx93-blk-ctrl.c
@@ -188,6 +188,20 @@ static int imx93_blk_ctrl_power_off(struct generic_pm_domain *genpd)
 	return 0;
 }
 
+static void imx93_release_genpd_provider(void *data)
+{
+	struct device_node *of_node = data;
+
+	of_genpd_del_provider(of_node);
+}
+
+static void imx93_release_pm_genpd(void *data)
+{
+	struct generic_pm_domain *genpd = data;
+
+	pm_genpd_remove(genpd);
+}
+
 static struct lock_class_key blk_ctrl_genpd_lock_class;
 
 static int imx93_blk_ctrl_probe(struct platform_device *pdev)
@@ -256,10 +270,8 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
 			domain->clks[j].id = data->clk_names[j];
 
 		ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks);
-		if (ret) {
-			dev_err_probe(dev, ret, "failed to get clock\n");
-			goto cleanup_pds;
-		}
+		if (ret)
+			return dev_err_probe(dev, ret, "failed to get clock\n");
 
 		domain->genpd.name = data->name;
 		domain->genpd.power_on = imx93_blk_ctrl_power_on;
@@ -267,11 +279,12 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
 		domain->bc = bc;
 
 		ret = pm_genpd_init(&domain->genpd, NULL, true);
-		if (ret) {
-			dev_err_probe(dev, ret, "failed to init power domain\n");
-			goto cleanup_pds;
-		}
+		if (ret)
+			return dev_err_probe(dev, ret, "failed to init power domain\n");
 
+		ret = devm_add_action_or_reset(dev, imx93_release_pm_genpd, &domain->genpd);
+		if (ret)
+			return dev_err_probe(dev, ret, "failed to add pm_genpd release callback\n");
 		/*
 		 * We use runtime PM to trigger power on/off of the upstream GPC
 		 * domain, as a strict hierarchical parent/child power domain
@@ -288,39 +301,19 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
 		bc->onecell_data.domains[i] = &domain->genpd;
 	}
 
-	pm_runtime_enable(dev);
+	ret = devm_pm_runtime_enable(dev);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to enable pm-runtime\n");
 
 	ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data);
-	if (ret) {
-		dev_err_probe(dev, ret, "failed to add power domain provider\n");
-		goto cleanup_pds;
-	}
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to add power domain provider\n");
 
-	dev_set_drvdata(dev, bc);
+	ret = devm_add_action_or_reset(dev, imx93_release_genpd_provider, dev->of_node);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to add genpd_provider release callback\n");
 
 	return 0;
-
-cleanup_pds:
-	for (i--; i >= 0; i--)
-		pm_genpd_remove(&bc->domains[i].genpd);
-
-	return ret;
-}
-
-static void imx93_blk_ctrl_remove(struct platform_device *pdev)
-{
-	struct imx93_blk_ctrl *bc = dev_get_drvdata(&pdev->dev);
-	int i;
-
-	of_genpd_del_provider(pdev->dev.of_node);
-
-	pm_runtime_disable(&pdev->dev);
-
-	for (i = 0; i < bc->onecell_data.num_domains; i++) {
-		struct imx93_blk_ctrl_domain *domain = &bc->domains[i];
-
-		pm_genpd_remove(&domain->genpd);
-	}
 }
 
 static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] = {
@@ -455,7 +448,6 @@ MODULE_DEVICE_TABLE(of, imx93_blk_ctrl_of_match);
 
 static struct platform_driver imx93_blk_ctrl_driver = {
 	.probe = imx93_blk_ctrl_probe,
-	.remove = imx93_blk_ctrl_remove,
 	.driver = {
 		.name = "imx93-blk-ctrl",
 		.of_match_table = imx93_blk_ctrl_of_match,

-- 
2.47.3



From marco.crivellari at suse.com  Tue Dec  2 05:25:22 2025
From: marco.crivellari at suse.com (Marco Crivellari)
Date: Tue, 2 Dec 2025 14:25:22 +0100
Subject: [PATCH] soc/xilinx: replace use of system_unbound_wq with system_dfl_wq
In-Reply-To: <20251104103942.96647-1-marco.crivellari@suse.com>
References: <20251104103942.96647-1-marco.crivellari@suse.com>
Message-ID: <CAAofZF4-D3PT_eE8e4VRX7bCkUV0d9h99YypeYyPhCg+sCFBpw@mail.gmail.com>

Hi,

On Tue, Nov 4, 2025 at 11:39?AM Marco Crivellari
<marco.crivellari at suse.com> wrote:
>  drivers/soc/xilinx/zynqmp_power.c | 6 +++---

Gentle ping.

Thanks!

-- 

Marco Crivellari

L3 Support Engineer, Technology & Product


From m.felsch at pengutronix.de  Tue Dec  2 05:33:00 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Tue, 02 Dec 2025 14:33:00 +0100
Subject: [PATCH v7 3/3] arm64: dts: imx93: Add parallel display output
 nodes
In-Reply-To: <20251202-v6-18-topic-imx93-parallel-display-v7-0-2cce31d64608@pengutronix.de>
References: <20251202-v6-18-topic-imx93-parallel-display-v7-0-2cce31d64608@pengutronix.de>
Message-ID: <20251202-v6-18-topic-imx93-parallel-display-v7-3-2cce31d64608@pengutronix.de>

Add required OF nodes to support the i.MX93 parallel output (DPI) path.

On the i.MX93 a single LCDIF is connected to three bridges: DPI, LVDS
LDB and the MIPI-DSI whereas the i.MX91 support only the DPI bridge.

Map endpoint at 0 as DPI bridge output since the i.MX93 TRM (Figure 485.
MEDIAMIX block diagram) doesn't mention any port-number <-> bridge
combination.

Set the MEDIA-AXI and MEDIA-APB clocks to the overdrive (OD) values
since the i.MX93 and i.MX91 use the overdrive (OD) clk settings per
default.

Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
---
 arch/arm64/boot/dts/freescale/imx91_93_common.dtsi | 57 ++++++++++++++++++++++
 arch/arm64/boot/dts/freescale/imx93.dtsi           | 12 +++++
 2 files changed, 69 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx91_93_common.dtsi b/arch/arm64/boot/dts/freescale/imx91_93_common.dtsi
index 52da571f26c4e8a2703e4476b5541fa7aca52f10..6dc01a76c68425bb65576712bfd98950d662bd38 100644
--- a/arch/arm64/boot/dts/freescale/imx91_93_common.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx91_93_common.dtsi
@@ -1122,8 +1122,65 @@ media_blk_ctrl: system-controller at 4ac10000 {
 				 <&clk IMX93_CLK_MIPI_DSI_GATE>;
 			clock-names = "apb", "axi", "nic", "disp", "cam",
 				      "pxp", "lcdif", "isi", "csi", "dsi";
+			assigned-clocks = <&clk IMX93_CLK_MEDIA_AXI>,
+					  <&clk IMX93_CLK_MEDIA_APB>,
+					  <&clk IMX93_CLK_MEDIA_DISP_PIX>;
+			assigned-clock-parents = <&clk IMX93_CLK_SYS_PLL_PFD1>,
+						 <&clk IMX93_CLK_SYS_PLL_PFD1_DIV2>,
+						 <&clk IMX93_CLK_VIDEO_PLL>;
+			assigned-clock-rates = <400000000>, <133333333>;
 			#power-domain-cells = <1>;
+			#address-cells = <1>;
+			#size-cells = <1>;
 			status = "disabled";
+
+			dpi_bridge: bridge at 60 {
+				compatible = "nxp,imx93-pdfc";
+				reg = <0x60 0x4>;
+				status = "disabled";
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port at 0 {
+						reg = <0>;
+
+						dpi_from_lcdif: endpoint {
+							remote-endpoint = <&lcdif_to_dpi>;
+						};
+					};
+
+					port at 1 {
+						reg = <1>;
+
+						dpi_to_panel: endpoint {
+						};
+					};
+				};
+			};
+		};
+
+		lcdif: display-controller at 4ae30000 {
+			compatible = "fsl,imx93-lcdif";
+			reg = <0x4ae30000 0x23c>;
+			interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clk IMX93_CLK_MEDIA_DISP_PIX>,
+				 <&clk IMX93_CLK_LCDIF_GATE>,
+				 <&clk IMX93_CLK_MEDIA_AXI>;
+			clock-names = "pix", "axi", "disp_axi";
+			power-domains = <&media_blk_ctrl IMX93_MEDIABLK_PD_LCDIF>;
+			status = "disabled";
+
+			port {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				lcdif_to_dpi: endpoint at 0 {
+					reg = <0>;
+					remote-endpoint = <&dpi_from_lcdif>;
+				};
+			};
 		};
 
 		usbotg1: usb at 4c100000 {
diff --git a/arch/arm64/boot/dts/freescale/imx93.dtsi b/arch/arm64/boot/dts/freescale/imx93.dtsi
index 7b27012dfcb564650882dc8c40e836e797b2fda1..5436b48b30e89eb1f939b398ce1bf105abe7e34b 100644
--- a/arch/arm64/boot/dts/freescale/imx93.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx93.dtsi
@@ -150,6 +150,18 @@ l3_cache: l3-cache {
 	};
 };
 
+&lcdif {
+	port {
+		lcdif_to_ldb: endpoint at 1 {
+			reg = <1>;
+		};
+
+		lcdif_to_dsi: endpoint at 2 {
+			reg = <2>;
+		};
+	};
+};
+
 &src {
 	mlmix: power-domain at 44461800 {
 		compatible = "fsl,imx93-src-slice";

-- 
2.47.3



From m.felsch at pengutronix.de  Tue Dec  2 05:32:58 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Tue, 02 Dec 2025 14:32:58 +0100
Subject: [PATCH v7 1/3] dt-bindings: soc: imx93-media-blk-ctrl: Add PDFC
 subnode to schema and example
In-Reply-To: <20251202-v6-18-topic-imx93-parallel-display-v7-0-2cce31d64608@pengutronix.de>
References: <20251202-v6-18-topic-imx93-parallel-display-v7-0-2cce31d64608@pengutronix.de>
Message-ID: <20251202-v6-18-topic-imx93-parallel-display-v7-1-2cce31d64608@pengutronix.de>

From: Liu Ying <victor.liu at nxp.com>

i.MX93 SoC mediamix blk-ctrl contains one DISPLAY_MUX register which
configures parallel display format by using the "PARALLEL_DISP_FORMAT"
field. Document the Parallel Display Format Configuration(PDFC) subnode
and add the subnode to example.

Signed-off-by: Liu Ying <victor.liu at nxp.com>
[m.felsch at pengutronix.de: port to v6.18-rc1]
[m.felsch at pengutronix.de: add bus-width]
Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
---
 .../bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml | 92 ++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
index 34aea58094e55365a2f9c86092f637e533f954ff..6e2d86d9341c75108b492bcbabc8a560d8e707cd 100644
--- a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
+++ b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
@@ -26,6 +26,12 @@ properties:
   reg:
     maxItems: 1
 
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 1
+
   '#power-domain-cells':
     const: 1
 
@@ -40,6 +46,60 @@ properties:
     minItems: 8
     maxItems: 10
 
+  bridge at 60:
+    type: object
+    additionalProperties: false
+
+    properties:
+      compatible:
+        const: nxp,imx93-pdfc
+
+      reg:
+        maxItems: 1
+
+      ports:
+        $ref: /schemas/graph.yaml#/properties/ports
+
+        properties:
+          port at 0:
+            $ref: /schemas/graph.yaml#/properties/port
+            description: Input port node to receive pixel data.
+
+          port at 1:
+            $ref: /schemas/graph.yaml#/$defs/port-base
+            unevaluatedProperties: false
+            description: Output port node to downstream pixel data receivers.
+
+            properties:
+              endpoint:
+                $ref: /schemas/graph.yaml#/$defs/endpoint-base
+                unevaluatedProperties: false
+
+                properties:
+                  bus-width:
+                    enum: [ 16, 18, 24 ]
+                    description:
+                      Specify the physical parallel bus width.
+
+                      This property is optional if the display bus-width
+                      matches the SoC bus-width, e.g. a 18-bit RGB666 (display)
+                      is connected and all 18-bit data lanes are muxed to the
+                      parallel-output pads.
+
+                      This property must be set to 18 to cut only the LSBs
+                      instead of the MSBs in case a 24-bit RGB888 display is
+                      connected and only the lower 18-bit data lanes are muxed
+                      to the parallel-output pads.
+
+        required:
+          - port at 0
+          - port at 1
+
+    required:
+      - compatible
+      - reg
+      - ports
+
 allOf:
   - if:
       properties:
@@ -81,9 +141,12 @@ allOf:
             - const: isi
             - const: csi
             - const: dsi
+
 required:
   - compatible
   - reg
+  - '#address-cells'
+  - '#size-cells'
   - power-domains
   - clocks
   - clock-names
@@ -112,4 +175,33 @@ examples:
                clock-names = "apb", "axi", "nic", "disp", "cam",
                              "pxp", "lcdif", "isi", "csi", "dsi";
       #power-domain-cells = <1>;
+      #address-cells = <1>;
+      #size-cells = <1>;
+
+      bridge at 60 {
+        compatible = "nxp,imx93-pdfc";
+        reg = <0x60 0x4>;
+
+        ports {
+          #address-cells = <1>;
+          #size-cells = <0>;
+
+          port at 0 {
+            reg = <0>;
+
+            pdfc_from_lcdif: endpoint {
+              remote-endpoint = <&lcdif_to_pdfc>;
+            };
+          };
+
+          port at 1 {
+            reg = <1>;
+
+            pdfc_to_panel: endpoint {
+              remote-endpoint = <&panel_from_pdfc>;
+              bus-width = <18>;
+            };
+          };
+        };
+      };
     };

-- 
2.47.3



From m.felsch at pengutronix.de  Tue Dec  2 05:32:59 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Tue, 02 Dec 2025 14:32:59 +0100
Subject: [PATCH v7 2/3] drm/bridge: imx: Add i.MX93 parallel display format
 configuration support
In-Reply-To: <20251202-v6-18-topic-imx93-parallel-display-v7-0-2cce31d64608@pengutronix.de>
References: <20251202-v6-18-topic-imx93-parallel-display-v7-0-2cce31d64608@pengutronix.de>
Message-ID: <20251202-v6-18-topic-imx93-parallel-display-v7-2-2cce31d64608@pengutronix.de>

From: Liu Ying <victor.liu at nxp.com>

NXP i.MX93 mediamix blk-ctrl contains one DISPLAY_MUX register which
configures parallel display format by using the "PARALLEL_DISP_FORMAT"
field. Add a DRM bridge driver to support the display format configuration.

Signed-off-by: Liu Ying <victor.liu at nxp.com>
[m.felsch at pengutronix.de: port to v6.18-rc1]
[m.felsch at pengutronix.de: add review feedback (Alexander)]
[m.felsch at pengutronix.de: fix to short Kconfig description (checkpath)]
[m.felsch at pengutronix.de: use "GPL" instead of "GPL v2" (checkpatch)]
[m.felsch at pengutronix.de: make use of reg property]
[m.felsch at pengutronix.de: add bus-width support]
Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
---
 drivers/gpu/drm/bridge/imx/Kconfig      |  11 ++
 drivers/gpu/drm/bridge/imx/Makefile     |   1 +
 drivers/gpu/drm/bridge/imx/imx93-pdfc.c | 227 ++++++++++++++++++++++++++++++++
 3 files changed, 239 insertions(+)

diff --git a/drivers/gpu/drm/bridge/imx/Kconfig b/drivers/gpu/drm/bridge/imx/Kconfig
index 9a480c6abb856276df9b71d23b39a43b3a9c542d..28fd7a00473a0ec50bf0ffb5d50972abc209ceec 100644
--- a/drivers/gpu/drm/bridge/imx/Kconfig
+++ b/drivers/gpu/drm/bridge/imx/Kconfig
@@ -88,4 +88,15 @@ config DRM_IMX93_MIPI_DSI
 	  Choose this to enable MIPI DSI controller found in Freescale i.MX93
 	  processor.
 
+config DRM_IMX93_PARALLEL_DISP_FMT_CONFIG
+	tristate "NXP i.MX91/i.MX93 parallel display format configuration"
+	depends on OF
+	select DRM_KMS_HELPER
+	help
+	  On i.MX93 and i.MX91 SoCs the parallel display format output is
+	  controlled via the MEDIAMIX BLK-CTRL DISPLAY_MUX.
+
+	  Say 'Y' or 'M' if you use the parallel display output path on a
+	  i.MX93 or i.MX91 SoC.
+
 endif # ARCH_MXC || COMPILE_TEST
diff --git a/drivers/gpu/drm/bridge/imx/Makefile b/drivers/gpu/drm/bridge/imx/Makefile
index dd5d4858480663bade98bd58039d1cb6f8aa18da..f4ccc5cbef72a576443d5fecf666b76dfba8aa94 100644
--- a/drivers/gpu/drm/bridge/imx/Makefile
+++ b/drivers/gpu/drm/bridge/imx/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_DRM_IMX8QXP_PIXEL_COMBINER) += imx8qxp-pixel-combiner.o
 obj-$(CONFIG_DRM_IMX8QXP_PIXEL_LINK) += imx8qxp-pixel-link.o
 obj-$(CONFIG_DRM_IMX8QXP_PIXEL_LINK_TO_DPI) += imx8qxp-pxl2dpi.o
 obj-$(CONFIG_DRM_IMX93_MIPI_DSI) += imx93-mipi-dsi.o
+obj-$(CONFIG_DRM_IMX93_PARALLEL_DISP_FMT_CONFIG) += imx93-pdfc.o
diff --git a/drivers/gpu/drm/bridge/imx/imx93-pdfc.c b/drivers/gpu/drm/bridge/imx/imx93-pdfc.c
new file mode 100644
index 0000000000000000000000000000000000000000..624389def0ac3f24158edc64a8913375a4cc2f12
--- /dev/null
+++ b/drivers/gpu/drm/bridge/imx/imx93-pdfc.c
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/*
+ * Copyright 2022-2025 NXP
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/media-bus-format.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_print.h>
+
+#define PARALLEL_DISP_FORMAT		GENMASK(10, 8)
+#define FORMAT_RGB888_TO_RGB888		FIELD_PREP(PARALLEL_DISP_FORMAT, 0)
+#define FORMAT_RGB888_TO_RGB666		FIELD_PREP(PARALLEL_DISP_FORMAT, 1)
+#define FORMAT_RGB565_TO_RGB565		FIELD_PREP(PARALLEL_DISP_FORMAT, 2)
+
+struct imx93_pdfc {
+	struct drm_bridge bridge;
+	struct drm_bridge *next_bridge;
+	struct device *dev;
+	struct regmap *regmap;
+	u64 disp_mux_reg_off;
+	u32 phy_bus_width;
+};
+
+static int
+imx93_pdfc_bridge_attach(struct drm_bridge *bridge, struct drm_encoder *encoder,
+			 enum drm_bridge_attach_flags flags)
+{
+	struct imx93_pdfc *pdfc = bridge->driver_private;
+
+	return drm_bridge_attach(bridge->encoder, pdfc->next_bridge, bridge, flags);
+}
+
+static void imx93_pdfc_bridge_atomic_enable(struct drm_bridge *bridge,
+					    struct drm_atomic_state *state)
+{
+	struct imx93_pdfc *pdfc = bridge->driver_private;
+	const struct drm_bridge_state *bridge_state;
+	unsigned int mask = PARALLEL_DISP_FORMAT;
+	unsigned int val;
+
+	bridge_state = drm_atomic_get_new_bridge_state(state, bridge);
+
+	switch (bridge_state->output_bus_cfg.format) {
+	case MEDIA_BUS_FMT_RGB888_1X24:
+		val = FORMAT_RGB888_TO_RGB888;
+		if (pdfc->phy_bus_width == 18) {
+			/*
+			 * Can be valid if physical bus limitation exist,
+			 * therefore use dev_dbg().
+			 */
+			dev_dbg(pdfc->dev, "Truncate two LSBs from each color\n");
+			val = FORMAT_RGB888_TO_RGB666;
+		}
+		break;
+	case MEDIA_BUS_FMT_RGB666_1X18:
+		val = FORMAT_RGB888_TO_RGB666;
+		break;
+	case MEDIA_BUS_FMT_RGB565_1X16:
+		val = FORMAT_RGB565_TO_RGB565;
+		break;
+	}
+
+	regmap_update_bits(pdfc->regmap, pdfc->disp_mux_reg_off, mask, val);
+}
+
+static const u32 imx93_pdfc_bus_output_fmts[] = {
+	MEDIA_BUS_FMT_RGB888_1X24,
+	MEDIA_BUS_FMT_RGB666_1X18,
+	MEDIA_BUS_FMT_RGB565_1X16,
+	MEDIA_BUS_FMT_FIXED
+};
+
+static bool imx93_pdfc_bus_output_fmt_supported(u32 fmt)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(imx93_pdfc_bus_output_fmts); i++) {
+		if (imx93_pdfc_bus_output_fmts[i] == fmt)
+			return true;
+	}
+
+	return false;
+}
+
+static u32 *
+imx93_pdfc_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
+					    struct drm_bridge_state *bridge_state,
+					    struct drm_crtc_state *crtc_state,
+					    struct drm_connector_state *conn_state,
+					    u32 output_fmt,
+					    unsigned int *num_input_fmts)
+{
+	u32 *input_fmts;
+
+	*num_input_fmts = 0;
+
+	if (!imx93_pdfc_bus_output_fmt_supported(output_fmt))
+		return NULL;
+
+	input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
+	if (!input_fmts)
+		return NULL;
+
+	switch (output_fmt) {
+	case MEDIA_BUS_FMT_RGB888_1X24:
+	case MEDIA_BUS_FMT_RGB565_1X16:
+		input_fmts[0] = output_fmt;
+		break;
+	case MEDIA_BUS_FMT_RGB666_1X18:
+	case MEDIA_BUS_FMT_FIXED:
+		input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24;
+		break;
+	}
+
+	*num_input_fmts = 1;
+
+	return input_fmts;
+}
+
+static int imx93_pdfc_bridge_atomic_check(struct drm_bridge *bridge,
+					  struct drm_bridge_state *bridge_state,
+					  struct drm_crtc_state *crtc_state,
+					  struct drm_connector_state *conn_state)
+{
+	struct imx93_pdfc *pdfc = bridge->driver_private;
+
+	switch (bridge_state->output_bus_cfg.format) {
+	case MEDIA_BUS_FMT_RGB888_1X24:
+	case MEDIA_BUS_FMT_RGB666_1X18:
+	case MEDIA_BUS_FMT_RGB565_1X16:
+		return 0;
+	default:
+		dev_warn(pdfc->dev, "Unsupported output bus format: 0x%x\n",
+			 bridge_state->output_bus_cfg.format);
+		return -EINVAL;
+	}
+}
+
+static const struct drm_bridge_funcs funcs = {
+	.attach			= imx93_pdfc_bridge_attach,
+	.atomic_enable		= imx93_pdfc_bridge_atomic_enable,
+	.atomic_duplicate_state	= drm_atomic_helper_bridge_duplicate_state,
+	.atomic_destroy_state	= drm_atomic_helper_bridge_destroy_state,
+	.atomic_get_input_bus_fmts	= imx93_pdfc_bridge_atomic_get_input_bus_fmts,
+	.atomic_check		= imx93_pdfc_bridge_atomic_check,
+	.atomic_reset		= drm_atomic_helper_bridge_reset,
+};
+
+static int imx93_pdfc_bridge_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct imx93_pdfc *pdfc;
+	struct device_node *ep;
+	int err;
+
+	pdfc = devm_drm_bridge_alloc(dev, struct imx93_pdfc, bridge, &funcs);
+	if (IS_ERR(pdfc))
+		return PTR_ERR(pdfc);
+
+	pdfc->regmap = syscon_node_to_regmap(dev->of_node->parent);
+	if (IS_ERR(pdfc->regmap))
+		return dev_err_probe(dev, PTR_ERR(pdfc->regmap),
+				     "failed to get regmap\n");
+
+	err = of_property_read_reg(dev->of_node, 0, &pdfc->disp_mux_reg_off, NULL);
+	if (err)
+		return dev_err_probe(dev, err,
+				     "failed to get display-mux reg\n");
+
+	/* No limits per default */
+	pdfc->phy_bus_width = 24;
+
+	/* Get output ep (port1/endpoint0) */
+	ep = of_graph_get_endpoint_by_regs(dev->of_node, 1, 0);
+	if (ep) {
+		err = of_property_read_u32(ep, "bus-width", &pdfc->phy_bus_width);
+		of_node_put(ep);
+
+		/* bus-width is optional but it must have valid data if present */
+		if (err && err != -EINVAL)
+			return dev_err_probe(dev, err,
+					     "failed to query bus-width\n");
+	}
+
+	pdfc->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
+	if (IS_ERR(pdfc->next_bridge))
+		return dev_err_probe(dev, PTR_ERR(pdfc->next_bridge),
+				     "failed to get next bridge\n");
+
+	pdfc->dev = dev;
+	pdfc->bridge.driver_private = pdfc;
+	pdfc->bridge.of_node = dev->of_node;
+	pdfc->bridge.type = DRM_MODE_CONNECTOR_DPI;
+
+	return devm_drm_bridge_add(dev, &pdfc->bridge);
+}
+
+static const struct of_device_id imx93_pdfc_dt_ids[] = {
+	{ .compatible = "nxp,imx93-pdfc", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx93_pdfc_dt_ids);
+
+static struct platform_driver imx93_pdfc_bridge_driver = {
+	.probe	= imx93_pdfc_bridge_probe,
+	.driver	= {
+		.of_match_table = imx93_pdfc_dt_ids,
+		.name = "imx93_pdfc",
+	},
+};
+module_platform_driver(imx93_pdfc_bridge_driver);
+
+MODULE_DESCRIPTION("NXP i.MX93 parallel display format configuration driver");
+MODULE_AUTHOR("Liu Ying <victor.liu at nxp.com>");
+MODULE_LICENSE("GPL");

-- 
2.47.3



From m.felsch at pengutronix.de  Tue Dec  2 05:32:57 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Tue, 02 Dec 2025 14:32:57 +0100
Subject: [PATCH v7 0/3] Add i.MX91/93 parallel display support
Message-ID: <20251202-v6-18-topic-imx93-parallel-display-v7-0-2cce31d64608@pengutronix.de>

Hi,

this patchset adds the driver, dt-bindings and dt integration required
to drive a parallel display on the i.MX93.

Since the i.MX91 register layout equals the one from the i.MX93, I added
the support for both but tested only the i.MX93 use-case.

This patchset depends on:
 - https://lore.kernel.org/all/20251201-v6-18-topic-imx93-blkctrl-v1-0-b57a72e60105 at pengutronix.de/

@Conor Dooley
I dropped your r-b tag since I added the 'bus-width' property.

Regards,
  Marco

Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
---
Changes in v7:
- Link to v6: https://lore.kernel.org/r/20251201-v6-18-topic-imx93-parallel-display-v6-0-7b056e1e5b1e at pengutronix.de
- Add missing bits.h and bitfield.h headers (lkp)

Changes in v6:
- Link to v5: https://lore.kernel.org/all/20250304082434.834031-1-victor.liu at nxp.com/
- Add bus-width support
- rebase onto v6.18-rc1
- add review feedback (Alexander)
- driver license "GPL v2" -> "GPL" (checkpatch)
- make use of reg of-property
- fix to short Kconfig description (checkpath)
- add OF integration

---
Liu Ying (2):
      dt-bindings: soc: imx93-media-blk-ctrl: Add PDFC subnode to schema and example
      drm/bridge: imx: Add i.MX93 parallel display format configuration support

Marco Felsch (1):
      arm64: dts: imx93: Add parallel display output nodes

 .../bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml |  92 +++++++++
 arch/arm64/boot/dts/freescale/imx91_93_common.dtsi |  57 ++++++
 arch/arm64/boot/dts/freescale/imx93.dtsi           |  12 ++
 drivers/gpu/drm/bridge/imx/Kconfig                 |  11 +
 drivers/gpu/drm/bridge/imx/Makefile                |   1 +
 drivers/gpu/drm/bridge/imx/imx93-pdfc.c            | 227 +++++++++++++++++++++
 6 files changed, 400 insertions(+)
---
base-commit: 3a8660878839faadb4f1a6dd72c3179c1df56787
change-id: 20251201-v6-18-topic-imx93-parallel-display-95f9234bf6cc

Best regards,
-- 
Marco Felsch <m.felsch at pengutronix.de>



From michal.simek at amd.com  Tue Dec  2 05:36:17 2025
From: michal.simek at amd.com (Michal Simek)
Date: Tue, 2 Dec 2025 14:36:17 +0100
Subject: [PATCH] soc/xilinx: replace use of system_unbound_wq with
 system_dfl_wq
In-Reply-To: <CAAofZF4-D3PT_eE8e4VRX7bCkUV0d9h99YypeYyPhCg+sCFBpw@mail.gmail.com>
References: <20251104103942.96647-1-marco.crivellari@suse.com>
 <CAAofZF4-D3PT_eE8e4VRX7bCkUV0d9h99YypeYyPhCg+sCFBpw@mail.gmail.com>
Message-ID: <19d32db7-5ec3-41cc-b0b0-5e90a4447fb4@amd.com>

Hi,

On 12/2/25 14:25, Marco Crivellari wrote:
> Hi,
> 
> On Tue, Nov 4, 2025 at 11:39?AM Marco Crivellari
> <marco.crivellari at suse.com> wrote:
>>   drivers/soc/xilinx/zynqmp_power.c | 6 +++---
> 

I will queue it after rc1 tag.

Thanks,
Michal


From andrew at lunn.ch  Tue Dec  2 05:36:11 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Tue, 2 Dec 2025 14:36:11 +0100
Subject: [PATCH net-next v4 4/4] net: ftgmac100: Add RGMII delay support
 for AST2600
In-Reply-To: <SEYPR06MB5134A5D1603F39E6025629A19DD8A@SEYPR06MB5134.apcprd06.prod.outlook.com>
References: <68f10ee1-d4c8-4498-88b0-90c26d606466@lunn.ch>
 <SEYPR06MB5134EBA2235B3D4BE39B19359DCCA@SEYPR06MB5134.apcprd06.prod.outlook.com>
 <3af52caa-88a7-4b88-bd92-fd47421cc81a@lunn.ch>
 <SEYPR06MB51342977EC2246163D14BDC19DCDA@SEYPR06MB5134.apcprd06.prod.outlook.com>
 <041e23a2-67e6-4ebb-aee5-14400491f99c@lunn.ch>
 <SEYPR06MB5134BC17E80DB66DD385024D9DD1A@SEYPR06MB5134.apcprd06.prod.outlook.com>
 <1c2ace4e-f3bb-4efa-a621-53c3711f46cb@lunn.ch>
 <aSbA8i5S36GeryXc@fedora>
 <SEYPR06MB513424DDB2D32ADB9C30B5119DDFA@SEYPR06MB5134.apcprd06.prod.outlook.com>
 <SEYPR06MB5134A5D1603F39E6025629A19DD8A@SEYPR06MB5134.apcprd06.prod.outlook.com>
Message-ID: <4f0e4aa0-166d-4a7f-b91e-42dbc6b832e5@lunn.ch>

> Hi Andrew,
> 
> I miss one condition is using fixed-link property.
> In ftgmac100, there are RGMII, NC-SI and fixed-link property.
> On RGMII, we have solution on dedicated PHY, but there is an issue on fixed-link
> property.
> 
> Example on dedicated PHY.
> The driver can pass the "rgmii-id" to tell PHY driver to enable the internal delay on
> PHY side. Therefore, we can force to disable RGMII delay on MAC side.
> But there is not any driver when using fixed-link property, which means
> no body can tell the outside device, like switch or MAC-to-MAC, to enable the internal
> delay on them. Also mean the phy-mode in fixed-link case is not used.
> 
> Therefore, could we ignore the RGMII delay on MAC side when the ftgmac100 driver gets
> the fixed-link property? Just keep the original delay value?

MAC to MAC is one of the edge cases where phy-mode is not great. What
is generally accepted it to use rx-internal-delay-ps and
tx-internal-delay-ps with 2ns and a comment explaining it is a MAC to
MAC link, with this MAC adding the delays.

I suggest you see how messy it is to implement this for 2600. If the
code looks horrible, keep the bootloader delays. For 2700 you have a
clean slate, you can implement all this correctly from the start.

	Andrew


From macro at orcam.me.uk  Tue Dec  2 05:39:14 2025
From: macro at orcam.me.uk (Maciej W. Rozycki)
Date: Tue, 2 Dec 2025 13:39:14 +0000 (GMT)
Subject: [PATCH v9 4/4] PCI: dwc: Support ECAM mechanism by enabling iATU
 'CFG Shift Feature'
In-Reply-To: <ps5jjiqv5mw2g3exzvfcfsa4bcda7hois2h6riarwb2d2son4u@2onu4bibw2hb>
References: <alpine.DEB.2.21.2511280256260.36486@angie.orcam.me.uk> <c7aea2b3-6984-40f5-8234-14d265dabefc@oss.qualcomm.com> <alpine.DEB.2.21.2511280755440.36486@angie.orcam.me.uk> <cabf4c20-095b-4579-adc1-146a566b19b9@oss.qualcomm.com>
 <alpine.DEB.2.21.2511281714030.36486@angie.orcam.me.uk> <a4c6d47f-28b5-40d3-bc82-10aeb14f8e78@oss.qualcomm.com> <alpine.DEB.2.21.2511290428340.36486@angie.orcam.me.uk> <h7pgm3lqolm53sb4wrcpcurk4ghz4tulqnr7vgd7rzxy4hscue@jcn5tepevlwl>
 <syg7vpbt3w53s24hgl7b6w64odmif5bq557lwlvzlbvgkukwcn@66jtzzc3vtiu> <alpine.DEB.2.21.2512011617250.49654@angie.orcam.me.uk> <ps5jjiqv5mw2g3exzvfcfsa4bcda7hois2h6riarwb2d2son4u@2onu4bibw2hb>
Message-ID: <alpine.DEB.2.21.2512021246470.49654@angie.orcam.me.uk>

On Tue, 2 Dec 2025, Manivannan Sadhasivam wrote:

> >  No change in behaviour, sorry.  I suppose it's this range of host address 
> > decoding:
> > 
> > fu740-pcie e00000000.pcie:       IO 0x0060080000..0x006008ffff -> 0x0060080000
> > 
> > aka:
> > 
> > pci_bus 0000:00: root bus resource [io  0x0000-0xffff] (bus address [0x60080000-0x6008ffff])
> > 
> > that you're after.  Are you sure your code discovers it correctly?  As I 
> > say I can only see IORESOURCE_MEM references and no IORESOURCE_IO ones as 
> > would be appropriate for the root bus resource quoted.
> 
> The I/O resource is discovered by the driver correctly as seen from the logs:
> 
> pci_bus 0000:00: root bus resource [io  0x0000-0xffff] (bus address [0x60080000-0x6008ffff])
> pci_bus 0000:00: root bus resource [mem 0x60090000-0x7fffffff]
> pci_bus 0000:00: root bus resource [mem 0x2000000000-0x3fffffffff pref]
> 
> But we believe that the iATU is not programmed for the I/O port, resulting in
> the I/O access not going out to the device.
> 
> Krishna found an issue in the previous patch that got shared. So I've attached a
> new one. Could you please try and let us know? If it didn't help, please share
> the dmesg log that will have some more info.

 This does work correctly, thank you; see the log diff below (I checked 
the defxx driver separately too).  Please make a proper submission and 
I'll give it a Tested-by: tag after final verification against 6.18.

--- dmesg-bad.log	2025-11-28 03:47:29.582049781 +0100
+++ dmesg-fixed.log	2025-12-02 13:58:56.627947450 +0100
@@ -1,5 +1,5 @@
-Booting Linux on hartid 1
-Linux version 6.17.0-rc1-00009-g0da48c5b2fa7-dirty (macro at angie) (riscv64-linux-gnu-gcc (GCC) 13.0.0 20220602 (experimental), GNU ld (GNU Binutils) 2.38.50.20220503) #20 SMP Fri Nov 28 02:43:00 GMT 2025
+Booting Linux on hartid 4
+Linux version 6.17.0-rc1-00009-g0da48c5b2fa7-dirty (macro at angie) (riscv64-linux-gnu-gcc (GCC) 13.0.0 20220602 (experimental), GNU ld (GNU Binutils) 2.38.50.20220503) #32 SMP Tue Dec  2 12:46:23 GMT 2025
 Machine model: SiFive HiFive Unmatched A00
 SBI specification v0.3 detected
 SBI implementation ID=0x1 Version=0x9
@@ -164,6 +164,9 @@
 fu740-pcie e00000000.pcie: ECAM at [mem 0xdf0000000-0xdffffffff] for [bus 00-ff]
 fu740-pcie e00000000.pcie: Using 256 MSI vectors
 fu740-pcie e00000000.pcie: iATU: unroll T, 8 ob, 8 ib, align 4K, limit 4096G
+fu740-pcie e00000000.pcie: dw_pcie_iatu_setup: 921 MEM index: 2
+fu740-pcie e00000000.pcie: dw_pcie_iatu_setup: 941 I/O index: 3
+fu740-pcie e00000000.pcie: dw_pcie_iatu_setup: 949 Final index: 4
 fu740-pcie e00000000.pcie: cap_exp at 70
 fu740-pcie e00000000.pcie: PCIe Gen.1 x8 link up
 fu740-pcie e00000000.pcie: changing speed back to original
@@ -736,6 +739,8 @@
 pcieport 0000:06:01.0: enabling bus mastering
 parport_pc 0000:07:00.0: enabling device (0000 -> 0001)
 PCI parallel port detected: 1415:c118, I/O at 0x1000(0x1008), IRQ 35
+parport0: PC-style at 0x1000 (0x1008), irq 35, using FIFO [PCSPP,TRISTATE,EPP,ECP]
+lp0: using parport0 (interrupt-driven).
 parport_pc 0000:07:00.0: vgaarb: pci_notify
 serial 0000:07:00.3: vgaarb: pci_notify
 serial 0000:07:00.3: assign IRQ: got 40

  Maciej


From quentin.schulz at cherry.de  Tue Dec  2 05:37:48 2025
From: quentin.schulz at cherry.de (Quentin Schulz)
Date: Tue, 2 Dec 2025 14:37:48 +0100
Subject: [PATCH v2 9/9] arm64: dts: rockchip: Add the Video-Demo overlay
 for Lion Haikou
In-Reply-To: <20251021074254.87065-10-heiko@sntech.de>
References: <20251021074254.87065-1-heiko@sntech.de>
 <20251021074254.87065-10-heiko@sntech.de>
Message-ID: <ae0d2de5-4fc8-492c-8d46-8d90118c5e64@cherry.de>

Hi Heiko,

On 10/21/25 9:42 AM, Heiko Stuebner wrote:
> From: Heiko Stuebner <heiko.stuebner at cherry.de>
> 
> The video-demo adapter also works on the Lion SoM when running
> on a Haikou baseboard, so add an overlay for it.
> 
> Signed-off-by: Heiko Stuebner <heiko.stuebner at cherry.de>
> ---
>   arch/arm64/boot/dts/rockchip/Makefile         |   5 +
>   .../rk3368-lion-haikou-video-demo.dtso        | 174 ++++++++++++++++++
>   2 files changed, 179 insertions(+)
>   create mode 100644 arch/arm64/boot/dts/rockchip/rk3368-lion-haikou-video-demo.dtso
> 
> diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
> index ad684e3831bc..494fdd685a5c 100644
> --- a/arch/arm64/boot/dts/rockchip/Makefile
> +++ b/arch/arm64/boot/dts/rockchip/Makefile
> @@ -42,6 +42,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-evb-act8846.dtb
>   dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-geekbox.dtb
>   dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-lba3368.dtb
>   dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-lion-haikou.dtb
> +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-lion-haikou-video-demo.dtbo
>   dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-orion-r68-meta.dtb
>   dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-px5-evb.dtb
>   dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-r88.dtb
> @@ -231,6 +232,10 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-ringneck-haikou-haikou-video-demo.dtb
>   px30-ringneck-haikou-haikou-video-demo-dtbs := px30-ringneck-haikou.dtb \
>   	px30-ringneck-haikou-video-demo.dtbo
>   
> +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-lion-haikou-haikou-video-demo.dtb
> +rk3368-lion-haikou-haikou-video-demo-dtbs := rk3368-lion-haikou.dtb \
> +	rk3368-lion-haikou-video-demo.dtbo
> +
>   dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-puma-haikou-haikou-video-demo.dtb
>   rk3399-puma-haikou-haikou-video-demo-dtbs := rk3399-puma-haikou.dtb \
>   	rk3399-puma-haikou-video-demo.dtbo
> diff --git a/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou-video-demo.dtso b/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou-video-demo.dtso
> new file mode 100644
> index 000000000000..e7767c008144
> --- /dev/null
> +++ b/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou-video-demo.dtso
> @@ -0,0 +1,174 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright (c) 2025 Cherry Embedded Solutions GmbH
> + *
> + * DEVKIT ADDON CAM-TS-A01
> + * https://embedded.cherry.de/product/development-kit/
> + *
> + * DT-overlay for the camera / DSI demo appliance for Haikou boards.
> + * In the flavour for use with a Puma system-on-module.

s/Puma/Lion/

> + */
> +
> +/dts-v1/;
> +/plugin/;
> +
> +#include <dt-bindings/clock/rk3368-cru.h>
> +#include <dt-bindings/gpio/gpio.h>
> +#include <dt-bindings/interrupt-controller/irq.h>
> +#include <dt-bindings/leds/common.h>
> +#include <dt-bindings/pinctrl/rockchip.h>
> +
> +&{/} {
> +	backlight: backlight {
> +		compatible = "pwm-backlight";
> +		power-supply = <&dc_12v>;
> +		pwms = <&pwm1 0 25000 0>;
> +	};
> +
> +	cam_afvdd_2v8: regulator-cam-afvdd-2v8 {
> +		compatible = "regulator-fixed";
> +		gpio = <&pca9670 2 GPIO_ACTIVE_LOW>;
> +		regulator-max-microvolt = <2800000>;
> +		regulator-min-microvolt = <2800000>;
> +		regulator-name = "cam-afvdd-2v8";
> +		vin-supply = <&vcc2v8_video>;
> +	};
> +
> +	cam_avdd_2v8: regulator-cam-avdd-2v8 {
> +		compatible = "regulator-fixed";
> +		gpio = <&pca9670 4 GPIO_ACTIVE_LOW>;
> +		regulator-max-microvolt = <2800000>;
> +		regulator-min-microvolt = <2800000>;
> +		regulator-name = "cam-avdd-2v8";
> +		vin-supply = <&vcc2v8_video>;
> +	};
> +
> +	cam_dovdd_1v8: regulator-cam-dovdd-1v8 {
> +		compatible = "regulator-fixed";
> +		gpio = <&pca9670 3 GPIO_ACTIVE_LOW>;
> +		regulator-max-microvolt = <1800000>;
> +		regulator-min-microvolt = <1800000>;
> +		regulator-name = "cam-dovdd-1v8";
> +		vin-supply = <&vcc1v8_video>;
> +	};
> +
> +	cam_dvdd_1v2: regulator-cam-dvdd-1v2 {
> +		compatible = "regulator-fixed";
> +		enable-active-high;
> +		gpio = <&pca9670 5 GPIO_ACTIVE_HIGH>;
> +		regulator-max-microvolt = <1200000>;
> +		regulator-min-microvolt = <1200000>;
> +		regulator-name = "cam-dvdd-1v2";
> +		vin-supply = <&vcc3v3_baseboard>;
> +	};
> +
> +	vcc1v8_video: regulator-vcc1v8-video {
> +		compatible = "regulator-fixed";
> +		regulator-always-on;
> +		regulator-boot-on;
> +		regulator-max-microvolt = <1800000>;
> +		regulator-min-microvolt = <1800000>;
> +		regulator-name = "vcc1v8-video";
> +		vin-supply = <&vcc3v3_baseboard>;
> +	};
> +
> +	vcc2v8_video: regulator-vcc2v8-video {
> +		compatible = "regulator-fixed";
> +		regulator-always-on;
> +		regulator-boot-on;
> +		regulator-max-microvolt = <2800000>;
> +		regulator-min-microvolt = <2800000>;
> +		regulator-name = "vcc2v8-video";
> +		vin-supply = <&vcc3v3_baseboard>;
> +	};
> +
> +	video-adapter-leds {
> +		compatible = "gpio-leds";
> +
> +		video-adapter-led {
> +			color = <LED_COLOR_ID_BLUE>;
> +			gpios = <&pca9670 7 GPIO_ACTIVE_HIGH>;
> +			label = "video-adapter-led";
> +			linux,default-trigger = "none";
> +		};
> +	};
> +};
> +
> +&dphy {
> +	status = "okay";
> +};
> +
> +&i2c_gp2 {
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +	/* OV5675, GT911, DW9714 are limited to 400KHz */
> +	clock-frequency = <400000>;
> +
> +	touchscreen at 14 {
> +		compatible = "goodix,gt911";
> +		reg = <0x14>;
> +		interrupt-parent = <&gpio1>;
> +		interrupts = <RK_PB5 IRQ_TYPE_LEVEL_LOW>;
> +		irq-gpios = <&gpio1 RK_PB5 GPIO_ACTIVE_HIGH>;
> +		pinctrl-0 = <&touch_int>;
> +		pinctrl-names = "default";
> +		reset-gpios = <&pca9670 1 GPIO_ACTIVE_HIGH>;
> +		AVDD28-supply = <&vcc2v8_video>;
> +		VDDIO-supply = <&vcc3v3_baseboard>;
> +	};
> +
> +	pca9670: gpio at 27 {
> +		compatible = "nxp,pca9670";
> +		reg = <0x27>;
> +		gpio-controller;
> +		#gpio-cells = <2>;
> +		pinctrl-0 = <&pca9670_resetn>;
> +		pinctrl-names = "default";
> +		reset-gpios = <&gpio1 RK_PA5 GPIO_ACTIVE_LOW>;
> +	};
> +};
> +
> +&mipi_dsi {
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +	status = "okay";
> +
> +	panel at 0 {
> +		compatible = "leadtek,ltk050h3148w";
> +		reg = <0>;
> +		backlight = <&backlight>;
> +		iovcc-supply = <&vcc1v8_video>;
> +		reset-gpios = <&pca9670 0 GPIO_ACTIVE_LOW>;
> +		vci-supply = <&vcc2v8_video>;
> +
> +		port {
> +			mipi_in_panel: endpoint {
> +				remote-endpoint = <&mipi_out_panel>;
> +			};
> +		};
> +	};
> +};
> +
> +&mipi_out {
> +	mipi_out_panel: endpoint {
> +		remote-endpoint = <&mipi_in_panel>;
> +	};
> +};
> +
> +&pinctrl {
> +	pca9670 {
> +		pca9670_resetn: pca9670-resetn {
> +			rockchip,pins = <1 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
> +		};
> +	};
> +
> +	touch {
> +		touch_int: touch-int {
> +			rockchip,pins = <1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
> +		};
> +	};
> +};
> +
> +&pwm1 {
> +	status = "okay";
> +};

Both Puma and Ringneck enable the PWM controller in Haikou as it is 
exposed as BLT_CTRL signal on the MISC I/O pin header. The Qseven 
standard specifies this signal is only for PWM (either for a panel 
backlight or generic PWM), so I believe it's proper to enable it in the 
motherboard DTS to also align with the DTSO for the other modules.

I've tested the touchscreen, backlight and LED, they all work as expected.

I have not yet managed to make the DSI display work. It is detected but 
modetest test pattern doesn't show, only blank.

Since there's only one VOP, I'm also wondering if we need to disable 
HDMI here? Or is Linux capable of handling multiple connected displays 
but only use one? I've tried to make DSI work with the HDMI controller 
disabled, it didn't change anything.

Cheers,
Quentin


From marek.vasut at mailbox.org  Tue Dec  2 05:41:51 2025
From: marek.vasut at mailbox.org (Marek Vasut)
Date: Tue,  2 Dec 2025 14:41:51 +0100
Subject: [PATCH] arm64: dts: imx8mp: Fix LAN8740Ai PHY reference clock on DH electronics i.MX8M Plus DHCOM
Message-ID: <20251202134200.8397-1-marek.vasut@mailbox.org>

Add missing 'clocks' property to LAN8740Ai PHY node, to allow the PHY driver
to manage LAN8740Ai CLKIN reference clock supply. This fixes sporadic link
bouncing caused by interruptions on the PHY reference clock, by letting the
PHY driver manage the reference clock and assure there are no interruptions.

This follows the matching PHY driver recommendation described in commit
bedd8d78aba3 ("net: phy: smsc: LAN8710/20: add phy refclk in support")

Fixes: 8d6712695bc8 ("arm64: dts: imx8mp: Add support for DH electronics i.MX8M Plus DHCOM and PDK2")
Signed-off-by: Marek Vasut <marek.vasut at mailbox.org>
---
Cc: Christoph Niedermaier <cniedermaier at dh-electronics.com>
Cc: Conor Dooley <conor+dt at kernel.org>
Cc: Fabio Estevam <festevam at gmail.com>
Cc: Krzysztof Kozlowski <krzk+dt at kernel.org>
Cc: Pengutronix Kernel Team <kernel at pengutronix.de>
Cc: Rob Herring <robh at kernel.org>
Cc: Sascha Hauer <s.hauer at pengutronix.de>
Cc: Shawn Guo <shawnguo at kernel.org>
Cc: devicetree at vger.kernel.org
Cc: imx at lists.linux.dev
Cc: kernel at dh-electronics.com
Cc: linux-arm-kernel at lists.infradead.org
---
 arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi
index 68c2e0156a5c8..f8303b7e2bd22 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi
@@ -113,6 +113,7 @@ mdio {
 		ethphy0f: ethernet-phy at 1 { /* SMSC LAN8740Ai */
 			compatible = "ethernet-phy-id0007.c110",
 				     "ethernet-phy-ieee802.3-c22";
+			clocks = <&clk IMX8MP_CLK_ENET_QOS>;
 			interrupt-parent = <&gpio3>;
 			interrupts = <19 IRQ_TYPE_LEVEL_LOW>;
 			pinctrl-0 = <&pinctrl_ethphy0>;
-- 
2.51.0



From mani at kernel.org  Tue Dec  2 05:45:28 2025
From: mani at kernel.org (Manivannan Sadhasivam)
Date: Tue, 2 Dec 2025 19:15:28 +0530
Subject: [PATCH v9 4/4] PCI: dwc: Support ECAM mechanism by enabling iATU
 'CFG Shift Feature'
In-Reply-To: <alpine.DEB.2.21.2512021246470.49654@angie.orcam.me.uk>
References: <alpine.DEB.2.21.2511280755440.36486@angie.orcam.me.uk>
 <cabf4c20-095b-4579-adc1-146a566b19b9@oss.qualcomm.com>
 <alpine.DEB.2.21.2511281714030.36486@angie.orcam.me.uk>
 <a4c6d47f-28b5-40d3-bc82-10aeb14f8e78@oss.qualcomm.com>
 <alpine.DEB.2.21.2511290428340.36486@angie.orcam.me.uk>
 <h7pgm3lqolm53sb4wrcpcurk4ghz4tulqnr7vgd7rzxy4hscue@jcn5tepevlwl>
 <syg7vpbt3w53s24hgl7b6w64odmif5bq557lwlvzlbvgkukwcn@66jtzzc3vtiu>
 <alpine.DEB.2.21.2512011617250.49654@angie.orcam.me.uk>
 <ps5jjiqv5mw2g3exzvfcfsa4bcda7hois2h6riarwb2d2son4u@2onu4bibw2hb>
 <alpine.DEB.2.21.2512021246470.49654@angie.orcam.me.uk>
Message-ID: <hiuivv6q6rakmkpdupuw7upx3mazzux46zvoxsontwag6xvaon@o2d2swxdtafb>

On Tue, Dec 02, 2025 at 01:39:14PM +0000, Maciej W. Rozycki wrote:
> On Tue, 2 Dec 2025, Manivannan Sadhasivam wrote:
> 
> > >  No change in behaviour, sorry.  I suppose it's this range of host address 
> > > decoding:
> > > 
> > > fu740-pcie e00000000.pcie:       IO 0x0060080000..0x006008ffff -> 0x0060080000
> > > 
> > > aka:
> > > 
> > > pci_bus 0000:00: root bus resource [io  0x0000-0xffff] (bus address [0x60080000-0x6008ffff])
> > > 
> > > that you're after.  Are you sure your code discovers it correctly?  As I 
> > > say I can only see IORESOURCE_MEM references and no IORESOURCE_IO ones as 
> > > would be appropriate for the root bus resource quoted.
> > 
> > The I/O resource is discovered by the driver correctly as seen from the logs:
> > 
> > pci_bus 0000:00: root bus resource [io  0x0000-0xffff] (bus address [0x60080000-0x6008ffff])
> > pci_bus 0000:00: root bus resource [mem 0x60090000-0x7fffffff]
> > pci_bus 0000:00: root bus resource [mem 0x2000000000-0x3fffffffff pref]
> > 
> > But we believe that the iATU is not programmed for the I/O port, resulting in
> > the I/O access not going out to the device.
> > 
> > Krishna found an issue in the previous patch that got shared. So I've attached a
> > new one. Could you please try and let us know? If it didn't help, please share
> > the dmesg log that will have some more info.
> 
>  This does work correctly, thank you; see the log diff below (I checked 
> the defxx driver separately too).

Cool! Thanks a lot for testing and sorry for the breakage once again. Btw, the
issue that was fixed in the last diff has been present for some time. It was
fortunate that you didn't hit that before.

>  Please make a proper submission and 
> I'll give it a Tested-by: tag after final verification against 6.18.
> 

Sure thing. Krishna will post the fix(es) as there are two separate issues and
will CC you.

- Mani

-- 
????????? ????????


From m.felsch at pengutronix.de  Tue Dec  2 05:44:53 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Tue, 02 Dec 2025 14:44:53 +0100
Subject: [PATCH 1/2] clk: imx: fracn-gppll: Add 332.60 MHz Support
In-Reply-To: <20251202-v6-18-topic-imx93-phyboard-segin-av-02-display-v1-0-9c14be6c7478@pengutronix.de>
References: <20251202-v6-18-topic-imx93-phyboard-segin-av-02-display-v1-0-9c14be6c7478@pengutronix.de>
Message-ID: <20251202-v6-18-topic-imx93-phyboard-segin-av-02-display-v1-1-9c14be6c7478@pengutronix.de>

Some parallel panels have a pixelclk of 33.260 MHz. Add support for
332.60 MHz so a by 10 divider can be used to derive the exact pixelclk.

Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
---
 drivers/clk/imx/clk-fracn-gppll.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/clk/imx/clk-fracn-gppll.c b/drivers/clk/imx/clk-fracn-gppll.c
index 090d608672508a8819dc68eedec5b8d4a2c140c8..579f76494eb041dfba58b8cd10eb2453a0ec4178 100644
--- a/drivers/clk/imx/clk-fracn-gppll.c
+++ b/drivers/clk/imx/clk-fracn-gppll.c
@@ -88,6 +88,7 @@ static const struct imx_fracn_gppll_rate_table fracn_tbl[] = {
 	PLL_FRACN_GP(445333333U, 167, 0, 1, 0, 9),
 	PLL_FRACN_GP(400000000U, 200, 0, 1, 0, 12),
 	PLL_FRACN_GP(393216000U, 163, 84, 100, 0, 10),
+	PLL_FRACN_GP(332600000U, 138, 584, 1000, 0, 10),
 	PLL_FRACN_GP(300000000U, 150, 0, 1, 0, 12)
 };
 

-- 
2.47.3



From m.felsch at pengutronix.de  Tue Dec  2 05:44:52 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Tue, 02 Dec 2025 14:44:52 +0100
Subject: [PATCH 0/2] i.MX93 phyBOARD-Segin DisplayKit AV-02 Support
Message-ID: <20251202-v6-18-topic-imx93-phyboard-segin-av-02-display-v1-0-9c14be6c7478@pengutronix.de>

Hi,

this small series add the support for the phyBOARD-Segin DisplayKit
AV-02 evaluation kit. This patchset depends on the following patchsets:

 - https://lore.kernel.org/linux-arm-kernel/20251202-v6-18-topic-imx93-blkctrl-v2-0-e73501034adc at pengutronix.de/
 - https://lore.kernel.org/linux-arm-kernel/20251202-v6-18-topic-imx93-parallel-display-v7-0-2cce31d64608 at pengutronix.de/

My test setup was:
- phyCORE-i.MX93 +
- phyBOARD-Segin + 
- DisplayKit

and I used 'modeset -r' to validate the display output.

Regards,
 Marco

Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
---
Andrej Picej (1):
      arm64: dts: imx93-phyboard-segin: Add peb-av-02 overlay

Marco Felsch (1):
      clk: imx: fracn-gppll: Add 332.60 MHz Support

 arch/arm64/boot/dts/freescale/Makefile             |   2 +
 .../freescale/imx93-phyboard-segin-peb-av-02.dtso  | 135 +++++++++++++++++++++
 drivers/clk/imx/clk-fracn-gppll.c                  |   1 +
 3 files changed, 138 insertions(+)
---
base-commit: 3a8660878839faadb4f1a6dd72c3179c1df56787
change-id: 20251202-v6-18-topic-imx93-phyboard-segin-av-02-display-c1687aa1ccf4

Best regards,
-- 
Marco Felsch <m.felsch at pengutronix.de>



From m.felsch at pengutronix.de  Tue Dec  2 05:44:54 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Tue, 02 Dec 2025 14:44:54 +0100
Subject: [PATCH 2/2] arm64: dts: imx93-phyboard-segin: Add peb-av-02
 overlay
In-Reply-To: <20251202-v6-18-topic-imx93-phyboard-segin-av-02-display-v1-0-9c14be6c7478@pengutronix.de>
References: <20251202-v6-18-topic-imx93-phyboard-segin-av-02-display-v1-0-9c14be6c7478@pengutronix.de>
Message-ID: <20251202-v6-18-topic-imx93-phyboard-segin-av-02-display-v1-2-9c14be6c7478@pengutronix.de>

From: Andrej Picej <andrej.picej at norik.com>

Add overlay for Audio-Video module PEB-AV-02. Add support for panel
display, capacitive touchscreen and backlight.

For now the backlight is configured as a GPIO, brightness of the display
can not be set. When the FLEXIO PWM driver is available this should be
switched to PWM backlight driver.

Signed-off-by: Andrej Picej <andrej.picej at norik.com>
[rework commit message, use local regulator, remove compatible]
Signed-off-by: Primoz Fiser <primoz.fiser at norik.com>
Signed-off-by: Christian Hemp <c.hemp at phytec.de>
[m.felsch at pengutronix.de: cleanup downstream commit]
Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
---
 arch/arm64/boot/dts/freescale/Makefile             |   2 +
 .../freescale/imx93-phyboard-segin-peb-av-02.dtso  | 135 +++++++++++++++++++++
 2 files changed, 137 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index 525ef180481d331e9c4decd092b7b831c497b67e..27e27ac29e82bc0692e86c2ba15c240dc9fbe1c6 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -357,10 +357,12 @@ dtb-$(CONFIG_ARCH_MXC) += imx93-phyboard-nash.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx93-phyboard-segin.dtb
 
 imx93-phyboard-nash-peb-wlbt-07-dtbs += imx93-phyboard-nash.dtb imx93-phyboard-nash-peb-wlbt-07.dtbo
+imx93-phyboard-segin-peb-av-02-dtbs += imx93-phyboard-segin.dtb imx93-phyboard-segin-peb-av-02.dtbo
 imx93-phyboard-segin-peb-eval-01-dtbs += imx93-phyboard-segin.dtb imx93-phyboard-segin-peb-eval-01.dtbo
 imx93-phyboard-segin-peb-wlbt-05-dtbs += imx93-phyboard-segin.dtb imx93-phyboard-segin-peb-wlbt-05.dtbo
 imx93-phycore-rpmsg-dtbs += imx93-phyboard-nash.dtb imx93-phyboard-segin.dtb imx93-phycore-rpmsg.dtbo
 dtb-$(CONFIG_ARCH_MXC) += imx93-phyboard-nash-peb-wlbt-07.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx93-phyboard-segin-peb-av-02.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx93-phyboard-segin-peb-eval-01.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx93-phyboard-segin-peb-wlbt-05.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx93-phycore-rpmsg.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx93-phyboard-segin-peb-av-02.dtso b/arch/arm64/boot/dts/freescale/imx93-phyboard-segin-peb-av-02.dtso
new file mode 100644
index 0000000000000000000000000000000000000000..2e7074e402dc8fdeb1568d4f2d4960431e972501
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx93-phyboard-segin-peb-av-02.dtso
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2025 PHYTEC Messtechnik GmbH
+ * Copyright (C) 2025 Pengutronix
+ *
+ * Author: Andrej Picej <andrej.picej at norik.com>
+ * Author: Marco Felsch <kernel at pengutronix.de>
+ */
+
+#include <dt-bindings/clock/imx93-clock.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include "imx93-pinfunc.h"
+
+/dts-v1/;
+/plugin/;
+
+&{/} {
+	/* TODO: Convert to PWM backlight once the FlexIO PWM is supported */
+	backlight: backlight {
+		compatible = "gpio-backlight";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_backlight>;
+		gpios = <&gpio4 28 GPIO_ACTIVE_HIGH>;
+	};
+
+	panel {
+		compatible = "edt,etm0700g0edh6";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_panel>;
+
+		backlight = <&backlight>;
+		enable-gpios = <&gpio4 29 GPIO_ACTIVE_HIGH>;
+		power-supply = <&reg_x71_vcc_3v3>;
+
+		port {
+			panel_in: endpoint {
+				remote-endpoint = <&dpi_to_panel>;
+			};
+		};
+	};
+
+	reg_x71_vcc_3v3: regulator-x71-vcc-3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "X71-VCC3V3";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+	};
+};
+
+&dpi_bridge {
+	status = "okay";
+};
+
+&dpi_to_panel {
+	remote-endpoint = <&panel_in>;
+	bus-width = <18>;
+};
+
+&lcdif {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_lcdif>;
+	assigned-clocks = <&clk IMX93_CLK_VIDEO_PLL>;
+	assigned-clock-rates = <332600000>;
+	status = "okay";
+};
+
+&lpi2c2 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	touchscreen at 38 {
+		compatible = "edt,edt-ft5406";
+		reg = <0x38>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_touchscreen>;
+		interrupt-parent = <&gpio4>;
+		interrupts = <12 IRQ_TYPE_EDGE_FALLING>;
+		reset-gpios = <&gpio4 1 GPIO_ACTIVE_LOW>;
+		touchscreen-size-x = <1792>;
+		touchscreen-size-y = <1024>;
+	};
+};
+
+&media_blk_ctrl {
+	status = "okay";
+};
+
+&iomuxc {
+	pinctrl_backlight: backlightgrp {
+		fsl,pins = <
+			MX93_PAD_CCM_CLKO3__GPIO4_IO28			0x1133e
+		>;
+	};
+
+	pinctrl_lcdif: lcdifgrp {
+		fsl,pins = <
+			MX93_PAD_GPIO_IO00__MEDIAMIX_DISP_CLK		0x50e
+			MX93_PAD_GPIO_IO01__MEDIAMIX_DISP_DE		0x50e
+			MX93_PAD_GPIO_IO02__MEDIAMIX_DISP_VSYNC		0x50e
+			MX93_PAD_GPIO_IO03__MEDIAMIX_DISP_HSYNC		0x50e
+			MX93_PAD_GPIO_IO04__MEDIAMIX_DISP_DATA00	0x50e
+			MX93_PAD_GPIO_IO05__MEDIAMIX_DISP_DATA01	0x50e
+			MX93_PAD_GPIO_IO06__MEDIAMIX_DISP_DATA02	0x50e
+			MX93_PAD_GPIO_IO07__MEDIAMIX_DISP_DATA03	0x50e
+			MX93_PAD_GPIO_IO08__MEDIAMIX_DISP_DATA04	0x50e
+			MX93_PAD_GPIO_IO09__MEDIAMIX_DISP_DATA05	0x51e
+			MX93_PAD_GPIO_IO10__MEDIAMIX_DISP_DATA06	0x50e
+			MX93_PAD_GPIO_IO11__MEDIAMIX_DISP_DATA07	0x50e
+			MX93_PAD_GPIO_IO12__MEDIAMIX_DISP_DATA08	0x50e
+			MX93_PAD_GPIO_IO13__MEDIAMIX_DISP_DATA09	0x50e
+			MX93_PAD_GPIO_IO14__MEDIAMIX_DISP_DATA10	0x50e
+			MX93_PAD_GPIO_IO15__MEDIAMIX_DISP_DATA11	0x50e
+			MX93_PAD_GPIO_IO16__MEDIAMIX_DISP_DATA12	0x506
+			MX93_PAD_GPIO_IO17__MEDIAMIX_DISP_DATA13	0x506
+			MX93_PAD_GPIO_IO18__MEDIAMIX_DISP_DATA14	0x506
+			MX93_PAD_GPIO_IO19__MEDIAMIX_DISP_DATA15	0x506
+			MX93_PAD_GPIO_IO20__MEDIAMIX_DISP_DATA16	0x506
+			MX93_PAD_GPIO_IO21__MEDIAMIX_DISP_DATA17	0x506
+		>;
+	};
+
+	pinctrl_panel: panelgrp {
+		fsl,pins = <
+			MX93_PAD_CCM_CLKO4__GPIO4_IO29			0x1133e
+		>;
+	};
+
+	pinctrl_touchscreen: touchscreengrp {
+		fsl,pins = <
+			MX93_PAD_ENET1_MDIO__GPIO4_IO01			0x11e
+			MX93_PAD_ENET1_RD2__GPIO4_IO12			0x1133e
+		>;
+	};
+};

-- 
2.47.3



From geert at linux-m68k.org  Tue Dec  2 05:56:52 2025
From: geert at linux-m68k.org (Geert Uytterhoeven)
Date: Tue, 2 Dec 2025 14:56:52 +0100
Subject: [PATCH v2 02/11] cpufreq: dt-platdev: Simplify with of_machine_get_match_data()
In-Reply-To: <20251112-b4-of-match-matchine-data-v2-2-d46b72003fd6@linaro.org>
References: <20251112-b4-of-match-matchine-data-v2-0-d46b72003fd6@linaro.org> <20251112-b4-of-match-matchine-data-v2-2-d46b72003fd6@linaro.org>
Message-ID: <CAMuHMdVJD4+J9QpUUs-sX0feKfuPD72CO0dcqN7shvF_UYpZ3Q@mail.gmail.com>

Hi Krzystof,

On Wed, 12 Nov 2025 at 11:37, Krzysztof Kozlowski
<krzysztof.kozlowski at linaro.org> wrote:
> Replace open-coded getting root OF node, matching against it and getting
> the match data with two new helpers: of_machine_get_match_data() and
> of_machine_device_match().
>
> Acked-by: Viresh Kumar <viresh.kumar at linaro.org>
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>

Thanks for your patch, which is now commit 6ea891a6dd370ab2
("cpufreq: dt-platdev: Simplify with of_machine_get_match_data()")
in dt-rh/for-next.

> --- a/drivers/cpufreq/cpufreq-dt-platdev.c
> +++ b/drivers/cpufreq/cpufreq-dt-platdev.c
> @@ -219,20 +219,13 @@ static bool __init cpu0_node_has_opp_v2_prop(void)
>
>  static int __init cpufreq_dt_platdev_init(void)
>  {
> -       struct device_node *np __free(device_node) = of_find_node_by_path("/");
> -       const struct of_device_id *match;
> -       const void *data = NULL;
> +       const void *data;
>
> -       if (!np)
> -               return -ENODEV;
> -
> -       match = of_match_node(allowlist, np);
> -       if (match) {
> -               data = match->data;
> +       data = of_machine_get_match_data(allowlist);
> +       if (data)
>                 goto create_pdev;
> -       }

I think this is a change in behavior:
Before, the pdev was created immediately if the node's compatible
value is found in allowlist, regardless of the value of data (which
is always NULL, except on RK3399),
After, the pdev is created immediately if the node's compatible value
is found in allowlist, AND data is non-NULL.

>
> -       if (cpu0_node_has_opp_v2_prop() && !of_match_node(blocklist, np))
> +       if (cpu0_node_has_opp_v2_prop() && !of_machine_device_match(blocklist))
>                 goto create_pdev;
>
>         return -ENODEV;

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds


From vladimir.zapolskiy at linaro.org  Tue Dec  2 05:59:03 2025
From: vladimir.zapolskiy at linaro.org (Vladimir Zapolskiy)
Date: Tue, 2 Dec 2025 15:59:03 +0200
Subject: [PATCH v6 2/3] arm64: dts: qcom: qcs8300: Add CCI definitions
In-Reply-To: <20251126081057.4191122-3-quic_vikramsa@quicinc.com>
References: <20251126081057.4191122-1-quic_vikramsa@quicinc.com>
 <20251126081057.4191122-3-quic_vikramsa@quicinc.com>
Message-ID: <8ff6ab79-a3d3-48e3-9340-8b91a9ce1b27@linaro.org>

On 11/26/25 10:10, Vikram Sharma wrote:
> From: Nihal Kumar Gupta <quic_nihalkum at quicinc.com>
> 
> Qualcomm QCS8300 SoC contains three Camera Control Interface (CCI).
> Compared to Lemans, the key difference is in SDA/SCL GPIO assignments
> and number of CCIs.
> 
> Signed-off-by: Nihal Kumar Gupta <quic_nihalkum at quicinc.com>
> Co-developed-by: Ravi Shankar <quic_rshankar at quicinc.com>
> Signed-off-by: Ravi Shankar <quic_rshankar at quicinc.com>
> Co-developed-by: Vishal Verma <quic_vishverm at quicinc.com>
> Signed-off-by: Vishal Verma <quic_vishverm at quicinc.com>
> Co-developed-by: Suresh Vankadara <quic_svankada at quicinc.com>
> Signed-off-by: Suresh Vankadara <quic_svankada at quicinc.com>
> Signed-off-by: Vikram Sharma <quic_vikramsa at quicinc.com>
> Reviewed-by: Vladimir Zapolskiy <vladimir.zapolskiy at linaro.org>
> Reviewed-by: Bryan O'Donoghue <bryan.odonoghue at linaro.org>
> Reviewed-by: Konrad Dybcio <konrad.dybcio at oss.qualcomm.com>
> ---
>   arch/arm64/boot/dts/qcom/monaco.dtsi | 345 +++++++++++++++++++++++++++
>   1 file changed, 345 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/qcom/monaco.dtsi b/arch/arm64/boot/dts/qcom/monaco.dtsi
> index 774255c3f6fc..7c575e1c5e10 100644
> --- a/arch/arm64/boot/dts/qcom/monaco.dtsi
> +++ b/arch/arm64/boot/dts/qcom/monaco.dtsi
> @@ -4776,6 +4776,117 @@ videocc: clock-controller at abf0000 {
>   			#power-domain-cells = <1>;
>   		};
>   
> +		cci0: cci at ac13000 {
> +			compatible = "qcom,qcs8300-cci", "qcom,msm8996-cci";
> +			reg = <0x0 0x0ac13000 0x0 0x1000>;
> +
> +			interrupts = <GIC_SPI 460 IRQ_TYPE_EDGE_RISING>;
> +
> +			clocks = <&camcc CAM_CC_CPAS_AHB_CLK>,
> +				 <&camcc CAM_CC_CCI_0_CLK>;
> +			clock-names = "cpas_ahb",
> +				      "cci";
> +
> +			power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>;
> +
> +			pinctrl-0 = <&cci0_0_default &cci0_1_default>;
> +			pinctrl-1 = <&cci0_0_sleep &cci0_1_sleep>;
> +			pinctrl-names = "default", "sleep";
> +
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +
> +			status = "disabled";
> +
> +			cci0_i2c0: i2c-bus at 0 {
> +				reg = <0>;
> +				clock-frequency = <1000000>;
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +			};
> +
> +			cci0_i2c1: i2c-bus at 1 {
> +				reg = <1>;
> +				clock-frequency = <1000000>;
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +			};
> +		};
> +
> +		cci1: cci at ac14000 {
> +			compatible = "qcom,qcs8300-cci", "qcom,msm8996-cci";
> +			reg = <0x0 0x0ac14000 0x0 0x1000>;
> +
> +			interrupts = <GIC_SPI 271 IRQ_TYPE_EDGE_RISING>;
> +
> +			clocks = <&camcc CAM_CC_CPAS_AHB_CLK>,
> +				 <&camcc CAM_CC_CCI_1_CLK>;
> +			clock-names = "cpas_ahb",
> +				      "cci";
> +
> +			power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>;
> +
> +			pinctrl-0 = <&cci1_0_default &cci1_1_default>;
> +			pinctrl-1 = <&cci1_0_sleep &cci1_1_sleep>;
> +			pinctrl-names = "default", "sleep";
> +
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +
> +			status = "disabled";
> +
> +			cci1_i2c0: i2c-bus at 0 {
> +				reg = <0>;
> +				clock-frequency = <1000000>;
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +			};
> +
> +			cci1_i2c1: i2c-bus at 1 {
> +				reg = <1>;
> +				clock-frequency = <1000000>;
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +			};
> +		};
> +
> +		cci2: cci at ac15000 {
> +			compatible = "qcom,qcs8300-cci", "qcom,msm8996-cci";
> +			reg = <0x0 0x0ac15000 0x0 0x1000>;
> +
> +			interrupts = <GIC_SPI 651 IRQ_TYPE_EDGE_RISING>;
> +
> +			clocks = <&camcc CAM_CC_CPAS_AHB_CLK>,
> +				 <&camcc CAM_CC_CCI_2_CLK>;
> +			clock-names = "cpas_ahb",
> +				      "cci";
> +
> +			power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>;
> +
> +			pinctrl-0 = <&cci2_0_default &cci2_1_default>;
> +			pinctrl-1 = <&cci2_0_sleep &cci2_1_sleep>;
> +			pinctrl-names = "default", "sleep";
> +
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +
> +			status = "disabled";
> +
> +			cci2_i2c0: i2c-bus at 0 {
> +				reg = <0>;
> +				clock-frequency = <1000000>;
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +			};
> +
> +			cci2_i2c1: i2c-bus at 1 {
> +				reg = <1>;
> +				clock-frequency = <1000000>;
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +			};
> +		};
> +
>   		camss: isp at ac78000 {
>   			compatible = "qcom,qcs8300-camss";
>   
> @@ -5071,6 +5182,240 @@ tlmm: pinctrl at f100000 {
>   			#interrupt-cells = <2>;
>   			wakeup-parent = <&pdc>;
>   
> +			cam0_avdd_2v8_en_default: cam0-avdd-2v8-en-state {
> +				pins = "gpio73";
> +				function = "gpio";
> +				drive-strength = <2>;
> +				bias-disable;
> +			};
> +
> +			cam0_default: cam0-default-state {
> +				pins = "gpio67";
> +				function = "cam_mclk";
> +				drive-strength = <2>;
> +				bias-disable;
> +			};
> +
> +			cam1_avdd_2v8_en_default: cam1-avdd-2v8-en-state {
> +				pins = "gpio74";
> +				function = "gpio";
> +				drive-strength = <2>;
> +				bias-disable;
> +			};
> +
> +			cam1_default: cam1-default-state {
> +				pins = "gpio68";
> +				function = "cam_mclk";
> +				drive-strength = <2>;
> +				bias-disable;
> +			};

MCLK pad function declatarions has nothing in common with the CCI, thus it
should be split into a separate commit.

> +
> +			cam2_avdd_2v8_en_default: cam2-avdd-2v8-en-state {
> +				pins = "gpio75";
> +				function = "gpio";
> +				drive-strength = <2>;
> +				bias-disable;
> +			};

All declarations of GPIOs to enable regulators shall be moved to a board
specific .dts file.

-- 
Best wishes,
Vladimir


From geert at linux-m68k.org  Tue Dec  2 06:07:03 2025
From: geert at linux-m68k.org (Geert Uytterhoeven)
Date: Tue, 2 Dec 2025 15:07:03 +0100
Subject: [PATCH v2 01/11] of: Add wrappers to match root node with OF
 device ID tables
In-Reply-To: <20251112-b4-of-match-matchine-data-v2-1-d46b72003fd6@linaro.org>
References: <20251112-b4-of-match-matchine-data-v2-0-d46b72003fd6@linaro.org> <20251112-b4-of-match-matchine-data-v2-1-d46b72003fd6@linaro.org>
Message-ID: <CAMuHMdVAZpp7M+pp27+kHZwoet2Q8Rm-Y4ePu7=W_1oXhebLmQ@mail.gmail.com>

Hi Krzysztof,

Thanks for your patch, which is now commit 4a93adcbd201aad5
("of: Add wrappers to match root node with OF device ID tables")
in dt-rh/for-next.

On Wed, 12 Nov 2025 at 11:30, Krzysztof Kozlowski
<krzysztof.kozlowski at linaro.org> wrote:
> Several drivers duplicate same code for getting reference to the root
> node, matching it against 'struct of_device_id' table and getting out
> the match data from the table entry.
>
> There is a of_machine_compatible_match() wrapper but it takes array of
> strings, which is not suitable for many drivers since they want the
> driver data associated with each compatible.
>
> Add two wrappers, similar to existing of_device_get_match_data():
> 1. of_machine_device_match() doing only matching against 'struct
>    of_device_id' and returning bool.
> 2. of_machine_get_match_data() doing the matching and returning
>    associated driver data for found compatible.

Shouldn't the first function be called of_match_machine(), and return
a const struct of_device_id *, cfr. of_match_device()?

>
> Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>

> --- a/drivers/of/base.c
> +++ b/drivers/of/base.c
> @@ -434,6 +434,53 @@ bool of_machine_compatible_match(const char *const *compats)
>  }
>  EXPORT_SYMBOL(of_machine_compatible_match);
>
> +/**
> + * of_machine_device_match - Test root of device tree against a of_device_id array
> + * @matches:   NULL terminated array of of_device_id match structures to search in
> + *
> + * Returns true if the root node has any of the given compatible values in its
> + * compatible property.
> + */
> +bool of_machine_device_match(const struct of_device_id *matches)
> +{
> +       struct device_node *root;
> +       const struct of_device_id *match = NULL;
> +
> +       root = of_find_node_by_path("/");
> +       if (root) {
> +               match = of_match_node(matches, root);
> +               of_node_put(root);
> +       }
> +
> +       return match != NULL;
> +}
> +EXPORT_SYMBOL(of_machine_device_match);
> +
> +/**
> + * of_machine_get_match_data - Tell if root of device tree has a matching of_match structure
> + * @matches:   NULL terminated array of of_device_id match structures to search in
> + *
> + * Returns data associated with matched entry or NULL
> + */
> +const void *of_machine_get_match_data(const struct of_device_id *matches)
> +{
> +       const struct of_device_id *match;
> +       struct device_node *root;
> +
> +       root = of_find_node_by_path("/");
> +       if (!root)
> +               return NULL;
> +
> +       match = of_match_node(matches, root);
> +       of_node_put(root);
> +
> +       if (!match)
> +               return NULL;
> +
> +       return match->data;
> +}
> +EXPORT_SYMBOL(of_machine_get_match_data);

These two functions are very similar, but look different.  If the
former would return a pointer instead of a bool, the latter could be
built on top.

Even if you still prefer returning a bool, they could share a common
private helper returning a pointer.

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds


From robh at kernel.org  Tue Dec  2 06:15:23 2025
From: robh at kernel.org (Rob Herring)
Date: Tue, 2 Dec 2025 08:15:23 -0600
Subject: [PATCH v7 2/2] remoteproc: qcom: Use of_reserved_mem_region_*
 functions for "memory-region"
In-Reply-To: <674efe8d-c299-4ce9-bf6b-c1920a5393eb@samsung.com>
References: <20251124182751.507624-1-robh@kernel.org> <CGME20251127142839eucas1p186846c6c1ea1d9e43369fbba9bb5d17c@eucas1p1.samsung.com>
 <20251124182751.507624-2-robh@kernel.org> <674efe8d-c299-4ce9-bf6b-c1920a5393eb@samsung.com>
Message-ID: <CAL_JsqJTrGAJx-fv8OQGDhsLVKavQzzQotssEq_E5f_aJe8bOg@mail.gmail.com>

On Thu, Nov 27, 2025 at 8:28?AM Marek Szyprowski
<m.szyprowski at samsung.com> wrote:
>
> Hi Rob,
>
> On 24.11.2025 19:27, Rob Herring (Arm) wrote:
> > Use the newly added of_reserved_mem_region_to_resource() and
> > of_reserved_mem_region_count() functions to handle "memory-region"
> > properties.
> >
> > The error handling is a bit different in some cases. Often
> > "memory-region" is optional, so failed lookup is not an error. But then
> > an error in of_reserved_mem_lookup() is treated as an error. However,
> > that distinction is not really important. Either the region is available
> > and usable or it is not. So now, it is just
> > of_reserved_mem_region_to_resource() which is checked for an error.
> >
> > Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
>
> This patch landed in today's linux-next as commit c70b9d5fdcd7
> ("remoteproc: qcom: Use of_reserved_mem_region_* functions for
> "memory-region""). In my tests I found that it breaks booting of
> DragonBoard410c (arch/arm64/boot/dts/qcom/apq8016-sbc.dts) by causing
> the NULL pointer dereference. The issue is caused by replacing
> devm_ioremap_wc() with devm_ioremap_resource_wc(), which fails on
> devm_request_mem_region(), see comment in the code below. It looks that
> the error handling is somewhere broken. Here is the the kernel log:
>
> remoteproc remoteproc0: 4080000.remoteproc is available
> qcom-wcnss-pil a204000.remoteproc: error -EBUSY: can't request region
> for resource [mem 0x8e200000-0x8e7fffff]
> remoteproc remoteproc1: a204000.remoteproc is available
> remoteproc remoteproc1: powering up a204000.remoteproc
> remoteproc remoteproc1: Booting fw image qcom/apq8016/wcnss.mbn, size
> 4111376
> Unable to handle kernel paging request at virtual address fffffffffffffff0
> Mem abort info:
> ...
> Internal error: Oops: 0000000096000046 [#1]  SMP
> Modules linked in: cpufreq_powersave qcom_wcnss_pil cpufreq_conservative
> coresight_stm coresight_replicator coresight_tmc coresight_tpiu stm_core
> coresight_funnel coresight_cpu_debug coresight_cti(+) adv7511 coresight
> nfc rfkill msm snd_soc_lpass_apq8016 snd_soc_apq8016_sbc
> snd_soc_lpass_cpu snd_soc_msm8916_analog snd_soc_msm8916_digital
> snd_soc_qcom_common snd_soc_lpass_platform snd_soc_core qrtr ubwc_config
> snd_compress llcc_qcom snd_pcm_dmaengine qcom_q6v5_mss snd_pcm ocmem
> qcom_pil_info qcom_spmi_vadc qcom_camss drm_gpuvm qcom_pon rtc_pm8xxx
> qcom_q6v5 qcom_spmi_temp_alarm venus_core qcom_vadc_common snd_timer
> drm_exec qcom_sysmon snd qcom_common gpu_sched videobuf2_dma_sg
> v4l2_mem2mem qcom_glink_smem v4l2_fwnode soundcore drm_dp_aux_bus
> qmi_helpers mdt_loader v4l2_async videobuf2_memops videobuf2_v4l2
> videodev qnoc_msm8916 videobuf2_common qcom_rng drm_display_helper mc
> qcom_stats rpmsg_ctrl rpmsg_char display_connector ramoops socinfo
> rmtfs_mem reed_solomon ax88796b asix usbnet phy_qcom_usb_hs ipv6 libsha1
> CPU: 2 UID: 0 PID: 28 Comm: kworker/2:0 Tainted: G W
> 6.18.0-rc1+ #16209 PREEMPT
> Tainted: [W]=WARN
> lr : __qcom_mdt_load+0x210/0x304 [mdt_loader]
> Call trace:
>   __pi_memcpy_generic+0x128/0x22c (P)
>   qcom_mdt_load+0x68/0x60c [mdt_loader]
>   wcnss_load+0x2c/0x5c [qcom_wcnss_pil]
>   rproc_start+0x30/0x1b4
>   rproc_boot+0x19c/0x560
>   rproc_auto_boot_callback+0x1c/0x34
>   request_firmware_work_func+0x4c/0x98
>   process_one_work+0x208/0x60c
>   worker_thread+0x244/0x388
>   kthread+0x150/0x228
>   ret_from_fork+0x10/0x20
> Code: 927cec03 cb0e0021 8b0e0042 a9411c26 (a900340c)
> ---[ end trace 0000000000000000 ]---
>
>
> > ---
> > v7:
> >   - Split QCom to separate patch
> > ---
> >   drivers/remoteproc/qcom_q6v5_adsp.c | 24 ++++------
> >   drivers/remoteproc/qcom_q6v5_mss.c  | 60 ++++++++-----------------
> >   drivers/remoteproc/qcom_q6v5_pas.c  | 69 +++++++++++------------------
> >   drivers/remoteproc/qcom_q6v5_wcss.c | 25 +++++------
> >   drivers/remoteproc/qcom_wcnss.c     | 23 ++++------
> >   5 files changed, 72 insertions(+), 129 deletions(-)
> >
>
> > ...
>
> > diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
> > index 2c7e519a2254..14005fb049a2 100644
> > --- a/drivers/remoteproc/qcom_wcnss.c
> > +++ b/drivers/remoteproc/qcom_wcnss.c
> > @@ -526,25 +526,20 @@ static int wcnss_request_irq(struct qcom_wcnss *wcnss,
> >
> >   static int wcnss_alloc_memory_region(struct qcom_wcnss *wcnss)
> >   {
> > -     struct reserved_mem *rmem = NULL;
> > -     struct device_node *node;
> > -
> > -     node = of_parse_phandle(wcnss->dev->of_node, "memory-region", 0);
> > -     if (node)
> > -             rmem = of_reserved_mem_lookup(node);
> > -     of_node_put(node);
> > +     struct resource res;
> > +     int ret;
> >
> > -     if (!rmem) {
> > +     ret = of_reserved_mem_region_to_resource(wcnss->dev->of_node, 0, &res);
> > +     if (ret) {
> >               dev_err(wcnss->dev, "unable to resolve memory-region\n");
> > -             return -EINVAL;
> > +             return ret;
> >       }
> >
> > -     wcnss->mem_phys = wcnss->mem_reloc = rmem->base;
> > -     wcnss->mem_size = rmem->size;
> > -     wcnss->mem_region = devm_ioremap_wc(wcnss->dev, wcnss->mem_phys, wcnss->mem_size);
> > +     wcnss->mem_phys = wcnss->mem_reloc = res.start;
> > +     wcnss->mem_size = resource_size(&res);
> > +     wcnss->mem_region = devm_ioremap_resource_wc(wcnss->dev, &res);
>
> The above line causes the failure. After restoring it to:
>
> wcnss->mem_region = devm_ioremap_wc(wcnss->dev, wcnss->mem_phys, wcnss->mem_size);
>
> the mentioned board boots fine again. I'm not sure about other drivers,
> if they also fail the same way as they might not be used on the tested
> board.

Other platforms (non-QCom) were tested also use
devm_ioremap_resource_wc(). So something else is claiming the same
region? Can you dump out /proc/iomem?

The region is dynamically allocated, so maybe that has something to do with it.

Rob


From bigeasy at linutronix.de  Tue Dec  2 06:18:16 2025
From: bigeasy at linutronix.de (Sebastian Andrzej Siewior)
Date: Tue, 2 Dec 2025 15:18:16 +0100
Subject: [PATCH v3 2/5] ARM: mm: fault: Enable interrupts before invoking
 __do_user_fault()
In-Reply-To: <20251110145555.2555055-3-bigeasy@linutronix.de>
References: <20251110145555.2555055-1-bigeasy@linutronix.de>
 <20251110145555.2555055-3-bigeasy@linutronix.de>
Message-ID: <20251202141816.wfHNUMFK@linutronix.de>

On 2025-11-10 15:55:52 [+0100], To linux-arm-kernel at lists.infradead.org wrote:
|
|   https://www.armlinux.org.uk/developer/patches/viewpatch.php?id=9460/1
|
| Moved to Discarded.
|
| This makes the issues with the branch predictor hardening worse if this
| patch is merged on its own - since this adds another path where
| interrupts are enabled before calling harden_branch_predictor() in
| __do_user_fault(). It would be sensible to move the interrupt enable
| into __do_user_fault().
|
|    *** PLEASE DO NOT REPLY TO THIS MESSAGE ***

I thought that we apply both.
In 9462/1 I am moving harden_branch_predictor() out of __do_user_fault()
because do_page_fault() needs the hardening before the interrupts are
enabled. Do mean something like

diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 2bc828a1940c0..f70b98fb562b3 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -186,6 +186,7 @@ __do_user_fault(unsigned long addr, unsigned int fsr, unsigned int sig,
 	if (addr > TASK_SIZE)
 		harden_branch_predictor();
 
+	local_irq_enable();
 #ifdef CONFIG_DEBUG_USER
 	if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) ||
 	    ((user_debug & UDBG_BUS)  && (sig == SIGBUS))) {
@@ -274,8 +275,13 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 
 
 	/* Enable interrupts if they were enabled in the parent context. */
-	if (interrupts_enabled(regs))
+	if (interrupts_enabled(regs)) {
+		if (addr >= TASK_SIZE && user_mode(regs)) {
+			__do_user_fault(addr, fsr, SIGSEGV, SEGV_MAPERR, regs);
+			return 0;
+		}
 		local_irq_enable();
+	}
 
 	/*
 	 * If we're in an interrupt or have no user

instead both patches? So now we end up in __do_user_fault() via
do_page_fault() with enabled interrupts but only for addr < TASK_SIZE
which does not involve harden_branch_predictor().

Sebastian


From leo.yan at arm.com  Tue Dec  2 06:21:55 2025
From: leo.yan at arm.com (Leo Yan)
Date: Tue, 2 Dec 2025 14:21:55 +0000
Subject: [PATCH 07/19] coresight: trbe: Refactor AUX flag setting
In-Reply-To: <e315b489-2ebf-4ab6-8a60-347f1b1dca16@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-7-7da32b076b28@arm.com>
 <e315b489-2ebf-4ab6-8a60-347f1b1dca16@arm.com>
Message-ID: <20251202142155.GB724103@e132581.arm.com>

On Tue, Dec 02, 2025 at 11:15:47AM +0000, Suzuki K Poulose wrote:

[...]

> > @@ -687,6 +668,23 @@ static enum trbe_fault_action trbe_get_fault_act(struct perf_output_handle *hand
> >   		goto out_fatal;
> >   	}
> > +	/*
> > +	 * Mark the buffer to indicate that there was a WRAP event by
> > +	 * setting the COLLISION flag. This indicates to the user that
> > +	 * the TRBE trace collection was stopped without stopping the
> > +	 * ETE and thus there might be some amount of trace that was
> > +	 * lost between the time the WRAP was detected and the IRQ
> > +	 * was consumed by the CPU.
> > +	 *
> > +	 * Setting the TRUNCATED flag would move the event to STOPPED
> > +	 * state unnecessarily, even when there is space left in the
> > +	 * ring buffer. Using the COLLISION flag doesn't have this side
> > +	 * effect. We only set TRUNCATED flag when there is no space
> > +	 * left in the ring buffer.
> > +	 */
> > +	if (!is_trbe_running(trbsr))
> 
> Is this really required ? There is a WARN_ON(is_trbe_running(trbsr))
> above ?

The WARN_ON() will reports warning for running case, here it sets
COLLISION flag for not running case, which is not conflict.

This works for the Fill mode (stop collection), we always set the
COLLISION flag for it.  Once we enable trigger and wrap modes, due to
the trace continues to run, we don't set the flag for these modes.

> > +		perf_aux_output_flag(handle, PERF_AUX_FLAG_COLLISION);
> 
> Also, setting this would unnecessarily mark COLLISION while stopping the
> TRBE buffer normally (when called from arm_trbe_update_buffer), when
> there is no WRAP event ?

Good point.  I should refactor arm_trbe_update_buffer(), it firstly
reads out TRBSR, stop trace afterwards, and then call
trbe_get_fault_act().

In this case, it is in running mode so COLLISION will not be set for
normal disable flow.

I will add a new patch for this and place it before this one.

> > +
> >   	if (is_trbe_wrap(trbsr))
> >   		return TRBE_FAULT_ACT_WRAP;
> 
> Couldn't this be :
> 
> 	/* Move the big fat comment here */
> 	if (is_trbe_wrap(trbsr)) {
> 		perf_aux_output_flag(handle, PERF_AUX_FLAG_COLLISION);
> 		return TRBE_FAULT_ACT_WRAP;
> 	}

It deliberately de-couples the COLLISION flag from the WRAP event.

In later change, a WRAP event only means buffer wrap around, it does
mean the trace has been stopped.  The AUX flag is only set for
stopping case.

Thanks,
Leo


From leo.yan at arm.com  Tue Dec  2 06:24:16 2025
From: leo.yan at arm.com (Leo Yan)
Date: Tue, 2 Dec 2025 14:24:16 +0000
Subject: [PATCH 06/19] coresight: trbe: Refactor syndrome decoding
In-Reply-To: <65c84357-0bda-454f-88c3-623b3ff9d29d@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-6-7da32b076b28@arm.com>
 <65c84357-0bda-454f-88c3-623b3ff9d29d@arm.com>
Message-ID: <20251202142416.GC724103@e132581.arm.com>

On Tue, Dec 02, 2025 at 11:06:48AM +0000, Suzuki K Poulose wrote:
> Hi Leo
> 
> A couple of minor nits below. Otherwise looks like a nice cleanup
> 
> 
> On 01/12/2025 11:21, Leo Yan wrote:
> > It gives priority to TRBSR_EL1.EA (external abort); an external abort
> > will immediately bail out and return an error.
> > 
> > Next, the syndrome decoding is refactored based on two levels of
> > information: the EC (Event Class) bits and the BSC (Trace Buffer Status
> > Code) bits.
> > 
> > If TRBSR_EL1.EC==0b000000, the driver continues parsing TRBSR_EL1.BSC to
> > identify the specific trace buffer event.  Otherwise, any non-zero
> > TRBSR_EL1.EC is treated as an error.
> > 
> > For error cases, the driver prints an error string and dumps registers
> > for debugging.
> 
> minor nit: Please avoid describing the code, which cod does well.
> Briefly mention what you are doing, giving any additional contexts
> that may not be evident from the code.

Sure, I will note this later.

> e.g:
> 
> "Add support for decoding the syndrome for TRBE, providing a verbose
> description of the code for Fatal/unhandled events.
> While at it add the new definitions from the latest Arm ARM for
> EC and BSC"

Will do this and followed comment.  Thanks for suggestion!

Leo


From cniedermaier at dh-electronics.com  Tue Dec  2 06:32:38 2025
From: cniedermaier at dh-electronics.com (Christoph Niedermaier)
Date: Tue, 2 Dec 2025 14:32:38 +0000
Subject: [PATCH] arm64: dts: imx8mp: Fix LAN8740Ai PHY reference clock on
 DH electronics i.MX8M Plus DHCOM
In-Reply-To: <20251202134200.8397-1-marek.vasut@mailbox.org>
References: <20251202134200.8397-1-marek.vasut@mailbox.org>
Message-ID: <12d58795b3664ff08e509f0a0929d1b9@dh-electronics.com>

From: Marek Vasut <marek.vasut at mailbox.org>
Sent: Tuesday, December 2, 2025 2:42 PM
> Add missing 'clocks' property to LAN8740Ai PHY node, to allow the PHY driver
> to manage LAN8740Ai CLKIN reference clock supply. This fixes sporadic link
> bouncing caused by interruptions on the PHY reference clock, by letting the
> PHY driver manage the reference clock and assure there are no interruptions.
> 
> This follows the matching PHY driver recommendation described in commit
> bedd8d78aba3 ("net: phy: smsc: LAN8710/20: add phy refclk in support")
> 
> Fixes: 8d6712695bc8 ("arm64: dts: imx8mp: Add support for DH electronics i.MX8M Plus DHCOM
> and PDK2")
> Signed-off-by: Marek Vasut <marek.vasut at mailbox.org>
> ---
> Cc: Christoph Niedermaier <cniedermaier at dh-electronics.com>
> Cc: Conor Dooley <conor+dt at kernel.org>
> Cc: Fabio Estevam <festevam at gmail.com>
> Cc: Krzysztof Kozlowski <krzk+dt at kernel.org>
> Cc: Pengutronix Kernel Team <kernel at pengutronix.de>
> Cc: Rob Herring <robh at kernel.org>
> Cc: Sascha Hauer <s.hauer at pengutronix.de>
> Cc: Shawn Guo <shawnguo at kernel.org>
> Cc: devicetree at vger.kernel.org
> Cc: imx at lists.linux.dev
> Cc: kernel at dh-electronics.com
> Cc: linux-arm-kernel at lists.infradead.org
> ---
>  arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi
> b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi
> index 68c2e0156a5c8..f8303b7e2bd22 100644
> --- a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi
> +++ b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi
> @@ -113,6 +113,7 @@ mdio {
>                 ethphy0f: ethernet-phy at 1 { /* SMSC LAN8740Ai */
>                         compatible = "ethernet-phy-id0007.c110",
>                                      "ethernet-phy-ieee802.3-c22";
> +                       clocks = <&clk IMX8MP_CLK_ENET_QOS>;
>                         interrupt-parent = <&gpio3>;
>                         interrupts = <19 IRQ_TYPE_LEVEL_LOW>;
>                         pinctrl-0 = <&pinctrl_ethphy0>;

Tested-by: Christoph Niedermaier <cniedermaier at dh-electronics.com>

Regards
Christoph

From john.ogness at linutronix.de  Tue Dec  2 06:33:54 2025
From: john.ogness at linutronix.de (John Ogness)
Date: Tue, 02 Dec 2025 15:39:54 +0106
Subject: [PATCH] printk/nbcon: Restore IRQ in atomic flush after each
 emitted record
In-Reply-To: <20251202135832.156559-1-pmladek@suse.com>
References: <20251202135832.156559-1-pmladek@suse.com>
Message-ID: <87o6oheywd.fsf@jogness.linutronix.de>

On 2025-12-02, Petr Mladek <pmladek at suse.com> wrote:
> diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
> index 3fa403f9831f..6b8becb6ecd9 100644
> --- a/kernel/printk/nbcon.c
> +++ b/kernel/printk/nbcon.c
> @@ -1549,6 +1549,7 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
>  {
>  	struct nbcon_write_context wctxt = { };
>  	struct nbcon_context *ctxt = &ACCESS_PRIVATE(&wctxt, ctxt);
> +	unsigned long flags;
>  	int err = 0;
>  
>  	ctxt->console			= con;
> @@ -1557,18 +1558,31 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
>  	ctxt->allow_unsafe_takeover	= nbcon_allow_unsafe_takeover();
>  
>  	while (nbcon_seq_read(con) < stop_seq) {
> -		if (!nbcon_context_try_acquire(ctxt, false))
> +		/*
> +		 * Atomic flushing does not use console driver synchronization
> +		 * (i.e. it does not hold the port lock for uart consoles).
> +		 * Therefore IRQs must be disabled to avoid being interrupted
> +		 * and then calling into a driver that will deadlock trying
> +		 * to acquire console ownership.
> +		 */
> +		local_irq_save(flags);
> +		if (!nbcon_context_try_acquire(ctxt, false)) {
> +			local_irq_restore(flags);
>  			return -EPERM;
> +		}
>  
>  		/*
>  		 * nbcon_emit_next_record() returns false when the console was
>  		 * handed over or taken over. In both cases the context is no
>  		 * longer valid.
>  		 */
> -		if (!nbcon_emit_next_record(&wctxt, true))
> +		if (!nbcon_emit_next_record(&wctxt, true)) {
> +			local_irq_restore(flags);
>  			return -EAGAIN;
> +		}
>  
>  		nbcon_context_release(ctxt);
> +		local_irq_restore(flags);


I am not really happy about all the local_irq_restore() usage. Using
guard syntax would be nice here, but AFAICT there is no guard for
local_irq_save()/_restore(). :-/ And I could not come up with any other
alternative that looked more elegant. So let's just keep it this way.

Reviewed-by: John Ogness <john.ogness at linutronix.de>


From s.pueschel at pengutronix.de  Tue Dec  2 06:36:33 2025
From: s.pueschel at pengutronix.de (=?UTF-8?Q?Sven_P=C3=BCschel?=)
Date: Tue, 2 Dec 2025 15:36:33 +0100
Subject: [PATCH 03/16] media: rockchip: rga: align stride to 16 bytes
In-Reply-To: <db7030790063d0ebe6d254c7053e758184b9d7cc.camel@ndufresne.ca>
References: <20251007-spu-rga3-v1-0-36ad85570402@pengutronix.de>
 <20251007-spu-rga3-v1-3-36ad85570402@pengutronix.de>
 <db7030790063d0ebe6d254c7053e758184b9d7cc.camel@ndufresne.ca>
Message-ID: <2dc6c675-9c69-40a1-b2ed-ff1d22157228@pengutronix.de>

Hi Nicolas,

On 10/7/25 8:19 PM, Nicolas Dufresne wrote:
> Hi,
>
>
> Le mardi 07 octobre 2025 ? 10:31 +0200, Sven P?schel a ?crit?:
>> Align the stride to a multiple of 16 according to the RGA3 requirements
>> mentioned in the datasheet. This also ensures that the stride of the RGA2
>> is aligned to 4 bytes, as it needs to divide the value by 4 (one word)
>> before storing it in the register.
>>
>> Increasing the stride for the alignment also requires to increase the
>> sizeimage value. This is usually handled by v4l2_fill_pixfmt_mp, but
>> it doesn't allow to set a stride alignment. Therefore use the generated
>> values to calculate the total number of lines to properly update the
>> sizeimage value after the bytesperline has been aligned.
>>
>> Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
>> ---
>>  ?drivers/media/platform/rockchip/rga/rga.c | 21 +++++++++++++++++++++
>>  ?1 file changed, 21 insertions(+)
>>
>> diff --git a/drivers/media/platform/rockchip/rga/rga.c
>> b/drivers/media/platform/rockchip/rga/rga.c
>> index
>> 6438119a6c7aeff1e89e7aa95dcd5d2921fefa08..3cb7ce470c47e39d694e8176875a75fad271
>> 7f96 100644
>> --- a/drivers/media/platform/rockchip/rga/rga.c
>> +++ b/drivers/media/platform/rockchip/rga/rga.c
>> @@ -459,6 +459,25 @@ static int vidioc_enum_fmt(struct file *file, void *priv,
>> struct v4l2_fmtdesc *f
>>  ?	return 0;
>>  ?}
>>   
>> +static void align_pixfmt(struct v4l2_pix_format_mplane *pix_fmt)
>> +{
>> +	int lines;
>> +	struct v4l2_plane_pix_format *fmt;
>> +
>> +	/*
>> +	 * Align stride to 16 for the RGA3 (based on the datasheet)
>> +	 * To not dismiss the v4l2_fill_pixfmt_mp helper
>> +	 * (and manually write it again), we're approximating the new
>> sizeimage
>> +	 */
>> +	for (fmt = pix_fmt->plane_fmt;
>> +	???? fmt < pix_fmt->plane_fmt + pix_fmt->num_planes;
>> +	???? fmt++) {
>> +		lines = DIV_ROUND_UP(fmt->sizeimage, fmt->bytesperline);
>> +		fmt->bytesperline = (fmt->bytesperline + 0xf) & ~0xf;
>> +		fmt->sizeimage = fmt->bytesperline * lines;
> Instead of open coding this, describe this with struct v4l2_frmsize_stepwise and
> then use v4l2_apply_frmsize_constraints().
Looking into v4l2_frmsize_stepwise, it only applies to the width/height 
values, whereas I'm interested to control the stride 
byte-alignment/stepping (allowing free range widths/heights).

Do you intent that I (mis)use it like this: 
v4l2_apply_frmsize_constraints(&fmt->bytesperline, &lines, &constraints)? ?

This only replaces one of the three lines in the for loop (where i 
manually do the alignment with & ~0xf) and would also look odd, as i use 
a value in bytes as a width parameter (expected to be in pixels).

Technically the core problem is that the v4l2_fill_pixfmt_mp helper 
doesn't allow to specify a stride byte alignment and just aligns the 
stride based on the format requirements. Therefore I think that maybe 
creating a new v4l2_fill_pixfmt_mp_aligned helper would probably be the 
better solution to get the correct bytesperline value right from the 
start instead of adjusting it afterwards.

Sincerely
 ? ? Sven
>
> Nicolas
>
>> +	}
>> +}
>> +
>>  ?static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
>>  ?{
>>  ?	struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp;
>> @@ -474,6 +493,7 @@ static int vidioc_g_fmt(struct file *file, void *priv,
>> struct v4l2_format *f)
>>  ?		return PTR_ERR(frm);
>>   
>>  ?	v4l2_fill_pixfmt_mp(pix_fmt, frm->fmt->fourcc, frm->width, frm-
>>> height);
>> +	align_pixfmt(pix_fmt);
>>   
>>  ?	pix_fmt->field = V4L2_FIELD_NONE;
>>  ?	pix_fmt->colorspace = frm->colorspace;
>> @@ -496,6 +516,7 @@ static int vidioc_try_fmt(struct file *file, void *priv,
>> struct v4l2_format *f)
>>  ?				(u32)MIN_HEIGHT, (u32)MAX_HEIGHT);
>>   
>>  ?	v4l2_fill_pixfmt_mp(pix_fmt, fmt->fourcc, pix_fmt->width, pix_fmt-
>>> height);
>> +	align_pixfmt(pix_fmt);
>>  ?	pix_fmt->field = V4L2_FIELD_NONE;
>>   
>>  ?	return 0;


From Frank.li at nxp.com  Tue Dec  2 06:40:23 2025
From: Frank.li at nxp.com (Frank Li)
Date: Tue, 2 Dec 2025 09:40:23 -0500
Subject: [PATCH v2 2/3] pmdomain: imx93-blk-ctrl: convert to devm_* only
In-Reply-To: <20251202-v6-18-topic-imx93-blkctrl-v2-2-e73501034adc@pengutronix.de>
References: <20251202-v6-18-topic-imx93-blkctrl-v2-0-e73501034adc@pengutronix.de>
 <20251202-v6-18-topic-imx93-blkctrl-v2-2-e73501034adc@pengutronix.de>
Message-ID: <aS76V3IFDdz9N2E4@lizhi-Precision-Tower-5810>

On Tue, Dec 02, 2025 at 02:21:03PM +0100, Marco Felsch wrote:
> Convert the driver to devm_ APIs only by making use of
> devm_add_action_or_reset() and devm_pm_runtime_enable() to simplify the
> probe error path and to drop the .remove() callback. This also ensures
> that the device release order equals the device probe error path order.
>
> Furthermore drop the dev_set_drvdata() usage since the only user was the
> .remove() callback which is removed by this commit.
>
> Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
> ---

Reviewed-by: Frank Li <Frank.Li at nxp.com>

>  drivers/pmdomain/imx/imx93-blk-ctrl.c | 66 +++++++++++++++--------------------
>  1 file changed, 29 insertions(+), 37 deletions(-)
>
> diff --git a/drivers/pmdomain/imx/imx93-blk-ctrl.c b/drivers/pmdomain/imx/imx93-blk-ctrl.c
> index 2aa163aef8de4ee901b9cde76ce2aad246c8c08a..49610f2389c3bbaf4de4133918fbcacb7924f672 100644
> --- a/drivers/pmdomain/imx/imx93-blk-ctrl.c
> +++ b/drivers/pmdomain/imx/imx93-blk-ctrl.c
> @@ -188,6 +188,20 @@ static int imx93_blk_ctrl_power_off(struct generic_pm_domain *genpd)
>  	return 0;
>  }
>
> +static void imx93_release_genpd_provider(void *data)
> +{
> +	struct device_node *of_node = data;
> +
> +	of_genpd_del_provider(of_node);
> +}
> +
> +static void imx93_release_pm_genpd(void *data)
> +{
> +	struct generic_pm_domain *genpd = data;
> +
> +	pm_genpd_remove(genpd);
> +}
> +
>  static struct lock_class_key blk_ctrl_genpd_lock_class;
>
>  static int imx93_blk_ctrl_probe(struct platform_device *pdev)
> @@ -256,10 +270,8 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
>  			domain->clks[j].id = data->clk_names[j];
>
>  		ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks);
> -		if (ret) {
> -			dev_err_probe(dev, ret, "failed to get clock\n");
> -			goto cleanup_pds;
> -		}
> +		if (ret)
> +			return dev_err_probe(dev, ret, "failed to get clock\n");
>
>  		domain->genpd.name = data->name;
>  		domain->genpd.power_on = imx93_blk_ctrl_power_on;
> @@ -267,11 +279,12 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
>  		domain->bc = bc;
>
>  		ret = pm_genpd_init(&domain->genpd, NULL, true);
> -		if (ret) {
> -			dev_err_probe(dev, ret, "failed to init power domain\n");
> -			goto cleanup_pds;
> -		}
> +		if (ret)
> +			return dev_err_probe(dev, ret, "failed to init power domain\n");
>
> +		ret = devm_add_action_or_reset(dev, imx93_release_pm_genpd, &domain->genpd);
> +		if (ret)
> +			return dev_err_probe(dev, ret, "failed to add pm_genpd release callback\n");
>  		/*
>  		 * We use runtime PM to trigger power on/off of the upstream GPC
>  		 * domain, as a strict hierarchical parent/child power domain
> @@ -288,39 +301,19 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
>  		bc->onecell_data.domains[i] = &domain->genpd;
>  	}
>
> -	pm_runtime_enable(dev);
> +	ret = devm_pm_runtime_enable(dev);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to enable pm-runtime\n");
>
>  	ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data);
> -	if (ret) {
> -		dev_err_probe(dev, ret, "failed to add power domain provider\n");
> -		goto cleanup_pds;
> -	}
> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to add power domain provider\n");
>
> -	dev_set_drvdata(dev, bc);
> +	ret = devm_add_action_or_reset(dev, imx93_release_genpd_provider, dev->of_node);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to add genpd_provider release callback\n");
>
>  	return 0;
> -
> -cleanup_pds:
> -	for (i--; i >= 0; i--)
> -		pm_genpd_remove(&bc->domains[i].genpd);
> -
> -	return ret;
> -}
> -
> -static void imx93_blk_ctrl_remove(struct platform_device *pdev)
> -{
> -	struct imx93_blk_ctrl *bc = dev_get_drvdata(&pdev->dev);
> -	int i;
> -
> -	of_genpd_del_provider(pdev->dev.of_node);
> -
> -	pm_runtime_disable(&pdev->dev);
> -
> -	for (i = 0; i < bc->onecell_data.num_domains; i++) {
> -		struct imx93_blk_ctrl_domain *domain = &bc->domains[i];
> -
> -		pm_genpd_remove(&domain->genpd);
> -	}
>  }
>
>  static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] = {
> @@ -455,7 +448,6 @@ MODULE_DEVICE_TABLE(of, imx93_blk_ctrl_of_match);
>
>  static struct platform_driver imx93_blk_ctrl_driver = {
>  	.probe = imx93_blk_ctrl_probe,
> -	.remove = imx93_blk_ctrl_remove,
>  	.driver = {
>  		.name = "imx93-blk-ctrl",
>  		.of_match_table = imx93_blk_ctrl_of_match,
>
> --
> 2.47.3
>


From Frank.li at nxp.com  Tue Dec  2 06:48:36 2025
From: Frank.li at nxp.com (Frank Li)
Date: Tue, 2 Dec 2025 09:48:36 -0500
Subject: [PATCH] arm64: dts: imx8qm-ss-dma: correct the dma channels of
 lpuart
In-Reply-To: <2395053.ElGaqSPkdT@steina-w>
References: <20251202111638.3553-1-sherry.sun@nxp.com>
 <2395053.ElGaqSPkdT@steina-w>
Message-ID: <aS78RJQAJDf6iU6X@lizhi-Precision-Tower-5810>

On Tue, Dec 02, 2025 at 12:48:15PM +0100, Alexander Stein wrote:
> Hi,
>
> Am Dienstag, 2. Dezember 2025, 12:16:38 CET schrieb Sherry Sun:
> > The commit 616effc0272b5 ("arm64: dts: imx8: Fix lpuart DMA channel
> > order") swap uart rx and tx channel at common imx8-ss-dma.dtsi. But miss
> > update imx8qm-ss-dma.dtsi.
> >
> > The commit 5a8e9b022e569 ("arm64: dts: imx8qm-ss-dma: Pass lpuart
> > dma-names") just simple add dma-names as binding doc requirement.
> >
> > Correct lpuart0 - lpuart3 dma rx and tx channels, and use defines for
> > the FSL_EDMA_RX flag.
> >
> > Fixes: 616effc0272b5 ("arm64: dts: imx8: Fix lpuart DMA channel order")
>
> I'm wondering if this is actually a fix for 5a8e9b022e569 ("arm64: dts:
> imx8qm-ss-dma: Pass lpuart dma-names") instead. 616effc0272b5 just
> focuses on the common parts. But I don't have a strong opinion here.

Yes, it should be 5a8e9b022e569.

Frank
>
> Thanks and best regards,
> Alexander
>
> > Signed-off-by: Sherry Sun <sherry.sun at nxp.com>
> > ---
> >  arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi | 8 ++++----
> >  1 file changed, 4 insertions(+), 4 deletions(-)
> >
> > diff --git a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi
> > index 5f24850bf322..974e193f8dcb 100644
> > --- a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi
> > +++ b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi
> > @@ -172,25 +172,25 @@ &flexcan3 {
> >
> >  &lpuart0 {
> >  	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
> > -	dmas = <&edma2 13 0 0>, <&edma2 12 0 1>;
> > +	dmas = <&edma2 12 0 FSL_EDMA_RX>, <&edma2 13 0 0>;
> >  	dma-names = "rx","tx";
> >  };
> >
> >  &lpuart1 {
> >  	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
> > -	dmas = <&edma2 15 0 0>, <&edma2 14 0 1>;
> > +	dmas = <&edma2 14 0 FSL_EDMA_RX>, <&edma2 15 0 0>;
> >  	dma-names = "rx","tx";
> >  };
> >
> >  &lpuart2 {
> >  	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
> > -	dmas = <&edma2 17 0 0>, <&edma2 16 0 1>;
> > +	dmas = <&edma2 16 0 FSL_EDMA_RX>, <&edma2 17 0 0>;
> >  	dma-names = "rx","tx";
> >  };
> >
> >  &lpuart3 {
> >  	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
> > -	dmas = <&edma2 19 0 0>, <&edma2 18 0 1>;
> > +	dmas = <&edma2 18 0 FSL_EDMA_RX>, <&edma2 19 0 0>;
> >  	dma-names = "rx","tx";
> >  };
> >
> >
>
>
> --
> TQ-Systems GmbH | M?hlstra?e 2, Gut Delling | 82229 Seefeld, Germany
> Amtsgericht M?nchen, HRB 105018
> Gesch?ftsf?hrer: Detlef Schneider, R?diger Stahl, Stefan Schneider
> http://www.tq-group.com/
>
>


From sudeep.holla at arm.com  Tue Dec  2 06:52:39 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Tue, 2 Dec 2025 14:52:39 +0000
Subject: [PATCH 1/2] dt-bindings: firmware: arm,scmi: Document
 arm,poll-transport property
In-Reply-To: <aRW7BZimWdpq4TyX@pluto>
References: <20251023123644.8730-1-marek.vasut+renesas@mailbox.org>
 <aPoxfH_TLrsMxMVQ@pluto>
 <70554674-7020-4582-a4e7-dbee34907096@mailbox.org>
 <5ae0a793-d3e7-45d1-bf5c-3c46593d1824@mailbox.org>
 <aRW7BZimWdpq4TyX@pluto>
Message-ID: <20251202-evasive-neon-rhino-d2745e@sudeepholla>

On Thu, Nov 13, 2025 at 11:03:33AM +0000, Cristian Marussi wrote:
> On Thu, Oct 30, 2025 at 01:52:42AM +0100, Marek Vasut wrote:
> > On 10/23/25 4:00 PM, Marek Vasut wrote:
> > 
> > Hello again,
> > 
> 
> Hi,
> 
> bit of a late reply...
> 
> > > > On Thu, Oct 23, 2025 at 02:35:57PM +0200, Marek Vasut wrote:
> > > > > Document new property arm,poll-transport, which sets all SCMI
> > > > > operation into
> > > > > poll mode. This is meant to work around uncooperative SCP
> > > > > implementations,
> > > > > which do not generate completion interrupts. This applies
> > > > > primarily on mbox
> > > > > based implementations, but does also cover SMC and VirtIO ones.
> > > > 
> > > > Hi,
> > > > 
> > > > ..indeed I was thinking a while ago about exposing the existing
> > > > force- polling
> > > > switch but in my case it was purely a testing-scenario
> > > > configuration, so a
> > > > no-no for the DT, things are different if you have to describe an HW
> > > > that has
> > > > no completion IRQ also on the a2p channel...
> > > 
> > > Correct, at least until the SCP on this hardware is updated.
> > > 
> > > > ...having said that, though, usually polling-mode is reserved to a few
> > > > selected commands in a few chosen scenarios (as you may have seen),
> > > > 'carpet-polling' non-for-testing for all the commands on A2P seems a lot
> > > > inefficient and heavy...is it really a viable solution ? or these
> > > > systems use such a low rate of SCMI messages that polling after each and
> > > > every message is negligible ?
> > > > 
> > > > ..just to understand the context...
> > > 
> > > These systems are early in development and it is likely that the SCP
> > > will be updated to generate interrupts properly. Currently, this is not
> > > the case, hence the carpet-polling, until this is resolved.
> > 
> > While I was going through the SCMI spec, DEN0056F , page 209 , section "4.1
> > Shared memory based transport" , bullet ? Completion interrupts, I found it
> > explicitly states:
> > 
> > "
> > This transport supports polling or interrupt driven modes of communication.
> > In interrupt mode, when the callee completes processing a message, it raises
> > an interrupt to the caller. Hardware support for completion interrupts is
> > optional.
> > "
> 
> Oh, yes...I knew that...it is just that till now, no systems were really
> ever developed that lacked the completion IRQ as a whole, it was, till now,
> more of a case of having the capability NOT to use it selectively at runtime
> and instead use polling when wanted (like for clock ops in ISR context)
> 

Indeed.

> I am not sure what is the reason why this only-polling scenario was never
> supported in the HW description, this indeed pre-dates my work on SCMI....
> ...I would/will check with Sudeep, when he's back, what are the reasons for
> this (if any)...
> 

As you mentioned earlier, no platform has required this before. I?m fine with
adding it, but we need to be more explicit about what it implies for SCMI. The
transport may be shared with other system components, and enforcing polling
for SCMI while the same transport generates interrupts for another user could
lead to issues.

Clearly defining these constraints would be helpful. It may also be useful to
note that this is primarily intended for mailbox transports, if that?s
accurate. Alternatively, we could keep the DT binding definition broader but
emit warnings when a transport other than mailbox is used. That approach might
make it easier to move forward.

-- 
Regards,
Sudeep


From Frank.li at nxp.com  Tue Dec  2 06:52:32 2025
From: Frank.li at nxp.com (Frank Li)
Date: Tue, 2 Dec 2025 09:52:32 -0500
Subject: [PATCH v2 6/6] spi: imx: enable DMA mode for target operation
In-Reply-To: <20251202075503.2448339-7-carlos.song@nxp.com>
References: <20251202075503.2448339-1-carlos.song@nxp.com>
 <20251202075503.2448339-7-carlos.song@nxp.com>
Message-ID: <aS79MEp9LMohngIc@lizhi-Precision-Tower-5810>

On Tue, Dec 02, 2025 at 03:55:03PM +0800, Carlos Song wrote:
> Enable DMA mode for SPI IMX in target mode. Disable the word delay feature
> for target mode, because target mode should always keep high performance
> to make sure it can follow the master. Target mode continues to operate in
> dynamic burst mode.
>
> Signed-off-by: Carlos Song <carlos.song at nxp.com>
> ---

Reviewed-by: Frank Li <Frank.Li at nxp.com>

>  drivers/spi/spi-imx.c | 77 ++++++++++++++++++++++++++++++++-----------
>  1 file changed, 57 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
> index 045f4ffd680a..e37d786a5276 100644
> --- a/drivers/spi/spi-imx.c
> +++ b/drivers/spi/spi-imx.c
> @@ -264,7 +264,13 @@ static bool spi_imx_can_dma(struct spi_controller *controller, struct spi_device
>  	if (!controller->dma_rx)
>  		return false;
>
> -	if (spi_imx->target_mode)
> +	/*
> +	 * Due to Freescale errata ERR003775 "eCSPI: Burst completion by Chip
> +	 * Select (SS) signal in Slave mode is not functional" burst size must
> +	 * be set exactly to the size of the transfer. This limit SPI transaction
> +	 * with maximum 2^12 bits.
> +	 */
> +	if (transfer->len > MX53_MAX_TRANSFER_BYTES && spi_imx->target_mode)
>  		return false;
>
>  	if (transfer->len < spi_imx->devtype_data->fifo_size)
> @@ -1763,23 +1769,51 @@ static int spi_imx_dma_submit(struct spi_imx_data *spi_imx,
>
>  	transfer_timeout = spi_imx_calculate_timeout(spi_imx, transfer->len);
>
> -	/* Wait SDMA to finish the data transfer.*/
> -	time_left = wait_for_completion_timeout(&spi_imx->dma_tx_completion,
> -						transfer_timeout);
> -	if (!time_left) {
> -		dev_err(spi_imx->dev, "I/O Error in DMA TX\n");
> -		dmaengine_terminate_all(controller->dma_tx);
> -		dmaengine_terminate_all(controller->dma_rx);
> -		return -ETIMEDOUT;
> -	}
> +	if (!spi_imx->target_mode) {
> +		/* Wait SDMA to finish the data transfer.*/
> +		time_left = wait_for_completion_timeout(&spi_imx->dma_tx_completion,
> +							transfer_timeout);
> +		if (!time_left) {
> +			dev_err(spi_imx->dev, "I/O Error in DMA TX\n");
> +			dmaengine_terminate_all(controller->dma_tx);
> +			dmaengine_terminate_all(controller->dma_rx);
> +			return -ETIMEDOUT;
> +		}
>
> -	time_left = wait_for_completion_timeout(&spi_imx->dma_rx_completion,
> -						transfer_timeout);
> -	if (!time_left) {
> -		dev_err(&controller->dev, "I/O Error in DMA RX\n");
> -		spi_imx->devtype_data->reset(spi_imx);
> -		dmaengine_terminate_all(controller->dma_rx);
> -		return -ETIMEDOUT;
> +		time_left = wait_for_completion_timeout(&spi_imx->dma_rx_completion,
> +							transfer_timeout);
> +		if (!time_left) {
> +			dev_err(&controller->dev, "I/O Error in DMA RX\n");
> +			spi_imx->devtype_data->reset(spi_imx);
> +			dmaengine_terminate_all(controller->dma_rx);
> +			return -ETIMEDOUT;
> +		}
> +	} else {
> +		spi_imx->target_aborted = false;
> +
> +		if (wait_for_completion_interruptible(&spi_imx->dma_tx_completion) ||
> +		    READ_ONCE(spi_imx->target_aborted)) {
> +			dev_dbg(spi_imx->dev, "I/O Error in DMA TX interrupted\n");
> +			dmaengine_terminate_all(controller->dma_tx);
> +			dmaengine_terminate_all(controller->dma_rx);
> +			return -EINTR;
> +		}
> +
> +		if (wait_for_completion_interruptible(&spi_imx->dma_rx_completion) ||
> +		    READ_ONCE(spi_imx->target_aborted)) {
> +			dev_dbg(spi_imx->dev, "I/O Error in DMA RX interrupted\n");
> +			dmaengine_terminate_all(controller->dma_rx);
> +			return -EINTR;
> +		}
> +
> +		/*
> +		 * ECSPI has a HW issue when works in Target mode, after 64 words
> +		 * writtern to TXFIFO, even TXFIFO becomes empty, ECSPI_TXDATA keeps
> +		 * shift out the last word data, so we have to disable ECSPI when in
> +		 * target mode after the transfer completes.
> +		 */
> +		if (spi_imx->devtype_data->disable)
> +			spi_imx->devtype_data->disable(spi_imx);
>  	}
>
>  	return 0;
> @@ -1902,7 +1936,7 @@ static int spi_imx_dma_package_transfer(struct spi_imx_data *spi_imx,
>  static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
>  				struct spi_transfer *transfer)
>  {
> -	bool word_delay = transfer->word_delay.value != 0;
> +	bool word_delay = transfer->word_delay.value != 0 && !spi_imx->target_mode;
>  	int ret;
>  	int i;
>
> @@ -2108,7 +2142,7 @@ static int spi_imx_transfer_one(struct spi_controller *controller,
>  	while (spi_imx->devtype_data->rx_available(spi_imx))
>  		readl(spi_imx->base + MXC_CSPIRXDATA);
>
> -	if (spi_imx->target_mode)
> +	if (spi_imx->target_mode && !spi_imx->usedma)
>  		return spi_imx_pio_transfer_target(spi, transfer);
>
>  	/*
> @@ -2120,7 +2154,10 @@ static int spi_imx_transfer_one(struct spi_controller *controller,
>  		ret = spi_imx_dma_transfer(spi_imx, transfer);
>  		if (transfer->error & SPI_TRANS_FAIL_NO_START) {
>  			spi_imx->usedma = false;
> -			return spi_imx_pio_transfer(spi, transfer);
> +			if (spi_imx->target_mode)
> +				return spi_imx_pio_transfer_target(spi, transfer);
> +			else
> +				return spi_imx_pio_transfer(spi, transfer);
>  		}
>  		return ret;
>  	}
> --
> 2.34.1
>


From Frank.li at nxp.com  Tue Dec  2 06:53:44 2025
From: Frank.li at nxp.com (Frank Li)
Date: Tue, 2 Dec 2025 09:53:44 -0500
Subject: [PATCH v6 1/4] dt-bindings: backlight: Add max25014 support
In-Reply-To: <b9fe6df7-fdc6-4a32-919b-8f3b44eace7d@gocontroll.com>
References: <20251201-max25014-v6-0-88e3ac8112ff@gocontroll.com>
 <20251201-max25014-v6-1-88e3ac8112ff@gocontroll.com>
 <aS3H1qzSMKHamqpP@lizhi-Precision-Tower-5810>
 <b9fe6df7-fdc6-4a32-919b-8f3b44eace7d@gocontroll.com>
Message-ID: <aS79eKc9Ac4np6Nf@lizhi-Precision-Tower-5810>

On Tue, Dec 02, 2025 at 08:46:21AM +0100, Maud Spierings wrote:
> On 12/1/25 17:52, Frank Li wrote:
> > On Mon, Dec 01, 2025 at 12:53:20PM +0100, Maud Spierings via B4 Relay wrote:
> > > From: Maud Spierings <maudspierings at gocontroll.com>
> > >
> > > The Maxim MAX25014 is a 4-channel automotive grade backlight driver IC
> > > with integrated boost controller.
> > >
> > > Signed-off-by: Maud Spierings <maudspierings at gocontroll.com>
> > >
> > > ---
> > >
> > > In the current implementation the control registers for channel 1,
> > > control all channels. So only one led subnode with led-sources is
> > > supported right now. If at some point the driver functionality is
> > > expanded the bindings can be easily extended with it.
> > > ---
> > >   .../bindings/leds/backlight/maxim,max25014.yaml    | 107 +++++++++++++++++++++
> > >   MAINTAINERS                                        |   5 +
> > >   2 files changed, 112 insertions(+)
> > >
> > > diff --git a/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml b/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
> > > new file mode 100644
> > > index 000000000000..e83723224b07
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
> > > @@ -0,0 +1,107 @@
> > > +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> > > +%YAML 1.2
> > > +---
> > > +$id: http://devicetree.org/schemas/leds/backlight/maxim,max25014.yaml#
> > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > +
> > > +title: Maxim max25014 backlight controller
> > > +
> > > +maintainers:
> > > +  - Maud Spierings <maudspierings at gocontroll.com>
> > > +
> > > +properties:
> > > +  compatible:
> > > +    enum:
> > > +      - maxim,max25014
> > > +
> > > +  reg:
> > > +    maxItems: 1
> > > +
> > > +  "#address-cells":
> > > +    const: 1
> > > +
> > > +  "#size-cells":
> > > +    const: 0
> > > +
> > > +  enable-gpios:
> > > +    maxItems: 1
> > > +
> > > +  interrupts:
> > > +    maxItems: 1
> > > +
> > > +  power-supply:
> > > +    description: Regulator which controls the boost converter input rail.
> > > +
> > > +  pwms:
> > > +    maxItems: 1
> > > +
> > > +  maxim,iset:
> > > +    $ref: /schemas/types.yaml#/definitions/uint32
> > > +    maximum: 15
> > > +    default: 11
> > > +    description:
> > > +      Value of the ISET field in the ISET register. This controls the current
> > > +      scale of the outputs, a higher number means more current.
> > > +
> > > +  led at 0:
> >
> > define whole binding, allow 0-3. binding is not related with driver's
> > implement.
> >
> > it'd better put unders leds.
> >
>
> so like:
>
> backlight: backlight at 6f {
> 	compatible = "maxim,max25014";
> 	reg = <0x6f>;
> 	enable-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
> 	pinctrl-names = "default";
> 	pinctrl-0 = <&pinctrl_backlight>;
> 	maxim,iset = <7>;
>
> 	leds {
> 		#address-cells = <1>;
> 		#size-cells = <0>;
>
> 		led at 0 {
> 			reg = <0>;
> 			led-sources = <0 1 2>;
> 			default-brightness = <50>;
> 		};
>
> 		optional led@#....
> 	};
> };
>
> right?

yes.

>
> Kind regards,
> Maud
>
> >
> > > +    type: object
> > > +    description: Properties for a string of connected LEDs.
> > > +    $ref: common.yaml#
> > > +
> > > +    properties:
> > > +      reg:
> > > +        const: 0
> > > +
> > > +      led-sources:
> > > +        allOf:
> > > +          - minItems: 1
> > > +            maxItems: 4
> > > +            items:
> > > +              minimum: 0
> > > +              maximum: 3
> > > +            default: [0, 1, 2, 3]
> > > +
> > > +      default-brightness:
> > > +        minimum: 0
> > > +        maximum: 100
> > > +        default: 50
> > > +
> > > +    required:
> > > +      - reg
> > > +
> > > +    additionalProperties: false
> >
> > unevaluatedProperties: false because ref to common.yaml
> >
> > Frank
> >
>
>


From marco.crivellari at suse.com  Tue Dec  2 06:55:56 2025
From: marco.crivellari at suse.com (Marco Crivellari)
Date: Tue, 2 Dec 2025 15:55:56 +0100
Subject: [PATCH] soc/xilinx: replace use of system_unbound_wq with system_dfl_wq
In-Reply-To: <19d32db7-5ec3-41cc-b0b0-5e90a4447fb4@amd.com>
References: <20251104103942.96647-1-marco.crivellari@suse.com>
 <CAAofZF4-D3PT_eE8e4VRX7bCkUV0d9h99YypeYyPhCg+sCFBpw@mail.gmail.com> <19d32db7-5ec3-41cc-b0b0-5e90a4447fb4@amd.com>
Message-ID: <CAAofZF62oEd0sXN5HNmXYBtwkkad9ppWg9RbMnu3WM9EQ9Gc2A@mail.gmail.com>

On Tue, Dec 2, 2025 at 2:36?PM Michal Simek <michal.simek at amd.com> wrote:
>
> Hi,
>
> On 12/2/25 14:25, Marco Crivellari wrote:
> > Hi,
> >
> > On Tue, Nov 4, 2025 at 11:39?AM Marco Crivellari
> > <marco.crivellari at suse.com> wrote:
> >>   drivers/soc/xilinx/zynqmp_power.c | 6 +++---
> >
>
> I will queue it after rc1 tag.
>
> Thanks,
> Michal

Hi,

Sure, many thanks!
I've realized after I've sent the email that 6.18 was already out...

-- 

Marco Crivellari

L3 Support Engineer, Technology & Product


From Frank.li at nxp.com  Tue Dec  2 07:06:34 2025
From: Frank.li at nxp.com (Frank Li)
Date: Tue, 2 Dec 2025 10:06:34 -0500
Subject: [PATCH v2 5/6] spi: imx: support dynamic burst length for ECSPI
 DMA mode
In-Reply-To: <20251202075503.2448339-6-carlos.song@nxp.com>
References: <20251202075503.2448339-1-carlos.song@nxp.com>
 <20251202075503.2448339-6-carlos.song@nxp.com>
Message-ID: <aS8AeiGqs6yv5V0u@lizhi-Precision-Tower-5810>

On Tue, Dec 02, 2025 at 03:55:02PM +0800, Carlos Song wrote:
> ECSPI transfers only one word per frame in DMA mode, causing SCLK stalls
> between words due to BURST_LENGTH updates, which significantly impacts
> performance.
>
> To improve throughput, configure BURST_LENGTH as large as possible (up to
> 512 bytes per frame) instead of word length. This avoids delays between
> words. When transfer length is not 4-byte aligned, use bounce buffers to
> align data for DMA. TX uses aligned words for TXFIFO, while RX trims DMA
> buffer data after transfer completion.
>
> Introduce a new dma_package structure to store:
>   1. BURST_LENGTH values for each DMA request
>   2. Variables for DMA submission
>   3. DMA transmission length and actual data length
>
> Handle three cases:
>   - len <= 512 bytes: one package, BURST_LENGTH = len * 8 - 1
>   - len > 512 and aligned: one package, BURST_LENGTH = max (512 bytes)
>   - len > 512 and unaligned: two packages, second for tail data
>
> Performance test (spidev_test @10MHz, 4KB):
>   Before: tx/rx ~6651.9 kbps
>   After:  tx/rx ~9922.2 kbps (~50% improvement)
>
> For compatibility with slow SPI devices, add configurable word delay in
> DMA mode. When word delay is set, dynamic burst is disabled and
> BURST_LENGTH equals word length.
>
> Signed-off-by: Carlos Song <carlos.song at nxp.com>
> ---
Reviewed-by: Frank Li <Frank.Li at nxp.com>
>  drivers/spi/spi-imx.c | 413 ++++++++++++++++++++++++++++++++++++++----
>  1 file changed, 377 insertions(+), 36 deletions(-)
>
> diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
> index 42f64d9535c9..045f4ffd680a 100644
> --- a/drivers/spi/spi-imx.c
> +++ b/drivers/spi/spi-imx.c
> @@ -60,6 +60,7 @@ MODULE_PARM_DESC(polling_limit_us,
>  #define MX51_ECSPI_CTRL_MAX_BURST	512
>  /* The maximum bytes that IMX53_ECSPI can transfer in target mode.*/
>  #define MX53_MAX_TRANSFER_BYTES		512
> +#define BYTES_PER_32BITS_WORD		4
>
>  enum spi_imx_devtype {
>  	IMX1_CSPI,
> @@ -95,6 +96,16 @@ struct spi_imx_devtype_data {
>  	enum spi_imx_devtype devtype;
>  };
>
> +struct dma_data_package {
> +	u32 cmd_word;
> +	void *dma_rx_buf;
> +	void *dma_tx_buf;
> +	dma_addr_t dma_tx_addr;
> +	dma_addr_t dma_rx_addr;
> +	int dma_len;
> +	int data_len;
> +};
> +
>  struct spi_imx_data {
>  	struct spi_controller *controller;
>  	struct device *dev;
> @@ -130,6 +141,9 @@ struct spi_imx_data {
>  	u32 wml;
>  	struct completion dma_rx_completion;
>  	struct completion dma_tx_completion;
> +	size_t dma_package_num;
> +	struct dma_data_package *dma_data __counted_by(dma_package_num);
> +	int rx_offset;
>
>  	const struct spi_imx_devtype_data *devtype_data;
>  };
> @@ -189,6 +203,9 @@ MXC_SPI_BUF_TX(u16)
>  MXC_SPI_BUF_RX(u32)
>  MXC_SPI_BUF_TX(u32)
>
> +/* Align to cache line to avoid swiotlo bounce */
> +#define DMA_CACHE_ALIGNED_LEN(x) ALIGN((x), dma_get_cache_alignment())
> +
>  /* First entry is reserved, second entry is valid only if SDHC_SPIEN is set
>   * (which is currently not the case in this driver)
>   */
> @@ -253,6 +270,14 @@ static bool spi_imx_can_dma(struct spi_controller *controller, struct spi_device
>  	if (transfer->len < spi_imx->devtype_data->fifo_size)
>  		return false;
>
> +	/* DMA only can transmit data in bytes */
> +	if (spi_imx->bits_per_word != 8 && spi_imx->bits_per_word != 16 &&
> +	    spi_imx->bits_per_word != 32)
> +		return false;
> +
> +	if (transfer->len >= MAX_SDMA_BD_BYTES)
> +		return false;
> +
>  	spi_imx->dynamic_burst = 0;
>
>  	return true;
> @@ -1398,8 +1423,6 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
>
>  	init_completion(&spi_imx->dma_rx_completion);
>  	init_completion(&spi_imx->dma_tx_completion);
> -	controller->can_dma = spi_imx_can_dma;
> -	controller->max_dma_len = MAX_SDMA_BD_BYTES;
>  	spi_imx->controller->flags = SPI_CONTROLLER_MUST_RX |
>  					 SPI_CONTROLLER_MUST_TX;
>
> @@ -1437,10 +1460,259 @@ static int spi_imx_calculate_timeout(struct spi_imx_data *spi_imx, int size)
>  	return secs_to_jiffies(2 * timeout);
>  }
>
> +static void spi_imx_dma_unmap(struct spi_imx_data *spi_imx,
> +			      struct dma_data_package *dma_data)
> +{
> +	struct device *tx_dev = spi_imx->controller->dma_tx->device->dev;
> +	struct device *rx_dev = spi_imx->controller->dma_rx->device->dev;
> +
> +	dma_unmap_single(tx_dev, dma_data->dma_tx_addr,
> +			 DMA_CACHE_ALIGNED_LEN(dma_data->dma_len),
> +			 DMA_TO_DEVICE);
> +	dma_unmap_single(rx_dev, dma_data->dma_rx_addr,
> +			 DMA_CACHE_ALIGNED_LEN(dma_data->dma_len),
> +			 DMA_FROM_DEVICE);
> +}
> +
> +static void spi_imx_dma_rx_data_handle(struct spi_imx_data *spi_imx,
> +				       struct dma_data_package *dma_data, void *rx_buf,
> +				       bool word_delay)
> +{
> +	void *copy_ptr;
> +	int unaligned;
> +
> +	/*
> +	 * On little-endian CPUs, adjust byte order:
> +	 * - Swap bytes when bpw = 8
> +	 * - Swap half-words when bpw = 16
> +	 * This ensures correct data ordering for DMA transfers.
> +	 */
> +#ifdef __LITTLE_ENDIAN
> +	if (!word_delay) {
> +		unsigned int bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
> +		u32 *temp = dma_data->dma_rx_buf;
> +
> +		for (int i = 0; i < DIV_ROUND_UP(dma_data->dma_len, sizeof(*temp)); i++) {
> +			if (bytes_per_word == 1)
> +				swab32s(temp + i);
> +			else if (bytes_per_word == 2)
> +				swahw32s(temp + i);
> +		}
> +	}
> +#endif
> +
> +	/*
> +	 * When dynamic burst enabled, DMA RX always receives 32-bit words from RXFIFO with
> +	 * buswidth = 4, but when data_len is not 4-bytes alignment, the RM shows when
> +	 * burst length = 32*n + m bits, a SPI burst contains the m LSB in first word and all
> +	 * 32 bits in other n words. So if garbage bytes in the first word, trim first word then
> +	 * copy the actual data to rx_buf.
> +	 */
> +	if (dma_data->data_len % BYTES_PER_32BITS_WORD && !word_delay) {
> +		unaligned = dma_data->data_len % BYTES_PER_32BITS_WORD;
> +		copy_ptr = (u8 *)dma_data->dma_rx_buf + BYTES_PER_32BITS_WORD - unaligned;
> +	} else {
> +		copy_ptr = dma_data->dma_rx_buf;
> +	}
> +
> +	memcpy(rx_buf, copy_ptr, dma_data->data_len);
> +}
> +
> +static int spi_imx_dma_map(struct spi_imx_data *spi_imx,
> +			   struct dma_data_package *dma_data)
> +{
> +	struct spi_controller *controller = spi_imx->controller;
> +	struct device *tx_dev = controller->dma_tx->device->dev;
> +	struct device *rx_dev = controller->dma_rx->device->dev;
> +	int ret;
> +
> +	dma_data->dma_tx_addr = dma_map_single(tx_dev, dma_data->dma_tx_buf,
> +					       DMA_CACHE_ALIGNED_LEN(dma_data->dma_len),
> +					       DMA_TO_DEVICE);
> +	ret = dma_mapping_error(tx_dev, dma_data->dma_tx_addr);
> +	if (ret < 0) {
> +		dev_err(spi_imx->dev, "DMA TX map failed %d\n", ret);
> +		return ret;
> +	}
> +
> +	dma_data->dma_rx_addr = dma_map_single(rx_dev, dma_data->dma_rx_buf,
> +					       DMA_CACHE_ALIGNED_LEN(dma_data->dma_len),
> +					       DMA_FROM_DEVICE);
> +	ret = dma_mapping_error(rx_dev, dma_data->dma_rx_addr);
> +	if (ret < 0) {
> +		dev_err(spi_imx->dev, "DMA RX map failed %d\n", ret);
> +		dma_unmap_single(tx_dev, dma_data->dma_tx_addr,
> +				 DMA_CACHE_ALIGNED_LEN(dma_data->dma_len),
> +				 DMA_TO_DEVICE);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int spi_imx_dma_tx_data_handle(struct spi_imx_data *spi_imx,
> +				      struct dma_data_package *dma_data,
> +				      const void *tx_buf,
> +				      bool word_delay)
> +{
> +	void *copy_ptr;
> +	int unaligned;
> +
> +	if (word_delay) {
> +		dma_data->dma_len = dma_data->data_len;
> +	} else {
> +		/*
> +		 * As per the reference manual, when burst length = 32*n + m bits, ECSPI
> +		 * sends m LSB bits in the first word, followed by n full 32-bit words.
> +		 * Since actual data may not be 4-byte aligned, allocate DMA TX/RX buffers
> +		 * to ensure alignment. For TX, DMA pushes 4-byte aligned words to TXFIFO,
> +		 * while ECSPI uses BURST_LENGTH settings to maintain correct bit count.
> +		 * For RX, DMA always receives 32-bit words from RXFIFO, when data len is
> +		 * not 4-byte aligned, trim the first word to drop garbage bytes, then group
> +		 * all transfer DMA bounse buffer and copy all valid data to rx_buf.
> +		 */
> +		dma_data->dma_len = ALIGN(dma_data->data_len, BYTES_PER_32BITS_WORD);
> +	}
> +
> +	dma_data->dma_tx_buf = kzalloc(dma_data->dma_len, GFP_KERNEL);
> +	if (!dma_data->dma_tx_buf)
> +		return -ENOMEM;
> +
> +	dma_data->dma_rx_buf = kzalloc(dma_data->dma_len, GFP_KERNEL);
> +	if (!dma_data->dma_rx_buf) {
> +		kfree(dma_data->dma_tx_buf);
> +		return -ENOMEM;
> +	}
> +
> +	if (dma_data->data_len % BYTES_PER_32BITS_WORD && !word_delay) {
> +		unaligned = dma_data->data_len % BYTES_PER_32BITS_WORD;
> +		copy_ptr = (u8 *)dma_data->dma_tx_buf + BYTES_PER_32BITS_WORD - unaligned;
> +	} else {
> +		copy_ptr = dma_data->dma_tx_buf;
> +	}
> +
> +	memcpy(copy_ptr, tx_buf, dma_data->data_len);
> +
> +	/*
> +	 * When word_delay is enabled, DMA transfers an entire word in one minor loop.
> +	 * In this case, no data requires additional handling.
> +	 */
> +	if (word_delay)
> +		return 0;
> +
> +#ifdef __LITTLE_ENDIAN
> +	/*
> +	 * On little-endian CPUs, adjust byte order:
> +	 * - Swap bytes when bpw = 8
> +	 * - Swap half-words when bpw = 16
> +	 * This ensures correct data ordering for DMA transfers.
> +	 */
> +	unsigned int bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
> +	u32 *temp = dma_data->dma_tx_buf;
> +
> +	for (int i = 0; i < DIV_ROUND_UP(dma_data->dma_len, sizeof(*temp)); i++) {
> +		if (bytes_per_word == 1)
> +			swab32s(temp + i);
> +		else if (bytes_per_word == 2)
> +			swahw32s(temp + i);
> +	}
> +#endif
> +
> +	return 0;
> +}
> +
> +static int spi_imx_dma_data_prepare(struct spi_imx_data *spi_imx,
> +				    struct spi_transfer *transfer,
> +				    bool word_delay)
> +{
> +	u32 pre_bl, tail_bl;
> +	u32 ctrl;
> +	int ret;
> +
> +	/*
> +	 * ECSPI supports a maximum burst of 512 bytes. When xfer->len exceeds 512
> +	 * and is not a multiple of 512, a tail transfer is required. BURST_LEGTH
> +	 * is used for SPI HW to maintain correct bit count. BURST_LENGTH should
> +	 * update with data length. After DMA request submit, SPI can not update the
> +	 * BURST_LENGTH, in this case, we must split two package, update the register
> +	 * then setup second DMA transfer.
> +	 */
> +	ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL);
> +	if (word_delay) {
> +		/*
> +		 * When SPI IMX need to support word delay, according to "Sample Period Control
> +		 * Register" shows, The Sample Period Control Register (ECSPI_PERIODREG)
> +		 * provides software a way to insert delays (wait states) between consecutive
> +		 * SPI transfers. As a result, ECSPI can only transfer one word per frame, and
> +		 * the delay occurs between frames.
> +		 */
> +		spi_imx->dma_package_num = 1;
> +		pre_bl = spi_imx->bits_per_word - 1;
> +	} else if (transfer->len <= MX51_ECSPI_CTRL_MAX_BURST) {
> +		spi_imx->dma_package_num = 1;
> +		pre_bl = transfer->len * BITS_PER_BYTE - 1;
> +	} else if (!(transfer->len % MX51_ECSPI_CTRL_MAX_BURST)) {
> +		spi_imx->dma_package_num = 1;
> +		pre_bl = MX51_ECSPI_CTRL_MAX_BURST * BITS_PER_BYTE - 1;
> +	} else {
> +		spi_imx->dma_package_num = 2;
> +		pre_bl = MX51_ECSPI_CTRL_MAX_BURST * BITS_PER_BYTE - 1;
> +		tail_bl = (transfer->len % MX51_ECSPI_CTRL_MAX_BURST) * BITS_PER_BYTE - 1;
> +	}
> +
> +	spi_imx->dma_data = kmalloc_array(spi_imx->dma_package_num,
> +					  sizeof(struct dma_data_package),
> +					  GFP_KERNEL | __GFP_ZERO);
> +	if (!spi_imx->dma_data) {
> +		dev_err(spi_imx->dev, "Failed to allocate DMA package buffer!\n");
> +		return -ENOMEM;
> +	}
> +
> +	if (spi_imx->dma_package_num == 1) {
> +		ctrl &= ~MX51_ECSPI_CTRL_BL_MASK;
> +		ctrl |= pre_bl << MX51_ECSPI_CTRL_BL_OFFSET;
> +		spi_imx->dma_data[0].cmd_word = ctrl;
> +		spi_imx->dma_data[0].data_len = transfer->len;
> +		ret = spi_imx_dma_tx_data_handle(spi_imx, &spi_imx->dma_data[0], transfer->tx_buf,
> +						 word_delay);
> +		if (ret) {
> +			kfree(spi_imx->dma_data);
> +			return ret;
> +		}
> +	} else {
> +		ctrl &= ~MX51_ECSPI_CTRL_BL_MASK;
> +		ctrl |= pre_bl << MX51_ECSPI_CTRL_BL_OFFSET;
> +		spi_imx->dma_data[0].cmd_word = ctrl;
> +		spi_imx->dma_data[0].data_len = round_down(transfer->len,
> +							   MX51_ECSPI_CTRL_MAX_BURST);
> +		ret = spi_imx_dma_tx_data_handle(spi_imx, &spi_imx->dma_data[0], transfer->tx_buf,
> +						 false);
> +		if (ret) {
> +			kfree(spi_imx->dma_data);
> +			return ret;
> +		}
> +
> +		ctrl &= ~MX51_ECSPI_CTRL_BL_MASK;
> +		ctrl |= tail_bl << MX51_ECSPI_CTRL_BL_OFFSET;
> +		spi_imx->dma_data[1].cmd_word = ctrl;
> +		spi_imx->dma_data[1].data_len = transfer->len % MX51_ECSPI_CTRL_MAX_BURST;
> +		ret = spi_imx_dma_tx_data_handle(spi_imx, &spi_imx->dma_data[1],
> +						 transfer->tx_buf + spi_imx->dma_data[0].data_len,
> +						 false);
> +		if (ret) {
> +			kfree(spi_imx->dma_data[0].dma_tx_buf);
> +			kfree(spi_imx->dma_data[0].dma_rx_buf);
> +			kfree(spi_imx->dma_data);
> +		}
> +	}
> +
> +	return 0;
> +}
> +
>  static int spi_imx_dma_submit(struct spi_imx_data *spi_imx,
> +			      struct dma_data_package *dma_data,
>  			      struct spi_transfer *transfer)
>  {
> -	struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg;
>  	struct spi_controller *controller = spi_imx->controller;
>  	struct dma_async_tx_descriptor *desc_tx, *desc_rx;
>  	unsigned long transfer_timeout;
> @@ -1451,9 +1723,9 @@ static int spi_imx_dma_submit(struct spi_imx_data *spi_imx,
>  	 * The TX DMA setup starts the transfer, so make sure RX is configured
>  	 * before TX.
>  	 */
> -	desc_rx = dmaengine_prep_slave_sg(controller->dma_rx,
> -					  rx->sgl, rx->nents, DMA_DEV_TO_MEM,
> -					  DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
> +	desc_rx = dmaengine_prep_slave_single(controller->dma_rx, dma_data->dma_rx_addr,
> +					      dma_data->dma_len, DMA_DEV_TO_MEM,
> +					      DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
>  	if (!desc_rx) {
>  		transfer->error |= SPI_TRANS_FAIL_NO_START;
>  		return -EINVAL;
> @@ -1471,9 +1743,9 @@ static int spi_imx_dma_submit(struct spi_imx_data *spi_imx,
>  	reinit_completion(&spi_imx->dma_rx_completion);
>  	dma_async_issue_pending(controller->dma_rx);
>
> -	desc_tx = dmaengine_prep_slave_sg(controller->dma_tx,
> -					  tx->sgl, tx->nents, DMA_MEM_TO_DEV,
> -					  DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
> +	desc_tx = dmaengine_prep_slave_single(controller->dma_tx, dma_data->dma_tx_addr,
> +					      dma_data->dma_len, DMA_MEM_TO_DEV,
> +					      DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
>  	if (!desc_tx)
>  		goto dmaengine_terminate_rx;
>
> @@ -1521,16 +1793,16 @@ static int spi_imx_dma_submit(struct spi_imx_data *spi_imx,
>  }
>
>  static void spi_imx_dma_max_wml_find(struct spi_imx_data *spi_imx,
> -				     struct spi_transfer *transfer)
> +				     struct dma_data_package *dma_data,
> +				     bool word_delay)
>  {
> -	struct sg_table *rx = &transfer->rx_sg;
> -	struct scatterlist *last_sg = sg_last(rx->sgl, rx->nents);
> -	unsigned int bytes_per_word, i;
> +	unsigned int bytes_per_word = word_delay ?
> +				      spi_imx_bytes_per_word(spi_imx->bits_per_word) :
> +				      BYTES_PER_32BITS_WORD;
> +	unsigned int i;
>
> -	/* Get the right burst length from the last sg to ensure no tail data */
> -	bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word);
>  	for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) {
> -		if (!(sg_dma_len(last_sg) % (i * bytes_per_word)))
> +		if (!dma_data->dma_len % (i * bytes_per_word))
>  			break;
>  	}
>  	/* Use 1 as wml in case no available burst length got */
> @@ -1540,25 +1812,29 @@ static void spi_imx_dma_max_wml_find(struct spi_imx_data *spi_imx,
>  	spi_imx->wml = i;
>  }
>
> -static int spi_imx_dma_configure(struct spi_controller *controller)
> +static int spi_imx_dma_configure(struct spi_controller *controller, bool word_delay)
>  {
>  	int ret;
>  	enum dma_slave_buswidth buswidth;
>  	struct dma_slave_config rx = {}, tx = {};
>  	struct spi_imx_data *spi_imx = spi_controller_get_devdata(controller);
>
> -	switch (spi_imx_bytes_per_word(spi_imx->bits_per_word)) {
> -	case 4:
> +	if (word_delay) {
> +		switch (spi_imx_bytes_per_word(spi_imx->bits_per_word)) {
> +		case 4:
> +			buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
> +			break;
> +		case 2:
> +			buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
> +			break;
> +		case 1:
> +			buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
> +			break;
> +		default:
> +			return -EINVAL;
> +		}
> +	} else {
>  		buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
> -		break;
> -	case 2:
> -		buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
> -		break;
> -	case 1:
> -		buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
> -		break;
> -	default:
> -		return -EINVAL;
>  	}
>
>  	tx.direction = DMA_MEM_TO_DEV;
> @@ -1584,15 +1860,17 @@ static int spi_imx_dma_configure(struct spi_controller *controller)
>  	return 0;
>  }
>
> -static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
> -				struct spi_transfer *transfer)
> +static int spi_imx_dma_package_transfer(struct spi_imx_data *spi_imx,
> +					struct dma_data_package *dma_data,
> +					struct spi_transfer *transfer,
> +					bool word_delay)
>  {
>  	struct spi_controller *controller = spi_imx->controller;
>  	int ret;
>
> -	spi_imx_dma_max_wml_find(spi_imx, transfer);
> +	spi_imx_dma_max_wml_find(spi_imx, dma_data, word_delay);
>
> -	ret = spi_imx_dma_configure(controller);
> +	ret = spi_imx_dma_configure(controller, word_delay);
>  	if (ret)
>  		goto dma_failure_no_start;
>
> @@ -1603,10 +1881,17 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
>  	}
>  	spi_imx->devtype_data->setup_wml(spi_imx);
>
> -	ret = spi_imx_dma_submit(spi_imx, transfer);
> +	ret = spi_imx_dma_submit(spi_imx, dma_data, transfer);
>  	if (ret)
>  		return ret;
>
> +	/* Trim the DMA RX buffer and copy the actual data to rx_buf */
> +	dma_sync_single_for_cpu(controller->dma_rx->device->dev, dma_data->dma_rx_addr,
> +				dma_data->dma_len, DMA_FROM_DEVICE);
> +	spi_imx_dma_rx_data_handle(spi_imx, dma_data, transfer->rx_buf + spi_imx->rx_offset,
> +				   word_delay);
> +	spi_imx->rx_offset += dma_data->data_len;
> +
>  	return 0;
>  /* fallback to pio */
>  dma_failure_no_start:
> @@ -1614,6 +1899,57 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
>  	return ret;
>  }
>
> +static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
> +				struct spi_transfer *transfer)
> +{
> +	bool word_delay = transfer->word_delay.value != 0;
> +	int ret;
> +	int i;
> +
> +	ret = spi_imx_dma_data_prepare(spi_imx, transfer, word_delay);
> +	if (ret < 0) {
> +		transfer->error |= SPI_TRANS_FAIL_NO_START;
> +		dev_err(spi_imx->dev, "DMA data prepare fail\n");
> +		goto fallback_pio;
> +	}
> +
> +	spi_imx->rx_offset = 0;
> +
> +	/* Each dma_package performs a separate DMA transfer once */
> +	for (i = 0; i < spi_imx->dma_package_num; i++) {
> +		ret = spi_imx_dma_map(spi_imx, &spi_imx->dma_data[i]);
> +		if (ret < 0) {
> +			if (i == 0)
> +				transfer->error |= SPI_TRANS_FAIL_NO_START;
> +			dev_err(spi_imx->dev, "DMA map fail\n");
> +			break;
> +		}
> +
> +		/* Update the CTRL register BL field */
> +		writel(spi_imx->dma_data[i].cmd_word, spi_imx->base + MX51_ECSPI_CTRL);
> +
> +		ret = spi_imx_dma_package_transfer(spi_imx, &spi_imx->dma_data[i],
> +						   transfer, word_delay);
> +
> +		/* Whether the dma transmission is successful or not, dma unmap is necessary */
> +		spi_imx_dma_unmap(spi_imx, &spi_imx->dma_data[i]);
> +
> +		if (ret < 0) {
> +			dev_dbg(spi_imx->dev, "DMA %d transfer not really finish\n", i);
> +			break;
> +		}
> +	}
> +
> +	for (int j = 0; j < spi_imx->dma_package_num; j++) {
> +		kfree(spi_imx->dma_data[j].dma_tx_buf);
> +		kfree(spi_imx->dma_data[j].dma_rx_buf);
> +	}
> +	kfree(spi_imx->dma_data);
> +
> +fallback_pio:
> +	return ret;
> +}
> +
>  static int spi_imx_pio_transfer(struct spi_device *spi,
>  				struct spi_transfer *transfer)
>  {
> @@ -1780,9 +2116,14 @@ static int spi_imx_transfer_one(struct spi_controller *controller,
>  	 * transfer, the SPI transfer has already been mapped, so we
>  	 * have to do the DMA transfer here.
>  	 */
> -	if (spi_imx->usedma)
> -		return spi_imx_dma_transfer(spi_imx, transfer);
> -
> +	if (spi_imx->usedma) {
> +		ret = spi_imx_dma_transfer(spi_imx, transfer);
> +		if (transfer->error & SPI_TRANS_FAIL_NO_START) {
> +			spi_imx->usedma = false;
> +			return spi_imx_pio_transfer(spi, transfer);
> +		}
> +		return ret;
> +	}
>  	/* run in polling mode for short transfers */
>  	if (transfer->len == 1 || (polling_limit_us &&
>  				   spi_imx_transfer_estimate_time_us(transfer) < polling_limit_us))
> --
> 2.34.1
>


From Frank.li at nxp.com  Tue Dec  2 07:08:04 2025
From: Frank.li at nxp.com (Frank Li)
Date: Tue, 2 Dec 2025 10:08:04 -0500
Subject: [PATCH v2] arm64: dts: imx93-9x9-qsb: add CAN support overlay
 file
In-Reply-To: <20251202-b4-9391-can-dts-v2-1-edab562615a7@nxp.com>
References: <20251202-b4-9391-can-dts-v2-1-edab562615a7@nxp.com>
Message-ID: <aS8A1B6/XTgYb+aO@lizhi-Precision-Tower-5810>

On Tue, Dec 02, 2025 at 02:04:33PM +0800, Haibo Chen wrote:
> CAN1 and Micfil share pins on imx93-9x9-qsb board, use TMUX1574RSVR
> to control the connection: put sel to high, select CAN1, put sel to
> low, select Micfil. In default, sel keep low.
>
> To support CAN1, need to put the sel to high. Besides, CAN1 use phy
> TJA1057GT/3.
>
> ---
> Signed-off-by: Haibo Chen <haibo.chen at nxp.com>
> ---

Reviewed-by: Frank Li <Frank.Li at nxp.com>

> Changes in v2:
> - change commit title
> - Keep order by alphabet in Makefile
> - Link to v1: https://lore.kernel.org/r/20251126-b4-9391-can-dts-v1-1-c23145f0d2db at nxp.com
> ---
>  arch/arm64/boot/dts/freescale/Makefile             |  2 +
>  .../boot/dts/freescale/imx93-9x9-qsb-can1.dtso     | 63 ++++++++++++++++++++++
>  2 files changed, 65 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
> index f30d3fd724d0ce6b38f7bef10e3970ac34f70f4a..e15a7b216c5c6753c39ab02801d82f23255b8e63 100644
> --- a/arch/arm64/boot/dts/freescale/Makefile
> +++ b/arch/arm64/boot/dts/freescale/Makefile
> @@ -372,7 +372,9 @@ dtb-$(CONFIG_ARCH_MXC) += imx91-phyboard-segin.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx91-tqma9131-mba91xxca.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx93-9x9-qsb.dtb
>
> +imx93-9x9-qsb-can1-dtbs += imx93-9x9-qsb.dtb imx93-9x9-qsb-can1.dtbo
>  imx93-9x9-qsb-i3c-dtbs += imx93-9x9-qsb.dtb imx93-9x9-qsb-i3c.dtbo
> +dtb-$(CONFIG_ARCH_MXC) += imx93-9x9-qsb-can1.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx93-9x9-qsb-i3c.dtb
>
>  dtb-$(CONFIG_ARCH_MXC) += imx93-11x11-evk.dtb
> diff --git a/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-can1.dtso b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-can1.dtso
> new file mode 100644
> index 0000000000000000000000000000000000000000..0bf1e9d4bad2ec540d71470fcebc64a82072b41d
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-can1.dtso
> @@ -0,0 +1,63 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright 2025 NXP
> + */
> +
> +#include <dt-bindings/gpio/gpio.h>
> +#include "imx93-pinfunc.h"
> +
> +/dts-v1/;
> +/plugin/;
> +
> +&{/} {
> +	flexcan_phy: can-phy {
> +		compatible = "nxp,tja1057";
> +		#phy-cells = <0>;
> +		max-bitrate = <5000000>;
> +		silent-gpios = <&pcal6524 23 GPIO_ACTIVE_HIGH>;
> +	};
> +};
> +
> +&flexcan1 {
> +	phys = <&flexcan_phy>;
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_flexcan1>;
> +	status = "okay";
> +};
> +
> +&iomuxc {
> +	pinctrl_flexcan1: flexcan1grp {
> +		fsl,pins = <
> +			MX93_PAD_PDM_CLK__CAN1_TX		0x139e
> +			MX93_PAD_PDM_BIT_STREAM0__CAN1_RX	0x139e
> +		>;
> +	};
> +};
> +
> +/* micfi1 use the A port, conflict with can1 */
> +&micfil {
> +	status = "disabled";
> +};
> +
> +&pcal6524 {
> +	/*
> +	 * mic-can-sel-hog have property 'output-low', dt overlay don't
> +	 * support /delete-property/. Both 'output-low' and 'output-high'
> +	 * will be exist under hog nodes if overlay file set 'output-high'.
> +	 * Workaround is disable this hog and create new hog with
> +	 * 'output-high'.
> +	 */
> +	mic-can-sel-hog {
> +		status = "disabled";
> +	};
> +
> +	/*
> +	 * Config the MIC/CAN_SEL to high, chose B
> +	 * port, connect to CAN.
> +	 */
> +	mic-can-high-sel-hog {
> +		gpio-hog;
> +		gpios = <0x11 0x00>;
> +		output-high;
> +	};
> +};
>
> ---
> base-commit: 422f3140bbcb657e1b86c484296972ab76f6d1ff
> change-id: 20251125-b4-9391-can-dts-2f4849978fc2
>
> Best regards,
> --
> Haibo Chen <haibo.chen at nxp.com>
>


From beata.michalska at arm.com  Tue Dec  2 07:31:48 2025
From: beata.michalska at arm.com (Beata Michalska)
Date: Tue, 2 Dec 2025 16:31:48 +0100
Subject: [PATCH v6 0/3] arm64: topology: Handle AMU FIE setup on CPU
 hotplug
In-Reply-To: <9b6882dc-a91a-42d6-bf76-347338930d71@huawei.com>
References: <20251119081356.2495290-1-zhenglifeng1@huawei.com>
 <aS2z0EURwHbbGZab@arm.com>
 <9b6882dc-a91a-42d6-bf76-347338930d71@huawei.com>
Message-ID: <aS8GZOuaS1-j14MD@arm.com>

On Tue, Dec 02, 2025 at 11:05:25AM +0800, zhenglifeng (A) wrote:
> On 2025/12/1 23:27, Beata Michalska wrote:
> > Hi,
> > 
> > Apologies for the delay in reviewing this - currently in progress....
> > Out of curiosity: what's the cpufreq driver used for testing this series ?
> 
> I used cppc_cpufreq for testing this. But with some modifications in
> processor_driver.c, or you'll find that the driver will fail to load with
> maxcpus set. The modification below is only a temporary solution. I'm still
> working on that.
>
Right, so overall the implementation looks good - thanks for that.
There are two issues though with the cppc cpufreq driver.

One: as you have already noticed - it fails to register when
cpumask_present != cpumask_online.

Second: it will mix the sources of the freq scale if not all CPUs within the
policy have AMUs enabled/valid. This is due to the fact that at the time of
registering the driver and initializing the FIE support policy->cpus ==
policy->related_cpus. Assuming scenario when there are two CPUs within the
policy, one being offline and missing valid AMU counters,
the topology_set_scale_freq_source from cppc cpufreq driver will register
the tick handler for both CPUs, whereas AMU support will (rightly so) register
only for the firs one. When the second CPU comes online, the mismatch will be
detected and the arch callback will get cleared for the first CPU, but the
second one will remain unchanged.

That said, I do not think any of those issues is a blocker for this series.
But both would need fixing.

---
BR
Beata


> ---
> diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
> index 5d824435b26b..2f286a1b0b02 100644
> --- a/drivers/acpi/processor_driver.c
> +++ b/drivers/acpi/processor_driver.c
> @@ -33,6 +33,7 @@ MODULE_AUTHOR("Paul Diefenbaugh");
>  MODULE_DESCRIPTION("ACPI Processor Driver");
>  MODULE_LICENSE("GPL");
>  
> +static int acpi_processor_start(struct device *dev);
>  static int acpi_processor_stop(struct device *dev);
>  
>  static const struct acpi_device_id processor_device_ids[] = {
> @@ -46,6 +47,7 @@ static struct device_driver acpi_processor_driver = {
>  	.name = "processor",
>  	.bus = &cpu_subsys,
>  	.acpi_match_table = processor_device_ids,
> +	.probe = acpi_processor_start,
>  	.remove = acpi_processor_stop,
>  };
>  
> @@ -191,6 +193,21 @@ static int __acpi_processor_start(struct acpi_device *device)
>  	return result;
>  }
>  
> +static int acpi_processor_start(struct device *dev)
> +{
> +	struct acpi_device *device = ACPI_COMPANION(dev);
> +	int ret;
> +
> +	if (!device)
> +		return -ENODEV;
> +
> +	/* Protect against concurrent CPU hotplug operations */
> +	cpu_hotplug_disable();
> +	ret = __acpi_processor_start(device);
> +	cpu_hotplug_enable();
> +	return ret;
> +}
> +
>  static int acpi_processor_stop(struct device *dev)
>  {
>  	struct acpi_device *device = ACPI_COMPANION(dev);
> @@ -264,9 +281,9 @@ static int __init acpi_processor_driver_init(void)
>  
>  	acpi_processor_register_idle_driver();
>  
> -	result = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
> -				   "acpi/cpu-drv:online",
> -				   acpi_soft_cpu_online, NULL);
> +	result = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
> +					   "acpi/cpu-drv:online",
> +					   acpi_soft_cpu_online, NULL);
>  	if (result < 0)
>  		goto err;
>  	hp_online = result;
> 
> > 
> > ---
> > BR
> > Beata
> > On Wed, Nov 19, 2025 at 04:13:53PM +0800, Lifeng Zheng wrote:
> >> Solve a problem that causes CPUs Setup AMU FIE failed in a corner case,
> >> even though they're eligible.
> >>
> >>
> > 
> 


From konrad.dybcio at oss.qualcomm.com  Tue Dec  2 07:37:08 2025
From: konrad.dybcio at oss.qualcomm.com (Konrad Dybcio)
Date: Tue, 2 Dec 2025 16:37:08 +0100
Subject: [PATCH 1/3] clk: qcom: clk-alpha-pll: Add support for Rivian ELU
 PLL
In-Reply-To: <20251202-sm8750_camcc-v1-1-b3f7ef6723f1@oss.qualcomm.com>
References: <20251202-sm8750_camcc-v1-0-b3f7ef6723f1@oss.qualcomm.com>
 <20251202-sm8750_camcc-v1-1-b3f7ef6723f1@oss.qualcomm.com>
Message-ID: <f7609d19-5254-4419-a600-d0904d92d525@oss.qualcomm.com>

On 12/2/25 11:26 AM, Taniya Das wrote:
> Add clock ops for Rivian ELU PLL, add the register offsets for supporting
> the PLL.
> 
> Signed-off-by: Taniya Das <taniya.das at oss.qualcomm.com>
> ---

Matches downstream

Reviewed-by: Konrad Dybcio <konrad.dybcio at oss.qualcomm.com>

Konrad


From linux at armlinux.org.uk  Tue Dec  2 07:46:25 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Tue, 2 Dec 2025 15:46:25 +0000
Subject: [PATCH v3 2/5] ARM: mm: fault: Enable interrupts before invoking
 __do_user_fault()
In-Reply-To: <20251202141816.wfHNUMFK@linutronix.de>
References: <20251110145555.2555055-1-bigeasy@linutronix.de>
 <20251110145555.2555055-3-bigeasy@linutronix.de>
 <20251202141816.wfHNUMFK@linutronix.de>
Message-ID: <aS8J0WrmmH01L3K1@shell.armlinux.org.uk>

On Tue, Dec 02, 2025 at 03:18:16PM +0100, Sebastian Andrzej Siewior wrote:
> On 2025-11-10 15:55:52 [+0100], To linux-arm-kernel at lists.infradead.org wrote:
> |
> |   https://www.armlinux.org.uk/developer/patches/viewpatch.php?id=9460/1
> |
> | Moved to Discarded.
> |
> | This makes the issues with the branch predictor hardening worse if this
> | patch is merged on its own - since this adds another path where
> | interrupts are enabled before calling harden_branch_predictor() in
> | __do_user_fault(). It would be sensible to move the interrupt enable
> | into __do_user_fault().
> |
> |    *** PLEASE DO NOT REPLY TO THIS MESSAGE ***
> 
> I thought that we apply both.
> In 9462/1 I am moving harden_branch_predictor() out of __do_user_fault()
> because do_page_fault() needs the hardening before the interrupts are
> enabled. Do mean something like

If I apply 9460/1 without 9462/1 first, then it makes the problems
with the branch predictor hardening worse. I'm not prepared to do that.

However, 9462/1 is tied up in the discussions that are ongoing, and I'm
not going to short-circuit the still-ongoing discussions that touch
this area by applying this patch - which would screw up everyone's
proposals to fix the various many problems that are being discovered in
the 32-bit ARM fault handling.

This means I can't apply 9462/1 nor 9460/1.

Since 9463/1 likely requires these, I can't apply that one either.

Sorry.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From maxime.chevallier at bootlin.com  Tue Dec  2 07:48:39 2025
From: maxime.chevallier at bootlin.com (Maxime Chevallier)
Date: Tue, 2 Dec 2025 16:48:39 +0100
Subject: [PATCH net-next v21 02/14] net: ethtool: Introduce
 ETHTOOL_LINK_MEDIUM_* values
In-Reply-To: <298e982d-7796-4e46-ad1d-a7f57c573f35@redhat.com>
References: <20251129082228.454678-1-maxime.chevallier@bootlin.com>
 <20251129082228.454678-3-maxime.chevallier@bootlin.com>
 <298e982d-7796-4e46-ad1d-a7f57c573f35@redhat.com>
Message-ID: <49709595-5012-4fa3-9616-839dcdbf6b09@bootlin.com>

Hi Paolo

On 02/12/2025 14:03, Paolo Abeni wrote:
> On 11/29/25 9:22 AM, Maxime Chevallier wrote:
>> @@ -298,138 +321,149 @@ static_assert(ARRAY_SIZE(link_mode_names) == __ETHTOOL_LINK_MODE_MASK_NBITS);
>>  		.speed	= SPEED_UNKNOWN, \
>>  		.lanes	= 0, \
>>  		.duplex	= DUPLEX_UNKNOWN, \
>> +		.mediums = BIT(ETHTOOL_LINK_MEDIUM_NONE), \
>>  	}
>>  
>>  const struct link_mode_info link_mode_params[] = {
>> -	__DEFINE_LINK_MODE_PARAMS(10, T, Half),
>> -	__DEFINE_LINK_MODE_PARAMS(10, T, Full),
>> -	__DEFINE_LINK_MODE_PARAMS(100, T, Half),
>> -	__DEFINE_LINK_MODE_PARAMS(100, T, Full),
>> -	__DEFINE_LINK_MODE_PARAMS(1000, T, Half),
>> -	__DEFINE_LINK_MODE_PARAMS(1000, T, Full),
>> +	__DEFINE_LINK_MODE_PARAMS_PAIRS(10, T, 2, 4, Half, T),
>> +	__DEFINE_LINK_MODE_PARAMS_PAIRS(10, T, 2, 4, Full, T),
>> +	__DEFINE_LINK_MODE_PARAMS_PAIRS(100, T, 2, 4, Half, T),
>> +	__DEFINE_LINK_MODE_PARAMS_PAIRS(100, T, 2, 4, Full, T),
>> +	__DEFINE_LINK_MODE_PARAMS_PAIRS(1000, T, 4, 4, Half, T),
>> +	__DEFINE_LINK_MODE_PARAMS_PAIRS(1000, T, 4, 4, Full, T),
>>  	__DEFINE_SPECIAL_MODE_PARAMS(Autoneg),
>>  	__DEFINE_SPECIAL_MODE_PARAMS(TP),
>>  	__DEFINE_SPECIAL_MODE_PARAMS(AUI),
>>  	__DEFINE_SPECIAL_MODE_PARAMS(MII),
>>  	__DEFINE_SPECIAL_MODE_PARAMS(FIBRE),
>>  	__DEFINE_SPECIAL_MODE_PARAMS(BNC),
>> -	__DEFINE_LINK_MODE_PARAMS(10000, T, Full),
>> +	__DEFINE_LINK_MODE_PARAMS_PAIRS(10000, T, 4, 4, Full, T),
>>  	__DEFINE_SPECIAL_MODE_PARAMS(Pause),
>>  	__DEFINE_SPECIAL_MODE_PARAMS(Asym_Pause),
>> -	__DEFINE_LINK_MODE_PARAMS(2500, X, Full),
>> +	__DEFINE_LINK_MODE_PARAMS_MEDIUMS(2500, X, Full,
>> +					  __MED(C) | __MED(S) | __MED(L)),
>>  	__DEFINE_SPECIAL_MODE_PARAMS(Backplane),
>> -	__DEFINE_LINK_MODE_PARAMS(1000, KX, Full),
>> -	__DEFINE_LINK_MODE_PARAMS(10000, KX4, Full),
>> -	__DEFINE_LINK_MODE_PARAMS(10000, KR, Full),
>> +	__DEFINE_LINK_MODE_PARAMS(1000, KX, Full, K),
>> +	__DEFINE_LINK_MODE_PARAMS(10000, KX4, Full, K),
>> +	__DEFINE_LINK_MODE_PARAMS(10000, KR, Full, K),
>>  	[ETHTOOL_LINK_MODE_10000baseR_FEC_BIT] = {
>>  		.speed	= SPEED_10000,
>>  		.lanes	= 1,
>>  		.duplex = DUPLEX_FULL,
> 
> The AI review points that medium is not initialized here:
> 
> https://netdev-ai.bots.linux.dev/ai-review.html?id=437cd013-c6a6-49e1-bec1-de4869930c7a#patch-1
> 
> Is that intentional? It should deserve at least an explanation in the
> commit message.

Yes it is OK, however I don't really know how to answer AI on that. I'm
sorry it's still a bit blurry to me what's the right way to proceed with
these reviews.

Should I paste the AI report, then reply to it ?

I'd rather add more comments to the code than say in my commit log "AI
says xxx, it's wrong because blabla" though.

> 
> Somewhat related, AI raised on the first patch the same question raised
> on a previous iteration, and I assumed you considered that valid,
> according to:
> 
> https://lore.kernel.org/netdev/f753719e-2370-401d-a001-821bdd5ee838 at bootlin.com/

So I don't know either how to proceed with this. dt_binding_check is
fine with the current state, and Rob acked the patch. I am not sure how
it's going to be received if I reach out to DT maintainers saying "the
netdev LLM said XXX, is this correct or hallucination ?", but it may
very well have a good point. I did try to dive into the yaml and then
json schema specs, but I wasn't able to go far enough to reach a proper
conclusion on wether we must remove "contains" for scalar :(

All of that would be a bit clearer if the AI review was on the ML, but I
also understand the risk for pollution with that, especially at an early
stage of adoption.

> 
> Otherwise I think some wording in the commit message explaining why the
> AI feedback is incorrect would be useful.
> 
> /P
> 

I'll update the commits and add comments anyways. I guess in a month
though, with net-next closed then the end of year.

Thanks,

Maxime


From bigeasy at linutronix.de  Tue Dec  2 08:05:10 2025
From: bigeasy at linutronix.de (Sebastian Andrzej Siewior)
Date: Tue, 2 Dec 2025 17:05:10 +0100
Subject: [PATCH v3 2/5] ARM: mm: fault: Enable interrupts before invoking
 __do_user_fault()
In-Reply-To: <aS8J0WrmmH01L3K1@shell.armlinux.org.uk>
References: <20251110145555.2555055-1-bigeasy@linutronix.de>
 <20251110145555.2555055-3-bigeasy@linutronix.de>
 <20251202141816.wfHNUMFK@linutronix.de>
 <aS8J0WrmmH01L3K1@shell.armlinux.org.uk>
Message-ID: <20251202160510.eUVnCuRx@linutronix.de>

On 2025-12-02 15:46:25 [+0000], Russell King (Oracle) wrote:
> If I apply 9460/1 without 9462/1 first, then it makes the problems
> with the branch predictor hardening worse. I'm not prepared to do that.
> 
> However, 9462/1 is tied up in the discussions that are ongoing, and I'm
> not going to short-circuit the still-ongoing discussions that touch
> this area by applying this patch - which would screw up everyone's
> proposals to fix the various many problems that are being discovered in
> the 32-bit ARM fault handling.
> 
> This means I can't apply 9462/1 nor 9460/1.
> 
> Since 9463/1 likely requires these, I can't apply that one either.
> 
> Sorry.

Understood. So you just want to get the other bug fixed first and then
we get back to this if it still remains open.
Please let me know if you need some testing or applied the fix and want
me to rebase these changes on top.

Sebastian


From y9.vivek at gmail.com  Tue Dec  2 08:14:13 2025
From: y9.vivek at gmail.com (vivek yadav)
Date: Tue,  2 Dec 2025 21:44:13 +0530
Subject: [PATCH] staging: media: imx: fix style issues
Message-ID: <20251202161413.92230-1-y9.vivek@gmail.com>

Applied checkpatch.pl recommendations:
- corrected whitespace
- fixed line length
- adjusted indentation

Signed-off-by: vivek yadav <y9.vivek at gmail.com>
---
 drivers/staging/media/imx/imx-media-csi.c  | 2 +-
 drivers/staging/media/imx/imx-media-vdic.c | 2 +-
 drivers/staging/media/imx/imx-media.h      | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c
index fd7e37d803e7..725478bc2026 100644
--- a/drivers/staging/media/imx/imx-media-csi.c
+++ b/drivers/staging/media/imx/imx-media-csi.c
@@ -1509,7 +1509,7 @@ static void csi_try_fmt(struct csi_priv *priv,
 	}
 
 	imx_media_try_colorimetry(&sdformat->format,
-			priv->active_output_pad == CSI_SRC_PAD_DIRECT);
+				  priv->active_output_pad == CSI_SRC_PAD_DIRECT);
 }
 
 static int csi_set_fmt(struct v4l2_subdev *sd,
diff --git a/drivers/staging/media/imx/imx-media-vdic.c b/drivers/staging/media/imx/imx-media-vdic.c
index 86f2b30cb06c..58f1112e28e5 100644
--- a/drivers/staging/media/imx/imx-media-vdic.c
+++ b/drivers/staging/media/imx/imx-media-vdic.c
@@ -616,7 +616,7 @@ static int vdic_set_fmt(struct v4l2_subdev *sd,
 }
 
 static int vdic_link_setup(struct media_entity *entity,
-			    const struct media_pad *local,
+			   const struct media_pad *local,
 			    const struct media_pad *remote, u32 flags)
 {
 	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
diff --git a/drivers/staging/media/imx/imx-media.h b/drivers/staging/media/imx/imx-media.h
index f095d9134fee..135daca7d55b 100644
--- a/drivers/staging/media/imx/imx-media.h
+++ b/drivers/staging/media/imx/imx-media.h
@@ -231,7 +231,7 @@ int imx_media_probe_complete(struct v4l2_async_notifier *notifier);
 struct imx_media_dev *imx_media_dev_init(struct device *dev,
 					 const struct media_device_ops *ops);
 int imx_media_dev_notifier_register(struct imx_media_dev *imxmd,
-			    const struct v4l2_async_notifier_operations *ops);
+				    const struct v4l2_async_notifier_operations *ops);
 
 /* imx-media-fim.c */
 struct imx_media_fim;
-- 
2.43.0



From dianders at google.com  Tue Dec  2 08:25:12 2025
From: dianders at google.com (Doug Anderson)
Date: Tue, 2 Dec 2025 08:25:12 -0800
Subject: [PATCH v8 2/2] usb: dwc3: Add Google Tensor SoC DWC3 glue driver
In-Reply-To: <00d75fd3-a796-402a-a1a3-2172862fcf91@kernel.org>
References: <20251122-controller-v8-0-e7562e0df658@google.com>
 <20251122-controller-v8-2-e7562e0df658@google.com> <2025112226-heave-refrain-53e6@gregkh>
 <CA+zupgwzQ5r=-_L79D74=9VRqRO94N0yTApHChM+Nu0cn1ss3w@mail.gmail.com>
 <2025120209-unstylish-john-2a6c@gregkh> <00d75fd3-a796-402a-a1a3-2172862fcf91@kernel.org>
Message-ID: <CAD=FV=VLOLiGDfQOWXOL0H+M4EnSj1kouYK37WHV=8OVEwt+qg@mail.gmail.com>

Hi,

On Tue, Dec 2, 2025 at 1:42?AM Krzysztof Kozlowski <krzk at kernel.org> wrote:
>
> >> I plan to add ARCH_GOOGLE as a dependency in the next
> >> version per [1], so the "depends on" would probably look like
> >> the following per your suggestion:
> >
> > But "Google" is not an arch :(
> >
> > And really, the whole "only have a sub-arch symbol" is something that
> > personally, I think is totally wrong and prevents kernel images from
> > being built for more than one "arch".  As an example, the Android GKI
>
> Probably you think ARCH_FOO as arch/FOO/ directory, but this is not the
> case. ARCH_FOO in this context is SoC platform, so e.g.
> arch/arm64/boot/dts/FOO/.
>
> All of ARCH_FOO build into one image and that's recommended way to limit
> unnecessary drivers.
>
> It's just confusing naming for whatever reason.
>
> > kernel has to support more than one of these, so what does putting this
> > behind a symbol that no one will actually use mean anything?  Android
> > will never be only building a ARCH_GOOGLE kernel.
>
> But distros will be, people will be. OK, maybe not for ARCH_GOOGLE, but
> ARCH_QCOM we do for Qualcomm-based laptops and embedded folks even more.
>
> We had this talk in the past. The point is that these drivers here are
> unusable outside of that hardware platform, so only when you choose
> hardware platform (ARCH_EXYNOS, ARCH_GOOGLE, ARCH_QCOM) you will be able
> to choose these drivers.
>
> You can also look at ARCH_FOO a bit orthogonal to actual kernel
> architecture, because ARCH_EXYNOS is for both arm (arm32) and arm64. The
> drivers should be available for all Exynos-platforms, regardless whether
> this is arm32 or arm64.

FWIW I don't feel strongly about the ARCH_XYZ Kconfig settings, but
I'd tend to agree with Krzysztof that I personally find them useful.
Sure, it's fine to just turn all of the ARCH_XYZ values on and they
shouldn't conflict with each other, but it provides an easy way for
someone to know that certain drivers are only useful if the kernel
you're building supports a given arch. If I'm building a kernel that
doesn't need to support any Qualcomm boards, for instance, I can just
turn that arch off and I don't even need to think about all of the
Qualcomm-related config options.

FWIW, if you do add a "depend" on ARCH_GOOGLE you should mention
somewhere (maybe "after the cut" in your patch) that ARCH_GOOGLE
doesn't exist yet. It should eventually exist when some version of
this patch lands:

https://lore.kernel.org/r/20251111112158.3.I35b9e835ac49ab408e5ca3e0983930a1f1395814 at changeid/

...but it's not there yet. ;-)

-Doug


From leo.yan at arm.com  Tue Dec  2 08:26:39 2025
From: leo.yan at arm.com (Leo Yan)
Date: Tue, 2 Dec 2025 16:26:39 +0000
Subject: [PATCH] printk/nbcon: Restore IRQ in atomic flush after each
 emitted record
In-Reply-To: <87o6oheywd.fsf@jogness.linutronix.de>
References: <20251202135832.156559-1-pmladek@suse.com>
 <87o6oheywd.fsf@jogness.linutronix.de>
Message-ID: <20251202162639.GD724103@e132581.arm.com>

On Tue, Dec 02, 2025 at 03:39:54PM +0106, John Ogness wrote:

[...]

> I am not really happy about all the local_irq_restore() usage. Using
> guard syntax would be nice here, but AFAICT there is no guard for
> local_irq_save()/_restore().

Sorry for suddenly jumping in.  Wouldn't guard(irqsave)() be helpful
here?


From broonie at kernel.org  Tue Dec  2 08:28:25 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 2 Dec 2025 16:28:25 +0000
Subject: [PATCH] spi: cadence-quadspi: Fix cqspi_probe() error handling
 for runtime pm
In-Reply-To: <dfbbd5ce209fac9a556c200748d8c521d0d4f450.camel@ti.com>
References: <20251119152545.2591651-1-s-vadapalli@ti.com>
 <20251201072844.GA6785@francesco-nb>
 <20251201074320.GA8737@francesco-nb>
 <dfbbd5ce209fac9a556c200748d8c521d0d4f450.camel@ti.com>
Message-ID: <5f288d65-4209-41cd-8f1a-3690f38da7ef@sirena.org.uk>

On Mon, Dec 01, 2025 at 06:08:07PM +0530, Siddharth Vadapalli wrote:
> On Mon, 2025-12-01 at 08:43 +0100, Francesco Dolcini wrote:
> > On Mon, Dec 01, 2025 at 08:28:44AM +0100, Francesco Dolcini wrote:

> > > > The error is due to the second invocation of 'clk_disable_unprepare()' on
> > > > 'cqspi->clk' in the error handling within 'cqspi_probe()', with the first
> > > > invocation being within 'cqspi_runtime_suspend()'.

> > > [    8.648915] cadence-qspi fc40000.spi: No flash device declared
> > > [    8.675671] cadence-qspi fc40000.spi: failed to setup flash parameters -19

> Could you please check if the driver's suspend callback has executed before
> the above? The patch intended to fix the very issue being reported.
> Therefore, the commit corresponding to the current patch might still
> trigger the issue. Ideally, reverting the commit for the current patch and
> the commit under Fixes (f1eb4e792bb1 ("spi: spi-cadence-quadspi: Enable pm
> runtime earlier to avoid imbalance"))
> should prevent the issue.

Given the above log we've failed at cqspi_setup_flash() so we shouldn't
have got as far as the code you changed for handling direct mode - I
think the actual issue is likely Anurag's earlier change f1eb4e792bb1
(spi: spi-cadence-quadspi: Enable pm runtime earlier to avoid imbalance)
that you mention, it means we've done a pm_runtime_get_noresume()
previously.  That shouldn't have done a clock enable due to the
noresume, but the get() being there will confuse pm_runtime_disable()
and cause it to invoke the suspend callback as Francesco identified.
This will have been failing previously if controller registration
failed, but it's now happening in more situations.

This is all very annoying since runtime PM can be configured off so we
can't rely on it's callbacks actually happening.  I *think* something
like the below ought to DTRT (I'd expect it should avoid the reported
error at least):

diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c
index af6d050da1c8..0833b6f666d0 100644
--- a/drivers/spi/spi-cadence-quadspi.c
+++ b/drivers/spi/spi-cadence-quadspi.c
@@ -1985,7 +1985,6 @@ static int cqspi_probe(struct platform_device *pdev)
 		pm_runtime_enable(dev);
 		pm_runtime_set_autosuspend_delay(dev, CQSPI_AUTOSUSPEND_TIMEOUT);
 		pm_runtime_use_autosuspend(dev);
-		pm_runtime_get_noresume(dev);
 	}
 
 	ret = cqspi_setup_flash(cqspi);
@@ -2012,6 +2011,7 @@ static int cqspi_probe(struct platform_device *pdev)
 	}
 
 	if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) {
+		pm_runtime_get_noresume(dev);
 		pm_runtime_mark_last_busy(dev);
 		pm_runtime_put_autosuspend(dev);
 	}

Unfortunately none of my testing appears to show the issue.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251202/91559d51/attachment.sig>

From marek.vasut at mailbox.org  Tue Dec  2 08:36:53 2025
From: marek.vasut at mailbox.org (Marek Vasut)
Date: Tue, 2 Dec 2025 17:36:53 +0100
Subject: [PATCH 1/2] dt-bindings: firmware: arm,scmi: Document
 arm,poll-transport property
In-Reply-To: <20251202-evasive-neon-rhino-d2745e@sudeepholla>
References: <20251023123644.8730-1-marek.vasut+renesas@mailbox.org>
 <aPoxfH_TLrsMxMVQ@pluto> <70554674-7020-4582-a4e7-dbee34907096@mailbox.org>
 <5ae0a793-d3e7-45d1-bf5c-3c46593d1824@mailbox.org> <aRW7BZimWdpq4TyX@pluto>
 <20251202-evasive-neon-rhino-d2745e@sudeepholla>
Message-ID: <66257fcf-9024-454f-b776-4ba584963ebe@mailbox.org>

On 12/2/25 3:52 PM, Sudeep Holla wrote:

Hello Sudeep,

>>> While I was going through the SCMI spec, DEN0056F , page 209 , section "4.1
>>> Shared memory based transport" , bullet ? Completion interrupts, I found it
>>> explicitly states:
>>>
>>> "
>>> This transport supports polling or interrupt driven modes of communication.
>>> In interrupt mode, when the callee completes processing a message, it raises
>>> an interrupt to the caller. Hardware support for completion interrupts is
>>> optional.
>>> "
>>
>> Oh, yes...I knew that...it is just that till now, no systems were really
>> ever developed that lacked the completion IRQ as a whole, it was, till now,
>> more of a case of having the capability NOT to use it selectively at runtime
>> and instead use polling when wanted (like for clock ops in ISR context)
>>
> 
> Indeed.
> 
>> I am not sure what is the reason why this only-polling scenario was never
>> supported in the HW description, this indeed pre-dates my work on SCMI....
>> ...I would/will check with Sudeep, when he's back, what are the reasons for
>> this (if any)...
>>
> 
> As you mentioned earlier, no platform has required this before. I?m fine with
> adding it, but we need to be more explicit about what it implies for SCMI. The
> transport may be shared with other system components, and enforcing polling
> for SCMI while the same transport generates interrupts for another user could
> lead to issues.

How do you imagine this -- a transport shared with other components, one 
which does generate IRQs and one which does not -- would look like ? Can 
you think of an example ?

> Clearly defining these constraints would be helpful. It may also be useful to
> note that this is primarily intended for mailbox transports, if that?s
> accurate. Alternatively, we could keep the DT binding definition broader but
> emit warnings when a transport other than mailbox is used. That approach might
> make it easier to move forward.

DEN0056F refers to this polling mode in Shared memory based transports, 
that can be other than mailbox transports, it includes e.g. SMC or OPTEE 
transports.

I don't think a warning is justified, if the behavior follows the 
specification. But I do agree the behavior is ... suboptimal.

-- 
Best regards,
Marek Vasut


From jon at nutanix.com  Tue Dec  2 08:54:44 2025
From: jon at nutanix.com (Jon Kohler)
Date: Tue, 2 Dec 2025 16:54:44 +0000
Subject: [PATCH net-next] vhost: use "checked" versions of get_user() and
 put_user()
In-Reply-To: <20251127013146-mutt-send-email-mst@kernel.org>
References: <E1226897-C6D1-439C-AB3B-012F8C4A72DF@nutanix.com>
 <CACGkMEuPK4=Tf3x-k0ZHY1rqL=2rg60-qdON8UJmQZTqpUryTQ@mail.gmail.com>
 <A0AFD371-1FA3-48F7-A259-6503A6F052E5@nutanix.com>
 <CACGkMEvD16y2rt+cXupZ-aEcPZ=nvU7+xYSYBkUj7tH=ER3f-A@mail.gmail.com>
 <121ABD73-9400-4657-997C-6AEA578864C5@nutanix.com>
 <CACGkMEtk7veKToaJO9rwo7UeJkN+reaoG9_XcPG-dKAho1dV+A@mail.gmail.com>
 <61102cff-bb35-4fe4-af61-9fc31e3c65e0@app.fastmail.com>
 <02B0FDF1-41D4-4A7D-A57E-089D2B69CEF2@nutanix.com>
 <CACGkMEshKS84YBuqyEzYuuWJqUwGML4N+5Ev6owbiPHvogO=3Q@mail.gmail.com>
 <5EB2ED95-0BA3-4E71-8887-2FCAF002577C@nutanix.com>
 <20251127013146-mutt-send-email-mst@kernel.org>
Message-ID: <6AD6B7D8-6368-45ED-B7EB-484F25D13BE6@nutanix.com>



> On Nov 27, 2025, at 1:32?AM, Michael S. Tsirkin <mst at redhat.com> wrote:
> 
> On Thu, Nov 27, 2025 at 03:11:57AM +0000, Jon Kohler wrote:
>> 
>> 
>>> On Nov 26, 2025, at 8:08?PM, Jason Wang <jasowang at redhat.com> wrote:
>>> 
>>> On Thu, Nov 27, 2025 at 3:48?AM Jon Kohler <jon at nutanix.com> wrote:
>>>> 
>>>> 
>>>>> On Nov 26, 2025, at 5:25?AM, Arnd Bergmann <arnd at arndb.de> wrote:
>>>>> 
>>>>> On Wed, Nov 26, 2025, at 07:04, Jason Wang wrote:
>>>>>> On Wed, Nov 26, 2025 at 3:45?AM Jon Kohler <jon at nutanix.com> wrote:
>>>>>>>> On Nov 19, 2025, at 8:57?PM, Jason Wang <jasowang at redhat.com> wrote:
>>>>>>>> On Tue, Nov 18, 2025 at 1:35?AM Jon Kohler <jon at nutanix.com> wrote:
>>>>>>> Same deal goes for __put_user() vs put_user by way of commit
>>>>>>> e3aa6243434f ("ARM: 8795/1: spectre-v1.1: use put_user() for __put_user()?)
>>>>>>> 
>>>>>>> Looking at arch/arm/mm/Kconfig, there are a variety of scenarios
>>>>>>> where CONFIG_CPU_SPECTRE will be enabled automagically. Looking at
>>>>>>> commit 252309adc81f ("ARM: Make CONFIG_CPU_V7 valid for 32bit ARMv8 implementations")
>>>>>>> it says that "ARMv8 is a superset of ARMv7", so I?d guess that just
>>>>>>> about everything ARM would include this by default?
>>>>> 
>>>>> I think the more relevant commit is for 64-bit Arm here, but this does
>>>>> the same thing, see 84624087dd7e ("arm64: uaccess: Don't bother
>>>>> eliding access_ok checks in __{get, put}_user").
>>>> 
>>>> Ah! Right, this is definitely the important bit, as it makes it
>>>> crystal clear that these are exactly the same thing. The current
>>>> code is:
>>>> #define get_user        __get_user
>>>> #define put_user        __put_user
>>>> 
>>>> So, this patch changing from __* to regular versions is a no-op
>>>> on arm side of the house, yea?
>>>> 
>>>>> I would think that if we change the __get_user() to get_user()
>>>>> in this driver, the same should be done for the
>>>>> __copy_{from,to}_user(), which similarly skips the access_ok()
>>>>> check but not the PAN/SMAP handling.
>>>> 
>>>> Perhaps, thats a good call out. I?d file that under one battle
>>>> at a time. Let?s get get/put user dusted first, then go down
>>>> that road?
>>>> 
>>>>> In general, the access_ok()/__get_user()/__copy_from_user()
>>>>> pattern isn't really helpful any more, as Linus already
>>>>> explained. I can't tell from the vhost driver code whether
>>>>> we can just drop the access_ok() here and use the plain
>>>>> get_user()/copy_from_user(), or if it makes sense to move
>>>>> to the newer user_access_begin()/unsafe_get_user()/
>>>>> unsafe_copy_from_user()/user_access_end() and try optimize
>>>>> out a few PAN/SMAP flips in the process.
>>> 
>>> Right, according to my testing in the past, PAN/SMAP is a killer for
>>> small packet performance (PPS).
>> 
>> For sure, every little bit helps along that path
>> 
>>> 
>>>> 
>>>> In general, I think there are a few spots where we might be
>>>> able to optimize (vhost_get_vq_desc perhaps?) as that gets
>>>> called quite a bit and IIRC there are at least two flips
>>>> in there that perhaps we could elide to one? An investigation
>>>> for another day I think.
>>> 
>>> Did you mean trying to read descriptors in a batch, that would be
>>> better and with IN_ORDER it would be even faster as a single (at most
>>> two) copy_from_user() might work (without the need to use
>>> user_access_begin()/user_access_end().
>> 
>> Yep. I haven?t fully thought through it, just a drive-by idea
>> from looking at code for the recent work I?ve been doing, just
>> scratching my head thinking there *must* be something we can do
>> better there.
>> 
>> Basically on the get rx/tx bufs path as well as the
>> vhost_add_used_and_signal_n path, I think we could cluster together
>> some of the get/put users and copy to/from?s. Would take some
>> massaging, but I think there is something there.
>> 
>>>> 
>>>> Anyhow, with this info - Jason - is there anything else you
>>>> can think of that we want to double click on?
>>> 
>>> Nope.
>>> 
>>> Thanks
>> 
>> Ok thanks. Perhaps we can land this in next and let it soak in,
>> though, knock on wood, I don?t think there will be fallout
>> (famous last words!) ?
>> 
> 
> 
> To clairify, I think vhost tree is better to put this
> in next than net-next, both because it's purely core vhost
> and because unlike net-next vhost rebases so it is easy to
> just drop the patch if there are issues.
> I'll put it there.
> 
> -- 
> MST
> 

Ok cool, thank you!

From leo.yan at arm.com  Tue Dec  2 08:56:47 2025
From: leo.yan at arm.com (Leo Yan)
Date: Tue, 2 Dec 2025 16:56:47 +0000
Subject: [PATCH 11/19] coresight: trbe: Apply overwrite erratum for only
 wrap event
In-Reply-To: <cca13ee6-83d9-4478-ace0-1e7bedf79d0e@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-11-7da32b076b28@arm.com>
 <cca13ee6-83d9-4478-ace0-1e7bedf79d0e@arm.com>
Message-ID: <20251202165647.GE724103@e132581.arm.com>

On Tue, Dec 02, 2025 at 12:05:52PM +0000, Suzuki K Poulose wrote:
> On 01/12/2025 11:22, Leo Yan wrote:
> > The overwrite erratum occurs only on wrap events, so apply the extra
> > wrap condition check in the workaround.
> > 
> > Signed-off-by: Leo Yan <leo.yan at arm.com>
> > ---
> >   drivers/hwtracing/coresight/coresight-trbe.c | 4 ++--
> >   1 file changed, 2 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
> > index e579ea98523c24d23a0cd265dcdd0a46b52b52da..2600af12a8fb94bb8c74efda2a101aacd01b0b34 100644
> > --- a/drivers/hwtracing/coresight/coresight-trbe.c
> > +++ b/drivers/hwtracing/coresight/coresight-trbe.c
> > @@ -714,7 +714,7 @@ static unsigned long trbe_get_trace_size(struct perf_output_handle *handle,
> >   	 * 64bytes. Thus we ignore the potential triggering of the erratum
> >   	 * on WRAP and limit the data to LIMIT.
> >   	 */
> > -	if (wrap)
> > +	if (wrap && trbe_may_overwrite_in_fill_mode(buf->cpudata))
> >   		write = get_trbe_limit_pointer();
> 
> This must be trbe_may_write_out_of_range() ?

SDEN (e.g., [1]) is ambiguous about how the write pointer acts for the
out-of-range erratum.

However, SDEN explicitly states for overwrite erratum: "The current
write pointer also increments by the same number of cache line
locations.

If this is still concerned, I can add check
trbe_may_write_out_of_range() in next spin.

Thanks,
Leo

[1] https://documentation-service.arm.com/static/636a660b4e6cf12278ad89c4?token=


From kees at kernel.org  Tue Dec  2 08:59:07 2025
From: kees at kernel.org (Kees Cook)
Date: Tue, 2 Dec 2025 08:59:07 -0800
Subject: [RFC PATCH v1 0/2] Fix bugs and performance of kstack offset
 randomisation
In-Reply-To: <20251127105958.2427758-1-ryan.roberts@arm.com>
References: <20251127105958.2427758-1-ryan.roberts@arm.com>
Message-ID: <202512020858.8BD22F486@keescook>

On Thu, Nov 27, 2025 at 10:59:54AM +0000, Ryan Roberts wrote:
> As I reported at [1], kstack offset randomisation suffers from a couple of bugs
> and, on arm64 at least, the performance is poor. This series attempts to fix
> both; patch 1 provides back-portable fixes for the functional bugs. Patch 2
> proposes a performance improvement approach.

Just to chime in -- this looks really good to me! Universally improved
performance, reduced complexity, and better randomness. :) I'm looking
forward to v2!

-Kees

-- 
Kees Cook


From danielwa at cisco.com  Tue Dec  2 09:04:28 2025
From: danielwa at cisco.com (Daniel Walker (danielwa))
Date: Tue, 2 Dec 2025 17:04:28 +0000
Subject: i2c-xiic driver changes from Cisco
Message-ID: <aS8cG4Otywg1kIcr@goliath>

Hi,

We have a slightly modified version of the Xilinx IP which the i2c-xiic.c
sources seem to support.

We made one (or at least one) change to the IP were we don't supply it with an
interrupt line. It doesn't appear the driver supports this configuration.
Is that accurate to your knowledge ?

If the drivers doesn't support some type of polling mode, is Xilinx willing to accept
changes which would make the driver compatible with a polling mode if an
interrupt is not supplied thru the device tree ?

It seems like it makes sense the driver should support a polling mode because
Xilinx customers may make a product where the interrupt line doesn't function
properly. In that case the customer would need a contingency which could be
polling for interrupts.

Daniel

From leo.yan at arm.com  Tue Dec  2 09:12:33 2025
From: leo.yan at arm.com (Leo Yan)
Date: Tue, 2 Dec 2025 17:12:33 +0000
Subject: [PATCH 11/19] coresight: trbe: Apply overwrite erratum for only
 wrap event
In-Reply-To: <20251202165647.GE724103@e132581.arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-11-7da32b076b28@arm.com>
 <cca13ee6-83d9-4478-ace0-1e7bedf79d0e@arm.com>
 <20251202165647.GE724103@e132581.arm.com>
Message-ID: <20251202171233.GF724103@e132581.arm.com>

On Tue, Dec 02, 2025 at 04:56:47PM +0000, Coresight ML wrote:
> On Tue, Dec 02, 2025 at 12:05:52PM +0000, Suzuki K Poulose wrote:
> > On 01/12/2025 11:22, Leo Yan wrote:
> > > The overwrite erratum occurs only on wrap events, so apply the extra
> > > wrap condition check in the workaround.
> > > 
> > > Signed-off-by: Leo Yan <leo.yan at arm.com>
> > > ---
> > >   drivers/hwtracing/coresight/coresight-trbe.c | 4 ++--
> > >   1 file changed, 2 insertions(+), 2 deletions(-)
> > > 
> > > diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
> > > index e579ea98523c24d23a0cd265dcdd0a46b52b52da..2600af12a8fb94bb8c74efda2a101aacd01b0b34 100644
> > > --- a/drivers/hwtracing/coresight/coresight-trbe.c
> > > +++ b/drivers/hwtracing/coresight/coresight-trbe.c
> > > @@ -714,7 +714,7 @@ static unsigned long trbe_get_trace_size(struct perf_output_handle *handle,
> > >   	 * 64bytes. Thus we ignore the potential triggering of the erratum
> > >   	 * on WRAP and limit the data to LIMIT.
> > >   	 */
> > > -	if (wrap)
> > > +	if (wrap && trbe_may_overwrite_in_fill_mode(buf->cpudata))
> > >   		write = get_trbe_limit_pointer();
> > 
> > This must be trbe_may_write_out_of_range() ?
> 
> SDEN (e.g., [1]) is ambiguous about how the write pointer acts for the
> out-of-range erratum.

Thought again, we should not worry about out-of-range case.

As the workaround always ensures sufficient space beyond the limit, the
write pointer remains valid within the allocated buffer even if it is
updated and crosses that limit.


From dan.carpenter at linaro.org  Tue Dec  2 10:17:03 2025
From: dan.carpenter at linaro.org (Dan Carpenter)
Date: Tue, 2 Dec 2025 21:17:03 +0300
Subject: [PATCH 1/4] net: stmmac: s32: use the syscon interface
 PHY_INTF_SEL_RGMII
In-Reply-To: <aS4W0M+ZkQzuUjtT@lizhi-Precision-Tower-5810>
References: <cover.1764592300.git.dan.carpenter@linaro.org>
 <6275e666a7ef78bd4c758d3f7f6fb6f30407393e.1764592300.git.dan.carpenter@linaro.org>
 <aS4W0M+ZkQzuUjtT@lizhi-Precision-Tower-5810>
Message-ID: <aS8tH3VD9uxl56ah@stanley.mountain>

On Mon, Dec 01, 2025 at 05:29:36PM -0500, Frank Li wrote:
> On Mon, Dec 01, 2025 at 04:08:20PM +0300, Dan Carpenter wrote:
> > On the s32 chipset the GMAC_0_CTRL_STS register is in GPR region.
> > Originally, accessing this register was done in a sort of ad-hoc way,
> > but we want to use the syscon interface to do it.
> 
> What's benefit by use syscon interface here? syscon have not much
> well consided funcitonal abstraction.
> 

The GPR has a bunch of random registers that aren't really related.
On these chips they're just regular MMIO registers, but in other
configurations you can only access them using SCMI.

It's better to group them together that's how they are in the hardware.
Otherwise we'd end up randomly adding a register address to the
ethernet device tree entry, but it's nicer to use a phandle to
reference the GPR.

The only register we're using now is the GMAC_0_CTRL_STS but here
is the list of registers in the GPR.

>From 0x4007C000

0  Software-Triggered Faults (SW_NCF)
4  GMAC Control (GMAC_0_CTRL_STS)
28 CMU Status 1 (CMU_STATUS_REG1)
2C CMUs Status 2 (CMU_STATUS_REG2)
30 FCCU EOUT Override Clear (FCCU_EOUT_OVERRIDE_CLEAR_REG)
38 SRC POR Control (SRC_POR_CTRL_REG)
54 GPR21 (GPR21)
5C GPR23 (GPR23)
60 GPR24 Register (GPR24)
CC Debug Control (DEBUG_CONTROL)
F0 Timestamp Control (TIMESTAMP_CONTROL_REGISTER)
F4 FlexRay OS Tick Input Select (FLEXRAY_OS_TICK_INPUT_SELECT_REG)
FC GPR63 Register (GPR63)

Then from 0x4007CA00

0  Coherency Enable for PFE Ports (PFE_COH_EN)
4  PFE EMAC Interface Mode (PFE_EMACX_INTF_SEL)
20 PFE EMACX Power Control (PFE_PWR_CTRL)
28 Error Injection on Cortex-M7 AHB and AXI Pipe (CM7_TCM_AHB_SLICE)
2C Error Injection AHBP Gasket Cortex-M7 (ERROR_INJECTION_AHBP_GASKET_CM7)
40 LLCE Subsystem Status (LLCE_STAT)
44 LLCE Power Control (LLCE_CTRL)
48 DDR Urgent Control (DDR_URGENT_CTRL)
4C FTM Global Load Control (FLXTIM_CTRL)
50 FTM LDOK Status (FLXTIM_STAT)
54 Top CMU Status (CMU_STAT)
58 Accelerator NoC No Pending Trans Status (NOC_NOPEND_TRANS)
90 SerDes RD/WD Toggle Control (PCIE_TOGGLE)
94 SerDes Toggle Done Status (PCIE_TOGGLEDONE_STAT)
E0 Generic Control 0 (GENCTRL0)
E4 Generic Control 1 (GENCTRL1)
F0 Generic Status 0 (GENSTAT0)
FC Cortex-M7 AXI Parity Error and AHBP Gasket Error Alarm (CM7_AXI_AHBP_GASKET_ERROR_ALARM)

>From 4007C800

4  GPR01 Register (GPR01)
30 GPR12 Register (GPR12)
58 GPR22 Register (GPR22)
70 GPR28 Register (GPR28)
74 GPR29 Register (GPR29)

>From 4007CB00

4 WKUP Pad Pullup/Pulldown Select (WKUP_PUS)

regards,
dan carpenter



From kuba at kernel.org  Tue Dec  2 10:34:52 2025
From: kuba at kernel.org (Jakub Kicinski)
Date: Tue, 2 Dec 2025 10:34:52 -0800
Subject: [PATCH v2] net: stmmac: Modify the judgment condition of
 "tx_avail" from 1 to 2
In-Reply-To: <tencent_4A0CBC92B9B22C699AC2890E139565FCB306@qq.com>
References: <tencent_4A0CBC92B9B22C699AC2890E139565FCB306@qq.com>
Message-ID: <20251202103452.0d2df13d@kernel.org>

On Tue,  2 Dec 2025 15:43:59 +0800 2694439648 at qq.com wrote:
> From: "hailong.fan" <hailong.fan at siengine.com>
> 
>     Under certain conditions, a WARN_ON will be triggered
>     if avail equals 1.
> 
>     For example, when a VLAN packet is to send,
>     stmmac_vlan_insert consumes one unit of space,
>     and the data itself consumes another.
>     actually requiring 2 units of space in total.
> 
>     ---
>     V0-V1:
>        1. Stop their queues earlier
>     V2-V1:
>        1. add fixes tag
>        2. Add stmmac_extra_space to count the additional required space

Why is the commit message indented ? Please looks around the mailing
list and try to follow the format others are using. Or read the
documentation. Either of the two will do.
https://www.kernel.org/doc/html/next/process/maintainer-netdev.html#changes-requested

> Fixes: 30d932279dc2 ("net: stmmac: Add support for VLAN Insertion Offload")
> Signed-off-by: hailong.fan <hailong.fan at siengine.com>
> ---
>  drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 14 ++++++++++++--
>  1 file changed, 12 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index 7b90ecd3a..9a665a3b2 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -4476,6 +4476,15 @@ static bool stmmac_has_ip_ethertype(struct sk_buff *skb)
>  		(proto == htons(ETH_P_IP) || proto == htons(ETH_P_IPV6));
>  }
>  
> +static inline int stmmac_extra_space(struct stmmac_priv *priv,
> +				     struct sk_buff *skb)
> +{
> +	if (!priv->dma_cap.vlins || !skb_vlan_tag_present(skb))
> +		return 0;
> +
> +	return 1;
> +}
> +
>  /**
>   *  stmmac_xmit - Tx entry point of the driver
>   *  @skb : the socket buffer
> @@ -4529,7 +4538,8 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
>  		}
>  	}
>  
> -	if (unlikely(stmmac_tx_avail(priv, queue) < nfrags + 1)) {
> +	if (unlikely(stmmac_tx_avail(priv, queue) <
> +		nfrags + 1 + stmmac_extra_space(priv, skb))) {

extra logic is likely not worth the single descriptor saving, can you
use the same + 2 as in the condition for stopping the queue, please?

>  		if (!netif_tx_queue_stopped(netdev_get_tx_queue(dev, queue))) {
>  			netif_tx_stop_queue(netdev_get_tx_queue(priv->dev,
>  								queue));
> @@ -4675,7 +4685,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
>  		print_pkt(skb->data, skb->len);
>  	}
>  
> -	if (unlikely(stmmac_tx_avail(priv, queue) <= (MAX_SKB_FRAGS + 1))) {
> +	if (unlikely(stmmac_tx_avail(priv, queue) <= (MAX_SKB_FRAGS + 2))) {


From kuba at kernel.org  Tue Dec  2 10:36:14 2025
From: kuba at kernel.org (Jakub Kicinski)
Date: Tue, 2 Dec 2025 10:36:14 -0800
Subject: [PATCH v2] net: stmmac: Modify the judgment condition of
 "tx_avail" from 1 to 2
In-Reply-To: <tencent_4A0CBC92B9B22C699AC2890E139565FCB306@qq.com>
References: <tencent_4A0CBC92B9B22C699AC2890E139565FCB306@qq.com>
Message-ID: <20251202103614.6a185bf6@kernel.org>

On Tue,  2 Dec 2025 15:43:59 +0800 2694439648 at qq.com wrote:
> -	if (unlikely(stmmac_tx_avail(priv, queue) <= (MAX_SKB_FRAGS + 1))) {
> +	if (unlikely(stmmac_tx_avail(priv, queue) <= (MAX_SKB_FRAGS + 2))) {

Also, if there isn't a comment already somewhere - it's worth
documenting what the + 2 stands for. head buffer + vlan + frags ?


From sudeep.holla at arm.com  Tue Dec  2 10:55:21 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Tue, 2 Dec 2025 18:55:21 +0000
Subject: [PATCH 1/2] dt-bindings: firmware: arm,scmi: Document
 arm,poll-transport property
In-Reply-To: <66257fcf-9024-454f-b776-4ba584963ebe@mailbox.org>
References: <20251023123644.8730-1-marek.vasut+renesas@mailbox.org>
 <aPoxfH_TLrsMxMVQ@pluto>
 <70554674-7020-4582-a4e7-dbee34907096@mailbox.org>
 <5ae0a793-d3e7-45d1-bf5c-3c46593d1824@mailbox.org>
 <aRW7BZimWdpq4TyX@pluto>
 <20251202-evasive-neon-rhino-d2745e@sudeepholla>
 <66257fcf-9024-454f-b776-4ba584963ebe@mailbox.org>
Message-ID: <aS82GSN8c2SnRn4S@bogus>

On Tue, Dec 02, 2025 at 05:36:53PM +0100, Marek Vasut wrote:
> On 12/2/25 3:52 PM, Sudeep Holla wrote:
> 
> Hello Sudeep,
> 
> > > > While I was going through the SCMI spec, DEN0056F , page 209 , section "4.1
> > > > Shared memory based transport" , bullet ? Completion interrupts, I found it
> > > > explicitly states:
> > > > 
> > > > "
> > > > This transport supports polling or interrupt driven modes of communication.
> > > > In interrupt mode, when the callee completes processing a message, it raises
> > > > an interrupt to the caller. Hardware support for completion interrupts is
> > > > optional.
> > > > "
> > > 
> > > Oh, yes...I knew that...it is just that till now, no systems were really
> > > ever developed that lacked the completion IRQ as a whole, it was, till now,
> > > more of a case of having the capability NOT to use it selectively at runtime
> > > and instead use polling when wanted (like for clock ops in ISR context)
> > > 
> > 
> > Indeed.
> > 
> > > I am not sure what is the reason why this only-polling scenario was never
> > > supported in the HW description, this indeed pre-dates my work on SCMI....
> > > ...I would/will check with Sudeep, when he's back, what are the reasons for
> > > this (if any)...
> > > 
> > 
> > As you mentioned earlier, no platform has required this before. I?m fine with
> > adding it, but we need to be more explicit about what it implies for SCMI. The
> > transport may be shared with other system components, and enforcing polling
> > for SCMI while the same transport generates interrupts for another user could
> > lead to issues.
> 
> How do you imagine this -- a transport shared with other components, one
> which does generate IRQs and one which does not -- would look like ? Can you
> think of an example ?
> 

Consider a system where a mailbox controller is present and one channel is
used for SCMI communication, while another channel is used for an unrelated
purpose. If both channels share the same interrupt line, and the other use
case enables interrupt mode on its channel, what would be the impact on the
SCMI-specific channel?

I am aware of systems that implement such sharing, which is why I prefer to be
explicit that this type of design is challenging to support within this
binding. The intent is to support only minimal, constrained cases - essentially
systems that are already somewhat broken. I do not see value in broadening the
binding to cover every conceivable scenario.

> > Clearly defining these constraints would be helpful. It may also be useful to
> > note that this is primarily intended for mailbox transports, if that?s
> > accurate. Alternatively, we could keep the DT binding definition broader but
> > emit warnings when a transport other than mailbox is used. That approach might
> > make it easier to move forward.
> 
> DEN0056F refers to this polling mode in Shared memory based transports, that
> can be other than mailbox transports, it includes e.g. SMC or OPTEE
> transports.
> 

However, polling does not make sense in the context of SMC. Once control
returns from an SMC call, the command has completed. What form of polling in
an SMC workflow do you have in mind? I believe the same applies to OP-TEE.
While OP-TEE now provides a notification mechanism that could, in theory,
allow synchronous commands to be treated in a quasi-asynchronous manner, I
strongly doubt that the current SCMI-over-OP-TEE implementation behaves this
way, given that it ultimately reaches the secure side via an SMC call.

> I don't think a warning is justified, if the behavior follows the
> specification. But I do agree the behavior is ... suboptimal.
> 

The specification does not address SMC or OP-TEE transports, placing them
outside its scope and likewise these DT bindings. Consequently, what we
decide here in this discussion effectively defines the expected behavior in
this context, in my view. So I would like to start with minimal possible
coverage, why do you think that is not a good idea here ?

-- 
Regards,
Sudeep


From marek.vasut at mailbox.org  Tue Dec  2 11:25:11 2025
From: marek.vasut at mailbox.org (Marek Vasut)
Date: Tue, 2 Dec 2025 20:25:11 +0100
Subject: [PATCH 1/2] dt-bindings: firmware: arm,scmi: Document
 arm,poll-transport property
In-Reply-To: <aS82GSN8c2SnRn4S@bogus>
References: <20251023123644.8730-1-marek.vasut+renesas@mailbox.org>
 <aPoxfH_TLrsMxMVQ@pluto> <70554674-7020-4582-a4e7-dbee34907096@mailbox.org>
 <5ae0a793-d3e7-45d1-bf5c-3c46593d1824@mailbox.org> <aRW7BZimWdpq4TyX@pluto>
 <20251202-evasive-neon-rhino-d2745e@sudeepholla>
 <66257fcf-9024-454f-b776-4ba584963ebe@mailbox.org> <aS82GSN8c2SnRn4S@bogus>
Message-ID: <8d773671-5e2e-4e21-ade6-2bf9a3b75066@mailbox.org>

On 12/2/25 7:55 PM, Sudeep Holla wrote:

Hello Sudeep,

>> How do you imagine this -- a transport shared with other components, one
>> which does generate IRQs and one which does not -- would look like ? Can you
>> think of an example ?
>>
> 
> Consider a system where a mailbox controller is present and one channel is
> used for SCMI communication, while another channel is used for an unrelated
> purpose. If both channels share the same interrupt line, and the other use
> case enables interrupt mode on its channel, what would be the impact on the
> SCMI-specific channel?

None, SCMI kernel driver and SCMI server side would still do polling on 
their respective SHMEM areas, while whatever kernel driver needs to 
receive the interrupt notifications would subscribe to them using 
request_irq(), right ?

> I am aware of systems that implement such sharing, which is why I prefer to be
> explicit that this type of design is challenging to support within this
> binding. The intent is to support only minimal, constrained cases - essentially
> systems that are already somewhat broken. I do not see value in broadening the
> binding to cover every conceivable scenario.
> 
>>> Clearly defining these constraints would be helpful. It may also be useful to
>>> note that this is primarily intended for mailbox transports, if that?s
>>> accurate. Alternatively, we could keep the DT binding definition broader but
>>> emit warnings when a transport other than mailbox is used. That approach might
>>> make it easier to move forward.
>>
>> DEN0056F refers to this polling mode in Shared memory based transports, that
>> can be other than mailbox transports, it includes e.g. SMC or OPTEE
>> transports.
>>
> 
> However, polling does not make sense in the context of SMC. Once control
> returns from an SMC call, the command has completed. What form of polling in
> an SMC workflow do you have in mind?

I think the polling happens on the SHMEM and the SMC transport is 
capable of that too, see :

drivers/firmware/arm_scmi/transports/smc.c

175         /*
176          * If there is an interrupt named "a2p", then the service and
177          * completion of a message is signaled by an interrupt 
rather than by
178          * the return of the SMC call.
179          */
180         scmi_info->irq = of_irq_get_byname(cdev->of_node, "a2p");

> I believe the same applies to OP-TEE.
> While OP-TEE now provides a notification mechanism that could, in theory,
> allow synchronous commands to be treated in a quasi-asynchronous manner, I
> strongly doubt that the current SCMI-over-OP-TEE implementation behaves this
> way, given that it ultimately reaches the secure side via an SMC call.
> 
>> I don't think a warning is justified, if the behavior follows the
>> specification. But I do agree the behavior is ... suboptimal.
>>
> 
> The specification does not address SMC or OP-TEE transports, placing them
> outside its scope and likewise these DT bindings.

I believe the shmem transport includes the SMC and OPTEE ones, right ?

> Consequently, what we
> decide here in this discussion effectively defines the expected behavior in
> this context, in my view. So I would like to start with minimal possible
> coverage, why do you think that is not a good idea here ?

I would argue the current implementation covers pretty much every 
transport which could ever need to do polling on shmem, so the 
implementation is generic and inline with the specification. Also, the 
current implementation is some 20 lines, so I think it is minimalistic?

What would you propose we do here ?

-- 
Best regards,
Marek Vasut


From sjg at chromium.org  Tue Dec  2 12:07:32 2025
From: sjg at chromium.org (Simon Glass)
Date: Tue, 2 Dec 2025 20:07:32 +0000
Subject: Proposal: Officially allow "incomplete" trees as a base
In-Reply-To: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
References: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
Message-ID: <CAFLszTiVT9rHwympUJSehxaDR7ks9Bs2FVjYEuN6=j1e_-289Q@mail.gmail.com>

Hi Doug!

On Tue, 18 Nov 2025 at 22:43, Doug Anderson <dianders at chromium.org> wrote:
>
> This is a continuation of the discussion that started in reply to my
> patch adding basic device trees for Pixel 10 phones [1].
>
>
> Problem statement:
> ------------------
>
> We would like an officially accepted scheme that lets us more
> efficiently ship compiled device trees for a handful of related
> products by breaking the device trees up into a common "base" device
> tree and then applying "overlay" device trees atop the base to make a
> full and complete device tree.
>
> To make it more concrete, we'd like to build a "base" device tree that
> describes a SoC and then have the overlays be enough to make a full
> description of a board. In theory, one could also imagine wanting to
> expand this to 3 or more levels (perhaps SoC, baseboard, derived
> boards), though this is not planned at this time.
>
> The primary reason for wanting to break device trees like this is
> efficiency of the shipped binary device trees. A large portion of a
> final device tree just describes the SoC. We save space in the final
> compiled device trees if they don't need to contain as much duplicated
> information.
>
> A secondary reason for wanting to break device trees like this is to
> more nicely handle when a board has a socketed SoC that can be
> replaced with a finite (and small) number of different SoCs (usually
> revisions of the same SoC). Even if this secondary reason is
> considered invalid or too difficult, the primary reason still
> describes a compelling need.
>
> In order to make this proposal work, it's expected that a bootloader
> will understand the scheme and will know how to combine the overlay
> atop the base before passing a complete device tree to the main OS.
>
>
> Current state of the art (downstream):
> --------------------------------------
>
> In Android, we do a pretty good job of solving the stated problem
> using device tree overlays. We describe the SoCs in "dts" files and
> compile them into "dtb"s. We describe boards in "dtso" files and
> compile them into "dtbo" files. A bootloader can handle identifying
> the correct base and overlay (the scheme for doing this is a separate
> but related topic) and applying the overlay atop the base "dtb". This
> solution is fully implemented downstream for Android phones and is
> well documented [2].
>
> The issues I'm aware of with the current state of the art are:
>
> 1. In order for the base device tree to pass schema validation on its
> own we'd need to document the top-level compatible strings in the
> device tree. It is the opinion of at least some device tree
> maintainers that a SoC doesn't qualify as a top-level compatible
> string. This prevents the device trees from landing in an officially
> sanctioned location.
>
> 2. It is also possible we may fail schema validation for the base SoC
> tree if the schema marks a property as "required" but that property
> needs to be filled out by the board (perhaps a "-supply" is marked as
> "required", since most "-supply" properties are filled in by the
> board. I'm not sure this is a big issue, but it's something to think
> about.
>
> 3. It's unclear if there is any official "ABI" promised here once
> we've compiled and validated the base device tree on its own. Will
> people assume that they can have out-of-tree overlays derived from the
> base SoC tree and that those out-of-tree overlays will continue to
> work across changes / cleanups to the base? NOTE: this is a
> pre-existing question for existing device tree overlay usage, but the
> sheer quantity of nodes/properties that a board would be expected to
> overlay/modify in the base make the problem more prominent.
>
> 4. We want the final device tree's top-level compatible to be all the
> compatible strings from the board followed by all of the compatible
> strings for the SoC. When the board's overlay is applied to the base
> SoC tree, though, the board's top-level compatible fully replaces the
> compatible from the base SoC tree. This can be solved today for
> non-socketed boards by just duplicating the SoC compatible strings in
> the board overlays. We can't solve this today for socketed boards,
> though we can simply make sure that no software drivers rely on the
> specific SoC compatible string being present and thus we can ignore
> the problem.
>
> None of the above problems are big enough to have prevented widespread
> use of this scheme in downstream Android.
>
>
> Current state of the art (upstream):
> ------------------------------------
>
> Upstream if we have a pile of related boards, we do allow
> deduplicating things at a source-code level with "dtsi" files. We can
> have a SoC "dtsi" file and that file is included by all boards that
> use that SoC. When it comes time to validate or ship things, though,
> we only work with full devices trees. This means that we ship
> duplicated information.
>
>
> Proposal:
> ---------
>
> 1. Allow the top-level compatible string of an "incomplete" device
> tree to be documented so it can be validated on its own by tools. It's
> understood that this SoC is not a board by itself and we'd never boot
> a full OS with this device tree without adding an overlay that changes
> the top-level compatible. Add a top-level property to the device tree
> (perhaps "incomplete-compatible;") to indicate that the tree is not
> complete without an overlay.

or be more description, e.g.: compatible-scope = "soc"  - or just scope = "soc"

In other words, I don't think we should be frightened to define some
levels (soc, som, carrier, exxpansion, chassis?)

>
> 2. If it turns out to be needed (hopefully it's not), allow some type
> of syntax in yaml files that allows a property to be marked as
> "required" in a "complete" device tree but not in an "incomplete"
> device tree. Alternatively, we could discourage marking properties as
> "required" if they're expected to be filled in by a board.

Another option would be to validate the soc DT with a chosen board,
just as a workaround. It would probably be good enough.

>
> 3. Define that there is no promised ABI between "incomplete" device
> trees and anything not stored with them. Specifically, all valid
> combinations of "incomplete" device trees with overlays to complete
> them should be enumerated together with the "incomplete" device tree.

This seems important, yes.

>
> 4. When applying an overlay to a device tree that's "incomplete", the
> top level overlay will be merged instead of replaced.
>
> Example for 2 levels:
>
> base (incomplete) compatible: "socvendor,mysoc-rev1", "socvendor,mysoc";
> overlay compatible: "boardvendor,myboard-rev1", "boardvendor,myboard";
> merged compatible: "boardvendor,myboard-rev1", "boardvendor,myboard",
>                    "socvendor,mysoc-rev1", "socvendor,mysoc";
>
> Possible example if we support 3 levels:
>
> SoC (incomplete) compatible: "socvendor,mysoc-rev1", "socvendor,mysoc"
> overlay1 (incomplete) compatible: "referencevendor,referencecodename";
> overlay2 compatible: "boardvendor,myboard-rev1", "boardvendor,myboard"
> merged compatible: "boardvendor,myboard-rev1", "boardvendor,myboard",
>                    "referencevendor,reference-codename",
>                    "socvendor,mysoc-rev1", "socvendor,mysoc";
>
> Obviously in the 3-level scheme we need to know the order that
> overlays are applied, but that's true for overlays today anyway.
>
> The above proposal takes the current downstream "state of the art" and
> addresses the known issues, solving the original problem statement.
>
>
> Other thoughts:
> ---------------
>
> If you don't like the proposal, I'd be interested in knowing if you
> have other ideas for solving the original problem statement, or if you
> simply think the problem we're trying to solve here is an invalid one.
>
> I'm happy to post up another revision of my Pixel 10 device trees
> following this proof of concept (or other ones). My v1 was _very_
> close to this, but didn't have the "incomplete-compatible;" property
> and didn't implement top-level compatible merging.

This proposal seems good to me.

We don't need to worry about old bootloaders since they presumably are
not installed on new hardware. Assuming Linux adopts this proposal, I
am sure people will implement it in bootloaders when they need to.

Chen-Yu, thank you for the reminder re my extensions thing for FIT. I
had forgotten about that. Here are some current proposed FIT
additions, BTW, in case anyone is interested in taking a look:

https://github.com/open-source-firmware/flat-image-tree/pulls

Regards,
Simon


>
>
> [1] https://lore.kernel.org/r/20251111112158.1.I72a0b72562b85d02fee424fed939fea9049ddda9 at changeid
> [2] https://source.android.com/docs/core/architecture/dto/partitions
>


From nicolas at ndufresne.ca  Tue Dec  2 12:21:40 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Tue, 02 Dec 2025 15:21:40 -0500
Subject: [PATCH v2 2/2] media: verisilicon: Avoid G2 bus error while
 decoding H.264 and HEVC
In-Reply-To: <64ad3d66-4edf-4a0b-8992-0db0e90a32b0@oss.nxp.com>
References: <20251128025117.535-1-ming.qian@oss.nxp.com>
	 <20251128025117.535-2-ming.qian@oss.nxp.com>
	 <46e9a5a881946d879d1b2af3421d574b26256ae3.camel@ndufresne.ca>
	 <64ad3d66-4edf-4a0b-8992-0db0e90a32b0@oss.nxp.com>
Message-ID: <570d444a92b0e49a11379cabc8f7f838e5228f7a.camel@ndufresne.ca>

Hi Ming,

Le lundi 01 d?cembre 2025 ? 09:52 +0800, Ming Qian(OSS) a ?crit?:
> > Then instead of this, I would like to add a kref to v4l2_m2m_dec, I checked
> > already and this is both safe and backward compatible.
> > 
> > Then in the get function, you will walk over the compatible that are
> > different
> > from the currently probe node. If you find one that is initialized, you will
> > call v4l2_m2m_get() to obtained a shared reference. In _remove() you will
> > simply
> > do v4l2_m2m_put() instead of v4l2_m2m_release().
> > 
> > Hope the others are happy with this. For Hantro drivers, this will make it a
> > much more powerfull mechanism.
> > 
> > Nicolas
> > 
> 
> For v4l2_m2m_get() and v4l2_m2m_put(), do you mean defining these two
> functions in v4l2 m2m, instead of just adding them in the hantro driver?

my idea was to add a kref to be able to share v4l2_m2m_dev. One thing I notice
is that its the v4l2_m2m dev that creates the media controller on all other
drivers. Note sure why Hantro does it own still, maybe it predates, maybe its
something else.

Its quite weirdly glued together, since the v4l2_m2m_release() function just
happily free the m2m_dev without even trying to cleanup the media controller. It
totally orthogonal to the job queue, maybe it shouldn't be there.

I'll make an RFC for the kref anyway, if that has a change, I'll try and split
out the v4l2_m2m_mc_dev on it own, so driver can share a m2m and use the
helpers.

Nicolas

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251202/a151fc4e/attachment.sig>

From andrew at lunn.ch  Tue Dec  2 12:31:54 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Tue, 2 Dec 2025 21:31:54 +0100
Subject: [PATCH RFC net-next 01/15] net: stmmac: rk: add GMAC_CLK_xx
 constants, simplify RGMII definitions
In-Reply-To: <E1vQ5El-0000000GNvU-2sXL@rmk-PC.armlinux.org.uk>
References: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
 <E1vQ5El-0000000GNvU-2sXL@rmk-PC.armlinux.org.uk>
Message-ID: <b732b6fd-0e69-459b-8337-ba60f5a56d47@lunn.ch>

On Mon, Dec 01, 2025 at 02:50:47PM +0000, Russell King (Oracle) wrote:
> All the definitions of the RGMII related xxx_GMAC_CLK_xxx definitions
> use the same field values to select the clock rate. Provide common
> defintions for these field values, passing them in to a single macro
> for each variant that generates the appropriate values for the speed
> register.
> 
> No change to produced code on aarch64.
> 
> Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>

Reviewed-by: Andrew Lunn <andrew at lunn.ch>

    Andrew


From Frank.li at nxp.com  Tue Dec  2 12:36:14 2025
From: Frank.li at nxp.com (Frank Li)
Date: Tue, 2 Dec 2025 15:36:14 -0500
Subject: [PATCH v4 0/5] media: imx8qxp: add parallel camera support
In-Reply-To: <aQzFiEOQvtZjHIsr@lizhi-Precision-Tower-5810>
References: <20250729-imx8qxp_pcam-v4-0-4dfca4ed2f87@nxp.com>
 <20250805010822.GC24627@pendragon.ideasonboard.com>
 <aLbcpEZXm5G1Onq7@lizhi-Precision-Tower-5810>
 <20250902123920.GM13448@pendragon.ideasonboard.com>
 <aLhJDXnz9HPGrWcp@lizhi-Precision-Tower-5810>
 <aQuDSROHLGHIhtlh@lizhi-Precision-Tower-5810>
 <20251105171928.GB6046@pendragon.ideasonboard.com>
 <aQul/VGG8e3MJxhx@lizhi-Precision-Tower-5810>
 <DE1JMG95RZME.2YSV10RI9AME4@gmail.com>
 <aQzFiEOQvtZjHIsr@lizhi-Precision-Tower-5810>
Message-ID: <aS9NvkAWTa42j7KW@lizhi-Precision-Tower-5810>

On Thu, Nov 06, 2025 at 10:58:00AM -0500, Frank Li wrote:
> On Thu, Nov 06, 2025 at 10:34:48AM +0000, Rui Miguel Silva wrote:
> > On Wed Nov 5, 2025 at 7:31 PM WET, Frank Li wrote:
> >
> > > On Wed, Nov 05, 2025 at 07:19:28PM +0200, Laurent Pinchart wrote:
> > >> Hi Frank,
> > >>
> > >> On Wed, Nov 05, 2025 at 12:03:05PM -0500, Frank Li wrote:
> > >> > On Wed, Sep 03, 2025 at 09:56:29AM -0400, Frank Li wrote:
> > >> > > On Tue, Sep 02, 2025 at 02:39:20PM +0200, Laurent Pinchart wrote:
> > >> > > > On Tue, Sep 02, 2025 at 08:01:40AM -0400, Frank Li wrote:
> > >> > > > > On Tue, Aug 05, 2025 at 04:08:22AM +0300, Laurent Pinchart wrote:
> > >> > > > > > Hi Frank,
> > >> > > > > >
> > >> > > > > > Thank you for the patches.
> > >> > > > > >
> > >> > > > > > I've quite busy these days, and I don't believe I will have time to
> > >> > > > > > review this series before coming back from OSS Europe at the beginning
> > >> > > > > > of September. Let's see if anyone on CC could volunteer.
> > >> > > > >
> > >> > > > > Laurent Pincha
> > >> > > > > 	I hope you have good time at OSS.
> > >> > > > >
> > >> > > > > 	Do you have chance to review this patch?
> > >> > > >
> > >> > > > I'm going through my mail backlog, which is really big at the moment.
> > >> > >
> > >> > > Understand.
> > >> > >
> > >> > > > I'd like someone else to volunteer to review this series. It won't scale
> > >> > > > if I have to review all NXP media patches in my spare time :-/
> > >> > >
> > >> > > Yes, but none volunteer review this in passed months. Expecially key
> > >> > > reviewer. I am reviewing i3c patches. but Not familiar v4l system yet. It
> > >> > > need scalable solution. I can help filter some common and simple problem
> > >> > > from beginning.
> > >> >
> > >> > Laurent Pinchart:
> > >> >
> > >> > 	Do you have chance to check this serise? this one should be related simple.
> > >> > 	This one sent at 7/29. Still not any volunteer to review it.
> > >>
> > >> I'm afraid I won't have time to review this for the time being. My spare
> > >> time is already exhausted by all the other drivers I maintain upstream.
> > >>
> > >> > 	How do we move forward?
> > >>
> > >> I think this is a question for the subsystem maintainers. Hans, Mauro ?
> > >
> > > Mauro Carvalho Chehab and Hans Verkuil:
> > >
> > > 	Laurent provided great help about review and land i.MX related
> > > patches in past, who are quite famillar with i.MX chips. But he is quite
> > > busy. So the whole reviews cycles takes quite long time and offten cross
> > > some merge windows.
> > >
> > > 	In pull requests for 6.19:
> > > https://lore.kernel.org/all/4989c563-47f4-478c-80c4-41f7e98597e4 at kernel.org/
> > > only 10 patches, and 4 patches is trivial clean up.
> > >
> > > 	In reviewing patch queue, there are
> > > 	1: media: nxp: imx8-isi: Add ISI support for i.MX95
> > > 	   https://lore.kernel.org/imx/20251105-isi_imx95-v3-0-3987533cca1c at nxp.com/T/#t
> > > 	   This one already review, but I am not sure if it capture 6.19 cycle because
> > > PULL-request already sent.
> > >
> > > 	2: Add MIPI CSI-2 support for i.MX8ULP
> > > 	   https://lore.kernel.org/imx/20251023-csi2_imx8ulp-v7-0-5ecb081ce79b at nxp.com/
> > >
> > > 	3: media: add imx93 mipi/controller csi support
> > > 	   https://lore.kernel.org/imx/20250821-95_cam-v3-0-c9286fbb34b9 at nxp.com/
> > > 	   This one is quite big, but first 10 patches is simple trivial cleanup patches.
> > > 	   I post at 8/27, but get first feedback around 10/27, I am not
> > > 	   sure if missing somethings.
> > >
> > > 	4: This series, laurent already said no time review it.
> > >
> > > 	5: ap1302 sensor patches
> > >            https://lore.kernel.org/imx/20250811-ap1302-v4-0-80cc41b91662 at nxp.com/
> > >            binding already ACK, most maintainer want to pick binding with
> > > 	   driver together, but not an feedback since 8/11.
> > >
> > > 	I jump into and help do some review.
> > >
> > > 	The questions is how to move forward pending patches, like [3], [4],
> > > [5]. How to keep good community channel to avoid long time pending?
> >
> > Sorry, but like Laurent I am really without spare cycles to go over the
> > patch series that have arrived in media (also I do not have any hw anymore).
> > So, Frank or maybe Laurent knows someone that would like to be add also as
> > maintainer of this drivers for me would be great, that would also help to
> > avoid such bottlenecks.
>
> If there are not other candidate, I can help maintain it although I am more
> familar with dt binding, i3c and dmaengine. I can start from simple patches
> and we have test team to help cover testing on the real hardware.

Rui:
	Any update? How to move forward? It was already passed more than 3
month!

Frank

>
> Frank
> >
> > Thanks in advance,
> > Cheers,
> >     Rui
> > >
> > > Best regards
> > > Frank Li


From linux at armlinux.org.uk  Tue Dec  2 12:41:09 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Tue, 2 Dec 2025 20:41:09 +0000
Subject: [PATCH RFC net-next 04/15] net: stmmac: rk: convert to
 mask-based interface mode configuration
In-Reply-To: <E1vQ5F1-0000000GNvm-0EON@rmk-PC.armlinux.org.uk>
References: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
 <E1vQ5F1-0000000GNvm-0EON@rmk-PC.armlinux.org.uk>
Message-ID: <aS9O5XqDQ_gyZSuN@shell.armlinux.org.uk>

Just FYI,

I suggest not reviewing past this patch as I've been doing some reorg
to the patch set since posting... the basic idea remains, but stuff
is getting some renaming, and the "speed" register bitfields are moving
to their own struct.

Thanks.

On Mon, Dec 01, 2025 at 02:51:03PM +0000, Russell King (Oracle) wrote:
> Most of the Rockchip implementations use the phy_intf_sel values for
> interface mode configuration, but the register and field within that
> register vary between each SoC. They also have a RMII mode bit, which
> is in the same register but a different bit position.
> 
> Rather than having each and every Rockchip implementation cope with
> this using code, add struct members to specify the regmap register
> offset, and the bitfield masks for these two parameters.
> 
> Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
> ---
>  .../net/ethernet/stmicro/stmmac/dwmac-rk.c    | 281 +++++++++++-------
>  1 file changed, 171 insertions(+), 110 deletions(-)
> 
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
> index e9f531d6c22a..369792b62c5e 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
> @@ -45,6 +45,11 @@ struct rk_gmac_ops {
>  				    bool enable);
>  	void (*integrated_phy_powerup)(struct rk_priv_data *bsp_priv);
>  	void (*integrated_phy_powerdown)(struct rk_priv_data *bsp_priv);
> +
> +	u16 phy_intf_sel_grf_reg;
> +	u16 phy_intf_sel_mask;
> +	u16 rmii_mode_mask;
> +
>  	bool php_grf_required;
>  	bool regs_valid;
>  	u32 regs[];
> @@ -90,12 +95,37 @@ struct rk_priv_data {
>  
>  	struct regmap *grf;
>  	struct regmap *php_grf;
> +
> +	u16 phy_intf_sel_grf_reg;
> +	u16 phy_intf_sel_mask;
> +	u16 rmii_mode_mask;
>  };
>  
>  #define GMAC_CLK_DIV1_125M		0
>  #define GMAC_CLK_DIV50_2_5M		2
>  #define GMAC_CLK_DIV5_25M		3
>  
> +static int rk_get_phy_intf_sel(phy_interface_t interface)
> +{
> +	int ret = stmmac_get_phy_intf_sel(interface);
> +
> +	/* Only RGMII and RMII are supported */
> +	if (ret != PHY_INTF_SEL_RGMII && ret != PHY_INTF_SEL_RMII)
> +		ret = -EINVAL;
> +
> +	return ret;
> +}
> +
> +static u32 rk_encode_wm16(u16 val, u16 mask)
> +{
> +	u32 reg_val = mask << 16;
> +
> +	if (mask)
> +		reg_val |= mask & (val << (ffs(mask) - 1));
> +
> +	return reg_val;
> +}
> +
>  static int rk_set_reg_speed(struct rk_priv_data *bsp_priv,
>  			    const struct rk_reg_speed_data *rsd,
>  			    unsigned int reg, phy_interface_t interface,
> @@ -239,14 +269,11 @@ static void rk_gmac_integrated_fephy_powerdown(struct rk_priv_data *priv,
>  #define PX30_GRF_GMAC_CON1		0x0904
>  
>  /* PX30_GRF_GMAC_CON1 */
> -#define PX30_GMAC_PHY_INTF_SEL(val)	GRF_FIELD(6, 4, val)
>  #define PX30_GMAC_SPEED_10M		GRF_CLR_BIT(2)
>  #define PX30_GMAC_SPEED_100M		GRF_BIT(2)
>  
>  static void px30_set_to_rmii(struct rk_priv_data *bsp_priv)
>  {
> -	regmap_write(bsp_priv->grf, PX30_GRF_GMAC_CON1,
> -		     PX30_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII));
>  }
>  
>  static int px30_set_speed(struct rk_priv_data *bsp_priv,
> @@ -281,6 +308,9 @@ static int px30_set_speed(struct rk_priv_data *bsp_priv,
>  static const struct rk_gmac_ops px30_ops = {
>  	.set_to_rmii = px30_set_to_rmii,
>  	.set_speed = px30_set_speed,
> +
> +	.phy_intf_sel_grf_reg = PX30_GRF_GMAC_CON1,
> +	.phy_intf_sel_mask = GENMASK_U16(6, 4),
>  };
>  
>  #define RK3128_GRF_MAC_CON0	0x0168
> @@ -295,7 +325,6 @@ static const struct rk_gmac_ops px30_ops = {
>  #define RK3128_GMAC_CLK_TX_DL_CFG(val) GRF_FIELD(6, 0, val)
>  
>  /* RK3128_GRF_MAC_CON1 */
> -#define RK3128_GMAC_PHY_INTF_SEL(val)  GRF_FIELD(8, 6, val)
>  #define RK3128_GMAC_FLOW_CTRL          GRF_BIT(9)
>  #define RK3128_GMAC_FLOW_CTRL_CLR      GRF_CLR_BIT(9)
>  #define RK3128_GMAC_SPEED_10M          GRF_CLR_BIT(10)
> @@ -303,15 +332,10 @@ static const struct rk_gmac_ops px30_ops = {
>  #define RK3128_GMAC_RMII_CLK_25M       GRF_BIT(11)
>  #define RK3128_GMAC_RMII_CLK_2_5M      GRF_CLR_BIT(11)
>  #define RK3128_GMAC_CLK(val)           GRF_FIELD_CONST(13, 12, val)
> -#define RK3128_GMAC_RMII_MODE          GRF_BIT(14)
> -#define RK3128_GMAC_RMII_MODE_CLR      GRF_CLR_BIT(14)
>  
>  static void rk3128_set_to_rgmii(struct rk_priv_data *bsp_priv,
>  				int tx_delay, int rx_delay)
>  {
> -	regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON1,
> -		     RK3128_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) |
> -		     RK3128_GMAC_RMII_MODE_CLR);
>  	regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON0,
>  		     DELAY_ENABLE(RK3128, tx_delay, rx_delay) |
>  		     RK3128_GMAC_CLK_RX_DL_CFG(rx_delay) |
> @@ -320,9 +344,6 @@ static void rk3128_set_to_rgmii(struct rk_priv_data *bsp_priv,
>  
>  static void rk3128_set_to_rmii(struct rk_priv_data *bsp_priv)
>  {
> -	regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON1,
> -		     RK3128_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII) |
> -		     RK3128_GMAC_RMII_MODE);
>  }
>  
>  static const struct rk_reg_speed_data rk3128_reg_speed_data = {
> @@ -344,6 +365,10 @@ static const struct rk_gmac_ops rk3128_ops = {
>  	.set_to_rgmii = rk3128_set_to_rgmii,
>  	.set_to_rmii = rk3128_set_to_rmii,
>  	.set_speed = rk3128_set_speed,
> +
> +	.phy_intf_sel_grf_reg = RK3128_GRF_MAC_CON1,
> +	.phy_intf_sel_mask = GENMASK_U16(8, 6),
> +	.rmii_mode_mask = BIT_U16(14),
>  };
>  
>  #define RK3228_GRF_MAC_CON0	0x0900
> @@ -356,7 +381,6 @@ static const struct rk_gmac_ops rk3128_ops = {
>  #define RK3228_GMAC_CLK_TX_DL_CFG(val)	GRF_FIELD(6, 0, val)
>  
>  /* RK3228_GRF_MAC_CON1 */
> -#define RK3228_GMAC_PHY_INTF_SEL(val)	GRF_FIELD(6, 4, val)
>  #define RK3228_GMAC_FLOW_CTRL		GRF_BIT(3)
>  #define RK3228_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(3)
>  #define RK3228_GMAC_SPEED_10M		GRF_CLR_BIT(2)
> @@ -364,8 +388,6 @@ static const struct rk_gmac_ops rk3128_ops = {
>  #define RK3228_GMAC_RMII_CLK_25M	GRF_BIT(7)
>  #define RK3228_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(7)
>  #define RK3228_GMAC_CLK(val)		GRF_FIELD_CONST(9, 8, val)
> -#define RK3228_GMAC_RMII_MODE		GRF_BIT(10)
> -#define RK3228_GMAC_RMII_MODE_CLR	GRF_CLR_BIT(10)
>  #define RK3228_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(0)
>  #define RK3228_GMAC_TXCLK_DLY_DISABLE	GRF_CLR_BIT(0)
>  #define RK3228_GMAC_RXCLK_DLY_ENABLE	GRF_BIT(1)
> @@ -378,8 +400,6 @@ static void rk3228_set_to_rgmii(struct rk_priv_data *bsp_priv,
>  				int tx_delay, int rx_delay)
>  {
>  	regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1,
> -		     RK3228_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) |
> -		     RK3228_GMAC_RMII_MODE_CLR |
>  		     DELAY_ENABLE(RK3228, tx_delay, rx_delay));
>  
>  	regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON0,
> @@ -389,10 +409,6 @@ static void rk3228_set_to_rgmii(struct rk_priv_data *bsp_priv,
>  
>  static void rk3228_set_to_rmii(struct rk_priv_data *bsp_priv)
>  {
> -	regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1,
> -		     RK3228_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII) |
> -		     RK3228_GMAC_RMII_MODE);
> -
>  	/* set MAC to RMII mode */
>  	regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1, GRF_BIT(11));
>  }
> @@ -426,13 +442,17 @@ static const struct rk_gmac_ops rk3228_ops = {
>  	.set_speed = rk3228_set_speed,
>  	.integrated_phy_powerup = rk3228_integrated_phy_powerup,
>  	.integrated_phy_powerdown = rk_gmac_integrated_ephy_powerdown,
> +
> +	.phy_intf_sel_grf_reg = RK3228_GRF_MAC_CON1,
> +	.phy_intf_sel_mask = GENMASK_U16(6, 4),
> +	.rmii_mode_mask = BIT_U16(10),
> +
>  };
>  
>  #define RK3288_GRF_SOC_CON1	0x0248
>  #define RK3288_GRF_SOC_CON3	0x0250
>  
>  /*RK3288_GRF_SOC_CON1*/
> -#define RK3288_GMAC_PHY_INTF_SEL(val)	GRF_FIELD(8, 6, val)
>  #define RK3288_GMAC_FLOW_CTRL		GRF_BIT(9)
>  #define RK3288_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(9)
>  #define RK3288_GMAC_SPEED_10M		GRF_CLR_BIT(10)
> @@ -440,8 +460,6 @@ static const struct rk_gmac_ops rk3228_ops = {
>  #define RK3288_GMAC_RMII_CLK_25M	GRF_BIT(11)
>  #define RK3288_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(11)
>  #define RK3288_GMAC_CLK(val)		GRF_FIELD_CONST(13, 12, val)
> -#define RK3288_GMAC_RMII_MODE		GRF_BIT(14)
> -#define RK3288_GMAC_RMII_MODE_CLR	GRF_CLR_BIT(14)
>  
>  /*RK3288_GRF_SOC_CON3*/
>  #define RK3288_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(14)
> @@ -454,9 +472,6 @@ static const struct rk_gmac_ops rk3228_ops = {
>  static void rk3288_set_to_rgmii(struct rk_priv_data *bsp_priv,
>  				int tx_delay, int rx_delay)
>  {
> -	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
> -		     RK3288_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) |
> -		     RK3288_GMAC_RMII_MODE_CLR);
>  	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3,
>  		     DELAY_ENABLE(RK3288, tx_delay, rx_delay) |
>  		     RK3288_GMAC_CLK_RX_DL_CFG(rx_delay) |
> @@ -465,9 +480,6 @@ static void rk3288_set_to_rgmii(struct rk_priv_data *bsp_priv,
>  
>  static void rk3288_set_to_rmii(struct rk_priv_data *bsp_priv)
>  {
> -	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
> -		     RK3288_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII) |
> -		     RK3288_GMAC_RMII_MODE);
>  }
>  
>  static const struct rk_reg_speed_data rk3288_reg_speed_data = {
> @@ -489,12 +501,15 @@ static const struct rk_gmac_ops rk3288_ops = {
>  	.set_to_rgmii = rk3288_set_to_rgmii,
>  	.set_to_rmii = rk3288_set_to_rmii,
>  	.set_speed = rk3288_set_speed,
> +
> +	.phy_intf_sel_grf_reg = RK3288_GRF_SOC_CON1,
> +	.phy_intf_sel_mask = GENMASK_U16(8, 6),
> +	.rmii_mode_mask = BIT_U16(14),
>  };
>  
>  #define RK3308_GRF_MAC_CON0		0x04a0
>  
>  /* RK3308_GRF_MAC_CON0 */
> -#define RK3308_GMAC_PHY_INTF_SEL(val)	GRF_FIELD(4, 2, val)
>  #define RK3308_GMAC_FLOW_CTRL		GRF_BIT(3)
>  #define RK3308_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(3)
>  #define RK3308_GMAC_SPEED_10M		GRF_CLR_BIT(0)
> @@ -502,8 +517,6 @@ static const struct rk_gmac_ops rk3288_ops = {
>  
>  static void rk3308_set_to_rmii(struct rk_priv_data *bsp_priv)
>  {
> -	regmap_write(bsp_priv->grf, RK3308_GRF_MAC_CON0,
> -		     RK3308_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII));
>  }
>  
>  static const struct rk_reg_speed_data rk3308_reg_speed_data = {
> @@ -521,6 +534,9 @@ static int rk3308_set_speed(struct rk_priv_data *bsp_priv,
>  static const struct rk_gmac_ops rk3308_ops = {
>  	.set_to_rmii = rk3308_set_to_rmii,
>  	.set_speed = rk3308_set_speed,
> +
> +	.phy_intf_sel_grf_reg = RK3308_GRF_MAC_CON0,
> +	.phy_intf_sel_mask = GENMASK_U16(4, 2),
>  };
>  
>  #define RK3328_GRF_MAC_CON0	0x0900
> @@ -533,7 +549,6 @@ static const struct rk_gmac_ops rk3308_ops = {
>  #define RK3328_GMAC_CLK_TX_DL_CFG(val)	GRF_FIELD(6, 0, val)
>  
>  /* RK3328_GRF_MAC_CON1 */
> -#define RK3328_GMAC_PHY_INTF_SEL(val)	GRF_FIELD(6, 4, val)
>  #define RK3328_GMAC_FLOW_CTRL		GRF_BIT(3)
>  #define RK3328_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(3)
>  #define RK3328_GMAC_SPEED_10M		GRF_CLR_BIT(2)
> @@ -541,20 +556,32 @@ static const struct rk_gmac_ops rk3308_ops = {
>  #define RK3328_GMAC_RMII_CLK_25M	GRF_BIT(7)
>  #define RK3328_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(7)
>  #define RK3328_GMAC_CLK(val)		GRF_FIELD_CONST(12, 11, val)
> -#define RK3328_GMAC_RMII_MODE		GRF_BIT(9)
> -#define RK3328_GMAC_RMII_MODE_CLR	GRF_CLR_BIT(9)
>  #define RK3328_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(0)
>  #define RK3328_GMAC_RXCLK_DLY_ENABLE	GRF_BIT(1)
>  
>  /* RK3328_GRF_MACPHY_CON1 */
>  #define RK3328_MACPHY_RMII_MODE		GRF_BIT(9)
>  
> +static int rk3328_init(struct rk_priv_data *bsp_priv)
> +{
> +	switch (bsp_priv->id) {
> +	case 0: /* gmac2io */
> +		bsp_priv->phy_intf_sel_grf_reg = RK3328_GRF_MAC_CON1;
> +		return 0;
> +
> +	case 1: /* gmac2phy */
> +		bsp_priv->phy_intf_sel_grf_reg = RK3328_GRF_MAC_CON2;
> +		return 0;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
>  static void rk3328_set_to_rgmii(struct rk_priv_data *bsp_priv,
>  				int tx_delay, int rx_delay)
>  {
>  	regmap_write(bsp_priv->grf, RK3328_GRF_MAC_CON1,
> -		     RK3328_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) |
> -		     RK3328_GMAC_RMII_MODE_CLR |
>  		     RK3328_GMAC_RXCLK_DLY_ENABLE |
>  		     RK3328_GMAC_TXCLK_DLY_ENABLE);
>  
> @@ -565,13 +592,6 @@ static void rk3328_set_to_rgmii(struct rk_priv_data *bsp_priv,
>  
>  static void rk3328_set_to_rmii(struct rk_priv_data *bsp_priv)
>  {
> -	unsigned int reg;
> -
> -	reg = bsp_priv->id ? RK3328_GRF_MAC_CON2 : RK3328_GRF_MAC_CON1;
> -
> -	regmap_write(bsp_priv->grf, reg,
> -		     RK3328_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII) |
> -		     RK3328_GMAC_RMII_MODE);
>  }
>  
>  static const struct rk_reg_speed_data rk3328_reg_speed_data = {
> @@ -602,12 +622,16 @@ static void rk3328_integrated_phy_powerup(struct rk_priv_data *priv)
>  }
>  
>  static const struct rk_gmac_ops rk3328_ops = {
> +	.init = rk3328_init,
>  	.set_to_rgmii = rk3328_set_to_rgmii,
>  	.set_to_rmii = rk3328_set_to_rmii,
>  	.set_speed = rk3328_set_speed,
>  	.integrated_phy_powerup = rk3328_integrated_phy_powerup,
>  	.integrated_phy_powerdown = rk_gmac_integrated_ephy_powerdown,
>  
> +	.phy_intf_sel_mask = GENMASK_U16(6, 4),
> +	.rmii_mode_mask = BIT_U16(9),
> +
>  	.regs_valid = true,
>  	.regs = {
>  		0xff540000, /* gmac2io */
> @@ -620,7 +644,6 @@ static const struct rk_gmac_ops rk3328_ops = {
>  #define RK3366_GRF_SOC_CON7	0x041c
>  
>  /* RK3366_GRF_SOC_CON6 */
> -#define RK3366_GMAC_PHY_INTF_SEL(val)	GRF_FIELD(11, 9, val)
>  #define RK3366_GMAC_FLOW_CTRL		GRF_BIT(8)
>  #define RK3366_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(8)
>  #define RK3366_GMAC_SPEED_10M		GRF_CLR_BIT(7)
> @@ -628,8 +651,6 @@ static const struct rk_gmac_ops rk3328_ops = {
>  #define RK3366_GMAC_RMII_CLK_25M	GRF_BIT(3)
>  #define RK3366_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(3)
>  #define RK3366_GMAC_CLK(val)		GRF_FIELD_CONST(5, 4, val)
> -#define RK3366_GMAC_RMII_MODE		GRF_BIT(6)
> -#define RK3366_GMAC_RMII_MODE_CLR	GRF_CLR_BIT(6)
>  
>  /* RK3366_GRF_SOC_CON7 */
>  #define RK3366_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(7)
> @@ -642,9 +663,6 @@ static const struct rk_gmac_ops rk3328_ops = {
>  static void rk3366_set_to_rgmii(struct rk_priv_data *bsp_priv,
>  				int tx_delay, int rx_delay)
>  {
> -	regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON6,
> -		     RK3366_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) |
> -		     RK3366_GMAC_RMII_MODE_CLR);
>  	regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON7,
>  		     DELAY_ENABLE(RK3366, tx_delay, rx_delay) |
>  		     RK3366_GMAC_CLK_RX_DL_CFG(rx_delay) |
> @@ -653,9 +671,6 @@ static void rk3366_set_to_rgmii(struct rk_priv_data *bsp_priv,
>  
>  static void rk3366_set_to_rmii(struct rk_priv_data *bsp_priv)
>  {
> -	regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON6,
> -		     RK3366_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII) |
> -		     RK3366_GMAC_RMII_MODE);
>  }
>  
>  static const struct rk_reg_speed_data rk3366_reg_speed_data = {
> @@ -677,13 +692,16 @@ static const struct rk_gmac_ops rk3366_ops = {
>  	.set_to_rgmii = rk3366_set_to_rgmii,
>  	.set_to_rmii = rk3366_set_to_rmii,
>  	.set_speed = rk3366_set_speed,
> +
> +	.phy_intf_sel_grf_reg = RK3366_GRF_SOC_CON6,
> +	.phy_intf_sel_mask = GENMASK_U16(11, 9),
> +	.rmii_mode_mask = BIT_U16(6),
>  };
>  
>  #define RK3368_GRF_SOC_CON15	0x043c
>  #define RK3368_GRF_SOC_CON16	0x0440
>  
>  /* RK3368_GRF_SOC_CON15 */
> -#define RK3368_GMAC_PHY_INTF_SEL(val)	GRF_FIELD(11, 9, val)
>  #define RK3368_GMAC_FLOW_CTRL		GRF_BIT(8)
>  #define RK3368_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(8)
>  #define RK3368_GMAC_SPEED_10M		GRF_CLR_BIT(7)
> @@ -691,8 +709,6 @@ static const struct rk_gmac_ops rk3366_ops = {
>  #define RK3368_GMAC_RMII_CLK_25M	GRF_BIT(3)
>  #define RK3368_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(3)
>  #define RK3368_GMAC_CLK(val)		GRF_FIELD_CONST(5, 4, val)
> -#define RK3368_GMAC_RMII_MODE		GRF_BIT(6)
> -#define RK3368_GMAC_RMII_MODE_CLR	GRF_CLR_BIT(6)
>  
>  /* RK3368_GRF_SOC_CON16 */
>  #define RK3368_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(7)
> @@ -705,9 +721,6 @@ static const struct rk_gmac_ops rk3366_ops = {
>  static void rk3368_set_to_rgmii(struct rk_priv_data *bsp_priv,
>  				int tx_delay, int rx_delay)
>  {
> -	regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
> -		     RK3368_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) |
> -		     RK3368_GMAC_RMII_MODE_CLR);
>  	regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON16,
>  		     DELAY_ENABLE(RK3368, tx_delay, rx_delay) |
>  		     RK3368_GMAC_CLK_RX_DL_CFG(rx_delay) |
> @@ -716,9 +729,6 @@ static void rk3368_set_to_rgmii(struct rk_priv_data *bsp_priv,
>  
>  static void rk3368_set_to_rmii(struct rk_priv_data *bsp_priv)
>  {
> -	regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
> -		     RK3368_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII) |
> -		     RK3368_GMAC_RMII_MODE);
>  }
>  
>  static const struct rk_reg_speed_data rk3368_reg_speed_data = {
> @@ -740,13 +750,16 @@ static const struct rk_gmac_ops rk3368_ops = {
>  	.set_to_rgmii = rk3368_set_to_rgmii,
>  	.set_to_rmii = rk3368_set_to_rmii,
>  	.set_speed = rk3368_set_speed,
> +
> +	.phy_intf_sel_grf_reg = RK3368_GRF_SOC_CON15,
> +	.phy_intf_sel_mask = GENMASK_U16(11, 9),
> +	.rmii_mode_mask = BIT_U16(6),
>  };
>  
>  #define RK3399_GRF_SOC_CON5	0xc214
>  #define RK3399_GRF_SOC_CON6	0xc218
>  
>  /* RK3399_GRF_SOC_CON5 */
> -#define RK3399_GMAC_PHY_INTF_SEL(val)	GRF_FIELD(11, 9, val)
>  #define RK3399_GMAC_FLOW_CTRL		GRF_BIT(8)
>  #define RK3399_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(8)
>  #define RK3399_GMAC_SPEED_10M		GRF_CLR_BIT(7)
> @@ -754,8 +767,6 @@ static const struct rk_gmac_ops rk3368_ops = {
>  #define RK3399_GMAC_RMII_CLK_25M	GRF_BIT(3)
>  #define RK3399_GMAC_RMII_CLK_2_5M	GRF_CLR_BIT(3)
>  #define RK3399_GMAC_CLK(val)		GRF_FIELD_CONST(5, 4, val)
> -#define RK3399_GMAC_RMII_MODE		GRF_BIT(6)
> -#define RK3399_GMAC_RMII_MODE_CLR	GRF_CLR_BIT(6)
>  
>  /* RK3399_GRF_SOC_CON6 */
>  #define RK3399_GMAC_TXCLK_DLY_ENABLE	GRF_BIT(7)
> @@ -768,9 +779,6 @@ static const struct rk_gmac_ops rk3368_ops = {
>  static void rk3399_set_to_rgmii(struct rk_priv_data *bsp_priv,
>  				int tx_delay, int rx_delay)
>  {
> -	regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON5,
> -		     RK3399_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) |
> -		     RK3399_GMAC_RMII_MODE_CLR);
>  	regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON6,
>  		     DELAY_ENABLE(RK3399, tx_delay, rx_delay) |
>  		     RK3399_GMAC_CLK_RX_DL_CFG(rx_delay) |
> @@ -779,9 +787,6 @@ static void rk3399_set_to_rgmii(struct rk_priv_data *bsp_priv,
>  
>  static void rk3399_set_to_rmii(struct rk_priv_data *bsp_priv)
>  {
> -	regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON5,
> -		     RK3399_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII) |
> -		     RK3399_GMAC_RMII_MODE);
>  }
>  
>  static const struct rk_reg_speed_data rk3399_reg_speed_data = {
> @@ -803,6 +808,10 @@ static const struct rk_gmac_ops rk3399_ops = {
>  	.set_to_rgmii = rk3399_set_to_rgmii,
>  	.set_to_rmii = rk3399_set_to_rmii,
>  	.set_speed = rk3399_set_speed,
> +
> +	.phy_intf_sel_grf_reg = RK3399_GRF_SOC_CON5,
> +	.phy_intf_sel_mask = GENMASK_U16(11, 9),
> +	.rmii_mode_mask = BIT_U16(6),
>  };
>  
>  #define RK3506_GRF_SOC_CON8		0x0020
> @@ -1005,7 +1014,6 @@ static const struct rk_gmac_ops rk3528_ops = {
>  #define RK3568_GRF_GMAC1_CON1		0x038c
>  
>  /* RK3568_GRF_GMAC0_CON1 && RK3568_GRF_GMAC1_CON1 */
> -#define RK3568_GMAC_PHY_INTF_SEL(val)	GRF_FIELD(6, 4, val)
>  #define RK3568_GMAC_FLOW_CTRL			GRF_BIT(3)
>  #define RK3568_GMAC_FLOW_CTRL_CLR		GRF_CLR_BIT(3)
>  #define RK3568_GMAC_RXCLK_DLY_ENABLE		GRF_BIT(1)
> @@ -1017,6 +1025,22 @@ static const struct rk_gmac_ops rk3528_ops = {
>  #define RK3568_GMAC_CLK_RX_DL_CFG(val)	GRF_FIELD(14, 8, val)
>  #define RK3568_GMAC_CLK_TX_DL_CFG(val)	GRF_FIELD(6, 0, val)
>  
> +static int rk3568_init(struct rk_priv_data *bsp_priv)
> +{
> +	switch (bsp_priv->id) {
> +	case 0:
> +		bsp_priv->phy_intf_sel_grf_reg = RK3568_GRF_GMAC0_CON1;
> +		return 0;
> +
> +	case 1:
> +		bsp_priv->phy_intf_sel_grf_reg = RK3568_GRF_GMAC1_CON1;
> +		return 0;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
>  static void rk3568_set_to_rgmii(struct rk_priv_data *bsp_priv,
>  				int tx_delay, int rx_delay)
>  {
> @@ -1032,25 +1056,22 @@ static void rk3568_set_to_rgmii(struct rk_priv_data *bsp_priv,
>  		     RK3568_GMAC_CLK_TX_DL_CFG(tx_delay));
>  
>  	regmap_write(bsp_priv->grf, con1,
> -		     RK3568_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) |
>  		     RK3568_GMAC_RXCLK_DLY_ENABLE |
>  		     RK3568_GMAC_TXCLK_DLY_ENABLE);
>  }
>  
>  static void rk3568_set_to_rmii(struct rk_priv_data *bsp_priv)
>  {
> -	u32 con1;
> -
> -	con1 = (bsp_priv->id == 1) ? RK3568_GRF_GMAC1_CON1 :
> -				     RK3568_GRF_GMAC0_CON1;
> -	regmap_write(bsp_priv->grf, con1,
> -		     RK3568_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII));
>  }
>  
>  static const struct rk_gmac_ops rk3568_ops = {
> +	.init = rk3568_init,
>  	.set_to_rgmii = rk3568_set_to_rgmii,
>  	.set_to_rmii = rk3568_set_to_rmii,
>  	.set_speed = rk_set_clk_mac_speed,
> +
> +	.phy_intf_sel_mask = GENMASK_U16(6, 4),
> +
>  	.regs_valid = true,
>  	.regs = {
>  		0xfe2a0000, /* gmac0 */
> @@ -1077,9 +1098,6 @@ static const struct rk_gmac_ops rk3568_ops = {
>  #define RK3576_GRF_GMAC_CON0			0X0020
>  #define RK3576_GRF_GMAC_CON1			0X0024
>  
> -#define RK3576_GMAC_RMII_MODE			GRF_BIT(3)
> -#define RK3576_GMAC_RGMII_MODE			GRF_CLR_BIT(3)
> -
>  #define RK3576_GMAC_CLK_SELECT_IO		GRF_BIT(7)
>  #define RK3576_GMAC_CLK_SELECT_CRU		GRF_CLR_BIT(7)
>  
> @@ -1091,16 +1109,27 @@ static const struct rk_gmac_ops rk3568_ops = {
>  #define RK3576_GMAC_CLK_RMII_GATE		GRF_BIT(4)
>  #define RK3576_GMAC_CLK_RMII_NOGATE		GRF_CLR_BIT(4)
>  
> +static int rk3576_init(struct rk_priv_data *bsp_priv)
> +{
> +	switch (bsp_priv->id) {
> +	case 0:
> +		bsp_priv->phy_intf_sel_grf_reg = RK3576_GRF_GMAC_CON0;
> +		return 0;
> +
> +	case 1:
> +		bsp_priv->phy_intf_sel_grf_reg = RK3576_GRF_GMAC_CON1;
> +		return 0;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
>  static void rk3576_set_to_rgmii(struct rk_priv_data *bsp_priv,
>  				int tx_delay, int rx_delay)
>  {
>  	unsigned int offset_con;
>  
> -	offset_con = bsp_priv->id == 1 ? RK3576_GRF_GMAC_CON1 :
> -					 RK3576_GRF_GMAC_CON0;
> -
> -	regmap_write(bsp_priv->grf, offset_con, RK3576_GMAC_RGMII_MODE);
> -
>  	offset_con = bsp_priv->id == 1 ? RK3576_VCCIO0_1_3_IOC_CON4 :
>  					 RK3576_VCCIO0_1_3_IOC_CON2;
>  
> @@ -1121,12 +1150,6 @@ static void rk3576_set_to_rgmii(struct rk_priv_data *bsp_priv,
>  
>  static void rk3576_set_to_rmii(struct rk_priv_data *bsp_priv)
>  {
> -	unsigned int offset_con;
> -
> -	offset_con = bsp_priv->id == 1 ? RK3576_GRF_GMAC_CON1 :
> -					 RK3576_GRF_GMAC_CON0;
> -
> -	regmap_write(bsp_priv->grf, offset_con, RK3576_GMAC_RMII_MODE);
>  }
>  
>  static const struct rk_reg_speed_data rk3578_reg_speed_data = {
> @@ -1166,10 +1189,14 @@ static void rk3576_set_clock_selection(struct rk_priv_data *bsp_priv, bool input
>  }
>  
>  static const struct rk_gmac_ops rk3576_ops = {
> +	.init = rk3576_init,
>  	.set_to_rgmii = rk3576_set_to_rgmii,
>  	.set_to_rmii = rk3576_set_to_rmii,
>  	.set_speed = rk3576_set_gmac_speed,
>  	.set_clock_selection = rk3576_set_clock_selection,
> +
> +	.rmii_mode_mask = BIT_U16(3),
> +
>  	.php_grf_required = true,
>  	.regs_valid = true,
>  	.regs = {
> @@ -1196,9 +1223,6 @@ static const struct rk_gmac_ops rk3576_ops = {
>  #define RK3588_GRF_GMAC_CON0			0X0008
>  #define RK3588_GRF_CLK_CON1			0X0070
>  
> -#define RK3588_GMAC_PHY_INTF_SEL(id, val)	\
> -	(GRF_FIELD(5, 3, val) << ((id) * 6))
> -
>  #define RK3588_GMAC_CLK_RMII_MODE(id)		GRF_BIT(5 * (id))
>  #define RK3588_GMAC_CLK_RGMII_MODE(id)		GRF_CLR_BIT(5 * (id))
>  
> @@ -1214,6 +1238,22 @@ static const struct rk_gmac_ops rk3576_ops = {
>  #define RK3588_GMAC_CLK_RMII_GATE(id)		GRF_BIT(5 * (id) + 1)
>  #define RK3588_GMAC_CLK_RMII_NOGATE(id)		GRF_CLR_BIT(5 * (id) + 1)
>  
> +static int rk3588_init(struct rk_priv_data *bsp_priv)
> +{
> +	switch (bsp_priv->id) {
> +	case 0:
> +		bsp_priv->phy_intf_sel_mask = GENMASK_U16(5, 3);
> +		return 0;
> +
> +	case 1:
> +		bsp_priv->phy_intf_sel_mask = GENMASK_U16(11, 9);
> +		return 0;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
>  static void rk3588_set_to_rgmii(struct rk_priv_data *bsp_priv,
>  				int tx_delay, int rx_delay)
>  {
> @@ -1222,9 +1262,6 @@ static void rk3588_set_to_rgmii(struct rk_priv_data *bsp_priv,
>  	offset_con = bsp_priv->id == 1 ? RK3588_GRF_GMAC_CON9 :
>  					 RK3588_GRF_GMAC_CON8;
>  
> -	regmap_write(bsp_priv->php_grf, RK3588_GRF_GMAC_CON0,
> -		     RK3588_GMAC_PHY_INTF_SEL(id, PHY_INTF_SEL_RGMII));
> -
>  	regmap_write(bsp_priv->php_grf, RK3588_GRF_CLK_CON1,
>  		     RK3588_GMAC_CLK_RGMII_MODE(id));
>  
> @@ -1239,9 +1276,6 @@ static void rk3588_set_to_rgmii(struct rk_priv_data *bsp_priv,
>  
>  static void rk3588_set_to_rmii(struct rk_priv_data *bsp_priv)
>  {
> -	regmap_write(bsp_priv->php_grf, RK3588_GRF_GMAC_CON0,
> -		     RK3588_GMAC_PHY_INTF_SEL(bsp_priv->id, PHY_INTF_SEL_RMII));
> -
>  	regmap_write(bsp_priv->php_grf, RK3588_GRF_CLK_CON1,
>  		     RK3588_GMAC_CLK_RMII_MODE(bsp_priv->id));
>  }
> @@ -1294,10 +1328,14 @@ static void rk3588_set_clock_selection(struct rk_priv_data *bsp_priv, bool input
>  }
>  
>  static const struct rk_gmac_ops rk3588_ops = {
> +	.init = rk3588_init,
>  	.set_to_rgmii = rk3588_set_to_rgmii,
>  	.set_to_rmii = rk3588_set_to_rmii,
>  	.set_speed = rk3588_set_gmac_speed,
>  	.set_clock_selection = rk3588_set_clock_selection,
> +
> +	.phy_intf_sel_grf_reg = RK3588_GRF_GMAC_CON0,
> +
>  	.php_grf_required = true,
>  	.regs_valid = true,
>  	.regs = {
> @@ -1310,7 +1348,6 @@ static const struct rk_gmac_ops rk3588_ops = {
>  #define RV1108_GRF_GMAC_CON0		0X0900
>  
>  /* RV1108_GRF_GMAC_CON0 */
> -#define RV1108_GMAC_PHY_INTF_SEL(val)	GRF_FIELD(6, 4, val)
>  #define RV1108_GMAC_FLOW_CTRL		GRF_BIT(3)
>  #define RV1108_GMAC_FLOW_CTRL_CLR	GRF_CLR_BIT(3)
>  #define RV1108_GMAC_SPEED_10M		GRF_CLR_BIT(2)
> @@ -1320,8 +1357,6 @@ static const struct rk_gmac_ops rk3588_ops = {
>  
>  static void rv1108_set_to_rmii(struct rk_priv_data *bsp_priv)
>  {
> -	regmap_write(bsp_priv->grf, RV1108_GRF_GMAC_CON0,
> -		     RV1108_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII));
>  }
>  
>  static const struct rk_reg_speed_data rv1108_reg_speed_data = {
> @@ -1339,6 +1374,9 @@ static int rv1108_set_speed(struct rk_priv_data *bsp_priv,
>  static const struct rk_gmac_ops rv1108_ops = {
>  	.set_to_rmii = rv1108_set_to_rmii,
>  	.set_speed = rv1108_set_speed,
> +
> +	.phy_intf_sel_grf_reg = RV1108_GRF_GMAC_CON0,
> +	.phy_intf_sel_mask = GENMASK_U16(6, 4),
>  };
>  
>  #define RV1126_GRF_GMAC_CON0		0X0070
> @@ -1346,7 +1384,6 @@ static const struct rk_gmac_ops rv1108_ops = {
>  #define RV1126_GRF_GMAC_CON2		0X0078
>  
>  /* RV1126_GRF_GMAC_CON0 */
> -#define RV1126_GMAC_PHY_INTF_SEL(val)	GRF_FIELD(6, 4, val)
>  #define RV1126_GMAC_FLOW_CTRL			GRF_BIT(7)
>  #define RV1126_GMAC_FLOW_CTRL_CLR		GRF_CLR_BIT(7)
>  #define RV1126_GMAC_M0_RXCLK_DLY_ENABLE		GRF_BIT(1)
> @@ -1369,7 +1406,6 @@ static void rv1126_set_to_rgmii(struct rk_priv_data *bsp_priv,
>  				int tx_delay, int rx_delay)
>  {
>  	regmap_write(bsp_priv->grf, RV1126_GRF_GMAC_CON0,
> -		     RV1126_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) |
>  		     RV1126_GMAC_M0_RXCLK_DLY_ENABLE |
>  		     RV1126_GMAC_M0_TXCLK_DLY_ENABLE |
>  		     RV1126_GMAC_M1_RXCLK_DLY_ENABLE |
> @@ -1386,14 +1422,15 @@ static void rv1126_set_to_rgmii(struct rk_priv_data *bsp_priv,
>  
>  static void rv1126_set_to_rmii(struct rk_priv_data *bsp_priv)
>  {
> -	regmap_write(bsp_priv->grf, RV1126_GRF_GMAC_CON0,
> -		     RV1126_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII));
>  }
>  
>  static const struct rk_gmac_ops rv1126_ops = {
>  	.set_to_rgmii = rv1126_set_to_rgmii,
>  	.set_to_rmii = rv1126_set_to_rmii,
>  	.set_speed = rk_set_clk_mac_speed,
> +
> +	.phy_intf_sel_grf_reg = RV1126_GRF_GMAC_CON0,
> +	.phy_intf_sel_mask = GENMASK_U16(6, 4),
>  };
>  
>  static int rk_gmac_clk_init(struct plat_stmmacenet_data *plat)
> @@ -1614,6 +1651,11 @@ static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,
>  
>  	bsp_priv->dev = dev;
>  
> +	/* Set the default phy_intf_sel and RMII mode register parameters. */
> +	bsp_priv->phy_intf_sel_grf_reg = ops->phy_intf_sel_grf_reg;
> +	bsp_priv->phy_intf_sel_mask = ops->phy_intf_sel_mask;
> +	bsp_priv->rmii_mode_mask = ops->rmii_mode_mask;
> +
>  	if (ops->init) {
>  		ret = ops->init(bsp_priv);
>  		if (ret) {
> @@ -1649,6 +1691,7 @@ static int rk_gmac_check_ops(struct rk_priv_data *bsp_priv)
>  static int rk_gmac_powerup(struct rk_priv_data *bsp_priv)
>  {
>  	struct device *dev = bsp_priv->dev;
> +	u32 val;
>  	int ret;
>  
>  	ret = rk_gmac_check_ops(bsp_priv);
> @@ -1659,6 +1702,24 @@ static int rk_gmac_powerup(struct rk_priv_data *bsp_priv)
>  	if (ret)
>  		return ret;
>  
> +	ret = rk_get_phy_intf_sel(bsp_priv->phy_iface);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (bsp_priv->phy_intf_sel_mask) {
> +		/* Encode the phy_intf_sel value */
> +		val = rk_encode_wm16(ret, bsp_priv->phy_intf_sel_mask);
> +
> +		/* If defined, encode the RMII mode mask setting. */
> +		val |= rk_encode_wm16(ret == PHY_INTF_SEL_RMII,
> +				      bsp_priv->rmii_mode_mask);
> +
> +		ret = regmap_write(bsp_priv->grf,
> +				   bsp_priv->phy_intf_sel_grf_reg, val);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
>  	/*rmii or rgmii*/
>  	switch (bsp_priv->phy_iface) {
>  	case PHY_INTERFACE_MODE_RGMII:
> -- 
> 2.47.3
> 
> 
> 

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From nicolas at ndufresne.ca  Tue Dec  2 12:57:43 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Tue, 02 Dec 2025 15:57:43 -0500
Subject: [PATCH v2 2/2] media: verisilicon: Avoid G2 bus error while
 decoding H.264 and HEVC
In-Reply-To: <570d444a92b0e49a11379cabc8f7f838e5228f7a.camel@ndufresne.ca>
References: <20251128025117.535-1-ming.qian@oss.nxp.com>
		 <20251128025117.535-2-ming.qian@oss.nxp.com>
		 <46e9a5a881946d879d1b2af3421d574b26256ae3.camel@ndufresne.ca>
		 <64ad3d66-4edf-4a0b-8992-0db0e90a32b0@oss.nxp.com>
	 <570d444a92b0e49a11379cabc8f7f838e5228f7a.camel@ndufresne.ca>
Message-ID: <99f3a6d843afb1c5c47b14e414b917920c3a5041.camel@ndufresne.ca>

Le mardi 02 d?cembre 2025 ? 15:21 -0500, Nicolas Dufresne a ?crit?:
> Hi Ming,
> 
> Le lundi 01 d?cembre 2025 ? 09:52 +0800, Ming Qian(OSS) a ?crit?:
> > > Then instead of this, I would like to add a kref to v4l2_m2m_dec, I checked
> > > already and this is both safe and backward compatible.
> > > 
> > > Then in the get function, you will walk over the compatible that are
> > > different
> > > from the currently probe node. If you find one that is initialized, you will
> > > call v4l2_m2m_get() to obtained a shared reference. In _remove() you will
> > > simply
> > > do v4l2_m2m_put() instead of v4l2_m2m_release().
> > > 
> > > Hope the others are happy with this. For Hantro drivers, this will make it a
> > > much more powerfull mechanism.
> > > 
> > > Nicolas
> > > 
> > 
> > For v4l2_m2m_get() and v4l2_m2m_put(), do you mean defining these two
> > functions in v4l2 m2m, instead of just adding them in the hantro driver?
> 
> my idea was to add a kref to be able to share v4l2_m2m_dev. One thing I notice
> is that its the v4l2_m2m dev that creates the media controller on all other
> drivers. Note sure why Hantro does it own still, maybe it predates, maybe its
> something else.
> 
> Its quite weirdly glued together, since the v4l2_m2m_release() function just
> happily free the m2m_dev without even trying to cleanup the media controller. It
> totally orthogonal to the job queue, maybe it shouldn't be there.
> 
> I'll make an RFC for the kref anyway, if that has a change, I'll try and split
> out the v4l2_m2m_mc_dev on it own, so driver can share a m2m and use the
> helpers.
> 
> Nicolas

Here's down below what I had in mind, this is for illustration. I can send a
proper RFC, while at it I will move the media controller part out and port
Hantro to use the helper.

The idea is that instead of using global, you can have a list of devices that
must be combined in the Hantro variant. You then walk the nodes, and if you find
a match, you reference the v4l2_m2m_dev, isntead of creating a new one.

This is slightly more elegant, and can be reused quickly later if we have other
hantro complications like this. One use case could be for modern integration of
the Nano decoder/encoder combo (H1/G1 combo). These are known to share the same
internal SRAM, and cannot be run concurrently. This was defined as a single
device node on RK3588, but I think this badly describe the hardware, and having
two nodes would be more clear.

A bonus would be to describe this dependency in the DT, but since this is
invisible hardware, its pretty hard to design. And in the case of imx8mq, its
not clear this was by design, but likely more an errata that should be added to
the pretty long list for this SoC.

cheers,
Nicolas

---
From: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Date: Tue, 2 Dec 2025 15:40:37 -0500
Subject: [PATCH] media: v4l2-mem2mem: Add a kref to the v4l2_m2m_dev structure

Adding a reference count to the v4l2_m2m_dev structure allow safely sharing it
across multiple hardware nodes. This can be used to prevent running jobs
concurrently on m2m cores that have some internal resource sharing.

Signed-off-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
---
 drivers/media/v4l2-core/v4l2-mem2mem.c | 22 ++++++++++++++++++++++
 include/media/v4l2-mem2mem.h           | 21 +++++++++++++++++++++
 2 files changed, 43 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c
index fec93c1a92317..b6940bab641d3 100644
--- a/drivers/media/v4l2-core/v4l2-mem2mem.c
+++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
@@ -90,6 +90,7 @@ static const char * const m2m_entity_name[] = {
  * @job_work:		worker to run queued jobs.
  * @job_queue_flags:	flags of the queue status, %QUEUE_PAUSED.
  * @m2m_ops:		driver callbacks
+ * @kref:		device reference count
  */
 struct v4l2_m2m_dev {
 	struct v4l2_m2m_ctx	*curr_ctx;
@@ -109,6 +110,8 @@ struct v4l2_m2m_dev {
 	unsigned long		job_queue_flags;
 
 	const struct v4l2_m2m_ops *m2m_ops;
+
+	struct kref kref;
 };
 
 static struct v4l2_m2m_queue_ctx *get_queue_ctx(struct v4l2_m2m_ctx *m2m_ctx,
@@ -1200,6 +1203,7 @@ struct v4l2_m2m_dev *v4l2_m2m_init(const struct v4l2_m2m_ops *m2m_ops)
 	INIT_LIST_HEAD(&m2m_dev->job_queue);
 	spin_lock_init(&m2m_dev->job_spinlock);
 	INIT_WORK(&m2m_dev->job_work, v4l2_m2m_device_run_work);
+	kref_init(&m2m_dev->kref);
 
 	return m2m_dev;
 }
@@ -1211,6 +1215,24 @@ void v4l2_m2m_release(struct v4l2_m2m_dev *m2m_dev)
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_release);
 
+void v4l2_m2m_get(struct v4l2_m2m_dev *m2m_dev)
+{
+	kref_get(&m2m_dev->kref);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_get);
+
+static void v4l2_m2m_release_from_kref(struct kref *kref)
+{
+	struct v4l2_m2m_dev *m2m_dev = container_of(kref, struct v4l2_m2m_dev, kref);
+	v4l2_m2m_release(m2m_dev);
+}
+
+void v4l2_m2m_put(struct v4l2_m2m_dev *m2m_dev)
+{
+	kref_put(&m2m_dev->kref, v4l2_m2m_release_from_kref);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_put);
+
 struct v4l2_m2m_ctx *v4l2_m2m_ctx_init(struct v4l2_m2m_dev *m2m_dev,
 		void *drv_priv,
 		int (*queue_init)(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq))
diff --git a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h
index bf6a09a04dcf8..ca295c660c7f9 100644
--- a/include/media/v4l2-mem2mem.h
+++ b/include/media/v4l2-mem2mem.h
@@ -547,6 +547,27 @@ v4l2_m2m_register_media_controller(struct v4l2_m2m_dev *m2m_dev,
  */
 void v4l2_m2m_release(struct v4l2_m2m_dev *m2m_dev);
 
+/**
+ * v4l2_m2m_get() - take a reference to the m2m_dev structure
+ *
+ * @m2m_dev: opaque pointer to the internal data to handle M2M context
+ *
+ * This is used to share the M2M device across multiple devices. This
+ * can be used to avoid scheduling two hardware nodes concurrently.
+ */
+void v4l2_m2m_get(struct v4l2_m2m_dev *m2m_dev);
+
+/**
+ * v4l2_m2m_put() - remove a reference to the m2m_dev structure
+ *
+ * @m2m_dev: opaque pointer to the internal data to handle M2M context
+ *
+ * Once the M2M device have no more references, v4l2_m2m_realse() will be
+ * called automatically. Users of this method should never call
+ * v4l2_m2m_release() directly. See v4l2_m2m_get() for more details.
+ */
+void v4l2_m2m_put(struct v4l2_m2m_dev *m2m_dev);
+
 /**
  * v4l2_m2m_ctx_init() - allocate and initialize a m2m context
  *
-- 
2.51.0
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251202/082589c4/attachment.sig>

From conor at kernel.org  Tue Dec  2 13:45:50 2025
From: conor at kernel.org (Conor Dooley)
Date: Tue, 2 Dec 2025 21:45:50 +0000
Subject: =?utf-8?B?5Zue5aSNOiDlm57lpI06IFtQQVRD?= =?utf-8?Q?H?= v3 1/3]
 dt-bindings: reset: add sky1 reset controller
In-Reply-To: <PUZPR06MB58873EBA3818208D061FF866EFDBA@PUZPR06MB5887.apcprd06.prod.outlook.com>
References: <20251124063235.952136-1-gary.yang@cixtech.com>
 <20251124063235.952136-2-gary.yang@cixtech.com>
 <20251124-selector-blemish-ec6e9a356bc6@spud>
 <PUZPR06MB5887CB84BC4D006EC594B654EFD1A@PUZPR06MB5887.apcprd06.prod.outlook.com>
 <20251126-dreamily-shorty-cb543d993e7a@spud>
 <PUZPR06MB58873EBA3818208D061FF866EFDBA@PUZPR06MB5887.apcprd06.prod.outlook.com>
Message-ID: <20251202-mortuary-omission-f20793e20a36@spud>

On Mon, Dec 01, 2025 at 03:13:44AM +0000, Gary Yang wrote:
> Hi Conor:
> 
> Thanks for your comments.
> 
> > -----????-----
> > ???: Conor Dooley <conor at kernel.org>
> > ????: 2025?11?27? 3:15
> > ???: Gary Yang <gary.yang at cixtech.com>
> > ??: p.zabel at pengutronix.de; robh at kernel.org; krzk+dt at kernel.org;
> > conor+dt at kernel.org; devicetree at vger.kernel.org;
> > linux-kernel at vger.kernel.org; linux-arm-kernel at lists.infradead.org;
> > cix-kernel-upstream <cix-kernel-upstream at cixtech.com>
> > ??: Re: ??: [PATCH v3 1/3] dt-bindings: reset: add sky1 reset controller
> > 
> > On Tue, Nov 25, 2025 at 02:12:23PM +0000, Gary Yang wrote:
> > > Hi Conor:
> > >
> > > Thanks for your comments
> > >
> > > > -----????-----
> > > > ???: Conor Dooley <conor at kernel.org>
> > > > ????: 2025?11?25? 3:54
> > > > ???: Gary Yang <gary.yang at cixtech.com>
> > > > ??: p.zabel at pengutronix.de; robh at kernel.org; krzk+dt at kernel.org;
> > > > conor+dt at kernel.org; devicetree at vger.kernel.org;
> > > > linux-kernel at vger.kernel.org; linux-arm-kernel at lists.infradead.org;
> > > > cix-kernel-upstream <cix-kernel-upstream at cixtech.com>
> > > > ??: Re: [PATCH v3 1/3] dt-bindings: reset: add sky1 reset controller
> > > >
> > > > On Mon, Nov 24, 2025 at 02:32:33PM +0800, Gary Yang wrote:
> > > > > There are two reset controllers on Cix sky1 Soc.
> > > > > One is located in S0 domain, and the other is located in S5 domain.
> > > > >
> > > > > Signed-off-by: Gary Yang <gary.yang at cixtech.com>
> > > > > ---
> > > > >  .../bindings/reset/cix,sky1-rst.yaml          |  50 ++++++
> > > > >  include/dt-bindings/reset/cix,sky1-rst-fch.h  |  42 +++++
> > > > >  include/dt-bindings/reset/cix,sky1-rst.h      | 164
> > ++++++++++++++++++
> > > > >  3 files changed, 256 insertions(+)  create mode 100644
> > > > > Documentation/devicetree/bindings/reset/cix,sky1-rst.yaml
> > > > >  create mode 100644 include/dt-bindings/reset/cix,sky1-rst-fch.h
> > > > >  create mode 100644 include/dt-bindings/reset/cix,sky1-rst.h
> > > > >
> > > > > diff --git
> > > > > a/Documentation/devicetree/bindings/reset/cix,sky1-rst.yaml
> > > > > b/Documentation/devicetree/bindings/reset/cix,sky1-rst.yaml
> > > > > new file mode 100644
> > > > > index 000000000000..a28f938a283d
> > > > > --- /dev/null
> > > > > +++ b/Documentation/devicetree/bindings/reset/cix,sky1-rst.yaml
> > > > > @@ -0,0 +1,50 @@
> > > > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML
> > > > > +1.2
> > > > > +---
> > > > > +$id: http://devicetree.org/schemas/reset/cix,sky1-rst.yaml#
> > > > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > > > +
> > > > > +title: CIX Sky1 Reset Controller
> > > > > +
> > > > > +maintainers:
> > > > > +  - Gary Yang <gary.yang at cixtech.com>
> > > > > +
> > > > > +description: |
> > > > > +  CIX Sky1 reset controller can be used to reset various set of
> > peripherals.
> > > > > +  There are two reset controllers, one is located in S0 domain,
> > > > > +the other
> > > > > +  is located in S5 domain.
> > > > > +
> > > > > +  See also:
> > > > > +  - include/dt-bindings/reset/cix,sky1-rst.h
> > > > > +
> > > > > +properties:
> > > > > +  compatible:
> > > > > +    items:
> > > > > +      - enum:
> > > > > +          - cix,sky1-rst
> > > > > +          - cix,sky1-rst-fch
> > > >
> > > > You've not addressed my v2 commentary:
> > > > https://lore.kernel.org/all/20251114-problem-overbook-383f8e45cd0b at s
> > > > pud
> > > > /
> > > > I asked what else the device does, but you didn't answer me.
> > > > Dropping the syscon doesn't make sense if the device genuinely has other
> > functions.
> > > >
> > >
> > > First I'm sorry for not responding your questions earlier. We agree the fact
> > the register space of reset should not depends on other modules.
> > > We found that while the reset register spaces on the sky1 platform are
> > non-contiguous, a specific register space among them is exclusively used by
> > reset.
> > > So we can remove syscon property and split serval register spaces. All right?
> > 
> > No, not all right, sorry.
> > It's perfectly okay for some region to do multiple things, most SoCs have
> > multiple regions exactly like this.
> > The normal thing to do is to treat these regions as a syscon like your earlier
> > version did. The problem with your v1 was that you called the whole thing a
> > reset, when it isn't just that.
> > There's plenty of examples using mfd for how these kinds of devices are
> > handled in the kernel. There's some using the simple-mfd compatible, which is
> > for when there are subdevices with their own nodes and other defining
> > mfd_cells and calling mfd_add_devices() when the subdevices do not have
> > enough complexity for a node (like your reset controller that has one property
> > and is unlikely to be reusable on another platform).
> > 
> > > > > +  reg:
> > > > > +    minItems: 1
> > > > > +    maxItems: 3
> > > > > +
> > > > > +  '#reset-cells':
> > > > > +    const: 1
> > > > > +
> > > > > +required:
> > > > > +  - compatible
> > > > > +  - reg
> > > > > +  - '#reset-cells'
> > > > > +
> > > > > +additionalProperties: false
> > > > > +
> > > > > +examples:
> > > > > +  - |
> > > > > +    #include <dt-bindings/reset/cix,sky1-rst.h>
> > > > > +    reset-controller at 16000304 {
> > > > > +      compatible = "cix,sky1-rst";
> > > >
> > > > > +      reg = <0x16000304 0xc>,
> > > > > +            <0x16000400 0x10>,
> > > > > +            <0x16000800 0x8>;
> > > >
> > > > This is also highly suspect, and I believe what you had before was
> > > > probably much more realistic.
> > > > Do things properly and fully *now*, rather than pay the price of
> > > > unravelling it all later. I just did this for one of my own
> > > > platforms, and putting in the effort to completely describe stuff up
> > > > front is actually worth it rather than having to refactor years down the line.
> > 
> > > Yes, I agree your view.
> > > This scheme is discussed in our team. It is our decision, not only mine.
> > > There are some modules here that haven't been pushed upstream yet.
> > > If we take them as our internal names, maybe make you confuse. For
> > > example,
> > 
> > If the naming is going to be confusing, then explain things in the description
> > property.
> > 
> > > The register space based 0x16000000 belongs to PMCTRL_S5. It is a system
> > power control module, not SCP.
> > > It not only includes reset controller, but also some usb control,
> > > wakeup sources, clk gates, sleep states settings, generic registers for software,
> > and so on. But In kernel, we mainly focus on reset controller and usb control.
> > > They are controlled by the different registers. So we decide to adopt this
> > scheme.
> > 
> > This is all very normal stuff that syscons are used for on other platforms.
> > Describe the register region based on what it contains, not based on what you
> > currently thing that linux is going to use. Maybe later you'll need the other
> > functions either in linux, or in other projects (like u-boot) that import our
> > devicetrees.
> > 
> 
> Yes?First we agree syscon scheme. It is very common in kernel. We want to verify the next actions with you.
> One, we add a node syscon at 16000000 as pmctrl_s5 an example.
> Two, the reset node and usb node both contain a phandle used to point to syscon node

Not quite. The rest node would be empty, other than the phandle, and is
therefore pointless. The #reset-cells property should go in the syscon
node itself. For usb, because it sounds like the syscon is only
providing some control registers and is not the usb controller itself, a
phandle is okay. It's a case by case thing, but if the syscon node
provides an entire feature then a phandle is not suitable and instead
either a child node of the syscon (which would make it a simple-mfd too)
should be used or the properties should go directly into the syscon
node. That depends on how complex the feature is and how likely it is to
be reused between devices. reset is very unlikely to be suitable for
reuse, for example.

> Three, In corresponding driver files, we can get the regmap pointers via syscon API.
> All right? By the way, How should we describe syscon in yaml file? Are there some files used to refer?

microchip,mpfs-mss-top-sysreg.yaml is one I wrote recently. Going to the
corresponding driver you will be able to see how the reset controller
driver is probed. You should be able to find it in linux-next.
sophgo,sg2044-top-syscon.yaml is another that works in the same way.

> Please show us your suggestions. Thanks
> 
> Best regards
> Gary
> 
> > > If you have any questions, please let us know. If make any mistakes, please
> > remind me kindly.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251202/491d7d21/attachment.sig>

From bisson.gary at gmail.com  Tue Dec  2 13:49:19 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Tue, 2 Dec 2025 22:49:19 +0100
Subject: [PATCH v2 0/4] Add support for Ezurio MediaTek platforms
In-Reply-To: <176459099842.2909480.6224244901963014446.robh@kernel.org>
References: <20251201-review-v2-0-dc2df44eec7e@gmail.com>
 <176459099842.2909480.6224244901963014446.robh@kernel.org>
Message-ID: <aS9e31OwQwsLvQ9l@owl5>

Hi

On Mon, Dec 01, 2025 at 06:27:02AM -0600, Rob Herring wrote:
> 
> On Mon, 01 Dec 2025 11:23:14 +0100, Gary Bisson wrote:
> > This series adds support for Ezurio MediaTek platforms called
> > "Tungsten". It includes support for MT8370-based Tungsten 510 and
> > MT8390-based Tungsten 700 SOMs.
> > 
> > Changelog v1 -> v2:
> > - use b4 to cc all maintainers properly
> > - squashed patches 2/3 together
> > - updated node names to be generic (pmic)
> > 
> > Couldn't repro the schema issues sent by the bots.
> > 
> > Regards,
> > 
> > Gary Bisson (4):
> >   dt-bindings: vendor-prefixes: Add Ezurio LLC
> >   dt-bindings: arm: mediatek: Add Ezurio Tungsten entries
> >   arm64: dts: mediatek: add device tree for Tungsten 510 board
> >   arm64: dts: mediatek: add device tree for Tungsten 700 board
> > 
> >  .../devicetree/bindings/arm/mediatek.yaml     |    2 +
> >  .../devicetree/bindings/vendor-prefixes.yaml  |    2 +
> >  arch/arm64/boot/dts/mediatek/Makefile         |    2 +
> >  .../dts/mediatek/mt8370-tungsten-smarc.dts    |   14 +
> >  .../dts/mediatek/mt8390-tungsten-smarc.dts    |   22 +
> >  .../dts/mediatek/mt83x0-tungsten-smarc.dtsi   | 1481 +++++++++++++++++
> >  6 files changed, 1523 insertions(+)
> >  create mode 100644 arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts
> >  create mode 100644 arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts
> >  create mode 100644 arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi
> > 
> > --
> > 2.43.0
> > 
> > ---
> > Gary Bisson (4):
> >       dt-bindings: vendor-prefixes: Add Ezurio LLC
> >       dt-bindings: arm: mediatek: Add Ezurio Tungsten entries
> >       arm64: dts: mediatek: add device tree for Tungsten 510 board
> >       arm64: dts: mediatek: add device tree for Tungsten 700 board
> > 
> >  .../devicetree/bindings/arm/mediatek.yaml          |    2 +
> >  .../devicetree/bindings/vendor-prefixes.yaml       |    2 +
> >  arch/arm64/boot/dts/mediatek/Makefile              |    2 +
> >  .../boot/dts/mediatek/mt8370-tungsten-smarc.dts    |   14 +
> >  .../boot/dts/mediatek/mt8390-tungsten-smarc.dts    |   22 +
> >  .../boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi   | 1481 ++++++++++++++++++++
> >  6 files changed, 1523 insertions(+)
> > ---
> > base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
> > change-id: 20251201-review-750072579991
> > 
> > Best regards,
> > --
> > Gary Bisson <bisson.gary at gmail.com>
> > 
> > 
> > 
> 
> 
> My bot found new DTB warnings on the .dts files added or changed in this
> series.
> 
> Some warnings may be from an existing SoC .dtsi. Or perhaps the warnings
> are fixed by another series. Ultimately, it is up to the platform
> maintainer whether these warnings are acceptable or not. No need to reply
> unless the platform maintainer has comments.
> 
> If you already ran DT checks and didn't see these error(s), then
> make sure dt-schema is up to date:
> 
>   pip3 install dtschema --upgrade
> 
> 
> This patch series was applied (using b4) to base:
>  Base: base-commit 7d0a66e4bb9081d75c82ec4957c50034cb0ea449 not known, ignoring
>  Base: attempting to guess base-commit...
>  Base: tags/v6.18-rc3 (exact match)
>  Base: tags/v6.18-rc3 (use --merge-base to override)

base-commit (7d0a66e4bb9081d75c82ec4957c50034cb0ea449) is tags/v6.18, it
should appear properly for next version of the patch.

> If this is not the correct base, please add 'base-commit' tag
> (or use b4 which does this automatically)
> 
> New warnings running 'make CHECK_DTBS=y for arch/arm64/boot/dts/mediatek/' for 20251201-review-v2-0-dc2df44eec7e at gmail.com:
> 
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: i2c0-gpio-pins: pins-gpio: {'pinmux': [1536], 'bias-pull-up': 203, 'drive-strength-microamp': [1000]} is not of type 'array'
> 	from schema $id: http://devicetree.org/schemas/gpio/gpio-consumer.yaml
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: pmic (mediatek,mt6359): '#sound-dai-cells' does not match any of the regexes: '^pinctrl-[0-9]+$'
> 	from schema $id: http://devicetree.org/schemas/mfd/mediatek,mt6397.yaml
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): pmic at 6:reg:0: [6, 0, 11] is too long
> 	from schema $id: http://devicetree.org/schemas/spmi/mtk,spmi-mtk-pmif.yaml
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): #address-cells: 2 was expected
> 	from schema $id: http://devicetree.org/schemas/spmi/mtk,spmi-mtk-pmif.yaml
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): #size-cells: 0 was expected
> 	from schema $id: http://devicetree.org/schemas/spmi/mtk,spmi-mtk-pmif.yaml
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): Unevaluated properties are not allowed ('#address-cells', '#size-cells', 'pmic at 6' were unexpected)
> 	from schema $id: http://devicetree.org/schemas/spmi/mtk,spmi-mtk-pmif.yaml
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): pmic at 6:reg:0: [6, 0, 11] is too long
> 	from schema $id: http://devicetree.org/schemas/spmi/spmi.yaml
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): #address-cells: 2 was expected
> 	from schema $id: http://devicetree.org/schemas/spmi/spmi.yaml
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): #size-cells: 0 was expected
> 	from schema $id: http://devicetree.org/schemas/spmi/spmi.yaml
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: pmic at 6 (mediatek,mt6315-regulator): regulators:vbuck1: Unevaluated properties are not allowed ('mtk,combined-regulator', 'regulator-compatible' were unexpected)
> 	from schema $id: http://devicetree.org/schemas/regulator/mt6315-regulator.yaml
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: pmic at 6 (mediatek,mt6315-regulator): regulators:vbuck3: Unevaluated properties are not allowed ('regulator-compatible' was unexpected)
> 	from schema $id: http://devicetree.org/schemas/regulator/mt6315-regulator.yaml
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: pmic at 6 (mediatek,mt6315-regulator): regulators:vbuck4: Unevaluated properties are not allowed ('regulator-compatible' was unexpected)
> 	from schema $id: http://devicetree.org/schemas/regulator/mt6315-regulator.yaml
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: vbuck1: 'mtk,combined-regulator' does not match any of the regexes: '^#.*', '^(at25|bm|devbus|dmacap|dsa|exynos|fsi[ab]|gpio-fan|gpio-key|gpio|gpmc|hdmi|i2c-gpio),.*', '^(keypad|m25p|max8952|max8997|max8998|mpmc),.*', '^(pciclass|pinctrl-single|#pinctrl-single|PowerPC),.*', '^(pl022|pxa-mmc|rcar_sound|rotary-encoder|s5m8767|sdhci),.*', '^(simple-audio-card|st-plgpio|st-spics|ts),.*', '^100ask,.*', '^70mai,.*', '^8dev,.*', '^GEFanuc,.*', '^IBM,.*', '^ORCL,.*', '^SUNW,.*', '^[a-zA-Z0-9#_][a-zA-Z0-9#+\-._@]{0,63}$', '^[a-zA-Z0-9+\-._]*@[0-9a-zA-Z,]*$', '^abb,.*', '^abilis,.*', '^abracon,.*', '^abt,.*', '^acbel,.*', '^acelink,.*', '^acer,.*', '^acme,.*', '^actions,.*', '^actiontec,.*', '^active-semi,.*', '^ad,.*', '^adafruit,.*', '^adapteva,.*', '^adaptrum,.*', '^adh,.*', '^adi,.*', '^adieng,.*', '^admatec,.*', '^advantech,.*', '^aeroflexgaisler,.*', '^aesop,.*', '^airoha,.*', '^al,.*', '^alcatel,.*', '^aldec,.*', '^alfa-network,.*'
>  , '^allegro,.*', '^allegromicro,.*', '^alliedtelesis,.*', '^alliedvision,.*', '^allo,.*', '^allwinner,.*', '^alphascale,.*', '^alps,.*', '^alt,.*', '^altr,.*', '^amarula,.*', '^amazon,.*', '^amcc,.*', '^amd,.*', '^amediatech,.*', '^amlogic,.*', '^ampere,.*', '^amphenol,.*', '^ampire,.*', '^ams,.*', '^amstaos,.*', '^analogix,.*', '^anbernic,.*', '^andestech,.*', '^anvo,.*', '^aoly,.*', '^aosong,.*', '^apm,.*', '^apple,.*', '^aptina,.*', '^arasan,.*', '^archermind,.*', '^arcom,.*', '^arctic,.*', '^arcx,.*', '^argon40,.*', '^ariaboard,.*', '^aries,.*', '^arm,.*', '^armadeus,.*', '^armsom,.*', '^arrow,.*', '^artesyn,.*', '^asahi-kasei,.*', '^asc,.*', '^asix,.*', '^aspeed,.*', '^asrock,.*', '^asteralabs,.*', '^asus,.*', '^atheros,.*', '^atlas,.*', '^atmel,.*', '^auo,.*', '^auvidea,.*', '^avago,.*', '^avia,.*', '^avic,.*', '^avnet,.*', '^awinic,.*', '^axentia,.*', '^axiado,.*', '^axis,.*', '^azoteq,.*', '^azw,.*', '^baikal,.*', '^bananapi,.*', '^beacon,.*', '^beagle,.*', '^belling,.*', '^
>  bestar,.*', '^bhf,.*', '^bigtreetech,.*', '^bitmain,.*', '^blaize,.*', '^bluegiga,.*', '^blutek,.*', '^boe,.*', '^bosch,.*', '^boundary,.*', '^brcm,.*', '^broadmobi,.*', '^bsh,.*', '^bticino,.*', '^buffalo,.*', '^buglabs,.*', '^bur,.*', '^bytedance,.*', '^calamp,.*', '^calao,.*', '^calaosystems,.*', '^calxeda,.*', '^cameo,.*', '^canaan,.*', '^caninos,.*', '^capella,.*', '^cascoda,.*', '^catalyst,.*', '^cavium,.*', '^cct,.*', '^cdns,.*', '^cdtech,.*', '^cellwise,.*', '^ceva,.*', '^chargebyte,.*', '^checkpoint,.*', '^chefree,.*', '^chipidea,.*', '^chipone,.*', '^chipspark,.*', '^chongzhou,.*', '^chrontel,.*', '^chrp,.*', '^chunghwa,.*', '^chuwi,.*', '^ciaa,.*', '^cirrus,.*', '^cisco,.*', '^cix,.*', '^clockwork,.*', '^cloos,.*', '^cloudengines,.*', '^cnm,.*', '^cnxt,.*', '^colorfly,.*', '^compal,.*', '^compulab,.*', '^comvetia,.*', '^congatec,.*', '^coolpi,.*', '^coreriver,.*', '^corpro,.*', '^cortina,.*', '^cosmic,.*', '^crane,.*', '^creative,.*', '^crystalfontz,.*', '^csky,.*', '^cso
>  t,.*', '^csq,.*', '^csr,.*', '^ctera,.*', '^ctu,.*', '^cubietech,.*', '^cudy,.*', '^cui,.*', '^cypress,.*', '^cyx,.*', '^cznic,.*', '^dallas,.*', '^dataimage,.*', '^davicom,.*', '^deepcomputing,.*', '^dell,.*', '^delta,.*', '^densitron,.*', '^denx,.*', '^devantech,.*', '^dfi,.*', '^dfrobot,.*', '^dh,.*', '^difrnce,.*', '^digi,.*', '^digilent,.*', '^dimonoff,.*', '^diodes,.*', '^dioo,.*', '^djn,.*', '^dlc,.*', '^dlg,.*', '^dlink,.*', '^dmo,.*', '^domintech,.*', '^dongwoon,.*', '^dptechnics,.*', '^dragino,.*', '^dream,.*', '^ds,.*', '^dserve,.*', '^dynaimage,.*', '^ea,.*', '^ebang,.*', '^ebbg,.*', '^ebs-systart,.*', '^ebv,.*', '^eckelmann,.*', '^econet,.*', '^edgeble,.*', '^edimax,.*', '^edt,.*', '^ees,.*', '^eeti,.*', '^egnite,.*', '^einfochips,.*', '^eink,.*', '^elan,.*', '^element14,.*', '^elgin,.*', '^elida,.*', '^elimo,.*', '^elpida,.*', '^embedfire,.*', '^embest,.*', '^emcraft,.*', '^emlid,.*', '^emmicro,.*', '^empire-electronix,.*', '^emtrion,.*', '^enbw,.*', '^enclustra,.*', '
>  ^endian,.*', '^endless,.*', '^ene,.*', '^energymicro,.*', '^engicam,.*', '^engleder,.*', '^epcos,.*', '^epfl,.*', '^epson,.*', '^esp,.*', '^est,.*', '^eswin,.*', '^ettus,.*', '^eukrea,.*', '^everest,.*', '^everspin,.*', '^evervision,.*', '^exar,.*', '^excito,.*', '^exegin,.*', '^ezchip,.*', '^ezurio,.*', '^facebook,.*', '^fairchild,.*', '^fairphone,.*', '^faraday,.*', '^fascontek,.*', '^fastrax,.*', '^fcs,.*', '^feixin,.*', '^feiyang,.*', '^fii,.*', '^firefly,.*', '^flipkart,.*', '^focaltech,.*', '^forlinx,.*', '^foursemi,.*', '^foxlink,.*', '^freebox,.*', '^freecom,.*', '^frida,.*', '^friendlyarm,.*', '^fsl,.*', '^fujitsu,.*', '^fxtec,.*', '^galaxycore,.*', '^gameforce,.*', '^gardena,.*', '^gateway,.*', '^gateworks,.*', '^gcw,.*', '^ge,.*', '^geekbuying,.*', '^gef,.*', '^gehc,.*', '^gemei,.*', '^gemtek,.*', '^genesys,.*', '^genexis,.*', '^geniatech,.*', '^giantec,.*', '^giantplus,.*', '^glinet,.*', '^globalscale,.*', '^globaltop,.*', '^gmt,.*', '^gocontroll,.*', '^goldelico,.*', '^
>  goodix,.*', '^google,.*', '^goramo,.*', '^gplus,.*', '^grinn,.*', '^grmn,.*', '^gumstix,.*', '^gw,.*', '^hannstar,.*', '^haochuangyi,.*', '^haoyu,.*', '^hardkernel,.*', '^hce,.*', '^headacoustics,.*', '^hechuang,.*', '^hideep,.*', '^himax,.*', '^hinlink,.*', '^hirschmann,.*', '^hisi,.*', '^hisilicon,.*', '^hit,.*', '^hitex,.*', '^holt,.*', '^holtek,.*', '^honestar,.*', '^honeywell,.*', '^hoperf,.*', '^hoperun,.*', '^hp,.*', '^hpe,.*', '^hsg,.*', '^htc,.*', '^huawei,.*', '^hugsun,.*', '^huiling,.*', '^hwacom,.*', '^hxt,.*', '^hycon,.*', '^hydis,.*', '^hynitron,.*', '^hynix,.*', '^hyundai,.*', '^i2se,.*', '^ibm,.*', '^icplus,.*', '^idt,.*', '^iei,.*', '^ifi,.*', '^ilitek,.*', '^imagis,.*', '^img,.*', '^imi,.*', '^inanbo,.*', '^incircuit,.*', '^incostartec,.*', '^indiedroid,.*', '^inet-tek,.*', '^infineon,.*', '^inforce,.*', '^ingenic,.*', '^ingrasys,.*', '^injoinic,.*', '^innocomm,.*', '^innolux,.*', '^inside-secure,.*', '^insignal,.*', '^inspur,.*', '^intel,.*', '^intercontrol,.*', '
>  ^invensense,.*', '^inventec,.*', '^inversepath,.*', '^iom,.*', '^irondevice,.*', '^isee,.*', '^isil,.*', '^issi,.*', '^ite,.*', '^itead,.*', '^itian,.*', '^ivo,.*', '^iwave,.*', '^jadard,.*', '^jasonic,.*', '^jdi,.*', '^jedec,.*', '^jenson,.*', '^jesurun,.*', '^jethome,.*', '^jianda,.*', '^jide,.*', '^joz,.*', '^jty,.*', '^kam,.*', '^karo,.*', '^keithkoep,.*', '^keymile,.*', '^khadas,.*', '^kiebackpeter,.*', '^kinetic,.*', '^kingdisplay,.*', '^kingnovel,.*', '^kionix,.*', '^kobo,.*', '^kobol,.*', '^koe,.*', '^kontron,.*', '^kosagi,.*', '^kvg,.*', '^kyo,.*', '^lacie,.*', '^laird,.*', '^lamobo,.*', '^lantiq,.*', '^lattice,.*', '^lckfb,.*', '^lctech,.*', '^leadtek,.*', '^leez,.*', '^lego,.*', '^lemaker,.*', '^lenovo,.*', '^lg,.*', '^lgphilips,.*', '^libretech,.*', '^licheepi,.*', '^linaro,.*', '^lincolntech,.*', '^lineartechnology,.*', '^linksprite,.*', '^linksys,.*', '^linutronix,.*', '^linux,.*', '^linx,.*', '^liontron,.*', '^liteon,.*', '^litex,.*', '^lltc,.*', '^logicpd,.*', '^logi
>  ctechno,.*', '^longcheer,.*', '^lontium,.*', '^loongmasses,.*', '^loongson,.*', '^lsi,.*', '^luckfox,.*', '^lunzn,.*', '^luxul,.*', '^lwn,.*', '^lxa,.*', '^m5stack,.*', '^macnica,.*', '^mantix,.*', '^mapleboard,.*', '^marantec,.*', '^marvell,.*', '^maxbotix,.*', '^maxim,.*', '^maxlinear,.*', '^maxtor,.*', '^mayqueen,.*', '^mbvl,.*', '^mcube,.*', '^meas,.*', '^mecer,.*', '^mediatek,.*', '^megachips,.*', '^mele,.*', '^melexis,.*', '^melfas,.*', '^mellanox,.*', '^memsensing,.*', '^memsic,.*', '^menlo,.*', '^mentor,.*', '^meraki,.*', '^merrii,.*', '^methode,.*', '^micrel,.*', '^microchip,.*', '^microcrystal,.*', '^micron,.*', '^microsoft,.*', '^microsys,.*', '^microtips,.*', '^mikroe,.*', '^mikrotik,.*', '^milkv,.*', '^miniand,.*', '^minix,.*', '^mips,.*', '^miramems,.*', '^mitsubishi,.*', '^mitsumi,.*', '^mixel,.*', '^miyoo,.*', '^mntre,.*', '^mobileye,.*', '^modtronix,.*', '^moortec,.*', '^mosaixtech,.*', '^motorcomm,.*', '^motorola,.*', '^moxa,.*', '^mpl,.*', '^mps,.*', '^mqmaker,.*'
>  , '^mrvl,.*', '^mscc,.*', '^msi,.*', '^mstar,.*', '^mti,.*', '^multi-inno,.*', '^mundoreader,.*', '^murata,.*', '^mxic,.*', '^mxicy,.*', '^myir,.*', '^national,.*', '^neardi,.*', '^nec,.*', '^neofidelity,.*', '^neonode,.*', '^netcube,.*', '^netgear,.*', '^netlogic,.*', '^netron-dy,.*', '^netronix,.*', '^netxeon,.*', '^neweast,.*', '^newhaven,.*', '^newvision,.*', '^nexbox,.*', '^nextthing,.*', '^ni,.*', '^nicera,.*', '^nintendo,.*', '^nlt,.*', '^nokia,.*', '^nordic,.*', '^nothing,.*', '^novatech,.*', '^novatek,.*', '^novtech,.*', '^numonyx,.*', '^nutsboard,.*', '^nuvoton,.*', '^nvd,.*', '^nvidia,.*', '^nxp,.*', '^oceanic,.*', '^ocs,.*', '^oct,.*', '^okaya,.*', '^oki,.*', '^olimex,.*', '^olpc,.*', '^oneplus,.*', '^onie,.*', '^onion,.*', '^onnn,.*', '^ontat,.*', '^opalkelly,.*', '^openailab,.*', '^opencores,.*', '^openembed,.*', '^openpandora,.*', '^openrisc,.*', '^openwrt,.*', '^option,.*', '^oranth,.*', '^orisetech,.*', '^ortustech,.*', '^osddisplays,.*', '^osmc,.*', '^ouya,.*', '^o
>  verkiz,.*', '^ovti,.*', '^oxsemi,.*', '^ozzmaker,.*', '^panasonic,.*', '^parade,.*', '^parallax,.*', '^particle,.*', '^pda,.*', '^pegatron,.*', '^pericom,.*', '^pervasive,.*', '^phicomm,.*', '^phontech,.*', '^phytec,.*', '^picochip,.*', '^pinctrl-[0-9]+$', '^pine64,.*', '^pineriver,.*', '^pixcir,.*', '^plantower,.*', '^plathome,.*', '^plda,.*', '^plx,.*', '^ply,.*', '^pni,.*', '^pocketbook,.*', '^polaroid,.*', '^polyhex,.*', '^pool[0-3],.*', '^portwell,.*', '^poslab,.*', '^pov,.*', '^powertip,.*', '^powervr,.*', '^powkiddy,.*', '^pri,.*', '^primeview,.*', '^primux,.*', '^probox2,.*', '^prt,.*', '^pulsedlight,.*', '^purism,.*', '^puya,.*', '^qca,.*', '^qcom,.*', '^qemu,.*', '^qi,.*', '^qiaodian,.*', '^qihua,.*', '^qishenglong,.*', '^qnap,.*', '^quanta,.*', '^radxa,.*', '^raidsonic,.*', '^ralink,.*', '^ramtron,.*', '^raspberrypi,.*', '^raumfeld,.*', '^raydium,.*', '^rda,.*', '^realtek,.*', '^relfor,.*', '^remarkable,.*', '^renesas,.*', '^rervision,.*', '^retronix,.*', '^revotics,.*', 
>  '^rex,.*', '^richtek,.*', '^ricoh,.*', '^rikomagic,.*', '^riot,.*', '^riscv,.*', '^rockchip,.*', '^rocktech,.*', '^rohm,.*', '^ronbo,.*', '^ronetix,.*', '^roofull,.*', '^roseapplepi,.*', '^rve,.*', '^saef,.*', '^sakurapi,.*', '^samsung,.*', '^samtec,.*', '^sancloud,.*', '^sandisk,.*', '^satoz,.*', '^sbs,.*', '^schindler,.*', '^schneider,.*', '^schulercontrol,.*', '^sciosense,.*', '^sdmc,.*', '^seagate,.*', '^seeed,.*', '^seirobotics,.*', '^semtech,.*', '^senseair,.*', '^sensirion,.*', '^sensortek,.*', '^sercomm,.*', '^sff,.*', '^sgd,.*', '^sgmicro,.*', '^sgx,.*', '^sharp,.*', '^shift,.*', '^shimafuji,.*', '^shineworld,.*', '^shiratech,.*', '^si-en,.*', '^si-linux,.*', '^sielaff,.*', '^siemens,.*', '^sifive,.*', '^siflower,.*', '^sigma,.*', '^sii,.*', '^sil,.*', '^silabs,.*', '^silan,.*', '^silead,.*', '^silergy,.*', '^silex-insight,.*', '^siliconfile,.*', '^siliconmitus,.*', '^silvaco,.*', '^simtek,.*', '^sinlinx,.*', '^sinovoip,.*', '^sinowealth,.*', '^sipeed,.*', '^sirf,.*', '^sis
>  ,.*', '^sitronix,.*', '^skov,.*', '^skyworks,.*', '^smartfiber,.*', '^smartlabs,.*', '^smartrg,.*', '^smi,.*', '^smsc,.*', '^snps,.*', '^sochip,.*', '^socionext,.*', '^solidrun,.*', '^solomon,.*', '^somfy,.*', '^sony,.*', '^sophgo,.*', '^sourceparts,.*', '^spacemit,.*', '^spansion,.*', '^sparkfun,.*', '^spinalhdl,.*', '^sprd,.*', '^square,.*', '^ssi,.*', '^sst,.*', '^sstar,.*', '^st,.*', '^st-ericsson,.*', '^starfive,.*', '^starry,.*', '^startek,.*', '^starterkit,.*', '^ste,.*', '^stericsson,.*', '^storlink,.*', '^storm,.*', '^storopack,.*', '^summit,.*', '^sunchip,.*', '^sundance,.*', '^sunplus,.*', '^supermicro,.*', '^swir,.*', '^syna,.*', '^synaptics,.*', '^synology,.*', '^synopsys,.*', '^taos,.*', '^tbs,.*', '^tbs-biometrics,.*', '^tcg,.*', '^tcl,.*', '^tcs,.*', '^tcu,.*', '^tdo,.*', '^team-source-display,.*', '^technexion,.*', '^technologic,.*', '^techstar,.*', '^techwell,.*', '^teejet,.*', '^teltonika,.*', '^tempo,.*', '^tenda,.*', '^terasic,.*', '^tesla,.*', '^test,.*', '^tfc
>  ,.*', '^thead,.*', '^thine,.*', '^thingyjp,.*', '^thundercomm,.*', '^thwc,.*', '^ti,.*', '^tianma,.*', '^tlm,.*', '^tmt,.*', '^topeet,.*', '^topic,.*', '^topland,.*', '^toppoly,.*', '^topwise,.*', '^toradex,.*', '^toshiba,.*', '^toumaz,.*', '^tpk,.*', '^tplink,.*', '^tpo,.*', '^tq,.*', '^transpeed,.*', '^traverse,.*', '^tronfy,.*', '^tronsmart,.*', '^truly,.*', '^tsd,.*', '^turing,.*', '^tyan,.*', '^tyhx,.*', '^u-blox,.*', '^u-boot,.*', '^ubnt,.*', '^ucrobotics,.*', '^udoo,.*', '^ufispace,.*', '^ugoos,.*', '^ultratronik,.*', '^uni-t,.*', '^uniwest,.*', '^upisemi,.*', '^urt,.*', '^usi,.*', '^usr,.*', '^utoo,.*', '^v3,.*', '^vaisala,.*', '^valve,.*', '^vamrs,.*', '^variscite,.*', '^vdl,.*', '^vertexcom,.*', '^via,.*', '^vialab,.*', '^vicor,.*', '^videostrong,.*', '^virtio,.*', '^virtual,.*', '^vishay,.*', '^visionox,.*', '^vitesse,.*', '^vivante,.*', '^vivax,.*', '^vocore,.*', '^voipac,.*', '^voltafield,.*', '^vot,.*', '^vscom,.*', '^vxt,.*', '^wacom,.*', '^wanchanglong,.*', '^wand,.*
>  ', '^waveshare,.*', '^wd,.*', '^we,.*', '^welltech,.*', '^wetek,.*', '^wexler,.*', '^whwave,.*', '^wi2wi,.*', '^widora,.*', '^wiligear,.*', '^willsemi,.*', '^winbond,.*', '^wingtech,.*', '^winlink,.*', '^winsen,.*', '^winstar,.*', '^wirelesstag,.*', '^wits,.*', '^wlf,.*', '^wm,.*', '^wobo,.*', '^wolfvision,.*', '^x-powers,.*', '^xen,.*', '^xes,.*', '^xiaomi,.*', '^xicor,.*', '^xillybus,.*', '^xingbangda,.*', '^xinpeng,.*', '^xiphera,.*', '^xlnx,.*', '^xnano,.*', '^xunlong,.*', '^xylon,.*', '^yadro,.*', '^yamaha,.*', '^yes-optoelectronics,.*', '^yic,.*', '^yiming,.*', '^ylm,.*', '^yna,.*', '^yones-toptech,.*', '^ys,.*', '^ysoft,.*', '^yuridenki,.*', '^yuzukihd,.*', '^zarlink,.*', '^zealz,.*', '^zeitec,.*', '^zidoo,.*', '^zii,.*', '^zinitix,.*', '^zkmagic,.*', '^zte,.*', '^zyxel,.*'
> 	from schema $id: http://devicetree.org/schemas/vendor-prefixes.yaml
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: scp at 10720000 (mediatek,mt8188-scp-dual): reg-names: ['cfg'] is too short
> 	from schema $id: http://devicetree.org/schemas/remoteproc/mtk,scp.yaml
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: scp at 10720000 (mediatek,mt8188-scp-dual): reg: [[0, 275906560, 0, 917504]] is too short
> 	from schema $id: http://devicetree.org/schemas/remoteproc/mtk,scp.yaml
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: scp at 10720000 (mediatek,mt8188-scp-dual): reg-names: ['cfg'] is too short
> 	from schema $id: http://devicetree.org/schemas/remoteproc/mtk,scp.yaml
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: mmc at 11250000 (mediatek,mt8188-mmc): Unevaluated properties are not allowed ('cap-sdio-async-int', 'eint-gpios', 'enable-sdio-wakeup' were unexpected)
> 	from schema $id: http://devicetree.org/schemas/mmc/mtk-sd.yaml
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'AVDD-supply' is a required property
> 	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'CPVDD-supply' is a required property
> 	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'DBVDD-supply' is a required property
> 	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'DCVDD-supply' is a required property
> 	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'MICVDD-supply' is a required property
> 	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'PLLVDD-supply' is a required property
> 	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'SPKVDD1-supply' is a required property
> 	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'SPKVDD2-supply' is a required property
> 	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: i2c at 11e01000 (mediatek,mt8188-i2c): pinctrl-names: ['default', 'default'] has non-unique elements
> 	from schema $id: http://devicetree.org/schemas/pinctrl/pinctrl-consumer.yaml
> arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: panel-dsi0 (tianma,tm070jdhg30): 'power-supply' is a required property
> 	from schema $id: http://devicetree.org/schemas/display/panel/panel-simple.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: i2c0-gpio-pins: pins-gpio: {'pinmux': [1536], 'bias-pull-up': 203, 'drive-strength-microamp': [1000]} is not of type 'array'
> 	from schema $id: http://devicetree.org/schemas/gpio/gpio-consumer.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: pmic (mediatek,mt6359): '#sound-dai-cells' does not match any of the regexes: '^pinctrl-[0-9]+$'
> 	from schema $id: http://devicetree.org/schemas/mfd/mediatek,mt6397.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): pmic at 6:reg:0: [6, 0, 11] is too long
> 	from schema $id: http://devicetree.org/schemas/spmi/mtk,spmi-mtk-pmif.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): #address-cells: 2 was expected
> 	from schema $id: http://devicetree.org/schemas/spmi/mtk,spmi-mtk-pmif.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): #size-cells: 0 was expected
> 	from schema $id: http://devicetree.org/schemas/spmi/mtk,spmi-mtk-pmif.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): Unevaluated properties are not allowed ('#address-cells', '#size-cells', 'pmic at 6' were unexpected)
> 	from schema $id: http://devicetree.org/schemas/spmi/mtk,spmi-mtk-pmif.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): pmic at 6:reg:0: [6, 0, 11] is too long
> 	from schema $id: http://devicetree.org/schemas/spmi/spmi.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): #address-cells: 2 was expected
> 	from schema $id: http://devicetree.org/schemas/spmi/spmi.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: spmi at 10027000 (mediatek,mt8188-spmi): #size-cells: 0 was expected
> 	from schema $id: http://devicetree.org/schemas/spmi/spmi.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: pmic at 6 (mediatek,mt6315-regulator): regulators:vbuck1: Unevaluated properties are not allowed ('mtk,combined-regulator', 'regulator-compatible' were unexpected)
> 	from schema $id: http://devicetree.org/schemas/regulator/mt6315-regulator.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: pmic at 6 (mediatek,mt6315-regulator): regulators:vbuck3: Unevaluated properties are not allowed ('regulator-compatible' was unexpected)
> 	from schema $id: http://devicetree.org/schemas/regulator/mt6315-regulator.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: pmic at 6 (mediatek,mt6315-regulator): regulators:vbuck4: Unevaluated properties are not allowed ('regulator-compatible' was unexpected)
> 	from schema $id: http://devicetree.org/schemas/regulator/mt6315-regulator.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: vbuck1: 'mtk,combined-regulator' does not match any of the regexes: '^#.*', '^(at25|bm|devbus|dmacap|dsa|exynos|fsi[ab]|gpio-fan|gpio-key|gpio|gpmc|hdmi|i2c-gpio),.*', '^(keypad|m25p|max8952|max8997|max8998|mpmc),.*', '^(pciclass|pinctrl-single|#pinctrl-single|PowerPC),.*', '^(pl022|pxa-mmc|rcar_sound|rotary-encoder|s5m8767|sdhci),.*', '^(simple-audio-card|st-plgpio|st-spics|ts),.*', '^100ask,.*', '^70mai,.*', '^8dev,.*', '^GEFanuc,.*', '^IBM,.*', '^ORCL,.*', '^SUNW,.*', '^[a-zA-Z0-9#_][a-zA-Z0-9#+\-._@]{0,63}$', '^[a-zA-Z0-9+\-._]*@[0-9a-zA-Z,]*$', '^abb,.*', '^abilis,.*', '^abracon,.*', '^abt,.*', '^acbel,.*', '^acelink,.*', '^acer,.*', '^acme,.*', '^actions,.*', '^actiontec,.*', '^active-semi,.*', '^ad,.*', '^adafruit,.*', '^adapteva,.*', '^adaptrum,.*', '^adh,.*', '^adi,.*', '^adieng,.*', '^admatec,.*', '^advantech,.*', '^aeroflexgaisler,.*', '^aesop,.*', '^airoha,.*', '^al,.*', '^alcatel,.*', '^aldec,.*', '^alfa-network,.*'
>  , '^allegro,.*', '^allegromicro,.*', '^alliedtelesis,.*', '^alliedvision,.*', '^allo,.*', '^allwinner,.*', '^alphascale,.*', '^alps,.*', '^alt,.*', '^altr,.*', '^amarula,.*', '^amazon,.*', '^amcc,.*', '^amd,.*', '^amediatech,.*', '^amlogic,.*', '^ampere,.*', '^amphenol,.*', '^ampire,.*', '^ams,.*', '^amstaos,.*', '^analogix,.*', '^anbernic,.*', '^andestech,.*', '^anvo,.*', '^aoly,.*', '^aosong,.*', '^apm,.*', '^apple,.*', '^aptina,.*', '^arasan,.*', '^archermind,.*', '^arcom,.*', '^arctic,.*', '^arcx,.*', '^argon40,.*', '^ariaboard,.*', '^aries,.*', '^arm,.*', '^armadeus,.*', '^armsom,.*', '^arrow,.*', '^artesyn,.*', '^asahi-kasei,.*', '^asc,.*', '^asix,.*', '^aspeed,.*', '^asrock,.*', '^asteralabs,.*', '^asus,.*', '^atheros,.*', '^atlas,.*', '^atmel,.*', '^auo,.*', '^auvidea,.*', '^avago,.*', '^avia,.*', '^avic,.*', '^avnet,.*', '^awinic,.*', '^axentia,.*', '^axiado,.*', '^axis,.*', '^azoteq,.*', '^azw,.*', '^baikal,.*', '^bananapi,.*', '^beacon,.*', '^beagle,.*', '^belling,.*', '^
>  bestar,.*', '^bhf,.*', '^bigtreetech,.*', '^bitmain,.*', '^blaize,.*', '^bluegiga,.*', '^blutek,.*', '^boe,.*', '^bosch,.*', '^boundary,.*', '^brcm,.*', '^broadmobi,.*', '^bsh,.*', '^bticino,.*', '^buffalo,.*', '^buglabs,.*', '^bur,.*', '^bytedance,.*', '^calamp,.*', '^calao,.*', '^calaosystems,.*', '^calxeda,.*', '^cameo,.*', '^canaan,.*', '^caninos,.*', '^capella,.*', '^cascoda,.*', '^catalyst,.*', '^cavium,.*', '^cct,.*', '^cdns,.*', '^cdtech,.*', '^cellwise,.*', '^ceva,.*', '^chargebyte,.*', '^checkpoint,.*', '^chefree,.*', '^chipidea,.*', '^chipone,.*', '^chipspark,.*', '^chongzhou,.*', '^chrontel,.*', '^chrp,.*', '^chunghwa,.*', '^chuwi,.*', '^ciaa,.*', '^cirrus,.*', '^cisco,.*', '^cix,.*', '^clockwork,.*', '^cloos,.*', '^cloudengines,.*', '^cnm,.*', '^cnxt,.*', '^colorfly,.*', '^compal,.*', '^compulab,.*', '^comvetia,.*', '^congatec,.*', '^coolpi,.*', '^coreriver,.*', '^corpro,.*', '^cortina,.*', '^cosmic,.*', '^crane,.*', '^creative,.*', '^crystalfontz,.*', '^csky,.*', '^cso
>  t,.*', '^csq,.*', '^csr,.*', '^ctera,.*', '^ctu,.*', '^cubietech,.*', '^cudy,.*', '^cui,.*', '^cypress,.*', '^cyx,.*', '^cznic,.*', '^dallas,.*', '^dataimage,.*', '^davicom,.*', '^deepcomputing,.*', '^dell,.*', '^delta,.*', '^densitron,.*', '^denx,.*', '^devantech,.*', '^dfi,.*', '^dfrobot,.*', '^dh,.*', '^difrnce,.*', '^digi,.*', '^digilent,.*', '^dimonoff,.*', '^diodes,.*', '^dioo,.*', '^djn,.*', '^dlc,.*', '^dlg,.*', '^dlink,.*', '^dmo,.*', '^domintech,.*', '^dongwoon,.*', '^dptechnics,.*', '^dragino,.*', '^dream,.*', '^ds,.*', '^dserve,.*', '^dynaimage,.*', '^ea,.*', '^ebang,.*', '^ebbg,.*', '^ebs-systart,.*', '^ebv,.*', '^eckelmann,.*', '^econet,.*', '^edgeble,.*', '^edimax,.*', '^edt,.*', '^ees,.*', '^eeti,.*', '^egnite,.*', '^einfochips,.*', '^eink,.*', '^elan,.*', '^element14,.*', '^elgin,.*', '^elida,.*', '^elimo,.*', '^elpida,.*', '^embedfire,.*', '^embest,.*', '^emcraft,.*', '^emlid,.*', '^emmicro,.*', '^empire-electronix,.*', '^emtrion,.*', '^enbw,.*', '^enclustra,.*', '
>  ^endian,.*', '^endless,.*', '^ene,.*', '^energymicro,.*', '^engicam,.*', '^engleder,.*', '^epcos,.*', '^epfl,.*', '^epson,.*', '^esp,.*', '^est,.*', '^eswin,.*', '^ettus,.*', '^eukrea,.*', '^everest,.*', '^everspin,.*', '^evervision,.*', '^exar,.*', '^excito,.*', '^exegin,.*', '^ezchip,.*', '^ezurio,.*', '^facebook,.*', '^fairchild,.*', '^fairphone,.*', '^faraday,.*', '^fascontek,.*', '^fastrax,.*', '^fcs,.*', '^feixin,.*', '^feiyang,.*', '^fii,.*', '^firefly,.*', '^flipkart,.*', '^focaltech,.*', '^forlinx,.*', '^foursemi,.*', '^foxlink,.*', '^freebox,.*', '^freecom,.*', '^frida,.*', '^friendlyarm,.*', '^fsl,.*', '^fujitsu,.*', '^fxtec,.*', '^galaxycore,.*', '^gameforce,.*', '^gardena,.*', '^gateway,.*', '^gateworks,.*', '^gcw,.*', '^ge,.*', '^geekbuying,.*', '^gef,.*', '^gehc,.*', '^gemei,.*', '^gemtek,.*', '^genesys,.*', '^genexis,.*', '^geniatech,.*', '^giantec,.*', '^giantplus,.*', '^glinet,.*', '^globalscale,.*', '^globaltop,.*', '^gmt,.*', '^gocontroll,.*', '^goldelico,.*', '^
>  goodix,.*', '^google,.*', '^goramo,.*', '^gplus,.*', '^grinn,.*', '^grmn,.*', '^gumstix,.*', '^gw,.*', '^hannstar,.*', '^haochuangyi,.*', '^haoyu,.*', '^hardkernel,.*', '^hce,.*', '^headacoustics,.*', '^hechuang,.*', '^hideep,.*', '^himax,.*', '^hinlink,.*', '^hirschmann,.*', '^hisi,.*', '^hisilicon,.*', '^hit,.*', '^hitex,.*', '^holt,.*', '^holtek,.*', '^honestar,.*', '^honeywell,.*', '^hoperf,.*', '^hoperun,.*', '^hp,.*', '^hpe,.*', '^hsg,.*', '^htc,.*', '^huawei,.*', '^hugsun,.*', '^huiling,.*', '^hwacom,.*', '^hxt,.*', '^hycon,.*', '^hydis,.*', '^hynitron,.*', '^hynix,.*', '^hyundai,.*', '^i2se,.*', '^ibm,.*', '^icplus,.*', '^idt,.*', '^iei,.*', '^ifi,.*', '^ilitek,.*', '^imagis,.*', '^img,.*', '^imi,.*', '^inanbo,.*', '^incircuit,.*', '^incostartec,.*', '^indiedroid,.*', '^inet-tek,.*', '^infineon,.*', '^inforce,.*', '^ingenic,.*', '^ingrasys,.*', '^injoinic,.*', '^innocomm,.*', '^innolux,.*', '^inside-secure,.*', '^insignal,.*', '^inspur,.*', '^intel,.*', '^intercontrol,.*', '
>  ^invensense,.*', '^inventec,.*', '^inversepath,.*', '^iom,.*', '^irondevice,.*', '^isee,.*', '^isil,.*', '^issi,.*', '^ite,.*', '^itead,.*', '^itian,.*', '^ivo,.*', '^iwave,.*', '^jadard,.*', '^jasonic,.*', '^jdi,.*', '^jedec,.*', '^jenson,.*', '^jesurun,.*', '^jethome,.*', '^jianda,.*', '^jide,.*', '^joz,.*', '^jty,.*', '^kam,.*', '^karo,.*', '^keithkoep,.*', '^keymile,.*', '^khadas,.*', '^kiebackpeter,.*', '^kinetic,.*', '^kingdisplay,.*', '^kingnovel,.*', '^kionix,.*', '^kobo,.*', '^kobol,.*', '^koe,.*', '^kontron,.*', '^kosagi,.*', '^kvg,.*', '^kyo,.*', '^lacie,.*', '^laird,.*', '^lamobo,.*', '^lantiq,.*', '^lattice,.*', '^lckfb,.*', '^lctech,.*', '^leadtek,.*', '^leez,.*', '^lego,.*', '^lemaker,.*', '^lenovo,.*', '^lg,.*', '^lgphilips,.*', '^libretech,.*', '^licheepi,.*', '^linaro,.*', '^lincolntech,.*', '^lineartechnology,.*', '^linksprite,.*', '^linksys,.*', '^linutronix,.*', '^linux,.*', '^linx,.*', '^liontron,.*', '^liteon,.*', '^litex,.*', '^lltc,.*', '^logicpd,.*', '^logi
>  ctechno,.*', '^longcheer,.*', '^lontium,.*', '^loongmasses,.*', '^loongson,.*', '^lsi,.*', '^luckfox,.*', '^lunzn,.*', '^luxul,.*', '^lwn,.*', '^lxa,.*', '^m5stack,.*', '^macnica,.*', '^mantix,.*', '^mapleboard,.*', '^marantec,.*', '^marvell,.*', '^maxbotix,.*', '^maxim,.*', '^maxlinear,.*', '^maxtor,.*', '^mayqueen,.*', '^mbvl,.*', '^mcube,.*', '^meas,.*', '^mecer,.*', '^mediatek,.*', '^megachips,.*', '^mele,.*', '^melexis,.*', '^melfas,.*', '^mellanox,.*', '^memsensing,.*', '^memsic,.*', '^menlo,.*', '^mentor,.*', '^meraki,.*', '^merrii,.*', '^methode,.*', '^micrel,.*', '^microchip,.*', '^microcrystal,.*', '^micron,.*', '^microsoft,.*', '^microsys,.*', '^microtips,.*', '^mikroe,.*', '^mikrotik,.*', '^milkv,.*', '^miniand,.*', '^minix,.*', '^mips,.*', '^miramems,.*', '^mitsubishi,.*', '^mitsumi,.*', '^mixel,.*', '^miyoo,.*', '^mntre,.*', '^mobileye,.*', '^modtronix,.*', '^moortec,.*', '^mosaixtech,.*', '^motorcomm,.*', '^motorola,.*', '^moxa,.*', '^mpl,.*', '^mps,.*', '^mqmaker,.*'
>  , '^mrvl,.*', '^mscc,.*', '^msi,.*', '^mstar,.*', '^mti,.*', '^multi-inno,.*', '^mundoreader,.*', '^murata,.*', '^mxic,.*', '^mxicy,.*', '^myir,.*', '^national,.*', '^neardi,.*', '^nec,.*', '^neofidelity,.*', '^neonode,.*', '^netcube,.*', '^netgear,.*', '^netlogic,.*', '^netron-dy,.*', '^netronix,.*', '^netxeon,.*', '^neweast,.*', '^newhaven,.*', '^newvision,.*', '^nexbox,.*', '^nextthing,.*', '^ni,.*', '^nicera,.*', '^nintendo,.*', '^nlt,.*', '^nokia,.*', '^nordic,.*', '^nothing,.*', '^novatech,.*', '^novatek,.*', '^novtech,.*', '^numonyx,.*', '^nutsboard,.*', '^nuvoton,.*', '^nvd,.*', '^nvidia,.*', '^nxp,.*', '^oceanic,.*', '^ocs,.*', '^oct,.*', '^okaya,.*', '^oki,.*', '^olimex,.*', '^olpc,.*', '^oneplus,.*', '^onie,.*', '^onion,.*', '^onnn,.*', '^ontat,.*', '^opalkelly,.*', '^openailab,.*', '^opencores,.*', '^openembed,.*', '^openpandora,.*', '^openrisc,.*', '^openwrt,.*', '^option,.*', '^oranth,.*', '^orisetech,.*', '^ortustech,.*', '^osddisplays,.*', '^osmc,.*', '^ouya,.*', '^o
>  verkiz,.*', '^ovti,.*', '^oxsemi,.*', '^ozzmaker,.*', '^panasonic,.*', '^parade,.*', '^parallax,.*', '^particle,.*', '^pda,.*', '^pegatron,.*', '^pericom,.*', '^pervasive,.*', '^phicomm,.*', '^phontech,.*', '^phytec,.*', '^picochip,.*', '^pinctrl-[0-9]+$', '^pine64,.*', '^pineriver,.*', '^pixcir,.*', '^plantower,.*', '^plathome,.*', '^plda,.*', '^plx,.*', '^ply,.*', '^pni,.*', '^pocketbook,.*', '^polaroid,.*', '^polyhex,.*', '^pool[0-3],.*', '^portwell,.*', '^poslab,.*', '^pov,.*', '^powertip,.*', '^powervr,.*', '^powkiddy,.*', '^pri,.*', '^primeview,.*', '^primux,.*', '^probox2,.*', '^prt,.*', '^pulsedlight,.*', '^purism,.*', '^puya,.*', '^qca,.*', '^qcom,.*', '^qemu,.*', '^qi,.*', '^qiaodian,.*', '^qihua,.*', '^qishenglong,.*', '^qnap,.*', '^quanta,.*', '^radxa,.*', '^raidsonic,.*', '^ralink,.*', '^ramtron,.*', '^raspberrypi,.*', '^raumfeld,.*', '^raydium,.*', '^rda,.*', '^realtek,.*', '^relfor,.*', '^remarkable,.*', '^renesas,.*', '^rervision,.*', '^retronix,.*', '^revotics,.*', 
>  '^rex,.*', '^richtek,.*', '^ricoh,.*', '^rikomagic,.*', '^riot,.*', '^riscv,.*', '^rockchip,.*', '^rocktech,.*', '^rohm,.*', '^ronbo,.*', '^ronetix,.*', '^roofull,.*', '^roseapplepi,.*', '^rve,.*', '^saef,.*', '^sakurapi,.*', '^samsung,.*', '^samtec,.*', '^sancloud,.*', '^sandisk,.*', '^satoz,.*', '^sbs,.*', '^schindler,.*', '^schneider,.*', '^schulercontrol,.*', '^sciosense,.*', '^sdmc,.*', '^seagate,.*', '^seeed,.*', '^seirobotics,.*', '^semtech,.*', '^senseair,.*', '^sensirion,.*', '^sensortek,.*', '^sercomm,.*', '^sff,.*', '^sgd,.*', '^sgmicro,.*', '^sgx,.*', '^sharp,.*', '^shift,.*', '^shimafuji,.*', '^shineworld,.*', '^shiratech,.*', '^si-en,.*', '^si-linux,.*', '^sielaff,.*', '^siemens,.*', '^sifive,.*', '^siflower,.*', '^sigma,.*', '^sii,.*', '^sil,.*', '^silabs,.*', '^silan,.*', '^silead,.*', '^silergy,.*', '^silex-insight,.*', '^siliconfile,.*', '^siliconmitus,.*', '^silvaco,.*', '^simtek,.*', '^sinlinx,.*', '^sinovoip,.*', '^sinowealth,.*', '^sipeed,.*', '^sirf,.*', '^sis
>  ,.*', '^sitronix,.*', '^skov,.*', '^skyworks,.*', '^smartfiber,.*', '^smartlabs,.*', '^smartrg,.*', '^smi,.*', '^smsc,.*', '^snps,.*', '^sochip,.*', '^socionext,.*', '^solidrun,.*', '^solomon,.*', '^somfy,.*', '^sony,.*', '^sophgo,.*', '^sourceparts,.*', '^spacemit,.*', '^spansion,.*', '^sparkfun,.*', '^spinalhdl,.*', '^sprd,.*', '^square,.*', '^ssi,.*', '^sst,.*', '^sstar,.*', '^st,.*', '^st-ericsson,.*', '^starfive,.*', '^starry,.*', '^startek,.*', '^starterkit,.*', '^ste,.*', '^stericsson,.*', '^storlink,.*', '^storm,.*', '^storopack,.*', '^summit,.*', '^sunchip,.*', '^sundance,.*', '^sunplus,.*', '^supermicro,.*', '^swir,.*', '^syna,.*', '^synaptics,.*', '^synology,.*', '^synopsys,.*', '^taos,.*', '^tbs,.*', '^tbs-biometrics,.*', '^tcg,.*', '^tcl,.*', '^tcs,.*', '^tcu,.*', '^tdo,.*', '^team-source-display,.*', '^technexion,.*', '^technologic,.*', '^techstar,.*', '^techwell,.*', '^teejet,.*', '^teltonika,.*', '^tempo,.*', '^tenda,.*', '^terasic,.*', '^tesla,.*', '^test,.*', '^tfc
>  ,.*', '^thead,.*', '^thine,.*', '^thingyjp,.*', '^thundercomm,.*', '^thwc,.*', '^ti,.*', '^tianma,.*', '^tlm,.*', '^tmt,.*', '^topeet,.*', '^topic,.*', '^topland,.*', '^toppoly,.*', '^topwise,.*', '^toradex,.*', '^toshiba,.*', '^toumaz,.*', '^tpk,.*', '^tplink,.*', '^tpo,.*', '^tq,.*', '^transpeed,.*', '^traverse,.*', '^tronfy,.*', '^tronsmart,.*', '^truly,.*', '^tsd,.*', '^turing,.*', '^tyan,.*', '^tyhx,.*', '^u-blox,.*', '^u-boot,.*', '^ubnt,.*', '^ucrobotics,.*', '^udoo,.*', '^ufispace,.*', '^ugoos,.*', '^ultratronik,.*', '^uni-t,.*', '^uniwest,.*', '^upisemi,.*', '^urt,.*', '^usi,.*', '^usr,.*', '^utoo,.*', '^v3,.*', '^vaisala,.*', '^valve,.*', '^vamrs,.*', '^variscite,.*', '^vdl,.*', '^vertexcom,.*', '^via,.*', '^vialab,.*', '^vicor,.*', '^videostrong,.*', '^virtio,.*', '^virtual,.*', '^vishay,.*', '^visionox,.*', '^vitesse,.*', '^vivante,.*', '^vivax,.*', '^vocore,.*', '^voipac,.*', '^voltafield,.*', '^vot,.*', '^vscom,.*', '^vxt,.*', '^wacom,.*', '^wanchanglong,.*', '^wand,.*
>  ', '^waveshare,.*', '^wd,.*', '^we,.*', '^welltech,.*', '^wetek,.*', '^wexler,.*', '^whwave,.*', '^wi2wi,.*', '^widora,.*', '^wiligear,.*', '^willsemi,.*', '^winbond,.*', '^wingtech,.*', '^winlink,.*', '^winsen,.*', '^winstar,.*', '^wirelesstag,.*', '^wits,.*', '^wlf,.*', '^wm,.*', '^wobo,.*', '^wolfvision,.*', '^x-powers,.*', '^xen,.*', '^xes,.*', '^xiaomi,.*', '^xicor,.*', '^xillybus,.*', '^xingbangda,.*', '^xinpeng,.*', '^xiphera,.*', '^xlnx,.*', '^xnano,.*', '^xunlong,.*', '^xylon,.*', '^yadro,.*', '^yamaha,.*', '^yes-optoelectronics,.*', '^yic,.*', '^yiming,.*', '^ylm,.*', '^yna,.*', '^yones-toptech,.*', '^ys,.*', '^ysoft,.*', '^yuridenki,.*', '^yuzukihd,.*', '^zarlink,.*', '^zealz,.*', '^zeitec,.*', '^zidoo,.*', '^zii,.*', '^zinitix,.*', '^zkmagic,.*', '^zte,.*', '^zyxel,.*'
> 	from schema $id: http://devicetree.org/schemas/vendor-prefixes.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: scp at 10720000 (mediatek,mt8188-scp-dual): reg-names: ['cfg'] is too short
> 	from schema $id: http://devicetree.org/schemas/remoteproc/mtk,scp.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: scp at 10720000 (mediatek,mt8188-scp-dual): reg: [[0, 275906560, 0, 917504]] is too short
> 	from schema $id: http://devicetree.org/schemas/remoteproc/mtk,scp.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: scp at 10720000 (mediatek,mt8188-scp-dual): reg-names: ['cfg'] is too short
> 	from schema $id: http://devicetree.org/schemas/remoteproc/mtk,scp.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: mmc at 11250000 (mediatek,mt8188-mmc): Unevaluated properties are not allowed ('cap-sdio-async-int', 'eint-gpios', 'enable-sdio-wakeup' were unexpected)
> 	from schema $id: http://devicetree.org/schemas/mmc/mtk-sd.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'AVDD-supply' is a required property
> 	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'CPVDD-supply' is a required property
> 	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'DBVDD-supply' is a required property
> 	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'DCVDD-supply' is a required property
> 	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'MICVDD-supply' is a required property
> 	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'PLLVDD-supply' is a required property
> 	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'SPKVDD1-supply' is a required property
> 	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: codec at 1a (wlf,wm8962): 'SPKVDD2-supply' is a required property
> 	from schema $id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: i2c at 11e01000 (mediatek,mt8188-i2c): pinctrl-names: ['default', 'default'] has non-unique elements
> 	from schema $id: http://devicetree.org/schemas/pinctrl/pinctrl-consumer.yaml
> arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: panel-dsi0 (tianma,tm070jdhg30): 'power-supply' is a required property
> 	from schema $id: http://devicetree.org/schemas/display/panel/panel-simple.yaml

Sorry my command was only checking the mediatek schema, I've fixed those
issues and I am now in par with the other Genio EVK dts. Meaning the
only warnings left are from the dtsi, see below:
/home/data/upstream/linux/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: pmic (mediatek,mt6359): '#sound-dai-cells' does not match any of the regexes: '^pinctrl-[0-9]+$'
        from schema $id: http://devicetree.org/schemas/mfd/mediatek,mt6397.yaml#
/home/data/upstream/linux/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: scp at 10720000 (mediatek,mt8188-scp-dual): reg-names: ['cfg'] is too short
        from schema $id: http://devicetree.org/schemas/remoteproc/mtk,scp.yaml#
/home/data/upstream/linux/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: scp at 10720000 (mediatek,mt8188-scp-dual): reg: [[0, 275906560, 0, 917504]] is too short
        from schema $id: http://devicetree.org/schemas/remoteproc/mtk,scp.yaml#
/home/data/upstream/linux/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: scp at 10720000 (mediatek,mt8188-scp-dual): reg-names: ['cfg'] is too short
        from schema $id: http://devicetree.org/schemas/remoteproc/mtk,scp.yaml#

Here is what I see for mt8390-genio-700-evk.dtb:
/home/data/upstream/linux/arch/arm64/boot/dts/mediatek/mt8390-genio-700-evk.dtb: pmic (mediatek,mt6359): '#sound-dai-cells' does not match any of the regexes: '^pinctrl-[0-9]+$'
        from schema $id: http://devicetree.org/schemas/mfd/mediatek,mt6397.yaml#
/home/data/upstream/linux/arch/arm64/boot/dts/mediatek/mt8390-genio-700-evk.dtb: scp at 10720000 (mediatek,mt8188-scp-dual): reg-names: ['cfg'] is too short
        from schema $id: http://devicetree.org/schemas/remoteproc/mtk,scp.yaml#
/home/data/upstream/linux/arch/arm64/boot/dts/mediatek/mt8390-genio-700-evk.dtb: scp at 10720000 (mediatek,mt8188-scp-dual): reg: [[0, 275906560, 0, 917504]] is too short
        from schema $id: http://devicetree.org/schemas/remoteproc/mtk,scp.yaml#
/home/data/upstream/linux/arch/arm64/boot/dts/mediatek/mt8390-genio-700-evk.dtb: scp at 10720000 (mediatek,mt8188-scp-dual): reg-names: ['cfg'] is too short
        from schema $id: http://devicetree.org/schemas/remoteproc/mtk,scp.yaml#

I'll send a v5 shortly.

Regards,
Gary


From jwerner at chromium.org  Tue Dec  2 13:58:11 2025
From: jwerner at chromium.org (Julius Werner)
Date: Tue, 2 Dec 2025 13:58:11 -0800
Subject: Proposal: Officially allow "incomplete" trees as a base
In-Reply-To: <aS66WcLPm6e5rdyk@shell.armlinux.org.uk>
References: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
 <aS66WcLPm6e5rdyk@shell.armlinux.org.uk>
Message-ID: <CAODwPW-sBSZfzbTnYLcGr2sN=+5p+okUeJEJeVvJOHCx3JbOgg@mail.gmail.com>

>> Is there really a need to merge the compatible strings in your case?
>
> Well, you could just require duplicating an overlay N times for N bases, but that doesn't scale

I think my question was more along the lines of "is there actually a
reason why the combined compatible string needs to be that accurate"
(i.e. contain the right "socvendor,mysoc-rev1" or
"socvendor,mysoc-rev2"). What is the purpose of having that string in
there? It wouldn't be used for matching which DTB(O) to load in this
case because we're already past that step. It's not used by the kernel
directly for anything as far as I know. Is it used by userspace
programs which parse /proc/device-tree/compatible in order to detect
which SoC revision they're running on? Because that's the only use
case I could think of that really remains, but I'd argue that the
compatible string is a pretty poor vehicle for things like that (it
would be easier to parse and use to just put a `soc-revision = <1>`
property somewhere). So if this is the only problem I'd say maybe just
don't use the board compatible string for that, don't expect to be
able to find such details in there accurately. But if we do think it
needs to be that accurate for some reason, then I'd suggest platforms
like this (which should be rather few, e.g. only those that really
have a socketable SoC with differentiations that are so compatible
that other than this identification information itself it doesn't
require any device tree differences) should simply have their
bootloaders rewrite the compatible string into the right format with
all the necessary information manually, rather than expect the overlay
application process to create it correctly.

> There is a proposal here[1]. It's simple, but I do wonder if looking at the root compatible only is too narrow of a view. An overlay could target a connector compatible for example.

This seems to just assume that every overlay matches exactly one base
tree, that kinda defeats the purpose of overlays in this case (sharing
data between multiple base trees). For our purposes we need a much
more complicated system that is able to stitch together an arbitrary
number of overlays based on identifiers specific to our platform.

> However, it isn't that simple. For example, when the Hummingboard2 is
> used with the iMX6Q SoC, there's a SATA device present in the SoC level
> that needs Hummingboard2 specific properties to tune the signal
> waveform. However, iMX6DL doesn't have this SATA device in silicon, so
> the node doesn't exist in the base SoC DT file. The situation is the
> same for Hummingboard, but the tuning parameters, being board specific,
> are different.

I think you would solve this simply by having more overlays? In that
situation you can have a imx6q.dtbo, imx6dl.dtbo and
hummingboard2.dtbo for the generic nodes and properties relating to
each of these components, and then a imx6q-hummingboard2.dtbo
specifically for the SATA tuning parameters of that SoC+board
combination. Your bootloader then just needs to figure out which of
those to load for which platform. (Of course there also has to be a
toplevel DTB, so if you don't have any further revision or SKU
differentiation above that then imx6q-hummingboard2.dtb could simply
be your toplevel DTB, containing those tuning parameters, and the rest
could be overlays. imx6dl-hummingboard2.dtb would then be an empty
toplevel DTB (save for the compatible string) if everything else that
makes up the platform gets provided by the overlays.)

> The other issue would be the /model property - for example:
>
>         model = "SolidRun HummingBoard2 Solo/DualLite";
>         model = "SolidRun HummingBoard2 Solo/DualLite (1.5som+emmc)";
>         model = "SolidRun HummingBoard2 Solo/DualLite (1.5som)";
>         model = "SolidRun HummingBoard Solo/DualLite";
>         model = "SolidRun HummingBoard2 Dual/Quad";
>         model = "SolidRun Cubox-i Solo/DualLite";

These can also go in the toplevel DTB. Basically, the toplevel DTB can
always refer to the most specific cross product of components and
contain properties like these that only make sense for the specific
combination. There will be a lot of toplevel DTB files, but they will
be for the most part very small. The "meat" of the device tree is
factored out into overlays that can be shared by multiple toplevel
DTBs. The benefit is smaller image size for platforms that need to
bundle DTBs for all possible variations in their kernel image (and
whether that's worth it or not is up to each platform, we're not
asking to make these overlays mandatory, we're just saying that we
have platforms that do need (and are in part already using) something
like this in order to deal with the sheer scale of supported platform
variations, and we'd like there to be an upstream standard for it).

> I also don't see a sensible way without something like the above for a
> boot loader to know the filenames of each of the components for a
> platform - and it would need to be told the order to glue those
> components together.

I think platform identification and matching which overlays to apply
should remain outside the scope of the device tree itself. The main
reason is that you usually want to compress DTB(O) files for
efficiency, and when you have a large list of overlays in a kernel
image you don't want to have to decompress them all just to determine
which ones to load for the current platform. So I think it's generally
better to let bootloaders come up with their own scheme to store this
information inside their file systems or whatever other data
structures they use to find these DTB(O) files.


From dianders at chromium.org  Tue Dec  2 13:59:50 2025
From: dianders at chromium.org (Doug Anderson)
Date: Tue, 2 Dec 2025 13:59:50 -0800
Subject: Proposal: Officially allow "incomplete" trees as a base
In-Reply-To: <CAL_JsqJz8D53OF8PGaq+o6X5zfE1Y4NrH+BpYPEo6OENviJvbg@mail.gmail.com>
References: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
 <CAODwPW_51fKOfDQbTUFCum13M621Uxi2Zw2YHng0DrrwwvZhRQ@mail.gmail.com> <CAL_JsqJz8D53OF8PGaq+o6X5zfE1Y4NrH+BpYPEo6OENviJvbg@mail.gmail.com>
Message-ID: <CAD=FV=Xe3zqbyN5RVRppWbN=v6L=nECs6HtCu43m=QYUa=iV4w@mail.gmail.com>

Hi,

On Mon, Dec 1, 2025 at 4:48?PM Rob Herring <robh at kernel.org> wrote:
>
> > > Possible example if we support 3 levels:
> > >
> > > SoC (incomplete) compatible: "socvendor,mysoc-rev1", "socvendor,mysoc"
> > > overlay1 (incomplete) compatible: "referencevendor,referencecodename";
>
> I don't understand this one...
>
> > > overlay2 compatible: "boardvendor,myboard-rev1", "boardvendor,myboard"
> > > merged compatible: "boardvendor,myboard-rev1", "boardvendor,myboard",
> > >                    "referencevendor,reference-codename",
> > >                     , "socvendor,mysoc";

I was just trying to come up with an example with 3 levels. Usually a
whole pile of boards are based on a reference design, so the reference
board could be an extra level of overlays. Thinking about this with
the sc7180 Chromebooks, you might have:

SoC: qcom,sc7180 (base DTB)
Reference design: google,trogdor
Actual board: google,lazor-rev1, google,lazor

So final compatible could be:
"google,lazor-rev1", "google-lazor", "google-trogdor", "qcom,sc7180"

In the case of what we ended up with upstream for sc7180 Chromebooks,
we actually _didn't_ include the reference design (google,trogdor) in
the list of compatibles in the final board. I think this was because
the name of the reference design ("trogdor") was also the name of the
reference _board_ and it would have been confusing. ...but I can also
see how one might want the reference board to show up here. I don't
feel super strongly either way.

In any case, I'm OK with not focusing on 3-levels right now and I'm
not actually planning to use it in the short term, I just want to make
sure that anything we do doesn't preclude it...


> > Sorry, I only cursorily followed the previous discussion so I may have
> > missed the exact need for this part. But I would caution against any
> > proposal that changes the basic rules of how an overlay is applied.
> > The definition of how overlays work has (I think?) been stable for
> > over a decade now, and is implemented in bootloaders that often cannot
> > easily be updated. I absolutely support your effort to get more
> > upstream standardization for managing base device trees and overlays
> > (which I think need to be flexible for arbitrary layers, not just SoC
> > and board), but let's not break the overlay code in old bootloaders
> > while doing it.
>
> I think merging compatibles is orthogonal to splitting SoC and board
> DTs. Doug needs to merge because there is more than 1 SoC version or
> base DT to pick. In many cases (SoC revision compatibles are the
> exception upstream), there is only 1 SoC DT and N board DTs. So we
> should consider both and define them separately. In the simple case,
> you'd have something like:
>
> SoC (incomplete) compatible: "socvendor,mysoc"
> Board overlay compatible: "boardvendor,myboard-rev1",
> "boardvendor,myboard", "socvendor,mysoc"
>
> Then you just apply the overlay and it overwrites the incomplete
> compatible. That works with existing overlay applying (overwriting)
> for multiple steps as long as each step is a superset (compatible
> list) of the prior steps.
>
> In Doug's case, I think you need code to decide which base to pick and
> then fixup the final compatible.
>
> SoC (incomplete) compatible: "socvendor,mysoc-rev1", "socvendor,mysoc"
> Board overlay compatible: "boardvendor,myboard-rev1",
> "boardvendor,myboard", "socvendor,mysoc"
>
> And then after applying, you do the merge to insert the SoC rev compatible:
>
> "boardvendor,myboard-rev1", "boardvendor,myboard",
> "socvendor,mysoc-rev1", "socvendor,mysoc"
>
> You need SoC specific code to know what SoC revision you are running
> on, so SoC specific post apply code should be fine too. There's not
> any existing bootloader problem because you need code to handle this.
>
> Maybe that fixup will end up being generic enough that it's not
> platform specific, but that's an optimization of the implementation.
>
> > Is there really a need to merge the compatible strings in your case?
>
> Well, you could just require duplicating an overlay N times for N
> bases, but that doesn't scale

I'm actually OK with deferring the "pluggable SoC" problem for now.
Even for the Google Pixel team, it's a bit of an edge case. If we have
to solve it by duplicating "dtbo" files for socketed boards (or any
board which could have more than one SoC) that's probably OK for now.
Once other problems are solved, we can perhaps come back to the idea
of merging compatible strings and/or other properties.

In v1 of my Pixel 10 series I wasn't even trying to support multiple
SoC revisions, I was just trying to look forward to the future based
on what I saw downstream. ;-)

If I drop the idea of merging compatible strings and just duplicate
the "SoC" parts of the compatible in each of the overlays, then do we
have something that's landable to get things off the ground? I think
Krzysztof will still NAK my base "dtb" that represents just the SoC
since it's not "complete". I certainly wouldn't want to just steamroll
over his concerns. Krzysztof: Do you have any thoughts? Do you
understand my goal here and agree that it's something worth solving?
If you don't agree it's worth solving, would it help to hear more
people express their interest in a solution? If you agree it's worth
solving, can you provide a suggestion for how we can move forward?


> > I
> > think in the vast majority of platform identification cases, code only
> > cares about matching the most precise string (i.e.
> > "boardvendor,myboard-rev1"). If we do feel like having the whole chain
> > of identification is necessary, it could be achieved by just
> > copy&pasting the extra strings into the overlay file. If we have
> > cross-validation between base and overlay source files we could also
> > have the validation check that the overlays correctly contain all
> > compatible strings from their base tree. If we know that the base
> > trees aren't standalone anyway, we could also just invent other
> > property names that identify them (e.g. `soc-compatible =
> > "socvendor,mysoc";`). Anything other than breaking the overlay format
> > would be preferable in my opinion.
>
> There's also a use case I'm aware of where the base DT is just for a
> SoM and then the bootloader applies an expansion board overlay. So it
> is not always "not standalone". And of course, this could be combined
> with what Doug wants to do.
>
> Note that for any new property (or an incomplete compatible) like
> soc-compatible, you will need to consider how we validate it.
>
> > I also feel like we need a better standardized way to tie base device
> > trees to overlays, like your `/loaders` node proposal in an earlier
> > email, although maybe that's an orthogonal discussion (but related,
> > especially if there's supposed to be cross-validation between base
> > trees and overlays). The compatible string is just not a scalable way
> > for bootloaders to make this determination, there may be a lot more
> > differentiation than just "SoC" and "board", and the scheme almost
> > certainly needs to be platform/bootloader-specific because every
> > hardware vendor has their own ideas about how to group and reuse parts
> > of a platform. This information doesn't necessarily need to be *in*
> > the device tree, it could also just be in a separate YAML file in the
> > same repo (since bootloaders will almost certainly want to have it
> > transformed into their own out-of-band descriptor at build-time
> > anyway, so that they can compress the device tree itself and don't
> > have to decompress each one for matching), but it needs to be
> > somewhere.
>
> There is a proposal here[1]. It's simple, but I do wonder if looking
> at the root compatible only is too narrow of a view. An overlay could
> target a connector compatible for example.

Yeah, I'm still not really a fan of that proposal. I think different
loaders are going to need different information to know which overlays
to apply, so we need to define "yaml" files for different loaders and
define the formats for a few different loaders.

>From a validation point of view, I'd imagine we'd want to (if
possible) validate all different combinations, but (if it's
well-defined in a binding) we could potentially include rules in the
kernel that understand different loaders and could come up with
different things to validate.


-Doug


From dianders at chromium.org  Tue Dec  2 14:02:23 2025
From: dianders at chromium.org (Doug Anderson)
Date: Tue, 2 Dec 2025 14:02:23 -0800
Subject: Proposal: Officially allow "incomplete" trees as a base
In-Reply-To: <CAL_Jsq+uVyGzi+TniwJQEOFDm=L9=S-aLWfvyDmY-GQD5iAEOA@mail.gmail.com>
References: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
 <CAD++jLkuRQKoiEN928GtAj7wUts5PxH905bLp6ZhKsJ3NnenEA@mail.gmail.com> <CAL_Jsq+uVyGzi+TniwJQEOFDm=L9=S-aLWfvyDmY-GQD5iAEOA@mail.gmail.com>
Message-ID: <CAD=FV=Vn1z0chJZ=q3NZ3mKYu5v=YnuCBWUyStHMtD8NmY+C5A@mail.gmail.com>

Hi,

On Mon, Dec 1, 2025 at 5:07?PM Rob Herring <robh at kernel.org> wrote:
>
> I would be interested in some experiments around making this change
> with existing DTs. Take a board DT and add the overlay boilerplate
> (that may be nothing more than add '/plugin/') and remove the SoC
> include. Does that apply to a compiled SoC DTB and is the result the
> same as before?
>
> Think of it as moving from building C code using a #include of every
> .c file to build a single .o to linking multiple individual .o files.
> No one would argue the former is better.

I suspect it would work some of the time, but it wouldn't be
guaranteed. In the very least, the base SoC "dtb" would fail to
validate because it would be missing a documented top-level
compatible. :-P ...but if we ignore that, I'd imagine these things
could break:

1. If a SoC is relying on a "label" that's provided by the boards, it
could break.

2. If any of the boards "delete" things from the SoC, it could break.

3. Board files could have been relying on the "bindings" #includes in
the base SoC file.

I guess the first two things are much more common between all of the
"dtsi" files included to make up a board than they are between the
main SoC "dtsi" file and the others, and the third one is "easily"
fixed.

OK, so I did a quick experiment and quickly found an example of #2.
Take a look at "sc7180-acer-aspire1.dts" and you'll find:

/delete-node/ &tz_mem;
/delete-node/ &ipa_fw_mem;

Those delete nodes from the SoC tree.

I also found an example of #3. sc7180-trogdor.dtsi refers to
"GCC_MSS_CFG_AHB_CLK", but it doesn't include
"dt-bindings/clock/qcom,gcc-sc7180.h".


All of the above could be fixed, but it stops being a "quick"
experiment. ;-) Essentially, if people weren't trying to follow the
rules of the overlay-to-base boundary it's likely they've crossed
them, as in the above case. :-P

If continuing the above experiment would help convince someone, I
could certainly continue it. I guess I just don't have too much of a
doubt that it could be made to work OK. I think it would be _less_
efficient overall to ship full DTBs generated like that because we'll
have compiled the base device tree with "-@". The only way to become
more efficient would be to actually ship the base DTB + overlays.

-Doug


From dianders at chromium.org  Tue Dec  2 14:03:06 2025
From: dianders at chromium.org (Doug Anderson)
Date: Tue, 2 Dec 2025 14:03:06 -0800
Subject: Proposal: Officially allow "incomplete" trees as a base
In-Reply-To: <CAGXv+5HyMYgKmLc+jmkj-gytm9SNVg9dS7Vn3dQ-dsH8Wo+4sg@mail.gmail.com>
References: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
 <CAD++jLkuRQKoiEN928GtAj7wUts5PxH905bLp6ZhKsJ3NnenEA@mail.gmail.com>
 <CAD=FV=X5=AK4XMANv+fatn3d9Y5vo9AXsHWb_47HmNaMWUtMwA@mail.gmail.com> <CAGXv+5HyMYgKmLc+jmkj-gytm9SNVg9dS7Vn3dQ-dsH8Wo+4sg@mail.gmail.com>
Message-ID: <CAD=FV=Uq9yfUkLUgg116G+2AvEKkEPmdRgUJ5f1bj229j=LxUg@mail.gmail.com>

Hi,

On Mon, Dec 1, 2025 at 7:31?PM Chen-Yu Tsai <wenst at chromium.org> wrote:
>
> > Separately, it can be noted that we always _wanted_ a similar solution
> > for ChromeOS, but we never quite got there... ;-)
>
> FTR ChromeOS is moving in that direction: splitting SKU differences
> based on components into overlays that get applied to the base by the
> bootloader.
>
> In the simplest example we could have one base dts and two overlays
> for two different DSI panel models:
>
>   - base.dtb
>     - panel-model-a.dtbo
>     - panel-model-b.dtbo
>
> The problem we then run into is that the base.dtb will only have the
> generic model compatible "google,foo", not the sku and revision
> specific ones like "google,foo-sku1-rev2".
>
> And we'd really like to avoid having _more_ overlays just to add the
> final specific compatible string, as that kind of defeats the purpose
> of using overlays to reduce the number of dts files.

I think you may have simplified the above a little too much to the
point where it's confusing. At least I'm a bit confused. I _think_ the
problems you're talking about are the kinds of things we run into when
we take overlays above just two levels. I'm imagining:

- base.dtb
- board1-rev1.dtbo
- board2-rev1.dtbo
- board1-rev2.dtbo
- board2-rev2.dtbo
- panel-a.dtbo
- panel-b.dtbo

So I think you're saying that you'd start with the "base.dtb" and then
extend it with exactly one of the "board" overlays and then exactly
one of the "panel" overlays. Is that right?

So I'd imagine that each of the "board" overlays could have "full"
compatible strings. For instance, I'd imagine "board2-rev2" could
have:

compatible = "google,booard2-rev2", "socVendor,soc"


The problem you're struggling with (I think) is that the panel
overlays won't be represented in the compatible string (and "model")
even though (historically) we always did in ChromeOS (they were
included in the "sku" part of the compatible string).

Did I get that right?


> I proposed internally maybe having the bootloader fix up the final
> compatible string, but I think we need some rough consensus upstream
> whether this is acceptable or not.

Maybe we need to come to some agreement about when the top-level
compatible string needs to be changed. In the above, I'd perhaps argue
that the panel isn't a major enough change that it needs to change the
top-level compatible string. That would solve the problem, right? What
do others think? Certainly for "probe-able" components we don't change
the top-level compatible string. Can anyone point to any official
documentation about the top-level compatible string?


-Doug


From dianders at chromium.org  Tue Dec  2 14:04:51 2025
From: dianders at chromium.org (Doug Anderson)
Date: Tue, 2 Dec 2025 14:04:51 -0800
Subject: Proposal: Officially allow "incomplete" trees as a base
In-Reply-To: <aS66WcLPm6e5rdyk@shell.armlinux.org.uk>
References: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
 <aS66WcLPm6e5rdyk@shell.armlinux.org.uk>
Message-ID: <CAD=FV=VxArGov6jB8jTTnPmM9XKAya_nc4wCDQS+uZf72hgmzA@mail.gmail.com>

Hi,

On Tue, Dec 2, 2025 at 2:07?AM Russell King (Oracle)
<linux at armlinux.org.uk> wrote:
>
> Having worked on the SolidRun i.MX6 platforms, I agree with this.
> Within these platforms there are:
>
> SoC     SOM             Platform
> imx6dl  pre-v1.5        cubox
> imx6q   v1.5            hummingboard
>         v1.5 + emmc     hummingboard2
>
> On top of these, I have specific "user" extensions for hardware that
> I've connected - e.g.
> - the NoIR RPi camera needs DT modification.
> - for monitoring a mechanical church clock, a "gps" variant that
>   allowed PPS to be used with a GPIO pin, and a "capture" variant
>   that configured the hardware to allow precise event stamping.
> - 1-wire, for ds18b20 temperature sensors.
>
> Without the user extensions, this adds up to 18 DTB files:
> arch/arm/boot/dts/nxp/imx/imx6dl-cubox-i-emmc-som-v15.dts
> arch/arm/boot/dts/nxp/imx/imx6dl-cubox-i-som-v15.dts
> arch/arm/boot/dts/nxp/imx/imx6dl-cubox-i.dts
> arch/arm/boot/dts/nxp/imx/imx6dl-hummingboard-emmc-som-v15.dts
> arch/arm/boot/dts/nxp/imx/imx6dl-hummingboard-som-v15.dts
> arch/arm/boot/dts/nxp/imx/imx6dl-hummingboard.dts
> arch/arm/boot/dts/nxp/imx/imx6dl-hummingboard2-emmc-som-v15.dts
> arch/arm/boot/dts/nxp/imx/imx6dl-hummingboard2-som-v15.dts
> arch/arm/boot/dts/nxp/imx/imx6dl-hummingboard2.dts
> arch/arm/boot/dts/nxp/imx/imx6q-cubox-i-emmc-som-v15.dts
> arch/arm/boot/dts/nxp/imx/imx6q-cubox-i-som-v15.dts
> arch/arm/boot/dts/nxp/imx/imx6q-cubox-i.dts
> arch/arm/boot/dts/nxp/imx/imx6q-hummingboard-emmc-som-v15.dts
> arch/arm/boot/dts/nxp/imx/imx6q-hummingboard-som-v15.dts
> arch/arm/boot/dts/nxp/imx/imx6q-hummingboard.dts
> arch/arm/boot/dts/nxp/imx/imx6q-hummingboard2-emmc-som-v15.dts
> arch/arm/boot/dts/nxp/imx/imx6q-hummingboard2-som-v15.dts
> arch/arm/boot/dts/nxp/imx/imx6q-hummingboard2.dts
>
> basically, every combination needs to be enumerated. So, having two SoC
> dt files, three for the SOM, and three for the platform that the boot
> loader combines would significantly cut this down - to 8.
>
> However, it isn't that simple. For example, when the Hummingboard2 is
> used with the iMX6Q SoC, there's a SATA device present in the SoC level
> that needs Hummingboard2 specific properties to tune the signal
> waveform. However, iMX6DL doesn't have this SATA device in silicon, so
> the node doesn't exist in the base SoC DT file. The situation is the
> same for Hummingboard, but the tuning parameters, being board specific,
> are different.
>
> This means is that there are DT properties that are dependent on the
> SoC DT component and the platform DT component which do not fit with
> splitting the DT files into their individual "component" levels.

Wow, it sounds complicated! Yeah, in your specific case where you need
specific tuning parameters for each combination of SoC and SoM the
easiest might be to just keep things separate as you have it. If
you're looking to optimize the total size of the distributed device
trees instead of the total number of files, overlays still could
possibly help you out, though. I could imagine a case where you first
apply the "coarse" overlays (SoC, SoM, board) and then you look for
finer-grained overlays that are applied atop that. You'd still need a
bunch of these "finer grained" overlays (one for each unique
combination) but each one would be tiny.

To make it concrete, I'd imagine:
- imx6q - base dtb
- som1.5 - overlay
- hummingboard2 - overlay
- hummingboard2-with-imx6q - overlay

...and the "hummingboard2-with-imx6q" could _just_ have the SATA
tunings in it. I think that would be possible, right?


> The other issue would be the /model property - for example:
>
>         model = "SolidRun HummingBoard2 Solo/DualLite";
>         model = "SolidRun HummingBoard2 Solo/DualLite (1.5som+emmc)";
>         model = "SolidRun HummingBoard2 Solo/DualLite (1.5som)";
>         model = "SolidRun HummingBoard Solo/DualLite";
>         model = "SolidRun HummingBoard2 Dual/Quad";
>         model = "SolidRun Cubox-i Solo/DualLite";
>
> as a set of examples. I don't see a clear way to generate these from
> a fragmented scheme. There's a similar problem with the board-level
> compatible:
>
>         compatible = "solidrun,cubox-i/dl", "fsl,imx6dl";
>         compatible = "solidrun,hummingboard2/dl", "fsl,imx6dl";
>         compatible = "solidrun,hummingboard/dl", "fsl,imx6dl";
>         compatible = "solidrun,hummingboard2/q", "fsl,imx6q";
>
> These don't include the SoM information.

Right. This is the question many of the messages in this thread have
been struggling with.

Things become a bit easier if you simply don't expect the top-level
"compatible" to describe everything. ...but in your case it sounds
like things are _very_ dynamic (everything can be combined with
everything), so if we want to solve your problem it seems like we
truly do need a way to "combine" compatible strings.

As per one of my earlier replies, it's possible we'll postpone this
and start with simpler cases where we don't need to do any top-level
compatible/model munging, but it's good to know that there's a use
case that really needs it.


> Maybe what would work would be a high-level DT file that contains
> paths to the lower levels that need to be combined, along with
> properties that need to be merged. E.g.
>
> / {
>         model = "SolidRun HummingBoard2 Dual/Quad";
>         compatible = "solidrun,hummingboard2/q", "fsl,imx6q";
>
>         dts-components {
>                 compatible = "boot/dt";
>
>                 component at 1 {
>                         compatible = "dt";
>                         path = "imx6q.dtbo";
>                 };
>
>                 component at 2 {
>                         compatible = "dt";
>                         path = "imx6qdl-sr-som-v1.5.dtbo";
>                 };
>
>                 component at 3 {
>                         compatible = "dt";
>                         path = "imx6qdl-hummingboard2.dtbo";
>                 };
>
>                 component at 4 {
>                         compatible = "dt";
>                         path = "imx6ql-hummingboard2-emmc.dtbo";
>                 };
>         };
>
>         soc {
>                 sata at 2200000 {
>                         .. sata tuning properties ..
>                 };
>         };
> };
>
> Or something similar.

Yeah, the question of how to know which files to combine is an
important and related point, but I've been trying to keep it separate
so we don't have to solve every complex problem at once. This is, I
believe, also the subject of one of Chen-Yu's talks at Plumbers.


> However, this would mean we would still need the
> 18 or so top level DT files, but also each component as well, which
> will increase the number of files we're having to manage on a target
> platform - so I'm wondering whether it's worth it.
>
> I don't think we'll be able to get away from this problem: it's likely
> that there will continue to be properties that are specific across
> several "levels" of a split DT setup, and apart from something like the
> above, I don't really see a way to handle them.
>
> I also don't see a sensible way without something like the above for a
> boot loader to know the filenames of each of the components for a
> platform - and it would need to be told the order to glue those
> components together.

Right, this kind of thing would be a judgement call. How you'd want to
organize things / use overlays would be up to you.


> I would have liked to use overlays for these platforms, but ISTR they
> either weren't supported at the time, or frowned upon, and even so I
> can only see them working for the simplest of cases due to the issue
> I mention above.

The fact that you have similar needs at least makes me continue to be
confident that this is an important problem to try to solve.


-Doug


From torvalds at linux-foundation.org  Tue Dec  2 14:07:25 2025
From: torvalds at linux-foundation.org (Linus Torvalds)
Date: Tue, 2 Dec 2025 14:07:25 -0800
Subject: [Bug report] hash_name() may cross page boundary and trigger
 sleep in RCU context
In-Reply-To: <aS7e9CbQXS27sGcd@shell.armlinux.org.uk>
References: <20251126090505.3057219-1-wozizhi@huaweicloud.com>
 <33ab4aef-020e-49e7-8539-31bf78dac61a@huaweicloud.com> <CAHk-=wh1Wfwt9OFB4AfBbjyeu4JVZuSWQ4A8OoT3W6x9btddfw@mail.gmail.com>
 <aSgut4QcBsbXDEo9@shell.armlinux.org.uk> <CAHk-=wh+cFLLi2x6u61pvL07phSyHPVBTo9Lac2uuqK4eRG_=w@mail.gmail.com>
 <aS7e9CbQXS27sGcd@shell.armlinux.org.uk>
Message-ID: <CAHk-=wg4ZnsfpgXYL5qhjYDYo1Gnssz+VxnKZzHXMEmE7qrnQQ@mail.gmail.com>

On Tue, 2 Dec 2025 at 04:43, Russell King (Oracle)
<linux at armlinux.org.uk> wrote:
>
> What I'm thinking is to address both of these by handling kernel space
> page faults (which will be permission or PTE-not-present) separately
> (not even build tested):

That patch looks sane to me.

But I also didn't build test it, just scanned it visually ;)

            Linus


From bisson.gary at gmail.com  Tue Dec  2 14:08:45 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Tue, 02 Dec 2025 23:08:45 +0100
Subject: [PATCH v4 0/4] Add support for Ezurio MediaTek platforms
Message-ID: <20251202-review-v4-0-93f5cd2a0d4a@gmail.com>

This series adds support for Ezurio MediaTek platforms called
"Tungsten". It includes support for MT8370-based Tungsten 510 and
MT8390-based Tungsten 700 SOMs.

Changes in v2:
- Use b4 to cc all maintainers properly
- Squashed patches 2/3 together
- Updated dts node names to be generic

Changes in v3:
- Added per-commit changelog
- Added missing Acked-by on 1st patch
- Link to v2: https://lore.kernel.org/r/20251201-review-v2-0-dc2df44eec7e at gmail.com

Changes in v4:
- Fixed remaining DTB warnings
- Link to v3: https://lore.kernel.org/r/20251201-review-v3-0-07f9af7341fd at gmail.com

Regards,

Gary Bisson (4):
  dt-bindings: vendor-prefixes: Add Ezurio LLC
  dt-bindings: arm: mediatek: Add Ezurio Tungsten entries
  arm64: dts: mediatek: add device tree for Tungsten 510 board
  arm64: dts: mediatek: add device tree for Tungsten 700 board

 .../devicetree/bindings/arm/mediatek.yaml     |    2 +
 .../devicetree/bindings/vendor-prefixes.yaml  |    2 +
 arch/arm64/boot/dts/mediatek/Makefile         |    2 +
 .../dts/mediatek/mt8370-tungsten-smarc.dts    |   14 +
 .../dts/mediatek/mt8390-tungsten-smarc.dts    |   22 +
 .../dts/mediatek/mt83x0-tungsten-smarc.dtsi   | 1481 +++++++++++++++++
 6 files changed, 1523 insertions(+)
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts
 create mode 100644 arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi

--
2.43.0

---
To: Rob Herring <robh at kernel.org>
To: Krzysztof Kozlowski <krzk+dt at kernel.org>
To: Conor Dooley <conor+dt at kernel.org>
To: Matthias Brugger <matthias.bgg at gmail.com>
To: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
To: Sean Wang <sean.wang at mediatek.com>
Cc: devicetree at vger.kernel.org
Cc: linux-kernel at vger.kernel.org
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-mediatek at lists.infradead.org

---
Gary Bisson (4):
      dt-bindings: vendor-prefixes: Add Ezurio LLC
      dt-bindings: arm: mediatek: Add Ezurio Tungsten entries
      arm64: dts: mediatek: add device tree for Tungsten 510 board
      arm64: dts: mediatek: add device tree for Tungsten 700 board

 .../devicetree/bindings/arm/mediatek.yaml          |    2 +
 .../devicetree/bindings/vendor-prefixes.yaml       |    2 +
 arch/arm64/boot/dts/mediatek/Makefile              |    2 +
 .../boot/dts/mediatek/mt8370-tungsten-smarc.dts    |   14 +
 .../boot/dts/mediatek/mt8390-tungsten-smarc.dts    |   22 +
 .../boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi   | 1510 ++++++++++++++++++++
 6 files changed, 1552 insertions(+)
---
base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
change-id: 20251201-review-750072579991

Best regards,
-- 
Gary Bisson <bisson.gary at gmail.com>



From bisson.gary at gmail.com  Tue Dec  2 14:08:46 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Tue, 02 Dec 2025 23:08:46 +0100
Subject: [PATCH v4 1/4] dt-bindings: vendor-prefixes: Add Ezurio LLC
In-Reply-To: <20251202-review-v4-0-93f5cd2a0d4a@gmail.com>
References: <20251202-review-v4-0-93f5cd2a0d4a@gmail.com>
Message-ID: <20251202-review-v4-1-93f5cd2a0d4a@gmail.com>

Ezurio is the new name of Laird Connectivity after it acquired Boundary
Devices.

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
Signed-off-by: Gary Bisson <bisson.gary at gmail.com>

---
Changes in v2:
- None
Changes in v3:
- Added missing Acked-by from Krzysztof
Changes in v4:
- None
---
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index f1d1882009ba..e76e6c5be726 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -547,6 +547,8 @@ patternProperties:
     description: Exegin Technologies Limited
   "^ezchip,.*":
     description: EZchip Semiconductor
+  "^ezurio,.*":
+    description: Ezurio LLC
   "^facebook,.*":
     description: Facebook
   "^fairchild,.*":

-- 
2.43.0



From bisson.gary at gmail.com  Tue Dec  2 14:08:47 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Tue, 02 Dec 2025 23:08:47 +0100
Subject: [PATCH v4 2/4] dt-bindings: arm: mediatek: Add Ezurio Tungsten
 entries
In-Reply-To: <20251202-review-v4-0-93f5cd2a0d4a@gmail.com>
References: <20251202-review-v4-0-93f5cd2a0d4a@gmail.com>
Message-ID: <20251202-review-v4-2-93f5cd2a0d4a@gmail.com>

Add device tree bindings support for the Ezurio Tungsten 510 (MT8370)
SMARC [1] / Ezurio Tungsten 700 (MT8390) SMARC [2] + Universal SMARC
carrier board [3].

[1] https://www.ezurio.com/product/tungsten510-smarc
[2] https://www.ezurio.com/product/tungsten700-smarc
[3] https://www.ezurio.com/system-on-module/accessories/universal-smarc-carrier

Signed-off-by: Gary Bisson <bisson.gary at gmail.com>

---
Changes in v2:
- Squashed both entries into 1 commit
Changed in v3:
- None
Changes in v4:
- None
---
 Documentation/devicetree/bindings/arm/mediatek.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/mediatek.yaml b/Documentation/devicetree/bindings/arm/mediatek.yaml
index f04277873694..cffb0f6ac690 100644
--- a/Documentation/devicetree/bindings/arm/mediatek.yaml
+++ b/Documentation/devicetree/bindings/arm/mediatek.yaml
@@ -431,12 +431,14 @@ properties:
           - const: mediatek,mt8365
       - items:
           - enum:
+              - ezurio,mt8370-tungsten-smarc
               - grinn,genio-510-sbc
               - mediatek,mt8370-evk
           - const: mediatek,mt8370
           - const: mediatek,mt8188
       - items:
           - enum:
+              - ezurio,mt8390-tungsten-smarc
               - grinn,genio-700-sbc
               - mediatek,mt8390-evk
           - const: mediatek,mt8390

-- 
2.43.0



From bisson.gary at gmail.com  Tue Dec  2 14:08:48 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Tue, 02 Dec 2025 23:08:48 +0100
Subject: [PATCH v4 3/4] arm64: dts: mediatek: add device tree for Tungsten
 510 board
In-Reply-To: <20251202-review-v4-0-93f5cd2a0d4a@gmail.com>
References: <20251202-review-v4-0-93f5cd2a0d4a@gmail.com>
Message-ID: <20251202-review-v4-3-93f5cd2a0d4a@gmail.com>

Add device tree to support Ezurio Tungsten 510 (MT8370) SMARC SOM [1] +
Universal SMARC carrier board [2].
It includes support for the MIPI-DSI BD070LIC3 display which uses the
Tianma TM070JDHG30 panel + TI SN65DSI84 MIPI-DSI to LVDS bridge [3].

[1] https://www.ezurio.com/product/tungsten510-smarc
[2] https://www.ezurio.com/system-on-module/accessories/universal-smarc-carrier
[3] https://www.ezurio.com/product/bd070lic3-7-touchscreen-display

Signed-off-by: Gary Bisson <bisson.gary at gmail.com>

---
Changes in v2:
- Updated nodes to be generic (pmic, i2c, usb-typec)
Changed in v3:
- None
Changed in v4:
- Fixed remaining DTB warnings
---
 arch/arm64/boot/dts/mediatek/Makefile              |    1 +
 .../boot/dts/mediatek/mt8370-tungsten-smarc.dts    |   14 +
 .../boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi   | 1510 ++++++++++++++++++++
 3 files changed, 1525 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile
index a4df4c21399e..30d169a31b10 100644
--- a/arch/arm64/boot/dts/mediatek/Makefile
+++ b/arch/arm64/boot/dts/mediatek/Makefile
@@ -99,6 +99,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8195-demo.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8195-evb.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8365-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-genio-510-evk.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-tungsten-smarc.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-genio-1200-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-genio-700-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-kontron-3-5-sbc-i1200.dtb
diff --git a/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts b/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts
new file mode 100644
index 000000000000..d713ef77df3a
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2025 Ezurio LLC
+ * Author: Gary Bisson <bisson.gary at gmail.com>
+ */
+/dts-v1/;
+#include "mt8370.dtsi"
+#include "mt83x0-tungsten-smarc.dtsi"
+
+/ {
+	model = "Ezurio Tungsten510 SMARC (MT8370)";
+	compatible = "ezurio,mt8370-tungsten-smarc", "mediatek,mt8370",
+		     "mediatek,mt8188";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi b/arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi
new file mode 100644
index 000000000000..d71148d78781
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi
@@ -0,0 +1,1510 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2025 Ezurio LLC
+ * Author: Gary Bisson <bisson.gary at gmail.com>
+ */
+
+#include "mt6359.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/net/microchip-lan78xx.h>
+#include <dt-bindings/pinctrl/mediatek,mt8188-pinfunc.h>
+#include <dt-bindings/spmi/spmi.h>
+#include <dt-bindings/usb/pd.h>
+
+/ {
+	aliases {
+		dsi0 = &disp_dsi0;
+		ethernet0 = &eth;
+		i2c0 = &i2c0;
+		i2c1 = &i2c1;
+		i2c2 = &i2c2;
+		i2c3 = &i2c3;
+		i2c4 = &i2c4;
+		i2c5 = &i2c5;
+		i2c6 = &i2c6;
+		mmc0 = &mmc0;
+		mmc1 = &mmc1;
+		mmc2 = &mmc2;
+		rtc0 = &rv3028;
+		rtc1 = &mt6359rtc;
+		serial0 = &uart0;
+	};
+
+	backlight_lcd0: backlight-lcd0 {
+		compatible = "pwm-backlight";
+		brightness-levels = <0 1023>;
+		default-brightness-level = <768>;
+		num-interpolated-steps = <1023>;
+		enable-gpios = <&pio 30 GPIO_ACTIVE_HIGH>;
+		pwms = <&disp_pwm0 0 30000>;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	firmware {
+		optee {
+			compatible = "linaro,optee-tz";
+			method = "smc";
+		};
+	};
+
+	memory at 40000000 {
+		device_type = "memory";
+		reg = <0 0x40000000 0x1 0x00000000>;
+	};
+
+	panel-dsi0 {
+		compatible = "tianma,tm070jdhg30";
+		backlight = <&backlight_lcd0>;
+		power-supply = <&reg_5v>;
+
+		port {
+			dsi0_panel_in: endpoint {
+				remote-endpoint = <&sn65dsi84_bridge_out>;
+			};
+		};
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		/*
+		 * 12 MiB reserved for OP-TEE (BL32)
+		 * +-----------------------+ 0x43e0_0000
+		 * |      SHMEM 2MiB       |
+		 * +-----------------------+ 0x43c0_0000
+		 * |        | TA_RAM  8MiB |
+		 * + TZDRAM +--------------+ 0x4340_0000
+		 * |        | TEE_RAM 2MiB |
+		 * +-----------------------+ 0x4320_0000
+		 */
+		optee_reserved: optee at 43200000 {
+			no-map;
+			reg = <0 0x43200000 0 0x00c00000>;
+		};
+
+		scp_mem: memory at 50000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x50000000 0 0x2900000>;
+			no-map;
+		};
+
+		/* 2 MiB reserved for ARM Trusted Firmware (BL31) */
+		bl31_secmon_reserved: memory at 54600000 {
+			no-map;
+			reg = <0 0x54600000 0x0 0x200000>;
+		};
+
+		apu_mem: memory at 55000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x55000000 0 0x1400000>; /* 20 MB */
+		};
+
+		vpu_mem: memory at 57000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x57000000 0 0x1400000>; /* 20 MB */
+		};
+
+		adsp_mem: memory at 60000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x60000000 0 0xf00000>;
+			no-map;
+		};
+
+		afe_dma_mem: memory at 60f00000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x60f00000 0 0x100000>;
+			no-map;
+		};
+
+		adsp_dma_mem: memory at 61000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x61000000 0 0x100000>;
+			no-map;
+		};
+	};
+
+	regulator-efuse {
+		compatible = "regulator-output";
+		vout-supply = <&mt6359_vefuse_ldo_reg>;
+	};
+
+	reg_1v8: regulator-1v8 {
+		compatible = "regulator-fixed";
+		regulator-name = "reg_1v8";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-always-on;
+	};
+
+	reg_3v3: regulator-3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "reg_3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	reg_5v: regulator-5v {
+		compatible = "regulator-fixed";
+		regulator-name = "reg_5v";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+	};
+
+	sdcard_en_3v3: regulator-sdcard-en {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-name = "sdcard_en_3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&pio 111 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	usb_p0_vbus: regulator-usb-p0-vbus {
+		compatible = "regulator-fixed";
+		regulator-name = "vbus_p0";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&pio 84 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	usb_p1_vbus: regulator-usb-p1-vbus {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&usb1_hub_pins>;
+		regulator-name = "vbus_p1";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		gpio = <&pio 147 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	usb_p2_vbus: regulator-usb-p2-vbus {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&usb2_eth_pins>;
+		regulator-name = "vbus_p2";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		gpio = <&pio 80 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	wifi_pwrseq: wifi-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		pinctrl-names = "default";
+		pinctrl-0 = <&wifi_pwrseq_pins>;
+		post-power-on-delay-ms = <200>;
+		reset-gpios = <&pio 89 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&adsp {
+	memory-region = <&adsp_dma_mem>, <&adsp_mem>;
+	status = "okay";
+};
+
+&afe {
+	memory-region = <&afe_dma_mem>;
+	status = "okay";
+};
+
+&cpu0 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};
+
+&cpu1 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};
+
+&cpu2 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};
+
+&cpu3 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};
+
+&cpu6 {
+	cpu-supply = <&mt6315_6_vbuck1>;
+};
+
+&cpu7 {
+	cpu-supply = <&mt6315_6_vbuck1>;
+};
+
+&disp_pwm0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&disp_pwm0_pins>;
+	status = "okay";
+};
+
+&disp_dsi0 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			reg = <0>;
+			dsi0_in: endpoint {
+				remote-endpoint = <&dither0_out>;
+			};
+		};
+
+		port at 1 {
+			reg = <1>;
+			dsi0_out: endpoint {
+				remote-endpoint = <&sn65dsi84_bridge_in>;
+			};
+		};
+	};
+};
+
+&dither0_in {
+	remote-endpoint = <&postmask0_out>;
+};
+
+&dither0_out {
+	remote-endpoint = <&dsi0_in>;
+};
+
+&eth {
+	phy-mode ="rgmii-id";
+	phy-handle = <&ethernet_phy0>;
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&eth_default_pins>;
+	pinctrl-1 = <&eth_sleep_pins>;
+	mediatek,mac-wol;
+	snps,reset-gpio = <&pio 27 GPIO_ACTIVE_LOW>;
+	snps,reset-active-low;
+	snps,reset-delays-us = <0 11000 1000>;
+	status = "okay";
+};
+
+&eth_mdio {
+	ethernet_phy0: ethernet-phy at 7 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <0x7>;
+		interrupts-extended = <&pio 148 IRQ_TYPE_LEVEL_LOW>;
+	};
+};
+
+&gamma0_out {
+	remote-endpoint = <&postmask0_in>;
+};
+
+&gpu {
+	mali-supply = <&mt6359_vproc2_buck_reg>;
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c0_pins>;
+	clock-frequency = <100000>;
+	status = "okay";
+
+	i2c-mux at 73 {
+		compatible = "nxp,pca9546";
+		reg = <0x73>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&i2c0_mux_pins>;
+		reset-gpios = <&pio 6 GPIO_ACTIVE_LOW>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		i2c_mux_gp_0: i2c at 0 {
+			clock-frequency = <100000>;
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_gp_1: i2c at 1 {
+			clock-frequency = <100000>;
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_gp_2: i2c at 2 {
+			clock-frequency = <100000>;
+			reg = <2>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_gp_3: i2c at 3 {
+			clock-frequency = <100000>;
+			reg = <3>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	clock-frequency = <400000>;
+	status = "okay";
+};
+
+&i2c2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_pins>;
+	clock-frequency = <400000>;
+	status = "okay";
+
+	i2c-mux at 73 {
+		compatible = "nxp,pca9546";
+		pinctrl-names = "default";
+		pinctrl-0 = <&i2c_mux_smarc_lcd_pins>;
+		reg = <0x73>;
+		reset-gpios = <&pio 5 GPIO_ACTIVE_LOW>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		i2c_mux_lcd_0: i2c at 0 {
+			clock-frequency = <100000>;
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_lcd_1: i2c at 1 {
+			clock-frequency = <100000>;
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_lcd_2: i2c at 2 {
+			clock-frequency = <100000>;
+			reg = <2>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_lcd_3: i2c at 3 {
+			clock-frequency = <100000>;
+			reg = <3>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+};
+
+&i2c3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c3_pins>;
+	clock-frequency = <400000>;
+	status = "okay";
+};
+
+&i2c4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c4_pins>;
+	clock-frequency = <400000>;
+	status = "okay";
+};
+
+&i2c_mux_gp_0 {
+	rv3028: rtc at 52 {
+		compatible = "microcrystal,rv3028";
+		reg = <0x52>;
+		interrupts-extended = <&pio 42 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&rv3028_pins>;
+		#clock-cells = <0>;
+		wakeup-source;
+	};
+};
+
+&i2c_mux_gp_1 {
+	usb-typec at 60 {
+		compatible = "ti,hd3ss3220";
+		interrupts-extended = <&pio 45 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&hd3ss3220_pins>;
+		reg = <0x60>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+				hd3ss3220_in_ep: endpoint {
+					remote-endpoint = <&ss_ep>;
+				};
+			};
+
+			port at 1 {
+				reg = <1>;
+				hd3ss3220_out_ep: endpoint {
+					remote-endpoint = <&usb_role_switch>;
+				};
+			};
+		};
+	};
+};
+
+&i2c_mux_gp_2 {
+	codec at 1a {
+		#sound-dai-cells = <0>;
+		AVDD-supply = <&reg_1v8>;
+		CPVDD-supply = <&reg_1v8>;
+		DBVDD-supply = <&reg_3v3>;
+		DCVDD-supply = <&reg_1v8>;
+		MICVDD-supply = <&reg_3v3>;
+		PLLVDD-supply = <&reg_1v8>;
+		SPKVDD1-supply = <&reg_5v>;
+		SPKVDD2-supply = <&reg_5v>;
+		clocks = <&topckgen CLK_TOP_I2SO1>;
+		compatible = "wlf,wm8962";
+		gpio-cfg = <
+			0x0000 /* n/c */
+			0x0000 /* gpio2: */
+			0x0000 /* gpio3: */
+			0x0000 /* n/c */
+			0x8081 /* gpio5:HP detect */
+			0x8095 /* gpio6:Mic detect */
+		>;
+		reg = <0x1a>;
+	};
+};
+
+&i2c_mux_lcd_2 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	bridge at 2c {
+		compatible = "ti,sn65dsi84";
+		reg = <0x2c>;
+		enable-gpios = <&pio 25 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&dsi0_sn65dsi84_pins>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+
+				sn65dsi84_bridge_in: endpoint {
+					remote-endpoint = <&dsi0_out>;
+					data-lanes = <1 2 3 4>;
+				};
+			};
+
+			port at 2 {
+				reg = <2>;
+
+				sn65dsi84_bridge_out: endpoint {
+					remote-endpoint = <&dsi0_panel_in>;
+				};
+			};
+		};
+	};
+
+	touchscren at 5d {
+		compatible = "goodix,gt911";
+		reg = <0x5d>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&ts_dsi0_goodix_pins>;
+		interrupts-extended = <&pio 146 IRQ_TYPE_LEVEL_HIGH>;
+		irq-gpios = <&pio 146 GPIO_ACTIVE_HIGH>;
+		reset-gpios = <&pio 7 GPIO_ACTIVE_HIGH>;
+	};
+};
+
+&mfg0 {
+	domain-supply = <&mt6359_vproc2_buck_reg>;
+};
+
+&mfg1 {
+	domain-supply = <&mt6359_vsram_others_ldo_reg>;
+};
+
+&mmc0 {
+	status = "okay";
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc0_default_pins>;
+	pinctrl-1 = <&mmc0_uhs_pins>;
+	bus-width = <8>;
+	max-frequency = <200000000>;
+	cap-mmc-highspeed;
+	cap-mmc-hw-reset;
+	mmc-hs200-1_8v;
+	mmc-hs400-1_8v;
+	supports-cqe;
+	cap-mmc-hw-reset;
+	no-sdio;
+	no-sd;
+	hs400-ds-delay = <0x1481b>;
+	vmmc-supply = <&mt6359_vemc_1_ldo_reg>;
+	vqmmc-supply = <&mt6359_vufs_ldo_reg>;
+	non-removable;
+};
+
+&mmc1 {
+	status = "okay";
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc1_default_pins>;
+	pinctrl-1 = <&mmc1_uhs_pins>;
+	bus-width = <4>;
+	max-frequency = <200000000>;
+	cap-sd-highspeed;
+	sd-uhs-sdr50;
+	sd-uhs-sdr104;
+	cd-gpios = <&pio 2 GPIO_ACTIVE_LOW>;
+	vqmmc-supply = <&mt6359_vsim1_ldo_reg>;
+	vmmc-supply = <&sdcard_en_3v3>;
+};
+
+&mmc2 {
+	status = "okay";
+	pinctrl-names = "default", "state_uhs", "state_eint";
+	pinctrl-0 = <&mmc2_default_pins>;
+	pinctrl-1 = <&mmc2_uhs_pins>;
+	pinctrl-2 = <&mmc2_eint_pins>;
+	/delete-property/ interrupts;
+	interrupt-names = "msdc", "sdio_wakeup";
+	interrupts-extended = <&gic GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH 0>,
+			      <&pio 172 IRQ_TYPE_LEVEL_LOW>;
+	bus-width = <4>;
+	max-frequency = <200000000>;
+	cap-sd-highspeed;
+	sd-uhs-sdr104;
+	keep-power-in-suspend;
+	wakeup-source;
+	cap-sdio-irq;
+	no-mmc;
+	no-sd;
+	non-removable;
+	vmmc-supply = <&mt6359_vcn33_2_bt_ldo_reg>;
+	vqmmc-supply = <&mt6359_vcn18_ldo_reg>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+};
+
+&mipi_tx_config0 {
+	status = "okay";
+};
+
+&mt6359codec {
+	mediatek,mic-type-0 = <1>;
+	mediatek,mic-type-1 = <3>;
+	mediatek,mic-type-2 = <0>;
+	mediatek,dmic-mode = <0>;
+};
+
+&mt6359_vbbck_ldo_reg {
+	regulator-always-on;
+};
+
+&mt6359_vcn18_ldo_reg {
+	regulator-name = "vcn18_pmu";
+	regulator-always-on;
+	regulator-boot-on;
+};
+
+&mt6359_vcn33_1_bt_ldo_reg {
+	regulator-name = "vcn33_1_pmu";
+	regulator-always-on;
+};
+
+&mt6359_vcn33_2_bt_ldo_reg {
+	regulator-name = "vcn33_2_pmu";
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-always-on;
+	regulator-boot-on;
+};
+
+&mt6359_vcore_buck_reg {
+	regulator-name = "dvdd_proc_l";
+	regulator-always-on;
+};
+
+&mt6359_vemc_1_ldo_reg {
+	regulator-always-on;
+};
+
+&mt6359_vgpu11_buck_reg {
+	regulator-name = "dvdd_core";
+	regulator-always-on;
+};
+
+&mt6359_vmodem_buck_reg {
+	regulator-always-on;
+};
+
+&mt6359_vpa_buck_reg {
+	regulator-name = "vpa_pmu";
+	regulator-always-on;
+};
+
+&mt6359_vproc2_buck_reg {
+	/* The name "vgpu" is required by mtk-regulator-coupler */
+	regulator-name = "vgpu";
+	regulator-min-microvolt = <550000>;
+	regulator-max-microvolt = <800000>;
+	regulator-coupled-with = <&mt6359_vsram_others_ldo_reg>;
+	regulator-coupled-max-spread = <225000>;
+	regulator-always-on;
+};
+
+&mt6359_vs2_buck_reg {
+	regulator-min-microvolt = <1600000>;
+	regulator-boot-on;
+};
+
+&mt6359_vpu_buck_reg {
+	regulator-name = "dvdd_adsp";
+	regulator-always-on;
+};
+
+&mt6359_vrf12_ldo_reg {
+	regulator-name = "va12_abb2_pmu";
+	regulator-always-on;
+};
+
+&mt6359_vsram_md_ldo_reg {
+	regulator-always-on;
+};
+
+&mt6359_vsram_others_ldo_reg {
+	/* The name "vsram_gpu" is required by mtk-regulator-coupler */
+	regulator-name = "vsram_gpu";
+	regulator-min-microvolt = <750000>;
+	regulator-max-microvolt = <800000>;
+	regulator-coupled-with = <&mt6359_vproc2_buck_reg>;
+	regulator-coupled-max-spread = <225000>;
+	regulator-always-on;
+};
+
+&mt6359_vsim1_ldo_reg {
+	regulator-name = "vsim1_pmu";
+	regulator-max-microvolt = <1800000>;
+	regulator-enable-ramp-delay = <480>;
+};
+
+&mt6359_vufs_ldo_reg {
+	regulator-name = "vufs18_pmu";
+	regulator-always-on;
+};
+
+&ovl0_in {
+	remote-endpoint = <&vdosys0_ep_main>;
+};
+
+&pcie {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie_default_pins>;
+	status = "okay";
+};
+
+&pciephy {
+	status = "okay";
+};
+
+&pmic {
+	interrupt-parent = <&pio>;
+	interrupts = <222 IRQ_TYPE_LEVEL_HIGH>;
+
+	keys {
+		compatible = "mediatek,mt6359-keys";
+		mediatek,long-press-mode = <1>;
+		power-off-time-sec = <0>;
+
+		power-key {
+			linux,keycodes = <116>;
+			wakeup-source;
+		};
+	};
+};
+
+&postmask0_in {
+	remote-endpoint = <&gamma0_out>;
+};
+
+&postmask0_out {
+	remote-endpoint = <&dither0_in>;
+};
+
+&scp_cluster {
+	status = "okay";
+};
+
+&scp_c0 {
+	firmware-name = "mediatek/mt8188/scp.img";
+	memory-region = <&scp_mem>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-0 = <&spi0_pins>;
+	pinctrl-names = "default";
+	mediatek,pad-select = <0>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+};
+
+&spi1 {
+	pinctrl-0 = <&spi1_pins>;
+	pinctrl-names = "default";
+	mediatek,pad-select = <0>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+};
+
+&spmi {
+	#address-cells = <2>;
+	#size-cells = <0>;
+
+	mt6315_6: pmic at 6 {
+		compatible = "mediatek,mt6315-regulator";
+		reg = <0x6 SPMI_USID>;
+
+		regulators {
+			mt6315_6_vbuck1: vbuck1 {
+				regulator-name = "vbuck1";
+				regulator-min-microvolt = <300000>;
+				regulator-max-microvolt = <1193750>;
+				regulator-enable-ramp-delay = <256>;
+				regulator-allowed-modes = <0 1 2>;
+				regulator-always-on;
+			};
+
+			mt6315_6_vbuck3: vbuck3 {
+				regulator-name = "vbuck3";
+				regulator-min-microvolt = <300000>;
+				regulator-max-microvolt = <1193750>;
+				regulator-enable-ramp-delay = <256>;
+				regulator-allowed-modes = <0 1 2>;
+				regulator-always-on;
+			};
+
+			mt6315_6_vbuck4: vbuck4 {
+				regulator-name = "vbuck4";
+				regulator-min-microvolt = <1193750>;
+				regulator-max-microvolt = <1193750>;
+				regulator-enable-ramp-delay = <256>;
+				regulator-allowed-modes = <0 1 2>;
+				regulator-always-on;
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1193750>;
+				};
+			};
+		};
+	};
+};
+
+&uart0 {
+	pinctrl-0 = <&uart0_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-0 = <&uart1_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-0 = <&uart2_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&ssusb0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&usbotg_pins>;
+	maximum-speed = "high-speed";
+	usb-role-switch;
+	dr_mode = "otg";
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	wakeup-source;
+	status = "okay";
+
+	connector {
+		compatible = "usb-c-connector";
+		label = "USB-C";
+		data-role = "dual";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+				hs_ep: endpoint {
+					remote-endpoint = <&usb_hs_ep>;
+				};
+			};
+
+			port at 1 {
+				reg = <1>;
+				ss_ep: endpoint {
+					remote-endpoint = <&hd3ss3220_in_ep>;
+				};
+			};
+		};
+	};
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			reg = <0>;
+			usb_hs_ep: endpoint {
+				remote-endpoint = <&hs_ep>;
+			};
+		};
+
+		port at 1 {
+			reg = <1>;
+			usb_role_switch: endpoint {
+				remote-endpoint = <&hd3ss3220_out_ep>;
+			};
+		};
+	};
+};
+
+&u2port0 {
+	status = "okay";
+};
+
+&u3phy0 {
+	status = "okay";
+};
+
+&xhci0 {
+	vbus-supply = <&usb_p0_vbus>;
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	status = "okay";
+};
+
+&ssusb1 {
+	pinctrl-0 = <&usb1_pins>;
+	pinctrl-names = "default";
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	dr_mode = "host";
+	wakeup-source;
+	status = "okay";
+};
+
+&u2port1 {
+	status = "okay";
+};
+
+&u3port1 {
+	status = "okay";
+};
+
+&u3phy1 {
+	status = "okay";
+};
+
+&xhci1 {
+	vbus-supply = <&usb_p1_vbus>;
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	status = "okay";
+};
+
+&ssusb2 {
+	maximum-speed = "high-speed";
+	dr_mode = "host";
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	status = "okay";
+	wakeup-source;
+};
+
+&u2port2 {
+	status = "okay";
+};
+
+&u3phy2 {
+	status = "okay";
+};
+
+&xhci2 {
+	vbus-supply = <&usb_p2_vbus>;
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+
+	ethernet at 1 {
+		compatible = "usb424,7850";
+		reg = <1>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		mdio {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			ethernet-phy at 1 {
+				reg = <1>;
+				microchip,led-modes = <
+					LAN78XX_LINK_1000_ACTIVITY
+					LAN78XX_LINK_10_ACTIVITY
+					LAN78XX_LINK_10_100_ACTIVITY
+					LAN78XX_LINK_ACTIVITY
+				>;
+			};
+		};
+	};
+};
+
+&vdosys0 {
+	port {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		vdosys0_ep_main: endpoint at 0 {
+			reg = <0>;
+			remote-endpoint = <&ovl0_in>;
+		};
+	};
+};
+
+&watchdog {
+	pinctrl-names = "default";
+	pinctrl-0 = <&watchdog_pins>;
+};
+
+&pio {
+	audio_pins: audio-pins {
+		pins-aud-pmic {
+			pinmux = <
+				PINMUX_GPIO101__FUNC_O_AUD_CLK_MOSI
+				PINMUX_GPIO102__FUNC_O_AUD_SYNC_MOSI
+				PINMUX_GPIO103__FUNC_O_AUD_DAT_MOSI0
+				PINMUX_GPIO104__FUNC_O_AUD_DAT_MOSI1
+				PINMUX_GPIO105__FUNC_I0_AUD_DAT_MISO0
+				PINMUX_GPIO106__FUNC_I0_AUD_DAT_MISO1
+			>;
+		};
+
+		pins-pcm-wifi {
+			pinmux = <
+				PINMUX_GPIO121__FUNC_B0_PCM_CLK
+				PINMUX_GPIO122__FUNC_B0_PCM_SYNC
+				PINMUX_GPIO123__FUNC_O_PCM_DO
+				PINMUX_GPIO124__FUNC_I0_PCM_DI
+			>;
+		};
+
+		pins-i2s {
+			pinmux = <
+				PINMUX_GPIO119__FUNC_O_I2SO1_MCK
+				PINMUX_GPIO112__FUNC_O_I2SO1_WS
+				PINMUX_GPIO120__FUNC_O_I2SO1_BCK
+				PINMUX_GPIO113__FUNC_O_I2SO1_D0
+				PINMUX_GPIO110__FUNC_I0_I2SIN_D0
+			>;
+		};
+	};
+
+	disp_pwm0_pins: disp-pwm0-pins {
+		pins {
+			pinmux = <PINMUX_GPIO29__FUNC_O_DISP_PWM0>;
+			bias-pull-down;
+		};
+	};
+
+	dsi0_sn65dsi84_pins: dsi0-sn65dsi84-pins {
+		pins-irq {
+			pinmux = <PINMUX_GPIO128__FUNC_B_GPIO128>;
+			bias-pull-down;
+			input-enable;
+		};
+
+		pins-enable {
+			pinmux = <PINMUX_GPIO25__FUNC_B_GPIO25>;
+			bias-pull-down;
+		};
+	};
+
+	eth_default_pins: eth-default-pins {
+		pins-txd {
+			pinmux = <PINMUX_GPIO131__FUNC_O_GBE_TXD3>,
+				 <PINMUX_GPIO132__FUNC_O_GBE_TXD2>,
+				 <PINMUX_GPIO133__FUNC_O_GBE_TXD1>,
+				 <PINMUX_GPIO134__FUNC_O_GBE_TXD0>;
+			drive-strength = <MTK_DRIVE_8mA>;
+		};
+		pins-cc {
+			pinmux = <PINMUX_GPIO139__FUNC_B0_GBE_TXC>,
+				 <PINMUX_GPIO142__FUNC_O_GBE_TXEN>,
+				 <PINMUX_GPIO141__FUNC_I0_GBE_RXDV>;
+			drive-strength = <MTK_DRIVE_8mA>;
+		};
+		pins-rxd {
+			pinmux = <PINMUX_GPIO135__FUNC_I0_GBE_RXD3>,
+				 <PINMUX_GPIO136__FUNC_I0_GBE_RXD2>,
+				 <PINMUX_GPIO137__FUNC_I0_GBE_RXD1>,
+				 <PINMUX_GPIO138__FUNC_I0_GBE_RXD0>,
+				 <PINMUX_GPIO140__FUNC_I0_GBE_RXC>;
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
+		};
+		pins-mdio {
+			pinmux = <PINMUX_GPIO143__FUNC_O_GBE_MDC>,
+				 <PINMUX_GPIO144__FUNC_B1_GBE_MDIO>;
+			drive-strength = <MTK_DRIVE_8mA>;
+			input-enable;
+		};
+		pins-power {
+			pinmux = <PINMUX_GPIO27__FUNC_B_GPIO27>; /* GP_EQOS_RESET */
+			output-high;
+		};
+		pins-intr {
+			pinmux = <PINMUX_GPIO148__FUNC_B_GPIO148>; /* GPIRQ_EQOS_PHY */
+			bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
+			input-enable;
+		};
+	};
+
+	eth_sleep_pins: eth-sleep-pins {
+		pins-txd {
+			pinmux = <PINMUX_GPIO131__FUNC_B_GPIO131>,
+				 <PINMUX_GPIO132__FUNC_B_GPIO132>,
+				 <PINMUX_GPIO133__FUNC_B_GPIO133>,
+				 <PINMUX_GPIO134__FUNC_B_GPIO134>;
+		};
+		pins-cc {
+			pinmux = <PINMUX_GPIO139__FUNC_B_GPIO139>,
+				 <PINMUX_GPIO142__FUNC_B_GPIO142>,
+				 <PINMUX_GPIO141__FUNC_B_GPIO141>,
+				 <PINMUX_GPIO140__FUNC_B_GPIO140>;
+		};
+		pins-rxd {
+			pinmux = <PINMUX_GPIO135__FUNC_B_GPIO135>,
+				 <PINMUX_GPIO136__FUNC_B_GPIO136>,
+				 <PINMUX_GPIO137__FUNC_B_GPIO137>,
+				 <PINMUX_GPIO138__FUNC_B_GPIO138>;
+		};
+		pins-mdio {
+			pinmux = <PINMUX_GPIO143__FUNC_B_GPIO143>,
+				 <PINMUX_GPIO144__FUNC_B_GPIO144>;
+			input-disable;
+			bias-disable;
+		};
+	};
+
+	gpio_keys_pins: gpio-keys-pins {
+		pins-keys {
+			pinmux = <PINMUX_GPIO129__FUNC_B_GPIO129>,
+				 <PINMUX_GPIO65__FUNC_B_GPIO65>,
+				 <PINMUX_GPIO66__FUNC_B_GPIO66>;
+			bias-pull-up;
+		};
+	};
+
+	hd3ss3220_pins: hd3ss3320-pins {
+		pins-irq {
+			pinmux = <PINMUX_GPIO45__FUNC_B_GPIO45>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+			input-enable;
+		};
+	};
+
+	hdmi_vreg_pins: hdmi-vreg-pins {
+		pins-pwr {
+			pinmux = <PINMUX_GPIO50__FUNC_O_HDMITX20_PWR5V>;
+			bias-disable;
+		};
+	};
+
+	hdmi_pins: hdmi-pins {
+		pins-hotplug {
+			pinmux = <PINMUX_GPIO51__FUNC_I0_HDMITX20_HTPLG>;
+			bias-pull-down;
+		};
+
+		pins-cec {
+			pinmux = <PINMUX_GPIO52__FUNC_B1_HDMITX20_CEC>;
+			bias-disable;
+		};
+
+		pins-ddc {
+			pinmux = <PINMUX_GPIO53__FUNC_B1_HDMITX20_SCL>,
+				 <PINMUX_GPIO54__FUNC_B1_HDMITX20_SDA>;
+			drive-strength = <10>;
+		};
+	};
+
+	i2c0_pins: i2c0-pins {
+		pins-bus {
+			pinmux = <PINMUX_GPIO56__FUNC_B1_SDA0>,
+				 <PINMUX_GPIO55__FUNC_B1_SCL0>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c0_mux_pins: i2c0-mux-pins {
+		pins-reset {
+			pinmux = <PINMUX_GPIO6__FUNC_B_GPIO6>;
+			bias-pull-up;
+		};
+	};
+
+	i2c1_pins: i2c1-pins {
+		pins-bus {
+			pinmux = <PINMUX_GPIO58__FUNC_B1_SDA1>,
+				 <PINMUX_GPIO57__FUNC_B1_SCL1>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c2_pins: i2c2-pins {
+		pins-bus {
+			pinmux = <PINMUX_GPIO60__FUNC_B1_SDA2>,
+				 <PINMUX_GPIO59__FUNC_B1_SCL2>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c3_pins: i2c3-pins {
+		pins-bus {
+			pinmux = <PINMUX_GPIO62__FUNC_B1_SDA3>,
+				 <PINMUX_GPIO61__FUNC_B1_SCL3>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c4_pins: i2c4-pins {
+		pins-bus {
+			pinmux = <PINMUX_GPIO64__FUNC_B1_SDA4>,
+				 <PINMUX_GPIO63__FUNC_B1_SCL4>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c_mux_smarc_lcd_pins: i2c-mux-smarc-lcd-pins {
+		pins-reset {
+			pinmux = <PINMUX_GPIO5__FUNC_B_GPIO5>;
+			bias-pull-down;
+		};
+	};
+
+	mmc0_default_pins: mmc0-default-pins {
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO161__FUNC_B1_MSDC0_DAT0>,
+				 <PINMUX_GPIO160__FUNC_B1_MSDC0_DAT1>,
+				 <PINMUX_GPIO159__FUNC_B1_MSDC0_DAT2>,
+				 <PINMUX_GPIO158__FUNC_B1_MSDC0_DAT3>,
+				 <PINMUX_GPIO154__FUNC_B1_MSDC0_DAT4>,
+				 <PINMUX_GPIO153__FUNC_B1_MSDC0_DAT5>,
+				 <PINMUX_GPIO152__FUNC_B1_MSDC0_DAT6>,
+				 <PINMUX_GPIO151__FUNC_B1_MSDC0_DAT7>,
+				 <PINMUX_GPIO156__FUNC_B1_MSDC0_CMD>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins-clk {
+			pinmux = <PINMUX_GPIO157__FUNC_B1_MSDC0_CLK>;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-rst {
+			pinmux = <PINMUX_GPIO155__FUNC_O_MSDC0_RSTB>;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+
+	mmc0_uhs_pins: mmc0-uhs-pins {
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO161__FUNC_B1_MSDC0_DAT0>,
+				 <PINMUX_GPIO160__FUNC_B1_MSDC0_DAT1>,
+				 <PINMUX_GPIO159__FUNC_B1_MSDC0_DAT2>,
+				 <PINMUX_GPIO158__FUNC_B1_MSDC0_DAT3>,
+				 <PINMUX_GPIO154__FUNC_B1_MSDC0_DAT4>,
+				 <PINMUX_GPIO153__FUNC_B1_MSDC0_DAT5>,
+				 <PINMUX_GPIO152__FUNC_B1_MSDC0_DAT6>,
+				 <PINMUX_GPIO151__FUNC_B1_MSDC0_DAT7>,
+				 <PINMUX_GPIO156__FUNC_B1_MSDC0_CMD>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins-clk {
+			pinmux = <PINMUX_GPIO157__FUNC_B1_MSDC0_CLK>;
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-ds {
+			pinmux = <PINMUX_GPIO162__FUNC_B0_MSDC0_DSL>;
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-rst {
+			pinmux = <PINMUX_GPIO155__FUNC_O_MSDC0_RSTB>;
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+
+	mmc1_default_pins: mmc1-default-pins {
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO163__FUNC_B1_MSDC1_CMD>,
+				 <PINMUX_GPIO165__FUNC_B1_MSDC1_DAT0>,
+				 <PINMUX_GPIO166__FUNC_B1_MSDC1_DAT1>,
+				 <PINMUX_GPIO167__FUNC_B1_MSDC1_DAT2>,
+				 <PINMUX_GPIO168__FUNC_B1_MSDC1_DAT3>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins-pwr {
+			pinmux = <PINMUX_GPIO111__FUNC_B_GPIO111>;
+			bias-pull-down;
+		};
+
+		pins-pullup {
+			pinmux = <PINMUX_GPIO11__FUNC_B_GPIO11>;
+			bias-pull-up;
+		};
+
+		pins-clk {
+			pinmux = <PINMUX_GPIO164__FUNC_B1_MSDC1_CLK>;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-insert {
+			pinmux = <PINMUX_GPIO2__FUNC_B_GPIO2>;
+			bias-pull-up;
+		};
+	};
+
+	mmc1_uhs_pins: mmc1-uhs-pins {
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO163__FUNC_B1_MSDC1_CMD>,
+				 <PINMUX_GPIO165__FUNC_B1_MSDC1_DAT0>,
+				 <PINMUX_GPIO166__FUNC_B1_MSDC1_DAT1>,
+				 <PINMUX_GPIO167__FUNC_B1_MSDC1_DAT2>,
+				 <PINMUX_GPIO168__FUNC_B1_MSDC1_DAT3>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins-clk {
+			pinmux = <PINMUX_GPIO164__FUNC_B1_MSDC1_CLK>;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+	};
+
+	mmc2_default_pins: mmc2-default-pins {
+		pins-clk {
+			pinmux = <PINMUX_GPIO170__FUNC_B1_MSDC2_CLK>;
+			drive-strength = <MTK_DRIVE_4mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO169__FUNC_B1_MSDC2_CMD>,
+				 <PINMUX_GPIO171__FUNC_B1_MSDC2_DAT0>,
+				 <PINMUX_GPIO172__FUNC_B1_MSDC2_DAT1>,
+				 <PINMUX_GPIO173__FUNC_B1_MSDC2_DAT2>,
+				 <PINMUX_GPIO174__FUNC_B1_MSDC2_DAT3>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+
+	mmc2_uhs_pins: mmc2-uhs-pins {
+		pins-clk {
+			pinmux = <PINMUX_GPIO170__FUNC_B1_MSDC2_CLK>;
+			drive-strength = <MTK_DRIVE_4mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO169__FUNC_B1_MSDC2_CMD>,
+				 <PINMUX_GPIO171__FUNC_B1_MSDC2_DAT0>,
+				 <PINMUX_GPIO172__FUNC_B1_MSDC2_DAT1>,
+				 <PINMUX_GPIO173__FUNC_B1_MSDC2_DAT2>,
+				 <PINMUX_GPIO174__FUNC_B1_MSDC2_DAT3>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+
+	mmc2_eint_pins: mmc2-eint-pins {
+		pins-dat1 {
+			pinmux = <PINMUX_GPIO172__FUNC_B_GPIO172>;
+			input-enable;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+
+	rv3028_pins: rv3028-pins {
+		pins-irq {
+			pinmux = <PINMUX_GPIO42__FUNC_B_GPIO42>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+			input-enable;
+		};
+	};
+
+	spi0_pins: spi0-pins {
+		pins-spi {
+			pinmux = <PINMUX_GPIO69__FUNC_O_SPIM0_CSB>,
+				<PINMUX_GPIO70__FUNC_O_SPIM0_CLK>,
+				<PINMUX_GPIO71__FUNC_B0_SPIM0_MOSI>,
+				<PINMUX_GPIO72__FUNC_B0_SPIM0_MISO>;
+			bias-disable;
+		};
+	};
+
+	spi1_pins: spi1-pins {
+		pins-spi {
+			pinmux = <PINMUX_GPIO75__FUNC_O_SPIM1_CSB>,
+				<PINMUX_GPIO76__FUNC_O_SPIM1_CLK>,
+				<PINMUX_GPIO77__FUNC_B0_SPIM1_MOSI>,
+				<PINMUX_GPIO78__FUNC_B0_SPIM1_MISO>;
+			bias-disable;
+		};
+	};
+
+	pcie_default_pins: pcie-default-pins {
+		pins {
+			pinmux = <PINMUX_GPIO47__FUNC_I1_WAKEN>,
+				 <PINMUX_GPIO48__FUNC_O_PERSTN>,
+				 <PINMUX_GPIO49__FUNC_B1_CLKREQN>;
+			bias-pull-up;
+		};
+	};
+
+	ts_dsi0_goodix_pins: ts-dsi0-goodix-pins {
+		pins-irq {
+			pinmux = <PINMUX_GPIO146__FUNC_B_GPIO146>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+			input-enable;
+		};
+
+		pins-reset {
+			pinmux = <PINMUX_GPIO7__FUNC_B_GPIO7>;
+			bias-pull-down;
+		};
+	};
+
+	uart0_pins: uart0-pins {
+		pins {
+			pinmux = <PINMUX_GPIO31__FUNC_O_UTXD0>,
+				 <PINMUX_GPIO32__FUNC_I1_URXD0>;
+			bias-pull-up;
+		};
+	};
+
+	uart1_pins: uart1-pins {
+		pins {
+			pinmux = <PINMUX_GPIO33__FUNC_O_UTXD1>,
+				 <PINMUX_GPIO34__FUNC_I1_URXD1>;
+			bias-pull-up;
+		};
+	};
+
+	uart2_pins: uart2-pins {
+		pins {
+			pinmux = <PINMUX_GPIO35__FUNC_O_UTXD2>,
+				 <PINMUX_GPIO36__FUNC_I1_URXD2>;
+			bias-pull-up;
+		};
+	};
+
+	usbotg_pins: usbotg-pins {
+		pins-iddig {
+			pinmux = <PINMUX_GPIO83__FUNC_B_GPIO83>;
+			input-enable;
+			bias-pull-up;
+		};
+
+		pins-valid {
+			pinmux = <PINMUX_GPIO85__FUNC_I0_VBUSVALID>;
+			input-enable;
+		};
+
+		pins-vbus {
+			pinmux = <PINMUX_GPIO84__FUNC_O_USB_DRVVBUS>;
+			output-high;
+		};
+	};
+
+	usb1_hub_pins: usb1-hub-pins {
+		pins {
+			pinmux = <PINMUX_GPIO147__FUNC_B_GPIO147>;
+			output-low;
+		};
+	};
+
+	usb1_pins: usb1-pins {
+		pins {
+			pinmux = <PINMUX_GPIO88__FUNC_I0_VBUSVALID_1P>;
+			input-enable;
+		};
+	};
+
+	usb2_eth_pins: usb2-eth-pins {
+		pins {
+			pinmux = <PINMUX_GPIO80__FUNC_B_GPIO80>;
+			output-low;
+		};
+	};
+
+	wifi_pwrseq_pins: wifi-pwrseq-pins {
+		pins {
+			pinmux = <PINMUX_GPIO89__FUNC_B_GPIO89>;
+			output-low;
+		};
+	};
+
+	watchdog_pins: watchdog-pins {
+		pins {
+			pinmux = <PINMUX_GPIO100__FUNC_O_WATCHDOG>;
+			bias-pull-up;
+		};
+	};
+};

-- 
2.43.0



From bisson.gary at gmail.com  Tue Dec  2 14:08:49 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Tue, 02 Dec 2025 23:08:49 +0100
Subject: [PATCH v4 4/4] arm64: dts: mediatek: add device tree for Tungsten
 700 board
In-Reply-To: <20251202-review-v4-0-93f5cd2a0d4a@gmail.com>
References: <20251202-review-v4-0-93f5cd2a0d4a@gmail.com>
Message-ID: <20251202-review-v4-4-93f5cd2a0d4a@gmail.com>

Add device tree to support Ezurio Tungsten 700 (MT8390) SMARC SOM [1] +
Universal SMARC carrier board [2].
It includes support for the MIPI-DSI BD070LIC3 display which uses the
Tianma TM070JDHG30 panel + TI SN65DSI84 MIPI-DSI to LVDS bridge [3].

[1] https://www.ezurio.com/product/tungsten700-smarc
[2] https://www.ezurio.com/system-on-module/accessories/universal-smarc-carrier
[3] https://www.ezurio.com/product/bd070lic3-7-touchscreen-display

Signed-off-by: Gary Bisson <bisson.gary at gmail.com>

---
Changes in v2:
- None
Changed in v3:
- None
Changed in v4:
- None
---
 arch/arm64/boot/dts/mediatek/Makefile              |  1 +
 .../boot/dts/mediatek/mt8390-tungsten-smarc.dts    | 22 ++++++++++++++++++++++
 2 files changed, 23 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile
index 30d169a31b10..85f338344dd3 100644
--- a/arch/arm64/boot/dts/mediatek/Makefile
+++ b/arch/arm64/boot/dts/mediatek/Makefile
@@ -102,6 +102,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-genio-510-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-tungsten-smarc.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-genio-1200-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-genio-700-evk.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-tungsten-smarc.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-kontron-3-5-sbc-i1200.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-radxa-nio-12l.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-radxa-nio-12l-8-hd-panel.dtbo
diff --git a/arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts b/arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts
new file mode 100644
index 000000000000..f1cf2821107f
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2025 Ezurio LLC
+ * Author: Gary Bisson <bisson.gary at gmail.com>
+ */
+/dts-v1/;
+#include "mt8188.dtsi"
+#include "mt83x0-tungsten-smarc.dtsi"
+
+/ {
+	model = "Ezurio Tungsten700 SMARC (MT8390)";
+	compatible = "ezurio,mt8390-tungsten-smarc", "mediatek,mt8390",
+		     "mediatek,mt8188";
+};
+
+&cpu4 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};
+
+&cpu5 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};

-- 
2.43.0



From dianders at chromium.org  Tue Dec  2 14:07:29 2025
From: dianders at chromium.org (Doug Anderson)
Date: Tue, 2 Dec 2025 14:07:29 -0800
Subject: Proposal: Officially allow "incomplete" trees as a base
In-Reply-To: <CAFLszTiVT9rHwympUJSehxaDR7ks9Bs2FVjYEuN6=j1e_-289Q@mail.gmail.com>
References: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
 <CAFLszTiVT9rHwympUJSehxaDR7ks9Bs2FVjYEuN6=j1e_-289Q@mail.gmail.com>
Message-ID: <CAD=FV=Vrit=N6L30dA3X6uV95e5E1bVoLph55_=ihqSTBy52FQ@mail.gmail.com>

Hi Simon!

On Tue, Dec 2, 2025 at 12:07?PM Simon Glass <sjg at chromium.org> wrote:
>
> > 1. Allow the top-level compatible string of an "incomplete" device
> > tree to be documented so it can be validated on its own by tools. It's
> > understood that this SoC is not a board by itself and we'd never boot
> > a full OS with this device tree without adding an overlay that changes
> > the top-level compatible. Add a top-level property to the device tree
> > (perhaps "incomplete-compatible;") to indicate that the tree is not
> > complete without an overlay.
>
> or be more description, e.g.: compatible-scope = "soc"  - or just scope = "soc"
>
> In other words, I don't think we should be frightened to define some
> levels (soc, som, carrier, exxpansion, chassis?)

Sure, I'd be OK with this if this is what DT folks want. I don't have
any strong opinions here. NOTE: something like this would only make
sense if we're going to introduce new variants on how we apply
overlays (like merging compatible strings).


> > 2. If it turns out to be needed (hopefully it's not), allow some type
> > of syntax in yaml files that allows a property to be marked as
> > "required" in a "complete" device tree but not in an "incomplete"
> > device tree. Alternatively, we could discourage marking properties as
> > "required" if they're expected to be filled in by a board.
>
> Another option would be to validate the soc DT with a chosen board,
> just as a workaround. It would probably be good enough.

Sure, though I think Rob and Krzysztof are pretty interested in being
able to validate the SoC DTB by itself. I'd like to at least set that
as a goal. If we find some reason why we _truly_ can't achieve that
then we can talk about relaxing it, but I'd like to start with the
more aggressive goal.


> We don't need to worry about old bootloaders since they presumably are
> not installed on new hardware. Assuming Linux adopts this proposal, I
> am sure people will implement it in bootloaders when they need to.

Right. IMO if we have to make changes to the way overlays are applied
and we can do it in a simple and backward compatible way, it should be
OK. Only new bootloaders would be able to take advantage of it, but
presumably we'll have to modify bootloaders a little anyway when we
standardize on ways to pick the right overlays to apply...


From pavel at ucw.cz  Tue Dec  2 14:14:01 2025
From: pavel at ucw.cz (Pavel Machek)
Date: Tue, 2 Dec 2025 23:14:01 +0100
Subject: [PATCH 0/4] arm64: google: Introduce frankel, blazer, and
 mustang boards
In-Reply-To: <CAD=FV=WVeiGa6YkRmce4McnePEV9X_n79YA0bywPdNZcZCV=ZQ@mail.gmail.com>
References: <20251111192422.4180216-1-dianders@chromium.org>
 <aSOKS35/huSWd/RW@duo.ucw.cz>
 <CAD=FV=WVeiGa6YkRmce4McnePEV9X_n79YA0bywPdNZcZCV=ZQ@mail.gmail.com>
Message-ID: <aS9kqTTiH2keDL5G@duo.ucw.cz>

Hi!

> > > This series adds barebones device trees for Pixel 10 (frankel), Pixel
> > > 10 Pro (blazer), and Pixel 10 Pro XL (mustang). With a yet-unreleased
> > > bootloader these can boot to a UART command prompt from an initramfs.
> >
> > Well, booting to full system with working cameras would be nicer,
> 
> For sure!
> 
> 
> > but
> > this is good start. Do you plan / do you have resources for full
> > support in some reasonable timeframe?
> 
> As you can probably guess, I can't really make any promises. :-) Of
> course, "full support" of Pixel 10 by an upstream kernel in a
> "reasonable" timeframe could arguably be impossible no matter how many
> resources were thrown at it. There are just some drivers / subsystems
> where getting upstream working as well as downstream is working
> doesn't feel likely as a short term goal.
> 
> That all being said, interest / support from the community helps.
> Knowing that people are interested in this work helps motivate folks
> at Google and (hopefully) upstream maintainers.

Motivation is certainly there, and race for usable, supported phone is
still continuing. Check https://wiki.postmarketos.org/wiki/Devices for
small glimpse into "mainline on phones" effort.

Best regards,

								Pavel
-- 
I don't work for Nazis and criminals, and neither should you.
Boycott Putin, Trump, Netanyahu and Musk!
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 195 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251202/677dfb82/attachment.sig>

From dianders at chromium.org  Tue Dec  2 14:30:52 2025
From: dianders at chromium.org (Doug Anderson)
Date: Tue, 2 Dec 2025 14:30:52 -0800
Subject: Proposal: Officially allow "incomplete" trees as a base
In-Reply-To: <CAODwPW-sBSZfzbTnYLcGr2sN=+5p+okUeJEJeVvJOHCx3JbOgg@mail.gmail.com>
References: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
 <aS66WcLPm6e5rdyk@shell.armlinux.org.uk> <CAODwPW-sBSZfzbTnYLcGr2sN=+5p+okUeJEJeVvJOHCx3JbOgg@mail.gmail.com>
Message-ID: <CAD=FV=WsWNb3FnHQHKGKzTckLuPNR4iDCQ2rxg07bLXwqZ-pWA@mail.gmail.com>

Hi,

On Tue, Dec 2, 2025 at 1:58?PM Julius Werner <jwerner at chromium.org> wrote:
>
> >> Is there really a need to merge the compatible strings in your case?
> >
> > Well, you could just require duplicating an overlay N times for N bases, but that doesn't scale
>
> I think my question was more along the lines of "is there actually a
> reason why the combined compatible string needs to be that accurate"
> (i.e. contain the right "socvendor,mysoc-rev1" or
> "socvendor,mysoc-rev2"). What is the purpose of having that string in
> there?

Yes, this matches what I just sent in several of my replies. What
exactly is the top-level compatible supposed to represent? I think
different people have different ideas. Is it documented somewhere? I
guess I could start a new thread to solve just this one question,
though I suspect not everyone (not even core DT folks) will agree. If
they don't, how do we solve that? Who is "the decider"?


> It wouldn't be used for matching which DTB(O) to load in this
> case because we're already past that step. It's not used by the kernel
> directly for anything as far as I know.

It has _sometimes_ been used by the Linux kernel. Specifically the
fact that the SoC is represented in the top-level compatible is used
to "blocklist" the generic cpufreq driver
(drivers/cpufreq/cpufreq-dt-platdev.c). I've never loved this, but it
is an example.

Occasionally, I have also seen random software workarounds that rely
on the top-level string. See Linux commit 127068abe85b ("i2c:
qcom-geni: Disable DMA processing on the Lenovo Yoga C630"), which
added:

+       if (!of_machine_is_compatible("lenovo,yoga-c630"))
+               dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);

...that's been since removed, but it's one example I can think of
where the top-level string was temporarily relied upon.

There are certainly lots of hits for `of_machine_is_compatible()` in
Linux today. I don't know if these are all for good reasons, but they
are examples of people relying on it. In my experience it's mostly
used for things that are a bit hacky, to avoid an unexplained bug, or
to work around the fact that someone didn't add a specific enough
compatible string somewhere else in the device tree.


> Is it used by userspace
> programs which parse /proc/device-tree/compatible in order to detect
> which SoC revision they're running on? Because that's the only use
> case I could think of that really remains, but I'd argue that the
> compatible string is a pretty poor vehicle for things like that

Agreed. This type of thing has always been broken on Chromebooks which
have more than one revision/sku listed since a single device tree
works on more than one device. We had long arguments about this in the
past and I think DT folks finally threw in the towel and let us land
these, though I think they still don't really like it to this day.


> (it
> would be easier to parse and use to just put a `soc-revision = <1>`
> property somewhere). So if this is the only problem I'd say maybe just
> don't use the board compatible string for that, don't expect to be
> able to find such details in there accurately. But if we do think it
> needs to be that accurate for some reason, then I'd suggest platforms
> like this (which should be rather few, e.g. only those that really
> have a socketable SoC with differentiations that are so compatible
> that other than this identification information itself it doesn't
> require any device tree differences) should simply have their
> bootloaders rewrite the compatible string into the right format with
> all the necessary information manually, rather than expect the overlay
> application process to create it correctly.

Yeah, trying to stuff the world into the top-level compatible never
seemed amazing to me. Given that today's advice is to have a top-level
`soc at 0` node, IMO SoC-specific details ought to be under that. This is
something that Stephen Boyd suggested a while ago but it never gained
traction.


> > I also don't see a sensible way without something like the above for a
> > boot loader to know the filenames of each of the components for a
> > platform - and it would need to be told the order to glue those
> > components together.
>
> I think platform identification and matching which overlays to apply
> should remain outside the scope of the device tree itself. The main
> reason is that you usually want to compress DTB(O) files for
> efficiency, and when you have a large list of overlays in a kernel
> image you don't want to have to decompress them all just to determine
> which ones to load for the current platform. So I think it's generally
> better to let bootloaders come up with their own scheme to store this
> information inside their file systems or whatever other data
> structures they use to find these DTB(O) files.

IMO it's still nice to be able to store some of the metadata that the
loader will use in the overlay files, just so we don't need a parallel
set of files. The current Android way of doing things is that the
metadata in the "dtbo" is parsed by the packaging tool (`mktdimg`) and
that creates the tables that the bootloader needs. This seems
reasonable, even though I'll argue that the metadata needs to be
documented under a specific node (one for `mkdtimg`). I wouldn't want
to have to maintain a separate file mapping overlays to their
metadata.

-Doug


From rdunlap at infradead.org  Tue Dec  2 14:37:53 2025
From: rdunlap at infradead.org (Randy Dunlap)
Date: Tue, 2 Dec 2025 14:37:53 -0800
Subject: linux-next: Tree for Nov 28
 (drivers/pci/controller/dwc/pcie-nxp-s32g.o)
In-Reply-To: <6ulzkdgd6j35ptu5mesgtgh2xa6fwalcmkgcxr2fdjwwfvzhrf@4dtcadsl2mvm>
References: <20251128162928.36eec2d6@canb.auug.org.au>
 <63e1daf7-f9a3-463e-8a1b-e9b72581c7af@infradead.org>
 <ykmo5qv46mo7f3srblxoi2fvghz722fj7kpm77ozpflaqup6rk@ttvhbw445pgu>
 <CAKfTPtA-wir5GzU7aTywe7SZG18Aj8Z9g1wjV-Y8vKoyKF1Mkg@mail.gmail.com>
 <vb6pcyaue6pqpx626ytfr2aif4luypopywqoazjsvy4crh6zic@gfv75ar7musy>
 <CAKfTPtCKmj_dHGU-2WPsEevf7CR-isRiyM0+oftCrMy5MswE4A@mail.gmail.com>
 <6ulzkdgd6j35ptu5mesgtgh2xa6fwalcmkgcxr2fdjwwfvzhrf@4dtcadsl2mvm>
Message-ID: <77bad218-9120-49d5-9d5a-7b1dcebf09b2@infradead.org>



On 12/2/25 2:12 AM, Manivannan Sadhasivam wrote:
> On Tue, Dec 02, 2025 at 11:03:07AM +0100, Vincent Guittot wrote:
>> On Tue, 2 Dec 2025 at 10:53, Manivannan Sadhasivam <mani at kernel.org> wrote:
>>>
>>> On Tue, Dec 02, 2025 at 09:54:24AM +0100, Vincent Guittot wrote:
>>>> On Tue, 2 Dec 2025 at 05:24, Manivannan Sadhasivam <mani at kernel.org> wrote:
>>>>>
>>>>> + Vincent
>>>>
>>>> Thanks for looping me in.
>>>>>
>>>>> On Sat, Nov 29, 2025 at 07:00:04PM -0800, Randy Dunlap wrote:
>>>>>>
>>>>>>
>>>>>> On 11/27/25 9:29 PM, Stephen Rothwell wrote:
>>>>>>> Hi all,
>>>>>>>
>>>>>>> Changes since 20251127:
>>>>>>>
>>>>>>
>>>>>> on i386 (allmodconfig):
>>>>>>
>>>>>> WARNING: modpost: vmlinux: section mismatch in reference: s32g_init_pcie_controller+0x2b (section: .text) -> memblock_start_of_DRAM (section: .init.text)
>>>>
>>>> Are there details to reproduce the warning ? I don't have such warning
>>>> when compiling allmodconfig locally
>>>>
>>>> s32 pcie can only be built in but I may have to use
>>>> builtin_platform_driver_probe() instead of builtin_platform_driver()
>>>>
>>>
>>> The is due to calling a function belonging to the __init section from non-init
>>> function. Ideally, functions prefixed with __init like memblock_start_of_DRAM()
>>> should be called from the module init functions.
>>>
>>> One way to fix would be to call memblock_start_of_DRAM() in probe(), and
>>> annotate probe() with __init. Since there is no remove, you could use
>>> builtin_platform_driver_probe().
>>>
>>> This also makes me wonder if we really should be using memblock_start_of_DRAM()
>>> in the driver. I know that this was suggested to you during reviews, but I would
>>> prefer to avoid it, especially due to this being the __init function.
>>
>> yeah, I suppose I can directly define the value in the driver has
>> there is only one memory config for now anyway
>>
>> /* Boundary between peripheral space and physical memory space */
>> #define S32G_MEMORY_BOUNDARY_ADDR 0x80000000
>>
> 
> Ok. I fixed it up myself with below diff:

Thanks.
Tested-by: Randy Dunlap <rdunlap at infradead.org> # build-tested

> diff --git a/drivers/pci/controller/dwc/pcie-nxp-s32g.c b/drivers/pci/controller/dwc/pcie-nxp-s32g.c
> index eacf0229762c..70b1dc404bbe 100644
> --- a/drivers/pci/controller/dwc/pcie-nxp-s32g.c
> +++ b/drivers/pci/controller/dwc/pcie-nxp-s32g.c
> @@ -7,7 +7,6 @@
>  
>  #include <linux/interrupt.h>
>  #include <linux/io.h>
> -#include <linux/memblock.h>
>  #include <linux/module.h>
>  #include <linux/of_device.h>
>  #include <linux/of_address.h>
> @@ -35,6 +34,9 @@
>  #define PCIE_S32G_PE0_INT_STS                  0xE8
>  #define HP_INT_STS                             BIT(6)
>  
> +/* Boundary between peripheral space and physical memory space */
> +#define S32G_MEMORY_BOUNDARY_ADDR              0x80000000
> +
>  struct s32g_pcie_port {
>         struct list_head list;
>         struct phy *phy;
> @@ -99,10 +101,10 @@ static struct dw_pcie_ops s32g_pcie_ops = {
>  };
>  
>  /* Configure the AMBA AXI Coherency Extensions (ACE) interface */
> -static void s32g_pcie_reset_mstr_ace(struct dw_pcie *pci, u64 ddr_base_addr)
> +static void s32g_pcie_reset_mstr_ace(struct dw_pcie *pci)
>  {
> -       u32 ddr_base_low = lower_32_bits(ddr_base_addr);
> -       u32 ddr_base_high = upper_32_bits(ddr_base_addr);
> +       u32 ddr_base_low = lower_32_bits(S32G_MEMORY_BOUNDARY_ADDR);
> +       u32 ddr_base_high = upper_32_bits(S32G_MEMORY_BOUNDARY_ADDR);
>  
>         dw_pcie_dbi_ro_wr_en(pci);
>         dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_3_OFF, 0x0);
> @@ -149,7 +151,7 @@ static int s32g_init_pcie_controller(struct dw_pcie_rp *pp)
>          * Make sure we use the coherency defaults (just in case the settings
>          * have been changed from their reset values)
>          */
> -       s32g_pcie_reset_mstr_ace(pci, memblock_start_of_DRAM());
> +       s32g_pcie_reset_mstr_ace(pci);
>  
>         dw_pcie_dbi_ro_wr_en(pci);
> 
> - Mani
> 

-- 
~Randy


From oupton at kernel.org  Tue Dec  2 14:43:36 2025
From: oupton at kernel.org (Oliver Upton)
Date: Tue, 2 Dec 2025 14:43:36 -0800
Subject: [PATCH v1 0/5] KVM: arm64: Enforce MTE disablement at EL2
In-Reply-To: <20251127122210.4111702-1-tabba@google.com>
References: <20251127122210.4111702-1-tabba@google.com>
Message-ID: <aS9rmMgNna7I5g4F@kernel.org>

Hi Fuad,

On Thu, Nov 27, 2025 at 12:22:05PM +0000, Fuad Tabba wrote:
> pKVM never exposes MTE to protected guests (pVM), but we must also
> ensure a malicious host cannot use MTE to attack the hypervisor or a
> pVM.
> 
> If MTE is supported by the hardware (and is enabled at EL3), it remains
> available to lower exception levels by default. Disabling it in the host
> kernel (e.g., via 'arm64.nomte') only stops the kernel from advertising
> the feature; it does not physically disable MTE in the hardware.
> 
> In this scenario, a malicious host could still access tags in pages
> donated to a guest using MTE instructions (e.g., STG and LDG), bypassing
> the kernel's configuration.
> 
> To prevent this, explicitly disable MTE at EL2 (by clearing HCR_EL2.ATA)
> when the host has MTE disabled. This causes any MTE instruction usage to
> generate a Data Abort (trap) to the hypervisor.
> 
> Additionally, to faithfully mimic hardware that does not support MTE,
> trap accesses to MTE system registers (e.g., GCR_EL1) and inject an
> Undefined Instruction exception back to the host.
> 
> This logic is applied in all non-VHE modes. For non-protected modes,
> this remains beneficial as it prevents unpredictable behavior caused by
> accessing allocation tags when the system considers them disabled.
> 
> Note that this ties into my other outgoing patch series [1], which also
> has some MTE-related fixes, but is not dependent on it.

To be honest, I've actually been having a bit of a hard time
rationalizing some of these targeted fixes for pKVM. It has been in a
half working state upstream for O(years) and we haven't made forward
progress on enabling pVMs.

Fully aware that guest_memfd has been one of the long poles here, but
I'm becoming less interested in fixes addressing "pKVM policy is XYZ"
without having the full picture of the feature.

What are the upstream plans on enabling some basic implementation of
protected VMs?

Thanks,
Oliver


From cmarinas at kernel.org  Tue Dec  2 15:05:56 2025
From: cmarinas at kernel.org (Catalin Marinas)
Date: Tue, 2 Dec 2025 23:05:56 +0000
Subject: [GIT PULL] arm64 updates for 6.19
Message-ID: <aS9w1LWtsZFLX9I9@arm.com>

Hi Linus,

These are the arm64 updates for 6.19. The biggest part is the Arm MPAM
driver under drivers/resctrl/. There's a patch touching mm/ to handle
spurious faults for huge pmd (similar to the pte version). The
corresponding arm64 part allows us to avoid the TLB maintenance if a
(huge) page is reused after a write fault. There's EFI refactoring to
allow runtime services with preemption enabled and the rest is the usual
perf/PMU updates and several cleanups/typos.

The git conflicts are relatively simple, see the end of this email
(after diffstats) for my resolution. However, there's another diff
needed to avoid build failures after the merge due to the changes via
the tip tree, commit 8cea569ca785 ("sched/mmcid: Use proper data
structures"). Same resolution as in -next:

------------------8<------------------------
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index fc407d891348..a9070d00b833 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -75,7 +75,7 @@ struct mm_struct efi_mm = {
 	.mmlist			= LIST_HEAD_INIT(efi_mm.mmlist),
 	.cpu_bitmap		= { [BITS_TO_LONGS(NR_CPUS)] = 0},
 #ifdef CONFIG_SCHED_MM_CID
-	.cpus_allowed_lock	= __RAW_SPIN_LOCK_UNLOCKED(efi_mm.cpus_allowed_lock),
+	.mm_cid.lock		= __RAW_SPIN_LOCK_UNLOCKED(efi_mm.mm_cid.lock),
 #endif
 };
------------------8<------------------------

Thanks.

The following changes since commit 3a8660878839faadb4f1a6dd72c3179c1df56787:

  Linux 6.18-rc1 (2025-10-12 13:42:36 -0700)

are available in the Git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux tags/arm64-upstream

for you to fetch changes up to edde060637b92607f3522252c03d64ad06369933:

  Merge branch 'for-next/set_memory' into for-next/core (2025-11-28 15:48:03 +0000)

----------------------------------------------------------------
arm64 updates for 6.19:

Core features:

 - Basic Arm MPAM (Memory system resource Partitioning And Monitoring)
   driver under drivers/resctrl/ which makes use of the fs/rectrl/ API

Perf and PMU:

 - Avoid cycle counter on multi-threaded CPUs

 - Extend CSPMU device probing and add additional filtering support for
   NVIDIA implementations

 - Add support for the PMUs on the NoC S3 interconnect

 - Add additional compatible strings for new Cortex and C1 CPUs

 - Add support for data source filtering to the SPE driver

 - Add support for i.MX8QM and "DB" PMU in the imx PMU driver

Memory managemennt:

 - Avoid broadcast TLBI if page reused in write fault

 - Elide TLB invalidation if the old PTE was not valid

 - Drop redundant cpu_set_*_tcr_t0sz() macros

 - Propagate pgtable_alloc() errors outside of __create_pgd_mapping()

 - Propagate return value from __change_memory_common()

ACPI and EFI:

 - Call EFI runtime services without disabling preemption

 - Remove unused ACPI function

Miscellaneous:

 - ptrace support to disable streaming on SME-only systems

 - Improve sysreg generation to include a 'Prefix' descriptor

 - Replace __ASSEMBLY__ with __ASSEMBLER__

 - Align register dumps in the kselftest zt-test

 - Remove some no longer used macros/functions

 - Various spelling corrections

----------------------------------------------------------------
Anshuman Khandual (3):
      arm64/mm: Drop cpu_set_[default|idmap]_tcr_t0sz()
      arm64/mm: Ensure PGD_SIZE is aligned to 64 bytes when PA_BITS = 52
      arm64/sysreg: Replace TCR_EL1 field macros

Ard Biesheuvel (7):
      efi: Add missing static initializer for efi_mm::cpus_allowed_lock
      efi/runtime-wrappers: Keep track of the efi_runtime_lock owner
      arm64/fpsimd: Don't warn when EFI execution context is preemptible
      arm64/fpsimd: Permit kernel mode NEON with IRQs off
      arm64/efi: Drop efi_rt_lock spinlock from EFI arch wrapper
      arm64/efi: Move uaccess en/disable out of efi_set_pgd()
      arm64/efi: Call EFI runtime services without disabling preemption

Ben Horgan (8):
      ACPI / PPTT: Add acpi_pptt_cache_v1_full to use pptt cache as one structure
      platform: Define platform_device_put cleanup handler
      ACPI: Define acpi_put_table cleanup handler and acpi_get_table_pointer() helper
      arm_mpam: Consider overflow in bandwidth counter state
      MAINTAINERS: new entry for MPAM Driver
      KVM: arm64: selftests: Remove ARM64_FEATURE_FIELD_BITS and its last user
      KVM: arm64: selftests: Consider all 7 possible levels of cache
      arm64/sysreg: Remove unused define ARM64_FEATURE_FIELD_BITS

Besar Wicaksono (4):
      perf/arm_cspmu: Add callback to reset filter config
      perf/arm_cspmu: Add pmpidr support
      perf/arm_cspmu: nvidia: Add revision id matching
      perf/arm_cspmu: nvidia: Add pmevfiltr2 support

Bo Liu (1):
      arm64: Fix double word in comments

Cai Xinchen (1):
      arm64: remove duplicate ARCH_HAS_MEM_ENCRYPT

Catalin Marinas (3):
      Merge branches 'for-next/misc', 'for-next/kselftest', 'for-next/efi-preempt', 'for-next/assembler-macro', 'for-next/typos', 'for-next/sme-ptrace-disable', 'for-next/local-tlbi-page-reused', 'for-next/mpam', 'for-next/acpi' and 'for-next/documentation', remote-tracking branch 'arm64/for-next/perf' into for-next/core
      Merge branch 'for-next/sysreg' into for-next/core
      Merge branch 'for-next/set_memory' into for-next/core

Chaitanya S Prakash (1):
      arm64/mm: Allow __create_pgd_mapping() to propagate pgtable_alloc() errors

Dawei Li (1):
      arm64: Remove assertion on CONFIG_VMAP_STACK

Dev Jain (3):
      arm64/mm: Elide TLB flush in certain pte protection transitions
      arm64/pageattr: Propagate return value from __change_memory_common
      arm64/mm: Document why linear map split failure upon vm_reset_perms is not problematic

Frank Li (3):
      dt-bindings: perf: fsl-imx-ddr: Add compatible string for i.MX8QM, i.MX8QXP and i.MX8DXL
      perf/imx_ddr: Move ida_alloc() from ddr_perf_init() to ddr_perf_probe()
      perf/imx_ddr: Get and enable optional clks

Huang Ying (2):
      mm: add spurious fault fixing support for huge pmd
      arm64, tlbflush: don't TLBI broadcast if page reused in write fault

James Clark (2):
      perf: Add perf_event_attr::config4
      perf: arm_spe: Add support for filtering on data source

James Morse (27):
      ACPI / PPTT: Add a helper to fill a cpumask from a processor container
      ACPI / PPTT: Stop acpi_count_levels() expecting callers to clear levels
      ACPI / PPTT: Find cache level by cache-id
      ACPI / PPTT: Add a helper to fill a cpumask from a cache_id
      arm64: kconfig: Add Kconfig entry for MPAM
      ACPI / MPAM: Parse the MPAM table
      arm_mpam: Add probe/remove for mpam msc driver and kbuild boiler plate
      arm_mpam: Add the class and component structures for firmware described ris
      arm_mpam: Add MPAM MSC register layout definitions
      arm_mpam: Add cpuhp callbacks to probe MSC hardware
      arm_mpam: Probe hardware to find the supported partid/pmg values
      arm_mpam: Add helpers for managing the locking around the mon_sel registers
      arm_mpam: Probe the hardware features resctrl supports
      arm_mpam: Merge supported features during mpam_enable() into mpam_class
      arm_mpam: Reset MSC controls from cpuhp callbacks
      arm_mpam: Add a helper to touch an MSC from any CPU
      arm_mpam: Extend reset logic to allow devices to be reset any time
      arm_mpam: Register and enable IRQs
      arm_mpam: Use a static key to indicate when mpam is enabled
      arm_mpam: Allow configuration to be applied and restored during cpu online
      arm_mpam: Probe and reset the rest of the features
      arm_mpam: Add helpers to allocate monitors
      arm_mpam: Add mpam_msmon_read() to read monitor value
      arm_mpam: Track bandwidth counter state for power management
      arm_mpam: Add helper to reset saved mbwu state
      arm_mpam: Add kunit test for bitmap reset
      arm_mpam: Add kunit tests for props_mismatch()

Joakim Zhang (1):
      perf/imx_ddr: Add support for PMU in DB (system interconnects)

Li Qiang (1):
      arm64: add unlikely hint to MTE async fault check in el0_svc_common

Linu Cherian (1):
      arm64/mm: Rename try_pgd_pgtable_alloc_init_mm

Linus Walleij (1):
      arm64: entry: Clean out some indirection

Ma Ke (1):
      perf: arm_cspmu: fix error handling in arm_cspmu_impl_unregister()

Marc Zyngier (1):
      ACPI: GTDT: Get rid of acpi_arch_timer_mem_init()

Mark Brown (3):
      arm64/sme: Support disabling streaming mode via ptrace on SME only systems
      kselftst/arm64: Test NT_ARM_SVE FPSIMD format writes on non-SVE systems
      kselftest/arm64: Cover disabling streaming mode without SVE in fp-ptrace

Mark Rutland (1):
      kselftest/arm64: Align zt-test register dumps

Omar Sandoval (1):
      arm64: remove unused ARCH_PFN_OFFSET

Osama Abdelkader (1):
      arm64: acpi: add newline to deferred APEI warning

Rob Herring (Arm) (1):
      perf: arm_pmuv3: Add new Cortex and C1 CPU PMUs

Robin Murphy (2):
      perf/arm-ni: Add NoC S3 support
      perf/arm-ni: Fix and optimise register offset calculation

Rohit Mathew (2):
      arm_mpam: Probe for long/lwd mbwu counters
      arm_mpam: Use long MBWU counters if supported

Ryo Takakura (1):
      arm64: use SOFTIRQ_ON_OWN_STACK for enabling softirq stack

Sascha Bischoff (4):
      arm64/sysreg: Fix checks for incomplete sysreg definitions
      arm64/sysreg: Support feature-specific fields with 'Prefix' descriptor
      arm64/sysreg: Move generation of RES0/RES1/UNKN to function
      arm64/sysreg: Add ICH_VMCR_EL2

Seongsu Park (1):
      arm64: atomics: lse: Remove unused parameters from ATOMIC_FETCH_OP_AND macros

Thomas Huth (2):
      arm64: Replace __ASSEMBLY__ with __ASSEMBLER__ in uapi headers
      arm64: Replace __ASSEMBLY__ with __ASSEMBLER__ in non-uapi headers

Yang Shi (2):
      arm64: mm: make linear mapping permission update more robust for patial range
      arm64: mm: use untagged address to calculate page index

Yicong Yang (2):
      perf: arm_pmuv3: Don't use PMCCNTR_EL0 on SMT cores
      arch_topology: Provide a stub topology_core_has_smt() for !CONFIG_GENERIC_ARCH_TOPOLOGY

Zenon Xiu (1):
      Documentation/arm64: Fix the typo of register names

mrigendrachaubey (1):
      arm64: Fix typos and spelling errors in comments

 Documentation/arch/arm64/booting.rst               |    8 +-
 Documentation/arch/arm64/sve.rst                   |    5 +
 .../devicetree/bindings/perf/fsl-imx-ddr.yaml      |   29 +-
 MAINTAINERS                                        |   10 +
 arch/arm64/Kconfig                                 |   26 +-
 arch/arm64/include/asm/alternative-macros.h        |    8 +-
 arch/arm64/include/asm/alternative.h               |    4 +-
 arch/arm64/include/asm/arch_gicv3.h                |    4 +-
 arch/arm64/include/asm/asm-extable.h               |    6 +-
 arch/arm64/include/asm/assembler.h                 |   12 +-
 arch/arm64/include/asm/atomic_lse.h                |   20 +-
 arch/arm64/include/asm/barrier.h                   |    4 +-
 arch/arm64/include/asm/cache.h                     |    4 +-
 arch/arm64/include/asm/cpucaps.h                   |    4 +-
 arch/arm64/include/asm/cpufeature.h                |    8 +-
 arch/arm64/include/asm/cputype.h                   |    6 +-
 arch/arm64/include/asm/current.h                   |    4 +-
 arch/arm64/include/asm/debug-monitors.h            |    4 +-
 arch/arm64/include/asm/efi.h                       |   13 +-
 arch/arm64/include/asm/el2_setup.h                 |    4 +-
 arch/arm64/include/asm/elf.h                       |    4 +-
 arch/arm64/include/asm/esr.h                       |    4 +-
 arch/arm64/include/asm/fixmap.h                    |    4 +-
 arch/arm64/include/asm/fpsimd.h                    |    2 +-
 arch/arm64/include/asm/ftrace.h                    |    6 +-
 arch/arm64/include/asm/gpr-num.h                   |    6 +-
 arch/arm64/include/asm/hwcap.h                     |    2 +-
 arch/arm64/include/asm/image.h                     |    4 +-
 arch/arm64/include/asm/insn.h                      |    4 +-
 arch/arm64/include/asm/jump_label.h                |    4 +-
 arch/arm64/include/asm/kasan.h                     |    2 +-
 arch/arm64/include/asm/kexec.h                     |    4 +-
 arch/arm64/include/asm/kgdb.h                      |    4 +-
 arch/arm64/include/asm/kvm_asm.h                   |    4 +-
 arch/arm64/include/asm/kvm_mmu.h                   |    4 +-
 arch/arm64/include/asm/kvm_mte.h                   |    4 +-
 arch/arm64/include/asm/kvm_ptrauth.h               |    6 +-
 arch/arm64/include/asm/linkage.h                   |    2 +-
 arch/arm64/include/asm/memory.h                    |    5 +-
 arch/arm64/include/asm/mmu.h                       |    4 +-
 arch/arm64/include/asm/mmu_context.h               |   20 +-
 arch/arm64/include/asm/mte-kasan.h                 |    4 +-
 arch/arm64/include/asm/mte.h                       |    4 +-
 arch/arm64/include/asm/page.h                      |    4 +-
 arch/arm64/include/asm/pgtable-hwdef.h             |  125 +-
 arch/arm64/include/asm/pgtable-prot.h              |    6 +-
 arch/arm64/include/asm/pgtable.h                   |   22 +-
 arch/arm64/include/asm/proc-fns.h                  |    4 +-
 arch/arm64/include/asm/processor.h                 |    4 +-
 arch/arm64/include/asm/ptrace.h                    |    4 +-
 arch/arm64/include/asm/rsi_smc.h                   |    4 +-
 arch/arm64/include/asm/rwonce.h                    |    4 +-
 arch/arm64/include/asm/scs.h                       |    4 +-
 arch/arm64/include/asm/sdei.h                      |    4 +-
 arch/arm64/include/asm/simd.h                      |    2 +-
 arch/arm64/include/asm/smp.h                       |    4 +-
 arch/arm64/include/asm/spectre.h                   |    4 +-
 arch/arm64/include/asm/stacktrace/frame.h          |    4 +-
 arch/arm64/include/asm/suspend.h                   |    2 +-
 arch/arm64/include/asm/sysreg.h                    |   12 +-
 arch/arm64/include/asm/system_misc.h               |    4 +-
 arch/arm64/include/asm/thread_info.h               |    2 +-
 arch/arm64/include/asm/tlbflush.h                  |   85 +-
 arch/arm64/include/asm/vdso.h                      |    4 +-
 arch/arm64/include/asm/vdso/compat_barrier.h       |    4 +-
 arch/arm64/include/asm/vdso/compat_gettimeofday.h  |    4 +-
 arch/arm64/include/asm/vdso/getrandom.h            |    4 +-
 arch/arm64/include/asm/vdso/gettimeofday.h         |    4 +-
 arch/arm64/include/asm/vdso/processor.h            |    4 +-
 arch/arm64/include/asm/vdso/vsyscall.h             |    4 +-
 arch/arm64/include/asm/virt.h                      |    4 +-
 arch/arm64/include/asm/vmap_stack.h                |    4 -
 arch/arm64/include/uapi/asm/kvm.h                  |    2 +-
 arch/arm64/include/uapi/asm/ptrace.h               |    4 +-
 arch/arm64/include/uapi/asm/sigcontext.h           |    4 +-
 arch/arm64/kernel/acpi.c                           |    4 +-
 arch/arm64/kernel/cpufeature.c                     |    6 +-
 arch/arm64/kernel/efi.c                            |   46 +-
 arch/arm64/kernel/entry-common.c                   |   28 +-
 arch/arm64/kernel/entry-ftrace.S                   |    2 +-
 arch/arm64/kernel/fpsimd.c                         |   29 +-
 arch/arm64/kernel/ftrace.c                         |    2 +-
 arch/arm64/kernel/irq.c                            |    2 +-
 arch/arm64/kernel/machine_kexec.c                  |    2 +-
 arch/arm64/kernel/pi/map_kernel.c                  |    8 +-
 arch/arm64/kernel/probes/uprobes.c                 |    2 +-
 arch/arm64/kernel/ptrace.c                         |   40 +-
 arch/arm64/kernel/sdei.c                           |    6 +-
 arch/arm64/kernel/smp.c                            |    4 +-
 arch/arm64/kernel/syscall.c                        |    2 +-
 arch/arm64/kernel/traps.c                          |    2 +-
 arch/arm64/kernel/vmcore_info.c                    |    2 +-
 arch/arm64/kvm/arch_timer.c                        |    2 +-
 arch/arm64/kvm/arm.c                               |    2 +-
 arch/arm64/kvm/hyp/nvhe/ffa.c                      |    2 +-
 arch/arm64/kvm/mmu.c                               |    2 +-
 arch/arm64/kvm/nested.c                            |    2 +-
 arch/arm64/mm/contpte.c                            |    3 +-
 arch/arm64/mm/fault.c                              |    8 +-
 arch/arm64/mm/mmu.c                                |  220 +-
 arch/arm64/mm/pageattr.c                           |   12 +-
 arch/arm64/mm/pgd.c                                |    2 +-
 arch/arm64/mm/proc.S                               |   36 +-
 arch/arm64/net/bpf_jit_comp.c                      |    2 +-
 arch/arm64/tools/gen-sysreg.awk                    |  146 +-
 arch/arm64/tools/sysreg                            |   21 +
 drivers/Kconfig                                    |    2 +
 drivers/Makefile                                   |    1 +
 drivers/acpi/arm64/Kconfig                         |    3 +
 drivers/acpi/arm64/Makefile                        |    1 +
 drivers/acpi/arm64/gtdt.c                          |   34 -
 drivers/acpi/arm64/mpam.c                          |  411 +++
 drivers/acpi/pptt.c                                |  280 +-
 drivers/acpi/tables.c                              |    2 +-
 drivers/firmware/efi/efi.c                         |    3 +
 drivers/firmware/efi/runtime-wrappers.c            |   17 +-
 drivers/perf/arm-ni.c                              |   97 +-
 drivers/perf/arm_cspmu/arm_cspmu.c                 |   52 +-
 drivers/perf/arm_cspmu/arm_cspmu.h                 |   39 +-
 drivers/perf/arm_cspmu/nvidia_cspmu.c              |  194 +-
 drivers/perf/arm_pmu.c                             |    6 +
 drivers/perf/arm_pmuv3.c                           |   24 +
 drivers/perf/arm_spe_pmu.c                         |   37 +
 drivers/perf/fsl_imx8_ddr_perf.c                   |   95 +-
 drivers/resctrl/Kconfig                            |   24 +
 drivers/resctrl/Makefile                           |    4 +
 drivers/resctrl/mpam_devices.c                     | 2723 ++++++++++++++++++++
 drivers/resctrl/mpam_internal.h                    |  658 +++++
 drivers/resctrl/test_mpam_devices.c                |  389 +++
 include/linux/acpi.h                               |   27 +-
 include/linux/arch_topology.h                      |   17 +-
 include/linux/arm_mpam.h                           |   66 +
 include/linux/efi.h                                |    2 +
 include/linux/huge_mm.h                            |    2 +-
 include/linux/perf/arm_pmu.h                       |    1 +
 include/linux/pgtable.h                            |    4 +
 include/linux/platform_device.h                    |    1 +
 include/uapi/linux/perf_event.h                    |    2 +
 mm/huge_memory.c                                   |   33 +-
 mm/internal.h                                      |    2 +-
 mm/memory.c                                        |   62 +-
 tools/arch/arm64/include/asm/cputype.h             |    4 +-
 tools/arch/arm64/include/asm/esr.h                 |    4 +-
 tools/arch/arm64/include/asm/gpr-num.h             |    6 +-
 tools/arch/arm64/include/asm/sysreg.h              |   12 +-
 tools/arch/arm64/include/uapi/asm/kvm.h            |    2 +-
 tools/testing/selftests/arm64/fp/fp-ptrace.c       |    5 +-
 tools/testing/selftests/arm64/fp/sve-ptrace.c      |   61 +
 tools/testing/selftests/arm64/fp/zt-test.S         |    2 +-
 tools/testing/selftests/kvm/arm64/set_id_regs.c    |   10 +-
 150 files changed, 5997 insertions(+), 711 deletions(-)
 create mode 100644 drivers/acpi/arm64/mpam.c
 create mode 100644 drivers/resctrl/Kconfig
 create mode 100644 drivers/resctrl/Makefile
 create mode 100644 drivers/resctrl/mpam_devices.c
 create mode 100644 drivers/resctrl/mpam_internal.h
 create mode 100644 drivers/resctrl/test_mpam_devices.c
 create mode 100644 include/linux/arm_mpam.h

------------------8<------------------------------
diff --cc arch/arm64/include/asm/el2_setup.h
index 99a7c0235e6d,cb0d72401d45..cacd20df1786
--- a/arch/arm64/include/asm/el2_setup.h
+++ b/arch/arm64/include/asm/el2_setup.h
@@@ -24,7 -24,11 +24,7 @@@
  	 * ID_AA64MMFR4_EL1.E2H0 < 0. On such CPUs HCR_EL2.E2H is RES1, but it
  	 * can reset into an UNKNOWN state and might not read as 1 until it has
  	 * been initialized explicitly.
- 	 * Initalize HCR_EL2.E2H so that later code can rely upon HCR_EL2.E2H
 -	 *
 -	 * Fruity CPUs seem to have HCR_EL2.E2H set to RAO/WI, but
 -	 * don't advertise it (they predate this relaxation).
 -	 *
+ 	 * Initialize HCR_EL2.E2H so that later code can rely upon HCR_EL2.E2H
  	 * indicating whether the CPU is running in E2H mode.
  	 */
  	mrs_s	x1, SYS_ID_AA64MMFR4_EL1
diff --cc arch/arm64/include/asm/scs.h
index c59f6324f2bb,d31b128f683f..0fbc2e7867d3
--- a/arch/arm64/include/asm/scs.h
+++ b/arch/arm64/include/asm/scs.h
@@@ -53,8 -53,8 +53,8 @@@ enum 
  	EDYNSCS_INVALID_CFA_OPCODE		= 4,
  };
  
 -int __pi_scs_patch(const u8 eh_frame[], int size);
 +int __pi_scs_patch(const u8 eh_frame[], int size, bool skip_dry_run);
  
- #endif /* __ASSEMBLY __ */
+ #endif /* __ASSEMBLER__ */
  
  #endif /* _ASM_SCS_H */
diff --cc arch/arm64/include/asm/spectre.h
index 900454aaa292,0527c53b0ec5..296ae3420bfd
--- a/arch/arm64/include/asm/spectre.h
+++ b/arch/arm64/include/asm/spectre.h
@@@ -117,7 -117,6 +117,7 @@@ void spectre_bhb_patch_wa3(struct alt_i
  			   __le32 *origptr, __le32 *updptr, int nr_inst);
  void spectre_bhb_patch_clearbhb(struct alt_instr *alt,
  				__le32 *origptr, __le32 *updptr, int nr_inst);
 +void spectre_print_disabled_mitigations(void);
  
- #endif	/* __ASSEMBLY__ */
+ #endif	/* __ASSEMBLER__ */
  #endif	/* __ASM_SPECTRE_H */

-- 
Catalin


From robh at kernel.org  Tue Dec  2 15:16:34 2025
From: robh at kernel.org (Rob Herring)
Date: Tue, 2 Dec 2025 17:16:34 -0600
Subject: Proposal: Officially allow "incomplete" trees as a base
In-Reply-To: <aS66WcLPm6e5rdyk@shell.armlinux.org.uk>
References: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
 <aS66WcLPm6e5rdyk@shell.armlinux.org.uk>
Message-ID: <CAL_JsqLxLakt94ACgv8z5A-O4WGZPfiZ-7UFaBPaOa7W8L3Cxw@mail.gmail.com>

On Tue, Dec 2, 2025 at 4:07?AM Russell King (Oracle)
<linux at armlinux.org.uk> wrote:
>
> On Tue, Nov 18, 2025 at 02:43:20PM -0800, Doug Anderson wrote:
> > This is a continuation of the discussion that started in reply to my
> > patch adding basic device trees for Pixel 10 phones [1].
> >
> >
> > Problem statement:
> > ------------------
> >
> > We would like an officially accepted scheme that lets us more
> > efficiently ship compiled device trees for a handful of related
> > products by breaking the device trees up into a common "base" device
> > tree and then applying "overlay" device trees atop the base to make a
> > full and complete device tree.
> >
> > To make it more concrete, we'd like to build a "base" device tree that
> > describes a SoC and then have the overlays be enough to make a full
> > description of a board. In theory, one could also imagine wanting to
> > expand this to 3 or more levels (perhaps SoC, baseboard, derived
> > boards), though this is not planned at this time.
> >
> > The primary reason for wanting to break device trees like this is
> > efficiency of the shipped binary device trees. A large portion of a
> > final device tree just describes the SoC. We save space in the final
> > compiled device trees if they don't need to contain as much duplicated
> > information.
>
> Having worked on the SolidRun i.MX6 platforms, I agree with this.
> Within these platforms there are:
>
> SoC     SOM             Platform
> imx6dl  pre-v1.5        cubox
> imx6q   v1.5            hummingboard
>         v1.5 + emmc     hummingboard2
>
> On top of these, I have specific "user" extensions for hardware that
> I've connected - e.g.
> - the NoIR RPi camera needs DT modification.
> - for monitoring a mechanical church clock, a "gps" variant that
>   allowed PPS to be used with a GPIO pin, and a "capture" variant
>   that configured the hardware to allow precise event stamping.
> - 1-wire, for ds18b20 temperature sensors.
>
> Without the user extensions, this adds up to 18 DTB files:
> arch/arm/boot/dts/nxp/imx/imx6dl-cubox-i-emmc-som-v15.dts
> arch/arm/boot/dts/nxp/imx/imx6dl-cubox-i-som-v15.dts
> arch/arm/boot/dts/nxp/imx/imx6dl-cubox-i.dts
> arch/arm/boot/dts/nxp/imx/imx6dl-hummingboard-emmc-som-v15.dts
> arch/arm/boot/dts/nxp/imx/imx6dl-hummingboard-som-v15.dts
> arch/arm/boot/dts/nxp/imx/imx6dl-hummingboard.dts
> arch/arm/boot/dts/nxp/imx/imx6dl-hummingboard2-emmc-som-v15.dts
> arch/arm/boot/dts/nxp/imx/imx6dl-hummingboard2-som-v15.dts
> arch/arm/boot/dts/nxp/imx/imx6dl-hummingboard2.dts
> arch/arm/boot/dts/nxp/imx/imx6q-cubox-i-emmc-som-v15.dts
> arch/arm/boot/dts/nxp/imx/imx6q-cubox-i-som-v15.dts
> arch/arm/boot/dts/nxp/imx/imx6q-cubox-i.dts
> arch/arm/boot/dts/nxp/imx/imx6q-hummingboard-emmc-som-v15.dts
> arch/arm/boot/dts/nxp/imx/imx6q-hummingboard-som-v15.dts
> arch/arm/boot/dts/nxp/imx/imx6q-hummingboard.dts
> arch/arm/boot/dts/nxp/imx/imx6q-hummingboard2-emmc-som-v15.dts
> arch/arm/boot/dts/nxp/imx/imx6q-hummingboard2-som-v15.dts
> arch/arm/boot/dts/nxp/imx/imx6q-hummingboard2.dts
>
> basically, every combination needs to be enumerated. So, having two SoC
> dt files, three for the SOM, and three for the platform that the boot
> loader combines would significantly cut this down - to 8.
>
> However, it isn't that simple. For example, when the Hummingboard2 is
> used with the iMX6Q SoC, there's a SATA device present in the SoC level
> that needs Hummingboard2 specific properties to tune the signal
> waveform. However, iMX6DL doesn't have this SATA device in silicon, so
> the node doesn't exist in the base SoC DT file. The situation is the
> same for Hummingboard, but the tuning parameters, being board specific,
> are different.

If that is a separate overlay fragment (i.e. not under another node in
the overlay), we could solve this by having some way to mark the
fragment as optional. Apply it if the base node is present, but don't
fail if not. Could be a need for this without overlays as well.
Something like this:

#include <soc.dtsi>

/optional/ &sata {
  foo = <0>;
};

Normally if 'sata' isn't found, that's an error.

To make that work for overlays, we'd have to transform /optional/ into
a property. "target-optional" alongside "target-path" perhaps.

> This means is that there are DT properties that are dependent on the
> SoC DT component and the platform DT component which do not fit with
> splitting the DT files into their individual "component" levels.
>
> The other issue would be the /model property - for example:
>
>         model = "SolidRun HummingBoard2 Solo/DualLite";
>         model = "SolidRun HummingBoard2 Solo/DualLite (1.5som+emmc)";
>         model = "SolidRun HummingBoard2 Solo/DualLite (1.5som)";
>         model = "SolidRun HummingBoard Solo/DualLite";
>         model = "SolidRun HummingBoard2 Dual/Quad";
>         model = "SolidRun Cubox-i Solo/DualLite";

I think you just give up and generalize it: "SolidRun HummingBoard/Cubox"


> as a set of examples. I don't see a clear way to generate these from
> a fragmented scheme. There's a similar problem with the board-level
> compatible:
>
>         compatible = "solidrun,cubox-i/dl", "fsl,imx6dl";
>         compatible = "solidrun,hummingboard2/dl", "fsl,imx6dl";
>         compatible = "solidrun,hummingboard/dl", "fsl,imx6dl";
>         compatible = "solidrun,hummingboard2/q", "fsl,imx6q";
>
> These don't include the SoM information.

So we're back to needing to merge compatible even though Doug was
willing to drop it. Or to put it another way, there's usecases for the
base to be different SoC revisions and variants. So I don't think we
should give up on solving that.

> Maybe what would work would be a high-level DT file that contains
> paths to the lower levels that need to be combined, along with
> properties that need to be merged. E.g.
>
> / {
>         model = "SolidRun HummingBoard2 Dual/Quad";
>         compatible = "solidrun,hummingboard2/q", "fsl,imx6q";
>
>         dts-components {
>                 compatible = "boot/dt";
>
>                 component at 1 {
>                         compatible = "dt";
>                         path = "imx6q.dtbo";
>                 };
>
>                 component at 2 {
>                         compatible = "dt";
>                         path = "imx6qdl-sr-som-v1.5.dtbo";
>                 };
>
>                 component at 3 {
>                         compatible = "dt";
>                         path = "imx6qdl-hummingboard2.dtbo";
>                 };
>
>                 component at 4 {
>                         compatible = "dt";
>                         path = "imx6ql-hummingboard2-emmc.dtbo";
>                 };
>         };
>
>         soc {
>                 sata at 2200000 {
>                         .. sata tuning properties ..
>                 };
>         };
> };
>
> Or something similar. However, this would mean we would still need the
> 18 or so top level DT files, but also each component as well, which
> will increase the number of files we're having to manage on a target
> platform - so I'm wondering whether it's worth it.

Looks like FIT...

> I don't think we'll be able to get away from this problem: it's likely
> that there will continue to be properties that are specific across
> several "levels" of a split DT setup, and apart from something like the
> above, I don't really see a way to handle them.

I tend to agree your cases might be the tip of the iceberg. I think
someone has to take some existing platforms and see what happens
splitting them.

> I also don't see a sensible way without something like the above for a
> boot loader to know the filenames of each of the components for a
> platform - and it would need to be told the order to glue those
> components together.

We've generally resisted making filenames significant/ABI.

Rob


From pr-tracker-bot at kernel.org  Tue Dec  2 17:19:23 2025
From: pr-tracker-bot at kernel.org (pr-tracker-bot at kernel.org)
Date: Wed, 03 Dec 2025 01:19:23 +0000
Subject: [GIT PULL] arm64 updates for 6.19
In-Reply-To: <aS9w1LWtsZFLX9I9@arm.com>
References: <aS9w1LWtsZFLX9I9@arm.com>
Message-ID: <176472476309.3463594.8331348325756271025.pr-tracker-bot@kernel.org>

The pull request you sent on Tue, 2 Dec 2025 23:05:56 +0000:

> git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux tags/arm64-upstream

has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/44fc84337b6eae580a51cf6f7ca6a22ef1349556

Thank you!

-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html


From 2694439648 at qq.com  Tue Dec  2 17:31:52 2025
From: 2694439648 at qq.com (2694439648 at qq.com)
Date: Wed,  3 Dec 2025 09:31:52 +0800
Subject: [PATCH v3] net: stmmac: Modify the judgment condition of "tx_avail" from 1 to 2
Message-ID: <tencent_639FC431D959DA3E8FC007985FC88EA5A90A@qq.com>

From: "hailong.fan" <hailong.fan at siengine.com>

Under certain conditions, a WARN_ON will be triggered
if avail equals 1.

For example, when a VLAN packet is to send,
stmmac_vlan_insert consumes one unit of space,
and the data itself consumes another.
actually requiring 2 units of space in total.

Changes from v3:
        - format commit message
Changes from v2:
        - add fixes tag
        - Add stmmac_extra_space to count the additional required space
Changes from v1:
        - Stop their queues earlier

Fixes: 30d932279dc2 ("net: stmmac: Add support for VLAN Insertion Offload")
Signed-off-by: hailong.fan <hailong.fan at siengine.com>
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 7b90ecd3a..9a665a3b2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -4476,6 +4476,15 @@ static bool stmmac_has_ip_ethertype(struct sk_buff *skb)
 		(proto == htons(ETH_P_IP) || proto == htons(ETH_P_IPV6));
 }
 
+static inline int stmmac_extra_space(struct stmmac_priv *priv,
+				     struct sk_buff *skb)
+{
+	if (!priv->dma_cap.vlins || !skb_vlan_tag_present(skb))
+		return 0;
+
+	return 1;
+}
+
 /**
  *  stmmac_xmit - Tx entry point of the driver
  *  @skb : the socket buffer
@@ -4529,7 +4538,8 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 		}
 	}
 
-	if (unlikely(stmmac_tx_avail(priv, queue) < nfrags + 1)) {
+	if (unlikely(stmmac_tx_avail(priv, queue) <
+		nfrags + 1 + stmmac_extra_space(priv, skb))) {
 		if (!netif_tx_queue_stopped(netdev_get_tx_queue(dev, queue))) {
 			netif_tx_stop_queue(netdev_get_tx_queue(priv->dev,
 								queue));
@@ -4675,7 +4685,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 		print_pkt(skb->data, skb->len);
 	}
 
-	if (unlikely(stmmac_tx_avail(priv, queue) <= (MAX_SKB_FRAGS + 1))) {
+	if (unlikely(stmmac_tx_avail(priv, queue) <= (MAX_SKB_FRAGS + 2))) {
 		netif_dbg(priv, hw, priv->dev, "%s: stop transmitted packets\n",
 			  __func__);
 		netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, queue));
-- 
2.34.1



From mingjin.ge at mediatek.com  Tue Dec  2 17:34:49 2025
From: mingjin.ge at mediatek.com (Mingjin Ge)
Date: Wed, 3 Dec 2025 09:34:49 +0800
Subject: [PATCH 0/1] add support remote wakeup of mt8189
Message-ID: <20251203013521.2038888-1-mingjin.ge@mediatek.com>

> This series is based on linux-next, tag: next-20251201.
> 
> Changes in v1:
> There are five USB controllers on mt8189,
> each controller's wakeup control is the same.
> Add a new specific version for them.

Mingjin Ge (1):
  usb: mtk-xhci: add support remote wakeup of mt8189

 drivers/usb/host/xhci-mtk.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

-- 
2.45.2



From mingjin.ge at mediatek.com  Tue Dec  2 17:34:50 2025
From: mingjin.ge at mediatek.com (Mingjin Ge)
Date: Wed, 3 Dec 2025 09:34:50 +0800
Subject: [PATCH 1/1] usb: mtk-xhci: add support remote wakeup of mt8189
In-Reply-To: <20251203013521.2038888-1-mingjin.ge@mediatek.com>
References: <20251203013521.2038888-1-mingjin.ge@mediatek.com>
Message-ID: <20251203013521.2038888-2-mingjin.ge@mediatek.com>

Add remote wakeup configuration for the mt8189 in xhci-mtk driver.

Signed-off-by: Chunfeng Yun <chunfeng.yun at mediatek.com>
Signed-off-by: Mingjin Ge <mingjin.ge at mediatek.com>
---
 drivers/usb/host/xhci-mtk.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
index 8da05e9dfa28..134a46907db5 100644
--- a/drivers/usb/host/xhci-mtk.c
+++ b/drivers/usb/host/xhci-mtk.c
@@ -96,6 +96,10 @@
 #define WC0_IS_P	BIT(12)	/* polarity */
 #define WC0_IS_EN	BIT(6)
 
+/* mt8189*/
+#define PERI_WK_CTRL0_8189	0x0
+#define WC0_IS_EN_P_89		BIT(18)
+
 /* mt8192 */
 #define WC0_SSUSB0_CDEN		BIT(6)
 #define WC0_IS_SPM_EN		BIT(1)
@@ -140,6 +144,7 @@ enum ssusb_uwk_vers {
 	SSUSB_UWK_V1_7,		/* mt8196 IP0 */
 	SSUSB_UWK_V1_8,		/* mt8196 IP1 */
 	SSUSB_UWK_V1_9,		/* mt8196 IP2 */
+	SSUSB_UWK_V1_10,	/* mt8189 IP all */
 };
 
 /*
@@ -407,6 +412,11 @@ static void usb_wakeup_ip_sleep_set(struct xhci_hcd_mtk *mtk, bool enable)
 		msk = WC1_IS_EN_P2_96;
 		val = enable ? msk : 0;
 		break;
+	case SSUSB_UWK_V1_10:
+		reg = mtk->uwk_reg_base + PERI_WK_CTRL0_8189;
+		msk = WC0_IS_EN_P_89;
+		val = enable ? msk : 0;
+		break;
 	case SSUSB_UWK_V2:
 		reg = mtk->uwk_reg_base + PERI_SSUSB_SPM_CTRL;
 		msk = SSC_IP_SLEEP_EN | SSC_SPM_INT_EN;
-- 
2.45.2



From sherry.sun at nxp.com  Tue Dec  2 17:48:06 2025
From: sherry.sun at nxp.com (Sherry Sun)
Date: Wed, 3 Dec 2025 01:48:06 +0000
Subject: [PATCH] arm64: dts: imx8qm-ss-dma: correct the dma channels of
 lpuart
In-Reply-To: <aS78RJQAJDf6iU6X@lizhi-Precision-Tower-5810>
References: <20251202111638.3553-1-sherry.sun@nxp.com>
 <2395053.ElGaqSPkdT@steina-w> <aS78RJQAJDf6iU6X@lizhi-Precision-Tower-5810>
Message-ID: <VI0PR04MB12114DF96354253F961BAD66D92D9A@VI0PR04MB12114.eurprd04.prod.outlook.com>



> -----Original Message-----
> From: Frank Li <frank.li at nxp.com>
> Sent: Tuesday, December 2, 2025 10:49 PM
> To: Alexander Stein <alexander.stein at ew.tq-group.com>
> Cc: robh at kernel.org; krzk+dt at kernel.org; conor+dt at kernel.org;
> shawnguo at kernel.org; s.hauer at pengutronix.de; festevam at gmail.com;
> Sherry Sun <sherry.sun at nxp.com>; devicetree at vger.kernel.org;
> kernel at pengutronix.de; linux-kernel at vger.kernel.org; imx at lists.linux.dev;
> linux-arm-kernel at lists.infradead.org
> Subject: Re: [PATCH] arm64: dts: imx8qm-ss-dma: correct the dma channels
> of lpuart
> 
> On Tue, Dec 02, 2025 at 12:48:15PM +0100, Alexander Stein wrote:
> > Hi,
> >
> > Am Dienstag, 2. Dezember 2025, 12:16:38 CET schrieb Sherry Sun:
> > > The commit 616effc0272b5 ("arm64: dts: imx8: Fix lpuart DMA channel
> > > order") swap uart rx and tx channel at common imx8-ss-dma.dtsi. But
> > > miss update imx8qm-ss-dma.dtsi.
> > >
> > > The commit 5a8e9b022e569 ("arm64: dts: imx8qm-ss-dma: Pass lpuart
> > > dma-names") just simple add dma-names as binding doc requirement.
> > >
> > > Correct lpuart0 - lpuart3 dma rx and tx channels, and use defines
> > > for the FSL_EDMA_RX flag.
> > >
> > > Fixes: 616effc0272b5 ("arm64: dts: imx8: Fix lpuart DMA channel
> > > order")
> >
> > I'm wondering if this is actually a fix for 5a8e9b022e569 ("arm64: dts:
> > imx8qm-ss-dma: Pass lpuart dma-names") instead. 616effc0272b5 just
> > focuses on the common parts. But I don't have a strong opinion here.
> 
> Yes, it should be 5a8e9b022e569.

Sure, will update this in V2.

Best Regards
Sherry
> 
> Frank
> >
> > Thanks and best regards,
> > Alexander
> >
> > > Signed-off-by: Sherry Sun <sherry.sun at nxp.com>
> > > ---
> > >  arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi | 8 ++++----
> > >  1 file changed, 4 insertions(+), 4 deletions(-)
> > >
> > > diff --git a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi
> > > b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi
> > > index 5f24850bf322..974e193f8dcb 100644
> > > --- a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi
> > > +++ b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi
> > > @@ -172,25 +172,25 @@ &flexcan3 {
> > >
> > >  &lpuart0 {
> > >  	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
> > > -	dmas = <&edma2 13 0 0>, <&edma2 12 0 1>;
> > > +	dmas = <&edma2 12 0 FSL_EDMA_RX>, <&edma2 13 0 0>;
> > >  	dma-names = "rx","tx";
> > >  };
> > >
> > >  &lpuart1 {
> > >  	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
> > > -	dmas = <&edma2 15 0 0>, <&edma2 14 0 1>;
> > > +	dmas = <&edma2 14 0 FSL_EDMA_RX>, <&edma2 15 0 0>;
> > >  	dma-names = "rx","tx";
> > >  };
> > >
> > >  &lpuart2 {
> > >  	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
> > > -	dmas = <&edma2 17 0 0>, <&edma2 16 0 1>;
> > > +	dmas = <&edma2 16 0 FSL_EDMA_RX>, <&edma2 17 0 0>;
> > >  	dma-names = "rx","tx";
> > >  };
> > >
> > >  &lpuart3 {
> > >  	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
> > > -	dmas = <&edma2 19 0 0>, <&edma2 18 0 1>;
> > > +	dmas = <&edma2 18 0 FSL_EDMA_RX>, <&edma2 19 0 0>;
> > >  	dma-names = "rx","tx";
> > >  };
> > >
> > >
> >
> >
> > --
> > TQ-Systems GmbH | M?hlstra?e 2, Gut Delling | 82229 Seefeld, Germany
> > Amtsgericht M?nchen, HRB 105018
> > Gesch?ftsf?hrer: Detlef Schneider, R?diger Stahl, Stefan Schneider
> > http://www.tq-group.com/
> >
> >


From xieyuanbin1 at huawei.com  Tue Dec  2 17:48:00 2025
From: xieyuanbin1 at huawei.com (Xie Yuanbin)
Date: Wed, 3 Dec 2025 09:48:00 +0800
Subject: [Bug report] hash_name() may cross page boundary and trigger sleep in RCU context
In-Reply-To: <CAHk-=wg4ZnsfpgXYL5qhjYDYo1Gnssz+VxnKZzHXMEmE7qrnQQ@mail.gmail.com>
References: <CAHk-=wg4ZnsfpgXYL5qhjYDYo1Gnssz+VxnKZzHXMEmE7qrnQQ@mail.gmail.com>
Message-ID: <20251203014800.4988-1-xieyuanbin1@huawei.com>

On Tue, 2 Dec 2025 14:07:25 -0800, Linus Torvalds wrote:
> On Tue, 2 Dec 2025 at 04:43, Russell King (Oracle)
> <linux at armlinux.org.uk> wrote:
>>
>> What I'm thinking is to address both of these by handling kernel space
>> page faults (which will be permission or PTE-not-present) separately
>> (not even build tested):
>
> That patch looks sane to me.
>
> But I also didn't build test it, just scanned it visually ;)

That patch removes harden_branch_predictor() from __do_user_fault(), and
moves it to do_page_fault()->do_kernel_address_page_fault(). 
This resolves previously mentioned kernel warning issue. However,
__do_user_fault() is not only called by do_page_fault(), it is
alse called by do_bad_area(), do_sect_fault() and do_translation_fault().

So I think that some harden_branch_predictor() is missing on other paths.
According to my tests, when CONFIG_ARM_LPAE=n, harden_branch_predictor()
will never be called anymore, even if a user program trys to access the
kernel address.

Or perhaps I've misunderstood something, could you please point it out?
Thank you very much.

What about something like this (The patch has been tested):
```patch
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 2bc828a1940c..af86198631c5 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -183,9 +183,11 @@ __do_user_fault(unsigned long addr, unsigned int fsr, unsigned int sig,
 {
 	struct task_struct *tsk = current;

-	if (addr > TASK_SIZE)
+	if (addr >= TASK_SIZE)
 		harden_branch_predictor();

+	local_irq_enable();
+
 #ifdef CONFIG_DEBUG_USER
 	if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) ||
 	    ((user_debug & UDBG_BUS)  && (sig == SIGBUS))) {
@@ -272,6 +274,24 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 	if (kprobe_page_fault(regs, fsr))
 		return 0;

+	if (unlikely(addr >= TASK_SIZE)) {
+		/*
+		 * Fault from user mode for a kernel space address. User mode
+		 * should not be faulting in kernel space, which includes the
+		 * vector/khelper page. Handle the Spectre issues while
+		 * interrupts are still disabled, then send a SIGSEGV. Note
+		 * that __do_user_fault() will enable interrupts.
+		 *
+		 * Fault from kernel mode. Jump to __do_kernel_fault()->
+		 * fixup_exception() directly, without getting mm lock and
+		 * finding vma. The interrupts are not enabled but it will be
+		 * good, just like what do_translation_fault() and
+		 * do_bad_area() does.
+		 */
+		fault = 0;
+		code = SEGV_MAPERR;
+		goto bad_area;
+	}

 	/* Enable interrupts if they were enabled in the parent context. */
 	if (interrupts_enabled(regs))

```

Thanks very much!


From sherry.sun at nxp.com  Tue Dec  2 17:59:56 2025
From: sherry.sun at nxp.com (Sherry Sun)
Date: Wed,  3 Dec 2025 09:59:56 +0800
Subject: [PATCH V2] arm64: dts: imx8qm-ss-dma: correct the dma channels of lpuart
Message-ID: <20251203015956.116364-1-sherry.sun@nxp.com>

The commit 616effc0272b5 ("arm64: dts: imx8: Fix lpuart DMA channel
order") swap uart rx and tx channel at common imx8-ss-dma.dtsi. But miss
update imx8qm-ss-dma.dtsi.

The commit 5a8e9b022e569 ("arm64: dts: imx8qm-ss-dma: Pass lpuart
dma-names") just simple add dma-names as binding doc requirement.

Correct lpuart0 - lpuart3 dma rx and tx channels, and use defines for
the FSL_EDMA_RX flag.

Fixes: 5a8e9b022e56 ("arm64: dts: imx8qm-ss-dma: Pass lpuart dma-names")
Signed-off-by: Sherry Sun <sherry.sun at nxp.com>
---
Changes in V2:
1. Correct the fixes commit as Frank and Alexander suggested.
---
 arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi
index 5f24850bf322..974e193f8dcb 100644
--- a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi
@@ -172,25 +172,25 @@ &flexcan3 {
 
 &lpuart0 {
 	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
-	dmas = <&edma2 13 0 0>, <&edma2 12 0 1>;
+	dmas = <&edma2 12 0 FSL_EDMA_RX>, <&edma2 13 0 0>;
 	dma-names = "rx","tx";
 };
 
 &lpuart1 {
 	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
-	dmas = <&edma2 15 0 0>, <&edma2 14 0 1>;
+	dmas = <&edma2 14 0 FSL_EDMA_RX>, <&edma2 15 0 0>;
 	dma-names = "rx","tx";
 };
 
 &lpuart2 {
 	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
-	dmas = <&edma2 17 0 0>, <&edma2 16 0 1>;
+	dmas = <&edma2 16 0 FSL_EDMA_RX>, <&edma2 17 0 0>;
 	dma-names = "rx","tx";
 };
 
 &lpuart3 {
 	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
-	dmas = <&edma2 19 0 0>, <&edma2 18 0 1>;
+	dmas = <&edma2 18 0 FSL_EDMA_RX>, <&edma2 19 0 0>;
 	dma-names = "rx","tx";
 };
 
-- 
2.34.1



From jiyu.yang at oss.nxp.com  Tue Dec  2 18:48:50 2025
From: jiyu.yang at oss.nxp.com (Rain Yang)
Date: Wed, 3 Dec 2025 10:48:50 +0800
Subject: [PATCH] arm64: dts: imx95: Use GPU_CGC as core clock for GPU
In-Reply-To: <20251129143220.14834-1-marek.vasut@mailbox.org>
References: <20251129143220.14834-1-marek.vasut@mailbox.org>
Message-ID: <aS-lEibp3zTsaR6T@oss.nxp.com>

On Sat, Nov 29, 2025 at 03:31:30PM +0100, Marek Vasut wrote:
>The i.MX95 imx-sm introduced new GPU_CGC clock since imx-sm commit
>ca5e078833fa ("SM-128: Add clock management via CCM LPCG direct control")
>which are downstream clock of GPU clock. These new GPU_CGC clock
>gate the existing GPU clock. Currently, without clk_ignore_unused
>on kernel command line, those new GPU_CGC clock are unused and the
>kernel will disable them. This has no impact on i.MX95 A0/A1, but
>does prevent GPU register access from working at all on i.MX95 B0.
>The GPU_CGC clock are present on both i.MX95 A0/A1/B0, therefore
>update the DT such, that the GPU core clock are the GPU_CGC clock.
>When the panthor driver enables the GPU core clock, it enables both
>the GPU_CGC as well as its parent GPU clock.
>
>Fixes: 67934f248e64 ("arm64: dts: imx95: Describe Mali G310 GPU")
>Signed-off-by: Marek Vasut <marek.vasut at mailbox.org>
>---
>Cc: Conor Dooley <conor+dt at kernel.org>
>Cc: Fabio Estevam <festevam at gmail.com>
>Cc: Frank Li <Frank.li at nxp.com>
>Cc: Krzysztof Kozlowski <krzk+dt at kernel.org>
>Cc: Peng Fan <peng.fan at nxp.com>
>Cc: Pengutronix Kernel Team <kernel at pengutronix.de>
>Cc: Rain Yang <jiyu.yang at oss.nxp.com>
>Cc: Rob Herring <robh at kernel.org>
>Cc: Sascha Hauer <s.hauer at pengutronix.de>
>Cc: Shawn Guo <shawnguo at kernel.org>
>Cc: devicetree at vger.kernel.org
>Cc: imx at lists.linux.dev
>Cc: linux-arm-kernel at lists.infradead.org
>---
> arch/arm64/boot/dts/freescale/imx95-clock.h | 1 +
> arch/arm64/boot/dts/freescale/imx95.dtsi    | 2 +-
> 2 files changed, 2 insertions(+), 1 deletion(-)
>
>diff --git a/arch/arm64/boot/dts/freescale/imx95-clock.h b/arch/arm64/boot/dts/freescale/imx95-clock.h
>index e1f91203e7947..22311612e4403 100644
>--- a/arch/arm64/boot/dts/freescale/imx95-clock.h
>+++ b/arch/arm64/boot/dts/freescale/imx95-clock.h
>@@ -183,5 +183,6 @@
> #define IMX95_CLK_SEL_A55P                 (IMX95_CCM_NUM_CLK_SRC + 123 + 7)
> #define IMX95_CLK_SEL_DRAM                 (IMX95_CCM_NUM_CLK_SRC + 123 + 8)
> #define IMX95_CLK_SEL_TEMPSENSE            (IMX95_CCM_NUM_CLK_SRC + 123 + 9)
>+#define IMX95_CLK_GPU_CGC                  (IMX95_CCM_NUM_CLK_SRC + 123 + 10)
> 
> #endif	/* __CLOCK_IMX95_H */
>diff --git a/arch/arm64/boot/dts/freescale/imx95.dtsi b/arch/arm64/boot/dts/freescale/imx95.dtsi
>index 6091c2713fa48..47f20e501315f 100644
>--- a/arch/arm64/boot/dts/freescale/imx95.dtsi
>+++ b/arch/arm64/boot/dts/freescale/imx95.dtsi
>@@ -2874,7 +2874,7 @@ netc_emdio: mdio at 0,0 {
> 		gpu: gpu at 4d900000 {
> 			compatible = "nxp,imx95-mali", "arm,mali-valhall-csf";
> 			reg = <0 0x4d900000 0 0x480000>;
>-			clocks = <&scmi_clk IMX95_CLK_GPU>, <&scmi_clk IMX95_CLK_GPUAPB>;
>+			clocks = <&scmi_clk IMX95_CLK_GPU_CGC>, <&scmi_clk IMX95_CLK_GPUAPB>;
> 			clock-names = "core", "coregroup";
> 			interrupts = <GIC_SPI 289 IRQ_TYPE_LEVEL_HIGH>,
> 				     <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>,
>-- 
>2.51.0
>
Hi Marek,

Thanks for integrating this downstream patch. Please note that CLK_GPUAPB and CLK_GPU are
always-on, so the commit message should be amended accordingly.
Additionally, the IMX95_CLK_GPUAPB handle shall be removed, as there is no valid OPP entry
in the frequency table, this also helps minimize differences between downstream and upstream,
reducing maintenance effort.


From royluo at google.com  Tue Dec  2 19:04:56 2025
From: royluo at google.com (Roy Luo)
Date: Wed, 3 Dec 2025 11:04:56 +0800
Subject: [PATCH v8 2/2] usb: dwc3: Add Google Tensor SoC DWC3 glue driver
In-Reply-To: <CAD=FV=VLOLiGDfQOWXOL0H+M4EnSj1kouYK37WHV=8OVEwt+qg@mail.gmail.com>
References: <20251122-controller-v8-0-e7562e0df658@google.com>
 <20251122-controller-v8-2-e7562e0df658@google.com> <2025112226-heave-refrain-53e6@gregkh>
 <CA+zupgwzQ5r=-_L79D74=9VRqRO94N0yTApHChM+Nu0cn1ss3w@mail.gmail.com>
 <2025120209-unstylish-john-2a6c@gregkh> <00d75fd3-a796-402a-a1a3-2172862fcf91@kernel.org>
 <CAD=FV=VLOLiGDfQOWXOL0H+M4EnSj1kouYK37WHV=8OVEwt+qg@mail.gmail.com>
Message-ID: <CA+zupgwiJmS9+MFt8F02HrPkRYPDidjg9dxNUJxd8d_0RM6cww@mail.gmail.com>

On Wed, Dec 3, 2025 at 12:25?AM Doug Anderson <dianders at google.com> wrote:
>
> Hi,
>
> On Tue, Dec 2, 2025 at 1:42?AM Krzysztof Kozlowski <krzk at kernel.org> wrote:
> >
> > >> I plan to add ARCH_GOOGLE as a dependency in the next
> > >> version per [1], so the "depends on" would probably look like
> > >> the following per your suggestion:
> > >
> > > But "Google" is not an arch :(
> > >
> > > And really, the whole "only have a sub-arch symbol" is something that
> > > personally, I think is totally wrong and prevents kernel images from
> > > being built for more than one "arch".  As an example, the Android GKI
> >
> > Probably you think ARCH_FOO as arch/FOO/ directory, but this is not the
> > case. ARCH_FOO in this context is SoC platform, so e.g.
> > arch/arm64/boot/dts/FOO/.
> >
> > All of ARCH_FOO build into one image and that's recommended way to limit
> > unnecessary drivers.
> >
> > It's just confusing naming for whatever reason.
> >
> > > kernel has to support more than one of these, so what does putting this
> > > behind a symbol that no one will actually use mean anything?  Android
> > > will never be only building a ARCH_GOOGLE kernel.
> >
> > But distros will be, people will be. OK, maybe not for ARCH_GOOGLE, but
> > ARCH_QCOM we do for Qualcomm-based laptops and embedded folks even more.
> >
> > We had this talk in the past. The point is that these drivers here are
> > unusable outside of that hardware platform, so only when you choose
> > hardware platform (ARCH_EXYNOS, ARCH_GOOGLE, ARCH_QCOM) you will be able
> > to choose these drivers.
> >
> > You can also look at ARCH_FOO a bit orthogonal to actual kernel
> > architecture, because ARCH_EXYNOS is for both arm (arm32) and arm64. The
> > drivers should be available for all Exynos-platforms, regardless whether
> > this is arm32 or arm64.
>
> FWIW I don't feel strongly about the ARCH_XYZ Kconfig settings, but
> I'd tend to agree with Krzysztof that I personally find them useful.
> Sure, it's fine to just turn all of the ARCH_XYZ values on and they
> shouldn't conflict with each other, but it provides an easy way for
> someone to know that certain drivers are only useful if the kernel
> you're building supports a given arch. If I'm building a kernel that
> doesn't need to support any Qualcomm boards, for instance, I can just
> turn that arch off and I don't even need to think about all of the
> Qualcomm-related config options.
>
> FWIW, if you do add a "depend" on ARCH_GOOGLE you should mention
> somewhere (maybe "after the cut" in your patch) that ARCH_GOOGLE
> doesn't exist yet. It should eventually exist when some version of
> this patch lands:
>
> https://lore.kernel.org/r/20251111112158.3.I35b9e835ac49ab408e5ca3e0983930a1f1395814 at changeid/
>
> ...but it's not there yet. ;-)
>
> -Doug

Hi all,

I appreciate the detailed discussion regarding Kconfig dependencies.
Based on all the feedback, I'll make the following adjustments:
- I will update the Kconfig dependency to depends on
  ARCH_GOOGLE || COMPILE_TEST and drop the other
  dependencies on OF && COMMON_CLK && RESET_CONTROLLER
  as suggested by Krzysztof. This should also address the build
  coverage concern from Greg.
- As Doug pointed out, the ARCH_GOOGLE Kconfig option does
  not exist... yet. I will add a note about this in the next version.

Thank you all again for helping me improve this patch.
I will send out a new version with these changes soon.

Regards,
Roy Luo


From pr-tracker-bot at kernel.org  Tue Dec  2 19:11:50 2025
From: pr-tracker-bot at kernel.org (pr-tracker-bot at kernel.org)
Date: Wed, 03 Dec 2025 03:11:50 +0000
Subject: [GIT PULL] arm64 FPSIMD buffer on-stack for 6.19
In-Reply-To: <20251130030105.GF12664@sol>
References: <20251130030105.GF12664@sol>
Message-ID: <176473151071.3498170.16297964704270989529.pr-tracker-bot@kernel.org>

The pull request you sent on Sat, 29 Nov 2025 19:01:05 -0800:

> https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git tags/fpsimd-on-stack-for-linus

has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/f617d24606553159a271f43e36d1c71a4c317e48

Thank you!

-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html


From zhanjie9 at hisilicon.com  Tue Dec  2 19:24:22 2025
From: zhanjie9 at hisilicon.com (Jie Zhan)
Date: Wed, 3 Dec 2025 11:24:22 +0800
Subject: [PATCH v4 3/3] cpufreq: CPPC: Update FIE arch_freq_scale in ticks for non-PCC regs
In-Reply-To: <20251203032422.3232957-1-zhanjie9@hisilicon.com>
References: <20251203032422.3232957-1-zhanjie9@hisilicon.com>
Message-ID: <20251203032422.3232957-4-zhanjie9@hisilicon.com>

Currently, the CPPC Frequency Invariance Engine (FIE) is invoked from the
scheduler tick but defers the update of arch_freq_scale to a separate
thread because cppc_get_perf_ctrs() would sleep if the CPC regs are in PCC.

However, this deferred update mechanism is unnecessary and introduces extra
overhead for non-PCC register spaces (e.g. System Memory or FFH), where
accessing the regs won't sleep and can be safely performed from the tick
context.

Furthermore, with the CPPC FIE registered, it throws repeated warnings of
"cppc_scale_freq_workfn: failed to read perf counters" on our platform with
the CPC regs in System Memory and a power-down idle state enabled.  That's
because the remote CPU can be in a power-down idle state, and reading its
perf counters returns 0.  Moving the FIE handling back to the scheduler
tick process makes the CPU handle its own perf counters, so it won't be
idle and the issue would be inherently solved.

To address the above issues, update arch_freq_scale directly in ticks for
non-PCC regs and keep the deferred update mechanism for PCC regs.

Signed-off-by: Jie Zhan <zhanjie9 at hisilicon.com>
---
 drivers/cpufreq/cppc_cpufreq.c | 77 +++++++++++++++++++++++-----------
 1 file changed, 52 insertions(+), 25 deletions(-)

diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index 947b4e2e1d4e..36e8a75a37f1 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -54,31 +54,24 @@ static int cppc_perf_from_fbctrs(struct cppc_perf_fb_ctrs *fb_ctrs_t0,
 				 struct cppc_perf_fb_ctrs *fb_ctrs_t1);
 
 /**
- * cppc_scale_freq_workfn - CPPC arch_freq_scale updater for frequency invariance
- * @work: The work item.
+ * __cppc_scale_freq_tick - CPPC arch_freq_scale updater for frequency invariance
+ * @cppc_fi: per-cpu CPPC FIE data.
  *
- * The CPPC driver register itself with the topology core to provide its own
+ * The CPPC driver registers itself with the topology core to provide its own
  * implementation (cppc_scale_freq_tick()) of topology_scale_freq_tick() which
  * gets called by the scheduler on every tick.
  *
  * Note that the arch specific counters have higher priority than CPPC counters,
  * if available, though the CPPC driver doesn't need to have any special
  * handling for that.
- *
- * On an invocation of cppc_scale_freq_tick(), we schedule an irq work (since we
- * reach here from hard-irq context), which then schedules a normal work item
- * and cppc_scale_freq_workfn() updates the per_cpu arch_freq_scale variable
- * based on the counter updates since the last tick.
  */
-static void cppc_scale_freq_workfn(struct kthread_work *work)
+static void __cppc_scale_freq_tick(struct cppc_freq_invariance *cppc_fi)
 {
-	struct cppc_freq_invariance *cppc_fi;
 	struct cppc_perf_fb_ctrs fb_ctrs = {0};
 	struct cppc_cpudata *cpu_data;
 	unsigned long local_freq_scale;
 	u64 perf;
 
-	cppc_fi = container_of(work, struct cppc_freq_invariance, work);
 	cpu_data = cppc_fi->cpu_data;
 
 	if (cppc_get_perf_ctrs(cppc_fi->cpu, &fb_ctrs)) {
@@ -102,6 +95,24 @@ static void cppc_scale_freq_workfn(struct kthread_work *work)
 	per_cpu(arch_freq_scale, cppc_fi->cpu) = local_freq_scale;
 }
 
+static void cppc_scale_freq_tick(void)
+{
+	__cppc_scale_freq_tick(&per_cpu(cppc_freq_inv, smp_processor_id()));
+}
+
+static struct scale_freq_data cppc_sftd = {
+	.source = SCALE_FREQ_SOURCE_CPPC,
+	.set_freq_scale = cppc_scale_freq_tick,
+};
+
+static void cppc_scale_freq_workfn(struct kthread_work *work)
+{
+	struct cppc_freq_invariance *cppc_fi;
+
+	cppc_fi = container_of(work, struct cppc_freq_invariance, work);
+	__cppc_scale_freq_tick(cppc_fi);
+}
+
 static void cppc_irq_work(struct irq_work *irq_work)
 {
 	struct cppc_freq_invariance *cppc_fi;
@@ -110,7 +121,14 @@ static void cppc_irq_work(struct irq_work *irq_work)
 	kthread_queue_work(kworker_fie, &cppc_fi->work);
 }
 
-static void cppc_scale_freq_tick(void)
+/*
+ * Reading perf counters may sleep if the CPC regs are in PCC.  Thus, we
+ * schedule an irq work in scale_freq_tick (since we reach here from hard-irq
+ * context), which then schedules a normal work item cppc_scale_freq_workfn()
+ * that updates the per_cpu arch_freq_scale variable based on the counter
+ * updates since the last tick.
+ */
+static void cppc_scale_freq_tick_pcc(void)
 {
 	struct cppc_freq_invariance *cppc_fi = &per_cpu(cppc_freq_inv, smp_processor_id());
 
@@ -121,13 +139,14 @@ static void cppc_scale_freq_tick(void)
 	irq_work_queue(&cppc_fi->irq_work);
 }
 
-static struct scale_freq_data cppc_sftd = {
+static struct scale_freq_data cppc_sftd_pcc = {
 	.source = SCALE_FREQ_SOURCE_CPPC,
-	.set_freq_scale = cppc_scale_freq_tick,
+	.set_freq_scale = cppc_scale_freq_tick_pcc,
 };
 
 static void cppc_cpufreq_cpu_fie_init(struct cpufreq_policy *policy)
 {
+	struct scale_freq_data *sftd = &cppc_sftd;
 	struct cppc_freq_invariance *cppc_fi;
 	int cpu, ret;
 
@@ -138,8 +157,11 @@ static void cppc_cpufreq_cpu_fie_init(struct cpufreq_policy *policy)
 		cppc_fi = &per_cpu(cppc_freq_inv, cpu);
 		cppc_fi->cpu = cpu;
 		cppc_fi->cpu_data = policy->driver_data;
-		kthread_init_work(&cppc_fi->work, cppc_scale_freq_workfn);
-		init_irq_work(&cppc_fi->irq_work, cppc_irq_work);
+		if (cppc_perf_ctrs_in_pcc_cpu(cpu)) {
+			kthread_init_work(&cppc_fi->work, cppc_scale_freq_workfn);
+			init_irq_work(&cppc_fi->irq_work, cppc_irq_work);
+			sftd = &cppc_sftd_pcc;
+		}
 
 		ret = cppc_get_perf_ctrs(cpu, &cppc_fi->prev_perf_fb_ctrs);
 
@@ -155,7 +177,7 @@ static void cppc_cpufreq_cpu_fie_init(struct cpufreq_policy *policy)
 	}
 
 	/* Register for freq-invariance */
-	topology_set_scale_freq_source(&cppc_sftd, policy->cpus);
+	topology_set_scale_freq_source(sftd, policy->cpus);
 }
 
 /*
@@ -178,6 +200,8 @@ static void cppc_cpufreq_cpu_fie_exit(struct cpufreq_policy *policy)
 	topology_clear_scale_freq_source(SCALE_FREQ_SOURCE_CPPC, policy->related_cpus);
 
 	for_each_cpu(cpu, policy->related_cpus) {
+		if (!cppc_perf_ctrs_in_pcc_cpu(cpu))
+			continue;
 		cppc_fi = &per_cpu(cppc_freq_inv, cpu);
 		irq_work_sync(&cppc_fi->irq_work);
 		kthread_cancel_work_sync(&cppc_fi->work);
@@ -206,6 +230,7 @@ static void cppc_fie_kworker_init(void)
 		pr_warn("%s: failed to create kworker_fie: %ld\n", __func__,
 			PTR_ERR(kworker_fie));
 		fie_disabled = FIE_DISABLED;
+		kworker_fie = NULL;
 		return;
 	}
 
@@ -215,20 +240,24 @@ static void cppc_fie_kworker_init(void)
 			ret);
 		kthread_destroy_worker(kworker_fie);
 		fie_disabled = FIE_DISABLED;
+		kworker_fie = NULL;
 	}
 }
 
 static void __init cppc_freq_invariance_init(void)
 {
-	if (fie_disabled != FIE_ENABLED && fie_disabled != FIE_DISABLED) {
-		fie_disabled = FIE_ENABLED;
-		if (cppc_perf_ctrs_in_pcc()) {
+	bool perf_ctrs_in_pcc = cppc_perf_ctrs_in_pcc();
+
+	if (fie_disabled == FIE_UNSET) {
+		if (perf_ctrs_in_pcc) {
 			pr_info("FIE not enabled on systems with registers in PCC\n");
 			fie_disabled = FIE_DISABLED;
+		} else {
+			fie_disabled = FIE_ENABLED;
 		}
 	}
 
-	if (fie_disabled)
+	if (fie_disabled || !perf_ctrs_in_pcc)
 		return;
 
 	cppc_fie_kworker_init();
@@ -236,10 +265,8 @@ static void __init cppc_freq_invariance_init(void)
 
 static void cppc_freq_invariance_exit(void)
 {
-	if (fie_disabled)
-		return;
-
-	kthread_destroy_worker(kworker_fie);
+	if (kworker_fie)
+		kthread_destroy_worker(kworker_fie);
 }
 
 #else
-- 
2.33.0



From zhanjie9 at hisilicon.com  Tue Dec  2 19:24:20 2025
From: zhanjie9 at hisilicon.com (Jie Zhan)
Date: Wed, 3 Dec 2025 11:24:20 +0800
Subject: [PATCH v4 1/3] ACPI: CPPC: Factor out and export per-cpu cppc_perf_ctrs_in_pcc_cpu()
In-Reply-To: <20251203032422.3232957-1-zhanjie9@hisilicon.com>
References: <20251203032422.3232957-1-zhanjie9@hisilicon.com>
Message-ID: <20251203032422.3232957-2-zhanjie9@hisilicon.com>

Factor out cppc_perf_ctrs_in_pcc_cpu() for checking whether per-cpu CPC
regs are defined in PCC channels, and export it out for further use.

Signed-off-by: Jie Zhan <zhanjie9 at hisilicon.com>
---
 drivers/acpi/cppc_acpi.c | 45 +++++++++++++++++++++-------------------
 include/acpi/cppc_acpi.h |  5 +++++
 2 files changed, 29 insertions(+), 21 deletions(-)

diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 3bdeeee3414e..aa80dbcf42c0 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1422,6 +1422,29 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
 }
 EXPORT_SYMBOL_GPL(cppc_get_perf_caps);
 
+bool cppc_perf_ctrs_in_pcc_cpu(unsigned int cpu)
+{
+	struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu);
+	struct cpc_register_resource *ref_perf_reg;
+
+	/*
+	 * If reference perf register is not supported then we should use the
+	 * nominal perf value
+	 */
+	ref_perf_reg = &cpc_desc->cpc_regs[REFERENCE_PERF];
+	if (!CPC_SUPPORTED(ref_perf_reg))
+		ref_perf_reg = &cpc_desc->cpc_regs[NOMINAL_PERF];
+
+	if (CPC_IN_PCC(&cpc_desc->cpc_regs[DELIVERED_CTR]) ||
+	    CPC_IN_PCC(&cpc_desc->cpc_regs[REFERENCE_CTR]) ||
+	    CPC_IN_PCC(&cpc_desc->cpc_regs[CTR_WRAP_TIME]) ||
+	    CPC_IN_PCC(ref_perf_reg))
+		return true;
+
+	return false;
+}
+EXPORT_SYMBOL_GPL(cppc_perf_ctrs_in_pcc_cpu);
+
 /**
  * cppc_perf_ctrs_in_pcc - Check if any perf counters are in a PCC region.
  *
@@ -1436,27 +1459,7 @@ bool cppc_perf_ctrs_in_pcc(void)
 	int cpu;
 
 	for_each_online_cpu(cpu) {
-		struct cpc_register_resource *ref_perf_reg;
-		struct cpc_desc *cpc_desc;
-
-		cpc_desc = per_cpu(cpc_desc_ptr, cpu);
-
-		if (CPC_IN_PCC(&cpc_desc->cpc_regs[DELIVERED_CTR]) ||
-		    CPC_IN_PCC(&cpc_desc->cpc_regs[REFERENCE_CTR]) ||
-		    CPC_IN_PCC(&cpc_desc->cpc_regs[CTR_WRAP_TIME]))
-			return true;
-
-
-		ref_perf_reg = &cpc_desc->cpc_regs[REFERENCE_PERF];
-
-		/*
-		 * If reference perf register is not supported then we should
-		 * use the nominal perf value
-		 */
-		if (!CPC_SUPPORTED(ref_perf_reg))
-			ref_perf_reg = &cpc_desc->cpc_regs[NOMINAL_PERF];
-
-		if (CPC_IN_PCC(ref_perf_reg))
+		if (cppc_perf_ctrs_in_pcc_cpu(cpu))
 			return true;
 	}
 
diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h
index 13fa81504844..4bcdcaf8bf2c 100644
--- a/include/acpi/cppc_acpi.h
+++ b/include/acpi/cppc_acpi.h
@@ -154,6 +154,7 @@ extern int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_ctrs);
 extern int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls);
 extern int cppc_set_enable(int cpu, bool enable);
 extern int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps);
+extern bool cppc_perf_ctrs_in_pcc_cpu(unsigned int cpu);
 extern bool cppc_perf_ctrs_in_pcc(void);
 extern unsigned int cppc_perf_to_khz(struct cppc_perf_caps *caps, unsigned int perf);
 extern unsigned int cppc_khz_to_perf(struct cppc_perf_caps *caps, unsigned int freq);
@@ -204,6 +205,10 @@ static inline int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps)
 {
 	return -EOPNOTSUPP;
 }
+static inline bool cppc_perf_ctrs_in_pcc_cpu(unsigned int cpu)
+{
+	return false;
+}
 static inline bool cppc_perf_ctrs_in_pcc(void)
 {
 	return false;
-- 
2.33.0



From zhanjie9 at hisilicon.com  Tue Dec  2 19:24:19 2025
From: zhanjie9 at hisilicon.com (Jie Zhan)
Date: Wed, 3 Dec 2025 11:24:19 +0800
Subject: [PATCH v4 0/3] cpufreq: CPPC: Update FIE arch_freq_scale in ticks for non-PCC regs
Message-ID: <20251203032422.3232957-1-zhanjie9@hisilicon.com>

Currently, the CPPC Frequency Invariance Engine (FIE) is invoked from the
scheduler tick but defers the update of arch_freq_scale to a separate
thread because cppc_get_perf_ctrs() would sleep if the CPC regs are in PCC.

However, this deferred update mechanism is unnecessary and introduces extra
overhead for non-PCC register spaces (e.g. System Memory or FFH), where
accessing the regs won't sleep and can be safely performed from the tick
context.

Furthermore, with the CPPC FIE registered, it throws repeated warnings of
"cppc_scale_freq_workfn: failed to read perf counters" on our platform with
the CPC regs in System Memory and a power-down idle state enabled.  That's
because the remote CPU can be in a power-down idle state, and reading its
perf counters returns 0.  Moving the FIE handling back to the scheduler
tick process makes the CPU handle its own perf counters, so it won't be
idle and the issue would be inherently solved.

To address the above issues, update arch_freq_scale directly in ticks for
non-PCC regs and keep the deferred update mechanism for PCC regs.

We have tested this on Kunpeng SoCs with the CPC regs both in System Memory
and FFH.  More tests on other platforms are welcome (typically with the
regs in PCC).

Changelog:
v4:
- Allow either non-PCC or PCC scale_freq_tick callbacks to be registered
  for each cpufreq policy.
- Factor out cppc_perf_ctrs_in_pcc_cpu() and cppc_fie_kworker_init() for
  the above change.

v3:
https://lore.kernel.org/linux-pm/20251104065039.1675549-1-zhanjie9 at hisilicon.com/
- Stash the state of 'cppc_perf_ctrs_in_pcc' so it won't have to check the
  CPC regs of all CPUs everywhere (Thanks to the suggestion from Beata
  Michalska).
- Update the commit log, explaining more on the warning issue caused by
  accessing perf counters on remote CPUs.
- Drop Patch 1 that has been accepted, and rebase Patch 2 on that.

v2:
https://lore.kernel.org/linux-pm/20250828110212.2108653-1-zhanjie9 at hisilicon.com/
- Update the cover letter and the commit log based on v1 discussion
- Update FIE arch_freq_scale in ticks for non-PCC regs

v1:
https://lore.kernel.org/linux-pm/20250730032312.167062-1-yubowen8 at huawei.com/

Jie Zhan (3):
  ACPI: CPPC: Factor out and export per-cpu cppc_perf_ctrs_in_pcc_cpu()
  cpufreq: CPPC: Factor out cppc_fie_kworker_init()
  cpufreq: CPPC: Update FIE arch_freq_scale in ticks for non-PCC regs

 drivers/acpi/cppc_acpi.c       | 45 ++++++++--------
 drivers/cpufreq/cppc_cpufreq.c | 96 ++++++++++++++++++++++------------
 include/acpi/cppc_acpi.h       |  5 ++
 3 files changed, 93 insertions(+), 53 deletions(-)

-- 
2.33.0



From zhanjie9 at hisilicon.com  Tue Dec  2 19:24:21 2025
From: zhanjie9 at hisilicon.com (Jie Zhan)
Date: Wed, 3 Dec 2025 11:24:21 +0800
Subject: [PATCH v4 2/3] cpufreq: CPPC: Factor out cppc_fie_kworker_init()
In-Reply-To: <20251203032422.3232957-1-zhanjie9@hisilicon.com>
References: <20251203032422.3232957-1-zhanjie9@hisilicon.com>
Message-ID: <20251203032422.3232957-3-zhanjie9@hisilicon.com>

Factor out the CPPC FIE kworker init in cppc_freq_invariance_init() because
it's a standalone procedure for use when the CPC regs are in PCC channels.

Signed-off-by: Jie Zhan <zhanjie9 at hisilicon.com>
---
 drivers/cpufreq/cppc_cpufreq.c | 29 +++++++++++++++++------------
 1 file changed, 17 insertions(+), 12 deletions(-)

diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index 9eac77c4f294..947b4e2e1d4e 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -184,7 +184,7 @@ static void cppc_cpufreq_cpu_fie_exit(struct cpufreq_policy *policy)
 	}
 }
 
-static void __init cppc_freq_invariance_init(void)
+static void cppc_fie_kworker_init(void)
 {
 	struct sched_attr attr = {
 		.size		= sizeof(struct sched_attr),
@@ -201,17 +201,6 @@ static void __init cppc_freq_invariance_init(void)
 	};
 	int ret;
 
-	if (fie_disabled != FIE_ENABLED && fie_disabled != FIE_DISABLED) {
-		fie_disabled = FIE_ENABLED;
-		if (cppc_perf_ctrs_in_pcc()) {
-			pr_info("FIE not enabled on systems with registers in PCC\n");
-			fie_disabled = FIE_DISABLED;
-		}
-	}
-
-	if (fie_disabled)
-		return;
-
 	kworker_fie = kthread_run_worker(0, "cppc_fie");
 	if (IS_ERR(kworker_fie)) {
 		pr_warn("%s: failed to create kworker_fie: %ld\n", __func__,
@@ -229,6 +218,22 @@ static void __init cppc_freq_invariance_init(void)
 	}
 }
 
+static void __init cppc_freq_invariance_init(void)
+{
+	if (fie_disabled != FIE_ENABLED && fie_disabled != FIE_DISABLED) {
+		fie_disabled = FIE_ENABLED;
+		if (cppc_perf_ctrs_in_pcc()) {
+			pr_info("FIE not enabled on systems with registers in PCC\n");
+			fie_disabled = FIE_DISABLED;
+		}
+	}
+
+	if (fie_disabled)
+		return;
+
+	cppc_fie_kworker_init();
+}
+
 static void cppc_freq_invariance_exit(void)
 {
 	if (fie_disabled)
-- 
2.33.0



From marek.vasut at mailbox.org  Tue Dec  2 19:38:19 2025
From: marek.vasut at mailbox.org (Marek Vasut)
Date: Wed, 3 Dec 2025 04:38:19 +0100
Subject: [PATCH] arm64: dts: imx95: Use GPU_CGC as core clock for GPU
In-Reply-To: <aS-lEibp3zTsaR6T@oss.nxp.com>
References: <20251129143220.14834-1-marek.vasut@mailbox.org>
 <aS-lEibp3zTsaR6T@oss.nxp.com>
Message-ID: <c6e0e55a-06da-4665-972e-e9b5b8c08bf7@mailbox.org>

On 12/3/25 3:48 AM, Rain Yang wrote:

Hello Rain,

>> diff --git a/arch/arm64/boot/dts/freescale/imx95-clock.h b/arch/arm64/boot/dts/freescale/imx95-clock.h
>> index e1f91203e7947..22311612e4403 100644
>> --- a/arch/arm64/boot/dts/freescale/imx95-clock.h
>> +++ b/arch/arm64/boot/dts/freescale/imx95-clock.h
>> @@ -183,5 +183,6 @@
>> #define IMX95_CLK_SEL_A55P                 (IMX95_CCM_NUM_CLK_SRC + 123 + 7)
>> #define IMX95_CLK_SEL_DRAM                 (IMX95_CCM_NUM_CLK_SRC + 123 + 8)
>> #define IMX95_CLK_SEL_TEMPSENSE            (IMX95_CCM_NUM_CLK_SRC + 123 + 9)
>> +#define IMX95_CLK_GPU_CGC                  (IMX95_CCM_NUM_CLK_SRC + 123 + 10)
>>
>> #endif	/* __CLOCK_IMX95_H */
>> diff --git a/arch/arm64/boot/dts/freescale/imx95.dtsi b/arch/arm64/boot/dts/freescale/imx95.dtsi
>> index 6091c2713fa48..47f20e501315f 100644
>> --- a/arch/arm64/boot/dts/freescale/imx95.dtsi
>> +++ b/arch/arm64/boot/dts/freescale/imx95.dtsi
>> @@ -2874,7 +2874,7 @@ netc_emdio: mdio at 0,0 {
>> 		gpu: gpu at 4d900000 {
>> 			compatible = "nxp,imx95-mali", "arm,mali-valhall-csf";
>> 			reg = <0 0x4d900000 0 0x480000>;
>> -			clocks = <&scmi_clk IMX95_CLK_GPU>, <&scmi_clk IMX95_CLK_GPUAPB>;
>> +			clocks = <&scmi_clk IMX95_CLK_GPU_CGC>, <&scmi_clk IMX95_CLK_GPUAPB>;
>> 			clock-names = "core", "coregroup";
>> 			interrupts = <GIC_SPI 289 IRQ_TYPE_LEVEL_HIGH>,
>> 				     <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>,
>> -- 
>> 2.51.0
>>
> Hi Marek,
> 
> Thanks for integrating this downstream patch.

Which downstream patch do you refer to ?

> Please note that CLK_GPUAPB and CLK_GPU are
> always-on, so the commit message should be amended accordingly.

The GPU clock do not seem to be always-on, neither do the GPUAPB . It 
seems the SM can turn those clock off perfectly well.

> Additionally, the IMX95_CLK_GPUAPB handle shall be removed, as there is no valid OPP entry
> in the frequency table, this also helps minimize differences between downstream and upstream,
> reducing maintenance effort.

Downstream kernel forks are not relevant to this discussion, upstream 
your content and then you won't have to spend maintenance effort on 
downstream stuff.


From jacky_chou at aspeedtech.com  Tue Dec  2 21:30:01 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Wed, 3 Dec 2025 05:30:01 +0000
Subject: [PATCH net-next v4 4/4] net: ftgmac100: Add RGMII delay support for
 AST2600
In-Reply-To: <4f0e4aa0-166d-4a7f-b91e-42dbc6b832e5@lunn.ch>
References: <68f10ee1-d4c8-4498-88b0-90c26d606466@lunn.ch>
 <SEYPR06MB5134EBA2235B3D4BE39B19359DCCA@SEYPR06MB5134.apcprd06.prod.outlook.com>
 <3af52caa-88a7-4b88-bd92-fd47421cc81a@lunn.ch>
 <SEYPR06MB51342977EC2246163D14BDC19DCDA@SEYPR06MB5134.apcprd06.prod.outlook.com>
 <041e23a2-67e6-4ebb-aee5-14400491f99c@lunn.ch>
 <SEYPR06MB5134BC17E80DB66DD385024D9DD1A@SEYPR06MB5134.apcprd06.prod.outlook.com>
 <1c2ace4e-f3bb-4efa-a621-53c3711f46cb@lunn.ch> <aSbA8i5S36GeryXc@fedora>
 <SEYPR06MB513424DDB2D32ADB9C30B5119DDFA@SEYPR06MB5134.apcprd06.prod.outlook.com>
 <SEYPR06MB5134A5D1603F39E6025629A19DD8A@SEYPR06MB5134.apcprd06.prod.outlook.com>
 <4f0e4aa0-166d-4a7f-b91e-42dbc6b832e5@lunn.ch>
Message-ID: <SEYPR06MB51347C9924E32731478BBDAB9DD9A@SEYPR06MB5134.apcprd06.prod.outlook.com>

> > I miss one condition is using fixed-link property.
> > In ftgmac100, there are RGMII, NC-SI and fixed-link property.
> > On RGMII, we have solution on dedicated PHY, but there is an issue on
> > fixed-link property.
> >
> > Example on dedicated PHY.
> > The driver can pass the "rgmii-id" to tell PHY driver to enable the
> > internal delay on PHY side. Therefore, we can force to disable RGMII delay on
> MAC side.
> > But there is not any driver when using fixed-link property, which
> > means no body can tell the outside device, like switch or MAC-to-MAC,
> > to enable the internal delay on them. Also mean the phy-mode in fixed-link
> case is not used.
> >
> > Therefore, could we ignore the RGMII delay on MAC side when the
> > ftgmac100 driver gets the fixed-link property? Just keep the original delay
> value?
> 
> MAC to MAC is one of the edge cases where phy-mode is not great. What is
> generally accepted it to use rx-internal-delay-ps and tx-internal-delay-ps with
> 2ns and a comment explaining it is a MAC to MAC link, with this MAC adding
> the delays.
> 
> I suggest you see how messy it is to implement this for 2600. If the code looks
> horrible, keep the bootloader delays. For 2700 you have a clean slate, you can
> implement all this correctly from the start.
> 

Thank you for your suggestion.
We will discuss internally how to implement for these cases and prepare in next
version.

Thanks,
Jacky



From andrew at codeconstruct.com.au  Tue Dec  2 21:55:29 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Wed, 03 Dec 2025 16:25:29 +1030
Subject: [PATCH v2] dt: aspeed: clemente: move hdd_led to its own
 gpio-leds group
In-Reply-To: <20251127-leo-dts-add-shunt-resistor-v2-1-c77dfbfb826c@fii-foxconn.com>
References: <20251127-leo-dts-add-shunt-resistor-v2-1-c77dfbfb826c@fii-foxconn.com>
Message-ID: <64349026443d6178487db34233d24478821a1ca1.camel@codeconstruct.com.au>

On Thu, 2025-11-27 at 17:44 +0800, Alex Wang via B4 Relay wrote:
> From: Alex Wang <alex.ts.wang at fii-foxconn.com>
> 
> The gpio-leds driver requires all GPIOs in a group to be available;
> if any GPIO in the group is not available the whole group will not be
> created. The hdd_led GPIO is only present after standby power is
> enabled, which can prevent other LEDs in the same group from being
> created and blocks properly setting 'bmc_ready_noled'.
> 
> Move the 'hdd_led' node into a separate gpio-leds group so that other
> LEDs are not blocked and the 'bmc_ready_noled' flag can be set
> correctly.
> 
> Signed-off-by: Alex Wang <alex.ts.wang at fii-foxconn.com>

I've applied this, however, I fixed the subject so it has the usual
'ARM: dts: aspeed:' prefix, and added the following Fixes tag:

Fixes: b5dd16228216 ("ARM: dts: aspeed: clemente: Add HDD LED GPIO")

Andrew


From ao.xu at amlogic.com  Tue Dec  2 21:56:16 2025
From: ao.xu at amlogic.com (Ao Xu)
Date: Wed, 3 Dec 2025 13:56:16 +0800
Subject: [PATCH 01/11] dt-bindings: display: meson-dw-hdmi: Add compatible
 for S4 HDMI controller
In-Reply-To: <F04DC684-AD64-447F-87EC-F503D411F25D@gmail.com>
References: <20250110-drm-s4-v1-0-cbc2d5edaae8@amlogic.com>
 <20250110-drm-s4-v1-1-cbc2d5edaae8@amlogic.com>
 <3AC316FA-A633-4B6C-81BA-CCCA290E7F03@gmail.com>
 <8c3b9fa4-326e-4791-8154-07b268faa132@amlogic.com>
 <7703796D-35D4-4AD2-B7F8-B75D2BE0F7AD@gmail.com>
 <a71f24c9-1f40-45a1-8fdb-6075bbf89930@amlogic.com>
 <F04DC684-AD64-447F-87EC-F503D411F25D@gmail.com>
Message-ID: <070eb0a3-2f6e-41ef-8310-0c592a2816dc@amlogic.com>

Hi Piotr?

     I will need about two more days to look into it. I will follow up with you ASAP.


? 2025/12/2 16:29, Piotr Oniszczuk ??:
> [You don't often get email from piotr.oniszczuk at gmail.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
>
> [ EXTERNAL EMAIL ]
>
> Ao,
> Any chance for updated s4 hdmi series for 6.18?
>
>
>> Wiadomo?? napisana przez Ao Xu <ao.xu at amlogic.com> w dniu 21 lis 2025, o godz. 03:55:
>>
>> Hi Piotr?
>>
>>      I will check this issue
>>
>> ? 2025/11/19 18:27, Piotr Oniszczuk ??:
>>> [You don't often get email from piotr.oniszczuk at gmail.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
>>>
>>> [ EXTERNAL EMAIL ]
>>>
>>> Pls see inline
>>>
>>>> Wiadomo?? napisana przez Chuan Liu <chuan.liu at amlogic.com> w dniu 19 lis 2025, o godz. 03:57:
>>>>
>>>> Hi Piotr,
>>>>
>>>>
>>>> On 11/18/2025 10:50 PM, Piotr Oniszczuk wrote:
>>>>> [You don't often get email from piotr.oniszczuk at gmail.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
>>>>> [ EXTERNAL EMAIL ]
>>>>> Ao,
>>>>> Is there any chance to get this s4 drm hdmi series for current 6.18?
>>>>> (i tried backport this series to 6.18 but have some issues with reparent vpu_0_sel to sysclk_b_sel)
>>>> Why do we need to reparent vpu_0_sel to sysclk_b_sel? is there any
>>>> background here?
>>> Well - it looks it is because bug....
>>> Martin Blumenstingl had perfect eye and catch typo in patch https://lore.kernel.org/all/20250110-drm-s4-v1-11-cbc2d5edaae8 at amlogic.com/:
>>>
>>> By replacing:
>>> assigned-clock-parents = <&clkc_periphs CLKID_FCLK_DIV3>,
>>> <0>, /* Do Nothing */
>>> <&clkc_periphs CLKID_VPU_0>,
>>> <&clkc_periphs CLKID_FCLK_DIV4>,
>>> <0>, /* Do Nothing */
>>> <&clkc_periphs CLKID_VAPB_0>;
>>>
>>> with:
>>> assigned-clock-parents = <&clkc_pll CLKID_FCLK_DIV3>,
>>> <0>, /* Do Nothing */
>>> <&clkc_periphs CLKID_VPU_0>,
>>> <&clkc_pll CLKID_FCLK_DIV4>,
>>> <0>, /* Do Nothing */
>>> <&clkc_periphs CLKID_VAPB_0>;
>>>
>>> dmesg is like this https://termbin.com/6020
>>>
>>> So i'm getting hdmi working - but only when device boots _without_ connected hdmi at boot (and connected later)
>>> If hdmi is connected at boot - boot hangs at:
>>>
>>>      0.341676] meson-dw-hdmi fe300000.hdmi-tx: Detected HDMI TX controller v2.01a with HDCP (meson_dw_hdmi_phy)
>>> [    0.342750] meson-dw-hdmi fe300000.hdmi-tx: registered DesignWare HDMI I2C bus driver
>>> [    0.343660] meson-drm ff000000.vpu: bound fe300000.hdmi-tx (ops meson_dw_hdmi_ops)
>>> [    0.344832] [drm] Initialized meson 1.0.0 for ff000000.vpu on minor 0
>>>
>>> FYI: It is after applying https://patchwork.kernel.org/project/linux-amlogic/cover/20250110-drm-s4-v1-0-cbc2d5edaae8 at amlogic.com/ on mainline 6.18 (with some my adjustments on this series required by changes in 6.18).
>>> For VPU clk changes see https://github.com/warpme/minimyth2/blob/master/script/kernel/linux-6.18/files/0312-drm-meson-add-vpu-clk-setting-for-S4.patch
>>> It is 6.18 adaptation of https://patchwork.kernel.org/project/linux-amlogic/patch/20250110-drm-s4-v1-9-cbc2d5edaae8 at amlogic.com/
>>>
>>> As kernel hangs - i have limited caps to drill where root cause is.
>>>
>>> Maybe above hang is reason of my backports or missing any pre-req required to get s4 drm working?
>>> Anyway - it will be good to test with updated to 6.18 series of Add DRM support for Amlogic S4 (plus info about any pre-req required to get s4 drm working)
>>>
>>>
>>>> The vpu_clk on S4 doesn't support sysclk_b_sel as one of its
>>>> selectable clock sources, so this reparent operation will definitely
>>>> fail. This has nothing to do with the kernel version.
>>>>
>>>>>> Wiadomo?? napisana przez Ao Xu via B4 Relay <devnull+ao.xu.amlogic.com at kernel.org> w dniu 10 sty 2025, o godz. 06:39:
>>>>>>
>>>>>> From: Ao Xu <ao.xu at amlogic.com>
>>>>>>
>>>>>> Add devicetree document for S4 HDMI controller
>>>>>>
>>>>>> Signed-off-by: Ao Xu <ao.xu at amlogic.com>
>>>>>> ---
>>>>>> Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml | 1 +
>>>>>> 1 file changed, 1 insertion(+)
>>>>>>
>>>>>> diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml
>>>>>> index 84d68b8cfccc86fd87a6a0fd2b70af12e51eb8a4..6e0a8369eee915fab55af24d450a6c40e08def38 100644
>>>>>> --- a/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml
>>>>>> +++ b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml
>>>>>> @@ -55,6 +55,7 @@ properties:
>>>>>>            - const: amlogic,meson-gx-dw-hdmi
>>>>>>        - enum:
>>>>>>            - amlogic,meson-g12a-dw-hdmi # G12A (S905X2, S905Y2, S905D2)
>>>>>> +          - amlogic,meson-s4-dw-hdmi # S4 (S905Y4)
>>>>>>
>>>>>>    reg:
>>>>>>      maxItems: 1
>>>>>>
>>>>>> --
>>>>>> 2.43.0
>>>>>>
>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>>> linux-amlogic mailing list
>>>>>> linux-amlogic at lists.infradead.org
>>>>>> http://lists.infradead.org/mailman/listinfo/linux-amlogic
>>>>> _______________________________________________
>>>>> linux-amlogic mailing list
>>>>> linux-amlogic at lists.infradead.org
>>>>> http://lists.infradead.org/mailman/listinfo/linux-amlogic


From angelogioacchino.delregno at collabora.com  Tue Dec  2 21:59:26 2025
From: angelogioacchino.delregno at collabora.com (AngeloGioacchino Del Regno)
Date: Wed, 3 Dec 2025 06:59:26 +0100
Subject: [PATCH 1/1] usb: mtk-xhci: add support remote wakeup of mt8189
In-Reply-To: <20251203013521.2038888-2-mingjin.ge@mediatek.com>
References: <20251203013521.2038888-1-mingjin.ge@mediatek.com>
 <20251203013521.2038888-2-mingjin.ge@mediatek.com>
Message-ID: <a709ada6-eb68-4609-ae8c-b3bb8bcf01ae@collabora.com>

Il 03/12/25 02:34, Mingjin Ge ha scritto:
> Add remote wakeup configuration for the mt8189 in xhci-mtk driver.
> 
> Signed-off-by: Chunfeng Yun <chunfeng.yun at mediatek.com>
> Signed-off-by: Mingjin Ge <mingjin.ge at mediatek.com>

This is not the first time that I say this - and probably not the last one.

Please, stop hiding hardware - the MT8189 SoC has their XHCI controllers behind
MTU3 controllers.

Please add the wakeup configuration controls to MTU3.

I didn't check the datasheet and going by memory here, so here's what to do:
  - If there is no standalone XHCI controller (all of them have a MTU3 parent)
    *do not* add the UWK here in XHCI-MTK, but add it in MTU3 only;
  - If there is at least one standalone XHCI controller (which has no MTU3 parent)
    add UWK *both* in XHCI-MTK *and* in MTU3.

Regards,
Angelo

> ---
>   drivers/usb/host/xhci-mtk.c | 10 ++++++++++
>   1 file changed, 10 insertions(+)
> 
> diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
> index 8da05e9dfa28..134a46907db5 100644
> --- a/drivers/usb/host/xhci-mtk.c
> +++ b/drivers/usb/host/xhci-mtk.c
> @@ -96,6 +96,10 @@
>   #define WC0_IS_P	BIT(12)	/* polarity */
>   #define WC0_IS_EN	BIT(6)
>   
> +/* mt8189*/
> +#define PERI_WK_CTRL0_8189	0x0
> +#define WC0_IS_EN_P_89		BIT(18)
> +
>   /* mt8192 */
>   #define WC0_SSUSB0_CDEN		BIT(6)
>   #define WC0_IS_SPM_EN		BIT(1)
> @@ -140,6 +144,7 @@ enum ssusb_uwk_vers {
>   	SSUSB_UWK_V1_7,		/* mt8196 IP0 */
>   	SSUSB_UWK_V1_8,		/* mt8196 IP1 */
>   	SSUSB_UWK_V1_9,		/* mt8196 IP2 */
> +	SSUSB_UWK_V1_10,	/* mt8189 IP all */
>   };
>   
>   /*
> @@ -407,6 +412,11 @@ static void usb_wakeup_ip_sleep_set(struct xhci_hcd_mtk *mtk, bool enable)
>   		msk = WC1_IS_EN_P2_96;
>   		val = enable ? msk : 0;
>   		break;
> +	case SSUSB_UWK_V1_10:
> +		reg = mtk->uwk_reg_base + PERI_WK_CTRL0_8189;
> +		msk = WC0_IS_EN_P_89;
> +		val = enable ? msk : 0;
> +		break;
>   	case SSUSB_UWK_V2:
>   		reg = mtk->uwk_reg_base + PERI_SSUSB_SPM_CTRL;
>   		msk = SSC_IP_SLEEP_EN | SSC_SPM_INT_EN;



From vulab at iscas.ac.cn  Tue Dec  2 22:13:47 2025
From: vulab at iscas.ac.cn (Haotian Zhang)
Date: Wed,  3 Dec 2025 14:13:47 +0800
Subject: [PATCH] pinctrl: single: Fix incorrect type for error return variable
Message-ID: <20251203061347.381-1-vulab@iscas.ac.cn>

pcs_pinconf_get() and pcs_pinconf_set() declare ret as unsigned int,
but assign it the return values of pcs_get_function() that may return
negative error codes. This causes negative error codes to be
converted to large positive values.

Change ret from unsigned int to int in both functions.

Fixes: 9dddb4df90d1 ("pinctrl: single: support generic pinconf")
Signed-off-by: Haotian Zhang <vulab at iscas.ac.cn>
---
 drivers/pinctrl/pinctrl-single.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 5cda6201b60f..21b2580480ca 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -485,7 +485,8 @@ static int pcs_pinconf_get(struct pinctrl_dev *pctldev,
 	struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
 	struct pcs_function *func;
 	enum pin_config_param param;
-	unsigned offset = 0, data = 0, i, j, ret;
+	unsigned offset = 0, data = 0, i, j;
+	int ret;
 
 	ret = pcs_get_function(pctldev, pin, &func);
 	if (ret)
@@ -549,9 +550,9 @@ static int pcs_pinconf_set(struct pinctrl_dev *pctldev,
 {
 	struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
 	struct pcs_function *func;
-	unsigned offset = 0, shift = 0, i, data, ret;
+	unsigned offset = 0, shift = 0, i, data;
 	u32 arg;
-	int j;
+	int j, ret;
 	enum pin_config_param param;
 
 	ret = pcs_get_function(pctldev, pin, &func);
-- 
2.50.1.windows.1



From guoniu.zhou at oss.nxp.com  Tue Dec  2 22:30:01 2025
From: guoniu.zhou at oss.nxp.com (Guoniu Zhou)
Date: Wed, 03 Dec 2025 14:30:01 +0800
Subject: [PATCH 0/2] media: nxp: Add CSI Pixel Formatter support
Message-ID: <20251203-csi_formatter-v1-0-eb9e1147b49e@nxp.com>

CSI Pixel Formatter is a module found on i.MX95. It could unpack the
pixels received by the formatter and reformat them to meet the pixel
link format requirement.

This patch series adds a new v4l2 driver for CSI Pixel Formatter.

v4l2-compliance 1.28.1-5233, 64 bits, 64-bit time_t
v4l2-compliance SHA: fc15e229d9d3 2024-07-23 19:22:15

Compliance test for device /dev/v4l-subdev9:

Driver Info:
	Driver version   : 6.18.0
	Capabilities     : 0x00000002
		Streams Support
	Client Capabilities: 0x0000000000000003
streams interval-uses-which
Required ioctls:
	test VIDIOC_SUDBEV_QUERYCAP: OK
	test invalid ioctls: OK

Allow for multiple opens:
	test second /dev/v4l-subdev9 open: OK
	test VIDIOC_SUBDEV_QUERYCAP: OK
	test for unlimited opens: OK

Debug ioctls:
	test VIDIOC_LOG_STATUS: OK (Not Supported)

Input ioctls:
	test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
	test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
	test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
	test VIDIOC_ENUMAUDIO: OK (Not Supported)
	test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
	test VIDIOC_G/S_AUDIO: OK (Not Supported)
	Inputs: 0 Audio Inputs: 0 Tuners: 0

Output ioctls:
	test VIDIOC_G/S_MODULATOR: OK (Not Supported)
	test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
	test VIDIOC_ENUMAUDOUT: OK (Not Supported)
	test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
	test VIDIOC_G/S_AUDOUT: OK (Not Supported)
	Outputs: 0 Audio Outputs: 0 Modulators: 0

Input/Output configuration ioctls:
	test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
	test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
	test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
	test VIDIOC_G/S_EDID: OK (Not Supported)

Sub-Device routing ioctls:
	test Try VIDIOC_SUBDEV_G_ROUTING/VIDIOC_SUBDEV_S_ROUTING: OK
	test Active VIDIOC_SUBDEV_G_ROUTING/VIDIOC_SUBDEV_S_ROUTING: OK

Control ioctls:
	test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK (Not Supported)
	test VIDIOC_QUERYCTRL: OK (Not Supported)
	test VIDIOC_G/S_CTRL: OK (Not Supported)
	test VIDIOC_G/S/TRY_EXT_CTRLS: OK (Not Supported)
	test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK (Not Supported)
	test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
	Standard Controls: 0 Private Controls: 0

Format ioctls:
	test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK (Not Supported)
	test VIDIOC_G/S_PARM: OK (Not Supported)
	test VIDIOC_G_FBUF: OK (Not Supported)
	test VIDIOC_G_FMT: OK (Not Supported)
	test VIDIOC_TRY_FMT: OK (Not Supported)
	test VIDIOC_S_FMT: OK (Not Supported)
	test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
	test Cropping: OK (Not Supported)
	test Composing: OK (Not Supported)
	test Scaling: OK (Not Supported)

Codec ioctls:
	test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
	test VIDIOC_G_ENC_INDEX: OK (Not Supported)
	test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

Buffer ioctls:
	test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK (Not Supported)
	test CREATE_BUFS maximum buffers: OK
	test VIDIOC_REMOVE_BUFS: OK
	test VIDIOC_EXPBUF: OK (Not Supported)
	test Requests: OK (Not Supported)

Total for device /dev/v4l-subdev9: 47, Succeeded: 47, Failed: 0, Warnings: 0

Signed-off-by: Guoniu Zhou <guoniu.zhou at nxp.com>
---
Guoniu Zhou (2):
      media: dt-bindings: Add CSI Pixel Formatter DT bindings
      media: nxp: Add i.MX9 CSI pixel formatter v4l2 driver

 .../bindings/media/nxp,imx9-csi-formatter.yaml     |  96 +++
 MAINTAINERS                                        |   8 +
 drivers/media/platform/nxp/Kconfig                 |  14 +
 drivers/media/platform/nxp/Makefile                |   1 +
 drivers/media/platform/nxp/imx9-csi-formatter.c    | 894 +++++++++++++++++++++
 5 files changed, 1013 insertions(+)
---
base-commit: 1f2353f5a1af995efbf7bea44341aa0d03460b28
change-id: 20251125-csi_formatter-e6d29316dce6

Best regards,
-- 
Guoniu Zhou <guoniu.zhou at nxp.com>



From guoniu.zhou at oss.nxp.com  Tue Dec  2 22:30:02 2025
From: guoniu.zhou at oss.nxp.com (Guoniu Zhou)
Date: Wed, 03 Dec 2025 14:30:02 +0800
Subject: [PATCH 1/2] media: dt-bindings: Add CSI Pixel Formatter DT
 bindings
In-Reply-To: <20251203-csi_formatter-v1-0-eb9e1147b49e@nxp.com>
References: <20251203-csi_formatter-v1-0-eb9e1147b49e@nxp.com>
Message-ID: <20251203-csi_formatter-v1-1-eb9e1147b49e@nxp.com>

From: Guoniu Zhou <guoniu.zhou at nxp.com>

The i.MX9 CSI pixel formatting module uses packet info, pixel and
non-pixel data from the CSI-2 host controller and reformat them to
match Pixel Link(PL) definition.

Signed-off-by: Guoniu Zhou <guoniu.zhou at nxp.com>
---
 .../bindings/media/nxp,imx9-csi-formatter.yaml     | 96 ++++++++++++++++++++++
 1 file changed, 96 insertions(+)

diff --git a/Documentation/devicetree/bindings/media/nxp,imx9-csi-formatter.yaml b/Documentation/devicetree/bindings/media/nxp,imx9-csi-formatter.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c992a2a225519d3b7934f48cf1646d2cd7089319
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/nxp,imx9-csi-formatter.yaml
@@ -0,0 +1,96 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/nxp,imx9-csi-formatter.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: i.MX9 CSI Pixel Formatter
+
+maintainers:
+  - Guoniu Zhou <guoniu.zhou at nxp.com>
+
+description: |
+  The CSI pixel formatting module uses packet info, pixel and non-pixel
+  data from the CSI-2 host controller and reformat them to match Pixel
+  Link(PL) definition.
+
+properties:
+  compatible:
+    const: fsl,imx9-csi-formatter
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 1
+
+  ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+
+    properties:
+      port at 0:
+        $ref: /schemas/graph.yaml#/$defs/port-base
+        unevaluatedProperties: false
+        description: MIPI CSI-2 RX IDI interface
+
+        properties:
+          endpoint:
+            $ref: video-interfaces.yaml#
+            unevaluatedProperties: false
+
+      port at 1:
+        $ref: /schemas/graph.yaml#/properties/port
+        description: Pixel Link Interface
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - power-domains
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/nxp,imx95-clock.h>
+
+    /*
+     * Power domain definitions from arch/arm64/boot/dts/freescale/imx95-power.h
+     */
+
+    #define IMX95_PD_CAMERA		3
+
+    formatter at 20 {
+        compatible = "fsl,imx9-csi-formatter";
+        reg = <0x20 0x100>;
+        clocks = <&cameramix_csr IMX95_CLK_CAMBLK_CSI2_FOR0>;
+        clock-names = "pixel";
+        power-domains = <&scmi_devpd IMX95_PD_CAMERA>;
+
+        ports {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            port at 0 {
+                reg = <0>;
+                formatter_in: endpoint {
+                    remote-endpoint = <&mipi_csi_0_out>;
+                };
+            };
+
+            port at 1 {
+                reg = <1>;
+                formatter_out: endpoint {
+                    remote-endpoint = <&isi_in_2>;
+                };
+            };
+        };
+    };

-- 
2.34.1



From guoniu.zhou at oss.nxp.com  Tue Dec  2 22:30:03 2025
From: guoniu.zhou at oss.nxp.com (Guoniu Zhou)
Date: Wed, 03 Dec 2025 14:30:03 +0800
Subject: [PATCH 2/2] media: nxp: Add i.MX9 CSI pixel formatter v4l2 driver
In-Reply-To: <20251203-csi_formatter-v1-0-eb9e1147b49e@nxp.com>
References: <20251203-csi_formatter-v1-0-eb9e1147b49e@nxp.com>
Message-ID: <20251203-csi_formatter-v1-2-eb9e1147b49e@nxp.com>

From: Guoniu Zhou <guoniu.zhou at nxp.com>

The CSI pixel formatter is a module found on i.MX95 used to reformat
packet info, pixel and non-pixel data from CSI-2 host controller to
match Pixel Link(PL) definition.

This driver adds its data formatting support.

Signed-off-by: Guoniu Zhou <guoniu.zhou at nxp.com>
---
 MAINTAINERS                                     |   8 +
 drivers/media/platform/nxp/Kconfig              |  14 +
 drivers/media/platform/nxp/Makefile             |   1 +
 drivers/media/platform/nxp/imx9-csi-formatter.c | 894 ++++++++++++++++++++++++
 4 files changed, 917 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 4205ca007e076f869613032b51e8cc5bff06b98e..24681a787818c3e69f93dcc220ee9838cef99886 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18626,6 +18626,14 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/media/nxp,imx8-jpeg.yaml
 F:	drivers/media/platform/nxp/imx-jpeg
 
+NXP i.MX 9 CSI PIXEL FORMATTER V4L2 DRIVER
+M:	Guoniu Zhou <guoniu.zhou at nxp.com>
+L:	imx at lists.linux.dev
+L:	linux-media at vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/media/nxp,imx9-csi-formatter.yaml
+F:	drivers/media/platform/nxp/imx9-csi-formatter.c
+
 NXP i.MX CLOCK DRIVERS
 M:	Abel Vesa <abelvesa at kernel.org>
 R:	Peng Fan <peng.fan at nxp.com>
diff --git a/drivers/media/platform/nxp/Kconfig b/drivers/media/platform/nxp/Kconfig
index 40e3436669e213fdc5da70821dc0b420e1821f4f..a7bb62a2b0249659ffdfeac50fa488aee9590a87 100644
--- a/drivers/media/platform/nxp/Kconfig
+++ b/drivers/media/platform/nxp/Kconfig
@@ -28,6 +28,20 @@ config VIDEO_IMX8MQ_MIPI_CSI2
 	  Video4Linux2 driver for the MIPI CSI-2 receiver found on the i.MX8MQ
 	  SoC.
 
+config VIDEO_IMX9_CSI_FORMATTER
+	tristate "NXP i.MX9 CSI Pixel Formatter driver"
+	depends on ARCH_MXC || COMPILE_TEST
+	depends on VIDEO_DEV
+	select MEDIA_CONTROLLER
+	select V4L2_FWNODE
+	select VIDEO_V4L2_SUBDEV_API
+	help
+	  This driver provides support for the CSI Pixel Formatter found on
+	  i.MX9 series SoC. This module unpacks the pixels received by the
+	  formatter and reformats them to meet the pixel link format requirement.
+
+	  Say Y here to enable CSI Pixel Formater module for i.MX9 SoC.
+
 config VIDEO_IMX_MIPI_CSIS
 	tristate "NXP MIPI CSI-2 CSIS receiver found on i.MX7 and i.MX8 models"
 	depends on ARCH_MXC || COMPILE_TEST
diff --git a/drivers/media/platform/nxp/Makefile b/drivers/media/platform/nxp/Makefile
index 4d90eb71365259ebdda84ea58483e1c4131d3ac7..39ba5660ba923141e7637b01b5b34a021dad7bb3 100644
--- a/drivers/media/platform/nxp/Makefile
+++ b/drivers/media/platform/nxp/Makefile
@@ -6,6 +6,7 @@ obj-y += imx8-isi/
 
 obj-$(CONFIG_VIDEO_IMX7_CSI) += imx7-media-csi.o
 obj-$(CONFIG_VIDEO_IMX8MQ_MIPI_CSI2) += imx8mq-mipi-csi2.o
+obj-$(CONFIG_VIDEO_IMX9_CSI_FORMATTER) += imx9-csi-formatter.o
 obj-$(CONFIG_VIDEO_IMX_MIPI_CSIS) += imx-mipi-csis.o
 obj-$(CONFIG_VIDEO_IMX_PXP) += imx-pxp.o
 obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o
diff --git a/drivers/media/platform/nxp/imx9-csi-formatter.c b/drivers/media/platform/nxp/imx9-csi-formatter.c
new file mode 100644
index 0000000000000000000000000000000000000000..59ccbd26d8acdbca79ea9093746524df803473fc
--- /dev/null
+++ b/drivers/media/platform/nxp/imx9-csi-formatter.c
@@ -0,0 +1,894 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2025 NXP
+ */
+
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include <media/mipi-csi2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mc.h>
+#include <media/v4l2-subdev.h>
+
+/* CSI Pixel Formatter registers map */
+
+#define CSI_VCx_INTERLACED_LINE_CNT(x)		(0x00 + (x) * 0x04)
+#define INTERLACED_ODD_LINE_CNT_SET(x)		FIELD_PREP(GENMASK(13, 0), (x))
+#define INTERLACED_EVEN_LINE_CNT_SET(x)		FIELD_PREP(GENMASK(29, 16), (x))
+
+#define CSI_VC_INTERLACED_CTRL			0x20
+
+#define CSI_VC_INTERLACED_ERR			0x24
+#define CSI_VC_ERR_MASK				GENMASK(7, 0)
+#define CSI_VC_ERR(vc)				BIT((vc))
+
+#define CSI_VC_YUV420_FIRST_LINE_EVEN		0x28
+#define YUV420_FIRST_LINE_EVEN(vc)		BIT((vc))
+
+#define CSI_RAW32_CTRL				0x30
+#define CSI_VCX_RAW32_MODE(vc)			BIT((vc))
+#define CSI_VCX_RAW32_SWAP_MODE(vc)		BIT((vc) + 8)
+
+#define STREAM_FENCING_CTRL			0x34
+#define CSI_VCx_STREAM_FENCING(vc)		BIT((vc))
+#define CSI_VCx_STREAM_FENCING_RST(vc)		BIT((vc) + 8)
+
+#define STREAM_FENCING_STS			0x38
+#define STREAM_FENCING_STS_MASK			GENMASK(7, 0)
+
+#define CSI_VCX_NON_PIXEL_DATA_TYPE(vc)		(0x40 + (vc) * 0x04)
+
+#define CSI_VCX_PIXEL_DATA_CTRL(vc)		(0x60 + (vc) * 0x04)
+#define NEW_VC(x)				FIELD_PREP(GENMASK(3, 1), x)
+#define REROUTE_VC_ENABLE			BIT(0)
+
+#define CSI_VCx_ROUTE_PIXEL_DATA_TYPE(vc)	(0x80 + (vc) * 0x04)
+
+#define CSI_VCx_NON_PIXEL_DATA_CTRL(vc)		(0xa0 + (vc) * 0x04)
+
+#define CSI_VCx_PIXEL_DATA_TYPE(vc)		(0xc0 + (vc) * 0x04)
+
+#define CSI_VCx_PIXEL_DATA_TYPE_ERR(vc)		(0xe0 + (vc) * 0x04)
+
+#define CSI_FORMATTER_PAD_SINK			0
+#define CSI_FORMATTER_PAD_SOURCE		1
+#define CSI_FORMATTER_PAD_NUM			2
+
+#define CSI_FORMATTER_DEF_MBUS_CODE		MEDIA_BUS_FMT_UYVY8_1X16
+#define CSI_FORMATTER_DEF_PIX_WIDTH		1920U
+#define CSI_FORMATTER_DEF_PIX_HEIGHT		1080U
+#define CSI_FORMATTER_MAX_PIX_WIDTH		0xffff
+#define CSI_FORMATTER_MAX_PIX_HEIGHT		0xffff
+
+#define CSI_FORMATTER_DRV_NAME			"csi-pixel-formatter"
+#define CSI_FORMATTER_VC_MAX			8
+
+struct formatter_pix_format {
+	u32 code;
+	u32 data_type;
+};
+
+struct csi_formatter {
+	struct device *dev;
+	struct regmap *regs;
+	struct clk *clk;
+
+	struct v4l2_subdev sd;
+	struct v4l2_subdev *csi_sd;
+	struct v4l2_async_notifier notifier;
+	struct v4l2_mbus_framefmt format[CSI_FORMATTER_PAD_NUM];
+	struct media_pad pads[CSI_FORMATTER_PAD_NUM];
+	const struct formatter_pix_format *fmt;
+
+	u16 remote_pad;
+	u32 reg_offset;
+	u64 enabled_streams;
+};
+
+struct dt_index {
+	u8 dtype;
+	u8 index;
+};
+
+static const struct dt_index formatter_dt_to_index_map[] = {
+	{ .dtype = MIPI_CSI2_DT_YUV420_8B,        .index = 0 },
+	{ .dtype = MIPI_CSI2_DT_YUV420_8B_LEGACY, .index = 2 },
+	{ .dtype = MIPI_CSI2_DT_YUV422_8B,        .index = 6 },
+	{ .dtype = MIPI_CSI2_DT_RGB444,		  .index = 8 },
+	{ .dtype = MIPI_CSI2_DT_RGB555,           .index = 9 },
+	{ .dtype = MIPI_CSI2_DT_RGB565,           .index = 10 },
+	{ .dtype = MIPI_CSI2_DT_RGB666,           .index = 11 },
+	{ .dtype = MIPI_CSI2_DT_RGB888,           .index = 12 },
+	{ .dtype = MIPI_CSI2_DT_RAW6,             .index = 16 },
+	{ .dtype = MIPI_CSI2_DT_RAW7,             .index = 17 },
+	{ .dtype = MIPI_CSI2_DT_RAW8,             .index = 18 },
+	{ .dtype = MIPI_CSI2_DT_RAW10,            .index = 19 },
+	{ .dtype = MIPI_CSI2_DT_RAW12,            .index = 20 },
+	{ .dtype = MIPI_CSI2_DT_RAW14,            .index = 21 },
+	{ .dtype = MIPI_CSI2_DT_RAW16,            .index = 22 },
+};
+
+static const struct formatter_pix_format formats[] = {
+	/* YUV formats */
+	{
+		.code = MEDIA_BUS_FMT_UYVY8_1X16,
+		.data_type = MIPI_CSI2_DT_YUV422_8B,
+	},
+	/* RGB formats */
+	{
+		.code = MEDIA_BUS_FMT_RGB565_1X16,
+		.data_type = MIPI_CSI2_DT_RGB565,
+	}, {
+		.code = MEDIA_BUS_FMT_RGB888_1X24,
+		.data_type = MIPI_CSI2_DT_RGB888,
+	},
+	/* RAW (Bayer and greyscale) formats. */
+	{
+		.code = MEDIA_BUS_FMT_SBGGR8_1X8,
+		.data_type = MIPI_CSI2_DT_RAW8,
+	}, {
+		.code = MEDIA_BUS_FMT_SGBRG8_1X8,
+		.data_type = MIPI_CSI2_DT_RAW8,
+	}, {
+		.code = MEDIA_BUS_FMT_SGRBG8_1X8,
+		.data_type = MIPI_CSI2_DT_RAW8,
+	}, {
+		.code = MEDIA_BUS_FMT_SRGGB8_1X8,
+		.data_type = MIPI_CSI2_DT_RAW8,
+	}, {
+		.code = MEDIA_BUS_FMT_Y8_1X8,
+		.data_type = MIPI_CSI2_DT_RAW8,
+	}, {
+		.code = MEDIA_BUS_FMT_SBGGR10_1X10,
+		.data_type = MIPI_CSI2_DT_RAW10,
+	}, {
+		.code = MEDIA_BUS_FMT_SGBRG10_1X10,
+		.data_type = MIPI_CSI2_DT_RAW10,
+	}, {
+		.code = MEDIA_BUS_FMT_SGRBG10_1X10,
+		.data_type = MIPI_CSI2_DT_RAW10,
+	}, {
+		.code = MEDIA_BUS_FMT_SRGGB10_1X10,
+		.data_type = MIPI_CSI2_DT_RAW10,
+	}, {
+		.code = MEDIA_BUS_FMT_Y10_1X10,
+		.data_type = MIPI_CSI2_DT_RAW10,
+	}, {
+		.code = MEDIA_BUS_FMT_SBGGR12_1X12,
+		.data_type = MIPI_CSI2_DT_RAW12,
+	}, {
+		.code = MEDIA_BUS_FMT_SGBRG12_1X12,
+		.data_type = MIPI_CSI2_DT_RAW12,
+	}, {
+		.code = MEDIA_BUS_FMT_SGRBG12_1X12,
+		.data_type = MIPI_CSI2_DT_RAW12,
+	}, {
+		.code = MEDIA_BUS_FMT_SRGGB12_1X12,
+		.data_type = MIPI_CSI2_DT_RAW12,
+	}, {
+		.code = MEDIA_BUS_FMT_Y12_1X12,
+		.data_type = MIPI_CSI2_DT_RAW12,
+	}, {
+		.code = MEDIA_BUS_FMT_SBGGR14_1X14,
+		.data_type = MIPI_CSI2_DT_RAW14,
+	}, {
+		.code = MEDIA_BUS_FMT_SGBRG14_1X14,
+		.data_type = MIPI_CSI2_DT_RAW14,
+	}, {
+		.code = MEDIA_BUS_FMT_SGRBG14_1X14,
+		.data_type = MIPI_CSI2_DT_RAW14,
+	}, {
+		.code = MEDIA_BUS_FMT_SRGGB14_1X14,
+		.data_type = MIPI_CSI2_DT_RAW14,
+	}, {
+		.code = MEDIA_BUS_FMT_SBGGR16_1X16,
+		.data_type = MIPI_CSI2_DT_RAW16,
+	}, {
+		.code = MEDIA_BUS_FMT_SGBRG16_1X16,
+		.data_type = MIPI_CSI2_DT_RAW16,
+	}, {
+		.code = MEDIA_BUS_FMT_SGRBG16_1X16,
+		.data_type = MIPI_CSI2_DT_RAW16,
+	}, {
+		.code = MEDIA_BUS_FMT_SRGGB16_1X16,
+		.data_type = MIPI_CSI2_DT_RAW16,
+	}
+};
+
+static const struct v4l2_mbus_framefmt formatter_default_fmt = {
+	.code = CSI_FORMATTER_DEF_MBUS_CODE,
+	.width = CSI_FORMATTER_DEF_PIX_WIDTH,
+	.height = CSI_FORMATTER_DEF_PIX_HEIGHT,
+	.field = V4L2_FIELD_NONE,
+	.colorspace = V4L2_COLORSPACE_SMPTE170M,
+	.xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SMPTE170M),
+	.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SMPTE170M),
+	.quantization = V4L2_QUANTIZATION_LIM_RANGE,
+};
+
+static const struct formatter_pix_format *find_csi_format(u32 code)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(formats); i++)
+		if (code == formats[i].code)
+			return &formats[i];
+
+	return &formats[0];
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+static inline struct csi_formatter *sd_to_formatter(struct v4l2_subdev *sdev)
+{
+	return container_of(sdev, struct csi_formatter, sd);
+}
+
+static int __formatter_subdev_set_routing(struct v4l2_subdev *sd,
+					  struct v4l2_subdev_state *state,
+					  struct v4l2_subdev_krouting *routing)
+{
+	int ret;
+
+	if (routing->num_routes > V4L2_FRAME_DESC_ENTRY_MAX)
+		return -EINVAL;
+
+	ret = v4l2_subdev_routing_validate(sd, routing,
+					   V4L2_SUBDEV_ROUTING_ONLY_1_TO_1);
+	if (ret)
+		return ret;
+
+	return v4l2_subdev_set_routing_with_fmt(sd, state, routing,
+						&formatter_default_fmt);
+}
+
+static int formatter_subdev_init_state(struct v4l2_subdev *sd,
+				       struct v4l2_subdev_state *sd_state)
+{
+	struct v4l2_subdev_route routes[] = {
+		{
+			.sink_pad = CSI_FORMATTER_PAD_SINK,
+			.sink_stream = 0,
+			.source_pad = CSI_FORMATTER_PAD_SOURCE,
+			.source_stream = 0,
+			.flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
+		},
+	};
+
+	struct v4l2_subdev_krouting routing = {
+		.num_routes = ARRAY_SIZE(routes),
+		.routes = routes,
+	};
+
+	return __formatter_subdev_set_routing(sd, sd_state, &routing);
+}
+
+static int formatter_subdev_enum_mbus_code(struct v4l2_subdev *sd,
+					   struct v4l2_subdev_state *sd_state,
+					   struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->pad == CSI_FORMATTER_PAD_SOURCE) {
+		struct v4l2_mbus_framefmt *fmt;
+
+		if (code->index > 0)
+			return -EINVAL;
+
+		fmt = v4l2_subdev_state_get_format(sd_state, code->pad,
+						   code->stream);
+		code->code = fmt->code;
+		return 0;
+	}
+
+	if (code->index >= ARRAY_SIZE(formats))
+		return -EINVAL;
+
+	code->code = formats[code->index].code;
+
+	return 0;
+}
+
+static int formatter_subdev_set_fmt(struct v4l2_subdev *sd,
+				    struct v4l2_subdev_state *sd_state,
+				    struct v4l2_subdev_format *sdformat)
+{
+	struct csi_formatter *formatter = sd_to_formatter(sd);
+	struct formatter_pix_format const *format;
+	struct v4l2_mbus_framefmt *fmt;
+
+	if (sdformat->pad == CSI_FORMATTER_PAD_SOURCE)
+		return v4l2_subdev_get_fmt(sd, sd_state, sdformat);
+
+	/*
+	 * Validate the media bus code and clamp and align the size.
+	 *
+	 * The total number of bits per line must be a multiple of 8. We thus
+	 * need to align the width for formats that are not multiples of 8
+	 * bits.
+	 */
+	format = find_csi_format(sdformat->format.code);
+
+	v4l_bound_align_image(&sdformat->format.width, 1,
+			      CSI_FORMATTER_MAX_PIX_WIDTH, 2,
+			      &sdformat->format.height, 1,
+			      CSI_FORMATTER_MAX_PIX_HEIGHT, 0, 0);
+
+	fmt = v4l2_subdev_state_get_format(sd_state, sdformat->pad,
+					   sdformat->stream);
+	*fmt = sdformat->format;
+
+	/* Set default code if user set an invalid value */
+	fmt->code = format->code;
+
+	/* Propagate the format from sink stream to source stream */
+	fmt = v4l2_subdev_state_get_opposite_stream_format(sd_state, sdformat->pad,
+							   sdformat->stream);
+	if (!fmt)
+		return -EINVAL;
+
+	*fmt = sdformat->format;
+
+	/* Store the CSIS format descriptor for active formats. */
+	if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+		formatter->fmt = format;
+
+	return 0;
+}
+
+static int formatter_subdev_get_frame_desc(struct v4l2_subdev *sd,
+					   unsigned int pad,
+					   struct v4l2_mbus_frame_desc *fd)
+{
+	struct csi_formatter *formatter = sd_to_formatter(sd);
+	struct v4l2_mbus_frame_desc csi_fd;
+	struct v4l2_subdev_route *route;
+	struct v4l2_subdev_state *state;
+	int ret;
+
+	if (pad != CSI_FORMATTER_PAD_SOURCE)
+		return -EINVAL;
+
+	ret = v4l2_subdev_call(formatter->csi_sd, pad, get_frame_desc,
+			       formatter->remote_pad, &csi_fd);
+	if (ret)
+		return ret;
+
+	if (csi_fd.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) {
+		dev_err(formatter->dev,
+			"Frame descriptor does not describe CSI-2 link\n");
+		return -EINVAL;
+	}
+
+	memset(fd, 0, sizeof(*fd));
+
+	fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2;
+
+	state = v4l2_subdev_lock_and_get_active_state(sd);
+
+	for_each_active_route(&state->routing, route) {
+		struct v4l2_mbus_frame_desc_entry *entry = NULL;
+		unsigned int i;
+
+		if (route->source_pad != pad)
+			continue;
+
+		for (i = 0; i < csi_fd.num_entries; ++i) {
+			if (csi_fd.entry[i].stream == route->sink_stream) {
+				entry = &csi_fd.entry[i];
+				break;
+			}
+		}
+
+		if (!entry) {
+			dev_err(formatter->dev,
+				"Failed to find stream from source frames desc\n");
+			ret = -EPIPE;
+			goto out_unlock;
+		}
+
+		fd->entry[fd->num_entries].stream = route->source_stream;
+		fd->entry[fd->num_entries].flags = entry->flags;
+		fd->entry[fd->num_entries].length = entry->length;
+		fd->entry[fd->num_entries].pixelcode = entry->pixelcode;
+		fd->entry[fd->num_entries].bus.csi2.vc = entry->bus.csi2.vc;
+		fd->entry[fd->num_entries].bus.csi2.dt = entry->bus.csi2.dt;
+
+		fd->num_entries++;
+	}
+
+out_unlock:
+	v4l2_subdev_unlock_state(state);
+	return ret;
+}
+
+static int formatter_subdev_set_routing(struct v4l2_subdev *sd,
+					struct v4l2_subdev_state *state,
+					enum v4l2_subdev_format_whence which,
+					struct v4l2_subdev_krouting *routing)
+{
+	if (which == V4L2_SUBDEV_FORMAT_ACTIVE &&
+	    media_entity_is_streaming(&sd->entity))
+		return -EBUSY;
+
+	return __formatter_subdev_set_routing(sd, state, routing);
+}
+
+static inline void formatter_write(struct csi_formatter *formatter,
+				   unsigned int reg, unsigned int value)
+{
+	u32 offset = formatter->reg_offset;
+
+	regmap_write(formatter->regs, reg + offset, value);
+}
+
+static u8 get_index_by_dt(u8 data_type)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(formatter_dt_to_index_map); ++i)
+		if (data_type == formatter_dt_to_index_map[i].dtype)
+			break;
+
+	if (i == ARRAY_SIZE(formatter_dt_to_index_map))
+		return formatter_dt_to_index_map[0].index;
+
+	return formatter_dt_to_index_map[i].index;
+}
+
+static int get_vc(struct csi_formatter *formatter, unsigned int stream)
+{
+	struct v4l2_mbus_frame_desc source_fd;
+	struct v4l2_mbus_frame_desc_entry *entry = NULL;
+	unsigned int i;
+	int ret;
+
+	/*
+	 * Return virtual channel 0 as default value when remote subdev
+	 * don't implement .get_frame_desc subdev callback
+	 */
+	ret = v4l2_subdev_call(formatter->csi_sd, pad, get_frame_desc,
+			       formatter->remote_pad, &source_fd);
+	if (ret < 0)
+		return (ret == -ENOIOCTLCMD) ? 0 : ret;
+
+	for (i = 0; i < source_fd.num_entries; ++i) {
+		if (source_fd.entry[i].stream == stream) {
+			entry = &source_fd.entry[i];
+			break;
+		}
+	}
+
+	if (!entry) {
+		dev_err(formatter->dev,
+			"Can't find valid frame desc corresponding to stream %d\n", stream);
+		return -EPIPE;
+	}
+
+	return entry->bus.csi2.vc;
+}
+
+static int csi_formatter_start_stream(struct csi_formatter *formatter,
+				      u64 stream_mask)
+{
+	const struct formatter_pix_format *fmt = formatter->fmt;
+	unsigned int i;
+	u32 val;
+	int vc;
+
+	for (i = 0; i < V4L2_FRAME_DESC_ENTRY_MAX; ++i) {
+		if (stream_mask & BIT(i))
+			break;
+	}
+
+	if (i == V4L2_FRAME_DESC_ENTRY_MAX) {
+		dev_err(formatter->dev, "Stream ID out of range\n");
+		return -EINVAL;
+	}
+
+	val = BIT(get_index_by_dt(fmt->data_type));
+	vc = get_vc(formatter, i);
+
+	if (vc < 0 || vc > CSI_FORMATTER_VC_MAX) {
+		dev_err(formatter->dev, "Invalid virtual channel(%d)\n", vc);
+		return -EINVAL;
+	}
+
+	formatter_write(formatter, CSI_VCx_PIXEL_DATA_TYPE(vc), val);
+
+	return 0;
+}
+
+static int formatter_subdev_enable_streams(struct v4l2_subdev *sd,
+					   struct v4l2_subdev_state *state,
+					   u32 pad, u64 streams_mask)
+{
+	struct csi_formatter *formatter = sd_to_formatter(sd);
+	struct device *dev = formatter->dev;
+	u64 sink_streams;
+	int ret;
+
+	if (!formatter->csi_sd) {
+		dev_err(dev, "CSI controller don't link with formatter\n");
+		return -EPIPE;
+	}
+
+	if (!formatter->enabled_streams) {
+		ret = pm_runtime_resume_and_get(formatter->dev);
+		if (ret < 0) {
+			dev_err(dev, "Formatter runtime get fail\n");
+			return ret;
+		}
+	}
+
+	ret = csi_formatter_start_stream(formatter, streams_mask);
+	if (ret)
+		goto runtime_put;
+
+	sink_streams = v4l2_subdev_state_xlate_streams(state,
+						       CSI_FORMATTER_PAD_SOURCE,
+						       CSI_FORMATTER_PAD_SINK,
+						       &streams_mask);
+
+	dev_dbg(dev, "remote sd: %s pad: %u, sink_stream:0x%llx\n",
+		formatter->csi_sd->name, formatter->remote_pad, sink_streams);
+
+	ret = v4l2_subdev_enable_streams(formatter->csi_sd, formatter->remote_pad,
+					 sink_streams);
+	if (ret)
+		goto runtime_put;
+
+	formatter->enabled_streams |= streams_mask;
+
+	return 0;
+
+runtime_put:
+	pm_runtime_put(formatter->dev);
+	return ret;
+}
+
+static int csi_formatter_stop_stream(struct csi_formatter *formatter,
+				     u64 stream_mask)
+{
+	unsigned int i;
+	int vc;
+
+	for (i = 0; i < V4L2_FRAME_DESC_ENTRY_MAX; ++i) {
+		if (stream_mask & BIT(i))
+			break;
+	}
+
+	if (i == V4L2_FRAME_DESC_ENTRY_MAX) {
+		dev_err(formatter->dev, "Stream ID out of range\n");
+		return -EINVAL;
+	}
+
+	vc = get_vc(formatter, i);
+
+	if (vc < 0 || vc > CSI_FORMATTER_VC_MAX) {
+		dev_err(formatter->dev, "Invalid virtual channel(%d)\n", vc);
+		return -EINVAL;
+	}
+
+	formatter_write(formatter, CSI_VCx_PIXEL_DATA_TYPE(vc), 0);
+
+	return 0;
+}
+
+static int formatter_subdev_disable_streams(struct v4l2_subdev *sd,
+					    struct v4l2_subdev_state *state,
+					    u32 pad, u64 streams_mask)
+{
+	struct csi_formatter *formatter = sd_to_formatter(sd);
+	u64 sink_streams;
+	int ret;
+
+	sink_streams = v4l2_subdev_state_xlate_streams(state,
+						       CSI_FORMATTER_PAD_SOURCE,
+						       CSI_FORMATTER_PAD_SINK,
+						       &streams_mask);
+
+	ret = v4l2_subdev_disable_streams(formatter->csi_sd, formatter->remote_pad,
+					  sink_streams);
+	if (ret)
+		return ret;
+
+	ret = csi_formatter_stop_stream(formatter, streams_mask);
+	if (ret)
+		return ret;
+
+	formatter->enabled_streams &= ~streams_mask;
+
+	if (!formatter->enabled_streams)
+		pm_runtime_put(formatter->dev);
+
+	return 0;
+}
+
+static const struct v4l2_subdev_pad_ops formatter_subdev_pad_ops = {
+	.enum_mbus_code		= formatter_subdev_enum_mbus_code,
+	.get_fmt		= v4l2_subdev_get_fmt,
+	.set_fmt		= formatter_subdev_set_fmt,
+	.get_frame_desc		= formatter_subdev_get_frame_desc,
+	.set_routing		= formatter_subdev_set_routing,
+	.enable_streams		= formatter_subdev_enable_streams,
+	.disable_streams	= formatter_subdev_disable_streams,
+};
+
+static const struct v4l2_subdev_ops formatter_subdev_ops = {
+	.pad = &formatter_subdev_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops formatter_internal_ops = {
+	.init_state = formatter_subdev_init_state,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+static const struct media_entity_operations formatter_entity_ops = {
+	.link_validate	= v4l2_subdev_link_validate,
+	.get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1,
+};
+
+static int csi_formatter_subdev_init(struct csi_formatter *formatter)
+{
+	struct v4l2_subdev *sd = &formatter->sd;
+	int ret;
+
+	v4l2_subdev_init(sd, &formatter_subdev_ops);
+
+	snprintf(sd->name, sizeof(sd->name), "%s", dev_name(formatter->dev));
+	sd->internal_ops = &formatter_internal_ops;
+
+	sd->owner = THIS_MODULE;
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+		     V4L2_SUBDEV_FL_HAS_EVENTS |
+		     V4L2_SUBDEV_FL_STREAMS;
+	sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
+	sd->entity.ops = &formatter_entity_ops;
+	sd->dev = formatter->dev;
+
+	formatter->pads[CSI_FORMATTER_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+	formatter->pads[CSI_FORMATTER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+	ret = media_entity_pads_init(&sd->entity, CSI_FORMATTER_PAD_NUM,
+				     formatter->pads);
+	if (ret) {
+		dev_err(formatter->dev, "Failed to init pads\n");
+		return ret;
+	}
+
+	ret = v4l2_subdev_init_finalize(sd);
+	if (ret)
+		media_entity_cleanup(&sd->entity);
+
+	return ret;
+}
+
+static inline struct csi_formatter *
+notifier_to_formatter(struct v4l2_async_notifier *n)
+{
+	return container_of(n, struct csi_formatter, notifier);
+}
+
+static int csi_formatter_notify_bound(struct v4l2_async_notifier *notifier,
+				      struct v4l2_subdev *sd,
+				      struct v4l2_async_connection *asc)
+{
+	const unsigned int link_flags = MEDIA_LNK_FL_IMMUTABLE
+				      | MEDIA_LNK_FL_ENABLED;
+	struct csi_formatter *formatter = notifier_to_formatter(notifier);
+	struct v4l2_subdev *sdev = &formatter->sd;
+	struct media_pad *sink = &sdev->entity.pads[CSI_FORMATTER_PAD_SINK];
+	struct media_pad *remote_pad;
+	int ret;
+
+	formatter->csi_sd = sd;
+
+	dev_dbg(formatter->dev, "Bound subdev: %s pad\n", sd->name);
+
+	ret = v4l2_create_fwnode_links_to_pad(sd, sink, link_flags);
+	if (ret < 0)
+		return ret;
+
+	remote_pad = media_pad_remote_pad_first(sink);
+	if (!remote_pad) {
+		dev_err(formatter->dev, "Pipe not setup correctly\n");
+		return -EPIPE;
+	}
+	formatter->remote_pad = remote_pad->index;
+
+	return 0;
+}
+
+static const struct v4l2_async_notifier_operations formatter_notify_ops = {
+	.bound = csi_formatter_notify_bound,
+};
+
+static int csi_formatter_async_register(struct csi_formatter *formatter)
+{
+	struct device *dev = formatter->dev;
+	struct v4l2_async_connection *asc;
+	struct fwnode_handle *ep;
+	int ret;
+
+	v4l2_async_subdev_nf_init(&formatter->notifier, &formatter->sd);
+
+	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0,
+					     FWNODE_GRAPH_ENDPOINT_NEXT);
+	if (!ep)
+		return -ENOTCONN;
+
+	asc = v4l2_async_nf_add_fwnode_remote(&formatter->notifier, ep,
+					      struct v4l2_async_connection);
+	if (IS_ERR(asc)) {
+		fwnode_handle_put(ep);
+		return PTR_ERR(asc);
+	}
+
+	fwnode_handle_put(ep);
+
+	formatter->notifier.ops = &formatter_notify_ops;
+
+	ret = v4l2_async_nf_register(&formatter->notifier);
+	if (ret)
+		return ret;
+
+	return v4l2_async_register_subdev(&formatter->sd);
+}
+
+/* -----------------------------------------------------------------------------
+ * Suspend/resume
+ */
+
+static int csi_formatter_system_suspend(struct device *dev)
+{
+	return pm_runtime_force_suspend(dev);
+}
+
+static int csi_formatter_system_resume(struct device *dev)
+{
+	int ret;
+
+	ret = pm_runtime_force_resume(dev);
+	if (ret < 0) {
+		dev_err(dev, "force resume %s failed!\n", dev_name(dev));
+		return ret;
+	}
+
+	return 0;
+}
+
+static int csi_formatter_runtime_suspend(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct csi_formatter *formatter = sd_to_formatter(sd);
+
+	clk_disable_unprepare(formatter->clk);
+
+	return 0;
+}
+
+static int csi_formatter_runtime_resume(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct csi_formatter *formatter = sd_to_formatter(sd);
+
+	return clk_prepare_enable(formatter->clk);
+}
+
+static const struct dev_pm_ops csi_formatter_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(csi_formatter_system_suspend,
+				csi_formatter_system_resume)
+	SET_RUNTIME_PM_OPS(csi_formatter_runtime_suspend,
+			   csi_formatter_runtime_resume,
+			   NULL)
+};
+
+static int csi_formatter_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct csi_formatter *formatter;
+	u32 val;
+	int ret;
+
+	formatter = devm_kzalloc(dev, sizeof(*formatter), GFP_KERNEL);
+	if (!formatter)
+		return -ENOMEM;
+
+	formatter->dev = dev;
+
+	formatter->regs = syscon_node_to_regmap(dev->parent->of_node);
+	if (IS_ERR(formatter->regs)) {
+		dev_err(dev, "Failed to get csi formatter regmap\n");
+		return -ENODEV;
+	}
+
+	ret = of_property_read_u32(dev->of_node, "reg", &val);
+	if (ret < 0) {
+		dev_err(dev, "Failed to get csi formatter reg property\n");
+		return ret;
+	}
+	formatter->reg_offset = val;
+
+	formatter->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(formatter->clk)) {
+		dev_err(dev, "Failed to get pixel clock\n");
+		return PTR_ERR(formatter->clk);
+	}
+
+	ret = csi_formatter_subdev_init(formatter);
+	if (ret < 0) {
+		dev_err(dev, "formatter subdev init fail\n");
+		return ret;
+	}
+
+	/* Initialize formatter pixel format */
+	formatter->fmt = find_csi_format(formatter_default_fmt.code);
+
+	ret = csi_formatter_async_register(formatter);
+	if (ret < 0) {
+		v4l2_subdev_cleanup(&formatter->sd);
+		dev_err(dev, "Async register failed\n");
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, &formatter->sd);
+
+	/* Enable runtime PM. */
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static void csi_formatter_remove(struct platform_device *pdev)
+{
+	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+	struct csi_formatter *formatter = sd_to_formatter(sd);
+
+	v4l2_async_nf_unregister(&formatter->notifier);
+	v4l2_async_nf_cleanup(&formatter->notifier);
+	v4l2_async_unregister_subdev(&formatter->sd);
+
+	pm_runtime_disable(&pdev->dev);
+	media_entity_cleanup(&formatter->sd.entity);
+	pm_runtime_set_suspended(&pdev->dev);
+}
+
+static const struct of_device_id csi_formatter_of_match[] = {
+	{ .compatible = "fsl,imx9-csi-formatter" },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, csi_formatter_of_match);
+
+static struct platform_driver csi_formatter_device_driver = {
+	.driver = {
+		.owner          = THIS_MODULE,
+		.name           = CSI_FORMATTER_DRV_NAME,
+		.of_match_table = csi_formatter_of_match,
+		.pm             = &csi_formatter_pm_ops,
+	},
+	.probe  = csi_formatter_probe,
+	.remove = csi_formatter_remove,
+};
+
+module_platform_driver(csi_formatter_device_driver);
+
+MODULE_ALIAS("platform:" CSI_FORMATTER_DRV_NAME);
+MODULE_AUTHOR("NXP Semiconductor, Inc.");
+MODULE_DESCRIPTION("NXP i.MX9 CSI Pixel Formatter driver");
+MODULE_LICENSE("GPL");

-- 
2.34.1



From pankaj.gupta at nxp.com  Tue Dec  2 22:48:05 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Wed, 03 Dec 2025 12:18:05 +0530
Subject: [PATCH v20 0/7] firmware: imx: driver for NXP secure-enclave
Message-ID: <20251203-imx-se-if-v20-0-a04a25c4255f@nxp.com>

The NXP's i.MX EdgeLock Enclave, a HW IP creating an embedded secure
enclave within the SoC boundary to enable features like
- HSM
- SHE
- V2X

Communicates via message unit with linux kernel. This driver is
enables communication ensuring well defined message sequence protocol
between Application Core and enclave's firmware.

Driver configures multiple misc-device on the MU, for multiple
user-space applications can communicate on single MU.

It exists on some i.MX processors. e.g. i.MX8ULP, i.MX93 etc.

-------
Changes in v20:
5/7:
- adds a func "se_chk_tx_msg_hdr", to check the validity of the in-coming message from usersapce.

1/2, 2/7, 3/7, 4/7, 6/7 & 7/7
- No changes

Reference:
- Link to v19: https://lore.kernel.org/r/20250927-imx-se-if-v19-0-d1e7e960c118 at nxp.com

Changes in v19:

1/7
- Added 9 lines to the Introduction from line 73-82.

3/7
-  Update the commit message for " For i.MX9x SoC(s) there is at least one
dedicated ELE MU(s) for each world - Linux(one or more) and OP-TEE OS (one or
more), that needs to be shared between them.."

Reference:
- Link to v18: https://lore.kernel.org/r/20250619-imx-se-if-v18-0-c98391ba446d at nxp.com

Changes in v18:

1/7
- Wrap both diagrams above in literal code block by using double-colon

3/7 & 5/7
- Collected Frank's R-b tag.

2/7, 4/7, 6/7 & 7/7
- No changes

Reference:
- Link to v17: https://lore.kernel.org/r/20250426-imx-se-if-v17-0-0c85155a50d1 at nxp.com

Changes in v17:
- Changes to 3/7 & 5/7: to wrap code text at 80 character whereever possible.

Reference:
- Link to v16: https://lore.kernel.org/r/20250409-imx-se-if-v16-0-5394e5f3417e at nxp.com

Changes in v16:
- commit 3/7 and 4/7 are moved to end commits making them as 6/7 and 7/7 respectively.
- No change in 1/7 & 2/7.

7/7
- Collected Frank's R-b tag.

6/7
- commit message is updated to wrap at 75 characters.

5/7
- func add_b_desc_to_pending_list, removed the initialization of b_desc to
  NULL.
- variable timeout in func ele_msg_rcv(), is renamed to timeout_ms.
- struct se_if_priv, member variable se_rcv_msg_timeout, is renamed to
  se_rcv_msg_timeout_ms.
- in func load_firmware, move the label exit after dma_free_coherent.

4/7
- commit message is updated to wrap at 75 characters.

3/7
- ele_debug_dump, updated the assignment of keep_logging.
- ele_fw_authenticate function definition is updated to take two address
  as arguments.

Reference:
- Link to v15: https://lore.kernel.org/r/20250407-imx-se-if-v15-0-e3382cecda01 at nxp.com

Changes in v15:
- Patch 3/6 is split into two:
  - 3/7: arm64: dts: imx8ulp-evk: add reserved memory property
  - 4/7: arm64: dts: imx8ulp: add nxp secure enclave firmware
- No change in 1/7 & 2/7.

7/7
- removed the se_intance_id structure member variable.
- replace variable name from wait to timeout.
- used 'goto' to follow the common exit path calling "release_firmware(fw);" in case of error path.
- removed TBD string.
- Used ARRAY_SIZE(pending_lists).
- moved init_device_context after init_misc_device_context.
- defined err as long to avoid force convert in func
- added se_rcv_msg_timeout to priv, to control probe/suspend/resume per interface.

6/7
- removed the se_intance_id structure member variable.
- Added dev_ctx to the structure se_clbk_handle, too.
- Collected Frank's R-b tag.

5/7
- removed the se_intance_id structure member variable.
- since added se_if_probe_cleanup to devm, se_if_remove() is redundant. hence removed it.
- rename se_add_msg_chksum to se_get_msg_chksum
- added check if msg-size is 4 byte aligned.
- Fixed multiline comments.
- ele_debug_dump api is updated as part of comment disposition like single setting of flag "keep_logging" & adding if (ret).
- moved dev_err to dev_dbg, for imem save/restore functions.
- moved func get_se_if_name, from 7/7 to here.

3/7
- Updated the commit message.
- split the current patch into two:
  -- 3/7 for board dts, and
  -- 4/7 for chip dts

Reference:
- Link to v14: https://lore.kernel.org/r/20250327-imx-se-if-v14-0-2219448932e4 at nxp.com

Changes in v14:

- Patch 5/5 is split into two:
  - firmware: drivers: imx: adds miscdev
  - Introduce dev-ctx dedicated to private.
    -- Base patch before enabling misc-device context, to have the send-receive path, based on device context.
- No change in 1/6 & 2/6.
- Copied change logs from individual commits.

6/6
- moved definition of func se_load_firmware, from 4/6 patch to this patch.
- split init_device_context to init_misc_device_context.
- Different value of se_rcv_msg_timeout is required to be set. Receiving the response of 4K RSA operation can to take upto 3 minutes.
  This long value cannot be set during Linux: boot-up and suspend-resume.
  Hence, it will be set to default small-value during Linux: boot-up and suspend-resume.
- func se_dev_ctx_cpy_out_data(), in either case: do_cpy true or false, the clean-up needs to be done and it is implemented like wise.
  Once do_cpy is false, no need to continue copy to user buffer. But continue to do clean-up. hence cannot return.
  And every dev-ctx operation is done after taking the lock. Hence, two operations with same dev-ctx is not possible in parallel.
- func "init_device_context", for 0th misc dev_ctx, which is created at the time of probe, the device memory management is required. hence there is a difference.
- func "init_device_context", dev_er is replaced with return dev_err_probe.
- func "init_device_context", devm_add_action is replaced by devm_add_action_reset.
- removed type-cast from func se_ioctl_get_se_soc_info_handler().
- used scoped_cond_guard(mutex, _intr, return -EBUSY, &<mutex_lock>)
- combined dev_err & dev_dbg to one dev_err in se_if_fops_read().
- removed the structure member "se_shared_mem_mgmt->secure_mem".

4/6
- trimmed the ele_fetch_soc_info.
- removed the function ptr "se_info->se_fetch_soc_info" and replaced with ele_fetch_soc_info.
- moved definition of func se_load_firmware, to 6/6 patch.
- Different SoC, different ways to fetch soc_info. Generic function declaration for ele_fetch_soc_info() is needed. Hence wrapping ele_get_info() in it.
- Updated Kconfig help text for assertive tone.
- func ele_debug_dump is updated, to remove constructing the format string.
- removed the macro usage for SOC_ID_MASK.
- used low case hex number.
- Condition will never occur, where msg_len satisfy the following condition "msg_len % 4 != 0". Err msg is added if it occurs.
- Function description is added to se_add_msg_crc.
- timeout is added to function ele_msg_rcv, in 5/5 patch.
- local variable "header" is initialized with "tx_msg" and replaced "return err" with "return tx_msg_sz" in func ele_msg_send().
- replace function name from "exception_for_size" to "check_hdr_exception_for_sz"
- replaced "return ret > 0 ? 0 : -1;" with "return ret > 0 ? 0 : ret;" in func "se_save_imem_state".
- func "se_restore_imem_state", to return if the condition is false to proceed.
- removed casting by (void *).
- removed devm_kasprintf and done direct allocatiion for attr->soc_id = "i.MX8ULP" & attr->soc_id = "i.MX8ULP", & attr->family.
- Followed Reverse christmas tree order, whereever missing.
- There is no return if ele_fw_authenticate fails. Execution flow continue forward and execute the fucn dma_free_coherent().
- The loop is not for retry. The loop is needed to load secondary fw followed by loading primary fw, first. This is the case when ELE also got reset.
- dev_err_probe is corrected in func "se_if_request_channel".

3/6
-

Reference:
- Link to v13: https://lore.kernel.org/r/20250311-imx-se-if-v13-0-9cc6d8fd6d1c at nxp.com

Changes in v13:

5/5
- Updated the commit message for imperative mood.
- Remove the usage of macros- NODE_NAME, GET_ASCII_TO_U8, GET_IDX_FROM_DEV_NODE_NAME.
- Clean-up the return path by replacing "ret = -<err>; return ret;" with "return -<err>;"
- Clean-up the return path by replacing "ret = -<err>; goto exit;" with "return -<err>;"
- Removed goto statements from the entire driver, where there is no common code at function's exit.
- Fixes the check-patch erros reported with flag "--strict"
- Replaced devm_add_action, with devm_add_action_or_reset
- Removed the un-necesary and obvious code comments.
- Removed dev_probe_err at the exit of function se_if_probe().

4/5
- Clean-up the return path by replacing "ret = -<err>; return ret;" with "return -<err>;"
- Clean-up the return path by replacing "ret = -<err>; goto exit;" with "return -<err>;"
- Removed goto statements from the entire driver, where there is no common code at function's exit.
- fixes the check-patch erros reported with flag "--strict"
- removed the un-necesary and obvious code comments.
- variable received msg timeout to be different at boot-up & suspend/resume and send/recv ioctlis.

3/5
- compatible string is modified from "fsl,imx8ulp-se" to "fsl,imx8ulp-se-ele-hsm".
- updated the alias name.

2/5
- compatible string is modified from "fsl,imx8ulp-se" to "fsl,imx8ulp-se-ele-hsm".
- compatible string is modified from "fsl,imx93-se" to "fsl,imx93-se-ele-hsm".
- compatible string is modified from "fsl,imx95-se" to "fsl,imx95-se-ele-hsm".
- Mis-understood the +1 from Conor. Hence dropped the Reviewed-by tag.
- Collected Rob's R-b tag on v7 (https://lore.kernel.org/all/172589152997.4184616.5889493628960272898.robh at kernel.org/)

1/5
- No change

Reference:
- Link to v12: https://lore.kernel.org/r/20250120-imx-se-if-v12-0-c5ec9754570c at nxp.com

Changes in v12:

5/5
- increased the wait-timeout.

4/5
- rename flag "handle_susp_resm" to "imem_mgmt"
- moved the buffer allocation ot load_fw->imem.buf, to se_probe_if.
- setting imem state at initialization.

3/5
- No change

2/5
- No change

1/5
- No change

Reference:
- Link to v11: https://lore.kernel.org/r/20241220-imx-se-if-v11-0-0c7e65d7ae7b at nxp.com

Changes in v11:

5/5
- devname is constructed by concatinating get_se_if_name(se_if_id) & se_if_instance_id.
- ele_rcv_msg(), is updated to add the wait_interruptible_timeout for the non-NVM-Daemon message exchanges, such that in case of no response from FW,
  Linux donot hangs.
- added a new helper function get_se_if_name(), to return the secure-enclave interface owner's name string.
- added a new helper function get_se_soc_id(), to return the secure-enclave's SoC id.

4/5
- moved the se_if_node_info member "soc_register", to the struct "se_if_node_info_list"; as soc registration done once, not per interface.
- moved the se_if_node_info member "se_fetch_soc_info", to the struct "se_if_node_info_list"; as soc info fetching is done once, not per interface.
- Added two member variable se_if_id and se_if_instance_id to struct se_if_defines.
- removed the member "se_name" from struct "se_if_node_info". Rather, it will constructed by concatinating get_se_if_name(se_if_id) & se_if_instance_id.
- moved the static global variable "se_version", to the newly created structure "struct se_var_info".
- moved the member "struct se_fw_load_info load_fw" of "se_if_node_info_list", to the newly created structure "struct se_var_info".
- Replaced RUNTIME_PM_OPS with SET_SYSTEM_SLEEP_PM_OPS, in power-managment ops.

3/5
- No change

2/5
- No change

1/5
- No change

Reference:
- Link to v10: https://lore.kernel.org/r/20241104-imx-se-if-v10-0-bf06083cc97f at nxp.com

v10: firmware: imx: driver for NXP secure-enclave

Changes in v10:
5/5
- replaced the u8, u16, u32, u64, with __u8, __u16, __u32, __u64 in
  'include/uapi/linux/se_ioctl.h'.

4/5
- No change

3/5
- No change

2/5
- No change

1/5
- No change

Reference:
- Link to v9: https://lore.kernel.org/r/20241016-imx-se-if-v9-0-fd8fa0c04eab at nxp.com

Changes in v9:

4/5
- change se_if_remove function signature, required after rebase to v6.12-rc1.
- move the info->macros to a structure "struct se_if_defines if_defs".
- Removed "info" from "struct se_if_defines if_defs".
- Moved "mem_pool" from "struct se_if_defines if_defs" to "priv".
- Fetching "info" using container-of.

5/5
- Fetching "info" using container-of.
- Fixed issue reported by sparse.

Reference:
- Link to v8: https://lore.kernel.org/r/20241015-imx-se-if-v8-0-915438e267d3 at nxp.com

Changes in v8:

5/5
- Remove the check for SE_IF_CTX_OPENED.
- replaced dev_ctx->priv-dev, priv->dev, whereever possible.
- func "if_misc_deregister" moved before func "init_device_context".
- func "init_device_context" before func "se_ioctl_cmd_snd_rcv_rsp_handler".
- func "se_if_fops_write" and "se_if_fops_read", are moved after func "se_ioctl_get_mu_info".
- non static functions "se_dev_ctx_cpy_out_data, se_dev_ctx_shared_mem_cleanup & init_device_context" are moved static and local scope.
- Removed back & forth between the two structs "struct se_if_device_ctx *dev_ctx" and "struct se_shared_mem_mgmt_info *se_shared_mem_mgmt"
- removed the NULL check for bdesc.
- fops_open, is corrected for acquiring the fops_lock.
- Fops_close, mutex unlock is removed. Infact check for waiting_rsp_clbk_hdl.dev_ctx, is removed.
- sema_init(&dev_ctx->fops_lock, 1);, replaced with Mutex.
- structure member se_notify, is removed.

4/5
- removed initializing err to zero in func ele_fetch_soc_info(),
- replaced 'return 0', with 'goto exit', if the condition (!priv->mem_pool) is true.
- replaced "struct *dev" with "struct se_if_priv *priv", in base_message API(s) and others.
- Created a separate structure "struct se_if_defines" to maintain interface's fixed values like cmd_tag, rsp_tag, success_tag etc.
- removed the macros "WORD_SZ", "SOC_VER_MASK", "DEFAULT_IMX_SOC_VER", "RESERVED_DMA_POOL".
- Added handling for "ctrl+c", by postponing the interrupt, till the response to the "command in flight" is received.
- Removed the mutext lock "se_if_lock".
- furnction prototype for "se_save_imem_state" and "se_restore_imem_state", is changed to pass "imem" by reference.
- Added a new structure "struct se_fw_load_info", dedicated to contain FW loading relevant info. It is a member of struct info_list.
- split "imem_mgmt_file_in_rfs" into two "prim_fw_nm_in_rfs" and "seco_fw_nm_in_rfs", to be part of "struct se_fw_load_info".
- moved the function "se_load_firmware" prior to func "if_mbox_free_channel".
- function "se_load_firmware" is updated to use "request_firmware", instead of "request_firmware_no_wait".
- function "se_load_firmware" is updated to load "primary" fw image, if the imem_state is not BAD. Then load the "secondary FW" image.
- Added a new mutex_lock in the function "se_load_firmware", for ensuring FW loading done once, when there are multiple application are in play.
- instead of "wait_queue_head_t wq", used "sruct completion".
- add devm_add_action with action as se_if_probe_cleanup.

Reference:
- Link to v7: https://lore.kernel.org/r/20240904-imx-se-if-v7-0-5afd2ab74264 at nxp.com

Changes in v7:

5/5
- struct se_clbk_handle, is added with a member struct se_if_device_ctx *dev_ctx.
- func call to ele_miscdev_msg_rcv() & ele_miscdev_msg_send(), are removed.
- func se_ioctl_cmd_snd_rcv_rsp_handler(), is modified to remove the func call to ele_miscdev_msg_rcv() & ele_miscdev_msg_send()
- func se_ioctl_cmd_snd_rcv_rsp_handler is callig func ele_msg_send_rcv(), instead.
- Mutext "se_cmd_if_lock", handling is removed from this patch.
- func ele_miscdev_msg_send() is replaced with func ele_msg_send(), in fops_write.
- func ele_miscdev_msg_rcv() is replaced with func ele_msg_rcv(), in fops_read.
- fops_open is modified to create the new dev_ctx instance (using func init_device_context()), which is not registered as miscdev.
- Only one dev_ctx is registered as miscdev and its reference is stored in the struct se_if_priv, as priv_dev_ctx.
- Separate func cleanup_se_shared_mem() & func init_se_shared_mem(), for shared memory handling part of struct dev_ctx.
- Input param for func(s) ele_msg_rcv(), ele_msg_send() & ele_msg_send_rcv(), is replaced from struct se_if_priv to struct se_if_device_ctx.

4/5
- A new structure is defined name struct "se_clbk_handle", to contain members processed in mailbox call-back function.
- "struct se_if_priv" is modified to contain the two structures of "se_clbk_handle" - waiting_rsp_clbk_hdl & cmd_receiver_clbk_hdl.
- func ele_msg_rcv() is modified to take a new additional input reference param "struct se_clbk_handle *se_clbk_hdl".
- func ele_msg_send() is modified to take a new additional input tx_msg_sz.
- func ele_msg_send_rcv(), is modified to take 2 more inputs - tx_msg_sz & exp_rx_msg_sz.
- func se_val_rsp_hdr_n_status(), is modified to take input of rx_msg buffer, instead of header value, as input param.
- each caller of the func ele_msg_send_rcv(), is sending these two additional input params.
- func se_if_callback(), is modified to work on two structures of "se_clbk_handle" - waiting_rsp_clbk_hdl & cmd_receiver_clbk_hdl.
- Variable "max_dev_ctx", is removed from info & priv struture, as well its usage.
- New member variable "se_img_file_to_load", is added to structure "priv".
- Other member variables - rx_msg(ptr), rx_msg_sz, completion done & list of dev_ctxs, is removed from priv struture, along with their usage.
- func se_resume(), updated to wakeup the two "wq", part of "struct se_clbk_handle": priv->waiting_rsp_clbk_hdl & priv->cmd_receiver_clbk_hdl.

3/5
- Node name is changed from senclave-firmware at 0 to "secure-enclave"

2/5
- Node name is changed to "secure-enclave".

Reference:
- Link to v6: https://lore.kernel.org/r/20240722-imx-se-if-v6-0-ee26a87b824a at nxp.com

Changes in v6:

5/5
- replaced scope_gaurd with gaurd.

4/5
- replaced scope_gaurd with gaurd.
- remove reading the regs property from dtb.
- Added NULL check for priv data fetched from device, as a sanity check, for ele_base_msg apis)

3/5
- replace firmware with senclave-firmware.

2/5
- replace firmware with senclave-firmware.
- drop description for mbox
- Replaced "items:" with maxItems:1 for "memory-region"
- Replaced "items:" with maxItems:1 for "sram"
- remove regs property.
- remove "$nodename"

Reference:
- Link to v5: https://lore.kernel.org/r/20240712-imx-se-if-v5-0-66a79903a872 at nxp.com

Changes in v5:

2/5
- updated the description of mboxes
- updated the description & items for mbox-names.
- updated the description of memory-region
- move "additional properties: false" after allOf block.
- removed other example except one.

4/5
- Corrected the indentation in Kconfig.
- info members:mbox_tx_name & mbox_rx_name, are replaced with macros.

5/5
- Replaced "for  secure enclaves", with "for secure enclaves"
- Replaced "user space" with "userspace".
- End the line "[include]<linux/firmware/imx/ele_mu_ioctl.h>" with a period.

Reference:
- Link to v4: https://lore.kernel.org/r/20240705-imx-se-if-v4-0-52d000e18a1d at nxp.com

Changes in v4:

1/5
a. Removed - from EdgeLock Enclave.

b. Removed , after "Each of the above feature,"

c. replace "can exists" with "can exist".

d.
-messaging units(MU) per SE. Each co-existing 'se' can have one or multiple exclusive
-MU(s), dedicated to itself. None of the MU is shared between two SEs.
+messaging units(MU) per SE. Each co-existing SE can have one or multiple exclusive
+MUs, dedicated to itself. None of the MU is shared between two SEs.
 Communication of the MU is realized using the Linux mailbox driver.

e.
-All those SE interfaces 'se-if' that is/are dedicated to a particular SE, will be
-enumerated and provisioned under the very single 'SE' node.
+Although MU(s) is/are not shared between SE(s). But for SoC like i.MX95 which has
+multiple SE(s) like HSM, V2X-HSM, V2X-SHE; all the SE(s) and their interfaces 'se-if'
+that is/are dedicated to a particular SE will be enumerated and provisioned using the
+single compatible node("fsl,imx95-se").

f. Removed ",". Replaced for "Each 'se-if'," with "Each se-if'.

g. removed ","
-  This layer is responsible for ensuring the communication protocol, that is defined
+  This layer is responsible for ensuring the communication protocol that is defined

h. removed "-"
-  - FW can handle one command-message at a time.
+  - FW can handle one command message at a time.

i.
-  Using these multiple device contexts, that are getting multiplexed over a single MU,
-  user-space application(s) can call fops like write/read to send the command-message,
-  and read back the command-response-message to/from Firmware.
-  fops like read & write uses the above defined service layer API(s) to communicate with
+  Using these multiple device contexts that are getting multiplexed over a single MU,
+  userspace application(s) can call fops like write/read to send the command message,
+  and read back the command response message to/from Firmware.
+  fops like read & write use the above defined service layer API(s) to communicate with
   Firmware.

j. Uppercase for word "Linux".

2/5
a. Rephrased the description to remove list of phandles.

b. Moved required before allOf:
+required:
+  - compatible
+  - reg
+  - mboxes
+  - mbox-names
+
+additionalProperties: false
+
 allOf:

c. replaced not: required: with properties: <property-name>: false.
   # memory-region
-      not:
-        required:
-          - memory-region
+      properties:
+        memory-region: false

   # sram
-    else:
-      not:
-        required:
-          - sram

d. Reduced examples. keeping example of i.MX95.
e. node-name is changed to "firmware@<hex>"

3/5
- node name changed to "firmware@<hex>".

4/5
- used sizeof(*s_info)
- return early, rather than doing goto exit, in ele_get_info().
- Use upper_32_bits() and lower_32_bits()
- use rx_msg here instead of priv->rx_msg
- Moved the status check to validate_rsp_hdr. Rename the function to "se_val_rsp_hdr_n_status"
- typecasting removed header = (struct se_msg_hdr *) msg;
- Converted the API name with prefix imx_ele_* or imx_se_*, to ele_* and se_*, respectively.
- Removed the functions definition & declaration for: free_phybuf_mem_pool() & get_phybuf_mem_pool()
- removed the mbox_free_channel() calls from clean-up.
- Flag "priv->flags" is removed.
- Converted the int se_if_probe_cleanup() to void se_if_probe_cleanup().
- Replaced NULL initialization of structure members: priv->cmd_receiver_dev & priv->waiting_rsp_dev , with comments.
- Removed the function's declaration get_phy_buf_mem_pool1

5/5
Changes to Documentation/ABI/testing/se-cdev.
a. Removed "-" from "secure-enclave" and "file-descriptor".

b. Removed "-" from "shared-library"

c. Replaced "get" with "getting".

d. Added description for the new IOCTL "send command and receive command response"

e. Replaced "wakeup_intruptible" with "wait_event_interruptible"

f. Removed ";"

g. Removd "," from "mailbox_lock,"

h. Replaced "free" with "frees"

i. In mailbox callback function, checking the buffer size before
copying.

Reference:
- Link to v3: https://lore.kernel.org/r/20240617-imx-se-if-v3-0-a7d28dea5c4a at nxp.com

Changes in v3:
5/5:
- Initialize tx_msg with NULL.
- memdup_user() returns an error pointer, not NULL. correct it by adding check for err_ptr.
- new IOCTL is added to send & recieve the message.
- replaced the while loop till list is empty, with list_for_each_entry.
- replaced __list_del_entry, with list_del.
- Removed the dev_err message from copy to user.
- Removed the casting of void *.
- corrected the typcasting in copy to user.
- removed un-necessary goto statement.
- Removed dead code for clean-up of memory.
- Removed un-mapping of secured memory
- Passing se_if_priv structure to init_device_context.
- Updated the below check to replace io.length with round_up(io.length).
	if (shared_mem->size < shared_mem->pos|| io.length >= shared_mem->size - shared_mem->pos)
- Created a function to cleanup the list of shared memory buffers.
- Used list_for_each_entry_safe(). created a separate functions: se_dev_ctx_cpy_out_data() & se_dev_ctx_shared_mem_cleanup()

4/5
- Changed the compatible string to replace "-ele", to "-se".
- Declaration of imx_se_node_info, is done as const in the whole file
- Remove the unused macros from ele_base_msg.h
- Remove the function declaration get_phy_buf_mem_pool1, from the header file.
- Replace the use of dmam_alloc_coherent to dma_alloc_coherent
- Check for function pointer, before calling the fucntion pointer in imx_fetch_se_soc_info
- Removed the unused flag for SE_MU_IO_FLAGS_USE_SEC_MEM.
-  Removed the unused macros WORD_SZ
- instead of struct device *dev, struct se_if_priv *priv, is used as argument to the funtions:se_save_imem_state, se_restore_imem_state, imx_fetch_se_soc_info
- Removed ret from validate_rsp_hdr.
- changed the prefix of the funtion: plat_add_msg_crc and plat_fill_cmd_msg_hdr.
- indentation correction for info structures.
- remove the check for priv not null from se_if_probe_cleanup
- Removed the casting of void *.
- se_load_firmware function is corrected for not freeing the buffer when allocation fails.
- Checking if get_imx_se_node_info() can return NULL, in se_if_probe()
- imem.size has type u32. return value from se_save_imem_state() will be assigned to imem.size in case of success only.
- removed the flag un-setting in case of failure. priv->flags &= (~RESERVED_DMA_POOL);
- removed the function call for devm_of_platform_populate(dev);
- Checking for not-NULL,  before calling the funtion pointer se_fetch_soc_info.
- Removed the checking for reserved memory flag, before freeing up the reserved memory, in se_probe_if_cleanup.

3/5
- Changed the compatible string to replace "-ele", to "-se".

2/5
- to fix the warning error, replaced the "-ele" & "-v2x" in compatible string, to "-se".
- Added an example for ele at 0 for compatible string "fsl,imx95-se"

Reference
- Link to v2: https://lore.kernel.org/r/20240523-imx-se-if-v2-0-5a6fd189a539 at nxp.com

Changes in v2:

4/4
- Split this patch into two: 1. base driver & 2. Miscdev
- Initialize the return variable "err" as 0, before calling 'return err', in the file ele_common.c
- Fix the usage of un-iniitialized pointer variable, by initializing them with NULL, in ele_base_msg.c.
- Fix initializing the ret variable, to return the correct error code in case of issue.
- replaced dmam_alloc_coherent with dma_alloc_coherent.
- Replace the use of ELE_GET_INFO_READ_SZ, with sizeof(soc_info).
- Replaced -1 with -EPERM
- Removed the safety check on func-input param, in ele_get_info().
- fix the assigning data[1] with lower 32 address, rather than zero, for ele_fw_authenticate API.
- Correctly initializing the function's return error code, for file  ele_base_msg.c.
- replaced 'return' with 'goto'.
- Use length in bytes.
- Corrected the structure se_msg_hdr.
- Moved setting of rx_msg  to priv, into the function imx_ele_msg_send_rcv
- Will add lockdep_assert_held, to receive path, in v2.
- corrected the spacing at "ret  = validate_rsp_hdr"
- FIELD_GET() used for RES_STATUS
- Re-write the structure soc_info, matching the information provided in response to this api.
- The "|" goes to the end of the previous line.
- Moved the locking and unlocking of the command lock to the caller of the function.
- removed the safety check for device private data.
- Structure memory reference, used to read message header.
- In the interrupt call back function, remove assigning waiting_rsp_dev to NULL, in case of response message rcv from FW.
- do while removed.
- replaced BIT(1) for RESERVED_DMA_POOL, to BIT(0)
- The backslash is removed while assigning the file name with absolute path to structure variable.fw_name_in_rfs =.
- Update the 'if' condition by removing "idx < 0".
- mbox_request_channel_byname() uses a "char" for the name not a u8. Corrected.
- devm managed resources, are not cleaned now, in function se_probe_if_cleanup
- Used dev_err_probe().
- Used %pe to print error string.
- remove "__maybe_unused" for "struct platform_device *enum_plat_dev __maybe_unused;"
- used FIELD_GET(), for  RES_STATUS. Removed the use of MSG_TAG, MSG_COMMAND, MSG_SIZE, MSG_VER.
- Depricated the used of member of struct se_if_priv, bool no_dev_ctx_used;
- Moved the text explaing the synchronization logic via mutexes, from patch 1/4 to se_ctrl.h.
- removed the type casting of info_list = (struct imx_se_node_info_list *) device_get_match_data(dev->parent);
- Used static variable priv->soc_rev in the se_ctrl.c, replaced the following condition: if (info_list->soc_rev) to if (priv->soc_rev) for checking if this flow is already executed or not.
- imx_fetch_soc_info will return failure if the get_info function fails.
- Removed devm_free from imx_fetch_soc_info too.

3/3
- Made changes to move all the properties to parent node, without any child node.

2/4
- Use Hex pattern string.
- Move the properties to parent node, with no child node.
- Add i.MX95-ele to compatible nodes to fix the warning "/example-2/v2x: failed to match any schema with compatible: ['fsl,imx95-v2x']"

1/1
- Corrected the spelling from creats to creates.
- drop the braces around the plural 's' for interfaces
- written se in upper case SE.
- Replace "multiple message(s)" with messages.
- Removed too much details about locks.

Testing
- make CHECK_DTBS=y freescale/imx8ulp-evk.dtb;
- make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j8  dt_binding_check DT_SCHEMA_FILES=fsl,imx-se.yaml
- make C=1 CHECK=scripts/coccicheck drivers/firmware/imx/*.* W=1 > r.txt
- ./scripts/checkpatch.pl --git <>..HEAD
- Tested the Image and .dtb, on the i.MX8ULP.

Reference
- Link to v1: https://lore.kernel.org/r/20240510-imx-se-if-v1-0-27c5a674916d at nxp.com

---
Pankaj Gupta (7):
      Documentation/firmware: add imx/se to other_interfaces
      dt-bindings: arm: fsl: add imx-se-fw binding doc
      firmware: imx: add driver for NXP EdgeLock Enclave
      firmware: imx: device context dedicated to priv
      firmware: drivers: imx: adds miscdev
      arm64: dts: imx8ulp: add secure enclave node
      arm64: dts: imx8ulp-evk: add reserved memory property

 Documentation/ABI/testing/se-cdev                  |   43 +
 .../devicetree/bindings/firmware/fsl,imx-se.yaml   |   91 ++
 .../driver-api/firmware/other_interfaces.rst       |  131 +++
 arch/arm64/boot/dts/freescale/imx8ulp-evk.dts      |   12 +-
 arch/arm64/boot/dts/freescale/imx8ulp.dtsi         |   11 +-
 drivers/firmware/imx/Kconfig                       |   13 +
 drivers/firmware/imx/Makefile                      |    2 +
 drivers/firmware/imx/ele_base_msg.c                |  297 +++++
 drivers/firmware/imx/ele_base_msg.h                |  115 ++
 drivers/firmware/imx/ele_common.c                  |  371 +++++++
 drivers/firmware/imx/ele_common.h                  |   51 +
 drivers/firmware/imx/se_ctrl.c                     | 1153 ++++++++++++++++++++
 drivers/firmware/imx/se_ctrl.h                     |  128 +++
 include/linux/firmware/imx/se_api.h                |   14 +
 include/uapi/linux/se_ioctl.h                      |   97 ++
 15 files changed, 2526 insertions(+), 3 deletions(-)
---
base-commit: 4a26e7032d7d57c998598c08a034872d6f0d3945
change-id: 20240507-imx-se-if-a40055093dc6

Best regards,
-- 
Pankaj Gupta <pankaj.gupta at nxp.com>



From pankaj.gupta at nxp.com  Tue Dec  2 22:48:06 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Wed, 03 Dec 2025 12:18:06 +0530
Subject: [PATCH v20 1/7] Documentation/firmware: add imx/se to
 other_interfaces
In-Reply-To: <20251203-imx-se-if-v20-0-a04a25c4255f@nxp.com>
References: <20251203-imx-se-if-v20-0-a04a25c4255f@nxp.com>
Message-ID: <20251203-imx-se-if-v20-1-a04a25c4255f@nxp.com>

Documents i.MX SoC's Service layer and C_DEV driver for selected SoC(s)
that contains the NXP hardware IP(s) for Secure Enclaves(se) like:
- NXP EdgeLock Enclave on i.MX93 & i.MX8ULP

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
---
 .../driver-api/firmware/other_interfaces.rst       | 131 +++++++++++++++++++++
 1 file changed, 131 insertions(+)

diff --git a/Documentation/driver-api/firmware/other_interfaces.rst b/Documentation/driver-api/firmware/other_interfaces.rst
index 06ac89adaafb..2a7d7100fdd4 100644
--- a/Documentation/driver-api/firmware/other_interfaces.rst
+++ b/Documentation/driver-api/firmware/other_interfaces.rst
@@ -49,3 +49,134 @@ of the requests on to a secure monitor (EL3).
 
 .. kernel-doc:: drivers/firmware/stratix10-svc.c
    :export:
+
+NXP Secure Enclave Firmware Interface
+=====================================
+
+Introduction
+------------
+The NXP's i.MX HW IP like EdgeLock Enclave, V2X etc., creates an embedded secure
+enclave within the SoC boundary to enable features like
+ - Hardware Security Module (HSM)
+ - Security Hardware Extension (SHE)
+ - Vehicular to Anything (V2X)
+
+Each of the above feature is enabled through dedicated NXP H/W IP on the SoC.
+On a single SoC, multiple hardware IP (or can say more than one secure enclave)
+can exist.
+
+NXP SoCs enabled with the such secure enclaves(SEs) IPs are:
+i.MX93, i.MX8ULP
+
+To communicate with one or more co-existing SE(s) on SoC, there is/are dedicated
+messaging units(MU) per SE. Each co-existing SE can have one or multiple exclusive
+MUs, dedicated to itself. None of the MU is shared between two SEs. Communication
+of the MU is realized using the mailbox driver. Each secure enclave can cater to
+multiple clients by virtue of these exclusive MUs. Also, they can distinguish
+transactions originating from these clients based on the MU used and core security
+state. The communication between the clients and secure enclaves is in form of
+command/response mechanism. Each client could expose specific set of secure enclave
+features to the higher layers, based on the commands supported by that client. For
+example, the secure enclave could simultaneously support an OPTEE TA and Linux
+middleware as clients. Each of these clients can expose specific set of secure
+enclave features based on the command set supported by them.
+
+NXP Secure Enclave(SE) Interface
+--------------------------------
+Although MU(s) is/are not shared between SE(s). But for SoC like i.MX95 which has
+multiple SE(s) like HSM, V2X-HSM, V2X-SHE; all the SE(s) and their interfaces 'se-if'
+that is/are dedicated to a particular SE will be enumerated and provisioned using the
+single compatible node("fsl,imx95-se").
+
+Each 'se-if' comprise of twp layers:
+- (C_DEV Layer) User-Space software-access interface.
+- (Service Layer) OS-level software-access interface.
+
+::
+   +--------------------------------------------+
+   |            Character Device(C_DEV)         |
+   |                                            |
+   |   +---------+ +---------+     +---------+  |
+   |   | misc #1 | | misc #2 | ... | misc #n |  |
+   |   |  dev    | |  dev    |     | dev     |  |
+   |   +---------+ +---------+     +---------+  |
+   |        +-------------------------+         |
+   |        | Misc. Dev Synchr. Logic |         |
+   |        +-------------------------+         |
+   |                                            |
+   +--------------------------------------------+
+
+   +--------------------------------------------+
+   |               Service Layer                |
+   |                                            |
+   |      +-----------------------------+       |
+   |      | Message Serialization Logic |       |
+   |      +-----------------------------+       |
+   |          +---------------+                 |
+   |          |  imx-mailbox  |                 |
+   |          |   mailbox.c   |                 |
+   |          +---------------+                 |
+   |                                            |
+   +--------------------------------------------+
+
+- service layer:
+  This layer is responsible for ensuring the communication protocol that is defined
+  for communication with firmware.
+
+  FW Communication protocol ensures two things:
+  - Serializing the messages to be sent over an MU.
+
+  - FW can handle one command message at a time.
+
+- c_dev:
+  This layer offers character device contexts, created as '/dev/<se>_mux_chx'.
+  Using these multiple device contexts that are getting multiplexed over a single MU,
+  userspace application(s) can call fops like write/read to send the command message,
+  and read back the command response message to/from Firmware.
+  fops like read & write use the above defined service layer API(s) to communicate with
+  Firmware.
+
+  Misc-device(/dev/<se>_mux_chn) synchronization protocol:
+::
+
+                                Non-Secure               +   Secure
+                                                         |
+                                                         |
+                  +---------+      +-------------+       |
+                  | se_fw.c +<---->+imx-mailbox.c|       |
+                  |         |      |  mailbox.c  +<-->+------+    +------+
+                  +---+-----+      +-------------+    | MU X +<-->+ ELE |
+                      |                               +------+    +------+
+                      +----------------+                 |
+                      |                |                 |
+                      v                v                 |
+                  logical           logical              |
+                  receiver          waiter               |
+                     +                 +                 |
+                     |                 |                 |
+                     |                 |                 |
+                     |            +----+------+          |
+                     |            |           |          |
+                     |            |           |          |
+              device_ctx     device_ctx     device_ctx   |
+                                                         |
+                User 0        User 1       User Y        |
+                +------+      +------+     +------+      |
+                |misc.c|      |misc.c|     |misc.c|      |
+ kernel space   +------+      +------+     +------+      |
+                                                         |
+ +------------------------------------------------------ |
+                    |             |           |          |
+ userspace     /dev/ele_muXch0    |           |          |
+                          /dev/ele_muXch1     |          |
+                                        /dev/ele_muXchY  |
+                                                         |
+
+When a user sends a command to the firmware, it registers its device_ctx
+as waiter of a response from firmware.
+
+Enclave's Firmware owns the storage management, over Linux filesystem.
+For this c_dev provisions a dedicated slave device called "receiver".
+
+.. kernel-doc:: drivers/firmware/imx/se_fw.c
+   :export:

-- 
2.43.0



From pankaj.gupta at nxp.com  Tue Dec  2 22:48:07 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Wed, 03 Dec 2025 12:18:07 +0530
Subject: [PATCH v20 2/7] dt-bindings: arm: fsl: add imx-se-fw binding doc
In-Reply-To: <20251203-imx-se-if-v20-0-a04a25c4255f@nxp.com>
References: <20251203-imx-se-if-v20-0-a04a25c4255f@nxp.com>
Message-ID: <20251203-imx-se-if-v20-2-a04a25c4255f@nxp.com>

The NXP security hardware IP(s) like: i.MX EdgeLock Enclave, V2X etc.,
creates an embedded secure enclave within the SoC boundary to enable
features like:
- HSM
- SHE
- V2X

Secure-Enclave(s) communication interface are typically via message
unit, i.e., based on mailbox linux kernel driver. This driver enables
communication ensuring well defined message sequence protocol between
Application Core and enclave's firmware.

Driver configures multiple misc-device on the MU, for multiple
user-space applications, to be able to communicate over single MU.

It exists on some i.MX processors. e.g. i.MX8ULP, i.MX93 etc.

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
---
 .../devicetree/bindings/firmware/fsl,imx-se.yaml   | 91 ++++++++++++++++++++++
 1 file changed, 91 insertions(+)

diff --git a/Documentation/devicetree/bindings/firmware/fsl,imx-se.yaml b/Documentation/devicetree/bindings/firmware/fsl,imx-se.yaml
new file mode 100644
index 000000000000..fa81adbf9b80
--- /dev/null
+++ b/Documentation/devicetree/bindings/firmware/fsl,imx-se.yaml
@@ -0,0 +1,91 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/firmware/fsl,imx-se.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP i.MX HW Secure Enclave(s) EdgeLock Enclave
+
+maintainers:
+  - Pankaj Gupta <pankaj.gupta at nxp.com>
+
+description: |
+  NXP's SoC may contain one or multiple embedded secure-enclave HW
+  IP(s) like i.MX EdgeLock Enclave, V2X etc. These NXP's HW IP(s)
+  enables features like
+    - Hardware Security Module (HSM),
+    - Security Hardware Extension (SHE), and
+    - Vehicular to Anything (V2X)
+
+  Communication interface to the secure-enclaves(se) is based on the
+  messaging unit(s).
+
+properties:
+  compatible:
+    enum:
+      - fsl,imx8ulp-se-ele-hsm
+      - fsl,imx93-se-ele-hsm
+      - fsl,imx95-se-ele-hsm
+
+  mboxes:
+    items:
+      - description: mailbox phandle to send message to se firmware
+      - description: mailbox phandle to receive message from se firmware
+
+  mbox-names:
+    items:
+      - const: tx
+      - const: rx
+
+  memory-region:
+    maxItems: 1
+
+  sram:
+    maxItems: 1
+
+required:
+  - compatible
+  - mboxes
+  - mbox-names
+
+allOf:
+  # memory-region
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - fsl,imx8ulp-se-ele-hsm
+              - fsl,imx93-se-ele-hsm
+    then:
+      required:
+        - memory-region
+    else:
+      properties:
+        memory-region: false
+
+  # sram
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - fsl,imx8ulp-se-ele-hsm
+    then:
+      required:
+        - sram
+
+    else:
+      properties:
+        sram: false
+
+additionalProperties: false
+
+examples:
+  - |
+    secure-enclave {
+      compatible = "fsl,imx95-se-ele-hsm";
+      mboxes = <&ele_mu0 0 0>, <&ele_mu0 1 0>;
+      mbox-names = "tx", "rx";
+    };
+...

-- 
2.43.0



From pankaj.gupta at nxp.com  Tue Dec  2 22:48:08 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Wed, 03 Dec 2025 12:18:08 +0530
Subject: [PATCH v20 3/7] firmware: imx: add driver for NXP EdgeLock Enclave
In-Reply-To: <20251203-imx-se-if-v20-0-a04a25c4255f@nxp.com>
References: <20251203-imx-se-if-v20-0-a04a25c4255f@nxp.com>
Message-ID: <20251203-imx-se-if-v20-3-a04a25c4255f@nxp.com>

Add driver for enabling MU based communication interface to secure-enclave.

NXP hardware IP(s) for secure-enclaves like Edgelock Enclave(ELE), are
embedded in the SoC to support the features like HSM, SHE & V2X, using
message based communication interface.

The secure enclave FW communicates with Linux over single or multiple
dedicated messaging unit(MU) based interface(s).
Exists on i.MX SoC(s) like i.MX8ULP, i.MX93, i.MX95 etc.

For i.MX9x SoC(s) there is at least one dedicated ELE MU(s) for each
world - Linux(one or more) and OPTEE-OS (one or more).

Other dependent kernel drivers will be:
- NVMEM: that supports non-volatile devices like EFUSES,
         managed by NXP's secure-enclave.

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/firmware/imx/Kconfig        |  13 ++
 drivers/firmware/imx/Makefile       |   2 +
 drivers/firmware/imx/ele_base_msg.c | 269 ++++++++++++++++++++++++
 drivers/firmware/imx/ele_base_msg.h |  95 +++++++++
 drivers/firmware/imx/ele_common.c   | 333 ++++++++++++++++++++++++++++++
 drivers/firmware/imx/ele_common.h   |  45 ++++
 drivers/firmware/imx/se_ctrl.c      | 401 ++++++++++++++++++++++++++++++++++++
 drivers/firmware/imx/se_ctrl.h      |  86 ++++++++
 include/linux/firmware/imx/se_api.h |  14 ++
 9 files changed, 1258 insertions(+)

diff --git a/drivers/firmware/imx/Kconfig b/drivers/firmware/imx/Kconfig
index 127ad752acf8..5fe96299b704 100644
--- a/drivers/firmware/imx/Kconfig
+++ b/drivers/firmware/imx/Kconfig
@@ -55,3 +55,16 @@ config IMX_SCMI_MISC_DRV
 	  core that could provide misc functions such as board control.
 
 	  This driver can also be built as a module.
+
+config IMX_SEC_ENCLAVE
+	tristate "i.MX Embedded Secure Enclave - EdgeLock Enclave Firmware driver."
+	depends on IMX_MBOX && ARCH_MXC && ARM64
+	select FW_LOADER
+	default m if ARCH_MXC
+
+	help
+	  Exposes APIs supported by the iMX Secure Enclave HW IP called:
+	  - EdgeLock Enclave Firmware (for i.MX8ULP, i.MX93),
+	    like base, HSM, V2X & SHE using the SAB protocol via the shared Messaging
+	    Unit. This driver exposes these interfaces via a set of file descriptors
+	    allowing to configure shared memory, send and receive messages.
diff --git a/drivers/firmware/imx/Makefile b/drivers/firmware/imx/Makefile
index 3bbaffa6e347..4412b15846b1 100644
--- a/drivers/firmware/imx/Makefile
+++ b/drivers/firmware/imx/Makefile
@@ -4,3 +4,5 @@ obj-$(CONFIG_IMX_SCU)		+= imx-scu.o misc.o imx-scu-irq.o rm.o imx-scu-soc.o
 obj-${CONFIG_IMX_SCMI_CPU_DRV}	+= sm-cpu.o
 obj-${CONFIG_IMX_SCMI_MISC_DRV}	+= sm-misc.o
 obj-${CONFIG_IMX_SCMI_LMM_DRV}	+= sm-lmm.o
+sec_enclave-objs		= se_ctrl.o ele_common.o ele_base_msg.o
+obj-${CONFIG_IMX_SEC_ENCLAVE}	+= sec_enclave.o
diff --git a/drivers/firmware/imx/ele_base_msg.c b/drivers/firmware/imx/ele_base_msg.c
new file mode 100644
index 000000000000..a070acbd895c
--- /dev/null
+++ b/drivers/firmware/imx/ele_base_msg.c
@@ -0,0 +1,269 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 NXP
+ */
+
+#include <linux/types.h>
+
+#include <linux/completion.h>
+#include <linux/dma-mapping.h>
+#include <linux/genalloc.h>
+
+#include "ele_base_msg.h"
+#include "ele_common.h"
+
+#define FW_DBG_DUMP_FIXED_STR		"ELE"
+
+int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info)
+{
+	struct se_api_msg *tx_msg __free(kfree) = NULL;
+	struct se_api_msg *rx_msg __free(kfree) = NULL;
+	dma_addr_t get_info_addr = 0;
+	u32 *get_info_data = NULL;
+	int ret = 0;
+
+	if (!priv)
+		return -EINVAL;
+
+	memset(s_info, 0x0, sizeof(*s_info));
+
+	tx_msg = kzalloc(ELE_GET_INFO_REQ_MSG_SZ, GFP_KERNEL);
+	if (!tx_msg)
+		return -ENOMEM;
+
+	rx_msg = kzalloc(ELE_GET_INFO_RSP_MSG_SZ, GFP_KERNEL);
+	if (!rx_msg)
+		return -ENOMEM;
+
+	if (priv->mem_pool)
+		get_info_data = gen_pool_dma_alloc(priv->mem_pool,
+						   ELE_GET_INFO_BUFF_SZ,
+						   &get_info_addr);
+	else
+		get_info_data = dma_alloc_coherent(priv->dev,
+						   ELE_GET_INFO_BUFF_SZ,
+						   &get_info_addr,
+						   GFP_KERNEL);
+	if (!get_info_data) {
+		dev_dbg(priv->dev,
+			"%s: Failed to allocate get_info_addr.", __func__);
+		return -ENOMEM;
+	}
+
+	ret = se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
+				  ELE_GET_INFO_REQ, ELE_GET_INFO_REQ_MSG_SZ,
+				  true);
+	if (ret)
+		goto exit;
+
+	tx_msg->data[0] = upper_32_bits(get_info_addr);
+	tx_msg->data[1] = lower_32_bits(get_info_addr);
+	tx_msg->data[2] = sizeof(*s_info);
+	ret = ele_msg_send_rcv(priv, tx_msg, ELE_GET_INFO_REQ_MSG_SZ, rx_msg,
+			       ELE_GET_INFO_RSP_MSG_SZ);
+	if (ret < 0)
+		goto exit;
+
+	ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_GET_INFO_REQ,
+				      ELE_GET_INFO_RSP_MSG_SZ, true);
+
+	memcpy(s_info, get_info_data, sizeof(*s_info));
+
+exit:
+	if (priv->mem_pool)
+		gen_pool_free(priv->mem_pool, (u64)get_info_data,
+			      ELE_GET_INFO_BUFF_SZ);
+	else
+		dma_free_coherent(priv->dev, ELE_GET_INFO_BUFF_SZ,
+				  get_info_data, get_info_addr);
+
+	return ret;
+}
+
+int ele_fetch_soc_info(struct se_if_priv *priv, void *data)
+{
+	return ele_get_info(priv, data);
+}
+
+int ele_ping(struct se_if_priv *priv)
+{
+	struct se_api_msg *tx_msg __free(kfree) = NULL;
+	struct se_api_msg *rx_msg __free(kfree) = NULL;
+	int ret = 0;
+
+	if (!priv)
+		return -EINVAL;
+
+	tx_msg = kzalloc(ELE_PING_REQ_SZ, GFP_KERNEL);
+	if (!tx_msg)
+		return -ENOMEM;
+
+	rx_msg = kzalloc(ELE_PING_RSP_SZ, GFP_KERNEL);
+	if (!rx_msg)
+		return -ENOMEM;
+
+	ret = se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
+				  ELE_PING_REQ, ELE_PING_REQ_SZ, true);
+	if (ret) {
+		dev_err(priv->dev, "Error: se_fill_cmd_msg_hdr failed.");
+		return ret;
+	}
+
+	ret = ele_msg_send_rcv(priv, tx_msg, ELE_PING_REQ_SZ, rx_msg,
+			       ELE_PING_RSP_SZ);
+	if (ret < 0)
+		return ret;
+
+	ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_PING_REQ,
+				      ELE_PING_RSP_SZ, true);
+
+	return ret;
+}
+
+int ele_service_swap(struct se_if_priv *priv,
+		     phys_addr_t addr,
+		     u32 addr_size, u16 flag)
+{
+	struct se_api_msg *tx_msg __free(kfree) = NULL;
+	struct se_api_msg *rx_msg __free(kfree) = NULL;
+	int ret = 0;
+
+	if (!priv)
+		return -EINVAL;
+
+	tx_msg = kzalloc(ELE_SERVICE_SWAP_REQ_MSG_SZ, GFP_KERNEL);
+	if (!tx_msg)
+		return -ENOMEM;
+
+	rx_msg = kzalloc(ELE_SERVICE_SWAP_RSP_MSG_SZ, GFP_KERNEL);
+	if (!rx_msg)
+		return -ENOMEM;
+
+	ret = se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
+				  ELE_SERVICE_SWAP_REQ,
+				  ELE_SERVICE_SWAP_REQ_MSG_SZ, true);
+	if (ret)
+		return ret;
+
+	tx_msg->data[0] = flag;
+	tx_msg->data[1] = addr_size;
+	tx_msg->data[2] = ELE_NONE_VAL;
+	tx_msg->data[3] = lower_32_bits(addr);
+	tx_msg->data[4] = se_get_msg_chksum((u32 *)&tx_msg[0],
+					    ELE_SERVICE_SWAP_REQ_MSG_SZ);
+	if (!tx_msg->data[4])
+		return -EINVAL;
+
+	ret = ele_msg_send_rcv(priv, tx_msg, ELE_SERVICE_SWAP_REQ_MSG_SZ,
+			       rx_msg, ELE_SERVICE_SWAP_RSP_MSG_SZ);
+	if (ret < 0)
+		return ret;
+
+	ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_SERVICE_SWAP_REQ,
+				      ELE_SERVICE_SWAP_RSP_MSG_SZ, true);
+	if (ret)
+		return ret;
+
+	if (flag == ELE_IMEM_EXPORT)
+		ret = rx_msg->data[1];
+	else
+		ret = 0;
+
+	return ret;
+}
+
+int ele_fw_authenticate(struct se_if_priv *priv, phys_addr_t contnr_addr,
+			phys_addr_t img_addr)
+{
+	struct se_api_msg *tx_msg __free(kfree) = NULL;
+	struct se_api_msg *rx_msg __free(kfree) = NULL;
+	int ret = 0;
+
+	if (!priv)
+		return -EINVAL;
+
+	tx_msg = kzalloc(ELE_FW_AUTH_REQ_SZ, GFP_KERNEL);
+	if (!tx_msg)
+		return -ENOMEM;
+
+	rx_msg = kzalloc(ELE_FW_AUTH_RSP_MSG_SZ, GFP_KERNEL);
+	if (!rx_msg)
+		return -ENOMEM;
+
+	ret = se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
+				  ELE_FW_AUTH_REQ, ELE_FW_AUTH_REQ_SZ, true);
+	if (ret)
+		return ret;
+
+	tx_msg->data[0] = lower_32_bits(contnr_addr);
+	tx_msg->data[1] = upper_32_bits(contnr_addr);
+	tx_msg->data[2] = img_addr;
+
+	ret = ele_msg_send_rcv(priv, tx_msg, ELE_FW_AUTH_REQ_SZ, rx_msg,
+			       ELE_FW_AUTH_RSP_MSG_SZ);
+	if (ret < 0)
+		return ret;
+
+	ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_FW_AUTH_REQ,
+				      ELE_FW_AUTH_RSP_MSG_SZ, true);
+	return ret;
+}
+
+int ele_debug_dump(struct se_if_priv *priv)
+{
+	struct se_api_msg *tx_msg __free(kfree) = NULL;
+	struct se_api_msg *rx_msg __free(kfree) = NULL;
+	bool keep_logging;
+	int msg_ex_cnt;
+	int ret = 0;
+	int i;
+
+	if (!priv)
+		return -EINVAL;
+
+	tx_msg = kzalloc(ELE_DEBUG_DUMP_REQ_SZ, GFP_KERNEL);
+	if (!tx_msg)
+		return -ENOMEM;
+
+	rx_msg = kzalloc(ELE_DEBUG_DUMP_RSP_SZ, GFP_KERNEL);
+	if (!rx_msg)
+		return -ENOMEM;
+
+	ret = se_fill_cmd_msg_hdr(priv, &tx_msg->header, ELE_DEBUG_DUMP_REQ,
+				  ELE_DEBUG_DUMP_REQ_SZ, true);
+	if (ret)
+		return ret;
+
+	msg_ex_cnt = 0;
+	do {
+		memset(rx_msg, 0x0, ELE_DEBUG_DUMP_RSP_SZ);
+
+		ret = ele_msg_send_rcv(priv, tx_msg, ELE_DEBUG_DUMP_REQ_SZ,
+				       rx_msg, ELE_DEBUG_DUMP_RSP_SZ);
+		if (ret < 0)
+			return ret;
+
+		ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_DEBUG_DUMP_REQ,
+					      ELE_DEBUG_DUMP_RSP_SZ, true);
+		if (ret) {
+			dev_err(priv->dev, "Dump_Debug_Buffer Error: %x.", ret);
+			break;
+		}
+		keep_logging = (rx_msg->header.size >= (ELE_DEBUG_DUMP_RSP_SZ >> 2) &&
+				msg_ex_cnt < ELE_MAX_DBG_DMP_PKT);
+
+		rx_msg->header.size -= 2;
+
+		if (rx_msg->header.size > 4)
+			rx_msg->header.size--;
+
+		for (i = 0; i < rx_msg->header.size; i += 2)
+			dev_info(priv->dev, "%s%02x_%02x: 0x%08x 0x%08x",
+				 FW_DBG_DUMP_FIXED_STR,	msg_ex_cnt, i,
+				 rx_msg->data[i + 1], rx_msg->data[i + 2]);
+
+		msg_ex_cnt++;
+	} while (keep_logging);
+
+	return ret;
+}
diff --git a/drivers/firmware/imx/ele_base_msg.h b/drivers/firmware/imx/ele_base_msg.h
new file mode 100644
index 000000000000..8e5b015e99a2
--- /dev/null
+++ b/drivers/firmware/imx/ele_base_msg.h
@@ -0,0 +1,95 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2025 NXP
+ *
+ * Header file for the EdgeLock Enclave Base API(s).
+ */
+
+#ifndef ELE_BASE_MSG_H
+#define ELE_BASE_MSG_H
+
+#include <linux/device.h>
+#include <linux/types.h>
+
+#include "se_ctrl.h"
+
+#define ELE_NONE_VAL			0x0
+
+#define ELE_GET_INFO_REQ		0xda
+#define ELE_GET_INFO_REQ_MSG_SZ		0x10
+#define ELE_GET_INFO_RSP_MSG_SZ		0x08
+
+#define MAX_UID_SIZE                     (16)
+#define DEV_GETINFO_ROM_PATCH_SHA_SZ     (32)
+#define DEV_GETINFO_FW_SHA_SZ            (32)
+#define DEV_GETINFO_OEM_SRKH_SZ          (64)
+#define DEV_GETINFO_MIN_VER_MASK	0xff
+#define DEV_GETINFO_MAJ_VER_MASK	0xff00
+#define ELE_DEV_INFO_EXTRA_SZ		0x60
+
+struct dev_info {
+	u8  cmd;
+	u8  ver;
+	u16 length;
+	u16 soc_id;
+	u16 soc_rev;
+	u16 lmda_val;
+	u8  ssm_state;
+	u8  dev_atts_api_ver;
+	u8  uid[MAX_UID_SIZE];
+	u8  sha_rom_patch[DEV_GETINFO_ROM_PATCH_SHA_SZ];
+	u8  sha_fw[DEV_GETINFO_FW_SHA_SZ];
+};
+
+struct dev_addn_info {
+	u8  oem_srkh[DEV_GETINFO_OEM_SRKH_SZ];
+	u8  trng_state;
+	u8  csal_state;
+	u8  imem_state;
+	u8  reserved2;
+};
+
+struct ele_dev_info {
+	struct dev_info d_info;
+	struct dev_addn_info d_addn_info;
+};
+
+#define ELE_GET_INFO_BUFF_SZ		(sizeof(struct ele_dev_info) \
+						+ ELE_DEV_INFO_EXTRA_SZ)
+
+#define GET_SERIAL_NUM_FROM_UID(x, uid_word_sz) \
+	(((u64)(((u32 *)(x))[(uid_word_sz) - 1]) << 32) | ((u32 *)(x))[0])
+
+#define ELE_MAX_DBG_DMP_PKT		50
+#define ELE_DEBUG_DUMP_REQ		0x21
+#define ELE_DEBUG_DUMP_REQ_SZ		0x4
+#define ELE_DEBUG_DUMP_RSP_SZ		0x5c
+
+#define ELE_PING_REQ			0x01
+#define ELE_PING_REQ_SZ			0x04
+#define ELE_PING_RSP_SZ			0x08
+
+#define ELE_SERVICE_SWAP_REQ		0xdf
+#define ELE_SERVICE_SWAP_REQ_MSG_SZ	0x18
+#define ELE_SERVICE_SWAP_RSP_MSG_SZ	0x0c
+#define ELE_IMEM_SIZE			0x10000
+#define ELE_IMEM_STATE_OK		0xca
+#define ELE_IMEM_STATE_BAD		0xfe
+#define ELE_IMEM_STATE_WORD		0x27
+#define ELE_IMEM_STATE_MASK		0x00ff0000
+#define ELE_IMEM_EXPORT			0x1
+#define ELE_IMEM_IMPORT			0x2
+
+#define ELE_FW_AUTH_REQ			0x02
+#define ELE_FW_AUTH_REQ_SZ		0x10
+#define ELE_FW_AUTH_RSP_MSG_SZ		0x08
+
+int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info);
+int ele_fetch_soc_info(struct se_if_priv *priv, void *data);
+int ele_ping(struct se_if_priv *priv);
+int ele_service_swap(struct se_if_priv *priv, phys_addr_t addr,
+		     u32 addr_size, u16 flag);
+int ele_fw_authenticate(struct se_if_priv *priv, phys_addr_t contnr_addr,
+			phys_addr_t img_addr);
+int ele_debug_dump(struct se_if_priv *priv);
+#endif
diff --git a/drivers/firmware/imx/ele_common.c b/drivers/firmware/imx/ele_common.c
new file mode 100644
index 000000000000..748eb09474d7
--- /dev/null
+++ b/drivers/firmware/imx/ele_common.c
@@ -0,0 +1,333 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 NXP
+ */
+
+#include "ele_base_msg.h"
+#include "ele_common.h"
+
+/*
+ * se_get_msg_chksum() - to calculate checksum word by word.
+ *
+ * @msg : reference to the input msg-data.
+ * @msg_len : reference to the input msg-data length in bytes.
+ *            Includes extra 4 bytes (or 1 words) chksum.
+ *
+ * This function returns the checksum calculated by ORing word by word.
+ *
+ * Return:
+ *  0: if the input length is not 4 byte aligned, or num of words < 5.
+ *  chksum: calculated word by word.
+ */
+u32 se_get_msg_chksum(u32 *msg, u32 msg_len)
+{
+	u32 nb_words = msg_len / (u32)sizeof(u32);
+	u32 chksum = 0;
+	u32 i;
+
+	if (nb_words < 5)
+		return chksum;
+
+	if (msg_len % SE_MSG_WORD_SZ) {
+		pr_err("Msg-len is not 4-byte aligned.");
+		return chksum;
+	}
+
+	/* nb_words include one checksum word, so skip it. */
+	nb_words--;
+
+	for (i = 0; i < nb_words; i++)
+		chksum ^= *(msg + i);
+
+	return chksum;
+}
+
+int ele_msg_rcv(struct se_if_priv *priv, struct se_clbk_handle *se_clbk_hdl)
+{
+	unsigned long timeout;
+	int ret;
+
+	do {
+		timeout = MAX_SCHEDULE_TIMEOUT;
+
+		ret = wait_for_completion_interruptible_timeout(&se_clbk_hdl->done, timeout);
+		if (ret == -ERESTARTSYS) {
+			if (priv->waiting_rsp_clbk_hdl.rx_msg) {
+				priv->waiting_rsp_clbk_hdl.signal_rcvd = true;
+				continue;
+			}
+			ret = -EINTR;
+			break;
+		}
+		ret = se_clbk_hdl->rx_msg_sz;
+		break;
+	} while (ret < 0);
+
+	return ret;
+}
+
+int ele_msg_send(struct se_if_priv *priv,
+		 void *tx_msg,
+		 int tx_msg_sz)
+{
+	struct se_msg_hdr *header = tx_msg;
+	int err;
+
+	/*
+	 * Check that the size passed as argument matches the size
+	 * carried in the message.
+	 */
+	if (header->size << 2 != tx_msg_sz) {
+		dev_err(priv->dev,
+			"User buf hdr: 0x%x, sz mismatced with input-sz (%d != %d).",
+			*(u32 *)header, header->size << 2, tx_msg_sz);
+		return -EINVAL;
+	}
+
+	err = mbox_send_message(priv->tx_chan, tx_msg);
+	if (err < 0) {
+		dev_err(priv->dev, "Error: mbox_send_message failure.\n");
+		return err;
+	}
+
+	return tx_msg_sz;
+}
+
+/* API used for send/receive blocking call. */
+int ele_msg_send_rcv(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz,
+		     void *rx_msg, int exp_rx_msg_sz)
+{
+	int err;
+
+	guard(mutex)(&priv->se_if_cmd_lock);
+
+	priv->waiting_rsp_clbk_hdl.rx_msg_sz = exp_rx_msg_sz;
+	priv->waiting_rsp_clbk_hdl.rx_msg = rx_msg;
+
+	err = ele_msg_send(priv, tx_msg, tx_msg_sz);
+	if (err < 0)
+		return err;
+
+	err = ele_msg_rcv(priv, &priv->waiting_rsp_clbk_hdl);
+
+	if (priv->waiting_rsp_clbk_hdl.signal_rcvd) {
+		err = -EINTR;
+		priv->waiting_rsp_clbk_hdl.signal_rcvd = false;
+		dev_err(priv->dev, "Err[0x%x]:Interrupted by signal.\n", err);
+	}
+
+	return err;
+}
+
+static bool check_hdr_exception_for_sz(struct se_if_priv *priv,
+				       struct se_msg_hdr *header)
+{
+	/*
+	 * List of API(s) header that can be accepte variable length
+	 * response buffer.
+	 */
+	if (header->command == ELE_DEBUG_DUMP_REQ &&
+	    header->ver == priv->if_defs->base_api_ver &&
+	    header->size >= 0 && header->size <= ELE_DEBUG_DUMP_RSP_SZ)
+		return true;
+
+	return false;
+}
+
+/*
+ * Callback called by mailbox FW, when data is received.
+ */
+void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg)
+{
+	struct se_clbk_handle *se_clbk_hdl;
+	struct device *dev = mbox_cl->dev;
+	struct se_msg_hdr *header;
+	struct se_if_priv *priv;
+	u32 rx_msg_sz;
+
+	priv = dev_get_drvdata(dev);
+
+	/* The function can be called with NULL msg */
+	if (!msg) {
+		dev_err(dev, "Message is invalid\n");
+		return;
+	}
+
+	header = msg;
+	rx_msg_sz = header->size << 2;
+
+	/* Incoming command: wake up the receiver if any. */
+	if (header->tag == priv->if_defs->cmd_tag) {
+		se_clbk_hdl = &priv->cmd_receiver_clbk_hdl;
+		dev_dbg(dev, "Selecting cmd receiver for mesg header:0x%x.",
+			*(u32 *)header);
+
+		/*
+		 * Pre-allocated buffer of MAX_NVM_MSG_LEN
+		 * as the NVM command are initiated by FW.
+		 * Size is revealed as part of this call function.
+		 */
+		if (rx_msg_sz > MAX_NVM_MSG_LEN) {
+			dev_err(dev,
+				"CMD-RCVER NVM: hdr(0x%x) with different sz(%d != %d).\n",
+				*(u32 *)header, rx_msg_sz, se_clbk_hdl->rx_msg_sz);
+
+			se_clbk_hdl->rx_msg_sz = MAX_NVM_MSG_LEN;
+		}
+		se_clbk_hdl->rx_msg_sz = rx_msg_sz;
+
+	} else if (header->tag == priv->if_defs->rsp_tag) {
+		se_clbk_hdl = &priv->waiting_rsp_clbk_hdl;
+		dev_dbg(dev, "Selecting resp waiter for mesg header:0x%x.",
+			*(u32 *)header);
+
+		if (rx_msg_sz != se_clbk_hdl->rx_msg_sz &&
+		    check_hdr_exception_for_sz(priv, header)) {
+			dev_err(dev,
+				"Rsp to CMD: hdr(0x%x) with different sz(%d != %d).\n",
+				*(u32 *)header, rx_msg_sz, se_clbk_hdl->rx_msg_sz);
+
+			se_clbk_hdl->rx_msg_sz = min(rx_msg_sz, se_clbk_hdl->rx_msg_sz);
+		}
+	} else {
+		dev_err(dev, "Failed to select a device for message: %.8x\n",
+			*((u32 *)header));
+		return;
+	}
+
+	memcpy(se_clbk_hdl->rx_msg, msg, se_clbk_hdl->rx_msg_sz);
+
+	/* Allow user to read */
+	complete(&se_clbk_hdl->done);
+}
+
+int se_val_rsp_hdr_n_status(struct se_if_priv *priv, struct se_api_msg *msg,
+			    u8 msg_id, u8 sz, bool is_base_api)
+{
+	struct se_msg_hdr *header = &msg->header;
+	u32 status;
+
+	if (header->tag != priv->if_defs->rsp_tag) {
+		dev_err(priv->dev, "MSG[0x%x] Hdr: Resp tag mismatch. (0x%x != 0x%x)",
+			msg_id, header->tag, priv->if_defs->rsp_tag);
+		return -EINVAL;
+	}
+
+	if (header->command != msg_id) {
+		dev_err(priv->dev, "MSG Header: Cmd id mismatch. (0x%x != 0x%x)",
+			header->command, msg_id);
+		return -EINVAL;
+	}
+
+	if ((sz % 4) || (header->size != (sz >> 2) &&
+			 !check_hdr_exception_for_sz(priv, header))) {
+		dev_err(priv->dev, "MSG[0x%x] Hdr: Cmd size mismatch. (0x%x != 0x%x)",
+			msg_id, header->size, (sz >> 2));
+		return -EINVAL;
+	}
+
+	if (is_base_api && header->ver != priv->if_defs->base_api_ver) {
+		dev_err(priv->dev,
+			"MSG[0x%x] Hdr: Base API Vers mismatch. (0x%x != 0x%x)",
+			msg_id, header->ver, priv->if_defs->base_api_ver);
+		return -EINVAL;
+	} else if (!is_base_api && header->ver != priv->if_defs->fw_api_ver) {
+		dev_err(priv->dev,
+			"MSG[0x%x] Hdr: FW API Vers mismatch. (0x%x != 0x%x)",
+			msg_id, header->ver, priv->if_defs->fw_api_ver);
+		return -EINVAL;
+	}
+
+	status = RES_STATUS(msg->data[0]);
+	if (status != priv->if_defs->success_tag) {
+		dev_err(priv->dev, "Command Id[%x], Response Failure = 0x%x",
+			header->command, status);
+		return -EPERM;
+	}
+
+	return 0;
+}
+
+int se_save_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem)
+{
+	struct ele_dev_info s_info = {0};
+	int ret;
+
+	ret = ele_get_info(priv, &s_info);
+	if (ret) {
+		dev_err(priv->dev, "Failed to get info from ELE.\n");
+		return ret;
+	}
+
+	/* Do not save the IMEM buffer, if the current IMEM state is BAD. */
+	if (s_info.d_addn_info.imem_state == ELE_IMEM_STATE_BAD)
+		return ret;
+
+	/*
+	 * EXPORT command will save encrypted IMEM to given address,
+	 * so later in resume, IMEM can be restored from the given
+	 * address.
+	 *
+	 * Size must be at least 64 kB.
+	 */
+	ret = ele_service_swap(priv, imem->phyaddr, ELE_IMEM_SIZE, ELE_IMEM_EXPORT);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to export IMEM.");
+		imem->size = 0;
+	} else {
+		dev_dbg(priv->dev,
+			"Exported %d bytes of encrypted IMEM.",
+			ret);
+		imem->size = ret;
+	}
+
+	return ret > 0 ? 0 : ret;
+}
+
+int se_restore_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem)
+{
+	struct ele_dev_info s_info;
+	int ret;
+
+	/* get info from ELE */
+	ret = ele_get_info(priv, &s_info);
+	if (ret) {
+		dev_err(priv->dev, "Failed to get info from ELE.");
+		return ret;
+	}
+	imem->state = s_info.d_addn_info.imem_state;
+
+	/* Get IMEM state, if 0xFE then import IMEM if imem size is non-zero. */
+	if (s_info.d_addn_info.imem_state != ELE_IMEM_STATE_BAD || !imem->size)
+		return ret;
+
+	/*
+	 * IMPORT command will restore IMEM from the given
+	 * address, here size is the actual size returned by ELE
+	 * during the export operation
+	 */
+	ret = ele_service_swap(priv, imem->phyaddr, imem->size, ELE_IMEM_IMPORT);
+	if (ret) {
+		dev_err(priv->dev, "Failed to import IMEM");
+		return ret;
+	}
+
+	/*
+	 * After importing IMEM, check if IMEM state is equal to 0xCA
+	 * to ensure IMEM is fully loaded and
+	 * ELE functionality can be used.
+	 */
+	ret = ele_get_info(priv, &s_info);
+	if (ret) {
+		dev_err(priv->dev, "Failed to get info from ELE.");
+		return ret;
+	}
+	imem->state = s_info.d_addn_info.imem_state;
+
+	if (s_info.d_addn_info.imem_state == ELE_IMEM_STATE_OK)
+		dev_dbg(priv->dev, "Successfully restored IMEM.");
+	else
+		dev_err(priv->dev, "Failed to restore IMEM.");
+
+	return ret;
+}
diff --git a/drivers/firmware/imx/ele_common.h b/drivers/firmware/imx/ele_common.h
new file mode 100644
index 000000000000..96e987ef6f88
--- /dev/null
+++ b/drivers/firmware/imx/ele_common.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2025 NXP
+ */
+
+#ifndef __ELE_COMMON_H__
+#define __ELE_COMMON_H__
+
+#include "se_ctrl.h"
+
+#define ELE_SUCCESS_IND			0xD6
+
+#define IMX_ELE_FW_DIR                 "imx/ele/"
+
+u32 se_get_msg_chksum(u32 *msg, u32 msg_len);
+
+int ele_msg_rcv(struct se_if_priv *priv, struct se_clbk_handle *se_clbk_hdl);
+
+int ele_msg_send(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz);
+
+int ele_msg_send_rcv(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz,
+		     void *rx_msg, int exp_rx_msg_sz);
+
+void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg);
+
+int se_val_rsp_hdr_n_status(struct se_if_priv *priv, struct se_api_msg *msg,
+			    u8 msg_id, u8 sz, bool is_base_api);
+
+/* Fill a command message header with a given command ID and length in bytes. */
+static inline int se_fill_cmd_msg_hdr(struct se_if_priv *priv, struct se_msg_hdr *hdr,
+				      u8 cmd, u32 len, bool is_base_api)
+{
+	hdr->tag = priv->if_defs->cmd_tag;
+	hdr->ver = (is_base_api) ? priv->if_defs->base_api_ver : priv->if_defs->fw_api_ver;
+	hdr->command = cmd;
+	hdr->size = len >> 2;
+
+	return 0;
+}
+
+int se_save_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem);
+
+int se_restore_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem);
+
+#endif /*__ELE_COMMON_H__ */
diff --git a/drivers/firmware/imx/se_ctrl.c b/drivers/firmware/imx/se_ctrl.c
new file mode 100644
index 000000000000..5f978c97da4a
--- /dev/null
+++ b/drivers/firmware/imx/se_ctrl.c
@@ -0,0 +1,401 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 NXP
+ */
+
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/firmware.h>
+#include <linux/firmware/imx/se_api.h>
+#include <linux/genalloc.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/miscdevice.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/sys_soc.h>
+
+#include "ele_base_msg.h"
+#include "ele_common.h"
+#include "se_ctrl.h"
+
+#define MAX_SOC_INFO_DATA_SZ		256
+#define MBOX_TX_NAME			"tx"
+#define MBOX_RX_NAME			"rx"
+
+#define SE_TYPE_STR_DBG			"dbg"
+#define SE_TYPE_STR_HSM			"hsm"
+
+#define SE_TYPE_ID_DBG			0x1
+#define SE_TYPE_ID_HSM			0x2
+
+struct se_fw_img_name {
+	const u8 *prim_fw_nm_in_rfs;
+	const u8 *seco_fw_nm_in_rfs;
+};
+
+struct se_fw_load_info {
+	const struct se_fw_img_name *se_fw_img_nm;
+	bool is_fw_tobe_loaded;
+	bool imem_mgmt;
+	struct se_imem_buf imem;
+};
+
+struct se_var_info {
+	u16 soc_rev;
+	struct se_fw_load_info load_fw;
+};
+
+/* contains fixed information */
+struct se_soc_info {
+	const u16 soc_id;
+	const bool soc_register;
+	const struct se_fw_img_name se_fw_img_nm;
+};
+
+struct se_if_node {
+	struct se_soc_info *se_info;
+	u8 *pool_name;
+	bool reserved_dma_ranges;
+	struct se_if_defines if_defs;
+};
+
+/* common for all the SoC. */
+static struct se_var_info var_se_info;
+
+static struct se_soc_info se_imx8ulp_info = {
+	.soc_id = SOC_ID_OF_IMX8ULP,
+	.soc_register = true,
+	.se_fw_img_nm = {
+		.prim_fw_nm_in_rfs = IMX_ELE_FW_DIR
+			"mx8ulpa2-ahab-container.img",
+		.seco_fw_nm_in_rfs = IMX_ELE_FW_DIR
+			"mx8ulpa2ext-ahab-container.img",
+	},
+};
+
+static struct se_if_node imx8ulp_se_ele_hsm = {
+	.se_info = &se_imx8ulp_info,
+	.pool_name = "sram",
+	.reserved_dma_ranges = true,
+	.if_defs = {
+		.se_if_type = SE_TYPE_ID_HSM,
+		.cmd_tag = 0x17,
+		.rsp_tag = 0xe1,
+		.success_tag = ELE_SUCCESS_IND,
+		.base_api_ver = MESSAGING_VERSION_6,
+		.fw_api_ver = MESSAGING_VERSION_7,
+	},
+};
+
+static struct se_soc_info se_imx93_info = {
+	.soc_id = SOC_ID_OF_IMX93,
+};
+
+static struct se_if_node imx93_se_ele_hsm = {
+	.se_info = &se_imx93_info,
+	.reserved_dma_ranges = true,
+	.if_defs = {
+		.se_if_type = SE_TYPE_ID_HSM,
+		.cmd_tag = 0x17,
+		.rsp_tag = 0xe1,
+		.success_tag = ELE_SUCCESS_IND,
+		.base_api_ver = MESSAGING_VERSION_6,
+		.fw_api_ver = MESSAGING_VERSION_7,
+	},
+};
+
+static const struct of_device_id se_match[] = {
+	{ .compatible = "fsl,imx8ulp-se-ele-hsm", .data = &imx8ulp_se_ele_hsm},
+	{ .compatible = "fsl,imx93-se-ele-hsm", .data = &imx93_se_ele_hsm},
+	{},
+};
+
+char *get_se_if_name(u8 se_if_id)
+{
+	switch (se_if_id) {
+	case SE_TYPE_ID_DBG: return SE_TYPE_STR_DBG;
+	case SE_TYPE_ID_HSM: return SE_TYPE_STR_HSM;
+	}
+
+	return NULL;
+}
+
+static struct se_fw_load_info *get_load_fw_instance(struct se_if_priv *priv)
+{
+	return &var_se_info.load_fw;
+}
+
+static int get_se_soc_info(struct se_if_priv *priv, const struct se_soc_info *se_info)
+{
+	struct se_fw_load_info *load_fw = get_load_fw_instance(priv);
+	struct soc_device_attribute *attr;
+	u8 data[MAX_SOC_INFO_DATA_SZ];
+	struct ele_dev_info *s_info;
+	struct soc_device *sdev;
+	int err = 0;
+
+	/*
+	 * This function should be called once.
+	 * Check if the se_soc_rev is zero to continue.
+	 */
+	if (var_se_info.soc_rev)
+		return err;
+
+	err = ele_fetch_soc_info(priv, &data);
+	if (err < 0)
+		return dev_err_probe(priv->dev, err, "Failed to fetch SoC Info.");
+	s_info = (void *)data;
+	var_se_info.soc_rev = s_info->d_info.soc_rev;
+	load_fw->imem.state = s_info->d_addn_info.imem_state;
+
+	if (!se_info->soc_register)
+		return 0;
+
+	attr = devm_kzalloc(priv->dev, sizeof(*attr), GFP_KERNEL);
+	if (!attr)
+		return -ENOMEM;
+
+	if (FIELD_GET(DEV_GETINFO_MIN_VER_MASK, var_se_info.soc_rev))
+		attr->revision = devm_kasprintf(priv->dev, GFP_KERNEL, "%x.%x",
+						FIELD_GET(DEV_GETINFO_MIN_VER_MASK,
+							  var_se_info.soc_rev),
+						FIELD_GET(DEV_GETINFO_MAJ_VER_MASK,
+							  var_se_info.soc_rev));
+	else
+		attr->revision = devm_kasprintf(priv->dev, GFP_KERNEL, "%x",
+						FIELD_GET(DEV_GETINFO_MAJ_VER_MASK,
+							  var_se_info.soc_rev));
+
+	switch (se_info->soc_id) {
+	case SOC_ID_OF_IMX8ULP:
+		attr->soc_id = "i.MX8ULP";
+		break;
+	case SOC_ID_OF_IMX93:
+		attr->soc_id = "i.MX93";
+		break;
+	}
+
+	err = of_property_read_string(of_root, "model", &attr->machine);
+	if (err)
+		return -EINVAL;
+
+	attr->family = "Freescale i.MX";
+
+	attr->serial_number = devm_kasprintf(priv->dev,
+					     GFP_KERNEL, "%016llX",
+					     GET_SERIAL_NUM_FROM_UID(s_info->d_info.uid,
+								     MAX_UID_SIZE >> 2));
+
+	sdev = soc_device_register(attr);
+	if (IS_ERR(sdev))
+		return PTR_ERR(sdev);
+
+	return 0;
+}
+
+/* interface for managed res to free a mailbox channel */
+static void if_mbox_free_channel(void *mbox_chan)
+{
+	mbox_free_channel(mbox_chan);
+}
+
+static int se_if_request_channel(struct device *dev, struct mbox_chan **chan,
+				 struct mbox_client *cl, const char *name)
+{
+	struct mbox_chan *t_chan;
+	int ret = 0;
+
+	t_chan = mbox_request_channel_byname(cl, name);
+	if (IS_ERR(t_chan))
+		return dev_err_probe(dev, PTR_ERR(t_chan),
+				     "Failed to request %s channel.", name);
+
+	ret = devm_add_action_or_reset(dev, if_mbox_free_channel, t_chan);
+	if (ret)
+		return dev_err_probe(dev, -EPERM,
+				     "Failed to add-action for removal of mbox: %s\n",
+				     name);
+	*chan = t_chan;
+
+	return ret;
+}
+
+static void se_if_probe_cleanup(void *plat_dev)
+{
+	struct platform_device *pdev = plat_dev;
+	struct se_fw_load_info *load_fw;
+	struct device *dev = &pdev->dev;
+	struct se_if_priv *priv;
+
+	priv = dev_get_drvdata(dev);
+	load_fw = get_load_fw_instance(priv);
+
+	/*
+	 * In se_if_request_channel(), passed the clean-up functional
+	 * pointer reference as action to devm_add_action_or_reset().
+	 * No need to free the mbox channels here.
+	 */
+
+	/*
+	 * free the buffer in se remove, previously allocated
+	 * in se probe to store encrypted IMEM
+	 */
+	if (load_fw && load_fw->imem.buf) {
+		dmam_free_coherent(dev, ELE_IMEM_SIZE, load_fw->imem.buf,
+				   load_fw->imem.phyaddr);
+		load_fw->imem.buf = NULL;
+	}
+
+	/*
+	 * No need to check, if reserved memory is allocated
+	 * before calling for its release. Or clearing the
+	 * un-set bit.
+	 */
+	of_reserved_mem_device_release(dev);
+}
+
+static int se_if_probe(struct platform_device *pdev)
+{
+	const struct se_soc_info *se_info;
+	const struct se_if_node *if_node;
+	struct se_fw_load_info *load_fw;
+	struct device *dev = &pdev->dev;
+	struct se_if_priv *priv;
+	int ret;
+
+	if_node = device_get_match_data(dev);
+	if (!if_node)
+		return -EINVAL;
+
+	se_info = if_node->se_info;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = dev;
+	priv->if_defs = &if_node->if_defs;
+	dev_set_drvdata(dev, priv);
+
+	ret = devm_add_action_or_reset(dev, se_if_probe_cleanup, pdev);
+	if (ret)
+		return ret;
+
+	/* Mailbox client configuration */
+	priv->se_mb_cl.dev		= dev;
+	priv->se_mb_cl.tx_block		= false;
+	priv->se_mb_cl.knows_txdone	= true;
+	priv->se_mb_cl.rx_callback	= se_if_rx_callback;
+
+	ret = se_if_request_channel(dev, &priv->tx_chan, &priv->se_mb_cl, MBOX_TX_NAME);
+	if (ret)
+		return ret;
+
+	ret = se_if_request_channel(dev, &priv->rx_chan, &priv->se_mb_cl, MBOX_RX_NAME);
+	if (ret)
+		return ret;
+
+	mutex_init(&priv->se_if_cmd_lock);
+
+	init_completion(&priv->waiting_rsp_clbk_hdl.done);
+	init_completion(&priv->cmd_receiver_clbk_hdl.done);
+
+	if (if_node->pool_name) {
+		priv->mem_pool = of_gen_pool_get(dev->of_node, if_node->pool_name, 0);
+		if (!priv->mem_pool)
+			return dev_err_probe(dev, -ENOMEM,
+					     "Unable to get sram pool = %s.",
+					     if_node->pool_name);
+	}
+
+	if (if_node->reserved_dma_ranges) {
+		ret = of_reserved_mem_device_init(dev);
+		if (ret)
+			return dev_err_probe(dev, ret,
+					    "Failed to init reserved memory region.");
+	}
+
+	if (if_node->if_defs.se_if_type == SE_TYPE_ID_HSM) {
+		ret = get_se_soc_info(priv, se_info);
+		if (ret)
+			return dev_err_probe(dev, ret, "Failed to fetch SoC Info.");
+	}
+
+	/* By default, there is no pending FW to be loaded.*/
+	if (se_info->se_fw_img_nm.seco_fw_nm_in_rfs) {
+		load_fw = get_load_fw_instance(priv);
+		load_fw->se_fw_img_nm = &se_info->se_fw_img_nm;
+		load_fw->is_fw_tobe_loaded = true;
+
+		if (load_fw->se_fw_img_nm->prim_fw_nm_in_rfs) {
+			/* allocate buffer where SE store encrypted IMEM */
+			load_fw->imem.buf = dmam_alloc_coherent(priv->dev, ELE_IMEM_SIZE,
+								&load_fw->imem.phyaddr,
+								GFP_KERNEL);
+			if (!load_fw->imem.buf)
+				return dev_err_probe(dev, -ENOMEM,
+						     "dmam-alloc-failed: To store encr-IMEM.");
+			load_fw->imem_mgmt = true;
+		}
+	}
+	dev_info(dev, "i.MX secure-enclave: %s0 interface to firmware, configured.",
+		 get_se_if_name(priv->if_defs->se_if_type));
+
+	return ret;
+}
+
+static int se_suspend(struct device *dev)
+{
+	struct se_if_priv *priv = dev_get_drvdata(dev);
+	struct se_fw_load_info *load_fw;
+	int ret = 0;
+
+	load_fw = get_load_fw_instance(priv);
+
+	if (load_fw->imem_mgmt)
+		ret = se_save_imem_state(priv, &load_fw->imem);
+
+	return ret;
+}
+
+static int se_resume(struct device *dev)
+{
+	struct se_if_priv *priv = dev_get_drvdata(dev);
+	struct se_fw_load_info *load_fw;
+
+	load_fw = get_load_fw_instance(priv);
+
+	if (load_fw->imem_mgmt)
+		se_restore_imem_state(priv, &load_fw->imem);
+
+	return 0;
+}
+
+static const struct dev_pm_ops se_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(se_suspend, se_resume)
+};
+
+static struct platform_driver se_driver = {
+	.driver = {
+		.name = "fsl-se",
+		.of_match_table = se_match,
+		.pm = &se_pm,
+	},
+	.probe = se_if_probe,
+};
+MODULE_DEVICE_TABLE(of, se_match);
+
+module_platform_driver(se_driver);
+MODULE_AUTHOR("Pankaj Gupta <pankaj.gupta at nxp.com>");
+MODULE_DESCRIPTION("iMX Secure Enclave Driver.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/imx/se_ctrl.h b/drivers/firmware/imx/se_ctrl.h
new file mode 100644
index 000000000000..b15c4022a46c
--- /dev/null
+++ b/drivers/firmware/imx/se_ctrl.h
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2025 NXP
+ */
+
+#ifndef SE_MU_H
+#define SE_MU_H
+
+#include <linux/miscdevice.h>
+#include <linux/semaphore.h>
+#include <linux/mailbox_client.h>
+
+#define MAX_FW_LOAD_RETRIES		50
+#define SE_MSG_WORD_SZ			0x4
+
+#define RES_STATUS(x)			FIELD_GET(0x000000ff, x)
+#define MAX_NVM_MSG_LEN			(256)
+#define MESSAGING_VERSION_6		0x6
+#define MESSAGING_VERSION_7		0x7
+
+struct se_clbk_handle {
+	struct completion done;
+	bool signal_rcvd;
+	u32 rx_msg_sz;
+	/*
+	 * Assignment of the rx_msg buffer to held till the
+	 * received content as part callback function, is copied.
+	 */
+	struct se_api_msg *rx_msg;
+};
+
+struct se_imem_buf {
+	u8 *buf;
+	phys_addr_t phyaddr;
+	u32 size;
+	u32 state;
+};
+
+/* Header of the messages exchange with the EdgeLock Enclave */
+struct se_msg_hdr {
+	u8 ver;
+	u8 size;
+	u8 command;
+	u8 tag;
+}  __packed;
+
+#define SE_MU_HDR_SZ	4
+
+struct se_api_msg {
+	struct se_msg_hdr header;
+	u32 data[];
+};
+
+struct se_if_defines {
+	const u8 se_if_type;
+	u8 cmd_tag;
+	u8 rsp_tag;
+	u8 success_tag;
+	u8 base_api_ver;
+	u8 fw_api_ver;
+};
+
+struct se_if_priv {
+	struct device *dev;
+
+	struct se_clbk_handle cmd_receiver_clbk_hdl;
+	/*
+	 * Update to the waiting_rsp_dev, to be protected
+	 * under se_if_cmd_lock.
+	 */
+	struct se_clbk_handle waiting_rsp_clbk_hdl;
+	/*
+	 * prevent new command to be sent on the se interface while previous
+	 * command is still processing. (response is awaited)
+	 */
+	struct mutex se_if_cmd_lock;
+
+	struct mbox_client se_mb_cl;
+	struct mbox_chan *tx_chan, *rx_chan;
+
+	struct gen_pool *mem_pool;
+	const struct se_if_defines *if_defs;
+};
+
+char *get_se_if_name(u8 se_if_id);
+#endif
diff --git a/include/linux/firmware/imx/se_api.h b/include/linux/firmware/imx/se_api.h
new file mode 100644
index 000000000000..b1c4c9115d7b
--- /dev/null
+++ b/include/linux/firmware/imx/se_api.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2025 NXP
+ */
+
+#ifndef __SE_API_H__
+#define __SE_API_H__
+
+#include <linux/types.h>
+
+#define SOC_ID_OF_IMX8ULP		0x084d
+#define SOC_ID_OF_IMX93			0x9300
+
+#endif /* __SE_API_H__ */

-- 
2.43.0



From pankaj.gupta at nxp.com  Tue Dec  2 22:48:09 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Wed, 03 Dec 2025 12:18:09 +0530
Subject: [PATCH v20 4/7] firmware: imx: device context dedicated to priv
In-Reply-To: <20251203-imx-se-if-v20-0-a04a25c4255f@nxp.com>
References: <20251203-imx-se-if-v20-0-a04a25c4255f@nxp.com>
Message-ID: <20251203-imx-se-if-v20-4-a04a25c4255f@nxp.com>

Add priv_dev_ctx to prepare enabling misc-device context based send-receive
path, to communicate with FW.

No functionality change.

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/firmware/imx/ele_base_msg.c | 14 +++++-----
 drivers/firmware/imx/ele_common.c   | 51 +++++++++++++++++++++----------------
 drivers/firmware/imx/ele_common.h   |  8 +++---
 drivers/firmware/imx/se_ctrl.c      | 29 +++++++++++++++++++++
 drivers/firmware/imx/se_ctrl.h      |  9 +++++++
 5 files changed, 78 insertions(+), 33 deletions(-)

diff --git a/drivers/firmware/imx/ele_base_msg.c b/drivers/firmware/imx/ele_base_msg.c
index a070acbd895c..b233729dd13d 100644
--- a/drivers/firmware/imx/ele_base_msg.c
+++ b/drivers/firmware/imx/ele_base_msg.c
@@ -59,8 +59,8 @@ int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info)
 	tx_msg->data[0] = upper_32_bits(get_info_addr);
 	tx_msg->data[1] = lower_32_bits(get_info_addr);
 	tx_msg->data[2] = sizeof(*s_info);
-	ret = ele_msg_send_rcv(priv, tx_msg, ELE_GET_INFO_REQ_MSG_SZ, rx_msg,
-			       ELE_GET_INFO_RSP_MSG_SZ);
+	ret = ele_msg_send_rcv(priv->priv_dev_ctx, tx_msg, ELE_GET_INFO_REQ_MSG_SZ,
+			       rx_msg, ELE_GET_INFO_RSP_MSG_SZ);
 	if (ret < 0)
 		goto exit;
 
@@ -109,8 +109,8 @@ int ele_ping(struct se_if_priv *priv)
 		return ret;
 	}
 
-	ret = ele_msg_send_rcv(priv, tx_msg, ELE_PING_REQ_SZ, rx_msg,
-			       ELE_PING_RSP_SZ);
+	ret = ele_msg_send_rcv(priv->priv_dev_ctx, tx_msg, ELE_PING_REQ_SZ,
+			       rx_msg, ELE_PING_RSP_SZ);
 	if (ret < 0)
 		return ret;
 
@@ -154,7 +154,7 @@ int ele_service_swap(struct se_if_priv *priv,
 	if (!tx_msg->data[4])
 		return -EINVAL;
 
-	ret = ele_msg_send_rcv(priv, tx_msg, ELE_SERVICE_SWAP_REQ_MSG_SZ,
+	ret = ele_msg_send_rcv(priv->priv_dev_ctx, tx_msg, ELE_SERVICE_SWAP_REQ_MSG_SZ,
 			       rx_msg, ELE_SERVICE_SWAP_RSP_MSG_SZ);
 	if (ret < 0)
 		return ret;
@@ -199,7 +199,7 @@ int ele_fw_authenticate(struct se_if_priv *priv, phys_addr_t contnr_addr,
 	tx_msg->data[1] = upper_32_bits(contnr_addr);
 	tx_msg->data[2] = img_addr;
 
-	ret = ele_msg_send_rcv(priv, tx_msg, ELE_FW_AUTH_REQ_SZ, rx_msg,
+	ret = ele_msg_send_rcv(priv->priv_dev_ctx, tx_msg, ELE_FW_AUTH_REQ_SZ, rx_msg,
 			       ELE_FW_AUTH_RSP_MSG_SZ);
 	if (ret < 0)
 		return ret;
@@ -238,7 +238,7 @@ int ele_debug_dump(struct se_if_priv *priv)
 	do {
 		memset(rx_msg, 0x0, ELE_DEBUG_DUMP_RSP_SZ);
 
-		ret = ele_msg_send_rcv(priv, tx_msg, ELE_DEBUG_DUMP_REQ_SZ,
+		ret = ele_msg_send_rcv(priv->priv_dev_ctx, tx_msg, ELE_DEBUG_DUMP_REQ_SZ,
 				       rx_msg, ELE_DEBUG_DUMP_RSP_SZ);
 		if (ret < 0)
 			return ret;
diff --git a/drivers/firmware/imx/ele_common.c b/drivers/firmware/imx/ele_common.c
index 748eb09474d7..f26fb4d55a9a 100644
--- a/drivers/firmware/imx/ele_common.c
+++ b/drivers/firmware/imx/ele_common.c
@@ -42,7 +42,7 @@ u32 se_get_msg_chksum(u32 *msg, u32 msg_len)
 	return chksum;
 }
 
-int ele_msg_rcv(struct se_if_priv *priv, struct se_clbk_handle *se_clbk_hdl)
+int ele_msg_rcv(struct se_if_device_ctx *dev_ctx, struct se_clbk_handle *se_clbk_hdl)
 {
 	unsigned long timeout;
 	int ret;
@@ -52,8 +52,8 @@ int ele_msg_rcv(struct se_if_priv *priv, struct se_clbk_handle *se_clbk_hdl)
 
 		ret = wait_for_completion_interruptible_timeout(&se_clbk_hdl->done, timeout);
 		if (ret == -ERESTARTSYS) {
-			if (priv->waiting_rsp_clbk_hdl.rx_msg) {
-				priv->waiting_rsp_clbk_hdl.signal_rcvd = true;
+			if (dev_ctx->priv->waiting_rsp_clbk_hdl.dev_ctx) {
+				dev_ctx->priv->waiting_rsp_clbk_hdl.signal_rcvd = true;
 				continue;
 			}
 			ret = -EINTR;
@@ -66,7 +66,7 @@ int ele_msg_rcv(struct se_if_priv *priv, struct se_clbk_handle *se_clbk_hdl)
 	return ret;
 }
 
-int ele_msg_send(struct se_if_priv *priv,
+int ele_msg_send(struct se_if_device_ctx *dev_ctx,
 		 void *tx_msg,
 		 int tx_msg_sz)
 {
@@ -78,15 +78,16 @@ int ele_msg_send(struct se_if_priv *priv,
 	 * carried in the message.
 	 */
 	if (header->size << 2 != tx_msg_sz) {
-		dev_err(priv->dev,
-			"User buf hdr: 0x%x, sz mismatced with input-sz (%d != %d).",
-			*(u32 *)header, header->size << 2, tx_msg_sz);
+		dev_err(dev_ctx->priv->dev,
+			"%s: User buf hdr: 0x%x, sz mismatced with input-sz (%d != %d).",
+			dev_ctx->devname, *(u32 *)header, header->size << 2, tx_msg_sz);
 		return -EINVAL;
 	}
 
-	err = mbox_send_message(priv->tx_chan, tx_msg);
+	err = mbox_send_message(dev_ctx->priv->tx_chan, tx_msg);
 	if (err < 0) {
-		dev_err(priv->dev, "Error: mbox_send_message failure.\n");
+		dev_err(dev_ctx->priv->dev,
+			"%s: Error: mbox_send_message failure.", dev_ctx->devname);
 		return err;
 	}
 
@@ -94,27 +95,31 @@ int ele_msg_send(struct se_if_priv *priv,
 }
 
 /* API used for send/receive blocking call. */
-int ele_msg_send_rcv(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz,
-		     void *rx_msg, int exp_rx_msg_sz)
+int ele_msg_send_rcv(struct se_if_device_ctx *dev_ctx, void *tx_msg,
+		     int tx_msg_sz, void *rx_msg, int exp_rx_msg_sz)
 {
+	struct se_if_priv *priv = dev_ctx->priv;
 	int err;
 
 	guard(mutex)(&priv->se_if_cmd_lock);
 
+	priv->waiting_rsp_clbk_hdl.dev_ctx = dev_ctx;
 	priv->waiting_rsp_clbk_hdl.rx_msg_sz = exp_rx_msg_sz;
 	priv->waiting_rsp_clbk_hdl.rx_msg = rx_msg;
 
-	err = ele_msg_send(priv, tx_msg, tx_msg_sz);
+	err = ele_msg_send(dev_ctx, tx_msg, tx_msg_sz);
 	if (err < 0)
 		return err;
 
-	err = ele_msg_rcv(priv, &priv->waiting_rsp_clbk_hdl);
+	err = ele_msg_rcv(dev_ctx, &priv->waiting_rsp_clbk_hdl);
 
 	if (priv->waiting_rsp_clbk_hdl.signal_rcvd) {
 		err = -EINTR;
 		priv->waiting_rsp_clbk_hdl.signal_rcvd = false;
-		dev_err(priv->dev, "Err[0x%x]:Interrupted by signal.\n", err);
+		dev_err(priv->dev, "%s: Err[0x%x]:Interrupted by signal.",
+			dev_ctx->devname, err);
 	}
+	priv->waiting_rsp_clbk_hdl.dev_ctx = NULL;
 
 	return err;
 }
@@ -159,8 +164,8 @@ void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg)
 	/* Incoming command: wake up the receiver if any. */
 	if (header->tag == priv->if_defs->cmd_tag) {
 		se_clbk_hdl = &priv->cmd_receiver_clbk_hdl;
-		dev_dbg(dev, "Selecting cmd receiver for mesg header:0x%x.",
-			*(u32 *)header);
+		dev_dbg(dev, "Selecting cmd receiver:%s for mesg header:0x%x.",
+			se_clbk_hdl->dev_ctx->devname,  *(u32 *)header);
 
 		/*
 		 * Pre-allocated buffer of MAX_NVM_MSG_LEN
@@ -169,8 +174,9 @@ void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg)
 		 */
 		if (rx_msg_sz > MAX_NVM_MSG_LEN) {
 			dev_err(dev,
-				"CMD-RCVER NVM: hdr(0x%x) with different sz(%d != %d).\n",
-				*(u32 *)header, rx_msg_sz, se_clbk_hdl->rx_msg_sz);
+				"%s: CMD-RCVER NVM: hdr(0x%x) with different sz(%d != %d).\n",
+				se_clbk_hdl->dev_ctx->devname, *(u32 *)header,
+				rx_msg_sz, se_clbk_hdl->rx_msg_sz);
 
 			se_clbk_hdl->rx_msg_sz = MAX_NVM_MSG_LEN;
 		}
@@ -178,14 +184,15 @@ void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg)
 
 	} else if (header->tag == priv->if_defs->rsp_tag) {
 		se_clbk_hdl = &priv->waiting_rsp_clbk_hdl;
-		dev_dbg(dev, "Selecting resp waiter for mesg header:0x%x.",
-			*(u32 *)header);
+		dev_dbg(dev, "Selecting resp waiter:%s for mesg header:0x%x.",
+			se_clbk_hdl->dev_ctx->devname, *(u32 *)header);
 
 		if (rx_msg_sz != se_clbk_hdl->rx_msg_sz &&
 		    check_hdr_exception_for_sz(priv, header)) {
 			dev_err(dev,
-				"Rsp to CMD: hdr(0x%x) with different sz(%d != %d).\n",
-				*(u32 *)header, rx_msg_sz, se_clbk_hdl->rx_msg_sz);
+				"%s: Rsp to CMD: hdr(0x%x) with different sz(%d != %d).\n",
+				se_clbk_hdl->dev_ctx->devname, *(u32 *)header,
+				rx_msg_sz, se_clbk_hdl->rx_msg_sz);
 
 			se_clbk_hdl->rx_msg_sz = min(rx_msg_sz, se_clbk_hdl->rx_msg_sz);
 		}
diff --git a/drivers/firmware/imx/ele_common.h b/drivers/firmware/imx/ele_common.h
index 96e987ef6f88..5bac14439d7d 100644
--- a/drivers/firmware/imx/ele_common.h
+++ b/drivers/firmware/imx/ele_common.h
@@ -14,12 +14,12 @@
 
 u32 se_get_msg_chksum(u32 *msg, u32 msg_len);
 
-int ele_msg_rcv(struct se_if_priv *priv, struct se_clbk_handle *se_clbk_hdl);
+int ele_msg_rcv(struct se_if_device_ctx *dev_ctx, struct se_clbk_handle *se_clbk_hdl);
 
-int ele_msg_send(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz);
+int ele_msg_send(struct se_if_device_ctx *dev_ctx, void *tx_msg, int tx_msg_sz);
 
-int ele_msg_send_rcv(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz,
-		     void *rx_msg, int exp_rx_msg_sz);
+int ele_msg_send_rcv(struct se_if_device_ctx *dev_ctx, void *tx_msg,
+		     int tx_msg_sz, void *rx_msg, int exp_rx_msg_sz);
 
 void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg);
 
diff --git a/drivers/firmware/imx/se_ctrl.c b/drivers/firmware/imx/se_ctrl.c
index 5f978c97da4a..40544cbc70ca 100644
--- a/drivers/firmware/imx/se_ctrl.c
+++ b/drivers/firmware/imx/se_ctrl.c
@@ -203,6 +203,29 @@ static int get_se_soc_info(struct se_if_priv *priv, const struct se_soc_info *se
 	return 0;
 }
 
+static int init_misc_device_context(struct se_if_priv *priv, int ch_id,
+				    struct se_if_device_ctx **new_dev_ctx)
+{
+	struct se_if_device_ctx *dev_ctx;
+	int ret = 0;
+
+	dev_ctx = devm_kzalloc(priv->dev, sizeof(*dev_ctx), GFP_KERNEL);
+
+	if (!dev_ctx)
+		return -ENOMEM;
+
+	dev_ctx->devname = devm_kasprintf(priv->dev, GFP_KERNEL, "%s0_ch%d",
+					  get_se_if_name(priv->if_defs->se_if_type),
+					  ch_id);
+	if (!dev_ctx->devname)
+		return -ENOMEM;
+
+	dev_ctx->priv = priv;
+	*new_dev_ctx = dev_ctx;
+
+	return ret;
+}
+
 /* interface for managed res to free a mailbox channel */
 static void if_mbox_free_channel(void *mbox_chan)
 {
@@ -325,6 +348,12 @@ static int se_if_probe(struct platform_device *pdev)
 					    "Failed to init reserved memory region.");
 	}
 
+	ret = init_misc_device_context(priv, 0, &priv->priv_dev_ctx);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed[0x%x] to create device contexts.",
+				     ret);
+
 	if (if_node->if_defs.se_if_type == SE_TYPE_ID_HSM) {
 		ret = get_se_soc_info(priv, se_info);
 		if (ret)
diff --git a/drivers/firmware/imx/se_ctrl.h b/drivers/firmware/imx/se_ctrl.h
index b15c4022a46c..b5e7705e2f26 100644
--- a/drivers/firmware/imx/se_ctrl.h
+++ b/drivers/firmware/imx/se_ctrl.h
@@ -19,6 +19,7 @@
 #define MESSAGING_VERSION_7		0x7
 
 struct se_clbk_handle {
+	struct se_if_device_ctx *dev_ctx;
 	struct completion done;
 	bool signal_rcvd;
 	u32 rx_msg_sz;
@@ -36,6 +37,12 @@ struct se_imem_buf {
 	u32 state;
 };
 
+/* Private struct for each char device instance. */
+struct se_if_device_ctx {
+	struct se_if_priv *priv;
+	const char *devname;
+};
+
 /* Header of the messages exchange with the EdgeLock Enclave */
 struct se_msg_hdr {
 	u8 ver;
@@ -80,6 +87,8 @@ struct se_if_priv {
 
 	struct gen_pool *mem_pool;
 	const struct se_if_defines *if_defs;
+
+	struct se_if_device_ctx *priv_dev_ctx;
 };
 
 char *get_se_if_name(u8 se_if_id);

-- 
2.43.0



From pankaj.gupta at nxp.com  Tue Dec  2 22:48:10 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Wed, 03 Dec 2025 12:18:10 +0530
Subject: [PATCH v20 5/7] firmware: drivers: imx: adds miscdev
In-Reply-To: <20251203-imx-se-if-v20-0-a04a25c4255f@nxp.com>
References: <20251203-imx-se-if-v20-0-a04a25c4255f@nxp.com>
Message-ID: <20251203-imx-se-if-v20-5-a04a25c4255f@nxp.com>

Adds the driver for communication interface to secure-enclave, that
enables exchanging messages with NXP secure enclave HW IP(s)
like EdgeLock Enclave, from:
- User-Space Applications via character driver.

ABI documentation for the NXP secure-enclave driver.

User-space library using this driver:
- i.MX Secure Enclave library:
  -- URL: https://github.com/nxp-imx/imx-secure-enclave.git,
- i.MX Secure Middle-Ware:
  -- URL: https://github.com/nxp-imx/imx-smw.git

Following checks are performed on the incoming msg-header,
to block exchanging invalid arbitrary commands:
- maximum allowed words,
- check if command-tag & response-tag are valid
- version,
- command id validation check, to allow limited base-line API(s)
  and restrict following:
  - exchanging power management commands.
  - reset requests.
  - BBSM configuration requests.
  - re-initializing the FW.
  - RNG init
  - CAAM resource release management
  - SE's internal memory management.
from user-space.

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
changes from v19 to v20
- adds a func "se_chk_tx_msg_hdr", to check the validity of
  the in-coming message from usersapce.
---
 Documentation/ABI/testing/se-cdev   |  43 +++
 drivers/firmware/imx/ele_base_msg.c |  28 ++
 drivers/firmware/imx/ele_base_msg.h |  20 +
 drivers/firmware/imx/ele_common.c   |  37 +-
 drivers/firmware/imx/ele_common.h   |   6 +
 drivers/firmware/imx/se_ctrl.c      | 741 +++++++++++++++++++++++++++++++++++-
 drivers/firmware/imx/se_ctrl.h      |  33 ++
 include/uapi/linux/se_ioctl.h       |  97 +++++
 8 files changed, 993 insertions(+), 12 deletions(-)

diff --git a/Documentation/ABI/testing/se-cdev b/Documentation/ABI/testing/se-cdev
new file mode 100644
index 000000000000..dad39ffd245a
--- /dev/null
+++ b/Documentation/ABI/testing/se-cdev
@@ -0,0 +1,43 @@
+What:		/dev/<se>_mu[0-9]+_ch[0-9]+
+Date:		Mar 2025
+KernelVersion:	6.8
+Contact:	linux-imx at nxp.com, pankaj.gupta at nxp.com
+Description:
+		NXP offers multiple hardware IP(s) for secure enclaves like EdgeLock-
+		Enclave(ELE), SECO. The character device file descriptors
+		/dev/<se>_mu*_ch* are the interface between userspace NXP's secure-
+		enclave shared library and the kernel driver.
+
+		The ioctl(2)-based ABI is defined and documented in
+		[include]<linux/firmware/imx/ele_mu_ioctl.h>.
+		ioctl(s) are used primarily for:
+			- shared memory management
+			- allocation of I/O buffers
+			- getting mu info
+			- setting a dev-ctx as receiver to receive all the commands from FW
+			- getting SoC info
+			- send command and receive command response
+
+		The following file operations are supported:
+
+		open(2)
+		  Currently the only useful flags are O_RDWR.
+
+		read(2)
+		  Every read() from the opened character device context is waiting on
+		  wait_event_interruptible, that gets set by the registered mailbox callback
+		  function, indicating a message received from the firmware on message-
+		  unit.
+
+		write(2)
+		  Every write() to the opened character device context needs to acquire
+		  mailbox_lock before sending message on to the message unit.
+
+		close(2)
+		  Stops and frees up the I/O contexts that were associated
+		  with the file descriptor.
+
+Users:		https://github.com/nxp-imx/imx-secure-enclave.git,
+		https://github.com/nxp-imx/imx-smw.git
+		crypto/skcipher,
+		drivers/nvmem/imx-ocotp-ele.c
diff --git a/drivers/firmware/imx/ele_base_msg.c b/drivers/firmware/imx/ele_base_msg.c
index b233729dd13d..ef1d89204ceb 100644
--- a/drivers/firmware/imx/ele_base_msg.c
+++ b/drivers/firmware/imx/ele_base_msg.c
@@ -14,6 +14,34 @@
 
 #define FW_DBG_DUMP_FIXED_STR		"ELE"
 
+int ele_uapi_allowed_base_cmd(struct se_if_priv *priv,
+			      struct se_msg_hdr *header)
+{
+	switch (header->command) {
+	case ELE_PING_REQ: return 0;
+	case ELE_DEBUG_DUMP_REQ: return 0;
+	case ELE_OEM_AUTH_CONTAINER_REQ: return 0;
+	case ELE_OEM_VERIFY_IMAGE_REQ: return 0;
+	case ELE_OEM_REL_CONTAINER_REQ: return 0;
+	case ELE_FW_LIFE_CYCLE_REQ: return 0;
+	case ELE_READ_FUSE_REQ: return 0;
+	case ELE_GET_FW_VERS_REQ: return 0;
+	case ELE_RETURN_LIFE_CYCLE_REQ: return 0;
+	case ELE_GET_EVENT_REQ: return 0;
+	case ELE_COMMIT_REQ: return 0;
+	case ELE_GEN_KEY_BLOB_REQ: return 0;
+	case ELE_GET_FW_STATUS_REQ: return 0;
+	case ELE_XIP_DECRYPT_REQ: return 0;
+	case ELE_WRITE_FUSE: return 0;
+	case ELE_GET_INFO_REQ: return 0;
+	case ELE_DEV_ATTEST_REQ: return 0;
+	case ELE_WRITE_SHADOW_FUSE_REQ: return 0;
+	case ELE_READ_SHADOW_FUSE_REQ: return 0;
+	default:
+		return -EACCES;
+	}
+}
+
 int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info)
 {
 	struct se_api_msg *tx_msg __free(kfree) = NULL;
diff --git a/drivers/firmware/imx/ele_base_msg.h b/drivers/firmware/imx/ele_base_msg.h
index 8e5b015e99a2..f8fabac331fd 100644
--- a/drivers/firmware/imx/ele_base_msg.h
+++ b/drivers/firmware/imx/ele_base_msg.h
@@ -15,6 +15,24 @@
 
 #define ELE_NONE_VAL			0x0
 
+
+#define ELE_OEM_AUTH_CONTAINER_REQ	0x87
+#define ELE_OEM_VERIFY_IMAGE_REQ	0x88
+#define ELE_OEM_REL_CONTAINER_REQ	0x89
+#define ELE_FW_LIFE_CYCLE_REQ		0x95
+#define ELE_READ_FUSE_REQ		0x97
+#define ELE_GET_FW_VERS_REQ		0x9d
+#define ELE_RETURN_LIFE_CYCLE_REQ	0xa0
+#define ELE_GET_EVENT_REQ		0xa2
+#define ELE_COMMIT_REQ			0xa8
+#define ELE_GEN_KEY_BLOB_REQ		0xaf
+#define ELE_GET_FW_STATUS_REQ		0xc5
+#define ELE_XIP_DECRYPT_REQ		0xc6
+#define ELE_WRITE_FUSE                  0xd6
+#define ELE_DEV_ATTEST_REQ              0xdb
+#define ELE_WRITE_SHADOW_FUSE_REQ       0xf2
+#define ELE_READ_SHADOW_FUSE_REQ        0xf3
+
 #define ELE_GET_INFO_REQ		0xda
 #define ELE_GET_INFO_REQ_MSG_SZ		0x10
 #define ELE_GET_INFO_RSP_MSG_SZ		0x08
@@ -92,4 +110,6 @@ int ele_service_swap(struct se_if_priv *priv, phys_addr_t addr,
 int ele_fw_authenticate(struct se_if_priv *priv, phys_addr_t contnr_addr,
 			phys_addr_t img_addr);
 int ele_debug_dump(struct se_if_priv *priv);
+int ele_uapi_allowed_base_cmd(struct se_if_priv *priv,
+			      struct se_msg_hdr *header);
 #endif
diff --git a/drivers/firmware/imx/ele_common.c b/drivers/firmware/imx/ele_common.c
index f26fb4d55a9a..a6801c5ae4a8 100644
--- a/drivers/firmware/imx/ele_common.c
+++ b/drivers/firmware/imx/ele_common.c
@@ -6,6 +6,23 @@
 #include "ele_base_msg.h"
 #include "ele_common.h"
 
+int se_chk_tx_msg_hdr(struct se_if_priv *priv, struct se_msg_hdr *header)
+{
+	if (!header->size || header->size > MAX_WORD_SIZE)
+		return -EINVAL;
+
+	if (header->tag != priv->if_defs->cmd_tag &&
+	    header->tag != priv->if_defs->rsp_tag)
+		return -EINVAL;
+
+	if (header->ver == priv->if_defs->base_api_ver)
+		return ele_uapi_allowed_base_cmd(priv, header);
+	else if (header->ver == priv->if_defs->fw_api_ver)
+		return 0;
+
+	return -EINVAL;
+}
+
 /*
  * se_get_msg_chksum() - to calculate checksum word by word.
  *
@@ -42,15 +59,22 @@ u32 se_get_msg_chksum(u32 *msg, u32 msg_len)
 	return chksum;
 }
 
+void set_se_rcv_msg_timeout(struct se_if_priv *priv, u32 timeout_ms)
+{
+	priv->se_rcv_msg_timeout_ms = timeout_ms;
+}
+
 int ele_msg_rcv(struct se_if_device_ctx *dev_ctx, struct se_clbk_handle *se_clbk_hdl)
 {
-	unsigned long timeout;
+	unsigned long timeout_ms;
 	int ret;
 
 	do {
-		timeout = MAX_SCHEDULE_TIMEOUT;
+		timeout_ms = MAX_SCHEDULE_TIMEOUT;
+		if (dev_ctx->priv->cmd_receiver_clbk_hdl.dev_ctx != dev_ctx)
+			timeout_ms = msecs_to_jiffies(dev_ctx->priv->se_rcv_msg_timeout_ms);
 
-		ret = wait_for_completion_interruptible_timeout(&se_clbk_hdl->done, timeout);
+		ret = wait_for_completion_interruptible_timeout(&se_clbk_hdl->done, timeout_ms);
 		if (ret == -ERESTARTSYS) {
 			if (dev_ctx->priv->waiting_rsp_clbk_hdl.dev_ctx) {
 				dev_ctx->priv->waiting_rsp_clbk_hdl.signal_rcvd = true;
@@ -59,6 +83,13 @@ int ele_msg_rcv(struct se_if_device_ctx *dev_ctx, struct se_clbk_handle *se_clbk
 			ret = -EINTR;
 			break;
 		}
+		if (ret == 0) {
+			ret = -ETIMEDOUT;
+			dev_err(dev_ctx->priv->dev,
+				"Fatal Error: SE interface: %s0, hangs indefinitely.\n",
+				get_se_if_name(dev_ctx->priv->if_defs->se_if_type));
+			break;
+		}
 		ret = se_clbk_hdl->rx_msg_sz;
 		break;
 	} while (ret < 0);
diff --git a/drivers/firmware/imx/ele_common.h b/drivers/firmware/imx/ele_common.h
index 5bac14439d7d..bdc13d1b715d 100644
--- a/drivers/firmware/imx/ele_common.h
+++ b/drivers/firmware/imx/ele_common.h
@@ -12,6 +12,11 @@
 
 #define IMX_ELE_FW_DIR                 "imx/ele/"
 
+#define MAX_WORD_SIZE			0x20
+#define SE_RCV_MSG_DEFAULT_TIMEOUT	5000
+#define SE_RCV_MSG_LONG_TIMEOUT		5000000
+
+void set_se_rcv_msg_timeout(struct se_if_priv *priv, u32 val);
 u32 se_get_msg_chksum(u32 *msg, u32 msg_len);
 
 int ele_msg_rcv(struct se_if_device_ctx *dev_ctx, struct se_clbk_handle *se_clbk_hdl);
@@ -42,4 +47,5 @@ int se_save_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem);
 
 int se_restore_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem);
 
+int se_chk_tx_msg_hdr(struct se_if_priv *priv, struct se_msg_hdr *header);
 #endif /*__ELE_COMMON_H__ */
diff --git a/drivers/firmware/imx/se_ctrl.c b/drivers/firmware/imx/se_ctrl.c
index 40544cbc70ca..b8070be57d15 100644
--- a/drivers/firmware/imx/se_ctrl.c
+++ b/drivers/firmware/imx/se_ctrl.c
@@ -23,6 +23,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/sys_soc.h>
+#include <uapi/linux/se_ioctl.h>
 
 #include "ele_base_msg.h"
 #include "ele_common.h"
@@ -32,12 +33,6 @@
 #define MBOX_TX_NAME			"tx"
 #define MBOX_RX_NAME			"rx"
 
-#define SE_TYPE_STR_DBG			"dbg"
-#define SE_TYPE_STR_HSM			"hsm"
-
-#define SE_TYPE_ID_DBG			0x1
-#define SE_TYPE_ID_HSM			0x2
-
 struct se_fw_img_name {
 	const u8 *prim_fw_nm_in_rfs;
 	const u8 *seco_fw_nm_in_rfs;
@@ -130,6 +125,13 @@ char *get_se_if_name(u8 se_if_id)
 	return NULL;
 }
 
+static u32 get_se_soc_id(struct se_if_priv *priv)
+{
+	const struct se_soc_info *se_info = device_get_match_data(priv->dev);
+
+	return se_info->soc_id;
+}
+
 static struct se_fw_load_info *get_load_fw_instance(struct se_if_priv *priv)
 {
 	return &var_se_info.load_fw;
@@ -203,8 +205,213 @@ static int get_se_soc_info(struct se_if_priv *priv, const struct se_soc_info *se
 	return 0;
 }
 
+static int load_firmware(struct se_if_priv *priv, const u8 *se_img_file_to_load)
+{
+	const struct firmware *fw = NULL;
+	phys_addr_t se_fw_phyaddr;
+	u8 *se_fw_buf;
+	int ret;
+
+	if (!se_img_file_to_load) {
+		dev_err(priv->dev, "FW image is not provided.");
+		return -EINVAL;
+	}
+	ret = request_firmware(&fw, se_img_file_to_load, priv->dev);
+	if (ret)
+		return ret;
+
+	dev_info(priv->dev, "loading firmware %s.", se_img_file_to_load);
+
+	/* allocate buffer to store the SE FW */
+	se_fw_buf = dma_alloc_coherent(priv->dev, fw->size, &se_fw_phyaddr, GFP_KERNEL);
+	if (!se_fw_buf) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	memcpy(se_fw_buf, fw->data, fw->size);
+	ret = ele_fw_authenticate(priv, se_fw_phyaddr, se_fw_phyaddr);
+	if (ret < 0) {
+		dev_err(priv->dev,
+			"Error %pe: Authenticate & load SE firmware %s.",
+			ERR_PTR(ret), se_img_file_to_load);
+		ret = -EPERM;
+	}
+	dma_free_coherent(priv->dev, fw->size, se_fw_buf, se_fw_phyaddr);
+exit:
+	release_firmware(fw);
+
+	return ret;
+}
+
+static int se_load_firmware(struct se_if_priv *priv)
+{
+	struct se_fw_load_info *load_fw = get_load_fw_instance(priv);
+	int ret = 0;
+
+	if (!load_fw->is_fw_tobe_loaded)
+		return 0;
+
+	if (load_fw->imem.state == ELE_IMEM_STATE_BAD) {
+		ret = load_firmware(priv, load_fw->se_fw_img_nm->prim_fw_nm_in_rfs);
+		if (ret) {
+			dev_err(priv->dev, "Failed to load boot firmware.");
+			return -EPERM;
+		}
+	}
+
+	ret = load_firmware(priv, load_fw->se_fw_img_nm->seco_fw_nm_in_rfs);
+	if (ret) {
+		dev_err(priv->dev, "Failed to load runtime firmware.");
+		return -EPERM;
+	}
+
+	load_fw->is_fw_tobe_loaded = false;
+
+	return ret;
+}
+
+static int init_se_shared_mem(struct se_if_device_ctx *dev_ctx)
+{
+	struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
+	struct se_if_priv *priv = dev_ctx->priv;
+
+	INIT_LIST_HEAD(&se_shared_mem_mgmt->pending_out);
+	INIT_LIST_HEAD(&se_shared_mem_mgmt->pending_in);
+
+	/*
+	 * Allocate some memory for data exchanges with S40x.
+	 * This will be used for data not requiring secure memory.
+	 */
+	se_shared_mem_mgmt->non_secure_mem.ptr =
+			dma_alloc_coherent(priv->dev, MAX_DATA_SIZE_PER_USER,
+					   &se_shared_mem_mgmt->non_secure_mem.dma_addr,
+					   GFP_KERNEL);
+	if (!se_shared_mem_mgmt->non_secure_mem.ptr)
+		return -ENOMEM;
+
+	se_shared_mem_mgmt->non_secure_mem.size = MAX_DATA_SIZE_PER_USER;
+	se_shared_mem_mgmt->non_secure_mem.pos = 0;
+
+	return 0;
+}
+
+static void cleanup_se_shared_mem(struct se_if_device_ctx *dev_ctx)
+{
+	struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
+	struct se_if_priv *priv = dev_ctx->priv;
+
+	/* Free non-secure shared buffer. */
+	dma_free_coherent(priv->dev, MAX_DATA_SIZE_PER_USER,
+			  se_shared_mem_mgmt->non_secure_mem.ptr,
+			  se_shared_mem_mgmt->non_secure_mem.dma_addr);
+
+	se_shared_mem_mgmt->non_secure_mem.ptr = NULL;
+	se_shared_mem_mgmt->non_secure_mem.dma_addr = 0;
+	se_shared_mem_mgmt->non_secure_mem.size = 0;
+	se_shared_mem_mgmt->non_secure_mem.pos = 0;
+}
+
+/* Need to copy the output data to user-device context.
+ */
+static int se_dev_ctx_cpy_out_data(struct se_if_device_ctx *dev_ctx)
+{
+	struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
+	struct se_if_priv *priv = dev_ctx->priv;
+	struct se_buf_desc *b_desc, *temp;
+	bool do_cpy = true;
+
+	list_for_each_entry_safe(b_desc, temp, &se_shared_mem_mgmt->pending_out, link) {
+		if (b_desc->usr_buf_ptr && b_desc->shared_buf_ptr && do_cpy) {
+			dev_dbg(priv->dev, "Copying output data to user.");
+			if (do_cpy && copy_to_user(b_desc->usr_buf_ptr,
+						   b_desc->shared_buf_ptr,
+						   b_desc->size)) {
+				dev_err(priv->dev, "Failure copying output data to user.");
+				do_cpy = false;
+			}
+		}
+
+		if (b_desc->shared_buf_ptr)
+			memset(b_desc->shared_buf_ptr, 0, b_desc->size);
+
+		list_del(&b_desc->link);
+		kfree(b_desc);
+	}
+
+	return do_cpy ? 0 : -EFAULT;
+}
+
+/*
+ * Clean the used Shared Memory space,
+ * whether its Input Data copied from user buffers, or
+ * Data received from FW.
+ */
+static void se_dev_ctx_shared_mem_cleanup(struct se_if_device_ctx *dev_ctx)
+{
+	struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
+	struct list_head *pending_lists[] = {&se_shared_mem_mgmt->pending_in,
+						&se_shared_mem_mgmt->pending_out};
+	struct se_buf_desc *b_desc, *temp;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pending_lists); i++) {
+		list_for_each_entry_safe(b_desc, temp, pending_lists[i], link) {
+			if (b_desc->shared_buf_ptr)
+				memset(b_desc->shared_buf_ptr, 0, b_desc->size);
+
+			list_del(&b_desc->link);
+			kfree(b_desc);
+		}
+	}
+	se_shared_mem_mgmt->non_secure_mem.pos = 0;
+}
+
+static int add_b_desc_to_pending_list(void *shared_ptr_with_pos,
+				      struct se_ioctl_setup_iobuf *io,
+				      struct se_if_device_ctx *dev_ctx)
+{
+	struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
+	struct se_buf_desc *b_desc;
+
+	b_desc = kzalloc(sizeof(*b_desc), GFP_KERNEL);
+	if (!b_desc)
+		return -ENOMEM;
+
+	b_desc->shared_buf_ptr = shared_ptr_with_pos;
+	b_desc->usr_buf_ptr = io->user_buf;
+	b_desc->size = io->length;
+
+	if (io->flags & SE_IO_BUF_FLAGS_IS_INPUT) {
+		/*
+		 * buffer is input:
+		 * add an entry in the "pending input buffers" list so
+		 * that copied data can be cleaned from shared memory
+		 * later.
+		 */
+		list_add_tail(&b_desc->link, &se_shared_mem_mgmt->pending_in);
+	} else {
+		/*
+		 * buffer is output:
+		 * add an entry in the "pending out buffers" list so data
+		 * can be copied to user space when receiving Secure-Enclave
+		 * response.
+		 */
+		list_add_tail(&b_desc->link, &se_shared_mem_mgmt->pending_out);
+	}
+
+	return 0;
+}
+
+/* interface for managed res to unregister a character device */
+static void if_misc_deregister(void *miscdevice)
+{
+	misc_deregister(miscdevice);
+}
+
 static int init_misc_device_context(struct se_if_priv *priv, int ch_id,
-				    struct se_if_device_ctx **new_dev_ctx)
+				    struct se_if_device_ctx **new_dev_ctx,
+				    const struct file_operations *se_if_fops)
 {
 	struct se_if_device_ctx *dev_ctx;
 	int ret = 0;
@@ -220,12 +427,517 @@ static int init_misc_device_context(struct se_if_priv *priv, int ch_id,
 	if (!dev_ctx->devname)
 		return -ENOMEM;
 
+	mutex_init(&dev_ctx->fops_lock);
+
 	dev_ctx->priv = priv;
 	*new_dev_ctx = dev_ctx;
 
+	dev_ctx->miscdev = devm_kzalloc(priv->dev, sizeof(*dev_ctx->miscdev), GFP_KERNEL);
+	if (!dev_ctx->miscdev) {
+		*new_dev_ctx = NULL;
+		return -ENOMEM;
+	}
+
+	dev_ctx->miscdev->name = dev_ctx->devname;
+	dev_ctx->miscdev->minor = MISC_DYNAMIC_MINOR;
+	dev_ctx->miscdev->fops = se_if_fops;
+	dev_ctx->miscdev->parent = priv->dev;
+	ret = misc_register(dev_ctx->miscdev);
+	if (ret)
+		return dev_err_probe(priv->dev, ret, "Failed to register misc device.");
+
+	ret = devm_add_action_or_reset(priv->dev, if_misc_deregister, dev_ctx->miscdev);
+	if (ret)
+		return dev_err_probe(priv->dev, ret,
+				     "Failed to add action to the misc-dev.");
 	return ret;
 }
 
+static int init_device_context(struct se_if_priv *priv, int ch_id,
+			       struct se_if_device_ctx **new_dev_ctx)
+{
+	struct se_if_device_ctx *dev_ctx;
+	int ret = 0;
+
+	dev_ctx = kzalloc(sizeof(*dev_ctx), GFP_KERNEL);
+
+	if (!dev_ctx)
+		return -ENOMEM;
+
+	dev_ctx->devname = kasprintf(GFP_KERNEL, "%s0_ch%d",
+				     get_se_if_name(priv->if_defs->se_if_type),
+				     ch_id);
+	if (!dev_ctx->devname) {
+		kfree(dev_ctx);
+		return -ENOMEM;
+	}
+
+	mutex_init(&dev_ctx->fops_lock);
+	dev_ctx->priv = priv;
+	*new_dev_ctx = dev_ctx;
+
+	list_add_tail(&dev_ctx->link, &priv->dev_ctx_list);
+	priv->active_devctx_count++;
+
+	ret = init_se_shared_mem(dev_ctx);
+	if (ret < 0) {
+		kfree(dev_ctx->devname);
+		kfree(dev_ctx);
+		*new_dev_ctx = NULL;
+	}
+
+	return ret;
+}
+
+static int se_ioctl_cmd_snd_rcv_rsp_handler(struct se_if_device_ctx *dev_ctx,
+					    u64 arg)
+{
+	struct se_ioctl_cmd_snd_rcv_rsp_info cmd_snd_rcv_rsp_info = {0};
+	struct se_api_msg *tx_msg __free(kfree) = NULL;
+	struct se_api_msg *rx_msg __free(kfree) = NULL;
+	struct se_if_priv *priv = dev_ctx->priv;
+	int err = 0;
+
+	if (copy_from_user(&cmd_snd_rcv_rsp_info, (u8 __user *)arg,
+			   sizeof(cmd_snd_rcv_rsp_info))) {
+		dev_err(priv->dev,
+			"%s: Failed to copy cmd_snd_rcv_rsp_info from user.",
+			dev_ctx->devname);
+		err = -EFAULT;
+		goto exit;
+	}
+
+	if (cmd_snd_rcv_rsp_info.tx_buf_sz < SE_MU_HDR_SZ) {
+		dev_err(priv->dev, "%s: User buffer too small(%d < %d)",
+			dev_ctx->devname, cmd_snd_rcv_rsp_info.tx_buf_sz, SE_MU_HDR_SZ);
+		err = -ENOSPC;
+		goto exit;
+	}
+
+	err = se_chk_tx_msg_hdr(priv, (struct se_msg_hdr *)cmd_snd_rcv_rsp_info.tx_buf);
+	if (err)
+		goto exit;
+
+	rx_msg = kzalloc(cmd_snd_rcv_rsp_info.rx_buf_sz, GFP_KERNEL);
+	if (!rx_msg) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	tx_msg = memdup_user(cmd_snd_rcv_rsp_info.tx_buf,
+			     cmd_snd_rcv_rsp_info.tx_buf_sz);
+	if (IS_ERR(tx_msg)) {
+		err = PTR_ERR(tx_msg);
+		goto exit;
+	}
+
+	if (tx_msg->header.tag != priv->if_defs->cmd_tag) {
+		err = -EINVAL;
+		goto exit;
+	}
+
+	if (tx_msg->header.ver == priv->if_defs->fw_api_ver &&
+	    get_load_fw_instance(priv)->is_fw_tobe_loaded) {
+		err = se_load_firmware(priv);
+		if (err) {
+			dev_err(priv->dev, "Could not send msg as FW is not loaded.");
+			err = -EPERM;
+			goto exit;
+		}
+	}
+	set_se_rcv_msg_timeout(priv, SE_RCV_MSG_LONG_TIMEOUT);
+
+	err = ele_msg_send_rcv(dev_ctx, tx_msg, cmd_snd_rcv_rsp_info.tx_buf_sz,
+			       rx_msg, cmd_snd_rcv_rsp_info.rx_buf_sz);
+	if (err < 0)
+		goto exit;
+
+	dev_dbg(priv->dev, "%s: %s %s.", dev_ctx->devname, __func__,
+		"message received, start transmit to user");
+
+	/* We may need to copy the output data to user before
+	 * delivering the completion message.
+	 */
+	err = se_dev_ctx_cpy_out_data(dev_ctx);
+	if (err < 0)
+		goto exit;
+
+	/* Copy data from the buffer */
+	print_hex_dump_debug("to user ", DUMP_PREFIX_OFFSET, 4, 4, rx_msg,
+			     cmd_snd_rcv_rsp_info.rx_buf_sz, false);
+
+	if (copy_to_user(cmd_snd_rcv_rsp_info.rx_buf, rx_msg,
+			 cmd_snd_rcv_rsp_info.rx_buf_sz)) {
+		dev_err(priv->dev, "%s: Failed to copy to user.", dev_ctx->devname);
+		err = -EFAULT;
+	}
+
+exit:
+
+	/* shared memory is allocated before this IOCTL */
+	se_dev_ctx_shared_mem_cleanup(dev_ctx);
+
+	if (copy_to_user((void __user *)arg, &cmd_snd_rcv_rsp_info,
+			 sizeof(cmd_snd_rcv_rsp_info))) {
+		dev_err(priv->dev, "%s: Failed to copy cmd_snd_rcv_rsp_info from user.",
+			dev_ctx->devname);
+		err = -EFAULT;
+	}
+
+	return err;
+}
+
+static int se_ioctl_get_mu_info(struct se_if_device_ctx *dev_ctx,
+				u64 arg)
+{
+	struct se_if_priv *priv = dev_ctx->priv;
+	struct se_ioctl_get_if_info if_info;
+	struct se_if_node *if_node;
+	int err = 0;
+
+	if_node = container_of(priv->if_defs, typeof(*if_node), if_defs);
+
+	if_info.se_if_id = 0;
+	if_info.interrupt_idx = 0;
+	if_info.tz = 0;
+	if_info.did = 0;
+	if_info.cmd_tag = priv->if_defs->cmd_tag;
+	if_info.rsp_tag = priv->if_defs->rsp_tag;
+	if_info.success_tag = priv->if_defs->success_tag;
+	if_info.base_api_ver = priv->if_defs->base_api_ver;
+	if_info.fw_api_ver = priv->if_defs->fw_api_ver;
+
+	dev_dbg(priv->dev, "%s: info [se_if_id: %d, irq_idx: %d, tz: 0x%x, did: 0x%x].",
+		dev_ctx->devname, if_info.se_if_id, if_info.interrupt_idx, if_info.tz,
+		if_info.did);
+
+	if (copy_to_user((u8 __user *)arg, &if_info, sizeof(if_info))) {
+		dev_err(priv->dev, "%s: Failed to copy mu info to user.",
+			dev_ctx->devname);
+		err = -EFAULT;
+	}
+
+	return err;
+}
+
+/*
+ * Copy a buffer of data to/from the user and return the address to use in
+ * messages
+ */
+static int se_ioctl_setup_iobuf_handler(struct se_if_device_ctx *dev_ctx,
+					u64 arg)
+{
+	struct se_shared_mem *shared_mem = NULL;
+	struct se_ioctl_setup_iobuf io = {0};
+	int err = 0;
+	u32 pos;
+
+	if (copy_from_user(&io, (u8 __user *)arg, sizeof(io))) {
+		dev_err(dev_ctx->priv->dev, "%s: Failed copy iobuf config from user.",
+			dev_ctx->devname);
+		return -EFAULT;
+	}
+
+	dev_dbg(dev_ctx->priv->dev, "%s: io [buf: %p(%d) flag: %x].", dev_ctx->devname,
+		io.user_buf, io.length, io.flags);
+
+	if (io.length == 0 || !io.user_buf) {
+		/*
+		 * Accept NULL pointers since some buffers are optional
+		 * in FW commands. In this case we should return 0 as
+		 * pointer to be embedded into the message.
+		 * Skip all data copy part of code below.
+		 */
+		io.ele_addr = 0;
+		goto copy;
+	}
+
+	/* No specific requirement for this buffer. */
+	shared_mem = &dev_ctx->se_shared_mem_mgmt.non_secure_mem;
+
+	/* Check there is enough space in the shared memory. */
+	dev_dbg(dev_ctx->priv->dev, "%s: req_size = %d, max_size= %d, curr_pos = %d",
+		dev_ctx->devname, round_up(io.length, 8u), shared_mem->size,
+		shared_mem->pos);
+
+	if (shared_mem->size < shared_mem->pos ||
+	    round_up(io.length, 8u) > (shared_mem->size - shared_mem->pos)) {
+		dev_err(dev_ctx->priv->dev, "%s: Not enough space in shared memory.",
+			dev_ctx->devname);
+		return -ENOMEM;
+	}
+
+	/* Allocate space in shared memory. 8 bytes aligned. */
+	pos = shared_mem->pos;
+	shared_mem->pos += round_up(io.length, 8u);
+	io.ele_addr = (u64)shared_mem->dma_addr + pos;
+
+	memset(shared_mem->ptr + pos, 0, io.length);
+	if ((io.flags & SE_IO_BUF_FLAGS_IS_INPUT) ||
+	    (io.flags & SE_IO_BUF_FLAGS_IS_IN_OUT)) {
+		/*
+		 * buffer is input:
+		 * copy data from user space to this allocated buffer.
+		 */
+		if (copy_from_user(shared_mem->ptr + pos, io.user_buf, io.length)) {
+			dev_err(dev_ctx->priv->dev,
+				"%s: Failed copy data to shared memory.",
+				dev_ctx->devname);
+			return -EFAULT;
+		}
+	}
+
+	err = add_b_desc_to_pending_list(shared_mem->ptr + pos, &io, dev_ctx);
+	if (err < 0)
+		dev_err(dev_ctx->priv->dev, "%s: Failed to allocate/link b_desc.",
+			dev_ctx->devname);
+
+copy:
+	/* Provide the EdgeLock Enclave address to user space only if success.*/
+	if (copy_to_user((u8 __user *)arg, &io, sizeof(io))) {
+		dev_err(dev_ctx->priv->dev, "%s: Failed to copy iobuff setup to user.",
+			dev_ctx->devname);
+		err = -EFAULT;
+	}
+
+	return err;
+}
+
+/* IOCTL to provide SoC information */
+static int se_ioctl_get_se_soc_info_handler(struct se_if_device_ctx *dev_ctx, u64 arg)
+{
+	struct se_ioctl_get_soc_info soc_info;
+	int err = -EINVAL;
+
+	soc_info.soc_id = get_se_soc_id(dev_ctx->priv);
+	soc_info.soc_rev = var_se_info.soc_rev;
+
+	err = copy_to_user((u8 __user *)arg, (u8 *)(&soc_info), sizeof(soc_info));
+	if (err) {
+		dev_err(dev_ctx->priv->dev, "%s: Failed to copy soc info to user.",
+			dev_ctx->devname);
+		err = -EFAULT;
+	}
+
+	return err;
+}
+
+/*
+ * File operations for user-space
+ */
+
+/* Write a message to the MU. */
+static ssize_t se_if_fops_write(struct file *fp, const char __user *buf,
+				size_t size, loff_t *ppos)
+{
+	struct se_if_device_ctx *dev_ctx = fp->private_data;
+	struct se_api_msg *tx_msg __free(kfree) = NULL;
+	struct se_if_priv *priv = dev_ctx->priv;
+	int err;
+
+	dev_dbg(priv->dev, "%s: write from buf (%p)%zu, ppos=%lld.", dev_ctx->devname,
+		buf, size, ((ppos) ? *ppos : 0));
+
+	scoped_cond_guard(mutex_intr, return -EBUSY, &dev_ctx->fops_lock) {
+		if (dev_ctx != priv->cmd_receiver_clbk_hdl.dev_ctx)
+			return -EINVAL;
+
+		err = se_chk_tx_msg_hdr(priv, (struct se_msg_hdr *)buf);
+		if (err)
+			return err;
+
+		if (size < SE_MU_HDR_SZ) {
+			dev_err(priv->dev, "%s: User buffer too small(%zu < %d).",
+				dev_ctx->devname, size, SE_MU_HDR_SZ);
+			return -ENOSPC;
+		}
+
+		tx_msg = memdup_user(buf, size);
+		if (IS_ERR(tx_msg))
+			return PTR_ERR(tx_msg);
+
+		print_hex_dump_debug("from user ", DUMP_PREFIX_OFFSET, 4, 4,
+				     tx_msg, size, false);
+
+		err = ele_msg_send(dev_ctx, tx_msg, size);
+
+		return err;
+	}
+}
+
+/*
+ * Read a message from the MU.
+ * Blocking until a message is available.
+ */
+static ssize_t se_if_fops_read(struct file *fp, char __user *buf, size_t size,
+			       loff_t *ppos)
+{
+	struct se_if_device_ctx *dev_ctx = fp->private_data;
+	struct se_if_priv *priv = dev_ctx->priv;
+	int err;
+
+	dev_dbg(priv->dev, "%s: read to buf %p(%zu), ppos=%lld.", dev_ctx->devname,
+		buf, size, ((ppos) ? *ppos : 0));
+
+	scoped_cond_guard(mutex_intr, return -EBUSY, &dev_ctx->fops_lock) {
+		if (dev_ctx != priv->cmd_receiver_clbk_hdl.dev_ctx) {
+			err = -EINVAL;
+			goto exit;
+		}
+
+		err = ele_msg_rcv(dev_ctx, &priv->cmd_receiver_clbk_hdl);
+		if (err < 0) {
+			dev_err(priv->dev, "%s: Err[0x%x]:Interrupted by signal."
+				"Current active dev-ctx count = %d.",
+				dev_ctx->devname, err, dev_ctx->priv->active_devctx_count);
+			goto exit;
+		}
+
+		/* We may need to copy the output data to user before
+		 * delivering the completion message.
+		 */
+		err = se_dev_ctx_cpy_out_data(dev_ctx);
+		if (err < 0)
+			goto exit;
+
+		/* Copy data from the buffer */
+		print_hex_dump_debug("to user ", DUMP_PREFIX_OFFSET, 4, 4,
+				     priv->cmd_receiver_clbk_hdl.rx_msg,
+				     priv->cmd_receiver_clbk_hdl.rx_msg_sz,
+				     false);
+
+		if (copy_to_user(buf, priv->cmd_receiver_clbk_hdl.rx_msg,
+				 priv->cmd_receiver_clbk_hdl.rx_msg_sz)) {
+			dev_err(priv->dev, "%s: Failed to copy to user.",
+				dev_ctx->devname);
+			err = -EFAULT;
+		} else {
+			err = priv->cmd_receiver_clbk_hdl.rx_msg_sz;
+		}
+exit:
+		priv->cmd_receiver_clbk_hdl.rx_msg_sz = 0;
+
+		se_dev_ctx_shared_mem_cleanup(dev_ctx);
+
+		return err;
+	}
+}
+
+/* Open a character device. */
+static int se_if_fops_open(struct inode *nd, struct file *fp)
+{
+	struct miscdevice *miscdev = fp->private_data;
+	struct se_if_device_ctx *misc_dev_ctx;
+	struct se_if_device_ctx *dev_ctx;
+	struct se_if_priv *priv;
+	int err = 0;
+
+	priv = dev_get_drvdata(miscdev->parent);
+	misc_dev_ctx = priv->priv_dev_ctx;
+
+	scoped_cond_guard(mutex_intr, return -EBUSY, &misc_dev_ctx->fops_lock) {
+		priv->dev_ctx_mono_count++;
+		err = init_device_context(priv,
+					  priv->dev_ctx_mono_count ?
+					  priv->dev_ctx_mono_count
+					  : priv->dev_ctx_mono_count++,
+					  &dev_ctx);
+		if (err)
+			dev_err(priv->dev, "Failed[0x%x] to create dev-ctx.", err);
+		else
+			fp->private_data = dev_ctx;
+
+		return err;
+	}
+}
+
+/* Close a character device. */
+static int se_if_fops_close(struct inode *nd, struct file *fp)
+{
+	struct se_if_device_ctx *dev_ctx = fp->private_data;
+	struct se_if_priv *priv = dev_ctx->priv;
+
+	scoped_cond_guard(mutex_intr, return -EBUSY, &dev_ctx->fops_lock) {
+		/* check if this device was registered as command receiver. */
+		if (priv->cmd_receiver_clbk_hdl.dev_ctx == dev_ctx) {
+			priv->cmd_receiver_clbk_hdl.dev_ctx = NULL;
+			kfree(priv->cmd_receiver_clbk_hdl.rx_msg);
+			priv->cmd_receiver_clbk_hdl.rx_msg = NULL;
+		}
+
+		se_dev_ctx_shared_mem_cleanup(dev_ctx);
+		cleanup_se_shared_mem(dev_ctx);
+
+		priv->active_devctx_count--;
+		list_del(&dev_ctx->link);
+
+		kfree(dev_ctx->devname);
+		kfree(dev_ctx);
+	}
+
+	return 0;
+}
+
+/* IOCTL entry point of a character device */
+static long se_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
+{
+	struct se_if_device_ctx *dev_ctx = fp->private_data;
+	struct se_if_priv *priv = dev_ctx->priv;
+	long err;
+
+	/* Prevent race during change of device context */
+	scoped_cond_guard(mutex_intr, return -EBUSY, &dev_ctx->fops_lock) {
+		switch (cmd) {
+		case SE_IOCTL_ENABLE_CMD_RCV:
+			if (!priv->cmd_receiver_clbk_hdl.dev_ctx) {
+				if (!priv->cmd_receiver_clbk_hdl.rx_msg) {
+					priv->cmd_receiver_clbk_hdl.rx_msg =
+						kzalloc(MAX_NVM_MSG_LEN,
+							GFP_KERNEL);
+					if (!priv->cmd_receiver_clbk_hdl.rx_msg) {
+						err = -ENOMEM;
+						break;
+					}
+				}
+				priv->cmd_receiver_clbk_hdl.rx_msg_sz = MAX_NVM_MSG_LEN;
+				priv->cmd_receiver_clbk_hdl.dev_ctx = dev_ctx;
+				err = 0;
+			} else {
+				err = -EBUSY;
+			}
+			break;
+		case SE_IOCTL_GET_MU_INFO:
+			err = se_ioctl_get_mu_info(dev_ctx, arg);
+			break;
+		case SE_IOCTL_SETUP_IOBUF:
+			err = se_ioctl_setup_iobuf_handler(dev_ctx, arg);
+			break;
+		case SE_IOCTL_GET_SOC_INFO:
+			err = se_ioctl_get_se_soc_info_handler(dev_ctx, arg);
+			break;
+		case SE_IOCTL_CMD_SEND_RCV_RSP:
+			err = se_ioctl_cmd_snd_rcv_rsp_handler(dev_ctx, arg);
+			break;
+		default:
+			err = -EINVAL;
+			dev_dbg(priv->dev, "%s: IOCTL %.8x not supported.",
+				dev_ctx->devname, cmd);
+		}
+	}
+
+	return err;
+}
+
+/* Char driver setup */
+static const struct file_operations se_if_fops = {
+	.open		= se_if_fops_open,
+	.owner		= THIS_MODULE,
+	.release	= se_if_fops_close,
+	.unlocked_ioctl = se_ioctl,
+	.read		= se_if_fops_read,
+	.write		= se_if_fops_write,
+};
+
 /* interface for managed res to free a mailbox channel */
 static void if_mbox_free_channel(void *mbox_chan)
 {
@@ -246,7 +958,7 @@ static int se_if_request_channel(struct device *dev, struct mbox_chan **chan,
 	ret = devm_add_action_or_reset(dev, if_mbox_free_channel, t_chan);
 	if (ret)
 		return dev_err_probe(dev, -EPERM,
-				     "Failed to add-action for removal of mbox: %s\n",
+				     "Failed to add-action for removal of mbox: %s.",
 				     name);
 	*chan = t_chan;
 
@@ -255,6 +967,7 @@ static int se_if_request_channel(struct device *dev, struct mbox_chan **chan,
 
 static void se_if_probe_cleanup(void *plat_dev)
 {
+	struct se_if_device_ctx *dev_ctx, *t_dev_ctx;
 	struct platform_device *pdev = plat_dev;
 	struct se_fw_load_info *load_fw;
 	struct device *dev = &pdev->dev;
@@ -279,6 +992,13 @@ static void se_if_probe_cleanup(void *plat_dev)
 		load_fw->imem.buf = NULL;
 	}
 
+	if (priv->dev_ctx_mono_count) {
+		list_for_each_entry_safe(dev_ctx, t_dev_ctx, &priv->dev_ctx_list, link) {
+			list_del(&dev_ctx->link);
+			priv->active_devctx_count--;
+		}
+	}
+
 	/*
 	 * No need to check, if reserved memory is allocated
 	 * before calling for its release. Or clearing the
@@ -319,6 +1039,7 @@ static int se_if_probe(struct platform_device *pdev)
 	priv->se_mb_cl.tx_block		= false;
 	priv->se_mb_cl.knows_txdone	= true;
 	priv->se_mb_cl.rx_callback	= se_if_rx_callback;
+	set_se_rcv_msg_timeout(priv, SE_RCV_MSG_DEFAULT_TIMEOUT);
 
 	ret = se_if_request_channel(dev, &priv->tx_chan, &priv->se_mb_cl, MBOX_TX_NAME);
 	if (ret)
@@ -340,6 +1061,7 @@ static int se_if_probe(struct platform_device *pdev)
 					     "Unable to get sram pool = %s.",
 					     if_node->pool_name);
 	}
+	INIT_LIST_HEAD(&priv->dev_ctx_list);
 
 	if (if_node->reserved_dma_ranges) {
 		ret = of_reserved_mem_device_init(dev);
@@ -348,7 +1070,7 @@ static int se_if_probe(struct platform_device *pdev)
 					    "Failed to init reserved memory region.");
 	}
 
-	ret = init_misc_device_context(priv, 0, &priv->priv_dev_ctx);
+	ret = init_misc_device_context(priv, 0, &priv->priv_dev_ctx, &se_if_fops);
 	if (ret)
 		return dev_err_probe(dev, ret,
 				     "Failed[0x%x] to create device contexts.",
@@ -389,6 +1111,7 @@ static int se_suspend(struct device *dev)
 	struct se_fw_load_info *load_fw;
 	int ret = 0;
 
+	set_se_rcv_msg_timeout(priv, SE_RCV_MSG_DEFAULT_TIMEOUT);
 	load_fw = get_load_fw_instance(priv);
 
 	if (load_fw->imem_mgmt)
diff --git a/drivers/firmware/imx/se_ctrl.h b/drivers/firmware/imx/se_ctrl.h
index b5e7705e2f26..5fcdcfe3e8e5 100644
--- a/drivers/firmware/imx/se_ctrl.h
+++ b/drivers/firmware/imx/se_ctrl.h
@@ -14,6 +14,7 @@
 #define SE_MSG_WORD_SZ			0x4
 
 #define RES_STATUS(x)			FIELD_GET(0x000000ff, x)
+#define MAX_DATA_SIZE_PER_USER		(65 * 1024)
 #define MAX_NVM_MSG_LEN			(256)
 #define MESSAGING_VERSION_6		0x6
 #define MESSAGING_VERSION_7		0x7
@@ -37,10 +38,38 @@ struct se_imem_buf {
 	u32 state;
 };
 
+struct se_buf_desc {
+	u8 *shared_buf_ptr;
+	void __user *usr_buf_ptr;
+	u32 size;
+	struct list_head link;
+};
+
+struct se_shared_mem {
+	dma_addr_t dma_addr;
+	u32 size;
+	u32 pos;
+	u8 *ptr;
+};
+
+struct se_shared_mem_mgmt_info {
+	struct list_head pending_in;
+	struct list_head pending_out;
+
+	struct se_shared_mem non_secure_mem;
+};
+
 /* Private struct for each char device instance. */
 struct se_if_device_ctx {
 	struct se_if_priv *priv;
+	struct miscdevice *miscdev;
 	const char *devname;
+
+	/* process one file operation at a time. */
+	struct mutex fops_lock;
+
+	struct se_shared_mem_mgmt_info se_shared_mem_mgmt;
+	struct list_head link;
 };
 
 /* Header of the messages exchange with the EdgeLock Enclave */
@@ -89,6 +118,10 @@ struct se_if_priv {
 	const struct se_if_defines *if_defs;
 
 	struct se_if_device_ctx *priv_dev_ctx;
+	struct list_head dev_ctx_list;
+	u32 active_devctx_count;
+	u32 dev_ctx_mono_count;
+	u32 se_rcv_msg_timeout_ms;
 };
 
 char *get_se_if_name(u8 se_if_id);
diff --git a/include/uapi/linux/se_ioctl.h b/include/uapi/linux/se_ioctl.h
new file mode 100644
index 000000000000..0c948bdc8c26
--- /dev/null
+++ b/include/uapi/linux/se_ioctl.h
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause*/
+/*
+ * Copyright 2025 NXP
+ */
+
+#ifndef SE_IOCTL_H
+#define SE_IOCTL_H
+
+#include <linux/types.h>
+
+#define SE_TYPE_STR_DBG			"dbg"
+#define SE_TYPE_STR_HSM			"hsm"
+#define SE_TYPE_ID_UNKWN		0x0
+#define SE_TYPE_ID_DBG			0x1
+#define SE_TYPE_ID_HSM			0x2
+/* IOCTL definitions. */
+
+struct se_ioctl_setup_iobuf {
+	void __user *user_buf;
+	__u32 length;
+	__u32 flags;
+	__u64 ele_addr;
+};
+
+struct se_ioctl_shared_mem_cfg {
+	__u32 base_offset;
+	__u32 size;
+};
+
+struct se_ioctl_get_if_info {
+	__u8 se_if_id;
+	__u8 interrupt_idx;
+	__u8 tz;
+	__u8 did;
+	__u8 cmd_tag;
+	__u8 rsp_tag;
+	__u8 success_tag;
+	__u8 base_api_ver;
+	__u8 fw_api_ver;
+};
+
+struct se_ioctl_cmd_snd_rcv_rsp_info {
+	__u32 __user *tx_buf;
+	int tx_buf_sz;
+	__u32 __user *rx_buf;
+	int rx_buf_sz;
+};
+
+struct se_ioctl_get_soc_info {
+	__u16 soc_id;
+	__u16 soc_rev;
+};
+
+/* IO Buffer Flags */
+#define SE_IO_BUF_FLAGS_IS_OUTPUT	(0x00u)
+#define SE_IO_BUF_FLAGS_IS_INPUT	(0x01u)
+#define SE_IO_BUF_FLAGS_USE_SEC_MEM	(0x02u)
+#define SE_IO_BUF_FLAGS_USE_SHORT_ADDR	(0x04u)
+#define SE_IO_BUF_FLAGS_IS_IN_OUT	(0x10u)
+
+/* IOCTLS */
+#define SE_IOCTL			0x0A /* like MISC_MAJOR. */
+
+/*
+ * ioctl to designated the current fd as logical-reciever.
+ * This is ioctl is send when the nvm-daemon, a slave to the
+ * firmware is started by the user.
+ */
+#define SE_IOCTL_ENABLE_CMD_RCV	_IO(SE_IOCTL, 0x01)
+
+/*
+ * ioctl to get the buffer allocated from the memory, which is shared
+ * between kernel and FW.
+ * Post allocation, the kernel tagged the allocated memory with:
+ *  Output
+ *  Input
+ *  Input-Output
+ *  Short address
+ *  Secure-memory
+ */
+#define SE_IOCTL_SETUP_IOBUF	_IOWR(SE_IOCTL, 0x03, struct se_ioctl_setup_iobuf)
+
+/*
+ * ioctl to get the mu information, that is used to exchange message
+ * with FW, from user-spaced.
+ */
+#define SE_IOCTL_GET_MU_INFO	_IOR(SE_IOCTL, 0x04, struct se_ioctl_get_if_info)
+/*
+ * ioctl to get SoC Info from user-space.
+ */
+#define SE_IOCTL_GET_SOC_INFO      _IOR(SE_IOCTL, 0x06, struct se_ioctl_get_soc_info)
+
+/*
+ * ioctl to send command and receive response from user-space.
+ */
+#define SE_IOCTL_CMD_SEND_RCV_RSP _IOWR(SE_IOCTL, 0x07, struct se_ioctl_cmd_snd_rcv_rsp_info)
+#endif

-- 
2.43.0



From pankaj.gupta at nxp.com  Tue Dec  2 22:48:11 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Wed, 03 Dec 2025 12:18:11 +0530
Subject: [PATCH v20 6/7] arm64: dts: imx8ulp: add secure enclave node
In-Reply-To: <20251203-imx-se-if-v20-0-a04a25c4255f@nxp.com>
References: <20251203-imx-se-if-v20-0-a04a25c4255f@nxp.com>
Message-ID: <20251203-imx-se-if-v20-6-a04a25c4255f@nxp.com>

Add support for NXP secure enclave called EdgeLock Enclave firmware (se-fw)
for imx8ulp-evk.

Add label sram0 for sram at 2201f000 and add secure-enclave node

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
 arch/arm64/boot/dts/freescale/imx8ulp.dtsi | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8ulp.dtsi b/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
index 13b01f3aa2a4..10a4779dd24c 100644
--- a/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
- * Copyright 2021 NXP
+ * Copyright 2021, 2025 NXP
  */
 
 #include <dt-bindings/clock/imx8ulp-clock.h>
@@ -154,7 +154,7 @@ sosc: clock-sosc {
 		#clock-cells = <0>;
 	};
 
-	sram at 2201f000 {
+	sram0: sram at 2201f000 {
 		compatible = "mmio-sram";
 		reg = <0x0 0x2201f000 0x0 0x1000>;
 
@@ -186,6 +186,13 @@ scmi_sensor: protocol at 15 {
 				#thermal-sensor-cells = <1>;
 			};
 		};
+
+		hsm0: secure-enclave {
+			 compatible = "fsl,imx8ulp-se-ele-hsm";
+			 mbox-names = "tx", "rx";
+			 mboxes = <&s4muap 0 0>, <&s4muap 1 0>;
+			 sram = <&sram0>;
+		 };
 	};
 
 	cm33: remoteproc-cm33 {

-- 
2.43.0



From pankaj.gupta at nxp.com  Tue Dec  2 22:48:12 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Wed, 03 Dec 2025 12:18:12 +0530
Subject: [PATCH v20 7/7] arm64: dts: imx8ulp-evk: add reserved memory
 property
In-Reply-To: <20251203-imx-se-if-v20-0-a04a25c4255f@nxp.com>
References: <20251203-imx-se-if-v20-0-a04a25c4255f@nxp.com>
Message-ID: <20251203-imx-se-if-v20-7-a04a25c4255f@nxp.com>

Reserve 1MB of DDR memory region due to EdgeLock Enclave's hardware
limitation restricting access to DDR addresses from 0x80000000
to 0xafffffff.

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
 arch/arm64/boot/dts/freescale/imx8ulp-evk.dts | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8ulp-evk.dts b/arch/arm64/boot/dts/freescale/imx8ulp-evk.dts
index 290a49bea2f7..10aaf02f8ea7 100644
--- a/arch/arm64/boot/dts/freescale/imx8ulp-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8ulp-evk.dts
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
- * Copyright 2021 NXP
+ * Copyright 2021, 2025 NXP
  */
 
 /dts-v1/;
@@ -37,6 +37,12 @@ linux,cma {
 			linux,cma-default;
 		};
 
+		ele_reserved: memory at 90000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x90000000 0 0x100000>;
+			no-map;
+		};
+
 		m33_reserved: noncacheable-section at a8600000 {
 			reg = <0 0xa8600000 0 0x1000000>;
 			no-map;
@@ -259,6 +265,10 @@ &usdhc0 {
 	status = "okay";
 };
 
+&hsm0 {
+	memory-region = <&ele_reserved>;
+};
+
 &fec {
 	pinctrl-names = "default", "sleep";
 	pinctrl-0 = <&pinctrl_enet>;

-- 
2.43.0



From angelogioacchino.delregno at collabora.com  Tue Dec  2 22:50:29 2025
From: angelogioacchino.delregno at collabora.com (AngeloGioacchino Del Regno)
Date: Wed, 3 Dec 2025 07:50:29 +0100
Subject: [PATCH v4 3/4] arm64: dts: mediatek: add device tree for Tungsten
 510 board
In-Reply-To: <20251202-review-v4-3-93f5cd2a0d4a@gmail.com>
References: <20251202-review-v4-0-93f5cd2a0d4a@gmail.com>
 <20251202-review-v4-3-93f5cd2a0d4a@gmail.com>
Message-ID: <e9edd5f2-c0ff-48fa-baf9-659dd0073e3d@collabora.com>

Il 02/12/25 23:08, Gary Bisson ha scritto:
> Add device tree to support Ezurio Tungsten 510 (MT8370) SMARC SOM [1] +
> Universal SMARC carrier board [2].
> It includes support for the MIPI-DSI BD070LIC3 display which uses the
> Tianma TM070JDHG30 panel + TI SN65DSI84 MIPI-DSI to LVDS bridge [3].
> 
> [1] https://www.ezurio.com/product/tungsten510-smarc
> [2] https://www.ezurio.com/system-on-module/accessories/universal-smarc-carrier
> [3] https://www.ezurio.com/product/bd070lic3-7-touchscreen-display
> 
> Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
> 

Hello!

Thanks for the patch, that's mostly good. Though, there are a few comments, please
check below.

> ---
> Changes in v2:
> - Updated nodes to be generic (pmic, i2c, usb-typec)
> Changed in v3:
> - None
> Changed in v4:
> - Fixed remaining DTB warnings
> ---
>   arch/arm64/boot/dts/mediatek/Makefile              |    1 +
>   .../boot/dts/mediatek/mt8370-tungsten-smarc.dts    |   14 +
>   .../boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi   | 1510 ++++++++++++++++++++
>   3 files changed, 1525 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile
> index a4df4c21399e..30d169a31b10 100644
> --- a/arch/arm64/boot/dts/mediatek/Makefile
> +++ b/arch/arm64/boot/dts/mediatek/Makefile
> @@ -99,6 +99,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8195-demo.dtb
>   dtb-$(CONFIG_ARCH_MEDIATEK) += mt8195-evb.dtb
>   dtb-$(CONFIG_ARCH_MEDIATEK) += mt8365-evk.dtb
>   dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-genio-510-evk.dtb
> +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-tungsten-smarc.dtb
>   dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-genio-1200-evk.dtb
>   dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-genio-700-evk.dtb
>   dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-kontron-3-5-sbc-i1200.dtb
> diff --git a/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts b/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts
> new file mode 100644
> index 000000000000..d713ef77df3a
> --- /dev/null
> +++ b/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts
> @@ -0,0 +1,14 @@
> +// SPDX-License-Identifier: (GPL-2.0 OR MIT)
> +/*
> + * Copyright (C) 2025 Ezurio LLC
> + * Author: Gary Bisson <bisson.gary at gmail.com>
> + */
> +/dts-v1/;
> +#include "mt8370.dtsi"
> +#include "mt83x0-tungsten-smarc.dtsi"
> +
> +/ {
> +	model = "Ezurio Tungsten510 SMARC (MT8370)";
> +	compatible = "ezurio,mt8370-tungsten-smarc", "mediatek,mt8370",
> +		     "mediatek,mt8188";
> +};
> diff --git a/arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi b/arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi
> new file mode 100644
> index 000000000000..d71148d78781
> --- /dev/null
> +++ b/arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi
> @@ -0,0 +1,1510 @@
> +// SPDX-License-Identifier: (GPL-2.0 OR MIT)
> +/*
> + * Copyright (C) 2025 Ezurio LLC
> + * Author: Gary Bisson <bisson.gary at gmail.com>
> + */
> +

..snip..

> +
> +&disp_dsi0 {
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +	status = "okay";
> +
> +	ports {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		port at 0 {
> +			reg = <0>;
> +			dsi0_in: endpoint {
> +				remote-endpoint = <&dither0_out>;
> +			};
> +		};
> +
> +		port at 1 {
> +			reg = <1>;
> +			dsi0_out: endpoint {
> +				remote-endpoint = <&sn65dsi84_bridge_in>;
> +			};
> +		};
> +	};
> +};
> +
> +&dither0_in {
> +	remote-endpoint = <&postmask0_out>;
> +};
> +
> +&dither0_out {
> +	remote-endpoint = <&dsi0_in>;
> +};
> +
> +&eth {
> +	phy-mode ="rgmii-id";
> +	phy-handle = <&ethernet_phy0>;
> +	pinctrl-names = "default", "sleep";
> +	pinctrl-0 = <&eth_default_pins>;
> +	pinctrl-1 = <&eth_sleep_pins>;
> +	mediatek,mac-wol;
> +	snps,reset-gpio = <&pio 27 GPIO_ACTIVE_LOW>;
> +	snps,reset-active-low;
> +	snps,reset-delays-us = <0 11000 1000>;
> +	status = "okay";
> +};
> +
> +&eth_mdio {
> +	ethernet_phy0: ethernet-phy at 7 {
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reg = <0x7>;
> +		interrupts-extended = <&pio 148 IRQ_TYPE_LEVEL_LOW>;
> +	};
> +};
> +
> +&gamma0_out {
> +	remote-endpoint = <&postmask0_in>;
> +};
> +
> +&gpu {
> +	mali-supply = <&mt6359_vproc2_buck_reg>;
> +	status = "okay";
> +};
> +
> +&i2c0 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&i2c0_pins>;
> +	clock-frequency = <100000>;
> +	status = "okay";
> +
> +	i2c-mux at 73 {
> +		compatible = "nxp,pca9546";
> +		reg = <0x73>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&i2c0_mux_pins>;
> +		reset-gpios = <&pio 6 GPIO_ACTIVE_LOW>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		i2c_mux_gp_0: i2c at 0 {
> +			clock-frequency = <100000>;
> +			reg = <0>;

reg = <0>;
clock-frequency = ...

> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +		};
> +
> +		i2c_mux_gp_1: i2c at 1 {
> +			clock-frequency = <100000>;
> +			reg = <1>;
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +		};
> +
> +		i2c_mux_gp_2: i2c at 2 {
> +			clock-frequency = <100000>;
> +			reg = <2>;
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +		};
> +
> +		i2c_mux_gp_3: i2c at 3 {
> +			clock-frequency = <100000>;
> +			reg = <3>;
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +		};
> +	};
> +};
> +
> +&i2c1 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&i2c1_pins>;
> +	clock-frequency = <400000>;
> +	status = "okay";
> +};
> +
> +&i2c2 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&i2c2_pins>;
> +	clock-frequency = <400000>;
> +	status = "okay";
> +
> +	i2c-mux at 73 {
> +		compatible = "nxp,pca9546";
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&i2c_mux_smarc_lcd_pins>;
> +		reg = <0x73>;
> +		reset-gpios = <&pio 5 GPIO_ACTIVE_LOW>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		i2c_mux_lcd_0: i2c at 0 {
> +			clock-frequency = <100000>;
> +			reg = <0>;
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +		};
> +
> +		i2c_mux_lcd_1: i2c at 1 {
> +			clock-frequency = <100000>;
> +			reg = <1>;
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +		};
> +
> +		i2c_mux_lcd_2: i2c at 2 {
> +			clock-frequency = <100000>;
> +			reg = <2>;
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +		};
> +
> +		i2c_mux_lcd_3: i2c at 3 {
> +			clock-frequency = <100000>;
> +			reg = <3>;
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +		};
> +	};
> +};
> +
> +&i2c3 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&i2c3_pins>;
> +	clock-frequency = <400000>;
> +	status = "okay";
> +};
> +
> +&i2c4 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&i2c4_pins>;
> +	clock-frequency = <400000>;
> +	status = "okay";
> +};
> +
> +&i2c_mux_gp_0 {
> +	rv3028: rtc at 52 {
> +		compatible = "microcrystal,rv3028";
> +		reg = <0x52>;
> +		interrupts-extended = <&pio 42 IRQ_TYPE_LEVEL_LOW>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&rv3028_pins>;
> +		#clock-cells = <0>;
> +		wakeup-source;
> +	};
> +};
> +
> +&i2c_mux_gp_1 {
> +	usb-typec at 60 {
> +		compatible = "ti,hd3ss3220";

reg always goes after compatible.

> +		interrupts-extended = <&pio 45 IRQ_TYPE_LEVEL_LOW>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&hd3ss3220_pins>;
> +		reg = <0x60>;
> +
> +		ports {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +
> +			port at 0 {
> +				reg = <0>;
> +				hd3ss3220_in_ep: endpoint {
> +					remote-endpoint = <&ss_ep>;
> +				};
> +			};
> +
> +			port at 1 {
> +				reg = <1>;
> +				hd3ss3220_out_ep: endpoint {
> +					remote-endpoint = <&usb_role_switch>;
> +				};
> +			};
> +		};
> +	};
> +};
> +
> +&i2c_mux_gp_2 {
> +	codec at 1a {

compatible
reg
clocks
gpio-cfg

supplies

P.S.: Please read
https://docs.kernel.org/devicetree/bindings/dts-coding-style.html

> +		#sound-dai-cells = <0>;
> +		AVDD-supply = <&reg_1v8>;
> +		CPVDD-supply = <&reg_1v8>;
> +		DBVDD-supply = <&reg_3v3>;
> +		DCVDD-supply = <&reg_1v8>;
> +		MICVDD-supply = <&reg_3v3>;
> +		PLLVDD-supply = <&reg_1v8>;
> +		SPKVDD1-supply = <&reg_5v>;
> +		SPKVDD2-supply = <&reg_5v>;
> +		clocks = <&topckgen CLK_TOP_I2SO1>;
> +		compatible = "wlf,wm8962";
> +		gpio-cfg = <
> +			0x0000 /* n/c */
> +			0x0000 /* gpio2: */
> +			0x0000 /* gpio3: */
> +			0x0000 /* n/c */
> +			0x8081 /* gpio5:HP detect */
> +			0x8095 /* gpio6:Mic detect */
> +		>;
> +		reg = <0x1a>;
> +	};
> +};
> +
> +&i2c_mux_lcd_2 {
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +
> +	bridge at 2c {
> +		compatible = "ti,sn65dsi84";
> +		reg = <0x2c>;
> +		enable-gpios = <&pio 25 GPIO_ACTIVE_HIGH>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&dsi0_sn65dsi84_pins>;
> +
> +		ports {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +
> +			port at 0 {
> +				reg = <0>;
> +
> +				sn65dsi84_bridge_in: endpoint {
> +					remote-endpoint = <&dsi0_out>;
> +					data-lanes = <1 2 3 4>;
> +				};
> +			};
> +
> +			port at 2 {
> +				reg = <2>;
> +
> +				sn65dsi84_bridge_out: endpoint {
> +					remote-endpoint = <&dsi0_panel_in>;
> +				};
> +			};
> +		};
> +	};
> +
> +	touchscren at 5d {
> +		compatible = "goodix,gt911";
> +		reg = <0x5d>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&ts_dsi0_goodix_pins>;
> +		interrupts-extended = <&pio 146 IRQ_TYPE_LEVEL_HIGH>;
> +		irq-gpios = <&pio 146 GPIO_ACTIVE_HIGH>;
> +		reset-gpios = <&pio 7 GPIO_ACTIVE_HIGH>;
> +	};
> +};
> +
> +&mfg0 {
> +	domain-supply = <&mt6359_vproc2_buck_reg>;
> +};
> +
> +&mfg1 {
> +	domain-supply = <&mt6359_vsram_others_ldo_reg>;
> +};
> +
> +&mmc0 {
> +	status = "okay";
> +	pinctrl-names = "default", "state_uhs";
> +	pinctrl-0 = <&mmc0_default_pins>;
> +	pinctrl-1 = <&mmc0_uhs_pins>;
> +	bus-width = <8>;
> +	max-frequency = <200000000>;
> +	cap-mmc-highspeed;
> +	cap-mmc-hw-reset;
> +	mmc-hs200-1_8v;
> +	mmc-hs400-1_8v;
> +	supports-cqe;
> +	cap-mmc-hw-reset;

You added cap-mmc-hw-reset twice.

> +	no-sdio;
> +	no-sd;
> +	hs400-ds-delay = <0x1481b>;
> +	vmmc-supply = <&mt6359_vemc_1_ldo_reg>;
> +	vqmmc-supply = <&mt6359_vufs_ldo_reg>;
> +	non-removable;

Also, please reorder by name:

bus-width ...
cap-mmc-highspeed;
cap-mmc-hw-reset;
hs400-ds-delay....
max-frequency ....
mmc-hs200-1_8v;
mmc-hs400-1_8v;
no-sd;
no-sdio;
non-removable;
supports-cqe;

pinctrl properties

power supplies

status

> +};
> +
> +&mmc1 {
> +	status = "okay";
> +	pinctrl-names = "default", "state_uhs";
> +	pinctrl-0 = <&mmc1_default_pins>;
> +	pinctrl-1 = <&mmc1_uhs_pins>;
> +	bus-width = <4>;
> +	max-frequency = <200000000>;
> +	cap-sd-highspeed;
> +	sd-uhs-sdr50;
> +	sd-uhs-sdr104;
> +	cd-gpios = <&pio 2 GPIO_ACTIVE_LOW>;
> +	vqmmc-supply = <&mt6359_vsim1_ldo_reg>;
> +	vmmc-supply = <&sdcard_en_3v3>;
> +};
> +
> +&mmc2 {
> +	status = "okay";

status at the end please

> +	pinctrl-names = "default", "state_uhs", "state_eint";
> +	pinctrl-0 = <&mmc2_default_pins>;
> +	pinctrl-1 = <&mmc2_uhs_pins>;
> +	pinctrl-2 = <&mmc2_eint_pins>;

Sorry, but I truly hate /delete-property/.

> +	/delete-property/ interrupts;
> +	interrupt-names = "msdc", "sdio_wakeup";
> +	interrupts-extended = <&gic GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH 0>,
> +			      <&pio 172 IRQ_TYPE_LEVEL_LOW>;

You're lucky in this case, though, because you're the first user of MMC2! :-)

The solution here is:
  - Change the interrupts property in mt8188.dtsi on mmc at 1125000 to
    `interrupts-extended = <&gic GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH 0>;`
  - Override it here without `/delete-property/ interrupts;`

> +	bus-width = <4>;

Please order the properties by name (bar X-supply, Y-pwrseq, status that go at
the end).

> +	max-frequency = <200000000>;
> +	cap-sd-highspeed;
> +	sd-uhs-sdr104;
> +	keep-power-in-suspend;
> +	wakeup-source;
> +	cap-sdio-irq;
> +	no-mmc;
> +	no-sd;
> +	non-removable;
> +	vmmc-supply = <&mt6359_vcn33_2_bt_ldo_reg>;
> +	vqmmc-supply = <&mt6359_vcn18_ldo_reg>;
> +	mmc-pwrseq = <&wifi_pwrseq>;
> +};
> +
> +&mipi_tx_config0 {
> +	status = "okay";
> +};
> +
> +&mt6359codec {
> +	mediatek,mic-type-0 = <1>;
> +	mediatek,mic-type-1 = <3>;

You can drop mic-type-2 and dmic-mode, as the defaults for these are already zero.

> +	mediatek,mic-type-2 = <0>;
> +	mediatek,dmic-mode = <0>;
> +};
> +

..snip..

> +
> +&mt6359_vproc2_buck_reg {
> +	/* The name "vgpu" is required by mtk-regulator-coupler */
> +	regulator-name = "vgpu";
> +	regulator-min-microvolt = <550000>;
> +	regulator-max-microvolt = <800000>;
> +	regulator-coupled-with = <&mt6359_vsram_others_ldo_reg>;
> +	regulator-coupled-max-spread = <225000>;
> +	regulator-always-on;

You don't need regulator-always-on here.

> +};
> +
> +&mt6359_vs2_buck_reg {
> +	regulator-min-microvolt = <1600000>;
> +	regulator-boot-on;
> +};
> +
> +&mt6359_vpu_buck_reg {
> +	regulator-name = "dvdd_adsp";

Is that for the MediaTek Audio DSP?

Thought Genio 500/700 were kind of "special" in having one just for that.

If so, you have to do this properly and add this to the ADSP power domain as a
domain-supply, if this effectively enables basic power to the ADSP itself.

To do so, you must also change drivers/pmdomain/mediatek/mt8188-pm-domains.h and in
MT8188_POWER_DOMAIN_ADSP you want to change `.caps` to

.caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_SRAM_ISO | MTK_SCPD_ACTIVE_WAKEUP |
	MTK_SCPD_DOMAIN_SUPPLY,

...so that you can remove the regulator-always-on property here, and benefit from a
nice bump in power efficiency (as you stop power leakages like so).

> +	regulator-always-on;
> +};
> +
> +&mt6359_vrf12_ldo_reg {
> +	regulator-name = "va12_abb2_pmu";
> +	regulator-always-on;
> +};
> +
> +&mt6359_vsram_md_ldo_reg {
> +	regulator-always-on;
> +};
> +
> +&mt6359_vsram_others_ldo_reg {
> +	/* The name "vsram_gpu" is required by mtk-regulator-coupler */
> +	regulator-name = "vsram_gpu";
> +	regulator-min-microvolt = <750000>;
> +	regulator-max-microvolt = <800000>;
> +	regulator-coupled-with = <&mt6359_vproc2_buck_reg>;
> +	regulator-coupled-max-spread = <225000>;
> +	regulator-always-on;

You don't need regulator-always-on here.

> +};
> +
> +&mt6359_vsim1_ldo_reg {
> +	regulator-name = "vsim1_pmu";
> +	regulator-max-microvolt = <1800000>;
> +	regulator-enable-ramp-delay = <480>;
> +};
> +
> +&mt6359_vufs_ldo_reg {
> +	regulator-name = "vufs18_pmu";
> +	regulator-always-on;
> +};
> +
> +&ovl0_in {
> +	remote-endpoint = <&vdosys0_ep_main>;
> +};
> +
> +&pcie {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pcie_default_pins>;
> +	status = "okay";
> +};
> +
> +&pciephy {
> +	status = "okay";
> +};
> +
> +&pmic {
> +	interrupt-parent = <&pio>;
> +	interrupts = <222 IRQ_TYPE_LEVEL_HIGH>;

Instead of interrupt-parent and interrupts, you can do:

interrupts-extended = <&pio 222 IRQ_TYPE_LEVEL_HIGH>;

> +
> +	keys {
> +		compatible = "mediatek,mt6359-keys";
> +		mediatek,long-press-mode = <1>;
> +		power-off-time-sec = <0>;
> +
> +		power-key {
> +			linux,keycodes = <116>;

At the top of the file, properly ordered:
#include <dt-bindings/input/linux-event-codes.h>

...then, here:
linux,keycodes = <KEY_POWER>;

> +			wakeup-source;
> +		};
> +	};
> +};
> +
> +&postmask0_in {
> +	remote-endpoint = <&gamma0_out>;
> +};
> +
> +&postmask0_out {
> +	remote-endpoint = <&dither0_in>;
> +};
> +
> +&scp_cluster {
> +	status = "okay";
> +};
> +
> +&scp_c0 {
> +	firmware-name = "mediatek/mt8188/scp.img";

You don't need (and can't have) firmware-name upstream: drop it.

> +	memory-region = <&scp_mem>;
> +	status = "okay";
> +};
> +
> +&spi0 {
> +	pinctrl-0 = <&spi0_pins>;
> +	pinctrl-names = "default";
> +	mediatek,pad-select = <0>;

vendor properties always at the end, before status = "okay";

> +	#address-cells = <1>;
> +	#size-cells = <0>;

...but anyway, #address-cells, #size-cells are already declared in mt8188.dtsi and
they even have the same values that you're assigning here. Drop those.

> +	status = "okay";
> +};
> +
> +&spi1 {
> +	pinctrl-0 = <&spi1_pins>;
> +	pinctrl-names = "default";
> +	mediatek,pad-select = <0>;

same comments apply here as well.

> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +	status = "okay";
> +};
> +

..snip..

> +&uart0 {
> +	pinctrl-0 = <&uart0_pins>;
> +	pinctrl-names = "default";
> +	status = "okay";
> +};
> +
> +&uart1 {
> +	pinctrl-0 = <&uart1_pins>;
> +	pinctrl-names = "default";
> +	status = "okay";
> +};
> +
> +&uart2 {
> +	pinctrl-0 = <&uart2_pins>;
> +	pinctrl-names = "default";
> +	status = "okay";
> +};
> +
> +&ssusb0 {

Please reorder:

dr_mode
maximum-speed
usb-role-switch;
wakeup-source;
pinctrl-0
pinctrl-names
vusb33-supply
status

> +	pinctrl-names = "default";
> +	pinctrl-0 = <&usbotg_pins>;
> +	maximum-speed = "high-speed";
> +	usb-role-switch;
> +	dr_mode = "otg";
> +	vusb33-supply = <&mt6359_vusb_ldo_reg>;
> +	wakeup-source;
> +	status = "okay";
> +
> +	connector {
> +		compatible = "usb-c-connector";
> +		label = "USB-C";
> +		data-role = "dual";
> +
> +		ports {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +
> +			port at 0 {
> +				reg = <0>;
> +				hs_ep: endpoint {
> +					remote-endpoint = <&usb_hs_ep>;
> +				};
> +			};
> +
> +			port at 1 {
> +				reg = <1>;
> +				ss_ep: endpoint {
> +					remote-endpoint = <&hd3ss3220_in_ep>;
> +				};
> +			};
> +		};
> +	};
> +
> +	ports {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		port at 0 {
> +			reg = <0>;
> +			usb_hs_ep: endpoint {
> +				remote-endpoint = <&hs_ep>;
> +			};
> +		};
> +
> +		port at 1 {
> +			reg = <1>;
> +			usb_role_switch: endpoint {
> +				remote-endpoint = <&hd3ss3220_out_ep>;
> +			};
> +		};
> +	};
> +};
> +
> +&u2port0 {
> +	status = "okay";
> +};
> +
> +&u3phy0 {
> +	status = "okay";
> +};
> +
> +&xhci0 {
> +	vbus-supply = <&usb_p0_vbus>;
> +	vusb33-supply = <&mt6359_vusb_ldo_reg>;
> +	status = "okay";
> +};
> +
> +&ssusb1 {

Please reorder:

dr_mode
maximum-speed
wakeup-source
pinctrl-0
pinctrl-names
vusb33-supply
status

> +	pinctrl-0 = <&usb1_pins>;
> +	pinctrl-names = "default";
> +	vusb33-supply = <&mt6359_vusb_ldo_reg>;
> +	dr_mode = "host";
> +	wakeup-source;
> +	status = "okay";
> +};
> +
> +&u2port1 {
> +	status = "okay";
> +};
> +
> +&u3port1 {
> +	status = "okay";
> +};
> +
> +&u3phy1 {
> +	status = "okay";
> +};
> +
> +&xhci1 {
> +	vbus-supply = <&usb_p1_vbus>;
> +	vusb33-supply = <&mt6359_vusb_ldo_reg>;
> +	status = "okay";
> +};
> +
> +&ssusb2 {

Please reorder:

dr_mode
maximum-speed
wakeup-source
vusb33-supply
status

> +	maximum-speed = "high-speed";
> +	dr_mode = "host";
> +	vusb33-supply = <&mt6359_vusb_ldo_reg>;
> +	status = "okay";
> +	wakeup-source;
> +};
> +
..snip..

> +&vdosys0 {
> +	port {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		vdosys0_ep_main: endpoint at 0 {
> +			reg = <0>;
> +			remote-endpoint = <&ovl0_in>;
> +		};
> +	};
> +};
> +
> +&watchdog {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&watchdog_pins>;
> +};
> +
> +&pio {
> +	audio_pins: audio-pins {
> +		pins-aud-pmic {
> +			pinmux = <
> +				PINMUX_GPIO101__FUNC_O_AUD_CLK_MOSI
> +				PINMUX_GPIO102__FUNC_O_AUD_SYNC_MOSI
> +				PINMUX_GPIO103__FUNC_O_AUD_DAT_MOSI0
> +				PINMUX_GPIO104__FUNC_O_AUD_DAT_MOSI1
> +				PINMUX_GPIO105__FUNC_I0_AUD_DAT_MISO0
> +				PINMUX_GPIO106__FUNC_I0_AUD_DAT_MISO1
> +			>;

You don't need the extra lines...

			pinmux = <PINMUX_GPIO101__FUNC_O_AUD_CLK_MOSI
				  PINMUX_GPIO102__FUNC_O_AUD_SYNC_MOSI
				  PINMUX_GPIO103__FUNC_O_AUD_DAT_MOSI0
				  PINMUX_GPIO104__FUNC_O_AUD_DAT_MOSI1
				  PINMUX_GPIO105__FUNC_I0_AUD_DAT_MISO0
				  PINMUX_GPIO106__FUNC_I0_AUD_DAT_MISO1>;

here and everywhere else please :-)
		
> +		};
> +
> +		pins-pcm-wifi {
> +			pinmux = <
> +				PINMUX_GPIO121__FUNC_B0_PCM_CLK
> +				PINMUX_GPIO122__FUNC_B0_PCM_SYNC
> +				PINMUX_GPIO123__FUNC_O_PCM_DO
> +				PINMUX_GPIO124__FUNC_I0_PCM_DI
> +			>;
> +		};
> +
> +		pins-i2s {
> +			pinmux = <
> +				PINMUX_GPIO119__FUNC_O_I2SO1_MCK
> +				PINMUX_GPIO112__FUNC_O_I2SO1_WS
> +				PINMUX_GPIO120__FUNC_O_I2SO1_BCK
> +				PINMUX_GPIO113__FUNC_O_I2SO1_D0
> +				PINMUX_GPIO110__FUNC_I0_I2SIN_D0
> +			>;
> +		};
> +	};
> +
> +	disp_pwm0_pins: disp-pwm0-pins {
> +		pins {
> +			pinmux = <PINMUX_GPIO29__FUNC_O_DISP_PWM0>;
> +			bias-pull-down;
> +		};
> +	};
> +
> +	dsi0_sn65dsi84_pins: dsi0-sn65dsi84-pins {
> +		pins-irq {
> +			pinmux = <PINMUX_GPIO128__FUNC_B_GPIO128>;
> +			bias-pull-down;
> +			input-enable;
> +		};
> +
> +		pins-enable {
> +			pinmux = <PINMUX_GPIO25__FUNC_B_GPIO25>;
> +			bias-pull-down;
> +		};
> +	};
> +
> +	eth_default_pins: eth-default-pins {
> +		pins-txd {
> +			pinmux = <PINMUX_GPIO131__FUNC_O_GBE_TXD3>,
> +				 <PINMUX_GPIO132__FUNC_O_GBE_TXD2>,
> +				 <PINMUX_GPIO133__FUNC_O_GBE_TXD1>,
> +				 <PINMUX_GPIO134__FUNC_O_GBE_TXD0>;
> +			drive-strength = <MTK_DRIVE_8mA>;

Please don't use the MTK_DRIVE_x macros, we are in the process of removing them.

All those macros are defining the .. same number that you can read in the macro
itself; as in:

MTK_DRIVE_(n)mA = n -> MTK_DRIVE_8mA = 8

So, remove all of them and use numbers directly.
In this specific case it is `drive-strength = <8>;` - please do this here and
everywhere else.


> +		};
> +		pins-cc {
> +			pinmux = <PINMUX_GPIO139__FUNC_B0_GBE_TXC>,
> +				 <PINMUX_GPIO142__FUNC_O_GBE_TXEN>,
> +				 <PINMUX_GPIO141__FUNC_I0_GBE_RXDV>;
> +			drive-strength = <MTK_DRIVE_8mA>;
> +		};
> +		pins-rxd {
> +			pinmux = <PINMUX_GPIO135__FUNC_I0_GBE_RXD3>,
> +				 <PINMUX_GPIO136__FUNC_I0_GBE_RXD2>,
> +				 <PINMUX_GPIO137__FUNC_I0_GBE_RXD1>,
> +				 <PINMUX_GPIO138__FUNC_I0_GBE_RXD0>,
> +				 <PINMUX_GPIO140__FUNC_I0_GBE_RXC>;
> +			drive-strength = <MTK_DRIVE_8mA>;
> +			bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
> +		};
> +		pins-mdio {
> +			pinmux = <PINMUX_GPIO143__FUNC_O_GBE_MDC>,
> +				 <PINMUX_GPIO144__FUNC_B1_GBE_MDIO>;
> +			drive-strength = <MTK_DRIVE_8mA>;
> +			input-enable;
> +		};
> +		pins-power {
> +			pinmux = <PINMUX_GPIO27__FUNC_B_GPIO27>; /* GP_EQOS_RESET */
> +			output-high;
> +		};
> +		pins-intr {
> +			pinmux = <PINMUX_GPIO148__FUNC_B_GPIO148>; /* GPIRQ_EQOS_PHY */
> +			bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
> +			input-enable;
> +		};
> +	};
> +

Cheers,
Angelo


From angelogioacchino.delregno at collabora.com  Tue Dec  2 22:54:47 2025
From: angelogioacchino.delregno at collabora.com (AngeloGioacchino Del Regno)
Date: Wed, 3 Dec 2025 07:54:47 +0100
Subject: [PATCH v4 3/4] arm64: dts: mediatek: add device tree for Tungsten
 510 board
In-Reply-To: <e9edd5f2-c0ff-48fa-baf9-659dd0073e3d@collabora.com>
References: <20251202-review-v4-0-93f5cd2a0d4a@gmail.com>
 <20251202-review-v4-3-93f5cd2a0d4a@gmail.com>
 <e9edd5f2-c0ff-48fa-baf9-659dd0073e3d@collabora.com>
Message-ID: <0b397409-bc6c-4d40-8dba-1d028b51de32@collabora.com>

Il 03/12/25 07:50, AngeloGioacchino Del Regno ha scritto:
> Il 02/12/25 23:08, Gary Bisson ha scritto:
>> Add device tree to support Ezurio Tungsten 510 (MT8370) SMARC SOM [1] +
>> Universal SMARC carrier board [2].
>> It includes support for the MIPI-DSI BD070LIC3 display which uses the
>> Tianma TM070JDHG30 panel + TI SN65DSI84 MIPI-DSI to LVDS bridge [3].
>>
>> [1] https://www.ezurio.com/product/tungsten510-smarc
>> [2] https://www.ezurio.com/system-on-module/accessories/universal-smarc-carrier
>> [3] https://www.ezurio.com/product/bd070lic3-7-touchscreen-display
>>
>> Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
>>
> 
> Hello!
> 
> Thanks for the patch, that's mostly good. Though, there are a few comments, please
> check below.
> 
>> ---
>> Changes in v2:
>> - Updated nodes to be generic (pmic, i2c, usb-typec)
>> Changed in v3:
>> - None
>> Changed in v4:
>> - Fixed remaining DTB warnings
>> ---
>> ? arch/arm64/boot/dts/mediatek/Makefile????????????? |??? 1 +
>> ? .../boot/dts/mediatek/mt8370-tungsten-smarc.dts??? |?? 14 +
>> ? .../boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi?? | 1510 ++++++++++++++++++++
>> ? 3 files changed, 1525 insertions(+)
>>
>> diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/ 
>> mediatek/Makefile
>> index a4df4c21399e..30d169a31b10 100644
>> --- a/arch/arm64/boot/dts/mediatek/Makefile
>> +++ b/arch/arm64/boot/dts/mediatek/Makefile
>> @@ -99,6 +99,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8195-demo.dtb
>> ? dtb-$(CONFIG_ARCH_MEDIATEK) += mt8195-evb.dtb
>> ? dtb-$(CONFIG_ARCH_MEDIATEK) += mt8365-evk.dtb
>> ? dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-genio-510-evk.dtb
>> +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-tungsten-smarc.dtb
>> ? dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-genio-1200-evk.dtb
>> ? dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-genio-700-evk.dtb
>> ? dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-kontron-3-5-sbc-i1200.dtb
>> diff --git a/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts b/arch/arm64/ 
>> boot/dts/mediatek/mt8370-tungsten-smarc.dts
>> new file mode 100644
>> index 000000000000..d713ef77df3a
>> --- /dev/null
>> +++ b/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts
>> @@ -0,0 +1,14 @@
>> +// SPDX-License-Identifier: (GPL-2.0 OR MIT)
>> +/*
>> + * Copyright (C) 2025 Ezurio LLC
>> + * Author: Gary Bisson <bisson.gary at gmail.com>
>> + */
>> +/dts-v1/;
>> +#include "mt8370.dtsi"
>> +#include "mt83x0-tungsten-smarc.dtsi"
>> +
>> +/ {
>> +??? model = "Ezurio Tungsten510 SMARC (MT8370)";
>> +??? compatible = "ezurio,mt8370-tungsten-smarc", "mediatek,mt8370",
>> +???????????? "mediatek,mt8188";
>> +};
>> diff --git a/arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi b/arch/ 
>> arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi
>> new file mode 100644
>> index 000000000000..d71148d78781
>> --- /dev/null
>> +++ b/arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi

Sorry for the double email, I noticed that right after sending the first one.

Please, no wildcards in names.

Rename this file to mt8390-tungsten-smarc.dtsi.

Cheers!

>> @@ -0,0 +1,1510 @@
>> +// SPDX-License-Identifier: (GPL-2.0 OR MIT)
>> +/*
>> + * Copyright (C) 2025 Ezurio LLC
>> + * Author: Gary Bisson <bisson.gary at gmail.com>
>> + */
>> +
> 
> ..snip..
> 
>> +
>> +&disp_dsi0 {
>> +??? #address-cells = <1>;
>> +??? #size-cells = <0>;
>> +??? status = "okay";
>> +
>> +??? ports {
>> +??????? #address-cells = <1>;
>> +??????? #size-cells = <0>;
>> +
>> +??????? port at 0 {
>> +??????????? reg = <0>;
>> +??????????? dsi0_in: endpoint {
>> +??????????????? remote-endpoint = <&dither0_out>;
>> +??????????? };
>> +??????? };
>> +
>> +??????? port at 1 {
>> +??????????? reg = <1>;
>> +??????????? dsi0_out: endpoint {
>> +??????????????? remote-endpoint = <&sn65dsi84_bridge_in>;
>> +??????????? };
>> +??????? };
>> +??? };
>> +};
>> +
>> +&dither0_in {
>> +??? remote-endpoint = <&postmask0_out>;
>> +};
>> +
>> +&dither0_out {
>> +??? remote-endpoint = <&dsi0_in>;
>> +};
>> +
>> +&eth {
>> +??? phy-mode ="rgmii-id";
>> +??? phy-handle = <&ethernet_phy0>;
>> +??? pinctrl-names = "default", "sleep";
>> +??? pinctrl-0 = <&eth_default_pins>;
>> +??? pinctrl-1 = <&eth_sleep_pins>;
>> +??? mediatek,mac-wol;
>> +??? snps,reset-gpio = <&pio 27 GPIO_ACTIVE_LOW>;
>> +??? snps,reset-active-low;
>> +??? snps,reset-delays-us = <0 11000 1000>;
>> +??? status = "okay";
>> +};
>> +
>> +&eth_mdio {
>> +??? ethernet_phy0: ethernet-phy at 7 {
>> +??????? compatible = "ethernet-phy-ieee802.3-c22";
>> +??????? reg = <0x7>;
>> +??????? interrupts-extended = <&pio 148 IRQ_TYPE_LEVEL_LOW>;
>> +??? };
>> +};
>> +
>> +&gamma0_out {
>> +??? remote-endpoint = <&postmask0_in>;
>> +};
>> +
>> +&gpu {
>> +??? mali-supply = <&mt6359_vproc2_buck_reg>;
>> +??? status = "okay";
>> +};
>> +
>> +&i2c0 {
>> +??? pinctrl-names = "default";
>> +??? pinctrl-0 = <&i2c0_pins>;
>> +??? clock-frequency = <100000>;
>> +??? status = "okay";
>> +
>> +??? i2c-mux at 73 {
>> +??????? compatible = "nxp,pca9546";
>> +??????? reg = <0x73>;
>> +??????? pinctrl-names = "default";
>> +??????? pinctrl-0 = <&i2c0_mux_pins>;
>> +??????? reset-gpios = <&pio 6 GPIO_ACTIVE_LOW>;
>> +??????? #address-cells = <1>;
>> +??????? #size-cells = <0>;
>> +
>> +??????? i2c_mux_gp_0: i2c at 0 {
>> +??????????? clock-frequency = <100000>;
>> +??????????? reg = <0>;
> 
> reg = <0>;
> clock-frequency = ...
> 
>> +??????????? #address-cells = <1>;
>> +??????????? #size-cells = <0>;
>> +??????? };
>> +
>> +??????? i2c_mux_gp_1: i2c at 1 {
>> +??????????? clock-frequency = <100000>;
>> +??????????? reg = <1>;
>> +??????????? #address-cells = <1>;
>> +??????????? #size-cells = <0>;
>> +??????? };
>> +
>> +??????? i2c_mux_gp_2: i2c at 2 {
>> +??????????? clock-frequency = <100000>;
>> +??????????? reg = <2>;
>> +??????????? #address-cells = <1>;
>> +??????????? #size-cells = <0>;
>> +??????? };
>> +
>> +??????? i2c_mux_gp_3: i2c at 3 {
>> +??????????? clock-frequency = <100000>;
>> +??????????? reg = <3>;
>> +??????????? #address-cells = <1>;
>> +??????????? #size-cells = <0>;
>> +??????? };
>> +??? };
>> +};
>> +
>> +&i2c1 {
>> +??? pinctrl-names = "default";
>> +??? pinctrl-0 = <&i2c1_pins>;
>> +??? clock-frequency = <400000>;
>> +??? status = "okay";
>> +};
>> +
>> +&i2c2 {
>> +??? pinctrl-names = "default";
>> +??? pinctrl-0 = <&i2c2_pins>;
>> +??? clock-frequency = <400000>;
>> +??? status = "okay";
>> +
>> +??? i2c-mux at 73 {
>> +??????? compatible = "nxp,pca9546";
>> +??????? pinctrl-names = "default";
>> +??????? pinctrl-0 = <&i2c_mux_smarc_lcd_pins>;
>> +??????? reg = <0x73>;
>> +??????? reset-gpios = <&pio 5 GPIO_ACTIVE_LOW>;
>> +??????? #address-cells = <1>;
>> +??????? #size-cells = <0>;
>> +
>> +??????? i2c_mux_lcd_0: i2c at 0 {
>> +??????????? clock-frequency = <100000>;
>> +??????????? reg = <0>;
>> +??????????? #address-cells = <1>;
>> +??????????? #size-cells = <0>;
>> +??????? };
>> +
>> +??????? i2c_mux_lcd_1: i2c at 1 {
>> +??????????? clock-frequency = <100000>;
>> +??????????? reg = <1>;
>> +??????????? #address-cells = <1>;
>> +??????????? #size-cells = <0>;
>> +??????? };
>> +
>> +??????? i2c_mux_lcd_2: i2c at 2 {
>> +??????????? clock-frequency = <100000>;
>> +??????????? reg = <2>;
>> +??????????? #address-cells = <1>;
>> +??????????? #size-cells = <0>;
>> +??????? };
>> +
>> +??????? i2c_mux_lcd_3: i2c at 3 {
>> +??????????? clock-frequency = <100000>;
>> +??????????? reg = <3>;
>> +??????????? #address-cells = <1>;
>> +??????????? #size-cells = <0>;
>> +??????? };
>> +??? };
>> +};
>> +
>> +&i2c3 {
>> +??? pinctrl-names = "default";
>> +??? pinctrl-0 = <&i2c3_pins>;
>> +??? clock-frequency = <400000>;
>> +??? status = "okay";
>> +};
>> +
>> +&i2c4 {
>> +??? pinctrl-names = "default";
>> +??? pinctrl-0 = <&i2c4_pins>;
>> +??? clock-frequency = <400000>;
>> +??? status = "okay";
>> +};
>> +
>> +&i2c_mux_gp_0 {
>> +??? rv3028: rtc at 52 {
>> +??????? compatible = "microcrystal,rv3028";
>> +??????? reg = <0x52>;
>> +??????? interrupts-extended = <&pio 42 IRQ_TYPE_LEVEL_LOW>;
>> +??????? pinctrl-names = "default";
>> +??????? pinctrl-0 = <&rv3028_pins>;
>> +??????? #clock-cells = <0>;
>> +??????? wakeup-source;
>> +??? };
>> +};
>> +
>> +&i2c_mux_gp_1 {
>> +??? usb-typec at 60 {
>> +??????? compatible = "ti,hd3ss3220";
> 
> reg always goes after compatible.
> 
>> +??????? interrupts-extended = <&pio 45 IRQ_TYPE_LEVEL_LOW>;
>> +??????? pinctrl-names = "default";
>> +??????? pinctrl-0 = <&hd3ss3220_pins>;
>> +??????? reg = <0x60>;
>> +
>> +??????? ports {
>> +??????????? #address-cells = <1>;
>> +??????????? #size-cells = <0>;
>> +
>> +??????????? port at 0 {
>> +??????????????? reg = <0>;
>> +??????????????? hd3ss3220_in_ep: endpoint {
>> +??????????????????? remote-endpoint = <&ss_ep>;
>> +??????????????? };
>> +??????????? };
>> +
>> +??????????? port at 1 {
>> +??????????????? reg = <1>;
>> +??????????????? hd3ss3220_out_ep: endpoint {
>> +??????????????????? remote-endpoint = <&usb_role_switch>;
>> +??????????????? };
>> +??????????? };
>> +??????? };
>> +??? };
>> +};
>> +
>> +&i2c_mux_gp_2 {
>> +??? codec at 1a {
> 
> compatible
> reg
> clocks
> gpio-cfg
> 
> supplies
> 
> P.S.: Please read
> https://docs.kernel.org/devicetree/bindings/dts-coding-style.html
> 
>> +??????? #sound-dai-cells = <0>;
>> +??????? AVDD-supply = <&reg_1v8>;
>> +??????? CPVDD-supply = <&reg_1v8>;
>> +??????? DBVDD-supply = <&reg_3v3>;
>> +??????? DCVDD-supply = <&reg_1v8>;
>> +??????? MICVDD-supply = <&reg_3v3>;
>> +??????? PLLVDD-supply = <&reg_1v8>;
>> +??????? SPKVDD1-supply = <&reg_5v>;
>> +??????? SPKVDD2-supply = <&reg_5v>;
>> +??????? clocks = <&topckgen CLK_TOP_I2SO1>;
>> +??????? compatible = "wlf,wm8962";
>> +??????? gpio-cfg = <
>> +??????????? 0x0000 /* n/c */
>> +??????????? 0x0000 /* gpio2: */
>> +??????????? 0x0000 /* gpio3: */
>> +??????????? 0x0000 /* n/c */
>> +??????????? 0x8081 /* gpio5:HP detect */
>> +??????????? 0x8095 /* gpio6:Mic detect */
>> +??????? >;
>> +??????? reg = <0x1a>;
>> +??? };
>> +};
>> +
>> +&i2c_mux_lcd_2 {
>> +??? #address-cells = <1>;
>> +??? #size-cells = <0>;
>> +
>> +??? bridge at 2c {
>> +??????? compatible = "ti,sn65dsi84";
>> +??????? reg = <0x2c>;
>> +??????? enable-gpios = <&pio 25 GPIO_ACTIVE_HIGH>;
>> +??????? pinctrl-names = "default";
>> +??????? pinctrl-0 = <&dsi0_sn65dsi84_pins>;
>> +
>> +??????? ports {
>> +??????????? #address-cells = <1>;
>> +??????????? #size-cells = <0>;
>> +
>> +??????????? port at 0 {
>> +??????????????? reg = <0>;
>> +
>> +??????????????? sn65dsi84_bridge_in: endpoint {
>> +??????????????????? remote-endpoint = <&dsi0_out>;
>> +??????????????????? data-lanes = <1 2 3 4>;
>> +??????????????? };
>> +??????????? };
>> +
>> +??????????? port at 2 {
>> +??????????????? reg = <2>;
>> +
>> +??????????????? sn65dsi84_bridge_out: endpoint {
>> +??????????????????? remote-endpoint = <&dsi0_panel_in>;
>> +??????????????? };
>> +??????????? };
>> +??????? };
>> +??? };
>> +
>> +??? touchscren at 5d {
>> +??????? compatible = "goodix,gt911";
>> +??????? reg = <0x5d>;
>> +??????? pinctrl-names = "default";
>> +??????? pinctrl-0 = <&ts_dsi0_goodix_pins>;
>> +??????? interrupts-extended = <&pio 146 IRQ_TYPE_LEVEL_HIGH>;
>> +??????? irq-gpios = <&pio 146 GPIO_ACTIVE_HIGH>;
>> +??????? reset-gpios = <&pio 7 GPIO_ACTIVE_HIGH>;
>> +??? };
>> +};
>> +
>> +&mfg0 {
>> +??? domain-supply = <&mt6359_vproc2_buck_reg>;
>> +};
>> +
>> +&mfg1 {
>> +??? domain-supply = <&mt6359_vsram_others_ldo_reg>;
>> +};
>> +
>> +&mmc0 {
>> +??? status = "okay";
>> +??? pinctrl-names = "default", "state_uhs";
>> +??? pinctrl-0 = <&mmc0_default_pins>;
>> +??? pinctrl-1 = <&mmc0_uhs_pins>;
>> +??? bus-width = <8>;
>> +??? max-frequency = <200000000>;
>> +??? cap-mmc-highspeed;
>> +??? cap-mmc-hw-reset;
>> +??? mmc-hs200-1_8v;
>> +??? mmc-hs400-1_8v;
>> +??? supports-cqe;
>> +??? cap-mmc-hw-reset;
> 
> You added cap-mmc-hw-reset twice.
> 
>> +??? no-sdio;
>> +??? no-sd;
>> +??? hs400-ds-delay = <0x1481b>;
>> +??? vmmc-supply = <&mt6359_vemc_1_ldo_reg>;
>> +??? vqmmc-supply = <&mt6359_vufs_ldo_reg>;
>> +??? non-removable;
> 
> Also, please reorder by name:
> 
> bus-width ...
> cap-mmc-highspeed;
> cap-mmc-hw-reset;
> hs400-ds-delay....
> max-frequency ....
> mmc-hs200-1_8v;
> mmc-hs400-1_8v;
> no-sd;
> no-sdio;
> non-removable;
> supports-cqe;
> 
> pinctrl properties
> 
> power supplies
> 
> status
> 
>> +};
>> +
>> +&mmc1 {
>> +??? status = "okay";
>> +??? pinctrl-names = "default", "state_uhs";
>> +??? pinctrl-0 = <&mmc1_default_pins>;
>> +??? pinctrl-1 = <&mmc1_uhs_pins>;
>> +??? bus-width = <4>;
>> +??? max-frequency = <200000000>;
>> +??? cap-sd-highspeed;
>> +??? sd-uhs-sdr50;
>> +??? sd-uhs-sdr104;
>> +??? cd-gpios = <&pio 2 GPIO_ACTIVE_LOW>;
>> +??? vqmmc-supply = <&mt6359_vsim1_ldo_reg>;
>> +??? vmmc-supply = <&sdcard_en_3v3>;
>> +};
>> +
>> +&mmc2 {
>> +??? status = "okay";
> 
> status at the end please
> 
>> +??? pinctrl-names = "default", "state_uhs", "state_eint";
>> +??? pinctrl-0 = <&mmc2_default_pins>;
>> +??? pinctrl-1 = <&mmc2_uhs_pins>;
>> +??? pinctrl-2 = <&mmc2_eint_pins>;
> 
> Sorry, but I truly hate /delete-property/.
> 
>> +??? /delete-property/ interrupts;
>> +??? interrupt-names = "msdc", "sdio_wakeup";
>> +??? interrupts-extended = <&gic GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH 0>,
>> +????????????????? <&pio 172 IRQ_TYPE_LEVEL_LOW>;
> 
> You're lucky in this case, though, because you're the first user of MMC2! :-)
> 
> The solution here is:
>  ?- Change the interrupts property in mt8188.dtsi on mmc at 1125000 to
>  ?? `interrupts-extended = <&gic GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH 0>;`
>  ?- Override it here without `/delete-property/ interrupts;`
> 
>> +??? bus-width = <4>;
> 
> Please order the properties by name (bar X-supply, Y-pwrseq, status that go at
> the end).
> 
>> +??? max-frequency = <200000000>;
>> +??? cap-sd-highspeed;
>> +??? sd-uhs-sdr104;
>> +??? keep-power-in-suspend;
>> +??? wakeup-source;
>> +??? cap-sdio-irq;
>> +??? no-mmc;
>> +??? no-sd;
>> +??? non-removable;
>> +??? vmmc-supply = <&mt6359_vcn33_2_bt_ldo_reg>;
>> +??? vqmmc-supply = <&mt6359_vcn18_ldo_reg>;
>> +??? mmc-pwrseq = <&wifi_pwrseq>;
>> +};
>> +
>> +&mipi_tx_config0 {
>> +??? status = "okay";
>> +};
>> +
>> +&mt6359codec {
>> +??? mediatek,mic-type-0 = <1>;
>> +??? mediatek,mic-type-1 = <3>;
> 
> You can drop mic-type-2 and dmic-mode, as the defaults for these are already zero.
> 
>> +??? mediatek,mic-type-2 = <0>;
>> +??? mediatek,dmic-mode = <0>;
>> +};
>> +
> 
> ..snip..
> 
>> +
>> +&mt6359_vproc2_buck_reg {
>> +??? /* The name "vgpu" is required by mtk-regulator-coupler */
>> +??? regulator-name = "vgpu";
>> +??? regulator-min-microvolt = <550000>;
>> +??? regulator-max-microvolt = <800000>;
>> +??? regulator-coupled-with = <&mt6359_vsram_others_ldo_reg>;
>> +??? regulator-coupled-max-spread = <225000>;
>> +??? regulator-always-on;
> 
> You don't need regulator-always-on here.
> 
>> +};
>> +
>> +&mt6359_vs2_buck_reg {
>> +??? regulator-min-microvolt = <1600000>;
>> +??? regulator-boot-on;
>> +};
>> +
>> +&mt6359_vpu_buck_reg {
>> +??? regulator-name = "dvdd_adsp";
> 
> Is that for the MediaTek Audio DSP?
> 
> Thought Genio 500/700 were kind of "special" in having one just for that.
> 
> If so, you have to do this properly and add this to the ADSP power domain as a
> domain-supply, if this effectively enables basic power to the ADSP itself.
> 
> To do so, you must also change drivers/pmdomain/mediatek/mt8188-pm-domains.h and in
> MT8188_POWER_DOMAIN_ADSP you want to change `.caps` to
> 
> .caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_SRAM_ISO | MTK_SCPD_ACTIVE_WAKEUP |
>  ????MTK_SCPD_DOMAIN_SUPPLY,
> 
> ...so that you can remove the regulator-always-on property here, and benefit from a
> nice bump in power efficiency (as you stop power leakages like so).
> 
>> +??? regulator-always-on;
>> +};
>> +
>> +&mt6359_vrf12_ldo_reg {
>> +??? regulator-name = "va12_abb2_pmu";
>> +??? regulator-always-on;
>> +};
>> +
>> +&mt6359_vsram_md_ldo_reg {
>> +??? regulator-always-on;
>> +};
>> +
>> +&mt6359_vsram_others_ldo_reg {
>> +??? /* The name "vsram_gpu" is required by mtk-regulator-coupler */
>> +??? regulator-name = "vsram_gpu";
>> +??? regulator-min-microvolt = <750000>;
>> +??? regulator-max-microvolt = <800000>;
>> +??? regulator-coupled-with = <&mt6359_vproc2_buck_reg>;
>> +??? regulator-coupled-max-spread = <225000>;
>> +??? regulator-always-on;
> 
> You don't need regulator-always-on here.
> 
>> +};
>> +
>> +&mt6359_vsim1_ldo_reg {
>> +??? regulator-name = "vsim1_pmu";
>> +??? regulator-max-microvolt = <1800000>;
>> +??? regulator-enable-ramp-delay = <480>;
>> +};
>> +
>> +&mt6359_vufs_ldo_reg {
>> +??? regulator-name = "vufs18_pmu";
>> +??? regulator-always-on;
>> +};
>> +
>> +&ovl0_in {
>> +??? remote-endpoint = <&vdosys0_ep_main>;
>> +};
>> +
>> +&pcie {
>> +??? pinctrl-names = "default";
>> +??? pinctrl-0 = <&pcie_default_pins>;
>> +??? status = "okay";
>> +};
>> +
>> +&pciephy {
>> +??? status = "okay";
>> +};
>> +
>> +&pmic {
>> +??? interrupt-parent = <&pio>;
>> +??? interrupts = <222 IRQ_TYPE_LEVEL_HIGH>;
> 
> Instead of interrupt-parent and interrupts, you can do:
> 
> interrupts-extended = <&pio 222 IRQ_TYPE_LEVEL_HIGH>;
> 
>> +
>> +??? keys {
>> +??????? compatible = "mediatek,mt6359-keys";
>> +??????? mediatek,long-press-mode = <1>;
>> +??????? power-off-time-sec = <0>;
>> +
>> +??????? power-key {
>> +??????????? linux,keycodes = <116>;
> 
> At the top of the file, properly ordered:
> #include <dt-bindings/input/linux-event-codes.h>
> 
> ...then, here:
> linux,keycodes = <KEY_POWER>;
> 
>> +??????????? wakeup-source;
>> +??????? };
>> +??? };
>> +};
>> +
>> +&postmask0_in {
>> +??? remote-endpoint = <&gamma0_out>;
>> +};
>> +
>> +&postmask0_out {
>> +??? remote-endpoint = <&dither0_in>;
>> +};
>> +
>> +&scp_cluster {
>> +??? status = "okay";
>> +};
>> +
>> +&scp_c0 {
>> +??? firmware-name = "mediatek/mt8188/scp.img";
> 
> You don't need (and can't have) firmware-name upstream: drop it.
> 
>> +??? memory-region = <&scp_mem>;
>> +??? status = "okay";
>> +};
>> +
>> +&spi0 {
>> +??? pinctrl-0 = <&spi0_pins>;
>> +??? pinctrl-names = "default";
>> +??? mediatek,pad-select = <0>;
> 
> vendor properties always at the end, before status = "okay";
> 
>> +??? #address-cells = <1>;
>> +??? #size-cells = <0>;
> 
> ...but anyway, #address-cells, #size-cells are already declared in mt8188.dtsi and
> they even have the same values that you're assigning here. Drop those.
> 
>> +??? status = "okay";
>> +};
>> +
>> +&spi1 {
>> +??? pinctrl-0 = <&spi1_pins>;
>> +??? pinctrl-names = "default";
>> +??? mediatek,pad-select = <0>;
> 
> same comments apply here as well.
> 
>> +??? #address-cells = <1>;
>> +??? #size-cells = <0>;
>> +??? status = "okay";
>> +};
>> +
> 
> ..snip..
> 
>> +&uart0 {
>> +??? pinctrl-0 = <&uart0_pins>;
>> +??? pinctrl-names = "default";
>> +??? status = "okay";
>> +};
>> +
>> +&uart1 {
>> +??? pinctrl-0 = <&uart1_pins>;
>> +??? pinctrl-names = "default";
>> +??? status = "okay";
>> +};
>> +
>> +&uart2 {
>> +??? pinctrl-0 = <&uart2_pins>;
>> +??? pinctrl-names = "default";
>> +??? status = "okay";
>> +};
>> +
>> +&ssusb0 {
> 
> Please reorder:
> 
> dr_mode
> maximum-speed
> usb-role-switch;
> wakeup-source;
> pinctrl-0
> pinctrl-names
> vusb33-supply
> status
> 
>> +??? pinctrl-names = "default";
>> +??? pinctrl-0 = <&usbotg_pins>;
>> +??? maximum-speed = "high-speed";
>> +??? usb-role-switch;
>> +??? dr_mode = "otg";
>> +??? vusb33-supply = <&mt6359_vusb_ldo_reg>;
>> +??? wakeup-source;
>> +??? status = "okay";
>> +
>> +??? connector {
>> +??????? compatible = "usb-c-connector";
>> +??????? label = "USB-C";
>> +??????? data-role = "dual";
>> +
>> +??????? ports {
>> +??????????? #address-cells = <1>;
>> +??????????? #size-cells = <0>;
>> +
>> +??????????? port at 0 {
>> +??????????????? reg = <0>;
>> +??????????????? hs_ep: endpoint {
>> +??????????????????? remote-endpoint = <&usb_hs_ep>;
>> +??????????????? };
>> +??????????? };
>> +
>> +??????????? port at 1 {
>> +??????????????? reg = <1>;
>> +??????????????? ss_ep: endpoint {
>> +??????????????????? remote-endpoint = <&hd3ss3220_in_ep>;
>> +??????????????? };
>> +??????????? };
>> +??????? };
>> +??? };
>> +
>> +??? ports {
>> +??????? #address-cells = <1>;
>> +??????? #size-cells = <0>;
>> +
>> +??????? port at 0 {
>> +??????????? reg = <0>;
>> +??????????? usb_hs_ep: endpoint {
>> +??????????????? remote-endpoint = <&hs_ep>;
>> +??????????? };
>> +??????? };
>> +
>> +??????? port at 1 {
>> +??????????? reg = <1>;
>> +??????????? usb_role_switch: endpoint {
>> +??????????????? remote-endpoint = <&hd3ss3220_out_ep>;
>> +??????????? };
>> +??????? };
>> +??? };
>> +};
>> +
>> +&u2port0 {
>> +??? status = "okay";
>> +};
>> +
>> +&u3phy0 {
>> +??? status = "okay";
>> +};
>> +
>> +&xhci0 {
>> +??? vbus-supply = <&usb_p0_vbus>;
>> +??? vusb33-supply = <&mt6359_vusb_ldo_reg>;
>> +??? status = "okay";
>> +};
>> +
>> +&ssusb1 {
> 
> Please reorder:
> 
> dr_mode
> maximum-speed
> wakeup-source
> pinctrl-0
> pinctrl-names
> vusb33-supply
> status
> 
>> +??? pinctrl-0 = <&usb1_pins>;
>> +??? pinctrl-names = "default";
>> +??? vusb33-supply = <&mt6359_vusb_ldo_reg>;
>> +??? dr_mode = "host";
>> +??? wakeup-source;
>> +??? status = "okay";
>> +};
>> +
>> +&u2port1 {
>> +??? status = "okay";
>> +};
>> +
>> +&u3port1 {
>> +??? status = "okay";
>> +};
>> +
>> +&u3phy1 {
>> +??? status = "okay";
>> +};
>> +
>> +&xhci1 {
>> +??? vbus-supply = <&usb_p1_vbus>;
>> +??? vusb33-supply = <&mt6359_vusb_ldo_reg>;
>> +??? status = "okay";
>> +};
>> +
>> +&ssusb2 {
> 
> Please reorder:
> 
> dr_mode
> maximum-speed
> wakeup-source
> vusb33-supply
> status
> 
>> +??? maximum-speed = "high-speed";
>> +??? dr_mode = "host";
>> +??? vusb33-supply = <&mt6359_vusb_ldo_reg>;
>> +??? status = "okay";
>> +??? wakeup-source;
>> +};
>> +
> ..snip..
> 
>> +&vdosys0 {
>> +??? port {
>> +??????? #address-cells = <1>;
>> +??????? #size-cells = <0>;
>> +
>> +??????? vdosys0_ep_main: endpoint at 0 {
>> +??????????? reg = <0>;
>> +??????????? remote-endpoint = <&ovl0_in>;
>> +??????? };
>> +??? };
>> +};
>> +
>> +&watchdog {
>> +??? pinctrl-names = "default";
>> +??? pinctrl-0 = <&watchdog_pins>;
>> +};
>> +
>> +&pio {
>> +??? audio_pins: audio-pins {
>> +??????? pins-aud-pmic {
>> +??????????? pinmux = <
>> +??????????????? PINMUX_GPIO101__FUNC_O_AUD_CLK_MOSI
>> +??????????????? PINMUX_GPIO102__FUNC_O_AUD_SYNC_MOSI
>> +??????????????? PINMUX_GPIO103__FUNC_O_AUD_DAT_MOSI0
>> +??????????????? PINMUX_GPIO104__FUNC_O_AUD_DAT_MOSI1
>> +??????????????? PINMUX_GPIO105__FUNC_I0_AUD_DAT_MISO0
>> +??????????????? PINMUX_GPIO106__FUNC_I0_AUD_DAT_MISO1
>> +??????????? >;
> 
> You don't need the extra lines...
> 
>  ??????????? pinmux = <PINMUX_GPIO101__FUNC_O_AUD_CLK_MOSI
>  ????????????????? PINMUX_GPIO102__FUNC_O_AUD_SYNC_MOSI
>  ????????????????? PINMUX_GPIO103__FUNC_O_AUD_DAT_MOSI0
>  ????????????????? PINMUX_GPIO104__FUNC_O_AUD_DAT_MOSI1
>  ????????????????? PINMUX_GPIO105__FUNC_I0_AUD_DAT_MISO0
>  ????????????????? PINMUX_GPIO106__FUNC_I0_AUD_DAT_MISO1>;
> 
> here and everywhere else please :-)
> 
>> +??????? };
>> +
>> +??????? pins-pcm-wifi {
>> +??????????? pinmux = <
>> +??????????????? PINMUX_GPIO121__FUNC_B0_PCM_CLK
>> +??????????????? PINMUX_GPIO122__FUNC_B0_PCM_SYNC
>> +??????????????? PINMUX_GPIO123__FUNC_O_PCM_DO
>> +??????????????? PINMUX_GPIO124__FUNC_I0_PCM_DI
>> +??????????? >;
>> +??????? };
>> +
>> +??????? pins-i2s {
>> +??????????? pinmux = <
>> +??????????????? PINMUX_GPIO119__FUNC_O_I2SO1_MCK
>> +??????????????? PINMUX_GPIO112__FUNC_O_I2SO1_WS
>> +??????????????? PINMUX_GPIO120__FUNC_O_I2SO1_BCK
>> +??????????????? PINMUX_GPIO113__FUNC_O_I2SO1_D0
>> +??????????????? PINMUX_GPIO110__FUNC_I0_I2SIN_D0
>> +??????????? >;
>> +??????? };
>> +??? };
>> +
>> +??? disp_pwm0_pins: disp-pwm0-pins {
>> +??????? pins {
>> +??????????? pinmux = <PINMUX_GPIO29__FUNC_O_DISP_PWM0>;
>> +??????????? bias-pull-down;
>> +??????? };
>> +??? };
>> +
>> +??? dsi0_sn65dsi84_pins: dsi0-sn65dsi84-pins {
>> +??????? pins-irq {
>> +??????????? pinmux = <PINMUX_GPIO128__FUNC_B_GPIO128>;
>> +??????????? bias-pull-down;
>> +??????????? input-enable;
>> +??????? };
>> +
>> +??????? pins-enable {
>> +??????????? pinmux = <PINMUX_GPIO25__FUNC_B_GPIO25>;
>> +??????????? bias-pull-down;
>> +??????? };
>> +??? };
>> +
>> +??? eth_default_pins: eth-default-pins {
>> +??????? pins-txd {
>> +??????????? pinmux = <PINMUX_GPIO131__FUNC_O_GBE_TXD3>,
>> +???????????????? <PINMUX_GPIO132__FUNC_O_GBE_TXD2>,
>> +???????????????? <PINMUX_GPIO133__FUNC_O_GBE_TXD1>,
>> +???????????????? <PINMUX_GPIO134__FUNC_O_GBE_TXD0>;
>> +??????????? drive-strength = <MTK_DRIVE_8mA>;
> 
> Please don't use the MTK_DRIVE_x macros, we are in the process of removing them.
> 
> All those macros are defining the .. same number that you can read in the macro
> itself; as in:
> 
> MTK_DRIVE_(n)mA = n -> MTK_DRIVE_8mA = 8
> 
> So, remove all of them and use numbers directly.
> In this specific case it is `drive-strength = <8>;` - please do this here and
> everywhere else.
> 
> 
>> +??????? };
>> +??????? pins-cc {
>> +??????????? pinmux = <PINMUX_GPIO139__FUNC_B0_GBE_TXC>,
>> +???????????????? <PINMUX_GPIO142__FUNC_O_GBE_TXEN>,
>> +???????????????? <PINMUX_GPIO141__FUNC_I0_GBE_RXDV>;
>> +??????????? drive-strength = <MTK_DRIVE_8mA>;
>> +??????? };
>> +??????? pins-rxd {
>> +??????????? pinmux = <PINMUX_GPIO135__FUNC_I0_GBE_RXD3>,
>> +???????????????? <PINMUX_GPIO136__FUNC_I0_GBE_RXD2>,
>> +???????????????? <PINMUX_GPIO137__FUNC_I0_GBE_RXD1>,
>> +???????????????? <PINMUX_GPIO138__FUNC_I0_GBE_RXD0>,
>> +???????????????? <PINMUX_GPIO140__FUNC_I0_GBE_RXC>;
>> +??????????? drive-strength = <MTK_DRIVE_8mA>;
>> +??????????? bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
>> +??????? };
>> +??????? pins-mdio {
>> +??????????? pinmux = <PINMUX_GPIO143__FUNC_O_GBE_MDC>,
>> +???????????????? <PINMUX_GPIO144__FUNC_B1_GBE_MDIO>;
>> +??????????? drive-strength = <MTK_DRIVE_8mA>;
>> +??????????? input-enable;
>> +??????? };
>> +??????? pins-power {
>> +??????????? pinmux = <PINMUX_GPIO27__FUNC_B_GPIO27>; /* GP_EQOS_RESET */
>> +??????????? output-high;
>> +??????? };
>> +??????? pins-intr {
>> +??????????? pinmux = <PINMUX_GPIO148__FUNC_B_GPIO148>; /* GPIRQ_EQOS_PHY */
>> +??????????? bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
>> +??????????? input-enable;
>> +??????? };
>> +??? };
>> +
> 
> Cheers,
> Angelo



From angelogioacchino.delregno at collabora.com  Tue Dec  2 22:54:51 2025
From: angelogioacchino.delregno at collabora.com (AngeloGioacchino Del Regno)
Date: Wed, 3 Dec 2025 07:54:51 +0100
Subject: [PATCH v4 4/4] arm64: dts: mediatek: add device tree for Tungsten
 700 board
In-Reply-To: <20251202-review-v4-4-93f5cd2a0d4a@gmail.com>
References: <20251202-review-v4-0-93f5cd2a0d4a@gmail.com>
 <20251202-review-v4-4-93f5cd2a0d4a@gmail.com>
Message-ID: <f50544e4-1038-418a-a2bb-555865642984@collabora.com>

Il 02/12/25 23:08, Gary Bisson ha scritto:
> Add device tree to support Ezurio Tungsten 700 (MT8390) SMARC SOM [1] +
> Universal SMARC carrier board [2].
> It includes support for the MIPI-DSI BD070LIC3 display which uses the
> Tianma TM070JDHG30 panel + TI SN65DSI84 MIPI-DSI to LVDS bridge [3].
> 
> [1] https://www.ezurio.com/product/tungsten700-smarc
> [2] https://www.ezurio.com/system-on-module/accessories/universal-smarc-carrier
> [3] https://www.ezurio.com/product/bd070lic3-7-touchscreen-display
> 
> Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
> 
> ---
> Changes in v2:
> - None
> Changed in v3:
> - None
> Changed in v4:
> - None
> ---
>   arch/arm64/boot/dts/mediatek/Makefile              |  1 +
>   .../boot/dts/mediatek/mt8390-tungsten-smarc.dts    | 22 ++++++++++++++++++++++
>   2 files changed, 23 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile
> index 30d169a31b10..85f338344dd3 100644
> --- a/arch/arm64/boot/dts/mediatek/Makefile
> +++ b/arch/arm64/boot/dts/mediatek/Makefile
> @@ -102,6 +102,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-genio-510-evk.dtb
>   dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-tungsten-smarc.dtb
>   dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-genio-1200-evk.dtb
>   dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-genio-700-evk.dtb
> +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-tungsten-smarc.dtb
>   dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-kontron-3-5-sbc-i1200.dtb
>   dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-radxa-nio-12l.dtb
>   dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-radxa-nio-12l-8-hd-panel.dtbo
> diff --git a/arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts b/arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts
> new file mode 100644
> index 000000000000..f1cf2821107f
> --- /dev/null
> +++ b/arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts
> @@ -0,0 +1,22 @@
> +// SPDX-License-Identifier: (GPL-2.0 OR MIT)
> +/*
> + * Copyright (C) 2025 Ezurio LLC
> + * Author: Gary Bisson <bisson.gary at gmail.com>
> + */
> +/dts-v1/;
> +#include "mt8188.dtsi"
> +#include "mt83x0-tungsten-smarc.dtsi"

I just noticed: please, no wildcards in names - this has to be named
mt8390-tungsten-smarc.dtsi instead.

> +
> +/ {
> +	model = "Ezurio Tungsten700 SMARC (MT8390)";
> +	compatible = "ezurio,mt8390-tungsten-smarc", "mediatek,mt8390",
> +		     "mediatek,mt8188";
> +};
> +
> +&cpu4 {
> +	cpu-supply = <&mt6359_vcore_buck_reg>;
> +};
> +
> +&cpu5 {
> +	cpu-supply = <&mt6359_vcore_buck_reg>;
> +};
> 

You could also just put the cpu4 and cpu5 supplies in the common
mt8390-tungsten-smarc.dtsi file instead.

That's based on your own preference, so..

Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>


From angelogioacchino.delregno at collabora.com  Tue Dec  2 22:55:53 2025
From: angelogioacchino.delregno at collabora.com (AngeloGioacchino Del Regno)
Date: Wed, 3 Dec 2025 07:55:53 +0100
Subject: [PATCH v4 1/4] dt-bindings: vendor-prefixes: Add Ezurio LLC
In-Reply-To: <20251202-review-v4-1-93f5cd2a0d4a@gmail.com>
References: <20251202-review-v4-0-93f5cd2a0d4a@gmail.com>
 <20251202-review-v4-1-93f5cd2a0d4a@gmail.com>
Message-ID: <81ea7372-9172-4ee5-9a90-66cf06c40062@collabora.com>

Il 02/12/25 23:08, Gary Bisson ha scritto:
> Ezurio is the new name of Laird Connectivity after it acquired Boundary
> Devices.
> 
> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
> Signed-off-by: Gary Bisson <bisson.gary at gmail.com>

Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>




From angelogioacchino.delregno at collabora.com  Tue Dec  2 22:55:51 2025
From: angelogioacchino.delregno at collabora.com (AngeloGioacchino Del Regno)
Date: Wed, 3 Dec 2025 07:55:51 +0100
Subject: [PATCH v4 2/4] dt-bindings: arm: mediatek: Add Ezurio Tungsten
 entries
In-Reply-To: <20251202-review-v4-2-93f5cd2a0d4a@gmail.com>
References: <20251202-review-v4-0-93f5cd2a0d4a@gmail.com>
 <20251202-review-v4-2-93f5cd2a0d4a@gmail.com>
Message-ID: <7b09d179-be5f-4daf-bb74-c1420a3b6fa8@collabora.com>

Il 02/12/25 23:08, Gary Bisson ha scritto:
> Add device tree bindings support for the Ezurio Tungsten 510 (MT8370)
> SMARC [1] / Ezurio Tungsten 700 (MT8390) SMARC [2] + Universal SMARC
> carrier board [3].
> 
> [1] https://www.ezurio.com/product/tungsten510-smarc
> [2] https://www.ezurio.com/product/tungsten700-smarc
> [3] https://www.ezurio.com/system-on-module/accessories/universal-smarc-carrier
> 
> Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
> 

Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>




From lkp at intel.com  Tue Dec  2 22:59:30 2025
From: lkp at intel.com (kernel test robot)
Date: Wed, 3 Dec 2025 14:59:30 +0800
Subject: [PATCH v2 5/6] spi: imx: support dynamic burst length for ECSPI
 DMA mode
In-Reply-To: <20251202075503.2448339-6-carlos.song@nxp.com>
References: <20251202075503.2448339-6-carlos.song@nxp.com>
Message-ID: <202512031425.cmBJXuXy-lkp@intel.com>

Hi Carlos,

kernel test robot noticed the following build errors:

[auto build test ERROR on v6.18]
[also build test ERROR on linus/master next-20251202]
[cannot apply to shawnguo/for-next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Carlos-Song/spi-imx-group-spi_imx_dma_configure-with-spi_imx_dma_transfer/20251202-160030
base:   v6.18
patch link:    https://lore.kernel.org/r/20251202075503.2448339-6-carlos.song%40nxp.com
patch subject: [PATCH v2 5/6] spi: imx: support dynamic burst length for ECSPI DMA mode
config: csky-allmodconfig (https://download.01.org/0day-ci/archive/20251203/202512031425.cmBJXuXy-lkp at intel.com/config)
compiler: csky-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251203/202512031425.cmBJXuXy-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512031425.cmBJXuXy-lkp at intel.com/

All errors (new ones prefixed by >>):

>> drivers/spi/spi-imx.c:144:34: error: 'counted_by' attribute is not allowed for a non-array field
     144 |         struct dma_data_package *dma_data __counted_by(dma_package_num);
         |                                  ^~~~~~~~


vim +/counted_by +144 drivers/spi/spi-imx.c

   107	
   108	struct spi_imx_data {
   109		struct spi_controller *controller;
   110		struct device *dev;
   111	
   112		struct completion xfer_done;
   113		void __iomem *base;
   114		unsigned long base_phys;
   115	
   116		struct clk *clk_per;
   117		struct clk *clk_ipg;
   118		unsigned long spi_clk;
   119		unsigned int spi_bus_clk;
   120	
   121		unsigned int bits_per_word;
   122		unsigned int spi_drctl;
   123	
   124		unsigned int count, remainder;
   125		void (*tx)(struct spi_imx_data *spi_imx);
   126		void (*rx)(struct spi_imx_data *spi_imx);
   127		void *rx_buf;
   128		const void *tx_buf;
   129		unsigned int txfifo; /* number of words pushed in tx FIFO */
   130		unsigned int dynamic_burst;
   131		bool rx_only;
   132	
   133		/* Target mode */
   134		bool target_mode;
   135		bool target_aborted;
   136		unsigned int target_burst;
   137	
   138		/* DMA */
   139		bool usedma;
   140		u32 wml;
   141		struct completion dma_rx_completion;
   142		struct completion dma_tx_completion;
   143		size_t dma_package_num;
 > 144		struct dma_data_package *dma_data __counted_by(dma_package_num);
   145		int rx_offset;
   146	
   147		const struct spi_imx_devtype_data *devtype_data;
   148	};
   149	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From chancel.liu at nxp.com  Tue Dec  2 23:06:00 2025
From: chancel.liu at nxp.com (Chancel Liu)
Date: Wed,  3 Dec 2025 16:06:00 +0900
Subject: [PATCH 0/5] arm64: dts: imx91-11x11-evk: Add audio sound cards support
Message-ID: <20251203070605.1868821-1-chancel.liu@nxp.com>

Add audio sound cards support including bt-sco, WM8962, PDM microphone,
and audio XCVR sound cards.

Chancel Liu (5):
  arm64: dts: imx91-11x11-evk: Refine label and node name of WM8962
  arm64: dts: imx91-11x11-evk: Add bt-sco sound card support
  arm64: dts: imx91-11x11-evk: Add WM8962 sound card support
  arm64: dts: imx91-11x11-evk: Add PDM microphone sound card support
  arm64: dts: imx91-11x11-evk: Add audio XCVR sound card support

 .../boot/dts/freescale/imx91-11x11-evk.dts    | 181 +++++++++++++++++-
 1 file changed, 180 insertions(+), 1 deletion(-)

-- 
2.50.1



From chancel.liu at nxp.com  Tue Dec  2 23:06:01 2025
From: chancel.liu at nxp.com (Chancel Liu)
Date: Wed,  3 Dec 2025 16:06:01 +0900
Subject: [PATCH 1/5] arm64: dts: imx91-11x11-evk: Refine label and node name of WM8962
In-Reply-To: <20251203070605.1868821-1-chancel.liu@nxp.com>
References: <20251203070605.1868821-1-chancel.liu@nxp.com>
Message-ID: <20251203070605.1868821-2-chancel.liu@nxp.com>

Refine label with "wm8962" and node name with "codec" to follow
devicetree specification.

Signed-off-by: Chancel Liu <chancel.liu at nxp.com>
---
 arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts b/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
index aca78768dbd4..313ebc7e8a9c 100644
--- a/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
@@ -132,7 +132,7 @@ &lpi2c1 {
 	pinctrl-names = "default";
 	status = "okay";
 
-	audio_codec: wm8962 at 1a {
+	wm8962: codec at 1a {
 		compatible = "wlf,wm8962";
 		reg = <0x1a>;
 		clocks = <&clk IMX93_CLK_SAI3_GATE>;
-- 
2.50.1



From chancel.liu at nxp.com  Tue Dec  2 23:06:02 2025
From: chancel.liu at nxp.com (Chancel Liu)
Date: Wed,  3 Dec 2025 16:06:02 +0900
Subject: [PATCH 2/5] arm64: dts: imx91-11x11-evk: Add bt-sco sound card support
In-Reply-To: <20251203070605.1868821-1-chancel.liu@nxp.com>
References: <20251203070605.1868821-1-chancel.liu@nxp.com>
Message-ID: <20251203070605.1868821-3-chancel.liu@nxp.com>

Add bt-sco sound card, which is used by BT HFP case.
It supports wb profile as default.

Signed-off-by: Chancel Liu <chancel.liu at nxp.com>
---
 .../boot/dts/freescale/imx91-11x11-evk.dts    | 53 +++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts b/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
index 313ebc7e8a9c..55d2ccafc376 100644
--- a/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
@@ -31,6 +31,11 @@ aliases {
 		serial4 = &lpuart5;
 	};
 
+	bt_sco_codec: bt-sco-codec {
+		compatible = "linux,bt-sco";
+		#sound-dai-cells = <1>;
+	};
+
 	chosen {
 		stdout-path = &lpuart1;
 	};
@@ -77,6 +82,25 @@ linux,cma {
 			linux,cma-default;
 		};
 	};
+
+	sound-bt-sco {
+		compatible = "simple-audio-card";
+		simple-audio-card,name = "bt-sco-audio";
+		simple-audio-card,format = "dsp_a";
+		simple-audio-card,bitclock-inversion;
+		simple-audio-card,frame-master = <&btcpu>;
+		simple-audio-card,bitclock-master = <&btcpu>;
+
+		simple-audio-card,codec {
+			sound-dai = <&bt_sco_codec 1>;
+		};
+
+		btcpu: simple-audio-card,cpu {
+			sound-dai = <&sai1>;
+			dai-tdm-slot-num = <2>;
+			dai-tdm-slot-width = <16>;
+		};
+	};
 };
 
 &adc1 {
@@ -372,6 +396,17 @@ bluetooth {
 	};
 };
 
+&sai1 {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&pinctrl_sai1>;
+	pinctrl-1 = <&pinctrl_sai1_sleep>;
+	assigned-clocks = <&clk IMX93_CLK_SAI1>;
+	assigned-clock-parents = <&clk IMX93_CLK_AUDIO_PLL>;
+	assigned-clock-rates = <12288000>;
+	fsl,sai-mclk-direction-output;
+	status = "okay";
+};
+
 &usbotg1 {
 	adp-disable;
 	disable-over-current;
@@ -528,6 +563,24 @@ MX91_PAD_I2C2_SDA__LPI2C2_SDA                           0x40000b9e
 		>;
 	};
 
+	pinctrl_sai1: sai1grp {
+		fsl,pins = <
+			MX91_PAD_SAI1_TXC__SAI1_TX_BCLK			0x31e
+			MX91_PAD_SAI1_TXFS__SAI1_TX_SYNC		0x31e
+			MX91_PAD_SAI1_TXD0__SAI1_TX_DATA0		0x31e
+			MX91_PAD_SAI1_RXD0__SAI1_RX_DATA0		0x31e
+		>;
+	};
+
+	pinctrl_sai1_sleep: sai1sleepgrp {
+		fsl,pins = <
+			MX91_PAD_SAI1_TXC__GPIO1_IO12			0x51e
+			MX91_PAD_SAI1_TXFS__GPIO1_IO11			0x51e
+			MX91_PAD_SAI1_TXD0__GPIO1_IO13			0x51e
+			MX91_PAD_SAI1_RXD0__GPIO1_IO14			0x51e
+		>;
+	};
+
 	pinctrl_lpi2c3: lpi2c3grp {
 		fsl,pins = <
 			MX91_PAD_GPIO_IO28__LPI2C3_SDA                          0x40000b9e
-- 
2.50.1



From chancel.liu at nxp.com  Tue Dec  2 23:06:03 2025
From: chancel.liu at nxp.com (Chancel Liu)
Date: Wed,  3 Dec 2025 16:06:03 +0900
Subject: [PATCH 3/5] arm64: dts: imx91-11x11-evk: Add WM8962 sound card support
In-Reply-To: <20251203070605.1868821-1-chancel.liu@nxp.com>
References: <20251203070605.1868821-1-chancel.liu@nxp.com>
Message-ID: <20251203070605.1868821-4-chancel.liu@nxp.com>

Add WM8962 sound card support which connects to SAI3.

Signed-off-by: Chancel Liu <chancel.liu at nxp.com>
---
 .../boot/dts/freescale/imx91-11x11-evk.dts    | 47 +++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts b/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
index 55d2ccafc376..a70a9af50ab7 100644
--- a/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
@@ -83,6 +83,22 @@ linux,cma {
 		};
 	};
 
+	sound-wm8962 {
+		compatible = "fsl,imx-audio-wm8962";
+		model = "wm8962-audio";
+		audio-cpu = <&sai3>;
+		audio-codec = <&wm8962>;
+		hp-det-gpio = <&pcal6524 4 GPIO_ACTIVE_HIGH>;
+		audio-routing =
+			"Headphone Jack", "HPOUTL",
+			"Headphone Jack", "HPOUTR",
+			"Ext Spk", "SPKOUTL",
+			"Ext Spk", "SPKOUTR",
+			"AMIC", "MICBIAS",
+			"IN3R", "AMIC",
+			"IN1R", "AMIC";
+	};
+
 	sound-bt-sco {
 		compatible = "simple-audio-card";
 		simple-audio-card,name = "bt-sco-audio";
@@ -407,6 +423,17 @@ &sai1 {
 	status = "okay";
 };
 
+&sai3 {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&pinctrl_sai3>;
+	pinctrl-1 = <&pinctrl_sai3_sleep>;
+	assigned-clocks = <&clk IMX93_CLK_SAI3>;
+	assigned-clock-parents = <&clk IMX93_CLK_AUDIO_PLL>;
+	assigned-clock-rates = <12288000>;
+	fsl,sai-mclk-direction-output;
+	status = "okay";
+};
+
 &usbotg1 {
 	adp-disable;
 	disable-over-current;
@@ -581,6 +608,26 @@ MX91_PAD_SAI1_RXD0__GPIO1_IO14			0x51e
 		>;
 	};
 
+	pinctrl_sai3: sai3grp {
+		fsl,pins = <
+			MX91_PAD_GPIO_IO16__SAI3_TX_BCLK		0x31e
+			MX91_PAD_GPIO_IO17__SAI3_MCLK			0x31e
+			MX91_PAD_GPIO_IO19__SAI3_TX_DATA0		0x31e
+			MX91_PAD_GPIO_IO20__SAI3_RX_DATA0		0x31e
+			MX91_PAD_GPIO_IO26__SAI3_TX_SYNC		0x31e
+		>;
+	};
+
+	pinctrl_sai3_sleep: sai3sleepgrp {
+		fsl,pins = <
+			MX91_PAD_GPIO_IO16__GPIO2_IO16			0x51e
+			MX91_PAD_GPIO_IO17__GPIO2_IO17			0x51e
+			MX91_PAD_GPIO_IO19__GPIO2_IO19			0x51e
+			MX91_PAD_GPIO_IO20__GPIO2_IO20			0x51e
+			MX91_PAD_GPIO_IO26__GPIO2_IO26			0x51e
+		>;
+	};
+
 	pinctrl_lpi2c3: lpi2c3grp {
 		fsl,pins = <
 			MX91_PAD_GPIO_IO28__LPI2C3_SDA                          0x40000b9e
-- 
2.50.1



From chancel.liu at nxp.com  Tue Dec  2 23:06:04 2025
From: chancel.liu at nxp.com (Chancel Liu)
Date: Wed,  3 Dec 2025 16:06:04 +0900
Subject: [PATCH 4/5] arm64: dts: imx91-11x11-evk: Add PDM microphone sound card support
In-Reply-To: <20251203070605.1868821-1-chancel.liu@nxp.com>
References: <20251203070605.1868821-1-chancel.liu@nxp.com>
Message-ID: <20251203070605.1868821-5-chancel.liu@nxp.com>

Add PDM micphone sound card support.

This sound card supports recording sound from PDM microphone
and convert the PDM format data to PCM data.

Signed-off-by: Chancel Liu <chancel.liu at nxp.com>
---
 .../boot/dts/freescale/imx91-11x11-evk.dts    | 40 +++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts b/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
index a70a9af50ab7..605b1d10513a 100644
--- a/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
@@ -117,6 +117,20 @@ btcpu: simple-audio-card,cpu {
 			dai-tdm-slot-width = <16>;
 		};
 	};
+
+	sound-micfil {
+		compatible = "fsl,imx-audio-card";
+		model = "micfil-audio";
+
+		pri-dai-link {
+			link-name = "micfil hifi";
+			format = "i2s";
+
+			cpu {
+				sound-dai = <&micfil>;
+			};
+		};
+	};
 };
 
 &adc1 {
@@ -412,6 +426,16 @@ bluetooth {
 	};
 };
 
+&micfil {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&pinctrl_pdm>;
+	pinctrl-1 = <&pinctrl_pdm_sleep>;
+	assigned-clocks = <&clk IMX93_CLK_PDM>;
+	assigned-clock-parents = <&clk IMX93_CLK_AUDIO_PLL>;
+	assigned-clock-rates = <49152000>;
+	status = "okay";
+};
+
 &sai1 {
 	pinctrl-names = "default", "sleep";
 	pinctrl-0 = <&pinctrl_sai1>;
@@ -590,6 +614,22 @@ MX91_PAD_I2C2_SDA__LPI2C2_SDA                           0x40000b9e
 		>;
 	};
 
+	pinctrl_pdm: pdmgrp {
+		fsl,pins = <
+			MX91_PAD_PDM_CLK__PDM_CLK			0x31e
+			MX91_PAD_PDM_BIT_STREAM0__PDM_BIT_STREAM0	0x31e
+			MX91_PAD_PDM_BIT_STREAM1__PDM_BIT_STREAM1	0x31e
+		>;
+	};
+
+	pinctrl_pdm_sleep: pdmsleepgrp {
+		fsl,pins = <
+			MX91_PAD_PDM_CLK__GPIO1_IO8			0x51e
+			MX91_PAD_PDM_BIT_STREAM0__GPIO1_IO9		0x51e
+			MX91_PAD_PDM_BIT_STREAM1__GPIO1_IO10		0x51e
+		>;
+	};
+
 	pinctrl_sai1: sai1grp {
 		fsl,pins = <
 			MX91_PAD_SAI1_TXC__SAI1_TX_BCLK			0x31e
-- 
2.50.1



From chancel.liu at nxp.com  Tue Dec  2 23:06:05 2025
From: chancel.liu at nxp.com (Chancel Liu)
Date: Wed,  3 Dec 2025 16:06:05 +0900
Subject: [PATCH 5/5] arm64: dts: imx91-11x11-evk: Add audio XCVR sound card support
In-Reply-To: <20251203070605.1868821-1-chancel.liu@nxp.com>
References: <20251203070605.1868821-1-chancel.liu@nxp.com>
Message-ID: <20251203070605.1868821-6-chancel.liu@nxp.com>

Add audio XCVR sound card, which supports SPDIF TX & RX only,
eARC RX, ARC RX are not supported.

Signed-off-by: Chancel Liu <chancel.liu at nxp.com>
---
 .../boot/dts/freescale/imx91-11x11-evk.dts    | 39 +++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts b/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
index 605b1d10513a..3cd9808fc332 100644
--- a/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
@@ -131,6 +131,19 @@ cpu {
 			};
 		};
 	};
+
+	sound-xcvr {
+		compatible = "fsl,imx-audio-card";
+		model = "imx-audio-xcvr";
+
+		pri-dai-link {
+			link-name = "XCVR PCM";
+
+			cpu {
+				sound-dai = <&xcvr>;
+			};
+		};
+	};
 };
 
 &adc1 {
@@ -523,6 +536,18 @@ &wdog3 {
 	status = "okay";
 };
 
+&xcvr {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&pinctrl_spdif>;
+	pinctrl-1 = <&pinctrl_spdif_sleep>;
+	assigned-clocks = <&clk IMX93_CLK_SPDIF>,
+			  <&clk IMX93_CLK_AUDIO_XCVR>;
+	assigned-clock-parents = <&clk IMX93_CLK_AUDIO_PLL>,
+				 <&clk IMX93_CLK_SYS_PLL_PFD1_DIV2>;
+	assigned-clock-rates = <12288000>, <200000000>;
+	status = "okay";
+};
+
 &iomuxc {
 	pinctrl_eqos: eqosgrp {
 		fsl,pins = <
@@ -668,6 +693,20 @@ MX91_PAD_GPIO_IO26__GPIO2_IO26			0x51e
 		>;
 	};
 
+	pinctrl_spdif: spdifgrp {
+		fsl,pins = <
+			MX91_PAD_GPIO_IO22__SPDIF_IN			0x31e
+			MX91_PAD_GPIO_IO23__SPDIF_OUT			0x31e
+		>;
+	};
+
+	pinctrl_spdif_sleep: spdifsleepgrp {
+		fsl,pins = <
+			MX91_PAD_GPIO_IO22__GPIO2_IO22			0x51e
+			MX91_PAD_GPIO_IO23__GPIO2_IO23			0x51e
+		>;
+	};
+
 	pinctrl_lpi2c3: lpi2c3grp {
 		fsl,pins = <
 			MX91_PAD_GPIO_IO28__LPI2C3_SDA                          0x40000b9e
-- 
2.50.1



From anshuman.khandual at arm.com  Tue Dec  2 23:07:48 2025
From: anshuman.khandual at arm.com (Anshuman Khandual)
Date: Wed, 3 Dec 2025 12:37:48 +0530
Subject: [v2 PATCH] arm64: mm: Fix kexec failure after pte_mkwrite_novma()
 change
In-Reply-To: <58d796ec-b430-4fc0-9a1c-8f1a6150f051@windriver.com>
References: <20251202022707.2720933-1-jianpeng.chang.cn@windriver.com>
 <381a3974-aafa-419f-a7ad-ed6e4c1671f0@arm.com>
 <58d796ec-b430-4fc0-9a1c-8f1a6150f051@windriver.com>
Message-ID: <296f9c4b-8c93-4464-9b75-e06770a4bd31@arm.com>



On 02/12/25 1:25 PM, Jianpeng Chang wrote:
> 
> On 12/2/25 2:57 PM, Anshuman Khandual wrote:
>> CAUTION: This email comes from a non Wind River email account!
>> Do not click links or open attachments unless you recognize the sender and know the content is safe.
>>
>> On 02/12/25 7:57 AM, Jianpeng Chang wrote:
>>> Commit 143937ca51cc ("arm64, mm: avoid always making PTE dirty in
>>> pte_mkwrite()") modified pte_mkwrite_novma() to only clear PTE_RDONLY
>>> when the page is already dirty (PTE_DIRTY is set). While this optimization
>>> prevents unnecessary dirty page marking in normal memory management paths,
>>> it breaks kexec on some platforms like NXP LS1043.
>>>
>>> The issue occurs in the kexec code path:
>>> 1. machine_kexec_post_load() calls trans_pgd_create_copy() to create a
>>>    writable copy of the linear mapping
>>> 2. _copy_pte() calls pte_mkwrite_novma() to ensure all pages in the copy
>>>    are writable for the new kernel image copying
>>> 3. With the new logic, clean pages (without PTE_DIRTY) remain read-only
>>> 4. When kexec tries to copy the new kernel image through the linear
>>>    mapping, it fails on read-only pages, causing the system to hang
>>>    after "Bye!"
>>>
>>> The same issue affects hibernation which uses the same trans_pgd code path.
>>>
>>> Fix this by explicitly clearing PTE_RDONLY in _copy_pte() for both
>> via pte_mkdirty() ?
> Sorry, for this.
> 
> Fix this by marking pages dirty with pte_mkdirty() in _copy_pte(), which
> ensures pte_mkwrite_novma() clears PTE_RDONLY for both kexec and
> hibernation, making all pages in the temporary mapping writable
> regardless of their dirty state.

Fair enough.

>>
>>> kexec and hibernation, ensuring all pages in the temporary mapping are
>>> writable regardless of their dirty state. This preserves the original
>>> commit's optimization for normal memory management while fixing the
>>> kexec/hibernation regression.
>>>
>>> Fixes: 143937ca51cc ("arm64, mm: avoid always making PTE dirty in pte_mkwrite()")
>>> Signed-off-by: Jianpeng Chang <jianpeng.chang.cn at windriver.com>
>>> ---
>>> v2:
>>>   - Use pte_mkwrite_novma(pte_mkdirty(pte)) instead of manual bit manipulation
>>>   - Updated comments to clarify pte_mkwrite_novma() alone cannot be used
>>> v1: https://lore.kernel.org/all/20251127034350.3600454-1-jianpeng.chang.cn at windriver.com/
>>>
>>>  arch/arm64/mm/trans_pgd.c | 9 +++++++--
>>>  1 file changed, 7 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/arch/arm64/mm/trans_pgd.c b/arch/arm64/mm/trans_pgd.c
>>> index 18543b603c77..08f5ee6643e1 100644
>>> --- a/arch/arm64/mm/trans_pgd.c
>>> +++ b/arch/arm64/mm/trans_pgd.c
>>> @@ -40,8 +40,13 @@ static void _copy_pte(pte_t *dst_ptep, pte_t *src_ptep, unsigned long addr)
>>>                * Resume will overwrite areas that may be marked
>>>                * read only (code, rodata). Clear the RDONLY bit from
>>>                * the temporary mappings we use during restore.
>>> +              *
>>> +              * For kexec/hibernation, we need writable access to all
>>> +              * pages in the linear mapping to copy the new kernel image.
>>> +              * Mark pages dirty first to ensure pte_mkwrite_novma()
>>> +              * clears PTE_RDONLY.
>>>                */
>>                /*
>>                 * For both kexec and hibernation, writable accesses are required
>>                 * for all pages in the linear map to copy over new kernel image.
>>                 * Hence mark these pages dirty first via pte_mkdirty() to ensure
>>                 * pte_mkwrite_novma() subsequently clears PTE_RDONLY - providing
>>                 * required write access for the pages.
>>                 */
> I will change it.
>>
>>> -             __set_pte(dst_ptep, pte_mkwrite_novma(pte));
>>> +             __set_pte(dst_ptep, pte_mkwrite_novma(pte_mkdirty(pte)));
>>>       } else if (!pte_none(pte)) {
>>>               /*
>>>                * debug_pagealloc will removed the PTE_VALID bit if
>>> @@ -57,7 +62,7 @@ static void _copy_pte(pte_t *dst_ptep, pte_t *src_ptep, unsigned long addr)
>>>                */
>>>               BUG_ON(!pfn_valid(pte_pfn(pte)));
>>>
>> The comments should be replicated here as well given the same special situation.
> I will change it.
>>
>>> -             __set_pte(dst_ptep, pte_mkvalid(pte_mkwrite_novma(pte)));
>>> +             __set_pte(dst_ptep, pte_mkvalid(pte_mkwrite_novma(pte_mkdirty(pte))));
>>>       }
>>>  }
>>>
>> static inline pte_t pte_mkwrite_novma(pte_t pte)
>> {
>>         pte = set_pte_bit(pte, __pgprot(PTE_WRITE));
>>         if (pte_sw_dirty(pte))
>>                 pte = clear_pte_bit(pte, __pgprot(PTE_RDONLY));
>>         return pte;
>> }
>>
>> static inline pte_t pte_mkdirty(pte_t pte)
>> {
>>         pte = set_pte_bit(pte, __pgprot(PTE_DIRTY));
>>
>>         if (pte_write(pte))
>>                 pte = clear_pte_bit(pte, __pgprot(PTE_RDONLY));
>>
>>         return pte;
>> }
>>
>> So if pte_write() is true, there will be a redundant PTE_RDONLY clearing which is OK.
>> Should this be mentioned in the commit message ?
> TBH, I don't have a better idea - any suggestions?
> 
> Or, let's add some lines:
> 
> Using pte_mkdirty() causes redundant bit operations, but this is
> acceptable since it's not a hot path.

Makes sense - better to call out potential redundancies.


From krzk at kernel.org  Tue Dec  2 23:20:50 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 3 Dec 2025 08:20:50 +0100
Subject: [PATCH v20 3/7] firmware: imx: add driver for NXP EdgeLock
 Enclave
In-Reply-To: <20251203-imx-se-if-v20-3-a04a25c4255f@nxp.com>
References: <20251203-imx-se-if-v20-0-a04a25c4255f@nxp.com>
 <20251203-imx-se-if-v20-3-a04a25c4255f@nxp.com>
Message-ID: <1ee383c7-ccbc-4c90-adf3-bfbe87fb6765@kernel.org>

On 03/12/2025 07:48, Pankaj Gupta wrote:
> Add driver for enabling MU based communication interface to secure-enclave.
> 
> NXP hardware IP(s) for secure-enclaves like Edgelock Enclave(ELE), are
> embedded in the SoC to support the features like HSM, SHE & V2X, using
> message based communication interface.
> 
> The secure enclave FW communicates with Linux over single or multiple
> dedicated messaging unit(MU) based interface(s).
> Exists on i.MX SoC(s) like i.MX8ULP, i.MX93, i.MX95 etc.
> 
> For i.MX9x SoC(s) there is at least one dedicated ELE MU(s) for each
> world - Linux(one or more) and OPTEE-OS (one or more).
> 
> Other dependent kernel drivers will be:
> - NVMEM: that supports non-volatile devices like EFUSES,
>          managed by NXP's secure-enclave.
> 
> Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
> Reviewed-by: Frank Li <Frank.Li at nxp.com>
> ---
>  drivers/firmware/imx/Kconfig        |  13 ++
>  drivers/firmware/imx/Makefile       |   2 +
>  drivers/firmware/imx/ele_base_msg.c | 269 ++++++++++++++++++++++++
>  drivers/firmware/imx/ele_base_msg.h |  95 +++++++++
>  drivers/firmware/imx/ele_common.c   | 333 ++++++++++++++++++++++++++++++
>  drivers/firmware/imx/ele_common.h   |  45 ++++
>  drivers/firmware/imx/se_ctrl.c      | 401 ++++++++++++++++++++++++++++++++++++
>  drivers/firmware/imx/se_ctrl.h      |  86 ++++++++
>  include/linux/firmware/imx/se_api.h |  14 ++
>  9 files changed, 1258 insertions(+)
> 
> diff --git a/drivers/firmware/imx/Kconfig b/drivers/firmware/imx/Kconfig
> index 127ad752acf8..5fe96299b704 100644
> --- a/drivers/firmware/imx/Kconfig
> +++ b/drivers/firmware/imx/Kconfig
> @@ -55,3 +55,16 @@ config IMX_SCMI_MISC_DRV
>  	  core that could provide misc functions such as board control.
>  
>  	  This driver can also be built as a module.
> +
> +config IMX_SEC_ENCLAVE
> +	tristate "i.MX Embedded Secure Enclave - EdgeLock Enclave Firmware driver."
> +	depends on IMX_MBOX && ARCH_MXC && ARM64
> +	select FW_LOADER
> +	default m if ARCH_MXC
> +
> +	help
> +	  Exposes APIs supported by the iMX Secure Enclave HW IP called:
> +	  - EdgeLock Enclave Firmware (for i.MX8ULP, i.MX93),
> +	    like base, HSM, V2X & SHE using the SAB protocol via the shared Messaging
> +	    Unit. This driver exposes these interfaces via a set of file descriptors
> +	    allowing to configure shared memory, send and receive messages.
> diff --git a/drivers/firmware/imx/Makefile b/drivers/firmware/imx/Makefile
> index 3bbaffa6e347..4412b15846b1 100644
> --- a/drivers/firmware/imx/Makefile
> +++ b/drivers/firmware/imx/Makefile
> @@ -4,3 +4,5 @@ obj-$(CONFIG_IMX_SCU)		+= imx-scu.o misc.o imx-scu-irq.o rm.o imx-scu-soc.o
>  obj-${CONFIG_IMX_SCMI_CPU_DRV}	+= sm-cpu.o
>  obj-${CONFIG_IMX_SCMI_MISC_DRV}	+= sm-misc.o
>  obj-${CONFIG_IMX_SCMI_LMM_DRV}	+= sm-lmm.o
> +sec_enclave-objs		= se_ctrl.o ele_common.o ele_base_msg.o
> +obj-${CONFIG_IMX_SEC_ENCLAVE}	+= sec_enclave.o
> diff --git a/drivers/firmware/imx/ele_base_msg.c b/drivers/firmware/imx/ele_base_msg.c
> new file mode 100644
> index 000000000000..a070acbd895c
> --- /dev/null
> +++ b/drivers/firmware/imx/ele_base_msg.c
> @@ -0,0 +1,269 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright 2025 NXP
> + */
> +
> +#include <linux/types.h>
> +
> +#include <linux/completion.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/genalloc.h>
> +
> +#include "ele_base_msg.h"
> +#include "ele_common.h"
> +
> +#define FW_DBG_DUMP_FIXED_STR		"ELE"
> +
> +int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info)
> +{
> +	struct se_api_msg *tx_msg __free(kfree) = NULL;
> +	struct se_api_msg *rx_msg __free(kfree) = NULL;

No, don't use this syntax. This is explicitly discouraged.

NAK

Best regards,
Krzysztof


From wenst at chromium.org  Tue Dec  2 23:34:25 2025
From: wenst at chromium.org (Chen-Yu Tsai)
Date: Wed, 3 Dec 2025 15:34:25 +0800
Subject: Proposal: Officially allow "incomplete" trees as a base
In-Reply-To: <CAD=FV=Uq9yfUkLUgg116G+2AvEKkEPmdRgUJ5f1bj229j=LxUg@mail.gmail.com>
References: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
 <CAD++jLkuRQKoiEN928GtAj7wUts5PxH905bLp6ZhKsJ3NnenEA@mail.gmail.com>
 <CAD=FV=X5=AK4XMANv+fatn3d9Y5vo9AXsHWb_47HmNaMWUtMwA@mail.gmail.com>
 <CAGXv+5HyMYgKmLc+jmkj-gytm9SNVg9dS7Vn3dQ-dsH8Wo+4sg@mail.gmail.com> <CAD=FV=Uq9yfUkLUgg116G+2AvEKkEPmdRgUJ5f1bj229j=LxUg@mail.gmail.com>
Message-ID: <CAGXv+5HU2y-8AZhXDjneaTdD1yr2h06OXbkozcQJj2mBcR1HmQ@mail.gmail.com>

On Wed, Dec 3, 2025 at 6:11?AM Doug Anderson <dianders at chromium.org> wrote:
>
> Hi,
>
> On Mon, Dec 1, 2025 at 7:31?PM Chen-Yu Tsai <wenst at chromium.org> wrote:
> >
> > > Separately, it can be noted that we always _wanted_ a similar solution
> > > for ChromeOS, but we never quite got there... ;-)
> >
> > FTR ChromeOS is moving in that direction: splitting SKU differences
> > based on components into overlays that get applied to the base by the
> > bootloader.
> >
> > In the simplest example we could have one base dts and two overlays
> > for two different DSI panel models:
> >
> >   - base.dtb
> >     - panel-model-a.dtbo
> >     - panel-model-b.dtbo
> >
> > The problem we then run into is that the base.dtb will only have the
> > generic model compatible "google,foo", not the sku and revision
> > specific ones like "google,foo-sku1-rev2".
> >
> > And we'd really like to avoid having _more_ overlays just to add the
> > final specific compatible string, as that kind of defeats the purpose
> > of using overlays to reduce the number of dts files.
>
> I think you may have simplified the above a little too much to the
> point where it's confusing. At least I'm a bit confused. I _think_ the
> problems you're talking about are the kinds of things we run into when
> we take overlays above just two levels. I'm imagining:
>
> - base.dtb
> - board1-rev1.dtbo
> - board2-rev1.dtbo
> - board1-rev2.dtbo
> - board2-rev2.dtbo
> - panel-a.dtbo
> - panel-b.dtbo
>
> So I think you're saying that you'd start with the "base.dtb" and then
> extend it with exactly one of the "board" overlays and then exactly
> one of the "panel" overlays. Is that right?

For now I think we just experiment with having one end "model" or
"product" as the base.dtb. The panel-*.dtbo selected describe the
optional components, while the board-rev??.dtbo just provides the
top level compatible and model.

In an example that I plan to send out this week, I would rework:

  - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri.dtsi
    - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku0.dts
    - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku1.dts
    - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku2.dts
    - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku3.dts
    - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku4.dts
    - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku5.dts
    - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku6.dts
    - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku7.dts

into:

  - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri.dts
    - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-audio-max98390-es8326.dtso
    - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-audio-max98390-rt5682s.dtso
    - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-audio-tas2563-es8326.dtso
    - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-audio-tas2563-rt5682s.dtso
    - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-panel-boe.dtso
    - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-panel-ivo.dtso
    - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku0.dtso
    - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku1.dtso
    - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku2.dtso
    - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku3.dtso
    - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku4.dtso
    - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku5.dtso
    - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku6.dtso
    - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku7.dtso

The "mt8188-geralt-ciri-sku?.dtso" files only contain the following
boilerplate:

    /dts-v1/;
    /plugin/;

    &{/} {
        model = "Google Ciri sku? board (rev4)";
        compatible = "google,ciri-sku?", "google,ciri", "mediatek,mt8188";
    };

The base "mt8188-geralt-ciri.dts" would already have a generic board-
specific compatible:

    model = "Google Ciri board";
    compatible = "google,ciri", "mediatek,mt8188";

> So I'd imagine that each of the "board" overlays could have "full"
> compatible strings. For instance, I'd imagine "board2-rev2" could
> have:
>
> compatible = "google,booard2-rev2", "socVendor,soc"
>
>
> The problem you're struggling with (I think) is that the panel
> overlays won't be represented in the compatible string (and "model")
> even though (historically) we always did in ChromeOS (they were
> included in the "sku" part of the compatible string).
>
> Did I get that right?

In a sense you've generalized the problem I was describing.

In my example, the top level compatible gets fixed up by the final
SKU-specific overlay. But that's 8 extra files to do one bit of
fixup that supposedly the bootloader could be taught to do, and
could do even better. The bootloader knows exactly which SKU and
revision it's running on and can insert the information appropriately.
We could get rid of those awkwardly long compatible string sequences:

  compatible = "google,tentacruel-sku262147", "google,tentacruel-sku262146",
               "google,tentacruel-sku262145", "google,tentacruel-sku262144",
               "google,tentacruel", "mediatek,mt8186";

Going back to what I think you're describing, is that instead of one
base board DTB for each product, we could have one base DTB for the
reference design (in place of the .dtsi file we currently have), and
make products and component selection all use overlays.

If we do that, then inserting the correct top level compatible and model
becomes more important, since we do have things such as the ChromeOS OF
component prober working based on top level compatible. Also, the model
is present in logs, and would be very misleading to say one device name
while in reality it is a different one.

> > I proposed internally maybe having the bootloader fix up the final
> > compatible string, but I think we need some rough consensus upstream
> > whether this is acceptable or not.
>
> Maybe we need to come to some agreement about when the top-level
> compatible string needs to be changed. In the above, I'd perhaps argue
> that the panel isn't a major enough change that it needs to change the
> top-level compatible string. That would solve the problem, right? What
> do others think? Certainly for "probe-able" components we don't change
> the top-level compatible string. Can anyone point to any official
> documentation about the top-level compatible string?

I'd certainly like more documentation as well.


ChenYu


From krzk at kernel.org  Tue Dec  2 23:49:59 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 3 Dec 2025 08:49:59 +0100
Subject: [PATCH v4 2/4] dt-bindings: arm: mediatek: Add Ezurio Tungsten
 entries
In-Reply-To: <20251202-review-v4-2-93f5cd2a0d4a@gmail.com>
References: <20251202-review-v4-0-93f5cd2a0d4a@gmail.com>
 <20251202-review-v4-2-93f5cd2a0d4a@gmail.com>
Message-ID: <1baf8704-9f56-4bb0-8118-5a0cfec92b7e@kernel.org>

On 02/12/2025 23:08, Gary Bisson wrote:
> Add device tree bindings support for the Ezurio Tungsten 510 (MT8370)
> SMARC [1] / Ezurio Tungsten 700 (MT8390) SMARC [2] + Universal SMARC
> carrier board [3].
> 
> [1] https://www.ezurio.com/product/tungsten510-smarc
> [2] https://www.ezurio.com/product/tungsten700-smarc
> [3] https://www.ezurio.com/system-on-module/accessories/universal-smarc-carrier
> 
> Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
> 


Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof


From u-kumar1 at ti.com  Tue Dec  2 23:50:24 2025
From: u-kumar1 at ti.com (Kumar, Udit)
Date: Wed, 3 Dec 2025 13:20:24 +0530
Subject: [PATCH RFC v2 3/4] clk: keystone: sci-clk: add restore_context()
 operation
In-Reply-To: <20251127-ti-sci-jacinto-s2r-restore-irq-v2-3-a487fa3ff221@bootlin.com>
References: <20251127-ti-sci-jacinto-s2r-restore-irq-v2-0-a487fa3ff221@bootlin.com>
 <20251127-ti-sci-jacinto-s2r-restore-irq-v2-3-a487fa3ff221@bootlin.com>
Message-ID: <1283df52-ee41-477f-8d91-5c4a02385cef@ti.com>


On 11/27/2025 2:08 PM, Thomas Richard (TI.com) wrote:
> Implement the restore_context() operation to restore the clock parent
> state. The parent index is saved in sci_clk struct during set_parent().
> During clock registration, the core retrieves each clock?s parent using
> get_parent() operation to ensure the internal clock tree reflects the
> actual hardware state, including any configurations made by the
> bootloader. So we also save the parent index in get_parent().
>
> Signed-off-by: Thomas Richard (TI.com) <thomas.richard at bootlin.com>
> ---
>   drivers/clk/keystone/sci-clk.c | 25 ++++++++++++++++++++-----
>   1 file changed, 20 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/clk/keystone/sci-clk.c b/drivers/clk/keystone/sci-clk.c
> index a4b42811de55d..1e5dd01484d1c 100644
> --- a/drivers/clk/keystone/sci-clk.c
> +++ b/drivers/clk/keystone/sci-clk.c
> @@ -47,6 +47,7 @@ struct sci_clk_provider {
>    * @node:	 Link for handling clocks probed via DT
>    * @cached_req:	 Cached requested freq for determine rate calls
>    * @cached_res:	 Cached result freq for determine rate calls
> + * @parent_id:	 Parent index for this clock
>    */
>   struct sci_clk {
>   	struct clk_hw hw;
> @@ -58,6 +59,7 @@ struct sci_clk {
>   	struct list_head node;
>   	unsigned long cached_req;
>   	unsigned long cached_res;
> +	u8 parent_id;

you may need to restore rate as well


>   };
>   
>   #define to_sci_clk(_hw) container_of(_hw, struct sci_clk, hw)
> @@ -237,9 +239,9 @@ static u8 sci_clk_get_parent(struct clk_hw *hw)
>   		return 0;
>   	}
>   
> -	parent_id = parent_id - clk->clk_id - 1;
> +	clk->parent_id = (u8)(parent_id - clk->clk_id - 1);
>   
> -	return (u8)parent_id;
> +	return clk->parent_id;
>   }
>   
>   /**
> @@ -252,12 +254,24 @@ static u8 sci_clk_get_parent(struct clk_hw *hw)
>   static int sci_clk_set_parent(struct clk_hw *hw, u8 index)
>   {
>   	struct sci_clk *clk = to_sci_clk(hw);
> +	int ret;
>   
>   	clk->cached_req = 0;
>   
> -	return clk->provider->ops->set_parent(clk->provider->sci, clk->dev_id,
> -					      clk->clk_id,
> -					      index + 1 + clk->clk_id);
> +	ret = clk->provider->ops->set_parent(clk->provider->sci, clk->dev_id,
> +					     clk->clk_id,
> +					     index + 1 + clk->clk_id);
> +	if (!ret)
> +		clk->parent_id = index;
> +
> +	return ret;
> +}
> +
> +static void sci_clk_restore_context(struct clk_hw *hw)
> +{
> +	struct sci_clk *clk = to_sci_clk(hw);
> +
> +	sci_clk_set_parent(hw, clk->parent_id);

You should restore,? if this is BOARD_CFG managed


>   }
>   
>   static const struct clk_ops sci_clk_ops = {
> @@ -269,6 +283,7 @@ static const struct clk_ops sci_clk_ops = {
>   	.set_rate = sci_clk_set_rate,
>   	.get_parent = sci_clk_get_parent,
>   	.set_parent = sci_clk_set_parent,
> +	.restore_context = sci_clk_restore_context,
>   };
>   
>   /**
>


From zhenglifeng1 at huawei.com  Tue Dec  2 23:55:34 2025
From: zhenglifeng1 at huawei.com (zhenglifeng (A))
Date: Wed, 3 Dec 2025 15:55:34 +0800
Subject: [PATCH v4 0/3] cpufreq: CPPC: Update FIE arch_freq_scale in ticks
 for non-PCC regs
In-Reply-To: <20251203032422.3232957-1-zhanjie9@hisilicon.com>
References: <20251203032422.3232957-1-zhanjie9@hisilicon.com>
Message-ID: <51dc71f8-8208-40c6-8ecd-50abd79a036a@huawei.com>

Reviewed-by: Lifeng Zheng <zhenglifeng1 at huawei.com>

On 2025/12/3 11:24, Jie Zhan wrote:
> Currently, the CPPC Frequency Invariance Engine (FIE) is invoked from the
> scheduler tick but defers the update of arch_freq_scale to a separate
> thread because cppc_get_perf_ctrs() would sleep if the CPC regs are in PCC.
> 
> However, this deferred update mechanism is unnecessary and introduces extra
> overhead for non-PCC register spaces (e.g. System Memory or FFH), where
> accessing the regs won't sleep and can be safely performed from the tick
> context.
> 
> Furthermore, with the CPPC FIE registered, it throws repeated warnings of
> "cppc_scale_freq_workfn: failed to read perf counters" on our platform with
> the CPC regs in System Memory and a power-down idle state enabled.  That's
> because the remote CPU can be in a power-down idle state, and reading its
> perf counters returns 0.  Moving the FIE handling back to the scheduler
> tick process makes the CPU handle its own perf counters, so it won't be
> idle and the issue would be inherently solved.
> 
> To address the above issues, update arch_freq_scale directly in ticks for
> non-PCC regs and keep the deferred update mechanism for PCC regs.
> 
> We have tested this on Kunpeng SoCs with the CPC regs both in System Memory
> and FFH.  More tests on other platforms are welcome (typically with the
> regs in PCC).
> 
> Changelog:
> v4:
> - Allow either non-PCC or PCC scale_freq_tick callbacks to be registered
>   for each cpufreq policy.
> - Factor out cppc_perf_ctrs_in_pcc_cpu() and cppc_fie_kworker_init() for
>   the above change.
> 
> v3:
> https://lore.kernel.org/linux-pm/20251104065039.1675549-1-zhanjie9 at hisilicon.com/
> - Stash the state of 'cppc_perf_ctrs_in_pcc' so it won't have to check the
>   CPC regs of all CPUs everywhere (Thanks to the suggestion from Beata
>   Michalska).
> - Update the commit log, explaining more on the warning issue caused by
>   accessing perf counters on remote CPUs.
> - Drop Patch 1 that has been accepted, and rebase Patch 2 on that.
> 
> v2:
> https://lore.kernel.org/linux-pm/20250828110212.2108653-1-zhanjie9 at hisilicon.com/
> - Update the cover letter and the commit log based on v1 discussion
> - Update FIE arch_freq_scale in ticks for non-PCC regs
> 
> v1:
> https://lore.kernel.org/linux-pm/20250730032312.167062-1-yubowen8 at huawei.com/
> 
> Jie Zhan (3):
>   ACPI: CPPC: Factor out and export per-cpu cppc_perf_ctrs_in_pcc_cpu()
>   cpufreq: CPPC: Factor out cppc_fie_kworker_init()
>   cpufreq: CPPC: Update FIE arch_freq_scale in ticks for non-PCC regs
> 
>  drivers/acpi/cppc_acpi.c       | 45 ++++++++--------
>  drivers/cpufreq/cppc_cpufreq.c | 96 ++++++++++++++++++++++------------
>  include/acpi/cppc_acpi.h       |  5 ++
>  3 files changed, 93 insertions(+), 53 deletions(-)
> 



From yuji.ishikawa.x51 at mail.toshiba  Tue Dec  2 23:50:24 2025
From: yuji.ishikawa.x51 at mail.toshiba (yuji.ishikawa.x51 at mail.toshiba)
Date: Wed, 3 Dec 2025 07:50:24 +0000
Subject: [PATCH v3 2/2] clk: visconti: Add VIIF clocks
In-Reply-To: <176369381444.11952.3963774406317821182@localhost.localdomain>
References: <20251114070512.855008-1-yuji2.ishikawa@toshiba.co.jp>
 <20251114070512.855008-3-yuji2.ishikawa@toshiba.co.jp>
 <176369381444.11952.3963774406317821182@localhost.localdomain>
Message-ID: <TYYPR01MB1225694BE61A6CB7A74B44EF5C3D9A@TYYPR01MB12256.jpnprd01.prod.outlook.com>

> -----Original Message-----
> From: Stephen Boyd <sboyd at kernel.org>
> Sent: Friday, November 21, 2025 11:57 AM
> To: Conor Dooley <conor+dt at kernel.org>; Krzysztof Kozlowski
> <krzk+dt at kernel.org>; Michael Turquette <mturquette at baylibre.com>;
> iwamatsu nobuhiro(?? ?? ?????????)
> <nobuhiro.iwamatsu.x90 at mail.toshiba>; Philipp Zabel
> <p.zabel at pengutronix.de>; Rob Herring <robh at kernel.org>; ishikawa yuji(?
> ? ?? ?????????) <yuji2.ishikawa at toshiba.co.jp>
> Cc: linux-clk at vger.kernel.org; linux-arm-kernel at lists.infradead.org;
> linux-kernel at vger.kernel.org; devicetree at vger.kernel.org; ishikawa yuji(??
> ?? ?????????) <yuji2.ishikawa at toshiba.co.jp>
> Subject: Re: [PATCH v3 2/2] clk: visconti: Add VIIF clocks
> 
> Quoting Yuji Ishikawa (2025-11-13 23:05:12)
> > Add the control sequence of register bits to handle the clocks and the
> > resets of Video Input Interface.
> >
> > Signed-off-by: Yuji Ishikawa <yuji2.ishikawa at toshiba.co.jp>
> > ---
> 
> Applied to clk-next but see below.
> 
> > diff --git a/drivers/clk/visconti/clkc-tmpv770x.c
> > b/drivers/clk/visconti/clkc-tmpv770x.c
> > index 94a736da6..1e2e8d643 100644
> > --- a/drivers/clk/visconti/clkc-tmpv770x.c
> > +++ b/drivers/clk/visconti/clkc-tmpv770x.c
> > @@ -18,8 +18,8 @@
> >  #include "reset.h"
> >
> >  /* Must be equal to the last clock/reset ID increased by one */
> > -#define CLKS_NR        (TMPV770X_CLK_BUSLCK + 1)
> > -#define RESETS_NR      (TMPV770X_RESET_SBUSCLK + 1)
> > +#define CLKS_NR        (TMPV770X_CLK_VIIFBS1_PROC + 1)
> > +#define RESETS_NR      (TMPV770X_RESET_VIIFBS1_L1ISP + 1)
> >
> >  static DEFINE_SPINLOCK(tmpv770x_clk_lock);
> >  static DEFINE_SPINLOCK(tmpv770x_rst_lock);
> > @@ -32,6 +32,10 @@ static const struct clk_parent_data
> pietherplls_parent_data[] = {
> >         { .fw_name = "pietherpll", .name = "pietherpll", },  };
> >
> > +static const struct clk_parent_data pidnnplls_parent_data[] = {
> > +       { .fw_name = "pidnnpll", .name = "pidnnpll", }, };
> 
> This is wrong. There's no "pidnnpll" in the DT binding for
> toshiba,tmpv770x-pismu 'clocks' property. Please send a follow up patch that
> cleans up the usage of clk_parent_data in this driver.

Thank you for pointing this out. I'll check the driver and consider how to clean up the usage.

Regards,
Yuji Ishikawa

From daniel at thingy.jp  Wed Dec  3 00:10:12 2025
From: daniel at thingy.jp (Daniel Palmer)
Date: Wed, 3 Dec 2025 17:10:12 +0900
Subject: [PATCH v5 07/14] gpio: msc313: Use modern PM macros
In-Reply-To: <20251124002105.25429-8-jszhang@kernel.org>
References: <20251124002105.25429-1-jszhang@kernel.org> <20251124002105.25429-8-jszhang@kernel.org>
Message-ID: <CAFr9PX=zXuaOBoEUGkYjrROK75e_xt6XZQu=mt0zQQNYWn_TYA@mail.gmail.com>

Hi Jisheng,

Sorry I missed this. This looks fine to me.

On Mon, 24 Nov 2025 at 09:39, Jisheng Zhang <jszhang at kernel.org> wrote:
>
> Use the modern PM macros for the suspend and resume functions to be
> automatically dropped by the compiler when CONFIG_PM or
> CONFIG_PM_SLEEP are disabled, without having to use __maybe_unused

Reviewed-by: Daniel Palmer <daniel at thingy.jp>


From kevin.brodsky at arm.com  Wed Dec  3 00:19:56 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Wed, 3 Dec 2025 09:19:56 +0100
Subject: [PATCH v5 05/12] mm: introduce CONFIG_ARCH_HAS_LAZY_MMU_MODE
In-Reply-To: <8d9ed1f1-77da-45af-85b5-78a5da66f1cc@arm.com>
References: <20251124132228.622678-1-kevin.brodsky@arm.com>
 <20251124132228.622678-6-kevin.brodsky@arm.com>
 <8d9ed1f1-77da-45af-85b5-78a5da66f1cc@arm.com>
Message-ID: <eb6fac72-a813-4b01-bbd7-f3961894bf53@arm.com>

On 01/12/2025 07:21, Anshuman Khandual wrote:
>> +config ARCH_HAS_LAZY_MMU_MODE
>> +	bool
>> +
> Might be worth adding a help description for the new config option.

Sure, would be an occasion to clarify which functions an arch needs to
define.

- Kevin


From kevin.brodsky at arm.com  Wed Dec  3 00:20:34 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Wed, 3 Dec 2025 09:20:34 +0100
Subject: [PATCH v5 06/12] mm: introduce generic lazy_mmu helpers
In-Reply-To: <07ffb66d-1e74-4634-bccb-75575b3862af-agordeev@linux.ibm.com>
References: <20251124132228.622678-1-kevin.brodsky@arm.com>
 <20251124132228.622678-7-kevin.brodsky@arm.com>
 <07ffb66d-1e74-4634-bccb-75575b3862af-agordeev@linux.ibm.com>
Message-ID: <51339cdd-3c73-433c-abf7-24553e0fbd6b@arm.com>

On 28/11/2025 14:50, Alexander Gordeev wrote:
> Would it make sense to explicitly describe the policy wrt sleeping while
> in lazy MMU mode? If I understand the conclusion of conversation right:
>
> * An arch implementation may disable preemption, but then it is arch
>   responsibility not to call any arch-specific code that might sleep;
> * As result, while in lazy MMU mode the generic code should never
>   call a code that might sleep;

I think that's a good summary, and I agree that the second point is not
obvious from the comment in <linux/pgtable.h>. This series it not making
any change in that respect, but I'll add a clarification in this patch
(or a separate patch).

- Kevin


From kevin.brodsky at arm.com  Wed Dec  3 00:20:57 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Wed, 3 Dec 2025 09:20:57 +0100
Subject: [PATCH v5 08/12] mm: enable lazy_mmu sections to nest
In-Reply-To: <23dcf752-0b75-45a7-84f8-25bddf97af08-agordeev@linux.ibm.com>
References: <20251124132228.622678-1-kevin.brodsky@arm.com>
 <20251124132228.622678-9-kevin.brodsky@arm.com>
 <23dcf752-0b75-45a7-84f8-25bddf97af08-agordeev@linux.ibm.com>
Message-ID: <703cbee6-a813-4970-9232-34ee91ed8961@arm.com>

On 28/11/2025 14:55, Alexander Gordeev wrote:
>> + * in_lazy_mmu_mode() can be used to check whether the lazy MMU mode is
>> + * currently enabled.
> The in_lazy_mmu_mode() name looks ambiguous to me. When the lazy MMU mode
> is paused are we still in lazy MMU mode? The __task_lazy_mmu_mode_active()
> implementation suggests we are not, while one could still assume we are,
> just paused.
>
> Should in_lazy_mmu_mode() be named e.g. as in_active_lazy_mmu_mode() such
> a confusion would not occur in the first place.

I see your point, how about is_lazy_mmu_mode_active()?

- Kevin


From jolsa at kernel.org  Wed Dec  3 00:23:53 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Wed,  3 Dec 2025 09:23:53 +0100
Subject: [PATCHv4 bpf-next 0/9] ftrace,bpf: Use single direct ops for bpf trampolines
Message-ID: <20251203082402.78816-1-jolsa@kernel.org>

hi,
while poking the multi-tracing interface I ended up with just one ftrace_ops
object to attach all trampolines.

This change allows to use less direct API calls during the attachment changes
in the future code, so in effect speeding up the attachment.

In current code we get a speed up from using just a single ftrace_ops object.

- with current code:

  Performance counter stats for 'bpftrace -e fentry:vmlinux:ksys_* {} -c true':

     6,364,157,902      cycles:k
       828,728,902      cycles:u
     1,064,803,824      instructions:u                   #    1.28  insn per cycle
    23,797,500,067      instructions:k                   #    3.74  insn per cycle

       4.416004987 seconds time elapsed

       0.164121000 seconds user
       1.289550000 seconds sys


- with the fix:

   Performance counter stats for 'bpftrace -e fentry:vmlinux:ksys_* {} -c true':

     6,535,857,905      cycles:k
       810,809,429      cycles:u
     1,064,594,027      instructions:u                   #    1.31  insn per cycle
    23,962,552,894      instructions:k                   #    3.67  insn per cycle

       1.666961239 seconds time elapsed

       0.157412000 seconds user
       1.283396000 seconds sys



The speedup seems to be related to the fact that with single ftrace_ops object
we don't call ftrace_shutdown anymore (we use ftrace_update_ops instead) and
we skip the synchronize rcu calls (each ~100ms) at the end of that function.

rfc: https://lore.kernel.org/bpf/20250729102813.1531457-1-jolsa at kernel.org/
v1:  https://lore.kernel.org/bpf/20250923215147.1571952-1-jolsa at kernel.org/
v2:  https://lore.kernel.org/bpf/20251113123750.2507435-1-jolsa at kernel.org/
v3:  https://lore.kernel.org/bpf/20251120212402.466524-1-jolsa at kernel.org/

v4 changes:
- rebased on top of bpf-next/master (with jmp attach changes)
  added patch 1 to deal with that
- added extra checks for update_ftrace_direct_del/mod to address
  the ci bot review

v3 changes:
- rebased on top of bpf-next/master
- fixed update_ftrace_direct_del cleanup path
- added missing inline to update_ftrace_direct_* stubs

v2 changes:
- rebased on top fo bpf-next/master plus Song's livepatch fixes [1] 
- renamed the API functions [2] [Steven]
- do not export the new api [Steven]
- kept the original direct interface:

  I'm not sure if we want to melt both *_ftrace_direct and the new interface
  into single one. It's bit different in semantic (hence the name change as
  Steven suggested [2]) and I don't think the changes are not that big so
  we could easily keep both APIs.

v1 changes:
- make the change x86 specific, after discussing with Mark options for
  arm64 [Mark]

thanks,
jirka


[1] https://lore.kernel.org/bpf/20251027175023.1521602-1-song at kernel.org/
[2] https://lore.kernel.org/bpf/20250924050415.4aefcb91 at batman.local.home/
---
Jiri Olsa (9):
      ftrace,bpf: Remove FTRACE_OPS_FL_JMP ftrace_ops flag
      ftrace: Make alloc_and_copy_ftrace_hash direct friendly
      ftrace: Export some of hash related functions
      ftrace: Add update_ftrace_direct_add function
      ftrace: Add update_ftrace_direct_del function
      ftrace: Add update_ftrace_direct_mod function
      bpf: Add trampoline ip hash table
      ftrace: Factor ftrace_ops ops_func interface
      bpf,x86: Use single ftrace_ops for direct calls

 arch/x86/Kconfig        |   1 +
 include/linux/bpf.h     |   7 ++-
 include/linux/ftrace.h  |  38 +++++++++++++-
 kernel/bpf/trampoline.c | 234 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
 kernel/trace/Kconfig    |   3 ++
 kernel/trace/ftrace.c   | 358 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
 kernel/trace/trace.h    |   8 ---
 7 files changed, 568 insertions(+), 81 deletions(-)


From jolsa at kernel.org  Wed Dec  3 00:23:54 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Wed,  3 Dec 2025 09:23:54 +0100
Subject: [PATCHv4 bpf-next 1/9] ftrace,bpf: Remove FTRACE_OPS_FL_JMP ftrace_ops flag
In-Reply-To: <20251203082402.78816-1-jolsa@kernel.org>
References: <20251203082402.78816-1-jolsa@kernel.org>
Message-ID: <20251203082402.78816-2-jolsa@kernel.org>

At the moment the we allow the jmp attach only for ftrace_ops that
has FTRACE_OPS_FL_JMP set. This conflicts with following changes
where we use single ftrace_ops object for all direct call sites,
so all could be be attached via just call or jmp.

We already limit the jmp attach support with config option and bit
(LSB) set on the trampoline address. It turns out that's actually
enough to limit the jmp attach for architecture and only for chosen
addresses (with LSB bit set).

Each user of register_ftrace_direct or modify_ftrace_direct can set
the trampoline bit (LSB) to indicate it has to be attached by jmp.

The bpf trampoline generation code uses trampoline flags to generate
jmp-attach specific code and ftrace inner code uses the trampoline
bit (LSB) to handle return from jmp attachment, so there's no harm
to remove the FTRACE_OPS_FL_JMP bit.

The fexit/fmodret performance stays the same (did not drop),
current code:

  fentry         :   77.904 ? 0.546M/s
  fexit          :   62.430 ? 0.554M/s
  fmodret        :   66.503 ? 0.902M/s

with this change:

  fentry         :   80.472 ? 0.061M/s
  fexit          :   63.995 ? 0.127M/s
  fmodret        :   67.362 ? 0.175M/s

Fixes: 25e4e3565d45 ("ftrace: Introduce FTRACE_OPS_FL_JMP")
Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 include/linux/ftrace.h  |  1 -
 kernel/bpf/trampoline.c | 32 ++++++++++++++------------------
 kernel/trace/ftrace.c   | 14 --------------
 3 files changed, 14 insertions(+), 33 deletions(-)

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 015dd1049bea..505b7d3f5641 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -359,7 +359,6 @@ enum {
 	FTRACE_OPS_FL_DIRECT			= BIT(17),
 	FTRACE_OPS_FL_SUBOP			= BIT(18),
 	FTRACE_OPS_FL_GRAPH			= BIT(19),
-	FTRACE_OPS_FL_JMP			= BIT(20),
 };
 
 #ifndef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index 976d89011b15..b9a358d7a78f 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -214,10 +214,15 @@ static int modify_fentry(struct bpf_trampoline *tr, u32 orig_flags,
 	int ret;
 
 	if (tr->func.ftrace_managed) {
+		unsigned long addr = (unsigned long) new_addr;
+
+		if (bpf_trampoline_use_jmp(tr->flags))
+			addr = ftrace_jmp_set(addr);
+
 		if (lock_direct_mutex)
-			ret = modify_ftrace_direct(tr->fops, (long)new_addr);
+			ret = modify_ftrace_direct(tr->fops, addr);
 		else
-			ret = modify_ftrace_direct_nolock(tr->fops, (long)new_addr);
+			ret = modify_ftrace_direct_nolock(tr->fops, addr);
 	} else {
 		ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr,
 						   new_addr);
@@ -240,10 +245,15 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
 	}
 
 	if (tr->func.ftrace_managed) {
+		unsigned long addr = (unsigned long) new_addr;
+
+		if (bpf_trampoline_use_jmp(tr->flags))
+			addr = ftrace_jmp_set(addr);
+
 		ret = ftrace_set_filter_ip(tr->fops, (unsigned long)ip, 0, 1);
 		if (ret)
 			return ret;
-		ret = register_ftrace_direct(tr->fops, (long)new_addr);
+		ret = register_ftrace_direct(tr->fops, addr);
 	} else {
 		ret = bpf_trampoline_update_fentry(tr, 0, NULL, new_addr);
 	}
@@ -499,13 +509,6 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut
 	if (err)
 		goto out_free;
 
-#ifdef CONFIG_DYNAMIC_FTRACE_WITH_JMP
-	if (bpf_trampoline_use_jmp(tr->flags))
-		tr->fops->flags |= FTRACE_OPS_FL_JMP;
-	else
-		tr->fops->flags &= ~FTRACE_OPS_FL_JMP;
-#endif
-
 	WARN_ON(tr->cur_image && total == 0);
 	if (tr->cur_image)
 		/* progs already running at this address */
@@ -533,15 +536,8 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut
 	tr->cur_image = im;
 out:
 	/* If any error happens, restore previous flags */
-	if (err) {
+	if (err)
 		tr->flags = orig_flags;
-#ifdef CONFIG_DYNAMIC_FTRACE_WITH_JMP
-		if (bpf_trampoline_use_jmp(tr->flags))
-			tr->fops->flags |= FTRACE_OPS_FL_JMP;
-		else
-			tr->fops->flags &= ~FTRACE_OPS_FL_JMP;
-#endif
-	}
 	kfree(tlinks);
 	return err;
 
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index bbb37c0f8c6c..b0dc911411f1 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -6017,15 +6017,8 @@ int register_ftrace_direct(struct ftrace_ops *ops, unsigned long addr)
 	if (ftrace_hash_empty(hash))
 		return -EINVAL;
 
-	/* This is a "raw" address, and this should never happen. */
-	if (WARN_ON_ONCE(ftrace_is_jmp(addr)))
-		return -EINVAL;
-
 	mutex_lock(&direct_mutex);
 
-	if (ops->flags & FTRACE_OPS_FL_JMP)
-		addr = ftrace_jmp_set(addr);
-
 	/* Make sure requested entries are not already registered.. */
 	size = 1 << hash->size_bits;
 	for (i = 0; i < size; i++) {
@@ -6146,13 +6139,6 @@ __modify_ftrace_direct(struct ftrace_ops *ops, unsigned long addr)
 
 	lockdep_assert_held_once(&direct_mutex);
 
-	/* This is a "raw" address, and this should never happen. */
-	if (WARN_ON_ONCE(ftrace_is_jmp(addr)))
-		return -EINVAL;
-
-	if (ops->flags & FTRACE_OPS_FL_JMP)
-		addr = ftrace_jmp_set(addr);
-
 	/* Enable the tmp_ops to have the same functions as the direct ops */
 	ftrace_ops_init(&tmp_ops);
 	tmp_ops.func_hash = ops->func_hash;
-- 
2.52.0



From jolsa at kernel.org  Wed Dec  3 00:23:55 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Wed,  3 Dec 2025 09:23:55 +0100
Subject: [PATCHv4 bpf-next 2/9] ftrace: Make alloc_and_copy_ftrace_hash direct friendly
In-Reply-To: <20251203082402.78816-1-jolsa@kernel.org>
References: <20251203082402.78816-1-jolsa@kernel.org>
Message-ID: <20251203082402.78816-3-jolsa@kernel.org>

Make alloc_and_copy_ftrace_hash to copy also direct address
for each hash entry.

Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 kernel/trace/ftrace.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index b0dc911411f1..7e3a81bd6f1e 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1186,7 +1186,7 @@ static void __add_hash_entry(struct ftrace_hash *hash,
 }
 
 static struct ftrace_func_entry *
-add_hash_entry(struct ftrace_hash *hash, unsigned long ip)
+add_hash_entry_direct(struct ftrace_hash *hash, unsigned long ip, unsigned long direct)
 {
 	struct ftrace_func_entry *entry;
 
@@ -1195,11 +1195,18 @@ add_hash_entry(struct ftrace_hash *hash, unsigned long ip)
 		return NULL;
 
 	entry->ip = ip;
+	entry->direct = direct;
 	__add_hash_entry(hash, entry);
 
 	return entry;
 }
 
+static struct ftrace_func_entry *
+add_hash_entry(struct ftrace_hash *hash, unsigned long ip)
+{
+	return add_hash_entry_direct(hash, ip, 0);
+}
+
 static void
 free_hash_entry(struct ftrace_hash *hash,
 		  struct ftrace_func_entry *entry)
@@ -1372,7 +1379,7 @@ alloc_and_copy_ftrace_hash(int size_bits, struct ftrace_hash *hash)
 	size = 1 << hash->size_bits;
 	for (i = 0; i < size; i++) {
 		hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
-			if (add_hash_entry(new_hash, entry->ip) == NULL)
+			if (add_hash_entry_direct(new_hash, entry->ip, entry->direct) == NULL)
 				goto free_hash;
 		}
 	}
-- 
2.52.0



From jolsa at kernel.org  Wed Dec  3 00:23:56 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Wed,  3 Dec 2025 09:23:56 +0100
Subject: [PATCHv4 bpf-next 3/9] ftrace: Export some of hash related functions
In-Reply-To: <20251203082402.78816-1-jolsa@kernel.org>
References: <20251203082402.78816-1-jolsa@kernel.org>
Message-ID: <20251203082402.78816-4-jolsa@kernel.org>

We are going to use these functions in following changes.

Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 include/linux/ftrace.h | 16 ++++++++++++++++
 kernel/trace/ftrace.c  |  7 +++----
 kernel/trace/trace.h   |  8 --------
 3 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 505b7d3f5641..8c034b028af4 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -405,6 +405,22 @@ enum ftrace_ops_cmd {
 typedef int (*ftrace_ops_func_t)(struct ftrace_ops *op, enum ftrace_ops_cmd cmd);
 
 #ifdef CONFIG_DYNAMIC_FTRACE
+
+#define FTRACE_HASH_DEFAULT_BITS 10
+
+struct ftrace_hash {
+	unsigned long		size_bits;
+	struct hlist_head	*buckets;
+	unsigned long		count;
+	unsigned long		flags;
+	struct rcu_head		rcu;
+};
+
+struct ftrace_hash *alloc_ftrace_hash(int size_bits);
+void free_ftrace_hash(struct ftrace_hash *hash);
+struct ftrace_func_entry *add_hash_entry_direct(struct ftrace_hash *hash,
+						unsigned long ip, unsigned long direct);
+
 /* The hash used to know what functions callbacks trace */
 struct ftrace_ops_hash {
 	struct ftrace_hash __rcu	*notrace_hash;
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 7e3a81bd6f1e..84aee9096a9e 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -68,7 +68,6 @@
 	})
 
 /* hash bits for specific function selection */
-#define FTRACE_HASH_DEFAULT_BITS 10
 #define FTRACE_HASH_MAX_BITS 12
 
 #ifdef CONFIG_DYNAMIC_FTRACE
@@ -1185,7 +1184,7 @@ static void __add_hash_entry(struct ftrace_hash *hash,
 	hash->count++;
 }
 
-static struct ftrace_func_entry *
+struct ftrace_func_entry *
 add_hash_entry_direct(struct ftrace_hash *hash, unsigned long ip, unsigned long direct)
 {
 	struct ftrace_func_entry *entry;
@@ -1265,7 +1264,7 @@ static void clear_ftrace_mod_list(struct list_head *head)
 	mutex_unlock(&ftrace_lock);
 }
 
-static void free_ftrace_hash(struct ftrace_hash *hash)
+void free_ftrace_hash(struct ftrace_hash *hash)
 {
 	if (!hash || hash == EMPTY_HASH)
 		return;
@@ -1305,7 +1304,7 @@ void ftrace_free_filter(struct ftrace_ops *ops)
 }
 EXPORT_SYMBOL_GPL(ftrace_free_filter);
 
-static struct ftrace_hash *alloc_ftrace_hash(int size_bits)
+struct ftrace_hash *alloc_ftrace_hash(int size_bits)
 {
 	struct ftrace_hash *hash;
 	int size;
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 85eabb454bee..62e0ac625f65 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -899,14 +899,6 @@ enum {
 	FTRACE_HASH_FL_MOD	= (1 << 0),
 };
 
-struct ftrace_hash {
-	unsigned long		size_bits;
-	struct hlist_head	*buckets;
-	unsigned long		count;
-	unsigned long		flags;
-	struct rcu_head		rcu;
-};
-
 struct ftrace_func_entry *
 ftrace_lookup_ip(struct ftrace_hash *hash, unsigned long ip);
 
-- 
2.52.0



From jolsa at kernel.org  Wed Dec  3 00:23:57 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Wed,  3 Dec 2025 09:23:57 +0100
Subject: [PATCHv4 bpf-next 4/9] ftrace: Add update_ftrace_direct_add function
In-Reply-To: <20251203082402.78816-1-jolsa@kernel.org>
References: <20251203082402.78816-1-jolsa@kernel.org>
Message-ID: <20251203082402.78816-5-jolsa@kernel.org>

Adding update_ftrace_direct_add function that adds all entries
(ip -> addr) provided in hash argument to direct ftrace ops
and updates its attachments.

The difference to current register_ftrace_direct is
 - hash argument that allows to register multiple ip -> direct
   entries at once
 - we can call update_ftrace_direct_add multiple times on the
   same ftrace_ops object, becase after first registration with
   register_ftrace_function_nolock, it uses ftrace_update_ops to
   update the ftrace_ops object

This change will allow us to have simple ftrace_ops for all bpf
direct interface users in following changes.

Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 include/linux/ftrace.h |   7 +++
 kernel/trace/ftrace.c  | 128 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 135 insertions(+)

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 8c034b028af4..eb60d971ec1d 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -550,6 +550,8 @@ int unregister_ftrace_direct(struct ftrace_ops *ops, unsigned long addr,
 int modify_ftrace_direct(struct ftrace_ops *ops, unsigned long addr);
 int modify_ftrace_direct_nolock(struct ftrace_ops *ops, unsigned long addr);
 
+int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash);
+
 void ftrace_stub_direct_tramp(void);
 
 #else
@@ -576,6 +578,11 @@ static inline int modify_ftrace_direct_nolock(struct ftrace_ops *ops, unsigned l
 	return -ENODEV;
 }
 
+static inline int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash)
+{
+	return -ENODEV;
+}
+
 /*
  * This must be implemented by the architecture.
  * It is the way the ftrace direct_ops helper, when called
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 84aee9096a9e..1660a87547dd 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -6249,6 +6249,134 @@ int modify_ftrace_direct(struct ftrace_ops *ops, unsigned long addr)
 	return err;
 }
 EXPORT_SYMBOL_GPL(modify_ftrace_direct);
+
+static unsigned long hash_count(struct ftrace_hash *hash)
+{
+	return hash ? hash->count : 0;
+}
+
+/**
+ * hash_add - adds two struct ftrace_hash and returns the result
+ * @a: struct ftrace_hash object
+ * @b: struct ftrace_hash object
+ *
+ * Returns struct ftrace_hash object on success, NULL on error.
+ */
+static struct ftrace_hash *hash_add(struct ftrace_hash *a, struct ftrace_hash *b)
+{
+	struct ftrace_func_entry *entry;
+	struct ftrace_hash *add;
+	int size, i;
+
+	size = hash_count(a) + hash_count(b);
+	if (size > 32)
+		size = 32;
+
+	add = alloc_and_copy_ftrace_hash(fls(size), a);
+	if (!add)
+		goto error;
+
+	size = 1 << b->size_bits;
+	for (i = 0; i < size; i++) {
+		hlist_for_each_entry(entry, &b->buckets[i], hlist) {
+			if (add_hash_entry_direct(add, entry->ip, entry->direct) == NULL)
+				goto error;
+		}
+	}
+	return add;
+
+ error:
+	free_ftrace_hash(add);
+	return NULL;
+}
+
+int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash)
+{
+	struct ftrace_hash *old_direct_functions = NULL, *new_direct_functions = NULL;
+	struct ftrace_hash *old_filter_hash = NULL, *new_filter_hash = NULL;
+	struct ftrace_func_entry *entry;
+	int i, size, err = -EINVAL;
+	bool reg;
+
+	if (!hash_count(hash))
+		return -EINVAL;
+
+	mutex_lock(&direct_mutex);
+
+	/* Make sure requested entries are not already registered. */
+	size = 1 << hash->size_bits;
+	for (i = 0; i < size; i++) {
+		hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
+			if (__ftrace_lookup_ip(direct_functions, entry->ip))
+				goto out_unlock;
+		}
+	}
+
+	old_filter_hash = ops->func_hash ? ops->func_hash->filter_hash : NULL;
+	old_direct_functions = direct_functions;
+
+	/* If there's nothing in filter_hash we need to register the ops. */
+	reg = hash_count(old_filter_hash) == 0;
+	if (reg) {
+		if (ops->func || ops->trampoline)
+			goto out_unlock;
+		if (ops->flags & FTRACE_OPS_FL_ENABLED)
+			goto out_unlock;
+	}
+
+	err = -ENOMEM;
+	new_filter_hash = hash_add(old_filter_hash, hash);
+	if (!new_filter_hash)
+		goto out_unlock;
+
+	new_direct_functions = hash_add(old_direct_functions, hash);
+	if (!new_direct_functions)
+		goto out_unlock;
+
+	rcu_assign_pointer(direct_functions, new_direct_functions);
+
+	if (reg) {
+		ops->func = call_direct_funcs;
+		ops->flags |= MULTI_FLAGS;
+		ops->trampoline = FTRACE_REGS_ADDR;
+		ops->local_hash.filter_hash = new_filter_hash;
+
+		err = register_ftrace_function_nolock(ops);
+		if (err) {
+			/* restore old filter on error */
+			ops->local_hash.filter_hash = old_filter_hash;
+			old_filter_hash = new_filter_hash;
+
+			/* cleanup for possible another register call */
+			ops->func = NULL;
+			ops->trampoline = 0;
+		}
+	} else {
+		err = ftrace_update_ops(ops, new_filter_hash, EMPTY_HASH);
+		/*
+		 * new_filter_hash is dup-ed, so we need to release it anyway,
+		 * old_filter_hash either stays on error or is released already
+		 */
+		old_filter_hash = new_filter_hash;
+	}
+
+	if (err) {
+		/* reset direct_functions and free the new one */
+		rcu_assign_pointer(direct_functions, old_direct_functions);
+		old_direct_functions = new_direct_functions;
+	}
+
+ out_unlock:
+	mutex_unlock(&direct_mutex);
+
+	if (old_direct_functions && old_direct_functions != EMPTY_HASH)
+		call_rcu_tasks(&old_direct_functions->rcu, register_ftrace_direct_cb);
+	if (old_filter_hash)
+		free_ftrace_hash(old_filter_hash);
+
+	return err;
+}
+
 #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
 
 /**
-- 
2.52.0



From jolsa at kernel.org  Wed Dec  3 00:23:58 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Wed,  3 Dec 2025 09:23:58 +0100
Subject: [PATCHv4 bpf-next 5/9] ftrace: Add update_ftrace_direct_del function
In-Reply-To: <20251203082402.78816-1-jolsa@kernel.org>
References: <20251203082402.78816-1-jolsa@kernel.org>
Message-ID: <20251203082402.78816-6-jolsa@kernel.org>

Adding update_ftrace_direct_del function that removes all entries
(ip -> addr) provided in hash argument to direct ftrace ops and
updates its attachments.

The difference to current unregister_ftrace_direct is
 - hash argument that allows to unregister multiple ip -> direct
   entries at once
 - we can call update_ftrace_direct_del multiple times on the
   same ftrace_ops object, becase we do not need to unregister
   all entries at once, we can do it gradualy with the help of
   ftrace_update_ops function

This change will allow us to have simple ftrace_ops for all bpf
direct interface users in following changes.

Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 include/linux/ftrace.h |   6 +++
 kernel/trace/ftrace.c  | 113 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 119 insertions(+)

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index eb60d971ec1d..bac9dd784826 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -551,6 +551,7 @@ int modify_ftrace_direct(struct ftrace_ops *ops, unsigned long addr);
 int modify_ftrace_direct_nolock(struct ftrace_ops *ops, unsigned long addr);
 
 int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash);
+int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash);
 
 void ftrace_stub_direct_tramp(void);
 
@@ -583,6 +584,11 @@ static inline int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace
 	return -ENODEV;
 }
 
+static inline int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash)
+{
+	return -ENODEV;
+}
+
 /*
  * This must be implemented by the architecture.
  * It is the way the ftrace direct_ops helper, when called
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 1660a87547dd..01e830be20e3 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -6377,6 +6377,119 @@ int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash)
 	return err;
 }
 
+/**
+ * hash_sub - substracts @b from @a and returns the result
+ * @a: struct ftrace_hash object
+ * @b: struct ftrace_hash object
+ *
+ * Returns struct ftrace_hash object on success, NULL on error.
+ */
+static struct ftrace_hash *hash_sub(struct ftrace_hash *a, struct ftrace_hash *b)
+{
+	struct ftrace_func_entry *entry, *del;
+	struct ftrace_hash *sub;
+	int size, i;
+
+	sub = alloc_and_copy_ftrace_hash(a->size_bits, a);
+	if (!sub)
+		goto error;
+
+	size = 1 << b->size_bits;
+	for (i = 0; i < size; i++) {
+		hlist_for_each_entry(entry, &b->buckets[i], hlist) {
+			del = __ftrace_lookup_ip(sub, entry->ip);
+			if (WARN_ON_ONCE(!del))
+				goto error;
+			remove_hash_entry(sub, del);
+			kfree(del);
+		}
+	}
+	return sub;
+
+ error:
+	free_ftrace_hash(sub);
+	return NULL;
+}
+
+int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash)
+{
+	struct ftrace_hash *old_direct_functions = NULL, *new_direct_functions = NULL;
+	struct ftrace_hash *old_filter_hash = NULL, *new_filter_hash = NULL;
+	struct ftrace_func_entry *del, *entry;
+	unsigned long size, i;
+	int err = -EINVAL;
+
+	if (!hash_count(hash))
+		return -EINVAL;
+	if (check_direct_multi(ops))
+		return -EINVAL;
+	if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
+		return -EINVAL;
+	if (direct_functions == EMPTY_HASH)
+		return -EINVAL;
+
+	mutex_lock(&direct_mutex);
+
+	old_filter_hash = ops->func_hash ? ops->func_hash->filter_hash : NULL;
+	old_direct_functions = direct_functions;
+
+	if (!hash_count(old_filter_hash))
+		goto out_unlock;
+
+	/* Make sure requested entries are already registered. */
+	size = 1 << hash->size_bits;
+	for (i = 0; i < size; i++) {
+		hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
+			del = __ftrace_lookup_ip(direct_functions, entry->ip);
+			if (!del || del->direct != entry->direct)
+				goto out_unlock;
+		}
+	}
+
+	err = -ENOMEM;
+	new_filter_hash = hash_sub(old_filter_hash, hash);
+	if (!new_filter_hash)
+		goto out_unlock;
+
+	new_direct_functions = hash_sub(old_direct_functions, hash);
+	if (!new_direct_functions)
+		goto out_unlock;
+
+	/* If there's nothing left, we need to unregister the ops. */
+	if (ftrace_hash_empty(new_filter_hash)) {
+		err = unregister_ftrace_function(ops);
+		if (!err) {
+			/* cleanup for possible another register call */
+			ops->func = NULL;
+			ops->trampoline = 0;
+			ftrace_free_filter(ops);
+			ops->func_hash->filter_hash = NULL;
+		}
+	} else {
+		err = ftrace_update_ops(ops, new_filter_hash, EMPTY_HASH);
+		/*
+		 * new_filter_hash is dup-ed, so we need to release it anyway,
+		 * old_filter_hash either stays on error or is released already
+		 */
+	}
+
+	if (err) {
+		/* reset direct_functions and free the new one */
+		old_direct_functions = new_direct_functions;
+	} else {
+		rcu_assign_pointer(direct_functions, new_direct_functions);
+	}
+
+ out_unlock:
+	mutex_unlock(&direct_mutex);
+
+	if (old_direct_functions && old_direct_functions != EMPTY_HASH)
+		call_rcu_tasks(&old_direct_functions->rcu, register_ftrace_direct_cb);
+	free_ftrace_hash(new_filter_hash);
+
+	return err;
+}
+
 #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
 
 /**
-- 
2.52.0



From jolsa at kernel.org  Wed Dec  3 00:23:59 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Wed,  3 Dec 2025 09:23:59 +0100
Subject: [PATCHv4 bpf-next 6/9] ftrace: Add update_ftrace_direct_mod function
In-Reply-To: <20251203082402.78816-1-jolsa@kernel.org>
References: <20251203082402.78816-1-jolsa@kernel.org>
Message-ID: <20251203082402.78816-7-jolsa@kernel.org>

Adding update_ftrace_direct_mod function that modifies all entries
(ip -> direct) provided in hash argument to direct ftrace ops and
updates its attachments.

The difference to current modify_ftrace_direct is:
- hash argument that allows to modify multiple ip -> direct
  entries at once

This change will allow us to have simple ftrace_ops for all bpf
direct interface users in following changes.

Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 include/linux/ftrace.h |  6 ++++
 kernel/trace/ftrace.c  | 72 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 78 insertions(+)

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index bac9dd784826..c27b7381c5f1 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -552,6 +552,7 @@ int modify_ftrace_direct_nolock(struct ftrace_ops *ops, unsigned long addr);
 
 int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash);
 int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash);
+int update_ftrace_direct_mod(struct ftrace_ops *ops, struct ftrace_hash *hash, bool do_direct_lock);
 
 void ftrace_stub_direct_tramp(void);
 
@@ -589,6 +590,11 @@ static inline int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace
 	return -ENODEV;
 }
 
+static inline int update_ftrace_direct_mod(struct ftrace_ops *ops, struct ftrace_hash *hash, bool do_direct_lock)
+{
+	return -ENODEV;
+}
+
 /*
  * This must be implemented by the architecture.
  * It is the way the ftrace direct_ops helper, when called
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 01e830be20e3..c77f620b3eb3 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -6490,6 +6490,78 @@ int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash)
 	return err;
 }
 
+int update_ftrace_direct_mod(struct ftrace_ops *ops, struct ftrace_hash *hash, bool do_direct_lock)
+{
+	struct ftrace_func_entry *entry, *tmp;
+	static struct ftrace_ops tmp_ops = {
+		.func		= ftrace_stub,
+		.flags		= FTRACE_OPS_FL_STUB,
+	};
+	struct ftrace_hash *orig_hash;
+	unsigned long size, i;
+	int err = -EINVAL;
+
+	if (!hash_count(hash))
+		return -EINVAL;
+	if (check_direct_multi(ops))
+		return -EINVAL;
+	if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
+		return -EINVAL;
+	if (direct_functions == EMPTY_HASH)
+		return -EINVAL;
+
+	if (do_direct_lock)
+		mutex_lock(&direct_mutex);
+
+	orig_hash = ops->func_hash ? ops->func_hash->filter_hash : NULL;
+	if (!orig_hash)
+		goto unlock;
+
+	/* Enable the tmp_ops to have the same functions as the direct ops */
+	ftrace_ops_init(&tmp_ops);
+	tmp_ops.func_hash = ops->func_hash;
+
+	err = register_ftrace_function_nolock(&tmp_ops);
+	if (err)
+		goto unlock;
+
+	/*
+	 * Call __ftrace_hash_update_ipmodify() here, so that we can call
+	 * ops->ops_func for the ops. This is needed because the above
+	 * register_ftrace_function_nolock() worked on tmp_ops.
+	 */
+	err = __ftrace_hash_update_ipmodify(ops, orig_hash, orig_hash, true);
+	if (err)
+		goto out;
+
+	/*
+	 * Now the ftrace_ops_list_func() is called to do the direct callers.
+	 * We can safely change the direct functions attached to each entry.
+	 */
+	mutex_lock(&ftrace_lock);
+
+	size = 1 << hash->size_bits;
+	for (i = 0; i < size; i++) {
+		hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
+			tmp = __ftrace_lookup_ip(direct_functions, entry->ip);
+			if (!tmp)
+				continue;
+			tmp->direct = entry->direct;
+		}
+	}
+
+	mutex_unlock(&ftrace_lock);
+
+out:
+	/* Removing the tmp_ops will add the updated direct callers to the functions */
+	unregister_ftrace_function(&tmp_ops);
+
+unlock:
+	if (do_direct_lock)
+		mutex_unlock(&direct_mutex);
+	return err;
+}
+
 #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
 
 /**
-- 
2.52.0



From jolsa at kernel.org  Wed Dec  3 00:24:00 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Wed,  3 Dec 2025 09:24:00 +0100
Subject: [PATCHv4 bpf-next 7/9] bpf: Add trampoline ip hash table
In-Reply-To: <20251203082402.78816-1-jolsa@kernel.org>
References: <20251203082402.78816-1-jolsa@kernel.org>
Message-ID: <20251203082402.78816-8-jolsa@kernel.org>

Following changes need to lookup trampoline based on its ip address,
adding hash table for that.

Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 include/linux/bpf.h     |  7 +++++--
 kernel/bpf/trampoline.c | 30 +++++++++++++++++++-----------
 2 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 6498be4c44f8..ef44653eae44 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -1307,14 +1307,17 @@ struct bpf_tramp_image {
 };
 
 struct bpf_trampoline {
-	/* hlist for trampoline_table */
-	struct hlist_node hlist;
+	/* hlist for trampoline_key_table */
+	struct hlist_node hlist_key;
+	/* hlist for trampoline_ip_table */
+	struct hlist_node hlist_ip;
 	struct ftrace_ops *fops;
 	/* serializes access to fields of this trampoline */
 	struct mutex mutex;
 	refcount_t refcnt;
 	u32 flags;
 	u64 key;
+	unsigned long ip;
 	struct {
 		struct btf_func_model model;
 		void *addr;
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index b9a358d7a78f..f298bafab76e 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -24,9 +24,10 @@ const struct bpf_prog_ops bpf_extension_prog_ops = {
 #define TRAMPOLINE_HASH_BITS 10
 #define TRAMPOLINE_TABLE_SIZE (1 << TRAMPOLINE_HASH_BITS)
 
-static struct hlist_head trampoline_table[TRAMPOLINE_TABLE_SIZE];
+static struct hlist_head trampoline_key_table[TRAMPOLINE_TABLE_SIZE];
+static struct hlist_head trampoline_ip_table[TRAMPOLINE_TABLE_SIZE];
 
-/* serializes access to trampoline_table */
+/* serializes access to trampoline tables */
 static DEFINE_MUTEX(trampoline_mutex);
 
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
@@ -135,15 +136,15 @@ void bpf_image_ksym_del(struct bpf_ksym *ksym)
 			   PAGE_SIZE, true, ksym->name);
 }
 
-static struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
+static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
 {
 	struct bpf_trampoline *tr;
 	struct hlist_head *head;
 	int i;
 
 	mutex_lock(&trampoline_mutex);
-	head = &trampoline_table[hash_64(key, TRAMPOLINE_HASH_BITS)];
-	hlist_for_each_entry(tr, head, hlist) {
+	head = &trampoline_key_table[hash_64(key, TRAMPOLINE_HASH_BITS)];
+	hlist_for_each_entry(tr, head, hlist_key) {
 		if (tr->key == key) {
 			refcount_inc(&tr->refcnt);
 			goto out;
@@ -164,8 +165,12 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
 #endif
 
 	tr->key = key;
-	INIT_HLIST_NODE(&tr->hlist);
-	hlist_add_head(&tr->hlist, head);
+	tr->ip = ftrace_location(ip);
+	INIT_HLIST_NODE(&tr->hlist_key);
+	INIT_HLIST_NODE(&tr->hlist_ip);
+	hlist_add_head(&tr->hlist_key, head);
+	head = &trampoline_ip_table[hash_64(tr->ip, TRAMPOLINE_HASH_BITS)];
+	hlist_add_head(&tr->hlist_ip, head);
 	refcount_set(&tr->refcnt, 1);
 	mutex_init(&tr->mutex);
 	for (i = 0; i < BPF_TRAMP_MAX; i++)
@@ -846,7 +851,7 @@ void bpf_trampoline_unlink_cgroup_shim(struct bpf_prog *prog)
 					 prog->aux->attach_btf_id);
 
 	bpf_lsm_find_cgroup_shim(prog, &bpf_func);
-	tr = bpf_trampoline_lookup(key);
+	tr = bpf_trampoline_lookup(key, 0);
 	if (WARN_ON_ONCE(!tr))
 		return;
 
@@ -866,7 +871,7 @@ struct bpf_trampoline *bpf_trampoline_get(u64 key,
 {
 	struct bpf_trampoline *tr;
 
-	tr = bpf_trampoline_lookup(key);
+	tr = bpf_trampoline_lookup(key, tgt_info->tgt_addr);
 	if (!tr)
 		return NULL;
 
@@ -902,7 +907,8 @@ void bpf_trampoline_put(struct bpf_trampoline *tr)
 	 * fexit progs. The fentry-only trampoline will be freed via
 	 * multiple rcu callbacks.
 	 */
-	hlist_del(&tr->hlist);
+	hlist_del(&tr->hlist_key);
+	hlist_del(&tr->hlist_ip);
 	if (tr->fops) {
 		ftrace_free_filter(tr->fops);
 		kfree(tr->fops);
@@ -1175,7 +1181,9 @@ static int __init init_trampolines(void)
 	int i;
 
 	for (i = 0; i < TRAMPOLINE_TABLE_SIZE; i++)
-		INIT_HLIST_HEAD(&trampoline_table[i]);
+		INIT_HLIST_HEAD(&trampoline_key_table[i]);
+	for (i = 0; i < TRAMPOLINE_TABLE_SIZE; i++)
+		INIT_HLIST_HEAD(&trampoline_ip_table[i]);
 	return 0;
 }
 late_initcall(init_trampolines);
-- 
2.52.0



From jolsa at kernel.org  Wed Dec  3 00:24:01 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Wed,  3 Dec 2025 09:24:01 +0100
Subject: [PATCHv4 bpf-next 8/9] ftrace: Factor ftrace_ops ops_func interface
In-Reply-To: <20251203082402.78816-1-jolsa@kernel.org>
References: <20251203082402.78816-1-jolsa@kernel.org>
Message-ID: <20251203082402.78816-9-jolsa@kernel.org>

We are going to remove "ftrace_ops->private == bpf_trampoline" setup
in following changes.

Adding ip argument to ftrace_ops_func_t callback function, so we can
use it to look up the trampoline.

Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 include/linux/ftrace.h  | 2 +-
 kernel/bpf/trampoline.c | 3 ++-
 kernel/trace/ftrace.c   | 6 +++---
 3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index c27b7381c5f1..515cf5b723dd 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -402,7 +402,7 @@ enum ftrace_ops_cmd {
  *        Negative on failure. The return value is dependent on the
  *        callback.
  */
-typedef int (*ftrace_ops_func_t)(struct ftrace_ops *op, enum ftrace_ops_cmd cmd);
+typedef int (*ftrace_ops_func_t)(struct ftrace_ops *op, unsigned long ip, enum ftrace_ops_cmd cmd);
 
 #ifdef CONFIG_DYNAMIC_FTRACE
 
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index f298bafab76e..17af2aad8382 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -33,7 +33,8 @@ static DEFINE_MUTEX(trampoline_mutex);
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
 static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mutex);
 
-static int bpf_tramp_ftrace_ops_func(struct ftrace_ops *ops, enum ftrace_ops_cmd cmd)
+static int bpf_tramp_ftrace_ops_func(struct ftrace_ops *ops, unsigned long ip,
+				     enum ftrace_ops_cmd cmd)
 {
 	struct bpf_trampoline *tr = ops->private;
 	int ret = 0;
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index c77f620b3eb3..9582cb374d4f 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -2049,7 +2049,7 @@ static int __ftrace_hash_update_ipmodify(struct ftrace_ops *ops,
 				 */
 				if (!ops->ops_func)
 					return -EBUSY;
-				ret = ops->ops_func(ops, FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_SELF);
+				ret = ops->ops_func(ops, rec->ip, FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_SELF);
 				if (ret)
 					return ret;
 			} else if (is_ipmodify) {
@@ -8984,7 +8984,7 @@ static int prepare_direct_functions_for_ipmodify(struct ftrace_ops *ops)
 				if (!op->ops_func)
 					return -EBUSY;
 
-				ret = op->ops_func(op, FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_PEER);
+				ret = op->ops_func(op, ip, FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_PEER);
 				if (ret)
 					return ret;
 			}
@@ -9031,7 +9031,7 @@ static void cleanup_direct_functions_after_ipmodify(struct ftrace_ops *ops)
 
 			/* The cleanup is optional, ignore any errors */
 			if (found_op && op->ops_func)
-				op->ops_func(op, FTRACE_OPS_CMD_DISABLE_SHARE_IPMODIFY_PEER);
+				op->ops_func(op, ip, FTRACE_OPS_CMD_DISABLE_SHARE_IPMODIFY_PEER);
 		}
 	}
 	mutex_unlock(&direct_mutex);
-- 
2.52.0



From jolsa at kernel.org  Wed Dec  3 00:24:02 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Wed,  3 Dec 2025 09:24:02 +0100
Subject: [PATCHv4 bpf-next 9/9] bpf,x86: Use single ftrace_ops for direct calls
In-Reply-To: <20251203082402.78816-1-jolsa@kernel.org>
References: <20251203082402.78816-1-jolsa@kernel.org>
Message-ID: <20251203082402.78816-10-jolsa@kernel.org>

Using single ftrace_ops for direct calls update instead of allocating
ftrace_ops object for each trampoline.

With single ftrace_ops object we can use update_ftrace_direct_* api
that allows multiple ip sites updates on single ftrace_ops object.

Adding HAVE_SINGLE_FTRACE_DIRECT_OPS config option to be enabled on
each arch that supports this.

At the moment we can enable this only on x86 arch, because arm relies
on ftrace_ops object representing just single trampoline image (stored
in ftrace_ops::direct_call). Ach that do not support this will continue
to use *_ftrace_direct api.

Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 arch/x86/Kconfig        |   1 +
 kernel/bpf/trampoline.c | 195 ++++++++++++++++++++++++++++++++++------
 kernel/trace/Kconfig    |   3 +
 kernel/trace/ftrace.c   |   7 +-
 4 files changed, 177 insertions(+), 29 deletions(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 462250a20311..737dff48342b 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -333,6 +333,7 @@ config X86
 	select SCHED_SMT			if SMP
 	select ARCH_SUPPORTS_SCHED_CLUSTER	if SMP
 	select ARCH_SUPPORTS_SCHED_MC		if SMP
+	select HAVE_SINGLE_FTRACE_DIRECT_OPS	if X86_64 && DYNAMIC_FTRACE_WITH_DIRECT_CALLS
 
 config INSTRUCTION_DECODER
 	def_bool y
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index 17af2aad8382..02371db3db3e 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -33,12 +33,40 @@ static DEFINE_MUTEX(trampoline_mutex);
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
 static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mutex);
 
+#ifdef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS
+static struct bpf_trampoline *direct_ops_ip_lookup(struct ftrace_ops *ops, unsigned long ip)
+{
+	struct hlist_head *head_ip;
+	struct bpf_trampoline *tr;
+
+	mutex_lock(&trampoline_mutex);
+	head_ip = &trampoline_ip_table[hash_64(ip, TRAMPOLINE_HASH_BITS)];
+	hlist_for_each_entry(tr, head_ip, hlist_ip) {
+		if (tr->ip == ip)
+			goto out;
+	}
+	tr = NULL;
+out:
+	mutex_unlock(&trampoline_mutex);
+	return tr;
+}
+#else
+static struct bpf_trampoline *direct_ops_ip_lookup(struct ftrace_ops *ops, unsigned long ip)
+{
+	return ops->private;
+}
+#endif /* CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS */
+
 static int bpf_tramp_ftrace_ops_func(struct ftrace_ops *ops, unsigned long ip,
 				     enum ftrace_ops_cmd cmd)
 {
-	struct bpf_trampoline *tr = ops->private;
+	struct bpf_trampoline *tr;
 	int ret = 0;
 
+	tr = direct_ops_ip_lookup(ops, ip);
+	if (!tr)
+		return -EINVAL;
+
 	if (cmd == FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_SELF) {
 		/* This is called inside register_ftrace_direct_multi(), so
 		 * tr->mutex is already locked.
@@ -137,6 +165,139 @@ void bpf_image_ksym_del(struct bpf_ksym *ksym)
 			   PAGE_SIZE, true, ksym->name);
 }
 
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
+#ifdef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS
+/*
+ * We have only single direct_ops which contains all the direct call
+ * sites and is the only global ftrace_ops for all trampolines.
+ *
+ * We use 'update_ftrace_direct_*' api for attachment.
+ */
+struct ftrace_ops direct_ops = {
+	.ops_func = bpf_tramp_ftrace_ops_func,
+};
+
+static int direct_ops_alloc(struct bpf_trampoline *tr)
+{
+	tr->fops = &direct_ops;
+	return 0;
+}
+
+static void direct_ops_free(struct bpf_trampoline *tr) { }
+
+static struct ftrace_hash *hash_from_ip(struct bpf_trampoline *tr, void *ptr)
+{
+	unsigned long ip, addr = (unsigned long) ptr;
+	struct ftrace_hash *hash;
+
+	ip = ftrace_location(tr->ip);
+	if (!ip)
+		return NULL;
+	hash = alloc_ftrace_hash(FTRACE_HASH_DEFAULT_BITS);
+	if (!hash)
+		return NULL;
+	if (bpf_trampoline_use_jmp(tr->flags))
+		addr = ftrace_jmp_set(addr);
+	if (!add_hash_entry_direct(hash, ip, addr)) {
+		free_ftrace_hash(hash);
+		return NULL;
+	}
+	return hash;
+}
+
+static int direct_ops_add(struct bpf_trampoline *tr, void *addr)
+{
+	struct ftrace_hash *hash = hash_from_ip(tr, addr);
+	int err = -ENOMEM;
+
+	if (hash)
+		err = update_ftrace_direct_add(tr->fops, hash);
+	free_ftrace_hash(hash);
+	return err;
+}
+
+static int direct_ops_del(struct bpf_trampoline *tr, void *addr)
+{
+	struct ftrace_hash *hash = hash_from_ip(tr, addr);
+	int err = -ENOMEM;
+
+	if (hash)
+		err = update_ftrace_direct_del(tr->fops, hash);
+	free_ftrace_hash(hash);
+	return err;
+}
+
+static int direct_ops_mod(struct bpf_trampoline *tr, void *addr, bool lock_direct_mutex)
+{
+	struct ftrace_hash *hash = hash_from_ip(tr, addr);
+	int err = -ENOMEM;
+
+	if (hash)
+		err = update_ftrace_direct_mod(tr->fops, hash, lock_direct_mutex);
+	free_ftrace_hash(hash);
+	return err;
+}
+#else
+/*
+ * We allocate ftrace_ops object for each trampoline and it contains
+ * call site specific for that trampoline.
+ *
+ * We use *_ftrace_direct api for attachment.
+ */
+static int direct_ops_alloc(struct bpf_trampoline *tr)
+{
+	tr->fops = kzalloc(sizeof(struct ftrace_ops), GFP_KERNEL);
+	if (!tr->fops)
+		return -ENOMEM;
+	tr->fops->private = tr;
+	tr->fops->ops_func = bpf_tramp_ftrace_ops_func;
+	return 0;
+}
+
+static void direct_ops_free(struct bpf_trampoline *tr)
+{
+	if (tr->fops) {
+		ftrace_free_filter(tr->fops);
+		kfree(tr->fops);
+	}
+}
+
+static int direct_ops_add(struct bpf_trampoline *tr, void *ptr)
+{
+	unsigned long addr = (unsigned long) ptr;
+	struct ftrace_ops *ops = tr->fops;
+	int ret;
+
+	if (bpf_trampoline_use_jmp(tr->flags))
+		addr = ftrace_jmp_set(addr);
+
+	ret = ftrace_set_filter_ip(ops, tr->ip, 0, 1);
+	if (ret)
+		return ret;
+	return register_ftrace_direct(ops, addr);
+}
+
+static int direct_ops_del(struct bpf_trampoline *tr, void *addr)
+{
+	return unregister_ftrace_direct(tr->fops, (long)addr, false);
+}
+
+static int direct_ops_mod(struct bpf_trampoline *tr, void *ptr, bool lock_direct_mutex)
+{
+	unsigned long addr = (unsigned long) ptr;
+	struct ftrace_ops *ops = tr->fops;
+
+	if (bpf_trampoline_use_jmp(tr->flags))
+		addr = ftrace_jmp_set(addr);
+	if (lock_direct_mutex)
+		return modify_ftrace_direct(ops, addr);
+	return modify_ftrace_direct_nolock(ops, addr);
+}
+#endif /* CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS */
+#else
+static void direct_ops_free(struct bpf_trampoline *tr) { }
+#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
+
 static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
 {
 	struct bpf_trampoline *tr;
@@ -155,14 +316,11 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
 	if (!tr)
 		goto out;
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
-	tr->fops = kzalloc(sizeof(struct ftrace_ops), GFP_KERNEL);
-	if (!tr->fops) {
+	if (direct_ops_alloc(tr)) {
 		kfree(tr);
 		tr = NULL;
 		goto out;
 	}
-	tr->fops->private = tr;
-	tr->fops->ops_func = bpf_tramp_ftrace_ops_func;
 #endif
 
 	tr->key = key;
@@ -206,7 +364,7 @@ static int unregister_fentry(struct bpf_trampoline *tr, u32 orig_flags,
 	int ret;
 
 	if (tr->func.ftrace_managed)
-		ret = unregister_ftrace_direct(tr->fops, (long)old_addr, false);
+		ret = direct_ops_del(tr, old_addr);
 	else
 		ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr, NULL);
 
@@ -220,15 +378,7 @@ static int modify_fentry(struct bpf_trampoline *tr, u32 orig_flags,
 	int ret;
 
 	if (tr->func.ftrace_managed) {
-		unsigned long addr = (unsigned long) new_addr;
-
-		if (bpf_trampoline_use_jmp(tr->flags))
-			addr = ftrace_jmp_set(addr);
-
-		if (lock_direct_mutex)
-			ret = modify_ftrace_direct(tr->fops, addr);
-		else
-			ret = modify_ftrace_direct_nolock(tr->fops, addr);
+		ret = direct_ops_mod(tr, new_addr, lock_direct_mutex);
 	} else {
 		ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr,
 						   new_addr);
@@ -251,15 +401,7 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
 	}
 
 	if (tr->func.ftrace_managed) {
-		unsigned long addr = (unsigned long) new_addr;
-
-		if (bpf_trampoline_use_jmp(tr->flags))
-			addr = ftrace_jmp_set(addr);
-
-		ret = ftrace_set_filter_ip(tr->fops, (unsigned long)ip, 0, 1);
-		if (ret)
-			return ret;
-		ret = register_ftrace_direct(tr->fops, addr);
+		ret = direct_ops_add(tr, new_addr);
 	} else {
 		ret = bpf_trampoline_update_fentry(tr, 0, NULL, new_addr);
 	}
@@ -910,10 +1052,7 @@ void bpf_trampoline_put(struct bpf_trampoline *tr)
 	 */
 	hlist_del(&tr->hlist_key);
 	hlist_del(&tr->hlist_ip);
-	if (tr->fops) {
-		ftrace_free_filter(tr->fops);
-		kfree(tr->fops);
-	}
+	direct_ops_free(tr);
 	kfree(tr);
 out:
 	mutex_unlock(&trampoline_mutex);
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index 4661b9e606e0..1ad2e307c834 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -50,6 +50,9 @@ config HAVE_DYNAMIC_FTRACE_WITH_REGS
 config HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
 	bool
 
+config HAVE_SINGLE_FTRACE_DIRECT_OPS
+	bool
+
 config HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS
 	bool
 
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 9582cb374d4f..0bdee1758fa1 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -2605,8 +2605,13 @@ unsigned long ftrace_find_rec_direct(unsigned long ip)
 static void call_direct_funcs(unsigned long ip, unsigned long pip,
 			      struct ftrace_ops *ops, struct ftrace_regs *fregs)
 {
-	unsigned long addr = READ_ONCE(ops->direct_call);
+	unsigned long addr;
 
+#ifdef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS
+	addr = ftrace_find_rec_direct(ip);
+#else
+	addr = READ_ONCE(ops->direct_call);
+#endif
 	if (!addr)
 		return;
 
-- 
2.52.0



From krzk at kernel.org  Wed Dec  3 00:30:47 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 3 Dec 2025 09:30:47 +0100
Subject: [PATCH 05/21] ARM: dts: omap: Bind panel to panel-dpi instead of
 ti,tilcdc,panel driver
In-Reply-To: <20251202135605.053ada96@kmaincent-XPS-13-7390>
References: <20251126-feature_tilcdc-v1-5-49b9ef2e3aa0@bootlin.com>
 <96b1b7bf-ddbe-4213-a201-dc89cf2998dd@ideasonboard.com>
 <3bc5bf92-05c3-4841-ab28-9bab2bb31cd5@kernel.org>
 <20251202104244.59a9e83d@kmaincent-XPS-13-7390>
 <d7515cd3-5488-4d15-82dc-d2b98cfa2bed@kernel.org>
 <20251202114416.09624a4b@kmaincent-XPS-13-7390>
 <94e254fa-289d-41ed-909f-1742cfbb2690@kernel.org>
 <20251202121856.0da62885@kmaincent-XPS-13-7390>
 <1d9a9269-bfda-4d43-938b-2df6b82b9369@ideasonboard.com>
 <20251202135605.053ada96@kmaincent-XPS-13-7390>
Message-ID: <20251203-aromatic-heavy-loon-0cbd14@quoll>

On Tue, Dec 02, 2025 at 01:56:05PM +0100, Kory Maincent wrote:
> On Tue, 2 Dec 2025 13:51:59 +0200
> Tomi Valkeinen <tomi.valkeinen at ideasonboard.com> wrote:
> 
> > Hi Kory,
> > 
> > On 02/12/2025 13:18, Kory Maincent wrote:
> > > On Tue, 2 Dec 2025 11:47:40 +0100
> > > Krzysztof Kozlowski <krzk at kernel.org> wrote:
> 
> > I will not NAK, removing bindings and breaking users is under some
> > conditions acceptable. You just need to come with the reasons and impact.
> > 
> > Reason "is ugly" is usually not good enough. Especially if things were
> > working.
> 
> Thanks for you reply.
> 
> > >>
> > >> DTS cannot go to drm, which means you either need to separate the change
> > >> and make entire work bisectable and backwards compatible for some time
> > >> OR at least document clearly the impact as we always ask.  
> > > 
> > > The thing is, if I split it, it has to be in 3. One for the of DRM bus flags
> > > support, a second for the the devicetree and binding change and a third for
> > > the whole tilcdc and tda998x cleaning stuff. I think I will go for one
> > > series, with better documentation.
> > > 
> > > Now, what is your point of view on my question. Will you nak any binding
> > > removal even if the binding is ugly and legacy and imply maintaining an
> > > non-standard tilcdc panel driver? I know it breaks DTB compatibility but
> > > there is several argument to not keep it. See patch 6.  
> > The binding being ugly and having to maintain non-standard tilcdc panel
> > driver may be nice things for us, the users don't care. The users care
> > if their board no longer works.
> 
> Yes I understand but then I have another question. At what cost should we
> continue to support legacy binding?

That's mostly question to platform maintainers and users. Extrapolating
kernel rule - we never break the user-space - we never break the users,
thus we take significant cost.

And that significant cost can be the cost of making the transition
smooth or smoother.

> 
> Just figured out this case already happened, ti,tilcdc,slave binding was
> removed from the tilcdc driver:
> 739acd85ffdb7 ("drm/tilcdc: Remove obsolete "ti,tilcdc,slave" dts binding
> support")
> 
> Even if there is still one mainline device tree that uses it:
> am335x-base0033.dts. :/

If that commit broke existing users, it is a good argument for your
changes, but you need to explicitly use that argument in commit msg.

> 
> > And how does this sync with u-boot? It also has code for at least for a
> > few of these boards.
> 
> U-boot has indeed a driver for the ti,tilcdc,panel binding.
> Changing this devicetree would beak display for these board in U-boot as it
> currently does not support the "panel-dpi" binding.

Thanks for checking, regardless of decision this also should be in
commit msg.

Maybe things were not working correctly for long time, so there is a
choice of fixing Linux side while breaking U-boot and not fixing, but
keeping bootloader working.


Best regards,
Krzysztof



From lkp at intel.com  Wed Dec  3 00:35:36 2025
From: lkp at intel.com (kernel test robot)
Date: Wed, 3 Dec 2025 16:35:36 +0800
Subject: [PATCH V3 1/3] iommu/arm-smmu-v3: Add device-tree support for
 CMDQV driver
In-Reply-To: <20251201163219.3237266-2-amhetre@nvidia.com>
References: <20251201163219.3237266-2-amhetre@nvidia.com>
Message-ID: <202512031601.IpliwbHW-lkp@intel.com>

Hi Ashish,

kernel test robot noticed the following build errors:

[auto build test ERROR on next-20251201]
[also build test ERROR on v6.18]
[cannot apply to robh/for-next linus/master v6.18 v6.18-rc7 v6.18-rc6]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Ashish-Mhetre/iommu-arm-smmu-v3-Add-device-tree-support-for-CMDQV-driver/20251202-003517
base:   next-20251201
patch link:    https://lore.kernel.org/r/20251201163219.3237266-2-amhetre%40nvidia.com
patch subject: [PATCH V3 1/3] iommu/arm-smmu-v3: Add device-tree support for CMDQV driver
config: arm64-allmodconfig (https://download.01.org/0day-ci/archive/20251203/202512031601.IpliwbHW-lkp at intel.com/config)
compiler: clang version 19.1.7 (https://github.com/llvm/llvm-project cd708029e0b2869e80abe31ddb175f7c35361f90)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251203/202512031601.IpliwbHW-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512031601.IpliwbHW-lkp at intel.com/

All errors (new ones prefixed by >>):

>> ld.lld: error: duplicate symbol: init_module
   >>> defined at arm-smmu-v3.c
   >>>            drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.o:(init_module)
   >>> defined at tegra241-cmdqv.c
   >>>            drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.o:(.init.text+0x4)
--
>> ld.lld: error: duplicate symbol: cleanup_module
   >>> defined at arm-smmu-v3.c
   >>>            drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.o:(cleanup_module)
   >>> defined at tegra241-cmdqv.c
   >>>            drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.o:(.exit.text+0x4)

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From parvathi at couthit.com  Wed Dec  3 00:37:59 2025
From: parvathi at couthit.com (Parvathi Pudi)
Date: Wed, 3 Dec 2025 14:07:59 +0530 (IST)
Subject: [PATCH net-next v8 2/3] net: ti: icssm-prueth: Add switchdev
 support for icssm_prueth driver
In-Reply-To: <20251201141638.00a986dd@kernel.org>
References: <20251126163056.2697668-1-parvathi@couthit.com> <20251126163056.2697668-3-parvathi@couthit.com> <20251201141638.00a986dd@kernel.org>
Message-ID: <483862293.84606.1764751079970.JavaMail.zimbra@couthit.local>

Hi,

> On Wed, 26 Nov 2025 21:57:13 +0530 Parvathi Pudi wrote:
>> + */
>> +static void icssm_prueth_sw_switchdev_event_work(struct work_struct *work)
>> +{
>> +	struct icssm_prueth_sw_switchdev_event_work *switchdev_work =
>> +		container_of(work,
>> +			     struct icssm_prueth_sw_switchdev_event_work, work);
> 
> Consider using shorter type names.
> 

We will address this in the next version.

>> +	struct prueth_emac *emac = switchdev_work->emac;
>> +	struct switchdev_notifier_fdb_info *fdb;
>> +	struct prueth *prueth = emac->prueth;
>> +	int port = emac->port_id;
>> +
>> +	rtnl_lock();
>> +
>> +	/* Interface is not up */
>> +	if (!emac->prueth->fdb_tbl) {
>> +		rtnl_unlock();
> 
> Are you not leaking the device reference here?
> 

We will address this in the next version.

Thanks and Regards,
Parvathi.


From parvathi at couthit.com  Wed Dec  3 00:40:41 2025
From: parvathi at couthit.com (Parvathi Pudi)
Date: Wed, 3 Dec 2025 14:10:41 +0530 (IST)
Subject: [PATCH net-next v8 1/3] net: ti: icssm-prueth: Add helper
 functions to configure and maintain FDB
In-Reply-To: <20251201141858.399fff62@kernel.org>
References: <20251126163056.2697668-1-parvathi@couthit.com> <20251126163056.2697668-2-parvathi@couthit.com> <20251201141858.399fff62@kernel.org>
Message-ID: <1648322401.84640.1764751241037.JavaMail.zimbra@couthit.local>

Hi,

> On Wed, 26 Nov 2025 21:57:12 +0530 Parvathi Pudi wrote:
>> +	u8 hash_val, mac_tbl_idx;
> 
> Using narrow types is generally quite counter productive.
> It can easily mask out-of-range accesses and subtle errors,
> given that max is outside of the range of the u8 type:
> 
> +#define FDB_INDEX_TBL_MAX_ENTRIES     256
> +#define FDB_MAC_TBL_MAX_ENTRIES       256
> 
> You should consider changing all the local variables to unsigned int.

OK, we will update the code to use unsigned int for relevant local
variables to avoid any silent errors.

Thanks and Regards,
Parvathi.


From bot+bpf-ci at kernel.org  Wed Dec  3 00:47:45 2025
From: bot+bpf-ci at kernel.org (bot+bpf-ci at kernel.org)
Date: Wed,  3 Dec 2025 08:47:45 +0000 (UTC)
Subject: [PATCHv4 bpf-next 4/9] ftrace: Add update_ftrace_direct_add function
In-Reply-To: <20251203082402.78816-5-jolsa@kernel.org>
References: <20251203082402.78816-5-jolsa@kernel.org>
Message-ID: <d0d8e0d78f614eb8b443772b50fb36093d48c7f43374316246ad3ad836b5c9ce@mail.kernel.org>

> diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
> index 8c034b028..eb60d971e 100644
> --- a/include/linux/ftrace.h
> +++ b/include/linux/ftrace.h

[ ... ]

> diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
> index 84aee9096..1660a8754 100644
> --- a/kernel/trace/ftrace.c
> +++ b/kernel/trace/ftrace.c

[ ... ]

> +int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash)
> +{
> +	struct ftrace_hash *old_direct_functions = NULL, *new_direct_functions = NULL;
> +	struct ftrace_hash *old_filter_hash = NULL, *new_filter_hash = NULL;
> +	struct ftrace_func_entry *entry;
> +	int i, size, err = -EINVAL;
> +	bool reg;
> +
> +	if (!hash_count(hash))
> +		return -EINVAL;
> +
> +	mutex_lock(&direct_mutex);
> +
> +	/* Make sure requested entries are not already registered. */
> +	size = 1 << hash->size_bits;
> +	for (i = 0; i < size; i++) {
> +		hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
> +			if (__ftrace_lookup_ip(direct_functions, entry->ip))
> +				goto out_unlock;
> +		}
> +	}
> +
> +	old_filter_hash = ops->func_hash ? ops->func_hash->filter_hash : NULL;
> +	old_direct_functions = direct_functions;
> +
> +	/* If there's nothing in filter_hash we need to register the ops. */
> +	reg = hash_count(old_filter_hash) == 0;
> +	if (reg) {
> +		if (ops->func || ops->trampoline)
> +			goto out_unlock;
> +		if (ops->flags & FTRACE_OPS_FL_ENABLED)
> +			goto out_unlock;
> +	}
> +
> +	err = -ENOMEM;
> +	new_filter_hash = hash_add(old_filter_hash, hash);
> +	if (!new_filter_hash)
> +		goto out_unlock;
> +
> +	new_direct_functions = hash_add(old_direct_functions, hash);
> +	if (!new_direct_functions)
> +		goto out_unlock;

Can new_filter_hash leak here?  If the second hash_add() fails but the
first one succeeds, update_ftrace_direct_add() will goto out_unlock
with new_filter_hash pointing to allocated memory.  At out_unlock, only
old_filter_hash gets freed, not new_filter_hash.

register_ftrace_direct() handles this by freeing new_hash on error:

    out_unlock:
        mutex_unlock(&direct_mutex);

        if (free_hash && free_hash != EMPTY_HASH)
            call_rcu_tasks(&free_hash->rcu, register_ftrace_direct_cb);

        if (new_hash)
            free_ftrace_hash(new_hash);

        return err;

> +
> +	rcu_assign_pointer(direct_functions, new_direct_functions);
> +
> +	if (reg) {
> +		ops->func = call_direct_funcs;
> +		ops->flags |= MULTI_FLAGS;
> +		ops->trampoline = FTRACE_REGS_ADDR;
> +		ops->local_hash.filter_hash = new_filter_hash;
> +
> +		err = register_ftrace_function_nolock(ops);
> +		if (err) {
> +			/* restore old filter on error */
> +			ops->local_hash.filter_hash = old_filter_hash;
> +			old_filter_hash = new_filter_hash;
> +
> +			/* cleanup for possible another register call */
> +			ops->func = NULL;
> +			ops->trampoline = 0;
> +		}
> +	} else {
> +		err = ftrace_update_ops(ops, new_filter_hash, EMPTY_HASH);
> +		/*
> +		 * new_filter_hash is dup-ed, so we need to release it anyway,
> +		 * old_filter_hash either stays on error or is released already
> +		 */
> +		old_filter_hash = new_filter_hash;
> +	}
> +
> +	if (err) {
> +		/* reset direct_functions and free the new one */
> +		rcu_assign_pointer(direct_functions, old_direct_functions);
> +		old_direct_functions = new_direct_functions;
> +	}
> +
> + out_unlock:
> +	mutex_unlock(&direct_mutex);
> +
> +	if (old_direct_functions && old_direct_functions != EMPTY_HASH)
> +		call_rcu_tasks(&old_direct_functions->rcu, register_ftrace_direct_cb);
> +	if (old_filter_hash)
> +		free_ftrace_hash(old_filter_hash);
> +
> +	return err;
> +}


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/19887401362

From carlos.song at nxp.com  Wed Dec  3 00:59:43 2025
From: carlos.song at nxp.com (Carlos Song)
Date: Wed,  3 Dec 2025 16:59:43 +0800
Subject: [PATCH v3 0/6] Support ECSPI dynamic burst feature for DMA mode
Message-ID: <20251203085949.2922166-1-carlos.song@nxp.com>

ECSPI has a low throughput because of no dynamic burst support, it
transfers only one word per frame in DMA mode, causing SCLK stalls
between words due to BURST_LENGTH updates.

This patch set is to support ECSPI dynamic burst feature to help improve
the ECSPI DMA mode performance.

Performance test (spidev_test @10MHz, 4KB):
  Before: tx/rx ~6651.9 kbps
  After:  tx/rx ~9922.2 kbps (~50% improvement)

For compatibility with slow SPI devices, add configurable word delay in
DMA mode. When word delay is set, dynamic burst is disabled and
BURST_LENGTH equals word length.

Also support target DMA mode with enabled dynamic burst.

---
Changes since v2:
* Patch1~4: no change
* Patch5: remove __counted_by from *dma_data, because spi_imx struct
  is allocated with a fixed memory in probe, flexible array is not
  suitable, so just remove it to avoid the build error. Also add
  review-by tag
* Patch6: add review-by tag
Changes since v1:
* Patch1~3:
* Add review-by tag
* Patch4:
  * Add review-by tag
  * Improve patch commit log
* Patch5:
  * Clean up tab instead of space for dma_tx_addr and dma_rx_addr
  * Add  __counted_by(dma_package_num) for dma_data_package *dma_data
  * Move temp and bytes_per_word to if()
  * Add comment for spi_imx_dma_rx_data_handle() and
    spi_imx_dma_tx_data_handle()
  * Use kzalloc instead of kmalloc(x, x | __GFP_ZERO)
  * Use sizeof(*temp) instead of BYTES_PER_32BITS_WORD in suitable place
  * Add comments and fix comments according to discussion
  * Propagate the error value of dma_mapping_error()
  * Use round_down() to replace DIV_ROUND_DOWN_ULL()
  * Improve transfer->error |= SPI_TRANS_FAIL_NO_START judgment for
    better readability
* Patch6:
  * Improve patch commit log
  * Add READ_ONCE for spi_imx->target_aborted
  * Add comments for data length limit
  * Move data length limit to spi_imx_can_dma()

Carlos Song (6):
  spi: imx: group spi_imx_dma_configure() with spi_imx_dma_transfer()
  spi: imx: introduce helper to clear DMA mode logic
  spi: imx: avoid dmaengine_terminate_all() on TX prep failure
  spi: imx: handle DMA submission errors with dma_submit_error()
  spi: imx: support dynamic burst length for ECSPI DMA mode
  spi: imx: enable DMA mode for target operation

 drivers/spi/spi-imx.c | 625 +++++++++++++++++++++++++++++++++++-------
 1 file changed, 519 insertions(+), 106 deletions(-)

-- 
2.34.1



From carlos.song at nxp.com  Wed Dec  3 00:59:44 2025
From: carlos.song at nxp.com (Carlos Song)
Date: Wed,  3 Dec 2025 16:59:44 +0800
Subject: [PATCH v3 1/6] spi: imx: group spi_imx_dma_configure() with spi_imx_dma_transfer()
In-Reply-To: <20251203085949.2922166-1-carlos.song@nxp.com>
References: <20251203085949.2922166-1-carlos.song@nxp.com>
Message-ID: <20251203085949.2922166-2-carlos.song@nxp.com>

Relocate spi_imx_dma_configure() next to spi_imx_dma_transfer() so that
all DMA-related functions are grouped together for better readability.
No functional changes.

Signed-off-by: Carlos Song <carlos.song at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/spi/spi-imx.c | 88 +++++++++++++++++++++----------------------
 1 file changed, 44 insertions(+), 44 deletions(-)

diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index b8b79bb7fec3..e78e02a84b50 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -1282,50 +1282,6 @@ static irqreturn_t spi_imx_isr(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-static int spi_imx_dma_configure(struct spi_controller *controller)
-{
-	int ret;
-	enum dma_slave_buswidth buswidth;
-	struct dma_slave_config rx = {}, tx = {};
-	struct spi_imx_data *spi_imx = spi_controller_get_devdata(controller);
-
-	switch (spi_imx_bytes_per_word(spi_imx->bits_per_word)) {
-	case 4:
-		buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
-		break;
-	case 2:
-		buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
-		break;
-	case 1:
-		buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	tx.direction = DMA_MEM_TO_DEV;
-	tx.dst_addr = spi_imx->base_phys + MXC_CSPITXDATA;
-	tx.dst_addr_width = buswidth;
-	tx.dst_maxburst = spi_imx->wml;
-	ret = dmaengine_slave_config(controller->dma_tx, &tx);
-	if (ret) {
-		dev_err(spi_imx->dev, "TX dma configuration failed with %d\n", ret);
-		return ret;
-	}
-
-	rx.direction = DMA_DEV_TO_MEM;
-	rx.src_addr = spi_imx->base_phys + MXC_CSPIRXDATA;
-	rx.src_addr_width = buswidth;
-	rx.src_maxburst = spi_imx->wml;
-	ret = dmaengine_slave_config(controller->dma_rx, &rx);
-	if (ret) {
-		dev_err(spi_imx->dev, "RX dma configuration failed with %d\n", ret);
-		return ret;
-	}
-
-	return 0;
-}
-
 static int spi_imx_setupxfer(struct spi_device *spi,
 				 struct spi_transfer *t)
 {
@@ -1481,6 +1437,50 @@ static int spi_imx_calculate_timeout(struct spi_imx_data *spi_imx, int size)
 	return secs_to_jiffies(2 * timeout);
 }
 
+static int spi_imx_dma_configure(struct spi_controller *controller)
+{
+	int ret;
+	enum dma_slave_buswidth buswidth;
+	struct dma_slave_config rx = {}, tx = {};
+	struct spi_imx_data *spi_imx = spi_controller_get_devdata(controller);
+
+	switch (spi_imx_bytes_per_word(spi_imx->bits_per_word)) {
+	case 4:
+		buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		break;
+	case 2:
+		buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
+		break;
+	case 1:
+		buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	tx.direction = DMA_MEM_TO_DEV;
+	tx.dst_addr = spi_imx->base_phys + MXC_CSPITXDATA;
+	tx.dst_addr_width = buswidth;
+	tx.dst_maxburst = spi_imx->wml;
+	ret = dmaengine_slave_config(controller->dma_tx, &tx);
+	if (ret) {
+		dev_err(spi_imx->dev, "TX dma configuration failed with %d\n", ret);
+		return ret;
+	}
+
+	rx.direction = DMA_DEV_TO_MEM;
+	rx.src_addr = spi_imx->base_phys + MXC_CSPIRXDATA;
+	rx.src_addr_width = buswidth;
+	rx.src_maxburst = spi_imx->wml;
+	ret = dmaengine_slave_config(controller->dma_rx, &rx);
+	if (ret) {
+		dev_err(spi_imx->dev, "RX dma configuration failed with %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
 static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
 				struct spi_transfer *transfer)
 {
-- 
2.34.1



From carlos.song at nxp.com  Wed Dec  3 00:59:45 2025
From: carlos.song at nxp.com (Carlos Song)
Date: Wed,  3 Dec 2025 16:59:45 +0800
Subject: [PATCH v3 2/6] spi: imx: introduce helper to clear DMA mode logic
In-Reply-To: <20251203085949.2922166-1-carlos.song@nxp.com>
References: <20251203085949.2922166-1-carlos.song@nxp.com>
Message-ID: <20251203085949.2922166-3-carlos.song@nxp.com>

Add a helper function to handle clearing DMA mode, including getting the
maximum watermark length and submitting the DMA request. This refactoring
makes the code more concise and improves readability.
No functional changes.

Signed-off-by: Carlos Song <carlos.song at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/spi/spi-imx.c | 164 +++++++++++++++++++++++-------------------
 1 file changed, 92 insertions(+), 72 deletions(-)

diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index e78e02a84b50..012f5bcbf73f 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -1437,6 +1437,94 @@ static int spi_imx_calculate_timeout(struct spi_imx_data *spi_imx, int size)
 	return secs_to_jiffies(2 * timeout);
 }
 
+static int spi_imx_dma_submit(struct spi_imx_data *spi_imx,
+			      struct spi_transfer *transfer)
+{
+	struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg;
+	struct spi_controller *controller = spi_imx->controller;
+	struct dma_async_tx_descriptor *desc_tx, *desc_rx;
+	unsigned long transfer_timeout;
+	unsigned long time_left;
+
+	/*
+	 * The TX DMA setup starts the transfer, so make sure RX is configured
+	 * before TX.
+	 */
+	desc_rx = dmaengine_prep_slave_sg(controller->dma_rx,
+					  rx->sgl, rx->nents, DMA_DEV_TO_MEM,
+					  DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	if (!desc_rx) {
+		transfer->error |= SPI_TRANS_FAIL_NO_START;
+		return -EINVAL;
+	}
+
+	desc_rx->callback = spi_imx_dma_rx_callback;
+	desc_rx->callback_param = (void *)spi_imx;
+	dmaengine_submit(desc_rx);
+	reinit_completion(&spi_imx->dma_rx_completion);
+	dma_async_issue_pending(controller->dma_rx);
+
+	desc_tx = dmaengine_prep_slave_sg(controller->dma_tx,
+					  tx->sgl, tx->nents, DMA_MEM_TO_DEV,
+					  DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	if (!desc_tx) {
+		dmaengine_terminate_all(controller->dma_tx);
+		dmaengine_terminate_all(controller->dma_rx);
+		return -EINVAL;
+	}
+
+	desc_tx->callback = spi_imx_dma_tx_callback;
+	desc_tx->callback_param = (void *)spi_imx;
+	dmaengine_submit(desc_tx);
+	reinit_completion(&spi_imx->dma_tx_completion);
+	dma_async_issue_pending(controller->dma_tx);
+
+	spi_imx->devtype_data->trigger(spi_imx);
+
+	transfer_timeout = spi_imx_calculate_timeout(spi_imx, transfer->len);
+
+	/* Wait SDMA to finish the data transfer.*/
+	time_left = wait_for_completion_timeout(&spi_imx->dma_tx_completion,
+						transfer_timeout);
+	if (!time_left) {
+		dev_err(spi_imx->dev, "I/O Error in DMA TX\n");
+		dmaengine_terminate_all(controller->dma_tx);
+		dmaengine_terminate_all(controller->dma_rx);
+		return -ETIMEDOUT;
+	}
+
+	time_left = wait_for_completion_timeout(&spi_imx->dma_rx_completion,
+						transfer_timeout);
+	if (!time_left) {
+		dev_err(&controller->dev, "I/O Error in DMA RX\n");
+		spi_imx->devtype_data->reset(spi_imx);
+		dmaengine_terminate_all(controller->dma_rx);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static void spi_imx_dma_max_wml_find(struct spi_imx_data *spi_imx,
+				     struct spi_transfer *transfer)
+{
+	struct sg_table *rx = &transfer->rx_sg;
+	struct scatterlist *last_sg = sg_last(rx->sgl, rx->nents);
+	unsigned int bytes_per_word, i;
+
+	/* Get the right burst length from the last sg to ensure no tail data */
+	bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word);
+	for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) {
+		if (!(sg_dma_len(last_sg) % (i * bytes_per_word)))
+			break;
+	}
+	/* Use 1 as wml in case no available burst length got */
+	if (i == 0)
+		i = 1;
+
+	spi_imx->wml = i;
+}
+
 static int spi_imx_dma_configure(struct spi_controller *controller)
 {
 	int ret;
@@ -1484,26 +1572,10 @@ static int spi_imx_dma_configure(struct spi_controller *controller)
 static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
 				struct spi_transfer *transfer)
 {
-	struct dma_async_tx_descriptor *desc_tx, *desc_rx;
-	unsigned long transfer_timeout;
-	unsigned long time_left;
 	struct spi_controller *controller = spi_imx->controller;
-	struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg;
-	struct scatterlist *last_sg = sg_last(rx->sgl, rx->nents);
-	unsigned int bytes_per_word, i;
 	int ret;
 
-	/* Get the right burst length from the last sg to ensure no tail data */
-	bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word);
-	for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) {
-		if (!(sg_dma_len(last_sg) % (i * bytes_per_word)))
-			break;
-	}
-	/* Use 1 as wml in case no available burst length got */
-	if (i == 0)
-		i = 1;
-
-	spi_imx->wml =  i;
+	spi_imx_dma_max_wml_find(spi_imx, transfer);
 
 	ret = spi_imx_dma_configure(controller);
 	if (ret)
@@ -1516,61 +1588,9 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
 	}
 	spi_imx->devtype_data->setup_wml(spi_imx);
 
-	/*
-	 * The TX DMA setup starts the transfer, so make sure RX is configured
-	 * before TX.
-	 */
-	desc_rx = dmaengine_prep_slave_sg(controller->dma_rx,
-				rx->sgl, rx->nents, DMA_DEV_TO_MEM,
-				DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-	if (!desc_rx) {
-		ret = -EINVAL;
-		goto dma_failure_no_start;
-	}
-
-	desc_rx->callback = spi_imx_dma_rx_callback;
-	desc_rx->callback_param = (void *)spi_imx;
-	dmaengine_submit(desc_rx);
-	reinit_completion(&spi_imx->dma_rx_completion);
-	dma_async_issue_pending(controller->dma_rx);
-
-	desc_tx = dmaengine_prep_slave_sg(controller->dma_tx,
-				tx->sgl, tx->nents, DMA_MEM_TO_DEV,
-				DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-	if (!desc_tx) {
-		dmaengine_terminate_all(controller->dma_tx);
-		dmaengine_terminate_all(controller->dma_rx);
-		return -EINVAL;
-	}
-
-	desc_tx->callback = spi_imx_dma_tx_callback;
-	desc_tx->callback_param = (void *)spi_imx;
-	dmaengine_submit(desc_tx);
-	reinit_completion(&spi_imx->dma_tx_completion);
-	dma_async_issue_pending(controller->dma_tx);
-
-	spi_imx->devtype_data->trigger(spi_imx);
-
-	transfer_timeout = spi_imx_calculate_timeout(spi_imx, transfer->len);
-
-	/* Wait SDMA to finish the data transfer.*/
-	time_left = wait_for_completion_timeout(&spi_imx->dma_tx_completion,
-						transfer_timeout);
-	if (!time_left) {
-		dev_err(spi_imx->dev, "I/O Error in DMA TX\n");
-		dmaengine_terminate_all(controller->dma_tx);
-		dmaengine_terminate_all(controller->dma_rx);
-		return -ETIMEDOUT;
-	}
-
-	time_left = wait_for_completion_timeout(&spi_imx->dma_rx_completion,
-						transfer_timeout);
-	if (!time_left) {
-		dev_err(&controller->dev, "I/O Error in DMA RX\n");
-		spi_imx->devtype_data->reset(spi_imx);
-		dmaengine_terminate_all(controller->dma_rx);
-		return -ETIMEDOUT;
-	}
+	ret = spi_imx_dma_submit(spi_imx, transfer);
+	if (ret)
+		return ret;
 
 	return 0;
 /* fallback to pio */
-- 
2.34.1



From carlos.song at nxp.com  Wed Dec  3 00:59:46 2025
From: carlos.song at nxp.com (Carlos Song)
Date: Wed,  3 Dec 2025 16:59:46 +0800
Subject: [PATCH v3 3/6] spi: imx: avoid dmaengine_terminate_all() on TX prep failure
In-Reply-To: <20251203085949.2922166-1-carlos.song@nxp.com>
References: <20251203085949.2922166-1-carlos.song@nxp.com>
Message-ID: <20251203085949.2922166-4-carlos.song@nxp.com>

If dmaengine_prep_slave_sg() fails, no descriptor is submitted to the TX
channel and DMA is never started. Therefore, calling
dmaengine_terminate_all() for the TX DMA channel is unnecessary.

Signed-off-by: Carlos Song <carlos.song at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/spi/spi-imx.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 012f5bcbf73f..186963d3d2e0 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -1468,7 +1468,6 @@ static int spi_imx_dma_submit(struct spi_imx_data *spi_imx,
 					  tx->sgl, tx->nents, DMA_MEM_TO_DEV,
 					  DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!desc_tx) {
-		dmaengine_terminate_all(controller->dma_tx);
 		dmaengine_terminate_all(controller->dma_rx);
 		return -EINVAL;
 	}
-- 
2.34.1



From carlos.song at nxp.com  Wed Dec  3 00:59:47 2025
From: carlos.song at nxp.com (Carlos Song)
Date: Wed,  3 Dec 2025 16:59:47 +0800
Subject: [PATCH v3 4/6] spi: imx: handle DMA submission errors with dma_submit_error()
In-Reply-To: <20251203085949.2922166-1-carlos.song@nxp.com>
References: <20251203085949.2922166-1-carlos.song@nxp.com>
Message-ID: <20251203085949.2922166-5-carlos.song@nxp.com>

Add error handling for DMA request submission by checking the return
cookie with dma_submit_error(). This prevents propagating submission
failures through the DMA transfer process, which could lead to
unexpected behavior.

Signed-off-by: Carlos Song <carlos.song at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/spi/spi-imx.c | 28 ++++++++++++++++++++++------
 1 file changed, 22 insertions(+), 6 deletions(-)

diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 186963d3d2e0..42f64d9535c9 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -1445,6 +1445,7 @@ static int spi_imx_dma_submit(struct spi_imx_data *spi_imx,
 	struct dma_async_tx_descriptor *desc_tx, *desc_rx;
 	unsigned long transfer_timeout;
 	unsigned long time_left;
+	dma_cookie_t cookie;
 
 	/*
 	 * The TX DMA setup starts the transfer, so make sure RX is configured
@@ -1460,21 +1461,29 @@ static int spi_imx_dma_submit(struct spi_imx_data *spi_imx,
 
 	desc_rx->callback = spi_imx_dma_rx_callback;
 	desc_rx->callback_param = (void *)spi_imx;
-	dmaengine_submit(desc_rx);
+	cookie = dmaengine_submit(desc_rx);
+	if (dma_submit_error(cookie)) {
+		dev_err(spi_imx->dev, "submitting DMA RX failed\n");
+		transfer->error |= SPI_TRANS_FAIL_NO_START;
+		goto dmaengine_terminate_rx;
+	}
+
 	reinit_completion(&spi_imx->dma_rx_completion);
 	dma_async_issue_pending(controller->dma_rx);
 
 	desc_tx = dmaengine_prep_slave_sg(controller->dma_tx,
 					  tx->sgl, tx->nents, DMA_MEM_TO_DEV,
 					  DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-	if (!desc_tx) {
-		dmaengine_terminate_all(controller->dma_rx);
-		return -EINVAL;
-	}
+	if (!desc_tx)
+		goto dmaengine_terminate_rx;
 
 	desc_tx->callback = spi_imx_dma_tx_callback;
 	desc_tx->callback_param = (void *)spi_imx;
-	dmaengine_submit(desc_tx);
+	cookie = dmaengine_submit(desc_tx);
+	if (dma_submit_error(cookie)) {
+		dev_err(spi_imx->dev, "submitting DMA TX failed\n");
+		goto dmaengine_terminate_tx;
+	}
 	reinit_completion(&spi_imx->dma_tx_completion);
 	dma_async_issue_pending(controller->dma_tx);
 
@@ -1502,6 +1511,13 @@ static int spi_imx_dma_submit(struct spi_imx_data *spi_imx,
 	}
 
 	return 0;
+
+dmaengine_terminate_tx:
+	dmaengine_terminate_all(controller->dma_tx);
+dmaengine_terminate_rx:
+	dmaengine_terminate_all(controller->dma_rx);
+
+	return -EINVAL;
 }
 
 static void spi_imx_dma_max_wml_find(struct spi_imx_data *spi_imx,
-- 
2.34.1



From primoz.fiser at norik.com  Wed Dec  3 00:34:43 2025
From: primoz.fiser at norik.com (Primoz Fiser)
Date: Wed, 3 Dec 2025 09:34:43 +0100
Subject: [PATCH 2/2] arm64: dts: imx93-phyboard-segin: Add peb-av-02
 overlay
In-Reply-To: <20251202-v6-18-topic-imx93-phyboard-segin-av-02-display-v1-2-9c14be6c7478@pengutronix.de>
References: <20251202-v6-18-topic-imx93-phyboard-segin-av-02-display-v1-0-9c14be6c7478@pengutronix.de>
 <20251202-v6-18-topic-imx93-phyboard-segin-av-02-display-v1-2-9c14be6c7478@pengutronix.de>
Message-ID: <15bb2331-713a-4b6a-ae9a-4870066e84dc@norik.com>

Hi Marco,

On 2. 12. 25 14:44, Marco Felsch wrote:
> From: Andrej Picej <andrej.picej at norik.com>
> 
> Add overlay for Audio-Video module PEB-AV-02. Add support for panel
> display, capacitive touchscreen and backlight.
> 
> For now the backlight is configured as a GPIO, brightness of the display
> can not be set. When the FLEXIO PWM driver is available this should be
> switched to PWM backlight driver.
> 
> Signed-off-by: Andrej Picej <andrej.picej at norik.com>
> [rework commit message, use local regulator, remove compatible]
> Signed-off-by: Primoz Fiser <primoz.fiser at norik.com>
> Signed-off-by: Christian Hemp <c.hemp at phytec.de>
> [m.felsch at pengutronix.de: cleanup downstream commit]
> Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
> ---
>  arch/arm64/boot/dts/freescale/Makefile             |   2 +
>  .../freescale/imx93-phyboard-segin-peb-av-02.dtso  | 135 +++++++++++++++++++++
>  2 files changed, 137 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
> index 525ef180481d331e9c4decd092b7b831c497b67e..27e27ac29e82bc0692e86c2ba15c240dc9fbe1c6 100644
> --- a/arch/arm64/boot/dts/freescale/Makefile
> +++ b/arch/arm64/boot/dts/freescale/Makefile
> @@ -357,10 +357,12 @@ dtb-$(CONFIG_ARCH_MXC) += imx93-phyboard-nash.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx93-phyboard-segin.dtb
>  
>  imx93-phyboard-nash-peb-wlbt-07-dtbs += imx93-phyboard-nash.dtb imx93-phyboard-nash-peb-wlbt-07.dtbo
> +imx93-phyboard-segin-peb-av-02-dtbs += imx93-phyboard-segin.dtb imx93-phyboard-segin-peb-av-02.dtbo
>  imx93-phyboard-segin-peb-eval-01-dtbs += imx93-phyboard-segin.dtb imx93-phyboard-segin-peb-eval-01.dtbo
>  imx93-phyboard-segin-peb-wlbt-05-dtbs += imx93-phyboard-segin.dtb imx93-phyboard-segin-peb-wlbt-05.dtbo
>  imx93-phycore-rpmsg-dtbs += imx93-phyboard-nash.dtb imx93-phyboard-segin.dtb imx93-phycore-rpmsg.dtbo
>  dtb-$(CONFIG_ARCH_MXC) += imx93-phyboard-nash-peb-wlbt-07.dtb
> +dtb-$(CONFIG_ARCH_MXC) += imx93-phyboard-segin-peb-av-02.dtb

Here you need to rebase since new commits on linux-next.

>  dtb-$(CONFIG_ARCH_MXC) += imx93-phyboard-segin-peb-eval-01.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx93-phyboard-segin-peb-wlbt-05.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx93-phycore-rpmsg.dtb
> diff --git a/arch/arm64/boot/dts/freescale/imx93-phyboard-segin-peb-av-02.dtso b/arch/arm64/boot/dts/freescale/imx93-phyboard-segin-peb-av-02.dtso
> new file mode 100644
> index 0000000000000000000000000000000000000000..2e7074e402dc8fdeb1568d4f2d4960431e972501
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx93-phyboard-segin-peb-av-02.dtso
> @@ -0,0 +1,135 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright (C) 2025 PHYTEC Messtechnik GmbH
> + * Copyright (C) 2025 Pengutronix
> + *
> + * Author: Andrej Picej <andrej.picej at norik.com>
> + * Author: Marco Felsch <kernel at pengutronix.de>
> + */
> +
> +#include <dt-bindings/clock/imx93-clock.h>
> +#include <dt-bindings/gpio/gpio.h>
> +#include <dt-bindings/interrupt-controller/arm-gic.h>
> +#include "imx93-pinfunc.h"
> +
> +/dts-v1/;
> +/plugin/;
> +
> +&{/} {
> +	/* TODO: Convert to PWM backlight once the FlexIO PWM is supported */
> +	backlight: backlight {
> +		compatible = "gpio-backlight";
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&pinctrl_backlight>;
> +		gpios = <&gpio4 28 GPIO_ACTIVE_HIGH>;
> +	};
> +
> +	panel {
> +		compatible = "edt,etm0700g0edh6";
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&pinctrl_panel>;
> +
> +		backlight = <&backlight>;
> +		enable-gpios = <&gpio4 29 GPIO_ACTIVE_HIGH>;
> +		power-supply = <&reg_x71_vcc_3v3>;
> +
> +		port {
> +			panel_in: endpoint {
> +				remote-endpoint = <&dpi_to_panel>;
> +			};
> +		};
> +	};
> +
> +	reg_x71_vcc_3v3: regulator-x71-vcc-3v3 {

I just checked the schematics.

Can we rename this to reg_vcc_3v3_con in v2 maybe?

> +		compatible = "regulator-fixed";
> +		regulator-name = "X71-VCC3V3";

And this to "VCC3V3_CON"?

The reasoning behind is that "X71-VCC3V3" voltage doesn't exist on the
schematics, while there is actually "VCC3V3_CON" voltage supplying the
display panel.

> +		regulator-max-microvolt = <3300000>;
> +		regulator-min-microvolt = <3300000>;
> +	};
> +};
> +
> +&dpi_bridge {
> +	status = "okay";
> +};
> +
> +&dpi_to_panel {
> +	remote-endpoint = <&panel_in>;
> +	bus-width = <18>;
> +};
> +
> +&lcdif {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_lcdif>;
> +	assigned-clocks = <&clk IMX93_CLK_VIDEO_PLL>;
> +	assigned-clock-rates = <332600000>;
> +	status = "okay";
> +};
> +
> +&lpi2c2 {
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +
> +	touchscreen at 38 {
> +		compatible = "edt,edt-ft5406";
> +		reg = <0x38>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&pinctrl_touchscreen>;
> +		interrupt-parent = <&gpio4>;
> +		interrupts = <12 IRQ_TYPE_EDGE_FALLING>;
> +		reset-gpios = <&gpio4 1 GPIO_ACTIVE_LOW>;
> +		touchscreen-size-x = <1792>;
> +		touchscreen-size-y = <1024>;

Please add "wakeup-source" property here like in the downstream commit.

With this in place, panel touch can be used to wake up the board from sleep.

Last but not least, can you add the vcc and iovcc supply regulators here
like in the downstream commit:

vcc-supply = <&reg_vcc_3v3_con>;
iovcc-supply = <&reg_vcc_3v3_con>;

to get rid of the following warnings:

edt_ft5x06 1-0038: supply vcc not found, using dummy regulator
edt_ft5x06 1-0038: supply iovcc not found, using dummy regulator

Anyway, I tested the display on the segin board with latest linux-next
and your patches. Can report display, touch and backlight work as expected.

Thank you!

Tested-by: Primoz Fiser <primoz.fiser at norik.com>

BR,
Primoz

> +	};
> +};
> +
> +&media_blk_ctrl {
> +	status = "okay";
> +};
> +
> +&iomuxc {
> +	pinctrl_backlight: backlightgrp {
> +		fsl,pins = <
> +			MX93_PAD_CCM_CLKO3__GPIO4_IO28			0x1133e
> +		>;
> +	};
> +
> +	pinctrl_lcdif: lcdifgrp {
> +		fsl,pins = <
> +			MX93_PAD_GPIO_IO00__MEDIAMIX_DISP_CLK		0x50e
> +			MX93_PAD_GPIO_IO01__MEDIAMIX_DISP_DE		0x50e
> +			MX93_PAD_GPIO_IO02__MEDIAMIX_DISP_VSYNC		0x50e
> +			MX93_PAD_GPIO_IO03__MEDIAMIX_DISP_HSYNC		0x50e
> +			MX93_PAD_GPIO_IO04__MEDIAMIX_DISP_DATA00	0x50e
> +			MX93_PAD_GPIO_IO05__MEDIAMIX_DISP_DATA01	0x50e
> +			MX93_PAD_GPIO_IO06__MEDIAMIX_DISP_DATA02	0x50e
> +			MX93_PAD_GPIO_IO07__MEDIAMIX_DISP_DATA03	0x50e
> +			MX93_PAD_GPIO_IO08__MEDIAMIX_DISP_DATA04	0x50e
> +			MX93_PAD_GPIO_IO09__MEDIAMIX_DISP_DATA05	0x51e
> +			MX93_PAD_GPIO_IO10__MEDIAMIX_DISP_DATA06	0x50e
> +			MX93_PAD_GPIO_IO11__MEDIAMIX_DISP_DATA07	0x50e
> +			MX93_PAD_GPIO_IO12__MEDIAMIX_DISP_DATA08	0x50e
> +			MX93_PAD_GPIO_IO13__MEDIAMIX_DISP_DATA09	0x50e
> +			MX93_PAD_GPIO_IO14__MEDIAMIX_DISP_DATA10	0x50e
> +			MX93_PAD_GPIO_IO15__MEDIAMIX_DISP_DATA11	0x50e
> +			MX93_PAD_GPIO_IO16__MEDIAMIX_DISP_DATA12	0x506
> +			MX93_PAD_GPIO_IO17__MEDIAMIX_DISP_DATA13	0x506
> +			MX93_PAD_GPIO_IO18__MEDIAMIX_DISP_DATA14	0x506
> +			MX93_PAD_GPIO_IO19__MEDIAMIX_DISP_DATA15	0x506
> +			MX93_PAD_GPIO_IO20__MEDIAMIX_DISP_DATA16	0x506
> +			MX93_PAD_GPIO_IO21__MEDIAMIX_DISP_DATA17	0x506
> +		>;
> +	};
> +
> +	pinctrl_panel: panelgrp {
> +		fsl,pins = <
> +			MX93_PAD_CCM_CLKO4__GPIO4_IO29			0x1133e
> +		>;
> +	};
> +
> +	pinctrl_touchscreen: touchscreengrp {
> +		fsl,pins = <
> +			MX93_PAD_ENET1_MDIO__GPIO4_IO01			0x11e
> +			MX93_PAD_ENET1_RD2__GPIO4_IO12			0x1133e
> +		>;
> +	};
> +};
> 

-- 
Primoz Fiser
phone: +386-41-390-545
email: primoz.fiser at norik.com
--
Norik systems d.o.o.
Your embedded software partner
Slovenia, EU
phone: +386-41-540-545
email: info at norik.com



From primoz.fiser at norik.com  Wed Dec  3 00:31:10 2025
From: primoz.fiser at norik.com (Primoz Fiser)
Date: Wed, 3 Dec 2025 09:31:10 +0100
Subject: [PATCH 1/2] clk: imx: fracn-gppll: Add 332.60 MHz Support
In-Reply-To: <20251202-v6-18-topic-imx93-phyboard-segin-av-02-display-v1-1-9c14be6c7478@pengutronix.de>
References: <20251202-v6-18-topic-imx93-phyboard-segin-av-02-display-v1-0-9c14be6c7478@pengutronix.de>
 <20251202-v6-18-topic-imx93-phyboard-segin-av-02-display-v1-1-9c14be6c7478@pengutronix.de>
Message-ID: <304467a9-4c7a-4722-9e70-4d178113c33b@norik.com>

Hi Marco,

On 2. 12. 25 14:44, Marco Felsch wrote:
> Some parallel panels have a pixelclk of 33.260 MHz. Add support for
> 332.60 MHz so a by 10 divider can be used to derive the exact pixelclk.

Reviewed-by: Primoz Fiser <primoz.fiser at norik.com>
> 
> Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
> ---
>  drivers/clk/imx/clk-fracn-gppll.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/clk/imx/clk-fracn-gppll.c b/drivers/clk/imx/clk-fracn-gppll.c
> index 090d608672508a8819dc68eedec5b8d4a2c140c8..579f76494eb041dfba58b8cd10eb2453a0ec4178 100644
> --- a/drivers/clk/imx/clk-fracn-gppll.c
> +++ b/drivers/clk/imx/clk-fracn-gppll.c
> @@ -88,6 +88,7 @@ static const struct imx_fracn_gppll_rate_table fracn_tbl[] = {
>  	PLL_FRACN_GP(445333333U, 167, 0, 1, 0, 9),
>  	PLL_FRACN_GP(400000000U, 200, 0, 1, 0, 12),
>  	PLL_FRACN_GP(393216000U, 163, 84, 100, 0, 10),
> +	PLL_FRACN_GP(332600000U, 138, 584, 1000, 0, 10),
>  	PLL_FRACN_GP(300000000U, 150, 0, 1, 0, 12)
>  };
>  
> 

-- 
Primoz Fiser
phone: +386-41-390-545
email: primoz.fiser at norik.com
--
Norik systems d.o.o.
Your embedded software partner
Slovenia, EU
phone: +386-41-540-545
email: info at norik.com



From carlos.song at nxp.com  Wed Dec  3 00:59:48 2025
From: carlos.song at nxp.com (Carlos Song)
Date: Wed,  3 Dec 2025 16:59:48 +0800
Subject: [PATCH v3 5/6] spi: imx: support dynamic burst length for ECSPI DMA mode
In-Reply-To: <20251203085949.2922166-1-carlos.song@nxp.com>
References: <20251203085949.2922166-1-carlos.song@nxp.com>
Message-ID: <20251203085949.2922166-6-carlos.song@nxp.com>

ECSPI transfers only one word per frame in DMA mode, causing SCLK stalls
between words due to BURST_LENGTH updates, which significantly impacts
performance.

To improve throughput, configure BURST_LENGTH as large as possible (up to
512 bytes per frame) instead of word length. This avoids delays between
words. When transfer length is not 4-byte aligned, use bounce buffers to
align data for DMA. TX uses aligned words for TXFIFO, while RX trims DMA
buffer data after transfer completion.

Introduce a new dma_package structure to store:
  1. BURST_LENGTH values for each DMA request
  2. Variables for DMA submission
  3. DMA transmission length and actual data length

Handle three cases:
  - len <= 512 bytes: one package, BURST_LENGTH = len * 8 - 1
  - len > 512 and aligned: one package, BURST_LENGTH = max (512 bytes)
  - len > 512 and unaligned: two packages, second for tail data

Performance test (spidev_test @10MHz, 4KB):
  Before: tx/rx ~6651.9 kbps
  After:  tx/rx ~9922.2 kbps (~50% improvement)

For compatibility with slow SPI devices, add configurable word delay in
DMA mode. When word delay is set, dynamic burst is disabled and
BURST_LENGTH equals word length.

Signed-off-by: Carlos Song <carlos.song at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/spi/spi-imx.c | 413 ++++++++++++++++++++++++++++++++++++++----
 1 file changed, 377 insertions(+), 36 deletions(-)

diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 42f64d9535c9..04a492e7dbeb 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -60,6 +60,7 @@ MODULE_PARM_DESC(polling_limit_us,
 #define MX51_ECSPI_CTRL_MAX_BURST	512
 /* The maximum bytes that IMX53_ECSPI can transfer in target mode.*/
 #define MX53_MAX_TRANSFER_BYTES		512
+#define BYTES_PER_32BITS_WORD		4
 
 enum spi_imx_devtype {
 	IMX1_CSPI,
@@ -95,6 +96,16 @@ struct spi_imx_devtype_data {
 	enum spi_imx_devtype devtype;
 };
 
+struct dma_data_package {
+	u32 cmd_word;
+	void *dma_rx_buf;
+	void *dma_tx_buf;
+	dma_addr_t dma_tx_addr;
+	dma_addr_t dma_rx_addr;
+	int dma_len;
+	int data_len;
+};
+
 struct spi_imx_data {
 	struct spi_controller *controller;
 	struct device *dev;
@@ -130,6 +141,9 @@ struct spi_imx_data {
 	u32 wml;
 	struct completion dma_rx_completion;
 	struct completion dma_tx_completion;
+	size_t dma_package_num;
+	struct dma_data_package *dma_data;
+	int rx_offset;
 
 	const struct spi_imx_devtype_data *devtype_data;
 };
@@ -189,6 +203,9 @@ MXC_SPI_BUF_TX(u16)
 MXC_SPI_BUF_RX(u32)
 MXC_SPI_BUF_TX(u32)
 
+/* Align to cache line to avoid swiotlo bounce */
+#define DMA_CACHE_ALIGNED_LEN(x) ALIGN((x), dma_get_cache_alignment())
+
 /* First entry is reserved, second entry is valid only if SDHC_SPIEN is set
  * (which is currently not the case in this driver)
  */
@@ -253,6 +270,14 @@ static bool spi_imx_can_dma(struct spi_controller *controller, struct spi_device
 	if (transfer->len < spi_imx->devtype_data->fifo_size)
 		return false;
 
+	/* DMA only can transmit data in bytes */
+	if (spi_imx->bits_per_word != 8 && spi_imx->bits_per_word != 16 &&
+	    spi_imx->bits_per_word != 32)
+		return false;
+
+	if (transfer->len >= MAX_SDMA_BD_BYTES)
+		return false;
+
 	spi_imx->dynamic_burst = 0;
 
 	return true;
@@ -1398,8 +1423,6 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
 
 	init_completion(&spi_imx->dma_rx_completion);
 	init_completion(&spi_imx->dma_tx_completion);
-	controller->can_dma = spi_imx_can_dma;
-	controller->max_dma_len = MAX_SDMA_BD_BYTES;
 	spi_imx->controller->flags = SPI_CONTROLLER_MUST_RX |
 					 SPI_CONTROLLER_MUST_TX;
 
@@ -1437,10 +1460,259 @@ static int spi_imx_calculate_timeout(struct spi_imx_data *spi_imx, int size)
 	return secs_to_jiffies(2 * timeout);
 }
 
+static void spi_imx_dma_unmap(struct spi_imx_data *spi_imx,
+			      struct dma_data_package *dma_data)
+{
+	struct device *tx_dev = spi_imx->controller->dma_tx->device->dev;
+	struct device *rx_dev = spi_imx->controller->dma_rx->device->dev;
+
+	dma_unmap_single(tx_dev, dma_data->dma_tx_addr,
+			 DMA_CACHE_ALIGNED_LEN(dma_data->dma_len),
+			 DMA_TO_DEVICE);
+	dma_unmap_single(rx_dev, dma_data->dma_rx_addr,
+			 DMA_CACHE_ALIGNED_LEN(dma_data->dma_len),
+			 DMA_FROM_DEVICE);
+}
+
+static void spi_imx_dma_rx_data_handle(struct spi_imx_data *spi_imx,
+				       struct dma_data_package *dma_data, void *rx_buf,
+				       bool word_delay)
+{
+	void *copy_ptr;
+	int unaligned;
+
+	/*
+	 * On little-endian CPUs, adjust byte order:
+	 * - Swap bytes when bpw = 8
+	 * - Swap half-words when bpw = 16
+	 * This ensures correct data ordering for DMA transfers.
+	 */
+#ifdef __LITTLE_ENDIAN
+	if (!word_delay) {
+		unsigned int bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
+		u32 *temp = dma_data->dma_rx_buf;
+
+		for (int i = 0; i < DIV_ROUND_UP(dma_data->dma_len, sizeof(*temp)); i++) {
+			if (bytes_per_word == 1)
+				swab32s(temp + i);
+			else if (bytes_per_word == 2)
+				swahw32s(temp + i);
+		}
+	}
+#endif
+
+	/*
+	 * When dynamic burst enabled, DMA RX always receives 32-bit words from RXFIFO with
+	 * buswidth = 4, but when data_len is not 4-bytes alignment, the RM shows when
+	 * burst length = 32*n + m bits, a SPI burst contains the m LSB in first word and all
+	 * 32 bits in other n words. So if garbage bytes in the first word, trim first word then
+	 * copy the actual data to rx_buf.
+	 */
+	if (dma_data->data_len % BYTES_PER_32BITS_WORD && !word_delay) {
+		unaligned = dma_data->data_len % BYTES_PER_32BITS_WORD;
+		copy_ptr = (u8 *)dma_data->dma_rx_buf + BYTES_PER_32BITS_WORD - unaligned;
+	} else {
+		copy_ptr = dma_data->dma_rx_buf;
+	}
+
+	memcpy(rx_buf, copy_ptr, dma_data->data_len);
+}
+
+static int spi_imx_dma_map(struct spi_imx_data *spi_imx,
+			   struct dma_data_package *dma_data)
+{
+	struct spi_controller *controller = spi_imx->controller;
+	struct device *tx_dev = controller->dma_tx->device->dev;
+	struct device *rx_dev = controller->dma_rx->device->dev;
+	int ret;
+
+	dma_data->dma_tx_addr = dma_map_single(tx_dev, dma_data->dma_tx_buf,
+					       DMA_CACHE_ALIGNED_LEN(dma_data->dma_len),
+					       DMA_TO_DEVICE);
+	ret = dma_mapping_error(tx_dev, dma_data->dma_tx_addr);
+	if (ret < 0) {
+		dev_err(spi_imx->dev, "DMA TX map failed %d\n", ret);
+		return ret;
+	}
+
+	dma_data->dma_rx_addr = dma_map_single(rx_dev, dma_data->dma_rx_buf,
+					       DMA_CACHE_ALIGNED_LEN(dma_data->dma_len),
+					       DMA_FROM_DEVICE);
+	ret = dma_mapping_error(rx_dev, dma_data->dma_rx_addr);
+	if (ret < 0) {
+		dev_err(spi_imx->dev, "DMA RX map failed %d\n", ret);
+		dma_unmap_single(tx_dev, dma_data->dma_tx_addr,
+				 DMA_CACHE_ALIGNED_LEN(dma_data->dma_len),
+				 DMA_TO_DEVICE);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int spi_imx_dma_tx_data_handle(struct spi_imx_data *spi_imx,
+				      struct dma_data_package *dma_data,
+				      const void *tx_buf,
+				      bool word_delay)
+{
+	void *copy_ptr;
+	int unaligned;
+
+	if (word_delay) {
+		dma_data->dma_len = dma_data->data_len;
+	} else {
+		/*
+		 * As per the reference manual, when burst length = 32*n + m bits, ECSPI
+		 * sends m LSB bits in the first word, followed by n full 32-bit words.
+		 * Since actual data may not be 4-byte aligned, allocate DMA TX/RX buffers
+		 * to ensure alignment. For TX, DMA pushes 4-byte aligned words to TXFIFO,
+		 * while ECSPI uses BURST_LENGTH settings to maintain correct bit count.
+		 * For RX, DMA always receives 32-bit words from RXFIFO, when data len is
+		 * not 4-byte aligned, trim the first word to drop garbage bytes, then group
+		 * all transfer DMA bounse buffer and copy all valid data to rx_buf.
+		 */
+		dma_data->dma_len = ALIGN(dma_data->data_len, BYTES_PER_32BITS_WORD);
+	}
+
+	dma_data->dma_tx_buf = kzalloc(dma_data->dma_len, GFP_KERNEL);
+	if (!dma_data->dma_tx_buf)
+		return -ENOMEM;
+
+	dma_data->dma_rx_buf = kzalloc(dma_data->dma_len, GFP_KERNEL);
+	if (!dma_data->dma_rx_buf) {
+		kfree(dma_data->dma_tx_buf);
+		return -ENOMEM;
+	}
+
+	if (dma_data->data_len % BYTES_PER_32BITS_WORD && !word_delay) {
+		unaligned = dma_data->data_len % BYTES_PER_32BITS_WORD;
+		copy_ptr = (u8 *)dma_data->dma_tx_buf + BYTES_PER_32BITS_WORD - unaligned;
+	} else {
+		copy_ptr = dma_data->dma_tx_buf;
+	}
+
+	memcpy(copy_ptr, tx_buf, dma_data->data_len);
+
+	/*
+	 * When word_delay is enabled, DMA transfers an entire word in one minor loop.
+	 * In this case, no data requires additional handling.
+	 */
+	if (word_delay)
+		return 0;
+
+#ifdef __LITTLE_ENDIAN
+	/*
+	 * On little-endian CPUs, adjust byte order:
+	 * - Swap bytes when bpw = 8
+	 * - Swap half-words when bpw = 16
+	 * This ensures correct data ordering for DMA transfers.
+	 */
+	unsigned int bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
+	u32 *temp = dma_data->dma_tx_buf;
+
+	for (int i = 0; i < DIV_ROUND_UP(dma_data->dma_len, sizeof(*temp)); i++) {
+		if (bytes_per_word == 1)
+			swab32s(temp + i);
+		else if (bytes_per_word == 2)
+			swahw32s(temp + i);
+	}
+#endif
+
+	return 0;
+}
+
+static int spi_imx_dma_data_prepare(struct spi_imx_data *spi_imx,
+				    struct spi_transfer *transfer,
+				    bool word_delay)
+{
+	u32 pre_bl, tail_bl;
+	u32 ctrl;
+	int ret;
+
+	/*
+	 * ECSPI supports a maximum burst of 512 bytes. When xfer->len exceeds 512
+	 * and is not a multiple of 512, a tail transfer is required. BURST_LEGTH
+	 * is used for SPI HW to maintain correct bit count. BURST_LENGTH should
+	 * update with data length. After DMA request submit, SPI can not update the
+	 * BURST_LENGTH, in this case, we must split two package, update the register
+	 * then setup second DMA transfer.
+	 */
+	ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL);
+	if (word_delay) {
+		/*
+		 * When SPI IMX need to support word delay, according to "Sample Period Control
+		 * Register" shows, The Sample Period Control Register (ECSPI_PERIODREG)
+		 * provides software a way to insert delays (wait states) between consecutive
+		 * SPI transfers. As a result, ECSPI can only transfer one word per frame, and
+		 * the delay occurs between frames.
+		 */
+		spi_imx->dma_package_num = 1;
+		pre_bl = spi_imx->bits_per_word - 1;
+	} else if (transfer->len <= MX51_ECSPI_CTRL_MAX_BURST) {
+		spi_imx->dma_package_num = 1;
+		pre_bl = transfer->len * BITS_PER_BYTE - 1;
+	} else if (!(transfer->len % MX51_ECSPI_CTRL_MAX_BURST)) {
+		spi_imx->dma_package_num = 1;
+		pre_bl = MX51_ECSPI_CTRL_MAX_BURST * BITS_PER_BYTE - 1;
+	} else {
+		spi_imx->dma_package_num = 2;
+		pre_bl = MX51_ECSPI_CTRL_MAX_BURST * BITS_PER_BYTE - 1;
+		tail_bl = (transfer->len % MX51_ECSPI_CTRL_MAX_BURST) * BITS_PER_BYTE - 1;
+	}
+
+	spi_imx->dma_data = kmalloc_array(spi_imx->dma_package_num,
+					  sizeof(struct dma_data_package),
+					  GFP_KERNEL | __GFP_ZERO);
+	if (!spi_imx->dma_data) {
+		dev_err(spi_imx->dev, "Failed to allocate DMA package buffer!\n");
+		return -ENOMEM;
+	}
+
+	if (spi_imx->dma_package_num == 1) {
+		ctrl &= ~MX51_ECSPI_CTRL_BL_MASK;
+		ctrl |= pre_bl << MX51_ECSPI_CTRL_BL_OFFSET;
+		spi_imx->dma_data[0].cmd_word = ctrl;
+		spi_imx->dma_data[0].data_len = transfer->len;
+		ret = spi_imx_dma_tx_data_handle(spi_imx, &spi_imx->dma_data[0], transfer->tx_buf,
+						 word_delay);
+		if (ret) {
+			kfree(spi_imx->dma_data);
+			return ret;
+		}
+	} else {
+		ctrl &= ~MX51_ECSPI_CTRL_BL_MASK;
+		ctrl |= pre_bl << MX51_ECSPI_CTRL_BL_OFFSET;
+		spi_imx->dma_data[0].cmd_word = ctrl;
+		spi_imx->dma_data[0].data_len = round_down(transfer->len,
+							   MX51_ECSPI_CTRL_MAX_BURST);
+		ret = spi_imx_dma_tx_data_handle(spi_imx, &spi_imx->dma_data[0], transfer->tx_buf,
+						 false);
+		if (ret) {
+			kfree(spi_imx->dma_data);
+			return ret;
+		}
+
+		ctrl &= ~MX51_ECSPI_CTRL_BL_MASK;
+		ctrl |= tail_bl << MX51_ECSPI_CTRL_BL_OFFSET;
+		spi_imx->dma_data[1].cmd_word = ctrl;
+		spi_imx->dma_data[1].data_len = transfer->len % MX51_ECSPI_CTRL_MAX_BURST;
+		ret = spi_imx_dma_tx_data_handle(spi_imx, &spi_imx->dma_data[1],
+						 transfer->tx_buf + spi_imx->dma_data[0].data_len,
+						 false);
+		if (ret) {
+			kfree(spi_imx->dma_data[0].dma_tx_buf);
+			kfree(spi_imx->dma_data[0].dma_rx_buf);
+			kfree(spi_imx->dma_data);
+		}
+	}
+
+	return 0;
+}
+
 static int spi_imx_dma_submit(struct spi_imx_data *spi_imx,
+			      struct dma_data_package *dma_data,
 			      struct spi_transfer *transfer)
 {
-	struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg;
 	struct spi_controller *controller = spi_imx->controller;
 	struct dma_async_tx_descriptor *desc_tx, *desc_rx;
 	unsigned long transfer_timeout;
@@ -1451,9 +1723,9 @@ static int spi_imx_dma_submit(struct spi_imx_data *spi_imx,
 	 * The TX DMA setup starts the transfer, so make sure RX is configured
 	 * before TX.
 	 */
-	desc_rx = dmaengine_prep_slave_sg(controller->dma_rx,
-					  rx->sgl, rx->nents, DMA_DEV_TO_MEM,
-					  DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	desc_rx = dmaengine_prep_slave_single(controller->dma_rx, dma_data->dma_rx_addr,
+					      dma_data->dma_len, DMA_DEV_TO_MEM,
+					      DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!desc_rx) {
 		transfer->error |= SPI_TRANS_FAIL_NO_START;
 		return -EINVAL;
@@ -1471,9 +1743,9 @@ static int spi_imx_dma_submit(struct spi_imx_data *spi_imx,
 	reinit_completion(&spi_imx->dma_rx_completion);
 	dma_async_issue_pending(controller->dma_rx);
 
-	desc_tx = dmaengine_prep_slave_sg(controller->dma_tx,
-					  tx->sgl, tx->nents, DMA_MEM_TO_DEV,
-					  DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	desc_tx = dmaengine_prep_slave_single(controller->dma_tx, dma_data->dma_tx_addr,
+					      dma_data->dma_len, DMA_MEM_TO_DEV,
+					      DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!desc_tx)
 		goto dmaengine_terminate_rx;
 
@@ -1521,16 +1793,16 @@ static int spi_imx_dma_submit(struct spi_imx_data *spi_imx,
 }
 
 static void spi_imx_dma_max_wml_find(struct spi_imx_data *spi_imx,
-				     struct spi_transfer *transfer)
+				     struct dma_data_package *dma_data,
+				     bool word_delay)
 {
-	struct sg_table *rx = &transfer->rx_sg;
-	struct scatterlist *last_sg = sg_last(rx->sgl, rx->nents);
-	unsigned int bytes_per_word, i;
+	unsigned int bytes_per_word = word_delay ?
+				      spi_imx_bytes_per_word(spi_imx->bits_per_word) :
+				      BYTES_PER_32BITS_WORD;
+	unsigned int i;
 
-	/* Get the right burst length from the last sg to ensure no tail data */
-	bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word);
 	for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) {
-		if (!(sg_dma_len(last_sg) % (i * bytes_per_word)))
+		if (!dma_data->dma_len % (i * bytes_per_word))
 			break;
 	}
 	/* Use 1 as wml in case no available burst length got */
@@ -1540,25 +1812,29 @@ static void spi_imx_dma_max_wml_find(struct spi_imx_data *spi_imx,
 	spi_imx->wml = i;
 }
 
-static int spi_imx_dma_configure(struct spi_controller *controller)
+static int spi_imx_dma_configure(struct spi_controller *controller, bool word_delay)
 {
 	int ret;
 	enum dma_slave_buswidth buswidth;
 	struct dma_slave_config rx = {}, tx = {};
 	struct spi_imx_data *spi_imx = spi_controller_get_devdata(controller);
 
-	switch (spi_imx_bytes_per_word(spi_imx->bits_per_word)) {
-	case 4:
+	if (word_delay) {
+		switch (spi_imx_bytes_per_word(spi_imx->bits_per_word)) {
+		case 4:
+			buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
+			break;
+		case 2:
+			buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
+			break;
+		case 1:
+			buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else {
 		buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
-		break;
-	case 2:
-		buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
-		break;
-	case 1:
-		buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
-		break;
-	default:
-		return -EINVAL;
 	}
 
 	tx.direction = DMA_MEM_TO_DEV;
@@ -1584,15 +1860,17 @@ static int spi_imx_dma_configure(struct spi_controller *controller)
 	return 0;
 }
 
-static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
-				struct spi_transfer *transfer)
+static int spi_imx_dma_package_transfer(struct spi_imx_data *spi_imx,
+					struct dma_data_package *dma_data,
+					struct spi_transfer *transfer,
+					bool word_delay)
 {
 	struct spi_controller *controller = spi_imx->controller;
 	int ret;
 
-	spi_imx_dma_max_wml_find(spi_imx, transfer);
+	spi_imx_dma_max_wml_find(spi_imx, dma_data, word_delay);
 
-	ret = spi_imx_dma_configure(controller);
+	ret = spi_imx_dma_configure(controller, word_delay);
 	if (ret)
 		goto dma_failure_no_start;
 
@@ -1603,10 +1881,17 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
 	}
 	spi_imx->devtype_data->setup_wml(spi_imx);
 
-	ret = spi_imx_dma_submit(spi_imx, transfer);
+	ret = spi_imx_dma_submit(spi_imx, dma_data, transfer);
 	if (ret)
 		return ret;
 
+	/* Trim the DMA RX buffer and copy the actual data to rx_buf */
+	dma_sync_single_for_cpu(controller->dma_rx->device->dev, dma_data->dma_rx_addr,
+				dma_data->dma_len, DMA_FROM_DEVICE);
+	spi_imx_dma_rx_data_handle(spi_imx, dma_data, transfer->rx_buf + spi_imx->rx_offset,
+				   word_delay);
+	spi_imx->rx_offset += dma_data->data_len;
+
 	return 0;
 /* fallback to pio */
 dma_failure_no_start:
@@ -1614,6 +1899,57 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
 	return ret;
 }
 
+static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
+				struct spi_transfer *transfer)
+{
+	bool word_delay = transfer->word_delay.value != 0;
+	int ret;
+	int i;
+
+	ret = spi_imx_dma_data_prepare(spi_imx, transfer, word_delay);
+	if (ret < 0) {
+		transfer->error |= SPI_TRANS_FAIL_NO_START;
+		dev_err(spi_imx->dev, "DMA data prepare fail\n");
+		goto fallback_pio;
+	}
+
+	spi_imx->rx_offset = 0;
+
+	/* Each dma_package performs a separate DMA transfer once */
+	for (i = 0; i < spi_imx->dma_package_num; i++) {
+		ret = spi_imx_dma_map(spi_imx, &spi_imx->dma_data[i]);
+		if (ret < 0) {
+			if (i == 0)
+				transfer->error |= SPI_TRANS_FAIL_NO_START;
+			dev_err(spi_imx->dev, "DMA map fail\n");
+			break;
+		}
+
+		/* Update the CTRL register BL field */
+		writel(spi_imx->dma_data[i].cmd_word, spi_imx->base + MX51_ECSPI_CTRL);
+
+		ret = spi_imx_dma_package_transfer(spi_imx, &spi_imx->dma_data[i],
+						   transfer, word_delay);
+
+		/* Whether the dma transmission is successful or not, dma unmap is necessary */
+		spi_imx_dma_unmap(spi_imx, &spi_imx->dma_data[i]);
+
+		if (ret < 0) {
+			dev_dbg(spi_imx->dev, "DMA %d transfer not really finish\n", i);
+			break;
+		}
+	}
+
+	for (int j = 0; j < spi_imx->dma_package_num; j++) {
+		kfree(spi_imx->dma_data[j].dma_tx_buf);
+		kfree(spi_imx->dma_data[j].dma_rx_buf);
+	}
+	kfree(spi_imx->dma_data);
+
+fallback_pio:
+	return ret;
+}
+
 static int spi_imx_pio_transfer(struct spi_device *spi,
 				struct spi_transfer *transfer)
 {
@@ -1780,9 +2116,14 @@ static int spi_imx_transfer_one(struct spi_controller *controller,
 	 * transfer, the SPI transfer has already been mapped, so we
 	 * have to do the DMA transfer here.
 	 */
-	if (spi_imx->usedma)
-		return spi_imx_dma_transfer(spi_imx, transfer);
-
+	if (spi_imx->usedma) {
+		ret = spi_imx_dma_transfer(spi_imx, transfer);
+		if (transfer->error & SPI_TRANS_FAIL_NO_START) {
+			spi_imx->usedma = false;
+			return spi_imx_pio_transfer(spi, transfer);
+		}
+		return ret;
+	}
 	/* run in polling mode for short transfers */
 	if (transfer->len == 1 || (polling_limit_us &&
 				   spi_imx_transfer_estimate_time_us(transfer) < polling_limit_us))
-- 
2.34.1



From carlos.song at nxp.com  Wed Dec  3 00:59:49 2025
From: carlos.song at nxp.com (Carlos Song)
Date: Wed,  3 Dec 2025 16:59:49 +0800
Subject: [PATCH v3 6/6] spi: imx: enable DMA mode for target operation
In-Reply-To: <20251203085949.2922166-1-carlos.song@nxp.com>
References: <20251203085949.2922166-1-carlos.song@nxp.com>
Message-ID: <20251203085949.2922166-7-carlos.song@nxp.com>

Enable DMA mode for SPI IMX in target mode. Disable the word delay feature
for target mode, because target mode should always keep high performance
to make sure it can follow the master. Target mode continues to operate in
dynamic burst mode.

Signed-off-by: Carlos Song <carlos.song at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/spi/spi-imx.c | 77 ++++++++++++++++++++++++++++++++-----------
 1 file changed, 57 insertions(+), 20 deletions(-)

diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 04a492e7dbeb..69c288c8c737 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -264,7 +264,13 @@ static bool spi_imx_can_dma(struct spi_controller *controller, struct spi_device
 	if (!controller->dma_rx)
 		return false;
 
-	if (spi_imx->target_mode)
+	/*
+	 * Due to Freescale errata ERR003775 "eCSPI: Burst completion by Chip
+	 * Select (SS) signal in Slave mode is not functional" burst size must
+	 * be set exactly to the size of the transfer. This limit SPI transaction
+	 * with maximum 2^12 bits.
+	 */
+	if (transfer->len > MX53_MAX_TRANSFER_BYTES && spi_imx->target_mode)
 		return false;
 
 	if (transfer->len < spi_imx->devtype_data->fifo_size)
@@ -1763,23 +1769,51 @@ static int spi_imx_dma_submit(struct spi_imx_data *spi_imx,
 
 	transfer_timeout = spi_imx_calculate_timeout(spi_imx, transfer->len);
 
-	/* Wait SDMA to finish the data transfer.*/
-	time_left = wait_for_completion_timeout(&spi_imx->dma_tx_completion,
-						transfer_timeout);
-	if (!time_left) {
-		dev_err(spi_imx->dev, "I/O Error in DMA TX\n");
-		dmaengine_terminate_all(controller->dma_tx);
-		dmaengine_terminate_all(controller->dma_rx);
-		return -ETIMEDOUT;
-	}
+	if (!spi_imx->target_mode) {
+		/* Wait SDMA to finish the data transfer.*/
+		time_left = wait_for_completion_timeout(&spi_imx->dma_tx_completion,
+							transfer_timeout);
+		if (!time_left) {
+			dev_err(spi_imx->dev, "I/O Error in DMA TX\n");
+			dmaengine_terminate_all(controller->dma_tx);
+			dmaengine_terminate_all(controller->dma_rx);
+			return -ETIMEDOUT;
+		}
 
-	time_left = wait_for_completion_timeout(&spi_imx->dma_rx_completion,
-						transfer_timeout);
-	if (!time_left) {
-		dev_err(&controller->dev, "I/O Error in DMA RX\n");
-		spi_imx->devtype_data->reset(spi_imx);
-		dmaengine_terminate_all(controller->dma_rx);
-		return -ETIMEDOUT;
+		time_left = wait_for_completion_timeout(&spi_imx->dma_rx_completion,
+							transfer_timeout);
+		if (!time_left) {
+			dev_err(&controller->dev, "I/O Error in DMA RX\n");
+			spi_imx->devtype_data->reset(spi_imx);
+			dmaengine_terminate_all(controller->dma_rx);
+			return -ETIMEDOUT;
+		}
+	} else {
+		spi_imx->target_aborted = false;
+
+		if (wait_for_completion_interruptible(&spi_imx->dma_tx_completion) ||
+		    READ_ONCE(spi_imx->target_aborted)) {
+			dev_dbg(spi_imx->dev, "I/O Error in DMA TX interrupted\n");
+			dmaengine_terminate_all(controller->dma_tx);
+			dmaengine_terminate_all(controller->dma_rx);
+			return -EINTR;
+		}
+
+		if (wait_for_completion_interruptible(&spi_imx->dma_rx_completion) ||
+		    READ_ONCE(spi_imx->target_aborted)) {
+			dev_dbg(spi_imx->dev, "I/O Error in DMA RX interrupted\n");
+			dmaengine_terminate_all(controller->dma_rx);
+			return -EINTR;
+		}
+
+		/*
+		 * ECSPI has a HW issue when works in Target mode, after 64 words
+		 * writtern to TXFIFO, even TXFIFO becomes empty, ECSPI_TXDATA keeps
+		 * shift out the last word data, so we have to disable ECSPI when in
+		 * target mode after the transfer completes.
+		 */
+		if (spi_imx->devtype_data->disable)
+			spi_imx->devtype_data->disable(spi_imx);
 	}
 
 	return 0;
@@ -1902,7 +1936,7 @@ static int spi_imx_dma_package_transfer(struct spi_imx_data *spi_imx,
 static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
 				struct spi_transfer *transfer)
 {
-	bool word_delay = transfer->word_delay.value != 0;
+	bool word_delay = transfer->word_delay.value != 0 && !spi_imx->target_mode;
 	int ret;
 	int i;
 
@@ -2108,7 +2142,7 @@ static int spi_imx_transfer_one(struct spi_controller *controller,
 	while (spi_imx->devtype_data->rx_available(spi_imx))
 		readl(spi_imx->base + MXC_CSPIRXDATA);
 
-	if (spi_imx->target_mode)
+	if (spi_imx->target_mode && !spi_imx->usedma)
 		return spi_imx_pio_transfer_target(spi, transfer);
 
 	/*
@@ -2120,7 +2154,10 @@ static int spi_imx_transfer_one(struct spi_controller *controller,
 		ret = spi_imx_dma_transfer(spi_imx, transfer);
 		if (transfer->error & SPI_TRANS_FAIL_NO_START) {
 			spi_imx->usedma = false;
-			return spi_imx_pio_transfer(spi, transfer);
+			if (spi_imx->target_mode)
+				return spi_imx_pio_transfer_target(spi, transfer);
+			else
+				return spi_imx_pio_transfer(spi, transfer);
 		}
 		return ret;
 	}
-- 
2.34.1



From songwei.chai at oss.qualcomm.com  Wed Dec  3 01:00:48 2025
From: songwei.chai at oss.qualcomm.com (Songwei Chai)
Date: Wed,  3 Dec 2025 01:00:48 -0800
Subject: [PATCH v8 0/7] Provides support for Trigger Generation Unit
Message-ID: <20251203090055.2432719-1-songwei.chai@oss.qualcomm.com>

We propose creating a new qcom directory under drivers/hwtracing
to host this TGU driver, as well as additional Qualcomm-specific
hwtracing drivers that we plan to submit in the coming months.
This structure will help organize vendor-specific implementations
and facilitate future development and maintenance.

Feedback from the community on this proposal is highly appreciated.

- Why we are proposing this:

TGU has the ability to monitor signal conditions and trigger debug-related
actions, serving as a programmable hardware component that enhances system
trace and debug capabilities. Placing it under drivers/hwtracing aligns with
its function as a trace generation utility.

We previously attempted to push this driver to drivers/hwtracing/coresight,
but did not receive support from the maintainers of the CoreSight subsystem.
The reason provided was: ?This component is primarily a part of the
Qualcomm proprietary QPMDA subsystem, and is capable of operating
independently from the CoreSight hardware trace generation system.?

Chat history : https://lore.kernel.org/all/CAJ9a7ViKxHThyZfFFDV_FkNRimk4uo1NrMtQ-kcaj1qO4ZcGnA at mail.gmail.com/

Given this, we have been considering whether it would be appropriate
to create a dedicated drivers/hwtracing/qcom directory for
Qualcomm-related hwtracing drivers. This would follow the precedent set
by Intel, which maintains its own directory at drivers/hwtracing/intel_th.
We believe this structure would significantly facilitate
future submissions of related Qualcomm drivers.

- Maintenance of drivers/hwtracing/qcom:

Bjorn, who maintains linux-arm-msm, will be the maintainer of this
directory ? we?ve discussed this with him and he?s aware that his task
list may grow accordingly. Additionally, Qualcomm engineers familiar with
the debug hardware ? such as [Tingwei Zhang, Jinlong Mao, Songwei Chai],
will be available to review incoming patches and support ongoing
development.

- Detail for TGU:

This component can be utilized to sense a plurality of signals and
create a trigger into the CTI or generate interrupts to processors
once the input signal meets the conditions. We can treat the TGU?s
workflow as a flowsheet, it has some ?steps? regions for customization.
In each step region, we can set the signals that we want with priority
in priority_group, set the conditions in each step via condition_decode,
and set the resultant action by condition_select. Meanwhile,
some TGUs (not all) also provide timer/counter functionality.
Based on the characteristics described above, we consider the TGU as a
helper in the CoreSight subsystem. Its master device is the TPDM, which
can transmit signals from other subsystems, and we reuse the existing
ports mechanism to link the TPDM to the connected TGU.

Here is a detailed example to explain how to use the TGU:

In this example, the TGU is configured to use 2 conditions, 2 steps, and
the timer. The goal is to look for one of two patterns which are generated
from TPDM, giving priority to one, and then generate a trigger once the
timer reaches a certain value. In other words, two conditions are used
for the first step to look for the two patterns, where the one with the
highest priority is used in the first condition. Then, in the second step,
the timer is enabled and set to be compared to the given value at each
clock cycle. These steps are better shown below.
    
              |-----------------|
              |                 |
              |       TPDM      |
              |                 |
              |-----------------|
                       |
                       |
    --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ------
    |                  |                                                 |
    |                  |                          |--------------------| |
    |    |---- --->    |                          |  Go to next steps  | |
    |    |             |                |--- ---> |  Enable timer      | |
    |    |             v                |         |                    | |
    |    |    |-----------------|       |         |--------------------| |
    |    |    |                 |  Yes  |                    |           |
    |    |    |   inputs==0xB   | ----->|                    | <-------- |
    |    |    |                 |       |                    |      No | |
    | No |    |-----------------|       |                    v         | |
    |    |             |                |          |-----------------| | |
    |    |             |                |          |                 | | |
    |    |             |                |          |      timer>=3   |-- |
    |    |             v                |          |                 |   |
    |    |    |-----------------|       |          |-----------------|   |
    |    |    |                 |  Yes  |                    |           |
    |    |--- |   inputs==0xA   | ----->|                    | Yes       |
    |         |                 |                            |           |
    |         |-----------------|                            v           |
    |                                              |-----------------|   |
    |                                              |                 |   |
    |                                              |      Trigger    |   |
    |                                              |                 |   |
    |                                              |-----------------|   |
    |  TGU                                                   |           |
    |--- --- --- --- --- --- --- --- --- --- --- --- --- --- |--- --- -- |
                                                             |
                                                             v
                                                    |-----------------|
                                                    |The controllers  |
                                                    |which will use   |
                                                    |triggers further |
                                                    |-----------------|

steps:
    1. Reset TGU /*it will disable tgu and reset dataset*/
    - echo 1 > /sys/bus/coresight/devices/<tgu-name>/reset_tgu

    2. Set the pattern match for priority0 to 0xA = 0b1010 and for
       priority 1 to 0xB = 0b1011.
    - echo 0x11113232 > /sys/bus/coresight/devices/<tgu-name>/step0_priority0/reg0
    - echo 0x11113233 > /sys/bus/coresight/devices/<tgu-name>/step0_priority1/reg0

    Note:
        Bit distribution diagram for each priority register
    |-------------------------------------------------------------------|
    |   Bits          |       Field Nam   |    Description              |
    |-------------------------------------------------------------------|
    |                 |                   | 00 = bypass for OR output   |
    |     29:28       |   SEL_BIT7_TYPE2  | 01 = bypass for AND output  |
    |                 |                   | 10 = sense input '0' is true|
    |                 |                   | 11 = sense input '1' is true|
    |-------------------------------------------------------------------|
    |                 |                   | 00 = bypass for OR output   |
    |     25:24       |   SEL_BIT6_TYPE2  | 01 = bypass for AND output  |
    |                 |                   | 10 = sense input '0' is true|
    |                 |                   | 11 = sense input '1' is true|
    |-------------------------------------------------------------------|
    |                 |                   | 00 = bypass for OR output   |
    |     21:20       |   SEL_BIT5_TYPE2  | 01 = bypass for AND output  |
    |                 |                   | 10 = sense input '0' is true|
    |                 |                   | 11 = sense input '1' is true|
    |-------------------------------------------------------------------|
    |                 |                   | 00 = bypass for OR output   |
    |     17:16       |   SEL_BIT4_TYPE2  | 01 = bypass for AND output  |
    |                 |                   | 10 = sense input '0' is true|
    |                 |                   | 11 = sense input '1' is true|
    |-------------------------------------------------------------------|
    |                 |                   | 00 = bypass for OR output   |
    |     13:12       |   SEL_BIT3_TYPE2  | 01 = bypass for AND output  |
    |                 |                   | 10 = sense input '0' is true|
    |                 |                   | 11 = sense input '1' is true|
    |-------------------------------------------------------------------|
    |                 |                   | 00 = bypass for OR output   |
    |      9:8        |   SEL_BIT2_TYPE2  | 01 = bypass for AND output  |
    |                 |                   | 10 = sense input '0' is true|
    |                 |                   | 11 = sense input '1' is true|
    |-------------------------------------------------------------------|
    |                 |                   | 00 = bypass for OR output   |
    |      5:4        |  SEL_BIT1_TYPE2   | 01 = bypass for AND output  |
    |                 |                   | 10 = sense input '0' is true|
    |                 |                   | 11 = sense input '1' is true|
    |-------------------------------------------------------------------|
    |                 |                   | 00 = bypass for OR output   |
    |      1:0        |  SEL_BIT0_TYPE2   | 01 = bypass for AND output  |
    |                 |                   | 10 = sense input '0' is true|
    |                 |                   | 11 = sense input '1' is true|
    |-------------------------------------------------------------------|
    These bits are used to identify the signals we want to sense, with
    a maximum signal number of 140. For example, to sense the signal
    0xA (binary 1010), we set the value of bits 0 to 13 to 3232, which
    represents 1010. The remaining bits are set to 1, as we want to use
    AND gate to summarize all the signals we want to sense here. For
    rising or falling edge detection of any input to the priority, set
    the remaining bits to 0 to use an OR gate.

    3. look for the pattern for priority_i i=0,1.
    - echo 0x3 > /sys/bus/coresight/devices/<tgu-name>/step0_condition_decode/reg0
    - echo 0x30 > /sys/bus/coresight/devices/<tgu-name>/step0_condition_decode/reg1

    |-------------------------------------------------------------------------------|
    |   Bits          |    Field Nam        |            Description                |
    |-------------------------------------------------------------------------------|
    |                 |                     |For each decoded condition, this       |
    |      24         |       NOT           |inverts the output. If the condition   |
    |                 |                     |decodes to true, and the NOT field     |
    |                 |                     |is '1', then the output is NOT true.   |
    |-------------------------------------------------------------------------------|
    |                 |                     |When '1' the output from the associated|
    |      21         |  BC0_COMP_ACTIVE    |comparator will be actively included in|
    |                 |                     |the decoding of this particular        |
    |                 |                     |condition.                             |
    |-------------------------------------------------------------------------------|
    |                 |                     |When '1' the output from the associated|
    |                 |                     |comparator will need to be 1 to affect |
    |      20         |   BC0_COMP_HIGH     |the decoding of this condition.        |
    |                 |                     |Conversely, a '0' here requires a '0'  |
    |                 |                     |from the comparator                    |
    |-------------------------------------------------------------------------------|
    |                 |                     |When '1' the output from the associated|
    |      17         |                     |comparator will be actively included in|
    |                 |  TC0_COMP_ACTIVE    |the decoding of this particular        |
    |                 |                     |condition.                             |
    |-------------------------------------------------------------------------------|
    |                 |                     |When '1' the output from the associated|
    |                 |                     |comparator will need to be 1 to affect |
    |      16         |  TC0_COMP_HIGH      |the decoding of this particular        |
    |                 |                     |condition.Conversely, a 0 here         |
    |                 |                     |requires a '0' from the comparator     |
    |-------------------------------------------------------------------------------|
    |                 |                     |When '1' the output from Priority_n    |
    |                 |                     |OR logic will be actively              |
    |     4n+3        | Priority_n_OR_ACTIVE|included in the decoding of            |
    |                 |    (n=0,1,2,3)      |this particular condition.             |
    |                 |                     |                                       |
    |-------------------------------------------------------------------------------|
    |                 |                     |When '1' the output from Priority_n    |
    |                 |                     |will need to be '1' to affect the      |
    |     4n+2        |  Priority_n_OR_HIGH |decoding of this particular            |
    |                 |    (n=0,1,2,3)      |condition. Conversely, a '0' here      |
    |                 |                     |requires a '0' from Priority_n OR logic|
    |-------------------------------------------------------------------------------|
    |                 |                     |When '1' the output from Priority_n    |
    |                 |                     |AND logic will be actively             |
    |     4n+1        |Priority_n_AND_ACTIVE|included in the decoding of this       |
    |                 |  (n=0,1,2,3)        |particular condition.                  |
    |                 |                     |                                       |
    |-------------------------------------------------------------------------------|
    |                 |                     |When '1' the output from Priority_n    |
    |                 |                     |AND logic will need to be '1' to       |
    |      4n         | Priority_n_AND_HIGH |affect the decoding of this            |
    |                 |   (n=0,1,2,3)       |particular condition. Conversely,      |
    |                 |                     |a '0' here requires a '0' from         |
    |                 |                     |Priority_n AND logic.                  |
    |-------------------------------------------------------------------------------|
    Since we use `priority_0` and `priority_1` with an AND output in step 2, we set `0x3`
    and `0x30` here to activate them.

    4. Set NEXT_STEP = 1 and TC0_ENABLE = 1 so that when the conditions
       are met then the next step will be step 1 and the timer will be enabled.
    - echo 0x20008 > /sys/bus/coresight/devices/<tgu-name>/step0_condition_select/reg0
    - echo 0x20008 > /sys/bus/coresight/devices/<tgu-name>/step0_condition_select/reg1

    |-----------------------------------------------------------------------------|
    |   Bits          |       Field Nam   |            Description                |
    |-----------------------------------------------------------------------------|
    |                 |                   |This field defines the next step the   |
    |    18:17        |     NEXT_STEP     |TGU will 'goto' for the associated     |
    |                 |                   |Condition and Step.                    |
    |-----------------------------------------------------------------------------|
    |                 |                   |For each possible output trigger       |
    |    13           |     TRIGGER       |available, set a '1' if you want       |
    |                 |                   |the trigger to go active for the       |
    |                 |                   |associated condition and Step.         |
    |-----------------------------------------------------------------------------|
    |                 |                   |This will cause BC0 to increment if the|
    |    9            |     BC0_INC       |associated Condition is decoded for    |
    |                 |                   |this step.                             |
    |-----------------------------------------------------------------------------|
    |                 |                   |This will cause BC0 to decrement if the|
    |    8            |     BC0_DEC       |associated Condition is decoded for    |
    |                 |                   |this step.                             |
    |-----------------------------------------------------------------------------|
    |                 |                   |This will clear BC0 count value to 0 if|
    |    7            |     BC0_CLEAR     |the associated Condition is decoded    |
    |                 |                   |for this step.                         |
    |-----------------------------------------------------------------------------|
    |                 |                   |This will cause TC0 to increment until |
    |    3            |     TC0_ENABLE    |paused or cleared if the associated    |
    |                 |                   |Condition is decoded for this step.    |
    |-----------------------------------------------------------------------------|
    |                 |                   |This will cause TC0 to pause until     |
    |    2            |     TC0_PAUSE     |enabled if the associated Condition    |
    |                 |                   |is decoded for this step.              |
    |-----------------------------------------------------------------------------|
    |                 |                   |This will clear TC0 count value to 0   |
    |    1            |     TC0_CLEAR     |if the associated Condition is         |
    |                 |                   |decoded for this step.                 |
    |-----------------------------------------------------------------------------|
    |                 |                   |This will set the done signal to the   |
    |    0            |     DONE          |TGU FSM if the associated Condition    |
    |                 |                   |is decoded for this step.              |
    |-----------------------------------------------------------------------------|
    Based on the distribution diagram, we set `0x20008` for `priority0` and `priority1` to
    achieve "jump to step 1 and enable TC0" once the signal is sensed.

    5. activate the timer comparison for this step.
    -  echo 0x30000  > /sys/bus/coresight/devices/<tgu-name>/step1_condition_decode/reg0

    |-------------------------------------------------------------------------------|
    |                 |                     |When '1' the output from the associated|
    |      17         |                     |comparator will be actively included in|
    |                 |  TC0_COMP_ACTIVE    |the decoding of this particular        |
    |                 |                     |condition.                             |
    |-------------------------------------------------------------------------------|
    |                 |                     |When '1' the output from the associated|
    |                 |                     |comparator will need to be 1 to affect |
    |      16         |  TC0_COMP_HIGH      |the decoding of this particular        |
    |                 |                     |condition.Conversely, a 0 here         |
    |                 |                     |requires a '0' from the comparator     |
    |-------------------------------------------------------------------------------|
    Accroding to the decode distribution diagram , we give 0x30000 here to set 16th&17th bit
    to enable timer comparison.

    6. Set the NEXT_STEP = 0 and TC0_PAUSE = 1 and TC0_CLEAR = 1 once the timer
       has reached the given value.
    - echo 0x6 > /sys/bus/coresight/devices/<tgu-name>/step1_condition_select/reg0

    7. Enable Trigger 0 for TGU when the condition 0 is met in step1,
       i.e. when the timer reaches 3.
    - echo 0x2000 > /sys/bus/coresight/devices/<tgu-name>/step1_condition_select/default

    Note:
        1. 'default' register allows for establishing the resultant action for
        the default condition

        2. Trigger:For each possible output trigger available from
        the Design document, there are three triggers: interrupts, CTI,
        and Cross-TGU mapping.All three triggers can occur, but
        the choice of which trigger to use depends on the user's
        needs.

    8. Compare the timer to 3 in step 1.
    - echo 0x3 > /sys/bus/coresight/devices/<tgu-name>/step1_timer/reg0

    9. enale tgu
    - echo 1 > /sys/bus/coresight/devices/<tgu-name>/enable_tgu
---
Link to V7: https://lore.kernel.org/all/20251104064043.88972-1-songwei.chai at oss.qualcomm.com/

Changes in V8:
- Add "select" section in bindings.
- Update publish date in "sysfs-bus-coresight-devices-tgu".
---
Link to V6: https://lore.kernel.org/all/20250709104114.22240-1-songchai at qti.qualcomm.com/

Changes in V7:
- Move the TGU code location from 'drivers/hwtracing/coresight/' to 'drivers/hwtracing/qcom/'.
- Rename the spinlock used in the code from 'spinlock' to 'lock'.
- Perform the 'calculate_array_location' separately, instead of doing it within the function.
- Update the sender email address.
---
Link to V5: https://lore.kernel.org/all/20250529081949.26493-1-quic_songchai at quicinc.com/

Changes in V6:
- Replace spinlock with guard(spinlock) in tgu_enable.
- Remove redundant blank line.
- Update publish date and contact member's name in "sysfs-bus-coresight-devices-tgu".
---
Link to V4: https://patchwork.kernel.org/project/linux-arm-msm/cover/20250423101054.954066-1-quic_songchai at quicinc.com/

Changes in V5:
- Update publish date and kernel_version in "sysfs-bus-coresight-devices-tgu"
---
Link to V3: https://lore.kernel.org/all/20250227092640.2666894-1-quic_songchai at quicinc.com/

Changes in V4:
- Add changlog in coverletter.
- Correct 'year' in Copyright in patch1.
- Correct port mechansim description in patch1.
- Remove 'tgu-steps','tgu-regs','tgu-conditions','tgu-timer-counters' from dt-binding
and set them through reading DEVID register as per Mike's suggestion.
- Modify tgu_disable func to make it have single return point in patch2 as per
Mike's suggestion.
- Use sysfs_emit in enable_tgu_show func in ptach2.
- Remove redundant judgement in enable_tgu_store in patch2.
- Correct typo in description in patch3.
- Set default ret as SYSFS_GROUP_INVISIBLE, and returnret at end in pacth3 as
per Mike's suggestion.
- Remove tgu_dataset_ro definition in patch3
- Use #define constants with explanations of what they are rather than
arbitrary magic numbers in patch3 and patch4.
- Check -EINVAL before using 'calculate_array_location()' in array in patch4.
- Add 'default' in 'tgu_dataset_show''s switch part in patch4.
- Document the value needed to initiate the reset in pacth7.
- Check "value" in 'reset_tgu_store' and bail out with an error code if 0 in patch7.
- Remove dev_dbg in 'reset_tgu_store' in patch7.
---
Link to V2: https://lore.kernel.org/all/20241010073917.16023-1-quic_songchai at quicinc.com/

Changes in V3:
- Correct typo and format in dt-binding in patch1
- Rebase to the latest kernel version
---
Link to V1: https://lore.kernel.org/all/20240830092311.14400-1-quic_songchai at quicinc.com/

Changes in V2:
 - Use real name instead of login name,
 - Correct typo and format in dt-binding and code.
 - Bring order in tgu_prob(declarations with and without assignments) as per
Krzysztof's suggestion.
 - Add module device table in patch2.
 - Set const for tgu_common_grp and tgu_ids in patch2.
 - Initialize 'data' in tgu_ids to fix the warning in pacth2.
---

Songwei Chai (7):
  dt-bindings: arm: Add support for Qualcomm TGU trace
  qcom-tgu: Add TGU driver
  qcom-tgu: Add signal priority support
  qcom-tgu: Add TGU decode support
  qcom-tgu: Add support to configure next action
  qcom-tgu: Add timer/counter functionality for TGU
  qcom-tgu: Add reset node to initialize

 .../testing/sysfs-bus-coresight-devices-tgu   |  51 ++
 .../devicetree/bindings/arm/qcom,tgu.yaml     |  92 +++
 drivers/Makefile                              |   1 +
 drivers/hwtracing/Kconfig                     |   2 +
 drivers/hwtracing/qcom/Kconfig                |  18 +
 drivers/hwtracing/qcom/Makefile               |   3 +
 drivers/hwtracing/qcom/tgu.c                  | 737 ++++++++++++++++++
 drivers/hwtracing/qcom/tgu.h                  | 252 ++++++
 8 files changed, 1156 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu
 create mode 100644 Documentation/devicetree/bindings/arm/qcom,tgu.yaml
 create mode 100644 drivers/hwtracing/qcom/Kconfig
 create mode 100644 drivers/hwtracing/qcom/Makefile
 create mode 100644 drivers/hwtracing/qcom/tgu.c
 create mode 100644 drivers/hwtracing/qcom/tgu.h

-- 
2.34.1



From songwei.chai at oss.qualcomm.com  Wed Dec  3 01:00:49 2025
From: songwei.chai at oss.qualcomm.com (Songwei Chai)
Date: Wed,  3 Dec 2025 01:00:49 -0800
Subject: [PATCH v8 1/7] dt-bindings: arm: Add support for Qualcomm TGU trace
In-Reply-To: <20251203090055.2432719-1-songwei.chai@oss.qualcomm.com>
References: <20251203090055.2432719-1-songwei.chai@oss.qualcomm.com>
Message-ID: <20251203090055.2432719-2-songwei.chai@oss.qualcomm.com>

The Trigger Generation Unit (TGU) is designed to detect patterns or
sequences within a specific region of the System on Chip (SoC). Once
configured and activated, it monitors sense inputs and can detect a
pre-programmed state or sequence across clock cycles, subsequently
producing a trigger.

   TGU configuration space
        offset table
 x-------------------------x
 |                         |
 |                         |
 |                         |                           Step configuration
 |                         |                             space layout
 |   coresight management  |                           x-------------x
 |        registers        |                     |---> |             |
 |                         |                     |     |  reserve    |
 |                         |                     |     |             |
 |-------------------------|                     |     |-------------|
 |                         |                     |     | priority[3] |
 |         step[7]         |<--                  |     |-------------|
 |-------------------------|   |                 |     | priority[2] |
 |                         |   |                 |     |-------------|
 |           ...           |   |Steps region     |     | priority[1] |
 |                         |   |                 |     |-------------|
 |-------------------------|   |                 |     | priority[0] |
 |                         |<--                  |     |-------------|
 |         step[0]         |-------------------->      |             |
 |-------------------------|                           |  condition  |
 |                         |                           |             |
 |     control and status  |                           x-------------x
 |           space         |                           |             |
 x-------------------------x                           |Timer/Counter|
                                                       |             |
						       x-------------x
TGU Configuration in Hardware

The TGU provides a step region for user configuration, similar
to a flow chart. Each step region consists of three register clusters:

1.Priority Region: Sets the required signals with priority.
2.Condition Region: Defines specific requirements (e.g., signal A
reaches three times) and the subsequent action once the requirement is
met.
3.Timer/Counter (Optional): Provides timing or counting functionality.

Add a new tgu.yaml file to describe the bindings required to
define the TGU in the device trees.

Signed-off-by: Songwei Chai <songwei.chai at oss.qualcomm.com>
---
 .../devicetree/bindings/arm/qcom,tgu.yaml     | 92 +++++++++++++++++++
 1 file changed, 92 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/qcom,tgu.yaml

diff --git a/Documentation/devicetree/bindings/arm/qcom,tgu.yaml b/Documentation/devicetree/bindings/arm/qcom,tgu.yaml
new file mode 100644
index 000000000000..5b6a58ebe691
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/qcom,tgu.yaml
@@ -0,0 +1,92 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+# Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/qcom,tgu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Trigger Generation Unit - TGU
+
+description: |
+  The Trigger Generation Unit (TGU) is a Data Engine which can be utilized
+  to sense a plurality of signals and create a trigger into the CTI or
+  generate interrupts to processors. The TGU is like the trigger circuit
+  of a Logic Analyzer. The corresponding trigger logic can be realized by
+  configuring the conditions for each step after sensing the signal.
+  Once setup and enabled, it will observe sense inputs and based upon
+  the activity of those inputs, even over clock cycles, may detect a
+  preprogrammed state/sequence and then produce a trigger or interrupt.
+
+  The primary use case of the TGU is to detect patterns or sequences on a
+  given set of signals within some region to identify the issue in time
+  once there is abnormal behavior in the subsystem.
+
+maintainers:
+  - Mao Jinlong <jinlong.mao at oss.qualcomm.com>
+  - Songwei Chai <songwei.chai at oss.qualcomm.com>
+
+# Need a custom select here or 'arm,primecell' will match on lots of nodes
+select:
+  properties:
+    compatible:
+      contains:
+        enum:
+          - qcom,tgu
+  required:
+    - compatible
+
+properties:
+  compatible:
+    items:
+      - const: qcom,tgu
+      - const: arm,primecell
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: apb_pclk
+
+  in-ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+    additionalProperties: false
+
+    properties:
+      port:
+        description:
+          The port mechanism here ensures the relationship between TGU and
+          TPDM, as TPDM is one of the inputs for TGU. It will allow TGU to
+          function as TPDM's helper and enable TGU when the connected
+          TPDM is enabled.
+        $ref: /schemas/graph.yaml#/properties/port
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    tgu at 10b0e000 {
+        compatible = "qcom,tgu", "arm,primecell";
+        reg = <0x10b0e000 0x1000>;
+
+        clocks = <&aoss_qmp>;
+        clock-names = "apb_pclk";
+
+        in-ports {
+            port {
+                tgu_in_tpdm_swao: endpoint{
+                    remote-endpoint = <&tpdm_swao_out_tgu>;
+                };
+            };
+        };
+    };
+...
-- 
2.34.1



From songwei.chai at oss.qualcomm.com  Wed Dec  3 01:00:50 2025
From: songwei.chai at oss.qualcomm.com (Songwei Chai)
Date: Wed,  3 Dec 2025 01:00:50 -0800
Subject: [PATCH v8 2/7] qcom-tgu: Add TGU driver
In-Reply-To: <20251203090055.2432719-1-songwei.chai@oss.qualcomm.com>
References: <20251203090055.2432719-1-songwei.chai@oss.qualcomm.com>
Message-ID: <20251203090055.2432719-3-songwei.chai@oss.qualcomm.com>

Add driver to support device TGU (Trigger Generation Unit).
TGU is a Data Engine which can be utilized to sense a plurality of
signals and create a trigger into the CTI or generate interrupts to
processors. Add probe/enable/disable functions for tgu.

Signed-off-by: Songwei Chai <songwei.chai at oss.qualcomm.com>
---
 .../testing/sysfs-bus-coresight-devices-tgu   |   9 +
 drivers/Makefile                              |   1 +
 drivers/hwtracing/Kconfig                     |   2 +
 drivers/hwtracing/qcom/Kconfig                |  18 ++
 drivers/hwtracing/qcom/Makefile               |   3 +
 drivers/hwtracing/qcom/tgu.c                  | 210 ++++++++++++++++++
 drivers/hwtracing/qcom/tgu.h                  |  33 +++
 7 files changed, 276 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu
 create mode 100644 drivers/hwtracing/qcom/Kconfig
 create mode 100644 drivers/hwtracing/qcom/Makefile
 create mode 100644 drivers/hwtracing/qcom/tgu.c
 create mode 100644 drivers/hwtracing/qcom/tgu.h

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu
new file mode 100644
index 000000000000..ccc2bc92edcd
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu
@@ -0,0 +1,9 @@
+What:		/sys/bus/coresight/devices/<tgu-name>/enable_tgu
+Date:		December 2025
+KernelVersion	6.18
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Songwei Chai <songwei.chai at oss.qualcomm.com>
+Description:
+		(RW) Set/Get the enable/disable status of TGU
+		Accepts only one of the 2 values -  0 or 1.
+		0 : disable TGU.
+		1 : enable TGU.
diff --git a/drivers/Makefile b/drivers/Makefile
index 20eb17596b89..46cd62aabfe8 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -176,6 +176,7 @@ obj-$(CONFIG_RAS)		+= ras/
 obj-$(CONFIG_USB4)		+= thunderbolt/
 obj-$(CONFIG_CORESIGHT)		+= hwtracing/coresight/
 obj-y				+= hwtracing/intel_th/
+obj-y				+= hwtracing/qcom/
 obj-$(CONFIG_STM)		+= hwtracing/stm/
 obj-$(CONFIG_HISI_PTT)		+= hwtracing/ptt/
 obj-y				+= android/
diff --git a/drivers/hwtracing/Kconfig b/drivers/hwtracing/Kconfig
index 911ee977103c..8a640218eed8 100644
--- a/drivers/hwtracing/Kconfig
+++ b/drivers/hwtracing/Kconfig
@@ -7,4 +7,6 @@ source "drivers/hwtracing/intel_th/Kconfig"
 
 source "drivers/hwtracing/ptt/Kconfig"
 
+source "drivers/hwtracing/qcom/Kconfig"
+
 endmenu
diff --git a/drivers/hwtracing/qcom/Kconfig b/drivers/hwtracing/qcom/Kconfig
new file mode 100644
index 000000000000..d6f6d4b0f28e
--- /dev/null
+++ b/drivers/hwtracing/qcom/Kconfig
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# QCOM specific hwtracing drivers
+#
+menu "Qualcomm specific hwtracing drivers"
+
+config QCOM_TGU
+	tristate "QCOM Trigger Generation Unit driver"
+	help
+	  This driver provides support for Trigger Generation Unit that is
+	  used to detect patterns or sequences on a given set of signals.
+	  TGU is used to monitor a particular bus within a given region to
+	  detect illegal transaction sequences or slave responses. It is also
+	  used to monitor a data stream to detect protocol violations and to
+	  provide a trigger point for centering data around a specific event
+	  within the trace data buffer.
+
+endmenu
diff --git a/drivers/hwtracing/qcom/Makefile b/drivers/hwtracing/qcom/Makefile
new file mode 100644
index 000000000000..5a0a868c1ea0
--- /dev/null
+++ b/drivers/hwtracing/qcom/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_QCOM_TGU) += tgu.o
diff --git a/drivers/hwtracing/qcom/tgu.c b/drivers/hwtracing/qcom/tgu.c
new file mode 100644
index 000000000000..368bb196b984
--- /dev/null
+++ b/drivers/hwtracing/qcom/tgu.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/amba/bus.h>
+#include <linux/coresight.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#include "../coresight/coresight-priv.h"
+#include "tgu.h"
+
+DEFINE_CORESIGHT_DEVLIST(tgu_devs, "tgu");
+
+static void tgu_write_all_hw_regs(struct tgu_drvdata *drvdata)
+{
+	CS_UNLOCK(drvdata->base);
+	/* Enable TGU to program the triggers */
+	writel(1, drvdata->base + TGU_CONTROL);
+	CS_LOCK(drvdata->base);
+}
+
+static int tgu_enable(struct coresight_device *csdev, enum cs_mode mode,
+		      void *data)
+{
+	struct tgu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	guard(spinlock)(&drvdata->lock);
+	if (drvdata->enable)
+		return -EBUSY;
+
+	tgu_write_all_hw_regs(drvdata);
+	drvdata->enable = true;
+
+	return 0;
+}
+
+static int tgu_disable(struct coresight_device *csdev, void *data)
+{
+	struct tgu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	spin_lock(&drvdata->lock);
+	if (drvdata->enable) {
+		CS_UNLOCK(drvdata->base);
+		writel(0, drvdata->base + TGU_CONTROL);
+		CS_LOCK(drvdata->base);
+
+		drvdata->enable = false;
+	}
+	spin_unlock(&drvdata->lock);
+	return 0;
+}
+
+static ssize_t enable_tgu_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	bool enabled;
+	struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	spin_lock(&drvdata->lock);
+	enabled = drvdata->enable;
+	spin_unlock(&drvdata->lock);
+
+	return sysfs_emit(buf, "%d\n", enabled);
+}
+
+/* enable_tgu_store - Configure Trace and Gating Unit (TGU) triggers. */
+static ssize_t enable_tgu_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf,
+				size_t size)
+{
+	int ret = 0;
+	unsigned long val;
+	struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	ret = kstrtoul(buf, 0, &val);
+	if (ret)
+		return ret;
+
+	if (val) {
+		ret = pm_runtime_resume_and_get(dev->parent);
+		if (ret)
+			return ret;
+		ret = tgu_enable(drvdata->csdev, CS_MODE_SYSFS, NULL);
+		if (ret)
+			pm_runtime_put(dev->parent);
+	} else {
+		ret = tgu_disable(drvdata->csdev, NULL);
+		pm_runtime_put(dev->parent);
+	}
+
+	if (ret)
+		return ret;
+	return size;
+}
+static DEVICE_ATTR_RW(enable_tgu);
+
+static const struct coresight_ops_helper tgu_helper_ops = {
+	.enable = tgu_enable,
+	.disable = tgu_disable,
+};
+
+static const struct coresight_ops tgu_ops = {
+	.helper_ops = &tgu_helper_ops,
+};
+
+static struct attribute *tgu_common_attrs[] = {
+	&dev_attr_enable_tgu.attr,
+	NULL,
+};
+
+static const struct attribute_group tgu_common_grp = {
+	.attrs = tgu_common_attrs,
+	NULL,
+};
+
+static const struct attribute_group *tgu_attr_groups[] = {
+	&tgu_common_grp,
+	NULL,
+};
+
+static int tgu_probe(struct amba_device *adev, const struct amba_id *id)
+{
+	int ret = 0;
+	struct device *dev = &adev->dev;
+	struct coresight_desc desc = { 0 };
+	struct coresight_platform_data *pdata;
+	struct tgu_drvdata *drvdata;
+
+	desc.name = coresight_alloc_device_name(&tgu_devs, dev);
+	if (!desc.name)
+		return -ENOMEM;
+
+	pdata = coresight_get_platform_data(dev);
+	if (IS_ERR(pdata))
+		return PTR_ERR(pdata);
+
+	adev->dev.platform_data = pdata;
+
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+
+	drvdata->dev = &adev->dev;
+	dev_set_drvdata(dev, drvdata);
+
+	drvdata->base = devm_ioremap_resource(dev, &adev->res);
+	if (!drvdata->base)
+		return -ENOMEM;
+
+	spin_lock_init(&drvdata->lock);
+
+	drvdata->enable = false;
+	desc.type = CORESIGHT_DEV_TYPE_HELPER;
+	desc.pdata = adev->dev.platform_data;
+	desc.dev = &adev->dev;
+	desc.ops = &tgu_ops;
+	desc.groups = tgu_attr_groups;
+
+	drvdata->csdev = coresight_register(&desc);
+	if (IS_ERR(drvdata->csdev)) {
+		ret = PTR_ERR(drvdata->csdev);
+		goto err;
+	}
+
+	pm_runtime_put(&adev->dev);
+	return 0;
+err:
+	pm_runtime_put(&adev->dev);
+	return ret;
+}
+
+static void tgu_remove(struct amba_device *adev)
+{
+	struct tgu_drvdata *drvdata = dev_get_drvdata(&adev->dev);
+
+	coresight_unregister(drvdata->csdev);
+}
+
+static const struct amba_id tgu_ids[] = {
+	{
+		.id = 0x000f0e00,
+		.mask = 0x000fffff,
+		.data = "TGU",
+	},
+	{ 0, 0, NULL },
+};
+
+MODULE_DEVICE_TABLE(amba, tgu_ids);
+
+static struct amba_driver tgu_driver = {
+	.drv = {
+		.name = "qcom-tgu",
+		.suppress_bind_attrs = true,
+	},
+	.probe = tgu_probe,
+	.remove = tgu_remove,
+	.id_table = tgu_ids,
+};
+
+module_amba_driver(tgu_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Qualcomm TGU driver");
diff --git a/drivers/hwtracing/qcom/tgu.h b/drivers/hwtracing/qcom/tgu.h
new file mode 100644
index 000000000000..1a55da90f521
--- /dev/null
+++ b/drivers/hwtracing/qcom/tgu.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _QCOM_TGU_H
+#define _QCOM_TGU_H
+
+/* Register addresses */
+#define TGU_CONTROL 0x0000
+
+/**
+ * struct tgu_drvdata - Data structure for a TGU (Trigger Generator Unit)
+ * @base: Memory-mapped base address of the TGU device
+ * @dev: Pointer to the associated device structure
+ * @csdev: Pointer to the associated coresight device
+ * @lock: Spinlock for handling concurrent access
+ * @enable: Flag indicating whether the TGU device is enabled
+ *
+ * This structure defines the data associated with a TGU device,
+ * including its base address, device pointers, clock, spinlock for
+ * synchronization, trigger data pointers, maximum limits for various
+ * trigger-related parameters, and enable status.
+ */
+struct tgu_drvdata {
+	void __iomem *base;
+	struct device *dev;
+	struct coresight_device *csdev;
+	spinlock_t lock;
+	bool enable;
+};
+
+#endif
-- 
2.34.1



From songwei.chai at oss.qualcomm.com  Wed Dec  3 01:00:51 2025
From: songwei.chai at oss.qualcomm.com (Songwei Chai)
Date: Wed,  3 Dec 2025 01:00:51 -0800
Subject: [PATCH v8 3/7] qcom-tgu: Add signal priority support
In-Reply-To: <20251203090055.2432719-1-songwei.chai@oss.qualcomm.com>
References: <20251203090055.2432719-1-songwei.chai@oss.qualcomm.com>
Message-ID: <20251203090055.2432719-4-songwei.chai@oss.qualcomm.com>

Like circuit of a Logic analyzer, in TGU, the requirement could be
configured in each step and the trigger will be created once the
requirements are met. Add priority functionality here to sort the
signals into different priorities. The signal which is wanted could
be configured in each step's priority node, the larger number means
the higher priority and the signal with higher priority will be sensed
more preferentially.

Signed-off-by: Songwei Chai <songwei.chai at oss.qualcomm.com>
---
 .../testing/sysfs-bus-coresight-devices-tgu   |   7 +
 drivers/hwtracing/qcom/tgu.c                  | 155 ++++++++++++++++++
 drivers/hwtracing/qcom/tgu.h                  | 111 +++++++++++++
 3 files changed, 273 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu
index ccc2bc92edcd..eafb0e0dd030 100644
--- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu
@@ -7,3 +7,10 @@ Description:
 		Accepts only one of the 2 values -  0 or 1.
 		0 : disable TGU.
 		1 : enable TGU.
+
+What:		/sys/bus/coresight/devices/<tgu-name>/step[0:7]_priority[0:3]/reg[0:17]
+Date:		December 2025
+KernelVersion	6.18
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Songwei Chai <songwei.chai at oss.qualcomm.com>
+Description:
+		(RW) Set/Get the sensed signal with specific step and priority for TGU.
diff --git a/drivers/hwtracing/qcom/tgu.c b/drivers/hwtracing/qcom/tgu.c
index 368bb196b984..a1ad8d97e9d2 100644
--- a/drivers/hwtracing/qcom/tgu.c
+++ b/drivers/hwtracing/qcom/tgu.c
@@ -17,14 +17,120 @@
 
 DEFINE_CORESIGHT_DEVLIST(tgu_devs, "tgu");
 
+static int calculate_array_location(struct tgu_drvdata *drvdata,
+				   int step_index, int operation_index,
+				   int reg_index)
+{
+	return operation_index * (drvdata->max_step) * (drvdata->max_reg) +
+		step_index * (drvdata->max_reg) + reg_index;
+}
+
+static ssize_t tgu_dataset_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int index;
+	struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	struct tgu_attribute *tgu_attr =
+			container_of(attr, struct tgu_attribute, attr);
+
+	index = calculate_array_location(drvdata, tgu_attr->step_index,
+					 tgu_attr->operation_index,
+					 tgu_attr->reg_num);
+
+	return sysfs_emit(buf, "0x%x\n",
+			  drvdata->value_table->priority[index]);
+}
+
+static ssize_t tgu_dataset_store(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf, size_t size)
+{
+	int index;
+	unsigned long val;
+
+	struct tgu_drvdata *tgu_drvdata = dev_get_drvdata(dev->parent);
+	struct tgu_attribute *tgu_attr =
+		container_of(attr, struct tgu_attribute, attr);
+
+	if (kstrtoul(buf, 0, &val))
+		return -EINVAL;
+
+	guard(spinlock)(&tgu_drvdata->lock);
+	index = calculate_array_location(tgu_drvdata, tgu_attr->step_index,
+					 tgu_attr->operation_index,
+					 tgu_attr->reg_num);
+
+	tgu_drvdata->value_table->priority[index] = val;
+	return size;
+}
+
+static umode_t tgu_node_visible(struct kobject *kobject,
+				struct attribute *attr,
+				int n)
+{
+	struct device *dev = kobj_to_dev(kobject);
+	struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	int ret = SYSFS_GROUP_INVISIBLE;
+
+	struct device_attribute *dev_attr =
+		container_of(attr, struct device_attribute, attr);
+	struct tgu_attribute *tgu_attr =
+		container_of(dev_attr, struct tgu_attribute, attr);
+
+	if (tgu_attr->step_index < drvdata->max_step) {
+		ret = (tgu_attr->reg_num < drvdata->max_reg) ?
+			attr->mode : 0;
+	}
+	return ret;
+}
+
 static void tgu_write_all_hw_regs(struct tgu_drvdata *drvdata)
 {
+	int i, j, k, index;
+
 	CS_UNLOCK(drvdata->base);
+	for (i = 0; i < drvdata->max_step; i++) {
+		for (j = 0; j < MAX_PRIORITY; j++) {
+			for (k = 0; k < drvdata->max_reg; k++) {
+				index = calculate_array_location(
+							drvdata, i, j, k);
+
+				writel(drvdata->value_table->priority[index],
+					drvdata->base +
+					PRIORITY_REG_STEP(i, j, k));
+			}
+		}
+	}
 	/* Enable TGU to program the triggers */
 	writel(1, drvdata->base + TGU_CONTROL);
 	CS_LOCK(drvdata->base);
 }
 
+static void tgu_set_reg_number(struct tgu_drvdata *drvdata)
+{
+	int num_sense_input;
+	int num_reg;
+	u32 devid;
+
+	devid = readl(drvdata->base + CORESIGHT_DEVID);
+
+	num_sense_input = TGU_DEVID_SENSE_INPUT(devid);
+	if (((num_sense_input * NUMBER_BITS_EACH_SIGNAL) % LENGTH_REGISTER) == 0)
+		num_reg = (num_sense_input * NUMBER_BITS_EACH_SIGNAL) / LENGTH_REGISTER;
+	else
+		num_reg = ((num_sense_input * NUMBER_BITS_EACH_SIGNAL) / LENGTH_REGISTER) + 1;
+	drvdata->max_reg = num_reg;
+}
+
+static void tgu_set_steps(struct tgu_drvdata *drvdata)
+{
+	u32 devid;
+
+	devid = readl(drvdata->base + CORESIGHT_DEVID);
+
+	drvdata->max_step = TGU_DEVID_STEPS(devid);
+}
+
 static int tgu_enable(struct coresight_device *csdev, enum cs_mode mode,
 		      void *data)
 {
@@ -122,6 +228,38 @@ static const struct attribute_group tgu_common_grp = {
 
 static const struct attribute_group *tgu_attr_groups[] = {
 	&tgu_common_grp,
+	PRIORITY_ATTRIBUTE_GROUP_INIT(0, 0),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(0, 1),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(0, 2),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(0, 3),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(1, 0),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(1, 1),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(1, 2),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(1, 3),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(2, 0),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(2, 1),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(2, 2),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(2, 3),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(3, 0),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(3, 1),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(3, 2),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(3, 3),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(4, 0),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(4, 1),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(4, 2),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(4, 3),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(5, 0),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(5, 1),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(5, 2),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(5, 3),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(6, 0),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(6, 1),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(6, 2),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(6, 3),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(7, 0),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(7, 1),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(7, 2),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(7, 3),
 	NULL,
 };
 
@@ -156,6 +294,23 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id)
 
 	spin_lock_init(&drvdata->lock);
 
+	tgu_set_reg_number(drvdata);
+	tgu_set_steps(drvdata);
+
+	drvdata->value_table =
+		devm_kzalloc(dev, sizeof(*drvdata->value_table), GFP_KERNEL);
+	if (!drvdata->value_table)
+		return -ENOMEM;
+
+	drvdata->value_table->priority = devm_kzalloc(
+		dev,
+		MAX_PRIORITY * drvdata->max_reg * drvdata->max_step *
+			sizeof(*(drvdata->value_table->priority)),
+		GFP_KERNEL);
+
+	if (!drvdata->value_table->priority)
+		return -ENOMEM;
+
 	drvdata->enable = false;
 	desc.type = CORESIGHT_DEV_TYPE_HELPER;
 	desc.pdata = adev->dev.platform_data;
diff --git a/drivers/hwtracing/qcom/tgu.h b/drivers/hwtracing/qcom/tgu.h
index 1a55da90f521..444804e52337 100644
--- a/drivers/hwtracing/qcom/tgu.h
+++ b/drivers/hwtracing/qcom/tgu.h
@@ -9,6 +9,111 @@
 /* Register addresses */
 #define TGU_CONTROL 0x0000
 
+#define TGU_DEVID_SENSE_INPUT(devid_val) ((int) BMVAL(devid_val, 10, 17))
+#define TGU_DEVID_STEPS(devid_val) ((int)BMVAL(devid_val, 3, 6))
+#define NUMBER_BITS_EACH_SIGNAL 4
+#define LENGTH_REGISTER 32
+
+/*
+ *  TGU configuration space                              Step configuration
+ *  offset table                                         space layout
+ * x-------------------------x$                          x-------------x$
+ * |                         |$                          |             |$
+ * |                         |                           |   reserve   |$
+ * |                         |                           |             |$
+ * |coresight management     |                           |-------------|base+n*0x1D8+0x1F4$
+ * |     registe             |                     |---> |prioroty[3]  |$
+ * |                         |                     |     |-------------|base+n*0x1D8+0x194$
+ * |                         |                     |     |prioroty[2]  |$
+ * |-------------------------|                     |     |-------------|base+n*0x1D8+0x134$
+ * |                         |                     |     |prioroty[1]  |$
+ * |         step[7]         |                     |     |-------------|base+n*0x1D8+0xD4$
+ * |-------------------------|->base+0x40+7*0x1D8  |     |prioroty[0]  |$
+ * |                         |                     |     |-------------|base+n*0x1D8+0x74$
+ * |         ...             |                     |     |  condition  |$
+ * |                         |                     |     |   select    |$
+ * |-------------------------|->base+0x40+1*0x1D8  |     |-------------|base+n*0x1D8+0x60$
+ * |                         |                     |     |  condition  |$
+ * |         step[0]         |-------------------->      |   decode    |$
+ * |-------------------------|-> base+0x40               |-------------|base+n*0x1D8+0x50$
+ * |                         |                           |             |$
+ * | Control and status space|                           |Timer/Counter|$
+ * |        space            |                           |             |$
+ * x-------------------------x->base                     x-------------x base+n*0x1D8+0x40$
+ *
+ */
+#define STEP_OFFSET 0x1D8
+#define PRIORITY_START_OFFSET 0x0074
+#define PRIORITY_OFFSET 0x60
+#define REG_OFFSET 0x4
+
+/* Calculate compare step addresses */
+#define PRIORITY_REG_STEP(step, priority, reg)\
+	(PRIORITY_START_OFFSET + PRIORITY_OFFSET * priority +\
+	 REG_OFFSET * reg + STEP_OFFSET * step)
+
+#define tgu_dataset_rw(name, step_index, type, reg_num)                  \
+	(&((struct tgu_attribute[]){ {                                   \
+		__ATTR(name, 0644, tgu_dataset_show, tgu_dataset_store), \
+		step_index,                                              \
+		type,                                                    \
+		reg_num,                                                 \
+	} })[0].attr.attr)
+
+#define STEP_PRIORITY(step_index, reg_num, priority)                     \
+	tgu_dataset_rw(reg##reg_num, step_index, TGU_PRIORITY##priority, \
+			reg_num)
+
+#define STEP_PRIORITY_LIST(step_index, priority)  \
+	{STEP_PRIORITY(step_index, 0, priority),  \
+	 STEP_PRIORITY(step_index, 1, priority),  \
+	 STEP_PRIORITY(step_index, 2, priority),  \
+	 STEP_PRIORITY(step_index, 3, priority),  \
+	 STEP_PRIORITY(step_index, 4, priority),  \
+	 STEP_PRIORITY(step_index, 5, priority),  \
+	 STEP_PRIORITY(step_index, 6, priority),  \
+	 STEP_PRIORITY(step_index, 7, priority),  \
+	 STEP_PRIORITY(step_index, 8, priority),  \
+	 STEP_PRIORITY(step_index, 9, priority),  \
+	 STEP_PRIORITY(step_index, 10, priority), \
+	 STEP_PRIORITY(step_index, 11, priority), \
+	 STEP_PRIORITY(step_index, 12, priority), \
+	 STEP_PRIORITY(step_index, 13, priority), \
+	 STEP_PRIORITY(step_index, 14, priority), \
+	 STEP_PRIORITY(step_index, 15, priority), \
+	 STEP_PRIORITY(step_index, 16, priority), \
+	 STEP_PRIORITY(step_index, 17, priority), \
+	 NULL                   \
+	}
+
+#define PRIORITY_ATTRIBUTE_GROUP_INIT(step, priority)\
+	(&(const struct attribute_group){\
+		.attrs = (struct attribute*[])STEP_PRIORITY_LIST(step, priority),\
+		.is_visible = tgu_node_visible,\
+		.name = "step" #step "_priority" #priority \
+	})
+
+enum operation_index {
+	TGU_PRIORITY0,
+	TGU_PRIORITY1,
+	TGU_PRIORITY2,
+	TGU_PRIORITY3,
+};
+
+/* Maximum priority that TGU supports */
+#define MAX_PRIORITY 4
+
+struct tgu_attribute {
+	struct device_attribute attr;
+	u32 step_index;
+	enum operation_index operation_index;
+	u32 reg_num;
+};
+
+struct value_table {
+	unsigned int *priority;
+};
+
 /**
  * struct tgu_drvdata - Data structure for a TGU (Trigger Generator Unit)
  * @base: Memory-mapped base address of the TGU device
@@ -16,6 +121,9 @@
  * @csdev: Pointer to the associated coresight device
  * @lock: Spinlock for handling concurrent access
  * @enable: Flag indicating whether the TGU device is enabled
+ * @value_table: Store given value based on relevant parameters.
+ * @max_reg: Maximum number of registers
+ * @max_step: Maximum step size
  *
  * This structure defines the data associated with a TGU device,
  * including its base address, device pointers, clock, spinlock for
@@ -28,6 +136,9 @@ struct tgu_drvdata {
 	struct coresight_device *csdev;
 	spinlock_t lock;
 	bool enable;
+	struct value_table *value_table;
+	int max_reg;
+	int max_step;
 };
 
 #endif
-- 
2.34.1



From songwei.chai at oss.qualcomm.com  Wed Dec  3 01:00:52 2025
From: songwei.chai at oss.qualcomm.com (Songwei Chai)
Date: Wed,  3 Dec 2025 01:00:52 -0800
Subject: [PATCH v8 4/7] qcom-tgu: Add TGU decode support
In-Reply-To: <20251203090055.2432719-1-songwei.chai@oss.qualcomm.com>
References: <20251203090055.2432719-1-songwei.chai@oss.qualcomm.com>
Message-ID: <20251203090055.2432719-5-songwei.chai@oss.qualcomm.com>

Decoding is when all the potential pieces for creating a trigger
are brought together for a given step. Example - there may be a
counter keeping track of some occurrences and a priority-group that
is being used to detect a pattern on the sense inputs. These 2
inputs to condition_decode must be programmed, for a given step,
to establish the condition for the trigger, or movement to another
steps.

Signed-off-by: Songwei Chai <songwei.chai at oss.qualcomm.com>
---
 .../testing/sysfs-bus-coresight-devices-tgu   |   7 +
 drivers/hwtracing/qcom/tgu.c                  | 153 ++++++++++++++++--
 drivers/hwtracing/qcom/tgu.h                  |  27 ++++
 3 files changed, 173 insertions(+), 14 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu
index eafb0e0dd030..df73a9d5043e 100644
--- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu
@@ -14,3 +14,10 @@ KernelVersion	6.18
 Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Songwei Chai <songwei.chai at oss.qualcomm.com>
 Description:
 		(RW) Set/Get the sensed signal with specific step and priority for TGU.
+
+What:		/sys/bus/coresight/devices/<tgu-name>/step[0:7]_condition_decode/reg[0:3]
+Date:		December 2025
+KernelVersion	6.18
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Songwei Chai <songwei.chai at oss.qualcomm.com>
+Description:
+		(RW) Set/Get the decode mode with specific step for TGU.
diff --git a/drivers/hwtracing/qcom/tgu.c b/drivers/hwtracing/qcom/tgu.c
index a1ad8d97e9d2..b4ff41cf0a11 100644
--- a/drivers/hwtracing/qcom/tgu.c
+++ b/drivers/hwtracing/qcom/tgu.c
@@ -21,8 +21,36 @@ static int calculate_array_location(struct tgu_drvdata *drvdata,
 				   int step_index, int operation_index,
 				   int reg_index)
 {
-	return operation_index * (drvdata->max_step) * (drvdata->max_reg) +
-		step_index * (drvdata->max_reg) + reg_index;
+	int ret = -EINVAL;
+
+	switch (operation_index) {
+	case TGU_PRIORITY0:
+	case TGU_PRIORITY1:
+	case TGU_PRIORITY2:
+	case TGU_PRIORITY3:
+		ret = operation_index * (drvdata->max_step) *
+			(drvdata->max_reg) +
+			step_index * (drvdata->max_reg) + reg_index;
+		break;
+	case TGU_CONDITION_DECODE:
+		ret = step_index * (drvdata->max_condition_decode) +
+			reg_index;
+		break;
+	default:
+		break;
+	}
+	return ret;
+}
+
+static int check_array_location(struct tgu_drvdata *drvdata, int step,
+				int ops, int reg)
+{
+	int result = calculate_array_location(drvdata, step, ops, reg);
+
+	if (result == -EINVAL)
+		dev_err(&drvdata->csdev->dev, "%s - Fail\n", __func__);
+
+	return result;
 }
 
 static ssize_t tgu_dataset_show(struct device *dev,
@@ -37,8 +65,26 @@ static ssize_t tgu_dataset_show(struct device *dev,
 					 tgu_attr->operation_index,
 					 tgu_attr->reg_num);
 
-	return sysfs_emit(buf, "0x%x\n",
-			  drvdata->value_table->priority[index]);
+	index = check_array_location(drvdata, tgu_attr->step_index,
+			     tgu_attr->operation_index, tgu_attr->reg_num);
+
+	if (index == -EINVAL)
+		return -EINVAL;
+
+	switch (tgu_attr->operation_index) {
+	case TGU_PRIORITY0:
+	case TGU_PRIORITY1:
+	case TGU_PRIORITY2:
+	case TGU_PRIORITY3:
+		return sysfs_emit(buf, "0x%x\n",
+				  drvdata->value_table->priority[index]);
+	case TGU_CONDITION_DECODE:
+		return sysfs_emit(buf, "0x%x\n",
+				  drvdata->value_table->condition_decode[index]);
+	default:
+		break;
+	}
+	return -EINVAL;
 }
 
 static ssize_t tgu_dataset_store(struct device *dev,
@@ -46,6 +92,7 @@ static ssize_t tgu_dataset_store(struct device *dev,
 				 const char *buf, size_t size)
 {
 	int index;
+	int ret = -EINVAL;
 	unsigned long val;
 
 	struct tgu_drvdata *tgu_drvdata = dev_get_drvdata(dev->parent);
@@ -53,15 +100,32 @@ static ssize_t tgu_dataset_store(struct device *dev,
 		container_of(attr, struct tgu_attribute, attr);
 
 	if (kstrtoul(buf, 0, &val))
-		return -EINVAL;
+		return ret;
 
 	guard(spinlock)(&tgu_drvdata->lock);
-	index = calculate_array_location(tgu_drvdata, tgu_attr->step_index,
+	index = check_array_location(tgu_drvdata, tgu_attr->step_index,
 					 tgu_attr->operation_index,
 					 tgu_attr->reg_num);
 
-	tgu_drvdata->value_table->priority[index] = val;
-	return size;
+	if (index == -EINVAL)
+		return ret;
+
+	switch (tgu_attr->operation_index) {
+	case TGU_PRIORITY0:
+	case TGU_PRIORITY1:
+	case TGU_PRIORITY2:
+	case TGU_PRIORITY3:
+		tgu_drvdata->value_table->priority[index] = val;
+		ret = size;
+		break;
+	case TGU_CONDITION_DECODE:
+		tgu_drvdata->value_table->condition_decode[index] = val;
+		ret = size;
+		break;
+	default:
+		break;
+	}
+	return ret;
 }
 
 static umode_t tgu_node_visible(struct kobject *kobject,
@@ -78,13 +142,27 @@ static umode_t tgu_node_visible(struct kobject *kobject,
 		container_of(dev_attr, struct tgu_attribute, attr);
 
 	if (tgu_attr->step_index < drvdata->max_step) {
-		ret = (tgu_attr->reg_num < drvdata->max_reg) ?
-			attr->mode : 0;
+		switch (tgu_attr->operation_index) {
+		case TGU_PRIORITY0:
+		case TGU_PRIORITY1:
+		case TGU_PRIORITY2:
+		case TGU_PRIORITY3:
+			ret = (tgu_attr->reg_num < drvdata->max_reg) ?
+				attr->mode : 0;
+			break;
+		case TGU_CONDITION_DECODE:
+			ret = (tgu_attr->reg_num <
+				drvdata->max_condition_decode) ?
+				attr->mode : 0;
+			break;
+		default:
+			break;
+		}
 	}
 	return ret;
 }
 
-static void tgu_write_all_hw_regs(struct tgu_drvdata *drvdata)
+static ssize_t tgu_write_all_hw_regs(struct tgu_drvdata *drvdata)
 {
 	int i, j, k, index;
 
@@ -92,8 +170,10 @@ static void tgu_write_all_hw_regs(struct tgu_drvdata *drvdata)
 	for (i = 0; i < drvdata->max_step; i++) {
 		for (j = 0; j < MAX_PRIORITY; j++) {
 			for (k = 0; k < drvdata->max_reg; k++) {
-				index = calculate_array_location(
+				index = check_array_location(
 							drvdata, i, j, k);
+				if (index == -EINVAL)
+					goto exit;
 
 				writel(drvdata->value_table->priority[index],
 					drvdata->base +
@@ -101,9 +181,23 @@ static void tgu_write_all_hw_regs(struct tgu_drvdata *drvdata)
 			}
 		}
 	}
+
+	for (i = 0; i < drvdata->max_step; i++) {
+		for (j = 0; j < drvdata->max_condition_decode; j++) {
+			index = check_array_location(drvdata, i,
+						TGU_CONDITION_DECODE, j);
+			if (index == -EINVAL)
+				goto exit;
+
+			writel(drvdata->value_table->condition_decode[index],
+				drvdata->base + CONDITION_DECODE_STEP(i, j));
+		}
+	}
 	/* Enable TGU to program the triggers */
 	writel(1, drvdata->base + TGU_CONTROL);
+exit:
 	CS_LOCK(drvdata->base);
+	return index >= 0 ? 0 : -EINVAL;
 }
 
 static void tgu_set_reg_number(struct tgu_drvdata *drvdata)
@@ -131,19 +225,32 @@ static void tgu_set_steps(struct tgu_drvdata *drvdata)
 	drvdata->max_step = TGU_DEVID_STEPS(devid);
 }
 
+static void tgu_set_conditions(struct tgu_drvdata *drvdata)
+{
+	u32 devid;
+
+	devid = readl(drvdata->base + CORESIGHT_DEVID);
+	drvdata->max_condition_decode = TGU_DEVID_CONDITIONS(devid);
+}
+
 static int tgu_enable(struct coresight_device *csdev, enum cs_mode mode,
 		      void *data)
 {
+	int ret = 0;
 	struct tgu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
 	guard(spinlock)(&drvdata->lock);
 	if (drvdata->enable)
 		return -EBUSY;
 
-	tgu_write_all_hw_regs(drvdata);
+	ret = tgu_write_all_hw_regs(drvdata);
+
+	if (ret == -EINVAL)
+		goto exit;
 	drvdata->enable = true;
 
-	return 0;
+exit:
+	return ret;
 }
 
 static int tgu_disable(struct coresight_device *csdev, void *data)
@@ -260,6 +367,14 @@ static const struct attribute_group *tgu_attr_groups[] = {
 	PRIORITY_ATTRIBUTE_GROUP_INIT(7, 1),
 	PRIORITY_ATTRIBUTE_GROUP_INIT(7, 2),
 	PRIORITY_ATTRIBUTE_GROUP_INIT(7, 3),
+	CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(0),
+	CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(1),
+	CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(2),
+	CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(3),
+	CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(4),
+	CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(5),
+	CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(6),
+	CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(7),
 	NULL,
 };
 
@@ -296,6 +411,7 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id)
 
 	tgu_set_reg_number(drvdata);
 	tgu_set_steps(drvdata);
+	tgu_set_conditions(drvdata);
 
 	drvdata->value_table =
 		devm_kzalloc(dev, sizeof(*drvdata->value_table), GFP_KERNEL);
@@ -311,6 +427,15 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id)
 	if (!drvdata->value_table->priority)
 		return -ENOMEM;
 
+	drvdata->value_table->condition_decode = devm_kzalloc(
+		dev,
+		drvdata->max_condition_decode * drvdata->max_step *
+			sizeof(*(drvdata->value_table->condition_decode)),
+		GFP_KERNEL);
+
+	if (!drvdata->value_table->condition_decode)
+		return -ENOMEM;
+
 	drvdata->enable = false;
 	desc.type = CORESIGHT_DEV_TYPE_HELPER;
 	desc.pdata = adev->dev.platform_data;
diff --git a/drivers/hwtracing/qcom/tgu.h b/drivers/hwtracing/qcom/tgu.h
index 444804e52337..cac5efeee1e9 100644
--- a/drivers/hwtracing/qcom/tgu.h
+++ b/drivers/hwtracing/qcom/tgu.h
@@ -11,6 +11,7 @@
 
 #define TGU_DEVID_SENSE_INPUT(devid_val) ((int) BMVAL(devid_val, 10, 17))
 #define TGU_DEVID_STEPS(devid_val) ((int)BMVAL(devid_val, 3, 6))
+#define TGU_DEVID_CONDITIONS(devid_val) ((int)BMVAL(devid_val, 0, 2))
 #define NUMBER_BITS_EACH_SIGNAL 4
 #define LENGTH_REGISTER 32
 
@@ -44,6 +45,7 @@
  */
 #define STEP_OFFSET 0x1D8
 #define PRIORITY_START_OFFSET 0x0074
+#define CONDITION_DECODE_OFFSET 0x0050
 #define PRIORITY_OFFSET 0x60
 #define REG_OFFSET 0x4
 
@@ -52,6 +54,9 @@
 	(PRIORITY_START_OFFSET + PRIORITY_OFFSET * priority +\
 	 REG_OFFSET * reg + STEP_OFFSET * step)
 
+#define CONDITION_DECODE_STEP(step, decode) \
+	(CONDITION_DECODE_OFFSET + REG_OFFSET * decode + STEP_OFFSET * step)
+
 #define tgu_dataset_rw(name, step_index, type, reg_num)                  \
 	(&((struct tgu_attribute[]){ {                                   \
 		__ATTR(name, 0644, tgu_dataset_show, tgu_dataset_store), \
@@ -64,6 +69,9 @@
 	tgu_dataset_rw(reg##reg_num, step_index, TGU_PRIORITY##priority, \
 			reg_num)
 
+#define STEP_DECODE(step_index, reg_num) \
+	tgu_dataset_rw(reg##reg_num, step_index, TGU_CONDITION_DECODE, reg_num)
+
 #define STEP_PRIORITY_LIST(step_index, priority)  \
 	{STEP_PRIORITY(step_index, 0, priority),  \
 	 STEP_PRIORITY(step_index, 1, priority),  \
@@ -86,6 +94,14 @@
 	 NULL                   \
 	}
 
+#define STEP_DECODE_LIST(n) \
+	{STEP_DECODE(n, 0), \
+	 STEP_DECODE(n, 1), \
+	 STEP_DECODE(n, 2), \
+	 STEP_DECODE(n, 3), \
+	 NULL		    \
+	}
+
 #define PRIORITY_ATTRIBUTE_GROUP_INIT(step, priority)\
 	(&(const struct attribute_group){\
 		.attrs = (struct attribute*[])STEP_PRIORITY_LIST(step, priority),\
@@ -93,11 +109,19 @@
 		.name = "step" #step "_priority" #priority \
 	})
 
+#define CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(step)\
+	(&(const struct attribute_group){\
+		.attrs = (struct attribute*[])STEP_DECODE_LIST(step),\
+		.is_visible = tgu_node_visible,\
+		.name = "step" #step "_condition_decode" \
+	})
+
 enum operation_index {
 	TGU_PRIORITY0,
 	TGU_PRIORITY1,
 	TGU_PRIORITY2,
 	TGU_PRIORITY3,
+	TGU_CONDITION_DECODE,
 };
 
 /* Maximum priority that TGU supports */
@@ -112,6 +136,7 @@ struct tgu_attribute {
 
 struct value_table {
 	unsigned int *priority;
+	unsigned int *condition_decode;
 };
 
 /**
@@ -124,6 +149,7 @@ struct value_table {
  * @value_table: Store given value based on relevant parameters.
  * @max_reg: Maximum number of registers
  * @max_step: Maximum step size
+ * @max_condition_decode: Maximum number of condition_decode
  *
  * This structure defines the data associated with a TGU device,
  * including its base address, device pointers, clock, spinlock for
@@ -139,6 +165,7 @@ struct tgu_drvdata {
 	struct value_table *value_table;
 	int max_reg;
 	int max_step;
+	int max_condition_decode;
 };
 
 #endif
-- 
2.34.1



From songwei.chai at oss.qualcomm.com  Wed Dec  3 01:00:53 2025
From: songwei.chai at oss.qualcomm.com (Songwei Chai)
Date: Wed,  3 Dec 2025 01:00:53 -0800
Subject: [PATCH v8 5/7] qcom-tgu: Add support to configure next action
In-Reply-To: <20251203090055.2432719-1-songwei.chai@oss.qualcomm.com>
References: <20251203090055.2432719-1-songwei.chai@oss.qualcomm.com>
Message-ID: <20251203090055.2432719-6-songwei.chai@oss.qualcomm.com>

Add "select" node for each step to determine if another step is taken,
trigger(s) are generated, counters/timers incremented/decremented, etc.

Signed-off-by: Songwei Chai <songwei.chai at oss.qualcomm.com>
---
 .../testing/sysfs-bus-coresight-devices-tgu   |  7 +++
 drivers/hwtracing/qcom/tgu.c                  | 52 +++++++++++++++++++
 drivers/hwtracing/qcom/tgu.h                  | 27 ++++++++++
 3 files changed, 86 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu
index df73a9d5043e..a0d5e2eb141b 100644
--- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu
@@ -21,3 +21,10 @@ KernelVersion	6.18
 Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Songwei Chai <songwei.chai at oss.qualcomm.com>
 Description:
 		(RW) Set/Get the decode mode with specific step for TGU.
+
+What:		/sys/bus/coresight/devices/<tgu-name>/step[0:7]_condition_select/reg[0:3]
+Date:		December 2025
+KernelVersion	6.18
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Songwei Chai <songwei.chai at oss.qualcomm.com>
+Description:
+		(RW) Set/Get the next action with specific step for TGU.
diff --git a/drivers/hwtracing/qcom/tgu.c b/drivers/hwtracing/qcom/tgu.c
index b4ff41cf0a11..98721891251a 100644
--- a/drivers/hwtracing/qcom/tgu.c
+++ b/drivers/hwtracing/qcom/tgu.c
@@ -36,6 +36,10 @@ static int calculate_array_location(struct tgu_drvdata *drvdata,
 		ret = step_index * (drvdata->max_condition_decode) +
 			reg_index;
 		break;
+	case TGU_CONDITION_SELECT:
+		ret = step_index * (drvdata->max_condition_select) +
+			reg_index;
+		break;
 	default:
 		break;
 	}
@@ -81,6 +85,9 @@ static ssize_t tgu_dataset_show(struct device *dev,
 	case TGU_CONDITION_DECODE:
 		return sysfs_emit(buf, "0x%x\n",
 				  drvdata->value_table->condition_decode[index]);
+	case TGU_CONDITION_SELECT:
+		return sysfs_emit(buf, "0x%x\n",
+				  drvdata->value_table->condition_select[index]);
 	default:
 		break;
 	}
@@ -122,6 +129,10 @@ static ssize_t tgu_dataset_store(struct device *dev,
 		tgu_drvdata->value_table->condition_decode[index] = val;
 		ret = size;
 		break;
+	case TGU_CONDITION_SELECT:
+		tgu_drvdata->value_table->condition_select[index] = val;
+		ret = size;
+		break;
 	default:
 		break;
 	}
@@ -155,6 +166,15 @@ static umode_t tgu_node_visible(struct kobject *kobject,
 				drvdata->max_condition_decode) ?
 				attr->mode : 0;
 			break;
+		case TGU_CONDITION_SELECT:
+		/* 'default' register is at the end of 'select' region */
+			if (tgu_attr->reg_num ==
+			    drvdata->max_condition_select - 1)
+				attr->name = "default";
+			ret = (tgu_attr->reg_num <
+				drvdata->max_condition_select) ?
+				attr->mode : 0;
+			break;
 		default:
 			break;
 		}
@@ -193,6 +213,19 @@ static ssize_t tgu_write_all_hw_regs(struct tgu_drvdata *drvdata)
 				drvdata->base + CONDITION_DECODE_STEP(i, j));
 		}
 	}
+
+	for (i = 0; i < drvdata->max_step; i++) {
+		for (j = 0; j < drvdata->max_condition_select; j++) {
+			index = check_array_location(drvdata, i,
+						TGU_CONDITION_SELECT, j);
+
+			if (index == -EINVAL)
+				goto exit;
+
+			writel(drvdata->value_table->condition_select[index],
+				drvdata->base + CONDITION_SELECT_STEP(i, j));
+		}
+	}
 	/* Enable TGU to program the triggers */
 	writel(1, drvdata->base + TGU_CONTROL);
 exit:
@@ -231,6 +264,8 @@ static void tgu_set_conditions(struct tgu_drvdata *drvdata)
 
 	devid = readl(drvdata->base + CORESIGHT_DEVID);
 	drvdata->max_condition_decode = TGU_DEVID_CONDITIONS(devid);
+	/* select region has an additional 'default' register */
+	drvdata->max_condition_select = TGU_DEVID_CONDITIONS(devid) + 1;
 }
 
 static int tgu_enable(struct coresight_device *csdev, enum cs_mode mode,
@@ -375,6 +410,14 @@ static const struct attribute_group *tgu_attr_groups[] = {
 	CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(5),
 	CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(6),
 	CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(7),
+	CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(0),
+	CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(1),
+	CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(2),
+	CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(3),
+	CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(4),
+	CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(5),
+	CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(6),
+	CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(7),
 	NULL,
 };
 
@@ -436,6 +479,15 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id)
 	if (!drvdata->value_table->condition_decode)
 		return -ENOMEM;
 
+	drvdata->value_table->condition_select = devm_kzalloc(
+		dev,
+		drvdata->max_condition_select * drvdata->max_step *
+			sizeof(*(drvdata->value_table->condition_select)),
+		GFP_KERNEL);
+
+	if (!drvdata->value_table->condition_select)
+		return -ENOMEM;
+
 	drvdata->enable = false;
 	desc.type = CORESIGHT_DEV_TYPE_HELPER;
 	desc.pdata = adev->dev.platform_data;
diff --git a/drivers/hwtracing/qcom/tgu.h b/drivers/hwtracing/qcom/tgu.h
index cac5efeee1e9..5056ec81fdae 100644
--- a/drivers/hwtracing/qcom/tgu.h
+++ b/drivers/hwtracing/qcom/tgu.h
@@ -46,6 +46,7 @@
 #define STEP_OFFSET 0x1D8
 #define PRIORITY_START_OFFSET 0x0074
 #define CONDITION_DECODE_OFFSET 0x0050
+#define CONDITION_SELECT_OFFSET 0x0060
 #define PRIORITY_OFFSET 0x60
 #define REG_OFFSET 0x4
 
@@ -57,6 +58,9 @@
 #define CONDITION_DECODE_STEP(step, decode) \
 	(CONDITION_DECODE_OFFSET + REG_OFFSET * decode + STEP_OFFSET * step)
 
+#define CONDITION_SELECT_STEP(step, select) \
+	(CONDITION_SELECT_OFFSET + REG_OFFSET * select + STEP_OFFSET * step)
+
 #define tgu_dataset_rw(name, step_index, type, reg_num)                  \
 	(&((struct tgu_attribute[]){ {                                   \
 		__ATTR(name, 0644, tgu_dataset_show, tgu_dataset_store), \
@@ -72,6 +76,9 @@
 #define STEP_DECODE(step_index, reg_num) \
 	tgu_dataset_rw(reg##reg_num, step_index, TGU_CONDITION_DECODE, reg_num)
 
+#define STEP_SELECT(step_index, reg_num) \
+	tgu_dataset_rw(reg##reg_num, step_index, TGU_CONDITION_SELECT, reg_num)
+
 #define STEP_PRIORITY_LIST(step_index, priority)  \
 	{STEP_PRIORITY(step_index, 0, priority),  \
 	 STEP_PRIORITY(step_index, 1, priority),  \
@@ -102,6 +109,15 @@
 	 NULL		    \
 	}
 
+#define STEP_SELECT_LIST(n) \
+	{STEP_SELECT(n, 0), \
+	 STEP_SELECT(n, 1), \
+	 STEP_SELECT(n, 2), \
+	 STEP_SELECT(n, 3), \
+	 STEP_SELECT(n, 4), \
+	 NULL		    \
+	}
+
 #define PRIORITY_ATTRIBUTE_GROUP_INIT(step, priority)\
 	(&(const struct attribute_group){\
 		.attrs = (struct attribute*[])STEP_PRIORITY_LIST(step, priority),\
@@ -116,12 +132,20 @@
 		.name = "step" #step "_condition_decode" \
 	})
 
+#define CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(step)\
+	(&(const struct attribute_group){\
+		.attrs = (struct attribute*[])STEP_SELECT_LIST(step),\
+		.is_visible = tgu_node_visible,\
+		.name = "step" #step "_condition_select" \
+	})
+
 enum operation_index {
 	TGU_PRIORITY0,
 	TGU_PRIORITY1,
 	TGU_PRIORITY2,
 	TGU_PRIORITY3,
 	TGU_CONDITION_DECODE,
+	TGU_CONDITION_SELECT,
 };
 
 /* Maximum priority that TGU supports */
@@ -137,6 +161,7 @@ struct tgu_attribute {
 struct value_table {
 	unsigned int *priority;
 	unsigned int *condition_decode;
+	unsigned int *condition_select;
 };
 
 /**
@@ -150,6 +175,7 @@ struct value_table {
  * @max_reg: Maximum number of registers
  * @max_step: Maximum step size
  * @max_condition_decode: Maximum number of condition_decode
+ * @max_condition_select: Maximum number of condition_select
  *
  * This structure defines the data associated with a TGU device,
  * including its base address, device pointers, clock, spinlock for
@@ -166,6 +192,7 @@ struct tgu_drvdata {
 	int max_reg;
 	int max_step;
 	int max_condition_decode;
+	int max_condition_select;
 };
 
 #endif
-- 
2.34.1



From songwei.chai at oss.qualcomm.com  Wed Dec  3 01:00:54 2025
From: songwei.chai at oss.qualcomm.com (Songwei Chai)
Date: Wed,  3 Dec 2025 01:00:54 -0800
Subject: [PATCH v8 6/7] qcom-tgu: Add timer/counter functionality for TGU
In-Reply-To: <20251203090055.2432719-1-songwei.chai@oss.qualcomm.com>
References: <20251203090055.2432719-1-songwei.chai@oss.qualcomm.com>
Message-ID: <20251203090055.2432719-7-songwei.chai@oss.qualcomm.com>

Add counter and timer node for each step which could be
programed if they are to be utilized in trigger event/sequence.

Signed-off-by: Songwei Chai <songwei.chai at oss.qualcomm.com>
---
 .../testing/sysfs-bus-coresight-devices-tgu   |  14 ++
 drivers/hwtracing/qcom/tgu.c                  | 120 ++++++++++++++++++
 drivers/hwtracing/qcom/tgu.h                  |  54 ++++++++
 3 files changed, 188 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu
index a0d5e2eb141b..28d1743bd2fc 100644
--- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu
@@ -28,3 +28,17 @@ KernelVersion	6.18
 Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Songwei Chai <songwei.chai at oss.qualcomm.com>
 Description:
 		(RW) Set/Get the next action with specific step for TGU.
+
+What:		/sys/bus/coresight/devices/<tgu-name>/step[0:7]_timer/reg[0:1]
+Date:		December 2025
+KernelVersion	6.18
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Songwei Chai <songwei.chai at oss.qualcomm.com>
+Description:
+		(RW) Set/Get the timer value with specific step for TGU.
+
+What:		/sys/bus/coresight/devices/<tgu-name>/step[0:7]_counter/reg[0:1]
+Date:		December 2025
+KernelVersion	6.18
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Songwei Chai <songwei.chai at oss.qualcomm.com>
+Description:
+		(RW) Set/Get the counter value with specific step for TGU.
diff --git a/drivers/hwtracing/qcom/tgu.c b/drivers/hwtracing/qcom/tgu.c
index 98721891251a..5db876c31a63 100644
--- a/drivers/hwtracing/qcom/tgu.c
+++ b/drivers/hwtracing/qcom/tgu.c
@@ -40,6 +40,12 @@ static int calculate_array_location(struct tgu_drvdata *drvdata,
 		ret = step_index * (drvdata->max_condition_select) +
 			reg_index;
 		break;
+	case TGU_COUNTER:
+		ret = step_index * (drvdata->max_counter) + reg_index;
+		break;
+	case TGU_TIMER:
+		ret = step_index * (drvdata->max_timer) + reg_index;
+		break;
 	default:
 		break;
 	}
@@ -88,6 +94,12 @@ static ssize_t tgu_dataset_show(struct device *dev,
 	case TGU_CONDITION_SELECT:
 		return sysfs_emit(buf, "0x%x\n",
 				  drvdata->value_table->condition_select[index]);
+	case TGU_TIMER:
+		return sysfs_emit(buf, "0x%x\n",
+				  drvdata->value_table->timer[index]);
+	case TGU_COUNTER:
+		return sysfs_emit(buf, "0x%x\n",
+				  drvdata->value_table->counter[index]);
 	default:
 		break;
 	}
@@ -133,6 +145,14 @@ static ssize_t tgu_dataset_store(struct device *dev,
 		tgu_drvdata->value_table->condition_select[index] = val;
 		ret = size;
 		break;
+	case TGU_TIMER:
+		tgu_drvdata->value_table->timer[index] = val;
+		ret = size;
+		break;
+	case TGU_COUNTER:
+		tgu_drvdata->value_table->counter[index] = val;
+		ret = size;
+		break;
 	default:
 		break;
 	}
@@ -175,6 +195,22 @@ static umode_t tgu_node_visible(struct kobject *kobject,
 				drvdata->max_condition_select) ?
 				attr->mode : 0;
 			break;
+		case TGU_COUNTER:
+			if (drvdata->max_counter == 0)
+				ret = SYSFS_GROUP_INVISIBLE;
+			else
+				ret = (tgu_attr->reg_num <
+					drvdata->max_counter) ?
+					attr->mode : 0;
+			break;
+		case TGU_TIMER:
+			if (drvdata->max_timer == 0)
+				ret = SYSFS_GROUP_INVISIBLE;
+			else
+				ret = (tgu_attr->reg_num <
+					drvdata->max_timer) ?
+					attr->mode : 0;
+			break;
 		default:
 			break;
 		}
@@ -226,6 +262,30 @@ static ssize_t tgu_write_all_hw_regs(struct tgu_drvdata *drvdata)
 				drvdata->base + CONDITION_SELECT_STEP(i, j));
 		}
 	}
+
+	for (i = 0; i < drvdata->max_step; i++) {
+		for (j = 0; j < drvdata->max_timer; j++) {
+			index = check_array_location(drvdata, i, TGU_TIMER, j);
+
+			if (index == -EINVAL)
+				goto exit;
+
+			writel(drvdata->value_table->timer[index],
+				drvdata->base + TIMER_COMPARE_STEP(i, j));
+		}
+	}
+
+	for (i = 0; i < drvdata->max_step; i++) {
+		for (j = 0; j < drvdata->max_counter; j++) {
+			index = check_array_location(drvdata, i, TGU_COUNTER, j);
+
+			if (index == -EINVAL)
+				goto exit;
+
+			writel(drvdata->value_table->counter[index],
+				drvdata->base + COUNTER_COMPARE_STEP(i, j));
+		}
+	}
 	/* Enable TGU to program the triggers */
 	writel(1, drvdata->base + TGU_CONTROL);
 exit:
@@ -268,6 +328,31 @@ static void tgu_set_conditions(struct tgu_drvdata *drvdata)
 	drvdata->max_condition_select = TGU_DEVID_CONDITIONS(devid) + 1;
 }
 
+static void tgu_set_timer_counter(struct tgu_drvdata *drvdata)
+{
+	int num_timers, num_counters;
+	u32 devid2;
+
+	devid2 = readl(drvdata->base + CORESIGHT_DEVID2);
+
+	if (TGU_DEVID2_TIMER0(devid2) && TGU_DEVID2_TIMER1(devid2))
+		num_timers = 2;
+	else if (TGU_DEVID2_TIMER0(devid2) || TGU_DEVID2_TIMER1(devid2))
+		num_timers = 1;
+	else
+		num_timers = 0;
+
+	if (TGU_DEVID2_COUNTER0(devid2) && TGU_DEVID2_COUNTER1(devid2))
+		num_counters = 2;
+	else if (TGU_DEVID2_COUNTER0(devid2) || TGU_DEVID2_COUNTER1(devid2))
+		num_counters = 1;
+	else
+		num_counters = 0;
+
+	drvdata->max_timer = num_timers;
+	drvdata->max_counter = num_counters;
+}
+
 static int tgu_enable(struct coresight_device *csdev, enum cs_mode mode,
 		      void *data)
 {
@@ -418,6 +503,22 @@ static const struct attribute_group *tgu_attr_groups[] = {
 	CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(5),
 	CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(6),
 	CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(7),
+	TIMER_ATTRIBUTE_GROUP_INIT(0),
+	TIMER_ATTRIBUTE_GROUP_INIT(1),
+	TIMER_ATTRIBUTE_GROUP_INIT(2),
+	TIMER_ATTRIBUTE_GROUP_INIT(3),
+	TIMER_ATTRIBUTE_GROUP_INIT(4),
+	TIMER_ATTRIBUTE_GROUP_INIT(5),
+	TIMER_ATTRIBUTE_GROUP_INIT(6),
+	TIMER_ATTRIBUTE_GROUP_INIT(7),
+	COUNTER_ATTRIBUTE_GROUP_INIT(0),
+	COUNTER_ATTRIBUTE_GROUP_INIT(1),
+	COUNTER_ATTRIBUTE_GROUP_INIT(2),
+	COUNTER_ATTRIBUTE_GROUP_INIT(3),
+	COUNTER_ATTRIBUTE_GROUP_INIT(4),
+	COUNTER_ATTRIBUTE_GROUP_INIT(5),
+	COUNTER_ATTRIBUTE_GROUP_INIT(6),
+	COUNTER_ATTRIBUTE_GROUP_INIT(7),
 	NULL,
 };
 
@@ -455,6 +556,7 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id)
 	tgu_set_reg_number(drvdata);
 	tgu_set_steps(drvdata);
 	tgu_set_conditions(drvdata);
+	tgu_set_timer_counter(drvdata);
 
 	drvdata->value_table =
 		devm_kzalloc(dev, sizeof(*drvdata->value_table), GFP_KERNEL);
@@ -488,6 +590,24 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id)
 	if (!drvdata->value_table->condition_select)
 		return -ENOMEM;
 
+	drvdata->value_table->timer = devm_kzalloc(
+		dev,
+		drvdata->max_step * drvdata->max_timer *
+			sizeof(*(drvdata->value_table->timer)),
+		GFP_KERNEL);
+
+	if (!drvdata->value_table->timer)
+		return -ENOMEM;
+
+	drvdata->value_table->counter = devm_kzalloc(
+		dev,
+		drvdata->max_step * drvdata->max_counter *
+			sizeof(*(drvdata->value_table->counter)),
+		GFP_KERNEL);
+
+	if (!drvdata->value_table->counter)
+		return -ENOMEM;
+
 	drvdata->enable = false;
 	desc.type = CORESIGHT_DEV_TYPE_HELPER;
 	desc.pdata = adev->dev.platform_data;
diff --git a/drivers/hwtracing/qcom/tgu.h b/drivers/hwtracing/qcom/tgu.h
index 5056ec81fdae..de438cf868c8 100644
--- a/drivers/hwtracing/qcom/tgu.h
+++ b/drivers/hwtracing/qcom/tgu.h
@@ -8,10 +8,16 @@
 
 /* Register addresses */
 #define TGU_CONTROL 0x0000
+#define CORESIGHT_DEVID2       0xfc0
 
 #define TGU_DEVID_SENSE_INPUT(devid_val) ((int) BMVAL(devid_val, 10, 17))
 #define TGU_DEVID_STEPS(devid_val) ((int)BMVAL(devid_val, 3, 6))
 #define TGU_DEVID_CONDITIONS(devid_val) ((int)BMVAL(devid_val, 0, 2))
+#define TGU_DEVID2_TIMER0(devid_val) ((int)BMVAL(devid_val, 18, 23))
+#define TGU_DEVID2_TIMER1(devid_val) ((int)BMVAL(devid_val, 13, 17))
+#define TGU_DEVID2_COUNTER0(devid_val) ((int)BMVAL(devid_val, 6, 11))
+#define TGU_DEVID2_COUNTER1(devid_val) ((int)BMVAL(devid_val, 0, 5))
+
 #define NUMBER_BITS_EACH_SIGNAL 4
 #define LENGTH_REGISTER 32
 
@@ -47,6 +53,8 @@
 #define PRIORITY_START_OFFSET 0x0074
 #define CONDITION_DECODE_OFFSET 0x0050
 #define CONDITION_SELECT_OFFSET 0x0060
+#define TIMER_START_OFFSET 0x0040
+#define COUNTER_START_OFFSET 0x0048
 #define PRIORITY_OFFSET 0x60
 #define REG_OFFSET 0x4
 
@@ -58,6 +66,12 @@
 #define CONDITION_DECODE_STEP(step, decode) \
 	(CONDITION_DECODE_OFFSET + REG_OFFSET * decode + STEP_OFFSET * step)
 
+#define TIMER_COMPARE_STEP(step, timer) \
+	(TIMER_START_OFFSET + REG_OFFSET * timer + STEP_OFFSET * step)
+
+#define COUNTER_COMPARE_STEP(step, counter) \
+	(COUNTER_START_OFFSET + REG_OFFSET * counter + STEP_OFFSET * step)
+
 #define CONDITION_SELECT_STEP(step, select) \
 	(CONDITION_SELECT_OFFSET + REG_OFFSET * select + STEP_OFFSET * step)
 
@@ -79,6 +93,12 @@
 #define STEP_SELECT(step_index, reg_num) \
 	tgu_dataset_rw(reg##reg_num, step_index, TGU_CONDITION_SELECT, reg_num)
 
+#define STEP_TIMER(step_index, reg_num) \
+	tgu_dataset_rw(reg##reg_num, step_index, TGU_TIMER, reg_num)
+
+#define STEP_COUNTER(step_index, reg_num) \
+	tgu_dataset_rw(reg##reg_num, step_index, TGU_COUNTER, reg_num)
+
 #define STEP_PRIORITY_LIST(step_index, priority)  \
 	{STEP_PRIORITY(step_index, 0, priority),  \
 	 STEP_PRIORITY(step_index, 1, priority),  \
@@ -118,6 +138,18 @@
 	 NULL		    \
 	}
 
+#define STEP_TIMER_LIST(n) \
+	{STEP_TIMER(n, 0), \
+	 STEP_TIMER(n, 1), \
+	 NULL              \
+	}
+
+#define STEP_COUNTER_LIST(n) \
+	{STEP_COUNTER(n, 0), \
+	 STEP_COUNTER(n, 1), \
+	 NULL                \
+	}
+
 #define PRIORITY_ATTRIBUTE_GROUP_INIT(step, priority)\
 	(&(const struct attribute_group){\
 		.attrs = (struct attribute*[])STEP_PRIORITY_LIST(step, priority),\
@@ -139,6 +171,20 @@
 		.name = "step" #step "_condition_select" \
 	})
 
+#define TIMER_ATTRIBUTE_GROUP_INIT(step)\
+	(&(const struct attribute_group){\
+		.attrs = (struct attribute*[])STEP_TIMER_LIST(step),\
+		.is_visible = tgu_node_visible,\
+		.name = "step" #step "_timer" \
+	})
+
+#define COUNTER_ATTRIBUTE_GROUP_INIT(step)\
+	(&(const struct attribute_group){\
+		.attrs = (struct attribute*[])STEP_COUNTER_LIST(step),\
+		.is_visible = tgu_node_visible,\
+		.name = "step" #step "_counter" \
+	})
+
 enum operation_index {
 	TGU_PRIORITY0,
 	TGU_PRIORITY1,
@@ -146,6 +192,8 @@ enum operation_index {
 	TGU_PRIORITY3,
 	TGU_CONDITION_DECODE,
 	TGU_CONDITION_SELECT,
+	TGU_TIMER,
+	TGU_COUNTER
 };
 
 /* Maximum priority that TGU supports */
@@ -162,6 +210,8 @@ struct value_table {
 	unsigned int *priority;
 	unsigned int *condition_decode;
 	unsigned int *condition_select;
+	unsigned int *timer;
+	unsigned int *counter;
 };
 
 /**
@@ -176,6 +226,8 @@ struct value_table {
  * @max_step: Maximum step size
  * @max_condition_decode: Maximum number of condition_decode
  * @max_condition_select: Maximum number of condition_select
+ * @max_timer: Maximum number of timers
+ * @max_counter: Maximum number of counters
  *
  * This structure defines the data associated with a TGU device,
  * including its base address, device pointers, clock, spinlock for
@@ -193,6 +245,8 @@ struct tgu_drvdata {
 	int max_step;
 	int max_condition_decode;
 	int max_condition_select;
+	int max_timer;
+	int max_counter;
 };
 
 #endif
-- 
2.34.1



From songwei.chai at oss.qualcomm.com  Wed Dec  3 01:00:55 2025
From: songwei.chai at oss.qualcomm.com (Songwei Chai)
Date: Wed,  3 Dec 2025 01:00:55 -0800
Subject: [PATCH v8 7/7] qcom-tgu: Add reset node to initialize
In-Reply-To: <20251203090055.2432719-1-songwei.chai@oss.qualcomm.com>
References: <20251203090055.2432719-1-songwei.chai@oss.qualcomm.com>
Message-ID: <20251203090055.2432719-8-songwei.chai@oss.qualcomm.com>

Add reset node to initialize the value of
priority/condition_decode/condition_select/timer/counter nodes.

Signed-off-by: Songwei Chai <songwei.chai at oss.qualcomm.com>
---
 .../testing/sysfs-bus-coresight-devices-tgu   |  7 ++
 drivers/hwtracing/qcom/tgu.c                  | 75 +++++++++++++++++++
 2 files changed, 82 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu
index 28d1743bd2fc..3029f342fc49 100644
--- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu
@@ -42,3 +42,10 @@ KernelVersion	6.18
 Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Songwei Chai <songwei.chai at oss.qualcomm.com>
 Description:
 		(RW) Set/Get the counter value with specific step for TGU.
+
+What:		/sys/bus/coresight/devices/<tgu-name>/reset_tgu
+Date:		December 2025
+KernelVersion	6.18
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Songwei Chai <songwei.chai at oss.qualcomm.com>
+Description:
+		(Write) Write 1 to reset the dataset for TGU.
diff --git a/drivers/hwtracing/qcom/tgu.c b/drivers/hwtracing/qcom/tgu.c
index 5db876c31a63..a164867c6b66 100644
--- a/drivers/hwtracing/qcom/tgu.c
+++ b/drivers/hwtracing/qcom/tgu.c
@@ -434,6 +434,80 @@ static ssize_t enable_tgu_store(struct device *dev,
 }
 static DEVICE_ATTR_RW(enable_tgu);
 
+/* reset_tgu_store - Reset Trace and Gating Unit (TGU) configuration. */
+static ssize_t reset_tgu_store(struct device *dev,
+			       struct device_attribute *attr, const char *buf,
+			       size_t size)
+{
+	unsigned long value;
+	struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	int i, j, ret;
+
+	if (kstrtoul(buf, 0, &value) || value == 0)
+		return -EINVAL;
+
+	if (!drvdata->enable) {
+		ret = pm_runtime_get_sync(drvdata->dev);
+		if (ret < 0) {
+			pm_runtime_put(drvdata->dev);
+			return ret;
+		}
+	}
+
+	spin_lock(&drvdata->lock);
+	CS_UNLOCK(drvdata->base);
+
+	writel(0, drvdata->base + TGU_CONTROL);
+
+	if (drvdata->value_table->priority)
+		memset(drvdata->value_table->priority, 0,
+			    MAX_PRIORITY * drvdata->max_step *
+				drvdata->max_reg * sizeof(unsigned int));
+
+	if (drvdata->value_table->condition_decode)
+		memset(drvdata->value_table->condition_decode, 0,
+			    drvdata->max_condition_decode * drvdata->max_step *
+				sizeof(unsigned int));
+
+		/* Initialize all condition registers to NOT(value=0x1000000) */
+	for (i = 0; i < drvdata->max_step; i++) {
+		for (j = 0; j < drvdata->max_condition_decode; j++) {
+			drvdata->value_table
+			->condition_decode[calculate_array_location(
+			drvdata, i, TGU_CONDITION_DECODE, j)] =
+			0x1000000;
+		}
+	}
+
+	if (drvdata->value_table->condition_select)
+		memset(drvdata->value_table->condition_select, 0,
+				drvdata->max_condition_select * drvdata->max_step *
+				sizeof(unsigned int));
+
+	if (drvdata->value_table->timer)
+		memset(drvdata->value_table->timer, 0,
+			    (drvdata->max_step) *
+				(drvdata->max_timer) *
+				sizeof(unsigned int));
+
+	if (drvdata->value_table->counter)
+		memset(drvdata->value_table->counter, 0,
+			    (drvdata->max_step) *
+				(drvdata->max_counter) *
+				sizeof(unsigned int));
+
+	dev_dbg(dev, "Coresight-TGU reset complete\n");
+
+	CS_LOCK(drvdata->base);
+
+	drvdata->enable = false;
+	spin_unlock(&drvdata->lock);
+	pm_runtime_put(drvdata->dev);
+
+	return size;
+}
+static DEVICE_ATTR_WO(reset_tgu);
+
 static const struct coresight_ops_helper tgu_helper_ops = {
 	.enable = tgu_enable,
 	.disable = tgu_disable,
@@ -445,6 +519,7 @@ static const struct coresight_ops tgu_ops = {
 
 static struct attribute *tgu_common_attrs[] = {
 	&dev_attr_enable_tgu.attr,
+	&dev_attr_reset_tgu.attr,
 	NULL,
 };
 
-- 
2.34.1



From menglong8.dong at gmail.com  Wed Dec  3 01:15:52 2025
From: menglong8.dong at gmail.com (Menglong Dong)
Date: Wed, 3 Dec 2025 17:15:52 +0800
Subject: [PATCHv4 bpf-next 1/9] ftrace,bpf: Remove FTRACE_OPS_FL_JMP
 ftrace_ops flag
In-Reply-To: <20251203082402.78816-2-jolsa@kernel.org>
References: <20251203082402.78816-1-jolsa@kernel.org> <20251203082402.78816-2-jolsa@kernel.org>
Message-ID: <CADxym3awpEbMiSKE5aDcyd2Cg1Cdo7++SLAMSuZmaggt3BSbUA@mail.gmail.com>

On Wed, Dec 3, 2025 at 4:24?PM Jiri Olsa <jolsa at kernel.org> wrote:
>
> At the moment the we allow the jmp attach only for ftrace_ops that
> has FTRACE_OPS_FL_JMP set. This conflicts with following changes
> where we use single ftrace_ops object for all direct call sites,
> so all could be be attached via just call or jmp.
>
> We already limit the jmp attach support with config option and bit
> (LSB) set on the trampoline address. It turns out that's actually
> enough to limit the jmp attach for architecture and only for chosen
> addresses (with LSB bit set).
>
> Each user of register_ftrace_direct or modify_ftrace_direct can set
> the trampoline bit (LSB) to indicate it has to be attached by jmp.
>
> The bpf trampoline generation code uses trampoline flags to generate
> jmp-attach specific code and ftrace inner code uses the trampoline
> bit (LSB) to handle return from jmp attachment, so there's no harm
> to remove the FTRACE_OPS_FL_JMP bit.
>
> The fexit/fmodret performance stays the same (did not drop),
> current code:
>
>   fentry         :   77.904 ? 0.546M/s
>   fexit          :   62.430 ? 0.554M/s
>   fmodret        :   66.503 ? 0.902M/s
>
> with this change:
>
>   fentry         :   80.472 ? 0.061M/s
>   fexit          :   63.995 ? 0.127M/s
>   fmodret        :   67.362 ? 0.175M/s
>
> Fixes: 25e4e3565d45 ("ftrace: Introduce FTRACE_OPS_FL_JMP")
> Signed-off-by: Jiri Olsa <jolsa at kernel.org>
> ---
>  include/linux/ftrace.h  |  1 -
>  kernel/bpf/trampoline.c | 32 ++++++++++++++------------------
>  kernel/trace/ftrace.c   | 14 --------------
>  3 files changed, 14 insertions(+), 33 deletions(-)
>
> diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
> index 015dd1049bea..505b7d3f5641 100644
> --- a/include/linux/ftrace.h
> +++ b/include/linux/ftrace.h
> @@ -359,7 +359,6 @@ enum {
>         FTRACE_OPS_FL_DIRECT                    = BIT(17),
>         FTRACE_OPS_FL_SUBOP                     = BIT(18),
>         FTRACE_OPS_FL_GRAPH                     = BIT(19),
> -       FTRACE_OPS_FL_JMP                       = BIT(20),

Yeah, the FTRACE_OPS_FL_JMP is not necessary. I added
it in case that we maybe want to implement such "jmp" for
ftrace trampoline in the feature. But it's OK to remove it now.

>  };
>
>  #ifndef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
> diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
> index 976d89011b15..b9a358d7a78f 100644
> --- a/kernel/bpf/trampoline.c
> +++ b/kernel/bpf/trampoline.c
> @@ -214,10 +214,15 @@ static int modify_fentry(struct bpf_trampoline *tr, u32 orig_flags,
>         int ret;
>
>         if (tr->func.ftrace_managed) {
> +               unsigned long addr = (unsigned long) new_addr;
> +
> +               if (bpf_trampoline_use_jmp(tr->flags))
> +                       addr = ftrace_jmp_set(addr);

nit: It seems that we can remove the variable "addr" can use
the "new_addr" directly?

> +
>                 if (lock_direct_mutex)
> -                       ret = modify_ftrace_direct(tr->fops, (long)new_addr);
> +                       ret = modify_ftrace_direct(tr->fops, addr);
>                 else
> -                       ret = modify_ftrace_direct_nolock(tr->fops, (long)new_addr);
> +                       ret = modify_ftrace_direct_nolock(tr->fops, addr);
>         } else {
>                 ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr,
>                                                    new_addr);
> @@ -240,10 +245,15 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
>         }
>
>         if (tr->func.ftrace_managed) {
> +               unsigned long addr = (unsigned long) new_addr;
> +
> +               if (bpf_trampoline_use_jmp(tr->flags))
> +                       addr = ftrace_jmp_set(addr);

And here.

Thanks!
Menglong Dong

> +
[...]
>


From jiyu.yang at oss.nxp.com  Wed Dec  3 01:28:25 2025
From: jiyu.yang at oss.nxp.com (Rain Yang)
Date: Wed, 3 Dec 2025 17:28:25 +0800
Subject: [PATCH] arm64: dts: imx95: Use GPU_CGC as core clock for GPU
In-Reply-To: <c6e0e55a-06da-4665-972e-e9b5b8c08bf7@mailbox.org>
References: <20251129143220.14834-1-marek.vasut@mailbox.org>
 <aS-lEibp3zTsaR6T@oss.nxp.com>
 <c6e0e55a-06da-4665-972e-e9b5b8c08bf7@mailbox.org>
Message-ID: <aTACuRjC_Zpf8IOU@oss.nxp.com>

On Wed, Dec 03, 2025 at 04:38:19AM +0100, Marek Vasut wrote:
>On 12/3/25 3:48 AM, Rain Yang wrote:
>
>Hello Rain,
>
>> > diff --git a/arch/arm64/boot/dts/freescale/imx95-clock.h b/arch/arm64/boot/dts/freescale/imx95-clock.h
>> > index e1f91203e7947..22311612e4403 100644
>> > --- a/arch/arm64/boot/dts/freescale/imx95-clock.h
>> > +++ b/arch/arm64/boot/dts/freescale/imx95-clock.h
>> > @@ -183,5 +183,6 @@
>> > #define IMX95_CLK_SEL_A55P                 (IMX95_CCM_NUM_CLK_SRC + 123 + 7)
>> > #define IMX95_CLK_SEL_DRAM                 (IMX95_CCM_NUM_CLK_SRC + 123 + 8)
>> > #define IMX95_CLK_SEL_TEMPSENSE            (IMX95_CCM_NUM_CLK_SRC + 123 + 9)
>> > +#define IMX95_CLK_GPU_CGC                  (IMX95_CCM_NUM_CLK_SRC + 123 + 10)
>> > 
>> > #endif	/* __CLOCK_IMX95_H */
>> > diff --git a/arch/arm64/boot/dts/freescale/imx95.dtsi b/arch/arm64/boot/dts/freescale/imx95.dtsi
>> > index 6091c2713fa48..47f20e501315f 100644
>> > --- a/arch/arm64/boot/dts/freescale/imx95.dtsi
>> > +++ b/arch/arm64/boot/dts/freescale/imx95.dtsi
>> > @@ -2874,7 +2874,7 @@ netc_emdio: mdio at 0,0 {
>> > 		gpu: gpu at 4d900000 {
>> > 			compatible = "nxp,imx95-mali", "arm,mali-valhall-csf";
>> > 			reg = <0 0x4d900000 0 0x480000>;
>> > -			clocks = <&scmi_clk IMX95_CLK_GPU>, <&scmi_clk IMX95_CLK_GPUAPB>;
>> > +			clocks = <&scmi_clk IMX95_CLK_GPU_CGC>, <&scmi_clk IMX95_CLK_GPUAPB>;
>> > 			clock-names = "core", "coregroup";
>> > 			interrupts = <GIC_SPI 289 IRQ_TYPE_LEVEL_HIGH>,
>> > 				     <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>,
>> > -- 
>> > 2.51.0
>> > 
>> Hi Marek,
>> 
>> Thanks for integrating this downstream patch.
>
>Which downstream patch do you refer to ?
>
>> Please note that CLK_GPUAPB and CLK_GPU are
>> always-on, so the commit message should be amended accordingly.
>
>The GPU clock do not seem to be always-on, neither do the GPUAPB . It seems
>the SM can turn those clock off perfectly well.
>
>> Additionally, the IMX95_CLK_GPUAPB handle shall be removed, as there is no valid OPP entry
>> in the frequency table, this also helps minimize differences between downstream and upstream,
>> reducing maintenance effort.
>
>Downstream kernel forks are not relevant to this discussion, upstream your
>content and then you won't have to spend maintenance effort on downstream
>stuff.

This patch [1] was the reference point. For the Linux working environment,
CLK_GPU and CLK_GPUAPB are always-on, while CLK_GPU_CGC can be gated off.

Regarding the IMX95_CLK_GPUAPB handle, my suggestion was based on the absence
of its frequency in any OPP entry within the frequency table. Removing it
could simplify the OPP handling logic and reduce unnecessary complexity.

[1] https://github.com/nxp-imx/linux-imx/commit/695f2bdc57b869ca5189313e4b5fa7eb5a12f622


From zhenglifeng1 at huawei.com  Wed Dec  3 01:44:08 2025
From: zhenglifeng1 at huawei.com (zhenglifeng (A))
Date: Wed, 3 Dec 2025 17:44:08 +0800
Subject: [PATCH v6 0/3] arm64: topology: Handle AMU FIE setup on CPU
 hotplug
In-Reply-To: <aS8GZOuaS1-j14MD@arm.com>
References: <20251119081356.2495290-1-zhenglifeng1@huawei.com>
 <aS2z0EURwHbbGZab@arm.com> <9b6882dc-a91a-42d6-bf76-347338930d71@huawei.com>
 <aS8GZOuaS1-j14MD@arm.com>
Message-ID: <71d202d7-4584-4328-94cd-b2fc0b3d7b04@huawei.com>

On 2025/12/2 23:31, Beata Michalska wrote:
> On Tue, Dec 02, 2025 at 11:05:25AM +0800, zhenglifeng (A) wrote:
>> On 2025/12/1 23:27, Beata Michalska wrote:
>>> Hi,
>>>
>>> Apologies for the delay in reviewing this - currently in progress....
>>> Out of curiosity: what's the cpufreq driver used for testing this series ?
>>
>> I used cppc_cpufreq for testing this. But with some modifications in
>> processor_driver.c, or you'll find that the driver will fail to load with
>> maxcpus set. The modification below is only a temporary solution. I'm still
>> working on that.
>>
> Right, so overall the implementation looks good - thanks for that.
> There are two issues though with the cppc cpufreq driver.
> 
> One: as you have already noticed - it fails to register when
> cpumask_present != cpumask_online.
> 
> Second: it will mix the sources of the freq scale if not all CPUs within the
> policy have AMUs enabled/valid. This is due to the fact that at the time of
> registering the driver and initializing the FIE support policy->cpus ==
> policy->related_cpus. Assuming scenario when there are two CPUs within the
> policy, one being offline and missing valid AMU counters,
> the topology_set_scale_freq_source from cppc cpufreq driver will register
> the tick handler for both CPUs, whereas AMU support will (rightly so) register
> only for the firs one. When the second CPU comes online, the mismatch will be
> detected and the arch callback will get cleared for the first CPU, but the
> second one will remain unchanged.

Thanks for pointing them out. I'll try to fix these issues after this series.

> 
> That said, I do not think any of those issues is a blocker for this series.
> But both would need fixing.
> 
> ---
> BR
> Beata
> 
> 
>> ---
>> diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
>> index 5d824435b26b..2f286a1b0b02 100644
>> --- a/drivers/acpi/processor_driver.c
>> +++ b/drivers/acpi/processor_driver.c
>> @@ -33,6 +33,7 @@ MODULE_AUTHOR("Paul Diefenbaugh");
>>  MODULE_DESCRIPTION("ACPI Processor Driver");
>>  MODULE_LICENSE("GPL");
>>  
>> +static int acpi_processor_start(struct device *dev);
>>  static int acpi_processor_stop(struct device *dev);
>>  
>>  static const struct acpi_device_id processor_device_ids[] = {
>> @@ -46,6 +47,7 @@ static struct device_driver acpi_processor_driver = {
>>  	.name = "processor",
>>  	.bus = &cpu_subsys,
>>  	.acpi_match_table = processor_device_ids,
>> +	.probe = acpi_processor_start,
>>  	.remove = acpi_processor_stop,
>>  };
>>  
>> @@ -191,6 +193,21 @@ static int __acpi_processor_start(struct acpi_device *device)
>>  	return result;
>>  }
>>  
>> +static int acpi_processor_start(struct device *dev)
>> +{
>> +	struct acpi_device *device = ACPI_COMPANION(dev);
>> +	int ret;
>> +
>> +	if (!device)
>> +		return -ENODEV;
>> +
>> +	/* Protect against concurrent CPU hotplug operations */
>> +	cpu_hotplug_disable();
>> +	ret = __acpi_processor_start(device);
>> +	cpu_hotplug_enable();
>> +	return ret;
>> +}
>> +
>>  static int acpi_processor_stop(struct device *dev)
>>  {
>>  	struct acpi_device *device = ACPI_COMPANION(dev);
>> @@ -264,9 +281,9 @@ static int __init acpi_processor_driver_init(void)
>>  
>>  	acpi_processor_register_idle_driver();
>>  
>> -	result = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
>> -				   "acpi/cpu-drv:online",
>> -				   acpi_soft_cpu_online, NULL);
>> +	result = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
>> +					   "acpi/cpu-drv:online",
>> +					   acpi_soft_cpu_online, NULL);
>>  	if (result < 0)
>>  		goto err;
>>  	hp_online = result;
>>
>>>
>>> ---
>>> BR
>>> Beata
>>> On Wed, Nov 19, 2025 at 04:13:53PM +0800, Lifeng Zheng wrote:
>>>> Solve a problem that causes CPUs Setup AMU FIE failed in a corner case,
>>>> even though they're eligible.
>>>>
>>>>
>>>
>>
> 



From james.clark at linaro.org  Wed Dec  3 01:47:25 2025
From: james.clark at linaro.org (James Clark)
Date: Wed, 3 Dec 2025 09:47:25 +0000
Subject: [PATCH v2] perf arm_spe: Add CPU variants supporting common data
 source packet
In-Reply-To: <20251113-perf_arm_spe_update_midr_list-v2-1-d547768f5520@arm.com>
References: <20251113-perf_arm_spe_update_midr_list-v2-1-d547768f5520@arm.com>
Message-ID: <7473f9ad-18dc-43c2-9754-1dbcf2db8a98@linaro.org>



On 13/11/2025 10:57 am, Leo Yan wrote:
> Add the following CPU variants to the list for data source decoding:
> 
>    - Cortex-A715 [1]
>    - Cortex-A78C [2]
>    - Cortex-X1 [3]
>    - Cortex-X4 [4]
>    - Neoverse V3 [5]
> 
> [1] https://developer.arm.com/documentation/101590/0103/Statistical-Profiling-Extension-Support/Statistical-Profiling-Extension-data-source-packet
> [2] https://developer.arm.com/documentation/102226/0002/Debug-descriptions/Statistical-Profiling-Extension/implementation-defined-features-of-SPE
> [3] https://developer.arm.com/documentation/101433/0102/Debug-descriptions/Statistical-Profiling-Extension/implementation-defined-features-of-SPE
> [4] https://developer.arm.com/documentation/102484/0003/Statistical-Profiling-Extension-support/Statistical-Profiling-Extension-data-source-packet
> [5] https://developer.arm.com/documentation/107734/0002/Statistical-Profiling-Extension-support/Statistical-Profiling-Extension-data-source-packet
> 
> Signed-off-by: Leo Yan <leo.yan at arm.com>
> ---
> Changes in v2:
> - Rebased on latest perf-tools-next branch.
> - Link to v1: https://lore.kernel.org/r/20251017-perf_arm_spe_update_midr_list-v1-1-9de407550354 at arm.com
> ---
>   tools/perf/util/arm-spe.c | 5 +++++
>   1 file changed, 5 insertions(+)
> 
> diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c
> index 614ce032f87e46d1f3754258f51bb1693ec128b7..f5bcc84eaa271f4dcc70bb585e517657e523de11 100644
> --- a/tools/perf/util/arm-spe.c
> +++ b/tools/perf/util/arm-spe.c
> @@ -570,16 +570,21 @@ static int arm_spe__synth_instruction_sample(struct arm_spe_queue *speq,
>   }
>   
>   static const struct midr_range common_ds_encoding_cpus[] = {
> +	MIDR_ALL_VERSIONS(MIDR_CORTEX_A715),
>   	MIDR_ALL_VERSIONS(MIDR_CORTEX_A720),
>   	MIDR_ALL_VERSIONS(MIDR_CORTEX_A720AE),
>   	MIDR_ALL_VERSIONS(MIDR_CORTEX_A725),
> +	MIDR_ALL_VERSIONS(MIDR_CORTEX_A78C),
> +	MIDR_ALL_VERSIONS(MIDR_CORTEX_X1),
>   	MIDR_ALL_VERSIONS(MIDR_CORTEX_X1C),
>   	MIDR_ALL_VERSIONS(MIDR_CORTEX_X3),
> +	MIDR_ALL_VERSIONS(MIDR_CORTEX_X4),
>   	MIDR_ALL_VERSIONS(MIDR_CORTEX_X925),
>   	MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N1),
>   	MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2),
>   	MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V1),
>   	MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V2),
> +	MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V3),
>   	{},
>   };
>   
> 
> ---
> base-commit: da8fcfba0854dbe0b0eca465d35620c9cf4c89c1
> change-id: 20251017-perf_arm_spe_update_midr_list-b654cc2ac0dd
> 
> Best regards,

Reviewed-by: James Clark <james.clark at linaro.org>



From s.pueschel at pengutronix.de  Wed Dec  3 01:49:27 2025
From: s.pueschel at pengutronix.de (=?UTF-8?Q?Sven_P=C3=BCschel?=)
Date: Wed, 3 Dec 2025 10:49:27 +0100
Subject: [PATCH 16/16] media: rockchip: rga: add rga3 support
In-Reply-To: <cfe8d17416184f11a93e56872c30a6bcaf017ef5.camel@ndufresne.ca>
References: <20251007-spu-rga3-v1-0-36ad85570402@pengutronix.de>
 <20251007-spu-rga3-v1-16-36ad85570402@pengutronix.de>
 <cfe8d17416184f11a93e56872c30a6bcaf017ef5.camel@ndufresne.ca>
Message-ID: <ccdcf1c3-4afd-45b7-92d0-c35a31be2188@pengutronix.de>

Hi Nicolas,

On 10/7/25 9:41 PM, Nicolas Dufresne wrote:
> Hi,
>
> Le mardi 07 octobre 2025 ? 10:32 +0200, Sven P?schel a ?crit?:
>
>> +}
>> +
>> +static void rga3_cmd_enable_win0(struct rga_ctx *ctx)
>> +{
>> +	u32 *cmd = ctx->rga->cmdbuf_virt;
>> +	unsigned int reg;
>> +
>> +	reg = RGA3_WIN0_RD_CTRL - RGA3_FIRST_CMD_REG;
>> +	cmd[reg >> 2] |= FIELD_PREP(RGA3_WIN_ENABLE, 1);
>> +}
>> +
>> +static void rga3_cmd_set_wr_format(struct rga_ctx *ctx)
>> +{
>> +	u32 *cmd = ctx->rga->cmdbuf_virt;
>> +	const struct rga3_fmt *out = ctx->out.fmt;
>> +	u8 wr_format;
>> +	unsigned int reg;
>> +
>> +	if (out->semi_planar)
>> +		wr_format = RGA3_RDWR_FORMAT_SEMI_PLANAR;
>> +	else
>> +		wr_format = RGA3_RDWR_FORMAT_INTERLEAVED;
>> +
>> +	reg = RGA3_WR_CTRL - RGA3_FIRST_CMD_REG;
>> +	cmd[reg >> 2] |= FIELD_PREP(RGA3_WR_PIC_FORMAT, out->hw_format)
>> +		????? |? FIELD_PREP(RGA3_WR_YC_SWAP, out->yc_swap)
>> +		????? |? FIELD_PREP(RGA3_WR_RBUV_SWAP, out->rbuv_swap)
>> +		????? |? FIELD_PREP(RGA3_WR_FORMAT, wr_format);
>> +}
>> +
>> +static void rga3_cmd_disable_wr_limitation(struct rga_ctx *ctx)
>> +{
>> +	u32 *cmd = ctx->rga->cmdbuf_virt;
>> +	unsigned int reg;
>> +
>> +	/* Use the max value to avoid limiting the write speed */
>> +	reg = RGA3_WR_CTRL - RGA3_FIRST_CMD_REG;
>> +	cmd[reg >> 2] |= FIELD_PREP(RGA3_WR_SW_OUTSTANDING_MAX, 63);
> No issue with the code, but quite an interesting feature. We did discussed in
> pas about using the target framerate (well frame duration in v4l2) to avoid
> bursting the memory.

Do you have any links to these discussions or some actual implementation?

 From the API perspective I didn't really find the desired API to 
support this feature. While VIDIOC_S_PARM would allow setting an frame 
interval, the documentation doesn't really encompass this use case (as 
we won't configure the RGA3 depending on this nor drop frames if the 
RGA3 is too slow).

Also limiting the potential burst size only seems practical, when it 
causes latency issues. Otherwise it should be more efficient to have big 
bursts (bandwidth and potentially even power consumption wise).

Sincerely
 ? ? Sven

>
>> +}
>> +
>> +static void rga3_cmd_set(struct rga_ctx *ctx,
>> +			 struct rga_vb_buffer *src, struct rga_vb_buffer *dst)
>> +{
>> +	struct rockchip_rga *rga = ctx->rga;
>> +
>> +	memset(rga->cmdbuf_virt, 0, RGA3_CMDBUF_SIZE * 4);
>> +
>> +	rga3_cmd_set_win0_addr(ctx, &src->dma_addrs);
>> +	rga3_cmd_set_wr_addr(ctx, &dst->dma_addrs);
>> +
>> +	rga3_cmd_set_win0_format(ctx);
>> +	rga3_cmd_enable_win0(ctx);
>> +	rga3_cmd_set_trans_info(ctx);
>> +	rga3_cmd_set_wr_format(ctx);
>> +	rga3_cmd_disable_wr_limitation(ctx);
>> +
>> +	rga_write(rga, RGA3_CMD_ADDR, rga->cmdbuf_phy);
>> +
>> +	/* sync CMD buf for RGA */
>> +	dma_sync_single_for_device(rga->dev, rga->cmdbuf_phy,
>> +				?? PAGE_SIZE, DMA_BIDIRECTIONAL);
>> +}
>> +
>> +static void rga3_hw_start(struct rockchip_rga *rga,
>> +			? struct rga_vb_buffer *src, struct rga_vb_buffer *dst)
>> +{
>> +	struct rga_ctx *ctx = rga->curr;
>> +
>> +	rga3_cmd_set(ctx, src, dst);
>> +
>> +	/* set to master mode and start the conversion */
>> +	rga_write(rga, RGA3_SYS_CTRL,
>> +		? FIELD_PREP(RGA3_CMD_MODE, RGA3_CMD_MODE_MASTER));
>> +	rga_write(rga, RGA3_INT_EN,
>> +		? FIELD_PREP(RGA3_INT_FRM_DONE, 1) |
>> +		? FIELD_PREP(RGA3_INT_DMA_READ_BUS_ERR, 1) |
>> +		? FIELD_PREP(RGA3_INT_WIN0_FBC_DEC_ERR, 1) |
>> +		? FIELD_PREP(RGA3_INT_WIN0_HOR_ERR, 1) |
>> +		? FIELD_PREP(RGA3_INT_WIN0_VER_ERR, 1) |
>> +		? FIELD_PREP(RGA3_INT_WR_VER_ERR, 1) |
>> +		? FIELD_PREP(RGA3_INT_WR_HOR_ERR, 1) |
>> +		? FIELD_PREP(RGA3_INT_WR_BUS_ERR, 1) |
>> +		? FIELD_PREP(RGA3_INT_WIN0_IN_FIFO_WR_ERR, 1) |
>> +		? FIELD_PREP(RGA3_INT_WIN0_IN_FIFO_RD_ERR, 1) |
>> +		? FIELD_PREP(RGA3_INT_WIN0_HOR_FIFO_WR_ERR, 1) |
>> +		? FIELD_PREP(RGA3_INT_WIN0_HOR_FIFO_RD_ERR, 1) |
>> +		? FIELD_PREP(RGA3_INT_WIN0_VER_FIFO_WR_ERR, 1) |
>> +		? FIELD_PREP(RGA3_INT_WIN0_VER_FIFO_RD_ERR, 1));
>> +	rga_write(rga, RGA3_CMD_CTRL,
>> +		? FIELD_PREP(RGA3_CMD_LINE_START_PULSE, 1));
>> +}
>> +
>> +static void rga3_soft_reset(struct rockchip_rga *rga)
>> +{
>> +	u32 i;
>> +
>> +	rga_write(rga, RGA3_SYS_CTRL,
>> +		? FIELD_PREP(RGA3_CCLK_SRESET, 1) |
>> +		? FIELD_PREP(RGA3_ACLK_SRESET, 1));
>> +
>> +	for (i = 0; i < RGA3_RESET_TIMEOUT; i++) {
>> +		if (FIELD_GET(RGA3_RO_SRST_DONE, rga_read(rga, RGA3_RO_SRST)))
>> +			break;
>> +
>> +		udelay(1);
> Did you measure this IP soft reset speed ? Perhaps this delay can be tune to
> avoid hugging on a CPU core ?
>
>> +	}
>> +
>> +	if (i == RGA3_RESET_TIMEOUT)
>> +		pr_err("Timeout of %d usec reached while waiting for an rga3 soft reset\n", i);
> What next if it failed ? System lockup, or just bunch of errors ?
>
>> +
>> +	rga_write(rga, RGA3_SYS_CTRL, 0);
>> +	rga_iommu_restore(rga);
>> +}
>> +
>> +static enum rga_irq_result rga3_handle_irq(struct rockchip_rga *rga)
>> +{
>> +	u32 intr;
>> +
>> +	intr = rga_read(rga, RGA3_INT_RAW);
>> +	/* clear all interrupts */
>> +	rga_write(rga, RGA3_INT_CLR, intr);
>> +
>> +	if (FIELD_GET(RGA3_INT_FRM_DONE, intr))
>> +		return RGA_IRQ_DONE;
>> +	if (FIELD_GET(RGA3_INT_DMA_READ_BUS_ERR, intr) ||
>> +	??? FIELD_GET(RGA3_INT_WIN0_FBC_DEC_ERR, intr) ||
>> +	??? FIELD_GET(RGA3_INT_WIN0_HOR_ERR, intr) ||
>> +	??? FIELD_GET(RGA3_INT_WIN0_VER_ERR, intr) ||
>> +	??? FIELD_GET(RGA3_INT_WR_VER_ERR, intr) ||
>> +	??? FIELD_GET(RGA3_INT_WR_HOR_ERR, intr) ||
>> +	??? FIELD_GET(RGA3_INT_WR_BUS_ERR, intr) ||
>> +	??? FIELD_GET(RGA3_INT_WIN0_IN_FIFO_WR_ERR, intr) ||
>> +	??? FIELD_GET(RGA3_INT_WIN0_IN_FIFO_RD_ERR, intr) ||
>> +	??? FIELD_GET(RGA3_INT_WIN0_HOR_FIFO_WR_ERR, intr) ||
>> +	??? FIELD_GET(RGA3_INT_WIN0_HOR_FIFO_RD_ERR, intr) ||
>> +	??? FIELD_GET(RGA3_INT_WIN0_VER_FIFO_WR_ERR, intr) ||
>> +	??? FIELD_GET(RGA3_INT_WIN0_VER_FIFO_RD_ERR, intr)) {
>> +		rga3_soft_reset(rga);
>> +		return RGA_IRQ_ERROR;
> Are you certain all these errors are fatal in the first place ? That being said,
> since you "soft reset", I bet this basically abort any pending operation, so it
> should not matter.
>
>> +	}
>> +
>> +	return RGA_IRQ_IGNORE;
>> +}
>> +
>> +static void rga3_get_version(struct rockchip_rga *rga)
>> +{
>> +	u32 version = rga_read(rga, RGA3_VERSION_NUM);
>> +
>> +	rga->version.major = FIELD_GET(RGA3_VERSION_NUM_MAJOR, version);
>> +	rga->version.minor = FIELD_GET(RGA3_VERSION_NUM_MINOR, version);
>> +}
>> +
>> +static struct rga3_fmt rga3_formats[] = {
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_RGB24,
>> +		.hw_format = RGA3_COLOR_FMT_BGR888,
>> +		.rbuv_swap = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_BGR24,
>> +		.hw_format = RGA3_COLOR_FMT_BGR888,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_ABGR32,
>> +		.hw_format = RGA3_COLOR_FMT_BGRA8888,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_RGBA32,
>> +		.hw_format = RGA3_COLOR_FMT_BGRA8888,
>> +		.rbuv_swap = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_XBGR32,
>> +		.hw_format = RGA3_COLOR_FMT_BGRA8888,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_RGBX32,
>> +		.hw_format = RGA3_COLOR_FMT_BGRA8888,
>> +		.rbuv_swap = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_RGB565,
>> +		.hw_format = RGA3_COLOR_FMT_BGR565,
>> +		.rbuv_swap = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_NV12M,
>> +		.hw_format = RGA3_COLOR_FMT_YUV420,
>> +		.semi_planar = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_NV12,
>> +		.hw_format = RGA3_COLOR_FMT_YUV420,
>> +		.semi_planar = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_NV21M,
>> +		.hw_format = RGA3_COLOR_FMT_YUV420,
>> +		.rbuv_swap = 1,
>> +		.semi_planar = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_NV21,
>> +		.hw_format = RGA3_COLOR_FMT_YUV420,
>> +		.rbuv_swap = 1,
>> +		.semi_planar = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_NV16M,
>> +		.hw_format = RGA3_COLOR_FMT_YUV422,
>> +		.semi_planar = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_NV16,
>> +		.hw_format = RGA3_COLOR_FMT_YUV422,
>> +		.semi_planar = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_NV61M,
>> +		.hw_format = RGA3_COLOR_FMT_YUV422,
>> +		.rbuv_swap = 1,
>> +		.semi_planar = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_NV61,
>> +		.hw_format = RGA3_COLOR_FMT_YUV422,
>> +		.rbuv_swap = 1,
>> +		.semi_planar = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_YUYV,
>> +		.hw_format = RGA3_COLOR_FMT_YUV422,
>> +		.yc_swap = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_YVYU,
>> +		.hw_format = RGA3_COLOR_FMT_YUV422,
>> +		.yc_swap = 1,
>> +		.rbuv_swap = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_UYVY,
>> +		.hw_format = RGA3_COLOR_FMT_YUV422,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_VYUY,
>> +		.hw_format = RGA3_COLOR_FMT_YUV422,
>> +		.rbuv_swap = 1,
> Any chance you could add 10bit formats ? It can handle NV15 and P010. So far
> this had been the main reason people have been interested in RGA3 (that and its
> AFBC feature, but the later is quite some more work, since we don't have the
> common code to compute the header sizes in media/ yet).
>
>> +	},
>> +	/* Input only formats last to keep rga3_enum_format simple */
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_ARGB32,
>> +		.hw_format = RGA3_COLOR_FMT_ABGR8888,
>> +		.rbuv_swap = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_BGRA32,
>> +		.hw_format = RGA3_COLOR_FMT_ABGR8888,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_XRGB32,
>> +		.hw_format = RGA3_COLOR_FMT_ABGR8888,
>> +		.rbuv_swap = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_BGRX32,
>> +		.hw_format = RGA3_COLOR_FMT_ABGR8888,
>> +	},
>> +};
>> +
>> +static int rga3_enum_format(struct v4l2_fmtdesc *f)
>> +{
>> +	struct rga3_fmt *fmt;
>> +
>> +	if (f->index >= ARRAY_SIZE(rga3_formats))
>> +		return -EINVAL;
>> +
>> +	fmt = &rga3_formats[f->index];
>> +	if (V4L2_TYPE_IS_CAPTURE(f->type) && !rga3_can_capture(fmt))
>> +		return -EINVAL;
>> +
>> +	f->pixelformat = fmt->fourcc;
>> +	return 0;
>> +}
>> +
>> +static void *rga3_try_format(u32 *fourcc, bool is_output)
> This is not really a try_format function, but a tiny subset. If you really like
> the "try", perhaps call it rga3_try_pixelformat() ?
>
>> +{
>> +	unsigned int i;
>> +
>> +	if (!fourcc)
>> +		return &rga3_formats[0];
>> +
>> +	for (i = 0; i < ARRAY_SIZE(rga3_formats); i++) {
>> +		if (!is_output && !rga3_can_capture(&rga3_formats[i]))
>> +			continue;
>> +
>> +		if (rga3_formats[i].fourcc == *fourcc)
>> +			return &rga3_formats[i];
>> +	}
>> +
>> +	*fourcc = rga3_formats[0].fourcc;
>> +	return &rga3_formats[0];
>> +}
>> +
>> +const struct rga_hw rga3_hw = {
>> +	.card_type = "rga3",
>> +	.has_internal_iommu = false,
>> +	.cmdbuf_size = RGA3_CMDBUF_SIZE,
>> +	.min_width = RGA3_MIN_WIDTH,
>> +	.min_height = RGA3_MIN_HEIGHT,
>> +	.max_width = RGA3_MAX_INPUT_WIDTH,
>> +	.max_height = RGA3_MAX_INPUT_HEIGHT,
>> +
>> +	.start = rga3_hw_start,
>> +	.handle_irq = rga3_handle_irq,
>> +	.get_version = rga3_get_version,
>> +	.enum_format = rga3_enum_format,
>> +	.try_format = rga3_try_format,
>> +};
>> diff --git a/drivers/media/platform/rockchip/rga/rga3-hw.h b/drivers/media/platform/rockchip/rga/rga3-hw.h
>> new file mode 100644
>> index 0000000000000000000000000000000000000000..3829469e310706c11ecc52f40d3d1eb43a61d9c2
>> --- /dev/null
>> +++ b/drivers/media/platform/rockchip/rga/rga3-hw.h
>> @@ -0,0 +1,186 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/*
>> + * Copyright (C) Pengutronix e.K.
>> + * Author: Sven P?schel <s.pueschel at pengutronix.de>
>> + */
>> +#ifndef __RGA3_HW_H__
>> +#define __RGA3_HW_H__
>> +
>> +#include <linux/types.h>
>> +
>> +#define RGA3_CMDBUF_SIZE 0x2e
>> +
>> +#define RGA3_MIN_WIDTH 128
>> +#define RGA3_MIN_HEIGHT 128
>> +#define RGA3_MAX_INPUT_WIDTH (8192 - 16)
>> +#define RGA3_MAX_INPUT_HEIGHT (8192 - 16)
>> +#define RGA3_RESET_TIMEOUT 1000
>> +
>> +/* Registers address */
>> +/* sys reg */
>> +#define RGA3_SYS_CTRL				0x000
>> +#define RGA3_CMD_CTRL				0x004
>> +#define RGA3_CMD_ADDR				0x008
>> +#define RGA3_MI_GROUP_CTRL			0x00c
>> +#define RGA3_ARQOS_CTRL				0x010
>> +#define RGA3_VERSION_NUM			0x018
>> +#define RGA3_VERSION_TIM			0x01c
>> +#define RGA3_INT_EN				0x020
>> +#define RGA3_INT_RAW				0x024
>> +#define RGA3_INT_MSK				0x028
>> +#define RGA3_INT_CLR				0x02c
>> +#define RGA3_RO_SRST				0x030
>> +#define RGA3_STATUS0				0x034
>> +#define RGA3_SCAN_CNT				0x038
>> +#define RGA3_CMD_STATE				0x040
>> +
>> +/* cmd reg */
>> +#define RGA3_WIN0_RD_CTRL			0x100
>> +#define RGA3_FIRST_CMD_REG			RGA3_WIN0_RD_CTRL
>> +#define RGA3_WIN0_Y_BASE			0x110
>> +#define RGA3_WIN0_U_BASE			0x114
>> +#define RGA3_WIN0_V_BASE			0x118
>> +#define RGA3_WIN0_VIR_STRIDE			0x11c
>> +#define RGA3_WIN0_FBC_OFF			0x120
>> +#define RGA3_WIN0_SRC_SIZE			0x124
>> +#define RGA3_WIN0_ACT_OFF			0x128
>> +#define RGA3_WIN0_ACT_SIZE			0x12c
>> +#define RGA3_WIN0_DST_SIZE			0x130
>> +#define RGA3_WIN0_SCL_FAC			0x134
>> +#define RGA3_WIN0_UV_VIR_STRIDE			0x138
>> +#define RGA3_WIN1_RD_CTRL			0x140
>> +#define RGA3_WIN1_Y_BASE			0x150
>> +#define RGA3_WIN1_U_BASE			0x154
>> +#define RGA3_WIN1_V_BASE			0x158
>> +#define RGA3_WIN1_VIR_STRIDE			0x15c
>> +#define RGA3_WIN1_FBC_OFF			0x160
>> +#define RGA3_WIN1_SRC_SIZE			0x164
>> +#define RGA3_WIN1_ACT_OFF			0x168
>> +#define RGA3_WIN1_ACT_SIZE			0x16c
>> +#define RGA3_WIN1_DST_SIZE			0x170
>> +#define RGA3_WIN1_SCL_FAC			0x174
>> +#define RGA3_WIN1_UV_VIR_STRIDE			0x178
>> +#define RGA3_OVLP_CTRL				0x180
>> +#define RGA3_OVLP_OFF				0x184
>> +#define RGA3_OVLP_TOP_KEY_MIN			0x188
>> +#define RGA3_OVLP_TOP_KEY_MAX			0x18c
>> +#define RGA3_OVLP_TOP_CTRL			0x190
>> +#define RGA3_OVLP_BOT_CTRL			0x194
>> +#define RGA3_OVLP_TOP_ALPHA			0x198
>> +#define RGA3_OVLP_BOT_ALPHA			0x19c
>> +#define RGA3_WR_CTRL				0x1a0
>> +#define RGA3_WR_FBCE_CTRL			0x1a4
>> +#define RGA3_WR_VIR_STRIDE			0x1a8
>> +#define RGA3_WR_PL_VIR_STRIDE			0x1ac
>> +#define RGA3_WR_Y_BASE				0x1b0
>> +#define RGA3_WR_U_BASE				0x1b4
>> +#define RGA3_WR_V_BASE				0x1b8
>> +
>> +/* Registers value */
>> +#define RGA3_COLOR_FMT_YUV420		0x0
>> +#define RGA3_COLOR_FMT_YUV422		0x1
>> +#define RGA3_COLOR_FMT_YUV420_10B	0x2
>> +#define RGA3_COLOR_FMT_YUV422_10B	0x3
>> +/*
>> + * Use memory ordering names
>> + * instead of the datasheet naming RGB formats in big endian order
>> + */
>> +#define RGA3_COLOR_FMT_BGR565		0x4
>> +#define RGA3_COLOR_FMT_BGR888		0x5
>> +#define RGA3_COLOR_FMT_FIRST_HAS_ALPHA	RGA3_COLOR_FMT_BGRA8888
>> +#define RGA3_COLOR_FMT_BGRA8888		0x6
>> +#define RGA3_COLOR_FMT_LAST_OUTPUT	RGA3_COLOR_FMT_BGRA8888
>> +/* the following are only supported as inputs */
>> +#define RGA3_COLOR_FMT_ABGR8888		0x7
>> +/*
>> + * the following seem to be unnecessary,
>> + * as they can be achieved with RB swaps
>> + */
>> +#define RGA3_COLOR_FMT_RGBA8888		0x8
>> +#define RGA3_COLOR_FMT_ARGB8888		0x9
>> +
>> +#define RGA3_RDWR_FORMAT_SEMI_PLANAR	0x1
>> +#define RGA3_RDWR_FORMAT_INTERLEAVED	0x2
>> +
>> +#define RGA3_CMD_MODE_MASTER 0x1
>> +
>> +#define RGA3_WIN_CSC_MODE_BT601_F 0x2
>> +
>> +/* RGA masks */
>> +/* SYS_CTRL */
>> +#define RGA3_CCLK_SRESET BIT(4)
>> +#define RGA3_ACLK_SRESET BIT(3)
>> +#define RGA3_CMD_MODE BIT(1)
>> +
>> +/* CMD_CTRL */
>> +#define RGA3_CMD_LINE_START_PULSE BIT(0)
>> +
>> +/* VERSION_NUM */
>> +#define RGA3_VERSION_NUM_MAJOR GENMASK(31, 28)
>> +#define RGA3_VERSION_NUM_MINOR GENMASK(27, 20)
>> +
>> +/* INT_* */
>> +#define RGA3_INT_FRM_DONE BIT(0)
>> +#define RGA3_INT_DMA_READ_BUS_ERR BIT(2)
>> +#define RGA3_INT_WIN0_FBC_DEC_ERR BIT(5)
>> +#define RGA3_INT_WIN0_HOR_ERR BIT(6)
>> +#define RGA3_INT_WIN0_VER_ERR BIT(7)
>> +#define RGA3_INT_WR_VER_ERR BIT(13)
>> +#define RGA3_INT_WR_HOR_ERR BIT(14)
>> +#define RGA3_INT_WR_BUS_ERR BIT(15)
>> +#define RGA3_INT_WIN0_IN_FIFO_WR_ERR BIT(16)
>> +#define RGA3_INT_WIN0_IN_FIFO_RD_ERR BIT(17)
>> +#define RGA3_INT_WIN0_HOR_FIFO_WR_ERR BIT(18)
>> +#define RGA3_INT_WIN0_HOR_FIFO_RD_ERR BIT(19)
>> +#define RGA3_INT_WIN0_VER_FIFO_WR_ERR BIT(20)
>> +#define RGA3_INT_WIN0_VER_FIFO_RD_ERR BIT(21)
>> +
>> +/* RO_SRST */
>> +#define RGA3_RO_SRST_DONE GENMASK(5, 0)
>> +
>> +/* *_SIZE */
>> +#define RGA3_HEIGHT GENMASK(28, 16)
>> +#define RGA3_WIDTH GENMASK(12, 0)
>> +
>> +/* SCL_FAC */
>> +#define RGA3_SCALE_VER_FAC GENMASK(31, 16)
>> +#define RGA3_SCALE_HOR_FAC GENMASK(15, 0)
>> +
>> +/* WINx_CTRL */
>> +#define RGA3_WIN_CSC_MODE GENMASK(27, 26)
>> +#define RGA3_WIN_R2Y BIT(25)
>> +#define RGA3_WIN_Y2R BIT(24)
>> +#define RGA3_WIN_SCALE_VER_UP BIT(23)
>> +#define RGA3_WIN_SCALE_VER_BYPASS BIT(22)
>> +#define RGA3_WIN_SCALE_HOR_UP BIT(21)
>> +#define RGA3_WIN_SCALE_HOR_BYPASS BIT(20)
>> +#define RGA3_WIN_YC_SWAP BIT(13)
>> +#define RGA3_WIN_RBUV_SWAP BIT(12)
>> +#define RGA3_WIN_RD_FORMAT GENMASK(9, 8)
>> +#define RGA3_WIN_PIC_FORMAT GENMASK(7, 4)
>> +#define RGA3_WIN_ENABLE BIT(0)
>> +
>> +/* COLOR_CTRL */
>> +#define RGA3_OVLP_GLOBAL_ALPHA GENMASK(23, 16)
>> +#define RGA3_OVLP_COLOR_MODE BIT(0)
>> +
>> +/* ALPHA_CTRL */
>> +#define RGA3_ALPHA_SELECT_MODE BIT(4)
>> +#define RGA3_ALPHA_BLEND_MODE GENMASK(3, 2)
>> +
>> +/* WR_CTRL */
>> +#define RGA3_WR_YC_SWAP BIT(20)
>> +#define RGA3_WR_SW_OUTSTANDING_MAX GENMASK(18, 13)
>> +#define RGA3_WR_RBUV_SWAP BIT(12)
>> +#define RGA3_WR_FORMAT GENMASK(9, 8)
>> +#define RGA3_WR_PIC_FORMAT GENMASK(7, 4)
>> +
>> +struct rga3_fmt {
>> +	u32 fourcc;
>> +	u8 hw_format;
>> +	bool rbuv_swap;
>> +	bool yc_swap;
>> +	bool semi_planar;
>> +};
>> +
>> +#endif


From daniel.baluta at gmail.com  Wed Dec  3 01:54:37 2025
From: daniel.baluta at gmail.com (Daniel Baluta)
Date: Wed, 3 Dec 2025 11:54:37 +0200
Subject: [PATCH 1/5] arm64: dts: imx91-11x11-evk: Refine label and node
 name of WM8962
In-Reply-To: <20251203070605.1868821-2-chancel.liu@nxp.com>
References: <20251203070605.1868821-1-chancel.liu@nxp.com> <20251203070605.1868821-2-chancel.liu@nxp.com>
Message-ID: <CAEnQRZDqX_-hB9mPT2s-mi99Ym_j2KVfwRykgS5W3hGJ8p_uJA@mail.gmail.com>

On Wed, Dec 3, 2025 at 9:06?AM Chancel Liu <chancel.liu at nxp.com> wrote:
>
> Refine label with "wm8962" and node name with "codec" to follow
> devicetree specification.
>
> Signed-off-by: Chancel Liu <chancel.liu at nxp.com>

Reviewed-by: Daniel Baluta <daniel.baluta at nxp.com>


From daniel.baluta at gmail.com  Wed Dec  3 01:55:47 2025
From: daniel.baluta at gmail.com (Daniel Baluta)
Date: Wed, 3 Dec 2025 11:55:47 +0200
Subject: [PATCH 2/5] arm64: dts: imx91-11x11-evk: Add bt-sco sound card support
In-Reply-To: <20251203070605.1868821-3-chancel.liu@nxp.com>
References: <20251203070605.1868821-1-chancel.liu@nxp.com> <20251203070605.1868821-3-chancel.liu@nxp.com>
Message-ID: <CAEnQRZDx6kBwMYzXRH7zEzJQ58We+o6cfEh-XYcnL6tL4K+gFQ@mail.gmail.com>

On Wed, Dec 3, 2025 at 9:07?AM Chancel Liu <chancel.liu at nxp.com> wrote:
>
> Add bt-sco sound card, which is used by BT HFP case.
> It supports wb profile as default.
>
> Signed-off-by: Chancel Liu <chancel.liu at nxp.com>

Reviewed-by: Daniel Baluta <daniel.baluta at nxp.com>


From daniel.baluta at gmail.com  Wed Dec  3 01:56:31 2025
From: daniel.baluta at gmail.com (Daniel Baluta)
Date: Wed, 3 Dec 2025 11:56:31 +0200
Subject: [PATCH 3/5] arm64: dts: imx91-11x11-evk: Add WM8962 sound card support
In-Reply-To: <20251203070605.1868821-4-chancel.liu@nxp.com>
References: <20251203070605.1868821-1-chancel.liu@nxp.com> <20251203070605.1868821-4-chancel.liu@nxp.com>
Message-ID: <CAEnQRZAJuVq_HnNE7pZkJ6O04QgE0K=AzmmyiREaVxzzL4QNEg@mail.gmail.com>

On Wed, Dec 3, 2025 at 9:07?AM Chancel Liu <chancel.liu at nxp.com> wrote:
>
> Add WM8962 sound card support which connects to SAI3.
>
> Signed-off-by: Chancel Liu <chancel.liu at nxp.com>

Reviewed-by: Daniel Baluta <daniel.baluta at nxp.com>


From daniel.baluta at gmail.com  Wed Dec  3 01:57:24 2025
From: daniel.baluta at gmail.com (Daniel Baluta)
Date: Wed, 3 Dec 2025 11:57:24 +0200
Subject: [PATCH 4/5] arm64: dts: imx91-11x11-evk: Add PDM microphone sound
 card support
In-Reply-To: <20251203070605.1868821-5-chancel.liu@nxp.com>
References: <20251203070605.1868821-1-chancel.liu@nxp.com> <20251203070605.1868821-5-chancel.liu@nxp.com>
Message-ID: <CAEnQRZDDLKyU9a1HPt=V=WvEmfOCsEBPd2zy8FWaKUAwUr5New@mail.gmail.com>

On Wed, Dec 3, 2025 at 9:08?AM Chancel Liu <chancel.liu at nxp.com> wrote:
>
> Add PDM micphone sound card support.
>
> This sound card supports recording sound from PDM microphone
> and convert the PDM format data to PCM data.
>
> Signed-off-by: Chancel Liu <chancel.liu at nxp.com>

Reviewed-by: Daniel Baluta <daniel.baluta at nxp.com>


From ziniu.wang_1 at nxp.com  Wed Dec  3 01:58:50 2025
From: ziniu.wang_1 at nxp.com (ziniu.wang_1 at nxp.com)
Date: Wed,  3 Dec 2025 17:58:50 +0800
Subject: [PATCH] mmc: sdhci-esdhc-imx: wait for data transfer completion before reset
Message-ID: <20251203095850.4019706-1-ziniu.wang_1@nxp.com>

From: Luke Wang <ziniu.wang_1 at nxp.com>

On IMX7ULP platforms, certain SD cards (e.g. Kingston Canvas Go! Plus)
cause system hangs and reboots during manual tuning. These cards exhibit
large gaps (~16us) between tuning command response and data transmission.
When CRC errors occur during tuning, the code assumes data errors even
tuning data hasn't been fully received and then reset host data circuit.

Per IMX7ULP reference manual, reset operations (RESET_DATA/ALL) need to
make sure no active data transfers. Previously, resetting while data was
in-flight caused unknown behavior. This patch adds polling for data
transfer completion before executing resets.

Signed-off-by: Luke Wang <ziniu.wang_1 at nxp.com>
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index a7a5df673b0f..affde1936510 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -1453,6 +1453,21 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
 
 static void esdhc_reset(struct sdhci_host *host, u8 mask)
 {
+	u32 present_state;
+	int ret;
+
+	/*
+	 * For data or full reset, ensure any active data transfer completes
+	 * before resetting to avoid system hang.
+	 */
+	if (mask & (SDHCI_RESET_DATA | SDHCI_RESET_ALL)) {
+		ret = readl_poll_timeout_atomic(host->ioaddr + ESDHC_PRSSTAT, present_state,
+						!(present_state & SDHCI_DATA_INHIBIT), 2, 100000);
+		if (ret == -ETIMEDOUT)
+			dev_warn(mmc_dev(host->mmc),
+				 "timeout waiting for data transfer completion\n");
+	}
+
 	sdhci_and_cqhci_reset(host, mask);
 
 	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
-- 
2.34.1



From haibo.chen at nxp.com  Wed Dec  3 02:35:13 2025
From: haibo.chen at nxp.com (Bough Chen)
Date: Wed, 3 Dec 2025 10:35:13 +0000
Subject: [PATCH] mmc: sdhci-esdhc-imx: wait for data transfer completion
 before reset
In-Reply-To: <20251203095850.4019706-1-ziniu.wang_1@nxp.com>
References: <20251203095850.4019706-1-ziniu.wang_1@nxp.com>
Message-ID: <DU0PR04MB9496B18892369C11ED3EEAD790D9A@DU0PR04MB9496.eurprd04.prod.outlook.com>

> -----Original Message-----
> From: Luke Wang <ziniu.wang_1 at nxp.com>
> Sent: 2025?12?3? 17:59
> To: adrian.hunter at intel.com; Bough Chen <haibo.chen at nxp.com>;
> ulf.hansson at linaro.org
> Cc: shawnguo at kernel.org; s.hauer at pengutronix.de; kernel at pengutronix.de;
> festevam at gmail.com; linux-mmc at vger.kernel.org; dl-S32 <S32 at nxp.com>;
> linux-arm-kernel at lists.infradead.org; linux-kernel at vger.kernel.org
> Subject: [PATCH] mmc: sdhci-esdhc-imx: wait for data transfer completion
> before reset
> 
> From: Luke Wang <ziniu.wang_1 at nxp.com>
> 
> On IMX7ULP platforms, certain SD cards (e.g. Kingston Canvas Go! Plus) cause
> system hangs and reboots during manual tuning. These cards exhibit large gaps
> (~16us) between tuning command response and data transmission.
> When CRC errors occur during tuning, the code assumes data errors even tuning

When cmd CRC errors occur during tuning,

> data hasn't been fully received and then reset host data circuit.
> 
> Per IMX7ULP reference manual, reset operations (RESET_DATA/ALL) need to
> make sure no active data transfers. Previously, resetting while data was in-flight
> caused unknown behavior. This patch adds polling for data transfer completion
> before executing resets.

You can show more details here for the unknown behavior, like clear the DMA address, causing bus error when use DMA transfer next data.


Regards
Haibo Chen
> 
> Signed-off-by: Luke Wang <ziniu.wang_1 at nxp.com>
> ---
>  drivers/mmc/host/sdhci-esdhc-imx.c | 15 +++++++++++++++
>  1 file changed, 15 insertions(+)
> 
> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c
> b/drivers/mmc/host/sdhci-esdhc-imx.c
> index a7a5df673b0f..affde1936510 100644
> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> @@ -1453,6 +1453,21 @@ static void esdhc_set_uhs_signaling(struct
> sdhci_host *host, unsigned timing)
> 
>  static void esdhc_reset(struct sdhci_host *host, u8 mask)  {
> +	u32 present_state;
> +	int ret;
> +
> +	/*
> +	 * For data or full reset, ensure any active data transfer completes
> +	 * before resetting to avoid system hang.
> +	 */
> +	if (mask & (SDHCI_RESET_DATA | SDHCI_RESET_ALL)) {
> +		ret = readl_poll_timeout_atomic(host->ioaddr + ESDHC_PRSSTAT,
> present_state,
> +						!(present_state & SDHCI_DATA_INHIBIT), 2,
> 100000);
> +		if (ret == -ETIMEDOUT)
> +			dev_warn(mmc_dev(host->mmc),
> +				 "timeout waiting for data transfer completion\n");
> +	}
> +
>  	sdhci_and_cqhci_reset(host, mask);
> 
>  	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
> --
> 2.34.1


From quentin.schulz at cherry.de  Wed Dec  3 02:36:10 2025
From: quentin.schulz at cherry.de (Quentin Schulz)
Date: Wed, 3 Dec 2025 11:36:10 +0100
Subject: [PATCH v2 9/9] arm64: dts: rockchip: Add the Video-Demo overlay
 for Lion Haikou
In-Reply-To: <ae0d2de5-4fc8-492c-8d46-8d90118c5e64@cherry.de>
References: <20251021074254.87065-1-heiko@sntech.de>
 <20251021074254.87065-10-heiko@sntech.de>
 <ae0d2de5-4fc8-492c-8d46-8d90118c5e64@cherry.de>
Message-ID: <66560f3d-dbb3-4c4e-a46b-8e2f604d53ed@cherry.de>

Hi Heiko,

On 12/2/25 2:37 PM, Quentin Schulz wrote:
> Hi Heiko,
> 
> On 10/21/25 9:42 AM, Heiko Stuebner wrote:
>> From: Heiko Stuebner <heiko.stuebner at cherry.de>

[...]

> I have not yet managed to make the DSI display work. It is detected but 
> modetest test pattern doesn't show, only blank.
> 

Seems like it was a classical case of PEBKAC. Haven't figured out what I 
did wrong the whole of yesterday, but it works fine today.

> Since there's only one VOP, I'm also wondering if we need to disable 
> HDMI here? Or is Linux capable of handling multiple connected displays 
> but only use one? I've tried to make DSI work with the HDMI controller 
> disabled, it didn't change anything.
> 

I can display the modetest pattern on either DSI or HDMI, when HDMI is 
used to display the pattern, DSI is not showing anything (it shows the 
console by default for me).

So no need to disable HDMI in the overlay with the DSI display.

Tested-by: Quentin Schulz <quentin.schulz at cherry.de>

Thanks!
Quentin


From jonathanh at nvidia.com  Wed Dec  3 02:44:43 2025
From: jonathanh at nvidia.com (Jon Hunter)
Date: Wed, 3 Dec 2025 10:44:43 +0000
Subject: [PATCH V3 3/3] arm64: dts: nvidia: Add nodes for CMDQV
In-Reply-To: <20251201163219.3237266-4-amhetre@nvidia.com>
References: <20251201163219.3237266-1-amhetre@nvidia.com>
 <20251201163219.3237266-4-amhetre@nvidia.com>
Message-ID: <516f57b2-cdf1-435c-8de4-978ac8b03f62@nvidia.com>



On 01/12/2025 16:32, Ashish Mhetre wrote:
> The Command Queue Virtualization (CMDQV) hardware is part of the
> SMMUv3 implementation on NVIDIA Tegra SoCs. It assists in
> virtualizing the command queue for the SMMU.
> 
> Update SMMU compatible strings to use nvidia,tegra264-smmu to enable
> CMDQV support. Add device tree nodes for the CMDQV hardware and enable
> them on the tegra264-p3834 platform where SMMUs are enabled. Each SMMU
> instance is paired with its corresponding CMDQV instance via the
> nvidia,cmdqv property.
> 
> Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
> ---
>   .../arm64/boot/dts/nvidia/tegra264-p3834.dtsi |  8 +++
>   arch/arm64/boot/dts/nvidia/tegra264.dtsi      | 55 +++++++++++++++++--
>   2 files changed, 58 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi b/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
> index 06795c82427a..7e2c3e66c2ab 100644
> --- a/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
> +++ b/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
> @@ -23,8 +23,16 @@ iommu at 5000000 {
>   			status = "okay";
>   		};
>   
> +		cmdqv at 5200000 {
> +			status = "okay";
> +		};
> +
>   		iommu at 6000000 {
>   			status = "okay";
>   		};
> +
> +		cmdqv at 6200000 {
> +			status = "okay";
> +		};
>   	};
>   };
> diff --git a/arch/arm64/boot/dts/nvidia/tegra264.dtsi b/arch/arm64/boot/dts/nvidia/tegra264.dtsi
> index f137565da804..5124715caeb3 100644
> --- a/arch/arm64/boot/dts/nvidia/tegra264.dtsi
> +++ b/arch/arm64/boot/dts/nvidia/tegra264.dtsi
> @@ -3361,7 +3361,7 @@ bus at 8100000000 {
>   			 <0x02 0x00000000 0xd0 0x00000000 0x08 0x80000000>; /* ECAM, prefetchable memory, I/O */
>   
>   		smmu1: iommu at 5000000 {
> -			compatible = "arm,smmu-v3";
> +			compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
>   			reg = <0x00 0x5000000 0x0 0x200000>;
>   			interrupts = <GIC_SPI 12 IRQ_TYPE_EDGE_RISING>,
>   				     <GIC_SPI 13 IRQ_TYPE_EDGE_RISING>;
> @@ -3370,10 +3370,19 @@ smmu1: iommu at 5000000 {
>   
>   			#iommu-cells = <1>;
>   			dma-coherent;
> +			nvidia,cmdqv = <&cmdqv1>;
> +		};
> +
> +		cmdqv1: cmdqv at 5200000 {
> +			compatible = "nvidia,tegra264-cmdqv";
> +			status = "disabled";
> +
> +			reg = <0x00 0x5200000 0x0 0x830000>;
> +			interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;

Like for other devices, the typical ordering is ...

  compatible = "nvidia,tegra264-cmdqv";
  reg = <0x00 0x5200000 0x0 0x830000>;
  interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
  status = "disabled";

So let's follow the same approach here.

Jon

-- 
nvpublic



From bisson.gary at gmail.com  Wed Dec  3 02:48:23 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Wed, 3 Dec 2025 11:48:23 +0100
Subject: [PATCH v4 3/4] arm64: dts: mediatek: add device tree for
 Tungsten 510 board
In-Reply-To: <e9edd5f2-c0ff-48fa-baf9-659dd0073e3d@collabora.com>
References: <20251202-review-v4-0-93f5cd2a0d4a@gmail.com>
 <20251202-review-v4-3-93f5cd2a0d4a@gmail.com>
 <e9edd5f2-c0ff-48fa-baf9-659dd0073e3d@collabora.com>
Message-ID: <aTAVd6wJYheV7M4p@owl5>

Hi Angelo,

On Wed, Dec 03, 2025 at 07:50:29AM +0100, AngeloGioacchino Del Regno wrote:
> Il 02/12/25 23:08, Gary Bisson ha scritto:
> > Add device tree to support Ezurio Tungsten 510 (MT8370) SMARC SOM [1] +
> > Universal SMARC carrier board [2].
> > It includes support for the MIPI-DSI BD070LIC3 display which uses the
> > Tianma TM070JDHG30 panel + TI SN65DSI84 MIPI-DSI to LVDS bridge [3].
> > 
> > [1] https://www.ezurio.com/product/tungsten510-smarc
> > [2] https://www.ezurio.com/system-on-module/accessories/universal-smarc-carrier
> > [3] https://www.ezurio.com/product/bd070lic3-7-touchscreen-display
> > 
> > Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
> > 
> 
> Hello!
> 
> Thanks for the patch, that's mostly good. Though, there are a few comments, please
> check below.

Thanks for the quick response, some comments inline below.

> > ---
> > Changes in v2:
> > - Updated nodes to be generic (pmic, i2c, usb-typec)
> > Changed in v3:
> > - None
> > Changed in v4:
> > - Fixed remaining DTB warnings
> > ---
> >   arch/arm64/boot/dts/mediatek/Makefile              |    1 +
> >   .../boot/dts/mediatek/mt8370-tungsten-smarc.dts    |   14 +
> >   .../boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi   | 1510 ++++++++++++++++++++
> >   3 files changed, 1525 insertions(+)
> > 
> > diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile
> > index a4df4c21399e..30d169a31b10 100644
> > --- a/arch/arm64/boot/dts/mediatek/Makefile
> > +++ b/arch/arm64/boot/dts/mediatek/Makefile
> > @@ -99,6 +99,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8195-demo.dtb
> >   dtb-$(CONFIG_ARCH_MEDIATEK) += mt8195-evb.dtb
> >   dtb-$(CONFIG_ARCH_MEDIATEK) += mt8365-evk.dtb
> >   dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-genio-510-evk.dtb
> > +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-tungsten-smarc.dtb
> >   dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-genio-1200-evk.dtb
> >   dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-genio-700-evk.dtb
> >   dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-kontron-3-5-sbc-i1200.dtb
> > diff --git a/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts b/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts
> > new file mode 100644
> > index 000000000000..d713ef77df3a
> > --- /dev/null
> > +++ b/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts
> > @@ -0,0 +1,14 @@
> > +// SPDX-License-Identifier: (GPL-2.0 OR MIT)
> > +/*
> > + * Copyright (C) 2025 Ezurio LLC
> > + * Author: Gary Bisson <bisson.gary at gmail.com>
> > + */
> > +/dts-v1/;
> > +#include "mt8370.dtsi"
> > +#include "mt83x0-tungsten-smarc.dtsi"
> > +
> > +/ {
> > +	model = "Ezurio Tungsten510 SMARC (MT8370)";
> > +	compatible = "ezurio,mt8370-tungsten-smarc", "mediatek,mt8370",
> > +		     "mediatek,mt8188";
> > +};
> > diff --git a/arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi b/arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi
> > new file mode 100644
> > index 000000000000..d71148d78781
> > --- /dev/null
> > +++ b/arch/arm64/boot/dts/mediatek/mt83x0-tungsten-smarc.dtsi
> > @@ -0,0 +1,1510 @@
> > +// SPDX-License-Identifier: (GPL-2.0 OR MIT)
> > +/*
> > + * Copyright (C) 2025 Ezurio LLC
> > + * Author: Gary Bisson <bisson.gary at gmail.com>
> > + */
> > +
> 
> ..snip..
> 
> > +
> > +&disp_dsi0 {
> > +	#address-cells = <1>;
> > +	#size-cells = <0>;
> > +	status = "okay";
> > +
> > +	ports {
> > +		#address-cells = <1>;
> > +		#size-cells = <0>;
> > +
> > +		port at 0 {
> > +			reg = <0>;
> > +			dsi0_in: endpoint {
> > +				remote-endpoint = <&dither0_out>;
> > +			};
> > +		};
> > +
> > +		port at 1 {
> > +			reg = <1>;
> > +			dsi0_out: endpoint {
> > +				remote-endpoint = <&sn65dsi84_bridge_in>;
> > +			};
> > +		};
> > +	};
> > +};
> > +
> > +&dither0_in {
> > +	remote-endpoint = <&postmask0_out>;
> > +};
> > +
> > +&dither0_out {
> > +	remote-endpoint = <&dsi0_in>;
> > +};
> > +
> > +&eth {
> > +	phy-mode ="rgmii-id";
> > +	phy-handle = <&ethernet_phy0>;
> > +	pinctrl-names = "default", "sleep";
> > +	pinctrl-0 = <&eth_default_pins>;
> > +	pinctrl-1 = <&eth_sleep_pins>;
> > +	mediatek,mac-wol;
> > +	snps,reset-gpio = <&pio 27 GPIO_ACTIVE_LOW>;
> > +	snps,reset-active-low;
> > +	snps,reset-delays-us = <0 11000 1000>;
> > +	status = "okay";
> > +};
> > +
> > +&eth_mdio {
> > +	ethernet_phy0: ethernet-phy at 7 {
> > +		compatible = "ethernet-phy-ieee802.3-c22";
> > +		reg = <0x7>;
> > +		interrupts-extended = <&pio 148 IRQ_TYPE_LEVEL_LOW>;
> > +	};
> > +};
> > +
> > +&gamma0_out {
> > +	remote-endpoint = <&postmask0_in>;
> > +};
> > +
> > +&gpu {
> > +	mali-supply = <&mt6359_vproc2_buck_reg>;
> > +	status = "okay";
> > +};
> > +
> > +&i2c0 {
> > +	pinctrl-names = "default";
> > +	pinctrl-0 = <&i2c0_pins>;
> > +	clock-frequency = <100000>;
> > +	status = "okay";
> > +
> > +	i2c-mux at 73 {
> > +		compatible = "nxp,pca9546";
> > +		reg = <0x73>;
> > +		pinctrl-names = "default";
> > +		pinctrl-0 = <&i2c0_mux_pins>;
> > +		reset-gpios = <&pio 6 GPIO_ACTIVE_LOW>;
> > +		#address-cells = <1>;
> > +		#size-cells = <0>;
> > +
> > +		i2c_mux_gp_0: i2c at 0 {
> > +			clock-frequency = <100000>;
> > +			reg = <0>;
> 
> reg = <0>;
> clock-frequency = ...
> 
> > +			#address-cells = <1>;
> > +			#size-cells = <0>;
> > +		};
> > +
> > +		i2c_mux_gp_1: i2c at 1 {
> > +			clock-frequency = <100000>;
> > +			reg = <1>;
> > +			#address-cells = <1>;
> > +			#size-cells = <0>;
> > +		};
> > +
> > +		i2c_mux_gp_2: i2c at 2 {
> > +			clock-frequency = <100000>;
> > +			reg = <2>;
> > +			#address-cells = <1>;
> > +			#size-cells = <0>;
> > +		};
> > +
> > +		i2c_mux_gp_3: i2c at 3 {
> > +			clock-frequency = <100000>;
> > +			reg = <3>;
> > +			#address-cells = <1>;
> > +			#size-cells = <0>;
> > +		};
> > +	};
> > +};
> > +
> > +&i2c1 {
> > +	pinctrl-names = "default";
> > +	pinctrl-0 = <&i2c1_pins>;
> > +	clock-frequency = <400000>;
> > +	status = "okay";
> > +};
> > +
> > +&i2c2 {
> > +	pinctrl-names = "default";
> > +	pinctrl-0 = <&i2c2_pins>;
> > +	clock-frequency = <400000>;
> > +	status = "okay";
> > +
> > +	i2c-mux at 73 {
> > +		compatible = "nxp,pca9546";
> > +		pinctrl-names = "default";
> > +		pinctrl-0 = <&i2c_mux_smarc_lcd_pins>;
> > +		reg = <0x73>;
> > +		reset-gpios = <&pio 5 GPIO_ACTIVE_LOW>;
> > +		#address-cells = <1>;
> > +		#size-cells = <0>;
> > +
> > +		i2c_mux_lcd_0: i2c at 0 {
> > +			clock-frequency = <100000>;
> > +			reg = <0>;
> > +			#address-cells = <1>;
> > +			#size-cells = <0>;
> > +		};
> > +
> > +		i2c_mux_lcd_1: i2c at 1 {
> > +			clock-frequency = <100000>;
> > +			reg = <1>;
> > +			#address-cells = <1>;
> > +			#size-cells = <0>;
> > +		};
> > +
> > +		i2c_mux_lcd_2: i2c at 2 {
> > +			clock-frequency = <100000>;
> > +			reg = <2>;
> > +			#address-cells = <1>;
> > +			#size-cells = <0>;
> > +		};
> > +
> > +		i2c_mux_lcd_3: i2c at 3 {
> > +			clock-frequency = <100000>;
> > +			reg = <3>;
> > +			#address-cells = <1>;
> > +			#size-cells = <0>;
> > +		};
> > +	};
> > +};
> > +
> > +&i2c3 {
> > +	pinctrl-names = "default";
> > +	pinctrl-0 = <&i2c3_pins>;
> > +	clock-frequency = <400000>;
> > +	status = "okay";
> > +};
> > +
> > +&i2c4 {
> > +	pinctrl-names = "default";
> > +	pinctrl-0 = <&i2c4_pins>;
> > +	clock-frequency = <400000>;
> > +	status = "okay";
> > +};
> > +
> > +&i2c_mux_gp_0 {
> > +	rv3028: rtc at 52 {
> > +		compatible = "microcrystal,rv3028";
> > +		reg = <0x52>;
> > +		interrupts-extended = <&pio 42 IRQ_TYPE_LEVEL_LOW>;
> > +		pinctrl-names = "default";
> > +		pinctrl-0 = <&rv3028_pins>;
> > +		#clock-cells = <0>;
> > +		wakeup-source;
> > +	};
> > +};
> > +
> > +&i2c_mux_gp_1 {
> > +	usb-typec at 60 {
> > +		compatible = "ti,hd3ss3220";
> 
> reg always goes after compatible.
> 
> > +		interrupts-extended = <&pio 45 IRQ_TYPE_LEVEL_LOW>;
> > +		pinctrl-names = "default";
> > +		pinctrl-0 = <&hd3ss3220_pins>;
> > +		reg = <0x60>;
> > +
> > +		ports {
> > +			#address-cells = <1>;
> > +			#size-cells = <0>;
> > +
> > +			port at 0 {
> > +				reg = <0>;
> > +				hd3ss3220_in_ep: endpoint {
> > +					remote-endpoint = <&ss_ep>;
> > +				};
> > +			};
> > +
> > +			port at 1 {
> > +				reg = <1>;
> > +				hd3ss3220_out_ep: endpoint {
> > +					remote-endpoint = <&usb_role_switch>;
> > +				};
> > +			};
> > +		};
> > +	};
> > +};
> > +
> > +&i2c_mux_gp_2 {
> > +	codec at 1a {
> 
> compatible
> reg
> clocks
> gpio-cfg
> 
> supplies
> 
> P.S.: Please read
> https://docs.kernel.org/devicetree/bindings/dts-coding-style.html

Noted, thanks. However for the wm8962 the gpio-cfg is recommended at the
per its doc, hope that's ok
("Documentation/devicetree/bindings/sound/wlf,wm8962.yaml).

> > +		#sound-dai-cells = <0>;
> > +		AVDD-supply = <&reg_1v8>;
> > +		CPVDD-supply = <&reg_1v8>;
> > +		DBVDD-supply = <&reg_3v3>;
> > +		DCVDD-supply = <&reg_1v8>;
> > +		MICVDD-supply = <&reg_3v3>;
> > +		PLLVDD-supply = <&reg_1v8>;
> > +		SPKVDD1-supply = <&reg_5v>;
> > +		SPKVDD2-supply = <&reg_5v>;
> > +		clocks = <&topckgen CLK_TOP_I2SO1>;
> > +		compatible = "wlf,wm8962";
> > +		gpio-cfg = <
> > +			0x0000 /* n/c */
> > +			0x0000 /* gpio2: */
> > +			0x0000 /* gpio3: */
> > +			0x0000 /* n/c */
> > +			0x8081 /* gpio5:HP detect */
> > +			0x8095 /* gpio6:Mic detect */
> > +		>;
> > +		reg = <0x1a>;
> > +	};
> > +};
> > +
> > +&i2c_mux_lcd_2 {
> > +	#address-cells = <1>;
> > +	#size-cells = <0>;
> > +
> > +	bridge at 2c {
> > +		compatible = "ti,sn65dsi84";
> > +		reg = <0x2c>;
> > +		enable-gpios = <&pio 25 GPIO_ACTIVE_HIGH>;
> > +		pinctrl-names = "default";
> > +		pinctrl-0 = <&dsi0_sn65dsi84_pins>;
> > +
> > +		ports {
> > +			#address-cells = <1>;
> > +			#size-cells = <0>;
> > +
> > +			port at 0 {
> > +				reg = <0>;
> > +
> > +				sn65dsi84_bridge_in: endpoint {
> > +					remote-endpoint = <&dsi0_out>;
> > +					data-lanes = <1 2 3 4>;
> > +				};
> > +			};
> > +
> > +			port at 2 {
> > +				reg = <2>;
> > +
> > +				sn65dsi84_bridge_out: endpoint {
> > +					remote-endpoint = <&dsi0_panel_in>;
> > +				};
> > +			};
> > +		};
> > +	};
> > +
> > +	touchscren at 5d {
> > +		compatible = "goodix,gt911";
> > +		reg = <0x5d>;
> > +		pinctrl-names = "default";
> > +		pinctrl-0 = <&ts_dsi0_goodix_pins>;
> > +		interrupts-extended = <&pio 146 IRQ_TYPE_LEVEL_HIGH>;
> > +		irq-gpios = <&pio 146 GPIO_ACTIVE_HIGH>;
> > +		reset-gpios = <&pio 7 GPIO_ACTIVE_HIGH>;
> > +	};
> > +};
> > +
> > +&mfg0 {
> > +	domain-supply = <&mt6359_vproc2_buck_reg>;
> > +};
> > +
> > +&mfg1 {
> > +	domain-supply = <&mt6359_vsram_others_ldo_reg>;
> > +};
> > +
> > +&mmc0 {
> > +	status = "okay";
> > +	pinctrl-names = "default", "state_uhs";
> > +	pinctrl-0 = <&mmc0_default_pins>;
> > +	pinctrl-1 = <&mmc0_uhs_pins>;
> > +	bus-width = <8>;
> > +	max-frequency = <200000000>;
> > +	cap-mmc-highspeed;
> > +	cap-mmc-hw-reset;
> > +	mmc-hs200-1_8v;
> > +	mmc-hs400-1_8v;
> > +	supports-cqe;
> > +	cap-mmc-hw-reset;
> 
> You added cap-mmc-hw-reset twice.
> 
> > +	no-sdio;
> > +	no-sd;
> > +	hs400-ds-delay = <0x1481b>;
> > +	vmmc-supply = <&mt6359_vemc_1_ldo_reg>;
> > +	vqmmc-supply = <&mt6359_vufs_ldo_reg>;
> > +	non-removable;
> 
> Also, please reorder by name:
> 
> bus-width ...
> cap-mmc-highspeed;
> cap-mmc-hw-reset;
> hs400-ds-delay....
> max-frequency ....
> mmc-hs200-1_8v;
> mmc-hs400-1_8v;
> no-sd;
> no-sdio;
> non-removable;
> supports-cqe;
> 
> pinctrl properties
> 
> power supplies
> 
> status

Will do, note that this is a copy/paste of the already-upstream
mt8390-genio-common.dtsi.

> > +};
> > +
> > +&mmc1 {
> > +	status = "okay";
> > +	pinctrl-names = "default", "state_uhs";
> > +	pinctrl-0 = <&mmc1_default_pins>;
> > +	pinctrl-1 = <&mmc1_uhs_pins>;
> > +	bus-width = <4>;
> > +	max-frequency = <200000000>;
> > +	cap-sd-highspeed;
> > +	sd-uhs-sdr50;
> > +	sd-uhs-sdr104;
> > +	cd-gpios = <&pio 2 GPIO_ACTIVE_LOW>;
> > +	vqmmc-supply = <&mt6359_vsim1_ldo_reg>;
> > +	vmmc-supply = <&sdcard_en_3v3>;
> > +};
> > +
> > +&mmc2 {
> > +	status = "okay";
> 
> status at the end please
> 
> > +	pinctrl-names = "default", "state_uhs", "state_eint";
> > +	pinctrl-0 = <&mmc2_default_pins>;
> > +	pinctrl-1 = <&mmc2_uhs_pins>;
> > +	pinctrl-2 = <&mmc2_eint_pins>;
> 
> Sorry, but I truly hate /delete-property/.
> 
> > +	/delete-property/ interrupts;
> > +	interrupt-names = "msdc", "sdio_wakeup";
> > +	interrupts-extended = <&gic GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH 0>,
> > +			      <&pio 172 IRQ_TYPE_LEVEL_LOW>;
> 
> You're lucky in this case, though, because you're the first user of MMC2! :-)
> 
> The solution here is:
>  - Change the interrupts property in mt8188.dtsi on mmc at 1125000 to
>    `interrupts-extended = <&gic GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH 0>;`
>  - Override it here without `/delete-property/ interrupts;`

Ok, will do a mt8188 patch then, I'll modify all mmc nodes that way to
be consistent.

> > +	bus-width = <4>;
> 
> Please order the properties by name (bar X-supply, Y-pwrseq, status that go at
> the end).
> 
> > +	max-frequency = <200000000>;
> > +	cap-sd-highspeed;
> > +	sd-uhs-sdr104;
> > +	keep-power-in-suspend;
> > +	wakeup-source;
> > +	cap-sdio-irq;
> > +	no-mmc;
> > +	no-sd;
> > +	non-removable;
> > +	vmmc-supply = <&mt6359_vcn33_2_bt_ldo_reg>;
> > +	vqmmc-supply = <&mt6359_vcn18_ldo_reg>;
> > +	mmc-pwrseq = <&wifi_pwrseq>;
> > +};
> > +
> > +&mipi_tx_config0 {
> > +	status = "okay";
> > +};
> > +
> > +&mt6359codec {
> > +	mediatek,mic-type-0 = <1>;
> > +	mediatek,mic-type-1 = <3>;
> 
> You can drop mic-type-2 and dmic-mode, as the defaults for these are already zero.
> 
> > +	mediatek,mic-type-2 = <0>;
> > +	mediatek,dmic-mode = <0>;
> > +};
> > +
> 
> ..snip..
> 
> > +
> > +&mt6359_vproc2_buck_reg {
> > +	/* The name "vgpu" is required by mtk-regulator-coupler */
> > +	regulator-name = "vgpu";
> > +	regulator-min-microvolt = <550000>;
> > +	regulator-max-microvolt = <800000>;
> > +	regulator-coupled-with = <&mt6359_vsram_others_ldo_reg>;
> > +	regulator-coupled-max-spread = <225000>;
> > +	regulator-always-on;
> 
> You don't need regulator-always-on here.
> 
> > +};
> > +
> > +&mt6359_vs2_buck_reg {
> > +	regulator-min-microvolt = <1600000>;
> > +	regulator-boot-on;
> > +};
> > +
> > +&mt6359_vpu_buck_reg {
> > +	regulator-name = "dvdd_adsp";
> 
> Is that for the MediaTek Audio DSP?

Yes and no, this design matches the EVK one from MTK on that rail, which
means the same rail is used as:
- DVDD_ADSP
- DVDD_SRAM_CORE
- DVDD_SRAM_MM
- AVDD075_DRV_DSI

> Thought Genio 500/700 were kind of "special" in having one just for that.
> 
> If so, you have to do this properly and add this to the ADSP power domain as a
> domain-supply, if this effectively enables basic power to the ADSP itself.
> 
> To do so, you must also change drivers/pmdomain/mediatek/mt8188-pm-domains.h and in
> MT8188_POWER_DOMAIN_ADSP you want to change `.caps` to
> 
> .caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_SRAM_ISO | MTK_SCPD_ACTIVE_WAKEUP |
> 	MTK_SCPD_DOMAIN_SUPPLY,
> 
> ...so that you can remove the regulator-always-on property here, and benefit from a
> nice bump in power efficiency (as you stop power leakages like so).

Considering the comment above, is it ok to leave it as-is (like it is
done in the mt8390-genio-common.dtsi)? Or would you like to change the
reg name to make it more obvious it's not only for adsp?

> > +	regulator-always-on;
> > +};
> > +
> > +&mt6359_vrf12_ldo_reg {
> > +	regulator-name = "va12_abb2_pmu";
> > +	regulator-always-on;
> > +};
> > +
> > +&mt6359_vsram_md_ldo_reg {
> > +	regulator-always-on;
> > +};
> > +
> > +&mt6359_vsram_others_ldo_reg {
> > +	/* The name "vsram_gpu" is required by mtk-regulator-coupler */
> > +	regulator-name = "vsram_gpu";
> > +	regulator-min-microvolt = <750000>;
> > +	regulator-max-microvolt = <800000>;
> > +	regulator-coupled-with = <&mt6359_vproc2_buck_reg>;
> > +	regulator-coupled-max-spread = <225000>;
> > +	regulator-always-on;
> 
> You don't need regulator-always-on here.
> 
> > +};
> > +
> > +&mt6359_vsim1_ldo_reg {
> > +	regulator-name = "vsim1_pmu";
> > +	regulator-max-microvolt = <1800000>;
> > +	regulator-enable-ramp-delay = <480>;
> > +};
> > +
> > +&mt6359_vufs_ldo_reg {
> > +	regulator-name = "vufs18_pmu";
> > +	regulator-always-on;
> > +};
> > +
> > +&ovl0_in {
> > +	remote-endpoint = <&vdosys0_ep_main>;
> > +};
> > +
> > +&pcie {
> > +	pinctrl-names = "default";
> > +	pinctrl-0 = <&pcie_default_pins>;
> > +	status = "okay";
> > +};
> > +
> > +&pciephy {
> > +	status = "okay";
> > +};
> > +
> > +&pmic {
> > +	interrupt-parent = <&pio>;
> > +	interrupts = <222 IRQ_TYPE_LEVEL_HIGH>;
> 
> Instead of interrupt-parent and interrupts, you can do:
> 
> interrupts-extended = <&pio 222 IRQ_TYPE_LEVEL_HIGH>;
> 
> > +
> > +	keys {
> > +		compatible = "mediatek,mt6359-keys";
> > +		mediatek,long-press-mode = <1>;
> > +		power-off-time-sec = <0>;
> > +
> > +		power-key {
> > +			linux,keycodes = <116>;
> 
> At the top of the file, properly ordered:
> #include <dt-bindings/input/linux-event-codes.h>
> 
> ...then, here:
> linux,keycodes = <KEY_POWER>;
> 
> > +			wakeup-source;
> > +		};
> > +	};
> > +};
> > +
> > +&postmask0_in {
> > +	remote-endpoint = <&gamma0_out>;
> > +};
> > +
> > +&postmask0_out {
> > +	remote-endpoint = <&dither0_in>;
> > +};
> > +
> > +&scp_cluster {
> > +	status = "okay";
> > +};
> > +
> > +&scp_c0 {
> > +	firmware-name = "mediatek/mt8188/scp.img";
> 
> You don't need (and can't have) firmware-name upstream: drop it.

Oops, that's a copy/paste from the collabora tree ;)

> > +	memory-region = <&scp_mem>;
> > +	status = "okay";
> > +};
> > +
> > +&spi0 {
> > +	pinctrl-0 = <&spi0_pins>;
> > +	pinctrl-names = "default";
> > +	mediatek,pad-select = <0>;
> 
> vendor properties always at the end, before status = "okay";
> 
> > +	#address-cells = <1>;
> > +	#size-cells = <0>;
> 
> ...but anyway, #address-cells, #size-cells are already declared in mt8188.dtsi and
> they even have the same values that you're assigning here. Drop those.
> 
> > +	status = "okay";
> > +};
> > +
> > +&spi1 {
> > +	pinctrl-0 = <&spi1_pins>;
> > +	pinctrl-names = "default";
> > +	mediatek,pad-select = <0>;
> 
> same comments apply here as well.
> 
> > +	#address-cells = <1>;
> > +	#size-cells = <0>;
> > +	status = "okay";
> > +};
> > +
> 
> ..snip..
> 
> > +&uart0 {
> > +	pinctrl-0 = <&uart0_pins>;
> > +	pinctrl-names = "default";
> > +	status = "okay";
> > +};
> > +
> > +&uart1 {
> > +	pinctrl-0 = <&uart1_pins>;
> > +	pinctrl-names = "default";
> > +	status = "okay";
> > +};
> > +
> > +&uart2 {
> > +	pinctrl-0 = <&uart2_pins>;
> > +	pinctrl-names = "default";
> > +	status = "okay";
> > +};
> > +
> > +&ssusb0 {
> 
> Please reorder:
> 
> dr_mode
> maximum-speed
> usb-role-switch;
> wakeup-source;
> pinctrl-0
> pinctrl-names
> vusb33-supply
> status

Ok, will rework all ports.

> > +	pinctrl-names = "default";
> > +	pinctrl-0 = <&usbotg_pins>;
> > +	maximum-speed = "high-speed";
> > +	usb-role-switch;
> > +	dr_mode = "otg";
> > +	vusb33-supply = <&mt6359_vusb_ldo_reg>;
> > +	wakeup-source;
> > +	status = "okay";
> > +
> > +	connector {
> > +		compatible = "usb-c-connector";
> > +		label = "USB-C";
> > +		data-role = "dual";
> > +
> > +		ports {
> > +			#address-cells = <1>;
> > +			#size-cells = <0>;
> > +
> > +			port at 0 {
> > +				reg = <0>;
> > +				hs_ep: endpoint {
> > +					remote-endpoint = <&usb_hs_ep>;
> > +				};
> > +			};
> > +
> > +			port at 1 {
> > +				reg = <1>;
> > +				ss_ep: endpoint {
> > +					remote-endpoint = <&hd3ss3220_in_ep>;
> > +				};
> > +			};
> > +		};
> > +	};
> > +
> > +	ports {
> > +		#address-cells = <1>;
> > +		#size-cells = <0>;
> > +
> > +		port at 0 {
> > +			reg = <0>;
> > +			usb_hs_ep: endpoint {
> > +				remote-endpoint = <&hs_ep>;
> > +			};
> > +		};
> > +
> > +		port at 1 {
> > +			reg = <1>;
> > +			usb_role_switch: endpoint {
> > +				remote-endpoint = <&hd3ss3220_out_ep>;
> > +			};
> > +		};
> > +	};
> > +};
> > +
> > +&u2port0 {
> > +	status = "okay";
> > +};
> > +
> > +&u3phy0 {
> > +	status = "okay";
> > +};
> > +
> > +&xhci0 {
> > +	vbus-supply = <&usb_p0_vbus>;
> > +	vusb33-supply = <&mt6359_vusb_ldo_reg>;
> > +	status = "okay";
> > +};
> > +
> > +&ssusb1 {
> 
> Please reorder:
> 
> dr_mode
> maximum-speed
> wakeup-source
> pinctrl-0
> pinctrl-names
> vusb33-supply
> status
> 
> > +	pinctrl-0 = <&usb1_pins>;
> > +	pinctrl-names = "default";
> > +	vusb33-supply = <&mt6359_vusb_ldo_reg>;
> > +	dr_mode = "host";
> > +	wakeup-source;
> > +	status = "okay";
> > +};
> > +
> > +&u2port1 {
> > +	status = "okay";
> > +};
> > +
> > +&u3port1 {
> > +	status = "okay";
> > +};
> > +
> > +&u3phy1 {
> > +	status = "okay";
> > +};
> > +
> > +&xhci1 {
> > +	vbus-supply = <&usb_p1_vbus>;
> > +	vusb33-supply = <&mt6359_vusb_ldo_reg>;
> > +	status = "okay";
> > +};
> > +
> > +&ssusb2 {
> 
> Please reorder:
> 
> dr_mode
> maximum-speed
> wakeup-source
> vusb33-supply
> status
> 
> > +	maximum-speed = "high-speed";
> > +	dr_mode = "host";
> > +	vusb33-supply = <&mt6359_vusb_ldo_reg>;
> > +	status = "okay";
> > +	wakeup-source;
> > +};
> > +
> ..snip..
> 
> > +&vdosys0 {
> > +	port {
> > +		#address-cells = <1>;
> > +		#size-cells = <0>;
> > +
> > +		vdosys0_ep_main: endpoint at 0 {
> > +			reg = <0>;
> > +			remote-endpoint = <&ovl0_in>;
> > +		};
> > +	};
> > +};
> > +
> > +&watchdog {
> > +	pinctrl-names = "default";
> > +	pinctrl-0 = <&watchdog_pins>;
> > +};
> > +
> > +&pio {
> > +	audio_pins: audio-pins {
> > +		pins-aud-pmic {
> > +			pinmux = <
> > +				PINMUX_GPIO101__FUNC_O_AUD_CLK_MOSI
> > +				PINMUX_GPIO102__FUNC_O_AUD_SYNC_MOSI
> > +				PINMUX_GPIO103__FUNC_O_AUD_DAT_MOSI0
> > +				PINMUX_GPIO104__FUNC_O_AUD_DAT_MOSI1
> > +				PINMUX_GPIO105__FUNC_I0_AUD_DAT_MISO0
> > +				PINMUX_GPIO106__FUNC_I0_AUD_DAT_MISO1
> > +			>;
> 
> You don't need the extra lines...
> 
> 			pinmux = <PINMUX_GPIO101__FUNC_O_AUD_CLK_MOSI
> 				  PINMUX_GPIO102__FUNC_O_AUD_SYNC_MOSI
> 				  PINMUX_GPIO103__FUNC_O_AUD_DAT_MOSI0
> 				  PINMUX_GPIO104__FUNC_O_AUD_DAT_MOSI1
> 				  PINMUX_GPIO105__FUNC_I0_AUD_DAT_MISO0
> 				  PINMUX_GPIO106__FUNC_I0_AUD_DAT_MISO1>;
> 
> here and everywhere else please :-)
> 		
> > +		};
> > +
> > +		pins-pcm-wifi {
> > +			pinmux = <
> > +				PINMUX_GPIO121__FUNC_B0_PCM_CLK
> > +				PINMUX_GPIO122__FUNC_B0_PCM_SYNC
> > +				PINMUX_GPIO123__FUNC_O_PCM_DO
> > +				PINMUX_GPIO124__FUNC_I0_PCM_DI
> > +			>;
> > +		};
> > +
> > +		pins-i2s {
> > +			pinmux = <
> > +				PINMUX_GPIO119__FUNC_O_I2SO1_MCK
> > +				PINMUX_GPIO112__FUNC_O_I2SO1_WS
> > +				PINMUX_GPIO120__FUNC_O_I2SO1_BCK
> > +				PINMUX_GPIO113__FUNC_O_I2SO1_D0
> > +				PINMUX_GPIO110__FUNC_I0_I2SIN_D0
> > +			>;
> > +		};
> > +	};
> > +
> > +	disp_pwm0_pins: disp-pwm0-pins {
> > +		pins {
> > +			pinmux = <PINMUX_GPIO29__FUNC_O_DISP_PWM0>;
> > +			bias-pull-down;
> > +		};
> > +	};
> > +
> > +	dsi0_sn65dsi84_pins: dsi0-sn65dsi84-pins {
> > +		pins-irq {
> > +			pinmux = <PINMUX_GPIO128__FUNC_B_GPIO128>;
> > +			bias-pull-down;
> > +			input-enable;
> > +		};
> > +
> > +		pins-enable {
> > +			pinmux = <PINMUX_GPIO25__FUNC_B_GPIO25>;
> > +			bias-pull-down;
> > +		};
> > +	};
> > +
> > +	eth_default_pins: eth-default-pins {
> > +		pins-txd {
> > +			pinmux = <PINMUX_GPIO131__FUNC_O_GBE_TXD3>,
> > +				 <PINMUX_GPIO132__FUNC_O_GBE_TXD2>,
> > +				 <PINMUX_GPIO133__FUNC_O_GBE_TXD1>,
> > +				 <PINMUX_GPIO134__FUNC_O_GBE_TXD0>;
> > +			drive-strength = <MTK_DRIVE_8mA>;
> 
> Please don't use the MTK_DRIVE_x macros, we are in the process of removing them.
> 
> All those macros are defining the .. same number that you can read in the macro
> itself; as in:
> 
> MTK_DRIVE_(n)mA = n -> MTK_DRIVE_8mA = 8
> 
> So, remove all of them and use numbers directly.
> In this specific case it is `drive-strength = <8>;` - please do this here and
> everywhere else.

Ok. Should be able to offer a new revision later today.

Thanks,
Gary


From kory.maincent at bootlin.com  Wed Dec  3 02:49:41 2025
From: kory.maincent at bootlin.com (Kory Maincent)
Date: Wed, 3 Dec 2025 11:49:41 +0100
Subject: [PATCH 00/21] Clean and update tilcdc driver to support
 DRM_BRIDGE_ATTACH_NO_CONNECTOR
In-Reply-To: <7b8e22d1-a872-4ea0-8fce-4323d2bf81ff@ti.com>
References: <20251126-feature_tilcdc-v1-0-49b9ef2e3aa0@bootlin.com>
	<7b8e22d1-a872-4ea0-8fce-4323d2bf81ff@ti.com>
Message-ID: <20251203114941.1fafd9dd@kmaincent-XPS-13-7390>

On Tue, 2 Dec 2025 17:55:15 +0530
Swamil Jain <s-jain1 at ti.com> wrote:

> Hi Kory,
> Thanks for the series.
> 
> On 11/26/25 23:05, Kory Maincent (TI.com) wrote:
> > The starting point for this work was adding support for the HDMI cape:
> > https://www.seeedstudio.com/Seeed-Studio-BeagleBone-Green-HDMI-Cape.html
> > This will be sent in a later series.
> > 
> > Initially, Miguel proposed modifying the ite-it66121 bridge to support
> > the legacy behavior without the DRM_BRIDGE_ATTACH_NO_CONNECTOR flag:
> > https://lore.kernel.org/lkml/20250909-it66121-fix-v1-1-bc79ca83df17 at bootlin.com/
> > This patch was NAK'd as we don't want to add more legacy code. Maxime
> > requested that the tilcdc driver be updated to use
> > DRM_BRIDGE_ATTACH_NO_CONNECTOR instead.
> > 
> > While working on this update, I discovered that the tilcdc driver
> > contained significant amounts of legacy code that needed cleaning.
> > Since this driver was developed alongside the tda998x driver for
> > several AM335x boards, the tda998x driver also required cleanup and
> > support for the DRM_BRIDGE_ATTACH_NO_CONNECTOR flag.
> > 
> > This series is based on the tilcdc fix sent to mainline:
> > https://lore.kernel.org/lkml/20251125090546.137193-1-kory.maincent at bootlin.com/
> > 
> > Patch 1-7: Convert tilcdc binding to YAML and remove the ti,tilcdc,panel
> > 	   sub-binding and driver
> > Patch 8-16: Clean up tilcdc driver
> > Patch 17-19: Clean up tda998x driver
> > Patch 20: Add DRM_BRIDGE_ATTACH_NO_CONNECTOR support to tda998x
> > Patch 21: Add DRM_BRIDGE_ATTACH_NO_CONNECTOR support to tilcdc
> > 
> > Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
> > ---
> > Kory Maincent (TI.com) (21):
> >        dt-bindings: display: tilcdc: Convert to DT schema
> >        dt-bindings: display: tilcdc: Add fifo-threshold property
> >        drm/tilcdc: Remove simulate_vesa_sync flag
> >        drm/tilcdc: Add support for DRM bus flags and simplify panel config
> >        ARM: dts: omap: Bind panel to panel-dpi instead of ti,tilcdc,panel
> > driver dt-bindings: display: tilcdc: Remove panel binding
> >        drm/tilcdc: Remove tilcdc panel driver
> >        drm/tilcdc: Remove component framework support
> >        drm/tilcdc: Remove tilcdc_panel_info structure
> >        drm/tilcdc: Remove redundant #endif/#ifdef in debugfs code
> >        drm/tilcdc: Remove unused encoder and connector tracking arrays
> >        drm/tilcdc: Rename external_encoder and external_connector to
> > encoder and connector drm/tilcdc: Rename tilcdc_external to tilcdc_encoder
> >        drm/tilcdc: Remove the useless module list support
> >        drm/tilcdc: Modernize driver initialization and cleanup paths
> >        drm/tilcdc: Remove the use of drm_device private_data
> >        drm/bridge: tda998x: Remove component support
> >        drm/bridge: tda998x: Move tda998x_create/destroy into probe and
> > remove drm/bridge: tda998x: Remove useless tda998x_connector_destroy wrapper
> >        drm/bridge: tda998x: Add support for DRM_BRIDGE_ATTACH_NO_CONNECTOR
> >        drm/tilcdc: Add support for DRM_BRIDGE_ATTACH_NO_CONNECTOR
> > 
> >   .../devicetree/bindings/display/tilcdc/panel.txt   |  66 ---
> >   .../devicetree/bindings/display/tilcdc/tilcdc.txt  |  82 ----
> >   .../devicetree/bindings/display/tilcdc/tilcdc.yaml | 103 +++++
> >   arch/arm/boot/dts/ti/davinci/da850-evm.dts         |  26 +-
> >   arch/arm/boot/dts/ti/omap/am335x-guardian.dts      |  25 +-
> >   arch/arm/boot/dts/ti/omap/am335x-pdu001.dts        |  21 +-
> >   arch/arm/boot/dts/ti/omap/am335x-pepper.dts        |  22 +-
> >   arch/arm/boot/dts/ti/omap/am335x-sbc-t335.dts      |  25 +-
> >   arch/arm/boot/dts/ti/omap/am335x-sl50.dts          |  25 +-
> >   drivers/gpu/drm/bridge/tda998x_drv.c               | 251 ++++++------
> >   drivers/gpu/drm/tilcdc/Makefile                    |   3 +-
> >   drivers/gpu/drm/tilcdc/tilcdc_crtc.c               | 117 ++----
> >   drivers/gpu/drm/tilcdc/tilcdc_drv.c                | 456
> > +++++++-------------- drivers/gpu/drm/tilcdc/tilcdc_drv.h                |
> > 88 +--- drivers/gpu/drm/tilcdc/tilcdc_encoder.c            |  93 +++++
> >   .../tilcdc/{tilcdc_external.h => tilcdc_encoder.h} |   5 +-
> >   drivers/gpu/drm/tilcdc/tilcdc_external.c           | 179 --------
> >   drivers/gpu/drm/tilcdc/tilcdc_panel.c              | 408
> > ------------------ drivers/gpu/drm/tilcdc/tilcdc_panel.h              |  15
> > - drivers/gpu/drm/tilcdc/tilcdc_plane.c              |   2 +-
> >   drivers/gpu/drm/tilcdc/tilcdc_regs.h               |   8 +-
> >   21 files changed, 589 insertions(+), 1431 deletions(-)
> > ---
> > base-commit: 670bacfc7579bdd79a3069cfb5ab60a6a7923003  
> 
> I was trying to test the patches, unable to find the base-commit, are
> you using drm-misc-next?

It is based on the tilcdc fix as explained in the cover letter.
https://lore.kernel.org/lkml/20251125090546.137193-1-kory.maincent at bootlin.com/
Therefore you won't be able to find this base commit hash. 

Regards,
-- 
K?ry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com


From punit.agrawal at oss.qualcomm.com  Wed Dec  3 03:04:09 2025
From: punit.agrawal at oss.qualcomm.com (Punit Agrawal)
Date: Wed, 03 Dec 2025 11:04:09 +0000
Subject: [PATCH 0/8] firmware: arm_scmi: Refactoring and enablement of
 ACPI PCC transport
In-Reply-To: <20251126-camouflaged-delightful-cuckoo-ddeac8@sudeepholla>
	(Sudeep Holla's message of "Wed, 26 Nov 2025 14:31:30 +0000")
References: <20251017-acpi_scmi_pcc-v1-0-0adbab7709d9@arm.com>
	<87wm44aect.fsf@stealth>
	<20251126-camouflaged-delightful-cuckoo-ddeac8@sudeepholla>
Message-ID: <877bv3n7x2.fsf@stealth>

Hi Sudeep,

Sudeep Holla <sudeep.holla at arm.com> writes:

> On Wed, Nov 05, 2025 at 11:49:38AM +0000, Punit Agrawal wrote:
>> Hi Sudeep,
>> 
>> Sudeep Holla <sudeep.holla at arm.com> writes:
>> 
>> > The SCMI can be utilized in systems using either the FDT or ACPI specification.
>> > While FDT-based systems can natively use SCMI, ACPI-based systems often
>> > need to abstract the functionality provided by SCMI under ASL methods.
>> > So far, there has been no need to support SCMI natively on ACPI systems.
>> >
>> > However, with the addition of a few new protocols such as Powercap and Telemetry,
>> > which lack abstractions in the ACPI specification, there is now a need to
>> > run SCMI natively for those use cases.
>> >
>> > This patch series introduces ACPI PCC transport support for the Arm SCMI
>> > framework, alongside several foundational refactors and enhancements to
>> > achieve firmware-node neutrality between Device Tree (DT) and ACPI systems.
>> >
>> > The key changes include:
>> >
>> > 1. ACPI/DT abstraction and fwnode transition
>> >
>> >    Converted the core SCMI code to use `fwnode_handle` instead of DT-specific
>> >    structures, ensuring seamless operation across both ACPI and DT
>> >    environments. All property lookups, child enumeration, and device
>> >    association paths have been updated accordingly.
>> >
>> > 2. Unified transport registration for ACPI and DT
>> >
>> >    Extended the SCMI transport driver macros to support ACPI match tables,
>> >    enabling transports to probe using ACPI device IDs while maintaining
>> >    backward compatibility with DT-only systems.
>> >
>> > 3. Protocol device initialization and refactoring
>> >
>> >    Refactored the protocol device creation and validation logic into a new
>> >    helper for improved readability and maintainability. Enhanced the
>> >    initialization logic to handle ACPI-based SCMI devices without explicit
>> >    child fwnodes.
>> >
>> > 4. Introduction of ACPI PCC transport
>> >
>> >    Added a new SCMI transport driver leveraging ACPI PCCT (Platform
>> >    Communications Channel Table) subspaces via the Linux PCC mailbox
>> >    framework. This enables SCMI communication over PCC on ACPI-based
>> >    platforms.
>> >
>> > Collectively, these changes lay the groundwork for robust SCMI operation on
>> > ACPI platforms, achieving near parity with DT systems where applicable,
>> > while enabling the new PCC transport path for firmware communication.
>> 
>> I was interested in taking a closer look at the patches here but they
>> have a dependency on support for the telemetry protocol patches. I get a
>> compile error.
>> 
>> I was wondering if you have a branch with the dependencies included. Are
>> the v1 telemetry support patches[0] the right version to be using?
>>
>
> I can create one but that is not strictly necessary. As mentioned in the
> cover letter, the only dependency is on value of SCMI_PROTOCOL_TELEMETRY
> ins `scmi_std_protocol` enumeration. Just add one and you must be able to
> compile the series independent of Cristian series.

Thanks, I managed to get the patches building. Looking forward to the
series progressing. If possible, do keep me in the loop for future
updates.


From amhetre at nvidia.com  Wed Dec  3 03:04:10 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Wed, 3 Dec 2025 16:34:10 +0530
Subject: [PATCH V3 1/3] iommu/arm-smmu-v3: Add device-tree support for
 CMDQV driver
In-Reply-To: <202512031601.IpliwbHW-lkp@intel.com>
References: <20251201163219.3237266-2-amhetre@nvidia.com>
 <202512031601.IpliwbHW-lkp@intel.com>
Message-ID: <47684b91-7c0f-4260-abfd-2795fdaa2b31@nvidia.com>


On 12/3/2025 2:05 PM, kernel test robot wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Ashish,
>
> kernel test robot noticed the following build errors:
>
> [auto build test ERROR on next-20251201]
> [also build test ERROR on v6.18]
> [cannot apply to robh/for-next linus/master v6.18 v6.18-rc7 v6.18-rc6]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
>
> url:    https://github.com/intel-lab-lkp/linux/commits/Ashish-Mhetre/iommu-arm-smmu-v3-Add-device-tree-support-for-CMDQV-driver/20251202-003517
> base:   next-20251201
> patch link:    https://lore.kernel.org/r/20251201163219.3237266-2-amhetre%40nvidia.com
> patch subject: [PATCH V3 1/3] iommu/arm-smmu-v3: Add device-tree support for CMDQV driver
> config: arm64-allmodconfig (https://download.01.org/0day-ci/archive/20251203/202512031601.IpliwbHW-lkp at intel.com/config)
> compiler: clang version 19.1.7 (https://github.com/llvm/llvm-project cd708029e0b2869e80abe31ddb175f7c35361f90)
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251203/202512031601.IpliwbHW-lkp at intel.com/reproduce)
>
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp at intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202512031601.IpliwbHW-lkp at intel.com/
>
> All errors (new ones prefixed by >>):
>
>>> ld.lld: error: duplicate symbol: init_module
>     >>> defined at arm-smmu-v3.c
>     >>>            drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.o:(init_module)
>     >>> defined at tegra241-cmdqv.c
>     >>>            drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.o:(.init.text+0x4)
> --
>>> ld.lld: error: duplicate symbol: cleanup_module
>     >>> defined at arm-smmu-v3.c
>     >>>            drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.o:(cleanup_module)
>     >>> defined at tegra241-cmdqv.c
>     >>>            drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.o:(.exit.text+0x4)

Hi Nic, Robin,

How do you suggest fixing this? Is it fine to compile tegra241-cmdqv as 
separate module
and export tegra241_cmdqv_probe() to fix this warning?
I am using GCC compiler and was not able to reproduce this with W=1 build.

Thanks,
Ashish Mhetre

> --
> 0-DAY CI Kernel Test Service
> https://github.com/intel/lkp-tests/wiki


From amhetre at nvidia.com  Wed Dec  3 03:06:53 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Wed, 3 Dec 2025 16:36:53 +0530
Subject: [PATCH V3 3/3] arm64: dts: nvidia: Add nodes for CMDQV
In-Reply-To: <516f57b2-cdf1-435c-8de4-978ac8b03f62@nvidia.com>
References: <20251201163219.3237266-1-amhetre@nvidia.com>
 <20251201163219.3237266-4-amhetre@nvidia.com>
 <516f57b2-cdf1-435c-8de4-978ac8b03f62@nvidia.com>
Message-ID: <8e742787-c60d-4f88-9de6-adfce31f7b27@nvidia.com>


On 12/3/2025 4:14 PM, Jon Hunter wrote:
>
>
> On 01/12/2025 16:32, Ashish Mhetre wrote:
>> The Command Queue Virtualization (CMDQV) hardware is part of the
>> SMMUv3 implementation on NVIDIA Tegra SoCs. It assists in
>> virtualizing the command queue for the SMMU.
>>
>> Update SMMU compatible strings to use nvidia,tegra264-smmu to enable
>> CMDQV support. Add device tree nodes for the CMDQV hardware and enable
>> them on the tegra264-p3834 platform where SMMUs are enabled. Each SMMU
>> instance is paired with its corresponding CMDQV instance via the
>> nvidia,cmdqv property.
>>
>> Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
>> ---
>> ? .../arm64/boot/dts/nvidia/tegra264-p3834.dtsi |? 8 +++
>> ? arch/arm64/boot/dts/nvidia/tegra264.dtsi????? | 55 +++++++++++++++++--
>> ? 2 files changed, 58 insertions(+), 5 deletions(-)
>>
>> diff --git a/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi 
>> b/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
>> index 06795c82427a..7e2c3e66c2ab 100644
>> --- a/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
>> +++ b/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
>> @@ -23,8 +23,16 @@ iommu at 5000000 {
>> ????????????? status = "okay";
>> ????????? };
>> ? +??????? cmdqv at 5200000 {
>> +??????????? status = "okay";
>> +??????? };
>> +
>> ????????? iommu at 6000000 {
>> ????????????? status = "okay";
>> ????????? };
>> +
>> +??????? cmdqv at 6200000 {
>> +??????????? status = "okay";
>> +??????? };
>> ????? };
>> ? };
>> diff --git a/arch/arm64/boot/dts/nvidia/tegra264.dtsi 
>> b/arch/arm64/boot/dts/nvidia/tegra264.dtsi
>> index f137565da804..5124715caeb3 100644
>> --- a/arch/arm64/boot/dts/nvidia/tegra264.dtsi
>> +++ b/arch/arm64/boot/dts/nvidia/tegra264.dtsi
>> @@ -3361,7 +3361,7 @@ bus at 8100000000 {
>> ?????????????? <0x02 0x00000000 0xd0 0x00000000 0x08 0x80000000>; /* 
>> ECAM, prefetchable memory, I/O */
>> ? ????????? smmu1: iommu at 5000000 {
>> -??????????? compatible = "arm,smmu-v3";
>> +??????????? compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
>> ????????????? reg = <0x00 0x5000000 0x0 0x200000>;
>> ????????????? interrupts = <GIC_SPI 12 IRQ_TYPE_EDGE_RISING>,
>> ?????????????????????? <GIC_SPI 13 IRQ_TYPE_EDGE_RISING>;
>> @@ -3370,10 +3370,19 @@ smmu1: iommu at 5000000 {
>> ? ????????????? #iommu-cells = <1>;
>> ????????????? dma-coherent;
>> +??????????? nvidia,cmdqv = <&cmdqv1>;
>> +??????? };
>> +
>> +??????? cmdqv1: cmdqv at 5200000 {
>> +??????????? compatible = "nvidia,tegra264-cmdqv";
>> +??????????? status = "disabled";
>> +
>> +??????????? reg = <0x00 0x5200000 0x0 0x830000>;
>> +??????????? interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
>
> Like for other devices, the typical ordering is ...
>
> ?compatible = "nvidia,tegra264-cmdqv";
> ?reg = <0x00 0x5200000 0x0 0x830000>;
> ?interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
> ?status = "disabled";
>
> So let's follow the same approach here.
>
> Jon
>

Sure, I'll update the ordering in next version. Thanks.



From punit.agrawal at oss.qualcomm.com  Wed Dec  3 03:21:35 2025
From: punit.agrawal at oss.qualcomm.com (Punit Agrawal)
Date: Wed, 03 Dec 2025 11:21:35 +0000
Subject: [PATCH v6 00/34] arm_mpam: Add basic mpam driver
In-Reply-To: <a04aa337-a3eb-42a0-855b-500ba549e2d8@arm.com> (Ben Horgan's
	message of "Thu, 27 Nov 2025 14:25:28 +0000")
References: <20251119122305.302149-1-ben.horgan@arm.com>
	<877bvfa23i.fsf@stealth>
	<a04aa337-a3eb-42a0-855b-500ba549e2d8@arm.com>
Message-ID: <87sedrlsjk.fsf@stealth>

Hi Ben,

Thanks for getting back.

Ben Horgan <ben.horgan at arm.com> writes:

> Hi Punit,
>
> On 11/24/25 15:21, Punit Agrawal wrote:
>> Hi Ben, James
>> 
>> Ben Horgan <ben.horgan at arm.com> writes:
>> 
>>>
>>> This series is based on v6.18-rc4, and can be retrieved from: (no v6 version)
>>> https://git.kernel.org/pub/scm/linux/kernel/git/morse/linux.git mpam/driver/v5
>>>
>>> The rest of the driver can be found here: (no v6 version)
>>> https://git.kernel.org/pub/scm/linux/kernel/git/morse/linux.git mpam/snapshot/v6.18-rc4-v5
>>>
>>> What is MPAM? Set your time-machine to 2020:
>>> https://lore.kernel.org/lkml/20201030161120.227225-1-james.morse at arm.com/
>> 
>> Although a little late to the party, I've managed to throw together
>> enough firmware to describe the MPAM hardware and take this set (more
>> specifically mpam/snapshot/v6.18-rc4-v5 branch from James' repository)
>> for a spin. Using the branch, the kernel is able to probe the hardware
>> and discover the advertised features. Yay! We are in business.
>
> Thanks for giving it a go. :)
>
>> 
>> Having said that, there are a few quirks of the platform that run into
>> issues with later patches in the branch. The platform has MSCs attached
>> to shared L2 caches which are being skipped during later stages of
>> initialisation. IIUC, the L2 MSCs' limitations stems from the
>> assumptions in the resctrl interface.
>
> What in particualar is being skipped?

The registration of the discovered MSCs with resctrl and subsequent
exposing it to the user.

>> I was wondering if there are any patches available to relax these
>> limitations? I can give them a try. Or do these need to be put together
>> from the ground up? Any pointers greatly appreciated.
>
> There are some extra things added in the extras branch [1] e.g. cache
> maximum usage controls (cmax). However, lots of possible things are
> still missing e.g. any monitors on L2. If it doesn't fit with the
> topology expected by resctrl then it is unlikely to have been considered
> yet.

Thanks for the pointer. I'll give the snapshot+extras branch[1] a try.

The platform does have both controls and monitors attached to L2. If
this isn't being looked at, I can try and put something together. Thanks
for confirming that the limitation is likely due to resctrl.

Looking forward to the next set of MPAM support landing.

> [1] https://git.kernel.org/pub/scm/linux/kernel/git/morse/linux.git/log/?h=mpam/snapshot%2bextras/v6.18-rc1

[...]



From louisalexis.eyraud at collabora.com  Wed Dec  3 03:32:42 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Wed, 03 Dec 2025 12:32:42 +0100
Subject: [PATCH] pinctrl: mediatek: mt8189: restore previous register base
 name array order
Message-ID: <20251203-mt8189-pinctrl-fix-regname-order-v1-1-16c8ff5490a7@collabora.com>

In mt8189-pinctrl driver, a previous commit changed the register base
name array (mt8189_pinctrl_register_base_names) entry name and order to
align it with the same name and order as the "mediatek,mt8189-pinctrl"
devicetree bindings. The new order (by ascending register address) now
causes an issue with MT8189 pinctrl configuration.

MT8189 SoC has multiple base addresses for the pin configuration
registers. Several constant data structures, declaring each pin
configuration, are using PIN_FIELD_BASE() macro which i_base parameter
indicates for a given pin the lookup index in the base register address
array of the driver internal data for the configuration register
read/write accesses. But in practice, this parameter is given a
hardcoded numerical value that corresponds to the expected base
register entry index in mt8189_pinctrl_register_base_names array.
Since this array reordering, the i_base index matching is no more
correct.

So, in order to avoid modifying over a thousand of PIN_FIELD_BASE()
calls, restore previous mt8189_pinctrl_register_base_names entry order.

Fixes: 518919276c41 ("pinctrl: mediatek: mt8189: align register base names to dt-bindings ones")
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 drivers/pinctrl/mediatek/pinctrl-mt8189.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8189.c b/drivers/pinctrl/mediatek/pinctrl-mt8189.c
index f6a3e584588b0e8a1aafa9dca74c559974a57af5..cd4cdff309a12b6987362b111e0613bf29b60d84 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8189.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8189.c
@@ -1642,7 +1642,7 @@ static const struct mtk_pin_reg_calc mt8189_reg_cals[PINCTRL_PIN_REG_MAX] = {
 };
 
 static const char * const mt8189_pinctrl_register_base_names[] = {
-	"base", "lm", "rb0", "rb1", "bm0", "bm1", "bm2", "lt0", "lt1", "rt",
+	"base", "bm0", "bm1", "bm2", "lm",  "lt0", "lt1", "rb0", "rb1", "rt",
 };
 
 static const struct mtk_eint_hw mt8189_eint_hw = {

---
base-commit: e47d97576181b31291cf58e77d737d21def0e160
change-id: 20251203-mt8189-pinctrl-fix-regname-order-8ecce1da422a

Best regards,
-- 
Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>



From sudeep.holla at arm.com  Wed Dec  3 03:41:51 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Wed, 3 Dec 2025 11:41:51 +0000
Subject: [PATCH 1/2] dt-bindings: firmware: arm,scmi: Document
 arm,poll-transport property
In-Reply-To: <8d773671-5e2e-4e21-ade6-2bf9a3b75066@mailbox.org>
References: <20251023123644.8730-1-marek.vasut+renesas@mailbox.org>
 <aPoxfH_TLrsMxMVQ@pluto>
 <70554674-7020-4582-a4e7-dbee34907096@mailbox.org>
 <5ae0a793-d3e7-45d1-bf5c-3c46593d1824@mailbox.org>
 <aRW7BZimWdpq4TyX@pluto>
 <20251202-evasive-neon-rhino-d2745e@sudeepholla>
 <66257fcf-9024-454f-b776-4ba584963ebe@mailbox.org>
 <aS82GSN8c2SnRn4S@bogus>
 <8d773671-5e2e-4e21-ade6-2bf9a3b75066@mailbox.org>
Message-ID: <20251203-thick-didactic-cockatoo-deaa1d@sudeepholla>

On Tue, Dec 02, 2025 at 08:25:11PM +0100, Marek Vasut wrote:
> On 12/2/25 7:55 PM, Sudeep Holla wrote:
> 
> Hello Sudeep,
> 
> > > How do you imagine this -- a transport shared with other components, one
> > > which does generate IRQs and one which does not -- would look like ? Can you
> > > think of an example ?
> > > 
> > 
> > Consider a system where a mailbox controller is present and one channel is
> > used for SCMI communication, while another channel is used for an unrelated
> > purpose. If both channels share the same interrupt line, and the other use
> > case enables interrupt mode on its channel, what would be the impact on the
> > SCMI-specific channel?
> 
> None, SCMI kernel driver and SCMI server side would still do polling on
> their respective SHMEM areas, while whatever kernel driver needs to receive
> the interrupt notifications would subscribe to them using request_irq(),
> right ?
> 

Fair enough. I was thinking if the controller manages to not call
mbox_chan_received_data() in that case. Also IIUC, the irq request happens
as part of channel startup and there are no explicit APIs for the mbox client
driver to control that. SCMI is mbox client in this case.

> > I am aware of systems that implement such sharing, which is why I prefer to be
> > explicit that this type of design is challenging to support within this
> > binding. The intent is to support only minimal, constrained cases - essentially
> > systems that are already somewhat broken. I do not see value in broadening the
> > binding to cover every conceivable scenario.
> > 
> > > > Clearly defining these constraints would be helpful. It may also be useful to
> > > > note that this is primarily intended for mailbox transports, if that?s
> > > > accurate. Alternatively, we could keep the DT binding definition broader but
> > > > emit warnings when a transport other than mailbox is used. That approach might
> > > > make it easier to move forward.
> > > 
> > > DEN0056F refers to this polling mode in Shared memory based transports, that
> > > can be other than mailbox transports, it includes e.g. SMC or OPTEE
> > > transports.
> > > 
> > 
> > However, polling does not make sense in the context of SMC. Once control
> > returns from an SMC call, the command has completed. What form of polling in
> > an SMC workflow do you have in mind?
> 
> I think the polling happens on the SHMEM and the SMC transport is capable of
> that too, see :
> 
> drivers/firmware/arm_scmi/transports/smc.c
> 
> 175         /*
> 176          * If there is an interrupt named "a2p", then the service and
> 177          * completion of a message is signaled by an interrupt rather
> than by
> 178          * the return of the SMC call.
> 179          */
> 180         scmi_info->irq = of_irq_get_byname(cdev->of_node, "a2p");
> 

Ah this one, is actually implemented to avoid sort of implicit polling
mode we get with any SMC/HVC. I don't know how the platform deals with it
but SMC/HVC is synchronous and doesn't need this polling. The irq introduced
here is again a sort of workaround to get some sort of async/non-polling
mode with SMC/HVC. So, to repeat polling mode make absolutely no sense
whatsoever for SMC/OPTEE(based on pure SMC) transports.

> > I believe the same applies to OP-TEE.
> > While OP-TEE now provides a notification mechanism that could, in theory,
> > allow synchronous commands to be treated in a quasi-asynchronous manner, I
> > strongly doubt that the current SCMI-over-OP-TEE implementation behaves this
> > way, given that it ultimately reaches the secure side via an SMC call.
> > 
> > > I don't think a warning is justified, if the behavior follows the
> > > specification. But I do agree the behavior is ... suboptimal.
> > > 
> > 
> > The specification does not address SMC or OP-TEE transports, placing them
> > outside its scope and likewise these DT bindings.
> 
> I believe the shmem transport includes the SMC and OPTEE ones, right ?
>

Yes, but the expectation when the SMC completes is to have the shmem to be
owned by the OS(except that irq workaround case). Again the OPTEE/SMC is
completely out of spec, but I agree the SHMEM behaviour must conform to the
specification.

> > Consequently, what we
> > decide here in this discussion effectively defines the expected behavior in
> > this context, in my view. So I would like to start with minimal possible
> > coverage, why do you think that is not a good idea here ?
> 
> I would argue the current implementation covers pretty much every transport
> which could ever need to do polling on shmem, so the implementation is
> generic and inline with the specification. Also, the current implementation
> is some 20 lines, so I think it is minimalistic?
> 
> What would you propose we do here ?
> 

Yes it can be minimalistic but not restrictive. As I already clearly mentioned
I don't see it makes any sense to enable this for SMC/OPTEE. Lets start with
just mailbox to start with and extend to other transports if and when needed.
It would be good to impose that restriction in the binding as well but that
is not a must IMO. I am fine if the bindings for whatever reasons(though I
don't see the need) to apply for any transport.

-- 
Regards,
Sudeep


From alexandru.elisei at arm.com  Wed Dec  3 03:43:14 2025
From: alexandru.elisei at arm.com (Alexandru Elisei)
Date: Wed, 3 Dec 2025 11:43:14 +0000
Subject: [PATCH 2/4] arm64: Convert VTCR_EL2 to sysreg infratructure
In-Reply-To: <20251129144525.2609207-3-maz@kernel.org>
References: <20251129144525.2609207-1-maz@kernel.org>
 <20251129144525.2609207-3-maz@kernel.org>
Message-ID: <aTAiUuc_aK5Bgce0@raptor>

Hi Marc,

On Sat, Nov 29, 2025 at 02:45:23PM +0000, Marc Zyngier wrote:
> Our definition of VTCR_EL2 is both partial (tons of fields are
> missing) and totally inconsistent (some constants are shifted,
> some are not). They are also expressed in terms of TCR, which is
> rather inconvenient.
> 
> Replace the ad-hoc definitions with the the generated version.
> This results in a bunch of additional changes to make the code
> with the unshifted nature of generated enumerations.
> 
> The register data was extracted from the BSD licenced AARCHMRS
> (AARCHMRS_OPENSOURCE_A_profile_FAT-2025-09_ASL0).

Looks correct to me:

Reviewed-by: Alexandru Elisei <alexandru.elisei at arm.com>

Thanks,
Alex

> 
> Signed-off-by: Marc Zyngier <maz at kernel.org>
> ---
>  arch/arm64/include/asm/kvm_arm.h | 52 +++++++----------------------
>  arch/arm64/include/asm/sysreg.h  |  1 -
>  arch/arm64/kvm/hyp/pgtable.c     |  8 ++---
>  arch/arm64/kvm/nested.c          |  8 ++---
>  arch/arm64/tools/sysreg          | 57 ++++++++++++++++++++++++++++++++
>  5 files changed, 76 insertions(+), 50 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
> index 1da290aeedce7..cd2dc378baee6 100644
> --- a/arch/arm64/include/asm/kvm_arm.h
> +++ b/arch/arm64/include/asm/kvm_arm.h
> @@ -123,37 +123,7 @@
>  #define TCR_EL2_MASK	(TCR_EL2_TG0_MASK | TCR_EL2_SH0_MASK | \
>  			 TCR_EL2_ORGN0_MASK | TCR_EL2_IRGN0_MASK)
>  
> -/* VTCR_EL2 Registers bits */
> -#define VTCR_EL2_DS		TCR_EL2_DS
> -#define VTCR_EL2_RES1		(1U << 31)
> -#define VTCR_EL2_HD		(1 << 22)
> -#define VTCR_EL2_HA		(1 << 21)
> -#define VTCR_EL2_PS_SHIFT	TCR_EL2_PS_SHIFT
> -#define VTCR_EL2_PS_MASK	TCR_EL2_PS_MASK
> -#define VTCR_EL2_TG0_MASK	TCR_TG0_MASK
> -#define VTCR_EL2_TG0_4K		TCR_TG0_4K
> -#define VTCR_EL2_TG0_16K	TCR_TG0_16K
> -#define VTCR_EL2_TG0_64K	TCR_TG0_64K
> -#define VTCR_EL2_SH0_MASK	TCR_SH0_MASK
> -#define VTCR_EL2_SH0_INNER	TCR_SH0_INNER
> -#define VTCR_EL2_ORGN0_MASK	TCR_ORGN0_MASK
> -#define VTCR_EL2_ORGN0_WBWA	TCR_ORGN0_WBWA
> -#define VTCR_EL2_IRGN0_MASK	TCR_IRGN0_MASK
> -#define VTCR_EL2_IRGN0_WBWA	TCR_IRGN0_WBWA
> -#define VTCR_EL2_SL0_SHIFT	6
> -#define VTCR_EL2_SL0_MASK	(3 << VTCR_EL2_SL0_SHIFT)
> -#define VTCR_EL2_T0SZ_MASK	0x3f
> -#define VTCR_EL2_VS_SHIFT	19
> -#define VTCR_EL2_VS_8BIT	(0 << VTCR_EL2_VS_SHIFT)
> -#define VTCR_EL2_VS_16BIT	(1 << VTCR_EL2_VS_SHIFT)
> -
> -#define VTCR_EL2_T0SZ(x)	TCR_T0SZ(x)
> -
>  /*
> - * We configure the Stage-2 page tables to always restrict the IPA space to be
> - * 40 bits wide (T0SZ = 24).  Systems with a PARange smaller than 40 bits are
> - * not known to exist and will break with this configuration.
> - *
>   * The VTCR_EL2 is configured per VM and is initialised in kvm_init_stage2_mmu.
>   *
>   * Note that when using 4K pages, we concatenate two first level page tables
> @@ -161,9 +131,6 @@
>   *
>   */
>  
> -#define VTCR_EL2_COMMON_BITS	(VTCR_EL2_SH0_INNER | VTCR_EL2_ORGN0_WBWA | \
> -				 VTCR_EL2_IRGN0_WBWA | VTCR_EL2_RES1)
> -
>  /*
>   * VTCR_EL2:SL0 indicates the entry level for Stage2 translation.
>   * Interestingly, it depends on the page size.
> @@ -195,30 +162,35 @@
>   */
>  #ifdef CONFIG_ARM64_64K_PAGES
>  
> -#define VTCR_EL2_TGRAN			VTCR_EL2_TG0_64K
> +#define VTCR_EL2_TGRAN			64K
>  #define VTCR_EL2_TGRAN_SL0_BASE		3UL
>  
>  #elif defined(CONFIG_ARM64_16K_PAGES)
>  
> -#define VTCR_EL2_TGRAN			VTCR_EL2_TG0_16K
> +#define VTCR_EL2_TGRAN			16K
>  #define VTCR_EL2_TGRAN_SL0_BASE		3UL
>  
>  #else	/* 4K */
>  
> -#define VTCR_EL2_TGRAN			VTCR_EL2_TG0_4K
> +#define VTCR_EL2_TGRAN			4K
>  #define VTCR_EL2_TGRAN_SL0_BASE		2UL
>  
>  #endif
>  
>  #define VTCR_EL2_LVLS_TO_SL0(levels)	\
> -	((VTCR_EL2_TGRAN_SL0_BASE - (4 - (levels))) << VTCR_EL2_SL0_SHIFT)
> +	FIELD_PREP(VTCR_EL2_SL0, (VTCR_EL2_TGRAN_SL0_BASE - (4 - (levels))))
>  #define VTCR_EL2_SL0_TO_LVLS(sl0)	\
>  	((sl0) + 4 - VTCR_EL2_TGRAN_SL0_BASE)
>  #define VTCR_EL2_LVLS(vtcr)		\
> -	VTCR_EL2_SL0_TO_LVLS(((vtcr) & VTCR_EL2_SL0_MASK) >> VTCR_EL2_SL0_SHIFT)
> +	VTCR_EL2_SL0_TO_LVLS(FIELD_GET(VTCR_EL2_SL0, (vtcr)))
> +
> +#define VTCR_EL2_FLAGS	(SYS_FIELD_PREP_ENUM(VTCR_EL2, SH0, INNER)	    | \
> +			 SYS_FIELD_PREP_ENUM(VTCR_EL2, ORGN0, WBWA)	    | \
> +			 SYS_FIELD_PREP_ENUM(VTCR_EL2, IRGN0, WBWA)	    | \
> +			 SYS_FIELD_PREP_ENUM(VTCR_EL2, TG0, VTCR_EL2_TGRAN) | \
> +			 VTCR_EL2_RES1)
>  
> -#define VTCR_EL2_FLAGS			(VTCR_EL2_COMMON_BITS | VTCR_EL2_TGRAN)
> -#define VTCR_EL2_IPA(vtcr)		(64 - ((vtcr) & VTCR_EL2_T0SZ_MASK))
> +#define VTCR_EL2_IPA(vtcr)		(64 - FIELD_GET(VTCR_EL2_T0SZ, (vtcr)))
>  
>  /*
>   * ARM VMSAv8-64 defines an algorithm for finding the translation table
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index c231d2a3e5159..acad7a7621b9e 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -516,7 +516,6 @@
>  #define SYS_TTBR1_EL2			sys_reg(3, 4, 2, 0, 1)
>  #define SYS_TCR_EL2			sys_reg(3, 4, 2, 0, 2)
>  #define SYS_VTTBR_EL2			sys_reg(3, 4, 2, 1, 0)
> -#define SYS_VTCR_EL2			sys_reg(3, 4, 2, 1, 2)
>  
>  #define SYS_HAFGRTR_EL2			sys_reg(3, 4, 3, 1, 6)
>  #define SYS_SPSR_EL2			sys_reg(3, 4, 4, 0, 0)
> diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
> index 947ac1a951a5b..e0bd6a0172729 100644
> --- a/arch/arm64/kvm/hyp/pgtable.c
> +++ b/arch/arm64/kvm/hyp/pgtable.c
> @@ -583,8 +583,8 @@ u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
>  	u64 vtcr = VTCR_EL2_FLAGS;
>  	s8 lvls;
>  
> -	vtcr |= kvm_get_parange(mmfr0) << VTCR_EL2_PS_SHIFT;
> -	vtcr |= VTCR_EL2_T0SZ(phys_shift);
> +	vtcr |= FIELD_PREP(VTCR_EL2_PS, kvm_get_parange(mmfr0));
> +	vtcr |= FIELD_PREP(VTCR_EL2_T0SZ, (UL(64) - phys_shift));
>  	/*
>  	 * Use a minimum 2 level page table to prevent splitting
>  	 * host PMD huge pages at stage2.
> @@ -624,9 +624,7 @@ u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
>  		vtcr |= VTCR_EL2_DS;
>  
>  	/* Set the vmid bits */
> -	vtcr |= (get_vmid_bits(mmfr1) == 16) ?
> -		VTCR_EL2_VS_16BIT :
> -		VTCR_EL2_VS_8BIT;
> +	vtcr |= (get_vmid_bits(mmfr1) == 16) ? VTCR_EL2_VS : 0;
>  
>  	return vtcr;
>  }
> diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
> index 911fc99ed99d9..e1ef8930c97b3 100644
> --- a/arch/arm64/kvm/nested.c
> +++ b/arch/arm64/kvm/nested.c
> @@ -377,7 +377,7 @@ static void vtcr_to_walk_info(u64 vtcr, struct s2_walk_info *wi)
>  {
>  	wi->t0sz = vtcr & TCR_EL2_T0SZ_MASK;
>  
> -	switch (vtcr & VTCR_EL2_TG0_MASK) {
> +	switch (FIELD_GET(VTCR_EL2_TG0_MASK, vtcr)) {
>  	case VTCR_EL2_TG0_4K:
>  		wi->pgshift = 12;	 break;
>  	case VTCR_EL2_TG0_16K:
> @@ -513,7 +513,7 @@ static u8 get_guest_mapping_ttl(struct kvm_s2_mmu *mmu, u64 addr)
>  
>  	lockdep_assert_held_write(&kvm_s2_mmu_to_kvm(mmu)->mmu_lock);
>  
> -	switch (vtcr & VTCR_EL2_TG0_MASK) {
> +	switch (FIELD_GET(VTCR_EL2_TG0_MASK, vtcr)) {
>  	case VTCR_EL2_TG0_4K:
>  		ttl = (TLBI_TTL_TG_4K << 2);
>  		break;
> @@ -530,7 +530,7 @@ static u8 get_guest_mapping_ttl(struct kvm_s2_mmu *mmu, u64 addr)
>  
>  again:
>  	/* Iteratively compute the block sizes for a particular granule size */
> -	switch (vtcr & VTCR_EL2_TG0_MASK) {
> +	switch (FIELD_GET(VTCR_EL2_TG0_MASK, vtcr)) {
>  	case VTCR_EL2_TG0_4K:
>  		if	(sz < SZ_4K)	sz = SZ_4K;
>  		else if (sz < SZ_2M)	sz = SZ_2M;
> @@ -593,7 +593,7 @@ unsigned long compute_tlb_inval_range(struct kvm_s2_mmu *mmu, u64 val)
>  
>  	if (!max_size) {
>  		/* Compute the maximum extent of the invalidation */
> -		switch (mmu->tlb_vtcr & VTCR_EL2_TG0_MASK) {
> +		switch (FIELD_GET(VTCR_EL2_TG0_MASK, mmu->tlb_vtcr)) {
>  		case VTCR_EL2_TG0_4K:
>  			max_size = SZ_1G;
>  			break;
> diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
> index 9d388f87d9a13..6f43b2ae5993b 100644
> --- a/arch/arm64/tools/sysreg
> +++ b/arch/arm64/tools/sysreg
> @@ -4400,6 +4400,63 @@ Field	56:12	BADDR
>  Res0	11:0
>  EndSysreg
>  
> +Sysreg	VTCR_EL2	3	4	2	1	2
> +Res0	63:46	
> +Field	45	HDBSS
> +Field	44	HAFT
> +Res0	43:42	
> +Field	41	TL0
> +Field	40	GCSH
> +Res0	39
> +Field	38	D128
> +Field	37	S2POE
> +Field	36	S2PIE
> +Field	35	TL1
> +Field	34	AssuredOnly
> +Field	33	SL2
> +Field	32	DS
> +Res1	31
> +Field	30	NSA
> +Field	29	NSW
> +Field	28	HWU62
> +Field	27	HWU61
> +Field	26	HWU60
> +Field	25	HWU59
> +Res0	24:23
> +Field	22	HD
> +Field	21	HA
> +Res0	20
> +Enum	19	VS
> +	0b0	8BIT
> +	0b1	16BIT
> +EndEnum
> +Field	18:16	PS
> +Enum	15:14	TG0
> +	0b00	4K
> +	0b01	64K
> +	0b10	16K
> +EndEnum
> +Enum	13:12	SH0
> +	0b00	NONE
> +	0b01	OUTER
> +	0b11	INNER
> +EndEnum
> +Enum	11:10	ORGN0
> +	0b00	NC
> +	0b01	WBWA
> +	0b10	WT
> +	0b11	WBnWA
> +EndEnum
> +Enum	9:8	IRGN0
> +	0b00	NC
> +	0b01	WBWA
> +	0b10	WT
> +	0b11	WBnWA
> +EndEnum
> +Field	7:6	SL0
> +Field	5:0	T0SZ
> +EndSysreg
> +
>  Sysreg	GCSCR_EL2	3	4	2	5	0
>  Fields	GCSCR_ELx
>  EndSysreg
> -- 
> 2.47.3
> 


From alexandru.elisei at arm.com  Wed Dec  3 03:44:14 2025
From: alexandru.elisei at arm.com (Alexandru Elisei)
Date: Wed, 3 Dec 2025 11:44:14 +0000
Subject: [PATCH 4/4] KVM: arm64: Convert VTCR_EL2 to config-driven
 sanitisation
In-Reply-To: <20251129144525.2609207-5-maz@kernel.org>
References: <20251129144525.2609207-1-maz@kernel.org>
 <20251129144525.2609207-5-maz@kernel.org>
Message-ID: <aTAijieCI8055FL0@raptor>

Hi Marc,

On Sat, Nov 29, 2025 at 02:45:25PM +0000, Marc Zyngier wrote:
> Describe all the VTCR_EL2 fields and their respective configurations,
> making sure that we correctly ignore the bits that are not defined
> for a given guest configuration.
> 
> Signed-off-by: Marc Zyngier <maz at kernel.org>
> ---
>  arch/arm64/kvm/config.c | 69 +++++++++++++++++++++++++++++++++++++++++
>  arch/arm64/kvm/nested.c |  3 +-
>  2 files changed, 70 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
> index a02c28d6a61c9..c36e133c51912 100644
> --- a/arch/arm64/kvm/config.c
> +++ b/arch/arm64/kvm/config.c
> @@ -141,6 +141,7 @@ struct reg_feat_map_desc {
>  #define FEAT_AA64EL1		ID_AA64PFR0_EL1, EL1, IMP
>  #define FEAT_AA64EL2		ID_AA64PFR0_EL1, EL2, IMP
>  #define FEAT_AA64EL3		ID_AA64PFR0_EL1, EL3, IMP
> +#define FEAT_SEL2		ID_AA64PFR0_EL1, SEL2, IMP
>  #define FEAT_AIE		ID_AA64MMFR3_EL1, AIE, IMP
>  #define FEAT_S2POE		ID_AA64MMFR3_EL1, S2POE, IMP
>  #define FEAT_S1POE		ID_AA64MMFR3_EL1, S1POE, IMP
> @@ -202,6 +203,8 @@ struct reg_feat_map_desc {
>  #define FEAT_ASID2		ID_AA64MMFR4_EL1, ASID2, IMP
>  #define FEAT_MEC		ID_AA64MMFR3_EL1, MEC, IMP
>  #define FEAT_HAFT		ID_AA64MMFR1_EL1, HAFDBS, HAFT
> +#define FEAT_HDBSS		ID_AA64MMFR1_EL1, HAFDBS, HDBSS
> +#define FEAT_HPDS2		ID_AA64MMFR1_EL1, HPDS, HPDS2
>  #define FEAT_BTI		ID_AA64PFR1_EL1, BT, IMP
>  #define FEAT_ExS		ID_AA64MMFR0_EL1, EXS, IMP
>  #define FEAT_IESB		ID_AA64MMFR2_EL1, IESB, IMP
> @@ -219,6 +222,7 @@ struct reg_feat_map_desc {
>  #define FEAT_FGT2		ID_AA64MMFR0_EL1, FGT, FGT2
>  #define FEAT_MTPMU		ID_AA64DFR0_EL1, MTPMU, IMP
>  #define FEAT_HCX		ID_AA64MMFR1_EL1, HCX, IMP
> +#define FEAT_S2PIE		ID_AA64MMFR3_EL1, S2PIE, IMP
>  
>  static bool not_feat_aa64el3(struct kvm *kvm)
>  {
> @@ -362,6 +366,28 @@ static bool feat_pmuv3p9(struct kvm *kvm)
>  	return check_pmu_revision(kvm, V3P9);
>  }
>  
> +#define has_feat_s2tgran(k, s)						\
> +  ((kvm_has_feat_enum(kvm, ID_AA64MMFR0_EL1, TGRAN##s##_2, TGRAN##s) && \
> +    !kvm_has_feat_enum(kvm, ID_AA64MMFR0_EL1, TGRAN##s, NI))	     ||	\

Wouldn't that read better as kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN##s, IMP)?
I think that would also be correct.

> +   kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN##s##_2, IMP))

A bit unexpected to treat the same field first as an enum, then as an integer,
but it saves one line.

> +
> +static bool feat_lpa2(struct kvm *kvm)
> +{
> +	return ((kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4, 52_BIT)    ||
> +		 !kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4, IMP))	&&
> +		(kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16, 52_BIT)   ||
> +		 !kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16, IMP))	&&
> +		(kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4_2, 52_BIT)  ||
> +		 !has_feat_s2tgran(kvm, 4))				&&
> +		(kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16_2, 52_BIT) ||
> +		 !has_feat_s2tgran(kvm, 16)));
> +}

That was a doozy, but looks correct to me if the intention was to have the check
as relaxed as possible - i.e, a VM can advertise 52 bit support for one granule,
but not the other (same for stage 1 and stage 2).

As far as I can tell, everything looks good to me:

Reviewed-by: Alexandru Elisei <alexandru.elisei at arm.com>

Thanks,
Alex

> +
> +static bool feat_vmid16(struct kvm *kvm)
> +{
> +	return kvm_has_feat_enum(kvm, ID_AA64MMFR1_EL1, VMIDBits, 16);
> +}
> +
>  static bool compute_hcr_rw(struct kvm *kvm, u64 *bits)
>  {
>  	/* This is purely academic: AArch32 and NV are mutually exclusive */
> @@ -1168,6 +1194,44 @@ static const struct reg_bits_to_feat_map mdcr_el2_feat_map[] = {
>  static const DECLARE_FEAT_MAP(mdcr_el2_desc, MDCR_EL2,
>  			      mdcr_el2_feat_map, FEAT_AA64EL2);
>  
> +static const struct reg_bits_to_feat_map vtcr_el2_feat_map[] = {
> +	NEEDS_FEAT(VTCR_EL2_HDBSS, FEAT_HDBSS),
> +	NEEDS_FEAT(VTCR_EL2_HAFT, FEAT_HAFT),
> +	NEEDS_FEAT(VTCR_EL2_TL0		|
> +		   VTCR_EL2_TL1		|
> +		   VTCR_EL2_AssuredOnly	|
> +		   VTCR_EL2_GCSH,
> +		   FEAT_THE),
> +	NEEDS_FEAT(VTCR_EL2_D128, FEAT_D128),
> +	NEEDS_FEAT(VTCR_EL2_S2POE, FEAT_S2POE),
> +	NEEDS_FEAT(VTCR_EL2_S2PIE, FEAT_S2PIE),
> +	NEEDS_FEAT(VTCR_EL2_SL2		|
> +		   VTCR_EL2_DS,
> +		   feat_lpa2),
> +	NEEDS_FEAT(VTCR_EL2_NSA		|
> +		   VTCR_EL2_NSW,
> +		   FEAT_SEL2),
> +	NEEDS_FEAT(VTCR_EL2_HWU62	|
> +		   VTCR_EL2_HWU61	|
> +		   VTCR_EL2_HWU60	|
> +		   VTCR_EL2_HWU59,
> +		   FEAT_HPDS2),
> +	NEEDS_FEAT(VTCR_EL2_HD, ID_AA64MMFR1_EL1, HAFDBS, DBM),
> +	NEEDS_FEAT(VTCR_EL2_HA, ID_AA64MMFR1_EL1, HAFDBS, AF),
> +	NEEDS_FEAT(VTCR_EL2_VS, feat_vmid16),
> +	NEEDS_FEAT(VTCR_EL2_PS		|
> +		   VTCR_EL2_TG0		|
> +		   VTCR_EL2_SH0		|
> +		   VTCR_EL2_ORGN0	|
> +		   VTCR_EL2_IRGN0	|
> +		   VTCR_EL2_SL0		|
> +		   VTCR_EL2_T0SZ,
> +		   FEAT_AA64EL1),
> +};
> +
> +static const DECLARE_FEAT_MAP(vtcr_el2_desc, VTCR_EL2,
> +			      vtcr_el2_feat_map, FEAT_AA64EL2);
> +
>  static void __init check_feat_map(const struct reg_bits_to_feat_map *map,
>  				  int map_size, u64 res0, const char *str)
>  {
> @@ -1211,6 +1275,7 @@ void __init check_feature_map(void)
>  	check_reg_desc(&tcr2_el2_desc);
>  	check_reg_desc(&sctlr_el1_desc);
>  	check_reg_desc(&mdcr_el2_desc);
> +	check_reg_desc(&vtcr_el2_desc);
>  }
>  
>  static bool idreg_feat_match(struct kvm *kvm, const struct reg_bits_to_feat_map *map)
> @@ -1425,6 +1490,10 @@ void get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg, u64 *res0, u64 *r
>  		*res0 = compute_reg_res0_bits(kvm, &mdcr_el2_desc, 0, 0);
>  		*res1 = MDCR_EL2_RES1;
>  		break;
> +	case VTCR_EL2:
> +		*res0 = compute_reg_res0_bits(kvm, &vtcr_el2_desc, 0, 0);
> +		*res1 = VTCR_EL2_RES1;
> +		break;
>  	default:
>  		WARN_ON_ONCE(1);
>  		*res0 = *res1 = 0;
> diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
> index e1ef8930c97b3..606cebcaa7c09 100644
> --- a/arch/arm64/kvm/nested.c
> +++ b/arch/arm64/kvm/nested.c
> @@ -1719,8 +1719,7 @@ int kvm_init_nv_sysregs(struct kvm_vcpu *vcpu)
>  	set_sysreg_masks(kvm, VTTBR_EL2, res0, res1);
>  
>  	/* VTCR_EL2 */
> -	res0 = GENMASK(63, 32) | GENMASK(30, 20);
> -	res1 = BIT(31);
> +	get_reg_fixed_bits(kvm, VTCR_EL2, &res0, &res1);
>  	set_sysreg_masks(kvm, VTCR_EL2, res0, res1);
>  
>  	/* VMPIDR_EL2 */
> -- 
> 2.47.3
> 


From louisalexis.eyraud at collabora.com  Wed Dec  3 03:45:33 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Wed, 03 Dec 2025 12:45:33 +0100
Subject: [PATCH 0/3] Add SD/MMC Card driver support for Mediatek MT8189 SoC
Message-ID: <20251203-mt8189-add-mmc-support-v1-0-f5ce43212fe9@collabora.com>

This patch series adds in the Mediatek SD/MMC Card host driver (mtk-sd)
the support of Mediatek MT8189 SoC and its variants (MT8371 and
MT8391).

It has been tested with a kernel based on next-20251203 tag on the
Mediatek Genio 720-EVK board, based on MT8391 SoC, using both onboard
eMMC storage and a micro-SD card.

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
Louis-Alexis Eyraud (3):
      dt-bindings: mmc: mtk-sd: Add support for MT8189 SoC
      mmc: mtk-sd: add support for SPM resource release control
      mmc: mtk-sd: add support for MT8189 SoC

 Documentation/devicetree/bindings/mmc/mtk-sd.yaml |  3 +++
 drivers/mmc/host/mtk-sd.c                         | 32 ++++++++++++++++++++---
 2 files changed, 32 insertions(+), 3 deletions(-)
---
base-commit: e47d97576181b31291cf58e77d737d21def0e160
change-id: 20251128-mt8189-add-mmc-support-ff6df8f89e41

Best regards,
-- 
Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>



From louisalexis.eyraud at collabora.com  Wed Dec  3 03:45:34 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Wed, 03 Dec 2025 12:45:34 +0100
Subject: [PATCH 1/3] dt-bindings: mmc: mtk-sd: Add support for MT8189 SoC
In-Reply-To: <20251203-mt8189-add-mmc-support-v1-0-f5ce43212fe9@collabora.com>
References: <20251203-mt8189-add-mmc-support-v1-0-f5ce43212fe9@collabora.com>
Message-ID: <20251203-mt8189-add-mmc-support-v1-1-f5ce43212fe9@collabora.com>

Add a new compatible for MMC IP in MT8189 SoC.
Even though this is partially compatible with the one found in MT8196
SoC, the MT8189 SoC register layout has some slight differences and
additional features.

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 Documentation/devicetree/bindings/mmc/mtk-sd.yaml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/mmc/mtk-sd.yaml b/Documentation/devicetree/bindings/mmc/mtk-sd.yaml
index 6dd26ad314916a3e40cf55ff69a7d93ed63dbdd4..eb3755bdfdf7e001602c3eb870898275085df3e6 100644
--- a/Documentation/devicetree/bindings/mmc/mtk-sd.yaml
+++ b/Documentation/devicetree/bindings/mmc/mtk-sd.yaml
@@ -25,6 +25,7 @@ properties:
           - mediatek,mt8135-mmc
           - mediatek,mt8173-mmc
           - mediatek,mt8183-mmc
+          - mediatek,mt8189-mmc
           - mediatek,mt8196-mmc
           - mediatek,mt8516-mmc
       - items:
@@ -192,6 +193,7 @@ allOf:
             - mediatek,mt8183-mmc
             - mediatek,mt8186-mmc
             - mediatek,mt8188-mmc
+            - mediatek,mt8189-mmc
             - mediatek,mt8195-mmc
             - mediatek,mt8196-mmc
             - mediatek,mt8516-mmc
@@ -240,6 +242,7 @@ allOf:
               - mediatek,mt7986-mmc
               - mediatek,mt7988-mmc
               - mediatek,mt8183-mmc
+              - mediatek,mt8189-mmc
               - mediatek,mt8196-mmc
     then:
       properties:

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Wed Dec  3 03:45:35 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Wed, 03 Dec 2025 12:45:35 +0100
Subject: [PATCH 2/3] mmc: mtk-sd: add support for SPM resource release
 control
In-Reply-To: <20251203-mt8189-add-mmc-support-v1-0-f5ce43212fe9@collabora.com>
References: <20251203-mt8189-add-mmc-support-v1-0-f5ce43212fe9@collabora.com>
Message-ID: <20251203-mt8189-add-mmc-support-v1-2-f5ce43212fe9@collabora.com>

The MT8189 SoC has in the status register an additional bit field to
release all System Power management (SPM) resource requests.
In preparation of MT8189 SoC support, add its use in suspend callback
and a support flag in the platform data.

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 drivers/mmc/host/mtk-sd.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index daed659f63f6872423edd755478f0ec57e7742b4..4ce596d616409646613748086476c58d8b7b8de9 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -203,9 +203,10 @@
 #define SDC_CFG_DTOC            GENMASK(31, 24)	/* RW */
 
 /* SDC_STS mask */
-#define SDC_STS_SDCBUSY         BIT(0)	/* RW */
-#define SDC_STS_CMDBUSY         BIT(1)	/* RW */
-#define SDC_STS_SWR_COMPL       BIT(31)	/* RW */
+#define SDC_STS_SDCBUSY			BIT(0)  /* RW */
+#define SDC_STS_CMDBUSY			BIT(1)  /* RW */
+#define SDC_STS_SPM_RESOURCE_RELEASE	BIT(3)  /* RW */
+#define SDC_STS_SWR_COMPL		BIT(31) /* RW */
 
 /* SDC_ADV_CFG0 mask */
 #define SDC_DAT1_IRQ_TRIGGER	BIT(19)	/* RW */
@@ -448,6 +449,7 @@ struct mtk_mmc_compatible {
 	bool use_internal_cd;
 	bool support_new_tx;
 	bool support_new_rx;
+	bool support_spm_res_release;
 };
 
 struct msdc_tune_para {
@@ -3296,6 +3298,10 @@ static int msdc_runtime_suspend(struct device *dev)
 
 		__msdc_enable_sdio_irq(host, 0);
 	}
+
+	if (host->dev_comp->support_spm_res_release)
+		sdr_set_bits(host->base + SDC_STS, SDC_STS_SPM_RESOURCE_RELEASE);
+
 	msdc_gate_clock(host);
 	return 0;
 }

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Wed Dec  3 03:45:36 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Wed, 03 Dec 2025 12:45:36 +0100
Subject: [PATCH 3/3] mmc: mtk-sd: add support for MT8189 SoC
In-Reply-To: <20251203-mt8189-add-mmc-support-v1-0-f5ce43212fe9@collabora.com>
References: <20251203-mt8189-add-mmc-support-v1-0-f5ce43212fe9@collabora.com>
Message-ID: <20251203-mt8189-add-mmc-support-v1-3-f5ce43212fe9@collabora.com>

Even though MMC IP in MT8189 SoC is partially compatible with the one
found in MT8196 SoC, its register layout has some slight differences
and additional features such as the system power management release
resource control support.
Thus, add new compatible and platform data to support this SoC.

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 drivers/mmc/host/mtk-sd.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index 4ce596d616409646613748086476c58d8b7b8de9..302ac8529c4f093a541db2d37dcc8709c3775557 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -675,6 +675,25 @@ static const struct mtk_mmc_compatible mt8516_compat = {
 	.stop_dly_sel = 3,
 };
 
+static const struct mtk_mmc_compatible mt8189_compat = {
+	.clk_div_bits = 12,
+	.recheck_sdio_irq = false,
+	.hs400_tune = false,
+	.needs_top_base = true,
+	.pad_tune_reg = MSDC_PAD_TUNE0,
+	.async_fifo = true,
+	.data_tune = true,
+	.busy_check = true,
+	.stop_clk_fix = true,
+	.stop_dly_sel = 1,
+	.pop_en_cnt = 2,
+	.enhance_rx = true,
+	.support_64g = true,
+	.support_new_tx = true,
+	.support_new_rx = true,
+	.support_spm_res_release = true,
+};
+
 static const struct mtk_mmc_compatible mt8196_compat = {
 	.clk_div_bits = 12,
 	.recheck_sdio_irq = false,
@@ -705,6 +724,7 @@ static const struct of_device_id msdc_of_ids[] = {
 	{ .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat},
 	{ .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat},
 	{ .compatible = "mediatek,mt8183-mmc", .data = &mt8183_compat},
+	{ .compatible = "mediatek,mt8189-mmc", .data = &mt8189_compat},
 	{ .compatible = "mediatek,mt8196-mmc", .data = &mt8196_compat},
 	{ .compatible = "mediatek,mt8516-mmc", .data = &mt8516_compat},
 

-- 
2.52.0



From robert.marko at sartura.hr  Wed Dec  3 04:08:23 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Wed,  3 Dec 2025 13:08:23 +0100
Subject: [PATCH] dmaengine: at_xdmac: get the number of DMA channels from device tree
Message-ID: <20251203120856.1267671-1-robert.marko@sartura.hr>

From: Tony Han <tony.han at microchip.com>

In case of kernel runs in non-secure mode, the number of DMA channels can
be got from device tree since the value read from GTYPE register is "0" as
it's always secured.
As the number of channels can never be negative, update them to the type
"unsigned".

Signed-off-by: Tony Han <tony.han at microchip.com>
Reviewed-by: Cristian Birsan <cristian.birsan at microchip.com>
---
 drivers/dma/at_xdmac.c | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)

diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
index 3fbc74710a13..acabf82e293c 100644
--- a/drivers/dma/at_xdmac.c
+++ b/drivers/dma/at_xdmac.c
@@ -2257,12 +2257,29 @@ static int __maybe_unused atmel_xdmac_runtime_resume(struct device *dev)
 	return clk_enable(atxdmac->clk);
 }
 
+static inline int at_xdmac_get_channel_number(struct platform_device *pdev,
+					      u32 reg, u32 *pchannels)
+{
+	int	ret;
+
+	if (reg) {
+		*pchannels = AT_XDMAC_NB_CH(reg);
+		return 0;
+	}
+
+	ret = of_property_read_u32(pdev->dev.of_node, "dma-channels", pchannels);
+	if (ret)
+		dev_err(&pdev->dev, "can't get number of channels\n");
+
+	return ret;
+}
+
 static int at_xdmac_probe(struct platform_device *pdev)
 {
 	struct at_xdmac	*atxdmac;
-	int		irq, nr_channels, i, ret;
+	int		irq, ret;
 	void __iomem	*base;
-	u32		reg;
+	u32		nr_channels, i, reg;
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0)
@@ -2278,7 +2295,10 @@ static int at_xdmac_probe(struct platform_device *pdev)
 	 * of channels to do the allocation.
 	 */
 	reg = readl_relaxed(base + AT_XDMAC_GTYPE);
-	nr_channels = AT_XDMAC_NB_CH(reg);
+	ret = at_xdmac_get_channel_number(pdev, reg, &nr_channels);
+	if (ret)
+		return ret;
+
 	if (nr_channels > AT_XDMAC_MAX_CHAN) {
 		dev_err(&pdev->dev, "invalid number of channels (%u)\n",
 			nr_channels);
-- 
2.52.0



From robert.marko at sartura.hr  Wed Dec  3 04:11:43 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Wed,  3 Dec 2025 13:11:43 +0100
Subject: [PATCH RESEND] dmaengine: at_xdmac: get the number of DMA channels from device tree
Message-ID: <20251203121208.1269487-1-robert.marko@sartura.hr>

From: Tony Han <tony.han at microchip.com>

In case of kernel runs in non-secure mode, the number of DMA channels can
be got from device tree since the value read from GTYPE register is "0" as
it's always secured.

As the number of channels can never be negative, update them to the type
"unsigned".

This is required for LAN969x.

Signed-off-by: Tony Han <tony.han at microchip.com>
Signed-off-by: Robert Marko <robert.marko at sartura.hr>
---
 drivers/dma/at_xdmac.c | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)

diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
index 3fbc74710a13..acabf82e293c 100644
--- a/drivers/dma/at_xdmac.c
+++ b/drivers/dma/at_xdmac.c
@@ -2257,12 +2257,29 @@ static int __maybe_unused atmel_xdmac_runtime_resume(struct device *dev)
 	return clk_enable(atxdmac->clk);
 }
 
+static inline int at_xdmac_get_channel_number(struct platform_device *pdev,
+					      u32 reg, u32 *pchannels)
+{
+	int	ret;
+
+	if (reg) {
+		*pchannels = AT_XDMAC_NB_CH(reg);
+		return 0;
+	}
+
+	ret = of_property_read_u32(pdev->dev.of_node, "dma-channels", pchannels);
+	if (ret)
+		dev_err(&pdev->dev, "can't get number of channels\n");
+
+	return ret;
+}
+
 static int at_xdmac_probe(struct platform_device *pdev)
 {
 	struct at_xdmac	*atxdmac;
-	int		irq, nr_channels, i, ret;
+	int		irq, ret;
 	void __iomem	*base;
-	u32		reg;
+	u32		nr_channels, i, reg;
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0)
@@ -2278,7 +2295,10 @@ static int at_xdmac_probe(struct platform_device *pdev)
 	 * of channels to do the allocation.
 	 */
 	reg = readl_relaxed(base + AT_XDMAC_GTYPE);
-	nr_channels = AT_XDMAC_NB_CH(reg);
+	ret = at_xdmac_get_channel_number(pdev, reg, &nr_channels);
+	if (ret)
+		return ret;
+
 	if (nr_channels > AT_XDMAC_MAX_CHAN) {
 		dev_err(&pdev->dev, "invalid number of channels (%u)\n",
 			nr_channels);
-- 
2.52.0



From s-jain1 at ti.com  Wed Dec  3 04:13:38 2025
From: s-jain1 at ti.com (Swamil Jain)
Date: Wed, 3 Dec 2025 17:43:38 +0530
Subject: [PATCH 00/21] Clean and update tilcdc driver to support
 DRM_BRIDGE_ATTACH_NO_CONNECTOR
In-Reply-To: <20251203114941.1fafd9dd@kmaincent-XPS-13-7390>
References: <20251126-feature_tilcdc-v1-0-49b9ef2e3aa0@bootlin.com>
 <7b8e22d1-a872-4ea0-8fce-4323d2bf81ff@ti.com>
 <20251203114941.1fafd9dd@kmaincent-XPS-13-7390>
Message-ID: <3ebd23db-8ebb-4b04-88a6-415ce92da131@ti.com>



On 12/3/25 16:19, Kory Maincent wrote:
> On Tue, 2 Dec 2025 17:55:15 +0530
> Swamil Jain <s-jain1 at ti.com> wrote:
> 
>> Hi Kory,
>> Thanks for the series.
>>
>> On 11/26/25 23:05, Kory Maincent (TI.com) wrote:
>>> The starting point for this work was adding support for the HDMI cape:
>>> https://www.seeedstudio.com/Seeed-Studio-BeagleBone-Green-HDMI-Cape.html
>>> This will be sent in a later series.
>>>
>>> Initially, Miguel proposed modifying the ite-it66121 bridge to support
>>> the legacy behavior without the DRM_BRIDGE_ATTACH_NO_CONNECTOR flag:
>>> https://lore.kernel.org/lkml/20250909-it66121-fix-v1-1-bc79ca83df17 at bootlin.com/
>>> This patch was NAK'd as we don't want to add more legacy code. Maxime
>>> requested that the tilcdc driver be updated to use
>>> DRM_BRIDGE_ATTACH_NO_CONNECTOR instead.
>>>
>>> While working on this update, I discovered that the tilcdc driver
>>> contained significant amounts of legacy code that needed cleaning.
>>> Since this driver was developed alongside the tda998x driver for
>>> several AM335x boards, the tda998x driver also required cleanup and
>>> support for the DRM_BRIDGE_ATTACH_NO_CONNECTOR flag.
>>>
>>> This series is based on the tilcdc fix sent to mainline:
>>> https://lore.kernel.org/lkml/20251125090546.137193-1-kory.maincent at bootlin.com/
>>>
>>> Patch 1-7: Convert tilcdc binding to YAML and remove the ti,tilcdc,panel
>>> 	   sub-binding and driver
>>> Patch 8-16: Clean up tilcdc driver
>>> Patch 17-19: Clean up tda998x driver
>>> Patch 20: Add DRM_BRIDGE_ATTACH_NO_CONNECTOR support to tda998x
>>> Patch 21: Add DRM_BRIDGE_ATTACH_NO_CONNECTOR support to tilcdc
>>>
>>> Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
>>> ---
>>> Kory Maincent (TI.com) (21):
>>>         dt-bindings: display: tilcdc: Convert to DT schema
>>>         dt-bindings: display: tilcdc: Add fifo-threshold property
>>>         drm/tilcdc: Remove simulate_vesa_sync flag
>>>         drm/tilcdc: Add support for DRM bus flags and simplify panel config
>>>         ARM: dts: omap: Bind panel to panel-dpi instead of ti,tilcdc,panel
>>> driver dt-bindings: display: tilcdc: Remove panel binding
>>>         drm/tilcdc: Remove tilcdc panel driver
>>>         drm/tilcdc: Remove component framework support
>>>         drm/tilcdc: Remove tilcdc_panel_info structure
>>>         drm/tilcdc: Remove redundant #endif/#ifdef in debugfs code
>>>         drm/tilcdc: Remove unused encoder and connector tracking arrays
>>>         drm/tilcdc: Rename external_encoder and external_connector to
>>> encoder and connector drm/tilcdc: Rename tilcdc_external to tilcdc_encoder
>>>         drm/tilcdc: Remove the useless module list support
>>>         drm/tilcdc: Modernize driver initialization and cleanup paths
>>>         drm/tilcdc: Remove the use of drm_device private_data
>>>         drm/bridge: tda998x: Remove component support
>>>         drm/bridge: tda998x: Move tda998x_create/destroy into probe and
>>> remove drm/bridge: tda998x: Remove useless tda998x_connector_destroy wrapper
>>>         drm/bridge: tda998x: Add support for DRM_BRIDGE_ATTACH_NO_CONNECTOR
>>>         drm/tilcdc: Add support for DRM_BRIDGE_ATTACH_NO_CONNECTOR
>>>
>>>    .../devicetree/bindings/display/tilcdc/panel.txt   |  66 ---
>>>    .../devicetree/bindings/display/tilcdc/tilcdc.txt  |  82 ----
>>>    .../devicetree/bindings/display/tilcdc/tilcdc.yaml | 103 +++++
>>>    arch/arm/boot/dts/ti/davinci/da850-evm.dts         |  26 +-
>>>    arch/arm/boot/dts/ti/omap/am335x-guardian.dts      |  25 +-
>>>    arch/arm/boot/dts/ti/omap/am335x-pdu001.dts        |  21 +-
>>>    arch/arm/boot/dts/ti/omap/am335x-pepper.dts        |  22 +-
>>>    arch/arm/boot/dts/ti/omap/am335x-sbc-t335.dts      |  25 +-
>>>    arch/arm/boot/dts/ti/omap/am335x-sl50.dts          |  25 +-
>>>    drivers/gpu/drm/bridge/tda998x_drv.c               | 251 ++++++------
>>>    drivers/gpu/drm/tilcdc/Makefile                    |   3 +-
>>>    drivers/gpu/drm/tilcdc/tilcdc_crtc.c               | 117 ++----
>>>    drivers/gpu/drm/tilcdc/tilcdc_drv.c                | 456
>>> +++++++-------------- drivers/gpu/drm/tilcdc/tilcdc_drv.h                |
>>> 88 +--- drivers/gpu/drm/tilcdc/tilcdc_encoder.c            |  93 +++++
>>>    .../tilcdc/{tilcdc_external.h => tilcdc_encoder.h} |   5 +-
>>>    drivers/gpu/drm/tilcdc/tilcdc_external.c           | 179 --------
>>>    drivers/gpu/drm/tilcdc/tilcdc_panel.c              | 408
>>> ------------------ drivers/gpu/drm/tilcdc/tilcdc_panel.h              |  15
>>> - drivers/gpu/drm/tilcdc/tilcdc_plane.c              |   2 +-
>>>    drivers/gpu/drm/tilcdc/tilcdc_regs.h               |   8 +-
>>>    21 files changed, 589 insertions(+), 1431 deletions(-)
>>> ---
>>> base-commit: 670bacfc7579bdd79a3069cfb5ab60a6a7923003
>>
>> I was trying to test the patches, unable to find the base-commit, are
>> you using drm-misc-next?
> 
> It is based on the tilcdc fix as explained in the cover letter.
> https://lore.kernel.org/lkml/20251125090546.137193-1-kory.maincent at bootlin.com/
> Therefore you won't be able to find this base commit hash.

Sorry I missed it. Thanks for pointing.

Regards,
Swamil.

> 
> Regards,



From gerg at linux-m68k.org  Wed Dec  3 04:15:52 2025
From: gerg at linux-m68k.org (Greg Ungerer)
Date: Wed, 3 Dec 2025 22:15:52 +1000
Subject: [PATCH v4 2/2] m68k: coldfire: Add RNG support for MCF54418
In-Reply-To: <20251126-b4-m5441x-add-rng-support-v4-2-5309548c9555@yoseli.org>
References: <20251126-b4-m5441x-add-rng-support-v4-0-5309548c9555@yoseli.org>
 <20251126-b4-m5441x-add-rng-support-v4-2-5309548c9555@yoseli.org>
Message-ID: <bd25e903-30fc-4905-986c-96d1b42e9f02@linux-m68k.org>

Hi Jean-Michel,

On 26/11/25 17:08, Jean-Michel Hautbois via B4 Relay wrote:
> From: Jean-Michel Hautbois <jeanmichel.hautbois at yoseli.org>
> 
> Add support for the hardware Random Number Generator (RNGB) found on
> MCF54418 ColdFire processors with clock enabled at platform
> initialization.
> 
> The RNGB block is compatible with the imx-rngc driver.
> 
> Reviewed-by: Frank Li <Frank.Li at nxp.com>
> Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois at yoseli.org>
> ---
>   arch/m68k/coldfire/device.c       | 28 ++++++++++++++++++++++++++++
>   arch/m68k/coldfire/m5441x.c       |  2 +-
>   arch/m68k/include/asm/m5441xsim.h |  9 +++++++++
>   drivers/char/hw_random/Kconfig    |  3 ++-
>   drivers/char/hw_random/imx-rngc.c |  7 +++++++
>   5 files changed, 47 insertions(+), 2 deletions(-)

I am happy with the ColdFire arch parts, so from me:

     Acked-by: Greg Ungerer <gerg at linux-m68k.org>

I don't mind taking this commit via the m68knommu git tree if the hw_rng
maintainers are ok with that. Otherwise if you break out the arch/m68k
parts I can apply those on their own.

Regards
Greg



> diff --git a/arch/m68k/coldfire/device.c b/arch/m68k/coldfire/device.c
> index b6958ec2a220..9d8f844e319a 100644
> --- a/arch/m68k/coldfire/device.c
> +++ b/arch/m68k/coldfire/device.c
> @@ -622,6 +622,31 @@ static struct platform_device mcf_flexcan0 = {
>   };
>   #endif /* MCFFLEXCAN_SIZE */
>   
> +#ifdef MCF_RNG_BASE
> +/*
> + * Random Number Generator (RNG) - only on MCF54418
> + */
> +static struct resource mcf_rng_resource[] = {
> +	{
> +		.start = MCF_RNG_BASE,
> +		.end   = MCF_RNG_BASE + MCF_RNG_SIZE - 1,
> +		.flags = IORESOURCE_MEM,
> +	},
> +	{
> +		.start = MCF_IRQ_RNG,
> +		.end   = MCF_IRQ_RNG,
> +		.flags = IORESOURCE_IRQ,
> +	},
> +};
> +
> +static struct platform_device mcf_rng = {
> +	.name           = "imx-rngc",
> +	.id             = -1,
> +	.num_resources  = ARRAY_SIZE(mcf_rng_resource),
> +	.resource       = mcf_rng_resource,
> +};
> +#endif /* MCF_RNG_BASE */
> +
>   static struct platform_device *mcf_devices[] __initdata = {
>   	&mcf_uart,
>   #ifdef MCFFEC_BASE0
> @@ -660,6 +685,9 @@ static struct platform_device *mcf_devices[] __initdata = {
>   #ifdef MCFFLEXCAN_SIZE
>   	&mcf_flexcan0,
>   #endif
> +#ifdef MCF_RNG_BASE
> +	&mcf_rng,
> +#endif
>   };
>   
>   /*
> diff --git a/arch/m68k/coldfire/m5441x.c b/arch/m68k/coldfire/m5441x.c
> index 7a25cfc7ac07..ab5b00637237 100644
> --- a/arch/m68k/coldfire/m5441x.c
> +++ b/arch/m68k/coldfire/m5441x.c
> @@ -158,6 +158,7 @@ static struct clk * const enable_clks[] __initconst = {
>   	&__clk_0_33, /* pit.1 */
>   	&__clk_0_37, /* eport */
>   	&__clk_0_48, /* pll */
> +	&__clk_0_49, /* rng */
>   	&__clk_0_51, /* esdhc */
>   
>   	&__clk_1_36, /* CCM/reset module/Power management */
> @@ -179,7 +180,6 @@ static struct clk * const disable_clks[] __initconst = {
>   	&__clk_0_44, /* usb otg */
>   	&__clk_0_45, /* usb host */
>   	&__clk_0_47, /* ssi.0 */
> -	&__clk_0_49, /* rng */
>   	&__clk_0_50, /* ssi.1 */
>   	&__clk_0_53, /* enet-fec */
>   	&__clk_0_54, /* enet-fec */
> diff --git a/arch/m68k/include/asm/m5441xsim.h b/arch/m68k/include/asm/m5441xsim.h
> index f48cf63bd782..dd64cdfcad3e 100644
> --- a/arch/m68k/include/asm/m5441xsim.h
> +++ b/arch/m68k/include/asm/m5441xsim.h
> @@ -198,6 +198,15 @@
>   #define MCFRTC_SIZE		(0xfc0a8840 - 0xfc0a8000)
>   #define MCF_IRQ_RTC		(MCFINT2_VECBASE + MCFINT2_RTC)
>   
> +/*
> + *  Random Number Generator (RNG) Module.
> + *  Note: Only present in MCF54418, not in MCF54410/54415/54417
> + */
> +#define MCF_RNG_BASE		0xfc0c4000
> +#define MCF_RNG_SIZE		0x1c
> +#define MCFINT2_RNG		28
> +#define MCF_IRQ_RNG		(MCFINT2_VECBASE + MCFINT2_RNG)
> +
>   /*
>    *  GPIO Module.
>    */
> diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
> index 492a2a61a65b..2f301e43db84 100644
> --- a/drivers/char/hw_random/Kconfig
> +++ b/drivers/char/hw_random/Kconfig
> @@ -270,12 +270,13 @@ config HW_RANDOM_MXC_RNGA
>   config HW_RANDOM_IMX_RNGC
>   	tristate "Freescale i.MX RNGC Random Number Generator"
>   	depends on HAS_IOMEM
> -	depends on SOC_IMX25 || SOC_IMX6SL || SOC_IMX6SLL || SOC_IMX6UL || COMPILE_TEST
> +	depends on SOC_IMX25 || SOC_IMX6SL || SOC_IMX6SLL || SOC_IMX6UL || COLDFIRE || COMPILE_TEST
>   	default HW_RANDOM
>   	help
>   	  This driver provides kernel-side support for the Random Number
>   	  Generator Version C hardware found on some Freescale i.MX
>   	  processors. Version B is also supported by this driver.
> +	  Also supports RNGB on Freescale MCF54418 (Coldfire V4e).
>   
>   	  To compile this driver as a module, choose M here: the
>   	  module will be called imx-rngc.
> diff --git a/drivers/char/hw_random/imx-rngc.c b/drivers/char/hw_random/imx-rngc.c
> index d6a847e48339..44f20a05de0a 100644
> --- a/drivers/char/hw_random/imx-rngc.c
> +++ b/drivers/char/hw_random/imx-rngc.c
> @@ -353,12 +353,19 @@ static const struct of_device_id imx_rngc_dt_ids[] = {
>   };
>   MODULE_DEVICE_TABLE(of, imx_rngc_dt_ids);
>   
> +static const struct platform_device_id imx_rngc_devtype[] = {
> +	{ .name = "imx-rngc" },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(platform, imx_rngc_devtype);
> +
>   static struct platform_driver imx_rngc_driver = {
>   	.driver = {
>   		.name = KBUILD_MODNAME,
>   		.pm = pm_ptr(&imx_rngc_pm_ops),
>   		.of_match_table = imx_rngc_dt_ids,
>   	},
> +	.id_table = imx_rngc_devtype,
>   };
>   
>   module_platform_driver_probe(imx_rngc_driver, imx_rngc_probe);
> 



From rui.silva at linaro.org  Wed Dec  3 04:19:04 2025
From: rui.silva at linaro.org (Rui Miguel Silva)
Date: Wed, 03 Dec 2025 12:19:04 +0000
Subject: [PATCH v4 0/5] media: imx8qxp: add parallel camera support
In-Reply-To: <aS9NvkAWTa42j7KW@lizhi-Precision-Tower-5810>
References: <20250729-imx8qxp_pcam-v4-0-4dfca4ed2f87@nxp.com>
 <20250805010822.GC24627@pendragon.ideasonboard.com>
 <aLbcpEZXm5G1Onq7@lizhi-Precision-Tower-5810>
 <20250902123920.GM13448@pendragon.ideasonboard.com>
 <aLhJDXnz9HPGrWcp@lizhi-Precision-Tower-5810>
 <aQuDSROHLGHIhtlh@lizhi-Precision-Tower-5810>
 <20251105171928.GB6046@pendragon.ideasonboard.com>
 <aQul/VGG8e3MJxhx@lizhi-Precision-Tower-5810>
 <DE1JMG95RZME.2YSV10RI9AME4@gmail.com>
 <aQzFiEOQvtZjHIsr@lizhi-Precision-Tower-5810>
 <aS9NvkAWTa42j7KW@lizhi-Precision-Tower-5810>
Message-ID: <DEOKQZMPDTLY.3H4NBUEC3LNHE@linaro.com>

Hey Frank,
On Tue Dec 2, 2025 at 8:36 PM WET, Frank Li wrote:

> On Thu, Nov 06, 2025 at 10:58:00AM -0500, Frank Li wrote:
>> On Thu, Nov 06, 2025 at 10:34:48AM +0000, Rui Miguel Silva wrote:
>> > On Wed Nov 5, 2025 at 7:31 PM WET, Frank Li wrote:
>> >
>> > > On Wed, Nov 05, 2025 at 07:19:28PM +0200, Laurent Pinchart wrote:
>> > >> Hi Frank,
>> > >>
>> > >> On Wed, Nov 05, 2025 at 12:03:05PM -0500, Frank Li wrote:
>> > >> > On Wed, Sep 03, 2025 at 09:56:29AM -0400, Frank Li wrote:
>> > >> > > On Tue, Sep 02, 2025 at 02:39:20PM +0200, Laurent Pinchart wrote:
>> > >> > > > On Tue, Sep 02, 2025 at 08:01:40AM -0400, Frank Li wrote:
>> > >> > > > > On Tue, Aug 05, 2025 at 04:08:22AM +0300, Laurent Pinchart wrote:
>> > >> > > > > > Hi Frank,
>> > >> > > > > >
>> > >> > > > > > Thank you for the patches.
>> > >> > > > > >
>> > >> > > > > > I've quite busy these days, and I don't believe I will have time to
>> > >> > > > > > review this series before coming back from OSS Europe at the beginning
>> > >> > > > > > of September. Let's see if anyone on CC could volunteer.
>> > >> > > > >
>> > >> > > > > Laurent Pincha
>> > >> > > > > 	I hope you have good time at OSS.
>> > >> > > > >
>> > >> > > > > 	Do you have chance to review this patch?
>> > >> > > >
>> > >> > > > I'm going through my mail backlog, which is really big at the moment.
>> > >> > >
>> > >> > > Understand.
>> > >> > >
>> > >> > > > I'd like someone else to volunteer to review this series. It won't scale
>> > >> > > > if I have to review all NXP media patches in my spare time :-/
>> > >> > >
>> > >> > > Yes, but none volunteer review this in passed months. Expecially key
>> > >> > > reviewer. I am reviewing i3c patches. but Not familiar v4l system yet. It
>> > >> > > need scalable solution. I can help filter some common and simple problem
>> > >> > > from beginning.
>> > >> >
>> > >> > Laurent Pinchart:
>> > >> >
>> > >> > 	Do you have chance to check this serise? this one should be related simple.
>> > >> > 	This one sent at 7/29. Still not any volunteer to review it.
>> > >>
>> > >> I'm afraid I won't have time to review this for the time being. My spare
>> > >> time is already exhausted by all the other drivers I maintain upstream.
>> > >>
>> > >> > 	How do we move forward?
>> > >>
>> > >> I think this is a question for the subsystem maintainers. Hans, Mauro ?
>> > >
>> > > Mauro Carvalho Chehab and Hans Verkuil:
>> > >
>> > > 	Laurent provided great help about review and land i.MX related
>> > > patches in past, who are quite famillar with i.MX chips. But he is quite
>> > > busy. So the whole reviews cycles takes quite long time and offten cross
>> > > some merge windows.
>> > >
>> > > 	In pull requests for 6.19:
>> > > https://lore.kernel.org/all/4989c563-47f4-478c-80c4-41f7e98597e4 at kernel.org/
>> > > only 10 patches, and 4 patches is trivial clean up.
>> > >
>> > > 	In reviewing patch queue, there are
>> > > 	1: media: nxp: imx8-isi: Add ISI support for i.MX95
>> > > 	   https://lore.kernel.org/imx/20251105-isi_imx95-v3-0-3987533cca1c at nxp.com/T/#t
>> > > 	   This one already review, but I am not sure if it capture 6.19 cycle because
>> > > PULL-request already sent.
>> > >
>> > > 	2: Add MIPI CSI-2 support for i.MX8ULP
>> > > 	   https://lore.kernel.org/imx/20251023-csi2_imx8ulp-v7-0-5ecb081ce79b at nxp.com/
>> > >
>> > > 	3: media: add imx93 mipi/controller csi support
>> > > 	   https://lore.kernel.org/imx/20250821-95_cam-v3-0-c9286fbb34b9 at nxp.com/
>> > > 	   This one is quite big, but first 10 patches is simple trivial cleanup patches.
>> > > 	   I post at 8/27, but get first feedback around 10/27, I am not
>> > > 	   sure if missing somethings.
>> > >
>> > > 	4: This series, laurent already said no time review it.
>> > >
>> > > 	5: ap1302 sensor patches
>> > >            https://lore.kernel.org/imx/20250811-ap1302-v4-0-80cc41b91662 at nxp.com/
>> > >            binding already ACK, most maintainer want to pick binding with
>> > > 	   driver together, but not an feedback since 8/11.
>> > >
>> > > 	I jump into and help do some review.
>> > >
>> > > 	The questions is how to move forward pending patches, like [3], [4],
>> > > [5]. How to keep good community channel to avoid long time pending?
>> >
>> > Sorry, but like Laurent I am really without spare cycles to go over the
>> > patch series that have arrived in media (also I do not have any hw anymore).
>> > So, Frank or maybe Laurent knows someone that would like to be add also as
>> > maintainer of this drivers for me would be great, that would also help to
>> > avoid such bottlenecks.
>>
>> If there are not other candidate, I can help maintain it although I am more
>> familar with dt binding, i3c and dmaengine. I can start from simple patches
>> and we have test team to help cover testing on the real hardware.
>
> Rui:
> 	Any update? How to move forward? It was already passed more than 3
> month!

Sorry, I did not realise something was blocked because of me, specially imx8
related. I thought you have sent the update to MAINTAINERS.

For me it is fine, it makes perfect sense since you have access to hardware
and documentation, for you to be the maintainer and steer the features and 
improvements in the imx media. you can move me to Reviewer, since there are
already other 2 persons (and Laurent already handle the pulls, thanks for that)
much more active in the IMX media subsystem.

Thanks again and Cheers,
    Rui


From robert.marko at sartura.hr  Wed Dec  3 04:21:29 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Wed,  3 Dec 2025 13:21:29 +0100
Subject: [PATCH 1/4] dt-bindings: usb: Add Microchip LAN969x support
Message-ID: <20251203122313.1287950-1-robert.marko@sartura.hr>

Microchip LAN969x has DWC3 compatible controller, though limited to 2.0(HS)
speed, so document it.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
---
 .../bindings/usb/microchip,lan9691-dwc3.yaml  | 68 +++++++++++++++++++
 1 file changed, 68 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/usb/microchip,lan9691-dwc3.yaml

diff --git a/Documentation/devicetree/bindings/usb/microchip,lan9691-dwc3.yaml b/Documentation/devicetree/bindings/usb/microchip,lan9691-dwc3.yaml
new file mode 100644
index 000000000000..7ffcbbd1e0f4
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/microchip,lan9691-dwc3.yaml
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/microchip,lan9691-dwc3.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Microchip LAN969x SuperSpeed DWC3 USB SoC controller
+
+maintainers:
+  - Robert Marko <robert.marko at sartura.hr>
+
+select:
+  properties:
+    compatible:
+      contains:
+        enum:
+          - microchip,lan9691-dwc3
+  required:
+    - compatible
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - microchip,lan9691-dwc3
+      - const: snps,dwc3
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: Gated USB DRD clock
+      - description: Controller reference clock
+
+  clock-names:
+    items:
+      - const: bus_early
+      - const: ref
+
+unevaluatedProperties: false
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+
+allOf:
+  - $ref: snps,dwc3.yaml#
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/microchip,lan969x.h>
+
+    usb at 300000 {
+      compatible = "microchip,lan9691-dwc3", "snps,dwc3";
+      reg = <0x300000 0x80000>;
+      interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+      clocks = <&clks GCK_GATE_USB_DRD>,
+               <&clks GCK_ID_USB_REFCLK>;
+      clock-names = "bus_early", "ref";
+    };
-- 
2.52.0



From robert.marko at sartura.hr  Wed Dec  3 04:21:30 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Wed,  3 Dec 2025 13:21:30 +0100
Subject: [PATCH 2/4] dt-bindings: arm: Document Microchip LAN969x
In-Reply-To: <20251203122313.1287950-1-robert.marko@sartura.hr>
References: <20251203122313.1287950-1-robert.marko@sartura.hr>
Message-ID: <20251203122313.1287950-2-robert.marko@sartura.hr>

Microchip LAN969x is a series of multi-port, multi-gigabit switches based
on ARMv8 Cortex-A53 CPU.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
---
 .../bindings/arm/microchip,lan969x.yaml       | 32 +++++++++++++++++++
 1 file changed, 32 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/microchip,lan969x.yaml

diff --git a/Documentation/devicetree/bindings/arm/microchip,lan969x.yaml b/Documentation/devicetree/bindings/arm/microchip,lan969x.yaml
new file mode 100644
index 000000000000..3fa1d4ed40d1
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/microchip,lan969x.yaml
@@ -0,0 +1,32 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/microchip,lan969x.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Microchip LAN969x Boards
+
+maintainers:
+  - Robert Marko <robert.marko at sartura.hr>
+
+description: |+
+   The Microchip LAN969x SoC is a ARMv8-based used in a family of
+   multi-port, multi-gigabit switches.
+
+properties:
+  $nodename:
+    const: '/'
+  compatible:
+    oneOf:
+      - description: The LAN969x EVB (EV23X71A) is a 24x 1G + 4x 10G
+          Ethernet development system board.
+        items:
+          - const: microchip,ev23x71a
+          - const: microchip,lan969x
+
+required:
+  - compatible
+
+additionalProperties: true
+
+...
-- 
2.52.0



From robert.marko at sartura.hr  Wed Dec  3 04:21:31 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Wed,  3 Dec 2025 13:21:31 +0100
Subject: [PATCH 3/4] include: dt-bindings: add LAN969x clock bindings
In-Reply-To: <20251203122313.1287950-1-robert.marko@sartura.hr>
References: <20251203122313.1287950-1-robert.marko@sartura.hr>
Message-ID: <20251203122313.1287950-3-robert.marko@sartura.hr>

Add the required LAN969x clock bindings.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
---
 include/dt-bindings/clock/microchip,lan969x.h | 24 +++++++++++++++++++
 1 file changed, 24 insertions(+)
 create mode 100644 include/dt-bindings/clock/microchip,lan969x.h

diff --git a/include/dt-bindings/clock/microchip,lan969x.h b/include/dt-bindings/clock/microchip,lan969x.h
new file mode 100644
index 000000000000..5a9c8bf7824a
--- /dev/null
+++ b/include/dt-bindings/clock/microchip,lan969x.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+
+#ifndef _DT_BINDINGS_CLK_LAN969X_H
+#define _DT_BINDINGS_CLK_LAN969X_H
+
+#define GCK_ID_QSPI0		0
+#define GCK_ID_QSPI2		1
+#define GCK_ID_SDMMC0		2
+#define GCK_ID_SDMMC1		3
+#define GCK_ID_MCAN0		4
+#define GCK_ID_MCAN1		5
+#define GCK_ID_FLEXCOM0		6
+#define GCK_ID_FLEXCOM1		7
+#define GCK_ID_FLEXCOM2		8
+#define GCK_ID_FLEXCOM3		9
+#define GCK_ID_TIMER		10
+#define GCK_ID_USB_REFCLK	11
+
+/* Gate clocks */
+#define GCK_GATE_USB_DRD	12
+#define GCK_GATE_MCRAMC		13
+#define GCK_GATE_HMATRIX	14
+
+#endif
-- 
2.52.0



From robert.marko at sartura.hr  Wed Dec  3 04:21:32 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Wed,  3 Dec 2025 13:21:32 +0100
Subject: [PATCH 4/4] arm64: dts: microchip: add LAN969x support
In-Reply-To: <20251203122313.1287950-1-robert.marko@sartura.hr>
References: <20251203122313.1287950-1-robert.marko@sartura.hr>
Message-ID: <20251203122313.1287950-4-robert.marko@sartura.hr>

Add support for Microchip LAN969x switch SoC, including the EV23X71A
EVB board.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
---
 arch/arm64/boot/dts/microchip/Makefile        |   2 +
 .../boot/dts/microchip/lan9696-ev23x71a.dts   | 761 ++++++++++++++++++
 arch/arm64/boot/dts/microchip/lan969x.dtsi    | 482 +++++++++++
 3 files changed, 1245 insertions(+)
 create mode 100644 arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts
 create mode 100644 arch/arm64/boot/dts/microchip/lan969x.dtsi

diff --git a/arch/arm64/boot/dts/microchip/Makefile b/arch/arm64/boot/dts/microchip/Makefile
index c6e0313eea0f..d02ac50aae79 100644
--- a/arch/arm64/boot/dts/microchip/Makefile
+++ b/arch/arm64/boot/dts/microchip/Makefile
@@ -2,3 +2,5 @@
 dtb-$(CONFIG_ARCH_SPARX5) += sparx5_pcb125.dtb
 dtb-$(CONFIG_ARCH_SPARX5) += sparx5_pcb134.dtb sparx5_pcb134_emmc.dtb
 dtb-$(CONFIG_ARCH_SPARX5) += sparx5_pcb135.dtb sparx5_pcb135_emmc.dtb
+
+dtb-$(CONFIG_ARCH_LAN969X) += lan9696-ev23x71a.dtb
\ No newline at end of file
diff --git a/arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts b/arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts
new file mode 100644
index 000000000000..6bbddad2a0b9
--- /dev/null
+++ b/arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts
@@ -0,0 +1,761 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT)
+/*
+ * Copyright (c) 2025 Microchip Technology Inc. and its subsidiaries.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
+#include "lan969x.dtsi"
+
+/ {
+	model = "Microchip EV23X71A";
+	compatible = "microchip,ev23x71a", "microchip,lan969x";
+
+	aliases {
+		serial0 = &usart0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	gpio-restart {
+		compatible = "gpio-restart";
+		gpios = <&gpio 60 GPIO_ACTIVE_LOW>;
+		open-source;
+		priority = <200>;
+	};
+
+	i2c-mux {
+		compatible = "i2c-mux-gpio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-parent = <&i2c3>;
+
+		mux-gpios = <&sgpio_out 0 1 GPIO_ACTIVE_HIGH
+			     &sgpio_out 0 2 GPIO_ACTIVE_HIGH
+			     &sgpio_out 0 3 GPIO_ACTIVE_HIGH>;
+		idle-state = <0x8>;
+
+		i2c_sfp0: i2c at 0 {
+			reg = <0x0>;
+		};
+
+		i2c_sfp1: i2c at 1 {
+			reg = <0x1>;
+		};
+
+		i2c_sfp2: i2c at 2 {
+			reg = <0x2>;
+		};
+
+		i2c_sfp3: i2c at 3 {
+			reg = <0x3>;
+		};
+
+		i2c_poe: i2c at 7 {
+			reg = <0x7>;
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		led-status {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_STATUS;
+			gpios = <&gpio 61 GPIO_ACTIVE_LOW>;
+		};
+
+		led-sfp1-green {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_LAN;
+			function-enumerator = <0>;
+			gpios = <&sgpio_out 6 0 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-sfp1-yellow {
+			color = <LED_COLOR_ID_YELLOW>;
+			function = LED_FUNCTION_LAN;
+			function-enumerator = <0>;
+			gpios = <&sgpio_out 6 1 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-sfp2-green {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_LAN;
+			function-enumerator = <1>;
+			gpios = <&sgpio_out 7 0 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-sfp2-yellow {
+			color = <LED_COLOR_ID_YELLOW>;
+			function = LED_FUNCTION_LAN;
+			function-enumerator = <1>;
+			gpios = <&sgpio_out 7 1 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-sfp3-green {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_LAN;
+			function-enumerator = <2>;
+			gpios = <&sgpio_out 8 0 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-sfp3-yellow {
+			color = <LED_COLOR_ID_YELLOW>;
+			function = LED_FUNCTION_LAN;
+			function-enumerator = <2>;
+			gpios = <&sgpio_out 8 1 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-sfp4-green {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_LAN;
+			function-enumerator = <3>;
+			gpios = <&sgpio_out 9 0 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-sfp4-yellow {
+			color = <LED_COLOR_ID_YELLOW>;
+			function = LED_FUNCTION_LAN;
+			function-enumerator = <3>;
+			gpios = <&sgpio_out 9 1 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+	};
+
+	mux-controller {
+		compatible = "gpio-mux";
+		#mux-control-cells = <0>;
+
+		mux-gpios = <&sgpio_out 1 2 GPIO_ACTIVE_LOW>,
+			    <&sgpio_out 1 3 GPIO_ACTIVE_LOW>;
+	};
+
+	sfp0: sfp0 {
+		compatible = "sff,sfp";
+		i2c-bus = <&i2c_sfp0>;
+		tx-disable-gpios = <&sgpio_out 6 2 GPIO_ACTIVE_HIGH>;
+		los-gpios = <&sgpio_in 6 0 GPIO_ACTIVE_HIGH>;
+		mod-def0-gpios = <&sgpio_in 6 1 GPIO_ACTIVE_LOW>;
+		tx-fault-gpios = <&sgpio_in 6 2 GPIO_ACTIVE_HIGH>;
+	};
+
+	sfp1: sfp1 {
+		compatible = "sff,sfp";
+		i2c-bus = <&i2c_sfp1>;
+		tx-disable-gpios = <&sgpio_out 7 2 GPIO_ACTIVE_HIGH>;
+		los-gpios = <&sgpio_in 7 0 GPIO_ACTIVE_HIGH>;
+		mod-def0-gpios = <&sgpio_in 7 1 GPIO_ACTIVE_LOW>;
+		tx-fault-gpios = <&sgpio_in 7 2 GPIO_ACTIVE_HIGH>;
+	};
+
+	sfp2: sfp2 {
+		compatible = "sff,sfp";
+		i2c-bus = <&i2c_sfp2>;
+		tx-disable-gpios = <&sgpio_out 8 2 GPIO_ACTIVE_HIGH>;
+		los-gpios = <&sgpio_in 8 0 GPIO_ACTIVE_HIGH>;
+		mod-def0-gpios = <&sgpio_in 8 1 GPIO_ACTIVE_LOW>;
+		tx-fault-gpios = <&sgpio_in 8 2 GPIO_ACTIVE_HIGH>;
+	};
+
+	sfp3: sfp3 {
+		compatible = "sff,sfp";
+		i2c-bus = <&i2c_sfp3>;
+		tx-disable-gpios = <&sgpio_out 9 2 GPIO_ACTIVE_HIGH>;
+		los-gpios = <&sgpio_in 9 0 GPIO_ACTIVE_HIGH>;
+		mod-def0-gpios = <&sgpio_in 9 1 GPIO_ACTIVE_LOW>;
+		tx-fault-gpios = <&sgpio_in 9 2 GPIO_ACTIVE_HIGH>;
+	};
+};
+
+&flx0 {
+	atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_USART>;
+	status = "okay";
+};
+
+&usart0 {
+	pinctrl-0 = <&fc0_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&flx2 {
+	atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_SPI>;
+	status = "okay";
+};
+
+&spi2 {
+	pinctrl-0 = <&fc2_pins>;
+	pinctrl-names = "default";
+	cs-gpios = <&gpio 63 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&flx3 {
+	atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_TWI>;
+	status = "okay";
+};
+
+&i2c3 {
+	pinctrl-0 = <&fc3_pins>;
+	pinctrl-names = "default";
+	i2c-analog-filter;
+	i2c-digital-filter;
+	i2c-digital-filter-width-ns = <35>;
+	i2c-sda-hold-time-ns = <1500>;
+	status = "okay";
+};
+
+&gpio {
+	emmc_sd_pins: emmc-sd-pins {
+		/* eMMC_SD - CMD, CLK, D0, D1, D2, D3, D4, D5, D6, D7, RSTN */
+		pins = "GPIO_14", "GPIO_15", "GPIO_16", "GPIO_17",
+		       "GPIO_18", "GPIO_19", "GPIO_20", "GPIO_21",
+		       "GPIO_22", "GPIO_23", "GPIO_24";
+		function = "emmc_sd";
+	};
+
+	fan_pins: fan-pins {
+		pins = "GPIO_25", "GPIO_26";
+		function = "fan";
+	};
+
+	fc0_pins: fc0-pins {
+		pins = "GPIO_3", "GPIO_4";
+		function = "fc";
+	};
+
+	fc2_pins: fc2-pins {
+		pins = "GPIO_64", "GPIO_65", "GPIO_66";
+		function = "fc";
+	};
+
+	fc3_pins: fc3-pins {
+		pins = "GPIO_55", "GPIO_56";
+		function = "fc";
+	};
+
+	mdio_pins: mdio-pins {
+		pins = "GPIO_9", "GPIO_10";
+		function = "miim";
+	};
+
+	mdio_irq_pins: mdio-irq-pins {
+		pins = "GPIO_11";
+		function = "miim_irq";
+	};
+
+	sgpio_pins: sgpio-pins {
+		/* SCK, D0, D1, LD */
+		pins = "GPIO_5", "GPIO_6", "GPIO_7", "GPIO_8";
+		function = "sgpio_a";
+	};
+
+	usb_ulpi_pins: usb-ulpi-pins {
+		pins = "GPIO_30", "GPIO_31", "GPIO_32", "GPIO_33",
+		"GPIO_34", "GPIO_35", "GPIO_36", "GPIO_37",
+		"GPIO_38", "GPIO_39", "GPIO_40", "GPIO_41";
+		function = "usb_ulpi";
+	};
+
+	usb_rst_pins: usb-rst-pins {
+		pins = "GPIO_12";
+		function = "usb2phy_rst";
+	};
+
+	usb_over_pins: usb-over-pins {
+		pins = "GPIO_13";
+		function = "usb_over_detect";
+	};
+
+	usb_power_pins: usb-power-pins {
+		pins = "GPIO_1";
+		function = "usb_power";
+	};
+
+	ptp_out_pins: ptp-out-pins {
+		pins = "GPIO_58";
+		function = "ptpsync_4";
+	};
+
+	ptp_ext_pins: ptp-ext-pins {
+		pins = "GPIO_59";
+		function = "ptpsync_5";
+	};
+};
+
+&tmon {
+	pinctrl-0 = <&fan_pins>;
+	pinctrl-names = "default";
+};
+
+&mdio0 {
+	pinctrl-0 = <&mdio_pins>, <&mdio_irq_pins>;
+	pinctrl-names = "default";
+	reset-gpios = <&gpio 62 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	phy3: phy at 3 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <3>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy4: phy at 4 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <4>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy5: phy at 5 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <5>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy6: phy at 6 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <6>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy7: phy at 7 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <7>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy8: phy at 8 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <8>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy9: phy at 9 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <9>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy10: phy at 10 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <10>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy11: phy at 11 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <11>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy12: phy at 12 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <12>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy13: phy at 13 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <13>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy14: phy at 14 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <14>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy15: phy at 15 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <15>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy16: phy at 16 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <16>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy17: phy at 17 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <17>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy18: phy at 18 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <18>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy19: phy at 19 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <19>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy20: phy at 20 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <20>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy21: phy at 21 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <21>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy22: phy at 22 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <22>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy23: phy at 23 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <23>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy24: phy at 24 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <24>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy25: phy at 25 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <25>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy26: phy at 26 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <26>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy27: phy at 27 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <27>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+};
+
+&serdes {
+	status = "okay";
+};
+
+&sgpio {
+	pinctrl-0 = <&sgpio_pins>;
+	pinctrl-names = "default";
+
+	microchip,sgpio-port-ranges = <0 1>, <6 9>;
+	status = "okay";
+
+	gpio at 0 {
+		ngpios = <128>;
+	};
+	gpio at 1 {
+		ngpios = <128>;
+	};
+};
+
+&switch {
+	pinctrl-0 = <&ptp_out_pins>, <&ptp_ext_pins>;
+	pinctrl-names = "default";
+
+	status = "okay";
+	ethernet-ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port0: port at 0 {
+			reg = <0>;
+			microchip,bandwidth = <1000>;
+			phy-handle = <&phy4>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 0>;
+		};
+
+		port1: port at 1 {
+			reg = <1>;
+			microchip,bandwidth = <1000>;
+			phy-handle = <&phy5>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 0>;
+		};
+
+		port2: port at 2 {
+			reg = <2>;
+			microchip,bandwidth = <1000>;
+			phy-handle = <&phy6>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 0>;
+		};
+
+		port3: port at 3 {
+			reg = <3>;
+			microchip,bandwidth = <1000>;
+			phy-handle = <&phy7>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 0>;
+		};
+
+		port4: port at 4 {
+			reg = <4>;
+			microchip,bandwidth = <1000>;
+			phy-handle = <&phy8>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 1>;
+		};
+
+		port5: port at 5 {
+			reg = <5>;
+			microchip,bandwidth = <1000>;
+			phy-handle = <&phy9>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 1>;
+		};
+
+		port6: port at 6 {
+			reg = <6>;
+			microchip,bandwidth = <1000>;
+			phy-handle = <&phy10>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 1>;
+		};
+
+		port7: port at 7 {
+			reg = <7>;
+			microchip,bandwidth = <1000>;
+			phy-handle = <&phy11>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 1>;
+		};
+
+		port8: port at 8 {
+			reg = <8>;
+			microchip,bandwidth = <1000>;
+			phy-handle = <&phy12>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 2>;
+		};
+
+		port9: port at 9 {
+			reg = <9>;
+			microchip,bandwidth = <1000>;
+			phy-handle = <&phy13>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 2>;
+		};
+
+		port10: port at 10 {
+			reg = <10>;
+			microchip,bandwidth = <1000>;
+			phy-handle = <&phy14>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 2>;
+		};
+
+		port11: port at 11 {
+			reg = <11>;
+			microchip,bandwidth = <1000>;
+			phy-handle = <&phy15>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 2>;
+		};
+
+		port12: port at 12 {
+			reg = <12>;
+			microchip,bandwidth = <1000>;
+			phy-handle = <&phy16>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 3>;
+		};
+
+		port13: port at 13 {
+			reg = <13>;
+			microchip,bandwidth = <1000>;
+			phy-handle = <&phy17>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 3>;
+		};
+
+		port14: port at 14 {
+			reg = <14>;
+			microchip,bandwidth = <1000>;
+			phy-handle = <&phy18>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 3>;
+		};
+
+		port15: port at 15 {
+			reg = <15>;
+			microchip,bandwidth = <1000>;
+			phy-handle = <&phy19>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 3>;
+		};
+
+		port16: port at 16 {
+			reg = <16>;
+			microchip,bandwidth = <1000>;
+			phy-handle = <&phy20>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 4>;
+		};
+
+		port17: port at 17 {
+			reg = <17>;
+			microchip,bandwidth = <1000>;
+			phy-handle = <&phy21>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 4>;
+		};
+
+		port18: port at 18 {
+			reg = <18>;
+			microchip,bandwidth = <1000>;
+			phy-handle = <&phy22>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 4>;
+		};
+
+		port19: port at 19 {
+			reg = <19>;
+			microchip,bandwidth = <1000>;
+			phy-handle = <&phy23>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 4>;
+		};
+
+		port20: port at 20 {
+			reg = <20>;
+			microchip,bandwidth = <1000>;
+			phy-handle = <&phy24>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 5>;
+		};
+
+		port21: port at 21 {
+			reg = <21>;
+			microchip,bandwidth = <1000>;
+			phy-handle = <&phy25>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 5>;
+		};
+
+		port22: port at 22 {
+			reg = <22>;
+			microchip,bandwidth = <1000>;
+			phy-handle = <&phy26>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 5>;
+		};
+
+		port23: port at 23 {
+			reg = <23>;
+			microchip,bandwidth = <1000>;
+			phy-handle = <&phy27>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 5>;
+		};
+
+		port24: port at 24 {
+			reg = <24>;
+			microchip,bandwidth = <10000>;
+			phys = <&serdes 6>;
+			phy-mode = "10gbase-r";
+			sfp = <&sfp0>;
+			microchip,sd-sgpio = <24>;
+			managed = "in-band-status";
+		};
+
+		port25: port at 25 {
+			reg = <25>;
+			microchip,bandwidth = <10000>;
+			phys = <&serdes 7>;
+			phy-mode = "10gbase-r";
+			sfp = <&sfp1>;
+			microchip,sd-sgpio = <28>;
+			managed = "in-band-status";
+		};
+
+		port26: port at 26 {
+			reg = <26>;
+			microchip,bandwidth = <10000>;
+			phys = <&serdes 8>;
+			phy-mode = "10gbase-r";
+			sfp = <&sfp2>;
+			microchip,sd-sgpio = <32>;
+			managed = "in-band-status";
+		};
+
+		port27: port at 27 {
+			reg = <27>;
+			microchip,bandwidth = <10000>;
+			phys = <&serdes 9>;
+			phy-mode = "10gbase-r";
+			sfp = <&sfp3>;
+			microchip,sd-sgpio = <36>;
+			managed = "in-band-status";
+		};
+
+		port29: port at 29 {
+			reg = <29>;
+			microchip,bandwidth = <1000>;
+			phys = <&serdes 11>;
+			phy-handle = <&phy3>;
+			phy-mode = "rgmii";
+			rx-internal-delay-ps = <1000>;
+			tx-internal-delay-ps = <1000>;
+		};
+	};
+};
+
+&usb {
+	status = "okay";
+	pinctrl-0 = <&usb_ulpi_pins>, <&usb_rst_pins>, <&usb_over_pins>, <&usb_power_pins>;
+	pinctrl-names = "default";
+};
diff --git a/arch/arm64/boot/dts/microchip/lan969x.dtsi b/arch/arm64/boot/dts/microchip/lan969x.dtsi
new file mode 100644
index 000000000000..39ea1999c801
--- /dev/null
+++ b/arch/arm64/boot/dts/microchip/lan969x.dtsi
@@ -0,0 +1,482 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT)
+/*
+ * Copyright (c) 2025 Microchip Technology Inc. and its subsidiaries.
+ */
+
+#include <dt-bindings/clock/microchip,lan969x.h>
+#include <dt-bindings/dma/at91.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/mfd/at91-usart.h>
+#include <dt-bindings/mfd/atmel-flexcom.h>
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	model = "Microchip LAN969x";
+	compatible = "microchip,lan969x";
+	interrupt-parent = <&gic>;
+
+	psci {
+		compatible = "arm,psci-1.0";
+		method = "smc";
+	};
+
+	clocks {
+		fx100_clk: fx100-clk {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <320000000>;
+		};
+
+		cpu_clk: cpu-clk {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <1000000000>;
+		};
+
+		ddr_clk: ddr-clk {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <600000000>;
+		};
+
+		fabric_clk: fabric-clk {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <250000000>;
+		};
+	};
+
+	cpus {
+		#address-cells = <2>;
+		#size-cells = <0>;
+
+		cpu0: cpu at 0 {
+			compatible = "arm,cortex-a53";
+			device_type = "cpu";
+			reg = <0x0 0x0>;
+			next-level-cache = <&l2_0>;
+		};
+
+		l2_0: l2-cache {
+			compatible = "cache";
+			cache-level = <2>;
+			cache-unified;
+		};
+	};
+
+	pmu {
+		compatible = "arm,cortex-a53-pmu";
+		interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>, /* Secure Phys IRQ */
+			     <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>, /* Non-secure Phys IRQ */
+			     <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>, /* Virt IRQ */
+			     <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>; /* Hyp IRQ */
+	};
+
+	axi: axi {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		usb: usb at 300000 {
+			compatible = "microchip,lan9691-dwc3", "snps,dwc3";
+			reg = <0x300000 0x80000>;
+			interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clks GCK_GATE_USB_DRD>,
+				 <&clks GCK_ID_USB_REFCLK>;
+			clock-names = "bus_early", "ref";
+			assigned-clocks = <&clks GCK_ID_USB_REFCLK>;
+			assigned-clock-rates = <60000000>;
+			maximum-speed = "high-speed";
+			dr_mode = "host";
+			status = "disabled";
+		};
+
+		flx0: flexcom at e0040000 {
+			compatible = "atmel,sama5d2-flexcom";
+			reg = <0xe0040000 0x100>;
+			clocks = <&clks GCK_ID_FLEXCOM0>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x0 0xe0040000 0x800>;
+			status = "disabled";
+
+			usart0: serial at 200 {
+				compatible = "atmel,at91sam9260-usart";
+				reg = <0x200 0x200>;
+				atmel,usart-mode = <AT91_USART_MODE_SERIAL>;
+				interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
+				       <&dma AT91_XDMAC_DT_PERID(2)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				clock-names = "usart";
+				atmel,fifo-size = <32>;
+				status = "disabled";
+			};
+
+			spi0: spi at 400 {
+				compatible = "atmel,at91rm9200-spi";
+				reg = <0x400 0x200>;
+				interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
+				       <&dma AT91_XDMAC_DT_PERID(2)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				clock-names = "spi_clk";
+				atmel,fifo-size = <32>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+
+			i2c0: i2c at 600 {
+				compatible = "microchip,sam9x60-i2c";
+				reg = <0x600 0x200>;
+				interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
+				       <&dma AT91_XDMAC_DT_PERID(2)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+		};
+
+		flx1: flexcom at e0044000 {
+			compatible = "atmel,sama5d2-flexcom";
+			reg = <0xe0044000 0x100>;
+			clocks = <&clks GCK_ID_FLEXCOM1>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x0 0xe0044000 0x800>;
+			status = "disabled";
+
+			usart1: serial at 200 {
+				compatible = "atmel,at91sam9260-usart";
+				reg = <0x200 0x200>;
+				atmel,usart-mode = <AT91_USART_MODE_SERIAL>;
+				interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
+				       <&dma AT91_XDMAC_DT_PERID(2)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				clock-names = "usart";
+				atmel,fifo-size = <32>;
+				status = "disabled";
+			};
+
+			spi1: spi at 400 {
+				compatible = "atmel,at91rm9200-spi";
+				reg = <0x400 0x200>;
+				interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
+				       <&dma AT91_XDMAC_DT_PERID(2)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				clock-names = "spi_clk";
+				atmel,fifo-size = <32>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+
+			i2c1: i2c at 600 {
+				compatible = "microchip,sam9x60-i2c";
+				reg = <0x600 0x200>;
+				interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
+				       <&dma AT91_XDMAC_DT_PERID(2)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+		};
+
+		trng: rng at e0048000 {
+			compatible = "atmel,at91sam9g45-trng";
+			reg = <0xe0048000 0x100>;
+			clocks = <&fabric_clk>;
+			status = "disabled";
+		};
+
+		aes: crypto at e004c000 {
+			compatible = "atmel,at91sam9g46-aes";
+			reg = <0xe004c000 0x100>;
+			interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&dma AT91_XDMAC_DT_PERID(12)>,
+			       <&dma AT91_XDMAC_DT_PERID(13)>;
+			dma-names = "tx", "rx";
+			clocks = <&fabric_clk>;
+			clock-names = "aes_clk";
+			status = "disabled";
+		};
+
+		flx2: flexcom at e0060000 {
+			compatible = "atmel,sama5d2-flexcom";
+			reg = <0xe0060000 0x100>;
+			clocks = <&clks GCK_ID_FLEXCOM2>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x0 0xe0060000 0x800>;
+			status = "disabled";
+
+			usart2: serial at 200 {
+				compatible = "atmel,at91sam9260-usart";
+				reg = <0x200 0x200>;
+				atmel,usart-mode = <AT91_USART_MODE_SERIAL>;
+				interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(7)>,
+				       <&dma AT91_XDMAC_DT_PERID(6)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				clock-names = "usart";
+				atmel,fifo-size = <32>;
+				status = "disabled";
+			};
+
+			spi2: spi at 400 {
+				compatible = "atmel,at91rm9200-spi";
+				reg = <0x400 0x200>;
+				interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(7)>,
+				       <&dma AT91_XDMAC_DT_PERID(6)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				clock-names = "spi_clk";
+				atmel,fifo-size = <32>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+
+			i2c2: i2c at 600 {
+				compatible = "microchip,sam9x60-i2c";
+				reg = <0x600 0x200>;
+				interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&fabric_clk>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+		};
+
+		flx3: flexcom at e0064000 {
+			compatible = "atmel,sama5d2-flexcom";
+			reg = <0xe0064000 0x100>;
+			clocks = <&clks GCK_ID_FLEXCOM3>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x0 0xe0064000 0x800>;
+			status = "disabled";
+
+			usart3: serial at 200 {
+				compatible = "atmel,at91sam9260-usart";
+				reg = <0x200 0x200>;
+				atmel,usart-mode = <AT91_USART_MODE_SERIAL>;
+				interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(9)>,
+				       <&dma AT91_XDMAC_DT_PERID(8)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				clock-names = "usart";
+				atmel,fifo-size = <32>;
+				status = "disabled";
+			};
+
+			spi3: spi at 400 {
+				compatible = "atmel,at91rm9200-spi";
+				reg = <0x400 0x200>;
+				interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(9)>,
+				       <&dma AT91_XDMAC_DT_PERID(8)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				clock-names = "spi_clk";
+				atmel,fifo-size = <32>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+
+			i2c3: i2c at 600 {
+				compatible = "microchip,sam9x60-i2c";
+				reg = <0x600 0x200>;
+				interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(9)>,
+				       <&dma AT91_XDMAC_DT_PERID(8)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+		};
+
+		dma: dma-controller at e0068000 {
+			compatible = "microchip,sama7g5-dma";
+			reg = <0xe0068000 0x1000>;
+			interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+			dma-channels = <16>;
+			#dma-cells = <1>;
+			clocks = <&fabric_clk>;
+			clock-names = "dma_clk";
+		};
+
+		sha: crypto at e006c000 {
+			compatible = "atmel,at91sam9g46-sha";
+			reg = <0xe006c000 0xec>;
+			interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&dma AT91_XDMAC_DT_PERID(14)>;
+			dma-names = "tx";
+			clocks = <&fabric_clk>;
+			clock-names = "sha_clk";
+			status = "disabled";
+		};
+
+		timer: timer at e008c000 {
+			compatible = "snps,dw-apb-timer";
+			reg = <0xe008c000 0x400>;
+			clocks = <&fabric_clk>;
+			clock-names = "timer";
+			interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
+		};
+
+		watchdog: watchdog at e0090000 {
+			compatible = "snps,dw-wdt";
+			reg = <0xe0090000 0x1000>;
+			interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&fabric_clk>;
+		};
+
+		cpu_ctrl: syscon at e00c0000 {
+			compatible = "microchip,lan966x-cpu-syscon", "syscon";
+			reg = <0xe00c0000 0x350>;
+		};
+
+		switch: switch at e00c0000 {
+			compatible = "microchip,lan9691-switch";
+			reg = <0xe00c0000 0x0010000>,
+			      <0xe2010000 0x1410000>;
+			reg-names = "cpu", "devices";
+			interrupt-names = "xtr", "fdma", "ptp";
+			interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI  9 IRQ_TYPE_LEVEL_HIGH>;
+			resets = <&reset 0>;
+			reset-names = "switch";
+			status = "disabled";
+		};
+
+		clks: clock-controller at e00c00b4 {
+			compatible = "microchip,lan9691-gck";
+			#clock-cells = <1>;
+			clocks = <&cpu_clk>, <&ddr_clk>, <&fx100_clk>;
+			clock-names = "cpu", "ddr", "sys";
+			reg = <0xe00c00b4 0x30>, <0xe00c0308 0x4>;
+		};
+
+		reset: reset-controller at e201000c {
+			compatible = "microchip,lan9691-switch-reset",
+				     "microchip,lan966x-switch-reset";
+			reg = <0xe201000c 0x4>;
+			reg-names = "gcb";
+			#reset-cells = <1>;
+			cpu-syscon = <&cpu_ctrl>;
+		};
+
+		gpio: pinctrl at e20100d4 {
+			compatible = "microchip,lan9691-pinctrl";
+			reg = <0xe20100d4 0xd4>,
+			      <0xe2010370 0xa8>;
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&gpio 0 0 66>;
+			interrupt-controller;
+			interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+			#interrupt-cells = <2>;
+		};
+
+		mdio0: mdio at e20101a8 {
+			compatible = "mscc,ocelot-miim";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xe20101a8 0x24>;
+			clocks = <&fx100_clk>;
+			status = "disabled";
+		};
+
+		mdio1: mdio at e20101cc {
+			compatible = "mscc,ocelot-miim";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xe20101cc 0x24>;
+			clocks = <&fx100_clk>;
+			status = "disabled";
+		};
+
+		sgpio: gpio at e2010230 {
+			compatible = "microchip,sparx5-sgpio";
+			reg = <0xe2010230 0x118>;
+			clocks = <&fx100_clk>;
+			resets = <&reset 0>;
+			reset-names = "switch";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+
+			sgpio_in: gpio at 0 {
+				compatible = "microchip,sparx5-sgpio-bank";
+				reg = <0>;
+				gpio-controller;
+				#gpio-cells = <3>;
+				interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-controller;
+				#interrupt-cells = <3>;
+			};
+
+			sgpio_out: gpio at 1 {
+				compatible = "microchip,sparx5-sgpio-bank";
+				reg = <1>;
+				gpio-controller;
+				#gpio-cells = <3>;
+			};
+		};
+
+		tmon: hwmon at e2020100 {
+			compatible = "microchip,sparx5-temp";
+			reg = <0xe2020100 0xc>;
+			clocks = <&fx100_clk>;
+			#thermal-sensor-cells = <0>;
+		};
+
+		serdes: serdes at e3410000 {
+			compatible = "microchip,lan9691-serdes";
+			#phy-cells = <1>;
+			clocks = <&fabric_clk>;
+			reg = <0xe3410000 0x150000>;
+		};
+
+		gic: interrupt-controller at e8c11000 {
+			compatible = "arm,gic-400";
+			#interrupt-cells = <3>;
+			interrupt-controller;
+			reg = <0xe8c11000 0x1000>, /* Distributor GICD_ */
+			      <0xe8c12000 0x2000>, /* CPU interface GICC_ */
+			      <0xe8c14000 0x2000>, /* Virt interface control */
+			      <0xe8c16000 0x2000>; /* Virt CPU interface */
+			interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+		};
+	};
+};
-- 
2.52.0



From john.ogness at linutronix.de  Wed Dec  3 04:27:38 2025
From: john.ogness at linutronix.de (John Ogness)
Date: Wed, 03 Dec 2025 13:33:38 +0106
Subject: [PATCH] printk/nbcon: Restore IRQ in atomic flush after each
 emitted record
In-Reply-To: <20251202162639.GD724103@e132581.arm.com>
References: <20251202135832.156559-1-pmladek@suse.com>
 <87o6oheywd.fsf@jogness.linutronix.de>
 <20251202162639.GD724103@e132581.arm.com>
Message-ID: <87ikenyclh.fsf@jogness.linutronix.de>

On 2025-12-02, Leo Yan <leo.yan at arm.com> wrote:
>> I am not really happy about all the local_irq_restore() usage. Using
>> guard syntax would be nice here, but AFAICT there is no guard for
>> local_irq_save()/_restore().
>
> Sorry for suddenly jumping in.  Wouldn't guard(irqsave)() be helpful
> here?

Thanks, I was not aware of the irqsave variant. We would want the scoped
version. So something like this?

$ git diff -w
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 3fa403f9831f..55beb64c4f4a 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -1557,6 +1557,14 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
 	ctxt->allow_unsafe_takeover	= nbcon_allow_unsafe_takeover();
 
 	while (nbcon_seq_read(con) < stop_seq) {
+		/*
+		 * Atomic flushing does not use console driver synchronization
+		 * (i.e. it does not hold the port lock for uart consoles).
+		 * Therefore IRQs must be disabled to avoid being interrupted
+		 * and then calling into a driver that will deadlock trying
+		 * to acquire console ownership.
+		 */
+		scoped_guard(irqsave) {
 			if (!nbcon_context_try_acquire(ctxt, false))
 				return -EPERM;
 
@@ -1569,6 +1577,7 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
 				return -EAGAIN;
 
 			nbcon_context_release(ctxt);
+		}
 
 		if (!ctxt->backlog) {
 			/* Are there reserved but not yet finalized records? */

John


From jie.gan at oss.qualcomm.com  Wed Dec  3 04:29:59 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Wed, 3 Dec 2025 20:29:59 +0800
Subject: [PATCH v7 0/9] coresight: ctcu: Enable byte-cntr function for TMC
 ETR
In-Reply-To: <20251013-enable-byte-cntr-for-ctcu-v7-0-e1e8f41e15dd@oss.qualcomm.com>
References: <20251013-enable-byte-cntr-for-ctcu-v7-0-e1e8f41e15dd@oss.qualcomm.com>
Message-ID: <3e069b0b-c73c-4a42-9d39-9fc5072a2710@oss.qualcomm.com>



On 10/13/2025 1:49 PM, Jie Gan wrote:
> The byte-cntr function provided by the CTCU device is used to count the
> trace data entering the ETR. An interrupt is triggered if the data size
> exceeds the threshold set in the BYTECNTRVAL register. The interrupt
> handler counts the number of triggered interruptions.
> 

Gentle reminder.

> Based on this concept, the irq_cnt can be used to determine whether
> the etr_buf is full. The ETR device will be disabled when the active
> etr_buf is nearly full or a timeout occurs. The nearly full buffer will
> be switched to background after synced. A new buffer will be picked from
> the etr_buf_list, then restart the ETR device.
> 
> The byte-cntr reading functions can access data from the synced and
> deactivated buffer, transferring trace data from the etr_buf to userspace
> without stopping the ETR device.
> 
> The byte-cntr read operation has integrated with the file node tmc_etr,
> for example:
> /dev/tmc_etr0
> /dev/tmc_etr1
> 
> There are two scenarios for the tmc_etr file node with byte-cntr function:
> 1. BYTECNTRVAL register is configured and byte-cntr is enabled -> byte-cntr read
> 2. BYTECNTRVAL register is reset or byte-cntr is disabled -> original behavior
> 
> Shell commands to enable byte-cntr reading for etr0:
> echo 0x10000 > /sys/bus/coresight/devices/ctcu0/irq_threshold
> echo 1 > /sys/bus/coresight/devices/tmc_etr0/enable_sink
> echo 1 > /sys/bus/coresight/devices/etm0/enable_source
> cat /dev/tmc_etr0
> 
> Enable both ETR0 and ETR1:
> echo 0x10000 0x10000 > /sys/bus/coresight/devices/ctcu0/irq_threshold
> 
> Reset the BYTECNTR register for etr0:
> echo 0 > /sys/bus/coresight/devices/ctcu0/irq_threshold
> 
> Changes in V7:
> 1. rebased on tag next-20251010
> 2. updated info for sysfs node document
> Link to V6 - https://lore.kernel.org/all/20250908-enable-byte-cntr-for-tmc-v6-0-1db9e621441a at oss.qualcomm.com/
> 
> Changes in V6:
> 1. rebased on next-20250905.
> 2. fixed the issue that the dtsi file has re-named from sa8775p.dtsi to
>     lemans.dtsi.
> 3. fixed some minor issues about comments.
> Link to V5 - https://lore.kernel.org/all/20250812083731.549-1-jie.gan at oss.qualcomm.com/
> 
> Changes in V5:
> 1. Add Mike's reviewed-by tag for patchset 1,2,5.
> 2. Remove the function pointer added to helper_ops according to Mike's
>     comment, it also results the patchset has been removed.
> 3. Optimizing the paired create/clean functions for etr_buf_list.
> 4. Remove the unneeded parameter "reading" from the etr_buf_node.
> Link to V4 - https://lore.kernel.org/all/20250725100806.1157-1-jie.gan at oss.qualcomm.com/
> 
> Changes in V4:
> 1. Rename the function to coresight_get_in_port_dest regarding to Mike's
> comment (patch 1/10).
> 2. Add lock to protect the connections regarding to Mike's comment
> (patch 2/10).
> 3. Move all byte-cntr functions to coresight-ctcu-byte-cntr file.
> 4. Add tmc_read_ops to wrap all read operations for TMC device.
> 5. Add a function in helper_ops to check whether the byte-cntr is
> enabkled.
> 6. Call byte-cntr's read_ops if byte-cntr is enabled when reading data
> from the sysfs node.
> Link to V3 resend - https://lore.kernel.org/all/20250714063109.591-1-jie.gan at oss.qualcomm.com/
> 
> Changes in V3 resend:
> 1. rebased on next-20250711.
> Link to V3 - https://lore.kernel.org/all/20250624060438.7469-1-jie.gan at oss.qualcomm.com/
> 
> Changes in V3:
> 1. The previous solution has been deprecated.
> 2. Add a etr_buf_list to manage allcated etr buffers.
> 3. Add a logic to switch buffer for ETR.
> 4. Add read functions to read trace data from synced etr buffer.
> Link to V2 - https://lore.kernel.org/all/20250410013330.3609482-1-jie.gan at oss.qualcomm.com/
> 
> Changes in V2:
> 1. Removed the independent file node /dev/byte_cntr.
> 2. Integrated the byte-cntr's file operations with current ETR file
>     node.
> 3. Optimized the driver code of the CTCU that associated with byte-cntr.
> 4. Add kernel document for the export API tmc_etr_get_rwp_offset.
> 5. Optimized the way to read the rwp_offset according to Mike's
>     suggestion.
> 6. Removed the dependency of the dts patch.
> Link to V1 - https://lore.kernel.org/all/20250310090407.2069489-1-quic_jiegan at quicinc.com/
> 
> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
> ---
> Jie Gan (9):
>        coresight: core: Refactoring ctcu_get_active_port and make it generic
>        coresight: core: add a new API to retrieve the helper device
>        coresight: tmc: add etr_buf_list to store allocated etr_buf
>        coresight: tmc: add create/clean functions for etr_buf_list
>        coresight: tmc: Introduce sysfs_read_ops to wrap sysfs read operations
>        dt-bindings: arm: add an interrupt property for Coresight CTCU
>        coresight: ctcu: enable byte-cntr for TMC ETR devices
>        coresight: tmc: integrate byte-cntr's read_ops with sysfs file_ops
>        arm64: dts: qcom: lemans: Add interrupts to CTCU device
> 
>   .../ABI/testing/sysfs-bus-coresight-devices-ctcu   |   6 +
>   .../bindings/arm/qcom,coresight-ctcu.yaml          |  17 +
>   arch/arm64/boot/dts/qcom/lemans.dtsi               |   5 +
>   drivers/hwtracing/coresight/Makefile               |   2 +-
>   drivers/hwtracing/coresight/coresight-core.c       |  59 ++++
>   .../hwtracing/coresight/coresight-ctcu-byte-cntr.c | 368 +++++++++++++++++++++
>   drivers/hwtracing/coresight/coresight-ctcu-core.c  | 108 ++++--
>   drivers/hwtracing/coresight/coresight-ctcu.h       |  62 +++-
>   drivers/hwtracing/coresight/coresight-priv.h       |   4 +
>   drivers/hwtracing/coresight/coresight-tmc-core.c   | 104 ++++--
>   drivers/hwtracing/coresight/coresight-tmc-etr.c    | 112 +++++++
>   drivers/hwtracing/coresight/coresight-tmc.h        |  37 +++
>   12 files changed, 825 insertions(+), 59 deletions(-)
> ---
> base-commit: 2b763d4652393c90eaa771a5164502ec9dd965ae
> change-id: 20251013-enable-byte-cntr-for-ctcu-6199b791b77a
> 
> Best regards,



From maz at kernel.org  Wed Dec  3 05:00:57 2025
From: maz at kernel.org (Marc Zyngier)
Date: Wed, 03 Dec 2025 13:00:57 +0000
Subject: [PATCH 4/4] KVM: arm64: Convert VTCR_EL2 to config-driven sanitisation
In-Reply-To: <aTAijieCI8055FL0@raptor>
References: <20251129144525.2609207-1-maz@kernel.org>
	<20251129144525.2609207-5-maz@kernel.org>
	<aTAijieCI8055FL0@raptor>
Message-ID: <86ikenpvna.wl-maz@kernel.org>

On Wed, 03 Dec 2025 11:44:14 +0000,
Alexandru Elisei <alexandru.elisei at arm.com> wrote:
> 
> Hi Marc,
> 
> On Sat, Nov 29, 2025 at 02:45:25PM +0000, Marc Zyngier wrote:
> > Describe all the VTCR_EL2 fields and their respective configurations,
> > making sure that we correctly ignore the bits that are not defined
> > for a given guest configuration.
> > 
> > Signed-off-by: Marc Zyngier <maz at kernel.org>
> > ---
> >  arch/arm64/kvm/config.c | 69 +++++++++++++++++++++++++++++++++++++++++
> >  arch/arm64/kvm/nested.c |  3 +-
> >  2 files changed, 70 insertions(+), 2 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
> > index a02c28d6a61c9..c36e133c51912 100644
> > --- a/arch/arm64/kvm/config.c
> > +++ b/arch/arm64/kvm/config.c
> > @@ -141,6 +141,7 @@ struct reg_feat_map_desc {
> >  #define FEAT_AA64EL1		ID_AA64PFR0_EL1, EL1, IMP
> >  #define FEAT_AA64EL2		ID_AA64PFR0_EL1, EL2, IMP
> >  #define FEAT_AA64EL3		ID_AA64PFR0_EL1, EL3, IMP
> > +#define FEAT_SEL2		ID_AA64PFR0_EL1, SEL2, IMP
> >  #define FEAT_AIE		ID_AA64MMFR3_EL1, AIE, IMP
> >  #define FEAT_S2POE		ID_AA64MMFR3_EL1, S2POE, IMP
> >  #define FEAT_S1POE		ID_AA64MMFR3_EL1, S1POE, IMP
> > @@ -202,6 +203,8 @@ struct reg_feat_map_desc {
> >  #define FEAT_ASID2		ID_AA64MMFR4_EL1, ASID2, IMP
> >  #define FEAT_MEC		ID_AA64MMFR3_EL1, MEC, IMP
> >  #define FEAT_HAFT		ID_AA64MMFR1_EL1, HAFDBS, HAFT
> > +#define FEAT_HDBSS		ID_AA64MMFR1_EL1, HAFDBS, HDBSS
> > +#define FEAT_HPDS2		ID_AA64MMFR1_EL1, HPDS, HPDS2
> >  #define FEAT_BTI		ID_AA64PFR1_EL1, BT, IMP
> >  #define FEAT_ExS		ID_AA64MMFR0_EL1, EXS, IMP
> >  #define FEAT_IESB		ID_AA64MMFR2_EL1, IESB, IMP
> > @@ -219,6 +222,7 @@ struct reg_feat_map_desc {
> >  #define FEAT_FGT2		ID_AA64MMFR0_EL1, FGT, FGT2
> >  #define FEAT_MTPMU		ID_AA64DFR0_EL1, MTPMU, IMP
> >  #define FEAT_HCX		ID_AA64MMFR1_EL1, HCX, IMP
> > +#define FEAT_S2PIE		ID_AA64MMFR3_EL1, S2PIE, IMP
> >  
> >  static bool not_feat_aa64el3(struct kvm *kvm)
> >  {
> > @@ -362,6 +366,28 @@ static bool feat_pmuv3p9(struct kvm *kvm)
> >  	return check_pmu_revision(kvm, V3P9);
> >  }
> >  
> > +#define has_feat_s2tgran(k, s)						\
> > +  ((kvm_has_feat_enum(kvm, ID_AA64MMFR0_EL1, TGRAN##s##_2, TGRAN##s) && \
> > +    !kvm_has_feat_enum(kvm, ID_AA64MMFR0_EL1, TGRAN##s, NI))	     ||	\
> 
> Wouldn't that read better as kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN##s, IMP)?
> I think that would also be correct.

Sure, I don't mind either way,

> 
> > +   kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN##s##_2, IMP))
> 
> A bit unexpected to treat the same field first as an enum, then as an integer,
> but it saves one line.

It potentially saves more if the encoding grows over time. I don't
think it matters.

> 
> > +
> > +static bool feat_lpa2(struct kvm *kvm)
> > +{
> > +	return ((kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4, 52_BIT)    ||
> > +		 !kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4, IMP))	&&
> > +		(kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16, 52_BIT)   ||
> > +		 !kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16, IMP))	&&
> > +		(kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4_2, 52_BIT)  ||
> > +		 !has_feat_s2tgran(kvm, 4))				&&
> > +		(kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16_2, 52_BIT) ||
> > +		 !has_feat_s2tgran(kvm, 16)));
> > +}
> 
> That was a doozy, but looks correct to me if the intention was to have the check
> as relaxed as possible - i.e, a VM can advertise 52 bit support for one granule,
> but not the other (same for stage 1 and stage 2).

Not quite. The intent is that, for all the possible granules, at all
the possible stages, either the granule size isn't implemented at all,
or it supports 52 bits. I think this covers it, but as you said, this
is a bit of a bran fsck.

This is essentially a transliteration of the MRS:

(FEAT_LPA2 && FEAT_S2TGran4K) <=> (UInt(ID_AA64MMFR0_EL1.TGran4_2) >= 3))
(FEAT_LPA2 && FEAT_S2TGran16K) <=> (UInt(ID_AA64MMFR0_EL1.TGran16_2) >= 3))
(FEAT_LPA2 && FEAT_TGran4K) <=> (SInt(ID_AA64MMFR0_EL1.TGran4) >= 1))
(FEAT_LPA2 && FEAT_TGran16K) <=> (UInt(ID_AA64MMFR0_EL1.TGran16) >= 2))
FEAT_S2TGran4K <=> (((UInt(ID_AA64MMFR0_EL1.TGran4_2) == 0) && FEAT_TGran4K) || (UInt(ID_AA64MMFR0_EL1.TGran4_2) >= 2))
FEAT_S2TGran16K <=> (((UInt(ID_AA64MMFR0_EL1.TGran16_2) == 0) && FEAT_TGran16K) || (UInt(ID_AA64MMFR0_EL1.TGran16_2) >= 2))
FEAT_TGran4K <=> (SInt(ID_AA64MMFR0_EL1.TGran4) >= 0)
FEAT_TGran16K <=> (UInt(ID_AA64MMFR0_EL1.TGran16) >= 1)

> As far as I can tell, everything looks good to me:
> 
> Reviewed-by: Alexandru Elisei <alexandru.elisei at arm.com>

Thanks,

	M.

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


From louisalexis.eyraud at collabora.com  Wed Dec  3 05:59:26 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Wed, 03 Dec 2025 14:59:26 +0100
Subject: [PATCH 1/4] dt-bindings: serial: mediatek,uart: Add compatible for
 MT8189 SoC
In-Reply-To: <20251203-add-mediatek-genio-520-720-evk-v1-0-df794b2a30ae@collabora.com>
References: <20251203-add-mediatek-genio-520-720-evk-v1-0-df794b2a30ae@collabora.com>
Message-ID: <20251203-add-mediatek-genio-520-720-evk-v1-1-df794b2a30ae@collabora.com>

Add a compatible string for the MT8189 SoC.
The UART IPs in this chip are fully compatible with the one found in
MT6577 SoC.

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 Documentation/devicetree/bindings/serial/mediatek,uart.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/serial/mediatek,uart.yaml b/Documentation/devicetree/bindings/serial/mediatek,uart.yaml
index 5bd8a8853ae0d4ae309d28350fd54b6f9b4e731e..3f0f4aea0a4c0ef11055ddd08ba71d045e7fa519 100644
--- a/Documentation/devicetree/bindings/serial/mediatek,uart.yaml
+++ b/Documentation/devicetree/bindings/serial/mediatek,uart.yaml
@@ -47,6 +47,7 @@ properties:
               - mediatek,mt8183-uart
               - mediatek,mt8186-uart
               - mediatek,mt8188-uart
+              - mediatek,mt8189-uart
               - mediatek,mt8192-uart
               - mediatek,mt8195-uart
               - mediatek,mt8365-uart

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Wed Dec  3 05:59:25 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Wed, 03 Dec 2025 14:59:25 +0100
Subject: [PATCH 0/4] Add support for the Mediatek Genio 520-EVK and 720-EVK
 boards
Message-ID: <20251203-add-mediatek-genio-520-720-evk-v1-0-df794b2a30ae@collabora.com>

This patch series adds the support for the Mediatek Genio 520-EVK (based
on MT8371 SoC) and Mediatek Genio 720-EVK (based on MT8391 SoC).

MT8371 and MT8391 SoC are less powerful variants of MT8189 SoC
with the following differences:
  - Arm Cortex-A78 CPU core maximum frequency (2.2 Ghz for MT8371, 2.6
    Ghz for MT8391, 3 Ghz for MT8189).
  - Arm Mali G57 MC2 GPU core maximum frequency (880 Mhz for MT8371,
    1.1 Ghz for MT8189 and MT8391)
  - ISP engine number (1 for MT8371, 2 for MT8189 and MT8391)
MT8371 and MT8391 SoC hardware register maps are identical to MT8189.

The Genio 520/720-EVK boards have following features:
  - MT8371 (or MT8391) SoC
  - MT6365 PMIC
  - MT6319 Buck IC
  - MT6375 Charger IC
  - 8GB LPDDR5 RAM
  - 64GB eMMC 5.1
  - 128GB UFS
  - 20V DC Jack
  - USB Type-C Power Adapter
  - Micro SD card slot
  - Push Button x 4 (Power, Reset, Download and Home Key)
  - LED x 3 (System Power, Reset, DC-IN Power)
  - USB Type-C Connector (USB 3.2) x 2
  - USB Type-C Connector (USB 2.0) x 1
  - 3.5mm Earphone Jack x 1 (with Microphone Input)
  - 3.5mm Line Out Audio Jack x 1
  - Analog Microphone x 1
  - Digital Microphone x 2
  - Gigabit Ethernet with RJ45 connector
  - DP x 1 (Mode over USB Type-C)
  - LVDS port x 1
  - eDP port x 1
  - UART x2 with serial-to-usb converters and USB Type-C connectors
  - UART Port x 2 on Pin Header
  - M.2 Slot x 2
  - I2C Capacitive Touch Pad
  - 4-Lane DSI x 1
  - 4-Data Lane CSI x 2
  - I2S Pin header
  - 40-Pin 2.54mm Pin Header x 1
  - CAN Bus x 1 (RS232 Connector)

The series adds two include files for mt8189 (mt8189.dtsi) and common
board definitions (mt8391-genio-common.dtsi) and a devicetree file for
each board. In regard to the current MT8189 SoC upstream support and in
order to limit the number of prerequisite patches, this series provides
the following basic hardware enablement for:
  - cpu
  - clocks
  - spmi and regulators
  - UART 0/1/2/3
  - eMMC and SD card
  - watchdog
  - timer
  - efuse and socinfo
  - auxadc

The series is based on linux-next next-20251203 tag, and the
following patch series are currently required:
- I2C dt-bindings [1]
- SPMI dt-bindings [2]
- timer dt-bindings [3]
- Add support for MT8189 clock/power controller [4]
- Add SD/MMC Card driver support for Mediatek MT8189 SoC [5]
- mt8189: Add pinmux macro header file [6]

Note:
The v3 revision of [4] patch series is causing the following `make dtbs_check`
issue for both board devicetrees:
```
arch/arm64/boot/dts/mediatek/mt8391-genio-720-evk.dtb: /soc/clock-controller at 1c000800: 
  failed to match any schema with compatible: ['mediatek,mt8189-vlp-ao', 'syscon']
```
The mismatch between compatible string in driver and dt-bindings has
already been reported during the series review ([7]) and hopefully will be
fixed in its future revision.

[1] https://lore.kernel.org/linux-mediatek/20251030-mt8189-dt-bindings-i2c-v1-1-5b60914c6453 at collabora.com/
[2] https://lore.kernel.org/linux-mediatek/20251029-mt8189-dt-bindings-spmi-v1-1-fbea12a4ed5e at collabora.com/
[3] https://lore.kernel.org/linux-mediatek/20250825033136.7705-1-zhanzhan.ge at mediatek.com/
[4] https://lore.kernel.org/linux-mediatek/20251106124330.1145600-1-irving-ch.lin at mediatek.com/
[5] https://lore.kernel.org/linux-mediatek/20251203-mt8189-add-mmc-support-v1-0-f5ce43212fe9 at collabora.com/
[6] https://lore.kernel.org/linux-mediatek/20250919020525.7904-1-ot_cathy.xu at mediatek.com/
[7] https://lore.kernel.org/linux-mediatek/a50e6d433afcf8b08a47694bc5a52acc28871ee5.camel at collabora.com/

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
Louis-Alexis Eyraud (4):
      dt-bindings: serial: mediatek,uart: Add compatible for MT8189 SoC
      dt-bindings: arm: mediatek: add compatibles for Mediatek Genio 520/720-EVK boards
      arm64: dts: mediatek: add device-tree for Genio 720-EVK board
      arm64: dts: mediatek: add device-tree for Genio 520-EVK board

 .../devicetree/bindings/arm/mediatek.yaml          |  10 +
 .../devicetree/bindings/serial/mediatek,uart.yaml  |   1 +
 arch/arm64/boot/dts/mediatek/Makefile              |   2 +
 arch/arm64/boot/dts/mediatek/mt8189.dtsi           | 860 +++++++++++++++++++++
 .../boot/dts/mediatek/mt8371-genio-520-evk.dts     |  19 +
 .../boot/dts/mediatek/mt8391-genio-720-evk.dts     |  15 +
 .../boot/dts/mediatek/mt8391-genio-common.dtsi     | 555 +++++++++++++
 7 files changed, 1462 insertions(+)
---
base-commit: e47d97576181b31291cf58e77d737d21def0e160
change-id: 20251128-add-mediatek-genio-520-720-evk-06162377974d
prerequisite-message-id: <20251030-mt8189-dt-bindings-i2c-v1-1-5b60914c6453 at collabora.com>
prerequisite-patch-id: af92e103b9f50af16560a11d4eabc644bd724b07
prerequisite-message-id: <20251029-mt8189-dt-bindings-spmi-v1-1-fbea12a4ed5e at collabora.com>
prerequisite-patch-id: c82ad0d3145322fea43aed2e1d830ebc8eae8180
prerequisite-message-id: <20250825033136.7705-1-zhanzhan.ge at mediatek.com>
prerequisite-patch-id: 7aeee7d452186b3bc1c11722b7ddb7dfbae7d396
prerequisite-message-id: <20251106124330.1145600-1-irving-ch.lin at mediatek.com>
prerequisite-patch-id: ea3e5cf891c9753a77f126ad1ddad455a0752883
prerequisite-patch-id: ae9a4cb1daadb56cc298b87142b29b749dc11835
prerequisite-patch-id: 3df47b0207d75102032975e6811f71a5e7909e43
prerequisite-patch-id: 1c25a1327d50152cef227f58c08076072d65cee3
prerequisite-patch-id: f2cd301aea79253adb85bd3f62c012dd3850e1a7
prerequisite-patch-id: 81dc09321182c48f6928582e8b9d22f35a757515
prerequisite-patch-id: e0a251231fd14fa582800db8f3bb77011f6836f9
prerequisite-patch-id: da7c54c83cb8566df39beac753c80615523479e5
prerequisite-patch-id: 2f3d41e32b230ddc016fd75ace5b286cd11b2127
prerequisite-patch-id: 309f350ed5c942b640b5c3434737fee28d6825b0
prerequisite-patch-id: 7579b6db7ec7a31e28db616c73b4c1b0eb4ee106
prerequisite-patch-id: 0cdea5380c8d35cfd89e01bf843ef7fdafbc7830
prerequisite-patch-id: 3dc3e377981d3c894fc39122200a0f0d46f5d71b
prerequisite-patch-id: b57bf39e50a5316d2f9264e1eb89071d3e8e8b0a
prerequisite-patch-id: 56fd80d33667839823794173064860c613f911cd
prerequisite-patch-id: 963a3ed54fb5fd9fd518f28254eaf93a70b2f603
prerequisite-patch-id: 3c9cbc33093f754d867ca324cc7e689fbbaae8af
prerequisite-patch-id: 336ba35d1924706d1d21c6e46718d973277f207a
prerequisite-patch-id: f3322d6494603585fc4728074484055d07484dd6
prerequisite-patch-id: f5a70e41fe9df7df0ab29538701bdfdb401a9d01
prerequisite-patch-id: b46a91afc38bea2ee6a8440f59e71e39728df6ad
prerequisite-message-id: <20251203-mt8189-add-mmc-support-v1-0-f5ce43212fe9 at collabora.com>
prerequisite-patch-id: feab935ed7d0d7234dcc1980185300782c61620e
prerequisite-patch-id: efbd41a9926397f9b3ffd19235a04791b61f35c7
prerequisite-patch-id: 5b12a1056dfe87e4d39af584d8b16c31a1a00a04
prerequisite-message-id: <20250919020525.7904-1-ot_cathy.xu at mediatek.com>
prerequisite-patch-id: 7f2d960cde2f0e0a307721150e83b7b05b9a60d7

Best regards,
-- 
Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>



From louisalexis.eyraud at collabora.com  Wed Dec  3 05:59:27 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Wed, 03 Dec 2025 14:59:27 +0100
Subject: [PATCH 2/4] dt-bindings: arm: mediatek: add compatibles for
 Mediatek Genio 520/720-EVK boards
In-Reply-To: <20251203-add-mediatek-genio-520-720-evk-v1-0-df794b2a30ae@collabora.com>
References: <20251203-add-mediatek-genio-520-720-evk-v1-0-df794b2a30ae@collabora.com>
Message-ID: <20251203-add-mediatek-genio-520-720-evk-v1-2-df794b2a30ae@collabora.com>

Add compatible strings for the Mediatek Genio 520-EVK (based on
MT8371 SoC) and Mediatek Genio 720-EVK (based on MT8391 SoC) boards.
MT8391 and MT8371 SoC are less powerful variants of MT8189 SoC,
with identical hardware register maps.

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 Documentation/devicetree/bindings/arm/mediatek.yaml | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/mediatek.yaml b/Documentation/devicetree/bindings/arm/mediatek.yaml
index 718d732174b9e3974b1a1bf827f48a347dae741f..9adb3c461796e2b176561db755d7d5131c8951d7 100644
--- a/Documentation/devicetree/bindings/arm/mediatek.yaml
+++ b/Documentation/devicetree/bindings/arm/mediatek.yaml
@@ -442,12 +442,22 @@ properties:
               - mediatek,mt8370-evk
           - const: mediatek,mt8370
           - const: mediatek,mt8188
+      - items:
+          - enum:
+              - mediatek,mt8371-evk
+          - const: mediatek,mt8371
+          - const: mediatek,mt8189
       - items:
           - enum:
               - grinn,genio-700-sbc
               - mediatek,mt8390-evk
           - const: mediatek,mt8390
           - const: mediatek,mt8188
+      - items:
+          - enum:
+              - mediatek,mt8391-evk
+          - const: mediatek,mt8391
+          - const: mediatek,mt8189
       - items:
           - enum:
               - kontron,3-5-sbc-i1200

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Wed Dec  3 05:59:28 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Wed, 03 Dec 2025 14:59:28 +0100
Subject: [PATCH 3/4] arm64: dts: mediatek: add device-tree for Genio
 720-EVK board
In-Reply-To: <20251203-add-mediatek-genio-520-720-evk-v1-0-df794b2a30ae@collabora.com>
References: <20251203-add-mediatek-genio-520-720-evk-v1-0-df794b2a30ae@collabora.com>
Message-ID: <20251203-add-mediatek-genio-520-720-evk-v1-3-df794b2a30ae@collabora.com>

Add support for MediaTek MT8189 SoC and its variants, and a device-tree
for the basic hardware enablement of the Genio 720-EVK board, based on
MT8391 SoC.

MT8391 SoC is a variant of MT8189 SoC with a difference for the Arm
Cortex-A78 CPU core maximum frequency (2.6 Ghz for MT8391, 3 Ghz for
MT8189). MT8391 hardware register maps are identical to MT8189.

The Genio 720-EVK board has following features:
  - MT8391 SoC
  - MT6365 PMIC
  - MT6319 Buck IC
  - MT6375 Charger IC
  - 8GB LPDDR5 RAM
  - 64GB eMMC 5.1
  - 128GB UFS
  - 20V DC Jack
  - USB Type-C Power Adapter
  - Micro SD card slot
  - Push Button x 4 (Power, Reset, Download and Home Key)
  - LED x 3 (System Power, Reset, DC-IN Power)
  - USB Type-C Connector (USB 3.2) x 2
  - USB Type-C Connector (USB 2.0) x 1
  - 3.5mm Earphone Jack x 1 (with Microphone Input)
  - 3.5mm Line Out Audio Jack x 1
  - Analog Microphone x 1
  - Digital Microphone x 2
  - Gigabit Ethernet with RJ45 connector
  - DP x 1 (Mode over USB Type-C)
  - LVDS port x 1
  - eDP port x 1
  - UART x2 with serial-to-usb converters and USB Type-C connectors
  - UART Port x 2 on Pin Header
  - M.2 Slot x 2
  - I2C Capacitive Touch Pad
  - 4-Lane DSI x 1
  - 4-Data Lane CSI x 2
  - I2S Pin header
  - 40-Pin 2.54mm Pin Header x 1
  - CAN Bus x 1 (RS232 Connector)

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 arch/arm64/boot/dts/mediatek/Makefile              |   1 +
 arch/arm64/boot/dts/mediatek/mt8189.dtsi           | 860 +++++++++++++++++++++
 .../boot/dts/mediatek/mt8391-genio-720-evk.dts     |  15 +
 .../boot/dts/mediatek/mt8391-genio-common.dtsi     | 555 +++++++++++++
 4 files changed, 1431 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile
index c5fd6191a925ad8fcea401712f7a686e8b0a57c8..e3b63085c0608b86dc8638c9d5e0b73441e9ed7b 100644
--- a/arch/arm64/boot/dts/mediatek/Makefile
+++ b/arch/arm64/boot/dts/mediatek/Makefile
@@ -110,6 +110,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-genio-1200-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-genio-1200-evk-ufs.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-genio-700-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-grinn-genio-700-sbc.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8391-genio-720-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-kontron-3-5-sbc-i1200.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-radxa-nio-12l.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-radxa-nio-12l-8-hd-panel.dtbo
diff --git a/arch/arm64/boot/dts/mediatek/mt8189.dtsi b/arch/arm64/boot/dts/mediatek/mt8189.dtsi
new file mode 100644
index 0000000000000000000000000000000000000000..bf8a232bcaf10cdf4c590109aea68c9a3e82cc42
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8189.dtsi
@@ -0,0 +1,860 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ *
+ * Copyright (c) 2025 Collabora Ltd.
+ * Author: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
+ */
+
+#include <dt-bindings/clock/mediatek,mt8189-clk.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+	compatible = "mediatek,mt8189";
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	aliases {
+		i2c0 = &i2c0;
+		i2c1 = &i2c1;
+		i2c2 = &i2c2;
+		i2c3 = &i2c3;
+		i2c4 = &i2c4;
+		i2c5 = &i2c5;
+		i2c6 = &i2c6;
+		i2c7 = &i2c7;
+		i2c8 = &i2c8;
+		mmc0 = &mmc0;
+		mmc1 = &mmc1;
+		serial0 = &uart0;
+	};
+
+	clk32k: oscillator-clk32k {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <32000>;
+		clock-output-names = "clk32k";
+	};
+
+	clk13m: oscillator-clk13m {
+		compatible = "fixed-factor-clock";
+		#clock-cells = <0>;
+		clocks = <&clk26m>;
+		clock-mult = <1>;
+		clock-div = <2>;
+		clock-output-names = "clk13m";
+	};
+
+	clk26m: oscillator-clk26m {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <26000000>;
+		clock-output-names = "clk26m";
+	};
+
+	clk104m: oscillator-clk104m {
+		compatible = "fixed-factor-clock";
+		#clock-cells = <0>;
+		clocks = <&clk26m>;
+		clock-mult = <4>;
+		clock-div = <1>;
+		clock-output-names = "clk104m";
+	};
+
+	ulposc: oscillator-ulposc {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <520000000>;
+		clock-output-names = "ulposc";
+	};
+
+	ulposc3: oscillator-ulposc3 {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <26000000>;
+		clock-output-names = "ulposc3";
+	};
+
+	vowpll: oscillator-vowpll {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <26000000>;
+		clock-output-names = "vowpll";
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu0: cpu at 0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a55";
+			reg = <0x000>;
+			enable-method = "psci";
+			capacity-dmips-mhz = <282>;
+			cpu-idle-states = <&cpu_off_l>;
+			i-cache-size = <32768>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <128>;
+			d-cache-size = <32768>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>;
+			next-level-cache = <&l2_0>;
+			performance-domains = <&performance 0>;
+			#cooling-cells = <2>;
+		};
+
+		cpu1: cpu at 100 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a55";
+			reg = <0x100>;
+			enable-method = "psci";
+			capacity-dmips-mhz = <282>;
+			cpu-idle-states = <&cpu_off_l>;
+			i-cache-size = <32768>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <128>;
+			d-cache-size = <32768>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>;
+			next-level-cache = <&l2_0>;
+			performance-domains = <&performance 0>;
+			#cooling-cells = <2>;
+		};
+
+		cpu2: cpu at 200 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a55";
+			reg = <0x200>;
+			enable-method = "psci";
+			capacity-dmips-mhz = <282>;
+			cpu-idle-states = <&cpu_off_l>;
+			i-cache-size = <32768>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <128>;
+			d-cache-size = <32768>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>;
+			next-level-cache = <&l2_0>;
+			performance-domains = <&performance 0>;
+			#cooling-cells = <2>;
+		};
+
+		cpu3: cpu at 300 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a55";
+			reg = <0x300>;
+			enable-method = "psci";
+			capacity-dmips-mhz = <282>;
+			cpu-idle-states = <&cpu_off_l>;
+			i-cache-size = <32768>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <128>;
+			d-cache-size = <32768>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>;
+			next-level-cache = <&l2_0>;
+			performance-domains = <&performance 0>;
+			#cooling-cells = <2>;
+		};
+
+		cpu4: cpu at 400 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a55";
+			reg = <0x400>;
+			enable-method = "psci";
+			capacity-dmips-mhz = <282>;
+			cpu-idle-states = <&cpu_off_l>;
+			i-cache-size = <32768>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <128>;
+			d-cache-size = <32768>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>;
+			next-level-cache = <&l2_0>;
+			performance-domains = <&performance 0>;
+			#cooling-cells = <2>;
+		};
+
+		cpu5: cpu at 500 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a55";
+			reg = <0x500>;
+			enable-method = "psci";
+			capacity-dmips-mhz = <282>;
+			cpu-idle-states = <&cpu_off_l>;
+			i-cache-size = <32768>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <128>;
+			d-cache-size = <32768>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>;
+			next-level-cache = <&l2_0>;
+			performance-domains = <&performance 0>;
+			#cooling-cells = <2>;
+		};
+
+		cpu6: cpu at 600 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a78";
+			reg = <0x600>;
+			enable-method = "psci";
+			capacity-dmips-mhz = <1024>;
+			cpu-idle-states = <&cpu_off_b>;
+			i-cache-size = <65536>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <256>;
+			d-cache-size = <65536>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <256>;
+			next-level-cache = <&l2_1>;
+			performance-domains = <&performance 1>;
+			#cooling-cells = <2>;
+		};
+
+		cpu7: cpu at 700 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a78";
+			reg = <0x700>;
+			enable-method = "psci";
+			capacity-dmips-mhz = <1024>;
+			cpu-idle-states = <&cpu_off_b>;
+			i-cache-size = <65536>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <256>;
+			d-cache-size = <65536>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <256>;
+			next-level-cache = <&l2_1>;
+			performance-domains = <&performance 1>;
+			#cooling-cells = <2>;
+		};
+
+		cpu-map {
+			cluster0 {
+				core0 {
+					cpu = <&cpu0>;
+				};
+
+				core1 {
+					cpu = <&cpu1>;
+				};
+
+				core2 {
+					cpu = <&cpu2>;
+				};
+
+				core3 {
+					cpu = <&cpu3>;
+				};
+
+				core4 {
+					cpu = <&cpu4>;
+				};
+
+				core5 {
+					cpu = <&cpu5>;
+				};
+
+				core6 {
+					cpu = <&cpu6>;
+				};
+
+				core7 {
+					cpu = <&cpu7>;
+				};
+			};
+		};
+
+		idle-states {
+			entry-method = "psci";
+
+			cpu_off_l: cpu-off-l {
+				compatible = "arm,idle-state";
+				arm,psci-suspend-param = <0x00010000>;
+				local-timer-stop;
+				entry-latency-us = <25>;
+				exit-latency-us = <57>;
+				min-residency-us = <5700>;
+			};
+
+			cpu_off_b: cpu-off-b {
+				compatible = "arm,idle-state";
+				arm,psci-suspend-param = <0x00010000>;
+				local-timer-stop;
+				entry-latency-us = <35>;
+				exit-latency-us = <82>;
+				min-residency-us = <1890>;
+			};
+		};
+
+		l2_0: l2-cache0 {
+			compatible = "cache";
+			cache-level = <2>;
+			cache-size = <131072>;
+			cache-line-size = <64>;
+			cache-sets = <512>;
+			next-level-cache = <&l3_0>;
+			cache-unified;
+		};
+
+		l2_1: l2-cache1 {
+			compatible = "cache";
+			cache-level = <2>;
+			cache-size = <262144>;
+			cache-line-size = <64>;
+			cache-sets = <512>;
+			next-level-cache = <&l3_0>;
+			cache-unified;
+		};
+
+		l3_0: l3-cache {
+			compatible = "cache";
+			cache-level = <3>;
+			cache-size = <1048576>;
+			cache-line-size = <64>;
+			cache-sets = <2048>;
+			cache-unified;
+		};
+	};
+
+	memory: memory at 40000000 {
+		device_type = "memory";
+		/* This memory size is filled in by the bootloader */
+		reg = <0 0x40000000 0 0>;
+	};
+
+	pmu-a55 {
+		compatible = "arm,cortex-a55-pmu";
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH &ppi_cluster0>;
+	};
+
+	pmu-a78 {
+		compatible = "arm,cortex-a78-pmu";
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH &ppi_cluster1>;
+	};
+
+	psci {
+		compatible = "arm,psci-1.0";
+		method = "smc";
+	};
+
+	soc {
+		compatible = "simple-bus";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+		dma-ranges = <0x0 0x0 0x0 0x0 0x10 0x0>;
+
+		performance: performance-controller at 108d78 {
+			compatible = "mediatek,cpufreq-hw";
+			reg = <0 0x00108d78 0 0x120>, <0 0x00108e98 0 0x120>;
+			#performance-domain-cells = <1>;
+		};
+
+		gic: interrupt-controller at c000000 {
+			compatible = "arm,gic-v3";
+			reg = <0 0xc000000 0 0x40000>, /* distributor */
+			      <0 0xc040000 0 0x200000>; /* redistributor */
+			interrupt-parent = <&gic>;
+			interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH 0>;
+			interrupt-controller;
+			#interrupt-cells = <4>;
+			#redistributor-regions = <1>;
+
+			ppi-partitions {
+				ppi_cluster0: interrupt-partition-0 {
+					affinity = <&cpu0 &cpu1 &cpu2 &cpu3 &cpu4 &cpu5>;
+				};
+
+				ppi_cluster1: interrupt-partition-1 {
+					affinity = <&cpu6 &cpu7>;
+				};
+			};
+		};
+
+		auxadc: adc at 11019000 {
+			compatible = "mediatek,mt8189-auxadc", "mediatek,mt8173-auxadc";
+			reg = <0 0x11019000 0 0x1000>;
+			clocks = <&pericfg_ao_clk CLK_PERAO_AUXADC_26M>;
+			clock-names = "main";
+			#io-channel-cells = <1>;
+			status = "disabled";
+		};
+
+		clock-controller at 1000c000 {
+			compatible = "mediatek,mt8189-apmixedsys", "syscon";
+			reg = <0 0x1000c000 0 0x1000>;
+			#clock-cells = <1>;
+		};
+
+		clock-controller at 1a000000 {
+			compatible = "mediatek,mt8189-camsys-main", "syscon";
+			reg = <0 0x1a000000 0 0x1000>;
+			#clock-cells = <1>;
+		};
+
+		clock-controller at 1a04f000 {
+			compatible = "mediatek,mt8189-camsys-rawa", "syscon";
+			reg = <0 0x1a04f000 0 0x1000>;
+			#clock-cells = <1>;
+		};
+
+		clock-controller at 1a06f000 {
+			compatible = "mediatek,mt8189-camsys-rawb", "syscon";
+			reg = <0 0x1a06f000 0 0x1000>;
+			#clock-cells = <1>;
+		};
+
+		clock-controller at d01a000 {
+			compatible = "mediatek,mt8189-dbg-ao", "syscon";
+			reg = <0 0xd01a000 0 0x1000>;
+			#clock-cells = <1>;
+		};
+
+		clock-controller at d0a0000 {
+			compatible = "mediatek,mt8189-dem", "syscon";
+			reg = <0 0xd0a0000 0 0x1000>;
+			#clock-cells = <1>;
+		};
+
+		clock-controller at 14000000 {
+			compatible = "mediatek,mt8189-dispsys", "syscon";
+			reg = <0 0x14000000 0 0x1000>;
+			#clock-cells = <1>;
+		};
+
+		clock-controller at 1c00f000 {
+			compatible = "mediatek,mt8189-dvfsrc-top", "syscon";
+			reg = <0 0x1c00f000 0 0x1000>;
+			#clock-cells = <1>;
+		};
+
+		clock-controller at 1e980000 {
+			compatible = "mediatek,mt8189-gce-d", "syscon";
+			reg = <0 0x1e980000 0 0x1000>;
+			#clock-cells = <1>;
+		};
+
+		clock-controller at 1e990000 {
+			compatible = "mediatek,mt8189-gce-m", "syscon";
+			reg = <0 0x1e990000 0 0x1000>;
+			#clock-cells = <1>;
+		};
+
+		iic_wrap_e_clk: clock-controller at 11c22e00 {
+			compatible = "mediatek,mt8189-iic-wrap-e", "syscon";
+			reg = <0 0x11c22e00 0 0x10>;
+			#clock-cells = <1>;
+		};
+
+		iic_wrap_en_clk: clock-controller at 11f32e00 {
+			compatible = "mediatek,mt8189-iic-wrap-en", "syscon";
+			reg = <0 0x11f32e00 0 0x10>;
+			#clock-cells = <1>;
+		};
+
+		iic_wrap_s_clk: clock-controller at 11d74e00 {
+			compatible = "mediatek,mt8189-iic-wrap-s", "syscon";
+			reg = <0 0x11d74e00 0 0x10>;
+			#clock-cells = <1>;
+		};
+
+		iic_wrap_ws_clk: clock-controller at 11b21e00 {
+			compatible = "mediatek,mt8189-iic-wrap-ws", "syscon";
+			reg = <0 0x11b21e00 0 0x10>;
+			#clock-cells = <1>;
+		};
+
+		clock-controller at 15020000 {
+			compatible = "mediatek,mt8189-imgsys1", "syscon";
+			reg = <0 0x15020000 0 0x1000>;
+			#clock-cells = <1>;
+		};
+
+		clock-controller at 15820000 {
+			compatible = "mediatek,mt8189-imgsys2", "syscon";
+			reg = <0 0x15820000 0 0x1000>;
+			#clock-cells = <1>;
+		};
+
+		clock-controller at 10001000 {
+			compatible = "mediatek,mt8189-infra-ao", "syscon";
+			reg = <0 0x10001000 0 0x1000>;
+			#clock-cells = <1>;
+		};
+
+		clock-controller at 1b000000 {
+			compatible = "mediatek,mt8189-ipesys", "syscon";
+			reg = <0 0x1b000000 0 0x1000>;
+			#clock-cells = <1>;
+		};
+
+		clock-controller at 1f000100 {
+			compatible = "mediatek,mt8189-mdpsys", "syscon";
+			reg = <0 0x1f000100 0 0x20>;
+			#clock-cells = <1>;
+		};
+
+		clock-controller at 13fbf000 {
+			compatible = "mediatek,mt8189-mfgcfg", "syscon";
+			reg = <0 0x13fbf000 0 0x1000>;
+			#clock-cells = <1>;
+		};
+
+		clock-controller at 1e800000 {
+			compatible = "mediatek,mt8189-mm-infra", "syscon";
+			reg = <0 0x1e800000 0 0x1000>;
+			#clock-cells = <1>;
+		};
+
+		pericfg_ao_clk: clock-controller at 11036000 {
+			compatible = "mediatek,mt8189-peri-ao", "syscon";
+			reg = <0 0x11036000 0 0x1000>;
+			#clock-cells = <1>;
+			#reset-cells = <1>;
+		};
+
+		topckgen_clk: clock-controller at 10000000 {
+			compatible = "mediatek,mt8189-topckgen", "syscon";
+			reg = <0 0x10000000 0 0x1000>;
+			#clock-cells = <1>;
+		};
+
+		clock-controller at 1c80ae10 {
+			compatible = "mediatek,mt8189-scp-i2c-clk", "syscon";
+			reg = <0 0x1c80ae10 0 0x10>;
+			#clock-cells = <1>;
+		};
+
+		clock-controller at 1cb21150 {
+			compatible = "mediatek,mt8189-scp-clk", "syscon";
+			reg = <0 0x1cb21150 0 0x10>;
+			#clock-cells = <1>;
+		};
+
+		clock-controller at 112b8000 {
+			compatible = "mediatek,mt8189-ufscfg-ao", "syscon";
+			reg = <0 0x112b8000 0 0x1000>;
+			#clock-cells = <1>;
+			#reset-cells = <1>;
+		};
+
+		clock-controller at 112bb000 {
+			compatible = "mediatek,mt8189-ufscfg-pdn", "syscon";
+			reg = <0 0x112bb000 0 0x1000>;
+			#clock-cells = <1>;
+			#reset-cells = <1>;
+		};
+
+		clock-controller at 1602f000 {
+			compatible = "mediatek,mt8189-vdec-core", "syscon";
+			reg = <0 0x1602f000 0 0x1000>;
+			#clock-cells = <1>;
+		};
+
+		clock-controller at 17000000 {
+			compatible = "mediatek,mt8189-venc", "syscon";
+			reg = <0 0x17000000 0 0x1000>;
+			#clock-cells = <1>;
+		};
+
+		clock-controller at 1c000800 {
+			compatible = "mediatek,mt8189-vlp-ao", "syscon";
+			reg = <0 0x1c000800 0 0x10>;
+			#clock-cells = <1>;
+		};
+
+		vlpcfg_ao_clk: clock-controller at 1c00c000 {
+			compatible = "mediatek,mt8189-vlpcfg-ao", "syscon";
+			reg = <0 0x1c00c000 0 0x1000>;
+			#clock-cells = <1>;
+		};
+
+		vlpckgen_clk: clock-controller at 1c012000 {
+			compatible = "mediatek,mt8189-vlpckgen", "syscon";
+			reg = <0 0x1c012000 0 0x1000>;
+			#clock-cells = <1>;
+		};
+
+		efuse at 11f10000 {
+			compatible = "mediatek,mt8189-efuse", "mediatek,mt8186-efuse";
+			reg = <0 0x11f10000 0 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			socinfo-data1 at 7a0 {
+				reg = <0x7a0 0x4>;
+			};
+
+			socinfo-data2 at 7e0 {
+				reg = <0x7e0 0x4>;
+			};
+		};
+
+		i2c0: i2c at 11c20000 {
+			compatible = "mediatek,mt8189-i2c", "mediatek,mt8188-i2c";
+			reg = <0 0x11c20000 0 0x1000>,
+			      <0 0x11300200 0 0x80>;
+			clock-div = <1>;
+			#address-cells = <1>;
+			clocks = <&iic_wrap_e_clk CLK_IMPE_I2C0>,
+				 <&pericfg_ao_clk CLK_PERAO_DMA_B>;
+			clock-names = "main", "dma";
+			interrupts = <GIC_SPI 274 IRQ_TYPE_LEVEL_HIGH 0>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c1: i2c at 11c21000 {
+			compatible = "mediatek,mt8189-i2c", "mediatek,mt8188-i2c";
+			reg = <0 0x11c21000 0 0x1000>,
+			      <0 0x11300300 0 0x80>;
+			#address-cells = <1>;
+			clock-div = <1>;
+			clocks = <&iic_wrap_e_clk CLK_IMPE_I2C1>,
+				 <&pericfg_ao_clk CLK_PERAO_DMA_B>;
+			clock-names = "main", "dma";
+			interrupts = <GIC_SPI 275 IRQ_TYPE_LEVEL_HIGH 0>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c2: i2c at 11b20000 {
+			compatible = "mediatek,mt8189-i2c", "mediatek,mt8188-i2c";
+			reg = <0 0x11b20000 0 0x1000>,
+			      <0 0x11300400 0 0x80>;
+			#address-cells = <1>;
+			clock-div = <1>;
+			clocks = <&iic_wrap_ws_clk CLK_IMPWS_I2C2>,
+				 <&pericfg_ao_clk CLK_PERAO_DMA_B>;
+			clock-names = "main", "dma";
+			interrupts = <GIC_SPI 276 IRQ_TYPE_LEVEL_HIGH 0>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c3: i2c at 11d70000 {
+			compatible = "mediatek,mt8189-i2c", "mediatek,mt8188-i2c";
+			reg = <0 0x11d70000 0 0x1000>,
+			      <0 0x11300500 0 0x80>;
+			#address-cells = <1>;
+			clock-div = <1>;
+			clocks = <&iic_wrap_s_clk CLK_IMPS_I2C3>,
+				 <&pericfg_ao_clk CLK_PERAO_DMA_B>;
+			clock-names = "main", "dma";
+			interrupts = <GIC_SPI 277 IRQ_TYPE_LEVEL_HIGH 0>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c4: i2c at 11d71000 {
+			compatible = "mediatek,mt8189-i2c", "mediatek,mt8188-i2c";
+			reg = <0 0x11d71000 0 0x1000>,
+			      <0 0x11300600 0 0x80>;
+			#address-cells = <1>;
+			clock-div = <1>;
+			clocks = <&iic_wrap_s_clk CLK_IMPS_I2C4>,
+				 <&pericfg_ao_clk CLK_PERAO_DMA_B>;
+			clock-names = "main", "dma";
+			interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH 0>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c5: i2c at 11d72000 {
+			compatible = "mediatek,mt8189-i2c", "mediatek,mt8188-i2c";
+			reg = <0 0x11d72000 0 0x1000>,
+			      <0 0x11300700 0 0x80>;
+			#address-cells = <1>;
+			clock-div = <1>;
+			clocks = <&iic_wrap_s_clk CLK_IMPS_I2C5>,
+				 <&pericfg_ao_clk CLK_PERAO_DMA_B>;
+			clock-names = "main", "dma";
+			interrupts = <GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH 0>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c6: i2c at 11d73000 {
+			compatible = "mediatek,mt8189-i2c", "mediatek,mt8188-i2c";
+			reg = <0 0x11d73000 0 0x1000>,
+			      <0 0x11300800 0 0x80>;
+			#address-cells = <1>;
+			clock-div = <1>;
+			clocks = <&iic_wrap_s_clk CLK_IMPS_I2C6>,
+				 <&pericfg_ao_clk CLK_PERAO_DMA_B>;
+			clock-names = "main", "dma";
+			interrupts = <GIC_SPI 210 IRQ_TYPE_LEVEL_HIGH 0>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c7: i2c at 11f30000 {
+			compatible = "mediatek,mt8189-i2c", "mediatek,mt8188-i2c";
+			reg = <0 0x11f30000 0 0x1000>,
+			      <0 0x11300900 0 0x80>;
+			#address-cells = <1>;
+			clock-div = <1>;
+			clocks = <&iic_wrap_en_clk CLK_IMPEN_I2C7>,
+				 <&pericfg_ao_clk CLK_PERAO_DMA_B>;
+			clock-names = "main", "dma";
+			interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH 0>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c8: i2c at 11f31000 {
+			compatible = "mediatek,mt8189-i2c", "mediatek,mt8188-i2c";
+			reg = <0 0x11f31000 0 0x1000>,
+			      <0 0x11300a00 0 0x80>;
+			#address-cells = <1>;
+			clock-div = <1>;
+			clocks = <&iic_wrap_en_clk CLK_IMPEN_I2C8>,
+				 <&pericfg_ao_clk CLK_PERAO_DMA_B>;
+			clock-names = "main", "dma";
+			interrupts = <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH 0>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		mmc0: mmc at 11230000 {
+			compatible = "mediatek,mt8189-mmc";
+			reg = <0 0x11230000 0 0x10000>,
+			      <0 0x11e70000 0 0x1000>;
+			clocks = <&topckgen_clk CLK_TOP_MSDC50_0_SEL>,
+				 <&pericfg_ao_clk CLK_PERAO_MSDC0_H>,
+				 <&pericfg_ao_clk CLK_PERAO_MSDC0>;
+			clock-names = "source", "hclk", "source_cg";
+			interrupts = <GIC_SPI 387 IRQ_TYPE_LEVEL_HIGH 0>;
+			status = "disabled";
+		};
+
+		mmc1: mmc at 11240000 {
+			compatible = "mediatek,mt8189-mmc";
+			reg = <0 0x11240000 0 0x1000>,
+			      <0 0x11d80000 0 0x1000>;
+			clocks = <&topckgen_clk CLK_TOP_MSDC30_1_SEL>,
+				 <&pericfg_ao_clk CLK_PERAO_MSDC1_H>,
+				 <&pericfg_ao_clk CLK_PERAO_MSDC1>;
+			clock-names = "source", "hclk", "source_cg";
+			interrupts = <GIC_SPI 388 IRQ_TYPE_LEVEL_HIGH 0>;
+			status = "disabled";
+		};
+
+		pio: pinctrl at 10005000 {
+			compatible = "mediatek,mt8189-pinctrl";
+			reg = <0 0x10005000 0 0x1000>,
+			      <0 0x11b50000 0 0x1000>,
+			      <0 0x11c50000 0 0x1000>,
+			      <0 0x11c60000 0 0x1000>,
+			      <0 0x11d20000 0 0x1000>,
+			      <0 0x11d30000 0 0x1000>,
+			      <0 0x11d40000 0 0x1000>,
+			      <0 0x11e20000 0 0x1000>,
+			      <0 0x11e30000 0 0x1000>,
+			      <0 0x11f20000 0 0x1000>,
+			      <0 0x11ce0000 0 0x1000>,
+			      <0 0x11de0000 0 0x1000>,
+			      <0 0x11e60000 0 0x1000>,
+			      <0 0x1c01e000 0 0x1000>,
+			      <0 0x11f00000 0 0x1000>;
+			reg-names = "base", "lm", "rb0", "rb1", "bm0", "bm1",
+				    "bm2", "lt0", "lt1", "rt", "eint0", "eint1",
+				    "eint2", "eint3", "eint4";
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&pio 0 0 182>;
+			interrupt-controller;
+			interrupts = <GIC_SPI 239 IRQ_TYPE_LEVEL_HIGH 0>;
+			#interrupt-cells = <2>;
+		};
+
+		pwrap: pwrap at 1cc04000 {
+			compatible = "mediatek,mt8189-pwrap", "mediatek,mt8195-pwrap", "syscon";
+			reg = <0 0x1cc04000 0 0x1000>;
+			reg-names = "pwrap";
+			assigned-clocks = <&vlpckgen_clk CLK_VLP_CK_PWRAP_ULPOSC_SEL>;
+			assigned-clock-parents = <&topckgen_clk CLK_TOP_OSC_D10>;
+			clocks =  <&vlpcfg_ao_clk CLK_VLPCFG_REG_PMIF_SPMI_M_SYS>,
+				  <&vlpcfg_ao_clk CLK_VLPCFG_REG_PMIF_SPMI_M_TMR>;
+			clock-names = "spi", "wrap";
+			interrupts = <GIC_SPI 496 IRQ_TYPE_LEVEL_HIGH 0>;
+		};
+
+		spmi: spmi at 1cc06000 {
+			compatible = "mediatek,mt8189-spmi", "mediatek,mt8195-spmi";
+			reg = <0 0x1cc06000 0 0x0008ff>,
+			      <0 0x1cc00000 0 0x000100>;
+			reg-names = "pmif", "spmimst";
+			clocks = <&vlpcfg_ao_clk CLK_VLPCFG_REG_PMIF_SPMI_P_SYS>,
+				 <&vlpcfg_ao_clk CLK_VLPCFG_REG_PMIF_SPMI_P_TMR>,
+				 <&vlpckgen_clk CLK_VLP_CK_SPMI_P_MST_SEL>;
+			clock-names = "pmif_sys_ck", "pmif_tmr_ck", "spmimst_clk_mux";
+			#address-cells = <2>;
+			#size-cells = <0>;
+		};
+
+		timer at 1cc10000 {
+			compatible = "mediatek,mt8189-timer", "mediatek,mt6765-timer";
+			reg = <0 0x1cc10000 0 0x1000>;
+			clocks = <&clk13m>;
+			interrupts = <GIC_SPI 249 IRQ_TYPE_LEVEL_HIGH 0>;
+		};
+
+		uart0: serial at 11001000 {
+			compatible = "mediatek,mt8189-uart", "mediatek,mt6577-uart";
+			reg = <0 0x11001000 0 0x1000>;
+			interrupts = <GIC_SPI 397 IRQ_TYPE_LEVEL_HIGH 0>;
+			clocks = <&clk26m>, <&pericfg_ao_clk CLK_PERAO_UART0>;
+			clock-names = "baud", "bus";
+			status = "disabled";
+		};
+
+		uart1: serial at 11002000 {
+			compatible = "mediatek,mt8189-uart", "mediatek,mt6577-uart";
+			reg = <0 0x11002000 0 0x1000>;
+			interrupts = <GIC_SPI 398 IRQ_TYPE_LEVEL_HIGH 0>;
+			clocks = <&clk26m>, <&pericfg_ao_clk CLK_PERAO_UART1>;
+			clock-names = "baud", "bus";
+			status = "disabled";
+		};
+
+		uart2: serial at 11003000 {
+			compatible = "mediatek,mt8189-uart", "mediatek,mt6577-uart";
+			reg = <0 0x11003000 0 0x1000>;
+			interrupts = <GIC_SPI 399 IRQ_TYPE_LEVEL_HIGH 0>;
+			clocks = <&clk26m>, <&pericfg_ao_clk CLK_PERAO_UART2>;
+			clock-names = "baud", "bus";
+			status = "disabled";
+		};
+
+		uart3: serial at 11004000 {
+			compatible = "mediatek,mt8189-uart", "mediatek,mt6577-uart";
+			reg = <0 0x11004000 0 0x1000>;
+			interrupts = <GIC_SPI 457 IRQ_TYPE_LEVEL_HIGH 0>;
+			clocks = <&clk26m>, <&pericfg_ao_clk CLK_PERAO_UART3>;
+			clock-names = "baud", "bus";
+			status = "disabled";
+		};
+
+		watchdog at 1c00a000 {
+			compatible = "mediatek,mt8189-wdt", "mediatek,mt6589-wdt";
+			reg = <0 0x1c00a000 0 0x100>;
+			#reset-cells = <1>;
+		};
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH 0>,
+			     <GIC_PPI 14 IRQ_TYPE_LEVEL_HIGH 0>,
+			     <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH 0>,
+			     <GIC_PPI 10 IRQ_TYPE_LEVEL_HIGH 0>;
+	};
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8391-genio-720-evk.dts b/arch/arm64/boot/dts/mediatek/mt8391-genio-720-evk.dts
new file mode 100644
index 0000000000000000000000000000000000000000..ddb6cdb95b04b2b732b24588b3ea2ee023ddf884
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8391-genio-720-evk.dts
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (c) 2025 Collabora Ltd.
+ * Author: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
+ */
+/dts-v1/;
+
+#include "mt8189.dtsi"
+#include "mt8391-genio-common.dtsi"
+
+/ {
+	model = "MediaTek Genio 720 EVK";
+	compatible = "mediatek,mt8391-evk", "mediatek,mt8391",
+		     "mediatek,mt8189";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8391-genio-common.dtsi b/arch/arm64/boot/dts/mediatek/mt8391-genio-common.dtsi
new file mode 100644
index 0000000000000000000000000000000000000000..744641916952111a4b389cf6adbd27c429b6eff2
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8391-genio-common.dtsi
@@ -0,0 +1,555 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (c) 2025 Collabora Ltd.
+ * Author: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
+ */
+
+#include "mt6359.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/spmi/spmi.h>
+#include "mt8189-pinfunc.h"
+
+/ {
+	aliases {
+		mmc0 = &mmc0;
+		serial0 = &uart0;
+	};
+
+	chosen: chosen {
+		stdout-path = "serial0:921600n8";
+	};
+
+	reserved_memory: reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		/* 2 MiB reserved for ARM Trusted Firmware (BL31) */
+		bl31_secmon_reserved: memory at 54600000 {
+			reg = <0 0x54600000 0x0 0x200000>;
+			no-map;
+		};
+	};
+};
+
+&auxadc {
+	status = "okay";
+};
+
+&cpu0 {
+	cpu-supply = <&mt6359_vmodem_buck_reg>;
+};
+
+&cpu1 {
+	cpu-supply = <&mt6359_vmodem_buck_reg>;
+};
+
+&cpu2 {
+	cpu-supply = <&mt6359_vmodem_buck_reg>;
+};
+
+&cpu3 {
+	cpu-supply = <&mt6359_vmodem_buck_reg>;
+};
+
+&cpu4 {
+	cpu-supply = <&mt6359_vmodem_buck_reg>;
+};
+
+&cpu5 {
+	cpu-supply = <&mt6359_vmodem_buck_reg>;
+};
+
+&cpu6 {
+	cpu-supply = <&mt6319_vbuck1>;
+};
+
+&cpu7 {
+	cpu-supply = <&mt6319_vbuck1>;
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c0_pins>;
+	status = "okay";
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	status = "okay";
+};
+
+&i2c2 {
+	clock-frequency = <1000000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_pins>;
+	status = "okay";
+};
+
+&i2c3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c3_pins>;
+	status = "disabled";
+};
+
+&i2c4 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c4_pins>;
+	status = "okay";
+};
+
+&i2c5 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c5_pins>;
+	status = "okay";
+};
+
+&i2c6 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c6_pins>;
+	status = "okay";
+};
+
+&i2c7 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c7_pins>;
+	status = "okay";
+};
+
+&i2c8 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c8_pins>;
+	status = "okay";
+};
+
+&mmc0 {
+	bus-width = <8>;
+	cap-mmc-highspeed;
+	cap-mmc-hw-reset;
+	hs400-ds-delay = <0x1481b>;
+	max-frequency = <200000000>;
+	mmc-hs200-1_8v;
+	mmc-hs400-1_8v;
+	mmc-hs400-enhanced-strobe;
+	no-sdio;
+	no-sd;
+	non-removable;
+	supports-cqe;
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc0_default_pins>;
+	pinctrl-1 = <&mmc0_uhs_pins>;
+	vmmc-supply = <&mt6359_vemc_1_ldo_reg>;
+	vqmmc-supply = <&mt6359_vufs_ldo_reg>;
+	status = "okay";
+};
+
+&mmc1 {
+	bus-width = <4>;
+	cap-sd-highspeed;
+	cd-gpios = <&pio 2 GPIO_ACTIVE_HIGH>;
+	max-frequency = <200000000>;
+	no-mmc;
+	no-sdio;
+	sd-uhs-sdr50;
+	sd-uhs-sdr104;
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc1_default_pins>;
+	pinctrl-1 = <&mmc1_uhs_pins>;
+	vmmc-supply = <&mt6359_vpa_buck_reg>;
+	vqmmc-supply = <&mt6359_vsim1_ldo_reg>;
+	status = "okay";
+};
+
+&mt6359_va09_ldo_reg{
+	regulator-name = "dvdd_sram_vadsp";
+	regulator-always-on;
+};
+
+&mt6359_vaux18_ldo_reg {
+	regulator-always-on;
+};
+
+&mt6359_vbbck_ldo_reg {
+	regulator-always-on;
+};
+
+&mt6359_vcore_buck_reg {
+	regulator-name = "dvdd_apu";
+	regulator-always-on;
+};
+
+&mt6359_vgpu11_buck_reg {
+	regulator-name = "dvdd_sram_core";
+	regulator-always-on;
+};
+
+&mt6359_vmodem_buck_reg {
+	regulator-name = "dvdd_proc_l";
+	regulator-always-on;
+};
+
+&mt6359_vproc1_buck_reg {
+	regulator-name = "vgpu";
+};
+
+&mt6359_vproc2_buck_reg {
+	regulator-name = "dvdd_core";
+	regulator-always-on;
+};
+
+&mt6359_vpu_buck_reg {
+	regulator-name = "avdd075_emi";
+	regulator-always-on;
+};
+
+&mt6359_vrf12_ldo_reg {
+	regulator-name = "va12_abb2";
+	regulator-always-on;
+};
+
+&mt6359_vrfck_ldo_reg {
+	regulator-always-on;
+};
+
+&mt6359_vsram_md_ldo_reg {
+	regulator-name = "dvdd_sram_proc_l";
+	regulator-always-on;
+};
+
+&mt6359_vsram_proc1_ldo_reg {
+	/delete-property/ regulator-always-on;
+
+	regulator-name = "vsram_gpu";
+};
+
+&mt6359_vsram_proc2_ldo_reg {
+	regulator-name = "dvdd_sram_proc_b";
+	regulator-always-on;
+};
+
+&mt6359_vsram_others_ldo_reg {
+	regulator-name = "dvdd_sram_apu";
+	regulator-always-on;
+};
+
+&mt6359_vufs_ldo_reg {
+	regulator-always-on;
+};
+
+&pio {
+	i2c0_pins: i2c0-pins {
+		pins {
+			pinmux = <PINMUX_GPIO52__FUNC_SDA0>,
+				 <PINMUX_GPIO51__FUNC_SCL0>;
+			bias-pull-up;
+		};
+	};
+
+	i2c1_pins: i2c1-pins {
+		pins {
+			pinmux = <PINMUX_GPIO54__FUNC_SDA1>,
+				 <PINMUX_GPIO53__FUNC_SCL1>;
+			bias-pull-up;
+		};
+	};
+
+	i2c2_pins: i2c2-pins {
+		pins {
+			pinmux = <PINMUX_GPIO56__FUNC_SDA2>,
+				 <PINMUX_GPIO55__FUNC_SCL2>;
+			bias-pull-up;
+		};
+	};
+
+	i2c3_pins: i2c3-pins {
+		pins {
+			pinmux = <PINMUX_GPIO58__FUNC_SDA3>,
+				 <PINMUX_GPIO57__FUNC_SCL3>;
+			bias-pull-up;
+		};
+	};
+
+	i2c4_pins: i2c4-pins {
+		pins {
+			pinmux = <PINMUX_GPIO60__FUNC_SDA4>,
+				 <PINMUX_GPIO59__FUNC_SCL4>;
+			bias-pull-up;
+		};
+	};
+	i2c5_pins: i2c5-pins {
+		pins {
+			pinmux = <PINMUX_GPIO62__FUNC_SDA5>,
+				 <PINMUX_GPIO61__FUNC_SCL5>;
+			bias-pull-up;
+		};
+	};
+
+	i2c6_pins: i2c6-pins {
+		pins {
+			pinmux = <PINMUX_GPIO64__FUNC_SDA6>,
+				 <PINMUX_GPIO63__FUNC_SCL6>;
+			bias-pull-up;
+		};
+	};
+
+	i2c7_pins: i2c7-pins {
+		pins {
+			pinmux = <PINMUX_GPIO66__FUNC_SDA7>,
+				 <PINMUX_GPIO65__FUNC_SCL7>;
+			bias-pull-up;
+		};
+	};
+
+	i2c8_pins: i2c8-pins {
+		pins {
+			pinmux = <PINMUX_GPIO68__FUNC_SDA8>,
+				 <PINMUX_GPIO67__FUNC_SCL8>;
+			bias-pull-up;
+		};
+	};
+
+	mmc0_default_pins: mmc0-default-pins {
+		pins-clk {
+			pinmux = <PINMUX_GPIO162__FUNC_MSDC0_CLK>;
+			drive-strength = <6>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO166__FUNC_MSDC0_DAT0>,
+				 <PINMUX_GPIO165__FUNC_MSDC0_DAT1>,
+				 <PINMUX_GPIO164__FUNC_MSDC0_DAT2>,
+				 <PINMUX_GPIO163__FUNC_MSDC0_DAT3>,
+				 <PINMUX_GPIO159__FUNC_MSDC0_DAT4>,
+				 <PINMUX_GPIO158__FUNC_MSDC0_DAT5>,
+				 <PINMUX_GPIO157__FUNC_MSDC0_DAT6>,
+				 <PINMUX_GPIO156__FUNC_MSDC0_DAT7>,
+				 <PINMUX_GPIO161__FUNC_MSDC0_CMD>;
+			input-enable;
+			drive-strength = <6>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins-rst {
+			pinmux = <PINMUX_GPIO160__FUNC_MSDC0_RSTB>;
+			drive-strength = <6>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_00>;
+		};
+	};
+
+	mmc0_uhs_pins: mmc0-uhs-pins {
+		pins-clk {
+			pinmux = <PINMUX_GPIO162__FUNC_MSDC0_CLK>;
+			drive-strength = <8>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO166__FUNC_MSDC0_DAT0>,
+				 <PINMUX_GPIO165__FUNC_MSDC0_DAT1>,
+				 <PINMUX_GPIO164__FUNC_MSDC0_DAT2>,
+				 <PINMUX_GPIO163__FUNC_MSDC0_DAT3>,
+				 <PINMUX_GPIO159__FUNC_MSDC0_DAT4>,
+				 <PINMUX_GPIO158__FUNC_MSDC0_DAT5>,
+				 <PINMUX_GPIO157__FUNC_MSDC0_DAT6>,
+				 <PINMUX_GPIO156__FUNC_MSDC0_DAT7>,
+				 <PINMUX_GPIO161__FUNC_MSDC0_CMD>;
+			input-enable;
+			drive-strength = <8>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins-ds {
+			pinmux = <PINMUX_GPIO167__FUNC_MSDC0_DSL>;
+			drive-strength = <8>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-rst {
+			pinmux = <PINMUX_GPIO160__FUNC_MSDC0_RSTB>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_00>;
+		};
+	};
+
+	mmc1_default_pins: mmc1-default-pins {
+		pins-clk {
+			pinmux = <PINMUX_GPIO169__FUNC_MSDC1_CLK>;
+			drive-strength = <6>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO170__FUNC_MSDC1_DAT0>,
+				 <PINMUX_GPIO171__FUNC_MSDC1_DAT1>,
+				 <PINMUX_GPIO172__FUNC_MSDC1_DAT2>,
+				 <PINMUX_GPIO173__FUNC_MSDC1_DAT3>,
+				 <PINMUX_GPIO168__FUNC_MSDC1_CMD>;
+			input-enable;
+			drive-strength = <6>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins-insert {
+			pinmux = <PINMUX_GPIO2__FUNC_GPIO2>;
+			bias-pull-up;
+		};
+	};
+
+	mmc1_uhs_pins: mmc1-uhs-pins {
+		pins-clk {
+			pinmux = <PINMUX_GPIO169__FUNC_MSDC1_CLK>;
+			drive-strength = <8>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO170__FUNC_MSDC1_DAT0>,
+				 <PINMUX_GPIO171__FUNC_MSDC1_DAT1>,
+				 <PINMUX_GPIO172__FUNC_MSDC1_DAT2>,
+				 <PINMUX_GPIO173__FUNC_MSDC1_DAT3>,
+				 <PINMUX_GPIO168__FUNC_MSDC1_CMD>;
+			input-enable;
+			drive-strength = <8>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+
+	uart0_pins: uart0-pins {
+		pins {
+			pinmux = <PINMUX_GPIO31__FUNC_UTXD0>,
+				 <PINMUX_GPIO32__FUNC_URXD0>;
+			bias-pull-up;
+		};
+	};
+
+	uart1_pins: uart1-pins {
+		pins {
+			pinmux = <PINMUX_GPIO33__FUNC_UTXD1>,
+				 <PINMUX_GPIO34__FUNC_URXD1>;
+			bias-pull-up;
+		};
+	};
+
+	uart2_pins: uart2-pins {
+		pins {
+			pinmux = <PINMUX_GPIO35__FUNC_UTXD2>,
+				 <PINMUX_GPIO36__FUNC_URXD2>;
+			bias-pull-up;
+		};
+
+		pins-rtscts {
+			pinmux = <PINMUX_GPIO16__FUNC_UCTS2>,
+				 <PINMUX_GPIO17__FUNC_URTS2>;
+		};
+	};
+
+	uart3_pins: uart3-pins {
+		pins {
+			pinmux = <PINMUX_GPIO37__FUNC_UTXD3>,
+				 <PINMUX_GPIO38__FUNC_URXD3>;
+			bias-pull-up;
+		};
+
+		pins-rtscts {
+			pinmux = <PINMUX_GPIO14__FUNC_UCTS3>,
+				 <PINMUX_GPIO15__FUNC_URTS3>;
+		};
+	};
+};
+
+&pmic {
+	interrupts-extended = <&pio 194 IRQ_TYPE_LEVEL_HIGH>;
+
+	keys {
+		compatible = "mediatek,mt6359-keys";
+		mediatek,long-press-mode = <1>;
+		power-off-time-sec = <0>;
+
+		power-key {
+			linux,keycodes = <KEY_POWER>;
+			wakeup-source;
+		};
+
+		home {
+			linux,keycodes = <KEY_HOME>;
+		};
+	};
+};
+
+&spmi {
+	pmic at 7 {
+		compatible = "mediatek,mt6319-regulator", "mediatek,mt6315-regulator";
+		reg = <0x7 SPMI_USID>;
+
+		regulators {
+			mt6319_vbuck1: vbuck1 {
+				regulator-name = "dvdd_proc_b";
+				regulator-min-microvolt = <300000>;
+				regulator-max-microvolt = <1193750>;
+				regulator-enable-ramp-delay = <256>;
+				regulator-allowed-modes = <0 1 2>;
+				regulator-always-on;
+			};
+
+			vbuck2 {
+				regulator-name = "vbuck2";
+				regulator-min-microvolt = <300000>;
+				regulator-max-microvolt = <1193750>;
+				regulator-enable-ramp-delay = <256>;
+				regulator-allowed-modes = <0 1 2>;
+				regulator-always-on;
+			};
+
+			vbuck3 {
+				regulator-name = "vdd2h_emi";
+				regulator-min-microvolt = <300000>;
+				regulator-max-microvolt = <1193750>;
+				regulator-enable-ramp-delay = <256>;
+				regulator-allowed-modes = <0 1 2>;
+				regulator-always-on;
+			};
+
+			vbuck4 {
+				regulator-name = "avddq_emi";
+				regulator-min-microvolt = <300000>;
+				regulator-max-microvolt = <1193750>;
+				regulator-enable-ramp-delay = <256>;
+				regulator-allowed-modes = <0 1 2>;
+				regulator-always-on;
+			};
+		};
+	};
+};
+
+&uart0 {
+	pinctrl-0 = <&uart0_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-0 = <&uart1_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-0 = <&uart2_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&uart3 {
+	pinctrl-0 = <&uart3_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Wed Dec  3 05:59:29 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Wed, 03 Dec 2025 14:59:29 +0100
Subject: [PATCH 4/4] arm64: dts: mediatek: add device-tree for Genio
 520-EVK board
In-Reply-To: <20251203-add-mediatek-genio-520-720-evk-v1-0-df794b2a30ae@collabora.com>
References: <20251203-add-mediatek-genio-520-720-evk-v1-0-df794b2a30ae@collabora.com>
Message-ID: <20251203-add-mediatek-genio-520-720-evk-v1-4-df794b2a30ae@collabora.com>

Add device-tree for the basic hardware enablement of the Genio 520-EVK
board, based on MT8371 SoC.

MT8371 SoC is a variant of MT8189 SoC with the following differences:
  - Arm Cortex-A78 CPU core maximum frequency (2.2 Ghz for MT8371, 3 Ghz
  for MT8189).
  - Arm Mali G57 MC2 GPU core maximum frequency (880 Mhz for MT8371, 1.1
  Ghz for MT8189)
  - one ISP engine instead of two
MT8371 hardware register maps are identical to MT8189.

The Genio 520-EVK has following features:
  - MT8371 SoC
  - MT6365 PMIC
  - MT6319 Buck IC
  - MT6375 Charger IC
  - 8GB LPDDR5 RAM
  - 64GB eMMC 5.1
  - 128GB UFS
  - 20V DC Jack
  - USB Type-C Power Adapter
  - Micro SD card slot
  - Push Button x 4 (Power, Reset, Download and Home Key)
  - LED x 3 (System Power, Reset, DC-IN Power)
  - USB Type-C Connector (USB 3.2) x 2
  - USB Type-C Connector (USB 2.0) x 1
  - 3.5mm Earphone Jack x 1 (with Microphone Input)
  - 3.5mm Line Out Audio Jack x 1
  - Analog Microphone x 1
  - Digital Microphone x 2
  - Gigabit Ethernet with RJ45 connector
  - DP x 1 (Mode over USB Type-C)
  - LVDS port x 1
  - eDP port x 1
  - UART x2 with serial-to-usb converters and USB Type-C connectors
  - UART Port x 2 on Pin Header
  - M.2 Slot x 2
  - I2C Capacitive Touch Pad
  - 4-Lane DSI x 1
  - 4-Data Lane CSI x 2
  - I2S Pin header
  - 40-Pin 2.54mm Pin Header x 1
  - CAN Bus x 1 (RS232 Connector)

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 arch/arm64/boot/dts/mediatek/Makefile                 |  1 +
 arch/arm64/boot/dts/mediatek/mt8371-genio-520-evk.dts | 19 +++++++++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile
index e3b63085c0608b86dc8638c9d5e0b73441e9ed7b..e6356733a1c0ad5f3ccf9517f3e393ba5f114da8 100644
--- a/arch/arm64/boot/dts/mediatek/Makefile
+++ b/arch/arm64/boot/dts/mediatek/Makefile
@@ -106,6 +106,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8195-evb.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8365-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-genio-510-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-grinn-genio-510-sbc.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8371-genio-520-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-genio-1200-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-genio-1200-evk-ufs.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-genio-700-evk.dtb
diff --git a/arch/arm64/boot/dts/mediatek/mt8371-genio-520-evk.dts b/arch/arm64/boot/dts/mediatek/mt8371-genio-520-evk.dts
new file mode 100644
index 0000000000000000000000000000000000000000..b259fc6c01a13bb84c1ed8b4433a799241a28a6b
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8371-genio-520-evk.dts
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (c) 2025 Collabora Ltd.
+ * Author: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
+ */
+/dts-v1/;
+#include "mt8189.dtsi"
+#include "mt8391-genio-common.dtsi"
+
+/*
+ * MT8371 SoC is a variant of the MT8189 with only one ISP engine
+ * and lower maximum frequency on the big cores and on the Mali GPU.
+ */
+
+/ {
+	model = "MediaTek Genio 520 EVK";
+	compatible = "mediatek,mt8371-evk", "mediatek,mt8371",
+		     "mediatek,mt8189";
+};

-- 
2.52.0



From alexandru.elisei at arm.com  Wed Dec  3 06:03:51 2025
From: alexandru.elisei at arm.com (Alexandru Elisei)
Date: Wed, 3 Dec 2025 14:03:51 +0000
Subject: [PATCH 4/4] KVM: arm64: Convert VTCR_EL2 to config-driven
 sanitisation
In-Reply-To: <86ikenpvna.wl-maz@kernel.org>
References: <20251129144525.2609207-1-maz@kernel.org>
 <20251129144525.2609207-5-maz@kernel.org>
 <aTAijieCI8055FL0@raptor>
 <86ikenpvna.wl-maz@kernel.org>
Message-ID: <aTBDRx1oeGDs2SFl@raptor>

Hi Marc,

On Wed, Dec 03, 2025 at 01:00:57PM +0000, Marc Zyngier wrote:
> On Wed, 03 Dec 2025 11:44:14 +0000,
> Alexandru Elisei <alexandru.elisei at arm.com> wrote:
> > 
> > Hi Marc,
> > 
> > On Sat, Nov 29, 2025 at 02:45:25PM +0000, Marc Zyngier wrote:
> > > Describe all the VTCR_EL2 fields and their respective configurations,
> > > making sure that we correctly ignore the bits that are not defined
> > > for a given guest configuration.
> > > 
> > > Signed-off-by: Marc Zyngier <maz at kernel.org>
> > > ---
> > >  arch/arm64/kvm/config.c | 69 +++++++++++++++++++++++++++++++++++++++++
> > >  arch/arm64/kvm/nested.c |  3 +-
> > >  2 files changed, 70 insertions(+), 2 deletions(-)
> > > 
> > > diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
> > > index a02c28d6a61c9..c36e133c51912 100644
> > > --- a/arch/arm64/kvm/config.c
> > > +++ b/arch/arm64/kvm/config.c
> > > @@ -141,6 +141,7 @@ struct reg_feat_map_desc {
> > >  #define FEAT_AA64EL1		ID_AA64PFR0_EL1, EL1, IMP
> > >  #define FEAT_AA64EL2		ID_AA64PFR0_EL1, EL2, IMP
> > >  #define FEAT_AA64EL3		ID_AA64PFR0_EL1, EL3, IMP
> > > +#define FEAT_SEL2		ID_AA64PFR0_EL1, SEL2, IMP
> > >  #define FEAT_AIE		ID_AA64MMFR3_EL1, AIE, IMP
> > >  #define FEAT_S2POE		ID_AA64MMFR3_EL1, S2POE, IMP
> > >  #define FEAT_S1POE		ID_AA64MMFR3_EL1, S1POE, IMP
> > > @@ -202,6 +203,8 @@ struct reg_feat_map_desc {
> > >  #define FEAT_ASID2		ID_AA64MMFR4_EL1, ASID2, IMP
> > >  #define FEAT_MEC		ID_AA64MMFR3_EL1, MEC, IMP
> > >  #define FEAT_HAFT		ID_AA64MMFR1_EL1, HAFDBS, HAFT
> > > +#define FEAT_HDBSS		ID_AA64MMFR1_EL1, HAFDBS, HDBSS
> > > +#define FEAT_HPDS2		ID_AA64MMFR1_EL1, HPDS, HPDS2
> > >  #define FEAT_BTI		ID_AA64PFR1_EL1, BT, IMP
> > >  #define FEAT_ExS		ID_AA64MMFR0_EL1, EXS, IMP
> > >  #define FEAT_IESB		ID_AA64MMFR2_EL1, IESB, IMP
> > > @@ -219,6 +222,7 @@ struct reg_feat_map_desc {
> > >  #define FEAT_FGT2		ID_AA64MMFR0_EL1, FGT, FGT2
> > >  #define FEAT_MTPMU		ID_AA64DFR0_EL1, MTPMU, IMP
> > >  #define FEAT_HCX		ID_AA64MMFR1_EL1, HCX, IMP
> > > +#define FEAT_S2PIE		ID_AA64MMFR3_EL1, S2PIE, IMP
> > >  
> > >  static bool not_feat_aa64el3(struct kvm *kvm)
> > >  {
> > > @@ -362,6 +366,28 @@ static bool feat_pmuv3p9(struct kvm *kvm)
> > >  	return check_pmu_revision(kvm, V3P9);
> > >  }
> > >  
> > > +#define has_feat_s2tgran(k, s)						\
> > > +  ((kvm_has_feat_enum(kvm, ID_AA64MMFR0_EL1, TGRAN##s##_2, TGRAN##s) && \
> > > +    !kvm_has_feat_enum(kvm, ID_AA64MMFR0_EL1, TGRAN##s, NI))	     ||	\
> > 
> > Wouldn't that read better as kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN##s, IMP)?
> > I think that would also be correct.
> 
> Sure, I don't mind either way,
> 
> > 
> > > +   kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN##s##_2, IMP))
> > 
> > A bit unexpected to treat the same field first as an enum, then as an integer,
> > but it saves one line.
> 
> It potentially saves more if the encoding grows over time. I don't
> think it matters.

Doesn't, was just aestethics and saves someone having to check the values to
make sure it wasn't an error.

> 
> > 
> > > +
> > > +static bool feat_lpa2(struct kvm *kvm)
> > > +{
> > > +	return ((kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4, 52_BIT)    ||
> > > +		 !kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4, IMP))	&&
> > > +		(kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16, 52_BIT)   ||
> > > +		 !kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16, IMP))	&&
> > > +		(kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4_2, 52_BIT)  ||
> > > +		 !has_feat_s2tgran(kvm, 4))				&&
> > > +		(kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16_2, 52_BIT) ||
> > > +		 !has_feat_s2tgran(kvm, 16)));
> > > +}
> > 
> > That was a doozy, but looks correct to me if the intention was to have the check
> > as relaxed as possible - i.e, a VM can advertise 52 bit support for one granule,
> > but not the other (same for stage 1 and stage 2).
> 
> Not quite. The intent is that, for all the possible granules, at all
> the possible stages, either the granule size isn't implemented at all,
> or it supports 52 bits. I think this covers it, but as you said, this
> is a bit of a bran fsck.

Hm... this sounds like something that should be sanitised in
set_id_aa64mmfr0_el1(). Sorry, but I just can't tell if TGran{4,16,64} are
writable by userspace.

> 
> This is essentially a transliteration of the MRS:
> 
> (FEAT_LPA2 && FEAT_S2TGran4K) <=> (UInt(ID_AA64MMFR0_EL1.TGran4_2) >= 3))
> (FEAT_LPA2 && FEAT_S2TGran16K) <=> (UInt(ID_AA64MMFR0_EL1.TGran16_2) >= 3))
> (FEAT_LPA2 && FEAT_TGran4K) <=> (SInt(ID_AA64MMFR0_EL1.TGran4) >= 1))
> (FEAT_LPA2 && FEAT_TGran16K) <=> (UInt(ID_AA64MMFR0_EL1.TGran16) >= 2))
> FEAT_S2TGran4K <=> (((UInt(ID_AA64MMFR0_EL1.TGran4_2) == 0) && FEAT_TGran4K) || (UInt(ID_AA64MMFR0_EL1.TGran4_2) >= 2))
> FEAT_S2TGran16K <=> (((UInt(ID_AA64MMFR0_EL1.TGran16_2) == 0) && FEAT_TGran16K) || (UInt(ID_AA64MMFR0_EL1.TGran16_2) >= 2))
> FEAT_TGran4K <=> (SInt(ID_AA64MMFR0_EL1.TGran4) >= 0)
> FEAT_TGran16K <=> (UInt(ID_AA64MMFR0_EL1.TGran16) >= 1)

How about (untested):

static bool feat_lpas2(struct kvm *kvm)
{
	if (kvm_has_feat_exact(kvm, ID_AA64MMFR0_EL1, TGRAN4, IMP) ||
	    kvm_has_feat_exact(kvm, ID_AA64MMFR0_EL1, TGRAN16, IMP) ||
	    kvm_has_feat_exact(kvm, ID_AA64MMFR0_EL1, TGRAN4_2, IMP) ||
	    kvm_has_feat_exact(kvm, ID_AA64MMFR0_EL1, TGRAN16_2, IMP))
		return false;

	return true;
}

where, in case there's not something similar already and I just don't know about
it:

#define kvm_has_feat_exact(kvm, id, fld, val)			\
	kvm_cmp_feat(kvm, id, fld, =, val)

The idea being that if one of the granules does not support 52 bit, then it's
not supported by any of the other granules.

Thanks,
Alex


From vladimir.zapolskiy at linaro.org  Wed Dec  3 06:09:58 2025
From: vladimir.zapolskiy at linaro.org (Vladimir Zapolskiy)
Date: Wed, 3 Dec 2025 16:09:58 +0200
Subject: [PATCH 2/3] dt-bindings: clock: qcom: Add camera clock controller
 for SM8750 SoC
In-Reply-To: <20251202-sm8750_camcc-v1-2-b3f7ef6723f1@oss.qualcomm.com>
References: <20251202-sm8750_camcc-v1-0-b3f7ef6723f1@oss.qualcomm.com>
 <20251202-sm8750_camcc-v1-2-b3f7ef6723f1@oss.qualcomm.com>
Message-ID: <7e22e126-cb08-4bc2-bad6-a895a4e35a8d@linaro.org>

Hi Taniya.

On 12/2/25 12:26, Taniya Das wrote:
> Add device tree bindings for the camera clock controller on
> Qualcomm SM8750 platform. The camera clock controller is split between
> camcc and cambist. The cambist controls the mclks of the camera clock
> controller.
> 
> Signed-off-by: Taniya Das <taniya.das at oss.qualcomm.com>
> ---
>   .../bindings/clock/qcom,sm8450-camcc.yaml          |   5 +
>   .../dt-bindings/clock/qcom,sm8750-cambistmclkcc.h  |  30 ++++
>   include/dt-bindings/clock/qcom,sm8750-camcc.h      | 151 +++++++++++++++++++++
>   3 files changed, 186 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml
> index c1e06f39431e68a3cd2f6c2dba84be2a3c143bb1..8e3baba5270b384eb03a68b4e47785e6c91ec6f7 100644
> --- a/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml
> +++ b/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml
> @@ -9,6 +9,7 @@ title: Qualcomm Camera Clock & Reset Controller on SM8450
>   maintainers:
>     - Vladimir Zapolskiy <vladimir.zapolskiy at linaro.org>
>     - Jagadeesh Kona <quic_jkona at quicinc.com>
> +  - Taniya Das <taniya.das at oss.qualcomm.com>
>   
>   description: |
>     Qualcomm camera clock control module provides the clocks, resets and power
> @@ -18,6 +19,8 @@ description: |
>       include/dt-bindings/clock/qcom,sm8450-camcc.h
>       include/dt-bindings/clock/qcom,sm8550-camcc.h
>       include/dt-bindings/clock/qcom,sm8650-camcc.h
> +    include/dt-bindings/clock/qcom,sm8750-cambistmclkcc.h
> +    include/dt-bindings/clock/qcom,sm8750-camcc.h
>   
>   properties:
>     compatible:
> @@ -26,6 +29,8 @@ properties:
>         - qcom,sm8475-camcc
>         - qcom,sm8550-camcc
>         - qcom,sm8650-camcc
> +      - qcom,sm8750-cambistmclkcc

Due to the very distinct nature of this new clock controller, I suppose
it does not inherit most of the properties of other CAMCC clocks, and
therefore it should be described in a separate dt binding documentation file.

Looking at the list of macro definitions from a new header file, a noticeable
remark is that this new clock controller is neither a reset controller nor
a power domain controller.

> +      - qcom,sm8750-camcc
>   
>     clocks:
>       items:
> diff --git a/include/dt-bindings/clock/qcom,sm8750-cambistmclkcc.h b/include/dt-bindings/clock/qcom,sm8750-cambistmclkcc.h
> new file mode 100644
> index 0000000000000000000000000000000000000000..51615bee307fd9e7f81f7e5c1662535093dd8b55
> --- /dev/null
> +++ b/include/dt-bindings/clock/qcom,sm8750-cambistmclkcc.h
> @@ -0,0 +1,30 @@
> +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +
> +#ifndef _DT_BINDINGS_CLK_QCOM_CAM_BIST_MCLK_CC_SM8750_H
> +#define _DT_BINDINGS_CLK_QCOM_CAM_BIST_MCLK_CC_SM8750_H
> +
> +/* CAM_BIST_MCLK_CC clocks */
> +#define CAM_BIST_MCLK_CC_MCLK0_CLK				0
> +#define CAM_BIST_MCLK_CC_MCLK0_CLK_SRC				1
> +#define CAM_BIST_MCLK_CC_MCLK1_CLK				2
> +#define CAM_BIST_MCLK_CC_MCLK1_CLK_SRC				3
> +#define CAM_BIST_MCLK_CC_MCLK2_CLK				4
> +#define CAM_BIST_MCLK_CC_MCLK2_CLK_SRC				5
> +#define CAM_BIST_MCLK_CC_MCLK3_CLK				6
> +#define CAM_BIST_MCLK_CC_MCLK3_CLK_SRC				7
> +#define CAM_BIST_MCLK_CC_MCLK4_CLK				8
> +#define CAM_BIST_MCLK_CC_MCLK4_CLK_SRC				9
> +#define CAM_BIST_MCLK_CC_MCLK5_CLK				10
> +#define CAM_BIST_MCLK_CC_MCLK5_CLK_SRC				11
> +#define CAM_BIST_MCLK_CC_MCLK6_CLK				12
> +#define CAM_BIST_MCLK_CC_MCLK6_CLK_SRC				13
> +#define CAM_BIST_MCLK_CC_MCLK7_CLK				14
> +#define CAM_BIST_MCLK_CC_MCLK7_CLK_SRC				15
> +#define CAM_BIST_MCLK_CC_PLL0					16
> +#define CAM_BIST_MCLK_CC_SLEEP_CLK				17
> +#define CAM_BIST_MCLK_CC_SLEEP_CLK_SRC				18
> +
> +#endif
> diff --git a/include/dt-bindings/clock/qcom,sm8750-camcc.h b/include/dt-bindings/clock/qcom,sm8750-camcc.h
> new file mode 100644
> index 0000000000000000000000000000000000000000..dae788247afe896ef812bef716897c6cf80df2bb
> --- /dev/null
> +++ b/include/dt-bindings/clock/qcom,sm8750-camcc.h
> @@ -0,0 +1,151 @@
> +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +
> +#ifndef _DT_BINDINGS_CLK_QCOM_CAM_CC_SM8750_H
> +#define _DT_BINDINGS_CLK_QCOM_CAM_CC_SM8750_H
> +
> +/* CAM_CC clocks */
> +#define CAM_CC_CAM_TOP_AHB_CLK					0
> +#define CAM_CC_CAM_TOP_FAST_AHB_CLK				1
> +#define CAM_CC_CAMNOC_DCD_XO_CLK				2
> +#define CAM_CC_CAMNOC_NRT_AXI_CLK				3
> +#define CAM_CC_CAMNOC_NRT_CRE_CLK				4
> +#define CAM_CC_CAMNOC_NRT_IPE_NPS_CLK				5
> +#define CAM_CC_CAMNOC_NRT_OFE_ANCHOR_CLK			6
> +#define CAM_CC_CAMNOC_NRT_OFE_HDR_CLK				7
> +#define CAM_CC_CAMNOC_NRT_OFE_MAIN_CLK				8
> +#define CAM_CC_CAMNOC_RT_AXI_CLK				9
> +#define CAM_CC_CAMNOC_RT_AXI_CLK_SRC				10
> +#define CAM_CC_CAMNOC_RT_IFE_LITE_CLK				11
> +#define CAM_CC_CAMNOC_RT_TFE_0_BAYER_CLK			12
> +#define CAM_CC_CAMNOC_RT_TFE_0_MAIN_CLK				13
> +#define CAM_CC_CAMNOC_RT_TFE_1_BAYER_CLK			14
> +#define CAM_CC_CAMNOC_RT_TFE_1_MAIN_CLK				15
> +#define CAM_CC_CAMNOC_RT_TFE_2_BAYER_CLK			16
> +#define CAM_CC_CAMNOC_RT_TFE_2_MAIN_CLK				17
> +#define CAM_CC_CAMNOC_XO_CLK					18
> +#define CAM_CC_CCI_0_CLK					19
> +#define CAM_CC_CCI_0_CLK_SRC					20
> +#define CAM_CC_CCI_1_CLK					21
> +#define CAM_CC_CCI_1_CLK_SRC					22
> +#define CAM_CC_CCI_2_CLK					23
> +#define CAM_CC_CCI_2_CLK_SRC					24
> +#define CAM_CC_CORE_AHB_CLK					25
> +#define CAM_CC_CPHY_RX_CLK_SRC					26
> +#define CAM_CC_CRE_AHB_CLK					27
> +#define CAM_CC_CRE_CLK						28
> +#define CAM_CC_CRE_CLK_SRC					29
> +#define CAM_CC_CSI0PHYTIMER_CLK					30
> +#define CAM_CC_CSI0PHYTIMER_CLK_SRC				31
> +#define CAM_CC_CSI1PHYTIMER_CLK					32
> +#define CAM_CC_CSI1PHYTIMER_CLK_SRC				33
> +#define CAM_CC_CSI2PHYTIMER_CLK					34
> +#define CAM_CC_CSI2PHYTIMER_CLK_SRC				35
> +#define CAM_CC_CSI3PHYTIMER_CLK					36
> +#define CAM_CC_CSI3PHYTIMER_CLK_SRC				37
> +#define CAM_CC_CSI4PHYTIMER_CLK					38
> +#define CAM_CC_CSI4PHYTIMER_CLK_SRC				39
> +#define CAM_CC_CSI5PHYTIMER_CLK					40
> +#define CAM_CC_CSI5PHYTIMER_CLK_SRC				41
> +#define CAM_CC_CSID_CLK						42
> +#define CAM_CC_CSID_CLK_SRC					43
> +#define CAM_CC_CSID_CSIPHY_RX_CLK				44
> +#define CAM_CC_CSIPHY0_CLK					45
> +#define CAM_CC_CSIPHY1_CLK					46
> +#define CAM_CC_CSIPHY2_CLK					47
> +#define CAM_CC_CSIPHY3_CLK					48
> +#define CAM_CC_CSIPHY4_CLK					49
> +#define CAM_CC_CSIPHY5_CLK					50
> +#define CAM_CC_DRV_AHB_CLK					51
> +#define CAM_CC_DRV_XO_CLK					52
> +#define CAM_CC_FAST_AHB_CLK_SRC					53
> +#define CAM_CC_GDSC_CLK						54
> +#define CAM_CC_ICP_0_AHB_CLK					55
> +#define CAM_CC_ICP_0_CLK					56
> +#define CAM_CC_ICP_0_CLK_SRC					57
> +#define CAM_CC_ICP_1_AHB_CLK					58
> +#define CAM_CC_ICP_1_CLK					59
> +#define CAM_CC_ICP_1_CLK_SRC					60
> +#define CAM_CC_IFE_LITE_AHB_CLK					61
> +#define CAM_CC_IFE_LITE_CLK					62
> +#define CAM_CC_IFE_LITE_CLK_SRC					63
> +#define CAM_CC_IFE_LITE_CPHY_RX_CLK				64
> +#define CAM_CC_IFE_LITE_CSID_CLK				65
> +#define CAM_CC_IFE_LITE_CSID_CLK_SRC				66
> +#define CAM_CC_IPE_NPS_AHB_CLK					67
> +#define CAM_CC_IPE_NPS_CLK					68
> +#define CAM_CC_IPE_NPS_CLK_SRC					69
> +#define CAM_CC_IPE_NPS_FAST_AHB_CLK				70
> +#define CAM_CC_IPE_PPS_CLK					71
> +#define CAM_CC_IPE_PPS_FAST_AHB_CLK				72
> +#define CAM_CC_JPEG_0_CLK					73
> +#define CAM_CC_JPEG_1_CLK					74
> +#define CAM_CC_JPEG_CLK_SRC					75
> +#define CAM_CC_OFE_AHB_CLK					76
> +#define CAM_CC_OFE_ANCHOR_CLK					77
> +#define CAM_CC_OFE_ANCHOR_FAST_AHB_CLK				78
> +#define CAM_CC_OFE_CLK_SRC					79
> +#define CAM_CC_OFE_HDR_CLK					80
> +#define CAM_CC_OFE_HDR_FAST_AHB_CLK				81
> +#define CAM_CC_OFE_MAIN_CLK					82
> +#define CAM_CC_OFE_MAIN_FAST_AHB_CLK				83
> +#define CAM_CC_PLL0						84
> +#define CAM_CC_PLL0_OUT_EVEN					85
> +#define CAM_CC_PLL0_OUT_ODD					86
> +#define CAM_CC_PLL1						87
> +#define CAM_CC_PLL1_OUT_EVEN					88
> +#define CAM_CC_PLL2						89
> +#define CAM_CC_PLL2_OUT_EVEN					90
> +#define CAM_CC_PLL3						91
> +#define CAM_CC_PLL3_OUT_EVEN					92
> +#define CAM_CC_PLL4						93
> +#define CAM_CC_PLL4_OUT_EVEN					94
> +#define CAM_CC_PLL5						95
> +#define CAM_CC_PLL5_OUT_EVEN					96
> +#define CAM_CC_PLL6						97
> +#define CAM_CC_PLL6_OUT_EVEN					98
> +#define CAM_CC_PLL6_OUT_ODD					99
> +#define CAM_CC_QDSS_DEBUG_CLK					100
> +#define CAM_CC_QDSS_DEBUG_CLK_SRC				101
> +#define CAM_CC_QDSS_DEBUG_XO_CLK				102
> +#define CAM_CC_SLEEP_CLK					103
> +#define CAM_CC_SLEEP_CLK_SRC					104
> +#define CAM_CC_SLOW_AHB_CLK_SRC					105
> +#define CAM_CC_TFE_0_BAYER_CLK					106
> +#define CAM_CC_TFE_0_BAYER_FAST_AHB_CLK				107
> +#define CAM_CC_TFE_0_CLK_SRC					108
> +#define CAM_CC_TFE_0_MAIN_CLK					109
> +#define CAM_CC_TFE_0_MAIN_FAST_AHB_CLK				110
> +#define CAM_CC_TFE_1_BAYER_CLK					111
> +#define CAM_CC_TFE_1_BAYER_FAST_AHB_CLK				112
> +#define CAM_CC_TFE_1_CLK_SRC					113
> +#define CAM_CC_TFE_1_MAIN_CLK					114
> +#define CAM_CC_TFE_1_MAIN_FAST_AHB_CLK				115
> +#define CAM_CC_TFE_2_BAYER_CLK					116
> +#define CAM_CC_TFE_2_BAYER_FAST_AHB_CLK				117
> +#define CAM_CC_TFE_2_CLK_SRC					118
> +#define CAM_CC_TFE_2_MAIN_CLK					119
> +#define CAM_CC_TFE_2_MAIN_FAST_AHB_CLK				120
> +#define CAM_CC_XO_CLK_SRC					121
> +
> +/* CAM_CC power domains */
> +#define CAM_CC_TITAN_TOP_GDSC					0
> +#define CAM_CC_IPE_0_GDSC					1
> +#define CAM_CC_OFE_GDSC						2
> +#define CAM_CC_TFE_0_GDSC					3
> +#define CAM_CC_TFE_1_GDSC					4
> +#define CAM_CC_TFE_2_GDSC					5
> +
> +/* CAM_CC resets */
> +#define CAM_CC_DRV_BCR						0
> +#define CAM_CC_ICP_BCR						1
> +#define CAM_CC_IPE_0_BCR					2
> +#define CAM_CC_OFE_BCR						3
> +#define CAM_CC_QDSS_DEBUG_BCR					4
> +#define CAM_CC_TFE_0_BCR					5
> +#define CAM_CC_TFE_1_BCR					6
> +#define CAM_CC_TFE_2_BCR					7
> +
> +#endif
> 

-- 
Best wishes,
Vladimir


From thomas.richard at bootlin.com  Wed Dec  3 06:10:07 2025
From: thomas.richard at bootlin.com (Thomas Richard)
Date: Wed, 3 Dec 2025 15:10:07 +0100
Subject: [PATCH RFC v2 3/4] clk: keystone: sci-clk: add restore_context()
 operation
In-Reply-To: <1283df52-ee41-477f-8d91-5c4a02385cef@ti.com>
References: <20251127-ti-sci-jacinto-s2r-restore-irq-v2-0-a487fa3ff221@bootlin.com>
 <20251127-ti-sci-jacinto-s2r-restore-irq-v2-3-a487fa3ff221@bootlin.com>
 <1283df52-ee41-477f-8d91-5c4a02385cef@ti.com>
Message-ID: <07c7d2c0-f29b-4bf2-abf1-c640c39e6d7a@bootlin.com>

Hi Udit,

On 12/3/25 8:50 AM, Kumar, Udit wrote:
> 
> On 11/27/2025 2:08 PM, Thomas Richard (TI.com) wrote:
>> Implement the restore_context() operation to restore the clock parent
>> state. The parent index is saved in sci_clk struct during set_parent().
>> During clock registration, the core retrieves each clock?s parent using
>> get_parent() operation to ensure the internal clock tree reflects the
>> actual hardware state, including any configurations made by the
>> bootloader. So we also save the parent index in get_parent().
>>
>> Signed-off-by: Thomas Richard (TI.com) <thomas.richard at bootlin.com>
>> ---
>> ? drivers/clk/keystone/sci-clk.c | 25 ++++++++++++++++++++-----
>> ? 1 file changed, 20 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/clk/keystone/sci-clk.c b/drivers/clk/keystone/
>> sci-clk.c
>> index a4b42811de55d..1e5dd01484d1c 100644
>> --- a/drivers/clk/keystone/sci-clk.c
>> +++ b/drivers/clk/keystone/sci-clk.c
>> @@ -47,6 +47,7 @@ struct sci_clk_provider {
>> ?? * @node:???? Link for handling clocks probed via DT
>> ?? * @cached_req:???? Cached requested freq for determine rate calls
>> ?? * @cached_res:???? Cached result freq for determine rate calls
>> + * @parent_id:???? Parent index for this clock
>> ?? */
>> ? struct sci_clk {
>> ????? struct clk_hw hw;
>> @@ -58,6 +59,7 @@ struct sci_clk {
>> ????? struct list_head node;
>> ????? unsigned long cached_req;
>> ????? unsigned long cached_res;
>> +??? u8 parent_id;
> 
> you may need to restore rate as well

will do in v3.

> 
> 
>> ? };
>> ? ? #define to_sci_clk(_hw) container_of(_hw, struct sci_clk, hw)
>> @@ -237,9 +239,9 @@ static u8 sci_clk_get_parent(struct clk_hw *hw)
>> ????????? return 0;
>> ????? }
>> ? -??? parent_id = parent_id - clk->clk_id - 1;
>> +??? clk->parent_id = (u8)(parent_id - clk->clk_id - 1);
>> ? -??? return (u8)parent_id;
>> +??? return clk->parent_id;
>> ? }
>> ? ? /**
>> @@ -252,12 +254,24 @@ static u8 sci_clk_get_parent(struct clk_hw *hw)
>> ? static int sci_clk_set_parent(struct clk_hw *hw, u8 index)
>> ? {
>> ????? struct sci_clk *clk = to_sci_clk(hw);
>> +??? int ret;
>> ? ????? clk->cached_req = 0;
>> ? -??? return clk->provider->ops->set_parent(clk->provider->sci, clk-
>> >dev_id,
>> -????????????????????????? clk->clk_id,
>> -????????????????????????? index + 1 + clk->clk_id);
>> +??? ret = clk->provider->ops->set_parent(clk->provider->sci, clk-
>> >dev_id,
>> +???????????????????????? clk->clk_id,
>> +???????????????????????? index + 1 + clk->clk_id);
>> +??? if (!ret)
>> +??????? clk->parent_id = index;
>> +
>> +??? return ret;
>> +}
>> +
>> +static void sci_clk_restore_context(struct clk_hw *hw)
>> +{
>> +??? struct sci_clk *clk = to_sci_clk(hw);
>> +
>> +??? sci_clk_set_parent(hw, clk->parent_id);
> 
> You should restore,? if this is BOARD_CFG managed

restore_context() operation is called by clk_restore_context() for each
registered clock. And we call clk_restore_context() from ti_sci driver
only for BOARDCFG_MANAGED mode.

sci-clk driver cannot decide if clock context shall be restored or not.
Decision shall come from ti_sci as it knows the lpm mode.

Best Regards,
Thomas



From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec  3 06:16:45 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed,  3 Dec 2025 15:16:45 +0100
Subject: [PATCH] ASoC: rockchip: Fix Wvoid-pointer-to-enum-cast warning (again)
Message-ID: <20251203141644.106459-2-krzysztof.kozlowski@oss.qualcomm.com>

'version' is an enum, thus cast of pointer on 64-bit compile test with
clang W=1 causes:

  rockchip_pdm.c:583:17: error: cast to smaller integer type 'enum rk_pdm_version' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast]

This was already fixed in commit 49a4a8d12612 ("ASoC: rockchip: Fix
Wvoid-pointer-to-enum-cast warning") but then got bad in
commit 9958d85968ed ("ASoC: Use device_get_match_data()").

Discussion on LKML also pointed out that 'uintptr_t' is not the correct
type and either 'kernel_ulong_t' or 'unsigned long' should be used,
with several arguments towards the latter [1].

Link: https://lore.kernel.org/r/CAMuHMdX7t=mabqFE5O-Cii3REMuyaePHmqX+j_mqyrn6XXzsoA at mail.gmail.com/ [1]
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 sound/soc/rockchip/rockchip_pdm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c
index c1ee470ec607..c69cdd6f2499 100644
--- a/sound/soc/rockchip/rockchip_pdm.c
+++ b/sound/soc/rockchip/rockchip_pdm.c
@@ -580,7 +580,7 @@ static int rockchip_pdm_probe(struct platform_device *pdev)
 	if (!pdm)
 		return -ENOMEM;
 
-	pdm->version = (enum rk_pdm_version)device_get_match_data(&pdev->dev);
+	pdm->version = (unsigned long)device_get_match_data(&pdev->dev);
 	if (pdm->version == RK_PDM_RK3308) {
 		pdm->reset = devm_reset_control_get(&pdev->dev, "pdm-m");
 		if (IS_ERR(pdm->reset))
-- 
2.51.0



From mike.leach at linaro.org  Wed Dec  3 06:24:17 2025
From: mike.leach at linaro.org (Mike Leach)
Date: Wed, 3 Dec 2025 14:24:17 +0000
Subject: [PATCH v6 3/9] coresight: tmc: add etr_buf_list to store
 allocated etr_buf
In-Reply-To: <20250908-enable-byte-cntr-for-tmc-v6-3-1db9e621441a@oss.qualcomm.com>
References: <20250908-enable-byte-cntr-for-tmc-v6-0-1db9e621441a@oss.qualcomm.com>
 <20250908-enable-byte-cntr-for-tmc-v6-3-1db9e621441a@oss.qualcomm.com>
Message-ID: <CAJ9a7Vgd7+Gd5=Es=z17BB+DbOiL1WYGvNWx3uC0VyEngj2v0Q@mail.gmail.com>

On Mon, 8 Sept 2025 at 03:02, Jie Gan <jie.gan at oss.qualcomm.com> wrote:
>
> Add a list to store allocated etr_buf.
>
> The byte-cntr functionality requires two etr_buf to receive trace data.
> The active etr_buf collects the trace data from source device, while the
> byte-cntr reading function accesses the deactivated etr_buf after is
> has been filled and synced, transferring data to the userspace.
>
> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
> ---
>  drivers/hwtracing/coresight/coresight-tmc-core.c |  1 +
>  drivers/hwtracing/coresight/coresight-tmc.h      | 17 +++++++++++++++++
>  2 files changed, 18 insertions(+)
>
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c
> index be964656be93..4d249af93097 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-core.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c
> @@ -830,6 +830,7 @@ static int __tmc_probe(struct device *dev, struct resource *res)
>                 idr_init(&drvdata->idr);
>                 mutex_init(&drvdata->idr_mutex);
>                 dev_list = &etr_devs;
> +               INIT_LIST_HEAD(&drvdata->etr_buf_list);
>                 break;
>         case TMC_CONFIG_TYPE_ETF:
>                 desc.groups = coresight_etf_groups;
> diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
> index 6541a27a018e..292e25d82b62 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc.h
> +++ b/drivers/hwtracing/coresight/coresight-tmc.h
> @@ -208,6 +208,19 @@ struct tmc_resrv_buf {
>         s64             len;
>  };
>
> +/**
> + * @sysfs_buf: Allocated sysfs_buf.
> + * @is_free:   Indicates whether the buffer is free to choose.
> + * @pos:       Position of the buffer.
> + * @node:      Node in etr_buf_list.
> + */
> +struct etr_buf_node {
> +       struct etr_buf          *sysfs_buf;
> +       bool                    is_free;
> +       loff_t                  pos;
> +       struct list_head        node;
> +};
> +
>  /**
>   * struct tmc_drvdata - specifics associated to an TMC component
>   * @pclk:      APB clock if present, otherwise NULL
> @@ -242,6 +255,8 @@ struct tmc_resrv_buf {
>   *             (after crash) by default.
>   * @crash_mdata: Reserved memory for storing tmc crash metadata.
>   *              Used by ETR/ETF.
> + * @etr_buf_list: List that is used to manage allocated etr_buf.
> + * @reading_node: Available buffer for byte-cntr reading.
>   */
>  struct tmc_drvdata {
>         struct clk              *pclk;
> @@ -271,6 +286,8 @@ struct tmc_drvdata {
>         struct etr_buf          *perf_buf;
>         struct tmc_resrv_buf    resrv_buf;
>         struct tmc_resrv_buf    crash_mdata;
> +       struct list_head        etr_buf_list;
> +       struct etr_buf_node     *reading_node;
>  };
>
>  struct etr_buf_operations {
>
> --
> 2.34.1
>

Reviewed-by: Mike Leach <mike.leach at linaro.org>

-- 
Mike Leach
Principal Engineer, ARM Ltd.
Manchester Design Centre. UK


From mike.leach at linaro.org  Wed Dec  3 06:26:58 2025
From: mike.leach at linaro.org (Mike Leach)
Date: Wed, 3 Dec 2025 14:26:58 +0000
Subject: [PATCH v6 4/9] coresight: tmc: add create/clean functions for etr_buf_list
In-Reply-To: <20250908-enable-byte-cntr-for-tmc-v6-4-1db9e621441a@oss.qualcomm.com>
References: <20250908-enable-byte-cntr-for-tmc-v6-0-1db9e621441a@oss.qualcomm.com>
 <20250908-enable-byte-cntr-for-tmc-v6-4-1db9e621441a@oss.qualcomm.com>
Message-ID: <CAJ9a7Vg93PZzgxao6NjmGW2rJrZnnMj6+Lz3tdJ2P5AP-JS7ow@mail.gmail.com>

On Mon, 8 Sept 2025 at 03:02, Jie Gan <jie.gan at oss.qualcomm.com> wrote:
>
> Create and insert or remove the etr_buf_node to/from the etr_buf_list.
>
> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
> ---
>  drivers/hwtracing/coresight/coresight-tmc-etr.c | 94 +++++++++++++++++++++++++
>  drivers/hwtracing/coresight/coresight-tmc.h     |  2 +
>  2 files changed, 96 insertions(+)
>
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> index b07fcdb3fe1a..ed15991b3217 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> @@ -1909,6 +1909,100 @@ const struct coresight_ops tmc_etr_cs_ops = {
>         .panic_ops      = &tmc_etr_sync_ops,
>  };
>
> +/**
> + * tmc_clean_etr_buf_list - clean the etr_buf_list.
> + * @drvdata:   driver data of the TMC device.
> + *
> + * Remove the allocated node from the list and free the extra buffer.
> + */
> +void tmc_clean_etr_buf_list(struct tmc_drvdata *drvdata)
> +{
> +       struct etr_buf_node *nd, *next;
> +
> +       list_for_each_entry_safe(nd, next, &drvdata->etr_buf_list, node) {
> +               if (nd->sysfs_buf == drvdata->sysfs_buf) {
> +                       if (coresight_get_mode(drvdata->csdev) == CS_MODE_DISABLED) {
> +                               drvdata->sysfs_buf = NULL;
> +                               tmc_free_etr_buf(nd->sysfs_buf);
> +                               nd->sysfs_buf = NULL;
> +                       }
> +                       list_del(&nd->node);
> +                       kfree(nd);
> +               } else {
> +                       /* Free allocated buffers which are not utilized by ETR */
> +                       list_del(&nd->node);
> +                       tmc_free_etr_buf(nd->sysfs_buf);
> +                       nd->sysfs_buf = NULL;
> +                       kfree(nd);
> +               }
> +       }
> +}
> +EXPORT_SYMBOL_GPL(tmc_clean_etr_buf_list);
> +
> +/**
> + * tmc_create_etr_buf_list - create a list to manage the etr_buf_node.
> + * @drvdata:   driver data of the TMC device.
> + * @num_nodes: number of nodes want to create with the list.
> + *
> + * Return 0 upon success and return the error number if fail.
> + */
> +int tmc_create_etr_buf_list(struct tmc_drvdata *drvdata, int num_nodes)
> +{
> +       struct etr_buf_node *new_node;
> +       struct etr_buf *sysfs_buf;
> +       int i = 0, ret = 0;
> +
> +       /* We dont need a list if there is only one node */
> +       if (num_nodes < 2)
> +               return -EINVAL;
> +
> +       /* We expect that sysfs_buf in drvdata has already been allocated. */
> +       if (drvdata->sysfs_buf) {
> +               /* Directly insert the allocated sysfs_buf into the list first */
> +               new_node = kzalloc(sizeof(struct etr_buf_node), GFP_KERNEL);
> +               if (IS_ERR(new_node))
> +                       return PTR_ERR(new_node);
> +
> +               new_node->sysfs_buf = drvdata->sysfs_buf;
> +               new_node->is_free = false;
> +               list_add(&new_node->node, &drvdata->etr_buf_list);
> +               i++;
> +       }
> +
> +       while (i < num_nodes) {
> +               new_node = kzalloc(sizeof(struct etr_buf_node), GFP_KERNEL);
> +               if (IS_ERR(new_node)) {
> +                       ret = PTR_ERR(new_node);
> +                       break;
> +               }
> +
> +               sysfs_buf = tmc_alloc_etr_buf(drvdata, drvdata->size, 0, cpu_to_node(0), NULL);
> +               if (IS_ERR(sysfs_buf)) {
> +                       kfree(new_node);
> +                       ret = PTR_ERR(new_node);
> +                       break;
> +               }
> +
> +               /* We dont have a available sysfs_buf in drvdata, setup one */
> +               if (!drvdata->sysfs_buf) {
> +                       drvdata->sysfs_buf = sysfs_buf;
> +                       new_node->is_free = false;
> +               } else
> +                       new_node->is_free = true;
> +
> +               new_node->sysfs_buf = sysfs_buf;
> +               list_add(&new_node->node, &drvdata->etr_buf_list);
> +               i++;
> +       }
> +
> +       /* Clean the list if there is an error */
> +       if (ret)
> +               tmc_clean_etr_buf_list(drvdata);
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL_GPL(tmc_create_etr_buf_list);
> +
>  int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
>  {
>         int ret = 0;
> diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
> index 292e25d82b62..ca0cba860d5f 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc.h
> +++ b/drivers/hwtracing/coresight/coresight-tmc.h
> @@ -459,5 +459,7 @@ void tmc_etr_remove_catu_ops(void);
>  struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev,
>                                    enum cs_mode mode, void *data);
>  extern const struct attribute_group coresight_etr_group;
> +void tmc_clean_etr_buf_list(struct tmc_drvdata *drvdata);
> +int tmc_create_etr_buf_list(struct tmc_drvdata *drvdata, int num_nodes);
>
>  #endif
>
> --
> 2.34.1
>

Reviewed-by: Mike Leach <mike.leach at linaro.org>
-- 
Mike Leach
Principal Engineer, ARM Ltd.
Manchester Design Centre. UK


From mike.leach at linaro.org  Wed Dec  3 06:30:22 2025
From: mike.leach at linaro.org (Mike Leach)
Date: Wed, 3 Dec 2025 14:30:22 +0000
Subject: [PATCH v6 6/9] dt-bindings: arm: add an interrupt property for
 Coresight CTCU
In-Reply-To: <20250908-enable-byte-cntr-for-tmc-v6-6-1db9e621441a@oss.qualcomm.com>
References: <20250908-enable-byte-cntr-for-tmc-v6-0-1db9e621441a@oss.qualcomm.com>
 <20250908-enable-byte-cntr-for-tmc-v6-6-1db9e621441a@oss.qualcomm.com>
Message-ID: <CAJ9a7VitqEix7dumLq2ND=6+PU_eCkm8=YkHB0n7iHdJ8iKeVA@mail.gmail.com>

On Mon, 8 Sept 2025 at 03:02, Jie Gan <jie.gan at oss.qualcomm.com> wrote:
>
> Add an interrupt property to CTCU device. The interrupt will be triggered
> when the data size in the ETR buffer exceeds the threshold of the
> BYTECNTRVAL register. Programming a threshold in the BYTECNTRVAL register
> of CTCU device will enable the interrupt.
>
> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
> ---
>  .../devicetree/bindings/arm/qcom,coresight-ctcu.yaml    | 17 +++++++++++++++++
>  1 file changed, 17 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
> index 843b52eaf872..ea05ad8f3dd3 100644
> --- a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
> +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
> @@ -39,6 +39,16 @@ properties:
>      items:
>        - const: apb
>
> +  interrupts:
> +    items:
> +      - description: Byte cntr interrupt for etr0
> +      - description: Byte cntr interrupt for etr1
> +
> +  interrupt-names:
> +    items:
> +      - const: etr0
> +      - const: etr1
> +
>    in-ports:
>      $ref: /schemas/graph.yaml#/properties/ports
>
> @@ -56,6 +66,8 @@ additionalProperties: false
>
>  examples:
>    - |
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +
>      ctcu at 1001000 {
>          compatible = "qcom,sa8775p-ctcu";
>          reg = <0x1001000 0x1000>;
> @@ -63,6 +75,11 @@ examples:
>          clocks = <&aoss_qmp>;
>          clock-names = "apb";
>
> +        interrupts = <GIC_SPI 270 IRQ_TYPE_EDGE_RISING>,
> +                     <GIC_SPI 262 IRQ_TYPE_EDGE_RISING>;
> +        interrupt-names = "etr0",
> +                          "etr1";
> +
>          in-ports {
>              #address-cells = <1>;
>              #size-cells = <0>;
>
> --
> 2.34.1
>
Not sure if you need me to review this purely DT hardware description
update but...

Reviewed-by: Mike Leach <mike.leach at linaro.org>

-- 
Mike Leach
Principal Engineer, ARM Ltd.
Manchester Design Centre. UK


From maz at kernel.org  Wed Dec  3 06:58:13 2025
From: maz at kernel.org (Marc Zyngier)
Date: Wed, 03 Dec 2025 14:58:13 +0000
Subject: [PATCH 4/4] KVM: arm64: Convert VTCR_EL2 to config-driven sanitisation
In-Reply-To: <aTBDRx1oeGDs2SFl@raptor>
References: <20251129144525.2609207-1-maz@kernel.org>
	<20251129144525.2609207-5-maz@kernel.org>
	<aTAijieCI8055FL0@raptor>
	<86ikenpvna.wl-maz@kernel.org>
	<aTBDRx1oeGDs2SFl@raptor>
Message-ID: <86h5u7pq7u.wl-maz@kernel.org>

On Wed, 03 Dec 2025 14:03:51 +0000,
Alexandru Elisei <alexandru.elisei at arm.com> wrote:
> 
> Hi Marc,
> 
> On Wed, Dec 03, 2025 at 01:00:57PM +0000, Marc Zyngier wrote:
> > On Wed, 03 Dec 2025 11:44:14 +0000,
> > Alexandru Elisei <alexandru.elisei at arm.com> wrote:
> > > 
> > > Hi Marc,
> > > 
> > > On Sat, Nov 29, 2025 at 02:45:25PM +0000, Marc Zyngier wrote:
> > > > Describe all the VTCR_EL2 fields and their respective configurations,
> > > > making sure that we correctly ignore the bits that are not defined
> > > > for a given guest configuration.
> > > > 
> > > > Signed-off-by: Marc Zyngier <maz at kernel.org>
> > > > ---
> > > >  arch/arm64/kvm/config.c | 69 +++++++++++++++++++++++++++++++++++++++++
> > > >  arch/arm64/kvm/nested.c |  3 +-
> > > >  2 files changed, 70 insertions(+), 2 deletions(-)
> > > > 
> > > > diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
> > > > index a02c28d6a61c9..c36e133c51912 100644
> > > > --- a/arch/arm64/kvm/config.c
> > > > +++ b/arch/arm64/kvm/config.c
> > > > @@ -141,6 +141,7 @@ struct reg_feat_map_desc {
> > > >  #define FEAT_AA64EL1		ID_AA64PFR0_EL1, EL1, IMP
> > > >  #define FEAT_AA64EL2		ID_AA64PFR0_EL1, EL2, IMP
> > > >  #define FEAT_AA64EL3		ID_AA64PFR0_EL1, EL3, IMP
> > > > +#define FEAT_SEL2		ID_AA64PFR0_EL1, SEL2, IMP
> > > >  #define FEAT_AIE		ID_AA64MMFR3_EL1, AIE, IMP
> > > >  #define FEAT_S2POE		ID_AA64MMFR3_EL1, S2POE, IMP
> > > >  #define FEAT_S1POE		ID_AA64MMFR3_EL1, S1POE, IMP
> > > > @@ -202,6 +203,8 @@ struct reg_feat_map_desc {
> > > >  #define FEAT_ASID2		ID_AA64MMFR4_EL1, ASID2, IMP
> > > >  #define FEAT_MEC		ID_AA64MMFR3_EL1, MEC, IMP
> > > >  #define FEAT_HAFT		ID_AA64MMFR1_EL1, HAFDBS, HAFT
> > > > +#define FEAT_HDBSS		ID_AA64MMFR1_EL1, HAFDBS, HDBSS
> > > > +#define FEAT_HPDS2		ID_AA64MMFR1_EL1, HPDS, HPDS2
> > > >  #define FEAT_BTI		ID_AA64PFR1_EL1, BT, IMP
> > > >  #define FEAT_ExS		ID_AA64MMFR0_EL1, EXS, IMP
> > > >  #define FEAT_IESB		ID_AA64MMFR2_EL1, IESB, IMP
> > > > @@ -219,6 +222,7 @@ struct reg_feat_map_desc {
> > > >  #define FEAT_FGT2		ID_AA64MMFR0_EL1, FGT, FGT2
> > > >  #define FEAT_MTPMU		ID_AA64DFR0_EL1, MTPMU, IMP
> > > >  #define FEAT_HCX		ID_AA64MMFR1_EL1, HCX, IMP
> > > > +#define FEAT_S2PIE		ID_AA64MMFR3_EL1, S2PIE, IMP
> > > >  
> > > >  static bool not_feat_aa64el3(struct kvm *kvm)
> > > >  {
> > > > @@ -362,6 +366,28 @@ static bool feat_pmuv3p9(struct kvm *kvm)
> > > >  	return check_pmu_revision(kvm, V3P9);
> > > >  }
> > > >  
> > > > +#define has_feat_s2tgran(k, s)						\
> > > > +  ((kvm_has_feat_enum(kvm, ID_AA64MMFR0_EL1, TGRAN##s##_2, TGRAN##s) && \
> > > > +    !kvm_has_feat_enum(kvm, ID_AA64MMFR0_EL1, TGRAN##s, NI))	     ||	\
> > > 
> > > Wouldn't that read better as kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN##s, IMP)?
> > > I think that would also be correct.
> > 
> > Sure, I don't mind either way,
> > 
> > > 
> > > > +   kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN##s##_2, IMP))
> > > 
> > > A bit unexpected to treat the same field first as an enum, then as an integer,
> > > but it saves one line.
> > 
> > It potentially saves more if the encoding grows over time. I don't
> > think it matters.
> 
> Doesn't, was just aestethics and saves someone having to check the values to
> make sure it wasn't an error.
> 
> > 
> > > 
> > > > +
> > > > +static bool feat_lpa2(struct kvm *kvm)
> > > > +{
> > > > +	return ((kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4, 52_BIT)    ||
> > > > +		 !kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4, IMP))	&&
> > > > +		(kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16, 52_BIT)   ||
> > > > +		 !kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16, IMP))	&&
> > > > +		(kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4_2, 52_BIT)  ||
> > > > +		 !has_feat_s2tgran(kvm, 4))				&&
> > > > +		(kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16_2, 52_BIT) ||
> > > > +		 !has_feat_s2tgran(kvm, 16)));
> > > > +}
> > > 
> > > That was a doozy, but looks correct to me if the intention was to have the check
> > > as relaxed as possible - i.e, a VM can advertise 52 bit support for one granule,
> > > but not the other (same for stage 1 and stage 2).
> > 
> > Not quite. The intent is that, for all the possible granules, at all
> > the possible stages, either the granule size isn't implemented at all,
> > or it supports 52 bits. I think this covers it, but as you said, this
> > is a bit of a bran fsck.
> 
> Hm... this sounds like something that should be sanitised in
> set_id_aa64mmfr0_el1(). Sorry, but I just can't tell if TGran{4,16,64} are
> writable by userspace.

Everything in ID_AA64MMFR0_EL1 is writable, except for ASIDBITS.

> 
> > 
> > This is essentially a transliteration of the MRS:
> > 
> > (FEAT_LPA2 && FEAT_S2TGran4K) <=> (UInt(ID_AA64MMFR0_EL1.TGran4_2) >= 3))
> > (FEAT_LPA2 && FEAT_S2TGran16K) <=> (UInt(ID_AA64MMFR0_EL1.TGran16_2) >= 3))
> > (FEAT_LPA2 && FEAT_TGran4K) <=> (SInt(ID_AA64MMFR0_EL1.TGran4) >= 1))
> > (FEAT_LPA2 && FEAT_TGran16K) <=> (UInt(ID_AA64MMFR0_EL1.TGran16) >= 2))
> > FEAT_S2TGran4K <=> (((UInt(ID_AA64MMFR0_EL1.TGran4_2) == 0) && FEAT_TGran4K) || (UInt(ID_AA64MMFR0_EL1.TGran4_2) >= 2))
> > FEAT_S2TGran16K <=> (((UInt(ID_AA64MMFR0_EL1.TGran16_2) == 0) && FEAT_TGran16K) || (UInt(ID_AA64MMFR0_EL1.TGran16_2) >= 2))
> > FEAT_TGran4K <=> (SInt(ID_AA64MMFR0_EL1.TGran4) >= 0)
> > FEAT_TGran16K <=> (UInt(ID_AA64MMFR0_EL1.TGran16) >= 1)
> 
> How about (untested):
> 
> static bool feat_lpas2(struct kvm *kvm)
> {
> 	if (kvm_has_feat_exact(kvm, ID_AA64MMFR0_EL1, TGRAN4, IMP) ||
> 	    kvm_has_feat_exact(kvm, ID_AA64MMFR0_EL1, TGRAN16, IMP) ||
> 	    kvm_has_feat_exact(kvm, ID_AA64MMFR0_EL1, TGRAN4_2, IMP) ||
> 	    kvm_has_feat_exact(kvm, ID_AA64MMFR0_EL1, TGRAN16_2, IMP))
> 		return false;
> 
> 	return true;
> }

The combination (TGRAN4=NI, TGRAN2_4=TGRAN4, TGRAN16=52_BIT,
TGRAN16_2=52_BIT) is a valid LPA2 configuration, which the test above
rejects.

> where, in case there's not something similar already and I just don't know about
> it:
> 
> #define kvm_has_feat_exact(kvm, id, fld, val)			\
> 	kvm_cmp_feat(kvm, id, fld, =, val)

#define __kvm_has_feat_enum(kvm, id, fld, val)				\
	kvm_cmp_feat_unsigned(kvm, id, fld, ==, val)

#define kvm_has_feat_enum(kvm, ...) __kvm_has_feat_enum(kvm, __VA_ARGS__)

> The idea being that if one of the granules does not support 52 bit, then it's
> not supported by any of the other granules.

See above why I think your proposal doesn't work.

Thanks,

	M.

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


From alexandru.elisei at arm.com  Wed Dec  3 07:20:16 2025
From: alexandru.elisei at arm.com (Alexandru Elisei)
Date: Wed, 3 Dec 2025 15:20:16 +0000
Subject: [PATCH 4/4] KVM: arm64: Convert VTCR_EL2 to config-driven
 sanitisation
In-Reply-To: <86h5u7pq7u.wl-maz@kernel.org>
References: <20251129144525.2609207-1-maz@kernel.org>
 <20251129144525.2609207-5-maz@kernel.org>
 <aTAijieCI8055FL0@raptor>
 <86ikenpvna.wl-maz@kernel.org>
 <aTBDRx1oeGDs2SFl@raptor>
 <86h5u7pq7u.wl-maz@kernel.org>
Message-ID: <aTBVMIxeVbiZq0ee@raptor>

Hi Marc,

On Wed, Dec 03, 2025 at 02:58:13PM +0000, Marc Zyngier wrote:
> On Wed, 03 Dec 2025 14:03:51 +0000,
> Alexandru Elisei <alexandru.elisei at arm.com> wrote:
> > 
> > Hi Marc,
> > 
> > On Wed, Dec 03, 2025 at 01:00:57PM +0000, Marc Zyngier wrote:
> > > On Wed, 03 Dec 2025 11:44:14 +0000,
> > > Alexandru Elisei <alexandru.elisei at arm.com> wrote:
> > > > 
> > > > Hi Marc,
> > > > 
> > > > On Sat, Nov 29, 2025 at 02:45:25PM +0000, Marc Zyngier wrote:
> > > > > Describe all the VTCR_EL2 fields and their respective configurations,
> > > > > making sure that we correctly ignore the bits that are not defined
> > > > > for a given guest configuration.
> > > > > 
> > > > > Signed-off-by: Marc Zyngier <maz at kernel.org>
> > > > > ---
> > > > >  arch/arm64/kvm/config.c | 69 +++++++++++++++++++++++++++++++++++++++++
> > > > >  arch/arm64/kvm/nested.c |  3 +-
> > > > >  2 files changed, 70 insertions(+), 2 deletions(-)
> > > > > 
> > > > > diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
> > > > > index a02c28d6a61c9..c36e133c51912 100644
> > > > > --- a/arch/arm64/kvm/config.c
> > > > > +++ b/arch/arm64/kvm/config.c
> > > > > @@ -141,6 +141,7 @@ struct reg_feat_map_desc {
> > > > >  #define FEAT_AA64EL1		ID_AA64PFR0_EL1, EL1, IMP
> > > > >  #define FEAT_AA64EL2		ID_AA64PFR0_EL1, EL2, IMP
> > > > >  #define FEAT_AA64EL3		ID_AA64PFR0_EL1, EL3, IMP
> > > > > +#define FEAT_SEL2		ID_AA64PFR0_EL1, SEL2, IMP
> > > > >  #define FEAT_AIE		ID_AA64MMFR3_EL1, AIE, IMP
> > > > >  #define FEAT_S2POE		ID_AA64MMFR3_EL1, S2POE, IMP
> > > > >  #define FEAT_S1POE		ID_AA64MMFR3_EL1, S1POE, IMP
> > > > > @@ -202,6 +203,8 @@ struct reg_feat_map_desc {
> > > > >  #define FEAT_ASID2		ID_AA64MMFR4_EL1, ASID2, IMP
> > > > >  #define FEAT_MEC		ID_AA64MMFR3_EL1, MEC, IMP
> > > > >  #define FEAT_HAFT		ID_AA64MMFR1_EL1, HAFDBS, HAFT
> > > > > +#define FEAT_HDBSS		ID_AA64MMFR1_EL1, HAFDBS, HDBSS
> > > > > +#define FEAT_HPDS2		ID_AA64MMFR1_EL1, HPDS, HPDS2
> > > > >  #define FEAT_BTI		ID_AA64PFR1_EL1, BT, IMP
> > > > >  #define FEAT_ExS		ID_AA64MMFR0_EL1, EXS, IMP
> > > > >  #define FEAT_IESB		ID_AA64MMFR2_EL1, IESB, IMP
> > > > > @@ -219,6 +222,7 @@ struct reg_feat_map_desc {
> > > > >  #define FEAT_FGT2		ID_AA64MMFR0_EL1, FGT, FGT2
> > > > >  #define FEAT_MTPMU		ID_AA64DFR0_EL1, MTPMU, IMP
> > > > >  #define FEAT_HCX		ID_AA64MMFR1_EL1, HCX, IMP
> > > > > +#define FEAT_S2PIE		ID_AA64MMFR3_EL1, S2PIE, IMP
> > > > >  
> > > > >  static bool not_feat_aa64el3(struct kvm *kvm)
> > > > >  {
> > > > > @@ -362,6 +366,28 @@ static bool feat_pmuv3p9(struct kvm *kvm)
> > > > >  	return check_pmu_revision(kvm, V3P9);
> > > > >  }
> > > > >  
> > > > > +#define has_feat_s2tgran(k, s)						\
> > > > > +  ((kvm_has_feat_enum(kvm, ID_AA64MMFR0_EL1, TGRAN##s##_2, TGRAN##s) && \
> > > > > +    !kvm_has_feat_enum(kvm, ID_AA64MMFR0_EL1, TGRAN##s, NI))	     ||	\
> > > > 
> > > > Wouldn't that read better as kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN##s, IMP)?
> > > > I think that would also be correct.
> > > 
> > > Sure, I don't mind either way,
> > > 
> > > > 
> > > > > +   kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN##s##_2, IMP))
> > > > 
> > > > A bit unexpected to treat the same field first as an enum, then as an integer,
> > > > but it saves one line.
> > > 
> > > It potentially saves more if the encoding grows over time. I don't
> > > think it matters.
> > 
> > Doesn't, was just aestethics and saves someone having to check the values to
> > make sure it wasn't an error.
> > 
> > > 
> > > > 
> > > > > +
> > > > > +static bool feat_lpa2(struct kvm *kvm)
> > > > > +{
> > > > > +	return ((kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4, 52_BIT)    ||
> > > > > +		 !kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4, IMP))	&&
> > > > > +		(kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16, 52_BIT)   ||
> > > > > +		 !kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16, IMP))	&&
> > > > > +		(kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4_2, 52_BIT)  ||
> > > > > +		 !has_feat_s2tgran(kvm, 4))				&&
> > > > > +		(kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16_2, 52_BIT) ||
> > > > > +		 !has_feat_s2tgran(kvm, 16)));
> > > > > +}
> > > > 
> > > > That was a doozy, but looks correct to me if the intention was to have the check
> > > > as relaxed as possible - i.e, a VM can advertise 52 bit support for one granule,
> > > > but not the other (same for stage 1 and stage 2).
> > > 
> > > Not quite. The intent is that, for all the possible granules, at all
> > > the possible stages, either the granule size isn't implemented at all,
> > > or it supports 52 bits. I think this covers it, but as you said, this
> > > is a bit of a bran fsck.
> > 
> > Hm... this sounds like something that should be sanitised in
> > set_id_aa64mmfr0_el1(). Sorry, but I just can't tell if TGran{4,16,64} are
> > writable by userspace.
> 
> Everything in ID_AA64MMFR0_EL1 is writable, except for ASIDBITS.

Aaah, ok so a bit set in the 'mask' argument to ID_FILTERED means the bit is
writable (the comment for ID_FILTERED doesn't explain that).

> 
> > 
> > > 
> > > This is essentially a transliteration of the MRS:
> > > 
> > > (FEAT_LPA2 && FEAT_S2TGran4K) <=> (UInt(ID_AA64MMFR0_EL1.TGran4_2) >= 3))
> > > (FEAT_LPA2 && FEAT_S2TGran16K) <=> (UInt(ID_AA64MMFR0_EL1.TGran16_2) >= 3))
> > > (FEAT_LPA2 && FEAT_TGran4K) <=> (SInt(ID_AA64MMFR0_EL1.TGran4) >= 1))
> > > (FEAT_LPA2 && FEAT_TGran16K) <=> (UInt(ID_AA64MMFR0_EL1.TGran16) >= 2))
> > > FEAT_S2TGran4K <=> (((UInt(ID_AA64MMFR0_EL1.TGran4_2) == 0) && FEAT_TGran4K) || (UInt(ID_AA64MMFR0_EL1.TGran4_2) >= 2))
> > > FEAT_S2TGran16K <=> (((UInt(ID_AA64MMFR0_EL1.TGran16_2) == 0) && FEAT_TGran16K) || (UInt(ID_AA64MMFR0_EL1.TGran16_2) >= 2))
> > > FEAT_TGran4K <=> (SInt(ID_AA64MMFR0_EL1.TGran4) >= 0)
> > > FEAT_TGran16K <=> (UInt(ID_AA64MMFR0_EL1.TGran16) >= 1)
> > 
> > How about (untested):
> > 
> > static bool feat_lpas2(struct kvm *kvm)
> > {
> > 	if (kvm_has_feat_exact(kvm, ID_AA64MMFR0_EL1, TGRAN4, IMP) ||
> > 	    kvm_has_feat_exact(kvm, ID_AA64MMFR0_EL1, TGRAN16, IMP) ||
> > 	    kvm_has_feat_exact(kvm, ID_AA64MMFR0_EL1, TGRAN4_2, IMP) ||
> > 	    kvm_has_feat_exact(kvm, ID_AA64MMFR0_EL1, TGRAN16_2, IMP))
> > 		return false;
> > 
> > 	return true;
> > }
> 
> The combination (TGRAN4=NI, TGRAN2_4=TGRAN4, TGRAN16=52_BIT,
> TGRAN16_2=52_BIT) is a valid LPA2 configuration, which the test above
> rejects.

Thank you for taking the time to entertain my comments. It's not clear to me why
the combination is rejected since there are no IMP values in your example, but I
trust your judgement and I don't want to waste your time on nitpicking.

My Reviewed-by stands, by the way, in case that wasn't clear.

Thanks,
Alex


From sudeep.holla at arm.com  Wed Dec  3 07:21:31 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Wed, 3 Dec 2025 15:21:31 +0000
Subject: [PATCH 0/8] firmware: arm_scmi: Refactoring and enablement of
 ACPI PCC transport
In-Reply-To: <877bv3n7x2.fsf@stealth>
References: <20251017-acpi_scmi_pcc-v1-0-0adbab7709d9@arm.com>
 <87wm44aect.fsf@stealth>
 <20251126-camouflaged-delightful-cuckoo-ddeac8@sudeepholla>
 <877bv3n7x2.fsf@stealth>
Message-ID: <20251203-super-kagu-of-amplitude-fef078@sudeepholla>

On Wed, Dec 03, 2025 at 11:04:09AM +0000, Punit Agrawal wrote:
> Hi Sudeep,
> 
> Sudeep Holla <sudeep.holla at arm.com> writes:
> 
> > I can create one but that is not strictly necessary. As mentioned in the
> > cover letter, the only dependency is on value of SCMI_PROTOCOL_TELEMETRY
> > ins `scmi_std_protocol` enumeration. Just add one and you must be able to
> > compile the series independent of Cristian series.
> 
> Thanks, I managed to get the patches building. Looking forward to the
> series progressing. If possible, do keep me in the loop for future
> updates.

Sure - I?ll try to remember to copy you on the next updates. I don?t have any
immediate plans, though, unless the spec moves into beta, changes come up, or
someone specifically requests important updates that would help them make
progress.

Do you have immediate plans to use this on a platform ? Or you are reviewing
just out of interest/curiosity ? ?

-- 
Regards,
Sudeep


From allyheev at gmail.com  Wed Dec  3 07:22:34 2025
From: allyheev at gmail.com (Ally Heev)
Date: Wed, 03 Dec 2025 20:52:34 +0530
Subject: [PATCH v2] arm: fix uninitialized pointers with free attr
Message-ID: <20251203-aheev-uninitialized-free-attr-arm-v2-1-db52b2655ddf@gmail.com>

Uninitialized pointers with `__free` attribute can cause undefined
behaviour as the memory assigned(randomly) to the pointer is freed
automatically when the pointer goes out of scope

arm doesn't have any bugs related to this as of now, but
it is better to initialize and assign pointers with `__free` attr
in one statement to ensure proper scope-based cleanup

Reported-by: Dan Carpenter <dan.carpenter at linaro.org>
Closes: https://lore.kernel.org/all/aPiG_F5EBQUjZqsl at stanley.mountain/
Signed-off-by: Ally Heev <allyheev at gmail.com>
Reviewed-by: Cristian Marussi <cristian.marussi at arm.com>
---
Changes in v2:
- added Reviewed-by trailer
- Link to v1: https://lore.kernel.org/r/20251105-aheev-uninitialized-free-attr-arm-v1-1-f7b6cb5d3361 at gmail.com
---
 drivers/firmware/arm_scmi/shmem.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/firmware/arm_scmi/shmem.c b/drivers/firmware/arm_scmi/shmem.c
index 11c347bff766763c61100f884432c2e4669e5918..dadb37557f8aee25465e1a423dfcb4a889852434 100644
--- a/drivers/firmware/arm_scmi/shmem.c
+++ b/drivers/firmware/arm_scmi/shmem.c
@@ -196,7 +196,6 @@ static void __iomem *shmem_setup_iomap(struct scmi_chan_info *cinfo,
 				       struct resource *res,
 				       struct scmi_shmem_io_ops **ops)
 {
-	struct device_node *shmem __free(device_node);
 	const char *desc = tx ? "Tx" : "Rx";
 	int ret, idx = tx ? 0 : 1;
 	struct device *cdev = cinfo->dev;
@@ -205,7 +204,9 @@ static void __iomem *shmem_setup_iomap(struct scmi_chan_info *cinfo,
 	void __iomem *addr;
 	u32 reg_io_width;
 
-	shmem = of_parse_phandle(cdev->of_node, "shmem", idx);
+	struct device_node *shmem __free(device_node) = of_parse_phandle(cdev->of_node,
+		"shmem", idx);
+
 	if (!shmem)
 		return IOMEM_ERR_PTR(-ENODEV);
 

---
base-commit: c9cfc122f03711a5124b4aafab3211cf4d35a2ac
change-id: 20251105-aheev-uninitialized-free-attr-arm-cf3516ba1a18

Best regards,
-- 
Ally Heev <allyheev at gmail.com>



From jonathanh at nvidia.com  Wed Dec  3 07:34:26 2025
From: jonathanh at nvidia.com (Jon Hunter)
Date: Wed, 3 Dec 2025 15:34:26 +0000
Subject: [PATCH V3 1/3] iommu/arm-smmu-v3: Add device-tree support for
 CMDQV driver
In-Reply-To: <20251201163219.3237266-2-amhetre@nvidia.com>
References: <20251201163219.3237266-1-amhetre@nvidia.com>
 <20251201163219.3237266-2-amhetre@nvidia.com>
Message-ID: <515c552a-2013-4c7e-a0fc-c9a8c7d40d69@nvidia.com>


On 01/12/2025 16:32, Ashish Mhetre wrote:
> Add device tree support to the CMDQV driver to enable usage on Tegra264
> SoCs. The implementation parses the nvidia,cmdqv phandle from the SMMU
> device tree node to associate each SMMU with its corresponding CMDQV
> instance based on compatible string.
> 
> Remove the dependency from Kconfig as the driver now supports both ACPI
> and device tree initialization through conditional compilation and
> ARM_SMMU_V3 depends on ARM64 which implies at least OF.
> 
> Reviewed-by: Nicolin Chen <nicolinc at nvidia.com>
> Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
> ---
>   drivers/iommu/arm/Kconfig                     |  1 -
>   drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 32 ++++++++++++++
>   .../iommu/arm/arm-smmu-v3/tegra241-cmdqv.c    | 43 ++++++++++++++++++-
>   3 files changed, 74 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/iommu/arm/Kconfig b/drivers/iommu/arm/Kconfig
> index ef42bbe07dbe..5fac08b89dee 100644
> --- a/drivers/iommu/arm/Kconfig
> +++ b/drivers/iommu/arm/Kconfig
> @@ -121,7 +121,6 @@ config ARM_SMMU_V3_KUNIT_TEST
>   
>   config TEGRA241_CMDQV
>   	bool "NVIDIA Tegra241 CMDQ-V extension support for ARM SMMUv3"
> -	depends on ACPI
>   	help
>   	  Support for NVIDIA CMDQ-Virtualization extension for ARM SMMUv3. The
>   	  CMDQ-V extension is similar to v3.3 ECMDQ for multi command queues
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index a33fbd12a0dd..206dffabc9c0 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -4530,6 +4530,35 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
>   	return 0;
>   }
>   
> +#ifdef CONFIG_TEGRA241_CMDQV
> +static void tegra_cmdqv_dt_probe(struct device_node *smmu_node,
> +				 struct arm_smmu_device *smmu)
> +{
> +	struct platform_device *pdev;
> +	struct device_node *np;
> +
> +	np = of_parse_phandle(smmu_node, "nvidia,cmdqv", 0);
> +	if (!np)
> +		return;
> +
> +	pdev = of_find_device_by_node(np);
> +	of_node_put(np);
> +	if (!pdev)
> +		return;
> +
> +	smmu->impl_dev = &pdev->dev;
> +	smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
> +	dev_info(smmu->dev, "found companion CMDQV device: %s\n",
> +		 dev_name(smmu->impl_dev));
> +	put_device(&pdev->dev);
> +}
> +#else
> +static void tegra_cmdqv_dt_probe(struct device_node *smmu_node,
> +				 struct arm_smmu_device *smmu)
> +{
> +}
> +#endif
> +
>   #ifdef CONFIG_ACPI
>   #ifdef CONFIG_TEGRA241_CMDQV
>   static void acpi_smmu_dsdt_probe_tegra241_cmdqv(struct acpi_iort_node *node,
> @@ -4634,6 +4663,9 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev,
>   	if (of_dma_is_coherent(dev->of_node))
>   		smmu->features |= ARM_SMMU_FEAT_COHERENCY;
>   
> +	if (of_device_is_compatible(dev->of_node, "nvidia,tegra264-smmu"))
> +		tegra_cmdqv_dt_probe(dev->of_node, smmu);
> +
>   	return ret;
>   }
>   
> diff --git a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
> index 378104cd395e..2608bf6518b4 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
> @@ -11,6 +11,8 @@
>   #include <linux/iommufd.h>
>   #include <linux/iopoll.h>
>   #include <uapi/linux/iommufd.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
>   
>   #include <acpi/acpixf.h>
>   
> @@ -917,6 +919,26 @@ tegra241_cmdqv_find_acpi_resource(struct device *dev, int *irq)
>   	return res;
>   }
>   
> +static struct resource *
> +tegra241_cmdqv_find_dt_resource(struct device *dev, int *irq)
> +{
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct resource *res;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res) {
> +		dev_err(dev, "no memory resource found for CMDQV\n");
> +		return NULL;
> +	}
> +
> +	if (irq)
> +		*irq = platform_get_irq_optional(pdev, 0);
> +	if (!irq || *irq <= 0)
> +		dev_warn(dev, "no interrupt. errors will not be reported\n");
> +
> +	return res;
> +}
> +
>   static int tegra241_cmdqv_init_structures(struct arm_smmu_device *smmu)
>   {
>   	struct tegra241_cmdqv *cmdqv =
> @@ -1048,11 +1070,14 @@ struct arm_smmu_device *tegra241_cmdqv_probe(struct arm_smmu_device *smmu)
>   
>   	if (!smmu->dev->of_node)
>   		res = tegra241_cmdqv_find_acpi_resource(smmu->impl_dev, &irq);
> +	else
> +		res = tegra241_cmdqv_find_dt_resource(smmu->impl_dev, &irq);
>   	if (!res)
>   		goto out_fallback;
>   
>   	new_smmu = __tegra241_cmdqv_probe(smmu, res, irq);
> -	kfree(res);
> +	if (!smmu->dev->of_node)
> +		kfree(res);
>   
>   	if (new_smmu)
>   		return new_smmu;
> @@ -1346,4 +1371,20 @@ tegra241_cmdqv_init_vintf_user(struct arm_vsmmu *vsmmu,
>   	return ret;
>   }
>   
> +static const struct of_device_id tegra241_cmdqv_of_match[] = {
> +	{ .compatible = "nvidia,tegra264-cmdqv" },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, tegra241_cmdqv_of_match);
> +
> +static struct platform_driver tegra241_cmdqv_driver = {
> +	.driver = {
> +		.name = "tegra241-cmdqv",
> +		.of_match_table = tegra241_cmdqv_of_match,
> +	},
> +};
> +module_platform_driver(tegra241_cmdqv_driver);

This part looks a bit weird, because it appears to do nothing. The 
compatible string is not used at all in the driver AFAICT. Have you 
tried this bit out because this is not a proper driver?

Jon

-- 
nvpublic



From suzuki.poulose at arm.com  Wed Dec  3 07:48:48 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Wed, 3 Dec 2025 15:48:48 +0000
Subject: [PATCH v8 0/7] Provides support for Trigger Generation Unit
In-Reply-To: <20251203090055.2432719-1-songwei.chai@oss.qualcomm.com>
References: <20251203090055.2432719-1-songwei.chai@oss.qualcomm.com>
Message-ID: <4f53766f-6338-4d94-a947-19b95952e08a@arm.com>

Cc: Greg

On 03/12/2025 09:00, Songwei Chai wrote:
> We propose creating a new qcom directory under drivers/hwtracing
> to host this TGU driver, as well as additional Qualcomm-specific
> hwtracing drivers that we plan to submit in the coming months.
> This structure will help organize vendor-specific implementations
> and facilitate future development and maintenance.
> 
> Feedback from the community on this proposal is highly appreciated.
> 
> - Why we are proposing this:
> 
> TGU has the ability to monitor signal conditions and trigger debug-related
> actions, serving as a programmable hardware component that enhances system
> trace and debug capabilities. Placing it under drivers/hwtracing aligns with
> its function as a trace generation utility.
> 
> We previously attempted to push this driver to drivers/hwtracing/coresight,
> but did not receive support from the maintainers of the CoreSight subsystem.
> The reason provided was: ?This component is primarily a part of the
> Qualcomm proprietary QPMDA subsystem, and is capable of operating
> independently from the CoreSight hardware trace generation system.?
> 
> Chat history : https://lore.kernel.org/all/CAJ9a7ViKxHThyZfFFDV_FkNRimk4uo1NrMtQ-kcaj1qO4ZcGnA at mail.gmail.com/
> 
> Given this, we have been considering whether it would be appropriate
> to create a dedicated drivers/hwtracing/qcom directory for
> Qualcomm-related hwtracing drivers. This would follow the precedent set
> by Intel, which maintains its own directory at drivers/hwtracing/intel_th.
> We believe this structure would significantly facilitate
> future submissions of related Qualcomm drivers.
> 
> - Maintenance of drivers/hwtracing/qcom:
> 

Fine by, me.


> Bjorn, who maintains linux-arm-msm, will be the maintainer of this
> directory ? we?ve discussed this with him and he?s aware that his task
> list may grow accordingly. Additionally, Qualcomm engineers familiar with
> the debug hardware ? such as [Tingwei Zhang, Jinlong Mao, Songwei Chai],
> will be available to review incoming patches and support ongoing
> development.
> 
> - Detail for TGU:
> 
> This component can be utilized to sense a plurality of signals and
> create a trigger into the CTI or generate interrupts to processors
> once the input signal meets the conditions. We can treat the TGU?s
> workflow as a flowsheet, it has some ?steps? regions for customization.
> In each step region, we can set the signals that we want with priority
> in priority_group, set the conditions in each step via condition_decode,
> and set the resultant action by condition_select. Meanwhile,
> some TGUs (not all) also provide timer/counter functionality.
> Based on the characteristics described above, we consider the TGU as a
> helper in the CoreSight subsystem. Its master device is the TPDM, which
> can transmit signals from other subsystems, and we reuse the existing
> ports mechanism to link the TPDM to the connected TGU.

Please remove the coresight_device and other dependencies. You may use
generic bits, CS_LOCK/UNLOCK etc. But including coresight-priv.h is
not something I would prefer. It brings in unnecessary dependencies
between two subsystems and I don't see any reason for using -priv.h.
It is named as it is, for a reason, coresight private definitions.


> 
> Here is a detailed example to explain how to use the TGU:
> 
> In this example, the TGU is configured to use 2 conditions, 2 steps, and
> the timer. The goal is to look for one of two patterns which are generated
> from TPDM, giving priority to one, and then generate a trigger once the
> timer reaches a certain value. In other words, two conditions are used
> for the first step to look for the two patterns, where the one with the
> highest priority is used in the first condition. Then, in the second step,
> the timer is enabled and set to be compared to the given value at each
> clock cycle. These steps are better shown below.
>      
>                |-----------------|
>                |                 |
>                |       TPDM      |
>                |                 |
>                |-----------------|
>                         |
>                         |
>      --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ------
>      |                  |                                                 |
>      |                  |                          |--------------------| |
>      |    |---- --->    |                          |  Go to next steps  | |
>      |    |             |                |--- ---> |  Enable timer      | |
>      |    |             v                |         |                    | |
>      |    |    |-----------------|       |         |--------------------| |
>      |    |    |                 |  Yes  |                    |           |
>      |    |    |   inputs==0xB   | ----->|                    | <-------- |
>      |    |    |                 |       |                    |      No | |
>      | No |    |-----------------|       |                    v         | |
>      |    |             |                |          |-----------------| | |
>      |    |             |                |          |                 | | |
>      |    |             |                |          |      timer>=3   |-- |
>      |    |             v                |          |                 |   |
>      |    |    |-----------------|       |          |-----------------|   |
>      |    |    |                 |  Yes  |                    |           |
>      |    |--- |   inputs==0xA   | ----->|                    | Yes       |
>      |         |                 |                            |           |
>      |         |-----------------|                            v           |
>      |                                              |-----------------|   |
>      |                                              |                 |   |
>      |                                              |      Trigger    |   |
>      |                                              |                 |   |
>      |                                              |-----------------|   |
>      |  TGU                                                   |           |
>      |--- --- --- --- --- --- --- --- --- --- --- --- --- --- |--- --- -- |
>                                                               |
>                                                               v
>                                                      |-----------------|
>                                                      |The controllers  |
>                                                      |which will use   |
>                                                      |triggers further |
>                                                      |-----------------|
> 
> steps:
>      1. Reset TGU /*it will disable tgu and reset dataset*/
>      - echo 1 > /sys/bus/coresight/devices/<tgu-name>/reset_tgu
> 
>      2. Set the pattern match for priority0 to 0xA = 0b1010 and for
>         priority 1 to 0xB = 0b1011.
>      - echo 0x11113232 > /sys/bus/coresight/devices/<tgu-name>/step0_priority0/reg0
>      - echo 0x11113233 > /sys/bus/coresight/devices/<tgu-name>/step0_priority1/reg0

Why do they need to be coresight devices and appear on the coresight bus 
if they are not coresight devices ? As I understand they are simply
devices with some sysfs knobs.

Otherwise, happy with the proposal


Suzuki




> 
>      Note:
>          Bit distribution diagram for each priority register
>      |-------------------------------------------------------------------|
>      |   Bits          |       Field Nam   |    Description              |
>      |-------------------------------------------------------------------|
>      |                 |                   | 00 = bypass for OR output   |
>      |     29:28       |   SEL_BIT7_TYPE2  | 01 = bypass for AND output  |
>      |                 |                   | 10 = sense input '0' is true|
>      |                 |                   | 11 = sense input '1' is true|
>      |-------------------------------------------------------------------|
>      |                 |                   | 00 = bypass for OR output   |
>      |     25:24       |   SEL_BIT6_TYPE2  | 01 = bypass for AND output  |
>      |                 |                   | 10 = sense input '0' is true|
>      |                 |                   | 11 = sense input '1' is true|
>      |-------------------------------------------------------------------|
>      |                 |                   | 00 = bypass for OR output   |
>      |     21:20       |   SEL_BIT5_TYPE2  | 01 = bypass for AND output  |
>      |                 |                   | 10 = sense input '0' is true|
>      |                 |                   | 11 = sense input '1' is true|
>      |-------------------------------------------------------------------|
>      |                 |                   | 00 = bypass for OR output   |
>      |     17:16       |   SEL_BIT4_TYPE2  | 01 = bypass for AND output  |
>      |                 |                   | 10 = sense input '0' is true|
>      |                 |                   | 11 = sense input '1' is true|
>      |-------------------------------------------------------------------|
>      |                 |                   | 00 = bypass for OR output   |
>      |     13:12       |   SEL_BIT3_TYPE2  | 01 = bypass for AND output  |
>      |                 |                   | 10 = sense input '0' is true|
>      |                 |                   | 11 = sense input '1' is true|
>      |-------------------------------------------------------------------|
>      |                 |                   | 00 = bypass for OR output   |
>      |      9:8        |   SEL_BIT2_TYPE2  | 01 = bypass for AND output  |
>      |                 |                   | 10 = sense input '0' is true|
>      |                 |                   | 11 = sense input '1' is true|
>      |-------------------------------------------------------------------|
>      |                 |                   | 00 = bypass for OR output   |
>      |      5:4        |  SEL_BIT1_TYPE2   | 01 = bypass for AND output  |
>      |                 |                   | 10 = sense input '0' is true|
>      |                 |                   | 11 = sense input '1' is true|
>      |-------------------------------------------------------------------|
>      |                 |                   | 00 = bypass for OR output   |
>      |      1:0        |  SEL_BIT0_TYPE2   | 01 = bypass for AND output  |
>      |                 |                   | 10 = sense input '0' is true|
>      |                 |                   | 11 = sense input '1' is true|
>      |-------------------------------------------------------------------|
>      These bits are used to identify the signals we want to sense, with
>      a maximum signal number of 140. For example, to sense the signal
>      0xA (binary 1010), we set the value of bits 0 to 13 to 3232, which
>      represents 1010. The remaining bits are set to 1, as we want to use
>      AND gate to summarize all the signals we want to sense here. For
>      rising or falling edge detection of any input to the priority, set
>      the remaining bits to 0 to use an OR gate.
> 
>      3. look for the pattern for priority_i i=0,1.
>      - echo 0x3 > /sys/bus/coresight/devices/<tgu-name>/step0_condition_decode/reg0
>      - echo 0x30 > /sys/bus/coresight/devices/<tgu-name>/step0_condition_decode/reg1
> 
>      |-------------------------------------------------------------------------------|
>      |   Bits          |    Field Nam        |            Description                |
>      |-------------------------------------------------------------------------------|
>      |                 |                     |For each decoded condition, this       |
>      |      24         |       NOT           |inverts the output. If the condition   |
>      |                 |                     |decodes to true, and the NOT field     |
>      |                 |                     |is '1', then the output is NOT true.   |
>      |-------------------------------------------------------------------------------|
>      |                 |                     |When '1' the output from the associated|
>      |      21         |  BC0_COMP_ACTIVE    |comparator will be actively included in|
>      |                 |                     |the decoding of this particular        |
>      |                 |                     |condition.                             |
>      |-------------------------------------------------------------------------------|
>      |                 |                     |When '1' the output from the associated|
>      |                 |                     |comparator will need to be 1 to affect |
>      |      20         |   BC0_COMP_HIGH     |the decoding of this condition.        |
>      |                 |                     |Conversely, a '0' here requires a '0'  |
>      |                 |                     |from the comparator                    |
>      |-------------------------------------------------------------------------------|
>      |                 |                     |When '1' the output from the associated|
>      |      17         |                     |comparator will be actively included in|
>      |                 |  TC0_COMP_ACTIVE    |the decoding of this particular        |
>      |                 |                     |condition.                             |
>      |-------------------------------------------------------------------------------|
>      |                 |                     |When '1' the output from the associated|
>      |                 |                     |comparator will need to be 1 to affect |
>      |      16         |  TC0_COMP_HIGH      |the decoding of this particular        |
>      |                 |                     |condition.Conversely, a 0 here         |
>      |                 |                     |requires a '0' from the comparator     |
>      |-------------------------------------------------------------------------------|
>      |                 |                     |When '1' the output from Priority_n    |
>      |                 |                     |OR logic will be actively              |
>      |     4n+3        | Priority_n_OR_ACTIVE|included in the decoding of            |
>      |                 |    (n=0,1,2,3)      |this particular condition.             |
>      |                 |                     |                                       |
>      |-------------------------------------------------------------------------------|
>      |                 |                     |When '1' the output from Priority_n    |
>      |                 |                     |will need to be '1' to affect the      |
>      |     4n+2        |  Priority_n_OR_HIGH |decoding of this particular            |
>      |                 |    (n=0,1,2,3)      |condition. Conversely, a '0' here      |
>      |                 |                     |requires a '0' from Priority_n OR logic|
>      |-------------------------------------------------------------------------------|
>      |                 |                     |When '1' the output from Priority_n    |
>      |                 |                     |AND logic will be actively             |
>      |     4n+1        |Priority_n_AND_ACTIVE|included in the decoding of this       |
>      |                 |  (n=0,1,2,3)        |particular condition.                  |
>      |                 |                     |                                       |
>      |-------------------------------------------------------------------------------|
>      |                 |                     |When '1' the output from Priority_n    |
>      |                 |                     |AND logic will need to be '1' to       |
>      |      4n         | Priority_n_AND_HIGH |affect the decoding of this            |
>      |                 |   (n=0,1,2,3)       |particular condition. Conversely,      |
>      |                 |                     |a '0' here requires a '0' from         |
>      |                 |                     |Priority_n AND logic.                  |
>      |-------------------------------------------------------------------------------|
>      Since we use `priority_0` and `priority_1` with an AND output in step 2, we set `0x3`
>      and `0x30` here to activate them.
> 
>      4. Set NEXT_STEP = 1 and TC0_ENABLE = 1 so that when the conditions
>         are met then the next step will be step 1 and the timer will be enabled.
>      - echo 0x20008 > /sys/bus/coresight/devices/<tgu-name>/step0_condition_select/reg0
>      - echo 0x20008 > /sys/bus/coresight/devices/<tgu-name>/step0_condition_select/reg1
> 
>      |-----------------------------------------------------------------------------|
>      |   Bits          |       Field Nam   |            Description                |
>      |-----------------------------------------------------------------------------|
>      |                 |                   |This field defines the next step the   |
>      |    18:17        |     NEXT_STEP     |TGU will 'goto' for the associated     |
>      |                 |                   |Condition and Step.                    |
>      |-----------------------------------------------------------------------------|
>      |                 |                   |For each possible output trigger       |
>      |    13           |     TRIGGER       |available, set a '1' if you want       |
>      |                 |                   |the trigger to go active for the       |
>      |                 |                   |associated condition and Step.         |
>      |-----------------------------------------------------------------------------|
>      |                 |                   |This will cause BC0 to increment if the|
>      |    9            |     BC0_INC       |associated Condition is decoded for    |
>      |                 |                   |this step.                             |
>      |-----------------------------------------------------------------------------|
>      |                 |                   |This will cause BC0 to decrement if the|
>      |    8            |     BC0_DEC       |associated Condition is decoded for    |
>      |                 |                   |this step.                             |
>      |-----------------------------------------------------------------------------|
>      |                 |                   |This will clear BC0 count value to 0 if|
>      |    7            |     BC0_CLEAR     |the associated Condition is decoded    |
>      |                 |                   |for this step.                         |
>      |-----------------------------------------------------------------------------|
>      |                 |                   |This will cause TC0 to increment until |
>      |    3            |     TC0_ENABLE    |paused or cleared if the associated    |
>      |                 |                   |Condition is decoded for this step.    |
>      |-----------------------------------------------------------------------------|
>      |                 |                   |This will cause TC0 to pause until     |
>      |    2            |     TC0_PAUSE     |enabled if the associated Condition    |
>      |                 |                   |is decoded for this step.              |
>      |-----------------------------------------------------------------------------|
>      |                 |                   |This will clear TC0 count value to 0   |
>      |    1            |     TC0_CLEAR     |if the associated Condition is         |
>      |                 |                   |decoded for this step.                 |
>      |-----------------------------------------------------------------------------|
>      |                 |                   |This will set the done signal to the   |
>      |    0            |     DONE          |TGU FSM if the associated Condition    |
>      |                 |                   |is decoded for this step.              |
>      |-----------------------------------------------------------------------------|
>      Based on the distribution diagram, we set `0x20008` for `priority0` and `priority1` to
>      achieve "jump to step 1 and enable TC0" once the signal is sensed.
> 
>      5. activate the timer comparison for this step.
>      -  echo 0x30000  > /sys/bus/coresight/devices/<tgu-name>/step1_condition_decode/reg0
> 
>      |-------------------------------------------------------------------------------|
>      |                 |                     |When '1' the output from the associated|
>      |      17         |                     |comparator will be actively included in|
>      |                 |  TC0_COMP_ACTIVE    |the decoding of this particular        |
>      |                 |                     |condition.                             |
>      |-------------------------------------------------------------------------------|
>      |                 |                     |When '1' the output from the associated|
>      |                 |                     |comparator will need to be 1 to affect |
>      |      16         |  TC0_COMP_HIGH      |the decoding of this particular        |
>      |                 |                     |condition.Conversely, a 0 here         |
>      |                 |                     |requires a '0' from the comparator     |
>      |-------------------------------------------------------------------------------|
>      Accroding to the decode distribution diagram , we give 0x30000 here to set 16th&17th bit
>      to enable timer comparison.
> 
>      6. Set the NEXT_STEP = 0 and TC0_PAUSE = 1 and TC0_CLEAR = 1 once the timer
>         has reached the given value.
>      - echo 0x6 > /sys/bus/coresight/devices/<tgu-name>/step1_condition_select/reg0
> 
>      7. Enable Trigger 0 for TGU when the condition 0 is met in step1,
>         i.e. when the timer reaches 3.
>      - echo 0x2000 > /sys/bus/coresight/devices/<tgu-name>/step1_condition_select/default
> 
>      Note:
>          1. 'default' register allows for establishing the resultant action for
>          the default condition
> 
>          2. Trigger:For each possible output trigger available from
>          the Design document, there are three triggers: interrupts, CTI,
>          and Cross-TGU mapping.All three triggers can occur, but
>          the choice of which trigger to use depends on the user's
>          needs.
> 
>      8. Compare the timer to 3 in step 1.
>      - echo 0x3 > /sys/bus/coresight/devices/<tgu-name>/step1_timer/reg0
> 
>      9. enale tgu
>      - echo 1 > /sys/bus/coresight/devices/<tgu-name>/enable_tgu
> ---
> Link to V7: https://lore.kernel.org/all/20251104064043.88972-1-songwei.chai at oss.qualcomm.com/
> 
> Changes in V8:
> - Add "select" section in bindings.
> - Update publish date in "sysfs-bus-coresight-devices-tgu".
> ---
> Link to V6: https://lore.kernel.org/all/20250709104114.22240-1-songchai at qti.qualcomm.com/
> 
> Changes in V7:
> - Move the TGU code location from 'drivers/hwtracing/coresight/' to 'drivers/hwtracing/qcom/'.
> - Rename the spinlock used in the code from 'spinlock' to 'lock'.
> - Perform the 'calculate_array_location' separately, instead of doing it within the function.
> - Update the sender email address.
> ---
> Link to V5: https://lore.kernel.org/all/20250529081949.26493-1-quic_songchai at quicinc.com/
> 
> Changes in V6:
> - Replace spinlock with guard(spinlock) in tgu_enable.
> - Remove redundant blank line.
> - Update publish date and contact member's name in "sysfs-bus-coresight-devices-tgu".
> ---
> Link to V4: https://patchwork.kernel.org/project/linux-arm-msm/cover/20250423101054.954066-1-quic_songchai at quicinc.com/
> 
> Changes in V5:
> - Update publish date and kernel_version in "sysfs-bus-coresight-devices-tgu"
> ---
> Link to V3: https://lore.kernel.org/all/20250227092640.2666894-1-quic_songchai at quicinc.com/
> 
> Changes in V4:
> - Add changlog in coverletter.
> - Correct 'year' in Copyright in patch1.
> - Correct port mechansim description in patch1.
> - Remove 'tgu-steps','tgu-regs','tgu-conditions','tgu-timer-counters' from dt-binding
> and set them through reading DEVID register as per Mike's suggestion.
> - Modify tgu_disable func to make it have single return point in patch2 as per
> Mike's suggestion.
> - Use sysfs_emit in enable_tgu_show func in ptach2.
> - Remove redundant judgement in enable_tgu_store in patch2.
> - Correct typo in description in patch3.
> - Set default ret as SYSFS_GROUP_INVISIBLE, and returnret at end in pacth3 as
> per Mike's suggestion.
> - Remove tgu_dataset_ro definition in patch3
> - Use #define constants with explanations of what they are rather than
> arbitrary magic numbers in patch3 and patch4.
> - Check -EINVAL before using 'calculate_array_location()' in array in patch4.
> - Add 'default' in 'tgu_dataset_show''s switch part in patch4.
> - Document the value needed to initiate the reset in pacth7.
> - Check "value" in 'reset_tgu_store' and bail out with an error code if 0 in patch7.
> - Remove dev_dbg in 'reset_tgu_store' in patch7.
> ---
> Link to V2: https://lore.kernel.org/all/20241010073917.16023-1-quic_songchai at quicinc.com/
> 
> Changes in V3:
> - Correct typo and format in dt-binding in patch1
> - Rebase to the latest kernel version
> ---
> Link to V1: https://lore.kernel.org/all/20240830092311.14400-1-quic_songchai at quicinc.com/
> 
> Changes in V2:
>   - Use real name instead of login name,
>   - Correct typo and format in dt-binding and code.
>   - Bring order in tgu_prob(declarations with and without assignments) as per
> Krzysztof's suggestion.
>   - Add module device table in patch2.
>   - Set const for tgu_common_grp and tgu_ids in patch2.
>   - Initialize 'data' in tgu_ids to fix the warning in pacth2.
> ---
> 
> Songwei Chai (7):
>    dt-bindings: arm: Add support for Qualcomm TGU trace
>    qcom-tgu: Add TGU driver
>    qcom-tgu: Add signal priority support
>    qcom-tgu: Add TGU decode support
>    qcom-tgu: Add support to configure next action
>    qcom-tgu: Add timer/counter functionality for TGU
>    qcom-tgu: Add reset node to initialize
> 
>   .../testing/sysfs-bus-coresight-devices-tgu   |  51 ++
>   .../devicetree/bindings/arm/qcom,tgu.yaml     |  92 +++
>   drivers/Makefile                              |   1 +
>   drivers/hwtracing/Kconfig                     |   2 +
>   drivers/hwtracing/qcom/Kconfig                |  18 +
>   drivers/hwtracing/qcom/Makefile               |   3 +
>   drivers/hwtracing/qcom/tgu.c                  | 737 ++++++++++++++++++
>   drivers/hwtracing/qcom/tgu.h                  | 252 ++++++
>   8 files changed, 1156 insertions(+)
>   create mode 100644 Documentation/ABI/testing/sysfs-bus-coresight-devices-tgu
>   create mode 100644 Documentation/devicetree/bindings/arm/qcom,tgu.yaml
>   create mode 100644 drivers/hwtracing/qcom/Kconfig
>   create mode 100644 drivers/hwtracing/qcom/Makefile
>   create mode 100644 drivers/hwtracing/qcom/tgu.c
>   create mode 100644 drivers/hwtracing/qcom/tgu.h
> 



From robin.murphy at arm.com  Wed Dec  3 07:49:31 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Wed, 3 Dec 2025 15:49:31 +0000
Subject: [PATCH V3 1/3] iommu/arm-smmu-v3: Add device-tree support for
 CMDQV driver
In-Reply-To: <47684b91-7c0f-4260-abfd-2795fdaa2b31@nvidia.com>
References: <20251201163219.3237266-2-amhetre@nvidia.com>
 <202512031601.IpliwbHW-lkp@intel.com>
 <47684b91-7c0f-4260-abfd-2795fdaa2b31@nvidia.com>
Message-ID: <a917aded-4404-4b63-8d2c-96aa8b84f81f@arm.com>

On 2025-12-03 11:04 am, Ashish Mhetre wrote:
> 
> On 12/3/2025 2:05 PM, kernel test robot wrote:
>> External email: Use caution opening links or attachments
>>
>>
>> Hi Ashish,
>>
>> kernel test robot noticed the following build errors:
>>
>> [auto build test ERROR on next-20251201]
>> [also build test ERROR on v6.18]
>> [cannot apply to robh/for-next linus/master v6.18 v6.18-rc7 v6.18-rc6]
>> [If your patch is applied to the wrong git tree, kindly drop us a note.
>> And when submitting patch, we suggest to use '--base' as documented in
>> https://git-scm.com/docs/git-format-patch#_base_tree_information]
>>
>> url:??? https://github.com/intel-lab-lkp/linux/commits/Ashish-Mhetre/ 
>> iommu-arm-smmu-v3-Add-device-tree-support-for-CMDQV- 
>> driver/20251202-003517
>> base:?? next-20251201
>> patch link:??? https://lore.kernel.org/r/20251201163219.3237266-2- 
>> amhetre%40nvidia.com
>> patch subject: [PATCH V3 1/3] iommu/arm-smmu-v3: Add device-tree 
>> support for CMDQV driver
>> config: arm64-allmodconfig (https://download.01.org/0day-ci/ 
>> archive/20251203/202512031601.IpliwbHW-lkp at intel.com/config)
>> compiler: clang version 19.1.7 (https://github.com/llvm/llvm-project 
>> cd708029e0b2869e80abe31ddb175f7c35361f90)
>> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/ 
>> archive/20251203/202512031601.IpliwbHW-lkp at intel.com/reproduce)
>>
>> If you fix the issue in a separate patch/commit (i.e. not just a new 
>> version of
>> the same patch/commit), kindly add following tags
>> | Reported-by: kernel test robot <lkp at intel.com>
>> | Closes: https://lore.kernel.org/oe-kbuild-all/202512031601.IpliwbHW- 
>> lkp at intel.com/
>>
>> All errors (new ones prefixed by >>):
>>
>>>> ld.lld: error: duplicate symbol: init_module
>> ??? >>> defined at arm-smmu-v3.c
>> ??? >>>??????????? drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.o: 
>> (init_module)
>> ??? >>> defined at tegra241-cmdqv.c
>> ??? >>>??????????? drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.o: 
>> (.init.text+0x4)
>> -- 
>>>> ld.lld: error: duplicate symbol: cleanup_module
>> ??? >>> defined at arm-smmu-v3.c
>> ??? >>>??????????? drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.o: 
>> (cleanup_module)
>> ??? >>> defined at tegra241-cmdqv.c
>> ??? >>>??????????? drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.o: 
>> (.exit.text+0x4)
> 
> Hi Nic, Robin,
> 
> How do you suggest fixing this? Is it fine to compile tegra241-cmdqv as 
> separate module
> and export tegra241_cmdqv_probe() to fix this warning?

As Jon just pointed out, the issue is using module_platform_driver(), 
which is unnecessary anyway since this is not a driver; nor is it even a 
module, it's just some extra code that can be included in the 
arm_smmu_v3 driver, and will be integral to the arm_smmu_v3.ko module if 
built as a such.

You could sanity-check the compatible of the phandle target in 
tegra_cmdqv_dt_probe() if you feel like you should do more than just 
blindly trust the DT, but either way trying to register a dummy platform 
driver that won't bind to anything is pointless.

> I am using GCC compiler and was not able to reproduce this with W=1 build.

This will be happening with CONFIG_ARM_SMMU_V3=m.

Thanks,
Robin.

> 
> Thanks,
> Ashish Mhetre
> 
>> -- 
>> 0-DAY CI Kernel Test Service
>> https://github.com/intel/lkp-tests/wiki



From sudeep.holla at arm.com  Wed Dec  3 07:51:56 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Wed, 3 Dec 2025 15:51:56 +0000
Subject: [PATCH v2] arm: fix uninitialized pointers with free attr
In-Reply-To: <20251203-aheev-uninitialized-free-attr-arm-v2-1-db52b2655ddf@gmail.com>
References: <20251203-aheev-uninitialized-free-attr-arm-v2-1-db52b2655ddf@gmail.com>
Message-ID: <20251203-angelic-enlightened-coyote-cde8ae@sudeepholla>

On Wed, Dec 03, 2025 at 08:52:34PM +0530, Ally Heev wrote:
> Uninitialized pointers with `__free` attribute can cause undefined
> behaviour as the memory assigned(randomly) to the pointer is freed
> automatically when the pointer goes out of scope
> 
> arm doesn't have any bugs related to this as of now, but
> it is better to initialize and assign pointers with `__free` attr
> in one statement to ensure proper scope-based cleanup
> 
> Reported-by: Dan Carpenter <dan.carpenter at linaro.org>
> Closes: https://lore.kernel.org/all/aPiG_F5EBQUjZqsl at stanley.mountain/
> Signed-off-by: Ally Heev <allyheev at gmail.com>
> Reviewed-by: Cristian Marussi <cristian.marussi at arm.com>
> ---
> Changes in v2:
> - added Reviewed-by trailer

Ideally, there is no need to repost the same patch with just trailers added.
Sorry for no response, I plan to queue this at -rc1 as fix, so please give
me some time to officially apply at -rc1. I have put this a branch, so I won't
miss this but may need to rebase and hence silence.

-- 
Regards,
Sudeep


From s.pueschel at pengutronix.de  Wed Dec  3 07:52:23 2025
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Wed, 03 Dec 2025 16:52:23 +0100
Subject: [PATCH v2 01/22] media: dt-bindings: media: rockchip-rga: add
 rockchip,rk3588-rga3
In-Reply-To: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
Message-ID: <20251203-spu-rga3-v2-1-989a67947f71@pengutronix.de>

Add a new compatible for the RGA3 (Raster Graphic Acceleration 3)
peripheral found on the RK3588 SoC.

The existing rga node refers to the RGA2 peripheral. The RK3588
contains one RGA2 core and two RGA3 cores. Both feature a similar
functionality of scaling, cropping and rotating of up to two input
images into one output image. Key differences of the RGA3 are:

- supports 10bit YUV output formats
- supports 8x8 tiles and FBCD as inputs and outputs
- supports BT2020 color space conversion
- max output resolution of (8192-64)x(8192-64)
- MMU can map up to 32G DDR RAM
- fully planar formats (3 planes) are not supported
- max scale up/down factor of 8

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 Documentation/devicetree/bindings/media/rockchip-rga.yaml | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/media/rockchip-rga.yaml b/Documentation/devicetree/bindings/media/rockchip-rga.yaml
index ac17cda65191b..4d11ca313749f 100644
--- a/Documentation/devicetree/bindings/media/rockchip-rga.yaml
+++ b/Documentation/devicetree/bindings/media/rockchip-rga.yaml
@@ -9,7 +9,9 @@ title: Rockchip 2D raster graphic acceleration controller (RGA)
 description:
   RGA is a standalone 2D raster graphic acceleration unit. It accelerates 2D
   graphics operations, such as point/line drawing, image scaling, rotation,
-  BitBLT, alpha blending and image blur/sharpness.
+  BitBLT, alpha blending and image blur/sharpness. There exist two variants
+  named RGA2 and RGA3 that differ in the supported inputs/output formats,
+  the attached IOMMU and the supported operations on the input.
 
 maintainers:
   - Jacob Chen <jacob-chen at iotwrt.com>
@@ -20,6 +22,7 @@ properties:
     oneOf:
       - const: rockchip,rk3288-rga
       - const: rockchip,rk3399-rga
+      - const: rockchip,rk3588-rga3
       - items:
           - enum:
               - rockchip,rk3228-rga

-- 
2.52.0



From s.pueschel at pengutronix.de  Wed Dec  3 07:52:25 2025
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Wed, 03 Dec 2025 16:52:25 +0100
Subject: [PATCH v2 03/22] media: v4l2-common: add
 v4l2_fill_pixfmt_mp_aligned helper
In-Reply-To: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
Message-ID: <20251203-spu-rga3-v2-3-989a67947f71@pengutronix.de>

Add a v4l2_fill_pixfmt_mp_aligned helper which allows the user to
specify a custom stride alignment in bytes. This is necessary for
hardware like the Rockchip RGA3, which requires the stride value to be
aligned to a 16 byte boundary.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/v4l2-core/v4l2-common.c | 34 ++++++++++++++++++++++++----------
 include/media/v4l2-common.h           |  4 ++++
 2 files changed, 28 insertions(+), 10 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index 2c7ac70c0f486..f86e7d7d29b8e 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -404,11 +404,12 @@ static inline unsigned int v4l2_format_block_height(const struct v4l2_format_inf
 }
 
 static inline unsigned int v4l2_format_plane_stride(const struct v4l2_format_info *info, int plane,
-						    unsigned int width)
+						    unsigned int width, u8 alignment)
 {
 	unsigned int hdiv = plane ? info->hdiv : 1;
 	unsigned int aligned_width =
 		ALIGN(width, v4l2_format_block_width(info, plane));
+	aligned_width = ALIGN(aligned_width, alignment);
 
 	return DIV_ROUND_UP(aligned_width, hdiv) *
 	       info->bpp[plane] / info->bpp_div[plane];
@@ -425,9 +426,10 @@ static inline unsigned int v4l2_format_plane_height(const struct v4l2_format_inf
 }
 
 static inline unsigned int v4l2_format_plane_size(const struct v4l2_format_info *info, int plane,
-						  unsigned int width, unsigned int height)
+						  unsigned int width, unsigned int height,
+						  u8 stride_alignment)
 {
-	return v4l2_format_plane_stride(info, plane, width) *
+	return v4l2_format_plane_stride(info, plane, width, stride_alignment) *
 	       v4l2_format_plane_height(info, plane, height);
 }
 
@@ -448,8 +450,9 @@ void v4l2_apply_frmsize_constraints(u32 *width, u32 *height,
 }
 EXPORT_SYMBOL_GPL(v4l2_apply_frmsize_constraints);
 
-int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
-			u32 pixelformat, u32 width, u32 height)
+int v4l2_fill_pixfmt_mp_aligned(struct v4l2_pix_format_mplane *pixfmt,
+				u32 pixelformat, u32 width, u32 height,
+				u8 stride_alignment)
 {
 	const struct v4l2_format_info *info;
 	struct v4l2_plane_pix_format *plane;
@@ -466,23 +469,34 @@ int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
 
 	if (info->mem_planes == 1) {
 		plane = &pixfmt->plane_fmt[0];
-		plane->bytesperline = v4l2_format_plane_stride(info, 0, width);
+		plane->bytesperline = v4l2_format_plane_stride(info, 0, width,
+							       stride_alignment);
 		plane->sizeimage = 0;
 
 		for (i = 0; i < info->comp_planes; i++)
 			plane->sizeimage +=
-				v4l2_format_plane_size(info, i, width, height);
+				v4l2_format_plane_size(info, i, width, height,
+						       stride_alignment);
 	} else {
 		for (i = 0; i < info->comp_planes; i++) {
 			plane = &pixfmt->plane_fmt[i];
 			plane->bytesperline =
-				v4l2_format_plane_stride(info, i, width);
+				v4l2_format_plane_stride(info, i, width,
+							 stride_alignment);
 			plane->sizeimage = plane->bytesperline *
 				v4l2_format_plane_height(info, i, height);
 		}
 	}
 	return 0;
 }
+EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt_mp_aligned);
+
+int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
+			u32 pixelformat, u32 width, u32 height)
+{
+	return v4l2_fill_pixfmt_mp_aligned(pixfmt, pixelformat,
+					   width, height, 1);
+}
 EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt_mp);
 
 int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat,
@@ -502,12 +516,12 @@ int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat,
 	pixfmt->width = width;
 	pixfmt->height = height;
 	pixfmt->pixelformat = pixelformat;
-	pixfmt->bytesperline = v4l2_format_plane_stride(info, 0, width);
+	pixfmt->bytesperline = v4l2_format_plane_stride(info, 0, width, 1);
 	pixfmt->sizeimage = 0;
 
 	for (i = 0; i < info->comp_planes; i++)
 		pixfmt->sizeimage +=
-			v4l2_format_plane_size(info, i, width, height);
+			v4l2_format_plane_size(info, i, width, height, 1);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt);
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index 401d8506c24b5..edd416178c333 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -558,6 +558,10 @@ int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat,
 		     u32 width, u32 height);
 int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, u32 pixelformat,
 			u32 width, u32 height);
+/* @stride_alignment is a power of 2 value in bytes */
+int v4l2_fill_pixfmt_mp_aligned(struct v4l2_pix_format_mplane *pixfmt,
+				u32 pixelformat, u32 width, u32 height,
+				u8 stride_alignment);
 
 /**
  * v4l2_get_link_freq - Get link rate from transmitter

-- 
2.52.0



From s.pueschel at pengutronix.de  Wed Dec  3 07:52:26 2025
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Wed, 03 Dec 2025 16:52:26 +0100
Subject: [PATCH v2 04/22] media: rockchip: rga: use clk_bulk api
In-Reply-To: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
Message-ID: <20251203-spu-rga3-v2-4-989a67947f71@pengutronix.de>

Use the clk_bulk API to avoid code duplication for each of the three
clocks.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga.c | 64 ++++---------------------------
 drivers/media/platform/rockchip/rga/rga.h |  5 +--
 2 files changed, 9 insertions(+), 60 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 43f6a8d993811..ef568b3758380 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -698,48 +698,10 @@ static const struct video_device rga_videodev = {
 	.device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING,
 };
 
-static int rga_enable_clocks(struct rockchip_rga *rga)
-{
-	int ret;
-
-	ret = clk_prepare_enable(rga->sclk);
-	if (ret) {
-		dev_err(rga->dev, "Cannot enable rga sclk: %d\n", ret);
-		return ret;
-	}
-
-	ret = clk_prepare_enable(rga->aclk);
-	if (ret) {
-		dev_err(rga->dev, "Cannot enable rga aclk: %d\n", ret);
-		goto err_disable_sclk;
-	}
-
-	ret = clk_prepare_enable(rga->hclk);
-	if (ret) {
-		dev_err(rga->dev, "Cannot enable rga hclk: %d\n", ret);
-		goto err_disable_aclk;
-	}
-
-	return 0;
-
-err_disable_aclk:
-	clk_disable_unprepare(rga->aclk);
-err_disable_sclk:
-	clk_disable_unprepare(rga->sclk);
-
-	return ret;
-}
-
-static void rga_disable_clocks(struct rockchip_rga *rga)
-{
-	clk_disable_unprepare(rga->sclk);
-	clk_disable_unprepare(rga->hclk);
-	clk_disable_unprepare(rga->aclk);
-}
-
 static int rga_parse_dt(struct rockchip_rga *rga)
 {
 	struct reset_control *core_rst, *axi_rst, *ahb_rst;
+	int ret;
 
 	core_rst = devm_reset_control_get(rga->dev, "core");
 	if (IS_ERR(core_rst)) {
@@ -771,22 +733,10 @@ static int rga_parse_dt(struct rockchip_rga *rga)
 	udelay(1);
 	reset_control_deassert(ahb_rst);
 
-	rga->sclk = devm_clk_get(rga->dev, "sclk");
-	if (IS_ERR(rga->sclk)) {
-		dev_err(rga->dev, "failed to get sclk clock\n");
-		return PTR_ERR(rga->sclk);
-	}
-
-	rga->aclk = devm_clk_get(rga->dev, "aclk");
-	if (IS_ERR(rga->aclk)) {
-		dev_err(rga->dev, "failed to get aclk clock\n");
-		return PTR_ERR(rga->aclk);
-	}
-
-	rga->hclk = devm_clk_get(rga->dev, "hclk");
-	if (IS_ERR(rga->hclk)) {
-		dev_err(rga->dev, "failed to get hclk clock\n");
-		return PTR_ERR(rga->hclk);
+	ret = devm_clk_bulk_get(rga->dev, ARRAY_SIZE(rga->clks), rga->clks);
+	if (ret) {
+		dev_err(rga->dev, "failed to get clocks\n");
+		return ret;
 	}
 
 	return 0;
@@ -935,7 +885,7 @@ static int __maybe_unused rga_runtime_suspend(struct device *dev)
 {
 	struct rockchip_rga *rga = dev_get_drvdata(dev);
 
-	rga_disable_clocks(rga);
+	clk_bulk_disable_unprepare(ARRAY_SIZE(rga->clks), rga->clks);
 
 	return 0;
 }
@@ -944,7 +894,7 @@ static int __maybe_unused rga_runtime_resume(struct device *dev)
 {
 	struct rockchip_rga *rga = dev_get_drvdata(dev);
 
-	return rga_enable_clocks(rga);
+	return clk_bulk_prepare_enable(ARRAY_SIZE(rga->clks), rga->clks);
 }
 
 static const struct dev_pm_ops rga_pm = {
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index 72a28b120fabf..a922fac0c01a3 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -6,6 +6,7 @@
 #ifndef __RGA_H__
 #define __RGA_H__
 
+#include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <media/videobuf2-v4l2.h>
 #include <media/v4l2-ctrls.h>
@@ -81,9 +82,7 @@ struct rockchip_rga {
 	struct device *dev;
 	struct regmap *grf;
 	void __iomem *regs;
-	struct clk *sclk;
-	struct clk *aclk;
-	struct clk *hclk;
+	struct clk_bulk_data clks[3];
 	struct rockchip_rga_version version;
 
 	/* vfd lock */

-- 
2.52.0



From s.pueschel at pengutronix.de  Wed Dec  3 07:52:22 2025
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Wed, 03 Dec 2025 16:52:22 +0100
Subject: [PATCH v2 00/22] media: platform: rga: Add RGA3 support
Message-ID: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>

This series adds support for the Raster Graphic Acceleration 3 (RGA3)
peripheral, which is included in the RK3588 SoC. The RK3588
contains one RGA2 core (which is already implemented by the rockchip rga
driver) and two independent RGA3 cores. RGA2 and RGA3 feature
a similar functionality of scaling, cropping and rotating of up to two input
images into one output image. Key differences of the RGA3 are:

- supports 10bit YUV output formats
- supports 8x8 tiles and FBCD as inputs and outputs
- supports BT2020 color space conversion
- max output resolution of (8192-64)x(8192-64)
- MMU can map up to 32G DDR RAM
- fully planar formats (3 planes) are not supported
- max scale up/down factor of 8

This patch set adds support for one RGA3 core in the existing
rga m2m driver. The feature set of the PR is limited to scaling and
format conversions between common 8bit RGB/YUV formats.
Also the color space conversion is fixed to BT601F.
This already allows a practical usage of the RGA3.

This was tested on a Radxa Rock 5T. Around 80 fps were measured when
scaling and converting from RGBA 480x360 to NV12 3840x2160 in a single
gstreamer pipeline. Format conversions were tested with a single
gstreamer pipeline converting a fixed input to a given input format.
Afterwards it's piped through the RGA3 and the result is converted back
to rgba and compared against a given hash value (generated after
comparing the output manually to the input).

The v4l2-compliance tests still complain about
the failing colorspace propagation for the RGA2.
For the RGA3 they complain about the ycbcr_enc
not being adopted with S_FMT, which is by design,
as the RGA3 currently has the BT601 full range
transfer hard coded:

  v4l2-compliance 1.28.1, 64 bits, 64-bit time_t
  ...
  	Card type        : rga2
  ...
  		fail: v4l2-test-formats.cpp(923): fmt_cap.g_colorspace() != col
  	test VIDIOC_S_FMT: FAIL
  ...
  Total for rockchip-rga device /dev/video0: 47, Succeeded: 46, Failed: 1, Warnings: 0
  
  v4l2-compliance 1.28.1, 64 bits, 64-bit time_t
  ...
  	Card type        : rga3
  ...
  		fail: v4l2-test-formats.cpp(920): fmt_out.g_ycbcr_enc() != ycbcr_enc
  	test VIDIOC_S_FMT: FAIL
  ...
  Total for rockchip-rga device /dev/video1: 47, Succeeded: 46, Failed: 1, Warnings: 0

To distinguish the RGA2 core from the RGA3 cores the Card type is set
accordingly. Scheduling operations between both RGA3 cores to double
the possible frame rate might be a future improvement. Until then
additional RGA3 cores are disabled to only provide one video device to
the user space. This prevents a potential ABI breakage when multi core
support is implemented.

The DTS change at the end is just as a preview, as this series targets
media/next. After it's merged the DTS change will be sent as a new
patch not targeting media.

Patch 1 documments the RGA3 compatible value
Patch 2-3 extend v4l2 common functionality
Patch 4-6 are general cleanups
Patch 7-20 prepare the rga driver for the RGA3
Patch 21 adds RGA3 support to the rga driver
Patch 22 dtsi additions for the RGA3

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
Changes in v2:
- Removed overclocking (assigning higher clock speeds in the dts)
- Disable the second RGA3 core
- Improved RGA3 feature documentation and code comments
- Don't write the whole command buffer in each frame
- Don't announce CIDs for the RGA3 and error out on s_selection
- Check the max scaling factor of 16 (RGA2) and 8 (RGA3)
- Move stride alignment and alpha checking to v4l2 common
- Register the interrupt as shared for an external IOMMU
- Add IOMMU patch as dependency to fix sporadic hangups
- Link to v1: https://lore.kernel.org/r/20251007-spu-rga3-v1-0-36ad85570402 at pengutronix.de

---
Michael Olbrich (1):
      media: rockchip: rga: share the interrupt when an external iommu is used

Sven P?schel (21):
      media: dt-bindings: media: rockchip-rga: add rockchip,rk3588-rga3
      media: v4l2-common: add has_alpha to v4l2_format_info
      media: v4l2-common: add v4l2_fill_pixfmt_mp_aligned helper
      media: rockchip: rga: use clk_bulk api
      media: rockchip: rga: use stride for offset calculation
      media: rockchip: rga: remove redundant rga_frame variables
      media: rockchip: rga: move hw specific parts to a dedicated struct
      media: rockchip: rga: move cmdbuf to rga_ctx
      media: rockchip: rga: align stride to 4 bytes
      media: rockchip: rga: prepare cmdbuf on streamon
      media: rockchip: rga: check scaling factor
      media: rockchip: rga: use card type to specify rga type
      media: rockchip: rga: change offset to dma_addresses
      media: rockchip: rga: support external iommus
      media: rockchip: rga: remove size from rga_frame
      media: rockchip: rga: remove stride from rga_frame
      media: rockchip: rga: move rga_fmt to rga-hw.h
      media: rockchip: rga: add feature flags
      media: rockchip: rga: disable multi-core support
      media: rockchip: rga: add rga3 support
      arm64: dts: rockchip: add rga3 dt nodes

 .../devicetree/bindings/media/rockchip-rga.yaml    |   5 +-
 arch/arm64/boot/dts/rockchip/rk3588-base.dtsi      |  46 ++
 drivers/media/platform/rockchip/rga/Makefile       |   2 +-
 drivers/media/platform/rockchip/rga/rga-buf.c      |  78 ++--
 drivers/media/platform/rockchip/rga/rga-hw.c       | 404 ++++++++++++----
 drivers/media/platform/rockchip/rga/rga-hw.h       |  18 +-
 drivers/media/platform/rockchip/rga/rga.c          | 518 ++++++++-------------
 drivers/media/platform/rockchip/rga/rga.h          |  82 ++--
 drivers/media/platform/rockchip/rga/rga3-hw.c      | 471 +++++++++++++++++++
 drivers/media/platform/rockchip/rga/rga3-hw.h      | 190 ++++++++
 drivers/media/v4l2-core/v4l2-common.c              |  48 +-
 include/media/v4l2-common.h                        |   6 +
 12 files changed, 1375 insertions(+), 493 deletions(-)
---
base-commit: 1f2353f5a1af995efbf7bea44341aa0d03460b28
change-id: 20251001-spu-rga3-8a00e018b120
prerequisite-change-id: 20251126-spu-iommudtefix-cd0c5244c74a:v1
prerequisite-patch-id: 10c6c977c0f71400931941b42da73adcaf63e810

Best regards,
-- 
Sven P?schel <s.pueschel at pengutronix.de>



From s.pueschel at pengutronix.de  Wed Dec  3 07:52:27 2025
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Wed, 03 Dec 2025 16:52:27 +0100
Subject: [PATCH v2 05/22] media: rockchip: rga: use stride for offset
 calculation
In-Reply-To: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
Message-ID: <20251203-spu-rga3-v2-5-989a67947f71@pengutronix.de>

Use the stride instead of the width for the offset calculation. This
ensures that the bytesperline value doesn't need to match the width
value of the image.

Furthermore this patch removes the dependency on the uv_factor property
and instead reuses the v4l2_format_info to determine the correct
division factor.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-buf.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
index 730bdf98565a5..b5e6b1b527ca8 100644
--- a/drivers/media/platform/rockchip/rga/rga-buf.c
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -14,7 +14,6 @@
 #include <media/videobuf2-dma-sg.h>
 #include <media/videobuf2-v4l2.h>
 
-#include "rga-hw.h"
 #include "rga.h"
 
 static ssize_t fill_descriptors(struct rga_dma_desc *desc, size_t max_desc,
@@ -92,14 +91,19 @@ static int rga_buf_init(struct vb2_buffer *vb)
 	return 0;
 }
 
-static int get_plane_offset(struct rga_frame *f, int plane)
+static int get_plane_offset(struct rga_frame *f,
+			    const struct v4l2_format_info *info,
+			    int plane)
 {
+	u32 stride = f->pix.plane_fmt[0].bytesperline;
+
 	if (plane == 0)
 		return 0;
 	if (plane == 1)
-		return f->width * f->height;
+		return stride * f->height;
 	if (plane == 2)
-		return f->width * f->height + (f->width * f->height / f->fmt->uv_factor);
+		return stride * f->height +
+		       (stride * f->height / info->hdiv / info->vdiv);
 
 	return -EINVAL;
 }
@@ -145,7 +149,7 @@ static int rga_buf_prepare(struct vb2_buffer *vb)
 	/* Fill the remaining planes */
 	info = v4l2_format_info(f->fmt->fourcc);
 	for (i = info->mem_planes; i < info->comp_planes; i++)
-		offsets[i] = get_plane_offset(f, i);
+		offsets[i] = get_plane_offset(f, info, i);
 
 	rbuf->offset.y_off = offsets[0];
 	rbuf->offset.u_off = offsets[1];

-- 
2.52.0



From s.pueschel at pengutronix.de  Wed Dec  3 07:52:24 2025
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Wed, 03 Dec 2025 16:52:24 +0100
Subject: [PATCH v2 02/22] media: v4l2-common: add has_alpha to
 v4l2_format_info
In-Reply-To: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
Message-ID: <20251203-spu-rga3-v2-2-989a67947f71@pengutronix.de>

Add a has_alpha value to the v4l2_format_info struct to indicate if the
format contains an alpha component. The implementation is based on the
drm_format_info implementation.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/v4l2-core/v4l2-common.c | 14 +++++++-------
 include/media/v4l2-common.h           |  2 ++
 2 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index 554c591e11133..2c7ac70c0f486 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -256,10 +256,10 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
 		{ .format = V4L2_PIX_FMT_XRGB32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
 		{ .format = V4L2_PIX_FMT_RGBX32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
 		{ .format = V4L2_PIX_FMT_HSV32,   .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
-		{ .format = V4L2_PIX_FMT_ARGB32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
-		{ .format = V4L2_PIX_FMT_RGBA32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
-		{ .format = V4L2_PIX_FMT_ABGR32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
-		{ .format = V4L2_PIX_FMT_BGRA32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+		{ .format = V4L2_PIX_FMT_ARGB32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
+		{ .format = V4L2_PIX_FMT_RGBA32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
+		{ .format = V4L2_PIX_FMT_ABGR32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
+		{ .format = V4L2_PIX_FMT_BGRA32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
 		{ .format = V4L2_PIX_FMT_RGB565,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
 		{ .format = V4L2_PIX_FMT_RGB565X, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
 		{ .format = V4L2_PIX_FMT_RGB555,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
@@ -267,10 +267,10 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
 		{ .format = V4L2_PIX_FMT_BGR48_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
 		{ .format = V4L2_PIX_FMT_BGR48, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
 		{ .format = V4L2_PIX_FMT_RGB48, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
-		{ .format = V4L2_PIX_FMT_ABGR64_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
-		{ .format = V4L2_PIX_FMT_RGBA1010102, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+		{ .format = V4L2_PIX_FMT_ABGR64_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
+		{ .format = V4L2_PIX_FMT_RGBA1010102, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
 		{ .format = V4L2_PIX_FMT_RGBX1010102, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
-		{ .format = V4L2_PIX_FMT_ARGB2101010, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+		{ .format = V4L2_PIX_FMT_ARGB2101010, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
 
 		/* YUV packed formats */
 		{ .format = V4L2_PIX_FMT_YUYV,    .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 },
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index f8b1faced79c8..401d8506c24b5 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -520,6 +520,7 @@ enum v4l2_pixel_encoding {
  * @vdiv: Vertical chroma subsampling factor
  * @block_w: Per-plane macroblock pixel width (optional)
  * @block_h: Per-plane macroblock pixel height (optional)
+ * @has_alpha: Does the format embeds an alpha component?
  */
 struct v4l2_format_info {
 	u32 format;
@@ -532,6 +533,7 @@ struct v4l2_format_info {
 	u8 vdiv;
 	u8 block_w[4];
 	u8 block_h[4];
+	bool has_alpha;
 };
 
 static inline bool v4l2_is_format_rgb(const struct v4l2_format_info *f)

-- 
2.52.0



From s.pueschel at pengutronix.de  Wed Dec  3 07:52:32 2025
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Wed, 03 Dec 2025 16:52:32 +0100
Subject: [PATCH v2 10/22] media: rockchip: rga: prepare cmdbuf on streamon
In-Reply-To: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
Message-ID: <20251203-spu-rga3-v2-10-989a67947f71@pengutronix.de>

Prepare the command buffer on streamon to reuse it's contents instead of
completely writing it for every frame. Due to the stream settings being
fixed after a streamon we only need to replace the source and destination
addresses for each frame. This reduces the amount of CPU and memory
operations done in each frame.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-hw.c | 13 +++++++++----
 drivers/media/platform/rockchip/rga/rga.c    | 13 ++++++++++++-
 drivers/media/platform/rockchip/rga/rga.h    |  1 +
 3 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index 56a2558539bfb..8cdfe089fd636 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -408,8 +408,6 @@ static void rga_cmd_set(struct rga_ctx *ctx,
 {
 	struct rockchip_rga *rga = ctx->rga;
 
-	memset(ctx->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);
-
 	rga_cmd_set_src_addr(ctx, src->dma_desc_pa);
 	/*
 	 * Due to hardware bug,
@@ -418,11 +416,9 @@ static void rga_cmd_set(struct rga_ctx *ctx,
 	rga_cmd_set_src1_addr(ctx, dst->dma_desc_pa);
 
 	rga_cmd_set_dst_addr(ctx, dst->dma_desc_pa);
-	rga_cmd_set_mode(ctx);
 
 	rga_cmd_set_src_info(ctx, &src->offset);
 	rga_cmd_set_dst_info(ctx, &dst->offset);
-	rga_cmd_set_trans_info(ctx);
 
 	rga_write(rga, RGA_CMD_BASE, ctx->cmdbuf_phy);
 
@@ -431,6 +427,14 @@ static void rga_cmd_set(struct rga_ctx *ctx,
 				   PAGE_SIZE, DMA_BIDIRECTIONAL);
 }
 
+static void rga_hw_setup_cmdbuf(struct rga_ctx *ctx)
+{
+	memset(ctx->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);
+
+	rga_cmd_set_mode(ctx);
+	rga_cmd_set_trans_info(ctx);
+}
+
 static void rga_hw_start(struct rockchip_rga *rga,
 			 struct rga_vb_buffer *src,  struct rga_vb_buffer *dst)
 {
@@ -622,6 +626,7 @@ const struct rga_hw rga2_hw = {
 	.max_height = MAX_HEIGHT,
 	.stride_alignment = 4,
 
+	.setup_cmdbuf = rga_hw_setup_cmdbuf,
 	.start = rga_hw_start,
 	.handle_irq = rga_handle_irq,
 	.get_version = rga_get_version,
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 592c977a07cf3..f02ae02de26ca 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -523,6 +523,17 @@ static int vidioc_s_selection(struct file *file, void *priv,
 	return ret;
 }
 
+static int vidioc_streamon(struct file *file, void *priv,
+			   enum v4l2_buf_type type)
+{
+	struct rga_ctx *ctx = file_to_rga_ctx(file);
+	const struct rga_hw *hw = ctx->rga->hw;
+
+	hw->setup_cmdbuf(ctx);
+
+	return v4l2_m2m_streamon(file, ctx->fh.m2m_ctx, type);
+}
+
 static const struct v4l2_ioctl_ops rga_ioctl_ops = {
 	.vidioc_querycap = vidioc_querycap,
 
@@ -547,7 +558,7 @@ static const struct v4l2_ioctl_ops rga_ioctl_ops = {
 	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
 	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 
-	.vidioc_streamon = v4l2_m2m_ioctl_streamon,
+	.vidioc_streamon = vidioc_streamon,
 	.vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
 
 	.vidioc_g_selection = vidioc_g_selection,
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index 0aef348dddb95..93162b118d069 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -154,6 +154,7 @@ struct rga_hw {
 	u32 max_width, max_height;
 	u8 stride_alignment;
 
+	void (*setup_cmdbuf)(struct rga_ctx *ctx);
 	void (*start)(struct rockchip_rga *rga,
 		      struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
 	bool (*handle_irq)(struct rockchip_rga *rga);

-- 
2.52.0



From s.pueschel at pengutronix.de  Wed Dec  3 07:52:31 2025
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Wed, 03 Dec 2025 16:52:31 +0100
Subject: [PATCH v2 09/22] media: rockchip: rga: align stride to 4 bytes
In-Reply-To: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
Message-ID: <20251203-spu-rga3-v2-9-989a67947f71@pengutronix.de>

Add an alignment setting to rga_hw to set the desired stride alignment.
As the RGA2 register for the stride counts in word units, the code
already divides the bytesperline value by 4 when writing it into the
register. Therefore fix the alignment to a multiple of 4 to avoid
potential off by one errors due from the division.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-hw.c |  1 +
 drivers/media/platform/rockchip/rga/rga.c    | 11 ++++++-----
 drivers/media/platform/rockchip/rga/rga.h    |  1 +
 3 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index 79bf911e74779..56a2558539bfb 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -620,6 +620,7 @@ const struct rga_hw rga2_hw = {
 	.max_width = MAX_WIDTH,
 	.min_height = MIN_HEIGHT,
 	.max_height = MAX_HEIGHT,
+	.stride_alignment = 4,
 
 	.start = rga_hw_start,
 	.handle_irq = rga_handle_irq,
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 74d94c7fe31ff..592c977a07cf3 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -234,10 +234,10 @@ static int rga_open(struct file *file)
 	ctx->in = def_frame;
 	ctx->out = def_frame;
 
-	v4l2_fill_pixfmt_mp(&ctx->in.pix,
-			    ctx->in.fmt->fourcc, def_width, def_height);
-	v4l2_fill_pixfmt_mp(&ctx->out.pix,
-			    ctx->out.fmt->fourcc, def_width, def_height);
+	v4l2_fill_pixfmt_mp_aligned(&ctx->in.pix, ctx->in.fmt->fourcc,
+				    def_width, def_height, rga->hw->stride_alignment);
+	v4l2_fill_pixfmt_mp_aligned(&ctx->out.pix, ctx->out.fmt->fourcc,
+				    def_width, def_height, rga->hw->stride_alignment);
 
 	if (mutex_lock_interruptible(&rga->mutex)) {
 		ret = -ERESTARTSYS;
@@ -359,7 +359,8 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	pix_fmt->height = clamp(pix_fmt->height,
 				hw->min_height, hw->max_height);
 
-	v4l2_fill_pixfmt_mp(pix_fmt, fmt->fourcc, pix_fmt->width, pix_fmt->height);
+	v4l2_fill_pixfmt_mp_aligned(pix_fmt, pix_fmt->pixelformat,
+				    pix_fmt->width, pix_fmt->height, hw->stride_alignment);
 	pix_fmt->field = V4L2_FIELD_NONE;
 
 	return 0;
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index f8c932fdec21a..0aef348dddb95 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -152,6 +152,7 @@ struct rga_hw {
 	size_t cmdbuf_size;
 	u32 min_width, min_height;
 	u32 max_width, max_height;
+	u8 stride_alignment;
 
 	void (*start)(struct rockchip_rga *rga,
 		      struct rga_vb_buffer *src, struct rga_vb_buffer *dst);

-- 
2.52.0



From s.pueschel at pengutronix.de  Wed Dec  3 07:52:28 2025
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Wed, 03 Dec 2025 16:52:28 +0100
Subject: [PATCH v2 06/22] media: rockchip: rga: remove redundant rga_frame
 variables
In-Reply-To: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
Message-ID: <20251203-spu-rga3-v2-6-989a67947f71@pengutronix.de>

Remove the redundant rga_frame variables width, height and color space.
The value of these variables is already contained in the pix member
of rga_frame. The code also keeps these values in sync. Therefore drop
them in favor of the existing pix member.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-buf.c |  6 ++---
 drivers/media/platform/rockchip/rga/rga-hw.c  |  6 ++---
 drivers/media/platform/rockchip/rga/rga.c     | 32 ++++++++++-----------------
 drivers/media/platform/rockchip/rga/rga.h     |  5 -----
 4 files changed, 18 insertions(+), 31 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
index b5e6b1b527ca8..0c59a4d330888 100644
--- a/drivers/media/platform/rockchip/rga/rga-buf.c
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -100,10 +100,10 @@ static int get_plane_offset(struct rga_frame *f,
 	if (plane == 0)
 		return 0;
 	if (plane == 1)
-		return stride * f->height;
+		return stride * f->pix.height;
 	if (plane == 2)
-		return stride * f->height +
-		       (stride * f->height / info->hdiv / info->vdiv);
+		return stride * f->pix.height +
+		       (stride * f->pix.height / info->hdiv / info->vdiv);
 
 	return -EINVAL;
 }
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index 43ed742a16492..f1d5237472941 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -53,7 +53,7 @@ rga_get_addr_offset(struct rga_frame *frm, struct rga_addr_offset *offset,
 	x_div = frm->fmt->x_div;
 	y_div = frm->fmt->y_div;
 	uv_stride = frm->stride / x_div;
-	pixel_width = frm->stride / frm->width;
+	pixel_width = frm->stride / frm->pix.width;
 
 	lt->y_off = offset->y_off + y * frm->stride + x * pixel_width;
 	lt->u_off = offset->u_off + (y / y_div) * uv_stride + x / x_div;
@@ -191,7 +191,7 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
 
 	if (RGA_COLOR_FMT_IS_YUV(ctx->in.fmt->hw_format) &&
 	    RGA_COLOR_FMT_IS_RGB(ctx->out.fmt->hw_format)) {
-		switch (ctx->in.colorspace) {
+		switch (ctx->in.pix.colorspace) {
 		case V4L2_COLORSPACE_REC709:
 			src_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
 			break;
@@ -203,7 +203,7 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
 
 	if (RGA_COLOR_FMT_IS_RGB(ctx->in.fmt->hw_format) &&
 	    RGA_COLOR_FMT_IS_YUV(ctx->out.fmt->hw_format)) {
-		switch (ctx->out.colorspace) {
+		switch (ctx->out.pix.colorspace) {
 		case V4L2_COLORSPACE_REC709:
 			dst_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
 			break;
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index ef568b3758380..f50fbbab0645e 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -345,9 +345,6 @@ static struct rga_fmt *rga_fmt_find(u32 pixelformat)
 }
 
 static struct rga_frame def_frame = {
-	.width = DEFAULT_WIDTH,
-	.height = DEFAULT_HEIGHT,
-	.colorspace = V4L2_COLORSPACE_DEFAULT,
 	.crop.left = 0,
 	.crop.top = 0,
 	.crop.width = DEFAULT_WIDTH,
@@ -379,9 +376,9 @@ static int rga_open(struct file *file)
 	ctx->out = def_frame;
 
 	v4l2_fill_pixfmt_mp(&ctx->in.pix,
-			    ctx->in.fmt->fourcc, ctx->out.width, ctx->out.height);
+			    ctx->in.fmt->fourcc, DEFAULT_WIDTH, DEFAULT_HEIGHT);
 	v4l2_fill_pixfmt_mp(&ctx->out.pix,
-			    ctx->out.fmt->fourcc, ctx->out.width, ctx->out.height);
+			    ctx->out.fmt->fourcc, DEFAULT_WIDTH, DEFAULT_HEIGHT);
 
 	if (mutex_lock_interruptible(&rga->mutex)) {
 		kfree(ctx);
@@ -469,10 +466,8 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	if (IS_ERR(frm))
 		return PTR_ERR(frm);
 
-	v4l2_fill_pixfmt_mp(pix_fmt, frm->fmt->fourcc, frm->width, frm->height);
-
+	*pix_fmt = frm->pix;
 	pix_fmt->field = V4L2_FIELD_NONE;
-	pix_fmt->colorspace = frm->colorspace;
 
 	return 0;
 }
@@ -521,27 +516,24 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	frm = rga_get_frame(ctx, f->type);
 	if (IS_ERR(frm))
 		return PTR_ERR(frm);
-	frm->width = pix_fmt->width;
-	frm->height = pix_fmt->height;
 	frm->size = 0;
 	for (i = 0; i < pix_fmt->num_planes; i++)
 		frm->size += pix_fmt->plane_fmt[i].sizeimage;
 	frm->fmt = rga_fmt_find(pix_fmt->pixelformat);
 	frm->stride = pix_fmt->plane_fmt[0].bytesperline;
-	frm->colorspace = pix_fmt->colorspace;
 
 	/* Reset crop settings */
 	frm->crop.left = 0;
 	frm->crop.top = 0;
-	frm->crop.width = frm->width;
-	frm->crop.height = frm->height;
+	frm->crop.width = pix_fmt->width;
+	frm->crop.height = pix_fmt->height;
 
 	frm->pix = *pix_fmt;
 
 	v4l2_dbg(debug, 1, &rga->v4l2_dev,
 		 "[%s] fmt - %p4cc %dx%d (stride %d, sizeimage %d)\n",
 		  V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
-		  &frm->fmt->fourcc, frm->width, frm->height,
+		  &frm->fmt->fourcc, pix_fmt->width, pix_fmt->height,
 		  frm->stride, frm->size);
 
 	for (i = 0; i < pix_fmt->num_planes; i++) {
@@ -595,8 +587,8 @@ static int vidioc_g_selection(struct file *file, void *priv,
 	} else {
 		s->r.left = 0;
 		s->r.top = 0;
-		s->r.width = f->width;
-		s->r.height = f->height;
+		s->r.width = f->pix.width;
+		s->r.height = f->pix.height;
 	}
 
 	return 0;
@@ -645,8 +637,8 @@ static int vidioc_s_selection(struct file *file, void *priv,
 		return -EINVAL;
 	}
 
-	if (s->r.left + s->r.width > f->width ||
-	    s->r.top + s->r.height > f->height ||
+	if (s->r.left + s->r.width > f->pix.width ||
+	    s->r.top + s->r.height > f->pix.height ||
 	    s->r.width < MIN_WIDTH || s->r.height < MIN_HEIGHT) {
 		v4l2_dbg(debug, 1, &rga->v4l2_dev, "unsupported crop value.\n");
 		return -EINVAL;
@@ -836,8 +828,8 @@ static int rga_probe(struct platform_device *pdev)
 		goto rel_m2m;
 	}
 
-	def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3;
-	def_frame.size = def_frame.stride * def_frame.height;
+	def_frame.stride = (DEFAULT_WIDTH * def_frame.fmt->depth) >> 3;
+	def_frame.size = def_frame.stride * DEFAULT_HEIGHT;
 
 	ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
 	if (ret) {
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index a922fac0c01a3..7ec1fcc03ed32 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -25,11 +25,6 @@ struct rga_fmt {
 };
 
 struct rga_frame {
-	/* Original dimensions */
-	u32 width;
-	u32 height;
-	u32 colorspace;
-
 	/* Crop */
 	struct v4l2_rect crop;
 

-- 
2.52.0



From s.pueschel at pengutronix.de  Wed Dec  3 07:52:30 2025
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Wed, 03 Dec 2025 16:52:30 +0100
Subject: [PATCH v2 08/22] media: rockchip: rga: move cmdbuf to rga_ctx
In-Reply-To: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
Message-ID: <20251203-spu-rga3-v2-8-989a67947f71@pengutronix.de>

Move the command buffer to the rga_ctx struct in preparation to reuse
an already prepared command buffer. Having a command buffer per context
allows to reuse the command buffer for other frames even when
multiple applications are using the RGA in at the same time.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-hw.c | 28 +++++++---------
 drivers/media/platform/rockchip/rga/rga.c    | 48 ++++++++++++++++------------
 drivers/media/platform/rockchip/rga/rga.h    |  5 +--
 3 files changed, 41 insertions(+), 40 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index 7419784efc693..79bf911e74779 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -113,8 +113,7 @@ static struct rga_addr_offset *rga_lookup_draw_pos(struct
 
 static void rga_cmd_set_src_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)
 {
-	struct rockchip_rga *rga = ctx->rga;
-	u32 *dest = rga->cmdbuf_virt;
+	u32 *dest = ctx->cmdbuf_virt;
 	unsigned int reg;
 
 	reg = RGA_MMU_SRC_BASE - RGA_MODE_BASE_REG;
@@ -126,8 +125,7 @@ static void rga_cmd_set_src_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)
 
 static void rga_cmd_set_src1_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)
 {
-	struct rockchip_rga *rga = ctx->rga;
-	u32 *dest = rga->cmdbuf_virt;
+	u32 *dest = ctx->cmdbuf_virt;
 	unsigned int reg;
 
 	reg = RGA_MMU_SRC1_BASE - RGA_MODE_BASE_REG;
@@ -139,8 +137,7 @@ static void rga_cmd_set_src1_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)
 
 static void rga_cmd_set_dst_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)
 {
-	struct rockchip_rga *rga = ctx->rga;
-	u32 *dest = rga->cmdbuf_virt;
+	u32 *dest = ctx->cmdbuf_virt;
 	unsigned int reg;
 
 	reg = RGA_MMU_DST_BASE - RGA_MODE_BASE_REG;
@@ -153,7 +150,7 @@ static void rga_cmd_set_dst_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)
 static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
 {
 	struct rockchip_rga *rga = ctx->rga;
-	u32 *dest = rga->cmdbuf_virt;
+	u32 *dest = ctx->cmdbuf_virt;
 	unsigned int scale_dst_w, scale_dst_h;
 	unsigned int src_h, src_w, dst_h, dst_w;
 	union rga_src_info src_info;
@@ -313,8 +310,7 @@ static void rga_cmd_set_src_info(struct rga_ctx *ctx,
 				 struct rga_addr_offset *offset)
 {
 	struct rga_corners_addr_offset src_offsets;
-	struct rockchip_rga *rga = ctx->rga;
-	u32 *dest = rga->cmdbuf_virt;
+	u32 *dest = ctx->cmdbuf_virt;
 	unsigned int src_h, src_w, src_x, src_y;
 
 	src_h = ctx->in.crop.height;
@@ -341,8 +337,7 @@ static void rga_cmd_set_dst_info(struct rga_ctx *ctx,
 {
 	struct rga_addr_offset *dst_offset;
 	struct rga_corners_addr_offset offsets;
-	struct rockchip_rga *rga = ctx->rga;
-	u32 *dest = rga->cmdbuf_virt;
+	u32 *dest = ctx->cmdbuf_virt;
 	unsigned int dst_h, dst_w, dst_x, dst_y;
 	unsigned int mir_mode = 0;
 	unsigned int rot_mode = 0;
@@ -388,8 +383,7 @@ static void rga_cmd_set_dst_info(struct rga_ctx *ctx,
 
 static void rga_cmd_set_mode(struct rga_ctx *ctx)
 {
-	struct rockchip_rga *rga = ctx->rga;
-	u32 *dest = rga->cmdbuf_virt;
+	u32 *dest = ctx->cmdbuf_virt;
 	union rga_mode_ctrl mode;
 	union rga_alpha_ctrl0 alpha_ctrl0;
 	union rga_alpha_ctrl1 alpha_ctrl1;
@@ -414,7 +408,7 @@ static void rga_cmd_set(struct rga_ctx *ctx,
 {
 	struct rockchip_rga *rga = ctx->rga;
 
-	memset(rga->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);
+	memset(ctx->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);
 
 	rga_cmd_set_src_addr(ctx, src->dma_desc_pa);
 	/*
@@ -430,11 +424,11 @@ static void rga_cmd_set(struct rga_ctx *ctx,
 	rga_cmd_set_dst_info(ctx, &dst->offset);
 	rga_cmd_set_trans_info(ctx);
 
-	rga_write(rga, RGA_CMD_BASE, rga->cmdbuf_phy);
+	rga_write(rga, RGA_CMD_BASE, ctx->cmdbuf_phy);
 
 	/* sync CMD buf for RGA */
-	dma_sync_single_for_device(rga->dev, rga->cmdbuf_phy,
-		PAGE_SIZE, DMA_BIDIRECTIONAL);
+	dma_sync_single_for_device(rga->dev, ctx->cmdbuf_phy,
+				   PAGE_SIZE, DMA_BIDIRECTIONAL);
 }
 
 static void rga_hw_start(struct rockchip_rga *rga,
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index d8b14c2d9f6a4..74d94c7fe31ff 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -219,6 +219,16 @@ static int rga_open(struct file *file)
 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
+
+	/* Create CMD buffer */
+	ctx->cmdbuf_virt = dma_alloc_attrs(rga->dev, rga->hw->cmdbuf_size,
+					   &ctx->cmdbuf_phy, GFP_KERNEL,
+					   DMA_ATTR_WRITE_COMBINE);
+	if (!ctx->cmdbuf_virt) {
+		ret = -ENOMEM;
+		goto rel_ctx;
+	}
+
 	ctx->rga = rga;
 	/* Set default formats */
 	ctx->in = def_frame;
@@ -230,15 +240,13 @@ static int rga_open(struct file *file)
 			    ctx->out.fmt->fourcc, def_width, def_height);
 
 	if (mutex_lock_interruptible(&rga->mutex)) {
-		kfree(ctx);
-		return -ERESTARTSYS;
+		ret = -ERESTARTSYS;
+		goto rel_cmdbuf;
 	}
 	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(rga->m2m_dev, ctx, &queue_init);
 	if (IS_ERR(ctx->fh.m2m_ctx)) {
 		ret = PTR_ERR(ctx->fh.m2m_ctx);
-		mutex_unlock(&rga->mutex);
-		kfree(ctx);
-		return ret;
+		goto unlock_mutex;
 	}
 	v4l2_fh_init(&ctx->fh, video_devdata(file));
 	v4l2_fh_add(&ctx->fh, file);
@@ -252,6 +260,15 @@ static int rga_open(struct file *file)
 	mutex_unlock(&rga->mutex);
 
 	return 0;
+
+unlock_mutex:
+	mutex_unlock(&rga->mutex);
+rel_cmdbuf:
+	dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, ctx->cmdbuf_virt,
+		       ctx->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
+rel_ctx:
+	kfree(ctx);
+	return ret;
 }
 
 static int rga_release(struct file *file)
@@ -266,6 +283,10 @@ static int rga_release(struct file *file)
 	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
 	v4l2_fh_del(&ctx->fh, file);
 	v4l2_fh_exit(&ctx->fh);
+
+	dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, ctx->cmdbuf_virt,
+		       ctx->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
+
 	kfree(ctx);
 
 	mutex_unlock(&rga->mutex);
@@ -674,19 +695,10 @@ static int rga_probe(struct platform_device *pdev)
 
 	pm_runtime_put(rga->dev);
 
-	/* Create CMD buffer */
-	rga->cmdbuf_virt = dma_alloc_attrs(rga->dev, rga->hw->cmdbuf_size,
-					   &rga->cmdbuf_phy, GFP_KERNEL,
-					   DMA_ATTR_WRITE_COMBINE);
-	if (!rga->cmdbuf_virt) {
-		ret = -ENOMEM;
-		goto rel_m2m;
-	}
-
 	ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
 	if (ret) {
 		v4l2_err(&rga->v4l2_dev, "Failed to register video device\n");
-		goto free_dma;
+		goto rel_m2m;
 	}
 
 	v4l2_info(&rga->v4l2_dev, "Registered %s as /dev/%s\n",
@@ -694,9 +706,6 @@ static int rga_probe(struct platform_device *pdev)
 
 	return 0;
 
-free_dma:
-	dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, rga->cmdbuf_virt,
-		       rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
 rel_m2m:
 	v4l2_m2m_release(rga->m2m_dev);
 rel_vdev:
@@ -713,9 +722,6 @@ static void rga_remove(struct platform_device *pdev)
 {
 	struct rockchip_rga *rga = platform_get_drvdata(pdev);
 
-	dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, rga->cmdbuf_virt,
-		       rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
-
 	v4l2_info(&rga->v4l2_dev, "Removing\n");
 
 	v4l2_m2m_release(rga->m2m_dev);
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index 98635ddd50d7c..f8c932fdec21a 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -56,6 +56,9 @@ struct rga_ctx {
 	struct rga_frame out;
 	struct v4l2_ctrl_handler ctrl_handler;
 
+	void *cmdbuf_virt;
+	dma_addr_t cmdbuf_phy;
+
 	int osequence;
 	int csequence;
 
@@ -91,8 +94,6 @@ struct rockchip_rga {
 	spinlock_t ctrl_lock;
 
 	struct rga_ctx *curr;
-	dma_addr_t cmdbuf_phy;
-	void *cmdbuf_virt;
 
 	const struct rga_hw *hw;
 };

-- 
2.52.0



From s.pueschel at pengutronix.de  Wed Dec  3 07:52:33 2025
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Wed, 03 Dec 2025 16:52:33 +0100
Subject: [PATCH v2 11/22] media: rockchip: rga: check scaling factor
In-Reply-To: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
Message-ID: <20251203-spu-rga3-v2-11-989a67947f71@pengutronix.de>

Check the scaling factor to avoid potential problems. This is relevant
for the upcoming RGA3 support, as it can hang when the scaling factor
is exceeded.

There are two relevant scenarios that have to be considered to protect
against invalid scaling values:

When the output or capture is already streaming, setting the format on
the other side should consider the max scaling factor and clamp it
accordingly. This is only done in the streaming case, as it otherwise
may unintentionally clamp the value when the application sets the first
format (due to a default format on the other side).

When the format is set on both sides first, then the format won't be
corrected by above means. Therefore the second streamon call has to
check the scaling factor and fail otherwise.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-hw.c |  1 +
 drivers/media/platform/rockchip/rga/rga-hw.h |  1 +
 drivers/media/platform/rockchip/rga/rga.c    | 60 +++++++++++++++++++++++++---
 drivers/media/platform/rockchip/rga/rga.h    |  1 +
 4 files changed, 58 insertions(+), 5 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index 8cdfe089fd636..2ed4f22a999d5 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -624,6 +624,7 @@ const struct rga_hw rga2_hw = {
 	.max_width = MAX_WIDTH,
 	.min_height = MIN_HEIGHT,
 	.max_height = MAX_HEIGHT,
+	.max_scaling_factor = MAX_SCALING_FACTOR,
 	.stride_alignment = 4,
 
 	.setup_cmdbuf = rga_hw_setup_cmdbuf,
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.h b/drivers/media/platform/rockchip/rga/rga-hw.h
index f4752aa823051..fffcab0131225 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.h
+++ b/drivers/media/platform/rockchip/rga/rga-hw.h
@@ -14,6 +14,7 @@
 
 #define MIN_WIDTH 34
 #define MIN_HEIGHT 34
+#define MAX_SCALING_FACTOR 16
 
 #define RGA_TIMEOUT 500
 
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index f02ae02de26ca..46dc94db6f85e 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -346,18 +346,47 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
 static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
 {
 	struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp;
-	struct rockchip_rga *rga = video_drvdata(file);
+	struct rga_ctx *ctx = file_to_rga_ctx(file);
+	struct rockchip_rga *rga = ctx->rga;
 	const struct rga_hw *hw = rga->hw;
 	struct rga_fmt *fmt;
+	u32 min_width = hw->min_width;
+	u32 max_width = hw->max_width;
+	u32 min_height = hw->min_height;
+	u32 max_height = hw->max_height;
 
 	fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
 	if (!fmt)
 		fmt = &hw->formats[0];
 
-	pix_fmt->width = clamp(pix_fmt->width,
-			       hw->min_width, hw->max_width);
-	pix_fmt->height = clamp(pix_fmt->height,
-				hw->min_height, hw->max_height);
+	if (V4L2_TYPE_IS_OUTPUT(f->type) &&
+	    v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx)->streaming) {
+		min_width =
+			MAX(min_width, DIV_ROUND_UP(ctx->out.pix.width,
+						    hw->max_scaling_factor));
+		max_width = MIN(max_width,
+				ctx->out.pix.width * hw->max_scaling_factor);
+		min_height =
+			MAX(min_height, DIV_ROUND_UP(ctx->out.pix.height,
+						     hw->max_scaling_factor));
+		max_height = MIN(max_height,
+				 ctx->out.pix.height * hw->max_scaling_factor);
+	} else if (V4L2_TYPE_IS_CAPTURE(f->type) &&
+		   v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx)->streaming) {
+		min_width =
+			MAX(min_width, DIV_ROUND_UP(ctx->in.pix.width,
+						    hw->max_scaling_factor));
+		max_width = MIN(max_width,
+				ctx->in.pix.width * hw->max_scaling_factor);
+		min_height =
+			MAX(min_height, DIV_ROUND_UP(ctx->in.pix.height,
+						     hw->max_scaling_factor));
+		max_height = MIN(max_height,
+				 ctx->in.pix.height * hw->max_scaling_factor);
+	}
+
+	pix_fmt->width = clamp(pix_fmt->width, min_width, max_width);
+	pix_fmt->height = clamp(pix_fmt->height, min_height, max_height);
 
 	v4l2_fill_pixfmt_mp_aligned(pix_fmt, pix_fmt->pixelformat,
 				    pix_fmt->width, pix_fmt->height, hw->stride_alignment);
@@ -523,12 +552,33 @@ static int vidioc_s_selection(struct file *file, void *priv,
 	return ret;
 }
 
+static bool check_scaling(const struct rga_hw *hw, u32 src_size, u32 dst_size)
+{
+	if (src_size < dst_size)
+		return src_size * hw->max_scaling_factor >= dst_size;
+	else
+		return dst_size * hw->max_scaling_factor >= src_size;
+}
+
 static int vidioc_streamon(struct file *file, void *priv,
 			   enum v4l2_buf_type type)
 {
 	struct rga_ctx *ctx = file_to_rga_ctx(file);
 	const struct rga_hw *hw = ctx->rga->hw;
 
+	if ((V4L2_TYPE_IS_OUTPUT(type) &&
+	     v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx)->streaming) ||
+	    (V4L2_TYPE_IS_CAPTURE(type) &&
+	     v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx)->streaming)) {
+		/*
+		 * As the other side is already streaming,
+		 * check that the max scaling factor isn't exceeded.
+		 */
+		if (!check_scaling(hw, ctx->in.pix.width, ctx->out.pix.width) ||
+		    !check_scaling(hw, ctx->in.pix.height, ctx->out.pix.height))
+			return -EINVAL;
+	}
+
 	hw->setup_cmdbuf(ctx);
 
 	return v4l2_m2m_streamon(file, ctx->fh.m2m_ctx, type);
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index 93162b118d069..d02d5730b4e3b 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -152,6 +152,7 @@ struct rga_hw {
 	size_t cmdbuf_size;
 	u32 min_width, min_height;
 	u32 max_width, max_height;
+	u8 max_scaling_factor;
 	u8 stride_alignment;
 
 	void (*setup_cmdbuf)(struct rga_ctx *ctx);

-- 
2.52.0



From s.pueschel at pengutronix.de  Wed Dec  3 07:52:29 2025
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Wed, 03 Dec 2025 16:52:29 +0100
Subject: [PATCH v2 07/22] media: rockchip: rga: move hw specific parts to a
 dedicated struct
In-Reply-To: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
Message-ID: <20251203-spu-rga3-v2-7-989a67947f71@pengutronix.de>

In preparation for the RGA3 unit, move RGA2 specific parts from rga.c
to rga-hw.c and create a struct to reference the RGA2 specific functions
and formats. This also allows to remove the rga-hw.h reference from the
include list of the rga driver.

Also document the command finish interrupt with a dedicated define.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-hw.c | 183 ++++++++++++++++++++-
 drivers/media/platform/rockchip/rga/rga-hw.h |   5 +-
 drivers/media/platform/rockchip/rga/rga.c    | 228 +++++----------------------
 drivers/media/platform/rockchip/rga/rga.h    |  23 ++-
 4 files changed, 245 insertions(+), 194 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index f1d5237472941..7419784efc693 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -437,8 +437,8 @@ static void rga_cmd_set(struct rga_ctx *ctx,
 		PAGE_SIZE, DMA_BIDIRECTIONAL);
 }
 
-void rga_hw_start(struct rockchip_rga *rga,
-		  struct rga_vb_buffer *src, struct rga_vb_buffer *dst)
+static void rga_hw_start(struct rockchip_rga *rga,
+			 struct rga_vb_buffer *src,  struct rga_vb_buffer *dst)
 {
 	struct rga_ctx *ctx = rga->curr;
 
@@ -452,3 +452,182 @@ void rga_hw_start(struct rockchip_rga *rga,
 
 	rga_write(rga, RGA_CMD_CTRL, 0x1);
 }
+
+static bool rga_handle_irq(struct rockchip_rga *rga)
+{
+	int intr;
+
+	intr = rga_read(rga, RGA_INT) & 0xf;
+
+	rga_mod(rga, RGA_INT, intr << 4, 0xf << 4);
+
+	return intr & RGA_INT_COMMAND_FINISHED;
+}
+
+static void rga_get_version(struct rockchip_rga *rga)
+{
+	rga->version.major = (rga_read(rga, RGA_VERSION_INFO) >> 24) & 0xFF;
+	rga->version.minor = (rga_read(rga, RGA_VERSION_INFO) >> 20) & 0x0F;
+}
+
+static struct rga_fmt formats[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_ARGB32,
+		.color_swap = RGA_COLOR_ALPHA_SWAP,
+		.hw_format = RGA_COLOR_FMT_ABGR8888,
+		.depth = 32,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_ABGR32,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_ABGR8888,
+		.depth = 32,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_XBGR32,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_XBGR8888,
+		.depth = 32,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_RGB24,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_RGB888,
+		.depth = 24,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_BGR24,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_RGB888,
+		.depth = 24,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_ARGB444,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_ABGR4444,
+		.depth = 16,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_ARGB555,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_ABGR1555,
+		.depth = 16,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_RGB565,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_BGR565,
+		.depth = 16,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV21,
+		.color_swap = RGA_COLOR_UV_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV420SP,
+		.depth = 12,
+		.uv_factor = 4,
+		.y_div = 2,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV61,
+		.color_swap = RGA_COLOR_UV_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV422SP,
+		.depth = 16,
+		.uv_factor = 2,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV12,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV420SP,
+		.depth = 12,
+		.uv_factor = 4,
+		.y_div = 2,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV12M,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV420SP,
+		.depth = 12,
+		.uv_factor = 4,
+		.y_div = 2,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV16,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV422SP,
+		.depth = 16,
+		.uv_factor = 2,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_YUV420,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV420P,
+		.depth = 12,
+		.uv_factor = 4,
+		.y_div = 2,
+		.x_div = 2,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_YUV422P,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV422P,
+
+		.depth = 16,
+		.uv_factor = 2,
+		.y_div = 1,
+		.x_div = 2,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_YVU420,
+		.color_swap = RGA_COLOR_UV_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV420P,
+		.depth = 12,
+		.uv_factor = 4,
+		.y_div = 2,
+		.x_div = 2,
+	},
+};
+
+const struct rga_hw rga2_hw = {
+	.formats = formats,
+	.num_formats = ARRAY_SIZE(formats),
+	.cmdbuf_size = RGA_CMDBUF_SIZE,
+	.min_width = MIN_WIDTH,
+	.max_width = MAX_WIDTH,
+	.min_height = MIN_HEIGHT,
+	.max_height = MAX_HEIGHT,
+
+	.start = rga_hw_start,
+	.handle_irq = rga_handle_irq,
+	.get_version = rga_get_version,
+};
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.h b/drivers/media/platform/rockchip/rga/rga-hw.h
index cc6bd7f5b0300..f4752aa823051 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.h
+++ b/drivers/media/platform/rockchip/rga/rga-hw.h
@@ -15,9 +15,6 @@
 #define MIN_WIDTH 34
 #define MIN_HEIGHT 34
 
-#define DEFAULT_WIDTH 100
-#define DEFAULT_HEIGHT 100
-
 #define RGA_TIMEOUT 500
 
 /* Registers address */
@@ -178,6 +175,8 @@
 #define RGA_ALPHA_COLOR_NORMAL 0
 #define RGA_ALPHA_COLOR_MULTIPLY_CAL 1
 
+#define RGA_INT_COMMAND_FINISHED 4
+
 /* Registers union */
 union rga_mode_ctrl {
 	unsigned int val;
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index f50fbbab0645e..d8b14c2d9f6a4 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -25,7 +25,6 @@
 #include <media/videobuf2-dma-sg.h>
 #include <media/videobuf2-v4l2.h>
 
-#include "rga-hw.h"
 #include "rga.h"
 
 static int debug;
@@ -47,7 +46,7 @@ static void device_run(void *prv)
 
 	dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
 
-	rga_hw_start(rga, vb_to_rga(src), vb_to_rga(dst));
+	rga->hw->start(rga, vb_to_rga(src), vb_to_rga(dst));
 
 	spin_unlock_irqrestore(&rga->ctrl_lock, flags);
 }
@@ -55,13 +54,8 @@ static void device_run(void *prv)
 static irqreturn_t rga_isr(int irq, void *prv)
 {
 	struct rockchip_rga *rga = prv;
-	int intr;
 
-	intr = rga_read(rga, RGA_INT) & 0xf;
-
-	rga_mod(rga, RGA_INT, intr << 4, 0xf << 4);
-
-	if (intr & 0x04) {
+	if (rga->hw->handle_irq(rga)) {
 		struct vb2_v4l2_buffer *src, *dst;
 		struct rga_ctx *ctx = rga->curr;
 
@@ -184,174 +178,17 @@ static int rga_setup_ctrls(struct rga_ctx *ctx)
 	return 0;
 }
 
-static struct rga_fmt formats[] = {
-	{
-		.fourcc = V4L2_PIX_FMT_ARGB32,
-		.color_swap = RGA_COLOR_ALPHA_SWAP,
-		.hw_format = RGA_COLOR_FMT_ABGR8888,
-		.depth = 32,
-		.uv_factor = 1,
-		.y_div = 1,
-		.x_div = 1,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_ABGR32,
-		.color_swap = RGA_COLOR_RB_SWAP,
-		.hw_format = RGA_COLOR_FMT_ABGR8888,
-		.depth = 32,
-		.uv_factor = 1,
-		.y_div = 1,
-		.x_div = 1,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_XBGR32,
-		.color_swap = RGA_COLOR_RB_SWAP,
-		.hw_format = RGA_COLOR_FMT_XBGR8888,
-		.depth = 32,
-		.uv_factor = 1,
-		.y_div = 1,
-		.x_div = 1,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_RGB24,
-		.color_swap = RGA_COLOR_NONE_SWAP,
-		.hw_format = RGA_COLOR_FMT_RGB888,
-		.depth = 24,
-		.uv_factor = 1,
-		.y_div = 1,
-		.x_div = 1,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_BGR24,
-		.color_swap = RGA_COLOR_RB_SWAP,
-		.hw_format = RGA_COLOR_FMT_RGB888,
-		.depth = 24,
-		.uv_factor = 1,
-		.y_div = 1,
-		.x_div = 1,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_ARGB444,
-		.color_swap = RGA_COLOR_RB_SWAP,
-		.hw_format = RGA_COLOR_FMT_ABGR4444,
-		.depth = 16,
-		.uv_factor = 1,
-		.y_div = 1,
-		.x_div = 1,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_ARGB555,
-		.color_swap = RGA_COLOR_RB_SWAP,
-		.hw_format = RGA_COLOR_FMT_ABGR1555,
-		.depth = 16,
-		.uv_factor = 1,
-		.y_div = 1,
-		.x_div = 1,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_RGB565,
-		.color_swap = RGA_COLOR_RB_SWAP,
-		.hw_format = RGA_COLOR_FMT_BGR565,
-		.depth = 16,
-		.uv_factor = 1,
-		.y_div = 1,
-		.x_div = 1,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_NV21,
-		.color_swap = RGA_COLOR_UV_SWAP,
-		.hw_format = RGA_COLOR_FMT_YUV420SP,
-		.depth = 12,
-		.uv_factor = 4,
-		.y_div = 2,
-		.x_div = 1,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_NV61,
-		.color_swap = RGA_COLOR_UV_SWAP,
-		.hw_format = RGA_COLOR_FMT_YUV422SP,
-		.depth = 16,
-		.uv_factor = 2,
-		.y_div = 1,
-		.x_div = 1,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_NV12,
-		.color_swap = RGA_COLOR_NONE_SWAP,
-		.hw_format = RGA_COLOR_FMT_YUV420SP,
-		.depth = 12,
-		.uv_factor = 4,
-		.y_div = 2,
-		.x_div = 1,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_NV12M,
-		.color_swap = RGA_COLOR_NONE_SWAP,
-		.hw_format = RGA_COLOR_FMT_YUV420SP,
-		.depth = 12,
-		.uv_factor = 4,
-		.y_div = 2,
-		.x_div = 1,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_NV16,
-		.color_swap = RGA_COLOR_NONE_SWAP,
-		.hw_format = RGA_COLOR_FMT_YUV422SP,
-		.depth = 16,
-		.uv_factor = 2,
-		.y_div = 1,
-		.x_div = 1,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_YUV420,
-		.color_swap = RGA_COLOR_NONE_SWAP,
-		.hw_format = RGA_COLOR_FMT_YUV420P,
-		.depth = 12,
-		.uv_factor = 4,
-		.y_div = 2,
-		.x_div = 2,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_YUV422P,
-		.color_swap = RGA_COLOR_NONE_SWAP,
-		.hw_format = RGA_COLOR_FMT_YUV422P,
-		.depth = 16,
-		.uv_factor = 2,
-		.y_div = 1,
-		.x_div = 2,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_YVU420,
-		.color_swap = RGA_COLOR_UV_SWAP,
-		.hw_format = RGA_COLOR_FMT_YUV420P,
-		.depth = 12,
-		.uv_factor = 4,
-		.y_div = 2,
-		.x_div = 2,
-	},
-};
-
-#define NUM_FORMATS ARRAY_SIZE(formats)
-
-static struct rga_fmt *rga_fmt_find(u32 pixelformat)
+static struct rga_fmt *rga_fmt_find(struct rockchip_rga *rga, u32 pixelformat)
 {
 	unsigned int i;
 
-	for (i = 0; i < NUM_FORMATS; i++) {
-		if (formats[i].fourcc == pixelformat)
-			return &formats[i];
+	for (i = 0; i < rga->hw->num_formats; i++) {
+		if (rga->hw->formats[i].fourcc == pixelformat)
+			return &rga->hw->formats[i];
 	}
 	return NULL;
 }
 
-static struct rga_frame def_frame = {
-	.crop.left = 0,
-	.crop.top = 0,
-	.crop.width = DEFAULT_WIDTH,
-	.crop.height = DEFAULT_HEIGHT,
-	.fmt = &formats[0],
-};
-
 struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type)
 {
 	if (V4L2_TYPE_IS_OUTPUT(type))
@@ -366,6 +203,18 @@ static int rga_open(struct file *file)
 	struct rockchip_rga *rga = video_drvdata(file);
 	struct rga_ctx *ctx = NULL;
 	int ret = 0;
+	u32 def_width = clamp(DEFAULT_WIDTH, rga->hw->min_width, rga->hw->max_width);
+	u32 def_height = clamp(DEFAULT_HEIGHT, rga->hw->min_height, rga->hw->max_height);
+	struct rga_frame def_frame = {
+		.crop.left = 0,
+		.crop.top = 0,
+		.crop.width = def_width,
+		.crop.height = def_height,
+		.fmt = &rga->hw->formats[0],
+	};
+
+	def_frame.stride = (def_width * def_frame.fmt->depth) >> 3;
+	def_frame.size = def_frame.stride * def_height;
 
 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
@@ -376,9 +225,9 @@ static int rga_open(struct file *file)
 	ctx->out = def_frame;
 
 	v4l2_fill_pixfmt_mp(&ctx->in.pix,
-			    ctx->in.fmt->fourcc, DEFAULT_WIDTH, DEFAULT_HEIGHT);
+			    ctx->in.fmt->fourcc, def_width, def_height);
 	v4l2_fill_pixfmt_mp(&ctx->out.pix,
-			    ctx->out.fmt->fourcc, DEFAULT_WIDTH, DEFAULT_HEIGHT);
+			    ctx->out.fmt->fourcc, def_width, def_height);
 
 	if (mutex_lock_interruptible(&rga->mutex)) {
 		kfree(ctx);
@@ -445,12 +294,13 @@ vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
 
 static int vidioc_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f)
 {
+	struct rockchip_rga *rga = video_drvdata(file);
 	struct rga_fmt *fmt;
 
-	if (f->index >= NUM_FORMATS)
+	if (f->index >= rga->hw->num_formats)
 		return -EINVAL;
 
-	fmt = &formats[f->index];
+	fmt = &rga->hw->formats[f->index];
 	f->pixelformat = fmt->fourcc;
 
 	return 0;
@@ -475,16 +325,18 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
 static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
 {
 	struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp;
+	struct rockchip_rga *rga = video_drvdata(file);
+	const struct rga_hw *hw = rga->hw;
 	struct rga_fmt *fmt;
 
-	fmt = rga_fmt_find(pix_fmt->pixelformat);
+	fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
 	if (!fmt)
-		fmt = &formats[0];
+		fmt = &hw->formats[0];
 
 	pix_fmt->width = clamp(pix_fmt->width,
-			       (u32)MIN_WIDTH, (u32)MAX_WIDTH);
+			       hw->min_width, hw->max_width);
 	pix_fmt->height = clamp(pix_fmt->height,
-				(u32)MIN_HEIGHT, (u32)MAX_HEIGHT);
+				hw->min_height, hw->max_height);
 
 	v4l2_fill_pixfmt_mp(pix_fmt, fmt->fourcc, pix_fmt->width, pix_fmt->height);
 	pix_fmt->field = V4L2_FIELD_NONE;
@@ -519,7 +371,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	frm->size = 0;
 	for (i = 0; i < pix_fmt->num_planes; i++)
 		frm->size += pix_fmt->plane_fmt[i].sizeimage;
-	frm->fmt = rga_fmt_find(pix_fmt->pixelformat);
+	frm->fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
 	frm->stride = pix_fmt->plane_fmt[0].bytesperline;
 
 	/* Reset crop settings */
@@ -639,7 +491,7 @@ static int vidioc_s_selection(struct file *file, void *priv,
 
 	if (s->r.left + s->r.width > f->pix.width ||
 	    s->r.top + s->r.height > f->pix.height ||
-	    s->r.width < MIN_WIDTH || s->r.height < MIN_HEIGHT) {
+	    s->r.width < rga->hw->min_width || s->r.height < rga->hw->min_height) {
 		v4l2_dbg(debug, 1, &rga->v4l2_dev, "unsupported crop value.\n");
 		return -EINVAL;
 	}
@@ -748,6 +600,10 @@ static int rga_probe(struct platform_device *pdev)
 	if (!rga)
 		return -ENOMEM;
 
+	rga->hw = of_device_get_match_data(&pdev->dev);
+	if (!rga->hw)
+		return dev_err_probe(&pdev->dev, -ENODEV, "failed to get match data\n");
+
 	rga->dev = &pdev->dev;
 	spin_lock_init(&rga->ctrl_lock);
 	mutex_init(&rga->mutex);
@@ -811,8 +667,7 @@ static int rga_probe(struct platform_device *pdev)
 	if (ret < 0)
 		goto rel_m2m;
 
-	rga->version.major = (rga_read(rga, RGA_VERSION_INFO) >> 24) & 0xFF;
-	rga->version.minor = (rga_read(rga, RGA_VERSION_INFO) >> 20) & 0x0F;
+	rga->hw->get_version(rga);
 
 	v4l2_info(&rga->v4l2_dev, "HW Version: 0x%02x.%02x\n",
 		  rga->version.major, rga->version.minor);
@@ -820,7 +675,7 @@ static int rga_probe(struct platform_device *pdev)
 	pm_runtime_put(rga->dev);
 
 	/* Create CMD buffer */
-	rga->cmdbuf_virt = dma_alloc_attrs(rga->dev, RGA_CMDBUF_SIZE,
+	rga->cmdbuf_virt = dma_alloc_attrs(rga->dev, rga->hw->cmdbuf_size,
 					   &rga->cmdbuf_phy, GFP_KERNEL,
 					   DMA_ATTR_WRITE_COMBINE);
 	if (!rga->cmdbuf_virt) {
@@ -828,9 +683,6 @@ static int rga_probe(struct platform_device *pdev)
 		goto rel_m2m;
 	}
 
-	def_frame.stride = (DEFAULT_WIDTH * def_frame.fmt->depth) >> 3;
-	def_frame.size = def_frame.stride * DEFAULT_HEIGHT;
-
 	ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
 	if (ret) {
 		v4l2_err(&rga->v4l2_dev, "Failed to register video device\n");
@@ -843,7 +695,7 @@ static int rga_probe(struct platform_device *pdev)
 	return 0;
 
 free_dma:
-	dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, rga->cmdbuf_virt,
+	dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, rga->cmdbuf_virt,
 		       rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
 rel_m2m:
 	v4l2_m2m_release(rga->m2m_dev);
@@ -861,7 +713,7 @@ static void rga_remove(struct platform_device *pdev)
 {
 	struct rockchip_rga *rga = platform_get_drvdata(pdev);
 
-	dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, rga->cmdbuf_virt,
+	dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, rga->cmdbuf_virt,
 		       rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
 
 	v4l2_info(&rga->v4l2_dev, "Removing\n");
@@ -897,9 +749,11 @@ static const struct dev_pm_ops rga_pm = {
 static const struct of_device_id rockchip_rga_match[] = {
 	{
 		.compatible = "rockchip,rk3288-rga",
+		.data = &rga2_hw,
 	},
 	{
 		.compatible = "rockchip,rk3399-rga",
+		.data = &rga2_hw,
 	},
 	{},
 };
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index 7ec1fcc03ed32..98635ddd50d7c 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -14,6 +14,9 @@
 
 #define RGA_NAME "rockchip-rga"
 
+#define DEFAULT_WIDTH 100
+#define DEFAULT_HEIGHT 100
+
 struct rga_fmt {
 	u32 fourcc;
 	int depth;
@@ -69,6 +72,8 @@ static inline struct rga_ctx *file_to_rga_ctx(struct file *filp)
 	return container_of(file_to_v4l2_fh(filp), struct rga_ctx, fh);
 }
 
+struct rga_hw;
+
 struct rockchip_rga {
 	struct v4l2_device v4l2_dev;
 	struct v4l2_m2m_dev *m2m_dev;
@@ -88,6 +93,8 @@ struct rockchip_rga {
 	struct rga_ctx *curr;
 	dma_addr_t cmdbuf_phy;
 	void *cmdbuf_virt;
+
+	const struct rga_hw *hw;
 };
 
 struct rga_addr_offset {
@@ -138,7 +145,19 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
 	rga_write(rga, reg, temp);
 };
 
-void rga_hw_start(struct rockchip_rga *rga,
-		  struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
+struct rga_hw {
+	struct rga_fmt *formats;
+	u32 num_formats;
+	size_t cmdbuf_size;
+	u32 min_width, min_height;
+	u32 max_width, max_height;
+
+	void (*start)(struct rockchip_rga *rga,
+		      struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
+	bool (*handle_irq)(struct rockchip_rga *rga);
+	void (*get_version)(struct rockchip_rga *rga);
+};
+
+extern const struct rga_hw rga2_hw;
 
 #endif

-- 
2.52.0



From s.pueschel at pengutronix.de  Wed Dec  3 07:52:36 2025
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Wed, 03 Dec 2025 16:52:36 +0100
Subject: [PATCH v2 14/22] media: rockchip: rga: support external iommus
In-Reply-To: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
Message-ID: <20251203-spu-rga3-v2-14-989a67947f71@pengutronix.de>

In preparation for the RGA3 add support for external iommus. This is a
transition step to just disable the RGA2 specific mmu table setup code.

Currently a simple rga_hw struct field is used to set the internal iommu.
But to handle the case of more sophisticated detection mechanisms
(e.g. check for an iommu property in the device tree), it is abstracted
by an inline function.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-buf.c | 46 ++++++++++++++++-----------
 drivers/media/platform/rockchip/rga/rga-hw.c  |  1 +
 drivers/media/platform/rockchip/rga/rga.c     | 11 +++++--
 drivers/media/platform/rockchip/rga/rga.h     |  6 ++++
 4 files changed, 43 insertions(+), 21 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
index 8845e1f894f29..e8d1e2e579140 100644
--- a/drivers/media/platform/rockchip/rga/rga-buf.c
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -12,6 +12,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-mem2mem.h>
 #include <media/videobuf2-dma-sg.h>
+#include <media/videobuf2-dma-contig.h>
 #include <media/videobuf2-v4l2.h>
 
 #include "rga.h"
@@ -79,14 +80,16 @@ static int rga_buf_init(struct vb2_buffer *vb)
 	struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type);
 	size_t n_desc = 0;
 
-	n_desc = DIV_ROUND_UP(f->size, PAGE_SIZE);
+	if (rga_has_internal_iommu(rga)) {
+		n_desc = DIV_ROUND_UP(f->size, PAGE_SIZE);
 
-	rbuf->n_desc = n_desc;
-	rbuf->dma_desc = dma_alloc_coherent(rga->dev,
-					    rbuf->n_desc * sizeof(*rbuf->dma_desc),
-					    &rbuf->dma_desc_pa, GFP_KERNEL);
-	if (!rbuf->dma_desc)
-		return -ENOMEM;
+		rbuf->n_desc = n_desc;
+		rbuf->dma_desc = dma_alloc_coherent(rga->dev,
+						    rbuf->n_desc * sizeof(*rbuf->dma_desc),
+						    &rbuf->dma_desc_pa, GFP_KERNEL);
+		if (!rbuf->dma_desc)
+			return -ENOMEM;
+	}
 
 	return 0;
 }
@@ -133,17 +136,21 @@ static int rga_buf_prepare(struct vb2_buffer *vb)
 	for (i = 0; i < vb->num_planes; i++) {
 		vb2_set_plane_payload(vb, i, f->pix.plane_fmt[i].sizeimage);
 
-		/* Create local MMU table for RGA */
-		n_desc = fill_descriptors(&rbuf->dma_desc[curr_desc],
-					  rbuf->n_desc - curr_desc,
-					  vb2_dma_sg_plane_desc(vb, i));
-		if (n_desc < 0) {
-			v4l2_err(&ctx->rga->v4l2_dev,
-				 "Failed to map video buffer to RGA\n");
-			return n_desc;
+		if (rga_has_internal_iommu(ctx->rga)) {
+			/* Create local MMU table for RGA */
+			n_desc = fill_descriptors(&rbuf->dma_desc[curr_desc],
+						  rbuf->n_desc - curr_desc,
+						  vb2_dma_sg_plane_desc(vb, i));
+			if (n_desc < 0) {
+				v4l2_err(&ctx->rga->v4l2_dev,
+					 "Failed to map video buffer to RGA\n");
+				return n_desc;
+			}
+			dma_addrs[i] = curr_desc << PAGE_SHIFT;
+			curr_desc += n_desc;
+		} else {
+			dma_addrs[i] = vb2_dma_contig_plane_dma_addr(vb, i);
 		}
-		dma_addrs[i] = curr_desc << PAGE_SHIFT;
-		curr_desc += n_desc;
 	}
 
 	/* Fill the remaining planes */
@@ -173,8 +180,9 @@ static void rga_buf_cleanup(struct vb2_buffer *vb)
 	struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
 	struct rockchip_rga *rga = ctx->rga;
 
-	dma_free_coherent(rga->dev, rbuf->n_desc * sizeof(*rbuf->dma_desc),
-			  rbuf->dma_desc, rbuf->dma_desc_pa);
+	if (rga_has_internal_iommu(rga))
+		dma_free_coherent(rga->dev, rbuf->n_desc * sizeof(*rbuf->dma_desc),
+				  rbuf->dma_desc, rbuf->dma_desc_pa);
 }
 
 static void rga_buf_return_buffers(struct vb2_queue *q,
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index fe6f518aedd4e..fb0389ae8e132 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -617,6 +617,7 @@ static struct rga_fmt formats[] = {
 
 const struct rga_hw rga2_hw = {
 	.card_type = "rga2",
+	.has_internal_iommu = true,
 	.formats = formats,
 	.num_formats = ARRAY_SIZE(formats),
 	.cmdbuf_size = RGA_CMDBUF_SIZE,
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index c9719c7bcfc1c..f28ec88c186fa 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -23,6 +23,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-mem2mem.h>
 #include <media/videobuf2-dma-sg.h>
+#include <media/videobuf2-dma-contig.h>
 #include <media/videobuf2-v4l2.h>
 
 #include "rga.h"
@@ -95,13 +96,16 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
 	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
 	src_vq->drv_priv = ctx;
 	src_vq->ops = &rga_qops;
-	src_vq->mem_ops = &vb2_dma_sg_memops;
+	src_vq->mem_ops = &vb2_dma_contig_memops;
 	src_vq->gfp_flags = __GFP_DMA32;
 	src_vq->buf_struct_size = sizeof(struct rga_vb_buffer);
 	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
 	src_vq->lock = &ctx->rga->mutex;
 	src_vq->dev = ctx->rga->v4l2_dev.dev;
 
+	if (rga_has_internal_iommu(ctx->rga))
+		src_vq->mem_ops = &vb2_dma_sg_memops;
+
 	ret = vb2_queue_init(src_vq);
 	if (ret)
 		return ret;
@@ -110,13 +114,16 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
 	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
 	dst_vq->drv_priv = ctx;
 	dst_vq->ops = &rga_qops;
-	dst_vq->mem_ops = &vb2_dma_sg_memops;
+	dst_vq->mem_ops = &vb2_dma_contig_memops;
 	dst_vq->gfp_flags = __GFP_DMA32;
 	dst_vq->buf_struct_size = sizeof(struct rga_vb_buffer);
 	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
 	dst_vq->lock = &ctx->rga->mutex;
 	dst_vq->dev = ctx->rga->v4l2_dev.dev;
 
+	if (rga_has_internal_iommu(ctx->rga))
+		dst_vq->mem_ops = &vb2_dma_sg_memops;
+
 	return vb2_queue_init(dst_vq);
 }
 
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index 772f7dff9a8e5..fc81bc5562792 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -148,6 +148,7 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
 
 struct rga_hw {
 	const char *card_type;
+	bool has_internal_iommu;
 	struct rga_fmt *formats;
 	u32 num_formats;
 	size_t cmdbuf_size;
@@ -163,6 +164,11 @@ struct rga_hw {
 	void (*get_version)(struct rockchip_rga *rga);
 };
 
+static inline bool rga_has_internal_iommu(const struct rockchip_rga *rga)
+{
+	return rga->hw->has_internal_iommu;
+}
+
 extern const struct rga_hw rga2_hw;
 
 #endif

-- 
2.52.0



From s.pueschel at pengutronix.de  Wed Dec  3 07:52:37 2025
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Wed, 03 Dec 2025 16:52:37 +0100
Subject: [PATCH v2 15/22] media: rockchip: rga: share the interrupt when an
 external iommu is used
In-Reply-To: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
Message-ID: <20251203-spu-rga3-v2-15-989a67947f71@pengutronix.de>

From: Michael Olbrich <m.olbrich at pengutronix.de>

The RGA3 and the corresponding iommu share the interrupt. So in that
case, request a shared interrupt so that the iommu driver can request
it as well.

Signed-off-by: Michael Olbrich <m.olbrich at pengutronix.de>
Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index f28ec88c186fa..1bfc4021f4a7b 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -718,7 +718,8 @@ static int rga_probe(struct platform_device *pdev)
 		goto err_put_clk;
 	}
 
-	ret = devm_request_irq(rga->dev, irq, rga_isr, 0,
+	ret = devm_request_irq(rga->dev, irq, rga_isr,
+			       rga_has_internal_iommu(rga) ? 0 : IRQF_SHARED,
 			       dev_name(rga->dev), rga);
 	if (ret < 0) {
 		dev_err(rga->dev, "failed to request irq\n");

-- 
2.52.0



From s.pueschel at pengutronix.de  Wed Dec  3 07:52:35 2025
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Wed, 03 Dec 2025 16:52:35 +0100
Subject: [PATCH v2 13/22] media: rockchip: rga: change offset to
 dma_addresses
In-Reply-To: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
Message-ID: <20251203-spu-rga3-v2-13-989a67947f71@pengutronix.de>

Change the offset to dma_addresses, as the current naming is misleading.
The offset naming comes from the fact that it references the offset in
the mapped iommu address space. But from the hardware point of view this
is an address, as also pointed out by the register naming
(e.g. RGA_DST_Y_RGB_BASE_ADDR). Therefore also change the type to
dma_addr_t, as with an external iommu driver this would also be the
correct type.

This change is a preparation for the RGA3 support, which uses an external
iommu and therefore just gets an dma_addr_t for each buffer. The field
renaming allows to reuse the existing fields of rga_vb_buffer to store
these values.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-buf.c |  12 +--
 drivers/media/platform/rockchip/rga/rga-hw.c  | 105 +++++++++++++-------------
 drivers/media/platform/rockchip/rga/rga.h     |  12 +--
 3 files changed, 64 insertions(+), 65 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
index 0c59a4d330888..8845e1f894f29 100644
--- a/drivers/media/platform/rockchip/rga/rga-buf.c
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -118,7 +118,7 @@ static int rga_buf_prepare(struct vb2_buffer *vb)
 	size_t curr_desc = 0;
 	int i;
 	const struct v4l2_format_info *info;
-	unsigned int offsets[VIDEO_MAX_PLANES];
+	unsigned int dma_addrs[VIDEO_MAX_PLANES];
 
 	if (IS_ERR(f))
 		return PTR_ERR(f);
@@ -142,18 +142,18 @@ static int rga_buf_prepare(struct vb2_buffer *vb)
 				 "Failed to map video buffer to RGA\n");
 			return n_desc;
 		}
-		offsets[i] = curr_desc << PAGE_SHIFT;
+		dma_addrs[i] = curr_desc << PAGE_SHIFT;
 		curr_desc += n_desc;
 	}
 
 	/* Fill the remaining planes */
 	info = v4l2_format_info(f->fmt->fourcc);
 	for (i = info->mem_planes; i < info->comp_planes; i++)
-		offsets[i] = get_plane_offset(f, info, i);
+		dma_addrs[i] = dma_addrs[0] + get_plane_offset(f, info, i);
 
-	rbuf->offset.y_off = offsets[0];
-	rbuf->offset.u_off = offsets[1];
-	rbuf->offset.v_off = offsets[2];
+	rbuf->dma_addrs.y_addr = dma_addrs[0];
+	rbuf->dma_addrs.u_addr = dma_addrs[1];
+	rbuf->dma_addrs.v_addr = dma_addrs[2];
 
 	return 0;
 }
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index 8953960d33bc5..fe6f518aedd4e 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -16,11 +16,11 @@ enum e_rga_start_pos {
 	RB = 3,
 };
 
-struct rga_corners_addr_offset {
-	struct rga_addr_offset left_top;
-	struct rga_addr_offset right_top;
-	struct rga_addr_offset left_bottom;
-	struct rga_addr_offset right_bottom;
+struct rga_corners_addrs {
+	struct rga_addrs left_top;
+	struct rga_addrs right_top;
+	struct rga_addrs left_bottom;
+	struct rga_addrs right_bottom;
 };
 
 static unsigned int rga_get_scaling(unsigned int src, unsigned int dst)
@@ -36,48 +36,47 @@ static unsigned int rga_get_scaling(unsigned int src, unsigned int dst)
 	return (src > dst) ? ((dst << 16) / src) : ((src << 16) / dst);
 }
 
-static struct rga_corners_addr_offset
-rga_get_addr_offset(struct rga_frame *frm, struct rga_addr_offset *offset,
-		    unsigned int x, unsigned int y, unsigned int w, unsigned int h)
+static struct rga_corners_addrs
+rga_get_corner_addrs(struct rga_frame *frm, struct rga_addrs *addrs,
+		     unsigned int x, unsigned int y, unsigned int w, unsigned int h)
 {
-	struct rga_corners_addr_offset offsets;
-	struct rga_addr_offset *lt, *lb, *rt, *rb;
+	struct rga_corners_addrs corner_addrs;
+	struct rga_addrs *lt, *lb, *rt, *rb;
 	unsigned int x_div = 0,
 		     y_div = 0, uv_stride = 0, pixel_width = 0;
 
-	lt = &offsets.left_top;
-	lb = &offsets.left_bottom;
-	rt = &offsets.right_top;
-	rb = &offsets.right_bottom;
+	lt = &corner_addrs.left_top;
+	lb = &corner_addrs.left_bottom;
+	rt = &corner_addrs.right_top;
+	rb = &corner_addrs.right_bottom;
 
 	x_div = frm->fmt->x_div;
 	y_div = frm->fmt->y_div;
 	uv_stride = frm->stride / x_div;
 	pixel_width = frm->stride / frm->pix.width;
 
-	lt->y_off = offset->y_off + y * frm->stride + x * pixel_width;
-	lt->u_off = offset->u_off + (y / y_div) * uv_stride + x / x_div;
-	lt->v_off = offset->v_off + (y / y_div) * uv_stride + x / x_div;
+	lt->y_addr = addrs->y_addr + y * frm->stride + x * pixel_width;
+	lt->u_addr = addrs->u_addr + (y / y_div) * uv_stride + x / x_div;
+	lt->v_addr = addrs->v_addr + (y / y_div) * uv_stride + x / x_div;
 
-	lb->y_off = lt->y_off + (h - 1) * frm->stride;
-	lb->u_off = lt->u_off + (h / y_div - 1) * uv_stride;
-	lb->v_off = lt->v_off + (h / y_div - 1) * uv_stride;
+	lb->y_addr = lt->y_addr + (h - 1) * frm->stride;
+	lb->u_addr = lt->u_addr + (h / y_div - 1) * uv_stride;
+	lb->v_addr = lt->v_addr + (h / y_div - 1) * uv_stride;
 
-	rt->y_off = lt->y_off + (w - 1) * pixel_width;
-	rt->u_off = lt->u_off + w / x_div - 1;
-	rt->v_off = lt->v_off + w / x_div - 1;
+	rt->y_addr = lt->y_addr + (w - 1) * pixel_width;
+	rt->u_addr = lt->u_addr + w / x_div - 1;
+	rt->v_addr = lt->v_addr + w / x_div - 1;
 
-	rb->y_off = lb->y_off + (w - 1) * pixel_width;
-	rb->u_off = lb->u_off + w / x_div - 1;
-	rb->v_off = lb->v_off + w / x_div - 1;
+	rb->y_addr = lb->y_addr + (w - 1) * pixel_width;
+	rb->u_addr = lb->u_addr + w / x_div - 1;
+	rb->v_addr = lb->v_addr + w / x_div - 1;
 
-	return offsets;
+	return corner_addrs;
 }
 
-static struct rga_addr_offset *rga_lookup_draw_pos(struct
-		rga_corners_addr_offset
-		* offsets, u32 rotate_mode,
-		u32 mirr_mode)
+static struct rga_addrs *rga_lookup_draw_pos(struct rga_corners_addrs *corner_addrs,
+					     u32 rotate_mode,
+					     u32 mirr_mode)
 {
 	static enum e_rga_start_pos rot_mir_point_matrix[4][4] = {
 		{
@@ -94,18 +93,18 @@ static struct rga_addr_offset *rga_lookup_draw_pos(struct
 		},
 	};
 
-	if (!offsets)
+	if (!corner_addrs)
 		return NULL;
 
 	switch (rot_mir_point_matrix[rotate_mode][mirr_mode]) {
 	case LT:
-		return &offsets->left_top;
+		return &corner_addrs->left_top;
 	case LB:
-		return &offsets->left_bottom;
+		return &corner_addrs->left_bottom;
 	case RT:
-		return &offsets->right_top;
+		return &corner_addrs->right_top;
 	case RB:
-		return &offsets->right_bottom;
+		return &corner_addrs->right_bottom;
 	}
 
 	return NULL;
@@ -307,9 +306,9 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
 }
 
 static void rga_cmd_set_src_info(struct rga_ctx *ctx,
-				 struct rga_addr_offset *offset)
+				 struct rga_addrs *addrs)
 {
-	struct rga_corners_addr_offset src_offsets;
+	struct rga_corners_addrs src_corner_addrs;
 	u32 *dest = ctx->cmdbuf_virt;
 	unsigned int src_h, src_w, src_x, src_y;
 
@@ -321,22 +320,22 @@ static void rga_cmd_set_src_info(struct rga_ctx *ctx,
 	/*
 	 * Calculate the source framebuffer base address with offset pixel.
 	 */
-	src_offsets = rga_get_addr_offset(&ctx->in, offset,
-					  src_x, src_y, src_w, src_h);
+	src_corner_addrs = rga_get_corner_addrs(&ctx->in, addrs,
+						src_x, src_y, src_w, src_h);
 
 	dest[(RGA_SRC_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
-		src_offsets.left_top.y_off;
+		src_corner_addrs.left_top.y_addr;
 	dest[(RGA_SRC_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
-		src_offsets.left_top.u_off;
+		src_corner_addrs.left_top.u_addr;
 	dest[(RGA_SRC_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
-		src_offsets.left_top.v_off;
+		src_corner_addrs.left_top.v_addr;
 }
 
 static void rga_cmd_set_dst_info(struct rga_ctx *ctx,
-				 struct rga_addr_offset *offset)
+				 struct rga_addrs *addrs)
 {
-	struct rga_addr_offset *dst_offset;
-	struct rga_corners_addr_offset offsets;
+	struct rga_addrs *dst_addrs;
+	struct rga_corners_addrs corner_addrs;
 	u32 *dest = ctx->cmdbuf_virt;
 	unsigned int dst_h, dst_w, dst_x, dst_y;
 	unsigned int mir_mode = 0;
@@ -370,15 +369,15 @@ static void rga_cmd_set_dst_info(struct rga_ctx *ctx,
 	/*
 	 * Configure the dest framebuffer base address with pixel offset.
 	 */
-	offsets = rga_get_addr_offset(&ctx->out, offset, dst_x, dst_y, dst_w, dst_h);
-	dst_offset = rga_lookup_draw_pos(&offsets, rot_mode, mir_mode);
+	corner_addrs = rga_get_corner_addrs(&ctx->out, addrs, dst_x, dst_y, dst_w, dst_h);
+	dst_addrs = rga_lookup_draw_pos(&corner_addrs, rot_mode, mir_mode);
 
 	dest[(RGA_DST_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
-		dst_offset->y_off;
+		dst_addrs->y_addr;
 	dest[(RGA_DST_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
-		dst_offset->u_off;
+		dst_addrs->u_addr;
 	dest[(RGA_DST_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
-		dst_offset->v_off;
+		dst_addrs->v_addr;
 }
 
 static void rga_cmd_set_mode(struct rga_ctx *ctx)
@@ -417,8 +416,8 @@ static void rga_cmd_set(struct rga_ctx *ctx,
 
 	rga_cmd_set_dst_addr(ctx, dst->dma_desc_pa);
 
-	rga_cmd_set_src_info(ctx, &src->offset);
-	rga_cmd_set_dst_info(ctx, &dst->offset);
+	rga_cmd_set_src_info(ctx, &src->dma_addrs);
+	rga_cmd_set_dst_info(ctx, &dst->dma_addrs);
 
 	rga_write(rga, RGA_CMD_BASE, ctx->cmdbuf_phy);
 
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index ee50f7f3ed601..772f7dff9a8e5 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -98,10 +98,10 @@ struct rockchip_rga {
 	const struct rga_hw *hw;
 };
 
-struct rga_addr_offset {
-	unsigned int y_off;
-	unsigned int u_off;
-	unsigned int v_off;
+struct rga_addrs {
+	dma_addr_t y_addr;
+	dma_addr_t u_addr;
+	dma_addr_t v_addr;
 };
 
 struct rga_vb_buffer {
@@ -113,8 +113,8 @@ struct rga_vb_buffer {
 	dma_addr_t dma_desc_pa;
 	size_t n_desc;
 
-	/* Plane offsets of this buffer into the mapping */
-	struct rga_addr_offset offset;
+	/* Plane DMA addresses after the MMU mapping of the buffer */
+	struct rga_addrs dma_addrs;
 };
 
 static inline struct rga_vb_buffer *vb_to_rga(struct vb2_v4l2_buffer *vb)

-- 
2.52.0



From s.pueschel at pengutronix.de  Wed Dec  3 07:52:34 2025
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Wed, 03 Dec 2025 16:52:34 +0100
Subject: [PATCH v2 12/22] media: rockchip: rga: use card type to specify
 rga type
In-Reply-To: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
Message-ID: <20251203-spu-rga3-v2-12-989a67947f71@pengutronix.de>

In preparation of the RGA3 support add a filed to the rga_hw struct
to specify the desired card type value. This allows the user to
differentiate the RGA2 and RGA3 video device nodes.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-hw.c | 1 +
 drivers/media/platform/rockchip/rga/rga.c    | 4 +++-
 drivers/media/platform/rockchip/rga/rga.h    | 1 +
 3 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index 2ed4f22a999d5..8953960d33bc5 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -617,6 +617,7 @@ static struct rga_fmt formats[] = {
 };
 
 const struct rga_hw rga2_hw = {
+	.card_type = "rga2",
 	.formats = formats,
 	.num_formats = ARRAY_SIZE(formats),
 	.cmdbuf_size = RGA_CMDBUF_SIZE,
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 46dc94db6f85e..c9719c7bcfc1c 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -306,8 +306,10 @@ static const struct v4l2_file_operations rga_fops = {
 static int
 vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
 {
+	struct rockchip_rga *rga = video_drvdata(file);
+
 	strscpy(cap->driver, RGA_NAME, sizeof(cap->driver));
-	strscpy(cap->card, "rockchip-rga", sizeof(cap->card));
+	strscpy(cap->card, rga->hw->card_type, sizeof(cap->card));
 	strscpy(cap->bus_info, "platform:rga", sizeof(cap->bus_info));
 
 	return 0;
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index d02d5730b4e3b..ee50f7f3ed601 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -147,6 +147,7 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
 };
 
 struct rga_hw {
+	const char *card_type;
 	struct rga_fmt *formats;
 	u32 num_formats;
 	size_t cmdbuf_size;

-- 
2.52.0



From s.pueschel at pengutronix.de  Wed Dec  3 07:52:39 2025
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Wed, 03 Dec 2025 16:52:39 +0100
Subject: [PATCH v2 17/22] media: rockchip: rga: remove stride from
 rga_frame
In-Reply-To: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
Message-ID: <20251203-spu-rga3-v2-17-989a67947f71@pengutronix.de>

Remove the stride variable from rga_frame. Despite the comment it
didn't involve any calculation and is just a copy of the
plane_fmt[0].bytesperline value. Therefore avoid this struct member
and use the bytesperline value directly in the places where it is
required.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-hw.c | 20 ++++++++++++--------
 drivers/media/platform/rockchip/rga/rga.c    |  5 +----
 drivers/media/platform/rockchip/rga/rga.h    |  3 ---
 3 files changed, 13 insertions(+), 15 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index fb0389ae8e132..4dee33d8f7206 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -43,7 +43,7 @@ rga_get_corner_addrs(struct rga_frame *frm, struct rga_addrs *addrs,
 	struct rga_corners_addrs corner_addrs;
 	struct rga_addrs *lt, *lb, *rt, *rb;
 	unsigned int x_div = 0,
-		     y_div = 0, uv_stride = 0, pixel_width = 0;
+		     y_div = 0, y_stride = 0, uv_stride = 0, pixel_width = 0;
 
 	lt = &corner_addrs.left_top;
 	lb = &corner_addrs.left_bottom;
@@ -52,14 +52,15 @@ rga_get_corner_addrs(struct rga_frame *frm, struct rga_addrs *addrs,
 
 	x_div = frm->fmt->x_div;
 	y_div = frm->fmt->y_div;
-	uv_stride = frm->stride / x_div;
-	pixel_width = frm->stride / frm->pix.width;
+	y_stride = frm->pix.plane_fmt[0].bytesperline;
+	uv_stride = y_stride / x_div;
+	pixel_width = y_stride / frm->pix.width;
 
-	lt->y_addr = addrs->y_addr + y * frm->stride + x * pixel_width;
+	lt->y_addr = addrs->y_addr + y * y_stride + x * pixel_width;
 	lt->u_addr = addrs->u_addr + (y / y_div) * uv_stride + x / x_div;
 	lt->v_addr = addrs->v_addr + (y / y_div) * uv_stride + x / x_div;
 
-	lb->y_addr = lt->y_addr + (h - 1) * frm->stride;
+	lb->y_addr = lt->y_addr + (h - 1) * y_stride;
 	lb->u_addr = lt->u_addr + (h / y_div - 1) * uv_stride;
 	lb->v_addr = lt->v_addr + (h / y_div - 1) * uv_stride;
 
@@ -160,6 +161,7 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
 	union rga_src_act_info src_act_info;
 	union rga_dst_vir_info dst_vir_info;
 	union rga_dst_act_info dst_act_info;
+	u32 in_stride, out_stride;
 
 	src_h = ctx->in.crop.height;
 	src_w = ctx->in.crop.width;
@@ -282,13 +284,15 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
 	 * Calculate the framebuffer virtual strides and active size,
 	 * note that the step of vir_stride / vir_width is 4 byte words
 	 */
-	src_vir_info.data.vir_stride = ctx->in.stride >> 2;
-	src_vir_info.data.vir_width = ctx->in.stride >> 2;
+	in_stride = ctx->in.pix.plane_fmt[0].bytesperline;
+	src_vir_info.data.vir_stride = in_stride >> 2;
+	src_vir_info.data.vir_width = in_stride >> 2;
 
 	src_act_info.data.act_height = src_h - 1;
 	src_act_info.data.act_width = src_w - 1;
 
-	dst_vir_info.data.vir_stride = ctx->out.stride >> 2;
+	out_stride = ctx->out.pix.plane_fmt[0].bytesperline;
+	dst_vir_info.data.vir_stride = out_stride >> 2;
 	dst_act_info.data.act_height = dst_h - 1;
 	dst_act_info.data.act_width = dst_w - 1;
 
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 0d7b0bcac950e..7e30fafb25fab 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -220,8 +220,6 @@ static int rga_open(struct file *file)
 		.fmt = &rga->hw->formats[0],
 	};
 
-	def_frame.stride = (def_width * def_frame.fmt->depth) >> 3;
-
 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
@@ -428,7 +426,6 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	if (IS_ERR(frm))
 		return PTR_ERR(frm);
 	frm->fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
-	frm->stride = pix_fmt->plane_fmt[0].bytesperline;
 
 	/* Reset crop settings */
 	frm->crop.left = 0;
@@ -442,7 +439,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 		 "[%s] fmt - %p4cc %dx%d (stride %d)\n",
 		  V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
 		  &frm->fmt->fourcc, pix_fmt->width, pix_fmt->height,
-		  frm->stride);
+		  pix_fmt->plane_fmt[0].bytesperline);
 
 	for (i = 0; i < pix_fmt->num_planes; i++) {
 		v4l2_dbg(debug, 1, &rga->v4l2_dev,
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index 466d568b9e614..a7f891b94a478 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -34,9 +34,6 @@ struct rga_frame {
 	/* Image format */
 	struct rga_fmt *fmt;
 	struct v4l2_pix_format_mplane pix;
-
-	/* Variables that can calculated once and reused */
-	u32 stride;
 };
 
 struct rga_dma_desc {

-- 
2.52.0



From s.pueschel at pengutronix.de  Wed Dec  3 07:52:38 2025
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Wed, 03 Dec 2025 16:52:38 +0100
Subject: [PATCH v2 16/22] media: rockchip: rga: remove size from rga_frame
In-Reply-To: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
Message-ID: <20251203-spu-rga3-v2-16-989a67947f71@pengutronix.de>

The size member is only used for the mmu page table mapping.
Therefore avoid storing the value and instead only calculate it
in place. This also avoids the calculation entirely when an external
iommu is used.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-buf.c | 6 +++++-
 drivers/media/platform/rockchip/rga/rga.c     | 8 ++------
 drivers/media/platform/rockchip/rga/rga.h     | 1 -
 3 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
index e8d1e2e579140..8de6b9c3fd615 100644
--- a/drivers/media/platform/rockchip/rga/rga-buf.c
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -79,9 +79,13 @@ static int rga_buf_init(struct vb2_buffer *vb)
 	struct rockchip_rga *rga = ctx->rga;
 	struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type);
 	size_t n_desc = 0;
+	u32 size = 0;
+	u8 i;
 
 	if (rga_has_internal_iommu(rga)) {
-		n_desc = DIV_ROUND_UP(f->size, PAGE_SIZE);
+		for (i = 0; i < f->pix.num_planes; i++)
+			size += f->pix.plane_fmt[i].sizeimage;
+		n_desc = DIV_ROUND_UP(size, PAGE_SIZE);
 
 		rbuf->n_desc = n_desc;
 		rbuf->dma_desc = dma_alloc_coherent(rga->dev,
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 1bfc4021f4a7b..0d7b0bcac950e 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -221,7 +221,6 @@ static int rga_open(struct file *file)
 	};
 
 	def_frame.stride = (def_width * def_frame.fmt->depth) >> 3;
-	def_frame.size = def_frame.stride * def_height;
 
 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
@@ -428,9 +427,6 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	frm = rga_get_frame(ctx, f->type);
 	if (IS_ERR(frm))
 		return PTR_ERR(frm);
-	frm->size = 0;
-	for (i = 0; i < pix_fmt->num_planes; i++)
-		frm->size += pix_fmt->plane_fmt[i].sizeimage;
 	frm->fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
 	frm->stride = pix_fmt->plane_fmt[0].bytesperline;
 
@@ -443,10 +439,10 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	frm->pix = *pix_fmt;
 
 	v4l2_dbg(debug, 1, &rga->v4l2_dev,
-		 "[%s] fmt - %p4cc %dx%d (stride %d, sizeimage %d)\n",
+		 "[%s] fmt - %p4cc %dx%d (stride %d)\n",
 		  V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
 		  &frm->fmt->fourcc, pix_fmt->width, pix_fmt->height,
-		  frm->stride, frm->size);
+		  frm->stride);
 
 	for (i = 0; i < pix_fmt->num_planes; i++) {
 		v4l2_dbg(debug, 1, &rga->v4l2_dev,
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index fc81bc5562792..466d568b9e614 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -37,7 +37,6 @@ struct rga_frame {
 
 	/* Variables that can calculated once and reused */
 	u32 stride;
-	u32 size;
 };
 
 struct rga_dma_desc {

-- 
2.52.0



From s.pueschel at pengutronix.de  Wed Dec  3 07:52:41 2025
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Wed, 03 Dec 2025 16:52:41 +0100
Subject: [PATCH v2 19/22] media: rockchip: rga: add feature flags
In-Reply-To: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
Message-ID: <20251203-spu-rga3-v2-19-989a67947f71@pengutronix.de>

In preparation to the RGA3 addition add feature flags, which can limit
the exposed feature set of the video device, like rotating or selection
support. This is necessary as the RGA3 doesn't initially implement the
full feature set currently exposed by the driver.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-hw.c |  4 ++++
 drivers/media/platform/rockchip/rga/rga.c    | 23 +++++++++++++++--------
 drivers/media/platform/rockchip/rga/rga.h    |  7 +++++++
 3 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index a868a34a1452e..0d1cf911af0d5 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -658,6 +658,10 @@ const struct rga_hw rga2_hw = {
 	.max_height = MAX_HEIGHT,
 	.max_scaling_factor = MAX_SCALING_FACTOR,
 	.stride_alignment = 4,
+	.features = RGA_FEATURE_FLIP
+		  | RGA_FEATURE_ROTATE
+		  | RGA_FEATURE_BG_COLOR
+		  | RGA_FEATURE_SELECTION,
 
 	.setup_cmdbuf = rga_hw_setup_cmdbuf,
 	.start = rga_hw_start,
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index c991cc64b4b7f..3958e71b8987d 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -162,17 +162,21 @@ static int rga_setup_ctrls(struct rga_ctx *ctx)
 
 	v4l2_ctrl_handler_init(&ctx->ctrl_handler, 4);
 
-	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
-			  V4L2_CID_HFLIP, 0, 1, 1, 0);
+	if (rga->hw->features & RGA_FEATURE_FLIP) {
+		v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
+				  V4L2_CID_HFLIP, 0, 1, 1, 0);
 
-	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
-			  V4L2_CID_VFLIP, 0, 1, 1, 0);
+		v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
+				  V4L2_CID_VFLIP, 0, 1, 1, 0);
+	}
 
-	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
-			  V4L2_CID_ROTATE, 0, 270, 90, 0);
+	if (rga->hw->features & RGA_FEATURE_ROTATE)
+		v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
+				  V4L2_CID_ROTATE, 0, 270, 90, 0);
 
-	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
-			  V4L2_CID_BG_COLOR, 0, 0xffffffff, 1, 0);
+	if (rga->hw->features & RGA_FEATURE_BG_COLOR)
+		v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
+				  V4L2_CID_BG_COLOR, 0, 0xffffffff, 1, 0);
 
 	if (ctx->ctrl_handler.error) {
 		int err = ctx->ctrl_handler.error;
@@ -489,6 +493,9 @@ static int vidioc_s_selection(struct file *file, void *priv,
 	struct rga_frame *f;
 	int ret = 0;
 
+	if (!(rga->hw->features & RGA_FEATURE_SELECTION))
+		return -EINVAL;
+
 	f = rga_get_frame(ctx, s->type);
 	if (IS_ERR(f))
 		return PTR_ERR(f);
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index 980f70f842317..b9c75b5fda4dc 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -6,6 +6,7 @@
 #ifndef __RGA_H__
 #define __RGA_H__
 
+#include <linux/bits.h>
 #include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <media/videobuf2-v4l2.h>
@@ -132,6 +133,11 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
 	rga_write(rga, reg, temp);
 };
 
+#define RGA_FEATURE_FLIP	BIT(0)
+#define RGA_FEATURE_ROTATE	BIT(1)
+#define RGA_FEATURE_BG_COLOR	BIT(2)
+#define RGA_FEATURE_SELECTION	BIT(3)
+
 struct rga_hw {
 	const char *card_type;
 	bool has_internal_iommu;
@@ -140,6 +146,7 @@ struct rga_hw {
 	u32 max_width, max_height;
 	u8 max_scaling_factor;
 	u8 stride_alignment;
+	u8 features;
 
 	void (*setup_cmdbuf)(struct rga_ctx *ctx);
 	void (*start)(struct rockchip_rga *rga,

-- 
2.52.0



From s.pueschel at pengutronix.de  Wed Dec  3 07:52:40 2025
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Wed, 03 Dec 2025 16:52:40 +0100
Subject: [PATCH v2 18/22] media: rockchip: rga: move rga_fmt to rga-hw.h
In-Reply-To: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
Message-ID: <20251203-spu-rga3-v2-18-989a67947f71@pengutronix.de>

Move rga_fmt to rga-hw in preparation of the RGA3 addition, as the struct
contains many RGA2 specific values. They are used to write the correct
register values quickly based on the chosen format. Therefore the
pointer to the rga_fmt struct is kept but changed to an opaque void
pointer outside of the rga-hw.h.

To enumerate and set the correct formats, two helper functions need to
be exposed in the rga_hw struct:

enum_format just get's the vidioc_enum_fmt format and it's return value
is also returned from vidioc_enum_fmt. This is a simple pass-through,
as the implementation is very simple.

adjust_and_map_format is a simple abstraction around the previous
rga_find_format. But unlike rga_find_format, it always returns a valid
format. Therefore the passed format value is also a pointer to update
it in case the values are not supported by the hardware.
Due to the RGA3 supporting different formats on the capture and output
side, an additional parameter is_capture has been added to support
this use-case.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-buf.c |  2 +-
 drivers/media/platform/rockchip/rga/rga-hw.c  | 53 +++++++++++++++++++++------
 drivers/media/platform/rockchip/rga/rga-hw.h  | 12 ++++++
 drivers/media/platform/rockchip/rga/rga.c     | 38 +++++--------------
 drivers/media/platform/rockchip/rga/rga.h     | 17 ++-------
 5 files changed, 68 insertions(+), 54 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
index 8de6b9c3fd615..b0f226f7f06d9 100644
--- a/drivers/media/platform/rockchip/rga/rga-buf.c
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -158,7 +158,7 @@ static int rga_buf_prepare(struct vb2_buffer *vb)
 	}
 
 	/* Fill the remaining planes */
-	info = v4l2_format_info(f->fmt->fourcc);
+	info = v4l2_format_info(f->pix.pixelformat);
 	for (i = info->mem_planes; i < info->comp_planes; i++)
 		dma_addrs[i] = dma_addrs[0] + get_plane_offset(f, info, i);
 
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index 4dee33d8f7206..a868a34a1452e 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -44,14 +44,15 @@ rga_get_corner_addrs(struct rga_frame *frm, struct rga_addrs *addrs,
 	struct rga_addrs *lt, *lb, *rt, *rb;
 	unsigned int x_div = 0,
 		     y_div = 0, y_stride = 0, uv_stride = 0, pixel_width = 0;
+	struct rga_fmt *fmt = frm->fmt;
 
 	lt = &corner_addrs.left_top;
 	lb = &corner_addrs.left_bottom;
 	rt = &corner_addrs.right_top;
 	rb = &corner_addrs.right_bottom;
 
-	x_div = frm->fmt->x_div;
-	y_div = frm->fmt->y_div;
+	x_div = fmt->x_div;
+	y_div = fmt->y_div;
 	y_stride = frm->pix.plane_fmt[0].bytesperline;
 	uv_stride = y_stride / x_div;
 	pixel_width = y_stride / frm->pix.width;
@@ -162,6 +163,8 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
 	union rga_dst_vir_info dst_vir_info;
 	union rga_dst_act_info dst_act_info;
 	u32 in_stride, out_stride;
+	struct rga_fmt *in_fmt = ctx->in.fmt;
+	struct rga_fmt *out_fmt = ctx->out.fmt;
 
 	src_h = ctx->in.crop.height;
 	src_w = ctx->in.crop.width;
@@ -177,18 +180,18 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
 	dst_vir_info.val = dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2];
 	dst_act_info.val = dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2];
 
-	src_info.data.format = ctx->in.fmt->hw_format;
-	src_info.data.swap = ctx->in.fmt->color_swap;
-	dst_info.data.format = ctx->out.fmt->hw_format;
-	dst_info.data.swap = ctx->out.fmt->color_swap;
+	src_info.data.format = in_fmt->hw_format;
+	src_info.data.swap = in_fmt->color_swap;
+	dst_info.data.format = out_fmt->hw_format;
+	dst_info.data.swap = out_fmt->color_swap;
 
 	/*
 	 * CSC mode must only be set when the colorspace families differ between
 	 * input and output. It must remain unset (zeroed) if both are the same.
 	 */
 
-	if (RGA_COLOR_FMT_IS_YUV(ctx->in.fmt->hw_format) &&
-	    RGA_COLOR_FMT_IS_RGB(ctx->out.fmt->hw_format)) {
+	if (RGA_COLOR_FMT_IS_YUV(in_fmt->hw_format) &&
+	    RGA_COLOR_FMT_IS_RGB(out_fmt->hw_format)) {
 		switch (ctx->in.pix.colorspace) {
 		case V4L2_COLORSPACE_REC709:
 			src_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
@@ -199,8 +202,8 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
 		}
 	}
 
-	if (RGA_COLOR_FMT_IS_RGB(ctx->in.fmt->hw_format) &&
-	    RGA_COLOR_FMT_IS_YUV(ctx->out.fmt->hw_format)) {
+	if (RGA_COLOR_FMT_IS_RGB(in_fmt->hw_format) &&
+	    RGA_COLOR_FMT_IS_YUV(out_fmt->hw_format)) {
 		switch (ctx->out.pix.colorspace) {
 		case V4L2_COLORSPACE_REC709:
 			dst_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
@@ -619,11 +622,35 @@ static struct rga_fmt formats[] = {
 	},
 };
 
+static void *rga_adjust_and_map_format(struct v4l2_pix_format_mplane *format,
+				       bool is_output)
+{
+	unsigned int i;
+
+	if (!format)
+		return &formats[0];
+
+	for (i = 0; i < ARRAY_SIZE(formats); i++) {
+		if (formats[i].fourcc == format->pixelformat)
+			return &formats[i];
+	}
+
+	format->pixelformat = formats[0].fourcc;
+	return &formats[0];
+}
+
+static int rga_enum_format(struct v4l2_fmtdesc *f)
+{
+	if (f->index >= ARRAY_SIZE(formats))
+		return -EINVAL;
+
+	f->pixelformat = formats[f->index].fourcc;
+	return 0;
+}
+
 const struct rga_hw rga2_hw = {
 	.card_type = "rga2",
 	.has_internal_iommu = true,
-	.formats = formats,
-	.num_formats = ARRAY_SIZE(formats),
 	.cmdbuf_size = RGA_CMDBUF_SIZE,
 	.min_width = MIN_WIDTH,
 	.max_width = MAX_WIDTH,
@@ -636,4 +663,6 @@ const struct rga_hw rga2_hw = {
 	.start = rga_hw_start,
 	.handle_irq = rga_handle_irq,
 	.get_version = rga_get_version,
+	.adjust_and_map_format = rga_adjust_and_map_format,
+	.enum_format = rga_enum_format,
 };
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.h b/drivers/media/platform/rockchip/rga/rga-hw.h
index fffcab0131225..3bc4b1f5acba2 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.h
+++ b/drivers/media/platform/rockchip/rga/rga-hw.h
@@ -6,6 +6,8 @@
 #ifndef __RGA_HW_H__
 #define __RGA_HW_H__
 
+#include <linux/types.h>
+
 #define RGA_CMDBUF_SIZE 0x20
 
 /* Hardware limits */
@@ -431,4 +433,14 @@ union rga_pat_con {
 	} data;
 };
 
+struct rga_fmt {
+	u32 fourcc;
+	int depth;
+	u8 uv_factor;
+	u8 y_div;
+	u8 x_div;
+	u8 color_swap;
+	u8 hw_format;
+};
+
 #endif
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 7e30fafb25fab..c991cc64b4b7f 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -185,17 +185,6 @@ static int rga_setup_ctrls(struct rga_ctx *ctx)
 	return 0;
 }
 
-static struct rga_fmt *rga_fmt_find(struct rockchip_rga *rga, u32 pixelformat)
-{
-	unsigned int i;
-
-	for (i = 0; i < rga->hw->num_formats; i++) {
-		if (rga->hw->formats[i].fourcc == pixelformat)
-			return &rga->hw->formats[i];
-	}
-	return NULL;
-}
-
 struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type)
 {
 	if (V4L2_TYPE_IS_OUTPUT(type))
@@ -217,7 +206,6 @@ static int rga_open(struct file *file)
 		.crop.top = 0,
 		.crop.width = def_width,
 		.crop.height = def_height,
-		.fmt = &rga->hw->formats[0],
 	};
 
 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
@@ -238,9 +226,11 @@ static int rga_open(struct file *file)
 	ctx->in = def_frame;
 	ctx->out = def_frame;
 
-	v4l2_fill_pixfmt_mp_aligned(&ctx->in.pix, ctx->in.fmt->fourcc,
+	ctx->in.fmt = rga->hw->adjust_and_map_format(&ctx->in.pix, true);
+	v4l2_fill_pixfmt_mp_aligned(&ctx->in.pix, ctx->in.pix.pixelformat,
 				    def_width, def_height, rga->hw->stride_alignment);
-	v4l2_fill_pixfmt_mp_aligned(&ctx->out.pix, ctx->out.fmt->fourcc,
+	ctx->out.fmt = rga->hw->adjust_and_map_format(&ctx->out.pix, false);
+	v4l2_fill_pixfmt_mp_aligned(&ctx->out.pix, ctx->out.pix.pixelformat,
 				    def_width, def_height, rga->hw->stride_alignment);
 
 	if (mutex_lock_interruptible(&rga->mutex)) {
@@ -322,15 +312,8 @@ vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
 static int vidioc_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f)
 {
 	struct rockchip_rga *rga = video_drvdata(file);
-	struct rga_fmt *fmt;
 
-	if (f->index >= rga->hw->num_formats)
-		return -EINVAL;
-
-	fmt = &rga->hw->formats[f->index];
-	f->pixelformat = fmt->fourcc;
-
-	return 0;
+	return rga->hw->enum_format(f);
 }
 
 static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
@@ -355,15 +338,13 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	struct rga_ctx *ctx = file_to_rga_ctx(file);
 	struct rockchip_rga *rga = ctx->rga;
 	const struct rga_hw *hw = rga->hw;
-	struct rga_fmt *fmt;
 	u32 min_width = hw->min_width;
 	u32 max_width = hw->max_width;
 	u32 min_height = hw->min_height;
 	u32 max_height = hw->max_height;
 
-	fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
-	if (!fmt)
-		fmt = &hw->formats[0];
+	hw->adjust_and_map_format(pix_fmt,
+				  V4L2_TYPE_IS_OUTPUT(f->type));
 
 	if (V4L2_TYPE_IS_OUTPUT(f->type) &&
 	    v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx)->streaming) {
@@ -425,7 +406,8 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	frm = rga_get_frame(ctx, f->type);
 	if (IS_ERR(frm))
 		return PTR_ERR(frm);
-	frm->fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
+	frm->fmt = rga->hw->adjust_and_map_format(pix_fmt,
+						  V4L2_TYPE_IS_OUTPUT(f->type));
 
 	/* Reset crop settings */
 	frm->crop.left = 0;
@@ -438,7 +420,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	v4l2_dbg(debug, 1, &rga->v4l2_dev,
 		 "[%s] fmt - %p4cc %dx%d (stride %d)\n",
 		  V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
-		  &frm->fmt->fourcc, pix_fmt->width, pix_fmt->height,
+		  &pix_fmt->pixelformat, pix_fmt->width, pix_fmt->height,
 		  pix_fmt->plane_fmt[0].bytesperline);
 
 	for (i = 0; i < pix_fmt->num_planes; i++) {
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index a7f891b94a478..980f70f842317 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -17,22 +17,12 @@
 #define DEFAULT_WIDTH 100
 #define DEFAULT_HEIGHT 100
 
-struct rga_fmt {
-	u32 fourcc;
-	int depth;
-	u8 uv_factor;
-	u8 y_div;
-	u8 x_div;
-	u8 color_swap;
-	u8 hw_format;
-};
-
 struct rga_frame {
 	/* Crop */
 	struct v4l2_rect crop;
 
 	/* Image format */
-	struct rga_fmt *fmt;
+	void *fmt;
 	struct v4l2_pix_format_mplane pix;
 };
 
@@ -145,8 +135,6 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
 struct rga_hw {
 	const char *card_type;
 	bool has_internal_iommu;
-	struct rga_fmt *formats;
-	u32 num_formats;
 	size_t cmdbuf_size;
 	u32 min_width, min_height;
 	u32 max_width, max_height;
@@ -158,6 +146,9 @@ struct rga_hw {
 		      struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
 	bool (*handle_irq)(struct rockchip_rga *rga);
 	void (*get_version)(struct rockchip_rga *rga);
+	void *(*adjust_and_map_format)(struct v4l2_pix_format_mplane *format,
+				       bool is_output);
+	int (*enum_format)(struct v4l2_fmtdesc *f);
 };
 
 static inline bool rga_has_internal_iommu(const struct rockchip_rga *rga)

-- 
2.52.0



From s.pueschel at pengutronix.de  Wed Dec  3 07:52:42 2025
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Wed, 03 Dec 2025 16:52:42 +0100
Subject: [PATCH v2 20/22] media: rockchip: rga: disable multi-core support
In-Reply-To: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
Message-ID: <20251203-spu-rga3-v2-20-989a67947f71@pengutronix.de>

Disable multi-core support in preparation of the RGA3 addition. The
RK3588 SoC features two equal RGA3 cores. This allows scheduling of the
work between both cores, which is not yet implemented. Until it is
implemented avoid exposing both cores as independent video devices to
prevent an ABI breakage when multi-core support is added.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 3958e71b8987d..65686228b7300 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -660,6 +660,30 @@ static int rga_parse_dt(struct rockchip_rga *rga)
 	return 0;
 }
 
+static int rga_disable_multicore(struct device *dev)
+{
+	const char *compatible;
+	struct device_node *node;
+	int ret;
+
+	/* Intentionally ignores the fallback strings */
+	ret = of_property_read_string(dev->of_node, "compatible", &compatible);
+	if (ret)
+		return ret;
+
+	/* first compatible node found from the root node is considered the main core */
+	node = of_find_compatible_node(NULL, NULL, compatible);
+	if (!node)
+		return -EINVAL; /* broken DT? */
+
+	if (dev->of_node != node) {
+		dev_info(dev, "missing multi-core support, ignoring this instance\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
 static int rga_probe(struct platform_device *pdev)
 {
 	struct rockchip_rga *rga;
@@ -670,6 +694,10 @@ static int rga_probe(struct platform_device *pdev)
 	if (!pdev->dev.of_node)
 		return -ENODEV;
 
+	ret = rga_disable_multicore(&pdev->dev);
+	if (ret)
+		return ret;
+
 	rga = devm_kzalloc(&pdev->dev, sizeof(*rga), GFP_KERNEL);
 	if (!rga)
 		return -ENOMEM;

-- 
2.52.0



From s.pueschel at pengutronix.de  Wed Dec  3 07:52:44 2025
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Wed, 03 Dec 2025 16:52:44 +0100
Subject: [PATCH v2 22/22] arm64: dts: rockchip: add rga3 dt nodes
In-Reply-To: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
Message-ID: <20251203-spu-rga3-v2-22-989a67947f71@pengutronix.de>

Add devicetree nodes for the RGA3 (Raster Graphics Acceleration 3)
peripheral in the RK3588.

The existing rga node refers to the RGA2 peripheral. The RK3588
contains one RGA2 core and two RGA3 cores. Both feature a similar
functionality of scaling, cropping and rotating of up to two input
images into one output image. Key differences of the RGA3 are:

- supports 10bit YUV output formats
- supports 8x8 tiles and FBCD as inputs and outputs
- supports BT2020 color space conversion
- max output resolution of (8192-64)x(8192-64)
- MMU can map up to 32G DDR RAM
- fully planar formats (3 planes) are not supported
- max scale up/down factor of 8

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 arch/arm64/boot/dts/rockchip/rk3588-base.dtsi | 46 +++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
index e2500e31c434a..11bad1f41a864 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
@@ -1273,6 +1273,52 @@ rga: rga at fdb80000 {
 		power-domains = <&power RK3588_PD_VDPU>;
 	};
 
+	rga3_core0: rga at fdb60000 {
+		compatible = "rockchip,rk3588-rga3";
+		reg = <0x0 0xfdb60000 0x0 0x200>;
+		interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH 0>;
+		interrupt-names = "rga3_core0_irq";
+		clocks = <&cru ACLK_RGA3_0>, <&cru HCLK_RGA3_0>, <&cru CLK_RGA3_0_CORE>;
+		clock-names = "aclk", "hclk", "sclk";
+		resets = <&cru SRST_RGA3_0_CORE>, <&cru SRST_A_RGA3_0>, <&cru SRST_H_RGA3_0>;
+		reset-names = "core", "axi", "ahb";
+		power-domains = <&power RK3588_PD_RGA30>;
+		iommus = <&rga3_0_mmu>;
+	};
+
+	rga3_0_mmu: iommu at fdb60f00 {
+		compatible = "rockchip,rk3588-iommu", "rockchip,rk3568-iommu";
+		reg = <0x0 0xfdb60f00 0x0 0x100>;
+		interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH 0>;
+		clocks = <&cru ACLK_RGA3_0>, <&cru HCLK_RGA3_0>;
+		clock-names = "aclk", "iface";
+		#iommu-cells = <0>;
+		power-domains = <&power RK3588_PD_RGA30>;
+	};
+
+	rga3_core1: rga at fdb70000 {
+		compatible = "rockchip,rk3588-rga3";
+		reg = <0x0 0xfdb70000 0x0 0x200>;
+		interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH 0>;
+		interrupt-names = "rga3_core1_irq";
+		clocks = <&cru ACLK_RGA3_1>, <&cru HCLK_RGA3_1>, <&cru CLK_RGA3_1_CORE>;
+		clock-names = "aclk", "hclk", "sclk";
+		resets = <&cru SRST_RGA3_1_CORE>, <&cru SRST_A_RGA3_1>, <&cru SRST_H_RGA3_1>;
+		reset-names = "core", "axi", "ahb";
+		power-domains = <&power RK3588_PD_RGA31>;
+		iommus = <&rga3_1_mmu>;
+	};
+
+	rga3_1_mmu: iommu at fdb70f00 {
+		compatible = "rockchip,rk3588-iommu", "rockchip,rk3568-iommu";
+		reg = <0x0 0xfdb70f00 0x0 0x100>;
+		interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH 0>;
+		clocks = <&cru ACLK_RGA3_1>, <&cru HCLK_RGA3_1>;
+		clock-names = "aclk", "iface";
+		#iommu-cells = <0>;
+		power-domains = <&power RK3588_PD_RGA31>;
+	};
+
 	vepu121_0: video-codec at fdba0000 {
 		compatible = "rockchip,rk3588-vepu121";
 		reg = <0x0 0xfdba0000 0x0 0x800>;

-- 
2.52.0



From s.pueschel at pengutronix.de  Wed Dec  3 07:52:43 2025
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Wed, 03 Dec 2025 16:52:43 +0100
Subject: [PATCH v2 21/22] media: rockchip: rga: add rga3 support
In-Reply-To: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
Message-ID: <20251203-spu-rga3-v2-21-989a67947f71@pengutronix.de>

Add support for the RGA3 unit contained in the RK3588.

Only a basic feature set consisting of scaling and color conversion is
implemented. Also the BT601F color space conversion is currently hard
coded. Currently unimplemented features include:
- Advanced formats like 10bit YUV, FBCE mode and Tile8x8 mode
- Colorspace conversions functions BT601L, BT709, BT2020
- Background color (V4L2_CID_BG_COLOR)
- Configurable alpha value (V4L2_CID_ALPHA_COMPONENT)
- Image flipping (V4L2_CID_HFLIP and V4L2_CID_VFLIP)
- Image rotation (V4L2_CID_ROTATE)
- Image cropping/composing (VIDIOC_S_SELECTION)

The register address defines were copied from the
vendor Rockchip kernel sources and slightly adjusted to not start at 0
again for the cmd registers.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/Makefile  |   2 +-
 drivers/media/platform/rockchip/rga/rga.c     |   4 +
 drivers/media/platform/rockchip/rga/rga.h     |   2 +-
 drivers/media/platform/rockchip/rga/rga3-hw.c | 471 ++++++++++++++++++++++++++
 drivers/media/platform/rockchip/rga/rga3-hw.h | 190 +++++++++++
 5 files changed, 667 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/Makefile b/drivers/media/platform/rockchip/rga/Makefile
index 1bbecdc3d8df2..7326a548f3dc7 100644
--- a/drivers/media/platform/rockchip/rga/Makefile
+++ b/drivers/media/platform/rockchip/rga/Makefile
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
-rockchip-rga-objs := rga.o rga-hw.o rga-buf.o
+rockchip-rga-objs := rga.o rga-hw.o rga3-hw.o rga-buf.o
 
 obj-$(CONFIG_VIDEO_ROCKCHIP_RGA) += rockchip-rga.o
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 65686228b7300..313d875c789bf 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -843,6 +843,10 @@ static const struct of_device_id rockchip_rga_match[] = {
 		.compatible = "rockchip,rk3399-rga",
 		.data = &rga2_hw,
 	},
+	{
+		.compatible = "rockchip,rk3588-rga3",
+		.data = &rga3_hw,
+	},
 	{},
 };
 
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index b9c75b5fda4dc..2c5f0330879fa 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -163,6 +163,6 @@ static inline bool rga_has_internal_iommu(const struct rockchip_rga *rga)
 	return rga->hw->has_internal_iommu;
 }
 
-extern const struct rga_hw rga2_hw;
+extern const struct rga_hw rga2_hw, rga3_hw;
 
 #endif
diff --git a/drivers/media/platform/rockchip/rga/rga3-hw.c b/drivers/media/platform/rockchip/rga/rga3-hw.c
new file mode 100644
index 0000000000000..2b8cd639da39b
--- /dev/null
+++ b/drivers/media/platform/rockchip/rga/rga3-hw.c
@@ -0,0 +1,471 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) Pengutronix e.K.
+ * Author: Sven P?schel <s.pueschel at pengutronix.de>
+ */
+
+#include <linux/pm_runtime.h>
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/printk.h>
+
+#include <media/v4l2-common.h>
+
+#include "rga3-hw.h"
+#include "rga.h"
+
+static unsigned int rga3_get_scaling(unsigned int src, unsigned int dst)
+{
+	/*
+	 * RGA3 scaling factor calculation as described in chapter 5.4.7 Resize
+	 * of the TRM Part 2. The resulting scaling factor is a 16-bit value
+	 * and therefore normalized with 2^16.
+	 *
+	 * While the TRM also mentions (dst-1)/(src-1) for the up-scaling case,
+	 * it didn't work as the value always exceeds 16 bit. Flipping the
+	 * factors results in a correct up-scaling. This is possible as the
+	 * RGA3 has the RGA3_WIN_SCALE_XXX_UP bit to determine if it does
+	 * an up or downscale.
+	 *
+	 * With a scaling factor of 1.0 the calculation technically also
+	 * overflows 16 bit. This isn't relevant, as in this case the
+	 * RGA3_WIN_SCALE_XXX_BYPASS bit completely skips the scaling operation.
+	 */
+	if (dst > src) {
+		if (((src - 1) << 16) % (dst - 1) == 0)
+			return ((src - 1) << 16) / (dst - 1) - 1;
+		else
+			return ((src - 1) << 16) / (dst - 1);
+	} else {
+		return ((dst - 1) << 16) / (src - 1) + 1;
+	}
+}
+
+/*
+ * Check if the given format can be captured, as the RGA3 doesn't support all
+ * input formats also on it's output.
+ */
+static bool rga3_can_capture(const struct rga3_fmt *fmt)
+{
+	return fmt->hw_format <= RGA3_COLOR_FMT_LAST_OUTPUT;
+}
+
+/*
+ * Map the transformations to the RGA3 command buffer.
+ * Currently this is just the scaling settings and a fixed alpha value.
+ */
+static void rga3_cmd_set_trans_info(struct rga_ctx *ctx)
+{
+	u32 *cmd = ctx->cmdbuf_virt;
+	unsigned int src_h, src_w, dst_h, dst_w;
+	unsigned int reg;
+	u16 hor_scl_fac, ver_scl_fac;
+	const struct rga3_fmt *in = ctx->in.fmt;
+
+	src_h = ctx->in.pix.height;
+	src_w = ctx->in.pix.width;
+	dst_h = ctx->out.pix.height;
+	dst_w = ctx->out.pix.width;
+
+	reg = RGA3_WIN0_RD_CTRL - RGA3_FIRST_CMD_REG;
+	cmd[reg >> 2] |= FIELD_PREP(RGA3_WIN_SCALE_HOR_UP, dst_w > src_w)
+		      |  FIELD_PREP(RGA3_WIN_SCALE_HOR_BYPASS, dst_w == src_w)
+		      |  FIELD_PREP(RGA3_WIN_SCALE_VER_UP, dst_h > src_h)
+		      |  FIELD_PREP(RGA3_WIN_SCALE_VER_BYPASS, dst_h == src_h);
+
+	hor_scl_fac = rga3_get_scaling(src_w, dst_w);
+	ver_scl_fac = rga3_get_scaling(src_h, dst_h);
+	reg = RGA3_WIN0_SCL_FAC - RGA3_FIRST_CMD_REG;
+	cmd[reg >> 2] = FIELD_PREP(RGA3_SCALE_HOR_FAC, hor_scl_fac)
+		      | FIELD_PREP(RGA3_SCALE_VER_FAC, ver_scl_fac);
+
+	if (v4l2_format_info(in->fourcc)->has_alpha) {
+		/* copy alpha from input */
+		reg = RGA3_OVLP_TOP_ALPHA - RGA3_FIRST_CMD_REG;
+		cmd[reg >> 2] = FIELD_PREP(RGA3_ALPHA_SELECT_MODE, 1)
+			      | FIELD_PREP(RGA3_ALPHA_BLEND_MODE, 1);
+		reg = RGA3_OVLP_BOT_ALPHA - RGA3_FIRST_CMD_REG;
+		cmd[reg >> 2] = FIELD_PREP(RGA3_ALPHA_SELECT_MODE, 1)
+			      | FIELD_PREP(RGA3_ALPHA_BLEND_MODE, 1);
+	} else {
+		/* just use a 255 alpha value */
+		reg = RGA3_OVLP_TOP_CTRL - RGA3_FIRST_CMD_REG;
+		cmd[reg >> 2] = FIELD_PREP(RGA3_OVLP_GLOBAL_ALPHA, 0xff)
+			      | FIELD_PREP(RGA3_OVLP_COLOR_MODE, 1);
+		reg = RGA3_OVLP_BOT_CTRL - RGA3_FIRST_CMD_REG;
+		cmd[reg >> 2] = FIELD_PREP(RGA3_OVLP_GLOBAL_ALPHA, 0xff)
+			      | FIELD_PREP(RGA3_OVLP_COLOR_MODE, 1);
+	}
+}
+
+static void rga3_cmd_set_win0_addr(struct rga_ctx *ctx,
+				   const struct rga_addrs *addrs)
+{
+	u32 *cmd = ctx->cmdbuf_virt;
+	unsigned int reg;
+
+	reg = RGA3_WIN0_Y_BASE - RGA3_FIRST_CMD_REG;
+	cmd[reg >> 2] = addrs->y_addr;
+	reg = RGA3_WIN0_U_BASE - RGA3_FIRST_CMD_REG;
+	cmd[reg >> 2] = addrs->u_addr;
+}
+
+static void rga3_cmd_set_wr_addr(struct rga_ctx *ctx,
+				 const struct rga_addrs *addrs)
+{
+	u32 *cmd = ctx->cmdbuf_virt;
+	unsigned int reg;
+
+	reg = RGA3_WR_Y_BASE - RGA3_FIRST_CMD_REG;
+	cmd[reg >> 2] = addrs->y_addr;
+	reg = RGA3_WR_U_BASE - RGA3_FIRST_CMD_REG;
+	cmd[reg >> 2] = addrs->u_addr;
+}
+
+/* Map the input pixel format to win0 of the comamnd buffer. */
+static void rga3_cmd_set_win0_format(struct rga_ctx *ctx)
+{
+	u32 *cmd = ctx->cmdbuf_virt;
+	const struct rga3_fmt *in = ctx->in.fmt;
+	const struct rga3_fmt *out = ctx->out.fmt;
+	const struct v4l2_format_info *in_fmt, *out_fmt;
+	unsigned int src_h, src_w;
+	bool r2y, y2r;
+	u8 rd_format;
+	unsigned int reg;
+
+	src_h = ctx->in.pix.height;
+	src_w = ctx->in.pix.width;
+
+	in_fmt = v4l2_format_info(in->fourcc);
+	out_fmt = v4l2_format_info(out->fourcc);
+	r2y = v4l2_is_format_rgb(in_fmt) && v4l2_is_format_yuv(out_fmt);
+	y2r = v4l2_is_format_yuv(in_fmt) && v4l2_is_format_rgb(out_fmt);
+
+	if (in->semi_planar)
+		rd_format = RGA3_RDWR_FORMAT_SEMI_PLANAR;
+	else
+		rd_format = RGA3_RDWR_FORMAT_INTERLEAVED;
+
+	/* set pixel format and CSC */
+	reg = RGA3_WIN0_RD_CTRL - RGA3_FIRST_CMD_REG;
+	cmd[reg >> 2] |= FIELD_PREP(RGA3_WIN_PIC_FORMAT, in->hw_format)
+		      |  FIELD_PREP(RGA3_WIN_YC_SWAP, in->yc_swap)
+		      |  FIELD_PREP(RGA3_WIN_RBUV_SWAP, in->rbuv_swap)
+		      |  FIELD_PREP(RGA3_WIN_RD_FORMAT, rd_format)
+		      |  FIELD_PREP(RGA3_WIN_R2Y, r2y)
+		      |  FIELD_PREP(RGA3_WIN_Y2R, y2r)
+		      |  FIELD_PREP(RGA3_WIN_CSC_MODE, RGA3_WIN_CSC_MODE_BT601_F);
+
+	/* set stride */
+	reg = RGA3_WIN0_VIR_STRIDE - RGA3_FIRST_CMD_REG;
+	/* stride needs to be in words */
+	cmd[reg >> 2] = ctx->in.pix.plane_fmt[0].bytesperline >> 2;
+	reg = RGA3_WIN0_UV_VIR_STRIDE - RGA3_FIRST_CMD_REG;
+	/* The Hardware only supports formats with 1/2 planes */
+	if (ctx->in.pix.num_planes == 2)
+		cmd[reg >> 2] = ctx->in.pix.plane_fmt[1].bytesperline >> 2;
+	else
+		cmd[reg >> 2] = ctx->in.pix.plane_fmt[0].bytesperline >> 2;
+
+	/* set size */
+	reg = RGA3_WIN0_ACT_SIZE - RGA3_FIRST_CMD_REG;
+	cmd[reg >> 2] = FIELD_PREP(RGA3_WIDTH, src_w)
+		      | FIELD_PREP(RGA3_HEIGHT, src_h);
+	/* no cropping support. Use same value as ACT_SIZE */
+	reg = RGA3_WIN0_SRC_SIZE - RGA3_FIRST_CMD_REG;
+	cmd[reg >> 2] = FIELD_PREP(RGA3_WIDTH, src_w)
+		      | FIELD_PREP(RGA3_HEIGHT, src_h);
+}
+
+static void rga3_cmd_enable_win0(struct rga_ctx *ctx)
+{
+	u32 *cmd = ctx->cmdbuf_virt;
+	unsigned int reg;
+
+	reg = RGA3_WIN0_RD_CTRL - RGA3_FIRST_CMD_REG;
+	cmd[reg >> 2] |= FIELD_PREP(RGA3_WIN_ENABLE, 1);
+}
+
+/* Map the output pixel format to the command buffer */
+static void rga3_cmd_set_wr_format(struct rga_ctx *ctx)
+{
+	u32 *cmd = ctx->cmdbuf_virt;
+	const struct rga3_fmt *out = ctx->out.fmt;
+	unsigned int dst_h, dst_w;
+	u8 wr_format;
+	unsigned int reg;
+
+	dst_h = ctx->out.pix.height;
+	dst_w = ctx->out.pix.width;
+
+	if (out->semi_planar)
+		wr_format = RGA3_RDWR_FORMAT_SEMI_PLANAR;
+	else
+		wr_format = RGA3_RDWR_FORMAT_INTERLEAVED;
+
+	/* set pixel format */
+	reg = RGA3_WR_CTRL - RGA3_FIRST_CMD_REG;
+	cmd[reg >> 2] |= FIELD_PREP(RGA3_WR_PIC_FORMAT, out->hw_format)
+		      |  FIELD_PREP(RGA3_WR_YC_SWAP, out->yc_swap)
+		      |  FIELD_PREP(RGA3_WR_RBUV_SWAP, out->rbuv_swap)
+		      |  FIELD_PREP(RGA3_WR_FORMAT, wr_format);
+
+	/* set stride */
+	reg = RGA3_WR_VIR_STRIDE - RGA3_FIRST_CMD_REG;
+	/* stride needs to be in words */
+	cmd[reg >> 2] = ctx->out.pix.plane_fmt[0].bytesperline >> 2;
+	reg = RGA3_WR_PL_VIR_STRIDE - RGA3_FIRST_CMD_REG;
+	/* The Hardware only supports formats with 1/2 planes */
+	if (ctx->out.pix.num_planes == 2)
+		cmd[reg >> 2] = ctx->out.pix.plane_fmt[1].bytesperline >> 2;
+	else
+		cmd[reg >> 2] = ctx->out.pix.plane_fmt[0].bytesperline >> 2;
+
+	/* Set size.
+	 * As two inputs are not supported, we don't use win1.
+	 * Therefore only set the size for win0.
+	 */
+	reg = RGA3_WIN0_DST_SIZE - RGA3_FIRST_CMD_REG;
+	cmd[reg >> 2] = FIELD_PREP(RGA3_WIDTH, dst_w)
+		      | FIELD_PREP(RGA3_HEIGHT, dst_h);
+}
+
+static void rga3_cmd_disable_wr_limitation(struct rga_ctx *ctx)
+{
+	u32 *cmd = ctx->cmdbuf_virt;
+	unsigned int reg;
+
+	/* Use the max value to avoid limiting the write speed */
+	reg = RGA3_WR_CTRL - RGA3_FIRST_CMD_REG;
+	cmd[reg >> 2] |= FIELD_PREP(RGA3_WR_SW_OUTSTANDING_MAX, 63);
+}
+
+static void rga3_hw_setup_cmdbuf(struct rga_ctx *ctx)
+{
+	memset(ctx->cmdbuf_virt, 0, RGA3_CMDBUF_SIZE * 4);
+
+	rga3_cmd_set_win0_format(ctx);
+	rga3_cmd_enable_win0(ctx);
+	rga3_cmd_set_trans_info(ctx);
+	rga3_cmd_set_wr_format(ctx);
+	rga3_cmd_disable_wr_limitation(ctx);
+}
+
+static void rga3_hw_start(struct rockchip_rga *rga,
+			  struct rga_vb_buffer *src, struct rga_vb_buffer *dst)
+{
+	struct rga_ctx *ctx = rga->curr;
+
+	rga3_cmd_set_win0_addr(ctx, &src->dma_addrs);
+	rga3_cmd_set_wr_addr(ctx, &dst->dma_addrs);
+
+	rga_write(rga, RGA3_CMD_ADDR, ctx->cmdbuf_phy);
+
+	/* sync CMD buf for RGA */
+	dma_sync_single_for_device(rga->dev, ctx->cmdbuf_phy,
+				   PAGE_SIZE, DMA_BIDIRECTIONAL);
+
+	/* set to master mode and start the conversion */
+	rga_write(rga, RGA3_SYS_CTRL,
+		  FIELD_PREP(RGA3_CMD_MODE, RGA3_CMD_MODE_MASTER));
+	rga_write(rga, RGA3_INT_EN, FIELD_PREP(RGA3_INT_FRM_DONE, 1));
+	rga_write(rga, RGA3_CMD_CTRL,
+		  FIELD_PREP(RGA3_CMD_LINE_START_PULSE, 1));
+}
+
+static bool rga3_handle_irq(struct rockchip_rga *rga)
+{
+	u32 intr;
+
+	intr = rga_read(rga, RGA3_INT_RAW);
+	/* clear all interrupts */
+	rga_write(rga, RGA3_INT_CLR, intr);
+
+	return FIELD_GET(RGA3_INT_FRM_DONE, intr);
+}
+
+static void rga3_get_version(struct rockchip_rga *rga)
+{
+	u32 version = rga_read(rga, RGA3_VERSION_NUM);
+
+	rga->version.major = FIELD_GET(RGA3_VERSION_NUM_MAJOR, version);
+	rga->version.minor = FIELD_GET(RGA3_VERSION_NUM_MINOR, version);
+}
+
+static struct rga3_fmt rga3_formats[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_RGB24,
+		.hw_format = RGA3_COLOR_FMT_BGR888,
+		.rbuv_swap = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_BGR24,
+		.hw_format = RGA3_COLOR_FMT_BGR888,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_ABGR32,
+		.hw_format = RGA3_COLOR_FMT_BGRA8888,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_RGBA32,
+		.hw_format = RGA3_COLOR_FMT_BGRA8888,
+		.rbuv_swap = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_XBGR32,
+		.hw_format = RGA3_COLOR_FMT_BGRA8888,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_RGBX32,
+		.hw_format = RGA3_COLOR_FMT_BGRA8888,
+		.rbuv_swap = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_RGB565,
+		.hw_format = RGA3_COLOR_FMT_BGR565,
+		.rbuv_swap = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV12M,
+		.hw_format = RGA3_COLOR_FMT_YUV420,
+		.semi_planar = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV12,
+		.hw_format = RGA3_COLOR_FMT_YUV420,
+		.semi_planar = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV21M,
+		.hw_format = RGA3_COLOR_FMT_YUV420,
+		.rbuv_swap = 1,
+		.semi_planar = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV21,
+		.hw_format = RGA3_COLOR_FMT_YUV420,
+		.rbuv_swap = 1,
+		.semi_planar = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV16M,
+		.hw_format = RGA3_COLOR_FMT_YUV422,
+		.semi_planar = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV16,
+		.hw_format = RGA3_COLOR_FMT_YUV422,
+		.semi_planar = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV61M,
+		.hw_format = RGA3_COLOR_FMT_YUV422,
+		.rbuv_swap = 1,
+		.semi_planar = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV61,
+		.hw_format = RGA3_COLOR_FMT_YUV422,
+		.rbuv_swap = 1,
+		.semi_planar = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_YUYV,
+		.hw_format = RGA3_COLOR_FMT_YUV422,
+		.yc_swap = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_YVYU,
+		.hw_format = RGA3_COLOR_FMT_YUV422,
+		.yc_swap = 1,
+		.rbuv_swap = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_UYVY,
+		.hw_format = RGA3_COLOR_FMT_YUV422,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_VYUY,
+		.hw_format = RGA3_COLOR_FMT_YUV422,
+		.rbuv_swap = 1,
+	},
+	/* Input only formats last to keep rga3_enum_format simple */
+	{
+		.fourcc = V4L2_PIX_FMT_ARGB32,
+		.hw_format = RGA3_COLOR_FMT_ABGR8888,
+		.rbuv_swap = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_BGRA32,
+		.hw_format = RGA3_COLOR_FMT_ABGR8888,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_XRGB32,
+		.hw_format = RGA3_COLOR_FMT_ABGR8888,
+		.rbuv_swap = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_BGRX32,
+		.hw_format = RGA3_COLOR_FMT_ABGR8888,
+	},
+};
+
+static int rga3_enum_format(struct v4l2_fmtdesc *f)
+{
+	struct rga3_fmt *fmt;
+
+	if (f->index >= ARRAY_SIZE(rga3_formats))
+		return -EINVAL;
+
+	fmt = &rga3_formats[f->index];
+	if (V4L2_TYPE_IS_CAPTURE(f->type) && !rga3_can_capture(fmt))
+		return -EINVAL;
+
+	f->pixelformat = fmt->fourcc;
+	return 0;
+}
+
+static void *rga3_adjust_and_map_format(struct v4l2_pix_format_mplane *format,
+					bool is_output)
+{
+	unsigned int i;
+
+	if (!format)
+		return &rga3_formats[0];
+
+	format->ycbcr_enc = V4L2_YCBCR_ENC_601;
+	format->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+
+	for (i = 0; i < ARRAY_SIZE(rga3_formats); i++) {
+		if (!is_output && !rga3_can_capture(&rga3_formats[i]))
+			continue;
+
+		if (rga3_formats[i].fourcc == format->pixelformat)
+			return &rga3_formats[i];
+	}
+
+	format->pixelformat = rga3_formats[0].fourcc;
+	return &rga3_formats[0];
+}
+
+const struct rga_hw rga3_hw = {
+	.card_type = "rga3",
+	.has_internal_iommu = false,
+	.cmdbuf_size = RGA3_CMDBUF_SIZE,
+	.min_width = RGA3_MIN_WIDTH,
+	.min_height = RGA3_MIN_HEIGHT,
+	/* use output size, as it's a bit smaller than the input size */
+	.max_width = RGA3_MAX_OUTPUT_WIDTH,
+	.max_height = RGA3_MAX_OUTPUT_HEIGHT,
+	.max_scaling_factor = RGA3_MAX_SCALING_FACTOR,
+	.stride_alignment = 16,
+	.features = 0,
+
+	.setup_cmdbuf = rga3_hw_setup_cmdbuf,
+	.start = rga3_hw_start,
+	.handle_irq = rga3_handle_irq,
+	.get_version = rga3_get_version,
+	.enum_format = rga3_enum_format,
+	.adjust_and_map_format = rga3_adjust_and_map_format,
+};
diff --git a/drivers/media/platform/rockchip/rga/rga3-hw.h b/drivers/media/platform/rockchip/rga/rga3-hw.h
new file mode 100644
index 0000000000000..fa16b95fb43ba
--- /dev/null
+++ b/drivers/media/platform/rockchip/rga/rga3-hw.h
@@ -0,0 +1,190 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) Pengutronix e.K.
+ * Author: Sven P?schel <s.pueschel at pengutronix.de>
+ */
+#ifndef __RGA3_HW_H__
+#define __RGA3_HW_H__
+
+#include <linux/bits.h>
+#include <linux/types.h>
+
+#define RGA3_CMDBUF_SIZE 0x2e
+
+#define RGA3_MIN_WIDTH 128
+#define RGA3_MIN_HEIGHT 128
+#define RGA3_MAX_INPUT_WIDTH (8192 - 16)
+#define RGA3_MAX_INPUT_HEIGHT (8192 - 16)
+#define RGA3_MAX_OUTPUT_WIDTH (8192 - 64)
+#define RGA3_MAX_OUTPUT_HEIGHT (8192 - 64)
+#define RGA3_MAX_SCALING_FACTOR 8
+#define RGA3_RESET_TIMEOUT 1000
+
+/* Registers address */
+/* sys reg */
+#define RGA3_SYS_CTRL				0x000
+#define RGA3_CMD_CTRL				0x004
+#define RGA3_CMD_ADDR				0x008
+#define RGA3_MI_GROUP_CTRL			0x00c
+#define RGA3_ARQOS_CTRL				0x010
+#define RGA3_VERSION_NUM			0x018
+#define RGA3_VERSION_TIM			0x01c
+#define RGA3_INT_EN				0x020
+#define RGA3_INT_RAW				0x024
+#define RGA3_INT_MSK				0x028
+#define RGA3_INT_CLR				0x02c
+#define RGA3_RO_SRST				0x030
+#define RGA3_STATUS0				0x034
+#define RGA3_SCAN_CNT				0x038
+#define RGA3_CMD_STATE				0x040
+
+/* cmd reg */
+#define RGA3_WIN0_RD_CTRL			0x100
+#define RGA3_FIRST_CMD_REG			RGA3_WIN0_RD_CTRL
+#define RGA3_WIN0_Y_BASE			0x110
+#define RGA3_WIN0_U_BASE			0x114
+#define RGA3_WIN0_V_BASE			0x118
+#define RGA3_WIN0_VIR_STRIDE			0x11c
+#define RGA3_WIN0_FBC_OFF			0x120
+#define RGA3_WIN0_SRC_SIZE			0x124
+#define RGA3_WIN0_ACT_OFF			0x128
+#define RGA3_WIN0_ACT_SIZE			0x12c
+#define RGA3_WIN0_DST_SIZE			0x130
+#define RGA3_WIN0_SCL_FAC			0x134
+#define RGA3_WIN0_UV_VIR_STRIDE			0x138
+#define RGA3_WIN1_RD_CTRL			0x140
+#define RGA3_WIN1_Y_BASE			0x150
+#define RGA3_WIN1_U_BASE			0x154
+#define RGA3_WIN1_V_BASE			0x158
+#define RGA3_WIN1_VIR_STRIDE			0x15c
+#define RGA3_WIN1_FBC_OFF			0x160
+#define RGA3_WIN1_SRC_SIZE			0x164
+#define RGA3_WIN1_ACT_OFF			0x168
+#define RGA3_WIN1_ACT_SIZE			0x16c
+#define RGA3_WIN1_DST_SIZE			0x170
+#define RGA3_WIN1_SCL_FAC			0x174
+#define RGA3_WIN1_UV_VIR_STRIDE			0x178
+#define RGA3_OVLP_CTRL				0x180
+#define RGA3_OVLP_OFF				0x184
+#define RGA3_OVLP_TOP_KEY_MIN			0x188
+#define RGA3_OVLP_TOP_KEY_MAX			0x18c
+#define RGA3_OVLP_TOP_CTRL			0x190
+#define RGA3_OVLP_BOT_CTRL			0x194
+#define RGA3_OVLP_TOP_ALPHA			0x198
+#define RGA3_OVLP_BOT_ALPHA			0x19c
+#define RGA3_WR_CTRL				0x1a0
+#define RGA3_WR_FBCE_CTRL			0x1a4
+#define RGA3_WR_VIR_STRIDE			0x1a8
+#define RGA3_WR_PL_VIR_STRIDE			0x1ac
+#define RGA3_WR_Y_BASE				0x1b0
+#define RGA3_WR_U_BASE				0x1b4
+#define RGA3_WR_V_BASE				0x1b8
+
+/* Registers value */
+#define RGA3_COLOR_FMT_YUV420		0x0
+#define RGA3_COLOR_FMT_YUV422		0x1
+#define RGA3_COLOR_FMT_YUV420_10B	0x2
+#define RGA3_COLOR_FMT_YUV422_10B	0x3
+/*
+ * Use memory ordering names
+ * instead of the datasheet naming RGB formats in big endian order
+ */
+#define RGA3_COLOR_FMT_BGR565		0x4
+#define RGA3_COLOR_FMT_BGR888		0x5
+#define RGA3_COLOR_FMT_FIRST_HAS_ALPHA	RGA3_COLOR_FMT_BGRA8888
+#define RGA3_COLOR_FMT_BGRA8888		0x6
+#define RGA3_COLOR_FMT_LAST_OUTPUT	RGA3_COLOR_FMT_BGRA8888
+/* the following are only supported as inputs */
+#define RGA3_COLOR_FMT_ABGR8888		0x7
+/*
+ * the following seem to be unnecessary,
+ * as they can be achieved with RB swaps
+ */
+#define RGA3_COLOR_FMT_RGBA8888		0x8
+#define RGA3_COLOR_FMT_ARGB8888		0x9
+
+#define RGA3_RDWR_FORMAT_SEMI_PLANAR	0x1
+#define RGA3_RDWR_FORMAT_INTERLEAVED	0x2
+
+#define RGA3_CMD_MODE_MASTER 0x1
+
+#define RGA3_WIN_CSC_MODE_BT601_F 0x2
+
+/* RGA masks */
+/* SYS_CTRL */
+#define RGA3_CCLK_SRESET BIT(4)
+#define RGA3_ACLK_SRESET BIT(3)
+#define RGA3_CMD_MODE BIT(1)
+
+/* CMD_CTRL */
+#define RGA3_CMD_LINE_START_PULSE BIT(0)
+
+/* VERSION_NUM */
+#define RGA3_VERSION_NUM_MAJOR GENMASK(31, 28)
+#define RGA3_VERSION_NUM_MINOR GENMASK(27, 20)
+
+/* INT_* */
+#define RGA3_INT_FRM_DONE BIT(0)
+#define RGA3_INT_DMA_READ_BUS_ERR BIT(2)
+#define RGA3_INT_WIN0_FBC_DEC_ERR BIT(5)
+#define RGA3_INT_WIN0_HOR_ERR BIT(6)
+#define RGA3_INT_WIN0_VER_ERR BIT(7)
+#define RGA3_INT_WR_VER_ERR BIT(13)
+#define RGA3_INT_WR_HOR_ERR BIT(14)
+#define RGA3_INT_WR_BUS_ERR BIT(15)
+#define RGA3_INT_WIN0_IN_FIFO_WR_ERR BIT(16)
+#define RGA3_INT_WIN0_IN_FIFO_RD_ERR BIT(17)
+#define RGA3_INT_WIN0_HOR_FIFO_WR_ERR BIT(18)
+#define RGA3_INT_WIN0_HOR_FIFO_RD_ERR BIT(19)
+#define RGA3_INT_WIN0_VER_FIFO_WR_ERR BIT(20)
+#define RGA3_INT_WIN0_VER_FIFO_RD_ERR BIT(21)
+
+/* RO_SRST */
+#define RGA3_RO_SRST_DONE GENMASK(5, 0)
+
+/* *_SIZE */
+#define RGA3_HEIGHT GENMASK(28, 16)
+#define RGA3_WIDTH GENMASK(12, 0)
+
+/* SCL_FAC */
+#define RGA3_SCALE_VER_FAC GENMASK(31, 16)
+#define RGA3_SCALE_HOR_FAC GENMASK(15, 0)
+
+/* WINx_CTRL */
+#define RGA3_WIN_CSC_MODE GENMASK(27, 26)
+#define RGA3_WIN_R2Y BIT(25)
+#define RGA3_WIN_Y2R BIT(24)
+#define RGA3_WIN_SCALE_VER_UP BIT(23)
+#define RGA3_WIN_SCALE_VER_BYPASS BIT(22)
+#define RGA3_WIN_SCALE_HOR_UP BIT(21)
+#define RGA3_WIN_SCALE_HOR_BYPASS BIT(20)
+#define RGA3_WIN_YC_SWAP BIT(13)
+#define RGA3_WIN_RBUV_SWAP BIT(12)
+#define RGA3_WIN_RD_FORMAT GENMASK(9, 8)
+#define RGA3_WIN_PIC_FORMAT GENMASK(7, 4)
+#define RGA3_WIN_ENABLE BIT(0)
+
+/* COLOR_CTRL */
+#define RGA3_OVLP_GLOBAL_ALPHA GENMASK(23, 16)
+#define RGA3_OVLP_COLOR_MODE BIT(0)
+
+/* ALPHA_CTRL */
+#define RGA3_ALPHA_SELECT_MODE BIT(4)
+#define RGA3_ALPHA_BLEND_MODE GENMASK(3, 2)
+
+/* WR_CTRL */
+#define RGA3_WR_YC_SWAP BIT(20)
+#define RGA3_WR_SW_OUTSTANDING_MAX GENMASK(18, 13)
+#define RGA3_WR_RBUV_SWAP BIT(12)
+#define RGA3_WR_FORMAT GENMASK(9, 8)
+#define RGA3_WR_PIC_FORMAT GENMASK(7, 4)
+
+struct rga3_fmt {
+	u32 fourcc;
+	u8 hw_format;
+	bool rbuv_swap;
+	bool yc_swap;
+	bool semi_planar;
+};
+
+#endif

-- 
2.52.0



From venkat88 at linux.ibm.com  Wed Dec  3 08:08:46 2025
From: venkat88 at linux.ibm.com (Venkat)
Date: Wed, 3 Dec 2025 21:38:46 +0530
Subject: [PATCH v5 00/12] Nesting support for lazy MMU mode
In-Reply-To: <20251124132228.622678-1-kevin.brodsky@arm.com>
References: <20251124132228.622678-1-kevin.brodsky@arm.com>
Message-ID: <94889730-1AEF-458F-B623-04092C0D6819@linux.ibm.com>



> On 24 Nov 2025, at 6:52?PM, Kevin Brodsky <kevin.brodsky at arm.com> wrote:
> 
> When the lazy MMU mode was introduced eons ago, it wasn't made clear
> whether such a sequence was legal:
> 
> arch_enter_lazy_mmu_mode()
> ...
> arch_enter_lazy_mmu_mode()
> ...
> arch_leave_lazy_mmu_mode()
> ...
> arch_leave_lazy_mmu_mode()
> 
> It seems fair to say that nested calls to
> arch_{enter,leave}_lazy_mmu_mode() were not expected, and most
> architectures never explicitly supported it.
> 
> Nesting does in fact occur in certain configurations, and avoiding it
> has proved difficult. This series therefore enables lazy_mmu sections to
> nest, on all architectures.
> 
> Nesting is handled using a counter in task_struct (patch 8), like other
> stateless APIs such as pagefault_{disable,enable}(). This is fully
> handled in a new generic layer in <linux/pgtable.h>; the arch_* API
> remains unchanged. A new pair of calls, lazy_mmu_mode_{pause,resume}(),
> is also introduced to allow functions that are called with the lazy MMU
> mode enabled to temporarily pause it, regardless of nesting.
> 
> An arch now opts in to using the lazy MMU mode by selecting
> CONFIG_ARCH_LAZY_MMU; this is more appropriate now that we have a
> generic API, especially with state conditionally added to task_struct.
> 
> ---
> 
> Background: Ryan Roberts' series from March [1] attempted to prevent
> nesting from ever occurring, and mostly succeeded. Unfortunately, a
> corner case (DEBUG_PAGEALLOC) may still cause nesting to occur on arm64.
> Ryan proposed [2] to address that corner case at the generic level but
> this approach received pushback; [3] then attempted to solve the issue
> on arm64 only, but it was deemed too fragile.
> 
> It feels generally difficult to guarantee that lazy_mmu sections don't
> nest, because callers of various standard mm functions do not know if
> the function uses lazy_mmu itself.
> 
> The overall approach in v3/v4 is very close to what David Hildenbrand
> proposed on v2 [4].
> 
> Unlike in v1/v2, no special provision is made for architectures to
> save/restore extra state when entering/leaving the mode. Based on the
> discussions so far, this does not seem to be required - an arch can
> store any relevant state in thread_struct during arch_enter() and
> restore it in arch_leave(). Nesting is not a concern as these functions
> are only called at the top level, not in nested sections.
> 
> The introduction of a generic layer, and tracking of the lazy MMU state
> in task_struct, also allows to streamline the arch callbacks - this
> series removes 67 lines from arch/.
> 
> Patch overview:
> 
> * Patch 1: cleanup - avoids having to deal with the powerpc
>  context-switching code
> 
> * Patch 2-4: prepare arch_flush_lazy_mmu_mode() to be called from the
>  generic layer (patch 8)
> 
> * Patch 5-6: new API + CONFIG_ARCH_LAZY_MMU
> 
> * Patch 7: ensure correctness in interrupt context
> 
> * Patch 8: nesting support
> 
> * Patch 9-12: replace arch-specific tracking of lazy MMU mode with
>  generic API
> 
> This series has been tested by running the mm kselftests on arm64 with
> DEBUG_VM, DEBUG_PAGEALLOC, KFENCE and KASAN. It was also build-tested on
> other architectures (with and without XEN_PV on x86).
> 
> - Kevin
> 
> [1] https://lore.kernel.org/all/20250303141542.3371656-1-ryan.roberts at arm.com/
> [2] https://lore.kernel.org/all/20250530140446.2387131-1-ryan.roberts at arm.com/
> [3] https://lore.kernel.org/all/20250606135654.178300-1-ryan.roberts at arm.com/
> [4] https://lore.kernel.org/all/ef343405-c394-4763-a79f-21381f217b6c at redhat.com/
> ---
> Changelog
> 
> v4..v5:
> 
> - Rebased on mm-unstable
> - Patch 3: added missing radix_enabled() check in arch_flush()
>  [Ritesh Harjani]
> - Patch 6: declare arch_flush_lazy_mmu_mode() as static inline on x86
>  [Ryan Roberts]
> - Patch 7 (formerly 12): moved before patch 8 to ensure correctness in
>  interrupt context [Ryan]. The diffs in in_lazy_mmu_mode() and
>  queue_pte_barriers() are moved to patch 8 and 9 resp.
> - Patch 8:
>  * Removed all restrictions regarding lazy_mmu_mode_{pause,resume}().
>    They may now be called even when lazy MMU isn't enabled, and
>    any call to lazy_mmu_mode_* may be made while paused (such calls
>    will be ignored). [David, Ryan]
>  * lazy_mmu_state.{nesting_level,active} are replaced with
>    {enable_count,pause_count} to track arbitrary nesting of both
>    enable/disable and pause/resume [Ryan]
>  * Added __task_lazy_mmu_mode_active() for use in patch 12 [David]
>  * Added documentation for all the functions [Ryan]
> - Patch 9: keep existing test + set TIF_LAZY_MMU_PENDING instead of
>  atomic RMW [David, Ryan]
> - Patch 12: use __task_lazy_mmu_mode_active() instead of accessing
>  lazy_mmu_state directly [David]
> - Collected R-b/A-b tags
> 
> v4: https://lore.kernel.org/all/20251029100909.3381140-1-kevin.brodsky at arm.com/
> 
> v3..v4:
> 
> - Patch 2: restored ordering of preempt_{disable,enable}() [Dave Hansen]
> - Patch 5 onwards: s/ARCH_LAZY_MMU/ARCH_HAS_LAZY_MMU_MODE/ [Mike Rapoport]
> - Patch 7: renamed lazy_mmu_state members, removed VM_BUG_ON(),
>  reordered writes to lazy_mmu_state members [David Hildenbrand]
> - Dropped patch 13 as it doesn't seem justified [David H]
> - Various improvements to commit messages [David H]
> 
> v3: https://lore.kernel.org/all/20251015082727.2395128-1-kevin.brodsky at arm.com/
> 
> v2..v3:
> 
> - Full rewrite; dropped all Acked-by/Reviewed-by.
> - Rebased on v6.18-rc1.
> 
> v2: https://lore.kernel.org/all/20250908073931.4159362-1-kevin.brodsky at arm.com/
> 
> v1..v2:
> - Rebased on mm-unstable.
> - Patch 2: handled new calls to enter()/leave(), clarified how the "flush"
>  pattern (leave() followed by enter()) is handled.
> - Patch 5,6: removed unnecessary local variable [Alexander Gordeev's
>  suggestion].
> - Added Mike Rapoport's Acked-by.
> 
> v1: https://lore.kernel.org/all/20250904125736.3918646-1-kevin.brodsky at arm.com/
> ---
> Cc: Alexander Gordeev <agordeev at linux.ibm.com>
> Cc: Andreas Larsson <andreas at gaisler.com>
> Cc: Andrew Morton <akpm at linux-foundation.org>
> Cc: Boris Ostrovsky <boris.ostrovsky at oracle.com>
> Cc: Borislav Petkov <bp at alien8.de>
> Cc: Catalin Marinas <catalin.marinas at arm.com>
> Cc: Christophe Leroy <christophe.leroy at csgroup.eu>
> Cc: Dave Hansen <dave.hansen at linux.intel.com>
> Cc: David Hildenbrand <david at redhat.com>
> Cc: "David S. Miller" <davem at davemloft.net>
> Cc: David Woodhouse <dwmw2 at infradead.org>
> Cc: "H. Peter Anvin" <hpa at zytor.com>
> Cc: Ingo Molnar <mingo at redhat.com>
> Cc: Jann Horn <jannh at google.com>
> Cc: Juergen Gross <jgross at suse.com>
> Cc: "Liam R. Howlett" <Liam.Howlett at oracle.com>
> Cc: Lorenzo Stoakes <lorenzo.stoakes at oracle.com>
> Cc: Madhavan Srinivasan <maddy at linux.ibm.com>
> Cc: Michael Ellerman <mpe at ellerman.id.au>
> Cc: Michal Hocko <mhocko at suse.com>
> Cc: Mike Rapoport <rppt at kernel.org>
> Cc: Nicholas Piggin <npiggin at gmail.com>
> Cc: Peter Zijlstra <peterz at infradead.org>
> Cc: Ritesh Harjani (IBM) <ritesh.list at gmail.com>
> Cc: Ryan Roberts <ryan.roberts at arm.com>
> Cc: Suren Baghdasaryan <surenb at google.com>
> Cc: Thomas Gleixner <tglx at linutronix.de>
> Cc: Venkat Rao Bagalkote <venkat88 at linux.ibm.com>
> Cc: Vlastimil Babka <vbabka at suse.cz>
> Cc: Will Deacon <will at kernel.org>
> Cc: Yeoreum Yun <yeoreum.yun at arm.com>
> Cc: linux-arm-kernel at lists.infradead.org
> Cc: linux-kernel at vger.kernel.org
> Cc: linuxppc-dev at lists.ozlabs.org
> Cc: sparclinux at vger.kernel.org
> Cc: xen-devel at lists.xenproject.org
> Cc: x86 at kernel.org
> ---
> Alexander Gordeev (1):
>  powerpc/64s: Do not re-activate batched TLB flush
> 
> Kevin Brodsky (11):
>  x86/xen: simplify flush_lazy_mmu()
>  powerpc/mm: implement arch_flush_lazy_mmu_mode()
>  sparc/mm: implement arch_flush_lazy_mmu_mode()
>  mm: introduce CONFIG_ARCH_HAS_LAZY_MMU_MODE
>  mm: introduce generic lazy_mmu helpers
>  mm: bail out of lazy_mmu_mode_* in interrupt context
>  mm: enable lazy_mmu sections to nest
>  arm64: mm: replace TIF_LAZY_MMU with in_lazy_mmu_mode()
>  powerpc/mm: replace batch->active with in_lazy_mmu_mode()
>  sparc/mm: replace batch->active with in_lazy_mmu_mode()
>  x86/xen: use lazy_mmu_state when context-switching
> 
> arch/arm64/Kconfig                            |   1 +
> arch/arm64/include/asm/pgtable.h              |  41 +----
> arch/arm64/include/asm/thread_info.h          |   3 +-
> arch/arm64/mm/mmu.c                           |   4 +-
> arch/arm64/mm/pageattr.c                      |   4 +-
> .../include/asm/book3s/64/tlbflush-hash.h     |  20 ++-
> arch/powerpc/include/asm/thread_info.h        |   2 -
> arch/powerpc/kernel/process.c                 |  25 ---
> arch/powerpc/mm/book3s64/hash_tlb.c           |  10 +-
> arch/powerpc/mm/book3s64/subpage_prot.c       |   4 +-
> arch/powerpc/platforms/Kconfig.cputype        |   1 +
> arch/sparc/Kconfig                            |   1 +
> arch/sparc/include/asm/tlbflush_64.h          |   5 +-
> arch/sparc/mm/tlb.c                           |  14 +-
> arch/x86/Kconfig                              |   1 +
> arch/x86/boot/compressed/misc.h               |   1 +
> arch/x86/boot/startup/sme.c                   |   1 +
> arch/x86/include/asm/paravirt.h               |   1 -
> arch/x86/include/asm/pgtable.h                |   1 +
> arch/x86/include/asm/thread_info.h            |   4 +-
> arch/x86/xen/enlighten_pv.c                   |   3 +-
> arch/x86/xen/mmu_pv.c                         |   6 +-
> fs/proc/task_mmu.c                            |   4 +-
> include/linux/mm_types_task.h                 |   5 +
> include/linux/pgtable.h                       | 147 +++++++++++++++++-
> include/linux/sched.h                         |  45 ++++++
> mm/Kconfig                                    |   3 +
> mm/kasan/shadow.c                             |   8 +-
> mm/madvise.c                                  |  18 +--
> mm/memory.c                                   |  16 +-
> mm/migrate_device.c                           |   8 +-
> mm/mprotect.c                                 |   4 +-
> mm/mremap.c                                   |   4 +-
> mm/userfaultfd.c                              |   4 +-
> mm/vmalloc.c                                  |  12 +-
> mm/vmscan.c                                   |  12 +-
> 36 files changed, 282 insertions(+), 161 deletions(-)

Tested this patch series by applying on top of mm-unstable, on both HASH and RADIX MMU, and all tests are passed on both MMU?s.

Ran: cache_shape, copyloops, mm from linux source, selftests/powerpc/ and ran memory-hotplug from selftests/. Also ran below tests from avocado misc-test repo.

Link to repo: https://github.com/avocado-framework-tests/avocado-misc-tests

avocado-misc-tests/memory/stutter.py
avocado-misc-tests/memory/eatmemory.py
avocado-misc-tests/memory/hugepage_sanity.py
avocado-misc-tests/memory/fork_mem.py
avocado-misc-tests/memory/memory_api.py
avocado-misc-tests/memory/mprotect.py
avocado-misc-tests/memory/vatest.py avocado-misc-tests/memory/vatest.py.data/vatest.yaml
avocado-misc-tests/memory/transparent_hugepages.py
avocado-misc-tests/memory/transparent_hugepages_swapping.py
avocado-misc-tests/memory/transparent_hugepages_defrag.py
avocado-misc-tests/memory/ksm_poison.py

If its good enough, please add below tag for PowerPC changes.

Tested-by: Venkat Rao Bagalkote <venkat88 at linux.ibm.com>

Regards,
Venkat.
> 
> 
> base-commit: 1f1edd95f9231ba58a1e535b10200cb1eeaf1f67
> -- 
> 2.51.2
> 



From suzuki.poulose at arm.com  Wed Dec  3 08:15:48 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Wed, 3 Dec 2025 16:15:48 +0000
Subject: [PATCH v6 2/9] coresight: core: add a new API to retrieve the
 helper device
In-Reply-To: <20250908-enable-byte-cntr-for-tmc-v6-2-1db9e621441a@oss.qualcomm.com>
References: <20250908-enable-byte-cntr-for-tmc-v6-0-1db9e621441a@oss.qualcomm.com>
 <20250908-enable-byte-cntr-for-tmc-v6-2-1db9e621441a@oss.qualcomm.com>
Message-ID: <d8c6111f-28ba-4046-bcd5-67233e8ed4ca@arm.com>

On 08/09/2025 03:01, Jie Gan wrote:
> Retrieving the helper device of the specific coresight device based on
> its helper_subtype because a single coresight device may has multiple types
> of the helper devices.
> 
> Reviewed-by: Mike Leach <mike.leach at linaro.org>
> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
> ---
>   drivers/hwtracing/coresight/coresight-core.c | 35 ++++++++++++++++++++++++++++
>   drivers/hwtracing/coresight/coresight-priv.h |  2 ++
>   2 files changed, 37 insertions(+)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
> index 042c4fa39e55..018b1119c48a 100644
> --- a/drivers/hwtracing/coresight/coresight-core.c
> +++ b/drivers/hwtracing/coresight/coresight-core.c
> @@ -580,6 +580,41 @@ struct coresight_device *coresight_get_sink(struct coresight_path *path)
>   }
>   EXPORT_SYMBOL_GPL(coresight_get_sink);
>   
> +/**
> + * coresight_get_helper: find the helper device of the assigned csdev.
> + *
> + * @csdev: The csdev the helper device is conntected to.
> + * @type:  helper_subtype of the expected helper device.
> + *
> + * Retrieve the helper device for the specific csdev based on its
> + * helper_subtype.
> + *
> + * Return: the helper's csdev upon success or NULL for fail.
> + */
> +struct coresight_device *coresight_get_helper(struct coresight_device *csdev,

> +					      int type)

nit: enum coresight_dev_subtype_helper subtype

Otherwise looks good to me

Suzuki

> +{
> +	int i;
> +	struct coresight_device *helper;
> +
> +	/* protect the connections */
> +	mutex_lock(&coresight_mutex);
> +	for (i = 0; i < csdev->pdata->nr_outconns; ++i) {
> +		helper = csdev->pdata->out_conns[i]->dest_dev;
> +		if (!helper || !coresight_is_helper(helper))
> +			continue;
> +
> +		if (helper->subtype.helper_subtype == type) {
> +			mutex_unlock(&coresight_mutex);
> +			return helper;
> +		}
> +	}
> +	mutex_unlock(&coresight_mutex);
> +
> +	return NULL;
> +}
> +EXPORT_SYMBOL_GPL(coresight_get_helper);
> +
>   /**
>    * coresight_get_in_port_dest: get the in-port number of the dest device
>    * that is connected to the src device.
> diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
> index e51b22b8ebde..f80122827934 100644
> --- a/drivers/hwtracing/coresight/coresight-priv.h
> +++ b/drivers/hwtracing/coresight/coresight-priv.h
> @@ -158,6 +158,8 @@ void coresight_path_assign_trace_id(struct coresight_path *path,
>   				   enum cs_mode mode);
>   int coresight_get_in_port_dest(struct coresight_device *src,
>   			       struct coresight_device *dest);
> +struct coresight_device *coresight_get_helper(struct coresight_device *csdev,
> +					      int type);
>   
>   #if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM3X)
>   int etm_readl_cp14(u32 off, unsigned int *val);
> 



From joey.gouly at arm.com  Wed Dec  3 08:17:15 2025
From: joey.gouly at arm.com (Joey Gouly)
Date: Wed, 3 Dec 2025 16:17:15 +0000
Subject: [PATCH 4/4] KVM: arm64: Convert VTCR_EL2 to config-driven
 sanitisation
In-Reply-To: <20251129144525.2609207-5-maz@kernel.org>
References: <20251129144525.2609207-1-maz@kernel.org>
 <20251129144525.2609207-5-maz@kernel.org>
Message-ID: <20251203161715.GA4187196@e124191.cambridge.arm.com>

Hi!

On Sat, Nov 29, 2025 at 02:45:25PM +0000, Marc Zyngier wrote:
> Describe all the VTCR_EL2 fields and their respective configurations,
> making sure that we correctly ignore the bits that are not defined
> for a given guest configuration.
> 
> Signed-off-by: Marc Zyngier <maz at kernel.org>
> ---
>  arch/arm64/kvm/config.c | 69 +++++++++++++++++++++++++++++++++++++++++
>  arch/arm64/kvm/nested.c |  3 +-
>  2 files changed, 70 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
> index a02c28d6a61c9..c36e133c51912 100644
> --- a/arch/arm64/kvm/config.c
> +++ b/arch/arm64/kvm/config.c
> @@ -141,6 +141,7 @@ struct reg_feat_map_desc {
>  #define FEAT_AA64EL1		ID_AA64PFR0_EL1, EL1, IMP
>  #define FEAT_AA64EL2		ID_AA64PFR0_EL1, EL2, IMP
>  #define FEAT_AA64EL3		ID_AA64PFR0_EL1, EL3, IMP
> +#define FEAT_SEL2		ID_AA64PFR0_EL1, SEL2, IMP
>  #define FEAT_AIE		ID_AA64MMFR3_EL1, AIE, IMP
>  #define FEAT_S2POE		ID_AA64MMFR3_EL1, S2POE, IMP
>  #define FEAT_S1POE		ID_AA64MMFR3_EL1, S1POE, IMP
> @@ -202,6 +203,8 @@ struct reg_feat_map_desc {
>  #define FEAT_ASID2		ID_AA64MMFR4_EL1, ASID2, IMP
>  #define FEAT_MEC		ID_AA64MMFR3_EL1, MEC, IMP
>  #define FEAT_HAFT		ID_AA64MMFR1_EL1, HAFDBS, HAFT
> +#define FEAT_HDBSS		ID_AA64MMFR1_EL1, HAFDBS, HDBSS
> +#define FEAT_HPDS2		ID_AA64MMFR1_EL1, HPDS, HPDS2
>  #define FEAT_BTI		ID_AA64PFR1_EL1, BT, IMP
>  #define FEAT_ExS		ID_AA64MMFR0_EL1, EXS, IMP
>  #define FEAT_IESB		ID_AA64MMFR2_EL1, IESB, IMP
> @@ -219,6 +222,7 @@ struct reg_feat_map_desc {
>  #define FEAT_FGT2		ID_AA64MMFR0_EL1, FGT, FGT2
>  #define FEAT_MTPMU		ID_AA64DFR0_EL1, MTPMU, IMP
>  #define FEAT_HCX		ID_AA64MMFR1_EL1, HCX, IMP
> +#define FEAT_S2PIE		ID_AA64MMFR3_EL1, S2PIE, IMP
>  
>  static bool not_feat_aa64el3(struct kvm *kvm)
>  {
> @@ -362,6 +366,28 @@ static bool feat_pmuv3p9(struct kvm *kvm)
>  	return check_pmu_revision(kvm, V3P9);
>  }
>  
> +#define has_feat_s2tgran(k, s)						\
> +  ((kvm_has_feat_enum(kvm, ID_AA64MMFR0_EL1, TGRAN##s##_2, TGRAN##s) && \
> +    !kvm_has_feat_enum(kvm, ID_AA64MMFR0_EL1, TGRAN##s, NI))	     ||	\
> +   kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN##s##_2, IMP))
> +
> +static bool feat_lpa2(struct kvm *kvm)
> +{
> +	return ((kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4, 52_BIT)    ||
> +		 !kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4, IMP))	&&
> +		(kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16, 52_BIT)   ||
> +		 !kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16, IMP))	&&
> +		(kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4_2, 52_BIT)  ||
> +		 !has_feat_s2tgran(kvm, 4))				&&
> +		(kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16_2, 52_BIT) ||
> +		 !has_feat_s2tgran(kvm, 16)));
> +}
> +
> +static bool feat_vmid16(struct kvm *kvm)
> +{
> +	return kvm_has_feat_enum(kvm, ID_AA64MMFR1_EL1, VMIDBits, 16);
> +}
> +
>  static bool compute_hcr_rw(struct kvm *kvm, u64 *bits)
>  {
>  	/* This is purely academic: AArch32 and NV are mutually exclusive */
> @@ -1168,6 +1194,44 @@ static const struct reg_bits_to_feat_map mdcr_el2_feat_map[] = {
>  static const DECLARE_FEAT_MAP(mdcr_el2_desc, MDCR_EL2,
>  			      mdcr_el2_feat_map, FEAT_AA64EL2);
>  
> +static const struct reg_bits_to_feat_map vtcr_el2_feat_map[] = {
> +	NEEDS_FEAT(VTCR_EL2_HDBSS, FEAT_HDBSS),
> +	NEEDS_FEAT(VTCR_EL2_HAFT, FEAT_HAFT),
> +	NEEDS_FEAT(VTCR_EL2_TL0		|
> +		   VTCR_EL2_TL1		|
> +		   VTCR_EL2_AssuredOnly	|
> +		   VTCR_EL2_GCSH,
> +		   FEAT_THE),

The text for VTCR_EL2.AssuredOnly says:

	This field is RES0 when VTCR_EL2.D128 is 1.

> +	NEEDS_FEAT(VTCR_EL2_D128, FEAT_D128),
> +	NEEDS_FEAT(VTCR_EL2_S2POE, FEAT_S2POE),
> +	NEEDS_FEAT(VTCR_EL2_S2PIE, FEAT_S2PIE),

The text for VTCR_EL2.S2PIE says:

	This field is RES1 when VTCR_EL2.D128 is set.


Are these cases that need to be handled here somehow?

Thanks,
Joey


> +	NEEDS_FEAT(VTCR_EL2_SL2		|
> +		   VTCR_EL2_DS,
> +		   feat_lpa2),
> +	NEEDS_FEAT(VTCR_EL2_NSA		|
> +		   VTCR_EL2_NSW,
> +		   FEAT_SEL2),
> +	NEEDS_FEAT(VTCR_EL2_HWU62	|
> +		   VTCR_EL2_HWU61	|
> +		   VTCR_EL2_HWU60	|
> +		   VTCR_EL2_HWU59,
> +		   FEAT_HPDS2),
> +	NEEDS_FEAT(VTCR_EL2_HD, ID_AA64MMFR1_EL1, HAFDBS, DBM),
> +	NEEDS_FEAT(VTCR_EL2_HA, ID_AA64MMFR1_EL1, HAFDBS, AF),
> +	NEEDS_FEAT(VTCR_EL2_VS, feat_vmid16),
> +	NEEDS_FEAT(VTCR_EL2_PS		|
> +		   VTCR_EL2_TG0		|
> +		   VTCR_EL2_SH0		|
> +		   VTCR_EL2_ORGN0	|
> +		   VTCR_EL2_IRGN0	|
> +		   VTCR_EL2_SL0		|
> +		   VTCR_EL2_T0SZ,
> +		   FEAT_AA64EL1),
> +};
> +
> +static const DECLARE_FEAT_MAP(vtcr_el2_desc, VTCR_EL2,
> +			      vtcr_el2_feat_map, FEAT_AA64EL2);
> +
>  static void __init check_feat_map(const struct reg_bits_to_feat_map *map,
>  				  int map_size, u64 res0, const char *str)
>  {
> @@ -1211,6 +1275,7 @@ void __init check_feature_map(void)
>  	check_reg_desc(&tcr2_el2_desc);
>  	check_reg_desc(&sctlr_el1_desc);
>  	check_reg_desc(&mdcr_el2_desc);
> +	check_reg_desc(&vtcr_el2_desc);
>  }
>  
>  static bool idreg_feat_match(struct kvm *kvm, const struct reg_bits_to_feat_map *map)
> @@ -1425,6 +1490,10 @@ void get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg, u64 *res0, u64 *r
>  		*res0 = compute_reg_res0_bits(kvm, &mdcr_el2_desc, 0, 0);
>  		*res1 = MDCR_EL2_RES1;
>  		break;
> +	case VTCR_EL2:
> +		*res0 = compute_reg_res0_bits(kvm, &vtcr_el2_desc, 0, 0);
> +		*res1 = VTCR_EL2_RES1;
> +		break;
>  	default:
>  		WARN_ON_ONCE(1);
>  		*res0 = *res1 = 0;
> diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
> index e1ef8930c97b3..606cebcaa7c09 100644
> --- a/arch/arm64/kvm/nested.c
> +++ b/arch/arm64/kvm/nested.c
> @@ -1719,8 +1719,7 @@ int kvm_init_nv_sysregs(struct kvm_vcpu *vcpu)
>  	set_sysreg_masks(kvm, VTTBR_EL2, res0, res1);
>  
>  	/* VTCR_EL2 */
> -	res0 = GENMASK(63, 32) | GENMASK(30, 20);
> -	res1 = BIT(31);
> +	get_reg_fixed_bits(kvm, VTCR_EL2, &res0, &res1);
>  	set_sysreg_masks(kvm, VTCR_EL2, res0, res1);
>  
>  	/* VMPIDR_EL2 */
> -- 
> 2.47.3
> 


From suzuki.poulose at arm.com  Wed Dec  3 08:18:17 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Wed, 3 Dec 2025 16:18:17 +0000
Subject: [PATCH v6 1/9] coresight: core: Refactoring ctcu_get_active_port
 and make it generic
In-Reply-To: <20250908-enable-byte-cntr-for-tmc-v6-1-1db9e621441a@oss.qualcomm.com>
References: <20250908-enable-byte-cntr-for-tmc-v6-0-1db9e621441a@oss.qualcomm.com>
 <20250908-enable-byte-cntr-for-tmc-v6-1-1db9e621441a@oss.qualcomm.com>
Message-ID: <29a61f75-df0b-41da-9c8d-3e2ced0a9ce7@arm.com>

On 08/09/2025 03:01, Jie Gan wrote:
> Remove ctcu_get_active_port from CTCU module and add it to the core
> framework.
> 
> The port number is crucial for the CTCU device to identify which ETR
> it serves. With the port number we can correctly get required parameters
> of the CTCU device in TMC module.
> 
> Reviewed-by: Mike Leach <mike.leach at linaro.org>
> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
> ---
>   drivers/hwtracing/coresight/coresight-core.c      | 24 +++++++++++++++++++++++
>   drivers/hwtracing/coresight/coresight-ctcu-core.c | 19 +-----------------
>   drivers/hwtracing/coresight/coresight-priv.h      |  2 ++
>   3 files changed, 27 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
> index 1accd7cbd54b..042c4fa39e55 100644
> --- a/drivers/hwtracing/coresight/coresight-core.c
> +++ b/drivers/hwtracing/coresight/coresight-core.c
> @@ -580,6 +580,30 @@ struct coresight_device *coresight_get_sink(struct coresight_path *path)
>   }
>   EXPORT_SYMBOL_GPL(coresight_get_sink);
>   
> +/**
> + * coresight_get_in_port_dest: get the in-port number of the dest device
> + * that is connected to the src device.
> + *
> + * @src: csdev of the source device.
> + * @dest: csdev of the destination device.
> + *
> + * Return: port number upon success or -EINVAL for fail.
> + */
> +int coresight_get_in_port_dest(struct coresight_device *src,

Please could we make this more explicit :

	/*
	 * Find the input port number at @csdev where a @remote
	 * device is connected to.
	 */
	coresight_get_in_port(struct coresight_device *csdev,
			      struct coresight_device *remote)
	{

	}
Suzuki



From suzuki.poulose at arm.com  Wed Dec  3 08:20:47 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Wed, 3 Dec 2025 16:20:47 +0000
Subject: [PATCH v6 3/9] coresight: tmc: add etr_buf_list to store
 allocated etr_buf
In-Reply-To: <20250908-enable-byte-cntr-for-tmc-v6-3-1db9e621441a@oss.qualcomm.com>
References: <20250908-enable-byte-cntr-for-tmc-v6-0-1db9e621441a@oss.qualcomm.com>
 <20250908-enable-byte-cntr-for-tmc-v6-3-1db9e621441a@oss.qualcomm.com>
Message-ID: <9d163813-068b-4921-87fe-8e229692ba2b@arm.com>

On 08/09/2025 03:01, Jie Gan wrote:
> Add a list to store allocated etr_buf.
> 
> The byte-cntr functionality requires two etr_buf to receive trace data.
> The active etr_buf collects the trace data from source device, while the
> byte-cntr reading function accesses the deactivated etr_buf after is
> has been filled and synced, transferring data to the userspace.
> 
> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>

This patch alone doesn't make any sense. Please fold it with a proper 
user (i.e. later patches). I can't make any sense of how this will be
used TBH without the following patches and on its own, it doesn't do
much anyways.

Suzuki


> ---
>   drivers/hwtracing/coresight/coresight-tmc-core.c |  1 +
>   drivers/hwtracing/coresight/coresight-tmc.h      | 17 +++++++++++++++++
>   2 files changed, 18 insertions(+)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c
> index be964656be93..4d249af93097 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-core.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c
> @@ -830,6 +830,7 @@ static int __tmc_probe(struct device *dev, struct resource *res)
>   		idr_init(&drvdata->idr);
>   		mutex_init(&drvdata->idr_mutex);
>   		dev_list = &etr_devs;
> +		INIT_LIST_HEAD(&drvdata->etr_buf_list);
>   		break;
>   	case TMC_CONFIG_TYPE_ETF:
>   		desc.groups = coresight_etf_groups;
> diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
> index 6541a27a018e..292e25d82b62 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc.h
> +++ b/drivers/hwtracing/coresight/coresight-tmc.h
> @@ -208,6 +208,19 @@ struct tmc_resrv_buf {
>   	s64		len;
>   };
>   
> +/**
> + * @sysfs_buf:	Allocated sysfs_buf.
> + * @is_free:	Indicates whether the buffer is free to choose.
> + * @pos:	Position of the buffer.
> + * @node:	Node in etr_buf_list.
> + */
> +struct etr_buf_node {
> +	struct etr_buf		*sysfs_buf;
> +	bool			is_free;
> +	loff_t			pos;
> +	struct list_head	node;
> +};
> +
>   /**
>    * struct tmc_drvdata - specifics associated to an TMC component
>    * @pclk:	APB clock if present, otherwise NULL
> @@ -242,6 +255,8 @@ struct tmc_resrv_buf {
>    *		(after crash) by default.
>    * @crash_mdata: Reserved memory for storing tmc crash metadata.
>    *		 Used by ETR/ETF.
> + * @etr_buf_list: List that is used to manage allocated etr_buf.
> + * @reading_node: Available buffer for byte-cntr reading.
>    */
>   struct tmc_drvdata {
>   	struct clk		*pclk;
> @@ -271,6 +286,8 @@ struct tmc_drvdata {
>   	struct etr_buf		*perf_buf;
>   	struct tmc_resrv_buf	resrv_buf;
>   	struct tmc_resrv_buf	crash_mdata;
> +	struct list_head        etr_buf_list;
> +	struct etr_buf_node     *reading_node;
>   };
>   
>   struct etr_buf_operations {
> 



From robin.murphy at arm.com  Wed Dec  3 08:21:25 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Wed, 3 Dec 2025 16:21:25 +0000
Subject: [PATCH] arm64: dts: rockchip: add SPDIF audio to Beelink A1
In-Reply-To: <20250828164300.3829488-1-christianshewitt@gmail.com>
References: <20250828164300.3829488-1-christianshewitt@gmail.com>
Message-ID: <66ae20b3-3316-4ec2-9c51-8414c053dc32@arm.com>

[ Just noticed this... ]

On 2025-08-28 5:43 pm, Christian Hewitt wrote:
> From: Alex Bee <knaerzche at gmail.com>
> 
> Add the required nodes to enable SPDIF audio output on
> the Beelink A1 set-top-box.

But the A1 doesn't have S/PDIF? Only HDMI plus a 3.5mm jack connected to 
the analog audio codec (and possibly the composite TV out) :/

Thanks,
Robin.

> Signed-off-by: Alex Bee <knaerzche at gmail.com>
> Signed-off-by: Christian Hewitt <christianshewitt at gmail.com>
> ---
>   arch/arm64/boot/dts/rockchip/rk3328-a1.dts | 23 ++++++++++++++++++++++
>   1 file changed, 23 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3328-a1.dts b/arch/arm64/boot/dts/rockchip/rk3328-a1.dts
> index f7c4578865c5..b276a29bdd85 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3328-a1.dts
> +++ b/arch/arm64/boot/dts/rockchip/rk3328-a1.dts
> @@ -58,6 +58,24 @@ ir-receiver {
>   		gpios = <&gpio2 RK_PA2 GPIO_ACTIVE_LOW>;
>   		linux,rc-map-name = "rc-beelink-gs1";
>   	};
> +
> +	spdif_sound: spdif-sound {
> +		compatible = "simple-audio-card";
> +		simple-audio-card,name = "SPDIF";
> +
> +		simple-audio-card,cpu {
> +			sound-dai = <&spdif>;
> +		};
> +
> +		simple-audio-card,codec {
> +			sound-dai = <&spdif_dit>;
> +		};
> +	};
> +
> +	spdif_dit: spdif-dit {
> +		compatible = "linux,spdif-dit";
> +		#sound-dai-cells = <0>;
> +	};
>   };
>   
>   &analog_sound {
> @@ -325,6 +343,11 @@ &sdmmc {
>   	status = "okay";
>   };
>   
> +&spdif {
> +	pinctrl-0 = <&spdifm0_tx>;
> +	status = "okay";
> +};
> +
>   &tsadc {
>   	rockchip,hw-tshut-mode = <0>;
>   	rockchip,hw-tshut-polarity = <0>;


From dianders at chromium.org  Wed Dec  3 08:25:01 2025
From: dianders at chromium.org (Doug Anderson)
Date: Wed, 3 Dec 2025 08:25:01 -0800
Subject: Proposal: Officially allow "incomplete" trees as a base
In-Reply-To: <CAGXv+5HU2y-8AZhXDjneaTdD1yr2h06OXbkozcQJj2mBcR1HmQ@mail.gmail.com>
References: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
 <CAD++jLkuRQKoiEN928GtAj7wUts5PxH905bLp6ZhKsJ3NnenEA@mail.gmail.com>
 <CAD=FV=X5=AK4XMANv+fatn3d9Y5vo9AXsHWb_47HmNaMWUtMwA@mail.gmail.com>
 <CAGXv+5HyMYgKmLc+jmkj-gytm9SNVg9dS7Vn3dQ-dsH8Wo+4sg@mail.gmail.com>
 <CAD=FV=Uq9yfUkLUgg116G+2AvEKkEPmdRgUJ5f1bj229j=LxUg@mail.gmail.com> <CAGXv+5HU2y-8AZhXDjneaTdD1yr2h06OXbkozcQJj2mBcR1HmQ@mail.gmail.com>
Message-ID: <CAD=FV=U54Uwny=kHY+VjG5DGCSHeRUCcWMG=hG88ov8hC6Ynew@mail.gmail.com>

Hi,

On Tue, Dec 2, 2025 at 11:34?PM Chen-Yu Tsai <wenst at chromium.org> wrote:
>
> On Wed, Dec 3, 2025 at 6:11?AM Doug Anderson <dianders at chromium.org> wrote:
> >
> > > In the simplest example we could have one base dts and two overlays
> > > for two different DSI panel models:
> > >
> > >   - base.dtb
> > >     - panel-model-a.dtbo
> > >     - panel-model-b.dtbo
> > >
> > > The problem we then run into is that the base.dtb will only have the
> > > generic model compatible "google,foo", not the sku and revision
> > > specific ones like "google,foo-sku1-rev2".
> > >
> > > And we'd really like to avoid having _more_ overlays just to add the
> > > final specific compatible string, as that kind of defeats the purpose
> > > of using overlays to reduce the number of dts files.
> >
> > I think you may have simplified the above a little too much to the
> > point where it's confusing. At least I'm a bit confused. I _think_ the
> > problems you're talking about are the kinds of things we run into when
> > we take overlays above just two levels. I'm imagining:
> >
> > - base.dtb
> > - board1-rev1.dtbo
> > - board2-rev1.dtbo
> > - board1-rev2.dtbo
> > - board2-rev2.dtbo
> > - panel-a.dtbo
> > - panel-b.dtbo
> >
> > So I think you're saying that you'd start with the "base.dtb" and then
> > extend it with exactly one of the "board" overlays and then exactly
> > one of the "panel" overlays. Is that right?
>
> For now I think we just experiment with having one end "model" or
> "product" as the base.dtb. The panel-*.dtbo selected describe the
> optional components, while the board-rev??.dtbo just provides the
> top level compatible and model.
>
> In an example that I plan to send out this week, I would rework:
>
>   - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri.dtsi
>     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku0.dts
>     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku1.dts
>     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku2.dts
>     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku3.dts
>     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku4.dts
>     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku5.dts
>     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku6.dts
>     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku7.dts
>
> into:
>
>   - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri.dts
>     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-audio-max98390-es8326.dtso
>     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-audio-max98390-rt5682s.dtso
>     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-audio-tas2563-es8326.dtso
>     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-audio-tas2563-rt5682s.dtso
>     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-panel-boe.dtso
>     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-panel-ivo.dtso
>     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku0.dtso
>     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku1.dtso
>     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku2.dtso
>     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku3.dtso
>     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku4.dtso
>     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku5.dtso
>     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku6.dtso
>     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku7.dtso
>
> The "mt8188-geralt-ciri-sku?.dtso" files only contain the following
> boilerplate:
>
>     /dts-v1/;
>     /plugin/;
>
>     &{/} {
>         model = "Google Ciri sku? board (rev4)";
>         compatible = "google,ciri-sku?", "google,ciri", "mediatek,mt8188";
>     };
>
> The base "mt8188-geralt-ciri.dts" would already have a generic board-
> specific compatible:
>
>     model = "Google Ciri board";
>     compatible = "google,ciri", "mediatek,mt8188";
>
> > So I'd imagine that each of the "board" overlays could have "full"
> > compatible strings. For instance, I'd imagine "board2-rev2" could
> > have:
> >
> > compatible = "google,booard2-rev2", "socVendor,soc"
> >
> >
> > The problem you're struggling with (I think) is that the panel
> > overlays won't be represented in the compatible string (and "model")
> > even though (historically) we always did in ChromeOS (they were
> > included in the "sku" part of the compatible string).
> >
> > Did I get that right?
>
> In a sense you've generalized the problem I was describing.
>
> In my example, the top level compatible gets fixed up by the final
> SKU-specific overlay. But that's 8 extra files to do one bit of
> fixup that supposedly the bootloader could be taught to do, and
> could do even better. The bootloader knows exactly which SKU and
> revision it's running on and can insert the information appropriately.
> We could get rid of those awkwardly long compatible string sequences:
>
>   compatible = "google,tentacruel-sku262147", "google,tentacruel-sku262146",
>                "google,tentacruel-sku262145", "google,tentacruel-sku262144",
>                "google,tentacruel", "mediatek,mt8186";
>
> Going back to what I think you're describing, is that instead of one
> base board DTB for each product, we could have one base DTB for the
> reference design (in place of the .dtsi file we currently have), and
> make products and component selection all use overlays.
>
> If we do that, then inserting the correct top level compatible and model
> becomes more important, since we do have things such as the ChromeOS OF
> component prober working based on top level compatible. Also, the model
> is present in logs, and would be very misleading to say one device name
> while in reality it is a different one.

I wasn't saying that you'd just have the same "compatible" for every
derivative of a reference board. That seems over the top. I was
thinking that you'd even have a unique "compatible" for each revision
of each board instance. I'm simply suggesting that you don't need a
per-SKU "compatible". Those don't add any real benefit, do they?

In your Ciri example above, you could get rid of all of the "sku"
overlay files since you've said that all they're doing is updating the
"compatible". Since (I think) you're only trying to support "rev4"
based on your model string, that would leave you just one file for
Ciri. If you had more than one revision then you'd have more than one,
but it doesn't need to be multiplied by the SKUs, right?

-Doug


From maz at kernel.org  Wed Dec  3 08:43:31 2025
From: maz at kernel.org (Marc Zyngier)
Date: Wed, 03 Dec 2025 16:43:31 +0000
Subject: [PATCH 4/4] KVM: arm64: Convert VTCR_EL2 to config-driven sanitisation
In-Reply-To: <20251203161715.GA4187196@e124191.cambridge.arm.com>
References: <20251129144525.2609207-1-maz@kernel.org>
	<20251129144525.2609207-5-maz@kernel.org>
	<20251203161715.GA4187196@e124191.cambridge.arm.com>
Message-ID: <86fr9rplcc.wl-maz@kernel.org>

On Wed, 03 Dec 2025 16:17:15 +0000,
Joey Gouly <joey.gouly at arm.com> wrote:
> 
> Hi!
> 
> On Sat, Nov 29, 2025 at 02:45:25PM +0000, Marc Zyngier wrote:
> > Describe all the VTCR_EL2 fields and their respective configurations,
> > making sure that we correctly ignore the bits that are not defined
> > for a given guest configuration.
> > 
> > Signed-off-by: Marc Zyngier <maz at kernel.org>
> > ---
> >  arch/arm64/kvm/config.c | 69 +++++++++++++++++++++++++++++++++++++++++
> >  arch/arm64/kvm/nested.c |  3 +-
> >  2 files changed, 70 insertions(+), 2 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
> > index a02c28d6a61c9..c36e133c51912 100644
> > --- a/arch/arm64/kvm/config.c
> > +++ b/arch/arm64/kvm/config.c
> > @@ -141,6 +141,7 @@ struct reg_feat_map_desc {
> >  #define FEAT_AA64EL1		ID_AA64PFR0_EL1, EL1, IMP
> >  #define FEAT_AA64EL2		ID_AA64PFR0_EL1, EL2, IMP
> >  #define FEAT_AA64EL3		ID_AA64PFR0_EL1, EL3, IMP
> > +#define FEAT_SEL2		ID_AA64PFR0_EL1, SEL2, IMP
> >  #define FEAT_AIE		ID_AA64MMFR3_EL1, AIE, IMP
> >  #define FEAT_S2POE		ID_AA64MMFR3_EL1, S2POE, IMP
> >  #define FEAT_S1POE		ID_AA64MMFR3_EL1, S1POE, IMP
> > @@ -202,6 +203,8 @@ struct reg_feat_map_desc {
> >  #define FEAT_ASID2		ID_AA64MMFR4_EL1, ASID2, IMP
> >  #define FEAT_MEC		ID_AA64MMFR3_EL1, MEC, IMP
> >  #define FEAT_HAFT		ID_AA64MMFR1_EL1, HAFDBS, HAFT
> > +#define FEAT_HDBSS		ID_AA64MMFR1_EL1, HAFDBS, HDBSS
> > +#define FEAT_HPDS2		ID_AA64MMFR1_EL1, HPDS, HPDS2
> >  #define FEAT_BTI		ID_AA64PFR1_EL1, BT, IMP
> >  #define FEAT_ExS		ID_AA64MMFR0_EL1, EXS, IMP
> >  #define FEAT_IESB		ID_AA64MMFR2_EL1, IESB, IMP
> > @@ -219,6 +222,7 @@ struct reg_feat_map_desc {
> >  #define FEAT_FGT2		ID_AA64MMFR0_EL1, FGT, FGT2
> >  #define FEAT_MTPMU		ID_AA64DFR0_EL1, MTPMU, IMP
> >  #define FEAT_HCX		ID_AA64MMFR1_EL1, HCX, IMP
> > +#define FEAT_S2PIE		ID_AA64MMFR3_EL1, S2PIE, IMP
> >  
> >  static bool not_feat_aa64el3(struct kvm *kvm)
> >  {
> > @@ -362,6 +366,28 @@ static bool feat_pmuv3p9(struct kvm *kvm)
> >  	return check_pmu_revision(kvm, V3P9);
> >  }
> >  
> > +#define has_feat_s2tgran(k, s)						\
> > +  ((kvm_has_feat_enum(kvm, ID_AA64MMFR0_EL1, TGRAN##s##_2, TGRAN##s) && \
> > +    !kvm_has_feat_enum(kvm, ID_AA64MMFR0_EL1, TGRAN##s, NI))	     ||	\
> > +   kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN##s##_2, IMP))
> > +
> > +static bool feat_lpa2(struct kvm *kvm)
> > +{
> > +	return ((kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4, 52_BIT)    ||
> > +		 !kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4, IMP))	&&
> > +		(kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16, 52_BIT)   ||
> > +		 !kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16, IMP))	&&
> > +		(kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4_2, 52_BIT)  ||
> > +		 !has_feat_s2tgran(kvm, 4))				&&
> > +		(kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16_2, 52_BIT) ||
> > +		 !has_feat_s2tgran(kvm, 16)));
> > +}
> > +
> > +static bool feat_vmid16(struct kvm *kvm)
> > +{
> > +	return kvm_has_feat_enum(kvm, ID_AA64MMFR1_EL1, VMIDBits, 16);
> > +}
> > +
> >  static bool compute_hcr_rw(struct kvm *kvm, u64 *bits)
> >  {
> >  	/* This is purely academic: AArch32 and NV are mutually exclusive */
> > @@ -1168,6 +1194,44 @@ static const struct reg_bits_to_feat_map mdcr_el2_feat_map[] = {
> >  static const DECLARE_FEAT_MAP(mdcr_el2_desc, MDCR_EL2,
> >  			      mdcr_el2_feat_map, FEAT_AA64EL2);
> >  
> > +static const struct reg_bits_to_feat_map vtcr_el2_feat_map[] = {
> > +	NEEDS_FEAT(VTCR_EL2_HDBSS, FEAT_HDBSS),
> > +	NEEDS_FEAT(VTCR_EL2_HAFT, FEAT_HAFT),
> > +	NEEDS_FEAT(VTCR_EL2_TL0		|
> > +		   VTCR_EL2_TL1		|
> > +		   VTCR_EL2_AssuredOnly	|
> > +		   VTCR_EL2_GCSH,
> > +		   FEAT_THE),
> 
> The text for VTCR_EL2.AssuredOnly says:
> 
> 	This field is RES0 when VTCR_EL2.D128 is 1.
> 
> > +	NEEDS_FEAT(VTCR_EL2_D128, FEAT_D128),
> > +	NEEDS_FEAT(VTCR_EL2_S2POE, FEAT_S2POE),
> > +	NEEDS_FEAT(VTCR_EL2_S2PIE, FEAT_S2PIE),
> 
> The text for VTCR_EL2.S2PIE says:
> 
> 	This field is RES1 when VTCR_EL2.D128 is set.
> 
> 
> Are these cases that need to be handled here somehow?

These are not static configurations. They are dynamic behaviours
depending on other control bits.

D128 code, if it ever exists, will have to *interpret* these bits as
RES0 (resp. RES1) when evaluating the page tables.

If you want a similar example in existing code, look at the way we
handle TCR_EL1.HPDn in the S1 PTW. They are treated as RES1 if
TCR2_EL1.PIE is set, as per R_JHSVW.

Thanks,

	M.

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


From broonie at kernel.org  Wed Dec  3 08:50:01 2025
From: broonie at kernel.org (Mark Brown)
Date: Wed, 03 Dec 2025 16:50:01 +0000
Subject: [PATCH] ASoC: rockchip: Fix Wvoid-pointer-to-enum-cast warning
 (again)
In-Reply-To: <20251203141644.106459-2-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251203141644.106459-2-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <176478060152.99790.2704238708778622367.b4-ty@kernel.org>

On Wed, 03 Dec 2025 15:16:45 +0100, Krzysztof Kozlowski wrote:
> 'version' is an enum, thus cast of pointer on 64-bit compile test with
> clang W=1 causes:
> 
>   rockchip_pdm.c:583:17: error: cast to smaller integer type 'enum rk_pdm_version' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast]
> 
> This was already fixed in commit 49a4a8d12612 ("ASoC: rockchip: Fix
> Wvoid-pointer-to-enum-cast warning") but then got bad in
> commit 9958d85968ed ("ASoC: Use device_get_match_data()").
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next

Thanks!

[1/1] ASoC: rockchip: Fix Wvoid-pointer-to-enum-cast warning (again)
      commit: 57d508b5f718730f74b11e0dc9609ac7976802d1

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark



From ardb at kernel.org  Wed Dec  3 08:59:21 2025
From: ardb at kernel.org (Ard Biesheuvel)
Date: Wed, 3 Dec 2025 17:59:21 +0100
Subject: [RFC/RFT PATCH 2/6] arc: Wire up cmpxchg64_local() to generic implementation
In-Reply-To: <20251127150614.GA3271003@e124191.cambridge.arm.com>
References: <20251127092226.1439196-8-ardb+git@google.com> <20251127092226.1439196-10-ardb+git@google.com>
 <20251127150614.GA3271003@e124191.cambridge.arm.com>
Message-ID: <CAMj1kXHhSFj-ScYXCZu=9SyWp8j3ZrO4qwOcmKLZ9FBLwN6-Qg@mail.gmail.com>

On Thu, 27 Nov 2025 at 16:06, Joey Gouly <joey.gouly at arm.com> wrote:
>
> On Thu, Nov 27, 2025 at 10:22:29AM +0100, Ard Biesheuvel wrote:
> > From: Ard Biesheuvel <ardb at kernel.org>
> >
> > Provide cmpxchg64_local() for hexagon so we can start using it in
> > generic code.
>
> nit: this is for arc, not hexagon.
>

Indeed, thanks!


From Frank.li at nxp.com  Wed Dec  3 08:59:33 2025
From: Frank.li at nxp.com (Frank Li)
Date: Wed, 3 Dec 2025 11:59:33 -0500
Subject: [PATCH v20 3/7] firmware: imx: add driver for NXP EdgeLock
 Enclave
In-Reply-To: <1ee383c7-ccbc-4c90-adf3-bfbe87fb6765@kernel.org>
References: <20251203-imx-se-if-v20-0-a04a25c4255f@nxp.com>
 <20251203-imx-se-if-v20-3-a04a25c4255f@nxp.com>
 <1ee383c7-ccbc-4c90-adf3-bfbe87fb6765@kernel.org>
Message-ID: <aTBsdW0lpZSCVsgp@lizhi-Precision-Tower-5810>

On Wed, Dec 03, 2025 at 08:20:50AM +0100, Krzysztof Kozlowski wrote:
> On 03/12/2025 07:48, Pankaj Gupta wrote:
> > Add driver for enabling MU based communication interface to secure-enclave.
> >
> > NXP hardware IP(s) for secure-enclaves like Edgelock Enclave(ELE), are
> > embedded in the SoC to support the features like HSM, SHE & V2X, using
> > message based communication interface.
> >
> > The secure enclave FW communicates with Linux over single or multiple
> > dedicated messaging unit(MU) based interface(s).
> > Exists on i.MX SoC(s) like i.MX8ULP, i.MX93, i.MX95 etc.
> >
> > For i.MX9x SoC(s) there is at least one dedicated ELE MU(s) for each
> > world - Linux(one or more) and OPTEE-OS (one or more).
> >
> > Other dependent kernel drivers will be:
> > - NVMEM: that supports non-volatile devices like EFUSES,
> >          managed by NXP's secure-enclave.
> >
> > Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
> > Reviewed-by: Frank Li <Frank.Li at nxp.com>
> > ---
> >  drivers/firmware/imx/Kconfig        |  13 ++
> >  drivers/firmware/imx/Makefile       |   2 +
> >  drivers/firmware/imx/ele_base_msg.c | 269 ++++++++++++++++++++++++
> >  drivers/firmware/imx/ele_base_msg.h |  95 +++++++++
> >  drivers/firmware/imx/ele_common.c   | 333 ++++++++++++++++++++++++++++++
> >  drivers/firmware/imx/ele_common.h   |  45 ++++
> >  drivers/firmware/imx/se_ctrl.c      | 401 ++++++++++++++++++++++++++++++++++++
> >  drivers/firmware/imx/se_ctrl.h      |  86 ++++++++
> >  include/linux/firmware/imx/se_api.h |  14 ++
> >  9 files changed, 1258 insertions(+)
> >
> > diff --git a/drivers/firmware/imx/Kconfig b/drivers/firmware/imx/Kconfig
> > index 127ad752acf8..5fe96299b704 100644
> > --- a/drivers/firmware/imx/Kconfig
> > +++ b/drivers/firmware/imx/Kconfig
> > @@ -55,3 +55,16 @@ config IMX_SCMI_MISC_DRV
> >  	  core that could provide misc functions such as board control.
> >
> >  	  This driver can also be built as a module.
> > +
> > +config IMX_SEC_ENCLAVE
> > +	tristate "i.MX Embedded Secure Enclave - EdgeLock Enclave Firmware driver."
> > +	depends on IMX_MBOX && ARCH_MXC && ARM64
> > +	select FW_LOADER
> > +	default m if ARCH_MXC
> > +
> > +	help
> > +	  Exposes APIs supported by the iMX Secure Enclave HW IP called:
> > +	  - EdgeLock Enclave Firmware (for i.MX8ULP, i.MX93),
> > +	    like base, HSM, V2X & SHE using the SAB protocol via the shared Messaging
> > +	    Unit. This driver exposes these interfaces via a set of file descriptors
> > +	    allowing to configure shared memory, send and receive messages.
> > diff --git a/drivers/firmware/imx/Makefile b/drivers/firmware/imx/Makefile
> > index 3bbaffa6e347..4412b15846b1 100644
> > --- a/drivers/firmware/imx/Makefile
> > +++ b/drivers/firmware/imx/Makefile
> > @@ -4,3 +4,5 @@ obj-$(CONFIG_IMX_SCU)		+= imx-scu.o misc.o imx-scu-irq.o rm.o imx-scu-soc.o
> >  obj-${CONFIG_IMX_SCMI_CPU_DRV}	+= sm-cpu.o
> >  obj-${CONFIG_IMX_SCMI_MISC_DRV}	+= sm-misc.o
> >  obj-${CONFIG_IMX_SCMI_LMM_DRV}	+= sm-lmm.o
> > +sec_enclave-objs		= se_ctrl.o ele_common.o ele_base_msg.o
> > +obj-${CONFIG_IMX_SEC_ENCLAVE}	+= sec_enclave.o
> > diff --git a/drivers/firmware/imx/ele_base_msg.c b/drivers/firmware/imx/ele_base_msg.c
> > new file mode 100644
> > index 000000000000..a070acbd895c
> > --- /dev/null
> > +++ b/drivers/firmware/imx/ele_base_msg.c
> > @@ -0,0 +1,269 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright 2025 NXP
> > + */
> > +
> > +#include <linux/types.h>
> > +
> > +#include <linux/completion.h>
> > +#include <linux/dma-mapping.h>
> > +#include <linux/genalloc.h>
> > +
> > +#include "ele_base_msg.h"
> > +#include "ele_common.h"
> > +
> > +#define FW_DBG_DUMP_FIXED_STR		"ELE"
> > +
> > +int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info)
> > +{
> > +	struct se_api_msg *tx_msg __free(kfree) = NULL;
> > +	struct se_api_msg *rx_msg __free(kfree) = NULL;
>
> No, don't use this syntax. This is explicitly discouraged.
>
> NAK

Add link for reference.

https://lore.kernel.org/all/CAHk-=whPZoi03ZwphxiW6cuWPtC3nyKYS8_BThgztCdgPWP1WA at mail.gmail.com/

Frank
>
> Best regards,
> Krzysztof


From Frank.li at nxp.com  Wed Dec  3 09:04:36 2025
From: Frank.li at nxp.com (Frank Li)
Date: Wed, 3 Dec 2025 12:04:36 -0500
Subject: [PATCH 1/2] media: dt-bindings: Add CSI Pixel Formatter DT
 bindings
In-Reply-To: <20251203-csi_formatter-v1-1-eb9e1147b49e@nxp.com>
References: <20251203-csi_formatter-v1-0-eb9e1147b49e@nxp.com>
 <20251203-csi_formatter-v1-1-eb9e1147b49e@nxp.com>
Message-ID: <aTBtpOpsMSmezIcL@lizhi-Precision-Tower-5810>

On Wed, Dec 03, 2025 at 02:30:02PM +0800, Guoniu Zhou wrote:
> From: Guoniu Zhou <guoniu.zhou at nxp.com>
>
> The i.MX9 CSI pixel formatting module uses packet info, pixel and
> non-pixel data from the CSI-2 host controller and reformat them to
> match Pixel Link(PL) definition.
>
> Signed-off-by: Guoniu Zhou <guoniu.zhou at nxp.com>
> ---
>  .../bindings/media/nxp,imx9-csi-formatter.yaml     | 96 ++++++++++++++++++++++
>  1 file changed, 96 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/media/nxp,imx9-csi-formatter.yaml b/Documentation/devicetree/bindings/media/nxp,imx9-csi-formatter.yaml
> new file mode 100644
> index 0000000000000000000000000000000000000000..c992a2a225519d3b7934f48cf1646d2cd7089319
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/nxp,imx9-csi-formatter.yaml
> @@ -0,0 +1,96 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/media/nxp,imx9-csi-formatter.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: i.MX9 CSI Pixel Formatter
> +
> +maintainers:
> +  - Guoniu Zhou <guoniu.zhou at nxp.com>
> +
> +description: |

needn't |

> +  The CSI pixel formatting module uses packet info, pixel and non-pixel
> +  data from the CSI-2 host controller and reformat them to match Pixel
> +  Link(PL) definition.
> +
> +properties:
> +  compatible:
> +    const: fsl,imx9-csi-formatter
> +
> +  reg:
> +    maxItems: 1
> +
> +  clocks:
> +    maxItems: 1
> +
> +  clock-names:
> +    maxItems: 1
> +
> +  power-domains:
> +    maxItems: 1
> +
> +  ports:
> +    $ref: /schemas/graph.yaml#/properties/ports
> +
> +    properties:
> +      port at 0:
> +        $ref: /schemas/graph.yaml#/$defs/port-base
> +        unevaluatedProperties: false
> +        description: MIPI CSI-2 RX IDI interface
> +
> +        properties:
> +          endpoint:
> +            $ref: video-interfaces.yaml#
> +            unevaluatedProperties: false
> +
> +      port at 1:
> +        $ref: /schemas/graph.yaml#/properties/port
> +        description: Pixel Link Interface
> +
> +required:
> +  - compatible
> +  - reg
> +  - clocks
> +  - clock-names
> +  - power-domains
> +  - ports
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/clock/nxp,imx95-clock.h>
> +
> +    /*
> +     * Power domain definitions from arch/arm64/boot/dts/freescale/imx95-power.h
> +     */
> +
> +    #define IMX95_PD_CAMERA		3
> +
> +    formatter at 20 {
> +        compatible = "fsl,imx9-csi-formatter";
> +        reg = <0x20 0x100>;
> +        clocks = <&cameramix_csr IMX95_CLK_CAMBLK_CSI2_FOR0>;
> +        clock-names = "pixel";
> +        power-domains = <&scmi_devpd IMX95_PD_CAMERA>;
> +
> +        ports {
> +            #address-cells = <1>;
> +            #size-cells = <0>;
> +
> +            port at 0 {
> +                reg = <0>;

need empty line between child node and property.

> +                formatter_in: endpoint {

Needn't label here

Frank
> +                    remote-endpoint = <&mipi_csi_0_out>;
> +                };
> +            };
> +
> +            port at 1 {
> +                reg = <1>;
> +                formatter_out: endpoint {
> +                    remote-endpoint = <&isi_in_2>;
> +                };
> +            };
> +        };
> +    };
>
> --
> 2.34.1
>


From james.morse at arm.com  Wed Dec  3 09:34:37 2025
From: james.morse at arm.com (James Morse)
Date: Wed, 3 Dec 2025 17:34:37 +0000
Subject: [PATCH v6 00/34] arm_mpam: Add basic mpam driver
In-Reply-To: <87sedrlsjk.fsf@stealth>
References: <20251119122305.302149-1-ben.horgan@arm.com>
 <877bvfa23i.fsf@stealth> <a04aa337-a3eb-42a0-855b-500ba549e2d8@arm.com>
 <87sedrlsjk.fsf@stealth>
Message-ID: <642767c9-f926-490a-83a1-160978c37553@arm.com>

Hi Punit,

On 03/12/2025 11:21, Punit Agrawal wrote:
> Ben Horgan <ben.horgan at arm.com> writes:
>> On 11/24/25 15:21, Punit Agrawal wrote:
>>> Although a little late to the party,

There was a party?!


>>> I've managed to throw together
>>> enough firmware to describe the MPAM hardware and take this set (more
>>> specifically mpam/snapshot/v6.18-rc4-v5 branch from James' repository)
>>> for a spin. Using the branch, the kernel is able to probe the hardware
>>> and discover the advertised features. Yay! We are in business.
>>
>> Thanks for giving it a go. :)
>>
>>>
>>> Having said that, there are a few quirks of the platform that run into
>>> issues with later patches in the branch.

So something in the resctrl support code is causing this.
Any idea which patch causes this to happen?

There are a load of pr_debug() in the picking logic, if you enable DYNDEBUG and add:
| dyndbg="file mpam_resctrl.c +pl"

to the commandline, you should get some snotty messages about what non-Xeon-like property
your platform has.



>>> The platform has MSCs attached
>>> to shared L2 caches which are being skipped during later stages of
>>> initialisation. IIUC, the L2 MSCs' limitations stems from the
>>> assumptions in the resctrl interface.
>>
>> What in particualar is being skipped?

> The registration of the discovered MSCs with resctrl and subsequent
> exposing it to the user.

resctrl's 'L2' support is limited to the CPOR bitmap.
If you have controls, there is no resctrl 'event' that can exposed them.
(the problem being they all have 'L3' in the name!)


>>> I was wondering if there are any patches available to relax these
>>> limitations?

Knowing which property it is will help - but some of these things are checked
to match resctrl's ABI. They can't necessarily be relaxed without breaking
user-space.

Others are sanity checks, e.g. all CPUs are represented. This is to avoid tasks
that run on cpu-9 escaping the resctrl controls. Platforms that did this may as
well not bother with resctrl at all.


>>> I can give them a try. Or do these need to be put together
>>> from the ground up? Any pointers greatly appreciated.
>>
>> There are some extra things added in the extras branch [1] e.g. cache
>> maximum usage controls (cmax). However, lots of possible things are
>> still missing e.g. any monitors on L2. If it doesn't fit with the
>> topology expected by resctrl then it is unlikely to have been considered
>> yet.
> 
> Thanks for the pointer. I'll give the snapshot+extras branch[1] a try.
> 
> The platform does have both controls and monitors attached to L2. If
> this isn't being looked at, I can try and put something together. Thanks
> for confirming that the limitation is likely due to resctrl.

My view on 'extra' counters is to try and expose them via perf, as this would also
allow platform specific counters. I worry that if we start adding 'easy' ones like
l2_mbm_total to resctrl, someone will want left_hand_side_of_soc_mbm_total.


Thanks,

James


From iuliana.prodan at nxp.com  Wed Dec  3 09:35:27 2025
From: iuliana.prodan at nxp.com (Iuliana Prodan)
Date: Wed, 3 Dec 2025 19:35:27 +0200
Subject: [PATCH 1/2] remoteproc: imx_dsp_rproc: Skip
 RP_MBOX_SUSPEND_SYSTEM when mailbox TX channel is uninitialized
In-Reply-To: <mkgc3gpgzvdvotzw4752om5ascwxpscocaj2x5urzaa7ss4iys@rsqb3ebrexw7>
References: <20251125124903.962295-1-iuliana.prodan@oss.nxp.com>
 <mkgc3gpgzvdvotzw4752om5ascwxpscocaj2x5urzaa7ss4iys@rsqb3ebrexw7>
Message-ID: <36564f56-eb61-449d-a90b-980304b0f5ea@nxp.com>

On 11/26/2025 10:14 PM, Bjorn Andersson wrote:
> On Tue, Nov 25, 2025 at 02:49:02PM +0200, Iuliana Prodan (OSS) wrote:
>> From: Iuliana Prodan <iuliana.prodan at nxp.com>
>>
>> Firmwares that do not use mailbox communication
>> (e.g., the hello_world sample) leave priv->tx_ch
>> as NULL. The current suspend logic unconditionally
>> sends RP_MBOX_SUSPEND_SYSTEM, which is invalid without
>> an initialized TX channel.
>>
>> Detect the no_mailboxes case early and skip sending
>> the suspend message. Instead, proceed directly to
>> the runtime PM suspend path, which is the correct
>> behavior for firmwares that cannot respond to mailbox
>> requests.
> 
> Please use the allotted 75 characters of width for your commit message.
> 
Right, will do in v2.

>>
>> Signed-off-by: Iuliana Prodan <iuliana.prodan at nxp.com>
>> ---
>>   drivers/remoteproc/imx_dsp_rproc.c | 9 +++++++++
>>   1 file changed, 9 insertions(+)
>>
>> diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c
>> index f11662f9a12f..fc0470aa72c1 100644
>> --- a/drivers/remoteproc/imx_dsp_rproc.c
>> +++ b/drivers/remoteproc/imx_dsp_rproc.c
>> @@ -1308,6 +1308,15 @@ static int imx_dsp_suspend(struct device *dev)
>>   	if (rproc->state != RPROC_RUNNING)
>>   		goto out;
>>   
>> +	/*
>> +	 * No channel available for sending messages;
>> +	 * indicates no mailboxes present, so trigger PM runtime suspend
>> +	 */
>> +	if (!priv->tx_ch) {
>> +		dev_err(dev, "No initialized mbox tx channel\n");
> 
> Commit message and comment above says this is "normal" behavior,
> dev_err() indicates that it's not. Should this be a dev_info()?
> 
> That said, it's still a message every time you suspend, so perhaps even
> omitting the print (or a dev_dbg()) makes more sense?
There's no error here; it's just a use case.
dev_dbg makes more sense, I agree.

> 
> Regards,
> Bjorn
> 
>> +		goto out;
>> +	}
>> +
>>   	reinit_completion(&priv->pm_comp);
>>   
>>   	/* Tell DSP that suspend is happening */
>> -- 
>> 2.34.1
>>



From andi.shyti at kernel.org  Wed Dec  3 09:38:18 2025
From: andi.shyti at kernel.org (Andi Shyti)
Date: Wed, 3 Dec 2025 18:38:18 +0100
Subject: [PATCH 1/3] i2c: bcm-iproc: Fix Wvoid-pointer-to-enum-cast
 warning
In-Reply-To: <20251126182257.157439-4-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251126182257.157439-4-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <iwix6mjanmhqzuwunt3ium3cuuicfvdypvylykhm62mrwp57dg@fmuq6f7vmrcw>

Hi Krzk,

All three patches merged to i2c/i2c-host.

Thanks,
Andi

On Wed, Nov 26, 2025 at 07:22:58PM +0100, Krzysztof Kozlowski wrote:
> 'type' is an enum, thus cast of pointer on 64-bit compile test with
> clang and W=1 causes:
> 
>   i2c-bcm-iproc.c:1102:3: error: cast to smaller integer type 'enum bcm_iproc_i2c_type' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast]
> 
> One of the discussions in 2023 on LKML suggested warning is not suitable
> for kernel.  Nothing changed in this regard since that time, so assume
> the warning will stay and we want to have warnings-free builds.
> 
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
> 
> ---
> 
> kernel_ulong_t is the preferred cast for such cases.
> ---
>  drivers/i2c/busses/i2c-bcm-iproc.c | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c
> index e418a4f23f15..b5629cffe99b 100644
> --- a/drivers/i2c/busses/i2c-bcm-iproc.c
> +++ b/drivers/i2c/busses/i2c-bcm-iproc.c
> @@ -1098,8 +1098,7 @@ static int bcm_iproc_i2c_probe(struct platform_device *pdev)
>  
>  	platform_set_drvdata(pdev, iproc_i2c);
>  	iproc_i2c->device = &pdev->dev;
> -	iproc_i2c->type =
> -		(enum bcm_iproc_i2c_type)of_device_get_match_data(&pdev->dev);
> +	iproc_i2c->type = (kernel_ulong_t)of_device_get_match_data(&pdev->dev);
>  	init_completion(&iproc_i2c->done);
>  
>  	iproc_i2c->base = devm_platform_ioremap_resource(pdev, 0);
> -- 
> 2.48.1
> 


From Frank.li at nxp.com  Wed Dec  3 09:41:08 2025
From: Frank.li at nxp.com (Frank Li)
Date: Wed, 3 Dec 2025 12:41:08 -0500
Subject: [PATCH 2/2] media: nxp: Add i.MX9 CSI pixel formatter v4l2
 drivery
In-Reply-To: <20251203-csi_formatter-v1-2-eb9e1147b49e@nxp.com>
References: <20251203-csi_formatter-v1-0-eb9e1147b49e@nxp.com>
 <20251203-csi_formatter-v1-2-eb9e1147b49e@nxp.com>
Message-ID: <aTB2NNYVSm6POk9y@lizhi-Precision-Tower-5810>

On Wed, Dec 03, 2025 at 02:30:03PM +0800, Guoniu Zhou wrote:
> From: Guoniu Zhou <guoniu.zhou at nxp.com>
>
> The CSI pixel formatter is a module found on i.MX95 used to reformat
> packet info, pixel and non-pixel data from CSI-2 host controller to
> match Pixel Link(PL) definition.
>
> This driver adds its data formatting support.

Needn't words "this driver", just

   Add data formatting support.

>
> Signed-off-by: Guoniu Zhou <guoniu.zhou at nxp.com>
> ---
>  MAINTAINERS                                     |   8 +
>  drivers/media/platform/nxp/Kconfig              |  14 +
>  drivers/media/platform/nxp/Makefile             |   1 +
>  drivers/media/platform/nxp/imx9-csi-formatter.c | 894 ++++++++++++++++++++++++
>  4 files changed, 917 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 4205ca007e076f869613032b51e8cc5bff06b98e..24681a787818c3e69f93dcc220ee9838cef99886 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -18626,6 +18626,14 @@ S:	Maintained
>  F:	Documentation/devicetree/bindings/media/nxp,imx8-jpeg.yaml
>  F:	drivers/media/platform/nxp/imx-jpeg
>
> +NXP i.MX 9 CSI PIXEL FORMATTER V4L2 DRIVER
> +M:	Guoniu Zhou <guoniu.zhou at nxp.com>
> +L:	imx at lists.linux.dev
> +L:	linux-media at vger.kernel.org
> +S:	Maintained
> +F:	Documentation/devicetree/bindings/media/nxp,imx9-csi-formatter.yaml
> +F:	drivers/media/platform/nxp/imx9-csi-formatter.c
> +

...
> +
> +#define CSI_FORMATTER_PAD_SINK			0
> +#define CSI_FORMATTER_PAD_SOURCE		1
> +#define CSI_FORMATTER_PAD_NUM			2
> +
> +#define CSI_FORMATTER_DEF_MBUS_CODE		MEDIA_BUS_FMT_UYVY8_1X16
> +#define CSI_FORMATTER_DEF_PIX_WIDTH		1920U
> +#define CSI_FORMATTER_DEF_PIX_HEIGHT		1080U
> +#define CSI_FORMATTER_MAX_PIX_WIDTH		0xffff
> +#define CSI_FORMATTER_MAX_PIX_HEIGHT		0xffff

These macro only use once, you put value direct at formatter_default_fmt.

> +
> +#define CSI_FORMATTER_DRV_NAME			"csi-pixel-formatter"
> +#define CSI_FORMATTER_VC_MAX			8
> +
> +struct formatter_pix_format {
> +	u32 code;
> +	u32 data_type;
> +};
> +
...
> +
> +static int formatter_subdev_get_frame_desc(struct v4l2_subdev *sd,
> +					   unsigned int pad,
> +					   struct v4l2_mbus_frame_desc *fd)
> +{
> +	struct csi_formatter *formatter = sd_to_formatter(sd);
> +	struct v4l2_mbus_frame_desc csi_fd;
> +	struct v4l2_subdev_route *route;
> +	struct v4l2_subdev_state *state;
> +	int ret;
> +
> +	if (pad != CSI_FORMATTER_PAD_SOURCE)
> +		return -EINVAL;
> +
> +	ret = v4l2_subdev_call(formatter->csi_sd, pad, get_frame_desc,
> +			       formatter->remote_pad, &csi_fd);
> +	if (ret)
> +		return ret;
> +
> +	if (csi_fd.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) {
> +		dev_err(formatter->dev,
> +			"Frame descriptor does not describe CSI-2 link\n");
> +		return -EINVAL;
> +	}
> +
> +	memset(fd, 0, sizeof(*fd));
> +
> +	fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2;
> +
> +	state = v4l2_subdev_lock_and_get_active_state(sd);
> +
> +	for_each_active_route(&state->routing, route) {
> +		struct v4l2_mbus_frame_desc_entry *entry = NULL;
> +		unsigned int i;
> +
> +		if (route->source_pad != pad)
> +			continue;
> +
> +		for (i = 0; i < csi_fd.num_entries; ++i) {
> +			if (csi_fd.entry[i].stream == route->sink_stream) {
> +				entry = &csi_fd.entry[i];
> +				break;
> +			}
> +		}
> +
> +		if (!entry) {
> +			dev_err(formatter->dev,
> +				"Failed to find stream from source frames desc\n");
> +			ret = -EPIPE;
> +			goto out_unlock;

may 'break' here is better?

> +		}
> +
> +		fd->entry[fd->num_entries].stream = route->source_stream;
> +		fd->entry[fd->num_entries].flags = entry->flags;
> +		fd->entry[fd->num_entries].length = entry->length;
> +		fd->entry[fd->num_entries].pixelcode = entry->pixelcode;
> +		fd->entry[fd->num_entries].bus.csi2.vc = entry->bus.csi2.vc;
> +		fd->entry[fd->num_entries].bus.csi2.dt = entry->bus.csi2.dt;
> +
> +		fd->num_entries++;
> +	}
> +
> +out_unlock:
> +	v4l2_subdev_unlock_state(state);
> +	return ret;
> +}
> +
...
> +
> +static int formatter_subdev_enable_streams(struct v4l2_subdev *sd,
> +					   struct v4l2_subdev_state *state,
> +					   u32 pad, u64 streams_mask)
> +{
> +	struct csi_formatter *formatter = sd_to_formatter(sd);
> +	struct device *dev = formatter->dev;
> +	u64 sink_streams;
> +	int ret;
> +
> +	if (!formatter->csi_sd) {
> +		dev_err(dev, "CSI controller don't link with formatter\n");
> +		return -EPIPE;
> +	}
> +
> +	if (!formatter->enabled_streams) {
> +		ret = pm_runtime_resume_and_get(formatter->dev);
> +		if (ret < 0) {
> +			dev_err(dev, "Formatter runtime get fail\n");
> +			return ret;
> +		}
> +	}
> +
> +	ret = csi_formatter_start_stream(formatter, streams_mask);
> +	if (ret)
> +		goto runtime_put;

if enable_streams is not 0, and goto runtime_put, it will cause runtime
refer count miss match.

I think you can call runtime_get uncondtional.

	PM_RUNTIME_ACQUIRE(xspi->dev, pm);
	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
	if (ret)
		return ret;

PM_RUNTIME_ACQUIRE already in linux-next, it should be safe to use for
next version.


> +
> +	sink_streams = v4l2_subdev_state_xlate_streams(state,
> +						       CSI_FORMATTER_PAD_SOURCE,
> +						       CSI_FORMATTER_PAD_SINK,
> +						       &streams_mask);
> +
> +	dev_dbg(dev, "remote sd: %s pad: %u, sink_stream:0x%llx\n",
> +		formatter->csi_sd->name, formatter->remote_pad, sink_streams);
> +
> +	ret = v4l2_subdev_enable_streams(formatter->csi_sd, formatter->remote_pad,
> +					 sink_streams);
> +	if (ret)
> +		goto runtime_put;
> +
> +	formatter->enabled_streams |= streams_mask;
> +
> +	return 0;
> +
> +runtime_put:
> +	pm_runtime_put(formatter->dev);
> +	return ret;
> +}
> +
> +static int csi_formatter_stop_stream(struct csi_formatter *formatter,
> +				     u64 stream_mask)
> +{
> +	unsigned int i;
> +	int vc;
> +
> +	for (i = 0; i < V4L2_FRAME_DESC_ENTRY_MAX; ++i) {
> +		if (stream_mask & BIT(i))
> +			break;
> +	}
> +
> +	if (i == V4L2_FRAME_DESC_ENTRY_MAX) {
> +		dev_err(formatter->dev, "Stream ID out of range\n");
> +		return -EINVAL;
> +	}
> +
> +	vc = get_vc(formatter, i);
> +
> +	if (vc < 0 || vc > CSI_FORMATTER_VC_MAX) {
> +		dev_err(formatter->dev, "Invalid virtual channel(%d)\n", vc);
> +		return -EINVAL;
> +	}
> +
> +	formatter_write(formatter, CSI_VCx_PIXEL_DATA_TYPE(vc), 0);
> +
> +	return 0;
> +}
> +
> +static int formatter_subdev_disable_streams(struct v4l2_subdev *sd,
> +					    struct v4l2_subdev_state *state,
> +					    u32 pad, u64 streams_mask)
> +{
> +	struct csi_formatter *formatter = sd_to_formatter(sd);
> +	u64 sink_streams;
> +	int ret;
> +
> +	sink_streams = v4l2_subdev_state_xlate_streams(state,
> +						       CSI_FORMATTER_PAD_SOURCE,
> +						       CSI_FORMATTER_PAD_SINK,
> +						       &streams_mask);
> +
> +	ret = v4l2_subdev_disable_streams(formatter->csi_sd, formatter->remote_pad,
> +					  sink_streams);
> +	if (ret)
> +		return ret;
> +
> +	ret = csi_formatter_stop_stream(formatter, streams_mask);
> +	if (ret)
> +		return ret;
> +
> +	formatter->enabled_streams &= ~streams_mask;
> +
> +	if (!formatter->enabled_streams)
> +		pm_runtime_put(formatter->dev);
> +
> +	return 0;
> +}
> +
> +static const struct v4l2_subdev_pad_ops formatter_subdev_pad_ops = {
> +	.enum_mbus_code		= formatter_subdev_enum_mbus_code,
> +	.get_fmt		= v4l2_subdev_get_fmt,
> +	.set_fmt		= formatter_subdev_set_fmt,
> +	.get_frame_desc		= formatter_subdev_get_frame_desc,
> +	.set_routing		= formatter_subdev_set_routing,
> +	.enable_streams		= formatter_subdev_enable_streams,
> +	.disable_streams	= formatter_subdev_disable_streams,
> +};
> +
> +static const struct v4l2_subdev_ops formatter_subdev_ops = {
> +	.pad = &formatter_subdev_pad_ops,
> +};
> +
> +static const struct v4l2_subdev_internal_ops formatter_internal_ops = {
> +	.init_state = formatter_subdev_init_state,
> +};
> +
> +/* -----------------------------------------------------------------------------
> + * Media entity operations
> + */
> +
> +static const struct media_entity_operations formatter_entity_ops = {
> +	.link_validate	= v4l2_subdev_link_validate,
> +	.get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1,
> +};
> +
> +static int csi_formatter_subdev_init(struct csi_formatter *formatter)
> +{
> +	struct v4l2_subdev *sd = &formatter->sd;
> +	int ret;
> +
> +	v4l2_subdev_init(sd, &formatter_subdev_ops);
> +
> +	snprintf(sd->name, sizeof(sd->name), "%s", dev_name(formatter->dev));
> +	sd->internal_ops = &formatter_internal_ops;
> +
> +	sd->owner = THIS_MODULE;
> +	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
> +		     V4L2_SUBDEV_FL_HAS_EVENTS |
> +		     V4L2_SUBDEV_FL_STREAMS;
> +	sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
> +	sd->entity.ops = &formatter_entity_ops;
> +	sd->dev = formatter->dev;
> +
> +	formatter->pads[CSI_FORMATTER_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
> +	formatter->pads[CSI_FORMATTER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
> +
> +	ret = media_entity_pads_init(&sd->entity, CSI_FORMATTER_PAD_NUM,
> +				     formatter->pads);
> +	if (ret) {
> +		dev_err(formatter->dev, "Failed to init pads\n");
> +		return ret;
> +	}
> +
> +	ret = v4l2_subdev_init_finalize(sd);
> +	if (ret)
> +		media_entity_cleanup(&sd->entity);
> +
> +	return ret;
> +}
> +
> +static inline struct csi_formatter *
> +notifier_to_formatter(struct v4l2_async_notifier *n)
> +{
> +	return container_of(n, struct csi_formatter, notifier);
> +}
> +
> +static int csi_formatter_notify_bound(struct v4l2_async_notifier *notifier,
> +				      struct v4l2_subdev *sd,
> +				      struct v4l2_async_connection *asc)
> +{
> +	const unsigned int link_flags = MEDIA_LNK_FL_IMMUTABLE
> +				      | MEDIA_LNK_FL_ENABLED;
> +	struct csi_formatter *formatter = notifier_to_formatter(notifier);
> +	struct v4l2_subdev *sdev = &formatter->sd;
> +	struct media_pad *sink = &sdev->entity.pads[CSI_FORMATTER_PAD_SINK];
> +	struct media_pad *remote_pad;
> +	int ret;
> +
> +	formatter->csi_sd = sd;
> +
> +	dev_dbg(formatter->dev, "Bound subdev: %s pad\n", sd->name);
> +
> +	ret = v4l2_create_fwnode_links_to_pad(sd, sink, link_flags);
> +	if (ret < 0)
> +		return ret;
> +
> +	remote_pad = media_pad_remote_pad_first(sink);
> +	if (!remote_pad) {
> +		dev_err(formatter->dev, "Pipe not setup correctly\n");
> +		return -EPIPE;
> +	}
> +	formatter->remote_pad = remote_pad->index;
> +
> +	return 0;
> +}
> +
> +static const struct v4l2_async_notifier_operations formatter_notify_ops = {
> +	.bound = csi_formatter_notify_bound,
> +};
> +
> +static int csi_formatter_async_register(struct csi_formatter *formatter)
> +{
> +	struct device *dev = formatter->dev;
> +	struct v4l2_async_connection *asc;
> +	struct fwnode_handle *ep;

struct fwnode_handle *ep __free(fwnode_handle) = fwnode_graph_get_endpoint_by_id()

https://lore.kernel.org/all/CAHk-=whPZoi03ZwphxiW6cuWPtC3nyKYS8_BThgztCdgPWP1WA at mail.gmail.com/

Laurent Pinchart:

	look like prefer this way, let me know if I am wrong.

> +	int ret;
> +
> +	v4l2_async_subdev_nf_init(&formatter->notifier, &formatter->sd);
> +
> +	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0,
> +					     FWNODE_GRAPH_ENDPOINT_NEXT);
> +	if (!ep)
> +		return -ENOTCONN;
> +
> +	asc = v4l2_async_nf_add_fwnode_remote(&formatter->notifier, ep,
> +					      struct v4l2_async_connection);
> +	if (IS_ERR(asc)) {
> +		fwnode_handle_put(ep);
> +		return PTR_ERR(asc);

missed fwnode_handle_put(ep);

> +	}
> +
> +	fwnode_handle_put(ep);
> +
> +	formatter->notifier.ops = &formatter_notify_ops;
> +
> +	ret = v4l2_async_nf_register(&formatter->notifier);
> +	if (ret)
> +		return ret;
> +
> +	return v4l2_async_register_subdev(&formatter->sd);
> +}
> +
> +/* -----------------------------------------------------------------------------
> + * Suspend/resume
> + */
> +
> +static int csi_formatter_system_suspend(struct device *dev)
> +{
> +	return pm_runtime_force_suspend(dev);
> +}
> +
> +static int csi_formatter_system_resume(struct device *dev)
> +{
> +	int ret;
> +
> +	ret = pm_runtime_force_resume(dev);
> +	if (ret < 0) {
> +		dev_err(dev, "force resume %s failed!\n", dev_name(dev));
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int csi_formatter_runtime_suspend(struct device *dev)
> +{
> +	struct v4l2_subdev *sd = dev_get_drvdata(dev);
> +	struct csi_formatter *formatter = sd_to_formatter(sd);
> +
> +	clk_disable_unprepare(formatter->clk);
> +
> +	return 0;
> +}
> +
> +static int csi_formatter_runtime_resume(struct device *dev)
> +{
> +	struct v4l2_subdev *sd = dev_get_drvdata(dev);
> +	struct csi_formatter *formatter = sd_to_formatter(sd);
> +
> +	return clk_prepare_enable(formatter->clk);
> +}
> +
> +static const struct dev_pm_ops csi_formatter_pm_ops = {
> +	SET_SYSTEM_SLEEP_PM_OPS(csi_formatter_system_suspend,
> +				csi_formatter_system_resume)
> +	SET_RUNTIME_PM_OPS(csi_formatter_runtime_suspend,
> +			   csi_formatter_runtime_resume,
> +			   NULL)


use modern:
SYSTEM_SLEEP_PM_OPS
RUNTIME_PM_OPS

ref
https://lore.kernel.org/imx/20250411085932.1902662-1-arnd at kernel.org/

> +};
> +
> +static int csi_formatter_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct csi_formatter *formatter;
> +	u32 val;
> +	int ret;
> +
> +	formatter = devm_kzalloc(dev, sizeof(*formatter), GFP_KERNEL);
> +	if (!formatter)
> +		return -ENOMEM;
> +
> +	formatter->dev = dev;
> +
> +	formatter->regs = syscon_node_to_regmap(dev->parent->of_node);
> +	if (IS_ERR(formatter->regs)) {
> +		dev_err(dev, "Failed to get csi formatter regmap\n");
> +		return -ENODEV;

return dev_err_probe(), check others

> +	}
> +
> +	ret = of_property_read_u32(dev->of_node, "reg", &val);
> +	if (ret < 0) {
> +		dev_err(dev, "Failed to get csi formatter reg property\n");
> +		return ret;
> +	}
> +	formatter->reg_offset = val;
> +
> +	formatter->clk = devm_clk_get(dev, NULL);
> +	if (IS_ERR(formatter->clk)) {
> +		dev_err(dev, "Failed to get pixel clock\n");
> +		return PTR_ERR(formatter->clk);
> +	}
> +
> +	ret = csi_formatter_subdev_init(formatter);
> +	if (ret < 0) {
> +		dev_err(dev, "formatter subdev init fail\n");
> +		return ret;
> +	}
> +
> +	/* Initialize formatter pixel format */
> +	formatter->fmt = find_csi_format(formatter_default_fmt.code);
> +
> +	ret = csi_formatter_async_register(formatter);
> +	if (ret < 0) {
> +		v4l2_subdev_cleanup(&formatter->sd);
> +		dev_err(dev, "Async register failed\n");
> +		return ret;
> +	}
> +
> +	platform_set_drvdata(pdev, &formatter->sd);
> +
> +	/* Enable runtime PM. */
> +	pm_runtime_enable(dev);
> +
> +	return 0;
> +}
> +
> +static void csi_formatter_remove(struct platform_device *pdev)
> +{
> +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> +	struct csi_formatter *formatter = sd_to_formatter(sd);
> +
> +	v4l2_async_nf_unregister(&formatter->notifier);
> +	v4l2_async_nf_cleanup(&formatter->notifier);
> +	v4l2_async_unregister_subdev(&formatter->sd);
> +
> +	pm_runtime_disable(&pdev->dev);
> +	media_entity_cleanup(&formatter->sd.entity);
> +	pm_runtime_set_suspended(&pdev->dev);
> +}
> +
> +static const struct of_device_id csi_formatter_of_match[] = {
> +	{ .compatible = "fsl,imx9-csi-formatter" },
> +	{ /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(of, csi_formatter_of_match);
> +
> +static struct platform_driver csi_formatter_device_driver = {
> +	.driver = {
> +		.owner          = THIS_MODULE,
> +		.name           = CSI_FORMATTER_DRV_NAME,
> +		.of_match_table = csi_formatter_of_match,
> +		.pm             = &csi_formatter_pm_ops,

pm_ptr()

> +	},
> +	.probe  = csi_formatter_probe,
> +	.remove = csi_formatter_remove,
> +};
> +
> +module_platform_driver(csi_formatter_device_driver);
> +
> +MODULE_ALIAS("platform:" CSI_FORMATTER_DRV_NAME);

drop this one.

Frank
> +MODULE_AUTHOR("NXP Semiconductor, Inc.");
> +MODULE_DESCRIPTION("NXP i.MX9 CSI Pixel Formatter driver");
> +MODULE_LICENSE("GPL");
>
> --
> 2.34.1
>


From Frank.li at nxp.com  Wed Dec  3 09:41:55 2025
From: Frank.li at nxp.com (Frank Li)
Date: Wed, 3 Dec 2025 12:41:55 -0500
Subject: [PATCH V2] arm64: dts: imx8qm-ss-dma: correct the dma channels
 of lpuart
In-Reply-To: <20251203015956.116364-1-sherry.sun@nxp.com>
References: <20251203015956.116364-1-sherry.sun@nxp.com>
Message-ID: <aTB2Y540EtnQUzWH@lizhi-Precision-Tower-5810>

On Wed, Dec 03, 2025 at 09:59:56AM +0800, Sherry Sun wrote:
> The commit 616effc0272b5 ("arm64: dts: imx8: Fix lpuart DMA channel
> order") swap uart rx and tx channel at common imx8-ss-dma.dtsi. But miss
> update imx8qm-ss-dma.dtsi.
>
> The commit 5a8e9b022e569 ("arm64: dts: imx8qm-ss-dma: Pass lpuart
> dma-names") just simple add dma-names as binding doc requirement.
>
> Correct lpuart0 - lpuart3 dma rx and tx channels, and use defines for
> the FSL_EDMA_RX flag.
>
> Fixes: 5a8e9b022e56 ("arm64: dts: imx8qm-ss-dma: Pass lpuart dma-names")
> Signed-off-by: Sherry Sun <sherry.sun at nxp.com>
> ---
Reviewed-by: Frank Li <Frank.Li at nxp.com>

> Changes in V2:
> 1. Correct the fixes commit as Frank and Alexander suggested.
> ---
>  arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi
> index 5f24850bf322..974e193f8dcb 100644
> --- a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi
> +++ b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi
> @@ -172,25 +172,25 @@ &flexcan3 {
>
>  &lpuart0 {
>  	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
> -	dmas = <&edma2 13 0 0>, <&edma2 12 0 1>;
> +	dmas = <&edma2 12 0 FSL_EDMA_RX>, <&edma2 13 0 0>;
>  	dma-names = "rx","tx";
>  };
>
>  &lpuart1 {
>  	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
> -	dmas = <&edma2 15 0 0>, <&edma2 14 0 1>;
> +	dmas = <&edma2 14 0 FSL_EDMA_RX>, <&edma2 15 0 0>;
>  	dma-names = "rx","tx";
>  };
>
>  &lpuart2 {
>  	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
> -	dmas = <&edma2 17 0 0>, <&edma2 16 0 1>;
> +	dmas = <&edma2 16 0 FSL_EDMA_RX>, <&edma2 17 0 0>;
>  	dma-names = "rx","tx";
>  };
>
>  &lpuart3 {
>  	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
> -	dmas = <&edma2 19 0 0>, <&edma2 18 0 1>;
> +	dmas = <&edma2 18 0 FSL_EDMA_RX>, <&edma2 19 0 0>;
>  	dma-names = "rx","tx";
>  };
>
> --
> 2.34.1
>


From krzk at kernel.org  Wed Dec  3 09:42:11 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 3 Dec 2025 18:42:11 +0100
Subject: [PATCH v20 3/7] firmware: imx: add driver for NXP EdgeLock
 Enclave
In-Reply-To: <aTBsdW0lpZSCVsgp@lizhi-Precision-Tower-5810>
References: <20251203-imx-se-if-v20-0-a04a25c4255f@nxp.com>
 <20251203-imx-se-if-v20-3-a04a25c4255f@nxp.com>
 <1ee383c7-ccbc-4c90-adf3-bfbe87fb6765@kernel.org>
 <aTBsdW0lpZSCVsgp@lizhi-Precision-Tower-5810>
Message-ID: <48d5895d-fde0-4795-8049-788fa3171fde@kernel.org>

On 03/12/2025 17:59, Frank Li wrote:
> On Wed, Dec 03, 2025 at 08:20:50AM +0100, Krzysztof Kozlowski wrote:
>> On 03/12/2025 07:48, Pankaj Gupta wrote:
>>> Add driver for enabling MU based communication interface to secure-enclave.
>>>
>>> NXP hardware IP(s) for secure-enclaves like Edgelock Enclave(ELE), are
>>> embedded in the SoC to support the features like HSM, SHE & V2X, using
>>> message based communication interface.
>>>
>>> The secure enclave FW communicates with Linux over single or multiple
>>> dedicated messaging unit(MU) based interface(s).
>>> Exists on i.MX SoC(s) like i.MX8ULP, i.MX93, i.MX95 etc.
>>>
>>> For i.MX9x SoC(s) there is at least one dedicated ELE MU(s) for each
>>> world - Linux(one or more) and OPTEE-OS (one or more).
>>>
>>> Other dependent kernel drivers will be:
>>> - NVMEM: that supports non-volatile devices like EFUSES,
>>>          managed by NXP's secure-enclave.
>>>
>>> Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
>>> Reviewed-by: Frank Li <Frank.Li at nxp.com>
>>> ---
>>>  drivers/firmware/imx/Kconfig        |  13 ++
>>>  drivers/firmware/imx/Makefile       |   2 +
>>>  drivers/firmware/imx/ele_base_msg.c | 269 ++++++++++++++++++++++++
>>>  drivers/firmware/imx/ele_base_msg.h |  95 +++++++++
>>>  drivers/firmware/imx/ele_common.c   | 333 ++++++++++++++++++++++++++++++
>>>  drivers/firmware/imx/ele_common.h   |  45 ++++
>>>  drivers/firmware/imx/se_ctrl.c      | 401 ++++++++++++++++++++++++++++++++++++
>>>  drivers/firmware/imx/se_ctrl.h      |  86 ++++++++
>>>  include/linux/firmware/imx/se_api.h |  14 ++
>>>  9 files changed, 1258 insertions(+)
>>>
>>> diff --git a/drivers/firmware/imx/Kconfig b/drivers/firmware/imx/Kconfig
>>> index 127ad752acf8..5fe96299b704 100644
>>> --- a/drivers/firmware/imx/Kconfig
>>> +++ b/drivers/firmware/imx/Kconfig
>>> @@ -55,3 +55,16 @@ config IMX_SCMI_MISC_DRV
>>>  	  core that could provide misc functions such as board control.
>>>
>>>  	  This driver can also be built as a module.
>>> +
>>> +config IMX_SEC_ENCLAVE
>>> +	tristate "i.MX Embedded Secure Enclave - EdgeLock Enclave Firmware driver."
>>> +	depends on IMX_MBOX && ARCH_MXC && ARM64
>>> +	select FW_LOADER
>>> +	default m if ARCH_MXC
>>> +
>>> +	help
>>> +	  Exposes APIs supported by the iMX Secure Enclave HW IP called:
>>> +	  - EdgeLock Enclave Firmware (for i.MX8ULP, i.MX93),
>>> +	    like base, HSM, V2X & SHE using the SAB protocol via the shared Messaging
>>> +	    Unit. This driver exposes these interfaces via a set of file descriptors
>>> +	    allowing to configure shared memory, send and receive messages.
>>> diff --git a/drivers/firmware/imx/Makefile b/drivers/firmware/imx/Makefile
>>> index 3bbaffa6e347..4412b15846b1 100644
>>> --- a/drivers/firmware/imx/Makefile
>>> +++ b/drivers/firmware/imx/Makefile
>>> @@ -4,3 +4,5 @@ obj-$(CONFIG_IMX_SCU)		+= imx-scu.o misc.o imx-scu-irq.o rm.o imx-scu-soc.o
>>>  obj-${CONFIG_IMX_SCMI_CPU_DRV}	+= sm-cpu.o
>>>  obj-${CONFIG_IMX_SCMI_MISC_DRV}	+= sm-misc.o
>>>  obj-${CONFIG_IMX_SCMI_LMM_DRV}	+= sm-lmm.o
>>> +sec_enclave-objs		= se_ctrl.o ele_common.o ele_base_msg.o
>>> +obj-${CONFIG_IMX_SEC_ENCLAVE}	+= sec_enclave.o
>>> diff --git a/drivers/firmware/imx/ele_base_msg.c b/drivers/firmware/imx/ele_base_msg.c
>>> new file mode 100644
>>> index 000000000000..a070acbd895c
>>> --- /dev/null
>>> +++ b/drivers/firmware/imx/ele_base_msg.c
>>> @@ -0,0 +1,269 @@
>>> +// SPDX-License-Identifier: GPL-2.0+
>>> +/*
>>> + * Copyright 2025 NXP
>>> + */
>>> +
>>> +#include <linux/types.h>
>>> +
>>> +#include <linux/completion.h>
>>> +#include <linux/dma-mapping.h>
>>> +#include <linux/genalloc.h>
>>> +
>>> +#include "ele_base_msg.h"
>>> +#include "ele_common.h"
>>> +
>>> +#define FW_DBG_DUMP_FIXED_STR		"ELE"
>>> +
>>> +int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info)
>>> +{
>>> +	struct se_api_msg *tx_msg __free(kfree) = NULL;
>>> +	struct se_api_msg *rx_msg __free(kfree) = NULL;
>>
>> No, don't use this syntax. This is explicitly discouraged.
>>
>> NAK
> 
> Add link for reference.
> 
> https://lore.kernel.org/all/CAHk-=whPZoi03ZwphxiW6cuWPtC3nyKYS8_BThgztCdgPWP1WA at mail.gmail.com/

This is since beginning documented in kernel, so contributor could read
cleanup docs before using them. Above Linus remark is nothing new, he
already wrote it ~2 years ago.

Best regards,
Krzysztof


From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec  3 09:59:42 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed,  3 Dec 2025 18:59:42 +0100
Subject: [GIT PULL 1/2] samsung: drivers: second late for v6.19
Message-ID: <20251203175942.296554-3-krzysztof.kozlowski@oss.qualcomm.com>

From: Krzysztof Kozlowski <krzk at kernel.org>

Hi,

Second drivers pull, but rebased on master/6.18-rc1, with late fixes.  Would be
nice if these go to v6.19.

Best regards,
Krzysztof


The following changes since commit 3a8660878839faadb4f1a6dd72c3179c1df56787:

  Linux 6.18-rc1 (2025-10-12 13:42:36 -0700)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux.git tags/samsung-drivers-6.19-2-late

for you to fetch changes up to 990eb9a8eb4540ab90c7b34bb07b87ff13881cad:

  soc: samsung: exynos-pmu: fix device leak on regmap lookup (2025-11-27 16:55:38 +0100)

----------------------------------------------------------------
Samsung SoC drivers for v6.19, part two

Two fixes for Exynos PMU (Power Management Unit) driver:

1. Silence lockdep warning being actually a false positive, but quite
   disturbing during testing.  Issue was introduced in v6.18.

2. Drop device refcount when requesting device regmap with
   exynos_get_pmu_regmap_by_phandle().  Issue was introduced much
   earlier (around v6.9), with code being rewritten in between.

----------------------------------------------------------------
Johan Hovold (1):
      soc: samsung: exynos-pmu: fix device leak on regmap lookup

Marek Szyprowski (1):
      soc: samsung: exynos-pmu: Fix structure initialization

 drivers/soc/samsung/exynos-pmu.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)


From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec  3 09:59:43 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed,  3 Dec 2025 18:59:43 +0100
Subject: [GIT PULL 2/2] ARM: dts: samsung: fixes for v6.19
In-Reply-To: <20251203175942.296554-3-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251203175942.296554-3-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <20251203175942.296554-4-krzysztof.kozlowski@oss.qualcomm.com>

From: Krzysztof Kozlowski <krzk at kernel.org>

Hi,

Non-critical DT fixes, broken since v6.14 by a change in brcmfmac driver, but
we noticed only recently.

Best regards,
Krzysztof


The following changes since commit 3a8660878839faadb4f1a6dd72c3179c1df56787:

  Linux 6.18-rc1 (2025-10-12 13:42:36 -0700)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux.git tags/samsung-dt-6.19

for you to fetch changes up to 2ff147fdfa99b8cbb8c2833e685fde7c42580ae6:

  ARM: dts: samsung: exynos4412-midas: turn off SDIO WLAN chip during system suspend (2025-11-27 16:07:16 +0100)

----------------------------------------------------------------
Samsung DTS ARM changes for v6.19

Fix WiFi on Exynos4210 and Exynos4412 boards with Broadcom chip after
system suspend and resume, by using cap-power-off-card to power off the
WiFi during suspend.

----------------------------------------------------------------
Marek Szyprowski (4):
      ARM: dts: samsung: universal_c210: turn off SDIO WLAN chip during system suspend
      ARM: dts: samsung: exynos4210-i9100: turn off SDIO WLAN chip during system suspend
      ARM: dts: samsung: exynos4210-trats: turn off SDIO WLAN chip during system suspend
      ARM: dts: samsung: exynos4412-midas: turn off SDIO WLAN chip during system suspend

 arch/arm/boot/dts/samsung/exynos4210-i9100.dts          | 1 +
 arch/arm/boot/dts/samsung/exynos4210-trats.dts          | 1 +
 arch/arm/boot/dts/samsung/exynos4210-universal_c210.dts | 1 +
 arch/arm/boot/dts/samsung/exynos4412-midas.dtsi         | 1 +
 4 files changed, 4 insertions(+)


From kees at kernel.org  Wed Dec  3 10:02:21 2025
From: kees at kernel.org (Kees Cook)
Date: Wed, 3 Dec 2025 10:02:21 -0800
Subject: [PATCH 1/2] lkdtm/bugs: Add cases for BUG and PANIC occurring in
 hardirq context
In-Reply-To: <20251112175316.2841017-5-ardb+git@google.com>
References: <20251112175316.2841017-4-ardb+git@google.com>
 <20251112175316.2841017-5-ardb+git@google.com>
Message-ID: <202512030959.87E62F908@keescook>

On Wed, Nov 12, 2025 at 06:53:18PM +0100, Ard Biesheuvel wrote:
> From: Ard Biesheuvel <ardb at kernel.org>
> 
> Add lkdtm cases to trigger a BUG() or panic() from hardirq context. This
> is useful for testing pstore behavior being invoked from such contexts.

Sorry I lost this! Thanks for the offline ping. :)

> 
> Signed-off-by: Ard Biesheuvel <ardb at kernel.org>
> ---
>  drivers/misc/lkdtm/bugs.c | 53 ++++++++++++++++++++
>  1 file changed, 53 insertions(+)
> 
> diff --git a/drivers/misc/lkdtm/bugs.c b/drivers/misc/lkdtm/bugs.c
> index 376047beea3d..fa05d77acb55 100644
> --- a/drivers/misc/lkdtm/bugs.c
> +++ b/drivers/misc/lkdtm/bugs.c
> @@ -8,6 +8,7 @@
>  #include "lkdtm.h"
>  #include <linux/cpu.h>
>  #include <linux/list.h>
> +#include <linux/hrtimer.h>
>  #include <linux/sched.h>
>  #include <linux/sched/signal.h>
>  #include <linux/sched/task_stack.h>
> @@ -100,11 +101,61 @@ static void lkdtm_PANIC_STOP_IRQOFF(void)
>  	stop_machine(panic_stop_irqoff_fn, &v, cpu_online_mask);
>  }
>  
> +static bool wait_for_panic;
> +
> +static enum hrtimer_restart panic_in_hardirq(struct hrtimer *timer)
> +{
> +	panic("from hard IRQ context");
> +
> +	wait_for_panic = false;
> +	return HRTIMER_NORESTART;
> +}
> +
> +static void lkdtm_PANIC_IN_HARDIRQ(void)
> +{
> +	struct hrtimer timer;
> +
> +	wait_for_panic = true;
> +	hrtimer_setup_on_stack(&timer, panic_in_hardirq,
> +			       CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD);
> +	hrtimer_start(&timer, us_to_ktime(100), HRTIMER_MODE_REL_HARD);
> +
> +	while (wait_for_panic)
> +		;
> +
> +	hrtimer_cancel(&timer);
> +}
> +
>  static void lkdtm_BUG(void)
>  {
>  	BUG();
>  }
>  
> +static bool wait_for_bug;
> +
> +static enum hrtimer_restart bug_in_hardirq(struct hrtimer *timer)
> +{
> +	BUG();
> +
> +	wait_for_bug = false;
> +	return HRTIMER_NORESTART;
> +}
> +
> +static void lkdtm_BUG_IN_HARDIRQ(void)
> +{
> +	struct hrtimer timer;
> +
> +	wait_for_bug = true;
> +	hrtimer_setup_on_stack(&timer, bug_in_hardirq,
> +			       CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD);
> +	hrtimer_start(&timer, us_to_ktime(100), HRTIMER_MODE_REL_HARD);
> +
> +	while (wait_for_bug)
> +		;
> +
> +	hrtimer_cancel(&timer);
> +}
> +
>  static int warn_counter;
>  
>  static void lkdtm_WARNING(void)
> @@ -696,7 +747,9 @@ static noinline void lkdtm_CORRUPT_PAC(void)
>  static struct crashtype crashtypes[] = {
>  	CRASHTYPE(PANIC),
>  	CRASHTYPE(PANIC_STOP_IRQOFF),
> +	CRASHTYPE(PANIC_IN_HARDIRQ),
>  	CRASHTYPE(BUG),
> +	CRASHTYPE(BUG_IN_HARDIRQ),
>  	CRASHTYPE(WARNING),
>  	CRASHTYPE(WARNING_MESSAGE),
>  	CRASHTYPE(EXCEPTION),

This all looks good to me. I always ask that new tests also get added to
the lkdtm selftest runner list in tools/testing/selftests/lkdtm/tests.txt

IIUC, bug in hardirq will result in a panic, so both these tests will
take out the entire system, so they should be skipped for the selftest.
Perhaps:


diff --git a/tools/testing/selftests/lkdtm/tests.txt b/tools/testing/selftests/lkdtm/tests.txt
index cff124c1eddd..67cd53715d93 100644
--- a/tools/testing/selftests/lkdtm/tests.txt
+++ b/tools/testing/selftests/lkdtm/tests.txt
@@ -1,6 +1,8 @@
 #PANIC
 #PANIC_STOP_IRQOFF Crashes entire system
+#PANIC_IN_HARDIRQ Crashes entire system
 BUG kernel BUG at
+#BUG_IN_HARDIRQ Crashes entire system
 WARNING WARNING:
 WARNING_MESSAGE message trigger
 EXCEPTION




-- 
Kees Cook


From rdunlap at infradead.org  Wed Dec  3 10:02:49 2025
From: rdunlap at infradead.org (Randy Dunlap)
Date: Wed, 3 Dec 2025 10:02:49 -0800
Subject: [PATCH v20 3/7] firmware: imx: add driver for NXP EdgeLock
 Enclave
In-Reply-To: <20251203-imx-se-if-v20-3-a04a25c4255f@nxp.com>
References: <20251203-imx-se-if-v20-0-a04a25c4255f@nxp.com>
 <20251203-imx-se-if-v20-3-a04a25c4255f@nxp.com>
Message-ID: <33d659bd-eba9-4b47-a374-32b6c763d640@infradead.org>

Hi--

On 12/2/25 10:48 PM, Pankaj Gupta wrote:
> diff --git a/drivers/firmware/imx/Kconfig b/drivers/firmware/imx/Kconfig
> index 127ad752acf8..5fe96299b704 100644
> --- a/drivers/firmware/imx/Kconfig
> +++ b/drivers/firmware/imx/Kconfig
> @@ -55,3 +55,16 @@ config IMX_SCMI_MISC_DRV
>  	  core that could provide misc functions such as board control.
>  
>  	  This driver can also be built as a module.
> +
> +config IMX_SEC_ENCLAVE
> +	tristate "i.MX Embedded Secure Enclave - EdgeLock Enclave Firmware driver."
> +	depends on IMX_MBOX && ARCH_MXC && ARM64

Is it possible to work COMPILE_TEST into this dependency?

> +	select FW_LOADER
> +	default m if ARCH_MXC
> +
> +	help
> +	  Exposes APIs supported by the iMX Secure Enclave HW IP called:
> +	  - EdgeLock Enclave Firmware (for i.MX8ULP, i.MX93),
> +	    like base, HSM, V2X & SHE using the SAB protocol via the shared Messaging
> +	    Unit. This driver exposes these interfaces via a set of file descriptors
> +	    allowing to configure shared memory, send and receive messages.

thanks.
-- 
~Randy



From kees at kernel.org  Wed Dec  3 10:02:56 2025
From: kees at kernel.org (Kees Cook)
Date: Wed, 3 Dec 2025 10:02:56 -0800
Subject: [PATCH 1/2] lkdtm/bugs: Add cases for BUG and PANIC occurring in
 hardirq context
In-Reply-To: <aR4ERqeHFbSWooZW@arm.com>
References: <20251112175316.2841017-4-ardb+git@google.com>
 <20251112175316.2841017-5-ardb+git@google.com>
 <aR4ERqeHFbSWooZW@arm.com>
Message-ID: <202512031002.ED3098374@keescook>

On Wed, Nov 19, 2025 at 05:54:14PM +0000, Catalin Marinas wrote:
> On Wed, Nov 12, 2025 at 06:53:18PM +0100, Ard Biesheuvel wrote:
> > From: Ard Biesheuvel <ardb at kernel.org>
> > 
> > Add lkdtm cases to trigger a BUG() or panic() from hardirq context. This
> > is useful for testing pstore behavior being invoked from such contexts.
> > 
> > Signed-off-by: Ard Biesheuvel <ardb at kernel.org>
> > ---
> >  drivers/misc/lkdtm/bugs.c | 53 ++++++++++++++++++++
> >  1 file changed, 53 insertions(+)
> 
> Kees, are you ok with this patch? Happy to take it through the arm64
> tree together with the second one.

With the small addition I just sent, yeah, this is fine by me. :)

Reviewed-by: Kees Cook <kees at kernel.org>

-- 
Kees Cook


From iuliana.prodan at nxp.com  Wed Dec  3 10:09:10 2025
From: iuliana.prodan at nxp.com (Iuliana Prodan)
Date: Wed, 3 Dec 2025 20:09:10 +0200
Subject: [PATCH 2/2] remoteproc: imx_dsp_rproc: Wait for suspend ACK only
 if WAIT_FW_READY is set
In-Reply-To: <l5udmggplyatnozipk7tjugkkzwtglckjejq67aa7q4mlywxw4@4vhjkbhjthnn>
References: <20251125124903.962295-1-iuliana.prodan@oss.nxp.com>
 <20251125124903.962295-2-iuliana.prodan@oss.nxp.com>
 <l5udmggplyatnozipk7tjugkkzwtglckjejq67aa7q4mlywxw4@4vhjkbhjthnn>
Message-ID: <6a6e90fb-c8be-49ad-83b4-4b602489a616@nxp.com>

On 11/26/2025 10:21 PM, Bjorn Andersson wrote:
> On Tue, Nov 25, 2025 at 02:49:03PM +0200, Iuliana Prodan (OSS) wrote:
>> From: Iuliana Prodan <iuliana.prodan at nxp.com>
>>
>> The DSP suspend path currently waits unconditionally
>> for a suspend ack from the firmware.
>> This breaks firmwares that do not implement the
>> mailbox-based READY handshake, as the DSP never
>> responds and system suspend fails with -EBUSY.
>>
> 
> But if the firmware doesn't implement "mailbox-based READY handshake",
> do you still want to send the RP_MBOX_SUSPEND_SYSTEM message?
> 
If FEATURE_DONT_WAIT_FW_READY is set, it means the remote does not send 
any feedback to the host and does not handle specific messages. In this 
case, it?s better not to send the message at all.

BTW, to avoid confusion with FW_READY macros, I?ll add a new patch to 
rename these macros to FW_CONFIRMATION, since they are used both for 
boot confirmation and other firmware acknowledgments.

> If so, can you clarify here in the commit message that the firmware
> expects the mailbox-based message, and only the "handshake" part should
> be omitted.
> 
> If that part isn't implemented either, then I think you should fix the
> code to not poke the mailbox in the first place.
> 
Yes, will fix in v2.

> 
> Also, wrap your commit message at 75 characters, please.
> 
>> The driver already uses the WAIT_FW_READY flag to
>> indicate that the firmware supports the READY
>> handshake at boot. Apply the same logic during
>> suspend: only wait for the suspend ack when the
>> firmware is expected to support it.
>>
>> Signed-off-by: Iuliana Prodan <iuliana.prodan at nxp.com>
>> ---
>>   drivers/remoteproc/imx_dsp_rproc.c | 7 ++++---
>>   1 file changed, 4 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c
>> index fc0470aa72c1..e25dbe32ef79 100644
>> --- a/drivers/remoteproc/imx_dsp_rproc.c
>> +++ b/drivers/remoteproc/imx_dsp_rproc.c
>> @@ -1327,10 +1327,11 @@ static int imx_dsp_suspend(struct device *dev)
>>   	}
>>   
>>   	/*
>> -	 * DSP need to save the context at suspend.
>> -	 * Here waiting the response for DSP, then power can be disabled.
>> +	 * The DSP must save its context during suspend.
> 
> Please double check that this comment reflect above conclusion.
> 
This is valid for some firmware, like Xtensa Audio Firmware (XAF), where 
we use both firmware-ready replay and the messages are handled on the 
remote side, where the DSP context is saved.

> Regards,
> Bjorn
> 
>> +	 * Wait for a response from the DSP if required before disabling power.
>>   	 */
>> -	if (!wait_for_completion_timeout(&priv->pm_comp, msecs_to_jiffies(100)))
>> +	if (priv->flags & WAIT_FW_READY &&
>> +	    !wait_for_completion_timeout(&priv->pm_comp, msecs_to_jiffies(100)))
>>   		return -EBUSY;
>>   
>>   out:
>> -- 
>> 2.34.1
>>



From suzuki.poulose at arm.com  Wed Dec  3 10:14:51 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Wed, 3 Dec 2025 18:14:51 +0000
Subject: [PATCH v6 6/9] dt-bindings: arm: add an interrupt property for
 Coresight CTCU
In-Reply-To: <20250908-enable-byte-cntr-for-tmc-v6-6-1db9e621441a@oss.qualcomm.com>
References: <20250908-enable-byte-cntr-for-tmc-v6-0-1db9e621441a@oss.qualcomm.com>
 <20250908-enable-byte-cntr-for-tmc-v6-6-1db9e621441a@oss.qualcomm.com>
Message-ID: <66d4488f-941a-4716-b81f-e0f9e1165931@arm.com>

On 08/09/2025 03:01, Jie Gan wrote:
> Add an interrupt property to CTCU device. The interrupt will be triggered
> when the data size in the ETR buffer exceeds the threshold of the
> BYTECNTRVAL register. Programming a threshold in the BYTECNTRVAL register
> of CTCU device will enable the interrupt.
> 
> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
> ---
>   .../devicetree/bindings/arm/qcom,coresight-ctcu.yaml    | 17 +++++++++++++++++
>   1 file changed, 17 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
> index 843b52eaf872..ea05ad8f3dd3 100644
> --- a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
> +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
> @@ -39,6 +39,16 @@ properties:
>       items:
>         - const: apb
>   
> +  interrupts:
> +    items:
> +      - description: Byte cntr interrupt for etr0
> +      - description: Byte cntr interrupt for etr1
> +
> +  interrupt-names:
> +    items:
> +      - const: etr0
> +      - const: etr1

Why are they named "etr0" "etr1" ? That would be confusing, isn't it, 
especially with the Linux driver naming things randomly for the TMC-ETRs.


What we want is the "port" number corresponding to the "TMC-ETR" being
monitored ?

Have you explored other options, "port-0", "port-1" ?

Suzuki

> +
>     in-ports:
>       $ref: /schemas/graph.yaml#/properties/ports
>   
> @@ -56,6 +66,8 @@ additionalProperties: false
>   
>   examples:
>     - |
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +
>       ctcu at 1001000 {
>           compatible = "qcom,sa8775p-ctcu";
>           reg = <0x1001000 0x1000>;
> @@ -63,6 +75,11 @@ examples:
>           clocks = <&aoss_qmp>;
>           clock-names = "apb";
>   
> +        interrupts = <GIC_SPI 270 IRQ_TYPE_EDGE_RISING>,
> +                     <GIC_SPI 262 IRQ_TYPE_EDGE_RISING>;
> +        interrupt-names = "etr0",
> +                          "etr1";
> +
>           in-ports {
>               #address-cells = <1>;
>               #size-cells = <0>;
> 



From nicolas at ndufresne.ca  Wed Dec  3 10:17:44 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 03 Dec 2025 13:17:44 -0500
Subject: [PATCH 16/16] media: rockchip: rga: add rga3 support
In-Reply-To: <ccdcf1c3-4afd-45b7-92d0-c35a31be2188@pengutronix.de>
References: <20251007-spu-rga3-v1-0-36ad85570402@pengutronix.de>
	 <20251007-spu-rga3-v1-16-36ad85570402@pengutronix.de>
	 <cfe8d17416184f11a93e56872c30a6bcaf017ef5.camel@ndufresne.ca>
	 <ccdcf1c3-4afd-45b7-92d0-c35a31be2188@pengutronix.de>
Message-ID: <f1938e17e04cfd1768f90b757813f9187b424505.camel@ndufresne.ca>

Hi,

Le mercredi 03 d?cembre 2025 ? 10:49 +0100, Sven P?schel a ?crit?:
> Hi Nicolas,
> 
> On 10/7/25 9:41 PM, Nicolas Dufresne wrote:
> > Hi,
> > 
> > Le mardi 07 octobre 2025 ? 10:32 +0200, Sven P?schel a ?crit?:
> > 
> > > +}
> > > +
> > > +static void rga3_cmd_enable_win0(struct rga_ctx *ctx)
> > > +{
> > > +	u32 *cmd = ctx->rga->cmdbuf_virt;
> > > +	unsigned int reg;
> > > +
> > > +	reg = RGA3_WIN0_RD_CTRL - RGA3_FIRST_CMD_REG;
> > > +	cmd[reg >> 2] |= FIELD_PREP(RGA3_WIN_ENABLE, 1);
> > > +}
> > > +
> > > +static void rga3_cmd_set_wr_format(struct rga_ctx *ctx)
> > > +{
> > > +	u32 *cmd = ctx->rga->cmdbuf_virt;
> > > +	const struct rga3_fmt *out = ctx->out.fmt;
> > > +	u8 wr_format;
> > > +	unsigned int reg;
> > > +
> > > +	if (out->semi_planar)
> > > +		wr_format = RGA3_RDWR_FORMAT_SEMI_PLANAR;
> > > +	else
> > > +		wr_format = RGA3_RDWR_FORMAT_INTERLEAVED;
> > > +
> > > +	reg = RGA3_WR_CTRL - RGA3_FIRST_CMD_REG;
> > > +	cmd[reg >> 2] |= FIELD_PREP(RGA3_WR_PIC_FORMAT, out->hw_format)
> > > +		????? |? FIELD_PREP(RGA3_WR_YC_SWAP, out->yc_swap)
> > > +		????? |? FIELD_PREP(RGA3_WR_RBUV_SWAP, out->rbuv_swap)
> > > +		????? |? FIELD_PREP(RGA3_WR_FORMAT, wr_format);
> > > +}
> > > +
> > > +static void rga3_cmd_disable_wr_limitation(struct rga_ctx *ctx)
> > > +{
> > > +	u32 *cmd = ctx->rga->cmdbuf_virt;
> > > +	unsigned int reg;
> > > +
> > > +	/* Use the max value to avoid limiting the write speed */
> > > +	reg = RGA3_WR_CTRL - RGA3_FIRST_CMD_REG;
> > > +	cmd[reg >> 2] |= FIELD_PREP(RGA3_WR_SW_OUTSTANDING_MAX, 63);
> > No issue with the code, but quite an interesting feature. We did discussed in
> > pas about using the target framerate (well frame duration in v4l2) to avoid
> > bursting the memory.
> 
> Do you have any links to these discussions or some actual implementation?

That likely happened during a media summit. Philippe Zabel might remember more.
I know for stateful encoders, you can already have two timing information, but
its all vague in my memory.

> 
> ?From the API perspective I didn't really find the desired API to 
> support this feature. While VIDIOC_S_PARM would allow setting an frame 
> interval, the documentation doesn't really encompass this use case (as 
> we won't configure the RGA3 depending on this nor drop frames if the 
> RGA3 is too slow).
> 
> Also limiting the potential burst size only seems practical, when it 
> causes latency issues. Otherwise it should be more efficient to have big 
> bursts (bandwidth and potentially even power consumption wise).

I have no issue with letting it to its maximum. The comment here simply
highlights it, but pretty much all other drivers will hardcore the maximum
working size and move on. In a second thought, if you multi-plex the RGA3 a lot,
you don't want any slower use of it, since it may hang up on the core for
longer. So I'd say, unless we have problems, this is fine as it is.

> 
> Sincerely
> ?? ? Sven

[...]

cheers,
Nicolas
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251203/ef23c6fc/attachment.sig>

From cristian.ciocaltea at collabora.com  Wed Dec  3 10:27:51 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Wed, 03 Dec 2025 20:27:51 +0200
Subject: [PATCH 0/4] Add HDMI 2.0 support to DW HDMI QP TX
Message-ID: <20251203-dw-hdmi-qp-scramb-v1-0-836fe7401a69@collabora.com>

This patch series provides the missing support for high TMDS clock ratio
and scrambling to DW HDMI QP TX library, required for handling HDMI 2.0
display modes on RK3576 & RK3588 SoCs.

In order to allow addressing the SCDC status lost on sink disconnects,
it adds an atomic variant of the drm_bridge_funcs.detect callback and a
new drm_bridge_detect_ctx() helper, which is further used in
drm_bridge_connector to switch to ->detect_ctx hook.

Furthermore, optimize HPD event handling in dw_hdmi_qp Rockchip platform
driver to run the detect cycle on the affected connector only.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
Cristian Ciocaltea (4):
      drm/bridge: Add ->detect_ctx hook and drm_bridge_detect_ctx()
      drm/bridge-connector: Switch to using ->detect_ctx hook
      drm/bridge: dw-hdmi-qp: Add high TMDS clock ratio and scrambling support
      drm/rockchip: dw_hdmi_qp: Do not send HPD events for all connectors

 drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c   | 174 +++++++++++++++++++++++--
 drivers/gpu/drm/display/drm_bridge_connector.c |  73 ++++++-----
 drivers/gpu/drm/drm_bridge.c                   |  58 +++++++++
 drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c |  44 +++----
 include/drm/drm_bridge.h                       |  30 +++++
 5 files changed, 308 insertions(+), 71 deletions(-)
---
base-commit: ac5b392a8c355001c4c3f230a0e4b1f904e359ca
change-id: 20251203-dw-hdmi-qp-scramb-cdbd8b57ccf9



From cristian.ciocaltea at collabora.com  Wed Dec  3 10:27:53 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Wed, 03 Dec 2025 20:27:53 +0200
Subject: [PATCH 2/4] drm/bridge-connector: Switch to using ->detect_ctx
 hook
In-Reply-To: <20251203-dw-hdmi-qp-scramb-v1-0-836fe7401a69@collabora.com>
References: <20251203-dw-hdmi-qp-scramb-v1-0-836fe7401a69@collabora.com>
Message-ID: <20251203-dw-hdmi-qp-scramb-v1-2-836fe7401a69@collabora.com>

In preparation to allow bridge drivers relying on the HDMI connector
framework to provide HDMI 2.0 support, make use of the atomic version of
drm_connector_funcs.detect() hook and invoke the newly introduced
drm_bridge_detect_ctx() helper.

In particular, this is going to be used for triggering an empty modeset
in drm_bridge_funcs.detect_ctx() callback, in order to manage SCDC
status lost on sink disconnects.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/display/drm_bridge_connector.c | 73 ++++++++++++++------------
 1 file changed, 38 insertions(+), 35 deletions(-)

diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index a2d30cf9e06d..0142c612545f 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -200,39 +200,6 @@ static void drm_bridge_connector_disable_hpd(struct drm_connector *connector)
  * Bridge Connector Functions
  */
 
-static enum drm_connector_status
-drm_bridge_connector_detect(struct drm_connector *connector, bool force)
-{
-	struct drm_bridge_connector *bridge_connector =
-		to_drm_bridge_connector(connector);
-	struct drm_bridge *detect = bridge_connector->bridge_detect;
-	struct drm_bridge *hdmi = bridge_connector->bridge_hdmi;
-	enum drm_connector_status status;
-
-	if (detect) {
-		status = detect->funcs->detect(detect, connector);
-
-		if (hdmi)
-			drm_atomic_helper_connector_hdmi_hotplug(connector, status);
-
-		drm_bridge_connector_hpd_notify(connector, status);
-	} else {
-		switch (connector->connector_type) {
-		case DRM_MODE_CONNECTOR_DPI:
-		case DRM_MODE_CONNECTOR_LVDS:
-		case DRM_MODE_CONNECTOR_DSI:
-		case DRM_MODE_CONNECTOR_eDP:
-			status = connector_status_connected;
-			break;
-		default:
-			status = connector_status_unknown;
-			break;
-		}
-	}
-
-	return status;
-}
-
 static void drm_bridge_connector_force(struct drm_connector *connector)
 {
 	struct drm_bridge_connector *bridge_connector =
@@ -270,7 +237,6 @@ static void drm_bridge_connector_reset(struct drm_connector *connector)
 
 static const struct drm_connector_funcs drm_bridge_connector_funcs = {
 	.reset = drm_bridge_connector_reset,
-	.detect = drm_bridge_connector_detect,
 	.force = drm_bridge_connector_force,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
@@ -283,6 +249,42 @@ static const struct drm_connector_funcs drm_bridge_connector_funcs = {
  * Bridge Connector Helper Functions
  */
 
+static int drm_bridge_connector_detect_ctx(struct drm_connector *connector,
+					   struct drm_modeset_acquire_ctx *ctx,
+					   bool force)
+{
+	struct drm_bridge_connector *bridge_connector =
+		to_drm_bridge_connector(connector);
+	struct drm_bridge *detect = bridge_connector->bridge_detect;
+	struct drm_bridge *hdmi = bridge_connector->bridge_hdmi;
+	int ret;
+
+	if (detect) {
+		ret = drm_bridge_detect_ctx(detect, connector, ctx);
+		if (ret < 0)
+			return ret;
+
+		if (hdmi)
+			drm_atomic_helper_connector_hdmi_hotplug(connector, ret);
+
+		drm_bridge_connector_hpd_notify(connector, ret);
+	} else {
+		switch (connector->connector_type) {
+		case DRM_MODE_CONNECTOR_DPI:
+		case DRM_MODE_CONNECTOR_LVDS:
+		case DRM_MODE_CONNECTOR_DSI:
+		case DRM_MODE_CONNECTOR_eDP:
+			ret = connector_status_connected;
+			break;
+		default:
+			ret = connector_status_unknown;
+			break;
+		}
+	}
+
+	return ret;
+}
+
 static int drm_bridge_connector_get_modes_edid(struct drm_connector *connector,
 					       struct drm_bridge *bridge)
 {
@@ -290,7 +292,7 @@ static int drm_bridge_connector_get_modes_edid(struct drm_connector *connector,
 	const struct drm_edid *drm_edid;
 	int n;
 
-	status = drm_bridge_connector_detect(connector, false);
+	status = drm_bridge_connector_detect_ctx(connector, NULL, false);
 	if (status != connector_status_connected)
 		goto no_edid;
 
@@ -376,6 +378,7 @@ static int drm_bridge_connector_atomic_check(struct drm_connector *connector,
 
 static const struct drm_connector_helper_funcs drm_bridge_connector_helper_funcs = {
 	.get_modes = drm_bridge_connector_get_modes,
+	.detect_ctx = drm_bridge_connector_detect_ctx,
 	.mode_valid = drm_bridge_connector_mode_valid,
 	.enable_hpd = drm_bridge_connector_enable_hpd,
 	.disable_hpd = drm_bridge_connector_disable_hpd,

-- 
2.51.2



From cristian.ciocaltea at collabora.com  Wed Dec  3 10:27:52 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Wed, 03 Dec 2025 20:27:52 +0200
Subject: [PATCH 1/4] drm/bridge: Add ->detect_ctx hook and
 drm_bridge_detect_ctx()
In-Reply-To: <20251203-dw-hdmi-qp-scramb-v1-0-836fe7401a69@collabora.com>
References: <20251203-dw-hdmi-qp-scramb-v1-0-836fe7401a69@collabora.com>
Message-ID: <20251203-dw-hdmi-qp-scramb-v1-1-836fe7401a69@collabora.com>

Add an atomic variant of the ->detect callback and a new helper to call
the hook while passing an optional drm_modeset_acquire_ctx reference.

When both ->detect_ctx and ->detect are defined, the latter is ignored.
If acquire_ctx is unset, the function takes care of the locking,
while also handling EDEADLK.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/drm_bridge.c | 58 ++++++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_bridge.h     | 30 +++++++++++++++++++++++
 2 files changed, 88 insertions(+)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 8f355df883d8..1fe03bcf2fc1 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -1280,6 +1280,64 @@ drm_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connector)
 }
 EXPORT_SYMBOL_GPL(drm_bridge_detect);
 
+/**
+ * drm_bridge_detect_ctx - check if anything is attached to the bridge output
+ * @bridge: bridge control structure
+ * @connector: attached connector
+ * @ctx: acquire_ctx, or NULL to let this function handle locking
+ *
+ * If the bridge supports output detection, as reported by the
+ * DRM_BRIDGE_OP_DETECT bridge ops flag, call &drm_bridge_funcs.detect_ctx
+ * or &drm_bridge_funcs.detect for the bridge and return the connection status.
+ * Otherwise return connector_status_unknown.
+ *
+ * When both @ctx and &drm_bridge_funcs.detect_ctx are not set, this helper
+ * function is equivalent to drm_bridge_detect() above.
+ *
+ * RETURNS:
+ * The detection status on success, or connector_status_unknown if the bridge
+ * doesn't support output detection.
+ * If @ctx is set, it might also return -EDEADLK.
+ */
+int drm_bridge_detect_ctx(struct drm_bridge *bridge,
+			  struct drm_connector *connector,
+			  struct drm_modeset_acquire_ctx *ctx)
+{
+	if (!(bridge->ops & DRM_BRIDGE_OP_DETECT))
+		return connector_status_unknown;
+
+	if (bridge->funcs->detect_ctx) {
+		struct drm_modeset_acquire_ctx br_ctx;
+		int ret;
+
+		if (ctx)
+			return bridge->funcs->detect_ctx(bridge, connector, ctx);
+
+		drm_modeset_acquire_init(&br_ctx, 0);
+retry:
+		ret = drm_modeset_lock(&connector->dev->mode_config.connection_mutex,
+				       &br_ctx);
+		if (!ret)
+			ret = bridge->funcs->detect_ctx(bridge, connector, &br_ctx);
+
+		if (ret == -EDEADLK) {
+			drm_modeset_backoff(&br_ctx);
+			goto retry;
+		}
+
+		if (ret < 0)
+			ret = connector_status_unknown;
+
+		drm_modeset_drop_locks(&br_ctx);
+		drm_modeset_acquire_fini(&br_ctx);
+
+		return ret;
+	}
+
+	return bridge->funcs->detect(bridge, connector);
+}
+EXPORT_SYMBOL_GPL(drm_bridge_detect_ctx);
+
 /**
  * drm_bridge_get_modes - fill all modes currently valid for the sink into the
  * @connector
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 0ff7ab4aa868..e11a1b39ef33 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -664,6 +664,33 @@ struct drm_bridge_funcs {
 	enum drm_connector_status (*detect)(struct drm_bridge *bridge,
 					    struct drm_connector *connector);
 
+	/**
+	 * @detect_ctx:
+	 *
+	 * Check if anything is attached to the bridge output.
+	 *
+	 * This callback is optional, if not implemented the bridge will be
+	 * considered as always having a component attached to its output.
+	 * Bridges that implement this callback shall set the
+	 * DRM_BRIDGE_OP_DETECT flag in their &drm_bridge->ops.
+	 *
+	 * This is the atomic version of &drm_bridge_funcs.detect.
+	 *
+	 * To avoid races against concurrent connector state updates, the
+	 * helper libraries always call this with ctx set to a valid context,
+	 * and &drm_mode_config.connection_mutex will always be locked with
+	 * the ctx parameter set to this ctx. This allows taking additional
+	 * locks as required.
+	 *
+	 * RETURNS:
+	 *
+	 * &drm_connector_status indicating the bridge output status,
+	 * or the error code returned by drm_modeset_lock(), -EDEADLK.
+	 */
+	int (*detect_ctx)(struct drm_bridge *bridge,
+			  struct drm_connector *connector,
+			  struct drm_modeset_acquire_ctx *ctx);
+
 	/**
 	 * @get_modes:
 	 *
@@ -1527,6 +1554,9 @@ drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge,
 
 enum drm_connector_status
 drm_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connector);
+int drm_bridge_detect_ctx(struct drm_bridge *bridge,
+			  struct drm_connector *connector,
+			  struct drm_modeset_acquire_ctx *ctx);
 int drm_bridge_get_modes(struct drm_bridge *bridge,
 			 struct drm_connector *connector);
 const struct drm_edid *drm_bridge_edid_read(struct drm_bridge *bridge,

-- 
2.51.2



From cristian.ciocaltea at collabora.com  Wed Dec  3 10:27:55 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Wed, 03 Dec 2025 20:27:55 +0200
Subject: [PATCH 4/4] drm/rockchip: dw_hdmi_qp: Do not send HPD events for
 all connectors
In-Reply-To: <20251203-dw-hdmi-qp-scramb-v1-0-836fe7401a69@collabora.com>
References: <20251203-dw-hdmi-qp-scramb-v1-0-836fe7401a69@collabora.com>
Message-ID: <20251203-dw-hdmi-qp-scramb-v1-4-836fe7401a69@collabora.com>

In order to optimize the HPD event handling and run the detect cycle on
the affected connector only, make use of
drm_connector_helper_hpd_irq_event() instead of
drm_helper_hpd_irq_event().

Additionally, move devm_request_threaded_irq() after bridge connector
initialization.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 44 ++++++++++++--------------
 1 file changed, 20 insertions(+), 24 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index c9fe6aa3e3e3..a05f711f036a 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -92,6 +92,7 @@ struct rockchip_hdmi_qp {
 	struct regmap *regmap;
 	struct regmap *vo_regmap;
 	struct rockchip_encoder encoder;
+	struct drm_connector *connector;
 	struct dw_hdmi_qp *hdmi;
 	struct phy *phy;
 	struct gpio_desc *frl_enable_gpio;
@@ -251,14 +252,10 @@ static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work)
 	struct rockchip_hdmi_qp *hdmi = container_of(work,
 						     struct rockchip_hdmi_qp,
 						     hpd_work.work);
-	struct drm_device *drm = hdmi->encoder.encoder.dev;
-	bool changed;
+	bool changed = drm_connector_helper_hpd_irq_event(hdmi->connector);
 
-	if (drm) {
-		changed = drm_helper_hpd_irq_event(drm);
-		if (changed)
-			dev_dbg(hdmi->dev, "connector status changed\n");
-	}
+	if (changed)
+		dev_dbg(hdmi->dev, "connector status changed\n");
 }
 
 static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
@@ -475,13 +472,12 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
 	struct dw_hdmi_qp_plat_data plat_data = {};
 	const struct rockchip_hdmi_qp_cfg *cfg;
 	struct drm_device *drm = data;
-	struct drm_connector *connector;
 	struct drm_encoder *encoder;
 	struct rockchip_hdmi_qp *hdmi;
 	struct resource *res;
 	struct clk_bulk_data *clks;
 	struct clk *ref_clk;
-	int ret, irq, i;
+	int ret, hpd_irq, i;
 
 	if (!pdev->dev.of_node)
 		return -ENODEV;
@@ -582,17 +578,9 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
 	if (plat_data.cec_irq < 0)
 		return plat_data.cec_irq;
 
-	irq = platform_get_irq_byname(pdev, "hpd");
-	if (irq < 0)
-		return irq;
-
-	ret = devm_request_threaded_irq(hdmi->dev, irq,
-					cfg->ctrl_ops->hardirq_callback,
-					cfg->ctrl_ops->irq_callback,
-					IRQF_SHARED, "dw-hdmi-qp-hpd",
-					hdmi);
-	if (ret)
-		return ret;
+	hpd_irq = platform_get_irq_byname(pdev, "hpd");
+	if (hpd_irq < 0)
+		return hpd_irq;
 
 	drm_encoder_helper_add(encoder, &dw_hdmi_qp_rockchip_encoder_helper_funcs);
 	drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
@@ -606,12 +594,20 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
 				     "Failed to bind dw-hdmi-qp");
 	}
 
-	connector = drm_bridge_connector_init(drm, encoder);
-	if (IS_ERR(connector))
-		return dev_err_probe(hdmi->dev, PTR_ERR(connector),
+	hdmi->connector = drm_bridge_connector_init(drm, encoder);
+	if (IS_ERR(hdmi->connector))
+		return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->connector),
 				     "Failed to init bridge connector\n");
 
-	return drm_connector_attach_encoder(connector, encoder);
+	ret = drm_connector_attach_encoder(hdmi->connector, encoder);
+	if (ret)
+		return ret;
+
+	return devm_request_threaded_irq(hdmi->dev, hpd_irq,
+					 cfg->ctrl_ops->hardirq_callback,
+					 cfg->ctrl_ops->irq_callback,
+					 IRQF_SHARED, "dw-hdmi-qp-hpd",
+					 hdmi);
 }
 
 static void dw_hdmi_qp_rockchip_unbind(struct device *dev,

-- 
2.51.2



From cristian.ciocaltea at collabora.com  Wed Dec  3 10:27:54 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Wed, 03 Dec 2025 20:27:54 +0200
Subject: [PATCH 3/4] drm/bridge: dw-hdmi-qp: Add high TMDS clock ratio and
 scrambling support
In-Reply-To: <20251203-dw-hdmi-qp-scramb-v1-0-836fe7401a69@collabora.com>
References: <20251203-dw-hdmi-qp-scramb-v1-0-836fe7401a69@collabora.com>
Message-ID: <20251203-dw-hdmi-qp-scramb-v1-3-836fe7401a69@collabora.com>

Add support for HDMI 2.0 display modes, e.g. 4K at 60Hz, by permitting TMDS
character rates above the 340 MHz limit of HDMI 1.4b.

Hence, provide the required SCDC management, including the high TMDS
clock ratio and scrambling setup, and filter out the HDMI 2.1 modes.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 174 +++++++++++++++++++++++++--
 1 file changed, 162 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index fe4c026280f0..f732bd238ff8 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -2,6 +2,7 @@
 /*
  * Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd.
  * Copyright (c) 2024 Collabora Ltd.
+ * Copyright (c) 2025 Amazon.com, Inc. or its affiliates.
  *
  * Author: Algea Cao <algea.cao at rock-chips.com>
  * Author: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
@@ -20,6 +21,7 @@
 #include <drm/display/drm_hdmi_helper.h>
 #include <drm/display/drm_hdmi_cec_helper.h>
 #include <drm/display/drm_hdmi_state_helper.h>
+#include <drm/display/drm_scdc_helper.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_bridge.h>
@@ -37,8 +39,10 @@
 #define DDC_SEGMENT_ADDR	0x30
 
 #define HDMI14_MAX_TMDSCLK	340000000
+#define HDMI20_MAX_TMDSRATE	600000000
 
-#define SCRAMB_POLL_DELAY_MS	3000
+#define SCDC_MIN_SOURCE_VERSION	0x1
+#define SCRAMB_POLL_DELAY_MS	5000
 
 /*
  * Unless otherwise noted, entries in this table are 100% optimization.
@@ -162,6 +166,11 @@ struct dw_hdmi_qp {
 	} phy;
 
 	unsigned long ref_clk_rate;
+
+	struct drm_connector *curr_conn;
+	struct delayed_work scramb_work;
+	bool scramb_enabled;
+
 	struct regmap *regm;
 
 	unsigned long tmds_char_rate;
@@ -851,28 +860,98 @@ static int dw_hdmi_qp_config_audio_infoframe(struct dw_hdmi_qp *hdmi,
 	return 0;
 }
 
+static bool dw_hdmi_qp_supports_scrambling(struct drm_display_info *display)
+{
+	if (!display->is_hdmi)
+		return false;
+
+	return display->hdmi.scdc.supported &&
+		display->hdmi.scdc.scrambling.supported;
+}
+
+static void dw_hdmi_qp_set_scramb(struct dw_hdmi_qp *hdmi)
+{
+	dev_dbg(hdmi->dev, "set scrambling\n");
+
+	drm_scdc_set_high_tmds_clock_ratio(hdmi->curr_conn, true);
+	drm_scdc_set_scrambling(hdmi->curr_conn, true);
+
+	schedule_delayed_work(&hdmi->scramb_work,
+			      msecs_to_jiffies(SCRAMB_POLL_DELAY_MS));
+}
+
+static void dw_hdmi_qp_scramb_work(struct work_struct *work)
+{
+	struct dw_hdmi_qp *hdmi = container_of(to_delayed_work(work),
+					       struct dw_hdmi_qp,
+					       scramb_work);
+	if (!drm_scdc_get_scrambling_status(hdmi->curr_conn))
+		dw_hdmi_qp_set_scramb(hdmi);
+}
+
+static void dw_hdmi_qp_enable_scramb(struct dw_hdmi_qp *hdmi)
+{
+	u8 ver;
+
+	if (!dw_hdmi_qp_supports_scrambling(&hdmi->curr_conn->display_info))
+		return;
+
+	drm_scdc_readb(hdmi->bridge.ddc, SCDC_SINK_VERSION, &ver);
+	drm_scdc_writeb(hdmi->bridge.ddc, SCDC_SOURCE_VERSION,
+			min_t(u8, ver, SCDC_MIN_SOURCE_VERSION));
+
+	dw_hdmi_qp_set_scramb(hdmi);
+	dw_hdmi_qp_write(hdmi, 1, SCRAMB_CONFIG0);
+
+	hdmi->scramb_enabled = true;
+
+	/* Wait at least 1 ms before resuming TMDS transmission */
+	usleep_range(1000, 5000);
+}
+
+static void dw_hdmi_qp_disable_scramb(struct dw_hdmi_qp *hdmi)
+{
+	if (!hdmi->scramb_enabled)
+		return;
+
+	dev_dbg(hdmi->dev, "disable scrambling\n");
+
+	hdmi->scramb_enabled = false;
+	cancel_delayed_work_sync(&hdmi->scramb_work);
+
+	dw_hdmi_qp_write(hdmi, 0, SCRAMB_CONFIG0);
+
+	if (hdmi->curr_conn->status == connector_status_connected) {
+		drm_scdc_set_scrambling(hdmi->curr_conn, false);
+		drm_scdc_set_high_tmds_clock_ratio(hdmi->curr_conn, false);
+	}
+}
+
 static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge,
 					    struct drm_atomic_state *state)
 {
 	struct dw_hdmi_qp *hdmi = bridge->driver_private;
 	struct drm_connector_state *conn_state;
-	struct drm_connector *connector;
 	unsigned int op_mode;
 
-	connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
-	if (WARN_ON(!connector))
+	hdmi->curr_conn = drm_atomic_get_new_connector_for_encoder(state,
+								   bridge->encoder);
+	if (WARN_ON(!hdmi->curr_conn))
 		return;
 
-	conn_state = drm_atomic_get_new_connector_state(state, connector);
+	conn_state = drm_atomic_get_new_connector_state(state, hdmi->curr_conn);
 	if (WARN_ON(!conn_state))
 		return;
 
-	if (connector->display_info.is_hdmi) {
+	if (hdmi->curr_conn->display_info.is_hdmi) {
 		dev_dbg(hdmi->dev, "%s mode=HDMI %s rate=%llu bpc=%u\n", __func__,
 			drm_hdmi_connector_get_output_format_name(conn_state->hdmi.output_format),
 			conn_state->hdmi.tmds_char_rate, conn_state->hdmi.output_bpc);
 		op_mode = 0;
 		hdmi->tmds_char_rate = conn_state->hdmi.tmds_char_rate;
+
+		if (conn_state->hdmi.tmds_char_rate > HDMI14_MAX_TMDSCLK)
+			dw_hdmi_qp_enable_scramb(hdmi);
 	} else {
 		dev_dbg(hdmi->dev, "%s mode=DVI\n", __func__);
 		op_mode = OPMODE_DVI;
@@ -883,7 +962,7 @@ static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge,
 	dw_hdmi_qp_mod(hdmi, HDCP2_BYPASS, HDCP2_BYPASS, HDCP2LOGIC_CONFIG0);
 	dw_hdmi_qp_mod(hdmi, op_mode, OPMODE_DVI, LINK_CONFIG0);
 
-	drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
+	drm_atomic_helper_connector_hdmi_update_infoframes(hdmi->curr_conn, state);
 }
 
 static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,
@@ -893,15 +972,84 @@ static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,
 
 	hdmi->tmds_char_rate = 0;
 
+	dw_hdmi_qp_disable_scramb(hdmi);
+
+	hdmi->curr_conn = NULL;
 	hdmi->phy.ops->disable(hdmi, hdmi->phy.data);
 }
 
-static enum drm_connector_status
-dw_hdmi_qp_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connector)
+static int dw_hdmi_qp_reset_link(struct dw_hdmi_qp *hdmi,
+				 struct drm_connector *conn,
+				 struct drm_modeset_acquire_ctx *ctx)
+{
+	struct drm_crtc *crtc;
+	u8 config;
+	int ret;
+
+	if (!conn->state)
+		return 0;
+
+	crtc = conn->state->crtc;
+	if (!crtc)
+		return 0;
+
+retry:
+	ret = drm_modeset_lock(&crtc->mutex, ctx);
+	if (ret)
+		goto check_err;
+
+	if (!crtc->state->active)
+		return 0;
+
+	if (conn->state->commit &&
+	    !try_wait_for_completion(&conn->state->commit->hw_done))
+		return 0;
+
+	ret = drm_scdc_readb(hdmi->bridge.ddc, SCDC_TMDS_CONFIG, &config);
+	if (ret < 0) {
+		dev_err(hdmi->dev, "Failed to read TMDS config: %d\n", ret);
+		return 0;
+	}
+
+	if (!!(config & SCDC_SCRAMBLING_ENABLE) == hdmi->scramb_enabled)
+		return 0;
+
+	dev_dbg(hdmi->dev, "%s resetting crtc\n", __func__);
+
+	drm_atomic_helper_connector_hdmi_hotplug(conn, connector_status_connected);
+
+	/*
+	 * Conform to HDMI 2.0 spec by ensuring scrambled data is not sent
+	 * before configuring the sink scrambling, as well as suspending any
+	 * TMDS transmission while changing the TMDS clock rate in the sink.
+	 */
+	ret = drm_atomic_helper_reset_crtc(crtc, ctx);
+
+check_err:
+	if (ret == -EDEADLK) {
+		drm_modeset_backoff(ctx);
+		goto retry;
+	}
+
+	return ret;
+}
+
+static int dw_hdmi_qp_bridge_detect(struct drm_bridge *bridge,
+				    struct drm_connector *connector,
+				    struct drm_modeset_acquire_ctx *ctx)
 {
 	struct dw_hdmi_qp *hdmi = bridge->driver_private;
+	enum drm_connector_status status;
 
-	return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data);
+	status = hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data);
+
+	dev_dbg(hdmi->dev, "%s status=%d scramb=%d\n", __func__,
+		status, hdmi->scramb_enabled);
+
+	if (status == connector_status_connected && hdmi->scramb_enabled)
+		dw_hdmi_qp_reset_link(hdmi, connector, ctx);
+
+	return status;
 }
 
 static const struct drm_edid *
@@ -925,7 +1073,7 @@ dw_hdmi_qp_bridge_tmds_char_rate_valid(const struct drm_bridge *bridge,
 {
 	struct dw_hdmi_qp *hdmi = bridge->driver_private;
 
-	if (rate > HDMI14_MAX_TMDSCLK) {
+	if (rate > HDMI20_MAX_TMDSRATE) {
 		dev_dbg(hdmi->dev, "Unsupported TMDS char rate: %lld\n", rate);
 		return MODE_CLOCK_HIGH;
 	}
@@ -1165,7 +1313,7 @@ static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {
 	.atomic_reset = drm_atomic_helper_bridge_reset,
 	.atomic_enable = dw_hdmi_qp_bridge_atomic_enable,
 	.atomic_disable = dw_hdmi_qp_bridge_atomic_disable,
-	.detect = dw_hdmi_qp_bridge_detect,
+	.detect_ctx = dw_hdmi_qp_bridge_detect,
 	.edid_read = dw_hdmi_qp_bridge_edid_read,
 	.hdmi_tmds_char_rate_valid = dw_hdmi_qp_bridge_tmds_char_rate_valid,
 	.hdmi_clear_infoframe = dw_hdmi_qp_bridge_clear_infoframe,
@@ -1247,6 +1395,8 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
 	if (IS_ERR(hdmi))
 		return ERR_CAST(hdmi);
 
+	INIT_DELAYED_WORK(&hdmi->scramb_work, dw_hdmi_qp_scramb_work);
+
 	hdmi->dev = dev;
 
 	regs = devm_platform_ioremap_resource(pdev, 0);

-- 
2.51.2



From leo.yan at arm.com  Wed Dec  3 10:29:44 2025
From: leo.yan at arm.com (Leo Yan)
Date: Wed, 3 Dec 2025 18:29:44 +0000
Subject: [PATCH v6 2/2] coresight: cti: Add Qualcomm extended CTI support
In-Reply-To: <20251202-extended_cti-v6-2-ab68bb15c4f5@oss.qualcomm.com>
References: <20251202-extended_cti-v6-0-ab68bb15c4f5@oss.qualcomm.com>
 <20251202-extended_cti-v6-2-ab68bb15c4f5@oss.qualcomm.com>
Message-ID: <20251203182944.GG724103@e132581.arm.com>

On Tue, Dec 02, 2025 at 02:42:21PM +0800, Yingchao Deng wrote:
> The QCOM extended CTI is a heavily parameterized version of ARM?s CSCTI.
> It allows a debugger to send to trigger events to a processor or to send
> a trigger event to one or more processors when a trigger event occurs
> on another processor on the same SoC, or even between SoCs. Qualcomm CTI
> implementation differs from the standard CTI in the following aspects:
> 
> 1. The number of supported triggers is extended to 128.
> 2. Several register offsets differ from the CoreSight specification.

I apologize for my late review of this series.  For easier maintenance
later, I have several comments for register access.

[...]

> +static const u32 cti_normal_offset[] = {
> +	[INDEX_CTIINTACK]		= CTIINTACK,
> +	[INDEX_CTIAPPSET]		= CTIAPPSET,
> +	[INDEX_CTIAPPCLEAR]		= CTIAPPCLEAR,
> +	[INDEX_CTIAPPPULSE]		= CTIAPPPULSE,
> +	[INDEX_CTIINEN]			= CTIINEN(0),
> +	[INDEX_CTIOUTEN]		= CTIOUTEN(0),

I prefer to update the these two macros to CTIINENn and CTIOUTENn, as
later we will not use CTIINEN(n) and CTIOUTEN(n) anymore.

> +	[INDEX_CTITRIGINSTATUS]		= CTITRIGINSTATUS,
> +	[INDEX_CTITRIGOUTSTATUS]	= CTITRIGOUTSTATUS,
> +	[INDEX_CTICHINSTATUS]		= CTICHINSTATUS,
> +	[INDEX_CTICHOUTSTATUS]		= CTICHOUTSTATUS,
> +	[INDEX_CTIGATE]			= CTIGATE,
> +	[INDEX_ASICCTL]			= ASICCTL,
> +	[INDEX_ITCHINACK]		= ITCHINACK,
> +	[INDEX_ITTRIGINACK]		= ITTRIGINACK,
> +	[INDEX_ITCHOUT]			= ITCHOUT,
> +	[INDEX_ITTRIGOUT]		= ITTRIGOUT,
> +	[INDEX_ITCHOUTACK]		= ITCHOUTACK,
> +	[INDEX_ITTRIGOUTACK]		= ITTRIGOUTACK,
> +	[INDEX_ITCHIN]			= ITCHIN,
> +	[INDEX_ITTRIGIN]		= ITTRIGIN,
> +	[INDEX_ITCTRL]			= CORESIGHT_ITCTRL,
> +};
> +
> +static const u32 cti_extended_offset[] = {
> +	[INDEX_CTIINTACK]		= QCOM_CTIINTACK,
> +	[INDEX_CTIAPPSET]		= QCOM_CTIAPPSET,
> +	[INDEX_CTIAPPCLEAR]		= QCOM_CTIAPPCLEAR,
> +	[INDEX_CTIAPPPULSE]		= QCOM_CTIAPPPULSE,
> +	[INDEX_CTIINEN]			= QCOM_CTIINEN,
> +	[INDEX_CTIOUTEN]		= QCOM_CTIOUTEN,
> +	[INDEX_CTITRIGINSTATUS]		= QCOM_CTITRIGINSTATUS,
> +	[INDEX_CTITRIGOUTSTATUS]	= QCOM_CTITRIGOUTSTATUS,
> +	[INDEX_CTICHINSTATUS]		= QCOM_CTICHINSTATUS,
> +	[INDEX_CTICHOUTSTATUS]		= QCOM_CTICHOUTSTATUS,
> +	[INDEX_CTIGATE]			= QCOM_CTIGATE,
> +	[INDEX_ASICCTL]			= QCOM_ASICCTL,
> +	[INDEX_ITCHINACK]		= QCOM_ITCHINACK,
> +	[INDEX_ITTRIGINACK]		= QCOM_ITTRIGINACK,
> +	[INDEX_ITCHOUT]			= QCOM_ITCHOUT,
> +	[INDEX_ITTRIGOUT]		= QCOM_ITTRIGOUT,
> +	[INDEX_ITCHOUTACK]		= QCOM_ITCHOUTACK,
> +	[INDEX_ITTRIGOUTACK]		= QCOM_ITTRIGOUTACK,
> +	[INDEX_ITCHIN]			= QCOM_ITCHIN,
> +	[INDEX_ITTRIGIN]		= QCOM_ITTRIGIN,
> +	[INDEX_ITCTRL]			= CORESIGHT_ITCTRL,
> +};

I saw CTI registers are within 4KiB (0x1000), we can don't convert
standard regiserts and only convert to QCOM register based on the
standard ones.  So you can drop the cti_normal_offset strucuture and
only have a cti_reg_qcom_offset[] struct:

  static const u32 cti_extended_offset[] = {
  	[CTIINTACK]		= QCOM_CTIINTACK,
  	[CTIAPPSET]		= QCOM_CTIAPPSET,
  	[CTIAPPCLEAR]		= QCOM_CTIAPPCLEAR,
  	[CTIAPPPULSE]		= QCOM_CTIAPPPULSE,
  	[CTIINEN]		= QCOM_CTIINEN,
        ...
  };

Then you could create two helpers for register address:

    static void __iomem *cti_reg_addr_with_nr(struct cti_drvdata *drvdata,
                                              u32 reg, u32 nr)
    {
        /* convert to qcom specific offset */
        if (unlikely(drvdata->is_qcom_cti))
            reg = cti_extended_offset[reg];

        return drvdata->base + reg + sizeof(u32) * nr;
    }

    static void __iomem *cti_reg_addr(struct cti_drvdata *drvdata, u32 reg)
    {
        return cti_reg_addr_with_nr(drvdata, reg, 0);
    }

>  /*
>   * CTI devices can be associated with a PE, or be connected to CoreSight
> @@ -70,15 +119,16 @@ void cti_write_all_hw_regs(struct cti_drvdata *drvdata)
>  
>  	/* write the CTI trigger registers */
>  	for (i = 0; i < config->nr_trig_max; i++) {
> -		writel_relaxed(config->ctiinen[i], drvdata->base + CTIINEN(i));
> +		writel_relaxed(config->ctiinen[i],
> +			       drvdata->base + cti_offset(drvdata, INDEX_CTIINEN, i));

writel_relaxed(config->ctiinen[i],
               cti_reg_addr_with_nr(drvdata, CTIINENn, i));

And apply for the same cases below.

>  	/* other regs */
> -	writel_relaxed(config->ctigate, drvdata->base + CTIGATE);
> -	writel_relaxed(config->asicctl, drvdata->base + ASICCTL);
> -	writel_relaxed(config->ctiappset, drvdata->base + CTIAPPSET);
> +	writel_relaxed(config->ctigate, drvdata->base + cti_offset(drvdata, INDEX_CTIGATE, 0));

writel_relaxed(config->ctigate, cti_reg_addr(drvdata, CTIGATE));

And apply for the same cases below.

[...]

> @@ -394,8 +447,8 @@ int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,
>  
>  	/* update the local register values */
>  	chan_bitmask = BIT(channel_idx);
> -	reg_offset = (direction == CTI_TRIG_IN ? CTIINEN(trigger_idx) :
> -		      CTIOUTEN(trigger_idx));
> +	reg_offset = (direction == CTI_TRIG_IN ? cti_offset(drvdata, INDEX_CTIINEN, trigger_idx) :
> +			cti_offset(drvdata, INDEX_CTIOUTEN, trigger_idx));

For readable, we can improve a bit with code alignment:

  reg_offset = (direction == CTI_TRIG_IN) ? cti_reg_addr_with_nr(drvdata, CTIINENn, trigger_idx) :
                                            cti_reg_addr_with_nr(drvdata, CTIOUTENn, trigger_idx);

[...]

> @@ -981,9 +1035,28 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id)
>  	drvdata->csdev_release = drvdata->csdev->dev.release;
>  	drvdata->csdev->dev.release = cti_device_release;
>  
> +	/* check architect value*/
> +	devarch = readl_relaxed(drvdata->base + CORESIGHT_DEVARCH);
> +	if (CTI_DEVARCH_ARCHITECT(devarch) == ARCHITECT_QCOM) {
> +		drvdata->subtype = QCOM_CTI;
> +		drvdata->offsets = cti_extended_offset;

As a result, we can only set the is_qcom_cti flag:

  drvdata->is_qcom_cti = true;

> +		/*
> +		 * QCOM CTI does not implement Claimtag functionality as
> +		 * per CoreSight specification, but its CLAIMSET register
> +		 * is incorrectly initialized to 0xF. This can mislead
> +		 * tools or drivers into thinking the component is claimed.
> +		 *
> +		 * Reset CLAIMSET to 0 to reflect that no claims are active.
> +		 */
> +		writel_relaxed(0, drvdata->base + CORESIGHT_CLAIMSET);

I am confused for this.  If QCOM CTI does not implement claim tag,
then what is the designed register at the offset CORESIGHT_CLAIMSET?

Should you bypass all claim tag related operations for QCOM CTI case?
(I don't see you touch anything for claim and declaim tags).

> +	} else {
> +		drvdata->subtype = ARM_STD_CTI;
> +		drvdata->offsets = cti_normal_offset;
> +	}
> +
>  	/* all done - dec pm refcount */
>  	pm_runtime_put(&adev->dev);
> -	dev_info(&drvdata->csdev->dev, "CTI initialized\n");
> +	dev_info(&drvdata->csdev->dev, "CTI initialized; subtype=%d\n", drvdata->subtype);

dev_info(&drvdata->csdev->dev, "%s CTI initialized\n",
         drvdata->is_qcom_cti ? "QCOM" : "");

>  	return 0;
>  
>  pm_release:
> diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
> index a9df77215141..12a495382999 100644
> --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c
> +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
> @@ -172,9 +172,8 @@ static struct attribute *coresight_cti_attrs[] = {
>  
>  /* register based attributes */
>  
> -/* Read registers with power check only (no enable check). */
> -static ssize_t coresight_cti_reg_show(struct device *dev,
> -			   struct device_attribute *attr, char *buf)
> +static ssize_t coresight_cti_mgmt_reg_show(struct device *dev,
> +					   struct device_attribute *attr, char *buf)
>  {
>  	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
>  	struct cs_off_attribute *cti_attr = container_of(attr, struct cs_off_attribute, attr);
> @@ -189,6 +188,40 @@ static ssize_t coresight_cti_reg_show(struct device *dev,
>  	return sysfs_emit(buf, "0x%x\n", val);
>  }
>  
> +/* Read registers with power check only (no enable check). */
> +static ssize_t coresight_cti_reg_show(struct device *dev,
> +				      struct device_attribute *attr, char *buf)
> +{
> +	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	struct cs_off_attribute *cti_attr = container_of(attr, struct cs_off_attribute, attr);
> +	u32 idx, val = 0;
> +
> +	pm_runtime_get_sync(dev->parent);
> +	raw_spin_lock(&drvdata->spinlock);
> +	idx = drvdata->config.ext_reg_sel;
> +	if (drvdata->config.hw_powered) {
> +		switch (cti_attr->off) {
> +		case INDEX_CTITRIGINSTATUS:
> +		case INDEX_CTITRIGOUTSTATUS:
> +		case INDEX_ITTRIGINACK:
> +		case INDEX_ITTRIGOUT:
> +		case INDEX_ITTRIGOUTACK:
> +		case INDEX_ITTRIGIN:
> +			val = readl_relaxed(drvdata->base +
> +					    cti_offset(drvdata, cti_attr->off, idx));
> +			break;
> +
> +		default:
> +			val = readl_relaxed(drvdata->base + cti_offset(drvdata, cti_attr->off, 0));
> +			break;
> +		}
> +	}
> +
> +	raw_spin_unlock(&drvdata->spinlock);
> +	pm_runtime_put_sync(dev->parent);
> +	return sysfs_emit(buf, "0x%x\n", val);
> +}
> +
>  /* Write registers with power check only (no enable check). */
>  static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,
>  						      struct device_attribute *attr,
> @@ -197,19 +230,39 @@ static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,
>  	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
>  	struct cs_off_attribute *cti_attr = container_of(attr, struct cs_off_attribute, attr);
>  	unsigned long val = 0;
> +	u32 idx;
>  
>  	if (kstrtoul(buf, 0, &val))
>  		return -EINVAL;
>  
>  	pm_runtime_get_sync(dev->parent);
>  	raw_spin_lock(&drvdata->spinlock);
> -	if (drvdata->config.hw_powered)
> -		cti_write_single_reg(drvdata, cti_attr->off, val);
> +	idx = drvdata->config.ext_reg_sel;
> +	if (drvdata->config.hw_powered) {
> +		switch (cti_attr->off) {
> +		case INDEX_ITTRIGINACK:
> +		case INDEX_ITTRIGOUT:
> +			cti_write_single_reg(drvdata, cti_offset(drvdata, cti_attr->off, idx), val);
> +			break;
> +
> +		default:
> +			cti_write_single_reg(drvdata, cti_offset(drvdata, cti_attr->off, 0), val);
> +			break;
> +		}
> +	}

For both coresight_cti_reg_show() and coresight_cti_reg_store(), can
we always use "cti_attr->off" as the offset for regitser access?  I
mean we don't need the extra config.ext_reg_sel, eventually any
register we can calculate a offset for it.

>  	raw_spin_unlock(&drvdata->spinlock);
>  	pm_runtime_put_sync(dev->parent);
>  	return size;
>  }
>  
> +#define coresight_cti_mgmt_reg(name, offset)	                        \
> +	(&((struct cs_off_attribute[]) {                                \
> +	   {                                                            \
> +		__ATTR(name, 0444, coresight_cti_mgmt_reg_show, NULL),  \
> +		offset							\
> +	   }								\
> +	})[0].attr.attr)
> +
>  #define coresight_cti_reg(name, offset)					\
>  	(&((struct cs_off_attribute[]) {				\
>  	   {								\
> @@ -237,17 +290,17 @@ static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,
>  
>  /* coresight management registers */
>  static struct attribute *coresight_cti_mgmt_attrs[] = {
> -	coresight_cti_reg(devaff0, CTIDEVAFF0),
> -	coresight_cti_reg(devaff1, CTIDEVAFF1),
> -	coresight_cti_reg(authstatus, CORESIGHT_AUTHSTATUS),
> -	coresight_cti_reg(devarch, CORESIGHT_DEVARCH),
> -	coresight_cti_reg(devid, CORESIGHT_DEVID),
> -	coresight_cti_reg(devtype, CORESIGHT_DEVTYPE),
> -	coresight_cti_reg(pidr0, CORESIGHT_PERIPHIDR0),
> -	coresight_cti_reg(pidr1, CORESIGHT_PERIPHIDR1),
> -	coresight_cti_reg(pidr2, CORESIGHT_PERIPHIDR2),
> -	coresight_cti_reg(pidr3, CORESIGHT_PERIPHIDR3),
> -	coresight_cti_reg(pidr4, CORESIGHT_PERIPHIDR4),
> +	coresight_cti_mgmt_reg(devaff0, CTIDEVAFF0),
> +	coresight_cti_mgmt_reg(devaff1, CTIDEVAFF1),
> +	coresight_cti_mgmt_reg(authstatus, CORESIGHT_AUTHSTATUS),
> +	coresight_cti_mgmt_reg(devarch, CORESIGHT_DEVARCH),
> +	coresight_cti_mgmt_reg(devid, CORESIGHT_DEVID),
> +	coresight_cti_mgmt_reg(devtype, CORESIGHT_DEVTYPE),
> +	coresight_cti_mgmt_reg(pidr0, CORESIGHT_PERIPHIDR0),
> +	coresight_cti_mgmt_reg(pidr1, CORESIGHT_PERIPHIDR1),
> +	coresight_cti_mgmt_reg(pidr2, CORESIGHT_PERIPHIDR2),
> +	coresight_cti_mgmt_reg(pidr3, CORESIGHT_PERIPHIDR3),
> +	coresight_cti_mgmt_reg(pidr4, CORESIGHT_PERIPHIDR4),

I don't see any benefit for updating from coresight_cti_reg() to
coresight_cti_mgmt_reg().  If really want to do this, should remove
the macro coresight_cti_reg()?

>  	NULL,
>  };
>  
> @@ -258,13 +311,15 @@ static struct attribute *coresight_cti_mgmt_attrs[] = {
>   * If inaccessible & pcached_val not NULL then show cached value.
>   */
>  static ssize_t cti_reg32_show(struct device *dev, char *buf,
> -			      u32 *pcached_val, int reg_offset)
> +			      u32 *pcached_val, int index)

We don't need to change anything for this.  The passed "reg_offset"
should be always a final offset, no matter for standard CTI or QCOM
case, the driver directly uses the offset for register access.

[...]

> +/*
> + * QCOM CTI supports up to 128 triggers, there are 6 registers need to be
> + * expanded to up to 4 instances, and ext_reg_sel can be used to indicate
> + * which one is in use.
> + * CTITRIGINSTATUS, CTITRIGOUTSTATUS,
> + * ITTRIGIN, ITTRIGOUT,
> + * ITTRIGINACK, ITTRIGOUTACK.
> + */
> +static ssize_t ext_reg_sel_show(struct device *dev,
> +				struct device_attribute *attr,
> +				char *buf)
> +{
> +	u32 val;
> +	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +
> +	raw_spin_lock(&drvdata->spinlock);
> +	val = drvdata->config.ext_reg_sel;
> +	raw_spin_unlock(&drvdata->spinlock);
> +	return sprintf(buf, "%d\n", val);
> +}
> +
> +static ssize_t ext_reg_sel_store(struct device *dev,
> +				 struct device_attribute *attr,
> +				 const char *buf, size_t size)
> +{
> +	unsigned long val;
> +	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +
> +	if (kstrtoul(buf, 0, &val))
> +		return -EINVAL;
> +	if (val > ((drvdata->config.nr_trig_max + 31) / 32 - 1))
> +		return -EINVAL;
> +
> +	raw_spin_lock(&drvdata->spinlock);
> +	drvdata->config.ext_reg_sel = val;
> +	raw_spin_unlock(&drvdata->spinlock);
> +	return size;
> +}

As said, I don't think the trigger register is any different from
other register access.  So the existed APIs would be sufficient.

As a result, we don't need to add two above functions.

Thanks,
Leo


From mathieu.poirier at linaro.org  Wed Dec  3 11:09:37 2025
From: mathieu.poirier at linaro.org (Mathieu Poirier)
Date: Wed, 3 Dec 2025 12:09:37 -0700
Subject: [PATCH v5 0/5] Enable Remote GPIO over RPMSG on i.MX Platform
In-Reply-To: <20251104203315.85706-1-shenwei.wang@nxp.com>
References: <20251104203315.85706-1-shenwei.wang@nxp.com>
Message-ID: <aTCK8e1SJA7Uh3wL@p14s>

On Tue, Nov 04, 2025 at 02:33:10PM -0600, Shenwei Wang wrote:
> Support the remote devices on the remote processor via the RPMSG bus on
> i.MX platform.
> 
> Changes in v5:
>  - move the gpio-rpmsg.rst from admin-guide to staging directory after
>    discussion with Randy Dunlap.
>  - add include files with some code improvements per Bartosz's comments.
> 
> Changes in v4:
>  - add a documentation to describe the transport protocol per Andrew's
>    comments.
>  - add a new handler to get the gpio direction.
> 
> Changes in v3:
>  - fix various format issue and return value check per Peng 's review
>    comments.
>  - add the logic to also populate the subnodes which are not in the
>    device map per Arnaud's request. (in imx_rproc.c)
>  - update the yaml per Frank's review comments.
> 
> Changes in v2:
>  - re-implemented the gpio driver per Linus Walleij's feedback by using
>    GPIOLIB_IRQCHIP helper library.
>  - fix various format issue per Mathieu/Peng 's review comments.
>  - update the yaml doc per Rob's feedback
> 
> Cc: Bartosz Golaszewski <brgl at bgdev.pl>
> Cc: Randy Dunlap <rdunlap at infradead.org>
> Cc: Andrew Lunn <andrew at lunn.ch>
> Cc: Mathieu Poirier <mathieu.poirier at linaro.org>
> Cc: Arnaud POULIQUEN <arnaud.pouliquen at foss.st.com>
> Cc: Linus Walleij <linus.walleij at linaro.org>
> Cc: linux-gpio at vger.kernel.org
> 
> Shenwei Wang (5):
>   dt-bindings: remoteproc: imx_rproc: Add "rpmsg" subnode support
>   remoteproc: imx_rproc: Populate devices under "rpmsg" subnode
>   docs: staging: gpio-rpmsg: gpio over rpmsg bus
>   gpio: imx-rpmsg: add imx-rpmsg GPIO driver
>   arm64: dts: imx8ulp: Add rpmsg node under imx_rproc
> 
>  .../bindings/remoteproc/fsl,imx-rproc.yaml    | 123 +++++
>  Documentation/staging/gpio-rpmsg.rst          | 202 ++++++++
>  Documentation/staging/index.rst               |   1 +
>  arch/arm64/boot/dts/freescale/imx8ulp.dtsi    |  27 +
>  drivers/gpio/Kconfig                          |  17 +
>  drivers/gpio/Makefile                         |   1 +
>  drivers/gpio/gpio-imx-rpmsg.c                 | 475 ++++++++++++++++++
>  drivers/remoteproc/imx_rproc.c                | 146 ++++++
>  include/linux/rpmsg/imx_rpmsg.h               |  48 ++
>  9 files changed, 1040 insertions(+)
>  create mode 100644 Documentation/staging/gpio-rpmsg.rst
>  create mode 100644 drivers/gpio/gpio-imx-rpmsg.c
>  create mode 100644 include/linux/rpmsg/imx_rpmsg.h
>

After reviewing this patchset I come to the following conclusion:

(1) Other people have pointed this out multiple time and I will do the same: the
only way this work will move forward is by adopting a generic solution.  This
proposal is not (no need to try to convince me otherwise).

(2) The right way to do this would be to have a separate set of virtqueues for
each component that sits behind the remoteproc, instantiated using the content
found in the resource table.  This would follow the same approach as the
namespace, with their own VIRTIO IDS as published in [1].  That way we could
re-use a lot of the work already done for other components, such as virtio-i2c
and virtio-gpio.

(3) Some environment may be too memory constrained for option (2) above, hence
using rpmsg as a transport protocol.  But as with option (2), that way also
needs to look like virtio devices to the kernel.  It also means that protocol
to interact with components need to follow the OASIS specification.  As such
you'd have platform drivers for rpmsg-i2c and rpmsg-gpio that would register
rpmsg_drivers.

I don't mind which approach is taken as they both represent the same amount of
work.  Lastly, your next patchset should contain an implementation for GPIO or
I2C, not both.

Thanks,
Mathieu

[1]. https://elixir.bootlin.com/linux/v6.18-rc7/source/include/uapi/linux/virtio_ids.h#L38
 
> --
> 2.43.0
> 


From conor at kernel.org  Wed Dec  3 11:19:07 2025
From: conor at kernel.org (Conor Dooley)
Date: Wed, 3 Dec 2025 19:19:07 +0000
Subject: [PATCH 2/4] dt-bindings: arm: Document Microchip LAN969x
In-Reply-To: <20251203122313.1287950-2-robert.marko@sartura.hr>
References: <20251203122313.1287950-1-robert.marko@sartura.hr>
 <20251203122313.1287950-2-robert.marko@sartura.hr>
Message-ID: <20251203-duly-leotard-86b83bd840c6@spud>

On Wed, Dec 03, 2025 at 01:21:30PM +0100, Robert Marko wrote:
> Microchip LAN969x is a series of multi-port, multi-gigabit switches based
> on ARMv8 Cortex-A53 CPU.
> 
> Signed-off-by: Robert Marko <robert.marko at sartura.hr>
> ---
>  .../bindings/arm/microchip,lan969x.yaml       | 32 +++++++++++++++++++

This should not be in a unique file, put it in with the other microchip
arm devices please. Also, the wildcard in the compatible is not
permitted, only way it'd make sense is if these are different binnings
of the same silicon. If that's the case, you need to explain why,
because compatibles are meant to be soc-specific.

pw-bot: changes-requested

>  1 file changed, 32 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/arm/microchip,lan969x.yaml
> 
> diff --git a/Documentation/devicetree/bindings/arm/microchip,lan969x.yaml b/Documentation/devicetree/bindings/arm/microchip,lan969x.yaml
> new file mode 100644
> index 000000000000..3fa1d4ed40d1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/arm/microchip,lan969x.yaml
> @@ -0,0 +1,32 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/arm/microchip,lan969x.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Microchip LAN969x Boards
> +
> +maintainers:
> +  - Robert Marko <robert.marko at sartura.hr>
> +
> +description: |+
> +   The Microchip LAN969x SoC is a ARMv8-based used in a family of
> +   multi-port, multi-gigabit switches.
> +
> +properties:
> +  $nodename:
> +    const: '/'
> +  compatible:
> +    oneOf:
> +      - description: The LAN969x EVB (EV23X71A) is a 24x 1G + 4x 10G
> +          Ethernet development system board.
> +        items:
> +          - const: microchip,ev23x71a
> +          - const: microchip,lan969x
> +
> +required:
> +  - compatible
> +
> +additionalProperties: true
> +
> +...
> -- 
> 2.52.0
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251203/0c3581f3/attachment-0001.sig>

From conor at kernel.org  Wed Dec  3 11:21:23 2025
From: conor at kernel.org (Conor Dooley)
Date: Wed, 3 Dec 2025 19:21:23 +0000
Subject: [PATCH 4/4] arm64: dts: microchip: add LAN969x support
In-Reply-To: <20251203122313.1287950-4-robert.marko@sartura.hr>
References: <20251203122313.1287950-1-robert.marko@sartura.hr>
 <20251203122313.1287950-4-robert.marko@sartura.hr>
Message-ID: <20251203-splendor-cubbyhole-eda2d6982b46@spud>

On Wed, Dec 03, 2025 at 01:21:32PM +0100, Robert Marko wrote:
> Add support for Microchip LAN969x switch SoC, including the EV23X71A
> EVB board.
> 
> Signed-off-by: Robert Marko <robert.marko at sartura.hr>
> ---
>  arch/arm64/boot/dts/microchip/Makefile        |   2 +
>  .../boot/dts/microchip/lan9696-ev23x71a.dts   | 761 ++++++++++++++++++

>  arch/arm64/boot/dts/microchip/lan969x.dtsi    | 482 +++++++++++

The majority of devices in this file are missing soc-specific
compatibles.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251203/0a1838cd/attachment.sig>

From conor at kernel.org  Wed Dec  3 11:22:35 2025
From: conor at kernel.org (Conor Dooley)
Date: Wed, 3 Dec 2025 19:22:35 +0000
Subject: [PATCH 3/4] include: dt-bindings: add LAN969x clock bindings
In-Reply-To: <20251203122313.1287950-3-robert.marko@sartura.hr>
References: <20251203122313.1287950-1-robert.marko@sartura.hr>
 <20251203122313.1287950-3-robert.marko@sartura.hr>
Message-ID: <20251203-flatten-spotty-69f16d3460f0@spud>

On Wed, Dec 03, 2025 at 01:21:31PM +0100, Robert Marko wrote:
> Add the required LAN969x clock bindings.
> 
> Signed-off-by: Robert Marko <robert.marko at sartura.hr>
> ---
>  include/dt-bindings/clock/microchip,lan969x.h | 24 +++++++++++++++++++
>  1 file changed, 24 insertions(+)
>  create mode 100644 include/dt-bindings/clock/microchip,lan969x.h

Same thing here, this should be specific. Probably 9691, because that's
what you're using the compatible of in your dts.

pw-bot: changes-requested

> 
> diff --git a/include/dt-bindings/clock/microchip,lan969x.h b/include/dt-bindings/clock/microchip,lan969x.h
> new file mode 100644
> index 000000000000..5a9c8bf7824a
> --- /dev/null
> +++ b/include/dt-bindings/clock/microchip,lan969x.h
> @@ -0,0 +1,24 @@
> +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
> +
> +#ifndef _DT_BINDINGS_CLK_LAN969X_H
> +#define _DT_BINDINGS_CLK_LAN969X_H
> +
> +#define GCK_ID_QSPI0		0
> +#define GCK_ID_QSPI2		1
> +#define GCK_ID_SDMMC0		2
> +#define GCK_ID_SDMMC1		3
> +#define GCK_ID_MCAN0		4
> +#define GCK_ID_MCAN1		5
> +#define GCK_ID_FLEXCOM0		6
> +#define GCK_ID_FLEXCOM1		7
> +#define GCK_ID_FLEXCOM2		8
> +#define GCK_ID_FLEXCOM3		9
> +#define GCK_ID_TIMER		10
> +#define GCK_ID_USB_REFCLK	11
> +
> +/* Gate clocks */
> +#define GCK_GATE_USB_DRD	12
> +#define GCK_GATE_MCRAMC		13
> +#define GCK_GATE_HMATRIX	14
> +
> +#endif
> -- 
> 2.52.0
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251203/9318d325/attachment.sig>

From krzk at kernel.org  Wed Dec  3 12:21:29 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 3 Dec 2025 21:21:29 +0100
Subject: [PATCH 1/4] dt-bindings: serial: mediatek,uart: Add compatible
 for MT8189 SoC
In-Reply-To: <20251203-add-mediatek-genio-520-720-evk-v1-1-df794b2a30ae@collabora.com>
References: <20251203-add-mediatek-genio-520-720-evk-v1-0-df794b2a30ae@collabora.com>
 <20251203-add-mediatek-genio-520-720-evk-v1-1-df794b2a30ae@collabora.com>
Message-ID: <4dbab3a5-64bf-4c34-ad4c-94620a041993@kernel.org>

On 03/12/2025 14:59, Louis-Alexis Eyraud wrote:
> Add a compatible string for the MT8189 SoC.
> The UART IPs in this chip are fully compatible with the one found in
> MT6577 SoC.
> 
> Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
> ---
>  Documentation/devicetree/bindings/serial/mediatek,uart.yaml | 1 +
>  1 file changed, 1 insertion(+)


Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof


From krzk at kernel.org  Wed Dec  3 12:23:06 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 3 Dec 2025 21:23:06 +0100
Subject: [PATCH 2/4] dt-bindings: arm: mediatek: add compatibles for
 Mediatek Genio 520/720-EVK boards
In-Reply-To: <20251203-add-mediatek-genio-520-720-evk-v1-2-df794b2a30ae@collabora.com>
References: <20251203-add-mediatek-genio-520-720-evk-v1-0-df794b2a30ae@collabora.com>
 <20251203-add-mediatek-genio-520-720-evk-v1-2-df794b2a30ae@collabora.com>
Message-ID: <1d516e97-5bfd-4bba-8496-65b00c26f76a@kernel.org>

On 03/12/2025 14:59, Louis-Alexis Eyraud wrote:
> Add compatible strings for the Mediatek Genio 520-EVK (based on
> MT8371 SoC) and Mediatek Genio 720-EVK (based on MT8391 SoC) boards.
> MT8391 and MT8371 SoC are less powerful variants of MT8189 SoC,
> with identical hardware register maps.

BTW, subject length is precious, so you can skip redundant parts like
"compatibles for" and just have it "add Mediatek foobar boards". That's
also expressed in submitting patches in DT. No need to resend for this.

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof


From knaerzche at gmail.com  Wed Dec  3 12:23:12 2025
From: knaerzche at gmail.com (Alex Bee)
Date: Wed, 3 Dec 2025 21:23:12 +0100
Subject: [PATCH] arm64: dts: rockchip: add SPDIF audio to Beelink A1
In-Reply-To: <66ae20b3-3316-4ec2-9c51-8414c053dc32@arm.com>
References: <20250828164300.3829488-1-christianshewitt@gmail.com>
 <66ae20b3-3316-4ec2-9c51-8414c053dc32@arm.com>
Message-ID: <f0df035f-3c3d-4649-9f48-3e8e2e69d17b@gmail.com>

Hi Robin,

Am 03.12.25 um 17:21 schrieb Robin Murphy:
> [ Just noticed this... ]
>
> On 2025-08-28 5:43 pm, Christian Hewitt wrote:
>> From: Alex Bee <knaerzche at gmail.com>
>>
>> Add the required nodes to enable SPDIF audio output on
>> the Beelink A1 set-top-box.
>
> But the A1 doesn't have S/PDIF? Only HDMI plus a 3.5mm jack connected 
> to the analog audio codec (and possibly the composite TV out) :/
>
Yeah, sorry - this patch wasn't supposed to be submitted upstream.

Regards,

Alex

> Thanks,
> Robin.
>
>> Signed-off-by: Alex Bee <knaerzche at gmail.com>
>> Signed-off-by: Christian Hewitt <christianshewitt at gmail.com>
>> ---
>> ? arch/arm64/boot/dts/rockchip/rk3328-a1.dts | 23 ++++++++++++++++++++++
>> ? 1 file changed, 23 insertions(+)
>>
>> diff --git a/arch/arm64/boot/dts/rockchip/rk3328-a1.dts 
>> b/arch/arm64/boot/dts/rockchip/rk3328-a1.dts
>> index f7c4578865c5..b276a29bdd85 100644
>> --- a/arch/arm64/boot/dts/rockchip/rk3328-a1.dts
>> +++ b/arch/arm64/boot/dts/rockchip/rk3328-a1.dts
>> @@ -58,6 +58,24 @@ ir-receiver {
>> ????????? gpios = <&gpio2 RK_PA2 GPIO_ACTIVE_LOW>;
>> ????????? linux,rc-map-name = "rc-beelink-gs1";
>> ????? };
>> +
>> +??? spdif_sound: spdif-sound {
>> +??????? compatible = "simple-audio-card";
>> +??????? simple-audio-card,name = "SPDIF";
>> +
>> +??????? simple-audio-card,cpu {
>> +??????????? sound-dai = <&spdif>;
>> +??????? };
>> +
>> +??????? simple-audio-card,codec {
>> +??????????? sound-dai = <&spdif_dit>;
>> +??????? };
>> +??? };
>> +
>> +??? spdif_dit: spdif-dit {
>> +??????? compatible = "linux,spdif-dit";
>> +??????? #sound-dai-cells = <0>;
>> +??? };
>> ? };
>> ? ? &analog_sound {
>> @@ -325,6 +343,11 @@ &sdmmc {
>> ????? status = "okay";
>> ? };
>> ? +&spdif {
>> +??? pinctrl-0 = <&spdifm0_tx>;
>> +??? status = "okay";
>> +};
>> +
>> ? &tsadc {
>> ????? rockchip,hw-tshut-mode = <0>;
>> ????? rockchip,hw-tshut-polarity = <0>;


From olsajiri at gmail.com  Wed Dec  3 12:23:47 2025
From: olsajiri at gmail.com (Jiri Olsa)
Date: Wed, 3 Dec 2025 21:23:47 +0100
Subject: [PATCHv4 bpf-next 1/9] ftrace,bpf: Remove FTRACE_OPS_FL_JMP
 ftrace_ops flag
In-Reply-To: <CADxym3awpEbMiSKE5aDcyd2Cg1Cdo7++SLAMSuZmaggt3BSbUA@mail.gmail.com>
References: <20251203082402.78816-1-jolsa@kernel.org>
 <20251203082402.78816-2-jolsa@kernel.org>
 <CADxym3awpEbMiSKE5aDcyd2Cg1Cdo7++SLAMSuZmaggt3BSbUA@mail.gmail.com>
Message-ID: <aTCcU509ajY9-Dgj@krava>

On Wed, Dec 03, 2025 at 05:15:52PM +0800, Menglong Dong wrote:
> On Wed, Dec 3, 2025 at 4:24?PM Jiri Olsa <jolsa at kernel.org> wrote:
> >
> > At the moment the we allow the jmp attach only for ftrace_ops that
> > has FTRACE_OPS_FL_JMP set. This conflicts with following changes
> > where we use single ftrace_ops object for all direct call sites,
> > so all could be be attached via just call or jmp.
> >
> > We already limit the jmp attach support with config option and bit
> > (LSB) set on the trampoline address. It turns out that's actually
> > enough to limit the jmp attach for architecture and only for chosen
> > addresses (with LSB bit set).
> >
> > Each user of register_ftrace_direct or modify_ftrace_direct can set
> > the trampoline bit (LSB) to indicate it has to be attached by jmp.
> >
> > The bpf trampoline generation code uses trampoline flags to generate
> > jmp-attach specific code and ftrace inner code uses the trampoline
> > bit (LSB) to handle return from jmp attachment, so there's no harm
> > to remove the FTRACE_OPS_FL_JMP bit.
> >
> > The fexit/fmodret performance stays the same (did not drop),
> > current code:
> >
> >   fentry         :   77.904 ? 0.546M/s
> >   fexit          :   62.430 ? 0.554M/s
> >   fmodret        :   66.503 ? 0.902M/s
> >
> > with this change:
> >
> >   fentry         :   80.472 ? 0.061M/s
> >   fexit          :   63.995 ? 0.127M/s
> >   fmodret        :   67.362 ? 0.175M/s
> >
> > Fixes: 25e4e3565d45 ("ftrace: Introduce FTRACE_OPS_FL_JMP")
> > Signed-off-by: Jiri Olsa <jolsa at kernel.org>
> > ---
> >  include/linux/ftrace.h  |  1 -
> >  kernel/bpf/trampoline.c | 32 ++++++++++++++------------------
> >  kernel/trace/ftrace.c   | 14 --------------
> >  3 files changed, 14 insertions(+), 33 deletions(-)
> >
> > diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
> > index 015dd1049bea..505b7d3f5641 100644
> > --- a/include/linux/ftrace.h
> > +++ b/include/linux/ftrace.h
> > @@ -359,7 +359,6 @@ enum {
> >         FTRACE_OPS_FL_DIRECT                    = BIT(17),
> >         FTRACE_OPS_FL_SUBOP                     = BIT(18),
> >         FTRACE_OPS_FL_GRAPH                     = BIT(19),
> > -       FTRACE_OPS_FL_JMP                       = BIT(20),
> 
> Yeah, the FTRACE_OPS_FL_JMP is not necessary. I added
> it in case that we maybe want to implement such "jmp" for
> ftrace trampoline in the feature. But it's OK to remove it now.
> 
> >  };
> >
> >  #ifndef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
> > diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
> > index 976d89011b15..b9a358d7a78f 100644
> > --- a/kernel/bpf/trampoline.c
> > +++ b/kernel/bpf/trampoline.c
> > @@ -214,10 +214,15 @@ static int modify_fentry(struct bpf_trampoline *tr, u32 orig_flags,
> >         int ret;
> >
> >         if (tr->func.ftrace_managed) {
> > +               unsigned long addr = (unsigned long) new_addr;
> > +
> > +               if (bpf_trampoline_use_jmp(tr->flags))
> > +                       addr = ftrace_jmp_set(addr);

I wanted to get rid of the  void * -> unsigned long casting in all the
places.. this way it has to be just on one place above, but maybe we
could have already direct_ops_add with unsigned long addr, will check

jirka

> 
> nit: It seems that we can remove the variable "addr" can use
> the "new_addr" directly?
> 
> > +
> >                 if (lock_direct_mutex)
> > -                       ret = modify_ftrace_direct(tr->fops, (long)new_addr);
> > +                       ret = modify_ftrace_direct(tr->fops, addr);
> >                 else
> > -                       ret = modify_ftrace_direct_nolock(tr->fops, (long)new_addr);
> > +                       ret = modify_ftrace_direct_nolock(tr->fops, addr);
> >         } else {
> >                 ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr,
> >                                                    new_addr);
> > @@ -240,10 +245,15 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
> >         }
> >
> >         if (tr->func.ftrace_managed) {
> > +               unsigned long addr = (unsigned long) new_addr;
> > +
> > +               if (bpf_trampoline_use_jmp(tr->flags))
> > +                       addr = ftrace_jmp_set(addr);
> 
> And here.
> 
> Thanks!
> Menglong Dong
> 
> > +
> [...]
> >


From olsajiri at gmail.com  Wed Dec  3 12:25:12 2025
From: olsajiri at gmail.com (Jiri Olsa)
Date: Wed, 3 Dec 2025 21:25:12 +0100
Subject: [PATCHv4 bpf-next 4/9] ftrace: Add update_ftrace_direct_add
 function
In-Reply-To: <d0d8e0d78f614eb8b443772b50fb36093d48c7f43374316246ad3ad836b5c9ce@mail.kernel.org>
References: <20251203082402.78816-5-jolsa@kernel.org>
 <d0d8e0d78f614eb8b443772b50fb36093d48c7f43374316246ad3ad836b5c9ce@mail.kernel.org>
Message-ID: <aTCcqGiWnEmGGuRI@krava>

On Wed, Dec 03, 2025 at 08:47:45AM +0000, bot+bpf-ci at kernel.org wrote:
> > diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
> > index 8c034b028..eb60d971e 100644
> > --- a/include/linux/ftrace.h
> > +++ b/include/linux/ftrace.h
> 
> [ ... ]
> 
> > diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
> > index 84aee9096..1660a8754 100644
> > --- a/kernel/trace/ftrace.c
> > +++ b/kernel/trace/ftrace.c
> 
> [ ... ]
> 
> > +int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash)
> > +{
> > +	struct ftrace_hash *old_direct_functions = NULL, *new_direct_functions = NULL;
> > +	struct ftrace_hash *old_filter_hash = NULL, *new_filter_hash = NULL;
> > +	struct ftrace_func_entry *entry;
> > +	int i, size, err = -EINVAL;
> > +	bool reg;
> > +
> > +	if (!hash_count(hash))
> > +		return -EINVAL;
> > +
> > +	mutex_lock(&direct_mutex);
> > +
> > +	/* Make sure requested entries are not already registered. */
> > +	size = 1 << hash->size_bits;
> > +	for (i = 0; i < size; i++) {
> > +		hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
> > +			if (__ftrace_lookup_ip(direct_functions, entry->ip))
> > +				goto out_unlock;
> > +		}
> > +	}
> > +
> > +	old_filter_hash = ops->func_hash ? ops->func_hash->filter_hash : NULL;
> > +	old_direct_functions = direct_functions;
> > +
> > +	/* If there's nothing in filter_hash we need to register the ops. */
> > +	reg = hash_count(old_filter_hash) == 0;
> > +	if (reg) {
> > +		if (ops->func || ops->trampoline)
> > +			goto out_unlock;
> > +		if (ops->flags & FTRACE_OPS_FL_ENABLED)
> > +			goto out_unlock;
> > +	}
> > +
> > +	err = -ENOMEM;
> > +	new_filter_hash = hash_add(old_filter_hash, hash);
> > +	if (!new_filter_hash)
> > +		goto out_unlock;
> > +
> > +	new_direct_functions = hash_add(old_direct_functions, hash);
> > +	if (!new_direct_functions)
> > +		goto out_unlock;
> 
> Can new_filter_hash leak here?  If the second hash_add() fails but the
> first one succeeds, update_ftrace_direct_add() will goto out_unlock
> with new_filter_hash pointing to allocated memory.  At out_unlock, only
> old_filter_hash gets freed, not new_filter_hash.

mamma mia, can't get this right apparently.. yea, will fix in next
version, thanks

jirka


> 
> register_ftrace_direct() handles this by freeing new_hash on error:
> 
>     out_unlock:
>         mutex_unlock(&direct_mutex);
> 
>         if (free_hash && free_hash != EMPTY_HASH)
>             call_rcu_tasks(&free_hash->rcu, register_ftrace_direct_cb);
> 
>         if (new_hash)
>             free_ftrace_hash(new_hash);
> 
>         return err;
> 
> > +
> > +	rcu_assign_pointer(direct_functions, new_direct_functions);
> > +
> > +	if (reg) {
> > +		ops->func = call_direct_funcs;
> > +		ops->flags |= MULTI_FLAGS;
> > +		ops->trampoline = FTRACE_REGS_ADDR;
> > +		ops->local_hash.filter_hash = new_filter_hash;
> > +
> > +		err = register_ftrace_function_nolock(ops);
> > +		if (err) {
> > +			/* restore old filter on error */
> > +			ops->local_hash.filter_hash = old_filter_hash;
> > +			old_filter_hash = new_filter_hash;
> > +
> > +			/* cleanup for possible another register call */
> > +			ops->func = NULL;
> > +			ops->trampoline = 0;
> > +		}
> > +	} else {
> > +		err = ftrace_update_ops(ops, new_filter_hash, EMPTY_HASH);
> > +		/*
> > +		 * new_filter_hash is dup-ed, so we need to release it anyway,
> > +		 * old_filter_hash either stays on error or is released already
> > +		 */
> > +		old_filter_hash = new_filter_hash;
> > +	}
> > +
> > +	if (err) {
> > +		/* reset direct_functions and free the new one */
> > +		rcu_assign_pointer(direct_functions, old_direct_functions);
> > +		old_direct_functions = new_direct_functions;
> > +	}
> > +
> > + out_unlock:
> > +	mutex_unlock(&direct_mutex);
> > +
> > +	if (old_direct_functions && old_direct_functions != EMPTY_HASH)
> > +		call_rcu_tasks(&old_direct_functions->rcu, register_ftrace_direct_cb);
> > +	if (old_filter_hash)
> > +		free_ftrace_hash(old_filter_hash);
> > +
> > +	return err;
> > +}
> 
> 
> ---
> AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
> See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
> 
> CI run summary: https://github.com/kernel-patches/bpf/actions/runs/19887401362



From krzk at kernel.org  Wed Dec  3 12:25:53 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 3 Dec 2025 21:25:53 +0100
Subject: [PATCH 3/4] arm64: dts: mediatek: add device-tree for Genio
 720-EVK board
In-Reply-To: <20251203-add-mediatek-genio-520-720-evk-v1-3-df794b2a30ae@collabora.com>
References: <20251203-add-mediatek-genio-520-720-evk-v1-0-df794b2a30ae@collabora.com>
 <20251203-add-mediatek-genio-520-720-evk-v1-3-df794b2a30ae@collabora.com>
Message-ID: <87db9b43-ceae-47b9-9435-9fa297054fc2@kernel.org>

On 03/12/2025 14:59, Louis-Alexis Eyraud wrote:
> Add support for MediaTek MT8189 SoC and its variants, and a device-tree
> for the basic hardware enablement of the Genio 720-EVK board, based on
> MT8391 SoC.
> 
> MT8391 SoC is a variant of MT8189 SoC with a difference for the Arm
> Cortex-A78 CPU core maximum frequency (2.6 Ghz for MT8391, 3 Ghz for
> MT8189). MT8391 hardware register maps are identical to MT8189.

Subject: drop redundant "device-tree for" (not mentioning not correct
name even...).

> 
> The Genio 720-EVK board has following features:
>   - MT8391 SoC
>   - MT6365 PMIC
>   - MT6319 Buck IC
>   - MT6375 Charger IC
>   - 8GB LPDDR5 RAM
>   - 64GB eMMC 5.1
>   - 128GB UFS
>   - 20V DC Jack
>   - USB Type-C Power Adapter
>   - Micro SD card slot
>   - Push Button x 4 (Power, Reset, Download and Home Key)
>   - LED x 3 (System Power, Reset, DC-IN Power)
>   - USB Type-C Connector (USB 3.2) x 2
>   - USB Type-C Connector (USB 2.0) x 1
>   - 3.5mm Earphone Jack x 1 (with Microphone Input)
>   - 3.5mm Line Out Audio Jack x 1
>   - Analog Microphone x 1
>   - Digital Microphone x 2
>   - Gigabit Ethernet with RJ45 connector
>   - DP x 1 (Mode over USB Type-C)
>   - LVDS port x 1
>   - eDP port x 1
>   - UART x2 with serial-to-usb converters and USB Type-C connectors
>   - UART Port x 2 on Pin Header
>   - M.2 Slot x 2
>   - I2C Capacitive Touch Pad
>   - 4-Lane DSI x 1
>   - 4-Data Lane CSI x 2
>   - I2S Pin header
>   - 40-Pin 2.54mm Pin Header x 1
>   - CAN Bus x 1 (RS232 Connector)
> 
> Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
> ---
>  arch/arm64/boot/dts/mediatek/Makefile              |   1 +
>  arch/arm64/boot/dts/mediatek/mt8189.dtsi           | 860 +++++++++++++++++++++
>  .../boot/dts/mediatek/mt8391-genio-720-evk.dts     |  15 +
>  .../boot/dts/mediatek/mt8391-genio-common.dtsi     | 555 +++++++++++++
>  4 files changed, 1431 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile
> index c5fd6191a925ad8fcea401712f7a686e8b0a57c8..e3b63085c0608b86dc8638c9d5e0b73441e9ed7b 100644
> --- a/arch/arm64/boot/dts/mediatek/Makefile
> +++ b/arch/arm64/boot/dts/mediatek/Makefile
> @@ -110,6 +110,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-genio-1200-evk.dtb
>  dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-genio-1200-evk-ufs.dtb
>  dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-genio-700-evk.dtb
>  dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-grinn-genio-700-sbc.dtb
> +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8391-genio-720-evk.dtb
>  dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-kontron-3-5-sbc-i1200.dtb
>  dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-radxa-nio-12l.dtb
>  dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-radxa-nio-12l-8-hd-panel.dtbo
> diff --git a/arch/arm64/boot/dts/mediatek/mt8189.dtsi b/arch/arm64/boot/dts/mediatek/mt8189.dtsi
> new file mode 100644
> index 0000000000000000000000000000000000000000..bf8a232bcaf10cdf4c590109aea68c9a3e82cc42
> --- /dev/null
> +++ b/arch/arm64/boot/dts/mediatek/mt8189.dtsi
> @@ -0,0 +1,860 @@
> +// SPDX-License-Identifier: (GPL-2.0 OR MIT)
> +/*
> + * Copyright (c) 2025 MediaTek Inc.
> + *
> + * Copyright (c) 2025 Collabora Ltd.
> + * Author: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
> + */
> +
> +#include <dt-bindings/clock/mediatek,mt8189-clk.h>
> +#include <dt-bindings/interrupt-controller/arm-gic.h>
> +#include <dt-bindings/interrupt-controller/irq.h>
> +
> +/ {
> +	compatible = "mediatek,mt8189";
> +	interrupt-parent = <&gic>;
> +	#address-cells = <2>;
> +	#size-cells = <2>;
> +
> +	aliases {
> +		i2c0 = &i2c0;
> +		i2c1 = &i2c1;
> +		i2c2 = &i2c2;
> +		i2c3 = &i2c3;
> +		i2c4 = &i2c4;
> +		i2c5 = &i2c5;
> +		i2c6 = &i2c6;
> +		i2c7 = &i2c7;
> +		i2c8 = &i2c8;
> +		mmc0 = &mmc0;
> +		mmc1 = &mmc1;
> +		serial0 = &uart0;

None of above are aliases of the soc. Please move them to the board,
because these are properties of the board currently (we did not finish
the discussion about soc-aliases, so it cannot be used as reason for above).



> +	};
> +
> +	clk32k: oscillator-clk32k {

Either oscillator or clock (clk). Not both. "clock-clk" makes no sense
and this is implied by oscillator.

Please use name for all fixed clocks which matches current format
recommendation: 'clock-<freq>' (see also the pattern in the binding for
any other options).

https://web.git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/clock/fixed-clock.yaml


Best regards,
Krzysztof


From krzk at kernel.org  Wed Dec  3 12:28:28 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 3 Dec 2025 21:28:28 +0100
Subject: [PATCH v2 01/22] media: dt-bindings: media: rockchip-rga: add
 rockchip,rk3588-rga3
In-Reply-To: <20251203-spu-rga3-v2-1-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
 <20251203-spu-rga3-v2-1-989a67947f71@pengutronix.de>
Message-ID: <81593c42-fcc2-47ad-8d0f-69a2d17664a6@kernel.org>

On 03/12/2025 16:52, Sven P?schel wrote:
> Add a new compatible for the RGA3 (Raster Graphic Acceleration 3)
> peripheral found on the RK3588 SoC.
> 
> The existing rga node refers to the RGA2 peripheral. The RK3588

What is "existing rga node"? There is no node here. This is a patch for
bindings, so you say which hardware existing binding describes and what
are the differences against that older hardware.

> contains one RGA2 core and two RGA3 cores. Both feature a similar
> functionality of scaling, cropping and rotating of up to two input
> images into one output image. Key differences of the RGA3 are:
> 
> - supports 10bit YUV output formats
> - supports 8x8 tiles and FBCD as inputs and outputs
> - supports BT2020 color space conversion
> - max output resolution of (8192-64)x(8192-64)
> - MMU can map up to 32G DDR RAM
> - fully planar formats (3 planes) are not supported
> - max scale up/down factor of 8

"differences" in meaning nothing above is supported by RGA2?

> 
> Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
> ---

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>


Best regards,
Krzysztof


From Frank.li at nxp.com  Wed Dec  3 13:01:19 2025
From: Frank.li at nxp.com (Frank Li)
Date: Wed, 3 Dec 2025 16:01:19 -0500
Subject: [PATCH v4 0/5] media: imx8qxp: add parallel camera support
In-Reply-To: <DEOKQZMPDTLY.3H4NBUEC3LNHE@linaro.com>
References: <aLbcpEZXm5G1Onq7@lizhi-Precision-Tower-5810>
 <20250902123920.GM13448@pendragon.ideasonboard.com>
 <aLhJDXnz9HPGrWcp@lizhi-Precision-Tower-5810>
 <aQuDSROHLGHIhtlh@lizhi-Precision-Tower-5810>
 <20251105171928.GB6046@pendragon.ideasonboard.com>
 <aQul/VGG8e3MJxhx@lizhi-Precision-Tower-5810>
 <DE1JMG95RZME.2YSV10RI9AME4@gmail.com>
 <aQzFiEOQvtZjHIsr@lizhi-Precision-Tower-5810>
 <aS9NvkAWTa42j7KW@lizhi-Precision-Tower-5810>
 <DEOKQZMPDTLY.3H4NBUEC3LNHE@linaro.com>
Message-ID: <aTClH5RSpXpXfxXx@lizhi-Precision-Tower-5810>

On Wed, Dec 03, 2025 at 12:19:04PM +0000, Rui Miguel Silva wrote:
> Hey Frank,
> On Tue Dec 2, 2025 at 8:36 PM WET, Frank Li wrote:
>
> > On Thu, Nov 06, 2025 at 10:58:00AM -0500, Frank Li wrote:
> >> On Thu, Nov 06, 2025 at 10:34:48AM +0000, Rui Miguel Silva wrote:
> >> > On Wed Nov 5, 2025 at 7:31 PM WET, Frank Li wrote:
> >> >
> >> > > On Wed, Nov 05, 2025 at 07:19:28PM +0200, Laurent Pinchart wrote:
> >> > >> Hi Frank,
> >> > >>
> >> > >> On Wed, Nov 05, 2025 at 12:03:05PM -0500, Frank Li wrote:
> >> > >> > On Wed, Sep 03, 2025 at 09:56:29AM -0400, Frank Li wrote:
> >> > >> > > On Tue, Sep 02, 2025 at 02:39:20PM +0200, Laurent Pinchart wrote:
> >> > >> > > > On Tue, Sep 02, 2025 at 08:01:40AM -0400, Frank Li wrote:
> >> > >> > > > > On Tue, Aug 05, 2025 at 04:08:22AM +0300, Laurent Pinchart wrote:
> >> > >> > > > > > Hi Frank,
> >> > >> > > > > >
> >> > >> > > > > > Thank you for the patches.
> >> > >> > > > > >
> >> > >> > > > > > I've quite busy these days, and I don't believe I will have time to
> >> > >> > > > > > review this series before coming back from OSS Europe at the beginning
> >> > >> > > > > > of September. Let's see if anyone on CC could volunteer.
> >> > >> > > > >
> >> > >> > > > > Laurent Pincha
> >> > >> > > > > 	I hope you have good time at OSS.
> >> > >> > > > >
> >> > >> > > > > 	Do you have chance to review this patch?
> >> > >> > > >
> >> > >> > > > I'm going through my mail backlog, which is really big at the moment.
> >> > >> > >
> >> > >> > > Understand.
> >> > >> > >
> >> > >> > > > I'd like someone else to volunteer to review this series. It won't scale
> >> > >> > > > if I have to review all NXP media patches in my spare time :-/
> >> > >> > >
> >> > >> > > Yes, but none volunteer review this in passed months. Expecially key
> >> > >> > > reviewer. I am reviewing i3c patches. but Not familiar v4l system yet. It
> >> > >> > > need scalable solution. I can help filter some common and simple problem
> >> > >> > > from beginning.
> >> > >> >
> >> > >> > Laurent Pinchart:
> >> > >> >
> >> > >> > 	Do you have chance to check this serise? this one should be related simple.
> >> > >> > 	This one sent at 7/29. Still not any volunteer to review it.
> >> > >>
> >> > >> I'm afraid I won't have time to review this for the time being. My spare
> >> > >> time is already exhausted by all the other drivers I maintain upstream.
> >> > >>
> >> > >> > 	How do we move forward?
> >> > >>
> >> > >> I think this is a question for the subsystem maintainers. Hans, Mauro ?
> >> > >
> >> > > Mauro Carvalho Chehab and Hans Verkuil:
> >> > >
> >> > > 	Laurent provided great help about review and land i.MX related
> >> > > patches in past, who are quite famillar with i.MX chips. But he is quite
> >> > > busy. So the whole reviews cycles takes quite long time and offten cross
> >> > > some merge windows.
> >> > >
> >> > > 	In pull requests for 6.19:
> >> > > https://lore.kernel.org/all/4989c563-47f4-478c-80c4-41f7e98597e4 at kernel.org/
> >> > > only 10 patches, and 4 patches is trivial clean up.
> >> > >
> >> > > 	In reviewing patch queue, there are
> >> > > 	1: media: nxp: imx8-isi: Add ISI support for i.MX95
> >> > > 	   https://lore.kernel.org/imx/20251105-isi_imx95-v3-0-3987533cca1c at nxp.com/T/#t
> >> > > 	   This one already review, but I am not sure if it capture 6.19 cycle because
> >> > > PULL-request already sent.
> >> > >
> >> > > 	2: Add MIPI CSI-2 support for i.MX8ULP
> >> > > 	   https://lore.kernel.org/imx/20251023-csi2_imx8ulp-v7-0-5ecb081ce79b at nxp.com/
> >> > >
> >> > > 	3: media: add imx93 mipi/controller csi support
> >> > > 	   https://lore.kernel.org/imx/20250821-95_cam-v3-0-c9286fbb34b9 at nxp.com/
> >> > > 	   This one is quite big, but first 10 patches is simple trivial cleanup patches.
> >> > > 	   I post at 8/27, but get first feedback around 10/27, I am not
> >> > > 	   sure if missing somethings.
> >> > >
> >> > > 	4: This series, laurent already said no time review it.
> >> > >
> >> > > 	5: ap1302 sensor patches
> >> > >            https://lore.kernel.org/imx/20250811-ap1302-v4-0-80cc41b91662 at nxp.com/
> >> > >            binding already ACK, most maintainer want to pick binding with
> >> > > 	   driver together, but not an feedback since 8/11.
> >> > >
> >> > > 	I jump into and help do some review.
> >> > >
> >> > > 	The questions is how to move forward pending patches, like [3], [4],
> >> > > [5]. How to keep good community channel to avoid long time pending?
> >> >
> >> > Sorry, but like Laurent I am really without spare cycles to go over the
> >> > patch series that have arrived in media (also I do not have any hw anymore).
> >> > So, Frank or maybe Laurent knows someone that would like to be add also as
> >> > maintainer of this drivers for me would be great, that would also help to
> >> > avoid such bottlenecks.
> >>
> >> If there are not other candidate, I can help maintain it although I am more
> >> familar with dt binding, i3c and dmaengine. I can start from simple patches
> >> and we have test team to help cover testing on the real hardware.
> >
> > Rui:
> > 	Any update? How to move forward? It was already passed more than 3
> > month!
>
> Sorry, I did not realise something was blocked because of me, specially imx8
> related. I thought you have sent the update to MAINTAINERS.

I just marked me as reviewer in prevous's patch.

>
> For me it is fine, it makes perfect sense since you have access to hardware
> and documentation, for you to be the maintainer and steer the features and
> improvements in the imx media. you can move me to Reviewer, since there are
> already other 2 persons (and Laurent already handle the pulls, thanks for that)
> much more active in the IMX media subsystem.

Laruent Pinchart:

	If I will remove common file change in patch
"media: v4l2-common: Add helper function v4l_get_required_align_by_bpp()"

	Are you okay to pick up this patches? Or what's way to get it
merged? Or anyone else can pickup and send pull if you have not time.

Frank

>
> Thanks again and Cheers,
>     Rui


From bisson.gary at gmail.com  Wed Dec  3 13:20:36 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Wed, 03 Dec 2025 22:20:36 +0100
Subject: [PATCH v5 0/5] Add support for Ezurio MediaTek platforms
Message-ID: <20251203-review-v5-0-b26d5512c6af@gmail.com>

This series adds support for Ezurio MediaTek platforms called
"Tungsten". It includes support for MT8370-based Tungsten 510 and
MT8390-based Tungsten 700 SOMs.

Changes in v2:
- Use b4 to cc all maintainers properly
- Squashed patches 2/3 together
- Updated dts node names to be generic

Changes in v3:
- Added per-commit changelog
- Added missing Acked-by on 1st patch
- Link to v2: https://lore.kernel.org/r/20251201-review-v2-0-dc2df44eec7e at gmail.com

Changes in v4:
- Fixed remaining DTB warnings
- Link to v3: https://lore.kernel.org/r/20251201-review-v3-0-07f9af7341fd at gmail.com

Changes in v5:
- Fixed DTB per Angelo's comments
- Added a MT8188 patch for easier mmc eint interrupt change
- Link to v4: https://lore.kernel.org/r/20251202-review-v4-0-93f5cd2a0d4a at gmail.com

Regards,

Gary Bisson (5):
  dt-bindings: vendor-prefixes: Add Ezurio LLC
  dt-bindings: arm: mediatek: Add Ezurio Tungsten entries
  arm64: dts: mediatek: mt8188: switch mmc nodes to interrupts-extended
  arm64: dts: mediatek: add device tree for Tungsten 510 board
  arm64: dts: mediatek: add device tree for Tungsten 700 board

 .../devicetree/bindings/arm/mediatek.yaml     |    2 +
 .../devicetree/bindings/vendor-prefixes.yaml  |    2 +
 arch/arm64/boot/dts/mediatek/Makefile         |    2 +
 arch/arm64/boot/dts/mediatek/mt8188.dtsi      |    6 +-
 .../dts/mediatek/mt8370-tungsten-smarc.dts    |   14 +
 .../dts/mediatek/mt8390-tungsten-smarc.dts    |   22 +
 .../dts/mediatek/mt8390-tungsten-smarc.dtsi   | 1489 +++++++++++++++++
 7 files changed, 1534 insertions(+), 3 deletions(-)
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtsi

--
2.43.0

---
To: Rob Herring <robh at kernel.org>
To: Krzysztof Kozlowski <krzk+dt at kernel.org>
To: Conor Dooley <conor+dt at kernel.org>
To: Matthias Brugger <matthias.bgg at gmail.com>
To: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
To: Sean Wang <sean.wang at mediatek.com>
Cc: devicetree at vger.kernel.org
Cc: linux-kernel at vger.kernel.org
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-mediatek at lists.infradead.org

---
Gary Bisson (5):
      dt-bindings: vendor-prefixes: Add Ezurio LLC
      dt-bindings: arm: mediatek: Add Ezurio Tungsten entries
      arm64: dts: mediatek: mt8188: switch mmc nodes to interrupts-extended
      arm64: dts: mediatek: add device tree for Tungsten 510 board
      arm64: dts: mediatek: add device tree for Tungsten 700 board

 .../devicetree/bindings/arm/mediatek.yaml          |    2 +
 .../devicetree/bindings/vendor-prefixes.yaml       |    2 +
 arch/arm64/boot/dts/mediatek/Makefile              |    2 +
 arch/arm64/boot/dts/mediatek/mt8188.dtsi           |    6 +-
 .../boot/dts/mediatek/mt8370-tungsten-smarc.dts    |   14 +
 .../boot/dts/mediatek/mt8390-tungsten-smarc.dts    |   22 +
 .../boot/dts/mediatek/mt8390-tungsten-smarc.dtsi   | 1489 ++++++++++++++++++++
 7 files changed, 1534 insertions(+), 3 deletions(-)
---
base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
change-id: 20251201-review-750072579991

Best regards,
-- 
Gary Bisson <bisson.gary at gmail.com>



From bisson.gary at gmail.com  Wed Dec  3 13:20:37 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Wed, 03 Dec 2025 22:20:37 +0100
Subject: [PATCH v5 1/5] dt-bindings: vendor-prefixes: Add Ezurio LLC
In-Reply-To: <20251203-review-v5-0-b26d5512c6af@gmail.com>
References: <20251203-review-v5-0-b26d5512c6af@gmail.com>
Message-ID: <20251203-review-v5-1-b26d5512c6af@gmail.com>

Ezurio is the new name of Laird Connectivity after it acquired Boundary
Devices.

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
---
Changes in v2:
- None
Changes in v3:
- Added missing Acked-by from Krzysztof
Changes in v4:
- None
Changes in v5:
- None
---
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index f1d1882009ba..e76e6c5be726 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -547,6 +547,8 @@ patternProperties:
     description: Exegin Technologies Limited
   "^ezchip,.*":
     description: EZchip Semiconductor
+  "^ezurio,.*":
+    description: Ezurio LLC
   "^facebook,.*":
     description: Facebook
   "^fairchild,.*":

-- 
2.43.0



From bisson.gary at gmail.com  Wed Dec  3 13:20:38 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Wed, 03 Dec 2025 22:20:38 +0100
Subject: [PATCH v5 2/5] dt-bindings: arm: mediatek: Add Ezurio Tungsten
 entries
In-Reply-To: <20251203-review-v5-0-b26d5512c6af@gmail.com>
References: <20251203-review-v5-0-b26d5512c6af@gmail.com>
Message-ID: <20251203-review-v5-2-b26d5512c6af@gmail.com>

Add device tree bindings support for the Ezurio Tungsten 510 (MT8370)
SMARC [1] / Ezurio Tungsten 700 (MT8390) SMARC [2] + Universal SMARC
carrier board [3].

[1] https://www.ezurio.com/product/tungsten510-smarc
[2] https://www.ezurio.com/product/tungsten700-smarc
[3] https://www.ezurio.com/system-on-module/accessories/universal-smarc-carrier

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
---
Changes in v2:
- Squashed both entries into 1 commit
Changed in v3:
- None
Changes in v4:
- None
Changes in v5:
- None
---
 Documentation/devicetree/bindings/arm/mediatek.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/mediatek.yaml b/Documentation/devicetree/bindings/arm/mediatek.yaml
index f04277873694..cffb0f6ac690 100644
--- a/Documentation/devicetree/bindings/arm/mediatek.yaml
+++ b/Documentation/devicetree/bindings/arm/mediatek.yaml
@@ -431,12 +431,14 @@ properties:
           - const: mediatek,mt8365
       - items:
           - enum:
+              - ezurio,mt8370-tungsten-smarc
               - grinn,genio-510-sbc
               - mediatek,mt8370-evk
           - const: mediatek,mt8370
           - const: mediatek,mt8188
       - items:
           - enum:
+              - ezurio,mt8390-tungsten-smarc
               - grinn,genio-700-sbc
               - mediatek,mt8390-evk
           - const: mediatek,mt8390

-- 
2.43.0



From bisson.gary at gmail.com  Wed Dec  3 13:20:39 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Wed, 03 Dec 2025 22:20:39 +0100
Subject: [PATCH v5 3/5] arm64: dts: mediatek: mt8188: switch mmc nodes to
 interrupts-extended
In-Reply-To: <20251203-review-v5-0-b26d5512c6af@gmail.com>
References: <20251203-review-v5-0-b26d5512c6af@gmail.com>
Message-ID: <20251203-review-v5-3-b26d5512c6af@gmail.com>

No functional change but will allow other dts including this one to
override the interrupts, for eint support for instance, without having
to delete the 'interrupts' property.

Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
---
 arch/arm64/boot/dts/mediatek/mt8188.dtsi | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/boot/dts/mediatek/mt8188.dtsi b/arch/arm64/boot/dts/mediatek/mt8188.dtsi
index 90c388f1890f..e3209a9a5f01 100644
--- a/arch/arm64/boot/dts/mediatek/mt8188.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8188.dtsi
@@ -1800,7 +1800,7 @@ mmc0: mmc at 11230000 {
 			compatible = "mediatek,mt8188-mmc", "mediatek,mt8183-mmc";
 			reg = <0 0x11230000 0 0x10000>,
 			      <0 0x11f50000 0 0x1000>;
-			interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH 0>;
+			interrupts-extended = <&gic GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH 0>;
 			clocks = <&topckgen CLK_TOP_MSDC50_0>,
 				 <&infracfg_ao CLK_INFRA_AO_MSDC0>,
 				 <&infracfg_ao CLK_INFRA_AO_MSDC0_SRC>,
@@ -1813,7 +1813,7 @@ mmc1: mmc at 11240000 {
 			compatible = "mediatek,mt8188-mmc", "mediatek,mt8183-mmc";
 			reg = <0 0x11240000 0 0x1000>,
 			      <0 0x11eb0000 0 0x1000>;
-			interrupts = <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH 0>;
+			interrupts-extended = <&gic GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH 0>;
 			clocks = <&topckgen CLK_TOP_MSDC30_1>,
 				 <&infracfg_ao CLK_INFRA_AO_MSDC1>,
 				 <&infracfg_ao CLK_INFRA_AO_MSDC1_SRC>;
@@ -1827,7 +1827,7 @@ mmc2: mmc at 11250000 {
 			compatible = "mediatek,mt8188-mmc", "mediatek,mt8183-mmc";
 			reg = <0 0x11250000 0 0x1000>,
 			      <0 0x11e60000 0 0x1000>;
-			interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH 0>;
+			interrupts-extended = <&gic GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH 0>;
 			clocks = <&topckgen CLK_TOP_MSDC30_2>,
 				 <&infracfg_ao CLK_INFRA_AO_MSDC2>,
 				 <&infracfg_ao CLK_INFRA_AO_MSDC30_2>;

-- 
2.43.0



From bisson.gary at gmail.com  Wed Dec  3 13:20:40 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Wed, 03 Dec 2025 22:20:40 +0100
Subject: [PATCH v5 4/5] arm64: dts: mediatek: add device tree for Tungsten
 510 board
In-Reply-To: <20251203-review-v5-0-b26d5512c6af@gmail.com>
References: <20251203-review-v5-0-b26d5512c6af@gmail.com>
Message-ID: <20251203-review-v5-4-b26d5512c6af@gmail.com>

Add device tree to support Ezurio Tungsten 510 (MT8370) SMARC SOM [1] +
Universal SMARC carrier board [2].
It includes support for the MIPI-DSI BD070LIC3 display which uses the
Tianma TM070JDHG30 panel + TI SN65DSI84 MIPI-DSI to LVDS bridge [3].

[1] https://www.ezurio.com/product/tungsten510-smarc
[2] https://www.ezurio.com/system-on-module/accessories/universal-smarc-carrier
[3] https://www.ezurio.com/product/bd070lic3-7-touchscreen-display

Signed-off-by: Gary Bisson <bisson.gary at gmail.com>

---
Changes in v2:
- Updated nodes to be generic (pmic, i2c, usb-typec)
Changed in v3:
- None
Changed in v4:
- Fixed remaining DTB warnings
Changed in v5:
- Fixed DTB issues per Angelo's feedback
- Updated dtsi name to remove wildcard
---
 arch/arm64/boot/dts/mediatek/Makefile              |    1 +
 .../boot/dts/mediatek/mt8370-tungsten-smarc.dts    |   14 +
 .../boot/dts/mediatek/mt8390-tungsten-smarc.dtsi   | 1489 ++++++++++++++++++++
 3 files changed, 1504 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile
index a4df4c21399e..30d169a31b10 100644
--- a/arch/arm64/boot/dts/mediatek/Makefile
+++ b/arch/arm64/boot/dts/mediatek/Makefile
@@ -99,6 +99,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8195-demo.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8195-evb.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8365-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-genio-510-evk.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-tungsten-smarc.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-genio-1200-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-genio-700-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-kontron-3-5-sbc-i1200.dtb
diff --git a/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts b/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts
new file mode 100644
index 000000000000..4c3a7c4579c8
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2025 Ezurio LLC
+ * Author: Gary Bisson <bisson.gary at gmail.com>
+ */
+/dts-v1/;
+#include "mt8370.dtsi"
+#include "mt8390-tungsten-smarc.dtsi"
+
+/ {
+	model = "Ezurio Tungsten510 SMARC (MT8370)";
+	compatible = "ezurio,mt8370-tungsten-smarc", "mediatek,mt8370",
+		     "mediatek,mt8188";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtsi b/arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtsi
new file mode 100644
index 000000000000..40b381d4cc35
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtsi
@@ -0,0 +1,1489 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2025 Ezurio LLC
+ * Author: Gary Bisson <bisson.gary at gmail.com>
+ */
+
+#include "mt6359.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/net/microchip-lan78xx.h>
+#include <dt-bindings/pinctrl/mediatek,mt8188-pinfunc.h>
+#include <dt-bindings/spmi/spmi.h>
+#include <dt-bindings/usb/pd.h>
+
+/ {
+	aliases {
+		dsi0 = &disp_dsi0;
+		ethernet0 = &eth;
+		i2c0 = &i2c0;
+		i2c1 = &i2c1;
+		i2c2 = &i2c2;
+		i2c3 = &i2c3;
+		i2c4 = &i2c4;
+		i2c5 = &i2c5;
+		i2c6 = &i2c6;
+		mmc0 = &mmc0;
+		mmc1 = &mmc1;
+		mmc2 = &mmc2;
+		rtc0 = &rv3028;
+		rtc1 = &mt6359rtc;
+		serial0 = &uart0;
+	};
+
+	backlight_lcd0: backlight-lcd0 {
+		compatible = "pwm-backlight";
+		brightness-levels = <0 1023>;
+		default-brightness-level = <768>;
+		num-interpolated-steps = <1023>;
+		enable-gpios = <&pio 30 GPIO_ACTIVE_HIGH>;
+		pwms = <&disp_pwm0 0 30000>;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	firmware {
+		optee {
+			compatible = "linaro,optee-tz";
+			method = "smc";
+		};
+	};
+
+	memory at 40000000 {
+		device_type = "memory";
+		reg = <0 0x40000000 0x1 0x00000000>;
+	};
+
+	panel-dsi0 {
+		compatible = "tianma,tm070jdhg30";
+		backlight = <&backlight_lcd0>;
+		power-supply = <&reg_5v>;
+
+		port {
+			dsi0_panel_in: endpoint {
+				remote-endpoint = <&sn65dsi84_bridge_out>;
+			};
+		};
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		/*
+		 * 12 MiB reserved for OP-TEE (BL32)
+		 * +-----------------------+ 0x43e0_0000
+		 * |      SHMEM 2MiB       |
+		 * +-----------------------+ 0x43c0_0000
+		 * |        | TA_RAM  8MiB |
+		 * + TZDRAM +--------------+ 0x4340_0000
+		 * |        | TEE_RAM 2MiB |
+		 * +-----------------------+ 0x4320_0000
+		 */
+		optee_reserved: optee at 43200000 {
+			no-map;
+			reg = <0 0x43200000 0 0x00c00000>;
+		};
+
+		scp_mem: memory at 50000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x50000000 0 0x2900000>;
+			no-map;
+		};
+
+		/* 2 MiB reserved for ARM Trusted Firmware (BL31) */
+		bl31_secmon_reserved: memory at 54600000 {
+			no-map;
+			reg = <0 0x54600000 0x0 0x200000>;
+		};
+
+		apu_mem: memory at 55000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x55000000 0 0x1400000>; /* 20 MB */
+		};
+
+		vpu_mem: memory at 57000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x57000000 0 0x1400000>; /* 20 MB */
+		};
+
+		adsp_mem: memory at 60000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x60000000 0 0xf00000>;
+			no-map;
+		};
+
+		afe_dma_mem: memory at 60f00000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x60f00000 0 0x100000>;
+			no-map;
+		};
+
+		adsp_dma_mem: memory at 61000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x61000000 0 0x100000>;
+			no-map;
+		};
+	};
+
+	regulator-efuse {
+		compatible = "regulator-output";
+		vout-supply = <&mt6359_vefuse_ldo_reg>;
+	};
+
+	reg_1v8: regulator-1v8 {
+		compatible = "regulator-fixed";
+		regulator-name = "reg_1v8";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-always-on;
+	};
+
+	reg_3v3: regulator-3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "reg_3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	reg_5v: regulator-5v {
+		compatible = "regulator-fixed";
+		regulator-name = "reg_5v";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+	};
+
+	sdcard_en_3v3: regulator-sdcard-en {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-name = "sdcard_en_3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&pio 111 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	usb_p0_vbus: regulator-usb-p0-vbus {
+		compatible = "regulator-fixed";
+		regulator-name = "vbus_p0";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&pio 84 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	usb_p1_vbus: regulator-usb-p1-vbus {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&usb1_hub_pins>;
+		regulator-name = "vbus_p1";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		gpio = <&pio 147 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	usb_p2_vbus: regulator-usb-p2-vbus {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&usb2_eth_pins>;
+		regulator-name = "vbus_p2";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		gpio = <&pio 80 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	wifi_pwrseq: wifi-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		pinctrl-names = "default";
+		pinctrl-0 = <&wifi_pwrseq_pins>;
+		post-power-on-delay-ms = <200>;
+		reset-gpios = <&pio 89 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&adsp {
+	memory-region = <&adsp_dma_mem>, <&adsp_mem>;
+	status = "okay";
+};
+
+&afe {
+	memory-region = <&afe_dma_mem>;
+	status = "okay";
+};
+
+&cpu0 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};
+
+&cpu1 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};
+
+&cpu2 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};
+
+&cpu3 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};
+
+&cpu6 {
+	cpu-supply = <&mt6315_6_vbuck1>;
+};
+
+&cpu7 {
+	cpu-supply = <&mt6315_6_vbuck1>;
+};
+
+&disp_pwm0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&disp_pwm0_pins>;
+	status = "okay";
+};
+
+&disp_dsi0 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			reg = <0>;
+			dsi0_in: endpoint {
+				remote-endpoint = <&dither0_out>;
+			};
+		};
+
+		port at 1 {
+			reg = <1>;
+			dsi0_out: endpoint {
+				remote-endpoint = <&sn65dsi84_bridge_in>;
+			};
+		};
+	};
+};
+
+&dither0_in {
+	remote-endpoint = <&postmask0_out>;
+};
+
+&dither0_out {
+	remote-endpoint = <&dsi0_in>;
+};
+
+&eth {
+	phy-mode ="rgmii-id";
+	phy-handle = <&ethernet_phy0>;
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&eth_default_pins>;
+	pinctrl-1 = <&eth_sleep_pins>;
+	mediatek,mac-wol;
+	snps,reset-gpio = <&pio 27 GPIO_ACTIVE_LOW>;
+	snps,reset-active-low;
+	snps,reset-delays-us = <0 11000 1000>;
+	status = "okay";
+};
+
+&eth_mdio {
+	ethernet_phy0: ethernet-phy at 7 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <0x7>;
+		interrupts-extended = <&pio 148 IRQ_TYPE_LEVEL_LOW>;
+	};
+};
+
+&gamma0_out {
+	remote-endpoint = <&postmask0_in>;
+};
+
+&gpu {
+	mali-supply = <&mt6359_vproc2_buck_reg>;
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c0_pins>;
+	clock-frequency = <100000>;
+	status = "okay";
+
+	i2c-mux at 73 {
+		compatible = "nxp,pca9546";
+		reg = <0x73>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&i2c0_mux_pins>;
+		reset-gpios = <&pio 6 GPIO_ACTIVE_LOW>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		i2c_mux_gp_0: i2c at 0 {
+			reg = <0>;
+			clock-frequency = <100000>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_gp_1: i2c at 1 {
+			reg = <1>;
+			clock-frequency = <100000>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_gp_2: i2c at 2 {
+			reg = <2>;
+			clock-frequency = <100000>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_gp_3: i2c at 3 {
+			reg = <3>;
+			clock-frequency = <100000>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	clock-frequency = <400000>;
+	status = "okay";
+};
+
+&i2c2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_pins>;
+	clock-frequency = <400000>;
+	status = "okay";
+
+	i2c-mux at 73 {
+		compatible = "nxp,pca9546";
+		reg = <0x73>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&i2c_mux_smarc_lcd_pins>;
+		reset-gpios = <&pio 5 GPIO_ACTIVE_LOW>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		i2c_mux_lcd_0: i2c at 0 {
+			reg = <0>;
+			clock-frequency = <100000>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_lcd_1: i2c at 1 {
+			reg = <1>;
+			clock-frequency = <100000>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_lcd_2: i2c at 2 {
+			reg = <2>;
+			clock-frequency = <100000>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c_mux_lcd_3: i2c at 3 {
+			reg = <3>;
+			clock-frequency = <100000>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+};
+
+&i2c3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c3_pins>;
+	clock-frequency = <400000>;
+	status = "okay";
+};
+
+&i2c4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c4_pins>;
+	clock-frequency = <400000>;
+	status = "okay";
+};
+
+&i2c_mux_gp_0 {
+	rv3028: rtc at 52 {
+		compatible = "microcrystal,rv3028";
+		reg = <0x52>;
+		interrupts-extended = <&pio 42 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&rv3028_pins>;
+		#clock-cells = <0>;
+		wakeup-source;
+	};
+};
+
+&i2c_mux_gp_1 {
+	usb-typec at 60 {
+		compatible = "ti,hd3ss3220";
+		reg = <0x60>;
+		interrupts-extended = <&pio 45 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&hd3ss3220_pins>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+				hd3ss3220_in_ep: endpoint {
+					remote-endpoint = <&ss_ep>;
+				};
+			};
+
+			port at 1 {
+				reg = <1>;
+				hd3ss3220_out_ep: endpoint {
+					remote-endpoint = <&usb_role_switch>;
+				};
+			};
+		};
+	};
+};
+
+&i2c_mux_gp_2 {
+	codec at 1a {
+		compatible = "wlf,wm8962";
+		reg = <0x1a>;
+		clocks = <&topckgen CLK_TOP_I2SO1>;
+		AVDD-supply = <&reg_1v8>;
+		CPVDD-supply = <&reg_1v8>;
+		DBVDD-supply = <&reg_3v3>;
+		DCVDD-supply = <&reg_1v8>;
+		MICVDD-supply = <&reg_3v3>;
+		PLLVDD-supply = <&reg_1v8>;
+		SPKVDD1-supply = <&reg_5v>;
+		SPKVDD2-supply = <&reg_5v>;
+		gpio-cfg = <
+			0x0000 /* n/c */
+			0x0000 /* gpio2: */
+			0x0000 /* gpio3: */
+			0x0000 /* n/c */
+			0x8081 /* gpio5:HP detect */
+			0x8095 /* gpio6:Mic detect */
+		>;
+	};
+};
+
+&i2c_mux_lcd_2 {
+	bridge at 2c {
+		compatible = "ti,sn65dsi84";
+		reg = <0x2c>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&dsi0_sn65dsi84_pins>;
+		enable-gpios = <&pio 25 GPIO_ACTIVE_HIGH>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+
+				sn65dsi84_bridge_in: endpoint {
+					remote-endpoint = <&dsi0_out>;
+					data-lanes = <1 2 3 4>;
+				};
+			};
+
+			port at 2 {
+				reg = <2>;
+
+				sn65dsi84_bridge_out: endpoint {
+					remote-endpoint = <&dsi0_panel_in>;
+				};
+			};
+		};
+	};
+
+	touchscren at 5d {
+		compatible = "goodix,gt911";
+		reg = <0x5d>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&ts_dsi0_goodix_pins>;
+		interrupts-extended = <&pio 146 IRQ_TYPE_LEVEL_HIGH>;
+		irq-gpios = <&pio 146 GPIO_ACTIVE_HIGH>;
+		reset-gpios = <&pio 7 GPIO_ACTIVE_HIGH>;
+	};
+};
+
+&mfg0 {
+	domain-supply = <&mt6359_vproc2_buck_reg>;
+};
+
+&mfg1 {
+	domain-supply = <&mt6359_vsram_others_ldo_reg>;
+};
+
+&mmc0 {
+	bus-width = <8>;
+	cap-mmc-highspeed;
+	cap-mmc-hw-reset;
+	hs400-ds-delay = <0x1481b>;
+	max-frequency = <200000000>;
+	mmc-hs200-1_8v;
+	mmc-hs400-1_8v;
+	non-removable;
+	no-sd;
+	no-sdio;
+	supports-cqe;
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc0_default_pins>;
+	pinctrl-1 = <&mmc0_uhs_pins>;
+	vmmc-supply = <&mt6359_vemc_1_ldo_reg>;
+	vqmmc-supply = <&mt6359_vufs_ldo_reg>;
+	status = "okay";
+};
+
+&mmc1 {
+	bus-width = <4>;
+	cap-sd-highspeed;
+	max-frequency = <200000000>;
+	sd-uhs-sdr104;
+	sd-uhs-sdr50;
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc1_default_pins>;
+	pinctrl-1 = <&mmc1_uhs_pins>;
+	cd-gpios = <&pio 2 GPIO_ACTIVE_LOW>;
+	vqmmc-supply = <&mt6359_vsim1_ldo_reg>;
+	vmmc-supply = <&sdcard_en_3v3>;
+	status = "okay";
+};
+
+&mmc2 {
+	bus-width = <4>;
+	cap-sd-highspeed;
+	cap-sdio-irq;
+	keep-power-in-suspend;
+	max-frequency = <200000000>;
+	no-mmc;
+	non-removable;
+	no-sd;
+	sd-uhs-sdr104;
+	wakeup-source;
+	pinctrl-names = "default", "state_uhs", "state_eint";
+	pinctrl-0 = <&mmc2_default_pins>;
+	pinctrl-1 = <&mmc2_uhs_pins>;
+	pinctrl-2 = <&mmc2_eint_pins>;
+	interrupt-names = "msdc", "sdio_wakeup";
+	interrupts-extended = <&gic GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH 0>,
+			      <&pio 172 IRQ_TYPE_LEVEL_LOW>;
+	vmmc-supply = <&mt6359_vcn33_2_bt_ldo_reg>;
+	vqmmc-supply = <&mt6359_vcn18_ldo_reg>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	status = "okay";
+};
+
+&mipi_tx_config0 {
+	status = "okay";
+};
+
+&mt6359codec {
+	mediatek,mic-type-0 = <1>;
+	mediatek,mic-type-1 = <3>;
+};
+
+&mt6359_vbbck_ldo_reg {
+	regulator-always-on;
+};
+
+&mt6359_vcn18_ldo_reg {
+	regulator-name = "vcn18_pmu";
+	regulator-always-on;
+	regulator-boot-on;
+};
+
+&mt6359_vcn33_1_bt_ldo_reg {
+	regulator-name = "vcn33_1_pmu";
+	regulator-always-on;
+};
+
+&mt6359_vcn33_2_bt_ldo_reg {
+	regulator-name = "vcn33_2_pmu";
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-always-on;
+	regulator-boot-on;
+};
+
+&mt6359_vcore_buck_reg {
+	regulator-name = "dvdd_proc_l";
+	regulator-always-on;
+};
+
+&mt6359_vemc_1_ldo_reg {
+	regulator-always-on;
+};
+
+&mt6359_vgpu11_buck_reg {
+	regulator-name = "dvdd_core";
+	regulator-always-on;
+};
+
+&mt6359_vmodem_buck_reg {
+	regulator-always-on;
+};
+
+&mt6359_vpa_buck_reg {
+	regulator-name = "vpa_pmu";
+	regulator-always-on;
+};
+
+&mt6359_vproc2_buck_reg {
+	/* The name "vgpu" is required by mtk-regulator-coupler */
+	regulator-name = "vgpu";
+	regulator-min-microvolt = <550000>;
+	regulator-max-microvolt = <800000>;
+	regulator-coupled-with = <&mt6359_vsram_others_ldo_reg>;
+	regulator-coupled-max-spread = <225000>;
+};
+
+&mt6359_vs2_buck_reg {
+	regulator-min-microvolt = <1600000>;
+	regulator-boot-on;
+};
+
+&mt6359_vpu_buck_reg {
+	regulator-name = "dvdd_adsp";
+	regulator-always-on;
+};
+
+&mt6359_vrf12_ldo_reg {
+	regulator-name = "va12_abb2_pmu";
+	regulator-always-on;
+};
+
+&mt6359_vsram_md_ldo_reg {
+	regulator-always-on;
+};
+
+&mt6359_vsram_others_ldo_reg {
+	/* The name "vsram_gpu" is required by mtk-regulator-coupler */
+	regulator-name = "vsram_gpu";
+	regulator-min-microvolt = <750000>;
+	regulator-max-microvolt = <800000>;
+	regulator-coupled-with = <&mt6359_vproc2_buck_reg>;
+	regulator-coupled-max-spread = <225000>;
+};
+
+&mt6359_vsim1_ldo_reg {
+	regulator-name = "vsim1_pmu";
+	regulator-max-microvolt = <1800000>;
+	regulator-enable-ramp-delay = <480>;
+};
+
+&mt6359_vufs_ldo_reg {
+	regulator-name = "vufs18_pmu";
+	regulator-always-on;
+};
+
+&ovl0_in {
+	remote-endpoint = <&vdosys0_ep_main>;
+};
+
+&pcie {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie_default_pins>;
+	status = "okay";
+};
+
+&pciephy {
+	status = "okay";
+};
+
+&pmic {
+	interrupts-extended = <&pio 222 IRQ_TYPE_LEVEL_HIGH>;
+
+	keys {
+		compatible = "mediatek,mt6359-keys";
+		mediatek,long-press-mode = <1>;
+		power-off-time-sec = <0>;
+
+		power-key {
+			linux,keycodes = <KEY_POWER>;
+			wakeup-source;
+		};
+	};
+};
+
+&postmask0_in {
+	remote-endpoint = <&gamma0_out>;
+};
+
+&postmask0_out {
+	remote-endpoint = <&dither0_in>;
+};
+
+&scp_cluster {
+	status = "okay";
+};
+
+&scp_c0 {
+	memory-region = <&scp_mem>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-0 = <&spi0_pins>;
+	pinctrl-names = "default";
+	mediatek,pad-select = <0>;
+	status = "okay";
+};
+
+&spi1 {
+	pinctrl-0 = <&spi1_pins>;
+	pinctrl-names = "default";
+	mediatek,pad-select = <0>;
+	status = "okay";
+};
+
+&spmi {
+	#address-cells = <2>;
+	#size-cells = <0>;
+
+	mt6315_6: pmic at 6 {
+		compatible = "mediatek,mt6315-regulator";
+		reg = <0x6 SPMI_USID>;
+
+		regulators {
+			mt6315_6_vbuck1: vbuck1 {
+				regulator-name = "vbuck1";
+				regulator-min-microvolt = <300000>;
+				regulator-max-microvolt = <1193750>;
+				regulator-enable-ramp-delay = <256>;
+				regulator-allowed-modes = <0 1 2>;
+				regulator-always-on;
+			};
+
+			mt6315_6_vbuck3: vbuck3 {
+				regulator-name = "vbuck3";
+				regulator-min-microvolt = <300000>;
+				regulator-max-microvolt = <1193750>;
+				regulator-enable-ramp-delay = <256>;
+				regulator-allowed-modes = <0 1 2>;
+				regulator-always-on;
+			};
+
+			mt6315_6_vbuck4: vbuck4 {
+				regulator-name = "vbuck4";
+				regulator-min-microvolt = <1193750>;
+				regulator-max-microvolt = <1193750>;
+				regulator-enable-ramp-delay = <256>;
+				regulator-allowed-modes = <0 1 2>;
+				regulator-always-on;
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1193750>;
+				};
+			};
+		};
+	};
+};
+
+&uart0 {
+	pinctrl-0 = <&uart0_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-0 = <&uart1_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-0 = <&uart2_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&ssusb0 {
+	dr_mode = "otg";
+	maximum-speed = "high-speed";
+	usb-role-switch;
+	wakeup-source;
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	pinctrl-0 = <&usbotg_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	connector {
+		compatible = "usb-c-connector";
+		label = "USB-C";
+		data-role = "dual";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+				hs_ep: endpoint {
+					remote-endpoint = <&usb_hs_ep>;
+				};
+			};
+
+			port at 1 {
+				reg = <1>;
+				ss_ep: endpoint {
+					remote-endpoint = <&hd3ss3220_in_ep>;
+				};
+			};
+		};
+	};
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			reg = <0>;
+			usb_hs_ep: endpoint {
+				remote-endpoint = <&hs_ep>;
+			};
+		};
+
+		port at 1 {
+			reg = <1>;
+			usb_role_switch: endpoint {
+				remote-endpoint = <&hd3ss3220_out_ep>;
+			};
+		};
+	};
+};
+
+&u2port0 {
+	status = "okay";
+};
+
+&u3phy0 {
+	status = "okay";
+};
+
+&xhci0 {
+	vbus-supply = <&usb_p0_vbus>;
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	status = "okay";
+};
+
+&ssusb1 {
+	dr_mode = "host";
+	wakeup-source;
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	pinctrl-0 = <&usb1_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&u2port1 {
+	status = "okay";
+};
+
+&u3port1 {
+	status = "okay";
+};
+
+&u3phy1 {
+	status = "okay";
+};
+
+&xhci1 {
+	vbus-supply = <&usb_p1_vbus>;
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	status = "okay";
+};
+
+&ssusb2 {
+	dr_mode = "host";
+	maximum-speed = "high-speed";
+	wakeup-source;
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	status = "okay";
+};
+
+&u2port2 {
+	status = "okay";
+};
+
+&u3phy2 {
+	status = "okay";
+};
+
+&xhci2 {
+	vbus-supply = <&usb_p2_vbus>;
+	vusb33-supply = <&mt6359_vusb_ldo_reg>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+
+	ethernet at 1 {
+		compatible = "usb424,7850";
+		reg = <1>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		mdio {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			ethernet-phy at 1 {
+				reg = <1>;
+				microchip,led-modes = <
+					LAN78XX_LINK_1000_ACTIVITY
+					LAN78XX_LINK_10_ACTIVITY
+					LAN78XX_LINK_10_100_ACTIVITY
+					LAN78XX_LINK_ACTIVITY
+				>;
+			};
+		};
+	};
+};
+
+&vdosys0 {
+	port {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		vdosys0_ep_main: endpoint at 0 {
+			reg = <0>;
+			remote-endpoint = <&ovl0_in>;
+		};
+	};
+};
+
+&watchdog {
+	pinctrl-names = "default";
+	pinctrl-0 = <&watchdog_pins>;
+};
+
+&pio {
+	audio_pins: audio-pins {
+		pins-aud-pmic {
+			pinmux = <PINMUX_GPIO101__FUNC_O_AUD_CLK_MOSI
+				  PINMUX_GPIO102__FUNC_O_AUD_SYNC_MOSI
+				  PINMUX_GPIO103__FUNC_O_AUD_DAT_MOSI0
+				  PINMUX_GPIO104__FUNC_O_AUD_DAT_MOSI1
+				  PINMUX_GPIO105__FUNC_I0_AUD_DAT_MISO0
+				  PINMUX_GPIO106__FUNC_I0_AUD_DAT_MISO1>;
+		};
+
+		pins-pcm-wifi {
+			pinmux = <PINMUX_GPIO121__FUNC_B0_PCM_CLK
+				  PINMUX_GPIO122__FUNC_B0_PCM_SYNC
+				  PINMUX_GPIO123__FUNC_O_PCM_DO
+				  PINMUX_GPIO124__FUNC_I0_PCM_DI>;
+		};
+
+		pins-i2s {
+			pinmux = <PINMUX_GPIO119__FUNC_O_I2SO1_MCK
+				  PINMUX_GPIO112__FUNC_O_I2SO1_WS
+				  PINMUX_GPIO120__FUNC_O_I2SO1_BCK
+				  PINMUX_GPIO113__FUNC_O_I2SO1_D0
+				  PINMUX_GPIO110__FUNC_I0_I2SIN_D0>;
+		};
+	};
+
+	disp_pwm0_pins: disp-pwm0-pins {
+		pins {
+			pinmux = <PINMUX_GPIO29__FUNC_O_DISP_PWM0>;
+			bias-pull-down;
+		};
+	};
+
+	dsi0_sn65dsi84_pins: dsi0-sn65dsi84-pins {
+		pins-irq {
+			pinmux = <PINMUX_GPIO128__FUNC_B_GPIO128>;
+			bias-pull-down;
+			input-enable;
+		};
+
+		pins-enable {
+			pinmux = <PINMUX_GPIO25__FUNC_B_GPIO25>;
+			bias-pull-down;
+		};
+	};
+
+	eth_default_pins: eth-default-pins {
+		pins-txd {
+			pinmux = <PINMUX_GPIO131__FUNC_O_GBE_TXD3>,
+				 <PINMUX_GPIO132__FUNC_O_GBE_TXD2>,
+				 <PINMUX_GPIO133__FUNC_O_GBE_TXD1>,
+				 <PINMUX_GPIO134__FUNC_O_GBE_TXD0>;
+			drive-strength = <8>;
+		};
+		pins-cc {
+			pinmux = <PINMUX_GPIO139__FUNC_B0_GBE_TXC>,
+				 <PINMUX_GPIO142__FUNC_O_GBE_TXEN>,
+				 <PINMUX_GPIO141__FUNC_I0_GBE_RXDV>;
+			drive-strength = <8>;
+		};
+		pins-rxd {
+			pinmux = <PINMUX_GPIO135__FUNC_I0_GBE_RXD3>,
+				 <PINMUX_GPIO136__FUNC_I0_GBE_RXD2>,
+				 <PINMUX_GPIO137__FUNC_I0_GBE_RXD1>,
+				 <PINMUX_GPIO138__FUNC_I0_GBE_RXD0>,
+				 <PINMUX_GPIO140__FUNC_I0_GBE_RXC>;
+			drive-strength = <8>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
+		};
+		pins-mdio {
+			pinmux = <PINMUX_GPIO143__FUNC_O_GBE_MDC>,
+				 <PINMUX_GPIO144__FUNC_B1_GBE_MDIO>;
+			drive-strength = <8>;
+			input-enable;
+		};
+		pins-power {
+			pinmux = <PINMUX_GPIO27__FUNC_B_GPIO27>; /* GP_EQOS_RESET */
+			output-high;
+		};
+		pins-intr {
+			pinmux = <PINMUX_GPIO148__FUNC_B_GPIO148>; /* GPIRQ_EQOS_PHY */
+			bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
+			input-enable;
+		};
+	};
+
+	eth_sleep_pins: eth-sleep-pins {
+		pins-txd {
+			pinmux = <PINMUX_GPIO131__FUNC_B_GPIO131>,
+				 <PINMUX_GPIO132__FUNC_B_GPIO132>,
+				 <PINMUX_GPIO133__FUNC_B_GPIO133>,
+				 <PINMUX_GPIO134__FUNC_B_GPIO134>;
+		};
+		pins-cc {
+			pinmux = <PINMUX_GPIO139__FUNC_B_GPIO139>,
+				 <PINMUX_GPIO142__FUNC_B_GPIO142>,
+				 <PINMUX_GPIO141__FUNC_B_GPIO141>,
+				 <PINMUX_GPIO140__FUNC_B_GPIO140>;
+		};
+		pins-rxd {
+			pinmux = <PINMUX_GPIO135__FUNC_B_GPIO135>,
+				 <PINMUX_GPIO136__FUNC_B_GPIO136>,
+				 <PINMUX_GPIO137__FUNC_B_GPIO137>,
+				 <PINMUX_GPIO138__FUNC_B_GPIO138>;
+		};
+		pins-mdio {
+			pinmux = <PINMUX_GPIO143__FUNC_B_GPIO143>,
+				 <PINMUX_GPIO144__FUNC_B_GPIO144>;
+			input-disable;
+			bias-disable;
+		};
+	};
+
+	gpio_keys_pins: gpio-keys-pins {
+		pins-keys {
+			pinmux = <PINMUX_GPIO129__FUNC_B_GPIO129>,
+				 <PINMUX_GPIO65__FUNC_B_GPIO65>,
+				 <PINMUX_GPIO66__FUNC_B_GPIO66>;
+			bias-pull-up;
+		};
+	};
+
+	hd3ss3220_pins: hd3ss3320-pins {
+		pins-irq {
+			pinmux = <PINMUX_GPIO45__FUNC_B_GPIO45>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+			input-enable;
+		};
+	};
+
+	hdmi_vreg_pins: hdmi-vreg-pins {
+		pins-pwr {
+			pinmux = <PINMUX_GPIO50__FUNC_O_HDMITX20_PWR5V>;
+			bias-disable;
+		};
+	};
+
+	hdmi_pins: hdmi-pins {
+		pins-hotplug {
+			pinmux = <PINMUX_GPIO51__FUNC_I0_HDMITX20_HTPLG>;
+			bias-pull-down;
+		};
+
+		pins-cec {
+			pinmux = <PINMUX_GPIO52__FUNC_B1_HDMITX20_CEC>;
+			bias-disable;
+		};
+
+		pins-ddc {
+			pinmux = <PINMUX_GPIO53__FUNC_B1_HDMITX20_SCL>,
+				 <PINMUX_GPIO54__FUNC_B1_HDMITX20_SDA>;
+			drive-strength = <10>;
+		};
+	};
+
+	i2c0_pins: i2c0-pins {
+		pins-bus {
+			pinmux = <PINMUX_GPIO56__FUNC_B1_SDA0>,
+				 <PINMUX_GPIO55__FUNC_B1_SCL0>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c0_mux_pins: i2c0-mux-pins {
+		pins-reset {
+			pinmux = <PINMUX_GPIO6__FUNC_B_GPIO6>;
+			bias-pull-up;
+		};
+	};
+
+	i2c1_pins: i2c1-pins {
+		pins-bus {
+			pinmux = <PINMUX_GPIO58__FUNC_B1_SDA1>,
+				 <PINMUX_GPIO57__FUNC_B1_SCL1>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c2_pins: i2c2-pins {
+		pins-bus {
+			pinmux = <PINMUX_GPIO60__FUNC_B1_SDA2>,
+				 <PINMUX_GPIO59__FUNC_B1_SCL2>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c3_pins: i2c3-pins {
+		pins-bus {
+			pinmux = <PINMUX_GPIO62__FUNC_B1_SDA3>,
+				 <PINMUX_GPIO61__FUNC_B1_SCL3>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c4_pins: i2c4-pins {
+		pins-bus {
+			pinmux = <PINMUX_GPIO64__FUNC_B1_SDA4>,
+				 <PINMUX_GPIO63__FUNC_B1_SCL4>;
+			bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+			drive-strength-microamp = <1000>;
+		};
+	};
+
+	i2c_mux_smarc_lcd_pins: i2c-mux-smarc-lcd-pins {
+		pins-reset {
+			pinmux = <PINMUX_GPIO5__FUNC_B_GPIO5>;
+			bias-pull-down;
+		};
+	};
+
+	mmc0_default_pins: mmc0-default-pins {
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO161__FUNC_B1_MSDC0_DAT0>,
+				 <PINMUX_GPIO160__FUNC_B1_MSDC0_DAT1>,
+				 <PINMUX_GPIO159__FUNC_B1_MSDC0_DAT2>,
+				 <PINMUX_GPIO158__FUNC_B1_MSDC0_DAT3>,
+				 <PINMUX_GPIO154__FUNC_B1_MSDC0_DAT4>,
+				 <PINMUX_GPIO153__FUNC_B1_MSDC0_DAT5>,
+				 <PINMUX_GPIO152__FUNC_B1_MSDC0_DAT6>,
+				 <PINMUX_GPIO151__FUNC_B1_MSDC0_DAT7>,
+				 <PINMUX_GPIO156__FUNC_B1_MSDC0_CMD>;
+			input-enable;
+			drive-strength = <6>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins-clk {
+			pinmux = <PINMUX_GPIO157__FUNC_B1_MSDC0_CLK>;
+			drive-strength = <6>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-rst {
+			pinmux = <PINMUX_GPIO155__FUNC_O_MSDC0_RSTB>;
+			drive-strength = <6>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+
+	mmc0_uhs_pins: mmc0-uhs-pins {
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO161__FUNC_B1_MSDC0_DAT0>,
+				 <PINMUX_GPIO160__FUNC_B1_MSDC0_DAT1>,
+				 <PINMUX_GPIO159__FUNC_B1_MSDC0_DAT2>,
+				 <PINMUX_GPIO158__FUNC_B1_MSDC0_DAT3>,
+				 <PINMUX_GPIO154__FUNC_B1_MSDC0_DAT4>,
+				 <PINMUX_GPIO153__FUNC_B1_MSDC0_DAT5>,
+				 <PINMUX_GPIO152__FUNC_B1_MSDC0_DAT6>,
+				 <PINMUX_GPIO151__FUNC_B1_MSDC0_DAT7>,
+				 <PINMUX_GPIO156__FUNC_B1_MSDC0_CMD>;
+			input-enable;
+			drive-strength = <8>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins-clk {
+			pinmux = <PINMUX_GPIO157__FUNC_B1_MSDC0_CLK>;
+			drive-strength = <8>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-ds {
+			pinmux = <PINMUX_GPIO162__FUNC_B0_MSDC0_DSL>;
+			drive-strength = <8>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-rst {
+			pinmux = <PINMUX_GPIO155__FUNC_O_MSDC0_RSTB>;
+			drive-strength = <8>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+
+	mmc1_default_pins: mmc1-default-pins {
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO163__FUNC_B1_MSDC1_CMD>,
+				 <PINMUX_GPIO165__FUNC_B1_MSDC1_DAT0>,
+				 <PINMUX_GPIO166__FUNC_B1_MSDC1_DAT1>,
+				 <PINMUX_GPIO167__FUNC_B1_MSDC1_DAT2>,
+				 <PINMUX_GPIO168__FUNC_B1_MSDC1_DAT3>;
+			input-enable;
+			drive-strength = <6>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins-pwr {
+			pinmux = <PINMUX_GPIO111__FUNC_B_GPIO111>;
+			bias-pull-down;
+		};
+
+		pins-pullup {
+			pinmux = <PINMUX_GPIO11__FUNC_B_GPIO11>;
+			bias-pull-up;
+		};
+
+		pins-clk {
+			pinmux = <PINMUX_GPIO164__FUNC_B1_MSDC1_CLK>;
+			drive-strength = <6>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-insert {
+			pinmux = <PINMUX_GPIO2__FUNC_B_GPIO2>;
+			bias-pull-up;
+		};
+	};
+
+	mmc1_uhs_pins: mmc1-uhs-pins {
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO163__FUNC_B1_MSDC1_CMD>,
+				 <PINMUX_GPIO165__FUNC_B1_MSDC1_DAT0>,
+				 <PINMUX_GPIO166__FUNC_B1_MSDC1_DAT1>,
+				 <PINMUX_GPIO167__FUNC_B1_MSDC1_DAT2>,
+				 <PINMUX_GPIO168__FUNC_B1_MSDC1_DAT3>;
+			input-enable;
+			drive-strength = <6>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins-clk {
+			pinmux = <PINMUX_GPIO164__FUNC_B1_MSDC1_CLK>;
+			drive-strength = <6>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+	};
+
+	mmc2_default_pins: mmc2-default-pins {
+		pins-clk {
+			pinmux = <PINMUX_GPIO170__FUNC_B1_MSDC2_CLK>;
+			drive-strength = <4>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO169__FUNC_B1_MSDC2_CMD>,
+				 <PINMUX_GPIO171__FUNC_B1_MSDC2_DAT0>,
+				 <PINMUX_GPIO172__FUNC_B1_MSDC2_DAT1>,
+				 <PINMUX_GPIO173__FUNC_B1_MSDC2_DAT2>,
+				 <PINMUX_GPIO174__FUNC_B1_MSDC2_DAT3>;
+			input-enable;
+			drive-strength = <6>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+
+	mmc2_uhs_pins: mmc2-uhs-pins {
+		pins-clk {
+			pinmux = <PINMUX_GPIO170__FUNC_B1_MSDC2_CLK>;
+			drive-strength = <4>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins-cmd-dat {
+			pinmux = <PINMUX_GPIO169__FUNC_B1_MSDC2_CMD>,
+				 <PINMUX_GPIO171__FUNC_B1_MSDC2_DAT0>,
+				 <PINMUX_GPIO172__FUNC_B1_MSDC2_DAT1>,
+				 <PINMUX_GPIO173__FUNC_B1_MSDC2_DAT2>,
+				 <PINMUX_GPIO174__FUNC_B1_MSDC2_DAT3>;
+			input-enable;
+			drive-strength = <6>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+
+	mmc2_eint_pins: mmc2-eint-pins {
+		pins-dat1 {
+			pinmux = <PINMUX_GPIO172__FUNC_B_GPIO172>;
+			input-enable;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+
+	rv3028_pins: rv3028-pins {
+		pins-irq {
+			pinmux = <PINMUX_GPIO42__FUNC_B_GPIO42>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+			input-enable;
+		};
+	};
+
+	spi0_pins: spi0-pins {
+		pins-spi {
+			pinmux = <PINMUX_GPIO69__FUNC_O_SPIM0_CSB>,
+				 <PINMUX_GPIO70__FUNC_O_SPIM0_CLK>,
+				 <PINMUX_GPIO71__FUNC_B0_SPIM0_MOSI>,
+				 <PINMUX_GPIO72__FUNC_B0_SPIM0_MISO>;
+			bias-disable;
+		};
+	};
+
+	spi1_pins: spi1-pins {
+		pins-spi {
+			pinmux = <PINMUX_GPIO75__FUNC_O_SPIM1_CSB>,
+				 <PINMUX_GPIO76__FUNC_O_SPIM1_CLK>,
+				 <PINMUX_GPIO77__FUNC_B0_SPIM1_MOSI>,
+				 <PINMUX_GPIO78__FUNC_B0_SPIM1_MISO>;
+			bias-disable;
+		};
+	};
+
+	pcie_default_pins: pcie-default-pins {
+		pins {
+			pinmux = <PINMUX_GPIO47__FUNC_I1_WAKEN>,
+				 <PINMUX_GPIO48__FUNC_O_PERSTN>,
+				 <PINMUX_GPIO49__FUNC_B1_CLKREQN>;
+			bias-pull-up;
+		};
+	};
+
+	ts_dsi0_goodix_pins: ts-dsi0-goodix-pins {
+		pins-irq {
+			pinmux = <PINMUX_GPIO146__FUNC_B_GPIO146>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+			input-enable;
+		};
+
+		pins-reset {
+			pinmux = <PINMUX_GPIO7__FUNC_B_GPIO7>;
+			bias-pull-down;
+		};
+	};
+
+	uart0_pins: uart0-pins {
+		pins {
+			pinmux = <PINMUX_GPIO31__FUNC_O_UTXD0>,
+				 <PINMUX_GPIO32__FUNC_I1_URXD0>;
+			bias-pull-up;
+		};
+	};
+
+	uart1_pins: uart1-pins {
+		pins {
+			pinmux = <PINMUX_GPIO33__FUNC_O_UTXD1>,
+				 <PINMUX_GPIO34__FUNC_I1_URXD1>;
+			bias-pull-up;
+		};
+	};
+
+	uart2_pins: uart2-pins {
+		pins {
+			pinmux = <PINMUX_GPIO35__FUNC_O_UTXD2>,
+				 <PINMUX_GPIO36__FUNC_I1_URXD2>;
+			bias-pull-up;
+		};
+	};
+
+	usbotg_pins: usbotg-pins {
+		pins-iddig {
+			pinmux = <PINMUX_GPIO83__FUNC_B_GPIO83>;
+			input-enable;
+			bias-pull-up;
+		};
+
+		pins-valid {
+			pinmux = <PINMUX_GPIO85__FUNC_I0_VBUSVALID>;
+			input-enable;
+		};
+
+		pins-vbus {
+			pinmux = <PINMUX_GPIO84__FUNC_O_USB_DRVVBUS>;
+			output-high;
+		};
+	};
+
+	usb1_hub_pins: usb1-hub-pins {
+		pins {
+			pinmux = <PINMUX_GPIO147__FUNC_B_GPIO147>;
+			output-low;
+		};
+	};
+
+	usb1_pins: usb1-pins {
+		pins {
+			pinmux = <PINMUX_GPIO88__FUNC_I0_VBUSVALID_1P>;
+			input-enable;
+		};
+	};
+
+	usb2_eth_pins: usb2-eth-pins {
+		pins {
+			pinmux = <PINMUX_GPIO80__FUNC_B_GPIO80>;
+			output-low;
+		};
+	};
+
+	wifi_pwrseq_pins: wifi-pwrseq-pins {
+		pins {
+			pinmux = <PINMUX_GPIO89__FUNC_B_GPIO89>;
+			output-low;
+		};
+	};
+
+	watchdog_pins: watchdog-pins {
+		pins {
+			pinmux = <PINMUX_GPIO100__FUNC_O_WATCHDOG>;
+			bias-pull-up;
+		};
+	};
+};

-- 
2.43.0



From bisson.gary at gmail.com  Wed Dec  3 13:20:41 2025
From: bisson.gary at gmail.com (Gary Bisson)
Date: Wed, 03 Dec 2025 22:20:41 +0100
Subject: [PATCH v5 5/5] arm64: dts: mediatek: add device tree for Tungsten
 700 board
In-Reply-To: <20251203-review-v5-0-b26d5512c6af@gmail.com>
References: <20251203-review-v5-0-b26d5512c6af@gmail.com>
Message-ID: <20251203-review-v5-5-b26d5512c6af@gmail.com>

Add device tree to support Ezurio Tungsten 700 (MT8390) SMARC SOM [1] +
Universal SMARC carrier board [2].
It includes support for the MIPI-DSI BD070LIC3 display which uses the
Tianma TM070JDHG30 panel + TI SN65DSI84 MIPI-DSI to LVDS bridge [3].

[1] https://www.ezurio.com/product/tungsten700-smarc
[2] https://www.ezurio.com/system-on-module/accessories/universal-smarc-carrier
[3] https://www.ezurio.com/product/bd070lic3-7-touchscreen-display

Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
Signed-off-by: Gary Bisson <bisson.gary at gmail.com>
---
Changes in v2:
- None
Changed in v3:
- None
Changed in v4:
- None
Changed in v5:
- Updated dtsi name to remove wildcard
---
 arch/arm64/boot/dts/mediatek/Makefile              |  1 +
 .../boot/dts/mediatek/mt8390-tungsten-smarc.dts    | 22 ++++++++++++++++++++++
 2 files changed, 23 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile
index 30d169a31b10..85f338344dd3 100644
--- a/arch/arm64/boot/dts/mediatek/Makefile
+++ b/arch/arm64/boot/dts/mediatek/Makefile
@@ -102,6 +102,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-genio-510-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8370-tungsten-smarc.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-genio-1200-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-genio-700-evk.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-tungsten-smarc.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-kontron-3-5-sbc-i1200.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-radxa-nio-12l.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-radxa-nio-12l-8-hd-panel.dtbo
diff --git a/arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts b/arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts
new file mode 100644
index 000000000000..7580f9e2f20d
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2025 Ezurio LLC
+ * Author: Gary Bisson <bisson.gary at gmail.com>
+ */
+/dts-v1/;
+#include "mt8188.dtsi"
+#include "mt8390-tungsten-smarc.dtsi"
+
+/ {
+	model = "Ezurio Tungsten700 SMARC (MT8390)";
+	compatible = "ezurio,mt8390-tungsten-smarc", "mediatek,mt8390",
+		     "mediatek,mt8188";
+};
+
+&cpu4 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};
+
+&cpu5 {
+	cpu-supply = <&mt6359_vcore_buck_reg>;
+};

-- 
2.43.0



From s.pueschel at pengutronix.de  Wed Dec  3 13:21:07 2025
From: s.pueschel at pengutronix.de (=?UTF-8?Q?Sven_P=C3=BCschel?=)
Date: Wed, 3 Dec 2025 22:21:07 +0100
Subject: [PATCH v2 01/22] media: dt-bindings: media: rockchip-rga: add
 rockchip,rk3588-rga3
In-Reply-To: <81593c42-fcc2-47ad-8d0f-69a2d17664a6@kernel.org>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
 <20251203-spu-rga3-v2-1-989a67947f71@pengutronix.de>
 <81593c42-fcc2-47ad-8d0f-69a2d17664a6@kernel.org>
Message-ID: <1db3a9ee-ae09-431f-93ac-680bac088f79@pengutronix.de>

Hi?Krzysztof,

On 12/3/25 9:28 PM, Krzysztof Kozlowski wrote:
> On 03/12/2025 16:52, Sven P?schel wrote:
>> Add a new compatible for the RGA3 (Raster Graphic Acceleration 3)
>> peripheral found on the RK3588 SoC.
>>
>> The existing rga node refers to the RGA2 peripheral. The RK3588
> What is "existing rga node"? There is no node here. This is a patch for
> bindings, so you say which hardware existing binding describes and what
> are the differences against that older hardware.
Yeah that is misleading. I refer to the existing binding/compatible 
values of rockchip-rk3xxx-rga which describe the hardware named RGA2 in 
the rk3588 TRM.
>
>> contains one RGA2 core and two RGA3 cores. Both feature a similar
>> functionality of scaling, cropping and rotating of up to two input
>> images into one output image. Key differences of the RGA3 are:
>>
>> - supports 10bit YUV output formats
>> - supports 8x8 tiles and FBCD as inputs and outputs
>> - supports BT2020 color space conversion
>> - max output resolution of (8192-64)x(8192-64)
>> - MMU can map up to 32G DDR RAM
>> - fully planar formats (3 planes) are not supported
>> - max scale up/down factor of 8
> "differences" in meaning nothing above is supported by RGA2?

except the last two points yes. The RGA2 supports fully planar formats 
with 3 planes and can scale up to a factor of 16. For the scaling I can 
add a note to make it more obvious that the RGA3 is worse in this regard.

Sincerely
 ? ? Sven

>
>> Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
>> ---
> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
>
>
> Best regards,
> Krzysztof
>


From lkp at intel.com  Wed Dec  3 13:24:24 2025
From: lkp at intel.com (kernel test robot)
Date: Thu, 4 Dec 2025 05:24:24 +0800
Subject: [PATCH 2/2] media: nxp: Add i.MX9 CSI pixel formatter v4l2 driver
In-Reply-To: <20251203-csi_formatter-v1-2-eb9e1147b49e@nxp.com>
References: <20251203-csi_formatter-v1-2-eb9e1147b49e@nxp.com>
Message-ID: <202512040546.yLIh1wBH-lkp@intel.com>

Hi Guoniu,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 1f2353f5a1af995efbf7bea44341aa0d03460b28]

url:    https://github.com/intel-lab-lkp/linux/commits/Guoniu-Zhou/media-dt-bindings-Add-CSI-Pixel-Formatter-DT-bindings/20251203-143208
base:   1f2353f5a1af995efbf7bea44341aa0d03460b28
patch link:    https://lore.kernel.org/r/20251203-csi_formatter-v1-2-eb9e1147b49e%40nxp.com
patch subject: [PATCH 2/2] media: nxp: Add i.MX9 CSI pixel formatter v4l2 driver
config: sh-allyesconfig (https://download.01.org/0day-ci/archive/20251204/202512040546.yLIh1wBH-lkp at intel.com/config)
compiler: sh4-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251204/202512040546.yLIh1wBH-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512040546.yLIh1wBH-lkp at intel.com/

All warnings (new ones prefixed by >>):

>> drivers/media/platform/nxp/imx9-csi-formatter.c:763:12: warning: 'csi_formatter_system_resume' defined but not used [-Wunused-function]
     763 | static int csi_formatter_system_resume(struct device *dev)
         |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/media/platform/nxp/imx9-csi-formatter.c:758:12: warning: 'csi_formatter_system_suspend' defined but not used [-Wunused-function]
     758 | static int csi_formatter_system_suspend(struct device *dev)
         |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~


vim +/csi_formatter_system_resume +763 drivers/media/platform/nxp/imx9-csi-formatter.c

   753	
   754	/* -----------------------------------------------------------------------------
   755	 * Suspend/resume
   756	 */
   757	
 > 758	static int csi_formatter_system_suspend(struct device *dev)
   759	{
   760		return pm_runtime_force_suspend(dev);
   761	}
   762	
 > 763	static int csi_formatter_system_resume(struct device *dev)
   764	{
   765		int ret;
   766	
   767		ret = pm_runtime_force_resume(dev);
   768		if (ret < 0) {
   769			dev_err(dev, "force resume %s failed!\n", dev_name(dev));
   770			return ret;
   771		}
   772	
   773		return 0;
   774	}
   775	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From Frank.li at nxp.com  Wed Dec  3 13:31:55 2025
From: Frank.li at nxp.com (Frank Li)
Date: Wed, 3 Dec 2025 16:31:55 -0500
Subject: [PATCH 4/4] media: nxp: use cleanup __free(fwnode_handle)
 simplify code
In-Reply-To: <20251119050239.GA16725@pendragon.ideasonboard.com>
References: <20251117-cam_cleanup-v1-0-6cd42872db79@nxp.com>
 <20251117-cam_cleanup-v1-4-6cd42872db79@nxp.com>
 <20251119042505.GO10711@pendragon.ideasonboard.com>
 <20251119050239.GA16725@pendragon.ideasonboard.com>
Message-ID: <aTCsS52Bbtld/vTk@lizhi-Precision-Tower-5810>

On Wed, Nov 19, 2025 at 02:02:39PM +0900, Laurent Pinchart wrote:
> On Wed, Nov 19, 2025 at 01:25:29PM +0900, Laurent Pinchart wrote:
> > On Mon, Nov 17, 2025 at 01:58:14PM -0500, Frank Li wrote:
> > > Use cleanup __free(fwnode_handle) simplify code. Change to dev_err_probe()
> > > because replace goto with return.
> > >
> > > Add missed "\n" at error message.
> > >
> > > No functional change.
> > >
> > > Signed-off-by: Frank Li <Frank.Li at nxp.com>
> > > ---
> > >  drivers/media/platform/nxp/imx-mipi-csis.c    | 31 +++++++++------------------
> > >  drivers/media/platform/nxp/imx8mq-mipi-csi2.c | 31 +++++++++------------------
> > >  2 files changed, 20 insertions(+), 42 deletions(-)
> > >
> > > diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c
> > > index ce93d868746f002c22e2f86b1e0aa84ec1a76061..d924adb406a30797b66f0094ab17e98ad44fefac 100644
> > > --- a/drivers/media/platform/nxp/imx-mipi-csis.c
> > > +++ b/drivers/media/platform/nxp/imx-mipi-csis.c
> > > @@ -12,6 +12,7 @@
> > >   *
> > >   */
> > >
> > > +#include <linux/cleanup.h>
> > >  #include <linux/clk.h>
> > >  #include <linux/debugfs.h>
> > >  #include <linux/delay.h>
> > > @@ -1349,28 +1350,25 @@ static int mipi_csis_async_register(struct mipi_csis_device *csis)
> > >  		.bus_type = V4L2_MBUS_CSI2_DPHY,
> > >  	};
> > >  	struct v4l2_async_connection *asd;
> > uuu> -	struct fwnode_handle *ep;
> > >  	unsigned int i;
> > >  	int ret;
> > >
> > >  	v4l2_async_subdev_nf_init(&csis->notifier, &csis->sd);
> > >
> > > -	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csis->dev), 0, 0,
> > > -					     FWNODE_GRAPH_ENDPOINT_NEXT);
> > > +	struct fwnode_handle *ep __free(fwnode_handle) =
> > > +		fwnode_graph_get_endpoint_by_id(dev_fwnode(csis->dev), 0, 0,
> > > +						FWNODE_GRAPH_ENDPOINT_NEXT);
> >
> > Let's avoid mixing variable declarations and code, this is a style
> > change that is not widely accepted (yet). You can write
> >
> > 	struct fwnode_handle *ep __free(fwnode_handle) = NULL;
> >  	struct v4l2_async_connection *asd;
> > 	unsigned int i;
> > 	int ret;
> >
> >   	v4l2_async_subdev_nf_init(&csis->notifier, &csis->sd);
> >
> > 	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csis->dev), 0, 0,
> > 					     FWNODE_GRAPH_ENDPOINT_NEXT);
>
> Quite a coincidence, there's an ongoing mail thread on LKML about this
> topic:
>
> http://lore.kernel.org/r/CAHk-=whPZoi03ZwphxiW6cuWPtC3nyKYS8_BThgztCdgPWP1WA at mail.gmail.com

Laurent:

	After read above thread and cleanup.h.

	Look like my method is prefered.

Frank

>
> > >  	if (!ep)
> > >  		return -ENOTCONN;
> > >
> > >  	ret = v4l2_fwnode_endpoint_parse(ep, &vep);
> > >  	if (ret)
> > > -		goto err_parse;
> > > +		return ret;
> > >
> > >  	for (i = 0; i < vep.bus.mipi_csi2.num_data_lanes; ++i) {
> > > -		if (vep.bus.mipi_csi2.data_lanes[i] != i + 1) {
> > > -			dev_err(csis->dev,
> > > -				"data lanes reordering is not supported");
> > > -			ret = -EINVAL;
> > > -			goto err_parse;
> > > -		}
> > > +		if (vep.bus.mipi_csi2.data_lanes[i] != i + 1)
> > > +			return dev_err_probe(csis->dev, -EINVAL,
> > > +					     "data lanes reordering is not supported\n");
> >
> > To switch to dev_err_probe(), we should drop the error message in the
> > probe() function when mipi_csis_async_register() fails, and make sure
> > every error path in this function prints a message. I'd prefer splitting
> > that to a separate patch.
> >
> > >  	}
> > >
> > >  	csis->bus = vep.bus.mipi_csi2;
> > > @@ -1381,12 +1379,8 @@ static int mipi_csis_async_register(struct mipi_csis_device *csis)
> > >
> > >  	asd = v4l2_async_nf_add_fwnode_remote(&csis->notifier, ep,
> > >  					      struct v4l2_async_connection);
> > > -	if (IS_ERR(asd)) {
> > > -		ret = PTR_ERR(asd);
> > > -		goto err_parse;
> > > -	}
> > > -
> > > -	fwnode_handle_put(ep);
> > > +	if (IS_ERR(asd))
> > > +		return PTR_ERR(asd);
> > >
> > >  	csis->notifier.ops = &mipi_csis_notify_ops;
> > >
> > > @@ -1395,11 +1389,6 @@ static int mipi_csis_async_register(struct mipi_csis_device *csis)
> > >  		return ret;
> > >
> > >  	return v4l2_async_register_subdev(&csis->sd);
> > > -
> > > -err_parse:
> > > -	fwnode_handle_put(ep);
> > > -
> > > -	return ret;
> > >  }
> > >
> > >  /* -----------------------------------------------------------------------------
> > > diff --git a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
> > > index 75709161fb26a61239b94430365849e022fdc14f..94882568405db55593c5c51722db2233a64d53e4 100644
> > > --- a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
> > > +++ b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
> > > @@ -6,6 +6,7 @@
> > >   */
> > >
> > >  #include <linux/bitfield.h>
> > > +#include <linux/cleanup.h>
> > >  #include <linux/clk.h>
> > >  #include <linux/clk-provider.h>
> > >  #include <linux/delay.h>
> > > @@ -717,28 +718,25 @@ static int imx8mq_mipi_csi_async_register(struct csi_state *state)
> > >  		.bus_type = V4L2_MBUS_CSI2_DPHY,
> > >  	};
> > >  	struct v4l2_async_connection *asd;
> > > -	struct fwnode_handle *ep;
> > >  	unsigned int i;
> > >  	int ret;
> > >
> > >  	v4l2_async_subdev_nf_init(&state->notifier, &state->sd);
> > >
> > > -	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(state->dev), 0, 0,
> > > -					     FWNODE_GRAPH_ENDPOINT_NEXT);
> > > +	struct fwnode_handle *ep __free(fwnode_handle) =
> > > +		fwnode_graph_get_endpoint_by_id(dev_fwnode(state->dev), 0, 0,
> > > +						FWNODE_GRAPH_ENDPOINT_NEXT);
> >
> > Same comment as above.
> >
> > >  	if (!ep)
> > >  		return -ENOTCONN;
> > >
> > >  	ret = v4l2_fwnode_endpoint_parse(ep, &vep);
> > >  	if (ret)
> > > -		goto err_parse;
> > > +		return ret;
> > >
> > >  	for (i = 0; i < vep.bus.mipi_csi2.num_data_lanes; ++i) {
> > > -		if (vep.bus.mipi_csi2.data_lanes[i] != i + 1) {
> > > -			dev_err(state->dev,
> > > -				"data lanes reordering is not supported");
> > > -			ret = -EINVAL;
> > > -			goto err_parse;
> > > -		}
> > > +		if (vep.bus.mipi_csi2.data_lanes[i] != i + 1)
> > > +			return dev_err_probe(state->dev, -EINVAL,
> > > +					     "data lanes reordering is not supported\n");
> >
> > And here too.
> >
> > Usage of __free(fwnode_handle) looks good, it just needs to be split to
> > a patch of its own.
> >
> > >  	}
> > >
> > >  	state->bus = vep.bus.mipi_csi2;
> > > @@ -749,12 +747,8 @@ static int imx8mq_mipi_csi_async_register(struct csi_state *state)
> > >
> > >  	asd = v4l2_async_nf_add_fwnode_remote(&state->notifier, ep,
> > >  					      struct v4l2_async_connection);
> > > -	if (IS_ERR(asd)) {
> > > -		ret = PTR_ERR(asd);
> > > -		goto err_parse;
> > > -	}
> > > -
> > > -	fwnode_handle_put(ep);
> > > +	if (IS_ERR(asd))
> > > +		return PTR_ERR(asd);
> > >
> > >  	state->notifier.ops = &imx8mq_mipi_csi_notify_ops;
> > >
> > > @@ -763,11 +757,6 @@ static int imx8mq_mipi_csi_async_register(struct csi_state *state)
> > >  		return ret;
> > >
> > >  	return v4l2_async_register_subdev(&state->sd);
> > > -
> > > -err_parse:
> > > -	fwnode_handle_put(ep);
> > > -
> > > -	return ret;
> > >  }
> > >
> > >  /* -----------------------------------------------------------------------------
>
> --
> Regards,
>
> Laurent Pinchart


From arnd at arndb.de  Wed Dec  3 13:35:36 2025
From: arnd at arndb.de (Arnd Bergmann)
Date: Wed, 03 Dec 2025 22:35:36 +0100
Subject: [PATCH QUESTION] arm64: configs: Add Snapdragon 845 config fragment
In-Reply-To: <20251126-sdm845-config-question-v1-1-ffa91ed53095@ixit.cz>
References: <20251126-sdm845-config-question-v1-1-ffa91ed53095@ixit.cz>
Message-ID: <8f8baac8-3b1a-442d-a64f-5a90f9e30552@app.fastmail.com>

On Wed, Nov 26, 2025, at 17:19, David Heidelberg via B4 Relay wrote:
>
> This patch is a question, if it would be viable to introduce this
> configuration fragment as part of mainline kernel, so keeping it in sync
> with recent kernel updates would be more straighforward.

I don't mind the idea of having additional fragments for specific
purposes, but as others have said this one does not seem that useful.

I think it does too many things at once and is still too specific to
a relatively uncommon usecase. Having an SDM845 specific fragment is
clearly too narrow, but I can see us adding a fragment for phones
overall, which would then turn on options for Qualcomm, Mediatek
and Samsung based phones.

> +# Samsung S9 SM-G9600(starqltechn)
> +CONFIG_SND_SOC_MAX98512=y
> +CONFIG_SND_SOC_MAXIM_DSM=y
> +CONFIG_SND_SOC_MAXIM_DSM_CAL=y
> +CONFIG_DRM_PANEL_SAMSUNG_S6E3HA8=y
> +CONFIG_TOUCHSCREEN_S6SY761=m
> +CONFIG_MFD_SEC_CORE=m
> +CONFIG_REGULATOR_S2DOS05=m
> +CONFIG_MFD_MAX77705=m
> +CONFIG_LEDS_MAX77705=m
> +CONFIG_CHARGER_MAX77705=m
> +CONFIG_BATTERY_MAX17042=m
> +CONFIG_INPUT_MAX77693_HAPTIC=m
> +CONFIG_PWM_CLK=m
> +
> +# SHIFT6mq
> +CONFIG_DRM_PANEL_VISIONOX_RM69299=y
> +CONFIG_SND_SOC_TFA989X=m

I think overall we can be fairly liberal with adding
more loadable modules to the common defconfig, but much
less so the built-in drivers.

> +# SOC
> +CONFIG_FORCE_NR_CPUS=y
> +CONFIG_NR_CPUS=8

This would break other devices that have more CPUs, which in turn
makes it impossible to combine the fragment with other fragments.

> +CONFIG_SCSI_UFS_QCOM=y
> +CONFIG_QCOM_GSBI=y
> +CONFIG_QCOM_LLCC=y
> +CONFIG_QCOM_OCMEM=y
> +CONFIG_QCOM_RMTFS_MEM=y
> +CONFIG_QCOM_SOCINFO=y
> +CONFIG_QCOM_WCNSS_CTRL=y
> +CONFIG_QCOM_APR=y
> +CONFIG_POWER_RESET_QCOM_PON=y
> +CONFIG_QCOM_SPMI_TEMP_ALARM=y
> +CONFIG_QCOM_LMH=y
> +CONFIG_SCHED_CLUSTER=y
> +CONFIG_SND_SOC_QDSP6_Q6VOICE=m
> +CONFIG_SCSI_UFS_BSG=y
> +CONFIG_PHY_QCOM_QMP_PCIE=y
> +CONFIG_BACKLIGHT_CLASS_DEVICE=y
> +CONFIG_INTERCONNECT_QCOM_OSM_L3=y

Again, these should mosely be loadable modules.

> +# Notification LED
> +# Must be builtin as it won't be automatically modprobed
> +CONFIG_LEDS_TRIGGER_PATTERN=y

This sounds like bug that we should fix and not work around.

> +# Graphics
> +CONFIG_DRM=y
> +CONFIG_FB_SIMPLE=y

I don't want to enable more fbdev drivers. Right now the
only one we enable is FB_EFI, and we should probably replace
that with DRM_SIMPLEDRM in order to turn off CONFIG_FB
entirely.

> +# Power management
> +CONFIG_PM_AUTOSLEEP=y
> +CONFIG_PM_WAKELOCKS=y
> +
> +# MGLRU
> +CONFIG_LRU_GEN=y
> +CONFIG_LRU_GEN_ENABLED=y
> +
> +# Usage clamping (scale CPU for specific tasks)
> +CONFIG_UCLAMP_TASK=y
> +CONFIG_UCLAMP_TASK_GROUP=y

We can discuss changing the defaults for these in the defconfig,
but this doesn't seem to belong with the other stuff.

> +# HID/Input
> +CONFIG_LCD_CLASS_DEVICE=m

This is not an input option

> +CONFIG_I2C_HID=y
> +CONFIG_HID_GENERIC=m
> +CONFIG_UHID=m
> +CONFIG_USB_HID=m
> +CONFIG_INPUT_EVDEV=y
> +CONFIG_BT_HIDP=m
> +CONFIG_INPUT_JOYDEV=m
> +CONFIG_HID_ACCUTOUCH=m
> +CONFIG_HID_ACRUX=m
> +CONFIG_HID_ACRUX_FF=y
> +CONFIG_HID_ALPS=m
> +CONFIG_HID_APPLEIR=m

This looks like you are just enabling every single USB HID 
driver, which is probably not something we want in a commonly
used fragment, though having a well-maintained fragment for
popular pluggable USB devices may be useful for others as well.

> +# Qcom stuff
> +CONFIG_RPMSG_CHAR=y
> +CONFIG_QCOM_Q6V5_ADSP=m
> +CONFIG_BT_RFCOMM=m
> +CONFIG_BT_RFCOMM_TTY=y
> +CONFIG_BT_BNEP=m
> +CONFIG_BT_BNEP_MC_FILTER=y
> +CONFIG_BT_BNEP_PROTO_FILTER=y
> +CONFIG_BT_HS=y
> +CONFIG_BT_LE=y
> +CONFIG_HID_BATTERY_STRENGTH=y
> +CONFIG_HIDRAW=y
> +CONFIG_QCOM_COINCELL=m
> +CONFIG_QCOM_FASTRPC=m
> +CONFIG_QCOM_SPMI_VADC=y
> +CONFIG_QCOM_SPMI_ADC5=y
> +CONFIG_PHY_QCOM_QMP=y
> +CONFIG_PHY_QCOM_QUSB2=y
> +CONFIG_PHY_QCOM_QMP_UFS=y
> +CONFIG_TYPEC=y
> +CONFIG_PHY_QCOM_QMP_COMBO=y
> +CONFIG_LEDS_CLASS_FLASH=y
> +CONFIG_TCP_CONG_ADVANCED=y
> +CONFIG_TCP_CONG_WESTWOOD=y
> +CONFIG_DEFAULT_WESTWOOD=y
> +CONFIG_BLK_DEV_RAM=y
> +CONFIG_BLK_DEV_RAM_SIZE=8192
> +CONFIG_BTRFS_FS=y
> +CONFIG_BTRFS_FS_POSIX_ACL=y
> +CONFIG_F2FS_FS=y

Most of these don't look like "Qcom stuff" to me. In particular
BTRFS is probably not something you'd even want to enable on
a phone, though that could be part of a generic distro config
that we have discussed several times in the past.

> +# WLAN debugging
> +CONFIG_ATH10K_DEBUG=y
> +CONFIG_ATH10K_DEBUGFS=y
> +CONFIG_ATH10K_SPECTRAL=y

This particular one seem arbitrary, but having a "debugging"
fragment is something others may find helpful as well. The
hard part there is figuring out which debug options are the
most helpful for the least overhead, as everyone is debugging
different bugs.

> +# Disable all unrelated stuffs afaik
> +CONFIG_ARCH_BLAIZE=n
> +CONFIG_ARCH_SPARX5=n
> +CONFIG_HIBERNATION=n
> +CONFIG_FW_LOADER_USER_HELPER=n
> +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=n
> +CONFIG_BLK_DEV_NVME=n

It feels wrong to turn things off in the same fragment
that turns other things on.

      Arnd


From briannorris at chromium.org  Wed Dec  3 13:46:19 2025
From: briannorris at chromium.org (Brian Norris)
Date: Wed, 3 Dec 2025 13:46:19 -0800
Subject: [DONOTAPPLY RFC PATCH v2 3/4] DONOTMERGE: net: mwifiex: fix
 timeouts with the SD8777 chip
In-Reply-To: <20251026182602.26464-4-balejk@matfyz.cz>
References: <20251026182602.26464-1-balejk@matfyz.cz>
 <20251026182602.26464-4-balejk@matfyz.cz>
Message-ID: <aTCvq7aN_WMts6hm@google.com>

Hi,

On Sun, Oct 26, 2025 at 07:20:40PM +0100, Karel Balej wrote:
> 	[ 2101.211178] mwifiex_sdio mmc2:0001:1: info: MWIFIEX VERSION: mwifiex 1.0 (14.75.33.p119)
... 
> Afterwards, a bisect was
> performed which first indicated the commit 808bbebcc8fc ("mwifiex: add
> Tx status support for EAPOL packets") introduced in the v3.18-v3.19
> cycle.
> 
> Reverting this commit (and the following one, commit 18ca43823f3c
> ("mwifiex: add Tx status support for ACTION frames"), to facilitate a
> clean revert) fixed the timeouts for v3.19, but during the next cycle,
> v3.19-v4.0, another breakage was introduced via commit 84b313b35f81
> ("mwifiex: make tx packet 64 byte DMA aligned").
> 
> Reverting all three commits fixed the timeouts on the current mainline
> kernel also. This patch contains the minimal changes needed to achieve
> that derived from the full revert commits.
...

(Trimmed the commit message down to the breaking commits, and the
version info)

>From the looks of it, you're dealing with incompatible changes made in
the Marvell firmware API. It seems that you have a "version 14"
firmware, and the timeline of these mwifiex changes (~2014) is approx
when linux-firmware started seeing v15 and v16 firmware. It *might* be
OK to try add some versioning to these structs and padding changes, and
make a choice based on adapter->fw_release_number or
adapter->fw_cap_info. It might be ugly and error-prone, but possible...

Or if the FW versioning doesn't work out, it's possible we could
specifically flag these quirks for SD8777 somehow.

> Signed-off-by: Karel Balej <balejk at matfyz.cz>
> ---
>  drivers/net/wireless/marvell/mwifiex/fw.h     |  4 +---
>  drivers/net/wireless/marvell/mwifiex/sta_tx.c | 10 ++--------
>  2 files changed, 3 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h
> index e9e896606912..5c4c3363c7de 100644
> --- a/drivers/net/wireless/marvell/mwifiex/fw.h
> +++ b/drivers/net/wireless/marvell/mwifiex/fw.h
> @@ -690,9 +690,7 @@ struct txpd {
>  	u8 priority;
>  	u8 flags;
>  	u8 pkt_delay_2ms;
> -	u8 reserved1[2];
> -	u8 tx_token_id;
> -	u8 reserved[2];
> +	u8 reserved1;

I'm inferring that 'sizeof(struct txpd)' (also spelled
'sizeof(*local_tx_pd)' below) is relevant, and that this struct probably
should retain the smaller size for FW version 14.

Maybe you need a new 'struct txpd_v14' layout, and embed that inside
'struct txpd'.

>  } __packed;
>  
>  struct rxpd {
> diff --git a/drivers/net/wireless/marvell/mwifiex/sta_tx.c b/drivers/net/wireless/marvell/mwifiex/sta_tx.c
> index 9d0ef04ebe02..857eb22f4c24 100644
> --- a/drivers/net/wireless/marvell/mwifiex/sta_tx.c
> +++ b/drivers/net/wireless/marvell/mwifiex/sta_tx.c
> @@ -41,8 +41,8 @@ void mwifiex_process_sta_txpd(struct mwifiex_private *priv,
>  
>  	pkt_type = mwifiex_is_skb_mgmt_frame(skb) ? PKT_TYPE_MGMT : 0;
>  
> -	pad = ((uintptr_t)skb->data - (sizeof(*local_tx_pd) + hroom)) &
> -	       (MWIFIEX_DMA_ALIGN_SZ - 1);
> +	pad = (4 - (((void *)skb->data - NULL) & 0x3)) % 4;

It's not clear to me whether your v14 FW doesn't like the 64-byte
alignment, or if it didn't like the new txpd header size/layout, or
both. But obviously this line won't fly, with magic numbers and all. It
will need to be expressed in terms of macros (MWIFIEX_DMA_ALIGN_SZ, or a
"V14" version of that; and sizeof(...)).

> +
>  	skb_push(skb, sizeof(*local_tx_pd) + pad);
>  
>  	local_tx_pd = (struct txpd *) skb->data;
> @@ -58,12 +58,6 @@ void mwifiex_process_sta_txpd(struct mwifiex_private *priv,
>  	local_tx_pd->pkt_delay_2ms =
>  				mwifiex_wmm_compute_drv_pkt_delay(priv, skb);
>  
> -	if (tx_info->flags & MWIFIEX_BUF_FLAG_EAPOL_TX_STATUS ||
> -	    tx_info->flags & MWIFIEX_BUF_FLAG_ACTION_TX_STATUS) {
> -		local_tx_pd->tx_token_id = tx_info->ack_frame_id;
> -		local_tx_pd->flags |= MWIFIEX_TXPD_FLAGS_REQ_TX_STATUS;
> -	}

Rather than dropping this block, would it work to also check:

	adapter->fw_api_ver >= MWIFIEX_FW_V15

?

Brian

> -
>  	if (local_tx_pd->priority <
>  	    ARRAY_SIZE(priv->wmm.user_pri_pkt_tx_ctrl))
>  		/*
> -- 
> 2.51.1
> 


From lkp at intel.com  Wed Dec  3 13:45:39 2025
From: lkp at intel.com (kernel test robot)
Date: Thu, 4 Dec 2025 05:45:39 +0800
Subject: [PATCH 2/2] media: nxp: Add i.MX9 CSI pixel formatter v4l2 driver
In-Reply-To: <20251203-csi_formatter-v1-2-eb9e1147b49e@nxp.com>
References: <20251203-csi_formatter-v1-2-eb9e1147b49e@nxp.com>
Message-ID: <202512040513.mvgeYlO0-lkp@intel.com>

Hi Guoniu,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 1f2353f5a1af995efbf7bea44341aa0d03460b28]

url:    https://github.com/intel-lab-lkp/linux/commits/Guoniu-Zhou/media-dt-bindings-Add-CSI-Pixel-Formatter-DT-bindings/20251203-143208
base:   1f2353f5a1af995efbf7bea44341aa0d03460b28
patch link:    https://lore.kernel.org/r/20251203-csi_formatter-v1-2-eb9e1147b49e%40nxp.com
patch subject: [PATCH 2/2] media: nxp: Add i.MX9 CSI pixel formatter v4l2 driver
config: m68k-allyesconfig (https://download.01.org/0day-ci/archive/20251204/202512040513.mvgeYlO0-lkp at intel.com/config)
compiler: m68k-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251204/202512040513.mvgeYlO0-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512040513.mvgeYlO0-lkp at intel.com/

All warnings (new ones prefixed by >>):

>> drivers/media/platform/nxp/imx9-csi-formatter.c:786:12: warning: 'csi_formatter_runtime_resume' defined but not used [-Wunused-function]
     786 | static int csi_formatter_runtime_resume(struct device *dev)
         |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/media/platform/nxp/imx9-csi-formatter.c:776:12: warning: 'csi_formatter_runtime_suspend' defined but not used [-Wunused-function]
     776 | static int csi_formatter_runtime_suspend(struct device *dev)
         |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/media/platform/nxp/imx9-csi-formatter.c:763:12: warning: 'csi_formatter_system_resume' defined but not used [-Wunused-function]
     763 | static int csi_formatter_system_resume(struct device *dev)
         |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/media/platform/nxp/imx9-csi-formatter.c:758:12: warning: 'csi_formatter_system_suspend' defined but not used [-Wunused-function]
     758 | static int csi_formatter_system_suspend(struct device *dev)
         |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~


vim +/csi_formatter_runtime_resume +786 drivers/media/platform/nxp/imx9-csi-formatter.c

   775	
 > 776	static int csi_formatter_runtime_suspend(struct device *dev)
   777	{
   778		struct v4l2_subdev *sd = dev_get_drvdata(dev);
   779		struct csi_formatter *formatter = sd_to_formatter(sd);
   780	
   781		clk_disable_unprepare(formatter->clk);
   782	
   783		return 0;
   784	}
   785	
 > 786	static int csi_formatter_runtime_resume(struct device *dev)
   787	{
   788		struct v4l2_subdev *sd = dev_get_drvdata(dev);
   789		struct csi_formatter *formatter = sd_to_formatter(sd);
   790	
   791		return clk_prepare_enable(formatter->clk);
   792	}
   793	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From briannorris at chromium.org  Wed Dec  3 13:47:27 2025
From: briannorris at chromium.org (Brian Norris)
Date: Wed, 3 Dec 2025 13:47:27 -0800
Subject: [DONOTAPPLY RFC PATCH v2 4/4] arm64: dts:
 samsung,coreprimevelte: add wifi node
In-Reply-To: <20251026182602.26464-5-balejk@matfyz.cz>
References: <20251026182602.26464-1-balejk@matfyz.cz>
 <20251026182602.26464-5-balejk@matfyz.cz>
Message-ID: <aTCv75hjdX5XvgCh@google.com>

On Sun, Oct 26, 2025 at 07:20:41PM +0100, Karel Balej wrote:
> Add a node for the phone's WiFi serviced by the Marvell SD8777 chip a
> communication with which happens over the SDIO. Also enable a regulator
> without which it is not possible to connect to networks although they
> are discovered properly.
> 
> Signed-off-by: Karel Balej <balejk at matfyz.cz>
> ---
>  .../mmp/pxa1908-samsung-coreprimevelte.dts        | 15 +++++++++++++++
>  1 file changed, 15 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/marvell/mmp/pxa1908-samsung-coreprimevelte.dts b/arch/arm64/boot/dts/marvell/mmp/pxa1908-samsung-coreprimevelte.dts
> index b2ce5edd9c6a..36d6ae4e902e 100644
> --- a/arch/arm64/boot/dts/marvell/mmp/pxa1908-samsung-coreprimevelte.dts
> +++ b/arch/arm64/boot/dts/marvell/mmp/pxa1908-samsung-coreprimevelte.dts
> @@ -475,6 +475,14 @@ ldo14: ldo14 {
>  				regulator-min-microvolt = <1200000>;
>  				regulator-max-microvolt = <3300000>;
>  			};
> +
> +			/*
> +			 * Needs to be enabled in order for the WiFi to be able
> +			 * to connect to networks.
> +			 */
> +			ldo15 {
> +				regulator-always-on;

Do we have a min/max voltage for this regulator?

> +			};
>  		};
>  	};
>  };
> @@ -523,6 +531,13 @@ &sdh1 {
>  	pinctrl-1 = <&sdh1_fast_pins_0 &sdh1_fast_pins_1 &sdh1_pins_2>;
>  	bus-width = <4>;
>  	non-removable;
> +	#address-cells = <1>;
> +	#size-cells = <0>;

I wonder if this should have:

	vmmc-supply = <&ldo16>;

rather than regulator-always-on above.

Brian

> +
> +	wifi at 1 {
> +		compatible = "marvell,sd8777";
> +		reg = <1>;
> +	};
>  };
>  
>  &pwm3 {
> -- 
> 2.51.1
> 


From briannorris at chromium.org  Wed Dec  3 13:50:52 2025
From: briannorris at chromium.org (Brian Norris)
Date: Wed, 3 Dec 2025 13:50:52 -0800
Subject: [DONOTAPPLY RFC PATCH v2 1/4] dt-bindings: mwifiex: document use
 with the SD8777 chipset
In-Reply-To: <20251026182602.26464-2-balejk@matfyz.cz>
References: <20251026182602.26464-1-balejk@matfyz.cz>
 <20251026182602.26464-2-balejk@matfyz.cz>
Message-ID: <aTCwvFBE6IF6WT1d@google.com>

On Sun, Oct 26, 2025 at 07:20:38PM +0100, Karel Balej wrote:
> Document the corresponding compatible string for the use of this driver
> with the Marvell SD8777 wireless chipset.

Device tree bindings aren't supposed to be about "drivers". This can
just be:

  Document the compatible string for the Marvell SD8777 wireless chipset.

On the bright side, it's totally legit to describe HW bindings even if
there isn't driver support yet. So:

Acked-by: Brian Norris <briannorris at chromium.org>

> Signed-off-by: Karel Balej <balejk at matfyz.cz>
> ---
>  .../devicetree/bindings/net/wireless/marvell,sd8787.yaml         | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/Documentation/devicetree/bindings/net/wireless/marvell,sd8787.yaml b/Documentation/devicetree/bindings/net/wireless/marvell,sd8787.yaml
> index 930b700b73d0..d31ff38f57d1 100644
> --- a/Documentation/devicetree/bindings/net/wireless/marvell,sd8787.yaml
> +++ b/Documentation/devicetree/bindings/net/wireless/marvell,sd8787.yaml
> @@ -18,6 +18,7 @@ description:
>  properties:
>    compatible:
>      enum:
> +      - marvell,sd8777
>        - marvell,sd8787
>        - marvell,sd8897
>        - marvell,sd8978
> -- 
> 2.51.1
> 


From Frank.li at nxp.com  Wed Dec  3 14:19:42 2025
From: Frank.li at nxp.com (Frank Li)
Date: Wed, 3 Dec 2025 17:19:42 -0500
Subject: [PATCH v2 1/2] dmaengine: Add cleanup FREE defines for
 dma_async_tx_descriptor
In-Reply-To: <20251003-dma_chan_free-v2-1-564946b6c563@nxp.com>
References: <20251003-dma_chan_free-v2-0-564946b6c563@nxp.com>
 <20251003-dma_chan_free-v2-1-564946b6c563@nxp.com>
Message-ID: <aTC3fly+fFU5hB2q@lizhi-Precision-Tower-5810>

On Fri, Oct 03, 2025 at 12:26:49PM -0400, Frank Li wrote:
> Add cleanup FREE defines for dma_async_tx_descriptor to support automatic
> cleanup and simplify error handling.
>
> Signed-off-by: Frank Li <Frank.Li at nxp.com>
> ---

Vinod Koul:

	Do you have chance to check this one, 3 month passed. Is it missed
at your review queue?

Frank

> Check patch report exceed 100 chars, but it's still better put into one
> line to keep consistent with other DEFINE_FREE and better readablity
>
> change in v2
> - remove surpoiouse remove empty line
> ---
>  include/linux/dmaengine.h | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
> index 99efe2b9b4ea9844ca6161208362ef18ef111d96..27fa1646a807c49c781e1bce9e3e7d9a3c66f41d 100644
> --- a/include/linux/dmaengine.h
> +++ b/include/linux/dmaengine.h
> @@ -5,6 +5,7 @@
>  #ifndef LINUX_DMAENGINE_H
>  #define LINUX_DMAENGINE_H
>
> +#include <linux/cleanup.h>
>  #include <linux/device.h>
>  #include <linux/err.h>
>  #include <linux/uio.h>
> @@ -1612,6 +1613,8 @@ static inline int dmaengine_desc_free(struct dma_async_tx_descriptor *desc)
>  	return desc->desc_free(desc);
>  }
>
> +DEFINE_FREE(dma_async_tx_descriptor, struct dma_async_tx_descriptor *, if (_T) dmaengine_desc_free(_T))
> +
>  /* --- DMA device --- */
>
>  int dma_async_device_register(struct dma_device *device);
>
> --
> 2.34.1
>


From devnull+david.ixit.cz at kernel.org  Wed Dec  3 14:34:10 2025
From: devnull+david.ixit.cz at kernel.org (David Heidelberg via B4 Relay)
Date: Wed, 03 Dec 2025 23:34:10 +0100
Subject: [PATCH] ALSA: Do not build obsolete API
Message-ID: <20251203-old-alsa-v1-1-ac80704f52c3@ixit.cz>

From: David Heidelberg <david at ixit.cz>

ALSA 0.9.0-rc3 is from 2002, 23 years old.

Signed-off-by: David Heidelberg <david at ixit.cz>
---
Maybe I could drop also the code and Kconfig option?

David
---
 arch/arm/configs/am200epdkit_defconfig    | 1 -
 arch/arm/configs/lpc32xx_defconfig        | 1 -
 arch/arm/configs/omap1_defconfig          | 1 -
 arch/arm/configs/tegra_defconfig          | 1 -
 arch/mips/configs/gcw0_defconfig          | 1 -
 arch/mips/configs/loongson1_defconfig     | 1 -
 arch/mips/configs/qi_lb60_defconfig       | 1 -
 arch/mips/configs/rbtx49xx_defconfig      | 1 -
 arch/mips/configs/rs90_defconfig          | 1 -
 arch/powerpc/configs/85xx-hw.config       | 1 -
 arch/powerpc/configs/86xx-hw.config       | 1 -
 arch/powerpc/configs/mpc5200_defconfig    | 1 -
 arch/powerpc/configs/ppc6xx_defconfig     | 1 -
 arch/sh/configs/edosk7760_defconfig       | 1 -
 arch/sh/configs/se7724_defconfig          | 1 -
 arch/sh/configs/sh7785lcr_32bit_defconfig | 1 -
 sound/core/Kconfig                        | 2 +-
 17 files changed, 1 insertion(+), 17 deletions(-)

diff --git a/arch/arm/configs/am200epdkit_defconfig b/arch/arm/configs/am200epdkit_defconfig
index 134a559aba3dd..2367b1685c1cf 100644
--- a/arch/arm/configs/am200epdkit_defconfig
+++ b/arch/arm/configs/am200epdkit_defconfig
@@ -68,7 +68,6 @@ CONFIG_SOUND=m
 CONFIG_SND=m
 CONFIG_SND_MIXER_OSS=m
 CONFIG_SND_PCM_OSS=m
-# CONFIG_SND_SUPPORT_OLD_API is not set
 # CONFIG_SND_VERBOSE_PROCFS is not set
 CONFIG_SND_PXA2XX_AC97=m
 CONFIG_USB_GADGET=y
diff --git a/arch/arm/configs/lpc32xx_defconfig b/arch/arm/configs/lpc32xx_defconfig
index 2bddb0924a8c0..b9e2e603cd95e 100644
--- a/arch/arm/configs/lpc32xx_defconfig
+++ b/arch/arm/configs/lpc32xx_defconfig
@@ -113,7 +113,6 @@ CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_VGA16 is not set
 CONFIG_SOUND=y
 CONFIG_SND=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
 # CONFIG_SND_VERBOSE_PROCFS is not set
 CONFIG_SND_DEBUG=y
 CONFIG_SND_DEBUG_VERBOSE=y
diff --git a/arch/arm/configs/omap1_defconfig b/arch/arm/configs/omap1_defconfig
index dee820474f444..df88763fc7c3d 100644
--- a/arch/arm/configs/omap1_defconfig
+++ b/arch/arm/configs/omap1_defconfig
@@ -148,7 +148,6 @@ CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_MIXER_OSS=y
 CONFIG_SND_PCM_OSS=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
 # CONFIG_SND_VERBOSE_PROCFS is not set
 CONFIG_SND_DUMMY=y
 CONFIG_SND_USB_AUDIO=y
diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig
index ce70ff07c978a..68aedaf92667a 100644
--- a/arch/arm/configs/tegra_defconfig
+++ b/arch/arm/configs/tegra_defconfig
@@ -219,7 +219,6 @@ CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
 CONFIG_LOGO=y
 CONFIG_SOUND=y
 CONFIG_SND=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
 # CONFIG_SND_DRIVERS is not set
 CONFIG_SND_HDA_TEGRA=y
 CONFIG_SND_HDA_INPUT_BEEP=y
diff --git a/arch/mips/configs/gcw0_defconfig b/arch/mips/configs/gcw0_defconfig
index fda9971bdd8d9..adb9fd62ddb0d 100644
--- a/arch/mips/configs/gcw0_defconfig
+++ b/arch/mips/configs/gcw0_defconfig
@@ -79,7 +79,6 @@ CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_VGA16 is not set
 CONFIG_SOUND=y
 CONFIG_SND=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
 # CONFIG_SND_PROC_FS is not set
 # CONFIG_SND_DRIVERS is not set
 # CONFIG_SND_SPI is not set
diff --git a/arch/mips/configs/loongson1_defconfig b/arch/mips/configs/loongson1_defconfig
index 02d29110f7024..1d9781ff96986 100644
--- a/arch/mips/configs/loongson1_defconfig
+++ b/arch/mips/configs/loongson1_defconfig
@@ -119,7 +119,6 @@ CONFIG_WATCHDOG_SYSFS=y
 CONFIG_LOONGSON1_WDT=y
 CONFIG_SOUND=y
 CONFIG_SND=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
 # CONFIG_SND_DRIVERS is not set
 # CONFIG_SND_MIPS is not set
 # CONFIG_SND_USB is not set
diff --git a/arch/mips/configs/qi_lb60_defconfig b/arch/mips/configs/qi_lb60_defconfig
index 5f5b0254d75e7..a1bb0792f6eb1 100644
--- a/arch/mips/configs/qi_lb60_defconfig
+++ b/arch/mips/configs/qi_lb60_defconfig
@@ -81,7 +81,6 @@ CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_CLUT224 is not set
 CONFIG_SOUND=y
 CONFIG_SND=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
 # CONFIG_SND_VERBOSE_PROCFS is not set
 # CONFIG_SND_DRIVERS is not set
 # CONFIG_SND_SPI is not set
diff --git a/arch/mips/configs/rbtx49xx_defconfig b/arch/mips/configs/rbtx49xx_defconfig
index 03a7bbe28a532..49c709d663beb 100644
--- a/arch/mips/configs/rbtx49xx_defconfig
+++ b/arch/mips/configs/rbtx49xx_defconfig
@@ -53,7 +53,6 @@ CONFIG_TXX9_WDT=m
 # CONFIG_VGA_ARB is not set
 CONFIG_SOUND=m
 CONFIG_SND=m
-# CONFIG_SND_SUPPORT_OLD_API is not set
 # CONFIG_SND_VERBOSE_PROCFS is not set
 # CONFIG_SND_DRIVERS is not set
 # CONFIG_SND_PCI is not set
diff --git a/arch/mips/configs/rs90_defconfig b/arch/mips/configs/rs90_defconfig
index a53dd66e9b864..8382d535e6dc1 100644
--- a/arch/mips/configs/rs90_defconfig
+++ b/arch/mips/configs/rs90_defconfig
@@ -105,7 +105,6 @@ CONFIG_LOGO=y
 CONFIG_SOUND=y
 CONFIG_SND=y
 # CONFIG_SND_PCM_TIMER is not set
-# CONFIG_SND_SUPPORT_OLD_API is not set
 # CONFIG_SND_PROC_FS is not set
 # CONFIG_SND_DRIVERS is not set
 # CONFIG_SND_MIPS is not set
diff --git a/arch/powerpc/configs/85xx-hw.config b/arch/powerpc/configs/85xx-hw.config
index 8aff832173977..2b19c20a9a2c4 100644
--- a/arch/powerpc/configs/85xx-hw.config
+++ b/arch/powerpc/configs/85xx-hw.config
@@ -117,7 +117,6 @@ CONFIG_SND_INTEL8X0=y
 CONFIG_SND_POWERPC_SOC=y
 # CONFIG_SND_PPC is not set
 CONFIG_SND_SOC=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
 # CONFIG_SND_USB is not set
 CONFIG_SND=y
 CONFIG_SOUND=y
diff --git a/arch/powerpc/configs/86xx-hw.config b/arch/powerpc/configs/86xx-hw.config
index e7bd265fae5a4..07f30ab881e59 100644
--- a/arch/powerpc/configs/86xx-hw.config
+++ b/arch/powerpc/configs/86xx-hw.config
@@ -80,7 +80,6 @@ CONFIG_SERIO_LIBPS2=y
 CONFIG_SND_INTEL8X0=y
 CONFIG_SND_MIXER_OSS=y
 CONFIG_SND_PCM_OSS=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
 CONFIG_SND=y
 CONFIG_SOUND=y
 CONFIG_ULI526X=y
diff --git a/arch/powerpc/configs/mpc5200_defconfig b/arch/powerpc/configs/mpc5200_defconfig
index c0fe5e76604a0..617650cea56a9 100644
--- a/arch/powerpc/configs/mpc5200_defconfig
+++ b/arch/powerpc/configs/mpc5200_defconfig
@@ -75,7 +75,6 @@ CONFIG_FB_SM501=m
 CONFIG_LOGO=y
 CONFIG_SOUND=y
 CONFIG_SND=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
 # CONFIG_SND_DRIVERS is not set
 # CONFIG_SND_PCI is not set
 # CONFIG_SND_PPC is not set
diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig
index b082c1fae13c9..787d707f64a42 100644
--- a/arch/powerpc/configs/ppc6xx_defconfig
+++ b/arch/powerpc/configs/ppc6xx_defconfig
@@ -726,7 +726,6 @@ CONFIG_SND_OSSEMUL=y
 CONFIG_SND_MIXER_OSS=m
 CONFIG_SND_PCM_OSS=m
 CONFIG_SND_DYNAMIC_MINORS=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
 CONFIG_SND_VERBOSE_PRINTK=y
 CONFIG_SND_DEBUG=y
 CONFIG_SND_DEBUG_VERBOSE=y
diff --git a/arch/sh/configs/edosk7760_defconfig b/arch/sh/configs/edosk7760_defconfig
index abeae220606a3..905fac1072845 100644
--- a/arch/sh/configs/edosk7760_defconfig
+++ b/arch/sh/configs/edosk7760_defconfig
@@ -79,7 +79,6 @@ CONFIG_FB_TILEBLITTING=y
 CONFIG_FB_SH_MOBILE_LCDC=m
 CONFIG_SOUND=y
 CONFIG_SND=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
 # CONFIG_SND_VERBOSE_PROCFS is not set
 CONFIG_SND_VERBOSE_PRINTK=y
 CONFIG_SND_SOC=y
diff --git a/arch/sh/configs/se7724_defconfig b/arch/sh/configs/se7724_defconfig
index 9e3a54936f76f..8ca46d704c8ba 100644
--- a/arch/sh/configs/se7724_defconfig
+++ b/arch/sh/configs/se7724_defconfig
@@ -83,7 +83,6 @@ CONFIG_LOGO=y
 # CONFIG_LOGO_SUPERH_VGA16 is not set
 CONFIG_SOUND=y
 CONFIG_SND=m
-# CONFIG_SND_SUPPORT_OLD_API is not set
 # CONFIG_SND_DRIVERS is not set
 # CONFIG_SND_SPI is not set
 # CONFIG_SND_SUPERH is not set
diff --git a/arch/sh/configs/sh7785lcr_32bit_defconfig b/arch/sh/configs/sh7785lcr_32bit_defconfig
index eb63aa61b0465..5468cc53cddb4 100644
--- a/arch/sh/configs/sh7785lcr_32bit_defconfig
+++ b/arch/sh/configs/sh7785lcr_32bit_defconfig
@@ -93,7 +93,6 @@ CONFIG_SND_PCM_OSS=y
 CONFIG_SND_SEQUENCER_OSS=y
 CONFIG_SND_HRTIMER=y
 CONFIG_SND_DYNAMIC_MINORS=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
 # CONFIG_SND_VERBOSE_PROCFS is not set
 CONFIG_SND_VERBOSE_PRINTK=y
 CONFIG_SND_DEBUG=y
diff --git a/sound/core/Kconfig b/sound/core/Kconfig
index 48db44fa56feb..4e7bc370ffd7f 100644
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -155,7 +155,7 @@ config SND_MAX_CARDS
 
 config SND_SUPPORT_OLD_API
 	bool "Support old ALSA API"
-	default y
+	default n
 	help
 	  Say Y here to support the obsolete ALSA PCM API (ver.0.9.0 rc3
 	  or older).

---
base-commit: b2c27842ba853508b0da00187a7508eb3a96c8f7
change-id: 20251203-old-alsa-fa2c2cb038e1

Best regards,
-- 
David Heidelberg <david at ixit.cz>




From dianders at chromium.org  Wed Dec  3 14:37:15 2025
From: dianders at chromium.org (Doug Anderson)
Date: Wed, 3 Dec 2025 14:37:15 -0800
Subject: Proposal: Officially allow "incomplete" trees as a base
In-Reply-To: <CAL_JsqLxLakt94ACgv8z5A-O4WGZPfiZ-7UFaBPaOa7W8L3Cxw@mail.gmail.com>
References: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
 <aS66WcLPm6e5rdyk@shell.armlinux.org.uk> <CAL_JsqLxLakt94ACgv8z5A-O4WGZPfiZ-7UFaBPaOa7W8L3Cxw@mail.gmail.com>
Message-ID: <CAD=FV=Wfu4ddQdTeupN+Md5Tv+5P1Up+Zo5U2AjGpqayTuqFhw@mail.gmail.com>

Hi,

On Tue, Dec 2, 2025 at 3:16?PM Rob Herring <robh at kernel.org> wrote:
>
> > as a set of examples. I don't see a clear way to generate these from
> > a fragmented scheme. There's a similar problem with the board-level
> > compatible:
> >
> >         compatible = "solidrun,cubox-i/dl", "fsl,imx6dl";
> >         compatible = "solidrun,hummingboard2/dl", "fsl,imx6dl";
> >         compatible = "solidrun,hummingboard/dl", "fsl,imx6dl";
> >         compatible = "solidrun,hummingboard2/q", "fsl,imx6q";
> >
> > These don't include the SoM information.
>
> So we're back to needing to merge compatible even though Doug was
> willing to drop it. Or to put it another way, there's usecases for the
> base to be different SoC revisions and variants. So I don't think we
> should give up on solving that.

I'm willing to take a crack at it. Before doing so, though, I think we
need to agree upon a definition of what the top-level "compatible" is
supposed to be. Otherwise, what exactly is our goal in trying to merge
"compatible" strings? We should have a goal of updating the official
documentation with whatever we decide.


I guess first, we should see what the spec says. The Devicetree
Specification v0.4 says this about the top-level compatible (which, it
should be noted, is documented _separtely_ from section 2.3.1 since
all of section 2.3 is only about device nodes):

> Specifies a list of platform architectures with which this platform is compatible. This property can be used by operating systems in selecting platform specific code. The recommended form of the property value is: "manufacturer,model" For example: compatible = "fsl,mpc8572ds"

That's not very detailed, but I guess we can start out looking at what
it _doesn't_ say.

a) The spec doesn't say anything about the top-level compatible
uniquely identifying a specific hardware configuration. Nothing there
says "look at one of the strings in the list and you can tell exactly
what product you have in front of you".

b) The spec doesn't specifically mention that one should include any
strings for a SoC / SoM / reference board. Indeed, the example given
shows an example "compatible" with just one string: "fsl,mpc8572ds".
Searching the interwebs, I find that this example "compatible"
probably refers to a Freescale "MPC8572 Development System", which is
a dev board with a "MPC8572" chip. Notably, the example "compatible"
didn't include the "MPC8572" chip.

c) The spec doesn't seem to include a firm definition of what they
mean by the word "platform". In my mind, one could interpret the SoC
as a "platform". One could also interpret a SoM or a reference board
as a "platform". It's not necessarily clear. Since AI is the answer to
all things these days, I asked Gemini. I asked what "platform" meant
in the context of the DT spec and it (confidently) told me that "the
platform is the physical machine." ...but when I asked if one could
also consider the SoC the "platform", it told me that was "an
excellent clarifying question" and went on to say the SoC "is often
referred to as the base platform or the SoC-level platform." :-P


How does that help us? I guess I'd summarize that, from reading the
spec and more loosely interpreting the word "platform":

a) The compatible string doesn't _need_ to include strings
representing the SoC, SoM, or baseboard, but it can.

b) The compatible string is primarily there for use by the operating
system to select platform (board, reference board, SoM, or SoC)
specific code.


That still doesn't really tell us when we should / shouldn't include a
SoC / SoM / baseboard in the top-level "compatible". It also doesn't
tell us if we should include even more detailed levels. ...and by
"more detailed levels", I would perhaps say that each of these could
also be considered a "platform":
* google,trogdor-lazor-rev6-sku6 - An exact model of board.
* google,trogdor-lazor-rev6 - A platform that has several SKUs.
* google,trogdor-lazor - A platform that has several revisions and SKUs.
* google,trogdor - A reference platform that has several boards.


Perhaps we should lean into the statement "This property can be used
by operating systems in selecting platform specific code" to give us
guidance? The problem is that we somehow need to not just look at
current operating systems but, if we want to strive towards the goal
of shipping binary device trees, we need to consider future operating
system code that hasn't yet been written. That sounds impossible and
makes one think you should cram as much info into the compatible
string as possible, but...

...actually, we only need to put information into the compatible
string if there's not an easy way for the operating system to get the
information elsewhere, right? If the information is found elsewhere in
the device tree or if the operating system can probe the information
itself, then there's really no _need_ to put it in the top-level
"compatible" and we'll never end up painting ourselves into a corner.
We could still put the information there just to make it convenient,
but it's not really needed. Does this make sense?

I would further argue that, in order to be useful, any given
"platform" should document its expectations and we need to be
consistent across anyone using that platform. To make it concrete, if
the Qualcomm SC7180 platform documents that "qcom,sc7180" belongs in
the top-level compatible string then all device trees including sc7180
should have that string. This _doesn't_ mean that on some future
platform (like qcom,sc9999) we couldn't make a different decision.
Maybe on "qcom,sc9999" we've decided to put SoC details as some
properties under the "soc at 0" node. Now the operating system can find
the details about which SoC is present from the "soc at 0" node and
therefore we don't need to represent it in the top-level compatible
string.


Assuming that all makes sense, maybe the way to document the top-level
compatible string:

--

Specifies a list of "platform architectures" with which this platform
is compatible. A "platform architecture" can be at any level, from the
specific board to the class of board to the reference platform to the
SoM to the SoC. A given "platform architecture" should always be
consistently included or not-included by all final device trees using
it. If the "qcom,sc7180" SoC platform is defined to be included, it
should be consistently included by any device trees with this SoC. The
criteria for whether to represent a "platform architecture" in the
top-level compatible string is the difficulty of the operating system
obtaining the information in some other way (including from other DT
properties or from probing). In general, the top-level "compatible"
used by operating systems in selecting platform specific code. The
recommended form of the property value is: "manufacturer,model"

Examples:

compatible = "fsl,mpc8572ds";
- Select code related to the Freescale MPC8572 Development System

No platform is included for the CPU since ("fsl,mpc8572") isn't
consistently listed as a platform.

compatible = "google,snow-rev4", "google,snow", "samsung,exynos5250",
"samsung,exynos5"
- Select code related to google,snow-rev4.
- Select code related to google,snow.
- Select code related to samsung,exynos5250.
- Select code related to samsung,exynos5.

In this example, the idea is that all exynos5 boards would have
"samsung,exynos5" so code that needed to run on "exynos5" could
consistently test for that "compatible" string. Similarly, all
exynos5250 boards would have "samsung,exynos5250" and all snow boards
would have "google,snow"

--

What do folks think?

Note that the current Chromebook stuff [1] we used on sc7180-trogdor
boards doesn't fit amazingly well into that definition, but it can
kinda squeeze in there. Essentially the sc7180-trogdor stuff is
designed around making it easy for the bootloader to find the right
device tree but doesn't provide anything terribly useful to the OS in
the top-level "compatible" string. At this point, I don't think I
would encourage others to adopt something similar.


If folks agree with the above interpretation, I think I'd end up back
to arguing _against_ the need to merge compatible strings. If we don't
need to put detailed SoC information into the top-level compatible
string then we don't need to merge. I think the most
flexible/futureproof would be to just define that for the SoC inside
Pixel 10 (and presumably all future Google Silicon) we'll put SoC
information under the "soc at 0" node and thus there's no need to include
it in the top-level "compatible". That leaves us without a
"compatible" to put in the base "dtb", but maybe we can just put
compatible = "incomplete" or something like that?

I suspect that even for Russell's purposes the information can either
be probed by the OS or put in places other than the top-level
compatible string. We might not want to change his existing
devicetrees in case some OS is relying on the existing compatible
strings, but for work going forward it feels like it would be a
solution...


[1] https://docs.kernel.org/arch/arm/google/chromebook-boot-flow.html


-Doug


From dave.jiang at intel.com  Wed Dec  3 14:48:41 2025
From: dave.jiang at intel.com (Dave Jiang)
Date: Wed, 3 Dec 2025 15:48:41 -0700
Subject: [PATCH v2 1/2] dmaengine: Add cleanup FREE defines for
 dma_async_tx_descriptor
In-Reply-To: <20251003-dma_chan_free-v2-1-564946b6c563@nxp.com>
References: <20251003-dma_chan_free-v2-0-564946b6c563@nxp.com>
 <20251003-dma_chan_free-v2-1-564946b6c563@nxp.com>
Message-ID: <2c457a46-2b7f-4d66-8555-3b3cb52afe64@intel.com>



On 10/3/25 9:26 AM, Frank Li wrote:
> Add cleanup FREE defines for dma_async_tx_descriptor to support automatic
> cleanup and simplify error handling.
> 
> Signed-off-by: Frank Li <Frank.Li at nxp.com>
> ---
> Check patch report exceed 100 chars, but it's still better put into one
> line to keep consistent with other DEFINE_FREE and better readablity
> 
> change in v2
> - remove surpoiouse remove empty line
> ---
>  include/linux/dmaengine.h | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
> index 99efe2b9b4ea9844ca6161208362ef18ef111d96..27fa1646a807c49c781e1bce9e3e7d9a3c66f41d 100644
> --- a/include/linux/dmaengine.h
> +++ b/include/linux/dmaengine.h
> @@ -5,6 +5,7 @@
>  #ifndef LINUX_DMAENGINE_H
>  #define LINUX_DMAENGINE_H
>  
> +#include <linux/cleanup.h>
>  #include <linux/device.h>
>  #include <linux/err.h>
>  #include <linux/uio.h>
> @@ -1612,6 +1613,8 @@ static inline int dmaengine_desc_free(struct dma_async_tx_descriptor *desc)
>  	return desc->desc_free(desc);
>  }
>  
> +DEFINE_FREE(dma_async_tx_descriptor, struct dma_async_tx_descriptor *, if (_T) dmaengine_desc_free(_T))

maybe free_dma_async_tx may be clearer as the name vs dma_async_tx_descriptor.

DJ

> +
>  /* --- DMA device --- */
>  
>  int dma_async_device_register(struct dma_device *device);
> 



From dave.jiang at intel.com  Wed Dec  3 14:52:09 2025
From: dave.jiang at intel.com (Dave Jiang)
Date: Wed, 3 Dec 2025 15:52:09 -0700
Subject: [PATCH v2 2/2] i2c: lpi2c: Use cleanup helper for
 dma_async_tx_descriptor error handling
In-Reply-To: <20251003-dma_chan_free-v2-2-564946b6c563@nxp.com>
References: <20251003-dma_chan_free-v2-0-564946b6c563@nxp.com>
 <20251003-dma_chan_free-v2-2-564946b6c563@nxp.com>
Message-ID: <26b9cb6d-8370-4908-aed9-9c5b07e5fb82@intel.com>



On 10/3/25 9:26 AM, Frank Li wrote:
> Use the cleanup helper to simplify dma_async_tx_descriptor error handling.
> 
> No functional change.
> 
> Signed-off-by: Frank Li <Frank.Li at nxp.com>
> ---
> change v2
>  need goto unmap buffer.
> 
> desc_prepare_err_exit:
>         dma_unmap_single(txchan->device->dev, dma->dma_tx_addr,
>                          dma->rx_cmd_buf_len, DMA_TO_DEVICE);
>         return -EINVAL;
> 
> submit_err_exit:
>         dma_unmap_single(txchan->device->dev, dma->dma_tx_addr,
>                          dma->rx_cmd_buf_len, DMA_TO_DEVICE);
>         dmaengine_desc_free(rx_cmd_desc)
> 
> auto cleanup by __free, so whole error path submit_err_exit can be removed
> and use desc_prepare_err_exit label.
> ---
>  drivers/i2c/busses/i2c-imx-lpi2c.c | 11 +++--------
>  1 file changed, 3 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c
> index 03b5a7e8c361abe1d75fb4d31f9614bbc6387d93..e31c2d81f59f18a09d34f79896a7fa4bb83c0a12 100644
> --- a/drivers/i2c/busses/i2c-imx-lpi2c.c
> +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c
> @@ -722,7 +722,7 @@ static void lpi2c_dma_callback(void *data)
>  
>  static int lpi2c_dma_rx_cmd_submit(struct lpi2c_imx_struct *lpi2c_imx)
>  {
> -	struct dma_async_tx_descriptor *rx_cmd_desc;
> +	struct dma_async_tx_descriptor *rx_cmd_desc __free(dma_async_tx_descriptor) = NULL;
>  	struct lpi2c_imx_dma *dma = lpi2c_imx->dma;
>  	struct dma_chan *txchan = dma->chan_tx;
>  	dma_cookie_t cookie;
> @@ -746,10 +746,11 @@ static int lpi2c_dma_rx_cmd_submit(struct lpi2c_imx_struct *lpi2c_imx)
>  	cookie = dmaengine_submit(rx_cmd_desc);
>  	if (dma_submit_error(cookie)) {
>  		dev_err(&lpi2c_imx->adapter.dev, "submitting DMA failed, use pio\n");
> -		goto submit_err_exit;
> +		goto desc_prepare_err_exit;

Typically if you are introducing cleanup usage, you will want to remove all the goto usages. Otherwise it gets kinda messy having both styles. Although not sure how to do a cleanup macro with dma_unmap_*. Unless a local one where lpi2c_imx_dma also contains a ptr to the device. Then that may be doable. 

DJ>  	}
>  
>  	dma_async_issue_pending(txchan);
> +	retain_and_null_ptr(rx_cmd_desc);
>  
>  	return 0;
>  
> @@ -757,12 +758,6 @@ static int lpi2c_dma_rx_cmd_submit(struct lpi2c_imx_struct *lpi2c_imx)
>  	dma_unmap_single(txchan->device->dev, dma->dma_tx_addr,
>  			 dma->rx_cmd_buf_len, DMA_TO_DEVICE);
>  	return -EINVAL;
> -
> -submit_err_exit:
> -	dma_unmap_single(txchan->device->dev, dma->dma_tx_addr,
> -			 dma->rx_cmd_buf_len, DMA_TO_DEVICE);
> -	dmaengine_desc_free(rx_cmd_desc);
> -	return -EINVAL;
>  }
>  
>  static int lpi2c_dma_submit(struct lpi2c_imx_struct *lpi2c_imx)
> 



From robh at kernel.org  Wed Dec  3 14:52:33 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Wed, 3 Dec 2025 16:52:33 -0600
Subject: [PATCH 1/3] dt-bindings: display/ti: Simplify dma-coherent
 property
In-Reply-To: <20251115122120.35315-4-krzk@kernel.org>
References: <20251115122120.35315-4-krzk@kernel.org>
Message-ID: <176480235071.4159178.4317055893040212478.robh@kernel.org>


On Sat, 15 Nov 2025 13:21:21 +0100, Krzysztof Kozlowski wrote:
> Common boolean properties need to be only allowed in the binding
> (":true"), because their type is already defined by core DT schema.
> Simplify dma-coherent property to match common syntax.
> 
> Signed-off-by: Krzysztof Kozlowski <krzk at kernel.org>
> ---
>  Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml | 3 +--
>  Documentation/devicetree/bindings/display/ti/ti,j721e-dss.yaml | 3 +--
>  2 files changed, 2 insertions(+), 4 deletions(-)
> 

Applied, thanks!



From marek.vasut at mailbox.org  Wed Dec  3 14:53:41 2025
From: marek.vasut at mailbox.org (Marek Vasut)
Date: Wed, 3 Dec 2025 23:53:41 +0100
Subject: [PATCH 1/2] dt-bindings: firmware: arm,scmi: Document
 arm,poll-transport property
In-Reply-To: <20251203-thick-didactic-cockatoo-deaa1d@sudeepholla>
References: <20251023123644.8730-1-marek.vasut+renesas@mailbox.org>
 <aPoxfH_TLrsMxMVQ@pluto> <70554674-7020-4582-a4e7-dbee34907096@mailbox.org>
 <5ae0a793-d3e7-45d1-bf5c-3c46593d1824@mailbox.org> <aRW7BZimWdpq4TyX@pluto>
 <20251202-evasive-neon-rhino-d2745e@sudeepholla>
 <66257fcf-9024-454f-b776-4ba584963ebe@mailbox.org> <aS82GSN8c2SnRn4S@bogus>
 <8d773671-5e2e-4e21-ade6-2bf9a3b75066@mailbox.org>
 <20251203-thick-didactic-cockatoo-deaa1d@sudeepholla>
Message-ID: <4ccbcffd-bcc7-478b-a525-a4a11e3092ee@mailbox.org>

On 12/3/25 12:41 PM, Sudeep Holla wrote:

Hello Sudeep,

>>> Consider a system where a mailbox controller is present and one channel is
>>> used for SCMI communication, while another channel is used for an unrelated
>>> purpose. If both channels share the same interrupt line, and the other use
>>> case enables interrupt mode on its channel, what would be the impact on the
>>> SCMI-specific channel?
>>
>> None, SCMI kernel driver and SCMI server side would still do polling on
>> their respective SHMEM areas, while whatever kernel driver needs to receive
>> the interrupt notifications would subscribe to them using request_irq(),
>> right ?
>>
> 
> Fair enough. I was thinking if the controller manages to not call
> mbox_chan_received_data() in that case.

Wouldn't such a setup use separate mailbox channels , therefore even if 
mailbox driver calls mbox_chan_received_data(), it would be called for a 
specific mailbox channel , and it won't interfere with the SCMI mailbox 
channel.

> Also IIUC, the irq request happens
> as part of channel startup and there are no explicit APIs for the mbox client
> driver to control that. SCMI is mbox client in this case.

Sure, but the mailbox driver has to make sure it is correctly demuxing 
the IRQs it handles and correctly sends received_data notifications to 
the right channel(s) .

>>> I am aware of systems that implement such sharing, which is why I prefer to be
>>> explicit that this type of design is challenging to support within this
>>> binding. The intent is to support only minimal, constrained cases - essentially
>>> systems that are already somewhat broken. I do not see value in broadening the
>>> binding to cover every conceivable scenario.
>>>
>>>>> Clearly defining these constraints would be helpful. It may also be useful to
>>>>> note that this is primarily intended for mailbox transports, if that?s
>>>>> accurate. Alternatively, we could keep the DT binding definition broader but
>>>>> emit warnings when a transport other than mailbox is used. That approach might
>>>>> make it easier to move forward.
>>>>
>>>> DEN0056F refers to this polling mode in Shared memory based transports, that
>>>> can be other than mailbox transports, it includes e.g. SMC or OPTEE
>>>> transports.
>>>>
>>>
>>> However, polling does not make sense in the context of SMC. Once control
>>> returns from an SMC call, the command has completed. What form of polling in
>>> an SMC workflow do you have in mind?
>>
>> I think the polling happens on the SHMEM and the SMC transport is capable of
>> that too, see :
>>
>> drivers/firmware/arm_scmi/transports/smc.c
>>
>> 175         /*
>> 176          * If there is an interrupt named "a2p", then the service and
>> 177          * completion of a message is signaled by an interrupt rather
>> than by
>> 178          * the return of the SMC call.
>> 179          */
>> 180         scmi_info->irq = of_irq_get_byname(cdev->of_node, "a2p");
>>
> 
> Ah this one, is actually implemented to avoid sort of implicit polling
> mode we get with any SMC/HVC. I don't know how the platform deals with it
> but SMC/HVC is synchronous and doesn't need this polling. The irq introduced
> here is again a sort of workaround to get some sort of async/non-polling
> mode with SMC/HVC. So, to repeat polling mode make absolutely no sense
> whatsoever for SMC/OPTEE(based on pure SMC) transports.

I can drop the SMC part from this patch if you think that's helpful ?

>>> I believe the same applies to OP-TEE.
>>> While OP-TEE now provides a notification mechanism that could, in theory,
>>> allow synchronous commands to be treated in a quasi-asynchronous manner, I
>>> strongly doubt that the current SCMI-over-OP-TEE implementation behaves this
>>> way, given that it ultimately reaches the secure side via an SMC call.
>>>
>>>> I don't think a warning is justified, if the behavior follows the
>>>> specification. But I do agree the behavior is ... suboptimal.
>>>>
>>>
>>> The specification does not address SMC or OP-TEE transports, placing them
>>> outside its scope and likewise these DT bindings.
>>
>> I believe the shmem transport includes the SMC and OPTEE ones, right ?
>>
> 
> Yes, but the expectation when the SMC completes is to have the shmem to be
> owned by the OS(except that irq workaround case). Again the OPTEE/SMC is
> completely out of spec, but I agree the SHMEM behaviour must conform to the
> specification.

OK

>>> Consequently, what we
>>> decide here in this discussion effectively defines the expected behavior in
>>> this context, in my view. So I would like to start with minimal possible
>>> coverage, why do you think that is not a good idea here ?
>>
>> I would argue the current implementation covers pretty much every transport
>> which could ever need to do polling on shmem, so the implementation is
>> generic and inline with the specification. Also, the current implementation
>> is some 20 lines, so I think it is minimalistic?
>>
>> What would you propose we do here ?
>>
> 
> Yes it can be minimalistic but not restrictive. As I already clearly mentioned
> I don't see it makes any sense to enable this for SMC/OPTEE. Lets start with
> just mailbox to start with and extend to other transports if and when needed.
> It would be good to impose that restriction in the binding as well but that
> is not a must IMO. I am fine if the bindings for whatever reasons(though I
> don't see the need) to apply for any transport.
So I should simply drop the smc.c changes , keep the rest, and send V2 ?


From marek.vasut at mailbox.org  Wed Dec  3 14:48:47 2025
From: marek.vasut at mailbox.org (Marek Vasut)
Date: Wed, 3 Dec 2025 23:48:47 +0100
Subject: [PATCH] arm64: dts: imx95: Use GPU_CGC as core clock for GPU
In-Reply-To: <aTACuRjC_Zpf8IOU@oss.nxp.com>
References: <20251129143220.14834-1-marek.vasut@mailbox.org>
 <aS-lEibp3zTsaR6T@oss.nxp.com>
 <c6e0e55a-06da-4665-972e-e9b5b8c08bf7@mailbox.org>
 <aTACuRjC_Zpf8IOU@oss.nxp.com>
Message-ID: <de36091e-c890-4897-b3e3-2a7575029a5d@mailbox.org>

On 12/3/25 10:28 AM, Rain Yang wrote:

Hello Rain,

>>> Thanks for integrating this downstream patch.
>>
>> Which downstream patch do you refer to ?
>>
>>> Please note that CLK_GPUAPB and CLK_GPU are
>>> always-on, so the commit message should be amended accordingly.
>>
>> The GPU clock do not seem to be always-on, neither do the GPUAPB . It seems
>> the SM can turn those clock off perfectly well.
>>
>>> Additionally, the IMX95_CLK_GPUAPB handle shall be removed, as there is no valid OPP entry
>>> in the frequency table, this also helps minimize differences between downstream and upstream,
>>> reducing maintenance effort.
>>
>> Downstream kernel forks are not relevant to this discussion, upstream your
>> content and then you won't have to spend maintenance effort on downstream
>> stuff.
> 
> This patch [1] was the reference point.

Sigh ... I was not aware of that one.

Maybe next time, it would be good to upstream these changes directly ?

> For the Linux working environment,
> CLK_GPU and CLK_GPUAPB are always-on, while CLK_GPU_CGC can be gated off.
> 
> Regarding the IMX95_CLK_GPUAPB handle, my suggestion was based on the absence
> of its frequency in any OPP entry within the frequency table. Removing it
> could simplify the OPP handling logic and reduce unnecessary complexity.

If the clock can be disabled by SM, Linux has to make sure they are NOT 
disabled, so they must be described in DT, right ?

> [1] https://github.com/nxp-imx/linux-imx/commit/695f2bdc57b869ca5189313e4b5fa7eb5a12f622


-- 
Best regards,
Marek Vasut


From linusw at kernel.org  Wed Dec  3 15:20:14 2025
From: linusw at kernel.org (Linus Walleij)
Date: Thu, 4 Dec 2025 00:20:14 +0100
Subject: [PATCH] pinctrl: single: Fix incorrect type for error return variable
In-Reply-To: <20251203061347.381-1-vulab@iscas.ac.cn>
References: <20251203061347.381-1-vulab@iscas.ac.cn>
Message-ID: <CAD++jLnH-ZT+9YMxqZ=TV=0fatXSRcFkJMk-snEuRSMLdfD6PQ@mail.gmail.com>

On Wed, Dec 3, 2025 at 7:14?AM Haotian Zhang <vulab at iscas.ac.cn> wrote:

> pcs_pinconf_get() and pcs_pinconf_set() declare ret as unsigned int,
> but assign it the return values of pcs_get_function() that may return
> negative error codes. This causes negative error codes to be
> converted to large positive values.
>
> Change ret from unsigned int to int in both functions.
>
> Fixes: 9dddb4df90d1 ("pinctrl: single: support generic pinconf")
> Signed-off-by: Haotian Zhang <vulab at iscas.ac.cn>

Patch applied.
Thanks Haotian!

Yours,
Linus Walleij


From cristian.ciocaltea at collabora.com  Wed Dec  3 15:54:08 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Thu, 04 Dec 2025 01:54:08 +0200
Subject: [PATCH 0/2] Fixup HDMI PLL for phy-rockchip-samsung-hdptx
Message-ID: <20251204-phy-hdptx-pll-fix-v1-0-d94fd6cfd59b@collabora.com>

The Samsung HDMI/eDP TX PHY is currently not able to provide an accurate
enough PLL output frequency to match the TMDS rate of a 1080p at 120Hz
display mode, when used with 10 bpc RGB.

This patch set adds a new entry to the TMDS configuration table,
providing the necessary frequency division coefficients for the PHY PLL
to generate the expected 461.101250 MHz output.

Additionally, it drops a bunch of unused members from struct
ropll_config and makes the configuration table more readable.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
Cristian Ciocaltea (2):
      phy: rockchip: samsung-hdptx: Pre-compute HDMI PLL config for 461.10125 MHz output
      phy: rockchip: samsung-hdptx: Cleanup TMDS PLL config table

 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 79 +++++++----------------
 1 file changed, 24 insertions(+), 55 deletions(-)
---
base-commit: b2c27842ba853508b0da00187a7508eb3a96c8f7
change-id: 20251204-phy-hdptx-pll-fix-0787c92e0cfe



From cristian.ciocaltea at collabora.com  Wed Dec  3 15:54:09 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Thu, 04 Dec 2025 01:54:09 +0200
Subject: [PATCH 1/2] phy: rockchip: samsung-hdptx: Pre-compute HDMI PLL
 config for 461.10125 MHz output
In-Reply-To: <20251204-phy-hdptx-pll-fix-v1-0-d94fd6cfd59b@collabora.com>
References: <20251204-phy-hdptx-pll-fix-v1-0-d94fd6cfd59b@collabora.com>
Message-ID: <20251204-phy-hdptx-pll-fix-v1-1-d94fd6cfd59b@collabora.com>

Attempting to make use of the 1080p at 120Hz HDMI mode with 10 bpc RGB on
my Acer XV275K P3 monitor results in a blank image.  A similar behavior
has been reported on Philips 279M1RV.

The faulty modeline is created by drm_gtf_mode_complex() based on the
following EDID entry from the Standard Timings block:

  GTF:  1920x1080  119.999987 Hz  16:9    138.840 kHz    368.759000 MHz

It's worth noting the computed pixel clock ends up being slightly higher
at 368.881000 MHz.  Nevertheless, this seems to work consistently fine
with 8 bpc RGB.

After switching to 10 bpc, the TMDS character rate expected for the mode
increases to 461.101250 MHz, as per drm_hdmi_compute_mode_clock().

Since there is no entry for this rate in the ropll_tmds_cfg table, the
necessary HDMI PLL configuration parameters are calculated dynamically
by rk_hdptx_phy_clk_pll_calc().  However, the resulting output rate is
not quite a perfect match, i.e. 461.100000 MHz, that proved to be the
actual root cause of the problem.

Add a new entry to the TMDS configuration table and provide the
necessary frequency division coefficients for the PHY PLL to generate
the expected 461.101250 MHz output.

Fixes: 9d0ec51d7c22 ("phy: rockchip: samsung-hdptx: Add high color depth management")
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index 29de2f7bdae8..cafa618d70fd 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -414,6 +414,8 @@ struct rk_hdptx_phy {
 static const struct ropll_config ropll_tmds_cfg[] = {
 	{ 594000000ULL, 124, 124, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
 	  1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
+	{ 461101250ULL, 97, 97, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 71, 1, 53, 2, 6,
+	  35, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
 	{ 371250000ULL, 155, 155, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
 	  1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
 	{ 297000000ULL, 124, 124, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,

-- 
2.51.2



From cristian.ciocaltea at collabora.com  Wed Dec  3 15:54:10 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Thu, 04 Dec 2025 01:54:10 +0200
Subject: [PATCH 2/2] phy: rockchip: samsung-hdptx: Cleanup TMDS PLL config
 table
In-Reply-To: <20251204-phy-hdptx-pll-fix-v1-0-d94fd6cfd59b@collabora.com>
References: <20251204-phy-hdptx-pll-fix-v1-0-d94fd6cfd59b@collabora.com>
Message-ID: <20251204-phy-hdptx-pll-fix-v1-2-d94fd6cfd59b@collabora.com>

Drop a bunch of unused members from struct ropll_config and make the
static ropll_tmds_cfg table more readable:

* add a table header
* sort rows by rate
* convert hex values to decimal (for consistency)

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 81 +++++++----------------
 1 file changed, 24 insertions(+), 57 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index cafa618d70fd..4b9b36c50623 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -336,12 +336,7 @@ struct ropll_config {
 	u8 pms_pdiv;
 	u8 pms_refdiv;
 	u8 pms_sdiv;
-	u8 pms_iqdiv_rstn;
-	u8 ref_clk_sel;
 	u8 sdm_en;
-	u8 sdm_rstn;
-	u8 sdc_frac_en;
-	u8 sdc_rstn;
 	u8 sdm_clk_div;
 	u8 sdm_deno;
 	u8 sdm_num_sign;
@@ -349,14 +344,6 @@ struct ropll_config {
 	u8 sdc_n;
 	u8 sdc_num;
 	u8 sdc_deno;
-	u8 sdc_ndiv_rstn;
-	u8 ssc_en;
-	u8 ssc_fm_dev;
-	u8 ssc_fm_freq;
-	u8 ssc_clk_div_sel;
-	u8 ana_cpp_ctrl;
-	u8 ana_lpf_c_sel;
-	u8 cd_tx_ser_rate_sel;
 };
 
 struct tx_drv_ctrl {
@@ -412,50 +399,30 @@ struct rk_hdptx_phy {
 };
 
 static const struct ropll_config ropll_tmds_cfg[] = {
-	{ 594000000ULL, 124, 124, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
-	  1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 461101250ULL, 97, 97, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 71, 1, 53, 2, 6,
-	  35, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 371250000ULL, 155, 155, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
-	  1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 297000000ULL, 124, 124, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
-	  1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 162000000ULL, 135, 135, 1, 1, 3, 1, 1, 0, 1, 1, 1, 1, 4, 0, 3, 5, 5, 0x10,
-	  1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 185625000ULL, 155, 155, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
-	  1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 154000000ULL, 193, 193, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 193, 1, 32, 2, 1,
-	  1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 148500000ULL, 0x7b, 0x7b, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 4, 0, 3, 5, 5,
-	  0x10, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 146250000ULL, 122, 122, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 244, 1, 16, 2, 1, 1,
-	  1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 119000000ULL, 149, 149, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 149, 1, 16, 2, 1, 1,
-	  1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 106500000ULL, 89, 89, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 89, 1, 16, 1, 0, 1,
-	  1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 108000000ULL, 135, 135, 1, 1, 5, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0,
-	  0x14, 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 85500000ULL, 214, 214, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 214, 1, 16, 2, 1,
-	  1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 83500000ULL, 105, 105, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 42, 1, 16, 1, 0,
-	  1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 92812500ULL, 155, 155, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
-	  1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 74250000ULL, 124, 124, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
-	  1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 65000000ULL, 162, 162, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 54, 0, 16, 4, 1,
-	  1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 50250000ULL, 84, 84, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 11, 1, 4, 5,
-	  4, 11, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 33750000ULL, 0x70, 0x70, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 0x2, 0, 0x01, 5,
-	  1, 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 40000000ULL, 100, 100, 1, 1, 11, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0,
-	  0x14, 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 27000000ULL, 0x5a, 0x5a, 1, 1, 0xf, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0,
-	  0x14, 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 25175000ULL, 84, 84, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 168, 1, 16, 4, 1, 1,
-	  1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
+/*             |              pms             |            sdm           |      sdc     | */
+/*        rate, mdiv, mdafc, pdiv, rdiv, sdiv, en, cdiv, deno, nsig, num,   n, num, deno, */
+{ 594000000ULL,  124,   124,    1,    1,    0,  1,    1,   62,    1,  16,   5,   0,    1, },
+{ 461101250ULL,   97,    97,    1,    1,    0,  1,    1,   71,    1,  53,   2,   6,   35, },
+{ 371250000ULL,  155,   155,    1,    1,    1,  1,    1,   62,    1,  16,   5,   0,    1, },
+{ 297000000ULL,  124,   124,    1,    1,    1,  1,    1,   62,    1,  16,   5,   0,    1, },
+{ 185625000ULL,  155,   155,    1,    1,    3,  1,    1,   62,    1,  16,   5,   0,    1, },
+{ 162000000ULL,  135,   135,    1,    1,    3,  0,    1,    4,    0,   3,   5,   5,   16, },
+{ 154000000ULL,  193,   193,    1,    1,    5,  1,    1,  193,    1,  32,   2,   1,    1, },
+{ 148500000ULL,  123,   123,    1,    1,    3,  1,    1,    4,    0,   3,   5,   5,   16, },
+{ 146250000ULL,  122,   122,    1,    1,    3,  1,    1,  244,    1,  16,   2,   1,    1, },
+{ 119000000ULL,  149,   149,    1,    1,    5,  1,    1,  149,    1,  16,   2,   1,    1, },
+{ 106500000ULL,   89,    89,    1,    1,    3,  1,    1,   89,    1,  16,   1,   0,    1, },
+{ 108000000ULL,  135,   135,    1,    1,    5,  0,    1,    9,    0,   5,   0,  20,   24, },
+{  92812500ULL,  155,   155,    1,    1,    7,  1,    1,   62,    1,  16,   5,   0,    1, },
+{  85500000ULL,  214,   214,    1,    1,   11,  1,    1,  214,    1,  16,   2,   1,    1, },
+{  83500000ULL,  105,   105,    1,    1,    5,  1,    1,   42,    1,  16,   1,   0,    1, },
+{  74250000ULL,  124,   124,    1,    1,    7,  1,    1,   62,    1,  16,   5,   0,    1, },
+{  65000000ULL,  162,   162,    1,    1,   11,  1,    1,   54,    0,  16,   4,   1,    1, },
+{  50250000ULL,   84,    84,    1,    1,    7,  1,    1,   11,    1,   4,   5,   4,   11, },
+{  40000000ULL,  100,   100,    1,    1,   11,  0,    1,    9,    0,   5,   0,  20,   24, },
+{  33750000ULL,  112,   112,    1,    1,   15,  1,    1,    2,    0,   1,   5,   1,    1, },
+{  27000000ULL,   90,    90,    1,    1,   15,  0,    1,    9,    0,   5,   0,  20,   24, },
+{  25175000ULL,   84,    84,    1,    1,   15,  1,    1,  168,    1,  16,   4,   1,    1, },
 };
 
 static const struct reg_sequence rk_hdtpx_common_cmn_init_seq[] = {

-- 
2.51.2



From dmatlack at google.com  Wed Dec  3 16:04:47 2025
From: dmatlack at google.com (David Matlack)
Date: Wed, 3 Dec 2025 16:04:47 -0800
Subject: [PATCH 00/10] KVM: selftests: Convert to kernel-style types
In-Reply-To: <aRZ9SQ_G2lsmXtur@google.com>
References: <20250501183304.2433192-1-dmatlack@google.com> <aBPhs39MJz-rt_Ob@google.com>
 <CALzav=eqv0Fh9pzaBgjZ-fehwFbD4YscoLQz0=o0TKQT_zLTwQ@mail.gmail.com> <aRZ9SQ_G2lsmXtur@google.com>
Message-ID: <CALzav=fN4FpZsfzwbdLeNSj4nx4OpRkwHvKiZNVgP8S-zsUvJA@mail.gmail.com>

On Thu, Nov 13, 2025 at 4:52?PM Sean Christopherson <seanjc at google.com> wrote:
>
> On Fri, Oct 17, 2025, David Matlack wrote:
> > On Thu, May 1, 2025 at 2:03?PM Sean Christopherson <seanjc at google.com> wrote:
> > > On Thu, May 01, 2025, David Matlack wrote:
> > > > This series renames types across all KVM selftests to more align with
> > > > types used in the kernel:
> > > >
> > > >   vm_vaddr_t -> gva_t
> > > >   vm_paddr_t -> gpa_t
> > >
> > > 10000% on these.
> > >
> > > >   uint64_t -> u64
> > > >   uint32_t -> u32
> > > >   uint16_t -> u16
> > > >   uint8_t  -> u8
> > > >
> > > >   int64_t -> s64
> > > >   int32_t -> s32
> > > >   int16_t -> s16
> > > >   int8_t  -> s8
> > >
> > > I'm definitely in favor of these renames.  I thought I was the only one that
> > > tripped over the uintNN_t stuff; at this point, I've probably lost hours of my
> > > life trying to type those things out.
> >
> > What should the next step be here? I'd be happy to spin a new version
> > whenever on whatever base commit you prefer.
>
> Sorry for the slow reply, I've had this window sitting open for something like
> two weeks.

No worries, thanks for taking a look :)

>
> My slowness is largely because I'm not sure how to land/approach this.  I'm 100%
> in favor of the renames, it's the timing and coordination I'm unsure of.
>
> In hindsight, it probably would have best to squeeze it into 6.18, so at least
> the most recent LTS wouldn't generate conflicts all over the place.  The next
> best option would probably be to spin a new version, bribe Paolo to apply it at
> the end of the next merge window, and tag the whole thing for stable@ (maybe
> limited to 6.18+?) to minimize downstream pain.

With LPC coming up I won't have cycles to post a new version before
the 6.19 merge window closes.

I'm tempted to say let's just wait for the next LTS release and merge
it in then. This is low priorit, so I'm fine with waiting.


From andrew at codeconstruct.com.au  Wed Dec  3 16:29:56 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Thu, 04 Dec 2025 10:59:56 +1030
Subject: [PATCH v5 0/2] Add device tree for NVIDIA BMC MSX4 CX8
 switchboard
In-Reply-To: <20251126-msx1_devicetree-v5-0-e508d13e2dda@nvidia.com>
References: <20251126-msx1_devicetree-v5-0-e508d13e2dda@nvidia.com>
Message-ID: <176480819607.976941.8757303196020007882.b4-ty@codeconstruct.com.au>

On Wed, 26 Nov 2025 16:43:05 -0800, Marc Olberding wrote:
> Patch 1 Adds the binding for the MSX4 CX8 switchboard
> Patch 2 Adds the device tree for the MSX4 CX8 switchboard reference implementation.
> 
> This is an Aspeed AST2600 based reference implementation for a BMC
> managing the NVIDIA MGX CX8 switchboard.
> 
> Reference to Ast2600 Soc [1].
> Reference to host architecture [2].
> 
> [...]

Thanks, I've applied this to the BMC tree.

-- 
Andrew Jeffery <andrew at codeconstruct.com.au>



From jacob.e.keller at intel.com  Wed Dec  3 16:37:11 2025
From: jacob.e.keller at intel.com (Jacob Keller)
Date: Wed, 3 Dec 2025 16:37:11 -0800
Subject: [PATCH] net: stmmac: fix oops when split header is enabled
In-Reply-To: <20251202025421.4560-1-jie.zhang@analog.com>
References: <20251202025421.4560-1-jie.zhang@analog.com>
Message-ID: <662d0fc5-7071-4190-903b-cf37f5a91adc@intel.com>



On 12/1/2025 6:54 PM, Jie Zhang wrote:
> For GMAC4, when split header is enabled, in some rare cases, the
> hardware does not fill buf2 of the first descriptor with payload.
> Thus we cannot assume buf2 is always fully filled if it is not
> the last descriptor. Otherwise, the length of buf2 of the second
> descriptor will be calculated wrong and cause an oops:
> 
> Unable to handle kernel paging request at virtual address ffff00019246bfc0
> Mem abort info:
>   ESR = 0x0000000096000145
>   EC = 0x25: DABT (current EL), IL = 32 bits
>   SET = 0, FnV = 0
>   EA = 0, S1PTW = 0
>   FSC = 0x05: level 1 translation fault
> Data abort info:
>   ISV = 0, ISS = 0x00000145, ISS2 = 0x00000000
>   CM = 1, WnR = 1, TnD = 0, TagAccess = 0
>   GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
> swapper pgtable: 4k pages, 48-bit VAs, pgdp=0000000090d8b000
> [ffff00019246bfc0] pgd=180000009dfff403, p4d=180000009dfff403, pud=0000000000000000
> Internal error: Oops: 0000000096000145 [#1]  SMP
> Modules linked in:
> CPU: 0 UID: 0 PID: 157 Comm: iperf3 Not tainted 6.18.0-rc6 #1 PREEMPT
> Hardware name: ADI 64-bit SC598 SOM EZ Kit (DT)
> pstate: 00400009 (nzcv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
> pc : dcache_inval_poc+0x28/0x58
> lr : arch_sync_dma_for_cpu+0x28/0x34
> sp : ffff800080dcbc40
> x29: ffff800080dcbc40 x28: 0000000000000008 x27: ffff000091c50980
> x26: ffff000091c50980 x25: 0000000000000000 x24: ffff000092a5fb00
> x23: ffff000092768f28 x22: 000000009246c000 x21: 0000000000000002
> x20: 00000000ffffffdc x19: ffff000091844c10 x18: 0000000000000000
> x17: ffff80001d308000 x16: ffff800080dc8000 x15: ffff0000929fb034
> x14: 70f709157374dd21 x13: ffff000092812ec0 x12: 0000000000000000
> x11: 000000000000dd86 x10: 0000000000000040 x9 : 0000000000000600
> x8 : ffff000092a5fbac x7 : 0000000000000001 x6 : 0000000000004240
> x5 : 000000009246c000 x4 : ffff000091844c10 x3 : 000000000000003f
> x2 : 0000000000000040 x1 : ffff00019246bfc0 x0 : ffff00009246c000
> Call trace:
>  dcache_inval_poc+0x28/0x58 (P)
>  dma_direct_sync_single_for_cpu+0x38/0x6c
>  __dma_sync_single_for_cpu+0x34/0x6c
>  stmmac_napi_poll_rx+0x8f0/0xb60
>  __napi_poll.constprop.0+0x30/0x144
>  net_rx_action+0x160/0x274
>  handle_softirqs+0x1b8/0x1fc
>  __do_softirq+0x10/0x18
>  ____do_softirq+0xc/0x14
>  call_on_irq_stack+0x30/0x48
>  do_softirq_own_stack+0x18/0x20
>  __irq_exit_rcu+0x64/0xe8
>  irq_exit_rcu+0xc/0x14
>  el1_interrupt+0x3c/0x58
>  el1h_64_irq_handler+0x14/0x1c
>  el1h_64_irq+0x6c/0x70
>  __arch_copy_to_user+0xbc/0x240 (P)
>  simple_copy_to_iter+0x28/0x30
>  __skb_datagram_iter+0x1bc/0x268
>  skb_copy_datagram_iter+0x1c/0x24
>  tcp_recvmsg_locked+0x3ec/0x778
>  tcp_recvmsg+0x10c/0x194
>  inet_recvmsg+0x64/0xa0
>  sock_recvmsg_nosec+0x1c/0x24
>  sock_read_iter+0x8c/0xdc
>  vfs_read+0x144/0x1a0
>  ksys_read+0x74/0xdc
>  __arm64_sys_read+0x14/0x1c
>  invoke_syscall+0x60/0xe4
>  el0_svc_common.constprop.0+0xb0/0xcc
>  do_el0_svc+0x18/0x20
>  el0_svc+0x80/0xc8
>  el0t_64_sync_handler+0x58/0x134
>  el0t_64_sync+0x170/0x174
> Code: d1000443 ea03003f 8a230021 54000040 (d50b7e21)
> ---[ end trace 0000000000000000 ]---
> Kernel panic - not syncing: Oops: Fatal exception in interrupt
> Kernel Offset: disabled
> CPU features: 0x080000,00008000,08006281,0400520b
> Memory Limit: none
> ---[ end Kernel panic - not syncing: Oops: Fatal exception in interrupt ]---
> 

You could probably minify the crash here a bit since much of this
information isn't that helpful in showing the crash. Not too big a deal
overall.

> To fix this, the PL bit-field in RDES3 register is used for all
> descriptors, whether it is the last descriptor or not.
> 
> Signed-off-by: Jie Zhang <jie.zhang at analog.com>


Reviewed-by: Jacob Keller <jacob.e.keller at intel.com>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature.asc
Type: application/pgp-signature
Size: 236 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251203/660e0ff9/attachment-0001.sig>

From jacob.e.keller at intel.com  Wed Dec  3 16:50:31 2025
From: jacob.e.keller at intel.com (Jacob Keller)
Date: Wed, 3 Dec 2025 16:50:31 -0800
Subject: [PATCH RFC net-next 00/15] net: stmmac: rk: cleanups galore
In-Reply-To: <aS3EfuypsaGK6Ww_@shell.armlinux.org.uk>
References: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
 <05db9d3e-88fa-42db-8731-b77039c60efa@lunn.ch>
 <aS3EfuypsaGK6Ww_@shell.armlinux.org.uk>
Message-ID: <53d0efe0-f970-49ed-939b-d3a53dc7db86@intel.com>



On 12/1/2025 8:38 AM, Russell King (Oracle) wrote:
> So, in future, I'm going to take the attitude that I will NAK
> contributions if I think there's a side issue that the contributor
> should also be addressing until that side issue is addressed.
> 
> This shouldn't be necessary, I wish this weren't necessary, and I wish
> people could be relied upon to do the right thing, but apparently it is
> going to take a stick (not merging their patches) to get them to co-
> operate. More fool me for trusting someone to do something.
> 

Yep this is unfortunately a reality of dealing with many contributors.
While its frustrating to require this.. If you don't, and end up never
getting things fixed the end result is worse.

As a maintainer, sometimes the only leverage you have is when someone
wants a contribution to merge. Balancing so that relevant improvements
and work get done while not being so harsh that contributors stop
returning is a difficult problem.

> I now have a couple of extra patches addressing my point raised in
> that email... which I myself shouldn't have had to write.
> 

:(
-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature.asc
Type: application/pgp-signature
Size: 236 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251203/b6becdae/attachment.sig>

From jacob.e.keller at intel.com  Wed Dec  3 16:51:59 2025
From: jacob.e.keller at intel.com (Jacob Keller)
Date: Wed, 3 Dec 2025 16:51:59 -0800
Subject: [PATCH RFC net-next 00/15] net: stmmac: rk: cleanups galore
In-Reply-To: <aS3F36UAkeLfFeHx@shell.armlinux.org.uk>
References: <aS2rFBlz1jdwXaS8@shell.armlinux.org.uk>
 <aS3F36UAkeLfFeHx@shell.armlinux.org.uk>
Message-ID: <60b8ac3f-cad4-4aa7-bcf1-230f2067cc77@intel.com>



On 12/1/2025 8:44 AM, Russell King (Oracle) wrote:
> Again, I don't like this foo_enable() / foo_power_on() pattern with
> a true/false argument - when false, the function is not enabling
> nor "on"-ing, but disabling or "off"-ing. So, gmac_clk_enable() is
> going to get split up and renamed.
> 

Agreed, removing this anti-pattern is good. It makes the logic more
difficult to follow and understand than well named functions.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature.asc
Type: application/pgp-signature
Size: 236 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251203/5dd8ffb3/attachment-0001.sig>

From Frank.li at nxp.com  Wed Dec  3 17:27:53 2025
From: Frank.li at nxp.com (Frank Li)
Date: Wed, 3 Dec 2025 20:27:53 -0500
Subject: [PATCH v2 2/2] i2c: lpi2c: Use cleanup helper for
 dma_async_tx_descriptor error handling
In-Reply-To: <26b9cb6d-8370-4908-aed9-9c5b07e5fb82@intel.com>
References: <20251003-dma_chan_free-v2-0-564946b6c563@nxp.com>
 <20251003-dma_chan_free-v2-2-564946b6c563@nxp.com>
 <26b9cb6d-8370-4908-aed9-9c5b07e5fb82@intel.com>
Message-ID: <aTDjmdfUk94R3Dyk@lizhi-Precision-Tower-5810>

On Wed, Dec 03, 2025 at 03:52:09PM -0700, Dave Jiang wrote:
>
>
> On 10/3/25 9:26 AM, Frank Li wrote:
> > Use the cleanup helper to simplify dma_async_tx_descriptor error handling.
> >
> > No functional change.
> >
> > Signed-off-by: Frank Li <Frank.Li at nxp.com>
> > ---
> > change v2
> >  need goto unmap buffer.
> >
> > desc_prepare_err_exit:
> >         dma_unmap_single(txchan->device->dev, dma->dma_tx_addr,
> >                          dma->rx_cmd_buf_len, DMA_TO_DEVICE);
> >         return -EINVAL;
> >
> > submit_err_exit:
> >         dma_unmap_single(txchan->device->dev, dma->dma_tx_addr,
> >                          dma->rx_cmd_buf_len, DMA_TO_DEVICE);
> >         dmaengine_desc_free(rx_cmd_desc)
> >
> > auto cleanup by __free, so whole error path submit_err_exit can be removed
> > and use desc_prepare_err_exit label.
> > ---
> >  drivers/i2c/busses/i2c-imx-lpi2c.c | 11 +++--------
> >  1 file changed, 3 insertions(+), 8 deletions(-)
> >
> > diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c
> > index 03b5a7e8c361abe1d75fb4d31f9614bbc6387d93..e31c2d81f59f18a09d34f79896a7fa4bb83c0a12 100644
> > --- a/drivers/i2c/busses/i2c-imx-lpi2c.c
> > +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c
> > @@ -722,7 +722,7 @@ static void lpi2c_dma_callback(void *data)
> >
> >  static int lpi2c_dma_rx_cmd_submit(struct lpi2c_imx_struct *lpi2c_imx)
> >  {
> > -	struct dma_async_tx_descriptor *rx_cmd_desc;
> > +	struct dma_async_tx_descriptor *rx_cmd_desc __free(dma_async_tx_descriptor) = NULL;
> >  	struct lpi2c_imx_dma *dma = lpi2c_imx->dma;
> >  	struct dma_chan *txchan = dma->chan_tx;
> >  	dma_cookie_t cookie;
> > @@ -746,10 +746,11 @@ static int lpi2c_dma_rx_cmd_submit(struct lpi2c_imx_struct *lpi2c_imx)
> >  	cookie = dmaengine_submit(rx_cmd_desc);
> >  	if (dma_submit_error(cookie)) {
> >  		dev_err(&lpi2c_imx->adapter.dev, "submitting DMA failed, use pio\n");
> > -		goto submit_err_exit;
> > +		goto desc_prepare_err_exit;
>
> Typically if you are introducing cleanup usage, you will want to remove all the goto usages. Otherwise it gets kinda messy having both styles. Although not sure how to do a cleanup macro with dma_unmap_*. Unless a local one where lpi2c_imx_dma also contains a ptr to the device. Then that may be doable.

dma_unmap() patch at
https://lore.kernel.org/imx/aPZbuY5bLpkoO2J%2F at lizhi-Precision-Tower-5810/

The first patch need be pickup and dma umap firstly.  Then I can remove all
goto.

Frank

>
> DJ>  	}
> >
> >  	dma_async_issue_pending(txchan);
> > +	retain_and_null_ptr(rx_cmd_desc);
> >
> >  	return 0;
> >
> > @@ -757,12 +758,6 @@ static int lpi2c_dma_rx_cmd_submit(struct lpi2c_imx_struct *lpi2c_imx)
> >  	dma_unmap_single(txchan->device->dev, dma->dma_tx_addr,
> >  			 dma->rx_cmd_buf_len, DMA_TO_DEVICE);
> >  	return -EINVAL;
> > -
> > -submit_err_exit:
> > -	dma_unmap_single(txchan->device->dev, dma->dma_tx_addr,
> > -			 dma->rx_cmd_buf_len, DMA_TO_DEVICE);
> > -	dmaengine_desc_free(rx_cmd_desc);
> > -	return -EINVAL;
> >  }
> >
> >  static int lpi2c_dma_submit(struct lpi2c_imx_struct *lpi2c_imx)
> >
>


From Frank.li at nxp.com  Wed Dec  3 17:30:32 2025
From: Frank.li at nxp.com (Frank Li)
Date: Wed, 3 Dec 2025 20:30:32 -0500
Subject: [PATCH v2 1/2] dmaengine: Add cleanup FREE defines for
 dma_async_tx_descriptor
In-Reply-To: <2c457a46-2b7f-4d66-8555-3b3cb52afe64@intel.com>
References: <20251003-dma_chan_free-v2-0-564946b6c563@nxp.com>
 <20251003-dma_chan_free-v2-1-564946b6c563@nxp.com>
 <2c457a46-2b7f-4d66-8555-3b3cb52afe64@intel.com>
Message-ID: <aTDkODHZg0JfrZJC@lizhi-Precision-Tower-5810>

On Wed, Dec 03, 2025 at 03:48:41PM -0700, Dave Jiang wrote:
>
>
> On 10/3/25 9:26 AM, Frank Li wrote:
> > Add cleanup FREE defines for dma_async_tx_descriptor to support automatic
> > cleanup and simplify error handling.
> >
> > Signed-off-by: Frank Li <Frank.Li at nxp.com>
> > ---
> > Check patch report exceed 100 chars, but it's still better put into one
> > line to keep consistent with other DEFINE_FREE and better readablity
> >
> > change in v2
> > - remove surpoiouse remove empty line
> > ---
> >  include/linux/dmaengine.h | 3 +++
> >  1 file changed, 3 insertions(+)
> >
> > diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
> > index 99efe2b9b4ea9844ca6161208362ef18ef111d96..27fa1646a807c49c781e1bce9e3e7d9a3c66f41d 100644
> > --- a/include/linux/dmaengine.h
> > +++ b/include/linux/dmaengine.h
> > @@ -5,6 +5,7 @@
> >  #ifndef LINUX_DMAENGINE_H
> >  #define LINUX_DMAENGINE_H
> >
> > +#include <linux/cleanup.h>
> >  #include <linux/device.h>
> >  #include <linux/err.h>
> >  #include <linux/uio.h>
> > @@ -1612,6 +1613,8 @@ static inline int dmaengine_desc_free(struct dma_async_tx_descriptor *desc)
> >  	return desc->desc_free(desc);
> >  }
> >
> > +DEFINE_FREE(dma_async_tx_descriptor, struct dma_async_tx_descriptor *, if (_T) dmaengine_desc_free(_T))
>
> maybe free_dma_async_tx may be clearer as the name vs dma_async_tx_descriptor.

If that, 'dmaengine_desc_free' is better because avoid create new name for
it.

Frank
>
> DJ
>
> > +
> >  /* --- DMA device --- */
> >
> >  int dma_async_device_register(struct dma_device *device);
> >
>


From jie.gan at oss.qualcomm.com  Wed Dec  3 18:45:21 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Thu, 4 Dec 2025 10:45:21 +0800
Subject: [PATCH v6 1/9] coresight: core: Refactoring ctcu_get_active_port
 and make it generic
In-Reply-To: <29a61f75-df0b-41da-9c8d-3e2ced0a9ce7@arm.com>
References: <20250908-enable-byte-cntr-for-tmc-v6-0-1db9e621441a@oss.qualcomm.com>
 <20250908-enable-byte-cntr-for-tmc-v6-1-1db9e621441a@oss.qualcomm.com>
 <29a61f75-df0b-41da-9c8d-3e2ced0a9ce7@arm.com>
Message-ID: <156d7def-364d-4fbf-b63f-99e1de657f93@oss.qualcomm.com>



On 12/4/2025 12:18 AM, Suzuki K Poulose wrote:
> On 08/09/2025 03:01, Jie Gan wrote:
>> Remove ctcu_get_active_port from CTCU module and add it to the core
>> framework.
>>
>> The port number is crucial for the CTCU device to identify which ETR
>> it serves. With the port number we can correctly get required parameters
>> of the CTCU device in TMC module.
>>
>> Reviewed-by: Mike Leach <mike.leach at linaro.org>
>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> ---
>> ? drivers/hwtracing/coresight/coresight-core.c????? | 24 +++++++++++++ 
>> ++++++++++
>> ? drivers/hwtracing/coresight/coresight-ctcu-core.c | 19 
>> +-----------------
>> ? drivers/hwtracing/coresight/coresight-priv.h????? |? 2 ++
>> ? 3 files changed, 27 insertions(+), 18 deletions(-)
>>
>> diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/ 
>> hwtracing/coresight/coresight-core.c
>> index 1accd7cbd54b..042c4fa39e55 100644
>> --- a/drivers/hwtracing/coresight/coresight-core.c
>> +++ b/drivers/hwtracing/coresight/coresight-core.c
>> @@ -580,6 +580,30 @@ struct coresight_device 
>> *coresight_get_sink(struct coresight_path *path)
>> ? }
>> ? EXPORT_SYMBOL_GPL(coresight_get_sink);
>> +/**
>> + * coresight_get_in_port_dest: get the in-port number of the dest device
>> + * that is connected to the src device.
>> + *
>> + * @src: csdev of the source device.
>> + * @dest: csdev of the destination device.
>> + *
>> + * Return: port number upon success or -EINVAL for fail.
>> + */
>> +int coresight_get_in_port_dest(struct coresight_device *src,
> 
> Please could we make this more explicit :
> 
>  ????/*
>  ???? * Find the input port number at @csdev where a @remote
>  ???? * device is connected to.
>  ???? */
>  ????coresight_get_in_port(struct coresight_device *csdev,
>  ????????????????? struct coresight_device *remote)
>  ????{
> 
>  ????}

Hi Suzuki

That's make sense for me, will update in next version.

Thanks,
Jie

> Suzuki
> 
> 



From jie.gan at oss.qualcomm.com  Wed Dec  3 18:47:15 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Thu, 4 Dec 2025 10:47:15 +0800
Subject: [PATCH v6 2/9] coresight: core: add a new API to retrieve the
 helper device
In-Reply-To: <d8c6111f-28ba-4046-bcd5-67233e8ed4ca@arm.com>
References: <20250908-enable-byte-cntr-for-tmc-v6-0-1db9e621441a@oss.qualcomm.com>
 <20250908-enable-byte-cntr-for-tmc-v6-2-1db9e621441a@oss.qualcomm.com>
 <d8c6111f-28ba-4046-bcd5-67233e8ed4ca@arm.com>
Message-ID: <d5f1dd06-1c53-4656-882b-dbf771e3a125@oss.qualcomm.com>



On 12/4/2025 12:15 AM, Suzuki K Poulose wrote:
> On 08/09/2025 03:01, Jie Gan wrote:
>> Retrieving the helper device of the specific coresight device based on
>> its helper_subtype because a single coresight device may has multiple 
>> types
>> of the helper devices.
>>
>> Reviewed-by: Mike Leach <mike.leach at linaro.org>
>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> ---
>> ? drivers/hwtracing/coresight/coresight-core.c | 35 ++++++++++++++++++ 
>> ++++++++++
>> ? drivers/hwtracing/coresight/coresight-priv.h |? 2 ++
>> ? 2 files changed, 37 insertions(+)
>>
>> diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/ 
>> hwtracing/coresight/coresight-core.c
>> index 042c4fa39e55..018b1119c48a 100644
>> --- a/drivers/hwtracing/coresight/coresight-core.c
>> +++ b/drivers/hwtracing/coresight/coresight-core.c
>> @@ -580,6 +580,41 @@ struct coresight_device 
>> *coresight_get_sink(struct coresight_path *path)
>> ? }
>> ? EXPORT_SYMBOL_GPL(coresight_get_sink);
>> +/**
>> + * coresight_get_helper: find the helper device of the assigned csdev.
>> + *
>> + * @csdev: The csdev the helper device is conntected to.
>> + * @type:? helper_subtype of the expected helper device.
>> + *
>> + * Retrieve the helper device for the specific csdev based on its
>> + * helper_subtype.
>> + *
>> + * Return: the helper's csdev upon success or NULL for fail.
>> + */
>> +struct coresight_device *coresight_get_helper(struct coresight_device 
>> *csdev,
> 
>> +????????????????????????? int type)
> 
> nit: enum coresight_dev_subtype_helper subtype
> 
> Otherwise looks good to me

Will update in next version.

Thanks,
Jie

> 
> Suzuki
> 
>> +{
>> +??? int i;
>> +??? struct coresight_device *helper;
>> +
>> +??? /* protect the connections */
>> +??? mutex_lock(&coresight_mutex);
>> +??? for (i = 0; i < csdev->pdata->nr_outconns; ++i) {
>> +??????? helper = csdev->pdata->out_conns[i]->dest_dev;
>> +??????? if (!helper || !coresight_is_helper(helper))
>> +??????????? continue;
>> +
>> +??????? if (helper->subtype.helper_subtype == type) {
>> +??????????? mutex_unlock(&coresight_mutex);
>> +??????????? return helper;
>> +??????? }
>> +??? }
>> +??? mutex_unlock(&coresight_mutex);
>> +
>> +??? return NULL;
>> +}
>> +EXPORT_SYMBOL_GPL(coresight_get_helper);
>> +
>> ? /**
>> ?? * coresight_get_in_port_dest: get the in-port number of the dest 
>> device
>> ?? * that is connected to the src device.
>> diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/ 
>> hwtracing/coresight/coresight-priv.h
>> index e51b22b8ebde..f80122827934 100644
>> --- a/drivers/hwtracing/coresight/coresight-priv.h
>> +++ b/drivers/hwtracing/coresight/coresight-priv.h
>> @@ -158,6 +158,8 @@ void coresight_path_assign_trace_id(struct 
>> coresight_path *path,
>> ???????????????????? enum cs_mode mode);
>> ? int coresight_get_in_port_dest(struct coresight_device *src,
>> ???????????????????? struct coresight_device *dest);
>> +struct coresight_device *coresight_get_helper(struct coresight_device 
>> *csdev,
>> +????????????????????????? int type);
>> ? #if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM3X)
>> ? int etm_readl_cp14(u32 off, unsigned int *val);
>>
> 
> 



From jie.gan at oss.qualcomm.com  Wed Dec  3 18:49:26 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Thu, 4 Dec 2025 10:49:26 +0800
Subject: [PATCH v6 6/9] dt-bindings: arm: add an interrupt property for
 Coresight CTCU
In-Reply-To: <CAJ9a7VitqEix7dumLq2ND=6+PU_eCkm8=YkHB0n7iHdJ8iKeVA@mail.gmail.com>
References: <20250908-enable-byte-cntr-for-tmc-v6-0-1db9e621441a@oss.qualcomm.com>
 <20250908-enable-byte-cntr-for-tmc-v6-6-1db9e621441a@oss.qualcomm.com>
 <CAJ9a7VitqEix7dumLq2ND=6+PU_eCkm8=YkHB0n7iHdJ8iKeVA@mail.gmail.com>
Message-ID: <dd87fd82-9ea7-4205-88b2-1af2eaadac06@oss.qualcomm.com>



On 12/3/2025 10:30 PM, Mike Leach wrote:
> On Mon, 8 Sept 2025 at 03:02, Jie Gan <jie.gan at oss.qualcomm.com> wrote:
>>
>> Add an interrupt property to CTCU device. The interrupt will be triggered
>> when the data size in the ETR buffer exceeds the threshold of the
>> BYTECNTRVAL register. Programming a threshold in the BYTECNTRVAL register
>> of CTCU device will enable the interrupt.
>>
>> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> ---
>>   .../devicetree/bindings/arm/qcom,coresight-ctcu.yaml    | 17 +++++++++++++++++
>>   1 file changed, 17 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
>> index 843b52eaf872..ea05ad8f3dd3 100644
>> --- a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
>> +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
>> @@ -39,6 +39,16 @@ properties:
>>       items:
>>         - const: apb
>>
>> +  interrupts:
>> +    items:
>> +      - description: Byte cntr interrupt for etr0
>> +      - description: Byte cntr interrupt for etr1
>> +
>> +  interrupt-names:
>> +    items:
>> +      - const: etr0
>> +      - const: etr1
>> +
>>     in-ports:
>>       $ref: /schemas/graph.yaml#/properties/ports
>>
>> @@ -56,6 +66,8 @@ additionalProperties: false
>>
>>   examples:
>>     - |
>> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
>> +
>>       ctcu at 1001000 {
>>           compatible = "qcom,sa8775p-ctcu";
>>           reg = <0x1001000 0x1000>;
>> @@ -63,6 +75,11 @@ examples:
>>           clocks = <&aoss_qmp>;
>>           clock-names = "apb";
>>
>> +        interrupts = <GIC_SPI 270 IRQ_TYPE_EDGE_RISING>,
>> +                     <GIC_SPI 262 IRQ_TYPE_EDGE_RISING>;
>> +        interrupt-names = "etr0",
>> +                          "etr1";
>> +
>>           in-ports {
>>               #address-cells = <1>;
>>               #size-cells = <0>;
>>
>> --
>> 2.34.1
>>
> Not sure if you need me to review this purely DT hardware description
> update but...

Hi Mike,

I am very glad to have you for reviewing, appreciate for your time.

Thanks,
Jie

> 
> Reviewed-by: Mike Leach <mike.leach at linaro.org>
> 



From jie.gan at oss.qualcomm.com  Wed Dec  3 18:53:55 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Thu, 4 Dec 2025 10:53:55 +0800
Subject: [PATCH v6 6/9] dt-bindings: arm: add an interrupt property for
 Coresight CTCU
In-Reply-To: <66d4488f-941a-4716-b81f-e0f9e1165931@arm.com>
References: <20250908-enable-byte-cntr-for-tmc-v6-0-1db9e621441a@oss.qualcomm.com>
 <20250908-enable-byte-cntr-for-tmc-v6-6-1db9e621441a@oss.qualcomm.com>
 <66d4488f-941a-4716-b81f-e0f9e1165931@arm.com>
Message-ID: <5a0e4abf-9e7f-4ef9-af02-dd6e34f5cfa8@oss.qualcomm.com>



On 12/4/2025 2:14 AM, Suzuki K Poulose wrote:
> On 08/09/2025 03:01, Jie Gan wrote:
>> Add an interrupt property to CTCU device. The interrupt will be triggered
>> when the data size in the ETR buffer exceeds the threshold of the
>> BYTECNTRVAL register. Programming a threshold in the BYTECNTRVAL register
>> of CTCU device will enable the interrupt.
>>
>> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> ---
>> ? .../devicetree/bindings/arm/qcom,coresight-ctcu.yaml??? | 17 +++++++ 
>> ++++++++++
>> ? 1 file changed, 17 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight- 
>> ctcu.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight- 
>> ctcu.yaml
>> index 843b52eaf872..ea05ad8f3dd3 100644
>> --- a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
>> +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
>> @@ -39,6 +39,16 @@ properties:
>> ????? items:
>> ??????? - const: apb
>> +? interrupts:
>> +??? items:
>> +????? - description: Byte cntr interrupt for etr0
>> +????? - description: Byte cntr interrupt for etr1
>> +
>> +? interrupt-names:
>> +??? items:
>> +????? - const: etr0
>> +????? - const: etr1
> 

Hi Suzuki,

> Why are they named "etr0" "etr1" ? That would be confusing, isn't it, 
> especially with the Linux driver naming things randomly for the TMC-ETRs.
> 

Yes, it will cause misunderstandings since the "etr0" here may not the 
right device we are expecting.

> 
> What we want is the "port" number corresponding to the "TMC-ETR" being
> monitored ?
> 
> Have you explored other options, "port-0", "port-1" ?
> 

I think it's much better. Will update in next version.

Thanks,
Jie

> Suzuki
> 
>> +
>> ??? in-ports:
>> ????? $ref: /schemas/graph.yaml#/properties/ports
>> @@ -56,6 +66,8 @@ additionalProperties: false
>> ? examples:
>> ??? - |
>> +??? #include <dt-bindings/interrupt-controller/arm-gic.h>
>> +
>> ????? ctcu at 1001000 {
>> ????????? compatible = "qcom,sa8775p-ctcu";
>> ????????? reg = <0x1001000 0x1000>;
>> @@ -63,6 +75,11 @@ examples:
>> ????????? clocks = <&aoss_qmp>;
>> ????????? clock-names = "apb";
>> +??????? interrupts = <GIC_SPI 270 IRQ_TYPE_EDGE_RISING>,
>> +???????????????????? <GIC_SPI 262 IRQ_TYPE_EDGE_RISING>;
>> +??????? interrupt-names = "etr0",
>> +????????????????????????? "etr1";
>> +
>> ????????? in-ports {
>> ????????????? #address-cells = <1>;
>> ????????????? #size-cells = <0>;
>>
> 
> 



From jiyu.yang at oss.nxp.com  Wed Dec  3 19:01:50 2025
From: jiyu.yang at oss.nxp.com (Rain Yang)
Date: Thu, 4 Dec 2025 11:01:50 +0800
Subject: [PATCH] arm64: dts: imx95: Use GPU_CGC as core clock for GPU
In-Reply-To: <de36091e-c890-4897-b3e3-2a7575029a5d@mailbox.org>
References: <20251129143220.14834-1-marek.vasut@mailbox.org>
 <aS-lEibp3zTsaR6T@oss.nxp.com>
 <c6e0e55a-06da-4665-972e-e9b5b8c08bf7@mailbox.org>
 <aTACuRjC_Zpf8IOU@oss.nxp.com>
 <de36091e-c890-4897-b3e3-2a7575029a5d@mailbox.org>
Message-ID: <aTD5np-HGaJqhzkD@oss.nxp.com>

On Wed, Dec 03, 2025 at 11:48:47PM +0100, Marek Vasut wrote:
>On 12/3/25 10:28 AM, Rain Yang wrote:
>
>Hello Rain,
>
>> > > Thanks for integrating this downstream patch.
>> > 
>> > Which downstream patch do you refer to ?
>> > 
>> > > Please note that CLK_GPUAPB and CLK_GPU are
>> > > always-on, so the commit message should be amended accordingly.
>> > 
>> > The GPU clock do not seem to be always-on, neither do the GPUAPB . It seems
>> > the SM can turn those clock off perfectly well.
>> > 
>> > > Additionally, the IMX95_CLK_GPUAPB handle shall be removed, as there is no valid OPP entry
>> > > in the frequency table, this also helps minimize differences between downstream and upstream,
>> > > reducing maintenance effort.
>> > 
>> > Downstream kernel forks are not relevant to this discussion, upstream your
>> > content and then you won't have to spend maintenance effort on downstream
>> > stuff.
>> 
>> This patch [1] was the reference point.
>
>Sigh ... I was not aware of that one.
>
>Maybe next time, it would be good to upstream these changes directly ?
>
>> For the Linux working environment,
>> CLK_GPU and CLK_GPUAPB are always-on, while CLK_GPU_CGC can be gated off.
>> 
>> Regarding the IMX95_CLK_GPUAPB handle, my suggestion was based on the absence
>> of its frequency in any OPP entry within the frequency table. Removing it
>> could simplify the OPP handling logic and reduce unnecessary complexity.
>
>If the clock can be disabled by SM, Linux has to make sure they are NOT
>disabled, so they must be described in DT, right ?
>
>> [1] https://github.com/nxp-imx/linux-imx/commit/695f2bdc57b869ca5189313e4b5fa7eb5a12f622
Currently, only CLK_GPU_CGC shall be described in the Device Tree[1], as it can be gated.
The other clocks (CLK_GPU and CLK_GPUAPB) are always-on in the Linux environment,
so describing any of them in DT is not necessary and would not be proper in this context.
>
>
>-- 
>Best regards,
>Marek Vasut


From marek.vasut at mailbox.org  Wed Dec  3 19:25:38 2025
From: marek.vasut at mailbox.org (Marek Vasut)
Date: Thu, 4 Dec 2025 04:25:38 +0100
Subject: [PATCH] arm64: dts: imx95: Use GPU_CGC as core clock for GPU
In-Reply-To: <aTD5np-HGaJqhzkD@oss.nxp.com>
References: <20251129143220.14834-1-marek.vasut@mailbox.org>
 <aS-lEibp3zTsaR6T@oss.nxp.com>
 <c6e0e55a-06da-4665-972e-e9b5b8c08bf7@mailbox.org>
 <aTACuRjC_Zpf8IOU@oss.nxp.com>
 <de36091e-c890-4897-b3e3-2a7575029a5d@mailbox.org>
 <aTD5np-HGaJqhzkD@oss.nxp.com>
Message-ID: <5944d872-01a3-47e9-977b-029f3be4fd83@mailbox.org>

On 12/4/25 4:01 AM, Rain Yang wrote:

[...]
>>> For the Linux working environment,
>>> CLK_GPU and CLK_GPUAPB are always-on, while CLK_GPU_CGC can be gated off.
>>>
>>> Regarding the IMX95_CLK_GPUAPB handle, my suggestion was based on the absence
>>> of its frequency in any OPP entry within the frequency table. Removing it
>>> could simplify the OPP handling logic and reduce unnecessary complexity.
>>
>> If the clock can be disabled by SM, Linux has to make sure they are NOT
>> disabled, so they must be described in DT, right ?
>>
>>> [1] https://github.com/nxp-imx/linux-imx/commit/695f2bdc57b869ca5189313e4b5fa7eb5a12f622
> Currently, only CLK_GPU_CGC shall be described in the Device Tree[1], as it can be gated.
> The other clocks (CLK_GPU and CLK_GPUAPB) are always-on in the Linux environment,
> so describing any of them in DT is not necessary and would not be proper in this context.

Since this discussion is in fact unrelated to this bugfix, I would 
propose to fork the discussion into a separate patch. Can you please 
submit a patch for the GPUAPB clock ? Note that I believe GPUAPB clock 
have to be described in DT, if only because DT is a hardware 
description, and to make sure the GPUAPB clock are correctly enabled by 
the driver.


From anshuman.khandual at arm.com  Wed Dec  3 19:36:56 2025
From: anshuman.khandual at arm.com (Anshuman Khandual)
Date: Thu, 4 Dec 2025 09:06:56 +0530
Subject: [PATCH v5 02/12] x86/xen: simplify flush_lazy_mmu()
In-Reply-To: <20251124132228.622678-3-kevin.brodsky@arm.com>
References: <20251124132228.622678-1-kevin.brodsky@arm.com>
 <20251124132228.622678-3-kevin.brodsky@arm.com>
Message-ID: <15cc652c-937b-4d5b-98f3-7cdcecf28e27@arm.com>



On 24/11/25 6:52 PM, Kevin Brodsky wrote:
> arch_flush_lazy_mmu_mode() is called when outstanding batched
> pgtable operations must be completed immediately. There should
> however be no need to leave and re-enter lazy MMU completely. The
> only part of that sequence that we really need is xen_mc_flush();
> call it directly.
> 
> Reviewed-by: David Hildenbrand <david at redhat.com>
> Reviewed-by: Ryan Roberts <ryan.roberts at arm.com>
> Reviewed-by: Juergen Gross <jgross at suse.com>
> Signed-off-by: Kevin Brodsky <kevin.brodsky at arm.com>
> ---

Reviewed-by: Anshuman Khandual <anshuman.khandual at arm.com>

>  arch/x86/xen/mmu_pv.c | 6 ++----
>  1 file changed, 2 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/x86/xen/mmu_pv.c b/arch/x86/xen/mmu_pv.c
> index 2a4a8deaf612..7a35c3393df4 100644
> --- a/arch/x86/xen/mmu_pv.c
> +++ b/arch/x86/xen/mmu_pv.c
> @@ -2139,10 +2139,8 @@ static void xen_flush_lazy_mmu(void)
>  {
>  	preempt_disable();
>  
> -	if (xen_get_lazy_mode() == XEN_LAZY_MMU) {
> -		arch_leave_lazy_mmu_mode();
> -		arch_enter_lazy_mmu_mode();
> -	}
> +	if (xen_get_lazy_mode() == XEN_LAZY_MMU)
> +		xen_mc_flush();
>  
>  	preempt_enable();
>  }



From jimmy.ho at sifive.com  Wed Dec  3 19:56:53 2025
From: jimmy.ho at sifive.com (Jimmy Ho)
Date: Thu, 4 Dec 2025 11:56:53 +0800
Subject: [PATCH v3 6/7] riscv: pmu: Integrate CTR Ext support in
 riscv_pmu_dev driver
In-Reply-To: <CAPqJEFr=3Re=L0CmEpCRHxovB74MDB9C8neNMfouYvWWbR0hyw@mail.gmail.com>
References: <20250523-b4-ctr_upstream_v3-v3-0-ad355304ba1c@rivosinc.com>
 <20250523-b4-ctr_upstream_v3-v3-6-ad355304ba1c@rivosinc.com> <CAPqJEFr=3Re=L0CmEpCRHxovB74MDB9C8neNMfouYvWWbR0hyw@mail.gmail.com>
Message-ID: <CAJh9TSJk0nZvqJrvTe5ENMpAB=56--+CFai0tXQnYFakKxQxQw@mail.gmail.com>

Hi Rajnesh,

> This integrates recently added CTR ext support in riscv_pmu_dev driver
> to enable branch stack sampling using PMU events.
>
> This mainly adds CTR enable/disable callbacks in rvpmu_ctr_stop()
> and rvpmu_ctr_start() function to start/stop branch recording along
> with the event.
>
> PMU overflow handler rvpmu_ovf_handler() is also updated to sample
> CTR entries in case of the overflow for the particular event programmed
> to records branches. The recorded entries are fed to core perf for
> further processing.
>
> Signed-off-by: Rajnesh Kanwal <rkanwal at rivosinc.com>
> ---
>  drivers/perf/riscv_pmu_common.c |  3 +-
>  drivers/perf/riscv_pmu_dev.c    | 67 ++++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 67 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/perf/riscv_pmu_common.c b/drivers/perf/riscv_pmu_common.c
> index b2dc78cbbb93926964f81f30be9ef4a1c02501df..0b032b8d8762e77d2b553643b0f9064e7c789cfe
> 100644
> --- a/drivers/perf/riscv_pmu_common.c
> +++ b/drivers/perf/riscv_pmu_common.c
> @@ -329,8 +329,7 @@ static int riscv_pmu_event_init(struct perf_event *event)
>         u64 event_config = 0;
>         uint64_t cmask;
>
> -       /* driver does not support branch stack sampling */
> -       if (has_branch_stack(event))
> +       if (needs_branch_stack(event) && !riscv_pmu_ctr_supported(rvpmu))
>                 return -EOPNOTSUPP;
>
>         hwc->flags = 0;
> diff --git a/drivers/perf/riscv_pmu_dev.c b/drivers/perf/riscv_pmu_dev.c
> index 95e6dd272db69f53b679e5fc3450785e45d5e8b9..b0c616fb939fcc61f7493877a8801916069f16f7
> 100644
> --- a/drivers/perf/riscv_pmu_dev.c
> +++ b/drivers/perf/riscv_pmu_dev.c
> @@ -1038,7 +1038,7 @@ static void rvpmu_sbi_ctr_stop(struct perf_event
> *event, unsigned long flag)
>  static void pmu_sched_task(struct perf_event_pmu_context *pmu_ctx,
>                            bool sched_in)
>  {
> -       /* Call CTR specific Sched hook. */
> +       riscv_pmu_ctr_sched_task(pmu_ctx, sched_in);
>  }
>
>  static int rvpmu_sbi_find_num_ctrs(void)
> @@ -1370,6 +1370,13 @@ static irqreturn_t rvpmu_ovf_handler(int irq, void *dev)
>                 hw_evt->state |= PERF_HES_UPTODATE;
>                 perf_sample_data_init(&data, 0, hw_evt->last_period);
>                 if (riscv_pmu_event_set_period(event)) {
> +                       if (needs_branch_stack(event)) {
> +                               riscv_pmu_ctr_consume(cpu_hw_evt, event);
> +                               perf_sample_save_brstack(
> +                                       &data, event,
> +
> &cpu_hw_evt->branches->branch_stack, NULL);
> +                       }
> +
>                         /*
>                          * Unlike other ISAs, RISC-V don't have to
> disable interrupts
>                          * to avoid throttling here. As per the
> specification, the
> @@ -1569,16 +1576,23 @@ static int rvpmu_deleg_ctr_get_idx(struct
> perf_event *event)
>
>  static void rvpmu_ctr_add(struct perf_event *event, int flags)
>  {
> +       if (needs_branch_stack(event))
> +               riscv_pmu_ctr_add(event);
>  }
>
>  static void rvpmu_ctr_del(struct perf_event *event, int flags)
>  {
> +       if (needs_branch_stack(event))
> +               riscv_pmu_ctr_del(event);
>  }
>
>  static void rvpmu_ctr_start(struct perf_event *event, u64 ival)
>  {
>         struct hw_perf_event *hwc = &event->hw;
>
> +       if (needs_branch_stack(event))
> +               riscv_pmu_ctr_enable(event);
> +
>         if (riscv_pmu_cdeleg_available() && !pmu_sbi_is_fw_event(event))
>                 rvpmu_deleg_ctr_start(event, ival);
>         else
> @@ -1593,6 +1607,9 @@ static void rvpmu_ctr_stop(struct perf_event
> *event, unsigned long flag)
>  {
>         struct hw_perf_event *hwc = &event->hw;
>
> +       if (needs_branch_stack(event) && flag != RISCV_PMU_STOP_FLAG_RESET)
> +               riscv_pmu_ctr_disable(event);
> +
>         if ((hwc->flags & PERF_EVENT_FLAG_USER_ACCESS) &&
>             (hwc->flags & PERF_EVENT_FLAG_USER_READ_CNT))
>                 rvpmu_reset_scounteren((void *)event);
> @@ -1650,6 +1667,9 @@ static u32 rvpmu_find_ctrs(void)
>
>  static int rvpmu_event_map(struct perf_event *event, u64 *econfig)
>  {
> +       if (needs_branch_stack(event) && !riscv_pmu_ctr_valid(event))
> +               return -EOPNOTSUPP;
> +
>         if (riscv_pmu_cdeleg_available() && !pmu_sbi_is_fw_event(event))
>                 return rvpmu_cdeleg_event_map(event, econfig);
>         else
> @@ -1696,6 +1716,8 @@ static int rvpmu_starting_cpu(unsigned int cpu,
> struct hlist_node *node)
>                 enable_percpu_irq(riscv_pmu_irq, IRQ_TYPE_NONE);
>         }
>
> +       riscv_pmu_ctr_starting_cpu();
> +
>         if (sbi_pmu_snapshot_available())
>                 return pmu_sbi_snapshot_setup(pmu, cpu);
>
> @@ -1710,6 +1732,7 @@ static int rvpmu_dying_cpu(unsigned int cpu,
> struct hlist_node *node)
>
>         /* Disable all counters access for user mode now */
>         csr_write(CSR_SCOUNTEREN, 0x0);
> +       riscv_pmu_ctr_dying_cpu();
>
>         if (sbi_pmu_snapshot_available())
>                 return pmu_sbi_snapshot_disable();
> @@ -1833,6 +1856,29 @@ static void riscv_pmu_destroy(struct riscv_pmu *pmu)
>         cpuhp_state_remove_instance(CPUHP_AP_PERF_RISCV_STARTING, &pmu->node);
>  }
>
> +static int branch_records_alloc(struct riscv_pmu *pmu)
> +{
> +       struct branch_records __percpu *tmp_alloc_ptr;
> +       struct branch_records *records;
> +       struct cpu_hw_events *events;
> +       int cpu;
> +
> +       if (!riscv_pmu_ctr_supported(pmu))
> +               return 0;
> +
> +       tmp_alloc_ptr = alloc_percpu_gfp(struct branch_records, GFP_KERNEL);
> +       if (!tmp_alloc_ptr)
> +               return -ENOMEM;
> +
> +       for_each_possible_cpu(cpu) {
> +               events = per_cpu_ptr(pmu->hw_events, cpu);
> +               records = per_cpu_ptr(tmp_alloc_ptr, cpu);
> +               events->branches = records;
> +       }
> +
> +       return 0;
> +}
> +
>  static void rvpmu_event_init(struct perf_event *event)
>  {
>         /*
> @@ -1845,6 +1891,9 @@ static void rvpmu_event_init(struct perf_event *event)
>                 event->hw.flags |= PERF_EVENT_FLAG_USER_ACCESS;
>         else
>                 event->hw.flags |= PERF_EVENT_FLAG_LEGACY;
> +
> +       if (branch_sample_call_stack(event))
> +               event->attach_state |= PERF_ATTACH_TASK_DATA;
>  }
>
>  static void rvpmu_event_mapped(struct perf_event *event, struct mm_struct *mm)
> @@ -1992,6 +2041,15 @@ static int rvpmu_device_probe(struct
> platform_device *pdev)
>                 pmu->pmu.attr_groups = riscv_cdeleg_pmu_attr_groups;
>         else
>                 pmu->pmu.attr_groups = riscv_sbi_pmu_attr_groups;
> +
> +       ret = riscv_pmu_ctr_init(pmu);
> +       if (ret)
> +               goto out_free;
> +
> +       ret = branch_records_alloc(pmu);
> +       if (ret)
> +               goto out_ctr_finish;
> +
>         pmu->cmask = cmask;
>         pmu->ctr_add = rvpmu_ctr_add;
>         pmu->ctr_del = rvpmu_ctr_del;
> @@ -2008,6 +2066,10 @@ static int rvpmu_device_probe(struct
> platform_device *pdev)
>         pmu->csr_index = rvpmu_csr_index;
>         pmu->sched_task = pmu_sched_task;
>
> +       ret = cpuhp_state_add_instance(CPUHP_AP_PERF_RISCV_STARTING,
> &pmu->node);
> +       if (ret)
> +               goto out_ctr_finish;

This hotplug registration should be removed, since there is already
one in the original code.
Otherwise, It will cause the CPU hotplug down to loop infinitely.

Best regards,
Jimmy Ho

> +
>         ret = riscv_pm_pmu_register(pmu);
>         if (ret)
>                 goto out_unregister;
> @@ -2057,6 +2119,9 @@ static int rvpmu_device_probe(struct
> platform_device *pdev)
>  out_unregister:
>         riscv_pmu_destroy(pmu);
>
> +out_ctr_finish:
> +       riscv_pmu_ctr_finish(pmu);
> +
>  out_free:
>         kfree(pmu);
>         return ret;
>
> --
> 2.43.0
>
>
> _______________________________________________
> linux-riscv mailing list
> linux-riscv at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv


From pavan.kondeti at oss.qualcomm.com  Wed Dec  3 20:07:15 2025
From: pavan.kondeti at oss.qualcomm.com (Pavan Kondeti)
Date: Thu, 4 Dec 2025 09:37:15 +0530
Subject: Alternative to arm64.nopauth cmdline for disabling Pointer
 Authentication
Message-ID: <3fcf6614-ee83-4a06-9024-83573b2e642e@quicinc.com>

Hi

The pointer authentication feature (PAuth) is only supported on
0-3 CPUs but it is not supported on 4-7 CPUS on QCS8300.
The ARM64 cpufeature discovery code expects late CPUs to have
this feature if boot CPU feature has it since PAuth is enabled
early. When a conflict like this is detected, the late CPUs are
not allowed to boot. It is expected that system will continue
to be functional with CPUs with Pauth feature supported and enabled.
This is not a desired behavior in production.

We started seeing this problem when Linux is booted in EL2. When Linux
is running under Gunyah (Type-1 hypervisor), Pointer Authentication
feature is hidden from EL1 via HCR_EL2.TID3. 

arm64.nopauth can be passed on kernel cmdline to disable the feature
in kernel so that all all CPUs can boot on QCS8300. I am told 
maintaining a custom kernel commandline per SoC in a Generic OS 
distribution is not recommended and asked to discuss the problem with
the comunity [1]

This patch [2] from Catalin adds a devicetree property under memory {}
to disable MTE. I believe this work predates the id-reg override
mechanism. However, this made me think if workarounds like this can be 
detected via devicetree, for example a property under cpu { } node.

Given that what we put in `chosen { bootargs="" }` kernel under
respective SoC devicetree can be overridden by bootloader, should we
have a **sticky** cmdline to specify critical workarounds like this?
This would be more generic than introducing any new parameters.

Looking for your inputs on this.

Thanks,
Pavan

[1] https://github.com/qualcomm-linux/meta-qcom/issues/1277
[2] https://lore.kernel.org/linux-arm-kernel/20200515171612.1020-24-catalin.marinas at arm.com/


From rkrcmar at ventanamicro.com  Wed Dec  3 20:07:20 2025
From: rkrcmar at ventanamicro.com (=?utf-8?q?Radim_Kr=C4=8Dm=C3=A1=C5=99?=)
Date: Thu, 04 Dec 2025 13:07:20 +0900
Subject: [PATCH v3 5/8] riscv: smp: use NMI for CPU stop
In-Reply-To: <20251127125305.89961-6-cuiyunhui@bytedance.com>
References: <20251127125305.89961-1-cuiyunhui@bytedance.com>
 <20251127125305.89961-6-cuiyunhui@bytedance.com>
Message-ID: <DEP4X1DAIOU5.2WLIV4BMWLMRR@ventanamicro.com>

2025-11-27T20:53:02+08:00, Yunhui Cui <cuiyunhui at bytedance.com>:
> Use NMI instead of IPI for CPU stop if RISC-V SSE NMI is supported.
>
> Signed-off-by: Yunhui Cui <cuiyunhui at bytedance.com>
> ---
> diff --git a/drivers/firmware/riscv/riscv_sse_nmi.c b/drivers/firmware/riscv/riscv_sse_nmi.c
> @@ -58,6 +58,7 @@ static int local_nmi_handler(u32 evt, void *arg, struct pt_regs *regs)
>  	type = atomic_read(this_cpu_ptr(&local_nmi));
>  
>  	NMI_HANDLE(LOCAL_NMI_CRASH, cpu_crash_stop, cpu, regs);
> +	NMI_HANDLE(LOCAL_NMI_STOP, cpu_stop);

Please document the intended preemption design for all SSE events,
because it will be a nightmare if we forget some assumptions in the
coming years.  (That includes the relative priorities of RAS/PMU/...)

Thanks.


From rkrcmar at ventanamicro.com  Wed Dec  3 20:11:39 2025
From: rkrcmar at ventanamicro.com (=?utf-8?q?Radim_Kr=C4=8Dm=C3=A1=C5=99?=)
Date: Thu, 04 Dec 2025 13:11:39 +0900
Subject: [PATCH v3 8/8] drivers: firmware: riscv: add unknown nmi
 support
In-Reply-To: <20251127125305.89961-9-cuiyunhui@bytedance.com>
References: <20251127125305.89961-1-cuiyunhui@bytedance.com>
 <20251127125305.89961-9-cuiyunhui@bytedance.com>
Message-ID: <DEP50CD8K22E.1JW7GL6WLK44W@ventanamicro.com>

2025-11-27T20:53:05+08:00, Yunhui Cui <cuiyunhui at bytedance.com>:
> Register unknown_nmi_handler() as the handler for the UNKNOWN_NMI
> event. When the system becomes unresponsive, unknown_nmi_handler()
> can be manually triggered, which in turn invokes nmi_panic() to
> collect vmcore for root cause analysis.

Is UNKNOWN_NMI what we expect the watchdog to send?

Thanks.


From anshuman.khandual at arm.com  Wed Dec  3 20:17:19 2025
From: anshuman.khandual at arm.com (Anshuman Khandual)
Date: Thu, 4 Dec 2025 09:47:19 +0530
Subject: [PATCH v5 06/12] mm: introduce generic lazy_mmu helpers
In-Reply-To: <20251124132228.622678-7-kevin.brodsky@arm.com>
References: <20251124132228.622678-1-kevin.brodsky@arm.com>
 <20251124132228.622678-7-kevin.brodsky@arm.com>
Message-ID: <e43c147f-bff8-462a-88dc-4345500f4ed7@arm.com>

On 24/11/25 6:52 PM, Kevin Brodsky wrote:
> The implementation of the lazy MMU mode is currently entirely
> arch-specific; core code directly calls arch helpers:
> arch_{enter,leave}_lazy_mmu_mode().
> 
> We are about to introduce support for nested lazy MMU sections.
> As things stand we'd have to duplicate that logic in every arch
> implementing lazy_mmu - adding to a fair amount of logic
> already duplicated across lazy_mmu implementations.
> 
> This patch therefore introduces a new generic layer that calls the
> existing arch_* helpers. Two pair of calls are introduced:
> 
> * lazy_mmu_mode_enable() ... lazy_mmu_mode_disable()
>     This is the standard case where the mode is enabled for a given
>     block of code by surrounding it with enable() and disable()
>     calls.
> 
> * lazy_mmu_mode_pause() ... lazy_mmu_mode_resume()
>     This is for situations where the mode is temporarily disabled
>     by first calling pause() and then resume() (e.g. to prevent any
>     batching from occurring in a critical section).
> 
> The documentation in <linux/pgtable.h> will be updated in a
> subsequent patch.
> > No functional change should be introduced at this stage.
> The implementation of enable()/resume() and disable()/pause() is
> currently identical, but nesting support will change that.
> 
> Most of the call sites have been updated using the following
> Coccinelle script:
> 
> @@
> @@
> {
> ...
> - arch_enter_lazy_mmu_mode();
> + lazy_mmu_mode_enable();
> ...
> - arch_leave_lazy_mmu_mode();
> + lazy_mmu_mode_disable();
> ...
> }
> 
> @@
> @@
> {
> ...
> - arch_leave_lazy_mmu_mode();
> + lazy_mmu_mode_pause();
> ...
> - arch_enter_lazy_mmu_mode();
> + lazy_mmu_mode_resume();
> ...
> }

At this point arch_enter/leave_lazy_mmu_mode() helpers are still
present on a given platform but now being called from new generic
helpers lazy_mmu_mode_enable/disable(). Well except x86, there is
direct call sites for those old helpers.

arch/arm64/include/asm/pgtable.h:static inline void arch_enter_lazy_mmu_mode(void)
arch/arm64/include/asm/pgtable.h:static inline void arch_leave_lazy_mmu_mode(void)

arch/arm64/mm/mmu.c:    lazy_mmu_mode_enable();
arch/arm64/mm/pageattr.c:       lazy_mmu_mode_enable();

arch/arm64/mm/mmu.c:    lazy_mmu_mode_disable();
arch/arm64/mm/pageattr.c:       lazy_mmu_mode_disable();

> 
> A couple of notes regarding x86:
> 
> * Xen is currently the only case where explicit handling is required
>   for lazy MMU when context-switching. This is purely an
>   implementation detail and using the generic lazy_mmu_mode_*
>   functions would cause trouble when nesting support is introduced,
>   because the generic functions must be called from the current task.
>   For that reason we still use arch_leave() and arch_enter() there.
> 
> * x86 calls arch_flush_lazy_mmu_mode() unconditionally in a few
>   places, but only defines it if PARAVIRT_XXL is selected, and we
>   are removing the fallback in <linux/pgtable.h>. Add a new fallback
>   definition to <asm/pgtable.h> to keep things building.
> 
> Acked-by: David Hildenbrand <david at redhat.com>
> Signed-off-by: Kevin Brodsky <kevin.brodsky at arm.com>
> ---
>  arch/arm64/mm/mmu.c                     |  4 ++--
>  arch/arm64/mm/pageattr.c                |  4 ++--
>  arch/powerpc/mm/book3s64/hash_tlb.c     |  8 +++----
>  arch/powerpc/mm/book3s64/subpage_prot.c |  4 ++--
>  arch/x86/include/asm/pgtable.h          |  1 +
>  fs/proc/task_mmu.c                      |  4 ++--
>  include/linux/pgtable.h                 | 29 +++++++++++++++++++++----
>  mm/kasan/shadow.c                       |  8 +++----
>  mm/madvise.c                            | 18 +++++++--------
>  mm/memory.c                             | 16 +++++++-------
>  mm/migrate_device.c                     |  8 +++----
>  mm/mprotect.c                           |  4 ++--
>  mm/mremap.c                             |  4 ++--
>  mm/userfaultfd.c                        |  4 ++--
>  mm/vmalloc.c                            | 12 +++++-----
>  mm/vmscan.c                             | 12 +++++-----
>  16 files changed, 81 insertions(+), 59 deletions(-)
> 
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index 94e29e3574ff..ce66ae77abaa 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -729,7 +729,7 @@ int split_kernel_leaf_mapping(unsigned long start, unsigned long end)
>  		return -EINVAL;
>  
>  	mutex_lock(&pgtable_split_lock);
> -	arch_enter_lazy_mmu_mode();
> +	lazy_mmu_mode_enable();
>  
>  	/*
>  	 * The split_kernel_leaf_mapping_locked() may sleep, it is not a
> @@ -751,7 +751,7 @@ int split_kernel_leaf_mapping(unsigned long start, unsigned long end)
>  			ret = split_kernel_leaf_mapping_locked(end);
>  	}
>  
> -	arch_leave_lazy_mmu_mode();
> +	lazy_mmu_mode_disable();
>  	mutex_unlock(&pgtable_split_lock);
>  	return ret;
>  }
> diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c
> index 5135f2d66958..e4059f13c4ed 100644
> --- a/arch/arm64/mm/pageattr.c
> +++ b/arch/arm64/mm/pageattr.c
> @@ -110,7 +110,7 @@ static int update_range_prot(unsigned long start, unsigned long size,
>  	if (WARN_ON_ONCE(ret))
>  		return ret;
>  
> -	arch_enter_lazy_mmu_mode();
> +	lazy_mmu_mode_enable();
>  
>  	/*
>  	 * The caller must ensure that the range we are operating on does not
> @@ -119,7 +119,7 @@ static int update_range_prot(unsigned long start, unsigned long size,
>  	 */
>  	ret = walk_kernel_page_table_range_lockless(start, start + size,
>  						    &pageattr_ops, NULL, &data);
> -	arch_leave_lazy_mmu_mode();
> +	lazy_mmu_mode_disable();
>  
>  	return ret;
>  }
> diff --git a/arch/powerpc/mm/book3s64/hash_tlb.c b/arch/powerpc/mm/book3s64/hash_tlb.c
> index 21fcad97ae80..787f7a0e27f0 100644
> --- a/arch/powerpc/mm/book3s64/hash_tlb.c
> +++ b/arch/powerpc/mm/book3s64/hash_tlb.c
> @@ -205,7 +205,7 @@ void __flush_hash_table_range(unsigned long start, unsigned long end)
>  	 * way to do things but is fine for our needs here.
>  	 */
>  	local_irq_save(flags);
> -	arch_enter_lazy_mmu_mode();
> +	lazy_mmu_mode_enable();
>  	for (; start < end; start += PAGE_SIZE) {
>  		pte_t *ptep = find_init_mm_pte(start, &hugepage_shift);
>  		unsigned long pte;
> @@ -217,7 +217,7 @@ void __flush_hash_table_range(unsigned long start, unsigned long end)
>  			continue;
>  		hpte_need_flush(&init_mm, start, ptep, pte, hugepage_shift);
>  	}
> -	arch_leave_lazy_mmu_mode();
> +	lazy_mmu_mode_disable();
>  	local_irq_restore(flags);
>  }
>  
> @@ -237,7 +237,7 @@ void flush_hash_table_pmd_range(struct mm_struct *mm, pmd_t *pmd, unsigned long
>  	 * way to do things but is fine for our needs here.
>  	 */
>  	local_irq_save(flags);
> -	arch_enter_lazy_mmu_mode();
> +	lazy_mmu_mode_enable();
>  	start_pte = pte_offset_map(pmd, addr);
>  	if (!start_pte)
>  		goto out;
> @@ -249,6 +249,6 @@ void flush_hash_table_pmd_range(struct mm_struct *mm, pmd_t *pmd, unsigned long
>  	}
>  	pte_unmap(start_pte);
>  out:
> -	arch_leave_lazy_mmu_mode();
> +	lazy_mmu_mode_disable();
>  	local_irq_restore(flags);
>  }
> diff --git a/arch/powerpc/mm/book3s64/subpage_prot.c b/arch/powerpc/mm/book3s64/subpage_prot.c
> index ec98e526167e..07c47673bba2 100644
> --- a/arch/powerpc/mm/book3s64/subpage_prot.c
> +++ b/arch/powerpc/mm/book3s64/subpage_prot.c
> @@ -73,13 +73,13 @@ static void hpte_flush_range(struct mm_struct *mm, unsigned long addr,
>  	pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
>  	if (!pte)
>  		return;
> -	arch_enter_lazy_mmu_mode();
> +	lazy_mmu_mode_enable();
>  	for (; npages > 0; --npages) {
>  		pte_update(mm, addr, pte, 0, 0, 0);
>  		addr += PAGE_SIZE;
>  		++pte;
>  	}
> -	arch_leave_lazy_mmu_mode();
> +	lazy_mmu_mode_disable();
>  	pte_unmap_unlock(pte - 1, ptl);
>  }
>  
> diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
> index e33df3da6980..2842fa1f7a2c 100644
> --- a/arch/x86/include/asm/pgtable.h
> +++ b/arch/x86/include/asm/pgtable.h
> @@ -118,6 +118,7 @@ extern pmdval_t early_pmd_flags;
>  #define __pte(x)	native_make_pte(x)
>  
>  #define arch_end_context_switch(prev)	do {} while(0)
> +static inline void arch_flush_lazy_mmu_mode(void) {}
>  #endif	/* CONFIG_PARAVIRT_XXL */
>  
>  static inline pmd_t pmd_set_flags(pmd_t pmd, pmdval_t set)
> diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
> index d00ac179d973..ee1778adcc20 100644
> --- a/fs/proc/task_mmu.c
> +++ b/fs/proc/task_mmu.c
> @@ -2737,7 +2737,7 @@ static int pagemap_scan_pmd_entry(pmd_t *pmd, unsigned long start,
>  		return 0;
>  	}
>  
> -	arch_enter_lazy_mmu_mode();
> +	lazy_mmu_mode_enable();
>  
>  	if ((p->arg.flags & PM_SCAN_WP_MATCHING) && !p->vec_out) {
>  		/* Fast path for performing exclusive WP */
> @@ -2807,7 +2807,7 @@ static int pagemap_scan_pmd_entry(pmd_t *pmd, unsigned long start,
>  	if (flush_end)
>  		flush_tlb_range(vma, start, addr);
>  
> -	arch_leave_lazy_mmu_mode();
> +	lazy_mmu_mode_disable();
>  	pte_unmap_unlock(start_pte, ptl);
>  
>  	cond_resched();
> diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
> index de7d2c7e63eb..c121358dba15 100644
> --- a/include/linux/pgtable.h
> +++ b/include/linux/pgtable.h
> @@ -231,10 +231,31 @@ static inline int pmd_dirty(pmd_t pmd)
>   * held, but for kernel PTE updates, no lock is held). Nesting is not permitted
>   * and the mode cannot be used in interrupt context.
>   */
> -#ifndef CONFIG_ARCH_HAS_LAZY_MMU_MODE
> -static inline void arch_enter_lazy_mmu_mode(void) {}
> -static inline void arch_leave_lazy_mmu_mode(void) {}
> -static inline void arch_flush_lazy_mmu_mode(void) {}
> +#ifdef CONFIG_ARCH_HAS_LAZY_MMU_MODE
> +static inline void lazy_mmu_mode_enable(void)
> +{
> +	arch_enter_lazy_mmu_mode();
> +}
> +
> +static inline void lazy_mmu_mode_disable(void)
> +{
> +	arch_leave_lazy_mmu_mode();
> +}
> +
> +static inline void lazy_mmu_mode_pause(void)
> +{
> +	arch_leave_lazy_mmu_mode();
> +}
> +
> +static inline void lazy_mmu_mode_resume(void)
> +{
> +	arch_enter_lazy_mmu_mode();
> +}
> +#else
> +static inline void lazy_mmu_mode_enable(void) {}
> +static inline void lazy_mmu_mode_disable(void) {}
> +static inline void lazy_mmu_mode_pause(void) {}
> +static inline void lazy_mmu_mode_resume(void) {}
>  #endif
>  
>  #ifndef pte_batch_hint
> diff --git a/mm/kasan/shadow.c b/mm/kasan/shadow.c
> index 29a751a8a08d..c1433d5cc5db 100644
> --- a/mm/kasan/shadow.c
> +++ b/mm/kasan/shadow.c
> @@ -305,7 +305,7 @@ static int kasan_populate_vmalloc_pte(pte_t *ptep, unsigned long addr,
>  	pte_t pte;
>  	int index;
>  
> -	arch_leave_lazy_mmu_mode();
> +	lazy_mmu_mode_pause();

This replacement works because lazy_mmu_mode_pause() still calls
arch_leave_lazy_mmu_mode() atleast for now.

>  
>  	index = PFN_DOWN(addr - data->start);
>  	page = data->pages[index];
> @@ -319,7 +319,7 @@ static int kasan_populate_vmalloc_pte(pte_t *ptep, unsigned long addr,
>  	}
>  	spin_unlock(&init_mm.page_table_lock);
>  
> -	arch_enter_lazy_mmu_mode();
> +	lazy_mmu_mode_resume();

Same.

>  
>  	return 0;
>  }
> @@ -471,7 +471,7 @@ static int kasan_depopulate_vmalloc_pte(pte_t *ptep, unsigned long addr,
>  	pte_t pte;
>  	int none;
>  
> -	arch_leave_lazy_mmu_mode();
> +	lazy_mmu_mode_pause();
>  
>  	spin_lock(&init_mm.page_table_lock);
>  	pte = ptep_get(ptep);
> @@ -483,7 +483,7 @@ static int kasan_depopulate_vmalloc_pte(pte_t *ptep, unsigned long addr,
>  	if (likely(!none))
>  		__free_page(pfn_to_page(pte_pfn(pte)));
>  
> -	arch_enter_lazy_mmu_mode();
> +	lazy_mmu_mode_resume();
>  
>  	return 0;
>  }
> diff --git a/mm/madvise.c b/mm/madvise.c
> index b617b1be0f53..6bf7009fa5ce 100644
> --- a/mm/madvise.c
> +++ b/mm/madvise.c
> @@ -453,7 +453,7 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd,
>  	if (!start_pte)
>  		return 0;
>  	flush_tlb_batched_pending(mm);
> -	arch_enter_lazy_mmu_mode();
> +	lazy_mmu_mode_enable();
>  	for (; addr < end; pte += nr, addr += nr * PAGE_SIZE) {
>  		nr = 1;
>  		ptent = ptep_get(pte);
> @@ -461,7 +461,7 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd,
>  		if (++batch_count == SWAP_CLUSTER_MAX) {
>  			batch_count = 0;
>  			if (need_resched()) {
> -				arch_leave_lazy_mmu_mode();
> +				lazy_mmu_mode_disable();
>  				pte_unmap_unlock(start_pte, ptl);
>  				cond_resched();
>  				goto restart;
> @@ -497,7 +497,7 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd,
>  				if (!folio_trylock(folio))
>  					continue;
>  				folio_get(folio);
> -				arch_leave_lazy_mmu_mode();
> +				lazy_mmu_mode_disable();
>  				pte_unmap_unlock(start_pte, ptl);
>  				start_pte = NULL;
>  				err = split_folio(folio);
> @@ -508,7 +508,7 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd,
>  				if (!start_pte)
>  					break;
>  				flush_tlb_batched_pending(mm);
> -				arch_enter_lazy_mmu_mode();
> +				lazy_mmu_mode_enable();
>  				if (!err)
>  					nr = 0;
>  				continue;
> @@ -556,7 +556,7 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd,
>  	}
>  
>  	if (start_pte) {
> -		arch_leave_lazy_mmu_mode();
> +		lazy_mmu_mode_disable();
>  		pte_unmap_unlock(start_pte, ptl);
>  	}
>  	if (pageout)
> @@ -675,7 +675,7 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,
>  	if (!start_pte)
>  		return 0;
>  	flush_tlb_batched_pending(mm);
> -	arch_enter_lazy_mmu_mode();
> +	lazy_mmu_mode_enable();
>  	for (; addr != end; pte += nr, addr += PAGE_SIZE * nr) {
>  		nr = 1;
>  		ptent = ptep_get(pte);
> @@ -724,7 +724,7 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,
>  				if (!folio_trylock(folio))
>  					continue;
>  				folio_get(folio);
> -				arch_leave_lazy_mmu_mode();
> +				lazy_mmu_mode_disable();
>  				pte_unmap_unlock(start_pte, ptl);
>  				start_pte = NULL;
>  				err = split_folio(folio);
> @@ -735,7 +735,7 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,
>  				if (!start_pte)
>  					break;
>  				flush_tlb_batched_pending(mm);
> -				arch_enter_lazy_mmu_mode();
> +				lazy_mmu_mode_enable();
>  				if (!err)
>  					nr = 0;
>  				continue;
> @@ -775,7 +775,7 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,
>  	if (nr_swap)
>  		add_mm_counter(mm, MM_SWAPENTS, nr_swap);
>  	if (start_pte) {
> -		arch_leave_lazy_mmu_mode();
> +		lazy_mmu_mode_disable();
>  		pte_unmap_unlock(start_pte, ptl);
>  	}
>  	cond_resched();
> diff --git a/mm/memory.c b/mm/memory.c
> index 6675e87eb7dd..c0c29a3b0bcc 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -1256,7 +1256,7 @@ copy_pte_range(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma,
>  	spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING);
>  	orig_src_pte = src_pte;
>  	orig_dst_pte = dst_pte;
> -	arch_enter_lazy_mmu_mode();
> +	lazy_mmu_mode_enable();
>  
>  	do {
>  		nr = 1;
> @@ -1325,7 +1325,7 @@ copy_pte_range(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma,
>  	} while (dst_pte += nr, src_pte += nr, addr += PAGE_SIZE * nr,
>  		 addr != end);
>  
> -	arch_leave_lazy_mmu_mode();
> +	lazy_mmu_mode_disable();
>  	pte_unmap_unlock(orig_src_pte, src_ptl);
>  	add_mm_rss_vec(dst_mm, rss);
>  	pte_unmap_unlock(orig_dst_pte, dst_ptl);
> @@ -1842,7 +1842,7 @@ static unsigned long zap_pte_range(struct mmu_gather *tlb,
>  		return addr;
>  
>  	flush_tlb_batched_pending(mm);
> -	arch_enter_lazy_mmu_mode();
> +	lazy_mmu_mode_enable();
>  	do {
>  		bool any_skipped = false;
>  
> @@ -1874,7 +1874,7 @@ static unsigned long zap_pte_range(struct mmu_gather *tlb,
>  		direct_reclaim = try_get_and_clear_pmd(mm, pmd, &pmdval);
>  
>  	add_mm_rss_vec(mm, rss);
> -	arch_leave_lazy_mmu_mode();
> +	lazy_mmu_mode_disable();
>  
>  	/* Do the actual TLB flush before dropping ptl */
>  	if (force_flush) {
> @@ -2813,7 +2813,7 @@ static int remap_pte_range(struct mm_struct *mm, pmd_t *pmd,
>  	mapped_pte = pte = pte_alloc_map_lock(mm, pmd, addr, &ptl);
>  	if (!pte)
>  		return -ENOMEM;
> -	arch_enter_lazy_mmu_mode();
> +	lazy_mmu_mode_enable();
>  	do {
>  		BUG_ON(!pte_none(ptep_get(pte)));
>  		if (!pfn_modify_allowed(pfn, prot)) {
> @@ -2823,7 +2823,7 @@ static int remap_pte_range(struct mm_struct *mm, pmd_t *pmd,
>  		set_pte_at(mm, addr, pte, pte_mkspecial(pfn_pte(pfn, prot)));
>  		pfn++;
>  	} while (pte++, addr += PAGE_SIZE, addr != end);
> -	arch_leave_lazy_mmu_mode();
> +	lazy_mmu_mode_disable();
>  	pte_unmap_unlock(mapped_pte, ptl);
>  	return err;
>  }
> @@ -3174,7 +3174,7 @@ static int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd,
>  			return -EINVAL;
>  	}
>  
> -	arch_enter_lazy_mmu_mode();
> +	lazy_mmu_mode_enable();
>  
>  	if (fn) {
>  		do {
> @@ -3187,7 +3187,7 @@ static int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd,
>  	}
>  	*mask |= PGTBL_PTE_MODIFIED;
>  
> -	arch_leave_lazy_mmu_mode();
> +	lazy_mmu_mode_disable();
>  
>  	if (mm != &init_mm)
>  		pte_unmap_unlock(mapped_pte, ptl);
> diff --git a/mm/migrate_device.c b/mm/migrate_device.c
> index 23379663b1e1..0346c2d7819f 100644
> --- a/mm/migrate_device.c
> +++ b/mm/migrate_device.c
> @@ -271,7 +271,7 @@ static int migrate_vma_collect_pmd(pmd_t *pmdp,
>  	ptep = pte_offset_map_lock(mm, pmdp, start, &ptl);
>  	if (!ptep)
>  		goto again;
> -	arch_enter_lazy_mmu_mode();
> +	lazy_mmu_mode_enable();
>  	ptep += (addr - start) / PAGE_SIZE;
>  
>  	for (; addr < end; addr += PAGE_SIZE, ptep++) {
> @@ -313,7 +313,7 @@ static int migrate_vma_collect_pmd(pmd_t *pmdp,
>  			if (folio_test_large(folio)) {
>  				int ret;
>  
> -				arch_leave_lazy_mmu_mode();
> +				lazy_mmu_mode_disable();
>  				pte_unmap_unlock(ptep, ptl);
>  				ret = migrate_vma_split_folio(folio,
>  							  migrate->fault_page);
> @@ -356,7 +356,7 @@ static int migrate_vma_collect_pmd(pmd_t *pmdp,
>  			if (folio && folio_test_large(folio)) {
>  				int ret;
>  
> -				arch_leave_lazy_mmu_mode();
> +				lazy_mmu_mode_disable();
>  				pte_unmap_unlock(ptep, ptl);
>  				ret = migrate_vma_split_folio(folio,
>  							  migrate->fault_page);
> @@ -485,7 +485,7 @@ static int migrate_vma_collect_pmd(pmd_t *pmdp,
>  	if (unmapped)
>  		flush_tlb_range(walk->vma, start, end);
>  
> -	arch_leave_lazy_mmu_mode();
> +	lazy_mmu_mode_disable();
>  	pte_unmap_unlock(ptep - 1, ptl);
>  
>  	return 0;
> diff --git a/mm/mprotect.c b/mm/mprotect.c
> index 283889e4f1ce..c0571445bef7 100644
> --- a/mm/mprotect.c
> +++ b/mm/mprotect.c
> @@ -233,7 +233,7 @@ static long change_pte_range(struct mmu_gather *tlb,
>  		is_private_single_threaded = vma_is_single_threaded_private(vma);
>  
>  	flush_tlb_batched_pending(vma->vm_mm);
> -	arch_enter_lazy_mmu_mode();
> +	lazy_mmu_mode_enable();
>  	do {
>  		nr_ptes = 1;
>  		oldpte = ptep_get(pte);
> @@ -379,7 +379,7 @@ static long change_pte_range(struct mmu_gather *tlb,
>  			}
>  		}
>  	} while (pte += nr_ptes, addr += nr_ptes * PAGE_SIZE, addr != end);
> -	arch_leave_lazy_mmu_mode();
> +	lazy_mmu_mode_disable();
>  	pte_unmap_unlock(pte - 1, ptl);
>  
>  	return pages;
> diff --git a/mm/mremap.c b/mm/mremap.c
> index 672264807db6..8275b9772ec1 100644
> --- a/mm/mremap.c
> +++ b/mm/mremap.c
> @@ -260,7 +260,7 @@ static int move_ptes(struct pagetable_move_control *pmc,
>  	if (new_ptl != old_ptl)
>  		spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
>  	flush_tlb_batched_pending(vma->vm_mm);
> -	arch_enter_lazy_mmu_mode();
> +	lazy_mmu_mode_enable();
>  
>  	for (; old_addr < old_end; old_ptep += nr_ptes, old_addr += nr_ptes * PAGE_SIZE,
>  		new_ptep += nr_ptes, new_addr += nr_ptes * PAGE_SIZE) {
> @@ -305,7 +305,7 @@ static int move_ptes(struct pagetable_move_control *pmc,
>  		}
>  	}
>  
> -	arch_leave_lazy_mmu_mode();
> +	lazy_mmu_mode_disable();
>  	if (force_flush)
>  		flush_tlb_range(vma, old_end - len, old_end);
>  	if (new_ptl != old_ptl)
> diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
> index e6dfd5f28acd..b11f81095fa5 100644
> --- a/mm/userfaultfd.c
> +++ b/mm/userfaultfd.c
> @@ -1103,7 +1103,7 @@ static long move_present_ptes(struct mm_struct *mm,
>  	/* It's safe to drop the reference now as the page-table is holding one. */
>  	folio_put(*first_src_folio);
>  	*first_src_folio = NULL;
> -	arch_enter_lazy_mmu_mode();
> +	lazy_mmu_mode_enable();
>  
>  	while (true) {
>  		orig_src_pte = ptep_get_and_clear(mm, src_addr, src_pte);
> @@ -1140,7 +1140,7 @@ static long move_present_ptes(struct mm_struct *mm,
>  			break;
>  	}
>  
> -	arch_leave_lazy_mmu_mode();
> +	lazy_mmu_mode_disable();
>  	if (src_addr > src_start)
>  		flush_tlb_range(src_vma, src_start, src_addr);
>  
> diff --git a/mm/vmalloc.c b/mm/vmalloc.c
> index ecbac900c35f..1dea299fbb5a 100644
> --- a/mm/vmalloc.c
> +++ b/mm/vmalloc.c
> @@ -108,7 +108,7 @@ static int vmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
>  	if (!pte)
>  		return -ENOMEM;
>  
> -	arch_enter_lazy_mmu_mode();
> +	lazy_mmu_mode_enable();
>  
>  	do {
>  		if (unlikely(!pte_none(ptep_get(pte)))) {
> @@ -134,7 +134,7 @@ static int vmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
>  		pfn++;
>  	} while (pte += PFN_DOWN(size), addr += size, addr != end);
>  
> -	arch_leave_lazy_mmu_mode();
> +	lazy_mmu_mode_disable();
>  	*mask |= PGTBL_PTE_MODIFIED;
>  	return 0;
>  }
> @@ -366,7 +366,7 @@ static void vunmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
>  	unsigned long size = PAGE_SIZE;
>  
>  	pte = pte_offset_kernel(pmd, addr);
> -	arch_enter_lazy_mmu_mode();
> +	lazy_mmu_mode_enable();
>  
>  	do {
>  #ifdef CONFIG_HUGETLB_PAGE
> @@ -385,7 +385,7 @@ static void vunmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
>  		WARN_ON(!pte_none(ptent) && !pte_present(ptent));
>  	} while (pte += (size >> PAGE_SHIFT), addr += size, addr != end);
>  
> -	arch_leave_lazy_mmu_mode();
> +	lazy_mmu_mode_disable();
>  	*mask |= PGTBL_PTE_MODIFIED;
>  }
>  
> @@ -533,7 +533,7 @@ static int vmap_pages_pte_range(pmd_t *pmd, unsigned long addr,
>  	if (!pte)
>  		return -ENOMEM;
>  
> -	arch_enter_lazy_mmu_mode();
> +	lazy_mmu_mode_enable();
>  
>  	do {
>  		struct page *page = pages[*nr];
> @@ -555,7 +555,7 @@ static int vmap_pages_pte_range(pmd_t *pmd, unsigned long addr,
>  		(*nr)++;
>  	} while (pte++, addr += PAGE_SIZE, addr != end);
>  
> -	arch_leave_lazy_mmu_mode();
> +	lazy_mmu_mode_disable();
>  	*mask |= PGTBL_PTE_MODIFIED;
>  
>  	return err;
> diff --git a/mm/vmscan.c b/mm/vmscan.c
> index 92980b072121..564c97a9362f 100644
> --- a/mm/vmscan.c
> +++ b/mm/vmscan.c
> @@ -3515,7 +3515,7 @@ static bool walk_pte_range(pmd_t *pmd, unsigned long start, unsigned long end,
>  		return false;
>  	}
>  
> -	arch_enter_lazy_mmu_mode();
> +	lazy_mmu_mode_enable();
>  restart:
>  	for (i = pte_index(start), addr = start; addr != end; i++, addr += PAGE_SIZE) {
>  		unsigned long pfn;
> @@ -3556,7 +3556,7 @@ static bool walk_pte_range(pmd_t *pmd, unsigned long start, unsigned long end,
>  	if (i < PTRS_PER_PTE && get_next_vma(PMD_MASK, PAGE_SIZE, args, &start, &end))
>  		goto restart;
>  
> -	arch_leave_lazy_mmu_mode();
> +	lazy_mmu_mode_disable();
>  	pte_unmap_unlock(pte, ptl);
>  
>  	return suitable_to_scan(total, young);
> @@ -3597,7 +3597,7 @@ static void walk_pmd_range_locked(pud_t *pud, unsigned long addr, struct vm_area
>  	if (!spin_trylock(ptl))
>  		goto done;
>  
> -	arch_enter_lazy_mmu_mode();
> +	lazy_mmu_mode_enable();
>  
>  	do {
>  		unsigned long pfn;
> @@ -3644,7 +3644,7 @@ static void walk_pmd_range_locked(pud_t *pud, unsigned long addr, struct vm_area
>  
>  	walk_update_folio(walk, last, gen, dirty);
>  
> -	arch_leave_lazy_mmu_mode();
> +	lazy_mmu_mode_disable();
>  	spin_unlock(ptl);
>  done:
>  	*first = -1;
> @@ -4243,7 +4243,7 @@ bool lru_gen_look_around(struct page_vma_mapped_walk *pvmw)
>  		}
>  	}
>  
> -	arch_enter_lazy_mmu_mode();
> +	lazy_mmu_mode_enable();
>  
>  	pte -= (addr - start) / PAGE_SIZE;
>  
> @@ -4277,7 +4277,7 @@ bool lru_gen_look_around(struct page_vma_mapped_walk *pvmw)
>  
>  	walk_update_folio(walk, last, gen, dirty);
>  
> -	arch_leave_lazy_mmu_mode();
> +	lazy_mmu_mode_disable();
>  
>  	/* feedback from rmap walkers to page table walkers */
>  	if (mm_state && suitable_to_scan(i, young))

LGTM and also no apparent problem on arm64 platform.

Reviewed-by: Anshuman Khandual <anshuman.khandual at arm.com>


From lkp at intel.com  Wed Dec  3 20:28:05 2025
From: lkp at intel.com (kernel test robot)
Date: Thu, 4 Dec 2025 12:28:05 +0800
Subject: [PATCH v20 5/7] firmware: drivers: imx: adds miscdev
In-Reply-To: <20251203-imx-se-if-v20-5-a04a25c4255f@nxp.com>
References: <20251203-imx-se-if-v20-5-a04a25c4255f@nxp.com>
Message-ID: <202512041241.yDXC2vpg-lkp@intel.com>

Hi Pankaj,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 4a26e7032d7d57c998598c08a034872d6f0d3945]

url:    https://github.com/intel-lab-lkp/linux/commits/Pankaj-Gupta/Documentation-firmware-add-imx-se-to-other_interfaces/20251203-145202
base:   4a26e7032d7d57c998598c08a034872d6f0d3945
patch link:    https://lore.kernel.org/r/20251203-imx-se-if-v20-5-a04a25c4255f%40nxp.com
patch subject: [PATCH v20 5/7] firmware: drivers: imx: adds miscdev
config: arm64-randconfig-r132-20251204 (https://download.01.org/0day-ci/archive/20251204/202512041241.yDXC2vpg-lkp at intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 734a912d0f025559fcf76bde9aaaeb0383c1625a)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251204/202512041241.yDXC2vpg-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512041241.yDXC2vpg-lkp at intel.com/

sparse warnings: (new ones prefixed by >>)
>> drivers/firmware/imx/se_ctrl.c:517:40: sparse: sparse: cast removes address space '__user' of expression
   drivers/firmware/imx/se_ctrl.c:745:48: sparse: sparse: cast removes address space '__user' of expression

vim +/__user +517 drivers/firmware/imx/se_ctrl.c

   491	
   492	static int se_ioctl_cmd_snd_rcv_rsp_handler(struct se_if_device_ctx *dev_ctx,
   493						    u64 arg)
   494	{
   495		struct se_ioctl_cmd_snd_rcv_rsp_info cmd_snd_rcv_rsp_info = {0};
   496		struct se_api_msg *tx_msg __free(kfree) = NULL;
   497		struct se_api_msg *rx_msg __free(kfree) = NULL;
   498		struct se_if_priv *priv = dev_ctx->priv;
   499		int err = 0;
   500	
   501		if (copy_from_user(&cmd_snd_rcv_rsp_info, (u8 __user *)arg,
   502				   sizeof(cmd_snd_rcv_rsp_info))) {
   503			dev_err(priv->dev,
   504				"%s: Failed to copy cmd_snd_rcv_rsp_info from user.",
   505				dev_ctx->devname);
   506			err = -EFAULT;
   507			goto exit;
   508		}
   509	
   510		if (cmd_snd_rcv_rsp_info.tx_buf_sz < SE_MU_HDR_SZ) {
   511			dev_err(priv->dev, "%s: User buffer too small(%d < %d)",
   512				dev_ctx->devname, cmd_snd_rcv_rsp_info.tx_buf_sz, SE_MU_HDR_SZ);
   513			err = -ENOSPC;
   514			goto exit;
   515		}
   516	
 > 517		err = se_chk_tx_msg_hdr(priv, (struct se_msg_hdr *)cmd_snd_rcv_rsp_info.tx_buf);
   518		if (err)
   519			goto exit;
   520	
   521		rx_msg = kzalloc(cmd_snd_rcv_rsp_info.rx_buf_sz, GFP_KERNEL);
   522		if (!rx_msg) {
   523			err = -ENOMEM;
   524			goto exit;
   525		}
   526	
   527		tx_msg = memdup_user(cmd_snd_rcv_rsp_info.tx_buf,
   528				     cmd_snd_rcv_rsp_info.tx_buf_sz);
   529		if (IS_ERR(tx_msg)) {
   530			err = PTR_ERR(tx_msg);
   531			goto exit;
   532		}
   533	
   534		if (tx_msg->header.tag != priv->if_defs->cmd_tag) {
   535			err = -EINVAL;
   536			goto exit;
   537		}
   538	
   539		if (tx_msg->header.ver == priv->if_defs->fw_api_ver &&
   540		    get_load_fw_instance(priv)->is_fw_tobe_loaded) {
   541			err = se_load_firmware(priv);
   542			if (err) {
   543				dev_err(priv->dev, "Could not send msg as FW is not loaded.");
   544				err = -EPERM;
   545				goto exit;
   546			}
   547		}
   548		set_se_rcv_msg_timeout(priv, SE_RCV_MSG_LONG_TIMEOUT);
   549	
   550		err = ele_msg_send_rcv(dev_ctx, tx_msg, cmd_snd_rcv_rsp_info.tx_buf_sz,
   551				       rx_msg, cmd_snd_rcv_rsp_info.rx_buf_sz);
   552		if (err < 0)
   553			goto exit;
   554	
   555		dev_dbg(priv->dev, "%s: %s %s.", dev_ctx->devname, __func__,
   556			"message received, start transmit to user");
   557	
   558		/* We may need to copy the output data to user before
   559		 * delivering the completion message.
   560		 */
   561		err = se_dev_ctx_cpy_out_data(dev_ctx);
   562		if (err < 0)
   563			goto exit;
   564	
   565		/* Copy data from the buffer */
   566		print_hex_dump_debug("to user ", DUMP_PREFIX_OFFSET, 4, 4, rx_msg,
   567				     cmd_snd_rcv_rsp_info.rx_buf_sz, false);
   568	
   569		if (copy_to_user(cmd_snd_rcv_rsp_info.rx_buf, rx_msg,
   570				 cmd_snd_rcv_rsp_info.rx_buf_sz)) {
   571			dev_err(priv->dev, "%s: Failed to copy to user.", dev_ctx->devname);
   572			err = -EFAULT;
   573		}
   574	
   575	exit:
   576	
   577		/* shared memory is allocated before this IOCTL */
   578		se_dev_ctx_shared_mem_cleanup(dev_ctx);
   579	
   580		if (copy_to_user((void __user *)arg, &cmd_snd_rcv_rsp_info,
   581				 sizeof(cmd_snd_rcv_rsp_info))) {
   582			dev_err(priv->dev, "%s: Failed to copy cmd_snd_rcv_rsp_info from user.",
   583				dev_ctx->devname);
   584			err = -EFAULT;
   585		}
   586	
   587		return err;
   588	}
   589	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From anshuman.khandual at arm.com  Wed Dec  3 20:34:04 2025
From: anshuman.khandual at arm.com (Anshuman Khandual)
Date: Thu, 4 Dec 2025 10:04:04 +0530
Subject: [PATCH v5 07/12] mm: bail out of lazy_mmu_mode_* in interrupt
 context
In-Reply-To: <20251124132228.622678-8-kevin.brodsky@arm.com>
References: <20251124132228.622678-1-kevin.brodsky@arm.com>
 <20251124132228.622678-8-kevin.brodsky@arm.com>
Message-ID: <565ac89c-1e7a-4e2f-a866-15039fbe22f6@arm.com>

On 24/11/25 6:52 PM, Kevin Brodsky wrote:
> The lazy MMU mode cannot be used in interrupt context. This is
> documented in <linux/pgtable.h>, but isn't consistently handled
> across architectures.
> 
> arm64 ensures that calls to lazy_mmu_mode_* have no effect in
> interrupt context, because such calls do occur in certain
> configurations - see commit b81c688426a9 ("arm64/mm: Disable barrier
> batching in interrupt contexts"). Other architectures do not check
> this situation, most likely because it hasn't occurred so far.
> 
> Let's handle this in the new generic lazy_mmu layer, in the same
> fashion as arm64: bail out of lazy_mmu_mode_* if in_interrupt().
> Also remove the arm64 handling that is now redundant.

Ensuring a common behaviour across platforms such as this in interrupt
context bail out - can now be easily achieved now as there are generic
helpers that call the platform ones.

> > Both arm64 and x86/Xen also ensure that any lazy MMU optimisation is
> disabled while in interrupt (see queue_pte_barriers() and
> xen_get_lazy_mode() respectively). This will be handled in the
> generic layer in a subsequent patch.

Makes sense.

> 
> Signed-off-by: Kevin Brodsky <kevin.brodsky at arm.com>
> ---
>  arch/arm64/include/asm/pgtable.h |  9 ---------
>  include/linux/pgtable.h          | 17 +++++++++++++++--
>  2 files changed, 15 insertions(+), 11 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
> index 54f8d6bb6f22..e596899f4029 100644
> --- a/arch/arm64/include/asm/pgtable.h
> +++ b/arch/arm64/include/asm/pgtable.h
> @@ -94,26 +94,17 @@ static inline void arch_enter_lazy_mmu_mode(void)
>  	 * keeps tracking simple.
>  	 */
>  
> -	if (in_interrupt())
> -		return;
> -
>  	set_thread_flag(TIF_LAZY_MMU);
>  }
>  
>  static inline void arch_flush_lazy_mmu_mode(void)
>  {
> -	if (in_interrupt())
> -		return;
> -
>  	if (test_and_clear_thread_flag(TIF_LAZY_MMU_PENDING))
>  		emit_pte_barriers();
>  }
>  
>  static inline void arch_leave_lazy_mmu_mode(void)
>  {
> -	if (in_interrupt())
> -		return;
> -
>  	arch_flush_lazy_mmu_mode();
>  	clear_thread_flag(TIF_LAZY_MMU);
>  }
> diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
> index c121358dba15..8ff6fdb4b13d 100644
> --- a/include/linux/pgtable.h
> +++ b/include/linux/pgtable.h
> @@ -228,27 +228,40 @@ static inline int pmd_dirty(pmd_t pmd)
>   * of the lazy mode. So the implementation must assume preemption may be enabled
>   * and cpu migration is possible; it must take steps to be robust against this.
>   * (In practice, for user PTE updates, the appropriate page table lock(s) are
> - * held, but for kernel PTE updates, no lock is held). Nesting is not permitted
> - * and the mode cannot be used in interrupt context.
> + * held, but for kernel PTE updates, no lock is held). The mode is disabled in
> + * interrupt context and calls to the lazy_mmu API have no effect.
> + * Nesting is not permitted.

Right - nesting is still not not permitted.

>   */>  #ifdef CONFIG_ARCH_HAS_LAZY_MMU_MODE
>  static inline void lazy_mmu_mode_enable(void)
>  {
> +	if (in_interrupt())
> +		return;
> +
>  	arch_enter_lazy_mmu_mode();
>  }
>  
>  static inline void lazy_mmu_mode_disable(void)
>  {
> +	if (in_interrupt())
> +		return;
> +
>  	arch_leave_lazy_mmu_mode();
>  }
>  
>  static inline void lazy_mmu_mode_pause(void)
>  {
> +	if (in_interrupt())
> +		return;
> +
>  	arch_leave_lazy_mmu_mode();
>  }
>  
>  static inline void lazy_mmu_mode_resume(void)
>  {
> +	if (in_interrupt())
> +		return;
> +
>  	arch_enter_lazy_mmu_mode();
>  }
>  #else

LGTM

Reviewed-by: Anshuman Khandual <anshuman.khandual at arm.com>


From yuanfang.zhang at oss.qualcomm.com  Wed Dec  3 20:43:06 2025
From: yuanfang.zhang at oss.qualcomm.com (Yuanfang Zhang)
Date: Wed, 03 Dec 2025 20:43:06 -0800
Subject: [PATCH RESEND v5 0/3] coresight-tnoc: Add support for Interconnect
 TNOC
Message-ID: <20251203-itnoc-v5-0-5b97c63f2268@oss.qualcomm.com>

This patch series adds support for the Qualcomm CoreSight Interconnect TNOC
(Trace Network On Chip) block, which acts as a CoreSight graph link forwarding
trace data from subsystems to the Aggregator TNOC. Unlike the Aggregator TNOC,
this block does not support aggregation or ATID assignment.

Signed-off-by: Yuanfang Zhang <yuanfang.zhang at oss.qualcomm.com>
---
Changes in v5:
- Add the missing review-by tag for patch 3.
- Link to v4: https://lore.kernel.org/r/20250831-itnoc-v4-0-f0fb0ef822a5 at oss.qualcomm.com

Changes in v4:
- Fix unintended blank line removals in trace_noc_enable_hw.
- Link to v3: https://lore.kernel.org/r/20250828-itnoc-v3-0-f1b55dea7a27 at oss.qualcomm.com

Changes in v3:
- Add detail for changes in V2.
- Remove '#address-cells' and '#size-cells' properties from in-ports field.
- Fix comment indentation for packet description.
- Link to v2: https://lore.kernel.org/r/20250819-itnoc-v2-0-2d0e6be44e2f at oss.qualcomm.com

Changes in v2:
- Removed the trailing '|' after the description in qcom,coresight-itnoc.yaml.
- Dropped the 'select' section from the YAML file.
- Updated node name to use a more generic naming convention.
- Removed the 'items' property from the compatible field.
- Deleted the description for the reg property.
- Dropped clock-names and adjusted the order of clock-names and clocks.
- Moved additionalProperties to follow the $ref of out-ports.
- Change "atid" type from u32 to int, set it as "-EOPNOTSUPP" for non-AMBA device.
- Link to v1: https://lore.kernel.org/r/20250815-itnoc-v1-0-62c8e4f7ad32 at oss.qualcomm.com

---
Yuanfang Zhang (3):
      dt-bindings: arm: qcom: Add Coresight Interconnect TNOC
      coresight-tnoc: add platform driver to support Interconnect TNOC
      coresight-tnoc: Add runtime PM support for Interconnect TNOC

 .../bindings/arm/qcom,coresight-itnoc.yaml         |  90 ++++++++++++++
 drivers/hwtracing/coresight/coresight-tnoc.c       | 136 +++++++++++++++++++--
 2 files changed, 215 insertions(+), 11 deletions(-)
---
base-commit: 2b52cf338d39d684a1c6af298e8204902c026aca
change-id: 20250815-itnoc-460273d1b80c

Best regards,
-- 
Yuanfang Zhang <yuanfang.zhang at oss.qualcomm.com>



From yuanfang.zhang at oss.qualcomm.com  Wed Dec  3 20:43:07 2025
From: yuanfang.zhang at oss.qualcomm.com (Yuanfang Zhang)
Date: Wed, 03 Dec 2025 20:43:07 -0800
Subject: [PATCH RESEND v5 1/3] dt-bindings: arm: qcom: Add Coresight
 Interconnect TNOC
In-Reply-To: <20251203-itnoc-v5-0-5b97c63f2268@oss.qualcomm.com>
References: <20251203-itnoc-v5-0-5b97c63f2268@oss.qualcomm.com>
Message-ID: <20251203-itnoc-v5-1-5b97c63f2268@oss.qualcomm.com>

Add device tree binding for Qualcomm Coresight Interconnect Trace
Network On Chip (ITNOC). This TNOC acts as a CoreSight
graph link that forwards trace data from a subsystem to the
Aggregator TNOC, without aggregation or ATID functionality.

Signed-off-by: Yuanfang Zhang <yuanfang.zhang at oss.qualcomm.com>
Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
---
 .../bindings/arm/qcom,coresight-itnoc.yaml         | 90 ++++++++++++++++++++++
 1 file changed, 90 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-itnoc.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-itnoc.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..8936bb7c3e8ea267ca66e0cc3fc4dac33ba6de30
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/qcom,coresight-itnoc.yaml
@@ -0,0 +1,90 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/qcom,coresight-itnoc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Interconnect Trace Network On Chip - ITNOC
+
+maintainers:
+  - Yuanfang Zhang <yuanfang.zhang at oss.qualcomm.com>
+
+description:
+  The Interconnect TNOC is a CoreSight graph link that forwards trace data
+  from a subsystem to the Aggregator TNOC. Compared to Aggregator TNOC, it
+  does not have aggregation and ATID functionality.
+
+properties:
+  $nodename:
+    pattern: "^itnoc(@[0-9a-f]+)?$"
+
+  compatible:
+    const: qcom,coresight-itnoc
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: apb
+
+  in-ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+
+    patternProperties:
+      '^port(@[0-9a-f]{1,2})?$':
+        description: Input connections from CoreSight Trace Bus
+        $ref: /schemas/graph.yaml#/properties/port
+
+  out-ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+    additionalProperties: false
+
+    properties:
+      port:
+        description: out connections to aggregator TNOC
+        $ref: /schemas/graph.yaml#/properties/port
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - in-ports
+  - out-ports
+
+additionalProperties: false
+
+examples:
+  - |
+    itnoc at 109ac000 {
+        compatible = "qcom,coresight-itnoc";
+        reg = <0x109ac000 0x1000>;
+
+        clocks = <&aoss_qmp>;
+        clock-names = "apb";
+
+        in-ports {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            port at 0 {
+                reg = <0>;
+                tn_ic_in_tpdm_dcc: endpoint {
+                    remote-endpoint = <&tpdm_dcc_out_tn_ic>;
+                };
+            };
+        };
+
+        out-ports {
+            port {
+                tn_ic_out_tnoc_aggr: endpoint {
+                    /* to Aggregator TNOC input */
+                    remote-endpoint = <&tn_ag_in_tn_ic>;
+                };
+            };
+        };
+    };
+...

-- 
2.34.1



From yuanfang.zhang at oss.qualcomm.com  Wed Dec  3 20:43:08 2025
From: yuanfang.zhang at oss.qualcomm.com (Yuanfang Zhang)
Date: Wed, 03 Dec 2025 20:43:08 -0800
Subject: [PATCH RESEND v5 2/3] coresight-tnoc: add platform driver to
 support Interconnect TNOC
In-Reply-To: <20251203-itnoc-v5-0-5b97c63f2268@oss.qualcomm.com>
References: <20251203-itnoc-v5-0-5b97c63f2268@oss.qualcomm.com>
Message-ID: <20251203-itnoc-v5-2-5b97c63f2268@oss.qualcomm.com>

This patch adds platform driver support for the CoreSight Interconnect
TNOC, Interconnect TNOC is a CoreSight link that forwards trace data
from a subsystem to the Aggregator TNOC. Compared to Aggregator TNOC,
it does not have aggregation and ATID functionality.

Key changes:
- Add platform driver `coresight-itnoc` with device tree match support.
- Refactor probe logic into a common `_tnoc_probe()` function.
- Conditionally initialize ATID only for AMBA-based TNOC blocks.

Signed-off-by: Yuanfang Zhang <yuanfang.zhang at oss.qualcomm.com>
Reviewed-by: Leo Yan <leo.yan at arm.com>
---
 drivers/hwtracing/coresight/coresight-tnoc.c | 113 ++++++++++++++++++++++++---
 1 file changed, 102 insertions(+), 11 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tnoc.c b/drivers/hwtracing/coresight/coresight-tnoc.c
index d542df46ea39314605290311f683010337bfd4bd..5be882300d79bc0173aa6a19d7da1d48c4aaca9c 100644
--- a/drivers/hwtracing/coresight/coresight-tnoc.c
+++ b/drivers/hwtracing/coresight/coresight-tnoc.c
@@ -34,6 +34,7 @@
  * @base:      memory mapped base address for this component.
  * @dev:       device node for trace_noc_drvdata.
  * @csdev:     component vitals needed by the framework.
+ * @pclk:	APB clock if present, otherwise NULL
  * @spinlock:  serialize enable/disable operation.
  * @atid:      id for the trace packet.
  */
@@ -41,8 +42,9 @@ struct trace_noc_drvdata {
 	void __iomem		*base;
 	struct device		*dev;
 	struct coresight_device	*csdev;
+	struct clk		*pclk;
 	spinlock_t		spinlock;
-	u32			atid;
+	int			atid;
 };
 
 DEFINE_CORESIGHT_DEVLIST(trace_noc_devs, "traceNoc");
@@ -51,6 +53,12 @@ static void trace_noc_enable_hw(struct trace_noc_drvdata *drvdata)
 {
 	u32 val;
 
+	/* No valid ATID, simply enable the unit */
+	if (drvdata->atid == -EOPNOTSUPP) {
+		writel(TRACE_NOC_CTRL_PORTEN, drvdata->base + TRACE_NOC_CTRL);
+		return;
+	}
+
 	/* Set ATID */
 	writel_relaxed(drvdata->atid, drvdata->base + TRACE_NOC_XLD);
 
@@ -124,6 +132,11 @@ static int trace_noc_init_default_data(struct trace_noc_drvdata *drvdata)
 {
 	int atid;
 
+	if (!dev_is_amba(drvdata->dev)) {
+		drvdata->atid = -EOPNOTSUPP;
+		return 0;
+	}
+
 	atid = coresight_trace_id_get_system_id();
 	if (atid < 0)
 		return atid;
@@ -149,8 +162,21 @@ static struct attribute *coresight_tnoc_attrs[] = {
 	NULL,
 };
 
+static umode_t trace_id_is_visible(struct kobject *kobj,
+				   struct attribute *attr, int idx)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct trace_noc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	if (attr == &dev_attr_traceid.attr && drvdata->atid < 0)
+		return 0;
+
+	return attr->mode;
+}
+
 static const struct attribute_group coresight_tnoc_group = {
 	.attrs = coresight_tnoc_attrs,
+	.is_visible = trace_id_is_visible,
 };
 
 static const struct attribute_group *coresight_tnoc_groups[] = {
@@ -158,9 +184,8 @@ static const struct attribute_group *coresight_tnoc_groups[] = {
 	NULL,
 };
 
-static int trace_noc_probe(struct amba_device *adev, const struct amba_id *id)
+static int _tnoc_probe(struct device *dev, struct resource *res)
 {
-	struct device *dev = &adev->dev;
 	struct coresight_platform_data *pdata;
 	struct trace_noc_drvdata *drvdata;
 	struct coresight_desc desc = { 0 };
@@ -173,16 +198,20 @@ static int trace_noc_probe(struct amba_device *adev, const struct amba_id *id)
 	pdata = coresight_get_platform_data(dev);
 	if (IS_ERR(pdata))
 		return PTR_ERR(pdata);
-	adev->dev.platform_data = pdata;
+	dev->platform_data = pdata;
 
 	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
 	if (!drvdata)
 		return -ENOMEM;
 
-	drvdata->dev = &adev->dev;
+	drvdata->dev = dev;
 	dev_set_drvdata(dev, drvdata);
 
-	drvdata->base = devm_ioremap_resource(dev, &adev->res);
+	ret = coresight_get_enable_clocks(dev, &drvdata->pclk, NULL);
+	if (ret)
+		return ret;
+
+	drvdata->base = devm_ioremap_resource(dev, res);
 	if (IS_ERR(drvdata->base))
 		return PTR_ERR(drvdata->base);
 
@@ -195,20 +224,31 @@ static int trace_noc_probe(struct amba_device *adev, const struct amba_id *id)
 	desc.ops = &trace_noc_cs_ops;
 	desc.type = CORESIGHT_DEV_TYPE_LINK;
 	desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG;
-	desc.pdata = adev->dev.platform_data;
-	desc.dev = &adev->dev;
+	desc.pdata = pdata;
+	desc.dev = dev;
 	desc.access = CSDEV_ACCESS_IOMEM(drvdata->base);
 	desc.groups = coresight_tnoc_groups;
 	drvdata->csdev = coresight_register(&desc);
 	if (IS_ERR(drvdata->csdev)) {
-		coresight_trace_id_put_system_id(drvdata->atid);
+		if (drvdata->atid > 0)
+			coresight_trace_id_put_system_id(drvdata->atid);
 		return PTR_ERR(drvdata->csdev);
 	}
-	pm_runtime_put(&adev->dev);
 
 	return 0;
 }
 
+static int trace_noc_probe(struct amba_device *adev, const struct amba_id *id)
+{
+	int ret;
+
+	ret = _tnoc_probe(&adev->dev, &adev->res);
+	if (!ret)
+		pm_runtime_put(&adev->dev);
+
+	return ret;
+}
+
 static void trace_noc_remove(struct amba_device *adev)
 {
 	struct trace_noc_drvdata *drvdata = dev_get_drvdata(&adev->dev);
@@ -236,7 +276,58 @@ static struct amba_driver trace_noc_driver = {
 	.id_table	= trace_noc_ids,
 };
 
-module_amba_driver(trace_noc_driver);
+static int itnoc_probe(struct platform_device *pdev)
+{
+	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	int ret;
+
+	pm_runtime_get_noresume(&pdev->dev);
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
+	ret = _tnoc_probe(&pdev->dev, res);
+	pm_runtime_put(&pdev->dev);
+	if (ret)
+		pm_runtime_disable(&pdev->dev);
+
+	return ret;
+}
+
+static void itnoc_remove(struct platform_device *pdev)
+{
+	struct trace_noc_drvdata *drvdata = platform_get_drvdata(pdev);
+
+	coresight_unregister(drvdata->csdev);
+	pm_runtime_disable(&pdev->dev);
+}
+
+static const struct of_device_id itnoc_of_match[] = {
+	{ .compatible = "qcom,coresight-itnoc" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, itnoc_of_match);
+
+static struct platform_driver itnoc_driver = {
+	.probe = itnoc_probe,
+	.remove = itnoc_remove,
+	.driver = {
+		.name = "coresight-itnoc",
+		.of_match_table = itnoc_of_match,
+		.suppress_bind_attrs = true,
+	},
+};
+
+static int __init tnoc_init(void)
+{
+	return coresight_init_driver("tnoc", &trace_noc_driver, &itnoc_driver, THIS_MODULE);
+}
+
+static void __exit tnoc_exit(void)
+{
+	coresight_remove_driver(&trace_noc_driver, &itnoc_driver);
+}
+module_init(tnoc_init);
+module_exit(tnoc_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Trace NOC driver");

-- 
2.34.1



From yuanfang.zhang at oss.qualcomm.com  Wed Dec  3 20:43:09 2025
From: yuanfang.zhang at oss.qualcomm.com (Yuanfang Zhang)
Date: Wed, 03 Dec 2025 20:43:09 -0800
Subject: [PATCH RESEND v5 3/3] coresight-tnoc: Add runtime PM support for
 Interconnect TNOC
In-Reply-To: <20251203-itnoc-v5-0-5b97c63f2268@oss.qualcomm.com>
References: <20251203-itnoc-v5-0-5b97c63f2268@oss.qualcomm.com>
Message-ID: <20251203-itnoc-v5-3-5b97c63f2268@oss.qualcomm.com>

This patch adds runtime power management support for platform-based
CoreSight Interconnect TNOC (ITNOC) devices. It introduces suspend and
resume callbacks to manage the APB clock (`pclk`) during device runtime
transitions.

Signed-off-by: Yuanfang Zhang <yuanfang.zhang at oss.qualcomm.com>
Reviewed-by: Leo Yan <leo.yan at arm.com>
---
 drivers/hwtracing/coresight/coresight-tnoc.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/hwtracing/coresight/coresight-tnoc.c b/drivers/hwtracing/coresight/coresight-tnoc.c
index 5be882300d79bc0173aa6a19d7da1d48c4aaca9c..2c5370497076536bfa868f0d80db775ef242968b 100644
--- a/drivers/hwtracing/coresight/coresight-tnoc.c
+++ b/drivers/hwtracing/coresight/coresight-tnoc.c
@@ -301,6 +301,28 @@ static void itnoc_remove(struct platform_device *pdev)
 	pm_runtime_disable(&pdev->dev);
 }
 
+#ifdef CONFIG_PM
+static int itnoc_runtime_suspend(struct device *dev)
+{
+	struct trace_noc_drvdata *drvdata = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(drvdata->pclk);
+
+	return 0;
+}
+
+static int itnoc_runtime_resume(struct device *dev)
+{
+	struct trace_noc_drvdata *drvdata = dev_get_drvdata(dev);
+
+	return clk_prepare_enable(drvdata->pclk);
+}
+#endif
+
+static const struct dev_pm_ops itnoc_dev_pm_ops = {
+	SET_RUNTIME_PM_OPS(itnoc_runtime_suspend, itnoc_runtime_resume, NULL)
+};
+
 static const struct of_device_id itnoc_of_match[] = {
 	{ .compatible = "qcom,coresight-itnoc" },
 	{}
@@ -314,6 +336,7 @@ static struct platform_driver itnoc_driver = {
 		.name = "coresight-itnoc",
 		.of_match_table = itnoc_of_match,
 		.suppress_bind_attrs = true,
+		.pm = &itnoc_dev_pm_ops,
 	},
 };
 

-- 
2.34.1



From cuiyunhui at bytedance.com  Wed Dec  3 21:00:40 2025
From: cuiyunhui at bytedance.com (yunhui cui)
Date: Thu, 4 Dec 2025 13:00:40 +0800
Subject: [External] Re: [PATCH v6 0/2] Add HARDLOCKUP_DETECTOR_PERF
 support for RISC-V
In-Reply-To: <CAD=FV=Vh-guJS+5BAqhao9aECtkRFgoqEjpzhuDYEsRVqtVA6w@mail.gmail.com>
References: <20251114033243.76509-1-cuiyunhui@bytedance.com> <CAD=FV=Vh-guJS+5BAqhao9aECtkRFgoqEjpzhuDYEsRVqtVA6w@mail.gmail.com>
Message-ID: <CAEEQ3wmz=CHkbxZwyMHGTSeXj0OFjBskgzyEKeZHk9rNOWge+w@mail.gmail.com>

Hi Andrew,

On Sat, Nov 15, 2025 at 3:21?AM Doug Anderson <dianders at chromium.org> wrote:
>
> Hi,
>
> On Thu, Nov 13, 2025 at 7:33?PM Yunhui Cui <cuiyunhui at bytedance.com> wrote:
> >
> > After discussion [1],[2], hardlockup_perf cannot be completely replaced by
> > the hardlockup_buddy approach, so this patch is still being submitted.
> >
> > v1->v2:
> > The contents of arch/arm64/watchdog_hld.c are directly consolidated into
> > kernel/watchdog_perf.c.
> >
> >
> > v2->v3:
> > Add CONFIG_WATCHDOG_PERF_ADJUST_PERIOD to enclose the period update logic,
> > select it by default on arm64 and riscv, without affecting other arches
> > like x86 and PPC.
> >
> > v3->v4:
> > Place the line "select WATCHDOG_PERF_ADJUST_PERIOD if HARDLOCKUP_DETECTOR_PERF && CPU_FREQ"
> > in the Kconfig files for arm64 and riscv in one line, with no line breaks.
> >
> > v4->v5:
> > Remove __weak from hw_nmi_get_sample_period()
> >
> > v5->v6:
> > Removed the dependency on CPU_FREQ for WATCHDOG_PERF_ADJUST_PERIOD in Kconfig, which fixes the
> > issue reported at: https://lore.kernel.org/oe-kbuild-all/202510240701.eB6r97V3-lkp at intel.com/
>
> I haven't tried compiling this myself, but it seems like an OK
> solution for the compile-time error to me.
>
> -Doug

Could you please help review and merge this again? Thank you!

>

Thanks,
Yunhui


From cuiyunhui at bytedance.com  Wed Dec  3 21:18:00 2025
From: cuiyunhui at bytedance.com (yunhui cui)
Date: Thu, 4 Dec 2025 13:18:00 +0800
Subject: [External] Re: [PATCH v3 8/8] drivers: firmware: riscv: add
 unknown nmi support
In-Reply-To: <DEP50CD8K22E.1JW7GL6WLK44W@ventanamicro.com>
References: <20251127125305.89961-1-cuiyunhui@bytedance.com>
 <20251127125305.89961-9-cuiyunhui@bytedance.com> <DEP50CD8K22E.1JW7GL6WLK44W@ventanamicro.com>
Message-ID: <CAEEQ3wkmFXAqBfHwJYbJRc5pagOJvtu-wEYGwXBF2beQiSMT1w@mail.gmail.com>

Hi Radim,

On Thu, Dec 4, 2025 at 12:11?PM Radim Kr?m?? <rkrcmar at ventanamicro.com> wrote:
>
> 2025-11-27T20:53:05+08:00, Yunhui Cui <cuiyunhui at bytedance.com>:
> > Register unknown_nmi_handler() as the handler for the UNKNOWN_NMI
> > event. When the system becomes unresponsive, unknown_nmi_handler()
> > can be manually triggered, which in turn invokes nmi_panic() to
> > collect vmcore for root cause analysis.
>
> Is UNKNOWN_NMI what we expect the watchdog to send?

For reference: As stated in
https://github.com/riscv-non-isa/riscv-sbi-doc/pull/223, "Generally,
an external interrupt is used as an Unknown NMI pin, and an Unknown
NMI event is sent to the SBI firmware by triggering this pin. Then the
SBI firmware will send SBI_SSE_EVENT_GLOBAL_UNKNOWN_NMI to the
kernel."

When the Linux system is unresponsive, we can manually trigger it via
BMC (ipmitool).

>
> Thanks.

Thanks,
Yunhui


From anshuman.khandual at arm.com  Wed Dec  3 21:25:51 2025
From: anshuman.khandual at arm.com (Anshuman Khandual)
Date: Thu, 4 Dec 2025 10:55:51 +0530
Subject: [PATCH v5 08/12] mm: enable lazy_mmu sections to nest
In-Reply-To: <703cbee6-a813-4970-9232-34ee91ed8961@arm.com>
References: <20251124132228.622678-1-kevin.brodsky@arm.com>
 <20251124132228.622678-9-kevin.brodsky@arm.com>
 <23dcf752-0b75-45a7-84f8-25bddf97af08-agordeev@linux.ibm.com>
 <703cbee6-a813-4970-9232-34ee91ed8961@arm.com>
Message-ID: <2c2b3382-7bdb-41a9-b48e-4fa9a44312ba@arm.com>



On 03/12/25 1:50 PM, Kevin Brodsky wrote:
> On 28/11/2025 14:55, Alexander Gordeev wrote:
>>> + * in_lazy_mmu_mode() can be used to check whether the lazy MMU mode is
>>> + * currently enabled.
>> The in_lazy_mmu_mode() name looks ambiguous to me. When the lazy MMU mode
>> is paused are we still in lazy MMU mode? The __task_lazy_mmu_mode_active()
>> implementation suggests we are not, while one could still assume we are,
>> just paused.
>>
>> Should in_lazy_mmu_mode() be named e.g. as in_active_lazy_mmu_mode() such
>> a confusion would not occur in the first place.
> 
> I see your point, how about is_lazy_mmu_mode_active()?

Agreed - is_lazy_mmu_mode_active() seems better.


From cuiyunhui at bytedance.com  Wed Dec  3 21:28:45 2025
From: cuiyunhui at bytedance.com (yunhui cui)
Date: Thu, 4 Dec 2025 13:28:45 +0800
Subject: [External] Re: [PATCH v3 5/8] riscv: smp: use NMI for CPU stop
In-Reply-To: <DEP4X1DAIOU5.2WLIV4BMWLMRR@ventanamicro.com>
References: <20251127125305.89961-1-cuiyunhui@bytedance.com>
 <20251127125305.89961-6-cuiyunhui@bytedance.com> <DEP4X1DAIOU5.2WLIV4BMWLMRR@ventanamicro.com>
Message-ID: <CAEEQ3wmAn=9w=fR=OMTMF17_tAcEnsdJWL_w8fw-3wA-Bfi6xw@mail.gmail.com>

Hi Radim,

On Thu, Dec 4, 2025 at 12:07?PM Radim Kr?m?? <rkrcmar at ventanamicro.com> wrote:
>
> 2025-11-27T20:53:02+08:00, Yunhui Cui <cuiyunhui at bytedance.com>:
> > Use NMI instead of IPI for CPU stop if RISC-V SSE NMI is supported.
> >
> > Signed-off-by: Yunhui Cui <cuiyunhui at bytedance.com>
> > ---
> > diff --git a/drivers/firmware/riscv/riscv_sse_nmi.c b/drivers/firmware/riscv/riscv_sse_nmi.c
> > @@ -58,6 +58,7 @@ static int local_nmi_handler(u32 evt, void *arg, struct pt_regs *regs)
> >       type = atomic_read(this_cpu_ptr(&local_nmi));
> >
> >       NMI_HANDLE(LOCAL_NMI_CRASH, cpu_crash_stop, cpu, regs);
> > +     NMI_HANDLE(LOCAL_NMI_STOP, cpu_stop);
>
> Please document the intended preemption design for all SSE events,
> because it will be a nightmare if we forget some assumptions in the
> coming years.  (That includes the relative priorities of RAS/PMU/...)

Actually, LOCAL_NMI_CRASH, LOCAL_NMI_STOP, LOCAL_NMI_BACKTRACE,
LOCAL_NMI_KGDB, ... are all implemented via the single SSE event
SBI_SSE_EVENT_LOCAL_SOFTWARE_INJECTED. Per the SSE design, no
preemption will occur among CRASH, STOP, BACKTRACE, and KGDB events.

>
> Thanks.

Thanks,
Yunhui


From jian.hu at amlogic.com  Wed Dec  3 21:36:29 2025
From: jian.hu at amlogic.com (Jian Hu)
Date: Thu, 4 Dec 2025 13:36:29 +0800
Subject: [PATCH v6 0/5] add support for T7 family clock controller
Message-ID: <20251204053635.1234150-1-jian.hu@amlogic.com>

It introduces three clock controllers:
- SCMI clock controller: these clocks are managed by the SCP and handled through SCMI.
- PLL clock controller.
- peripheral clock controller.

Changes v6 since v5 at [5]:
- add a blank line after each PLL register region
- update GP1 PLL note
- update PLL and peripherals help message
- add parentheses around the _iflags member in MESON_COMP_GATE
- drop CLK_SET_RATE_PARENT and the 4th parent for rtc
- move sd_emmc_c after sd_emmc_b

Changes v5 since v4 at [4]:
- rename rtc and cec dualdiv clocks
- rename dsp clocks
- rename anakin clocks
- rename fdiv2_divn to 25m and fix its parent
- add flag for T7_COMP_GATE
- use T7_COMP_SEL/DIV/GATE to define glitch clocks
- add CLK_SET_RATE_NO_REPARENT for t7_eth_rmii_sel and rtc
- move module_platform_driver after clock driver

Changes v4 since v3 at [3]:
- drop amlogic_t7_pll_probe, use meson_clkc_mmio_probe instead
- add CLK_DIVIDER_MAX_AT_ZERO for pcie_pll_od clk
- add frac for hifi_dco_pll_dco
- add l_detect for mclk_pll_dco
- drop v3 5/6 patch, and use MESON_PCLK
- drop SPI_PWM_CLK_XX macro and use MESON_COMP_XX
- drop the register's prefix

Changes v3 since v2 at [2]:
- update T7 PLL YAML
- add 't7_' prefix for t7 clock name and variable in t7-pll.c and t7-peripherals.c
- correct v1 patch link
- add new macro MESON_PCLK_V2
- update the driver,header,yaml file license

Changes v2 since v1 at [1]:
- add CLK_MESON import
- add const for clkc_regmap_config in PLL driver
- fix eth_rmii_sel parent
- update T7 PLL YAML file

[1]: https://lore.kernel.org/all/20241231060047.2298871-1-jian.hu at amlogic.com
[2]: https://lore.kernel.org/all/20250108094025.2664201-1-jian.hu at amlogic.com
[3]: https://lore.kernel.org/all/20250509074825.1933254-1-jian.hu at amlogic.com
[4]: https://lore.kernel.org/all/20251030094345.2571222-1-jian.hu at amlogic.com
[5]: https://lore.kernel.org/all/20251121105934.1759745-1-jian.hu at amlogic.com
Jian Hu (5):
  dt-bindings: clock: add Amlogic T7 PLL clock controller
  dt-bindings: clock: add Amlogic T7 SCMI clock controller
  dt-bindings: clock: add Amlogic T7 peripherals clock controller
  clk: meson: t7: add support for the T7 SoC PLL clock
  clk: meson: t7: add t7 clock peripherals controller driver

 .../clock/amlogic,t7-peripherals-clkc.yaml    |  116 ++
 .../bindings/clock/amlogic,t7-pll-clkc.yaml   |  114 ++
 drivers/clk/meson/Kconfig                     |   27 +
 drivers/clk/meson/Makefile                    |    2 +
 drivers/clk/meson/t7-peripherals.c            | 1271 +++++++++++++++++
 drivers/clk/meson/t7-pll.c                    | 1074 ++++++++++++++
 .../clock/amlogic,t7-peripherals-clkc.h       |  228 +++
 .../dt-bindings/clock/amlogic,t7-pll-clkc.h   |   56 +
 include/dt-bindings/clock/amlogic,t7-scmi.h   |   47 +
 9 files changed, 2935 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/amlogic,t7-peripherals-clkc.yaml
 create mode 100644 Documentation/devicetree/bindings/clock/amlogic,t7-pll-clkc.yaml
 create mode 100644 drivers/clk/meson/t7-peripherals.c
 create mode 100644 drivers/clk/meson/t7-pll.c
 create mode 100644 include/dt-bindings/clock/amlogic,t7-peripherals-clkc.h
 create mode 100644 include/dt-bindings/clock/amlogic,t7-pll-clkc.h
 create mode 100644 include/dt-bindings/clock/amlogic,t7-scmi.h

-- 
2.47.1



From jian.hu at amlogic.com  Wed Dec  3 21:36:30 2025
From: jian.hu at amlogic.com (Jian Hu)
Date: Thu, 4 Dec 2025 13:36:30 +0800
Subject: [PATCH v6 1/5] dt-bindings: clock: add Amlogic T7 PLL clock controller
In-Reply-To: <20251204053635.1234150-1-jian.hu@amlogic.com>
References: <20251204053635.1234150-1-jian.hu@amlogic.com>
Message-ID: <20251204053635.1234150-2-jian.hu@amlogic.com>

Add DT bindings for the PLL clock controller of the Amlogic T7 SoC family.

Signed-off-by: Jian Hu <jian.hu at amlogic.com>
Reviewed-by: Conor Dooley <conor.dooley at microchip.com>
---
 .../bindings/clock/amlogic,t7-pll-clkc.yaml   | 114 ++++++++++++++++++
 .../dt-bindings/clock/amlogic,t7-pll-clkc.h   |  56 +++++++++
 2 files changed, 170 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/amlogic,t7-pll-clkc.yaml
 create mode 100644 include/dt-bindings/clock/amlogic,t7-pll-clkc.h

diff --git a/Documentation/devicetree/bindings/clock/amlogic,t7-pll-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,t7-pll-clkc.yaml
new file mode 100644
index 000000000000..49c61f65deff
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/amlogic,t7-pll-clkc.yaml
@@ -0,0 +1,114 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2024-2025 Amlogic, Inc. All rights reserved
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/amlogic,t7-pll-clkc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Amlogic T7 PLL Clock Control Controller
+
+maintainers:
+  - Neil Armstrong <neil.armstrong at linaro.org>
+  - Jerome Brunet <jbrunet at baylibre.com>
+  - Jian Hu <jian.hu at amlogic.com>
+  - Xianwei Zhao <xianwei.zhao at amlogic.com>
+
+properties:
+  compatible:
+    enum:
+      - amlogic,t7-gp0-pll
+      - amlogic,t7-gp1-pll
+      - amlogic,t7-hifi-pll
+      - amlogic,t7-pcie-pll
+      - amlogic,t7-mpll
+      - amlogic,t7-hdmi-pll
+      - amlogic,t7-mclk-pll
+
+  reg:
+    maxItems: 1
+
+  '#clock-cells':
+    const: 1
+
+  clocks:
+    items:
+      - description: mclk pll input oscillator gate
+      - description: oscillator input clock source for mclk_sel_0
+      - description: fixed input clock source for mclk_sel_0
+    minItems: 1
+
+  clock-names:
+    items:
+      - const: in0
+      - const: in1
+      - const: in2
+    minItems: 1
+
+required:
+  - compatible
+  - '#clock-cells'
+  - reg
+  - clocks
+  - clock-names
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: amlogic,t7-mclk-pll
+
+    then:
+      properties:
+        clocks:
+          minItems: 3
+
+        clock-names:
+          minItems: 3
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - amlogic,t7-gp0-pll
+              - amlogic,t7-gp1--pll
+              - amlogic,t7-hifi-pll
+              - amlogic,t7-pcie-pll
+              - amlogic,t7-mpll
+              - amlogic,t7-hdmi-pll
+
+    then:
+      properties:
+        clocks:
+          maxItems: 1
+
+        clock-names:
+          maxItems: 1
+
+additionalProperties: false
+
+examples:
+  - |
+    apb {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        clock-controller at 8080 {
+            compatible = "amlogic,t7-gp0-pll";
+            reg = <0 0x8080 0 0x20>;
+            clocks = <&scmi_clk 2>;
+            clock-names = "in0";
+            #clock-cells = <1>;
+        };
+
+        clock-controller at 8300 {
+            compatible = "amlogic,t7-mclk-pll";
+            reg = <0 0x8300 0 0x18>;
+            clocks = <&scmi_clk 2>,
+                     <&xtal>,
+                     <&scmi_clk 31>;
+            clock-names = "in0", "in1", "in2";
+            #clock-cells = <1>;
+        };
+    };
diff --git a/include/dt-bindings/clock/amlogic,t7-pll-clkc.h b/include/dt-bindings/clock/amlogic,t7-pll-clkc.h
new file mode 100644
index 000000000000..e2481f2f1163
--- /dev/null
+++ b/include/dt-bindings/clock/amlogic,t7-pll-clkc.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
+/*
+ * Copyright (C) 2024-2025 Amlogic, Inc. All rights reserved
+ */
+
+#ifndef __T7_PLL_CLKC_H
+#define __T7_PLL_CLKC_H
+
+/* GP0 */
+#define CLKID_GP0_PLL_DCO	0
+#define CLKID_GP0_PLL		1
+
+/* GP1 */
+#define CLKID_GP1_PLL_DCO	0
+#define CLKID_GP1_PLL		1
+
+/* HIFI */
+#define CLKID_HIFI_PLL_DCO	0
+#define CLKID_HIFI_PLL		1
+
+/* PCIE */
+#define CLKID_PCIE_PLL_DCO	0
+#define CLKID_PCIE_PLL_DCO_DIV2	1
+#define CLKID_PCIE_PLL_OD	2
+#define CLKID_PCIE_PLL		3
+
+/* MPLL */
+#define CLKID_MPLL_PREDIV	0
+#define CLKID_MPLL0_DIV		1
+#define CLKID_MPLL0		2
+#define CLKID_MPLL1_DIV		3
+#define CLKID_MPLL1		4
+#define CLKID_MPLL2_DIV		5
+#define CLKID_MPLL2		6
+#define CLKID_MPLL3_DIV		7
+#define CLKID_MPLL3		8
+
+/* HDMI */
+#define CLKID_HDMI_PLL_DCO	0
+#define CLKID_HDMI_PLL_OD	1
+#define CLKID_HDMI_PLL		2
+
+/* MCLK */
+#define CLKID_MCLK_PLL_DCO	0
+#define CLKID_MCLK_PRE		1
+#define CLKID_MCLK_PLL		2
+#define CLKID_MCLK_0_SEL	3
+#define CLKID_MCLK_0_DIV2	4
+#define CLKID_MCLK_0_PRE	5
+#define CLKID_MCLK_0		6
+#define CLKID_MCLK_1_SEL	7
+#define CLKID_MCLK_1_DIV2	8
+#define CLKID_MCLK_1_PRE	9
+#define CLKID_MCLK_1		10
+
+#endif /* __T7_PLL_CLKC_H */
-- 
2.47.1



From jian.hu at amlogic.com  Wed Dec  3 21:36:31 2025
From: jian.hu at amlogic.com (Jian Hu)
Date: Thu, 4 Dec 2025 13:36:31 +0800
Subject: [PATCH v6 2/5] dt-bindings: clock: add Amlogic T7 SCMI clock controller
In-Reply-To: <20251204053635.1234150-1-jian.hu@amlogic.com>
References: <20251204053635.1234150-1-jian.hu@amlogic.com>
Message-ID: <20251204053635.1234150-3-jian.hu@amlogic.com>

Add DT bindings for the SCMI clock controller of the Amlogic T7 SoC family.

Signed-off-by: Jian Hu <jian.hu at amlogic.com>
Acked-by: Rob Herring (Arm) <robh at kernel.org>
---
 include/dt-bindings/clock/amlogic,t7-scmi.h | 47 +++++++++++++++++++++
 1 file changed, 47 insertions(+)
 create mode 100644 include/dt-bindings/clock/amlogic,t7-scmi.h

diff --git a/include/dt-bindings/clock/amlogic,t7-scmi.h b/include/dt-bindings/clock/amlogic,t7-scmi.h
new file mode 100644
index 000000000000..27bd257bd4ea
--- /dev/null
+++ b/include/dt-bindings/clock/amlogic,t7-scmi.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
+/*
+ * Copyright (C) 2024-2025 Amlogic, Inc. All rights reserved
+ */
+
+#ifndef __T7_SCMI_CLKC_H
+#define __T7_SCMI_CLKC_H
+
+#define CLKID_DDR_PLL_OSC			0
+#define CLKID_AUD_PLL_OSC			1
+#define CLKID_TOP_PLL_OSC			2
+#define CLKID_TCON_PLL_OSC			3
+#define CLKID_USB_PLL0_OSC			4
+#define CLKID_USB_PLL1_OSC			5
+#define CLKID_MCLK_PLL_OSC			6
+#define CLKID_PCIE_OSC				7
+#define CLKID_ETH_PLL_OSC			8
+#define CLKID_PCIE_REFCLK_PLL_OSC		9
+#define CLKID_EARC_OSC				10
+#define CLKID_SYS1_PLL_OSC			11
+#define CLKID_HDMI_PLL_OSC			12
+#define CLKID_SYS_CLK				13
+#define CLKID_AXI_CLK				14
+#define CLKID_FIXED_PLL_DCO			15
+#define CLKID_FIXED_PLL				16
+#define CLKID_FCLK_DIV2_DIV			17
+#define CLKID_FCLK_DIV2				18
+#define CLKID_FCLK_DIV2P5_DIV			19
+#define CLKID_FCLK_DIV2P5			20
+#define CLKID_FCLK_DIV3_DIV			21
+#define CLKID_FCLK_DIV3				22
+#define CLKID_FCLK_DIV4_DIV			23
+#define CLKID_FCLK_DIV4				24
+#define CLKID_FCLK_DIV5_DIV			25
+#define CLKID_FCLK_DIV5				26
+#define CLKID_FCLK_DIV7_DIV			27
+#define CLKID_FCLK_DIV7				28
+#define CLKID_FCLK_50M_DIV			29
+#define CLKID_FCLK_50M				30
+#define CLKID_CPU_CLK				31
+#define CLKID_A73_CLK				32
+#define CLKID_CPU_CLK_DIV16_DIV			33
+#define CLKID_CPU_CLK_DIV16			34
+#define CLKID_A73_CLK_DIV16_DIV			35
+#define CLKID_A73_CLK_DIV16			36
+
+#endif /* __T7_SCMI_CLKC_H */
-- 
2.47.1



From jian.hu at amlogic.com  Wed Dec  3 21:36:32 2025
From: jian.hu at amlogic.com (Jian Hu)
Date: Thu, 4 Dec 2025 13:36:32 +0800
Subject: [PATCH v6 3/5] dt-bindings: clock: add Amlogic T7 peripherals clock controller
In-Reply-To: <20251204053635.1234150-1-jian.hu@amlogic.com>
References: <20251204053635.1234150-1-jian.hu@amlogic.com>
Message-ID: <20251204053635.1234150-4-jian.hu@amlogic.com>

Add DT bindings for the peripheral clock controller of the Amlogic T7
SoC family.

Signed-off-by: Jian Hu <jian.hu at amlogic.com>
Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
---
 .../clock/amlogic,t7-peripherals-clkc.yaml    | 116 +++++++++
 .../clock/amlogic,t7-peripherals-clkc.h       | 228 ++++++++++++++++++
 2 files changed, 344 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/amlogic,t7-peripherals-clkc.yaml
 create mode 100644 include/dt-bindings/clock/amlogic,t7-peripherals-clkc.h

diff --git a/Documentation/devicetree/bindings/clock/amlogic,t7-peripherals-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,t7-peripherals-clkc.yaml
new file mode 100644
index 000000000000..55bb73707d58
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/amlogic,t7-peripherals-clkc.yaml
@@ -0,0 +1,116 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2024-2025 Amlogic, Inc. All rights reserved
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/amlogic,t7-peripherals-clkc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Amlogic T7 Peripherals Clock Controller
+
+maintainers:
+  - Neil Armstrong <neil.armstrong at linaro.org>
+  - Jerome Brunet <jbrunet at baylibre.com>
+  - Xianwei Zhao <xianwei.zhao at amlogic.com>
+  - Jian Hu <jian.hu at amlogic.com>
+
+properties:
+  compatible:
+    const: amlogic,t7-peripherals-clkc
+
+  reg:
+    maxItems: 1
+
+  '#clock-cells':
+    const: 1
+
+  clocks:
+    minItems: 14
+    items:
+      - description: input oscillator
+      - description: input sys clk
+      - description: input fixed pll
+      - description: input fclk div 2
+      - description: input fclk div 2p5
+      - description: input fclk div 3
+      - description: input fclk div 4
+      - description: input fclk div 5
+      - description: input fclk div 7
+      - description: input hifi pll
+      - description: input gp0 pll
+      - description: input gp1 pll
+      - description: input mpll1
+      - description: input mpll2
+      - description: external input rmii oscillator (optional)
+      - description: input video pll0 (optional)
+      - description: external pad input for rtc (optional)
+
+  clock-names:
+    minItems: 14
+    items:
+      - const: xtal
+      - const: sys
+      - const: fix
+      - const: fdiv2
+      - const: fdiv2p5
+      - const: fdiv3
+      - const: fdiv4
+      - const: fdiv5
+      - const: fdiv7
+      - const: hifi
+      - const: gp0
+      - const: gp1
+      - const: mpll1
+      - const: mpll2
+      - const: ext_rmii
+      - const: vid_pll0
+      - const: ext_rtc
+
+required:
+  - compatible
+  - '#clock-cells'
+  - reg
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    apb {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        clkc_periphs:clock-controller at 0 {
+            compatible = "amlogic,t7-peripherals-clkc";
+            reg = <0 0x0 0 0x1c8>;
+            #clock-cells = <1>;
+            clocks = <&xtal>,
+                     <&scmi_clk 13>,
+                     <&scmi_clk 16>,
+                     <&scmi_clk 18>,
+                     <&scmi_clk 20>,
+                     <&scmi_clk 22>,
+                     <&scmi_clk 24>,
+                     <&scmi_clk 26>,
+                     <&scmi_clk 28>,
+                     <&hifi 1>,
+                     <&gp0 1>,
+                     <&gp1 1>,
+                     <&mpll 4>,
+                     <&mpll 6>;
+            clock-names = "xtal",
+                          "sys",
+                          "fix",
+                          "fdiv2",
+                          "fdiv2p5",
+                          "fdiv3",
+                          "fdiv4",
+                          "fdiv5",
+                          "fdiv7",
+                          "hifi",
+                          "gp0",
+                          "gp1",
+                          "mpll1",
+                          "mpll2";
+        };
+    };
diff --git a/include/dt-bindings/clock/amlogic,t7-peripherals-clkc.h b/include/dt-bindings/clock/amlogic,t7-peripherals-clkc.h
new file mode 100644
index 000000000000..32c4b62037de
--- /dev/null
+++ b/include/dt-bindings/clock/amlogic,t7-peripherals-clkc.h
@@ -0,0 +1,228 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
+/*
+ * Copyright (C) 2024-2025 Amlogic, Inc. All rights reserved
+ */
+
+#ifndef __T7_PERIPHERALS_CLKC_H
+#define __T7_PERIPHERALS_CLKC_H
+
+#define CLKID_RTC_DUALDIV_IN		0
+#define CLKID_RTC_DUALDIV_DIV		1
+#define CLKID_RTC_DUALDIV_SEL		2
+#define CLKID_RTC_DUALDIV		3
+#define CLKID_RTC			4
+#define CLKID_CECA_DUALDIV_IN		5
+#define CLKID_CECA_DUALDIV_DIV		6
+#define CLKID_CECA_DUALDIV_SEL		7
+#define CLKID_CECA_DUALDIV		8
+#define CLKID_CECA			9
+#define CLKID_CECB_DUALDIV_IN		10
+#define CLKID_CECB_DUALDIV_DIV		11
+#define CLKID_CECB_DUALDIV_SEL		12
+#define CLKID_CECB_DUALDIV		13
+#define CLKID_CECB			14
+#define CLKID_SC_SEL			15
+#define CLKID_SC_DIV			16
+#define CLKID_SC			17
+#define CLKID_DSPA_0_SEL		18
+#define CLKID_DSPA_0_DIV		19
+#define CLKID_DSPA_0			20
+#define CLKID_DSPA_1_SEL		21
+#define CLKID_DSPA_1_DIV		22
+#define CLKID_DSPA_1			23
+#define CLKID_DSPA			24
+#define CLKID_DSPB_0_SEL		25
+#define CLKID_DSPB_0_DIV		26
+#define CLKID_DSPB_0			27
+#define CLKID_DSPB_1_SEL		28
+#define CLKID_DSPB_1_DIV		29
+#define CLKID_DSPB_1			30
+#define CLKID_DSPB			31
+#define CLKID_24M			32
+#define CLKID_24M_DIV2			33
+#define CLKID_12M			34
+#define CLKID_25M_DIV			35
+#define CLKID_25M			36
+#define CLKID_ANAKIN_0_SEL		37
+#define CLKID_ANAKIN_0_DIV		38
+#define CLKID_ANAKIN_0			39
+#define CLKID_ANAKIN_1_SEL		40
+#define CLKID_ANAKIN_1_DIV		41
+#define CLKID_ANAKIN_1			42
+#define CLKID_ANAKIN_01_SEL		43
+#define CLKID_ANAKIN			44
+#define CLKID_TS_DIV			45
+#define CLKID_TS			46
+#define CLKID_MIPI_CSI_PHY_0_SEL	47
+#define CLKID_MIPI_CSI_PHY_0_DIV	48
+#define CLKID_MIPI_CSI_PHY_0		49
+#define CLKID_MIPI_CSI_PHY_1_SEL	50
+#define CLKID_MIPI_CSI_PHY_1_DIV	51
+#define CLKID_MIPI_CSI_PHY_1		52
+#define CLKID_MIPI_CSI_PHY		53
+#define CLKID_MIPI_ISP_SEL		54
+#define CLKID_MIPI_ISP_DIV		55
+#define CLKID_MIPI_ISP			56
+#define CLKID_MALI_0_SEL		57
+#define CLKID_MALI_0_DIV		58
+#define CLKID_MALI_0			59
+#define CLKID_MALI_1_SEL		60
+#define CLKID_MALI_1_DIV		61
+#define CLKID_MALI_1			62
+#define CLKID_MALI			63
+#define CLKID_ETH_RMII_SEL		64
+#define CLKID_ETH_RMII_DIV		65
+#define CLKID_ETH_RMII			66
+#define CLKID_FCLK_DIV2_DIV8		67
+#define CLKID_ETH_125M			68
+#define CLKID_SD_EMMC_A_SEL		69
+#define CLKID_SD_EMMC_A_DIV		70
+#define CLKID_SD_EMMC_A			71
+#define CLKID_SD_EMMC_B_SEL		72
+#define CLKID_SD_EMMC_B_DIV		73
+#define CLKID_SD_EMMC_B			74
+#define CLKID_SD_EMMC_C_SEL		75
+#define CLKID_SD_EMMC_C_DIV		76
+#define CLKID_SD_EMMC_C			77
+#define CLKID_SPICC0_SEL		78
+#define CLKID_SPICC0_DIV		79
+#define CLKID_SPICC0			80
+#define CLKID_SPICC1_SEL		81
+#define CLKID_SPICC1_DIV		82
+#define CLKID_SPICC1			83
+#define CLKID_SPICC2_SEL		84
+#define CLKID_SPICC2_DIV		85
+#define CLKID_SPICC2			86
+#define CLKID_SPICC3_SEL		87
+#define CLKID_SPICC3_DIV		88
+#define CLKID_SPICC3			89
+#define CLKID_SPICC4_SEL		90
+#define CLKID_SPICC4_DIV		91
+#define CLKID_SPICC4			92
+#define CLKID_SPICC5_SEL		93
+#define CLKID_SPICC5_DIV		94
+#define CLKID_SPICC5			95
+#define CLKID_SARADC_SEL		96
+#define CLKID_SARADC_DIV		97
+#define CLKID_SARADC			98
+#define CLKID_PWM_A_SEL			99
+#define CLKID_PWM_A_DIV			100
+#define CLKID_PWM_A			101
+#define CLKID_PWM_B_SEL			102
+#define CLKID_PWM_B_DIV			103
+#define CLKID_PWM_B			104
+#define CLKID_PWM_C_SEL			105
+#define CLKID_PWM_C_DIV			106
+#define CLKID_PWM_C			107
+#define CLKID_PWM_D_SEL			108
+#define CLKID_PWM_D_DIV			109
+#define CLKID_PWM_D			110
+#define CLKID_PWM_E_SEL			111
+#define CLKID_PWM_E_DIV			112
+#define CLKID_PWM_E			113
+#define CLKID_PWM_F_SEL			114
+#define CLKID_PWM_F_DIV			115
+#define CLKID_PWM_F			116
+#define CLKID_PWM_AO_A_SEL		117
+#define CLKID_PWM_AO_A_DIV		118
+#define CLKID_PWM_AO_A			119
+#define CLKID_PWM_AO_B_SEL		120
+#define CLKID_PWM_AO_B_DIV		121
+#define CLKID_PWM_AO_B			122
+#define CLKID_PWM_AO_C_SEL		123
+#define CLKID_PWM_AO_C_DIV		124
+#define CLKID_PWM_AO_C			125
+#define CLKID_PWM_AO_D_SEL		126
+#define CLKID_PWM_AO_D_DIV		127
+#define CLKID_PWM_AO_D			128
+#define CLKID_PWM_AO_E_SEL		129
+#define CLKID_PWM_AO_E_DIV		130
+#define CLKID_PWM_AO_E			131
+#define CLKID_PWM_AO_F_SEL		132
+#define CLKID_PWM_AO_F_DIV		133
+#define CLKID_PWM_AO_F			134
+#define CLKID_PWM_AO_G_SEL		135
+#define CLKID_PWM_AO_G_DIV		136
+#define CLKID_PWM_AO_G			137
+#define CLKID_PWM_AO_H_SEL		138
+#define CLKID_PWM_AO_H_DIV		139
+#define CLKID_PWM_AO_H			140
+#define CLKID_SYS_DDR			141
+#define CLKID_SYS_DOS			142
+#define CLKID_SYS_MIPI_DSI_A		143
+#define CLKID_SYS_MIPI_DSI_B		144
+#define CLKID_SYS_ETHPHY		145
+#define CLKID_SYS_MALI			146
+#define CLKID_SYS_AOCPU			147
+#define CLKID_SYS_AUCPU			148
+#define CLKID_SYS_CEC			149
+#define CLKID_SYS_GDC			150
+#define CLKID_SYS_DESWARP		151
+#define CLKID_SYS_AMPIPE_NAND		152
+#define CLKID_SYS_AMPIPE_ETH		153
+#define CLKID_SYS_AM2AXI0		154
+#define CLKID_SYS_AM2AXI1		155
+#define CLKID_SYS_AM2AXI2		156
+#define CLKID_SYS_SD_EMMC_A		157
+#define CLKID_SYS_SD_EMMC_B		158
+#define CLKID_SYS_SD_EMMC_C		159
+#define CLKID_SYS_SMARTCARD		160
+#define CLKID_SYS_ACODEC		161
+#define CLKID_SYS_SPIFC			162
+#define CLKID_SYS_MSR_CLK		163
+#define CLKID_SYS_IR_CTRL		164
+#define CLKID_SYS_AUDIO			165
+#define CLKID_SYS_ETH			166
+#define CLKID_SYS_UART_A		167
+#define CLKID_SYS_UART_B		168
+#define CLKID_SYS_UART_C		169
+#define CLKID_SYS_UART_D		170
+#define CLKID_SYS_UART_E		171
+#define CLKID_SYS_UART_F		172
+#define CLKID_SYS_AIFIFO		173
+#define CLKID_SYS_SPICC2		174
+#define CLKID_SYS_SPICC3		175
+#define CLKID_SYS_SPICC4		176
+#define CLKID_SYS_TS_A73		177
+#define CLKID_SYS_TS_A53		178
+#define CLKID_SYS_SPICC5		179
+#define CLKID_SYS_G2D			180
+#define CLKID_SYS_SPICC0		181
+#define CLKID_SYS_SPICC1		182
+#define CLKID_SYS_PCIE			183
+#define CLKID_SYS_USB			184
+#define CLKID_SYS_PCIE_PHY		185
+#define CLKID_SYS_I2C_AO_A		186
+#define CLKID_SYS_I2C_AO_B		187
+#define CLKID_SYS_I2C_M_A		188
+#define CLKID_SYS_I2C_M_B		189
+#define CLKID_SYS_I2C_M_C		190
+#define CLKID_SYS_I2C_M_D		191
+#define CLKID_SYS_I2C_M_E		192
+#define CLKID_SYS_I2C_M_F		193
+#define CLKID_SYS_HDMITX_APB		194
+#define CLKID_SYS_I2C_S_A		195
+#define CLKID_SYS_HDMIRX_PCLK		196
+#define CLKID_SYS_MMC_APB		197
+#define CLKID_SYS_MIPI_ISP_PCLK		198
+#define CLKID_SYS_RSA			199
+#define CLKID_SYS_PCLK_SYS_APB		200
+#define CLKID_SYS_A73PCLK_APB		201
+#define CLKID_SYS_DSPA			202
+#define CLKID_SYS_DSPB			203
+#define CLKID_SYS_VPU_INTR		204
+#define CLKID_SYS_SAR_ADC		205
+#define CLKID_SYS_GIC			206
+#define CLKID_SYS_TS_GPU		207
+#define CLKID_SYS_TS_NNA		208
+#define CLKID_SYS_TS_VPU		209
+#define CLKID_SYS_TS_HEVC		210
+#define CLKID_SYS_PWM_AB		211
+#define CLKID_SYS_PWM_CD		212
+#define CLKID_SYS_PWM_EF		213
+#define CLKID_SYS_PWM_AO_AB		214
+#define CLKID_SYS_PWM_AO_CD		215
+#define CLKID_SYS_PWM_AO_EF		216
+#define CLKID_SYS_PWM_AO_GH		217
+
+#endif /* __T7_PERIPHERALS_CLKC_H */
-- 
2.47.1



From jian.hu at amlogic.com  Wed Dec  3 21:36:33 2025
From: jian.hu at amlogic.com (Jian Hu)
Date: Thu, 4 Dec 2025 13:36:33 +0800
Subject: [PATCH v6 4/5] clk: meson: t7: add support for the T7 SoC PLL clock
In-Reply-To: <20251204053635.1234150-1-jian.hu@amlogic.com>
References: <20251204053635.1234150-1-jian.hu@amlogic.com>
Message-ID: <20251204053635.1234150-5-jian.hu@amlogic.com>

Add PLL clock controller driver for the Amlogic T7 SoC family.

Signed-off-by: Jian Hu <jian.hu at amlogic.com>
---
 drivers/clk/meson/Kconfig  |   14 +
 drivers/clk/meson/Makefile |    1 +
 drivers/clk/meson/t7-pll.c | 1074 ++++++++++++++++++++++++++++++++++++
 3 files changed, 1089 insertions(+)
 create mode 100644 drivers/clk/meson/t7-pll.c

diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index 71481607a6d5..c071de83f35b 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -201,4 +201,18 @@ config COMMON_CLK_S4_PERIPHERALS
 	help
 	  Support for the peripherals clock controller on Amlogic S805X2 and S905Y4
 	  devices, AKA S4. Say Y if you want S4 peripherals clock controller to work.
+
+config COMMON_CLK_T7_PLL
+	tristate "Amlogic T7 SoC PLL controller support"
+	depends on ARM64
+	default ARCH_MESON
+	select COMMON_CLK_MESON_REGMAP
+	select COMMON_CLK_MESON_CLKC_UTILS
+	select COMMON_CLK_MESON_PLL
+	imply COMMON_CLK_SCMI
+	help
+	  Support for the PLL clock controller on Amlogic A311D2 based
+	  device, AKA T7. PLLs are required by most peripheral to operate.
+	  Say Y if you want T7 PLL clock controller to work.
+
 endmenu
diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
index c6998e752c68..8e3f7f94c639 100644
--- a/drivers/clk/meson/Makefile
+++ b/drivers/clk/meson/Makefile
@@ -26,3 +26,4 @@ obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o
 obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o meson8-ddr.o
 obj-$(CONFIG_COMMON_CLK_S4_PLL) += s4-pll.o
 obj-$(CONFIG_COMMON_CLK_S4_PERIPHERALS) += s4-peripherals.o
+obj-$(CONFIG_COMMON_CLK_T7_PLL) += t7-pll.o
diff --git a/drivers/clk/meson/t7-pll.c b/drivers/clk/meson/t7-pll.c
new file mode 100644
index 000000000000..0a622f45fa36
--- /dev/null
+++ b/drivers/clk/meson/t7-pll.c
@@ -0,0 +1,1074 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
+/*
+ * Copyright (C) 2024-2025 Amlogic, Inc. All rights reserved.
+ * Author: Jian Hu <jian.hu at amlogic.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/platform_device.h>
+#include "clk-regmap.h"
+#include "clk-pll.h"
+#include "clk-mpll.h"
+#include "meson-clkc-utils.h"
+#include <dt-bindings/clock/amlogic,t7-pll-clkc.h>
+
+#define GP0PLL_CTRL0		0x00
+#define GP0PLL_CTRL1		0x04
+#define GP0PLL_CTRL2		0x08
+#define GP0PLL_CTRL3		0x0c
+#define GP0PLL_CTRL4		0x10
+#define GP0PLL_CTRL5		0x14
+#define GP0PLL_CTRL6		0x18
+#define GP0PLL_STS		0x1c
+
+#define GP1PLL_CTRL0		0x00
+#define GP1PLL_CTRL1		0x04
+#define GP1PLL_CTRL2		0x08
+#define GP1PLL_CTRL3		0x0c
+#define GP1PLL_STS		0x1c
+
+#define HIFIPLL_CTRL0		0x00
+#define HIFIPLL_CTRL1		0x04
+#define HIFIPLL_CTRL2		0x08
+#define HIFIPLL_CTRL3		0x0c
+#define HIFIPLL_CTRL4		0x10
+#define HIFIPLL_CTRL5		0x14
+#define HIFIPLL_CTRL6		0x18
+#define HIFIPLL_STS		0x1c
+
+#define PCIEPLL_CTRL0		0x00
+#define PCIEPLL_CTRL1		0x04
+#define PCIEPLL_CTRL2		0x08
+#define PCIEPLL_CTRL3		0x0c
+#define PCIEPLL_CTRL4		0x10
+#define PCIEPLL_CTRL5		0x14
+#define PCIEPLL_STS		0x18
+
+#define MPLL_CTRL0		0x00
+#define MPLL_CTRL1		0x04
+#define MPLL_CTRL2		0x08
+#define MPLL_CTRL3		0x0c
+#define MPLL_CTRL4		0x10
+#define MPLL_CTRL5		0x14
+#define MPLL_CTRL6		0x18
+#define MPLL_CTRL7		0x1c
+#define MPLL_CTRL8		0x20
+#define MPLL_STS		0x24
+
+#define HDMIPLL_CTRL0		0x00
+#define HDMIPLL_CTRL1		0x04
+#define HDMIPLL_CTRL2		0x08
+#define HDMIPLL_CTRL3		0x0c
+#define HDMIPLL_CTRL4		0x10
+#define HDMIPLL_CTRL5		0x14
+#define HDMIPLL_CTRL6		0x18
+#define HDMIPLL_STS		0x1c
+
+#define MCLK_PLL_CNTL0		0x00
+#define MCLK_PLL_CNTL1		0x04
+#define MCLK_PLL_CNTL2		0x08
+#define MCLK_PLL_CNTL3		0x0c
+#define MCLK_PLL_CNTL4		0x10
+#define MCLK_PLL_STS		0x14
+
+static const struct pll_mult_range t7_media_pll_mult_range = {
+	.min = 125,
+	.max = 250,
+};
+
+static const struct reg_sequence t7_gp0_init_regs[] = {
+	{ .reg = GP0PLL_CTRL1,  .def = 0x00000000 },
+	{ .reg = GP0PLL_CTRL2,  .def = 0x00000000 },
+	{ .reg = GP0PLL_CTRL3,  .def = 0x48681c00 },
+	{ .reg = GP0PLL_CTRL4,  .def = 0x88770290 },
+	{ .reg = GP0PLL_CTRL5,  .def = 0x3927200a },
+	{ .reg = GP0PLL_CTRL6,  .def = 0x56540000 },
+};
+
+static struct clk_regmap t7_gp0_pll_dco = {
+	.data = &(struct meson_clk_pll_data){
+		.en = {
+			.reg_off = GP0PLL_CTRL0,
+			.shift   = 28,
+			.width   = 1,
+		},
+		.m = {
+			.reg_off = GP0PLL_CTRL0,
+			.shift   = 0,
+			.width   = 8,
+		},
+		.n = {
+			.reg_off = GP0PLL_CTRL0,
+			.shift   = 10,
+			.width   = 5,
+		},
+		.l = {
+			.reg_off = GP0PLL_STS,
+			.shift   = 31,
+			.width   = 1,
+		},
+		.rst = {
+			.reg_off = GP0PLL_CTRL0,
+			.shift   = 29,
+			.width   = 1,
+		},
+		.range = &t7_media_pll_mult_range,
+		.init_regs = t7_gp0_init_regs,
+		.init_count = ARRAY_SIZE(t7_gp0_init_regs),
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "gp0_pll_dco",
+		.ops = &meson_clk_pll_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "in0",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_gp0_pll = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = GP0PLL_CTRL0,
+		.shift = 16,
+		.width = 3,
+		.flags = CLK_DIVIDER_POWER_OF_TWO,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "gp0_pll",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_gp0_pll_dco.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+/*
+ * Compared with GP0 PLL, GP1 PLL is a newly designed PLL with
+ * a DCO range of 1.6GHz to 3.2GHz.
+ */
+static const struct pll_mult_range t7_gp1_pll_mult_range = {
+	.min = 67,
+	.max = 133,
+};
+
+static const struct reg_sequence t7_gp1_init_regs[] = {
+	{ .reg = GP1PLL_CTRL1,  .def = 0x1420500f },
+	{ .reg = GP1PLL_CTRL2,  .def = 0x00023001 },
+	{ .reg = GP1PLL_CTRL3,  .def = 0x00000000 },
+};
+
+static struct clk_regmap t7_gp1_pll_dco = {
+	.data = &(struct meson_clk_pll_data){
+		.en = {
+			.reg_off = GP1PLL_CTRL0,
+			.shift   = 28,
+			.width   = 1,
+		},
+		.m = {
+			.reg_off = GP1PLL_CTRL0,
+			.shift   = 0,
+			.width   = 8,
+		},
+		.n = {
+			.reg_off = GP1PLL_CTRL0,
+			.shift   = 16,
+			.width   = 5,
+		},
+		.l = {
+			.reg_off = GP1PLL_STS,
+			.shift   = 31,
+			.width   = 1,
+		},
+		.rst = {
+			.reg_off = GP1PLL_CTRL0,
+			.shift   = 29,
+			.width   = 1,
+		},
+		.range = &t7_gp1_pll_mult_range,
+		.init_regs = t7_gp1_init_regs,
+		.init_count = ARRAY_SIZE(t7_gp1_init_regs),
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "gp1_pll_dco",
+		.ops = &meson_clk_pll_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "in0",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_gp1_pll = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = GP1PLL_CTRL0,
+		.shift = 12,
+		.width = 3,
+		.flags = CLK_DIVIDER_POWER_OF_TWO,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "gp1_pll",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_gp1_pll_dco.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static const struct reg_sequence t7_hifi_init_regs[] = {
+	{ .reg = HIFIPLL_CTRL1, .def = 0x00000000 },
+	{ .reg = HIFIPLL_CTRL2, .def = 0x00000000 },
+	{ .reg = HIFIPLL_CTRL3, .def = 0x6a285c00 },
+	{ .reg = HIFIPLL_CTRL4, .def = 0x65771290 },
+	{ .reg = HIFIPLL_CTRL5, .def = 0x3927200a },
+	{ .reg = HIFIPLL_CTRL6, .def = 0x56540000 }
+};
+
+static struct clk_regmap t7_hifi_pll_dco = {
+	.data = &(struct meson_clk_pll_data){
+		.en = {
+			.reg_off = HIFIPLL_CTRL0,
+			.shift   = 28,
+			.width   = 1,
+		},
+		.m = {
+			.reg_off = HIFIPLL_CTRL0,
+			.shift   = 0,
+			.width   = 8,
+		},
+		.n = {
+			.reg_off = HIFIPLL_CTRL0,
+			.shift   = 10,
+			.width   = 5,
+		},
+		.frac = {
+			.reg_off = HIFIPLL_CTRL1,
+			.shift   = 0,
+			.width   = 17,
+		},
+		.l = {
+			.reg_off = HIFIPLL_STS,
+			.shift   = 31,
+			.width   = 1,
+		},
+		.rst = {
+			.reg_off = HIFIPLL_CTRL0,
+			.shift   = 29,
+			.width   = 1,
+		},
+		.range = &t7_media_pll_mult_range,
+		.init_regs = t7_hifi_init_regs,
+		.init_count = ARRAY_SIZE(t7_hifi_init_regs),
+		.frac_max = 100000,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "hifi_pll_dco",
+		.ops = &meson_clk_pll_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "in0",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_hifi_pll = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = HIFIPLL_CTRL0,
+		.shift = 16,
+		.width = 2,
+		.flags = CLK_DIVIDER_POWER_OF_TWO,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "hifi_pll",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_hifi_pll_dco.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+/*
+ * The T7 PCIE PLL is fined tuned to deliver a very precise
+ * 100MHz reference clock for the PCIe Analog PHY, and thus requires
+ * a strict register sequence to enable the PLL.
+ */
+static const struct reg_sequence t7_pcie_pll_init_regs[] = {
+	{ .reg = PCIEPLL_CTRL0,	.def = 0x200c04c8 },
+	{ .reg = PCIEPLL_CTRL0,	.def = 0x300c04c8 },
+	{ .reg = PCIEPLL_CTRL1,	.def = 0x30000000 },
+	{ .reg = PCIEPLL_CTRL2,	.def = 0x00001100 },
+	{ .reg = PCIEPLL_CTRL3,	.def = 0x10058e00 },
+	{ .reg = PCIEPLL_CTRL4,	.def = 0x000100c0 },
+	{ .reg = PCIEPLL_CTRL5,	.def = 0x68000048 },
+	{ .reg = PCIEPLL_CTRL5,	.def = 0x68000068, .delay_us = 20 },
+	{ .reg = PCIEPLL_CTRL4,	.def = 0x008100c0, .delay_us = 20 },
+	{ .reg = PCIEPLL_CTRL0,	.def = 0x340c04c8 },
+	{ .reg = PCIEPLL_CTRL0,	.def = 0x140c04c8, .delay_us = 20 },
+	{ .reg = PCIEPLL_CTRL2,	.def = 0x00001000 }
+};
+
+static struct clk_regmap t7_pcie_pll_dco = {
+	.data = &(struct meson_clk_pll_data){
+		.en = {
+			.reg_off = PCIEPLL_CTRL0,
+			.shift   = 28,
+			.width   = 1,
+		},
+		.m = {
+			.reg_off = PCIEPLL_CTRL0,
+			.shift   = 0,
+			.width   = 8,
+		},
+		.n = {
+			.reg_off = PCIEPLL_CTRL0,
+			.shift   = 10,
+			.width   = 5,
+		},
+		.l = {
+			.reg_off = PCIEPLL_CTRL0,
+			.shift   = 31,
+			.width   = 1,
+		},
+		.rst = {
+			.reg_off = PCIEPLL_CTRL0,
+			.shift   = 29,
+			.width   = 1,
+		},
+		.init_regs = t7_pcie_pll_init_regs,
+		.init_count = ARRAY_SIZE(t7_pcie_pll_init_regs),
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "pcie_pll_dco",
+		.ops = &meson_clk_pcie_pll_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "in0",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_fixed_factor t7_pcie_pll_dco_div2 = {
+	.mult = 1,
+	.div = 2,
+	.hw.init = &(struct clk_init_data){
+		.name = "pcie_pll_dco_div2",
+		.ops = &clk_fixed_factor_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_pcie_pll_dco.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_pcie_pll_od = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = PCIEPLL_CTRL0,
+		.shift = 16,
+		.width = 5,
+		/* the divisor is 32 when [16:21] = 0 */
+		.flags = CLK_DIVIDER_MAX_AT_ZERO,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "pcie_pll_od",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_pcie_pll_dco_div2.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_fixed_factor t7_pcie_pll = {
+	.mult = 1,
+	.div = 2,
+	.hw.init = &(struct clk_init_data){
+		.name = "pcie_pll",
+		.ops = &clk_fixed_factor_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_pcie_pll_od.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_fixed_factor t7_mpll_prediv = {
+	.mult = 1,
+	.div = 2,
+	.hw.init = &(struct clk_init_data){
+		.name = "mpll_prediv",
+		.ops = &clk_fixed_factor_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "in0",
+		},
+		.num_parents = 1,
+	},
+};
+
+static const struct reg_sequence t7_mpll0_init_regs[] = {
+	{ .reg = MPLL_CTRL2, .def = 0x40000033 }
+};
+
+static struct clk_regmap t7_mpll0_div = {
+	.data = &(struct meson_clk_mpll_data){
+		.sdm = {
+			.reg_off = MPLL_CTRL1,
+			.shift   = 0,
+			.width   = 14,
+		},
+		.sdm_en = {
+			.reg_off = MPLL_CTRL1,
+			.shift   = 30,
+			.width	 = 1,
+		},
+		.n2 = {
+			.reg_off = MPLL_CTRL1,
+			.shift   = 20,
+			.width   = 9,
+		},
+		.ssen = {
+			.reg_off = MPLL_CTRL1,
+			.shift   = 29,
+			.width	 = 1,
+		},
+		.init_regs = t7_mpll0_init_regs,
+		.init_count = ARRAY_SIZE(t7_mpll0_init_regs),
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mpll0_div",
+		.ops = &meson_clk_mpll_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_mpll_prediv.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_mpll0 = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = MPLL_CTRL1,
+		.bit_idx = 31,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mpll0",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) { &t7_mpll0_div.hw },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static const struct reg_sequence t7_mpll1_init_regs[] = {
+	{ .reg = MPLL_CTRL4,	.def = 0x40000033 }
+};
+
+static struct clk_regmap t7_mpll1_div = {
+	.data = &(struct meson_clk_mpll_data){
+		.sdm = {
+			.reg_off = MPLL_CTRL3,
+			.shift   = 0,
+			.width   = 14,
+		},
+		.sdm_en = {
+			.reg_off = MPLL_CTRL3,
+			.shift   = 30,
+			.width	 = 1,
+		},
+		.n2 = {
+			.reg_off = MPLL_CTRL3,
+			.shift   = 20,
+			.width   = 9,
+		},
+		.ssen = {
+			.reg_off = MPLL_CTRL3,
+			.shift   = 29,
+			.width	 = 1,
+		},
+		.init_regs = t7_mpll1_init_regs,
+		.init_count = ARRAY_SIZE(t7_mpll1_init_regs),
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mpll1_div",
+		.ops = &meson_clk_mpll_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_mpll_prediv.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_mpll1 = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = MPLL_CTRL3,
+		.bit_idx = 31,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mpll1",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) { &t7_mpll1_div.hw },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static const struct reg_sequence t7_mpll2_init_regs[] = {
+	{ .reg = MPLL_CTRL6, .def = 0x40000033 }
+};
+
+static struct clk_regmap t7_mpll2_div = {
+	.data = &(struct meson_clk_mpll_data){
+		.sdm = {
+			.reg_off = MPLL_CTRL5,
+			.shift   = 0,
+			.width   = 14,
+		},
+		.sdm_en = {
+			.reg_off = MPLL_CTRL5,
+			.shift   = 30,
+			.width	 = 1,
+		},
+		.n2 = {
+			.reg_off = MPLL_CTRL5,
+			.shift   = 20,
+			.width   = 9,
+		},
+		.ssen = {
+			.reg_off = MPLL_CTRL5,
+			.shift   = 29,
+			.width	 = 1,
+		},
+		.init_regs = t7_mpll2_init_regs,
+		.init_count = ARRAY_SIZE(t7_mpll2_init_regs),
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mpll2_div",
+		.ops = &meson_clk_mpll_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_mpll_prediv.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_mpll2 = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = MPLL_CTRL5,
+		.bit_idx = 31,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mpll2",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) { &t7_mpll2_div.hw },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static const struct reg_sequence t7_mpll3_init_regs[] = {
+	{ .reg = MPLL_CTRL8, .def = 0x40000033 }
+};
+
+static struct clk_regmap t7_mpll3_div = {
+	.data = &(struct meson_clk_mpll_data){
+		.sdm = {
+			.reg_off = MPLL_CTRL7,
+			.shift   = 0,
+			.width   = 14,
+		},
+		.sdm_en = {
+			.reg_off = MPLL_CTRL7,
+			.shift   = 30,
+			.width	 = 1,
+		},
+		.n2 = {
+			.reg_off = MPLL_CTRL7,
+			.shift   = 20,
+			.width   = 9,
+		},
+		.ssen = {
+			.reg_off = MPLL_CTRL7,
+			.shift   = 29,
+			.width	 = 1,
+		},
+		.init_regs = t7_mpll3_init_regs,
+		.init_count = ARRAY_SIZE(t7_mpll3_init_regs),
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mpll3_div",
+		.ops = &meson_clk_mpll_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_mpll_prediv.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_mpll3 = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = MPLL_CTRL7,
+		.bit_idx = 31,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mpll3",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) { &t7_mpll3_div.hw },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static const struct reg_sequence t7_hdmi_init_regs[] = {
+	{ .reg = HDMIPLL_CTRL1, .def = 0x00000000 },
+	{ .reg = HDMIPLL_CTRL2, .def = 0x00000000 },
+	{ .reg = HDMIPLL_CTRL3, .def = 0x6a28dc00 },
+	{ .reg = HDMIPLL_CTRL4, .def = 0x65771290 },
+	{ .reg = HDMIPLL_CTRL5, .def = 0x39272000 },
+	{ .reg = HDMIPLL_CTRL6, .def = 0x56540000 }
+};
+
+static struct clk_regmap t7_hdmi_pll_dco = {
+	.data = &(struct meson_clk_pll_data){
+		.en = {
+			.reg_off = HDMIPLL_CTRL0,
+			.shift   = 28,
+			.width   = 1,
+		},
+		.m = {
+			.reg_off = HDMIPLL_CTRL0,
+			.shift   = 0,
+			.width   = 9,
+		},
+		.n = {
+			.reg_off = HDMIPLL_CTRL0,
+			.shift   = 10,
+			.width   = 5,
+		},
+		.l = {
+			.reg_off = HDMIPLL_CTRL0,
+			.shift   = 31,
+			.width   = 1,
+		},
+		.rst = {
+			.reg_off = HDMIPLL_CTRL0,
+			.shift   = 29,
+			.width   = 1,
+		},
+		.range = &t7_media_pll_mult_range,
+		.init_regs = t7_hdmi_init_regs,
+		.init_count = ARRAY_SIZE(t7_hdmi_init_regs),
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "hdmi_pll_dco",
+		.ops = &meson_clk_pll_ops,
+		.parent_data = (const struct clk_parent_data []) {
+			{ .fw_name = "in0", }
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_hdmi_pll_od = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = HDMIPLL_CTRL0,
+		.shift = 16,
+		.width = 4,
+		.flags = CLK_DIVIDER_POWER_OF_TWO,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "hdmi_pll_od",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_hdmi_pll_dco.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_hdmi_pll = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = HDMIPLL_CTRL0,
+		.shift = 20,
+		.width = 2,
+		.flags = CLK_DIVIDER_POWER_OF_TWO,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "hdmi_pll",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_hdmi_pll_od.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static const struct pll_mult_range t7_mclk_pll_mult_range = {
+	.min = 67,
+	.max = 133,
+};
+
+static const struct reg_sequence t7_mclk_init_regs[] = {
+	{ .reg = MCLK_PLL_CNTL1, .def = 0x1470500f },
+	{ .reg = MCLK_PLL_CNTL2, .def = 0x00023001 },
+	{ .reg = MCLK_PLL_CNTL3, .def = 0x18180000 },
+	{ .reg = MCLK_PLL_CNTL4, .def = 0x00180303 },
+};
+
+static struct clk_regmap t7_mclk_pll_dco = {
+	.data = &(struct meson_clk_pll_data){
+		.en = {
+			.reg_off = MCLK_PLL_CNTL0,
+			.shift   = 28,
+			.width   = 1,
+		},
+		.m = {
+			.reg_off = MCLK_PLL_CNTL0,
+			.shift   = 0,
+			.width   = 8,
+		},
+		.n = {
+			.reg_off = MCLK_PLL_CNTL0,
+			.shift   = 16,
+			.width   = 5,
+		},
+		.l = {
+			.reg_off = MCLK_PLL_CNTL0,
+			.shift   = 31,
+			.width   = 1,
+		},
+		.rst = {
+			.reg_off = MCLK_PLL_CNTL0,
+			.shift   = 29,
+			.width   = 1,
+		},
+		.l_detect = {
+			.reg_off = MCLK_PLL_CNTL2,
+			.shift   = 6,
+			.width   = 1,
+		},
+		.range = &t7_mclk_pll_mult_range,
+		.init_regs = t7_mclk_init_regs,
+		.init_count = ARRAY_SIZE(t7_mclk_init_regs),
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mclk_pll_dco",
+		.ops = &meson_clk_pll_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "in0",
+		},
+		.num_parents = 1,
+	},
+};
+
+/* max div is 16 */
+static const struct clk_div_table t7_mclk_div[] = {
+	{ .val = 0, .div = 1 },
+	{ .val = 1, .div = 2 },
+	{ .val = 2, .div = 4 },
+	{ .val = 3, .div = 8 },
+	{ .val = 4, .div = 16 },
+	{ /* sentinel */ }
+};
+
+static struct clk_regmap t7_mclk_pre_od = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = MCLK_PLL_CNTL0,
+		.shift = 12,
+		.width = 3,
+		.table = t7_mclk_div,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mclk_pre_od",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_mclk_pll_dco.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_mclk_pll = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = MCLK_PLL_CNTL4,
+		.shift = 16,
+		.width = 5,
+		.flags = CLK_DIVIDER_ONE_BASED,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mclk_pll",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_mclk_pre_od.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_mclk_0_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = MCLK_PLL_CNTL4,
+		.mask = 0x3,
+		.shift = 4,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mclk_0_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = (const struct clk_parent_data []) {
+			{ .hw = &t7_mclk_pll.hw },
+			{ .fw_name = "in1", },
+			{ .fw_name = "in2", },
+		},
+		.num_parents = 3,
+	},
+};
+
+static struct clk_fixed_factor t7_mclk_0_div2 = {
+	.mult = 1,
+	.div = 2,
+	.hw.init = &(struct clk_init_data){
+		.name = "mclk_0_div2",
+		.ops = &clk_fixed_factor_ops,
+		.parent_hws = (const struct clk_hw *[]) { &t7_mclk_0_sel.hw },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_mclk_0_pre = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = MCLK_PLL_CNTL4,
+		.bit_idx = 2,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "mclk_0_pre",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_mclk_0_div2.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_mclk_0 = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = MCLK_PLL_CNTL4,
+		.bit_idx = 0,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "mclk_0",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_mclk_0_pre.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_mclk_1_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = MCLK_PLL_CNTL4,
+		.mask = 0x3,
+		.shift = 12,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mclk_1_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = (const struct clk_parent_data []) {
+			{ .hw = &t7_mclk_pll.hw },
+			{ .fw_name = "in1", },
+			{ .fw_name = "in2", },
+		},
+		.num_parents = 3,
+	},
+};
+
+static struct clk_fixed_factor t7_mclk_1_div2 = {
+	.mult = 1,
+	.div = 2,
+	.hw.init = &(struct clk_init_data){
+		.name = "mclk_1_div2",
+		.ops = &clk_fixed_factor_ops,
+		.parent_hws = (const struct clk_hw *[]) { &t7_mclk_1_sel.hw },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_mclk_1_pre = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = MCLK_PLL_CNTL4,
+		.bit_idx = 10,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "mclk_1_pre",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_mclk_1_div2.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_mclk_1 = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = MCLK_PLL_CNTL4,
+		.bit_idx = 8,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "mclk_1",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_mclk_1_pre.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_hw *t7_gp0_hw_clks[] = {
+	[CLKID_GP0_PLL_DCO]		= &t7_gp0_pll_dco.hw,
+	[CLKID_GP0_PLL]			= &t7_gp0_pll.hw,
+};
+
+static struct clk_hw *t7_gp1_hw_clks[] = {
+	[CLKID_GP1_PLL_DCO]		= &t7_gp1_pll_dco.hw,
+	[CLKID_GP1_PLL]			= &t7_gp1_pll.hw,
+};
+
+static struct clk_hw *t7_hifi_hw_clks[] = {
+	[CLKID_HIFI_PLL_DCO]		= &t7_hifi_pll_dco.hw,
+	[CLKID_HIFI_PLL]		= &t7_hifi_pll.hw,
+};
+
+static struct clk_hw *t7_pcie_hw_clks[] = {
+	[CLKID_PCIE_PLL_DCO]		= &t7_pcie_pll_dco.hw,
+	[CLKID_PCIE_PLL_DCO_DIV2]	= &t7_pcie_pll_dco_div2.hw,
+	[CLKID_PCIE_PLL_OD]		= &t7_pcie_pll_od.hw,
+	[CLKID_PCIE_PLL]		= &t7_pcie_pll.hw,
+};
+
+static struct clk_hw *t7_mpll_hw_clks[] = {
+	[CLKID_MPLL_PREDIV]		= &t7_mpll_prediv.hw,
+	[CLKID_MPLL0_DIV]		= &t7_mpll0_div.hw,
+	[CLKID_MPLL0]			= &t7_mpll0.hw,
+	[CLKID_MPLL1_DIV]		= &t7_mpll1_div.hw,
+	[CLKID_MPLL1]			= &t7_mpll1.hw,
+	[CLKID_MPLL2_DIV]		= &t7_mpll2_div.hw,
+	[CLKID_MPLL2]			= &t7_mpll2.hw,
+	[CLKID_MPLL3_DIV]		= &t7_mpll3_div.hw,
+	[CLKID_MPLL3]			= &t7_mpll3.hw,
+};
+
+static struct clk_hw *t7_hdmi_hw_clks[] = {
+	[CLKID_HDMI_PLL_DCO]		= &t7_hdmi_pll_dco.hw,
+	[CLKID_HDMI_PLL_OD]		= &t7_hdmi_pll_od.hw,
+	[CLKID_HDMI_PLL]		= &t7_hdmi_pll.hw,
+};
+
+static struct clk_hw *t7_mclk_hw_clks[] = {
+	[CLKID_MCLK_PLL_DCO]		= &t7_mclk_pll_dco.hw,
+	[CLKID_MCLK_PRE]		= &t7_mclk_pre_od.hw,
+	[CLKID_MCLK_PLL]		= &t7_mclk_pll.hw,
+	[CLKID_MCLK_0_SEL]		= &t7_mclk_0_sel.hw,
+	[CLKID_MCLK_0_DIV2]		= &t7_mclk_0_div2.hw,
+	[CLKID_MCLK_0_PRE]		= &t7_mclk_0_pre.hw,
+	[CLKID_MCLK_0]			= &t7_mclk_0.hw,
+	[CLKID_MCLK_1_SEL]		= &t7_mclk_1_sel.hw,
+	[CLKID_MCLK_1_DIV2]		= &t7_mclk_1_div2.hw,
+	[CLKID_MCLK_1_PRE]		= &t7_mclk_1_pre.hw,
+	[CLKID_MCLK_1]			= &t7_mclk_1.hw,
+};
+
+static const struct meson_clkc_data t7_gp0_data = {
+	.hw_clks = {
+		.hws = t7_gp0_hw_clks,
+		.num = ARRAY_SIZE(t7_gp0_hw_clks),
+	},
+};
+
+static const struct meson_clkc_data t7_gp1_data = {
+	.hw_clks = {
+		.hws = t7_gp1_hw_clks,
+		.num = ARRAY_SIZE(t7_gp1_hw_clks),
+	},
+};
+
+static const struct meson_clkc_data t7_hifi_data = {
+	.hw_clks = {
+		.hws = t7_hifi_hw_clks,
+		.num = ARRAY_SIZE(t7_hifi_hw_clks),
+	},
+};
+
+static const struct meson_clkc_data t7_pcie_data = {
+	.hw_clks = {
+		.hws = t7_pcie_hw_clks,
+		.num = ARRAY_SIZE(t7_pcie_hw_clks),
+	},
+};
+
+static const struct reg_sequence t7_mpll_init_regs[] = {
+	{ .reg = MPLL_CTRL0, .def = 0x00000543 }
+};
+
+static const struct meson_clkc_data t7_mpll_data = {
+	.hw_clks = {
+		.hws = t7_mpll_hw_clks,
+		.num = ARRAY_SIZE(t7_mpll_hw_clks),
+	},
+	.init_regs = t7_mpll_init_regs,
+	.init_count = ARRAY_SIZE(t7_mpll_init_regs),
+};
+
+static const struct meson_clkc_data t7_hdmi_data = {
+	.hw_clks = {
+		.hws = t7_hdmi_hw_clks,
+		.num = ARRAY_SIZE(t7_hdmi_hw_clks),
+	},
+};
+
+static const struct meson_clkc_data t7_mclk_data = {
+	.hw_clks = {
+		.hws = t7_mclk_hw_clks,
+		.num = ARRAY_SIZE(t7_mclk_hw_clks),
+	},
+};
+
+static const struct of_device_id t7_pll_clkc_match_table[] = {
+	{ .compatible = "amlogic,t7-gp0-pll",	.data = &t7_gp0_data, },
+	{ .compatible = "amlogic,t7-gp1-pll",	.data = &t7_gp1_data, },
+	{ .compatible = "amlogic,t7-hifi-pll",	.data = &t7_hifi_data, },
+	{ .compatible = "amlogic,t7-pcie-pll",	.data = &t7_pcie_data, },
+	{ .compatible = "amlogic,t7-mpll",	.data = &t7_mpll_data, },
+	{ .compatible = "amlogic,t7-hdmi-pll",	.data = &t7_hdmi_data, },
+	{ .compatible = "amlogic,t7-mclk-pll",	.data = &t7_mclk_data, },
+	{}
+};
+MODULE_DEVICE_TABLE(of, t7_pll_clkc_match_table);
+
+static struct platform_driver t7_pll_clkc_driver = {
+	.probe = meson_clkc_mmio_probe,
+	.driver = {
+		.name = "t7-pll-clkc",
+		.of_match_table = t7_pll_clkc_match_table,
+	},
+};
+module_platform_driver(t7_pll_clkc_driver);
+
+MODULE_DESCRIPTION("Amlogic T7 PLL Clock Controller driver");
+MODULE_AUTHOR("Jian Hu <jian.hu at amlogic.com>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("CLK_MESON");
-- 
2.47.1



From jian.hu at amlogic.com  Wed Dec  3 21:36:34 2025
From: jian.hu at amlogic.com (Jian Hu)
Date: Thu, 4 Dec 2025 13:36:34 +0800
Subject: [PATCH v6 5/5] clk: meson: t7: add t7 clock peripherals controller driver
In-Reply-To: <20251204053635.1234150-1-jian.hu@amlogic.com>
References: <20251204053635.1234150-1-jian.hu@amlogic.com>
Message-ID: <20251204053635.1234150-6-jian.hu@amlogic.com>

Add Peripheral clock controller driver for the Amlogic T7 SoC family.

Signed-off-by: Jian Hu <jian.hu at amlogic.com>
---
 drivers/clk/meson/Kconfig          |   13 +
 drivers/clk/meson/Makefile         |    1 +
 drivers/clk/meson/t7-peripherals.c | 1271 ++++++++++++++++++++++++++++
 3 files changed, 1285 insertions(+)
 create mode 100644 drivers/clk/meson/t7-peripherals.c

diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index c071de83f35b..ad35b171485c 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -215,4 +215,17 @@ config COMMON_CLK_T7_PLL
 	  device, AKA T7. PLLs are required by most peripheral to operate.
 	  Say Y if you want T7 PLL clock controller to work.
 
+config COMMON_CLK_T7_PERIPHERALS
+	tristate "Amlogic T7 SoC peripherals clock controller support"
+	depends on ARM64
+	default ARCH_MESON
+	select COMMON_CLK_MESON_REGMAP
+	select COMMON_CLK_MESON_CLKC_UTILS
+	select COMMON_CLK_MESON_DUALDIV
+	imply COMMON_CLK_SCMI
+	imply COMMON_CLK_T7_PLL
+	help
+	  Support for the peripherals clock controller on Amlogic A311D2 based
+	  device, AKA T7. Peripherals are required by most peripheral to operate.
+	  Say Y if you want T7 peripherals clock controller to work.
 endmenu
diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
index 8e3f7f94c639..c6719694a242 100644
--- a/drivers/clk/meson/Makefile
+++ b/drivers/clk/meson/Makefile
@@ -27,3 +27,4 @@ obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o meson8-ddr.o
 obj-$(CONFIG_COMMON_CLK_S4_PLL) += s4-pll.o
 obj-$(CONFIG_COMMON_CLK_S4_PERIPHERALS) += s4-peripherals.o
 obj-$(CONFIG_COMMON_CLK_T7_PLL) += t7-pll.o
+obj-$(CONFIG_COMMON_CLK_T7_PERIPHERALS) += t7-peripherals.o
diff --git a/drivers/clk/meson/t7-peripherals.c b/drivers/clk/meson/t7-peripherals.c
new file mode 100644
index 000000000000..214db7850d86
--- /dev/null
+++ b/drivers/clk/meson/t7-peripherals.c
@@ -0,0 +1,1271 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
+/*
+ * Copyright (C) 2024-2025 Amlogic, Inc. All rights reserved.
+ * Author: Jian Hu <jian.hu at amlogic.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/platform_device.h>
+#include "clk-dualdiv.h"
+#include "clk-regmap.h"
+#include "meson-clkc-utils.h"
+#include <dt-bindings/clock/amlogic,t7-peripherals-clkc.h>
+
+#define RTC_BY_OSCIN_CTRL0	0x8
+#define RTC_BY_OSCIN_CTRL1	0xc
+#define RTC_CTRL		0x10
+#define SYS_CLK_CTRL0		0x40
+#define SYS_CLK_EN0_REG0	0x44
+#define SYS_CLK_EN0_REG1	0x48
+#define SYS_CLK_EN0_REG2	0x4c
+#define SYS_CLK_EN0_REG3	0x50
+#define CECA_CTRL0		0x88
+#define CECA_CTRL1		0x8c
+#define CECB_CTRL0		0x90
+#define CECB_CTRL1		0x94
+#define SC_CLK_CTRL		0x98
+#define DSPA_CLK_CTRL0		0x9c
+#define DSPB_CLK_CTRL0		0xa0
+#define CLK12_24_CTRL		0xa8
+#define ANAKIN_CLK_CTRL		0xac
+#define MIPI_CSI_PHY_CLK_CTRL	0x10c
+#define MIPI_ISP_CLK_CTRL	0x110
+#define TS_CLK_CTRL		0x158
+#define MALI_CLK_CTRL		0x15c
+#define ETH_CLK_CTRL		0x164
+#define NAND_CLK_CTRL		0x168
+#define SD_EMMC_CLK_CTRL	0x16c
+#define SPICC_CLK_CTRL		0x174
+#define SAR_CLK_CTRL0		0x17c
+#define PWM_CLK_AB_CTRL		0x180
+#define PWM_CLK_CD_CTRL		0x184
+#define PWM_CLK_EF_CTRL		0x188
+#define PWM_CLK_AO_AB_CTRL	0x1a0
+#define PWM_CLK_AO_CD_CTRL	0x1a4
+#define PWM_CLK_AO_EF_CTRL	0x1a8
+#define PWM_CLK_AO_GH_CTRL	0x1ac
+#define SPICC_CLK_CTRL1		0x1c0
+#define SPICC_CLK_CTRL2		0x1c4
+
+#define T7_COMP_SEL(_name, _reg, _shift, _mask, _pdata) \
+	MESON_COMP_SEL(t7_, _name, _reg, _shift, _mask, _pdata, NULL, 0, 0)
+
+#define T7_COMP_DIV(_name, _reg, _shift, _width) \
+	MESON_COMP_DIV(t7_, _name, _reg, _shift, _width, 0, CLK_SET_RATE_PARENT)
+
+#define T7_COMP_GATE(_name, _reg, _bit, _iflags) \
+	MESON_COMP_GATE(t7_, _name, _reg, _bit, CLK_SET_RATE_PARENT | (_iflags))
+
+static struct clk_regmap t7_rtc_dualdiv_in = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = RTC_BY_OSCIN_CTRL0,
+		.bit_idx = 31,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "rtc_duandiv_in",
+		.ops = &clk_regmap_gate_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "xtal",
+		},
+		.num_parents = 1,
+	},
+};
+
+static const struct meson_clk_dualdiv_param t7_dualdiv_table[] = {
+	{
+		.n1	= 733, .m1	= 8,
+		.n2	= 732, .m2	= 11,
+		.dual	= 1,
+	},
+	{}
+};
+
+static struct clk_regmap t7_rtc_dualdiv_div = {
+	.data = &(struct meson_clk_dualdiv_data){
+		.n1 = {
+			.reg_off = RTC_BY_OSCIN_CTRL0,
+			.shift   = 0,
+			.width   = 12,
+		},
+		.n2 = {
+			.reg_off = RTC_BY_OSCIN_CTRL0,
+			.shift   = 12,
+			.width   = 12,
+		},
+		.m1 = {
+			.reg_off = RTC_BY_OSCIN_CTRL1,
+			.shift   = 0,
+			.width   = 12,
+		},
+		.m2 = {
+			.reg_off = RTC_BY_OSCIN_CTRL1,
+			.shift   = 12,
+			.width   = 12,
+		},
+		.dual = {
+			.reg_off = RTC_BY_OSCIN_CTRL0,
+			.shift   = 28,
+			.width   = 1,
+		},
+		.table = t7_dualdiv_table,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "rtc_dualdiv_div",
+		.ops = &meson_clk_dualdiv_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_rtc_dualdiv_in.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_rtc_dualdiv_sel = {
+	.data = &(struct clk_regmap_mux_data) {
+		.offset = RTC_BY_OSCIN_CTRL1,
+		.mask = 0x1,
+		.shift = 24,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "rtc_dualdiv_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_rtc_dualdiv_div.hw,
+			&t7_rtc_dualdiv_in.hw,
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_rtc_dualdiv = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = RTC_BY_OSCIN_CTRL0,
+		.bit_idx = 30,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "rtc_dualdiv",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_rtc_dualdiv_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_rtc = {
+	.data = &(struct clk_regmap_mux_data) {
+		.offset = RTC_CTRL,
+		.mask = 0x3,
+		.shift = 0,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "rtc",
+		.ops = &clk_regmap_mux_ops,
+		/*
+		 * xtal is also on parent input #3 but that it is not useful to CCF since
+		 * the same parent is available with parent input #0
+		 */
+		.parent_data = (const struct clk_parent_data []) {
+			{ .fw_name = "xtal", },
+			{ .hw = &t7_rtc_dualdiv.hw },
+			{ .fw_name = "ext_rtc", },
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_NO_REPARENT,
+	},
+};
+
+static struct clk_regmap t7_ceca_dualdiv_in = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = CECA_CTRL0,
+		.bit_idx = 31,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "ceca_dualdiv_in",
+		.ops = &clk_regmap_gate_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "xtal",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_ceca_dualdiv_div = {
+	.data = &(struct meson_clk_dualdiv_data){
+		.n1 = {
+			.reg_off = CECA_CTRL0,
+			.shift   = 0,
+			.width   = 12,
+		},
+		.n2 = {
+			.reg_off = CECA_CTRL0,
+			.shift   = 12,
+			.width   = 12,
+		},
+		.m1 = {
+			.reg_off = CECA_CTRL1,
+			.shift   = 0,
+			.width   = 12,
+		},
+		.m2 = {
+			.reg_off = CECA_CTRL1,
+			.shift   = 12,
+			.width   = 12,
+		},
+		.dual = {
+			.reg_off = CECA_CTRL0,
+			.shift   = 28,
+			.width   = 1,
+		},
+		.table = t7_dualdiv_table,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "ceca_dualdiv_div",
+		.ops = &meson_clk_dualdiv_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_ceca_dualdiv_in.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_ceca_dualdiv_sel = {
+	.data = &(struct clk_regmap_mux_data) {
+		.offset = CECA_CTRL1,
+		.mask = 0x1,
+		.shift = 24,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "ceca_dualdiv_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_ceca_dualdiv_div.hw,
+			&t7_ceca_dualdiv_in.hw,
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_ceca_dualdiv = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = CECA_CTRL0,
+		.bit_idx = 30,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "ceca_dualdiv",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_ceca_dualdiv_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_ceca = {
+	.data = &(struct clk_regmap_mux_data) {
+		.offset = CECA_CTRL1,
+		.mask = 0x1,
+		.shift = 31,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "ceca",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_ceca_dualdiv.hw,
+			&t7_rtc.hw,
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_cecb_dualdiv_in = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = CECB_CTRL0,
+		.bit_idx = 31,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "cecb_dualdiv_in",
+		.ops = &clk_regmap_gate_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "xtal",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_cecb_dualdiv_div = {
+	.data = &(struct meson_clk_dualdiv_data){
+		.n1 = {
+			.reg_off = CECB_CTRL0,
+			.shift   = 0,
+			.width   = 12,
+		},
+		.n2 = {
+			.reg_off = CECB_CTRL0,
+			.shift   = 12,
+			.width   = 12,
+		},
+		.m1 = {
+			.reg_off = CECB_CTRL1,
+			.shift   = 0,
+			.width   = 12,
+		},
+		.m2 = {
+			.reg_off = CECB_CTRL1,
+			.shift   = 12,
+			.width   = 12,
+		},
+		.dual = {
+			.reg_off = CECB_CTRL0,
+			.shift   = 28,
+			.width   = 1,
+		},
+		.table = t7_dualdiv_table,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "cecb_dualdiv_div",
+		.ops = &meson_clk_dualdiv_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_cecb_dualdiv_in.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_cecb_dualdiv_sel = {
+	.data = &(struct clk_regmap_mux_data) {
+		.offset = CECB_CTRL1,
+		.mask = 0x1,
+		.shift = 24,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "cecb_dualdiv_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_cecb_dualdiv_div.hw,
+			&t7_cecb_dualdiv_in.hw,
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_cecb_dualdiv = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = CECB_CTRL0,
+		.bit_idx = 30,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "cecb_dualdiv",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_cecb_dualdiv_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_cecb = {
+	.data = &(struct clk_regmap_mux_data) {
+		.offset = CECB_CTRL1,
+		.mask = 0x1,
+		.shift = 31,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "cecb",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_cecb_dualdiv.hw,
+			&t7_rtc.hw,
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static const struct clk_parent_data t7_sc_parents[] = {
+	{ .fw_name = "fdiv4", },
+	{ .fw_name = "fdiv3", },
+	{ .fw_name = "fdiv5", },
+	{ .fw_name = "xtal", },
+};
+
+static T7_COMP_SEL(sc, SC_CLK_CTRL, 9, 0x3, t7_sc_parents);
+static T7_COMP_DIV(sc, SC_CLK_CTRL, 0, 8);
+static T7_COMP_GATE(sc, SC_CLK_CTRL, 8, 0);
+
+static const struct clk_parent_data t7_dsp_parents[] = {
+	{ .fw_name = "xtal", },
+	{ .fw_name = "fdiv2p5", },
+	{ .fw_name = "fdiv3", },
+	{ .fw_name = "fdiv5", },
+	{ .fw_name = "hifi", },
+	{ .fw_name = "fdiv4", },
+	{ .fw_name = "fdiv7", },
+	{ .hw = &t7_rtc.hw },
+};
+
+static T7_COMP_SEL(dspa_0, DSPA_CLK_CTRL0, 10, 0x7, t7_dsp_parents);
+static T7_COMP_DIV(dspa_0, DSPA_CLK_CTRL0, 0, 10);
+static T7_COMP_GATE(dspa_0, DSPA_CLK_CTRL0, 13, CLK_SET_RATE_GATE);
+
+static T7_COMP_SEL(dspa_1, DSPA_CLK_CTRL0, 26, 0x7, t7_dsp_parents);
+static T7_COMP_DIV(dspa_1, DSPA_CLK_CTRL0, 16, 10);
+static T7_COMP_GATE(dspa_1, DSPA_CLK_CTRL0, 29, CLK_SET_RATE_GATE);
+
+static struct clk_regmap t7_dspa = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = DSPA_CLK_CTRL0,
+		.mask = 0x1,
+		.shift = 15,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "dspa",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_dspa_0.hw,
+			&t7_dspa_1.hw,
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static T7_COMP_SEL(dspb_0, DSPB_CLK_CTRL0, 10, 0x7, t7_dsp_parents);
+static T7_COMP_DIV(dspb_0, DSPB_CLK_CTRL0, 0, 10);
+static T7_COMP_GATE(dspb_0, DSPB_CLK_CTRL0, 13, CLK_SET_RATE_GATE);
+
+static T7_COMP_SEL(dspb_1, DSPB_CLK_CTRL0, 26, 0x7, t7_dsp_parents);
+static T7_COMP_DIV(dspb_1, DSPB_CLK_CTRL0, 16, 10);
+static T7_COMP_GATE(dspb_1, DSPB_CLK_CTRL0, 29, CLK_SET_RATE_GATE);
+
+static struct clk_regmap t7_dspb = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = DSPB_CLK_CTRL0,
+		.mask = 0x1,
+		.shift = 15,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "dspb",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_dspb_0.hw,
+			&t7_dspb_1.hw,
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_24m = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = CLK12_24_CTRL,
+		.bit_idx = 11,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "24m",
+		.ops = &clk_regmap_gate_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "xtal",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_fixed_factor t7_24m_div2 = {
+	.mult = 1,
+	.div = 2,
+	.hw.init = &(struct clk_init_data){
+		.name = "24m_div2",
+		.ops = &clk_fixed_factor_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_24m.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_12m = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = CLK12_24_CTRL,
+		.bit_idx = 10,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "12m",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_24m_div2.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_25m_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = CLK12_24_CTRL,
+		.shift = 0,
+		.width = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "25m_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "fix",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_25m = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = CLK12_24_CTRL,
+		.bit_idx = 12,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "25m",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_25m_div.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static const struct clk_parent_data t7_anakin_parents[] = {
+	{ .fw_name = "fdiv4", },
+	{ .fw_name = "fdiv3", },
+	{ .fw_name = "fdiv5", },
+	{ .fw_name = "fdiv2", },
+	{ .fw_name = "vid_pll0", },
+	{ .fw_name = "mpll1", },
+	{ .fw_name = "mpll2", },
+	{ .fw_name = "fdiv2p5", },
+};
+
+static T7_COMP_SEL(anakin_0, ANAKIN_CLK_CTRL, 9, 0x7, t7_anakin_parents);
+static T7_COMP_DIV(anakin_0, ANAKIN_CLK_CTRL, 0, 7);
+static T7_COMP_GATE(anakin_0, ANAKIN_CLK_CTRL, 8, CLK_SET_RATE_GATE);
+
+static T7_COMP_SEL(anakin_1, ANAKIN_CLK_CTRL, 25, 0x7, t7_anakin_parents);
+static T7_COMP_DIV(anakin_1, ANAKIN_CLK_CTRL, 16, 7);
+static T7_COMP_GATE(anakin_1, ANAKIN_CLK_CTRL, 24, CLK_SET_RATE_GATE);
+
+static struct clk_regmap t7_anakin_01_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = ANAKIN_CLK_CTRL,
+		.mask = 1,
+		.shift = 31,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "anakin_01_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_anakin_0.hw,
+			&t7_anakin_1.hw
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT
+	},
+};
+
+static struct clk_regmap t7_anakin = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = ANAKIN_CLK_CTRL,
+		.bit_idx = 30,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "anakin",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_anakin_01_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT
+	},
+};
+
+static const struct clk_parent_data t7_mipi_csi_phy_parents[] = {
+	{ .fw_name = "xtal", },
+	{ .fw_name = "gp1", },
+	{ .fw_name = "mpll1", },
+	{ .fw_name = "mpll2", },
+	{ .fw_name = "fdiv3", },
+	{ .fw_name = "fdiv4", },
+	{ .fw_name = "fdiv5", },
+	{ .fw_name = "fdiv7", },
+};
+
+static T7_COMP_SEL(mipi_csi_phy_0, MIPI_CSI_PHY_CLK_CTRL, 9, 0x7, t7_mipi_csi_phy_parents);
+static T7_COMP_DIV(mipi_csi_phy_0, MIPI_CSI_PHY_CLK_CTRL, 0, 7);
+static T7_COMP_GATE(mipi_csi_phy_0, MIPI_CSI_PHY_CLK_CTRL, 8, CLK_SET_RATE_GATE);
+
+static T7_COMP_SEL(mipi_csi_phy_1, MIPI_CSI_PHY_CLK_CTRL, 25, 0x7, t7_mipi_csi_phy_parents);
+static T7_COMP_DIV(mipi_csi_phy_1, MIPI_CSI_PHY_CLK_CTRL, 16, 7);
+static T7_COMP_GATE(mipi_csi_phy_1, MIPI_CSI_PHY_CLK_CTRL, 24, CLK_SET_RATE_GATE);
+
+static struct clk_regmap t7_mipi_csi_phy = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = MIPI_CSI_PHY_CLK_CTRL,
+		.mask = 0x1,
+		.shift = 31,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mipi_csi_phy",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_mipi_csi_phy_0.hw,
+			&t7_mipi_csi_phy_1.hw
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static const struct clk_parent_data t7_mipi_isp_parents[] = {
+	{ .fw_name = "xtal", },
+	{ .fw_name = "fdiv4", },
+	{ .fw_name = "fdiv3", },
+	{ .fw_name = "fdiv5", },
+	{ .fw_name = "fdiv7", },
+	{ .fw_name = "mpll2", },
+	{ .fw_name = "mpll3", },
+	{ .fw_name = "gp1", },
+};
+
+static T7_COMP_SEL(mipi_isp, MIPI_ISP_CLK_CTRL, 9, 0x7, t7_mipi_isp_parents);
+static T7_COMP_DIV(mipi_isp, MIPI_ISP_CLK_CTRL, 0, 7);
+static T7_COMP_GATE(mipi_isp, MIPI_ISP_CLK_CTRL, 8, 0);
+
+static struct clk_regmap t7_ts_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = TS_CLK_CTRL,
+		.shift = 0,
+		.width = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "ts_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "xtal",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_ts = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = TS_CLK_CTRL,
+		.bit_idx = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "ts",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_ts_div.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static const struct clk_parent_data t7_mali_parents[] = {
+	{ .fw_name = "xtal", },
+	{ .fw_name = "gp0", },
+	{ .fw_name = "gp1", },
+	{ .fw_name = "fdiv2p5", },
+	{ .fw_name = "fdiv3", },
+	{ .fw_name = "fdiv4", },
+	{ .fw_name = "fdiv5", },
+	{ .fw_name = "fdiv7", },
+};
+
+static T7_COMP_SEL(mali_0, MALI_CLK_CTRL, 9, 0x7, t7_mali_parents);
+static T7_COMP_DIV(mali_0, MALI_CLK_CTRL, 0, 7);
+static T7_COMP_GATE(mali_0, MALI_CLK_CTRL, 8, CLK_SET_RATE_GATE);
+
+static T7_COMP_SEL(mali_1, MALI_CLK_CTRL, 25, 0x7, t7_mali_parents);
+static T7_COMP_DIV(mali_1, MALI_CLK_CTRL, 16, 7);
+static T7_COMP_GATE(mali_1, MALI_CLK_CTRL, 24, CLK_SET_RATE_GATE);
+
+static struct clk_regmap t7_mali = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = MALI_CLK_CTRL,
+		.mask = 1,
+		.shift = 31,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mali",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_mali_0.hw,
+			&t7_mali_1.hw,
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+/*
+ * parent index 2, 3, 4, 5, 6 not connect any clock signal,
+ * the last parent connect external PAD
+ */
+static u32 t7_eth_rmii_parents_val_table[] = { 0, 1, 7 };
+static const struct clk_parent_data t7_eth_rmii_parents[] = {
+	{ .fw_name = "fdiv2", },
+	{ .fw_name = "gp1", },
+	{ .fw_name = "ext_rmii", },
+};
+
+static struct clk_regmap t7_eth_rmii_sel = {
+	.data = &(struct clk_regmap_mux_data) {
+		.offset = ETH_CLK_CTRL,
+		.mask = 0x7,
+		.shift = 9,
+		.table = t7_eth_rmii_parents_val_table,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "eth_rmii_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = t7_eth_rmii_parents,
+		.num_parents = ARRAY_SIZE(t7_eth_rmii_parents),
+		.flags = CLK_SET_RATE_NO_REPARENT,
+	},
+};
+
+static struct clk_regmap t7_eth_rmii_div = {
+	.data = &(struct clk_regmap_div_data) {
+		.offset = ETH_CLK_CTRL,
+		.shift = 0,
+		.width = 7,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "eth_rmii_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_eth_rmii_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_eth_rmii = {
+	.data = &(struct clk_regmap_gate_data) {
+		.offset = ETH_CLK_CTRL,
+		.bit_idx = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "eth_rmii",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_eth_rmii_div.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_fixed_factor t7_fdiv2_div8 = {
+	.mult = 1,
+	.div = 8,
+	.hw.init = &(struct clk_init_data){
+		.name = "fdiv2_div8",
+		.ops = &clk_fixed_factor_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "fdiv2",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_eth_125m = {
+	.data = &(struct clk_regmap_gate_data) {
+		.offset = ETH_CLK_CTRL,
+		.bit_idx = 7,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "eth_125m",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_fdiv2_div8.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static const struct clk_parent_data t7_sd_emmc_parents[] = {
+	{ .fw_name = "xtal", },
+	{ .fw_name = "fdiv2", },
+	{ .fw_name = "fdiv3", },
+	{ .fw_name = "hifi", },
+	{ .fw_name = "fdiv2p5", },
+	{ .fw_name = "mpll2", },
+	{ .fw_name = "mpll3", },
+	{ .fw_name = "gp0", },
+};
+
+static T7_COMP_SEL(sd_emmc_a, SD_EMMC_CLK_CTRL, 9, 0x7, t7_sd_emmc_parents);
+static T7_COMP_DIV(sd_emmc_a, SD_EMMC_CLK_CTRL, 0, 7);
+static T7_COMP_GATE(sd_emmc_a, SD_EMMC_CLK_CTRL, 7, 0);
+
+static T7_COMP_SEL(sd_emmc_b, SD_EMMC_CLK_CTRL, 25, 0x7, t7_sd_emmc_parents);
+static T7_COMP_DIV(sd_emmc_b, SD_EMMC_CLK_CTRL, 16, 7);
+static T7_COMP_GATE(sd_emmc_b, SD_EMMC_CLK_CTRL, 23, 0);
+
+static T7_COMP_SEL(sd_emmc_c, NAND_CLK_CTRL, 9, 0x7, t7_sd_emmc_parents);
+static T7_COMP_DIV(sd_emmc_c, NAND_CLK_CTRL, 0, 7);
+static T7_COMP_GATE(sd_emmc_c, NAND_CLK_CTRL, 7, 0);
+
+static const struct clk_parent_data t7_spicc_parents[] = {
+	{ .fw_name = "xtal", },
+	{ .fw_name = "sys", },
+	{ .fw_name = "fdiv4", },
+	{ .fw_name = "fdiv3", },
+	{ .fw_name = "fdiv2", },
+	{ .fw_name = "fdiv5", },
+	{ .fw_name = "fdiv7", },
+	{ .fw_name = "gp1", },
+};
+
+static T7_COMP_SEL(spicc0, SPICC_CLK_CTRL, 7, 0x7, t7_spicc_parents);
+static T7_COMP_DIV(spicc0, SPICC_CLK_CTRL, 0, 6);
+static T7_COMP_GATE(spicc0, SPICC_CLK_CTRL, 6, 0);
+
+static T7_COMP_SEL(spicc1, SPICC_CLK_CTRL, 23, 0x7, t7_spicc_parents);
+static T7_COMP_DIV(spicc1, SPICC_CLK_CTRL, 16, 6);
+static T7_COMP_GATE(spicc1, SPICC_CLK_CTRL, 22, 0);
+
+static T7_COMP_SEL(spicc2, SPICC_CLK_CTRL1, 7, 0x7, t7_spicc_parents);
+static T7_COMP_DIV(spicc2, SPICC_CLK_CTRL1, 0, 6);
+static T7_COMP_GATE(spicc2, SPICC_CLK_CTRL1, 6, 0);
+
+static T7_COMP_SEL(spicc3, SPICC_CLK_CTRL1, 23, 0x7, t7_spicc_parents);
+static T7_COMP_DIV(spicc3, SPICC_CLK_CTRL1, 16, 6);
+static T7_COMP_GATE(spicc3, SPICC_CLK_CTRL1, 22, 0);
+
+static T7_COMP_SEL(spicc4, SPICC_CLK_CTRL2, 7, 0x7, t7_spicc_parents);
+static T7_COMP_DIV(spicc4, SPICC_CLK_CTRL2, 0, 6);
+static T7_COMP_GATE(spicc4, SPICC_CLK_CTRL2, 6, 0);
+
+static T7_COMP_SEL(spicc5, SPICC_CLK_CTRL2, 23, 0x7, t7_spicc_parents);
+static T7_COMP_DIV(spicc5, SPICC_CLK_CTRL2, 16, 6);
+static T7_COMP_GATE(spicc5, SPICC_CLK_CTRL2, 22, 0);
+
+static const struct clk_parent_data t7_saradc_parents[] = {
+	{ .fw_name = "xtal" },
+	{ .fw_name = "sys" },
+};
+
+static T7_COMP_SEL(saradc, SAR_CLK_CTRL0, 9, 0x1, t7_saradc_parents);
+static T7_COMP_DIV(saradc, SAR_CLK_CTRL0, 0, 8);
+static T7_COMP_GATE(saradc, SAR_CLK_CTRL0, 8, 0);
+
+static const struct clk_parent_data t7_pwm_parents[]  = {
+	{ .fw_name = "xtal", },
+	{ .fw_name = "vid_pll0", },
+	{ .fw_name = "fdiv4", },
+	{ .fw_name = "fdiv3", },
+};
+
+static T7_COMP_SEL(pwm_a, PWM_CLK_AB_CTRL, 9, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_a, PWM_CLK_AB_CTRL, 0, 8);
+static T7_COMP_GATE(pwm_a, PWM_CLK_AB_CTRL, 8, 0);
+
+static T7_COMP_SEL(pwm_b, PWM_CLK_AB_CTRL, 25, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_b, PWM_CLK_AB_CTRL, 16, 8);
+static T7_COMP_GATE(pwm_b, PWM_CLK_AB_CTRL, 24, 0);
+
+static T7_COMP_SEL(pwm_c, PWM_CLK_CD_CTRL, 9, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_c, PWM_CLK_CD_CTRL, 0, 8);
+static T7_COMP_GATE(pwm_c, PWM_CLK_CD_CTRL, 8, 0);
+
+static T7_COMP_SEL(pwm_d, PWM_CLK_CD_CTRL, 25, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_d, PWM_CLK_CD_CTRL, 16, 8);
+static T7_COMP_GATE(pwm_d, PWM_CLK_CD_CTRL, 24, 0);
+
+static T7_COMP_SEL(pwm_e, PWM_CLK_EF_CTRL, 9, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_e, PWM_CLK_EF_CTRL, 0, 8);
+static T7_COMP_GATE(pwm_e, PWM_CLK_EF_CTRL, 8, 0);
+
+static T7_COMP_SEL(pwm_f, PWM_CLK_EF_CTRL, 25, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_f, PWM_CLK_EF_CTRL, 16, 8);
+static T7_COMP_GATE(pwm_f, PWM_CLK_EF_CTRL, 24, 0);
+
+static T7_COMP_SEL(pwm_ao_a, PWM_CLK_AO_AB_CTRL, 9, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_ao_a, PWM_CLK_AO_AB_CTRL, 0, 8);
+static T7_COMP_GATE(pwm_ao_a, PWM_CLK_AO_AB_CTRL, 8, 0);
+
+static T7_COMP_SEL(pwm_ao_b, PWM_CLK_AO_AB_CTRL, 25, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_ao_b, PWM_CLK_AO_AB_CTRL, 16, 8);
+static T7_COMP_GATE(pwm_ao_b, PWM_CLK_AO_AB_CTRL, 24, 0);
+
+static T7_COMP_SEL(pwm_ao_c, PWM_CLK_AO_CD_CTRL, 9, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_ao_c, PWM_CLK_AO_CD_CTRL, 0, 8);
+static T7_COMP_GATE(pwm_ao_c, PWM_CLK_AO_CD_CTRL, 8, 0);
+
+static T7_COMP_SEL(pwm_ao_d, PWM_CLK_AO_CD_CTRL, 25, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_ao_d, PWM_CLK_AO_CD_CTRL, 16, 8);
+static T7_COMP_GATE(pwm_ao_d, PWM_CLK_AO_CD_CTRL, 24, 0);
+
+static T7_COMP_SEL(pwm_ao_e, PWM_CLK_AO_EF_CTRL, 9, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_ao_e, PWM_CLK_AO_EF_CTRL, 0, 8);
+static T7_COMP_GATE(pwm_ao_e, PWM_CLK_AO_EF_CTRL, 8, 0);
+
+static T7_COMP_SEL(pwm_ao_f, PWM_CLK_AO_EF_CTRL, 25, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_ao_f, PWM_CLK_AO_EF_CTRL, 16, 8);
+static T7_COMP_GATE(pwm_ao_f, PWM_CLK_AO_EF_CTRL, 24, 0);
+
+static T7_COMP_SEL(pwm_ao_g, PWM_CLK_AO_GH_CTRL, 9, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_ao_g, PWM_CLK_AO_GH_CTRL, 0, 8);
+static T7_COMP_GATE(pwm_ao_g, PWM_CLK_AO_GH_CTRL, 8, 0);
+
+static T7_COMP_SEL(pwm_ao_h, PWM_CLK_AO_GH_CTRL, 25, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_ao_h, PWM_CLK_AO_GH_CTRL, 16, 8);
+static T7_COMP_GATE(pwm_ao_h, PWM_CLK_AO_GH_CTRL, 24, 0);
+
+static const struct clk_parent_data t7_sys_pclk_parents = { .fw_name = "sys" };
+
+#define T7_SYS_PCLK(_name, _reg, _bit, _flags) \
+	MESON_PCLK(t7_##_name, _reg, _bit, &t7_sys_pclk_parents, _flags)
+
+static T7_SYS_PCLK(sys_ddr,		SYS_CLK_EN0_REG0, 0,	0);
+static T7_SYS_PCLK(sys_dos,		SYS_CLK_EN0_REG0, 1,	0);
+static T7_SYS_PCLK(sys_mipi_dsi_a,	SYS_CLK_EN0_REG0, 2,	0);
+static T7_SYS_PCLK(sys_mipi_dsi_b,	SYS_CLK_EN0_REG0, 3,	0);
+static T7_SYS_PCLK(sys_ethphy,		SYS_CLK_EN0_REG0, 4,	0);
+static T7_SYS_PCLK(sys_mali,		SYS_CLK_EN0_REG0, 6,	0);
+static T7_SYS_PCLK(sys_aocpu,		SYS_CLK_EN0_REG0, 13,	0);
+static T7_SYS_PCLK(sys_aucpu,		SYS_CLK_EN0_REG0, 14,	0);
+static T7_SYS_PCLK(sys_cec,		SYS_CLK_EN0_REG0, 16,	0);
+static T7_SYS_PCLK(sys_gdc,		SYS_CLK_EN0_REG0, 17,	0);
+static T7_SYS_PCLK(sys_deswarp,		SYS_CLK_EN0_REG0, 18,	0);
+static T7_SYS_PCLK(sys_ampipe_nand,	SYS_CLK_EN0_REG0, 19,	0);
+static T7_SYS_PCLK(sys_ampipe_eth,	SYS_CLK_EN0_REG0, 20,	0);
+static T7_SYS_PCLK(sys_am2axi0,		SYS_CLK_EN0_REG0, 21,	0);
+static T7_SYS_PCLK(sys_am2axi1,		SYS_CLK_EN0_REG0, 22,	0);
+static T7_SYS_PCLK(sys_am2axi2,		SYS_CLK_EN0_REG0, 23,	0);
+static T7_SYS_PCLK(sys_sd_emmc_a,	SYS_CLK_EN0_REG0, 24,	0);
+static T7_SYS_PCLK(sys_sd_emmc_b,	SYS_CLK_EN0_REG0, 25,	0);
+static T7_SYS_PCLK(sys_sd_emmc_c,	SYS_CLK_EN0_REG0, 26,	0);
+static T7_SYS_PCLK(sys_smartcard,	SYS_CLK_EN0_REG0, 27,	0);
+static T7_SYS_PCLK(sys_acodec,		SYS_CLK_EN0_REG0, 28,	0);
+static T7_SYS_PCLK(sys_spifc,		SYS_CLK_EN0_REG0, 29,	0);
+static T7_SYS_PCLK(sys_msr_clk,		SYS_CLK_EN0_REG0, 30,	0);
+static T7_SYS_PCLK(sys_ir_ctrl,		SYS_CLK_EN0_REG0, 31,	0);
+static T7_SYS_PCLK(sys_audio,		SYS_CLK_EN0_REG1, 0,	0);
+static T7_SYS_PCLK(sys_eth,		SYS_CLK_EN0_REG1, 3,	0);
+static T7_SYS_PCLK(sys_uart_a,		SYS_CLK_EN0_REG1, 5,	0);
+static T7_SYS_PCLK(sys_uart_b,		SYS_CLK_EN0_REG1, 6,	0);
+static T7_SYS_PCLK(sys_uart_c,		SYS_CLK_EN0_REG1, 7,	0);
+static T7_SYS_PCLK(sys_uart_d,		SYS_CLK_EN0_REG1, 8,	0);
+static T7_SYS_PCLK(sys_uart_e,		SYS_CLK_EN0_REG1, 9,	0);
+static T7_SYS_PCLK(sys_uart_f,		SYS_CLK_EN0_REG1, 10,	0);
+static T7_SYS_PCLK(sys_aififo,		SYS_CLK_EN0_REG1, 11,	0);
+static T7_SYS_PCLK(sys_spicc2,		SYS_CLK_EN0_REG1, 12,	0);
+static T7_SYS_PCLK(sys_spicc3,		SYS_CLK_EN0_REG1, 13,	0);
+static T7_SYS_PCLK(sys_spicc4,		SYS_CLK_EN0_REG1, 14,	0);
+static T7_SYS_PCLK(sys_ts_a73,		SYS_CLK_EN0_REG1, 15,	0);
+static T7_SYS_PCLK(sys_ts_a53,		SYS_CLK_EN0_REG1, 16,	0);
+static T7_SYS_PCLK(sys_spicc5,		SYS_CLK_EN0_REG1, 17,	0);
+static T7_SYS_PCLK(sys_g2d,		SYS_CLK_EN0_REG1, 20,	0);
+static T7_SYS_PCLK(sys_spicc0,		SYS_CLK_EN0_REG1, 21,	0);
+static T7_SYS_PCLK(sys_spicc1,		SYS_CLK_EN0_REG1, 22,	0);
+static T7_SYS_PCLK(sys_pcie,		SYS_CLK_EN0_REG1, 24,	0);
+static T7_SYS_PCLK(sys_usb,		SYS_CLK_EN0_REG1, 26,	0);
+static T7_SYS_PCLK(sys_pcie_phy,	SYS_CLK_EN0_REG1, 27,	0);
+static T7_SYS_PCLK(sys_i2c_ao_a,	SYS_CLK_EN0_REG1, 28,	0);
+static T7_SYS_PCLK(sys_i2c_ao_b,	SYS_CLK_EN0_REG1, 29,	0);
+static T7_SYS_PCLK(sys_i2c_m_a,		SYS_CLK_EN0_REG1, 30,	0);
+static T7_SYS_PCLK(sys_i2c_m_b,		SYS_CLK_EN0_REG1, 31,	0);
+static T7_SYS_PCLK(sys_i2c_m_c,		SYS_CLK_EN0_REG2, 0,	0);
+static T7_SYS_PCLK(sys_i2c_m_d,		SYS_CLK_EN0_REG2, 1,	0);
+static T7_SYS_PCLK(sys_i2c_m_e,		SYS_CLK_EN0_REG2, 2,	0);
+static T7_SYS_PCLK(sys_i2c_m_f,		SYS_CLK_EN0_REG2, 3,	0);
+static T7_SYS_PCLK(sys_hdmitx_apb,	SYS_CLK_EN0_REG2, 4,	0);
+static T7_SYS_PCLK(sys_i2c_s_a,		SYS_CLK_EN0_REG2, 5,	0);
+static T7_SYS_PCLK(sys_hdmirx_pclk,	SYS_CLK_EN0_REG2, 8,	0);
+static T7_SYS_PCLK(sys_mmc_apb,		SYS_CLK_EN0_REG2, 11,	0);
+static T7_SYS_PCLK(sys_mipi_isp_pclk,	SYS_CLK_EN0_REG2, 17,	0);
+static T7_SYS_PCLK(sys_rsa,		SYS_CLK_EN0_REG2, 18,	0);
+static T7_SYS_PCLK(sys_pclk_sys_apb,	SYS_CLK_EN0_REG2, 19,	0);
+static T7_SYS_PCLK(sys_a73pclk_apb,	SYS_CLK_EN0_REG2, 20,	0);
+static T7_SYS_PCLK(sys_dspa,		SYS_CLK_EN0_REG2, 21,	0);
+static T7_SYS_PCLK(sys_dspb,		SYS_CLK_EN0_REG2, 22,	0);
+static T7_SYS_PCLK(sys_vpu_intr,	SYS_CLK_EN0_REG2, 25,	0);
+static T7_SYS_PCLK(sys_sar_adc,		SYS_CLK_EN0_REG2, 28,	0);
+/*
+ * sys_gic provides the clock for GIC(Generic Interrupt Controller).
+ * After clock is disabled, The GIC cannot work properly. At present, the driver
+ * used by our GIC is the public driver in kernel, and there is no management
+ * clock in the driver.
+ */
+static T7_SYS_PCLK(sys_gic,		SYS_CLK_EN0_REG2, 30,	CLK_IS_CRITICAL);
+static T7_SYS_PCLK(sys_ts_gpu,		SYS_CLK_EN0_REG2, 31,	0);
+static T7_SYS_PCLK(sys_ts_nna,		SYS_CLK_EN0_REG3, 0,	0);
+static T7_SYS_PCLK(sys_ts_vpu,		SYS_CLK_EN0_REG3, 1,	0);
+static T7_SYS_PCLK(sys_ts_hevc,		SYS_CLK_EN0_REG3, 2,	0);
+static T7_SYS_PCLK(sys_pwm_ao_ab,	SYS_CLK_EN0_REG3, 3,	0);
+static T7_SYS_PCLK(sys_pwm_ao_cd,	SYS_CLK_EN0_REG3, 4,	0);
+static T7_SYS_PCLK(sys_pwm_ao_ef,	SYS_CLK_EN0_REG3, 5,	0);
+static T7_SYS_PCLK(sys_pwm_ao_gh,	SYS_CLK_EN0_REG3, 6,	0);
+static T7_SYS_PCLK(sys_pwm_ab,		SYS_CLK_EN0_REG3, 7,	0);
+static T7_SYS_PCLK(sys_pwm_cd,		SYS_CLK_EN0_REG3, 8,	0);
+static T7_SYS_PCLK(sys_pwm_ef,		SYS_CLK_EN0_REG3, 9,	0);
+
+/* Array of all clocks registered by this provider */
+static struct clk_hw *t7_peripherals_hw_clks[] = {
+	[CLKID_RTC_DUALDIV_IN]		= &t7_rtc_dualdiv_in.hw,
+	[CLKID_RTC_DUALDIV_DIV]		= &t7_rtc_dualdiv_div.hw,
+	[CLKID_RTC_DUALDIV_SEL]		= &t7_rtc_dualdiv_sel.hw,
+	[CLKID_RTC_DUALDIV]		= &t7_rtc_dualdiv.hw,
+	[CLKID_RTC]			= &t7_rtc.hw,
+	[CLKID_CECA_DUALDIV_IN]		= &t7_ceca_dualdiv_in.hw,
+	[CLKID_CECA_DUALDIV_DIV]	= &t7_ceca_dualdiv_div.hw,
+	[CLKID_CECA_DUALDIV_SEL]	= &t7_ceca_dualdiv_sel.hw,
+	[CLKID_CECA_DUALDIV]		= &t7_ceca_dualdiv.hw,
+	[CLKID_CECA]			= &t7_ceca.hw,
+	[CLKID_CECB_DUALDIV_IN]		= &t7_cecb_dualdiv_in.hw,
+	[CLKID_CECB_DUALDIV_DIV]	= &t7_cecb_dualdiv_div.hw,
+	[CLKID_CECB_DUALDIV_SEL]	= &t7_cecb_dualdiv_sel.hw,
+	[CLKID_CECB_DUALDIV]		= &t7_cecb_dualdiv.hw,
+	[CLKID_CECB]			= &t7_cecb.hw,
+	[CLKID_SC_SEL]			= &t7_sc_sel.hw,
+	[CLKID_SC_DIV]			= &t7_sc_div.hw,
+	[CLKID_SC]			= &t7_sc.hw,
+	[CLKID_DSPA_0_SEL]		= &t7_dspa_0_sel.hw,
+	[CLKID_DSPA_0_DIV]		= &t7_dspa_0_div.hw,
+	[CLKID_DSPA_0]			= &t7_dspa_0.hw,
+	[CLKID_DSPA_1_SEL]		= &t7_dspa_1_sel.hw,
+	[CLKID_DSPA_1_DIV]		= &t7_dspa_1_div.hw,
+	[CLKID_DSPA_1]			= &t7_dspa_1.hw,
+	[CLKID_DSPA]			= &t7_dspa.hw,
+	[CLKID_DSPB_0_SEL]		= &t7_dspb_0_sel.hw,
+	[CLKID_DSPB_0_DIV]		= &t7_dspb_0_div.hw,
+	[CLKID_DSPB_0]			= &t7_dspb_0.hw,
+	[CLKID_DSPB_1_SEL]		= &t7_dspb_1_sel.hw,
+	[CLKID_DSPB_1_DIV]		= &t7_dspb_1_div.hw,
+	[CLKID_DSPB_1]			= &t7_dspb_1.hw,
+	[CLKID_DSPB]			= &t7_dspb.hw,
+	[CLKID_24M]			= &t7_24m.hw,
+	[CLKID_24M_DIV2]		= &t7_24m_div2.hw,
+	[CLKID_12M]			= &t7_12m.hw,
+	[CLKID_25M_DIV]			= &t7_25m_div.hw,
+	[CLKID_25M]			= &t7_25m.hw,
+	[CLKID_ANAKIN_0_SEL]		= &t7_anakin_0_sel.hw,
+	[CLKID_ANAKIN_0_DIV]		= &t7_anakin_0_div.hw,
+	[CLKID_ANAKIN_0]		= &t7_anakin_0.hw,
+	[CLKID_ANAKIN_1_SEL]		= &t7_anakin_1_sel.hw,
+	[CLKID_ANAKIN_1_DIV]		= &t7_anakin_1_div.hw,
+	[CLKID_ANAKIN_1]		= &t7_anakin_1.hw,
+	[CLKID_ANAKIN_01_SEL]		= &t7_anakin_01_sel.hw,
+	[CLKID_ANAKIN]			= &t7_anakin.hw,
+	[CLKID_MIPI_CSI_PHY_0_SEL]	= &t7_mipi_csi_phy_0_sel.hw,
+	[CLKID_MIPI_CSI_PHY_0_DIV]	= &t7_mipi_csi_phy_0_div.hw,
+	[CLKID_MIPI_CSI_PHY_0]		= &t7_mipi_csi_phy_0.hw,
+	[CLKID_MIPI_CSI_PHY_1_SEL]	= &t7_mipi_csi_phy_1_sel.hw,
+	[CLKID_MIPI_CSI_PHY_1_DIV]	= &t7_mipi_csi_phy_1_div.hw,
+	[CLKID_MIPI_CSI_PHY_1]		= &t7_mipi_csi_phy_1.hw,
+	[CLKID_MIPI_CSI_PHY]		= &t7_mipi_csi_phy.hw,
+	[CLKID_MIPI_ISP_SEL]		= &t7_mipi_isp_sel.hw,
+	[CLKID_MIPI_ISP_DIV]		= &t7_mipi_isp_div.hw,
+	[CLKID_MIPI_ISP]		= &t7_mipi_isp.hw,
+	[CLKID_TS_DIV]			= &t7_ts_div.hw,
+	[CLKID_TS]			= &t7_ts.hw,
+	[CLKID_MALI_0_SEL]		= &t7_mali_0_sel.hw,
+	[CLKID_MALI_0_DIV]		= &t7_mali_0_div.hw,
+	[CLKID_MALI_0]			= &t7_mali_0.hw,
+	[CLKID_MALI_1_SEL]		= &t7_mali_1_sel.hw,
+	[CLKID_MALI_1_DIV]		= &t7_mali_1_div.hw,
+	[CLKID_MALI_1]			= &t7_mali_1.hw,
+	[CLKID_MALI]			= &t7_mali.hw,
+	[CLKID_ETH_RMII_SEL]		= &t7_eth_rmii_sel.hw,
+	[CLKID_ETH_RMII_DIV]		= &t7_eth_rmii_div.hw,
+	[CLKID_ETH_RMII]		= &t7_eth_rmii.hw,
+	[CLKID_FCLK_DIV2_DIV8]		= &t7_fdiv2_div8.hw,
+	[CLKID_ETH_125M]		= &t7_eth_125m.hw,
+	[CLKID_SD_EMMC_A_SEL]		= &t7_sd_emmc_a_sel.hw,
+	[CLKID_SD_EMMC_A_DIV]		= &t7_sd_emmc_a_div.hw,
+	[CLKID_SD_EMMC_A]		= &t7_sd_emmc_a.hw,
+	[CLKID_SD_EMMC_B_SEL]		= &t7_sd_emmc_b_sel.hw,
+	[CLKID_SD_EMMC_B_DIV]		= &t7_sd_emmc_b_div.hw,
+	[CLKID_SD_EMMC_B]		= &t7_sd_emmc_b.hw,
+	[CLKID_SD_EMMC_C_SEL]		= &t7_sd_emmc_c_sel.hw,
+	[CLKID_SD_EMMC_C_DIV]		= &t7_sd_emmc_c_div.hw,
+	[CLKID_SD_EMMC_C]		= &t7_sd_emmc_c.hw,
+	[CLKID_SPICC0_SEL]		= &t7_spicc0_sel.hw,
+	[CLKID_SPICC0_DIV]		= &t7_spicc0_div.hw,
+	[CLKID_SPICC0]			= &t7_spicc0.hw,
+	[CLKID_SPICC1_SEL]		= &t7_spicc1_sel.hw,
+	[CLKID_SPICC1_DIV]		= &t7_spicc1_div.hw,
+	[CLKID_SPICC1]			= &t7_spicc1.hw,
+	[CLKID_SPICC2_SEL]		= &t7_spicc2_sel.hw,
+	[CLKID_SPICC2_DIV]		= &t7_spicc2_div.hw,
+	[CLKID_SPICC2]			= &t7_spicc2.hw,
+	[CLKID_SPICC3_SEL]		= &t7_spicc3_sel.hw,
+	[CLKID_SPICC3_DIV]		= &t7_spicc3_div.hw,
+	[CLKID_SPICC3]			= &t7_spicc3.hw,
+	[CLKID_SPICC4_SEL]		= &t7_spicc4_sel.hw,
+	[CLKID_SPICC4_DIV]		= &t7_spicc4_div.hw,
+	[CLKID_SPICC4]			= &t7_spicc4.hw,
+	[CLKID_SPICC5_SEL]		= &t7_spicc5_sel.hw,
+	[CLKID_SPICC5_DIV]		= &t7_spicc5_div.hw,
+	[CLKID_SPICC5]			= &t7_spicc5.hw,
+	[CLKID_SARADC_SEL]		= &t7_saradc_sel.hw,
+	[CLKID_SARADC_DIV]		= &t7_saradc_div.hw,
+	[CLKID_SARADC]			= &t7_saradc.hw,
+	[CLKID_PWM_A_SEL]		= &t7_pwm_a_sel.hw,
+	[CLKID_PWM_A_DIV]		= &t7_pwm_a_div.hw,
+	[CLKID_PWM_A]			= &t7_pwm_a.hw,
+	[CLKID_PWM_B_SEL]		= &t7_pwm_b_sel.hw,
+	[CLKID_PWM_B_DIV]		= &t7_pwm_b_div.hw,
+	[CLKID_PWM_B]			= &t7_pwm_b.hw,
+	[CLKID_PWM_C_SEL]		= &t7_pwm_c_sel.hw,
+	[CLKID_PWM_C_DIV]		= &t7_pwm_c_div.hw,
+	[CLKID_PWM_C]			= &t7_pwm_c.hw,
+	[CLKID_PWM_D_SEL]		= &t7_pwm_d_sel.hw,
+	[CLKID_PWM_D_DIV]		= &t7_pwm_d_div.hw,
+	[CLKID_PWM_D]			= &t7_pwm_d.hw,
+	[CLKID_PWM_E_SEL]		= &t7_pwm_e_sel.hw,
+	[CLKID_PWM_E_DIV]		= &t7_pwm_e_div.hw,
+	[CLKID_PWM_E]			= &t7_pwm_e.hw,
+	[CLKID_PWM_F_SEL]		= &t7_pwm_f_sel.hw,
+	[CLKID_PWM_F_DIV]		= &t7_pwm_f_div.hw,
+	[CLKID_PWM_F]			= &t7_pwm_f.hw,
+	[CLKID_PWM_AO_A_SEL]		= &t7_pwm_ao_a_sel.hw,
+	[CLKID_PWM_AO_A_DIV]		= &t7_pwm_ao_a_div.hw,
+	[CLKID_PWM_AO_A]		= &t7_pwm_ao_a.hw,
+	[CLKID_PWM_AO_B_SEL]		= &t7_pwm_ao_b_sel.hw,
+	[CLKID_PWM_AO_B_DIV]		= &t7_pwm_ao_b_div.hw,
+	[CLKID_PWM_AO_B]		= &t7_pwm_ao_b.hw,
+	[CLKID_PWM_AO_C_SEL]		= &t7_pwm_ao_c_sel.hw,
+	[CLKID_PWM_AO_C_DIV]		= &t7_pwm_ao_c_div.hw,
+	[CLKID_PWM_AO_C]		= &t7_pwm_ao_c.hw,
+	[CLKID_PWM_AO_D_SEL]		= &t7_pwm_ao_d_sel.hw,
+	[CLKID_PWM_AO_D_DIV]		= &t7_pwm_ao_d_div.hw,
+	[CLKID_PWM_AO_D]		= &t7_pwm_ao_d.hw,
+	[CLKID_PWM_AO_E_SEL]		= &t7_pwm_ao_e_sel.hw,
+	[CLKID_PWM_AO_E_DIV]		= &t7_pwm_ao_e_div.hw,
+	[CLKID_PWM_AO_E]		= &t7_pwm_ao_e.hw,
+	[CLKID_PWM_AO_F_SEL]		= &t7_pwm_ao_f_sel.hw,
+	[CLKID_PWM_AO_F_DIV]		= &t7_pwm_ao_f_div.hw,
+	[CLKID_PWM_AO_F]		= &t7_pwm_ao_f.hw,
+	[CLKID_PWM_AO_G_SEL]		= &t7_pwm_ao_g_sel.hw,
+	[CLKID_PWM_AO_G_DIV]		= &t7_pwm_ao_g_div.hw,
+	[CLKID_PWM_AO_G]		= &t7_pwm_ao_g.hw,
+	[CLKID_PWM_AO_H_SEL]		= &t7_pwm_ao_h_sel.hw,
+	[CLKID_PWM_AO_H_DIV]		= &t7_pwm_ao_h_div.hw,
+	[CLKID_PWM_AO_H]		= &t7_pwm_ao_h.hw,
+	[CLKID_SYS_DDR]			= &t7_sys_ddr.hw,
+	[CLKID_SYS_DOS]			= &t7_sys_dos.hw,
+	[CLKID_SYS_MIPI_DSI_A]		= &t7_sys_mipi_dsi_a.hw,
+	[CLKID_SYS_MIPI_DSI_B]		= &t7_sys_mipi_dsi_b.hw,
+	[CLKID_SYS_ETHPHY]		= &t7_sys_ethphy.hw,
+	[CLKID_SYS_MALI]		= &t7_sys_mali.hw,
+	[CLKID_SYS_AOCPU]		= &t7_sys_aocpu.hw,
+	[CLKID_SYS_AUCPU]		= &t7_sys_aucpu.hw,
+	[CLKID_SYS_CEC]			= &t7_sys_cec.hw,
+	[CLKID_SYS_GDC]			= &t7_sys_gdc.hw,
+	[CLKID_SYS_DESWARP]		= &t7_sys_deswarp.hw,
+	[CLKID_SYS_AMPIPE_NAND]		= &t7_sys_ampipe_nand.hw,
+	[CLKID_SYS_AMPIPE_ETH]		= &t7_sys_ampipe_eth.hw,
+	[CLKID_SYS_AM2AXI0]		= &t7_sys_am2axi0.hw,
+	[CLKID_SYS_AM2AXI1]		= &t7_sys_am2axi1.hw,
+	[CLKID_SYS_AM2AXI2]		= &t7_sys_am2axi2.hw,
+	[CLKID_SYS_SD_EMMC_A]		= &t7_sys_sd_emmc_a.hw,
+	[CLKID_SYS_SD_EMMC_B]		= &t7_sys_sd_emmc_b.hw,
+	[CLKID_SYS_SD_EMMC_C]		= &t7_sys_sd_emmc_c.hw,
+	[CLKID_SYS_SMARTCARD]		= &t7_sys_smartcard.hw,
+	[CLKID_SYS_ACODEC]		= &t7_sys_acodec.hw,
+	[CLKID_SYS_SPIFC]		= &t7_sys_spifc.hw,
+	[CLKID_SYS_MSR_CLK]		= &t7_sys_msr_clk.hw,
+	[CLKID_SYS_IR_CTRL]		= &t7_sys_ir_ctrl.hw,
+	[CLKID_SYS_AUDIO]		= &t7_sys_audio.hw,
+	[CLKID_SYS_ETH]			= &t7_sys_eth.hw,
+	[CLKID_SYS_UART_A]		= &t7_sys_uart_a.hw,
+	[CLKID_SYS_UART_B]		= &t7_sys_uart_b.hw,
+	[CLKID_SYS_UART_C]		= &t7_sys_uart_c.hw,
+	[CLKID_SYS_UART_D]		= &t7_sys_uart_d.hw,
+	[CLKID_SYS_UART_E]		= &t7_sys_uart_e.hw,
+	[CLKID_SYS_UART_F]		= &t7_sys_uart_f.hw,
+	[CLKID_SYS_AIFIFO]		= &t7_sys_aififo.hw,
+	[CLKID_SYS_SPICC2]		= &t7_sys_spicc2.hw,
+	[CLKID_SYS_SPICC3]		= &t7_sys_spicc3.hw,
+	[CLKID_SYS_SPICC4]		= &t7_sys_spicc4.hw,
+	[CLKID_SYS_TS_A73]		= &t7_sys_ts_a73.hw,
+	[CLKID_SYS_TS_A53]		= &t7_sys_ts_a53.hw,
+	[CLKID_SYS_SPICC5]		= &t7_sys_spicc5.hw,
+	[CLKID_SYS_G2D]			= &t7_sys_g2d.hw,
+	[CLKID_SYS_SPICC0]		= &t7_sys_spicc0.hw,
+	[CLKID_SYS_SPICC1]		= &t7_sys_spicc1.hw,
+	[CLKID_SYS_PCIE]		= &t7_sys_pcie.hw,
+	[CLKID_SYS_USB]			= &t7_sys_usb.hw,
+	[CLKID_SYS_PCIE_PHY]		= &t7_sys_pcie_phy.hw,
+	[CLKID_SYS_I2C_AO_A]		= &t7_sys_i2c_ao_a.hw,
+	[CLKID_SYS_I2C_AO_B]		= &t7_sys_i2c_ao_b.hw,
+	[CLKID_SYS_I2C_M_A]		= &t7_sys_i2c_m_a.hw,
+	[CLKID_SYS_I2C_M_B]		= &t7_sys_i2c_m_b.hw,
+	[CLKID_SYS_I2C_M_C]		= &t7_sys_i2c_m_c.hw,
+	[CLKID_SYS_I2C_M_D]		= &t7_sys_i2c_m_d.hw,
+	[CLKID_SYS_I2C_M_E]		= &t7_sys_i2c_m_e.hw,
+	[CLKID_SYS_I2C_M_F]		= &t7_sys_i2c_m_f.hw,
+	[CLKID_SYS_HDMITX_APB]		= &t7_sys_hdmitx_apb.hw,
+	[CLKID_SYS_I2C_S_A]		= &t7_sys_i2c_s_a.hw,
+	[CLKID_SYS_HDMIRX_PCLK]		= &t7_sys_hdmirx_pclk.hw,
+	[CLKID_SYS_MMC_APB]		= &t7_sys_mmc_apb.hw,
+	[CLKID_SYS_MIPI_ISP_PCLK]	= &t7_sys_mipi_isp_pclk.hw,
+	[CLKID_SYS_RSA]			= &t7_sys_rsa.hw,
+	[CLKID_SYS_PCLK_SYS_APB]	= &t7_sys_pclk_sys_apb.hw,
+	[CLKID_SYS_A73PCLK_APB]		= &t7_sys_a73pclk_apb.hw,
+	[CLKID_SYS_DSPA]		= &t7_sys_dspa.hw,
+	[CLKID_SYS_DSPB]		= &t7_sys_dspb.hw,
+	[CLKID_SYS_VPU_INTR]		= &t7_sys_vpu_intr.hw,
+	[CLKID_SYS_SAR_ADC]		= &t7_sys_sar_adc.hw,
+	[CLKID_SYS_GIC]			= &t7_sys_gic.hw,
+	[CLKID_SYS_TS_GPU]		= &t7_sys_ts_gpu.hw,
+	[CLKID_SYS_TS_NNA]		= &t7_sys_ts_nna.hw,
+	[CLKID_SYS_TS_VPU]		= &t7_sys_ts_vpu.hw,
+	[CLKID_SYS_TS_HEVC]		= &t7_sys_ts_hevc.hw,
+	[CLKID_SYS_PWM_AO_AB]		= &t7_sys_pwm_ao_ab.hw,
+	[CLKID_SYS_PWM_AO_CD]		= &t7_sys_pwm_ao_cd.hw,
+	[CLKID_SYS_PWM_AO_EF]		= &t7_sys_pwm_ao_ef.hw,
+	[CLKID_SYS_PWM_AO_GH]		= &t7_sys_pwm_ao_gh.hw,
+	[CLKID_SYS_PWM_AB]		= &t7_sys_pwm_ab.hw,
+	[CLKID_SYS_PWM_CD]		= &t7_sys_pwm_cd.hw,
+	[CLKID_SYS_PWM_EF]		= &t7_sys_pwm_ef.hw,
+};
+
+static const struct meson_clkc_data t7_peripherals_data = {
+	.hw_clks = {
+		.hws = t7_peripherals_hw_clks,
+		.num = ARRAY_SIZE(t7_peripherals_hw_clks),
+	},
+};
+
+static const struct of_device_id t7_peripherals_clkc_match_table[] = {
+	{
+		.compatible = "amlogic,t7-peripherals-clkc",
+		.data = &t7_peripherals_data
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, t7_peripherals_clkc_match_table);
+
+static struct platform_driver t7_peripherals_clkc_driver = {
+	.probe = meson_clkc_mmio_probe,
+	.driver = {
+		.name = "t7-peripherals-clkc",
+		.of_match_table = t7_peripherals_clkc_match_table,
+	},
+};
+module_platform_driver(t7_peripherals_clkc_driver);
+
+MODULE_DESCRIPTION("Amlogic T7 Peripherals Clock Controller driver");
+MODULE_AUTHOR("Jian Hu <jian.hu at amlogic.com>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("CLK_MESON");
-- 
2.47.1



From anshuman.khandual at arm.com  Wed Dec  3 22:23:17 2025
From: anshuman.khandual at arm.com (Anshuman Khandual)
Date: Thu, 4 Dec 2025 11:53:17 +0530
Subject: [PATCH v5 08/12] mm: enable lazy_mmu sections to nest
In-Reply-To: <20251124132228.622678-9-kevin.brodsky@arm.com>
References: <20251124132228.622678-1-kevin.brodsky@arm.com>
 <20251124132228.622678-9-kevin.brodsky@arm.com>
Message-ID: <2dfd54d7-fe2a-4921-85ff-a581392a777a@arm.com>

On 24/11/25 6:52 PM, Kevin Brodsky wrote:
> Despite recent efforts to prevent lazy_mmu sections from nesting, it
> remains difficult to ensure that it never occurs - and in fact it
> does occur on arm64 in certain situations (CONFIG_DEBUG_PAGEALLOC).
> Commit 1ef3095b1405 ("arm64/mm: Permit lazy_mmu_mode to be nested")
> made nesting tolerable on arm64, but without truly supporting it:
> the inner call to leave() disables the batching optimisation before
> the outer section ends.
> 
> This patch actually enables lazy_mmu sections to nest by tracking
> the nesting level in task_struct, in a similar fashion to e.g.
> pagefault_{enable,disable}(). This is fully handled by the generic
> lazy_mmu helpers that were recently introduced.
> 
> lazy_mmu sections were not initially intended to nest, so we need to
> clarify the semantics w.r.t. the arch_*_lazy_mmu_mode() callbacks.
> This patch takes the following approach:
> 
> * The outermost calls to lazy_mmu_mode_{enable,disable}() trigger
>   calls to arch_{enter,leave}_lazy_mmu_mode() - this is unchanged.
> 
> * Nested calls to lazy_mmu_mode_{enable,disable}() are not forwarded
>   to the arch via arch_{enter,leave} - lazy MMU remains enabled so
>   the assumption is that these callbacks are not relevant. However,
>   existing code may rely on a call to disable() to flush any batched
>   state, regardless of nesting. arch_flush_lazy_mmu_mode() is
>   therefore called in that situation.
> 
> A separate interface was recently introduced to temporarily pause
> the lazy MMU mode: lazy_mmu_mode_{pause,resume}(). pause() fully
> exits the mode *regardless of the nesting level*, and resume()
> restores the mode at the same nesting level.
> 
> pause()/resume() are themselves allowed to nest, so we actually
> store two nesting levels in task_struct: enable_count and
> pause_count. A new helper in_lazy_mmu_mode() is introduced to
> determine whether we are currently in lazy MMU mode; this will be
> used in subsequent patches to replace the various ways arch's
> currently track whether the mode is enabled.
> 
> In summary (enable/pause represent the values *after* the call):
> 
> lazy_mmu_mode_enable()		-> arch_enter()	    enable=1 pause=0
>     lazy_mmu_mode_enable()	-> ?		    enable=2 pause=0
> 	lazy_mmu_mode_pause()	-> arch_leave()     enable=2 pause=1
> 	lazy_mmu_mode_resume()	-> arch_enter()     enable=2 pause=0
>     lazy_mmu_mode_disable()	-> arch_flush()     enable=1 pause=0
> lazy_mmu_mode_disable()		-> arch_leave()     enable=0 pause=0
> 
> Note: in_lazy_mmu_mode() is added to <linux/sched.h> to allow arch
> headers included by <linux/pgtable.h> to use it.
> 
> Signed-off-by: Kevin Brodsky <kevin.brodsky at arm.com>
> ---
>  arch/arm64/include/asm/pgtable.h |  12 ----
>  include/linux/mm_types_task.h    |   5 ++
>  include/linux/pgtable.h          | 115 +++++++++++++++++++++++++++++--
>  include/linux/sched.h            |  45 ++++++++++++
>  4 files changed, 158 insertions(+), 19 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
> index e596899f4029..a7d99dee3dc4 100644
> --- a/arch/arm64/include/asm/pgtable.h
> +++ b/arch/arm64/include/asm/pgtable.h
> @@ -82,18 +82,6 @@ static inline void queue_pte_barriers(void)
>  
>  static inline void arch_enter_lazy_mmu_mode(void)
>  {
> -	/*
> -	 * lazy_mmu_mode is not supposed to permit nesting. But in practice this
> -	 * does happen with CONFIG_DEBUG_PAGEALLOC, where a page allocation
> -	 * inside a lazy_mmu_mode section (such as zap_pte_range()) will change
> -	 * permissions on the linear map with apply_to_page_range(), which
> -	 * re-enters lazy_mmu_mode. So we tolerate nesting in our
> -	 * implementation. The first call to arch_leave_lazy_mmu_mode() will
> -	 * flush and clear the flag such that the remainder of the work in the
> -	 * outer nest behaves as if outside of lazy mmu mode. This is safe and
> -	 * keeps tracking simple.
> -	 */
> -
>  	set_thread_flag(TIF_LAZY_MMU);>  }

Should not platform specific changes be deferred to subsequent patches until
nesting is completely enabled in generic first ? Although no problem as such
but would be bit cleaner.

>  
> diff --git a/include/linux/mm_types_task.h b/include/linux/mm_types_task.h
> index a82aa80c0ba4..11bf319d78ec 100644
> --- a/include/linux/mm_types_task.h
> +++ b/include/linux/mm_types_task.h
> @@ -88,4 +88,9 @@ struct tlbflush_unmap_batch {
>  #endif
>  };
>  
> +struct lazy_mmu_state {
> +	u8 enable_count;
> +	u8 pause_count;
> +};
> +

Should not this be wrapped with CONFIG_ARCH_HAS_LAZY_MMU_MODE as the task_struct
element 'lazy_mmu_state' is only available with the feature. Besides, is a depth
of 256 really expected here ? 4 bits for each element would not be sufficient for
a depth of 16 ?


>  #endif /* _LINUX_MM_TYPES_TASK_H */
> diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
> index 8ff6fdb4b13d..24fdb6f5c2e1 100644
> --- a/include/linux/pgtable.h
> +++ b/include/linux/pgtable.h
> @@ -230,39 +230,140 @@ static inline int pmd_dirty(pmd_t pmd)
>   * (In practice, for user PTE updates, the appropriate page table lock(s) are
>   * held, but for kernel PTE updates, no lock is held). The mode is disabled in
>   * interrupt context and calls to the lazy_mmu API have no effect.
> - * Nesting is not permitted.
> + *
> + * The lazy MMU mode is enabled for a given block of code using:
> + *
> + *   lazy_mmu_mode_enable();
> + *   <code>
> + *   lazy_mmu_mode_disable();
> + *
> + * Nesting is permitted: <code> may itself use an enable()/disable() pair.
> + * A nested call to enable() has no functional effect; however disable() causes
> + * any batched architectural state to be flushed regardless of nesting. After a

Just wondering if there is a method for these generic helpers to ensure that platform
really does the required flushing on _disable() or the expected platform semantics is
only described via this comment alone ?

> + * call to disable(), the caller can therefore rely on all previous page table
> + * modifications to have taken effect, but the lazy MMU mode may still be
> + * enabled.
> + *
> + * In certain cases, it may be desirable to temporarily pause the lazy MMU mode.
> + * This can be done using:
> + *
> + *   lazy_mmu_mode_pause();
> + *   <code>
> + *   lazy_mmu_mode_resume();
> + *
> + * pause() ensures that the mode is exited regardless of the nesting level;
> + * resume() re-enters the mode at the same nesting level. Any call to the
> + * lazy_mmu_mode_* API between those two calls has no effect. In particular,
> + * this means that pause()/resume() pairs may nest.
> + *
> + * in_lazy_mmu_mode() can be used to check whether the lazy MMU mode is
> + * currently enabled.

Just wondering - could a corresponding test be included probably via KUNIT_TEST
to ensure the above described semantics are being followed.

>   */
>  #ifdef CONFIG_ARCH_HAS_LAZY_MMU_MODE
> +/**
> + * lazy_mmu_mode_enable() - Enable the lazy MMU mode.
> + *
> + * Enters a new lazy MMU mode section; if the mode was not already enabled,
> + * enables it and calls arch_enter_lazy_mmu_mode().
> + *
> + * Must be paired with a call to lazy_mmu_mode_disable().
> + *
> + * Has no effect if called:
> + * - While paused - see lazy_mmu_mode_pause()
> + * - In interrupt context
> + */
>  static inline void lazy_mmu_mode_enable(void)
>  {
> -	if (in_interrupt())
> +	struct lazy_mmu_state *state = &current->lazy_mmu_state;
> +
> +	if (in_interrupt() || state->pause_count > 0)
>  		return;
>  
> -	arch_enter_lazy_mmu_mode();
> +	VM_WARN_ON_ONCE(state->enable_count == U8_MAX);
> +
> +	if (state->enable_count++ == 0)
> +		arch_enter_lazy_mmu_mode();

When lazy_mmu_mode_enable() gets called for the first time with state->enable_count as 0,
then arch_enter_lazy_mmu_mode() will not get called ? Bit confused.

>  }
>  
> +/**
> + * lazy_mmu_mode_disable() - Disable the lazy MMU mode.
> + *
> + * Exits the current lazy MMU mode section. If it is the outermost section,
> + * disables the mode and calls arch_leave_lazy_mmu_mode(). Otherwise (nested
> + * section), calls arch_flush_lazy_mmu_mode().
> + *
> + * Must match a call to lazy_mmu_mode_enable().
> + *
> + * Has no effect if called:
> + * - While paused - see lazy_mmu_mode_pause()
> + * - In interrupt context
> + */
>  static inline void lazy_mmu_mode_disable(void)
>  {
> -	if (in_interrupt())
> +	struct lazy_mmu_state *state = &current->lazy_mmu_state;
> +
> +	if (in_interrupt() || state->pause_count > 0)
>  		return;
>  
> -	arch_leave_lazy_mmu_mode();
> +	VM_WARN_ON_ONCE(state->enable_count == 0);
> +
> +	if (--state->enable_count == 0)
> +		arch_leave_lazy_mmu_mode();
> +	else /* Exiting a nested section */
> +		arch_flush_lazy_mmu_mode();
> +
>  }
>  
> +/**
> + * lazy_mmu_mode_pause() - Pause the lazy MMU mode.
> + *
> + * Pauses the lazy MMU mode; if it is currently active, disables it and calls
> + * arch_leave_lazy_mmu_mode().
> + *
> + * Must be paired with a call to lazy_mmu_mode_resume(). Calls to the
> + * lazy_mmu_mode_* API have no effect until the matching resume() call.
> + *
> + * Has no effect if called:
> + * - While paused (inside another pause()/resume() pair)
> + * - In interrupt context
> + */
>  static inline void lazy_mmu_mode_pause(void)
>  {
> +	struct lazy_mmu_state *state = &current->lazy_mmu_state;
> +
>  	if (in_interrupt())
>  		return;
>  
> -	arch_leave_lazy_mmu_mode();
> +	VM_WARN_ON_ONCE(state->pause_count == U8_MAX);
> +
> +	if (state->pause_count++ == 0 && state->enable_count > 0)
> +		arch_leave_lazy_mmu_mode();
>  }
>  
> +/**
> + * lazy_mmu_mode_pause() - Resume the lazy MMU mode.
> + *
> + * Resumes the lazy MMU mode; if it was active at the point where the matching
> + * call to lazy_mmu_mode_pause() was made, re-enables it and calls
> + * arch_enter_lazy_mmu_mode().
> + *
> + * Must match a call to lazy_mmu_mode_pause().
> + *
> + * Has no effect if called:
> + * - While paused (inside another pause()/resume() pair)
> + * - In interrupt context
> + */
>  static inline void lazy_mmu_mode_resume(void)
>  {
> +	struct lazy_mmu_state *state = &current->lazy_mmu_state;
> +
>  	if (in_interrupt())
>  		return;
>  
> -	arch_enter_lazy_mmu_mode();
> +	VM_WARN_ON_ONCE(state->pause_count == 0);
> +
> +	if (--state->pause_count == 0 && state->enable_count > 0)
> +		arch_enter_lazy_mmu_mode();
>  }

Should not state->pause/enable_count tests and increment/decrement be handled
inside include/linux/sched via helpers like in_lazy_mmu_mode() ? This is will
ensure cleaner abstraction with respect to task_struct.

>  #else
>  static inline void lazy_mmu_mode_enable(void) {}
> diff --git a/include/linux/sched.h b/include/linux/sched.h
> index b469878de25c..847e242376db 100644
> --- a/include/linux/sched.h
> +++ b/include/linux/sched.h
> @@ -1441,6 +1441,10 @@ struct task_struct {
>  
>  	struct page_frag		task_frag;
>  
> +#ifdef CONFIG_ARCH_HAS_LAZY_MMU_MODE
> +	struct lazy_mmu_state		lazy_mmu_state;
> +#endif
> +
>  #ifdef CONFIG_TASK_DELAY_ACCT
>  	struct task_delay_info		*delays;
>  #endif
> @@ -1724,6 +1728,47 @@ static inline char task_state_to_char(struct task_struct *tsk)
>  	return task_index_to_char(task_state_index(tsk));
>  }
>  
> +#ifdef CONFIG_ARCH_HAS_LAZY_MMU_MODE
> +/**
> + * __task_lazy_mmu_mode_active() - Test the lazy MMU mode state for a task.
> + * @tsk: The task to check.
> + *
> + * Test whether @tsk has its lazy MMU mode state set to active (i.e. enabled
> + * and not paused).
> + *
> + * This function only considers the state saved in task_struct; to test whether
> + * current actually is in lazy MMU mode, in_lazy_mmu_mode() should be used
> + * instead.
> + *
> + * This function is intended for architectures that implement the lazy MMU
> + * mode; it must not be called from generic code.
> + */
> +static inline bool __task_lazy_mmu_mode_active(struct task_struct *tsk)
> +{
> +	struct lazy_mmu_state *state = &tsk->lazy_mmu_state;
> +
> +	return state->enable_count > 0 && state->pause_count == 0;
> +}
> +
> +/**
> + * in_lazy_mmu_mode() - Test whether we are currently in lazy MMU mode.
> + *
> + * Test whether the current context is in lazy MMU mode. This is true if both:
> + * 1. We are not in interrupt context
> + * 2. Lazy MMU mode is active for the current task
> + *
> + * This function is intended for architectures that implement the lazy MMU
> + * mode; it must not be called from generic code.
> + */
> +static inline bool in_lazy_mmu_mode(void)
> +{
> +	if (in_interrupt())
> +		return false;
> +
> +	return __task_lazy_mmu_mode_active(current);
> +}
> +#endif
> +
>  extern struct pid *cad_pid;
>  
>  /*



From jianpeng.chang.cn at windriver.com  Wed Dec  3 22:27:22 2025
From: jianpeng.chang.cn at windriver.com (Jianpeng Chang)
Date: Thu, 4 Dec 2025 14:27:22 +0800
Subject: [v3 PATCH] arm64: mm: Fix kexec failure after pte_mkwrite_novma() change
Message-ID: <20251204062722.3367201-1-jianpeng.chang.cn@windriver.com>

Commit 143937ca51cc ("arm64, mm: avoid always making PTE dirty in
pte_mkwrite()") modified pte_mkwrite_novma() to only clear PTE_RDONLY
when the page is already dirty (PTE_DIRTY is set). While this optimization
prevents unnecessary dirty page marking in normal memory management paths,
it breaks kexec on some platforms like NXP LS1043.

The issue occurs in the kexec code path:
1. machine_kexec_post_load() calls trans_pgd_create_copy() to create a
   writable copy of the linear mapping
2. _copy_pte() calls pte_mkwrite_novma() to ensure all pages in the copy
   are writable for the new kernel image copying
3. With the new logic, clean pages (without PTE_DIRTY) remain read-only
4. When kexec tries to copy the new kernel image through the linear
   mapping, it fails on read-only pages, causing the system to hang
   after "Bye!"

The same issue affects hibernation which uses the same trans_pgd code path.

Fix this by marking pages dirty with pte_mkdirty() in _copy_pte(), which
ensures pte_mkwrite_novma() clears PTE_RDONLY for both kexec and
hibernation, making all pages in the temporary mapping writable regardless
of their dirty state. This preserves the original commit's optimization
for normal memory management while fixing the kexec/hibernation regression.

Using pte_mkdirty() causes redundant bit operations when the page is
already writable (redundant PTE_RDONLY clearing), but this is acceptable
since it's not a hot path and only affects kexec/hibernation scenarios.

Fixes: 143937ca51cc ("arm64, mm: avoid always making PTE dirty in pte_mkwrite()")
Signed-off-by: Jianpeng Chang <jianpeng.chang.cn at windriver.com>
Reviewed-by: Huang Ying <ying.huang at linux.alibaba.com>
---
v3: 
  - Add the description about pte_mkdirty in commit message
  - Note that the redundant bit operations in commit message
  - Fix the comments following the suggestions
v2: https://lore.kernel.org/all/20251202022707.2720933-1-jianpeng.chang.cn at windriver.com/
  - Use pte_mkwrite_novma(pte_mkdirty(pte)) instead of manual bit manipulation
  - Updated comments to clarify pte_mkwrite_novma() alone cannot be used
v1: https://lore.kernel.org/all/20251127034350.3600454-1-jianpeng.chang.cn at windriver.com/

 arch/arm64/mm/trans_pgd.c | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/mm/trans_pgd.c b/arch/arm64/mm/trans_pgd.c
index 18543b603c77..766883780d2a 100644
--- a/arch/arm64/mm/trans_pgd.c
+++ b/arch/arm64/mm/trans_pgd.c
@@ -40,8 +40,14 @@ static void _copy_pte(pte_t *dst_ptep, pte_t *src_ptep, unsigned long addr)
 		 * Resume will overwrite areas that may be marked
 		 * read only (code, rodata). Clear the RDONLY bit from
 		 * the temporary mappings we use during restore.
+		 *
+		 * For both kexec and hibernation, writable accesses are required
+		 * for all pages in the linear map to copy over new kernel image.
+		 * Hence mark these pages dirty first via pte_mkdirty() to ensure
+		 * pte_mkwrite_novma() subsequently clears PTE_RDONLY - providing
+		 * required write access for the pages.
 		 */
-		__set_pte(dst_ptep, pte_mkwrite_novma(pte));
+		__set_pte(dst_ptep, pte_mkwrite_novma(pte_mkdirty(pte)));
 	} else if (!pte_none(pte)) {
 		/*
 		 * debug_pagealloc will removed the PTE_VALID bit if
@@ -57,7 +63,14 @@ static void _copy_pte(pte_t *dst_ptep, pte_t *src_ptep, unsigned long addr)
 		 */
 		BUG_ON(!pfn_valid(pte_pfn(pte)));
 
-		__set_pte(dst_ptep, pte_mkvalid(pte_mkwrite_novma(pte)));
+		/*
+		 * For both kexec and hibernation, writable accesses are required
+		 * for all pages in the linear map to copy over new kernel image.
+		 * Hence mark these pages dirty first via pte_mkdirty() to ensure
+		 * pte_mkwrite_novma() subsequently clears PTE_RDONLY - providing
+		 * required write access for the pages.
+		 */
+		__set_pte(dst_ptep, pte_mkvalid(pte_mkwrite_novma(pte_mkdirty(pte))));
 	}
 }
 
-- 
2.52.0



From kernel at airkyi.com  Wed Dec  3 22:30:58 2025
From: kernel at airkyi.com (Chaoyi Chen)
Date: Thu,  4 Dec 2025 14:30:58 +0800
Subject: [RESEND PATCH v11 00/11] Add Type-C DP support for RK3399 EVB IND board
Message-ID: <20251204063109.104-1-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

This series focuses on adding Type-C DP support for USBDP PHY and DP
driver. The USBDP PHY and DP will perceive the changes in cable status
based on the USB PD and Type-C state machines provided by TCPM. Before
this, the USBDP PHY and DP controller of RK3399 sensed cable state
changes through extcon, and devices such as the RK3399 Gru-Chromebook
rely on them. This series should not break them.

====
1. DisplayPort HPD status notify

Before v7, I implemented a variety of DP HPD status notify. However,
they all had various problems and it was difficult to become a generic
solution.

Under the guidance of Heikki and Dmitry, a decoupled notification
method between the TypeC and DRM subsystems was introduced in v7.
First, a notification is sent when TypeC registers a new altmode.
Then, a generic DP AUX HPD bridge is implemented on the DRM side.

During v7-v10, we added a new notifier in typec to notify the altmode
device register event. With the help of Greg and Heikki, we implemented
the reuse of notifiers for the type bus itself in patch1 of v11.

That makes it redundant for each Type-C controller driver to implement
a similar DP AUX HPD bridge in embedded scenarios.

====
2. Altmode switching and orientation switching for USBDP PHY

For USB Type-C interfaces, an external Type-C controller chip assists
by detecting cable attachment, determining plug orientation, and
reporting USB PD message. The USB/DP combo PHY supports software
configurable pin mapping and DisplayPort lane assignment. Based on
these message, the combo PHY can perform both altmode switching and
orientation switching via software.

The RK3399 EVB IND board has a Type-C interface DisplayPort. It use
fusb302 chip as Type-C controller. The connection diagram is shown below:

fusb302 chip +---> USB2.0 PHY ----> DWC3 USB controller
             |
             +---> USB/DP PHY0 +--> CDN-DP controller
                               |
                               +--> DWC3 USB controller

====
3. Multiple bridge model for RK3399 CDN-DP

The RK3399 has two USB/DP combo PHY and one CDN-DP controller. And
the CDN-DP can be switched to output to one of the PHYs.

USB/DP PHY0 ---+
               | <----> CDN-DP controller
USB/DP PHY1 ---+

In previous versions, if both PHY ports were connected to DP,
the CDN-DP driver would select the first PHY port for output.

On Dmitry's suggestion, we introduced a multi-bridge model to support
flexible selection of the output PHY port. For each PHY port, a
separate encoder and bridge are registered.

The change is based on the DRM AUX HPD bridge, rather than the
extcon approach. This requires the DT to correctly describe the
connections between the first bridge in bridge chain and DP
controller. And Once the first bridge is obtained, we can get the
last bridge corresponding to the USB-C connector, and then set the
DRM connector's fwnode to the corresponding one to enable HPD
notification.

====
Patch1 set the bus also for the port and plug altmodes.
Patch2 export typec bus and typec altmode device types.
Patch3 add generic USB Type-C DP HPD bridge.
Patch4 add new API drm_aux_bridge_register_from_node().
Patch5 add new Type-C mode switch for RK3399 USBDP phy binding.
Patch6 add typec_mux and typec_switch for RK3399 USBDP PHY.
Patch7 add DRM AUX bridge support for RK3399 USBDP PHY.
Patch8 drops CDN-DP's extcon dependency when Type-C is present.
Patch9 add multiple bridges to support PHY port selection.
Patch10 add missing dp_out port for RK3399 CDN-DP.
Patch11 add Type-C DP support for RK3399 EVB IND board.

Changes in v11:
- Link to V10: https://lore.kernel.org/all/20251120022343.250-1-kernel at airkyi.com/
- Switch to using typec bus notifiers.

Changes in v10:
- Link to V9: https://lore.kernel.org/all/20251111105040.94-1-kernel at airkyi.com/
- Notify TYPEC_ALTMODE_UNREGISTERED when altmode removed. 
- Add drm_aux_bridge_register_from_node().
- Fix refcount usage of drm_bridge.

Changes in v9:
- Link to V8: https://lore.kernel.org/all/20251029071435.88-1-kernel at airkyi.com/
- Remove the exposed DRM_AUX_HPD_BRIDGE option, and select
DRM_AUX_HPD_TYPEC_BRIDGE when it is available.
- Add usb role switch for Type-C.
- Remove USB2 PHY in Type-C connection.
- ...

Changes in v8:
- Link to V7: https://lore.kernel.org/all/20251023033009.90-1-kernel at airkyi.com/
- Export all typec device types for identification.
- Merge generic DP HPD bridge into one module.
- Fix coding style.

Changes in v7:
- Link to V6: https://lore.kernel.org/all/20251016022741.91-1-kernel at airkyi.com/
- Add notifier functions for Type-C core.
- Add generic USB Type-C DP HPD bridge.

Changes in v6:
- Link to V5: https://lore.kernel.org/all/20251011033233.97-1-kernel at airkyi.com/
- Fix depend in Kconfig.
- Check DP svid in tcphy_typec_mux_set().
- Remove mode setting in tcphy_orien_sw_set().
- Rename some variable names.
- Attach the DP bridge to the next bridge.

Changes in v5:
- Link to V4: https://lore.kernel.org/all/20250922012039.323-1-kernel at airkyi.com/
- Remove the calls related to `drm_aux_hpd_bridge_notify()`.
- Place the helper functions in the same compilation unit.
- Add more comments about parent device.
- Add DRM AUX bridge support for RK3399 USBDP PHY
- By parsing the HPD bridge chain, set the connector's of_node to the
of_node corresponding to the USB-C connector.
- Return EDID cache when other port is already enabled.

Changes in v4:
- Link to V3: https://lore.kernel.org/all/20250729090032.97-1-kernel at airkyi.com/
- Add default HPD device for DisplayPort altmode.
- Introduce multiple bridges for CDN-DP.
- ...

Changes in v3:
- Link to V2: https://lore.kernel.org/all/20250718062619.99-1-kernel at airkyi.com/
- Add more descriptions to clarify the role of the PHY in switching.
- Fix wrong vdo value.
- Fix port node in usb-c-connector.

Changes in v2:
- Link to V1: https://lore.kernel.org/all/20250715112456.101-1-kernel at airkyi.com/
- Reuse dp-port/usb3-port in rk3399-typec-phy binding.
- Fix compile error when CONFIG_TYPEC is not enabled.
- Notify DP HPD state by USB/DP PHY.
- Ignore duplicate HPD events.
- Add endpoint to link DP PHY and DP controller.
- Fix devicetree coding style.

Chaoyi Chen (10):
  usb: typec: Export typec bus and typec altmode device type
  drm/bridge: Implement generic USB Type-C DP HPD bridge
  drm/bridge: aux: Add drm_aux_bridge_register_from_node()
  dt-bindings: phy: rockchip: rk3399-typec-phy: Support mode-switch
  phy: rockchip: phy-rockchip-typec: Add typec_mux/typec_switch support
  phy: rockchip: phy-rockchip-typec: Add DRM AUX bridge
  drm/rockchip: cdn-dp: Support handle lane info without extcon
  drm/rockchip: cdn-dp: Add multiple bridges to support PHY port
    selection
  arm64: dts: rockchip: Add missing dp_out port for RK3399 CDN-DP
  arm64: dts: rockchip: rk3399-evb-ind: Add support for DisplayPort

Heikki Krogerus (1):
  usb: typec: Set the bus also for the port and plug altmodes

 .../phy/rockchip,rk3399-typec-phy.yaml        |   6 +
 arch/arm64/boot/dts/rockchip/rk3399-base.dtsi |  10 +-
 .../boot/dts/rockchip/rk3399-evb-ind.dts      | 147 +++++++
 drivers/gpu/drm/bridge/Kconfig                |  10 +
 drivers/gpu/drm/bridge/Makefile               |   1 +
 drivers/gpu/drm/bridge/aux-bridge.c           |  24 +-
 .../gpu/drm/bridge/aux-hpd-typec-dp-bridge.c  |  51 +++
 drivers/gpu/drm/rockchip/Kconfig              |   1 +
 drivers/gpu/drm/rockchip/cdn-dp-core.c        | 350 +++++++++++++---
 drivers/gpu/drm/rockchip/cdn-dp-core.h        |  18 +-
 drivers/phy/rockchip/Kconfig                  |   3 +
 drivers/phy/rockchip/phy-rockchip-typec.c     | 373 +++++++++++++++++-
 drivers/usb/typec/bus.c                       |  25 +-
 drivers/usb/typec/bus.h                       |   6 -
 drivers/usb/typec/class.c                     |  36 +-
 include/drm/bridge/aux-bridge.h               |   6 +
 include/linux/usb/typec.h                     |   3 +
 include/linux/usb/typec_altmode.h             |   8 +
 18 files changed, 976 insertions(+), 102 deletions(-)
 create mode 100644 drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c

-- 
2.51.1



From kernel at airkyi.com  Wed Dec  3 22:31:01 2025
From: kernel at airkyi.com (Chaoyi Chen)
Date: Thu,  4 Dec 2025 14:31:01 +0800
Subject: [RESEND PATCH v11 03/11] drm/bridge: Implement generic USB Type-C DP HPD bridge
In-Reply-To: <20251204063109.104-1-kernel@airkyi.com>
References: <20251204063109.104-1-kernel@airkyi.com>
Message-ID: <20251204063109.104-4-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

The HPD function of Type-C DP is implemented through
drm_connector_oob_hotplug_event(). For embedded DP, it is required
that the DRM connector fwnode corresponds to the Type-C port fwnode.

To describe the relationship between the DP controller and the Type-C
port device, we usually using drm_bridge to build a bridge chain.

Now several USB-C controller drivers have already implemented the DP
HPD bridge function provided by aux-hpd-bridge.c, it will build a DP
HPD bridge on USB-C connector port device.

But this requires the USB-C controller driver to manually register the
HPD bridge. If the driver does not implement this feature, the bridge
will not be create.

So this patch implements a generic DP HPD bridge based on
aux-hpd-bridge.c. It will monitor Type-C bus events, and when a
Type-C port device containing the DP svid is registered, it will
create an HPD bridge for it without the need for the USB-C controller
driver to implement it.

Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
---

Changes in v11:
- Switch to using typec bus notifiers.

(no changes since v10)

Changes in v9:
- Remove the exposed DRM_AUX_HPD_BRIDGE option, and select
DRM_AUX_HPD_TYPEC_BRIDGE when it is available.
- Add more commit comment about problem background.

Changes in v8:
- Merge generic DP HPD bridge into one module.

 drivers/gpu/drm/bridge/Kconfig                | 10 ++++
 drivers/gpu/drm/bridge/Makefile               |  1 +
 .../gpu/drm/bridge/aux-hpd-typec-dp-bridge.c  | 51 +++++++++++++++++++
 3 files changed, 62 insertions(+)
 create mode 100644 drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index a250afd8d662..559487aa09a9 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -30,6 +30,16 @@ config DRM_AUX_HPD_BRIDGE
 	  Simple bridge that terminates the bridge chain and provides HPD
 	  support.
 
+if DRM_AUX_HPD_BRIDGE
+config DRM_AUX_HPD_TYPEC_BRIDGE
+	tristate
+	depends on TYPEC || !TYPEC
+	default TYPEC
+	help
+	  Simple bridge that terminates the bridge chain and provides HPD
+	  support. It build bridge on each USB-C connector device node.
+endif
+
 menu "Display Interface Bridges"
 	depends on DRM && DRM_BRIDGE
 
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index c7dc03182e59..a3a0393d2e72 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_DRM_AUX_BRIDGE) += aux-bridge.o
 obj-$(CONFIG_DRM_AUX_HPD_BRIDGE) += aux-hpd-bridge.o
+obj-$(CONFIG_DRM_AUX_HPD_TYPEC_BRIDGE) += aux-hpd-typec-dp-bridge.o
 obj-$(CONFIG_DRM_CHIPONE_ICN6211) += chipone-icn6211.o
 obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o
 obj-$(CONFIG_DRM_CROS_EC_ANX7688) += cros-ec-anx7688.o
diff --git a/drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c b/drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c
new file mode 100644
index 000000000000..94be3d5f69e9
--- /dev/null
+++ b/drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0+
+#include <linux/of.h>
+#include <linux/usb/typec_altmode.h>
+#include <linux/usb/typec_dp.h>
+
+#include <drm/bridge/aux-bridge.h>
+
+static int drm_typec_bus_event(struct notifier_block *nb,
+			       unsigned long action, void *data)
+{
+	struct device *dev = (struct device *)data;
+	struct typec_altmode *alt = to_typec_altmode(dev);
+
+	if (action != BUS_NOTIFY_ADD_DEVICE)
+		goto done;
+
+	if (is_typec_partner_altmode(&alt->dev) || alt->svid != USB_TYPEC_DP_SID)
+		goto done;
+
+	/*
+	 * alt->dev.parent->parent : USB-C controller device
+	 * alt->dev.parent         : USB-C connector device
+	 */
+	drm_dp_hpd_bridge_register(alt->dev.parent->parent,
+				   to_of_node(alt->dev.parent->fwnode));
+
+done:
+	return NOTIFY_OK;
+}
+
+static struct notifier_block drm_typec_event_nb = {
+	.notifier_call = drm_typec_bus_event,
+};
+
+static void drm_aux_hpd_typec_dp_bridge_module_exit(void)
+{
+	bus_unregister_notifier(&typec_bus, &drm_typec_event_nb);
+}
+
+static int __init drm_aux_hpd_typec_dp_bridge_module_init(void)
+{
+	bus_register_notifier(&typec_bus, &drm_typec_event_nb);
+
+	return 0;
+}
+
+module_init(drm_aux_hpd_typec_dp_bridge_module_init);
+module_exit(drm_aux_hpd_typec_dp_bridge_module_exit);
+
+MODULE_DESCRIPTION("DRM TYPEC DP HPD BRIDGE");
+MODULE_LICENSE("GPL");
-- 
2.51.1



From kernel at airkyi.com  Wed Dec  3 22:30:59 2025
From: kernel at airkyi.com (Chaoyi Chen)
Date: Thu,  4 Dec 2025 14:30:59 +0800
Subject: [RESEND PATCH v11 01/11] usb: typec: Set the bus also for the port and plug altmodes
In-Reply-To: <20251204063109.104-1-kernel@airkyi.com>
References: <20251204063109.104-1-kernel@airkyi.com>
Message-ID: <20251204063109.104-2-kernel@airkyi.com>

From: Heikki Krogerus <heikki.krogerus at linux.intel.com>

The port and plug altmodes can't be bound to the altmode
drivers because the altmode drivers are meant for partner
communication using the VDM (vendor defined messages), but
they can still be part of the bus. The bus will make sure
that the normal bus notifications are available also with
the port altmodes.

The previously used common device type for all alternate
modes is replaced with separate dedicated device types for
port, plug, and partner alternate modes.

Signed-off-by: Heikki Krogerus <heikki.krogerus at linux.intel.com>
Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
---
 drivers/usb/typec/bus.c   | 24 +++++++++++++++++++++++-
 drivers/usb/typec/bus.h   |  8 ++++++--
 drivers/usb/typec/class.c | 33 ++++++++++++++++++++++-----------
 3 files changed, 51 insertions(+), 14 deletions(-)

diff --git a/drivers/usb/typec/bus.c b/drivers/usb/typec/bus.c
index a884cec9ab7e..a33da7f458a5 100644
--- a/drivers/usb/typec/bus.c
+++ b/drivers/usb/typec/bus.c
@@ -445,7 +445,23 @@ static struct attribute *typec_attrs[] = {
 	&dev_attr_description.attr,
 	NULL
 };
-ATTRIBUTE_GROUPS(typec);
+
+static umode_t typec_is_visible(struct kobject *kobj, struct attribute *attr, int n)
+{
+	if (is_typec_partner_altmode(kobj_to_dev(kobj)))
+		return attr->mode;
+	return 0;
+}
+
+static const struct attribute_group typec_group = {
+	.is_visible = typec_is_visible,
+	.attrs = typec_attrs,
+};
+
+static const struct attribute_group *typec_groups[] = {
+	&typec_group,
+	NULL
+};
 
 static int typec_match(struct device *dev, const struct device_driver *driver)
 {
@@ -453,6 +469,9 @@ static int typec_match(struct device *dev, const struct device_driver *driver)
 	struct typec_altmode *altmode = to_typec_altmode(dev);
 	const struct typec_device_id *id;
 
+	if (!is_typec_partner_altmode(dev))
+		return 0;
+
 	for (id = drv->id_table; id->svid; id++)
 		if (id->svid == altmode->svid)
 			return 1;
@@ -463,6 +482,9 @@ static int typec_uevent(const struct device *dev, struct kobj_uevent_env *env)
 {
 	const struct typec_altmode *altmode = to_typec_altmode(dev);
 
+	if (!is_typec_partner_altmode(dev))
+		return 0;
+
 	if (add_uevent_var(env, "SVID=%04X", altmode->svid))
 		return -ENOMEM;
 
diff --git a/drivers/usb/typec/bus.h b/drivers/usb/typec/bus.h
index 643b8c81786d..b58e131450d1 100644
--- a/drivers/usb/typec/bus.h
+++ b/drivers/usb/typec/bus.h
@@ -29,8 +29,12 @@ struct altmode {
 #define to_altmode(d) container_of(d, struct altmode, adev)
 
 extern const struct bus_type typec_bus;
-extern const struct device_type typec_altmode_dev_type;
+extern const struct device_type typec_port_altmode_dev_type;
+extern const struct device_type typec_plug_altmode_dev_type;
+extern const struct device_type typec_partner_altmode_dev_type;
 
-#define is_typec_altmode(_dev_) (_dev_->type == &typec_altmode_dev_type)
+#define is_typec_port_altmode(dev) ((dev)->type == &typec_port_altmode_dev_type)
+#define is_typec_plug_altmode(dev) ((dev)->type == &typec_plug_altmode_dev_type)
+#define is_typec_partner_altmode(dev) ((dev)->type == &typec_partner_altmode_dev_type)
 
 #endif /* __USB_TYPEC_ALTMODE_H__ */
diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index 9b2647cb199b..d6b88317f8a4 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -235,7 +235,7 @@ static int altmode_match(struct device *dev, const void *data)
 	struct typec_altmode *adev = to_typec_altmode(dev);
 	const struct typec_device_id *id = data;
 
-	if (!is_typec_altmode(dev))
+	if (!is_typec_port_altmode(dev))
 		return 0;
 
 	return (adev->svid == id->svid);
@@ -532,15 +532,28 @@ static void typec_altmode_release(struct device *dev)
 	kfree(alt);
 }
 
-const struct device_type typec_altmode_dev_type = {
-	.name = "typec_alternate_mode",
+const struct device_type typec_port_altmode_dev_type = {
+	.name = "typec_port_alternate_mode",
+	.groups = typec_altmode_groups,
+	.release = typec_altmode_release,
+};
+
+const struct device_type typec_plug_altmode_dev_type = {
+	.name = "typec_plug_alternate_mode",
+	.groups = typec_altmode_groups,
+	.release = typec_altmode_release,
+};
+
+const struct device_type typec_partner_altmode_dev_type = {
+	.name = "typec_partner_alternate_mode",
 	.groups = typec_altmode_groups,
 	.release = typec_altmode_release,
 };
 
 static struct typec_altmode *
 typec_register_altmode(struct device *parent,
-		       const struct typec_altmode_desc *desc)
+		       const struct typec_altmode_desc *desc,
+		       const struct device_type *type)
 {
 	unsigned int id = altmode_id_get(parent);
 	bool is_port = is_typec_port(parent);
@@ -575,7 +588,7 @@ typec_register_altmode(struct device *parent,
 
 	alt->adev.dev.parent = parent;
 	alt->adev.dev.groups = alt->groups;
-	alt->adev.dev.type = &typec_altmode_dev_type;
+	alt->adev.dev.type = type;
 	dev_set_name(&alt->adev.dev, "%s.%u", dev_name(parent), id);
 
 	get_device(alt->adev.dev.parent);
@@ -584,9 +597,7 @@ typec_register_altmode(struct device *parent,
 	if (!is_port)
 		typec_altmode_set_partner(alt);
 
-	/* The partners are bind to drivers */
-	if (is_typec_partner(parent))
-		alt->adev.dev.bus = &typec_bus;
+	alt->adev.dev.bus = &typec_bus;
 
 	/* Plug alt modes need a class to generate udev events. */
 	if (is_typec_plug(parent))
@@ -963,7 +974,7 @@ struct typec_altmode *
 typec_partner_register_altmode(struct typec_partner *partner,
 			       const struct typec_altmode_desc *desc)
 {
-	return typec_register_altmode(&partner->dev, desc);
+	return typec_register_altmode(&partner->dev, desc, &typec_partner_altmode_dev_type);
 }
 EXPORT_SYMBOL_GPL(typec_partner_register_altmode);
 
@@ -1193,7 +1204,7 @@ struct typec_altmode *
 typec_plug_register_altmode(struct typec_plug *plug,
 			    const struct typec_altmode_desc *desc)
 {
-	return typec_register_altmode(&plug->dev, desc);
+	return typec_register_altmode(&plug->dev, desc, &typec_plug_altmode_dev_type);
 }
 EXPORT_SYMBOL_GPL(typec_plug_register_altmode);
 
@@ -2493,7 +2504,7 @@ typec_port_register_altmode(struct typec_port *port,
 		return ERR_CAST(retimer);
 	}
 
-	adev = typec_register_altmode(&port->dev, desc);
+	adev = typec_register_altmode(&port->dev, desc, &typec_port_altmode_dev_type);
 	if (IS_ERR(adev)) {
 		typec_retimer_put(retimer);
 		typec_mux_put(mux);
-- 
2.51.1



From kernel at airkyi.com  Wed Dec  3 22:31:03 2025
From: kernel at airkyi.com (Chaoyi Chen)
Date: Thu,  4 Dec 2025 14:31:03 +0800
Subject: [RESEND PATCH v11 05/11] dt-bindings: phy: rockchip: rk3399-typec-phy: Support mode-switch
In-Reply-To: <20251204063109.104-1-kernel@airkyi.com>
References: <20251204063109.104-1-kernel@airkyi.com>
Message-ID: <20251204063109.104-6-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

The RK3399 SoC integrates two USB/DP combo PHYs, each of which
supports software-configurable pin mapping and DisplayPort lane
assignment. These capabilities enable the PHY itself to handle both
mode switching and orientation switching, based on the Type-C plug
orientation and USB PD negotiation results.

While an external Type-C controller is still required to detect cable
attachment and report USB PD events, the actual mode and orientation
switching is performed internally by the PHY through software
configuration. This allows the PHY to act as a Type-C multiplexer for
both data role and DP altmode configuration.

To reflect this hardware design, this patch introduces a new
"mode-switch" property for the dp-port node in the device tree bindings.
This property indicates that the connected PHY is capable of handling
Type-C mode switching itself.

Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
---

(no changes since v5)

Changes in v4:
- Remove "|" in description.

Changes in v3:
- Add more descriptions to clarify the role of the PHY in switching.

Changes in v2:
- Reuse dp-port/usb3-port in rk3399-typec-phy binding.

 .../devicetree/bindings/phy/rockchip,rk3399-typec-phy.yaml  | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/phy/rockchip,rk3399-typec-phy.yaml b/Documentation/devicetree/bindings/phy/rockchip,rk3399-typec-phy.yaml
index 91c011f68cd0..83ebcde096ea 100644
--- a/Documentation/devicetree/bindings/phy/rockchip,rk3399-typec-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/rockchip,rk3399-typec-phy.yaml
@@ -51,6 +51,12 @@ properties:
       '#phy-cells':
         const: 0
 
+      mode-switch:
+        description:
+          Indicates the PHY can handle altmode switching. In this case,
+          requires an external USB Type-C controller to report USB PD message.
+        type: boolean
+
       port:
         $ref: /schemas/graph.yaml#/properties/port
         description: Connection to USB Type-C connector
-- 
2.51.1



From kernel at airkyi.com  Wed Dec  3 22:31:00 2025
From: kernel at airkyi.com (Chaoyi Chen)
Date: Thu,  4 Dec 2025 14:31:00 +0800
Subject: [RESEND PATCH v11 02/11] usb: typec: Export typec bus and typec altmode device type
In-Reply-To: <20251204063109.104-1-kernel@airkyi.com>
References: <20251204063109.104-1-kernel@airkyi.com>
Message-ID: <20251204063109.104-3-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

The DRM may want to register a notifier on the typec bus to know when
a typec altmode device is added, and distinguish between different
types of typec altmode device.

Export these things.

Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
---

Changes in v11:
- Also export typec bus.
- Add more detailed comments.

(no changes since v9)

 drivers/usb/typec/bus.c           |  1 +
 drivers/usb/typec/bus.h           | 10 ----------
 drivers/usb/typec/class.c         |  3 +++
 include/linux/usb/typec.h         |  3 +++
 include/linux/usb/typec_altmode.h |  8 ++++++++
 5 files changed, 15 insertions(+), 10 deletions(-)

diff --git a/drivers/usb/typec/bus.c b/drivers/usb/typec/bus.c
index a33da7f458a5..e84b134a3381 100644
--- a/drivers/usb/typec/bus.c
+++ b/drivers/usb/typec/bus.c
@@ -569,3 +569,4 @@ const struct bus_type typec_bus = {
 	.probe = typec_probe,
 	.remove = typec_remove,
 };
+EXPORT_SYMBOL_GPL(typec_bus);
diff --git a/drivers/usb/typec/bus.h b/drivers/usb/typec/bus.h
index b58e131450d1..7df5deb1dd3a 100644
--- a/drivers/usb/typec/bus.h
+++ b/drivers/usb/typec/bus.h
@@ -5,7 +5,6 @@
 
 #include <linux/usb/typec_altmode.h>
 
-struct bus_type;
 struct typec_mux;
 struct typec_retimer;
 
@@ -28,13 +27,4 @@ struct altmode {
 
 #define to_altmode(d) container_of(d, struct altmode, adev)
 
-extern const struct bus_type typec_bus;
-extern const struct device_type typec_port_altmode_dev_type;
-extern const struct device_type typec_plug_altmode_dev_type;
-extern const struct device_type typec_partner_altmode_dev_type;
-
-#define is_typec_port_altmode(dev) ((dev)->type == &typec_port_altmode_dev_type)
-#define is_typec_plug_altmode(dev) ((dev)->type == &typec_plug_altmode_dev_type)
-#define is_typec_partner_altmode(dev) ((dev)->type == &typec_partner_altmode_dev_type)
-
 #endif /* __USB_TYPEC_ALTMODE_H__ */
diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index d6b88317f8a4..c4ff4310ff58 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -537,18 +537,21 @@ const struct device_type typec_port_altmode_dev_type = {
 	.groups = typec_altmode_groups,
 	.release = typec_altmode_release,
 };
+EXPORT_SYMBOL_GPL(typec_port_altmode_dev_type);
 
 const struct device_type typec_plug_altmode_dev_type = {
 	.name = "typec_plug_alternate_mode",
 	.groups = typec_altmode_groups,
 	.release = typec_altmode_release,
 };
+EXPORT_SYMBOL_GPL(typec_plug_altmode_dev_type);
 
 const struct device_type typec_partner_altmode_dev_type = {
 	.name = "typec_partner_alternate_mode",
 	.groups = typec_altmode_groups,
 	.release = typec_altmode_release,
 };
+EXPORT_SYMBOL_GPL(typec_partner_altmode_dev_type);
 
 static struct typec_altmode *
 typec_register_altmode(struct device *parent,
diff --git a/include/linux/usb/typec.h b/include/linux/usb/typec.h
index 309251572e2e..c6fd46902fce 100644
--- a/include/linux/usb/typec.h
+++ b/include/linux/usb/typec.h
@@ -20,12 +20,15 @@ struct typec_port;
 struct typec_altmode_ops;
 struct typec_cable_ops;
 
+struct bus_type;
 struct fwnode_handle;
 struct device;
 
 struct usb_power_delivery;
 struct usb_power_delivery_desc;
 
+extern const struct bus_type typec_bus;
+
 enum typec_port_type {
 	TYPEC_PORT_SRC,
 	TYPEC_PORT_SNK,
diff --git a/include/linux/usb/typec_altmode.h b/include/linux/usb/typec_altmode.h
index f7db3bd4c90e..9197a4637a93 100644
--- a/include/linux/usb/typec_altmode.h
+++ b/include/linux/usb/typec_altmode.h
@@ -9,6 +9,14 @@
 
 #define MODE_DISCOVERY_MAX	6
 
+extern const struct device_type typec_port_altmode_dev_type;
+extern const struct device_type typec_plug_altmode_dev_type;
+extern const struct device_type typec_partner_altmode_dev_type;
+
+#define is_typec_port_altmode(dev) ((dev)->type == &typec_port_altmode_dev_type)
+#define is_typec_plug_altmode(dev) ((dev)->type == &typec_plug_altmode_dev_type)
+#define is_typec_partner_altmode(dev) ((dev)->type == &typec_partner_altmode_dev_type)
+
 struct typec_altmode_ops;
 
 /**
-- 
2.51.1



From kernel at airkyi.com  Wed Dec  3 22:31:04 2025
From: kernel at airkyi.com (Chaoyi Chen)
Date: Thu,  4 Dec 2025 14:31:04 +0800
Subject: [RESEND PATCH v11 06/11] phy: rockchip: phy-rockchip-typec: Add typec_mux/typec_switch support
In-Reply-To: <20251204063109.104-1-kernel@airkyi.com>
References: <20251204063109.104-1-kernel@airkyi.com>
Message-ID: <20251204063109.104-7-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

This patch add support for Type-C Port Controller Manager. Each PHY
will register typec_mux and typec_switch when external Type-C
controller is present. Type-C events are handled by TCPM without
extcon.

The extcon device should still be supported.

Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
---

(no changes since v7)

Changes in v6:
- Fix depend in Kconfig.
- Check DP svid in tcphy_typec_mux_set().
- Remove mode setting in tcphy_orien_sw_set().

(no changes since v5)

Changes in v4:
- Remove notify DP HPD state by USB/DP PHY.

(no changes since v3)

Changes in v2:
- Fix compile error when CONFIG_TYPEC is not enabled.
- Notify DP HPD state by USB/DP PHY.

 drivers/phy/rockchip/Kconfig              |   1 +
 drivers/phy/rockchip/phy-rockchip-typec.c | 368 +++++++++++++++++++++-
 2 files changed, 353 insertions(+), 16 deletions(-)

diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig
index 14698571b607..db4adc7c53da 100644
--- a/drivers/phy/rockchip/Kconfig
+++ b/drivers/phy/rockchip/Kconfig
@@ -119,6 +119,7 @@ config PHY_ROCKCHIP_SNPS_PCIE3
 config PHY_ROCKCHIP_TYPEC
 	tristate "Rockchip TYPEC PHY Driver"
 	depends on OF && (ARCH_ROCKCHIP || COMPILE_TEST)
+	depends on TYPEC || TYPEC=n
 	select EXTCON
 	select GENERIC_PHY
 	select RESET_CONTROLLER
diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c
index d9701b6106d5..1f5b4142cbe4 100644
--- a/drivers/phy/rockchip/phy-rockchip-typec.c
+++ b/drivers/phy/rockchip/phy-rockchip-typec.c
@@ -54,6 +54,8 @@
 
 #include <linux/mfd/syscon.h>
 #include <linux/phy/phy.h>
+#include <linux/usb/typec_dp.h>
+#include <linux/usb/typec_mux.h>
 
 #define CMN_SSM_BANDGAP			(0x21 << 2)
 #define CMN_SSM_BIAS			(0x22 << 2)
@@ -286,12 +288,23 @@
 #define RX_DIAG_SC2C_DELAY		(0x81e1 << 2)
 
 #define PMA_LANE_CFG			(0xc000 << 2)
+#define PMA_LANE3_DP_LANE_SEL(x)	(((x) & 0x3) << 14)
+#define PMA_LANE3_INTERFACE_SEL(x)	(((x) & 0x1) << 12)
+#define PMA_LANE2_DP_LANE_SEL(x)	(((x) & 0x3) << 10)
+#define PMA_LANE2_INTERFACE_SEL(x)	(((x) & 0x1) << 8)
+#define PMA_LANE1_DP_LANE_SEL(x)	(((x) & 0x3) << 6)
+#define PMA_LANE1_INTERFACE_SEL(x)	(((x) & 0x1) << 4)
+#define PMA_LANE0_DP_LANE_SEL(x)	(((x) & 0x3) << 2)
+#define PMA_LANE0_INTERFACE_SEL(x)	(((x) & 0x1) << 0)
 #define PIPE_CMN_CTRL1			(0xc001 << 2)
 #define PIPE_CMN_CTRL2			(0xc002 << 2)
 #define PIPE_COM_LOCK_CFG1		(0xc003 << 2)
 #define PIPE_COM_LOCK_CFG2		(0xc004 << 2)
 #define PIPE_RCV_DET_INH		(0xc005 << 2)
 #define DP_MODE_CTL			(0xc008 << 2)
+#define PHY_DP_POWER_STATE_ACK_MASK	GENMASK(7, 4)
+#define PHY_DP_POWER_STATE_ACK_SHIFT	4
+#define PHY_DP_POWER_STATE_MASK		GENMASK(3, 0)
 #define DP_CLK_CTL			(0xc009 << 2)
 #define STS				(0xc00F << 2)
 #define PHY_ISO_CMN_CTRL		(0xc010 << 2)
@@ -327,8 +340,15 @@
 
 #define DP_MODE_A0			BIT(4)
 #define DP_MODE_A2			BIT(6)
-#define DP_MODE_ENTER_A0		0xc101
-#define DP_MODE_ENTER_A2		0xc104
+
+#define DP_MODE_MASK			0xf
+#define DP_MODE_ENTER_A0		BIT(0)
+#define DP_MODE_ENTER_A2		BIT(2)
+#define DP_MODE_ENTER_A3		BIT(3)
+#define DP_MODE_A0_ACK			BIT(4)
+#define DP_MODE_A2_ACK			BIT(6)
+#define DP_MODE_A3_ACK			BIT(7)
+#define DP_LINK_RESET_DEASSERTED	BIT(8)
 
 #define PHY_MODE_SET_TIMEOUT		100000
 
@@ -340,6 +360,31 @@
 #define MODE_DFP_USB			BIT(1)
 #define MODE_DFP_DP			BIT(2)
 
+enum phy_dp_lane_num {
+	PHY_DP_LANE_0 = 0,
+	PHY_DP_LANE_1,
+	PHY_DP_LANE_2,
+	PHY_DP_LANE_3,
+};
+
+enum phy_pma_if {
+	PMA_IF_PIPE_PCS = 0,
+	PMA_IF_PHY_DP,
+};
+
+enum phy_typec_role {
+	TYPEC_PHY_USB = 0,
+	TYPEC_PHY_DP,
+	TYPEC_PHY_MAX,
+};
+
+enum phy_dp_power_state {
+	PHY_DP_POWER_STATE_A0 = 0,
+	PHY_DP_POWER_STATE_A1,
+	PHY_DP_POWER_STATE_A2,
+	PHY_DP_POWER_STATE_A3,
+};
+
 struct usb3phy_reg {
 	u32 offset;
 	u32 enable_bit;
@@ -372,18 +417,22 @@ struct rockchip_typec_phy {
 	struct device *dev;
 	void __iomem *base;
 	struct extcon_dev *extcon;
+	struct typec_mux_dev *mux;
+	struct typec_switch_dev *sw;
 	struct regmap *grf_regs;
 	struct clk *clk_core;
 	struct clk *clk_ref;
 	struct reset_control *uphy_rst;
 	struct reset_control *pipe_rst;
 	struct reset_control *tcphy_rst;
+	struct phy *phys[TYPEC_PHY_MAX];
 	const struct rockchip_usb3phy_port_cfg *port_cfgs;
 	/* mutex to protect access to individual PHYs */
 	struct mutex lock;
 
 	bool flip;
 	u8 mode;
+	u8 new_mode;
 };
 
 struct phy_reg {
@@ -454,6 +503,99 @@ static const struct rockchip_usb3phy_port_cfg rk3399_usb3phy_port_cfgs[] = {
 	{ /* sentinel */ }
 };
 
+static int tcphy_cfg_usb3_to_usb2_only(struct rockchip_typec_phy *tcphy,
+				       bool value);
+
+static int tcphy_dp_set_power_state(struct rockchip_typec_phy *tcphy,
+				    enum phy_dp_power_state state)
+{
+	u32 ack, reg, sts = BIT(state);
+	int ret;
+
+	/*
+	 * Power state changes must not be requested until after the cmn_ready
+	 * signal has gone active.
+	 */
+	reg = readl(tcphy->base + PMA_CMN_CTRL1);
+	if (!(reg & CMN_READY)) {
+		dev_err(tcphy->dev, "cmn_ready in the inactive state\n");
+		return -EINVAL;
+	}
+
+	reg = readl(tcphy->base + DP_MODE_CTL);
+	reg &= ~PHY_DP_POWER_STATE_MASK;
+	reg |= sts;
+	writel(reg, tcphy->base + DP_MODE_CTL);
+
+	ret = readl_poll_timeout(tcphy->base + DP_MODE_CTL,
+				 ack, (((ack & PHY_DP_POWER_STATE_ACK_MASK) >>
+				 PHY_DP_POWER_STATE_ACK_SHIFT) == sts), 10,
+				 PHY_MODE_SET_TIMEOUT);
+	if (ret < 0) {
+		dev_err(tcphy->dev, "failed to enter power state %d\n", state);
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+ * For the TypeC PHY, the 4 lanes are mapping to the USB TypeC receptacle pins
+ * as follows:
+ *   -------------------------------------------------------------------
+ *	PHY Lanes/Module Pins			TypeC Receptacle Pins
+ *   -------------------------------------------------------------------
+ *	Lane0 (tx_p/m_ln_0)			TX1+/TX1- (pins A2/A3)
+ *	Lane1 (tx_rx_p/m_ln_1)			RX1+/RX1- (pins B11/B10)
+ *	Lane2 (tx_rx_p/m_ln_2)			RX2+/RX2- (pins A11/A10)
+ *	Lane3 (tx_p/m_ln_3)			TX2+/TX2- (pins B2/B3)
+ *   -------------------------------------------------------------------
+ *
+ * USB and DP lanes mapping to TypeC PHY lanes for each of pin assignment
+ * options (normal connector orientation) described in the VESA DisplayPort
+ * Alt Mode on USB TypeC Standard as follows:
+ *
+ * ----------------------------------------------------------------------
+ *	PHY Lanes	A	B	C	D	E	F
+ * ----------------------------------------------------------------------
+ *	  0	       ML1     SSTX    ML2     SSTX    ML2     SSTX
+ *	  1	       ML3     SSRX    ML3     SSRX    ML3     SSRX
+ *	  2	       ML2     ML1     ML0     ML0     ML0     ML0
+ *	  3	       ML0     ML0     ML1     ML1     ML1     ML1
+ * ----------------------------------------------------------------------
+ */
+static void tcphy_set_lane_mapping(struct rockchip_typec_phy *tcphy, u8 mode)
+{
+	/*
+	 * The PMA_LANE_CFG register is used to select whether a PMA lane
+	 * is mapped for USB or PHY DP. The PMA_LANE_CFG register is
+	 * configured based on a normal connector orientation. Logic in the
+	 * PHY automatically handles the flipped connector case based on the
+	 * setting of orientation of TypeC PHY.
+	 */
+	if (mode == MODE_DFP_DP) {
+		/* This maps to VESA DP Alt Mode pin assignments C and E. */
+		writel(PMA_LANE3_DP_LANE_SEL(PHY_DP_LANE_1) |
+		       PMA_LANE3_INTERFACE_SEL(PMA_IF_PHY_DP) |
+		       PMA_LANE2_DP_LANE_SEL(PHY_DP_LANE_0) |
+		       PMA_LANE2_INTERFACE_SEL(PMA_IF_PHY_DP) |
+		       PMA_LANE1_DP_LANE_SEL(PHY_DP_LANE_3) |
+		       PMA_LANE1_INTERFACE_SEL(PMA_IF_PHY_DP) |
+		       PMA_LANE0_DP_LANE_SEL(PHY_DP_LANE_2) |
+		       PMA_LANE0_INTERFACE_SEL(PMA_IF_PHY_DP),
+		       tcphy->base + PMA_LANE_CFG);
+	} else {
+		/* This maps to VESA DP Alt Mode pin assignments D and F. */
+		writel(PMA_LANE3_DP_LANE_SEL(PHY_DP_LANE_1) |
+		       PMA_LANE3_INTERFACE_SEL(PMA_IF_PHY_DP) |
+		       PMA_LANE2_DP_LANE_SEL(PHY_DP_LANE_0) |
+		       PMA_LANE2_INTERFACE_SEL(PMA_IF_PHY_DP) |
+		       PMA_LANE1_INTERFACE_SEL(PMA_IF_PIPE_PCS) |
+		       PMA_LANE0_INTERFACE_SEL(PMA_IF_PIPE_PCS),
+		       tcphy->base + PMA_LANE_CFG);
+	}
+}
+
 static void tcphy_cfg_24m(struct rockchip_typec_phy *tcphy)
 {
 	u32 i, rdata;
@@ -743,8 +885,10 @@ static int tcphy_phy_init(struct rockchip_typec_phy *tcphy, u8 mode)
 	tcphy_dp_aux_set_flip(tcphy);
 
 	tcphy_cfg_24m(tcphy);
+	tcphy_set_lane_mapping(tcphy, mode);
 
 	if (mode == MODE_DFP_DP) {
+		tcphy_cfg_usb3_to_usb2_only(tcphy, true);
 		tcphy_cfg_dp_pll(tcphy);
 		for (i = 0; i < 4; i++)
 			tcphy_dp_cfg_lane(tcphy, i);
@@ -768,7 +912,10 @@ static int tcphy_phy_init(struct rockchip_typec_phy *tcphy, u8 mode)
 		writel(PIN_ASSIGN_D_F, tcphy->base + PMA_LANE_CFG);
 	}
 
-	writel(DP_MODE_ENTER_A2, tcphy->base + DP_MODE_CTL);
+	val = readl(tcphy->base + DP_MODE_CTL);
+	val &= ~DP_MODE_MASK;
+	val |= DP_MODE_ENTER_A2 | DP_LINK_RESET_DEASSERTED;
+	writel(val, tcphy->base + DP_MODE_CTL);
 
 	reset_control_deassert(tcphy->uphy_rst);
 
@@ -811,8 +958,9 @@ static int tcphy_get_mode(struct rockchip_typec_phy *tcphy)
 	u8 mode;
 	int ret, ufp, dp;
 
+	/* If extcon not exist, try to use tcpm mode */
 	if (!edev)
-		return MODE_DFP_USB;
+		return tcphy->new_mode;
 
 	ufp = extcon_get_state(edev, EXTCON_USB);
 	dp = extcon_get_state(edev, EXTCON_DISP_DP);
@@ -850,6 +998,71 @@ static int tcphy_get_mode(struct rockchip_typec_phy *tcphy)
 	return mode;
 }
 
+#if IS_ENABLED(CONFIG_TYPEC)
+static int tcphy_orien_sw_set(struct typec_switch_dev *sw,
+			      enum typec_orientation orien)
+{
+	struct rockchip_typec_phy *tcphy = typec_switch_get_drvdata(sw);
+
+	mutex_lock(&tcphy->lock);
+
+	if (orien == TYPEC_ORIENTATION_NONE) {
+		tcphy->new_mode = MODE_DISCONNECT;
+		goto unlock_ret;
+	}
+
+	tcphy->flip = (orien == TYPEC_ORIENTATION_REVERSE) ? true : false;
+
+unlock_ret:
+	mutex_unlock(&tcphy->lock);
+	return 0;
+}
+
+static void udphy_orien_switch_unregister(void *data)
+{
+	struct rockchip_typec_phy *tcphy = data;
+
+	typec_switch_unregister(tcphy->sw);
+}
+
+static int tcphy_setup_orien_switch(struct rockchip_typec_phy *tcphy)
+{
+	struct typec_switch_desc sw_desc = { };
+	struct device_node *np;
+	int ret = 0;
+
+	np = of_get_child_by_name(tcphy->dev->of_node, "usb3-port");
+	if (!np)
+		return 0;
+
+	if (!of_property_read_bool(np, "orientation-switch"))
+		goto put_np;
+
+	sw_desc.drvdata = tcphy;
+	sw_desc.fwnode = device_get_named_child_node(tcphy->dev, "usb3-port");
+	sw_desc.set = tcphy_orien_sw_set;
+
+	tcphy->sw = typec_switch_register(tcphy->dev, &sw_desc);
+	if (IS_ERR(tcphy->sw)) {
+		dev_err(tcphy->dev, "Error register typec orientation switch: %ld\n",
+			PTR_ERR(tcphy->sw));
+		ret = PTR_ERR(tcphy->sw);
+		goto put_np;
+	}
+
+	ret = devm_add_action_or_reset(tcphy->dev, udphy_orien_switch_unregister, tcphy);
+
+put_np:
+	of_node_put(np);
+	return ret;
+}
+#else
+static int tcphy_setup_orien_switch(struct rockchip_typec_phy *tcphy)
+{
+	return 0;
+}
+#endif
+
 static int tcphy_cfg_usb3_to_usb2_only(struct rockchip_typec_phy *tcphy,
 				       bool value)
 {
@@ -989,14 +1202,9 @@ static int rockchip_dp_phy_power_on(struct phy *phy)
 
 	tcphy_dp_aux_calibration(tcphy);
 
-	writel(DP_MODE_ENTER_A0, tcphy->base + DP_MODE_CTL);
-
-	ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL,
-				 val, val & DP_MODE_A0, 1000,
-				 PHY_MODE_SET_TIMEOUT);
-	if (ret < 0) {
-		writel(DP_MODE_ENTER_A2, tcphy->base + DP_MODE_CTL);
-		dev_err(tcphy->dev, "failed to wait TCPHY enter A0\n");
+	ret = tcphy_dp_set_power_state(tcphy, PHY_DP_POWER_STATE_A0);
+	if (ret) {
+		dev_err(tcphy->dev, "failed to enter A0 power state\n");
 		goto power_on_finish;
 	}
 
@@ -1013,6 +1221,7 @@ static int rockchip_dp_phy_power_on(struct phy *phy)
 static int rockchip_dp_phy_power_off(struct phy *phy)
 {
 	struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy);
+	int ret;
 
 	mutex_lock(&tcphy->lock);
 
@@ -1021,7 +1230,11 @@ static int rockchip_dp_phy_power_off(struct phy *phy)
 
 	tcphy->mode &= ~MODE_DFP_DP;
 
-	writel(DP_MODE_ENTER_A2, tcphy->base + DP_MODE_CTL);
+	ret = tcphy_dp_set_power_state(tcphy, PHY_DP_POWER_STATE_A2);
+	if (ret) {
+		dev_err(tcphy->dev, "failed to enter A2 power state\n");
+		goto unlock;
+	}
 
 	if (tcphy->mode == MODE_DISCONNECT)
 		tcphy_phy_deinit(tcphy);
@@ -1037,6 +1250,93 @@ static const struct phy_ops rockchip_dp_phy_ops = {
 	.owner		= THIS_MODULE,
 };
 
+#if IS_ENABLED(CONFIG_TYPEC)
+static int tcphy_typec_mux_set(struct typec_mux_dev *mux, struct typec_mux_state *state)
+{
+	struct rockchip_typec_phy *tcphy = typec_mux_get_drvdata(mux);
+	struct typec_displayport_data *data;
+	int hpd = 0;
+
+	mutex_lock(&tcphy->lock);
+
+	switch (state->mode) {
+	case TYPEC_STATE_SAFE:
+		fallthrough;
+	case TYPEC_STATE_USB:
+		tcphy->new_mode = MODE_DFP_USB;
+		phy_set_bus_width(tcphy->phys[TYPEC_PHY_DP], 0);
+		break;
+	case TYPEC_DP_STATE_C:
+	case TYPEC_DP_STATE_E:
+		if (state->alt->svid != USB_TYPEC_DP_SID)
+			break;
+		tcphy->new_mode = MODE_DFP_DP;
+		data = state->data;
+		hpd = !!(data->status & DP_STATUS_HPD_STATE);
+		phy_set_bus_width(tcphy->phys[TYPEC_PHY_DP], hpd ? 4 : 0);
+		break;
+	case TYPEC_DP_STATE_D:
+		if (state->alt->svid != USB_TYPEC_DP_SID)
+			break;
+		tcphy->new_mode = MODE_DFP_DP | MODE_DFP_USB;
+		data = state->data;
+		hpd = !!(data->status & DP_STATUS_HPD_STATE);
+		phy_set_bus_width(tcphy->phys[TYPEC_PHY_DP], hpd ? 2 : 0);
+		break;
+	default:
+		break;
+	}
+
+	mutex_unlock(&tcphy->lock);
+
+	return 0;
+}
+
+static void tcphy_typec_mux_unregister(void *data)
+{
+	struct rockchip_typec_phy *tcphy = data;
+
+	typec_mux_unregister(tcphy->mux);
+}
+
+static int tcphy_setup_typec_mux(struct rockchip_typec_phy *tcphy)
+{
+	struct typec_mux_desc mux_desc = {};
+	struct device_node *np;
+	int ret = 0;
+
+	np = of_get_child_by_name(tcphy->dev->of_node, "dp-port");
+	if (!np)
+		return 0;
+
+	if (!of_property_read_bool(np, "mode-switch"))
+		goto put_np;
+
+	mux_desc.drvdata = tcphy;
+	mux_desc.fwnode = device_get_named_child_node(tcphy->dev, "dp-port");
+	mux_desc.set = tcphy_typec_mux_set;
+
+	tcphy->mux = typec_mux_register(tcphy->dev, &mux_desc);
+	if (IS_ERR(tcphy->mux)) {
+		dev_err(tcphy->dev, "Error register typec mux: %ld\n",
+			PTR_ERR(tcphy->mux));
+		ret = PTR_ERR(tcphy->mux);
+		goto put_np;
+	}
+
+	ret = devm_add_action_or_reset(tcphy->dev, tcphy_typec_mux_unregister, tcphy);
+
+put_np:
+	of_node_put(np);
+	return ret;
+}
+#else
+static int tcphy_setup_typec_mux(struct rockchip_typec_phy *tcphy)
+{
+	return 0;
+}
+#endif
+
 static int tcphy_parse_dt(struct rockchip_typec_phy *tcphy,
 			  struct device *dev)
 {
@@ -1095,6 +1395,25 @@ static void typec_phy_pre_init(struct rockchip_typec_phy *tcphy)
 	tcphy->mode = MODE_DISCONNECT;
 }
 
+static int typec_dp_lane_get(struct rockchip_typec_phy *tcphy)
+{
+	int dp_lanes;
+
+	switch (tcphy->new_mode) {
+	case MODE_DFP_DP:
+		dp_lanes = 4;
+		break;
+	case MODE_DFP_DP | MODE_DFP_USB:
+		dp_lanes = 2;
+		break;
+	default:
+		dp_lanes = 0;
+		break;
+	}
+
+	return dp_lanes;
+}
+
 static int rockchip_typec_phy_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -1142,6 +1461,7 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev)
 		return ret;
 
 	tcphy->dev = dev;
+	tcphy->new_mode = MODE_DFP_USB;
 	platform_set_drvdata(pdev, tcphy);
 	mutex_init(&tcphy->lock);
 
@@ -1151,6 +1471,7 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev)
 	if (IS_ERR(tcphy->extcon)) {
 		if (PTR_ERR(tcphy->extcon) == -ENODEV) {
 			tcphy->extcon = NULL;
+			dev_info(dev, "extcon not exist, try to use typec mux\n");
 		} else {
 			if (PTR_ERR(tcphy->extcon) != -EPROBE_DEFER)
 				dev_err(dev, "Invalid or missing extcon\n");
@@ -1158,19 +1479,34 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev)
 		}
 	}
 
+	ret = tcphy_setup_orien_switch(tcphy);
+	if (ret)
+		return ret;
+
+	ret = tcphy_setup_typec_mux(tcphy);
+	if (ret)
+		return ret;
+
 	pm_runtime_enable(dev);
 
 	for_each_available_child_of_node(np, child_np) {
 		struct phy *phy;
 
-		if (of_node_name_eq(child_np, "dp-port"))
+		if (of_node_name_eq(child_np, "dp-port")) {
 			phy = devm_phy_create(dev, child_np,
 					      &rockchip_dp_phy_ops);
-		else if (of_node_name_eq(child_np, "usb3-port"))
+			if (!IS_ERR(phy)) {
+				tcphy->phys[TYPEC_PHY_DP] = phy;
+				phy_set_bus_width(phy, typec_dp_lane_get(tcphy));
+			}
+		} else if (of_node_name_eq(child_np, "usb3-port")) {
 			phy = devm_phy_create(dev, child_np,
 					      &rockchip_usb3_phy_ops);
-		else
+			if (!IS_ERR(phy))
+				tcphy->phys[TYPEC_PHY_USB] = phy;
+		} else {
 			continue;
+		}
 
 		if (IS_ERR(phy)) {
 			dev_err(dev, "failed to create phy: %pOFn\n",
-- 
2.51.1



From kernel at airkyi.com  Wed Dec  3 22:31:02 2025
From: kernel at airkyi.com (Chaoyi Chen)
Date: Thu,  4 Dec 2025 14:31:02 +0800
Subject: [RESEND PATCH v11 04/11] drm/bridge: aux: Add drm_aux_bridge_register_from_node()
In-Reply-To: <20251204063109.104-1-kernel@airkyi.com>
References: <20251204063109.104-1-kernel@airkyi.com>
Message-ID: <20251204063109.104-5-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

The drm_aux_bridge_register() uses the device->of_node as the
bridge->of_node.

This patch adds drm_aux_bridge_register_from_node() to allow
specifying the of_node corresponding to the bridge.

Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
Reviewed-by: Neil Armstrong <neil.armstrong at linaro.org>
---

(no changes since v11)

 drivers/gpu/drm/bridge/aux-bridge.c | 24 ++++++++++++++++++++++--
 include/drm/bridge/aux-bridge.h     |  6 ++++++
 2 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/bridge/aux-bridge.c b/drivers/gpu/drm/bridge/aux-bridge.c
index b3e4cdff61d6..52dff4601c2d 100644
--- a/drivers/gpu/drm/bridge/aux-bridge.c
+++ b/drivers/gpu/drm/bridge/aux-bridge.c
@@ -35,6 +35,7 @@ static void drm_aux_bridge_unregister_adev(void *_adev)
 /**
  * drm_aux_bridge_register - Create a simple bridge device to link the chain
  * @parent: device instance providing this bridge
+ * @np: device node pointer corresponding to this bridge instance
  *
  * Creates a simple DRM bridge that doesn't implement any drm_bridge
  * operations. Such bridges merely fill a place in the bridge chain linking
@@ -42,7 +43,7 @@ static void drm_aux_bridge_unregister_adev(void *_adev)
  *
  * Return: zero on success, negative error code on failure
  */
-int drm_aux_bridge_register(struct device *parent)
+int drm_aux_bridge_register_from_node(struct device *parent, struct device_node *np)
 {
 	struct auxiliary_device *adev;
 	int ret;
@@ -62,7 +63,10 @@ int drm_aux_bridge_register(struct device *parent)
 	adev->dev.parent = parent;
 	adev->dev.release = drm_aux_bridge_release;
 
-	device_set_of_node_from_dev(&adev->dev, parent);
+	if (np)
+		device_set_node(&adev->dev, of_fwnode_handle(np));
+	else
+		device_set_of_node_from_dev(&adev->dev, parent);
 
 	ret = auxiliary_device_init(adev);
 	if (ret) {
@@ -80,6 +84,22 @@ int drm_aux_bridge_register(struct device *parent)
 
 	return devm_add_action_or_reset(parent, drm_aux_bridge_unregister_adev, adev);
 }
+EXPORT_SYMBOL_GPL(drm_aux_bridge_register_from_node);
+
+/**
+ * drm_aux_bridge_register - Create a simple bridge device to link the chain
+ * @parent: device instance providing this bridge
+ *
+ * Creates a simple DRM bridge that doesn't implement any drm_bridge
+ * operations. Such bridges merely fill a place in the bridge chain linking
+ * surrounding DRM bridges.
+ *
+ * Return: zero on success, negative error code on failure
+ */
+int drm_aux_bridge_register(struct device *parent)
+{
+	return drm_aux_bridge_register_from_node(parent, NULL);
+}
 EXPORT_SYMBOL_GPL(drm_aux_bridge_register);
 
 struct drm_aux_bridge_data {
diff --git a/include/drm/bridge/aux-bridge.h b/include/drm/bridge/aux-bridge.h
index c2f5a855512f..7dd1f17a1354 100644
--- a/include/drm/bridge/aux-bridge.h
+++ b/include/drm/bridge/aux-bridge.h
@@ -13,11 +13,17 @@ struct auxiliary_device;
 
 #if IS_ENABLED(CONFIG_DRM_AUX_BRIDGE)
 int drm_aux_bridge_register(struct device *parent);
+int drm_aux_bridge_register_from_node(struct device *parent, struct device_node *np);
 #else
 static inline int drm_aux_bridge_register(struct device *parent)
 {
 	return 0;
 }
+
+static inline int drm_aux_bridge_register_from_node(struct device *parent, struct device_node *np)
+{
+	return 0;
+}
 #endif
 
 #if IS_ENABLED(CONFIG_DRM_AUX_HPD_BRIDGE)
-- 
2.51.1



From kernel at airkyi.com  Wed Dec  3 22:31:06 2025
From: kernel at airkyi.com (Chaoyi Chen)
Date: Thu,  4 Dec 2025 14:31:06 +0800
Subject: [RESEND PATCH v11 08/11] drm/rockchip: cdn-dp: Support handle lane info without extcon
In-Reply-To: <20251204063109.104-1-kernel@airkyi.com>
References: <20251204063109.104-1-kernel@airkyi.com>
Message-ID: <20251204063109.104-9-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

This patch add support for get PHY lane info without help of extcon.

There is no extcon needed if the Type-C controller is present. In this
case, the lane info can be get from PHY instead of extcon.

The extcon device should still be supported if Type-C controller is
not present.

Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
---

(no changes since v5)

Changes in v4:
- Remove cdn_dp_hpd_notify().

(no changes since v3)

Changes in v2:
- Ignore duplicate HPD events.

 drivers/gpu/drm/rockchip/cdn-dp-core.c | 25 +++++++++++++++++--------
 1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
index b7e3f5dcf8d5..1e27301584a4 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
@@ -156,6 +156,9 @@ static int cdn_dp_get_port_lanes(struct cdn_dp_port *port)
 	int dptx;
 	u8 lanes;
 
+	if (!edev)
+		return phy_get_bus_width(port->phy);
+
 	dptx = extcon_get_state(edev, EXTCON_DISP_DP);
 	if (dptx > 0) {
 		extcon_get_property(edev, EXTCON_DISP_DP,
@@ -219,7 +222,7 @@ static bool cdn_dp_check_sink_connection(struct cdn_dp_device *dp)
 	 * some docks need more time to power up.
 	 */
 	while (time_before(jiffies, timeout)) {
-		if (!extcon_get_state(port->extcon, EXTCON_DISP_DP))
+		if (port->extcon && !extcon_get_state(port->extcon, EXTCON_DISP_DP))
 			return false;
 
 		if (!cdn_dp_get_sink_count(dp, &sink_count))
@@ -385,11 +388,14 @@ static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port)
 		goto err_power_on;
 	}
 
-	ret = extcon_get_property(port->extcon, EXTCON_DISP_DP,
-				  EXTCON_PROP_USB_TYPEC_POLARITY, &property);
-	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "get property failed\n");
-		goto err_power_on;
+	property.intval = 0;
+	if (port->extcon) {
+		ret = extcon_get_property(port->extcon, EXTCON_DISP_DP,
+					  EXTCON_PROP_USB_TYPEC_POLARITY, &property);
+		if (ret) {
+			DRM_DEV_ERROR(dp->dev, "get property failed\n");
+			goto err_power_on;
+		}
 	}
 
 	port->lanes = cdn_dp_get_port_lanes(port);
@@ -1028,6 +1034,9 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
 	for (i = 0; i < dp->ports; i++) {
 		port = dp->port[i];
 
+		if (!port->extcon)
+			continue;
+
 		port->event_nb.notifier_call = cdn_dp_pd_event;
 		ret = devm_extcon_register_notifier(dp->dev, port->extcon,
 						    EXTCON_DISP_DP,
@@ -1120,14 +1129,14 @@ static int cdn_dp_probe(struct platform_device *pdev)
 		    PTR_ERR(phy) == -EPROBE_DEFER)
 			return -EPROBE_DEFER;
 
-		if (IS_ERR(extcon) || IS_ERR(phy))
+		if (IS_ERR(phy) || PTR_ERR(extcon) != -ENODEV)
 			continue;
 
 		port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
 		if (!port)
 			return -ENOMEM;
 
-		port->extcon = extcon;
+		port->extcon = IS_ERR(extcon) ? NULL : extcon;
 		port->phy = phy;
 		port->dp = dp;
 		port->id = i;
-- 
2.51.1



From kernel at airkyi.com  Wed Dec  3 22:31:05 2025
From: kernel at airkyi.com (Chaoyi Chen)
Date: Thu,  4 Dec 2025 14:31:05 +0800
Subject: [RESEND PATCH v11 07/11] phy: rockchip: phy-rockchip-typec: Add DRM AUX bridge
In-Reply-To: <20251204063109.104-1-kernel@airkyi.com>
References: <20251204063109.104-1-kernel@airkyi.com>
Message-ID: <20251204063109.104-8-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

Using the DRM_AUX_BRIDGE helper to create the transparent DRM bridge
device.

Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
Reviewed-by: Neil Armstrong <neil.armstrong at linaro.org>
---

(no changes since v11)

Changes in v10:
- Use drm_aux_bridge_register_from_node() instead.

(no changes since v7)

Changes in v6:
- Fix depend in Kconfig.

 drivers/phy/rockchip/Kconfig              | 2 ++
 drivers/phy/rockchip/phy-rockchip-typec.c | 5 +++++
 2 files changed, 7 insertions(+)

diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig
index db4adc7c53da..bcb5476222fc 100644
--- a/drivers/phy/rockchip/Kconfig
+++ b/drivers/phy/rockchip/Kconfig
@@ -120,6 +120,8 @@ config PHY_ROCKCHIP_TYPEC
 	tristate "Rockchip TYPEC PHY Driver"
 	depends on OF && (ARCH_ROCKCHIP || COMPILE_TEST)
 	depends on TYPEC || TYPEC=n
+	depends on DRM || DRM=n
+	select DRM_AUX_BRIDGE if DRM_BRIDGE
 	select EXTCON
 	select GENERIC_PHY
 	select RESET_CONTROLLER
diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c
index 1f5b4142cbe4..e31b778c3537 100644
--- a/drivers/phy/rockchip/phy-rockchip-typec.c
+++ b/drivers/phy/rockchip/phy-rockchip-typec.c
@@ -56,6 +56,7 @@
 #include <linux/phy/phy.h>
 #include <linux/usb/typec_dp.h>
 #include <linux/usb/typec_mux.h>
+#include <drm/bridge/aux-bridge.h>
 
 #define CMN_SSM_BANDGAP			(0x21 << 2)
 #define CMN_SSM_BIAS			(0x22 << 2)
@@ -1312,6 +1313,10 @@ static int tcphy_setup_typec_mux(struct rockchip_typec_phy *tcphy)
 	if (!of_property_read_bool(np, "mode-switch"))
 		goto put_np;
 
+	ret = drm_aux_bridge_register_from_node(tcphy->dev, np);
+	if (ret)
+		goto put_np;
+
 	mux_desc.drvdata = tcphy;
 	mux_desc.fwnode = device_get_named_child_node(tcphy->dev, "dp-port");
 	mux_desc.set = tcphy_typec_mux_set;
-- 
2.51.1



From kernel at airkyi.com  Wed Dec  3 22:31:07 2025
From: kernel at airkyi.com (Chaoyi Chen)
Date: Thu,  4 Dec 2025 14:31:07 +0800
Subject: [RESEND PATCH v11 09/11] drm/rockchip: cdn-dp: Add multiple bridges to support PHY port selection
In-Reply-To: <20251204063109.104-1-kernel@airkyi.com>
References: <20251204063109.104-1-kernel@airkyi.com>
Message-ID: <20251204063109.104-10-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

The RK3399 has two USB/DP combo PHY and one CDN-DP controller. And
the CDN-DP can be switched to output to one of the PHYs. If both ports
are plugged into DP, DP will select the first port for output.

This patch adds support for multiple bridges, enabling users to flexibly
select the output port. For each PHY port, a separate encoder and bridge
are registered.

The change is based on the DRM AUX HPD bridge, rather than the
extcon approach. This requires the DT to correctly describe the
connections between the first bridge in bridge chain and DP
controller. For example, the bridge chain may be like this:

PHY aux birdge -> fsa4480 analog audio switch bridge ->
onnn,nb7vpq904m USB reminder bridge -> USB-C controller AUX HPD bridge

In this case, the connection relationships among the PHY aux bridge
and the DP contorller need to be described in DT.

In addition, the cdn_dp_parse_next_bridge_dt() will parses it and
determines whether to register one or two bridges.

Since there is only one DP controller, only one of the PHY ports can
output at a time. The key is how to switch between different PHYs,
which is handled by cdn_dp_switch_port() and cdn_dp_enable().

There are two cases:

1. Neither bridge is enabled. In this case, both bridges can
independently read the EDID, and the PHY port may switch before
reading the EDID.

2. One bridge is already enabled. In this case, other bridges are not
allowed to read the EDID. So we will try to return the cached EDID.

Since the scenario of two ports plug in at the same time is rare,
I don't have a board which support two TypeC connector to test this.
Therefore, I tested forced switching on a single PHY port, as well as
output using a fake PHY port alongside a real PHY port.

Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
---

(no changes since v11)

Changes in v10:
- Fix refcount usage of drm_bridge.
- Remove unused cdn_dp_next_bridge type.

Changes in v9:
- Select DRM_AUX_HPD_BRIDGE when using DP driver.

(no changes since v7)

Changes in v6:
- Rename some variable names.
- Attach the DP bridge to the next bridge.

Changes in v5:
- By parsing the HPD bridge chain, set the connector's of_node to the
of_node corresponding to the USB-C connector.
- Return EDID cache when other port is already enabled.

 drivers/gpu/drm/rockchip/Kconfig       |   1 +
 drivers/gpu/drm/rockchip/cdn-dp-core.c | 325 ++++++++++++++++++++-----
 drivers/gpu/drm/rockchip/cdn-dp-core.h |  18 +-
 3 files changed, 287 insertions(+), 57 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index b7b025814e72..10d9f29a3d44 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -56,6 +56,7 @@ config ROCKCHIP_CDN_DP
 	select DRM_DISPLAY_HELPER
 	select DRM_BRIDGE_CONNECTOR
 	select DRM_DISPLAY_DP_HELPER
+	select DRM_AUX_HPD_BRIDGE
 	help
 	  This selects support for Rockchip SoC specific extensions
 	  for the cdn DP driver. If you want to enable Dp on
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
index 1e27301584a4..0bc3d248c266 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
@@ -27,16 +27,17 @@
 #include "cdn-dp-core.h"
 #include "cdn-dp-reg.h"
 
-static inline struct cdn_dp_device *bridge_to_dp(struct drm_bridge *bridge)
+static int cdn_dp_switch_port(struct cdn_dp_device *dp, struct cdn_dp_port *prev_port,
+			      struct cdn_dp_port *port);
+
+static inline struct cdn_dp_bridge *bridge_to_dp_bridge(struct drm_bridge *bridge)
 {
-	return container_of(bridge, struct cdn_dp_device, bridge);
+	return container_of(bridge, struct cdn_dp_bridge, bridge);
 }
 
-static inline struct cdn_dp_device *encoder_to_dp(struct drm_encoder *encoder)
+static inline struct cdn_dp_device *bridge_to_dp(struct drm_bridge *bridge)
 {
-	struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
-
-	return container_of(rkencoder, struct cdn_dp_device, encoder);
+	return bridge_to_dp_bridge(bridge)->parent;
 }
 
 #define GRF_SOC_CON9		0x6224
@@ -191,14 +192,27 @@ static int cdn_dp_get_sink_count(struct cdn_dp_device *dp, u8 *sink_count)
 static struct cdn_dp_port *cdn_dp_connected_port(struct cdn_dp_device *dp)
 {
 	struct cdn_dp_port *port;
-	int i, lanes;
+	int i, lanes[MAX_PHY];
 
 	for (i = 0; i < dp->ports; i++) {
 		port = dp->port[i];
-		lanes = cdn_dp_get_port_lanes(port);
-		if (lanes)
+		lanes[i] = cdn_dp_get_port_lanes(port);
+		if (!dp->next_bridge_valid)
 			return port;
 	}
+
+	if (dp->next_bridge_valid) {
+		/* If more than one port is available, pick the last active port */
+		if (dp->active_port > 0 && lanes[dp->active_port])
+			return dp->port[dp->active_port];
+
+		/* If the last active port is not available, pick an available port in order */
+		for (i = 0; i < dp->bridge_count; i++) {
+			if (lanes[i])
+				return dp->port[i];
+		}
+	}
+
 	return NULL;
 }
 
@@ -253,12 +267,45 @@ static const struct drm_edid *
 cdn_dp_bridge_edid_read(struct drm_bridge *bridge, struct drm_connector *connector)
 {
 	struct cdn_dp_device *dp = bridge_to_dp(bridge);
-	const struct drm_edid *drm_edid;
+	struct cdn_dp_bridge *dp_bridge = bridge_to_dp_bridge(bridge);
+	struct cdn_dp_port *port = dp->port[dp_bridge->id];
+	struct cdn_dp_port *prev_port;
+	const struct drm_edid *drm_edid = NULL;
+	int i, ret;
 
 	mutex_lock(&dp->lock);
+
+	/* More than one port is available */
+	if (dp->bridge_count > 1 && !port->phy_enabled) {
+		for (i = 0; i < dp->bridge_count; i++) {
+			/* Another port already enable */
+			if (dp->bridge_list[i] != dp_bridge && dp->bridge_list[i]->enabled)
+				goto get_cache;
+			/* Find already enabled port */
+			if (dp->port[i]->phy_enabled)
+				prev_port = dp->port[i];
+		}
+
+		/* Switch to current port */
+		if (prev_port) {
+			ret = cdn_dp_switch_port(dp, prev_port, port);
+			if (ret)
+				goto get_cache;
+		}
+	}
+
 	drm_edid = drm_edid_read_custom(connector, cdn_dp_get_edid_block, dp);
+	/* replace edid cache */
+	if (dp->edid_cache[dp_bridge->id])
+		drm_edid_free(dp->edid_cache[dp_bridge->id]);
+	dp->edid_cache[dp_bridge->id] = drm_edid_dup(drm_edid);
+
 	mutex_unlock(&dp->lock);
+	return drm_edid;
 
+get_cache:
+	drm_edid = drm_edid_dup(dp->edid_cache[dp_bridge->id]);
+	mutex_unlock(&dp->lock);
 	return drm_edid;
 }
 
@@ -267,12 +314,13 @@ cdn_dp_bridge_mode_valid(struct drm_bridge *bridge,
 			 const struct drm_display_info *display_info,
 			 const struct drm_display_mode *mode)
 {
+	struct cdn_dp_bridge *dp_bridge = bridge_to_dp_bridge(bridge);
 	struct cdn_dp_device *dp = bridge_to_dp(bridge);
 	u32 requested, actual, rate, sink_max, source_max = 0;
 	u8 lanes, bpc;
 
 	/* If DP is disconnected, every mode is invalid */
-	if (!dp->connected)
+	if (!dp_bridge->connected || !dp->connected)
 		return MODE_BAD;
 
 	switch (display_info->bpc) {
@@ -550,6 +598,54 @@ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp)
 	return drm_dp_channel_eq_ok(link_status, min(port->lanes, sink_lanes));
 }
 
+static int cdn_dp_switch_port(struct cdn_dp_device *dp, struct cdn_dp_port *prev_port,
+			      struct cdn_dp_port *port)
+{
+	int ret;
+
+	if (dp->active)
+		return 0;
+
+	ret = cdn_dp_disable_phy(dp, prev_port);
+	if (ret)
+		goto out;
+	ret = cdn_dp_enable_phy(dp, port);
+	if (ret)
+		goto out;
+
+	ret = cdn_dp_get_sink_capability(dp);
+	if (ret) {
+		cdn_dp_disable_phy(dp, port);
+		goto out;
+	}
+
+	dp->active = true;
+	dp->lanes = port->lanes;
+
+	if (!cdn_dp_check_link_status(dp)) {
+		dev_info(dp->dev, "Connected with sink; re-train link\n");
+
+		ret = cdn_dp_train_link(dp);
+		if (ret) {
+			dev_err(dp->dev, "Training link failed: %d\n", ret);
+			goto out;
+		}
+
+		ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE);
+		if (ret) {
+			dev_err(dp->dev, "Failed to idle video %d\n", ret);
+			goto out;
+		}
+
+		ret = cdn_dp_config_video(dp);
+		if (ret)
+			dev_err(dp->dev, "Failed to configure video: %d\n", ret);
+	}
+
+out:
+	return ret;
+}
+
 static void cdn_dp_display_info_update(struct cdn_dp_device *dp,
 				       struct drm_display_info *display_info)
 {
@@ -571,6 +667,7 @@ static void cdn_dp_display_info_update(struct cdn_dp_device *dp,
 static void cdn_dp_bridge_atomic_enable(struct drm_bridge *bridge, struct drm_atomic_state *state)
 {
 	struct cdn_dp_device *dp = bridge_to_dp(bridge);
+	struct cdn_dp_bridge *dp_bridge = bridge_to_dp_bridge(bridge);
 	struct drm_connector *connector;
 	int ret, val;
 
@@ -580,7 +677,7 @@ static void cdn_dp_bridge_atomic_enable(struct drm_bridge *bridge, struct drm_at
 
 	cdn_dp_display_info_update(dp, &connector->display_info);
 
-	ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, &dp->encoder.encoder);
+	ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, &dp_bridge->encoder.encoder);
 	if (ret < 0) {
 		DRM_DEV_ERROR(dp->dev, "Could not get vop id, %d", ret);
 		return;
@@ -599,6 +696,9 @@ static void cdn_dp_bridge_atomic_enable(struct drm_bridge *bridge, struct drm_at
 
 	mutex_lock(&dp->lock);
 
+	if (dp->next_bridge_valid)
+		dp->active_port = dp_bridge->id;
+
 	ret = cdn_dp_enable(dp);
 	if (ret) {
 		DRM_DEV_ERROR(dp->dev, "Failed to enable bridge %d\n",
@@ -631,6 +731,7 @@ static void cdn_dp_bridge_atomic_enable(struct drm_bridge *bridge, struct drm_at
 		goto out;
 	}
 
+	dp_bridge->enabled = true;
 out:
 	mutex_unlock(&dp->lock);
 }
@@ -638,9 +739,11 @@ static void cdn_dp_bridge_atomic_enable(struct drm_bridge *bridge, struct drm_at
 static void cdn_dp_bridge_atomic_disable(struct drm_bridge *bridge, struct drm_atomic_state *state)
 {
 	struct cdn_dp_device *dp = bridge_to_dp(bridge);
+	struct cdn_dp_bridge *dp_bridge = bridge_to_dp_bridge(bridge);
 	int ret;
 
 	mutex_lock(&dp->lock);
+	dp_bridge->enabled = false;
 
 	if (dp->active) {
 		ret = cdn_dp_disable(dp);
@@ -827,6 +930,16 @@ static int cdn_dp_audio_mute_stream(struct drm_bridge *bridge,
 	return ret;
 }
 
+static void cdn_dp_bridge_hpd_notify(struct drm_bridge *bridge,
+			   enum drm_connector_status status)
+{
+	struct cdn_dp_bridge *dp_bridge = bridge_to_dp_bridge(bridge);
+	struct cdn_dp_device *dp = bridge_to_dp(bridge);
+
+	dp->bridge_list[dp_bridge->id]->connected = status == connector_status_connected;
+	schedule_work(&dp->event_work);
+}
+
 static const struct drm_bridge_funcs cdn_dp_bridge_funcs = {
 	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
@@ -837,6 +950,7 @@ static const struct drm_bridge_funcs cdn_dp_bridge_funcs = {
 	.atomic_disable = cdn_dp_bridge_atomic_disable,
 	.mode_valid = cdn_dp_bridge_mode_valid,
 	.mode_set = cdn_dp_bridge_mode_set,
+	.hpd_notify = cdn_dp_bridge_hpd_notify,
 
 	.dp_audio_prepare = cdn_dp_audio_prepare,
 	.dp_audio_mute_stream = cdn_dp_audio_mute_stream,
@@ -885,7 +999,8 @@ static void cdn_dp_pd_event_work(struct work_struct *work)
 {
 	struct cdn_dp_device *dp = container_of(work, struct cdn_dp_device,
 						event_work);
-	int ret;
+	bool connected;
+	int i, ret;
 
 	mutex_lock(&dp->lock);
 
@@ -944,9 +1059,12 @@ static void cdn_dp_pd_event_work(struct work_struct *work)
 
 out:
 	mutex_unlock(&dp->lock);
-	drm_bridge_hpd_notify(&dp->bridge,
-			      dp->connected ? connector_status_connected
-					    : connector_status_disconnected);
+	for (i = 0; i < dp->bridge_count; i++) {
+		connected = dp->connected && dp->bridge_list[i]->connected;
+		drm_bridge_hpd_notify(&dp->bridge_list[i]->bridge,
+				      connected ? connector_status_connected
+						: connector_status_disconnected);
+	}
 }
 
 static int cdn_dp_pd_event(struct notifier_block *nb,
@@ -966,28 +1084,16 @@ static int cdn_dp_pd_event(struct notifier_block *nb,
 	return NOTIFY_DONE;
 }
 
-static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
+static int cdn_bridge_add(struct device *dev,
+			  struct drm_bridge *bridge,
+			  struct drm_bridge *next_bridge,
+			  struct drm_encoder *encoder)
 {
 	struct cdn_dp_device *dp = dev_get_drvdata(dev);
-	struct drm_encoder *encoder;
+	struct drm_device *drm_dev = dp->drm_dev;
+	struct drm_bridge *last_bridge __free(drm_bridge_put) = NULL;
 	struct drm_connector *connector;
-	struct cdn_dp_port *port;
-	struct drm_device *drm_dev = data;
-	int ret, i;
-
-	ret = cdn_dp_parse_dt(dp);
-	if (ret < 0)
-		return ret;
-
-	dp->drm_dev = drm_dev;
-	dp->connected = false;
-	dp->active = false;
-	dp->active_port = -1;
-	dp->fw_loaded = false;
-
-	INIT_WORK(&dp->event_work, cdn_dp_pd_event_work);
-
-	encoder = &dp->encoder.encoder;
+	int ret;
 
 	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
 							     dev->of_node);
@@ -1002,26 +1108,35 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
 
 	drm_encoder_helper_add(encoder, &cdn_dp_encoder_helper_funcs);
 
-	dp->bridge.ops =
-			DRM_BRIDGE_OP_DETECT |
-			DRM_BRIDGE_OP_EDID |
-			DRM_BRIDGE_OP_HPD |
-			DRM_BRIDGE_OP_DP_AUDIO;
-	dp->bridge.of_node = dp->dev->of_node;
-	dp->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
-	dp->bridge.hdmi_audio_dev = dp->dev;
-	dp->bridge.hdmi_audio_max_i2s_playback_channels = 8;
-	dp->bridge.hdmi_audio_spdif_playback = 1;
-	dp->bridge.hdmi_audio_dai_port = -1;
-
-	ret = devm_drm_bridge_add(dev, &dp->bridge);
+	bridge->ops =
+		DRM_BRIDGE_OP_DETECT |
+		DRM_BRIDGE_OP_EDID |
+		DRM_BRIDGE_OP_HPD |
+		DRM_BRIDGE_OP_DP_AUDIO;
+	bridge->of_node = dp->dev->of_node;
+	bridge->type = DRM_MODE_CONNECTOR_DisplayPort;
+	bridge->hdmi_audio_dev = dp->dev;
+	bridge->hdmi_audio_max_i2s_playback_channels = 8;
+	bridge->hdmi_audio_spdif_playback = 1;
+	bridge->hdmi_audio_dai_port = -1;
+
+	ret = devm_drm_bridge_add(dev, bridge);
 	if (ret)
 		return ret;
 
-	ret = drm_bridge_attach(encoder, &dp->bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
+	ret = drm_bridge_attach(encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
 	if (ret)
 		return ret;
 
+	if (next_bridge) {
+		ret = drm_bridge_attach(encoder, next_bridge, bridge,
+					DRM_BRIDGE_ATTACH_NO_CONNECTOR);
+		if (ret)
+			return ret;
+
+		last_bridge = drm_bridge_chain_get_last_bridge(bridge->encoder);
+	}
+
 	connector = drm_bridge_connector_init(drm_dev, encoder);
 	if (IS_ERR(connector)) {
 		ret = PTR_ERR(connector);
@@ -1029,8 +1144,100 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
 		return ret;
 	}
 
+	if (last_bridge)
+		connector->fwnode = fwnode_handle_get(of_fwnode_handle(last_bridge->of_node));
+
 	drm_connector_attach_encoder(connector, encoder);
 
+	return 0;
+}
+
+static int cdn_dp_parse_next_bridge_dt(struct cdn_dp_device *dp)
+{
+	struct device_node *np = dp->dev->of_node;
+	struct device_node *port __free(device_node) = of_graph_get_port_by_id(np, 1);
+	struct drm_bridge *bridge;
+	int count = 0;
+	int ret = 0;
+	int i;
+
+	/* If device use extcon, do not use hpd bridge */
+	for (i = 0; i < dp->ports; i++) {
+		if (dp->port[i]->extcon) {
+			dp->bridge_count = 1;
+			return 0;
+		}
+	}
+
+	/* One endpoint may correspond to one next bridge. */
+	for_each_of_graph_port_endpoint(port, dp_ep) {
+		struct device_node *next_bridge_node __free(device_node) =
+			of_graph_get_remote_port_parent(dp_ep);
+
+		bridge = of_drm_find_bridge(next_bridge_node);
+		if (!bridge) {
+			ret = -EPROBE_DEFER;
+			goto out;
+		}
+
+		drm_bridge_get(bridge);
+		dp->next_bridge_valid = true;
+		dp->next_bridge_list[count] = bridge;
+		count++;
+	}
+
+out:
+	dp->bridge_count = count ? count : 1;
+	return ret;
+}
+
+static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
+{
+	struct cdn_dp_device *dp = dev_get_drvdata(dev);
+	struct drm_bridge *bridge, *next_bridge;
+	struct drm_encoder *encoder;
+	struct cdn_dp_port *port;
+	struct drm_device *drm_dev = data;
+	struct cdn_dp_bridge *dp_bridge;
+	int ret, i;
+
+	ret = cdn_dp_parse_dt(dp);
+	if (ret < 0)
+		return ret;
+
+	ret = cdn_dp_parse_next_bridge_dt(dp);
+	if (ret)
+		return ret;
+
+	dp->drm_dev = drm_dev;
+	dp->connected = false;
+	dp->active = false;
+	dp->active_port = -1;
+	dp->fw_loaded = false;
+
+	for (i = 0; i < dp->bridge_count; i++) {
+		dp_bridge = devm_drm_bridge_alloc(dev, struct cdn_dp_bridge, bridge,
+						    &cdn_dp_bridge_funcs);
+		if (IS_ERR(dp_bridge))
+			return PTR_ERR(dp_bridge);
+		dp_bridge->id = i;
+		dp_bridge->parent = dp;
+		if (!dp->next_bridge_valid)
+			dp_bridge->connected = true;
+		dp->bridge_list[i] = dp_bridge;
+	}
+
+	for (i = 0; i < dp->bridge_count; i++) {
+		encoder = &dp->bridge_list[i]->encoder.encoder;
+		bridge = &dp->bridge_list[i]->bridge;
+		next_bridge = dp->next_bridge_list[i];
+		ret = cdn_bridge_add(dev, bridge, next_bridge, encoder);
+		if (ret)
+			return ret;
+	}
+
+	INIT_WORK(&dp->event_work, cdn_dp_pd_event_work);
+
 	for (i = 0; i < dp->ports; i++) {
 		port = dp->port[i];
 
@@ -1058,10 +1265,18 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
 static void cdn_dp_unbind(struct device *dev, struct device *master, void *data)
 {
 	struct cdn_dp_device *dp = dev_get_drvdata(dev);
-	struct drm_encoder *encoder = &dp->encoder.encoder;
+	struct drm_encoder *encoder;
+	int i;
 
 	cancel_work_sync(&dp->event_work);
-	encoder->funcs->destroy(encoder);
+	for (i = 0; i < dp->bridge_count; i++) {
+		encoder = &dp->bridge_list[i]->encoder.encoder;
+		encoder->funcs->destroy(encoder);
+		drm_bridge_put(dp->next_bridge_list[i]);
+	}
+
+	for (i = 0; i < MAX_PHY; i++)
+		drm_edid_free(dp->edid_cache[i]);
 
 	pm_runtime_disable(dev);
 	if (dp->fw_loaded)
@@ -1112,10 +1327,10 @@ static int cdn_dp_probe(struct platform_device *pdev)
 	int ret;
 	int i;
 
-	dp = devm_drm_bridge_alloc(dev, struct cdn_dp_device, bridge,
-				   &cdn_dp_bridge_funcs);
-	if (IS_ERR(dp))
-		return PTR_ERR(dp);
+	dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
+	if (!dp)
+		return -ENOMEM;
+
 	dp->dev = dev;
 
 	match = of_match_node(cdn_dp_dt_ids, pdev->dev.of_node);
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h
index e9c30b9fd543..c10e423bbf06 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.h
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h
@@ -38,6 +38,8 @@ enum vic_pxl_encoding_format {
 	Y_ONLY = 0x10,
 };
 
+struct cdn_dp_device;
+
 struct video_info {
 	bool h_sync_polarity;
 	bool v_sync_polarity;
@@ -63,16 +65,28 @@ struct cdn_dp_port {
 	u8 id;
 };
 
+struct cdn_dp_bridge {
+	struct cdn_dp_device *parent;
+	struct drm_bridge bridge;
+	struct rockchip_encoder encoder;
+	bool connected;
+	bool enabled;
+	int id;
+};
+
 struct cdn_dp_device {
 	struct device *dev;
 	struct drm_device *drm_dev;
-	struct drm_bridge bridge;
-	struct rockchip_encoder encoder;
+	int bridge_count;
+	struct cdn_dp_bridge *bridge_list[MAX_PHY];
+	struct drm_bridge *next_bridge_list[MAX_PHY];
+	const struct drm_edid *edid_cache[MAX_PHY];
 	struct drm_display_mode mode;
 	struct platform_device *audio_pdev;
 	struct work_struct event_work;
 
 	struct mutex lock;
+	bool next_bridge_valid;
 	bool connected;
 	bool active;
 	bool suspended;
-- 
2.51.1



From kernel at airkyi.com  Wed Dec  3 22:31:08 2025
From: kernel at airkyi.com (Chaoyi Chen)
Date: Thu,  4 Dec 2025 14:31:08 +0800
Subject: [RESEND PATCH v11 10/11] arm64: dts: rockchip: Add missing dp_out port for RK3399 CDN-DP
In-Reply-To: <20251204063109.104-1-kernel@airkyi.com>
References: <20251204063109.104-1-kernel@airkyi.com>
Message-ID: <20251204063109.104-11-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

Let's make the ports nodes of cdn_dp in the same style as the other
display interface, and match the style of ports's yaml.

Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
---

(no changes since v5)

Changes in v4:
- Remove unnecessary #address/#size-cells

(no changes since v1)

 arch/arm64/boot/dts/rockchip/rk3399-base.dtsi | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi
index 4dcceb9136b7..93b42820998f 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi
@@ -618,7 +618,11 @@ cdn_dp: dp at fec00000 {
 		status = "disabled";
 
 		ports {
-			dp_in: port {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			dp_in: port at 0 {
+				reg = <0>;
 				#address-cells = <1>;
 				#size-cells = <0>;
 
@@ -632,6 +636,10 @@ dp_in_vopl: endpoint at 1 {
 					remote-endpoint = <&vopl_out_dp>;
 				};
 			};
+
+			dp_out: port at 1 {
+				reg = <1>;
+			};
 		};
 	};
 
-- 
2.51.1



From kernel at airkyi.com  Wed Dec  3 22:31:09 2025
From: kernel at airkyi.com (Chaoyi Chen)
Date: Thu,  4 Dec 2025 14:31:09 +0800
Subject: [RESEND PATCH v11 11/11] arm64: dts: rockchip: rk3399-evb-ind: Add support for DisplayPort
In-Reply-To: <20251204063109.104-1-kernel@airkyi.com>
References: <20251204063109.104-1-kernel@airkyi.com>
Message-ID: <20251204063109.104-12-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

The RK3399 EVB IND board has a Type-C interface DisplayPort.
It use fusb302 chip as Type-C controller.

fusb302 chip ---> USB/DP PHY0 <----> CDN-DP controller

Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
---

(no changes since v10)

Changes in v9:
- Add usb role switch for Type-C.
- Remove USB2 PHY in Type-C connection.

(no changes since v4)

Changes in v3:
- Fix wrong vdo value.
- Fix port node in usb-c-connector.

Changes in v2:
- Add endpoint to link DP PHY and DP controller.
- Fix devicetree coding style.

 .../boot/dts/rockchip/rk3399-evb-ind.dts      | 147 ++++++++++++++++++
 1 file changed, 147 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-evb-ind.dts b/arch/arm64/boot/dts/rockchip/rk3399-evb-ind.dts
index 70aee1ab904c..be1e90f7a453 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-evb-ind.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-evb-ind.dts
@@ -4,6 +4,7 @@
  */
 
 /dts-v1/;
+#include <dt-bindings/usb/pd.h>
 #include "rk3399.dtsi"
 
 / {
@@ -19,6 +20,21 @@ chosen {
 		stdout-path = "serial2:1500000n8";
 	};
 
+	sound: sound {
+		compatible = "rockchip,rk3399-gru-sound";
+		rockchip,cpu = <&i2s0 &spdif>;
+	};
+
+	vbus_typec: regulator-vbus-typec {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpio1 RK_PC2 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&vcc5v0_typec0_en>;
+		regulator-name = "vbus_typec";
+		vin-supply = <&vcc5v0_sys>;
+	};
+
 	vcc5v0_sys: regulator-vcc5v0-sys {
 		compatible = "regulator-fixed";
 		enable-active-high;
@@ -31,6 +47,11 @@ vcc5v0_sys: regulator-vcc5v0-sys {
 	};
 };
 
+&cdn_dp {
+	phys = <&tcphy0_dp>;
+	status = "okay";
+};
+
 &cpu_b0 {
 	cpu-supply = <&vdd_cpu_b>;
 };
@@ -55,6 +76,12 @@ &cpu_l3 {
 	cpu-supply = <&vdd_cpu_l>;
 };
 
+&dp_out {
+	dp_controller_output: endpoint {
+		remote-endpoint = <&dp_phy_in>;
+	};
+};
+
 &emmc_phy {
 	status = "okay";
 };
@@ -341,6 +368,71 @@ regulator-state-mem {
 	};
 };
 
+&i2c4 {
+	i2c-scl-rising-time-ns = <475>;
+	i2c-scl-falling-time-ns = <26>;
+	status = "okay";
+
+	usbc0: typec-portc at 22 {
+		compatible = "fcs,fusb302";
+		reg = <0x22>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <RK_PA2 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&usbc0_int>;
+		vbus-supply = <&vbus_typec>;
+
+		usb_con: connector {
+			compatible = "usb-c-connector";
+			label = "USB-C";
+			data-role = "dual";
+			power-role = "dual";
+			try-power-role = "sink";
+			op-sink-microwatt = <1000000>;
+			sink-pdos =
+				<PDO_FIXED(5000, 2500, PDO_FIXED_USB_COMM)>;
+			source-pdos =
+				<PDO_FIXED(5000, 1500, PDO_FIXED_USB_COMM)>;
+
+			altmodes {
+				displayport {
+					svid = /bits/ 16 <0xff01>;
+					vdo = <0x00001c46>;
+				};
+			};
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+
+					usbc0_orien_sw: endpoint {
+						remote-endpoint = <&tcphy0_orientation_switch>;
+					};
+				};
+
+				port at 1 {
+					reg = <1>;
+
+					usbc0_role_sw: endpoint {
+						remote-endpoint = <&dwc3_0_role_switch>;
+					};
+				};
+
+				port at 2 {
+					reg = <2>;
+
+					dp_altmode_mux: endpoint {
+						remote-endpoint = <&tcphy0_typec_dp>;
+					};
+				};
+			};
+		};
+	};
+};
+
 &i2s2 {
 	status = "okay";
 };
@@ -354,6 +446,16 @@ &io_domains {
 };
 
 &pinctrl {
+	usb-typec {
+		usbc0_int: usbc0-int {
+			rockchip,pins = <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+
+		vcc5v0_typec0_en: vcc5v0-typec0-en {
+			rockchip,pins = <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
 	pmic {
 		pmic_int_l: pmic-int-l {
 			rockchip,pins = <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>;
@@ -400,10 +502,48 @@ &sdmmc {
 	status = "okay";
 };
 
+&sound {
+	rockchip,codec = <&cdn_dp>;
+	status = "okay";
+};
+
+&spdif {
+	status = "okay";
+};
+
 &tcphy0 {
 	status = "okay";
 };
 
+&tcphy0_dp {
+	mode-switch;
+
+	port {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		tcphy0_typec_dp: endpoint at 0 {
+			reg = <0>;
+			remote-endpoint = <&dp_altmode_mux>;
+		};
+
+		dp_phy_in: endpoint at 1 {
+			reg = <1>;
+			remote-endpoint = <&dp_controller_output>;
+		};
+	};
+};
+
+&tcphy0_usb3 {
+	orientation-switch;
+
+	port {
+		tcphy0_orientation_switch: endpoint {
+			remote-endpoint = <&usbc0_orien_sw>;
+		};
+	};
+};
+
 &tcphy1 {
 	status = "okay";
 };
@@ -461,7 +601,14 @@ &usb_host1_ohci {
 };
 
 &usbdrd_dwc3_0 {
+	usb-role-switch;
 	status = "okay";
+
+	port {
+		dwc3_0_role_switch: endpoint {
+			remote-endpoint = <&usbc0_role_sw>;
+		};
+	};
 };
 
 &usbdrd3_0 {
-- 
2.51.1



From taniya.das at oss.qualcomm.com  Wed Dec  3 22:49:28 2025
From: taniya.das at oss.qualcomm.com (Taniya Das)
Date: Thu, 4 Dec 2025 12:19:28 +0530
Subject: [PATCH v2 07/11] dt-bindings: clock: qcom: document the Kaanapali
 GPU Clock Controller
In-Reply-To: <20251126-elated-stoic-scorpion-25b630@kuoka>
References: <20251125-kaanapali-mmcc-v2-v2-0-fb44e78f300b@oss.qualcomm.com>
 <20251125-kaanapali-mmcc-v2-v2-7-fb44e78f300b@oss.qualcomm.com>
 <20251126-elated-stoic-scorpion-25b630@kuoka>
Message-ID: <de44560d-4ed8-41fe-be7b-56412b933a8c@oss.qualcomm.com>



On 11/26/2025 3:05 PM, Krzysztof Kozlowski wrote:
> On Tue, Nov 25, 2025 at 11:15:16PM +0530, Taniya Das wrote:
>> Add bindings documentation for the Kaanapali Graphics Clock and Graphics
>> power domain Controller.
>>
>> Signed-off-by: Jingyi Wang <jingyi.wang at oss.qualcomm.com>
>> Reviewed-by: Bryan O'Donoghue <bryan.odonoghue at linaro.org>
>> Signed-off-by: Taniya Das <taniya.das at oss.qualcomm.com>
>> ---
>>  .../bindings/clock/qcom,kaanapali-gxclkctl.yaml    | 63 ++++++++++++++++++++++
>>  .../bindings/clock/qcom,sm8450-gpucc.yaml          |  2 +
>>  include/dt-bindings/clock/qcom,kaanapali-gpucc.h   | 47 ++++++++++++++++
>>  .../dt-bindings/clock/qcom,kaanapali-gxclkctl.h    | 12 +++++
>>  4 files changed, 124 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/clock/qcom,kaanapali-gxclkctl.yaml b/Documentation/devicetree/bindings/clock/qcom,kaanapali-gxclkctl.yaml
>> new file mode 100644
>> index 0000000000000000000000000000000000000000..31398aec839d88007c9f1de7e1a248beae826640
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/clock/qcom,kaanapali-gxclkctl.yaml
>> @@ -0,0 +1,63 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/clock/qcom,kaanapali-gxclkctl.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Qualcomm Graphics power domain Controller on Kaanapali
> 
> "Power Domain"
> 

will fix in the next patch.

>> +
>> +maintainers:
>> +  - Taniya Das <taniya.das at oss.qualcomm.com>
>> +
>> +description: |
>> +  Qualcomm graphics power domain control module provides the power
>> +  domains on Qualcomm SoCs. This module exposes the GDSC power domain
>> +  which helps the recovery of Graphics subsystem.
>> +
>> +  See also::
> 
> Just one ':'
> 

My bad, will fix it in the next series.


>> +    include/dt-bindings/clock/qcom,kaanapali-gxclkctl.h
>> +
>> +properties:
>> +  compatible:
>> +    enum:
>> +      - qcom,kaanapali-gxclkctl
>> +
>> +  power-domains:
>> +    description:
>> +      Power domains required for the clock controller to operate
>> +    items:
>> +      - description: GFX power domain
>> +      - description: GMXC power domain
>> +      - description: GPUCC(CX) power domain
>> +
>> +  '#power-domain-cells':
> 
> Power domain controllers do not belong to clocks, so this is:
> 1. Misplaced - wrong folder
> 2. Probably wrongly named. gxclkctl sounds like clock controller, but
> this is domain controller?
> 

The GFXCLKCTL is actually a clock controller which has PLLs, clocks and
Power domains (GDSC), but the requirement here is to use the GDSC from
the clock controller to recover the GPU firmware in case of any
failure/hangs. The rest of the resources of the clock controller are
being used by the firmware of GPU. The GDSC is a clock controller
resource and modeled from the clock controller drivers across chipsets.

>> +    const: 1
>> +
>> +  reg:
>> +    maxItems: 1
>> +
>> +required:
>> +  - compatible
>> +  - reg
>> +  - power-domains
>> +  - '#power-domain-cells'
>> +
>> +unevaluatedProperties: false
>> +
>> +examples:
>> +  - |
>> +    #include <dt-bindings/power/qcom,rpmhpd.h>
>> +    soc {
>> +        #address-cells = <2>;
>> +        #size-cells = <2>;
>> +
>> +        clock-controller at 3d68024 {
>> +            compatible = "qcom,kaanapali-gxclkctl";
>> +            reg = <0 0x3d68024 0x0 0x8>;
> 
> Keep consistent hex, so first 0 -> 0x0.

Sure, will fix this.

> But the problem is that you defined a device for two registers,
> basically one domain. I have doubts now whether this is complete and
> real device.
> 

As the Linux GPU driver requires only the GDSC, I have mapped the region
which is required by the clock controller driver. If required, the
entire region can be mapped as well.

>> +            power-domains = <&rpmhpd RPMHPD_GFX>,
>> +                            <&rpmhpd RPMHPD_GMXC>,
>> +                            <&gpucc 0>;
>> +            #power-domain-cells = <1>;
> 
> And cells 1 makes no sense in such case.
> 

We would like to leverage the existing common clock driver(GDSC) code to
register the power-domains and also maintain uniformity across chipsets
and consistency in consumer GDSC phandle usage.


-- 
Thanks,
Taniya Das



From taniya.das at oss.qualcomm.com  Wed Dec  3 22:51:45 2025
From: taniya.das at oss.qualcomm.com (Taniya Das)
Date: Thu, 4 Dec 2025 12:21:45 +0530
Subject: [PATCH v2 10/11] clk: qcom: Add support for VideoCC driver for
 Kaanapali
In-Reply-To: <850c172d-66e0-4d28-903d-fbcef7ad7444@oss.qualcomm.com>
References: <20251125-kaanapali-mmcc-v2-v2-0-fb44e78f300b@oss.qualcomm.com>
 <20251125-kaanapali-mmcc-v2-v2-10-fb44e78f300b@oss.qualcomm.com>
 <850c172d-66e0-4d28-903d-fbcef7ad7444@oss.qualcomm.com>
Message-ID: <db8a9c71-8400-46f2-892a-a9a8adcd8dd0@oss.qualcomm.com>



On 12/1/2025 6:45 PM, Konrad Dybcio wrote:
> On 11/25/25 6:45 PM, Taniya Das wrote:
>> Enable Kaanapali video clock driver for video SW to be able to control
>> the clocks from the Video SW driver.
>>
>> Signed-off-by: Taniya Das <taniya.das at oss.qualcomm.com>
>> ---
> 
> [...]
> 
>> +static struct clk_mem_branch video_cc_mvs0_freerun_clk = {
>> +	.mem_enable_reg = 0x80E4,
>> +	.mem_ack_reg =  0x80E4,
> 
> hex must be lowercase
> 

Sure, will fix this.

>> +	.mem_enable_mask = BIT(3),
>> +	.mem_enable_ack_mask = 0xc00,
> 
> GENMASK(11, 10)
> 

will fix this as well.

>> +	.mem_enable_invert = true,
>> +	.branch = {
>> +		.halt_reg = 0x80e0,
>> +		.halt_check = BRANCH_HALT,
>> +		.clkr = {
>> +			.enable_reg = 0x80e0,
>> +			.enable_mask = BIT(0),
>> +			.hw.init = &(const struct clk_init_data) {
>> +				.name = "video_cc_mvs0_freerun_clk",
>> +				.parent_hws = (const struct clk_hw*[]) {
>> +					&video_cc_mvs0_clk_src.clkr.hw,
>> +				},
>> +			.num_parents = 1,
>> +			.flags = CLK_SET_RATE_PARENT,
>> +			.ops = &clk_branch2_ops,
>> +			},
> 
> The indentation is a little malformed 
> 

will check this and fix.

> 
>> +static void clk_kaanapali_regs_configure(struct device *dev, struct regmap *regmap)
>> +{
>> +	/*
>> +	 * Enable clk_on sync for MVS0 and VPP clocks via VIDEO_CC_SPARE1
>> +	 * during core reset by default.
>> +	 */
>> +	regmap_update_bits(regmap, 0x9f24, BIT(0), BIT(0));
> 
> regmap_set_bits()
> 

Will replace with the new API.

> lgtm otherwise
> 
> Konrad

-- 
Thanks,
Taniya Das



From anshuman.khandual at arm.com  Wed Dec  3 22:52:13 2025
From: anshuman.khandual at arm.com (Anshuman Khandual)
Date: Thu, 4 Dec 2025 12:22:13 +0530
Subject: [PATCH v5 09/12] arm64: mm: replace TIF_LAZY_MMU with
 in_lazy_mmu_mode()
In-Reply-To: <20251124132228.622678-10-kevin.brodsky@arm.com>
References: <20251124132228.622678-1-kevin.brodsky@arm.com>
 <20251124132228.622678-10-kevin.brodsky@arm.com>
Message-ID: <89ecddb7-83ee-427b-823b-984204939ecf@arm.com>

On 24/11/25 6:52 PM, Kevin Brodsky wrote:
> The generic lazy_mmu layer now tracks whether a task is in lazy MMU
> mode. As a result we no longer need a TIF flag for that purpose -
> let's use the new in_lazy_mmu_mode() helper instead.
> 
> The explicit check for in_interrupt() is no longer necessary either
> as in_lazy_mmu_mode() always returns false in interrupt context.
> 
> Signed-off-by: Kevin Brodsky <kevin.brodsky at arm.com>
> ---
>  arch/arm64/include/asm/pgtable.h     | 19 +++----------------
>  arch/arm64/include/asm/thread_info.h |  3 +--
>  2 files changed, 4 insertions(+), 18 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
> index a7d99dee3dc4..dd7ed653a20d 100644
> --- a/arch/arm64/include/asm/pgtable.h
> +++ b/arch/arm64/include/asm/pgtable.h
> @@ -62,28 +62,16 @@ static inline void emit_pte_barriers(void)
>  
>  static inline void queue_pte_barriers(void)
>  {
> -	unsigned long flags;
> -
> -	if (in_interrupt()) {
> -		emit_pte_barriers();
> -		return;
> -	}
> -
> -	flags = read_thread_flags();
> -
> -	if (flags & BIT(TIF_LAZY_MMU)) {
> +	if (in_lazy_mmu_mode()) {
>  		/* Avoid the atomic op if already set. */
> -		if (!(flags & BIT(TIF_LAZY_MMU_PENDING)))
> +		if (!test_thread_flag(TIF_LAZY_MMU_PENDING))

A small nit - will it be better not to use test_thread_flag() here and just
keep checking flags like earlier to avoid non-related changes. Although not
a problem TBH.

>  			set_thread_flag(TIF_LAZY_MMU_PENDING);
>  	} else {
>  		emit_pte_barriers();
>  	}
>  }
>  
> -static inline void arch_enter_lazy_mmu_mode(void)
> -{
> -	set_thread_flag(TIF_LAZY_MMU);
> -}
> +static inline void arch_enter_lazy_mmu_mode(void) {}
>  
>  static inline void arch_flush_lazy_mmu_mode(void)
>  {
> @@ -94,7 +82,6 @@ static inline void arch_flush_lazy_mmu_mode(void)
>  static inline void arch_leave_lazy_mmu_mode(void)
>  {
>  	arch_flush_lazy_mmu_mode();
> -	clear_thread_flag(TIF_LAZY_MMU);
>  }
>  
>  #ifdef CONFIG_TRANSPARENT_HUGEPAGE
> diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
> index f241b8601ebd..4ff8da0767d9 100644
> --- a/arch/arm64/include/asm/thread_info.h
> +++ b/arch/arm64/include/asm/thread_info.h
> @@ -84,8 +84,7 @@ void arch_setup_new_exec(void);
>  #define TIF_SME_VL_INHERIT	28	/* Inherit SME vl_onexec across exec */
>  #define TIF_KERNEL_FPSTATE	29	/* Task is in a kernel mode FPSIMD section */
>  #define TIF_TSC_SIGSEGV		30	/* SIGSEGV on counter-timer access */
> -#define TIF_LAZY_MMU		31	/* Task in lazy mmu mode */
> -#define TIF_LAZY_MMU_PENDING	32	/* Ops pending for lazy mmu mode exit */
> +#define TIF_LAZY_MMU_PENDING	31	/* Ops pending for lazy mmu mode exit */
>  
>  #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
>  #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)

LGTM.

Hence with or without the 'flags' changes in queue_pte_barriers() above.

Reviewed-by: Anshuman Khandual <anshuman.khandual at arm.com>


From wei.fang at nxp.com  Wed Dec  3 23:13:32 2025
From: wei.fang at nxp.com (Wei Fang)
Date: Thu,  4 Dec 2025 15:13:32 +0800
Subject: [PATCH net] net: stmmac: fix the crash issue for zero copy XDP_TX action
Message-ID: <20251204071332.1907111-1-wei.fang@nxp.com>

There is a crash issue when running zero copy XDP_TX action, the crash
log is shown below.

[  216.122464] Unable to handle kernel paging request at virtual address fffeffff80000000
[  216.187524] Internal error: Oops: 0000000096000144 [#1]  SMP
[  216.301694] Call trace:
[  216.304130]  dcache_clean_poc+0x20/0x38 (P)
[  216.308308]  __dma_sync_single_for_device+0x1bc/0x1e0
[  216.313351]  stmmac_xdp_xmit_xdpf+0x354/0x400
[  216.317701]  __stmmac_xdp_run_prog+0x164/0x368
[  216.322139]  stmmac_napi_poll_rxtx+0xba8/0xf00
[  216.326576]  __napi_poll+0x40/0x218
[  216.408054] Kernel panic - not syncing: Oops: Fatal exception in interrupt

For XDP_TX action, the xdp_buff is converted to xdp_frame by
xdp_convert_buff_to_frame(). The memory type of the resulting xdp_frame
depends on the memory type of the xdp_buff. For page pool based xdp_buff
it produces xdp_frame with memory type MEM_TYPE_PAGE_POOL. For zero copy
XSK pool based xdp_buff it produces xdp_frame with memory type
MEM_TYPE_PAGE_ORDER0. However, stmmac_xdp_xmit_back() does not check the
memory type and always uses the page pool type, this leads to invalid
mappings and causes the crash. Therefore, check the xdp_buff memory type
in stmmac_xdp_xmit_back() to fix this issue.

Fixes: bba2556efad6 ("net: stmmac: Enable RX via AF_XDP zero-copy")
Signed-off-by: Wei Fang <wei.fang at nxp.com>
---
 .../net/ethernet/stmicro/stmmac/stmmac_main.c   | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 7b90ecd3a55e..a6664f300e4a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -88,6 +88,7 @@ MODULE_PARM_DESC(phyaddr, "Physical device address");
 #define STMMAC_XDP_CONSUMED	BIT(0)
 #define STMMAC_XDP_TX		BIT(1)
 #define STMMAC_XDP_REDIRECT	BIT(2)
+#define STMMAC_XSK_CONSUMED	BIT(3)
 
 static int flow_ctrl = 0xdead;
 module_param(flow_ctrl, int, 0644);
@@ -4988,6 +4989,7 @@ static int stmmac_xdp_get_tx_queue(struct stmmac_priv *priv,
 static int stmmac_xdp_xmit_back(struct stmmac_priv *priv,
 				struct xdp_buff *xdp)
 {
+	bool zc = !!(xdp->rxq->mem.type == MEM_TYPE_XSK_BUFF_POOL);
 	struct xdp_frame *xdpf = xdp_convert_buff_to_frame(xdp);
 	int cpu = smp_processor_id();
 	struct netdev_queue *nq;
@@ -5004,9 +5006,18 @@ static int stmmac_xdp_xmit_back(struct stmmac_priv *priv,
 	/* Avoids TX time-out as we are sharing with slow path */
 	txq_trans_cond_update(nq);
 
-	res = stmmac_xdp_xmit_xdpf(priv, queue, xdpf, false);
-	if (res == STMMAC_XDP_TX)
+	/* For zero copy XDP_TX action, dma_map is true */
+	res = stmmac_xdp_xmit_xdpf(priv, queue, xdpf, zc);
+	if (res == STMMAC_XDP_TX) {
 		stmmac_flush_tx_descriptors(priv, queue);
+	} else if (res == STMMAC_XDP_CONSUMED && zc) {
+		/* xdp has been freed by xdp_convert_buff_to_frame(),
+		 * no need to call xsk_buff_free() again, so return
+		 * STMMAC_XSK_CONSUMED.
+		 */
+		res = STMMAC_XSK_CONSUMED;
+		xdp_return_frame(xdpf);
+	}
 
 	__netif_tx_unlock(nq);
 
@@ -5356,6 +5367,8 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue)
 			break;
 		case STMMAC_XDP_CONSUMED:
 			xsk_buff_free(buf->xdp);
+			fallthrough;
+		case STMMAC_XSK_CONSUMED:
 			rx_dropped++;
 			break;
 		case STMMAC_XDP_TX:
-- 
2.34.1



From taniya.das at oss.qualcomm.com  Wed Dec  3 23:14:16 2025
From: taniya.das at oss.qualcomm.com (Taniya Das)
Date: Thu, 4 Dec 2025 12:44:16 +0530
Subject: [PATCH v2 08/11] clk: qcom: dispcc: Add support for display clock
 controller Kaanapali
In-Reply-To: <8d0ec7fc-6eb0-4b71-8e0f-3deaf1f489d6@oss.qualcomm.com>
References: <20251125-kaanapali-mmcc-v2-v2-0-fb44e78f300b@oss.qualcomm.com>
 <20251125-kaanapali-mmcc-v2-v2-8-fb44e78f300b@oss.qualcomm.com>
 <w3ezxipjucswfswfg2z7b7uyu55bssqatdnbxa6jflii4j7nym@lxsnidrewepu>
 <8d0ec7fc-6eb0-4b71-8e0f-3deaf1f489d6@oss.qualcomm.com>
Message-ID: <75e53a37-0fd2-41d6-92bc-fb4ad5856829@oss.qualcomm.com>



On 12/1/2025 6:50 PM, Konrad Dybcio wrote:
> On 11/26/25 1:09 AM, Dmitry Baryshkov wrote:
>> On Tue, Nov 25, 2025 at 11:15:17PM +0530, Taniya Das wrote:
>>> Support the clock controller driver for Kaanapali to enable display SW to
>>> be able to control the clocks.
>>>
>>> Signed-off-by: Taniya Das <taniya.das at oss.qualcomm.com>
>>> ---
> 
> [...]
> 
>>> +/* 257.142858 MHz Configuration */
>>
>> This is a bit strange frequency for the boot config.

The lowest PLL configuration is used as boot config based on the
MDP_CLK_SRC clock requirement. The PLLs on Kaanapali can support these
lower frequencies as well.


> The frequency map lists this odd cookie as the lowest predefined config,
> perhaps it was pulled from there.
> 

Correct Konrad.

> More interestingly, the only consumer of this PLL (MDP_CLK_SRC) makes no
> effort to use the m/n/d registers, instead relying on the PLL to re-clock
> for its ratesetting with a fixed divider of 3 (and div1 @ XO rate).
> 

The m/n is not preferred in the cases where the PLL needs to slew to
derive a new VCO frequency. That is the reason to keep the divider
constant as much as possible to derive a particular frequency.

> 257.142858 * 3 = 771.428574 over-drives MDP_CLK_SRC, FWIW.
> 

The lowest frequency requirement is 85.7MHz and the frequency is derived
using
257.142858 (PLL VCO) / 3 (RCG Div) = 85.714286 MHz

there is no over-drive at RCG of MDP.

> Taniya, we've seen something like this in camera too. Is there a reason
> the frequency is being set this way?
> 

We start with the lowest frequency to configure the PLL and frequency
requirements are decided based on usecases.

-- 
Thanks,
Taniya Das



From jimmy.ho at sifive.com  Wed Dec  3 23:23:02 2025
From: jimmy.ho at sifive.com (Jimmy Ho)
Date: Thu, 4 Dec 2025 15:23:02 +0800
Subject: [PATCH v3 6/7] riscv: pmu: Integrate CTR Ext support in
 riscv_pmu_dev driver
In-Reply-To: <CAJh9TSJk0nZvqJrvTe5ENMpAB=56--+CFai0tXQnYFakKxQxQw@mail.gmail.com>
References: <20250523-b4-ctr_upstream_v3-v3-0-ad355304ba1c@rivosinc.com>
 <20250523-b4-ctr_upstream_v3-v3-6-ad355304ba1c@rivosinc.com>
 <CAPqJEFr=3Re=L0CmEpCRHxovB74MDB9C8neNMfouYvWWbR0hyw@mail.gmail.com> <CAJh9TSJk0nZvqJrvTe5ENMpAB=56--+CFai0tXQnYFakKxQxQw@mail.gmail.com>
Message-ID: <CAJh9TS+MM+4ytsQ4tOhddNihvTrRMwV0rFRmMv1xRQTGcE18Dw@mail.gmail.com>

Hi Rajnesh,

> This integrates recently added CTR ext support in riscv_pmu_dev driver
> to enable branch stack sampling using PMU events.
>
> This mainly adds CTR enable/disable callbacks in rvpmu_ctr_stop()
> and rvpmu_ctr_start() function to start/stop branch recording along
> with the event.
>
> PMU overflow handler rvpmu_ovf_handler() is also updated to sample
> CTR entries in case of the overflow for the particular event programmed
> to records branches. The recorded entries are fed to core perf for
> further processing.
>
> Signed-off-by: Rajnesh Kanwal <rkanwal at rivosinc.com>
> ---
>  drivers/perf/riscv_pmu_common.c |  3 +-
>  drivers/perf/riscv_pmu_dev.c    | 67 ++++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 67 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/perf/riscv_pmu_common.c b/drivers/perf/riscv_pmu_common.c
> index b2dc78cbbb93926964f81f30be9ef4a1c02501df..0b032b8d8762e77d2b553643b0f9064e7c789cfe
> 100644
> --- a/drivers/perf/riscv_pmu_common.c
> +++ b/drivers/perf/riscv_pmu_common.c
> @@ -329,8 +329,7 @@ static int riscv_pmu_event_init(struct perf_event *event)
>         u64 event_config = 0;
>         uint64_t cmask;
>
> -       /* driver does not support branch stack sampling */
> -       if (has_branch_stack(event))
> +       if (needs_branch_stack(event) && !riscv_pmu_ctr_supported(rvpmu))
>                 return -EOPNOTSUPP;
>
>         hwc->flags = 0;
> diff --git a/drivers/perf/riscv_pmu_dev.c b/drivers/perf/riscv_pmu_dev.c
> index 95e6dd272db69f53b679e5fc3450785e45d5e8b9..b0c616fb939fcc61f7493877a8801916069f16f7
> 100644
> --- a/drivers/perf/riscv_pmu_dev.c
> +++ b/drivers/perf/riscv_pmu_dev.c
> @@ -1038,7 +1038,7 @@ static void rvpmu_sbi_ctr_stop(struct perf_event
> *event, unsigned long flag)
>  static void pmu_sched_task(struct perf_event_pmu_context *pmu_ctx,
>                            bool sched_in)
>  {
> -       /* Call CTR specific Sched hook. */
> +       riscv_pmu_ctr_sched_task(pmu_ctx, sched_in);
>  }
>
>  static int rvpmu_sbi_find_num_ctrs(void)
> @@ -1370,6 +1370,13 @@ static irqreturn_t rvpmu_ovf_handler(int irq, void *dev)
>                 hw_evt->state |= PERF_HES_UPTODATE;
>                 perf_sample_data_init(&data, 0, hw_evt->last_period);
>                 if (riscv_pmu_event_set_period(event)) {
> +                       if (needs_branch_stack(event)) {
> +                               riscv_pmu_ctr_consume(cpu_hw_evt, event);
> +                               perf_sample_save_brstack(
> +                                       &data, event,
> +
> &cpu_hw_evt->branches->branch_stack, NULL);
> +                       }
> +
>                         /*
>                          * Unlike other ISAs, RISC-V don't have to
> disable interrupts
>                          * to avoid throttling here. As per the
> specification, the
> @@ -1569,16 +1576,23 @@ static int rvpmu_deleg_ctr_get_idx(struct
> perf_event *event)
>
>  static void rvpmu_ctr_add(struct perf_event *event, int flags)
>  {
> +       if (needs_branch_stack(event))
> +               riscv_pmu_ctr_add(event);
>  }
>
>  static void rvpmu_ctr_del(struct perf_event *event, int flags)
>  {
> +       if (needs_branch_stack(event))
> +               riscv_pmu_ctr_del(event);
>  }
>
>  static void rvpmu_ctr_start(struct perf_event *event, u64 ival)
>  {
>         struct hw_perf_event *hwc = &event->hw;
>
> +       if (needs_branch_stack(event))
> +               riscv_pmu_ctr_enable(event);
> +
>         if (riscv_pmu_cdeleg_available() && !pmu_sbi_is_fw_event(event))
>                 rvpmu_deleg_ctr_start(event, ival);
>         else
> @@ -1593,6 +1607,9 @@ static void rvpmu_ctr_stop(struct perf_event
> *event, unsigned long flag)
>  {
>         struct hw_perf_event *hwc = &event->hw;
>
> +       if (needs_branch_stack(event) && flag != RISCV_PMU_STOP_FLAG_RESET)
> +               riscv_pmu_ctr_disable(event);
> +
>         if ((hwc->flags & PERF_EVENT_FLAG_USER_ACCESS) &&
>             (hwc->flags & PERF_EVENT_FLAG_USER_READ_CNT))
>                 rvpmu_reset_scounteren((void *)event);
> @@ -1650,6 +1667,9 @@ static u32 rvpmu_find_ctrs(void)
>
>  static int rvpmu_event_map(struct perf_event *event, u64 *econfig)
>  {
> +       if (needs_branch_stack(event) && !riscv_pmu_ctr_valid(event))
> +               return -EOPNOTSUPP;
> +
>         if (riscv_pmu_cdeleg_available() && !pmu_sbi_is_fw_event(event))
>                 return rvpmu_cdeleg_event_map(event, econfig);
>         else
> @@ -1696,6 +1716,8 @@ static int rvpmu_starting_cpu(unsigned int cpu,
> struct hlist_node *node)
>                 enable_percpu_irq(riscv_pmu_irq, IRQ_TYPE_NONE);
>         }
>
> +       riscv_pmu_ctr_starting_cpu();
> +
>         if (sbi_pmu_snapshot_available())
>                 return pmu_sbi_snapshot_setup(pmu, cpu);
>
> @@ -1710,6 +1732,7 @@ static int rvpmu_dying_cpu(unsigned int cpu,
> struct hlist_node *node)
>
>         /* Disable all counters access for user mode now */
>         csr_write(CSR_SCOUNTEREN, 0x0);
> +       riscv_pmu_ctr_dying_cpu();
>
>         if (sbi_pmu_snapshot_available())
>                 return pmu_sbi_snapshot_disable();
> @@ -1833,6 +1856,29 @@ static void riscv_pmu_destroy(struct riscv_pmu *pmu)
>         cpuhp_state_remove_instance(CPUHP_AP_PERF_RISCV_STARTING, &pmu->node);
>  }
>
> +static int branch_records_alloc(struct riscv_pmu *pmu)
> +{
> +       struct branch_records __percpu *tmp_alloc_ptr;
> +       struct branch_records *records;
> +       struct cpu_hw_events *events;
> +       int cpu;
> +
> +       if (!riscv_pmu_ctr_supported(pmu))
> +               return 0;
> +
> +       tmp_alloc_ptr = alloc_percpu_gfp(struct branch_records, GFP_KERNEL);
> +       if (!tmp_alloc_ptr)
> +               return -ENOMEM;
> +
> +       for_each_possible_cpu(cpu) {
> +               events = per_cpu_ptr(pmu->hw_events, cpu);
> +               records = per_cpu_ptr(tmp_alloc_ptr, cpu);
> +               events->branches = records;
> +       }
> +
> +       return 0;
> +}
> +
>  static void rvpmu_event_init(struct perf_event *event)
>  {
>         /*
> @@ -1845,6 +1891,9 @@ static void rvpmu_event_init(struct perf_event *event)
>                 event->hw.flags |= PERF_EVENT_FLAG_USER_ACCESS;
>         else
>                 event->hw.flags |= PERF_EVENT_FLAG_LEGACY;
> +
> +       if (branch_sample_call_stack(event))
> +               event->attach_state |= PERF_ATTACH_TASK_DATA;
>  }
>
>  static void rvpmu_event_mapped(struct perf_event *event, struct mm_struct *mm)
> @@ -1992,6 +2041,15 @@ static int rvpmu_device_probe(struct
> platform_device *pdev)
>                 pmu->pmu.attr_groups = riscv_cdeleg_pmu_attr_groups;
>         else
>                 pmu->pmu.attr_groups = riscv_sbi_pmu_attr_groups;
> +
> +       ret = riscv_pmu_ctr_init(pmu);
> +       if (ret)
> +               goto out_free;
> +
> +       ret = branch_records_alloc(pmu);
> +       if (ret)
> +               goto out_ctr_finish;
> +
>         pmu->cmask = cmask;
>         pmu->ctr_add = rvpmu_ctr_add;
>         pmu->ctr_del = rvpmu_ctr_del;
> @@ -2008,6 +2066,10 @@ static int rvpmu_device_probe(struct
> platform_device *pdev)
>         pmu->csr_index = rvpmu_csr_index;
>         pmu->sched_task = pmu_sched_task;
>
> +       ret = cpuhp_state_add_instance(CPUHP_AP_PERF_RISCV_STARTING,
> &pmu->node);
> +       if (ret)
> +               goto out_ctr_finish;

This hotplug registration should be removed, since there is already
one in the original code.
Otherwise, It will cause the CPU hotplug down to loop infinitely.

Best regards,
Jimmy Ho

> +
>         ret = riscv_pm_pmu_register(pmu);
>         if (ret)
>                 goto out_unregister;
> @@ -2057,6 +2119,9 @@ static int rvpmu_device_probe(struct
> platform_device *pdev)
>  out_unregister:
>         riscv_pmu_destroy(pmu);
>
> +out_ctr_finish:
> +       riscv_pmu_ctr_finish(pmu);
> +
>  out_free:
>         kfree(pmu);
>         return ret;
>
> --
> 2.43.0
>
>
> _______________________________________________
> linux-riscv mailing list
> linux-riscv at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv


From chleroy at kernel.org  Wed Dec  3 23:39:03 2025
From: chleroy at kernel.org (Christophe Leroy (CS GROUP))
Date: Thu, 4 Dec 2025 08:39:03 +0100
Subject: [PATCH] ALSA: Do not build obsolete API
In-Reply-To: <20251203-old-alsa-v1-1-ac80704f52c3@ixit.cz>
References: <20251203-old-alsa-v1-1-ac80704f52c3@ixit.cz>
Message-ID: <b896d109-d707-4651-8bb0-6cf5071e46bf@kernel.org>



Le 03/12/2025 ? 23:34, David Heidelberg via B4 Relay a ?crit?:
> [Vous ne recevez pas souvent de courriers de devnull+david.ixit.cz at kernel.org. D?couvrez pourquoi ceci est important ? https://aka.ms/LearnAboutSenderIdentification ]
> 
> From: David Heidelberg <david at ixit.cz>
> 
> ALSA 0.9.0-rc3 is from 2002, 23 years old.
> 
> Signed-off-by: David Heidelberg <david at ixit.cz>
> ---
> Maybe I could drop also the code and Kconfig option?
> 
> David
> ---
>   arch/arm/configs/am200epdkit_defconfig    | 1 -
>   arch/arm/configs/lpc32xx_defconfig        | 1 -
>   arch/arm/configs/omap1_defconfig          | 1 -
>   arch/arm/configs/tegra_defconfig          | 1 -
>   arch/mips/configs/gcw0_defconfig          | 1 -
>   arch/mips/configs/loongson1_defconfig     | 1 -
>   arch/mips/configs/qi_lb60_defconfig       | 1 -
>   arch/mips/configs/rbtx49xx_defconfig      | 1 -
>   arch/mips/configs/rs90_defconfig          | 1 -
>   arch/powerpc/configs/85xx-hw.config       | 1 -
>   arch/powerpc/configs/86xx-hw.config       | 1 -
>   arch/powerpc/configs/mpc5200_defconfig    | 1 -
>   arch/powerpc/configs/ppc6xx_defconfig     | 1 -

For powerpc:

Reviewed-by: Christophe Leroy (CS GROUP) <chleroy at kernel.org>
Acked-by: Christophe Leroy (CS GROUP) <chleroy at kernel.org>



>   arch/sh/configs/edosk7760_defconfig       | 1 -
>   arch/sh/configs/se7724_defconfig          | 1 -
>   arch/sh/configs/sh7785lcr_32bit_defconfig | 1 -
>   sound/core/Kconfig                        | 2 +-
>   17 files changed, 1 insertion(+), 17 deletions(-)
> 
> diff --git a/arch/arm/configs/am200epdkit_defconfig b/arch/arm/configs/am200epdkit_defconfig
> index 134a559aba3dd..2367b1685c1cf 100644
> --- a/arch/arm/configs/am200epdkit_defconfig
> +++ b/arch/arm/configs/am200epdkit_defconfig
> @@ -68,7 +68,6 @@ CONFIG_SOUND=m
>   CONFIG_SND=m
>   CONFIG_SND_MIXER_OSS=m
>   CONFIG_SND_PCM_OSS=m
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>   # CONFIG_SND_VERBOSE_PROCFS is not set
>   CONFIG_SND_PXA2XX_AC97=m
>   CONFIG_USB_GADGET=y
> diff --git a/arch/arm/configs/lpc32xx_defconfig b/arch/arm/configs/lpc32xx_defconfig
> index 2bddb0924a8c0..b9e2e603cd95e 100644
> --- a/arch/arm/configs/lpc32xx_defconfig
> +++ b/arch/arm/configs/lpc32xx_defconfig
> @@ -113,7 +113,6 @@ CONFIG_LOGO=y
>   # CONFIG_LOGO_LINUX_VGA16 is not set
>   CONFIG_SOUND=y
>   CONFIG_SND=y
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>   # CONFIG_SND_VERBOSE_PROCFS is not set
>   CONFIG_SND_DEBUG=y
>   CONFIG_SND_DEBUG_VERBOSE=y
> diff --git a/arch/arm/configs/omap1_defconfig b/arch/arm/configs/omap1_defconfig
> index dee820474f444..df88763fc7c3d 100644
> --- a/arch/arm/configs/omap1_defconfig
> +++ b/arch/arm/configs/omap1_defconfig
> @@ -148,7 +148,6 @@ CONFIG_SOUND=y
>   CONFIG_SND=y
>   CONFIG_SND_MIXER_OSS=y
>   CONFIG_SND_PCM_OSS=y
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>   # CONFIG_SND_VERBOSE_PROCFS is not set
>   CONFIG_SND_DUMMY=y
>   CONFIG_SND_USB_AUDIO=y
> diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig
> index ce70ff07c978a..68aedaf92667a 100644
> --- a/arch/arm/configs/tegra_defconfig
> +++ b/arch/arm/configs/tegra_defconfig
> @@ -219,7 +219,6 @@ CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
>   CONFIG_LOGO=y
>   CONFIG_SOUND=y
>   CONFIG_SND=y
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>   # CONFIG_SND_DRIVERS is not set
>   CONFIG_SND_HDA_TEGRA=y
>   CONFIG_SND_HDA_INPUT_BEEP=y
> diff --git a/arch/mips/configs/gcw0_defconfig b/arch/mips/configs/gcw0_defconfig
> index fda9971bdd8d9..adb9fd62ddb0d 100644
> --- a/arch/mips/configs/gcw0_defconfig
> +++ b/arch/mips/configs/gcw0_defconfig
> @@ -79,7 +79,6 @@ CONFIG_LOGO=y
>   # CONFIG_LOGO_LINUX_VGA16 is not set
>   CONFIG_SOUND=y
>   CONFIG_SND=y
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>   # CONFIG_SND_PROC_FS is not set
>   # CONFIG_SND_DRIVERS is not set
>   # CONFIG_SND_SPI is not set
> diff --git a/arch/mips/configs/loongson1_defconfig b/arch/mips/configs/loongson1_defconfig
> index 02d29110f7024..1d9781ff96986 100644
> --- a/arch/mips/configs/loongson1_defconfig
> +++ b/arch/mips/configs/loongson1_defconfig
> @@ -119,7 +119,6 @@ CONFIG_WATCHDOG_SYSFS=y
>   CONFIG_LOONGSON1_WDT=y
>   CONFIG_SOUND=y
>   CONFIG_SND=y
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>   # CONFIG_SND_DRIVERS is not set
>   # CONFIG_SND_MIPS is not set
>   # CONFIG_SND_USB is not set
> diff --git a/arch/mips/configs/qi_lb60_defconfig b/arch/mips/configs/qi_lb60_defconfig
> index 5f5b0254d75e7..a1bb0792f6eb1 100644
> --- a/arch/mips/configs/qi_lb60_defconfig
> +++ b/arch/mips/configs/qi_lb60_defconfig
> @@ -81,7 +81,6 @@ CONFIG_LOGO=y
>   # CONFIG_LOGO_LINUX_CLUT224 is not set
>   CONFIG_SOUND=y
>   CONFIG_SND=y
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>   # CONFIG_SND_VERBOSE_PROCFS is not set
>   # CONFIG_SND_DRIVERS is not set
>   # CONFIG_SND_SPI is not set
> diff --git a/arch/mips/configs/rbtx49xx_defconfig b/arch/mips/configs/rbtx49xx_defconfig
> index 03a7bbe28a532..49c709d663beb 100644
> --- a/arch/mips/configs/rbtx49xx_defconfig
> +++ b/arch/mips/configs/rbtx49xx_defconfig
> @@ -53,7 +53,6 @@ CONFIG_TXX9_WDT=m
>   # CONFIG_VGA_ARB is not set
>   CONFIG_SOUND=m
>   CONFIG_SND=m
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>   # CONFIG_SND_VERBOSE_PROCFS is not set
>   # CONFIG_SND_DRIVERS is not set
>   # CONFIG_SND_PCI is not set
> diff --git a/arch/mips/configs/rs90_defconfig b/arch/mips/configs/rs90_defconfig
> index a53dd66e9b864..8382d535e6dc1 100644
> --- a/arch/mips/configs/rs90_defconfig
> +++ b/arch/mips/configs/rs90_defconfig
> @@ -105,7 +105,6 @@ CONFIG_LOGO=y
>   CONFIG_SOUND=y
>   CONFIG_SND=y
>   # CONFIG_SND_PCM_TIMER is not set
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>   # CONFIG_SND_PROC_FS is not set
>   # CONFIG_SND_DRIVERS is not set
>   # CONFIG_SND_MIPS is not set
> diff --git a/arch/powerpc/configs/85xx-hw.config b/arch/powerpc/configs/85xx-hw.config
> index 8aff832173977..2b19c20a9a2c4 100644
> --- a/arch/powerpc/configs/85xx-hw.config
> +++ b/arch/powerpc/configs/85xx-hw.config
> @@ -117,7 +117,6 @@ CONFIG_SND_INTEL8X0=y
>   CONFIG_SND_POWERPC_SOC=y
>   # CONFIG_SND_PPC is not set
>   CONFIG_SND_SOC=y
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>   # CONFIG_SND_USB is not set
>   CONFIG_SND=y
>   CONFIG_SOUND=y
> diff --git a/arch/powerpc/configs/86xx-hw.config b/arch/powerpc/configs/86xx-hw.config
> index e7bd265fae5a4..07f30ab881e59 100644
> --- a/arch/powerpc/configs/86xx-hw.config
> +++ b/arch/powerpc/configs/86xx-hw.config
> @@ -80,7 +80,6 @@ CONFIG_SERIO_LIBPS2=y
>   CONFIG_SND_INTEL8X0=y
>   CONFIG_SND_MIXER_OSS=y
>   CONFIG_SND_PCM_OSS=y
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>   CONFIG_SND=y
>   CONFIG_SOUND=y
>   CONFIG_ULI526X=y
> diff --git a/arch/powerpc/configs/mpc5200_defconfig b/arch/powerpc/configs/mpc5200_defconfig
> index c0fe5e76604a0..617650cea56a9 100644
> --- a/arch/powerpc/configs/mpc5200_defconfig
> +++ b/arch/powerpc/configs/mpc5200_defconfig
> @@ -75,7 +75,6 @@ CONFIG_FB_SM501=m
>   CONFIG_LOGO=y
>   CONFIG_SOUND=y
>   CONFIG_SND=y
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>   # CONFIG_SND_DRIVERS is not set
>   # CONFIG_SND_PCI is not set
>   # CONFIG_SND_PPC is not set
> diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig
> index b082c1fae13c9..787d707f64a42 100644
> --- a/arch/powerpc/configs/ppc6xx_defconfig
> +++ b/arch/powerpc/configs/ppc6xx_defconfig
> @@ -726,7 +726,6 @@ CONFIG_SND_OSSEMUL=y
>   CONFIG_SND_MIXER_OSS=m
>   CONFIG_SND_PCM_OSS=m
>   CONFIG_SND_DYNAMIC_MINORS=y
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>   CONFIG_SND_VERBOSE_PRINTK=y
>   CONFIG_SND_DEBUG=y
>   CONFIG_SND_DEBUG_VERBOSE=y
> diff --git a/arch/sh/configs/edosk7760_defconfig b/arch/sh/configs/edosk7760_defconfig
> index abeae220606a3..905fac1072845 100644
> --- a/arch/sh/configs/edosk7760_defconfig
> +++ b/arch/sh/configs/edosk7760_defconfig
> @@ -79,7 +79,6 @@ CONFIG_FB_TILEBLITTING=y
>   CONFIG_FB_SH_MOBILE_LCDC=m
>   CONFIG_SOUND=y
>   CONFIG_SND=y
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>   # CONFIG_SND_VERBOSE_PROCFS is not set
>   CONFIG_SND_VERBOSE_PRINTK=y
>   CONFIG_SND_SOC=y
> diff --git a/arch/sh/configs/se7724_defconfig b/arch/sh/configs/se7724_defconfig
> index 9e3a54936f76f..8ca46d704c8ba 100644
> --- a/arch/sh/configs/se7724_defconfig
> +++ b/arch/sh/configs/se7724_defconfig
> @@ -83,7 +83,6 @@ CONFIG_LOGO=y
>   # CONFIG_LOGO_SUPERH_VGA16 is not set
>   CONFIG_SOUND=y
>   CONFIG_SND=m
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>   # CONFIG_SND_DRIVERS is not set
>   # CONFIG_SND_SPI is not set
>   # CONFIG_SND_SUPERH is not set
> diff --git a/arch/sh/configs/sh7785lcr_32bit_defconfig b/arch/sh/configs/sh7785lcr_32bit_defconfig
> index eb63aa61b0465..5468cc53cddb4 100644
> --- a/arch/sh/configs/sh7785lcr_32bit_defconfig
> +++ b/arch/sh/configs/sh7785lcr_32bit_defconfig
> @@ -93,7 +93,6 @@ CONFIG_SND_PCM_OSS=y
>   CONFIG_SND_SEQUENCER_OSS=y
>   CONFIG_SND_HRTIMER=y
>   CONFIG_SND_DYNAMIC_MINORS=y
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>   # CONFIG_SND_VERBOSE_PROCFS is not set
>   CONFIG_SND_VERBOSE_PRINTK=y
>   CONFIG_SND_DEBUG=y
> diff --git a/sound/core/Kconfig b/sound/core/Kconfig
> index 48db44fa56feb..4e7bc370ffd7f 100644
> --- a/sound/core/Kconfig
> +++ b/sound/core/Kconfig
> @@ -155,7 +155,7 @@ config SND_MAX_CARDS
> 
>   config SND_SUPPORT_OLD_API
>          bool "Support old ALSA API"
> -       default y
> +       default n
>          help
>            Say Y here to support the obsolete ALSA PCM API (ver.0.9.0 rc3
>            or older).
> 
> ---
> base-commit: b2c27842ba853508b0da00187a7508eb3a96c8f7
> change-id: 20251203-old-alsa-fa2c2cb038e1
> 
> Best regards,
> --
> David Heidelberg <david at ixit.cz>
> 
> 



From alexander.stein at ew.tq-group.com  Wed Dec  3 23:44:12 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Thu, 04 Dec 2025 08:44:12 +0100
Subject: [PATCH V2] arm64: dts: imx8qm-ss-dma: correct the dma channels of lpuart
In-Reply-To: <20251203015956.116364-1-sherry.sun@nxp.com>
References: <20251203015956.116364-1-sherry.sun@nxp.com>
Message-ID: <3023939.e9J7NaK4W3@steina-w>

Hi,

Am Mittwoch, 3. Dezember 2025, 02:59:56 CET schrieb Sherry Sun:
> The commit 616effc0272b5 ("arm64: dts: imx8: Fix lpuart DMA channel
> order") swap uart rx and tx channel at common imx8-ss-dma.dtsi. But miss
> update imx8qm-ss-dma.dtsi.
> 
> The commit 5a8e9b022e569 ("arm64: dts: imx8qm-ss-dma: Pass lpuart
> dma-names") just simple add dma-names as binding doc requirement.
> 
> Correct lpuart0 - lpuart3 dma rx and tx channels, and use defines for
> the FSL_EDMA_RX flag.
> 
> Fixes: 5a8e9b022e56 ("arm64: dts: imx8qm-ss-dma: Pass lpuart dma-names")
> Signed-off-by: Sherry Sun <sherry.sun at nxp.com>

Reviewed-by: Alexander Stein <alexander.stein at ew.tq-group.com>

> ---
> Changes in V2:
> 1. Correct the fixes commit as Frank and Alexander suggested.
> ---
>  arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi
> index 5f24850bf322..974e193f8dcb 100644
> --- a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi
> +++ b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi
> @@ -172,25 +172,25 @@ &flexcan3 {
>  
>  &lpuart0 {
>  	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
> -	dmas = <&edma2 13 0 0>, <&edma2 12 0 1>;
> +	dmas = <&edma2 12 0 FSL_EDMA_RX>, <&edma2 13 0 0>;
>  	dma-names = "rx","tx";
>  };
>  
>  &lpuart1 {
>  	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
> -	dmas = <&edma2 15 0 0>, <&edma2 14 0 1>;
> +	dmas = <&edma2 14 0 FSL_EDMA_RX>, <&edma2 15 0 0>;
>  	dma-names = "rx","tx";
>  };
>  
>  &lpuart2 {
>  	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
> -	dmas = <&edma2 17 0 0>, <&edma2 16 0 1>;
> +	dmas = <&edma2 16 0 FSL_EDMA_RX>, <&edma2 17 0 0>;
>  	dma-names = "rx","tx";
>  };
>  
>  &lpuart3 {
>  	compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart";
> -	dmas = <&edma2 19 0 0>, <&edma2 18 0 1>;
> +	dmas = <&edma2 18 0 FSL_EDMA_RX>, <&edma2 19 0 0>;
>  	dma-names = "rx","tx";
>  };
>  
> 


-- 
TQ-Systems GmbH | M?hlstra?e 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht M?nchen, HRB 105018
Gesch?ftsf?hrer: Detlef Schneider, R?diger Stahl, Stefan Schneider
http://www.tq-group.com/




From anshuman.khandual at arm.com  Thu Dec  4 00:07:11 2025
From: anshuman.khandual at arm.com (Anshuman Khandual)
Date: Thu, 4 Dec 2025 13:37:11 +0530
Subject: [v3 PATCH] arm64: mm: Fix kexec failure after pte_mkwrite_novma()
 change
In-Reply-To: <20251204062722.3367201-1-jianpeng.chang.cn@windriver.com>
References: <20251204062722.3367201-1-jianpeng.chang.cn@windriver.com>
Message-ID: <8248c3fa-5c17-419c-ad8d-7abda988f0aa@arm.com>

On 04/12/25 11:57 AM, Jianpeng Chang wrote:
> Commit 143937ca51cc ("arm64, mm: avoid always making PTE dirty in
> pte_mkwrite()") modified pte_mkwrite_novma() to only clear PTE_RDONLY
> when the page is already dirty (PTE_DIRTY is set). While this optimization
> prevents unnecessary dirty page marking in normal memory management paths,
> it breaks kexec on some platforms like NXP LS1043.

Why is this problem only applicable for NXP LS1043 ? OR is that the only
platform you have observed the issue ? although that is problematic else
where as well.

> 
> The issue occurs in the kexec code path:
> 1. machine_kexec_post_load() calls trans_pgd_create_copy() to create a
>    writable copy of the linear mapping
> 2. _copy_pte() calls pte_mkwrite_novma() to ensure all pages in the copy
>    are writable for the new kernel image copying
> 3. With the new logic, clean pages (without PTE_DIRTY) remain read-only
> 4. When kexec tries to copy the new kernel image through the linear
>    mapping, it fails on read-only pages, causing the system to hang
>    after "Bye!"
> 
> The same issue affects hibernation which uses the same trans_pgd code path.
> 
> Fix this by marking pages dirty with pte_mkdirty() in _copy_pte(), which
> ensures pte_mkwrite_novma() clears PTE_RDONLY for both kexec and
> hibernation, making all pages in the temporary mapping writable regardless
> of their dirty state. This preserves the original commit's optimization
> for normal memory management while fixing the kexec/hibernation regression.
> 
> Using pte_mkdirty() causes redundant bit operations when the page is
> already writable (redundant PTE_RDONLY clearing), but this is acceptable
> since it's not a hot path and only affects kexec/hibernation scenarios.
> 
> Fixes: 143937ca51cc ("arm64, mm: avoid always making PTE dirty in pte_mkwrite()")
> Signed-off-by: Jianpeng Chang <jianpeng.chang.cn at windriver.com>
> Reviewed-by: Huang Ying <ying.huang at linux.alibaba.com>
> ---
> v3: 
>   - Add the description about pte_mkdirty in commit message
>   - Note that the redundant bit operations in commit message
>   - Fix the comments following the suggestions
> v2: https://lore.kernel.org/all/20251202022707.2720933-1-jianpeng.chang.cn at windriver.com/
>   - Use pte_mkwrite_novma(pte_mkdirty(pte)) instead of manual bit manipulation
>   - Updated comments to clarify pte_mkwrite_novma() alone cannot be used
> v1: https://lore.kernel.org/all/20251127034350.3600454-1-jianpeng.chang.cn at windriver.com/
> 
>  arch/arm64/mm/trans_pgd.c | 17 +++++++++++++++--
>  1 file changed, 15 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/mm/trans_pgd.c b/arch/arm64/mm/trans_pgd.c
> index 18543b603c77..766883780d2a 100644
> --- a/arch/arm64/mm/trans_pgd.c
> +++ b/arch/arm64/mm/trans_pgd.c
> @@ -40,8 +40,14 @@ static void _copy_pte(pte_t *dst_ptep, pte_t *src_ptep, unsigned long addr)
>  		 * Resume will overwrite areas that may be marked
>  		 * read only (code, rodata). Clear the RDONLY bit from
>  		 * the temporary mappings we use during restore.
> +		 *
> +		 * For both kexec and hibernation, writable accesses are required
> +		 * for all pages in the linear map to copy over new kernel image.
> +		 * Hence mark these pages dirty first via pte_mkdirty() to ensure
> +		 * pte_mkwrite_novma() subsequently clears PTE_RDONLY - providing
> +		 * required write access for the pages.
>  		 */
> -		__set_pte(dst_ptep, pte_mkwrite_novma(pte));
> +		__set_pte(dst_ptep, pte_mkwrite_novma(pte_mkdirty(pte)));
>  	} else if (!pte_none(pte)) {
>  		/*
>  		 * debug_pagealloc will removed the PTE_VALID bit if
> @@ -57,7 +63,14 @@ static void _copy_pte(pte_t *dst_ptep, pte_t *src_ptep, unsigned long addr)
>  		 */
>  		BUG_ON(!pfn_valid(pte_pfn(pte)));
>  
> -		__set_pte(dst_ptep, pte_mkvalid(pte_mkwrite_novma(pte)));
> +		/*
> +		 * For both kexec and hibernation, writable accesses are required
> +		 * for all pages in the linear map to copy over new kernel image.
> +		 * Hence mark these pages dirty first via pte_mkdirty() to ensure
> +		 * pte_mkwrite_novma() subsequently clears PTE_RDONLY - providing
> +		 * required write access for the pages.
> +		 */
> +		__set_pte(dst_ptep, pte_mkvalid(pte_mkwrite_novma(pte_mkdirty(pte))));
>  	}
>  }
>  



From lorenzo at kernel.org  Thu Dec  4 00:10:42 2025
From: lorenzo at kernel.org (Lorenzo Bianconi)
Date: Thu, 04 Dec 2025 09:10:42 +0100
Subject: [PATCH mt76 00/11] mt76: mt7996: preliminary support for MT7996
 NPU offloading
Message-ID: <20251204-mt76-npu-eagle-offload-v1-0-7819c52c0893@kernel.org>

Introduce preliminary support to enable NPU offloading in MT7996
(7990-Eagle) chipset.

---
Lorenzo Bianconi (11):
      wifi: mt76: mt7996: Fix NPU stop procedure
      wifi: mt76: npu: Add missing rx_token_size initialization
      wifi: mt76: always enable RRO queues for non-MT7992 chipset
      wifi: mt76: mt7996: Fix BAND2 tx queues initialization when NPU is enabled
      wifi: mt76: mt7996: Fix wdma_idx for MT7996 device if NPU is enabled
      wifi: mt76: mt7996: Add mt7992_npu_txrx_offload_init routine
      wifi: mt76: mt7996: Rename mt7996_npu_rxd_init() in mt7992_npu_rxd_init()
      wifi: mt76: mt7996: Add NPU support for MT7996 chipset
      wifi: mt76: mt7996: Integrate NPU in RRO session management
      wifi: mt76: mt7996: Integrate MT7996 init configuration for NPU
      wifi: mt76: mt7996: Integrate MT7996 dma configuration for NPU

 drivers/net/wireless/mediatek/mt76/dma.c           |   9 +-
 drivers/net/wireless/mediatek/mt76/mt76.h          |  10 +
 drivers/net/wireless/mediatek/mt76/mt7996/dma.c    | 132 ++++---
 drivers/net/wireless/mediatek/mt76/mt7996/init.c   |  47 ++-
 drivers/net/wireless/mediatek/mt76/mt7996/mac.c    |   3 +-
 drivers/net/wireless/mediatek/mt76/mt7996/main.c   |   4 +
 drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h |   2 +
 drivers/net/wireless/mediatek/mt76/mt7996/npu.c    | 394 +++++++++++++++++----
 drivers/net/wireless/mediatek/mt76/npu.c           |  31 ++
 9 files changed, 503 insertions(+), 129 deletions(-)
---
base-commit: 53d1548612670aa8b5d89745116cc33d9d172863
change-id: 20251202-mt76-npu-eagle-offload-0059fa426498

Best regards,
-- 
Lorenzo Bianconi <lorenzo at kernel.org>



From lorenzo at kernel.org  Thu Dec  4 00:10:43 2025
From: lorenzo at kernel.org (Lorenzo Bianconi)
Date: Thu, 04 Dec 2025 09:10:43 +0100
Subject: [PATCH mt76 01/11] wifi: mt76: mt7996: Fix NPU stop procedure
In-Reply-To: <20251204-mt76-npu-eagle-offload-v1-0-7819c52c0893@kernel.org>
References: <20251204-mt76-npu-eagle-offload-v1-0-7819c52c0893@kernel.org>
Message-ID: <20251204-mt76-npu-eagle-offload-v1-1-7819c52c0893@kernel.org>

Fix NPU stop procedure used during device L1 SER recovery moving
mt7996_npu_hw_stop routine before disabling rx NAPIs.
Add missing usleep_range in mt7996_npu_hw_stop().

Tested-by: Hui Ma <hui.ma at airoha.com>
Fixes: 377aa17d2aedc ("wifi: mt76: mt7996: Add NPU offload support to MT7996 driver")
Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
---
 drivers/net/wireless/mediatek/mt76/mt7996/mac.c |  3 +--
 drivers/net/wireless/mediatek/mt76/mt7996/npu.c | 23 ++++++++++++++---------
 2 files changed, 15 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
index 2560e2f46e89a4bc46e21d796fca80b7decefa5c..2a8e91f59b0cafd46c97a9ac73b78f1ba087b5d8 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
@@ -2543,6 +2543,7 @@ void mt7996_mac_reset_work(struct work_struct *work)
 	if (mtk_wed_device_active(&dev->mt76.mmio.wed))
 		mtk_wed_device_stop(&dev->mt76.mmio.wed);
 
+	mt7996_npu_hw_stop(dev);
 	ieee80211_stop_queues(mt76_hw(dev));
 
 	set_bit(MT76_RESET, &dev->mphy.state);
@@ -2569,8 +2570,6 @@ void mt7996_mac_reset_work(struct work_struct *work)
 
 	mutex_lock(&dev->mt76.mutex);
 
-	mt7996_npu_hw_stop(dev);
-
 	mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED);
 
 	if (mt7996_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/npu.c b/drivers/net/wireless/mediatek/mt76/mt7996/npu.c
index 29bb735da4cb8f5998c9483567c65f3e3530c771..067ef647e404073173833aad3a2800d6591a5188 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/npu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/npu.c
@@ -320,33 +320,38 @@ int mt7996_npu_hw_init(struct mt7996_dev *dev)
 int mt7996_npu_hw_stop(struct mt7996_dev *dev)
 {
 	struct airoha_npu *npu;
-	int i, err;
+	int i, err = 0;
 	u32 info;
 
+	mutex_lock(&dev->mt76.mutex);
+
 	npu = rcu_dereference_protected(dev->mt76.mmio.npu, &dev->mt76.mutex);
 	if (!npu)
-		return 0;
+		goto unlock;
 
 	err = mt76_npu_send_msg(npu, 4, WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR,
 				0, GFP_KERNEL);
 	if (err)
-		return err;
+		goto unlock;
 
 	for (i = 0; i < 10; i++) {
 		err = mt76_npu_get_msg(npu, 3, WLAN_FUNC_GET_WAIT_NPU_INFO,
 				       &info, GFP_KERNEL);
-		if (err)
-			continue;
+		if (!err && !info)
+			break;
 
-		if (info) {
-			err = -ETIMEDOUT;
-			continue;
-		}
+		err = -ETIMEDOUT;
+		usleep_range(10000, 15000);
 	}
 
 	if (!err)
 		err = mt76_npu_send_msg(npu, 6,
 					WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR,
 					0, GFP_KERNEL);
+	else
+		dev_err(dev->mt76.dev, "npu stop failed\n");
+unlock:
+	mutex_unlock(&dev->mt76.mutex);
+
 	return err;
 }

-- 
2.52.0



From lorenzo at kernel.org  Thu Dec  4 00:10:44 2025
From: lorenzo at kernel.org (Lorenzo Bianconi)
Date: Thu, 04 Dec 2025 09:10:44 +0100
Subject: [PATCH mt76 02/11] wifi: mt76: npu: Add missing rx_token_size
 initialization
In-Reply-To: <20251204-mt76-npu-eagle-offload-v1-0-7819c52c0893@kernel.org>
References: <20251204-mt76-npu-eagle-offload-v1-0-7819c52c0893@kernel.org>
Message-ID: <20251204-mt76-npu-eagle-offload-v1-2-7819c52c0893@kernel.org>

Add missing rx_token_size initialization for NPU offloading.

Tested-by: Hui Ma <hui.ma at airoha.com>
Fixes: 7fb554b1b623 ("wifi: mt76: Introduce the NPU generic layer")
Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
---
 drivers/net/wireless/mediatek/mt76/npu.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/wireless/mediatek/mt76/npu.c b/drivers/net/wireless/mediatek/mt76/npu.c
index ec36975f6dc946f5dbc5ab6029b0574fbc602615..9679237f739842bd44497e0b1022a868cb3a0d6c 100644
--- a/drivers/net/wireless/mediatek/mt76/npu.c
+++ b/drivers/net/wireless/mediatek/mt76/npu.c
@@ -457,6 +457,7 @@ int mt76_npu_init(struct mt76_dev *dev, phys_addr_t phy_addr, int type)
 	dev->mmio.npu_type = type;
 	/* NPU offloading requires HW-RRO for RX packet reordering. */
 	dev->hwrro_mode = MT76_HWRRO_V3_1;
+	dev->rx_token_size = 32768;
 
 	rcu_assign_pointer(dev->mmio.npu, npu);
 	rcu_assign_pointer(dev->mmio.ppe_dev, ppe_dev);

-- 
2.52.0



From lorenzo at kernel.org  Thu Dec  4 00:10:45 2025
From: lorenzo at kernel.org (Lorenzo Bianconi)
Date: Thu, 04 Dec 2025 09:10:45 +0100
Subject: [PATCH mt76 03/11] wifi: mt76: always enable RRO queues for
 non-MT7992 chipset
In-Reply-To: <20251204-mt76-npu-eagle-offload-v1-0-7819c52c0893@kernel.org>
References: <20251204-mt76-npu-eagle-offload-v1-0-7819c52c0893@kernel.org>
Message-ID: <20251204-mt76-npu-eagle-offload-v1-3-7819c52c0893@kernel.org>

MT7996 NPU binary requires to initialize NPU desc_base after configuring
ring_size. This is a preliminary patch to enable NPU offload for MT7996
(7990-Eagle) chipset.

Tested-by: Hui Ma <hui.ma at airoha.com>
Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
---
 drivers/net/wireless/mediatek/mt76/dma.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index f240016ed9f0ead27e98e350f4fdb818e1686781..fc2ac463e4e78872f9e4e7dacbdaa34bac383fb7 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -6,6 +6,7 @@
 #include <linux/dma-mapping.h>
 #include "mt76.h"
 #include "dma.h"
+#include "mt76_connac.h"
 
 static struct mt76_txwi_cache *
 mt76_alloc_txwi(struct mt76_dev *dev)
@@ -188,16 +189,18 @@ mt76_dma_queue_magic_cnt_init(struct mt76_dev *dev, struct mt76_queue *q)
 static void
 mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q)
 {
-	Q_WRITE(q, desc_base, q->desc_dma);
-	if ((q->flags & MT_QFLAG_WED_RRO_EN) && !mt76_npu_device_active(dev))
+	if ((q->flags & MT_QFLAG_WED_RRO_EN) &&
+	    (!is_mt7992(dev) || !mt76_npu_device_active(dev)))
 		Q_WRITE(q, ring_size, MT_DMA_RRO_EN | q->ndesc);
 	else
 		Q_WRITE(q, ring_size, q->ndesc);
 
 	if (mt76_queue_is_npu_tx(q)) {
-		writel(q->desc_dma, &q->regs->desc_base);
 		writel(q->ndesc, &q->regs->ring_size);
+		writel(q->desc_dma, &q->regs->desc_base);
 	}
+
+	Q_WRITE(q, desc_base, q->desc_dma);
 	q->head = Q_READ(q, dma_idx);
 	q->tail = q->head;
 }

-- 
2.52.0



From lorenzo at kernel.org  Thu Dec  4 00:10:47 2025
From: lorenzo at kernel.org (Lorenzo Bianconi)
Date: Thu, 04 Dec 2025 09:10:47 +0100
Subject: [PATCH mt76 05/11] wifi: mt76: mt7996: Fix wdma_idx for MT7996
 device if NPU is enabled
In-Reply-To: <20251204-mt76-npu-eagle-offload-v1-0-7819c52c0893@kernel.org>
References: <20251204-mt76-npu-eagle-offload-v1-0-7819c52c0893@kernel.org>
Message-ID: <20251204-mt76-npu-eagle-offload-v1-5-7819c52c0893@kernel.org>

This is a preliminary patch to enable NPU offload for MT7996
(7990-Eagle) chipset.

Tested-by: Hui Ma <hui.ma at airoha.com>
Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
---
 drivers/net/wireless/mediatek/mt76/mt7996/main.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index beed795edb24c67e1b7b44fe87fd5de125a21d94..d9df3a72f4ef8170722cca626538ea526c04781b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -2204,6 +2204,10 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
 		path->mtk_wdma.wdma_idx = wed->wdma_idx;
 	else
 #endif
+	if (is_mt7996(&dev->mt76) && mt76_npu_device_active(&dev->mt76) &&
+	    msta_link->wcid.phy_idx == MT_BAND2)
+		path->mtk_wdma.wdma_idx = 1;
+	else
 		path->mtk_wdma.wdma_idx = link->mt76.band_idx;
 	path->mtk_wdma.bss = link->mt76.idx;
 	path->mtk_wdma.queue = 0;

-- 
2.52.0



From lorenzo at kernel.org  Thu Dec  4 00:10:46 2025
From: lorenzo at kernel.org (Lorenzo Bianconi)
Date: Thu, 04 Dec 2025 09:10:46 +0100
Subject: [PATCH mt76 04/11] wifi: mt76: mt7996: Fix BAND2 tx queues
 initialization when NPU is enabled
In-Reply-To: <20251204-mt76-npu-eagle-offload-v1-0-7819c52c0893@kernel.org>
References: <20251204-mt76-npu-eagle-offload-v1-0-7819c52c0893@kernel.org>
Message-ID: <20251204-mt76-npu-eagle-offload-v1-4-7819c52c0893@kernel.org>

Fix BAND2 tx queues initialization for MT7996 chipset when NPU is
enabled. This is a preliminary patch to enable NPU offload for MT7996
(7990-Eagle) chipset.

Tested-by: Hui Ma <hui.ma at airoha.com>
Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
---
 drivers/net/wireless/mediatek/mt76/mt7996/init.c   | 18 ++++++++++++------
 drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h |  1 +
 2 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
index 00a8286bd136862d756706d6ad8098a2ddc3ca4e..9fbe4235de0d0d42776d5661fa1c297e431b8d27 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
@@ -668,8 +668,9 @@ static int mt7996_register_phy(struct mt7996_dev *dev, enum mt76_band_id band)
 		return 0;
 
 	if (dev->hif2 &&
-	    ((is_mt7996(&dev->mt76) && band == MT_BAND2) ||
-	     (is_mt7992(&dev->mt76) && band == MT_BAND1))) {
+	    ((is_mt7992(&dev->mt76) && band == MT_BAND1) ||
+	     (is_mt7996(&dev->mt76) && band == MT_BAND2 &&
+	      !mt76_npu_device_active(&dev->mt76)))) {
 		hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
 		wed = &dev->mt76.mmio.wed_hif2;
 	}
@@ -709,14 +710,19 @@ static int mt7996_register_phy(struct mt7996_dev *dev, enum mt76_band_id band)
 	/* init wiphy according to mphy and phy */
 	mt7996_init_wiphy_band(mphy->hw, phy);
 
-	if (is_mt7996(&dev->mt76) && !dev->hif2 && band == MT_BAND1) {
+	if (is_mt7996(&dev->mt76) &&
+	    ((band == MT_BAND1 && !dev->hif2) ||
+	     (band == MT_BAND2 && mt76_npu_device_active(&dev->mt76)))) {
 		int i;
 
 		for (i = 0; i <= MT_TXQ_PSD; i++)
-			mphy->q_tx[i] = dev->mt76.phys[MT_BAND0]->q_tx[0];
+			mphy->q_tx[i] = dev->mt76.phys[band - 1]->q_tx[0];
 	} else {
-		ret = mt7996_init_tx_queues(mphy->priv, MT_TXQ_ID(band),
-					    MT7996_TX_RING_SIZE,
+		int size = is_mt7996(&dev->mt76) &&
+			   mt76_npu_device_active(&dev->mt76)
+			   ? MT7996_NPU_TX_RING_SIZE / 2 : MT7996_TX_RING_SIZE;
+
+		ret = mt7996_init_tx_queues(mphy->priv, MT_TXQ_ID(band), size,
 					    MT_TXQ_RING_BASE(band) + hif1_ofs,
 					    wed);
 		if (ret)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
index 7a884311800ea8cfc0e302b2a140a4072ce18b69..29a77d75099033727f5df5a487216c043fd04f85 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
@@ -29,6 +29,7 @@
 #define MT7996_RX_RING_SIZE		1536
 #define MT7996_RX_MCU_RING_SIZE		512
 #define MT7996_RX_MCU_RING_SIZE_WA	1024
+#define MT7996_NPU_TX_RING_SIZE		1024
 /* scatter-gather of mcu event is not supported in connac3 */
 #define MT7996_RX_MCU_BUF_SIZE		(2048 + \
 					 SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))

-- 
2.52.0



From lorenzo at kernel.org  Thu Dec  4 00:10:48 2025
From: lorenzo at kernel.org (Lorenzo Bianconi)
Date: Thu, 04 Dec 2025 09:10:48 +0100
Subject: [PATCH mt76 06/11] wifi: mt76: mt7996: Add
 mt7992_npu_txrx_offload_init routine
In-Reply-To: <20251204-mt76-npu-eagle-offload-v1-0-7819c52c0893@kernel.org>
References: <20251204-mt76-npu-eagle-offload-v1-0-7819c52c0893@kernel.org>
Message-ID: <20251204-mt76-npu-eagle-offload-v1-6-7819c52c0893@kernel.org>

Introduce mt7992_npu_txrx_offload_init utility routine.
This is a preliminary patch to enable NPU offload for MT7996
(7990-Eagle) chipset.

Tested-by: Hui Ma <hui.ma at airoha.com>
Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
---
 drivers/net/wireless/mediatek/mt76/mt7996/npu.c | 63 +++++++++++++++----------
 1 file changed, 37 insertions(+), 26 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/npu.c b/drivers/net/wireless/mediatek/mt76/mt7996/npu.c
index 067ef647e404073173833aad3a2800d6591a5188..d79f8dfbd7faa7695ea54b632ac86063fa8ffe3a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/npu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/npu.c
@@ -8,34 +8,14 @@
 
 #include "mt7996.h"
 
-static int mt7996_npu_offload_init(struct mt7996_dev *dev,
-				   struct airoha_npu *npu)
+static int mt7992_npu_txrx_offload_init(struct mt7996_dev *dev,
+					struct airoha_npu *npu)
 {
+	u32 hif1_ofs = dev->hif2 ? MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0) : 0;
 	phys_addr_t phy_addr = dev->mt76.mmio.phy_addr;
-	u32 val, hif1_ofs = 0, dma_addr;
+	u32 dma_addr;
 	int i, err;
 
-	err = mt76_npu_get_msg(npu, 0, WLAN_FUNC_GET_WAIT_NPU_VERSION,
-			       &val, GFP_KERNEL);
-	if (err) {
-		dev_warn(dev->mt76.dev, "failed getting NPU fw version\n");
-		return err;
-	}
-
-	dev_info(dev->mt76.dev, "NPU version: %0d.%d\n",
-		 (val >> 16) & 0xffff, val & 0xffff);
-
-	err = mt76_npu_send_msg(npu, 0, WLAN_FUNC_SET_WAIT_PCIE_PORT_TYPE,
-				dev->mt76.mmio.npu_type, GFP_KERNEL);
-	if (err) {
-		dev_warn(dev->mt76.dev,
-			 "failed setting NPU wlan PCIe port type\n");
-		return err;
-	}
-
-	if (dev->hif2)
-		hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
-
 	for (i = MT_BAND0; i < MT_BAND2; i++) {
 		dma_addr = phy_addr;
 		if (i)
@@ -56,7 +36,7 @@ static int mt7996_npu_offload_init(struct mt7996_dev *dev,
 					MT7996_RX_RING_SIZE, GFP_KERNEL);
 		if (err) {
 			dev_warn(dev->mt76.dev,
-				 "failed setting NPU wlan PCIe desc size\n");
+				 "failed setting NPU wlan rx desc size\n");
 			return err;
 		}
 
@@ -97,10 +77,41 @@ static int mt7996_npu_offload_init(struct mt7996_dev *dev,
 				phy_addr + MT_RRO_ACK_SN_CTRL, GFP_KERNEL);
 	if (err) {
 		dev_warn(dev->mt76.dev,
-			 "failed setting NPU wlan rro_ack_sn desc addr\n");
+			 "failed setting NPU wlan tx desc addr\n");
 		return err;
 	}
 
+	return 0;
+}
+
+static int mt7996_npu_offload_init(struct mt7996_dev *dev,
+				   struct airoha_npu *npu)
+{
+	u32 val;
+	int err;
+
+	err = mt76_npu_get_msg(npu, 0, WLAN_FUNC_GET_WAIT_NPU_VERSION,
+			       &val, GFP_KERNEL);
+	if (err) {
+		dev_warn(dev->mt76.dev, "failed getting NPU fw version\n");
+		return err;
+	}
+
+	dev_info(dev->mt76.dev, "NPU version: %0d.%d\n",
+		 (val >> 16) & 0xffff, val & 0xffff);
+
+	err = mt76_npu_send_msg(npu, 0, WLAN_FUNC_SET_WAIT_PCIE_PORT_TYPE,
+				dev->mt76.mmio.npu_type, GFP_KERNEL);
+	if (err) {
+		dev_warn(dev->mt76.dev,
+			 "failed setting NPU wlan PCIe port type\n");
+		return err;
+	}
+
+	err = mt7992_npu_txrx_offload_init(dev, npu);
+	if (err)
+		return err;
+
 	err = mt76_npu_send_msg(npu, 0, WLAN_FUNC_SET_WAIT_TOKEN_ID_SIZE,
 				MT7996_HW_TOKEN_SIZE, GFP_KERNEL);
 	if (err)

-- 
2.52.0



From lorenzo at kernel.org  Thu Dec  4 00:10:49 2025
From: lorenzo at kernel.org (Lorenzo Bianconi)
Date: Thu, 04 Dec 2025 09:10:49 +0100
Subject: [PATCH mt76 07/11] wifi: mt76: mt7996: Rename
 mt7996_npu_rxd_init() in mt7992_npu_rxd_init()
In-Reply-To: <20251204-mt76-npu-eagle-offload-v1-0-7819c52c0893@kernel.org>
References: <20251204-mt76-npu-eagle-offload-v1-0-7819c52c0893@kernel.org>
Message-ID: <20251204-mt76-npu-eagle-offload-v1-7-7819c52c0893@kernel.org>

This is a preliminary patch to enable NPU offload for MT7996
(7990-Eagle) chipset.

Tested-by: Hui Ma <hui.ma at airoha.com>
Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
---
 drivers/net/wireless/mediatek/mt76/mt7996/npu.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/npu.c b/drivers/net/wireless/mediatek/mt76/mt7996/npu.c
index d79f8dfbd7faa7695ea54b632ac86063fa8ffe3a..a9569278f73bf83454a0357e93602837c6ccaa86 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/npu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/npu.c
@@ -122,7 +122,7 @@ static int mt7996_npu_offload_init(struct mt7996_dev *dev,
 	return 0;
 }
 
-static int mt7996_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu)
+static int mt7992_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu)
 {
 	u32 val;
 	int err;
@@ -304,7 +304,7 @@ int mt7996_npu_hw_init(struct mt7996_dev *dev)
 	if (err)
 		goto unlock;
 
-	err = mt7996_npu_rxd_init(dev, npu);
+	err = mt7992_npu_rxd_init(dev, npu);
 	if (err)
 		goto unlock;
 

-- 
2.52.0



From lorenzo at kernel.org  Thu Dec  4 00:10:50 2025
From: lorenzo at kernel.org (Lorenzo Bianconi)
Date: Thu, 04 Dec 2025 09:10:50 +0100
Subject: [PATCH mt76 08/11] wifi: mt76: mt7996: Add NPU support for MT7996
 chipset
In-Reply-To: <20251204-mt76-npu-eagle-offload-v1-0-7819c52c0893@kernel.org>
References: <20251204-mt76-npu-eagle-offload-v1-0-7819c52c0893@kernel.org>
Message-ID: <20251204-mt76-npu-eagle-offload-v1-8-7819c52c0893@kernel.org>

Introduce support for MT7996 (7990-Eagle) chipset in MT7996 npu
configuration codebase.

Tested-by: Hui Ma <hui.ma at airoha.com>
Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
---
 drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h |   1 +
 drivers/net/wireless/mediatek/mt76/mt7996/npu.c    | 308 ++++++++++++++++++---
 2 files changed, 277 insertions(+), 32 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
index 29a77d75099033727f5df5a487216c043fd04f85..de31385aa966116b34e545de92623a214bddc8f8 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
@@ -30,6 +30,7 @@
 #define MT7996_RX_MCU_RING_SIZE		512
 #define MT7996_RX_MCU_RING_SIZE_WA	1024
 #define MT7996_NPU_TX_RING_SIZE		1024
+#define MT7996_NPU_RX_RING_SIZE		1024
 /* scatter-gather of mcu event is not supported in connac3 */
 #define MT7996_RX_MCU_BUF_SIZE		(2048 + \
 					 SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/npu.c b/drivers/net/wireless/mediatek/mt76/mt7996/npu.c
index a9569278f73bf83454a0357e93602837c6ccaa86..1a77a7dc103762c8cc998508348e418858c30029 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/npu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/npu.c
@@ -17,21 +17,6 @@ static int mt7992_npu_txrx_offload_init(struct mt7996_dev *dev,
 	int i, err;
 
 	for (i = MT_BAND0; i < MT_BAND2; i++) {
-		dma_addr = phy_addr;
-		if (i)
-			dma_addr += MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND1) + 0x90 +
-				    hif1_ofs;
-		else
-			dma_addr += MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND0) + 0x80;
-
-		err = mt76_npu_send_msg(npu, i, WLAN_FUNC_SET_WAIT_PCIE_ADDR,
-					dma_addr, GFP_KERNEL);
-		if (err) {
-			dev_warn(dev->mt76.dev,
-				 "failed setting NPU wlan PCIe desc addr\n");
-			return err;
-		}
-
 		err = mt76_npu_send_msg(npu, i, WLAN_FUNC_SET_WAIT_DESC,
 					MT7996_RX_RING_SIZE, GFP_KERNEL);
 		if (err) {
@@ -84,6 +69,134 @@ static int mt7992_npu_txrx_offload_init(struct mt7996_dev *dev,
 	return 0;
 }
 
+static int mt7996_npu_txrx_offload_init(struct mt7996_dev *dev,
+					struct airoha_npu *npu)
+{
+	u32 hif1_ofs = dev->hif2 ? MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0) : 0;
+	phys_addr_t phy_addr = dev->mt76.mmio.phy_addr;
+	u32 dma_addr;
+	int err;
+
+	/* npu rx rro ring0 */
+	err = mt76_npu_send_msg(npu, 0, WLAN_FUNC_SET_WAIT_DESC,
+				MT7996_RX_RING_SIZE, GFP_KERNEL);
+	if (err) {
+		dev_warn(dev->mt76.dev,
+			 "failed setting NPU wlan rx desc size\n");
+		return err;
+	}
+
+	/* npu rx rro ring1 */
+	err = mt76_npu_send_msg(npu, 2, WLAN_FUNC_SET_WAIT_DESC,
+				MT7996_NPU_RX_RING_SIZE, GFP_KERNEL);
+	if (err) {
+		dev_warn(dev->mt76.dev,
+			 "failed setting NPU wlan rx desc size\n");
+		return err;
+	}
+
+	/* msdu pg  2GHz */
+	dma_addr = phy_addr + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND0) + 0xa0;
+	err = mt76_npu_send_msg(npu, 5, WLAN_FUNC_SET_WAIT_PCIE_ADDR,
+				dma_addr, GFP_KERNEL);
+	if (err) {
+		dev_warn(dev->mt76.dev,
+			 "failed setting NPU wlan PCIe desc addr\n");
+		return err;
+	}
+
+	err = mt76_npu_send_msg(npu, 5, WLAN_FUNC_SET_WAIT_DESC,
+				MT7996_NPU_RX_RING_SIZE / 4, GFP_KERNEL);
+	if (err) {
+		dev_warn(dev->mt76.dev,
+			 "failed setting NPU wlan rx desc size\n");
+		return err;
+	}
+
+	/* msdu pg 5GHz */
+	dma_addr = phy_addr + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND1) + 0xb0;
+	err = mt76_npu_send_msg(npu, 6, WLAN_FUNC_SET_WAIT_PCIE_ADDR,
+				dma_addr, GFP_KERNEL);
+	if (err) {
+		dev_warn(dev->mt76.dev,
+			 "failed setting NPU wlan PCIe desc addr\n");
+		return err;
+	}
+
+	err = mt76_npu_send_msg(npu, 6, WLAN_FUNC_SET_WAIT_DESC,
+				MT7996_NPU_RX_RING_SIZE / 2, GFP_KERNEL);
+	if (err) {
+		dev_warn(dev->mt76.dev,
+			 "failed setting NPU wlan rx desc size\n");
+		return err;
+	}
+
+	/* msdu pg 6GHz */
+	dma_addr = phy_addr + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND2) + 0xc0;
+	err = mt76_npu_send_msg(npu, 7, WLAN_FUNC_SET_WAIT_PCIE_ADDR,
+				dma_addr, GFP_KERNEL);
+	if (err) {
+		dev_warn(dev->mt76.dev,
+			 "failed setting NPU wlan PCIe desc addr\n");
+		return err;
+	}
+
+	err = mt76_npu_send_msg(npu, 7, WLAN_FUNC_SET_WAIT_DESC,
+				MT7996_NPU_RX_RING_SIZE, GFP_KERNEL);
+	if (err) {
+		dev_warn(dev->mt76.dev,
+			 "failed setting NPU wlan rx desc size\n");
+		return err;
+	}
+
+	/* ind cmd ring */
+	err = mt76_npu_send_msg(npu, 8, WLAN_FUNC_SET_WAIT_PCIE_ADDR,
+				phy_addr + MT_RXQ_RRO_IND_RING_BASE,
+				GFP_KERNEL);
+	if (err) {
+		dev_warn(dev->mt76.dev,
+			 "failed setting NPU wlan PCIe desc addr\n");
+		return err;
+	}
+
+	err = mt76_npu_send_msg(npu, 8, WLAN_FUNC_SET_WAIT_DESC,
+				MT7996_RX_RING_SIZE, GFP_KERNEL);
+	if (err) {
+		dev_warn(dev->mt76.dev,
+			 "failed setting NPU wlan rx desc size\n");
+		return err;
+	}
+
+	err = mt76_npu_send_msg(npu, 3, WLAN_FUNC_SET_WAIT_TX_RING_PCIE_ADDR,
+				phy_addr + MT_RRO_ACK_SN_CTRL, GFP_KERNEL);
+	if (err) {
+		dev_warn(dev->mt76.dev,
+			 "failed setting NPU wlan tx desc addr\n");
+		return err;
+	}
+
+	/* npu tx */
+	dma_addr = phy_addr + MT_TXQ_RING_BASE(1) + 0x120;
+	err = mt76_npu_send_msg(npu, 0, WLAN_FUNC_SET_WAIT_TX_RING_PCIE_ADDR,
+				dma_addr, GFP_KERNEL);
+	if (err) {
+		dev_warn(dev->mt76.dev,
+			 "failed setting NPU wlan tx desc addr\n");
+		return err;
+	}
+
+	dma_addr = phy_addr + MT_TXQ_RING_BASE(0) + 0x150 + hif1_ofs;
+	err = mt76_npu_send_msg(npu, 2, WLAN_FUNC_SET_WAIT_TX_RING_PCIE_ADDR,
+				dma_addr, GFP_KERNEL);
+	if (err) {
+		dev_warn(dev->mt76.dev,
+			 "failed setting NPU wlan tx desc addr\n");
+		return err;
+	}
+
+	return 0;
+}
+
 static int mt7996_npu_offload_init(struct mt7996_dev *dev,
 				   struct airoha_npu *npu)
 {
@@ -108,7 +221,11 @@ static int mt7996_npu_offload_init(struct mt7996_dev *dev,
 		return err;
 	}
 
-	err = mt7992_npu_txrx_offload_init(dev, npu);
+	if (is_mt7996(&dev->mt76))
+		err = mt7996_npu_txrx_offload_init(dev, npu);
+	else
+		err = mt7992_npu_txrx_offload_init(dev, npu);
+
 	if (err)
 		return err;
 
@@ -157,15 +274,84 @@ static int mt7992_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu)
 	return 0;
 }
 
-static int mt7996_npu_txd_init(struct mt7996_dev *dev, struct airoha_npu *npu)
+static int mt7996_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu)
 {
-	int i, err;
+	u32 val;
+	int err;
 
-	for (i = MT_BAND0; i < MT_BAND2; i++) {
+	err = mt76_npu_get_msg(npu, 0, WLAN_FUNC_GET_WAIT_RXDESC_BASE,
+			       &val, GFP_KERNEL);
+	if (err) {
+		dev_warn(dev->mt76.dev,
+			 "failed retriving NPU wlan rx ring0 addr\n");
+		return err;
+	}
+	writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_BAND0].regs->desc_base);
+
+	err = mt76_npu_get_msg(npu, 2, WLAN_FUNC_GET_WAIT_RXDESC_BASE,
+			       &val, GFP_KERNEL);
+	if (err) {
+		dev_warn(dev->mt76.dev,
+			 "failed retriving NPU wlan rx ring2 addr\n");
+		return err;
+	}
+	writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_BAND2].regs->desc_base);
+
+	/* msdu pg ring */
+	err = mt76_npu_get_msg(npu, 10, WLAN_FUNC_GET_WAIT_RXDESC_BASE,
+			       &val, GFP_KERNEL);
+	if (err) {
+		dev_warn(dev->mt76.dev,
+			 "failed retriving NPU wlan msdu pg ring addr\n");
+		return err;
+	}
+	writel(val, &dev->mt76.q_rx[MT_RXQ_MSDU_PAGE_BAND0].regs->desc_base);
+
+	err = mt76_npu_get_msg(npu, 11, WLAN_FUNC_GET_WAIT_RXDESC_BASE,
+			       &val, GFP_KERNEL);
+	if (err) {
+		dev_warn(dev->mt76.dev,
+			 "failed retriving NPU wlan msdu pg ring addr\n");
+		return err;
+	}
+	writel(val, &dev->mt76.q_rx[MT_RXQ_MSDU_PAGE_BAND1].regs->desc_base);
+
+	err = mt76_npu_get_msg(npu, 12, WLAN_FUNC_GET_WAIT_RXDESC_BASE,
+			       &val, GFP_KERNEL);
+	if (err) {
+		dev_warn(dev->mt76.dev,
+			 "failed retriving NPU wlan msdu pg ring addr\n");
+		return err;
+	}
+	writel(val, &dev->mt76.q_rx[MT_RXQ_MSDU_PAGE_BAND2].regs->desc_base);
+
+	/* ind_cmd ring */
+	err = mt76_npu_get_msg(npu, 8, WLAN_FUNC_GET_WAIT_RXDESC_BASE,
+			       &val, GFP_KERNEL);
+	if (err) {
+		dev_warn(dev->mt76.dev,
+			 "failed retriving NPU wlan ind_cmd ring addr\n");
+		return err;
+	}
+	writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_IND].regs->desc_base);
+
+	return 0;
+}
+
+static int mt7996_npu_txd_init(struct mt7996_dev *dev, struct airoha_npu *npu)
+{
+	const enum mt76_band_id band_list[] = {
+		MT_BAND0,
+		is_mt7996(&dev->mt76) ? MT_BAND2 : MT_BAND1,
+	};
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(band_list); i++) {
+		int err, band = band_list[i], phy_id;
 		dma_addr_t dma_addr;
-		u32 val;
+		u32 val, size;
 
-		err = mt76_npu_get_msg(npu, i + 5,
+		err = mt76_npu_get_msg(npu, band + 5,
 				       WLAN_FUNC_GET_WAIT_RXDESC_BASE,
 				       &val, GFP_KERNEL);
 		if (err) {
@@ -173,14 +359,20 @@ static int mt7996_npu_txd_init(struct mt7996_dev *dev, struct airoha_npu *npu)
 				 "failed retriving NPU wlan tx ring addr\n");
 			return err;
 		}
-		writel(val, &dev->mt76.phys[i]->q_tx[0]->regs->desc_base);
 
-		if (!dmam_alloc_coherent(dev->mt76.dma_dev,
-					 256 * MT7996_TX_RING_SIZE,
+		phy_id = is_mt7996(&dev->mt76) ? band == MT_BAND0 ? 1 : 0
+					       : band;
+		writel(val, &dev->mt76.phys[phy_id]->q_tx[0]->regs->desc_base);
+
+		size = is_mt7996(&dev->mt76) ? band == MT_BAND2
+					     ? MT7996_NPU_TX_RING_SIZE
+					     : MT7996_NPU_RX_RING_SIZE / 2
+					     : MT7996_TX_RING_SIZE;
+		if (!dmam_alloc_coherent(dev->mt76.dma_dev, 256 * size,
 					 &dma_addr, GFP_KERNEL))
 			return -ENOMEM;
 
-		err = mt76_npu_send_msg(npu, i,
+		err = mt76_npu_send_msg(npu, band,
 					WLAN_FUNC_SET_WAIT_TX_BUF_SPACE_HW_BASE,
 					dma_addr, GFP_KERNEL);
 		if (err) {
@@ -189,12 +381,11 @@ static int mt7996_npu_txd_init(struct mt7996_dev *dev, struct airoha_npu *npu)
 			return err;
 		}
 
-		if (!dmam_alloc_coherent(dev->mt76.dma_dev,
-					 256 * MT7996_TX_RING_SIZE,
+		if (!dmam_alloc_coherent(dev->mt76.dma_dev, 256 * size,
 					 &dma_addr, GFP_KERNEL))
 			return -ENOMEM;
 
-		err = mt76_npu_send_msg(npu, i + 5,
+		err = mt76_npu_send_msg(npu, band + 5,
 					WLAN_FUNC_SET_WAIT_TX_BUF_SPACE_HW_BASE,
 					dma_addr, GFP_KERNEL);
 		if (err) {
@@ -207,7 +398,7 @@ static int mt7996_npu_txd_init(struct mt7996_dev *dev, struct airoha_npu *npu)
 					 &dma_addr, GFP_KERNEL))
 			return -ENOMEM;
 
-		err = mt76_npu_send_msg(npu, i + 10,
+		err = mt76_npu_send_msg(npu, band + 10,
 					WLAN_FUNC_SET_WAIT_TX_BUF_SPACE_HW_BASE,
 					dma_addr, GFP_KERNEL);
 		if (err) {
@@ -223,8 +414,9 @@ static int mt7996_npu_txd_init(struct mt7996_dev *dev, struct airoha_npu *npu)
 static int mt7996_npu_rx_event_init(struct mt7996_dev *dev,
 				    struct airoha_npu *npu)
 {
-	struct mt76_queue *q = &dev->mt76.q_rx[MT_RXQ_MAIN_WA];
+	int qid = is_mt7996(&dev->mt76) ? MT_RXQ_TXFREE_BAND0 : MT_RXQ_MAIN_WA;
 	phys_addr_t phy_addr = dev->mt76.mmio.phy_addr;
+	struct mt76_queue *q = &dev->mt76.q_rx[qid];
 	int err;
 
 	err = mt76_npu_send_msg(npu, 0,
@@ -244,7 +436,8 @@ static int mt7996_npu_rx_event_init(struct mt7996_dev *dev,
 		return err;
 	}
 
-	phy_addr += MT_RXQ_RING_BASE(MT_RXQ_MAIN_WA) + 0x20;
+	phy_addr += MT_RXQ_RING_BASE(qid);
+	phy_addr += is_mt7996(&dev->mt76) ? 0x90 : 0x20;
 	err = mt76_npu_send_msg(npu, 10, WLAN_FUNC_SET_WAIT_PCIE_ADDR,
 				phy_addr, GFP_KERNEL);
 	if (err)
@@ -253,11 +446,54 @@ static int mt7996_npu_rx_event_init(struct mt7996_dev *dev,
 	return err;
 }
 
+static int mt7996_npu_set_pcie_addr(struct mt7996_dev *dev,
+				    struct airoha_npu *npu)
+{
+	u32 hif1_ofs = dev->hif2 ? MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0) : 0;
+	dma_addr_t dma_addr = dev->mt76.mmio.phy_addr;
+	int err;
+
+	dma_addr += MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND0) + 0x80;
+	err = mt76_npu_send_msg(npu, 0, WLAN_FUNC_SET_WAIT_PCIE_ADDR,
+				dma_addr, GFP_KERNEL);
+	if (err) {
+		dev_warn(dev->mt76.dev,
+			 "failed setting NPU wlan PCIe desc addr\n");
+		return err;
+	}
+
+	dma_addr = dev->mt76.mmio.phy_addr + hif1_ofs;
+	if (is_mt7996(&dev->mt76)) {
+		dma_addr += MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND2) + 0x60;
+		err = mt76_npu_send_msg(npu, 2, WLAN_FUNC_SET_WAIT_PCIE_ADDR,
+					dma_addr, GFP_KERNEL);
+	} else {
+		dma_addr += MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND1) + 0x90;
+		err = mt76_npu_send_msg(npu, 1, WLAN_FUNC_SET_WAIT_PCIE_ADDR,
+					dma_addr, GFP_KERNEL);
+	}
+
+	if (err)
+		dev_warn(dev->mt76.dev,
+			 "failed setting NPU wlan PCIe desc addr\n");
+
+	return err;
+}
+
 static int mt7996_npu_tx_done_init(struct mt7996_dev *dev,
 				   struct airoha_npu *npu)
 {
 	int err;
 
+	/* rro ring cpu idx */
+	err = mt76_npu_send_msg(npu, 15, WLAN_FUNC_SET_WAIT_PCIE_ADDR,
+				0, GFP_KERNEL);
+	if (err) {
+		dev_warn(dev->mt76.dev,
+			 "failed setting NPU wlan PCIe desc addr\n");
+		return err;
+	}
+
 	err = mt76_npu_send_msg(npu, 2, WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR,
 				0, GFP_KERNEL);
 	if (err) {
@@ -304,7 +540,11 @@ int mt7996_npu_hw_init(struct mt7996_dev *dev)
 	if (err)
 		goto unlock;
 
-	err = mt7992_npu_rxd_init(dev, npu);
+	if (is_mt7996(&dev->mt76))
+		err = mt7996_npu_rxd_init(dev, npu);
+	else
+		err = mt7992_npu_rxd_init(dev, npu);
+
 	if (err)
 		goto unlock;
 
@@ -316,6 +556,10 @@ int mt7996_npu_hw_init(struct mt7996_dev *dev)
 	if (err)
 		goto unlock;
 
+	err = mt7996_npu_set_pcie_addr(dev, npu);
+	if (err)
+		goto unlock;
+
 	err = mt7996_npu_tx_done_init(dev, npu);
 	if (err)
 		goto unlock;

-- 
2.52.0



From lorenzo at kernel.org  Thu Dec  4 00:10:51 2025
From: lorenzo at kernel.org (Lorenzo Bianconi)
Date: Thu, 04 Dec 2025 09:10:51 +0100
Subject: [PATCH mt76 09/11] wifi: mt76: mt7996: Integrate NPU in RRO
 session management
In-Reply-To: <20251204-mt76-npu-eagle-offload-v1-0-7819c52c0893@kernel.org>
References: <20251204-mt76-npu-eagle-offload-v1-0-7819c52c0893@kernel.org>
Message-ID: <20251204-mt76-npu-eagle-offload-v1-9-7819c52c0893@kernel.org>

Add NPU integration in RRO 3.0 session management.
This is a preliminary patch to enable NPU offload for MT7996
(7990-Eagle) chipset.

Tested-by: Hui Ma <hui.ma at airoha.com>
Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
---
 drivers/net/wireless/mediatek/mt76/mt76.h        | 10 ++++++++
 drivers/net/wireless/mediatek/mt76/mt7996/init.c | 16 ++++++++++++-
 drivers/net/wireless/mediatek/mt76/npu.c         | 30 ++++++++++++++++++++++++
 3 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index d05e83ea1cacc43512f37743e1708390c3cb2f35..eefc3f555f8afea2af67517683d522b657e20b7b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -1649,6 +1649,9 @@ void mt76_npu_txdesc_cleanup(struct mt76_queue *q, int index);
 int mt76_npu_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 			  struct net_device *dev, enum tc_setup_type type,
 			  void *type_data);
+int mt76_npu_send_txrx_addr(struct mt76_dev *dev, int ifindex,
+			    u32 direction, u32 i_count_addr,
+			    u32 o_status_addr, u32 o_count_addr);
 #else
 static inline void mt76_npu_check_ppe(struct mt76_dev *dev,
 				      struct sk_buff *skb, u32 info)
@@ -1707,6 +1710,13 @@ static inline int mt76_npu_net_setup_tc(struct ieee80211_hw *hw,
 {
 	return -EOPNOTSUPP;
 }
+
+static inline int mt76_npu_send_txrx_addr(struct mt76_dev *dev, int ifindex,
+					  u32 direction, u32 i_count_addr,
+					  u32 o_status_addr, u32 o_count_addr)
+{
+	return -EOPNOTSUPP;
+}
 #endif /* CONFIG_MT76_NPU */
 
 static inline bool mt76_npu_device_active(struct mt76_dev *dev)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
index 9fbe4235de0d0d42776d5661fa1c297e431b8d27..03c1ccb49ef02ebe9c2ae91db836593e680ee2c0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
@@ -941,6 +941,12 @@ static int mt7996_wed_rro_init(struct mt7996_dev *dev)
 			addr++;
 		}
 
+		if (is_mt7996(&dev->mt76) &&
+		    mt76_npu_device_active(&dev->mt76))
+			mt76_npu_send_txrx_addr(&dev->mt76, 0, i,
+					dev->wed_rro.addr_elem[i].phy_addr,
+					0, 0);
+
 #ifdef CONFIG_NET_MEDIATEK_SOC_WED
 		if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
 		    mtk_wed_get_rx_capa(&dev->mt76.mmio.wed)) {
@@ -1001,6 +1007,10 @@ static int mt7996_wed_rro_init(struct mt7996_dev *dev)
 		addr++;
 	}
 
+	if (is_mt7996(&dev->mt76) && mt76_npu_device_active(&dev->mt76))
+		mt76_npu_send_txrx_addr(&dev->mt76, 1, 0,
+					dev->wed_rro.session.phy_addr, 0, 0);
+
 	mt7996_rro_hw_init(dev);
 
 	return mt7996_dma_rro_init(dev);
@@ -1087,8 +1097,12 @@ static void mt7996_wed_rro_work(struct work_struct *work)
 				     list);
 		list_del_init(&e->list);
 
-		if (mt76_npu_device_active(&dev->mt76))
+		if (mt76_npu_device_active(&dev->mt76)) {
+			if (is_mt7996(&dev->mt76))
+				mt76_npu_send_txrx_addr(&dev->mt76, 3, e->id,
+							0, 0, 0);
 			goto reset_session;
+		}
 
 		for (i = 0; i < MT7996_RRO_WINDOW_MAX_LEN; i++) {
 			void *ptr = dev->wed_rro.session.ptr;
diff --git a/drivers/net/wireless/mediatek/mt76/npu.c b/drivers/net/wireless/mediatek/mt76/npu.c
index 9679237f739842bd44497e0b1022a868cb3a0d6c..bc8f2012be9dbe2c7fc1fc885b6135d796d8c0d6 100644
--- a/drivers/net/wireless/mediatek/mt76/npu.c
+++ b/drivers/net/wireless/mediatek/mt76/npu.c
@@ -390,6 +390,36 @@ int mt76_npu_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 }
 EXPORT_SYMBOL_GPL(mt76_npu_net_setup_tc);
 
+int mt76_npu_send_txrx_addr(struct mt76_dev *dev, int ifindex,
+			    u32 direction, u32 i_count_addr,
+			    u32 o_status_addr, u32 o_count_addr)
+{
+	struct {
+		__le32 dir;
+		__le32 in_count_addr;
+		__le32 out_status_addr;
+		__le32 out_count_addr;
+	} info = {
+		.dir = cpu_to_le32(direction),
+		.in_count_addr = cpu_to_le32(i_count_addr),
+		.out_status_addr = cpu_to_le32(o_status_addr),
+		.out_count_addr = cpu_to_le32(o_count_addr),
+	};
+	struct airoha_npu *npu;
+	int err = -ENODEV;
+
+	rcu_read_lock();
+	npu = rcu_dereference(dev->mmio.npu);
+	if (npu)
+		err = airoha_npu_wlan_send_msg(npu, ifindex,
+				WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR,
+				&info, sizeof(info), GFP_ATOMIC);
+	rcu_read_unlock();
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(mt76_npu_send_txrx_addr);
+
 void mt76_npu_disable_irqs(struct mt76_dev *dev)
 {
 	struct airoha_npu *npu;

-- 
2.52.0



From lorenzo at kernel.org  Thu Dec  4 00:10:52 2025
From: lorenzo at kernel.org (Lorenzo Bianconi)
Date: Thu, 04 Dec 2025 09:10:52 +0100
Subject: [PATCH mt76 10/11] wifi: mt76: mt7996: Integrate MT7996 init
 configuration for NPU
In-Reply-To: <20251204-mt76-npu-eagle-offload-v1-0-7819c52c0893@kernel.org>
References: <20251204-mt76-npu-eagle-offload-v1-0-7819c52c0893@kernel.org>
Message-ID: <20251204-mt76-npu-eagle-offload-v1-10-7819c52c0893@kernel.org>

Add NPU integration in MT7996 init codebase for MT7996 chipset.
This is a preliminary patch to enable NPU offload for MT7996
(7990-Eagle) chipset.

Tested-by: Hui Ma <hui.ma at airoha.com>
Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
---
 drivers/net/wireless/mediatek/mt76/mt7996/init.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
index 03c1ccb49ef02ebe9c2ae91db836593e680ee2c0..526a2cb298fd7f9dc8d0fcdd8de0e4071c07338f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
@@ -592,7 +592,7 @@ static void mt7996_mac_init_basic_rates(struct mt7996_dev *dev)
 void mt7996_mac_init(struct mt7996_dev *dev)
 {
 #define HIF_TXD_V2_1	0x21
-	int i;
+	int i, rx_path_type;
 
 	mt76_clear(dev, MT_MDP_DCR2, MT_MDP_DCR2_RX_TRANS_SHORT);
 
@@ -606,11 +606,16 @@ void mt7996_mac_init(struct mt7996_dev *dev)
 	}
 
 	/* rro module init */
-	if (dev->hif2)
+	if (dev->hif2) {
+		if (mt76_npu_device_active(&dev->mt76))
+			rx_path_type = is_mt7996(&dev->mt76) ? 6 : 8;
+		else
+			rx_path_type = is_mt7996(&dev->mt76) ? 2 : 7;
 		mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE,
-				   is_mt7996(&dev->mt76) ? 2 : 7);
-	else
+				   rx_path_type);
+	} else {
 		mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 0);
+	}
 
 	if (mt7996_has_hwrro(dev)) {
 		u16 timeout;

-- 
2.52.0



From lorenzo at kernel.org  Thu Dec  4 00:10:53 2025
From: lorenzo at kernel.org (Lorenzo Bianconi)
Date: Thu, 04 Dec 2025 09:10:53 +0100
Subject: [PATCH mt76 11/11] wifi: mt76: mt7996: Integrate MT7996 dma
 configuration for NPU
In-Reply-To: <20251204-mt76-npu-eagle-offload-v1-0-7819c52c0893@kernel.org>
References: <20251204-mt76-npu-eagle-offload-v1-0-7819c52c0893@kernel.org>
Message-ID: <20251204-mt76-npu-eagle-offload-v1-11-7819c52c0893@kernel.org>

Add NPU integration in MT7996 dma codebase for MT7996 chipset.
This is a preliminary patch to enable NPU offload for MT7996
(7990-Eagle) chipset.

Tested-by: Hui Ma <hui.ma at airoha.com>
Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
---
 drivers/net/wireless/mediatek/mt76/mt7996/dma.c | 132 +++++++++++++++---------
 1 file changed, 86 insertions(+), 46 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c
index 274b273df1ee941e83db2bf2f9771cbdd4da8b6f..07212d93bc62df69720963f5ba04090bc82003fc 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c
@@ -128,15 +128,27 @@ static void mt7996_dma_config(struct mt7996_dev *dev)
 
 	/* data tx queue */
 	if (is_mt7996(&dev->mt76)) {
-		TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7996_TXQ_BAND0);
 		if (dev->hif2) {
-			/* default bn1:ring19 bn2:ring21 */
-			TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1,
-				   MT7996_TXQ_BAND1);
-			TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND2,
-				   MT7996_TXQ_BAND2);
+			if (mt76_npu_device_active(&dev->mt76)) {
+				TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND2,
+					   MT7996_TXQ_BAND2);
+				TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND0,
+					   MT7996_TXQ_BAND0);
+				TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND1,
+					   MT7996_TXQ_BAND1);
+			} else {
+				/* default bn1:ring19 bn2:ring21 */
+				TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0,
+					   MT7996_TXQ_BAND0);
+				TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1,
+					   MT7996_TXQ_BAND1);
+				TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND2,
+					   MT7996_TXQ_BAND2);
+			}
 		} else {
 			/* single pcie bn0/1:ring18 bn2:ring19 */
+			TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0,
+				   MT7996_TXQ_BAND0);
 			TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND1,
 				   MT7996_TXQ_BAND1);
 		}
@@ -350,6 +362,9 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset)
 	if (!mt7996_has_wa(dev) || mt76_npu_device_active(&dev->mt76))
 		irq_mask &= ~(MT_INT_RX(MT_RXQ_MAIN_WA) |
 			      MT_INT_RX(MT_RXQ_BAND1_WA));
+	if (is_mt7996(&dev->mt76) && mt76_npu_device_active(&dev->mt76))
+		irq_mask &= ~(MT_INT_RX(MT_RXQ_TXFREE_BAND0) |
+			      MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND2));
 	irq_mask = reset ? MT_INT_MCU_CMD : irq_mask;
 
 	mt7996_irq_enable(dev, irq_mask);
@@ -430,39 +445,48 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset)
 			   MT_WFDMA_HOST_CONFIG_BAND1_PCIE1 |
 			   MT_WFDMA_HOST_CONFIG_BAND2_PCIE1);
 
-		if (is_mt7996(&dev->mt76))
-			mt76_set(dev, MT_WFDMA_HOST_CONFIG,
-				 MT_WFDMA_HOST_CONFIG_BAND2_PCIE1);
-		else
+		if (is_mt7996(&dev->mt76)) {
+			if (mt76_npu_device_active(&dev->mt76))
+				mt76_set(dev, MT_WFDMA_HOST_CONFIG,
+					 MT_WFDMA_HOST_CONFIG_BAND0_PCIE1);
+			else
+				mt76_set(dev, MT_WFDMA_HOST_CONFIG,
+					 MT_WFDMA_HOST_CONFIG_BAND2_PCIE1);
+		} else {
 			mt76_set(dev, MT_WFDMA_HOST_CONFIG,
 				 MT_WFDMA_HOST_CONFIG_BAND1_PCIE1);
+		}
 
 		/* AXI read outstanding number */
 		mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL,
 			 MT_WFDMA_AXI_R2A_CTRL_OUTSTAND_MASK, 0x14);
 
-		if (dev->hif2->speed < PCIE_SPEED_5_0GT ||
-		    (dev->hif2->speed == PCIE_SPEED_5_0GT &&
-		     dev->hif2->width < PCIE_LNK_X2)) {
-			mt76_rmw(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs,
-				 WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK,
-				 FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK,
-					    0x1));
-			mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL2,
-				 MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK,
-				 FIELD_PREP(MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK,
-					    0x1));
-		} else if (dev->hif2->speed < PCIE_SPEED_8_0GT ||
-			   (dev->hif2->speed == PCIE_SPEED_8_0GT &&
-			    dev->hif2->width < PCIE_LNK_X2)) {
-			mt76_rmw(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs,
-				 WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK,
-				 FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK,
-					    0x2));
-			mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL2,
-				 MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK,
-				 FIELD_PREP(MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK,
-					    0x2));
+		if (!is_mt7996(&dev->mt76) ||
+		    !mt76_npu_device_active(&dev->mt76)) {
+			if (dev->hif2->speed < PCIE_SPEED_5_0GT ||
+			    (dev->hif2->speed == PCIE_SPEED_5_0GT &&
+			     dev->hif2->width < PCIE_LNK_X2)) {
+				mt76_rmw(dev,
+					 WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs,
+					 WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK,
+					 FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK,
+						    0x1));
+				mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL2,
+					 MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK,
+					 FIELD_PREP(MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK,
+						    0x1));
+			} else if (dev->hif2->speed < PCIE_SPEED_8_0GT ||
+				   (dev->hif2->speed == PCIE_SPEED_8_0GT &&
+				    dev->hif2->width < PCIE_LNK_X2)) {
+				mt76_rmw(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs,
+					 WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK,
+					 FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK,
+						    0x2));
+				mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL2,
+					 MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK,
+					 FIELD_PREP(MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK,
+						    0x2));
+			}
 		}
 
 		/* WFDMA rx threshold */
@@ -497,7 +521,7 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset)
 int mt7996_dma_rro_init(struct mt7996_dev *dev)
 {
 	struct mt76_dev *mdev = &dev->mt76;
-	u32 irq_mask;
+	u32 irq_mask, size;
 	int ret;
 
 	if (dev->mt76.hwrro_mode == MT76_HWRRO_V3_1) {
@@ -545,10 +569,12 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev)
 	if (mtk_wed_device_active(&mdev->mmio.wed) &&
 	    mtk_wed_get_rx_capa(&mdev->mmio.wed))
 		mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0].wed = &mdev->mmio.wed;
+
+	size = is_mt7996(mdev) && mt76_npu_device_active(mdev)
+	       ? MT7996_NPU_RX_RING_SIZE / 4 : MT7996_RX_RING_SIZE;
 	ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0],
 			       MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND0),
-			       MT7996_RX_RING_SIZE,
-			       MT7996_RX_MSDU_PAGE_SIZE,
+			       size, MT7996_RX_MSDU_PAGE_SIZE,
 			       MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND0));
 	if (ret)
 		return ret;
@@ -560,10 +586,12 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev)
 		if (mtk_wed_device_active(&mdev->mmio.wed) &&
 		    mtk_wed_get_rx_capa(&mdev->mmio.wed))
 			mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1].wed = &mdev->mmio.wed;
+
+		size = is_mt7996(mdev) && mt76_npu_device_active(mdev)
+		       ? MT7996_NPU_RX_RING_SIZE / 2 : MT7996_RX_RING_SIZE;
 		ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1],
 				       MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND1),
-				       MT7996_RX_RING_SIZE,
-				       MT7996_RX_MSDU_PAGE_SIZE,
+				       size, MT7996_RX_MSDU_PAGE_SIZE,
 				       MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND1));
 		if (ret)
 			return ret;
@@ -576,10 +604,12 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev)
 		if (mtk_wed_device_active(&mdev->mmio.wed) &&
 		    mtk_wed_get_rx_capa(&mdev->mmio.wed))
 			mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2].wed = &mdev->mmio.wed;
+
+		size = is_mt7996(mdev) && mt76_npu_device_active(mdev)
+		       ? MT7996_NPU_RX_RING_SIZE : MT7996_RX_RING_SIZE;
 		ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2],
 				       MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND2),
-				       MT7996_RX_RING_SIZE,
-				       MT7996_RX_MSDU_PAGE_SIZE,
+				       size, MT7996_RX_MSDU_PAGE_SIZE,
 				       MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND2));
 		if (ret)
 			return ret;
@@ -642,11 +672,16 @@ int mt7996_dma_init(struct mt7996_dev *dev)
 	mt7996_dma_disable(dev, true);
 
 	/* init tx queue */
-	ret = mt7996_init_tx_queues(&dev->phy,
-				    MT_TXQ_ID(dev->mphy.band_idx),
-				    MT7996_TX_RING_SIZE,
-				    MT_TXQ_RING_BASE(0),
-				    wed);
+	if (is_mt7996(&dev->mt76) && mt76_npu_device_active(&dev->mt76))
+		ret = mt7996_init_tx_queues(&dev->phy, MT_TXQ_ID(0),
+					    MT7996_NPU_TX_RING_SIZE,
+					    MT_TXQ_RING_BASE(0) + hif1_ofs,
+					    NULL);
+	else
+		ret = mt7996_init_tx_queues(&dev->phy,
+					    MT_TXQ_ID(dev->mphy.band_idx),
+					    MT7996_TX_RING_SIZE,
+					    MT_TXQ_RING_BASE(0), wed);
 	if (ret)
 		return ret;
 
@@ -859,16 +894,21 @@ int mt7996_dma_init(struct mt7996_dev *dev)
 		}
 
 		if (mt7996_band_valid(dev, MT_BAND2)) {
+			u32 size;
+
 			/* rx rro data queue for band2 */
 			dev->mt76.q_rx[MT_RXQ_RRO_BAND2].flags =
 				MT_WED_RRO_Q_DATA(1) | MT_QFLAG_WED_RRO_EN;
 			if (mtk_wed_device_active(wed) &&
 			    mtk_wed_get_rx_capa(wed))
 				dev->mt76.q_rx[MT_RXQ_RRO_BAND2].wed = wed;
+
+			size = is_mt7996(&dev->mt76) &&
+			       mt76_npu_device_active(&dev->mt76)
+			       ? MT7996_NPU_RX_RING_SIZE : MT7996_RX_RING_SIZE;
 			ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_RRO_BAND2],
 					       MT_RXQ_ID(MT_RXQ_RRO_BAND2),
-					       MT7996_RX_RING_SIZE,
-					       MT7996_RX_BUF_SIZE,
+					       size, MT7996_RX_BUF_SIZE,
 					       MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND2) + hif1_ofs);
 			if (ret)
 				return ret;

-- 
2.52.0



From Jianpeng.Chang.CN at windriver.com  Thu Dec  4 00:16:28 2025
From: Jianpeng.Chang.CN at windriver.com (Chang, Jianpeng (CN))
Date: Thu, 4 Dec 2025 16:16:28 +0800
Subject: [v3 PATCH] arm64: mm: Fix kexec failure after pte_mkwrite_novma()
 change
In-Reply-To: <8248c3fa-5c17-419c-ad8d-7abda988f0aa@arm.com>
References: <20251204062722.3367201-1-jianpeng.chang.cn@windriver.com>
 <8248c3fa-5c17-419c-ad8d-7abda988f0aa@arm.com>
Message-ID: <4050b918-2ff8-4625-b1b6-8bb43e82c906@windriver.com>



On 12/4/2025 4:07 PM, Anshuman Khandual wrote:
> CAUTION: This email comes from a non Wind River email account!
> Do not click links or open attachments unless you recognize the sender and know the content is safe.
> 
> On 04/12/25 11:57 AM, Jianpeng Chang wrote:
>> Commit 143937ca51cc ("arm64, mm: avoid always making PTE dirty in
>> pte_mkwrite()") modified pte_mkwrite_novma() to only clear PTE_RDONLY
>> when the page is already dirty (PTE_DIRTY is set). While this optimization
>> prevents unnecessary dirty page marking in normal memory management paths,
>> it breaks kexec on some platforms like NXP LS1043.
> 
> Why is this problem only applicable for NXP LS1043 ? OR is that the only
> platform you have observed the issue ? although that is problematic else
> where as well.

Not only 1043. I found it on the NXP LS1043, and I have both NXP LS1043 
and LS1046 boards available. They both have this issue.

> 
>>
>> The issue occurs in the kexec code path:
>> 1. machine_kexec_post_load() calls trans_pgd_create_copy() to create a
>>     writable copy of the linear mapping
>> 2. _copy_pte() calls pte_mkwrite_novma() to ensure all pages in the copy
>>     are writable for the new kernel image copying
>> 3. With the new logic, clean pages (without PTE_DIRTY) remain read-only
>> 4. When kexec tries to copy the new kernel image through the linear
>>     mapping, it fails on read-only pages, causing the system to hang
>>     after "Bye!"
>>
>> The same issue affects hibernation which uses the same trans_pgd code path.
>>
>> Fix this by marking pages dirty with pte_mkdirty() in _copy_pte(), which
>> ensures pte_mkwrite_novma() clears PTE_RDONLY for both kexec and
>> hibernation, making all pages in the temporary mapping writable regardless
>> of their dirty state. This preserves the original commit's optimization
>> for normal memory management while fixing the kexec/hibernation regression.
>>
>> Using pte_mkdirty() causes redundant bit operations when the page is
>> already writable (redundant PTE_RDONLY clearing), but this is acceptable
>> since it's not a hot path and only affects kexec/hibernation scenarios.
>>
>> Fixes: 143937ca51cc ("arm64, mm: avoid always making PTE dirty in pte_mkwrite()")
>> Signed-off-by: Jianpeng Chang <jianpeng.chang.cn at windriver.com>
>> Reviewed-by: Huang Ying <ying.huang at linux.alibaba.com>
>> ---
>> v3:
>>    - Add the description about pte_mkdirty in commit message
>>    - Note that the redundant bit operations in commit message
>>    - Fix the comments following the suggestions
>> v2: https://lore.kernel.org/all/20251202022707.2720933-1-jianpeng.chang.cn at windriver.com/
>>    - Use pte_mkwrite_novma(pte_mkdirty(pte)) instead of manual bit manipulation
>>    - Updated comments to clarify pte_mkwrite_novma() alone cannot be used
>> v1: https://lore.kernel.org/all/20251127034350.3600454-1-jianpeng.chang.cn at windriver.com/
>>
>>   arch/arm64/mm/trans_pgd.c | 17 +++++++++++++++--
>>   1 file changed, 15 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/arm64/mm/trans_pgd.c b/arch/arm64/mm/trans_pgd.c
>> index 18543b603c77..766883780d2a 100644
>> --- a/arch/arm64/mm/trans_pgd.c
>> +++ b/arch/arm64/mm/trans_pgd.c
>> @@ -40,8 +40,14 @@ static void _copy_pte(pte_t *dst_ptep, pte_t *src_ptep, unsigned long addr)
>>                 * Resume will overwrite areas that may be marked
>>                 * read only (code, rodata). Clear the RDONLY bit from
>>                 * the temporary mappings we use during restore.
>> +              *
>> +              * For both kexec and hibernation, writable accesses are required
>> +              * for all pages in the linear map to copy over new kernel image.
>> +              * Hence mark these pages dirty first via pte_mkdirty() to ensure
>> +              * pte_mkwrite_novma() subsequently clears PTE_RDONLY - providing
>> +              * required write access for the pages.
>>                 */
>> -             __set_pte(dst_ptep, pte_mkwrite_novma(pte));
>> +             __set_pte(dst_ptep, pte_mkwrite_novma(pte_mkdirty(pte)));
>>        } else if (!pte_none(pte)) {
>>                /*
>>                 * debug_pagealloc will removed the PTE_VALID bit if
>> @@ -57,7 +63,14 @@ static void _copy_pte(pte_t *dst_ptep, pte_t *src_ptep, unsigned long addr)
>>                 */
>>                BUG_ON(!pfn_valid(pte_pfn(pte)));
>>
>> -             __set_pte(dst_ptep, pte_mkvalid(pte_mkwrite_novma(pte)));
>> +             /*
>> +              * For both kexec and hibernation, writable accesses are required
>> +              * for all pages in the linear map to copy over new kernel image.
>> +              * Hence mark these pages dirty first via pte_mkdirty() to ensure
>> +              * pte_mkwrite_novma() subsequently clears PTE_RDONLY - providing
>> +              * required write access for the pages.
>> +              */
>> +             __set_pte(dst_ptep, pte_mkvalid(pte_mkwrite_novma(pte_mkdirty(pte))));
>>        }
>>   }
>>
> 



From ruanjinjie at huawei.com  Thu Dec  4 00:21:08 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 4 Dec 2025 16:21:08 +0800
Subject: [PATCH v9 01/16] arm64: Remove unused _TIF_WORK_MASK
In-Reply-To: <20251204082123.2792067-1-ruanjinjie@huawei.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
Message-ID: <20251204082123.2792067-2-ruanjinjie@huawei.com>

Since commit b3cf07851b6c ("arm64: entry: Switch to generic IRQ
entry"), _TIF_WORK_MASK is never used, so remove it.

Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/include/asm/thread_info.h | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index f241b8601ebd..ff4998fa1844 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -106,12 +106,6 @@ void arch_setup_new_exec(void);
 #define _TIF_NOTIFY_SIGNAL	(1 << TIF_NOTIFY_SIGNAL)
 #define _TIF_TSC_SIGSEGV	(1 << TIF_TSC_SIGSEGV)
 
-#define _TIF_WORK_MASK		(_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY | \
-				 _TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE | \
-				 _TIF_UPROBE | _TIF_MTE_ASYNC_FAULT | \
-				 _TIF_NOTIFY_SIGNAL | _TIF_SIGPENDING | \
-				 _TIF_PATCH_PENDING)
-
 #define _TIF_SYSCALL_WORK	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
 				 _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \
 				 _TIF_SYSCALL_EMU)
-- 
2.34.1



From ruanjinjie at huawei.com  Thu Dec  4 00:21:10 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 4 Dec 2025 16:21:10 +0800
Subject: [PATCH v9 03/16] arm64/ptrace: Return early for ptrace_report_syscall_entry() error
In-Reply-To: <20251204082123.2792067-1-ruanjinjie@huawei.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
Message-ID: <20251204082123.2792067-4-ruanjinjie@huawei.com>

The generic entry abort the syscall_trace_enter() sequence if
ptrace_report_syscall_entry() errors out, but arm64 not.

As the ptrace_report_syscall_entry() comment said, the calling arch code
should abort the system call and must prevent normal entry so no system
call is made if ptrace_report_syscall_entry() return nonzero.

In preparation for moving arm64 over to the generic entry code,
return early if ptrace_report_syscall_entry() encounters an error.

Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/kernel/ptrace.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 4532e9831856..3926ce6aa268 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -2346,15 +2346,18 @@ static __always_inline unsigned long ptrace_save_reg(struct pt_regs *regs,
 	return saved_reg;
 }
 
-static void report_syscall_entry(struct pt_regs *regs)
+static int report_syscall_entry(struct pt_regs *regs)
 {
 	unsigned long saved_reg;
-	int regno;
+	int regno, ret;
 
 	saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_ENTER, &regno);
-	if (ptrace_report_syscall_entry(regs))
+	ret = ptrace_report_syscall_entry(regs);
+	if (ret)
 		forget_syscall(regs);
 	regs->regs[regno] = saved_reg;
+
+	return ret;
 }
 
 static void report_syscall_exit(struct pt_regs *regs)
@@ -2381,10 +2384,11 @@ static void report_syscall_exit(struct pt_regs *regs)
 int syscall_trace_enter(struct pt_regs *regs)
 {
 	unsigned long flags = read_thread_flags();
+	int ret;
 
 	if (flags & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE)) {
-		report_syscall_entry(regs);
-		if (flags & _TIF_SYSCALL_EMU)
+		ret = report_syscall_entry(regs);
+		if (ret || (flags & _TIF_SYSCALL_EMU))
 			return NO_SYSCALL;
 	}
 
-- 
2.34.1



From ruanjinjie at huawei.com  Thu Dec  4 00:21:09 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 4 Dec 2025 16:21:09 +0800
Subject: [PATCH v9 02/16] arm64/ptrace: Split report_syscall()
In-Reply-To: <20251204082123.2792067-1-ruanjinjie@huawei.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
Message-ID: <20251204082123.2792067-3-ruanjinjie@huawei.com>

The generic syscall entry code has the form:

| syscall_trace_enter()
| {
|	ptrace_report_syscall_entry()
| }
|
| syscall_exit_work()
| {
|	ptrace_report_syscall_exit()
| }

In preparation for moving arm64 over to the generic entry code, split
report_syscall() to two separate enter and exit functions to align
the structure of the arm64 code with syscall_trace_enter() and
syscall_exit_work() from the generic entry code.

No functional changes.

Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
Suggested-by: Mark Rutland <mark.rutland at arm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
v8:
- report_syscall_enter() -> report_syscall_entry().
- Add ptrace_save_reg() helper.
---
 arch/arm64/kernel/ptrace.c | 41 +++++++++++++++++++++++++++-----------
 1 file changed, 29 insertions(+), 12 deletions(-)

diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 4b001121c72d..4532e9831856 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -2317,9 +2317,10 @@ enum ptrace_syscall_dir {
 	PTRACE_SYSCALL_EXIT,
 };
 
-static void report_syscall(struct pt_regs *regs, enum ptrace_syscall_dir dir)
+static __always_inline unsigned long ptrace_save_reg(struct pt_regs *regs,
+						     enum ptrace_syscall_dir dir,
+						     int *regno)
 {
-	int regno;
 	unsigned long saved_reg;
 
 	/*
@@ -2338,15 +2339,31 @@ static void report_syscall(struct pt_regs *regs, enum ptrace_syscall_dir dir)
 	 * - Syscall stops behave differently to seccomp and pseudo-step traps
 	 *   (the latter do not nobble any registers).
 	 */
-	regno = (is_compat_task() ? 12 : 7);
-	saved_reg = regs->regs[regno];
-	regs->regs[regno] = dir;
+	*regno = (is_compat_task() ? 12 : 7);
+	saved_reg = regs->regs[*regno];
+	regs->regs[*regno] = dir;
 
-	if (dir == PTRACE_SYSCALL_ENTER) {
-		if (ptrace_report_syscall_entry(regs))
-			forget_syscall(regs);
-		regs->regs[regno] = saved_reg;
-	} else if (!test_thread_flag(TIF_SINGLESTEP)) {
+	return saved_reg;
+}
+
+static void report_syscall_entry(struct pt_regs *regs)
+{
+	unsigned long saved_reg;
+	int regno;
+
+	saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_ENTER, &regno);
+	if (ptrace_report_syscall_entry(regs))
+		forget_syscall(regs);
+	regs->regs[regno] = saved_reg;
+}
+
+static void report_syscall_exit(struct pt_regs *regs)
+{
+	unsigned long saved_reg;
+	int regno;
+
+	saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_EXIT, &regno);
+	if (!test_thread_flag(TIF_SINGLESTEP)) {
 		ptrace_report_syscall_exit(regs, 0);
 		regs->regs[regno] = saved_reg;
 	} else {
@@ -2366,7 +2383,7 @@ int syscall_trace_enter(struct pt_regs *regs)
 	unsigned long flags = read_thread_flags();
 
 	if (flags & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE)) {
-		report_syscall(regs, PTRACE_SYSCALL_ENTER);
+		report_syscall_entry(regs);
 		if (flags & _TIF_SYSCALL_EMU)
 			return NO_SYSCALL;
 	}
@@ -2394,7 +2411,7 @@ void syscall_trace_exit(struct pt_regs *regs)
 		trace_sys_exit(regs, syscall_get_return_value(current, regs));
 
 	if (flags & (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP))
-		report_syscall(regs, PTRACE_SYSCALL_EXIT);
+		report_syscall_exit(regs);
 
 	rseq_syscall(regs);
 }
-- 
2.34.1



From ruanjinjie at huawei.com  Thu Dec  4 00:21:11 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 4 Dec 2025 16:21:11 +0800
Subject: [PATCH v9 04/16] arm64/ptrace: Refactor syscall_trace_enter/exit()
In-Reply-To: <20251204082123.2792067-1-ruanjinjie@huawei.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
Message-ID: <20251204082123.2792067-5-ruanjinjie@huawei.com>

The generic syscall entry code has the following form, which use
the input syscall work flag and syscall number:

| syscall_trace_enter(struct pt_regs *regs, long syscall,
|		      unsigned long work)
|
| syscall_exit_work(struct pt_regs *regs, unsigned long work)

In preparation for moving arm64 over to the generic entry code,
refactor syscall_trace_enter/exit() to also pass thread flags, and
get syscall number by syscall_get_nr() helper.

No functional changes.

Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/include/asm/syscall.h |  4 ++--
 arch/arm64/kernel/ptrace.c       | 25 ++++++++++++++++---------
 arch/arm64/kernel/syscall.c      |  5 +++--
 3 files changed, 21 insertions(+), 13 deletions(-)

diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
index 5e4c7fc44f73..cef1d9ce6e1b 100644
--- a/arch/arm64/include/asm/syscall.h
+++ b/arch/arm64/include/asm/syscall.h
@@ -120,7 +120,7 @@ static inline int syscall_get_arch(struct task_struct *task)
 	return AUDIT_ARCH_AARCH64;
 }
 
-int syscall_trace_enter(struct pt_regs *regs);
-void syscall_trace_exit(struct pt_regs *regs);
+int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags);
+void syscall_trace_exit(struct pt_regs *regs, unsigned long flags);
 
 #endif	/* __ASM_SYSCALL_H */
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 3926ce6aa268..b962cbcca11d 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -2381,9 +2381,8 @@ static void report_syscall_exit(struct pt_regs *regs)
 	}
 }
 
-int syscall_trace_enter(struct pt_regs *regs)
+int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags)
 {
-	unsigned long flags = read_thread_flags();
 	int ret;
 
 	if (flags & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE)) {
@@ -2396,19 +2395,27 @@ int syscall_trace_enter(struct pt_regs *regs)
 	if (secure_computing() == -1)
 		return NO_SYSCALL;
 
-	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
-		trace_sys_enter(regs, regs->syscallno);
+	/* Either of the above might have changed the syscall number */
+	syscall = syscall_get_nr(current, regs);
 
-	audit_syscall_entry(regs->syscallno, regs->orig_x0, regs->regs[1],
+	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) {
+		trace_sys_enter(regs, syscall);
+
+		/*
+		 * Probes or BPF hooks in the tracepoint may have changed the
+		 * system call number as well.
+		 */
+		 syscall = syscall_get_nr(current, regs);
+	}
+
+	audit_syscall_entry(syscall, regs->orig_x0, regs->regs[1],
 			    regs->regs[2], regs->regs[3]);
 
-	return regs->syscallno;
+	return syscall;
 }
 
-void syscall_trace_exit(struct pt_regs *regs)
+void syscall_trace_exit(struct pt_regs *regs, unsigned long flags)
 {
-	unsigned long flags = read_thread_flags();
-
 	audit_syscall_exit(regs);
 
 	if (flags & _TIF_SYSCALL_TRACEPOINT)
diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index aba7ca6bca2d..ec31f82d2e9f 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -124,7 +124,7 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 		 */
 		if (scno == NO_SYSCALL)
 			syscall_set_return_value(current, regs, -ENOSYS, 0);
-		scno = syscall_trace_enter(regs);
+		scno = syscall_trace_enter(regs, scno, flags);
 		if (scno == NO_SYSCALL)
 			goto trace_exit;
 	}
@@ -143,7 +143,8 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 	}
 
 trace_exit:
-	syscall_trace_exit(regs);
+	flags = read_thread_flags();
+	syscall_trace_exit(regs, flags);
 }
 
 void do_el0_svc(struct pt_regs *regs)
-- 
2.34.1



From ruanjinjie at huawei.com  Thu Dec  4 00:21:07 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 4 Dec 2025 16:21:07 +0800
Subject: [PATCH v9 00/16] arm64: entry: Convert to Generic Entry
Message-ID: <20251204082123.2792067-1-ruanjinjie@huawei.com>

Currently, x86, Riscv, Loongarch use the Generic Entry which makes
maintainers' work easier and codes more elegant. arm64 has already
successfully switched to the Generic IRQ Entry in commit
b3cf07851b6c ("arm64: entry: Switch to generic IRQ entry"), it is
time to completely convert arm64 to Generic Entry.

The goal is to bring arm64 in line with other architectures that already
use the generic entry infrastructure, reducing duplicated code and
making it easier to share future changes in entry/exit paths, such as
"Syscall User Dispatch".

This patch set is rebased on v6.18-rc7. And the performance was measured
on Kunpeng 920 using "perf bench basic syscall" with "arm64.nopauth
selinux=0 audit=1".

After switch to Generic Entry, the performance are below:

| Metric     | W/O Generic Framework | With Generic Framework | Change |
| ---------- | --------------------- | ---------------------- | ------ |
| Total time | 2.130 [sec]           | 2.235 [sec]            | ?4.90% |
| usecs/op   | 0.213095              | 0.223512               | ?4.89% |
| ops/sec    | 4,692,753             | 4,474,044              | ?4.89% |

Compared to earlier with arch specific handling, the performance decreased
by approximately 4.9%.

On the basis of optimizing syscall_get_arguments()[1], el0_svc_common()
and syscall_exit_work(), the performance are below:

| Metric     | W/O Generic Entry | With Generic Entry opt| Change |
| ---------- | ----------------- | ------------------    | ------ |
| Total time | 2.130 [sec]       | 2.134 [sec]           | ?0.18% |
| usecs/op   | 0.213095          | 0.213414              | ?0.15% |
| ops/sec    | 4,692,753         | 4,685,737             | ?0.15% |

Therefore, after the optimization, ARM64 System Call performance remains
almost unchanged.

It was tested ok with following test cases on kunpeng920 and QEMU
virt platform:
 - Perf tests.
 - Different `dynamic preempt` mode switch.
 - Pseudo NMI tests.
 - Stress-ng CPU stress test.
 - Hackbench stress test.
 - MTE test case in Documentation/arch/arm64/memory-tagging-extension.rst
   and all test cases in tools/testing/selftests/arm64/mte/*.
 - "sud" selftest testcase.
 - get_set_sud, get_syscall_info, set_syscall_info, peeksiginfo
   in tools/testing/selftests/ptrace.
 - breakpoint_test_arm64 in selftests/breakpoints.
 - syscall-abi and ptrace in tools/testing/selftests/arm64/abi
 - fp-ptrace, sve-ptrace, za-ptrace in selftests/arm64/fp.
 - vdso_test_getrandom in tools/testing/selftests/vDSO
 - Strace tests.

The test QEMU configuration is as follows:

	qemu-system-aarch64 \
		-M virt,gic-version=3,virtualization=on,mte=on \
		-cpu max,pauth-impdef=on \
		-kernel Image \
		-smp 8,sockets=1,cores=4,threads=2 \
		-m 512m \
		-nographic \
		-no-reboot \
		-device virtio-rng-pci \
		-append "root=/dev/vda rw console=ttyAMA0 kgdboc=ttyAMA0,115200 \
			earlycon preempt=voluntary irqchip.gicv3_pseudo_nmi=1" \
		-drive if=none,file=images/rootfs.ext4,format=raw,id=hd0 \
		-device virtio-blk-device,drive=hd0 \

[1]: https://lore.kernel.org/all/20251201120633.1193122-3-ruanjinjie at huawei.com/

Changes in v9:
- Move "Return early for ptrace_report_syscall_entry() error" patch ahead
  to make it not introduce a regression.
- Not check _TIF_SECCOMP/SYSCALL_EMU for syscall_exit_work() in
  a separate patch.
- Do not report_syscall_exit() for PTRACE_SYSEMU_SINGLESTEP in a separate
  patch.
- Add two performance patch to improve the arm64 performance.
- Add Reviewed-by.
- Link to v8: https://lore.kernel.org/all/20251126071446.3234218-1-ruanjinjie at huawei.com/

Changes in v8:
- Rename "report_syscall_enter()" to "report_syscall_entry()".
- Add ptrace_save_reg() to avoid duplication.
- Remove unused _TIF_WORK_MASK in a standalone patch.
- Align syscall_trace_enter() return value with the generic version.
- Use "scno" instead of regs->syscallno in el0_svc_common().
- Move rseq_syscall() ahead in a standalone patch to clarify it clearly.
- Rename "syscall_trace_exit()" to "syscall_exit_work()".
- Keep the goto in el0_svc_common().
- No argument was passed to __secure_computing() and check -1 not -1L.
- Remove "Add has_syscall_work() helper" patch.
- Move "Add syscall_exit_to_user_mode_prepare() helper" patch later.
- Add miss header for asm/entry-common.h.
- Update the implementation of arch_syscall_is_vdso_sigreturn().
- Add "ARCH_SYSCALL_WORK_EXIT" to be defined as "SECCOMP | SYSCALL_EMU"
  to keep the behaviour unchanged.
- Add more testcases test.
- Add Reviewed-by.
- Update the commit message.
- Link to v7: https://lore.kernel.org/all/20251117133048.53182-1-ruanjinjie at huawei.com/

Chanegs in v7:
- Support "Syscall User Dispatch" by implementing
  arch_syscall_is_vdso_sigreturn() as kemal suggested.
- Add aarch64 support for "sud" selftest testcase, which tested ok with
  the patch series.
- Fix the kernel test robot warning for arch_ptrace_report_syscall_entry()
  and arch_ptrace_report_syscall_exit() in asm/entry-common.h.
- Add perf syscall performance test.
- Link to v6: https://lore.kernel.org/all/20250916082611.2972008-1-ruanjinjie at huawei.com/

Changes in v6:
- Rebased on v6.17-rc5-next as arm64 generic irq entry has merged.
- Update the commit message.
- Link to v5: https://lore.kernel.org/all/20241206101744.4161990-1-ruanjinjie at huawei.com/

Changes in v5:
- Not change arm32 and keep inerrupts_enabled() macro for gicv3 driver.
- Move irqentry_state definition into arch/arm64/kernel/entry-common.c.
- Avoid removing the __enter_from_*() and __exit_to_*() wrappers.
- Update "irqentry_state_t ret/irq_state" to "state"
  to keep it consistently.
- Use generic irq entry header for PREEMPT_DYNAMIC after split
  the generic entry.
- Also refactor the ARM64 syscall code.
- Introduce arch_ptrace_report_syscall_entry/exit(), instead of
  arch_pre/post_report_syscall_entry/exit() to simplify code.
- Make the syscall patches clear separation.
- Update the commit message.
- Link to v4: https://lore.kernel.org/all/20241025100700.3714552-1-ruanjinjie at huawei.com/

Changes in v4:
- Rework/cleanup split into a few patches as Mark suggested.
- Replace interrupts_enabled() macro with regs_irqs_disabled(), instead
  of left it here.
- Remove rcu and lockdep state in pt_regs by using temporary
  irqentry_state_t as Mark suggested.
- Remove some unnecessary intermediate functions to make it clear.
- Rework preempt irq and PREEMPT_DYNAMIC code
  to make the switch more clear.
- arch_prepare_*_entry/exit() -> arch_pre_*_entry/exit().
- Expand the arch functions comment.
- Make arch functions closer to its caller.
- Declare saved_reg in for block.
- Remove arch_exit_to_kernel_mode_prepare(), arch_enter_from_kernel_mode().
- Adjust "Add few arch functions to use generic entry" patch to be
  the penultimate.
- Update the commit message.
- Add suggested-by.
- Link to v3: https://lore.kernel.org/all/20240629085601.470241-1-ruanjinjie at huawei.com/

Changes in v3:
- Test the MTE test cases.
- Handle forget_syscall() in arch_post_report_syscall_entry()
- Make the arch funcs not use __weak as Thomas suggested, so move
  the arch funcs to entry-common.h, and make arch_forget_syscall() folded
  in arch_post_report_syscall_entry() as suggested.
- Move report_single_step() to thread_info.h for arm64
- Change __always_inline() to inline, add inline for the other arch funcs.
- Remove unused signal.h for entry-common.h.
- Add Suggested-by.
- Update the commit message.

Changes in v2:
- Add tested-by.
- Fix a bug that not call arch_post_report_syscall_entry() in
  syscall_trace_enter() if ptrace_report_syscall_entry() return not zero.
- Refactor report_syscall().
- Add comment for arch_prepare_report_syscall_exit().
- Adjust entry-common.h header file inclusion to alphabetical order.
- Update the commit message.

Jinjie Ruan (15):
  arm64: Remove unused _TIF_WORK_MASK
  arm64/ptrace: Split report_syscall()
  arm64/ptrace: Return early for ptrace_report_syscall_entry() error
  arm64/ptrace: Refactor syscall_trace_enter/exit()
  arm64: ptrace: Move rseq_syscall() before audit_syscall_exit()
  arm64: syscall: Rework el0_svc_common()
  arm64/ptrace: Not check _TIF_SECCOMP/SYSCALL_EMU for
    syscall_exit_work()
  arm64/ptrace: Do not report_syscall_exit() for
    PTRACE_SYSEMU_SINGLESTEP
  arm64/ptrace: Expand secure_computing() in place
  arm64/ptrace: Use syscall_get_arguments() helper
  entry: Split syscall_exit_to_user_mode_work() for arch reuse
  entry: Add arch_ptrace_report_syscall_entry/exit()
  arm64: entry: Convert to generic entry
  arm64: Inline el0_svc_common()
  entry: Inline syscall_exit_work()

kemal (1):
  selftests: sud_test: Support aarch64

 arch/arm64/Kconfig                            |  2 +-
 arch/arm64/include/asm/entry-common.h         | 76 ++++++++++++++
 arch/arm64/include/asm/syscall.h              | 19 +++-
 arch/arm64/include/asm/thread_info.h          | 22 +----
 arch/arm64/kernel/debug-monitors.c            |  7 ++
 arch/arm64/kernel/ptrace.c                    | 94 ------------------
 arch/arm64/kernel/signal.c                    |  2 +-
 arch/arm64/kernel/syscall.c                   | 29 ++----
 include/linux/entry-common.h                  | 98 ++++++++++++++++---
 kernel/entry/syscall-common.c                 | 60 +++++-------
 .../syscall_user_dispatch/sud_test.c          |  4 +
 11 files changed, 220 insertions(+), 193 deletions(-)

-- 
2.34.1



From ruanjinjie at huawei.com  Thu Dec  4 00:21:12 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 4 Dec 2025 16:21:12 +0800
Subject: [PATCH v9 05/16] arm64: ptrace: Move rseq_syscall() before audit_syscall_exit()
In-Reply-To: <20251204082123.2792067-1-ruanjinjie@huawei.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
Message-ID: <20251204082123.2792067-6-ruanjinjie@huawei.com>

commit a9f3a74a29af ("entry: Provide generic syscall exit function")
introduce generic syscall exit function and call rseq_syscall()
before audit_syscall_exit() and arch_syscall_exit_tracehook().

And commit b74406f37737 ("arm: Add syscall detection for restartable
sequences") add rseq support for arm32, which also call rseq_syscall()
before audit_syscall_exit() and tracehook_report_syscall().

However, commit 409d5db49867c ("arm64: rseq: Implement backend rseq
calls and select HAVE_RSEQ") implement arm64 rseq and call
rseq_syscall() after audit_syscall_exit() and tracehook_report_syscall().

So compared to the generic entry and arm32 code, arm64 terminates
the process a bit later if the syscall is issued within
a restartable sequence.

But as commit b74406f37737 ("arm: Add syscall detection for restartable
sequences") said, syscalls are not allowed inside restartable sequences,
so should call rseq_syscall() at the very beginning of system call
exiting path for CONFIG_DEBUG_RSEQ=y kernel. This could help us to detect
whether there is a syscall issued inside restartable sequences.

It makes sense to raise SIGSEGV via rseq_syscall() before auditing
and ptrace syscall exit, because this guarantees that the process is
already in an error state with SIGSEGV pending when those later steps
run. Although it makes no practical difference to signal delivery (signals
are processed at the very end in arm64_exit_to_user_mode()), the ordering
is more logical: detect and flag the error first, then proceed with
the remaining work.

To make it more reasonable and in preparation for moving arm64 over to
the generic entry code, move rseq_syscall() ahead before
audit_syscall_exit().

Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/kernel/ptrace.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index b962cbcca11d..8b0a46aac51f 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -2416,6 +2416,8 @@ int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags)
 
 void syscall_trace_exit(struct pt_regs *regs, unsigned long flags)
 {
+	rseq_syscall(regs);
+
 	audit_syscall_exit(regs);
 
 	if (flags & _TIF_SYSCALL_TRACEPOINT)
@@ -2423,8 +2425,6 @@ void syscall_trace_exit(struct pt_regs *regs, unsigned long flags)
 
 	if (flags & (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP))
 		report_syscall_exit(regs);
-
-	rseq_syscall(regs);
 }
 
 /*
-- 
2.34.1



From ruanjinjie at huawei.com  Thu Dec  4 00:21:14 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 4 Dec 2025 16:21:14 +0800
Subject: [PATCH v9 07/16] arm64/ptrace: Not check _TIF_SECCOMP/SYSCALL_EMU for syscall_exit_work()
In-Reply-To: <20251204082123.2792067-1-ruanjinjie@huawei.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
Message-ID: <20251204082123.2792067-8-ruanjinjie@huawei.com>

As syscall_exit_work() do not handle seccomp, so not check _TIF_SECCOMP
for syscall_exit_work().

And as the man manual of PTRACE_SYSEMU and PTRACE_SYSEMU_SINGLESTEP
said, "For PTRACE_SYSEMU, continue and stop on entry to the next system
call, which will not be executed. For PTRACE_SYSEMU_SINGLESTEP, do the same
but also singlestep if not a system call.". So only the syscall entry need
to be reported for SYSCALL_EMU, so not check _TIF_SYSCALL_EMU for
syscall_exit_work().

After this, audit_syscall_exit() and report_syscall_exit() will
no longer be called if only SECCOMP and/or SYSCALL_EMU is set.

And remove has_syscall_work() by the way as currently it is only used in
el0_svc_common().

This is another preparation for moving arm64 over to the generic
entry code.

Link?https://man7.org/linux/man-pages/man2/ptrace.2.html
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/include/asm/syscall.h     | 5 -----
 arch/arm64/include/asm/thread_info.h | 3 +++
 arch/arm64/kernel/ptrace.c           | 2 +-
 arch/arm64/kernel/syscall.c          | 2 +-
 4 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
index ccdaa805aa52..9f2aa9c57560 100644
--- a/arch/arm64/include/asm/syscall.h
+++ b/arch/arm64/include/asm/syscall.h
@@ -120,11 +120,6 @@ static inline int syscall_get_arch(struct task_struct *task)
 	return AUDIT_ARCH_AARCH64;
 }
 
-static inline bool has_syscall_work(unsigned long flags)
-{
-	return unlikely(flags & _TIF_SYSCALL_WORK);
-}
-
 int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags);
 void syscall_exit_to_user_mode_prepare(struct pt_regs *regs);
 
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index ff4998fa1844..8d308ef64612 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -110,6 +110,9 @@ void arch_setup_new_exec(void);
 				 _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \
 				 _TIF_SYSCALL_EMU)
 
+#define _TIF_SYSCALL_EXIT_WORK	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
+				 _TIF_SYSCALL_TRACEPOINT)
+
 #ifdef CONFIG_SHADOW_CALL_STACK
 #define INIT_SCS							\
 	.scs_base	= init_shadow_call_stack,			\
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 25fdf320d73a..3e233968efa2 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -2431,7 +2431,7 @@ void syscall_exit_to_user_mode_prepare(struct pt_regs *regs)
 
 	rseq_syscall(regs);
 
-	if (has_syscall_work(flags) || flags & _TIF_SINGLESTEP)
+	if (unlikely(flags & _TIF_SYSCALL_EXIT_WORK) || flags & _TIF_SINGLESTEP)
 		syscall_exit_work(regs, flags);
 }
 
diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index 65021d0f49e1..881fd261e8cb 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -101,7 +101,7 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 		return;
 	}
 
-	if (has_syscall_work(flags)) {
+	if (unlikely(flags & _TIF_SYSCALL_WORK)) {
 		/*
 		 * The de-facto standard way to skip a system call using ptrace
 		 * is to set the system call to -1 (NO_SYSCALL) and set x0 to a
-- 
2.34.1



From ruanjinjie at huawei.com  Thu Dec  4 00:21:13 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 4 Dec 2025 16:21:13 +0800
Subject: [PATCH v9 06/16] arm64: syscall: Rework el0_svc_common()
In-Reply-To: <20251204082123.2792067-1-ruanjinjie@huawei.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
Message-ID: <20251204082123.2792067-7-ruanjinjie@huawei.com>

The generic syscall syscall_exit_work() has the following content:

| audit_syscall_exit(regs)
| trace_sys_exit(regs, ...)
| ptrace_report_syscall_exit(regs, step)

The generic syscall syscall_exit_to_user_mode_work() has
the following form:

| unsigned long work = READ_ONCE(current_thread_info()->syscall_work)
| rseq_syscall()
| if (unlikely(work & SYSCALL_WORK_EXIT))
|	syscall_exit_work(regs, work)

In preparation for moving arm64 over to the generic entry code,
rework el0_svc_common() as below:

- Rename syscall_trace_exit() to syscall_exit_work().

- Add syscall_exit_to_user_mode_prepare() function to replace
  the combination of read_thread_flags() and syscall_exit_work(),
  also move the syscall exit check logic into it. Move has_syscall_work()
  helper into asm/syscall.h for reuse.

- As currently rseq_syscall() is always called and itself is controlled
  by the CONFIG_DEBUG_RSEQ macro, so the CONFIG_DEBUG_RSEQ check
  is removed.

Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/include/asm/syscall.h |  7 ++++++-
 arch/arm64/kernel/ptrace.c       | 14 +++++++++++---
 arch/arm64/kernel/syscall.c      | 20 +-------------------
 3 files changed, 18 insertions(+), 23 deletions(-)

diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
index cef1d9ce6e1b..ccdaa805aa52 100644
--- a/arch/arm64/include/asm/syscall.h
+++ b/arch/arm64/include/asm/syscall.h
@@ -120,7 +120,12 @@ static inline int syscall_get_arch(struct task_struct *task)
 	return AUDIT_ARCH_AARCH64;
 }
 
+static inline bool has_syscall_work(unsigned long flags)
+{
+	return unlikely(flags & _TIF_SYSCALL_WORK);
+}
+
 int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags);
-void syscall_trace_exit(struct pt_regs *regs, unsigned long flags);
+void syscall_exit_to_user_mode_prepare(struct pt_regs *regs);
 
 #endif	/* __ASM_SYSCALL_H */
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 8b0a46aac51f..25fdf320d73a 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -2414,10 +2414,8 @@ int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags)
 	return syscall;
 }
 
-void syscall_trace_exit(struct pt_regs *regs, unsigned long flags)
+static void syscall_exit_work(struct pt_regs *regs, unsigned long flags)
 {
-	rseq_syscall(regs);
-
 	audit_syscall_exit(regs);
 
 	if (flags & _TIF_SYSCALL_TRACEPOINT)
@@ -2427,6 +2425,16 @@ void syscall_trace_exit(struct pt_regs *regs, unsigned long flags)
 		report_syscall_exit(regs);
 }
 
+void syscall_exit_to_user_mode_prepare(struct pt_regs *regs)
+{
+	unsigned long flags = read_thread_flags();
+
+	rseq_syscall(regs);
+
+	if (has_syscall_work(flags) || flags & _TIF_SINGLESTEP)
+		syscall_exit_work(regs, flags);
+}
+
 /*
  * SPSR_ELx bits which are always architecturally RES0 per ARM DDI 0487D.a.
  * We permit userspace to set SSBS (AArch64 bit 12, AArch32 bit 23) which is
diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index ec31f82d2e9f..65021d0f49e1 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -65,11 +65,6 @@ static void invoke_syscall(struct pt_regs *regs, unsigned int scno,
 	choose_random_kstack_offset(get_random_u16());
 }
 
-static inline bool has_syscall_work(unsigned long flags)
-{
-	return unlikely(flags & _TIF_SYSCALL_WORK);
-}
-
 static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 			   const syscall_fn_t syscall_table[])
 {
@@ -130,21 +125,8 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 	}
 
 	invoke_syscall(regs, scno, sc_nr, syscall_table);
-
-	/*
-	 * The tracing status may have changed under our feet, so we have to
-	 * check again. However, if we were tracing entry, then we always trace
-	 * exit regardless, as the old entry assembly did.
-	 */
-	if (!has_syscall_work(flags) && !IS_ENABLED(CONFIG_DEBUG_RSEQ)) {
-		flags = read_thread_flags();
-		if (!has_syscall_work(flags) && !(flags & _TIF_SINGLESTEP))
-			return;
-	}
-
 trace_exit:
-	flags = read_thread_flags();
-	syscall_trace_exit(regs, flags);
+	syscall_exit_to_user_mode_prepare(regs);
 }
 
 void do_el0_svc(struct pt_regs *regs)
-- 
2.34.1



From ruanjinjie at huawei.com  Thu Dec  4 00:21:15 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 4 Dec 2025 16:21:15 +0800
Subject: [PATCH v9 08/16] arm64/ptrace: Do not report_syscall_exit() for PTRACE_SYSEMU_SINGLESTEP
In-Reply-To: <20251204082123.2792067-1-ruanjinjie@huawei.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
Message-ID: <20251204082123.2792067-9-ruanjinjie@huawei.com>

The generic report_single_step() always returns false if SYSCALL_EMU
is set, but arm64 only checks _TIF_SINGLESTEP and does not check
_TIF_SYSCALL_EMU, which means that if both _TIF_SINGLESTEP and
_TIF_SYSCALL_EMU are set, the generic entry will not report
a single-step, whereas arm64 will do it.

As the man manual of PTRACE_SYSEMU and PTRACE_SYSEMU_SINGLESTEP said,
"For PTRACE_SYSEMU, continue and stop on entry to the next system
call, which will not be executed. For PTRACE_SYSEMU_SINGLESTEP, do the
same but also singlestep if not a system call.". And as the generic entry
report_single_step() comment said, If SYSCALL_EMU is set, then the only
reason to report is when SINGLESTEP is set (i.e. PTRACE_SYSEMU_SINGLESTEP).
Because this syscall instruction has been already reported
in syscall_trace_enter(), there is no need to report the syscall
again in syscall_exit_work().

In preparation for moving arm64 over to the generic entry code,

- Add report_single_step() helper for arm64 to make it clear.

- Do not report_syscall_exit() if both _TIF_SYSCALL_EMU and
  _TIF_SINGLESTEP set.

Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/kernel/ptrace.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 3e233968efa2..25111c121b5e 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -2414,14 +2414,25 @@ int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags)
 	return syscall;
 }
 
+static inline bool report_single_step(unsigned long flags)
+{
+	if (flags & _TIF_SYSCALL_EMU)
+		return false;
+
+	return flags & _TIF_SINGLESTEP;
+}
+
 static void syscall_exit_work(struct pt_regs *regs, unsigned long flags)
 {
+	bool step;
+
 	audit_syscall_exit(regs);
 
 	if (flags & _TIF_SYSCALL_TRACEPOINT)
 		trace_sys_exit(regs, syscall_get_return_value(current, regs));
 
-	if (flags & (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP))
+	step = report_single_step(flags);
+	if (step || flags & _TIF_SYSCALL_TRACE)
 		report_syscall_exit(regs);
 }
 
-- 
2.34.1



From ruanjinjie at huawei.com  Thu Dec  4 00:21:16 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 4 Dec 2025 16:21:16 +0800
Subject: [PATCH v9 09/16] arm64/ptrace: Expand secure_computing() in place
In-Reply-To: <20251204082123.2792067-1-ruanjinjie@huawei.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
Message-ID: <20251204082123.2792067-10-ruanjinjie@huawei.com>

The generic entry expand secure_computing() in place and call
__secure_computing() directly.

In order to switch to the generic entry for arm64, refactor
secure_computing() for syscall_trace_enter().

No functional changes.

Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/kernel/ptrace.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 25111c121b5e..c6dee8a355e5 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -2392,8 +2392,11 @@ int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags)
 	}
 
 	/* Do the secure computing after ptrace; failures should be fast. */
-	if (secure_computing() == -1)
-		return NO_SYSCALL;
+	if (flags & _TIF_SECCOMP) {
+		ret = __secure_computing();
+		if (ret == -1)
+			return NO_SYSCALL;
+	}
 
 	/* Either of the above might have changed the syscall number */
 	syscall = syscall_get_nr(current, regs);
@@ -2411,7 +2414,7 @@ int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags)
 	audit_syscall_entry(syscall, regs->orig_x0, regs->regs[1],
 			    regs->regs[2], regs->regs[3]);
 
-	return syscall;
+	return ret ? : syscall;
 }
 
 static inline bool report_single_step(unsigned long flags)
-- 
2.34.1



From ruanjinjie at huawei.com  Thu Dec  4 00:21:17 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 4 Dec 2025 16:21:17 +0800
Subject: [PATCH v9 10/16] arm64/ptrace: Use syscall_get_arguments() helper
In-Reply-To: <20251204082123.2792067-1-ruanjinjie@huawei.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
Message-ID: <20251204082123.2792067-11-ruanjinjie@huawei.com>

The generic entry check audit context first and use
syscall_get_arguments() helper.

In order to switch to the generic entry for arm64,

- Also use syscall_get_arguments() to get audit_syscall_entry()'s
  last four parameters.

- Extract the syscall_enter_audit() helper to make it clear.

- Check audit context first, which saves an unnecessary memcpy when
  current process's audit_context is NULL.

Overall these changes make syscall_enter_audit() exactly equivalent
to the generic one.

No functional changes.

Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/kernel/ptrace.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index c6dee8a355e5..36e7ba3f38a5 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -2381,6 +2381,16 @@ static void report_syscall_exit(struct pt_regs *regs)
 	}
 }
 
+static inline void syscall_enter_audit(struct pt_regs *regs, long syscall)
+{
+	if (unlikely(audit_context())) {
+		unsigned long args[6];
+
+		syscall_get_arguments(current, regs, args);
+		audit_syscall_entry(syscall, args[0], args[1], args[2], args[3]);
+	}
+}
+
 int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags)
 {
 	int ret;
@@ -2411,8 +2421,7 @@ int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags)
 		 syscall = syscall_get_nr(current, regs);
 	}
 
-	audit_syscall_entry(syscall, regs->orig_x0, regs->regs[1],
-			    regs->regs[2], regs->regs[3]);
+	syscall_enter_audit(regs, syscall);
 
 	return ret ? : syscall;
 }
-- 
2.34.1



From ruanjinjie at huawei.com  Thu Dec  4 00:21:18 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 4 Dec 2025 16:21:18 +0800
Subject: [PATCH v9 11/16] entry: Split syscall_exit_to_user_mode_work() for arch reuse
In-Reply-To: <20251204082123.2792067-1-ruanjinjie@huawei.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
Message-ID: <20251204082123.2792067-12-ruanjinjie@huawei.com>

In the generic entry code, the beginning of
syscall_exit_to_user_mode_work() can be reused on arm64 so it makes
sense to split it.

In preparation for moving arm64 over to the generic entry
code, split out syscall_exit_to_user_mode_prepare() helper from
syscall_exit_to_user_mode_work().

No functional changes.

Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
Reviewed-by: Thomas Gleixner <tglx at linutronix.de>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 include/linux/entry-common.h | 35 ++++++++++++++++++++++-------------
 1 file changed, 22 insertions(+), 13 deletions(-)

diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h
index 7177436f0f9e..cd6dacb2d8bf 100644
--- a/include/linux/entry-common.h
+++ b/include/linux/entry-common.h
@@ -137,20 +137,11 @@ static __always_inline long syscall_enter_from_user_mode(struct pt_regs *regs, l
  */
 void syscall_exit_work(struct pt_regs *regs, unsigned long work);
 
-/**
- * syscall_exit_to_user_mode_work - Handle work before returning to user mode
- * @regs:	Pointer to currents pt_regs
- *
- * Same as step 1 and 2 of syscall_exit_to_user_mode() but without calling
- * exit_to_user_mode() to perform the final transition to user mode.
- *
- * Calling convention is the same as for syscall_exit_to_user_mode() and it
- * returns with all work handled and interrupts disabled. The caller must
- * invoke exit_to_user_mode() before actually switching to user mode to
- * make the final state transitions. Interrupts must stay disabled between
- * return from this function and the invocation of exit_to_user_mode().
+/*
+ * Syscall specific exit to user mode preparation. Runs with interrupts
+ * enabled.
  */
-static __always_inline void syscall_exit_to_user_mode_work(struct pt_regs *regs)
+static __always_inline void syscall_exit_to_user_mode_prepare(struct pt_regs *regs)
 {
 	unsigned long work = READ_ONCE(current_thread_info()->syscall_work);
 	unsigned long nr = syscall_get_nr(current, regs);
@@ -171,6 +162,24 @@ static __always_inline void syscall_exit_to_user_mode_work(struct pt_regs *regs)
 	 */
 	if (unlikely(work & SYSCALL_WORK_EXIT))
 		syscall_exit_work(regs, work);
+}
+
+/**
+ * syscall_exit_to_user_mode_work - Handle work before returning to user mode
+ * @regs:	Pointer to currents pt_regs
+ *
+ * Same as step 1 and 2 of syscall_exit_to_user_mode() but without calling
+ * exit_to_user_mode() to perform the final transition to user mode.
+ *
+ * Calling convention is the same as for syscall_exit_to_user_mode() and it
+ * returns with all work handled and interrupts disabled. The caller must
+ * invoke exit_to_user_mode() before actually switching to user mode to
+ * make the final state transitions. Interrupts must stay disabled between
+ * return from this function and the invocation of exit_to_user_mode().
+ */
+static __always_inline void syscall_exit_to_user_mode_work(struct pt_regs *regs)
+{
+	syscall_exit_to_user_mode_prepare(regs);
 	local_irq_disable_exit_to_user();
 	exit_to_user_mode_prepare(regs);
 }
-- 
2.34.1



From ruanjinjie at huawei.com  Thu Dec  4 00:21:19 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 4 Dec 2025 16:21:19 +0800
Subject: [PATCH v9 12/16] entry: Add arch_ptrace_report_syscall_entry/exit()
In-Reply-To: <20251204082123.2792067-1-ruanjinjie@huawei.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
Message-ID: <20251204082123.2792067-13-ruanjinjie@huawei.com>

Differ from generic entry, due to historical reasons, ARM64 need to
save/restore during syscall entry/exit because ARM64 use a scratch
register (ip(r12) on AArch32, x7 on AArch64) to denote syscall entry/exit.

In preparation for moving arm64 over to the generic entry code,
add arch_ptrace_report_syscall_entry/exit() as the default
ptrace_report_syscall_entry/exit() implementation. This allows
arm64 to implement the architecture specific version.

This allows arm64 to implement the architecture specific version.

Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
Suggested-by: Mark Rutland <mark.rutland at arm.com>
Suggested-by: Thomas Gleixner <tglx at linutronix.de>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 kernel/entry/syscall-common.c | 43 +++++++++++++++++++++++++++++++++--
 1 file changed, 41 insertions(+), 2 deletions(-)

diff --git a/kernel/entry/syscall-common.c b/kernel/entry/syscall-common.c
index 66e6ba7fa80c..27310e611567 100644
--- a/kernel/entry/syscall-common.c
+++ b/kernel/entry/syscall-common.c
@@ -17,6 +17,25 @@ static inline void syscall_enter_audit(struct pt_regs *regs, long syscall)
 	}
 }
 
+/**
+ * arch_ptrace_report_syscall_entry - Architecture specific
+ *				      ptrace_report_syscall_entry().
+ *
+ * Invoked from syscall_trace_enter() to wrap ptrace_report_syscall_entry().
+ * Defaults to ptrace_report_syscall_entry.
+ *
+ * The main purpose is to support arch-specific ptrace_report_syscall_entry()
+ * implementation.
+ */
+static __always_inline int arch_ptrace_report_syscall_entry(struct pt_regs *regs);
+
+#ifndef arch_ptrace_report_syscall_entry
+static __always_inline int arch_ptrace_report_syscall_entry(struct pt_regs *regs)
+{
+	return ptrace_report_syscall_entry(regs);
+}
+#endif
+
 long syscall_trace_enter(struct pt_regs *regs, long syscall,
 				unsigned long work)
 {
@@ -34,7 +53,7 @@ long syscall_trace_enter(struct pt_regs *regs, long syscall,
 
 	/* Handle ptrace */
 	if (work & (SYSCALL_WORK_SYSCALL_TRACE | SYSCALL_WORK_SYSCALL_EMU)) {
-		ret = ptrace_report_syscall_entry(regs);
+		ret = arch_ptrace_report_syscall_entry(regs);
 		if (ret || (work & SYSCALL_WORK_SYSCALL_EMU))
 			return -1L;
 	}
@@ -84,6 +103,26 @@ static inline bool report_single_step(unsigned long work)
 	return work & SYSCALL_WORK_SYSCALL_EXIT_TRAP;
 }
 
+/**
+ * arch_ptrace_report_syscall_exit - Architecture specific
+ *				     ptrace_report_syscall_exit.
+ *
+ * Invoked from syscall_exit_work() to wrap ptrace_report_syscall_exit().
+ *
+ * The main purpose is to support arch-specific ptrace_report_syscall_exit
+ * implementation.
+ */
+static __always_inline void arch_ptrace_report_syscall_exit(struct pt_regs *regs,
+							    int step);
+
+#ifndef arch_ptrace_report_syscall_exit
+static __always_inline void arch_ptrace_report_syscall_exit(struct pt_regs *regs,
+							    int step)
+{
+	ptrace_report_syscall_exit(regs, step);
+}
+#endif
+
 void syscall_exit_work(struct pt_regs *regs, unsigned long work)
 {
 	bool step;
@@ -108,5 +147,5 @@ void syscall_exit_work(struct pt_regs *regs, unsigned long work)
 
 	step = report_single_step(work);
 	if (step || work & SYSCALL_WORK_SYSCALL_TRACE)
-		ptrace_report_syscall_exit(regs, step);
+		arch_ptrace_report_syscall_exit(regs, step);
 }
-- 
2.34.1



From ruanjinjie at huawei.com  Thu Dec  4 00:21:21 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 4 Dec 2025 16:21:21 +0800
Subject: [PATCH v9 14/16] arm64: Inline el0_svc_common()
In-Reply-To: <20251204082123.2792067-1-ruanjinjie@huawei.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
Message-ID: <20251204082123.2792067-15-ruanjinjie@huawei.com>

After switch arm64 to Generic Entry, the compiler no longer inlines
el0_svc_common() into do_el0_svc(). So inline el0_svc_common() and it
has 1% performance uplift on perf bench basic syscall on kunpeng920
as below.

| Metric     | W/O this patch | With this patch | Change    |
| ---------- | -------------- | --------------- | --------- |
| Total time | 2.195 [sec]    | 2.171 [sec]     |  ?1.1%   |
| usecs/op   | 0.219575       | 0.217192        |  ?1.1%   |
| ops/sec    | 4,554,260      | 4,604,225       |  ?1.1%    |

Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/kernel/syscall.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index 47e193a1cfff..5aa51da9ec25 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -66,8 +66,8 @@ static void invoke_syscall(struct pt_regs *regs, unsigned int scno,
 	choose_random_kstack_offset(get_random_u16());
 }
 
-static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
-			   const syscall_fn_t syscall_table[])
+static __always_inline void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
+					   const syscall_fn_t syscall_table[])
 {
 	unsigned long work = READ_ONCE(current_thread_info()->syscall_work);
 	unsigned long flags = read_thread_flags();
-- 
2.34.1



From ruanjinjie at huawei.com  Thu Dec  4 00:21:20 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 4 Dec 2025 16:21:20 +0800
Subject: [PATCH v9 13/16] arm64: entry: Convert to generic entry
In-Reply-To: <20251204082123.2792067-1-ruanjinjie@huawei.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
Message-ID: <20251204082123.2792067-14-ruanjinjie@huawei.com>

Currently, x86, Riscv, Loongarch use the generic entry which makes
maintainers' work easier and codes more elegant. arm64 has already
switched to the generic IRQ entry, so completely convert arm64 to use
the generic entry infrastructure from kernel/entry/*.

The changes are below:
 - Remove TIF_SYSCALL_* flag.

 - Remove _TIF_SYSCALL_WORK and has_syscall_work(), as _TIF_SYSCALL_WORK
   is equal with SYSCALL_WORK_ENTER.

 - Implement arch_ptrace_report_syscall_entry/exit() with
   report_syscall_entry/exit() to do arm64-specific save/restore
   during syscall entry/exit.

 - Add "ARCH_SYSCALL_WORK_EXIT" to be defined as "_TIF_SECCOMP |
   _TIF_SYSCALL_EMU" to keep the arm64 behaviour unchanged.

 - Remove arm64 syscall_trace_enter(), syscall_exit_to_user_mode_prepare(),
   and related sub-functions including syscall_exit_work() and
   syscall_enter_audit(), by calling generic entry's functions with similar
   functionality.

- Implement arch_syscall_is_vdso_sigreturn() to support "Syscall User
  Dispatch".

Suggested-by: Kevin Brodsky <kevin.brodsky at arm.com>
Suggested-by: Mark Rutland <mark.rutland at arm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/Kconfig                    |   2 +-
 arch/arm64/include/asm/entry-common.h |  76 +++++++++++++
 arch/arm64/include/asm/syscall.h      |  19 +++-
 arch/arm64/include/asm/thread_info.h  |  19 +---
 arch/arm64/kernel/debug-monitors.c    |   7 ++
 arch/arm64/kernel/ptrace.c            | 153 --------------------------
 arch/arm64/kernel/signal.c            |   2 +-
 arch/arm64/kernel/syscall.c           |   6 +-
 8 files changed, 107 insertions(+), 177 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 6663ffd23f25..1463ff15d67a 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -152,9 +152,9 @@ config ARM64
 	select GENERIC_CPU_DEVICES
 	select GENERIC_CPU_VULNERABILITIES
 	select GENERIC_EARLY_IOREMAP
+	select GENERIC_ENTRY
 	select GENERIC_IDLE_POLL_SETUP
 	select GENERIC_IOREMAP
-	select GENERIC_IRQ_ENTRY
 	select GENERIC_IRQ_IPI
 	select GENERIC_IRQ_KEXEC_CLEAR_VM_FORWARD
 	select GENERIC_IRQ_PROBE
diff --git a/arch/arm64/include/asm/entry-common.h b/arch/arm64/include/asm/entry-common.h
index cab8cd78f693..d8bf4bf342e8 100644
--- a/arch/arm64/include/asm/entry-common.h
+++ b/arch/arm64/include/asm/entry-common.h
@@ -3,14 +3,21 @@
 #ifndef _ASM_ARM64_ENTRY_COMMON_H
 #define _ASM_ARM64_ENTRY_COMMON_H
 
+#include <linux/ptrace.h>
 #include <linux/thread_info.h>
 
+#include <asm/compat.h>
 #include <asm/cpufeature.h>
 #include <asm/daifflags.h>
 #include <asm/fpsimd.h>
 #include <asm/mte.h>
 #include <asm/stacktrace.h>
 
+enum ptrace_syscall_dir {
+	PTRACE_SYSCALL_ENTER = 0,
+	PTRACE_SYSCALL_EXIT,
+};
+
 #define ARCH_EXIT_TO_USER_MODE_WORK (_TIF_MTE_ASYNC_FAULT | _TIF_FOREIGN_FPSTATE)
 
 static __always_inline void arch_exit_to_user_mode_work(struct pt_regs *regs,
@@ -54,4 +61,73 @@ static inline bool arch_irqentry_exit_need_resched(void)
 
 #define arch_irqentry_exit_need_resched arch_irqentry_exit_need_resched
 
+static __always_inline unsigned long ptrace_save_reg(struct pt_regs *regs,
+						     enum ptrace_syscall_dir dir,
+						     int *regno)
+{
+	unsigned long saved_reg;
+
+	/*
+	 * We have some ABI weirdness here in the way that we handle syscall
+	 * exit stops because we indicate whether or not the stop has been
+	 * signalled from syscall entry or syscall exit by clobbering a general
+	 * purpose register (ip/r12 for AArch32, x7 for AArch64) in the tracee
+	 * and restoring its old value after the stop. This means that:
+	 *
+	 * - Any writes by the tracer to this register during the stop are
+	 *   ignored/discarded.
+	 *
+	 * - The actual value of the register is not available during the stop,
+	 *   so the tracer cannot save it and restore it later.
+	 *
+	 * - Syscall stops behave differently to seccomp and pseudo-step traps
+	 *   (the latter do not nobble any registers).
+	 */
+	*regno = (is_compat_task() ? 12 : 7);
+	saved_reg = regs->regs[*regno];
+	regs->regs[*regno] = dir;
+
+	return saved_reg;
+}
+
+static __always_inline int arch_ptrace_report_syscall_entry(struct pt_regs *regs)
+{
+	unsigned long saved_reg;
+	int regno, ret;
+
+	saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_ENTER, &regno);
+	ret = ptrace_report_syscall_entry(regs);
+	if (ret)
+		forget_syscall(regs);
+	regs->regs[regno] = saved_reg;
+
+	return ret;
+}
+
+#define arch_ptrace_report_syscall_entry arch_ptrace_report_syscall_entry
+
+static __always_inline void arch_ptrace_report_syscall_exit(struct pt_regs *regs,
+							    int step)
+{
+	unsigned long saved_reg;
+	int regno;
+
+	saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_EXIT, &regno);
+	if (!step) {
+		ptrace_report_syscall_exit(regs, 0);
+		regs->regs[regno] = saved_reg;
+	} else {
+		regs->regs[regno] = saved_reg;
+
+		/*
+		 * Signal a pseudo-step exception since we are stepping but
+		 * tracer modifications to the registers may have rewound the
+		 * state machine.
+		 */
+		ptrace_report_syscall_exit(regs, 1);
+	}
+}
+
+#define arch_ptrace_report_syscall_exit arch_ptrace_report_syscall_exit
+
 #endif /* _ASM_ARM64_ENTRY_COMMON_H */
diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
index 9f2aa9c57560..240d45735cc5 100644
--- a/arch/arm64/include/asm/syscall.h
+++ b/arch/arm64/include/asm/syscall.h
@@ -9,6 +9,9 @@
 #include <linux/compat.h>
 #include <linux/err.h>
 
+#include <asm/compat.h>
+#include <asm/vdso.h>
+
 typedef long (*syscall_fn_t)(const struct pt_regs *regs);
 
 extern const syscall_fn_t sys_call_table[];
@@ -120,7 +123,19 @@ static inline int syscall_get_arch(struct task_struct *task)
 	return AUDIT_ARCH_AARCH64;
 }
 
-int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags);
-void syscall_exit_to_user_mode_prepare(struct pt_regs *regs);
+static inline bool arch_syscall_is_vdso_sigreturn(struct pt_regs *regs)
+{
+	unsigned long sigtramp;
+
+#ifdef CONFIG_COMPAT
+	if (is_compat_task()) {
+		unsigned long sigpage = (unsigned long)current->mm->context.sigpage;
+
+		return regs->pc >= sigpage && regs->pc < (sigpage + PAGE_SIZE);
+	}
+#endif
+	sigtramp = (unsigned long)VDSO_SYMBOL(current->mm->context.vdso, sigtramp);
+	return regs->pc == (sigtramp + 8);
+}
 
 #endif	/* __ASM_SYSCALL_H */
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index 8d308ef64612..0c083be23018 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -43,6 +43,7 @@ struct thread_info {
 	void			*scs_sp;
 #endif
 	u32			cpu;
+	unsigned long		syscall_work;   /* SYSCALL_WORK_ flags */
 };
 
 #define thread_saved_pc(tsk)	\
@@ -65,11 +66,6 @@ void arch_setup_new_exec(void);
 #define TIF_UPROBE		5	/* uprobe breakpoint or singlestep */
 #define TIF_MTE_ASYNC_FAULT	6	/* MTE Asynchronous Tag Check Fault */
 #define TIF_NOTIFY_SIGNAL	7	/* signal notifications exist */
-#define TIF_SYSCALL_TRACE	8	/* syscall trace active */
-#define TIF_SYSCALL_AUDIT	9	/* syscall auditing */
-#define TIF_SYSCALL_TRACEPOINT	10	/* syscall tracepoint for ftrace */
-#define TIF_SECCOMP		11	/* syscall secure computing */
-#define TIF_SYSCALL_EMU		12	/* syscall emulation active */
 #define TIF_PATCH_PENDING	13	/* pending live patching update */
 #define TIF_MEMDIE		18	/* is terminating due to OOM killer */
 #define TIF_FREEZE		19
@@ -92,27 +88,14 @@ void arch_setup_new_exec(void);
 #define _TIF_NEED_RESCHED_LAZY	(1 << TIF_NEED_RESCHED_LAZY)
 #define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
 #define _TIF_FOREIGN_FPSTATE	(1 << TIF_FOREIGN_FPSTATE)
-#define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
-#define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
-#define _TIF_SYSCALL_TRACEPOINT	(1 << TIF_SYSCALL_TRACEPOINT)
-#define _TIF_SECCOMP		(1 << TIF_SECCOMP)
-#define _TIF_SYSCALL_EMU	(1 << TIF_SYSCALL_EMU)
 #define _TIF_PATCH_PENDING	(1 << TIF_PATCH_PENDING)
 #define _TIF_UPROBE		(1 << TIF_UPROBE)
-#define _TIF_SINGLESTEP		(1 << TIF_SINGLESTEP)
 #define _TIF_32BIT		(1 << TIF_32BIT)
 #define _TIF_SVE		(1 << TIF_SVE)
 #define _TIF_MTE_ASYNC_FAULT	(1 << TIF_MTE_ASYNC_FAULT)
 #define _TIF_NOTIFY_SIGNAL	(1 << TIF_NOTIFY_SIGNAL)
 #define _TIF_TSC_SIGSEGV	(1 << TIF_TSC_SIGSEGV)
 
-#define _TIF_SYSCALL_WORK	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
-				 _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \
-				 _TIF_SYSCALL_EMU)
-
-#define _TIF_SYSCALL_EXIT_WORK	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
-				 _TIF_SYSCALL_TRACEPOINT)
-
 #ifdef CONFIG_SHADOW_CALL_STACK
 #define INIT_SCS							\
 	.scs_base	= init_shadow_call_stack,			\
diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c
index 29307642f4c9..e67643a70405 100644
--- a/arch/arm64/kernel/debug-monitors.c
+++ b/arch/arm64/kernel/debug-monitors.c
@@ -385,11 +385,18 @@ void user_enable_single_step(struct task_struct *task)
 
 	if (!test_and_set_ti_thread_flag(ti, TIF_SINGLESTEP))
 		set_regs_spsr_ss(task_pt_regs(task));
+
+	/*
+	 * Ensure that a trap is triggered once stepping out of a system
+	 * call prior to executing any user instruction.
+	 */
+	set_task_syscall_work(task, SYSCALL_EXIT_TRAP);
 }
 NOKPROBE_SYMBOL(user_enable_single_step);
 
 void user_disable_single_step(struct task_struct *task)
 {
 	clear_ti_thread_flag(task_thread_info(task), TIF_SINGLESTEP);
+	clear_task_syscall_work(task, SYSCALL_EXIT_TRAP);
 }
 NOKPROBE_SYMBOL(user_disable_single_step);
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 36e7ba3f38a5..cfbb6e409fcf 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -8,7 +8,6 @@
  * Copyright (C) 2012 ARM Ltd.
  */
 
-#include <linux/audit.h>
 #include <linux/compat.h>
 #include <linux/kernel.h>
 #include <linux/sched/signal.h>
@@ -18,7 +17,6 @@
 #include <linux/smp.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
-#include <linux/seccomp.h>
 #include <linux/security.h>
 #include <linux/init.h>
 #include <linux/signal.h>
@@ -28,7 +26,6 @@
 #include <linux/hw_breakpoint.h>
 #include <linux/regset.h>
 #include <linux/elf.h>
-#include <linux/rseq.h>
 
 #include <asm/compat.h>
 #include <asm/cpufeature.h>
@@ -38,13 +35,9 @@
 #include <asm/mte.h>
 #include <asm/pointer_auth.h>
 #include <asm/stacktrace.h>
-#include <asm/syscall.h>
 #include <asm/traps.h>
 #include <asm/system_misc.h>
 
-#define CREATE_TRACE_POINTS
-#include <trace/events/syscalls.h>
-
 struct pt_regs_offset {
 	const char *name;
 	int offset;
@@ -2312,152 +2305,6 @@ long arch_ptrace(struct task_struct *child, long request,
 	return ptrace_request(child, request, addr, data);
 }
 
-enum ptrace_syscall_dir {
-	PTRACE_SYSCALL_ENTER = 0,
-	PTRACE_SYSCALL_EXIT,
-};
-
-static __always_inline unsigned long ptrace_save_reg(struct pt_regs *regs,
-						     enum ptrace_syscall_dir dir,
-						     int *regno)
-{
-	unsigned long saved_reg;
-
-	/*
-	 * We have some ABI weirdness here in the way that we handle syscall
-	 * exit stops because we indicate whether or not the stop has been
-	 * signalled from syscall entry or syscall exit by clobbering a general
-	 * purpose register (ip/r12 for AArch32, x7 for AArch64) in the tracee
-	 * and restoring its old value after the stop. This means that:
-	 *
-	 * - Any writes by the tracer to this register during the stop are
-	 *   ignored/discarded.
-	 *
-	 * - The actual value of the register is not available during the stop,
-	 *   so the tracer cannot save it and restore it later.
-	 *
-	 * - Syscall stops behave differently to seccomp and pseudo-step traps
-	 *   (the latter do not nobble any registers).
-	 */
-	*regno = (is_compat_task() ? 12 : 7);
-	saved_reg = regs->regs[*regno];
-	regs->regs[*regno] = dir;
-
-	return saved_reg;
-}
-
-static int report_syscall_entry(struct pt_regs *regs)
-{
-	unsigned long saved_reg;
-	int regno, ret;
-
-	saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_ENTER, &regno);
-	ret = ptrace_report_syscall_entry(regs);
-	if (ret)
-		forget_syscall(regs);
-	regs->regs[regno] = saved_reg;
-
-	return ret;
-}
-
-static void report_syscall_exit(struct pt_regs *regs)
-{
-	unsigned long saved_reg;
-	int regno;
-
-	saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_EXIT, &regno);
-	if (!test_thread_flag(TIF_SINGLESTEP)) {
-		ptrace_report_syscall_exit(regs, 0);
-		regs->regs[regno] = saved_reg;
-	} else {
-		regs->regs[regno] = saved_reg;
-
-		/*
-		 * Signal a pseudo-step exception since we are stepping but
-		 * tracer modifications to the registers may have rewound the
-		 * state machine.
-		 */
-		ptrace_report_syscall_exit(regs, 1);
-	}
-}
-
-static inline void syscall_enter_audit(struct pt_regs *regs, long syscall)
-{
-	if (unlikely(audit_context())) {
-		unsigned long args[6];
-
-		syscall_get_arguments(current, regs, args);
-		audit_syscall_entry(syscall, args[0], args[1], args[2], args[3]);
-	}
-}
-
-int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags)
-{
-	int ret;
-
-	if (flags & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE)) {
-		ret = report_syscall_entry(regs);
-		if (ret || (flags & _TIF_SYSCALL_EMU))
-			return NO_SYSCALL;
-	}
-
-	/* Do the secure computing after ptrace; failures should be fast. */
-	if (flags & _TIF_SECCOMP) {
-		ret = __secure_computing();
-		if (ret == -1)
-			return NO_SYSCALL;
-	}
-
-	/* Either of the above might have changed the syscall number */
-	syscall = syscall_get_nr(current, regs);
-
-	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) {
-		trace_sys_enter(regs, syscall);
-
-		/*
-		 * Probes or BPF hooks in the tracepoint may have changed the
-		 * system call number as well.
-		 */
-		 syscall = syscall_get_nr(current, regs);
-	}
-
-	syscall_enter_audit(regs, syscall);
-
-	return ret ? : syscall;
-}
-
-static inline bool report_single_step(unsigned long flags)
-{
-	if (flags & _TIF_SYSCALL_EMU)
-		return false;
-
-	return flags & _TIF_SINGLESTEP;
-}
-
-static void syscall_exit_work(struct pt_regs *regs, unsigned long flags)
-{
-	bool step;
-
-	audit_syscall_exit(regs);
-
-	if (flags & _TIF_SYSCALL_TRACEPOINT)
-		trace_sys_exit(regs, syscall_get_return_value(current, regs));
-
-	step = report_single_step(flags);
-	if (step || flags & _TIF_SYSCALL_TRACE)
-		report_syscall_exit(regs);
-}
-
-void syscall_exit_to_user_mode_prepare(struct pt_regs *regs)
-{
-	unsigned long flags = read_thread_flags();
-
-	rseq_syscall(regs);
-
-	if (unlikely(flags & _TIF_SYSCALL_EXIT_WORK) || flags & _TIF_SINGLESTEP)
-		syscall_exit_work(regs, flags);
-}
-
 /*
  * SPSR_ELx bits which are always architecturally RES0 per ARM DDI 0487D.a.
  * We permit userspace to set SSBS (AArch64 bit 12, AArch32 bit 23) which is
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 1110eeb21f57..d3ec1892b3c7 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -8,8 +8,8 @@
 
 #include <linux/cache.h>
 #include <linux/compat.h>
+#include <linux/entry-common.h>
 #include <linux/errno.h>
-#include <linux/irq-entry-common.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/freezer.h>
diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index 881fd261e8cb..47e193a1cfff 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -2,6 +2,7 @@
 
 #include <linux/compiler.h>
 #include <linux/context_tracking.h>
+#include <linux/entry-common.h>
 #include <linux/errno.h>
 #include <linux/nospec.h>
 #include <linux/ptrace.h>
@@ -68,6 +69,7 @@ static void invoke_syscall(struct pt_regs *regs, unsigned int scno,
 static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 			   const syscall_fn_t syscall_table[])
 {
+	unsigned long work = READ_ONCE(current_thread_info()->syscall_work);
 	unsigned long flags = read_thread_flags();
 
 	regs->orig_x0 = regs->regs[0];
@@ -101,7 +103,7 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 		return;
 	}
 
-	if (unlikely(flags & _TIF_SYSCALL_WORK)) {
+	if (unlikely(work & SYSCALL_WORK_ENTER)) {
 		/*
 		 * The de-facto standard way to skip a system call using ptrace
 		 * is to set the system call to -1 (NO_SYSCALL) and set x0 to a
@@ -119,7 +121,7 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 		 */
 		if (scno == NO_SYSCALL)
 			syscall_set_return_value(current, regs, -ENOSYS, 0);
-		scno = syscall_trace_enter(regs, scno, flags);
+		scno = syscall_trace_enter(regs, scno, work);
 		if (scno == NO_SYSCALL)
 			goto trace_exit;
 	}
-- 
2.34.1



From ruanjinjie at huawei.com  Thu Dec  4 00:21:22 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 4 Dec 2025 16:21:22 +0800
Subject: [PATCH v9 15/16] entry: Inline syscall_exit_work()
In-Reply-To: <20251204082123.2792067-1-ruanjinjie@huawei.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
Message-ID: <20251204082123.2792067-16-ruanjinjie@huawei.com>

After switch arm64 to Generic Entry, a new hotspot syscall_exit_work()
appeared because syscall_exit_work() is no longer inlined. so inline
syscall_exit_work(), and it has 2.6% performance uplift on perf bench
basic syscall on kunpeng920 as below.

    | Metric     | W/O this patch | With this patch | Change    |
    | ---------- | -------------- | --------------- | --------- |
    | Total time | 2.171 [sec]    | 2.114 [sec]     |  ?2.6%    |
    | usecs/op   | 0.217192       | 0.211453        |  ?2.6%    |
    | ops/sec    | 4,604,225      | 4,729,178       |  ?2.7%    |

Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 include/linux/entry-common.h  | 63 ++++++++++++++++++++++++++++++++++-
 kernel/entry/syscall-common.c | 59 ++------------------------------
 2 files changed, 64 insertions(+), 58 deletions(-)

diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h
index cd6dacb2d8bf..2f84377fb016 100644
--- a/include/linux/entry-common.h
+++ b/include/linux/entry-common.h
@@ -2,6 +2,7 @@
 #ifndef __LINUX_ENTRYCOMMON_H
 #define __LINUX_ENTRYCOMMON_H
 
+#include <linux/audit.h>
 #include <linux/irq-entry-common.h>
 #include <linux/ptrace.h>
 #include <linux/seccomp.h>
@@ -128,6 +129,41 @@ static __always_inline long syscall_enter_from_user_mode(struct pt_regs *regs, l
 	return ret;
 }
 
+/*
+ * If SYSCALL_EMU is set, then the only reason to report is when
+ * SINGLESTEP is set (i.e. PTRACE_SYSEMU_SINGLESTEP).  This syscall
+ * instruction has been already reported in syscall_enter_from_user_mode().
+ */
+static __always_inline bool report_single_step(unsigned long work)
+{
+	if (work & SYSCALL_WORK_SYSCALL_EMU)
+		return false;
+
+	return work & SYSCALL_WORK_SYSCALL_EXIT_TRAP;
+}
+
+/**
+ * arch_ptrace_report_syscall_exit - Architecture specific
+ *				     ptrace_report_syscall_exit.
+ *
+ * Invoked from syscall_exit_work() to wrap ptrace_report_syscall_exit().
+ *
+ * The main purpose is to support arch-specific ptrace_report_syscall_exit
+ * implementation.
+ */
+static __always_inline void arch_ptrace_report_syscall_exit(struct pt_regs *regs,
+							    int step);
+
+#ifndef arch_ptrace_report_syscall_exit
+static __always_inline void arch_ptrace_report_syscall_exit(struct pt_regs *regs,
+							    int step)
+{
+	ptrace_report_syscall_exit(regs, step);
+}
+#endif
+
+void __trace_sys_exit(struct pt_regs *regs, long ret);
+
 /**
  * syscall_exit_work - Handle work before returning to user mode
  * @regs:	Pointer to current pt_regs
@@ -135,7 +171,32 @@ static __always_inline long syscall_enter_from_user_mode(struct pt_regs *regs, l
  *
  * Do one-time syscall specific work.
  */
-void syscall_exit_work(struct pt_regs *regs, unsigned long work);
+static __always_inline void syscall_exit_work(struct pt_regs *regs, unsigned long work)
+{
+	bool step;
+
+	/*
+	 * If the syscall was rolled back due to syscall user dispatching,
+	 * then the tracers below are not invoked for the same reason as
+	 * the entry side was not invoked in syscall_trace_enter(): The ABI
+	 * of these syscalls is unknown.
+	 */
+	if (work & SYSCALL_WORK_SYSCALL_USER_DISPATCH) {
+		if (unlikely(current->syscall_dispatch.on_dispatch)) {
+			current->syscall_dispatch.on_dispatch = false;
+			return;
+		}
+	}
+
+	audit_syscall_exit(regs);
+
+	if (work & SYSCALL_WORK_SYSCALL_TRACEPOINT)
+		__trace_sys_exit(regs, syscall_get_return_value(current, regs));
+
+	step = report_single_step(work);
+	if (step || work & SYSCALL_WORK_SYSCALL_TRACE)
+		arch_ptrace_report_syscall_exit(regs, step);
+}
 
 /*
  * Syscall specific exit to user mode preparation. Runs with interrupts
diff --git a/kernel/entry/syscall-common.c b/kernel/entry/syscall-common.c
index 27310e611567..1636f49c58d2 100644
--- a/kernel/entry/syscall-common.c
+++ b/kernel/entry/syscall-common.c
@@ -90,62 +90,7 @@ noinstr void syscall_enter_from_user_mode_prepare(struct pt_regs *regs)
 	instrumentation_end();
 }
 
-/*
- * If SYSCALL_EMU is set, then the only reason to report is when
- * SINGLESTEP is set (i.e. PTRACE_SYSEMU_SINGLESTEP).  This syscall
- * instruction has been already reported in syscall_enter_from_user_mode().
- */
-static inline bool report_single_step(unsigned long work)
-{
-	if (work & SYSCALL_WORK_SYSCALL_EMU)
-		return false;
-
-	return work & SYSCALL_WORK_SYSCALL_EXIT_TRAP;
-}
-
-/**
- * arch_ptrace_report_syscall_exit - Architecture specific
- *				     ptrace_report_syscall_exit.
- *
- * Invoked from syscall_exit_work() to wrap ptrace_report_syscall_exit().
- *
- * The main purpose is to support arch-specific ptrace_report_syscall_exit
- * implementation.
- */
-static __always_inline void arch_ptrace_report_syscall_exit(struct pt_regs *regs,
-							    int step);
-
-#ifndef arch_ptrace_report_syscall_exit
-static __always_inline void arch_ptrace_report_syscall_exit(struct pt_regs *regs,
-							    int step)
+void __trace_sys_exit(struct pt_regs *regs, long ret)
 {
-	ptrace_report_syscall_exit(regs, step);
-}
-#endif
-
-void syscall_exit_work(struct pt_regs *regs, unsigned long work)
-{
-	bool step;
-
-	/*
-	 * If the syscall was rolled back due to syscall user dispatching,
-	 * then the tracers below are not invoked for the same reason as
-	 * the entry side was not invoked in syscall_trace_enter(): The ABI
-	 * of these syscalls is unknown.
-	 */
-	if (work & SYSCALL_WORK_SYSCALL_USER_DISPATCH) {
-		if (unlikely(current->syscall_dispatch.on_dispatch)) {
-			current->syscall_dispatch.on_dispatch = false;
-			return;
-		}
-	}
-
-	audit_syscall_exit(regs);
-
-	if (work & SYSCALL_WORK_SYSCALL_TRACEPOINT)
-		trace_sys_exit(regs, syscall_get_return_value(current, regs));
-
-	step = report_single_step(work);
-	if (step || work & SYSCALL_WORK_SYSCALL_TRACE)
-		arch_ptrace_report_syscall_exit(regs, step);
+	trace_sys_exit(regs, ret);
 }
-- 
2.34.1



From ruanjinjie at huawei.com  Thu Dec  4 00:21:23 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 4 Dec 2025 16:21:23 +0800
Subject: [PATCH v9 16/16] selftests: sud_test: Support aarch64
In-Reply-To: <20251204082123.2792067-1-ruanjinjie@huawei.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
Message-ID: <20251204082123.2792067-17-ruanjinjie@huawei.com>

From: kemal <kmal at cock.li>

Support aarch64 to test "Syscall User Dispatch" with sud_test
selftest testcase.

Signed-off-by: kemal <kmal at cock.li>
---
 tools/testing/selftests/syscall_user_dispatch/sud_test.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/tools/testing/selftests/syscall_user_dispatch/sud_test.c b/tools/testing/selftests/syscall_user_dispatch/sud_test.c
index 2eb2c06303f2..f53ebc89befc 100644
--- a/tools/testing/selftests/syscall_user_dispatch/sud_test.c
+++ b/tools/testing/selftests/syscall_user_dispatch/sud_test.c
@@ -192,6 +192,10 @@ static void handle_sigsys(int sig, siginfo_t *info, void *ucontext)
 	((ucontext_t *)ucontext)->uc_mcontext.__gregs[REG_A0] =
 			((ucontext_t *)ucontext)->uc_mcontext.__gregs[REG_A7];
 #endif
+#ifdef __aarch64__
+	((ucontext_t *)ucontext)->uc_mcontext.regs[0] = (unsigned int)
+			((ucontext_t *)ucontext)->uc_mcontext.regs[8];
+#endif
 }
 
 int setup_sigsys_handler(void)
-- 
2.34.1



From leo.yan at arm.com  Thu Dec  4 00:38:02 2025
From: leo.yan at arm.com (Leo Yan)
Date: Thu, 4 Dec 2025 08:38:02 +0000
Subject: [PATCH v6 2/2] coresight: cti: Add Qualcomm extended CTI support
In-Reply-To: <20251203182944.GG724103@e132581.arm.com>
References: <20251202-extended_cti-v6-0-ab68bb15c4f5@oss.qualcomm.com>
 <20251202-extended_cti-v6-2-ab68bb15c4f5@oss.qualcomm.com>
 <20251203182944.GG724103@e132581.arm.com>
Message-ID: <20251204083802.GI724103@e132581.arm.com>

On Wed, Dec 03, 2025 at 06:29:44PM +0000, Coresight ML wrote:

[...]

> > +/* Read registers with power check only (no enable check). */
> > +static ssize_t coresight_cti_reg_show(struct device *dev,
> > +				      struct device_attribute *attr, char *buf)
> > +{
> > +	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
> > +	struct cs_off_attribute *cti_attr = container_of(attr, struct cs_off_attribute, attr);
> > +	u32 idx, val = 0;
> > +
> > +	pm_runtime_get_sync(dev->parent);
> > +	raw_spin_lock(&drvdata->spinlock);
> > +	idx = drvdata->config.ext_reg_sel;
> > +	if (drvdata->config.hw_powered) {
> > +		switch (cti_attr->off) {
> > +		case INDEX_CTITRIGINSTATUS:
> > +		case INDEX_CTITRIGOUTSTATUS:
> > +		case INDEX_ITTRIGINACK:
> > +		case INDEX_ITTRIGOUT:
> > +		case INDEX_ITTRIGOUTACK:
> > +		case INDEX_ITTRIGIN:

I read again and now I understand why you need "config.ext_reg_sel"
as an index for these expending registers.

I think you should extend attrs for the new adding registers:

  static struct attribute *coresight_cti_regs_attrs[] = {
      ...
      coresight_cti_reg(triginstatus, CTITRIGINSTATUS),
      /* Qcom CTI only for triginstatus1/2/3 */
      coresight_cti_reg(triginstatus1, CTITRIGINSTATUS + 0x4),
      coresight_cti_reg(triginstatus2, CTITRIGINSTATUS + 0x8),
      coresight_cti_reg(triginstatus3, CTITRIGINSTATUS + 0xc),
      ...
  }

Then, you can add a is_visible() in coresight_cti_regs_group:

  static umode_t coresight_cti_regs_is_visible(struct kobject *kobj,
                  struct attribute *attr, int n)
  {
          struct device *dev = container_of(kobj, struct device, kobj);
          struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);

          /* Mute QCOM CTI registers for standard CTI module */
          if (!drvdata->is_qcom_cti) {
              if (attr == &triginstatus1.attr ||
                  attr == &triginstatus2.attr ||
                  attr == &triginstatus3.attr)
                  return 0;
          }

          return attr->mode;
  }

  static const struct attribute_group coresight_cti_regs_group = {
          .attrs = coresight_cti_regs_attrs,
          .name = "regs",
          .is_visible = coresight_cti_regs_is_visible,
  };

Thanks,
Leo


From michal.simek at amd.com  Thu Dec  4 00:47:01 2025
From: michal.simek at amd.com (Michal Simek)
Date: Thu, 4 Dec 2025 09:47:01 +0100
Subject: i2c-xiic driver changes from Cisco
In-Reply-To: <aS8cG4Otywg1kIcr@goliath>
References: <aS8cG4Otywg1kIcr@goliath>
Message-ID: <f2913b37-d259-406d-9f17-b1b5028cce6d@amd.com>

Hi,

On 12/2/25 18:04, Daniel Walker (danielwa) wrote:
> Hi,
> 
> We have a slightly modified version of the Xilinx IP which the i2c-xiic.c
> sources seem to support.
> 
> We made one (or at least one) change to the IP were we don't supply it with an
> interrupt line. It doesn't appear the driver supports this configuration.
> Is that accurate to your knowledge ?
> 
> If the drivers doesn't support some type of polling mode, is Xilinx willing to accept
> changes which would make the driver compatible with a polling mode if an
> interrupt is not supplied thru the device tree ?
> 
> It seems like it makes sense the driver should support a polling mode because
> Xilinx customers may make a product where the interrupt line doesn't function
> properly. In that case the customer would need a contingency which could be
> polling for interrupts.

Not sure what that change means but if you don't connect IRQ in design I expect 
vivado removes the whole logic around it at synthesis time.

Anyway using this IP without IRQ is perfectly valid use case and no issue from 
my side to also support it in the kernel.

Thanks,
Michal


From mike.leach at linaro.org  Thu Dec  4 01:04:03 2025
From: mike.leach at linaro.org (Mike Leach)
Date: Thu, 4 Dec 2025 09:04:03 +0000
Subject: [PATCH v6 2/2] coresight: cti: Add Qualcomm extended CTI support
In-Reply-To: <20251204083802.GI724103@e132581.arm.com>
References: <20251202-extended_cti-v6-0-ab68bb15c4f5@oss.qualcomm.com>
 <20251202-extended_cti-v6-2-ab68bb15c4f5@oss.qualcomm.com>
 <20251203182944.GG724103@e132581.arm.com> <20251204083802.GI724103@e132581.arm.com>
Message-ID: <CAJ9a7VhNW6cQt_O6NX+99LXfo-t3mFTejzdNjWcyssbMrXR4OQ@mail.gmail.com>

Hi,

On Thu, 4 Dec 2025 at 08:38, Leo Yan <leo.yan at arm.com> wrote:
>
> On Wed, Dec 03, 2025 at 06:29:44PM +0000, Coresight ML wrote:
>
> [...]
>
> > > +/* Read registers with power check only (no enable check). */
> > > +static ssize_t coresight_cti_reg_show(struct device *dev,
> > > +                                 struct device_attribute *attr, char *buf)
> > > +{
> > > +   struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
> > > +   struct cs_off_attribute *cti_attr = container_of(attr, struct cs_off_attribute, attr);
> > > +   u32 idx, val = 0;
> > > +
> > > +   pm_runtime_get_sync(dev->parent);
> > > +   raw_spin_lock(&drvdata->spinlock);
> > > +   idx = drvdata->config.ext_reg_sel;
> > > +   if (drvdata->config.hw_powered) {
> > > +           switch (cti_attr->off) {
> > > +           case INDEX_CTITRIGINSTATUS:
> > > +           case INDEX_CTITRIGOUTSTATUS:
> > > +           case INDEX_ITTRIGINACK:
> > > +           case INDEX_ITTRIGOUT:
> > > +           case INDEX_ITTRIGOUTACK:
> > > +           case INDEX_ITTRIGIN:
>
> I read again and now I understand why you need "config.ext_reg_sel"
> as an index for these expending registers.
>

Having this index for these extended registers matches what we do for
the INEN and OUTEN registers. This gives the user a consistent
approach. We do not want the unnecessary attributes as  it will
increase the memory footprint for all cti instances, not just the qcom
ones.

The first patch in this series works to reduce the memory footprint by
only allocating resource based on the actual configuration. For
example for an ARM designed CTI with 8 trigger registers, we no longer
declare static 128 x 32 bit arrays for each of INEN and OUTEN which
were required by the original design.

Given that there can be 10s or 100s of CTIs in a large multicore
system, reducing the footprint to match the actual configuration, and
offering a level of compression by using an index + single file to
access a set of registers improves the efficiency of the driver.

Regards

Mike

> I think you should extend attrs for the new adding registers:
>
>   static struct attribute *coresight_cti_regs_attrs[] = {
>       ...
>       coresight_cti_reg(triginstatus, CTITRIGINSTATUS),
>       /* Qcom CTI only for triginstatus1/2/3 */
>       coresight_cti_reg(triginstatus1, CTITRIGINSTATUS + 0x4),
>       coresight_cti_reg(triginstatus2, CTITRIGINSTATUS + 0x8),
>       coresight_cti_reg(triginstatus3, CTITRIGINSTATUS + 0xc),
>       ...
>   }
>
> Then, you can add a is_visible() in coresight_cti_regs_group:
>
>   static umode_t coresight_cti_regs_is_visible(struct kobject *kobj,
>                   struct attribute *attr, int n)
>   {
>           struct device *dev = container_of(kobj, struct device, kobj);
>           struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
>
>           /* Mute QCOM CTI registers for standard CTI module */
>           if (!drvdata->is_qcom_cti) {
>               if (attr == &triginstatus1.attr ||
>                   attr == &triginstatus2.attr ||
>                   attr == &triginstatus3.attr)
>                   return 0;
>           }
>
>           return attr->mode;
>   }
>
>   static const struct attribute_group coresight_cti_regs_group = {
>           .attrs = coresight_cti_regs_attrs,
>           .name = "regs",
>           .is_visible = coresight_cti_regs_is_visible,
>   };
>
> Thanks,
> Leo



-- 
Mike Leach
Principal Engineer, ARM Ltd.
Manchester Design Centre. UK


From mike.leach at linaro.org  Thu Dec  4 01:07:56 2025
From: mike.leach at linaro.org (Mike Leach)
Date: Thu, 4 Dec 2025 09:07:56 +0000
Subject: [PATCH v6 2/2] coresight: cti: Add Qualcomm extended CTI support
In-Reply-To: <20251203182944.GG724103@e132581.arm.com>
References: <20251202-extended_cti-v6-0-ab68bb15c4f5@oss.qualcomm.com>
 <20251202-extended_cti-v6-2-ab68bb15c4f5@oss.qualcomm.com> <20251203182944.GG724103@e132581.arm.com>
Message-ID: <CAJ9a7VjWDBEwdmMf53geACBWGusC8BC3pJuOLETeecw24+N35Q@mail.gmail.com>

Hi,

On Wed, 3 Dec 2025 at 18:29, Leo Yan <leo.yan at arm.com> wrote:
>
> On Tue, Dec 02, 2025 at 02:42:21PM +0800, Yingchao Deng wrote:
> > The QCOM extended CTI is a heavily parameterized version of ARM?s CSCTI.
> > It allows a debugger to send to trigger events to a processor or to send
> > a trigger event to one or more processors when a trigger event occurs
> > on another processor on the same SoC, or even between SoCs. Qualcomm CTI
> > implementation differs from the standard CTI in the following aspects:
> >
> > 1. The number of supported triggers is extended to 128.
> > 2. Several register offsets differ from the CoreSight specification.
>
> I apologize for my late review of this series.  For easier maintenance
> later, I have several comments for register access.
>
> [...]
>
> > +static const u32 cti_normal_offset[] = {
> > +     [INDEX_CTIINTACK]               = CTIINTACK,
> > +     [INDEX_CTIAPPSET]               = CTIAPPSET,
> > +     [INDEX_CTIAPPCLEAR]             = CTIAPPCLEAR,
> > +     [INDEX_CTIAPPPULSE]             = CTIAPPPULSE,
> > +     [INDEX_CTIINEN]                 = CTIINEN(0),
> > +     [INDEX_CTIOUTEN]                = CTIOUTEN(0),
>
> I prefer to update the these two macros to CTIINENn and CTIOUTENn, as
> later we will not use CTIINEN(n) and CTIOUTEN(n) anymore.
>
> > +     [INDEX_CTITRIGINSTATUS]         = CTITRIGINSTATUS,
> > +     [INDEX_CTITRIGOUTSTATUS]        = CTITRIGOUTSTATUS,
> > +     [INDEX_CTICHINSTATUS]           = CTICHINSTATUS,
> > +     [INDEX_CTICHOUTSTATUS]          = CTICHOUTSTATUS,
> > +     [INDEX_CTIGATE]                 = CTIGATE,
> > +     [INDEX_ASICCTL]                 = ASICCTL,
> > +     [INDEX_ITCHINACK]               = ITCHINACK,
> > +     [INDEX_ITTRIGINACK]             = ITTRIGINACK,
> > +     [INDEX_ITCHOUT]                 = ITCHOUT,
> > +     [INDEX_ITTRIGOUT]               = ITTRIGOUT,
> > +     [INDEX_ITCHOUTACK]              = ITCHOUTACK,
> > +     [INDEX_ITTRIGOUTACK]            = ITTRIGOUTACK,
> > +     [INDEX_ITCHIN]                  = ITCHIN,
> > +     [INDEX_ITTRIGIN]                = ITTRIGIN,
> > +     [INDEX_ITCTRL]                  = CORESIGHT_ITCTRL,
> > +};
> > +
> > +static const u32 cti_extended_offset[] = {
> > +     [INDEX_CTIINTACK]               = QCOM_CTIINTACK,
> > +     [INDEX_CTIAPPSET]               = QCOM_CTIAPPSET,
> > +     [INDEX_CTIAPPCLEAR]             = QCOM_CTIAPPCLEAR,
> > +     [INDEX_CTIAPPPULSE]             = QCOM_CTIAPPPULSE,
> > +     [INDEX_CTIINEN]                 = QCOM_CTIINEN,
> > +     [INDEX_CTIOUTEN]                = QCOM_CTIOUTEN,
> > +     [INDEX_CTITRIGINSTATUS]         = QCOM_CTITRIGINSTATUS,
> > +     [INDEX_CTITRIGOUTSTATUS]        = QCOM_CTITRIGOUTSTATUS,
> > +     [INDEX_CTICHINSTATUS]           = QCOM_CTICHINSTATUS,
> > +     [INDEX_CTICHOUTSTATUS]          = QCOM_CTICHOUTSTATUS,
> > +     [INDEX_CTIGATE]                 = QCOM_CTIGATE,
> > +     [INDEX_ASICCTL]                 = QCOM_ASICCTL,
> > +     [INDEX_ITCHINACK]               = QCOM_ITCHINACK,
> > +     [INDEX_ITTRIGINACK]             = QCOM_ITTRIGINACK,
> > +     [INDEX_ITCHOUT]                 = QCOM_ITCHOUT,
> > +     [INDEX_ITTRIGOUT]               = QCOM_ITTRIGOUT,
> > +     [INDEX_ITCHOUTACK]              = QCOM_ITCHOUTACK,
> > +     [INDEX_ITTRIGOUTACK]            = QCOM_ITTRIGOUTACK,
> > +     [INDEX_ITCHIN]                  = QCOM_ITCHIN,
> > +     [INDEX_ITTRIGIN]                = QCOM_ITTRIGIN,
> > +     [INDEX_ITCTRL]                  = CORESIGHT_ITCTRL,
> > +};
>
> I saw CTI registers are within 4KiB (0x1000), we can don't convert
> standard regiserts and only convert to QCOM register based on the
> standard ones.  So you can drop the cti_normal_offset strucuture and
> only have a cti_reg_qcom_offset[] struct:
>
>   static const u32 cti_extended_offset[] = {
>         [CTIINTACK]             = QCOM_CTIINTACK,
>         [CTIAPPSET]             = QCOM_CTIAPPSET,
>         [CTIAPPCLEAR]           = QCOM_CTIAPPCLEAR,
>         [CTIAPPPULSE]           = QCOM_CTIAPPPULSE,
>         [CTIINEN]               = QCOM_CTIINEN,
>         ...
>   };
>

I suggested the dual offset approach a couple of patchset revisions
ago as it actually simplifies the code & makes it more efficient. The
offset array in use is set during probe and the remaining code is then
common to both without lots of "if qcom else " occurences.

Regards

Mike

> Then you could create two helpers for register address:
>
>     static void __iomem *cti_reg_addr_with_nr(struct cti_drvdata *drvdata,
>                                               u32 reg, u32 nr)
>     {
>         /* convert to qcom specific offset */
>         if (unlikely(drvdata->is_qcom_cti))
>             reg = cti_extended_offset[reg];
>
>         return drvdata->base + reg + sizeof(u32) * nr;
>     }
>
>     static void __iomem *cti_reg_addr(struct cti_drvdata *drvdata, u32 reg)
>     {
>         return cti_reg_addr_with_nr(drvdata, reg, 0);
>     }
>
> >  /*
> >   * CTI devices can be associated with a PE, or be connected to CoreSight
> > @@ -70,15 +119,16 @@ void cti_write_all_hw_regs(struct cti_drvdata *drvdata)
> >
> >       /* write the CTI trigger registers */
> >       for (i = 0; i < config->nr_trig_max; i++) {
> > -             writel_relaxed(config->ctiinen[i], drvdata->base + CTIINEN(i));
> > +             writel_relaxed(config->ctiinen[i],
> > +                            drvdata->base + cti_offset(drvdata, INDEX_CTIINEN, i));
>
> writel_relaxed(config->ctiinen[i],
>                cti_reg_addr_with_nr(drvdata, CTIINENn, i));
>
> And apply for the same cases below.
>
> >       /* other regs */
> > -     writel_relaxed(config->ctigate, drvdata->base + CTIGATE);
> > -     writel_relaxed(config->asicctl, drvdata->base + ASICCTL);
> > -     writel_relaxed(config->ctiappset, drvdata->base + CTIAPPSET);
> > +     writel_relaxed(config->ctigate, drvdata->base + cti_offset(drvdata, INDEX_CTIGATE, 0));
>
> writel_relaxed(config->ctigate, cti_reg_addr(drvdata, CTIGATE));
>
> And apply for the same cases below.
>
> [...]
>
> > @@ -394,8 +447,8 @@ int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,
> >
> >       /* update the local register values */
> >       chan_bitmask = BIT(channel_idx);
> > -     reg_offset = (direction == CTI_TRIG_IN ? CTIINEN(trigger_idx) :
> > -                   CTIOUTEN(trigger_idx));
> > +     reg_offset = (direction == CTI_TRIG_IN ? cti_offset(drvdata, INDEX_CTIINEN, trigger_idx) :
> > +                     cti_offset(drvdata, INDEX_CTIOUTEN, trigger_idx));
>
> For readable, we can improve a bit with code alignment:
>
>   reg_offset = (direction == CTI_TRIG_IN) ? cti_reg_addr_with_nr(drvdata, CTIINENn, trigger_idx) :
>                                             cti_reg_addr_with_nr(drvdata, CTIOUTENn, trigger_idx);
>
> [...]
>
> > @@ -981,9 +1035,28 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id)
> >       drvdata->csdev_release = drvdata->csdev->dev.release;
> >       drvdata->csdev->dev.release = cti_device_release;
> >
> > +     /* check architect value*/
> > +     devarch = readl_relaxed(drvdata->base + CORESIGHT_DEVARCH);
> > +     if (CTI_DEVARCH_ARCHITECT(devarch) == ARCHITECT_QCOM) {
> > +             drvdata->subtype = QCOM_CTI;
> > +             drvdata->offsets = cti_extended_offset;
>
> As a result, we can only set the is_qcom_cti flag:
>
>   drvdata->is_qcom_cti = true;
>
> > +             /*
> > +              * QCOM CTI does not implement Claimtag functionality as
> > +              * per CoreSight specification, but its CLAIMSET register
> > +              * is incorrectly initialized to 0xF. This can mislead
> > +              * tools or drivers into thinking the component is claimed.
> > +              *
> > +              * Reset CLAIMSET to 0 to reflect that no claims are active.
> > +              */
> > +             writel_relaxed(0, drvdata->base + CORESIGHT_CLAIMSET);
>
> I am confused for this.  If QCOM CTI does not implement claim tag,
> then what is the designed register at the offset CORESIGHT_CLAIMSET?
>
> Should you bypass all claim tag related operations for QCOM CTI case?
> (I don't see you touch anything for claim and declaim tags).
>
> > +     } else {
> > +             drvdata->subtype = ARM_STD_CTI;
> > +             drvdata->offsets = cti_normal_offset;
> > +     }
> > +
> >       /* all done - dec pm refcount */
> >       pm_runtime_put(&adev->dev);
> > -     dev_info(&drvdata->csdev->dev, "CTI initialized\n");
> > +     dev_info(&drvdata->csdev->dev, "CTI initialized; subtype=%d\n", drvdata->subtype);
>
> dev_info(&drvdata->csdev->dev, "%s CTI initialized\n",
>          drvdata->is_qcom_cti ? "QCOM" : "");
>
> >       return 0;
> >
> >  pm_release:
> > diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
> > index a9df77215141..12a495382999 100644
> > --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c
> > +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
> > @@ -172,9 +172,8 @@ static struct attribute *coresight_cti_attrs[] = {
> >
> >  /* register based attributes */
> >
> > -/* Read registers with power check only (no enable check). */
> > -static ssize_t coresight_cti_reg_show(struct device *dev,
> > -                        struct device_attribute *attr, char *buf)
> > +static ssize_t coresight_cti_mgmt_reg_show(struct device *dev,
> > +                                        struct device_attribute *attr, char *buf)
> >  {
> >       struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
> >       struct cs_off_attribute *cti_attr = container_of(attr, struct cs_off_attribute, attr);
> > @@ -189,6 +188,40 @@ static ssize_t coresight_cti_reg_show(struct device *dev,
> >       return sysfs_emit(buf, "0x%x\n", val);
> >  }
> >
> > +/* Read registers with power check only (no enable check). */
> > +static ssize_t coresight_cti_reg_show(struct device *dev,
> > +                                   struct device_attribute *attr, char *buf)
> > +{
> > +     struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
> > +     struct cs_off_attribute *cti_attr = container_of(attr, struct cs_off_attribute, attr);
> > +     u32 idx, val = 0;
> > +
> > +     pm_runtime_get_sync(dev->parent);
> > +     raw_spin_lock(&drvdata->spinlock);
> > +     idx = drvdata->config.ext_reg_sel;
> > +     if (drvdata->config.hw_powered) {
> > +             switch (cti_attr->off) {
> > +             case INDEX_CTITRIGINSTATUS:
> > +             case INDEX_CTITRIGOUTSTATUS:
> > +             case INDEX_ITTRIGINACK:
> > +             case INDEX_ITTRIGOUT:
> > +             case INDEX_ITTRIGOUTACK:
> > +             case INDEX_ITTRIGIN:
> > +                     val = readl_relaxed(drvdata->base +
> > +                                         cti_offset(drvdata, cti_attr->off, idx));
> > +                     break;
> > +
> > +             default:
> > +                     val = readl_relaxed(drvdata->base + cti_offset(drvdata, cti_attr->off, 0));
> > +                     break;
> > +             }
> > +     }
> > +
> > +     raw_spin_unlock(&drvdata->spinlock);
> > +     pm_runtime_put_sync(dev->parent);
> > +     return sysfs_emit(buf, "0x%x\n", val);
> > +}
> > +
> >  /* Write registers with power check only (no enable check). */
> >  static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,
> >                                                     struct device_attribute *attr,
> > @@ -197,19 +230,39 @@ static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,
> >       struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
> >       struct cs_off_attribute *cti_attr = container_of(attr, struct cs_off_attribute, attr);
> >       unsigned long val = 0;
> > +     u32 idx;
> >
> >       if (kstrtoul(buf, 0, &val))
> >               return -EINVAL;
> >
> >       pm_runtime_get_sync(dev->parent);
> >       raw_spin_lock(&drvdata->spinlock);
> > -     if (drvdata->config.hw_powered)
> > -             cti_write_single_reg(drvdata, cti_attr->off, val);
> > +     idx = drvdata->config.ext_reg_sel;
> > +     if (drvdata->config.hw_powered) {
> > +             switch (cti_attr->off) {
> > +             case INDEX_ITTRIGINACK:
> > +             case INDEX_ITTRIGOUT:
> > +                     cti_write_single_reg(drvdata, cti_offset(drvdata, cti_attr->off, idx), val);
> > +                     break;
> > +
> > +             default:
> > +                     cti_write_single_reg(drvdata, cti_offset(drvdata, cti_attr->off, 0), val);
> > +                     break;
> > +             }
> > +     }
>
> For both coresight_cti_reg_show() and coresight_cti_reg_store(), can
> we always use "cti_attr->off" as the offset for regitser access?  I
> mean we don't need the extra config.ext_reg_sel, eventually any
> register we can calculate a offset for it.
>
> >       raw_spin_unlock(&drvdata->spinlock);
> >       pm_runtime_put_sync(dev->parent);
> >       return size;
> >  }
> >
> > +#define coresight_cti_mgmt_reg(name, offset)                         \
> > +     (&((struct cs_off_attribute[]) {                                \
> > +        {                                                            \
> > +             __ATTR(name, 0444, coresight_cti_mgmt_reg_show, NULL),  \
> > +             offset                                                  \
> > +        }                                                            \
> > +     })[0].attr.attr)
> > +
> >  #define coresight_cti_reg(name, offset)                                      \
> >       (&((struct cs_off_attribute[]) {                                \
> >          {                                                            \
> > @@ -237,17 +290,17 @@ static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,
> >
> >  /* coresight management registers */
> >  static struct attribute *coresight_cti_mgmt_attrs[] = {
> > -     coresight_cti_reg(devaff0, CTIDEVAFF0),
> > -     coresight_cti_reg(devaff1, CTIDEVAFF1),
> > -     coresight_cti_reg(authstatus, CORESIGHT_AUTHSTATUS),
> > -     coresight_cti_reg(devarch, CORESIGHT_DEVARCH),
> > -     coresight_cti_reg(devid, CORESIGHT_DEVID),
> > -     coresight_cti_reg(devtype, CORESIGHT_DEVTYPE),
> > -     coresight_cti_reg(pidr0, CORESIGHT_PERIPHIDR0),
> > -     coresight_cti_reg(pidr1, CORESIGHT_PERIPHIDR1),
> > -     coresight_cti_reg(pidr2, CORESIGHT_PERIPHIDR2),
> > -     coresight_cti_reg(pidr3, CORESIGHT_PERIPHIDR3),
> > -     coresight_cti_reg(pidr4, CORESIGHT_PERIPHIDR4),
> > +     coresight_cti_mgmt_reg(devaff0, CTIDEVAFF0),
> > +     coresight_cti_mgmt_reg(devaff1, CTIDEVAFF1),
> > +     coresight_cti_mgmt_reg(authstatus, CORESIGHT_AUTHSTATUS),
> > +     coresight_cti_mgmt_reg(devarch, CORESIGHT_DEVARCH),
> > +     coresight_cti_mgmt_reg(devid, CORESIGHT_DEVID),
> > +     coresight_cti_mgmt_reg(devtype, CORESIGHT_DEVTYPE),
> > +     coresight_cti_mgmt_reg(pidr0, CORESIGHT_PERIPHIDR0),
> > +     coresight_cti_mgmt_reg(pidr1, CORESIGHT_PERIPHIDR1),
> > +     coresight_cti_mgmt_reg(pidr2, CORESIGHT_PERIPHIDR2),
> > +     coresight_cti_mgmt_reg(pidr3, CORESIGHT_PERIPHIDR3),
> > +     coresight_cti_mgmt_reg(pidr4, CORESIGHT_PERIPHIDR4),
>
> I don't see any benefit for updating from coresight_cti_reg() to
> coresight_cti_mgmt_reg().  If really want to do this, should remove
> the macro coresight_cti_reg()?
>
> >       NULL,
> >  };
> >
> > @@ -258,13 +311,15 @@ static struct attribute *coresight_cti_mgmt_attrs[] = {
> >   * If inaccessible & pcached_val not NULL then show cached value.
> >   */
> >  static ssize_t cti_reg32_show(struct device *dev, char *buf,
> > -                           u32 *pcached_val, int reg_offset)
> > +                           u32 *pcached_val, int index)
>
> We don't need to change anything for this.  The passed "reg_offset"
> should be always a final offset, no matter for standard CTI or QCOM
> case, the driver directly uses the offset for register access.
>
> [...]
>
> > +/*
> > + * QCOM CTI supports up to 128 triggers, there are 6 registers need to be
> > + * expanded to up to 4 instances, and ext_reg_sel can be used to indicate
> > + * which one is in use.
> > + * CTITRIGINSTATUS, CTITRIGOUTSTATUS,
> > + * ITTRIGIN, ITTRIGOUT,
> > + * ITTRIGINACK, ITTRIGOUTACK.
> > + */
> > +static ssize_t ext_reg_sel_show(struct device *dev,
> > +                             struct device_attribute *attr,
> > +                             char *buf)
> > +{
> > +     u32 val;
> > +     struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
> > +
> > +     raw_spin_lock(&drvdata->spinlock);
> > +     val = drvdata->config.ext_reg_sel;
> > +     raw_spin_unlock(&drvdata->spinlock);
> > +     return sprintf(buf, "%d\n", val);
> > +}
> > +
> > +static ssize_t ext_reg_sel_store(struct device *dev,
> > +                              struct device_attribute *attr,
> > +                              const char *buf, size_t size)
> > +{
> > +     unsigned long val;
> > +     struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
> > +
> > +     if (kstrtoul(buf, 0, &val))
> > +             return -EINVAL;
> > +     if (val > ((drvdata->config.nr_trig_max + 31) / 32 - 1))
> > +             return -EINVAL;
> > +
> > +     raw_spin_lock(&drvdata->spinlock);
> > +     drvdata->config.ext_reg_sel = val;
> > +     raw_spin_unlock(&drvdata->spinlock);
> > +     return size;
> > +}
>
> As said, I don't think the trigger register is any different from
> other register access.  So the existed APIs would be sufficient.
>
> As a result, we don't need to add two above functions.
>
> Thanks,
> Leo



-- 
Mike Leach
Principal Engineer, ARM Ltd.
Manchester Design Centre. UK


From ming.qian at oss.nxp.com  Thu Dec  4 01:08:09 2025
From: ming.qian at oss.nxp.com (ming.qian at oss.nxp.com)
Date: Thu,  4 Dec 2025 17:08:09 +0800
Subject: [PATCH v3 1/3] media: v4l2-mem2mem: Add a kref to the v4l2_m2m_dev structure
Message-ID: <20251204090813.595-1-ming.qian@oss.nxp.com>

From: Nicolas Dufresne <nicolas.dufresne at collabora.com>

Adding a reference count to the v4l2_m2m_dev structure allow safely
sharing it across multiple hardware nodes. This can be used to prevent
running jobs concurrently on m2m cores that have some internal resource
sharing.

Signed-off-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
---
 drivers/media/v4l2-core/v4l2-mem2mem.c | 23 +++++++++++++++++++++++
 include/media/v4l2-mem2mem.h           | 21 +++++++++++++++++++++
 2 files changed, 44 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c
index fec93c1a9231..ae0de54d4c3e 100644
--- a/drivers/media/v4l2-core/v4l2-mem2mem.c
+++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
@@ -90,6 +90,7 @@ static const char * const m2m_entity_name[] = {
  * @job_work:		worker to run queued jobs.
  * @job_queue_flags:	flags of the queue status, %QUEUE_PAUSED.
  * @m2m_ops:		driver callbacks
+ * @kref:		device reference count
  */
 struct v4l2_m2m_dev {
 	struct v4l2_m2m_ctx	*curr_ctx;
@@ -109,6 +110,8 @@ struct v4l2_m2m_dev {
 	unsigned long		job_queue_flags;
 
 	const struct v4l2_m2m_ops *m2m_ops;
+
+	struct kref kref;
 };
 
 static struct v4l2_m2m_queue_ctx *get_queue_ctx(struct v4l2_m2m_ctx *m2m_ctx,
@@ -1200,6 +1203,7 @@ struct v4l2_m2m_dev *v4l2_m2m_init(const struct v4l2_m2m_ops *m2m_ops)
 	INIT_LIST_HEAD(&m2m_dev->job_queue);
 	spin_lock_init(&m2m_dev->job_spinlock);
 	INIT_WORK(&m2m_dev->job_work, v4l2_m2m_device_run_work);
+	kref_init(&m2m_dev->kref);
 
 	return m2m_dev;
 }
@@ -1211,6 +1215,25 @@ void v4l2_m2m_release(struct v4l2_m2m_dev *m2m_dev)
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_release);
 
+void v4l2_m2m_get(struct v4l2_m2m_dev *m2m_dev)
+{
+	kref_get(&m2m_dev->kref);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_get);
+
+static void v4l2_m2m_release_from_kref(struct kref *kref)
+{
+	struct v4l2_m2m_dev *m2m_dev = container_of(kref, struct v4l2_m2m_dev, kref);
+
+	v4l2_m2m_release(m2m_dev);
+}
+
+void v4l2_m2m_put(struct v4l2_m2m_dev *m2m_dev)
+{
+	kref_put(&m2m_dev->kref, v4l2_m2m_release_from_kref);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_put);
+
 struct v4l2_m2m_ctx *v4l2_m2m_ctx_init(struct v4l2_m2m_dev *m2m_dev,
 		void *drv_priv,
 		int (*queue_init)(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq))
diff --git a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h
index bf6a09a04dcf..ca295c660c7f 100644
--- a/include/media/v4l2-mem2mem.h
+++ b/include/media/v4l2-mem2mem.h
@@ -547,6 +547,27 @@ v4l2_m2m_register_media_controller(struct v4l2_m2m_dev *m2m_dev,
  */
 void v4l2_m2m_release(struct v4l2_m2m_dev *m2m_dev);
 
+/**
+ * v4l2_m2m_get() - take a reference to the m2m_dev structure
+ *
+ * @m2m_dev: opaque pointer to the internal data to handle M2M context
+ *
+ * This is used to share the M2M device across multiple devices. This
+ * can be used to avoid scheduling two hardware nodes concurrently.
+ */
+void v4l2_m2m_get(struct v4l2_m2m_dev *m2m_dev);
+
+/**
+ * v4l2_m2m_put() - remove a reference to the m2m_dev structure
+ *
+ * @m2m_dev: opaque pointer to the internal data to handle M2M context
+ *
+ * Once the M2M device have no more references, v4l2_m2m_realse() will be
+ * called automatically. Users of this method should never call
+ * v4l2_m2m_release() directly. See v4l2_m2m_get() for more details.
+ */
+void v4l2_m2m_put(struct v4l2_m2m_dev *m2m_dev);
+
 /**
  * v4l2_m2m_ctx_init() - allocate and initialize a m2m context
  *
-- 
2.52.0



From ming.qian at oss.nxp.com  Thu Dec  4 01:08:10 2025
From: ming.qian at oss.nxp.com (ming.qian at oss.nxp.com)
Date: Thu,  4 Dec 2025 17:08:10 +0800
Subject: [PATCH v3 2/3] pmdomain: imx8m-blk-ctrl: Remove separate rst and clk mask for 8mq vpu
In-Reply-To: <20251204090813.595-1-ming.qian@oss.nxp.com>
References: <20251204090813.595-1-ming.qian@oss.nxp.com>
Message-ID: <20251204090813.595-2-ming.qian@oss.nxp.com>

From: Ming Qian <ming.qian at oss.nxp.com>

For i.MX8MQ platform, the ADB in the VPUMIX domain has no separate reset
and clock enable bits, but is ungated and reset together with the VPUs.
So we can't reset G1 or G2 separately, it may led to the system hang.
Remove rst_mask and clk_mask of imx8mq_vpu_blk_ctl_domain_data.
Let imx8mq_vpu_power_notifier() do really vpu reset.

Fixes: 608d7c325e85 ("soc: imx: imx8m-blk-ctrl: add i.MX8MQ VPU blk-ctrl")
Signed-off-by: Ming Qian <ming.qian at oss.nxp.com>
Reviewed-by: Benjamin Gaignard <benjamin.gaignard at collabora.com>
Reviewed-by: Peng Fan <peng.fan at nxp.com>
---
v3
- Add some comments
v2
- Update commit message

 drivers/pmdomain/imx/imx8m-blk-ctrl.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/pmdomain/imx/imx8m-blk-ctrl.c b/drivers/pmdomain/imx/imx8m-blk-ctrl.c
index 5c83e5599f1e..74bf4936991d 100644
--- a/drivers/pmdomain/imx/imx8m-blk-ctrl.c
+++ b/drivers/pmdomain/imx/imx8m-blk-ctrl.c
@@ -846,22 +846,25 @@ static int imx8mq_vpu_power_notifier(struct notifier_block *nb,
 	return NOTIFY_OK;
 }
 
+/*
+ * For i.MX8MQ, the ADB in the VPUMIX domain has no separate reset and clock
+ * enable bits, but is ungated and reset together with the VPUs.
+ * Resetting G1 or G2 separately may led to system hang.
+ * Remove the rst_mask and clk_mask from the domain data of G1 and G2,
+ * Let imx8mq_vpu_power_notifier() do really vpu reset.
+ */
 static const struct imx8m_blk_ctrl_domain_data imx8mq_vpu_blk_ctl_domain_data[] = {
 	[IMX8MQ_VPUBLK_PD_G1] = {
 		.name = "vpublk-g1",
 		.clk_names = (const char *[]){ "g1", },
 		.num_clks = 1,
 		.gpc_name = "g1",
-		.rst_mask = BIT(1),
-		.clk_mask = BIT(1),
 	},
 	[IMX8MQ_VPUBLK_PD_G2] = {
 		.name = "vpublk-g2",
 		.clk_names = (const char *[]){ "g2", },
 		.num_clks = 1,
 		.gpc_name = "g2",
-		.rst_mask = BIT(0),
-		.clk_mask = BIT(0),
 	},
 };
 
-- 
2.52.0



From ming.qian at oss.nxp.com  Thu Dec  4 01:08:11 2025
From: ming.qian at oss.nxp.com (ming.qian at oss.nxp.com)
Date: Thu,  4 Dec 2025 17:08:11 +0800
Subject: [PATCH v3 3/3] media: verisilicon: Avoid G2 bus error while decoding H.264 and HEVC
In-Reply-To: <20251204090813.595-1-ming.qian@oss.nxp.com>
References: <20251204090813.595-1-ming.qian@oss.nxp.com>
Message-ID: <20251204090813.595-3-ming.qian@oss.nxp.com>

From: Ming Qian <ming.qian at oss.nxp.com>

For the i.MX8MQ platform, there is a hardware limitation: the g1 VPU and
g2 VPU cannot decode simultaneously; otherwise, it will cause below bus
error and produce corrupted pictures, even potentially lead to system hang.

[  110.527986] hantro-vpu 38310000.video-codec: frame decode timed out.
[  110.583517] hantro-vpu 38310000.video-codec: bus error detected.

Therefore, it is necessary to ensure that g1 and g2 operate alternately.
This allows for successful multi-instance decoding of H.264 and HEVC.

To achieve this, we can have g1 and g2 share the same v4l2_m2m_dev, and
then the v4l2_m2m_dev can handle the scheduling.

Fixes: cb5dd5a0fa518 ("media: hantro: Introduce G2/HEVC decoder")
Co-developed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Signed-off-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Signed-off-by: Ming Qian <ming.qian at oss.nxp.com>
---
v3
- Apply Nicolas's approach that use an array list to define the shared
  devices

v2
- Abandon the waiting approach.
- Switch to a shared v4l2_m2m_dev solution.

 drivers/media/platform/verisilicon/hantro.h   |  2 +
 .../media/platform/verisilicon/hantro_drv.c   | 42 +++++++++++++++++--
 .../media/platform/verisilicon/imx8m_vpu_hw.c |  8 ++++
 3 files changed, 49 insertions(+), 3 deletions(-)

diff --git a/drivers/media/platform/verisilicon/hantro.h b/drivers/media/platform/verisilicon/hantro.h
index e0fdc4535b2d..0353de154a1e 100644
--- a/drivers/media/platform/verisilicon/hantro.h
+++ b/drivers/media/platform/verisilicon/hantro.h
@@ -77,6 +77,7 @@ struct hantro_irq {
  * @double_buffer:		core needs double buffering
  * @legacy_regs:		core uses legacy register set
  * @late_postproc:		postproc must be set up at the end of the job
+ * @shared_devices:		an array of device ids that cannot run concurrently
  */
 struct hantro_variant {
 	unsigned int enc_offset;
@@ -101,6 +102,7 @@ struct hantro_variant {
 	unsigned int double_buffer : 1;
 	unsigned int legacy_regs : 1;
 	unsigned int late_postproc : 1;
+	const struct of_device_id *shared_devices;
 };
 
 /**
diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c
index 60b95b5d8565..70160eaf3d15 100644
--- a/drivers/media/platform/verisilicon/hantro_drv.c
+++ b/drivers/media/platform/verisilicon/hantro_drv.c
@@ -13,6 +13,7 @@
 #include <linux/clk.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
@@ -1035,6 +1036,41 @@ static int hantro_disable_multicore(struct hantro_dev *vpu)
 	return 0;
 }
 
+static struct v4l2_m2m_dev *hantro_get_v4l2_m2m_dev(struct hantro_dev *vpu)
+{
+	struct device_node *node;
+	struct hantro_dev *shared_vpu;
+
+	if (!vpu->variant || !vpu->variant->shared_devices)
+		goto init_new_m2m_dev;
+
+	for_each_matching_node(node, vpu->variant->shared_devices) {
+		struct platform_device *pdev;
+		struct v4l2_m2m_dev *m2m_dev;
+
+		pdev = of_find_device_by_node(node);
+		of_node_put(node);
+
+		if (!pdev)
+			continue;
+
+		shared_vpu = platform_get_drvdata(pdev);
+		if (IS_ERR_OR_NULL(shared_vpu) || shared_vpu == vpu) {
+			platform_device_put(pdev);
+			continue;
+		}
+
+		v4l2_m2m_get(shared_vpu->m2m_dev);
+		m2m_dev = shared_vpu->m2m_dev;
+		platform_device_put(pdev);
+
+		return m2m_dev;
+	}
+
+init_new_m2m_dev:
+	return v4l2_m2m_init(&vpu_m2m_ops);
+}
+
 static int hantro_probe(struct platform_device *pdev)
 {
 	const struct of_device_id *match;
@@ -1186,7 +1222,7 @@ static int hantro_probe(struct platform_device *pdev)
 	}
 	platform_set_drvdata(pdev, vpu);
 
-	vpu->m2m_dev = v4l2_m2m_init(&vpu_m2m_ops);
+	vpu->m2m_dev = hantro_get_v4l2_m2m_dev(vpu);
 	if (IS_ERR(vpu->m2m_dev)) {
 		v4l2_err(&vpu->v4l2_dev, "Failed to init mem2mem device\n");
 		ret = PTR_ERR(vpu->m2m_dev);
@@ -1225,7 +1261,7 @@ static int hantro_probe(struct platform_device *pdev)
 	hantro_remove_enc_func(vpu);
 err_m2m_rel:
 	media_device_cleanup(&vpu->mdev);
-	v4l2_m2m_release(vpu->m2m_dev);
+	v4l2_m2m_put(vpu->m2m_dev);
 err_v4l2_unreg:
 	v4l2_device_unregister(&vpu->v4l2_dev);
 err_clk_unprepare:
@@ -1248,7 +1284,7 @@ static void hantro_remove(struct platform_device *pdev)
 	hantro_remove_dec_func(vpu);
 	hantro_remove_enc_func(vpu);
 	media_device_cleanup(&vpu->mdev);
-	v4l2_m2m_release(vpu->m2m_dev);
+	v4l2_m2m_put(vpu->m2m_dev);
 	v4l2_device_unregister(&vpu->v4l2_dev);
 	clk_bulk_unprepare(vpu->variant->num_clocks, vpu->clocks);
 	reset_control_assert(vpu->resets);
diff --git a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
index 5be0e2e76882..6f8e43b7f157 100644
--- a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
+++ b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
@@ -343,6 +343,12 @@ const struct hantro_variant imx8mq_vpu_variant = {
 	.num_regs = ARRAY_SIZE(imx8mq_reg_names)
 };
 
+static const struct of_device_id imx8mq_vpu_shared_resources[] __initconst = {
+	{ .compatible = "nxp,imx8mq-vpu-g1", },
+	{ .compatible = "nxp,imx8mq-vpu-g2", },
+	{ /* sentinel */ }
+};
+
 const struct hantro_variant imx8mq_vpu_g1_variant = {
 	.dec_fmts = imx8m_vpu_dec_fmts,
 	.num_dec_fmts = ARRAY_SIZE(imx8m_vpu_dec_fmts),
@@ -356,6 +362,7 @@ const struct hantro_variant imx8mq_vpu_g1_variant = {
 	.num_irqs = ARRAY_SIZE(imx8mq_irqs),
 	.clk_names = imx8mq_g1_clk_names,
 	.num_clocks = ARRAY_SIZE(imx8mq_g1_clk_names),
+	.shared_devices = imx8mq_vpu_shared_resources,
 };
 
 const struct hantro_variant imx8mq_vpu_g2_variant = {
@@ -371,6 +378,7 @@ const struct hantro_variant imx8mq_vpu_g2_variant = {
 	.num_irqs = ARRAY_SIZE(imx8mq_g2_irqs),
 	.clk_names = imx8mq_g2_clk_names,
 	.num_clocks = ARRAY_SIZE(imx8mq_g2_clk_names),
+	.shared_devices = imx8mq_vpu_shared_resources,
 };
 
 const struct hantro_variant imx8mm_vpu_g1_variant = {
-- 
2.52.0



From mike.leach at linaro.org  Thu Dec  4 01:15:07 2025
From: mike.leach at linaro.org (Mike Leach)
Date: Thu, 4 Dec 2025 09:15:07 +0000
Subject: [PATCH v6 2/2] coresight: cti: Add Qualcomm extended CTI support
In-Reply-To: <20251203182944.GG724103@e132581.arm.com>
References: <20251202-extended_cti-v6-0-ab68bb15c4f5@oss.qualcomm.com>
 <20251202-extended_cti-v6-2-ab68bb15c4f5@oss.qualcomm.com> <20251203182944.GG724103@e132581.arm.com>
Message-ID: <CAJ9a7VhcSxTTaxMR4SS+GbHoPHXm0honykjXy92fbv0HG=1o4Q@mail.gmail.com>

Hi

On Wed, 3 Dec 2025 at 18:29, Leo Yan <leo.yan at arm.com> wrote:
>
> On Tue, Dec 02, 2025 at 02:42:21PM +0800, Yingchao Deng wrote:
> > The QCOM extended CTI is a heavily parameterized version of ARM?s CSCTI.
> > It allows a debugger to send to trigger events to a processor or to send
> > a trigger event to one or more processors when a trigger event occurs
> > on another processor on the same SoC, or even between SoCs. Qualcomm CTI
> > implementation differs from the standard CTI in the following aspects:
> >
> > 1. The number of supported triggers is extended to 128.
> > 2. Several register offsets differ from the CoreSight specification.
>
> I apologize for my late review of this series.  For easier maintenance
> later, I have several comments for register access.
>
> [...]
>
> > +static const u32 cti_normal_offset[] = {
> > +     [INDEX_CTIINTACK]               = CTIINTACK,
> > +     [INDEX_CTIAPPSET]               = CTIAPPSET,
> > +     [INDEX_CTIAPPCLEAR]             = CTIAPPCLEAR,
> > +     [INDEX_CTIAPPPULSE]             = CTIAPPPULSE,
> > +     [INDEX_CTIINEN]                 = CTIINEN(0),
> > +     [INDEX_CTIOUTEN]                = CTIOUTEN(0),
>
> I prefer to update the these two macros to CTIINENn and CTIOUTENn, as
> later we will not use CTIINEN(n) and CTIOUTEN(n) anymore.
>
> > +     [INDEX_CTITRIGINSTATUS]         = CTITRIGINSTATUS,
> > +     [INDEX_CTITRIGOUTSTATUS]        = CTITRIGOUTSTATUS,
> > +     [INDEX_CTICHINSTATUS]           = CTICHINSTATUS,
> > +     [INDEX_CTICHOUTSTATUS]          = CTICHOUTSTATUS,
> > +     [INDEX_CTIGATE]                 = CTIGATE,
> > +     [INDEX_ASICCTL]                 = ASICCTL,
> > +     [INDEX_ITCHINACK]               = ITCHINACK,
> > +     [INDEX_ITTRIGINACK]             = ITTRIGINACK,
> > +     [INDEX_ITCHOUT]                 = ITCHOUT,
> > +     [INDEX_ITTRIGOUT]               = ITTRIGOUT,
> > +     [INDEX_ITCHOUTACK]              = ITCHOUTACK,
> > +     [INDEX_ITTRIGOUTACK]            = ITTRIGOUTACK,
> > +     [INDEX_ITCHIN]                  = ITCHIN,
> > +     [INDEX_ITTRIGIN]                = ITTRIGIN,
> > +     [INDEX_ITCTRL]                  = CORESIGHT_ITCTRL,
> > +};
> > +
> > +static const u32 cti_extended_offset[] = {
> > +     [INDEX_CTIINTACK]               = QCOM_CTIINTACK,
> > +     [INDEX_CTIAPPSET]               = QCOM_CTIAPPSET,
> > +     [INDEX_CTIAPPCLEAR]             = QCOM_CTIAPPCLEAR,
> > +     [INDEX_CTIAPPPULSE]             = QCOM_CTIAPPPULSE,
> > +     [INDEX_CTIINEN]                 = QCOM_CTIINEN,
> > +     [INDEX_CTIOUTEN]                = QCOM_CTIOUTEN,
> > +     [INDEX_CTITRIGINSTATUS]         = QCOM_CTITRIGINSTATUS,
> > +     [INDEX_CTITRIGOUTSTATUS]        = QCOM_CTITRIGOUTSTATUS,
> > +     [INDEX_CTICHINSTATUS]           = QCOM_CTICHINSTATUS,
> > +     [INDEX_CTICHOUTSTATUS]          = QCOM_CTICHOUTSTATUS,
> > +     [INDEX_CTIGATE]                 = QCOM_CTIGATE,
> > +     [INDEX_ASICCTL]                 = QCOM_ASICCTL,
> > +     [INDEX_ITCHINACK]               = QCOM_ITCHINACK,
> > +     [INDEX_ITTRIGINACK]             = QCOM_ITTRIGINACK,
> > +     [INDEX_ITCHOUT]                 = QCOM_ITCHOUT,
> > +     [INDEX_ITTRIGOUT]               = QCOM_ITTRIGOUT,
> > +     [INDEX_ITCHOUTACK]              = QCOM_ITCHOUTACK,
> > +     [INDEX_ITTRIGOUTACK]            = QCOM_ITTRIGOUTACK,
> > +     [INDEX_ITCHIN]                  = QCOM_ITCHIN,
> > +     [INDEX_ITTRIGIN]                = QCOM_ITTRIGIN,
> > +     [INDEX_ITCTRL]                  = CORESIGHT_ITCTRL,
> > +};
>
> I saw CTI registers are within 4KiB (0x1000), we can don't convert
> standard regiserts and only convert to QCOM register based on the
> standard ones.  So you can drop the cti_normal_offset strucuture and
> only have a cti_reg_qcom_offset[] struct:
>
>   static const u32 cti_extended_offset[] = {
>         [CTIINTACK]             = QCOM_CTIINTACK,
>         [CTIAPPSET]             = QCOM_CTIAPPSET,
>         [CTIAPPCLEAR]           = QCOM_CTIAPPCLEAR,
>         [CTIAPPPULSE]           = QCOM_CTIAPPPULSE,
>         [CTIINEN]               = QCOM_CTIINEN,
>         ...
>   };
>
> Then you could create two helpers for register address:
>
>     static void __iomem *cti_reg_addr_with_nr(struct cti_drvdata *drvdata,
>                                               u32 reg, u32 nr)
>     {
>         /* convert to qcom specific offset */
>         if (unlikely(drvdata->is_qcom_cti))
>             reg = cti_extended_offset[reg];
>
>         return drvdata->base + reg + sizeof(u32) * nr;
>     }
>
>     static void __iomem *cti_reg_addr(struct cti_drvdata *drvdata, u32 reg)
>     {
>         return cti_reg_addr_with_nr(drvdata, reg, 0);
>     }
>
> >  /*
> >   * CTI devices can be associated with a PE, or be connected to CoreSight
> > @@ -70,15 +119,16 @@ void cti_write_all_hw_regs(struct cti_drvdata *drvdata)
> >
> >       /* write the CTI trigger registers */
> >       for (i = 0; i < config->nr_trig_max; i++) {
> > -             writel_relaxed(config->ctiinen[i], drvdata->base + CTIINEN(i));
> > +             writel_relaxed(config->ctiinen[i],
> > +                            drvdata->base + cti_offset(drvdata, INDEX_CTIINEN, i));
>
> writel_relaxed(config->ctiinen[i],
>                cti_reg_addr_with_nr(drvdata, CTIINENn, i));
>
> And apply for the same cases below.
>
> >       /* other regs */
> > -     writel_relaxed(config->ctigate, drvdata->base + CTIGATE);
> > -     writel_relaxed(config->asicctl, drvdata->base + ASICCTL);
> > -     writel_relaxed(config->ctiappset, drvdata->base + CTIAPPSET);
> > +     writel_relaxed(config->ctigate, drvdata->base + cti_offset(drvdata, INDEX_CTIGATE, 0));
>
> writel_relaxed(config->ctigate, cti_reg_addr(drvdata, CTIGATE));
>
> And apply for the same cases below.
>
> [...]
>
> > @@ -394,8 +447,8 @@ int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,
> >
> >       /* update the local register values */
> >       chan_bitmask = BIT(channel_idx);
> > -     reg_offset = (direction == CTI_TRIG_IN ? CTIINEN(trigger_idx) :
> > -                   CTIOUTEN(trigger_idx));
> > +     reg_offset = (direction == CTI_TRIG_IN ? cti_offset(drvdata, INDEX_CTIINEN, trigger_idx) :
> > +                     cti_offset(drvdata, INDEX_CTIOUTEN, trigger_idx));
>
> For readable, we can improve a bit with code alignment:
>
>   reg_offset = (direction == CTI_TRIG_IN) ? cti_reg_addr_with_nr(drvdata, CTIINENn, trigger_idx) :
>                                             cti_reg_addr_with_nr(drvdata, CTIOUTENn, trigger_idx);
>
> [...]
>
> > @@ -981,9 +1035,28 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id)
> >       drvdata->csdev_release = drvdata->csdev->dev.release;
> >       drvdata->csdev->dev.release = cti_device_release;
> >
> > +     /* check architect value*/
> > +     devarch = readl_relaxed(drvdata->base + CORESIGHT_DEVARCH);
> > +     if (CTI_DEVARCH_ARCHITECT(devarch) == ARCHITECT_QCOM) {
> > +             drvdata->subtype = QCOM_CTI;
> > +             drvdata->offsets = cti_extended_offset;
>
> As a result, we can only set the is_qcom_cti flag:
>
>   drvdata->is_qcom_cti = true;
>
> > +             /*
> > +              * QCOM CTI does not implement Claimtag functionality as
> > +              * per CoreSight specification, but its CLAIMSET register
> > +              * is incorrectly initialized to 0xF. This can mislead
> > +              * tools or drivers into thinking the component is claimed.
> > +              *
> > +              * Reset CLAIMSET to 0 to reflect that no claims are active.
> > +              */
> > +             writel_relaxed(0, drvdata->base + CORESIGHT_CLAIMSET);
>
> I am confused for this.  If QCOM CTI does not implement claim tag,
> then what is the designed register at the offset CORESIGHT_CLAIMSET?
>
> Should you bypass all claim tag related operations for QCOM CTI case?
> (I don't see you touch anything for claim and declaim tags).
>

The patch I have created to handle systems without correct claim tag
operation is a dependency for this patch set. Thus no need for
override here as the core code will handle this correctly.

The only issue is ensuring the non-CTI spec implementation will result
in the correct detection of no claim tags present.

Regards

Miike


> > +     } else {
> > +             drvdata->subtype = ARM_STD_CTI;
> > +             drvdata->offsets = cti_normal_offset;
> > +     }
> > +
> >       /* all done - dec pm refcount */
> >       pm_runtime_put(&adev->dev);
> > -     dev_info(&drvdata->csdev->dev, "CTI initialized\n");
> > +     dev_info(&drvdata->csdev->dev, "CTI initialized; subtype=%d\n", drvdata->subtype);
>
> dev_info(&drvdata->csdev->dev, "%s CTI initialized\n",
>          drvdata->is_qcom_cti ? "QCOM" : "");
>
> >       return 0;
> >
> >  pm_release:
> > diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
> > index a9df77215141..12a495382999 100644
> > --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c
> > +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
> > @@ -172,9 +172,8 @@ static struct attribute *coresight_cti_attrs[] = {
> >
> >  /* register based attributes */
> >
> > -/* Read registers with power check only (no enable check). */
> > -static ssize_t coresight_cti_reg_show(struct device *dev,
> > -                        struct device_attribute *attr, char *buf)
> > +static ssize_t coresight_cti_mgmt_reg_show(struct device *dev,
> > +                                        struct device_attribute *attr, char *buf)
> >  {
> >       struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
> >       struct cs_off_attribute *cti_attr = container_of(attr, struct cs_off_attribute, attr);
> > @@ -189,6 +188,40 @@ static ssize_t coresight_cti_reg_show(struct device *dev,
> >       return sysfs_emit(buf, "0x%x\n", val);
> >  }
> >
> > +/* Read registers with power check only (no enable check). */
> > +static ssize_t coresight_cti_reg_show(struct device *dev,
> > +                                   struct device_attribute *attr, char *buf)
> > +{
> > +     struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
> > +     struct cs_off_attribute *cti_attr = container_of(attr, struct cs_off_attribute, attr);
> > +     u32 idx, val = 0;
> > +
> > +     pm_runtime_get_sync(dev->parent);
> > +     raw_spin_lock(&drvdata->spinlock);
> > +     idx = drvdata->config.ext_reg_sel;
> > +     if (drvdata->config.hw_powered) {
> > +             switch (cti_attr->off) {
> > +             case INDEX_CTITRIGINSTATUS:
> > +             case INDEX_CTITRIGOUTSTATUS:
> > +             case INDEX_ITTRIGINACK:
> > +             case INDEX_ITTRIGOUT:
> > +             case INDEX_ITTRIGOUTACK:
> > +             case INDEX_ITTRIGIN:
> > +                     val = readl_relaxed(drvdata->base +
> > +                                         cti_offset(drvdata, cti_attr->off, idx));
> > +                     break;
> > +
> > +             default:
> > +                     val = readl_relaxed(drvdata->base + cti_offset(drvdata, cti_attr->off, 0));
> > +                     break;
> > +             }
> > +     }
> > +
> > +     raw_spin_unlock(&drvdata->spinlock);
> > +     pm_runtime_put_sync(dev->parent);
> > +     return sysfs_emit(buf, "0x%x\n", val);
> > +}
> > +
> >  /* Write registers with power check only (no enable check). */
> >  static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,
> >                                                     struct device_attribute *attr,
> > @@ -197,19 +230,39 @@ static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,
> >       struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
> >       struct cs_off_attribute *cti_attr = container_of(attr, struct cs_off_attribute, attr);
> >       unsigned long val = 0;
> > +     u32 idx;
> >
> >       if (kstrtoul(buf, 0, &val))
> >               return -EINVAL;
> >
> >       pm_runtime_get_sync(dev->parent);
> >       raw_spin_lock(&drvdata->spinlock);
> > -     if (drvdata->config.hw_powered)
> > -             cti_write_single_reg(drvdata, cti_attr->off, val);
> > +     idx = drvdata->config.ext_reg_sel;
> > +     if (drvdata->config.hw_powered) {
> > +             switch (cti_attr->off) {
> > +             case INDEX_ITTRIGINACK:
> > +             case INDEX_ITTRIGOUT:
> > +                     cti_write_single_reg(drvdata, cti_offset(drvdata, cti_attr->off, idx), val);
> > +                     break;
> > +
> > +             default:
> > +                     cti_write_single_reg(drvdata, cti_offset(drvdata, cti_attr->off, 0), val);
> > +                     break;
> > +             }
> > +     }
>
> For both coresight_cti_reg_show() and coresight_cti_reg_store(), can
> we always use "cti_attr->off" as the offset for regitser access?  I
> mean we don't need the extra config.ext_reg_sel, eventually any
> register we can calculate a offset for it.
>
> >       raw_spin_unlock(&drvdata->spinlock);
> >       pm_runtime_put_sync(dev->parent);
> >       return size;
> >  }
> >
> > +#define coresight_cti_mgmt_reg(name, offset)                         \
> > +     (&((struct cs_off_attribute[]) {                                \
> > +        {                                                            \
> > +             __ATTR(name, 0444, coresight_cti_mgmt_reg_show, NULL),  \
> > +             offset                                                  \
> > +        }                                                            \
> > +     })[0].attr.attr)
> > +
> >  #define coresight_cti_reg(name, offset)                                      \
> >       (&((struct cs_off_attribute[]) {                                \
> >          {                                                            \
> > @@ -237,17 +290,17 @@ static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,
> >
> >  /* coresight management registers */
> >  static struct attribute *coresight_cti_mgmt_attrs[] = {
> > -     coresight_cti_reg(devaff0, CTIDEVAFF0),
> > -     coresight_cti_reg(devaff1, CTIDEVAFF1),
> > -     coresight_cti_reg(authstatus, CORESIGHT_AUTHSTATUS),
> > -     coresight_cti_reg(devarch, CORESIGHT_DEVARCH),
> > -     coresight_cti_reg(devid, CORESIGHT_DEVID),
> > -     coresight_cti_reg(devtype, CORESIGHT_DEVTYPE),
> > -     coresight_cti_reg(pidr0, CORESIGHT_PERIPHIDR0),
> > -     coresight_cti_reg(pidr1, CORESIGHT_PERIPHIDR1),
> > -     coresight_cti_reg(pidr2, CORESIGHT_PERIPHIDR2),
> > -     coresight_cti_reg(pidr3, CORESIGHT_PERIPHIDR3),
> > -     coresight_cti_reg(pidr4, CORESIGHT_PERIPHIDR4),
> > +     coresight_cti_mgmt_reg(devaff0, CTIDEVAFF0),
> > +     coresight_cti_mgmt_reg(devaff1, CTIDEVAFF1),
> > +     coresight_cti_mgmt_reg(authstatus, CORESIGHT_AUTHSTATUS),
> > +     coresight_cti_mgmt_reg(devarch, CORESIGHT_DEVARCH),
> > +     coresight_cti_mgmt_reg(devid, CORESIGHT_DEVID),
> > +     coresight_cti_mgmt_reg(devtype, CORESIGHT_DEVTYPE),
> > +     coresight_cti_mgmt_reg(pidr0, CORESIGHT_PERIPHIDR0),
> > +     coresight_cti_mgmt_reg(pidr1, CORESIGHT_PERIPHIDR1),
> > +     coresight_cti_mgmt_reg(pidr2, CORESIGHT_PERIPHIDR2),
> > +     coresight_cti_mgmt_reg(pidr3, CORESIGHT_PERIPHIDR3),
> > +     coresight_cti_mgmt_reg(pidr4, CORESIGHT_PERIPHIDR4),
>
> I don't see any benefit for updating from coresight_cti_reg() to
> coresight_cti_mgmt_reg().  If really want to do this, should remove
> the macro coresight_cti_reg()?
>
> >       NULL,
> >  };
> >
> > @@ -258,13 +311,15 @@ static struct attribute *coresight_cti_mgmt_attrs[] = {
> >   * If inaccessible & pcached_val not NULL then show cached value.
> >   */
> >  static ssize_t cti_reg32_show(struct device *dev, char *buf,
> > -                           u32 *pcached_val, int reg_offset)
> > +                           u32 *pcached_val, int index)
>
> We don't need to change anything for this.  The passed "reg_offset"
> should be always a final offset, no matter for standard CTI or QCOM
> case, the driver directly uses the offset for register access.
>
> [...]
>
> > +/*
> > + * QCOM CTI supports up to 128 triggers, there are 6 registers need to be
> > + * expanded to up to 4 instances, and ext_reg_sel can be used to indicate
> > + * which one is in use.
> > + * CTITRIGINSTATUS, CTITRIGOUTSTATUS,
> > + * ITTRIGIN, ITTRIGOUT,
> > + * ITTRIGINACK, ITTRIGOUTACK.
> > + */
> > +static ssize_t ext_reg_sel_show(struct device *dev,
> > +                             struct device_attribute *attr,
> > +                             char *buf)
> > +{
> > +     u32 val;
> > +     struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
> > +
> > +     raw_spin_lock(&drvdata->spinlock);
> > +     val = drvdata->config.ext_reg_sel;
> > +     raw_spin_unlock(&drvdata->spinlock);
> > +     return sprintf(buf, "%d\n", val);
> > +}
> > +
> > +static ssize_t ext_reg_sel_store(struct device *dev,
> > +                              struct device_attribute *attr,
> > +                              const char *buf, size_t size)
> > +{
> > +     unsigned long val;
> > +     struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
> > +
> > +     if (kstrtoul(buf, 0, &val))
> > +             return -EINVAL;
> > +     if (val > ((drvdata->config.nr_trig_max + 31) / 32 - 1))
> > +             return -EINVAL;
> > +
> > +     raw_spin_lock(&drvdata->spinlock);
> > +     drvdata->config.ext_reg_sel = val;
> > +     raw_spin_unlock(&drvdata->spinlock);
> > +     return size;
> > +}
>
> As said, I don't think the trigger register is any different from
> other register access.  So the existed APIs would be sufficient.
>
> As a result, we don't need to add two above functions.
>
> Thanks,
> Leo



-- 
Mike Leach
Principal Engineer, ARM Ltd.
Manchester Design Centre. UK


From maz at kernel.org  Thu Dec  4 01:15:29 2025
From: maz at kernel.org (Marc Zyngier)
Date: Thu, 04 Dec 2025 09:15:29 +0000
Subject: Alternative to arm64.nopauth cmdline for disabling Pointer Authentication
In-Reply-To: <3fcf6614-ee83-4a06-9024-83573b2e642e@quicinc.com>
References: <3fcf6614-ee83-4a06-9024-83573b2e642e@quicinc.com>
Message-ID: <86ecpappzi.wl-maz@kernel.org>

On Thu, 04 Dec 2025 04:07:15 +0000,
Pavan Kondeti <pavan.kondeti at oss.qualcomm.com> wrote:
> 
> Hi
> 
> The pointer authentication feature (PAuth) is only supported on
> 0-3 CPUs but it is not supported on 4-7 CPUS on QCS8300.

On what grounds? Hardware incompatibility? I seriously doubt it, since
nobody glues pre-8.3 CPUs to anything more modern. Or, as I expect it,
a firmware implemented with little understanding of what is required?

> The ARM64 cpufeature discovery code expects late CPUs to have
> this feature if boot CPU feature has it since PAuth is enabled
> early. When a conflict like this is detected, the late CPUs are
> not allowed to boot. It is expected that system will continue
> to be functional with CPUs with Pauth feature supported and enabled.
> This is not a desired behavior in production.

What is even less desirable is to produce this sort of contraption.

> We started seeing this problem when Linux is booted in EL2. When Linux
> is running under Gunyah (Type-1 hypervisor), Pointer Authentication
> feature is hidden from EL1 via HCR_EL2.TID3. 
> 
> arm64.nopauth can be passed on kernel cmdline to disable the feature
> in kernel so that all all CPUs can boot on QCS8300. I am told 
> maintaining a custom kernel commandline per SoC in a Generic OS 
> distribution is not recommended and asked to discuss the problem with
> the comunity [1]

Well, you get to own the problem you have created for yourself. You
build hardware/firmware that cannot run generic SW, and yet you want
generic SW to run seamlessly on it. Spot the issue?

> This patch [2] from Catalin adds a devicetree property under memory {}
> to disable MTE. I believe this work predates the id-reg override
> mechanism. However, this made me think if workarounds like this can be
> detected via devicetree, for example a property under cpu { } node.

Not only it predates it, but it also doesn't work in general. For a
start, it is DT specific. How are you going to make that work for
ACPI? I know you don't care, but I do.

> Given that what we put in `chosen { bootargs="" }` kernel under
> respective SoC devicetree can be overridden by bootloader, should we
> have a **sticky** cmdline to specify critical workarounds like this?
> This would be more generic than introducing any new parameters.

You already have a way to have a sticky command-line, by building it
into the kernel. Yes, I understand that this isn't what you want, but:

(1) a user should be allowed to pass the kernel command-line *they*
    want, not what someone has decided for them

(2) the generic mechanism exists, doesn't rely on additional firmware
    specifications, and is used for a whole lot of other QC platforms
    suffering from the same issue of broken firmware.  What are you
    going to do for these?

(3) what if you, by miracle, happened to *fix* the firmware?

To sum it up, the kernel is not in the business of papering over these
issues. You have a tool to work around the problem you have created,
use it. Alternatively, you can always boot on a non-PAC CPU, and be
done with it.

Thanks,

	M.

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


From ardb at kernel.org  Thu Dec  4 01:17:29 2025
From: ardb at kernel.org (Ard Biesheuvel)
Date: Thu, 4 Dec 2025 10:17:29 +0100
Subject: [PATCH v3 0/9] arch,sysfb,efi: Support EDID on non-x86 EFI systems
In-Reply-To: <fc4ea259-3389-46e2-b860-972aa8179507@suse.de>
References: <20251126160854.553077-1-tzimmermann@suse.de> <aSe1ZBXa3JBidhem@r1chard>
 <fc4ea259-3389-46e2-b860-972aa8179507@suse.de>
Message-ID: <CAMj1kXE8Q6FGX5+64gPyW=ExicR4UbnEDeW4ycCsSsD2WtaYJA@mail.gmail.com>

On Thu, 27 Nov 2025 at 08:43, Thomas Zimmermann <tzimmermann at suse.de> wrote:
>
> Hi
>
> Am 27.11.25 um 03:20 schrieb Richard Lyu:
> > Hi Thomas,
> >
> > I am attempting to test this patch series but encountered merge conflicts when applying it to various trees.
> > Could you please clarify the specific base commit (or branch/tag) this series was generated against?
>
> Thanks for testing.
>
> >
> > When testing on the next branch on commits 7a2ff00 and e41ef37, I hit a conflict on PATCH v3 4/9:
> > patching file drivers/pci/vgaarb.c
> > Hunk #2 FAILED at 557.
> > 1 out of 2 hunks FAILED -- rejects in file drivers/pci/vgaarb.c
> >
> > When testing against 3a86608 (Linux 6.18-rc1), the following conflicts occurred:
> > patching file drivers/gpu/drm/sysfb/efidrm.c
> > Hunk #1 FAILED at 24.
> > 1 out of 2 hunks FAILED -- rejects in file drivers/gpu/drm/sysfb/efidrm.c
> > patching file drivers/gpu/drm/sysfb/vesadrm.c
> > Hunk #1 FAILED at 25.
> > 1 out of 2 hunks FAILED -- rejects in file drivers/gpu/drm/sysfb/vesadrm.c
> >
> > Please let me know the correct base, and I will retest.
>
> It's in the cover letter: d724c6f85e80a23ed46b7ebc6e38b527c09d64f5 The
> commit is in linux-next. The idea is that the EFI tree can pick up the
> changes easily in the next cycle. linux-next seemed like the best
> choice. Best regards Thomas

Thanks. I will queue this up as soon as -rc1 is released.


From suzuki.poulose at arm.com  Thu Dec  4 01:22:38 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Thu, 4 Dec 2025 09:22:38 +0000
Subject: [PATCH v6 6/9] dt-bindings: arm: add an interrupt property for
 Coresight CTCU
In-Reply-To: <5a0e4abf-9e7f-4ef9-af02-dd6e34f5cfa8@oss.qualcomm.com>
References: <20250908-enable-byte-cntr-for-tmc-v6-0-1db9e621441a@oss.qualcomm.com>
 <20250908-enable-byte-cntr-for-tmc-v6-6-1db9e621441a@oss.qualcomm.com>
 <66d4488f-941a-4716-b81f-e0f9e1165931@arm.com>
 <5a0e4abf-9e7f-4ef9-af02-dd6e34f5cfa8@oss.qualcomm.com>
Message-ID: <9c00516c-6e07-4c57-a1f1-6dfc32ab3a53@arm.com>

On 04/12/2025 02:53, Jie Gan wrote:
> 
> 
> On 12/4/2025 2:14 AM, Suzuki K Poulose wrote:
>> On 08/09/2025 03:01, Jie Gan wrote:
>>> Add an interrupt property to CTCU device. The interrupt will be 
>>> triggered
>>> when the data size in the ETR buffer exceeds the threshold of the
>>> BYTECNTRVAL register. Programming a threshold in the BYTECNTRVAL 
>>> register
>>> of CTCU device will enable the interrupt.
>>>
>>> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
>>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>>> ---
>>> ? .../devicetree/bindings/arm/qcom,coresight-ctcu.yaml??? | 17 ++++++ 
>>> + ++++++++++
>>> ? 1 file changed, 17 insertions(+)
>>>
>>> diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight- 
>>> ctcu.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight- 
>>> ctcu.yaml
>>> index 843b52eaf872..ea05ad8f3dd3 100644
>>> --- a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
>>> +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
>>> @@ -39,6 +39,16 @@ properties:
>>> ????? items:
>>> ??????? - const: apb
>>> +? interrupts:
>>> +??? items:
>>> +????? - description: Byte cntr interrupt for etr0
>>> +????? - description: Byte cntr interrupt for etr1
>>> +
>>> +? interrupt-names:
>>> +??? items:
>>> +????? - const: etr0
>>> +????? - const: etr1
>>
> 
> Hi Suzuki,
> 
>> Why are they named "etr0" "etr1" ? That would be confusing, isn't it, 
>> especially with the Linux driver naming things randomly for the TMC-ETRs.
>>
> 
> Yes, it will cause misunderstandings since the "etr0" here may not the 
> right device we are expecting.
> 
>>
>> What we want is the "port" number corresponding to the "TMC-ETR" being
>> monitored ?
>>
>> Have you explored other options, "port-0", "port-1" ?
>>
> 
> I think it's much better. Will update in next version.

I am not sure if there exists a better scheme for identifying or
numbering the interrupts. Happy to listen to the DT experts.

Rob, Krzysztof, thoughts ?

Suzuki


> 
> Thanks,
> Jie
> 
>> Suzuki
>>
>>> +
>>> ??? in-ports:
>>> ????? $ref: /schemas/graph.yaml#/properties/ports
>>> @@ -56,6 +66,8 @@ additionalProperties: false
>>> ? examples:
>>> ??? - |
>>> +??? #include <dt-bindings/interrupt-controller/arm-gic.h>
>>> +
>>> ????? ctcu at 1001000 {
>>> ????????? compatible = "qcom,sa8775p-ctcu";
>>> ????????? reg = <0x1001000 0x1000>;
>>> @@ -63,6 +75,11 @@ examples:
>>> ????????? clocks = <&aoss_qmp>;
>>> ????????? clock-names = "apb";
>>> +??????? interrupts = <GIC_SPI 270 IRQ_TYPE_EDGE_RISING>,
>>> +???????????????????? <GIC_SPI 262 IRQ_TYPE_EDGE_RISING>;
>>> +??????? interrupt-names = "etr0",
>>> +????????????????????????? "etr1";
>>> +
>>> ????????? in-ports {
>>> ????????????? #address-cells = <1>;
>>> ????????????? #size-cells = <0>;
>>>
>>
>>
> 



From konrad.dybcio at oss.qualcomm.com  Thu Dec  4 01:34:58 2025
From: konrad.dybcio at oss.qualcomm.com (Konrad Dybcio)
Date: Thu, 4 Dec 2025 10:34:58 +0100
Subject: [PATCH v2 08/11] clk: qcom: dispcc: Add support for display clock
 controller Kaanapali
In-Reply-To: <75e53a37-0fd2-41d6-92bc-fb4ad5856829@oss.qualcomm.com>
References: <20251125-kaanapali-mmcc-v2-v2-0-fb44e78f300b@oss.qualcomm.com>
 <20251125-kaanapali-mmcc-v2-v2-8-fb44e78f300b@oss.qualcomm.com>
 <w3ezxipjucswfswfg2z7b7uyu55bssqatdnbxa6jflii4j7nym@lxsnidrewepu>
 <8d0ec7fc-6eb0-4b71-8e0f-3deaf1f489d6@oss.qualcomm.com>
 <75e53a37-0fd2-41d6-92bc-fb4ad5856829@oss.qualcomm.com>
Message-ID: <69f7f357-d328-4559-be8a-81a9df790f0a@oss.qualcomm.com>

On 12/4/25 8:14 AM, Taniya Das wrote:
> 
> 
> On 12/1/2025 6:50 PM, Konrad Dybcio wrote:
>> On 11/26/25 1:09 AM, Dmitry Baryshkov wrote:
>>> On Tue, Nov 25, 2025 at 11:15:17PM +0530, Taniya Das wrote:
>>>> Support the clock controller driver for Kaanapali to enable display SW to
>>>> be able to control the clocks.
>>>>
>>>> Signed-off-by: Taniya Das <taniya.das at oss.qualcomm.com>
>>>> ---
>>
>> [...]
>>
>>>> +/* 257.142858 MHz Configuration */
>>>
>>> This is a bit strange frequency for the boot config.
> 
> The lowest PLL configuration is used as boot config based on the
> MDP_CLK_SRC clock requirement. The PLLs on Kaanapali can support these
> lower frequencies as well.
> 
> 
>> The frequency map lists this odd cookie as the lowest predefined config,
>> perhaps it was pulled from there.
>>
> 
> Correct Konrad.
> 
>> More interestingly, the only consumer of this PLL (MDP_CLK_SRC) makes no
>> effort to use the m/n/d registers, instead relying on the PLL to re-clock
>> for its ratesetting with a fixed divider of 3 (and div1 @ XO rate).
>>
> 
> The m/n is not preferred in the cases where the PLL needs to slew to
> derive a new VCO frequency. That is the reason to keep the divider
> constant as much as possible to derive a particular frequency.

OK this is roughly what I expected, thanks for the explanation.

> 
>> 257.142858 * 3 = 771.428574 over-drives MDP_CLK_SRC, FWIW.
>>
> 
> The lowest frequency requirement is 85.7MHz and the frequency is derived
> using
> 257.142858 (PLL VCO) / 3 (RCG Div) = 85.714286 MHz
> 
> there is no over-drive at RCG of MDP.

Sorry, you're obviously right, I don't know how I got it backwards..

>> Taniya, we've seen something like this in camera too. Is there a reason
>> the frequency is being set this way?
>>
> 
> We start with the lowest frequency to configure the PLL and frequency
> requirements are decided based on usecases.

I meant the rate-change-through-PLL-reclocking, but you've answered
that above

Konrad


From arnd at kernel.org  Thu Dec  4 01:46:26 2025
From: arnd at kernel.org (Arnd Bergmann)
Date: Thu,  4 Dec 2025 10:46:26 +0100
Subject: [PATCH] drm/imx: select DRM_DISPLAY_HELPER as needed
Message-ID: <20251204094635.1030724-1-arnd@kernel.org>

From: Arnd Bergmann <arnd at arndb.de>

CONFIG_DRM_BRIDGE_CONNECTOR is a bool option that turns on features of
the display helpers, which are in a module controlled by the (tristate)
CONFIG_DRM_DISPLAY_HELPER. If the display helpers are in a loadable
module, a built-in driver trying to use the bridge connectors fails
to link:

x86_64-linux-ld: drivers/gpu/drm/imx/ipuv3/parallel-display.o: in function `imx_pd_bind':
parallel-display.c:(.text+0xcd): undefined reference to `drm_bridge_connector_init'
x86_64-linux-ld: drivers/gpu/drm/imx/ipuv3/imx-ldb.o: in function `imx_ldb_bind':
imx-ldb.c:(.text+0x224): undefined reference to `drm_bridge_connector_init'

Select the DRM_BRIDGE_CONNECTOR symbol as well, to ensure it's built-in
if anything needs it.

Fixes: f94b9707a1c9 ("drm/imx: parallel-display: switch to imx_legacy_bridge / drm_bridge_connector")
Signed-off-by: Arnd Bergmann <arnd at arndb.de>
---
 drivers/gpu/drm/imx/ipuv3/Kconfig | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/imx/ipuv3/Kconfig b/drivers/gpu/drm/imx/ipuv3/Kconfig
index acaf25089001..1c3825a86380 100644
--- a/drivers/gpu/drm/imx/ipuv3/Kconfig
+++ b/drivers/gpu/drm/imx/ipuv3/Kconfig
@@ -13,6 +13,7 @@ config DRM_IMX
 config DRM_IMX_PARALLEL_DISPLAY
 	tristate "Support for parallel displays"
 	depends on DRM_IMX
+	select DRM_DISPLAY_HELPER
 	select DRM_BRIDGE
 	select DRM_BRIDGE_CONNECTOR
 	select DRM_IMX_LEGACY_BRIDGE
@@ -33,6 +34,7 @@ config DRM_IMX_LDB
 	depends on DRM_IMX
 	depends on COMMON_CLK
 	select MFD_SYSCON
+	select DRM_DISPLAY_HELPER
 	select DRM_BRIDGE
 	select DRM_BRIDGE_CONNECTOR
 	select DRM_PANEL_BRIDGE
-- 
2.39.5



From dmitry.baryshkov at oss.qualcomm.com  Thu Dec  4 01:47:28 2025
From: dmitry.baryshkov at oss.qualcomm.com (Dmitry Baryshkov)
Date: Thu, 4 Dec 2025 11:47:28 +0200
Subject: [PATCH] drm/imx: select DRM_DISPLAY_HELPER as needed
In-Reply-To: <20251204094635.1030724-1-arnd@kernel.org>
References: <20251204094635.1030724-1-arnd@kernel.org>
Message-ID: <191ee8f8-b48a-44be-9b2a-3690a362c541@oss.qualcomm.com>

On 04/12/2025 11:46, Arnd Bergmann wrote:
> From: Arnd Bergmann <arnd at arndb.de>
> 
> CONFIG_DRM_BRIDGE_CONNECTOR is a bool option that turns on features of
> the display helpers, which are in a module controlled by the (tristate)
> CONFIG_DRM_DISPLAY_HELPER. If the display helpers are in a loadable
> module, a built-in driver trying to use the bridge connectors fails
> to link:
> 
> x86_64-linux-ld: drivers/gpu/drm/imx/ipuv3/parallel-display.o: in function `imx_pd_bind':
> parallel-display.c:(.text+0xcd): undefined reference to `drm_bridge_connector_init'
> x86_64-linux-ld: drivers/gpu/drm/imx/ipuv3/imx-ldb.o: in function `imx_ldb_bind':
> imx-ldb.c:(.text+0x224): undefined reference to `drm_bridge_connector_init'
> 
> Select the DRM_BRIDGE_CONNECTOR symbol as well, to ensure it's built-in
> if anything needs it.
> 
> Fixes: f94b9707a1c9 ("drm/imx: parallel-display: switch to imx_legacy_bridge / drm_bridge_connector")
> Signed-off-by: Arnd Bergmann <arnd at arndb.de>
> ---
>   drivers/gpu/drm/imx/ipuv3/Kconfig | 2 ++
>   1 file changed, 2 insertions(+)

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>

-- 
With best wishes
Dmitry


From maz at kernel.org  Thu Dec  4 01:47:59 2025
From: maz at kernel.org (Marc Zyngier)
Date: Thu,  4 Dec 2025 09:47:59 +0000
Subject: [PATCH v3 2/9] KVM: arm64: Add trap routing for GMID_EL1
In-Reply-To: <20251204094806.3846619-1-maz@kernel.org>
References: <20251204094806.3846619-1-maz@kernel.org>
Message-ID: <20251204094806.3846619-3-maz@kernel.org>

HCR_EL2.TID5 is currently ignored by the trap routing infrastructure.
Wire it in the routing table so that GMID_EL1, the sole register
trapped by this bit, is correctly handled in the NV case.

Signed-off-by: Marc Zyngier <maz at kernel.org>
---
 arch/arm64/kvm/emulate-nested.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c
index 834f13fb1fb7d..616eb6ad68701 100644
--- a/arch/arm64/kvm/emulate-nested.c
+++ b/arch/arm64/kvm/emulate-nested.c
@@ -70,6 +70,7 @@ enum cgt_group_id {
 	CGT_HCR_ENSCXT,
 	CGT_HCR_TTLBIS,
 	CGT_HCR_TTLBOS,
+	CGT_HCR_TID5,
 
 	CGT_MDCR_TPMCR,
 	CGT_MDCR_TPM,
@@ -308,6 +309,12 @@ static const struct trap_bits coarse_trap_bits[] = {
 		.mask		= HCR_TTLBOS,
 		.behaviour	= BEHAVE_FORWARD_RW,
 	},
+	[CGT_HCR_TID5] = {
+		.index		= HCR_EL2,
+		.value		= HCR_TID5,
+		.mask		= HCR_TID5,
+		.behaviour	= BEHAVE_FORWARD_RW,
+	},
 	[CGT_MDCR_TPMCR] = {
 		.index		= MDCR_EL2,
 		.value		= MDCR_EL2_TPMCR,
@@ -665,6 +672,7 @@ static const struct encoding_to_trap_config encoding_to_cgt[] __initconst = {
 	SR_TRAP(SYS_CCSIDR2_EL1,	CGT_HCR_TID2_TID4),
 	SR_TRAP(SYS_CLIDR_EL1,		CGT_HCR_TID2_TID4),
 	SR_TRAP(SYS_CSSELR_EL1,		CGT_HCR_TID2_TID4),
+	SR_TRAP(SYS_GMID_EL1,		CGT_HCR_TID5),
 	SR_RANGE_TRAP(SYS_ID_PFR0_EL1,
 		      sys_reg(3, 0, 0, 7, 7), CGT_HCR_TID3),
 	SR_TRAP(SYS_ICC_SGI0R_EL1,	CGT_HCR_IMO_FMO_ICH_HCR_TC),
-- 
2.47.3



From maz at kernel.org  Thu Dec  4 01:48:00 2025
From: maz at kernel.org (Marc Zyngier)
Date: Thu,  4 Dec 2025 09:48:00 +0000
Subject: [PATCH v3 3/9] KVM: arm64: Add a generic synchronous exception injection primitive
In-Reply-To: <20251204094806.3846619-1-maz@kernel.org>
References: <20251204094806.3846619-1-maz@kernel.org>
Message-ID: <20251204094806.3846619-4-maz@kernel.org>

Maybe in a surprising way, we don't currently have a generic way
to inject a synchronous exception at the EL the vcpu is currently
running at.

Extract such primitive from the UNDEF injection code.

Reviewed-by: Ben Horgan <ben.horgan at arm.com>
Reviewed-by: Yuan Yao <yaoyuan at linux.alibaba.com>
Signed-off-by: Marc Zyngier <maz at kernel.org>
---
 arch/arm64/include/asm/kvm_emulate.h |  1 +
 arch/arm64/kvm/inject_fault.c        | 10 +++++++---
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index c9eab316398e2..df20d47f0d256 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -45,6 +45,7 @@ bool kvm_condition_valid32(const struct kvm_vcpu *vcpu);
 void kvm_skip_instr32(struct kvm_vcpu *vcpu);
 
 void kvm_inject_undefined(struct kvm_vcpu *vcpu);
+void kvm_inject_sync(struct kvm_vcpu *vcpu, u64 esr);
 int kvm_inject_serror_esr(struct kvm_vcpu *vcpu, u64 esr);
 int kvm_inject_sea(struct kvm_vcpu *vcpu, bool iabt, u64 addr);
 void kvm_inject_size_fault(struct kvm_vcpu *vcpu);
diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
index dfcd66c655179..7102424a3fa5e 100644
--- a/arch/arm64/kvm/inject_fault.c
+++ b/arch/arm64/kvm/inject_fault.c
@@ -162,12 +162,16 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
 	vcpu_write_sys_reg(vcpu, esr, exception_esr_elx(vcpu));
 }
 
+void kvm_inject_sync(struct kvm_vcpu *vcpu, u64 esr)
+{
+	pend_sync_exception(vcpu);
+	vcpu_write_sys_reg(vcpu, esr, exception_esr_elx(vcpu));
+}
+
 static void inject_undef64(struct kvm_vcpu *vcpu)
 {
 	u64 esr = (ESR_ELx_EC_UNKNOWN << ESR_ELx_EC_SHIFT);
 
-	pend_sync_exception(vcpu);
-
 	/*
 	 * Build an unknown exception, depending on the instruction
 	 * set.
@@ -175,7 +179,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
 	if (kvm_vcpu_trap_il_is32bit(vcpu))
 		esr |= ESR_ELx_IL;
 
-	vcpu_write_sys_reg(vcpu, esr, exception_esr_elx(vcpu));
+	kvm_inject_sync(vcpu, esr);
 }
 
 #define DFSR_FSC_EXTABT_LPAE	0x10
-- 
2.47.3



From maz at kernel.org  Thu Dec  4 01:48:02 2025
From: maz at kernel.org (Marc Zyngier)
Date: Thu,  4 Dec 2025 09:48:02 +0000
Subject: [PATCH v3 5/9] KVM: arm64: Handle CSSIDR2_EL1 and SMIDR_EL1 in a generic way
In-Reply-To: <20251204094806.3846619-1-maz@kernel.org>
References: <20251204094806.3846619-1-maz@kernel.org>
Message-ID: <20251204094806.3846619-6-maz@kernel.org>

Now that we can handle ID registers using the FEAT_IDST infrastrcuture,
get rid of the handling of CSSIDR2_EL1 and SMIDR_EL1.

Signed-off-by: Marc Zyngier <maz at kernel.org>
---
 arch/arm64/kvm/sys_regs.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index ec3fbe0b8d525..ae1e72df1ed45 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -3399,8 +3399,6 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	{ SYS_DESC(SYS_CCSIDR_EL1), access_ccsidr },
 	{ SYS_DESC(SYS_CLIDR_EL1), access_clidr, reset_clidr, CLIDR_EL1,
 	  .set_user = set_clidr, .val = ~CLIDR_EL1_RES0 },
-	{ SYS_DESC(SYS_CCSIDR2_EL1), undef_access },
-	{ SYS_DESC(SYS_SMIDR_EL1), undef_access },
 	IMPLEMENTATION_ID(AIDR_EL1, GENMASK_ULL(63, 0)),
 	{ SYS_DESC(SYS_CSSELR_EL1), access_csselr, reset_unknown, CSSELR_EL1 },
 	ID_FILTERED(CTR_EL0, ctr_el0,
-- 
2.47.3



From maz at kernel.org  Thu Dec  4 01:47:58 2025
From: maz at kernel.org (Marc Zyngier)
Date: Thu,  4 Dec 2025 09:47:58 +0000
Subject: [PATCH v3 1/9] arm64: Repaint ID_AA64MMFR2_EL1.IDS description
In-Reply-To: <20251204094806.3846619-1-maz@kernel.org>
References: <20251204094806.3846619-1-maz@kernel.org>
Message-ID: <20251204094806.3846619-2-maz@kernel.org>

ID_AA64MMFR2_EL1.IDS, as described in the sysreg file, is pretty horrible
as it diesctly give the ESR value. Repaint it using the usual NI/IMP
identifiers to describe the absence/presence of FEAT_IDST.

Signed-off-by: Marc Zyngier <maz at kernel.org>
---
 arch/arm64/kvm/hyp/nvhe/sys_regs.c | 2 +-
 arch/arm64/tools/sysreg            | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/sys_regs.c b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
index 82da9b03692d4..107d62921b168 100644
--- a/arch/arm64/kvm/hyp/nvhe/sys_regs.c
+++ b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
@@ -134,7 +134,7 @@ static const struct pvm_ftr_bits pvmid_aa64mmfr2[] = {
 	MAX_FEAT(ID_AA64MMFR2_EL1, UAO, IMP),
 	MAX_FEAT(ID_AA64MMFR2_EL1, IESB, IMP),
 	MAX_FEAT(ID_AA64MMFR2_EL1, AT, IMP),
-	MAX_FEAT_ENUM(ID_AA64MMFR2_EL1, IDS, 0x18),
+	MAX_FEAT_ENUM(ID_AA64MMFR2_EL1, IDS, IMP),
 	MAX_FEAT(ID_AA64MMFR2_EL1, TTL, IMP),
 	MAX_FEAT(ID_AA64MMFR2_EL1, BBM, 2),
 	MAX_FEAT(ID_AA64MMFR2_EL1, E0PD, IMP),
diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
index 1c6cdf9d54bba..3261e8791ac03 100644
--- a/arch/arm64/tools/sysreg
+++ b/arch/arm64/tools/sysreg
@@ -2257,8 +2257,8 @@ UnsignedEnum	43:40	FWB
 	0b0001	IMP
 EndEnum
 Enum	39:36	IDS
-	0b0000	0x0
-	0b0001	0x18
+	0b0000	NI
+	0b0001	IMP
 EndEnum
 UnsignedEnum	35:32	AT
 	0b0000	NI
-- 
2.47.3



From maz at kernel.org  Thu Dec  4 01:48:01 2025
From: maz at kernel.org (Marc Zyngier)
Date: Thu,  4 Dec 2025 09:48:01 +0000
Subject: [PATCH v3 4/9] KVM: arm64: Handle FEAT_IDST for sysregs without specific handlers
In-Reply-To: <20251204094806.3846619-1-maz@kernel.org>
References: <20251204094806.3846619-1-maz@kernel.org>
Message-ID: <20251204094806.3846619-5-maz@kernel.org>

Add a bit of infrastrtcture to triage_sysreg_trap() to handle the
case of registers falling into the Feature ID space that do not
have a local handler.

For these, we can directly apply the FEAT_IDST semantics and inject
an EC=0x18 exception. Otherwise, an UNDEF will do.

Signed-off-by: Marc Zyngier <maz at kernel.org>
---
 arch/arm64/kvm/emulate-nested.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c
index 616eb6ad68701..fac2707221b47 100644
--- a/arch/arm64/kvm/emulate-nested.c
+++ b/arch/arm64/kvm/emulate-nested.c
@@ -2588,6 +2588,26 @@ bool triage_sysreg_trap(struct kvm_vcpu *vcpu, int *sr_index)
 
 		params = esr_sys64_to_params(esr);
 
+		/*
+		 * This implements the pseudocode UnimplementedIDRegister()
+		 * helper for the purpose of fealing with FEAT_IDST.
+		 *
+		 * The Feature ID space is defined as the System register
+		 * space in AArch64 with op0==3, op1=={0, 1, 3}, CRn==0,
+		 * CRm=={0-7}, op2=={0-7}.
+		 */
+		if (params.Op0 == 3 &&
+		    !(params.Op1 & 0b100) && params.Op1 != 2 &&
+		    params.CRn == 0 &&
+		    !(params.CRm & 0b1000)) {
+			if (kvm_has_feat_enum(vcpu->kvm, ID_AA64MMFR2_EL1, IDS, IMP))
+				kvm_inject_sync(vcpu, kvm_vcpu_get_esr(vcpu));
+			else
+				kvm_inject_undefined(vcpu);
+
+			return true;
+		}
+
 		/*
 		 * Check for the IMPDEF range, as per DDI0487 J.a,
 		 * D18.3.2 Reserved encodings for IMPLEMENTATION
-- 
2.47.3



From maz at kernel.org  Thu Dec  4 01:48:03 2025
From: maz at kernel.org (Marc Zyngier)
Date: Thu,  4 Dec 2025 09:48:03 +0000
Subject: [PATCH v3 6/9] KVM: arm64: Force trap of GMID_EL1 when the guest doesn't have MTE
In-Reply-To: <20251204094806.3846619-1-maz@kernel.org>
References: <20251204094806.3846619-1-maz@kernel.org>
Message-ID: <20251204094806.3846619-7-maz@kernel.org>

If our host has MTE, but the guest doesn't, make sure we set HCR_EL2.TID5
to force GMID_EL1 being trapped. Such trap will be handled by the
FEAT_IDST handling.

Reviewed-by: Joey Gouly <joey.gouly at arm.com>
Signed-off-by: Marc Zyngier <maz at kernel.org>
---
 arch/arm64/kvm/sys_regs.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index ae1e72df1ed45..2e94c423594eb 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -5558,6 +5558,8 @@ static void vcpu_set_hcr(struct kvm_vcpu *vcpu)
 
 	if (kvm_has_mte(vcpu->kvm))
 		vcpu->arch.hcr_el2 |= HCR_ATA;
+	else
+		vcpu->arch.hcr_el2 |= HCR_TID5;
 
 	/*
 	 * In the absence of FGT, we cannot independently trap TLBI
-- 
2.47.3



From maz at kernel.org  Thu Dec  4 01:47:57 2025
From: maz at kernel.org (Marc Zyngier)
Date: Thu,  4 Dec 2025 09:47:57 +0000
Subject: [PATCH v3 0/9] KVM: arm64: Add support for FEAT_IDST
Message-ID: <20251204094806.3846619-1-maz@kernel.org>

FEAT_IDST appeared in ARMv8.4, and allows ID registers to be trapped
if they are not implemented. This only concerns 3 registers (GMID_EL1,
CCSIDR2_EL1 and SMIDR_EL1), which are part of features that may not be
exposed to the guest even if present on the host.

For these registers, the HW should report them with EC=0x18, even if
the feature isn't implemented.

Add support for this feature by handling these registers in a specific
way and implementing GMID_EL1 support in the process. A very basic
selftest checks that these registers behave as expected.

* From v2: [2]

  - Repainted ID_AA64MMFR2_EL1.IDS description (Oliver)

  - Made the IDST handling more generic in the core KVM code, which
    resulted in the series being restructured a bit

  - Added handling to pKVM (in a slightly different way, as pKVM
    insist on seeing a full enumeration of the trapped registers)

  - Some cleanups

  - Collected RBs, with thanks

* From v1: [1]

  - Fixed commit message in patch #4 (Ben)

  - Collected RB, with thanks (Joey)

[1] https://lore.kernel.org/r/20251120133202.2037803-1-maz at kernel.org
[2] https://lore.kernel.org/r/20251126155951.1146317-1-maz at kernel.org

Marc Zyngier (9):
  arm64: Repaint ID_AA64MMFR2_EL1.IDS description
  KVM: arm64: Add trap routing for GMID_EL1
  KVM: arm64: Add a generic synchronous exception injection primitive
  KVM: arm64: Handle FEAT_IDST for sysregs without specific handlers
  KVM: arm64: Handle CSSIDR2_EL1 and SMIDR_EL1 in a generic way
  KVM: arm64: Force trap of GMID_EL1 when the guest doesn't have MTE
  KVM: arm64: pkvm: Add a generic synchronous exception injection
    primitive
  KVM: arm64: pkvm: Report optional ID register traps with a 0x18
    syndrome
  KVM: arm64: selftests: Add a test for FEAT_IDST

 arch/arm64/include/asm/kvm_emulate.h          |   1 +
 arch/arm64/kvm/emulate-nested.c               |  28 +++++
 arch/arm64/kvm/hyp/nvhe/sys_regs.c            |  39 ++++--
 arch/arm64/kvm/inject_fault.c                 |  10 +-
 arch/arm64/kvm/sys_regs.c                     |   4 +-
 arch/arm64/tools/sysreg                       |   4 +-
 tools/testing/selftests/kvm/Makefile.kvm      |   1 +
 .../testing/selftests/kvm/arm64/idreg-idst.c  | 117 ++++++++++++++++++
 8 files changed, 189 insertions(+), 15 deletions(-)
 create mode 100644 tools/testing/selftests/kvm/arm64/idreg-idst.c

-- 
2.47.3



From maz at kernel.org  Thu Dec  4 01:48:04 2025
From: maz at kernel.org (Marc Zyngier)
Date: Thu,  4 Dec 2025 09:48:04 +0000
Subject: [PATCH v3 7/9] KVM: arm64: pkvm: Add a generic synchronous exception injection primitive
In-Reply-To: <20251204094806.3846619-1-maz@kernel.org>
References: <20251204094806.3846619-1-maz@kernel.org>
Message-ID: <20251204094806.3846619-8-maz@kernel.org>

Similarly to the "classic" KVM code, pKVM doesn't have an "anything
goes" synchronous exception injection primitive.

Carve one out of the UNDEF injection code.

Signed-off-by: Marc Zyngier <maz at kernel.org>
---
 arch/arm64/kvm/hyp/nvhe/sys_regs.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/sys_regs.c b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
index 107d62921b168..876b36d3d4788 100644
--- a/arch/arm64/kvm/hyp/nvhe/sys_regs.c
+++ b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
@@ -243,16 +243,15 @@ static u64 pvm_calc_id_reg(const struct kvm_vcpu *vcpu, u32 id)
 	}
 }
 
-/*
- * Inject an unknown/undefined exception to an AArch64 guest while most of its
- * sysregs are live.
- */
-static void inject_undef64(struct kvm_vcpu *vcpu)
+static void inject_sync64(struct kvm_vcpu *vcpu, u64 esr)
 {
-	u64 esr = (ESR_ELx_EC_UNKNOWN << ESR_ELx_EC_SHIFT);
-
 	*vcpu_pc(vcpu) = read_sysreg_el2(SYS_ELR);
 	*vcpu_cpsr(vcpu) = read_sysreg_el2(SYS_SPSR);
+
+	/*
+	 * Make sure we have the latest update to VBAR_EL1, as pKVM
+	 * handles traps very early, before sysregs are resync'ed
+	 */
 	__vcpu_assign_sys_reg(vcpu, VBAR_EL1, read_sysreg_el1(SYS_VBAR));
 
 	kvm_pend_exception(vcpu, EXCEPT_AA64_EL1_SYNC);
@@ -265,6 +264,15 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
 	write_sysreg_el2(*vcpu_cpsr(vcpu), SYS_SPSR);
 }
 
+/*
+ * Inject an unknown/undefined exception to an AArch64 guest while most of its
+ * sysregs are live.
+ */
+static void inject_undef64(struct kvm_vcpu *vcpu)
+{
+	inject_sync64(vcpu, (ESR_ELx_EC_UNKNOWN << ESR_ELx_EC_SHIFT));
+}
+
 static u64 read_id_reg(const struct kvm_vcpu *vcpu,
 		       struct sys_reg_desc const *r)
 {
-- 
2.47.3



From maz at kernel.org  Thu Dec  4 01:48:05 2025
From: maz at kernel.org (Marc Zyngier)
Date: Thu,  4 Dec 2025 09:48:05 +0000
Subject: [PATCH v3 8/9] KVM: arm64: pkvm: Report optional ID register traps with a 0x18 syndrome
In-Reply-To: <20251204094806.3846619-1-maz@kernel.org>
References: <20251204094806.3846619-1-maz@kernel.org>
Message-ID: <20251204094806.3846619-9-maz@kernel.org>

With FEAT_IDST, unimplemented system registers in the feature ID space
must be reported using EC=0x18 at the closest handling EL, rather than
with an UNDEF.

Most of these system registers are always implemented thanks to their
dependency on FEAT_AA64, except for a set of (currently) three registers:
GMID_EL1 (depending on MTE2), CCSIDR2_EL1 (depending on FEAT_CCIDX),
and SMIDR_EL1 (depending on SME).

For these three registers, report their trap as EC=0x18 if they
end-up trapping into KVM and that FEAT_IDST is implemented in the guest.
Otherwise, just make them UNDEF.

Signed-off-by: Marc Zyngier <maz at kernel.org>
---
 arch/arm64/kvm/hyp/nvhe/sys_regs.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/arch/arm64/kvm/hyp/nvhe/sys_regs.c b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
index 876b36d3d4788..efc36645f4b5a 100644
--- a/arch/arm64/kvm/hyp/nvhe/sys_regs.c
+++ b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
@@ -347,6 +347,18 @@ static bool pvm_gic_read_sre(struct kvm_vcpu *vcpu,
 	return true;
 }
 
+static bool pvm_idst_access(struct kvm_vcpu *vcpu,
+			    struct sys_reg_params *p,
+			    const struct sys_reg_desc *r)
+{
+	if (kvm_has_feat_enum(vcpu->kvm, ID_AA64MMFR2_EL1, IDS, NI))
+		inject_undef64(vcpu);
+	else
+		inject_sync64(vcpu, kvm_vcpu_get_esr(vcpu));
+
+	return false;
+}
+
 /* Mark the specified system register as an AArch32 feature id register. */
 #define AARCH32(REG) { SYS_DESC(REG), .access = pvm_access_id_aarch32 }
 
@@ -472,6 +484,9 @@ static const struct sys_reg_desc pvm_sys_reg_descs[] = {
 
 	HOST_HANDLED(SYS_CCSIDR_EL1),
 	HOST_HANDLED(SYS_CLIDR_EL1),
+	{ SYS_DESC(SYS_CCSIDR2_EL1), .access = pvm_idst_access },
+	{ SYS_DESC(SYS_GMID_EL1), .access = pvm_idst_access },
+	{ SYS_DESC(SYS_SMIDR_EL1), .access = pvm_idst_access },
 	HOST_HANDLED(SYS_AIDR_EL1),
 	HOST_HANDLED(SYS_CSSELR_EL1),
 	HOST_HANDLED(SYS_CTR_EL0),
-- 
2.47.3



From maz at kernel.org  Thu Dec  4 01:48:06 2025
From: maz at kernel.org (Marc Zyngier)
Date: Thu,  4 Dec 2025 09:48:06 +0000
Subject: [PATCH v3 9/9] KVM: arm64: selftests: Add a test for FEAT_IDST
In-Reply-To: <20251204094806.3846619-1-maz@kernel.org>
References: <20251204094806.3846619-1-maz@kernel.org>
Message-ID: <20251204094806.3846619-10-maz@kernel.org>

Add a very basic test checking that FEAT_IDST actually works for
the {GMID,SMIDR,CSSIDR2}_EL1 registers.

Signed-off-by: Marc Zyngier <maz at kernel.org>
---
 tools/testing/selftests/kvm/Makefile.kvm      |   1 +
 .../testing/selftests/kvm/arm64/idreg-idst.c  | 117 ++++++++++++++++++
 2 files changed, 118 insertions(+)
 create mode 100644 tools/testing/selftests/kvm/arm64/idreg-idst.c

diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 148d427ff24be..fa44e6d9afc35 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -171,6 +171,7 @@ TEST_GEN_PROGS_arm64 += arm64/vgic_irq
 TEST_GEN_PROGS_arm64 += arm64/vgic_lpi_stress
 TEST_GEN_PROGS_arm64 += arm64/vpmu_counter_access
 TEST_GEN_PROGS_arm64 += arm64/no-vgic-v3
+TEST_GEN_PROGS_arm64 += arm64/idreg-idst
 TEST_GEN_PROGS_arm64 += arm64/kvm-uuid
 TEST_GEN_PROGS_arm64 += access_tracking_perf_test
 TEST_GEN_PROGS_arm64 += arch_timer
diff --git a/tools/testing/selftests/kvm/arm64/idreg-idst.c b/tools/testing/selftests/kvm/arm64/idreg-idst.c
new file mode 100644
index 0000000000000..9ca9f125abdb7
--- /dev/null
+++ b/tools/testing/selftests/kvm/arm64/idreg-idst.c
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Access all FEAT_IDST-handled registers that depend on more than
+ * just FEAT_AA64, and fail if we don't get an a trap with an 0x18 EC.
+ */
+
+#include <test_util.h>
+#include <kvm_util.h>
+#include <processor.h>
+
+static volatile bool sys64, undef;
+
+#define __check_sr_read(r)					\
+	({							\
+		uint64_t val;					\
+								\
+		sys64 = false;					\
+		undef = false;					\
+		dsb(sy);					\
+		val = read_sysreg_s(SYS_ ## r);			\
+		val;						\
+	})
+
+/* Fatal checks */
+#define check_sr_read(r)					\
+	do {							\
+		__check_sr_read(r);				\
+		__GUEST_ASSERT(!undef, #r " unexpected UNDEF");	\
+		__GUEST_ASSERT(sys64, #r " didn't trap");	\
+	} while(0)
+
+
+static void guest_code(void)
+{
+	check_sr_read(CCSIDR2_EL1);
+	check_sr_read(SMIDR_EL1);
+	check_sr_read(GMID_EL1);
+
+	GUEST_DONE();
+}
+
+static void guest_sys64_handler(struct ex_regs *regs)
+{
+	sys64 = true;
+	undef = false;
+	regs->pc += 4;
+}
+
+static void guest_undef_handler(struct ex_regs *regs)
+{
+	sys64 = false;
+	undef = true;
+	regs->pc += 4;
+}
+
+static void test_run_vcpu(struct kvm_vcpu *vcpu)
+{
+	struct ucall uc;
+
+	do {
+		vcpu_run(vcpu);
+
+		switch (get_ucall(vcpu, &uc)) {
+		case UCALL_ABORT:
+			REPORT_GUEST_ASSERT(uc);
+			break;
+		case UCALL_PRINTF:
+			printf("%s", uc.buffer);
+			break;
+		case UCALL_DONE:
+			break;
+		default:
+			TEST_FAIL("Unknown ucall %lu", uc.cmd);
+		}
+	} while (uc.cmd != UCALL_DONE);
+}
+
+static void test_guest_feat_idst(void)
+{
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+
+	/* This VM has no MTE, no SME, no CCIDX */
+	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+
+	vm_init_descriptor_tables(vm);
+	vcpu_init_descriptor_tables(vcpu);
+
+	vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT,
+				ESR_ELx_EC_SYS64, guest_sys64_handler);
+	vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT,
+				ESR_ELx_EC_UNKNOWN, guest_undef_handler);
+
+	test_run_vcpu(vcpu);
+
+	kvm_vm_free(vm);
+}
+
+int main(int argc, char *argv[])
+{
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+	uint64_t mmfr2;
+
+	test_disable_default_vgic();
+
+	vm = vm_create_with_one_vcpu(&vcpu, NULL);
+	mmfr2 = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64MMFR2_EL1));
+	__TEST_REQUIRE(FIELD_GET(ID_AA64MMFR2_EL1_IDS, mmfr2) > 0,
+		       "FEAT_IDST not supported");
+	kvm_vm_free(vm);
+
+	test_guest_feat_idst();
+
+	return 0;
+}
-- 
2.47.3



From arnd at kernel.org  Thu Dec  4 01:53:47 2025
From: arnd at kernel.org (Arnd Bergmann)
Date: Thu,  4 Dec 2025 10:53:47 +0100
Subject: [PATCH] ARM: omap1: avoid symbol clashes in fiq handler
Message-ID: <20251204095355.1032786-1-arnd@kernel.org>

From: Arnd Bergmann <arnd at arndb.de>

The ams-delta-fiq-handler.S file has a number of symbols with fairly
generic names, including one named 'exit' that causes a compiler warning
in some configuration options:

vmlinux.o: error: exit() function name creates ambiguity with -ffunction-sections

Change all these symbols to use a .L prefix to make them local to
the fiq handler.

Signed-off-by: Arnd Bergmann <arnd at arndb.de>
---
 arch/arm/mach-omap1/ams-delta-fiq-handler.S | 38 ++++++++++-----------
 1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/arch/arm/mach-omap1/ams-delta-fiq-handler.S b/arch/arm/mach-omap1/ams-delta-fiq-handler.S
index 35c2f9574dbd..5cf6fcca602c 100644
--- a/arch/arm/mach-omap1/ams-delta-fiq-handler.S
+++ b/arch/arm/mach-omap1/ams-delta-fiq-handler.S
@@ -97,7 +97,7 @@ ENTRY(qwerty_fiqin_start)
 
 	ldr r13, [r12, #IRQ_ITR_REG_OFFSET]	@ fetch interrupts status
 	bics r13, r13, r11			@ clear masked - any left?
-	beq exit				@ none - spurious FIQ? exit
+	beq .Lexit				@ none - spurious FIQ? exit
 
 	ldr r10, [r12, #IRQ_SIR_FIQ_REG_OFFSET]	@ get requested interrupt number
 
@@ -105,25 +105,25 @@ ENTRY(qwerty_fiqin_start)
 	str r8, [r12, #IRQ_CONTROL_REG_OFFSET]
 
 	cmp r10, #(INT_GPIO_BANK1 - NR_IRQS_LEGACY)	@ is it GPIO interrupt?
-	beq gpio				@ yes - process it
+	beq .Lgpio				@ yes - process it
 
 	mov r8, #1
 	orr r8, r11, r8, lsl r10		@ mask spurious interrupt
 	str r8, [r12, #IRQ_MIR_REG_OFFSET]
-exit:
+.Lexit:
 	subs	pc, lr, #4			@ return from FIQ
 	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
 
 	@@@@@@@@@@@@@@@@@@@@@@@@@@@
-gpio:	@ GPIO bank interrupt handler
+.Lgpio:	@ GPIO bank interrupt handler
 	ldr r12, omap1510_gpio_base		@ set base pointer to GPIO bank
 
 	ldr r11, [r12, #OMAP1510_GPIO_INT_MASK]	@ fetch GPIO interrupts mask
-restart:
+.Lrestart:
 	ldr r13, [r12, #OMAP1510_GPIO_INT_STATUS]	@ fetch status bits
 	bics r13, r13, r11			@ clear masked - any left?
-	beq exit				@ no - spurious interrupt? exit
+	beq .Lexit				@ no - spurious interrupt? exit
 
 	orr r11, r11, r13			@ mask all requested interrupts
 	str r11, [r12, #OMAP1510_GPIO_INT_MASK]
@@ -131,7 +131,7 @@ restart:
 	str r13, [r12, #OMAP1510_GPIO_INT_STATUS] @ ack all requested interrupts
 
 	ands r10, r13, #KEYBRD_CLK_MASK		@ extract keyboard status - set?
-	beq hksw				@ no - try next source
+	beq .Lhksw				@ no - try next source
 
 
 	@@@@@@@@@@@@@@@@@@@@@@
@@ -145,10 +145,10 @@ restart:
 
 	ldr r10, [r9, #BUF_STATE]		@ fetch kbd interface state
 	cmp r10, #0				@ are we expecting start bit?
-	bne data				@ no - go to data processing
+	bne .Ldata				@ no - go to data processing
 
 	ands r8, r8, #KEYBRD_DATA_MASK		@ check start bit - detected?
-	beq hksw				@ no - try next source
+	beq .Lhksw				@ no - try next source
 
 	@ r8 contains KEYBRD_DATA_MASK, use it
 	str r8, [r9, #BUF_STATE]		@ enter data processing state
@@ -162,9 +162,9 @@ restart:
 	mvn r11, #KEYBRD_CLK_MASK		@ prepare all except kbd mask
 	str r11, [r12, #OMAP1510_GPIO_INT_MASK]	@ store into the mask register
 
-	b restart				@ restart
+	b .Lrestart				@ restart
 
-data:	ldr r10, [r9, #BUF_MASK]		@ fetch current input bit mask
+.Ldata:	ldr r10, [r9, #BUF_MASK]		@ fetch current input bit mask
 
 	@ r8 still contains GPIO input bits
 	ands r8, r8, #KEYBRD_DATA_MASK		@ is keyboard data line low?
@@ -175,7 +175,7 @@ data:	ldr r10, [r9, #BUF_MASK]		@ fetch current input bit mask
 	mov r10, r10, lsl #1			@ shift mask left
 	bics r10, r10, #0x800			@ have we got all the bits?
 	strne r10, [r9, #BUF_MASK]		@ not yet - store the mask
-	bne restart				@ and restart
+	bne .Lrestart				@ and restart
 
 	@ r10 already contains 0, reuse it
 	str r10, [r9, #BUF_STATE]		@ reset state to start
@@ -189,7 +189,7 @@ data:	ldr r10, [r9, #BUF_MASK]		@ fetch current input bit mask
 	ldr r10, [r9, #BUF_KEYS_CNT]		@ get saved keystrokes count
 	ldr r8, [r9, #BUF_BUF_LEN]		@ get buffer size
 	cmp r10, r8				@ is buffer full?
-	beq hksw				@ yes - key lost, next source
+	beq .Lhksw				@ yes - key lost, next source
 
 	add r10, r10, #1			@ incremet keystrokes counter
 	str r10, [r9, #BUF_KEYS_CNT]
@@ -213,9 +213,9 @@ data:	ldr r10, [r9, #BUF_MASK]		@ fetch current input bit mask
 	@@@@@@@@@@@@@@@@@@@@@@@@
 
 
-hksw:	@Is hook switch interrupt requested?
+.Lhksw:	@Is hook switch interrupt requested?
 	tst r13, #HOOK_SWITCH_MASK 		@ is hook switch status bit set?
-	beq mdm					@ no - try next source
+	beq .Lmdm				@ no - try next source
 
 
 	@@@@@@@@@@@@@@@@@@@@@@@@
@@ -230,9 +230,9 @@ hksw:	@Is hook switch interrupt requested?
 	@@@@@@@@@@@@@@@@@@@@@@@@
 
 
-mdm:	@Is it a modem interrupt?
+.Lmdm:	@Is it a modem interrupt?
 	tst r13, #MODEM_IRQ_MASK 		@ is modem status bit set?
-	beq irq					@ no - check for next interrupt
+	beq .Lirq				@ no - check for next interrupt
 
 
 	@@@@@@@@@@@@@@@@@@@@@@@@
@@ -245,13 +245,13 @@ mdm:	@Is it a modem interrupt?
 	@@@@@@@@@@@@@@@@@@@@@@@@
 
 
-irq:	@ Place deferred_fiq interrupt request
+.Lirq:	@ Place deferred_fiq interrupt request
 	ldr r12, deferred_fiq_ih_base		@ set pointer to IRQ handler
 	mov r10, #DEFERRED_FIQ_MASK		@ set deferred_fiq bit
 	str r10, [r12, #IRQ_ISR_REG_OFFSET] 	@ place it in the ISR register
 
 	ldr r12, omap1510_gpio_base		@ set pointer back to GPIO bank
-	b restart				@ check for next GPIO interrupt
+	b .Lrestart				@ check for next GPIO interrupt
 	@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
 
-- 
2.39.5



From mike.leach at linaro.org  Thu Dec  4 01:54:31 2025
From: mike.leach at linaro.org (Mike Leach)
Date: Thu, 4 Dec 2025 09:54:31 +0000
Subject: [PATCH v6 1/2] coresight: cti: Convert trigger usage fields to
 dynamic bitmaps and arrays
In-Reply-To: <20251202-extended_cti-v6-1-ab68bb15c4f5@oss.qualcomm.com>
References: <20251202-extended_cti-v6-0-ab68bb15c4f5@oss.qualcomm.com> <20251202-extended_cti-v6-1-ab68bb15c4f5@oss.qualcomm.com>
Message-ID: <CAJ9a7ViMU0hp1ot9XavWGuZtoiH8sO_Oih4TqWFubVp=aNiLEw@mail.gmail.com>

You are missing the review-by on this patch I sent for v5

On Tue, 2 Dec 2025 at 06:43, Yingchao Deng
<yingchao.deng at oss.qualcomm.com> wrote:
>
> Replace the fixed-size u32 fields in the cti_config and cti_trig_grp
> structure with dynamically allocated bitmaps and arrays. This allows
> memory to be allocated based on the actual number of triggers during probe
> time, reducing memory footprint and improving scalability for platforms
> with varying trigger counts.
> Additionally, repack struct cti_config to reduce its size from 80 bytes to
> 72 bytes.
>
> Signed-off-by: Yingchao Deng <yingchao.deng at oss.qualcomm.com>
> ---
>  drivers/hwtracing/coresight/coresight-cti-core.c   | 58 ++++++++++++++++------
>  .../hwtracing/coresight/coresight-cti-platform.c   | 16 +++---
>  drivers/hwtracing/coresight/coresight-cti-sysfs.c  | 10 ++--
>  drivers/hwtracing/coresight/coresight-cti.h        | 17 ++++---
>  4 files changed, 65 insertions(+), 36 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c
> index bfbc365bb2ef..f9970e40dd59 100644
> --- a/drivers/hwtracing/coresight/coresight-cti-core.c
> +++ b/drivers/hwtracing/coresight/coresight-cti-core.c
> @@ -214,8 +214,8 @@ void cti_write_intack(struct device *dev, u32 ackval)
>  /* DEVID[19:16] - number of CTM channels */
>  #define CTI_DEVID_CTMCHANNELS(devid_val) ((int) BMVAL(devid_val, 16, 19))
>
> -static void cti_set_default_config(struct device *dev,
> -                                  struct cti_drvdata *drvdata)
> +static int cti_set_default_config(struct device *dev,
> +                                 struct cti_drvdata *drvdata)
>  {
>         struct cti_config *config = &drvdata->config;
>         u32 devid;
> @@ -234,12 +234,33 @@ static void cti_set_default_config(struct device *dev,
>                 config->nr_trig_max = CTIINOUTEN_MAX;
>         }
>
> +       config->trig_in_use = devm_bitmap_zalloc(dev, config->nr_trig_max, GFP_KERNEL);
> +       if (!config->trig_in_use)
> +               return -ENOMEM;
> +
> +       config->trig_out_use = devm_bitmap_zalloc(dev, config->nr_trig_max, GFP_KERNEL);
> +       if (!config->trig_out_use)
> +               return -ENOMEM;
> +
> +       config->trig_out_filter = devm_bitmap_zalloc(dev, config->nr_trig_max, GFP_KERNEL);
> +       if (!config->trig_out_filter)
> +               return -ENOMEM;
> +
> +       config->ctiinen = devm_kcalloc(dev, config->nr_trig_max, sizeof(u32), GFP_KERNEL);
> +       if (!config->ctiinen)
> +               return -ENOMEM;
> +
> +       config->ctiouten = devm_kcalloc(dev, config->nr_trig_max, sizeof(u32), GFP_KERNEL);
> +       if (!config->ctiouten)
> +               return -ENOMEM;
> +
>         config->nr_ctm_channels = CTI_DEVID_CTMCHANNELS(devid);
>
>         /* Most regs default to 0 as zalloc'ed except...*/
>         config->trig_filter_enable = true;
>         config->ctigate = GENMASK(config->nr_ctm_channels - 1, 0);
>         config->enable_req_count = 0;
> +       return 0;
>  }
>
>  /*
> @@ -270,8 +291,10 @@ int cti_add_connection_entry(struct device *dev, struct cti_drvdata *drvdata,
>         cti_dev->nr_trig_con++;
>
>         /* add connection usage bit info to overall info */
> -       drvdata->config.trig_in_use |= tc->con_in->used_mask;
> -       drvdata->config.trig_out_use |= tc->con_out->used_mask;
> +       bitmap_or(drvdata->config.trig_in_use, drvdata->config.trig_in_use,
> +                 tc->con_in->used_mask, drvdata->config.nr_trig_max);
> +       bitmap_or(drvdata->config.trig_out_use, drvdata->config.trig_out_use,
> +                 tc->con_out->used_mask, drvdata->config.nr_trig_max);
>
>         return 0;
>  }
> @@ -293,12 +316,20 @@ struct cti_trig_con *cti_allocate_trig_con(struct device *dev, int in_sigs,
>         if (!in)
>                 return NULL;
>
> +       in->used_mask = devm_bitmap_alloc(dev, in_sigs, GFP_KERNEL);
> +       if (!in->used_mask)
> +               return NULL;
> +
>         out = devm_kzalloc(dev,
>                            offsetof(struct cti_trig_grp, sig_types[out_sigs]),
>                            GFP_KERNEL);
>         if (!out)
>                 return NULL;
>
> +       out->used_mask = devm_bitmap_alloc(dev, out_sigs, GFP_KERNEL);
> +       if (!out->used_mask)
> +               return NULL;
> +
>         tc->con_in = in;
>         tc->con_out = out;
>         tc->con_in->nr_sigs = in_sigs;
> @@ -314,7 +345,6 @@ int cti_add_default_connection(struct device *dev, struct cti_drvdata *drvdata)
>  {
>         int ret = 0;
>         int n_trigs = drvdata->config.nr_trig_max;
> -       u32 n_trig_mask = GENMASK(n_trigs - 1, 0);
>         struct cti_trig_con *tc = NULL;
>
>         /*
> @@ -325,8 +355,9 @@ int cti_add_default_connection(struct device *dev, struct cti_drvdata *drvdata)
>         if (!tc)
>                 return -ENOMEM;
>
> -       tc->con_in->used_mask = n_trig_mask;
> -       tc->con_out->used_mask = n_trig_mask;
> +       bitmap_fill(tc->con_in->used_mask, n_trigs);
> +       bitmap_fill(tc->con_out->used_mask, n_trigs);
> +
>         ret = cti_add_connection_entry(dev, drvdata, tc, NULL, "default");
>         return ret;
>  }
> @@ -339,7 +370,6 @@ int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,
>  {
>         struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
>         struct cti_config *config = &drvdata->config;
> -       u32 trig_bitmask;
>         u32 chan_bitmask;
>         u32 reg_value;
>         int reg_offset;
> @@ -349,18 +379,16 @@ int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,
>            (trigger_idx >= config->nr_trig_max))
>                 return -EINVAL;
>
> -       trig_bitmask = BIT(trigger_idx);
> -
>         /* ensure registered triggers and not out filtered */
>         if (direction == CTI_TRIG_IN)   {
> -               if (!(trig_bitmask & config->trig_in_use))
> +               if (!(test_bit(trigger_idx, config->trig_in_use)))
>                         return -EINVAL;
>         } else {
> -               if (!(trig_bitmask & config->trig_out_use))
> +               if (!(test_bit(trigger_idx, config->trig_out_use)))
>                         return -EINVAL;
>
>                 if ((config->trig_filter_enable) &&
> -                   (config->trig_out_filter & trig_bitmask))
> +                   test_bit(trigger_idx, config->trig_out_filter))
>                         return -EINVAL;
>         }
>
> @@ -892,7 +920,9 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id)
>         raw_spin_lock_init(&drvdata->spinlock);
>
>         /* initialise CTI driver config values */
> -       cti_set_default_config(dev, drvdata);
> +       ret = cti_set_default_config(dev, drvdata);
> +       if (ret)
> +               return ret;
>
>         pdata = coresight_cti_get_platform_data(dev);
>         if (IS_ERR(pdata)) {
> diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c
> index d0ae10bf6128..4bef860a0484 100644
> --- a/drivers/hwtracing/coresight/coresight-cti-platform.c
> +++ b/drivers/hwtracing/coresight/coresight-cti-platform.c
> @@ -136,8 +136,8 @@ static int cti_plat_create_v8_etm_connection(struct device *dev,
>                 goto create_v8_etm_out;
>
>         /* build connection data */
> -       tc->con_in->used_mask = 0xF0; /* sigs <4,5,6,7> */
> -       tc->con_out->used_mask = 0xF0; /* sigs <4,5,6,7> */
> +       bitmap_set(tc->con_in->used_mask, 4, 4); /* sigs <4,5,6,7> */
> +       bitmap_set(tc->con_out->used_mask, 4, 4); /* sigs <4,5,6,7> */
>
>         /*
>          * The EXTOUT type signals from the ETM are connected to a set of input
> @@ -194,10 +194,10 @@ static int cti_plat_create_v8_connections(struct device *dev,
>                 goto of_create_v8_out;
>
>         /* Set the v8 PE CTI connection data */
> -       tc->con_in->used_mask = 0x3; /* sigs <0 1> */
> +       bitmap_set(tc->con_in->used_mask, 0, 2); /* sigs <0 1> */
>         tc->con_in->sig_types[0] = PE_DBGTRIGGER;
>         tc->con_in->sig_types[1] = PE_PMUIRQ;
> -       tc->con_out->used_mask = 0x7; /* sigs <0 1 2 > */
> +       bitmap_set(tc->con_out->used_mask, 0, 3); /* sigs <0 1 2 > */
>         tc->con_out->sig_types[0] = PE_EDBGREQ;
>         tc->con_out->sig_types[1] = PE_DBGRESTART;
>         tc->con_out->sig_types[2] = PE_CTIIRQ;
> @@ -213,7 +213,7 @@ static int cti_plat_create_v8_connections(struct device *dev,
>                 goto of_create_v8_out;
>
>         /* filter pe_edbgreq - PE trigout sig <0> */
> -       drvdata->config.trig_out_filter |= 0x1;
> +       set_bit(0, drvdata->config.trig_out_filter);
>
>  of_create_v8_out:
>         return ret;
> @@ -257,7 +257,7 @@ static int cti_plat_read_trig_group(struct cti_trig_grp *tgrp,
>         if (!err) {
>                 /* set the signal usage mask */
>                 for (idx = 0; idx < tgrp->nr_sigs; idx++)
> -                       tgrp->used_mask |= BIT(values[idx]);
> +                       set_bit(values[idx], tgrp->used_mask);
>         }
>
>         kfree(values);
> @@ -331,7 +331,9 @@ static int cti_plat_process_filter_sigs(struct cti_drvdata *drvdata,
>
>         err = cti_plat_read_trig_group(tg, fwnode, CTI_DT_FILTER_OUT_SIGS);
>         if (!err)
> -               drvdata->config.trig_out_filter |= tg->used_mask;
> +               bitmap_or(drvdata->config.trig_out_filter,
> +                         drvdata->config.trig_out_filter,
> +                         tg->used_mask, drvdata->config.nr_trig_max);
>
>         kfree(tg);
>         return err;
> diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
> index 572b80ee96fb..a9df77215141 100644
> --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c
> +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
> @@ -711,10 +711,8 @@ static ssize_t trigout_filtered_show(struct device *dev,
>         struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
>         struct cti_config *cfg = &drvdata->config;
>         int size = 0, nr_trig_max = cfg->nr_trig_max;
> -       unsigned long mask = cfg->trig_out_filter;
>
> -       if (mask)
> -               size = bitmap_print_to_pagebuf(true, buf, &mask, nr_trig_max);
> +       size = bitmap_print_to_pagebuf(true, buf, cfg->trig_out_filter, nr_trig_max);
>         return size;
>  }
>  static DEVICE_ATTR_RO(trigout_filtered);
> @@ -926,9 +924,8 @@ static ssize_t trigin_sig_show(struct device *dev,
>         struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
>         struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
>         struct cti_config *cfg = &drvdata->config;
> -       unsigned long mask = con->con_in->used_mask;
>
> -       return bitmap_print_to_pagebuf(true, buf, &mask, cfg->nr_trig_max);
> +       return bitmap_print_to_pagebuf(true, buf, con->con_in->used_mask, cfg->nr_trig_max);
>  }
>
>  static ssize_t trigout_sig_show(struct device *dev,
> @@ -940,9 +937,8 @@ static ssize_t trigout_sig_show(struct device *dev,
>         struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
>         struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
>         struct cti_config *cfg = &drvdata->config;
> -       unsigned long mask = con->con_out->used_mask;
>
> -       return bitmap_print_to_pagebuf(true, buf, &mask, cfg->nr_trig_max);
> +       return bitmap_print_to_pagebuf(true, buf, con->con_out->used_mask, cfg->nr_trig_max);
>  }
>
>  /* convert a sig type id to a name */
> diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h
> index 4f89091ee93f..e7b88b07cffe 100644
> --- a/drivers/hwtracing/coresight/coresight-cti.h
> +++ b/drivers/hwtracing/coresight/coresight-cti.h
> @@ -68,7 +68,7 @@ struct fwnode_handle;
>   */
>  struct cti_trig_grp {
>         int nr_sigs;
> -       u32 used_mask;
> +       unsigned long *used_mask;
>         int sig_types[];
>  };
>
> @@ -146,20 +146,21 @@ struct cti_config {
>         bool hw_enabled;
>         bool hw_powered;
>
> -       /* registered triggers and filtering */
> -       u32 trig_in_use;
> -       u32 trig_out_use;
> -       u32 trig_out_filter;
>         bool trig_filter_enable;
>         u8 xtrig_rchan_sel;
>
>         /* cti cross trig programmable regs */
> -       u32 ctiappset;
>         u8 ctiinout_sel;
> -       u32 ctiinen[CTIINOUTEN_MAX];
> -       u32 ctiouten[CTIINOUTEN_MAX];
> +       u32 ctiappset;
>         u32 ctigate;
>         u32 asicctl;
> +       u32 *ctiinen;
> +       u32 *ctiouten;
> +
> +       /* registered triggers and filtering */
> +       unsigned long *trig_in_use;
> +       unsigned long *trig_out_use;
> +       unsigned long *trig_out_filter;
>  };
>
>  /**
>
> --
> 2.43.0
>


-- 
Mike Leach
Principal Engineer, ARM Ltd.
Manchester Design Centre. UK


From pabeni at redhat.com  Thu Dec  4 01:58:40 2025
From: pabeni at redhat.com (Paolo Abeni)
Date: Thu, 4 Dec 2025 10:58:40 +0100
Subject: [PATCH net v2] net: stmmac: Fix E2E delay mechanism
In-Reply-To: <20251129-ext-ptp-2v-v2-1-d23aca3e694f@altera.com>
References: <20251129-ext-ptp-2v-v2-1-d23aca3e694f@altera.com>
Message-ID: <26656845-d9d6-4fd2-bfff-99996cf03741@redhat.com>

On 11/29/25 4:07 AM, Rohan G Thomas wrote:
> For E2E delay mechanism, "received DELAY_REQ without timestamp" error
> messages show up for dwmac v3.70+ and dwxgmac IPs.
> 
> This issue affects socfpga platforms, Agilex7 (dwmac 3.70) and
> Agilex5 (dwxgmac). According to the databook, to enable timestamping
> for all events, the SNAPTYPSEL bits in the MAC_Timestamp_Control
> register must be set to 2'b01, and the TSEVNTENA bit must be cleared
> to 0'b0.
> 
> Commit 3cb958027cb8 ("net: stmmac: Fix E2E delay mechanism") already
> addresses this problem for all dwmacs above version v4.10. However,
> same holds true for v3.70 and above, as well as for dwxgmac. Updates
> the check accordingly.
> 
> Fixes: 14f347334bf2 ("net: stmmac: Correctly take timestamp for PTPv2")
> Fixes: f2fb6b6275eb ("net: stmmac: enable timestamp snapshot for required PTP packets in dwmac v5.10a")
> Fixes: 3cb958027cb8 ("net: stmmac: Fix E2E delay mechanism")
> Signed-off-by: Rohan G Thomas <rohan.g.thomas at altera.com>
> ---
> v1 -> v2:
>    - Rebased patch to net tree
>    - Replace core_type with has_xgmac
>    - Nit changes in the commit message
>    - Link: https://lore.kernel.org/all/20251125-ext-ptp-fix-v1-1-83f9f069cb36 at altera.com/

Given there is some uncertain WRT the exact oldest version to be used,
it would be great to have some 3rd party testing/feedback on this. Let's
wait a little more.

Thanks,

Paolo



From leo.yan at arm.com  Thu Dec  4 02:02:03 2025
From: leo.yan at arm.com (Leo Yan)
Date: Thu, 4 Dec 2025 10:02:03 +0000
Subject: [PATCH v6 2/2] coresight: cti: Add Qualcomm extended CTI support
In-Reply-To: <CAJ9a7VhNW6cQt_O6NX+99LXfo-t3mFTejzdNjWcyssbMrXR4OQ@mail.gmail.com>
References: <20251202-extended_cti-v6-0-ab68bb15c4f5@oss.qualcomm.com>
 <20251202-extended_cti-v6-2-ab68bb15c4f5@oss.qualcomm.com>
 <20251203182944.GG724103@e132581.arm.com>
 <20251204083802.GI724103@e132581.arm.com>
 <CAJ9a7VhNW6cQt_O6NX+99LXfo-t3mFTejzdNjWcyssbMrXR4OQ@mail.gmail.com>
Message-ID: <20251204100203.GJ724103@e132581.arm.com>

On Thu, Dec 04, 2025 at 09:04:03AM +0000, Mike Leach wrote:
> Hi,
> 
> On Thu, 4 Dec 2025 at 08:38, Leo Yan <leo.yan at arm.com> wrote:
> >
> > On Wed, Dec 03, 2025 at 06:29:44PM +0000, Coresight ML wrote:
> >
> > [...]
> >
> > > > +/* Read registers with power check only (no enable check). */
> > > > +static ssize_t coresight_cti_reg_show(struct device *dev,
> > > > +                                 struct device_attribute *attr, char *buf)
> > > > +{
> > > > +   struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
> > > > +   struct cs_off_attribute *cti_attr = container_of(attr, struct cs_off_attribute, attr);
> > > > +   u32 idx, val = 0;
> > > > +
> > > > +   pm_runtime_get_sync(dev->parent);
> > > > +   raw_spin_lock(&drvdata->spinlock);
> > > > +   idx = drvdata->config.ext_reg_sel;
> > > > +   if (drvdata->config.hw_powered) {
> > > > +           switch (cti_attr->off) {
> > > > +           case INDEX_CTITRIGINSTATUS:
> > > > +           case INDEX_CTITRIGOUTSTATUS:
> > > > +           case INDEX_ITTRIGINACK:
> > > > +           case INDEX_ITTRIGOUT:
> > > > +           case INDEX_ITTRIGOUTACK:
> > > > +           case INDEX_ITTRIGIN:
> >
> > I read again and now I understand why you need "config.ext_reg_sel"
> > as an index for these expending registers.
> >
> 
> Having this index for these extended registers matches what we do for
> the INEN and OUTEN registers. This gives the user a consistent
> approach. We do not want the unnecessary attributes as  it will
> increase the memory footprint for all cti instances, not just the qcom
> ones.

I agree with using index for CTI triggers, but it is not necessary to
add a new index for other registers (status, mode setting, ACK, etc).

It would be directive to present the status and mode setting
registers, given these registers are only from 0-3.  This will be easy
accessed from userspace, and avoid complexity in the driver.

> The first patch in this series works to reduce the memory footprint by
> only allocating resource based on the actual configuration. For
> example for an ARM designed CTI with 8 trigger registers, we no longer
> declare static 128 x 32 bit arrays for each of INEN and OUTEN which
> were required by the original design.
> 
> Given that there can be 10s or 100s of CTIs in a large multicore
> system, reducing the footprint to match the actual configuration, and
> offering a level of compression by using an index + single file to
> access a set of registers improves the efficiency of the driver.

It is good for reducing footprint, but I would give priority for a
neat implementation and easy use interfaces.

And the sysfs attr code and global structures (e.g. register conversion
struct) can shared by all instances, so I don't worry much the scale
issue if we extend them.

Thanks,
Leo


From pmladek at suse.com  Thu Dec  4 02:20:37 2025
From: pmladek at suse.com (Petr Mladek)
Date: Thu, 4 Dec 2025 11:20:37 +0100
Subject: [PATCH] printk/nbcon: Restore IRQ in atomic flush after each
 emitted record
In-Reply-To: <87ikenyclh.fsf@jogness.linutronix.de>
References: <20251202135832.156559-1-pmladek@suse.com>
 <87o6oheywd.fsf@jogness.linutronix.de>
 <20251202162639.GD724103@e132581.arm.com>
 <87ikenyclh.fsf@jogness.linutronix.de>
Message-ID: <aTFgdQNeKb0k4SQS@pathway.suse.cz>

On Wed 2025-12-03 13:33:38, John Ogness wrote:
> On 2025-12-02, Leo Yan <leo.yan at arm.com> wrote:
> >> I am not really happy about all the local_irq_restore() usage. Using
> >> guard syntax would be nice here, but AFAICT there is no guard for
> >> local_irq_save()/_restore().
> >
> > Sorry for suddenly jumping in.  Wouldn't guard(irqsave)() be helpful
> > here?
> 
> Thanks, I was not aware of the irqsave variant. We would want the scoped
> version. So something like this?
> 
> $ git diff -w
> diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
> index 3fa403f9831f..55beb64c4f4a 100644
> --- a/kernel/printk/nbcon.c
> +++ b/kernel/printk/nbcon.c
> @@ -1557,6 +1557,14 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
>  	ctxt->allow_unsafe_takeover	= nbcon_allow_unsafe_takeover();
>  
>  	while (nbcon_seq_read(con) < stop_seq) {
> +		/*
> +		 * Atomic flushing does not use console driver synchronization
> +		 * (i.e. it does not hold the port lock for uart consoles).
> +		 * Therefore IRQs must be disabled to avoid being interrupted
> +		 * and then calling into a driver that will deadlock trying
> +		 * to acquire console ownership.
> +		 */
> +		scoped_guard(irqsave) {
>  			if (!nbcon_context_try_acquire(ctxt, false))
>  				return -EPERM;
>  
> @@ -1569,6 +1577,7 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
>  				return -EAGAIN;
>  
>  			nbcon_context_release(ctxt);
> +		}
>  
>  		if (!ctxt->backlog) {
>  			/* Are there reserved but not yet finalized records? */
> 

Great. Thanks for hint. I am going to send v2 with this change.

Best Regards,
Petr


From leo.yan at arm.com  Thu Dec  4 02:31:51 2025
From: leo.yan at arm.com (Leo Yan)
Date: Thu, 4 Dec 2025 10:31:51 +0000
Subject: [PATCH v6 2/2] coresight: cti: Add Qualcomm extended CTI support
In-Reply-To: <CAJ9a7VjWDBEwdmMf53geACBWGusC8BC3pJuOLETeecw24+N35Q@mail.gmail.com>
References: <20251202-extended_cti-v6-0-ab68bb15c4f5@oss.qualcomm.com>
 <20251202-extended_cti-v6-2-ab68bb15c4f5@oss.qualcomm.com>
 <20251203182944.GG724103@e132581.arm.com>
 <CAJ9a7VjWDBEwdmMf53geACBWGusC8BC3pJuOLETeecw24+N35Q@mail.gmail.com>
Message-ID: <20251204103151.GK724103@e132581.arm.com>

On Thu, Dec 04, 2025 at 09:07:56AM +0000, Mike Leach wrote:

[...]

> > I saw CTI registers are within 4KiB (0x1000), we can don't convert
> > standard regiserts and only convert to QCOM register based on the
> > standard ones.  So you can drop the cti_normal_offset strucuture and
> > only have a cti_reg_qcom_offset[] struct:
> >
> >   static const u32 cti_extended_offset[] = {
> >         [CTIINTACK]             = QCOM_CTIINTACK,
> >         [CTIAPPSET]             = QCOM_CTIAPPSET,
> >         [CTIAPPCLEAR]           = QCOM_CTIAPPCLEAR,
> >         [CTIAPPPULSE]           = QCOM_CTIAPPPULSE,
> >         [CTIINEN]               = QCOM_CTIINEN,
> >         ...
> >   };
> >
> 
> I suggested the dual offset approach a couple of patchset revisions
> ago as it actually simplifies the code & makes it more efficient. The
> offset array in use is set during probe and the remaining code is then
> common to both without lots of "if qcom else " occurences.

AFAICS, we will handle the QCOM CTI particularly in three cases:

  1) The register access;
  2) The claim tag;
  3) Sysfs attr is visible.

Now we are discussing the reigster access.  As suggested, the
"if qcom / else" is encapsulated (e.g., in cti_reg_addr_with_nr()), it
will not spread out.

I'd use standard registers by default and convert to non-standard ones
only when needed.  A new "neutral" index layer seems redundant, as the
existing standard register indexes already serve this purpose.

For the sysfs attrs, it makes sense to use a central place to decide
which knobs are only visible for QCOM CTI, otherwise, we also will not
spread the condition check.

I will reply separately for claim tag issue.

Thanks,
Leo


From joey.gouly at arm.com  Thu Dec  4 02:32:00 2025
From: joey.gouly at arm.com (Joey Gouly)
Date: Thu, 4 Dec 2025 10:32:00 +0000
Subject: [PATCH v3 1/9] arm64: Repaint ID_AA64MMFR2_EL1.IDS description
In-Reply-To: <20251204094806.3846619-2-maz@kernel.org>
References: <20251204094806.3846619-1-maz@kernel.org>
 <20251204094806.3846619-2-maz@kernel.org>
Message-ID: <20251204103200.GA98666@e124191.cambridge.arm.com>

On Thu, Dec 04, 2025 at 09:47:58AM +0000, Marc Zyngier wrote:
> ID_AA64MMFR2_EL1.IDS, as described in the sysreg file, is pretty horrible
> as it diesctly give the ESR value. Repaint it using the usual NI/IMP
typo:   directly
> identifiers to describe the absence/presence of FEAT_IDST.
> 
> Signed-off-by: Marc Zyngier <maz at kernel.org>
Reviewed-by: Joey Gouly <joey.gouly at arm.com>
> ---
>  arch/arm64/kvm/hyp/nvhe/sys_regs.c | 2 +-
>  arch/arm64/tools/sysreg            | 4 ++--
>  2 files changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/nvhe/sys_regs.c b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
> index 82da9b03692d4..107d62921b168 100644
> --- a/arch/arm64/kvm/hyp/nvhe/sys_regs.c
> +++ b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
> @@ -134,7 +134,7 @@ static const struct pvm_ftr_bits pvmid_aa64mmfr2[] = {
>  	MAX_FEAT(ID_AA64MMFR2_EL1, UAO, IMP),
>  	MAX_FEAT(ID_AA64MMFR2_EL1, IESB, IMP),
>  	MAX_FEAT(ID_AA64MMFR2_EL1, AT, IMP),
> -	MAX_FEAT_ENUM(ID_AA64MMFR2_EL1, IDS, 0x18),
> +	MAX_FEAT_ENUM(ID_AA64MMFR2_EL1, IDS, IMP),
>  	MAX_FEAT(ID_AA64MMFR2_EL1, TTL, IMP),
>  	MAX_FEAT(ID_AA64MMFR2_EL1, BBM, 2),
>  	MAX_FEAT(ID_AA64MMFR2_EL1, E0PD, IMP),
> diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
> index 1c6cdf9d54bba..3261e8791ac03 100644
> --- a/arch/arm64/tools/sysreg
> +++ b/arch/arm64/tools/sysreg
> @@ -2257,8 +2257,8 @@ UnsignedEnum	43:40	FWB
>  	0b0001	IMP
>  EndEnum
>  Enum	39:36	IDS
> -	0b0000	0x0
> -	0b0001	0x18
> +	0b0000	NI
> +	0b0001	IMP
>  EndEnum
>  UnsignedEnum	35:32	AT
>  	0b0000	NI
> -- 
> 2.47.3
> 


From pavan.kondeti at oss.qualcomm.com  Thu Dec  4 02:36:12 2025
From: pavan.kondeti at oss.qualcomm.com (Pavan Kondeti)
Date: Thu, 4 Dec 2025 16:06:12 +0530
Subject: Alternative to arm64.nopauth cmdline for disabling Pointer
 Authentication
In-Reply-To: <86ecpappzi.wl-maz@kernel.org>
References: <3fcf6614-ee83-4a06-9024-83573b2e642e@quicinc.com>
 <86ecpappzi.wl-maz@kernel.org>
Message-ID: <adc22b19-7dcc-4c38-9319-d979f1e3886a@quicinc.com>

Hi Marc,

On Thu, Dec 04, 2025 at 09:15:29AM +0000, Marc Zyngier wrote:
> On Thu, 04 Dec 2025 04:07:15 +0000,
> Pavan Kondeti <pavan.kondeti at oss.qualcomm.com> wrote:
> > 
> > Hi
> > 
> > The pointer authentication feature (PAuth) is only supported on
> > 0-3 CPUs but it is not supported on 4-7 CPUS on QCS8300.
> 
> On what grounds? Hardware incompatibility? I seriously doubt it, since
> nobody glues pre-8.3 CPUs to anything more modern. Or, as I expect it,
> a firmware implemented with little understanding of what is required?

I don't know the answer to this question. I will talk to folks who may
know answer to this question and get back.

Can you please elaborate on the firmware part you are talking here? I
see that Linux runs at EL2 and AA64ISAR1 register values on CPU#0 (A78)
indicates that PAuth is supported but not for CPU#4 (A55). I am told, there
are no other controls outside EL2 (trap) to manipulate this feature. So,
I am assuming that this is indeed reflecting the HW.

> 
> > The ARM64 cpufeature discovery code expects late CPUs to have
> > this feature if boot CPU feature has it since PAuth is enabled
> > early. When a conflict like this is detected, the late CPUs are
> > not allowed to boot. It is expected that system will continue
> > to be functional with CPUs with Pauth feature supported and enabled.
> > This is not a desired behavior in production.
> 
> What is even less desirable is to produce this sort of contraption.
> 
> > We started seeing this problem when Linux is booted in EL2. When Linux
> > is running under Gunyah (Type-1 hypervisor), Pointer Authentication
> > feature is hidden from EL1 via HCR_EL2.TID3. 
> > 
> > arm64.nopauth can be passed on kernel cmdline to disable the feature
> > in kernel so that all all CPUs can boot on QCS8300. I am told 
> > maintaining a custom kernel commandline per SoC in a Generic OS 
> > distribution is not recommended and asked to discuss the problem with
> > the comunity [1]
> 
> Well, you get to own the problem you have created for yourself. You
> build hardware/firmware that cannot run generic SW, and yet you want
> generic SW to run seamlessly on it. Spot the issue?
> 
> > This patch [2] from Catalin adds a devicetree property under memory {}
> > to disable MTE. I believe this work predates the id-reg override
> > mechanism. However, this made me think if workarounds like this can be
> > detected via devicetree, for example a property under cpu { } node.
> 
> Not only it predates it, but it also doesn't work in general. For a
> start, it is DT specific. How are you going to make that work for
> ACPI? I know you don't care, but I do.

Point taken. I understand that this does not fall under errata but is
there a possiblity to introduce an Errata targeting CPU#0 MIDR and
disabling the Pointer authentication? I understand that if there is
another Qualcomm SoC that exists with all CPUs supporting pointer
authentication with same MIDR, we may be disabling the feature but this
is something I can check internally.

> 
> > Given that what we put in `chosen { bootargs="" }` kernel under
> > respective SoC devicetree can be overridden by bootloader, should we
> > have a **sticky** cmdline to specify critical workarounds like this?
> > This would be more generic than introducing any new parameters.
> 
> You already have a way to have a sticky command-line, by building it
> into the kernel. Yes, I understand that this isn't what you want, but:
> 
> (1) a user should be allowed to pass the kernel command-line *they*
>     want, not what someone has decided for them

Agreed. This is what made me to ask the question. Should kernel have a
sticky command line which may have critical workarounds like this?

> 
> (2) the generic mechanism exists, doesn't rely on additional firmware
>     specifications, and is used for a whole lot of other QC platforms
>     suffering from the same issue of broken firmware.  What are you
>     going to do for these?

The generic mechanism, you mean bootloader passing the kernel cmdline
with `arm64.nopauth`? or something else.

> 
> (3) what if you, by miracle, happened to *fix* the firmware?

As I have asked above, the firmware part is not clear. 

Thanks Marc for your time and guidance.

Thanks,
Pavan


From ben.horgan at arm.com  Thu Dec  4 02:36:54 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Thu, 4 Dec 2025 10:36:54 +0000
Subject: [PATCH v3 1/9] arm64: Repaint ID_AA64MMFR2_EL1.IDS description
In-Reply-To: <20251204094806.3846619-2-maz@kernel.org>
References: <20251204094806.3846619-1-maz@kernel.org>
 <20251204094806.3846619-2-maz@kernel.org>
Message-ID: <b98c154a-1658-4501-bfa5-a93303aa5b3f@arm.com>

Hi Marc,

On 12/4/25 09:47, Marc Zyngier wrote:
> ID_AA64MMFR2_EL1.IDS, as described in the sysreg file, is pretty horrible
> as it diesctly give the ESR value. Repaint it using the usual NI/IMP
> identifiers to describe the absence/presence of FEAT_IDST.
> 
> Signed-off-by: Marc Zyngier <maz at kernel.org>
> ---
>  arch/arm64/kvm/hyp/nvhe/sys_regs.c | 2 +-
>  arch/arm64/tools/sysreg            | 4 ++--
>  2 files changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/nvhe/sys_regs.c b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
> index 82da9b03692d4..107d62921b168 100644
> --- a/arch/arm64/kvm/hyp/nvhe/sys_regs.c
> +++ b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
> @@ -134,7 +134,7 @@ static const struct pvm_ftr_bits pvmid_aa64mmfr2[] = {
>  	MAX_FEAT(ID_AA64MMFR2_EL1, UAO, IMP),
>  	MAX_FEAT(ID_AA64MMFR2_EL1, IESB, IMP),
>  	MAX_FEAT(ID_AA64MMFR2_EL1, AT, IMP),
> -	MAX_FEAT_ENUM(ID_AA64MMFR2_EL1, IDS, 0x18),
> +	MAX_FEAT_ENUM(ID_AA64MMFR2_EL1, IDS, IMP),
>  	MAX_FEAT(ID_AA64MMFR2_EL1, TTL, IMP),
>  	MAX_FEAT(ID_AA64MMFR2_EL1, BBM, 2),
>  	MAX_FEAT(ID_AA64MMFR2_EL1, E0PD, IMP),
> diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
> index 1c6cdf9d54bba..3261e8791ac03 100644
> --- a/arch/arm64/tools/sysreg
> +++ b/arch/arm64/tools/sysreg
> @@ -2257,8 +2257,8 @@ UnsignedEnum	43:40	FWB
>  	0b0001	IMP
>  EndEnum
>  Enum	39:36	IDS

Should this also be changed to an UnsignedEnum?

> -	0b0000	0x0
> -	0b0001	0x18
> +	0b0000	NI
> +	0b0001	IMP
>  EndEnum
>  UnsignedEnum	35:32	AT
>  	0b0000	NI


Thanks,

Ben



From leo.yan at arm.com  Thu Dec  4 02:47:13 2025
From: leo.yan at arm.com (Leo Yan)
Date: Thu, 4 Dec 2025 10:47:13 +0000
Subject: [PATCH v6 2/2] coresight: cti: Add Qualcomm extended CTI support
In-Reply-To: <CAJ9a7VhcSxTTaxMR4SS+GbHoPHXm0honykjXy92fbv0HG=1o4Q@mail.gmail.com>
References: <20251202-extended_cti-v6-0-ab68bb15c4f5@oss.qualcomm.com>
 <20251202-extended_cti-v6-2-ab68bb15c4f5@oss.qualcomm.com>
 <20251203182944.GG724103@e132581.arm.com>
 <CAJ9a7VhcSxTTaxMR4SS+GbHoPHXm0honykjXy92fbv0HG=1o4Q@mail.gmail.com>
Message-ID: <20251204104713.GL724103@e132581.arm.com>

On Thu, Dec 04, 2025 at 09:15:07AM +0000, Mike Leach wrote:

[...]

> > > +             /*
> > > +              * QCOM CTI does not implement Claimtag functionality as
> > > +              * per CoreSight specification, but its CLAIMSET register
> > > +              * is incorrectly initialized to 0xF. This can mislead
> > > +              * tools or drivers into thinking the component is claimed.
> > > +              *
> > > +              * Reset CLAIMSET to 0 to reflect that no claims are active.
> > > +              */
> > > +             writel_relaxed(0, drvdata->base + CORESIGHT_CLAIMSET);
> >
> > I am confused for this.  If QCOM CTI does not implement claim tag,
> > then what is the designed register at the offset CORESIGHT_CLAIMSET?
> >
> > Should you bypass all claim tag related operations for QCOM CTI case?
> > (I don't see you touch anything for claim and declaim tags).
> >
> 
> The patch I have created to handle systems without correct claim tag
> operation is a dependency for this patch set. Thus no need for
> override here as the core code will handle this correctly.
> 
> The only issue is ensuring the non-CTI spec implementation will result
> in the correct detection of no claim tags present.

Your patch works only when a module has implemented claim registers.

This leads to two issues: we end up clearing an unknown register in the
CTI driver, and then the coresight core layer assumes it is reading a
claim register even though it is not.

For QCOM CTI, combined with your patch, I would suggest directly
setting csdev->access.claim_tag_impl to false (perhaps using a helper).
This would be much clearer than the "hacking" way.

Thanks,
Leo


From maz at kernel.org  Thu Dec  4 02:48:42 2025
From: maz at kernel.org (Marc Zyngier)
Date: Thu, 04 Dec 2025 10:48:42 +0000
Subject: [PATCH v3 1/9] arm64: Repaint ID_AA64MMFR2_EL1.IDS description
In-Reply-To: <b98c154a-1658-4501-bfa5-a93303aa5b3f@arm.com>
References: <20251204094806.3846619-1-maz@kernel.org>
	<20251204094806.3846619-2-maz@kernel.org>
	<b98c154a-1658-4501-bfa5-a93303aa5b3f@arm.com>
Message-ID: <86cy4uplo5.wl-maz@kernel.org>

On Thu, 04 Dec 2025 10:36:54 +0000,
Ben Horgan <ben.horgan at arm.com> wrote:
> 
> Hi Marc,
> 
> On 12/4/25 09:47, Marc Zyngier wrote:
> > ID_AA64MMFR2_EL1.IDS, as described in the sysreg file, is pretty horrible
> > as it diesctly give the ESR value. Repaint it using the usual NI/IMP
> > identifiers to describe the absence/presence of FEAT_IDST.
> > 
> > Signed-off-by: Marc Zyngier <maz at kernel.org>
> > ---
> >  arch/arm64/kvm/hyp/nvhe/sys_regs.c | 2 +-
> >  arch/arm64/tools/sysreg            | 4 ++--
> >  2 files changed, 3 insertions(+), 3 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/hyp/nvhe/sys_regs.c b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
> > index 82da9b03692d4..107d62921b168 100644
> > --- a/arch/arm64/kvm/hyp/nvhe/sys_regs.c
> > +++ b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
> > @@ -134,7 +134,7 @@ static const struct pvm_ftr_bits pvmid_aa64mmfr2[] = {
> >  	MAX_FEAT(ID_AA64MMFR2_EL1, UAO, IMP),
> >  	MAX_FEAT(ID_AA64MMFR2_EL1, IESB, IMP),
> >  	MAX_FEAT(ID_AA64MMFR2_EL1, AT, IMP),
> > -	MAX_FEAT_ENUM(ID_AA64MMFR2_EL1, IDS, 0x18),
> > +	MAX_FEAT_ENUM(ID_AA64MMFR2_EL1, IDS, IMP),
> >  	MAX_FEAT(ID_AA64MMFR2_EL1, TTL, IMP),
> >  	MAX_FEAT(ID_AA64MMFR2_EL1, BBM, 2),
> >  	MAX_FEAT(ID_AA64MMFR2_EL1, E0PD, IMP),
> > diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
> > index 1c6cdf9d54bba..3261e8791ac03 100644
> > --- a/arch/arm64/tools/sysreg
> > +++ b/arch/arm64/tools/sysreg
> > @@ -2257,8 +2257,8 @@ UnsignedEnum	43:40	FWB
> >  	0b0001	IMP
> >  EndEnum
> >  Enum	39:36	IDS
> 
> Should this also be changed to an UnsignedEnum?

I'm not sure this brings much when you only have two values. If IDS
was growing a third value, and that there was an actual order in the
numbering scheme, then yes, that'd be useful.

But at this stage, I'm not confident that this is desirable, let alone
necessary.

Thanks,

	M.

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


From ben.horgan at arm.com  Thu Dec  4 02:51:19 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Thu, 4 Dec 2025 10:51:19 +0000
Subject: [PATCH v3 8/9] KVM: arm64: pkvm: Report optional ID register
 traps with a 0x18 syndrome
In-Reply-To: <20251204094806.3846619-9-maz@kernel.org>
References: <20251204094806.3846619-1-maz@kernel.org>
 <20251204094806.3846619-9-maz@kernel.org>
Message-ID: <7f853a85-f1da-4e6f-ab3f-63507731f8ee@arm.com>

Hi Marc,

On 12/4/25 09:48, Marc Zyngier wrote:
> With FEAT_IDST, unimplemented system registers in the feature ID space
> must be reported using EC=0x18 at the closest handling EL, rather than
> with an UNDEF.
> 
> Most of these system registers are always implemented thanks to their
> dependency on FEAT_AA64, except for a set of (currently) three registers:
> GMID_EL1 (depending on MTE2), CCSIDR2_EL1 (depending on FEAT_CCIDX),
> and SMIDR_EL1 (depending on SME).
> 
> For these three registers, report their trap as EC=0x18 if they
> end-up trapping into KVM and that FEAT_IDST is implemented in the guest.
> Otherwise, just make them UNDEF.
> 
> Signed-off-by: Marc Zyngier <maz at kernel.org>
> ---
>  arch/arm64/kvm/hyp/nvhe/sys_regs.c | 15 +++++++++++++++
>  1 file changed, 15 insertions(+)
> 
> diff --git a/arch/arm64/kvm/hyp/nvhe/sys_regs.c b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
> index 876b36d3d4788..efc36645f4b5a 100644
> --- a/arch/arm64/kvm/hyp/nvhe/sys_regs.c
> +++ b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
> @@ -347,6 +347,18 @@ static bool pvm_gic_read_sre(struct kvm_vcpu *vcpu,
>  	return true;
>  }
>  
> +static bool pvm_idst_access(struct kvm_vcpu *vcpu,
> +			    struct sys_reg_params *p,
> +			    const struct sys_reg_desc *r)
> +{
> +	if (kvm_has_feat_enum(vcpu->kvm, ID_AA64MMFR2_EL1, IDS, NI))
> +		inject_undef64(vcpu);
> +	else
> +		inject_sync64(vcpu, kvm_vcpu_get_esr(vcpu));
> +
> +	return false;
> +}
> +

Just wondering, why is the pkvm version register specific? You changed
the non-pkvm from register specific to generic.

>  /* Mark the specified system register as an AArch32 feature id register. */
>  #define AARCH32(REG) { SYS_DESC(REG), .access = pvm_access_id_aarch32 }
>  
> @@ -472,6 +484,9 @@ static const struct sys_reg_desc pvm_sys_reg_descs[] = {
>  
>  	HOST_HANDLED(SYS_CCSIDR_EL1),
>  	HOST_HANDLED(SYS_CLIDR_EL1),
> +	{ SYS_DESC(SYS_CCSIDR2_EL1), .access = pvm_idst_access },
> +	{ SYS_DESC(SYS_GMID_EL1), .access = pvm_idst_access },
> +	{ SYS_DESC(SYS_SMIDR_EL1), .access = pvm_idst_access },
>  	HOST_HANDLED(SYS_AIDR_EL1),
>  	HOST_HANDLED(SYS_CSSELR_EL1),
>  	HOST_HANDLED(SYS_CTR_EL0),

Thanks,

Ben



From joey.gouly at arm.com  Thu Dec  4 02:52:30 2025
From: joey.gouly at arm.com (Joey Gouly)
Date: Thu, 4 Dec 2025 10:52:30 +0000
Subject: [PATCH v3 4/9] KVM: arm64: Handle FEAT_IDST for sysregs without
 specific handlers
In-Reply-To: <20251204094806.3846619-5-maz@kernel.org>
References: <20251204094806.3846619-1-maz@kernel.org>
 <20251204094806.3846619-5-maz@kernel.org>
Message-ID: <20251204105230.GB98666@e124191.cambridge.arm.com>

On Thu, Dec 04, 2025 at 09:48:01AM +0000, Marc Zyngier wrote:
> Add a bit of infrastrtcture to triage_sysreg_trap() to handle the
> case of registers falling into the Feature ID space that do not
> have a local handler.
> 
> For these, we can directly apply the FEAT_IDST semantics and inject
> an EC=0x18 exception. Otherwise, an UNDEF will do.
> 
> Signed-off-by: Marc Zyngier <maz at kernel.org>
> ---
>  arch/arm64/kvm/emulate-nested.c | 20 ++++++++++++++++++++
>  1 file changed, 20 insertions(+)
> 
> diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c
> index 616eb6ad68701..fac2707221b47 100644
> --- a/arch/arm64/kvm/emulate-nested.c
> +++ b/arch/arm64/kvm/emulate-nested.c
> @@ -2588,6 +2588,26 @@ bool triage_sysreg_trap(struct kvm_vcpu *vcpu, int *sr_index)
>  
>  		params = esr_sys64_to_params(esr);
>  
> +		/*
> +		 * This implements the pseudocode UnimplementedIDRegister()
> +		 * helper for the purpose of fealing with FEAT_IDST.
                                            *dealing

> +		 *
> +		 * The Feature ID space is defined as the System register
> +		 * space in AArch64 with op0==3, op1=={0, 1, 3}, CRn==0,
> +		 * CRm=={0-7}, op2=={0-7}.
> +		 */
> +		if (params.Op0 == 3 &&
> +		    !(params.Op1 & 0b100) && params.Op1 != 2 &&
> +		    params.CRn == 0 &&
> +		    !(params.CRm & 0b1000)) {
> +			if (kvm_has_feat_enum(vcpu->kvm, ID_AA64MMFR2_EL1, IDS, IMP))
> +				kvm_inject_sync(vcpu, kvm_vcpu_get_esr(vcpu));
> +			else
> +				kvm_inject_undefined(vcpu);
> +
> +			return true;
> +		}
> +
>  		/*
>  		 * Check for the IMPDEF range, as per DDI0487 J.a,
>  		 * D18.3.2 Reserved encodings for IMPLEMENTATION
> -- 
> 2.47.3
> 

Reviewed-by: Joey Gouly <joey.gouly at arm.com>


From james.clark at linaro.org  Thu Dec  4 02:55:30 2025
From: james.clark at linaro.org (James Clark)
Date: Thu, 4 Dec 2025 10:55:30 +0000
Subject: [PATCH 2/7] perf tools: apply evsel__set_config_if_unset() to all
 config fields
In-Reply-To: <20251202111403.GS724103@e132581.arm.com>
References: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
 <20251201-james-perf-config-bits-v1-2-22ecbbf8007c@linaro.org>
 <20251202111403.GS724103@e132581.arm.com>
Message-ID: <6661f623-0b27-429d-92ee-785caf04e682@linaro.org>



On 02/12/2025 11:14 am, Leo Yan wrote:
> On Mon, Dec 01, 2025 at 04:41:05PM +0000, Coresight ML wrote:
> 
> [...]
> 
>>   void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
>>   				const char *config_name, u64 val)
>>   {
>>   	u64 user_bits = 0, bits;
>> -	struct evsel_config_term *term = evsel__get_config_term(evsel, USR_CHG_CONFIG);
>> +	struct evsel_config_term *term;
>> +	struct perf_pmu_format *format = pmu_find_format(&pmu->format, config_name);
>> +	__u64 *vp;
> 
> Should check (format == NULL) here and bail out for a unknown config name?
> 

Good point, yes I'll return without any errors. It will be slightly 
inconsistent with the other config functions that return an error if 
it's not found, but it's consistent with the existing function which is 
a nop in that case.

>> +
>> +	switch (format->value) {
>> +	case PERF_PMU_FORMAT_VALUE_CONFIG:
>> +		term = evsel__get_config_term(evsel, USR_CHG_CONFIG);
>> +		vp = &evsel->core.attr.config;
>> +		break;
>> +	case PERF_PMU_FORMAT_VALUE_CONFIG1:
>> +		term = evsel__get_config_term(evsel, USR_CHG_CONFIG1);
>> +		vp = &evsel->core.attr.config1;
>> +		break;
>> +	case PERF_PMU_FORMAT_VALUE_CONFIG2:
>> +		term = evsel__get_config_term(evsel, USR_CHG_CONFIG2);
>> +		vp = &evsel->core.attr.config2;
>> +		break;
>> +	case PERF_PMU_FORMAT_VALUE_CONFIG3:
>> +		term = evsel__get_config_term(evsel, USR_CHG_CONFIG3);
>> +		vp = &evsel->core.attr.config3;
>> +		break;
>> +	case PERF_PMU_FORMAT_VALUE_CONFIG4:
>> +		term = evsel__get_config_term(evsel, USR_CHG_CONFIG4);
>> +		vp = &evsel->core.attr.config4;
>> +		break;
>> +	default:
>> +		pr_err("Unknown format value: %d\n", format->value);
>> +		return;
>> +	}
>>   
>>   	if (term)
>>   		user_bits = term->val.cfg_chg;
>> @@ -1396,20 +1436,8 @@ void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
>>   		return;
>>   
>>   	/* Otherwise replace it */
>> -	evsel->core.attr.config &= ~bits;
>> -	evsel->core.attr.config |= field_prep(bits, val);
>> -}
>> -
>> -static struct perf_pmu_format *
>> -pmu_find_format(const struct list_head *formats, const char *name)
>> -{
>> -	struct perf_pmu_format *format;
>> -
>> -	list_for_each_entry(format, formats, list)
>> -		if (!strcmp(format->name, name))
>> -			return format;
>> -
>> -	return NULL;
>> +	*vp &= ~bits;
>> +	*vp |= FIELD_PREP(bits, val);
>>   }



From james.clark at linaro.org  Thu Dec  4 02:55:37 2025
From: james.clark at linaro.org (James Clark)
Date: Thu, 4 Dec 2025 10:55:37 +0000
Subject: [PATCH 4/7] perf cs-etm: Don't use hard coded config bits when
 setting up ETMCR
In-Reply-To: <53b24702-eb3b-4e08-bca3-70402eaf4db5@linaro.org>
References: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
 <20251201-james-perf-config-bits-v1-4-22ecbbf8007c@linaro.org>
 <20251202114300.GV724103@e132581.arm.com>
 <53b24702-eb3b-4e08-bca3-70402eaf4db5@linaro.org>
Message-ID: <96c54895-cebe-4247-86e6-d41b8be0dd40@linaro.org>



On 02/12/2025 11:53 am, James Clark wrote:
> 
> 
> On 02/12/2025 11:43 am, Leo Yan wrote:
>> On Mon, Dec 01, 2025 at 04:41:07PM +0000, Coresight ML wrote:
>>
>> [...]
>>
>>> @@ -746,7 +779,7 @@ static void cs_etm_get_metadata(struct perf_cpu 
>>> cpu, u32 *offset,
>>> ????? case CS_ETMV3:
>>> ????????? magic = __perf_cs_etmv3_magic;
>>> ????????? /* Get configuration register */
>>> -??????? info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr);
>>> +??????? info->priv[*offset + CS_ETM_ETMCR] = cs_etm_guess_etmcr(itr);
>>
>> I still think cs_etm_get_config() is better than cs_etm_guess_etmcr().
>>
>> For ETMv3, we directly pass CONFIG to the kernel, and after validation
>> in the dirver, then the value will be set to ETMCR.? If we already know
>> the config value is consistent between user space and kernel, why

One other note is that since moving the timestamp field, this is no 
longer true either. The value in attr.config isn't directly put into ETMCR.

>> introduce a redundant "guess" operation here?
>>
>> Thanks,
>> Leo
> 
> Because userspace doesn't always come up with the same value as the 
> driver. For example right now in ETM3, ETMCR_RETURN_STACK isn't set 
> depending on certain conditions that userspace doesn't know about.? ETM4 
> has the same for TRCCONFIGR_RS and maybe some others. In the future, 
> other versions of the driver could do different things as long as we 
> don't break decoding.
> 
> I didn't want the function name to imply it was doing something it 
> wasn't as that confused me a little bit. It's definitely not "getting" 
> the value. Maybe "guess" isn't the best it could be, but it's not far off.
> 



From danielt at kernel.org  Thu Dec  4 02:56:13 2025
From: danielt at kernel.org (Daniel Thompson)
Date: Thu, 4 Dec 2025 10:56:13 +0000
Subject: [PATCH v4 16/26] genirq: Allow per-cpu interrupt sharing for
 non-overlapping affinities
In-Reply-To: <20251020122944.3074811-17-maz@kernel.org>
References: <20251020122944.3074811-1-maz@kernel.org>
 <20251020122944.3074811-17-maz@kernel.org>
Message-ID: <aTFozefMQRg7lYxh@aspen.lan>

On Mon, Oct 20, 2025 at 01:29:33PM +0100, Marc Zyngier wrote:
> Interrupt sharing for percpu-devid interrupts is forbidden, and
> for good reasons. These are interrupts generated *from* a CPU and
> handled by itself (timer, for example). Nobody in their right mind
> would put two devices on the same pin (and if they have, they get to
> keep the pieces...).
>
> But this also prevents more benign cases, where devices are connected
> to groups of CPUs, and for which the affinities are not overlapping.
> Effectively, the only thing they share is the interrupt number, and
> nothing else.
>
> Let's tweak the definition of IRQF_SHARED applied to percpu_devid
> interrupts to allow this particular case. This results in extra
> validation at the point of the interrupt being setup and freed,
> as well as a tiny bit of extra complexity for interrupts at handling
> time (to pick the correct irqaction).
>
> Tested-by: Will Deacon <will at kernel.org>
> Signed-off-by: Marc Zyngier <maz at kernel.org>

I picked up this patch via linux-next and it appears be causing boot
regressions on MIPS/qemu. This patch was identified with a bisect and
a git revert of this patch from the linux-next tip resolves the problem
(specifically, next-20251204 with git revert bdf4e2ac295f).

I'm running the code as part of the kgdb test suite but the system
doesn't survive long enough for kgdb to be involved. In fact I was able
to reduce things to the following reproduction with all the kgdb pieces
removed:

    make malta_kvm_defconfig generic/64r6.config
    ../scripts/config \
        --enable WERROR --enable CPU_MIPS64_R6 --enable MIPS_CPS \
	--enable BLK_DEV_INITRD --set-val FRAME_WARN 2048
    make olddefconfig
    make -j$(nproc) all
    qemu-system-mips64el -cpu I6400 -M malta -m 1G -smp 2 \
        -kernel vmlinux -nographic \
	-append " console=ttyS0,115200 clk_ignore_unused"

The stack dumps continually so I have to abridge the logs but the logs
to second stack trace are:

~~~
Linux version 6.18.0-next-20251204 (drt at wychelm) (mips64el-linux-gcc.br_real (Buildroot 2025.02.8) 14.3.0, GNU ld (GNU Binutils) 2.44) #20 SMP Thu Dec  4 10:37:28 GMT 2025
earlycon: uart8250 at I/O port 0x3f8 (options '38400n8')
printk: legacy bootconsole [uart8250] enabled
CPU0 revision is: 0001a900 (MIPS I6400)
FPU revision is: 20f30300
MSA revision is: 00000300
MIPS: machine is mti,malta
Software DMA cache coherency enabled
Initial ramdisk at: 0x900000000fc40000 (3818338 bytes)
OF: reserved mem: Reserved memory: No reserved-memory node in the DT
VP topology {2} total 2
Primary instruction cache 64kB, VIPT, 4-way, linesize 64 bytes.
Primary data cache 64kB, 4-way, PIPT, no aliases, linesize 64 bytes
Zone ranges:
  DMA      [mem 0x0000000000000000-0x0000000000ffffff]
  DMA32    [mem 0x0000000001000000-0x00000000ffffffff]
  Normal   empty
Movable zone start for each node
Early memory node ranges
  node   0: [mem 0x0000000000000000-0x000000000fffffff]
  node   0: [mem 0x0000000090000000-0x00000000bfffffff]
Initmem setup node 0 [mem 0x0000000000000000-0x00000000bfffffff]
On node 0, zone DMA32: 131072 pages in unavailable ranges
random: crng init done
percpu: Embedded 7 pages/cpu s69728 r8192 d36768 u114688
Kernel command line: rd_start=0xffffffff8fc40000 rd_size=3818338  console=ttyS0,115200 kgdboc=ttyS0 clk_ignore_unused
Unknown kernel command line parameters "kgdboc=ttyS0", will be passed to user space.
printk: log buffer data + meta data: 32768 + 114688 = 147456 bytes
Dentry cache hash table entries: 131072 (order: 6, 1048576 bytes, linear)
Inode-cache hash table entries: 65536 (order: 5, 524288 bytes, linear)
Cache parity protection disabled
MAAR configuration:
  [0]: 0x0000000000000000-0x000000000fffffff speculate
  [1]: 0x0000000090000000-0x00000000bfffffff speculate
  [2]: disabled
  [3]: disabled
  [4]: disabled
  [5]: disabled
  [6]: disabled
  [7]: disabled
Built 1 zonelists, mobility grouping on.  Total pages: 65536
mem auto-init: stack:all(zero), heap alloc:off, heap free:off
SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=2, Nodes=1
rcu: Hierarchical RCU implementation.
rcu: 	RCU event tracing is enabled.
	Tracing variant of Tasks RCU enabled.
rcu: RCU calculated value of scheduler-enlistment delay is 10 jiffies.
RCU Tasks Trace: Setting shift to 1 and lim to 1 rcu_task_cb_adjust=1 rcu_task_cpu_ids=2.
NR_IRQS: 256
rcu: srcu_init: Setting srcu_struct sizes based on contention.
CPU frequency 320.00 MHz
GIC frequency 100.00 MHz
clocksource: GIC: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19113045595 ns
sched_clock: 32 bits at 100MHz, resolution 10ns, wraps every 21475332090ns
clocksource: MIPS: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 11945377117 ns
Console: colour dummy device 80x25
Calibrating delay loop...
CPU 0 Unable to handle kernel paging request at virtual address 0000000000000000, epc == ffffffff801c2398, ra == ffffffff801bab00
Oops[#1]:
CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted 6.18.0-next-20251204 #20 NONE
Hardware name: mti,malta
$ 0   : 0000000000000000 0000000000000001 0000000000000000 0000000000000000
$ 4   : 0000000000000001 a8000000020e8008 0000000000000000 ffffffff80c23b80
$ 8   : 0000000000000004 0000000000000000 0000000000000000 000000000000002f
$12   : a8000000020f4000 0000000000003ff0 0000000000003000 0000000000000003
$16   : ffffffff80d095c0 ffffffff80ceb410 0000000000000019 ffffffff80c378c0
$20   : ffffffff80c4bec8 0000000000000000 ffffffff80e00000 ffffffff80de0000
$24   : 0000000000000000 0000000000000010
$28   : ffffffff80c20000 a8000000020f7ec0 a800000000e12fcd ffffffff801bab00
epc   : ffffffff801c2398 handle_percpu_devid_irq+0xb8/0x250
ra    : ffffffff801bab00 handle_irq_desc+0x48/0x88
Status: 1400a4e2	KX SX UX KERNEL EXL
Cause : 00800408 (ExcCode 02)
BadVA : 0000000000000000
PrId  : 0001a900 (MIPS I6400)
Modules linked in:
Process swapper/0 (pid: 0, threadinfo=(____ptrval____), task=(____ptrval____), tls=0000000000000000)
Stack : ffffffff80c35a2c 0000000000000002 ffffffff80e00000 0fffffffffffffff
        ffffffff80c50000 0000000000000001 0000000000000003 ffffffff801bab00
        0000000000000000 ffffffff805d82a8 0000000000000000 0000000000000008
        0000000000000000 0000000000000000 0000000000000000 5189d95a7a4f4800
        a800000002014300 0000000000000002 0000000000000001 000000000000001f
        ffffffff80e00000 0000000000000004 0000000000000000 ffffffff801bab00
        0000000000000000 ffffffff809ec128 0000000000000001 fffffffffffffffb
        0000000000000001 ffffffff805d7ebc 0000000000000000 0000000000000000
        ffffffff80c23c80 ffffffff80c50000 ffffffff80de0000 ffffffff80db0000
        0000000000000000 ffffffff80112f10 ffffffff80c23c80 0000000000000000
Call Trace:
[<ffffffff801c2398>] handle_percpu_devid_irq+0xb8/0x250
[<ffffffff801bab00>] handle_irq_desc+0x48/0x88
[<ffffffff805d82a8>] gic_irq_dispatch+0xc0/0x288
[<ffffffff801bab00>] handle_irq_desc+0x48/0x88
[<ffffffff809ec128>] do_domain_IRQ+0x28/0x40
[<ffffffff805d7ebc>] plat_irq_dispatch+0x64/0xe8
[<ffffffff80112f10>] handle_int+0x134/0x140
[<ffffffff80110dc8>] calibrate_delay+0x158/0x290
[<ffffffff80d58e48>] start_kernel+0x754/0x7a4

Code: da000048  de020010  0043102d <dc420000> 00c21016  30420001  d85ffff8  00000000  00000000

CPU 0 Unable to handle kernel paging request at virtual address 0000000000000000, epc == ffffffff801c2398, ra == ffffffff801bab00
Oops[#2]:
CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Tainted: G      D             6.18.0-next-20251204 #20 NONE
Tainted: [D]=DIE
Hardware name: mti,malta
$ 0   : 0000000000000000 0000000000000001 0000000000000000 0000000000000000
$ 4   : 0000000000000002 a8000000020e8008 0000000000000000 a8000000020f7ae0
$ 8   : 0000000000000004 0000000000000000 0000000000000000 0000000000000000
$12   : a8000000020f4000 a8000000020f4000 0000000000003000 0000000000000000
$16   : ffffffff80d095c0 ffffffff80ceb410 0000000000000019 ffffffff80c378c0
$20   : ffffffff80c4bec8 0000000000000000 ffffffff80e00000 0000000000000001
$24   : 0000000000000000 ffffffffffffffff
$28   : ffffffff80c20000 a8000000020f7ab0 a800000000e12fcd ffffffff801bab00
epc   : ffffffff801c2398 handle_percpu_devid_irq+0xb8/0x250
ra    : ffffffff801bab00 handle_irq_desc+0x48/0x88
Status: 1400a4e2	KX SX UX KERNEL EXL
Cause : 00800408 (ExcCode 02)
BadVA : 0000000000000000
PrId  : 0001a900 (MIPS I6400)
Modules linked in:
Process swapper/0 (pid: 0, threadinfo=(____ptrval____), task=(____ptrval____), tls=0000000000000000)
Stack : ffffffff80c50000 0000000000000002 ffffffff80e00000 0fffffffffffffff
        ffffffff80c50000 0000000000000001 0000000000000003 ffffffff801bab00
        0000000000000000 ffffffff805d82a8 a8000000020f7bd8 ffffffff801b94f4
        0000000000000000 0000000000000000 ffffffff80c4bc10 5189d95a7a4f4800
        a800000002014300 0000000000000002 0000000000000001 000000000000001f
        ffffffff80e00000 0000000000000004 0000000000000000 ffffffff801bab00
        0000000000000001 ffffffff809ec128 0000000000000000 fffffffffffffffb
        0000000000000001 ffffffff805d7ebc ffffffff80c7b558 ffffffff80c23c80
        a8000000020f7be0 ffffffff80b2fcb8 ffffffff80de0000 ffffffff80c4bec8
        ffffffff80c515c0 ffffffff80112f10 0000000000000000 0000000000000001
        ...
Call Trace:
[<ffffffff801c2398>] handle_percpu_devid_irq+0xb8/0x250
[<ffffffff801bab00>] handle_irq_desc+0x48/0x88
[<ffffffff805d82a8>] gic_irq_dispatch+0xc0/0x288
[<ffffffff801bab00>] handle_irq_desc+0x48/0x88
[<ffffffff809ec128>] do_domain_IRQ+0x28/0x40
[<ffffffff805d7ebc>] plat_irq_dispatch+0x64/0xe8
[<ffffffff80112f10>] handle_int+0x134/0x140
[<ffffffff8011a730>] die+0xa8/0xf8
[<ffffffff80134680>] do_page_fault+0x530/0x540
[<ffffffff8013a1a8>] tlb_do_page_fault_0+0x108/0x110
[<ffffffff801bab00>] handle_irq_desc+0x48/0x88

Code: da000048  de020010  0043102d <dc420000> 00c21016  30420001  d85ffff8  00000000  00000000
~~~

FWIW I'm using a buildroot gcc-14 toolchain but I've seen the same problem on
gcc-13 in previous kgdbtest logs.


Daniel.


From haoxiang_li2024 at 163.com  Thu Dec  4 03:04:52 2025
From: haoxiang_li2024 at 163.com (Haoxiang Li)
Date: Thu,  4 Dec 2025 19:04:52 +0800
Subject: [PATCH] soc: mediatek: SVS: Fix a reference leak bug in svs_add_device_link()
Message-ID: <20251204110452.93867-1-haoxiang_li2024@163.com>

svs_get_subsys_device() increases the reference count of the returned
device, if error happens, put_device() is required to drop the device
reference.

Fixes: 681a02e95000 ("soc: mediatek: SVS: introduce MTK SVS engine")
Cc: stable at vger.kernel.org
Signed-off-by: Haoxiang Li <haoxiang_li2024 at 163.com>
---
 drivers/soc/mediatek/mtk-svs.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c
index f45537546553..c8f15bb139c6 100644
--- a/drivers/soc/mediatek/mtk-svs.c
+++ b/drivers/soc/mediatek/mtk-svs.c
@@ -2155,12 +2155,15 @@ static struct device *svs_add_device_link(struct svs_platform *svsp,
 	sup_link = device_link_add(svsp->dev, dev,
 				   DL_FLAG_AUTOREMOVE_CONSUMER);
 	if (!sup_link) {
+		put_device(dev);
 		dev_err(svsp->dev, "sup_link is NULL\n");
 		return ERR_PTR(-EINVAL);
 	}
 
-	if (sup_link->supplier->links.status != DL_DEV_DRIVER_BOUND)
+	if (sup_link->supplier->links.status != DL_DEV_DRIVER_BOUND) {
+		put_device(dev);
 		return ERR_PTR(-EPROBE_DEFER);
+	}
 
 	return dev;
 }
-- 
2.25.1



From ben.horgan at arm.com  Thu Dec  4 03:13:41 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Thu, 4 Dec 2025 11:13:41 +0000
Subject: [PATCH v3 1/9] arm64: Repaint ID_AA64MMFR2_EL1.IDS description
In-Reply-To: <86cy4uplo5.wl-maz@kernel.org>
References: <20251204094806.3846619-1-maz@kernel.org>
 <20251204094806.3846619-2-maz@kernel.org>
 <b98c154a-1658-4501-bfa5-a93303aa5b3f@arm.com> <86cy4uplo5.wl-maz@kernel.org>
Message-ID: <d546725b-e96f-461e-887d-8679cf747c7d@arm.com>

Hi Marc,

On 12/4/25 10:48, Marc Zyngier wrote:
> On Thu, 04 Dec 2025 10:36:54 +0000,
> Ben Horgan <ben.horgan at arm.com> wrote:
>>
>> Hi Marc,
>>
>> On 12/4/25 09:47, Marc Zyngier wrote:
>>> ID_AA64MMFR2_EL1.IDS, as described in the sysreg file, is pretty horrible
>>> as it diesctly give the ESR value. Repaint it using the usual NI/IMP
>>> identifiers to describe the absence/presence of FEAT_IDST.
>>>
>>> Signed-off-by: Marc Zyngier <maz at kernel.org>
>>> ---
>>>  arch/arm64/kvm/hyp/nvhe/sys_regs.c | 2 +-
>>>  arch/arm64/tools/sysreg            | 4 ++--
>>>  2 files changed, 3 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/arch/arm64/kvm/hyp/nvhe/sys_regs.c b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
>>> index 82da9b03692d4..107d62921b168 100644
>>> --- a/arch/arm64/kvm/hyp/nvhe/sys_regs.c
>>> +++ b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
>>> @@ -134,7 +134,7 @@ static const struct pvm_ftr_bits pvmid_aa64mmfr2[] = {
>>>  	MAX_FEAT(ID_AA64MMFR2_EL1, UAO, IMP),
>>>  	MAX_FEAT(ID_AA64MMFR2_EL1, IESB, IMP),
>>>  	MAX_FEAT(ID_AA64MMFR2_EL1, AT, IMP),
>>> -	MAX_FEAT_ENUM(ID_AA64MMFR2_EL1, IDS, 0x18),
>>> +	MAX_FEAT_ENUM(ID_AA64MMFR2_EL1, IDS, IMP),
>>>  	MAX_FEAT(ID_AA64MMFR2_EL1, TTL, IMP),
>>>  	MAX_FEAT(ID_AA64MMFR2_EL1, BBM, 2),
>>>  	MAX_FEAT(ID_AA64MMFR2_EL1, E0PD, IMP),
>>> diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
>>> index 1c6cdf9d54bba..3261e8791ac03 100644
>>> --- a/arch/arm64/tools/sysreg
>>> +++ b/arch/arm64/tools/sysreg
>>> @@ -2257,8 +2257,8 @@ UnsignedEnum	43:40	FWB
>>>  	0b0001	IMP
>>>  EndEnum
>>>  Enum	39:36	IDS
>>
>> Should this also be changed to an UnsignedEnum?
> 
> I'm not sure this brings much when you only have two values. If IDS
> was growing a third value, and that there was an actual order in the
> numbering scheme, then yes, that'd be useful.

Joey just pointed out to me that there is a new third field. Not in the
arm reference manual yet, but mentioned in the xml. I'm unsure if it's
necessary to consider this at the moment though.

https://developer.arm.com/documentation/ddi0601/2025-09/AArch64-Registers/ID-AA64MMFR2-EL1--AArch64-Memory-Model-Feature-Register-2?lang=en

> 
> But at this stage, I'm not confident that this is desirable, let alone
> necessary.
> 
> Thanks,
> 
> 	M.
> 

Thanks,

Ben



From linux at armlinux.org.uk  Thu Dec  4 03:19:01 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Thu, 4 Dec 2025 11:19:01 +0000
Subject: [PATCH net v2] net: stmmac: Fix E2E delay mechanism
In-Reply-To: <26656845-d9d6-4fd2-bfff-99996cf03741@redhat.com>
References: <20251129-ext-ptp-2v-v2-1-d23aca3e694f@altera.com>
 <26656845-d9d6-4fd2-bfff-99996cf03741@redhat.com>
Message-ID: <aTFuJUiLMnHrnpW5@shell.armlinux.org.uk>

On Thu, Dec 04, 2025 at 10:58:40AM +0100, Paolo Abeni wrote:
> On 11/29/25 4:07 AM, Rohan G Thomas wrote:
> > For E2E delay mechanism, "received DELAY_REQ without timestamp" error
> > messages show up for dwmac v3.70+ and dwxgmac IPs.
> > 
> > This issue affects socfpga platforms, Agilex7 (dwmac 3.70) and
> > Agilex5 (dwxgmac). According to the databook, to enable timestamping
> > for all events, the SNAPTYPSEL bits in the MAC_Timestamp_Control
> > register must be set to 2'b01, and the TSEVNTENA bit must be cleared
> > to 0'b0.
> > 
> > Commit 3cb958027cb8 ("net: stmmac: Fix E2E delay mechanism") already
> > addresses this problem for all dwmacs above version v4.10. However,
> > same holds true for v3.70 and above, as well as for dwxgmac. Updates
> > the check accordingly.
> > 
> > Fixes: 14f347334bf2 ("net: stmmac: Correctly take timestamp for PTPv2")
> > Fixes: f2fb6b6275eb ("net: stmmac: enable timestamp snapshot for required PTP packets in dwmac v5.10a")
> > Fixes: 3cb958027cb8 ("net: stmmac: Fix E2E delay mechanism")
> > Signed-off-by: Rohan G Thomas <rohan.g.thomas at altera.com>
> > ---
> > v1 -> v2:
> >    - Rebased patch to net tree
> >    - Replace core_type with has_xgmac
> >    - Nit changes in the commit message
> >    - Link: https://lore.kernel.org/all/20251125-ext-ptp-fix-v1-1-83f9f069cb36 at altera.com/
> 
> Given there is some uncertain WRT the exact oldest version to be used,
> it would be great to have some 3rd party testing/feedback on this. Let's
> wait a little more.

As I said, in the v3.74 documentation, it is stated that the SNAPTYPSEL
functions changed between v3.50 and v3.60, so I think it would be better
to propose a patch to test for < v3.6.

Alternatively, if someone has the pre-v3.6 databook to check what the
SNAPTYPSEL definition is and compare it with the v3.6+ definition, that
would also be a good thing to do.

>From the 3.74:

SNAPTYPSEL
00		?
01		?
10		Sync, Delay_Req
11		Sync, PDelay_Req, PDelay_Resp

TSEVNTENA
0		All messages except Announce, Management and Signalling
1		Sync, Delay_Req, PDelay_Req, PDelay_Resp

No table is provided, so it's difficult to know what all the bit
combinations do for v3.74.

>From STM32MP151 documentation (v4.2 according to GMAC4_VERSION
register):

SNAPTYPSEL	TSMSTRENA	TSEVNTENA
00		x		0		Sync, Delay_Req
00		0		1		Delay_Req
00		1		1		Sync
01		x		0		Sync, PDelay_Req, PDelay_Resp
01		0		1		Sync, Delay_Req, PDelay_Req,
						PDelay_Resp
01		1		1		Sync, PDelay_Req, PDelay_Resp
10		x		x		Sync, Delay_Req
11		x		x		Sync, PDelay_Req, PDelay_Resp

For iMX8MP (v5.1) and STM32MP23/25xx (v5.3) documentatiion:

SNAPTYPSEL	TSMSTRENA	TSEVNTENA
00		x		0		Sync, Follow_Up, Delay_Req,
						Delay_Resp
00		0		1		Sync
00		1		1		Delay_Req
01		x		0		Sync, Follow_Up, Delay_Req,
						Delay_Resp, PDelay_Req,
						PDelay_Resp
01		0		1		Sync, PDelay_Req, PDelay_Resp
01		1		1		Delay_Req, PDelay_Req,
						PDelay_Resp
10		x		x		Sync, Delay_Req
11		x		x		PDelay_Req, PDelay_Resp

Differences:
00 x 0 - adds Follow_Up
00 X 1 - TSMSTRENA bit inverted
01 x 0 - adds Follow_Up, Delay_Req, Delay_Resp
01 0 1 - removes Delay_Req
01 1 1 - removes Sync, adds Delay_Req
11 x x - removes Sync

So, it looks like there's another difference between v4.2 and v5.1.

If the STM32MP151 (v4.2) documentation is correct, then from what I see
in the driver, if HWTSTAMP_FILTER_PTP_V1_L4_SYNC is requested, we set
SNAPTYPSEL=00 TSMSTRENA=0 TSEVNTENA=1, which semects Delay_Req messages
only, but on iMX8MP this selects Sync messages.

HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ is the opposite (due to the
inversion of TSMSTRENA) for SNAPTYPSEL=00.

For HWTSTAMP_FILTER_PTP_V2_EVENT, we currently set SNAPTYPSEL=01
TSMSTRENA=0 and TSEVNTENA=1 for cores < v4.1:
- For STM32MP151 (v4.2) we get Sync, PDelay_Req, PDelay_Resp but
  _not_ Delay_Req. Seems broken.
- For iMX8MP (v5.1) and STM32MP23/25xx (v5.3), we get
  Sync, Follow_Up, Delay_Req, Delay_Resp, PDelay_Req, PDelay_Resp

Basically, the conclusion I am coming to is that Synopsys's idea
of "lets tell the hardware what _kind_ of PTP clock we want to be,
whether we're master, etc" is subject to multiple revisions in
terms of which messages each mode selects, and it would have been
_far_ simpler and easier to understand had they just provided a
16-bit bitfield of message types to accept.

So, I'm wary about this change - I think there's more "mess"
here than just that single version check in
HWTSTAMP_FILTER_PTP_V2_EVENT, I think it's a lot more complicated.
I'm not sure what the best solution is right now, because I don't
have the full information, but it looks to me like the current
approach does not result in the expected configuration for each
of the dwmac core versions, and there are multiple issues here.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From pavel at ucw.cz  Thu Dec  4 03:22:47 2025
From: pavel at ucw.cz (Pavel Machek)
Date: Thu, 4 Dec 2025 12:22:47 +0100
Subject: [PATCH v2 3/3] ARM: samsung: exynos5250: Allow CPU1 to boot
In-Reply-To: <20251125-google-manta-v2-3-0f097cfff39c@timmermann.space>
References: <20251125-google-manta-v2-0-0f097cfff39c@timmermann.space>
 <20251125-google-manta-v2-3-0f097cfff39c@timmermann.space>
Message-ID: <aTFvBwjms8msxIae@duo.ucw.cz>

On Tue 2025-11-25 16:12:42, Lukas Timmermann wrote:
> From: Alexandre Marquet <tb at a-marquet.fr>
> 
> Add an exception to let the secondary CPU boot.
> 
> Signed-off-by: Alexandre Marquet <tb at a-marquet.fr>
> Signed-off-by: Lukas Timmermann <linux at timmermann.space>
> ---
>  arch/arm/mach-exynos/firmware.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c
> index a5e22678e27b..80e645b4d338 100644
> --- a/arch/arm/mach-exynos/firmware.c
> +++ b/arch/arm/mach-exynos/firmware.c
> @@ -61,10 +61,10 @@ static int exynos_cpu_boot(int cpu)
>  	 * Exynos3250 doesn't need to send smc command for secondary CPU boot
>  	 * because Exynos3250 removes WFE in secure mode.
>  	 *
> -	 * On Exynos5 devices the call is ignored by trustzone firmware.
> +	 * On most Exynos5 devices the call is ignored by trustzone firmware.
>  	 */
>  	if (!soc_is_exynos4210() && !soc_is_exynos4212() &&
> -	    !soc_is_exynos4412())
> +	    !soc_is_exynos4412() && !of_machine_is_compatible("samsung,nexus10-manta"))
>  		return 0;

Strange -- +       compatible = "google,manta", "samsung,exynos5250", "samsung,exynos5";

Should this be google,manta or something?

Also please cc: phone-devel mailing list with phone related patches.

Best regards,
								Pavel

-- 
I don't work for Nazis and criminals, and neither should you.
Boycott Putin, Trump, Netanyahu and Musk!
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 195 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251204/18765ddc/attachment.sig>

From david at kernel.org  Thu Dec  4 03:39:10 2025
From: david at kernel.org (David Hildenbrand (Red Hat))
Date: Thu, 4 Dec 2025 12:39:10 +0100
Subject: [PATCH v5 09/12] arm64: mm: replace TIF_LAZY_MMU with
 in_lazy_mmu_mode()
In-Reply-To: <89ecddb7-83ee-427b-823b-984204939ecf@arm.com>
References: <20251124132228.622678-1-kevin.brodsky@arm.com>
 <20251124132228.622678-10-kevin.brodsky@arm.com>
 <89ecddb7-83ee-427b-823b-984204939ecf@arm.com>
Message-ID: <b341e7fa-4382-48b5-896a-1a0d347b66ca@kernel.org>

On 12/4/25 07:52, Anshuman Khandual wrote:
> On 24/11/25 6:52 PM, Kevin Brodsky wrote:
>> The generic lazy_mmu layer now tracks whether a task is in lazy MMU
>> mode. As a result we no longer need a TIF flag for that purpose -
>> let's use the new in_lazy_mmu_mode() helper instead.
>>
>> The explicit check for in_interrupt() is no longer necessary either
>> as in_lazy_mmu_mode() always returns false in interrupt context.
>>
>> Signed-off-by: Kevin Brodsky <kevin.brodsky at arm.com>
>> ---
>>   arch/arm64/include/asm/pgtable.h     | 19 +++----------------
>>   arch/arm64/include/asm/thread_info.h |  3 +--
>>   2 files changed, 4 insertions(+), 18 deletions(-)
>>
>> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
>> index a7d99dee3dc4..dd7ed653a20d 100644
>> --- a/arch/arm64/include/asm/pgtable.h
>> +++ b/arch/arm64/include/asm/pgtable.h
>> @@ -62,28 +62,16 @@ static inline void emit_pte_barriers(void)
>>   
>>   static inline void queue_pte_barriers(void)
>>   {
>> -	unsigned long flags;
>> -
>> -	if (in_interrupt()) {
>> -		emit_pte_barriers();
>> -		return;
>> -	}
>> -
>> -	flags = read_thread_flags();
>> -
>> -	if (flags & BIT(TIF_LAZY_MMU)) {
>> +	if (in_lazy_mmu_mode()) {
>>   		/* Avoid the atomic op if already set. */
>> -		if (!(flags & BIT(TIF_LAZY_MMU_PENDING)))
>> +		if (!test_thread_flag(TIF_LAZY_MMU_PENDING))
> 
> A small nit - will it be better not to use test_thread_flag() here and just
> keep checking flags like earlier to avoid non-related changes. Although not
> a problem TBH.

I'd assume the existing code wanted to avoid fetching the flags two 
times? So switching to test_thread_flag() should be fine now.

-- 
Cheers

David


From krzk at kernel.org  Thu Dec  4 03:51:36 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 4 Dec 2025 12:51:36 +0100
Subject: [PATCH v2 3/3] ARM: samsung: exynos5250: Allow CPU1 to boot
In-Reply-To: <aTFvBwjms8msxIae@duo.ucw.cz>
References: <20251125-google-manta-v2-0-0f097cfff39c@timmermann.space>
 <20251125-google-manta-v2-3-0f097cfff39c@timmermann.space>
 <aTFvBwjms8msxIae@duo.ucw.cz>
Message-ID: <73efeaeb-0cde-45af-af92-4fd7b5d4589c@kernel.org>

On 04/12/2025 12:22, Pavel Machek wrote:
> Also please cc: phone-devel mailing list with phone related patches.

You don't have to. This list is not part of any upstream Linux kernel
process (see `git grep`), it's not relevant to upstream kernel development.


Best regards,
Krzysztof


From david at kernel.org  Thu Dec  4 03:52:32 2025
From: david at kernel.org (David Hildenbrand (Red Hat))
Date: Thu, 4 Dec 2025 12:52:32 +0100
Subject: [PATCH v5 08/12] mm: enable lazy_mmu sections to nest
In-Reply-To: <2dfd54d7-fe2a-4921-85ff-a581392a777a@arm.com>
References: <20251124132228.622678-1-kevin.brodsky@arm.com>
 <20251124132228.622678-9-kevin.brodsky@arm.com>
 <2dfd54d7-fe2a-4921-85ff-a581392a777a@arm.com>
Message-ID: <93d04ef8-0364-4013-8839-ba599d930cb2@kernel.org>

Some comments from my side:


>>   static inline void arch_enter_lazy_mmu_mode(void)
>>   {
>> -	/*
>> -	 * lazy_mmu_mode is not supposed to permit nesting. But in practice this
>> -	 * does happen with CONFIG_DEBUG_PAGEALLOC, where a page allocation
>> -	 * inside a lazy_mmu_mode section (such as zap_pte_range()) will change
>> -	 * permissions on the linear map with apply_to_page_range(), which
>> -	 * re-enters lazy_mmu_mode. So we tolerate nesting in our
>> -	 * implementation. The first call to arch_leave_lazy_mmu_mode() will
>> -	 * flush and clear the flag such that the remainder of the work in the
>> -	 * outer nest behaves as if outside of lazy mmu mode. This is safe and
>> -	 * keeps tracking simple.
>> -	 */
>> -
>>   	set_thread_flag(TIF_LAZY_MMU);>  }
> 
> Should not platform specific changes be deferred to subsequent patches until
> nesting is completely enabled in generic first ? Although no problem as such
> but would be bit cleaner.

This could indeed be done in a separate patch. But I also don't see a 
problem with updating the doc in this patch.

> 
>>   
>> diff --git a/include/linux/mm_types_task.h b/include/linux/mm_types_task.h
>> index a82aa80c0ba4..11bf319d78ec 100644
>> --- a/include/linux/mm_types_task.h
>> +++ b/include/linux/mm_types_task.h
>> @@ -88,4 +88,9 @@ struct tlbflush_unmap_batch {
>>   #endif
>>   };
>>   
>> +struct lazy_mmu_state {
>> +	u8 enable_count;
>> +	u8 pause_count;
>> +};
>> +
> 
> Should not this be wrapped with CONFIG_ARCH_HAS_LAZY_MMU_MODE as the task_struct
> element 'lazy_mmu_state' is only available with the feature.

No strong opinion; the compiler will ignore it either way. And less 
ifdef is good, right? :)

... and there is nothing magical in there that would result in other 
dependencies.

> Besides, is a depth
> of 256 really expected here ? 4 bits for each element would not be sufficient for
> a depth of 16 ?


We could indeed use something like

struct lazy_mmu_state {
	u8 enable_count : 4;
	u8 pause_count : 4;
};

but then, the individual operations on enable_count/pause_count need 
more instructions.

Further, as discussed, this 1 additional byte barely matters given the 
existing size of the task struct.

No strong opinion.

> 
>>    */
>>   #ifdef CONFIG_ARCH_HAS_LAZY_MMU_MODE
>> +/**
>> + * lazy_mmu_mode_enable() - Enable the lazy MMU mode.
>> + *
>> + * Enters a new lazy MMU mode section; if the mode was not already enabled,
>> + * enables it and calls arch_enter_lazy_mmu_mode().
>> + *
>> + * Must be paired with a call to lazy_mmu_mode_disable().
>> + *
>> + * Has no effect if called:
>> + * - While paused - see lazy_mmu_mode_pause()
>> + * - In interrupt context
>> + */
>>   static inline void lazy_mmu_mode_enable(void)
>>   {
>> -	if (in_interrupt())
>> +	struct lazy_mmu_state *state = &current->lazy_mmu_state;
>> +
>> +	if (in_interrupt() || state->pause_count > 0)
>>   		return;
>>   
>> -	arch_enter_lazy_mmu_mode();
>> +	VM_WARN_ON_ONCE(state->enable_count == U8_MAX);
>> +
>> +	if (state->enable_count++ == 0)
>> +		arch_enter_lazy_mmu_mode();
> 
> When lazy_mmu_mode_enable() gets called for the first time with state->enable_count as 0,
> then arch_enter_lazy_mmu_mode() will not get called ? Bit confused.


state->enable_count++ returns the old value (0). Are you thinking of
++state->enable_count?

But maybe I misudnerstood your concern.

[...]

>> +/**
>> + * lazy_mmu_mode_pause() - Resume the lazy MMU mode.
>> + *
>> + * Resumes the lazy MMU mode; if it was active at the point where the matching
>> + * call to lazy_mmu_mode_pause() was made, re-enables it and calls
>> + * arch_enter_lazy_mmu_mode().
>> + *
>> + * Must match a call to lazy_mmu_mode_pause().
>> + *
>> + * Has no effect if called:
>> + * - While paused (inside another pause()/resume() pair)
>> + * - In interrupt context
>> + */
>>   static inline void lazy_mmu_mode_resume(void)
>>   {
>> +	struct lazy_mmu_state *state = &current->lazy_mmu_state;
>> +
>>   	if (in_interrupt())
>>   		return;
>>   
>> -	arch_enter_lazy_mmu_mode();
>> +	VM_WARN_ON_ONCE(state->pause_count == 0);
>> +
>> +	if (--state->pause_count == 0 && state->enable_count > 0)
>> +		arch_enter_lazy_mmu_mode();
>>   }
> 
> Should not state->pause/enable_count tests and increment/decrement be handled
> inside include/linux/sched via helpers like in_lazy_mmu_mode() ? This is will
> ensure cleaner abstraction with respect to task_struct.

I don't think this is required given that this code here implements
CONFIG_ARCH_HAS_LAZY_MMU_MODE support.

-- 
Cheers

David


From pavel at ucw.cz  Thu Dec  4 03:53:03 2025
From: pavel at ucw.cz (Pavel Machek)
Date: Thu, 4 Dec 2025 12:53:03 +0100
Subject: [PATCH v2 3/3] ARM: samsung: exynos5250: Allow CPU1 to boot
In-Reply-To: <73efeaeb-0cde-45af-af92-4fd7b5d4589c@kernel.org>
References: <20251125-google-manta-v2-0-0f097cfff39c@timmermann.space>
 <20251125-google-manta-v2-3-0f097cfff39c@timmermann.space>
 <aTFvBwjms8msxIae@duo.ucw.cz>
 <73efeaeb-0cde-45af-af92-4fd7b5d4589c@kernel.org>
Message-ID: <aTF2H0f9TJiwCLe5@duo.ucw.cz>

On Thu 2025-12-04 12:51:36, Krzysztof Kozlowski wrote:
> On 04/12/2025 12:22, Pavel Machek wrote:
> > Also please cc: phone-devel mailing list with phone related patches.
> 
> You don't have to. This list is not part of any upstream Linux kernel
> process (see `git grep`), it's not relevant to upstream kernel development.

Yes, you should. Its a relevant mailing list.

								Pavel
-- 
I don't work for Nazis and criminals, and neither should you.
Boycott Putin, Trump, Netanyahu and Musk!
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 195 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251204/4d9996bf/attachment.sig>

From david at kernel.org  Thu Dec  4 03:53:18 2025
From: david at kernel.org (David Hildenbrand (Red Hat))
Date: Thu, 4 Dec 2025 12:53:18 +0100
Subject: [PATCH v5 08/12] mm: enable lazy_mmu sections to nest
In-Reply-To: <2c2b3382-7bdb-41a9-b48e-4fa9a44312ba@arm.com>
References: <20251124132228.622678-1-kevin.brodsky@arm.com>
 <20251124132228.622678-9-kevin.brodsky@arm.com>
 <23dcf752-0b75-45a7-84f8-25bddf97af08-agordeev@linux.ibm.com>
 <703cbee6-a813-4970-9232-34ee91ed8961@arm.com>
 <2c2b3382-7bdb-41a9-b48e-4fa9a44312ba@arm.com>
Message-ID: <0f08e893-6097-4ab1-8231-ac3304c51ee9@kernel.org>

On 12/4/25 06:25, Anshuman Khandual wrote:
> 
> 
> On 03/12/25 1:50 PM, Kevin Brodsky wrote:
>> On 28/11/2025 14:55, Alexander Gordeev wrote:
>>>> + * in_lazy_mmu_mode() can be used to check whether the lazy MMU mode is
>>>> + * currently enabled.
>>> The in_lazy_mmu_mode() name looks ambiguous to me. When the lazy MMU mode
>>> is paused are we still in lazy MMU mode? The __task_lazy_mmu_mode_active()
>>> implementation suggests we are not, while one could still assume we are,
>>> just paused.
>>>
>>> Should in_lazy_mmu_mode() be named e.g. as in_active_lazy_mmu_mode() such
>>> a confusion would not occur in the first place.
>>
>> I see your point, how about is_lazy_mmu_mode_active()?
> 
> Agreed - is_lazy_mmu_mode_active() seems better.

+1, I was scratching my head over this in previous revisions as well.

-- 
Cheers

David


From krzk at kernel.org  Thu Dec  4 03:54:03 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 4 Dec 2025 12:54:03 +0100
Subject: [PATCH v2 3/3] ARM: samsung: exynos5250: Allow CPU1 to boot
In-Reply-To: <aTF2H0f9TJiwCLe5@duo.ucw.cz>
References: <20251125-google-manta-v2-0-0f097cfff39c@timmermann.space>
 <20251125-google-manta-v2-3-0f097cfff39c@timmermann.space>
 <aTFvBwjms8msxIae@duo.ucw.cz>
 <73efeaeb-0cde-45af-af92-4fd7b5d4589c@kernel.org>
 <aTF2H0f9TJiwCLe5@duo.ucw.cz>
Message-ID: <a68ee81f-1d2c-47f4-b86f-e0e803c1cfd3@kernel.org>

On 04/12/2025 12:53, Pavel Machek wrote:
> On Thu 2025-12-04 12:51:36, Krzysztof Kozlowski wrote:
>> On 04/12/2025 12:22, Pavel Machek wrote:
>>> Also please cc: phone-devel mailing list with phone related patches.
>>
>> You don't have to. This list is not part of any upstream Linux kernel
>> process (see `git grep`), it's not relevant to upstream kernel development.
> 
> Yes, you should. Its a relevant mailing list.

git grep for it. Stop inventing rules.

Best regards,
Krzysztof


From pavel at ucw.cz  Thu Dec  4 03:55:59 2025
From: pavel at ucw.cz (Pavel Machek)
Date: Thu, 4 Dec 2025 12:55:59 +0100
Subject: [PATCH v2 3/3] ARM: samsung: exynos5250: Allow CPU1 to boot
In-Reply-To: <a68ee81f-1d2c-47f4-b86f-e0e803c1cfd3@kernel.org>
References: <20251125-google-manta-v2-0-0f097cfff39c@timmermann.space>
 <20251125-google-manta-v2-3-0f097cfff39c@timmermann.space>
 <aTFvBwjms8msxIae@duo.ucw.cz>
 <73efeaeb-0cde-45af-af92-4fd7b5d4589c@kernel.org>
 <aTF2H0f9TJiwCLe5@duo.ucw.cz>
 <a68ee81f-1d2c-47f4-b86f-e0e803c1cfd3@kernel.org>
Message-ID: <aTF2z5HbvmEuu9Iy@duo.ucw.cz>

On Thu 2025-12-04 12:54:03, Krzysztof Kozlowski wrote:
> On 04/12/2025 12:53, Pavel Machek wrote:
> > On Thu 2025-12-04 12:51:36, Krzysztof Kozlowski wrote:
> >> On 04/12/2025 12:22, Pavel Machek wrote:
> >>> Also please cc: phone-devel mailing list with phone related patches.
> >>
> >> You don't have to. This list is not part of any upstream Linux kernel
> >> process (see `git grep`), it's not relevant to upstream kernel development.
> > 
> > Yes, you should. Its a relevant mailing list.
> 
> git grep for it. Stop inventing rules.

Who is inventing rules here? Stop sabotaging review process.

"Many kernel-related lists are hosted on vger.kernel.org; you can find a
list of them at http://vger.kernel.org/vger-lists.html.  There are
kernel-related lists hosted elsewhere as well, though."

								Pavel
-- 
I don't work for Nazis and criminals, and neither should you.
Boycott Putin, Trump, Netanyahu and Musk!
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 195 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251204/6df01e68/attachment.sig>

From diederik at cknow-tech.com  Thu Dec  4 03:59:53 2025
From: diederik at cknow-tech.com (Diederik de Haas)
Date: Thu, 04 Dec 2025 12:59:53 +0100
Subject: [PATCH] regulator: fixed: fix GPIO descriptor leak on register
 failure
In-Reply-To: <20251028172828.625-1-vulab@iscas.ac.cn>
References: <20251028172828.625-1-vulab@iscas.ac.cn>
Message-ID: <DEPEYUF5BRGY.UKFBWRRE8HNP@cknow-tech.com>

On Tue Oct 28, 2025 at 6:28 PM CET, Haotian Zhang wrote:
> In the commit referenced by the Fixes tag,
> devm_gpiod_get_optional() was replaced by manual
> GPIO management, relying on the regulator core to release the
> GPIO descriptor. However, this approach does not account for the
> error path: when regulator registration fails, the core never
> takes over the GPIO, resulting in a resource leak.
>
> Add gpiod_put() before returning on regulator registration failure.
>
> Fixes: 5e6f3ae5c13b ("regulator: fixed: Let core handle GPIO descriptor")
> Signed-off-by: Haotian Zhang <vulab at iscas.ac.cn>
> ---
>  drivers/regulator/fixed.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
> index 1cb647ed70c6..a2d16e9abfb5 100644
> --- a/drivers/regulator/fixed.c
> +++ b/drivers/regulator/fixed.c
> @@ -334,6 +334,7 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
>  		ret = dev_err_probe(&pdev->dev, PTR_ERR(drvdata->dev),
>  				    "Failed to register regulator: %ld\n",
>  				    PTR_ERR(drvdata->dev));
> +		gpiod_put(cfg.ena_gpiod);
>  		return ret;
>  	}
>  

I recently upgraded the kernel of my PINE64 Quartz64 - Model A (8GB) to
6.18 and saw several stack traces and the result was that it didn't see
my PCIe card which connects a USB drive to it.
Doing a ``git bisect`` led me to this commit/patch.
I'm assuming ``git bisect log`` output isn't useful.

Interestingly enough, I haven't seen it on any of my other Rockchip
based devices thus far: not on Rock 5B (rk3588) nor on NanoPi R5S
(rk3568). Both of these devices also use PCIe via a NVMe drive.

What's possibly relevant is that quite a lot of my kernel modules are
built as ``=m``, which can/does affect probe order (apparently).

This is the call trace I'm seeing most often:

```
[   19.941158] Unable to handle kernel paging request at virtual address fffffffffffffc78
[   19.941919] Mem abort info:
[   19.942182]   ESR = 0x0000000096000006
[   19.942530]   EC = 0x25: DABT (current EL), IL = 32 bits
[   19.943013]   SET = 0, FnV = 0
[   19.943298]   EA = 0, S1PTW = 0
[   19.943591]   FSC = 0x06: level 2 translation fault
[   19.944163] Data abort info:
[   19.944440]   ISV = 0, ISS = 0x00000006, ISS2 = 0x00000000
[   19.944938]   CM = 0, WnR = 0, TnD = 0, TagAccess = 0
[   19.945400]   GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
[   19.945887] swapper pgtable: 4k pages, 48-bit VAs, pgdp=0000000003d46000
[   19.946496] [fffffffffffffc78] pgd=0000000000000000, p4d=0000000004477403, pud=0000000004478403, pmd=0000000000000000
[   19.947477] Internal error: Oops: 0000000096000006 [#1]  SMP
[   19.947997] Modules linked in: nfsd auth_rpcgss nfs_acl lockd grace sunrpc efi_pstore configfs nfnetlink autofs4 ext4 crc16 mbcache jbd2 rockchip_rng xhci_plat_hcd xhci_hcd dw_hdmi_cec d
w_hdmi_i2s_audio rk808_regulator rtc_rk808 rk817_charger fan53555 rockchipdrm gpio_rockchip dw_hdmi_qp sdhci_of_dwcmshc dwmac_rk sdhci_pltfm dw_mipi_dsi stmmac_platform sdhci dw_hdmi stmmac
 dw_mmc_rockchip analogix_dp fixed display_connector dw_mmc_pltfm drm_dp_aux_bus pcs_xpcs dwc3 phy_rockchip_inno_usb2 dw_wdt phy_rockchip_naneng_combphy phylink pl330 cqhci drm_display_help
er dw_mmc cec rc_core drm_client_lib mdio_devres drm_dma_helper ehci_platform udc_core of_mdio io_domain ehci_hcd fixed_phy drm_kms_helper ohci_platform fwnode_mdio ohci_hcd libphy rockchip
_dfi drm usbcore i2c_rk3x ulpi mdio_bus usb_common
[   19.954611] CPU: 0 UID: 0 PID: 38 Comm: kworker/u16:3 Not tainted 6.18-rc6-arm64-cknow #1 PREEMPTLAZY  Debian 6.18~rc6-1
[   19.955602] Hardware name: Pine64 Quartz64 Model A (DT)
[   19.956084] Workqueue: events_unbound deferred_probe_work_func
[   19.956649] pstate: a0400009 (NzCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[   19.957284] pc : gpio_device_find+0x58/0x160
[   19.957692] lr : gpio_device_find+0x38/0x160
[   19.958094] sp : ffff80008024b810
[   19.958401] x29: ffff80008024b810 x28: 0000000000000001 x27: ffffde478c23e248
[   19.959063] x26: 0000000000000000 x25: ffffffffffffefff x24: ffffde478b48ba98
[   19.959722] x23: 0000000000000000 x22: ffff80008024b868 x21: ffffde478ce630a8
[   19.960380] x20: ffff0001ff04bee8 x19: fffffffffffffc40 x18: 000000000000000a
[   19.961038] x17: 0000000082a13c1f x16: ffff000100356490 x15: 0000000000000000
[   19.961696] x14: 0000000000000000 x13: ffffde478cdd4838 x12: ffff8000810c0000
[   19.962353] x11: ffff8000812c0000 x10: ffff21b977a41118 x9 : ffffde478b4856c0
[   19.963012] x8 : 0101010101010101 x7 : 000000000000001a x6 : 0000000000000000
[   19.963670] x5 : ffffde478cbed940 x4 : 0000000000000001 x3 : ffff21ba6a799000
[   19.964328] x2 : ffff000100935000 x1 : 0000000100000000 x0 : 0000000000000000
[   19.964988] Call trace:
[   19.965223]  gpio_device_find+0x58/0x160 (P)
[   19.965633]  of_get_named_gpiod_flags+0xf4/0x3a0
[   19.966070]  of_find_gpio+0x90/0x1b0
[   19.966412]  gpiod_find_by_fwnode+0x148/0x208
[   19.966822]  gpiod_find_and_request+0xa0/0x4b0
[   19.967239]  gpiod_get_index+0x60/0x90
[   19.967593]  devm_gpiod_get_index+0x28/0xa0
[   19.967985]  devm_gpiod_get_optional+0x20/0x48
[   19.968400]  rockchip_pcie_probe+0xa4/0x588
[   19.968800]  platform_probe+0x64/0xc0
[   19.969152]  really_probe+0xc8/0x3a0
[   19.969493]  __driver_probe_device+0x84/0x160
[   19.969902]  driver_probe_device+0x48/0x130
[   19.970295]  __device_attach_driver+0xc4/0x178
[   19.970714]  bus_for_each_drv+0x90/0xf8
[   19.971077]  __device_attach+0xa4/0x1c8
[   19.971440]  device_initial_probe+0x1c/0x38
[   19.971833]  bus_probe_device+0xa8/0xc0
[   19.972195]  deferred_probe_work_func+0xb8/0x120
[   19.972627]  process_one_work+0x170/0x3e0
[   19.973008]  worker_thread+0x25c/0x390
[   19.973362]  kthread+0x148/0x240
[   19.973678]  ret_from_fork+0x10/0x20
[   19.974030] Code: d10f0273 a9046bf9 92820019 d503201f (f9401e60)
[   19.974593] ---[ end trace 0000000000000000 ]---
```

it then gets followed by several other call traces, see f.e. here:
https://paste.sr.ht/~diederik/619211a270f27fca4fbf9438ac2bbfcc8401f47d

I also did a test where I removed the PCIe card from the PCIe slot (and
disabled any references to my USB drive), but still got the crash.

But booting the latest 'bisect kernel', thus based on this commit:
636f4618b1cd ("regulator: fixed: fix GPIO descriptor leak on register failure")

gave a different call trace and landed me in the initramfs:

```
...
[    7.764336] rk_gmac-dwmac fe010000.ethernet: IRQ eth_lpi not found
[    7.764948] rk_gmac-dwmac fe010000.ethernet: IRQ sfty not found
[    7.775498] dwmmc_rockchip fe2c0000.mmc: IDMAC supports 32-bit address mode.
[    7.776396] dwmmc_rockchip fe2c0000.mmc: Using internal DMA controller.
[    7.777013] dwmmc_rockchip fe2c0000.mmc: Version ID is 270a
[    7.777573] dwmmc_rockchip fe2c0000.mmc: DW MMC controller at irq 67,32 bit host data width,256 deep fifo
[    8.031099] rk_gmac-dwmac fe010000.ethernet: IRQ eth_lpi not found
[    8.032588] rk_gmac-dwmac fe010000.ethernet: IRQ sfty not found
[    8.041752] rockchip-drm display-subsystem: bound fe040000.vop (ops vop2_component_ops [rockchipdrm])
[    8.053961] dwmmc_rockchip fe2c0000.mmc: IDMAC supports 32-bit address mode.
[    8.054694] dwmmc_rockchip fe2c0000.mmc: Using internal DMA controller.
[    8.055310] dwmmc_rockchip fe2c0000.mmc: Version ID is 270a
[    8.055949] dwmmc_rockchip fe2c0000.mmc: DW MMC controller at irq 67,32 bit host data width,256 deep fifo
[    8.177729] fan53555-regulator 0-001c: FAN53555 Option[12] Rev[15] Detected!
[    8.190700] rk_gmac-dwmac fe010000.ethernet: IRQ eth_lpi not found
[    8.191317] rk_gmac-dwmac fe010000.ethernet: IRQ sfty not found
[    8.247794] rockchip-drm display-subsystem: bound fe040000.vop (ops rockchip_drm_fini [rockchipdrm])
[    8.307337] dwmmc_rockchip fe2c0000.mmc: IDMAC supports 32-bit address mode.
[    8.308195] dwmmc_rockchip fe2c0000.mmc: Using internal DMA controller.
[    8.308820] dwmmc_rockchip fe2c0000.mmc: Version ID is 270a
[    8.309384] dwmmc_rockchip fe2c0000.mmc: DW MMC controller at irq 67,32 bit host data width,256 deep fifo
[    8.513425] rk808-rtc rk808-rtc.4.auto: registered as rtc0
[    8.517302] rk_gmac-dwmac fe010000.ethernet: IRQ eth_lpi not found
[    8.517922] rk_gmac-dwmac fe010000.ethernet: IRQ sfty not found
[    8.520914] rk808-rtc rk808-rtc.4.auto: setting system clock to 2025-12-04T10:30:22 UTC (1764844222)
[    8.539869] rockchip-drm display-subsystem: bound fe040000.vop (ops rockchip_drm_fini [rockchipdrm])
[    8.554583] dwmmc_rockchip fe2c0000.mmc: IDMAC supports 32-bit address mode.
[    8.555321] dwmmc_rockchip fe2c0000.mmc: Using internal DMA controller.
[    8.556030] dwmmc_rockchip fe2c0000.mmc: Version ID is 270a
[    8.556546] rk_gmac-dwmac fe010000.ethernet: IRQ eth_lpi not found
[    8.556598] dwmmc_rockchip fe2c0000.mmc: DW MMC controller at irq 67,32 bit host data width,256 deep fifo
[    8.557114] rk_gmac-dwmac fe010000.ethernet: IRQ sfty not found
[    8.559859] rk_gmac-dwmac fe010000.ethernet: clock input or output? (input).
[    8.560546] rk_gmac-dwmac fe010000.ethernet: TX delay(0x30).
[    8.561075] rk_gmac-dwmac fe010000.ethernet: RX delay(0x10).
[    8.561616] rk_gmac-dwmac fe010000.ethernet: integrated PHY? (no).
[    8.562256] rk_gmac-dwmac fe010000.ethernet: clock input from PHY
[    8.569953] rk_gmac-dwmac fe010000.ethernet: init for RGMII
[    8.571077] rk_gmac-dwmac fe010000.ethernet: User ID: 0x30, Synopsys ID: 0x51
[    8.571847] rk_gmac-dwmac fe010000.ethernet:         DWMAC4/5
[    8.572341] rk_gmac-dwmac fe010000.ethernet: DMA HW capability register supported
[    8.573032] rk_gmac-dwmac fe010000.ethernet: RX Checksum Offload Engine supported
[    8.573719] rk_gmac-dwmac fe010000.ethernet: TX Checksum insertion supported
[    8.574362] rk_gmac-dwmac fe010000.ethernet: Wake-Up On Lan supported
[    8.575119] rk_gmac-dwmac fe010000.ethernet: TSO supported
[    8.575687] rk_gmac-dwmac fe010000.ethernet: Enable RX Mitigation via HW Watchdog Timer
[    8.576429] rk_gmac-dwmac fe010000.ethernet: Enabled RFS Flow TC (entries=10)
[    8.577088] rk_gmac-dwmac fe010000.ethernet: TSO feature enabled
[    8.577640] rk_gmac-dwmac fe010000.ethernet: Using 32/32 bits DMA host/device width
[    8.581607] Unable to handle kernel paging request at virtual address 02ff342760bfa000
[    8.582364] Mem abort info:
[    8.582630]   ESR = 0x0000000096000004
[    8.582979]   EC = 0x25: DABT (current EL), IL = 32 bits
[    8.583465]   SET = 0, FnV = 0
[    8.583806]   EA = 0, S1PTW = 0
[    8.584107]   FSC = 0x04: level 0 translation fault
[    8.584556] Data abort info:
[    8.584825]   ISV = 0, ISS = 0x00000004, ISS2 = 0x00000000
[    8.585326]   CM = 0, WnR = 0, TnD = 0, TagAccess = 0
[    8.585790]   GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
[    8.586276] [02ff342760bfa000] address between user and kernel address ranges
[    8.586924] Internal error: Oops: 0000000096000004 [#1]  SMP
[    8.587444] Modules linked in: rk808_regulator(+) rk817_charger rtc_rk808 fan53555 rockchipdrm dw_hdmi_qp dw_mipi_dsi dw_hdmi analogix_dp drm_dp_aux_bus drm_display_helper dwmac_rk gpio_
rockchip stmmac_platform cec fixed display_connector stmmac rc_core drm_client_lib pcs_xpcs sdhci_of_dwcmshc drm_dma_helper phylink sdhci_pltfm dwc3 drm_kms_helper ehci_platform sdhci phy_r
ockchip_inno_usb2 mdio_devres pl330 dw_mmc_rockchip ohci_platform cqhci dw_wdt ehci_hcd ohci_hcd udc_core phy_rockchip_naneng_combphy dw_mmc_pltfm of_mdio rockchip_dfi dw_mmc fixed_phy drm
usbcore fwnode_mdio io_domain ulpi i2c_rk3x libphy usb_common mdio_bus
[    8.592659] CPU: 1 UID: 0 PID: 119 Comm: kworker/u16:4 Not tainted 6.18.0-rc4+ #9 PREEMPTLAZY
[    8.593452] Hardware name: Pine64 Quartz64 Model A (DT)
[    8.593935] Workqueue: events_unbound deferred_probe_work_func
[    8.594499] pstate: 80400009 (Nzcv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[    8.595139] pc : __srcu_read_lock+0x38/0x98
[    8.595539] lr : gpio_device_find+0x6c/0x160
[    8.595950] sp : ffff800080e4b5a0
[    8.596260] x29: ffff800080e4b5a0 x28: 0000000000000001 x27: ffffcbda959ecd50
[    8.596926] x26: 0000000000000000 x25: ffffffffffffefff x24: ffffcbdaa8277338
[    8.597588] x23: 0000000000000000 x22: ffff800080e4b618 x21: ffffcbdaa9671d28
[    8.598248] x20: ffffffffff600448 x19: ffffffffff600030 x18: 000000000000000a
[    8.598908] x17: 0000000072de8d8d x16: ffffcbdaa8276e90 x15: 5f454c4249544150
[    8.599569] x14: 0000000000000000 x13: 3d4d554e51455300 x12: ffffcbdaa99571c0
[    8.600230] x11: 0000000000000000 x10: ffff3426602357e0 x9 : ffffcbdaa8270f94
[    8.600894] x8 : 0101010101010101 x7 : 0000000000736c6c x6 : 0000000000000000
[    8.601558] x5 : 030000000b050000 x4 : 0000000000000001 x3 : ffff342755baa000
[    8.602223] x2 : ffff000104ec2680 x1 : 02ff342760bfa000 x0 : ffffffffff600448
[    8.602885] Call trace:
[    8.603123]  __srcu_read_lock+0x38/0x98 (P)
[    8.603531]  gpio_device_find+0x6c/0x160
[    8.603913]  of_get_named_gpiod_flags+0xf4/0x3a0
[    8.604353]  of_find_gpio+0x90/0x1b0
[    8.604698]  gpiod_find_by_fwnode+0x148/0x208
[    8.605111]  gpiod_find_and_request+0xa0/0x4b0
[    8.605529]  gpiod_get_index+0x60/0x90
[    8.605883]  devm_gpiod_get_index+0x28/0xa0
[    8.606276]  devm_gpiod_get_optional+0x20/0x48
[    8.606691]  stmmac_mdio_reset+0x64/0x180 [stmmac]
[    8.607260]  __mdiobus_register+0x17c/0x460 [libphy]
[    8.607784]  __of_mdiobus_register+0xb8/0x240 [of_mdio]
[    8.608277]  stmmac_mdio_register+0x174/0x600 [stmmac]
[    8.608824]  stmmac_dvr_probe+0xb00/0xf40 [stmmac]
[    8.609315]  rk_gmac_probe+0x598/0x620 [dwmac_rk]
[    8.609773]  platform_probe+0x64/0xc0
[    8.610140]  really_probe+0xc8/0x3a0
[    8.610484]  __driver_probe_device+0x84/0x160
[    8.610896]  driver_probe_device+0x48/0x130
[    8.611292]  __device_attach_driver+0xc4/0x178
[    8.611710]  bus_for_each_drv+0x90/0xf8
[    8.612075]  __device_attach+0xa4/0x1c8
[    8.612439]  device_initial_probe+0x1c/0x38
[    8.612832]  bus_probe_device+0xa8/0xc0
[    8.613196]  deferred_probe_work_func+0xb8/0x120
[    8.613629]  process_one_work+0x170/0x3e0
[    8.614011]  worker_thread+0x25c/0x390
[    8.614365]  kthread+0x148/0x240
[    8.614678]  ret_from_fork+0x10/0x20
[    8.615029] Code: d2800024 aa0503e1 d53cd043 8b030021 (f824003f)
[    8.615592] ---[ end trace 0000000000000000 ]---
[    8.616085] note: kworker/u16:4[119] exited with preempt_count 1
[    8.625817] boost: Bringing 4700000uV into 5000000-5000000uV
Begin: Loading essential drivers ... done.
Begin: Running /scripts/init-premount ... done.
Begin: Mounting root file system ... Begin: Running /scripts/local-top ... done.
Begin: Running /scripts/local-premount ... done.
Begin: Waiting for root file system ... Begin: Running /scripts/local-block ... done.
Begin: Running /scripts/local-block ... done.
Begin: Running /scripts/local-block ... done.
Begin: Running /scripts/local-block ... done.
...
```

If you want/need more info, just ask.

Cheers,
  Diederik


From krzk at kernel.org  Thu Dec  4 04:02:00 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 4 Dec 2025 13:02:00 +0100
Subject: [PATCH v2 3/3] ARM: samsung: exynos5250: Allow CPU1 to boot
In-Reply-To: <aTF2z5HbvmEuu9Iy@duo.ucw.cz>
References: <20251125-google-manta-v2-0-0f097cfff39c@timmermann.space>
 <20251125-google-manta-v2-3-0f097cfff39c@timmermann.space>
 <aTFvBwjms8msxIae@duo.ucw.cz>
 <73efeaeb-0cde-45af-af92-4fd7b5d4589c@kernel.org>
 <aTF2H0f9TJiwCLe5@duo.ucw.cz>
 <a68ee81f-1d2c-47f4-b86f-e0e803c1cfd3@kernel.org>
 <aTF2z5HbvmEuu9Iy@duo.ucw.cz>
Message-ID: <39ac918c-0394-495b-b717-dfa0fd35d7dc@kernel.org>

On 04/12/2025 12:55, Pavel Machek wrote:
> On Thu 2025-12-04 12:54:03, Krzysztof Kozlowski wrote:
>> On 04/12/2025 12:53, Pavel Machek wrote:
>>> On Thu 2025-12-04 12:51:36, Krzysztof Kozlowski wrote:
>>>> On 04/12/2025 12:22, Pavel Machek wrote:
>>>>> Also please cc: phone-devel mailing list with phone related patches.
>>>>
>>>> You don't have to. This list is not part of any upstream Linux kernel
>>>> process (see `git grep`), it's not relevant to upstream kernel development.
>>>
>>> Yes, you should. Its a relevant mailing list.
>>
>> git grep for it. Stop inventing rules.
> 
> Who is inventing rules here? Stop sabotaging review process.

You invented rule that some specific list of your interest has to be
CCed, even though no one knows about that list and it is nowhere documented.

> 
> "Many kernel-related lists are hosted on vger.kernel.org; you can find a
> list of them at http://vger.kernel.org/vger-lists.html.  There are
> kernel-related lists hosted elsewhere as well, though."

This proves nothing. There are just some lists there. No one has to cc
whatever list there just because Pavel Machek asks them. Kernel process
defines it or not. Not you.


Best regards,
Krzysztof


From maz at kernel.org  Thu Dec  4 04:02:46 2025
From: maz at kernel.org (Marc Zyngier)
Date: Thu, 04 Dec 2025 12:02:46 +0000
Subject: [PATCH v3 1/9] arm64: Repaint ID_AA64MMFR2_EL1.IDS description
In-Reply-To: <d546725b-e96f-461e-887d-8679cf747c7d@arm.com>
References: <20251204094806.3846619-1-maz@kernel.org>
	<20251204094806.3846619-2-maz@kernel.org>
	<b98c154a-1658-4501-bfa5-a93303aa5b3f@arm.com>
	<86cy4uplo5.wl-maz@kernel.org>
	<d546725b-e96f-461e-887d-8679cf747c7d@arm.com>
Message-ID: <86bjkepi8p.wl-maz@kernel.org>

On Thu, 04 Dec 2025 11:13:41 +0000,
Ben Horgan <ben.horgan at arm.com> wrote:
> 
> Hi Marc,
> 
> On 12/4/25 10:48, Marc Zyngier wrote:
> > On Thu, 04 Dec 2025 10:36:54 +0000,
> > Ben Horgan <ben.horgan at arm.com> wrote:
> >>
> >> Hi Marc,
> >>
> >> On 12/4/25 09:47, Marc Zyngier wrote:
> >>> ID_AA64MMFR2_EL1.IDS, as described in the sysreg file, is pretty horrible
> >>> as it diesctly give the ESR value. Repaint it using the usual NI/IMP
> >>> identifiers to describe the absence/presence of FEAT_IDST.
> >>>
> >>> Signed-off-by: Marc Zyngier <maz at kernel.org>
> >>> ---
> >>>  arch/arm64/kvm/hyp/nvhe/sys_regs.c | 2 +-
> >>>  arch/arm64/tools/sysreg            | 4 ++--
> >>>  2 files changed, 3 insertions(+), 3 deletions(-)
> >>>
> >>> diff --git a/arch/arm64/kvm/hyp/nvhe/sys_regs.c b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
> >>> index 82da9b03692d4..107d62921b168 100644
> >>> --- a/arch/arm64/kvm/hyp/nvhe/sys_regs.c
> >>> +++ b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
> >>> @@ -134,7 +134,7 @@ static const struct pvm_ftr_bits pvmid_aa64mmfr2[] = {
> >>>  	MAX_FEAT(ID_AA64MMFR2_EL1, UAO, IMP),
> >>>  	MAX_FEAT(ID_AA64MMFR2_EL1, IESB, IMP),
> >>>  	MAX_FEAT(ID_AA64MMFR2_EL1, AT, IMP),
> >>> -	MAX_FEAT_ENUM(ID_AA64MMFR2_EL1, IDS, 0x18),
> >>> +	MAX_FEAT_ENUM(ID_AA64MMFR2_EL1, IDS, IMP),
> >>>  	MAX_FEAT(ID_AA64MMFR2_EL1, TTL, IMP),
> >>>  	MAX_FEAT(ID_AA64MMFR2_EL1, BBM, 2),
> >>>  	MAX_FEAT(ID_AA64MMFR2_EL1, E0PD, IMP),
> >>> diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
> >>> index 1c6cdf9d54bba..3261e8791ac03 100644
> >>> --- a/arch/arm64/tools/sysreg
> >>> +++ b/arch/arm64/tools/sysreg
> >>> @@ -2257,8 +2257,8 @@ UnsignedEnum	43:40	FWB
> >>>  	0b0001	IMP
> >>>  EndEnum
> >>>  Enum	39:36	IDS
> >>
> >> Should this also be changed to an UnsignedEnum?
> > 
> > I'm not sure this brings much when you only have two values. If IDS
> > was growing a third value, and that there was an actual order in the
> > numbering scheme, then yes, that'd be useful.
> 
> Joey just pointed out to me that there is a new third field. Not in the
> arm reference manual yet, but mentioned in the xml. I'm unsure if it's
> necessary to consider this at the moment though.
> 
> https://developer.arm.com/documentation/ddi0601/2025-09/AArch64-Registers/ID-AA64MMFR2-EL1--AArch64-Memory-Model-Feature-Register-2?lang=en

Ah, nice catch. In which case I agree that this should become
UnsignedEnum, as the new EL3 feature is a strict superset of 0b0001.

I'll add fix for that on top.

Thanks,

	M.

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


From andriy.shevchenko at linux.intel.com  Thu Dec  4 04:04:33 2025
From: andriy.shevchenko at linux.intel.com (Andy Shevchenko)
Date: Thu, 4 Dec 2025 14:04:33 +0200
Subject: [PATCH v4 01/29] Revert "treewide: Fix probing of devices in DT
 overlays"
In-Reply-To: <20251204083839.4fb8a4b1@bootlin.com>
References: <5cf2a12a-7c66-4622-b4a9-14896c6df005@gmail.com>
 <CAL_JsqJjm12LxpDg6LmpY=Ro_keHwnrWiYMLVnG=s_pSP4X2WQ@mail.gmail.com>
 <072dde7c-a53c-4525-83ac-57ea38edc0b5@gmail.com>
 <CAL_JsqKyG98pXGKpL=gxSc92izpzN7YCdq62ZJByhE6aFYs1fw@mail.gmail.com>
 <55076f4b-d523-4f8c-8bd4-0645b790737e@gmail.com>
 <20251202102619.5cd971cc@bootlin.com>
 <088af3ff-bd04-4bc9-b304-85f6ed555f2a@gmail.com>
 <20251202175836.747593c0@bootlin.com>
 <dc813fc2-28d2-4f2c-a2a3-08e33eec8ec7@gmail.com>
 <20251204083839.4fb8a4b1@bootlin.com>
Message-ID: <aTF40eLT2YTB8OoO@smile.fi.intel.com>

On Thu, Dec 04, 2025 at 08:38:39AM +0100, Herve Codina wrote:
> On Wed, 3 Dec 2025 12:11:45 +0200
> Kalle Niemi <kaleposti at gmail.com> wrote:

...

> Saravana's email (Saravana Kannan <saravanak at google.com>) seems incorrect.
> Got emails delivery failure with this email address.

According to the Git history his last activity was in August 2025 with
adding (surprise) his name to one of the MAINTAINERS records.

And according to lore, his last message was in October 2025, so I dunno
what's going on there.

-- 
With Best Regards,
Andy Shevchenko




From mark.rutland at arm.com  Thu Dec  4 04:04:42 2025
From: mark.rutland at arm.com (Mark Rutland)
Date: Thu, 4 Dec 2025 12:04:42 +0000
Subject: Alternative to arm64.nopauth cmdline for disabling Pointer
 Authentication
In-Reply-To: <adc22b19-7dcc-4c38-9319-d979f1e3886a@quicinc.com>
References: <3fcf6614-ee83-4a06-9024-83573b2e642e@quicinc.com>
 <86ecpappzi.wl-maz@kernel.org>
 <adc22b19-7dcc-4c38-9319-d979f1e3886a@quicinc.com>
Message-ID: <aTF42v5dpTuCe7r3@J2N7QTR9R3>

Hi Pavan, Marc,

On Thu, Dec 04, 2025 at 04:06:12PM +0530, Pavan Kondeti wrote:
> On Thu, Dec 04, 2025 at 09:15:29AM +0000, Marc Zyngier wrote:
> > On Thu, 04 Dec 2025 04:07:15 +0000,
> > Pavan Kondeti <pavan.kondeti at oss.qualcomm.com> wrote:
> > > Hi
> > > 
> > > The pointer authentication feature (PAuth) is only supported on
> > > 0-3 CPUs but it is not supported on 4-7 CPUS on QCS8300.

> > On what grounds? Hardware incompatibility? I seriously doubt it,
> > since nobody glues pre-8.3 CPUs to anything more modern.

Marc, it seems like that's exactly that's happened here. :/

> I see that Linux runs at EL2 and AA64ISAR1 register values on CPU#0
> (A78) indicates that PAuth is supported but not for CPU#4 (A55). I am
> told, there are no other controls outside EL2 (trap) to manipulate
> this feature. So, I am assuming that this is indeed reflecting the HW.

Cortex-A78 doesn't have pointer authentication, but Cortex-A78C does, so
maybe you actually have Cortex-A78C?

What are the MIDRs on this SoC? e.g. the output of:

  cat /sys/devices/system/cpu/cpu*/regs/identification/midr_el1 | sort | uniq

If this SoC has both Cortex-A78C and Cortex-A55, that's a rather
unfortunate combination that should have been caught at the SoC design
phase, as Marc alluded to.

[...]

> > > This patch [2] from Catalin adds a devicetree property under memory {}
> > > to disable MTE.

Catalin's patch was a bit different. It described whether the memory
range supported tags (and was actually a property of the memory). That
patch didn't make it into mainline AFAICT.

[...]

> I understand that this does not fall under errata but is
> there a possiblity to introduce an Errata targeting CPU#0 MIDR and
> disabling the Pointer authentication? I understand that if there is
> another Qualcomm SoC that exists with all CPUs supporting pointer
> authentication with same MIDR, we may be disabling the feature but this
> is something I can check internally.

I strongly suspect we cannot use the MIDR for this. Per:

  https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=53a52a0ec7680287b170b36488203b5822e6da2d

... Qualcomm's Kryo {Prime,Gold,Silver} parts seem to identify
themselves as Arm ltd implementations, and those will appear in other
non-Qualcomm SoCs.

Without know *exactly* which MIDRs you have on this part, we cannot say.

Regardless, I strongly suspect that we have to live with the command
line option for these parts.

Mark.


From maz at kernel.org  Thu Dec  4 04:06:04 2025
From: maz at kernel.org (Marc Zyngier)
Date: Thu, 04 Dec 2025 12:06:04 +0000
Subject: [PATCH v3 8/9] KVM: arm64: pkvm: Report optional ID register traps with a 0x18 syndrome
In-Reply-To: <7f853a85-f1da-4e6f-ab3f-63507731f8ee@arm.com>
References: <20251204094806.3846619-1-maz@kernel.org>
	<20251204094806.3846619-9-maz@kernel.org>
	<7f853a85-f1da-4e6f-ab3f-63507731f8ee@arm.com>
Message-ID: <86a4zypi37.wl-maz@kernel.org>

On Thu, 04 Dec 2025 10:51:19 +0000,
Ben Horgan <ben.horgan at arm.com> wrote:
> 
> Hi Marc,
> 
> On 12/4/25 09:48, Marc Zyngier wrote:
> > With FEAT_IDST, unimplemented system registers in the feature ID space
> > must be reported using EC=0x18 at the closest handling EL, rather than
> > with an UNDEF.
> > 
> > Most of these system registers are always implemented thanks to their
> > dependency on FEAT_AA64, except for a set of (currently) three registers:
> > GMID_EL1 (depending on MTE2), CCSIDR2_EL1 (depending on FEAT_CCIDX),
> > and SMIDR_EL1 (depending on SME).
> > 
> > For these three registers, report their trap as EC=0x18 if they
> > end-up trapping into KVM and that FEAT_IDST is implemented in the guest.
> > Otherwise, just make them UNDEF.
> > 
> > Signed-off-by: Marc Zyngier <maz at kernel.org>
> > ---
> >  arch/arm64/kvm/hyp/nvhe/sys_regs.c | 15 +++++++++++++++
> >  1 file changed, 15 insertions(+)
> > 
> > diff --git a/arch/arm64/kvm/hyp/nvhe/sys_regs.c b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
> > index 876b36d3d4788..efc36645f4b5a 100644
> > --- a/arch/arm64/kvm/hyp/nvhe/sys_regs.c
> > +++ b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
> > @@ -347,6 +347,18 @@ static bool pvm_gic_read_sre(struct kvm_vcpu *vcpu,
> >  	return true;
> >  }
> >  
> > +static bool pvm_idst_access(struct kvm_vcpu *vcpu,
> > +			    struct sys_reg_params *p,
> > +			    const struct sys_reg_desc *r)
> > +{
> > +	if (kvm_has_feat_enum(vcpu->kvm, ID_AA64MMFR2_EL1, IDS, NI))
> > +		inject_undef64(vcpu);
> > +	else
> > +		inject_sync64(vcpu, kvm_vcpu_get_esr(vcpu));
> > +
> > +	return false;
> > +}
> > +
> 
> Just wondering, why is the pkvm version register specific? You changed
> the non-pkvm from register specific to generic.

Because pKVM relies on a full enumeration of the registers as a design
principle, and refrains from having wide-casting nets as a catch-all.

That's to ensure that there is a "surprise trap" always results in an
UNDEF. Different model from the rest of KVM.

Thanks,

	M.

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


From anshuman.khandual at arm.com  Thu Dec  4 04:08:05 2025
From: anshuman.khandual at arm.com (Anshuman Khandual)
Date: Thu, 4 Dec 2025 17:38:05 +0530
Subject: [PATCH 01/19] coresight: trbe: Use helpers for checking errata
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-1-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-1-7da32b076b28@arm.com>
Message-ID: <9440a191-86af-4eea-b867-8f65131bd701@arm.com>

On 01/12/25 4:51 PM, Leo Yan wrote:
> Use the existed helpers for checking errata instead of open coded

Small nit - s/the existed helpers/the existing helpers/

> equivalent.> 
> Signed-off-by: Leo Yan <leo.yan at arm.com>
> ---
>  drivers/hwtracing/coresight/coresight-trbe.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
> index 293715b4ff0eb0abe30f9b477700ca94f81cd4a2..0ddb3db0213cf0014e29decfb79da68b0a351b31 100644
> --- a/drivers/hwtracing/coresight/coresight-trbe.c
> +++ b/drivers/hwtracing/coresight/coresight-trbe.c
> @@ -723,7 +723,7 @@ static unsigned long trbe_get_trace_size(struct perf_output_handle *handle,
>  	 * the space we skipped with IGNORE packets. And we are always
>  	 * guaranteed to have at least a PAGE_SIZE space in the buffer.
>  	 */
> -	if (trbe_has_erratum(buf->cpudata, TRBE_WORKAROUND_OVERWRITE_FILL_MODE) &&
> +	if (trbe_may_overwrite_in_fill_mode(buf->cpudata) &&
>  	    !WARN_ON(size < overwrite_skip))
>  		__trbe_pad_buf(buf, start_off, overwrite_skip);
>  
> @@ -946,7 +946,7 @@ static int trbe_apply_work_around_before_enable(struct trbe_buf *buf)
>  	 *  - At trace collection:
>  	 *     - Pad the 256bytes skipped above again with IGNORE packets.
>  	 */
> -	if (trbe_has_erratum(buf->cpudata, TRBE_WORKAROUND_OVERWRITE_FILL_MODE)) {
> +	if (trbe_may_overwrite_in_fill_mode(buf->cpudata)) {
>  		if (WARN_ON(!IS_ALIGNED(buf->trbe_write, PAGE_SIZE)))
>  			return -EINVAL;
>  		buf->trbe_hw_base = buf->trbe_write;
> @@ -970,7 +970,7 @@ static int trbe_apply_work_around_before_enable(struct trbe_buf *buf)
>  	 *     - Adjust the TRBLIMITR.LIMIT to leave the extra PAGE outside
>  	 *       the TRBE's range (i.e [TRBBASER, TRBLIMITR.LIMI] ).
>  	 */
> -	if (trbe_has_erratum(buf->cpudata, TRBE_WORKAROUND_WRITE_OUT_OF_RANGE)) {
> +	if (trbe_may_write_out_of_range(buf->cpudata)) {
>  		s64 space = buf->trbe_limit - buf->trbe_write;
>  		/*
>  		 * We must have more than a PAGE_SIZE worth space in the proposed
> 

LGTM

Reviewed-by: Anshuman Khandual <anshuman.khandual at arm.com>


From anshuman.khandual at arm.com  Thu Dec  4 04:25:03 2025
From: anshuman.khandual at arm.com (Anshuman Khandual)
Date: Thu, 4 Dec 2025 17:55:03 +0530
Subject: [PATCH 02/19] coresight: trbe: Remove redundant disable operation
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-2-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-2-7da32b076b28@arm.com>
Message-ID: <26841df4-04d5-45d6-b589-e6061db2ad33@arm.com>



On 01/12/25 4:51 PM, Leo Yan wrote:
> The trace unit is already disabled when trbe_stop_and_truncate_event()
> is called, so draining and stopping the buffer in the function is
> redundant.
> 
> Remove the unnecessary disable operation and rename the function to
> trbe_truncate_event() to better reflect its purpose.
> 
> Signed-off-by: Leo Yan <leo.yan at arm.com>
> ---
>  drivers/hwtracing/coresight/coresight-trbe.c | 14 +++-----------
>  1 file changed, 3 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
> index 0ddb3db0213cf0014e29decfb79da68b0a351b31..2f44e4a65e0ee2b2c8fdd06a51ab01fc57f44a4e 100644
> --- a/drivers/hwtracing/coresight/coresight-trbe.c
> +++ b/drivers/hwtracing/coresight/coresight-trbe.c
> @@ -284,18 +284,10 @@ static void trbe_report_wrap_event(struct perf_output_handle *handle)
>  	perf_aux_output_flag(handle, PERF_AUX_FLAG_COLLISION);
>  }
>  
> -static void trbe_stop_and_truncate_event(struct perf_output_handle *handle)
> +static void trbe_truncate_event(struct perf_output_handle *handle)
>  {
>  	struct trbe_buf *buf = etm_perf_sink_config(handle);
>  
> -	/*
> -	 * We cannot proceed with the buffer collection and we
> -	 * do not have any data for the current session. The
> -	 * etm_perf driver expects to close out the aux_buffer
> -	 * at event_stop(). So disable the TRBE here and leave
> -	 * the update_buffer() to return a 0 size.
> -	 */
> -	trbe_drain_and_disable_local(buf->cpudata);
>  	perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED);
>  	perf_aux_output_end(handle, 0);
>  	*this_cpu_ptr(buf->cpudata->drvdata->handle) = NULL;
> @@ -1008,7 +1000,7 @@ static int __arm_trbe_enable(struct trbe_buf *buf,
>  	trbe_enable_hw(buf);
>  	return 0;
>  err:
> -	trbe_stop_and_truncate_event(handle);
> +	trbe_truncate_event(handle);
>  	return ret;
>  }
>  
> @@ -1169,7 +1161,7 @@ static irqreturn_t arm_trbe_irq_handler(int irq, void *dev)
>  		trbe_handle_spurious(handle);
>  		break;
>  	case TRBE_FAULT_ACT_FATAL:
> -		trbe_stop_and_truncate_event(handle);
> +		trbe_truncate_event(handle);
>  		truncated = true;
>  		break;
>  	}
> 

In arm_trbe_irq_handler() function trbe_drain_and_disable_local() is
called early on before TRBE_FAULT_ACT_FATAL gets handled but for the
other case __arm_trbe_enable() - do all the code paths leading upto
present trbe_stop_and_truncate_event() would have definitely called
trbe_drain_and_disable_local() as well ? If yes, please do call out
those code paths clearly in the commit message.

Besides it might be worth adding an WARN_ON() in trbe_truncate_event()
if the TRBE has not been disabled as now being expected there.


From pabeni at redhat.com  Thu Dec  4 04:26:11 2025
From: pabeni at redhat.com (Paolo Abeni)
Date: Thu, 4 Dec 2025 13:26:11 +0100
Subject: [PATCH] net: stmmac: fix oops when split header is enabled
In-Reply-To: <20251202025421.4560-1-jie.zhang@analog.com>
References: <20251202025421.4560-1-jie.zhang@analog.com>
Message-ID: <81491196-2872-4fd3-a1f3-f27ce0bb998b@redhat.com>


n 12/2/25 3:54 AM, Jie Zhang wrote:
> For GMAC4, when split header is enabled, in some rare cases, the
> hardware does not fill buf2 of the first descriptor with payload.
> Thus we cannot assume buf2 is always fully filled if it is not
> the last descriptor. Otherwise, the length of buf2 of the second
> descriptor will be calculated wrong and cause an oops:
> 
> Unable to handle kernel paging request at virtual address ffff00019246bfc0
> Mem abort info:
>   ESR = 0x0000000096000145
>   EC = 0x25: DABT (current EL), IL = 32 bits
>   SET = 0, FnV = 0
>   EA = 0, S1PTW = 0
>   FSC = 0x05: level 1 translation fault
> Data abort info:
>   ISV = 0, ISS = 0x00000145, ISS2 = 0x00000000
>   CM = 1, WnR = 1, TnD = 0, TagAccess = 0
>   GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
> swapper pgtable: 4k pages, 48-bit VAs, pgdp=0000000090d8b000
> [ffff00019246bfc0] pgd=180000009dfff403, p4d=180000009dfff403, pud=0000000000000000
> Internal error: Oops: 0000000096000145 [#1]  SMP
> Modules linked in:
> CPU: 0 UID: 0 PID: 157 Comm: iperf3 Not tainted 6.18.0-rc6 #1 PREEMPT
> Hardware name: ADI 64-bit SC598 SOM EZ Kit (DT)
> pstate: 00400009 (nzcv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
> pc : dcache_inval_poc+0x28/0x58
> lr : arch_sync_dma_for_cpu+0x28/0x34
> sp : ffff800080dcbc40
> x29: ffff800080dcbc40 x28: 0000000000000008 x27: ffff000091c50980
> x26: ffff000091c50980 x25: 0000000000000000 x24: ffff000092a5fb00
> x23: ffff000092768f28 x22: 000000009246c000 x21: 0000000000000002
> x20: 00000000ffffffdc x19: ffff000091844c10 x18: 0000000000000000
> x17: ffff80001d308000 x16: ffff800080dc8000 x15: ffff0000929fb034
> x14: 70f709157374dd21 x13: ffff000092812ec0 x12: 0000000000000000
> x11: 000000000000dd86 x10: 0000000000000040 x9 : 0000000000000600
> x8 : ffff000092a5fbac x7 : 0000000000000001 x6 : 0000000000004240
> x5 : 000000009246c000 x4 : ffff000091844c10 x3 : 000000000000003f
> x2 : 0000000000000040 x1 : ffff00019246bfc0 x0 : ffff00009246c000
> Call trace:
>  dcache_inval_poc+0x28/0x58 (P)
>  dma_direct_sync_single_for_cpu+0x38/0x6c
>  __dma_sync_single_for_cpu+0x34/0x6c
>  stmmac_napi_poll_rx+0x8f0/0xb60
>  __napi_poll.constprop.0+0x30/0x144
>  net_rx_action+0x160/0x274
>  handle_softirqs+0x1b8/0x1fc
>  __do_softirq+0x10/0x18
>  ____do_softirq+0xc/0x14
>  call_on_irq_stack+0x30/0x48
>  do_softirq_own_stack+0x18/0x20
>  __irq_exit_rcu+0x64/0xe8
>  irq_exit_rcu+0xc/0x14
>  el1_interrupt+0x3c/0x58
>  el1h_64_irq_handler+0x14/0x1c
>  el1h_64_irq+0x6c/0x70
>  __arch_copy_to_user+0xbc/0x240 (P)
>  simple_copy_to_iter+0x28/0x30
>  __skb_datagram_iter+0x1bc/0x268
>  skb_copy_datagram_iter+0x1c/0x24
>  tcp_recvmsg_locked+0x3ec/0x778
>  tcp_recvmsg+0x10c/0x194
>  inet_recvmsg+0x64/0xa0
>  sock_recvmsg_nosec+0x1c/0x24
>  sock_read_iter+0x8c/0xdc
>  vfs_read+0x144/0x1a0
>  ksys_read+0x74/0xdc
>  __arm64_sys_read+0x14/0x1c
>  invoke_syscall+0x60/0xe4
>  el0_svc_common.constprop.0+0xb0/0xcc
>  do_el0_svc+0x18/0x20
>  el0_svc+0x80/0xc8
>  el0t_64_sync_handler+0x58/0x134
>  el0t_64_sync+0x170/0x174
> Code: d1000443 ea03003f 8a230021 54000040 (d50b7e21)
> ---[ end trace 0000000000000000 ]---
> Kernel panic - not syncing: Oops: Fatal exception in interrupt
> Kernel Offset: disabled
> CPU features: 0x080000,00008000,08006281,0400520b
> Memory Limit: none
> ---[ end Kernel panic - not syncing: Oops: Fatal exception in interrupt ]---

Please avoid including the last 6 lines in the commit message, the '---'
separator could foul git when applying the patch and truncate the commit
message.
> To fix this, the PL bit-field in RDES3 register is used for all
> descriptors, whether it is the last descriptor or not.
> 
> Signed-off-by: Jie Zhang <jie.zhang at analog.com>
Looks like a fixes suitable for net; a fix tag is required and you should
include the target tree into the subj prefix, see:
https://elixir.bootlin.com/linux/v6.18/source/Documentation/process/maintainer-netdev.rst#L64The
patch does not apply to 'net' anymore, please rebase and resubmit. You
can retain Jacob's ack.

/P




From iuliana.prodan at oss.nxp.com  Thu Dec  4 04:28:23 2025
From: iuliana.prodan at oss.nxp.com (Iuliana Prodan (OSS))
Date: Thu,  4 Dec 2025 14:28:23 +0200
Subject: [PATCH v2 1/3] remoteproc: imx_dsp_rproc: Skip RP_MBOX_SUSPEND_SYSTEM when mailbox TX channel is uninitialized
Message-ID: <20251204122825.756106-1-iuliana.prodan@oss.nxp.com>

From: Iuliana Prodan <iuliana.prodan at nxp.com>

Firmwares that do not use mailbox communication (e.g., the hello_world
sample) leave priv->tx_ch as NULL. The current suspend logic
unconditionally sends RP_MBOX_SUSPEND_SYSTEM, which is invalid without
an initialized TX channel.

Detect the no_mailboxes case early and skip sending the suspend
message. Instead, proceed directly to the runtime PM suspend path,
which is the correct behavior for firmwares that cannot respond to
mailbox requests.

Signed-off-by: Iuliana Prodan <iuliana.prodan at nxp.com>
---
Changes since v1:
- Wrapped commit message to 75 characters
- Changed dev_err to dev_dbg since this case is normal behavior
---
 drivers/remoteproc/imx_dsp_rproc.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c
index 5130a35214c9..f51deaacc700 100644
--- a/drivers/remoteproc/imx_dsp_rproc.c
+++ b/drivers/remoteproc/imx_dsp_rproc.c
@@ -1242,6 +1242,15 @@ static int imx_dsp_suspend(struct device *dev)
 	if (rproc->state != RPROC_RUNNING)
 		goto out;
 
+	/*
+	 * No channel available for sending messages;
+	 * indicates no mailboxes present, so trigger PM runtime suspend
+	 */
+	if (!priv->tx_ch) {
+		dev_dbg(dev, "No initialized mbox tx channel, suspend directly.\n");
+		goto out;
+	}
+
 	reinit_completion(&priv->pm_comp);
 
 	/* Tell DSP that suspend is happening */
-- 
2.25.1



From iuliana.prodan at oss.nxp.com  Thu Dec  4 04:28:24 2025
From: iuliana.prodan at oss.nxp.com (Iuliana Prodan (OSS))
Date: Thu,  4 Dec 2025 14:28:24 +0200
Subject: [PATCH v2 2/3] remoteproc: imx_dsp_rproc: Rename macro to reflect multiple contexts
In-Reply-To: <20251204122825.756106-1-iuliana.prodan@oss.nxp.com>
References: <20251204122825.756106-1-iuliana.prodan@oss.nxp.com>
Message-ID: <20251204122825.756106-2-iuliana.prodan@oss.nxp.com>

From: Iuliana Prodan <iuliana.prodan at nxp.com>

Rename WAIT_FW_READY to WAIT_FW_CONFIRMATION and FEATURE_DONT_WAIT_FW_READY
to FEATURE_SKIP_FW_CONFIRMATION. This way, the term CONFIRMATION covers:
- waiting for firmware to confirm it is ready to start;
- waiting for any other confirmation from firmware.

Signed-off-by: Iuliana Prodan <iuliana.prodan at nxp.com>
---
Changes since v1:
- New commit
---
 drivers/remoteproc/imx_dsp_rproc.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c
index f51deaacc700..1f3a35756769 100644
--- a/drivers/remoteproc/imx_dsp_rproc.c
+++ b/drivers/remoteproc/imx_dsp_rproc.c
@@ -38,15 +38,15 @@ MODULE_PARM_DESC(no_mailboxes,
 
 /* Flag indicating that the remote is up and running */
 #define REMOTE_IS_READY				BIT(0)
-/* Flag indicating that the host should wait for a firmware-ready response */
-#define WAIT_FW_READY				BIT(1)
+/* Flag indicating that the host should wait for a firmware-confirmation response */
+#define WAIT_FW_CONFIRMATION				BIT(1)
 #define REMOTE_READY_WAIT_MAX_RETRIES		500
 
 /*
  * This flag is set in the DSP resource table's features field to indicate
- * that the firmware requires the host NOT to wait for a FW_READY response.
+ * that the firmware requires the host NOT to wait for a FW_CONFIRMATION response.
  */
-#define FEATURE_DONT_WAIT_FW_READY		BIT(0)
+#define FEATURE_SKIP_FW_CONFIRMATION		BIT(0)
 
 /* att flags */
 /* DSP own area */
@@ -287,7 +287,7 @@ static int imx_dsp_rproc_ready(struct rproc *rproc)
  * @avail: available space in the resource table
  *
  * Parse the DSP-specific resource entry and update flags accordingly.
- * If the WAIT_FW_READY feature is set, the host must wait for the firmware
+ * If the WAIT_FW_CONFIRMATION feature is set, the host must wait for the firmware
  * to signal readiness before proceeding with execution.
  *
  * Return: RSC_HANDLED if processed successfully, RSC_IGNORED otherwise.
@@ -322,7 +322,7 @@ static int imx_dsp_rproc_handle_rsc(struct rproc *rproc, u32 rsc_type,
 
 	/*
 	 * For now, in struct fw_rsc_imx_dsp, version 0,
-	 * only FEATURE_DONT_WAIT_FW_READY is valid.
+	 * only FEATURE_SKIP_FW_CONFIRMATION is valid.
 	 *
 	 * When adding new features, please upgrade version.
 	 */
@@ -332,8 +332,8 @@ static int imx_dsp_rproc_handle_rsc(struct rproc *rproc, u32 rsc_type,
 		return RSC_IGNORED;
 	}
 
-	if (imx_dsp_rsc->features & FEATURE_DONT_WAIT_FW_READY)
-		priv->flags &= ~WAIT_FW_READY;
+	if (imx_dsp_rsc->features & FEATURE_SKIP_FW_CONFIRMATION)
+		priv->flags &= ~WAIT_FW_CONFIRMATION;
 
 	return RSC_HANDLED;
 }
@@ -385,7 +385,7 @@ static int imx_dsp_rproc_start(struct rproc *rproc)
 		return ret;
 	}
 
-	if (priv->flags & WAIT_FW_READY)
+	if (priv->flags & WAIT_FW_CONFIRMATION)
 		return imx_dsp_rproc_ready(rproc);
 
 	return 0;
@@ -1131,8 +1131,8 @@ static int imx_dsp_rproc_probe(struct platform_device *pdev)
 	priv = rproc->priv;
 	priv->rproc = rproc;
 	priv->dsp_dcfg = dsp_dcfg;
-	/* By default, host waits for fw_ready reply */
-	priv->flags |= WAIT_FW_READY;
+	/* By default, host waits for fw_confirmation reply */
+	priv->flags |= WAIT_FW_CONFIRMATION;
 
 	if (no_mailboxes)
 		imx_dsp_rproc_mbox_init = imx_dsp_rproc_mbox_no_alloc;
-- 
2.25.1



From iuliana.prodan at oss.nxp.com  Thu Dec  4 04:28:25 2025
From: iuliana.prodan at oss.nxp.com (Iuliana Prodan (OSS))
Date: Thu,  4 Dec 2025 14:28:25 +0200
Subject: [PATCH v2 3/3] remoteproc: imx_dsp_rproc: Wait for suspend ACK only if WAIT_FW_CONFIRMATION is set
In-Reply-To: <20251204122825.756106-1-iuliana.prodan@oss.nxp.com>
References: <20251204122825.756106-1-iuliana.prodan@oss.nxp.com>
Message-ID: <20251204122825.756106-3-iuliana.prodan@oss.nxp.com>

From: Iuliana Prodan <iuliana.prodan at nxp.com>

The DSP suspend path currently waits unconditionally for a suspend ack
from the firmware. This breaks firmwares that do not implement the
mailbox-based CONFIRMATION handshake, as the DSP never responds and
system suspend fails with -EBUSY.

The driver already uses the WAIT_FW_CONFIRMATION flag to indicate that
the firmware supports the CONFIRMATION handshake at boot. Apply the same
logic during suspend: only send the suspend message and wait for the
suspend ack when the firmware is expected to support it.

Signed-off-by: Iuliana Prodan <iuliana.prodan at nxp.com>
---
Changes since v1:
- Moved confirmation check earlier to avoid sending the message when
FEATURE_SKIP_FW_CONFIRMATION is set, since RP_MBOX_SUSPEND_SYSTEM is
not handled on the remote side.
---
 drivers/remoteproc/imx_dsp_rproc.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c
index 1f3a35756769..d03017d6b214 100644
--- a/drivers/remoteproc/imx_dsp_rproc.c
+++ b/drivers/remoteproc/imx_dsp_rproc.c
@@ -1251,6 +1251,12 @@ static int imx_dsp_suspend(struct device *dev)
 		goto out;
 	}
 
+	/* No fw confirmation expected, so trigger PM runtime suspend */
+	if (!(priv->flags & WAIT_FW_CONFIRMATION)) {
+		dev_dbg(dev, "No FW_CONFIRMATION needed, suspend directly.\n");
+		goto out;
+	}
+
 	reinit_completion(&priv->pm_comp);
 
 	/* Tell DSP that suspend is happening */
-- 
2.25.1



From anshuman.khandual at arm.com  Thu Dec  4 04:31:53 2025
From: anshuman.khandual at arm.com (Anshuman Khandual)
Date: Thu, 4 Dec 2025 18:01:53 +0530
Subject: [PATCH 03/19] coresight: trbe: Remove buffer disabling in
 trbe_handle_overflow()
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-3-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-3-7da32b076b28@arm.com>
Message-ID: <92ab073c-c2fc-4218-a8c8-458a69619db7@arm.com>

On 01/12/25 4:51 PM, Leo Yan wrote:
> When trbe_handle_overflow() runs, the buffer has already been disabled
> and drained, so the duplicate operation is unnecessary.  Remove it.
> 
> Signed-off-by: Leo Yan <leo.yan at arm.com>
> ---
>  drivers/hwtracing/coresight/coresight-trbe.c | 1 -
>  1 file changed, 1 deletion(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
> index 2f44e4a65e0ee2b2c8fdd06a51ab01fc57f44a4e..f5597bd9b5fba9a8f5053d5823b03380fd468b5c 100644
> --- a/drivers/hwtracing/coresight/coresight-trbe.c
> +++ b/drivers/hwtracing/coresight/coresight-trbe.c
> @@ -1077,7 +1077,6 @@ static int trbe_handle_overflow(struct perf_output_handle *handle)
>  		 * is able to detect this with a disconnected handle
>  		 * (handle->event = NULL).
>  		 */
> -		trbe_drain_and_disable_local(buf->cpudata);
>  		*this_cpu_ptr(buf->cpudata->drvdata->handle) = NULL;
>  		return -EINVAL;
>  	}
> 

Like the previous patch - trbe_drain_and_disable_local() would have run
if TRBE_FAULT_ACT_WRAP case is being handled via trbe_handle_overflow().
But please do mention these details in the commit message for things to
be clear and explicit.

Reviewed-by: Anshuman Khandual <anshuman.khandual at arm.com>


From sudeep.holla at arm.com  Thu Dec  4 04:33:44 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Thu, 4 Dec 2025 12:33:44 +0000
Subject: [PATCH 1/2] dt-bindings: firmware: arm,scmi: Document
 arm,poll-transport property
In-Reply-To: <4ccbcffd-bcc7-478b-a525-a4a11e3092ee@mailbox.org>
References: <aPoxfH_TLrsMxMVQ@pluto>
 <70554674-7020-4582-a4e7-dbee34907096@mailbox.org>
 <5ae0a793-d3e7-45d1-bf5c-3c46593d1824@mailbox.org>
 <aRW7BZimWdpq4TyX@pluto>
 <20251202-evasive-neon-rhino-d2745e@sudeepholla>
 <66257fcf-9024-454f-b776-4ba584963ebe@mailbox.org>
 <aS82GSN8c2SnRn4S@bogus>
 <8d773671-5e2e-4e21-ade6-2bf9a3b75066@mailbox.org>
 <20251203-thick-didactic-cockatoo-deaa1d@sudeepholla>
 <4ccbcffd-bcc7-478b-a525-a4a11e3092ee@mailbox.org>
Message-ID: <20251204-calm-peacock-of-fantasy-6b8cbe@sudeepholla>

On Wed, Dec 03, 2025 at 11:53:41PM +0100, Marek Vasut wrote:
> On 12/3/25 12:41 PM, Sudeep Holla wrote:
> 
> Hello Sudeep,
> 
> > > > Consider a system where a mailbox controller is present and one channel is
> > > > used for SCMI communication, while another channel is used for an unrelated
> > > > purpose. If both channels share the same interrupt line, and the other use
> > > > case enables interrupt mode on its channel, what would be the impact on the
> > > > SCMI-specific channel?
> > > 
> > > None, SCMI kernel driver and SCMI server side would still do polling on
> > > their respective SHMEM areas, while whatever kernel driver needs to receive
> > > the interrupt notifications would subscribe to them using request_irq(),
> > > right ?
> > > 
> > 
> > Fair enough. I was thinking if the controller manages to not call
> > mbox_chan_received_data() in that case.
> 
> Wouldn't such a setup use separate mailbox channels, therefore even if
> mailbox driver calls mbox_chan_received_data(), it would be called for a
> specific mailbox channel , and it won't interfere with the SCMI mailbox
> channel.
> 

Ideally yes. Because PCC uses shared interrupts and provides no mechanism to
identify the channel that raised the interrupt, we must run the handler for
every registered channel. This behaviour is specific to PCC; other controllers
that support interrupt source detection may not need to do this. But SCMI
must work with any mailbox or other transports.

> > Also IIUC, the irq request happens
> > as part of channel startup and there are no explicit APIs for the mbox client
> > driver to control that. SCMI is mbox client in this case.
> 
> Sure, but the mailbox driver has to make sure it is correctly demuxing the
> IRQs it handles and correctly sends received_data notifications to the right
> channel(s) .
> 

Agreed, but the concern is that if SCMI is forced to use polling when the
channel is opened, and IRQs are enabled by default with no way for SCMI to
disable them in polling mode, we could run into issues. I realise it?s a very
specific corner case, but every time I?ve assumed such scenarios wouldn?t
occur, we eventually ended up encountering them. So sorry if I am very
pedantic, but I prefer to start smaller and restrictive and expand if and
when necessary or required only.

> > > > I am aware of systems that implement such sharing, which is why I prefer to be
> > > > explicit that this type of design is challenging to support within this
> > > > binding. The intent is to support only minimal, constrained cases - essentially
> > > > systems that are already somewhat broken. I do not see value in broadening the
> > > > binding to cover every conceivable scenario.
> > > > 
> > > > > > Clearly defining these constraints would be helpful. It may also be useful to
> > > > > > note that this is primarily intended for mailbox transports, if that?s
> > > > > > accurate. Alternatively, we could keep the DT binding definition broader but
> > > > > > emit warnings when a transport other than mailbox is used. That approach might
> > > > > > make it easier to move forward.
> > > > > 
> > > > > DEN0056F refers to this polling mode in Shared memory based transports, that
> > > > > can be other than mailbox transports, it includes e.g. SMC or OPTEE
> > > > > transports.
> > > > > 
> > > > 
> > > > However, polling does not make sense in the context of SMC. Once control
> > > > returns from an SMC call, the command has completed. What form of polling in
> > > > an SMC workflow do you have in mind?
> > > 
> > > I think the polling happens on the SHMEM and the SMC transport is capable of
> > > that too, see :
> > > 
> > > drivers/firmware/arm_scmi/transports/smc.c
> > > 
> > > 175         /*
> > > 176          * If there is an interrupt named "a2p", then the service and
> > > 177          * completion of a message is signaled by an interrupt rather
> > > than by
> > > 178          * the return of the SMC call.
> > > 179          */
> > > 180         scmi_info->irq = of_irq_get_byname(cdev->of_node, "a2p");
> > > 
> > 
> > Ah this one, is actually implemented to avoid sort of implicit polling
> > mode we get with any SMC/HVC. I don't know how the platform deals with it
> > but SMC/HVC is synchronous and doesn't need this polling. The irq introduced
> > here is again a sort of workaround to get some sort of async/non-polling
> > mode with SMC/HVC. So, to repeat polling mode make absolutely no sense
> > whatsoever for SMC/OPTEE(based on pure SMC) transports.
> 
> I can drop the SMC part from this patch if you think that's helpful ?
> 

Yes, that?s essential, because polling in an SMC context is meaningless in my
opinion.

> > > > I believe the same applies to OP-TEE.
> > > > While OP-TEE now provides a notification mechanism that could, in theory,
> > > > allow synchronous commands to be treated in a quasi-asynchronous manner, I
> > > > strongly doubt that the current SCMI-over-OP-TEE implementation behaves this
> > > > way, given that it ultimately reaches the secure side via an SMC call.
> > > > 
> > > > > I don't think a warning is justified, if the behavior follows the
> > > > > specification. But I do agree the behavior is ... suboptimal.
> > > > > 
> > > > 
> > > > The specification does not address SMC or OP-TEE transports, placing them
> > > > outside its scope and likewise these DT bindings.
> > > 
> > > I believe the shmem transport includes the SMC and OPTEE ones, right ?
> > > 
> > 
> > Yes, but the expectation when the SMC completes is to have the shmem to be
> > owned by the OS(except that irq workaround case). Again the OPTEE/SMC is
> > completely out of spec, but I agree the SHMEM behaviour must conform to the
> > specification.
> 
> OK
> 
> > > > Consequently, what we
> > > > decide here in this discussion effectively defines the expected behavior in
> > > > this context, in my view. So I would like to start with minimal possible
> > > > coverage, why do you think that is not a good idea here ?
> > > 
> > > I would argue the current implementation covers pretty much every transport
> > > which could ever need to do polling on shmem, so the implementation is
> > > generic and inline with the specification. Also, the current implementation
> > > is some 20 lines, so I think it is minimalistic?
> > > 
> > > What would you propose we do here ?
> > > 
> > 
> > Yes it can be minimalistic but not restrictive. As I already clearly mentioned
> > I don't see it makes any sense to enable this for SMC/OPTEE. Lets start with
> > just mailbox to start with and extend to other transports if and when needed.
> > It would be good to impose that restriction in the binding as well but that
> > is not a must IMO. I am fine if the bindings for whatever reasons(though I
> > don't see the need) to apply for any transport.
> So I should simply drop the smc.c changes , keep the rest, and send V2 ?

Not just that. Unless DT maintainers oppose, I just want to keep this
new property valid only for mailbox transport(i.e. "arm,scmi" compatible
not otherwise) so that we can catch any other use in binding checks and
interested parties must discuss on the list and expand that if they require.

Also we can explore if we can parse and scan this in mailbox transport for
now.

-- 
Regards,
Sudeep


From pavel at ucw.cz  Thu Dec  4 04:38:06 2025
From: pavel at ucw.cz (Pavel Machek)
Date: Thu, 4 Dec 2025 13:38:06 +0100
Subject: [PATCH v2 3/3] ARM: samsung: exynos5250: Allow CPU1 to boot
In-Reply-To: <39ac918c-0394-495b-b717-dfa0fd35d7dc@kernel.org>
References: <20251125-google-manta-v2-0-0f097cfff39c@timmermann.space>
 <20251125-google-manta-v2-3-0f097cfff39c@timmermann.space>
 <aTFvBwjms8msxIae@duo.ucw.cz>
 <73efeaeb-0cde-45af-af92-4fd7b5d4589c@kernel.org>
 <aTF2H0f9TJiwCLe5@duo.ucw.cz>
 <a68ee81f-1d2c-47f4-b86f-e0e803c1cfd3@kernel.org>
 <aTF2z5HbvmEuu9Iy@duo.ucw.cz>
 <39ac918c-0394-495b-b717-dfa0fd35d7dc@kernel.org>
Message-ID: <aTGAruX7N/7ZT0ur@duo.ucw.cz>

On Thu 2025-12-04 13:02:00, Krzysztof Kozlowski wrote:
> On 04/12/2025 12:55, Pavel Machek wrote:
> > On Thu 2025-12-04 12:54:03, Krzysztof Kozlowski wrote:
> >> On 04/12/2025 12:53, Pavel Machek wrote:
> >>> On Thu 2025-12-04 12:51:36, Krzysztof Kozlowski wrote:
> >>>> On 04/12/2025 12:22, Pavel Machek wrote:
> >>>>> Also please cc: phone-devel mailing list with phone related patches.
> >>>>
> >>>> You don't have to. This list is not part of any upstream Linux kernel
> >>>> process (see `git grep`), it's not relevant to upstream kernel development.
> >>>
> >>> Yes, you should. Its a relevant mailing list.
> >>
> >> git grep for it. Stop inventing rules.
> > 
> > Who is inventing rules here? Stop sabotaging review process.
> 
> You invented rule that some specific list of your interest has to be
> CCed, even though no one knows about that list and it is nowhere documented.

No. I'm asking people to please cc the mailing list so that interested
people can see the patches. It is you blabbering nonsense about "git
grep" and "get_maintainer" as if those were rules.

> > "Many kernel-related lists are hosted on vger.kernel.org; you can find a
> > list of them at http://vger.kernel.org/vger-lists.html.  There are
> > kernel-related lists hosted elsewhere as well, though."
> 
> This proves nothing. There are just some lists there. No one has to cc
> whatever list there just because Pavel Machek asks them. Kernel process
> defines it or not. Not you.

And not you.

Kernel process is to cc relevant people, and relevant mailing lists,
SubmittingPatches points you to http://vger.kernel.org/vger-lists.html
. If people are interested in the patch (for example because they
reacted to previous version), you should cc them. People in
phone-devel expressed interest in phone-related kernel development, so
you should cc them.

								Pavel
-- 
I don't work for Nazis and criminals, and neither should you.
Boycott Putin, Trump, Netanyahu and Musk!
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 195 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251204/bb1f4a98/attachment.sig>

From anshuman.khandual at arm.com  Thu Dec  4 04:43:56 2025
From: anshuman.khandual at arm.com (Anshuman Khandual)
Date: Thu, 4 Dec 2025 18:13:56 +0530
Subject: [PATCH 04/19] coresight: trbe: Remove set_trbe_disabled() from
 the enable flow
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-4-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-4-7da32b076b28@arm.com>
Message-ID: <789573eb-c12b-419f-80bc-3de65367583e@arm.com>

On 01/12/25 4:51 PM, Leo Yan wrote:
> set_trbe_disabled() should never appear in the enable flow, otherwise,
> it may potentially hide bugs in the disable flow.
> 
> Remove set_trbe_disabled() from the enable path.

IIRC without first disabling TRBLIMITR_EL1_E - TRBE registers or their
fields should not be fetched or interpreted. Without that none of the
subsequent HW operations should be performed inside trbe_enable_hw()
leading upto enabling it.

> 
> Signed-off-by: Leo Yan <leo.yan at arm.com>
> ---
>  drivers/hwtracing/coresight/coresight-trbe.c | 1 -
>  1 file changed, 1 deletion(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
> index f5597bd9b5fba9a8f5053d5823b03380fd468b5c..e426991e2c2c398a9d3982e9d0f7f542e404cbab 100644
> --- a/drivers/hwtracing/coresight/coresight-trbe.c
> +++ b/drivers/hwtracing/coresight/coresight-trbe.c
> @@ -629,7 +629,6 @@ static void trbe_enable_hw(struct trbe_buf *buf)
>  	WARN_ON(buf->trbe_hw_base < buf->trbe_base);
>  	WARN_ON(buf->trbe_write < buf->trbe_hw_base);
>  	WARN_ON(buf->trbe_write >= buf->trbe_limit);
> -	set_trbe_disabled(buf->cpudata);
>  	clr_trbe_status();
>  	set_trbe_base_pointer(buf->trbe_hw_base);
>  	set_trbe_write_pointer(buf->trbe_write);
> 



From anshuman.khandual at arm.com  Thu Dec  4 04:57:27 2025
From: anshuman.khandual at arm.com (Anshuman Khandual)
Date: Thu, 4 Dec 2025 18:27:27 +0530
Subject: [PATCH 05/19] coresight: trbe: Refactor status clearing
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-5-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-5-7da32b076b28@arm.com>
Message-ID: <fb3b495a-3e04-417f-a674-e1753fd85177@arm.com>

On 01/12/25 4:51 PM, Leo Yan wrote:
> If the driver does not clear the status when disabling the trace buffer
> unit, stale state will carry over to the next enable, though the driver
> clears it again on enable.

There is no problem now ! Because trbe_enable_hw() calls clr_trbe_status().

> 
> Explicitly clear status after the trace is disabled in the interrupt
> handling and when a perf session ends.  Keep the status for spurious
> interrupts for continuous tracing.

But is not that the behaviour already without this change ?

clr_trbe_status() in trbe_enable_hw() ensures that no TRBE session can be
started without first clearing the existing status. Still wondering what
is the purpose of this change ?

> 
> Signed-off-by: Leo Yan <leo.yan at arm.com>
> ---
>  drivers/hwtracing/coresight/coresight-trbe.c | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
> index e426991e2c2c398a9d3982e9d0f7f542e404cbab..9e565122816949b37b8ff5e4ba04cfbc317c6f25 100644
> --- a/drivers/hwtracing/coresight/coresight-trbe.c
> +++ b/drivers/hwtracing/coresight/coresight-trbe.c
> @@ -629,7 +629,6 @@ static void trbe_enable_hw(struct trbe_buf *buf)
>  	WARN_ON(buf->trbe_hw_base < buf->trbe_base);
>  	WARN_ON(buf->trbe_write < buf->trbe_hw_base);
>  	WARN_ON(buf->trbe_write >= buf->trbe_limit);
> -	clr_trbe_status();
>  	set_trbe_base_pointer(buf->trbe_hw_base);
>  	set_trbe_write_pointer(buf->trbe_write);
>  
> @@ -1036,6 +1035,8 @@ static int arm_trbe_disable(struct coresight_device *csdev)
>  		return -EINVAL;
>  
>  	trbe_drain_and_disable_local(cpudata);
> +	clr_trbe_status();
> +
>  	buf->cpudata = NULL;
>  	cpudata->buf = NULL;
>  	cpudata->mode = CS_MODE_DISABLED;
> @@ -1151,6 +1152,10 @@ static irqreturn_t arm_trbe_irq_handler(int irq, void *dev)
>  		return IRQ_NONE;
>  
>  	act = trbe_get_fault_act(handle, status);
> +
> +	if (act != TRBE_FAULT_ACT_SPURIOUS)
> +		clr_trbe_status();
> +
>  	switch (act) {
>  	case TRBE_FAULT_ACT_WRAP:
>  		truncated = !!trbe_handle_overflow(handle);
> 



From maz at kernel.org  Thu Dec  4 05:01:40 2025
From: maz at kernel.org (Marc Zyngier)
Date: Thu, 04 Dec 2025 13:01:40 +0000
Subject: Alternative to arm64.nopauth cmdline for disabling Pointer Authentication
In-Reply-To: <adc22b19-7dcc-4c38-9319-d979f1e3886a@quicinc.com>
References: <3fcf6614-ee83-4a06-9024-83573b2e642e@quicinc.com>
	<86ecpappzi.wl-maz@kernel.org>
	<adc22b19-7dcc-4c38-9319-d979f1e3886a@quicinc.com>
Message-ID: <868qfipfij.wl-maz@kernel.org>

[dropping Ricardo, as his address bounces]

On Thu, 04 Dec 2025 10:36:12 +0000,
Pavan Kondeti <pavan.kondeti at oss.qualcomm.com> wrote:
> 
> Hi Marc,
> 
> On Thu, Dec 04, 2025 at 09:15:29AM +0000, Marc Zyngier wrote:
> > On Thu, 04 Dec 2025 04:07:15 +0000,
> > Pavan Kondeti <pavan.kondeti at oss.qualcomm.com> wrote:
> > > 
> > > Hi
> > > 
> > > The pointer authentication feature (PAuth) is only supported on
> > > 0-3 CPUs but it is not supported on 4-7 CPUS on QCS8300.
> > 
> > On what grounds? Hardware incompatibility? I seriously doubt it, since
> > nobody glues pre-8.3 CPUs to anything more modern. Or, as I expect it,
> > a firmware implemented with little understanding of what is required?
> 
> I don't know the answer to this question. I will talk to folks who may
> know answer to this question and get back.
> 
> Can you please elaborate on the firmware part you are talking here? I
> see that Linux runs at EL2 and AA64ISAR1 register values on CPU#0 (A78)
> indicates that PAuth is supported but not for CPU#4 (A55). I am told, there
> are no other controls outside EL2 (trap) to manipulate this feature. So,
> I am assuming that this is indeed reflecting the HW.

Neither A78 nor A55 have PAuth. They are both firmly ARMv8.2 CPUs, and
predate this functionality. So I guess that there are only two possible
outcomes:

- either the FW is indeed not at fault, but that you have a *third*
  type of CPU that is at least 8.3 in the mix

- or that you misidentified the CPUs that are on your system, they
  have PAuth, and the firmware is borked

Which one is it?

> 
> > 
> > > The ARM64 cpufeature discovery code expects late CPUs to have
> > > this feature if boot CPU feature has it since PAuth is enabled
> > > early. When a conflict like this is detected, the late CPUs are
> > > not allowed to boot. It is expected that system will continue
> > > to be functional with CPUs with Pauth feature supported and enabled.
> > > This is not a desired behavior in production.
> > 
> > What is even less desirable is to produce this sort of contraption.
> > 
> > > We started seeing this problem when Linux is booted in EL2. When Linux
> > > is running under Gunyah (Type-1 hypervisor), Pointer Authentication
> > > feature is hidden from EL1 via HCR_EL2.TID3. 
> > > 
> > > arm64.nopauth can be passed on kernel cmdline to disable the feature
> > > in kernel so that all all CPUs can boot on QCS8300. I am told 
> > > maintaining a custom kernel commandline per SoC in a Generic OS 
> > > distribution is not recommended and asked to discuss the problem with
> > > the comunity [1]
> > 
> > Well, you get to own the problem you have created for yourself. You
> > build hardware/firmware that cannot run generic SW, and yet you want
> > generic SW to run seamlessly on it. Spot the issue?
> > 
> > > This patch [2] from Catalin adds a devicetree property under memory {}
> > > to disable MTE. I believe this work predates the id-reg override
> > > mechanism. However, this made me think if workarounds like this can be
> > > detected via devicetree, for example a property under cpu { } node.
> > 
> > Not only it predates it, but it also doesn't work in general. For a
> > start, it is DT specific. How are you going to make that work for
> > ACPI? I know you don't care, but I do.
> 
> Point taken. I understand that this does not fall under errata but is
> there a possiblity to introduce an Errata targeting CPU#0 MIDR and
> disabling the Pointer authentication? I understand that if there is
> another Qualcomm SoC that exists with all CPUs supporting pointer
> authentication with same MIDR, we may be disabling the feature but this
> is something I can check internally.
> 
> > 
> > > Given that what we put in `chosen { bootargs="" }` kernel under
> > > respective SoC devicetree can be overridden by bootloader, should we
> > > have a **sticky** cmdline to specify critical workarounds like this?
> > > This would be more generic than introducing any new parameters.
> > 
> > You already have a way to have a sticky command-line, by building it
> > into the kernel. Yes, I understand that this isn't what you want, but:
> > 
> > (1) a user should be allowed to pass the kernel command-line *they*
> >     want, not what someone has decided for them
> 
> Agreed. This is what made me to ask the question. Should kernel have a
> sticky command line which may have critical workarounds like this?

Absolutely *not*. You are not in charge of defining what is good for
the user. If the user themselves want that, they have plenty of ways
to achieve that particular goal already. Put it in the bootargs
string, in the kernel build, in a grub config file, as a u-boot
hack... There is an infinite number of choices already, and we don't
need an extra one to hide how ugly their HW is.

> > (2) the generic mechanism exists, doesn't rely on additional firmware
> >     specifications, and is used for a whole lot of other QC platforms
> >     suffering from the same issue of broken firmware.  What are you
> >     going to do for these?
> 
> The generic mechanism, you mean bootloader passing the kernel cmdline
> with `arm64.nopauth`? or something else.

Exactly that. This is the mechanism by which we instruct the kernel
not to use a particular feature if it can avoid it. It is easy to add,
doesn't depend on new esoteric firmware interfaces, and is a constant
reminder that you are dealing with stuff that isn't fit for purpose.

> > (3) what if you, by miracle, happened to *fix* the firmware?
> 
> As I have asked above, the firmware part is not clear. 

Well, your description of the root cause of the problem isn't clear
either, so we're even! ;-)

	M.

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


From horms at kernel.org  Thu Dec  4 05:11:40 2025
From: horms at kernel.org (Simon Horman)
Date: Thu, 4 Dec 2025 13:11:40 +0000
Subject: [PATCH] net: stmmac: fix oops when split header is enabled
In-Reply-To: <20251202025421.4560-1-jie.zhang@analog.com>
References: <20251202025421.4560-1-jie.zhang@analog.com>
Message-ID: <aTGIjNiHhWHd_RkN@horms.kernel.org>

On Mon, Dec 01, 2025 at 09:54:16PM -0500, Jie Zhang wrote:
> For GMAC4, when split header is enabled, in some rare cases, the
> hardware does not fill buf2 of the first descriptor with payload.
> Thus we cannot assume buf2 is always fully filled if it is not
> the last descriptor. Otherwise, the length of buf2 of the second
> descriptor will be calculated wrong and cause an oops:

...

As a bug fix this should have a Fixes tag here
(no blank line between it and your Signed-off-by line).
As a rule of thumb, it should cite the patch where
the bug was introduced.

Perhaps in this case the following is appropriate:

Fixes: ec222003bd94 ("net: stmmac: Prepare to add Split Header support")

> Signed-off-by: Jie Zhang <jie.zhang at analog.com>


From lorenzo at kernel.org  Thu Dec  4 05:13:27 2025
From: lorenzo at kernel.org (Lorenzo Bianconi)
Date: Thu, 04 Dec 2025 14:13:27 +0100
Subject: [PATCH mt76 0/3] wifi: mt76: mt7996: Some MLO link management
 fixes
Message-ID: <20251204-mt76-txq-wicd-fix-v1-0-1f4b2f2b3b2c@kernel.org>


---
Lorenzo Bianconi (3):
      wifi: mt76: mt7996: Set mtxq->wcid just for primary link
      wifi: mt76: mt7996: Reset mtxq->idx if primary link is removed in mt7996_vif_link_remove()
      wifi: mt76: mt7996: Switch to the secondary link if the default one is removed

 drivers/net/wireless/mediatek/mt76/mt7996/main.c | 84 ++++++++++++++++--------
 1 file changed, 58 insertions(+), 26 deletions(-)
---
base-commit: 53d1548612670aa8b5d89745116cc33d9d172863
change-id: 20251204-mt76-txq-wicd-fix-267a4941622e

Best regards,
-- 
Lorenzo Bianconi <lorenzo at kernel.org>



From lorenzo at kernel.org  Thu Dec  4 05:13:28 2025
From: lorenzo at kernel.org (Lorenzo Bianconi)
Date: Thu, 04 Dec 2025 14:13:28 +0100
Subject: [PATCH mt76 1/3] wifi: mt76: mt7996: Set mtxq->wcid just for
 primary link
In-Reply-To: <20251204-mt76-txq-wicd-fix-v1-0-1f4b2f2b3b2c@kernel.org>
References: <20251204-mt76-txq-wicd-fix-v1-0-1f4b2f2b3b2c@kernel.org>
Message-ID: <20251204-mt76-txq-wicd-fix-v1-1-1f4b2f2b3b2c@kernel.org>

Set WCID index in mt76_txq struct just for the primary link in
mt7996_vif_link_add routine.

Fixes: 69d54ce7491d0 ("wifi: mt76: mt7996: switch to single multi-radio wiphy")
Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
---
 drivers/net/wireless/mediatek/mt76/mt7996/main.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index beed795edb24c67e1b7b44fe87fd5de125a21d94..0ad0152478a7e1b11bfe5d68d750cb8332d54290 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -300,7 +300,6 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
 		.cmd = SET_KEY,
 		.link_id = link_conf->link_id,
 	};
-	struct mt76_txq *mtxq;
 	int mld_idx, idx, ret;
 
 	mlink->idx = __ffs64(~dev->mt76.vif_mask);
@@ -343,11 +342,6 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
 	mt7996_mac_wtbl_update(dev, idx,
 			       MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
 
-	if (vif->txq) {
-		mtxq = (struct mt76_txq *)vif->txq->drv_priv;
-		mtxq->wcid = idx;
-	}
-
 	if (vif->type != NL80211_IFTYPE_AP &&
 	    (!mlink->omac_idx || mlink->omac_idx > 3))
 		vif->offload_flags = 0;
@@ -371,8 +365,15 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
 	ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, &it);
 
 	if (!mlink->wcid->offchannel &&
-	    mvif->mt76.deflink_id == IEEE80211_LINK_UNSPECIFIED)
+	    mvif->mt76.deflink_id == IEEE80211_LINK_UNSPECIFIED) {
+		if (vif->txq) {
+			struct mt76_txq *mtxq;
+
+			mtxq = (struct mt76_txq *)vif->txq->drv_priv;
+			mtxq->wcid = idx;
+		}
 		mvif->mt76.deflink_id = link_conf->link_id;
+	}
 
 	return 0;
 }

-- 
2.52.0



From lorenzo at kernel.org  Thu Dec  4 05:13:29 2025
From: lorenzo at kernel.org (Lorenzo Bianconi)
Date: Thu, 04 Dec 2025 14:13:29 +0100
Subject: [PATCH mt76 2/3] wifi: mt76: mt7996: Reset mtxq->idx if primary
 link is removed in mt7996_vif_link_remove()
In-Reply-To: <20251204-mt76-txq-wicd-fix-v1-0-1f4b2f2b3b2c@kernel.org>
References: <20251204-mt76-txq-wicd-fix-v1-0-1f4b2f2b3b2c@kernel.org>
Message-ID: <20251204-mt76-txq-wicd-fix-v1-2-1f4b2f2b3b2c@kernel.org>

Reset WCID index in mt76_txq struct if primary link is removed in
mt7996_vif_link_remove routine.

Fixes: a3316d2fc669f ("wifi: mt76: mt7996: set vif default link_id adding/removing vif links")
Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
---
 drivers/net/wireless/mediatek/mt76/mt7996/main.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index 0ad0152478a7e1b11bfe5d68d750cb8332d54290..8bf85a9beee7dc8c6741568af5b36cf89f0c1a88 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -409,12 +409,23 @@ void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif,
 		struct ieee80211_bss_conf *iter;
 		unsigned int link_id;
 
+		/* Primary link will be removed, look for a new one */
 		mvif->mt76.deflink_id = IEEE80211_LINK_UNSPECIFIED;
 		for_each_vif_active_link(vif, iter, link_id) {
-			if (link_id != IEEE80211_LINK_UNSPECIFIED) {
-				mvif->mt76.deflink_id = link_id;
-				break;
+			struct mt7996_vif_link *link;
+
+			link = mt7996_vif_link(dev, vif, link_id);
+			if (!link)
+				continue;
+
+			if (vif->txq) {
+				struct mt76_txq *mtxq;
+
+				mtxq = (struct mt76_txq *)vif->txq->drv_priv;
+				mtxq->wcid = link->msta_link.wcid.idx;
 			}
+			mvif->mt76.deflink_id = link_id;
+			break;
 		}
 	}
 

-- 
2.52.0



From lorenzo at kernel.org  Thu Dec  4 05:13:30 2025
From: lorenzo at kernel.org (Lorenzo Bianconi)
Date: Thu, 04 Dec 2025 14:13:30 +0100
Subject: [PATCH mt76 3/3] wifi: mt76: mt7996: Switch to the secondary link
 if the default one is removed
In-Reply-To: <20251204-mt76-txq-wicd-fix-v1-0-1f4b2f2b3b2c@kernel.org>
References: <20251204-mt76-txq-wicd-fix-v1-0-1f4b2f2b3b2c@kernel.org>
Message-ID: <20251204-mt76-txq-wicd-fix-v1-3-1f4b2f2b3b2c@kernel.org>

Switch to the secondary link if available in mt7996_mac_sta_remove_links
routine if the primary one is removed.
Moreover reset secondary link index for single link scenario.

Fixes: 85cd5534a3f2e ("wifi: mt76: mt7996: use correct link_id when filling TXD and TXP")
Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
---
 drivers/net/wireless/mediatek/mt76/mt7996/main.c | 52 ++++++++++++++++--------
 1 file changed, 36 insertions(+), 16 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index 8bf85a9beee7dc8c6741568af5b36cf89f0c1a88..1baace971ec3511dba3e8a64c236a2b55f9dbd36 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -945,6 +945,22 @@ mt7996_channel_switch_beacon(struct ieee80211_hw *hw,
 	mutex_unlock(&dev->mt76.mutex);
 }
 
+static void
+mt7996_sta_init_txq_wcid(struct ieee80211_sta *sta, int idx)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
+		struct mt76_txq *mtxq;
+
+		if (!sta->txq[i])
+			continue;
+
+		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
+		mtxq->wcid = idx;
+	}
+}
+
 static int
 mt7996_mac_sta_init_link(struct mt7996_dev *dev,
 			 struct ieee80211_bss_conf *link_conf,
@@ -962,21 +978,10 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev,
 		return -ENOSPC;
 
 	if (msta->deflink_id == IEEE80211_LINK_UNSPECIFIED) {
-		int i;
-
 		msta_link = &msta->deflink;
 		msta->deflink_id = link_id;
 		msta->seclink_id = msta->deflink_id;
-
-		for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
-			struct mt76_txq *mtxq;
-
-			if (!sta->txq[i])
-				continue;
-
-			mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
-			mtxq->wcid = idx;
-		}
+		mt7996_sta_init_txq_wcid(sta, idx);
 	} else {
 		msta_link = kzalloc(sizeof(*msta_link), GFP_KERNEL);
 		if (!msta_link)
@@ -1058,13 +1063,28 @@ mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif,
 
 		mphy->num_sta--;
 		if (msta->deflink_id == link_id) {
-			msta->deflink_id = IEEE80211_LINK_UNSPECIFIED;
-			continue;
+			if (msta->seclink_id == msta->deflink_id) {
+				/* no secondary link available */
+				msta->deflink_id = IEEE80211_LINK_UNSPECIFIED;
+				msta->seclink_id = msta->deflink_id;
+			} else {
+				struct mt7996_sta_link *msta_seclink;
+
+				/* switch to the secondary link */
+				msta->deflink_id = msta->seclink_id;
+				msta_seclink = mt76_dereference(
+						msta->link[msta->seclink_id],
+						mdev);
+				if (msta_seclink)
+					mt7996_sta_init_txq_wcid(sta,
+						msta_seclink->wcid.idx);
+			}
 		} else if (msta->seclink_id == link_id) {
-			msta->seclink_id = IEEE80211_LINK_UNSPECIFIED;
+			msta->seclink_id = msta->deflink_id;
 		}
 
-		kfree_rcu(msta_link, rcu_head);
+		if (msta_link != &msta->deflink)
+			kfree_rcu(msta_link, rcu_head);
 	}
 }
 

-- 
2.52.0



From rkrcmar at ventanamicro.com  Thu Dec  4 05:16:24 2025
From: rkrcmar at ventanamicro.com (=?utf-8?q?Radim_Kr=C4=8Dm=C3=A1=C5=99?=)
Date: Thu, 04 Dec 2025 22:16:24 +0900
Subject: [External] Re: [PATCH v3 5/8] riscv: smp: use NMI for CPU stop
In-Reply-To: <CAEEQ3wmAn=9w=fR=OMTMF17_tAcEnsdJWL_w8fw-3wA-Bfi6xw@mail.gmail.com>
References: <20251127125305.89961-1-cuiyunhui@bytedance.com>
 <20251127125305.89961-6-cuiyunhui@bytedance.com>
 <DEP4X1DAIOU5.2WLIV4BMWLMRR@ventanamicro.com>
 <CAEEQ3wmAn=9w=fR=OMTMF17_tAcEnsdJWL_w8fw-3wA-Bfi6xw@mail.gmail.com>
Message-ID: <DEPGLFUVHA0O.XSZVD2T1ENLD@ventanamicro.com>

2025-12-04T13:28:45+08:00, yunhui cui <cuiyunhui at bytedance.com>:
> Hi Radim,
>
> On Thu, Dec 4, 2025 at 12:07?PM Radim Kr?m?? <rkrcmar at ventanamicro.com> wrote:
>>
>> 2025-11-27T20:53:02+08:00, Yunhui Cui <cuiyunhui at bytedance.com>:
>> > Use NMI instead of IPI for CPU stop if RISC-V SSE NMI is supported.
>> >
>> > Signed-off-by: Yunhui Cui <cuiyunhui at bytedance.com>
>> > ---
>> > diff --git a/drivers/firmware/riscv/riscv_sse_nmi.c b/drivers/firmware/riscv/riscv_sse_nmi.c
>> > @@ -58,6 +58,7 @@ static int local_nmi_handler(u32 evt, void *arg, struct pt_regs *regs)
>> >       type = atomic_read(this_cpu_ptr(&local_nmi));
>> >
>> >       NMI_HANDLE(LOCAL_NMI_CRASH, cpu_crash_stop, cpu, regs);
>> > +     NMI_HANDLE(LOCAL_NMI_STOP, cpu_stop);
>>
>> Please document the intended preemption design for all SSE events,
>> because it will be a nightmare if we forget some assumptions in the
>> coming years.  (That includes the relative priorities of RAS/PMU/...)
>
> Actually, LOCAL_NMI_CRASH, LOCAL_NMI_STOP, LOCAL_NMI_BACKTRACE,
> LOCAL_NMI_KGDB, ... are all implemented via the single SSE event
> SBI_SSE_EVENT_LOCAL_SOFTWARE_INJECTED. Per the SSE design, no
> preemption will occur among CRASH, STOP, BACKTRACE, and KGDB events.

That is how it is.  I don't understand why it must be like that.

For example: PMU_OVERFLOW has lower event_id than SOFTWARE_INJECTED, so
it will currently interrupt NMI_CRASH as they both have priority 0,
although NMI_CRASH probably shouldn't be masked by anything, and should
preempt everything.
NMI_BACKTRACE, on the other hand, probably shouldn't have that high
priority as there seem more important events (e.g. RAS and NMI_CRASH).

The issues can be avoided by event priorities, masking, or deemed as
non-issue, but I think it would be beneficial to provide some reasoning
behind the design, as the choices don't seem obvious to me.

Thanks.


From olteanv at gmail.com  Thu Dec  4 05:16:26 2025
From: olteanv at gmail.com (Vladimir Oltean)
Date: Thu, 4 Dec 2025 15:16:26 +0200
Subject: [PATCH v3 2/2] net: dsa: mt7530: Use GPIO polarity to generate
 correct reset sequence
In-Reply-To: <aS7Zj3AFsSp2CTNv@makrotopia.org>
References: <20251129234603.2544-1-ptpt52@gmail.com>
 <20251129234603.2544-2-ptpt52@gmail.com>
 <0675b35f-217d-4261-9e3f-2eb24753d43c@lunn.ch>
 <20251130080731.ty2dlxaypxvodxiw@skbuf>
 <3fbc4e67-b931-421c-9d83-2214aaa2f6ed@lunn.ch>
 <0d85e1e6-ea75-4f20-aef1-90d446b4bfa1@kernel.org>
 <00f308a1-a4b1-4f20-8d8e-459ddf4c39b1@gmx.de>
 <aS7Zj3AFsSp2CTNv@makrotopia.org>
Message-ID: <20251204131626.upw77jncqfwxydww@skbuf>

On Tue, Dec 02, 2025 at 12:20:31PM +0000, Daniel Golle wrote:
> On Tue, Dec 02, 2025 at 12:52:44PM +0100, Frank Wunderlich wrote:
> > Hi,
> > 
> > Am 01.12.25 um 08:48 schrieb Krzysztof Kozlowski:
> > > On 30/11/2025 21:17, Andrew Lunn wrote:
> > > > On Sun, Nov 30, 2025 at 10:07:31AM +0200, Vladimir Oltean wrote:
> > > > > On Sun, Nov 30, 2025 at 02:11:05AM +0100, Andrew Lunn wrote:
> > > > > > > -		gpiod_set_value_cansleep(priv->reset, 0);
> > > > > > > +		int is_active_low = !!gpiod_is_active_low(priv->reset);
> > > > > > > +		gpiod_set_value_cansleep(priv->reset, is_active_low);
> > > > > > I think you did not correctly understand what Russell said. You pass
> > > > > > the logical value to gpiod_set_value(). If the GPIO has been marked as
> > > > > > active LOW, the GPIO core will invert the logical values to the raw
> > > > > > value. You should not be using gpiod_is_active_low().
> > > > > > 
> > > > > > But as i said to the previous patch, i would just leave everything as
> > > > > > it is, except document the issue.
> > > > > > 
> > > > > > 	Andrew
> > > > > > 
> > > > > It was my suggestion to do it like this (but I don't understand why I'm
> > > > > again not in CC).
> > > > > 
> > > > > We _know_ that the reset pin of the switch should be active low. So by
> > > > > using gpiod_is_active_low(), we can determine whether the device tree is
> > > > > wrong or not, and we can work with a wrong device tree too (just invert
> > > > > the logical values).
> > > > Assuming there is not a NOT gate placed between the GPIO and the reset
> > > > pin, because the board designer decided to do that for some reason?
> > jumping in because i prepare mt7987 / BPI-R4Lite dts for upstreaming when
> > driver-changes are in.
> > With current driver i need to define the reset-gpio for mt7531 again wrong
> > to get it
> > working. So to have future dts correct, imho this (or similar) change to
> > driver is needed.
> > 
> > Of course we cannot simply say that current value is wrong and just invert
> > it because of
> > possible "external" inversion of reset signal between SoC and switch.
> > I have to look on schematics for the boards i have (BPI-R64, BPI-R3,
> > BPI-R2Pro) if there is such circuit.
> 
> I'm also not aware of any board which doesn't directly connect the
> reset of the MT7530 to a GPIO pin of the SoC. For MediaTek's designs
> there is often even a specific pin desginated for this purpose and
> most vendors do follow this. If they deviate at all, then it's just
> that a different pin is used for the switch reset, but I've never
> seen any logic between the SoC's GPIO pin and the switch reset.
> 
> > Maybe the mt7988 (mt7530-mmio) based boards also affected?
> 
> There is no GPIO reset for switches which are integrated in the SoC,
> so this only matters for external MT7530 and MT7531 ICs for which an
> actual GPIO line connected to the SoC is used to reset the switch.

I get the feeling that we're complicating a simple solution because of a
theoretical "what if" scenario. The "NOT" gate is somewhat contrived
given the fact that most GPIOs can already be active high or low, but OK.

If this is blocking progress for new device trees, can we just construct,
using of_machine_is_compatible(), a list of all boards where the device
tree defines incorrect reset polarity that shouldn't be trusted by the
driver when driving the reset GPIO? If we do this, we can also leave
those existing device trees alone.


From heikki.krogerus at linux.intel.com  Thu Dec  4 05:18:48 2025
From: heikki.krogerus at linux.intel.com (Heikki Krogerus)
Date: Thu, 4 Dec 2025 15:18:48 +0200
Subject: [PATCH v11 03/11] drm/bridge: Implement generic USB Type-C DP
 HPD bridge
In-Reply-To: <20251128020405.90-4-kernel@airkyi.com>
References: <20251128020405.90-1-kernel@airkyi.com>
 <20251128020405.90-4-kernel@airkyi.com>
Message-ID: <aTGKODdf7vsHFY72@kuha>

Hi,

Fri, Nov 28, 2025 at 10:03:57AM +0800, Chaoyi Chen kirjoitti:
> diff --git a/drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c b/drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c
> new file mode 100644
> index 000000000000..94be3d5f69e9
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c
> @@ -0,0 +1,51 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +#include <linux/of.h>
> +#include <linux/usb/typec_altmode.h>
> +#include <linux/usb/typec_dp.h>
> +
> +#include <drm/bridge/aux-bridge.h>
> +
> +static int drm_typec_bus_event(struct notifier_block *nb,
> +			       unsigned long action, void *data)
> +{
> +	struct device *dev = (struct device *)data;
> +	struct typec_altmode *alt = to_typec_altmode(dev);
> +
> +	if (action != BUS_NOTIFY_ADD_DEVICE)
> +		goto done;
> +
> +	if (is_typec_partner_altmode(&alt->dev) || alt->svid != USB_TYPEC_DP_SID)
> +		goto done;

There are also plug altmodes. Just make sure it's a plug altmode.

	if (!is_typec_plug_altmode(&alt->dev) || alt->svid != USB_TYPEC_DP_SID)
                goto done;

> +	/*
> +	 * alt->dev.parent->parent : USB-C controller device
> +	 * alt->dev.parent         : USB-C connector device
> +	 */
> +	drm_dp_hpd_bridge_register(alt->dev.parent->parent,
> +				   to_of_node(alt->dev.parent->fwnode));
> +
> +done:
> +	return NOTIFY_OK;
> +}
> +
> +static struct notifier_block drm_typec_event_nb = {
> +	.notifier_call = drm_typec_bus_event,
> +};
> +
> +static void drm_aux_hpd_typec_dp_bridge_module_exit(void)
> +{
> +	bus_unregister_notifier(&typec_bus, &drm_typec_event_nb);
> +}
> +
> +static int __init drm_aux_hpd_typec_dp_bridge_module_init(void)
> +{
> +	bus_register_notifier(&typec_bus, &drm_typec_event_nb);
> +
> +	return 0;
> +}
> +
> +module_init(drm_aux_hpd_typec_dp_bridge_module_init);
> +module_exit(drm_aux_hpd_typec_dp_bridge_module_exit);
> +
> +MODULE_DESCRIPTION("DRM TYPEC DP HPD BRIDGE");
> +MODULE_LICENSE("GPL");

thanks,

-- 
heikki


From leo.yan at arm.com  Thu Dec  4 05:25:00 2025
From: leo.yan at arm.com (Leo Yan)
Date: Thu, 4 Dec 2025 13:25:00 +0000
Subject: [PATCH 04/19] coresight: trbe: Remove set_trbe_disabled() from
 the enable flow
In-Reply-To: <789573eb-c12b-419f-80bc-3de65367583e@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-4-7da32b076b28@arm.com>
 <789573eb-c12b-419f-80bc-3de65367583e@arm.com>
Message-ID: <20251204132500.GM724103@e132581.arm.com>

On Thu, Dec 04, 2025 at 06:13:56PM +0530, Anshuman Khandual wrote:
> On 01/12/25 4:51 PM, Leo Yan wrote:
> > set_trbe_disabled() should never appear in the enable flow, otherwise,
> > it may potentially hide bugs in the disable flow.
> > 
> > Remove set_trbe_disabled() from the enable path.
> 
> IIRC without first disabling TRBLIMITR_EL1_E - TRBE registers or their
> fields should not be fetched or interpreted.

Yes. I think you are referring to the rule DJMDD in Arm ARM: "The PE
might ignore a direct or external write to any of certain Trace Buffer
Unit registers ... (when) TRBLIMITR_EL1.E is 1, and the Trace Buffer
Unit is using Self-hosted mode."

> Without that none of the
> subsequent HW operations should be performed inside trbe_enable_hw()
> leading upto enabling it.

Fair enough.

If we can conclude the trace unit has been disabled properly in below
cases, no reason to arbitrarily calling set_trbe_disabled() during each
enable.

  1) The SYS_TRBLIMITR_EL1 register is cleared in trbe_reset_local()
     during probe phase.
  2) The SYS_TRBLIMITR_EL1.E bit is cleared in arm_trbe_irq_handler()
     for interrupt handling.
  3) The SYS_TRBLIMITR_EL1.E bit is cleared in the disable flow.


Seems to me, this is not only for code cleanup, we need to promise a
sane logic in the flow.

Thanks,
Leo


From rkrcmar at ventanamicro.com  Thu Dec  4 05:26:34 2025
From: rkrcmar at ventanamicro.com (=?utf-8?q?Radim_Kr=C4=8Dm=C3=A1=C5=99?=)
Date: Thu, 04 Dec 2025 22:26:34 +0900
Subject: [External] Re: [PATCH v3 8/8] drivers: firmware: riscv: add
 unknown nmi support
In-Reply-To: <CAEEQ3wkmFXAqBfHwJYbJRc5pagOJvtu-wEYGwXBF2beQiSMT1w@mail.gmail.com>
References: <20251127125305.89961-1-cuiyunhui@bytedance.com>
 <20251127125305.89961-9-cuiyunhui@bytedance.com>
 <DEP50CD8K22E.1JW7GL6WLK44W@ventanamicro.com>
 <CAEEQ3wkmFXAqBfHwJYbJRc5pagOJvtu-wEYGwXBF2beQiSMT1w@mail.gmail.com>
Message-ID: <DEPGT7OPYNFW.10L6V344HZE4T@ventanamicro.com>

2025-12-04T13:18:00+08:00, yunhui cui <cuiyunhui at bytedance.com>:
> Hi Radim,
>
> On Thu, Dec 4, 2025 at 12:11?PM Radim Kr?m?? <rkrcmar at ventanamicro.com> wrote:
>>
>> 2025-11-27T20:53:05+08:00, Yunhui Cui <cuiyunhui at bytedance.com>:
>> > Register unknown_nmi_handler() as the handler for the UNKNOWN_NMI
>> > event. When the system becomes unresponsive, unknown_nmi_handler()
>> > can be manually triggered, which in turn invokes nmi_panic() to
>> > collect vmcore for root cause analysis.
>>
>> Is UNKNOWN_NMI what we expect the watchdog to send?
>
> For reference: As stated in
> https://github.com/riscv-non-isa/riscv-sbi-doc/pull/223, "Generally,
> an external interrupt is used as an Unknown NMI pin, and an Unknown
> NMI event is sent to the SBI firmware by triggering this pin. Then the
> SBI firmware will send SBI_SSE_EVENT_GLOBAL_UNKNOWN_NMI to the
> kernel."
>
> When the Linux system is unresponsive, we can manually trigger it via
> BMC (ipmitool).

Makes sense, thanks, and do we plan to deal with other crash sources?

For example if a watchdog/sysrq triggers a crash, and then gets
interrupted with UNKNOWN_NMI.


From heikki.krogerus at linux.intel.com  Thu Dec  4 05:40:56 2025
From: heikki.krogerus at linux.intel.com (Heikki Krogerus)
Date: Thu, 4 Dec 2025 15:40:56 +0200
Subject: [RESEND PATCH v11 03/11] drm/bridge: Implement generic USB
 Type-C DP HPD bridge
In-Reply-To: <20251204063109.104-4-kernel@airkyi.com>
References: <20251204063109.104-1-kernel@airkyi.com>
 <20251204063109.104-4-kernel@airkyi.com>
Message-ID: <aTGPaJmwd7uHfrnV@kuha>

Hi,

I don't know what's going on here - this series is the 12th?
In any case, you need to fix this..

> diff --git a/drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c b/drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c
> new file mode 100644
> index 000000000000..94be3d5f69e9
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c
> @@ -0,0 +1,51 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +#include <linux/of.h>
> +#include <linux/usb/typec_altmode.h>
> +#include <linux/usb/typec_dp.h>
> +
> +#include <drm/bridge/aux-bridge.h>
> +
> +static int drm_typec_bus_event(struct notifier_block *nb,
> +			       unsigned long action, void *data)
> +{
> +	struct device *dev = (struct device *)data;
> +	struct typec_altmode *alt = to_typec_altmode(dev);
> +
> +	if (action != BUS_NOTIFY_ADD_DEVICE)
> +		goto done;
> +
> +	if (is_typec_partner_altmode(&alt->dev) || alt->svid != USB_TYPEC_DP_SID)
> +		goto done;

That's still not enough because of the plug altmodes. You need to
check that it's a port altmode:

        if (is_typec_port_altmode(&alt->dev) && alt->svid == USB_TYPEC_DP_SID)
        	drm_dp_hpd_bridge_register(alt->dev.parent->parent,
        				   to_of_node(alt->dev.parent->fwnode));

> +	/*
> +	 * alt->dev.parent->parent : USB-C controller device
> +	 * alt->dev.parent         : USB-C connector device
> +	 */
> +	drm_dp_hpd_bridge_register(alt->dev.parent->parent,
> +				   to_of_node(alt->dev.parent->fwnode));
> +
> +done:
> +	return NOTIFY_OK;
> +}
> +
> +static struct notifier_block drm_typec_event_nb = {
> +	.notifier_call = drm_typec_bus_event,
> +};
> +
> +static void drm_aux_hpd_typec_dp_bridge_module_exit(void)
> +{
> +	bus_unregister_notifier(&typec_bus, &drm_typec_event_nb);
> +}
> +
> +static int __init drm_aux_hpd_typec_dp_bridge_module_init(void)
> +{
> +	bus_register_notifier(&typec_bus, &drm_typec_event_nb);
> +
> +	return 0;
> +}
> +
> +module_init(drm_aux_hpd_typec_dp_bridge_module_init);
> +module_exit(drm_aux_hpd_typec_dp_bridge_module_exit);
> +
> +MODULE_DESCRIPTION("DRM TYPEC DP HPD BRIDGE");
> +MODULE_LICENSE("GPL");

thanks,

-- 
heikki


From heikki.krogerus at linux.intel.com  Thu Dec  4 05:41:56 2025
From: heikki.krogerus at linux.intel.com (Heikki Krogerus)
Date: Thu, 4 Dec 2025 15:41:56 +0200
Subject: [RESEND PATCH v11 02/11] usb: typec: Export typec bus and typec
 altmode device type
In-Reply-To: <20251204063109.104-3-kernel@airkyi.com>
References: <20251204063109.104-1-kernel@airkyi.com>
 <20251204063109.104-3-kernel@airkyi.com>
Message-ID: <aTGPpInIEzFhftf4@kuha>

Thu, Dec 04, 2025 at 02:31:00PM +0800, Chaoyi Chen kirjoitti:
> From: Chaoyi Chen <chaoyi.chen at rock-chips.com>
> 
> The DRM may want to register a notifier on the typec bus to know when
> a typec altmode device is added, and distinguish between different
> types of typec altmode device.
> 
> Export these things.
> 
> Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>

Reviewed-by: Heikki Krogerus <heikki.krogerus at linux.intel.com>

> ---
> 
> Changes in v11:
> - Also export typec bus.
> - Add more detailed comments.
> 
> (no changes since v9)
> 
>  drivers/usb/typec/bus.c           |  1 +
>  drivers/usb/typec/bus.h           | 10 ----------
>  drivers/usb/typec/class.c         |  3 +++
>  include/linux/usb/typec.h         |  3 +++
>  include/linux/usb/typec_altmode.h |  8 ++++++++
>  5 files changed, 15 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/usb/typec/bus.c b/drivers/usb/typec/bus.c
> index a33da7f458a5..e84b134a3381 100644
> --- a/drivers/usb/typec/bus.c
> +++ b/drivers/usb/typec/bus.c
> @@ -569,3 +569,4 @@ const struct bus_type typec_bus = {
>  	.probe = typec_probe,
>  	.remove = typec_remove,
>  };
> +EXPORT_SYMBOL_GPL(typec_bus);
> diff --git a/drivers/usb/typec/bus.h b/drivers/usb/typec/bus.h
> index b58e131450d1..7df5deb1dd3a 100644
> --- a/drivers/usb/typec/bus.h
> +++ b/drivers/usb/typec/bus.h
> @@ -5,7 +5,6 @@
>  
>  #include <linux/usb/typec_altmode.h>
>  
> -struct bus_type;
>  struct typec_mux;
>  struct typec_retimer;
>  
> @@ -28,13 +27,4 @@ struct altmode {
>  
>  #define to_altmode(d) container_of(d, struct altmode, adev)
>  
> -extern const struct bus_type typec_bus;
> -extern const struct device_type typec_port_altmode_dev_type;
> -extern const struct device_type typec_plug_altmode_dev_type;
> -extern const struct device_type typec_partner_altmode_dev_type;
> -
> -#define is_typec_port_altmode(dev) ((dev)->type == &typec_port_altmode_dev_type)
> -#define is_typec_plug_altmode(dev) ((dev)->type == &typec_plug_altmode_dev_type)
> -#define is_typec_partner_altmode(dev) ((dev)->type == &typec_partner_altmode_dev_type)
> -
>  #endif /* __USB_TYPEC_ALTMODE_H__ */
> diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
> index d6b88317f8a4..c4ff4310ff58 100644
> --- a/drivers/usb/typec/class.c
> +++ b/drivers/usb/typec/class.c
> @@ -537,18 +537,21 @@ const struct device_type typec_port_altmode_dev_type = {
>  	.groups = typec_altmode_groups,
>  	.release = typec_altmode_release,
>  };
> +EXPORT_SYMBOL_GPL(typec_port_altmode_dev_type);
>  
>  const struct device_type typec_plug_altmode_dev_type = {
>  	.name = "typec_plug_alternate_mode",
>  	.groups = typec_altmode_groups,
>  	.release = typec_altmode_release,
>  };
> +EXPORT_SYMBOL_GPL(typec_plug_altmode_dev_type);
>  
>  const struct device_type typec_partner_altmode_dev_type = {
>  	.name = "typec_partner_alternate_mode",
>  	.groups = typec_altmode_groups,
>  	.release = typec_altmode_release,
>  };
> +EXPORT_SYMBOL_GPL(typec_partner_altmode_dev_type);
>  
>  static struct typec_altmode *
>  typec_register_altmode(struct device *parent,
> diff --git a/include/linux/usb/typec.h b/include/linux/usb/typec.h
> index 309251572e2e..c6fd46902fce 100644
> --- a/include/linux/usb/typec.h
> +++ b/include/linux/usb/typec.h
> @@ -20,12 +20,15 @@ struct typec_port;
>  struct typec_altmode_ops;
>  struct typec_cable_ops;
>  
> +struct bus_type;
>  struct fwnode_handle;
>  struct device;
>  
>  struct usb_power_delivery;
>  struct usb_power_delivery_desc;
>  
> +extern const struct bus_type typec_bus;
> +
>  enum typec_port_type {
>  	TYPEC_PORT_SRC,
>  	TYPEC_PORT_SNK,
> diff --git a/include/linux/usb/typec_altmode.h b/include/linux/usb/typec_altmode.h
> index f7db3bd4c90e..9197a4637a93 100644
> --- a/include/linux/usb/typec_altmode.h
> +++ b/include/linux/usb/typec_altmode.h
> @@ -9,6 +9,14 @@
>  
>  #define MODE_DISCOVERY_MAX	6
>  
> +extern const struct device_type typec_port_altmode_dev_type;
> +extern const struct device_type typec_plug_altmode_dev_type;
> +extern const struct device_type typec_partner_altmode_dev_type;
> +
> +#define is_typec_port_altmode(dev) ((dev)->type == &typec_port_altmode_dev_type)
> +#define is_typec_plug_altmode(dev) ((dev)->type == &typec_plug_altmode_dev_type)
> +#define is_typec_partner_altmode(dev) ((dev)->type == &typec_partner_altmode_dev_type)
> +
>  struct typec_altmode_ops;
>  
>  /**
> -- 
> 2.51.1

-- 
heikki


From francesco at dolcini.it  Thu Dec  4 05:42:17 2025
From: francesco at dolcini.it (Francesco Dolcini)
Date: Thu,  4 Dec 2025 14:42:17 +0100
Subject: [PATCH v1 0/2] arm64: dts: ti: k3-am69-aquila: Fix USB-C Sink PDO
Message-ID: <20251204134220.129304-1-francesco@dolcini.it>

From: Francesco Dolcini <francesco.dolcini at toradex.com>

Change USB-C Sink PDO and the amount of power that the device can sink to
zero to maximize compatibility with other USB peers (the Aquila Clover and
Development Boards are not sinking any current, they are self powered).

Francesco Dolcini (2):
  arm64: dts: ti: k3-am69-aquila-dev: Fix USB-C Sink PDO
  arm64: dts: ti: k3-am69-aquila-clover: Fix USB-C Sink PDO

 arch/arm64/boot/dts/ti/k3-am69-aquila-clover.dts | 4 ++--
 arch/arm64/boot/dts/ti/k3-am69-aquila-dev.dts    | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

-- 
2.47.3



From francesco at dolcini.it  Thu Dec  4 05:42:19 2025
From: francesco at dolcini.it (Francesco Dolcini)
Date: Thu,  4 Dec 2025 14:42:19 +0100
Subject: [PATCH v1 2/2] arm64: dts: ti: k3-am69-aquila-clover: Fix USB-C Sink PDO
In-Reply-To: <20251204134220.129304-1-francesco@dolcini.it>
References: <20251204134220.129304-1-francesco@dolcini.it>
Message-ID: <20251204134220.129304-3-francesco@dolcini.it>

From: Francesco Dolcini <francesco.dolcini at toradex.com>

Change USB-C Sink PDO and the amount of power that the device can sink
to zero to maximize compatibility with other USB peers (the Aquila
Clover Board is not sinking any current, it is self powered).

Fixes: 9f748a6177e1 ("arm64: dts: ti: am69-aquila: Add Clover")
Signed-off-by: Francesco Dolcini <francesco.dolcini at toradex.com>
---
 arch/arm64/boot/dts/ti/k3-am69-aquila-clover.dts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/ti/k3-am69-aquila-clover.dts b/arch/arm64/boot/dts/ti/k3-am69-aquila-clover.dts
index 55fd214a82e4..c816ba3bfbdf 100644
--- a/arch/arm64/boot/dts/ti/k3-am69-aquila-clover.dts
+++ b/arch/arm64/boot/dts/ti/k3-am69-aquila-clover.dts
@@ -280,8 +280,8 @@ connector {
 			try-power-role = "sink";
 			self-powered;
 			source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
-			sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
-			op-sink-microwatt = <1000000>;
+			sink-pdos = <PDO_FIXED(5000, 0, PDO_FIXED_USB_COMM)>;
+			op-sink-microwatt = <0>;
 
 			ports {
 				#address-cells = <1>;
-- 
2.47.3



From francesco at dolcini.it  Thu Dec  4 05:42:18 2025
From: francesco at dolcini.it (Francesco Dolcini)
Date: Thu,  4 Dec 2025 14:42:18 +0100
Subject: [PATCH v1 1/2] arm64: dts: ti: k3-am69-aquila-dev: Fix USB-C Sink PDO
In-Reply-To: <20251204134220.129304-1-francesco@dolcini.it>
References: <20251204134220.129304-1-francesco@dolcini.it>
Message-ID: <20251204134220.129304-2-francesco@dolcini.it>

From: Francesco Dolcini <francesco.dolcini at toradex.com>

Change USB-C Sink PDO and the amount of power that the device can sink
to zero to maximize compatibility with other USB peers (the Aquila
Development Board is not sinking any current, it is self powered).

Fixes: 39ac6623b1d8 ("arm64: dts: ti: Add Aquila AM69 Support")
Signed-off-by: Francesco Dolcini <francesco.dolcini at toradex.com>
---
 arch/arm64/boot/dts/ti/k3-am69-aquila-dev.dts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/ti/k3-am69-aquila-dev.dts b/arch/arm64/boot/dts/ti/k3-am69-aquila-dev.dts
index c7ce804eac70..f48601ae38b7 100644
--- a/arch/arm64/boot/dts/ti/k3-am69-aquila-dev.dts
+++ b/arch/arm64/boot/dts/ti/k3-am69-aquila-dev.dts
@@ -399,8 +399,8 @@ connector {
 			try-power-role = "sink";
 			self-powered;
 			source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
-			sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
-			op-sink-microwatt = <1000000>;
+			sink-pdos = <PDO_FIXED(5000, 0, PDO_FIXED_USB_COMM)>;
+			op-sink-microwatt = <0>;
 
 			ports {
 				#address-cells = <1>;
-- 
2.47.3



From mike.leach at linaro.org  Thu Dec  4 05:45:46 2025
From: mike.leach at linaro.org (Mike Leach)
Date: Thu, 4 Dec 2025 13:45:46 +0000
Subject: [PATCH 4/7] perf cs-etm: Don't use hard coded config bits when
 setting up ETMCR
In-Reply-To: <96c54895-cebe-4247-86e6-d41b8be0dd40@linaro.org>
References: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
 <20251201-james-perf-config-bits-v1-4-22ecbbf8007c@linaro.org>
 <20251202114300.GV724103@e132581.arm.com> <53b24702-eb3b-4e08-bca3-70402eaf4db5@linaro.org>
 <96c54895-cebe-4247-86e6-d41b8be0dd40@linaro.org>
Message-ID: <CAJ9a7Vgn+HBSO0d3s-x+vjqk3Zfm2shpW1di12_OEZVSN6S0yw@mail.gmail.com>

Hi,

On Thu, 4 Dec 2025 at 10:55, James Clark <james.clark at linaro.org> wrote:
>
>
>
> On 02/12/2025 11:53 am, James Clark wrote:
> >
> >
> > On 02/12/2025 11:43 am, Leo Yan wrote:
> >> On Mon, Dec 01, 2025 at 04:41:07PM +0000, Coresight ML wrote:
> >>
> >> [...]
> >>
> >>> @@ -746,7 +779,7 @@ static void cs_etm_get_metadata(struct perf_cpu
> >>> cpu, u32 *offset,
> >>>       case CS_ETMV3:
> >>>           magic = __perf_cs_etmv3_magic;
> >>>           /* Get configuration register */
> >>> -        info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr);
> >>> +        info->priv[*offset + CS_ETM_ETMCR] = cs_etm_guess_etmcr(itr);
> >>
> >> I still think cs_etm_get_config() is better than cs_etm_guess_etmcr().
> >>
> >> For ETMv3, we directly pass CONFIG to the kernel, and after validation
> >> in the dirver, then the value will be set to ETMCR.  If we already know
> >> the config value is consistent between user space and kernel, why
>
> One other note is that since moving the timestamp field, this is no
> longer true either. The value in attr.config isn't directly put into ETMCR.
>
> >> introduce a redundant "guess" operation here?
> >>
> >> Thanks,
> >> Leo
> >
> > Because userspace doesn't always come up with the same value as the
> > driver. For example right now in ETM3, ETMCR_RETURN_STACK isn't set
> > depending on certain conditions that userspace doesn't know about.  ETM4
> > has the same for TRCCONFIGR_RS and maybe some others. In the future,
> > other versions of the driver could do different things as long as we
> > don't break decoding.
> >
> > I didn't want the function name to imply it was doing something it
> > wasn't as that confused me a little bit. It's definitely not "getting"
> > the value. Maybe "guess" isn't the best it could be, but it's not far off.
> >
>

Perhaps cs_etm_synth_etmcr()? We cannot read it directly as it has not
been set at the time of creating these headers. (unlike the sets of
static read only IDR regs that we do read).

When in perf mode the only configuration bits set in the ConfigR for
either ETM3 or 4 are those generated or implied by parameters on the
perf command line.
This info has to pass from perf to the driver somehow. Evidently many
years ago, when only ETMv3/PTM existed the easy way was perf.config ==
etm.configr, now that is no longer feasible.
As long as perf and the drivers interpret the command line attributes
in the same way - all is well.

As James says, the actual configr can differ from the synth one - the
key is the bits that control the trace format - e.g. cyclecounts,
rather than trace filtering e.g. userspace/kernel that affects the
drivers configr but not the synthesized value in perf.
Decode cares about format, not about filtering. Additionally some
things - like return-stack are implementation dependent - optional on
PTM, not at all on ETMv3. If the trace unit does not support it then
the drivers ignore this. the only effect on the trace output is less
compression if retstack cannot be used.

Generally decode needs to know about things that affect format and
function, rather than filtering.

Mike
-- 
Mike Leach
Principal Engineer, ARM Ltd.
Manchester Design Centre. UK


From james.clark at linaro.org  Thu Dec  4 05:48:40 2025
From: james.clark at linaro.org (James Clark)
Date: Thu, 4 Dec 2025 13:48:40 +0000
Subject: [PATCH 4/7] perf cs-etm: Don't use hard coded config bits when
 setting up ETMCR
In-Reply-To: <CAJ9a7Vgn+HBSO0d3s-x+vjqk3Zfm2shpW1di12_OEZVSN6S0yw@mail.gmail.com>
References: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
 <20251201-james-perf-config-bits-v1-4-22ecbbf8007c@linaro.org>
 <20251202114300.GV724103@e132581.arm.com>
 <53b24702-eb3b-4e08-bca3-70402eaf4db5@linaro.org>
 <96c54895-cebe-4247-86e6-d41b8be0dd40@linaro.org>
 <CAJ9a7Vgn+HBSO0d3s-x+vjqk3Zfm2shpW1di12_OEZVSN6S0yw@mail.gmail.com>
Message-ID: <745f9aa8-6f09-46ac-9612-536fa8292825@linaro.org>



On 04/12/2025 1:45 pm, Mike Leach wrote:
> Hi,
> 
> On Thu, 4 Dec 2025 at 10:55, James Clark <james.clark at linaro.org> wrote:
>>
>>
>>
>> On 02/12/2025 11:53 am, James Clark wrote:
>>>
>>>
>>> On 02/12/2025 11:43 am, Leo Yan wrote:
>>>> On Mon, Dec 01, 2025 at 04:41:07PM +0000, Coresight ML wrote:
>>>>
>>>> [...]
>>>>
>>>>> @@ -746,7 +779,7 @@ static void cs_etm_get_metadata(struct perf_cpu
>>>>> cpu, u32 *offset,
>>>>>        case CS_ETMV3:
>>>>>            magic = __perf_cs_etmv3_magic;
>>>>>            /* Get configuration register */
>>>>> -        info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr);
>>>>> +        info->priv[*offset + CS_ETM_ETMCR] = cs_etm_guess_etmcr(itr);
>>>>
>>>> I still think cs_etm_get_config() is better than cs_etm_guess_etmcr().
>>>>
>>>> For ETMv3, we directly pass CONFIG to the kernel, and after validation
>>>> in the dirver, then the value will be set to ETMCR.  If we already know
>>>> the config value is consistent between user space and kernel, why
>>
>> One other note is that since moving the timestamp field, this is no
>> longer true either. The value in attr.config isn't directly put into ETMCR.
>>
>>>> introduce a redundant "guess" operation here?
>>>>
>>>> Thanks,
>>>> Leo
>>>
>>> Because userspace doesn't always come up with the same value as the
>>> driver. For example right now in ETM3, ETMCR_RETURN_STACK isn't set
>>> depending on certain conditions that userspace doesn't know about.  ETM4
>>> has the same for TRCCONFIGR_RS and maybe some others. In the future,
>>> other versions of the driver could do different things as long as we
>>> don't break decoding.
>>>
>>> I didn't want the function name to imply it was doing something it
>>> wasn't as that confused me a little bit. It's definitely not "getting"
>>> the value. Maybe "guess" isn't the best it could be, but it's not far off.
>>>
>>
> 
> Perhaps cs_etm_synth_etmcr()? We cannot read it directly as it has not

synth is a good name, I can use that.

> been set at the time of creating these headers. (unlike the sets of
> static read only IDR regs that we do read).
> 
> When in perf mode the only configuration bits set in the ConfigR for
> either ETM3 or 4 are those generated or implied by parameters on the
> perf command line.
> This info has to pass from perf to the driver somehow. Evidently many
> years ago, when only ETMv3/PTM existed the easy way was perf.config ==
> etm.configr, now that is no longer feasible.
> As long as perf and the drivers interpret the command line attributes
> in the same way - all is well.
> 
> As James says, the actual configr can differ from the synth one - the
> key is the bits that control the trace format - e.g. cyclecounts,
> rather than trace filtering e.g. userspace/kernel that affects the
> drivers configr but not the synthesized value in perf.
> Decode cares about format, not about filtering. Additionally some
> things - like return-stack are implementation dependent - optional on
> PTM, not at all on ETMv3. If the trace unit does not support it then
> the drivers ignore this. the only effect on the trace output is less
> compression if retstack cannot be used.
> 
> Generally decode needs to know about things that affect format and
> function, rather than filtering.
> 
> Mike



From daniel at makrotopia.org  Thu Dec  4 05:50:52 2025
From: daniel at makrotopia.org (Daniel Golle)
Date: Thu, 4 Dec 2025 13:50:52 +0000
Subject: [PATCH v3 2/2] net: dsa: mt7530: Use GPIO polarity to generate
 correct reset sequence
In-Reply-To: <20251204131626.upw77jncqfwxydww@skbuf>
References: <20251129234603.2544-1-ptpt52@gmail.com>
 <20251129234603.2544-2-ptpt52@gmail.com>
 <0675b35f-217d-4261-9e3f-2eb24753d43c@lunn.ch>
 <20251130080731.ty2dlxaypxvodxiw@skbuf>
 <3fbc4e67-b931-421c-9d83-2214aaa2f6ed@lunn.ch>
 <0d85e1e6-ea75-4f20-aef1-90d446b4bfa1@kernel.org>
 <00f308a1-a4b1-4f20-8d8e-459ddf4c39b1@gmx.de>
 <aS7Zj3AFsSp2CTNv@makrotopia.org>
 <20251204131626.upw77jncqfwxydww@skbuf>
Message-ID: <aTGRvADkT-1kAQgA@makrotopia.org>

On Thu, Dec 04, 2025 at 03:16:26PM +0200, Vladimir Oltean wrote:
> On Tue, Dec 02, 2025 at 12:20:31PM +0000, Daniel Golle wrote:
> > On Tue, Dec 02, 2025 at 12:52:44PM +0100, Frank Wunderlich wrote:
> > > Hi,
> > > 
> > > Am 01.12.25 um 08:48 schrieb Krzysztof Kozlowski:
> > > > On 30/11/2025 21:17, Andrew Lunn wrote:
> > > > > On Sun, Nov 30, 2025 at 10:07:31AM +0200, Vladimir Oltean wrote:
> > > > > > On Sun, Nov 30, 2025 at 02:11:05AM +0100, Andrew Lunn wrote:
> > > > > > > > -		gpiod_set_value_cansleep(priv->reset, 0);
> > > > > > > > +		int is_active_low = !!gpiod_is_active_low(priv->reset);
> > > > > > > > +		gpiod_set_value_cansleep(priv->reset, is_active_low);
> > > > > > > I think you did not correctly understand what Russell said. You pass
> > > > > > > the logical value to gpiod_set_value(). If the GPIO has been marked as
> > > > > > > active LOW, the GPIO core will invert the logical values to the raw
> > > > > > > value. You should not be using gpiod_is_active_low().
> > > > > > > 
> > > > > > > But as i said to the previous patch, i would just leave everything as
> > > > > > > it is, except document the issue.
> > > > > > > 
> > > > > > > 	Andrew
> > > > > > > 
> > > > > > It was my suggestion to do it like this (but I don't understand why I'm
> > > > > > again not in CC).
> > > > > > 
> > > > > > We _know_ that the reset pin of the switch should be active low. So by
> > > > > > using gpiod_is_active_low(), we can determine whether the device tree is
> > > > > > wrong or not, and we can work with a wrong device tree too (just invert
> > > > > > the logical values).
> > > > > Assuming there is not a NOT gate placed between the GPIO and the reset
> > > > > pin, because the board designer decided to do that for some reason?
> > > jumping in because i prepare mt7987 / BPI-R4Lite dts for upstreaming when
> > > driver-changes are in.
> > > With current driver i need to define the reset-gpio for mt7531 again wrong
> > > to get it
> > > working. So to have future dts correct, imho this (or similar) change to
> > > driver is needed.
> > > 
> > > Of course we cannot simply say that current value is wrong and just invert
> > > it because of
> > > possible "external" inversion of reset signal between SoC and switch.
> > > I have to look on schematics for the boards i have (BPI-R64, BPI-R3,
> > > BPI-R2Pro) if there is such circuit.
> > 
> > I'm also not aware of any board which doesn't directly connect the
> > reset of the MT7530 to a GPIO pin of the SoC. For MediaTek's designs
> > there is often even a specific pin desginated for this purpose and
> > most vendors do follow this. If they deviate at all, then it's just
> > that a different pin is used for the switch reset, but I've never
> > seen any logic between the SoC's GPIO pin and the switch reset.
> > 
> > > Maybe the mt7988 (mt7530-mmio) based boards also affected?
> > 
> > There is no GPIO reset for switches which are integrated in the SoC,
> > so this only matters for external MT7530 and MT7531 ICs for which an
> > actual GPIO line connected to the SoC is used to reset the switch.
> 
> I get the feeling that we're complicating a simple solution because of a
> theoretical "what if" scenario. The "NOT" gate is somewhat contrived
> given the fact that most GPIOs can already be active high or low, but OK.
> 
> If this is blocking progress for new device trees, can we just construct,
> using of_machine_is_compatible(), a list of all boards where the device
> tree defines incorrect reset polarity that shouldn't be trusted by the
> driver when driving the reset GPIO? If we do this, we can also leave
> those existing device trees alone.

>From OpenWrt's point of view this would be kind of ugly as we would either
have to extend the list of affected boards downstream, or fix the polarity
in some but not all of our downstream DTS files. I'd prefer to rather
have the option to force the "wrong" GPIO polarity for theoretical future
boards with that (very unlikely to ever exist) NOT gate between the SoC
GPIO and switch reset line. That would allow to gradually update boards
to reflect the physical reality and yet the driver would not break if the
GPIO polarity is stated wrongly.


From james.clark at linaro.org  Thu Dec  4 06:08:59 2025
From: james.clark at linaro.org (James Clark)
Date: Thu, 4 Dec 2025 14:08:59 +0000
Subject: [PATCH 6/7] perf cs-etm: Don't hard code config attribute when
 configuring the event
In-Reply-To: <20251202121528.GX724103@e132581.arm.com>
References: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
 <20251201-james-perf-config-bits-v1-6-22ecbbf8007c@linaro.org>
 <20251202121528.GX724103@e132581.arm.com>
Message-ID: <857538e7-cac2-4871-9711-4c434420df8a@linaro.org>



On 02/12/2025 12:15 pm, Leo Yan wrote:
> On Mon, Dec 01, 2025 at 04:41:09PM +0000, Coresight ML wrote:
> 
> [...]
> 
>> @@ -103,13 +103,20 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
>>   				      struct perf_cpu cpu)
>>   {
>>   	int err;
>> -	__u64 val;
>> -	u64 contextid = evsel->core.attr.config &
>> -		(perf_pmu__format_bits(cs_etm_pmu, "contextid") |
>> -		 perf_pmu__format_bits(cs_etm_pmu, "contextid1") |
>> -		 perf_pmu__format_bits(cs_etm_pmu, "contextid2"));
>> +	u64 ctxt, ctxt1, ctxt2;
>> +	__u64 trcidr2;
>>   
>> -	if (!contextid)
>> +	err = evsel__get_config_val(cs_etm_pmu, evsel, "contextid", &ctxt);
>> +	if (err)
>> +		return err;
>> +	err = evsel__get_config_val(cs_etm_pmu, evsel, "contextid1", &ctxt1);
>> +	if (err)
>> +		return err;
>> +	err = evsel__get_config_val(cs_etm_pmu, evsel, "contextid2", &ctxt2);
>> +	if (err)
>> +		return err;
> 
> Seems to me, this is not right.  The current code checks any context
> ID setting but it can tolerate if missing "contexid[*]" format.
> 
> After calling evsel__get_config_val(), if any "contextid[*]" format is
> missed, it returns error and will diretly bail out.  As a result,
> cs_etm_validate_context_id() will always return error.
> 

Missed by the driver or the user? evsel__get_config_val() only returns 
an error when "contextid" isn't published by the driver, not when the 
user doesn't supply one of those options. The actual user supplied value 
is in the out param, not the return value.

Having said that, this does make it an error if the driver did stop 
publishing one, which might be too inflexible and is a new behavior. I 
can change to it ignore the errors instead.

>> +
>> +	if (!ctxt && !ctxt1 && !ctxt2)
>>   		return 0;
>>   
>>   	/* Not supported in etmv3 */
>> @@ -120,12 +127,11 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
>>   	}
>>   
>>   	/* Get a handle on TRCIDR2 */
>> -	err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2], &val);
>> +	err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2], &trcidr2);
>>   	if (err)
>>   		return err;
>>   
>> -	if (contextid &
>> -	    perf_pmu__format_bits(cs_etm_pmu, "contextid1")) {
>> +	if (ctxt1) {
>>   		/*
>>   		 * TRCIDR2.CIDSIZE, bit [9-5], indicates whether contextID
>>   		 * tracing is supported:
>> @@ -133,15 +139,14 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
>>   		 *  0b00100 Maximum of 32-bit Context ID size.
>>   		 *  All other values are reserved.
>>   		 */
>> -		if (BMVAL(val, 5, 9) != 0x4) {
>> +		if (BMVAL(trcidr2, 5, 9) != 0x4) {
>>   			pr_err("%s: CONTEXTIDR_EL1 isn't supported, disable with %s/contextid1=0/\n",
>>   			       CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME);
>>   			return -EINVAL;
>>   		}
>>   	}
>>   
>> -	if (contextid &
>> -	    perf_pmu__format_bits(cs_etm_pmu, "contextid2")) {
>> +	if (ctxt2) {
>>   		/*
>>   		 * TRCIDR2.VMIDOPT[30:29] != 0 and
>>   		 * TRCIDR2.VMIDSIZE[14:10] == 0b00100 (32bit virtual contextid)
>> @@ -149,7 +154,7 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
>>   		 * virtual context id is < 32bit.
>>   		 * Any value of VMIDSIZE >= 4 (i.e, > 32bit) is fine for us.
>>   		 */
>> -		if (!BMVAL(val, 29, 30) || BMVAL(val, 10, 14) < 4) {
>> +		if (!BMVAL(trcidr2, 29, 30) || BMVAL(trcidr2, 10, 14) < 4) {
>>   			pr_err("%s: CONTEXTIDR_EL2 isn't supported, disable with %s/contextid2=0/\n",
>>   			       CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME);
>>   			return -EINVAL;
>> @@ -163,10 +168,14 @@ static int cs_etm_validate_timestamp(struct perf_pmu *cs_etm_pmu, struct evsel *
>>   				     struct perf_cpu cpu)
>>   {
>>   	int err;
>> -	__u64 val;
>> +	u64 val;
>> +	__u64 trcidr0;
>>   
>> -	if (!(evsel->core.attr.config &
>> -	      perf_pmu__format_bits(cs_etm_pmu, "timestamp")))
>> +	err = evsel__get_config_val(cs_etm_pmu, evsel, "timestamp", &val);
>> +	if (err)
>> +		return err;
>> +
>> +	if (!val)
>>   		return 0;
> 
> Similiar issue here.  The current code returns 0 if not find "timestamp"
> format.  With this change, it returns error instead.
> 
> Thanks,
> Leo



From christianshewitt at gmail.com  Thu Dec  4 06:13:29 2025
From: christianshewitt at gmail.com (Christian Hewitt)
Date: Thu, 4 Dec 2025 18:13:29 +0400
Subject: [PATCH] arm64: dts: rockchip: add SPDIF audio to Beelink A1
In-Reply-To: <f0df035f-3c3d-4649-9f48-3e8e2e69d17b@gmail.com>
References: <20250828164300.3829488-1-christianshewitt@gmail.com>
 <66ae20b3-3316-4ec2-9c51-8414c053dc32@arm.com>
 <f0df035f-3c3d-4649-9f48-3e8e2e69d17b@gmail.com>
Message-ID: <5557C31E-3B1D-426C-BF9F-C417FF29E97C@gmail.com>

> On 4 Dec 2025, at 12:23?am, Alex Bee <knaerzche at gmail.com> wrote:
> 
> Hi Robin,
> 
> Am 03.12.25 um 17:21 schrieb Robin Murphy:
>> [ Just noticed this... ]
>> 
>> On 2025-08-28 5:43 pm, Christian Hewitt wrote:
>>> From: Alex Bee <knaerzche at gmail.com>
>>> 
>>> Add the required nodes to enable SPDIF audio output on
>>> the Beelink A1 set-top-box.
>> 
>> But the A1 doesn't have S/PDIF? Only HDMI plus a 3.5mm jack connected to the analog audio codec (and possibly the composite TV out) :/
>> 
> Yeah, sorry - this patch wasn't supposed to be submitted upstream.

Apologies, this is my enthusiasm for trying to clear out the patch
collection LibreELEC has been hoarding by sending things upstream
on behalf of the original authors (and hoarders).

Would you like me to send a revert patch?

Christian

> Regards,
> 
> Alex
> 
>> Thanks,
>> Robin.
>> 
>>> Signed-off-by: Alex Bee <knaerzche at gmail.com>
>>> Signed-off-by: Christian Hewitt <christianshewitt at gmail.com>
>>> ---
>>>   arch/arm64/boot/dts/rockchip/rk3328-a1.dts | 23 ++++++++++++++++++++++
>>>   1 file changed, 23 insertions(+)
>>> 
>>> diff --git a/arch/arm64/boot/dts/rockchip/rk3328-a1.dts b/arch/arm64/boot/dts/rockchip/rk3328-a1.dts
>>> index f7c4578865c5..b276a29bdd85 100644
>>> --- a/arch/arm64/boot/dts/rockchip/rk3328-a1.dts
>>> +++ b/arch/arm64/boot/dts/rockchip/rk3328-a1.dts
>>> @@ -58,6 +58,24 @@ ir-receiver {
>>>           gpios = <&gpio2 RK_PA2 GPIO_ACTIVE_LOW>;
>>>           linux,rc-map-name = "rc-beelink-gs1";
>>>       };
>>> +
>>> +    spdif_sound: spdif-sound {
>>> +        compatible = "simple-audio-card";
>>> +        simple-audio-card,name = "SPDIF";
>>> +
>>> +        simple-audio-card,cpu {
>>> +            sound-dai = <&spdif>;
>>> +        };
>>> +
>>> +        simple-audio-card,codec {
>>> +            sound-dai = <&spdif_dit>;
>>> +        };
>>> +    };
>>> +
>>> +    spdif_dit: spdif-dit {
>>> +        compatible = "linux,spdif-dit";
>>> +        #sound-dai-cells = <0>;
>>> +    };
>>>   };
>>>     &analog_sound {
>>> @@ -325,6 +343,11 @@ &sdmmc {
>>>       status = "okay";
>>>   };
>>>   +&spdif {
>>> +    pinctrl-0 = <&spdifm0_tx>;
>>> +    status = "okay";
>>> +};
>>> +
>>>   &tsadc {
>>>       rockchip,hw-tshut-mode = <0>;
>>>       rockchip,hw-tshut-polarity = <0>;



From maz at kernel.org  Thu Dec  4 06:21:51 2025
From: maz at kernel.org (Marc Zyngier)
Date: Thu, 04 Dec 2025 14:21:51 +0000
Subject: [PATCH v4 16/26] genirq: Allow per-cpu interrupt sharing for non-overlapping affinities
In-Reply-To: <aTFozefMQRg7lYxh@aspen.lan>
References: <20251020122944.3074811-1-maz@kernel.org>
	<20251020122944.3074811-17-maz@kernel.org>
	<aTFozefMQRg7lYxh@aspen.lan>
Message-ID: <867bv2pbsw.wl-maz@kernel.org>

On Thu, 04 Dec 2025 10:56:13 +0000,
Daniel Thompson <danielt at kernel.org> wrote:
> 
> On Mon, Oct 20, 2025 at 01:29:33PM +0100, Marc Zyngier wrote:
> > Interrupt sharing for percpu-devid interrupts is forbidden, and
> > for good reasons. These are interrupts generated *from* a CPU and
> > handled by itself (timer, for example). Nobody in their right mind
> > would put two devices on the same pin (and if they have, they get to
> > keep the pieces...).
> >
> > But this also prevents more benign cases, where devices are connected
> > to groups of CPUs, and for which the affinities are not overlapping.
> > Effectively, the only thing they share is the interrupt number, and
> > nothing else.
> >
> > Let's tweak the definition of IRQF_SHARED applied to percpu_devid
> > interrupts to allow this particular case. This results in extra
> > validation at the point of the interrupt being setup and freed,
> > as well as a tiny bit of extra complexity for interrupts at handling
> > time (to pick the correct irqaction).
> >
> > Tested-by: Will Deacon <will at kernel.org>
> > Signed-off-by: Marc Zyngier <maz at kernel.org>
> 
> I picked up this patch via linux-next and it appears be causing boot
> regressions on MIPS/qemu. This patch was identified with a bisect and
> a git revert of this patch from the linux-next tip resolves the problem
> (specifically, next-20251204 with git revert bdf4e2ac295f).
> 
> I'm running the code as part of the kgdb test suite but the system
> doesn't survive long enough for kgdb to be involved. In fact I was able
> to reduce things to the following reproduction with all the kgdb pieces
> removed:
> 
>     make malta_kvm_defconfig generic/64r6.config
>     ../scripts/config \
>         --enable WERROR --enable CPU_MIPS64_R6 --enable MIPS_CPS \
> 	--enable BLK_DEV_INITRD --set-val FRAME_WARN 2048
>     make olddefconfig
>     make -j$(nproc) all
>     qemu-system-mips64el -cpu I6400 -M malta -m 1G -smp 2 \
>         -kernel vmlinux -nographic \
> 	-append " console=ttyS0,115200 clk_ignore_unused"

Many thanks for the minimal reproducer, that really helped a lot!

[...]

> CPU 0 Unable to handle kernel paging request at virtual address 0000000000000000, epc == ffffffff801c2398, ra == ffffffff801bab00
> Oops[#1]:
> CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted 6.18.0-next-20251204 #20 NONE
> Hardware name: mti,malta
> $ 0   : 0000000000000000 0000000000000001 0000000000000000 0000000000000000
> $ 4   : 0000000000000001 a8000000020e8008 0000000000000000 ffffffff80c23b80
> $ 8   : 0000000000000004 0000000000000000 0000000000000000 000000000000002f
> $12   : a8000000020f4000 0000000000003ff0 0000000000003000 0000000000000003
> $16   : ffffffff80d095c0 ffffffff80ceb410 0000000000000019 ffffffff80c378c0
> $20   : ffffffff80c4bec8 0000000000000000 ffffffff80e00000 ffffffff80de0000
> $24   : 0000000000000000 0000000000000010
> $28   : ffffffff80c20000 a8000000020f7ec0 a800000000e12fcd ffffffff801bab00
> epc   : ffffffff801c2398 handle_percpu_devid_irq+0xb8/0x250
> ra    : ffffffff801bab00 handle_irq_desc+0x48/0x88
> Status: 1400a4e2	KX SX UX KERNEL EXL
> Cause : 00800408 (ExcCode 02)
> BadVA : 0000000000000000
> PrId  : 0001a900 (MIPS I6400)
> Modules linked in:
> Process swapper/0 (pid: 0, threadinfo=(____ptrval____), task=(____ptrval____), tls=0000000000000000)
> Stack : ffffffff80c35a2c 0000000000000002 ffffffff80e00000 0fffffffffffffff
>         ffffffff80c50000 0000000000000001 0000000000000003 ffffffff801bab00
>         0000000000000000 ffffffff805d82a8 0000000000000000 0000000000000008
>         0000000000000000 0000000000000000 0000000000000000 5189d95a7a4f4800
>         a800000002014300 0000000000000002 0000000000000001 000000000000001f
>         ffffffff80e00000 0000000000000004 0000000000000000 ffffffff801bab00
>         0000000000000000 ffffffff809ec128 0000000000000001 fffffffffffffffb
>         0000000000000001 ffffffff805d7ebc 0000000000000000 0000000000000000
>         ffffffff80c23c80 ffffffff80c50000 ffffffff80de0000 ffffffff80db0000
>         0000000000000000 ffffffff80112f10 ffffffff80c23c80 0000000000000000
> Call Trace:
> [<ffffffff801c2398>] handle_percpu_devid_irq+0xb8/0x250
> [<ffffffff801bab00>] handle_irq_desc+0x48/0x88
> [<ffffffff805d82a8>] gic_irq_dispatch+0xc0/0x288
> [<ffffffff801bab00>] handle_irq_desc+0x48/0x88
> [<ffffffff809ec128>] do_domain_IRQ+0x28/0x40
> [<ffffffff805d7ebc>] plat_irq_dispatch+0x64/0xe8
> [<ffffffff80112f10>] handle_int+0x134/0x140
> [<ffffffff80110dc8>] calibrate_delay+0x158/0x290
> [<ffffffff80d58e48>] start_kernel+0x754/0x7a4

This hack fixes it for me, but really, mips needs to grow up and stop
using these antiquated APIs.

Can please you give it a go?

Thanks,

	M.

diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 0bb29316b4362..8b1b4c8a4f54c 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -2470,6 +2470,9 @@ int setup_percpu_irq(unsigned int irq, struct irqaction *act)
 	if (retval < 0)
 		return retval;
 
+	if (!act->affinity)
+		act->affinity = cpu_online_mask;
+
 	retval = __setup_irq(irq, desc, act);
 
 	if (retval)

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


From robin.murphy at arm.com  Thu Dec  4 06:33:36 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Thu, 4 Dec 2025 14:33:36 +0000
Subject: [PATCH] arm64: dts: rockchip: add SPDIF audio to Beelink A1
In-Reply-To: <5557C31E-3B1D-426C-BF9F-C417FF29E97C@gmail.com>
References: <20250828164300.3829488-1-christianshewitt@gmail.com>
 <66ae20b3-3316-4ec2-9c51-8414c053dc32@arm.com>
 <f0df035f-3c3d-4649-9f48-3e8e2e69d17b@gmail.com>
 <5557C31E-3B1D-426C-BF9F-C417FF29E97C@gmail.com>
Message-ID: <43f9753d-2e63-4b52-a4af-ca8d22f0b351@arm.com>

On 2025-12-04 2:13 pm, Christian Hewitt wrote:
>> On 4 Dec 2025, at 12:23?am, Alex Bee <knaerzche at gmail.com> wrote:
>>
>> Hi Robin,
>>
>> Am 03.12.25 um 17:21 schrieb Robin Murphy:
>>> [ Just noticed this... ]
>>>
>>> On 2025-08-28 5:43 pm, Christian Hewitt wrote:
>>>> From: Alex Bee <knaerzche at gmail.com>
>>>>
>>>> Add the required nodes to enable SPDIF audio output on
>>>> the Beelink A1 set-top-box.
>>>
>>> But the A1 doesn't have S/PDIF? Only HDMI plus a 3.5mm jack connected to the analog audio codec (and possibly the composite TV out) :/
>>>
>> Yeah, sorry - this patch wasn't supposed to be submitted upstream.
> 
> Apologies, this is my enthusiasm for trying to clear out the patch
> collection LibreELEC has been hoarding by sending things upstream
> on behalf of the original authors (and hoarders).

No worries :)

> Would you like me to send a revert patch?

Since I'm the only one complaining, and I'm liable to have a couple more 
Rockchip DT patches to send soon anyway, feel free to leave it with me 
unless you're particularly keen.

Cheers,
Robin.

> 
> Christian
> 
>> Regards,
>>
>> Alex
>>
>>> Thanks,
>>> Robin.
>>>
>>>> Signed-off-by: Alex Bee <knaerzche at gmail.com>
>>>> Signed-off-by: Christian Hewitt <christianshewitt at gmail.com>
>>>> ---
>>>>    arch/arm64/boot/dts/rockchip/rk3328-a1.dts | 23 ++++++++++++++++++++++
>>>>    1 file changed, 23 insertions(+)
>>>>
>>>> diff --git a/arch/arm64/boot/dts/rockchip/rk3328-a1.dts b/arch/arm64/boot/dts/rockchip/rk3328-a1.dts
>>>> index f7c4578865c5..b276a29bdd85 100644
>>>> --- a/arch/arm64/boot/dts/rockchip/rk3328-a1.dts
>>>> +++ b/arch/arm64/boot/dts/rockchip/rk3328-a1.dts
>>>> @@ -58,6 +58,24 @@ ir-receiver {
>>>>            gpios = <&gpio2 RK_PA2 GPIO_ACTIVE_LOW>;
>>>>            linux,rc-map-name = "rc-beelink-gs1";
>>>>        };
>>>> +
>>>> +    spdif_sound: spdif-sound {
>>>> +        compatible = "simple-audio-card";
>>>> +        simple-audio-card,name = "SPDIF";
>>>> +
>>>> +        simple-audio-card,cpu {
>>>> +            sound-dai = <&spdif>;
>>>> +        };
>>>> +
>>>> +        simple-audio-card,codec {
>>>> +            sound-dai = <&spdif_dit>;
>>>> +        };
>>>> +    };
>>>> +
>>>> +    spdif_dit: spdif-dit {
>>>> +        compatible = "linux,spdif-dit";
>>>> +        #sound-dai-cells = <0>;
>>>> +    };
>>>>    };
>>>>      &analog_sound {
>>>> @@ -325,6 +343,11 @@ &sdmmc {
>>>>        status = "okay";
>>>>    };
>>>>    +&spdif {
>>>> +    pinctrl-0 = <&spdifm0_tx>;
>>>> +    status = "okay";
>>>> +};
>>>> +
>>>>    &tsadc {
>>>>        rockchip,hw-tshut-mode = <0>;
>>>>        rockchip,hw-tshut-polarity = <0>;
> 



From leo.yan at arm.com  Thu Dec  4 06:43:36 2025
From: leo.yan at arm.com (Leo Yan)
Date: Thu, 4 Dec 2025 14:43:36 +0000
Subject: [PATCH 6/7] perf cs-etm: Don't hard code config attribute when
 configuring the event
In-Reply-To: <857538e7-cac2-4871-9711-4c434420df8a@linaro.org>
References: <20251201-james-perf-config-bits-v1-0-22ecbbf8007c@linaro.org>
 <20251201-james-perf-config-bits-v1-6-22ecbbf8007c@linaro.org>
 <20251202121528.GX724103@e132581.arm.com>
 <857538e7-cac2-4871-9711-4c434420df8a@linaro.org>
Message-ID: <20251204144336.GN724103@e132581.arm.com>

On Thu, Dec 04, 2025 at 02:08:59PM +0000, James Clark wrote:

[...]

> > > +	err = evsel__get_config_val(cs_etm_pmu, evsel, "contextid", &ctxt);
> > > +	if (err)
> > > +		return err;
> > > +	err = evsel__get_config_val(cs_etm_pmu, evsel, "contextid1", &ctxt1);
> > > +	if (err)
> > > +		return err;
> > > +	err = evsel__get_config_val(cs_etm_pmu, evsel, "contextid2", &ctxt2);
> > > +	if (err)
> > > +		return err;
> > 
> > Seems to me, this is not right.  The current code checks any context
> > ID setting but it can tolerate if missing "contexid[*]" format.
> > 
> > After calling evsel__get_config_val(), if any "contextid[*]" format is
> > missed, it returns error and will diretly bail out.  As a result,
> > cs_etm_validate_context_id() will always return error.
> > 
> 
> Missed by the driver or the user? evsel__get_config_val() only returns an
> error when "contextid" isn't published by the driver, not when the user
> doesn't supply one of those options. The actual user supplied value is in
> the out param, not the return value.

My question is for missing format from user.  Thanks for reminding the
error is only for driver's publishing.

> Having said that, this does make it an error if the driver did stop
> publishing one, which might be too inflexible and is a new behavior. I can
> change to it ignore the errors instead.

Yeah, this will likely break nVHE / pKVM cases.

Thanks,
Leo


From krzk at kernel.org  Thu Dec  4 06:49:52 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 4 Dec 2025 15:49:52 +0100
Subject: [PATCH v3 2/2] net: dsa: mt7530: Use GPIO polarity to generate
 correct reset sequence
In-Reply-To: <20251204131626.upw77jncqfwxydww@skbuf>
References: <20251129234603.2544-1-ptpt52@gmail.com>
 <20251129234603.2544-2-ptpt52@gmail.com>
 <0675b35f-217d-4261-9e3f-2eb24753d43c@lunn.ch>
 <20251130080731.ty2dlxaypxvodxiw@skbuf>
 <3fbc4e67-b931-421c-9d83-2214aaa2f6ed@lunn.ch>
 <0d85e1e6-ea75-4f20-aef1-90d446b4bfa1@kernel.org>
 <00f308a1-a4b1-4f20-8d8e-459ddf4c39b1@gmx.de>
 <aS7Zj3AFsSp2CTNv@makrotopia.org> <20251204131626.upw77jncqfwxydww@skbuf>
Message-ID: <4170c560-1edd-4ff8-96af-a479063be4a5@kernel.org>

On 04/12/2025 14:16, Vladimir Oltean wrote:
> On Tue, Dec 02, 2025 at 12:20:31PM +0000, Daniel Golle wrote:
>> On Tue, Dec 02, 2025 at 12:52:44PM +0100, Frank Wunderlich wrote:
>>> Hi,
>>>
>>> Am 01.12.25 um 08:48 schrieb Krzysztof Kozlowski:
>>>> On 30/11/2025 21:17, Andrew Lunn wrote:
>>>>> On Sun, Nov 30, 2025 at 10:07:31AM +0200, Vladimir Oltean wrote:
>>>>>> On Sun, Nov 30, 2025 at 02:11:05AM +0100, Andrew Lunn wrote:
>>>>>>>> -		gpiod_set_value_cansleep(priv->reset, 0);
>>>>>>>> +		int is_active_low = !!gpiod_is_active_low(priv->reset);
>>>>>>>> +		gpiod_set_value_cansleep(priv->reset, is_active_low);
>>>>>>> I think you did not correctly understand what Russell said. You pass
>>>>>>> the logical value to gpiod_set_value(). If the GPIO has been marked as
>>>>>>> active LOW, the GPIO core will invert the logical values to the raw
>>>>>>> value. You should not be using gpiod_is_active_low().
>>>>>>>
>>>>>>> But as i said to the previous patch, i would just leave everything as
>>>>>>> it is, except document the issue.
>>>>>>>
>>>>>>> 	Andrew
>>>>>>>
>>>>>> It was my suggestion to do it like this (but I don't understand why I'm
>>>>>> again not in CC).
>>>>>>
>>>>>> We _know_ that the reset pin of the switch should be active low. So by
>>>>>> using gpiod_is_active_low(), we can determine whether the device tree is
>>>>>> wrong or not, and we can work with a wrong device tree too (just invert
>>>>>> the logical values).
>>>>> Assuming there is not a NOT gate placed between the GPIO and the reset
>>>>> pin, because the board designer decided to do that for some reason?
>>> jumping in because i prepare mt7987 / BPI-R4Lite dts for upstreaming when
>>> driver-changes are in.
>>> With current driver i need to define the reset-gpio for mt7531 again wrong
>>> to get it
>>> working. So to have future dts correct, imho this (or similar) change to
>>> driver is needed.
>>>
>>> Of course we cannot simply say that current value is wrong and just invert
>>> it because of
>>> possible "external" inversion of reset signal between SoC and switch.
>>> I have to look on schematics for the boards i have (BPI-R64, BPI-R3,
>>> BPI-R2Pro) if there is such circuit.
>>
>> I'm also not aware of any board which doesn't directly connect the
>> reset of the MT7530 to a GPIO pin of the SoC. For MediaTek's designs
>> there is often even a specific pin desginated for this purpose and
>> most vendors do follow this. If they deviate at all, then it's just
>> that a different pin is used for the switch reset, but I've never
>> seen any logic between the SoC's GPIO pin and the switch reset.
>>
>>> Maybe the mt7988 (mt7530-mmio) based boards also affected?
>>
>> There is no GPIO reset for switches which are integrated in the SoC,
>> so this only matters for external MT7530 and MT7531 ICs for which an
>> actual GPIO line connected to the SoC is used to reset the switch.
> 
> I get the feeling that we're complicating a simple solution because of a
> theoretical "what if" scenario. The "NOT" gate is somewhat contrived

You downplay this case and suggest (if I get it right) that NOT gate is
something unusual.

 I mentioned "line inverter" but it's not about NOT gate. There is no
need for NOT gate at all, like some magical component which no one puts
to the board. The only thing needed is just to pull the GPIO up or down,
that's it. It's completely normal design thus it CAN happen.

Of course "can" does not mean it actually does, because certain
configurations like powerdown-fail-safe are more likely and I am not an
electric circuit designer to tell which one is better, but that
downplaying does not help here.

Just to clarify: I expect clear communication that some users will be
broken with as good as you can provide analysis of the impact (which
users). I only object the clame here "no one can ever pull down a GPIO
line thus I handled all possible cases and made it backward compatible".

And that claim to quote was:
"Therefore, regardless of whether a DTS is old or new, correct or
incorrect, the driver now generates the correct electrical reset pulse."

which is 100% false and I am surprised how one could claim that.


> given the fact that most GPIOs can already be active high or low, but OK.
> 
> If this is blocking progress for new device trees, can we just construct,
> using of_machine_is_compatible(), a list of all boards where the device
> tree defines incorrect reset polarity that shouldn't be trusted by the
> driver when driving the reset GPIO? If we do this, we can also leave
> those existing device trees alone.

Works for me. You can also print fat warning for every unusual case.
Nothing like that was here in the original patch...


Best regards,
Krzysztof


From mike.leach at linaro.org  Thu Dec  4 07:07:10 2025
From: mike.leach at linaro.org (Mike Leach)
Date: Thu, 4 Dec 2025 15:07:10 +0000
Subject: [PATCH v6 2/2] coresight: cti: Add Qualcomm extended CTI support
In-Reply-To: <20251204104713.GL724103@e132581.arm.com>
References: <20251202-extended_cti-v6-0-ab68bb15c4f5@oss.qualcomm.com>
 <20251202-extended_cti-v6-2-ab68bb15c4f5@oss.qualcomm.com>
 <20251203182944.GG724103@e132581.arm.com> <CAJ9a7VhcSxTTaxMR4SS+GbHoPHXm0honykjXy92fbv0HG=1o4Q@mail.gmail.com>
 <20251204104713.GL724103@e132581.arm.com>
Message-ID: <CAJ9a7VgV6chvWmeG2xta11YqyNpdRZqx4=EF7vC7k=J2utpRYQ@mail.gmail.com>

Hi Leo

On Thu, 4 Dec 2025 at 10:47, Leo Yan <leo.yan at arm.com> wrote:
>
> On Thu, Dec 04, 2025 at 09:15:07AM +0000, Mike Leach wrote:
>
> [...]
>
> > > > +             /*
> > > > +              * QCOM CTI does not implement Claimtag functionality as
> > > > +              * per CoreSight specification, but its CLAIMSET register
> > > > +              * is incorrectly initialized to 0xF. This can mislead
> > > > +              * tools or drivers into thinking the component is claimed.
> > > > +              *
> > > > +              * Reset CLAIMSET to 0 to reflect that no claims are active.
> > > > +              */
> > > > +             writel_relaxed(0, drvdata->base + CORESIGHT_CLAIMSET);
> > >
> > > I am confused for this.  If QCOM CTI does not implement claim tag,
> > > then what is the designed register at the offset CORESIGHT_CLAIMSET?
> > >
> > > Should you bypass all claim tag related operations for QCOM CTI case?
> > > (I don't see you touch anything for claim and declaim tags).
> > >
> >
> > The patch I have created to handle systems without correct claim tag
> > operation is a dependency for this patch set. Thus no need for
> > override here as the core code will handle this correctly.
> >
> > The only issue is ensuring the non-CTI spec implementation will result
> > in the correct detection of no claim tags present.
>
> Your patch works only when a module has implemented claim registers.
>

Per the Coresight spec - unimplemented registers must be RAZ/WI- so
this still works for non implemented claim registers.

> This leads to two issues: we end up clearing an unknown register in the
> CTI driver, and then the coresight core layer assumes it is reading a
> claim register even though it is not.

Again RAZ will simply read 0x0 - which is an indication that there are
no claim bits implemented.

>
> For QCOM CTI, combined with your patch, I would suggest directly
> setting csdev->access.claim_tag_impl to false (perhaps using a helper).

That would be a better solution, though as Qcom appear to have
implemented a pair of standard RW registers rather than the claim tag
functionality, the write solution works for this particular
implementation.

Regards

Mike

> This would be much clearer than the "hacking" way.
>
> Thanks,
> Leo



-- 
Mike Leach
Principal Engineer, ARM Ltd.
Manchester Design Centre. UK


From dave.jiang at intel.com  Thu Dec  4 07:07:53 2025
From: dave.jiang at intel.com (Dave Jiang)
Date: Thu, 4 Dec 2025 08:07:53 -0700
Subject: [PATCH v2 1/2] dmaengine: Add cleanup FREE defines for
 dma_async_tx_descriptor
In-Reply-To: <aTDkODHZg0JfrZJC@lizhi-Precision-Tower-5810>
References: <20251003-dma_chan_free-v2-0-564946b6c563@nxp.com>
 <20251003-dma_chan_free-v2-1-564946b6c563@nxp.com>
 <2c457a46-2b7f-4d66-8555-3b3cb52afe64@intel.com>
 <aTDkODHZg0JfrZJC@lizhi-Precision-Tower-5810>
Message-ID: <77ff15d7-cdb9-46f7-9f05-97aff2dc8ee9@intel.com>



On 12/3/25 6:30 PM, Frank Li wrote:
> On Wed, Dec 03, 2025 at 03:48:41PM -0700, Dave Jiang wrote:
>>
>>
>> On 10/3/25 9:26 AM, Frank Li wrote:
>>> Add cleanup FREE defines for dma_async_tx_descriptor to support automatic
>>> cleanup and simplify error handling.
>>>
>>> Signed-off-by: Frank Li <Frank.Li at nxp.com>
>>> ---
>>> Check patch report exceed 100 chars, but it's still better put into one
>>> line to keep consistent with other DEFINE_FREE and better readablity
>>>
>>> change in v2
>>> - remove surpoiouse remove empty line
>>> ---
>>>  include/linux/dmaengine.h | 3 +++
>>>  1 file changed, 3 insertions(+)
>>>
>>> diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
>>> index 99efe2b9b4ea9844ca6161208362ef18ef111d96..27fa1646a807c49c781e1bce9e3e7d9a3c66f41d 100644
>>> --- a/include/linux/dmaengine.h
>>> +++ b/include/linux/dmaengine.h
>>> @@ -5,6 +5,7 @@
>>>  #ifndef LINUX_DMAENGINE_H
>>>  #define LINUX_DMAENGINE_H
>>>
>>> +#include <linux/cleanup.h>
>>>  #include <linux/device.h>
>>>  #include <linux/err.h>
>>>  #include <linux/uio.h>
>>> @@ -1612,6 +1613,8 @@ static inline int dmaengine_desc_free(struct dma_async_tx_descriptor *desc)
>>>  	return desc->desc_free(desc);
>>>  }
>>>
>>> +DEFINE_FREE(dma_async_tx_descriptor, struct dma_async_tx_descriptor *, if (_T) dmaengine_desc_free(_T))
>>
>> maybe free_dma_async_tx may be clearer as the name vs dma_async_tx_descriptor.
> 
> If that, 'dmaengine_desc_free' is better because avoid create new name for
> it.

That works too.

> 
> Frank
>>
>> DJ
>>
>>> +
>>>  /* --- DMA device --- */
>>>
>>>  int dma_async_device_register(struct dma_device *device);
>>>
>>
> 



From dave.jiang at intel.com  Thu Dec  4 07:09:12 2025
From: dave.jiang at intel.com (Dave Jiang)
Date: Thu, 4 Dec 2025 08:09:12 -0700
Subject: [PATCH v2 2/2] i2c: lpi2c: Use cleanup helper for
 dma_async_tx_descriptor error handling
In-Reply-To: <aTDjmdfUk94R3Dyk@lizhi-Precision-Tower-5810>
References: <20251003-dma_chan_free-v2-0-564946b6c563@nxp.com>
 <20251003-dma_chan_free-v2-2-564946b6c563@nxp.com>
 <26b9cb6d-8370-4908-aed9-9c5b07e5fb82@intel.com>
 <aTDjmdfUk94R3Dyk@lizhi-Precision-Tower-5810>
Message-ID: <3a065c54-f043-4c94-ac52-ef5b48a0dc71@intel.com>



On 12/3/25 6:27 PM, Frank Li wrote:
> On Wed, Dec 03, 2025 at 03:52:09PM -0700, Dave Jiang wrote:
>>
>>
>> On 10/3/25 9:26 AM, Frank Li wrote:
>>> Use the cleanup helper to simplify dma_async_tx_descriptor error handling.
>>>
>>> No functional change.
>>>
>>> Signed-off-by: Frank Li <Frank.Li at nxp.com>
>>> ---
>>> change v2
>>>  need goto unmap buffer.
>>>
>>> desc_prepare_err_exit:
>>>         dma_unmap_single(txchan->device->dev, dma->dma_tx_addr,
>>>                          dma->rx_cmd_buf_len, DMA_TO_DEVICE);
>>>         return -EINVAL;
>>>
>>> submit_err_exit:
>>>         dma_unmap_single(txchan->device->dev, dma->dma_tx_addr,
>>>                          dma->rx_cmd_buf_len, DMA_TO_DEVICE);
>>>         dmaengine_desc_free(rx_cmd_desc)
>>>
>>> auto cleanup by __free, so whole error path submit_err_exit can be removed
>>> and use desc_prepare_err_exit label.
>>> ---
>>>  drivers/i2c/busses/i2c-imx-lpi2c.c | 11 +++--------
>>>  1 file changed, 3 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c
>>> index 03b5a7e8c361abe1d75fb4d31f9614bbc6387d93..e31c2d81f59f18a09d34f79896a7fa4bb83c0a12 100644
>>> --- a/drivers/i2c/busses/i2c-imx-lpi2c.c
>>> +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c
>>> @@ -722,7 +722,7 @@ static void lpi2c_dma_callback(void *data)
>>>
>>>  static int lpi2c_dma_rx_cmd_submit(struct lpi2c_imx_struct *lpi2c_imx)
>>>  {
>>> -	struct dma_async_tx_descriptor *rx_cmd_desc;
>>> +	struct dma_async_tx_descriptor *rx_cmd_desc __free(dma_async_tx_descriptor) = NULL;
>>>  	struct lpi2c_imx_dma *dma = lpi2c_imx->dma;
>>>  	struct dma_chan *txchan = dma->chan_tx;
>>>  	dma_cookie_t cookie;
>>> @@ -746,10 +746,11 @@ static int lpi2c_dma_rx_cmd_submit(struct lpi2c_imx_struct *lpi2c_imx)
>>>  	cookie = dmaengine_submit(rx_cmd_desc);
>>>  	if (dma_submit_error(cookie)) {
>>>  		dev_err(&lpi2c_imx->adapter.dev, "submitting DMA failed, use pio\n");
>>> -		goto submit_err_exit;
>>> +		goto desc_prepare_err_exit;
>>
>> Typically if you are introducing cleanup usage, you will want to remove all the goto usages. Otherwise it gets kinda messy having both styles. Although not sure how to do a cleanup macro with dma_unmap_*. Unless a local one where lpi2c_imx_dma also contains a ptr to the device. Then that may be doable.
> 
> dma_unmap() patch at
> https://lore.kernel.org/imx/aPZbuY5bLpkoO2J%2F at lizhi-Precision-Tower-5810/
> 
> The first patch need be pickup and dma umap firstly.  Then I can remove all
> goto.

perfect


> 
> Frank
> 
>>
>> DJ>  	}
>>>
>>>  	dma_async_issue_pending(txchan);
>>> +	retain_and_null_ptr(rx_cmd_desc);
>>>
>>>  	return 0;
>>>
>>> @@ -757,12 +758,6 @@ static int lpi2c_dma_rx_cmd_submit(struct lpi2c_imx_struct *lpi2c_imx)
>>>  	dma_unmap_single(txchan->device->dev, dma->dma_tx_addr,
>>>  			 dma->rx_cmd_buf_len, DMA_TO_DEVICE);
>>>  	return -EINVAL;
>>> -
>>> -submit_err_exit:
>>> -	dma_unmap_single(txchan->device->dev, dma->dma_tx_addr,
>>> -			 dma->rx_cmd_buf_len, DMA_TO_DEVICE);
>>> -	dmaengine_desc_free(rx_cmd_desc);
>>> -	return -EINVAL;
>>>  }
>>>
>>>  static int lpi2c_dma_submit(struct lpi2c_imx_struct *lpi2c_imx)
>>>
>>
> 



From andrew at lunn.ch  Thu Dec  4 07:22:10 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Thu, 4 Dec 2025 16:22:10 +0100
Subject: [PATCH v3 2/2] net: dsa: mt7530: Use GPIO polarity to generate
 correct reset sequence
In-Reply-To: <20251204131626.upw77jncqfwxydww@skbuf>
References: <20251129234603.2544-1-ptpt52@gmail.com>
 <20251129234603.2544-2-ptpt52@gmail.com>
 <0675b35f-217d-4261-9e3f-2eb24753d43c@lunn.ch>
 <20251130080731.ty2dlxaypxvodxiw@skbuf>
 <3fbc4e67-b931-421c-9d83-2214aaa2f6ed@lunn.ch>
 <0d85e1e6-ea75-4f20-aef1-90d446b4bfa1@kernel.org>
 <00f308a1-a4b1-4f20-8d8e-459ddf4c39b1@gmx.de>
 <aS7Zj3AFsSp2CTNv@makrotopia.org>
 <20251204131626.upw77jncqfwxydww@skbuf>
Message-ID: <7aacc2c2-50d0-4a08-9800-dc4a572dffcb@lunn.ch>

> If this is blocking progress for new device trees, can we just construct,
> using of_machine_is_compatible(), a list of all boards where the device
> tree defines incorrect reset polarity that shouldn't be trusted by the
> driver when driving the reset GPIO? If we do this, we can also leave
> those existing device trees alone.

I've still not seen a good answer to my question, why not just leave
it 'broken', and document the fact.

Does the fact it is inverted in both DT and the driver prevent us from
making some board work?

Why do we need to fix this?

Sometimes it is better to just leave it alone, if it is not hurting
anybody.

	Andrew


From vladimir.oltean at nxp.com  Thu Dec  4 07:34:01 2025
From: vladimir.oltean at nxp.com (Vladimir Oltean)
Date: Thu, 4 Dec 2025 17:34:01 +0200
Subject: [PATCH net-next 5/9] phy: add phy_get_rx_polarity() and
 phy_get_tx_polarity()
In-Reply-To: <69ac21ea-eed2-449a-b231-c43e3cd0bdc0@kernel.org>
References: <20251122193341.332324-1-vladimir.oltean@nxp.com>
 <20251122193341.332324-6-vladimir.oltean@nxp.com>
 <20251124200121.5b82f09e@kernel.org>
 <aS1T5i3pCHsNVql6@vaman>
 <69ac21ea-eed2-449a-b231-c43e3cd0bdc0@kernel.org>
Message-ID: <20251204153401.tinrt57ifjthw55r@skbuf>

On Mon, Dec 01, 2025 at 09:41:21AM +0100, Krzysztof Kozlowski wrote:
> On 01/12/2025 09:37, Vinod Koul wrote:
> > On 24-11-25, 20:01, Jakub Kicinski wrote:
> >> On Sat, 22 Nov 2025 21:33:37 +0200 Vladimir Oltean wrote:
> >>> Add helpers in the generic PHY folder which can be used using 'select
> >>> GENERIC_PHY_COMMON_PROPS' from Kconfig, without otherwise needing to
> >>> enable GENERIC_PHY.
> >>>
> >>> These helpers need to deal with the slight messiness of the fact that
> >>> the polarity properties are arrays per protocol, and with the fact that
> >>> there is no default value mandated by the standard properties, all
> >>> default values depend on driver and protocol (PHY_POL_NORMAL may be a
> >>> good default for SGMII, whereas PHY_POL_AUTO may be a good default for
> >>> PCIe).
> >>>
> >>> Push the supported mask of polarities to these helpers, to simplify
> >>> drivers such that they don't need to validate what's in the device tree
> >>> (or other firmware description).
> >>>
> >>> The proposed maintainership model is joint custody between netdev and
> >>> linux-phy, because of the fact that these properties can be applied to
> >>> Ethernet PCS blocks just as well as Generic PHY devices. I've added as
> >>> maintainers those from "ETHERNET PHY LIBRARY", "NETWORKING DRIVERS" and
> >>> "GENERIC PHY FRAMEWORK".
> >>
> >> I dunno.. ain't no such thing as "joint custody" maintainership.
> >> We have to pick one tree. Given the set of Ms here, I suspect 
> >> the best course of action may be to bubble this up to its own tree.
> >> Ask Konstantin for a tree in k.org, then you can "co-post" the patches
> >> for review + PR link in the cover letter (e.g. how Tony from Intel
> >> submits their patches). This way not networking and PHY can pull
> >> the shared changes with stable commit IDs.
> > 
> > How much is the volume of the changes that we are talking about, we can
> > always ack and pull into each other trees..?
> 
> That's just one C file, isn't it? Having dedicated tree for one file
> feels like huge overhead.

I have to admit, no matter how we define what pertains to this presumed
new git tree, the fact is that the volume of patches will be quite low.

Since the API provider always sits in drivers/phy/ in every case that I
can think about, technically all situations can be resolved by linux-phy
providing these stable PR branches to netdev. In turn, to netdev it
makes no difference whether the branches are coming from linux-phy or a
third git tree. Whereas to linux-phy, things would even maybe a bit
simpler, due to already having the patches vs needing to pull them from
the 3rd tree.

>From my perspective, if I'm perfectly honest, the idea was attractive
because of the phenomenal difference in turnaround times between netdev
and linux-phy review&merge processes (very fast in netdev, very slow and
patchy in linux-phy). If there's a set like this, where all API consumers
are in netdev for now but the API itself is in linux-phy, you'd have to
introduce 1000 NOP cycles just to wait for the PR branch.

In that sense, having more people into the mix would help just because
there's more people (i.e. fewer points of failure), even though overall
there's more overhead.

IDK, these are my 2 cents, I can resubmit this set in 2 weeks with the
maintainership of the PHY common properties exclusive to linux-phy.


From robh at kernel.org  Thu Dec  4 07:37:01 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Thu, 4 Dec 2025 09:37:01 -0600
Subject: [PATCH 1/3] dt-bindings: clock: exynosautov920: add MFD clock
 definitions
In-Reply-To: <20251119114744.1914416-2-raghav.s@samsung.com>
References: <20251119114744.1914416-1-raghav.s@samsung.com>
 <CGME20251119113927epcas5p15154cb4a7824e9ca65ac18842b68d785@epcas5p1.samsung.com>
 <20251119114744.1914416-2-raghav.s@samsung.com>
Message-ID: <176486262088.1527918.10847897816665673488.robh@kernel.org>


On Wed, 19 Nov 2025 17:17:42 +0530, Raghav Sharma wrote:
> Add device tree clock binding definitions for CMU_MFD
> 
> Signed-off-by: Raghav Sharma <raghav.s at samsung.com>
> ---
>  .../clock/samsung,exynosautov920-clock.yaml   | 19 +++++++++++++++++++
>  .../clock/samsung,exynosautov920.h            |  4 ++++
>  2 files changed, 23 insertions(+)
> 

Acked-by: Rob Herring (Arm) <robh at kernel.org>



From olteanv at gmail.com  Thu Dec  4 07:37:21 2025
From: olteanv at gmail.com (Vladimir Oltean)
Date: Thu, 4 Dec 2025 17:37:21 +0200
Subject: [PATCH v3 2/2] net: dsa: mt7530: Use GPIO polarity to generate
 correct reset sequence
In-Reply-To: <7aacc2c2-50d0-4a08-9800-dc4a572dffcb@lunn.ch>
References: <20251129234603.2544-1-ptpt52@gmail.com>
 <20251129234603.2544-2-ptpt52@gmail.com>
 <0675b35f-217d-4261-9e3f-2eb24753d43c@lunn.ch>
 <20251130080731.ty2dlxaypxvodxiw@skbuf>
 <3fbc4e67-b931-421c-9d83-2214aaa2f6ed@lunn.ch>
 <0d85e1e6-ea75-4f20-aef1-90d446b4bfa1@kernel.org>
 <00f308a1-a4b1-4f20-8d8e-459ddf4c39b1@gmx.de>
 <aS7Zj3AFsSp2CTNv@makrotopia.org>
 <20251204131626.upw77jncqfwxydww@skbuf>
 <7aacc2c2-50d0-4a08-9800-dc4a572dffcb@lunn.ch>
Message-ID: <20251204153721.ubmxifrev4cre6ab@skbuf>

On Thu, Dec 04, 2025 at 04:22:10PM +0100, Andrew Lunn wrote:
> > If this is blocking progress for new device trees, can we just construct,
> > using of_machine_is_compatible(), a list of all boards where the device
> > tree defines incorrect reset polarity that shouldn't be trusted by the
> > driver when driving the reset GPIO? If we do this, we can also leave
> > those existing device trees alone.
> 
> I've still not seen a good answer to my question, why not just leave
> it 'broken', and document the fact.
> 
> Does the fact it is inverted in both DT and the driver prevent us from
> making some board work?
> 
> Why do we need to fix this?
> 
> Sometimes it is better to just leave it alone, if it is not hurting
> anybody.
> 
> 	Andrew

Frank said that the fact the driver expecting a wrong device tree is
forcing him to keep introducing even more wrong device trees for new
boards.


From olteanv at gmail.com  Thu Dec  4 07:45:57 2025
From: olteanv at gmail.com (Vladimir Oltean)
Date: Thu, 4 Dec 2025 17:45:57 +0200
Subject: [PATCH v3 2/2] net: dsa: mt7530: Use GPIO polarity to generate
 correct reset sequence
In-Reply-To: <aTGRvADkT-1kAQgA@makrotopia.org>
References: <20251129234603.2544-1-ptpt52@gmail.com>
 <20251129234603.2544-2-ptpt52@gmail.com>
 <0675b35f-217d-4261-9e3f-2eb24753d43c@lunn.ch>
 <20251130080731.ty2dlxaypxvodxiw@skbuf>
 <3fbc4e67-b931-421c-9d83-2214aaa2f6ed@lunn.ch>
 <0d85e1e6-ea75-4f20-aef1-90d446b4bfa1@kernel.org>
 <00f308a1-a4b1-4f20-8d8e-459ddf4c39b1@gmx.de>
 <aS7Zj3AFsSp2CTNv@makrotopia.org>
 <20251204131626.upw77jncqfwxydww@skbuf>
 <aTGRvADkT-1kAQgA@makrotopia.org>
Message-ID: <20251204154557.b7asnuxq7hiy5zlq@skbuf>

On Thu, Dec 04, 2025 at 01:50:52PM +0000, Daniel Golle wrote:
> On Thu, Dec 04, 2025 at 03:16:26PM +0200, Vladimir Oltean wrote:
> > If this is blocking progress for new device trees, can we just construct,
> > using of_machine_is_compatible(), a list of all boards where the device
> > tree defines incorrect reset polarity that shouldn't be trusted by the
> > driver when driving the reset GPIO? If we do this, we can also leave
> > those existing device trees alone.
> 
> From OpenWrt's point of view this would be kind of ugly as we would either
> have to extend the list of affected boards downstream, or fix the polarity
> in some but not all of our downstream DTS files.

Including the downstream-only boards, how many compatibles are we
talking about? If we patched mainline to cover all, are you confident
that it would be an exhaustive solution?

> I'd prefer to rather have the option to force the "wrong" GPIO
> polarity for theoretical future boards with that (very unlikely to
> ever exist) NOT gate between the SoC GPIO and switch reset line. That
> would allow to gradually update boards to reflect the physical reality
> and yet the driver would not break if the GPIO polarity is stated
> wrongly.

I didn't get that from this thread - how would you prefer having this
option implemented exactly?


From andrew at lunn.ch  Thu Dec  4 07:50:12 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Thu, 4 Dec 2025 16:50:12 +0100
Subject: [PATCH v3 2/2] net: dsa: mt7530: Use GPIO polarity to generate
 correct reset sequence
In-Reply-To: <20251204153721.ubmxifrev4cre6ab@skbuf>
References: <20251129234603.2544-2-ptpt52@gmail.com>
 <0675b35f-217d-4261-9e3f-2eb24753d43c@lunn.ch>
 <20251130080731.ty2dlxaypxvodxiw@skbuf>
 <3fbc4e67-b931-421c-9d83-2214aaa2f6ed@lunn.ch>
 <0d85e1e6-ea75-4f20-aef1-90d446b4bfa1@kernel.org>
 <00f308a1-a4b1-4f20-8d8e-459ddf4c39b1@gmx.de>
 <aS7Zj3AFsSp2CTNv@makrotopia.org>
 <20251204131626.upw77jncqfwxydww@skbuf>
 <7aacc2c2-50d0-4a08-9800-dc4a572dffcb@lunn.ch>
 <20251204153721.ubmxifrev4cre6ab@skbuf>
Message-ID: <16038b9d-11f4-4995-b0c2-7e7d55bb494a@lunn.ch>

> Frank said that the fact the driver expecting a wrong device tree is
> forcing him to keep introducing even more wrong device trees for new
> boards.

So it sounds like there is no technical reason to fix this, it is just
aesthetics?

	Andrew


From robh at kernel.org  Thu Dec  4 07:52:19 2025
From: robh at kernel.org (Rob Herring)
Date: Thu, 4 Dec 2025 09:52:19 -0600
Subject: [PATCH net-next 2/9] dt-bindings: phy-common-props: create a
 reusable "protocol-names" definition
In-Reply-To: <20251122193341.332324-3-vladimir.oltean@nxp.com>
References: <20251122193341.332324-1-vladimir.oltean@nxp.com>
 <20251122193341.332324-3-vladimir.oltean@nxp.com>
Message-ID: <20251204155219.GA1533839-robh@kernel.org>

On Sat, Nov 22, 2025 at 09:33:34PM +0200, Vladimir Oltean wrote:
> Other properties also need to be defined per protocol than just
> tx-p2p-microvolt-names. Create a common definition to avoid copying a 55
> line property.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean at nxp.com>
> ---
>  .../bindings/phy/phy-common-props.yaml        | 34 +++++++++++--------
>  1 file changed, 19 insertions(+), 15 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/phy/phy-common-props.yaml b/Documentation/devicetree/bindings/phy/phy-common-props.yaml
> index 255205ac09cd..775f4dfe3cc3 100644
> --- a/Documentation/devicetree/bindings/phy/phy-common-props.yaml
> +++ b/Documentation/devicetree/bindings/phy/phy-common-props.yaml
> @@ -13,22 +13,12 @@ description:
>  maintainers:
>    - Marek Beh?n <kabel at kernel.org>
>  
> -properties:
> -  tx-p2p-microvolt:
> +$defs:
> +  protocol-names:
>      description:
> -      Transmit amplitude voltages in microvolts, peak-to-peak. If this property
> -      contains multiple values for various PHY modes, the
> -      'tx-p2p-microvolt-names' property must be provided and contain
> -      corresponding mode names.
> -
> -  tx-p2p-microvolt-names:
> -    description: |
> -      Names of the modes corresponding to voltages in the 'tx-p2p-microvolt'
> -      property. Required only if multiple voltages are provided.
> -
> -      If a value of 'default' is provided, the system should use it for any PHY
> -      mode that is otherwise not defined here. If 'default' is not provided, the
> -      system should use manufacturer default value.
> +      Names of the PHY modes. If a value of 'default' is provided, the system
> +      should use it for any PHY mode that is otherwise not defined here. If
> +      'default' is not provided, the system should use manufacturer default value.
>      minItems: 1
>      maxItems: 16
>      items:
> @@ -89,6 +79,20 @@ properties:
>          - mipi-dphy-univ
>          - mipi-dphy-v2.5-univ
>  
> +properties:
> +  tx-p2p-microvolt:
> +    description:
> +      Transmit amplitude voltages in microvolts, peak-to-peak. If this property
> +      contains multiple values for various PHY modes, the
> +      'tx-p2p-microvolt-names' property must be provided and contain
> +      corresponding mode names.
> +
> +  tx-p2p-microvolt-names:
> +    description:
> +      Names of the modes corresponding to voltages in the 'tx-p2p-microvolt'
> +      property. Required only if multiple voltages are provided.
> +    $ref: "#/$defs/protocol-names"

The default for .*-names is the entries don't have to be unique. That's 
for the exception, but unfortunately everyone else has to define the 
type (type.yaml#/definitons/string).

Each user needs to define the names of the entries which will enforce 
the length. So defining the length 1-16 here doesn't do much. So I think 
you can drop that and then the $defs is not needed either.

Rob


From krzk at kernel.org  Thu Dec  4 07:52:53 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 4 Dec 2025 16:52:53 +0100
Subject: [PATCH v3 2/2] net: dsa: mt7530: Use GPIO polarity to generate
 correct reset sequence
In-Reply-To: <20251204153721.ubmxifrev4cre6ab@skbuf>
References: <20251129234603.2544-1-ptpt52@gmail.com>
 <20251129234603.2544-2-ptpt52@gmail.com>
 <0675b35f-217d-4261-9e3f-2eb24753d43c@lunn.ch>
 <20251130080731.ty2dlxaypxvodxiw@skbuf>
 <3fbc4e67-b931-421c-9d83-2214aaa2f6ed@lunn.ch>
 <0d85e1e6-ea75-4f20-aef1-90d446b4bfa1@kernel.org>
 <00f308a1-a4b1-4f20-8d8e-459ddf4c39b1@gmx.de>
 <aS7Zj3AFsSp2CTNv@makrotopia.org> <20251204131626.upw77jncqfwxydww@skbuf>
 <7aacc2c2-50d0-4a08-9800-dc4a572dffcb@lunn.ch>
 <20251204153721.ubmxifrev4cre6ab@skbuf>
Message-ID: <6344bdfd-c22c-45a1-854d-59091dfeda97@kernel.org>

On 04/12/2025 16:37, Vladimir Oltean wrote:
> On Thu, Dec 04, 2025 at 04:22:10PM +0100, Andrew Lunn wrote:
>>> If this is blocking progress for new device trees, can we just construct,
>>> using of_machine_is_compatible(), a list of all boards where the device
>>> tree defines incorrect reset polarity that shouldn't be trusted by the
>>> driver when driving the reset GPIO? If we do this, we can also leave
>>> those existing device trees alone.
>>
>> I've still not seen a good answer to my question, why not just leave
>> it 'broken', and document the fact.
>>
>> Does the fact it is inverted in both DT and the driver prevent us from
>> making some board work?
>>
>> Why do we need to fix this?
>>
>> Sometimes it is better to just leave it alone, if it is not hurting
>> anybody.
>>
>> 	Andrew
> 
> Frank said that the fact the driver expecting a wrong device tree is
> forcing him to keep introducing even more wrong device trees for new
> boards.


Yeah. BTW, you can also refer to one of my commits -
738455858a2d21b769f673892546cf8300c9fd78 - but also note that similar
work later combined with much more useful change of gpio->gpiod API was
rejected by Mark Brown on basis:

"No, the DT is supposed to be an ABI.  The point in having a domain
specific language with a compiler is to allow device trees to be
distributed independently of the kernel."

https://lore.kernel.org/all/9942c3a9-51d1-4161-8871-f6ec696cb4db at sirena.org.uk/

What's interesting, exactly the same commit for the same file, done by
different person (Peng), introducing the same issues without addressing
them, was then merged by Mark:
https://patch.msgid.link/20250324-wcd-gpiod-v2-2-773f67ce3b56 at nxp.com
(commit c2d359b4acfbe847d3edcc25d3dc4e594daf9010)

so you know... it's all relative. :)

Best regards,
Krzysztof


From olteanv at gmail.com  Thu Dec  4 08:02:47 2025
From: olteanv at gmail.com (Vladimir Oltean)
Date: Thu, 4 Dec 2025 18:02:47 +0200
Subject: [PATCH v3 2/2] net: dsa: mt7530: Use GPIO polarity to generate
 correct reset sequence
In-Reply-To: <4170c560-1edd-4ff8-96af-a479063be4a5@kernel.org>
References: <20251129234603.2544-1-ptpt52@gmail.com>
 <20251129234603.2544-2-ptpt52@gmail.com>
 <0675b35f-217d-4261-9e3f-2eb24753d43c@lunn.ch>
 <20251130080731.ty2dlxaypxvodxiw@skbuf>
 <3fbc4e67-b931-421c-9d83-2214aaa2f6ed@lunn.ch>
 <0d85e1e6-ea75-4f20-aef1-90d446b4bfa1@kernel.org>
 <00f308a1-a4b1-4f20-8d8e-459ddf4c39b1@gmx.de>
 <aS7Zj3AFsSp2CTNv@makrotopia.org>
 <20251204131626.upw77jncqfwxydww@skbuf>
 <4170c560-1edd-4ff8-96af-a479063be4a5@kernel.org>
Message-ID: <20251204160247.yz42mnxvzhxas5jc@skbuf>

On Thu, Dec 04, 2025 at 03:49:52PM +0100, Krzysztof Kozlowski wrote:
> On 04/12/2025 14:16, Vladimir Oltean wrote:
> > I get the feeling that we're complicating a simple solution because of a
> > theoretical "what if" scenario. The "NOT" gate is somewhat contrived
> 
> You downplay this case and suggest (if I get it right) that NOT gate is
> something unusual.
> 
>  I mentioned "line inverter" but it's not about NOT gate. There is no
> need for NOT gate at all, like some magical component which no one puts
> to the board. The only thing needed is just to pull the GPIO up or down,
> that's it. It's completely normal design thus it CAN happen.
> 
> Of course "can" does not mean it actually does, because certain
> configurations like powerdown-fail-safe are more likely and I am not an
> electric circuit designer to tell which one is better, but that
> downplaying does not help here.

I don't want to dismiss this comment, but I don't really understand it.
What do you mean by "line inverter", is it the component inside the GPIO
pin which makes it active low?

I thought that the premise of this patch set is that old device trees
are all (incorrectly) defined as GPIO_ACTIVE_HIGH, but someone familiar
with the matter needs to fact-check this statement.

Anyway, you and Andrew are talking about different things, you haven't
made it clear (or at least it wasn't clear to me) that the inverter you
are talking about isn't his NOT gate (that isn't described in the device
tree at all, as opposed to your inverter which would make the GPIO line
GPIO_ACTIVE_LOW - that's something verifiable).

> Just to clarify: I expect clear communication that some users will be
> broken with as good as you can provide analysis of the impact (which
> users). I only object the clame here "no one can ever pull down a GPIO
> line thus I handled all possible cases and made it backward compatible".
> 
> And that claim to quote was:
> "Therefore, regardless of whether a DTS is old or new, correct or
> incorrect, the driver now generates the correct electrical reset pulse."
> 
> which is 100% false and I am surprised how one could claim that.

Agree, the communication should be better.


From robh at kernel.org  Thu Dec  4 08:11:33 2025
From: robh at kernel.org (Rob Herring)
Date: Thu, 4 Dec 2025 10:11:33 -0600
Subject: [PATCH net-next 2/9] dt-bindings: phy-common-props: create a
 reusable "protocol-names" definition
In-Reply-To: <20251204155219.GA1533839-robh@kernel.org>
References: <20251122193341.332324-1-vladimir.oltean@nxp.com>
 <20251122193341.332324-3-vladimir.oltean@nxp.com>
 <20251204155219.GA1533839-robh@kernel.org>
Message-ID: <20251204161133.GA1574692-robh@kernel.org>

On Thu, Dec 04, 2025 at 09:52:19AM -0600, Rob Herring wrote:
> On Sat, Nov 22, 2025 at 09:33:34PM +0200, Vladimir Oltean wrote:
> > Other properties also need to be defined per protocol than just
> > tx-p2p-microvolt-names. Create a common definition to avoid copying a 55
> > line property.
> > 
> > Signed-off-by: Vladimir Oltean <vladimir.oltean at nxp.com>
> > ---
> >  .../bindings/phy/phy-common-props.yaml        | 34 +++++++++++--------
> >  1 file changed, 19 insertions(+), 15 deletions(-)
> > 
> > diff --git a/Documentation/devicetree/bindings/phy/phy-common-props.yaml b/Documentation/devicetree/bindings/phy/phy-common-props.yaml
> > index 255205ac09cd..775f4dfe3cc3 100644
> > --- a/Documentation/devicetree/bindings/phy/phy-common-props.yaml
> > +++ b/Documentation/devicetree/bindings/phy/phy-common-props.yaml
> > @@ -13,22 +13,12 @@ description:
> >  maintainers:
> >    - Marek Beh?n <kabel at kernel.org>
> >  
> > -properties:
> > -  tx-p2p-microvolt:
> > +$defs:
> > +  protocol-names:
> >      description:
> > -      Transmit amplitude voltages in microvolts, peak-to-peak. If this property
> > -      contains multiple values for various PHY modes, the
> > -      'tx-p2p-microvolt-names' property must be provided and contain
> > -      corresponding mode names.
> > -
> > -  tx-p2p-microvolt-names:
> > -    description: |
> > -      Names of the modes corresponding to voltages in the 'tx-p2p-microvolt'
> > -      property. Required only if multiple voltages are provided.
> > -
> > -      If a value of 'default' is provided, the system should use it for any PHY
> > -      mode that is otherwise not defined here. If 'default' is not provided, the
> > -      system should use manufacturer default value.
> > +      Names of the PHY modes. If a value of 'default' is provided, the system
> > +      should use it for any PHY mode that is otherwise not defined here. If
> > +      'default' is not provided, the system should use manufacturer default value.
> >      minItems: 1
> >      maxItems: 16
> >      items:
> > @@ -89,6 +79,20 @@ properties:
> >          - mipi-dphy-univ
> >          - mipi-dphy-v2.5-univ
> >  
> > +properties:
> > +  tx-p2p-microvolt:
> > +    description:
> > +      Transmit amplitude voltages in microvolts, peak-to-peak. If this property
> > +      contains multiple values for various PHY modes, the
> > +      'tx-p2p-microvolt-names' property must be provided and contain
> > +      corresponding mode names.
> > +
> > +  tx-p2p-microvolt-names:
> > +    description:
> > +      Names of the modes corresponding to voltages in the 'tx-p2p-microvolt'
> > +      property. Required only if multiple voltages are provided.
> > +    $ref: "#/$defs/protocol-names"
> 
> The default for .*-names is the entries don't have to be unique. That's 
> for the exception, but unfortunately everyone else has to define the 
> type (type.yaml#/definitons/string).
> 
> Each user needs to define the names of the entries which will enforce 
> the length. So defining the length 1-16 here doesn't do much. So I think 
> you can drop that and then the $defs is not needed either.

I missed that all the names are defined here. Nevermind on the 2nd 
point. We probably still need either a $ref or 'uniqueItems: true'. 
Either way should work.

Rob


From robh at kernel.org  Thu Dec  4 08:11:50 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Thu, 4 Dec 2025 10:11:50 -0600
Subject: [PATCH net-next 1/9] dt-bindings: phy: rename
 transmit-amplitude.yaml to phy-common-props.yaml
In-Reply-To: <20251122193341.332324-2-vladimir.oltean@nxp.com>
References: <20251122193341.332324-1-vladimir.oltean@nxp.com>
 <20251122193341.332324-2-vladimir.oltean@nxp.com>
Message-ID: <176486470918.1577839.2388132003794152045.robh@kernel.org>


On Sat, 22 Nov 2025 21:33:33 +0200, Vladimir Oltean wrote:
> I would like to add more properties similar to tx-p2p-microvolt, and I
> don't think it makes sense to create one schema for each such property
> (transmit-amplitude.yaml, lane-polarity.yaml, transmit-equalization.yaml
> etc).
> 
> Instead, let's rename to phy-common-props.yaml, which makes it a more
> adequate host schema for all the above properties.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean at nxp.com>
> ---
>  .../{transmit-amplitude.yaml => phy-common-props.yaml}    | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
>  rename Documentation/devicetree/bindings/phy/{transmit-amplitude.yaml => phy-common-props.yaml} (90%)
> 

Acked-by: Rob Herring (Arm) <robh at kernel.org>



From robh at kernel.org  Thu Dec  4 08:13:02 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Thu, 4 Dec 2025 10:13:02 -0600
Subject: [PATCH net-next 3/9] dt-bindings: phy-common-props: RX and TX
 lane polarity inversion
In-Reply-To: <20251122193341.332324-4-vladimir.oltean@nxp.com>
References: <20251122193341.332324-1-vladimir.oltean@nxp.com>
 <20251122193341.332324-4-vladimir.oltean@nxp.com>
Message-ID: <176486478133.1579282.8723601049864810210.robh@kernel.org>


On Sat, 22 Nov 2025 21:33:35 +0200, Vladimir Oltean wrote:
> Differential signaling is a technique for high-speed protocols to be
> more resilient to noise. At the transmit side we have a positive and a
> negative signal which are mirror images of each other. At the receiver,
> if we subtract the negative signal (say of amplitude -A) from the
> positive signal (say +A), we recover the original single-ended signal at
> twice its original amplitude. But any noise, like one coming from EMI
> from outside sources, is supposed to have an almost equal impact upon
> the positive (A + E, E being for "error") and negative signal (-A + E).
> So (A + E) - (-A + E) eliminates this noise, and this is what makes
> differential signaling useful.
> 
> Except that in order to work, there must be strict requirements observed
> during PCB design and layout, like the signal traces needing to have the
> same length and be physically close to each other, and many others.
> 
> Sometimes it is not easy to fulfill all these requirements, a simple
> case to understand is when on chip A's pins, the positive pin is on the
> left and the negative is on the right, but on the chip B's pins (with
> which A tries to communicate), positive is on the right and negative on
> the left. The signals would need to cross, using vias and other ugly
> stuff that affects signal integrity (introduces impedance
> discontinuities which cause reflections, etc).
> 
> So sometimes, board designers intentionally connect differential lanes
> the wrong way, and expect somebody else to invert that signal to recover
> useful data. This is where RX and TX polarity inversion comes in as a
> generic concept that applies to any high-speed serial protocol as long
> as it uses differential signaling.
> 
> I've stopped two attempts to introduce more vendor-specific descriptions
> of this only in the past month:
> https://lore.kernel.org/linux-phy/20251110110536.2596490-1-horatiu.vultur at microchip.com/
> https://lore.kernel.org/netdev/20251028000959.3kiac5kwo5pcl4ft at skbuf/
> 
> and in the kernel we already have merged:
> - "st,px_rx_pol_inv"
> - "st,pcie-tx-pol-inv"
> - "st,sata-tx-pol-inv"
> - "mediatek,pnswap"
> - "airoha,pnswap-rx"
> - "airoha,pnswap-tx"
> 
> and maybe more. So it is pretty general.
> 
> One additional element of complexity is introduced by the fact that for
> some protocols, receivers can automatically detect and correct for an
> inverted lane polarity (example: the PCIe LTSSM does this in the
> Polling.Configuration state; the USB 3.1 Link Layer Test Specification
> says that the detection and correction of the lane polarity inversion in
> SuperSpeed operation shall be enabled in Polling.RxEQ.). Whereas for
> other protocols (SGMII, SATA, 10GBase-R, etc etc), the polarity is all
> manual and there is no detection mechanism mandated by their respective
> standards.
> 
> So why would one even describe rx-polarity and tx-polarity for protocols
> like PCIe, if it had to always be PHY_POL_AUTO?
> 
> Related question: why would we define the polarity as an array per
> protocol? Isn't the physical PCB layout protocol-agnostic, and aren't we
> describing the same physical reality from the lens of different protocols?
> 
> The answer to both questions is because multi-protocol PHYs exist
> (supporting e.g. USB2 and USB3, or SATA and PCIe, or PCIe and Ethernet
> over the same lane), one would need to manually set the polarity for
> SATA/Ethernet, while leaving it at auto for PCIe/USB 3.0+.
> 
> I also investigated from another angle: what if polarity inversion in
> the PHY is one layer, and then the PCIe/USB3 LTSSM polarity detection is
> another layer on top? Then rx-polarity = <PHY_POL_AUTO> doesn't make
> sense, it can still be rx-polarity = <PHY_POL_NORMAL> or <PHY_POL_INVERT>,
> and the link training state machine figures things out on top of that.
> This would radically simplify the design, as the elimination of
> PHY_POL_AUTO inherently means that the need for a property array per
> protocol also goes away.
> 
> I don't know how things are in the general case, but at least in the 10G
> and 28G Lynx SerDes blocks from NXP Layerscape devices, this isn't the
> case, and there's only a single level of RX polarity inversion: in the
> SerDes lane. In the case of PCIe, the controller is in charge of driving
> the RDAT_INV bit autonomously, and it is read-only to software.
> 
> So the existence of this kind of SerDes lane proves the need for
> PHY_POL_AUTO to be a third state.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean at nxp.com>
> ---
>  .../bindings/phy/phy-common-props.yaml        | 45 +++++++++++++++++++
>  include/dt-bindings/phy/phy.h                 |  4 ++
>  2 files changed, 49 insertions(+)
> 

Reviewed-by: Rob Herring (Arm) <robh at kernel.org>



From robh at kernel.org  Thu Dec  4 08:13:15 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Thu, 4 Dec 2025 10:13:15 -0600
Subject: [PATCH net-next 4/9] dt-bindings: net: xpcs: allow properties
 from phy-common-props.yaml
In-Reply-To: <20251122193341.332324-5-vladimir.oltean@nxp.com>
References: <20251122193341.332324-1-vladimir.oltean@nxp.com>
 <20251122193341.332324-5-vladimir.oltean@nxp.com>
Message-ID: <176486479535.1579612.18279461397755794325.robh@kernel.org>


On Sat, 22 Nov 2025 21:33:36 +0200, Vladimir Oltean wrote:
> Now XPCS device tree nodes can specify properties to configure transmit
> amplitude, receiver polarity inversion, and transmitter polarity
> inversion for different PHY protocols.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean at nxp.com>
> ---
>  Documentation/devicetree/bindings/net/pcs/snps,dw-xpcs.yaml | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> 

Reviewed-by: Rob Herring (Arm) <robh at kernel.org>



From robh at kernel.org  Thu Dec  4 08:13:37 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Thu, 4 Dec 2025 10:13:37 -0600
Subject: [PATCH net-next 9/9] dt-bindings: net: airoha,en8811h: deprecate
 "airoha,pnswap-rx" and "airoha,pnswap-tx"
In-Reply-To: <20251122193341.332324-10-vladimir.oltean@nxp.com>
References: <20251122193341.332324-1-vladimir.oltean@nxp.com>
 <20251122193341.332324-10-vladimir.oltean@nxp.com>
Message-ID: <176486481672.1580073.2236762382059854935.robh@kernel.org>


On Sat, 22 Nov 2025 21:33:41 +0200, Vladimir Oltean wrote:
> Reference the common PHY properties, and update the example to use them.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean at nxp.com>
> ---
>  .../devicetree/bindings/net/airoha,en8811h.yaml       | 11 ++++++++++-
>  1 file changed, 10 insertions(+), 1 deletion(-)
> 

Reviewed-by: Rob Herring (Arm) <robh at kernel.org>



From sudeep.holla at arm.com  Thu Dec  4 08:16:21 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Thu, 4 Dec 2025 16:16:21 +0000
Subject: [PATCH v4] firmware: arm_scmi: refactor reset domain handling
In-Reply-To: <20251123163557.230530-1-a.shimko.dev@gmail.com>
References: <aRW4PpPjVw1-melm@pluto>
 <20251123163557.230530-1-a.shimko.dev@gmail.com>
Message-ID: <20251204-slick-granite-chameleon-58ebc2@sudeepholla>

On Sun, Nov 23, 2025 at 07:35:57PM +0300, Artem Shimko wrote:
> Improve the SCMI reset protocol implementation by centralizing domain
> validation and enhancing error handling.
> 
> Add scmi_reset_domain_lookup() helper function to validate
> domain ids and return appropriate error codes. Refactor all
> domain-specific functions to use this helper, ensuring consistent
> error handling throughout the reset protocol.
> 
> Suggested-by: Cristian Marussi <cristian.marussi at arm.com>
> Signed-off-by: Artem Shimko <a.shimko.dev at gmail.com>
> ---
> 
> Hi Cristian,
> 
> Thank you for suggesting! If it works for you I'll try to improve the others protocols.
> 
> It was tested on my board in QEMU and on real hardware.
> The functionality didn't break, and peripherals that are reseted via SCMI work correctly.
> 
> As an example, I can provide DMA test results (as one of the processor units dependent on SCMI reset).
> 
> [    2.559040] dw_axi_dmac_platform 1000nda0.nda_dma_0: DesignWare AXI DMA Controller, nda channels
> [    2.569265] dw_axi_dmac_platform 1000nda0.nda_dma_1: DesignWare AXI DMA Controller, nda channels
> [    2.580601] dw_axi_dmac_platform 1000nda0.nda_dma_2: DesignWare AXI DMA Controller, nda channels
> 
> # echo 2000 > /sys/module/dmatest/parameters/timeout
> # echo 1000 > /sys/module/dmatest/parameters/iterations
> # echo dma0chan0 > /sys/module/dmatest/parameters/channel
> [   95.917504] dmatest: Added 1 threads using dma0chan0
> # echo 1 > /sys/module/dmatest/parameters/run
> [  101.931372] dmatest: Started 1 threads using dma0chan0
> [  102.731009] dmatest: dma0chan0-copy0: summary 1000 tests, 0 failures 2508.42 iops 19706 KB/s (0)
> 
> And vice versa:
> 
> 1. Confirmed that the DMA module is non-functional without a proper reset via SCMI.
> Disabling the reset logic causes a system crash on first access to its registers.
> 
> 2. Requesting a non-existent reset domain:
> 
> [    2.463400] dw_axi_dmac_platform 1000nda0.nda_dma_0: error -EINVAL: Failed to deassert resets
> [    2.472091] dw_axi_dmac_platform 1000nda0.nda_dma_0: probe with driver dw_axi_dmac_platform failed with error -22
> [    2.482911] dw_axi_dmac_platform 1000nda0.nda_dma_1: error -EINVAL: Failed to deassert resets
> [    2.491553] dw_axi_dmac_platform 1000nda0.nda_dma_1: probe with driver dw_axi_dmac_platform failed with error -22
> [    2.502256] dw_axi_dmac_platform 1000nda0.nda_dma_2: error -EINVAL: Failed to deassert resets
> [    2.510735] dw_axi_dmac_platform 1000nda0.nda_dma_2: probe with driver dw_axi_dmac_platform failed with error -22
> 
> --
> Regards,
> Artem
> 
> ---
> ChangeLog:
>   v4: Add Suggested-by tag
> 
>  drivers/firmware/arm_scmi/reset.c | 59 ++++++++++++++++++++-----------
>  1 file changed, 39 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/firmware/arm_scmi/reset.c b/drivers/firmware/arm_scmi/reset.c
> index 0aa82b96f41b..9854a3016d13 100644
> --- a/drivers/firmware/arm_scmi/reset.c
> +++ b/drivers/firmware/arm_scmi/reset.c
> @@ -100,6 +100,7 @@ static int scmi_reset_attributes_get(const struct scmi_protocol_handle *ph,
>  
>  static int
>  scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph,
> +				 struct reset_dom_info *dom_info,

Instead of changing this, ...

>  				 struct scmi_reset_info *pinfo,
>  				 u32 domain, u32 version)
>  {
> @@ -107,7 +108,6 @@ scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph,
>  	u32 attributes;
>  	struct scmi_xfer *t;
>  	struct scmi_msg_resp_reset_domain_attributes *attr;
> -	struct reset_dom_info *dom_info = pinfo->dom_info + domain;
>  

... You can just follow the pattern you have done everywhere else in this
change like:

struct reset_dom_info *dom_info; 

dom_info = scmi_reset_domain_lookup(ph, domain);
if (IS_ERR(dom_info))
	return PTR_ERR(dom_info);

Any particular reason for not doing that ?

-- 
Regards,
Sudeep


From daniel at riscstar.com  Thu Dec  4 08:17:20 2025
From: daniel at riscstar.com (Daniel Thompson)
Date: Thu, 4 Dec 2025 16:17:20 +0000
Subject: [PATCH v6 2/4] backlight: add max25014atg backlight
In-Reply-To: <20251201-max25014-v6-2-88e3ac8112ff@gocontroll.com>
References: <20251201-max25014-v6-0-88e3ac8112ff@gocontroll.com>
 <20251201-max25014-v6-2-88e3ac8112ff@gocontroll.com>
Message-ID: <aTG0EK_zuSB-U_bb@aspen.lan>

On Mon, Dec 01, 2025 at 12:53:21PM +0100, Maud Spierings via B4 Relay wrote:
> From: Maud Spierings <maudspierings at gocontroll.com>
>
> The Maxim MAX25014 is a 4-channel automotive grade backlight driver IC
> with integrated boost controller.
>
> Signed-off-by: Maud Spierings <maudspierings at gocontroll.com>

> <snip>

> +static int max25014_check_errors(struct max25014 *maxim)
> +{
> +	uint32_t val;
> +	uint8_t i;
> +	int ret;
> +
> +	ret = regmap_read(maxim->regmap, MAX25014_OPEN, &val);
> +	if (ret)
> +		return ret;
> +	if (val) {
> +		dev_err(&maxim->client->dev, "Open led strings detected on:\n");
> +		for (i = 0; i < 4; i++) {
> +			if (val & 1 << i)
> +				dev_err(&maxim->client->dev, "string %d\n", i + 1);
> +		}
> +		return -EIO;
> +	}
> +
> +	ret = regmap_read(maxim->regmap, MAX25014_SHORT_GND, &val);
> +	if (ret)
> +		return ret;
> +	if (val) {
> +		dev_err(&maxim->client->dev, "Short to ground detected on:\n");
> +		for (i = 0; i < 4; i++) {
> +			if (val & 1 << i)
> +				dev_err(&maxim->client->dev, "string %d\n", i + 1);
> +		}
> +		return -EIO;
> +	}
> +
> +	ret = regmap_read(maxim->regmap, MAX25014_SHORT_GND, &val);

Shouldn't this be MAX25014_SHORT_LED?


> +	if (ret)
> +		return ret;
> +	if (val) {
> +		dev_err(&maxim->client->dev, "Shorted led detected on:\n");
> +		for (i = 0; i < 4; i++) {
> +			if (val & 1 << i)
> +				dev_err(&maxim->client->dev, "string %d\n", i + 1);
> +		}
> +		return -EIO;
> +	}
> +
> +	ret = regmap_read(maxim->regmap, MAX25014_DIAG, &val);
> +	if (ret)
> +		return ret;
> +	/*
> +	 * The HW_RST bit always starts at 1 after power up.
> +	 * It is reset on first read, does not indicate an error.
> +	 */
> +	if (val && val != MAX25014_DIAG_HW_RST) {
> +		if (val & MAX25014_DIAG_OT)
> +			dev_err(&maxim->client->dev,
> +				"Overtemperature shutdown\n");
> +		if (val & MAX25014_DIAG_OTW)
> +			dev_err(&maxim->client->dev,
> +				 "Chip is getting too hot (>125C)\n");
> +		if (val & MAX25014_DIAG_BSTOV)
> +			dev_err(&maxim->client->dev,
> +				"Boost converter overvoltage\n");
> +		if (val & MAX25014_DIAG_BSTUV)
> +			dev_err(&maxim->client->dev,
> +				"Boost converter undervoltage\n");
> +		if (val & MAX25014_DIAG_IREFOOR)
> +			dev_err(&maxim->client->dev, "IREF out of range\n");
> +		return -EIO;
> +	}
> +	return 0;
> +}
> +
> +/*
> + * 1. disable unused strings
> + * 2. set dim mode
> + * 3. set setting register
> + * 4. enable the backlight
> + */
> +static int max25014_configure(struct max25014 *maxim, int initial_state)
> +{
> +	uint32_t val;
> +	int ret;
> +
> +	/*
> +	 * Strings can only be disabled when MAX25014_ISET_ENA == 0, check if
> +	 * it needs to be changed at all to prevent the backlight flashing when
> +	 * it is configured correctly by the bootloader
> +	 */

Attach the comment to the if statement rather than the read.


> +	ret = regmap_read(maxim->regmap, MAX25014_DISABLE, &val);
> +	if (ret)
> +		return ret;
> +
> +	if (!((val & MAX25014_DISABLE_DIS_MASK) == maxim->strings_mask)) {
> +		if (initial_state == BACKLIGHT_POWER_ON) {
> +			ret = regmap_write(maxim->regmap, MAX25014_ISET, 0);
> +			if (ret)
> +				return ret;
> +		}
> +		ret = regmap_write(maxim->regmap, MAX25014_DISABLE, maxim->strings_mask);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = regmap_write(maxim->regmap, MAX25014_IMODE, MAX25014_IMODE_HDIM);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_read(maxim->regmap, MAX25014_SETTING, &val);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_write(maxim->regmap, MAX25014_SETTING,
> +			   val & ~MAX25014_SETTING_FPWM);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_write(maxim->regmap, MAX25014_ISET,
> +			   maxim->iset | MAX25014_ISET_ENA |
> +			   MAX25014_ISET_PSEN);
> +	return ret;
> +}
> +
> +static int max25014_update_status(struct backlight_device *bl_dev)
> +{
> +	struct max25014 *maxim = bl_get_data(bl_dev);
> +	uint32_t reg;
> +	int ret;
> +
> +	if (backlight_is_blank(maxim->bl))
> +		bl_dev->props.brightness = 0;

This isn't right. Why would you change the backlight level just because
it is currently blanked (and sorry I missed this one last time).

> +
> +	reg  = TON_STEP * bl_dev->props.brightness;

The correct way to honour blanking is just go call
backlight_get_brightness() instead of reading the property directly.


> +
> +	/*
> +	 * 18 bit number lowest, 2 bits in first register,
> +	 * next lowest 8 in the L register, next 8 in the H register
> +	 * Seemingly setting the strength of only one string controls all of
> +	 * them, individual settings don't affect the outcome.
> +	 */
> +
> +	ret = regmap_write(maxim->regmap, MAX25014_TON_1_4_LSB, reg & 0b00000011);
> +	if (ret != 0)
> +		return ret;
> +	ret = regmap_write(maxim->regmap, MAX25014_TON1L, (reg >> 2) & 0b11111111);
> +	if (ret != 0)
> +		return ret;
> +	return regmap_write(maxim->regmap, MAX25014_TON1H, (reg >> 10) & 0b11111111);
> +}
> +
> +static const struct backlight_ops max25014_bl_ops = {
> +	.options = BL_CORE_SUSPENDRESUME,
> +	.update_status = max25014_update_status,
> +};
> +
> +static int max25014_parse_dt(struct max25014 *maxim,
> +			     uint32_t *initial_brightness)
> +{
> +	struct device *dev = &maxim->client->dev;
> +	struct device_node *node = dev->of_node;
> +	struct fwnode_handle *child;
> +	uint32_t strings[4];
> +	int res, i;
> +
> +	if (!node)
> +		return dev_err_probe(dev, -EINVAL, "no platform data\n");
> +
> +	child = device_get_next_child_node(dev, NULL);
> +	if (child) {
> +		res = fwnode_property_count_u32(child, "led-sources");
> +		if (res > 0) {
> +			fwnode_property_read_u32_array(child, "led-sources",
> +						       strings, res);
> +
> +			/* set all strings as disabled, then enable those in led-sources*/
> +			maxim->strings_mask = 0xf;
> +			for (i = 0; i < res; i++) {
> +				if (strings[i] <= 4)
> +					maxim->strings_mask &= ~BIT(strings[i]);
> +			}
> +		}
> +
> +		fwnode_property_read_u32(child, "default-brightness",
> +					 initial_brightness);
> +
> +		fwnode_handle_put(child);
> +	}
> +
> +	maxim->iset = MAX25014_ISET_DEFAULT_100;
> +	of_property_read_u32(node, "maxim,iset", &maxim->iset);
> +
> +	if (maxim->iset > 15)
> +		return dev_err_probe(dev, -EINVAL,
> +				     "Invalid iset, should be a value from 0-15, entered was %d\n",
> +				     maxim->iset);
> +
> +	if (*initial_brightness > 100)
> +		return dev_err_probe(dev, -EINVAL,
> +				     "Invalid initial brightness, should be a value from 0-100, entered was %d\n",
> +				     *initial_brightness);
> +
> +	return 0;
> +}
> +
> +static int max25014_probe(struct i2c_client *cl)
> +{
> +	const struct i2c_device_id *id = i2c_client_get_device_id(cl);
> +	struct backlight_properties props;
> +	uint32_t initial_brightness = 50;
> +	struct backlight_device *bl;
> +	struct max25014 *maxim;
> +	int ret;
> +
> +	maxim = devm_kzalloc(&cl->dev, sizeof(struct max25014), GFP_KERNEL);
> +	if (!maxim)
> +		return -ENOMEM;
> +
> +	maxim->client = cl;
> +
> +	ret = max25014_parse_dt(maxim, &initial_brightness);
> +	if (ret)
> +		return ret;
> +
> +	maxim->vin = devm_regulator_get(&maxim->client->dev, "power");
> +	if (IS_ERR(maxim->vin)) {
> +		return dev_err_probe(&maxim->client->dev, PTR_ERR(maxim->vin),
> +				     "failed to get power-supply");
> +	}
> +
> +	ret = regulator_enable(maxim->vin);
> +	if (ret)
> +		return dev_err_probe(&maxim->client->dev, ret,
> +			"failed to enable power-supply\n");

Can this use devm_regulator_get_enable()?


> +
> +	maxim->enable = devm_gpiod_get_optional(&maxim->client->dev, "enable",
> +						GPIOD_OUT_HIGH);
> +	if (IS_ERR(maxim->enable)) {
> +		ret = dev_err_probe(&maxim->client->dev, PTR_ERR(maxim->enable),
> +				    "failed to get enable gpio\n");
> +		goto disable_vin;
> +	}
> +
> +	/* Datasheet Electrical Characteristics tSTARTUP 2ms */
> +	fsleep(2000);
> +
> +	maxim->regmap = devm_regmap_init_i2c(cl, &max25014_regmap_config);
> +	if (IS_ERR(maxim->regmap)) {
> +		ret = dev_err_probe(&maxim->client->dev, PTR_ERR(maxim->regmap),
> +			"failed to initialize the i2c regmap\n");
> +		goto disable_full;
> +	}
> +
> +	i2c_set_clientdata(cl, maxim);
> +
> +	ret = max25014_check_errors(maxim);
> +	if (ret) { /* error is already reported in the above function */
> +		goto disable_full;
> +	}
> +
> +	ret = max25014_initial_power_state(maxim);
> +	if (ret < 0) {
> +		dev_err_probe(&maxim->client->dev, ret, "Could not get enabled state\n");
> +		goto disable_full;
> +	}
> +
> +	memset(&props, 0, sizeof(struct backlight_properties));
> +	props.type = BACKLIGHT_PLATFORM;
> +	props.max_brightness = MAX_BRIGHTNESS;
> +	props.brightness = initial_brightness;
> +	props.scale = BACKLIGHT_SCALE_LINEAR;
> +	props.power = ret;
> +
> +	ret = max25014_configure(maxim, ret);
> +	if (ret) {
> +		dev_err_probe(&maxim->client->dev, ret, "device config error");
> +		goto disable_full;
> +	}
> +
> +	bl = devm_backlight_device_register(&maxim->client->dev, id->name,
> +					    &maxim->client->dev, maxim,
> +					    &max25014_bl_ops, &props);
> +	if (IS_ERR(bl)) {
> +		ret = dev_err_probe(&maxim->client->dev, PTR_ERR(bl),
> +				    "failed to register backlight\n");
> +		goto disable_full;
> +	}
> +
> +	maxim->bl = bl;
> +
> +	backlight_update_status(maxim->bl);
> +
> +	return 0;
> +
> +disable_full:
> +	gpiod_set_value_cansleep(maxim->enable, 0);

Why is this needed? It was only ever set by devm_gpiod_get_optional().

> +disable_vin:
> +	regulator_disable(maxim->vin);

This is also not needed if you use devm_regulator_get_enable().


> +	return ret;
> +}


Daniel.


From mike.leach at linaro.org  Thu Dec  4 08:17:35 2025
From: mike.leach at linaro.org (Mike Leach)
Date: Thu, 4 Dec 2025 16:17:35 +0000
Subject: [PATCH v6 2/2] coresight: cti: Add Qualcomm extended CTI support
In-Reply-To: <20251204103151.GK724103@e132581.arm.com>
References: <20251202-extended_cti-v6-0-ab68bb15c4f5@oss.qualcomm.com>
 <20251202-extended_cti-v6-2-ab68bb15c4f5@oss.qualcomm.com>
 <20251203182944.GG724103@e132581.arm.com> <CAJ9a7VjWDBEwdmMf53geACBWGusC8BC3pJuOLETeecw24+N35Q@mail.gmail.com>
 <20251204103151.GK724103@e132581.arm.com>
Message-ID: <CAJ9a7VjHHkkTz9XJqjdQ+11_XX9zXuY0ZcQzPtq=Zvi4CN__0A@mail.gmail.com>

Hi Leo

On Thu, 4 Dec 2025 at 10:31, Leo Yan <leo.yan at arm.com> wrote:
>
> On Thu, Dec 04, 2025 at 09:07:56AM +0000, Mike Leach wrote:
>
> [...]
>
> > > I saw CTI registers are within 4KiB (0x1000), we can don't convert
> > > standard regiserts and only convert to QCOM register based on the
> > > standard ones.  So you can drop the cti_normal_offset strucuture and
> > > only have a cti_reg_qcom_offset[] struct:
> > >
> > >   static const u32 cti_extended_offset[] = {
> > >         [CTIINTACK]             = QCOM_CTIINTACK,
> > >         [CTIAPPSET]             = QCOM_CTIAPPSET,
> > >         [CTIAPPCLEAR]           = QCOM_CTIAPPCLEAR,
> > >         [CTIAPPPULSE]           = QCOM_CTIAPPPULSE,
> > >         [CTIINEN]               = QCOM_CTIINEN,
> > >         ...
> > >   };
> > >
> >

The tables in the patch are

    [reg_type_array_index] = offset_address;

e.g.

  [INDEX_CTIINTACK]  = QCOM_CTIINTACK

which resolves to

 [1] = 0x020

where index is constant for a given register type,

As far as I can tell what you have suggested above is a table that is

  [std_addr_offset] = qcom_addr_offset;

e.g.

[CTIINTACK]             = QCOM_CTIINTACK,

which resolves to

[0x10]  = 0x020

which does not appear to work correctly?

The registers are sparsely spread across the memory map, so a simple
mapping does not work, even if we divide the original offset by 4 to
create a register number.

The largest standard offset we have is ITTRIGIN = 0xEF8, so assuming
the compiler allows us to sparselly populate the array (which I think
it does, along with some padding), we end up with an array of at least
0xEF8 elements, rather then the indexed 21?

Regards

Mike

> > I suggested the dual offset approach a couple of patchset revisions
> > ago as it actually simplifies the code & makes it more efficient. The
> > offset array in use is set during probe and the remaining code is then
> > common to both without lots of "if qcom else " occurences.
>
> AFAICS, we will handle the QCOM CTI particularly in three cases:
>
>   1) The register access;
>   2) The claim tag;
>   3) Sysfs attr is visible.
>
> Now we are discussing the reigster access.  As suggested, the
> "if qcom / else" is encapsulated (e.g., in cti_reg_addr_with_nr()), it
> will not spread out.
>
> I'd use standard registers by default and convert to non-standard ones
> only when needed.  A new "neutral" index layer seems redundant, as the
> existing standard register indexes already serve this purpose.
>
> For the sysfs attrs, it makes sense to use a central place to decide
> which knobs are only visible for QCOM CTI, otherwise, we also will not
> spread the condition check.
>
> I will reply separately for claim tag issue.
>
> Thanks,
> Leo


--
Mike Leach
Principal Engineer, ARM Ltd.
Manchester Design Centre. UK


From jmkrzyszt at gmail.com  Thu Dec  4 08:27:16 2025
From: jmkrzyszt at gmail.com (Janusz Krzysztofik)
Date: Thu, 04 Dec 2025 17:27:16 +0100
Subject: [PATCH] ARM: omap1: avoid symbol clashes in fiq handler
In-Reply-To: <20251204095355.1032786-1-arnd@kernel.org>
References: <20251204095355.1032786-1-arnd@kernel.org>
Message-ID: <6216166.lOV4Wx5bFT@dell>

On Thursday, 4 December 2025 10:53:47 CET Arnd Bergmann wrote:
> From: Arnd Bergmann <arnd at arndb.de>
> 
> The ams-delta-fiq-handler.S file has a number of symbols with fairly
> generic names, including one named 'exit' that causes a compiler warning
> in some configuration options:
> 
> vmlinux.o: error: exit() function name creates ambiguity with -ffunction-sections
> 
> Change all these symbols to use a .L prefix to make them local to
> the fiq handler.

Reviewed-by: Janusz Krzysztofik <jmkrzyszt at gmail.com>

> 
> Signed-off-by: Arnd Bergmann <arnd at arndb.de>
> ---
>  arch/arm/mach-omap1/ams-delta-fiq-handler.S | 38 ++++++++++-----------
>  1 file changed, 19 insertions(+), 19 deletions(-)
> 
> diff --git a/arch/arm/mach-omap1/ams-delta-fiq-handler.S b/arch/arm/mach-omap1/ams-delta-fiq-handler.S
> index 35c2f9574dbd..5cf6fcca602c 100644
> --- a/arch/arm/mach-omap1/ams-delta-fiq-handler.S
> +++ b/arch/arm/mach-omap1/ams-delta-fiq-handler.S
> @@ -97,7 +97,7 @@ ENTRY(qwerty_fiqin_start)
>  
>  	ldr r13, [r12, #IRQ_ITR_REG_OFFSET]	@ fetch interrupts status
>  	bics r13, r13, r11			@ clear masked - any left?
> -	beq exit				@ none - spurious FIQ? exit
> +	beq .Lexit				@ none - spurious FIQ? exit
>  
>  	ldr r10, [r12, #IRQ_SIR_FIQ_REG_OFFSET]	@ get requested interrupt number
>  
> @@ -105,25 +105,25 @@ ENTRY(qwerty_fiqin_start)
>  	str r8, [r12, #IRQ_CONTROL_REG_OFFSET]
>  
>  	cmp r10, #(INT_GPIO_BANK1 - NR_IRQS_LEGACY)	@ is it GPIO interrupt?
> -	beq gpio				@ yes - process it
> +	beq .Lgpio				@ yes - process it
>  
>  	mov r8, #1
>  	orr r8, r11, r8, lsl r10		@ mask spurious interrupt
>  	str r8, [r12, #IRQ_MIR_REG_OFFSET]
> -exit:
> +.Lexit:
>  	subs	pc, lr, #4			@ return from FIQ
>  	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
>  
>  
>  	@@@@@@@@@@@@@@@@@@@@@@@@@@@
> -gpio:	@ GPIO bank interrupt handler
> +.Lgpio:	@ GPIO bank interrupt handler
>  	ldr r12, omap1510_gpio_base		@ set base pointer to GPIO bank
>  
>  	ldr r11, [r12, #OMAP1510_GPIO_INT_MASK]	@ fetch GPIO interrupts mask
> -restart:
> +.Lrestart:
>  	ldr r13, [r12, #OMAP1510_GPIO_INT_STATUS]	@ fetch status bits
>  	bics r13, r13, r11			@ clear masked - any left?
> -	beq exit				@ no - spurious interrupt? exit
> +	beq .Lexit				@ no - spurious interrupt? exit
>  
>  	orr r11, r11, r13			@ mask all requested interrupts
>  	str r11, [r12, #OMAP1510_GPIO_INT_MASK]
> @@ -131,7 +131,7 @@ restart:
>  	str r13, [r12, #OMAP1510_GPIO_INT_STATUS] @ ack all requested interrupts
>  
>  	ands r10, r13, #KEYBRD_CLK_MASK		@ extract keyboard status - set?
> -	beq hksw				@ no - try next source
> +	beq .Lhksw				@ no - try next source
>  
>  
>  	@@@@@@@@@@@@@@@@@@@@@@
> @@ -145,10 +145,10 @@ restart:
>  
>  	ldr r10, [r9, #BUF_STATE]		@ fetch kbd interface state
>  	cmp r10, #0				@ are we expecting start bit?
> -	bne data				@ no - go to data processing
> +	bne .Ldata				@ no - go to data processing
>  
>  	ands r8, r8, #KEYBRD_DATA_MASK		@ check start bit - detected?
> -	beq hksw				@ no - try next source
> +	beq .Lhksw				@ no - try next source
>  
>  	@ r8 contains KEYBRD_DATA_MASK, use it
>  	str r8, [r9, #BUF_STATE]		@ enter data processing state
> @@ -162,9 +162,9 @@ restart:
>  	mvn r11, #KEYBRD_CLK_MASK		@ prepare all except kbd mask
>  	str r11, [r12, #OMAP1510_GPIO_INT_MASK]	@ store into the mask register
>  
> -	b restart				@ restart
> +	b .Lrestart				@ restart
>  
> -data:	ldr r10, [r9, #BUF_MASK]		@ fetch current input bit mask
> +.Ldata:	ldr r10, [r9, #BUF_MASK]		@ fetch current input bit mask
>  
>  	@ r8 still contains GPIO input bits
>  	ands r8, r8, #KEYBRD_DATA_MASK		@ is keyboard data line low?
> @@ -175,7 +175,7 @@ data:	ldr r10, [r9, #BUF_MASK]		@ fetch current input bit mask
>  	mov r10, r10, lsl #1			@ shift mask left
>  	bics r10, r10, #0x800			@ have we got all the bits?
>  	strne r10, [r9, #BUF_MASK]		@ not yet - store the mask
> -	bne restart				@ and restart
> +	bne .Lrestart				@ and restart
>  
>  	@ r10 already contains 0, reuse it
>  	str r10, [r9, #BUF_STATE]		@ reset state to start
> @@ -189,7 +189,7 @@ data:	ldr r10, [r9, #BUF_MASK]		@ fetch current input bit mask
>  	ldr r10, [r9, #BUF_KEYS_CNT]		@ get saved keystrokes count
>  	ldr r8, [r9, #BUF_BUF_LEN]		@ get buffer size
>  	cmp r10, r8				@ is buffer full?
> -	beq hksw				@ yes - key lost, next source
> +	beq .Lhksw				@ yes - key lost, next source
>  
>  	add r10, r10, #1			@ incremet keystrokes counter
>  	str r10, [r9, #BUF_KEYS_CNT]
> @@ -213,9 +213,9 @@ data:	ldr r10, [r9, #BUF_MASK]		@ fetch current input bit mask
>  	@@@@@@@@@@@@@@@@@@@@@@@@
>  
>  
> -hksw:	@Is hook switch interrupt requested?
> +.Lhksw:	@Is hook switch interrupt requested?
>  	tst r13, #HOOK_SWITCH_MASK 		@ is hook switch status bit set?
> -	beq mdm					@ no - try next source
> +	beq .Lmdm				@ no - try next source
>  
>  
>  	@@@@@@@@@@@@@@@@@@@@@@@@
> @@ -230,9 +230,9 @@ hksw:	@Is hook switch interrupt requested?
>  	@@@@@@@@@@@@@@@@@@@@@@@@
>  
>  
> -mdm:	@Is it a modem interrupt?
> +.Lmdm:	@Is it a modem interrupt?
>  	tst r13, #MODEM_IRQ_MASK 		@ is modem status bit set?
> -	beq irq					@ no - check for next interrupt
> +	beq .Lirq				@ no - check for next interrupt
>  
>  
>  	@@@@@@@@@@@@@@@@@@@@@@@@
> @@ -245,13 +245,13 @@ mdm:	@Is it a modem interrupt?
>  	@@@@@@@@@@@@@@@@@@@@@@@@
>  
>  
> -irq:	@ Place deferred_fiq interrupt request
> +.Lirq:	@ Place deferred_fiq interrupt request
>  	ldr r12, deferred_fiq_ih_base		@ set pointer to IRQ handler
>  	mov r10, #DEFERRED_FIQ_MASK		@ set deferred_fiq bit
>  	str r10, [r12, #IRQ_ISR_REG_OFFSET] 	@ place it in the ISR register
>  
>  	ldr r12, omap1510_gpio_base		@ set pointer back to GPIO bank
> -	b restart				@ check for next GPIO interrupt
> +	b .Lrestart				@ check for next GPIO interrupt
>  	@@@@@@@@@@@@@@@@@@@@@@@@@@@
>  
>  
> 

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251204/bce683e6/attachment.sig>

From ardb at kernel.org  Thu Dec  4 08:28:15 2025
From: ardb at kernel.org (Ard Biesheuvel)
Date: Thu,  4 Dec 2025 17:28:15 +0100
Subject: [PATCH] arm64/simd: Avoid pointless clearing of FP/SIMD buffer
Message-ID: <20251204162815.522879-2-ardb@kernel.org>

The buffer provided to kernel_neon_begin() is only used if the task is
scheduled out while the FP/SIMD is in use by the kernel, or when such a
section is interrupted by a softirq that also uses the FP/SIMD.

IOW, this happens rarely, and even if it happened often, there is still
no reason for this buffer to be cleared beforehand, which happens by
default when using a compiler that supports -ftrivial-auto-var-init.

So mark the buffer as __uninitialized. Given that this is a variable
attribute not a type attribute, this requires that the expression is
tweaked a bit.

Cc: Will Deacon <will at kernel.org>,
Cc: Catalin Marinas <catalin.marinas at arm.com>,
Cc: Kees Cook <keescook at chromium.org>
Cc: Eric Biggers <ebiggers at kernel.org>
Cc: Justin Stitt <justinstitt at google.com>
Signed-off-by: Ard Biesheuvel <ardb at kernel.org>
---
 arch/arm64/include/asm/simd.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

The issue here is that returning a pointer to an automatic variable as
it goes out of scope is slightly dodgy, especially in the context of
__attribute__((cleanup())), on which the scoped guard API relies
heavily. However, in this case it should be safe, given that this
expression is the input to the guarded variable type's constructor.

It is definitely not pretty, though, so hopefully here is a better way
to attach this.

diff --git a/arch/arm64/include/asm/simd.h b/arch/arm64/include/asm/simd.h
index 0941f6f58a14..825b7fe94003 100644
--- a/arch/arm64/include/asm/simd.h
+++ b/arch/arm64/include/asm/simd.h
@@ -48,6 +48,7 @@ DEFINE_LOCK_GUARD_1(ksimd,
 		    kernel_neon_begin(_T->lock),
 		    kernel_neon_end(_T->lock))
 
-#define scoped_ksimd()	scoped_guard(ksimd, &(struct user_fpsimd_state){})
+#define scoped_ksimd()	\
+	scoped_guard(ksimd, ({ struct user_fpsimd_state __uninitialized s; &s; }))
 
 #endif
-- 
2.47.3



From olteanv at gmail.com  Thu Dec  4 08:33:15 2025
From: olteanv at gmail.com (Vladimir Oltean)
Date: Thu, 4 Dec 2025 18:33:15 +0200
Subject: [PATCH v3 2/2] net: dsa: mt7530: Use GPIO polarity to generate
 correct reset sequence
In-Reply-To: <6344bdfd-c22c-45a1-854d-59091dfeda97@kernel.org>
References: <0675b35f-217d-4261-9e3f-2eb24753d43c@lunn.ch>
 <20251130080731.ty2dlxaypxvodxiw@skbuf>
 <3fbc4e67-b931-421c-9d83-2214aaa2f6ed@lunn.ch>
 <0d85e1e6-ea75-4f20-aef1-90d446b4bfa1@kernel.org>
 <00f308a1-a4b1-4f20-8d8e-459ddf4c39b1@gmx.de>
 <aS7Zj3AFsSp2CTNv@makrotopia.org>
 <20251204131626.upw77jncqfwxydww@skbuf>
 <7aacc2c2-50d0-4a08-9800-dc4a572dffcb@lunn.ch>
 <20251204153721.ubmxifrev4cre6ab@skbuf>
 <6344bdfd-c22c-45a1-854d-59091dfeda97@kernel.org>
Message-ID: <20251204163315.rlc36k72cwfdyye6@skbuf>

On Thu, Dec 04, 2025 at 04:52:53PM +0100, Krzysztof Kozlowski wrote:
> Yeah. BTW, you can also refer to one of my commits -
> 738455858a2d21b769f673892546cf8300c9fd78 - but also note that similar
> work later combined with much more useful change of gpio->gpiod API was
> rejected by Mark Brown on basis:
> 
> "No, the DT is supposed to be an ABI.  The point in having a domain
> specific language with a compiler is to allow device trees to be
> distributed independently of the kernel."
> 
> https://lore.kernel.org/all/9942c3a9-51d1-4161-8871-f6ec696cb4db at sirena.org.uk/
> 
> What's interesting, exactly the same commit for the same file, done by
> different person (Peng), introducing the same issues without addressing
> them, was then merged by Mark:
> https://patch.msgid.link/20250324-wcd-gpiod-v2-2-773f67ce3b56 at nxp.com
> (commit c2d359b4acfbe847d3edcc25d3dc4e594daf9010)
> 
> so you know... it's all relative. :)

Yeah, IDK. May we all stand by our own past statements.


From jmkrzyszt at gmail.com  Thu Dec  4 08:38:59 2025
From: jmkrzyszt at gmail.com (Janusz Krzysztofik)
Date: Thu, 04 Dec 2025 17:38:59 +0100
Subject: [PATCH] ALSA: Do not build obsolete API
In-Reply-To: <20251203-old-alsa-v1-1-ac80704f52c3@ixit.cz>
References: <20251203-old-alsa-v1-1-ac80704f52c3@ixit.cz>
Message-ID: <1939135.tdWV9SEqCh@dell>

On Wednesday, 3 December 2025 23:34:10 CET David Heidelberg via B4 Relay wrote:
> From: David Heidelberg <david at ixit.cz>
> 
> ALSA 0.9.0-rc3 is from 2002, 23 years old.
> 
> Signed-off-by: David Heidelberg <david at ixit.cz>
> ---
> Maybe I could drop also the code and Kconfig option?
> 
> David
> ---
>  arch/arm/configs/am200epdkit_defconfig    | 1 -
>  arch/arm/configs/lpc32xx_defconfig        | 1 -
>  arch/arm/configs/omap1_defconfig          | 1 -

For omap1:

Reviewed-by: Janusz Krzysztofik <jmkrzyszt at gmail.com>


>  arch/arm/configs/tegra_defconfig          | 1 -
>  arch/mips/configs/gcw0_defconfig          | 1 -
>  arch/mips/configs/loongson1_defconfig     | 1 -
>  arch/mips/configs/qi_lb60_defconfig       | 1 -
>  arch/mips/configs/rbtx49xx_defconfig      | 1 -
>  arch/mips/configs/rs90_defconfig          | 1 -
>  arch/powerpc/configs/85xx-hw.config       | 1 -
>  arch/powerpc/configs/86xx-hw.config       | 1 -
>  arch/powerpc/configs/mpc5200_defconfig    | 1 -
>  arch/powerpc/configs/ppc6xx_defconfig     | 1 -
>  arch/sh/configs/edosk7760_defconfig       | 1 -
>  arch/sh/configs/se7724_defconfig          | 1 -
>  arch/sh/configs/sh7785lcr_32bit_defconfig | 1 -
>  sound/core/Kconfig                        | 2 +-
>  17 files changed, 1 insertion(+), 17 deletions(-)
> 
> diff --git a/arch/arm/configs/am200epdkit_defconfig b/arch/arm/configs/am200epdkit_defconfig
> index 134a559aba3dd..2367b1685c1cf 100644
> --- a/arch/arm/configs/am200epdkit_defconfig
> +++ b/arch/arm/configs/am200epdkit_defconfig
> @@ -68,7 +68,6 @@ CONFIG_SOUND=m
>  CONFIG_SND=m
>  CONFIG_SND_MIXER_OSS=m
>  CONFIG_SND_PCM_OSS=m
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>  # CONFIG_SND_VERBOSE_PROCFS is not set
>  CONFIG_SND_PXA2XX_AC97=m
>  CONFIG_USB_GADGET=y
> diff --git a/arch/arm/configs/lpc32xx_defconfig b/arch/arm/configs/lpc32xx_defconfig
> index 2bddb0924a8c0..b9e2e603cd95e 100644
> --- a/arch/arm/configs/lpc32xx_defconfig
> +++ b/arch/arm/configs/lpc32xx_defconfig
> @@ -113,7 +113,6 @@ CONFIG_LOGO=y
>  # CONFIG_LOGO_LINUX_VGA16 is not set
>  CONFIG_SOUND=y
>  CONFIG_SND=y
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>  # CONFIG_SND_VERBOSE_PROCFS is not set
>  CONFIG_SND_DEBUG=y
>  CONFIG_SND_DEBUG_VERBOSE=y
> diff --git a/arch/arm/configs/omap1_defconfig b/arch/arm/configs/omap1_defconfig
> index dee820474f444..df88763fc7c3d 100644
> --- a/arch/arm/configs/omap1_defconfig
> +++ b/arch/arm/configs/omap1_defconfig
> @@ -148,7 +148,6 @@ CONFIG_SOUND=y
>  CONFIG_SND=y
>  CONFIG_SND_MIXER_OSS=y
>  CONFIG_SND_PCM_OSS=y
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>  # CONFIG_SND_VERBOSE_PROCFS is not set
>  CONFIG_SND_DUMMY=y
>  CONFIG_SND_USB_AUDIO=y
> diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig
> index ce70ff07c978a..68aedaf92667a 100644
> --- a/arch/arm/configs/tegra_defconfig
> +++ b/arch/arm/configs/tegra_defconfig
> @@ -219,7 +219,6 @@ CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
>  CONFIG_LOGO=y
>  CONFIG_SOUND=y
>  CONFIG_SND=y
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>  # CONFIG_SND_DRIVERS is not set
>  CONFIG_SND_HDA_TEGRA=y
>  CONFIG_SND_HDA_INPUT_BEEP=y
> diff --git a/arch/mips/configs/gcw0_defconfig b/arch/mips/configs/gcw0_defconfig
> index fda9971bdd8d9..adb9fd62ddb0d 100644
> --- a/arch/mips/configs/gcw0_defconfig
> +++ b/arch/mips/configs/gcw0_defconfig
> @@ -79,7 +79,6 @@ CONFIG_LOGO=y
>  # CONFIG_LOGO_LINUX_VGA16 is not set
>  CONFIG_SOUND=y
>  CONFIG_SND=y
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>  # CONFIG_SND_PROC_FS is not set
>  # CONFIG_SND_DRIVERS is not set
>  # CONFIG_SND_SPI is not set
> diff --git a/arch/mips/configs/loongson1_defconfig b/arch/mips/configs/loongson1_defconfig
> index 02d29110f7024..1d9781ff96986 100644
> --- a/arch/mips/configs/loongson1_defconfig
> +++ b/arch/mips/configs/loongson1_defconfig
> @@ -119,7 +119,6 @@ CONFIG_WATCHDOG_SYSFS=y
>  CONFIG_LOONGSON1_WDT=y
>  CONFIG_SOUND=y
>  CONFIG_SND=y
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>  # CONFIG_SND_DRIVERS is not set
>  # CONFIG_SND_MIPS is not set
>  # CONFIG_SND_USB is not set
> diff --git a/arch/mips/configs/qi_lb60_defconfig b/arch/mips/configs/qi_lb60_defconfig
> index 5f5b0254d75e7..a1bb0792f6eb1 100644
> --- a/arch/mips/configs/qi_lb60_defconfig
> +++ b/arch/mips/configs/qi_lb60_defconfig
> @@ -81,7 +81,6 @@ CONFIG_LOGO=y
>  # CONFIG_LOGO_LINUX_CLUT224 is not set
>  CONFIG_SOUND=y
>  CONFIG_SND=y
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>  # CONFIG_SND_VERBOSE_PROCFS is not set
>  # CONFIG_SND_DRIVERS is not set
>  # CONFIG_SND_SPI is not set
> diff --git a/arch/mips/configs/rbtx49xx_defconfig b/arch/mips/configs/rbtx49xx_defconfig
> index 03a7bbe28a532..49c709d663beb 100644
> --- a/arch/mips/configs/rbtx49xx_defconfig
> +++ b/arch/mips/configs/rbtx49xx_defconfig
> @@ -53,7 +53,6 @@ CONFIG_TXX9_WDT=m
>  # CONFIG_VGA_ARB is not set
>  CONFIG_SOUND=m
>  CONFIG_SND=m
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>  # CONFIG_SND_VERBOSE_PROCFS is not set
>  # CONFIG_SND_DRIVERS is not set
>  # CONFIG_SND_PCI is not set
> diff --git a/arch/mips/configs/rs90_defconfig b/arch/mips/configs/rs90_defconfig
> index a53dd66e9b864..8382d535e6dc1 100644
> --- a/arch/mips/configs/rs90_defconfig
> +++ b/arch/mips/configs/rs90_defconfig
> @@ -105,7 +105,6 @@ CONFIG_LOGO=y
>  CONFIG_SOUND=y
>  CONFIG_SND=y
>  # CONFIG_SND_PCM_TIMER is not set
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>  # CONFIG_SND_PROC_FS is not set
>  # CONFIG_SND_DRIVERS is not set
>  # CONFIG_SND_MIPS is not set
> diff --git a/arch/powerpc/configs/85xx-hw.config b/arch/powerpc/configs/85xx-hw.config
> index 8aff832173977..2b19c20a9a2c4 100644
> --- a/arch/powerpc/configs/85xx-hw.config
> +++ b/arch/powerpc/configs/85xx-hw.config
> @@ -117,7 +117,6 @@ CONFIG_SND_INTEL8X0=y
>  CONFIG_SND_POWERPC_SOC=y
>  # CONFIG_SND_PPC is not set
>  CONFIG_SND_SOC=y
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>  # CONFIG_SND_USB is not set
>  CONFIG_SND=y
>  CONFIG_SOUND=y
> diff --git a/arch/powerpc/configs/86xx-hw.config b/arch/powerpc/configs/86xx-hw.config
> index e7bd265fae5a4..07f30ab881e59 100644
> --- a/arch/powerpc/configs/86xx-hw.config
> +++ b/arch/powerpc/configs/86xx-hw.config
> @@ -80,7 +80,6 @@ CONFIG_SERIO_LIBPS2=y
>  CONFIG_SND_INTEL8X0=y
>  CONFIG_SND_MIXER_OSS=y
>  CONFIG_SND_PCM_OSS=y
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>  CONFIG_SND=y
>  CONFIG_SOUND=y
>  CONFIG_ULI526X=y
> diff --git a/arch/powerpc/configs/mpc5200_defconfig b/arch/powerpc/configs/mpc5200_defconfig
> index c0fe5e76604a0..617650cea56a9 100644
> --- a/arch/powerpc/configs/mpc5200_defconfig
> +++ b/arch/powerpc/configs/mpc5200_defconfig
> @@ -75,7 +75,6 @@ CONFIG_FB_SM501=m
>  CONFIG_LOGO=y
>  CONFIG_SOUND=y
>  CONFIG_SND=y
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>  # CONFIG_SND_DRIVERS is not set
>  # CONFIG_SND_PCI is not set
>  # CONFIG_SND_PPC is not set
> diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig
> index b082c1fae13c9..787d707f64a42 100644
> --- a/arch/powerpc/configs/ppc6xx_defconfig
> +++ b/arch/powerpc/configs/ppc6xx_defconfig
> @@ -726,7 +726,6 @@ CONFIG_SND_OSSEMUL=y
>  CONFIG_SND_MIXER_OSS=m
>  CONFIG_SND_PCM_OSS=m
>  CONFIG_SND_DYNAMIC_MINORS=y
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>  CONFIG_SND_VERBOSE_PRINTK=y
>  CONFIG_SND_DEBUG=y
>  CONFIG_SND_DEBUG_VERBOSE=y
> diff --git a/arch/sh/configs/edosk7760_defconfig b/arch/sh/configs/edosk7760_defconfig
> index abeae220606a3..905fac1072845 100644
> --- a/arch/sh/configs/edosk7760_defconfig
> +++ b/arch/sh/configs/edosk7760_defconfig
> @@ -79,7 +79,6 @@ CONFIG_FB_TILEBLITTING=y
>  CONFIG_FB_SH_MOBILE_LCDC=m
>  CONFIG_SOUND=y
>  CONFIG_SND=y
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>  # CONFIG_SND_VERBOSE_PROCFS is not set
>  CONFIG_SND_VERBOSE_PRINTK=y
>  CONFIG_SND_SOC=y
> diff --git a/arch/sh/configs/se7724_defconfig b/arch/sh/configs/se7724_defconfig
> index 9e3a54936f76f..8ca46d704c8ba 100644
> --- a/arch/sh/configs/se7724_defconfig
> +++ b/arch/sh/configs/se7724_defconfig
> @@ -83,7 +83,6 @@ CONFIG_LOGO=y
>  # CONFIG_LOGO_SUPERH_VGA16 is not set
>  CONFIG_SOUND=y
>  CONFIG_SND=m
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>  # CONFIG_SND_DRIVERS is not set
>  # CONFIG_SND_SPI is not set
>  # CONFIG_SND_SUPERH is not set
> diff --git a/arch/sh/configs/sh7785lcr_32bit_defconfig b/arch/sh/configs/sh7785lcr_32bit_defconfig
> index eb63aa61b0465..5468cc53cddb4 100644
> --- a/arch/sh/configs/sh7785lcr_32bit_defconfig
> +++ b/arch/sh/configs/sh7785lcr_32bit_defconfig
> @@ -93,7 +93,6 @@ CONFIG_SND_PCM_OSS=y
>  CONFIG_SND_SEQUENCER_OSS=y
>  CONFIG_SND_HRTIMER=y
>  CONFIG_SND_DYNAMIC_MINORS=y
> -# CONFIG_SND_SUPPORT_OLD_API is not set
>  # CONFIG_SND_VERBOSE_PROCFS is not set
>  CONFIG_SND_VERBOSE_PRINTK=y
>  CONFIG_SND_DEBUG=y
> diff --git a/sound/core/Kconfig b/sound/core/Kconfig
> index 48db44fa56feb..4e7bc370ffd7f 100644
> --- a/sound/core/Kconfig
> +++ b/sound/core/Kconfig
> @@ -155,7 +155,7 @@ config SND_MAX_CARDS
>  
>  config SND_SUPPORT_OLD_API
>  	bool "Support old ALSA API"
> -	default y
> +	default n
>  	help
>  	  Say Y here to support the obsolete ALSA PCM API (ver.0.9.0 rc3
>  	  or older).
> 
> ---
> base-commit: b2c27842ba853508b0da00187a7508eb3a96c8f7
> change-id: 20251203-old-alsa-fa2c2cb038e1
> 
> Best regards,
> 

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251204/2987e229/attachment.sig>

From visitorckw at gmail.com  Thu Dec  4 08:42:28 2025
From: visitorckw at gmail.com (Kuan-Wei Chiu)
Date: Thu,  4 Dec 2025 16:42:28 +0000
Subject: [PATCH] ARM: dts: integrator: Fix DMA ranges mismatch warning on IM-PD1
Message-ID: <20251204164228.113587-1-visitorckw@gmail.com>

When compiling the device tree for the Integrator/AP with IM-PD1, the
following warning is observed regarding the display controller node:

arch/arm/boot/dts/arm/integratorap-im-pd1.dts:251.3-14: Warning
(dma_ranges_format):
/bus at c0000000/bus at c0000000/display at 1000000:dma-ranges: empty
"dma-ranges" property but its #address-cells (2) differs from
/bus at c0000000/bus at c0000000 (1)

The display node specifies an empty "dma-ranges" property, intended to
describe a 1:1 identity mapping. However, the node lacks explicit
"#address-cells" and "#size-cells" properties. In this case, the device
tree compiler defaults the address cells to 2 (64-bit), which conflicts
with the parent bus configuration (32-bit, 1 cell).

Fix this by explicitly defining "#address-cells" and "#size-cells" as
1. This matches the 32-bit architecture of the Integrator platform and
ensures the address translation range is correctly parsed by the
compiler.

Fixes: 7bea67a99430 ("ARM: dts: integrator: Fix DMA ranges")
Cc: stable at vger.kernel.org
Signed-off-by: Kuan-Wei Chiu <visitorckw at gmail.com>
---
 arch/arm/boot/dts/arm/integratorap-im-pd1.dts | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/boot/dts/arm/integratorap-im-pd1.dts b/arch/arm/boot/dts/arm/integratorap-im-pd1.dts
index db13e09f2fab..6d90d9a42dc9 100644
--- a/arch/arm/boot/dts/arm/integratorap-im-pd1.dts
+++ b/arch/arm/boot/dts/arm/integratorap-im-pd1.dts
@@ -248,6 +248,8 @@ display at 1000000 {
 		/* 640x480 16bpp @ 25.175MHz is 36827428 bytes/s */
 		max-memory-bandwidth = <40000000>;
 		memory-region = <&impd1_ram>;
+		#address-cells = <1>;
+		#size-cells = <1>;
 		dma-ranges;
 
 		port at 0 {
-- 
2.52.0.177.g9f829587af-goog



From krzk at kernel.org  Thu Dec  4 08:48:07 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 4 Dec 2025 17:48:07 +0100
Subject: [PATCH v3 2/2] net: dsa: mt7530: Use GPIO polarity to generate
 correct reset sequence
In-Reply-To: <20251204160247.yz42mnxvzhxas5jc@skbuf>
References: <20251129234603.2544-1-ptpt52@gmail.com>
 <20251129234603.2544-2-ptpt52@gmail.com>
 <0675b35f-217d-4261-9e3f-2eb24753d43c@lunn.ch>
 <20251130080731.ty2dlxaypxvodxiw@skbuf>
 <3fbc4e67-b931-421c-9d83-2214aaa2f6ed@lunn.ch>
 <0d85e1e6-ea75-4f20-aef1-90d446b4bfa1@kernel.org>
 <00f308a1-a4b1-4f20-8d8e-459ddf4c39b1@gmx.de>
 <aS7Zj3AFsSp2CTNv@makrotopia.org> <20251204131626.upw77jncqfwxydww@skbuf>
 <4170c560-1edd-4ff8-96af-a479063be4a5@kernel.org>
 <20251204160247.yz42mnxvzhxas5jc@skbuf>
Message-ID: <66d080f1-e989-451f-9d5e-34460e5eb1b0@kernel.org>

On 04/12/2025 17:02, Vladimir Oltean wrote:
> On Thu, Dec 04, 2025 at 03:49:52PM +0100, Krzysztof Kozlowski wrote:
>> On 04/12/2025 14:16, Vladimir Oltean wrote:
>>> I get the feeling that we're complicating a simple solution because of a
>>> theoretical "what if" scenario. The "NOT" gate is somewhat contrived
>>
>> You downplay this case and suggest (if I get it right) that NOT gate is
>> something unusual.
>>
>>  I mentioned "line inverter" but it's not about NOT gate. There is no
>> need for NOT gate at all, like some magical component which no one puts
>> to the board. The only thing needed is just to pull the GPIO up or down,
>> that's it. It's completely normal design thus it CAN happen.
>>
>> Of course "can" does not mean it actually does, because certain
>> configurations like powerdown-fail-safe are more likely and I am not an
>> electric circuit designer to tell which one is better, but that
>> downplaying does not help here.
> 
> I don't want to dismiss this comment, but I don't really understand it.
> What do you mean by "line inverter", is it the component inside the GPIO
> pin which makes it active low?

I mentioned much earlier "line inverter" and here the "NOT gate"
appeared and both suggest you need some dedicated component.

What I want to say that it is not true. You do not need dedicated
component to have different polarity, because it is as simple as
connecting the wire to ground or to voltage and moving a resistor from
one place to another.

> 
> I thought that the premise of this patch set is that old device trees
> are all (incorrectly) defined as GPIO_ACTIVE_HIGH, but someone familiar
> with the matter needs to fact-check this statement.

Yes, that's most likely true.

> 
> Anyway, you and Andrew are talking about different things, you haven't
> made it clear (or at least it wasn't clear to me) that the inverter you
> are talking about isn't his NOT gate (that isn't described in the device
> tree at all, as opposed to your inverter which would make the GPIO line
> GPIO_ACTIVE_LOW - that's something verifiable).

Both are the same - inverter or NOT gate, same stuff. It is just
connecting wire to pull up, not actual component on the board (although
one could make and buy such component as well...). We never describe
these inverters in the DTS, these are just too trivial circuits, thus
the final GPIO_ACTIVE_XXX should already include whatever is on the wire
between SoC and device.

> 
>> Just to clarify: I expect clear communication that some users will be
>> broken with as good as you can provide analysis of the impact (which
>> users). I only object the clame here "no one can ever pull down a GPIO
>> line thus I handled all possible cases and made it backward compatible".
>>
>> And that claim to quote was:
>> "Therefore, regardless of whether a DTS is old or new, correct or
>> incorrect, the driver now generates the correct electrical reset pulse."
>>
>> which is 100% false and I am surprised how one could claim that.
> 
> Agree, the communication should be better.


Best regards,
Krzysztof


From krzk at kernel.org  Thu Dec  4 08:48:57 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 4 Dec 2025 17:48:57 +0100
Subject: [PATCH net-next 5/9] phy: add phy_get_rx_polarity() and
 phy_get_tx_polarity()
In-Reply-To: <20251204153401.tinrt57ifjthw55r@skbuf>
References: <20251122193341.332324-1-vladimir.oltean@nxp.com>
 <20251122193341.332324-6-vladimir.oltean@nxp.com>
 <20251124200121.5b82f09e@kernel.org> <aS1T5i3pCHsNVql6@vaman>
 <69ac21ea-eed2-449a-b231-c43e3cd0bdc0@kernel.org>
 <20251204153401.tinrt57ifjthw55r@skbuf>
Message-ID: <c7cbdaaa-e786-4842-9346-e2fde998fde5@kernel.org>

On 04/12/2025 16:34, Vladimir Oltean wrote:
> On Mon, Dec 01, 2025 at 09:41:21AM +0100, Krzysztof Kozlowski wrote:
>> On 01/12/2025 09:37, Vinod Koul wrote:
>>> On 24-11-25, 20:01, Jakub Kicinski wrote:
>>>> On Sat, 22 Nov 2025 21:33:37 +0200 Vladimir Oltean wrote:
>>>>> Add helpers in the generic PHY folder which can be used using 'select
>>>>> GENERIC_PHY_COMMON_PROPS' from Kconfig, without otherwise needing to
>>>>> enable GENERIC_PHY.
>>>>>
>>>>> These helpers need to deal with the slight messiness of the fact that
>>>>> the polarity properties are arrays per protocol, and with the fact that
>>>>> there is no default value mandated by the standard properties, all
>>>>> default values depend on driver and protocol (PHY_POL_NORMAL may be a
>>>>> good default for SGMII, whereas PHY_POL_AUTO may be a good default for
>>>>> PCIe).
>>>>>
>>>>> Push the supported mask of polarities to these helpers, to simplify
>>>>> drivers such that they don't need to validate what's in the device tree
>>>>> (or other firmware description).
>>>>>
>>>>> The proposed maintainership model is joint custody between netdev and
>>>>> linux-phy, because of the fact that these properties can be applied to
>>>>> Ethernet PCS blocks just as well as Generic PHY devices. I've added as
>>>>> maintainers those from "ETHERNET PHY LIBRARY", "NETWORKING DRIVERS" and
>>>>> "GENERIC PHY FRAMEWORK".
>>>>
>>>> I dunno.. ain't no such thing as "joint custody" maintainership.
>>>> We have to pick one tree. Given the set of Ms here, I suspect 
>>>> the best course of action may be to bubble this up to its own tree.
>>>> Ask Konstantin for a tree in k.org, then you can "co-post" the patches
>>>> for review + PR link in the cover letter (e.g. how Tony from Intel
>>>> submits their patches). This way not networking and PHY can pull
>>>> the shared changes with stable commit IDs.
>>>
>>> How much is the volume of the changes that we are talking about, we can
>>> always ack and pull into each other trees..?
>>
>> That's just one C file, isn't it? Having dedicated tree for one file
>> feels like huge overhead.
> 
> I have to admit, no matter how we define what pertains to this presumed
> new git tree, the fact is that the volume of patches will be quite low.
> 
> Since the API provider always sits in drivers/phy/ in every case that I
> can think about, technically all situations can be resolved by linux-phy
> providing these stable PR branches to netdev. In turn, to netdev it
> makes no difference whether the branches are coming from linux-phy or a
> third git tree. Whereas to linux-phy, things would even maybe a bit
> simpler, due to already having the patches vs needing to pull them from
> the 3rd tree.
> 
> From my perspective, if I'm perfectly honest, the idea was attractive
> because of the phenomenal difference in turnaround times between netdev
> and linux-phy review&merge processes (very fast in netdev, very slow and
> patchy in linux-phy). If there's a set like this, where all API consumers
> are in netdev for now but the API itself is in linux-phy, you'd have to
> introduce 1000 NOP cycles just to wait for the PR branch.
> 
> In that sense, having more people into the mix would help just because
> there's more people (i.e. fewer points of failure), even though overall
> there's more overhead.
> 
> IDK, these are my 2 cents, I can resubmit this set in 2 weeks with the
> maintainership of the PHY common properties exclusive to linux-phy.


Jakub supported the idea, so I also do not oppose, and if that helps you
folks, then go ahead.

Best regards,
Krzysztof


From pavan.kondeti at oss.qualcomm.com  Thu Dec  4 08:55:43 2025
From: pavan.kondeti at oss.qualcomm.com (Pavan Kondeti)
Date: Thu, 4 Dec 2025 22:25:43 +0530
Subject: Alternative to arm64.nopauth cmdline for disabling Pointer
 Authentication
In-Reply-To: <aTF42v5dpTuCe7r3@J2N7QTR9R3>
References: <3fcf6614-ee83-4a06-9024-83573b2e642e@quicinc.com>
 <86ecpappzi.wl-maz@kernel.org>
 <adc22b19-7dcc-4c38-9319-d979f1e3886a@quicinc.com>
 <aTF42v5dpTuCe7r3@J2N7QTR9R3>
Message-ID: <33ab9112-39c5-4dba-9e56-089b7e8a7243@quicinc.com>

On Thu, Dec 04, 2025 at 12:04:42PM +0000, Mark Rutland wrote:
> Hi Pavan, Marc,
> 
> On Thu, Dec 04, 2025 at 04:06:12PM +0530, Pavan Kondeti wrote:
> > On Thu, Dec 04, 2025 at 09:15:29AM +0000, Marc Zyngier wrote:
> > > On Thu, 04 Dec 2025 04:07:15 +0000,
> > > Pavan Kondeti <pavan.kondeti at oss.qualcomm.com> wrote:
> > > > Hi
> > > > 
> > > > The pointer authentication feature (PAuth) is only supported on
> > > > 0-3 CPUs but it is not supported on 4-7 CPUS on QCS8300.
> 
> > > On what grounds? Hardware incompatibility? I seriously doubt it,
> > > since nobody glues pre-8.3 CPUs to anything more modern.
> 
> Marc, it seems like that's exactly that's happened here. :/
> 
> > I see that Linux runs at EL2 and AA64ISAR1 register values on CPU#0
> > (A78) indicates that PAuth is supported but not for CPU#4 (A55). I am
> > told, there are no other controls outside EL2 (trap) to manipulate
> > this feature. So, I am assuming that this is indeed reflecting the HW.
> 
> Cortex-A78 doesn't have pointer authentication, but Cortex-A78C does, so
> maybe you actually have Cortex-A78C?
> 
> What are the MIDRs on this SoC? e.g. the output of:
> 
>   cat /sys/devices/system/cpu/cpu*/regs/identification/midr_el1 | sort | uniq
> 
> If this SoC has both Cortex-A78C and Cortex-A55, that's a rather
> unfortunate combination that should have been caught at the SoC design
> phase, as Marc alluded to.

Yes. The MIDR register indicate the same. A78C + A55

root at v8a-arm64:~# cat /sys/devices/system/cpu/cpu*/regs/identification/midr_el1
0x00000000410fd4b2
0x00000000410fd4b2
0x00000000410fd4b2
0x00000000410fd4b2
0x00000000412fd050
0x00000000412fd050
0x00000000412fd050
0x00000000412fd050

> 
> [...]
> 
> > > > This patch [2] from Catalin adds a devicetree property under memory {}
> > > > to disable MTE.
> 
> Catalin's patch was a bit different. It described whether the memory
> range supported tags (and was actually a property of the memory). That
> patch didn't make it into mainline AFAICT.
> 
> [...]
> 
> > I understand that this does not fall under errata but is
> > there a possiblity to introduce an Errata targeting CPU#0 MIDR and
> > disabling the Pointer authentication? I understand that if there is
> > another Qualcomm SoC that exists with all CPUs supporting pointer
> > authentication with same MIDR, we may be disabling the feature but this
> > is something I can check internally.
> 
> I strongly suspect we cannot use the MIDR for this. Per:
> 
>   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=53a52a0ec7680287b170b36488203b5822e6da2d
> 
> ... Qualcomm's Kryo {Prime,Gold,Silver} parts seem to identify
> themselves as Arm ltd implementations, and those will appear in other
> non-Qualcomm SoCs.

Thank you for explaining this. Agree that we can't use MIDR based
workaround here. 
> 
> Without know *exactly* which MIDRs you have on this part, we cannot say.
> 
> Regardless, I strongly suspect that we have to live with the command
> line option for these parts.
> 

Got it. 

Thanks,
Pavan


From linux at fw-web.de  Thu Dec  4 08:58:42 2025
From: linux at fw-web.de (Frank Wunderlich)
Date: Thu,  4 Dec 2025 17:58:42 +0100
Subject: [RFC v2 0/3] Add RSS and LRO support
Message-ID: <20251204165849.8214-1-linux@fw-web.de>

From: Frank Wunderlich <frank-w at public-files.de>

This series is currently only for discussion to get the upported SDK driver
changes in a good shape.
To use it some other parts are still missing like USXGMII PCS support on
mt7988.

patches are upported from mtk SDK:
- https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/refs/heads/master/master/files/target/linux/mediatek/patches-6.12/999-eth-08-mtk_eth_soc-add-register-definitions-for-rss-lro-reg.patch
- https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/refs/heads/master/master/files/target/linux/mediatek/patches-6.12/999-eth-09-mtk_eth_soc-add-rss-support.patch
- https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/refs/heads/master/master/files/target/linux/mediatek/patches-6.12/999-eth-10-mtk_eth_soc-add-hw-lro-support.patch

RSS / LRO

HW-acceleration for ending traffic. For routed traffic PPE is needed and
hw offloading in nftables.
Bridged traffic may need additional changes (openwrt use bridger utility).

RSS (Receive Side Scaling)

using 4 additional IRQ for spreading load

cat /proc/interrupts | grep ethernet

echo 1 > /proc/irq/105/smp_affinity
echo 2 > /proc/irq/106/smp_affinity
echo 4 > /proc/irq/107/smp_affinity
echo 8 > /proc/irq/108/smp_affinity

moving tx frame-engine irq to different cpu (here 3rd)
echo 4 > /proc/irq/103/smp_affinity

disable RPS (Receive Packet Steering) for all macs:

echo 0 > /sys/devices/platform/soc/15100000.ethernet/net/eth0/queues/rx-0/rps_cpus

pay attention on iperf-version (iperf 3.17 is ok, 3.12 is not)

traffic must be created using multiple streams so that it can be splitted, so use
multithreaded iperf3

on R4: bin/iperf3 -s
on the other side: iperf3 -c 192.168.1.1 -i 1 -P 4

you should reach ~9.3 GBit/s

and see spreading load over CPU cores

root at bpi-r4-phy-8G:~# cat /proc/interrupts | grep eth
103: 20 198366 0 0 GICv3 229 Level 15100000.ethernet
105: 3611 0 0 0 GICv3 221 Level 15100000.ethernet, 15100000.ethernet
106: 2 6842 0 0 GICv3 222 Level 15100000.ethernet, 15100000.ethernet
107: 4 0 27643 0 GICv3 223 Level 15100000.ethernet, 15100000.ethernet
108: 3 0 0 27925 GICv3 224 Level 15100000.ethernet, 15100000.ethernet

using the iperf3 from debian bookworm (3.12) results in only 6.7GBit/s, so
newer version is needed (not tested yet in trixie).

LRO(Large Receive Offload)

Add HW LRO RX rule:

ethtool -N [interface] flow-type tcp4 dst-ip [IP] action 0 loc [0/1]

Delete HW LRO RX rule:

ethtool -N [interface] delete [0/1]

Enable/Disable HW LRO rule:

ethtool -K [interface] lro [on | off]

Show the current offload features:

ethtool -k [interface]

example:

ethtool -N eth2 flow-type tcp4 dst-ip 192.168.1.1 action 0 loc 0
ethtool -K eth2 lro on ethtool -k eth2

using iperf(2) instead of iperf3 to reach full traffic!

verify with propritary debugfs (not part of this series)

Enable HW LRO rings
echo 4 1 > /proc/mtketh/hw_lro_auto_tlb
Enable HW LRO statistics
echo 5 1 > /proc/mtketh/hw_lro_auto_tlb

cat /proc/mtketh/hw_lro_stats

changes:
  v2:
    - drop wrong change (MTK_CDMP_IG_CTRL is only netsys v1)
    - Fix immutable string IRQ setup (thx to Emilia Schotte)
    - drop links to 6.6 patches/commits in sdk in comments


Mason Chang (3):
  net: ethernet: mtk_eth_soc: Add register definitions for RSS and LRO
  net: ethernet: mtk_eth_soc: Add RSS support
  net: ethernet: mtk_eth_soc: Add LRO support

 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 762 ++++++++++++++++----
 drivers/net/ethernet/mediatek/mtk_eth_soc.h | 171 +++--
 2 files changed, 753 insertions(+), 180 deletions(-)

-- 
2.43.0



From linux at fw-web.de  Thu Dec  4 08:58:43 2025
From: linux at fw-web.de (Frank Wunderlich)
Date: Thu,  4 Dec 2025 17:58:43 +0100
Subject: [RFC v2 1/3] net: ethernet: mtk_eth_soc: Add register definitions for RSS and LRO
In-Reply-To: <20251204165849.8214-1-linux@fw-web.de>
References: <20251204165849.8214-1-linux@fw-web.de>
Message-ID: <20251204165849.8214-2-linux@fw-web.de>

From: Mason Chang <mason-cw.chang at mediatek.com>

Add definitions for Receive Side Scaling and Large Receive Offload support.

Signed-off-by: Mason Chang <mason-cw.chang at mediatek.com>
Signed-off-by: Frank Wunderlich <frank-w at public-files.de>
---
 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 23 +++++++++++++++
 drivers/net/ethernet/mediatek/mtk_eth_soc.h | 32 +++++++++++++++------
 2 files changed, 46 insertions(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index e68997a29191..243ff16fd15e 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -50,13 +50,18 @@ static const struct mtk_reg_map mtk_reg_map = {
 		.rx_ptr		= 0x0900,
 		.rx_cnt_cfg	= 0x0904,
 		.pcrx_ptr	= 0x0908,
+		.lro_ctrl_dw0   = 0x0980,
 		.glo_cfg	= 0x0a04,
 		.rst_idx	= 0x0a08,
 		.delay_irq	= 0x0a0c,
 		.irq_status	= 0x0a20,
 		.irq_mask	= 0x0a28,
 		.adma_rx_dbg0	= 0x0a38,
+		.lro_alt_score_delta	= 0x0a4c,
 		.int_grp	= 0x0a50,
+		.lro_rx1_dly_int	= 0x0a70,
+		.lro_ring_dip_dw0	= 0x0b04,
+		.lro_ring_ctrl_dw1	= 0x0b28,
 	},
 	.qdma = {
 		.qtx_cfg	= 0x1800,
@@ -113,6 +118,7 @@ static const struct mtk_reg_map mt7986_reg_map = {
 	.tx_irq_mask		= 0x461c,
 	.tx_irq_status		= 0x4618,
 	.pdma = {
+		.rss_glo_cfg    = 0x2800,
 		.rx_ptr		= 0x4100,
 		.rx_cnt_cfg	= 0x4104,
 		.pcrx_ptr	= 0x4108,
@@ -123,6 +129,12 @@ static const struct mtk_reg_map mt7986_reg_map = {
 		.irq_mask	= 0x4228,
 		.adma_rx_dbg0	= 0x4238,
 		.int_grp	= 0x4250,
+		.int_grp3	= 0x422c,
+		.lro_ctrl_dw0	= 0x4180,
+		.lro_alt_score_delta	= 0x424c,
+		.lro_rx1_dly_int	= 0x4270,
+		.lro_ring_dip_dw0	= 0x4304,
+		.lro_ring_ctrl_dw1	= 0x4328,
 	},
 	.qdma = {
 		.qtx_cfg	= 0x4400,
@@ -170,10 +182,21 @@ static const struct mtk_reg_map mt7988_reg_map = {
 		.glo_cfg	= 0x6a04,
 		.rst_idx	= 0x6a08,
 		.delay_irq	= 0x6a0c,
+		.rx_cfg		= 0x6a10,
 		.irq_status	= 0x6a20,
 		.irq_mask	= 0x6a28,
 		.adma_rx_dbg0	= 0x6a38,
 		.int_grp	= 0x6a50,
+		.int_grp3	= 0x6a58,
+		.tx_delay_irq	= 0x6ab0,
+		.rx_delay_irq	= 0x6ac0,
+		.lro_ctrl_dw0	= 0x6c08,
+		.lro_alt_score_delta	= 0x6c1c,
+		.lro_ring_dip_dw0	= 0x6c14,
+		.lro_ring_ctrl_dw1	= 0x6c38,
+		.lro_alt_dbg	= 0x6c40,
+		.lro_alt_dbg_data	= 0x6c44,
+		.rss_glo_cfg	= 0x7000,
 	},
 	.qdma = {
 		.qtx_cfg	= 0x4400,
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index 0168e2fbc619..334625814b97 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -1143,16 +1143,30 @@ struct mtk_reg_map {
 	u32	tx_irq_mask;
 	u32	tx_irq_status;
 	struct {
-		u32	rx_ptr;		/* rx base pointer */
-		u32	rx_cnt_cfg;	/* rx max count configuration */
-		u32	pcrx_ptr;	/* rx cpu pointer */
-		u32	glo_cfg;	/* global configuration */
-		u32	rst_idx;	/* reset index */
-		u32	delay_irq;	/* delay interrupt */
-		u32	irq_status;	/* interrupt status */
-		u32	irq_mask;	/* interrupt mask */
+		u32	rx_ptr;			/* rx base pointer */
+		u32	rx_cnt_cfg;		/* rx max count configuration */
+		u32	pcrx_ptr;		/* rx cpu pointer */
+		u32	pdrx_ptr;		/* rx dma pointer */
+		u32	glo_cfg;		/* global configuration */
+		u32	rst_idx;		/* reset index */
+		u32	rx_cfg;			/* rx dma configuration */
+		u32	delay_irq;		/* delay interrupt */
+		u32	irq_status;		/* interrupt status */
+		u32	irq_mask;		/* interrupt mask */
 		u32	adma_rx_dbg0;
-		u32	int_grp;
+		u32	int_grp;		/* interrupt group1 */
+		u32	int_grp3;		/* interrupt group3 */
+		u32	tx_delay_irq;		/* tx delay interrupt */
+		u32	rx_delay_irq;		/* rx delay interrupt */
+		u32	lro_ctrl_dw0;		/* lro ctrl dword0 */
+		u32	lro_alt_score_delta;	/* lro auto-learn score delta */
+		u32	lro_rx1_dly_int;	/* lro rx ring1 delay interrupt */
+		u32	lro_ring_dip_dw0;	/* lro ring dip dword0 */
+		u32	lro_ring_ctrl_dw1;	/* lro ring ctrl dword1 */
+		u32	lro_alt_dbg;		/* lro auto-learn debug */
+		u32	lro_alt_dbg_data;	/* lro auto-learn debug data */
+		u32	rss_glo_cfg;		/* rss global configuration */
+
 	} pdma;
 	struct {
 		u32	qtx_cfg;	/* tx queue configuration */
-- 
2.43.0



From linux at fw-web.de  Thu Dec  4 08:58:45 2025
From: linux at fw-web.de (Frank Wunderlich)
Date: Thu,  4 Dec 2025 17:58:45 +0100
Subject: [RFC v2 3/3] net: ethernet: mtk_eth_soc: Add LRO support
In-Reply-To: <20251204165849.8214-1-linux@fw-web.de>
References: <20251204165849.8214-1-linux@fw-web.de>
Message-ID: <20251204165849.8214-4-linux@fw-web.de>

From: Mason Chang <mason-cw.chang at mediatek.com>

Add Large Receive Offload support to mediatek ethernet driver and
activate it for MT7988.

Signed-off-by: Mason Chang <mason-cw.chang at mediatek.com>
Signed-off-by: Frank Wunderlich <frank-w at public-files.de>
---
v2:
- drop link to commit for 6.6 patch
---
 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 213 ++++++++++++++++++--
 drivers/net/ethernet/mediatek/mtk_eth_soc.h |  48 +++--
 2 files changed, 221 insertions(+), 40 deletions(-)

diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 56fc9e4f23c6..e7206a0ec5cd 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -2785,7 +2785,7 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag)
 	if (!ring->data)
 		return -ENOMEM;
 
-	if (mtk_page_pool_enabled(eth)) {
+	if (mtk_page_pool_enabled(eth) && rcu_access_pointer(eth->prog))  {
 		struct page_pool *pp;
 
 		pp = mtk_create_page_pool(eth, &ring->xdp_q, ring_no,
@@ -2932,7 +2932,8 @@ static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring, bool in_
 static int mtk_hwlro_rx_init(struct mtk_eth *eth)
 {
 	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
-	int i;
+	const struct mtk_soc_data *soc = eth->soc;
+	int i, val;
 	u32 ring_ctrl_dw1 = 0, ring_ctrl_dw2 = 0, ring_ctrl_dw3 = 0;
 	u32 lro_ctrl_dw0 = 0, lro_ctrl_dw3 = 0;
 
@@ -2953,7 +2954,7 @@ static int mtk_hwlro_rx_init(struct mtk_eth *eth)
 	ring_ctrl_dw2 |= MTK_RING_MAX_AGG_CNT_L;
 	ring_ctrl_dw3 |= MTK_RING_MAX_AGG_CNT_H;
 
-	for (i = 1; i < MTK_MAX_RX_RING_NUM; i++) {
+	for (i = 1; i <= MTK_HW_LRO_RING_NUM; i++) {
 		mtk_w32(eth, ring_ctrl_dw1, MTK_LRO_CTRL_DW1_CFG(i));
 		mtk_w32(eth, ring_ctrl_dw2, MTK_LRO_CTRL_DW2_CFG(i));
 		mtk_w32(eth, ring_ctrl_dw3, MTK_LRO_CTRL_DW3_CFG(i));
@@ -2975,8 +2976,22 @@ static int mtk_hwlro_rx_init(struct mtk_eth *eth)
 	mtk_w32(eth, (MTK_HW_LRO_TIMER_UNIT << 16) | MTK_HW_LRO_REFRESH_TIME,
 		MTK_PDMA_LRO_ALT_REFRESH_TIMER);
 
-	/* set HW LRO mode & the max aggregation count for rx packets */
-	lro_ctrl_dw3 |= MTK_ADMA_MODE | (MTK_HW_LRO_MAX_AGG_CNT & 0xff);
+	if (mtk_is_netsys_v3_or_greater(eth)) {
+		val = mtk_r32(eth, reg_map->pdma.rx_cfg);
+		mtk_w32(eth, val | ((MTK_PDMA_LRO_SDL + MTK_MAX_RX_LENGTH) <<
+			MTK_RX_CFG_SDL_OFFSET), reg_map->pdma.rx_cfg);
+
+		lro_ctrl_dw0 |= MTK_PDMA_LRO_SDL << MTK_CTRL_DW0_SDL_OFFSET;
+
+		/* enable cpu reason black list */
+		lro_ctrl_dw0 |= MTK_LRO_CRSN_BNW;
+
+		/* no use PPE cpu reason */
+		mtk_w32(eth, 0xffffffff, MTK_PDMA_LRO_CTRL_DW1);
+	} else {
+		/* set HW LRO mode & the max aggregation count for rx packets */
+		lro_ctrl_dw3 |= MTK_ADMA_MODE | (MTK_HW_LRO_MAX_AGG_CNT & 0xff);
+	}
 
 	/* the minimal remaining room of SDL0 in RXD for lro aggregation */
 	lro_ctrl_dw3 |= MTK_LRO_MIN_RXD_SDL;
@@ -2987,6 +3002,16 @@ static int mtk_hwlro_rx_init(struct mtk_eth *eth)
 	mtk_w32(eth, lro_ctrl_dw3, MTK_PDMA_LRO_CTRL_DW3);
 	mtk_w32(eth, lro_ctrl_dw0, MTK_PDMA_LRO_CTRL_DW0);
 
+	if (mtk_is_netsys_v2_or_greater(eth)) {
+		i = (soc->rx.desc_size == sizeof(struct mtk_rx_dma_v2)) ? 1 : 0;
+		mtk_m32(eth, MTK_RX_DONE_INT(MTK_HW_LRO_RING(i)),
+			MTK_RX_DONE_INT(MTK_HW_LRO_RING(i)), reg_map->pdma.int_grp);
+		mtk_m32(eth, MTK_RX_DONE_INT(MTK_HW_LRO_RING(i + 1)),
+			MTK_RX_DONE_INT(MTK_HW_LRO_RING(i + 1)), reg_map->pdma.int_grp + 0x4);
+		mtk_m32(eth, MTK_RX_DONE_INT(MTK_HW_LRO_RING(i + 2)),
+			MTK_RX_DONE_INT(MTK_HW_LRO_RING(i + 2)), reg_map->pdma.int_grp3);
+	}
+
 	return 0;
 }
 
@@ -3010,7 +3035,7 @@ static void mtk_hwlro_rx_uninit(struct mtk_eth *eth)
 	}
 
 	/* invalidate lro rings */
-	for (i = 1; i < MTK_MAX_RX_RING_NUM; i++)
+	for (i = 1; i <= MTK_HW_LRO_RING_NUM; i++)
 		mtk_w32(eth, 0, MTK_LRO_CTRL_DW2_CFG(i));
 
 	/* disable HW LRO */
@@ -3059,6 +3084,64 @@ static int mtk_hwlro_get_ip_cnt(struct mtk_mac *mac)
 	return cnt;
 }
 
+static int mtk_hwlro_add_ipaddr_idx(struct net_device *dev, u32 ip4dst)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
+	u32 reg_val;
+	int i;
+
+	/* check for duplicate IP address in the current DIP list */
+	for (i = 1; i <= MTK_HW_LRO_DIP_NUM; i++) {
+		reg_val = mtk_r32(eth, MTK_LRO_DIP_DW0_CFG(i));
+		if (reg_val == ip4dst)
+			break;
+	}
+
+	if (i < MTK_HW_LRO_DIP_NUM + 1) {
+		netdev_warn(dev, "Duplicate IP address at DIP(%d)!\n", i);
+		return -EEXIST;
+	}
+
+	/* find out available DIP index */
+	for (i = 1; i <= MTK_HW_LRO_DIP_NUM; i++) {
+		reg_val = mtk_r32(eth, MTK_LRO_DIP_DW0_CFG(i));
+		if (reg_val == 0UL)
+			break;
+	}
+
+	if (i >= MTK_HW_LRO_DIP_NUM + 1) {
+		netdev_warn(dev, "DIP index is currently out of resource!\n");
+		return -EBUSY;
+	}
+
+	return i;
+}
+
+static int mtk_hwlro_get_ipaddr_idx(struct net_device *dev, u32 ip4dst)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
+	u32 reg_val;
+	int i;
+
+	/* find out DIP index that matches the given IP address */
+	for (i = 1; i <= MTK_HW_LRO_DIP_NUM; i++) {
+		reg_val = mtk_r32(eth, MTK_LRO_DIP_DW0_CFG(i));
+		if (reg_val == ip4dst)
+			break;
+	}
+
+	if (i >= MTK_HW_LRO_DIP_NUM + 1) {
+		netdev_warn(dev, "DIP address is not exist!\n");
+		return -ENOENT;
+	}
+
+	return i;
+}
+
 static int mtk_hwlro_add_ipaddr(struct net_device *dev,
 				struct ethtool_rxnfc *cmd)
 {
@@ -3067,15 +3150,19 @@ static int mtk_hwlro_add_ipaddr(struct net_device *dev,
 	struct mtk_mac *mac = netdev_priv(dev);
 	struct mtk_eth *eth = mac->hw;
 	int hwlro_idx;
+	u32 ip4dst;
 
 	if ((fsp->flow_type != TCP_V4_FLOW) ||
 	    (!fsp->h_u.tcp_ip4_spec.ip4dst) ||
 	    (fsp->location > 1))
 		return -EINVAL;
 
-	mac->hwlro_ip[fsp->location] = htonl(fsp->h_u.tcp_ip4_spec.ip4dst);
-	hwlro_idx = (mac->id * MTK_MAX_LRO_IP_CNT) + fsp->location;
+	ip4dst = htonl(fsp->h_u.tcp_ip4_spec.ip4dst);
+	hwlro_idx = mtk_hwlro_add_ipaddr_idx(dev, ip4dst);
+	if (hwlro_idx < 0)
+		return hwlro_idx;
 
+	mac->hwlro_ip[fsp->location] = ip4dst;
 	mac->hwlro_ip_cnt = mtk_hwlro_get_ip_cnt(mac);
 
 	mtk_hwlro_val_ipaddr(eth, hwlro_idx, mac->hwlro_ip[fsp->location]);
@@ -3091,13 +3178,17 @@ static int mtk_hwlro_del_ipaddr(struct net_device *dev,
 	struct mtk_mac *mac = netdev_priv(dev);
 	struct mtk_eth *eth = mac->hw;
 	int hwlro_idx;
+	u32 ip4dst;
 
 	if (fsp->location > 1)
 		return -EINVAL;
 
-	mac->hwlro_ip[fsp->location] = 0;
-	hwlro_idx = (mac->id * MTK_MAX_LRO_IP_CNT) + fsp->location;
+	ip4dst = mac->hwlro_ip[fsp->location];
+	hwlro_idx = mtk_hwlro_get_ipaddr_idx(dev, ip4dst);
+	if (hwlro_idx < 0)
+		return hwlro_idx;
 
+	mac->hwlro_ip[fsp->location] = 0;
 	mac->hwlro_ip_cnt = mtk_hwlro_get_ip_cnt(mac);
 
 	mtk_hwlro_inval_ipaddr(eth, hwlro_idx);
@@ -3105,6 +3196,24 @@ static int mtk_hwlro_del_ipaddr(struct net_device *dev,
 	return 0;
 }
 
+static void mtk_hwlro_netdev_enable(struct net_device *dev)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	int i, hwlro_idx;
+
+	for (i = 0; i < MTK_MAX_LRO_IP_CNT; i++) {
+		if (mac->hwlro_ip[i] == 0)
+			continue;
+
+		hwlro_idx = mtk_hwlro_get_ipaddr_idx(dev, mac->hwlro_ip[i]);
+		if (hwlro_idx < 0)
+			continue;
+
+		mtk_hwlro_val_ipaddr(eth, hwlro_idx, mac->hwlro_ip[i]);
+	}
+}
+
 static void mtk_hwlro_netdev_disable(struct net_device *dev)
 {
 	struct mtk_mac *mac = netdev_priv(dev);
@@ -3112,8 +3221,14 @@ static void mtk_hwlro_netdev_disable(struct net_device *dev)
 	int i, hwlro_idx;
 
 	for (i = 0; i < MTK_MAX_LRO_IP_CNT; i++) {
+		if (mac->hwlro_ip[i] == 0)
+			continue;
+
+		hwlro_idx = mtk_hwlro_get_ipaddr_idx(dev, mac->hwlro_ip[i]);
+		if (hwlro_idx < 0)
+			continue;
+
 		mac->hwlro_ip[i] = 0;
-		hwlro_idx = (mac->id * MTK_MAX_LRO_IP_CNT) + i;
 
 		mtk_hwlro_inval_ipaddr(eth, hwlro_idx);
 	}
@@ -3299,6 +3414,8 @@ static int mtk_set_features(struct net_device *dev, netdev_features_t features)
 
 	if ((diff & NETIF_F_LRO) && !(features & NETIF_F_LRO))
 		mtk_hwlro_netdev_disable(dev);
+	else if ((diff & NETIF_F_LRO) && (features & NETIF_F_LRO))
+		mtk_hwlro_netdev_enable(dev);
 
 	return 0;
 }
@@ -3356,8 +3473,8 @@ static int mtk_dma_init(struct mtk_eth *eth)
 		return err;
 
 	if (eth->hwlro) {
-		for (i = 1; i < MTK_MAX_RX_RING_NUM; i++) {
-			err = mtk_rx_alloc(eth, i, MTK_RX_FLAGS_HWLRO);
+		for (i = 0; i < MTK_HW_LRO_RING_NUM; i++) {
+			err = mtk_rx_alloc(eth, MTK_HW_LRO_RING(i), MTK_RX_FLAGS_HWLRO);
 			if (err)
 				return err;
 		}
@@ -3419,8 +3536,8 @@ static void mtk_dma_free(struct mtk_eth *eth)
 
 	if (eth->hwlro) {
 		mtk_hwlro_rx_uninit(eth);
-		for (i = 1; i < MTK_MAX_RX_RING_NUM; i++)
-			mtk_rx_clean(eth, &eth->rx_ring[i], false);
+		for (i = 0; i < MTK_HW_LRO_RING_NUM; i++)
+			mtk_rx_clean(eth, &eth->rx_ring[MTK_HW_LRO_RING(i)], false);
 	}
 
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
@@ -3615,16 +3732,21 @@ static int mtk_start_dma(struct mtk_eth *eth)
 			val |= MTK_RX_BT_32DWORDS;
 		mtk_w32(eth, val, reg_map->qdma.glo_cfg);
 
-		mtk_w32(eth,
-			MTK_RX_DMA_EN | rx_2b_offset |
-			MTK_RX_BT_32DWORDS | MTK_MULTI_EN,
-			reg_map->pdma.glo_cfg);
+		val = mtk_r32(eth, reg_map->pdma.glo_cfg);
+		val |= MTK_RX_DMA_EN | rx_2b_offset |
+		       MTK_RX_BT_32DWORDS | MTK_MULTI_EN;
+		mtk_w32(eth, val, reg_map->pdma.glo_cfg);
 	} else {
 		mtk_w32(eth, MTK_TX_WB_DDONE | MTK_TX_DMA_EN | MTK_RX_DMA_EN |
 			MTK_MULTI_EN | MTK_PDMA_SIZE_8DWORDS,
 			reg_map->pdma.glo_cfg);
 	}
 
+	if (eth->hwlro && mtk_is_netsys_v3_or_greater(eth)) {
+		val = mtk_r32(eth, reg_map->pdma.glo_cfg);
+		mtk_w32(eth, val | MTK_RX_DMA_LRO_EN, reg_map->pdma.glo_cfg);
+	}
+
 	return 0;
 }
 
@@ -3768,6 +3890,13 @@ static int mtk_open(struct net_device *dev)
 			}
 		}
 
+		if (eth->hwlro) {
+			for (i = 0; i < MTK_HW_LRO_RING_NUM; i++) {
+				napi_enable(&eth->rx_napi[MTK_HW_LRO_RING(i)].napi);
+				mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(MTK_HW_LRO_RING(i)));
+			}
+		}
+
 		refcount_set(&eth->dma_refcnt, 1);
 	} else {
 		refcount_inc(&eth->dma_refcnt);
@@ -3863,6 +3992,14 @@ static int mtk_stop(struct net_device *dev)
 		}
 	}
 
+	if (eth->hwlro) {
+		for (i = 0; i < MTK_HW_LRO_RING_NUM; i++) {
+			mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(MTK_HW_LRO_RING(i)));
+			napi_synchronize(&eth->rx_napi[MTK_HW_LRO_RING(i)].napi);
+			napi_disable(&eth->rx_napi[MTK_HW_LRO_RING(i)].napi);
+		}
+	}
+
 	cancel_work_sync(&eth->rx_dim.work);
 	cancel_work_sync(&eth->tx_dim.work);
 
@@ -4262,6 +4399,14 @@ static int mtk_napi_init(struct mtk_eth *eth)
 		}
 	}
 
+	if (eth->hwlro) {
+		for (i = 0; i < MTK_HW_LRO_RING_NUM; i++) {
+			rx_napi = &eth->rx_napi[MTK_HW_LRO_RING(i)];
+			rx_napi->eth = eth;
+			rx_napi->rx_ring = &eth->rx_ring[MTK_HW_LRO_RING(i)];
+		}
+	}
+
 	return 0;
 }
 
@@ -4825,7 +4970,7 @@ static int mtk_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
 	switch (cmd->cmd) {
 	case ETHTOOL_GRXRINGS:
 		if (dev->hw_features & NETIF_F_LRO) {
-			cmd->data = MTK_MAX_RX_RING_NUM;
+			cmd->data = MTK_HW_LRO_RING_NUM;
 			ret = 0;
 		} else if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
 			cmd->data = MTK_RX_RSS_NUM;
@@ -5531,6 +5676,21 @@ static int mtk_probe(struct platform_device *pdev)
 						goto err_free_dev;
 				}
 			}
+
+			if (eth->hwlro) {
+				for (i = 0; i < MTK_HW_LRO_RING_NUM; i++) {
+					irqname = devm_kasprintf(eth->dev, GFP_KERNEL,
+								 "%s LRO RX %d",
+								 dev_name(eth->dev), i);
+					err = devm_request_irq(eth->dev,
+							       eth->irq_pdma[MTK_HW_LRO_IRQ(i)],
+							       mtk_handle_irq_rx, IRQF_SHARED,
+							       irqname,
+							       &eth->rx_napi[MTK_HW_LRO_RING(i)]);
+					if (err)
+						goto err_free_dev;
+				}
+			}
 		} else {
 			irqname = devm_kasprintf(eth->dev, GFP_KERNEL, "%s RX",
 						 dev_name(eth->dev));
@@ -5602,6 +5762,13 @@ static int mtk_probe(struct platform_device *pdev)
 				       mtk_napi_rx);
 	}
 
+	if (eth->hwlro) {
+		for (i = 0; i < MTK_HW_LRO_RING_NUM; i++) {
+			netif_napi_add(eth->dummy_dev, &eth->rx_napi[MTK_HW_LRO_RING(i)].napi,
+				       mtk_napi_rx);
+		}
+	}
+
 	platform_set_drvdata(pdev, eth);
 	schedule_delayed_work(&eth->reset.monitor_work,
 			      MTK_DMA_MONITOR_TIMEOUT);
@@ -5650,6 +5817,12 @@ static void mtk_remove(struct platform_device *pdev)
 		for (i = 1; i < MTK_RX_RSS_NUM; i++)
 			netif_napi_del(&eth->rx_napi[MTK_RSS_RING(i)].napi);
 	}
+
+	if (eth->hwlro) {
+		for (i = 0; i < MTK_HW_LRO_RING_NUM; i++)
+			netif_napi_del(&eth->rx_napi[MTK_HW_LRO_RING(i)].napi);
+	}
+
 	mtk_cleanup(eth);
 	free_netdev(eth->dummy_dev);
 	mtk_mdio_cleanup(eth);
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index db72337e9fd4..a8f54ea17f1c 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -35,7 +35,7 @@
 #define MTK_DMA_SIZE(x)		(SZ_##x)
 #define MTK_FQ_DMA_HEAD		32
 #define MTK_FQ_DMA_LENGTH	2048
-#define MTK_RX_ETH_HLEN		(ETH_HLEN + ETH_FCS_LEN)
+#define MTK_RX_ETH_HLEN		(VLAN_ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN)
 #define MTK_RX_HLEN		(NET_SKB_PAD + MTK_RX_ETH_HLEN + NET_IP_ALIGN)
 #define MTK_DMA_DUMMY_DESC	0xffffffff
 #define MTK_DEFAULT_MSG_ENABLE	(NETIF_MSG_DRV | \
@@ -63,10 +63,13 @@
 
 #define MTK_QRX_OFFSET		0x10
 
-#define MTK_MAX_RX_RING_NUM	4
-#define MTK_HW_LRO_DMA_SIZE	8
+#define MTK_MAX_RX_RING_NUM	(8)
+#define MTK_HW_LRO_DMA_SIZE	(mtk_is_netsys_v3_or_greater(eth) ? 64 : 8)
+#define IS_HW_LRO_RING(ring_no)	(mtk_is_netsys_v3_or_greater(eth) ?		\
+				 (((ring_no) > 3) && ((ring_no) < 8)) :		\
+				 (((ring_no) > 0) && ((ring_no) < 4)))
 
-#define	MTK_MAX_LRO_RX_LENGTH		(4096 * 3)
+#define	MTK_MAX_LRO_RX_LENGTH		(4096 * 3 + MTK_MAX_RX_LENGTH)
 #define	MTK_MAX_LRO_IP_CNT		2
 #define	MTK_HW_LRO_TIMER_UNIT		1	/* 20 us */
 #define	MTK_HW_LRO_REFRESH_TIME		50000	/* 1 sec. */
@@ -182,31 +185,35 @@
 #define MTK_CDMM_THRES		0x165c
 
 /* PDMA HW LRO Control Registers */
-#define MTK_PDMA_LRO_CTRL_DW0	0x980
+#define MTK_HW_LRO_DIP_NUM		(mtk_is_netsys_v3_or_greater(eth) ? 4 : 3)
 #define MTK_HW_LRO_RING_NUM		(mtk_is_netsys_v3_or_greater(eth) ? 4 : 3)
+#define MTK_HW_LRO_RING(x)		((x) + (mtk_is_netsys_v3_or_greater(eth) ? 4 : 1))
+#define MTK_HW_LRO_IRQ(x)		((x) + (mtk_is_netsys_v3_or_greater(eth) ? 0 : 1))
+#define MTK_LRO_CRSN_BNW		BIT((mtk_is_netsys_v3_or_greater(eth) ? 22 : 6))
 #define MTK_LRO_EN			BIT(0)
 #define MTK_NON_LRO_MULTI_EN		BIT(2)
 #define MTK_LRO_DLY_INT_EN		BIT(5)
-#define MTK_L3_CKS_UPD_EN		BIT(7)
-#define MTK_L3_CKS_UPD_EN_V2		BIT(19)
+#define MTK_L3_CKS_UPD_EN		BIT(mtk_is_netsys_v3_or_greater(eth) ? 19 : 7)
 #define MTK_LRO_ALT_PKT_CNT_MODE	BIT(21)
-#define MTK_LRO_RING_RELINQUISH_REQ	(0x7 << 26)
-#define MTK_LRO_RING_RELINQUISH_REQ_V2	(0xf << 24)
-#define MTK_LRO_RING_RELINQUISH_DONE	(0x7 << 29)
-#define MTK_LRO_RING_RELINQUISH_DONE_V2	(0xf << 28)
-
-#define MTK_PDMA_LRO_CTRL_DW1	0x984
-#define MTK_PDMA_LRO_CTRL_DW2	0x988
-#define MTK_PDMA_LRO_CTRL_DW3	0x98c
+#define MTK_LRO_RING_RELINQUISH_REQ	(mtk_is_netsys_v3_or_greater(eth) ? 0xf << 24 : 0x7 << 26)
+#define MTK_LRO_RING_RELINQUISH_DONE	(mtk_is_netsys_v3_or_greater(eth) ? 0xf << 28 : 0x7 << 29)
+
+#define MTK_PDMA_LRO_CTRL_DW0	(reg_map->pdma.lro_ctrl_dw0)
+#define MTK_PDMA_LRO_CTRL_DW1	(reg_map->pdma.lro_ctrl_dw0 + 0x04)
+#define MTK_PDMA_LRO_CTRL_DW2	(reg_map->pdma.lro_ctrl_dw0 + 0x08)
+#define MTK_PDMA_LRO_CTRL_DW3	(reg_map->pdma.lro_ctrl_dw0 + 0x0c)
 #define MTK_ADMA_MODE		BIT(15)
 #define MTK_LRO_MIN_RXD_SDL	(MTK_HW_LRO_SDL_REMAIN_ROOM << 16)
 
+#define MTK_CTRL_DW0_SDL_OFFSET	(3)
+#define MTK_CTRL_DW0_SDL_MASK	BITS(3, 18)
+
 #define MTK_RX_DMA_LRO_EN	BIT(8)
 #define MTK_MULTI_EN		BIT(10)
 #define MTK_PDMA_SIZE_8DWORDS	(1 << 4)
 
 /* PDMA RSS Control Registers */
-#define MTK_RX_NAPI_NUM			(4)
+#define MTK_RX_NAPI_NUM			(8)
 #define MTK_RX_RSS_NUM			(eth->soc->rss_num)
 #define MTK_RSS_RING(x)			(x)
 #define MTK_RSS_EN			BIT(0)
@@ -242,11 +249,10 @@
 #define MTK_PDMA_DELAY_PTIME_MASK	0xff
 
 /* PDMA HW LRO Alter Flow Delta Register */
-#define MTK_PDMA_LRO_ALT_SCORE_DELTA	0xa4c
+#define MTK_PDMA_LRO_ALT_SCORE_DELTA	(reg_map->pdma.lro_alt_score_delta)
 
 /* PDMA HW LRO IP Setting Registers */
-#define MTK_LRO_RX_RING0_DIP_DW0	0xb04
-#define MTK_LRO_DIP_DW0_CFG(x)		(MTK_LRO_RX_RING0_DIP_DW0 + (x * 0x40))
+#define MTK_LRO_DIP_DW0_CFG(x)		(reg_map->pdma.lro_ring_dip_dw0 + ((x) * 0x40))
 #define MTK_RING_MYIP_VLD		BIT(9)
 
 /* PDMA HW LRO Ring Control Registers */
@@ -1184,7 +1190,8 @@ enum mkt_eth_capabilities {
 
 #define MT7988_CAPS  (MTK_36BIT_DMA | MTK_GDM1_ESW | MTK_GMAC2_2P5GPHY | \
 		      MTK_MUX_GMAC2_TO_2P5GPHY | MTK_QDMA | MTK_RSTCTRL_PPE1 | \
-		      MTK_RSTCTRL_PPE2 | MTK_SRAM | MTK_PDMA_INT | MTK_RSS)
+		      MTK_RSTCTRL_PPE2 | MTK_SRAM | MTK_PDMA_INT | MTK_RSS | \
+		      MTK_HWLRO)
 
 struct mtk_tx_dma_desc_info {
 	dma_addr_t	addr;
@@ -1459,6 +1466,7 @@ struct mtk_mac {
 
 /* the struct describing the SoC. these are declared in the soc_xyz.c files */
 extern const struct of_device_id of_mtk_match[];
+extern u32 mtk_hwlro_stats_ebl;
 
 static inline bool mtk_is_netsys_v1(struct mtk_eth *eth)
 {
-- 
2.43.0



From linux at fw-web.de  Thu Dec  4 08:58:44 2025
From: linux at fw-web.de (Frank Wunderlich)
Date: Thu,  4 Dec 2025 17:58:44 +0100
Subject: [RFC v2 2/3] net: ethernet: mtk_eth_soc: Add RSS support
In-Reply-To: <20251204165849.8214-1-linux@fw-web.de>
References: <20251204165849.8214-1-linux@fw-web.de>
Message-ID: <20251204165849.8214-3-linux@fw-web.de>

From: Mason Chang <mason-cw.chang at mediatek.com>

Add support for Receive Side Scaling.

We can adjust SMP affinity with the following command:
echo [CPU bitmap num] > /proc/irq/[virtual IRQ ID]/smp_affinity,
with interrupts evenly assigned to 4 CPUs, we were able to measure
an RX throughput of 7.3Gbps using iperf3 on the MT7988. Further
optimizations will be carried out in the future.

The experimental command is as follows:
PC: iperf3 -c [IP] -P 10
DUT: iperf3 -s

The entire indirection table can be imagined as 128 buckets, we
can use the ethtool command to mark which RX ring we want to send
the packets in these buckets to.

Show RSS RX ring parameters in indirection table and RSS hash key:
ethtool -x [interface]
Change RSS RX rings weight under uniform distribution:
ethtool --set-rxfh-indir [interface] equal [ring num]
Change RSS RX rings weight under non-uniform distribution:
ethtool --set-rxfh-indir [interface] weight [ring0 weight]
[ring1 weight] [ring2 weight] [ring3 weight]

Signed-off-by: Mason Chang <mason-cw.chang at mediatek.com>
Signed-off-by: Frank Wunderlich <frank-w at public-files.de>
---
v2:
- drop wrong change (MTK_CDMP_IG_CTRL is only netsys v1)
- Fix immutable string IRQ setup (thx to Emilia Schotte)
- drop link to no more existent 6.6 patch in comment
---
 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 526 +++++++++++++++-----
 drivers/net/ethernet/mediatek/mtk_eth_soc.h |  95 +++-
 2 files changed, 488 insertions(+), 133 deletions(-)

diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 243ff16fd15e..56fc9e4f23c6 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -1275,6 +1275,7 @@ static bool mtk_rx_get_desc(struct mtk_eth *eth, struct mtk_rx_dma_v2 *rxd,
 	if (mtk_is_netsys_v3_or_greater(eth)) {
 		rxd->rxd5 = READ_ONCE(dma_rxd->rxd5);
 		rxd->rxd6 = READ_ONCE(dma_rxd->rxd6);
+		rxd->rxd7 = READ_ONCE(dma_rxd->rxd7);
 	}
 
 	return true;
@@ -1842,47 +1843,9 @@ static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	return NETDEV_TX_OK;
 }
 
-static struct mtk_rx_ring *mtk_get_rx_ring(struct mtk_eth *eth)
+static void mtk_update_rx_cpu_idx(struct mtk_eth *eth, struct mtk_rx_ring *ring)
 {
-	int i;
-	struct mtk_rx_ring *ring;
-	int idx;
-
-	if (!eth->hwlro)
-		return &eth->rx_ring[0];
-
-	for (i = 0; i < MTK_MAX_RX_RING_NUM; i++) {
-		struct mtk_rx_dma *rxd;
-
-		ring = &eth->rx_ring[i];
-		idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size);
-		rxd = ring->dma + idx * eth->soc->rx.desc_size;
-		if (rxd->rxd2 & RX_DMA_DONE) {
-			ring->calc_idx_update = true;
-			return ring;
-		}
-	}
-
-	return NULL;
-}
-
-static void mtk_update_rx_cpu_idx(struct mtk_eth *eth)
-{
-	struct mtk_rx_ring *ring;
-	int i;
-
-	if (!eth->hwlro) {
-		ring = &eth->rx_ring[0];
-		mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg);
-	} else {
-		for (i = 0; i < MTK_MAX_RX_RING_NUM; i++) {
-			ring = &eth->rx_ring[i];
-			if (ring->calc_idx_update) {
-				ring->calc_idx_update = false;
-				mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg);
-			}
-		}
-	}
+	mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg);
 }
 
 static bool mtk_page_pool_enabled(struct mtk_eth *eth)
@@ -1913,7 +1876,7 @@ static struct page_pool *mtk_create_page_pool(struct mtk_eth *eth,
 		return pp;
 
 	err = __xdp_rxq_info_reg(xdp_q, eth->dummy_dev, id,
-				 eth->rx_napi.napi_id, PAGE_SIZE);
+				 eth->rx_napi[id].napi.napi_id, PAGE_SIZE);
 	if (err < 0)
 		goto err_free_pp;
 
@@ -2202,7 +2165,8 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
 		       struct mtk_eth *eth)
 {
 	struct dim_sample dim_sample = {};
-	struct mtk_rx_ring *ring;
+	struct mtk_napi *rx_napi = container_of(napi, struct mtk_napi, napi);
+	struct mtk_rx_ring *ring = rx_napi->rx_ring;
 	bool xdp_flush = false;
 	int idx;
 	struct sk_buff *skb;
@@ -2213,16 +2177,15 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
 	dma_addr_t dma_addr = DMA_MAPPING_ERROR;
 	int ppe_idx = 0;
 
+	if (unlikely(!ring))
+		goto rx_done;
+
 	while (done < budget) {
 		unsigned int pktlen, *rxdcsum;
 		struct net_device *netdev;
 		u32 hash, reason;
 		int mac = 0;
 
-		ring = mtk_get_rx_ring(eth);
-		if (unlikely(!ring))
-			goto rx_done;
-
 		idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size);
 		rxd = ring->dma + idx * eth->soc->rx.desc_size;
 		data = ring->data[idx];
@@ -2414,7 +2377,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
 		 * we continue
 		 */
 		wmb();
-		mtk_update_rx_cpu_idx(eth);
+		mtk_update_rx_cpu_idx(eth, ring);
 	}
 
 	eth->rx_packets += done;
@@ -2623,7 +2586,9 @@ static int mtk_napi_tx(struct napi_struct *napi, int budget)
 
 static int mtk_napi_rx(struct napi_struct *napi, int budget)
 {
-	struct mtk_eth *eth = container_of(napi, struct mtk_eth, rx_napi);
+	struct mtk_napi *rx_napi = container_of(napi, struct mtk_napi, napi);
+	struct mtk_eth *eth = rx_napi->eth;
+	struct mtk_rx_ring *ring = rx_napi->rx_ring;
 	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
 	int rx_done_total = 0;
 
@@ -2632,7 +2597,7 @@ static int mtk_napi_rx(struct napi_struct *napi, int budget)
 	do {
 		int rx_done;
 
-		mtk_w32(eth, eth->soc->rx.irq_done_mask,
+		mtk_w32(eth, MTK_RX_DONE_INT(ring->ring_no),
 			reg_map->pdma.irq_status);
 		rx_done = mtk_poll_rx(napi, budget - rx_done_total, eth);
 		rx_done_total += rx_done;
@@ -2648,10 +2613,10 @@ static int mtk_napi_rx(struct napi_struct *napi, int budget)
 			return budget;
 
 	} while (mtk_r32(eth, reg_map->pdma.irq_status) &
-		 eth->soc->rx.irq_done_mask);
+		 MTK_RX_DONE_INT(ring->ring_no));
 
 	if (napi_complete_done(napi, rx_done_total))
-		mtk_rx_irq_enable(eth, eth->soc->rx.irq_done_mask);
+		mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(ring->ring_no));
 
 	return rx_done_total;
 }
@@ -2897,6 +2862,7 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag)
 	else
 		ring->crx_idx_reg = reg_map->pdma.pcrx_ptr +
 				    ring_no * MTK_QRX_OFFSET;
+	ring->ring_no = ring_no;
 	/* make sure that all changes to the dma ring are flushed before we
 	 * continue
 	 */
@@ -2965,6 +2931,7 @@ static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring, bool in_
 
 static int mtk_hwlro_rx_init(struct mtk_eth *eth)
 {
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
 	int i;
 	u32 ring_ctrl_dw1 = 0, ring_ctrl_dw2 = 0, ring_ctrl_dw3 = 0;
 	u32 lro_ctrl_dw0 = 0, lro_ctrl_dw3 = 0;
@@ -3025,6 +2992,7 @@ static int mtk_hwlro_rx_init(struct mtk_eth *eth)
 
 static void mtk_hwlro_rx_uninit(struct mtk_eth *eth)
 {
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
 	int i;
 	u32 val;
 
@@ -3051,6 +3019,7 @@ static void mtk_hwlro_rx_uninit(struct mtk_eth *eth)
 
 static void mtk_hwlro_val_ipaddr(struct mtk_eth *eth, int idx, __be32 ip)
 {
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
 	u32 reg_val;
 
 	reg_val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(idx));
@@ -3066,6 +3035,7 @@ static void mtk_hwlro_val_ipaddr(struct mtk_eth *eth, int idx, __be32 ip)
 
 static void mtk_hwlro_inval_ipaddr(struct mtk_eth *eth, int idx)
 {
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
 	u32 reg_val;
 
 	reg_val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(idx));
@@ -3201,6 +3171,111 @@ static int mtk_hwlro_get_fdir_all(struct net_device *dev,
 	return 0;
 }
 
+static u32 mtk_rss_indr_table(struct mtk_rss_params *rss_params, int index)
+{
+	u32 val = 0;
+	int i;
+
+	for (i = 16 * index; i < 16 * index + 16; i++)
+		val |= (rss_params->indirection_table[i] << (2 * (i % 16)));
+
+	return val;
+}
+
+static int mtk_rss_init(struct mtk_eth *eth)
+{
+	const struct mtk_soc_data *soc = eth->soc;
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
+	struct mtk_rss_params *rss_params = &eth->rss_params;
+	static u8 hash_key[MTK_RSS_HASH_KEYSIZE] = {
+		0xfa, 0x01, 0xac, 0xbe, 0x3b, 0xb7, 0x42, 0x6a,
+		0x0c, 0xf2, 0x30, 0x80, 0xa3, 0x2d, 0xcb, 0x77,
+		0xb4, 0x30, 0x7b, 0xae, 0xcb, 0x2b, 0xca, 0xd0,
+		0xb0, 0x8f, 0xa3, 0x43, 0x3d, 0x25, 0x67, 0x41,
+		0xc2, 0x0e, 0x5b, 0x25, 0xda, 0x56, 0x5a, 0x6d};
+	u32 val;
+	int i;
+
+	memcpy(rss_params->hash_key, hash_key, MTK_RSS_HASH_KEYSIZE);
+
+	for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE; i++)
+		rss_params->indirection_table[i] = i % eth->soc->rss_num;
+
+	if (soc->rx.desc_size == sizeof(struct mtk_rx_dma)) {
+		/* Set RSS rings to PSE modes */
+		for (i = 1; i <= MTK_HW_LRO_RING_NUM; i++) {
+			val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(i));
+			val |= MTK_RING_PSE_MODE;
+			mtk_w32(eth, val, MTK_LRO_CTRL_DW2_CFG(i));
+		}
+
+		/* Enable non-lro multiple rx */
+		val = mtk_r32(eth, reg_map->pdma.lro_ctrl_dw0);
+		val |= MTK_NON_LRO_MULTI_EN;
+		mtk_w32(eth, val, reg_map->pdma.lro_ctrl_dw0);
+
+		/* Enable RSS dly int supoort */
+		val |= MTK_LRO_DLY_INT_EN;
+		mtk_w32(eth, val, reg_map->pdma.lro_ctrl_dw0);
+	}
+
+	/* Hash Type */
+	val = mtk_r32(eth, reg_map->pdma.rss_glo_cfg);
+	val |= MTK_RSS_IPV4_STATIC_HASH;
+	val |= MTK_RSS_IPV6_STATIC_HASH;
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+	/* Hash Key */
+	for (i = 0; i < MTK_RSS_HASH_KEYSIZE / sizeof(u32); i++)
+		mtk_w32(eth, rss_params->hash_key[i], MTK_RSS_HASH_KEY_DW(i));
+
+	/* Select the size of indirection table */
+	for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE / 16; i++)
+		mtk_w32(eth, mtk_rss_indr_table(rss_params, i),
+			MTK_RSS_INDR_TABLE_DW(i));
+
+	/* Pause */
+	val |= MTK_RSS_CFG_REQ;
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+	/* Enable RSS */
+	val |= MTK_RSS_EN;
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+	/* Release pause */
+	val &= ~(MTK_RSS_CFG_REQ);
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+	/* Set perRSS GRP INT */
+	mtk_m32(eth, MTK_RX_DONE_INT(MTK_RSS_RING(1)),
+		MTK_RX_DONE_INT(MTK_RSS_RING(1)), reg_map->pdma.int_grp);
+	mtk_m32(eth, MTK_RX_DONE_INT(MTK_RSS_RING(2)),
+		MTK_RX_DONE_INT(MTK_RSS_RING(2)), reg_map->pdma.int_grp + 0x4);
+	mtk_m32(eth, MTK_RX_DONE_INT(MTK_RSS_RING(3)),
+		MTK_RX_DONE_INT(MTK_RSS_RING(3)), reg_map->pdma.int_grp3);
+
+	return 0;
+}
+
+static void mtk_rss_uninit(struct mtk_eth *eth)
+{
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
+	u32 val;
+
+	/* Pause */
+	val = mtk_r32(eth, reg_map->pdma.rss_glo_cfg);
+	val |= MTK_RSS_CFG_REQ;
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+	/* Disable RSS */
+	val &= ~(MTK_RSS_EN);
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+	/* Release pause */
+	val &= ~(MTK_RSS_CFG_REQ);
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+}
+
 static netdev_features_t mtk_fix_features(struct net_device *dev,
 					  netdev_features_t features)
 {
@@ -3291,6 +3366,17 @@ static int mtk_dma_init(struct mtk_eth *eth)
 			return err;
 	}
 
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		for (i = 1; i < MTK_RX_RSS_NUM; i++) {
+			err = mtk_rx_alloc(eth, MTK_RSS_RING(i), MTK_RX_FLAGS_NORMAL);
+			if (err)
+				return err;
+		}
+		err = mtk_rss_init(eth);
+		if (err)
+			return err;
+	}
+
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {
 		/* Enable random early drop and set drop threshold
 		 * automatically
@@ -3337,6 +3423,12 @@ static void mtk_dma_free(struct mtk_eth *eth)
 			mtk_rx_clean(eth, &eth->rx_ring[i], false);
 	}
 
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		mtk_rss_uninit(eth);
+		for (i = 1; i < MTK_RX_RSS_NUM; i++)
+			mtk_rx_clean(eth, &eth->rx_ring[MTK_RSS_RING(i)], true);
+	}
+
 	for (i = 0; i < DIV_ROUND_UP(soc->tx.fq_dma_size, MTK_FQ_DMA_LENGTH); i++) {
 		kfree(eth->scratch_head[i]);
 		eth->scratch_head[i] = NULL;
@@ -3369,23 +3461,23 @@ static void mtk_tx_timeout(struct net_device *dev, unsigned int txqueue)
 	schedule_work(&eth->pending_work);
 }
 
-static int mtk_get_irqs(struct platform_device *pdev, struct mtk_eth *eth)
+static int mtk_get_irqs_fe(struct platform_device *pdev, struct mtk_eth *eth)
 {
 	int i;
 
 	/* future SoCs beginning with MT7988 should use named IRQs in dts */
-	eth->irq[MTK_FE_IRQ_TX] = platform_get_irq_byname_optional(pdev, "fe1");
-	eth->irq[MTK_FE_IRQ_RX] = platform_get_irq_byname_optional(pdev, "fe2");
-	if (eth->irq[MTK_FE_IRQ_TX] >= 0 && eth->irq[MTK_FE_IRQ_RX] >= 0)
+	eth->irq_fe[MTK_FE_IRQ_TX] = platform_get_irq_byname_optional(pdev, "fe1");
+	eth->irq_fe[MTK_FE_IRQ_RX] = platform_get_irq_byname_optional(pdev, "fe2");
+	if (eth->irq_fe[MTK_FE_IRQ_TX] >= 0 && eth->irq_fe[MTK_FE_IRQ_RX] >= 0)
 		return 0;
 
 	/* only use legacy mode if platform_get_irq_byname_optional returned -ENXIO */
-	if (eth->irq[MTK_FE_IRQ_TX] != -ENXIO)
-		return dev_err_probe(&pdev->dev, eth->irq[MTK_FE_IRQ_TX],
+	if (eth->irq_fe[MTK_FE_IRQ_TX] != -ENXIO)
+		return dev_err_probe(&pdev->dev, eth->irq_fe[MTK_FE_IRQ_TX],
 				     "Error requesting FE TX IRQ\n");
 
-	if (eth->irq[MTK_FE_IRQ_RX] != -ENXIO)
-		return dev_err_probe(&pdev->dev, eth->irq[MTK_FE_IRQ_RX],
+	if (eth->irq_fe[MTK_FE_IRQ_RX] != -ENXIO)
+		return dev_err_probe(&pdev->dev, eth->irq_fe[MTK_FE_IRQ_RX],
 				     "Error requesting FE RX IRQ\n");
 
 	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT))
@@ -3400,14 +3492,14 @@ static int mtk_get_irqs(struct platform_device *pdev, struct mtk_eth *eth)
 	for (i = 0; i < MTK_FE_IRQ_NUM; i++) {
 		if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT)) {
 			if (i == MTK_FE_IRQ_SHARED)
-				eth->irq[MTK_FE_IRQ_SHARED] = platform_get_irq(pdev, i);
+				eth->irq_fe[MTK_FE_IRQ_SHARED] = platform_get_irq(pdev, i);
 			else
-				eth->irq[i] = eth->irq[MTK_FE_IRQ_SHARED];
+				eth->irq_fe[i] = eth->irq_fe[MTK_FE_IRQ_SHARED];
 		} else {
-			eth->irq[i] = platform_get_irq(pdev, i + 1);
+			eth->irq_fe[i] = platform_get_irq(pdev, i + 1);
 		}
 
-		if (eth->irq[i] < 0) {
+		if (eth->irq_fe[i] < 0) {
 			dev_err(&pdev->dev, "no IRQ%d resource found\n", i);
 			return -ENXIO;
 		}
@@ -3416,14 +3508,36 @@ static int mtk_get_irqs(struct platform_device *pdev, struct mtk_eth *eth)
 	return 0;
 }
 
-static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth)
+static int mtk_get_irqs_pdma(struct platform_device *pdev, struct mtk_eth *eth)
 {
-	struct mtk_eth *eth = _eth;
+	char rxring[] = "pdma0";
+	int i;
+
+	for (i = 0; i < MTK_PDMA_IRQ_NUM; i++) {
+		rxring[4] = '0' + i;
+		eth->irq_pdma[i] = platform_get_irq_byname(pdev, rxring);
+		if (eth->irq_pdma[i] < 0)
+			return eth->irq_pdma[i];
+	}
+
+	return 0;
+}
+
+static irqreturn_t mtk_handle_irq_rx(int irq, void *priv)
+{
+	struct mtk_napi *rx_napi = priv;
+	struct mtk_eth *eth = rx_napi->eth;
+	struct mtk_rx_ring *ring = rx_napi->rx_ring;
 
 	eth->rx_events++;
-	if (likely(napi_schedule_prep(&eth->rx_napi))) {
-		mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask);
-		__napi_schedule(&eth->rx_napi);
+	if (unlikely(!(mtk_r32(eth, eth->soc->reg_map->pdma.irq_status) &
+		       mtk_r32(eth, eth->soc->reg_map->pdma.irq_mask) &
+		       MTK_RX_DONE_INT(ring->ring_no))))
+		return IRQ_NONE;
+
+	if (likely(napi_schedule_prep(&rx_napi->napi))) {
+		mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(ring->ring_no));
+		__napi_schedule(&rx_napi->napi);
 	}
 
 	return IRQ_HANDLED;
@@ -3448,10 +3562,10 @@ static irqreturn_t mtk_handle_irq(int irq, void *_eth)
 	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
 
 	if (mtk_r32(eth, reg_map->pdma.irq_mask) &
-	    eth->soc->rx.irq_done_mask) {
+	    MTK_RX_DONE_INT(0)) {
 		if (mtk_r32(eth, reg_map->pdma.irq_status) &
-		    eth->soc->rx.irq_done_mask)
-			mtk_handle_irq_rx(irq, _eth);
+		    MTK_RX_DONE_INT(0))
+			mtk_handle_irq_rx(irq, &eth->rx_napi[0]);
 	}
 	if (mtk_r32(eth, reg_map->tx_irq_mask) & MTK_TX_DONE_INT) {
 		if (mtk_r32(eth, reg_map->tx_irq_status) & MTK_TX_DONE_INT)
@@ -3468,10 +3582,10 @@ static void mtk_poll_controller(struct net_device *dev)
 	struct mtk_eth *eth = mac->hw;
 
 	mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
-	mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask);
-	mtk_handle_irq_rx(eth->irq[MTK_FE_IRQ_RX], dev);
+	mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(0));
+	mtk_handle_irq_rx(eth->irq_fe[MTK_FE_IRQ_RX], &eth->rx_napi[0]);
 	mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
-	mtk_rx_irq_enable(eth, eth->soc->rx.irq_done_mask);
+	mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(0));
 }
 #endif
 
@@ -3643,9 +3757,17 @@ static int mtk_open(struct net_device *dev)
 		}
 
 		napi_enable(&eth->tx_napi);
-		napi_enable(&eth->rx_napi);
+		napi_enable(&eth->rx_napi[0].napi);
 		mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
-		mtk_rx_irq_enable(eth, soc->rx.irq_done_mask);
+		mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(0));
+
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+			for (i = 1; i < MTK_RX_RSS_NUM; i++) {
+				napi_enable(&eth->rx_napi[MTK_RSS_RING(i)].napi);
+				mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(MTK_RSS_RING(i)));
+			}
+		}
+
 		refcount_set(&eth->dma_refcnt, 1);
 	} else {
 		refcount_inc(&eth->dma_refcnt);
@@ -3730,9 +3852,16 @@ static int mtk_stop(struct net_device *dev)
 		mtk_gdm_config(eth, i, MTK_GDMA_DROP_ALL);
 
 	mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
-	mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask);
+	mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(0));
 	napi_disable(&eth->tx_napi);
-	napi_disable(&eth->rx_napi);
+	napi_disable(&eth->rx_napi[0].napi);
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		for (i = 1; i < MTK_RX_RSS_NUM; i++) {
+			mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(MTK_RSS_RING(i)));
+			napi_disable(&eth->rx_napi[MTK_RSS_RING(i)].napi);
+		}
+	}
 
 	cancel_work_sync(&eth->rx_dim.work);
 	cancel_work_sync(&eth->tx_dim.work);
@@ -3843,9 +3972,7 @@ static void mtk_dim_rx(struct work_struct *work)
 						dim->profile_ix);
 	spin_lock_bh(&eth->dim_lock);
 
-	val = mtk_r32(eth, reg_map->pdma.delay_irq);
-	val &= MTK_PDMA_DELAY_TX_MASK;
-	val |= MTK_PDMA_DELAY_RX_EN;
+	val = MTK_PDMA_DELAY_RX_EN;
 
 	cur = min_t(u32, DIV_ROUND_UP(cur_profile.usec, 20), MTK_PDMA_DELAY_PTIME_MASK);
 	val |= cur << MTK_PDMA_DELAY_RX_PTIME_SHIFT;
@@ -3853,9 +3980,19 @@ static void mtk_dim_rx(struct work_struct *work)
 	cur = min_t(u32, cur_profile.pkts, MTK_PDMA_DELAY_PINT_MASK);
 	val |= cur << MTK_PDMA_DELAY_RX_PINT_SHIFT;
 
-	mtk_w32(eth, val, reg_map->pdma.delay_irq);
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
-		mtk_w32(eth, val, reg_map->qdma.delay_irq);
+		mtk_m32(eth, MTK_PDMA_DELAY_TX_MASK,
+			val << MTK_PDMA_DELAY_TX_PTIME_SHIFT, reg_map->qdma.delay_irq);
+
+	if (eth->soc->rx.desc_size == sizeof(struct mtk_rx_dma)) {
+		mtk_m32(eth, MTK_PDMA_DELAY_RX_MASK, val, reg_map->pdma.delay_irq);
+		mtk_w32(eth, val, reg_map->pdma.lro_rx1_dly_int);
+		mtk_w32(eth, val, reg_map->pdma.lro_rx1_dly_int + 0x4);
+		mtk_w32(eth, val, reg_map->pdma.lro_rx1_dly_int + 0x8);
+	} else {
+		val = val | (val << MTK_PDMA_DELAY_RX_RING_SHIFT);
+		mtk_w32(eth, val, reg_map->pdma.rx_delay_irq);
+	}
 
 	spin_unlock_bh(&eth->dim_lock);
 
@@ -3874,9 +4011,7 @@ static void mtk_dim_tx(struct work_struct *work)
 						dim->profile_ix);
 	spin_lock_bh(&eth->dim_lock);
 
-	val = mtk_r32(eth, reg_map->pdma.delay_irq);
-	val &= MTK_PDMA_DELAY_RX_MASK;
-	val |= MTK_PDMA_DELAY_TX_EN;
+	val = MTK_PDMA_DELAY_TX_EN;
 
 	cur = min_t(u32, DIV_ROUND_UP(cur_profile.usec, 20), MTK_PDMA_DELAY_PTIME_MASK);
 	val |= cur << MTK_PDMA_DELAY_TX_PTIME_SHIFT;
@@ -3884,9 +4019,16 @@ static void mtk_dim_tx(struct work_struct *work)
 	cur = min_t(u32, cur_profile.pkts, MTK_PDMA_DELAY_PINT_MASK);
 	val |= cur << MTK_PDMA_DELAY_TX_PINT_SHIFT;
 
-	mtk_w32(eth, val, reg_map->pdma.delay_irq);
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
-		mtk_w32(eth, val, reg_map->qdma.delay_irq);
+		mtk_m32(eth, MTK_PDMA_DELAY_RX_MASK,
+			val >> MTK_PDMA_DELAY_TX_PTIME_SHIFT, reg_map->qdma.delay_irq);
+
+	if (eth->soc->rx.desc_size == sizeof(struct mtk_rx_dma)) {
+		mtk_m32(eth, MTK_PDMA_DELAY_TX_MASK, val, reg_map->pdma.delay_irq);
+	} else {
+		mtk_w32(eth, val >> MTK_PDMA_DELAY_TX_PTIME_SHIFT,
+			reg_map->pdma.tx_delay_irq);
+	}
 
 	spin_unlock_bh(&eth->dim_lock);
 
@@ -4104,6 +4246,25 @@ static void mtk_hw_reset_monitor_work(struct work_struct *work)
 			      MTK_DMA_MONITOR_TIMEOUT);
 }
 
+static int mtk_napi_init(struct mtk_eth *eth)
+{
+	struct mtk_napi *rx_napi = &eth->rx_napi[0];
+	int i;
+
+	rx_napi->eth = eth;
+	rx_napi->rx_ring = &eth->rx_ring[0];
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		for (i = 1; i < MTK_RX_RSS_NUM; i++) {
+			rx_napi = &eth->rx_napi[MTK_RSS_RING(i)];
+			rx_napi->eth = eth;
+			rx_napi->rx_ring = &eth->rx_ring[MTK_RSS_RING(i)];
+		}
+	}
+
+	return 0;
+}
+
 static int mtk_hw_init(struct mtk_eth *eth, bool reset)
 {
 	u32 dma_mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA |
@@ -4209,11 +4370,17 @@ static int mtk_hw_init(struct mtk_eth *eth, bool reset)
 	mtk_rx_irq_disable(eth, ~0);
 
 	/* FE int grouping */
-	mtk_w32(eth, MTK_TX_DONE_INT, reg_map->pdma.int_grp);
-	mtk_w32(eth, eth->soc->rx.irq_done_mask, reg_map->pdma.int_grp + 4);
+
 	mtk_w32(eth, MTK_TX_DONE_INT, reg_map->qdma.int_grp);
-	mtk_w32(eth, eth->soc->rx.irq_done_mask, reg_map->qdma.int_grp + 4);
-	mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP);
+	mtk_w32(eth, MTK_RX_DONE_INT(0), reg_map->qdma.int_grp + 4);
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_PDMA_INT)) {
+		mtk_w32(eth, 0x210FFFF2, MTK_FE_INT_GRP);
+	} else {
+		mtk_w32(eth, MTK_TX_DONE_INT, reg_map->pdma.int_grp);
+		mtk_w32(eth, MTK_RX_DONE_INT(0), reg_map->pdma.int_grp + 4);
+		mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP);
+	}
 
 	if (mtk_is_netsys_v3_or_greater(eth)) {
 		/* PSE dummy page mechanism */
@@ -4651,6 +4818,8 @@ static void mtk_get_ethtool_stats(struct net_device *dev,
 static int mtk_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
 			 u32 *rule_locs)
 {
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
 	int ret = -EOPNOTSUPP;
 
 	switch (cmd->cmd) {
@@ -4658,6 +4827,9 @@ static int mtk_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
 		if (dev->hw_features & NETIF_F_LRO) {
 			cmd->data = MTK_MAX_RX_RING_NUM;
 			ret = 0;
+		} else if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+			cmd->data = MTK_RX_RSS_NUM;
+			ret = 0;
 		}
 		break;
 	case ETHTOOL_GRXCLSRLCNT:
@@ -4732,6 +4904,71 @@ static int mtk_set_eee(struct net_device *dev, struct ethtool_keee *eee)
 	return phylink_ethtool_set_eee(mac->phylink, eee);
 }
 
+static u32 mtk_get_rxfh_key_size(struct net_device *dev)
+{
+	return MTK_RSS_HASH_KEYSIZE;
+}
+
+static u32 mtk_get_rxfh_indir_size(struct net_device *dev)
+{
+	return MTK_RSS_MAX_INDIRECTION_TABLE;
+}
+
+static int mtk_get_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	struct mtk_rss_params *rss_params = &eth->rss_params;
+	int i;
+
+	if (rxfh->hfunc)
+		rxfh->hfunc = ETH_RSS_HASH_TOP;	/* Toeplitz */
+
+	if (rxfh->key) {
+		memcpy(rxfh->key, rss_params->hash_key,
+		       sizeof(rss_params->hash_key));
+	}
+
+	if (rxfh->indir) {
+		for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE; i++)
+			rxfh->indir[i] = rss_params->indirection_table[i];
+	}
+
+	return 0;
+}
+
+static int mtk_set_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh,
+			struct netlink_ext_ack *extack)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	struct mtk_rss_params *rss_params = &eth->rss_params;
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
+	int i;
+
+	if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+	    rxfh->hfunc != ETH_RSS_HASH_TOP)
+		return -EOPNOTSUPP;
+
+	if (rxfh->key) {
+		memcpy(rss_params->hash_key, rxfh->key,
+		       sizeof(rss_params->hash_key));
+		for (i = 0; i < MTK_RSS_HASH_KEYSIZE / sizeof(u32); i++)
+			mtk_w32(eth, rss_params->hash_key[i],
+				MTK_RSS_HASH_KEY_DW(i));
+	}
+
+	if (rxfh->indir) {
+		for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE; i++)
+			rss_params->indirection_table[i] = rxfh->indir[i];
+		for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE / 16; i++)
+			mtk_w32(eth, mtk_rss_indr_table(rss_params, i),
+				MTK_RSS_INDR_TABLE_DW(i));
+	}
+
+	return 0;
+}
+
 static u16 mtk_select_queue(struct net_device *dev, struct sk_buff *skb,
 			    struct net_device *sb_dev)
 {
@@ -4766,6 +5003,10 @@ static const struct ethtool_ops mtk_ethtool_ops = {
 	.set_rxnfc		= mtk_set_rxnfc,
 	.get_eee		= mtk_get_eee,
 	.set_eee		= mtk_set_eee,
+	.get_rxfh_key_size	= mtk_get_rxfh_key_size,
+	.get_rxfh_indir_size	= mtk_get_rxfh_indir_size,
+	.get_rxfh		= mtk_get_rxfh,
+	.set_rxfh		= mtk_set_rxfh,
 };
 
 static const struct net_device_ops mtk_netdev_ops = {
@@ -4955,7 +5196,7 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
 	eth->netdev[id]->features |= eth->soc->hw_features;
 	eth->netdev[id]->ethtool_ops = &mtk_ethtool_ops;
 
-	eth->netdev[id]->irq = eth->irq[MTK_FE_IRQ_SHARED];
+	eth->netdev[id]->irq = eth->irq_fe[MTK_FE_IRQ_SHARED];
 	eth->netdev[id]->dev.of_node = np;
 
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628))
@@ -5066,6 +5307,7 @@ static int mtk_probe(struct platform_device *pdev)
 	struct resource *res = NULL;
 	struct device_node *mac_np;
 	struct mtk_eth *eth;
+	char *irqname;
 	int err, i;
 
 	eth = devm_kzalloc(&pdev->dev, sizeof(*eth), GFP_KERNEL);
@@ -5197,10 +5439,16 @@ static int mtk_probe(struct platform_device *pdev)
 		}
 	}
 
-	err = mtk_get_irqs(pdev, eth);
+	err = mtk_get_irqs_fe(pdev, eth);
 	if (err)
 		goto err_wed_exit;
 
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_PDMA_INT)) {
+		err = mtk_get_irqs_pdma(pdev, eth);
+		if (err)
+			goto err_wed_exit;
+	}
+
 	for (i = 0; i < ARRAY_SIZE(eth->clks); i++) {
 		eth->clks[i] = devm_clk_get(eth->dev,
 					    mtk_clks_source_name[i]);
@@ -5243,23 +5491,56 @@ static int mtk_probe(struct platform_device *pdev)
 		}
 	}
 
+	err = mtk_napi_init(eth);
+	if (err)
+		goto err_free_dev;
+
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT)) {
-		err = devm_request_irq(eth->dev, eth->irq[MTK_FE_IRQ_SHARED],
+		err = devm_request_irq(eth->dev, eth->irq_fe[MTK_FE_IRQ_SHARED],
 				       mtk_handle_irq, 0,
 				       dev_name(eth->dev), eth);
 	} else {
-		err = devm_request_irq(eth->dev, eth->irq[MTK_FE_IRQ_TX],
+		irqname = devm_kasprintf(eth->dev, GFP_KERNEL, "%s TX",
+					 dev_name(eth->dev));
+		err = devm_request_irq(eth->dev, eth->irq_fe[MTK_FE_IRQ_TX],
 				       mtk_handle_irq_tx, 0,
-				       dev_name(eth->dev), eth);
+				       irqname, eth);
 		if (err)
 			goto err_free_dev;
 
-		err = devm_request_irq(eth->dev, eth->irq[MTK_FE_IRQ_RX],
-				       mtk_handle_irq_rx, 0,
-				       dev_name(eth->dev), eth);
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_PDMA_INT)) {
+			irqname = devm_kasprintf(eth->dev, GFP_KERNEL, "%s PDMA RX %d",
+						 dev_name(eth->dev), 0);
+			err = devm_request_irq(eth->dev, eth->irq_pdma[0],
+					       mtk_handle_irq_rx, IRQF_SHARED,
+					       irqname, &eth->rx_napi[0]);
+			if (err)
+				goto err_free_dev;
+
+			if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+				for (i = 1; i < MTK_RX_RSS_NUM; i++) {
+					irqname = devm_kasprintf(eth->dev, GFP_KERNEL,
+								 "%s RSS RX %d",
+								 dev_name(eth->dev), i);
+					err = devm_request_irq(eth->dev,
+							       eth->irq_pdma[MTK_RSS_RING(i)],
+							       mtk_handle_irq_rx, IRQF_SHARED,
+							       irqname,
+							       &eth->rx_napi[MTK_RSS_RING(i)]);
+					if (err)
+						goto err_free_dev;
+				}
+			}
+		} else {
+			irqname = devm_kasprintf(eth->dev, GFP_KERNEL, "%s RX",
+						 dev_name(eth->dev));
+			err = devm_request_irq(eth->dev, eth->irq_fe[MTK_FE_IRQ_RX],
+					       mtk_handle_irq_rx, 0,
+					       irqname, &eth->rx_napi[0]);
+			if (err)
+				goto err_free_dev;
+		}
 	}
-	if (err)
-		goto err_free_dev;
 
 	/* No MT7628/88 support yet */
 	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) {
@@ -5300,7 +5581,7 @@ static int mtk_probe(struct platform_device *pdev)
 		} else
 			netif_info(eth, probe, eth->netdev[i],
 				   "mediatek frame engine at 0x%08lx, irq %d\n",
-				   eth->netdev[i]->base_addr, eth->irq[MTK_FE_IRQ_SHARED]);
+				   eth->netdev[i]->base_addr, eth->irq_fe[MTK_FE_IRQ_SHARED]);
 	}
 
 	/* we run 2 devices on the same DMA ring so we need a dummy device
@@ -5313,7 +5594,13 @@ static int mtk_probe(struct platform_device *pdev)
 		goto err_unreg_netdev;
 	}
 	netif_napi_add(eth->dummy_dev, &eth->tx_napi, mtk_napi_tx);
-	netif_napi_add(eth->dummy_dev, &eth->rx_napi, mtk_napi_rx);
+	netif_napi_add(eth->dummy_dev, &eth->rx_napi[0].napi, mtk_napi_rx);
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		for (i = 1; i < MTK_RX_RSS_NUM; i++)
+			netif_napi_add(eth->dummy_dev, &eth->rx_napi[MTK_RSS_RING(i)].napi,
+				       mtk_napi_rx);
+	}
 
 	platform_set_drvdata(pdev, eth);
 	schedule_delayed_work(&eth->reset.monitor_work,
@@ -5357,7 +5644,12 @@ static void mtk_remove(struct platform_device *pdev)
 	mtk_hw_deinit(eth);
 
 	netif_napi_del(&eth->tx_napi);
-	netif_napi_del(&eth->rx_napi);
+	netif_napi_del(&eth->rx_napi[0].napi);
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		for (i = 1; i < MTK_RX_RSS_NUM; i++)
+			netif_napi_del(&eth->rx_napi[MTK_RSS_RING(i)].napi);
+	}
 	mtk_cleanup(eth);
 	free_netdev(eth->dummy_dev);
 	mtk_mdio_cleanup(eth);
@@ -5370,6 +5662,7 @@ static const struct mtk_soc_data mt2701_data = {
 	.required_clks = MT7623_CLKS_BITMAP,
 	.required_pctl = true,
 	.version = 1,
+	.rss_num = 0,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5379,7 +5672,6 @@ static const struct mtk_soc_data mt2701_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID,
 		.dma_size = MTK_DMA_SIZE(2K),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5398,6 +5690,7 @@ static const struct mtk_soc_data mt7621_data = {
 	.ppe_num = 1,
 	.hash_offset = 2,
 	.foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
+	.rss_num = 0,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5407,7 +5700,6 @@ static const struct mtk_soc_data mt7621_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID,
 		.dma_size = MTK_DMA_SIZE(2K),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5428,6 +5720,7 @@ static const struct mtk_soc_data mt7622_data = {
 	.hash_offset = 2,
 	.has_accounting = true,
 	.foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
+	.rss_num = 0,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5437,7 +5730,6 @@ static const struct mtk_soc_data mt7622_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID,
 		.dma_size = MTK_DMA_SIZE(2K),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5457,6 +5749,7 @@ static const struct mtk_soc_data mt7623_data = {
 	.hash_offset = 2,
 	.foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
 	.disable_pll_modes = true,
+	.rss_num = 0,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5466,7 +5759,6 @@ static const struct mtk_soc_data mt7623_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID,
 		.dma_size = MTK_DMA_SIZE(2K),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5483,6 +5775,7 @@ static const struct mtk_soc_data mt7629_data = {
 	.required_pctl = false,
 	.has_accounting = true,
 	.version = 1,
+	.rss_num = 0,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5492,7 +5785,6 @@ static const struct mtk_soc_data mt7629_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID,
 		.dma_size = MTK_DMA_SIZE(2K),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5513,16 +5805,16 @@ static const struct mtk_soc_data mt7981_data = {
 	.hash_offset = 4,
 	.has_accounting = true,
 	.foe_entry_size = MTK_FOE_ENTRY_V2_SIZE,
+	.rss_num = 4,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma_v2),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
 		.dma_len_offset = 8,
-		.dma_size = MTK_DMA_SIZE(2K),
+		.dma_size = MTK_DMA_SIZE(4K),
 		.fq_dma_size = MTK_DMA_SIZE(2K),
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID_V2,
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
 		.dma_len_offset = 16,
@@ -5543,6 +5835,7 @@ static const struct mtk_soc_data mt7986_data = {
 	.hash_offset = 4,
 	.has_accounting = true,
 	.foe_entry_size = MTK_FOE_ENTRY_V2_SIZE,
+	.rss_num = 4,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma_v2),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
@@ -5552,7 +5845,6 @@ static const struct mtk_soc_data mt7986_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID_V2,
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
 		.dma_len_offset = 16,
@@ -5573,20 +5865,20 @@ static const struct mtk_soc_data mt7988_data = {
 	.hash_offset = 4,
 	.has_accounting = true,
 	.foe_entry_size = MTK_FOE_ENTRY_V3_SIZE,
+	.rss_num = 4,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma_v2),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
 		.dma_len_offset = 8,
-		.dma_size = MTK_DMA_SIZE(2K),
+		.dma_size = MTK_DMA_SIZE(4K),
 		.fq_dma_size = MTK_DMA_SIZE(4K),
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma_v2),
-		.irq_done_mask = MTK_RX_DONE_INT_V2,
 		.dma_l4_valid = RX_DMA_L4_VALID_V2,
 		.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
 		.dma_len_offset = 8,
-		.dma_size = MTK_DMA_SIZE(2K),
+		.dma_size = MTK_DMA_SIZE(1K),
 	},
 };
 
@@ -5597,6 +5889,7 @@ static const struct mtk_soc_data rt5350_data = {
 	.required_clks = MT7628_CLKS_BITMAP,
 	.required_pctl = false,
 	.version = 1,
+	.rss_num = 0,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5605,7 +5898,6 @@ static const struct mtk_soc_data rt5350_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID_PDMA,
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
 		.dma_len_offset = 16,
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index 334625814b97..db72337e9fd4 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -76,6 +76,8 @@
 #define	MTK_HW_LRO_BW_THRE		3000
 #define	MTK_HW_LRO_REPLACE_DELTA	1000
 #define	MTK_HW_LRO_SDL_REMAIN_ROOM	1522
+#define MTK_RSS_HASH_KEYSIZE		40
+#define MTK_RSS_MAX_INDIRECTION_TABLE	128
 
 /* Frame Engine Global Configuration */
 #define MTK_FE_GLO_CFG(x)	(((x) == MTK_GMAC3_ID) ? 0x24 : 0x00)
@@ -97,6 +99,8 @@
 #define MTK_GDM1_AF		BIT(28)
 #define MTK_GDM2_AF		BIT(29)
 
+#define MTK_PDMA_IRQ_NUM	(4)
+
 /* PDMA HW LRO Alter Flow Timer Register */
 #define MTK_PDMA_LRO_ALT_REFRESH_TIMER	0x1c
 
@@ -179,7 +183,10 @@
 
 /* PDMA HW LRO Control Registers */
 #define MTK_PDMA_LRO_CTRL_DW0	0x980
+#define MTK_HW_LRO_RING_NUM		(mtk_is_netsys_v3_or_greater(eth) ? 4 : 3)
 #define MTK_LRO_EN			BIT(0)
+#define MTK_NON_LRO_MULTI_EN		BIT(2)
+#define MTK_LRO_DLY_INT_EN		BIT(5)
 #define MTK_L3_CKS_UPD_EN		BIT(7)
 #define MTK_L3_CKS_UPD_EN_V2		BIT(19)
 #define MTK_LRO_ALT_PKT_CNT_MODE	BIT(21)
@@ -198,6 +205,19 @@
 #define MTK_MULTI_EN		BIT(10)
 #define MTK_PDMA_SIZE_8DWORDS	(1 << 4)
 
+/* PDMA RSS Control Registers */
+#define MTK_RX_NAPI_NUM			(4)
+#define MTK_RX_RSS_NUM			(eth->soc->rss_num)
+#define MTK_RSS_RING(x)			(x)
+#define MTK_RSS_EN			BIT(0)
+#define MTK_RSS_CFG_REQ			BIT(2)
+#define MTK_RSS_IPV6_STATIC_HASH	(0x7 << 8)
+#define MTK_RSS_IPV4_STATIC_HASH	(0x7 << 12)
+#define MTK_RSS_HASH_KEY_DW(x)		(reg_map->pdma.rss_glo_cfg + 0x20 +	\
+					 ((x) * 0x4))
+#define MTK_RSS_INDR_TABLE_DW(x)	(reg_map->pdma.rss_glo_cfg + 0x50 +	\
+					 ((x) * 0x4))
+
 /* PDMA Global Configuration Register */
 #define MTK_PDMA_LRO_SDL	0x3000
 #define MTK_RX_CFG_SDL_OFFSET	16
@@ -209,6 +229,7 @@
 /* PDMA Delay Interrupt Register */
 #define MTK_PDMA_DELAY_RX_MASK		GENMASK(15, 0)
 #define MTK_PDMA_DELAY_RX_EN		BIT(15)
+#define MTK_PDMA_DELAY_RX_RING_SHIFT	16
 #define MTK_PDMA_DELAY_RX_PINT_SHIFT	8
 #define MTK_PDMA_DELAY_RX_PTIME_SHIFT	0
 
@@ -229,14 +250,12 @@
 #define MTK_RING_MYIP_VLD		BIT(9)
 
 /* PDMA HW LRO Ring Control Registers */
-#define MTK_LRO_RX_RING0_CTRL_DW1	0xb28
-#define MTK_LRO_RX_RING0_CTRL_DW2	0xb2c
-#define MTK_LRO_RX_RING0_CTRL_DW3	0xb30
-#define MTK_LRO_CTRL_DW1_CFG(x)		(MTK_LRO_RX_RING0_CTRL_DW1 + (x * 0x40))
-#define MTK_LRO_CTRL_DW2_CFG(x)		(MTK_LRO_RX_RING0_CTRL_DW2 + (x * 0x40))
-#define MTK_LRO_CTRL_DW3_CFG(x)		(MTK_LRO_RX_RING0_CTRL_DW3 + (x * 0x40))
+#define MTK_LRO_CTRL_DW1_CFG(x)		(reg_map->pdma.lro_ring_ctrl_dw1 + ((x) * 0x40))
+#define MTK_LRO_CTRL_DW2_CFG(x)		(reg_map->pdma.lro_ring_ctrl_dw1 + 0x4 + ((x) * 0x40))
+#define MTK_LRO_CTRL_DW3_CFG(x)		(reg_map->pdma.lro_ring_ctrl_dw1 + 0x8 + ((x) * 0x40))
 #define MTK_RING_AGE_TIME_L		((MTK_HW_LRO_AGE_TIME & 0x3ff) << 22)
 #define MTK_RING_AGE_TIME_H		((MTK_HW_LRO_AGE_TIME >> 10) & 0x3f)
+#define MTK_RING_PSE_MODE		BIT(6)
 #define MTK_RING_AUTO_LERAN_MODE	(3 << 6)
 #define MTK_RING_VLD			BIT(8)
 #define MTK_RING_MAX_AGG_TIME		((MTK_HW_LRO_AGG_TIME & 0xffff) << 10)
@@ -290,7 +309,20 @@
 #define FC_THRES_MIN		0x4444
 
 /* QDMA Interrupt Status Register */
-#define MTK_RX_DONE_DLY		BIT(30)
+#define MTK_RX_DONE_INT_V1(ring_no) \
+	( \
+		(ring_no) ? \
+		BIT(24 + (ring_no)) : \
+		BIT(30) \
+	)
+
+#define MTK_RX_DONE_INT_V2(ring_no)	BIT(24 + (ring_no))
+
+#define MTK_RX_DONE_INT(ring_no)		\
+	(mtk_is_netsys_v3_or_greater(eth) ?  \
+	 MTK_RX_DONE_INT_V2(ring_no) : \
+	 MTK_RX_DONE_INT_V1(ring_no))
+
 #define MTK_TX_DONE_DLY		BIT(28)
 #define MTK_RX_DONE_INT3	BIT(19)
 #define MTK_RX_DONE_INT2	BIT(18)
@@ -300,11 +332,8 @@
 #define MTK_TX_DONE_INT2	BIT(2)
 #define MTK_TX_DONE_INT1	BIT(1)
 #define MTK_TX_DONE_INT0	BIT(0)
-#define MTK_RX_DONE_INT		MTK_RX_DONE_DLY
 #define MTK_TX_DONE_INT		MTK_TX_DONE_DLY
 
-#define MTK_RX_DONE_INT_V2	BIT(14)
-
 #define MTK_CDM_TXFIFO_RDY	BIT(7)
 
 /* QDMA Interrupt grouping registers */
@@ -942,6 +971,7 @@ struct mtk_tx_ring {
 	struct mtk_tx_dma *dma_pdma;	/* For MT7628/88 PDMA handling */
 	dma_addr_t phys_pdma;
 	int cpu_idx;
+	bool in_sram;
 };
 
 /* PDMA rx ring mode */
@@ -967,13 +997,38 @@ struct mtk_rx_ring {
 	u16 buf_size;
 	u16 dma_size;
 	bool calc_idx_update;
+	bool in_sram;
 	u16 calc_idx;
 	u32 crx_idx_reg;
+	u32 ring_no;
 	/* page_pool */
 	struct page_pool *page_pool;
 	struct xdp_rxq_info xdp_q;
 };
 
+/* struct mtk_rss_params -	This is the structure holding parameters
+ *				for the RSS ring
+ * @hash_key			The element is used to record the
+ *				secret key for the RSS ring
+ * indirection_table		The element is used to record the
+ *				indirection table for the RSS ring
+ */
+struct mtk_rss_params {
+	u32		hash_key[MTK_RSS_HASH_KEYSIZE / sizeof(u32)];
+	u8		indirection_table[MTK_RSS_MAX_INDIRECTION_TABLE];
+};
+
+/* struct mtk_napi -	This is the structure holding NAPI-related information,
+ *			and a mtk_napi struct is binding to one interrupt group
+ * @napi:		The NAPI struct
+ * @rx_ring:		Pointer to the memory holding info about the RX ring
+ */
+struct mtk_napi {
+	struct napi_struct	napi;
+	struct mtk_eth		*eth;
+	struct mtk_rx_ring	*rx_ring;
+};
+
 enum mkt_eth_capabilities {
 	MTK_RGMII_BIT = 0,
 	MTK_TRGMII_BIT,
@@ -985,7 +1040,9 @@ enum mkt_eth_capabilities {
 	MTK_INFRA_BIT,
 	MTK_SHARED_SGMII_BIT,
 	MTK_HWLRO_BIT,
+	MTK_RSS_BIT,
 	MTK_SHARED_INT_BIT,
+	MTK_PDMA_INT_BIT,
 	MTK_TRGMII_MT7621_CLK_BIT,
 	MTK_QDMA_BIT,
 	MTK_SOC_MT7628_BIT,
@@ -1025,7 +1082,9 @@ enum mkt_eth_capabilities {
 #define MTK_INFRA		BIT_ULL(MTK_INFRA_BIT)
 #define MTK_SHARED_SGMII	BIT_ULL(MTK_SHARED_SGMII_BIT)
 #define MTK_HWLRO		BIT_ULL(MTK_HWLRO_BIT)
+#define MTK_RSS			BIT_ULL(MTK_RSS_BIT)
 #define MTK_SHARED_INT		BIT_ULL(MTK_SHARED_INT_BIT)
+#define MTK_PDMA_INT		BIT_ULL(MTK_PDMA_INT_BIT)
 #define MTK_TRGMII_MT7621_CLK	BIT_ULL(MTK_TRGMII_MT7621_CLK_BIT)
 #define MTK_QDMA		BIT_ULL(MTK_QDMA_BIT)
 #define MTK_SOC_MT7628		BIT_ULL(MTK_SOC_MT7628_BIT)
@@ -1117,15 +1176,15 @@ enum mkt_eth_capabilities {
 #define MT7981_CAPS  (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC2_GEPHY | \
 		      MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \
 		      MTK_MUX_U3_GMAC2_TO_QPHY | MTK_U3_COPHY_V2 | \
-		      MTK_RSTCTRL_PPE1 | MTK_SRAM)
+		      MTK_RSTCTRL_PPE1 | MTK_SRAM | MTK_PDMA_INT)
 
 #define MT7986_CAPS  (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \
 		      MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \
-		      MTK_RSTCTRL_PPE1 | MTK_SRAM)
+		      MTK_RSTCTRL_PPE1 | MTK_SRAM | MTK_PDMA_INT)
 
 #define MT7988_CAPS  (MTK_36BIT_DMA | MTK_GDM1_ESW | MTK_GMAC2_2P5GPHY | \
 		      MTK_MUX_GMAC2_TO_2P5GPHY | MTK_QDMA | MTK_RSTCTRL_PPE1 | \
-		      MTK_RSTCTRL_PPE2 | MTK_SRAM)
+		      MTK_RSTCTRL_PPE2 | MTK_SRAM | MTK_PDMA_INT | MTK_RSS)
 
 struct mtk_tx_dma_desc_info {
 	dma_addr_t	addr;
@@ -1223,6 +1282,7 @@ struct mtk_reg_map {
 struct mtk_soc_data {
 	const struct mtk_reg_map *reg_map;
 	u32             ana_rgc3;
+	u32		rss_num;
 	u64		caps;
 	u64		required_clks;
 	bool		required_pctl;
@@ -1270,7 +1330,8 @@ struct mtk_soc_data {
  *			dummy for NAPI to work
  * @netdev:		The netdev instances
  * @mac:		Each netdev is linked to a physical MAC
- * @irq:		The IRQ that we are using
+ * @irq_fe:		Array of IRQs of the frame engine
+ * @irq_pdma:		Array of IRQs of the PDMA used for RSS
  * @msg_enable:		Ethtool msg level
  * @ethsys:		The register map pointing at the range used to setup
  *			MII modes
@@ -1314,7 +1375,8 @@ struct mtk_eth {
 	struct net_device		*dummy_dev;
 	struct net_device		*netdev[MTK_MAX_DEVS];
 	struct mtk_mac			*mac[MTK_MAX_DEVS];
-	int				irq[MTK_FE_IRQ_NUM];
+	int				irq_fe[MTK_FE_IRQ_NUM];
+	int				irq_pdma[MTK_PDMA_IRQ_NUM];
 	u32				msg_enable;
 	unsigned long			sysclk;
 	struct regmap			*ethsys;
@@ -1327,7 +1389,8 @@ struct mtk_eth {
 	struct mtk_rx_ring		rx_ring[MTK_MAX_RX_RING_NUM];
 	struct mtk_rx_ring		rx_ring_qdma;
 	struct napi_struct		tx_napi;
-	struct napi_struct		rx_napi;
+	struct mtk_napi			rx_napi[MTK_RX_NAPI_NUM];
+	struct mtk_rss_params		rss_params;
 	void				*scratch_ring;
 	dma_addr_t			phy_scratch_ring;
 	void				*scratch_head[MTK_FQ_DMA_HEAD];
-- 
2.43.0



From pavan.kondeti at oss.qualcomm.com  Thu Dec  4 09:01:57 2025
From: pavan.kondeti at oss.qualcomm.com (Pavan Kondeti)
Date: Thu, 4 Dec 2025 22:31:57 +0530
Subject: Alternative to arm64.nopauth cmdline for disabling Pointer
 Authentication
In-Reply-To: <868qfipfij.wl-maz@kernel.org>
References: <3fcf6614-ee83-4a06-9024-83573b2e642e@quicinc.com>
 <86ecpappzi.wl-maz@kernel.org>
 <adc22b19-7dcc-4c38-9319-d979f1e3886a@quicinc.com>
 <868qfipfij.wl-maz@kernel.org>
Message-ID: <ef2d04e5-4687-4d2f-83a7-6cf9a7990ade@quicinc.com>

On Thu, Dec 04, 2025 at 01:01:40PM +0000, Marc Zyngier wrote:
> [dropping Ricardo, as his address bounces]
> 
> On Thu, 04 Dec 2025 10:36:12 +0000,
> Pavan Kondeti <pavan.kondeti at oss.qualcomm.com> wrote:
> > 
> > Hi Marc,
> > 
> > On Thu, Dec 04, 2025 at 09:15:29AM +0000, Marc Zyngier wrote:
> > > On Thu, 04 Dec 2025 04:07:15 +0000,
> > > Pavan Kondeti <pavan.kondeti at oss.qualcomm.com> wrote:
> > > > 
> > > > Hi
> > > > 
> > > > The pointer authentication feature (PAuth) is only supported on
> > > > 0-3 CPUs but it is not supported on 4-7 CPUS on QCS8300.
> > > 
> > > On what grounds? Hardware incompatibility? I seriously doubt it, since
> > > nobody glues pre-8.3 CPUs to anything more modern. Or, as I expect it,
> > > a firmware implemented with little understanding of what is required?
> > 
> > I don't know the answer to this question. I will talk to folks who may
> > know answer to this question and get back.
> > 
> > Can you please elaborate on the firmware part you are talking here? I
> > see that Linux runs at EL2 and AA64ISAR1 register values on CPU#0 (A78)
> > indicates that PAuth is supported but not for CPU#4 (A55). I am told, there
> > are no other controls outside EL2 (trap) to manipulate this feature. So,
> > I am assuming that this is indeed reflecting the HW.
> 
> Neither A78 nor A55 have PAuth. They are both firmly ARMv8.2 CPUs, and
> predate this functionality. So I guess that there are only two possible
> outcomes:
> 
> - either the FW is indeed not at fault, but that you have a *third*
>   type of CPU that is at least 8.3 in the mix
> 
> - or that you misidentified the CPUs that are on your system, they
>   have PAuth, and the firmware is borked
> 
> Which one is it?
> 

As Mark pointed out and MIDR indicates, it is A78C. sorry for the
confusion.

> > 
> > > 
> > > > The ARM64 cpufeature discovery code expects late CPUs to have
> > > > this feature if boot CPU feature has it since PAuth is enabled
> > > > early. When a conflict like this is detected, the late CPUs are
> > > > not allowed to boot. It is expected that system will continue
> > > > to be functional with CPUs with Pauth feature supported and enabled.
> > > > This is not a desired behavior in production.
> > > 
> > > What is even less desirable is to produce this sort of contraption.
> > > 
> > > > We started seeing this problem when Linux is booted in EL2. When Linux
> > > > is running under Gunyah (Type-1 hypervisor), Pointer Authentication
> > > > feature is hidden from EL1 via HCR_EL2.TID3. 
> > > > 
> > > > arm64.nopauth can be passed on kernel cmdline to disable the feature
> > > > in kernel so that all all CPUs can boot on QCS8300. I am told 
> > > > maintaining a custom kernel commandline per SoC in a Generic OS 
> > > > distribution is not recommended and asked to discuss the problem with
> > > > the comunity [1]
> > > 
> > > Well, you get to own the problem you have created for yourself. You
> > > build hardware/firmware that cannot run generic SW, and yet you want
> > > generic SW to run seamlessly on it. Spot the issue?
> > > 
> > > > This patch [2] from Catalin adds a devicetree property under memory {}
> > > > to disable MTE. I believe this work predates the id-reg override
> > > > mechanism. However, this made me think if workarounds like this can be
> > > > detected via devicetree, for example a property under cpu { } node.
> > > 
> > > Not only it predates it, but it also doesn't work in general. For a
> > > start, it is DT specific. How are you going to make that work for
> > > ACPI? I know you don't care, but I do.
> > 
> > Point taken. I understand that this does not fall under errata but is
> > there a possiblity to introduce an Errata targeting CPU#0 MIDR and
> > disabling the Pointer authentication? I understand that if there is
> > another Qualcomm SoC that exists with all CPUs supporting pointer
> > authentication with same MIDR, we may be disabling the feature but this
> > is something I can check internally.
> > 
> > > 
> > > > Given that what we put in `chosen { bootargs="" }` kernel under
> > > > respective SoC devicetree can be overridden by bootloader, should we
> > > > have a **sticky** cmdline to specify critical workarounds like this?
> > > > This would be more generic than introducing any new parameters.
> > > 
> > > You already have a way to have a sticky command-line, by building it
> > > into the kernel. Yes, I understand that this isn't what you want, but:
> > > 
> > > (1) a user should be allowed to pass the kernel command-line *they*
> > >     want, not what someone has decided for them
> > 
> > Agreed. This is what made me to ask the question. Should kernel have a
> > sticky command line which may have critical workarounds like this?
> 
> Absolutely *not*. You are not in charge of defining what is good for
> the user. If the user themselves want that, they have plenty of ways
> to achieve that particular goal already. Put it in the bootargs
> string, in the kernel build, in a grub config file, as a u-boot
> hack... There is an infinite number of choices already, and we don't
> need an extra one to hide how ugly their HW is.
> 
> > > (2) the generic mechanism exists, doesn't rely on additional firmware
> > >     specifications, and is used for a whole lot of other QC platforms
> > >     suffering from the same issue of broken firmware.  What are you
> > >     going to do for these?
> > 
> > The generic mechanism, you mean bootloader passing the kernel cmdline
> > with `arm64.nopauth`? or something else.
> 
> Exactly that. This is the mechanism by which we instruct the kernel
> not to use a particular feature if it can avoid it. It is easy to add,
> doesn't depend on new esoteric firmware interfaces, and is a constant
> reminder that you are dealing with stuff that isn't fit for purpose.
> 

Got it. 

Thanks,
Pavan


From robh at kernel.org  Thu Dec  4 09:09:09 2025
From: robh at kernel.org (Rob Herring)
Date: Thu, 4 Dec 2025 11:09:09 -0600
Subject: [PATCH] dt-bindings: pci: brcmstb: Add rp1-nexus node to fix DTC warning
In-Reply-To: <aLVePQRfU4IB1zK8@apocalypse>
References: <20250812085037.13517-1-andrea.porta@suse.com> <4fee3870-f9d5-48e3-a5be-6df581d3e296@kernel.org>
 <aKc5nMT1xXpY03ip@apocalypse> <e7875f70-2b79-48e0-a63b-caf6f1fd287b@kernel.org>
 <aLVePQRfU4IB1zK8@apocalypse>
Message-ID: <CAL_JsqJUzB71QdMcxJtNZ7raoPcK+SfTh7EVzGmk=syo8xLKQw@mail.gmail.com>

On Mon, Sep 1, 2025 at 3:48?AM Andrea della Porta <andrea.porta at suse.com> wrote:
>
> Hi Krzysztof,
>
> On 08:50 Fri 22 Aug     , Krzysztof Kozlowski wrote:
> > On 21/08/2025 17:22, Andrea della Porta wrote:
> > > Hi Krzysztof,
> > >
> > > On 10:55 Tue 12 Aug     , Krzysztof Kozlowski wrote:
> > >> On 12/08/2025 10:50, Andrea della Porta wrote:
> > >>> The devicetree compiler is complaining as follows:
> > >>>
> > >>> arch/arm64/boot/dts/broadcom/rp1-nexus.dtsi:3.11-14.3: Warning (unit_address_vs_reg): /axi/pcie at 1000120000/rp1_nexus: node has a reg or ranges property, but no unit name
> > >>> /home/andrea/linux-torvalds/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dtb: pcie at 1000120000: Unevaluated properties are not allowed ('rp1_nexus' was unexpected)
> > >>
> > >> Please trim the paths.
> > >
> > > Ack.
> > >
> > >>
> > >>>
> > >>> Add the optional node that fix this to the DT binding.
> > >>>
> > >>> Reported-by: kernel test robot <lkp at intel.com>
> > >>> Closes: https://lore.kernel.org/oe-kbuild-all/202506041952.baJDYBT4-lkp at intel.com/
> > >>> Signed-off-by: Andrea della Porta <andrea.porta at suse.com>
> > >>> ---
> > >>>  Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml | 9 +++++++++
> > >>>  1 file changed, 9 insertions(+)
> > >>>
> > >>> diff --git a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
> > >>> index 812ef5957cfc..7d8ba920b652 100644
> > >>> --- a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
> > >>> +++ b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
> > >>> @@ -126,6 +126,15 @@ required:
> > >>>  allOf:
> > >>>    - $ref: /schemas/pci/pci-host-bridge.yaml#
> > >>>    - $ref: /schemas/interrupt-controller/msi-controller.yaml#
> > >>> +  - if:
> > >>> +      properties:
> > >>> +        compatible:
> > >>> +          contains:
> > >>> +            const: brcm,bcm2712-pcie
> > >>> +    then:
> > >>> +      properties:
> > >>> +        rp1_nexus:
> > >>
> > >> No, you cannot document post-factum... This does not follow DTS coding
> > >> style.
> > >
> > > I think I didn't catch what you mean here: would that mean that
> > > we cannot resolve that warning since we cannot add anything to the
> > > binding?
> >
> > I meant, you cannot use a warning from the code you recently introduced
> > as a reason to use incorrect style.
> >
> > Fixing warning is of course fine and correct, but for the code recently
> > introduced and which bypassed ABI review it is basically like new review
> > of new ABI.
> >
> > This needs standard review practice, so you need to document WHY you
> > need such node. Warning is not the reason here why you are doing. If
> > this was part of original patchset, like it should have been, you would
> > not use some imaginary warning as reason, right?
> >
> > So provide reason why you need here this dedicated child, what is that
> > child representing.
>
> Ack.
>
> >
> > Otherwise I can suggest: drop the child and DTSO, this also solves the
> > warning...
>
> This would not fix the issue: it's the non overlay that needs the specific
> node. But I got the point, and we have a solution for that (see below).
>
> >
> > >
> > > Regarding rp1_nexus, you're right I guess it should be
> > > rp1-nexus as per DTS coding style.
> > >
> > >>
> > >> Also:
> > >>
> > >> Node names should be generic. See also an explanation and list of
> > >> examples (not exhaustive) in DT specification:
> > >> https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation
> > >
> > > In this case it could be difficult: we need to search for a DT node
> >
> > Search like in driver? That's wrong, you should be searching by compatible.
>
> Thanks for the hint. Searching by compatble is the solution.

No, it is not.

> >
> > > starting from the DT root and using generic names like pci at 0,0 or
> > > dev at 0,0 could possibly led to conflicts with other peripherals.
> > > That's why I chose a specific name.
> >
> > Dunno, depends what can be there, but you do not get a specific
> > (non-generic) device node name for a generic PCI device or endpoint.
>
> I would use 'port' instead of rp1-nexus. Would it work for you?

Do you still plan to fix this? This is broken far worse than just the node name.

The 'rp1_nexus' node is applied to the PCI host bridge. That's wrong
unless this is PCI rather than PCIe. There's the root port device in
between.

The clue that things are wrong are start in the driver here:

rp1_node = of_find_node_by_name(NULL, "rp1_nexus");
if (!rp1_node) {
  rp1_node = dev_of_node(dev);
  skip_ovl = false;
}

You should not need to do this nor care what the node name is. The PCI
core should have populated pdev->dev.of_node for you. If not, your DT
is wrong. Turn on CONFIG_PCI_DYNAMIC_OF_NODES and look at the
resulting PCI nodes. They should also match what the hierarchy looks
like with lspci. I don't recommend you rely on
CONFIG_PCI_DYNAMIC_OF_NODES, but statically populate the nodes in the
DT. First, CONFIG_PCI_DYNAMIC_OF_NODES is an under development thing
and I hope to get rid of the config option. Second, your case is
static (i.e. not a PCIe card in a slot) so there is no issue
hardcoding the DT.

As far as the node name, I don't care so much as long as the driver
doesn't care and you don't use '_' or 'pcie?' (that's for PCI
bridges).

And why do we have drivers/misc/rp1/rp1-pci.dtso and a .dtso in
arch/arm64? There should not be both.

Rob


From olteanv at gmail.com  Thu Dec  4 09:11:59 2025
From: olteanv at gmail.com (Vladimir Oltean)
Date: Thu, 4 Dec 2025 19:11:59 +0200
Subject: [PATCH v3 2/2] net: dsa: mt7530: Use GPIO polarity to generate
 correct reset sequence
In-Reply-To: <66d080f1-e989-451f-9d5e-34460e5eb1b0@kernel.org>
References: <0675b35f-217d-4261-9e3f-2eb24753d43c@lunn.ch>
 <20251130080731.ty2dlxaypxvodxiw@skbuf>
 <3fbc4e67-b931-421c-9d83-2214aaa2f6ed@lunn.ch>
 <0d85e1e6-ea75-4f20-aef1-90d446b4bfa1@kernel.org>
 <00f308a1-a4b1-4f20-8d8e-459ddf4c39b1@gmx.de>
 <aS7Zj3AFsSp2CTNv@makrotopia.org>
 <20251204131626.upw77jncqfwxydww@skbuf>
 <4170c560-1edd-4ff8-96af-a479063be4a5@kernel.org>
 <20251204160247.yz42mnxvzhxas5jc@skbuf>
 <66d080f1-e989-451f-9d5e-34460e5eb1b0@kernel.org>
Message-ID: <20251204171159.yy3nkvzttxecmhfo@skbuf>

On Thu, Dec 04, 2025 at 05:48:07PM +0100, Krzysztof Kozlowski wrote:
> Both are the same - inverter or NOT gate, same stuff. It is just
> connecting wire to pull up, not actual component on the board (although
> one could make and buy such component as well...). We never describe
> these inverters in the DTS, these are just too trivial circuits, thus
> the final GPIO_ACTIVE_XXX should already include whatever is on the wire
> between SoC and device.

Please read what Andrew said:
https://lore.kernel.org/netdev/3fbc4e67-b931-421c-9d83-2214aaa2f6ed at lunn.ch/

  Assuming there is not a NOT gate placed between the GPIO and the reset
  pin, because the board designer decided to do that for some reason?
                   ~~~~~~~~~~~~~~

You two are *not* talking about the same thing. I dismissed the
probability of there being a NOT gate in the form of a discrete chip on
the PCB, *exactly because* you can most likely invert the signal in the
GPIO pin itself.


From Frank.li at nxp.com  Thu Dec  4 09:17:41 2025
From: Frank.li at nxp.com (Frank Li)
Date: Thu, 4 Dec 2025 12:17:41 -0500
Subject: [PATCH v2 2/3] remoteproc: imx_dsp_rproc: Rename macro to
 reflect multiple contexts
In-Reply-To: <20251204122825.756106-2-iuliana.prodan@oss.nxp.com>
References: <20251204122825.756106-1-iuliana.prodan@oss.nxp.com>
 <20251204122825.756106-2-iuliana.prodan@oss.nxp.com>
Message-ID: <aTHCNeb7eXpttUwp@lizhi-Precision-Tower-5810>

On Thu, Dec 04, 2025 at 02:28:24PM +0200, Iuliana Prodan (OSS) wrote:
> From: Iuliana Prodan <iuliana.prodan at nxp.com>
>
> Rename WAIT_FW_READY to WAIT_FW_CONFIRMATION and FEATURE_DONT_WAIT_FW_READY
> to FEATURE_SKIP_FW_CONFIRMATION. This way, the term CONFIRMATION covers:
> - waiting for firmware to confirm it is ready to start;
> - waiting for any other confirmation from firmware.
>
> Signed-off-by: Iuliana Prodan <iuliana.prodan at nxp.com>
> ---

Reviewed-by: Frank Li <Frank.Li at nxp.com>

> Changes since v1:
> - New commit
> ---
>  drivers/remoteproc/imx_dsp_rproc.c | 22 +++++++++++-----------
>  1 file changed, 11 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c
> index f51deaacc700..1f3a35756769 100644
> --- a/drivers/remoteproc/imx_dsp_rproc.c
> +++ b/drivers/remoteproc/imx_dsp_rproc.c
> @@ -38,15 +38,15 @@ MODULE_PARM_DESC(no_mailboxes,
>
>  /* Flag indicating that the remote is up and running */
>  #define REMOTE_IS_READY				BIT(0)
> -/* Flag indicating that the host should wait for a firmware-ready response */
> -#define WAIT_FW_READY				BIT(1)
> +/* Flag indicating that the host should wait for a firmware-confirmation response */
> +#define WAIT_FW_CONFIRMATION				BIT(1)
>  #define REMOTE_READY_WAIT_MAX_RETRIES		500
>
>  /*
>   * This flag is set in the DSP resource table's features field to indicate
> - * that the firmware requires the host NOT to wait for a FW_READY response.
> + * that the firmware requires the host NOT to wait for a FW_CONFIRMATION response.
>   */
> -#define FEATURE_DONT_WAIT_FW_READY		BIT(0)
> +#define FEATURE_SKIP_FW_CONFIRMATION		BIT(0)
>
>  /* att flags */
>  /* DSP own area */
> @@ -287,7 +287,7 @@ static int imx_dsp_rproc_ready(struct rproc *rproc)
>   * @avail: available space in the resource table
>   *
>   * Parse the DSP-specific resource entry and update flags accordingly.
> - * If the WAIT_FW_READY feature is set, the host must wait for the firmware
> + * If the WAIT_FW_CONFIRMATION feature is set, the host must wait for the firmware
>   * to signal readiness before proceeding with execution.
>   *
>   * Return: RSC_HANDLED if processed successfully, RSC_IGNORED otherwise.
> @@ -322,7 +322,7 @@ static int imx_dsp_rproc_handle_rsc(struct rproc *rproc, u32 rsc_type,
>
>  	/*
>  	 * For now, in struct fw_rsc_imx_dsp, version 0,
> -	 * only FEATURE_DONT_WAIT_FW_READY is valid.
> +	 * only FEATURE_SKIP_FW_CONFIRMATION is valid.
>  	 *
>  	 * When adding new features, please upgrade version.
>  	 */
> @@ -332,8 +332,8 @@ static int imx_dsp_rproc_handle_rsc(struct rproc *rproc, u32 rsc_type,
>  		return RSC_IGNORED;
>  	}
>
> -	if (imx_dsp_rsc->features & FEATURE_DONT_WAIT_FW_READY)
> -		priv->flags &= ~WAIT_FW_READY;
> +	if (imx_dsp_rsc->features & FEATURE_SKIP_FW_CONFIRMATION)
> +		priv->flags &= ~WAIT_FW_CONFIRMATION;
>
>  	return RSC_HANDLED;
>  }
> @@ -385,7 +385,7 @@ static int imx_dsp_rproc_start(struct rproc *rproc)
>  		return ret;
>  	}
>
> -	if (priv->flags & WAIT_FW_READY)
> +	if (priv->flags & WAIT_FW_CONFIRMATION)
>  		return imx_dsp_rproc_ready(rproc);
>
>  	return 0;
> @@ -1131,8 +1131,8 @@ static int imx_dsp_rproc_probe(struct platform_device *pdev)
>  	priv = rproc->priv;
>  	priv->rproc = rproc;
>  	priv->dsp_dcfg = dsp_dcfg;
> -	/* By default, host waits for fw_ready reply */
> -	priv->flags |= WAIT_FW_READY;
> +	/* By default, host waits for fw_confirmation reply */
> +	priv->flags |= WAIT_FW_CONFIRMATION;
>
>  	if (no_mailboxes)
>  		imx_dsp_rproc_mbox_init = imx_dsp_rproc_mbox_no_alloc;
> --
> 2.25.1
>


From Frank.li at nxp.com  Thu Dec  4 09:20:06 2025
From: Frank.li at nxp.com (Frank Li)
Date: Thu, 4 Dec 2025 12:20:06 -0500
Subject: [PATCH v2 3/3] remoteproc: imx_dsp_rproc: Wait for suspend ACK
 only if WAIT_FW_CONFIRMATION is set
In-Reply-To: <20251204122825.756106-3-iuliana.prodan@oss.nxp.com>
References: <20251204122825.756106-1-iuliana.prodan@oss.nxp.com>
 <20251204122825.756106-3-iuliana.prodan@oss.nxp.com>
Message-ID: <aTHCxkHUKyLLurzi@lizhi-Precision-Tower-5810>

On Thu, Dec 04, 2025 at 02:28:25PM +0200, Iuliana Prodan (OSS) wrote:
> From: Iuliana Prodan <iuliana.prodan at nxp.com>
>
> The DSP suspend path currently waits unconditionally for a suspend ack
> from the firmware. This breaks firmwares that do not implement the
> mailbox-based CONFIRMATION handshake, as the DSP never responds and
> system suspend fails with -EBUSY.
>
> The driver already uses the WAIT_FW_CONFIRMATION flag to indicate that
> the firmware supports the CONFIRMATION handshake at boot. Apply the same
> logic during suspend: only send the suspend message and wait for the
> suspend ack when the firmware is expected to support it.
>
> Signed-off-by: Iuliana Prodan <iuliana.prodan at nxp.com>
> ---

Reviewed-by: Frank Li <Frank.Li at nxp.com>

> Changes since v1:
> - Moved confirmation check earlier to avoid sending the message when
> FEATURE_SKIP_FW_CONFIRMATION is set, since RP_MBOX_SUSPEND_SYSTEM is
> not handled on the remote side.
> ---
>  drivers/remoteproc/imx_dsp_rproc.c | 6 ++++++
>  1 file changed, 6 insertions(+)
>
> diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c
> index 1f3a35756769..d03017d6b214 100644
> --- a/drivers/remoteproc/imx_dsp_rproc.c
> +++ b/drivers/remoteproc/imx_dsp_rproc.c
> @@ -1251,6 +1251,12 @@ static int imx_dsp_suspend(struct device *dev)
>  		goto out;
>  	}
>
> +	/* No fw confirmation expected, so trigger PM runtime suspend */
> +	if (!(priv->flags & WAIT_FW_CONFIRMATION)) {
> +		dev_dbg(dev, "No FW_CONFIRMATION needed, suspend directly.\n");
> +		goto out;
> +	}
> +
>  	reinit_completion(&priv->pm_comp);
>
>  	/* Tell DSP that suspend is happening */
> --
> 2.25.1
>


From Frank.li at nxp.com  Thu Dec  4 09:23:21 2025
From: Frank.li at nxp.com (Frank Li)
Date: Thu, 4 Dec 2025 12:23:21 -0500
Subject: [PATCH v3 1/3] media: v4l2-mem2mem: Add a kref to the
 v4l2_m2m_dev structure
In-Reply-To: <20251204090813.595-1-ming.qian@oss.nxp.com>
References: <20251204090813.595-1-ming.qian@oss.nxp.com>
Message-ID: <aTHDiVI6ZB3E7Anh@lizhi-Precision-Tower-5810>

On Thu, Dec 04, 2025 at 05:08:09PM +0800, ming.qian at oss.nxp.com wrote:
> From: Nicolas Dufresne <nicolas.dufresne at collabora.com>
>
> Adding a reference count to the v4l2_m2m_dev structure allow safely
> sharing it across multiple hardware nodes. This can be used to prevent
> running jobs concurrently on m2m cores that have some internal resource
> sharing.
>
> Signed-off-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

Also need your s-o-b, or just said refer to other thread if it already
posted.

Frank
> ---
>  drivers/media/v4l2-core/v4l2-mem2mem.c | 23 +++++++++++++++++++++++
>  include/media/v4l2-mem2mem.h           | 21 +++++++++++++++++++++
>  2 files changed, 44 insertions(+)
>
> diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c
> index fec93c1a9231..ae0de54d4c3e 100644
> --- a/drivers/media/v4l2-core/v4l2-mem2mem.c
> +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
> @@ -90,6 +90,7 @@ static const char * const m2m_entity_name[] = {
>   * @job_work:		worker to run queued jobs.
>   * @job_queue_flags:	flags of the queue status, %QUEUE_PAUSED.
>   * @m2m_ops:		driver callbacks
> + * @kref:		device reference count
>   */
>  struct v4l2_m2m_dev {
>  	struct v4l2_m2m_ctx	*curr_ctx;
> @@ -109,6 +110,8 @@ struct v4l2_m2m_dev {
>  	unsigned long		job_queue_flags;
>
>  	const struct v4l2_m2m_ops *m2m_ops;
> +
> +	struct kref kref;
>  };
>
>  static struct v4l2_m2m_queue_ctx *get_queue_ctx(struct v4l2_m2m_ctx *m2m_ctx,
> @@ -1200,6 +1203,7 @@ struct v4l2_m2m_dev *v4l2_m2m_init(const struct v4l2_m2m_ops *m2m_ops)
>  	INIT_LIST_HEAD(&m2m_dev->job_queue);
>  	spin_lock_init(&m2m_dev->job_spinlock);
>  	INIT_WORK(&m2m_dev->job_work, v4l2_m2m_device_run_work);
> +	kref_init(&m2m_dev->kref);
>
>  	return m2m_dev;
>  }
> @@ -1211,6 +1215,25 @@ void v4l2_m2m_release(struct v4l2_m2m_dev *m2m_dev)
>  }
>  EXPORT_SYMBOL_GPL(v4l2_m2m_release);
>
> +void v4l2_m2m_get(struct v4l2_m2m_dev *m2m_dev)
> +{
> +	kref_get(&m2m_dev->kref);
> +}
> +EXPORT_SYMBOL_GPL(v4l2_m2m_get);
> +
> +static void v4l2_m2m_release_from_kref(struct kref *kref)
> +{
> +	struct v4l2_m2m_dev *m2m_dev = container_of(kref, struct v4l2_m2m_dev, kref);
> +
> +	v4l2_m2m_release(m2m_dev);
> +}
> +
> +void v4l2_m2m_put(struct v4l2_m2m_dev *m2m_dev)
> +{
> +	kref_put(&m2m_dev->kref, v4l2_m2m_release_from_kref);
> +}
> +EXPORT_SYMBOL_GPL(v4l2_m2m_put);
> +
>  struct v4l2_m2m_ctx *v4l2_m2m_ctx_init(struct v4l2_m2m_dev *m2m_dev,
>  		void *drv_priv,
>  		int (*queue_init)(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq))
> diff --git a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h
> index bf6a09a04dcf..ca295c660c7f 100644
> --- a/include/media/v4l2-mem2mem.h
> +++ b/include/media/v4l2-mem2mem.h
> @@ -547,6 +547,27 @@ v4l2_m2m_register_media_controller(struct v4l2_m2m_dev *m2m_dev,
>   */
>  void v4l2_m2m_release(struct v4l2_m2m_dev *m2m_dev);
>
> +/**
> + * v4l2_m2m_get() - take a reference to the m2m_dev structure
> + *
> + * @m2m_dev: opaque pointer to the internal data to handle M2M context
> + *
> + * This is used to share the M2M device across multiple devices. This
> + * can be used to avoid scheduling two hardware nodes concurrently.
> + */
> +void v4l2_m2m_get(struct v4l2_m2m_dev *m2m_dev);
> +
> +/**
> + * v4l2_m2m_put() - remove a reference to the m2m_dev structure
> + *
> + * @m2m_dev: opaque pointer to the internal data to handle M2M context
> + *
> + * Once the M2M device have no more references, v4l2_m2m_realse() will be
> + * called automatically. Users of this method should never call
> + * v4l2_m2m_release() directly. See v4l2_m2m_get() for more details.
> + */
> +void v4l2_m2m_put(struct v4l2_m2m_dev *m2m_dev);
> +
>  /**
>   * v4l2_m2m_ctx_init() - allocate and initialize a m2m context
>   *
> --
> 2.52.0
>


From krzk at kernel.org  Thu Dec  4 09:23:48 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 4 Dec 2025 18:23:48 +0100
Subject: [PATCH v3 2/2] net: dsa: mt7530: Use GPIO polarity to generate
 correct reset sequence
In-Reply-To: <20251204171159.yy3nkvzttxecmhfo@skbuf>
References: <0675b35f-217d-4261-9e3f-2eb24753d43c@lunn.ch>
 <20251130080731.ty2dlxaypxvodxiw@skbuf>
 <3fbc4e67-b931-421c-9d83-2214aaa2f6ed@lunn.ch>
 <0d85e1e6-ea75-4f20-aef1-90d446b4bfa1@kernel.org>
 <00f308a1-a4b1-4f20-8d8e-459ddf4c39b1@gmx.de>
 <aS7Zj3AFsSp2CTNv@makrotopia.org> <20251204131626.upw77jncqfwxydww@skbuf>
 <4170c560-1edd-4ff8-96af-a479063be4a5@kernel.org>
 <20251204160247.yz42mnxvzhxas5jc@skbuf>
 <66d080f1-e989-451f-9d5e-34460e5eb1b0@kernel.org>
 <20251204171159.yy3nkvzttxecmhfo@skbuf>
Message-ID: <178afbeb-168f-4765-bb0b-fad0bcd29382@kernel.org>

On 04/12/2025 18:11, Vladimir Oltean wrote:
> On Thu, Dec 04, 2025 at 05:48:07PM +0100, Krzysztof Kozlowski wrote:
>> Both are the same - inverter or NOT gate, same stuff. It is just
>> connecting wire to pull up, not actual component on the board (although
>> one could make and buy such component as well...). We never describe
>> these inverters in the DTS, these are just too trivial circuits, thus
>> the final GPIO_ACTIVE_XXX should already include whatever is on the wire
>> between SoC and device.
> 
> Please read what Andrew said:
> https://lore.kernel.org/netdev/3fbc4e67-b931-421c-9d83-2214aaa2f6ed at lunn.ch/
> 
>   Assuming there is not a NOT gate placed between the GPIO and the reset
>   pin, because the board designer decided to do that for some reason?
>                    ~~~~~~~~~~~~~~
> 
> You two are *not* talking about the same thing. I dismissed the


It's the same thing. NOT gate is just pulling some pin down or up.

> probability of there being a NOT gate in the form of a discrete chip on

We do not describe NOT gates as discreet chips. I don't think anyone
actually places something as NOT gate. It's logical NOT gate, but on
circuit it is just pull up/down as I said multiple times. The pull +
resistor is the "NOT gate".

It's so easy and that's why it is potentially so common design.

> the PCB, *exactly because* you can most likely invert the signal in the
> GPIO pin itself.



Best regards,
Krzysztof


From Frank.li at nxp.com  Thu Dec  4 09:24:16 2025
From: Frank.li at nxp.com (Frank Li)
Date: Thu, 4 Dec 2025 12:24:16 -0500
Subject: [PATCH v3 2/3] pmdomain: imx8m-blk-ctrl: Remove separate rst and
 clk mask for 8mq vpu
In-Reply-To: <20251204090813.595-2-ming.qian@oss.nxp.com>
References: <20251204090813.595-1-ming.qian@oss.nxp.com>
 <20251204090813.595-2-ming.qian@oss.nxp.com>
Message-ID: <aTHDwHKcNnesAjKP@lizhi-Precision-Tower-5810>

On Thu, Dec 04, 2025 at 05:08:10PM +0800, ming.qian at oss.nxp.com wrote:
> From: Ming Qian <ming.qian at oss.nxp.com>
>
> For i.MX8MQ platform, the ADB in the VPUMIX domain has no separate reset
> and clock enable bits, but is ungated and reset together with the VPUs.
> So we can't reset G1 or G2 separately, it may led to the system hang.
> Remove rst_mask and clk_mask of imx8mq_vpu_blk_ctl_domain_data.
> Let imx8mq_vpu_power_notifier() do really vpu reset.
>
> Fixes: 608d7c325e85 ("soc: imx: imx8m-blk-ctrl: add i.MX8MQ VPU blk-ctrl")
> Signed-off-by: Ming Qian <ming.qian at oss.nxp.com>
> Reviewed-by: Benjamin Gaignard <benjamin.gaignard at collabora.com>
> Reviewed-by: Peng Fan <peng.fan at nxp.com>

Reviewed-by: Frank Li <Frank.Li at nxp.com>

> ---
> v3
> - Add some comments
> v2
> - Update commit message
>
>  drivers/pmdomain/imx/imx8m-blk-ctrl.c | 11 +++++++----
>  1 file changed, 7 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/pmdomain/imx/imx8m-blk-ctrl.c b/drivers/pmdomain/imx/imx8m-blk-ctrl.c
> index 5c83e5599f1e..74bf4936991d 100644
> --- a/drivers/pmdomain/imx/imx8m-blk-ctrl.c
> +++ b/drivers/pmdomain/imx/imx8m-blk-ctrl.c
> @@ -846,22 +846,25 @@ static int imx8mq_vpu_power_notifier(struct notifier_block *nb,
>  	return NOTIFY_OK;
>  }
>
> +/*
> + * For i.MX8MQ, the ADB in the VPUMIX domain has no separate reset and clock
> + * enable bits, but is ungated and reset together with the VPUs.
> + * Resetting G1 or G2 separately may led to system hang.
> + * Remove the rst_mask and clk_mask from the domain data of G1 and G2,
> + * Let imx8mq_vpu_power_notifier() do really vpu reset.
> + */
>  static const struct imx8m_blk_ctrl_domain_data imx8mq_vpu_blk_ctl_domain_data[] = {
>  	[IMX8MQ_VPUBLK_PD_G1] = {
>  		.name = "vpublk-g1",
>  		.clk_names = (const char *[]){ "g1", },
>  		.num_clks = 1,
>  		.gpc_name = "g1",
> -		.rst_mask = BIT(1),
> -		.clk_mask = BIT(1),
>  	},
>  	[IMX8MQ_VPUBLK_PD_G2] = {
>  		.name = "vpublk-g2",
>  		.clk_names = (const char *[]){ "g2", },
>  		.num_clks = 1,
>  		.gpc_name = "g2",
> -		.rst_mask = BIT(0),
> -		.clk_mask = BIT(0),
>  	},
>  };
>
> --
> 2.52.0
>


From krzk at kernel.org  Thu Dec  4 09:32:23 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 4 Dec 2025 18:32:23 +0100
Subject: [PATCH v3 2/2] net: dsa: mt7530: Use GPIO polarity to generate
 correct reset sequence
In-Reply-To: <178afbeb-168f-4765-bb0b-fad0bcd29382@kernel.org>
References: <0675b35f-217d-4261-9e3f-2eb24753d43c@lunn.ch>
 <20251130080731.ty2dlxaypxvodxiw@skbuf>
 <3fbc4e67-b931-421c-9d83-2214aaa2f6ed@lunn.ch>
 <0d85e1e6-ea75-4f20-aef1-90d446b4bfa1@kernel.org>
 <00f308a1-a4b1-4f20-8d8e-459ddf4c39b1@gmx.de>
 <aS7Zj3AFsSp2CTNv@makrotopia.org> <20251204131626.upw77jncqfwxydww@skbuf>
 <4170c560-1edd-4ff8-96af-a479063be4a5@kernel.org>
 <20251204160247.yz42mnxvzhxas5jc@skbuf>
 <66d080f1-e989-451f-9d5e-34460e5eb1b0@kernel.org>
 <20251204171159.yy3nkvzttxecmhfo@skbuf>
 <178afbeb-168f-4765-bb0b-fad0bcd29382@kernel.org>
Message-ID: <9f7da6ae-9e3e-442f-a203-28a8881dbe0f@kernel.org>

On 04/12/2025 18:23, Krzysztof Kozlowski wrote:
> On 04/12/2025 18:11, Vladimir Oltean wrote:
>> On Thu, Dec 04, 2025 at 05:48:07PM +0100, Krzysztof Kozlowski wrote:
>>> Both are the same - inverter or NOT gate, same stuff. It is just
>>> connecting wire to pull up, not actual component on the board (although
>>> one could make and buy such component as well...). We never describe
>>> these inverters in the DTS, these are just too trivial circuits, thus
>>> the final GPIO_ACTIVE_XXX should already include whatever is on the wire
>>> between SoC and device.
>>
>> Please read what Andrew said:
>> https://lore.kernel.org/netdev/3fbc4e67-b931-421c-9d83-2214aaa2f6ed at lunn.ch/
>>
>>   Assuming there is not a NOT gate placed between the GPIO and the reset
>>   pin, because the board designer decided to do that for some reason?
>>                    ~~~~~~~~~~~~~~
>>
>> You two are *not* talking about the same thing. I dismissed the
> 
> 
> It's the same thing. NOT gate is just pulling some pin down or up.

Although transistor would be still needed, so indeed that's still a bit
more than a wire and resistor as I implied.

It looks like:
https://www.electronics-tutorials.ws/wp-content/uploads/2018/05/logic-log47.gif


> 
>> probability of there being a NOT gate in the form of a discrete chip on
> 
> We do not describe NOT gates as discreet chips. I don't think anyone
> actually places something as NOT gate. It's logical NOT gate, but on
> circuit it is just pull up/down as I said multiple times. The pull +
> resistor is the "NOT gate".
> 
> It's so easy and that's why it is potentially so common design.


We still do not describe transistors in DTS. We do not describe NOT
gates. The final flag should include that as I said.


Best regards,
Krzysztof


From Frank.li at nxp.com  Thu Dec  4 09:34:31 2025
From: Frank.li at nxp.com (Frank Li)
Date: Thu, 4 Dec 2025 12:34:31 -0500
Subject: [PATCH v3 3/3] media: verisilicon: Avoid G2 bus error while
 decoding H.264 and HEVC
In-Reply-To: <20251204090813.595-3-ming.qian@oss.nxp.com>
References: <20251204090813.595-1-ming.qian@oss.nxp.com>
 <20251204090813.595-3-ming.qian@oss.nxp.com>
Message-ID: <aTHGJzVKa7PbEifJ@lizhi-Precision-Tower-5810>

On Thu, Dec 04, 2025 at 05:08:11PM +0800, ming.qian at oss.nxp.com wrote:
> From: Ming Qian <ming.qian at oss.nxp.com>
>
> For the i.MX8MQ platform, there is a hardware limitation: the g1 VPU and
> g2 VPU cannot decode simultaneously; otherwise, it will cause below bus
> error and produce corrupted pictures, even potentially lead to system hang.
>
> [  110.527986] hantro-vpu 38310000.video-codec: frame decode timed out.
> [  110.583517] hantro-vpu 38310000.video-codec: bus error detected.
>
> Therefore, it is necessary to ensure that g1 and g2 operate alternately.
> This allows for successful multi-instance decoding of H.264 and HEVC.
>
> To achieve this, we can have g1 and g2 share the same v4l2_m2m_dev, and
> then the v4l2_m2m_dev can handle the scheduling.

To achieve this, g1 and g2 share the same v4l2_m2m_dev, ...

>
> Fixes: cb5dd5a0fa518 ("media: hantro: Introduce G2/HEVC decoder")
> Co-developed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
> Signed-off-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
> Signed-off-by: Ming Qian <ming.qian at oss.nxp.com>
> ---
> v3
> - Apply Nicolas's approach that use an array list to define the shared
>   devices
>
> v2
> - Abandon the waiting approach.
> - Switch to a shared v4l2_m2m_dev solution.
>
>  drivers/media/platform/verisilicon/hantro.h   |  2 +
>  .../media/platform/verisilicon/hantro_drv.c   | 42 +++++++++++++++++--
>  .../media/platform/verisilicon/imx8m_vpu_hw.c |  8 ++++
>  3 files changed, 49 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/media/platform/verisilicon/hantro.h b/drivers/media/platform/verisilicon/hantro.h
> index e0fdc4535b2d..0353de154a1e 100644
> --- a/drivers/media/platform/verisilicon/hantro.h
> +++ b/drivers/media/platform/verisilicon/hantro.h
> @@ -77,6 +77,7 @@ struct hantro_irq {
>   * @double_buffer:		core needs double buffering
>   * @legacy_regs:		core uses legacy register set
>   * @late_postproc:		postproc must be set up at the end of the job
> + * @shared_devices:		an array of device ids that cannot run concurrently
>   */
>  struct hantro_variant {
>  	unsigned int enc_offset;
> @@ -101,6 +102,7 @@ struct hantro_variant {
>  	unsigned int double_buffer : 1;
>  	unsigned int legacy_regs : 1;
>  	unsigned int late_postproc : 1;
> +	const struct of_device_id *shared_devices;
>  };
>
>  /**
> diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c
> index 60b95b5d8565..70160eaf3d15 100644
> --- a/drivers/media/platform/verisilicon/hantro_drv.c
> +++ b/drivers/media/platform/verisilicon/hantro_drv.c
> @@ -13,6 +13,7 @@
>  #include <linux/clk.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
> +#include <linux/of_platform.h>
>  #include <linux/platform_device.h>
>  #include <linux/pm.h>
>  #include <linux/pm_runtime.h>
> @@ -1035,6 +1036,41 @@ static int hantro_disable_multicore(struct hantro_dev *vpu)
>  	return 0;
>  }
>
> +static struct v4l2_m2m_dev *hantro_get_v4l2_m2m_dev(struct hantro_dev *vpu)
> +{
> +	struct device_node *node;
> +	struct hantro_dev *shared_vpu;
> +
> +	if (!vpu->variant || !vpu->variant->shared_devices)
> +		goto init_new_m2m_dev;

I found only use shared_devices here, how to  ensure that g1 and g2 operate
alternately by using shared_devices?

Frank

> +
> +	for_each_matching_node(node, vpu->variant->shared_devices) {
> +		struct platform_device *pdev;
> +		struct v4l2_m2m_dev *m2m_dev;
> +
> +		pdev = of_find_device_by_node(node);
> +		of_node_put(node);
> +
> +		if (!pdev)
> +			continue;
> +
> +		shared_vpu = platform_get_drvdata(pdev);
> +		if (IS_ERR_OR_NULL(shared_vpu) || shared_vpu == vpu) {
> +			platform_device_put(pdev);
> +			continue;
> +		}
> +
> +		v4l2_m2m_get(shared_vpu->m2m_dev);
> +		m2m_dev = shared_vpu->m2m_dev;
> +		platform_device_put(pdev);
> +
> +		return m2m_dev;
> +	}
> +
> +init_new_m2m_dev:
> +	return v4l2_m2m_init(&vpu_m2m_ops);
> +}
> +
>  static int hantro_probe(struct platform_device *pdev)
>  {
>  	const struct of_device_id *match;
> @@ -1186,7 +1222,7 @@ static int hantro_probe(struct platform_device *pdev)
>  	}
>  	platform_set_drvdata(pdev, vpu);
>
> -	vpu->m2m_dev = v4l2_m2m_init(&vpu_m2m_ops);
> +	vpu->m2m_dev = hantro_get_v4l2_m2m_dev(vpu);
>  	if (IS_ERR(vpu->m2m_dev)) {
>  		v4l2_err(&vpu->v4l2_dev, "Failed to init mem2mem device\n");
>  		ret = PTR_ERR(vpu->m2m_dev);
> @@ -1225,7 +1261,7 @@ static int hantro_probe(struct platform_device *pdev)
>  	hantro_remove_enc_func(vpu);
>  err_m2m_rel:
>  	media_device_cleanup(&vpu->mdev);
> -	v4l2_m2m_release(vpu->m2m_dev);
> +	v4l2_m2m_put(vpu->m2m_dev);
>  err_v4l2_unreg:
>  	v4l2_device_unregister(&vpu->v4l2_dev);
>  err_clk_unprepare:
> @@ -1248,7 +1284,7 @@ static void hantro_remove(struct platform_device *pdev)
>  	hantro_remove_dec_func(vpu);
>  	hantro_remove_enc_func(vpu);
>  	media_device_cleanup(&vpu->mdev);
> -	v4l2_m2m_release(vpu->m2m_dev);
> +	v4l2_m2m_put(vpu->m2m_dev);
>  	v4l2_device_unregister(&vpu->v4l2_dev);
>  	clk_bulk_unprepare(vpu->variant->num_clocks, vpu->clocks);
>  	reset_control_assert(vpu->resets);
> diff --git a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
> index 5be0e2e76882..6f8e43b7f157 100644
> --- a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
> +++ b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
> @@ -343,6 +343,12 @@ const struct hantro_variant imx8mq_vpu_variant = {
>  	.num_regs = ARRAY_SIZE(imx8mq_reg_names)
>  };
>
> +static const struct of_device_id imx8mq_vpu_shared_resources[] __initconst = {
> +	{ .compatible = "nxp,imx8mq-vpu-g1", },
> +	{ .compatible = "nxp,imx8mq-vpu-g2", },
> +	{ /* sentinel */ }
> +};
> +
>  const struct hantro_variant imx8mq_vpu_g1_variant = {
>  	.dec_fmts = imx8m_vpu_dec_fmts,
>  	.num_dec_fmts = ARRAY_SIZE(imx8m_vpu_dec_fmts),
> @@ -356,6 +362,7 @@ const struct hantro_variant imx8mq_vpu_g1_variant = {
>  	.num_irqs = ARRAY_SIZE(imx8mq_irqs),
>  	.clk_names = imx8mq_g1_clk_names,
>  	.num_clocks = ARRAY_SIZE(imx8mq_g1_clk_names),
> +	.shared_devices = imx8mq_vpu_shared_resources,
>  };
>
>  const struct hantro_variant imx8mq_vpu_g2_variant = {
> @@ -371,6 +378,7 @@ const struct hantro_variant imx8mq_vpu_g2_variant = {
>  	.num_irqs = ARRAY_SIZE(imx8mq_g2_irqs),
>  	.clk_names = imx8mq_g2_clk_names,
>  	.num_clocks = ARRAY_SIZE(imx8mq_g2_clk_names),
> +	.shared_devices = imx8mq_vpu_shared_resources,
>  };
>
>  const struct hantro_variant imx8mm_vpu_g1_variant = {
> --
> 2.52.0
>


From linux at armlinux.org.uk  Thu Dec  4 09:45:30 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Thu, 4 Dec 2025 17:45:30 +0000
Subject: [PATCH v3 2/2] net: dsa: mt7530: Use GPIO polarity to generate
 correct reset sequence
In-Reply-To: <178afbeb-168f-4765-bb0b-fad0bcd29382@kernel.org>
References: <3fbc4e67-b931-421c-9d83-2214aaa2f6ed@lunn.ch>
 <0d85e1e6-ea75-4f20-aef1-90d446b4bfa1@kernel.org>
 <00f308a1-a4b1-4f20-8d8e-459ddf4c39b1@gmx.de>
 <aS7Zj3AFsSp2CTNv@makrotopia.org>
 <20251204131626.upw77jncqfwxydww@skbuf>
 <4170c560-1edd-4ff8-96af-a479063be4a5@kernel.org>
 <20251204160247.yz42mnxvzhxas5jc@skbuf>
 <66d080f1-e989-451f-9d5e-34460e5eb1b0@kernel.org>
 <20251204171159.yy3nkvzttxecmhfo@skbuf>
 <178afbeb-168f-4765-bb0b-fad0bcd29382@kernel.org>
Message-ID: <aTHIulPW055AyLW_@shell.armlinux.org.uk>

On Thu, Dec 04, 2025 at 06:23:48PM +0100, Krzysztof Kozlowski wrote:
> On 04/12/2025 18:11, Vladimir Oltean wrote:
> > You two are *not* talking about the same thing. I dismissed the
> 
> It's the same thing. NOT gate is just pulling some pin down or up.
> 
> > probability of there being a NOT gate in the form of a discrete chip on
> 
> We do not describe NOT gates as discreet chips. I don't think anyone
> actually places something as NOT gate. It's logical NOT gate, but on
> circuit it is just pull up/down as I said multiple times. The pull +
> resistor is the "NOT gate".

You can get SOT-23 packages that are NOT gates. E.g.
https://www.ti.com/lit/ds/symlink/sn74ahc1g04.pdf?ts=1764851465989

This is a real NOT gate - it's absolute max ratings state that it
can source/sink up to 25mA through its output. So no external
resistor required.

What you describe sounds to me more like a normal transistor though.

Irrespective of this, the exact nature of a device that inverts the
level of a reset signal in the path between a GPIO pin and a device
is irrelevant. What matters is whether there is or is not such a
device.

So, can we stop splitting hairs about what a NOT gate is in this
discussion? It's irrelevant.

> It's so easy and that's why it is potentially so common design.

Do you have any real evidence of this when used with a GPIO pin for
a reset input?

It would make sense if a single GPIO pin is used for resetting
several devices, some of them with an active-high reset input and
others with active-low.

What matters for a GPIO pin used to source a reset signal is "what
is the active level at the GPIO pin for the reset to be asserted to
the connected device(s)."

If we have a device that requires an active-low reset input, but there
is some form of inversion in the path to that input from a GPIO, then
the GPIO _should_ be marked active-high. If the same active-low reset
input is connected directly to a GPIO, the GPIO _should_ be marked as
active-low. Thus, to assert reset, writing '1' through
gpiod_set_value() _should_ assert the reset input on the target device
in both cases.

This is why gpiolib supports software inversion - so software engineers
can think in terms of positive non-inverted logic when programming
GPIOs.

Sadly, we keep having people mark active-low signals as "active high"
in DT, and then have to write '0' to assert the signal. These people
basically don't understand electronics and/or our GPIO model.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From derek.foreman at collabora.com  Thu Dec  4 09:48:17 2025
From: derek.foreman at collabora.com (Derek Foreman)
Date: Thu, 4 Dec 2025 17:48:17 +0000
Subject: [PATCH 1/2] phy: rockchip: samsung-hdptx: Pre-compute HDMI PLL
 config for 461.10125 MHz output
In-Reply-To: <20251204-phy-hdptx-pll-fix-v1-1-d94fd6cfd59b@collabora.com>
References: <20251204-phy-hdptx-pll-fix-v1-0-d94fd6cfd59b@collabora.com>
 <20251204-phy-hdptx-pll-fix-v1-1-d94fd6cfd59b@collabora.com>
Message-ID: <0102019aea7aa358-97e812cb-8010-4699-9a0e-ec041d6d9316-000000@eu-west-1.amazonses.com>

On 12/3/25 5:54 PM, Cristian Ciocaltea wrote:
> Attempting to make use of the 1080p at 120Hz HDMI mode with 10 bpc RGB on
> my Acer XV275K P3 monitor results in a blank image.  A similar behavior
> has been reported on Philips 279M1RV.

Hello,

I'm the Philips 279M1RV complaint, and this patch fixes the problem on 
that monitor for me.

Tested-by: Derek Foreman <derek.foreman at collabora.com>

Thanks,
Derek

> The faulty modeline is created by drm_gtf_mode_complex() based on the
> following EDID entry from the Standard Timings block:
>
>    GTF:  1920x1080  119.999987 Hz  16:9    138.840 kHz    368.759000 MHz
>
> It's worth noting the computed pixel clock ends up being slightly higher
> at 368.881000 MHz.  Nevertheless, this seems to work consistently fine
> with 8 bpc RGB.
>
> After switching to 10 bpc, the TMDS character rate expected for the mode
> increases to 461.101250 MHz, as per drm_hdmi_compute_mode_clock().
>
> Since there is no entry for this rate in the ropll_tmds_cfg table, the
> necessary HDMI PLL configuration parameters are calculated dynamically
> by rk_hdptx_phy_clk_pll_calc().  However, the resulting output rate is
> not quite a perfect match, i.e. 461.100000 MHz, that proved to be the
> actual root cause of the problem.
>
> Add a new entry to the TMDS configuration table and provide the
> necessary frequency division coefficients for the PHY PLL to generate
> the expected 461.101250 MHz output.
>
> Fixes: 9d0ec51d7c22 ("phy: rockchip: samsung-hdptx: Add high color depth management")
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
> ---
>   drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 2 ++
>   1 file changed, 2 insertions(+)
>
> diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
> index 29de2f7bdae8..cafa618d70fd 100644
> --- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
> +++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
> @@ -414,6 +414,8 @@ struct rk_hdptx_phy {
>   static const struct ropll_config ropll_tmds_cfg[] = {
>   	{ 594000000ULL, 124, 124, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
>   	  1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
> +	{ 461101250ULL, 97, 97, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 71, 1, 53, 2, 6,
> +	  35, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
>   	{ 371250000ULL, 155, 155, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
>   	  1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
>   	{ 297000000ULL, 124, 124, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
>


From broonie at kernel.org  Thu Dec  4 09:52:54 2025
From: broonie at kernel.org (Mark Brown)
Date: Thu, 4 Dec 2025 17:52:54 +0000
Subject: [PATCH] regulator: fixed: fix GPIO descriptor leak on register
 failure
In-Reply-To: <DEPEYUF5BRGY.UKFBWRRE8HNP@cknow-tech.com>
References: <20251028172828.625-1-vulab@iscas.ac.cn>
 <DEPEYUF5BRGY.UKFBWRRE8HNP@cknow-tech.com>
Message-ID: <6a964031-4286-4898-8c25-c0940a78f387@sirena.org.uk>

On Thu, Dec 04, 2025 at 12:59:53PM +0100, Diederik de Haas wrote:
> On Tue Oct 28, 2025 at 6:28 PM CET, Haotian Zhang wrote:

> > In the commit referenced by the Fixes tag,
> > devm_gpiod_get_optional() was replaced by manual
> > GPIO management, relying on the regulator core to release the
> > GPIO descriptor. However, this approach does not account for the
> > error path: when regulator registration fails, the core never
> > takes over the GPIO, resulting in a resource leak.

This should just be reverted, the core always takes ownership of and
consumes the GPIO even if it fails (that is simpler than callers working
out how far it got).  I've written a patch, I'll send it out later all
being well - thanks for reporting.

> But booting the latest 'bisect kernel', thus based on this commit:
> 636f4618b1cd ("regulator: fixed: fix GPIO descriptor leak on register failure")
> gave a different call trace and landed me in the initramfs:

It's corrupting data structures in gpiolib which will I expect be why
you're seeing varying symptoms - exactly what gets corrupted and how the
data gets looked at afterwards will vary.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251204/c134cbb3/attachment.sig>

From nicolas at ndufresne.ca  Thu Dec  4 10:15:35 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Thu, 04 Dec 2025 13:15:35 -0500
Subject: [PATCH v3 3/3] media: verisilicon: Avoid G2 bus error while
 decoding H.264 and HEVC
In-Reply-To: <aTHGJzVKa7PbEifJ@lizhi-Precision-Tower-5810>
References: <20251204090813.595-1-ming.qian@oss.nxp.com>
	 <20251204090813.595-3-ming.qian@oss.nxp.com>
	 <aTHGJzVKa7PbEifJ@lizhi-Precision-Tower-5810>
Message-ID: <9f38bda2f1753645a1ae392ce5364ea0165fdc01.camel@ndufresne.ca>

Hi Frank,

Le jeudi 04 d?cembre 2025 ? 12:34 -0500, Frank Li a ?crit?:
> > +static struct v4l2_m2m_dev *hantro_get_v4l2_m2m_dev(struct hantro_dev *vpu)
> > +{
> > +	struct device_node *node;
> > +	struct hantro_dev *shared_vpu;
> > +
> > +	if (!vpu->variant || !vpu->variant->shared_devices)
> > +		goto init_new_m2m_dev;
> 
> I found only use shared_devices here, how to? ensure that g1 and g2 operate
> alternately by using shared_devices?

shared_devices is an array of of_device_id we match against. All the matching
devices will share the same v4l2_m2m_dev (aka m2m scheduler). Typically, both
cores will be schedule as one. This achieve what alternate operations without
active polling or blocking locks/mutex.

For this platform, we only matched against the compatible for simplicity, since
we know there is only one of each type. I've suggested this method to Ming,
since it will make it really easy to apply such a quirk if other hardware have
problems or design constraints.

regards,
Nicolas
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251204/9175db9d/attachment.sig>

From jonathan.cameron at huawei.com  Thu Dec  4 10:19:40 2025
From: jonathan.cameron at huawei.com (Jonathan Cameron)
Date: Thu, 4 Dec 2025 18:19:40 +0000
Subject: PRI support in arm-smmu-v3 driver
In-Reply-To: <20251125180353.GC520526@nvidia.com>
References: <1256faaa-e9cd-46a6-9a42-25aa74b984a8@quicinc.com>
	<aSXupxMeHLajOmDW@willie-the-truck>
	<20251125180353.GC520526@nvidia.com>
Message-ID: <20251204181940.000062ab@huawei.com>

On Tue, 25 Nov 2025 14:03:53 -0400
Jason Gunthorpe <jgg at nvidia.com> wrote:

> On Tue, Nov 25, 2025 at 06:00:07PM +0000, Will Deacon wrote:
> > [+iommu list and usual suspects]
> > 
> > Hi Pavan,
> > 
> > On Tue, Nov 25, 2025 at 02:22:05PM +0530, Pavan Kondeti wrote:  
> > > I am trying to understand IO fault handling in Linux w/ SMMUv3. While reading
> > > the code, I understand that SVA domain creation allows taking IO pagefaults.
> > > arm_smmu_enable_iopf() checks if the master support stall upon fault
> > > feature or not. How do we handle page faults for PCIe devices, for which 
> > > transactions cannot safely be stalled? IIUC, The PRI handling in the
> > > driver i.e arm_smmu_priq_thread()->arm_smmu_handle_ppr() is not doing
> > > anything. In the SVA support for SMMUv3 series v7, I see the support for
> > > PRI via "Add support for PRI" patch [1] but it is not merged. 
> > > 
> > > Can you please clarify if we can support SVA with PCIe devices w/o
> > > pinning the memory?
> > > 
> > > [1]
> > > https://lore.kernel.org/all/20200519175502.2504091-25-jean-philippe at linaro.org/  
> > 
> > The only SVA client we've had for SMMUv3 in the upstream kernel is the
> > "uacce" thing from HiSilicon which is a platform device (rather than a
> > PCIe device) and so I think the PRI support just fell by the wayside due
> > to lack of an upstream user and no ability to test it.  
> 
> Right, we only support "stall" mode in the driver, not PRI right
> now. PRI has a bunch of differences at the SMMU level.
> 
> > I'm not sure whether or not Jason has plans to implement PRI but maybe
> > it's something you could help with if you have hardware?  
> 
> I've been waiting for someone who has HW to take this on.
> 
> Honestly, I'm not entirely sure what the missing gaps are, at least I
> think we need to get the PRI information and package it into the fault
> queue and link it back to a PRI response.

Long ago we did some testing using various 'interesting' PRI supporting
test setups (they weren't what you would call real devices but did let
us exercise the support).

IIRC the above stuff from JPB worked at the time. Given we didn't have
any real endpoints, we didn't push for it to merge.

No idea what status would be today though. It is on our list to come
back to.

Jonathan

> 
> Jason
> 



From olteanv at gmail.com  Thu Dec  4 10:21:31 2025
From: olteanv at gmail.com (Vladimir Oltean)
Date: Thu, 4 Dec 2025 20:21:31 +0200
Subject: [PATCH v3 2/2] net: dsa: mt7530: Use GPIO polarity to generate
 correct reset sequence
In-Reply-To: <aTHIulPW055AyLW_@shell.armlinux.org.uk>
References: <0d85e1e6-ea75-4f20-aef1-90d446b4bfa1@kernel.org>
 <00f308a1-a4b1-4f20-8d8e-459ddf4c39b1@gmx.de>
 <aS7Zj3AFsSp2CTNv@makrotopia.org>
 <20251204131626.upw77jncqfwxydww@skbuf>
 <4170c560-1edd-4ff8-96af-a479063be4a5@kernel.org>
 <20251204160247.yz42mnxvzhxas5jc@skbuf>
 <66d080f1-e989-451f-9d5e-34460e5eb1b0@kernel.org>
 <20251204171159.yy3nkvzttxecmhfo@skbuf>
 <178afbeb-168f-4765-bb0b-fad0bcd29382@kernel.org>
 <aTHIulPW055AyLW_@shell.armlinux.org.uk>
Message-ID: <20251204182131.gfqwy566gjzd7dbx@skbuf>

On Thu, Dec 04, 2025 at 05:45:30PM +0000, Russell King (Oracle) wrote:
> It would make sense if a single GPIO pin is used for resetting
> several devices, some of them with an active-high reset input and
> others with active-low.
> 
> What matters for a GPIO pin used to source a reset signal is "what
> is the active level at the GPIO pin for the reset to be asserted to
> the connected device(s)."
> 
> If we have a device that requires an active-low reset input, but there
> is some form of inversion in the path to that input from a GPIO, then
> the GPIO _should_ be marked active-high. If the same active-low reset
> input is connected directly to a GPIO, the GPIO _should_ be marked as
> active-low. Thus, to assert reset, writing '1' through
> gpiod_set_value() _should_ assert the reset input on the target device
> in both cases.
> 
> This is why gpiolib supports software inversion - so software engineers
> can think in terms of positive non-inverted logic when programming
> GPIOs.

Thanks for this message, to me it brought new info which I didn't
consider before, which is that if there are *future* boards where some
sort of inversion on the reset signal (likely due to it being shared as
you say), they should be described as GPIO_ACTIVE_HIGH, but this patch
locks us out of that possibility.

If I may bring one more data point into the discussion: the switch
binding specifically requests not to describe shared reset lines
(because unrelated drivers might reset the switch after it probed):

  reset-gpios:
    description: |
      GPIO to reset the switch. Use this if mediatek,mcm is not used.
      This property is optional because some boards share the reset line with
      other components which makes it impossible to probe the switch if the
      reset line is used.

so I guess that the probability for a reset signal inversion, even if
it exists, to cause problems in the GPIO_ACTIVE_HIGH reinterpretation,
is still low, albeit for a completely different reason than the one I
initially claimed (which is bogus and Krzysztof was right to challenge it).

> Sadly, we keep having people mark active-low signals as "active high"
> in DT, and then have to write '0' to assert the signal. These people
> basically don't understand electronics and/or our GPIO model.

This is the case we seem to be in.

On a scale of safety, having quirks for the affected device trees still
ranks a bit higher, though.


From punit.agrawal at oss.qualcomm.com  Thu Dec  4 10:25:37 2025
From: punit.agrawal at oss.qualcomm.com (Punit Agrawal)
Date: Thu, 04 Dec 2025 18:25:37 +0000
Subject: [PATCH 0/8] firmware: arm_scmi: Refactoring and enablement of
 ACPI PCC transport
In-Reply-To: <20251203-super-kagu-of-amplitude-fef078@sudeepholla> (Sudeep
	Holla's message of "Wed, 3 Dec 2025 15:21:31 +0000")
References: <20251017-acpi_scmi_pcc-v1-0-0adbab7709d9@arm.com>
	<87wm44aect.fsf@stealth>
	<20251126-camouflaged-delightful-cuckoo-ddeac8@sudeepholla>
	<877bv3n7x2.fsf@stealth>
	<20251203-super-kagu-of-amplitude-fef078@sudeepholla>
Message-ID: <87h5u6ksta.fsf@stealth>

Sudeep Holla <sudeep.holla at arm.com> writes:

> On Wed, Dec 03, 2025 at 11:04:09AM +0000, Punit Agrawal wrote:
>> Hi Sudeep,
>> 
>> Sudeep Holla <sudeep.holla at arm.com> writes:
>> 
>> > I can create one but that is not strictly necessary. As mentioned in the
>> > cover letter, the only dependency is on value of SCMI_PROTOCOL_TELEMETRY
>> > ins `scmi_std_protocol` enumeration. Just add one and you must be able to
>> > compile the series independent of Cristian series.
>> 
>> Thanks, I managed to get the patches building. Looking forward to the
>> series progressing. If possible, do keep me in the loop for future
>> updates.
>
> Sure - I?ll try to remember to copy you on the next updates. I don?t have any
> immediate plans, though, unless the spec moves into beta, changes come up, or
> someone specifically requests important updates that would help them make
> progress.
>
> Do you have immediate plans to use this on a platform ? Or you are reviewing
> just out of interest/curiosity ? ?

Ah right - although I'd read it in the cover letter it slipped my mind.

I am hoping to migrate some prototype code on top of your patches. Only
worry is if there are big changes planned in your patches. I should be
able to use the posted version for now.


From robh at kernel.org  Thu Dec  4 10:35:41 2025
From: robh at kernel.org (Rob Herring)
Date: Thu, 4 Dec 2025 12:35:41 -0600
Subject: [PATCH net-next v21 01/14] dt-bindings: net: Introduce the
 ethernet-connector description
In-Reply-To: <5dc32a3f-42d8-43d7-854b-3cf11c05544c@kernel.org>
References: <20251129082228.454678-1-maxime.chevallier@bootlin.com>
 <20251129082228.454678-2-maxime.chevallier@bootlin.com>
 <176440811455.3523222.6418355134728802633.robh@kernel.org>
 <5dc32a3f-42d8-43d7-854b-3cf11c05544c@kernel.org>
Message-ID: <20251204183541.GA1936817-robh@kernel.org>

On Sat, Nov 29, 2025 at 12:40:15PM +0100, Christophe Leroy (CS GROUP) wrote:
> 
> 
> Le 29/11/2025 ? 10:21, Rob Herring (Arm) a ?crit?:
> > 
> > On Sat, 29 Nov 2025 09:22:13 +0100, Maxime Chevallier wrote:
> > > The ability to describe the physical ports of Ethernet devices is useful
> > > to describe multi-port devices, as well as to remove any ambiguity with
> > > regard to the nature of the port.
> > > 
> > > Moreover, describing ports allows for a better description of features
> > > that are tied to connectors, such as PoE through the PSE-PD devices.
> > > 
> > > Introduce a binding to allow describing the ports, for now with 2
> > > attributes :
> > > 
> > >   - The number of pairs, which is a quite generic property that allows
> > >     differentating between multiple similar technologies such as BaseT1
> > >     and "regular" BaseT (which usually means BaseT4).
> > > 
> > >   - The media that can be used on that port, such as BaseT for Twisted
> > >     Copper, BaseC for coax copper, BaseS/L for Fiber, BaseK for backplane
> > >     ethernet, etc. This allows defining the nature of the port, and
> > >     therefore avoids the need for vendor-specific properties such as
> > >     "micrel,fiber-mode" or "ti,fiber-mode".
> > > 
> > > The port description lives in its own file, as it is intended in the
> > > future to allow describing the ports for phy-less devices.
> > > 
> > > Reviewed-by: Andrew Lunn <andrew at lunn.ch>
> > > Reviewed-by: Christophe Leroy <christophe.leroy at csgroup.eu>
> > > Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
> > > Tested-by: Christophe Leroy <christophe.leroy at csgroup.eu>
> > > Signed-off-by: Maxime Chevallier <maxime.chevallier at bootlin.com>
> > > ---
> > >   .../bindings/net/ethernet-connector.yaml      | 57 +++++++++++++++++++
> > >   .../devicetree/bindings/net/ethernet-phy.yaml | 18 ++++++
> > >   MAINTAINERS                                   |  1 +
> > >   3 files changed, 76 insertions(+)
> > >   create mode 100644 Documentation/devicetree/bindings/net/ethernet-connector.yaml
> > > 
> > 
> > My bot found errors running 'make dt_binding_check' on your patch:
> > 
> > yamllint warnings/errors:
> > 
> > dtschema/dtc warnings/errors:
> > Documentation/devicetree/bindings/thermal/thermal-sensor.example.dtb: /example-0/soc/thermal-sensor at c263000: failed to match any schema with compatible: ['qcom,sdm845-tsens', 'qcom,tsens-v2']
> > Documentation/devicetree/bindings/thermal/thermal-sensor.example.dtb: /example-0/soc/thermal-sensor at c263000: failed to match any schema with compatible: ['qcom,sdm845-tsens', 'qcom,tsens-v2']
> > Documentation/devicetree/bindings/thermal/thermal-sensor.example.dtb: /example-0/soc/thermal-sensor at c265000: failed to match any schema with compatible: ['qcom,sdm845-tsens', 'qcom,tsens-v2']
> > Documentation/devicetree/bindings/thermal/thermal-sensor.example.dtb: /example-0/soc/thermal-sensor at c265000: failed to match any schema with compatible: ['qcom,sdm845-tsens', 'qcom,tsens-v2']
> 
> Those errors are unrelated to the blamed patch, the patch is about Ethernet
> the error is about thermal-sensors.

There was an assumption that the base (generally linux-next if not 
defined) works. That unfortunately was not the case when a patch applied 
introduced a tab char presumably as part of conflict resolution. So now 
almost every patch fails. Applying the months old patch was timed 
perfectly with my disappearing for US holidays as well as the merge 
window because as an added bonus it went into Linus' tree too. Anyways, 
Linus' tree and today's next are fixed now. The automated testing now 
aborts if the base has issues, so this shouldn't happen again (it will 
be for other reasons). So most of the patches aren't getting tested now 
until folks move of the broken linux-next versions.  

And thanks to all this, now Linus wants to change all kernel YAML files 
over to tabs instead. That's been my week...

Rob


From kuba at kernel.org  Thu Dec  4 10:37:39 2025
From: kuba at kernel.org (Jakub Kicinski)
Date: Thu, 4 Dec 2025 10:37:39 -0800
Subject: [RFC v2 2/3] net: ethernet: mtk_eth_soc: Add RSS support
In-Reply-To: <20251204165849.8214-3-linux@fw-web.de>
References: <20251204165849.8214-1-linux@fw-web.de>
	<20251204165849.8214-3-linux@fw-web.de>
Message-ID: <20251204103739.013d053b@kernel.org>

On Thu,  4 Dec 2025 17:58:44 +0100 Frank Wunderlich wrote:
> +static int mtk_rss_init(struct mtk_eth *eth)
> +{
> +	const struct mtk_soc_data *soc = eth->soc;
> +	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
> +	struct mtk_rss_params *rss_params = &eth->rss_params;
> +	static u8 hash_key[MTK_RSS_HASH_KEYSIZE] = {
> +		0xfa, 0x01, 0xac, 0xbe, 0x3b, 0xb7, 0x42, 0x6a,
> +		0x0c, 0xf2, 0x30, 0x80, 0xa3, 0x2d, 0xcb, 0x77,
> +		0xb4, 0x30, 0x7b, 0xae, 0xcb, 0x2b, 0xca, 0xd0,
> +		0xb0, 0x8f, 0xa3, 0x43, 0x3d, 0x25, 0x67, 0x41,
> +		0xc2, 0x0e, 0x5b, 0x25, 0xda, 0x56, 0x5a, 0x6d};
> +	u32 val;
> +	int i;
> +
> +	memcpy(rss_params->hash_key, hash_key, MTK_RSS_HASH_KEYSIZE);

netdev_rss_key_fill()

> +	for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE; i++)
> +		rss_params->indirection_table[i] = i % eth->soc->rss_num;

ethtool_rxfh_indir_default()

> +static int mtk_get_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh)
> +{
> +	struct mtk_mac *mac = netdev_priv(dev);
> +	struct mtk_eth *eth = mac->hw;
> +	struct mtk_rss_params *rss_params = &eth->rss_params;
> +	int i;
> +
> +	if (rxfh->hfunc)
> +		rxfh->hfunc = ETH_RSS_HASH_TOP;	/* Toeplitz */

hfunc is not a pointer, you should just set it?

> +	if (rxfh->key) {
> +		memcpy(rxfh->key, rss_params->hash_key,
> +		       sizeof(rss_params->hash_key));
> +	}
> +
> +	if (rxfh->indir) {
> +		for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE; i++)
> +			rxfh->indir[i] = rss_params->indirection_table[i];
> +	}
> +
> +	return 0;
> +}


From namhyung at kernel.org  Thu Dec  4 11:10:45 2025
From: namhyung at kernel.org (Namhyung Kim)
Date: Thu, 04 Dec 2025 11:10:45 -0800
Subject: [PATCH v2] perf arm_spe: Add CPU variants supporting common
 data source packet
In-Reply-To: <20251113-perf_arm_spe_update_midr_list-v2-1-d547768f5520@arm.com>
References: <20251113-perf_arm_spe_update_midr_list-v2-1-d547768f5520@arm.com>
Message-ID: <176487544583.182574.10220163589833287696.b4-ty@kernel.org>

On Thu, 13 Nov 2025 10:57:39 +0000, Leo Yan wrote:
> Add the following CPU variants to the list for data source decoding:
> 
>   - Cortex-A715 [1]
>   - Cortex-A78C [2]
>   - Cortex-X1 [3]
>   - Cortex-X4 [4]
>   - Neoverse V3 [5]
> 
> [...]
Applied to perf-tools-next, thanks!

Best regards,
Namhyung




From marek.vasut at mailbox.org  Thu Dec  4 10:59:20 2025
From: marek.vasut at mailbox.org (Marek Vasut)
Date: Thu, 4 Dec 2025 19:59:20 +0100
Subject: [PATCH 1/2] dt-bindings: firmware: arm,scmi: Document
 arm,poll-transport property
In-Reply-To: <20251204-calm-peacock-of-fantasy-6b8cbe@sudeepholla>
References: <aPoxfH_TLrsMxMVQ@pluto>
 <70554674-7020-4582-a4e7-dbee34907096@mailbox.org>
 <5ae0a793-d3e7-45d1-bf5c-3c46593d1824@mailbox.org> <aRW7BZimWdpq4TyX@pluto>
 <20251202-evasive-neon-rhino-d2745e@sudeepholla>
 <66257fcf-9024-454f-b776-4ba584963ebe@mailbox.org> <aS82GSN8c2SnRn4S@bogus>
 <8d773671-5e2e-4e21-ade6-2bf9a3b75066@mailbox.org>
 <20251203-thick-didactic-cockatoo-deaa1d@sudeepholla>
 <4ccbcffd-bcc7-478b-a525-a4a11e3092ee@mailbox.org>
 <20251204-calm-peacock-of-fantasy-6b8cbe@sudeepholla>
Message-ID: <e25c690c-e74d-4641-a97e-8eae81a59168@mailbox.org>

On 12/4/25 1:33 PM, Sudeep Holla wrote:

Hello Sudeep,

>> Wouldn't such a setup use separate mailbox channels, therefore even if
>> mailbox driver calls mbox_chan_received_data(), it would be called for a
>> specific mailbox channel , and it won't interfere with the SCMI mailbox
>> channel.
>>
> 
> Ideally yes. Because PCC uses shared interrupts and provides no mechanism to
> identify the channel that raised the interrupt, we must run the handler for
> every registered channel. This behaviour is specific to PCC; other controllers
> that support interrupt source detection may not need to do this. But SCMI
> must work with any mailbox or other transports.

It seems the pcc_mbox_irq() operates per-channel, so it seems even the 
PCC can demux channels for each IRQ and does trigger 
mbox_chan_received_data() for correct channel ?

What exactly happens on the PCC mailbox driver with this polling mode 
enabled ?

>>> Also IIUC, the irq request happens
>>> as part of channel startup and there are no explicit APIs for the mbox client
>>> driver to control that. SCMI is mbox client in this case.
>>
>> Sure, but the mailbox driver has to make sure it is correctly demuxing the
>> IRQs it handles and correctly sends received_data notifications to the right
>> channel(s) .
>>
> 
> Agreed, but the concern is that if SCMI is forced to use polling when the
> channel is opened, and IRQs are enabled by default with no way for SCMI to
> disable them in polling mode, we could run into issues.

This constellation seems odd -- if the channel can do IRQs, then this 
property should not be present in DT.

> I realise it?s a very
> specific corner case, but every time I?ve assumed such scenarios wouldn?t
> occur, we eventually ended up encountering them. So sorry if I am very
> pedantic, but I prefer to start smaller and restrictive and expand if and
> when necessary or required only.

I don't think this case, where mailbox channel does IRQs and polling is 
enabled, can/should even be considered valid. Either the channel does 
not do IRQs and then it should do polling, or it does IRQs and then it 
should use IRQs, but not both.

>>>>> I am aware of systems that implement such sharing, which is why I prefer to be
>>>>> explicit that this type of design is challenging to support within this
>>>>> binding. The intent is to support only minimal, constrained cases - essentially
>>>>> systems that are already somewhat broken. I do not see value in broadening the
>>>>> binding to cover every conceivable scenario.
>>>>>
>>>>>>> Clearly defining these constraints would be helpful. It may also be useful to
>>>>>>> note that this is primarily intended for mailbox transports, if that?s
>>>>>>> accurate. Alternatively, we could keep the DT binding definition broader but
>>>>>>> emit warnings when a transport other than mailbox is used. That approach might
>>>>>>> make it easier to move forward.
>>>>>>
>>>>>> DEN0056F refers to this polling mode in Shared memory based transports, that
>>>>>> can be other than mailbox transports, it includes e.g. SMC or OPTEE
>>>>>> transports.
>>>>>>
>>>>>
>>>>> However, polling does not make sense in the context of SMC. Once control
>>>>> returns from an SMC call, the command has completed. What form of polling in
>>>>> an SMC workflow do you have in mind?
>>>>
>>>> I think the polling happens on the SHMEM and the SMC transport is capable of
>>>> that too, see :
>>>>
>>>> drivers/firmware/arm_scmi/transports/smc.c
>>>>
>>>> 175         /*
>>>> 176          * If there is an interrupt named "a2p", then the service and
>>>> 177          * completion of a message is signaled by an interrupt rather
>>>> than by
>>>> 178          * the return of the SMC call.
>>>> 179          */
>>>> 180         scmi_info->irq = of_irq_get_byname(cdev->of_node, "a2p");
>>>>
>>>
>>> Ah this one, is actually implemented to avoid sort of implicit polling
>>> mode we get with any SMC/HVC. I don't know how the platform deals with it
>>> but SMC/HVC is synchronous and doesn't need this polling. The irq introduced
>>> here is again a sort of workaround to get some sort of async/non-polling
>>> mode with SMC/HVC. So, to repeat polling mode make absolutely no sense
>>> whatsoever for SMC/OPTEE(based on pure SMC) transports.
>>
>> I can drop the SMC part from this patch if you think that's helpful ?
>>
> 
> Yes, that?s essential, because polling in an SMC context is meaningless in my
> opinion.

Maybe the "a2p" IRQ is also used for notifications from longer running 
operations ?

[...]

>>> Yes it can be minimalistic but not restrictive. As I already clearly mentioned
>>> I don't see it makes any sense to enable this for SMC/OPTEE. Lets start with
>>> just mailbox to start with and extend to other transports if and when needed.
>>> It would be good to impose that restriction in the binding as well but that
>>> is not a must IMO. I am fine if the bindings for whatever reasons(though I
>>> don't see the need) to apply for any transport.
>> So I should simply drop the smc.c changes , keep the rest, and send V2 ?
> 
> Not just that. Unless DT maintainers oppose, I just want to keep this
> new property valid only for mailbox transport(i.e. "arm,scmi" compatible
> not otherwise) so that we can catch any other use in binding checks and
> interested parties must discuss on the list and expand that if they require.
> 
> Also we can explore if we can parse and scan this in mailbox transport for
> now.
I feel that this only adds more implementation complexity and makes the 
solution less generic, while it does win us very little in the end ? The 
generic solution implementation is actually easier to implement.


From robh at kernel.org  Thu Dec  4 11:53:55 2025
From: robh at kernel.org (Rob Herring)
Date: Thu, 4 Dec 2025 13:53:55 -0600
Subject: [PATCH v6 0/7] Add ASPEED PCIe Root Complex support
In-Reply-To: <20251201-upstream_pcie_rc-v6-0-8c8800c56b16@aspeedtech.com>
References: <20251201-upstream_pcie_rc-v6-0-8c8800c56b16@aspeedtech.com>
Message-ID: <20251204195355.GA1975043-robh@kernel.org>

On Mon, Dec 01, 2025 at 02:29:10PM +0800, Jacky Chou wrote:
> This patch series adds support for the ASPEED PCIe Root Complex,
> including device tree bindings, pinctrl support, and the PCIe host controller
> driver. The patches introduce the necessary device tree nodes, pinmux groups,
> and driver implementation to enable PCIe functionality on ASPEED platforms.
> Currently, the ASPEED PCIe Root Complex only supports a single port.
> 
> Summary of changes:
> - Add device tree binding documents for ASPEED PCIe PHY, PCIe Config, and PCIe RC
> - Update MAINTAINERS for new bindings and driver
> - Add PCIe RC node and PERST control pin to aspeed-g6 device tree
> - Implement ASPEED PCIe PHY driver
> - Implement ASPEED PCIe Root Complex host controller driver
> 
> This series has been tested on AST2600/AST2700 platforms and enables PCIe device
> enumeration and operation.
> 
> Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
> ---
> Changes in v6:
> - Refer to pci-cpi-bridge.yaml to update aspeed,ast2600-pcie.yaml and
>   the pcie node of aspeed-g6.dtsi.

Where is this? You don't describe the root port and its properties at 
all now.

> - 'dt-bindings: pinctrl: aspeed,ast2600-pinctrl: Add PCIe RC PERST#
>   group' have applied, remove it from this version.
> - Adjust the defnitions in pci.h. 
> - Link to v5: https://lore.kernel.org/r/20251117-upstream_pcie_rc-v5-0-b4a198576acf at aspeedtech.com


From justinstitt at google.com  Thu Dec  4 12:44:48 2025
From: justinstitt at google.com (Justin Stitt)
Date: Thu, 04 Dec 2025 12:44:48 -0800
Subject: [PATCH 5.15.y RESEND] KVM: arm64: sys_regs: disable
 -Wuninitialized-const-pointer warning
Message-ID: <20251204-b4-stable-disable-uninit-ptr-warn-5-15-v1-1-41212e2c6409@google.com>

A new warning in Clang 22 [1] complains that @clidr passed to
get_clidr_el1() is an uninitialized const pointer. get_clidr_el1()
doesn't really care since it casts away the const-ness anyways -- it is
a false positive.

|  ../arch/arm64/kvm/sys_regs.c:2838:23: warning: variable 'clidr' is uninitialized when passed as a const pointer argument here [-Wuninitialized-const-pointer]
|   2838 |         get_clidr_el1(NULL, &clidr); /* Ugly... */
|        |                              ^~~~~

This patch isn't needed for anything past 6.1 as this code section was
reworked in Commit 7af0c2534f4c ("KVM: arm64: Normalize cache
configuration"). Since there is no upstream equivalent, this patch just
needs to be applied to 5.15.

Disable this warning for sys_regs.o with an iron fist as it doesn't make
sense to waste maintainer's time or potentially break builds by
backporting large changelists from 6.2+.

Cc: stable at vger.kernel.org
Fixes: 7c8c5e6a9101e ("arm64: KVM: system register handling")
Link: https://github.com/llvm/llvm-project/commit/00dacf8c22f065cb52efb14cd091d441f19b319e [1]
Reviewed-by: Nathan Chancellor <nathan at kernel.org>
Signed-off-by: Justin Stitt <justinstitt at google.com>
---
Resending this with Nathan's RB tag, an updated commit log and better
recipients from checkpatch.pl.

I'm also sending a similar patch resend for 6.1.
---
 arch/arm64/kvm/Makefile | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index 989bb5dad2c8..109cca425d3e 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -25,3 +25,6 @@ kvm-y := $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o $(KVM)/eventfd.o \
 	 vgic/vgic-its.o vgic/vgic-debug.o
 
 kvm-$(CONFIG_HW_PERF_EVENTS)  += pmu-emul.o
+
+# Work around a false positive Clang 22 -Wuninitialized-const-pointer warning
+CFLAGS_sys_regs.o := $(call cc-disable-warning, uninitialized-const-pointer)

---
base-commit: 8bb7eca972ad531c9b149c0a51ab43a417385813
change-id: 20250728-b4-stable-disable-uninit-ptr-warn-5-15-c0c9db3df206

Best regards,
--
Justin Stitt <justinstitt at google.com>



From linux at armlinux.org.uk  Thu Dec  4 12:47:30 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Thu, 4 Dec 2025 20:47:30 +0000
Subject: [PATCH v3 2/2] net: dsa: mt7530: Use GPIO polarity to generate
 correct reset sequence
In-Reply-To: <9f7da6ae-9e3e-442f-a203-28a8881dbe0f@kernel.org>
References: <0d85e1e6-ea75-4f20-aef1-90d446b4bfa1@kernel.org>
 <00f308a1-a4b1-4f20-8d8e-459ddf4c39b1@gmx.de>
 <aS7Zj3AFsSp2CTNv@makrotopia.org>
 <20251204131626.upw77jncqfwxydww@skbuf>
 <4170c560-1edd-4ff8-96af-a479063be4a5@kernel.org>
 <20251204160247.yz42mnxvzhxas5jc@skbuf>
 <66d080f1-e989-451f-9d5e-34460e5eb1b0@kernel.org>
 <20251204171159.yy3nkvzttxecmhfo@skbuf>
 <178afbeb-168f-4765-bb0b-fad0bcd29382@kernel.org>
 <9f7da6ae-9e3e-442f-a203-28a8881dbe0f@kernel.org>
Message-ID: <aTHzYq5L7kvAPrjQ@shell.armlinux.org.uk>

On Thu, Dec 04, 2025 at 06:32:23PM +0100, Krzysztof Kozlowski wrote:
> On 04/12/2025 18:23, Krzysztof Kozlowski wrote:
> > On 04/12/2025 18:11, Vladimir Oltean wrote:
> >> On Thu, Dec 04, 2025 at 05:48:07PM +0100, Krzysztof Kozlowski wrote:
> >>> Both are the same - inverter or NOT gate, same stuff. It is just
> >>> connecting wire to pull up, not actual component on the board (although
> >>> one could make and buy such component as well...). We never describe
> >>> these inverters in the DTS, these are just too trivial circuits, thus
> >>> the final GPIO_ACTIVE_XXX should already include whatever is on the wire
> >>> between SoC and device.
> >>
> >> Please read what Andrew said:
> >> https://lore.kernel.org/netdev/3fbc4e67-b931-421c-9d83-2214aaa2f6ed at lunn.ch/
> >>
> >>   Assuming there is not a NOT gate placed between the GPIO and the reset
> >>   pin, because the board designer decided to do that for some reason?
> >>                    ~~~~~~~~~~~~~~
> >>
> >> You two are *not* talking about the same thing. I dismissed the
> > 
> > 
> > It's the same thing. NOT gate is just pulling some pin down or up.
> 
> Although transistor would be still needed, so indeed that's still a bit
> more than a wire and resistor as I implied.
> 
> It looks like:
> https://www.electronics-tutorials.ws/wp-content/uploads/2018/05/logic-log47.gif

A bit more than even that... I do hope folk don't use exactly that,
that's the kind of thing that would be used in "learning about
electronics" projects! That's a recipe to drive a transistor into
full saturation, which makes it comparitively very slow to turn off.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From justinstitt at google.com  Thu Dec  4 12:50:11 2025
From: justinstitt at google.com (Justin Stitt)
Date: Thu, 04 Dec 2025 12:50:11 -0800
Subject: [PATCH 6.1.y RESEND] KVM: arm64: silence -Wuninitialized-const-pointer
 warning
Message-ID: <20251204-b4-clidr-unint-const-ptr-v1-1-95161315ad92@google.com>

A new warning in Clang 22 [1] complains that @clidr passed to
get_clidr_el1() is an uninitialized const pointer. get_clidr_el1()
doesn't really care since it casts away the const-ness anyways.

Silence the warning by initializing the struct.

This patch won't apply to anything past v6.1 as this code section was
reworked in Commit 7af0c2534f4c ("KVM: arm64: Normalize cache
configuration"). There is no upstream equivalent so this patch only
needs to be applied (stable only) to 6.1.

Cc: stable at vger.kernel.org
Fixes: 7c8c5e6a9101e ("arm64: KVM: system register handling")
Link: https://github.com/llvm/llvm-project/commit/00dacf8c22f065cb52efb14cd091d441f19b319e [1]
Signed-off-by: Justin Stitt <justinstitt at google.com>
---
Resending this with Nathan's RB tag, an updated commit log and better
recipients from checkpatch.pl.

I've also sent a similar patch resend for 5.15
---
 arch/arm64/kvm/sys_regs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index f4a7c5abcbca..d7ebd7387221 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -2948,7 +2948,7 @@ int kvm_sys_reg_table_init(void)
 {
 	bool valid = true;
 	unsigned int i;
-	struct sys_reg_desc clidr;
+	struct sys_reg_desc clidr = {0};
 
 	/* Make sure tables are unique and in order. */
 	valid &= check_sysreg_table(sys_reg_descs, ARRAY_SIZE(sys_reg_descs), false);

---
base-commit: 830b3c68c1fb1e9176028d02ef86f3cf76aa2476
change-id: 20250724-b4-clidr-unint-const-ptr-7edb960bc3bd

Best regards,
--
Justin Stitt <justinstitt at google.com>



From justinstitt at google.com  Thu Dec  4 12:53:58 2025
From: justinstitt at google.com (Justin Stitt)
Date: Thu, 4 Dec 2025 12:53:58 -0800
Subject: [PATCH 6.1.y RESEND] KVM: arm64: silence
 -Wuninitialized-const-pointer warning
In-Reply-To: <20251204-b4-clidr-unint-const-ptr-v1-1-95161315ad92@google.com>
References: <20251204-b4-clidr-unint-const-ptr-v1-1-95161315ad92@google.com>
Message-ID: <2lse2swdqrovimdsakgtriadki2fsvikhuetjzxztoui5hpsai@6mmc64ugt22k>

Quick correction:

On Thu, Dec 04, 2025 at 12:50:11PM -0800, Justin Stitt wrote:
> A new warning in Clang 22 [1] complains that @clidr passed to
> get_clidr_el1() is an uninitialized const pointer. get_clidr_el1()
> doesn't really care since it casts away the const-ness anyways.
> 
> Silence the warning by initializing the struct.
> 
> This patch won't apply to anything past v6.1 as this code section was
> reworked in Commit 7af0c2534f4c ("KVM: arm64: Normalize cache
> configuration"). There is no upstream equivalent so this patch only
> needs to be applied (stable only) to 6.1.
> 
> Cc: stable at vger.kernel.org
> Fixes: 7c8c5e6a9101e ("arm64: KVM: system register handling")
> Link: https://github.com/llvm/llvm-project/commit/00dacf8c22f065cb52efb14cd091d441f19b319e [1]
> Signed-off-by: Justin Stitt <justinstitt at google.com>
> ---
> Resending this with Nathan's RB tag, an updated commit log and better
> recipients from checkpatch.pl.

My usage of $ b4 trailers must've not been correct because this 6.1
version didn't pick up Nathan's RB tag. Whoops! Hopefully whoever picks
this up can add that for me :)

<snip>


From rebecca at bsdio.com  Thu Dec  4 13:02:33 2025
From: rebecca at bsdio.com (Rebecca Cran)
Date: Thu,  4 Dec 2025 14:02:33 -0700
Subject: [PATCH v3 0/3] Add device tree for ASRock Rack ALTRAD8 BMC
Message-ID: <20251204210238.40742-1-rebecca@bsdio.com>

Apologies for the long delay between v2 and v3 patches.

cc Billy Tsai for the move of ast2500 pwm-tacho docs from
aspeed-pwm-tacho.txt to aspeed,g5-pwm-tacho.yaml.

The ASRock Rack ALTRAD8 BMC is an Aspeed AST2500-based BMC for the
ALTRAD8UD-1L2T and ALTRAD8UD2-1L2Q boards with an Ampere Altra
processor. The BMC runs OpenBMC.

These patches add a device tree and binding for the BMC.

**Changes between v2 and v3**

- Removed system fault and enclosure identify LEDs; added heartbeat.
- Removed the code partition from the BIOS/UEFI flash.
- Renoved bus-frequency from i2c nodes.
- Renamed hardware-monitor to temperature-sensor.
- Fixed indentation of nct7802 subnodes.
- Swapped eth0_macaddress and eth1_macaddress.
- Removed pca9557 subnodes.
- Reworked GPIO names to be more consistent.
- Moved documentation of aspeed-pwm-tacho from txt to yaml file.

**Testing**

Ran `make ARCH=arm CHECK_DTBS=y aspeed/aspeed-bmc-asrock-altrad8.dtb` and
verified the messages about the aspeed,pwm-tacho device are no longer present.
The remaining messages are:

arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dtb: /ahb/apb/lpc at 1e789000/lhc at a0: failed to match any schema with compatible: ['aspeed,ast2500-lhc']
arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dtb: /ahb/apb/lpc at 1e789000/ibt at 140: failed to match any schema with compatible: ['aspeed,ast2500-ibt-bmc']

Rebecca Cran (3):
  dt-bindings: arm: aspeed: add ASRock Rack ALTRAD8 board
  ARM: dts: aspeed: add device tree for ASRock Rack ALTRAD8 BMC
  dt-bindings: hwmon: (aspeed,g5-pwm-tacho) Move info from txt to yaml

 Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml      |   1 +
 Documentation/devicetree/bindings/hwmon/aspeed,pwm-tacho.yaml |  91 +++
 Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt  |  73 ---
 arch/arm/boot/dts/aspeed/Makefile                             |   1 +
 arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts        | 612 ++++++++++++++++++++
 5 files changed, 705 insertions(+), 73 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/hwmon/aspeed,pwm-tacho.yaml
 delete mode 100644 Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt
 create mode 100644 arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts

-- 
2.47.3



From rebecca at bsdio.com  Thu Dec  4 13:02:35 2025
From: rebecca at bsdio.com (Rebecca Cran)
Date: Thu,  4 Dec 2025 14:02:35 -0700
Subject: [PATCH v3 2/3] ARM: dts: aspeed: add device tree for ASRock Rack ALTRAD8 BMC
In-Reply-To: <20251204210238.40742-1-rebecca@bsdio.com>
References: <20251204210238.40742-1-rebecca@bsdio.com>
Message-ID: <20251204210238.40742-3-rebecca@bsdio.com>

The ALTRAD8 BMC is an Aspeed AST2500-based BMC for the ASRock Rack
ALTRAD8UD-1L2T and ALTRAD8UD2-1L2Q boards.

Signed-off-by: Rebecca Cran <rebecca at bsdio.com>
---
 arch/arm/boot/dts/aspeed/Makefile                      |   1 +
 arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts | 612 ++++++++++++++++++++
 2 files changed, 613 insertions(+)

diff --git a/arch/arm/boot/dts/aspeed/Makefile b/arch/arm/boot/dts/aspeed/Makefile
index 0f0b5b707654..9fd42a30c56d 100644
--- a/arch/arm/boot/dts/aspeed/Makefile
+++ b/arch/arm/boot/dts/aspeed/Makefile
@@ -9,6 +9,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \
 	aspeed-bmc-ampere-mtjefferson.dtb \
 	aspeed-bmc-ampere-mtmitchell.dtb \
 	aspeed-bmc-arm-stardragon4800-rep2.dtb \
+	aspeed-bmc-asrock-altrad8.dtb \
 	aspeed-bmc-asrock-e3c246d4i.dtb \
 	aspeed-bmc-asrock-e3c256d4i.dtb \
 	aspeed-bmc-asrock-romed8hm3.dtb \
diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts
new file mode 100644
index 000000000000..2696a8692607
--- /dev/null
+++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts
@@ -0,0 +1,612 @@
+// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+
+#include "aspeed-g5.dtsi"
+#include <dt-bindings/gpio/aspeed-gpio.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/i2c/i2c.h>
+
+/ {
+	model = "ASRock ALTRAD8 BMC";
+	compatible = "asrock,altrad8-bmc", "aspeed,ast2500";
+
+	aliases {
+		serial4 = &uart5;
+		i2c50 = &nvme1;
+		i2c51 = &pcie4;
+		i2c52 = &pcie5;
+		i2c53 = &pcie6;
+		i2c54 = &pcie7;
+		i2c55 = &nvme3;
+		i2c56 = &nvme2;
+		i2c57 = &nvme0;
+		i2c58 = &nvme4;
+		i2c59 = &nvme5;
+		i2c60 = &nvme6;
+		i2c61 = &nvme7;
+		i2c62 = &nvme8;
+		i2c63 = &nvme9;
+		i2c64 = &nvme10;
+		i2c65 = &nvme11;
+	};
+
+	chosen {
+		stdout-path = "uart5:115200n8";
+	};
+
+	iio-hwmon {
+		compatible = "iio-hwmon";
+		io-channels =	<&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>,
+				<&adc 4> ,<&adc 5>, <&adc 6>, <&adc 7>,
+				<&adc 8>, <&adc 9>, <&adc 10>, <&adc 11>,
+				<&adc 12>, <&adc 13>, <&adc 14>, <&adc 15>;
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		led-heartbeat {
+			gpios = <&gpio ASPEED_GPIO(G,0) GPIO_ACTIVE_LOW>;
+			label = "platform:green:heartbeat";
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_INDICATOR;
+		};
+
+		led-fan1-fault {
+			retain-state-shutdown;
+			default-state = "off";
+			gpios = <&io_expander0 0 GPIO_ACTIVE_LOW>;
+			label = "fan1:red:fault";
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_FAULT;
+		};
+
+		led-fan2-fault {
+			retain-state-shutdown;
+			default-state = "off";
+			gpios = <&io_expander0 1 GPIO_ACTIVE_LOW>;
+			label = "fan2:red:fault";
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_FAULT;
+		};
+
+		led-fan3-fault {
+			retain-state-shutdown;
+			default-state = "off";
+			gpios = <&io_expander0 2 GPIO_ACTIVE_LOW>;
+			label = "fan3:red:fault";
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_FAULT;
+		};
+
+		led-fan4-fault {
+			retain-state-shutdown;
+			default-state = "off";
+			gpios = <&io_expander0 3 GPIO_ACTIVE_LOW>;
+			label = "fan4:red:fault";
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_FAULT;
+		};
+
+		led-fan5-fault {
+			retain-state-shutdown;
+			default-state = "off";
+			gpios = <&io_expander0 4 GPIO_ACTIVE_LOW>;
+			label = "fan5:red:fault";
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_FAULT;
+		};
+	};
+
+	memory at 80000000 {
+		reg = <0x80000000 0x20000000>;
+	};
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		gfx_memory: framebuffer {
+			compatible = "shared-dma-pool";
+			size = <0x01000000>;
+			alignment = <0x01000000>;
+			reusable;
+		};
+
+		vga_memory: framebuffer at 9f000000 {
+			no-map;
+			reg = <0x9f000000 0x01000000>; /* 16M */
+		};
+
+		video_engine_memory: jpegbuffer {
+			compatible = "shared-dma-pool";
+			size = <0x02000000>;	/* 32M */
+			alignment = <0x01000000>;
+			reusable;
+		};
+	};
+};
+
+&adc {
+	status = "okay";
+};
+
+&fmc {
+	status = "okay";
+
+	flash at 0 {
+		label = "bmc";
+		m25p,fast-read;
+		spi-max-frequency = <50000000>;
+		status = "okay";
+#include "openbmc-flash-layout-64.dtsi"
+	};
+};
+
+&gfx {
+	memory-region = <&gfx_memory>;
+	status = "okay";
+};
+
+&gpio {
+	gpio-line-names =
+	/*A0-A7*/	"","","","bmc-ready","","","","",
+	/*B0-B7*/	"i2c-backup-sel","","","","","","","host0-shd-ack-n",
+	/*C0-C7*/	"","","","","","","","",
+	/*D0-D7*/	"power-button","power-out","button-reset",
+			"host0-sysreset-n","","","power-chassis-good","",
+	/*E0-E7*/	"","s0-vrd1-vddq0123-fault-n",
+			"s0-vrd1-vddq4567-fault-n","s0-vrd0-vddc-fault-n",
+			"s0-vrd3-p0v75-fault-n","","","",
+	/*F0-F7*/	"","","ps-atx-on-n","","","","","",
+	/*G0-G7*/	"led-identify","button-identify","","","uboot-ready",\
+			"bmc-salt2-n","","",
+	/*H0-H7*/	"ps-pwr-ok","uart1-mode1","uart2-mode1","uart3-mode1",
+			"uart4-mode1","","led-bmc-heartbeat","",
+	/*I0-I7*/	"","","","","","","","",
+	/*J0-J7*/	"s0-hightemp-n","","","","","","","",
+	/*K0-K7*/	"","","","","","","","",
+	/*L0-L7*/	"","","","","","","","",
+	/*M0-M7*/	"","","","","","s0-spi-auth-fail-n","","",
+	/*N0-N7*/	"","","","","","","","",
+	/*O0-O7*/	"","","","","","","","",
+	/*P0-P7*/	"","","cpld-disable-bmc","","","","","",
+	/*Q0-Q7*/	"","","ext-hightemp-n","","","","",
+			"chassis-intrusion",
+	/*R0-R7*/	"","","ext-hightemp-n","spi0-program-sel","",
+			"hwm-bat-en","","",
+	/*S0-S7*/	"s0-vr-hot-n","","","bmc-sysreset-n","","","","",
+	/*T0-T7*/	"","","","","","","","",
+	/*U0-U7*/	"","","","","","","","",
+	/*V0-V7*/	"","","","","","","","",
+	/*W0-W7*/	"","","","","","","","",
+	/*X0-X7*/	"","","","","","","","",
+	/*Y0-Y7*/	"sio-s3","sio-s5","sio-pwr-req","sio-on-ctrl","","","","",
+	/*Z0-Z7*/	"","sio-pwr-good","","s0-rtc-lock","","","","",
+	/*AA0-AA7*/	"rtc-int","","","","","pmbus-sel-n","","",
+	/*AB0-AB7*/	"host0-reboot-ack-n","s0-sys-auth-failure-n",
+			"","","","","","",
+	/*AC0-AC7*/	"s0-fault-alert","host0-ready","s0-overtemp-n",
+			"","bmc-ok","host0-special-boot","presence-cpu0",
+			"host0-shd-req-n";
+
+	status = "okay";
+};
+
+&i2c0 {
+	status = "okay";
+
+	ipmb at 10 {
+		compatible = "ipmb-dev";
+		reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>;
+		i2c-protocol;
+	};
+
+};
+
+&i2c1 {
+	status = "okay";
+
+	i2c-mux1 at 73 {
+		compatible = "nxp,pca9548";
+		reg = <0x73>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		nvme1: i2c at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+		};
+
+		pcie4: i2c at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+		};
+
+		pcie5: i2c at 2 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2>;
+		};
+
+		pcie6: i2c at 3 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <3>;
+		};
+
+		pcie7: i2c at 4 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <4>;
+		};
+
+		nvme3: i2c at 5 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <5>;
+		};
+
+		nvme2: i2c at 6 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <6>;
+		};
+
+		nvme0: i2c at 7 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <7>;
+		};
+	};
+
+	i2c-mux2 at 75 {
+		compatible = "nxp,pca9548";
+		reg = <0x75>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		nvme4: i2c at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+		};
+
+		nvme5: i2c at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+		};
+
+		nvme6: i2c at 2 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2>;
+		};
+
+		nvme7: i2c at 3 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <3>;
+		};
+
+		nvme8: i2c at 4 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <4>;
+		};
+
+		nvme9: i2c at 5 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <5>;
+		};
+
+		nvme10: i2c at 6 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <6>;
+		};
+
+		nvme11: i2c at 7 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <7>;
+		};
+	};
+};
+
+&i2c2 {
+	status = "okay";
+
+	smpro at 4f {
+		compatible = "ampere,smpro";
+		reg = <0x4f>;
+	};
+};
+
+&i2c3 {
+	status = "okay";
+
+	// PSU FRU
+	eeprom at 38 {
+		compatible = "atmel,24c02";
+		reg = <0x38>;
+	};
+};
+
+&i2c4 {
+	status = "okay";
+
+	temperature-sensor at 29 {
+		compatible = "nuvoton,nct7802";
+		reg = <0x29>;
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		channel at 0 { /* LTD */
+			reg = <0>;
+			status = "okay";
+		};
+
+		channel at 1 { /* RTD1 */
+			reg = <1>;
+			sensor-type = "temperature";
+			temperature-mode = "thermistor";
+		};
+
+		channel at 2 { /* RTD2 */
+			reg = <2>;
+			sensor-type = "temperature";
+			temperature-mode = "thermal-diode";
+		};
+	};
+
+	temperature-sensor at 4c {
+		compatible = "nuvoton,w83773g";
+		reg = <0x4c>;
+	};
+};
+
+&i2c5 {
+	status = "okay";
+};
+
+&i2c6 {
+	status = "okay";
+
+	rtc at 6f {
+		compatible = "isil,isl1208";
+		reg = <0x6f>;
+	};
+};
+
+&i2c7 {
+	status = "okay";
+
+	// BMC FRU
+	eeprom at 57 {
+		compatible = "atmel,24c128";
+		reg = <0x57>;
+
+		nvmem-layout {
+			compatible = "fixed-layout";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			eth1_macaddress: macaddress at 3f80 {
+				reg = <0x3f80 6>;
+			};
+
+			eth0_macaddress: macaddress at 3f88 {
+				reg = <0x3f88 6>;
+			};
+		};
+	};
+};
+
+&i2c8 {
+	status = "okay";
+
+	io_expander0: gpio at 1c {
+		compatible = "nxp,pca9557";
+		reg = <0x1c>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+};
+
+&i2c9 {
+	status = "okay";
+};
+
+&i2c10 {
+	status = "okay";
+};
+
+&i2c11 {
+	status = "okay";
+};
+
+&i2c12 {
+	status = "okay";
+};
+
+&i2c13 {
+	status = "okay";
+
+	ssif-bmc at 10 {
+		compatible = "ssif-bmc";
+		reg = <0x10>;
+	};
+};
+
+// Connected to host Intel X550 (ALTRAD8UD-1L2T) or
+// Broadcom BCM57414 (ALTRAD8UD2-1L2Q) interface
+&mac0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_rmii1_default>;
+	clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+		 <&syscon ASPEED_CLK_MAC1RCLK>;
+	clock-names = "MACCLK", "RCLK";
+	use-ncsi;
+	nvmem-cells = <&eth0_macaddress>;
+	nvmem-cell-names = "mac-address";
+
+	status = "okay";
+};
+
+// Connected to Realtek RTL8211E
+&mac1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>;
+
+	nvmem-cells = <&eth1_macaddress>;
+	nvmem-cell-names = "mac-address";
+
+	status = "okay";
+};
+
+&pinctrl {
+	aspeed,external-nodes = <&gfx &lhc>;
+};
+
+&pwm_tacho {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pwm0_default
+			&pinctrl_pwm1_default
+			&pinctrl_pwm2_default
+			&pinctrl_pwm3_default
+			&pinctrl_pwm4_default
+			&pinctrl_pwm5_default
+			&pinctrl_pwm6_default
+			&pinctrl_pwm7_default>;
+
+	status = "okay";
+
+	fan at 0 {
+		reg = <0x00>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x00 0x08>;
+	};
+
+	fan at 1 {
+		reg = <0x01>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x01 0x09>;
+	};
+
+	fan at 2 {
+		reg = <0x02>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x02 0x0a>;
+	};
+
+	fan at 3 {
+		reg = <0x03>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x03 0x0b>;
+	};
+
+	fan at 4 {
+		reg = <0x04>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x04 0x0c>;
+	};
+
+	fan at 5 {
+		reg = <0x05>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x05 0x0d>;
+	};
+
+	fan at 6 {
+		reg = <0x06>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x06 0x0e>;
+	};
+
+	fan at 7 {
+		reg = <0x07>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x07 0x0f>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_spi1_default>;
+
+	status = "okay";
+
+	// Host BIOS/UEFI EEPROM
+	flash at 0 {
+		m25p,fast-read;
+		label = "pnor";
+		spi-max-frequency = <100000000>;
+		status = "okay";
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			tfa at 400000 {
+				reg = <0x400000 0x200000>;
+				label = "pnor-tfa";
+			};
+
+			uefi at 600000 {
+				reg = <0x600000 0x1A00000>;
+				label = "pnor-uefi";
+			};
+		};
+	};
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_txd1_default
+			 &pinctrl_rxd1_default
+			 &pinctrl_ncts1_default
+			 &pinctrl_nrts1_default>;
+
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_txd2_default
+			&pinctrl_rxd2_default>;
+
+	status = "okay";
+};
+
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_txd3_default
+			&pinctrl_rxd3_default>;
+
+	status = "okay";
+};
+
+&uart4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_txd4_default
+			&pinctrl_rxd4_default>;
+
+	status = "okay";
+};
+
+// The BMC's uart
+&uart5 {
+	status = "okay";
+};
+
+&vhub {
+	status = "okay";
+};
+
+&video {
+	memory-region = <&video_engine_memory>;
+
+	status = "okay";
+};
-- 
2.47.3



From rebecca at bsdio.com  Thu Dec  4 13:02:36 2025
From: rebecca at bsdio.com (Rebecca Cran)
Date: Thu,  4 Dec 2025 14:02:36 -0700
Subject: [PATCH v3 3/3] dt-bindings: hwmon: (aspeed,g5-pwm-tacho) Move info from txt to yaml
In-Reply-To: <20251204210238.40742-1-rebecca@bsdio.com>
References: <20251204210238.40742-1-rebecca@bsdio.com>
Message-ID: <20251204210238.40742-4-rebecca@bsdio.com>

Move the documentation for the aspeed,ast2400-pwm-tacho and
aspeed,ast2500-pwm-tacho devices from a text file to yaml file.

This allows for dts files containing these devices to be validated.

Where the text file documenation of required properties differ from the
implementation, prefer the implementation and update the schema to
match.

"#size-cells" was 1 but implementation is 0.
"#cooling-cells" was marked as required but appears optional.

In the fan subnode, "cooling-levels" is optional according to the code
in drivers/hwmon/aspeed-pwm-tacho.c.

Signed-off-by: Rebecca Cran <rebecca at bsdio.com>
---
 Documentation/devicetree/bindings/hwmon/aspeed,pwm-tacho.yaml | 91 ++++++++++++++++++++
 Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt  | 73 ----------------
 2 files changed, 91 insertions(+), 73 deletions(-)

diff --git a/Documentation/devicetree/bindings/hwmon/aspeed,pwm-tacho.yaml b/Documentation/devicetree/bindings/hwmon/aspeed,pwm-tacho.yaml
new file mode 100644
index 000000000000..b23c3519604b
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwmon/aspeed,pwm-tacho.yaml
@@ -0,0 +1,91 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2023 Aspeed, Inc.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/hwmon/aspeed,g5-pwm-tacho.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ASPEED AST2400/AST2500 PWM and Fan Tacho controller
+
+maintainers:
+  - Billy Tsai <billy_tsai at aspeedtech.com>
+
+description: |
+  The ASPEED PWM controller can support up to 8 PWM outputs. The ASPEED Fan
+  Tacho controller can support up to 16 Fan tachometer inputs.
+
+  There can be up to 8 fans supported. Each fan can have one PWM output and
+  one/two Fan tach inputs.
+
+properties:
+  compatible:
+    enum:
+      - aspeed,ast2400-pwm-tacho
+      - aspeed,ast2500-pwm-tacho
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+patternProperties:
+  "^fan@[0-9]+$":
+    $ref: fan-common.yaml#
+    unevaluatedProperties: false
+    properties:
+      aspeed,fan-tach-ch:
+        description:
+          The tach channel used for the fan.
+        $ref: /schemas/types.yaml#/definitions/uint8-array
+
+    required:
+      - reg
+      - aspeed,fan-tach-ch
+
+required:
+  - compatible
+  - "#address-cells"
+  - "#size-cells"
+  - reg
+  - pinctrl-names
+  - pinctrl-0
+  - clocks
+  - resets
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/aspeed-clock.h>
+    pwm_tacho: pwmtachocontroller at 1e786000 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        #cooling-cells = <2>;
+        reg = <0x1E786000 0x1000>;
+        compatible = "aspeed,ast2500-pwm-tacho";
+        clocks = <&syscon ASPEED_CLK_APB>;
+        resets = <&syscon ASPEED_RESET_PWM>;
+        pinctrl-names = "default";
+        pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default>;
+
+        fan at 0 {
+                reg = <0x00>;
+                cooling-levels = /bits/ 8 <125 151 177 203 229 255>;
+                aspeed,fan-tach-ch = /bits/ 8 <0x00>;
+        };
+
+        fan at 1 {
+                reg = <0x01>;
+                aspeed,fan-tach-ch = /bits/ 8 <0x01 0x02>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt b/Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt
deleted file mode 100644
index 8645cd3b867a..000000000000
--- a/Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt
+++ /dev/null
@@ -1,73 +0,0 @@
-ASPEED AST2400/AST2500 PWM and Fan Tacho controller device driver
-
-The ASPEED PWM controller can support upto 8 PWM outputs. The ASPEED Fan Tacho
-controller can support upto 16 Fan tachometer inputs.
-
-There can be upto 8 fans supported. Each fan can have one PWM output and
-one/two Fan tach inputs.
-
-Required properties for pwm-tacho node:
-- #address-cells : should be 1.
-
-- #size-cells : should be 1.
-
-- #cooling-cells: should be 2.
-
-- reg : address and length of the register set for the device.
-
-- pinctrl-names : a pinctrl state named "default" must be defined.
-
-- pinctrl-0 : phandle referencing pin configuration of the PWM ports.
-
-- compatible : should be "aspeed,ast2400-pwm-tacho" for AST2400 and
-	       "aspeed,ast2500-pwm-tacho" for AST2500.
-
-- clocks : phandle to clock provider with the clock number in the second cell
-
-- resets : phandle to reset controller with the reset number in the second cell
-
-fan subnode format:
-===================
-Under fan subnode there can upto 8 child nodes, with each child node
-representing a fan. If there are 8 fans each fan can have one PWM port and
-one/two Fan tach inputs.
-For PWM port can be configured cooling-levels to create cooling device.
-Cooling device could be bound to a thermal zone for the thermal control.
-
-Required properties for each child node:
-- reg : should specify PWM source port.
-	integer value in the range 0 to 7 with 0 indicating PWM port A and
-	7 indicating PWM port H.
-
-- cooling-levels: PWM duty cycle values in a range from 0 to 255
-                  which correspond to thermal cooling states.
-
-- aspeed,fan-tach-ch : should specify the Fan tach input channel.
-                integer value in the range 0 through 15, with 0 indicating
-		Fan tach channel 0 and 15 indicating Fan tach channel 15.
-		At least one Fan tach input channel is required.
-
-Examples:
-
-pwm_tacho: pwmtachocontroller at 1e786000 {
-	#address-cells = <1>;
-	#size-cells = <1>;
-	#cooling-cells = <2>;
-	reg = <0x1E786000 0x1000>;
-	compatible = "aspeed,ast2500-pwm-tacho";
-	clocks = <&syscon ASPEED_CLK_APB>;
-	resets = <&syscon ASPEED_RESET_PWM>;
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default>;
-
-	fan at 0 {
-		reg = <0x00>;
-		cooling-levels = /bits/ 8 <125 151 177 203 229 255>;
-		aspeed,fan-tach-ch = /bits/ 8 <0x00>;
-	};
-
-	fan at 1 {
-		reg = <0x01>;
-		aspeed,fan-tach-ch = /bits/ 8 <0x01 0x02>;
-	};
-};
-- 
2.47.3



From rebecca at bsdio.com  Thu Dec  4 13:02:34 2025
From: rebecca at bsdio.com (Rebecca Cran)
Date: Thu,  4 Dec 2025 14:02:34 -0700
Subject: [PATCH v3 1/3] dt-bindings: arm: aspeed: add ASRock Rack ALTRAD8 board
In-Reply-To: <20251204210238.40742-1-rebecca@bsdio.com>
References: <20251204210238.40742-1-rebecca@bsdio.com>
Message-ID: <20251204210238.40742-2-rebecca@bsdio.com>

Document ASRock Rack ALTRAD8 (ALTRAD8UD-1L2T and ALTRAD8UD2-1L2Q)
compatibles.

Signed-off-by: Rebecca Cran <rebecca at bsdio.com>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
 Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
index aedefca7cf4a..049e86107c50 100644
--- a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
+++ b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
@@ -34,6 +34,7 @@ properties:
               - amd,ethanolx-bmc
               - ampere,mtjade-bmc
               - aspeed,ast2500-evb
+              - asrock,altrad8-bmc
               - asrock,e3c246d4i-bmc
               - asrock,e3c256d4i-bmc
               - asrock,romed8hm3-bmc
-- 
2.47.3



From amitsd at google.com  Thu Dec  4 13:06:39 2025
From: amitsd at google.com (Amit Sunil Dhamne)
Date: Thu, 4 Dec 2025 13:06:39 -0800
Subject: [PATCH 1/6] dt-bindings: power: supply: Add Maxim MAX77759
 charger
In-Reply-To: <076777c3-b238-4d1d-a11b-602027348ee4@kernel.org>
References: <20251123-max77759-charger-v1-0-6b2e4b8f7f54@google.com>
 <20251123-max77759-charger-v1-1-6b2e4b8f7f54@google.com>
 <d4455f4b-2a0f-4bc0-b897-14f2e27af3ea@kernel.org>
 <c9b059f8-9219-4219-95c8-23a3733fea58@google.com>
 <20251125-amorphous-bobcat-of-whirlwind-afdab1@kuoka>
 <7ad91325-e881-461d-b39e-6ff15d98b3c5@google.com>
 <076777c3-b238-4d1d-a11b-602027348ee4@kernel.org>
Message-ID: <19e501f4-da1b-4a91-8681-da78922bc302@google.com>


On 12/2/25 5:00 AM, Krzysztof Kozlowski wrote:
> On 26/11/2025 00:48, Amit Sunil Dhamne wrote:
>> On 11/25/25 1:56 AM, Krzysztof Kozlowski wrote:
>>> On Sun, Nov 23, 2025 at 06:34:05PM -0800, Amit Sunil Dhamne wrote:
>>>> Hi Krzysztof,
>>>>
>>>> On 11/23/25 1:28 AM, Krzysztof Kozlowski wrote:
>>>>> On 23/11/2025 09:35, Amit Sunil Dhamne via B4 Relay wrote:
>>>>>> From: Amit Sunil Dhamne <amitsd at google.com>
>>>>>>
>>>>>> Add bindings for Maxim max77759 charger device.
>>>>>>
>>>>>> Signed-off-by: Amit Sunil Dhamne <amitsd at google.com>
>>>>>> ---
>>>>>>    .../power/supply/maxim,max77759-charger.yaml       | 36 ++++++++++++++++++++++
>>>>>>    1 file changed, 36 insertions(+)
>>>>>>
>>>>>> diff --git a/Documentation/devicetree/bindings/power/supply/maxim,max77759-charger.yaml b/Documentation/devicetree/bindings/power/supply/maxim,max77759-charger.yaml
>>>>>> new file mode 100644
>>>>>> index 000000000000..71f866419774
>>>>>> --- /dev/null
>>>>>> +++ b/Documentation/devicetree/bindings/power/supply/maxim,max77759-charger.yaml
>>>>>> @@ -0,0 +1,36 @@
>>>>>> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
>>>>>> +%YAML 1.2
>>>>>> +---
>>>>>> +$id: http://devicetree.org/schemas/power/supply/maxim,max77759-charger.yaml#
>>>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>>>>> +
>>>>>> +title: Maxim Integrated MAX77759 Battery charger
>>>>>> +
>>>>>> +maintainers:
>>>>>> +  - Amit Sunil Dhamne <amitsd at google.com>
>>>>>> +
>>>>>> +description: |
>>>>>> +  This module is part of the MAX77759 PMIC. For additional information, see
>>>>>> +  Documentation/devicetree/bindings/mfd/maxim,max77759.yaml.
>>>>>> +
>>>>>> +  The Maxim MAX77759 is a dual input switch mode battery charger for portable
>>>>>> +  applications. It supports wired and wireless charging and can operate in buck
>>>>>> +  and boost mode.
>>>>>> +
>>>>>> +allOf:
>>>>>> +  - $ref: power-supply.yaml#
>>>>>> +
>>>>>> +properties:
>>>>>> +  compatible:
>>>>>> +    const: maxim,max77759-charger
>>>>>> +
>>>>> This should be just folded into parent node, no need for separate
>>>>> charger device or is just incomplete.
>>>> Thanks for the review! You are right, the binding is incomplete. This
>>>> charger block actually listens on its own I2C address, distinct from the
>>>> main PMIC.
>>>>
>>>> I will update v2 to include the reg property. I will also add the
>>> AFAIK, the main (parent) device schema does not reference children via
>>> any sort of addressing, so reg here would not be suitable.
>> I agree that currently nvmem and gpio devices (which are children of
>> PMIC device) are not referenced using any address. But I was guessing
>> that's because they share the i2c client id with the PMIC and sharing
>> its address space (implied).
>>
>> The charger device while being part of the MAX77759 PMIC package has
>> it's own i2c client id and address space that's why I proposed "reg".
>> The underlying assumption I made was separate client id implies that a
>> "reg" property required. But maybe that's incorrect.
>>
>> I can understand the argument against having a "reg" property. As the
>> i2c client id will remain same for a max77759 charger device (as it's a
>> chip property and not a board property) it will always remain a
>> constant. I will drop the "reg" proposal.
>>
>>
>>>> standard properties `constant-charge-current-max-microamp` and
>>>> `constant-charge-voltage-max-microvolt` to configure the hardware
>>>> limits, as this charger device does not manage the battery profile
>>>> directly (that is handled by a separate fuel gauge).
>>> Well, still, what's the benefit for the bindings to have it as a
>>> separate child? Kind of depends on your example, which is quite small -
>>> one regulator and supply. Grow the example with battery and other
>>> independent resources (if they are) to justify it. Or show arguments why
>>> this is re-usable.
>> The primary reasons for keeping the charger as a distinct child node are
>> to model the hardware topology for the power supply subsystem and to
> You do not need children for that at all.

Actually what you said makes sense. I will fold the charger's schema 
into mfd/maxim,max77759's schema.


Thanks,

Amit

>> house the OTG regulator provided by the charger block.
>> The charger needs to be referenced by the Fuel Gauge (which handles the
>> battery profile) via power-supplies. Additionally, the charger block
>> provides a regulator for USB OTG VBUS, which is cleaner to represent as
>> a child node of the charger rather than mixing it into the top-level
>> PMIC node.
> Sorry but argument that you need a child device to be able to construct
> a phandle is just wrong. You can create phandles on every other way as well.
>
>
> Best regards,
> Krzysztof


From rebecca at bsdio.com  Thu Dec  4 13:12:44 2025
From: rebecca at bsdio.com (Rebecca Cran)
Date: Thu, 4 Dec 2025 14:12:44 -0700
Subject: [PATCH v3 3/3] dt-bindings: hwmon: (aspeed,g5-pwm-tacho) Move
 info from txt to yaml
In-Reply-To: <20251204210238.40742-4-rebecca@bsdio.com>
References: <20251204210238.40742-1-rebecca@bsdio.com>
 <20251204210238.40742-4-rebecca@bsdio.com>
Message-ID: <4e61c405-8495-4285-b848-04398f87ac9b@bsdio.com>

On 12/4/25 14:02, Rebecca Cran wrote:
> diff --git a/Documentation/devicetree/bindings/hwmon/aspeed,pwm-tacho.yaml b/Documentation/devicetree/bindings/hwmon/aspeed,pwm-tacho.yaml
> new file mode 100644
> index 000000000000..b23c3519604b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/hwmon/aspeed,pwm-tacho.yaml
> @@ -0,0 +1,91 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +# Copyright (C) 2023 Aspeed, Inc.
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/hwmon/aspeed,g5-pwm-tacho.yaml#

When I renamed the file from aspeed,g5-pwm-tacho.yaml I forgot to update 
this id line.
I'll send out a v4 patch in a couple of days to gather any other early 
feedback.

-- 
Rebecca Cran



From Anatoliy.Klymenko at amd.com  Thu Dec  4 13:16:17 2025
From: Anatoliy.Klymenko at amd.com (Klymenko, Anatoliy)
Date: Thu, 4 Dec 2025 21:16:17 +0000
Subject: [PATCH 3/3] drm: zynqmp: Add blend mode property to graphics
 plane
In-Reply-To: <7f7423e9-809d-4023-be01-db59e6dd755e@linux.dev>
References: <20251113203715.2768107-1-sean.anderson@linux.dev>
 <20251113203715.2768107-4-sean.anderson@linux.dev>
 <MW4PR12MB716514EB76EE4585605D0E5AE6CDA@MW4PR12MB7165.namprd12.prod.outlook.com>
 <b97065ce-2dc0-453b-ab8e-b2d134fc3467@linux.dev>
 <MW4PR12MB7165C437114B30DB21702365E6CBA@MW4PR12MB7165.namprd12.prod.outlook.com>
 <7f7423e9-809d-4023-be01-db59e6dd755e@linux.dev>
Message-ID: <MW4PR12MB7165CDDB17CF0855EA19AACDE6A6A@MW4PR12MB7165.namprd12.prod.outlook.com>

[AMD Official Use Only - AMD Internal Distribution Only]

Hi Sean,

> -----Original Message-----
> From: Sean Anderson <sean.anderson at linux.dev>
> Sent: Monday, November 17, 2025 7:36 AM
> To: Klymenko, Anatoliy <Anatoliy.Klymenko at amd.com>; Laurent Pinchart
> <laurent.pinchart at ideasonboard.com>; Tomi Valkeinen
> <tomi.valkeinen at ideasonboard.com>; dri-devel at lists.freedesktop.org
> Cc: linux-kernel at vger.kernel.org; Mike Looijmans <mike.looijmans at topic.nl>;
> David Airlie <airlied at gmail.com>; Thomas Zimmermann
> <tzimmermann at suse.de>; Maarten Lankhorst
> <maarten.lankhorst at linux.intel.com>; Maxime Ripard <mripard at kernel.org>;
> linux-arm-kernel at lists.infradead.org; Simona Vetter <simona at ffwll.ch>; Simek,
> Michal <michal.simek at amd.com>
> Subject: Re: [PATCH 3/3] drm: zynqmp: Add blend mode property to graphics
> plane
>
> Caution: This message originated from an External Source. Use proper caution
> when opening attachments, clicking links, or responding.
>
>
> On 11/14/25 19:12, Klymenko, Anatoliy wrote:
> > [AMD Official Use Only - AMD Internal Distribution Only]
> >
> >> -----Original Message-----
> >> From: dri-devel <dri-devel-bounces at lists.freedesktop.org> On Behalf Of
> Sean
> >> Anderson
> >> Sent: Thursday, November 13, 2025 3:07 PM
> >> To: Klymenko, Anatoliy <Anatoliy.Klymenko at amd.com>; Laurent Pinchart
> >> <laurent.pinchart at ideasonboard.com>; Tomi Valkeinen
> >> <tomi.valkeinen at ideasonboard.com>; dri-devel at lists.freedesktop.org
> >> Cc: linux-kernel at vger.kernel.org; Mike Looijmans
> <mike.looijmans at topic.nl>;
> >> David Airlie <airlied at gmail.com>; Thomas Zimmermann
> >> <tzimmermann at suse.de>; Maarten Lankhorst
> >> <maarten.lankhorst at linux.intel.com>; Maxime Ripard
> <mripard at kernel.org>;
> >> linux-arm-kernel at lists.infradead.org; Simona Vetter <simona at ffwll.ch>;
> Simek,
> >> Michal <michal.simek at amd.com>
> >> Subject: Re: [PATCH 3/3] drm: zynqmp: Add blend mode property to graphics
> >> plane
> >>
> >> Caution: This message originated from an External Source. Use proper
> caution
> >> when opening attachments, clicking links, or responding.
> >>
> >>
> >> On 11/13/25 18:03, Klymenko, Anatoliy wrote:
> >> > [AMD Official Use Only - AMD Internal Distribution Only]
> >> >
> >> > Hi Sean,
> >> >
> >> > Thank you for the patch.
> >> >
> >> >> -----Original Message-----
> >> >> From: Sean Anderson <sean.anderson at linux.dev>
> >> >> Sent: Thursday, November 13, 2025 12:37 PM
> >> >> To: Laurent Pinchart <laurent.pinchart at ideasonboard.com>; Tomi
> Valkeinen
> >> >> <tomi.valkeinen at ideasonboard.com>; dri-devel at lists.freedesktop.org
> >> >> Cc: linux-kernel at vger.kernel.org; Mike Looijmans
> >> <mike.looijmans at topic.nl>;
> >> >> David Airlie <airlied at gmail.com>; Thomas Zimmermann
> >> >> <tzimmermann at suse.de>; Maarten Lankhorst
> >> >> <maarten.lankhorst at linux.intel.com>; Klymenko, Anatoliy
> >> >> <Anatoliy.Klymenko at amd.com>; Maxime Ripard <mripard at kernel.org>;
> >> linux-
> >> >> arm-kernel at lists.infradead.org; Simona Vetter <simona at ffwll.ch>;
> Simek,
> >> >> Michal <michal.simek at amd.com>; Sean Anderson
> >> >> <sean.anderson at linux.dev>
> >> >> Subject: [PATCH 3/3] drm: zynqmp: Add blend mode property to graphics
> >> plane
> >> >>
> >> >> Caution: This message originated from an External Source. Use proper
> >> caution
> >> >> when opening attachments, clicking links, or responding.
> >> >>
> >> >>
> >> >> When global alpha is enabled, per-pixel alpha is ignored. Allow
> >> >> userspace to explicitly specify whether to use per-pixel alpha by
> >> >> exposing it through the blend mode property. I'm not sure whether the
> >> >> per-pixel alpha is pre-multiplied or not [1], but apparently it *must* be
> >> >> pre-multiplied so I guess we have to advertise it.
> >> >>
> >> >> [1] All we get is "The alpha value available with the graphics stream
> >> >>     will define the transparency of the graphics."
> >> >>
> >> >> Signed-off-by: Sean Anderson <sean.anderson at linux.dev>
> >> >> ---
> >> >>
> >> >>  drivers/gpu/drm/xlnx/zynqmp_kms.c | 24 ++++++++++++++++++++++--
> >> >>  1 file changed, 22 insertions(+), 2 deletions(-)
> >> >>
> >> >> diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c
> >> >> b/drivers/gpu/drm/xlnx/zynqmp_kms.c
> >> >> index 456ada9ac003..fa1cfc16db36 100644
> >> >> --- a/drivers/gpu/drm/xlnx/zynqmp_kms.c
> >> >> +++ b/drivers/gpu/drm/xlnx/zynqmp_kms.c
> >> >> @@ -61,6 +61,13 @@ static int
> zynqmp_dpsub_plane_atomic_check(struct
> >> >> drm_plane *plane,
> >> >>         if (!new_plane_state->crtc)
> >> >>                 return 0;
> >> >>
> >> >> +       if (new_plane_state->pixel_blend_mode !=
> >> >> DRM_MODE_BLEND_PIXEL_NONE &&
> >> >> +           new_plane_state->alpha >> 8 != 0xff) {
> >> >> +               drm_dbg_kms(plane->dev,
> >> >> +                           "Plane alpha must be 1.0 when using pixel alpha\n");
> >> >> +               return -EINVAL;
> >> >> +       }
> >> >> +
> >> >>         crtc_state = drm_atomic_get_crtc_state(state, new_plane_state-
> >crtc);
> >> >>         if (IS_ERR(crtc_state))
> >> >>                 return PTR_ERR(crtc_state);
> >> >> @@ -117,9 +124,13 @@ static void
> >> >> zynqmp_dpsub_plane_atomic_update(struct drm_plane *plane,
> >> >>
> >> >>         zynqmp_disp_layer_update(layer, new_state);
> >> >>
> >> >> -       if (plane->index == ZYNQMP_DPSUB_LAYER_GFX)
> >> >> -               zynqmp_disp_blend_set_global_alpha(dpsub->disp, true,
> >> >> +       if (plane->index == ZYNQMP_DPSUB_LAYER_GFX) {
> >> >> +               bool blend = plane->state->pixel_blend_mode ==
> >> >> +                            DRM_MODE_BLEND_PIXEL_NONE;
> >> >> +
> >> >> +               zynqmp_disp_blend_set_global_alpha(dpsub->disp, blend,
> >> >>                                                    plane->state->alpha >> 8);
> >> >> +       }
> >> >>
> >> >>         /*
> >> >>          * Unconditionally enable the layer, as it may have been disabled
> >> >> @@ -179,9 +190,18 @@ static int zynqmp_dpsub_create_planes(struct
> >> >> zynqmp_dpsub *dpsub)
> >> >>                         return ret;
> >> >>
> >> >>                 if (i == ZYNQMP_DPSUB_LAYER_GFX) {
> >> >> +                       unsigned int blend_modes =
> >> >> +                               BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> >> >> +                               BIT(DRM_MODE_BLEND_PREMULTI);
> >> >
> >> > | BIT(DRM_MODE_BLEND_COVERAGE) - this is what implemented in the
> >> hardware.
> >>
> >> Do you have a datasheet (or other) reference?
> >>
> >
> > Yes https://docs.amd.com/v/u/en-US/ug1085-zynq-ultrascale-trm
>
> There is no mention of this in the TRM.
>
> | Video Blending is defined for two RGB video streams. One of these
> | streams will be graphics that have an alpha value along with RGB
> | stream. The alpha value available with the graphics stream will define
> | the transparency of the graphics. Alpha value defined for blending
> | function is always 8-bit. 1-bit alpha and 4-bit alpha are also
> | supported, but these are scaled to 8-bits before they are used for
> | alpha blending
>
> Please quote a specific section where the alpha blending formula is
> documented.
>

Yes, there is no explicit alpha blending formula in the TRM, although
absence of "premultiplied alpha" term anywhere in the doc suggests that
alpha is treated as a straight. Anyways, I cooked a quick test that proved
the straight alpha theory: https://github.com/onotole/zynqmp-dp-alpha

> >> But in any case, DRM_MODE_BLEND_PREMULTI is mandatory even if we
> >> don't support
> >> it. See drm_plane_create_blend_mode_property for details.
> >>
> >
> > No doubts here
>
> OK, so regardless of what the hardware does, we have to pretend to
> support pre-multiplied alpha.
>

Yes, we my pretend so, or we may work around backward compatibility check
in drm_plane_create_blend_mode_property by setting blend mode to
DRM_MODE_BLEND_COVERAGE immediately and later reject plane states
with DRM_MODE_BLEND_PREMULTI mode.

> --Sean

Thank you,
Anatoliy

From robh at kernel.org  Thu Dec  4 13:28:25 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Thu, 4 Dec 2025 15:28:25 -0600
Subject: [PATCH V3 2/3] dt-bindings: iommu: Add NVIDIA Tegra CMDQV support
In-Reply-To: <20251201163219.3237266-3-amhetre@nvidia.com>
References: <20251201163219.3237266-1-amhetre@nvidia.com>
 <20251201163219.3237266-3-amhetre@nvidia.com>
Message-ID: <176488370517.2196325.5157844880170253515.robh@kernel.org>


On Mon, 01 Dec 2025 16:32:18 +0000, Ashish Mhetre wrote:
> The Command Queue Virtualization (CMDQV) hardware is part of the
> SMMUv3 implementation on NVIDIA Tegra SoCs. It assists in
> virtualizing the command queue for the SMMU.
> 
> Add a new device tree binding document for nvidia,tegra264-cmdqv.
> 
> Also update the arm,smmu-v3 binding to include an optional nvidia,cmdqv
> property. This property is a phandle to the CMDQV device node, allowing
> the SMMU driver to associate with its corresponding CMDQV instance.
> Restrict this property usage to Nvidia Tegra264 only.
> 
> Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
> ---
>  .../bindings/iommu/arm,smmu-v3.yaml           | 30 ++++++++++++-
>  .../bindings/iommu/nvidia,tegra264-cmdqv.yaml | 42 +++++++++++++++++++
>  2 files changed, 70 insertions(+), 2 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/iommu/nvidia,tegra264-cmdqv.yaml
> 

Reviewed-by: Rob Herring (Arm) <robh at kernel.org>



From pr-tracker-bot at kernel.org  Thu Dec  4 14:11:16 2025
From: pr-tracker-bot at kernel.org (pr-tracker-bot at kernel.org)
Date: Thu, 04 Dec 2025 22:11:16 +0000
Subject: [GIT PULL] pmdomain/cpuidle-psci updates for v6.19
In-Reply-To: <20251201175125.34284-1-ulf.hansson@linaro.org>
References: <20251201175125.34284-1-ulf.hansson@linaro.org>
Message-ID: <176488627629.997489.5449329879391180741.pr-tracker-bot@kernel.org>

The pull request you sent on Mon,  1 Dec 2025 18:51:25 +0100:

> git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm.git tags/pmdomain-v6.19

has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/52206f82d9244546e5790f5ad64465343aa7ffd5

Thank you!

-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html


From tan.siewert at hetzner.com  Thu Dec  4 14:29:16 2025
From: tan.siewert at hetzner.com (Tan Siewert)
Date: Thu, 4 Dec 2025 23:29:16 +0100
Subject: [PATCH v3 2/3] ARM: dts: aspeed: add device tree for ASRock Rack
 ALTRAD8 BMC
In-Reply-To: <20251204210238.40742-3-rebecca@bsdio.com>
References: <20251204210238.40742-1-rebecca@bsdio.com>
 <20251204210238.40742-3-rebecca@bsdio.com>
Message-ID: <aa75c5a4-27cf-4cc2-9851-07713999f469@hetzner.com>

Hiya,

Please see the comments below.

-- Tan

On 04.12.25 22:02, Rebecca Cran wrote:
> The ALTRAD8 BMC is an Aspeed AST2500-based BMC for the ASRock Rack
> ALTRAD8UD-1L2T and ALTRAD8UD2-1L2Q boards.
> 
> Signed-off-by: Rebecca Cran <rebecca at bsdio.com>
> ---
>   arch/arm/boot/dts/aspeed/Makefile                      |   1 +
>   arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts | 612 ++++++++++++++++++++
>   2 files changed, 613 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/aspeed/Makefile b/arch/arm/boot/dts/aspeed/Makefile
> index 0f0b5b707654..9fd42a30c56d 100644
> --- a/arch/arm/boot/dts/aspeed/Makefile
> +++ b/arch/arm/boot/dts/aspeed/Makefile
> @@ -9,6 +9,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \
>   	aspeed-bmc-ampere-mtjefferson.dtb \
>   	aspeed-bmc-ampere-mtmitchell.dtb \
>   	aspeed-bmc-arm-stardragon4800-rep2.dtb \
> +	aspeed-bmc-asrock-altrad8.dtb \
>   	aspeed-bmc-asrock-e3c246d4i.dtb \
>   	aspeed-bmc-asrock-e3c256d4i.dtb \
>   	aspeed-bmc-asrock-romed8hm3.dtb \
> diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts
> new file mode 100644
> index 000000000000..2696a8692607
> --- /dev/null
> +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts
> @@ -0,0 +1,612 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/dts-v1/;
> +
> +#include "aspeed-g5.dtsi"
> +#include <dt-bindings/gpio/aspeed-gpio.h>
> +#include <dt-bindings/leds/common.h>
> +#include <dt-bindings/i2c/i2c.h>
> +
> +/ {
> +	model = "ASRock ALTRAD8 BMC";
> +	compatible = "asrock,altrad8-bmc", "aspeed,ast2500";
> +
> +	aliases {
> +		serial4 = &uart5;
> +		i2c50 = &nvme1;
> +		i2c51 = &pcie4;
> +		i2c52 = &pcie5;
> +		i2c53 = &pcie6;
> +		i2c54 = &pcie7;
> +		i2c55 = &nvme3;
> +		i2c56 = &nvme2;
> +		i2c57 = &nvme0;
> +		i2c58 = &nvme4;
> +		i2c59 = &nvme5;
> +		i2c60 = &nvme6;
> +		i2c61 = &nvme7;
> +		i2c62 = &nvme8;
> +		i2c63 = &nvme9;
> +		i2c64 = &nvme10;
> +		i2c65 = &nvme11;
> +	};
> +
> +	chosen {
> +		stdout-path = "uart5:115200n8";
> +	};
> +
> +	iio-hwmon {
> +		compatible = "iio-hwmon";
> +		io-channels =	<&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>,
> +				<&adc 4> ,<&adc 5>, <&adc 6>, <&adc 7>,
> +				<&adc 8>, <&adc 9>, <&adc 10>, <&adc 11>,
> +				<&adc 12>, <&adc 13>, <&adc 14>, <&adc 15>;
> +	};
> +
> +	leds {
> +		compatible = "gpio-leds";
> +

What is the reason for the removal of the `system-fault` led?

> +		led-heartbeat {
> +			gpios = <&gpio ASPEED_GPIO(G,0) GPIO_ACTIVE_LOW>;
> +			label = "platform:green:heartbeat";
> +			color = <LED_COLOR_ID_GREEN>;
> +			function = LED_FUNCTION_INDICATOR;

Maybe add `linux,default-trigger = "timer";`?

> +		};
> +
> +		led-fan1-fault {
> +			retain-state-shutdown;
> +			default-state = "off";
> +			gpios = <&io_expander0 0 GPIO_ACTIVE_LOW>;
> +			label = "fan1:red:fault";
> +			color = <LED_COLOR_ID_RED>;
> +			function = LED_FUNCTION_FAULT;
> +		};
> +
> +		led-fan2-fault {
> +			retain-state-shutdown;
> +			default-state = "off";
> +			gpios = <&io_expander0 1 GPIO_ACTIVE_LOW>;
> +			label = "fan2:red:fault";
> +			color = <LED_COLOR_ID_RED>;
> +			function = LED_FUNCTION_FAULT;
> +		};
> +
> +		led-fan3-fault {
> +			retain-state-shutdown;
> +			default-state = "off";
> +			gpios = <&io_expander0 2 GPIO_ACTIVE_LOW>;
> +			label = "fan3:red:fault";
> +			color = <LED_COLOR_ID_RED>;
> +			function = LED_FUNCTION_FAULT;
> +		};
> +
> +		led-fan4-fault {
> +			retain-state-shutdown;
> +			default-state = "off";
> +			gpios = <&io_expander0 3 GPIO_ACTIVE_LOW>;
> +			label = "fan4:red:fault";
> +			color = <LED_COLOR_ID_RED>;
> +			function = LED_FUNCTION_FAULT;
> +		};
> +
> +		led-fan5-fault {
> +			retain-state-shutdown;
> +			default-state = "off";
> +			gpios = <&io_expander0 4 GPIO_ACTIVE_LOW>;
> +			label = "fan5:red:fault";
> +			color = <LED_COLOR_ID_RED>;
> +			function = LED_FUNCTION_FAULT;
> +		};
> +	};
> +
> +	memory at 80000000 {
> +		reg = <0x80000000 0x20000000>;
> +	};
> +
> +	reserved-memory {
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		ranges;
> +
> +		gfx_memory: framebuffer {
> +			compatible = "shared-dma-pool";
> +			size = <0x01000000>;
> +			alignment = <0x01000000>;
> +			reusable;
> +		};
> +
> +		vga_memory: framebuffer at 9f000000 {
> +			no-map;
> +			reg = <0x9f000000 0x01000000>; /* 16M */
> +		};
> +
> +		video_engine_memory: jpegbuffer {
> +			compatible = "shared-dma-pool";
> +			size = <0x02000000>;	/* 32M */
> +			alignment = <0x01000000>;
> +			reusable;
> +		};
> +	};
> +};
> +
> +&adc {
> +	status = "okay";

I'm not sure if you have to explicitly set pinctrl-0 for ADC.

> +};
> +
> +&fmc {
> +	status = "okay";
> +
> +	flash at 0 {
> +		label = "bmc";
> +		m25p,fast-read;
> +		spi-max-frequency = <50000000>;
> +		status = "okay";
> +#include "openbmc-flash-layout-64.dtsi"
> +	};
> +};
> +
> +&gfx {
> +	memory-region = <&gfx_memory>;
> +	status = "okay";
> +};
> +
> +&gpio {
> +	gpio-line-names =
> +	/*A0-A7*/	"","","","bmc-ready","","","","",
> +	/*B0-B7*/	"i2c-backup-sel","","","","","","","host0-shd-ack-n",
> +	/*C0-C7*/	"","","","","","","","",
> +	/*D0-D7*/	"power-button","power-out","button-reset",
> +			"host0-sysreset-n","","","power-chassis-good","",
> +	/*E0-E7*/	"","s0-vrd1-vddq0123-fault-n",
> +			"s0-vrd1-vddq4567-fault-n","s0-vrd0-vddc-fault-n",
> +			"s0-vrd3-p0v75-fault-n","","","",
> +	/*F0-F7*/	"","","ps-atx-on-n","","","","","",
> +	/*G0-G7*/	"led-identify","button-identify","","","uboot-ready",\

`button-identify` should be `button-identify-n` (active-low).

`led-system-fault-n` is GPIOG3.

`led-identify-n` _could_ be at GPIOQ6 (seems to be wired to the CPLD (?!)).

> +			"bmc-salt2-n","","",
> +	/*H0-H7*/	"ps-pwr-ok","uart1-mode1","uart2-mode1","uart3-mode1",
> +			"uart4-mode1","","led-bmc-heartbeat","",

GPIOH6 is `BMC_JTAG_SEL_S0`. The `led-bmc-hearbeat-n` should be GPIOG0.

> +	/*I0-I7*/	"","","","","","","","",
> +	/*J0-J7*/	"s0-hightemp-n","","","","","","","",
> +	/*K0-K7*/	"","","","","","","","",
> +	/*L0-L7*/	"","","","","","","","",
> +	/*M0-M7*/	"","","","","","s0-spi-auth-fail-n","","",
> +	/*N0-N7*/	"","","","","","","","",
> +	/*O0-O7*/	"","","","","","","","",
> +	/*P0-P7*/	"","","cpld-disable-bmc","","","","","",

`cpld-disable-bmc` should be `cpld-disable-bmc-n` and at GPIOM0 
(`CPLD_DISABLE_BMC_L` in schematic). GPIOP2 is a fan tacho.

> +	/*Q0-Q7*/	"","","ext-hightemp-n","","","","",

double assignment of `ext-hightemp-n`. Correct one is GPIOR2. Please 
remove it.

> +			"chassis-intrusion",

`chassis-intrusion-n` (active-low).

> +	/*R0-R7*/	"","","ext-hightemp-n","spi0-program-sel","",
> +			"hwm-bat-en","","",

`hwm-bat-en` could be prefixed with `output-`.

> +	/*S0-S7*/	"s0-vr-hot-n","","","bmc-sysreset-n","","","","",

GPIOS2 (`input-salt5-n`) _could_ be useful (comes from the X550 for WoL 
(`LAN_3V3STBY_ALRT_N` in schematic)).

> +	/*T0-T7*/	"","","","","","","","",
> +	/*U0-U7*/	"","","","","","","","",
> +	/*V0-V7*/	"","","","","","","","",
> +	/*W0-W7*/	"","","","","","","","",
> +	/*X0-X7*/	"","","","","","","","",
> +	/*Y0-Y7*/	"sio-s3","sio-s5","sio-pwr-req","sio-on-ctrl","","","","",
> +	/*Z0-Z7*/	"","sio-pwr-good","","s0-rtc-lock","","","","",

System has no Super-IO. Please remove the `sio-` assignments.

> +	/*AA0-AA7*/	"rtc-int","","","","","pmbus-sel-n","","",

`rtc-int` should be `s0-rtc-int-n`.

> +	/*AB0-AB7*/	"host0-reboot-ack-n","s0-sys-auth-failure-n",
> +			"","","","","","",
> +	/*AC0-AC7*/	"s0-fault-alert","host0-ready","s0-overtemp-n",
> +			"","bmc-ok","host0-special-boot","presence-cpu0",
> +			"host0-shd-req-n";
> +
> +	status = "okay";
> +};
> +
> +&i2c0 {
> +	status = "okay";
> +
> +	ipmb at 10 {
> +		compatible = "ipmb-dev";
> +		reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>;
> +		i2c-protocol;
> +	};
> +
> +};
> +
> +&i2c1 {
> +	status = "okay";
> +
> +	i2c-mux1 at 73 {
> +		compatible = "nxp,pca9548";
> +		reg = <0x73>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		i2c-mux-idle-disconnect;
> +
> +		nvme1: i2c at 0 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <0>;
> +		};
> +
> +		pcie4: i2c at 1 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <1>;
> +		};
> +
> +		pcie5: i2c at 2 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <2>;
> +		};
> +
> +		pcie6: i2c at 3 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <3>;
> +		};
> +
> +		pcie7: i2c at 4 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <4>;
> +		};
> +
> +		nvme3: i2c at 5 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <5>;
> +		};
> +
> +		nvme2: i2c at 6 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <6>;
> +		};
> +
> +		nvme0: i2c at 7 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <7>;
> +		};
> +	};
> +
> +	i2c-mux2 at 75 {
> +		compatible = "nxp,pca9548";
> +		reg = <0x75>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		i2c-mux-idle-disconnect;
> +
> +		nvme4: i2c at 0 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <0>;
> +		};
> +
> +		nvme5: i2c at 1 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <1>;
> +		};
> +
> +		nvme6: i2c at 2 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <2>;
> +		};
> +
> +		nvme7: i2c at 3 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <3>;
> +		};
> +
> +		nvme8: i2c at 4 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <4>;
> +		};
> +
> +		nvme9: i2c at 5 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <5>;
> +		};
> +
> +		nvme10: i2c at 6 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <6>;
> +		};
> +
> +		nvme11: i2c at 7 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <7>;
> +		};
> +	};
> +};
> +
> +&i2c2 {
> +	status = "okay";
> +
> +	smpro at 4f {
> +		compatible = "ampere,smpro";
> +		reg = <0x4f>;
> +	};
> +};
> +
> +&i2c3 {
> +	status = "okay";
> +
> +	// PSU FRU
> +	eeprom at 38 {
> +		compatible = "atmel,24c02";
> +		reg = <0x38>;
> +	};
> +};
> +
> +&i2c4 {
> +	status = "okay";
> +
> +	temperature-sensor at 29 {
> +		compatible = "nuvoton,nct7802";
> +		reg = <0x29>;
> +
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		channel at 0 { /* LTD */
> +			reg = <0>;
> +			status = "okay";
> +		};
> +
> +		channel at 1 { /* RTD1 */
> +			reg = <1>;
> +			sensor-type = "temperature";
> +			temperature-mode = "thermistor";
> +		};
> +
> +		channel at 2 { /* RTD2 */
> +			reg = <2>;
> +			sensor-type = "temperature";
> +			temperature-mode = "thermal-diode";
> +		};
> +	};
> +
> +	temperature-sensor at 4c {
> +		compatible = "nuvoton,w83773g";
> +		reg = <0x4c>;
> +	};
> +};
> +
> +&i2c5 {
> +	status = "okay";
> +};
> +
> +&i2c6 {
> +	status = "okay";
> +
> +	rtc at 6f {
> +		compatible = "isil,isl1208";
> +		reg = <0x6f>;
> +	};
> +};
> +
> +&i2c7 {
> +	status = "okay";
> +
> +	// BMC FRU
> +	eeprom at 57 {
> +		compatible = "atmel,24c128";
> +		reg = <0x57>;
> +
> +		nvmem-layout {
> +			compatible = "fixed-layout";
> +			#address-cells = <1>;
> +			#size-cells = <1>;
> +
> +			eth1_macaddress: macaddress at 3f80 {
> +				reg = <0x3f80 6>;
> +			};
> +
> +			eth0_macaddress: macaddress at 3f88 {
> +				reg = <0x3f88 6>;
> +			};

Please add a comment explaining that 0x3f88 as offset is indeed the MAC 
for eth0 / the RTL8211E interface and not a typo.

> +		};
> +	};
> +};
> +
> +&i2c8 {
> +	status = "okay";
> +
> +	io_expander0: gpio at 1c {
> +		compatible = "nxp,pca9557";
> +		reg = <0x1c>;
> +		gpio-controller;
> +		#gpio-cells = <2>;
> +	};
> +};
> +
> +&i2c9 {
> +	status = "okay";
> +};
> +
> +&i2c10 {
> +	status = "okay";
> +};
> +
> +&i2c11 {
> +	status = "okay";
> +};
> +
> +&i2c12 {

Please add a comment that this is the I2C Bus for accessing the SCP EEPROM.

> +	status = "okay";
> +};
> +
> +&i2c13 {
> +	status = "okay";
> +
> +	ssif-bmc at 10 {
> +		compatible = "ssif-bmc";
> +		reg = <0x10>;
> +	};
> +};
> +
> +// Connected to host Intel X550 (ALTRAD8UD-1L2T) or
> +// Broadcom BCM57414 (ALTRAD8UD2-1L2Q) interface

mac0 is unconnected for the ALTRAD8UD-1L (not 1L2T).

> +&mac0 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_rmii1_default>;
> +	clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
> +		 <&syscon ASPEED_CLK_MAC1RCLK>;
> +	clock-names = "MACCLK", "RCLK";
> +	use-ncsi;
> +	nvmem-cells = <&eth0_macaddress>;
> +	nvmem-cell-names = "mac-address";
> +
> +	status = "okay";
> +};
> +
> +// Connected to Realtek RTL8211E
> +&mac1 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>;
> +
> +	nvmem-cells = <&eth1_macaddress>;
> +	nvmem-cell-names = "mac-address";
> +
> +	status = "okay";
> +};
> +
> +&pinctrl {
> +	aspeed,external-nodes = <&gfx &lhc>;
> +};
> +
> +&pwm_tacho {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_pwm0_default
> +			&pinctrl_pwm1_default
> +			&pinctrl_pwm2_default
> +			&pinctrl_pwm3_default
> +			&pinctrl_pwm4_default
> +			&pinctrl_pwm5_default
> +			&pinctrl_pwm6_default
> +			&pinctrl_pwm7_default>;
> +
> +	status = "okay";
> +
> +	fan at 0 {
> +		reg = <0x00>;
> +		aspeed,fan-tach-ch = /bits/ 8 <0x00 0x08>;
> +	};
> +
> +	fan at 1 {
> +		reg = <0x01>;
> +		aspeed,fan-tach-ch = /bits/ 8 <0x01 0x09>;
> +	};
> +
> +	fan at 2 {
> +		reg = <0x02>;
> +		aspeed,fan-tach-ch = /bits/ 8 <0x02 0x0a>;
> +	};
> +
> +	fan at 3 {
> +		reg = <0x03>;
> +		aspeed,fan-tach-ch = /bits/ 8 <0x03 0x0b>;
> +	};
> +
> +	fan at 4 {
> +		reg = <0x04>;
> +		aspeed,fan-tach-ch = /bits/ 8 <0x04 0x0c>;
> +	};
> +
> +	fan at 5 {
> +		reg = <0x05>;
> +		aspeed,fan-tach-ch = /bits/ 8 <0x05 0x0d>;
> +	};
> +
> +	fan at 6 {
> +		reg = <0x06>;
> +		aspeed,fan-tach-ch = /bits/ 8 <0x06 0x0e>;
> +	};
> +
> +	fan at 7 {
> +		reg = <0x07>;
> +		aspeed,fan-tach-ch = /bits/ 8 <0x07 0x0f>;
> +	};
> +};
> +
> +&spi1 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_spi1_default>;
> +
> +	status = "okay";
> +
> +	// Host BIOS/UEFI EEPROM
> +	flash at 0 {
> +		m25p,fast-read;
> +		label = "pnor";
> +		spi-max-frequency = <100000000>;
> +		status = "okay";
> +
> +		partitions {
> +			compatible = "fixed-partitions";
> +			#address-cells = <1>;
> +			#size-cells = <1>;
> +
> +			tfa at 400000 {
> +				reg = <0x400000 0x200000>;
> +				label = "pnor-tfa";
> +			};
> +
> +			uefi at 600000 {
> +				reg = <0x600000 0x1A00000>;
> +				label = "pnor-uefi";
> +			};
> +		};
> +	};
> +};
> +
> +&uart1 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_txd1_default
> +			 &pinctrl_rxd1_default
> +			 &pinctrl_ncts1_default
> +			 &pinctrl_nrts1_default>;
> +
> +	status = "okay";
> +};
> +
> +&uart2 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_txd2_default
> +			&pinctrl_rxd2_default>;
> +
> +	status = "okay";
> +};
> +
> +&uart3 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_txd3_default
> +			&pinctrl_rxd3_default>;
> +
> +	status = "okay";
> +};
> +
> +&uart4 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_txd4_default
> +			&pinctrl_rxd4_default>;
> +
> +	status = "okay";
> +};
> +
> +// The BMC's uart
> +&uart5 {
> +	status = "okay";
> +};
> +
> +&vhub {
> +	status = "okay";
> +};
> +
> +&video {
> +	memory-region = <&video_engine_memory>;
> +
> +	status = "okay";
> +};

-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature.asc
Type: application/pgp-signature
Size: 840 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251204/26d1fda3/attachment-0001.sig>

From Anatoliy.Klymenko at amd.com  Thu Dec  4 14:33:06 2025
From: Anatoliy.Klymenko at amd.com (Klymenko, Anatoliy)
Date: Thu, 4 Dec 2025 22:33:06 +0000
Subject: [PATCH 2/3] drm: zynqmp: Make the video plane primary
In-Reply-To: <7248b96f-be82-4b89-87e4-f86b3898bc55@linux.dev>
References: <20251113203715.2768107-1-sean.anderson@linux.dev>
 <20251113203715.2768107-3-sean.anderson@linux.dev>
 <MW4PR12MB71651E0E82AD8E4898DBD017E6CDA@MW4PR12MB7165.namprd12.prod.outlook.com>
 <680bee12-6bac-4634-8a02-4b1717a90aa2@linux.dev>
 <MW4PR12MB7165F8413848B53CB8C7C031E6CBA@MW4PR12MB7165.namprd12.prod.outlook.com>
 <7248b96f-be82-4b89-87e4-f86b3898bc55@linux.dev>
Message-ID: <MW4PR12MB7165FECBD72C189B803D859AE6A6A@MW4PR12MB7165.namprd12.prod.outlook.com>

[AMD Official Use Only - AMD Internal Distribution Only]

Hi Sean,

> -----Original Message-----
> From: Sean Anderson <sean.anderson at linux.dev>
> Sent: Monday, November 17, 2025 8:10 AM
> To: Klymenko, Anatoliy <Anatoliy.Klymenko at amd.com>; Laurent Pinchart
> <laurent.pinchart at ideasonboard.com>; Tomi Valkeinen
> <tomi.valkeinen at ideasonboard.com>; dri-devel at lists.freedesktop.org
> Cc: linux-kernel at vger.kernel.org; Mike Looijmans <mike.looijmans at topic.nl>;
> David Airlie <airlied at gmail.com>; Thomas Zimmermann
> <tzimmermann at suse.de>; Maarten Lankhorst
> <maarten.lankhorst at linux.intel.com>; Maxime Ripard <mripard at kernel.org>;
> linux-arm-kernel at lists.infradead.org; Simona Vetter <simona at ffwll.ch>; Simek,
> Michal <michal.simek at amd.com>
> Subject: Re: [PATCH 2/3] drm: zynqmp: Make the video plane primary
>
> Caution: This message originated from an External Source. Use proper caution
> when opening attachments, clicking links, or responding.
>
>
> On 11/14/25 19:57, Klymenko, Anatoliy wrote:
> > [AMD Official Use Only - AMD Internal Distribution Only]
> >
> >> -----Original Message-----
> >> From: dri-devel <dri-devel-bounces at lists.freedesktop.org> On Behalf Of
> Sean
> >> Anderson
> >> Sent: Thursday, November 13, 2025 2:52 PM
> >> To: Klymenko, Anatoliy <Anatoliy.Klymenko at amd.com>; Laurent Pinchart
> >> <laurent.pinchart at ideasonboard.com>; Tomi Valkeinen
> >> <tomi.valkeinen at ideasonboard.com>; dri-devel at lists.freedesktop.org
> >> Cc: linux-kernel at vger.kernel.org; Mike Looijmans
> <mike.looijmans at topic.nl>;
> >> David Airlie <airlied at gmail.com>; Thomas Zimmermann
> >> <tzimmermann at suse.de>; Maarten Lankhorst
> >> <maarten.lankhorst at linux.intel.com>; Maxime Ripard
> <mripard at kernel.org>;
> >> linux-arm-kernel at lists.infradead.org; Simona Vetter <simona at ffwll.ch>;
> Simek,
> >> Michal <michal.simek at amd.com>
> >> Subject: Re: [PATCH 2/3] drm: zynqmp: Make the video plane primary
> >>
> >> Caution: This message originated from an External Source. Use proper
> caution
> >> when opening attachments, clicking links, or responding.
> >>
> >>
> >> On 11/13/25 17:45, Klymenko, Anatoliy wrote:
> >> > [AMD Official Use Only - AMD Internal Distribution Only]
> >> >
> >> > Hi Sean,
> >> >
> >> > Thanks a lot for the patch (and tackling the alpha issue in general)
> >> >
> >> >> -----Original Message-----
> >> >> From: Sean Anderson <sean.anderson at linux.dev>
> >> >> Sent: Thursday, November 13, 2025 12:37 PM
> >> >> To: Laurent Pinchart <laurent.pinchart at ideasonboard.com>; Tomi
> Valkeinen
> >> >> <tomi.valkeinen at ideasonboard.com>; dri-devel at lists.freedesktop.org
> >> >> Cc: linux-kernel at vger.kernel.org; Mike Looijmans
> >> <mike.looijmans at topic.nl>;
> >> >> David Airlie <airlied at gmail.com>; Thomas Zimmermann
> >> >> <tzimmermann at suse.de>; Maarten Lankhorst
> >> >> <maarten.lankhorst at linux.intel.com>; Klymenko, Anatoliy
> >> >> <Anatoliy.Klymenko at amd.com>; Maxime Ripard <mripard at kernel.org>;
> >> linux-
> >> >> arm-kernel at lists.infradead.org; Simona Vetter <simona at ffwll.ch>;
> Simek,
> >> >> Michal <michal.simek at amd.com>; Sean Anderson
> >> >> <sean.anderson at linux.dev>
> >> >> Subject: [PATCH 2/3] drm: zynqmp: Make the video plane primary
> >> >>
> >> >> Caution: This message originated from an External Source. Use proper
> >> caution
> >> >> when opening attachments, clicking links, or responding.
> >> >>
> >> >>
> >> >> The zynqmp has two planes: "video" and "graphics". The video plane
> >> >>
> >> >> - Is on the bottom (zpos=0) (except when chroma keying as the master
> >> plane)
> >> >> - Supports "live" input (e.g. from an external source)
> >> >> - Supports RGB, YUV, and YCbCr formats, including XRGB8888
> >> >> - Does not support transparency, except via chroma keying (colorkey)
> >> >> - Must cover the entire screen (translation/resizing not supported)
> >> >>
> >> >> The graphics plane
> >> >>
> >> >> - Is on the top (zpos=1)
> >> >> - Supports "live" input (e.g. from an external source)
> >> >> - Supports RGB and YUV444 formats, but not XRGB8888
> >> >> - Supports transparency either via
> >> >>   - Global alpha channel, which disables per-pixel alpha when enabled
> >> >>   - Per-pixel alpha, which cannot be used with global alpha
> >> >>   - Chroma keying (colorkey)
> >> >> - Must cover the entire screen (translation/resizing not supported)
> >> >>
> >> >> Currently the graphics plane is the primary plane. Make the video plane
> >> >> the primary plane:
> >> >>
> >> >> - The video plane supports XRGB8888, which is the default 24-bit
> >> >>   colorspace for X. This results in improved performance when compared
> >> >>   to RGB565.
> >> >> - The graphics plane can be used as an overlay because it has a higher
> >> >>   z-pos and supports a per-pixel alpha channel. Unfortunately, clients
> >> >>   like weston cannot currently take advantage of this because they
> >> >>   expect overlay planes to support translation/resizing.
> >> >>
> >> >> One downside to this approach could be that the graphics plane has
> worse
> >> >> support for YUV and YCBCr, so it may be more difficult to compose video
> >> >
> >> > Not just more difficult but practically impossible:
> >> > 1. GFX (in Xilinx terminology) plane doesn't support pixel upscaling, so
> >> > no support for NV12, YUY2 and other common video pixel formats.
> >> > 2. Both planes are unscalable, this means we can only output native
> >> > display resolution video on the top plane, or display thick black frame
> >> > around the picture. We are losing GFX masking capabilities.
> >>
> >> The graphics masking capabilities are the same as they always were.
> >>
> >> > 3. We won't be able to render subtitles on top of the video.
> >> > Probably the only practical video player option remains here is to render
> >> > video to a texture and embed it into graphics composition.
> >>
> >> OK, but none of this is currently possible either because of the global
> >> alpha setting. So do you have a specific program in mind that plays
> >> video and will do it with an "underlay" plane?
> >>
> >
> > webOS, Roku OS, just to name a few. But most importantly, AMD has quite
> > a few customers using "underlay" plane because of its YUV 420 capability.
>
> Can you link to a specific example where the plane is selected based on
> its primary/overlay status and not based on its format support?  I'm not
> too familiar with these distros, but e.g. [1] selects the plane based on
> the format, and doesn't care which one is primary.
>

The plane selection by the type may not be explicit. For instance, if a
graphics compositor uses legacy API with drmModeSetCrtc, it would allocate
the primary plane implicitly. Or some compositor may just rely on planes
z-order. For instance, here [2] you may see exact z-order WebOS compositor
expects from the HW planes (both VideoPlane and FullscreenPlane are used
for the video playback, the graphics lives on MainPlane). Anyways, the
probability of primary plane being reserved for a graphics compositor is
too high to ignore.
Back to example [1], in our case the renderer would fail this check:
if ((ovr->possible_crtcs & (1 << pipe)) && !ovr->crtc_id)
for the primary plane pre-occupied by the graphics, and this check:
if (!format_support(ovr, p->fourcc))
for the overlay plane lacking pixel upsampling support.

[2] https://github.com/webosose/luna-surfacemanager/blob/b2fef6f73232244f6f13102aa66d2d3f5942835e/modules/weboscompositor/webossurfaceitem.cpp#L1794

> --Sean
>
> [1] https://github.com/webosose/omx-
> components/blob/27b33e17c25023f2c7ffbbfda10169fb500dacdc/src/omxdrm/vid
> eorenderer.cpp#L469
>
> >> >> streams into the window of a media player. However, no existing software
> >> >> could rely on this because there is no way to enable the per-pixel alpha
> >> >> channel when the graphics plane is enabled. This makes it impossible to
> >> >
> >> > This situation is a driver bug not a fatum.
> >>
> >> And yet the driver bug provides ample evidence that no one is doing this,
> >> so we don't need to worry about it.
> >>
> >> --Sean
> >>
> >> > Per pixel alpha blending works
> >> > just fine if we disable global alpha. We just need to avoid enabling it when
> >> > we have alpha capable GFX plane format.
> >> >
> >> >> "carve out" an area in the graphics plane where the video plane shows
> >> >> through. This limitation is addressed in the next patch, but it means we
> >> >> do not need to worry about compatibility in this area.
> >> >>
> >> >> An alternate approach could be to pretend that the graphics plane
> >> >> supports XRGB8888 by using the supported ARGB8888 mode instead
> and
> >> >> enabling the global alpha channel. However, this would rule out ever
> >> >> using the per-pixel alpha channel.
> >> >>
> >> >> Signed-off-by: Sean Anderson <sean.anderson at linux.dev>
> >> >> ---
> >> >>
> >> >>  drivers/gpu/drm/xlnx/zynqmp_kms.c | 6 +++---
> >> >>  1 file changed, 3 insertions(+), 3 deletions(-)
> >> >>
> >> >> diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c
> >> >> b/drivers/gpu/drm/xlnx/zynqmp_kms.c
> >> >> index c80a2d4034f3..456ada9ac003 100644
> >> >> --- a/drivers/gpu/drm/xlnx/zynqmp_kms.c
> >> >> +++ b/drivers/gpu/drm/xlnx/zynqmp_kms.c
> >> >> @@ -161,8 +161,8 @@ static int zynqmp_dpsub_create_planes(struct
> >> >> zynqmp_dpsub *dpsub)
> >> >>                 if (!formats)
> >> >>                         return -ENOMEM;
> >> >>
> >> >> -               /* Graphics layer is primary, and video layer is overlay. */
> >> >> -               type = i == ZYNQMP_DPSUB_LAYER_VID
> >> >> +               /* Graphics layer is overlay, and video layer is primary. */
> >> >> +               type = i == ZYNQMP_DPSUB_LAYER_GFX
> >> >>                      ? DRM_PLANE_TYPE_OVERLAY :
> >> >> DRM_PLANE_TYPE_PRIMARY;
> >> >>                 ret = drm_universal_plane_init(&dpsub->drm->dev, plane, 0,
> >> >>                                                &zynqmp_dpsub_plane_funcs,
> >> >> @@ -322,7 +322,7 @@ static const struct drm_crtc_funcs
> >> >> zynqmp_dpsub_crtc_funcs = {
> >> >>
> >> >>  static int zynqmp_dpsub_create_crtc(struct zynqmp_dpsub *dpsub)
> >> >>  {
> >> >> -       struct drm_plane *plane = &dpsub->drm-
> >> >> >planes[ZYNQMP_DPSUB_LAYER_GFX];
> >> >> +       struct drm_plane *plane = &dpsub->drm-
> >> >> >planes[ZYNQMP_DPSUB_LAYER_VID];
> >> >>         struct drm_crtc *crtc = &dpsub->drm->crtc;
> >> >>         int ret;
> >> >>
> >> >> --
> >> >> 2.35.1.1320.gc452695387.dirty
> >> >
> >> > Thank you,
> >> > Anatoliy
> >
> > Thank you,
> > Anatoliy

Thank you,
Anatoliy

From Frank.li at nxp.com  Thu Dec  4 14:57:05 2025
From: Frank.li at nxp.com (Frank Li)
Date: Thu, 4 Dec 2025 17:57:05 -0500
Subject: [PATCH v3 3/3] media: verisilicon: Avoid G2 bus error while
 decoding H.264 and HEVC
In-Reply-To: <9f38bda2f1753645a1ae392ce5364ea0165fdc01.camel@ndufresne.ca>
References: <20251204090813.595-1-ming.qian@oss.nxp.com>
 <20251204090813.595-3-ming.qian@oss.nxp.com>
 <aTHGJzVKa7PbEifJ@lizhi-Precision-Tower-5810>
 <9f38bda2f1753645a1ae392ce5364ea0165fdc01.camel@ndufresne.ca>
Message-ID: <aTIRwcocnye0Y6yV@lizhi-Precision-Tower-5810>

On Thu, Dec 04, 2025 at 01:15:35PM -0500, Nicolas Dufresne wrote:
> Hi Frank,
>
> Le jeudi 04 d?cembre 2025 ? 12:34 -0500, Frank Li a ?crit?:
> > > +static struct v4l2_m2m_dev *hantro_get_v4l2_m2m_dev(struct hantro_dev *vpu)
> > > +{
> > > +	struct device_node *node;
> > > +	struct hantro_dev *shared_vpu;
> > > +
> > > +	if (!vpu->variant || !vpu->variant->shared_devices)
> > > +		goto init_new_m2m_dev;
> >
> > I found only use shared_devices here, how to? ensure that g1 and g2 operate
> > alternately by using shared_devices?
>
> shared_devices is an array of of_device_id we match against. All the matching
> devices will share the same v4l2_m2m_dev (aka m2m scheduler). Typically, both
> cores will be schedule as one. This achieve what alternate operations without
> active polling or blocking locks/mutex.

Okay, but this code require shared_devices==NULL's device probe firstly.
generally not order guaranteed, if there are not depentance at DT.

Does VPU always probe before g1/g2?

and if there are two VPU instances, what's happen?

Frank

>
> For this platform, we only matched against the compatible for simplicity, since
> we know there is only one of each type. I've suggested this method to Ming,
> since it will make it really easy to apply such a quirk if other hardware have
> problems or design constraints.
>
> regards,
> Nicolas




From ilkka at os.amperecomputing.com  Thu Dec  4 15:48:25 2025
From: ilkka at os.amperecomputing.com (Ilkka Koskinen)
Date: Thu, 4 Dec 2025 15:48:25 -0800 (PST)
Subject: [PATCH] perf/arm-cmn: Support CMN-600AE
In-Reply-To: <f0c6e66df6b74f073df77c00bdf9ed560ca9c703.1764002394.git.robin.murphy@arm.com>
References: <f0c6e66df6b74f073df77c00bdf9ed560ca9c703.1764002394.git.robin.murphy@arm.com>
Message-ID: <9fba2a91-af38-5af3-9209-facae7c9c255@os.amperecomputing.com>


On Mon, 24 Nov 2025, Robin Murphy wrote:
> The functional safety features of CMN-600AE have little to no impact on
> the PMU relative to the base CMN-600 design, so for simplicity we can
> reasonably just treat it as the same thing. The only obvious difference
> is that the revision numbers aren't aligned, so we may hide some aliases
> for events which do actually exist, but those can still be specified via
> the underlying "type,eventid" format so it's not too big a deal.
>
> Signed-off-by: Robin Murphy <robin.murphy at arm.com>

Looks good to me.

Reviewed-by: Ilkka Koskinen <ilkka at os.amperecomputing.com>

> ---
> drivers/perf/arm-cmn.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c
> index 23245352a3fc..651edd73bfcb 100644
> --- a/drivers/perf/arm-cmn.c
> +++ b/drivers/perf/arm-cmn.c
> @@ -210,6 +210,7 @@ enum cmn_model {
> enum cmn_part {
> 	PART_CMN600 = 0x434,
> 	PART_CMN650 = 0x436,
> +	PART_CMN600AE = 0x438,
> 	PART_CMN700 = 0x43c,
> 	PART_CI700 = 0x43a,
> 	PART_CMN_S3 = 0x43e,
> @@ -2266,6 +2267,9 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
> 	reg = readq_relaxed(cfg_region + CMN_CFGM_PERIPH_ID_01);
> 	part = FIELD_GET(CMN_CFGM_PID0_PART_0, reg);
> 	part |= FIELD_GET(CMN_CFGM_PID1_PART_1, reg) << 8;
> +	/* 600AE is close enough that it's not really worth more complexity */
> +	if (part == PART_CMN600AE)
> +		part = PART_CMN600;
> 	if (cmn->part && cmn->part != part)
> 		dev_warn(cmn->dev,
> 			 "Firmware binding mismatch: expected part number 0x%x, found 0x%x\n",
> -- 
> 2.34.1
>
>


From nicolas at ndufresne.ca  Thu Dec  4 16:05:01 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Thu, 04 Dec 2025 19:05:01 -0500
Subject: [PATCH v3 3/3] media: verisilicon: Avoid G2 bus error while
 decoding H.264 and HEVC
In-Reply-To: <aTIRwcocnye0Y6yV@lizhi-Precision-Tower-5810>
References: <20251204090813.595-1-ming.qian@oss.nxp.com>
	 <20251204090813.595-3-ming.qian@oss.nxp.com>
	 <aTHGJzVKa7PbEifJ@lizhi-Precision-Tower-5810>
	 <9f38bda2f1753645a1ae392ce5364ea0165fdc01.camel@ndufresne.ca>
	 <aTIRwcocnye0Y6yV@lizhi-Precision-Tower-5810>
Message-ID: <b45a73845e66355080cfad0f0040b6e7a9d78241.camel@ndufresne.ca>

Le jeudi 04 d?cembre 2025 ? 17:57 -0500, Frank Li a ?crit?:
> On Thu, Dec 04, 2025 at 01:15:35PM -0500, Nicolas Dufresne wrote:
> > Hi Frank,
> > 
> > Le jeudi 04 d?cembre 2025 ? 12:34 -0500, Frank Li a ?crit?:
> > > > +static struct v4l2_m2m_dev *hantro_get_v4l2_m2m_dev(struct hantro_dev *vpu)
> > > > +{
> > > > +	struct device_node *node;
> > > > +	struct hantro_dev *shared_vpu;
> > > > +
> > > > +	if (!vpu->variant || !vpu->variant->shared_devices)
> > > > +		goto init_new_m2m_dev;
> > > 
> > > I found only use shared_devices here, how to? ensure that g1 and g2 operate
> > > alternately by using shared_devices?
> > 
> > shared_devices is an array of of_device_id we match against. All the matching
> > devices will share the same v4l2_m2m_dev (aka m2m scheduler). Typically, both
> > cores will be schedule as one. This achieve what alternate operations without
> > active polling or blocking locks/mutex.
> 
> Okay, but this code require shared_devices==NULL's device probe firstly.
> generally not order guaranteed, if there are not depentance at DT.

shared_devices is a constant array that is set inside the variant. It is
normally NULL, except for the imx8mq SoC, for which its always set.

> 
> Does VPU always probe before g1/g2?
> 
> and if there are two VPU instances, what's happen?

Since there is two VPU, g1 and g2, we will enter this loop:

> +	for_each_matching_node(node, vpu->variant->shared_devices) {

On imx8mq, this will match twice.

> +		struct platform_device *pdev;
> +		struct v4l2_m2m_dev *m2m_dev;
> +
> +		pdev = of_find_device_by_node(node);
> +		of_node_put(node);
> +
> +		if (!pdev)
> +			continue;

If the match does not have a device yet (not probe yet), we skip.

> +
> +		shared_vpu = platform_get_drvdata(pdev);
> +		if (IS_ERR_OR_NULL(shared_vpu) || shared_vpu == vpu) {
> +			platform_device_put(pdev);
> +			continue;
> +		}

If its the current VPU, we also skip.

> +
> +		v4l2_m2m_get(shared_vpu->m2m_dev);
> +		m2m_dev = shared_vpu->m2m_dev;
> +		platform_device_put(pdev);

Finally, if the other VPU was initialized, we ref the v4l2_m2m_dev. We will then
create m2m_ctx from it which will cause the two VPU to be scheduled one after
the other.

> +
> +		return m2m_dev;
> +	}

> +
> +init_new_m2m_dev:
> +	return v4l2_m2m_init(&vpu_m2m_ops);

Otherwhise we create a fresh one.

Does it make sense now ?

Nicolas
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251204/aa2f47e3/attachment.sig>

From jacky_chou at aspeedtech.com  Thu Dec  4 16:12:35 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Fri, 5 Dec 2025 00:12:35 +0000
Subject: [PATCH v6 0/7] Add ASPEED PCIe Root Complex support
In-Reply-To: <20251204195355.GA1975043-robh@kernel.org>
References: <20251201-upstream_pcie_rc-v6-0-8c8800c56b16@aspeedtech.com>
 <20251204195355.GA1975043-robh@kernel.org>
Message-ID: <SEYPR06MB5134D0D5911E3C86D869151E9DA7A@SEYPR06MB5134.apcprd06.prod.outlook.com>

Hi Rob,

Thanks for your comments.

> > Changes in v6:
> > - Refer to pci-cpi-bridge.yaml to update aspeed,ast2600-pcie.yaml and
> >   the pcie node of aspeed-g6.dtsi.
> 
> Where is this? You don't describe the root port and its properties at all now.
> 

May I confirm whether the pcie at 8,0 in aspeed-g6.dtsi is not considered the 
root port? From my understanding, that node represents the root port, so I 
want to make sure I'm aligning with your expectation before updating the binding.

Could you help clarify how you would like the root port and its properties to 
be described in the schema?

Thanks,
Jacky



From nathan at kernel.org  Thu Dec  4 16:22:45 2025
From: nathan at kernel.org (Nathan Chancellor)
Date: Thu, 4 Dec 2025 17:22:45 -0700
Subject: [PATCH 6.1.y RESEND] KVM: arm64: silence
 -Wuninitialized-const-pointer warning
In-Reply-To: <2lse2swdqrovimdsakgtriadki2fsvikhuetjzxztoui5hpsai@6mmc64ugt22k>
References: <20251204-b4-clidr-unint-const-ptr-v1-1-95161315ad92@google.com>
 <2lse2swdqrovimdsakgtriadki2fsvikhuetjzxztoui5hpsai@6mmc64ugt22k>
Message-ID: <20251205002245.GA3463270@ax162>

On Thu, Dec 04, 2025 at 12:53:58PM -0800, Justin Stitt wrote:
> Quick correction:
> 
> On Thu, Dec 04, 2025 at 12:50:11PM -0800, Justin Stitt wrote:
> > A new warning in Clang 22 [1] complains that @clidr passed to
> > get_clidr_el1() is an uninitialized const pointer. get_clidr_el1()
> > doesn't really care since it casts away the const-ness anyways.
> > 
> > Silence the warning by initializing the struct.
> > 
> > This patch won't apply to anything past v6.1 as this code section was
> > reworked in Commit 7af0c2534f4c ("KVM: arm64: Normalize cache
> > configuration"). There is no upstream equivalent so this patch only
> > needs to be applied (stable only) to 6.1.
> > 
> > Cc: stable at vger.kernel.org
> > Fixes: 7c8c5e6a9101e ("arm64: KVM: system register handling")
> > Link: https://github.com/llvm/llvm-project/commit/00dacf8c22f065cb52efb14cd091d441f19b319e [1]
> > Signed-off-by: Justin Stitt <justinstitt at google.com>
> > ---
> > Resending this with Nathan's RB tag, an updated commit log and better
> > recipients from checkpatch.pl.
> 
> My usage of $ b4 trailers must've not been correct because this 6.1
> version didn't pick up Nathan's RB tag. Whoops! Hopefully whoever picks
> this up can add that for me :)

Looks like you resent the first iteration of this change [1] instead of
the second [2], hence why 'b4 trailers -u' did not work, since I never
reviewed the first iteration after Marc rejected it :)

Your 5.15 resend looks correct though.

[1]: https://lore.kernel.org/20250724-b4-clidr-unint-const-ptr-v1-1-67c4d620b6b6 at google.com/
[2]: https://lore.kernel.org/20250728-stable-disable-unit-ptr-warn-v1-1-958be9b66520 at google.com/

Cheers,
Nathan


From jie.gan at oss.qualcomm.com  Thu Dec  4 17:01:35 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Fri, 5 Dec 2025 09:01:35 +0800
Subject: [PATCH v6 6/9] dt-bindings: arm: add an interrupt property for
 Coresight CTCU
In-Reply-To: <9c00516c-6e07-4c57-a1f1-6dfc32ab3a53@arm.com>
References: <20250908-enable-byte-cntr-for-tmc-v6-0-1db9e621441a@oss.qualcomm.com>
 <20250908-enable-byte-cntr-for-tmc-v6-6-1db9e621441a@oss.qualcomm.com>
 <66d4488f-941a-4716-b81f-e0f9e1165931@arm.com>
 <5a0e4abf-9e7f-4ef9-af02-dd6e34f5cfa8@oss.qualcomm.com>
 <9c00516c-6e07-4c57-a1f1-6dfc32ab3a53@arm.com>
Message-ID: <bf6033e5-8429-482c-bf3b-adb8bc22711b@oss.qualcomm.com>


On 12/4/2025 5:22 PM, Suzuki K Poulose wrote:
> On 04/12/2025 02:53, Jie Gan wrote:
>>
>>
>> On 12/4/2025 2:14 AM, Suzuki K Poulose wrote:
>>> On 08/09/2025 03:01, Jie Gan wrote:
>>>> Add an interrupt property to CTCU device. The interrupt will be 
>>>> triggered
>>>> when the data size in the ETR buffer exceeds the threshold of the
>>>> BYTECNTRVAL register. Programming a threshold in the BYTECNTRVAL 
>>>> register
>>>> of CTCU device will enable the interrupt.
>>>>
>>>> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
>>>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>>>> ---
>>>> ? .../devicetree/bindings/arm/qcom,coresight-ctcu.yaml??? | 17 +++++ 
>>>> + + ++++++++++
>>>> ? 1 file changed, 17 insertions(+)
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight- 
>>>> ctcu.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight- 
>>>> ctcu.yaml
>>>> index 843b52eaf872..ea05ad8f3dd3 100644
>>>> --- a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
>>>> +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
>>>> @@ -39,6 +39,16 @@ properties:
>>>> ????? items:
>>>> ??????? - const: apb
>>>> +? interrupts:
>>>> +??? items:
>>>> +????? - description: Byte cntr interrupt for etr0
>>>> +????? - description: Byte cntr interrupt for etr1
>>>> +
>>>> +? interrupt-names:
>>>> +??? items:
>>>> +????? - const: etr0
>>>> +????? - const: etr1
>>>
>>
>> Hi Suzuki,
>>
>>> Why are they named "etr0" "etr1" ? That would be confusing, isn't it, 
>>> especially with the Linux driver naming things randomly for the TMC- 
>>> ETRs.
>>>
>>
>> Yes, it will cause misunderstandings since the "etr0" here may not the 
>> right device we are expecting.
>>
>>>
>>> What we want is the "port" number corresponding to the "TMC-ETR" being
>>> monitored ?
>>>
>>> Have you explored other options, "port-0", "port-1" ?
>>>
>>
>> I think it's much better. Will update in next version.
> 
> I am not sure if there exists a better scheme for identifying or
> numbering the interrupts. Happy to listen to the DT experts.
> 
> Rob, Krzysztof, thoughts ?
> 

Hi Suzuki,

I was thinking how about the name "ETRIRQ0", "ETRIRQ1" etc...

Thanks,
Jie

> Suzuki
> 
> 
>>
>> Thanks,
>> Jie
>>
>>> Suzuki
>>>
>>>> +
>>>> ??? in-ports:
>>>> ????? $ref: /schemas/graph.yaml#/properties/ports
>>>> @@ -56,6 +66,8 @@ additionalProperties: false
>>>> ? examples:
>>>> ??? - |
>>>> +??? #include <dt-bindings/interrupt-controller/arm-gic.h>
>>>> +
>>>> ????? ctcu at 1001000 {
>>>> ????????? compatible = "qcom,sa8775p-ctcu";
>>>> ????????? reg = <0x1001000 0x1000>;
>>>> @@ -63,6 +75,11 @@ examples:
>>>> ????????? clocks = <&aoss_qmp>;
>>>> ????????? clock-names = "apb";
>>>> +??????? interrupts = <GIC_SPI 270 IRQ_TYPE_EDGE_RISING>,
>>>> +???????????????????? <GIC_SPI 262 IRQ_TYPE_EDGE_RISING>;
>>>> +??????? interrupt-names = "etr0",
>>>> +????????????????????????? "etr1";
>>>> +
>>>> ????????? in-ports {
>>>> ????????????? #address-cells = <1>;
>>>> ????????????? #size-cells = <0>;
>>>>
>>>
>>>
>>
> 



From willmcvicker at google.com  Thu Dec  4 17:10:13 2025
From: willmcvicker at google.com (Will McVicker)
Date: Fri,  5 Dec 2025 01:10:13 +0000
Subject: [PATCH v7 0/6] Add module support for Arm64 Exynos MCT driver
Message-ID: <20251205011027.720512-1-willmcvicker@google.com>

This series adds support to build the Arm64 Exynos MCT driver as a module.
This is only possible on Arm64 SoCs since they can use the Arm architected
timer as the clocksource. Once the Exynos MCT module is loaded and the device
probes, the MCT is used as the wakeup source for the arch_timer to ensure the
device can wakeup from the "c2" idle state.

These patches are originally from the downstream Pixel 6 (gs101) kernel found
at [1] and have been adapted for upstream. Not only has the Exynos MCT driver
been shipping as a module in the field with Android, but I've also tested this
series with the upstream kernel on my Pixel 6 Pro.

To the driver changes (both as built-in and as module) on Pixel 6 Pro, I ran
these tests:

# cat /proc/interrupts | grep -E "mct|arch_timer"
 23:       6823      10938       7795       5607       8935      12828      21947       2200    GICv3  30 Level     arch_timer
104:          1          0          0          0          0          0          0          0    GICv3 785 Level     mct_comp_irq
105:        547          0          0          0          0          0          0          0    GICv3 789 Level     mct_tick0
106:          0       1333          0          0          0          0          0          0    GICv3 790 Level     mct_tick1
107:          0          0       1467          0          0          0          0          0    GICv3 791 Level     mct_tick2
108:          0          0          0        583          0          0          0          0    GICv3 792 Level     mct_tick3
109:          0          0          0          0        206          0          0          0    GICv3 793 Level     mct_tick4
110:          0          0          0          0          0        153          0          0    GICv3 794 Level     mct_tick5
111:          0          0          0          0          0          0         13          0    GICv3 795 Level     mct_tick6
112:          0          0          0          0          0          0          0         87    GICv3 796 Level     mct_tick7

# cat /sys/devices/system/clocksource/clocksource0/current_clocksource
arch_sys_counter

When built and loaded as a module, you can verify via:

# lsmod | grep exynos_mct
exynos_mct             20480  9

I also compile tested for ARCH=ARM DEFCONFIG=multi_v7_defconfig with the
following debug configs to ensure the section mismatches are fixed:
  CONFIG_DEBUG_SECTION_MISMATCH=y
  # CONFIG_SECTION_MISMATCH_WARN_ONLY is not set

Any additional testing is much appreciated!

Thanks,
Will

Note1, instructions to build and flash a Pixel 6 device with the upstream
kernel can be found at [2].

Note2, this series is based off of krzk/for-next commit bca42080637c (Merge
branch 'next/drivers-late' into for-next).

[1] https://android.googlesource.com/kernel/gs/+log/refs/heads/android-gs-raviole-5.10-android12-d1
[2] https://gitlab.com/LinaroLtd/googlelt/pixelscripts/-/blob/clo/main/README.md?ref_type=heads

Cc: Alim Akhtar <alim.akhtar at samsung.com>
Cc: Daniel Lezcano <daniel.lezcano at linaro.org>
Cc: Donghoon Yu <hoony.yu at samsung.com>
Cc: Rob Herring <robh at kernel.org>
Cc: John Stultz <jstultz at google.com>
Cc: Thomas Gleixner <tglx at linutronix.de>
Cc: Youngmin Nam <youngmin.nam at samsung.com>
Cc: Peter Griffin <peter.griffin at linaro.org>
Cc: Tudor Ambarus <tudor.ambarus at linaro.org>
Cc: Andr? Draszik <andre.draszik at linaro.org>
Cc: Will Deacon <will at kernel.org>
Cc: Conor Dooley <conor+dt at kernel.org>
Cc: Krzysztof Kozlowski <krzk at kernel.org>
Cc: Marek Szyprowski <m.szyprowski at samsung.com>
Cc: "Russell King (Oracle)" <linux at armlinux.org.uk>
Cc: linux-samsung-soc at vger.kernel.org
Cc: kernel-team at android.com
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-kernel at vger.kernel.org
---

Changes in v7:
- Dropped v6 patch 1/6 that removed __init from register_current_timer_delay()
- Refactored the init function in patch 4/7 to handle the case of registering
  the timer delay function for ARM 32-bit systems from an __init tagged function.
  This addresses the original section mismatch issues reported in v4.
- Rebased series onto base commit bca42080637c (Merge branch
  'next/drivers-late' into for-next).

Changes in v6:
- Updated module support to only register the MCT driver as a platform driver
  for ARM64 to ensure ARM 32-bit SoCs continue to probe the MCT driver very
  early.
- Squashed the percpu fix suggested by Marek Szyprowski in
  https://lore.kernel.org/all/20250827102645.1964659-1-m.szyprowski at samsung.com/
  together with patch 3/6.

Changes in v5:
- Fixed section mismatch issues.
- Addressed Arnd's concerns regarding potential issues with unloading and/or
  unbinding the driver.
- Fixed SoB concerns to clarify the development chain from AOSP to Linux.
- Pulled in https://lore.kernel.org/all/20250827102645.1964659-1-m.szyprowski at samsung.com/
  to limit percpu interrupts only for ARM64.

Changes in v4:
- Missed the "v3" string in the previous series for the actual patches
- Re-generated patches with --base a15edf91668beefdb5171c53fa698c9b43dd1e0d
  for kernel test robot.

Changes in v3:
- Rebased on top of Daniel's timer modularization prep series [3] and
  krzk/for-next commit a15edf91668b ("Merge branch 'next/dt64' into
  for-next")
- Added owner references to Exynos MCT clocksource and clockevent objects.
- Dropped #ifdef MODULE conditional section in favor of just using
  module_platform_driver() which will properly handle setting up the
  of_device_id table based on if the driver is built-in or a module.
- Update commit message for patch 2 based on John's feedback.
- Dropped DT change from v2 as it was picked up by Krzysztof for CPU Idle.

Changes in v2:
- Re-worked patch v1 5 based on Rob Herring's review to use the compatible
  data for retrieving the mct_init function pointer.
- Updated the Kconfig logic to disallow building the Exynos MCT driver as
  a module for ARM32 configurations based on Krzysztof Kozlowski's findings.
- Added comments and clarified commit messages in patches 1 and 2 based on
  reviews from John Stultz and Youngmin Nam.
- Fixed an issue found during testing that resulted in the device getting
  stuck on boot. This is included in v2 as patch 5.
- Collected *-by tags
- Rebased to the latest linux-next/master.
---

Donghoon Yu (1):
  clocksource/drivers/exynos_mct: Don't register as a sched_clock on
    arm64

Hosung Kim (1):
  clocksource/drivers/exynos_mct: Set percpu local timer interrupts for
    ARM64

Will McVicker (4):
  clocksource/drivers/exynos_mct: Fix uninitialized irq name warning
  clocksource/drivers/exynos_mct: Refactor driver init
  clocksource/drivers/exynos_mct: Add module support for ARM64
  arm64: exynos: Drop select CLKSRC_EXYNOS_MCT

 arch/arm64/Kconfig.platforms     |   1 -
 drivers/clocksource/Kconfig      |   3 +-
 drivers/clocksource/exynos_mct.c | 255 ++++++++++++++++++++++---------
 3 files changed, 182 insertions(+), 77 deletions(-)


base-commit: bca42080637ce3a21092fc0f7d5411e853b0c3b3
-- 
2.52.0.223.gf5cc29aaa4-goog



From willmcvicker at google.com  Thu Dec  4 17:10:14 2025
From: willmcvicker at google.com (Will McVicker)
Date: Fri,  5 Dec 2025 01:10:14 +0000
Subject: [PATCH v7 1/6] clocksource/drivers/exynos_mct: Don't register as a
 sched_clock on arm64
In-Reply-To: <20251205011027.720512-1-willmcvicker@google.com>
References: <20251205011027.720512-1-willmcvicker@google.com>
Message-ID: <20251205011027.720512-2-willmcvicker@google.com>

From: Donghoon Yu <hoony.yu at samsung.com>

The MCT register is unfortunately very slow to access, but importantly
does not halt in the c2 idle state. So for ARM64, we can improve
performance by not registering the MCT for sched_clock, allowing the
system to use the faster ARM architected timer for sched_clock instead.

The MCT is still registered as a clocksource, and a clockevent in order
to be a wakeup source for the arch_timer to exit the "c2" idle state.

Since ARM32 SoCs don't have an architected timer, the MCT must continue
to be used for sched_clock. Detailed discussion on this topic can be
found at [1].

[1] https://lore.kernel.org/linux-samsung-soc/1400188079-21832-1-git-send-email-chirantan at chromium.org/

[Original commit from https://android.googlesource.com/kernel/gs/+/630817f7080e92c5e0216095ff52f6eb8dd00727

Signed-off-by: Donghoon Yu <hoony.yu at samsung.com>
Signed-off-by: Youngmin Nam <youngmin.nam at samsung.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano at linaro.org>
Acked-by: John Stultz <jstultz at google.com>
Tested-by: Youngmin Nam <youngmin.nam at samsung.com> # AOSP -> Linux port
Reviewed-by: Youngmin Nam <youngmin.nam at samsung.com> # AOSP -> Linux port
Signed-off-by: Will McVicker <willmcvicker at google.com>
---
 drivers/clocksource/exynos_mct.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c
index da09f467a6bb..96361d5dc57d 100644
--- a/drivers/clocksource/exynos_mct.c
+++ b/drivers/clocksource/exynos_mct.c
@@ -219,12 +219,18 @@ static struct clocksource mct_frc = {
 	.resume		= exynos4_frc_resume,
 };
 
+/*
+ * Since ARM devices do not have an architected timer, they need to continue
+ * using the MCT as the main clocksource for timekeeping, sched_clock, and the
+ * delay timer. For AARCH64 SoCs, the architected timer is the preferred
+ * clocksource due to it's superior performance.
+ */
+#if defined(CONFIG_ARM)
 static u64 notrace exynos4_read_sched_clock(void)
 {
 	return exynos4_read_count_32();
 }
 
-#if defined(CONFIG_ARM)
 static struct delay_timer exynos4_delay_timer;
 
 static cycles_t exynos4_read_current_timer(void)
@@ -250,12 +256,13 @@ static int __init exynos4_clocksource_init(bool frc_shared)
 	exynos4_delay_timer.read_current_timer = &exynos4_read_current_timer;
 	exynos4_delay_timer.freq = clk_rate;
 	register_current_timer_delay(&exynos4_delay_timer);
+
+	sched_clock_register(exynos4_read_sched_clock, 32, clk_rate);
 #endif
 
 	if (clocksource_register_hz(&mct_frc, clk_rate))
 		panic("%s: can't register clocksource\n", mct_frc.name);
 
-	sched_clock_register(exynos4_read_sched_clock, 32, clk_rate);
 
 	return 0;
 }
-- 
2.52.0.223.gf5cc29aaa4-goog



From willmcvicker at google.com  Thu Dec  4 17:10:15 2025
From: willmcvicker at google.com (Will McVicker)
Date: Fri,  5 Dec 2025 01:10:15 +0000
Subject: [PATCH v7 2/6] clocksource/drivers/exynos_mct: Set percpu local timer
 interrupts for ARM64
In-Reply-To: <20251205011027.720512-1-willmcvicker@google.com>
References: <20251205011027.720512-1-willmcvicker@google.com>
Message-ID: <20251205011027.720512-3-willmcvicker@google.com>

From: Hosung Kim <hosung0.kim at samsung.com>

To allow the CPU to handle it's own clock events, we need to set the
IRQF_PERCPU flag. This prevents the local timer interrupts from
migrating to other CPUs. This is only supported on ARM64.

Signed-off-by: Hosung Kim <hosung0.kim at samsung.com>
[Original commit from https://android.googlesource.com/kernel/gs/+/03267fad19f093bac979ca78309483e9eb3a8d16]
Reviewed-by: Peter Griffin <peter.griffin at linaro.org>
Reviewed-by: Youngmin Nam <youngmin.nam at samsung.com>
Tested-by: Youngmin Nam <youngmin.nam at samsung.com>
Suggested-by: Marek Szyprowski <m.szyprowski at samsung.com>
Link: https://lore.kernel.org/all/20250827102645.1964659-1-m.szyprowski at samsung.com/
Signed-off-by: Will McVicker <willmcvicker at google.com>
---
 drivers/clocksource/exynos_mct.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c
index 96361d5dc57d..1429b9d03a58 100644
--- a/drivers/clocksource/exynos_mct.c
+++ b/drivers/clocksource/exynos_mct.c
@@ -596,7 +596,9 @@ static int __init exynos4_timer_interrupts(struct device_node *np,
 			irq_set_status_flags(mct_irq, IRQ_NOAUTOEN);
 			if (request_irq(mct_irq,
 					exynos4_mct_tick_isr,
-					IRQF_TIMER | IRQF_NOBALANCING,
+					IRQF_TIMER | IRQF_NOBALANCING |
+					(IS_ENABLED(CONFIG_ARM64) ?
+					 IRQF_PERCPU : 0),
 					pcpu_mevt->name, pcpu_mevt)) {
 				pr_err("exynos-mct: cannot register IRQ (cpu%d)\n",
 									cpu);
-- 
2.52.0.223.gf5cc29aaa4-goog



From willmcvicker at google.com  Thu Dec  4 17:10:16 2025
From: willmcvicker at google.com (Will McVicker)
Date: Fri,  5 Dec 2025 01:10:16 +0000
Subject: [PATCH v7 3/6] clocksource/drivers/exynos_mct: Fix uninitialized irq
 name warning
In-Reply-To: <20251205011027.720512-1-willmcvicker@google.com>
References: <20251205011027.720512-1-willmcvicker@google.com>
Message-ID: <20251205011027.720512-4-willmcvicker@google.com>

The Exynos MCT driver doesn't set the clocksource name until the CPU
hotplug state is setup which happens after the IRQs are requested. This
results in an empty IRQ name which leads to the below warning at
proc_create() time. When this happens, the userdata partition fails to
mount and the device gets stuck in an endless loop printing the error:

  root '/dev/disk/by-partlabel/userdata' doesn't exist or does not contain a /dev.

To fix this, we just need to initialize the name before requesting the
IRQs.

Warning from Pixel 6 kernel log:

[  T430] name len 0
[  T430] WARNING: CPU: 6 PID: 430 at fs/proc/generic.c:407 __proc_create+0x258/0x2b4
[  T430] Modules linked in: dwc3_exynos(E+)
[  T430]  ufs_exynos(E+) phy_exynos_ufs(E)
[  T430]  phy_exynos5_usbdrd(E) exynos_usi(E+) exynos_mct(E+) s3c2410_wdt(E)
[  T430]  arm_dsu_pmu(E) simplefb(E)
[  T430] CPU: 6 UID: 0 PID: 430 Comm: (udev-worker) Tainted:
         ... 6.14.0-next-20250331-4k-00008-g59adf909e40e #1 ...
[  T430] Tainted: [W]=WARN, [E]=UNSIGNED_MODULE
[  T430] Hardware name: Raven (DT)
[...]
[  T430] Call trace:
[  T430]  __proc_create+0x258/0x2b4 (P)
[  T430]  proc_mkdir+0x40/0xa0
[  T430]  register_handler_proc+0x118/0x140
[  T430]  __setup_irq+0x460/0x6d0
[  T430]  request_threaded_irq+0xcc/0x1b0
[  T430]  mct_init_dt+0x244/0x604 [exynos_mct ...]
[  T430]  mct_init_spi+0x18/0x34 [exynos_mct ...]
[  T430]  exynos4_mct_probe+0x30/0x4c [exynos_mct ...]
[  T430]  platform_probe+0x6c/0xe4
[  T430]  really_probe+0xf4/0x38c
[...]
[  T430]  driver_register+0x6c/0x140
[  T430]  __platform_driver_register+0x28/0x38
[  T430]  exynos4_mct_driver_init+0x24/0xfe8 [exynos_mct ...]
[  T430]  do_one_initcall+0x84/0x3c0
[  T430]  do_init_module+0x58/0x208
[  T430]  load_module+0x1de0/0x2500
[  T430]  init_module_from_file+0x8c/0xdc

Reviewed-by: Peter Griffin <peter.griffin at linaro.org>
Reviewed-by: Youngmin Nam <youngmin.nam at samsung.com>
Tested-by: Youngmin Nam <youngmin.nam at samsung.com>
Signed-off-by: Will McVicker <willmcvicker at google.com>
---
 drivers/clocksource/exynos_mct.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c
index 1429b9d03a58..fece6bbc190e 100644
--- a/drivers/clocksource/exynos_mct.c
+++ b/drivers/clocksource/exynos_mct.c
@@ -465,8 +465,6 @@ static int exynos4_mct_starting_cpu(unsigned int cpu)
 		per_cpu_ptr(&percpu_mct_tick, cpu);
 	struct clock_event_device *evt = &mevt->evt;
 
-	snprintf(mevt->name, sizeof(mevt->name), "mct_tick%d", cpu);
-
 	evt->name = mevt->name;
 	evt->cpumask = cpumask_of(cpu);
 	evt->set_next_event = exynos4_tick_set_next_event;
@@ -567,6 +565,14 @@ static int __init exynos4_timer_interrupts(struct device_node *np,
 	for (i = MCT_L0_IRQ; i < nr_irqs; i++)
 		mct_irqs[i] = irq_of_parse_and_map(np, i);
 
+	for_each_possible_cpu(cpu) {
+		struct mct_clock_event_device *mevt =
+		    per_cpu_ptr(&percpu_mct_tick, cpu);
+
+		snprintf(mevt->name, sizeof(mevt->name), "mct_tick%d",
+			 cpu);
+	}
+
 	if (mct_int_type == MCT_INT_PPI) {
 
 		err = request_percpu_irq(mct_irqs[MCT_L0_IRQ],
-- 
2.52.0.223.gf5cc29aaa4-goog



From willmcvicker at google.com  Thu Dec  4 17:10:17 2025
From: willmcvicker at google.com (Will McVicker)
Date: Fri,  5 Dec 2025 01:10:17 +0000
Subject: [PATCH v7 4/6] clocksource/drivers/exynos_mct: Refactor driver init
In-Reply-To: <20251205011027.720512-1-willmcvicker@google.com>
References: <20251205011027.720512-1-willmcvicker@google.com>
Message-ID: <20251205011027.720512-5-willmcvicker@google.com>

This patch cleans up the driver a bit by
- refactoring mct_init_dt() to allow better separation of ARM 32-bit
  specific code and ARM64 code. Ultimately this allows the driver to
  access context data outside of mct_init_dt().
- adds driver data to distinguish the interrupt type which allows
  a single driver init function.

This clean up is in preparation for modularizing the MCT driver for only
ARM64 SoCs.

Signed-off-by: Will McVicker <willmcvicker at google.com>
---
 drivers/clocksource/exynos_mct.c | 199 +++++++++++++++++++------------
 1 file changed, 125 insertions(+), 74 deletions(-)

diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c
index fece6bbc190e..922c2b519a39 100644
--- a/drivers/clocksource/exynos_mct.c
+++ b/drivers/clocksource/exynos_mct.c
@@ -74,13 +74,22 @@ enum {
 	MCT_INT_PPI
 };
 
+/* Needs to be global for sched_clock_register() since we can't pass in data. */
 static void __iomem *reg_base;
-static unsigned long clk_rate;
-static unsigned int mct_int_type;
-static int mct_irqs[MCT_NR_IRQS];
+
+struct mct_data {
+	unsigned int int_type;
+};
+
+struct mct_context {
+	const struct mct_data *drvdata;
+	unsigned long clk_rate;
+	int mct_irqs[MCT_NR_IRQS];
+};
 
 struct mct_clock_event_device {
 	struct clock_event_device evt;
+	struct mct_context *ctx;
 	unsigned long base;
 	/**
 	 *  The length of the name must be adjusted if number of
@@ -89,6 +98,12 @@ struct mct_clock_event_device {
 	char name[11];
 };
 
+static struct mct_clock_event_device *
+to_mct_clock_event_device(struct clock_event_device *evt)
+{
+	return container_of(evt, struct mct_clock_event_device, evt);
+}
+
 static void exynos4_mct_write(unsigned int value, unsigned long offset)
 {
 	unsigned long stat_addr;
@@ -241,7 +256,7 @@ static cycles_t exynos4_read_current_timer(void)
 }
 #endif
 
-static int __init exynos4_clocksource_init(bool frc_shared)
+static int __init exynos4_clocksource_init(struct mct_context *ctx, bool frc_shared)
 {
 	/*
 	 * When the frc is shared, the main processor should have already
@@ -252,18 +267,9 @@ static int __init exynos4_clocksource_init(bool frc_shared)
 	else
 		exynos4_mct_frc_start();
 
-#if defined(CONFIG_ARM)
-	exynos4_delay_timer.read_current_timer = &exynos4_read_current_timer;
-	exynos4_delay_timer.freq = clk_rate;
-	register_current_timer_delay(&exynos4_delay_timer);
-
-	sched_clock_register(exynos4_read_sched_clock, 32, clk_rate);
-#endif
-
-	if (clocksource_register_hz(&mct_frc, clk_rate))
+	if (clocksource_register_hz(&mct_frc, ctx->clk_rate))
 		panic("%s: can't register clocksource\n", mct_frc.name);
 
-
 	return 0;
 }
 
@@ -297,7 +303,7 @@ static void exynos4_mct_comp0_start(bool periodic, unsigned long cycles)
 	exynos4_mct_write(0x1, EXYNOS4_MCT_G_INT_ENB);
 
 	tcon |= MCT_G_TCON_COMP0_ENABLE;
-	exynos4_mct_write(tcon , EXYNOS4_MCT_G_TCON);
+	exynos4_mct_write(tcon, EXYNOS4_MCT_G_TCON);
 }
 
 static int exynos4_comp_set_next_event(unsigned long cycles,
@@ -325,17 +331,19 @@ static int mct_set_state_periodic(struct clock_event_device *evt)
 	return 0;
 }
 
-static struct clock_event_device mct_comp_device = {
-	.name			= "mct-comp",
-	.features		= CLOCK_EVT_FEAT_PERIODIC |
-				  CLOCK_EVT_FEAT_ONESHOT,
-	.rating			= 250,
-	.set_next_event		= exynos4_comp_set_next_event,
-	.set_state_periodic	= mct_set_state_periodic,
-	.set_state_shutdown	= mct_set_state_shutdown,
-	.set_state_oneshot	= mct_set_state_shutdown,
-	.set_state_oneshot_stopped = mct_set_state_shutdown,
-	.tick_resume		= mct_set_state_shutdown,
+static struct mct_clock_event_device mct_comp_device = {
+	.evt = {
+		.name			= "mct-comp",
+		.features		= CLOCK_EVT_FEAT_PERIODIC |
+					  CLOCK_EVT_FEAT_ONESHOT,
+		.rating			= 250,
+		.set_next_event		= exynos4_comp_set_next_event,
+		.set_state_periodic	= mct_set_state_periodic,
+		.set_state_shutdown	= mct_set_state_shutdown,
+		.set_state_oneshot	= mct_set_state_shutdown,
+		.set_state_oneshot_stopped = mct_set_state_shutdown,
+		.tick_resume		= mct_set_state_shutdown,
+	},
 };
 
 static irqreturn_t exynos4_mct_comp_isr(int irq, void *dev_id)
@@ -349,14 +357,16 @@ static irqreturn_t exynos4_mct_comp_isr(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-static int exynos4_clockevent_init(void)
+static int exynos4_clockevent_init(struct mct_context *ctx)
 {
-	mct_comp_device.cpumask = cpumask_of(0);
-	clockevents_config_and_register(&mct_comp_device, clk_rate,
+	struct clock_event_device *evt = &mct_comp_device.evt;
+
+	mct_comp_device.ctx = ctx;
+	evt->cpumask = cpumask_of(0);
+	clockevents_config_and_register(evt, ctx->clk_rate,
 					0xf, 0xffffffff);
-	if (request_irq(mct_irqs[MCT_G0_IRQ], exynos4_mct_comp_isr,
-			IRQF_TIMER | IRQF_IRQPOLL, "mct_comp_irq",
-			&mct_comp_device))
+	if (request_irq(ctx->mct_irqs[MCT_G0_IRQ], exynos4_mct_comp_isr,
+			IRQF_TIMER | IRQF_IRQPOLL, "mct_comp_irq", evt))
 		pr_err("%s: request_irq() failed\n", "mct_comp_irq");
 
 	return 0;
@@ -409,18 +419,16 @@ static void exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)
 static int exynos4_tick_set_next_event(unsigned long cycles,
 				       struct clock_event_device *evt)
 {
-	struct mct_clock_event_device *mevt;
+	struct mct_clock_event_device *mevt = to_mct_clock_event_device(evt);
 
-	mevt = container_of(evt, struct mct_clock_event_device, evt);
 	exynos4_mct_tick_start(cycles, mevt);
 	return 0;
 }
 
 static int set_state_shutdown(struct clock_event_device *evt)
 {
-	struct mct_clock_event_device *mevt;
+	struct mct_clock_event_device *mevt = to_mct_clock_event_device(evt);
 
-	mevt = container_of(evt, struct mct_clock_event_device, evt);
 	exynos4_mct_tick_stop(mevt);
 	exynos4_mct_tick_clear(mevt);
 	return 0;
@@ -428,10 +436,9 @@ static int set_state_shutdown(struct clock_event_device *evt)
 
 static int set_state_periodic(struct clock_event_device *evt)
 {
-	struct mct_clock_event_device *mevt;
+	struct mct_clock_event_device *mevt = to_mct_clock_event_device(evt);
 	unsigned long cycles_per_jiffy;
 
-	mevt = container_of(evt, struct mct_clock_event_device, evt);
 	cycles_per_jiffy = (((unsigned long long)NSEC_PER_SEC / HZ * evt->mult)
 			    >> evt->shift);
 	exynos4_mct_tick_stop(mevt);
@@ -464,6 +471,7 @@ static int exynos4_mct_starting_cpu(unsigned int cpu)
 	struct mct_clock_event_device *mevt =
 		per_cpu_ptr(&percpu_mct_tick, cpu);
 	struct clock_event_device *evt = &mevt->evt;
+	struct mct_context *ctx = mevt->ctx;
 
 	evt->name = mevt->name;
 	evt->cpumask = cpumask_of(cpu);
@@ -479,7 +487,7 @@ static int exynos4_mct_starting_cpu(unsigned int cpu)
 
 	exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET);
 
-	if (mct_int_type == MCT_INT_SPI) {
+	if (ctx->drvdata->int_type == MCT_INT_SPI) {
 
 		if (evt->irq == -1)
 			return -EIO;
@@ -487,9 +495,9 @@ static int exynos4_mct_starting_cpu(unsigned int cpu)
 		irq_force_affinity(evt->irq, cpumask_of(cpu));
 		enable_irq(evt->irq);
 	} else {
-		enable_percpu_irq(mct_irqs[MCT_L0_IRQ], 0);
+		enable_percpu_irq(ctx->mct_irqs[MCT_L0_IRQ], 0);
 	}
-	clockevents_config_and_register(evt, clk_rate / (TICK_BASE_CNT + 1),
+	clockevents_config_and_register(evt, ctx->clk_rate / (TICK_BASE_CNT + 1),
 					0xf, 0x7fffffff);
 
 	return 0;
@@ -500,18 +508,20 @@ static int exynos4_mct_dying_cpu(unsigned int cpu)
 	struct mct_clock_event_device *mevt =
 		per_cpu_ptr(&percpu_mct_tick, cpu);
 	struct clock_event_device *evt = &mevt->evt;
+	struct mct_context *ctx = mevt->ctx;
 
-	if (mct_int_type == MCT_INT_SPI) {
+	if (ctx->drvdata->int_type == MCT_INT_SPI) {
 		if (evt->irq != -1)
 			disable_irq_nosync(evt->irq);
 		exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET);
 	} else {
-		disable_percpu_irq(mct_irqs[MCT_L0_IRQ]);
+		disable_percpu_irq(ctx->mct_irqs[MCT_L0_IRQ]);
 	}
 	return 0;
 }
 
-static int __init exynos4_timer_resources(struct device_node *np)
+static int __init exynos4_timer_resources(struct mct_context *ctx,
+					  struct device_node *np)
 {
 	struct clk *mct_clk, *tick_clk;
 
@@ -522,7 +532,7 @@ static int __init exynos4_timer_resources(struct device_node *np)
 	tick_clk = of_clk_get_by_name(np, "fin_pll");
 	if (IS_ERR(tick_clk))
 		panic("%s: unable to determine tick clock rate\n", __func__);
-	clk_rate = clk_get_rate(tick_clk);
+	ctx->clk_rate = clk_get_rate(tick_clk);
 
 	mct_clk = of_clk_get_by_name(np, "mct");
 	if (IS_ERR(mct_clk))
@@ -534,22 +544,20 @@ static int __init exynos4_timer_resources(struct device_node *np)
 
 /**
  * exynos4_timer_interrupts - initialize MCT interrupts
+ * @ctx: device context
  * @np: device node for MCT
- * @int_type: interrupt type, MCT_INT_PPI or MCT_INT_SPI
  * @local_idx: array mapping CPU numbers to local timer indices
  * @nr_local: size of @local_idx array
  */
-static int __init exynos4_timer_interrupts(struct device_node *np,
-					   unsigned int int_type,
+static int __init exynos4_timer_interrupts(struct mct_context *ctx,
+					   struct device_node *np,
 					   const u32 *local_idx,
 					   size_t nr_local)
 {
 	int nr_irqs, i, err, cpu;
 
-	mct_int_type = int_type;
-
 	/* This driver uses only one global timer interrupt */
-	mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ);
+	ctx->mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ);
 
 	/*
 	 * Find out the number of local irqs specified. The local
@@ -557,29 +565,30 @@ static int __init exynos4_timer_interrupts(struct device_node *np,
 	 * irqs are specified.
 	 */
 	nr_irqs = of_irq_count(np);
-	if (nr_irqs > ARRAY_SIZE(mct_irqs)) {
+	if (nr_irqs > ARRAY_SIZE(ctx->mct_irqs)) {
 		pr_err("exynos-mct: too many (%d) interrupts configured in DT\n",
 			nr_irqs);
-		nr_irqs = ARRAY_SIZE(mct_irqs);
+		nr_irqs = ARRAY_SIZE(ctx->mct_irqs);
 	}
 	for (i = MCT_L0_IRQ; i < nr_irqs; i++)
-		mct_irqs[i] = irq_of_parse_and_map(np, i);
+		ctx->mct_irqs[i] = irq_of_parse_and_map(np, i);
 
 	for_each_possible_cpu(cpu) {
 		struct mct_clock_event_device *mevt =
 		    per_cpu_ptr(&percpu_mct_tick, cpu);
 
+		mevt->ctx = ctx;
 		snprintf(mevt->name, sizeof(mevt->name), "mct_tick%d",
 			 cpu);
 	}
 
-	if (mct_int_type == MCT_INT_PPI) {
+	if (ctx->drvdata->int_type == MCT_INT_PPI) {
 
-		err = request_percpu_irq(mct_irqs[MCT_L0_IRQ],
+		err = request_percpu_irq(ctx->mct_irqs[MCT_L0_IRQ],
 					 exynos4_mct_tick_isr, "MCT",
 					 &percpu_mct_tick);
 		WARN(err, "MCT: can't request IRQ %d (%d)\n",
-		     mct_irqs[MCT_L0_IRQ], err);
+		     ctx->mct_irqs[MCT_L0_IRQ], err);
 	} else {
 		for_each_possible_cpu(cpu) {
 			int mct_irq;
@@ -595,9 +604,9 @@ static int __init exynos4_timer_interrupts(struct device_node *np,
 			irq_idx = MCT_L0_IRQ + local_idx[cpu];
 
 			pcpu_mevt->evt.irq = -1;
-			if (irq_idx >= ARRAY_SIZE(mct_irqs))
+			if (irq_idx >= ARRAY_SIZE(ctx->mct_irqs))
 				break;
-			mct_irq = mct_irqs[irq_idx];
+			mct_irq = ctx->mct_irqs[irq_idx];
 
 			irq_set_status_flags(mct_irq, IRQ_NOAUTOEN);
 			if (request_irq(mct_irq,
@@ -637,8 +646,8 @@ static int __init exynos4_timer_interrupts(struct device_node *np,
 	return 0;
 
 out_irq:
-	if (mct_int_type == MCT_INT_PPI) {
-		free_percpu_irq(mct_irqs[MCT_L0_IRQ], &percpu_mct_tick);
+	if (ctx->drvdata->int_type == MCT_INT_PPI) {
+		free_percpu_irq(ctx->mct_irqs[MCT_L0_IRQ], &percpu_mct_tick);
 	} else {
 		for_each_possible_cpu(cpu) {
 			struct mct_clock_event_device *pcpu_mevt =
@@ -653,7 +662,7 @@ static int __init exynos4_timer_interrupts(struct device_node *np,
 	return err;
 }
 
-static int __init mct_init_dt(struct device_node *np, unsigned int int_type)
+static int __init mct_init_dt(struct mct_context *ctx, struct device_node *np)
 {
 	bool frc_shared = of_property_read_bool(np, "samsung,frc-shared");
 	u32 local_idx[MCT_NR_LOCAL] = {0};
@@ -679,15 +688,15 @@ static int __init mct_init_dt(struct device_node *np, unsigned int int_type)
 			local_idx[i] = i;
 	}
 
-	ret = exynos4_timer_resources(np);
+	ret = exynos4_timer_resources(ctx, np);
 	if (ret)
 		return ret;
 
-	ret = exynos4_timer_interrupts(np, int_type, local_idx, nr_local);
+	ret = exynos4_timer_interrupts(ctx, np, local_idx, nr_local);
 	if (ret)
 		return ret;
 
-	ret = exynos4_clocksource_init(frc_shared);
+	ret = exynos4_clocksource_init(ctx, frc_shared);
 	if (ret)
 		return ret;
 
@@ -698,18 +707,60 @@ static int __init mct_init_dt(struct device_node *np, unsigned int int_type)
 	if (frc_shared)
 		return 0;
 
-	return exynos4_clockevent_init();
+	ret = exynos4_clockevent_init(ctx);
+	if (ret)
+		return ret;
+
+	return 0;
 }
 
+static const struct mct_data exynos4210_mct_data = { .int_type = MCT_INT_SPI, };
+static const struct mct_data exynos4412_mct_data = { .int_type = MCT_INT_PPI, };
 
-static int __init mct_init_spi(struct device_node *np)
-{
-	return mct_init_dt(np, MCT_INT_SPI);
-}
+static const struct of_device_id exynos4_mct_match_table[] = {
+	{ .compatible = "samsung,exynos4210-mct", .data = &exynos4210_mct_data, },
+	{ .compatible = "samsung,exynos4412-mct", .data = &exynos4412_mct_data, },
+	{}
+};
 
-static int __init mct_init_ppi(struct device_node *np)
+/* Note, legacy ARM 32-bit systems depend on the MCT as the only clocksource
+ * which requires this driver to be initialized very early. We need to keep this
+ * special condition until we can transparently support modular and early init
+ * timers.
+ */
+static int __init mct_of_declare_init(struct device_node *np)
 {
-	return mct_init_dt(np, MCT_INT_PPI);
+	struct mct_context *ctx;
+	const struct of_device_id *match;
+	int ret;
+
+	match = of_match_node(exynos4_mct_match_table, np);
+	if (!match || !match->data)
+		return -ENODEV;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ctx->drvdata = match->data;
+
+	ret = mct_init_dt(ctx, np);
+	if (ret)
+		goto out_ctx;
+
+#if defined(CONFIG_ARM)
+	sched_clock_register(exynos4_read_sched_clock, 32, ctx->clk_rate);
+
+	exynos4_delay_timer.read_current_timer = &exynos4_read_current_timer;
+	exynos4_delay_timer.freq = ctx->clk_rate;
+	register_current_timer_delay(&exynos4_delay_timer);
+#endif
+
+	return 0;
+
+out_ctx:
+	kfree(ctx);
+	return ret;
 }
-TIMER_OF_DECLARE(exynos4210, "samsung,exynos4210-mct", mct_init_spi);
-TIMER_OF_DECLARE(exynos4412, "samsung,exynos4412-mct", mct_init_ppi);
+TIMER_OF_DECLARE(exynos4210, "samsung,exynos4210-mct", mct_of_declare_init);
+TIMER_OF_DECLARE(exynos4412, "samsung,exynos4412-mct", mct_of_declare_init);
-- 
2.52.0.223.gf5cc29aaa4-goog



From willmcvicker at google.com  Thu Dec  4 17:10:18 2025
From: willmcvicker at google.com (Will McVicker)
Date: Fri,  5 Dec 2025 01:10:18 +0000
Subject: [PATCH v7 5/6] clocksource/drivers/exynos_mct: Add module support for ARM64
In-Reply-To: <20251205011027.720512-1-willmcvicker@google.com>
References: <20251205011027.720512-1-willmcvicker@google.com>
Message-ID: <20251205011027.720512-6-willmcvicker@google.com>

On Arm64 platforms the Exynos MCT driver can be built as a module. On
boot (and even after boot) the arch_timer is used as the clocksource and
tick timer. Once the MCT driver is loaded, it can be used as the wakeup
source for the arch_timer.

Note, this commit was derived from
https://android.googlesource.com/kernel/gs/+/8a52a8288ec7d88ff78f0b37480dbb0e9c65bbfd.

Signed-off-by: Daniel Lezcano <daniel.lezcano at linaro.org>
Reviewed-by: Youngmin Nam <youngmin.nam at samsung.com> # AOSP -> Linux port
Tested-by: Youngmin Nam <youngmin.nam at samsung.com> # AOSP -> Linux port
Signed-off-by: Will McVicker <willmcvicker at google.com>
---
 drivers/clocksource/Kconfig      |  3 +-
 drivers/clocksource/exynos_mct.c | 51 ++++++++++++++++++++++++++++----
 2 files changed, 47 insertions(+), 7 deletions(-)

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index ffcd23668763..9450cfaf982f 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -451,7 +451,8 @@ config ATMEL_TCB_CLKSRC
 	  Support for Timer Counter Blocks on Atmel SoCs.
 
 config CLKSRC_EXYNOS_MCT
-	bool "Exynos multi core timer driver" if COMPILE_TEST
+	tristate "Exynos multi core timer driver" if ARM64
+	default y if ARCH_EXYNOS || COMPILE_TEST
 	depends on ARM || ARM64
 	depends on ARCH_ARTPEC || ARCH_EXYNOS || COMPILE_TEST
 	help
diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c
index 922c2b519a39..d9a888607726 100644
--- a/drivers/clocksource/exynos_mct.c
+++ b/drivers/clocksource/exynos_mct.c
@@ -15,9 +15,11 @@
 #include <linux/cpu.h>
 #include <linux/delay.h>
 #include <linux/percpu.h>
+#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_irq.h>
 #include <linux/of_address.h>
+#include <linux/platform_device.h>
 #include <linux/clocksource.h>
 #include <linux/sched_clock.h>
 
@@ -232,6 +234,7 @@ static struct clocksource mct_frc = {
 	.mask		= CLOCKSOURCE_MASK(32),
 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
 	.resume		= exynos4_frc_resume,
+	.owner		= THIS_MODULE,
 };
 
 /*
@@ -256,7 +259,7 @@ static cycles_t exynos4_read_current_timer(void)
 }
 #endif
 
-static int __init exynos4_clocksource_init(struct mct_context *ctx, bool frc_shared)
+static int __init_or_module exynos4_clocksource_init(struct mct_context *ctx, bool frc_shared)
 {
 	/*
 	 * When the frc is shared, the main processor should have already
@@ -343,6 +346,7 @@ static struct mct_clock_event_device mct_comp_device = {
 		.set_state_oneshot	= mct_set_state_shutdown,
 		.set_state_oneshot_stopped = mct_set_state_shutdown,
 		.tick_resume		= mct_set_state_shutdown,
+		.owner			= THIS_MODULE,
 	},
 };
 
@@ -484,6 +488,7 @@ static int exynos4_mct_starting_cpu(unsigned int cpu)
 	evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
 			CLOCK_EVT_FEAT_PERCPU;
 	evt->rating = MCT_CLKEVENTS_RATING;
+	evt->owner = THIS_MODULE;
 
 	exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET);
 
@@ -520,7 +525,7 @@ static int exynos4_mct_dying_cpu(unsigned int cpu)
 	return 0;
 }
 
-static int __init exynos4_timer_resources(struct mct_context *ctx,
+static int __init_or_module exynos4_timer_resources(struct mct_context *ctx,
 					  struct device_node *np)
 {
 	struct clk *mct_clk, *tick_clk;
@@ -549,7 +554,7 @@ static int __init exynos4_timer_resources(struct mct_context *ctx,
  * @local_idx: array mapping CPU numbers to local timer indices
  * @nr_local: size of @local_idx array
  */
-static int __init exynos4_timer_interrupts(struct mct_context *ctx,
+static int __init_or_module exynos4_timer_interrupts(struct mct_context *ctx,
 					   struct device_node *np,
 					   const u32 *local_idx,
 					   size_t nr_local)
@@ -662,7 +667,7 @@ static int __init exynos4_timer_interrupts(struct mct_context *ctx,
 	return err;
 }
 
-static int __init mct_init_dt(struct mct_context *ctx, struct device_node *np)
+static int __init_or_module mct_init_dt(struct mct_context *ctx, struct device_node *np)
 {
 	bool frc_shared = of_property_read_bool(np, "samsung,frc-shared");
 	u32 local_idx[MCT_NR_LOCAL] = {0};
@@ -722,7 +727,9 @@ static const struct of_device_id exynos4_mct_match_table[] = {
 	{ .compatible = "samsung,exynos4412-mct", .data = &exynos4412_mct_data, },
 	{}
 };
+MODULE_DEVICE_TABLE(of, exynos4_mct_match_table);
 
+#if defined(CONFIG_ARM)
 /* Note, legacy ARM 32-bit systems depend on the MCT as the only clocksource
  * which requires this driver to be initialized very early. We need to keep this
  * special condition until we can transparently support modular and early init
@@ -748,13 +755,11 @@ static int __init mct_of_declare_init(struct device_node *np)
 	if (ret)
 		goto out_ctx;
 
-#if defined(CONFIG_ARM)
 	sched_clock_register(exynos4_read_sched_clock, 32, ctx->clk_rate);
 
 	exynos4_delay_timer.read_current_timer = &exynos4_read_current_timer;
 	exynos4_delay_timer.freq = ctx->clk_rate;
 	register_current_timer_delay(&exynos4_delay_timer);
-#endif
 
 	return 0;
 
@@ -764,3 +769,37 @@ static int __init mct_of_declare_init(struct device_node *np)
 }
 TIMER_OF_DECLARE(exynos4210, "samsung,exynos4210-mct", mct_of_declare_init);
 TIMER_OF_DECLARE(exynos4412, "samsung,exynos4412-mct", mct_of_declare_init);
+#else
+static int exynos4_mct_probe(struct platform_device *pdev)
+{
+	struct mct_context *ctx;
+	struct device *dev = &pdev->dev;
+
+	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ctx->drvdata = of_device_get_match_data(dev);
+	if (!ctx->drvdata)
+		return -EINVAL;
+
+	return mct_init_dt(ctx, dev->of_node);
+}
+
+static struct platform_driver exynos4_mct_driver = {
+	.probe		= exynos4_mct_probe,
+	.driver		= {
+		.name	= "exynos-mct",
+		.of_match_table = exynos4_mct_match_table,
+	},
+};
+
+static int __init exynos_mct_init(void)
+{
+	return platform_driver_register(&exynos4_mct_driver);
+}
+module_init(exynos_mct_init);
+
+MODULE_DESCRIPTION("Exynos Multi Core Timer Driver");
+MODULE_LICENSE("GPL");
+#endif /* CONFIG_ARM */
-- 
2.52.0.223.gf5cc29aaa4-goog



From willmcvicker at google.com  Thu Dec  4 17:10:19 2025
From: willmcvicker at google.com (Will McVicker)
Date: Fri,  5 Dec 2025 01:10:19 +0000
Subject: [PATCH v7 6/6] arm64: exynos: Drop select CLKSRC_EXYNOS_MCT
In-Reply-To: <20251205011027.720512-1-willmcvicker@google.com>
References: <20251205011027.720512-1-willmcvicker@google.com>
Message-ID: <20251205011027.720512-7-willmcvicker@google.com>

Since the Exynos MCT driver can be built as a module for some Arm64 SoCs
like gs101, drop force-selecting it as a built-in driver by ARCH_EXYNOS
and instead depend on `default y if ARCH_EXYNOS` to select it
automatically. This allows platforms like Android to build the driver as
a module if desired.

Reviewed-by: Youngmin Nam <youngmin.nam at samsung.com>
Tested-by: Youngmin Nam <youngmin.nam at samsung.com>
Signed-off-by: Will McVicker <willmcvicker at google.com>
---
 arch/arm64/Kconfig.platforms | 1 -
 1 file changed, 1 deletion(-)

diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index 13173795c43d..fc6026c368ca 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -128,7 +128,6 @@ config ARCH_CIX
 config ARCH_EXYNOS
 	bool "Samsung Exynos SoC family"
 	select COMMON_CLK_SAMSUNG
-	select CLKSRC_EXYNOS_MCT
 	select EXYNOS_PM_DOMAINS if PM_GENERIC_DOMAINS
 	select EXYNOS_PMU
 	select PINCTRL
-- 
2.52.0.223.gf5cc29aaa4-goog



From songwei.chai at oss.qualcomm.com  Thu Dec  4 17:13:21 2025
From: songwei.chai at oss.qualcomm.com (Songwei Chai)
Date: Fri, 5 Dec 2025 09:13:21 +0800
Subject: [PATCH v8 0/7] Provides support for Trigger Generation Unit
In-Reply-To: <4f53766f-6338-4d94-a947-19b95952e08a@arm.com>
References: <20251203090055.2432719-1-songwei.chai@oss.qualcomm.com>
 <4f53766f-6338-4d94-a947-19b95952e08a@arm.com>
Message-ID: <b2f3c31a-76fa-4f59-9ba4-0f93f861ffb2@oss.qualcomm.com>



On 12/3/2025 11:48 PM, Suzuki K Poulose wrote:
> Cc: Greg
> 
> On 03/12/2025 09:00, Songwei Chai wrote:
>> We propose creating a new qcom directory under drivers/hwtracing
>> to host this TGU driver, as well as additional Qualcomm-specific
>> hwtracing drivers that we plan to submit in the coming months.
>> This structure will help organize vendor-specific implementations
>> and facilitate future development and maintenance.
>>
>> Feedback from the community on this proposal is highly appreciated.
>>
>> - Why we are proposing this:
>>
>> TGU has the ability to monitor signal conditions and trigger debug- 
>> related
>> actions, serving as a programmable hardware component that enhances 
>> system
>> trace and debug capabilities. Placing it under drivers/hwtracing 
>> aligns with
>> its function as a trace generation utility.
>>
>> We previously attempted to push this driver to drivers/hwtracing/ 
>> coresight,
>> but did not receive support from the maintainers of the CoreSight 
>> subsystem.
>> The reason provided was: ?This component is primarily a part of the
>> Qualcomm proprietary QPMDA subsystem, and is capable of operating
>> independently from the CoreSight hardware trace generation system.?
>>
>> Chat history : https://lore.kernel.org/all/ 
>> CAJ9a7ViKxHThyZfFFDV_FkNRimk4uo1NrMtQ-kcaj1qO4ZcGnA at mail.gmail.com/
>>
>> Given this, we have been considering whether it would be appropriate
>> to create a dedicated drivers/hwtracing/qcom directory for
>> Qualcomm-related hwtracing drivers. This would follow the precedent set
>> by Intel, which maintains its own directory at drivers/hwtracing/ 
>> intel_th.
>> We believe this structure would significantly facilitate
>> future submissions of related Qualcomm drivers.
>>
>> - Maintenance of drivers/hwtracing/qcom:
>>
> 
> Fine by, me.
> 
> 
>> Bjorn, who maintains linux-arm-msm, will be the maintainer of this
>> directory ? we?ve discussed this with him and he?s aware that his task
>> list may grow accordingly. Additionally, Qualcomm engineers familiar with
>> the debug hardware ? such as [Tingwei Zhang, Jinlong Mao, Songwei Chai],
>> will be available to review incoming patches and support ongoing
>> development.
>>
>> - Detail for TGU:
>>
>> This component can be utilized to sense a plurality of signals and
>> create a trigger into the CTI or generate interrupts to processors
>> once the input signal meets the conditions. We can treat the TGU?s
>> workflow as a flowsheet, it has some ?steps? regions for customization.
>> In each step region, we can set the signals that we want with priority
>> in priority_group, set the conditions in each step via condition_decode,
>> and set the resultant action by condition_select. Meanwhile,
>> some TGUs (not all) also provide timer/counter functionality.
>> Based on the characteristics described above, we consider the TGU as a
>> helper in the CoreSight subsystem. Its master device is the TPDM, which
>> can transmit signals from other subsystems, and we reuse the existing
>> ports mechanism to link the TPDM to the connected TGU.
> 
> Please remove the coresight_device and other dependencies. You may use
> generic bits, CS_LOCK/UNLOCK etc. But including coresight-priv.h is
> not something I would prefer. It brings in unnecessary dependencies
> between two subsystems and I don't see any reason for using -priv.h.
> It is named as it is, for a reason, coresight private definitions.
> 
> 
>>
>> Here is a detailed example to explain how to use the TGU:
>>
>> In this example, the TGU is configured to use 2 conditions, 2 steps, and
>> the timer. The goal is to look for one of two patterns which are 
>> generated
>> from TPDM, giving priority to one, and then generate a trigger once the
>> timer reaches a certain value. In other words, two conditions are used
>> for the first step to look for the two patterns, where the one with the
>> highest priority is used in the first condition. Then, in the second 
>> step,
>> the timer is enabled and set to be compared to the given value at each
>> clock cycle. These steps are better shown below.
>> ?????????????? |-----------------|
>> ?????????????? |???????????????? |
>> ?????????????? |?????? TPDM????? |
>> ?????????????? |???????????????? |
>> ?????????????? |-----------------|
>> ??????????????????????? |
>> ??????????????????????? |
>> ???? --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- 
>> ------
>> ???? |????????????????? | 
>> ???????????????????????????????????????????????? |
>> ???? |????????????????? |                          
>> |--------------------| |
>> ???? |??? |---- --->??? |????????????????????????? |? Go to next 
>> steps? | |
>> ???? |??? |???????????? |??????????????? |--- ---> |? Enable 
>> timer????? | |
>> ???? |??? |???????????? v??????????????? |???????? | 
>> ??????????????????? | |
>> ???? |??? |??? |-----------------|?????? |         
>> |--------------------| |
>> ???? |??? |??? |???????????????? |? Yes? |??????????????????? | 
>> ?????????? |
>> ???? |??? |??? |?? inputs==0xB?? | ----->|??????????????????? | 
>> <-------- |
>> ???? |??? |??? |???????????????? |?????? |??????????????????? |      
>> No | |
>> ???? | No |??? |-----------------|?????? |                    
>> v???????? | |
>> ???? |??? |???????????? |??????????????? |          
>> |-----------------| | |
>> ???? |??? |???????????? |??????????????? |????????? |                 
>> | | |
>> ???? |??? |???????????? |??????????????? |????????? |????? timer>=3   
>> |-- |
>> ???? |??? |???????????? v??????????????? |????????? |                 
>> |?? |
>> ???? |??? |??? |-----------------|?????? |          
>> |-----------------|?? |
>> ???? |??? |??? |???????????????? |? Yes? |??????????????????? | 
>> ?????????? |
>> ???? |??? |--- |?? inputs==0xA?? | ----->|??????????????????? | 
>> Yes?????? |
>> ???? |???????? |???????????????? |??????????????????????????? | 
>> ?????????? |
>> ???? |???????? |-----------------|                            
>> v?????????? |
>> ???? |                                              
>> |-----------------|?? |
>> ???? |????????????????????????????????????????????? |                 
>> |?? |
>> ???? |????????????????????????????????????????????? |????? Trigger    
>> |?? |
>> ???? |????????????????????????????????????????????? |                 
>> |?? |
>> ???? |                                              
>> |-----------------|?? |
>> ???? |? TGU?????????????????????????????????????????????????? | 
>> ?????????? |
>> ???? |--- --- --- --- --- --- --- --- --- --- --- --- --- --- |--- --- 
>> -- |
>> ????????????????????????????????????????????????????????????? |
>> ????????????????????????????????????????????????????????????? v
>> ???????????????????????????????????????????????????? |-----------------|
>> ???????????????????????????????????????????????????? |The controllers? |
>> ???????????????????????????????????????????????????? |which will use?? |
>> ???????????????????????????????????????????????????? |triggers further |
>> ???????????????????????????????????????????????????? |-----------------|
>>
>> steps:
>> ???? 1. Reset TGU /*it will disable tgu and reset dataset*/
>> ???? - echo 1 > /sys/bus/coresight/devices/<tgu-name>/reset_tgu
>>
>> ???? 2. Set the pattern match for priority0 to 0xA = 0b1010 and for
>> ??????? priority 1 to 0xB = 0b1011.
>> ???? - echo 0x11113232 > /sys/bus/coresight/devices/<tgu-name>/ 
>> step0_priority0/reg0
>> ???? - echo 0x11113233 > /sys/bus/coresight/devices/<tgu-name>/ 
>> step0_priority1/reg0
> 
> Why do they need to be coresight devices and appear on the coresight bus 
> if they are not coresight devices ? As I understand they are simply
> devices with some sysfs knobs.
> 
> Otherwise, happy with the proposal
> 
> 
> Suzuki

Hi Suzuki,

Would it be a good idea to register the TGU device as a platform device 
so that it will appear under "/sys/devices/platform/" and the code could 
also be decoupled from coresight-priv.h

BRs,
Songwei>
> 
> 
> 
>>
>> ???? Note:
>> ???????? Bit distribution diagram for each priority register
>>      
>> |-------------------------------------------------------------------|
>> ???? |?? Bits????????? |?????? Field Nam?? |    
>> Description????????????? |
>>      
>> |-------------------------------------------------------------------|
>> ???? |???????????????? |?????????????????? | 00 = bypass for OR 
>> output?? |
>> ???? |???? 29:28?????? |?? SEL_BIT7_TYPE2? | 01 = bypass for AND 
>> output? |
>> ???? |???????????????? |?????????????????? | 10 = sense input '0' is 
>> true|
>> ???? |???????????????? |?????????????????? | 11 = sense input '1' is 
>> true|
>>      
>> |-------------------------------------------------------------------|
>> ???? |???????????????? |?????????????????? | 00 = bypass for OR 
>> output?? |
>> ???? |???? 25:24?????? |?? SEL_BIT6_TYPE2? | 01 = bypass for AND 
>> output? |
>> ???? |???????????????? |?????????????????? | 10 = sense input '0' is 
>> true|
>> ???? |???????????????? |?????????????????? | 11 = sense input '1' is 
>> true|
>>      
>> |-------------------------------------------------------------------|
>> ???? |???????????????? |?????????????????? | 00 = bypass for OR 
>> output?? |
>> ???? |???? 21:20?????? |?? SEL_BIT5_TYPE2? | 01 = bypass for AND 
>> output? |
>> ???? |???????????????? |?????????????????? | 10 = sense input '0' is 
>> true|
>> ???? |???????????????? |?????????????????? | 11 = sense input '1' is 
>> true|
>>      
>> |-------------------------------------------------------------------|
>> ???? |???????????????? |?????????????????? | 00 = bypass for OR 
>> output?? |
>> ???? |???? 17:16?????? |?? SEL_BIT4_TYPE2? | 01 = bypass for AND 
>> output? |
>> ???? |???????????????? |?????????????????? | 10 = sense input '0' is 
>> true|
>> ???? |???????????????? |?????????????????? | 11 = sense input '1' is 
>> true|
>>      
>> |-------------------------------------------------------------------|
>> ???? |???????????????? |?????????????????? | 00 = bypass for OR 
>> output?? |
>> ???? |???? 13:12?????? |?? SEL_BIT3_TYPE2? | 01 = bypass for AND 
>> output? |
>> ???? |???????????????? |?????????????????? | 10 = sense input '0' is 
>> true|
>> ???? |???????????????? |?????????????????? | 11 = sense input '1' is 
>> true|
>>      
>> |-------------------------------------------------------------------|
>> ???? |???????????????? |?????????????????? | 00 = bypass for OR 
>> output?? |
>> ???? |????? 9:8??????? |?? SEL_BIT2_TYPE2? | 01 = bypass for AND 
>> output? |
>> ???? |???????????????? |?????????????????? | 10 = sense input '0' is 
>> true|
>> ???? |???????????????? |?????????????????? | 11 = sense input '1' is 
>> true|
>>      
>> |-------------------------------------------------------------------|
>> ???? |???????????????? |?????????????????? | 00 = bypass for OR 
>> output?? |
>> ???? |????? 5:4??????? |? SEL_BIT1_TYPE2?? | 01 = bypass for AND 
>> output? |
>> ???? |???????????????? |?????????????????? | 10 = sense input '0' is 
>> true|
>> ???? |???????????????? |?????????????????? | 11 = sense input '1' is 
>> true|
>>      
>> |-------------------------------------------------------------------|
>> ???? |???????????????? |?????????????????? | 00 = bypass for OR 
>> output?? |
>> ???? |????? 1:0??????? |? SEL_BIT0_TYPE2?? | 01 = bypass for AND 
>> output? |
>> ???? |???????????????? |?????????????????? | 10 = sense input '0' is 
>> true|
>> ???? |???????????????? |?????????????????? | 11 = sense input '1' is 
>> true|
>>      
>> |-------------------------------------------------------------------|
>> ???? These bits are used to identify the signals we want to sense, with
>> ???? a maximum signal number of 140. For example, to sense the signal
>> ???? 0xA (binary 1010), we set the value of bits 0 to 13 to 3232, which
>> ???? represents 1010. The remaining bits are set to 1, as we want to use
>> ???? AND gate to summarize all the signals we want to sense here. For
>> ???? rising or falling edge detection of any input to the priority, set
>> ???? the remaining bits to 0 to use an OR gate.
>>
>> ???? 3. look for the pattern for priority_i i=0,1.
>> ???? - echo 0x3 > /sys/bus/coresight/devices/<tgu-name>/ 
>> step0_condition_decode/reg0
>> ???? - echo 0x30 > /sys/bus/coresight/devices/<tgu-name>/ 
>> step0_condition_decode/reg1
>>
>>      
>> |-------------------------------------------------------------------------------|
>> ???? |?? Bits????????? |??? Field Nam??????? |            
>> Description??????????????? |
>>      
>> |-------------------------------------------------------------------------------|
>> ???? |???????????????? |???????????????????? |For each decoded 
>> condition, this?????? |
>> ???? |????? 24???????? |?????? NOT?????????? |inverts the output. If 
>> the condition?? |
>> ???? |???????????????? |???????????????????? |decodes to true, and the 
>> NOT field???? |
>> ???? |???????????????? |???????????????????? |is '1', then the output 
>> is NOT true.?? |
>>      
>> |-------------------------------------------------------------------------------|
>> ???? |???????????????? |???????????????????? |When '1' the output from 
>> the associated|
>> ???? |????? 21???????? |? BC0_COMP_ACTIVE??? |comparator will be 
>> actively included in|
>> ???? |???????????????? |???????????????????? |the decoding of this 
>> particular??????? |
>> ???? |???????????????? |???????????????????? | 
>> condition.???????????????????????????? |
>>      
>> |-------------------------------------------------------------------------------|
>> ???? |???????????????? |???????????????????? |When '1' the output from 
>> the associated|
>> ???? |???????????????? |???????????????????? |comparator will need to 
>> be 1 to affect |
>> ???? |????? 20???????? |?? BC0_COMP_HIGH???? |the decoding of this 
>> condition.??????? |
>> ???? |???????????????? |???????????????????? |Conversely, a '0' here 
>> requires a '0'? |
>> ???? |???????????????? |???????????????????? |from the 
>> comparator??????????????????? |
>>      
>> |-------------------------------------------------------------------------------|
>> ???? |???????????????? |???????????????????? |When '1' the output from 
>> the associated|
>> ???? |????? 17???????? |???????????????????? |comparator will be 
>> actively included in|
>> ???? |???????????????? |? TC0_COMP_ACTIVE??? |the decoding of this 
>> particular??????? |
>> ???? |???????????????? |???????????????????? | 
>> condition.???????????????????????????? |
>>      
>> |-------------------------------------------------------------------------------|
>> ???? |???????????????? |???????????????????? |When '1' the output from 
>> the associated|
>> ???? |???????????????? |???????????????????? |comparator will need to 
>> be 1 to affect |
>> ???? |????? 16???????? |? TC0_COMP_HIGH????? |the decoding of this 
>> particular??????? |
>> ???? |???????????????? |???????????????????? |condition.Conversely, a 
>> 0 here???????? |
>> ???? |???????????????? |???????????????????? |requires a '0' from the 
>> comparator???? |
>>      
>> |-------------------------------------------------------------------------------|
>> ???? |???????????????? |???????????????????? |When '1' the output from 
>> Priority_n??? |
>> ???? |???????????????? |???????????????????? |OR logic will be 
>> actively????????????? |
>> ???? |???? 4n+3??????? | Priority_n_OR_ACTIVE|included in the decoding 
>> of??????????? |
>> ???? |???????????????? |??? (n=0,1,2,3)????? |this particular 
>> condition.???????????? |
>> ???? |???????????????? |???????????????????? | 
>> ?????????????????????????????????????? |
>>      
>> |-------------------------------------------------------------------------------|
>> ???? |???????????????? |???????????????????? |When '1' the output from 
>> Priority_n??? |
>> ???? |???????????????? |???????????????????? |will need to be '1' to 
>> affect the????? |
>> ???? |???? 4n+2??????? |? Priority_n_OR_HIGH |decoding of this 
>> particular??????????? |
>> ???? |???????????????? |??? (n=0,1,2,3)????? |condition. Conversely, a 
>> '0' here????? |
>> ???? |???????????????? |???????????????????? |requires a '0' from 
>> Priority_n OR logic|
>>      
>> |-------------------------------------------------------------------------------|
>> ???? |???????????????? |???????????????????? |When '1' the output from 
>> Priority_n??? |
>> ???? |???????????????? |???????????????????? |AND logic will be 
>> actively???????????? |
>> ???? |???? 4n+1??????? |Priority_n_AND_ACTIVE|included in the decoding 
>> of this?????? |
>> ???? |???????????????? |? (n=0,1,2,3)??????? |particular 
>> condition.????????????????? |
>> ???? |???????????????? |???????????????????? | 
>> ?????????????????????????????????????? |
>>      
>> |-------------------------------------------------------------------------------|
>> ???? |???????????????? |???????????????????? |When '1' the output from 
>> Priority_n??? |
>> ???? |???????????????? |???????????????????? |AND logic will need to 
>> be '1' to?????? |
>> ???? |????? 4n???????? | Priority_n_AND_HIGH |affect the decoding of 
>> this??????????? |
>> ???? |???????????????? |?? (n=0,1,2,3)?????? |particular condition. 
>> Conversely,????? |
>> ???? |???????????????? |???????????????????? |a '0' here requires a 
>> '0' from???????? |
>> ???? |???????????????? |???????????????????? |Priority_n AND 
>> logic.????????????????? |
>>      
>> |-------------------------------------------------------------------------------|
>> ???? Since we use `priority_0` and `priority_1` with an AND output in 
>> step 2, we set `0x3`
>> ???? and `0x30` here to activate them.
>>
>> ???? 4. Set NEXT_STEP = 1 and TC0_ENABLE = 1 so that when the conditions
>> ??????? are met then the next step will be step 1 and the timer will 
>> be enabled.
>> ???? - echo 0x20008 > /sys/bus/coresight/devices/<tgu-name>/ 
>> step0_condition_select/reg0
>> ???? - echo 0x20008 > /sys/bus/coresight/devices/<tgu-name>/ 
>> step0_condition_select/reg1
>>
>>      
>> |-----------------------------------------------------------------------------|
>> ???? |?? Bits????????? |?????? Field Nam?? |            
>> Description??????????????? |
>>      
>> |-----------------------------------------------------------------------------|
>> ???? |???????????????? |?????????????????? |This field defines the 
>> next step the?? |
>> ???? |??? 18:17??????? |???? NEXT_STEP???? |TGU will 'goto' for the 
>> associated???? |
>> ???? |???????????????? |?????????????????? |Condition and 
>> Step.??????????????????? |
>>      
>> |-----------------------------------------------------------------------------|
>> ???? |???????????????? |?????????????????? |For each possible output 
>> trigger?????? |
>> ???? |??? 13?????????? |???? TRIGGER?????? |available, set a '1' if 
>> you want?????? |
>> ???? |???????????????? |?????????????????? |the trigger to go active 
>> for the?????? |
>> ???? |???????????????? |?????????????????? |associated condition and 
>> Step.???????? |
>>      
>> |-----------------------------------------------------------------------------|
>> ???? |???????????????? |?????????????????? |This will cause BC0 to 
>> increment if the|
>> ???? |??? 9??????????? |???? BC0_INC?????? |associated Condition is 
>> decoded for??? |
>> ???? |???????????????? |?????????????????? |this 
>> step.???????????????????????????? |
>>      
>> |-----------------------------------------------------------------------------|
>> ???? |???????????????? |?????????????????? |This will cause BC0 to 
>> decrement if the|
>> ???? |??? 8??????????? |???? BC0_DEC?????? |associated Condition is 
>> decoded for??? |
>> ???? |???????????????? |?????????????????? |this 
>> step.???????????????????????????? |
>>      
>> |-----------------------------------------------------------------------------|
>> ???? |???????????????? |?????????????????? |This will clear BC0 count 
>> value to 0 if|
>> ???? |??? 7??????????? |???? BC0_CLEAR???? |the associated Condition 
>> is decoded??? |
>> ???? |???????????????? |?????????????????? |for this 
>> step.???????????????????????? |
>>      
>> |-----------------------------------------------------------------------------|
>> ???? |???????????????? |?????????????????? |This will cause TC0 to 
>> increment until |
>> ???? |??? 3??????????? |???? TC0_ENABLE??? |paused or cleared if the 
>> associated??? |
>> ???? |???????????????? |?????????????????? |Condition is decoded for 
>> this step.??? |
>>      
>> |-----------------------------------------------------------------------------|
>> ???? |???????????????? |?????????????????? |This will cause TC0 to 
>> pause until???? |
>> ???? |??? 2??????????? |???? TC0_PAUSE???? |enabled if the associated 
>> Condition??? |
>> ???? |???????????????? |?????????????????? |is decoded for this 
>> step.????????????? |
>>      
>> |-----------------------------------------------------------------------------|
>> ???? |???????????????? |?????????????????? |This will clear TC0 count 
>> value to 0?? |
>> ???? |??? 1??????????? |???? TC0_CLEAR???? |if the associated 
>> Condition is???????? |
>> ???? |???????????????? |?????????????????? |decoded for this 
>> step.???????????????? |
>>      
>> |-----------------------------------------------------------------------------|
>> ???? |???????????????? |?????????????????? |This will set the done 
>> signal to the?? |
>> ???? |??? 0??????????? |???? DONE????????? |TGU FSM if the associated 
>> Condition??? |
>> ???? |???????????????? |?????????????????? |is decoded for this 
>> step.????????????? |
>>      
>> |-----------------------------------------------------------------------------|
>> ???? Based on the distribution diagram, we set `0x20008` for 
>> `priority0` and `priority1` to
>> ???? achieve "jump to step 1 and enable TC0" once the signal is sensed.
>>
>> ???? 5. activate the timer comparison for this step.
>> ???? -? echo 0x30000? > /sys/bus/coresight/devices/<tgu-name>/ 
>> step1_condition_decode/reg0
>>
>>      
>> |-------------------------------------------------------------------------------|
>> ???? |???????????????? |???????????????????? |When '1' the output from 
>> the associated|
>> ???? |????? 17???????? |???????????????????? |comparator will be 
>> actively included in|
>> ???? |???????????????? |? TC0_COMP_ACTIVE??? |the decoding of this 
>> particular??????? |
>> ???? |???????????????? |???????????????????? | 
>> condition.???????????????????????????? |
>>      
>> |-------------------------------------------------------------------------------|
>> ???? |???????????????? |???????????????????? |When '1' the output from 
>> the associated|
>> ???? |???????????????? |???????????????????? |comparator will need to 
>> be 1 to affect |
>> ???? |????? 16???????? |? TC0_COMP_HIGH????? |the decoding of this 
>> particular??????? |
>> ???? |???????????????? |???????????????????? |condition.Conversely, a 
>> 0 here???????? |
>> ???? |???????????????? |???????????????????? |requires a '0' from the 
>> comparator???? |
>>      
>> |-------------------------------------------------------------------------------|
>> ???? Accroding to the decode distribution diagram , we give 0x30000 
>> here to set 16th&17th bit
>> ???? to enable timer comparison.
>>
>> ???? 6. Set the NEXT_STEP = 0 and TC0_PAUSE = 1 and TC0_CLEAR = 1 once 
>> the timer
>> ??????? has reached the given value.
>> ???? - echo 0x6 > /sys/bus/coresight/devices/<tgu-name>/ 
>> step1_condition_select/reg0
>>
>> ???? 7. Enable Trigger 0 for TGU when the condition 0 is met in step1,
>> ??????? i.e. when the timer reaches 3.
>> ???? - echo 0x2000 > /sys/bus/coresight/devices/<tgu-name>/ 
>> step1_condition_select/default
>>
>> ???? Note:
>> ???????? 1. 'default' register allows for establishing the resultant 
>> action for
>> ???????? the default condition
>>
>> ???????? 2. Trigger:For each possible output trigger available from
>> ???????? the Design document, there are three triggers: interrupts, CTI,
>> ???????? and Cross-TGU mapping.All three triggers can occur, but
>> ???????? the choice of which trigger to use depends on the user's
>> ???????? needs.
>>
>> ???? 8. Compare the timer to 3 in step 1.
>> ???? - echo 0x3 > /sys/bus/coresight/devices/<tgu-name>/step1_timer/reg0
>>
>> ???? 9. enale tgu
>> ???? - echo 1 > /sys/bus/coresight/devices/<tgu-name>/enable_tgu
>> ---
>> Link to V7: https://lore.kernel.org/all/20251104064043.88972-1- 
>> songwei.chai at oss.qualcomm.com/
>>
>> Changes in V8:
>> - Add "select" section in bindings.
>> - Update publish date in "sysfs-bus-coresight-devices-tgu".
>> ---
>> Link to V6: https://lore.kernel.org/all/20250709104114.22240-1- 
>> songchai at qti.qualcomm.com/
>>
>> Changes in V7:
>> - Move the TGU code location from 'drivers/hwtracing/coresight/' to 
>> 'drivers/hwtracing/qcom/'.
>> - Rename the spinlock used in the code from 'spinlock' to 'lock'.
>> - Perform the 'calculate_array_location' separately, instead of doing 
>> it within the function.
>> - Update the sender email address.
>> ---
>> Link to V5: https://lore.kernel.org/all/20250529081949.26493-1- 
>> quic_songchai at quicinc.com/
>>
>> Changes in V6:
>> - Replace spinlock with guard(spinlock) in tgu_enable.
>> - Remove redundant blank line.
>> - Update publish date and contact member's name in "sysfs-bus- 
>> coresight-devices-tgu".
>> ---
>> Link to V4: https://patchwork.kernel.org/project/linux-arm-msm/ 
>> cover/20250423101054.954066-1-quic_songchai at quicinc.com/
>>
>> Changes in V5:
>> - Update publish date and kernel_version in "sysfs-bus-coresight- 
>> devices-tgu"
>> ---
>> Link to V3: https://lore.kernel.org/all/20250227092640.2666894-1- 
>> quic_songchai at quicinc.com/
>>
>> Changes in V4:
>> - Add changlog in coverletter.
>> - Correct 'year' in Copyright in patch1.
>> - Correct port mechansim description in patch1.
>> - Remove 'tgu-steps','tgu-regs','tgu-conditions','tgu-timer-counters' 
>> from dt-binding
>> and set them through reading DEVID register as per Mike's suggestion.
>> - Modify tgu_disable func to make it have single return point in 
>> patch2 as per
>> Mike's suggestion.
>> - Use sysfs_emit in enable_tgu_show func in ptach2.
>> - Remove redundant judgement in enable_tgu_store in patch2.
>> - Correct typo in description in patch3.
>> - Set default ret as SYSFS_GROUP_INVISIBLE, and returnret at end in 
>> pacth3 as
>> per Mike's suggestion.
>> - Remove tgu_dataset_ro definition in patch3
>> - Use #define constants with explanations of what they are rather than
>> arbitrary magic numbers in patch3 and patch4.
>> - Check -EINVAL before using 'calculate_array_location()' in array in 
>> patch4.
>> - Add 'default' in 'tgu_dataset_show''s switch part in patch4.
>> - Document the value needed to initiate the reset in pacth7.
>> - Check "value" in 'reset_tgu_store' and bail out with an error code 
>> if 0 in patch7.
>> - Remove dev_dbg in 'reset_tgu_store' in patch7.
>> ---
>> Link to V2: https://lore.kernel.org/all/20241010073917.16023-1- 
>> quic_songchai at quicinc.com/
>>
>> Changes in V3:
>> - Correct typo and format in dt-binding in patch1
>> - Rebase to the latest kernel version
>> ---
>> Link to V1: https://lore.kernel.org/all/20240830092311.14400-1- 
>> quic_songchai at quicinc.com/
>>
>> Changes in V2:
>> ? - Use real name instead of login name,
>> ? - Correct typo and format in dt-binding and code.
>> ? - Bring order in tgu_prob(declarations with and without assignments) 
>> as per
>> Krzysztof's suggestion.
>> ? - Add module device table in patch2.
>> ? - Set const for tgu_common_grp and tgu_ids in patch2.
>> ? - Initialize 'data' in tgu_ids to fix the warning in pacth2.
>> ---
>>
>> Songwei Chai (7):
>> ?? dt-bindings: arm: Add support for Qualcomm TGU trace
>> ?? qcom-tgu: Add TGU driver
>> ?? qcom-tgu: Add signal priority support
>> ?? qcom-tgu: Add TGU decode support
>> ?? qcom-tgu: Add support to configure next action
>> ?? qcom-tgu: Add timer/counter functionality for TGU
>> ?? qcom-tgu: Add reset node to initialize
>>
>> ? .../testing/sysfs-bus-coresight-devices-tgu?? |? 51 ++
>> ? .../devicetree/bindings/arm/qcom,tgu.yaml???? |? 92 +++
>> ? drivers/Makefile????????????????????????????? |?? 1 +
>> ? drivers/hwtracing/Kconfig???????????????????? |?? 2 +
>> ? drivers/hwtracing/qcom/Kconfig??????????????? |? 18 +
>> ? drivers/hwtracing/qcom/Makefile?????????????? |?? 3 +
>> ? drivers/hwtracing/qcom/tgu.c????????????????? | 737 ++++++++++++++++++
>> ? drivers/hwtracing/qcom/tgu.h????????????????? | 252 ++++++
>> ? 8 files changed, 1156 insertions(+)
>> ? create mode 100644 Documentation/ABI/testing/sysfs-bus-coresight- 
>> devices-tgu
>> ? create mode 100644 Documentation/devicetree/bindings/arm/qcom,tgu.yaml
>> ? create mode 100644 drivers/hwtracing/qcom/Kconfig
>> ? create mode 100644 drivers/hwtracing/qcom/Makefile
>> ? create mode 100644 drivers/hwtracing/qcom/tgu.c
>> ? create mode 100644 drivers/hwtracing/qcom/tgu.h
>>
> 



From jacky_chou at aspeedtech.com  Thu Dec  4 17:37:22 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Fri, 5 Dec 2025 09:37:22 +0800
Subject: [PATCH net-next] net: mdio: aspeed: add dummy read to avoid
 read-after-write issue
Message-ID: <20251205-aspeed_mdio_add_dummy_read-v1-1-60145ae20ea7@aspeedtech.com>

The Aspeed MDIO controller may return incorrect data when a read operation
follows immediately after a write. Due to a controller bug, the subsequent
read can latch stale data, causing the polling logic to terminate earlier
than expected.

To work around this hardware issue, insert a dummy read after each write
operation. This ensures that the next actual read returns the correct
data and prevents premature polling exit.

This workaround has been verified to stabilize MDIO transactions on
affected Aspeed platforms.

Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
---
 drivers/net/mdio/mdio-aspeed.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/net/mdio/mdio-aspeed.c b/drivers/net/mdio/mdio-aspeed.c
index e55be6dc9ae7..00e61b922876 100644
--- a/drivers/net/mdio/mdio-aspeed.c
+++ b/drivers/net/mdio/mdio-aspeed.c
@@ -62,6 +62,12 @@ static int aspeed_mdio_op(struct mii_bus *bus, u8 st, u8 op, u8 phyad, u8 regad,
 		| FIELD_PREP(ASPEED_MDIO_DATA_MIIRDATA, data);
 
 	iowrite32(ctrl, ctx->base + ASPEED_MDIO_CTRL);
+	/* Workaround for read-after-write issue.
+	 * The controller may return stale data if a read follows immediately
+	 * after a write. A dummy read forces the hardware to update its
+	 * internal state, ensuring that the next real read returns correct data.
+	 */
+	(void)ioread32(ctx->base + ASPEED_MDIO_CTRL);
 
 	return readl_poll_timeout(ctx->base + ASPEED_MDIO_CTRL, ctrl,
 				!(ctrl & ASPEED_MDIO_CTRL_FIRE),

---
base-commit: 8f7aa3d3c7323f4ca2768a9e74ebbe359c4f8f88
change-id: 20251205-aspeed_mdio_add_dummy_read-d58d1e49412d

Best regards,
-- 
Jacky Chou <jacky_chou at aspeedtech.com>



From kuba at kernel.org  Thu Dec  4 17:51:48 2025
From: kuba at kernel.org (Jakub Kicinski)
Date: Thu, 4 Dec 2025 17:51:48 -0800
Subject: [PATCH v3] net: stmmac: Modify the judgment condition of
 "tx_avail" from 1 to 2
In-Reply-To: <tencent_639FC431D959DA3E8FC007985FC88EA5A90A@qq.com>
References: <tencent_639FC431D959DA3E8FC007985FC88EA5A90A@qq.com>
Message-ID: <20251204175148.5a5cc065@kernel.org>

On Wed,  3 Dec 2025 09:31:52 +0800 2694439648 at qq.com wrote:
> -	if (unlikely(stmmac_tx_avail(priv, queue) <= (MAX_SKB_FRAGS + 1))) {
> +	if (unlikely(stmmac_tx_avail(priv, queue) <= (MAX_SKB_FRAGS + 2))) {

Please add a constant for "(MAX_SKB_FRAGS + 2)" and a comment next to
it explaining why the literal 2 is used.


From ming.qian at oss.nxp.com  Thu Dec  4 17:54:23 2025
From: ming.qian at oss.nxp.com (ming.qian at oss.nxp.com)
Date: Fri,  5 Dec 2025 09:54:23 +0800
Subject: [PATCH v4 0/3] Fix concurrency issues between G1 and G2 on
Message-ID: <20251205015428.643-1-ming.qian@oss.nxp.com>

From: Ming Qian <ming.qian at oss.nxp.com>

On the i.MX8MQ, we encountered some concurrency issues with H264 and HEVC
decoding.

There are two main reasons:
1. The vpu blk-ctrl don't have separate reset and clock enable bits.
2. The g1 VPU and g2 VPU cannot decode simultaneously.

We attempted to make corresponding fix to address these two issues.

Ming Qian (2):
  pmdomain: imx8m-blk-ctrl: Remove separate rst and clk mask for 8mq vpu
  media: verisilicon: Avoid G2 bus error while decoding H.264 and HEVC

Nicolas Dufresne (1):
  media: v4l2-mem2mem: Add a kref to the v4l2_m2m_dev structure

 drivers/media/platform/verisilicon/hantro.h   |  2 +
 .../media/platform/verisilicon/hantro_drv.c   | 42 +++++++++++++++++--
 .../media/platform/verisilicon/imx8m_vpu_hw.c |  8 ++++
 drivers/media/v4l2-core/v4l2-mem2mem.c        | 23 ++++++++++
 drivers/pmdomain/imx/imx8m-blk-ctrl.c         | 11 +++--
 include/media/v4l2-mem2mem.h                  | 21 ++++++++++
 6 files changed, 100 insertions(+), 7 deletions(-)

-- 
2.52.0



From ming.qian at oss.nxp.com  Thu Dec  4 17:54:24 2025
From: ming.qian at oss.nxp.com (ming.qian at oss.nxp.com)
Date: Fri,  5 Dec 2025 09:54:24 +0800
Subject: [PATCH v4 1/3] media: v4l2-mem2mem: Add a kref to the v4l2_m2m_dev structure
In-Reply-To: <20251205015428.643-1-ming.qian@oss.nxp.com>
References: <20251205015428.643-1-ming.qian@oss.nxp.com>
Message-ID: <20251205015428.643-2-ming.qian@oss.nxp.com>

From: Nicolas Dufresne <nicolas.dufresne at collabora.com>

Adding a reference count to the v4l2_m2m_dev structure allow safely
sharing it across multiple hardware nodes. This can be used to prevent
running jobs concurrently on m2m cores that have some internal resource
sharing.

Signed-off-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Signed-off-by: Ming Qian <ming.qian at oss.nxp.com>
---
v4
- Add my Signed-off-by

 drivers/media/v4l2-core/v4l2-mem2mem.c | 23 +++++++++++++++++++++++
 include/media/v4l2-mem2mem.h           | 21 +++++++++++++++++++++
 2 files changed, 44 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c
index fec93c1a9231..ae0de54d4c3e 100644
--- a/drivers/media/v4l2-core/v4l2-mem2mem.c
+++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
@@ -90,6 +90,7 @@ static const char * const m2m_entity_name[] = {
  * @job_work:		worker to run queued jobs.
  * @job_queue_flags:	flags of the queue status, %QUEUE_PAUSED.
  * @m2m_ops:		driver callbacks
+ * @kref:		device reference count
  */
 struct v4l2_m2m_dev {
 	struct v4l2_m2m_ctx	*curr_ctx;
@@ -109,6 +110,8 @@ struct v4l2_m2m_dev {
 	unsigned long		job_queue_flags;
 
 	const struct v4l2_m2m_ops *m2m_ops;
+
+	struct kref kref;
 };
 
 static struct v4l2_m2m_queue_ctx *get_queue_ctx(struct v4l2_m2m_ctx *m2m_ctx,
@@ -1200,6 +1203,7 @@ struct v4l2_m2m_dev *v4l2_m2m_init(const struct v4l2_m2m_ops *m2m_ops)
 	INIT_LIST_HEAD(&m2m_dev->job_queue);
 	spin_lock_init(&m2m_dev->job_spinlock);
 	INIT_WORK(&m2m_dev->job_work, v4l2_m2m_device_run_work);
+	kref_init(&m2m_dev->kref);
 
 	return m2m_dev;
 }
@@ -1211,6 +1215,25 @@ void v4l2_m2m_release(struct v4l2_m2m_dev *m2m_dev)
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_release);
 
+void v4l2_m2m_get(struct v4l2_m2m_dev *m2m_dev)
+{
+	kref_get(&m2m_dev->kref);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_get);
+
+static void v4l2_m2m_release_from_kref(struct kref *kref)
+{
+	struct v4l2_m2m_dev *m2m_dev = container_of(kref, struct v4l2_m2m_dev, kref);
+
+	v4l2_m2m_release(m2m_dev);
+}
+
+void v4l2_m2m_put(struct v4l2_m2m_dev *m2m_dev)
+{
+	kref_put(&m2m_dev->kref, v4l2_m2m_release_from_kref);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_put);
+
 struct v4l2_m2m_ctx *v4l2_m2m_ctx_init(struct v4l2_m2m_dev *m2m_dev,
 		void *drv_priv,
 		int (*queue_init)(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq))
diff --git a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h
index bf6a09a04dcf..ca295c660c7f 100644
--- a/include/media/v4l2-mem2mem.h
+++ b/include/media/v4l2-mem2mem.h
@@ -547,6 +547,27 @@ v4l2_m2m_register_media_controller(struct v4l2_m2m_dev *m2m_dev,
  */
 void v4l2_m2m_release(struct v4l2_m2m_dev *m2m_dev);
 
+/**
+ * v4l2_m2m_get() - take a reference to the m2m_dev structure
+ *
+ * @m2m_dev: opaque pointer to the internal data to handle M2M context
+ *
+ * This is used to share the M2M device across multiple devices. This
+ * can be used to avoid scheduling two hardware nodes concurrently.
+ */
+void v4l2_m2m_get(struct v4l2_m2m_dev *m2m_dev);
+
+/**
+ * v4l2_m2m_put() - remove a reference to the m2m_dev structure
+ *
+ * @m2m_dev: opaque pointer to the internal data to handle M2M context
+ *
+ * Once the M2M device have no more references, v4l2_m2m_realse() will be
+ * called automatically. Users of this method should never call
+ * v4l2_m2m_release() directly. See v4l2_m2m_get() for more details.
+ */
+void v4l2_m2m_put(struct v4l2_m2m_dev *m2m_dev);
+
 /**
  * v4l2_m2m_ctx_init() - allocate and initialize a m2m context
  *
-- 
2.52.0



From ming.qian at oss.nxp.com  Thu Dec  4 17:54:25 2025
From: ming.qian at oss.nxp.com (ming.qian at oss.nxp.com)
Date: Fri,  5 Dec 2025 09:54:25 +0800
Subject: [PATCH v4 2/3] pmdomain: imx8m-blk-ctrl: Remove separate rst and clk mask for 8mq vpu
In-Reply-To: <20251205015428.643-1-ming.qian@oss.nxp.com>
References: <20251205015428.643-1-ming.qian@oss.nxp.com>
Message-ID: <20251205015428.643-3-ming.qian@oss.nxp.com>

From: Ming Qian <ming.qian at oss.nxp.com>

For i.MX8MQ platform, the ADB in the VPUMIX domain has no separate reset
and clock enable bits, but is ungated and reset together with the VPUs.
So we can't reset G1 or G2 separately, it may led to the system hang.
Remove rst_mask and clk_mask of imx8mq_vpu_blk_ctl_domain_data.
Let imx8mq_vpu_power_notifier() do really vpu reset.

Fixes: 608d7c325e85 ("soc: imx: imx8m-blk-ctrl: add i.MX8MQ VPU blk-ctrl")
Signed-off-by: Ming Qian <ming.qian at oss.nxp.com>
Reviewed-by: Benjamin Gaignard <benjamin.gaignard at collabora.com>
Reviewed-by: Peng Fan <peng.fan at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
v3
- Add some comments
v2
- Update commit message

 drivers/pmdomain/imx/imx8m-blk-ctrl.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/pmdomain/imx/imx8m-blk-ctrl.c b/drivers/pmdomain/imx/imx8m-blk-ctrl.c
index 5c83e5599f1e..74bf4936991d 100644
--- a/drivers/pmdomain/imx/imx8m-blk-ctrl.c
+++ b/drivers/pmdomain/imx/imx8m-blk-ctrl.c
@@ -846,22 +846,25 @@ static int imx8mq_vpu_power_notifier(struct notifier_block *nb,
 	return NOTIFY_OK;
 }
 
+/*
+ * For i.MX8MQ, the ADB in the VPUMIX domain has no separate reset and clock
+ * enable bits, but is ungated and reset together with the VPUs.
+ * Resetting G1 or G2 separately may led to system hang.
+ * Remove the rst_mask and clk_mask from the domain data of G1 and G2,
+ * Let imx8mq_vpu_power_notifier() do really vpu reset.
+ */
 static const struct imx8m_blk_ctrl_domain_data imx8mq_vpu_blk_ctl_domain_data[] = {
 	[IMX8MQ_VPUBLK_PD_G1] = {
 		.name = "vpublk-g1",
 		.clk_names = (const char *[]){ "g1", },
 		.num_clks = 1,
 		.gpc_name = "g1",
-		.rst_mask = BIT(1),
-		.clk_mask = BIT(1),
 	},
 	[IMX8MQ_VPUBLK_PD_G2] = {
 		.name = "vpublk-g2",
 		.clk_names = (const char *[]){ "g2", },
 		.num_clks = 1,
 		.gpc_name = "g2",
-		.rst_mask = BIT(0),
-		.clk_mask = BIT(0),
 	},
 };
 
-- 
2.52.0



From ming.qian at oss.nxp.com  Thu Dec  4 17:54:26 2025
From: ming.qian at oss.nxp.com (ming.qian at oss.nxp.com)
Date: Fri,  5 Dec 2025 09:54:26 +0800
Subject: [PATCH v4 3/3] media: verisilicon: Avoid G2 bus error while decoding H.264 and HEVC
In-Reply-To: <20251205015428.643-1-ming.qian@oss.nxp.com>
References: <20251205015428.643-1-ming.qian@oss.nxp.com>
Message-ID: <20251205015428.643-4-ming.qian@oss.nxp.com>

From: Ming Qian <ming.qian at oss.nxp.com>

For the i.MX8MQ platform, there is a hardware limitation: the g1 VPU and
g2 VPU cannot decode simultaneously; otherwise, it will cause below bus
error and produce corrupted pictures, even potentially lead to system hang.

[  110.527986] hantro-vpu 38310000.video-codec: frame decode timed out.
[  110.583517] hantro-vpu 38310000.video-codec: bus error detected.

Therefore, it is necessary to ensure that g1 and g2 operate alternately.
This allows for successful multi-instance decoding of H.264 and HEVC.

To achieve this, g1 and g2 share the same v4l2_m2m_dev, and then the
v4l2_m2m_dev can handle the scheduling.

Fixes: cb5dd5a0fa518 ("media: hantro: Introduce G2/HEVC decoder")
Co-developed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Signed-off-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Signed-off-by: Ming Qian <ming.qian at oss.nxp.com>
---
v4
- Avoid double put device node in for_each_matching_node
v3
- Add some comments
v2
- Update commit message

 drivers/media/platform/verisilicon/hantro.h   |  2 +
 .../media/platform/verisilicon/hantro_drv.c   | 42 +++++++++++++++++--
 .../media/platform/verisilicon/imx8m_vpu_hw.c |  8 ++++
 3 files changed, 49 insertions(+), 3 deletions(-)

diff --git a/drivers/media/platform/verisilicon/hantro.h b/drivers/media/platform/verisilicon/hantro.h
index e0fdc4535b2d..0353de154a1e 100644
--- a/drivers/media/platform/verisilicon/hantro.h
+++ b/drivers/media/platform/verisilicon/hantro.h
@@ -77,6 +77,7 @@ struct hantro_irq {
  * @double_buffer:		core needs double buffering
  * @legacy_regs:		core uses legacy register set
  * @late_postproc:		postproc must be set up at the end of the job
+ * @shared_devices:		an array of device ids that cannot run concurrently
  */
 struct hantro_variant {
 	unsigned int enc_offset;
@@ -101,6 +102,7 @@ struct hantro_variant {
 	unsigned int double_buffer : 1;
 	unsigned int legacy_regs : 1;
 	unsigned int late_postproc : 1;
+	const struct of_device_id *shared_devices;
 };
 
 /**
diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c
index 60b95b5d8565..94f58f4e4a4e 100644
--- a/drivers/media/platform/verisilicon/hantro_drv.c
+++ b/drivers/media/platform/verisilicon/hantro_drv.c
@@ -13,6 +13,7 @@
 #include <linux/clk.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
@@ -1035,6 +1036,41 @@ static int hantro_disable_multicore(struct hantro_dev *vpu)
 	return 0;
 }
 
+static struct v4l2_m2m_dev *hantro_get_v4l2_m2m_dev(struct hantro_dev *vpu)
+{
+	struct device_node *node;
+	struct hantro_dev *shared_vpu;
+
+	if (!vpu->variant || !vpu->variant->shared_devices)
+		goto init_new_m2m_dev;
+
+	for_each_matching_node(node, vpu->variant->shared_devices) {
+		struct platform_device *pdev;
+		struct v4l2_m2m_dev *m2m_dev;
+
+		pdev = of_find_device_by_node(node);
+		if (!pdev)
+			continue;
+
+		shared_vpu = platform_get_drvdata(pdev);
+		if (IS_ERR_OR_NULL(shared_vpu) || shared_vpu == vpu) {
+			platform_device_put(pdev);
+			continue;
+		}
+
+		v4l2_m2m_get(shared_vpu->m2m_dev);
+		m2m_dev = shared_vpu->m2m_dev;
+		platform_device_put(pdev);
+
+		of_node_put(node);
+
+		return m2m_dev;
+	}
+
+init_new_m2m_dev:
+	return v4l2_m2m_init(&vpu_m2m_ops);
+}
+
 static int hantro_probe(struct platform_device *pdev)
 {
 	const struct of_device_id *match;
@@ -1186,7 +1222,7 @@ static int hantro_probe(struct platform_device *pdev)
 	}
 	platform_set_drvdata(pdev, vpu);
 
-	vpu->m2m_dev = v4l2_m2m_init(&vpu_m2m_ops);
+	vpu->m2m_dev = hantro_get_v4l2_m2m_dev(vpu);
 	if (IS_ERR(vpu->m2m_dev)) {
 		v4l2_err(&vpu->v4l2_dev, "Failed to init mem2mem device\n");
 		ret = PTR_ERR(vpu->m2m_dev);
@@ -1225,7 +1261,7 @@ static int hantro_probe(struct platform_device *pdev)
 	hantro_remove_enc_func(vpu);
 err_m2m_rel:
 	media_device_cleanup(&vpu->mdev);
-	v4l2_m2m_release(vpu->m2m_dev);
+	v4l2_m2m_put(vpu->m2m_dev);
 err_v4l2_unreg:
 	v4l2_device_unregister(&vpu->v4l2_dev);
 err_clk_unprepare:
@@ -1248,7 +1284,7 @@ static void hantro_remove(struct platform_device *pdev)
 	hantro_remove_dec_func(vpu);
 	hantro_remove_enc_func(vpu);
 	media_device_cleanup(&vpu->mdev);
-	v4l2_m2m_release(vpu->m2m_dev);
+	v4l2_m2m_put(vpu->m2m_dev);
 	v4l2_device_unregister(&vpu->v4l2_dev);
 	clk_bulk_unprepare(vpu->variant->num_clocks, vpu->clocks);
 	reset_control_assert(vpu->resets);
diff --git a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
index 5be0e2e76882..6f8e43b7f157 100644
--- a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
+++ b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
@@ -343,6 +343,12 @@ const struct hantro_variant imx8mq_vpu_variant = {
 	.num_regs = ARRAY_SIZE(imx8mq_reg_names)
 };
 
+static const struct of_device_id imx8mq_vpu_shared_resources[] __initconst = {
+	{ .compatible = "nxp,imx8mq-vpu-g1", },
+	{ .compatible = "nxp,imx8mq-vpu-g2", },
+	{ /* sentinel */ }
+};
+
 const struct hantro_variant imx8mq_vpu_g1_variant = {
 	.dec_fmts = imx8m_vpu_dec_fmts,
 	.num_dec_fmts = ARRAY_SIZE(imx8m_vpu_dec_fmts),
@@ -356,6 +362,7 @@ const struct hantro_variant imx8mq_vpu_g1_variant = {
 	.num_irqs = ARRAY_SIZE(imx8mq_irqs),
 	.clk_names = imx8mq_g1_clk_names,
 	.num_clocks = ARRAY_SIZE(imx8mq_g1_clk_names),
+	.shared_devices = imx8mq_vpu_shared_resources,
 };
 
 const struct hantro_variant imx8mq_vpu_g2_variant = {
@@ -371,6 +378,7 @@ const struct hantro_variant imx8mq_vpu_g2_variant = {
 	.num_irqs = ARRAY_SIZE(imx8mq_g2_irqs),
 	.clk_names = imx8mq_g2_clk_names,
 	.num_clocks = ARRAY_SIZE(imx8mq_g2_clk_names),
+	.shared_devices = imx8mq_vpu_shared_resources,
 };
 
 const struct hantro_variant imx8mm_vpu_g1_variant = {
-- 
2.52.0



From chaoyi.chen at rock-chips.com  Thu Dec  4 18:26:20 2025
From: chaoyi.chen at rock-chips.com (Chaoyi Chen)
Date: Fri, 5 Dec 2025 10:26:20 +0800
Subject: [RESEND PATCH v11 03/11] drm/bridge: Implement generic USB Type-C
 DP HPD bridge
In-Reply-To: <aTGPaJmwd7uHfrnV@kuha>
References: <20251204063109.104-1-kernel@airkyi.com>
 <20251204063109.104-4-kernel@airkyi.com> <aTGPaJmwd7uHfrnV@kuha>
Message-ID: <84f06c0f-3ec7-4a43-bba2-1979c3a07127@rock-chips.com>

Hi Heikki,

On 12/4/2025 9:40 PM, Heikki Krogerus wrote:
> Hi,
> 
> I don't know what's going on here - this series is the 12th?
> In any case, you need to fix this..
> 

It is 11th. Patch 1 was missing the Signed-off-by line, so I've resent
it. Sorry for the confusion.

>> diff --git a/drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c b/drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c
>> new file mode 100644
>> index 000000000000..94be3d5f69e9
>> --- /dev/null
>> +++ b/drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c
>> @@ -0,0 +1,51 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +#include <linux/of.h>
>> +#include <linux/usb/typec_altmode.h>
>> +#include <linux/usb/typec_dp.h>
>> +
>> +#include <drm/bridge/aux-bridge.h>
>> +
>> +static int drm_typec_bus_event(struct notifier_block *nb,
>> +			       unsigned long action, void *data)
>> +{
>> +	struct device *dev = (struct device *)data;
>> +	struct typec_altmode *alt = to_typec_altmode(dev);
>> +
>> +	if (action != BUS_NOTIFY_ADD_DEVICE)
>> +		goto done;
>> +
>> +	if (is_typec_partner_altmode(&alt->dev) || alt->svid != USB_TYPEC_DP_SID)
>> +		goto done;
> 
> That's still not enough because of the plug altmodes. You need to
> check that it's a port altmode:
> 
>         if (is_typec_port_altmode(&alt->dev) && alt->svid == USB_TYPEC_DP_SID)
>         	drm_dp_hpd_bridge_register(alt->dev.parent->parent,
>         				   to_of_node(alt->dev.parent->fwnode));
>

Oh, it is. Will fix in v12. Thank you.

>> +	/*
>> +	 * alt->dev.parent->parent : USB-C controller device
>> +	 * alt->dev.parent         : USB-C connector device
>> +	 */
>> +	drm_dp_hpd_bridge_register(alt->dev.parent->parent,
>> +				   to_of_node(alt->dev.parent->fwnode));
>> +
>> +done:
>> +	return NOTIFY_OK;
>> +}
>> +
>> +static struct notifier_block drm_typec_event_nb = {
>> +	.notifier_call = drm_typec_bus_event,
>> +};
>> +
>> +static void drm_aux_hpd_typec_dp_bridge_module_exit(void)
>> +{
>> +	bus_unregister_notifier(&typec_bus, &drm_typec_event_nb);
>> +}
>> +
>> +static int __init drm_aux_hpd_typec_dp_bridge_module_init(void)
>> +{
>> +	bus_register_notifier(&typec_bus, &drm_typec_event_nb);
>> +
>> +	return 0;
>> +}
>> +
>> +module_init(drm_aux_hpd_typec_dp_bridge_module_init);
>> +module_exit(drm_aux_hpd_typec_dp_bridge_module_exit);
>> +
>> +MODULE_DESCRIPTION("DRM TYPEC DP HPD BRIDGE");
>> +MODULE_LICENSE("GPL");
> 
> thanks,
> 

-- 
Best, 
Chaoyi


From royluo at google.com  Thu Dec  4 18:26:36 2025
From: royluo at google.com (Roy Luo)
Date: Fri, 05 Dec 2025 02:26:36 +0000
Subject: [PATCH v9 0/2] Add Google Tensor SoC USB controller support
Message-ID: <20251205-controller-v9-0-9f158b18f979@google.com>

This series introduces USB controller support for the Google Tensor G5
SoC (codename: Laguna), a new generation of Google silicon first
launched with Pixel 10 devices.

The Tensor G5 represents a significant architectural overhaul compared
to previous Tensor generations (e.g., gs101), which were based on Samsung
Exynos IP. Although the G5 still utilizes Synopsys IP for the USB
components, the custom top-level integration introduces a completely new
design for clock, reset scheme, register interfaces and programming
sequence, necessitating new drivers and device tree bindings.

The USB subsystem on Tensor G5 integrates a Synopsys DWC3 USB 3.1
DRD-Single Port controller with hibernation support, and a custom PHY
block comprising Synopsys eUSB2 and USB 3.2/DP combo PHYs. The PHY
support is sent as a separate patch series.

Co-developed-by: Joy Chakraborty <joychakr at google.com>
Signed-off-by: Joy Chakraborty <joychakr at google.com>
Co-developed-by: Naveen Kumar <mnkumar at google.com>
Signed-off-by: Naveen Kumar <mnkumar at google.com>
Signed-off-by: Roy Luo <royluo at google.com>
---
Changes in v9:
- Update the Kconfig dependency to depends on ARCH_GOOGLE || COMPILE_TEST
  Note that ARCH_GOOGLE does not exist yet but will eventually
  be there when the following patch lands
  https://lore.kernel.org/r/20251111112158.3.I35b9e835ac49ab408e5ca3e0983930a1f1395814 at changeid/
- Mention SoC codename Laguna in Kconfig description.
- Sort the header alphabetically.
- Add driver and binding files to the Tensor SoC MAINTAINER entry.
Link to v8: https://lore.kernel.org/r/20251122-controller-v8-0-e7562e0df658 at google.com

Changes in v8:
- Add COMPILE_TEST to dependencies for build coverage.
- Drop redundant default n in Kconfig.
- Update Kconfig help text to explicitly state the module name.
- Use container_of_const() in the to_dwc3_google() macro for type safety.
Link to v7: https://lore.kernel.org/linux-usb/20251119093749.292926-1-royluo at google.com

Changes in v7:
- Follow driver naming convention and rename the driver as "dwc3-google".
Link to v6: https://lore.kernel.org/linux-usb/20251112123257.3755489-1-royluo at google.com

Changes in v6:
- Use "lga" as SoC name instead of "gs5" to align with Tensor G5 device
  tree https://lore.kernel.org/lkml/20251111192422.4180216-1-dianders at chromium.org
Link to v5: https://lore.kernel.org/linux-usb/20251111130624.3069704-1-royluo at google.com

Changes in v5:
- Use syscon to access host_cfg and usbint_cfg MMIO space per
  discussion in https://lore.kernel.org/linux-phy/89733ddf-8af3-42d0-b6e5-20b7a4ef588c at kernel.org
- Make warn logs in dwc3_google_resume_irq() dev_dbg.
Link to v4: https://lore.kernel.org/linux-usb/20251017233459.2409975-1-royluo at google.com

Changes in v4:
- Separate controller and phy changes into two distinct patch series.
- Rename dwc3 core interrupt as "core".
- Remove u2phy_apb clk/reset (moved to PHY)
- Configure usb2only mode when usb3 phy is not present.
- Adopt pm_ptr PM macros to fix build warnings.
Link to v3: https://lore.kernel.org/linux-usb/20251010201607.1190967-1-royluo at google.com

Changes in v3:
- Align binding file name with the compatible string
- Simplify the compatible property in binding to a single const value.
- Add descriptive comments and use item list in binding.
- Rename binding entries for clarity and brevity.
Link to v2: https://lore.kernel.org/linux-usb/20251008060000.3136021-1-royluo at google.com

Changes in v2:
- Reorder patches to present bindings first.
- Update dt binding compatible strings to be SoC-specific (google,gs5-*).
- Better describe the hardware in dt binding commit messages and
  descriptions.
- Adjust PHY driver commit subjects to use correct prefixes ("phy:").
- Move PHY driver from a subdirectory to drivers/phy/.
Link to v1: https://lore.kernel.org/linux-usb/20251006232125.1833979-1-royluo at google.com/

---
Roy Luo (2):
      dt-bindings: usb: dwc3: Add Google Tensor G5 DWC3
      usb: dwc3: Add Google Tensor SoC DWC3 glue driver

 .../devicetree/bindings/usb/google,lga-dwc3.yaml   | 140 +++++
 MAINTAINERS                                        |   2 +
 drivers/usb/dwc3/Kconfig                           |  12 +
 drivers/usb/dwc3/Makefile                          |   1 +
 drivers/usb/dwc3/dwc3-google.c                     | 628 +++++++++++++++++++++
 5 files changed, 783 insertions(+)
---
base-commit: 43dfc13ca972988e620a6edb72956981b75ab6b0
change-id: 20251122-controller-129b0dd57a74

Best regards,
-- 
Roy Luo <royluo at google.com>



From royluo at google.com  Thu Dec  4 18:26:37 2025
From: royluo at google.com (Roy Luo)
Date: Fri, 05 Dec 2025 02:26:37 +0000
Subject: [PATCH v9 1/2] dt-bindings: usb: dwc3: Add Google Tensor G5 DWC3
In-Reply-To: <20251205-controller-v9-0-9f158b18f979@google.com>
References: <20251205-controller-v9-0-9f158b18f979@google.com>
Message-ID: <20251205-controller-v9-1-9f158b18f979@google.com>

Document the device tree bindings for the DWC3 USB controller found in
Google Tensor SoCs, starting with the G5 generation (codename: laguna).

The Tensor G5 silicon represents a complete architectural departure from
previous generations (like gs101), including entirely new clock/reset
schemes, top-level wrapper and register interface. Consequently,
existing Samsung/Exynos DWC3 USB bindings are incompatible, necessitating
this new device tree binding.

The USB controller on Tensor G5 is based on Synopsys DWC3 IP and features
Dual-Role Device single port with hibernation support.

Signed-off-by: Roy Luo <royluo at google.com>
---
 .../devicetree/bindings/usb/google,lga-dwc3.yaml   | 140 +++++++++++++++++++++
 MAINTAINERS                                        |   1 +
 2 files changed, 141 insertions(+)

diff --git a/Documentation/devicetree/bindings/usb/google,lga-dwc3.yaml b/Documentation/devicetree/bindings/usb/google,lga-dwc3.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..95be84c843f5da0e80ef5ef1ac9193019b5eb2a0
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/google,lga-dwc3.yaml
@@ -0,0 +1,140 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright (c) 2025, Google LLC
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/google,lga-dwc3.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Google Tensor Series G5 (Laguna) DWC3 USB SoC Controller
+
+maintainers:
+  - Roy Luo <royluo at google.com>
+
+description:
+  Describes the DWC3 USB controller block implemented on Google Tensor SoCs,
+  starting with the G5 generation (laguna). Based on Synopsys DWC3 IP, the
+  controller features Dual-Role Device single port with hibernation add-on.
+
+properties:
+  compatible:
+    const: google,lga-dwc3
+
+  reg:
+    items:
+      - description: Core DWC3 IP registers.
+
+  interrupts:
+    items:
+      - description: Core DWC3 interrupt.
+      - description: High speed power management event for remote wakeup.
+      - description: Super speed power management event for remote wakeup.
+
+  interrupt-names:
+    items:
+      - const: core
+      - const: hs_pme
+      - const: ss_pme
+
+  clocks:
+    items:
+      - description: Non-sticky module clock.
+      - description: Sticky module clock.
+
+  clock-names:
+    items:
+      - const: non_sticky
+      - const: sticky
+
+  resets:
+    items:
+      - description: Non-sticky module reset.
+      - description: Sticky module reset.
+      - description: DRD bus reset.
+      - description: Top-level reset.
+
+  reset-names:
+    items:
+      - const: non_sticky
+      - const: sticky
+      - const: drd_bus
+      - const: top
+
+  power-domains:
+    items:
+      - description: Power switchable domain, the child of top domain.
+          Turning it on puts the controller into full power state,
+          turning it off puts the controller into power gated state.
+      - description: Top domain, the parent of power switchable domain.
+          Turning it on puts the controller into power gated state,
+          turning it off completely shuts off the controller.
+
+  power-domain-names:
+    items:
+      - const: psw
+      - const: top
+
+  iommus:
+    maxItems: 1
+
+  google,usb-cfg-csr:
+    description:
+      A phandle to a syscon node used to access the USB configuration
+      registers. These registers are the top-level wrapper of the USB
+      subsystem and provide control and status for the integrated USB
+      controller and USB PHY.
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    items:
+      - items:
+          - description: phandle to the syscon node.
+          - description: USB host controller configuration register offset.
+          - description: USB custom interrrupts control register offset.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-names
+  - clocks
+  - clock-names
+  - resets
+  - reset-names
+  - power-domains
+  - power-domain-names
+  - google,usb-cfg-csr
+
+allOf:
+  - $ref: snps,dwc3-common.yaml#
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        usb at c400000 {
+            compatible = "google,lga-dwc3";
+            reg = <0 0x0c400000  0 0xd060>;
+            interrupts = <GIC_SPI 580 IRQ_TYPE_LEVEL_HIGH 0>,
+                         <GIC_SPI 597 IRQ_TYPE_LEVEL_HIGH 0>,
+                         <GIC_SPI 598 IRQ_TYPE_LEVEL_HIGH 0>;
+            interrupt-names = "core", "hs_pme", "ss_pme";
+            clocks = <&hsion_usbc_non_sticky_clk>,  <&hsion_usbc_sticky_clk>;
+            clock-names = "non_sticky", "sticky";
+            resets = <&hsion_resets_usbc_non_sticky>, <&hsion_resets_usbc_sticky>,
+                     <&hsion_resets_usb_drd_bus>, <&hsion_resets_usb_top>;
+            reset-names = "non_sticky", "sticky", "drd_bus", "top";
+            power-domains = <&hsio_n_usb_psw>, <&hsio_n_usb>;
+            power-domain-names = "psw", "top";
+            phys = <&usb_phy 0>;
+            phy-names = "usb2-phy";
+            snps,quirk-frame-length-adjustment = <0x20>;
+            snps,gfladj-refclk-lpm-sel-quirk;
+            snps,incr-burst-type-adjustment = <4>;
+            google,usb-cfg-csr = <&usb_cfg_csr 0x0 0x20>;
+        };
+    };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 772af0072fff0921000c6fe27c018666c1579e48..61f5768b31ae31cd72f4c2a3b74398f9473e192b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10662,6 +10662,7 @@ P:	Documentation/process/maintainer-soc-clean-dts.rst
 C:	irc://irc.oftc.net/pixel6-kernel-dev
 F:	Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
 F:	Documentation/devicetree/bindings/soc/google/google,gs101-pmu-intr-gen.yaml
+F:	Documentation/devicetree/bindings/usb/google,lga-dwc3.yaml
 F:	arch/arm64/boot/dts/exynos/google/
 F:	drivers/clk/samsung/clk-gs101.c
 F:	drivers/phy/samsung/phy-gs101-ufs.c

-- 
2.52.0.223.gf5cc29aaa4-goog



From royluo at google.com  Thu Dec  4 18:26:38 2025
From: royluo at google.com (Roy Luo)
Date: Fri, 05 Dec 2025 02:26:38 +0000
Subject: [PATCH v9 2/2] usb: dwc3: Add Google Tensor SoC DWC3 glue driver
In-Reply-To: <20251205-controller-v9-0-9f158b18f979@google.com>
References: <20251205-controller-v9-0-9f158b18f979@google.com>
Message-ID: <20251205-controller-v9-2-9f158b18f979@google.com>

Add support for the DWC3 USB controller found on Google Tensor G5
(codename: laguna). The controller features dual-role functionality
and hibernation.

The primary focus is implementing hibernation support in host mode,
enabling the controller to enter a low-power state (D3). This is
particularly relevant during system power state transition and
runtime power management for power efficiency.
Highlights:
- Align suspend callback with dwc3_suspend_common() for deciding
  between a full teardown and hibernation in host mode.
- Integration with `psw` (power switchable) and `top` power domains,
  managing their states and device links to support hibernation.
- A notifier callback dwc3_google_usb_psw_pd_notifier() for
  `psw` power domain events to manage controller state
  transitions to/from D3.
- Coordination of the `non_sticky` reset during power state
  transitions, asserting it on D3 entry and deasserting on D0 entry
  in hibernation scenario.
- Handling of high-speed and super-speed PME interrupts
  that are generated by remote wakeup during hibernation.

Co-developed-by: Joy Chakraborty <joychakr at google.com>
Signed-off-by: Joy Chakraborty <joychakr at google.com>
Co-developed-by: Naveen Kumar <mnkumar at google.com>
Signed-off-by: Naveen Kumar <mnkumar at google.com>
Reviewed-by: Peter Griffin <peter.griffin at linaro.org>
Signed-off-by: Roy Luo <royluo at google.com>
---
 MAINTAINERS                    |   1 +
 drivers/usb/dwc3/Kconfig       |  12 +
 drivers/usb/dwc3/Makefile      |   1 +
 drivers/usb/dwc3/dwc3-google.c | 628 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 642 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 61f5768b31ae31cd72f4c2a3b74398f9473e192b..0659847b980128801b63014de96294c07abca3a0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10666,6 +10666,7 @@ F:	Documentation/devicetree/bindings/usb/google,lga-dwc3.yaml
 F:	arch/arm64/boot/dts/exynos/google/
 F:	drivers/clk/samsung/clk-gs101.c
 F:	drivers/phy/samsung/phy-gs101-ufs.c
+F:	drivers/usb/dwc3/dwc3-google.c
 F:	include/dt-bindings/clock/google,gs101.h
 K:	[gG]oogle.?[tT]ensor
 
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index 4925d15084f816d3ff92059b476ebcc799b56b51..05e4b7e1d98b1c03c8887c50dfff7e39d365f2a3 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -200,4 +200,16 @@ config USB_DWC3_GENERIC_PLAT
 	  the dwc3 child node in the device tree.
 	  Say 'Y' or 'M' here if your platform integrates DWC3 in a similar way.
 
+config USB_DWC3_GOOGLE
+	tristate "Google Platform"
+	depends on ARCH_GOOGLE || COMPILE_TEST
+	help
+	  Support the DesignWare Core USB3 IP found on Google Tensor SoCs,
+	  starting with the G5 generation (Laguna). This driver includes
+	  support for hibernation in host mode.
+	  Say 'Y' or 'M' if you have one such device.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called dwc3-google.ko.
+
 endif
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index 96469e48ff9d189cc8d0b65e65424eae2158bcfe..cf1cd408d938b3ac26d58b9be7fcc5af3ee82660 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -58,3 +58,4 @@ obj-$(CONFIG_USB_DWC3_XILINX)		+= dwc3-xilinx.o
 obj-$(CONFIG_USB_DWC3_OCTEON)		+= dwc3-octeon.o
 obj-$(CONFIG_USB_DWC3_RTK)		+= dwc3-rtk.o
 obj-$(CONFIG_USB_DWC3_GENERIC_PLAT)	+= dwc3-generic-plat.o
+obj-$(CONFIG_USB_DWC3_GOOGLE)		+= dwc3-google.o
diff --git a/drivers/usb/dwc3/dwc3-google.c b/drivers/usb/dwc3/dwc3-google.c
new file mode 100644
index 0000000000000000000000000000000000000000..a19857bd6b131d841d165717b70f2959b4bac806
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3-google.c
@@ -0,0 +1,628 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * dwc3-google.c - Google DWC3 Specific Glue Layer
+ *
+ * Copyright (c) 2025, Google LLC
+ * Author: Roy Luo <royluo at google.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include "core.h"
+#include "glue.h"
+
+/* HOST CFG registers */
+#define HC_STATUS_OFFSET 0x0
+#define HC_STATUS_CURRENT_POWER_STATE_U2PMU GENMASK(1, 0)
+#define HC_STATUS_CURRENT_POWER_STATE_U3PMU GENMASK(4, 3)
+
+#define HOST_CFG1_OFFSET 0x4
+#define HOST_CFG1_PME_EN BIT(3)
+#define HOST_CFG1_PM_POWER_STATE_REQUEST GENMASK(5, 4)
+#define HOST_CFG1_PM_POWER_STATE_D0 0x0
+#define HOST_CFG1_PM_POWER_STATE_D3 0x3
+
+/* USBINT registers */
+#define USBINT_CFG1_OFFSET 0x0
+#define USBINT_CFG1_USBDRD_PME_GEN_U2P_INTR_MSK BIT(2)
+#define USBINT_CFG1_USBDRD_PME_GEN_U3P_INTR_MSK BIT(3)
+#define USBINT_CFG1_USBDRD_PME_GEN_U2P_INTR_INT_EN BIT(8)
+#define USBINT_CFG1_USBDRD_PME_GEN_U3P_INTR_INT_EN BIT(9)
+#define USBINT_CFG1_USBDRD_PME_GEN_U2_INTR_CLR BIT(14)
+#define USBINT_CFG1_USBDRD_PME_GEN_U3_INTR_CLR BIT(15)
+
+#define USBINT_STATUS_OFFSET 0x4
+#define USBINT_STATUS_USBDRD_PME_GEN_U2P_INTR_STS_RAW BIT(2)
+#define USBINT_STATUS_USBDRD_PME_GEN_U3P_INTR_STS_RAW BIT(3)
+
+#define USBCS_TOP_CTRL_CFG1_OFFSET 0xc
+#define USBCS_TOP_CTRL_CFG1_USB2ONLY_MODE BIT(5)
+
+#define DWC3_GOOGLE_MAX_RESETS	4
+
+struct dwc3_google {
+	struct device		*dev;
+	struct dwc3		dwc;
+	struct clk_bulk_data	*clks;
+	int			num_clks;
+	struct reset_control_bulk_data rsts[DWC3_GOOGLE_MAX_RESETS];
+	int			num_rsts;
+	struct reset_control	*non_sticky_rst;
+	struct device		*usb_psw_pd;
+	struct device_link	*usb_psw_pd_dl;
+	struct notifier_block	usb_psw_pd_nb;
+	struct device		*usb_top_pd;
+	struct device_link	*usb_top_pd_dl;
+	struct regmap		*usb_cfg_regmap;
+	unsigned int		host_cfg_offset;
+	unsigned int		usbint_cfg_offset;
+	int			hs_pme_irq;
+	int			ss_pme_irq;
+	bool			is_usb2only;
+	bool			is_hibernation;
+};
+
+#define to_dwc3_google(d) container_of_const((d), struct dwc3_google, dwc)
+
+static int dwc3_google_rst_init(struct dwc3_google *google)
+{
+	int ret;
+
+	google->num_rsts = 4;
+	google->rsts[0].id = "non_sticky";
+	google->rsts[1].id = "sticky";
+	google->rsts[2].id = "drd_bus";
+	google->rsts[3].id = "top";
+
+	ret = devm_reset_control_bulk_get_exclusive(google->dev,
+						    google->num_rsts,
+						    google->rsts);
+
+	if (ret < 0)
+		return ret;
+
+	google->non_sticky_rst = google->rsts[0].rstc;
+
+	return 0;
+}
+
+static int dwc3_google_set_pmu_state(struct dwc3_google *google, int state)
+{
+	u32 reg;
+	int ret;
+
+	regmap_read(google->usb_cfg_regmap,
+		    google->host_cfg_offset + HOST_CFG1_OFFSET, &reg);
+
+	reg &= ~HOST_CFG1_PM_POWER_STATE_REQUEST;
+	reg |= (FIELD_PREP(HOST_CFG1_PM_POWER_STATE_REQUEST, state) |
+		HOST_CFG1_PME_EN);
+	regmap_write(google->usb_cfg_regmap,
+		     google->host_cfg_offset + HOST_CFG1_OFFSET, reg);
+
+	ret = regmap_read_poll_timeout(google->usb_cfg_regmap,
+				       google->host_cfg_offset + HC_STATUS_OFFSET, reg,
+				       (FIELD_GET(HC_STATUS_CURRENT_POWER_STATE_U2PMU,
+						  reg) == state &&
+					FIELD_GET(HC_STATUS_CURRENT_POWER_STATE_U3PMU,
+						  reg) == state),
+				       10, 10000);
+
+	if (ret)
+		dev_err(google->dev, "failed to set PMU state %d\n", state);
+
+	return ret;
+}
+
+/*
+ * Clear pme interrupts and report their status.
+ * The hardware requires write-1 then write-0 sequence to clear the interrupt bits.
+ */
+static u32 dwc3_google_clear_pme_irqs(struct dwc3_google *google)
+{
+	u32 irq_status, reg_set, reg_clear;
+
+	regmap_read(google->usb_cfg_regmap,
+		    google->usbint_cfg_offset + USBINT_STATUS_OFFSET, &irq_status);
+
+	irq_status &= (USBINT_STATUS_USBDRD_PME_GEN_U2P_INTR_STS_RAW |
+		       USBINT_STATUS_USBDRD_PME_GEN_U3P_INTR_STS_RAW);
+	if (!irq_status)
+		return irq_status;
+
+	regmap_read(google->usb_cfg_regmap,
+		    google->usbint_cfg_offset + USBINT_CFG1_OFFSET, &reg_set);
+
+	reg_clear = reg_set;
+	if (irq_status & USBINT_STATUS_USBDRD_PME_GEN_U2P_INTR_STS_RAW) {
+		reg_set |= USBINT_CFG1_USBDRD_PME_GEN_U2_INTR_CLR;
+		reg_clear &= ~USBINT_CFG1_USBDRD_PME_GEN_U2_INTR_CLR;
+	}
+	if (irq_status & USBINT_STATUS_USBDRD_PME_GEN_U3P_INTR_STS_RAW) {
+		reg_set |= USBINT_CFG1_USBDRD_PME_GEN_U3_INTR_CLR;
+		reg_clear &= ~USBINT_CFG1_USBDRD_PME_GEN_U3_INTR_CLR;
+	}
+
+	regmap_write(google->usb_cfg_regmap,
+		     google->usbint_cfg_offset + USBINT_CFG1_OFFSET, reg_set);
+	regmap_write(google->usb_cfg_regmap,
+		     google->usbint_cfg_offset + USBINT_CFG1_OFFSET, reg_clear);
+
+	return irq_status;
+}
+
+static void dwc3_google_enable_pme_irq(struct dwc3_google *google)
+{
+	u32 reg;
+
+	regmap_read(google->usb_cfg_regmap,
+		    google->usbint_cfg_offset + USBINT_CFG1_OFFSET, &reg);
+	reg &= ~(USBINT_CFG1_USBDRD_PME_GEN_U2P_INTR_MSK |
+		 USBINT_CFG1_USBDRD_PME_GEN_U3P_INTR_MSK);
+	reg |= (USBINT_CFG1_USBDRD_PME_GEN_U2P_INTR_INT_EN |
+		USBINT_CFG1_USBDRD_PME_GEN_U3P_INTR_INT_EN);
+	regmap_write(google->usb_cfg_regmap,
+		     google->usbint_cfg_offset + USBINT_CFG1_OFFSET, reg);
+
+	enable_irq(google->hs_pme_irq);
+	enable_irq(google->ss_pme_irq);
+	enable_irq_wake(google->hs_pme_irq);
+	enable_irq_wake(google->ss_pme_irq);
+}
+
+static void dwc3_google_disable_pme_irq(struct dwc3_google *google)
+{
+	u32 reg;
+
+	regmap_read(google->usb_cfg_regmap,
+		    google->usbint_cfg_offset + USBINT_CFG1_OFFSET, &reg);
+	reg &= ~(USBINT_CFG1_USBDRD_PME_GEN_U2P_INTR_INT_EN |
+		 USBINT_CFG1_USBDRD_PME_GEN_U3P_INTR_INT_EN);
+	reg |= (USBINT_CFG1_USBDRD_PME_GEN_U2P_INTR_MSK |
+		USBINT_CFG1_USBDRD_PME_GEN_U3P_INTR_MSK);
+	regmap_write(google->usb_cfg_regmap,
+		     google->usbint_cfg_offset + USBINT_CFG1_OFFSET, reg);
+
+	disable_irq_wake(google->hs_pme_irq);
+	disable_irq_wake(google->ss_pme_irq);
+	disable_irq_nosync(google->hs_pme_irq);
+	disable_irq_nosync(google->ss_pme_irq);
+}
+
+static irqreturn_t dwc3_google_resume_irq(int irq, void *data)
+{
+	struct dwc3_google      *google = data;
+	struct dwc3             *dwc = &google->dwc;
+	u32 irq_status, dr_role;
+
+	irq_status = dwc3_google_clear_pme_irqs(google);
+	dr_role = dwc->current_dr_role;
+
+	if (!irq_status || !google->is_hibernation ||
+	    dr_role != DWC3_GCTL_PRTCAP_HOST) {
+		dev_dbg(google->dev, "spurious pme irq %d, hibernation %d, dr_role %u\n",
+			irq, google->is_hibernation, dr_role);
+		return IRQ_HANDLED;
+	}
+
+	if (dwc->xhci)
+		pm_runtime_resume(&dwc->xhci->dev);
+
+	return IRQ_HANDLED;
+}
+
+static int dwc3_google_request_irq(struct dwc3_google *google, struct platform_device *pdev,
+				   const char *irq_name, const char *req_name)
+{
+	int ret;
+	int irq;
+
+	irq = platform_get_irq_byname(pdev, irq_name);
+	if (irq < 0) {
+		dev_err(google->dev, "invalid irq name %s\n", irq_name);
+		return irq;
+	}
+
+	irq_set_status_flags(irq, IRQ_NOAUTOEN);
+	ret = devm_request_threaded_irq(google->dev, irq, NULL,
+					dwc3_google_resume_irq,
+					IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+					req_name, google);
+	if (ret < 0) {
+		dev_err(google->dev, "failed to request irq %s\n", req_name);
+		return ret;
+	}
+
+	return irq;
+}
+
+static int dwc3_google_usb_psw_pd_notifier(struct notifier_block *nb, unsigned long action, void *d)
+{
+	struct dwc3_google *google = container_of(nb, struct dwc3_google, usb_psw_pd_nb);
+	int ret;
+
+	if (!google->is_hibernation)
+		return NOTIFY_OK;
+
+	if (action == GENPD_NOTIFY_OFF) {
+		dev_dbg(google->dev, "enter D3 power state\n");
+		dwc3_google_set_pmu_state(google, HOST_CFG1_PM_POWER_STATE_D3);
+		ret = reset_control_assert(google->non_sticky_rst);
+		if (ret)
+			dev_err(google->dev, "non sticky reset assert failed: %d\n", ret);
+	} else if (action == GENPD_NOTIFY_ON) {
+		dev_dbg(google->dev, "enter D0 power state\n");
+		dwc3_google_clear_pme_irqs(google);
+		ret = reset_control_deassert(google->non_sticky_rst);
+		if (ret)
+			dev_err(google->dev, "non sticky reset deassert failed: %d\n", ret);
+		dwc3_google_set_pmu_state(google, HOST_CFG1_PM_POWER_STATE_D0);
+	}
+
+	return NOTIFY_OK;
+}
+
+static void dwc3_google_pm_domain_deinit(struct dwc3_google *google)
+{
+	if (google->usb_top_pd_dl)
+		device_link_del(google->usb_top_pd_dl);
+
+	if (!IS_ERR_OR_NULL(google->usb_top_pd)) {
+		device_set_wakeup_capable(google->usb_top_pd, false);
+		dev_pm_domain_detach(google->usb_top_pd, true);
+	}
+
+	if (google->usb_psw_pd_dl)
+		device_link_del(google->usb_psw_pd_dl);
+
+	if (!IS_ERR_OR_NULL(google->usb_psw_pd)) {
+		dev_pm_genpd_remove_notifier(google->usb_psw_pd);
+		dev_pm_domain_detach(google->usb_psw_pd, true);
+	}
+}
+
+static int dwc3_google_pm_domain_init(struct dwc3_google *google)
+{
+	int ret;
+
+	/*
+	 * Establish PM RUNTIME link between dwc dev and its power domain usb_psw_pd,
+	 * register notifier block to handle hibernation.
+	 */
+	google->usb_psw_pd = dev_pm_domain_attach_by_name(google->dev, "psw");
+	if (IS_ERR_OR_NULL(google->usb_psw_pd)) {
+		dev_err(google->dev, "failed to get psw pd");
+		ret = google->usb_psw_pd ? PTR_ERR(google->usb_psw_pd) : -ENODATA;
+		return ret;
+	}
+
+	google->usb_psw_pd_nb.notifier_call = dwc3_google_usb_psw_pd_notifier;
+	ret = dev_pm_genpd_add_notifier(google->usb_psw_pd, &google->usb_psw_pd_nb);
+	if (ret) {
+		dev_err(google->dev, "failed to add psw pd notifier");
+		goto err;
+	}
+
+	google->usb_psw_pd_dl = device_link_add(google->dev, google->usb_psw_pd,
+						DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME |
+						DL_FLAG_RPM_ACTIVE);
+	if (!google->usb_psw_pd_dl) {
+		dev_err(google->usb_psw_pd, "failed to add device link");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	/*
+	 * usb_top_pd is the parent power domain of usb_psw_pd. Keeping usb_top_pd on
+	 * while usb_psw_pd is off places the controller in a power-gated state,
+	 * essential for hibernation. Acquire a handle to usb_top_pd and sets it as
+	 * wakeup-capable to allow the domain to be left on during system suspend.
+	 */
+	google->usb_top_pd = dev_pm_domain_attach_by_name(google->dev, "top");
+	if (IS_ERR_OR_NULL(google->usb_top_pd)) {
+		dev_err(google->dev, "failed to get top pd");
+		ret = google->usb_top_pd ? PTR_ERR(google->usb_top_pd) : -ENODATA;
+		goto err;
+	}
+	device_set_wakeup_capable(google->usb_top_pd, true);
+
+	google->usb_top_pd_dl = device_link_add(google->dev, google->usb_top_pd,
+						DL_FLAG_STATELESS);
+	if (!google->usb_top_pd_dl) {
+		dev_err(google->usb_top_pd, "failed to add device link");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	return 0;
+
+err:
+	dwc3_google_pm_domain_deinit(google);
+
+	return ret;
+}
+
+static void dwc3_google_program_usb2only(struct dwc3_google *google)
+{
+	u32 reg;
+
+	regmap_read(google->usb_cfg_regmap,
+		    google->usbint_cfg_offset + USBCS_TOP_CTRL_CFG1_OFFSET, &reg);
+	reg |= USBCS_TOP_CTRL_CFG1_USB2ONLY_MODE;
+	regmap_write(google->usb_cfg_regmap,
+		     google->usbint_cfg_offset + USBCS_TOP_CTRL_CFG1_OFFSET, reg);
+}
+
+static int dwc3_google_probe(struct platform_device *pdev)
+{
+	struct dwc3_probe_data	probe_data = {};
+	struct device		*dev = &pdev->dev;
+	struct dwc3_google	*google;
+	struct resource		*res;
+	int			ret;
+	u32			args[2];
+
+	google = devm_kzalloc(&pdev->dev, sizeof(*google), GFP_KERNEL);
+	if (!google)
+		return -ENOMEM;
+
+	google->dev = &pdev->dev;
+
+	ret = dwc3_google_pm_domain_init(google);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "failed to init pdom\n");
+
+	google->usb_cfg_regmap =
+		syscon_regmap_lookup_by_phandle_args(dev->of_node,
+						     "google,usb-cfg-csr",
+						     ARRAY_SIZE(args), args);
+	if (IS_ERR(google->usb_cfg_regmap)) {
+		return dev_err_probe(dev, PTR_ERR(google->usb_cfg_regmap),
+				     "invalid usb cfg csr\n");
+	}
+
+	google->host_cfg_offset = args[0];
+	google->usbint_cfg_offset = args[1];
+
+	if (device_property_match_string(dev, "phy-names", "usb3-phy") < 0) {
+		google->is_usb2only = true;
+		dwc3_google_program_usb2only(google);
+	}
+
+	ret = devm_clk_bulk_get_all_enabled(dev, &google->clks);
+	if (ret < 0) {
+		ret = dev_err_probe(dev, ret, "failed to get and enable clks\n");
+		goto err_deinit_pdom;
+	}
+	google->num_clks = ret;
+
+	ret = dwc3_google_rst_init(google);
+	if (ret) {
+		ret = dev_err_probe(dev, ret, "failed to get resets\n");
+		goto err_deinit_pdom;
+	}
+
+	ret = reset_control_bulk_deassert(google->num_rsts, google->rsts);
+	if (ret) {
+		ret = dev_err_probe(dev, ret, "failed to deassert rsts\n");
+		goto err_deinit_pdom;
+	}
+
+	ret = dwc3_google_request_irq(google, pdev, "hs_pme", "USB HS wakeup");
+	if (ret < 0) {
+		ret = dev_err_probe(dev, ret, "failed to request hs pme irq");
+		goto err_reset_assert;
+	}
+	google->hs_pme_irq = ret;
+
+	ret = dwc3_google_request_irq(google, pdev, "ss_pme", "USB SS wakeup");
+	if (ret < 0) {
+		ret = dev_err_probe(dev, ret, "failed to request ss pme irq");
+		goto err_reset_assert;
+	}
+	google->ss_pme_irq = ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = dev_err_probe(dev, -ENODEV, "invalid memory\n");
+		goto err_reset_assert;
+	}
+
+	device_init_wakeup(dev, true);
+
+	google->dwc.dev = dev;
+	probe_data.dwc = &google->dwc;
+	probe_data.res = res;
+	probe_data.ignore_clocks_and_resets = true;
+	ret = dwc3_core_probe(&probe_data);
+	if (ret)  {
+		ret = dev_err_probe(dev, ret, "failed to register DWC3 Core\n");
+		goto err_reset_assert;
+	}
+
+	return 0;
+
+err_reset_assert:
+	reset_control_bulk_assert(google->num_rsts, google->rsts);
+
+err_deinit_pdom:
+	dwc3_google_pm_domain_deinit(google);
+
+	return ret;
+}
+
+static void dwc3_google_remove(struct platform_device *pdev)
+{
+	struct dwc3 *dwc = platform_get_drvdata(pdev);
+	struct dwc3_google *google = to_dwc3_google(dwc);
+
+	dwc3_core_remove(&google->dwc);
+
+	reset_control_bulk_assert(google->num_rsts, google->rsts);
+
+	dwc3_google_pm_domain_deinit(google);
+}
+
+static int dwc3_google_suspend(struct dwc3_google *google, pm_message_t msg)
+{
+	if (pm_runtime_suspended(google->dev))
+		return 0;
+
+	if (google->dwc.current_dr_role == DWC3_GCTL_PRTCAP_HOST) {
+		/*
+		 * Follow dwc3_suspend_common() guidelines for deciding between
+		 * a full teardown and hibernation.
+		 */
+		if (PMSG_IS_AUTO(msg) || device_may_wakeup(google->dev)) {
+			dev_dbg(google->dev, "enter hibernation");
+			pm_runtime_get_sync(google->usb_top_pd);
+			device_wakeup_enable(google->usb_top_pd);
+			dwc3_google_enable_pme_irq(google);
+			google->is_hibernation = true;
+			return 0;
+		}
+	}
+
+	reset_control_bulk_assert(google->num_rsts, google->rsts);
+	clk_bulk_disable_unprepare(google->num_clks, google->clks);
+
+	return 0;
+}
+
+static int dwc3_google_resume(struct dwc3_google *google, pm_message_t msg)
+{
+	int ret;
+
+	if (google->is_hibernation) {
+		dev_dbg(google->dev, "exit hibernation");
+		dwc3_google_disable_pme_irq(google);
+		device_wakeup_disable(google->usb_top_pd);
+		pm_runtime_put_sync(google->usb_top_pd);
+		google->is_hibernation = false;
+		return 0;
+	}
+
+	if (google->is_usb2only)
+		dwc3_google_program_usb2only(google);
+
+	ret = clk_bulk_prepare_enable(google->num_clks, google->clks);
+	if (ret)
+		return ret;
+
+	ret = reset_control_bulk_deassert(google->num_rsts, google->rsts);
+	if (ret) {
+		clk_bulk_disable_unprepare(google->num_clks, google->clks);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int dwc3_google_pm_suspend(struct device *dev)
+{
+	struct dwc3 *dwc = dev_get_drvdata(dev);
+	struct dwc3_google *google = to_dwc3_google(dwc);
+	int ret;
+
+	ret = dwc3_pm_suspend(&google->dwc);
+	if (ret)
+		return ret;
+
+	return dwc3_google_suspend(google, PMSG_SUSPEND);
+}
+
+static int dwc3_google_pm_resume(struct device *dev)
+{
+	struct dwc3 *dwc = dev_get_drvdata(dev);
+	struct dwc3_google *google = to_dwc3_google(dwc);
+	int ret;
+
+	ret = dwc3_google_resume(google, PMSG_RESUME);
+	if (ret)
+		return ret;
+
+	return dwc3_pm_resume(&google->dwc);
+}
+
+static void dwc3_google_complete(struct device *dev)
+{
+	struct dwc3 *dwc = dev_get_drvdata(dev);
+
+	dwc3_pm_complete(dwc);
+}
+
+static int dwc3_google_prepare(struct device *dev)
+{
+	struct dwc3 *dwc = dev_get_drvdata(dev);
+
+	return dwc3_pm_prepare(dwc);
+}
+
+static int dwc3_google_runtime_suspend(struct device *dev)
+{
+	struct dwc3 *dwc = dev_get_drvdata(dev);
+	struct dwc3_google *google = to_dwc3_google(dwc);
+	int ret;
+
+	ret = dwc3_runtime_suspend(&google->dwc);
+	if (ret)
+		return ret;
+
+	return dwc3_google_suspend(google, PMSG_AUTO_SUSPEND);
+}
+
+static int dwc3_google_runtime_resume(struct device *dev)
+{
+	struct dwc3 *dwc = dev_get_drvdata(dev);
+	struct dwc3_google *google = to_dwc3_google(dwc);
+	int ret;
+
+	ret = dwc3_google_resume(google, PMSG_AUTO_RESUME);
+	if (ret)
+		return ret;
+
+	return dwc3_runtime_resume(&google->dwc);
+}
+
+static int dwc3_google_runtime_idle(struct device *dev)
+{
+	return dwc3_runtime_idle(dev_get_drvdata(dev));
+}
+
+static const struct dev_pm_ops dwc3_google_dev_pm_ops = {
+	SYSTEM_SLEEP_PM_OPS(dwc3_google_pm_suspend, dwc3_google_pm_resume)
+	RUNTIME_PM_OPS(dwc3_google_runtime_suspend, dwc3_google_runtime_resume,
+		       dwc3_google_runtime_idle)
+	.complete = pm_sleep_ptr(dwc3_google_complete),
+	.prepare = pm_sleep_ptr(dwc3_google_prepare),
+};
+
+static const struct of_device_id dwc3_google_of_match[] = {
+	{ .compatible = "google,lga-dwc3" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, dwc3_google_of_match);
+
+static struct platform_driver dwc3_google_driver = {
+	.probe		= dwc3_google_probe,
+	.remove		= dwc3_google_remove,
+	.driver		= {
+		.name	= "dwc3-google",
+		.pm	= pm_ptr(&dwc3_google_dev_pm_ops),
+		.of_match_table	= dwc3_google_of_match,
+	},
+};
+
+module_platform_driver(dwc3_google_driver);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DesignWare DWC3 Google Glue Driver");

-- 
2.52.0.223.gf5cc29aaa4-goog



From xu.yang_2 at nxp.com  Thu Dec  4 18:41:42 2025
From: xu.yang_2 at nxp.com (Xu Yang)
Date: Fri, 5 Dec 2025 10:41:42 +0800
Subject: [PATCH 2/2] usb: dwc3: imx8mp: disable auto suspend for host role
In-Reply-To: <20251202000013.qnv3nkhyr7gtlu6n@synopsys.com>
References: <20251105074504.1427926-1-xu.yang_2@nxp.com>
 <20251105074504.1427926-2-xu.yang_2@nxp.com>
 <20251113230541.wbzt6xbine5gdmpp@synopsys.com>
 <7kpf7gnftumdwdowutryjz73nkap4vp3cfisrigt6def4f36vg@ijlj2eqwzsip>
 <20251121003742.q54ouezxhghmpwgn@synopsys.com>
 <bj6hroepwqflz5z3wabxacfhxltt2u6x274gd5v66rihosy3my@pzgq2e4v45fx>
 <20251202000013.qnv3nkhyr7gtlu6n@synopsys.com>
Message-ID: <qnaxqfnnjxx4vnsceemcgsq37uai4apqypcjiudyrdb7jrz5bf@qyhzmjf43vvb>

On Tue, Dec 02, 2025 at 12:00:16AM +0000, Thinh Nguyen wrote:
> On Tue, Nov 25, 2025, Xu Yang wrote:
> > On Fri, Nov 21, 2025 at 12:37:47AM +0000, Thinh Nguyen wrote:
> > > On Mon, Nov 17, 2025, Xu Yang wrote:
> > > > On Thu, Nov 13, 2025 at 11:05:43PM +0000, Thinh Nguyen wrote:
> > > > > On Wed, Nov 05, 2025, Xu Yang wrote:
> > > > > > Do dwc3 core auto suspend enable for device and disable for host
> > > > > > , this can make sure dwc3 core device auto suspend setting is
> > > > > > correct all the time, the background of disable dwc3 core device
> > > > > > auto suspend is to make its parent device suspend immediately
> > > > > > (so wakeup enable can be enabled) after xhci-plat device suspended,
> > > > > > for device mode, we keep the dwc3 core device auto suspend is to
> > > > > > give some wait for gadget to be enumerated.
> > > > > > 
> > > > > > Signed-off-by: Xu Yang <xu.yang_2 at nxp.com>
> > > > > > ---
> > > > > >  drivers/usb/dwc3/dwc3-imx8mp.c | 31 +++++++++++++++++++++++++++++++
> > > > > >  1 file changed, 31 insertions(+)
> > > > > > 
> > > > > > diff --git a/drivers/usb/dwc3/dwc3-imx8mp.c b/drivers/usb/dwc3/dwc3-imx8mp.c
> > > > > > index bce6af82f54c..80a431cb6fed 100644
> > > > > > --- a/drivers/usb/dwc3/dwc3-imx8mp.c
> > > > > > +++ b/drivers/usb/dwc3/dwc3-imx8mp.c
> > > > > > @@ -158,11 +158,31 @@ static irqreturn_t dwc3_imx8mp_interrupt(int irq, void *_dwc3_imx)
> > > > > >  	return IRQ_HANDLED;
> > > > > >  }
> > > > > >  
> > > > > > +static void dwc3_imx_pre_set_role(struct dwc3 *dwc, enum usb_role role)
> > > > > > +{
> > > > > > +	if (role == USB_ROLE_HOST)
> > > > > > +		/*
> > > > > > +		 * For xhci host, we need disable dwc core auto
> > > > > > +		 * suspend, because during this auto suspend delay(5s),
> > > > > > +		 * xhci host RUN_STOP is cleared and wakeup is not
> > > > > > +		 * enabled, if device is inserted, xhci host can't
> > > > > > +		 * response the connection.
> > > > > > +		 */
> > > > > > +		pm_runtime_dont_use_autosuspend(dwc->dev);
> > > > > > +	else
> > > > > > +		pm_runtime_use_autosuspend(dwc->dev);
> > > > > 
> > > > > Would this override the user setting everytime there's a role switch?
> > > > 
> > > > From what I know, the user can't control whether to enable or disable
> > > > autosuspend feature. So there should be no overriding problem. When
> > > > user change autosuspend_delay_ms, the delay setting will be kept
> > > > everytime there's a role switch.
> > > 
> > > Should we set pm_runtime_mark_last_busy()?
> > 
> > I think we needn't explicitly call pm_runtime_mark_last_busy().
> > Since commit "08071e64cb64 PM: runtime: Mark last busy stamp in pm_runtime_autosuspend()",
> > pm_runtime_autosuspend() will do that thing automatically once dwc3 device is idle.
> 
> Ok.
> 
> > 
> > > 
> > > Also, if pm_runtime_use_autosuspend() is set, make sure to unwind with
> > > pm_runtime_dont_use_autosuspend() on remove.
> > > 
> > > > 
> > > > > 
> > > > > > +}
> > > > > > +
> > > > > > +struct dwc3_glue_ops dwc3_imx_glue_ops = {
> > > > > > +	.pre_set_role   = dwc3_imx_pre_set_role,
> > > > > > +};
> > > > > > +
> > > > > >  static int dwc3_imx8mp_probe(struct platform_device *pdev)
> > > > > >  {
> > > > > >  	struct device		*dev = &pdev->dev;
> > > > > >  	struct device_node	*node = dev->of_node;
> > > > > >  	struct dwc3_imx8mp	*dwc3_imx;
> > > > > > +	struct dwc3		*dwc3;
> > > > > >  	struct resource		*res;
> > > > > >  	int			err, irq;
> > > > > >  
> > > > > > @@ -240,6 +260,17 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev)
> > > > > >  		goto depopulate;
> > > > > >  	}
> > > > > >  
> > > > > > +	dwc3 = platform_get_drvdata(dwc3_imx->dwc3);
> > > > > 
> > > > > It's confusing how dwc3_imx->dwc3 is also named dwc3...
> > > > 
> > > > I will rename it later.
> > > > 
> > > > > 
> > > > > > +	if (!dwc3) {
> > > > > > +		err = dev_err_probe(dev, -EPROBE_DEFER, "failed to get dwc3 platform data\n");
> > > > > > +		goto depopulate;
> > > > > > +	}
> > > > > > +
> > > > > > +	dwc3->glue_ops = &dwc3_imx_glue_ops;
> > > > > 
> > > > > If you want to use glue_ops, please use the new flatten model. I
> > > > > don't want dwc3 to be initialized again after of_platform_populate().
> > > > 
> > > > I understand the new flatten model is a more suitable way. Considering that
> > > > many i.MX devices are using this legacy unflatten model, do you mind allow
> > > > this change firstly and we will switch to the new flatten model in the future?
> > > > 
> > > 
> > > Do you have plans for this transition? Perhaps this is a good time to
> > > initiate the process so to avoid having and maintaining this improper
> > > code while we still don't have it yet.
> > 
> > OK. It's a trend to use new flatten model. I do have plan for it. I'll
> > prepare for it later.
> > 
> 
> Ok. Can we add a note that this is a temporary solution until we switch
> to using the new model in the commit message.

Ok. Will do. Thank you!

Thanks,
Xu Yang

> 
> Thanks,
> Thinh


From xu.yang_2 at nxp.com  Thu Dec  4 19:29:40 2025
From: xu.yang_2 at nxp.com (Xu Yang)
Date: Fri,  5 Dec 2025 11:29:40 +0800
Subject: [PATCH v2 1/3] usb: dwc3: drd: extend dwc3_pre_set_role() to extcon and otg usecase
Message-ID: <20251205032942.2259671-1-xu.yang_2@nxp.com>

Call dwc3_pre_set_role() to support both extcon and otg usecase, so that
the glue driver can do proper action in case of role changes.

Reviewed-by: Frank Li <Frank.Li at nxp.com>
Acked-by: Thinh Nguyen <Thinh.Nguyen at synopsys.com>
Signed-off-by: Xu Yang <xu.yang_2 at nxp.com>

---
Changes in v2:
 - improve commit message
 - add Rb and Ab tag
---
 drivers/usb/dwc3/drd.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c
index 589bbeb27454..031cfd12300a 100644
--- a/drivers/usb/dwc3/drd.c
+++ b/drivers/usb/dwc3/drd.c
@@ -381,6 +381,7 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus)
 		dwc3_otgregs_init(dwc);
 		dwc3_otg_host_init(dwc);
 		spin_unlock_irqrestore(&dwc->lock, flags);
+		dwc3_pre_set_role(dwc, USB_ROLE_HOST);
 		ret = dwc3_host_init(dwc);
 		if (ret) {
 			dev_err(dwc->dev, "failed to initialize host\n");
@@ -406,6 +407,7 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus)
 			otg_set_vbus(dwc->usb2_phy->otg, false);
 		if (dwc->usb2_generic_phy[0])
 			phy_set_mode(dwc->usb2_generic_phy[0], PHY_MODE_USB_DEVICE);
+		dwc3_pre_set_role(dwc, USB_ROLE_DEVICE);
 		ret = dwc3_gadget_init(dwc);
 		if (ret)
 			dev_err(dwc->dev, "failed to initialize peripheral\n");
@@ -433,10 +435,12 @@ static int dwc3_drd_notifier(struct notifier_block *nb,
 			     unsigned long event, void *ptr)
 {
 	struct dwc3 *dwc = container_of(nb, struct dwc3, edev_nb);
+	u32 mode = event ? DWC3_GCTL_PRTCAP_HOST : DWC3_GCTL_PRTCAP_DEVICE;
+	enum usb_role role = mode == DWC3_GCTL_PRTCAP_HOST ?
+				     USB_ROLE_HOST : USB_ROLE_DEVICE;
 
-	dwc3_set_mode(dwc, event ?
-		      DWC3_GCTL_PRTCAP_HOST :
-		      DWC3_GCTL_PRTCAP_DEVICE);
+	dwc3_pre_set_role(dwc, role);
+	dwc3_set_mode(dwc, mode);
 
 	return NOTIFY_DONE;
 }
-- 
2.34.1



From xu.yang_2 at nxp.com  Thu Dec  4 19:29:41 2025
From: xu.yang_2 at nxp.com (Xu Yang)
Date: Fri,  5 Dec 2025 11:29:41 +0800
Subject: [PATCH v2 2/3] usb: dwc3: imx8mp: rename dwc3 to dwc3_pdev in struct dwc3_imx8mp
In-Reply-To: <20251205032942.2259671-1-xu.yang_2@nxp.com>
References: <20251205032942.2259671-1-xu.yang_2@nxp.com>
Message-ID: <20251205032942.2259671-2-xu.yang_2@nxp.com>

It's confuse to let "dwc3" represent a platform_device, because "dwc3"
may also represent a dwc3 core structure. Rename it for better
distinction.

Signed-off-by: Xu Yang <xu.yang_2 at nxp.com>

---
Changes in v2:
 - new patch
---
 drivers/usb/dwc3/dwc3-imx8mp.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/dwc3/dwc3-imx8mp.c b/drivers/usb/dwc3/dwc3-imx8mp.c
index 050da327f785..8bece4baecbf 100644
--- a/drivers/usb/dwc3/dwc3-imx8mp.c
+++ b/drivers/usb/dwc3/dwc3-imx8mp.c
@@ -51,7 +51,7 @@
 
 struct dwc3_imx8mp {
 	struct device			*dev;
-	struct platform_device		*dwc3;
+	struct platform_device		*dwc3_pdev;
 	void __iomem			*hsio_blk_base;
 	void __iomem			*glue_base;
 	struct clk			*hsio_clk;
@@ -100,7 +100,7 @@ static void imx8mp_configure_glue(struct dwc3_imx8mp *dwc3_imx)
 static void dwc3_imx8mp_wakeup_enable(struct dwc3_imx8mp *dwc3_imx,
 				      pm_message_t msg)
 {
-	struct dwc3	*dwc3 = platform_get_drvdata(dwc3_imx->dwc3);
+	struct dwc3	*dwc3 = platform_get_drvdata(dwc3_imx->dwc3_pdev);
 	u32		val;
 
 	if (!dwc3)
@@ -142,7 +142,7 @@ static const struct software_node dwc3_imx8mp_swnode = {
 static irqreturn_t dwc3_imx8mp_interrupt(int irq, void *_dwc3_imx)
 {
 	struct dwc3_imx8mp	*dwc3_imx = _dwc3_imx;
-	struct dwc3		*dwc = platform_get_drvdata(dwc3_imx->dwc3);
+	struct dwc3		*dwc = platform_get_drvdata(dwc3_imx->dwc3_pdev);
 
 	if (!dwc3_imx->pm_suspended)
 		return IRQ_HANDLED;
@@ -233,8 +233,8 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev)
 		goto remove_swnode;
 	}
 
-	dwc3_imx->dwc3 = of_find_device_by_node(dwc3_np);
-	if (!dwc3_imx->dwc3) {
+	dwc3_imx->dwc3_pdev = of_find_device_by_node(dwc3_np);
+	if (!dwc3_imx->dwc3_pdev) {
 		dev_err(dev, "failed to get dwc3 platform device\n");
 		err = -ENODEV;
 		goto depopulate;
@@ -253,7 +253,7 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev)
 	return 0;
 
 put_dwc3:
-	put_device(&dwc3_imx->dwc3->dev);
+	put_device(&dwc3_imx->dwc3_pdev->dev);
 depopulate:
 	of_platform_depopulate(dev);
 remove_swnode:
@@ -270,7 +270,7 @@ static void dwc3_imx8mp_remove(struct platform_device *pdev)
 	struct dwc3_imx8mp *dwc3_imx = platform_get_drvdata(pdev);
 	struct device *dev = &pdev->dev;
 
-	put_device(&dwc3_imx->dwc3->dev);
+	put_device(&dwc3_imx->dwc3_pdev->dev);
 
 	pm_runtime_get_sync(dev);
 	of_platform_depopulate(dev);
@@ -296,7 +296,7 @@ static int dwc3_imx8mp_suspend(struct dwc3_imx8mp *dwc3_imx, pm_message_t msg)
 
 static int dwc3_imx8mp_resume(struct dwc3_imx8mp *dwc3_imx, pm_message_t msg)
 {
-	struct dwc3	*dwc = platform_get_drvdata(dwc3_imx->dwc3);
+	struct dwc3	*dwc = platform_get_drvdata(dwc3_imx->dwc3_pdev);
 	int ret = 0;
 
 	if (!dwc3_imx->pm_suspended)
-- 
2.34.1



From xu.yang_2 at nxp.com  Thu Dec  4 19:29:42 2025
From: xu.yang_2 at nxp.com (Xu Yang)
Date: Fri,  5 Dec 2025 11:29:42 +0800
Subject: [PATCH v2 3/3] usb: dwc3: imx8mp: disable auto suspend for host role
In-Reply-To: <20251205032942.2259671-1-xu.yang_2@nxp.com>
References: <20251205032942.2259671-1-xu.yang_2@nxp.com>
Message-ID: <20251205032942.2259671-3-xu.yang_2@nxp.com>

Do dwc3 core auto suspend enable for device and disable for host
, this can make sure dwc3 core device auto suspend setting is
correct all the time, the background of disable dwc3 core device
auto suspend is to make its parent device suspend immediately
(so wakeup enable can be enabled) after xhci-plat device suspended,
for device mode, we keep the dwc3 core device auto suspend is to
give some wait for gadget to be enumerated.

Note: It's a temporary solution until we switch to using the new
      flatten model.

Signed-off-by: Xu Yang <xu.yang_2 at nxp.com>

---
Changes in v2:
 - add a note suggested by Thinh
---
 drivers/usb/dwc3/dwc3-imx8mp.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/drivers/usb/dwc3/dwc3-imx8mp.c b/drivers/usb/dwc3/dwc3-imx8mp.c
index 8bece4baecbf..2e13ca588f42 100644
--- a/drivers/usb/dwc3/dwc3-imx8mp.c
+++ b/drivers/usb/dwc3/dwc3-imx8mp.c
@@ -158,11 +158,31 @@ static irqreturn_t dwc3_imx8mp_interrupt(int irq, void *_dwc3_imx)
 	return IRQ_HANDLED;
 }
 
+static void dwc3_imx_pre_set_role(struct dwc3 *dwc, enum usb_role role)
+{
+	if (role == USB_ROLE_HOST)
+		/*
+		 * For xhci host, we need disable dwc core auto
+		 * suspend, because during this auto suspend delay(5s),
+		 * xhci host RUN_STOP is cleared and wakeup is not
+		 * enabled, if device is inserted, xhci host can't
+		 * response the connection.
+		 */
+		pm_runtime_dont_use_autosuspend(dwc->dev);
+	else
+		pm_runtime_use_autosuspend(dwc->dev);
+}
+
+struct dwc3_glue_ops dwc3_imx_glue_ops = {
+	.pre_set_role   = dwc3_imx_pre_set_role,
+};
+
 static int dwc3_imx8mp_probe(struct platform_device *pdev)
 {
 	struct device		*dev = &pdev->dev;
 	struct device_node	*node = dev->of_node;
 	struct dwc3_imx8mp	*dwc3_imx;
+	struct dwc3		*dwc3;
 	struct resource		*res;
 	int			err, irq;
 
@@ -240,6 +260,17 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev)
 		goto depopulate;
 	}
 
+	dwc3 = platform_get_drvdata(dwc3_imx->dwc3_pdev);
+	if (!dwc3) {
+		err = dev_err_probe(dev, -EPROBE_DEFER, "failed to get dwc3 platform data\n");
+		goto depopulate;
+	}
+
+	dwc3->glue_ops = &dwc3_imx_glue_ops;
+
+	if (dwc3->dr_mode == USB_DR_MODE_HOST)
+		pm_runtime_dont_use_autosuspend(dwc3->dev);
+
 	err = devm_request_threaded_irq(dev, irq, NULL, dwc3_imx8mp_interrupt,
 					IRQF_ONESHOT, dev_name(dev), dwc3_imx);
 	if (err) {
-- 
2.34.1



From royluo at google.com  Thu Dec  4 19:51:01 2025
From: royluo at google.com (Roy Luo)
Date: Thu, 4 Dec 2025 19:51:01 -0800
Subject: [PATCH v7 2/2] phy: Add Google Tensor SoC USB PHY driver
In-Reply-To: <1a53d473-fc13-4ac5-ba52-4701d95e3073@kernel.org>
References: <20251121-phyb4-v7-0-df644fa62180@google.com> <20251121-phyb4-v7-2-df644fa62180@google.com>
 <CADrjBPpLn9qzg1y5_c_0CYL2U8p6taMWtPOw5RykAO4=4uNeUA@mail.gmail.com> <1a53d473-fc13-4ac5-ba52-4701d95e3073@kernel.org>
Message-ID: <CA+zupgw4_o7Po_Zw1qT13YU=PGXoJ_RAPKiAwFpt6RRyO14OAA@mail.gmail.com>

On Sat, Nov 22, 2025 at 4:49?AM Krzysztof Kozlowski <krzk at kernel.org> wrote:
>
> On 22/11/2025 13:48, Peter Griffin wrote:
> > Hi Roy,
> >
> > On Fri, 21 Nov 2025 at 08:56, Roy Luo <royluo at google.com> wrote:
> >>
> >> Support the USB PHY found on Google Tensor G5 (Laguna). This
> >> particular USB PHY supports both high-speed and super-speed
> >> operations, and is integrated with the SNPS DWC3 controller that's
> >> also on the SoC. This initial patch specifically adds functionality
> >> for high-speed.
> >>
> >> Co-developed-by: Joy Chakraborty <joychakr at google.com>
> >> Signed-off-by: Joy Chakraborty <joychakr at google.com>
> >> Co-developed-by: Naveen Kumar <mnkumar at google.com>
> >> Signed-off-by: Naveen Kumar <mnkumar at google.com>
> >> Signed-off-by: Roy Luo <royluo at google.com>
> >> ---
> >>  drivers/phy/Kconfig          |  13 ++
> >>  drivers/phy/Makefile         |   1 +
> >>  drivers/phy/phy-google-usb.c | 292 +++++++++++++++++++++++++++++++++++++++++++
> >
> > Please add this new file to Tensor SoC MAINTAINERS entry so it's
> > easier to review future patches.
> >
> >>  3 files changed, 306 insertions(+)
> >>
> >> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> >> index 678dd0452f0aa0597773433f04d2a9ba77474d2a..af14ec74542a9879c856dee8236753990fdf3705 100644
> >> --- a/drivers/phy/Kconfig
> >> +++ b/drivers/phy/Kconfig
> >> @@ -101,6 +101,19 @@ config PHY_NXP_PTN3222
> >>           schemes. It supports all three USB 2.0 data rates: Low Speed, Full
> >>           Speed and High Speed.
> >>
> >> +config PHY_GOOGLE_USB
> >> +       tristate "Google Tensor SoC USB PHY driver"
> >> +       depends on HAS_IOMEM
> >> +       depends on OF
> >> +       depends on TYPEC
> >
> > Add COMPILE_TEST for build testing.
>
> ... and this probably should depend on your ARCH_xxx || COMPILE_TEST
>
> Same for USB DWC driver.
>
>
> Best regards,
> Krzysztof

Peter and Krzysztof,

Thanks for the review and ack to all the comments.
Sending out a new version.

Thanks,
Roy Luo


From sashal at kernel.org  Thu Dec  4 19:52:34 2025
From: sashal at kernel.org (Sasha Levin)
Date: Thu,  4 Dec 2025 22:52:34 -0500
Subject: [PATCH AUTOSEL 6.18-5.10] cpufreq: s5pv210: fix refcount leak
In-Reply-To: <20251205035239.341989-1-sashal@kernel.org>
References: <20251205035239.341989-1-sashal@kernel.org>
Message-ID: <20251205035239.341989-5-sashal@kernel.org>

From: Shuhao Fu <sfual at cse.ust.hk>

[ Upstream commit 2de5cb96060a1664880d65b120e59485a73588a8 ]

In function `s5pv210_cpu_init`, a possible refcount inconsistency has
been identified, causing a resource leak.

Why it is a bug:
1. For every clk_get, there should be a matching clk_put on every
successive error handling path.
2. After calling `clk_get(dmc1_clk)`, variable `dmc1_clk` will not be
freed even if any error happens.

How it is fixed: For every failed path, an extra goto label is added to
ensure `dmc1_clk` will be freed regardlessly.

Signed-off-by: Shuhao Fu <sfual at cse.ust.hk>
Signed-off-by: Viresh Kumar <viresh.kumar at linaro.org>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---

LLM Generated explanations, may be completely bogus:

## Analysis

### 1. COMMIT MESSAGE ANALYSIS

The commit message describes a refcount leak:
- Subject: "cpufreq: s5pv210: fix refcount leak"
- Explains the bug: `dmc1_clk` is not freed on error paths
- Explains the fix: adds a new `out:` label to ensure cleanup
- Signed-off-by: Shuhao Fu and Viresh Kumar (cpufreq maintainer)

Missing tags:
- No "Cc: stable at vger.kernel.org"
- No "Fixes:" tag pointing to the commit that introduced the bug
  (4911ca1031c2ad from 2011)

### 2. CODE CHANGE ANALYSIS

The bug:
- In `s5pv210_cpu_init()`, after `dmc1_clk = clk_get(...)` succeeds, two
  error paths jump to `out_dmc1`:
  1. `policy->cpu != 0` (line 521)
  2. Unsupported memory type (line 533)
- `out_dmc1` only frees `dmc0_clk` and `policy->clk`, not `dmc1_clk`,
  causing a refcount leak.

The fix:
- Adds a new `out:` label that calls `clk_put(dmc1_clk)`
- Changes the two error paths to `goto out;` instead of `goto out_dmc1;`
- `out:` falls through to `out_dmc1` for the rest of cleanup

Change size: 4 lines added, 2 lines modified (minimal change)

### 3. CLASSIFICATION

- Bug fix: fixes a resource leak
- Not a feature addition
- Not a new API
- Standard error handling pattern

### 4. SCOPE AND RISK ASSESSMENT

- Scope: single function, error paths only
- Risk: low
  - Only affects error paths
  - Standard cleanup pattern
  - No logic changes beyond cleanup
- Subsystem: cpufreq (mature)
- Dependencies: none; self-contained

### 5. USER IMPACT

- Affected users: systems using the S5PV210/S5PC110 cpufreq driver
- Severity: resource leak (not a crash, but still a bug)
- Trigger conditions:
  1. `policy->cpu != 0` (non-zero CPU)
  2. Unsupported memory type (not LPDDR/LPDDR2)
- Impact: clock reference leak on error paths

Historical context:
- Driver introduced in v2.6.37 (2010)
- Bug introduced in commit 4911ca1031c2ad (2011-06-06)
- Present in all stable trees since 2011

### 6. STABILITY INDICATORS

- Tested: no "Tested-by:" tag
- Reviewed: signed by Viresh Kumar (maintainer)
- Age: commit is recent (Oct 2025), but the bug is old

### 7. DEPENDENCY CHECK

- No dependencies
- Code exists in stable trees (driver present since v2.6.37)
- Fix applies cleanly to stable trees

### 8. COMPARISON WITH SIMILAR FIXES

Similar refcount leak fixes in cpufreq:
- `cpufreq: nforce2: fix reference count leak` (9600156bb9985)
- `cpufreq: mediatek: fix device leak on probe failure` (ebc4ed14a4dbf)
- `cpufreq: qcom-nvmem: fix memory leaks in probe error paths`
  (e3fd01a810537)

These follow the same pattern and are appropriate for stable.

### 9. STABLE KERNEL RULES COMPLIANCE

- Obviously correct: yes ? standard cleanup pattern
- Fixes a real bug: yes ? resource leak
- Important issue: moderate ? resource leak, not a crash
- Small and contained: yes ? 6 lines changed
- No new features: yes ? only fixes cleanup
- Applies cleanly: yes ? no dependencies

### 10. RISK VS BENEFIT TRADE-OFF

Benefits:
- Fixes a long-standing bug (14 years)
- Prevents resource leaks
- Low risk, small change
- Standard pattern

Risks:
- Minimal ? only touches error paths
- No functional changes

Concerns:
- No explicit stable request tag
- Driver targets older ARM SoCs (may have limited current use)
- Leak only occurs on error paths

### FINAL ASSESSMENT

This is a valid bug fix that meets stable criteria:
1. Fixes a real resource leak
2. Small, contained change
3. Low risk
4. No new features
5. Standard error handling pattern

The lack of a "Cc: stable" tag is not a blocker; maintainers may add it,
or it may have been missed. The fix is appropriate for stable backport.

**YES**

 drivers/cpufreq/s5pv210-cpufreq.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c
index 4215621deb3fe..ba8a1c96427a1 100644
--- a/drivers/cpufreq/s5pv210-cpufreq.c
+++ b/drivers/cpufreq/s5pv210-cpufreq.c
@@ -518,7 +518,7 @@ static int s5pv210_cpu_init(struct cpufreq_policy *policy)
 
 	if (policy->cpu != 0) {
 		ret = -EINVAL;
-		goto out_dmc1;
+		goto out;
 	}
 
 	/*
@@ -530,7 +530,7 @@ static int s5pv210_cpu_init(struct cpufreq_policy *policy)
 	if ((mem_type != LPDDR) && (mem_type != LPDDR2)) {
 		pr_err("CPUFreq doesn't support this memory type\n");
 		ret = -EINVAL;
-		goto out_dmc1;
+		goto out;
 	}
 
 	/* Find current refresh counter and frequency each DMC */
@@ -544,6 +544,8 @@ static int s5pv210_cpu_init(struct cpufreq_policy *policy)
 	cpufreq_generic_init(policy, s5pv210_freq_table, 40000);
 	return 0;
 
+out:
+	clk_put(dmc1_clk);
 out_dmc1:
 	clk_put(dmc0_clk);
 out_dmc0:
-- 
2.51.0



From royluo at google.com  Thu Dec  4 19:54:10 2025
From: royluo at google.com (Roy Luo)
Date: Fri, 05 Dec 2025 03:54:10 +0000
Subject: [PATCH v8 0/2] Add Google Tensor SoC USB PHY support
Message-ID: <20251205-phyb4-v8-0-c59ea80a4458@google.com>

This series introduces USB PHY support for the Google Tensor G5
SoC (codename: Laguna), a new generation of Google silicon first
launched with Pixel 10 devices.

The Tensor G5 represents a significant architectural overhaul compared
to previous Tensor generations (e.g., gs101), which were based on Samsung
Exynos IP. Although the G5 still utilizes Synopsys IP for the USB
components, the custom top-level integration introduces a completely new
design for clock, reset scheme, register interfaces and programming
sequence, necessitating new drivers and device tree bindings.

The USB subsystem on Tensor G5 integrates a Synopsys DWC3 USB 3.1
DRD-Single Port controller with hibernation support, and a custom PHY
block comprising Synopsys eUSB2 and USB 3.2/DP combo PHYs. The controller
support is sent as a separate patch series.

Co-developed-by: Joy Chakraborty <joychakr at google.com>
Signed-off-by: Joy Chakraborty <joychakr at google.com>
Co-developed-by: Naveen Kumar <mnkumar at google.com>
Signed-off-by: Naveen Kumar <mnkumar at google.com>
Signed-off-by: Roy Luo <royluo at google.com>
---
Changes in v8:
- Update the Kconfig dependency to depends on ARCH_GOOGLE || COMPILE_TEST
  Note that ARCH_GOOGLE does not exist yet but will eventually
  be there when the following patch lands
  https://lore.kernel.org/r/20251111112158.3.I35b9e835ac49ab408e5ca3e0983930a1f1395814 at changeid/
- Mention SoC codename Laguna in Kconfig description.
- Sort the header alphabetically and sort the variables using the
  reverse christmas tree ordering.
- Add driver and binding files to the Tensor SoC MAINTAINER entry.
- Add detailed comment for phy_mutex
Link to v7: https://lore.kernel.org/r/20251121-phyb4-v7-0-df644fa62180 at google.com

Changes in v7:
- Change the device tree binding example node name to usb-phy to follow
 the hyphen-separated naming convention and remove label.
Link to v6: https://lore.kernel.org/r/20251120-phyb4-v6-0-b6694e1f0caf at google.com

Changes in v6:
- Use "lga" as SoC name instead of "gs5" to align with Tensor G5 device
  tree https://lore.kernel.org/lkml/20251111192422.4180216-1-dianders at chromium.org 
- Add "usb2_core" to the reg property to define the MMIO space for
  the eUSB 2.0 PHY IP.
- Rename "usb3_top" reg as "usbdp_top" and update the description to
  reflect its nature as a top-level wrapper and align with internal
  documentation.
- Use syscon to access the "usb2_cfg" MMIO space.
- Remove minItems for clocks and resets, making all listed clocks and
  resets (including USB3) mandatory.
Link to v5: https://lore.kernel.org/linux-phy/20251029214032.3175261-1-royluo at google.com

Changes in v5:
- Add usb3 registers/clks/resets to binding as suggested by Krzysztof
  Kozlowski. This ensures completeness of the binding, though the
  driver has not yet ultilized the resources. The usb3 clks and resets
  are optional if usb2-only operation is desired, this is denoted by
  minItems and descriptions in the clocks and resets properties.
  Additionally, rename existing binding entries for consistency and to
  better differntiate between usb2 and usb3.
- Move the description of the phy select to phy-cells in binding as
  suggested by Krzysztof Kozlowski.
Link to v4: https://lore.kernel.org/linux-phy/20251017235159.2417576-1-royluo at google.com

Changes in v4:
- Separate controller and phy changes into two distinct patch series.
- Remove usb2only mode configuration and the corresponding usb_top_cfg
  reg (moved to controller)
- Add more descriptions to dp_top reg to indicate it's not DP specific.
- Add u2phy_apb clk/reset
Link to v3: https://lore.kernel.org/linux-usb/20251010201607.1190967-1-royluo at google.com

Changes in v3:
- Align binding file name with the compatible string
- Simplify the compatible property in binding to a single const value.
- Add descriptive comments and use item list in binding.
- Rename binding entries for clarity and brevity.
Link to v2: https://lore.kernel.org/linux-usb/20251008060000.3136021-1-royluo at google.com

Changes in v2:
- Reorder patches to present bindings first.
- Update dt binding compatible strings to be SoC-specific (google,gs5-*).
- Better describe the hardware in dt binding commit messages and
  descriptions.
- Adjust PHY driver commit subjects to use correct prefixes ("phy:").
- Move PHY driver from a subdirectory to drivers/phy/.
Link to v1: https://lore.kernel.org/linux-usb/20251006232125.1833979-1-royluo at google.com/

---
Roy Luo (2):
      dt-bindings: phy: google: Add Google Tensor G5 USB PHY
      phy: Add Google Tensor SoC USB PHY driver

 .../bindings/phy/google,lga-usb-phy.yaml           | 133 ++++++++++
 MAINTAINERS                                        |   2 +
 drivers/phy/Kconfig                                |  11 +
 drivers/phy/Makefile                               |   1 +
 drivers/phy/phy-google-usb.c                       | 295 +++++++++++++++++++++
 5 files changed, 442 insertions(+)
---
base-commit: 43dfc13ca972988e620a6edb72956981b75ab6b0
change-id: 20251119-phyb4-2e03a7c449c4

Best regards,
-- 
Roy Luo <royluo at google.com>



From royluo at google.com  Thu Dec  4 19:54:12 2025
From: royluo at google.com (Roy Luo)
Date: Fri, 05 Dec 2025 03:54:12 +0000
Subject: [PATCH v8 2/2] phy: Add Google Tensor SoC USB PHY driver
In-Reply-To: <20251205-phyb4-v8-0-c59ea80a4458@google.com>
References: <20251205-phyb4-v8-0-c59ea80a4458@google.com>
Message-ID: <20251205-phyb4-v8-2-c59ea80a4458@google.com>

Support the USB PHY found on Google Tensor G5 (Laguna). This
particular USB PHY supports both high-speed and super-speed
operations, and is integrated with the SNPS DWC3 controller that's
also on the SoC. This initial patch specifically adds functionality
for high-speed.

Co-developed-by: Joy Chakraborty <joychakr at google.com>
Signed-off-by: Joy Chakraborty <joychakr at google.com>
Co-developed-by: Naveen Kumar <mnkumar at google.com>
Signed-off-by: Naveen Kumar <mnkumar at google.com>
Signed-off-by: Roy Luo <royluo at google.com>
---
 MAINTAINERS                  |   1 +
 drivers/phy/Kconfig          |  11 ++
 drivers/phy/Makefile         |   1 +
 drivers/phy/phy-google-usb.c | 295 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 308 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 27e6f9e20f5e83b861c6a04dededb93b8561715c..50ffe42c7c373914aa96314430f35843efc1dc07 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10665,6 +10665,7 @@ F:	Documentation/devicetree/bindings/phy/google,lga-usb-phy.yaml
 F:	Documentation/devicetree/bindings/soc/google/google,gs101-pmu-intr-gen.yaml
 F:	arch/arm64/boot/dts/exynos/google/
 F:	drivers/clk/samsung/clk-gs101.c
+F:	drivers/phy/phy-google-usb.c
 F:	drivers/phy/samsung/phy-gs101-ufs.c
 F:	include/dt-bindings/clock/google,gs101.h
 K:	[gG]oogle.?[tT]ensor
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 678dd0452f0aa0597773433f04d2a9ba77474d2a..c6fbf83de656349f5c9be27a18748b9bd327f683 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -101,6 +101,17 @@ config PHY_NXP_PTN3222
 	  schemes. It supports all three USB 2.0 data rates: Low Speed, Full
 	  Speed and High Speed.
 
+config PHY_GOOGLE_USB
+	tristate "Google Tensor SoC USB PHY driver"
+	depends on ARCH_GOOGLE || COMPILE_TEST
+	select GENERIC_PHY
+	help
+	  Enable support for the USB PHY on Google Tensor SoCs, starting with
+	  the G5 generation (Laguna). This driver provides the PHY interfaces
+	  to interact with the SNPS eUSB2 and USB 3.2/DisplayPort Combo PHY,
+	  both of which are integrated with the DWC3 USB DRD controller.
+	  This driver currently supports USB high-speed.
+
 source "drivers/phy/allwinner/Kconfig"
 source "drivers/phy/amlogic/Kconfig"
 source "drivers/phy/broadcom/Kconfig"
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index bfb27fb5a494283d7fd05dd670ebd1b12df8b1a1..aeaaaf988554a24bb572d8b34b54638a6a3aed73 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_PHY_SNPS_EUSB2)		+= phy-snps-eusb2.o
 obj-$(CONFIG_USB_LGM_PHY)		+= phy-lgm-usb.o
 obj-$(CONFIG_PHY_AIROHA_PCIE)		+= phy-airoha-pcie.o
 obj-$(CONFIG_PHY_NXP_PTN3222)		+= phy-nxp-ptn3222.o
+obj-$(CONFIG_PHY_GOOGLE_USB)		+= phy-google-usb.o
 obj-y					+= allwinner/	\
 					   amlogic/	\
 					   broadcom/	\
diff --git a/drivers/phy/phy-google-usb.c b/drivers/phy/phy-google-usb.c
new file mode 100644
index 0000000000000000000000000000000000000000..97e345fdab9b3679e7a76f6957ae3814ef3420e8
--- /dev/null
+++ b/drivers/phy/phy-google-usb.c
@@ -0,0 +1,295 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * phy-google-usb.c - Google USB PHY driver
+ *
+ * Copyright (C) 2025, Google LLC
+ */
+
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/usb/typec_mux.h>
+
+#define USBCS_USB2PHY_CFG19_OFFSET 0x0
+#define USBCS_USB2PHY_CFG19_PHY_CFG_PLL_FB_DIV GENMASK(19, 8)
+
+#define USBCS_USB2PHY_CFG21_OFFSET 0x8
+#define USBCS_USB2PHY_CFG21_PHY_ENABLE BIT(12)
+#define USBCS_USB2PHY_CFG21_REF_FREQ_SEL GENMASK(15, 13)
+#define USBCS_USB2PHY_CFG21_PHY_TX_DIG_BYPASS_SEL BIT(19)
+
+#define USBCS_PHY_CFG1_OFFSET 0x28
+#define USBCS_PHY_CFG1_SYS_VBUSVALID BIT(17)
+
+enum google_usb_phy_id {
+	GOOGLE_USB2_PHY,
+	GOOGLE_USB_PHY_NUM,
+};
+
+struct google_usb_phy_instance {
+	int index;
+	struct phy *phy;
+	int num_clks;
+	struct clk_bulk_data *clks;
+	int num_rsts;
+	struct reset_control_bulk_data *rsts;
+};
+
+struct google_usb_phy {
+	struct device *dev;
+	struct regmap *usb_cfg_regmap;
+	unsigned int usb2_cfg_offset;
+	void __iomem *usbdp_top_base;
+	struct google_usb_phy_instance insts[GOOGLE_USB_PHY_NUM];
+	/*
+	 * Protect phy registers from concurrent access, specifically via
+	 * google_usb_set_orientation callback.
+	 */
+	struct mutex phy_mutex;
+	struct typec_switch_dev *sw;
+	enum typec_orientation orientation;
+};
+
+static inline struct google_usb_phy *to_google_usb_phy(struct google_usb_phy_instance *inst)
+{
+	return container_of(inst, struct google_usb_phy, insts[inst->index]);
+}
+
+static void set_vbus_valid(struct google_usb_phy *gphy)
+{
+	u32 reg;
+
+	if (gphy->orientation == TYPEC_ORIENTATION_NONE) {
+		reg = readl(gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+		reg &= ~USBCS_PHY_CFG1_SYS_VBUSVALID;
+		writel(reg, gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+	} else {
+		reg = readl(gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+		reg |= USBCS_PHY_CFG1_SYS_VBUSVALID;
+		writel(reg, gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+	}
+}
+
+static int google_usb_set_orientation(struct typec_switch_dev *sw,
+				      enum typec_orientation orientation)
+{
+	struct google_usb_phy *gphy = typec_switch_get_drvdata(sw);
+
+	dev_dbg(gphy->dev, "set orientation %d\n", orientation);
+
+	gphy->orientation = orientation;
+
+	if (pm_runtime_suspended(gphy->dev))
+		return 0;
+
+	guard(mutex)(&gphy->phy_mutex);
+
+	set_vbus_valid(gphy);
+
+	return 0;
+}
+
+static int google_usb2_phy_init(struct phy *_phy)
+{
+	struct google_usb_phy_instance *inst = phy_get_drvdata(_phy);
+	struct google_usb_phy *gphy = to_google_usb_phy(inst);
+	u32 reg;
+	int ret = 0;
+
+	dev_dbg(gphy->dev, "initializing usb2 phy\n");
+
+	guard(mutex)(&gphy->phy_mutex);
+
+	regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, &reg);
+	reg &= ~USBCS_USB2PHY_CFG21_PHY_TX_DIG_BYPASS_SEL;
+	reg &= ~USBCS_USB2PHY_CFG21_REF_FREQ_SEL;
+	reg |= FIELD_PREP(USBCS_USB2PHY_CFG21_REF_FREQ_SEL, 0);
+	regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, reg);
+
+	regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG19_OFFSET, &reg);
+	reg &= ~USBCS_USB2PHY_CFG19_PHY_CFG_PLL_FB_DIV;
+	reg |= FIELD_PREP(USBCS_USB2PHY_CFG19_PHY_CFG_PLL_FB_DIV, 368);
+	regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG19_OFFSET, reg);
+
+	set_vbus_valid(gphy);
+
+	ret = clk_bulk_prepare_enable(inst->num_clks, inst->clks);
+	if (ret)
+		return ret;
+
+	ret = reset_control_bulk_deassert(inst->num_rsts, inst->rsts);
+	if (ret) {
+		clk_bulk_disable_unprepare(inst->num_clks, inst->clks);
+		return ret;
+	}
+
+	regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, &reg);
+	reg |= USBCS_USB2PHY_CFG21_PHY_ENABLE;
+	regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, reg);
+
+	return ret;
+}
+
+static int google_usb2_phy_exit(struct phy *_phy)
+{
+	struct google_usb_phy_instance *inst = phy_get_drvdata(_phy);
+	struct google_usb_phy *gphy = to_google_usb_phy(inst);
+	u32 reg;
+
+	dev_dbg(gphy->dev, "exiting usb2 phy\n");
+
+	guard(mutex)(&gphy->phy_mutex);
+
+	regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, &reg);
+	reg &= ~USBCS_USB2PHY_CFG21_PHY_ENABLE;
+	regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, reg);
+
+	reset_control_bulk_assert(inst->num_rsts, inst->rsts);
+	clk_bulk_disable_unprepare(inst->num_clks, inst->clks);
+
+	return 0;
+}
+
+static const struct phy_ops google_usb2_phy_ops = {
+	.init		= google_usb2_phy_init,
+	.exit		= google_usb2_phy_exit,
+};
+
+static struct phy *google_usb_phy_xlate(struct device *dev,
+					const struct of_phandle_args *args)
+{
+	struct google_usb_phy *gphy = dev_get_drvdata(dev);
+
+	if (args->args[0] >= GOOGLE_USB_PHY_NUM) {
+		dev_err(dev, "invalid PHY index requested from DT\n");
+		return ERR_PTR(-ENODEV);
+	}
+	return gphy->insts[args->args[0]].phy;
+}
+
+static int google_usb_phy_probe(struct platform_device *pdev)
+{
+	struct typec_switch_desc sw_desc = { };
+	struct google_usb_phy_instance *inst;
+	struct phy_provider *phy_provider;
+	struct device *dev = &pdev->dev;
+	struct google_usb_phy *gphy;
+	struct phy *phy;
+	u32 args[1];
+	int ret;
+
+	gphy = devm_kzalloc(dev, sizeof(*gphy), GFP_KERNEL);
+	if (!gphy)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, gphy);
+	gphy->dev = dev;
+
+	ret = devm_mutex_init(dev, &gphy->phy_mutex);
+	if (ret)
+		return ret;
+
+	gphy->usb_cfg_regmap =
+		syscon_regmap_lookup_by_phandle_args(dev->of_node,
+						     "google,usb-cfg-csr",
+						     ARRAY_SIZE(args), args);
+	if (IS_ERR(gphy->usb_cfg_regmap)) {
+		return dev_err_probe(dev, PTR_ERR(gphy->usb_cfg_regmap),
+				     "invalid usb cfg csr\n");
+	}
+
+	gphy->usb2_cfg_offset = args[0];
+
+	gphy->usbdp_top_base = devm_platform_ioremap_resource_byname(pdev,
+								     "usbdp_top");
+	if (IS_ERR(gphy->usbdp_top_base))
+		return dev_err_probe(dev, PTR_ERR(gphy->usbdp_top_base),
+				    "invalid usbdp top\n");
+
+	inst = &gphy->insts[GOOGLE_USB2_PHY];
+	inst->index = GOOGLE_USB2_PHY;
+	phy = devm_phy_create(dev, NULL, &google_usb2_phy_ops);
+	if (IS_ERR(phy))
+		return dev_err_probe(dev, PTR_ERR(phy),
+				     "failed to create usb2 phy instance\n");
+	inst->phy = phy;
+	phy_set_drvdata(phy, inst);
+
+	inst->num_clks = 2;
+	inst->clks = devm_kcalloc(dev, inst->num_clks, sizeof(*inst->clks), GFP_KERNEL);
+	if (!inst->clks)
+		return -ENOMEM;
+	inst->clks[0].id = "usb2";
+	inst->clks[1].id = "usb2_apb";
+	ret = devm_clk_bulk_get(dev, inst->num_clks, inst->clks);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to get u2 phy clks\n");
+
+	inst->num_rsts = 2;
+	inst->rsts = devm_kcalloc(dev, inst->num_rsts, sizeof(*inst->rsts), GFP_KERNEL);
+	if (!inst->rsts)
+		return -ENOMEM;
+	inst->rsts[0].id = "usb2";
+	inst->rsts[1].id = "usb2_apb";
+	ret = devm_reset_control_bulk_get_exclusive(dev, inst->num_rsts, inst->rsts);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to get u2 phy resets\n");
+
+	phy_provider = devm_of_phy_provider_register(dev, google_usb_phy_xlate);
+	if (IS_ERR(phy_provider))
+		return dev_err_probe(dev, PTR_ERR(phy_provider),
+				     "failed to register phy provider\n");
+
+	pm_runtime_enable(dev);
+
+	sw_desc.fwnode = dev_fwnode(dev);
+	sw_desc.drvdata = gphy;
+	sw_desc.name = fwnode_get_name(dev_fwnode(dev));
+	sw_desc.set = google_usb_set_orientation;
+
+	gphy->sw = typec_switch_register(dev, &sw_desc);
+	if (IS_ERR(gphy->sw))
+		return dev_err_probe(dev, PTR_ERR(gphy->sw),
+				     "failed to register typec switch\n");
+
+	return 0;
+}
+
+static void google_usb_phy_remove(struct platform_device *pdev)
+{
+	struct google_usb_phy *gphy = dev_get_drvdata(&pdev->dev);
+
+	typec_switch_unregister(gphy->sw);
+	pm_runtime_disable(&pdev->dev);
+}
+
+static const struct of_device_id google_usb_phy_of_match[] = {
+	{
+		.compatible = "google,lga-usb-phy",
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, google_usb_phy_of_match);
+
+static struct platform_driver google_usb_phy = {
+	.probe	= google_usb_phy_probe,
+	.remove = google_usb_phy_remove,
+	.driver = {
+		.name		= "google-usb-phy",
+		.of_match_table	= google_usb_phy_of_match,
+	}
+};
+
+module_platform_driver(google_usb_phy);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Google USB phy driver");

-- 
2.52.0.223.gf5cc29aaa4-goog



From royluo at google.com  Thu Dec  4 19:54:11 2025
From: royluo at google.com (Roy Luo)
Date: Fri, 05 Dec 2025 03:54:11 +0000
Subject: [PATCH v8 1/2] dt-bindings: phy: google: Add Google Tensor G5 USB PHY
In-Reply-To: <20251205-phyb4-v8-0-c59ea80a4458@google.com>
References: <20251205-phyb4-v8-0-c59ea80a4458@google.com>
Message-ID: <20251205-phyb4-v8-1-c59ea80a4458@google.com>

Document the device tree bindings for the USB PHY interfaces integrated
with the DWC3 controller on Google Tensor SoCs, starting with G5
generation (Laguna). The USB PHY on Tensor G5 includes two integrated
Synopsys PHY IPs: the eUSB 2.0 PHY IP and the USB 3.2/DisplayPort combo
PHY IP.

Due to a complete architectural overhaul in the Google Tensor G5, the
existing Samsung/Exynos USB PHY binding for older generations of Google
silicons such as gs101 are no longer compatible, necessitating this new
device tree binding.

Signed-off-by: Roy Luo <royluo at google.com>
---
 .../bindings/phy/google,lga-usb-phy.yaml           | 133 +++++++++++++++++++++
 MAINTAINERS                                        |   1 +
 2 files changed, 134 insertions(+)

diff --git a/Documentation/devicetree/bindings/phy/google,lga-usb-phy.yaml b/Documentation/devicetree/bindings/phy/google,lga-usb-phy.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..427e2e3425f645f40c0813e29d6efe4f62b20609
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/google,lga-usb-phy.yaml
@@ -0,0 +1,133 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2025, Google LLC
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/google,lga-usb-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Google Tensor Series G5 (Laguna) USB PHY
+
+maintainers:
+  - Roy Luo <royluo at google.com>
+
+description:
+  Describes the USB PHY interfaces integrated with the DWC3 USB controller on
+  Google Tensor SoCs, starting with the G5 generation (laguna).
+  Two specific PHY IPs from Synopsys are integrated, including eUSB 2.0 PHY IP
+  and USB3.2/DisplayPort combo PHY IP.
+
+properties:
+  compatible:
+    const: google,lga-usb-phy
+
+  reg:
+    items:
+      - description: USB3.2/DisplayPort combo PHY core registers.
+      - description: USB3.2/DisplayPort combo PHY Type-C Assist registers.
+      - description: eUSB 2.0 PHY core registers.
+      - description: Top-level wrapper registers for the integrated PHYs.
+
+  reg-names:
+    items:
+      - const: usb3_core
+      - const: usb3_tca
+      - const: usb2_core
+      - const: usbdp_top
+
+  "#phy-cells":
+    description: |
+      The phandle's argument in the PHY specifier selects one of the three
+      following PHY interfaces.
+      - 0 for USB high-speed.
+      - 1 for USB super-speed.
+      - 2 for DisplayPort.
+    const: 1
+
+  clocks:
+    items:
+      - description: USB2 PHY clock.
+      - description: USB2 PHY APB clock.
+      - description: USB3.2/DisplayPort combo PHY clock.
+      - description: USB3.2/DisplayPort combo PHY firmware clock.
+
+  clock-names:
+    items:
+      - const: usb2
+      - const: usb2_apb
+      - const: usb3
+      - const: usb3_fw
+
+  resets:
+    items:
+      - description: USB2 PHY reset.
+      - description: USB2 PHY APB reset.
+      - description: USB3.2/DisplayPort combo PHY reset.
+
+  reset-names:
+    items:
+      - const: usb2
+      - const: usb2_apb
+      - const: usb3
+
+  power-domains:
+    maxItems: 1
+
+  orientation-switch:
+    type: boolean
+    description:
+      Indicates the PHY as a handler of USB Type-C orientation changes
+
+  google,usb-cfg-csr:
+    description:
+      A phandle to a syscon node used to access the USB configuration
+      registers. These registers are the top-level wrapper of the USB
+      subsystem and provide control and status for the integrated USB
+      controller and USB PHY.
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    items:
+      - items:
+          - description: phandle to the syscon node.
+          - description: USB2 PHY configuration register offset.
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - "#phy-cells"
+  - clocks
+  - clock-names
+  - resets
+  - reset-names
+  - power-domains
+  - orientation-switch
+  - google,usb-cfg-csr
+
+additionalProperties: false
+
+examples:
+  - |
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        usb-phy at c410000 {
+            compatible = "google,lga-usb-phy";
+            reg = <0 0x0c410000 0 0x20000>,
+                  <0 0x0c430000 0 0x1000>,
+                  <0 0x0c440000 0 0x10000>,
+                  <0 0x0c637000 0 0xa0>;
+            reg-names = "usb3_core", "usb3_tca", "usb2_core", "usbdp_top";
+            #phy-cells = <1>;
+            clocks = <&hsion_usb2_phy_clk>, <&hsion_u2phy_apb_clk>,
+                     <&hsion_usb3_phy_clk>, <&hsion_usb3_phy_fw_clk>;
+            clock-names = "usb2", "usb2_apb", "usb3", "usb3_fw";
+            resets = <&hsion_resets_usb2_phy>,
+                     <&hsion_resets_u2phy_apb>,
+                     <&hsion_resets_usb3_phy>;
+            reset-names = "usb2", "usb2_apb", "usb3";
+            power-domains = <&hsio_n_usb_pd>;
+            orientation-switch;
+            google,usb-cfg-csr = <&usb_cfg_csr 0x14>;
+        };
+    };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 772af0072fff0921000c6fe27c018666c1579e48..27e6f9e20f5e83b861c6a04dededb93b8561715c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10661,6 +10661,7 @@ S:	Maintained
 P:	Documentation/process/maintainer-soc-clean-dts.rst
 C:	irc://irc.oftc.net/pixel6-kernel-dev
 F:	Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
+F:	Documentation/devicetree/bindings/phy/google,lga-usb-phy.yaml
 F:	Documentation/devicetree/bindings/soc/google/google,gs101-pmu-intr-gen.yaml
 F:	arch/arm64/boot/dts/exynos/google/
 F:	drivers/clk/samsung/clk-gs101.c

-- 
2.52.0.223.gf5cc29aaa4-goog



From anshuman.khandual at arm.com  Thu Dec  4 20:10:33 2025
From: anshuman.khandual at arm.com (Anshuman Khandual)
Date: Fri, 5 Dec 2025 09:40:33 +0530
Subject: [PATCH 06/19] coresight: trbe: Refactor syndrome decoding
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-6-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-6-7da32b076b28@arm.com>
Message-ID: <ae63c69c-eff9-4665-a9a6-d395e61bea86@arm.com>

On 01/12/25 4:51 PM, Leo Yan wrote:
> It gives priority to TRBSR_EL1.EA (external abort); an external abort
> will immediately bail out and return an error.

This is an abrupt starting for a commit message without giving context.
The rationale for the change needs to be explained rather than details
of implementation.

> 
> Next, the syndrome decoding is refactored based on two levels of
> information: the EC (Event Class) bits and the BSC (Trace Buffer Status
> Code) bits.
> 
> If TRBSR_EL1.EC==0b000000, the driver continues parsing TRBSR_EL1.BSC to
> identify the specific trace buffer event.  Otherwise, any non-zero
> TRBSR_EL1.EC is treated as an error.
> 
> For error cases, the driver prints an error string and dumps registers
> for debugging.
> 
> No additional checks are required for wrap mode beyond verifying the
> TRBSR_EL1.WRAP bit, even on units with overwrite errata, as this bit
> reliably indicates a buffer wrap.

Should the errata related changes be done in a separate patch instead ?

> 
> Signed-off-by: Leo Yan <leo.yan at arm.com>
> ---
>  drivers/hwtracing/coresight/coresight-trbe.c | 60 +++++++++++++++++++++-------
>  drivers/hwtracing/coresight/coresight-trbe.h |  8 ++--
>  2 files changed, 51 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
> index 9e565122816949b37b8ff5e4ba04cfbc317c6f25..28e2bfa68074f19ccaa4a737d00af577aea818fe 100644
> --- a/drivers/hwtracing/coresight/coresight-trbe.c
> +++ b/drivers/hwtracing/coresight/coresight-trbe.c
> @@ -643,29 +643,61 @@ static void trbe_enable_hw(struct trbe_buf *buf)
>  static enum trbe_fault_action trbe_get_fault_act(struct perf_output_handle *handle,
>  						 u64 trbsr)
>  {
> +	const char *err_str;
>  	int ec = get_trbe_ec(trbsr);
>  	int bsc = get_trbe_bsc(trbsr);
> -	struct trbe_buf *buf = etm_perf_sink_config(handle);
> -	struct trbe_cpudata *cpudata = buf->cpudata;
>  
>  	WARN_ON(is_trbe_running(trbsr));
> -	if (is_trbe_trg(trbsr) || is_trbe_abort(trbsr))
> -		return TRBE_FAULT_ACT_FATAL;
>  
> -	if ((ec == TRBE_EC_STAGE1_ABORT) || (ec == TRBE_EC_STAGE2_ABORT))
> -		return TRBE_FAULT_ACT_FATAL;
> +	if (is_trbe_abort(trbsr)) {
> +		err_str = "External abort";
> +		goto out_fatal;
> +	}
>  
> -	/*
> -	 * If the trbe is affected by TRBE_WORKAROUND_OVERWRITE_FILL_MODE,
> -	 * it might write data after a WRAP event in the fill mode.
> -	 * Thus the check TRBPTR == TRBBASER will not be honored.
> -	 */
> -	if ((is_trbe_wrap(trbsr) && (ec == TRBE_EC_OTHERS) && (bsc == TRBE_BSC_FILLED)) &&
> -	    (trbe_may_overwrite_in_fill_mode(cpudata) ||
> -	     get_trbe_write_pointer() == get_trbe_base_pointer()))
> +	switch (ec) {
> +	case TRBE_EC_OTHERS:
> +		break;

No message for this ?

> +	case TRBE_EC_BUF_MGMT_IMPL:
> +		err_str = "Unexpected implemented management";
> +		goto out_fatal;
> +	case TRBE_EC_GP_CHECK_FAULT:
> +		err_str = "Granule Protection Check fault";
> +		goto out_fatal;
> +	case TRBE_EC_STAGE1_ABORT:
> +		err_str = "Stage 1 data abort";
> +		goto out_fatal;
> +	case TRBE_EC_STAGE2_ABORT:
> +		err_str = "Stage 2 data abort";
> +		goto out_fatal;
> +	default:
> +		err_str = "Unknown error code";
> +		goto out_fatal;
> +	}
> +
> +	switch (bsc) {
> +	case TRBE_BSC_NOT_STOPPED:
> +		break;
> +	case TRBE_BSC_FILLED:
> +		break;
> +	case TRBE_BSC_TRIGGERED:
> +		err_str = "Unexpected trigger status";
> +		goto out_fatal;
> +	default:
> +		err_str = "Unexpected buffer status code";
> +		goto out_fatal;
> +	}

Just wondering if it would be cleaner to add a const char * based
static array mapping these EC/BSC codes with above error messages.
 
> +
> +	if (is_trbe_wrap(trbsr))

But what about TRBE affected with trbe_may_overwrite_in_fill_mode()
is that still being taken care of some how ?

>  		return TRBE_FAULT_ACT_WRAP;
>  
>  	return TRBE_FAULT_ACT_SPURIOUS;
> +
> +out_fatal:
> +	pr_err_ratelimited("%s on CPU %d [TRBSR=0x%016llx, TRBPTR=0x%016llx, TRBLIMITR=0x%016llx]\n",
> +			   err_str, smp_processor_id(), trbsr,
> +			   read_sysreg_s(SYS_TRBPTR_EL1),
> +			   read_sysreg_s(SYS_TRBLIMITR_EL1));

Right - comprehensive TRBE configuration register dump when a fatal
error happens.

> +	return TRBE_FAULT_ACT_FATAL;
>  }
>  
>  static unsigned long trbe_get_trace_size(struct perf_output_handle *handle,
> diff --git a/drivers/hwtracing/coresight/coresight-trbe.h b/drivers/hwtracing/coresight/coresight-trbe.h
> index 45202c48accec7c86ba56130e2737bc2d1830fae..d7f7cd763c0c7139cf322b7336ee563073e3bea0 100644
> --- a/drivers/hwtracing/coresight/coresight-trbe.h
> +++ b/drivers/hwtracing/coresight/coresight-trbe.h
> @@ -35,9 +35,11 @@ static inline bool is_trbe_enabled(void)
>  	return trblimitr & TRBLIMITR_EL1_E;
>  }
>  
> -#define TRBE_EC_OTHERS		0
> -#define TRBE_EC_STAGE1_ABORT	36
> -#define TRBE_EC_STAGE2_ABORT	37
> +#define TRBE_EC_OTHERS			0x0
> +#define TRBE_EC_GP_CHECK_FAULT		0X1e
> +#define TRBE_EC_BUF_MGMT_IMPL		0x1f
> +#define TRBE_EC_STAGE1_ABORT		0x24
> +#define TRBE_EC_STAGE2_ABORT		0x25

Please do mention the document source for these new EC codes in the
commit message.

>  
>  static inline int get_trbe_ec(u64 trbsr)
>  {
> 



From anshuman.khandual at arm.com  Thu Dec  4 20:28:02 2025
From: anshuman.khandual at arm.com (Anshuman Khandual)
Date: Fri, 5 Dec 2025 09:58:02 +0530
Subject: [PATCH 08/19] coresight: trbe: Use PERF_AUX_FLAG_PARTIAL instead
 of PERF_AUX_FLAG_COLLISION
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-8-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-8-7da32b076b28@arm.com>
Message-ID: <5f6bcd93-b565-4b10-9a2d-6851141e5dbe@arm.com>

On 01/12/25 4:51 PM, Leo Yan wrote:
> When tracing stops, there is no collision with other samples, so using
> PERF_AUX_FLAG_COLLISION does not accurately reflect the trace state and
> may mislead userspace.
> 
> Use PERF_AUX_FLAG_PARTIAL instead to indicate that tracing stopped and
> the record may contain gaps.
> 
> Signed-off-by: Leo Yan <leo.yan at arm.com>
> ---
>  drivers/hwtracing/coresight/coresight-trbe.c | 19 ++++++-------------
>  1 file changed, 6 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
> index b06885a08e082fd34f68d9588518807b5c47c86e..0caa4a6b437a3aa39fc6bcc72a23711b54f7c598 100644
> --- a/drivers/hwtracing/coresight/coresight-trbe.c
> +++ b/drivers/hwtracing/coresight/coresight-trbe.c
> @@ -669,21 +669,14 @@ static enum trbe_fault_action trbe_get_fault_act(struct perf_output_handle *hand
>  	}
>  
>  	/*
> -	 * Mark the buffer to indicate that there was a WRAP event by
> -	 * setting the COLLISION flag. This indicates to the user that
> -	 * the TRBE trace collection was stopped without stopping the
> -	 * ETE and thus there might be some amount of trace that was
> -	 * lost between the time the WRAP was detected and the IRQ
> -	 * was consumed by the CPU.
> -	 *
> -	 * Setting the TRUNCATED flag would move the event to STOPPED
> -	 * state unnecessarily, even when there is space left in the
> -	 * ring buffer. Using the COLLISION flag doesn't have this side
> -	 * effect. We only set TRUNCATED flag when there is no space
> -	 * left in the ring buffer.
> +	 * Mark the buffer to indicate that the trace is stopped by setting
> +	 * the PARTIAL flag. This indicates to the user that the TRBE trace
> +	 * collection was stopped without stopping the ETE and thus there
> +	 * might be some amount of trace that was lost between the time the
> +	 * TRBE event was detected and the IRQ was consumed by the CPU.
>  	 */
>  	if (!is_trbe_running(trbsr))
> -		perf_aux_output_flag(handle, PERF_AUX_FLAG_COLLISION);
> +		perf_aux_output_flag(handle, PERF_AUX_FLAG_PARTIAL);

This is interesting. So there is a no possibility for the records to be
overridden in the perf ring buffer and incomplete record is all that can
happen when TRBE is stopped, without stopping the ETE first ? Could both
of these scenarios might be possible as well ?

>  
>  	if (is_trbe_wrap(trbsr))
>  		return TRBE_FAULT_ACT_WRAP;
> 


From anshuman.khandual at arm.com  Thu Dec  4 20:48:11 2025
From: anshuman.khandual at arm.com (Anshuman Khandual)
Date: Fri, 5 Dec 2025 10:18:11 +0530
Subject: [PATCH 19/19] perf: cs-etm: Set watermark for AUX trace
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-19-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-19-7da32b076b28@arm.com>
Message-ID: <c22b084b-3853-405d-8b43-397786af7be9@arm.com>

On 01/12/25 4:52 PM, Leo Yan wrote:
> The default watermark is half of the total buffer size. In many cases,
> the tool can not be notified with sufficient free space, especially when
> profiling with small AUX buffer (e.g., 64KiB).

Could not smaller AUX buffer be prevented for TRBE instead ?

> > Setting watermark to quarter of the buffer to notifies the tool to read
> data earlier and prevents the data loss.
> 
> Signed-off-by: Leo Yan <leo.yan at arm.com>
> ---
>  tools/perf/arch/arm/util/cs-etm.c | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
> index ea891d12f8f40beebf8dee1d3db71cad701f5666..649b8b0d0f92b4af45fb97db9da3c5ccf24a978b 100644
> --- a/tools/perf/arch/arm/util/cs-etm.c
> +++ b/tools/perf/arch/arm/util/cs-etm.c
> @@ -424,6 +424,13 @@ static int cs_etm_recording_options(struct auxtrace_record *itr,
>  		pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME,
>  			  opts->auxtrace_snapshot_size);
>  
> +	if (!opts->auxtrace_snapshot_mode && !opts->auxtrace_sample_mode) {
> +		size_t aw = opts->auxtrace_mmap_pages * (size_t)page_size / 4;
> +		u32 aux_watermark = aw > UINT_MAX ? UINT_MAX : aw;
> +
> +		cs_etm_evsel->core.attr.aux_watermark = aux_watermark;
> +	}
> +
>  	/*
>  	 * To obtain the auxtrace buffer file descriptor, the auxtrace
>  	 * event must come first.
> 



From anshuman.khandual at arm.com  Thu Dec  4 20:53:54 2025
From: anshuman.khandual at arm.com (Anshuman Khandual)
Date: Fri, 5 Dec 2025 10:23:54 +0530
Subject: [PATCH 00/19] coresight: trbe: Support trigger and circle buffer
 modes
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
Message-ID: <ae9aacb1-29ae-4e05-ac55-0db555c3e455@arm.com>

On 01/12/25 4:51 PM, Leo Yan wrote:
> The current TRBE driver operates only in fill mode, where tracing stops
> at the top of buffer and a maintenance interrupt is raised.  Due to
> interrupt latency, tracing is halted while the program continues to run,
> resulting in trace data lose.
> 
> This series enhances the driver for the trigger mode to mitigate trace
> discontinuity.  The circle buffer mode is introduced to avoid any
> maintenance interrupts during the snapshot session.
> 
> It can be divided into three parts for easier review:
> 
>   Patches 01~05: Minor refactoring for disabling operations and
>                  clearing status.

Could these patches be posted first ?

>   Patches 06~12: Refactor fault action and trace size calculation.

Followed by this set which still keeps the existing functionality intact.

>   Patches 13~19: Support trigger and circle modes. To better utilize the
>                  new buffer modes, perf sets the watermark to
> 		 one-quarter of the buffer size.

Then finally all above changes which are newer functions and tests etc.

I guess that will be much easier to review.

> 
> This series is applied on coresight-next branch and has been validated
> on Orion O6 board:
> 
>   1) The trigger count and wrap mode are verified using Ftrace logs.
>   2) A new kunit test module verifies limit and count calculations.
>   3) Basic perf record / script commands and module load/unload have
>      been tested successfully.
> 
> Signed-off-by: Leo Yan <leo.yan at arm.com>
> ---
> Leo Yan (19):
>       coresight: trbe: Use helpers for checking errata
>       coresight: trbe: Remove redundant disable operation
>       coresight: trbe: Remove buffer disabling in trbe_handle_overflow()
>       coresight: trbe: Remove set_trbe_disabled() from the enable flow
>       coresight: trbe: Refactor status clearing
>       coresight: trbe: Refactor syndrome decoding
>       coresight: trbe: Refactor AUX flag setting
>       coresight: trbe: Use PERF_AUX_FLAG_PARTIAL instead of PERF_AUX_FLAG_COLLISION
>       coresight: trbe: Add fault action argument to trbe_handle_overflow()
>       coresight: trbe: Always check fault action when updating buffer
>       coresight: trbe: Apply overwrite erratum for only wrap event
>       coresight: trbe: Calculate size for buffer wrapping
>       coresight: trbe: Remove misleading comment
>       coresight: trbe: Refactor compute_trbe_buffer_limit()
>       coresight: trbe: Add static key for bypassing trigger mode
>       coresight: trbe: Support trigger mode
>       coresight: trbe: Enable circle mode for snapshot
>       coresight: trbe: Add kunit tests
>       perf: cs-etm: Set watermark for AUX trace
> 
>  drivers/hwtracing/coresight/Kconfig                |   9 +
>  drivers/hwtracing/coresight/Makefile               |   1 +
>  .../coresight/coresight-trbe-kunit-tests.c         | 536 +++++++++++++++++++++
>  drivers/hwtracing/coresight/coresight-trbe.c       | 440 +++++++++--------
>  drivers/hwtracing/coresight/coresight-trbe.h       | 111 ++++-
>  tools/perf/arch/arm/util/cs-etm.c                  |   7 +
>  6 files changed, 896 insertions(+), 208 deletions(-)
> ---
> base-commit: 9e9182cab5ebc3ee7544e60ef08ba19fdf216920
> change-id: 20251120-trbe_buffer_refactor_v1-1-8f8023105469
> 
> Best regards,



From yaoyuan at linux.alibaba.com  Thu Dec  4 22:02:50 2025
From: yaoyuan at linux.alibaba.com (Yao Yuan)
Date: Fri, 5 Dec 2025 14:02:50 +0800
Subject: [PATCH v3 6/9] KVM: arm64: Force trap of GMID_EL1 when the guest
 doesn't have MTE
In-Reply-To: <20251204094806.3846619-7-maz@kernel.org>
References: <20251204094806.3846619-1-maz@kernel.org>
 <20251204094806.3846619-7-maz@kernel.org>
Message-ID: <3v4gqr3eghu6gcruhhp2255pqq5s5nsaaowobaaqecpkp7an5v@vrntb3ggwecp>

Hi Marc,
On Thu, Dec 04, 2025 at 09:48:03AM +0800, Marc Zyngier wrote:
> If our host has MTE, but the guest doesn't, make sure we set HCR_EL2.TID5
> to force GMID_EL1 being trapped. Such trap will be handled by the
> FEAT_IDST handling.
>
> Reviewed-by: Joey Gouly <joey.gouly at arm.com>
> Signed-off-by: Marc Zyngier <maz at kernel.org>
> ---
>  arch/arm64/kvm/sys_regs.c | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index ae1e72df1ed45..2e94c423594eb 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -5558,6 +5558,8 @@ static void vcpu_set_hcr(struct kvm_vcpu *vcpu)
>
>  	if (kvm_has_mte(vcpu->kvm))
>  		vcpu->arch.hcr_el2 |= HCR_ATA;
> +	else
> +		vcpu->arch.hcr_el2 |= HCR_TID5;

Reviewed-by: Yuan Yao <yaoyuan at linux.alibaba.com>

>
>  	/*
>  	 * In the absence of FGT, we cannot independently trap TLBI
> --
> 2.47.3


From gregkh at linuxfoundation.org  Thu Dec  4 22:05:24 2025
From: gregkh at linuxfoundation.org (Greg Kroah-Hartman)
Date: Fri, 5 Dec 2025 07:05:24 +0100
Subject: [PATCH v9 2/2] usb: dwc3: Add Google Tensor SoC DWC3 glue driver
In-Reply-To: <20251205-controller-v9-2-9f158b18f979@google.com>
References: <20251205-controller-v9-0-9f158b18f979@google.com>
 <20251205-controller-v9-2-9f158b18f979@google.com>
Message-ID: <2025120553-suffrage-divisive-5890@gregkh>

On Fri, Dec 05, 2025 at 02:26:38AM +0000, Roy Luo wrote:
> +config USB_DWC3_GOOGLE
> +	tristate "Google Platform"
> +	depends on ARCH_GOOGLE || COMPILE_TEST

There is no ARCH_GOOGLE in the tree now, so how is this supposed to
work?  Shouldn't tools that check for "invalid config options" trigger
on this?

thanks,

greg k-h


From yaoyuan at linux.alibaba.com  Thu Dec  4 22:10:23 2025
From: yaoyuan at linux.alibaba.com (Yao Yuan)
Date: Fri, 5 Dec 2025 14:10:23 +0800
Subject: [PATCH v3 4/9] KVM: arm64: Handle FEAT_IDST for sysregs without
 specific handlers
In-Reply-To: <20251204094806.3846619-5-maz@kernel.org>
References: <20251204094806.3846619-1-maz@kernel.org>
 <20251204094806.3846619-5-maz@kernel.org>
Message-ID: <ibifd2p7fkwjmyfgfaerjdbzlmrabfdpepmn7zhure3s7k2aj7@wgqa7druilzt>

On Thu, Dec 04, 2025 at 09:48:01AM +0800, Marc Zyngier wrote:
> Add a bit of infrastrtcture to triage_sysreg_trap() to handle the
> case of registers falling into the Feature ID space that do not
> have a local handler.
>
> For these, we can directly apply the FEAT_IDST semantics and inject
> an EC=0x18 exception. Otherwise, an UNDEF will do.
>
> Signed-off-by: Marc Zyngier <maz at kernel.org>
> ---
>  arch/arm64/kvm/emulate-nested.c | 20 ++++++++++++++++++++
>  1 file changed, 20 insertions(+)
>
> diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c
> index 616eb6ad68701..fac2707221b47 100644
> --- a/arch/arm64/kvm/emulate-nested.c
> +++ b/arch/arm64/kvm/emulate-nested.c
> @@ -2588,6 +2588,26 @@ bool triage_sysreg_trap(struct kvm_vcpu *vcpu, int *sr_index)
>
>  		params = esr_sys64_to_params(esr);
>
> +		/*
> +		 * This implements the pseudocode UnimplementedIDRegister()
> +		 * helper for the purpose of fealing with FEAT_IDST.
> +		 *
> +		 * The Feature ID space is defined as the System register
> +		 * space in AArch64 with op0==3, op1=={0, 1, 3}, CRn==0,
> +		 * CRm=={0-7}, op2=={0-7}.
> +		 */
> +		if (params.Op0 == 3 &&
> +		    !(params.Op1 & 0b100) && params.Op1 != 2 &&
> +		    params.CRn == 0 &&
> +		    !(params.CRm & 0b1000)) {

Hi Marc,

May give a macro/inline function or local variable w/ name like "is_feat_id_space()"
can simplify the long comment here. Others LGTM:

Reviewed-by: Yuan Yao <yaoyuan at linux.alibaba.com>

> +			if (kvm_has_feat_enum(vcpu->kvm, ID_AA64MMFR2_EL1, IDS, IMP))
> +				kvm_inject_sync(vcpu, kvm_vcpu_get_esr(vcpu));
> +			else
> +				kvm_inject_undefined(vcpu);
> +
> +			return true;
> +		}
> +
>  		/*
>  		 * Check for the IMPDEF range, as per DDI0487 J.a,
>  		 * D18.3.2 Reserved encodings for IMPLEMENTATION
> --
> 2.47.3


From yang.yicong at picoheart.com  Thu Dec  4 22:12:33 2025
From: yang.yicong at picoheart.com (Yicong Yang)
Date: Fri, 5 Dec 2025 14:12:33 +0800
Subject: [PATCH v6 2/2] riscv: add HARDLOCKUP_DETECTOR_PERF support
In-Reply-To: <20251114033243.76509-3-cuiyunhui@bytedance.com>
References: <20251114033243.76509-1-cuiyunhui@bytedance.com> <20251114033243.76509-3-cuiyunhui@bytedance.com>
Message-ID: <96fd2a69-baf4-4109-8341-0d4bb6c60393@picoheart.com>

Hi Yunhui,

this has conflicts on the mainline master. looks like you have a dependency
on the SSE PMU support patchset [1], need to mention it for the maintainer
to apply.

[1] https://lore.kernel.org/linux-riscv/20250908181717.1997461-5-cleger at rivosinc.com/

one comment below.

On 2025/11/14 11:32, Yunhui Cui wrote:
> Enable the HARDLOCKUP_DETECTOR_PERF function based on RISC-V SSE.
> 
> Signed-off-by: Yunhui Cui <cuiyunhui at bytedance.com>
> Reviewed-by: Douglas Anderson <dianders at chromium.org>
> Acked-by: Paul Walmsley <pjw at kernel.org>
> ---
>  arch/riscv/Kconfig           |  3 +++
>  drivers/perf/riscv_pmu_sbi.c | 10 ++++++++++
>  2 files changed, 13 insertions(+)
> 
> diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
> index fadec20b87a8e..46ccd33732fa8 100644
> --- a/arch/riscv/Kconfig
> +++ b/arch/riscv/Kconfig
> @@ -186,6 +186,9 @@ config RISCV
>  	select HAVE_PAGE_SIZE_4KB
>  	select HAVE_PCI
>  	select HAVE_PERF_EVENTS
> +	select HAVE_PERF_EVENTS_NMI if RISCV_PMU_SBI_SSE
> +	select HAVE_HARDLOCKUP_DETECTOR_PERF if PERF_EVENTS && HAVE_PERF_EVENTS_NMI
> +	select WATCHDOG_PERF_ADJUST_PERIOD if HARDLOCKUP_DETECTOR_PERF
>  	select HAVE_PERF_REGS
>  	select HAVE_PERF_USER_STACK_DUMP
>  	select HAVE_POSIX_CPU_TIMERS_TASK_WORK
> diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
> index c852f64a50221..0c7c5924687c9 100644
> --- a/drivers/perf/riscv_pmu_sbi.c
> +++ b/drivers/perf/riscv_pmu_sbi.c
> @@ -22,6 +22,7 @@
>  #include <linux/sched/clock.h>
>  #include <linux/soc/andes/irq.h>
>  #include <linux/workqueue.h>
> +#include <linux/nmi.h>
>  
>  #include <asm/errata_list.h>
>  #include <asm/sbi.h>
> @@ -1192,6 +1193,13 @@ static int pmu_sbi_setup_sse(struct riscv_pmu *pmu)
>  }
>  #endif
>  
> +#ifdef CONFIG_HARDLOCKUP_DETECTOR_PERF
> +bool arch_perf_nmi_is_available(void)
> +{
> +	return IS_ENABLED(CONFIG_RISCV_PMU_SBI_SSE);

this looks incorrect per implementation in [1]. we'll fallback to the normal
interrupt if failed to register the SSE event, in which case NMI is not
available for the PMU. Check the kconfig is not sufficient.

you can check pmu->sse_evt instead for the NMI support here, or cached the
NMI status somewhere like how arm_pmu does.

Thanks.

> +}
> +#endif
> +
>  static int pmu_sbi_starting_cpu(unsigned int cpu, struct hlist_node *node)
>  {
>  	struct riscv_pmu *pmu = hlist_entry_safe(node, struct riscv_pmu, node);
> @@ -1618,6 +1626,8 @@ static int __init pmu_sbi_devinit(void)
>  	/* Notify legacy implementation that SBI pmu is available*/
>  	riscv_pmu_legacy_skip_init();
>  
> +	lockup_detector_retry_init();
> +
>  	return ret;
>  }
>  device_initcall(pmu_sbi_devinit)


From anshuld at ti.com  Thu Dec  4 22:15:43 2025
From: anshuld at ti.com (Anshul Dalal)
Date: Fri, 5 Dec 2025 11:45:43 +0530
Subject: [PATCH v4] dt-bindings: arm: keystone: add boot_* mboxes to ti,sci
Message-ID: <20251205-k3_syscon_add_boot_mailboxes-v4-1-8e216fb88941@ti.com>

The bootloader on K3 devices makes use of mailboxes as per the ROM spec
which might be different than one's available to the kernel (firmware
spec).

Therefore, this patch adds the missing mailbox entries to the DT binding
if the matching compatible is ti,am654-sci to represent the mailboxes
exposed by the hardware during boot for the purpose of loading the
firmware.

Signed-off-by: Anshul Dalal <anshuld at ti.com>
---
Changes in v4:
- Make new boot_* mboxes conditional on ti,am654-sci compatible
- Link to v3: https://lore.kernel.org/r/20251112-k3_syscon_add_boot_mailboxes-v3-1-66155a4236dc at ti.com

Changes in v3:
- Drop [1/2] of the last patch series
- Update existing example with boot_* mailboxes instead of adding a new one
- Link to v2: https://lore.kernel.org/r/20251112-k3_syscon_add_boot_mailboxes-v2-0-aebc1e47b391 at ti.com

Changes in v2:
- Remove maxItems entry
- Remove RFC tag from patch (added by mistake in v1)
- Document the new mailboxes in mboxes instead of mbox-names
- Provide example with all the mailboxes set
- Update commit title to have "ti,sci"
- Split into two patches
- Link to v1: https://lore.kernel.org/r/20251111-k3_syscon_add_boot_mailboxes-v1-1-529a27f21076 at ti.com
---
 .../devicetree/bindings/arm/keystone/ti,sci.yaml   | 50 +++++++++++++++++++---
 1 file changed, 43 insertions(+), 7 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
index 25a2b42105e5..d9eb2a81e539 100644
--- a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
+++ b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
@@ -51,15 +51,15 @@ properties:
     minItems: 1
 
   mbox-names:
+    minItems: 2
+    maxItems: 6
     description: |
       Specifies the mailboxes used to communicate with TI-SCI Controller
       made available from TI-SCI controller.
-    items:
-      - const: rx
-      - const: tx
 
   mboxes:
     minItems: 2
+    maxItems: 6
 
   ti,host-id:
     $ref: /schemas/types.yaml#/definitions/uint32
@@ -79,6 +79,42 @@ properties:
     type: object
     $ref: /schemas/reset/ti,sci-reset.yaml#
 
+if:
+  properties:
+    compatible:
+      contains:
+        const: ti,am654-sci
+then:
+  properties:
+    mbox-names:
+      minItems: 2
+      items:
+        - const: rx
+        - const: tx
+        - const: notify
+        - const: boot_rx
+        - const: boot_tx
+        - const: boot_notify
+    mboxes:
+      minItems: 2
+      items:
+        - description: RX thread
+        - description: TX thread
+        - description: Notify thread
+        - description: boot stage RX thread
+        - description: boot stage TX thread
+        - description: boot stage Notify thread
+else:
+  properties:
+    mbox-names:
+      items:
+        - const: rx
+        - const: tx
+    mboxes:
+      items:
+        - description: RX thread
+        - description: TX thread
+
 required:
   - compatible
   - mbox-names
@@ -99,11 +135,11 @@ examples:
 
   - |
     dmsc: system-controller at 44083000 {
-      compatible = "ti,k2g-sci";
+      compatible = "ti,am654-sci";
       ti,host-id = <12>;
-      mbox-names = "rx", "tx";
-      mboxes = <&secure_proxy_main 11>,
-               <&secure_proxy_main 13>;
+      mbox-names = "rx", "tx", "notify", "boot_rx", "boot_tx";
+      mboxes= <&secure_proxy_mcu 6>, <&secure_proxy_mcu 8>,
+        <&secure_proxy_mcu 5>, <&secure_proxy_mcu 5>, <&secure_proxy_mcu 4>;
       reg-names = "debug_messages";
       reg = <0x44083000 0x1000>;
 

---
base-commit: 4427259cc7f7571a157fbc9b5011e1ef6fe0a4a8
change-id: 20251105-k3_syscon_add_boot_mailboxes-8452bdd98962

Best regards,
-- 
Anshul Dalal <anshuld at ti.com>



From amhetre at nvidia.com  Thu Dec  4 22:15:28 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Fri, 5 Dec 2025 11:45:28 +0530
Subject: [PATCH V3 1/3] iommu/arm-smmu-v3: Add device-tree support for
 CMDQV driver
In-Reply-To: <a917aded-4404-4b63-8d2c-96aa8b84f81f@arm.com>
References: <20251201163219.3237266-2-amhetre@nvidia.com>
 <202512031601.IpliwbHW-lkp@intel.com>
 <47684b91-7c0f-4260-abfd-2795fdaa2b31@nvidia.com>
 <a917aded-4404-4b63-8d2c-96aa8b84f81f@arm.com>
Message-ID: <3be111a4-faa8-4a30-8638-d8e8db0f365d@nvidia.com>


On 12/3/2025 9:19 PM, Robin Murphy wrote:
> External email: Use caution opening links or attachments
>
>
> On 2025-12-03 11:04 am, Ashish Mhetre wrote:
>>
>> On 12/3/2025 2:05 PM, kernel test robot wrote:
>>> External email: Use caution opening links or attachments
>>>
>>>
>>> Hi Ashish,
>>>
>>> kernel test robot noticed the following build errors:
>>>
>>> [auto build test ERROR on next-20251201]
>>> [also build test ERROR on v6.18]
>>> [cannot apply to robh/for-next linus/master v6.18 v6.18-rc7 v6.18-rc6]
>>> [If your patch is applied to the wrong git tree, kindly drop us a note.
>>> And when submitting patch, we suggest to use '--base' as documented in
>>> https://git-scm.com/docs/git-format-patch#_base_tree_information]
>>>
>>> url: https://github.com/intel-lab-lkp/linux/commits/Ashish-Mhetre/
>>> iommu-arm-smmu-v3-Add-device-tree-support-for-CMDQV-
>>> driver/20251202-003517
>>> base:?? next-20251201
>>> patch link: https://lore.kernel.org/r/20251201163219.3237266-2-
>>> amhetre%40nvidia.com
>>> patch subject: [PATCH V3 1/3] iommu/arm-smmu-v3: Add device-tree
>>> support for CMDQV driver
>>> config: arm64-allmodconfig (https://download.01.org/0day-ci/
>>> archive/20251203/202512031601.IpliwbHW-lkp at intel.com/config)
>>> compiler: clang version 19.1.7 (https://github.com/llvm/llvm-project
>>> cd708029e0b2869e80abe31ddb175f7c35361f90)
>>> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/
>>> archive/20251203/202512031601.IpliwbHW-lkp at intel.com/reproduce)
>>>
>>> If you fix the issue in a separate patch/commit (i.e. not just a new
>>> version of
>>> the same patch/commit), kindly add following tags
>>> | Reported-by: kernel test robot <lkp at intel.com>
>>> | Closes: https://lore.kernel.org/oe-kbuild-all/202512031601.IpliwbHW-
>>> lkp at intel.com/
>>>
>>> All errors (new ones prefixed by >>):
>>>
>>>>> ld.lld: error: duplicate symbol: init_module
>>> ??? >>> defined at arm-smmu-v3.c
>>> ??? >>> drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.o:
>>> (init_module)
>>> ??? >>> defined at tegra241-cmdqv.c
>>> ??? >>> drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.o:
>>> (.init.text+0x4)
>>> -- 
>>>>> ld.lld: error: duplicate symbol: cleanup_module
>>> ??? >>> defined at arm-smmu-v3.c
>>> ??? >>> drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.o:
>>> (cleanup_module)
>>> ??? >>> defined at tegra241-cmdqv.c
>>> ??? >>> drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.o:
>>> (.exit.text+0x4)
>>
>> Hi Nic, Robin,
>>
>> How do you suggest fixing this? Is it fine to compile tegra241-cmdqv as
>> separate module
>> and export tegra241_cmdqv_probe() to fix this warning?
>
> As Jon just pointed out, the issue is using module_platform_driver(),
> which is unnecessary anyway since this is not a driver; nor is it even a
> module, it's just some extra code that can be included in the
> arm_smmu_v3 driver, and will be integral to the arm_smmu_v3.ko module if
> built as a such.
>
> You could sanity-check the compatible of the phandle target in
> tegra_cmdqv_dt_probe() if you feel like you should do more than just
> blindly trust the DT, but either way trying to register a dummy platform
> driver that won't bind to anything is pointless.
>

Thanks for the pointers Jon, Robin. I agree that this part of code is
redundant and can be removed. I will make these changes in next version.

>> I am using GCC compiler and was not able to reproduce this with W=1 
>> build.
>
> This will be happening with CONFIG_ARM_SMMU_V3=m.
>
> Thanks,
> Robin.
>
>>
>> Thanks,
>> Ashish Mhetre
>>
>>> -- 
>>> 0-DAY CI Kernel Test Service
>>> https://github.com/intel/lkp-tests/wiki
>


From yaoyuan at linux.alibaba.com  Thu Dec  4 22:25:07 2025
From: yaoyuan at linux.alibaba.com (Yao Yuan)
Date: Fri, 5 Dec 2025 14:25:07 +0800
Subject: [PATCH v3 5/9] KVM: arm64: Handle CSSIDR2_EL1 and SMIDR_EL1 in a
 generic way
In-Reply-To: <20251204094806.3846619-6-maz@kernel.org>
References: <20251204094806.3846619-1-maz@kernel.org>
 <20251204094806.3846619-6-maz@kernel.org>
Message-ID: <csa7ttcducyjm5z7tdnw7kimry7obkhflo4zknenw267b3shlp@t37ltcp6flps>

On Thu, Dec 04, 2025 at 09:48:02AM +0800, Marc Zyngier wrote:
> Now that we can handle ID registers using the FEAT_IDST infrastrcuture,
> get rid of the handling of CSSIDR2_EL1 and SMIDR_EL1.
>
> Signed-off-by: Marc Zyngier <maz at kernel.org>
> ---
>  arch/arm64/kvm/sys_regs.c | 2 --
>  1 file changed, 2 deletions(-)
>
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index ec3fbe0b8d525..ae1e72df1ed45 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -3399,8 +3399,6 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>  	{ SYS_DESC(SYS_CCSIDR_EL1), access_ccsidr },
>  	{ SYS_DESC(SYS_CLIDR_EL1), access_clidr, reset_clidr, CLIDR_EL1,
>  	  .set_user = set_clidr, .val = ~CLIDR_EL1_RES0 },
> -	{ SYS_DESC(SYS_CCSIDR2_EL1), undef_access },
> -	{ SYS_DESC(SYS_SMIDR_EL1), undef_access },
Hi Marc,

I checked the arm ARM to make sure these 2 belong to ID space.

Reviewed-by: Yuan Yao <yaoyuan at linux.alibaba.com>

>  	IMPLEMENTATION_ID(AIDR_EL1, GENMASK_ULL(63, 0)),
>  	{ SYS_DESC(SYS_CSSELR_EL1), access_csselr, reset_unknown, CSSELR_EL1 },
>  	ID_FILTERED(CTR_EL0, ctr_el0,
> --
> 2.47.3


From ot_zexin.wang at mediatek.com  Thu Dec  4 22:33:54 2025
From: ot_zexin.wang at mediatek.com (Zexin Wang)
Date: Fri, 5 Dec 2025 14:33:54 +0800
Subject: [PATCH] reset-controller: ti: introduce a new reset handler
Message-ID: <20251205063356.13515-1-ot_zexin.wang@mediatek.com>

Introduce ti_syscon_reset() to integrate assert and deassert together.
If some modules need do serialized assert and deassert operations
to reset itself, reset_control_reset can be called for convenience.

Signed-off-by: Zexin Wang <ot_zexin.wang at mediatek.com>
---
 drivers/reset/reset-ti-syscon.c | 34 +++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/drivers/reset/reset-ti-syscon.c b/drivers/reset/reset-ti-syscon.c
index 23f86ddb8668..f37685e32b0a 100644
--- a/drivers/reset/reset-ti-syscon.c
+++ b/drivers/reset/reset-ti-syscon.c
@@ -7,6 +7,7 @@
  *	Suman Anna <afd at ti.com>
  */
 
+#include <linux/delay.h>
 #include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of.h>
@@ -42,12 +43,14 @@ struct ti_syscon_reset_control {
  * @regmap: regmap handle containing the memory-mapped reset registers
  * @controls: array of reset controls
  * @nr_controls: number of controls in control array
+ * @reset_duration_us: time of controller assert reset
  */
 struct ti_syscon_reset_data {
 	struct reset_controller_dev rcdev;
 	struct regmap *regmap;
 	struct ti_syscon_reset_control *controls;
 	unsigned int nr_controls;
+	unsigned int reset_duration_us;
 };
 
 #define to_ti_syscon_reset_data(_rcdev)	\
@@ -150,9 +153,37 @@ static int ti_syscon_reset_status(struct reset_controller_dev *rcdev,
 		!(control->flags & STATUS_SET);
 }
 
+/**
+ * ti_syscon_reset() - perform a full reset cycle on a device
+ * @rcdev: reset controller entity
+ * @id: ID of the reset to be asserted and deasserted
+ *
+ * This function performs a full reset cycle by asserting and then
+ * deasserting the reset signal for a device. It ensures the device
+ * is properly reset and ready for operation.
+ *
+ * Return: 0 for successful request, else a corresponding error value
+ */
+static int ti_syscon_reset(struct reset_controller_dev *rcdev,
+		   unsigned long id)
+{
+	struct ti_syscon_reset_data *data = to_ti_syscon_reset_data(rcdev);
+	int ret;
+
+	ret = ti_syscon_reset_assert(rcdev, id);
+	if (ret)
+		return ret;
+
+	if (data->reset_duration_us)
+		usleep_range(data->reset_duration_us, data->reset_duration_us * 2);
+
+	return ti_syscon_reset_deassert(rcdev, id);
+}
+
 static const struct reset_control_ops ti_syscon_reset_ops = {
 	.assert		= ti_syscon_reset_assert,
 	.deassert	= ti_syscon_reset_deassert,
+	.reset		= ti_syscon_reset,
 	.status		= ti_syscon_reset_status,
 };
 
@@ -196,6 +227,9 @@ static int ti_syscon_reset_probe(struct platform_device *pdev)
 		controls[i].flags = be32_to_cpup(list++);
 	}
 
+	of_property_read_u32(pdev->dev.of_node, "reset-duration-us",
+			     &data->reset_duration_us);
+
 	data->rcdev.ops = &ti_syscon_reset_ops;
 	data->rcdev.owner = THIS_MODULE;
 	data->rcdev.of_node = np;
-- 
2.45.2



From ot_cathy.xu at mediatek.com  Thu Dec  4 22:43:35 2025
From: ot_cathy.xu at mediatek.com (Cathy Xu)
Date: Fri, 5 Dec 2025 14:43:35 +0800
Subject: [PATCH v2] arm64: dts: mediatek: mt8189: Add pinmux macro header file
Message-ID: <20251205064357.13591-1-ot_cathy.xu@mediatek.com>

Add the pinctrl header file on MediaTek mt8189.

Signed-off-by: Cathy Xu <ot_cathy.xu at mediatek.com>
---
This patch is base on the patch series:
https://patchwork.kernel.org/project/linux-mediatek/list/?series=981475
[1] dt-bindings: pinctrl: mediatek: Add support for mt8189
[2] arm64: dts: mediatek: mt8189: Add pinmux macro header file
[3] pinctrl: mediatek: Add pinctrl driver on mt8189
Since patch [1] and [3] of the series have already been merged, this
patch(patch [2]) is being resent individually after modifications.
---
 arch/arm64/boot/dts/mediatek/mt8189-pinfunc.h | 1125 +++++++++++++++++
 1 file changed, 1125 insertions(+)
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8189-pinfunc.h

diff --git a/arch/arm64/boot/dts/mediatek/mt8189-pinfunc.h b/arch/arm64/boot/dts/mediatek/mt8189-pinfunc.h
new file mode 100644
index 000000000000..df69f50c267a
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8189-pinfunc.h
@@ -0,0 +1,1125 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
+/*
+ * Copyright (C) 2025 MediaTek Inc.
+ * Author: Lei Xue <lei.xue at mediatek.com>
+ *         Cathy Xu <ot_cathy.xu at mediatek.com>
+ */
+
+#ifndef __MT8189_PINFUNC_H
+#define __MT8189_PINFUNC_H
+
+#include <dt-bindings/pinctrl/mt65xx.h>
+
+#define PINMUX_GPIO0__FUNC_GPIO0 (MTK_PIN_NO(0) | 0)
+#define PINMUX_GPIO0__FUNC_TP_GPIO0_AO (MTK_PIN_NO(0) | 1)
+#define PINMUX_GPIO0__FUNC_SPIM3_A_CSB (MTK_PIN_NO(0) | 2)
+#define PINMUX_GPIO0__FUNC_I2SOUT0_MCK (MTK_PIN_NO(0) | 3)
+#define PINMUX_GPIO0__FUNC_SCP_SPI0_CS (MTK_PIN_NO(0) | 4)
+#define PINMUX_GPIO0__FUNC_CONN_BPI_BUS6 (MTK_PIN_NO(0) | 6)
+#define PINMUX_GPIO0__FUNC_DBG_MON_A0 (MTK_PIN_NO(0) | 7)
+
+#define PINMUX_GPIO1__FUNC_GPIO1 (MTK_PIN_NO(1) | 0)
+#define PINMUX_GPIO1__FUNC_TP_GPIO1_AO (MTK_PIN_NO(1) | 1)
+#define PINMUX_GPIO1__FUNC_SPIM3_A_CLK (MTK_PIN_NO(1) | 2)
+#define PINMUX_GPIO1__FUNC_I2SOUT0_BCK (MTK_PIN_NO(1) | 3)
+#define PINMUX_GPIO1__FUNC_SCP_SPI0_CK (MTK_PIN_NO(1) | 4)
+#define PINMUX_GPIO1__FUNC_CONN_BPI_BUS7 (MTK_PIN_NO(1) | 6)
+#define PINMUX_GPIO1__FUNC_DBG_MON_A1 (MTK_PIN_NO(1) | 7)
+
+#define PINMUX_GPIO2__FUNC_GPIO2 (MTK_PIN_NO(2) | 0)
+#define PINMUX_GPIO2__FUNC_TP_GPIO2_AO (MTK_PIN_NO(2) | 1)
+#define PINMUX_GPIO2__FUNC_SPIM3_A_MO (MTK_PIN_NO(2) | 2)
+#define PINMUX_GPIO2__FUNC_I2SOUT0_LRCK (MTK_PIN_NO(2) | 3)
+#define PINMUX_GPIO2__FUNC_SCP_SPI0_MO (MTK_PIN_NO(2) | 4)
+#define PINMUX_GPIO2__FUNC_CONN_BPI_BUS8 (MTK_PIN_NO(2) | 6)
+#define PINMUX_GPIO2__FUNC_DBG_MON_A2 (MTK_PIN_NO(2) | 7)
+
+#define PINMUX_GPIO3__FUNC_GPIO3 (MTK_PIN_NO(3) | 0)
+#define PINMUX_GPIO3__FUNC_TP_GPIO3_AO (MTK_PIN_NO(3) | 1)
+#define PINMUX_GPIO3__FUNC_SPIM3_A_MI (MTK_PIN_NO(3) | 2)
+#define PINMUX_GPIO3__FUNC_I2SOUT0_DO (MTK_PIN_NO(3) | 3)
+#define PINMUX_GPIO3__FUNC_SCP_SPI0_MI (MTK_PIN_NO(3) | 4)
+#define PINMUX_GPIO3__FUNC_CONN_BPI_BUS9 (MTK_PIN_NO(3) | 6)
+#define PINMUX_GPIO3__FUNC_DBG_MON_A3 (MTK_PIN_NO(3) | 7)
+
+#define PINMUX_GPIO4__FUNC_GPIO4 (MTK_PIN_NO(4) | 0)
+#define PINMUX_GPIO4__FUNC_TP_GPIO4_AO (MTK_PIN_NO(4) | 1)
+#define PINMUX_GPIO4__FUNC_SPIM4_A_CSB (MTK_PIN_NO(4) | 2)
+#define PINMUX_GPIO4__FUNC_I2SIN0_DI (MTK_PIN_NO(4) | 3)
+#define PINMUX_GPIO4__FUNC_SCP_SPI1_CS (MTK_PIN_NO(4) | 4)
+#define PINMUX_GPIO4__FUNC_CONN_BPI_BUS10 (MTK_PIN_NO(4) | 6)
+#define PINMUX_GPIO4__FUNC_DBG_MON_A4 (MTK_PIN_NO(4) | 7)
+
+#define PINMUX_GPIO5__FUNC_GPIO5 (MTK_PIN_NO(5) | 0)
+#define PINMUX_GPIO5__FUNC_TP_GPIO5_AO (MTK_PIN_NO(5) | 1)
+#define PINMUX_GPIO5__FUNC_SPIM4_A_CLK (MTK_PIN_NO(5) | 2)
+#define PINMUX_GPIO5__FUNC_I2SIN0_BCK (MTK_PIN_NO(5) | 3)
+#define PINMUX_GPIO5__FUNC_SCP_SPI1_CK (MTK_PIN_NO(5) | 4)
+#define PINMUX_GPIO5__FUNC_CONN_BPI_BUS11_OLAT0 (MTK_PIN_NO(5) | 6)
+#define PINMUX_GPIO5__FUNC_DBG_MON_A5 (MTK_PIN_NO(5) | 7)
+
+#define PINMUX_GPIO6__FUNC_GPIO6 (MTK_PIN_NO(6) | 0)
+#define PINMUX_GPIO6__FUNC_TP_GPIO6_AO (MTK_PIN_NO(6) | 1)
+#define PINMUX_GPIO6__FUNC_SPIM4_A_MO (MTK_PIN_NO(6) | 2)
+#define PINMUX_GPIO6__FUNC_I2SIN0_LRCK (MTK_PIN_NO(6) | 3)
+#define PINMUX_GPIO6__FUNC_SCP_SPI1_MO (MTK_PIN_NO(6) | 4)
+#define PINMUX_GPIO6__FUNC_CONN_BPI_BUS12_OLAT1 (MTK_PIN_NO(6) | 6)
+#define PINMUX_GPIO6__FUNC_DBG_MON_A6 (MTK_PIN_NO(6) | 7)
+
+#define PINMUX_GPIO7__FUNC_GPIO7 (MTK_PIN_NO(7) | 0)
+#define PINMUX_GPIO7__FUNC_TP_GPIO7_AO (MTK_PIN_NO(7) | 1)
+#define PINMUX_GPIO7__FUNC_SPIM4_A_MI (MTK_PIN_NO(7) | 2)
+#define PINMUX_GPIO7__FUNC_I2SIN0_MCK (MTK_PIN_NO(7) | 3)
+#define PINMUX_GPIO7__FUNC_SCP_SPI1_MI (MTK_PIN_NO(7) | 4)
+#define PINMUX_GPIO7__FUNC_CONN_BPI_BUS13_OLAT2 (MTK_PIN_NO(7) | 6)
+#define PINMUX_GPIO7__FUNC_DBG_MON_A7 (MTK_PIN_NO(7) | 7)
+
+#define PINMUX_GPIO8__FUNC_GPIO8 (MTK_PIN_NO(8) | 0)
+#define PINMUX_GPIO8__FUNC_TP_UTXD1_VLP (MTK_PIN_NO(8) | 1)
+#define PINMUX_GPIO8__FUNC_SPIM5_A_CSB (MTK_PIN_NO(8) | 2)
+#define PINMUX_GPIO8__FUNC_I2SOUT1_MCK (MTK_PIN_NO(8) | 3)
+#define PINMUX_GPIO8__FUNC_VADSP_UTXD0 (MTK_PIN_NO(8) | 4)
+#define PINMUX_GPIO8__FUNC_CONN_BPI_BUS14_OLAT3 (MTK_PIN_NO(8) | 6)
+#define PINMUX_GPIO8__FUNC_DBG_MON_A8 (MTK_PIN_NO(8) | 7)
+
+#define PINMUX_GPIO9__FUNC_GPIO9 (MTK_PIN_NO(9) | 0)
+#define PINMUX_GPIO9__FUNC_TP_URXD1_VLP (MTK_PIN_NO(9) | 1)
+#define PINMUX_GPIO9__FUNC_SPIM5_A_CLK (MTK_PIN_NO(9) | 2)
+#define PINMUX_GPIO9__FUNC_I2SOUT1_BCK (MTK_PIN_NO(9) | 3)
+#define PINMUX_GPIO9__FUNC_VADSP_URXD0 (MTK_PIN_NO(9) | 4)
+#define PINMUX_GPIO9__FUNC_CONN_BPI_BUS15_OLAT4 (MTK_PIN_NO(9) | 6)
+#define PINMUX_GPIO9__FUNC_DBG_MON_A9 (MTK_PIN_NO(9) | 7)
+
+#define PINMUX_GPIO10__FUNC_GPIO10 (MTK_PIN_NO(10) | 0)
+#define PINMUX_GPIO10__FUNC_TP_UCTS1_VLP (MTK_PIN_NO(10) | 1)
+#define PINMUX_GPIO10__FUNC_SPIM5_A_MO (MTK_PIN_NO(10) | 2)
+#define PINMUX_GPIO10__FUNC_I2SOUT1_LRCK (MTK_PIN_NO(10) | 3)
+#define PINMUX_GPIO10__FUNC_SRCLKENAI0 (MTK_PIN_NO(10) | 4)
+#define PINMUX_GPIO10__FUNC_CONN_BPI_BUS16_OLAT5 (MTK_PIN_NO(10) | 6)
+#define PINMUX_GPIO10__FUNC_DBG_MON_A10 (MTK_PIN_NO(10) | 7)
+
+#define PINMUX_GPIO11__FUNC_GPIO11 (MTK_PIN_NO(11) | 0)
+#define PINMUX_GPIO11__FUNC_TP_URTS1_VLP (MTK_PIN_NO(11) | 1)
+#define PINMUX_GPIO11__FUNC_SPIM5_A_MI (MTK_PIN_NO(11) | 2)
+#define PINMUX_GPIO11__FUNC_I2SOUT1_DO (MTK_PIN_NO(11) | 3)
+#define PINMUX_GPIO11__FUNC_SRCLKENAI1 (MTK_PIN_NO(11) | 4)
+#define PINMUX_GPIO11__FUNC_PWM_vlp (MTK_PIN_NO(11) | 5)
+#define PINMUX_GPIO11__FUNC_DBG_MON_A11 (MTK_PIN_NO(11) | 7)
+
+#define PINMUX_GPIO12__FUNC_GPIO12 (MTK_PIN_NO(12) | 0)
+#define PINMUX_GPIO12__FUNC_TP_UTXD1_VCORE (MTK_PIN_NO(12) | 1)
+#define PINMUX_GPIO12__FUNC_UTXD3 (MTK_PIN_NO(12) | 2)
+#define PINMUX_GPIO12__FUNC_CLKM0 (MTK_PIN_NO(12) | 3)
+#define PINMUX_GPIO12__FUNC_CMFLASH0 (MTK_PIN_NO(12) | 4)
+#define PINMUX_GPIO12__FUNC_ANT_SEL0 (MTK_PIN_NO(12) | 6)
+#define PINMUX_GPIO12__FUNC_DBG_MON_B20 (MTK_PIN_NO(12) | 7)
+
+#define PINMUX_GPIO13__FUNC_GPIO13 (MTK_PIN_NO(13) | 0)
+#define PINMUX_GPIO13__FUNC_TP_URXD1_VCORE (MTK_PIN_NO(13) | 1)
+#define PINMUX_GPIO13__FUNC_URXD3 (MTK_PIN_NO(13) | 2)
+#define PINMUX_GPIO13__FUNC_CLKM1 (MTK_PIN_NO(13) | 3)
+#define PINMUX_GPIO13__FUNC_CMFLASH1 (MTK_PIN_NO(13) | 4)
+#define PINMUX_GPIO13__FUNC_ANT_SEL1 (MTK_PIN_NO(13) | 6)
+#define PINMUX_GPIO13__FUNC_DBG_MON_B21 (MTK_PIN_NO(13) | 7)
+
+#define PINMUX_GPIO14__FUNC_GPIO14 (MTK_PIN_NO(14) | 0)
+#define PINMUX_GPIO14__FUNC_TP_UCTS1_VCORE (MTK_PIN_NO(14) | 1)
+#define PINMUX_GPIO14__FUNC_UCTS3 (MTK_PIN_NO(14) | 2)
+#define PINMUX_GPIO14__FUNC_CLKM2 (MTK_PIN_NO(14) | 3)
+#define PINMUX_GPIO14__FUNC_CMFLASH2 (MTK_PIN_NO(14) | 4)
+#define PINMUX_GPIO14__FUNC_ANT_SEL2 (MTK_PIN_NO(14) | 6)
+#define PINMUX_GPIO14__FUNC_DBG_MON_B22 (MTK_PIN_NO(14) | 7)
+
+#define PINMUX_GPIO15__FUNC_GPIO15 (MTK_PIN_NO(15) | 0)
+#define PINMUX_GPIO15__FUNC_TP_URTS1_VCORE (MTK_PIN_NO(15) | 1)
+#define PINMUX_GPIO15__FUNC_URTS3 (MTK_PIN_NO(15) | 2)
+#define PINMUX_GPIO15__FUNC_CLKM3 (MTK_PIN_NO(15) | 3)
+#define PINMUX_GPIO15__FUNC_CMVREF0 (MTK_PIN_NO(15) | 4)
+#define PINMUX_GPIO15__FUNC_ANT_SEL3 (MTK_PIN_NO(15) | 6)
+#define PINMUX_GPIO15__FUNC_DBG_MON_B23 (MTK_PIN_NO(15) | 7)
+
+#define PINMUX_GPIO16__FUNC_GPIO16 (MTK_PIN_NO(16) | 0)
+#define PINMUX_GPIO16__FUNC_PWM_0 (MTK_PIN_NO(16) | 1)
+#define PINMUX_GPIO16__FUNC_UCTS2 (MTK_PIN_NO(16) | 2)
+#define PINMUX_GPIO16__FUNC_DP_TX_HPD (MTK_PIN_NO(16) | 3)
+#define PINMUX_GPIO16__FUNC_CMVREF1 (MTK_PIN_NO(16) | 4)
+#define PINMUX_GPIO16__FUNC_MD32_0_GPIO0 (MTK_PIN_NO(16) | 5)
+#define PINMUX_GPIO16__FUNC_ANT_SEL4 (MTK_PIN_NO(16) | 6)
+#define PINMUX_GPIO16__FUNC_DBG_MON_B24 (MTK_PIN_NO(16) | 7)
+
+#define PINMUX_GPIO17__FUNC_GPIO17 (MTK_PIN_NO(17) | 0)
+#define PINMUX_GPIO17__FUNC_PWM_1 (MTK_PIN_NO(17) | 1)
+#define PINMUX_GPIO17__FUNC_URTS2 (MTK_PIN_NO(17) | 2)
+#define PINMUX_GPIO17__FUNC_EDP_TX_HPD (MTK_PIN_NO(17) | 3)
+#define PINMUX_GPIO17__FUNC_CMVREF2 (MTK_PIN_NO(17) | 4)
+#define PINMUX_GPIO17__FUNC_MD32_1_GPIO0 (MTK_PIN_NO(17) | 5)
+#define PINMUX_GPIO17__FUNC_PMSR_SMAP (MTK_PIN_NO(17) | 6)
+#define PINMUX_GPIO17__FUNC_DBG_MON_B25 (MTK_PIN_NO(17) | 7)
+
+#define PINMUX_GPIO18__FUNC_GPIO18 (MTK_PIN_NO(18) | 0)
+#define PINMUX_GPIO18__FUNC_CMFLASH0 (MTK_PIN_NO(18) | 1)
+#define PINMUX_GPIO18__FUNC_CMVREF3 (MTK_PIN_NO(18) | 2)
+#define PINMUX_GPIO18__FUNC_UTXD2 (MTK_PIN_NO(18) | 3)
+#define PINMUX_GPIO18__FUNC_DISP_PWM1 (MTK_PIN_NO(18) | 4)
+#define PINMUX_GPIO18__FUNC_I2SIN1_MCK (MTK_PIN_NO(18) | 5)
+#define PINMUX_GPIO18__FUNC_MBISTREADEN_TRIGGER (MTK_PIN_NO(18) | 6)
+#define PINMUX_GPIO18__FUNC_DBG_MON_A12 (MTK_PIN_NO(18) | 7)
+
+#define PINMUX_GPIO19__FUNC_GPIO19 (MTK_PIN_NO(19) | 0)
+#define PINMUX_GPIO19__FUNC_CMFLASH1 (MTK_PIN_NO(19) | 1)
+#define PINMUX_GPIO19__FUNC_CMVREF2 (MTK_PIN_NO(19) | 2)
+#define PINMUX_GPIO19__FUNC_URXD2 (MTK_PIN_NO(19) | 3)
+#define PINMUX_GPIO19__FUNC_USB_DRVVBUS_1P (MTK_PIN_NO(19) | 4)
+#define PINMUX_GPIO19__FUNC_I2SIN1_BCK (MTK_PIN_NO(19) | 5)
+#define PINMUX_GPIO19__FUNC_MBISTWRITEEN_TRIGGER (MTK_PIN_NO(19) | 6)
+#define PINMUX_GPIO19__FUNC_DBG_MON_A13 (MTK_PIN_NO(19) | 7)
+
+#define PINMUX_GPIO20__FUNC_GPIO20 (MTK_PIN_NO(20) | 0)
+#define PINMUX_GPIO20__FUNC_CMFLASH2 (MTK_PIN_NO(20) | 1)
+#define PINMUX_GPIO20__FUNC_CMVREF1 (MTK_PIN_NO(20) | 2)
+#define PINMUX_GPIO20__FUNC_UCTS2 (MTK_PIN_NO(20) | 3)
+#define PINMUX_GPIO20__FUNC_PERSTN (MTK_PIN_NO(20) | 4)
+#define PINMUX_GPIO20__FUNC_I2SIN1_LRCK (MTK_PIN_NO(20) | 5)
+#define PINMUX_GPIO20__FUNC_DMIC0_DAT1 (MTK_PIN_NO(20) | 6)
+#define PINMUX_GPIO20__FUNC_DBG_MON_A14 (MTK_PIN_NO(20) | 7)
+
+#define PINMUX_GPIO21__FUNC_GPIO21 (MTK_PIN_NO(21) | 0)
+#define PINMUX_GPIO21__FUNC_CMFLASH3 (MTK_PIN_NO(21) | 1)
+#define PINMUX_GPIO21__FUNC_CMVREF0 (MTK_PIN_NO(21) | 2)
+#define PINMUX_GPIO21__FUNC_URTS2 (MTK_PIN_NO(21) | 3)
+#define PINMUX_GPIO21__FUNC_CLKREQN (MTK_PIN_NO(21) | 4)
+#define PINMUX_GPIO21__FUNC_I2SIN1_DI (MTK_PIN_NO(21) | 5)
+#define PINMUX_GPIO21__FUNC_DMIC1_DAT1 (MTK_PIN_NO(21) | 6)
+#define PINMUX_GPIO21__FUNC_DBG_MON_A15 (MTK_PIN_NO(21) | 7)
+
+#define PINMUX_GPIO22__FUNC_GPIO22 (MTK_PIN_NO(22) | 0)
+#define PINMUX_GPIO22__FUNC_CMMCLK0 (MTK_PIN_NO(22) | 1)
+#define PINMUX_GPIO22__FUNC_TP_GPIO4_AO (MTK_PIN_NO(22) | 2)
+
+#define PINMUX_GPIO23__FUNC_GPIO23 (MTK_PIN_NO(23) | 0)
+#define PINMUX_GPIO23__FUNC_CMMCLK1 (MTK_PIN_NO(23) | 1)
+#define PINMUX_GPIO23__FUNC_TP_GPIO5_AO (MTK_PIN_NO(23) | 2)
+#define PINMUX_GPIO23__FUNC_SSPM_UTXD_AO_VLP (MTK_PIN_NO(23) | 3)
+#define PINMUX_GPIO23__FUNC_PWM_vlp (MTK_PIN_NO(23) | 4)
+#define PINMUX_GPIO23__FUNC_SRCLKENAI0 (MTK_PIN_NO(23) | 6)
+
+#define PINMUX_GPIO24__FUNC_GPIO24 (MTK_PIN_NO(24) | 0)
+#define PINMUX_GPIO24__FUNC_CMMCLK2 (MTK_PIN_NO(24) | 1)
+#define PINMUX_GPIO24__FUNC_TP_GPIO6_AO (MTK_PIN_NO(24) | 2)
+#define PINMUX_GPIO24__FUNC_SSPM_URXD_AO_VLP (MTK_PIN_NO(24) | 3)
+#define PINMUX_GPIO24__FUNC_WAKEN (MTK_PIN_NO(24) | 4)
+#define PINMUX_GPIO24__FUNC_SPMI_P_TRIG_FLAG (MTK_PIN_NO(24) | 5)
+#define PINMUX_GPIO24__FUNC_SRCLKENAI1 (MTK_PIN_NO(24) | 6)
+
+#define PINMUX_GPIO25__FUNC_GPIO25 (MTK_PIN_NO(25) | 0)
+#define PINMUX_GPIO25__FUNC_LCM_RST (MTK_PIN_NO(25) | 1)
+#define PINMUX_GPIO25__FUNC_DP_TX_HPD (MTK_PIN_NO(25) | 2)
+#define PINMUX_GPIO25__FUNC_CMFLASH3 (MTK_PIN_NO(25) | 3)
+#define PINMUX_GPIO25__FUNC_MD32_0_GPIO0 (MTK_PIN_NO(25) | 4)
+#define PINMUX_GPIO25__FUNC_USB_DRVVBUS_2P (MTK_PIN_NO(25) | 5)
+
+#define PINMUX_GPIO26__FUNC_GPIO26 (MTK_PIN_NO(26) | 0)
+#define PINMUX_GPIO26__FUNC_DSI_TE (MTK_PIN_NO(26) | 1)
+#define PINMUX_GPIO26__FUNC_EDP_TX_HPD (MTK_PIN_NO(26) | 2)
+#define PINMUX_GPIO26__FUNC_CMVREF3 (MTK_PIN_NO(26) | 3)
+#define PINMUX_GPIO26__FUNC_MD32_1_GPIO0 (MTK_PIN_NO(26) | 4)
+#define PINMUX_GPIO26__FUNC_USB_DRVVBUS_3P (MTK_PIN_NO(26) | 5)
+
+#define PINMUX_GPIO27__FUNC_GPIO27 (MTK_PIN_NO(27) | 0)
+#define PINMUX_GPIO27__FUNC_DP_TX_HPD (MTK_PIN_NO(27) | 1)
+#define PINMUX_GPIO27__FUNC_MBISTREADEN_TRIGGER (MTK_PIN_NO(27) | 2)
+#define PINMUX_GPIO27__FUNC_MD32_0_GPIO0 (MTK_PIN_NO(27) | 3)
+#define PINMUX_GPIO27__FUNC_TP_UCTS1_VCORE (MTK_PIN_NO(27) | 4)
+#define PINMUX_GPIO27__FUNC_CMVREF4 (MTK_PIN_NO(27) | 5)
+#define PINMUX_GPIO27__FUNC_EXTIF0_ACT (MTK_PIN_NO(27) | 6)
+#define PINMUX_GPIO27__FUNC_ANT_SEL0 (MTK_PIN_NO(27) | 7)
+
+#define PINMUX_GPIO28__FUNC_GPIO28 (MTK_PIN_NO(28) | 0)
+#define PINMUX_GPIO28__FUNC_EDP_TX_HPD (MTK_PIN_NO(28) | 1)
+#define PINMUX_GPIO28__FUNC_MBISTWRITEEN_TRIGGER (MTK_PIN_NO(28) | 2)
+#define PINMUX_GPIO28__FUNC_MD32_1_GPIO0 (MTK_PIN_NO(28) | 3)
+#define PINMUX_GPIO28__FUNC_TP_URTS1_VCORE (MTK_PIN_NO(28) | 4)
+#define PINMUX_GPIO28__FUNC_EXTIF0_PRI (MTK_PIN_NO(28) | 6)
+#define PINMUX_GPIO28__FUNC_ANT_SEL1 (MTK_PIN_NO(28) | 7)
+
+#define PINMUX_GPIO29__FUNC_GPIO29 (MTK_PIN_NO(29) | 0)
+#define PINMUX_GPIO29__FUNC_DISP_PWM0 (MTK_PIN_NO(29) | 1)
+#define PINMUX_GPIO29__FUNC_MD32_1_TXD (MTK_PIN_NO(29) | 2)
+#define PINMUX_GPIO29__FUNC_SSPM_UTXD_AO_VCORE (MTK_PIN_NO(29) | 3)
+#define PINMUX_GPIO29__FUNC_USB_DRVVBUS_4P (MTK_PIN_NO(29) | 5)
+
+#define PINMUX_GPIO30__FUNC_GPIO30 (MTK_PIN_NO(30) | 0)
+#define PINMUX_GPIO30__FUNC_DISP_PWM1 (MTK_PIN_NO(30) | 1)
+#define PINMUX_GPIO30__FUNC_MD32_1_RXD (MTK_PIN_NO(30) | 2)
+#define PINMUX_GPIO30__FUNC_SSPM_URXD_AO_VCORE (MTK_PIN_NO(30) | 3)
+#define PINMUX_GPIO30__FUNC_PMSR_SMAP (MTK_PIN_NO(30) | 5)
+#define PINMUX_GPIO30__FUNC_EXTIF0_GNT_B (MTK_PIN_NO(30) | 6)
+#define PINMUX_GPIO30__FUNC_ANT_SEL2 (MTK_PIN_NO(30) | 7)
+
+#define PINMUX_GPIO31__FUNC_GPIO31 (MTK_PIN_NO(31) | 0)
+#define PINMUX_GPIO31__FUNC_UTXD0 (MTK_PIN_NO(31) | 1)
+#define PINMUX_GPIO31__FUNC_MD32_0_TXD (MTK_PIN_NO(31) | 2)
+
+#define PINMUX_GPIO32__FUNC_GPIO32 (MTK_PIN_NO(32) | 0)
+#define PINMUX_GPIO32__FUNC_URXD0 (MTK_PIN_NO(32) | 1)
+#define PINMUX_GPIO32__FUNC_MD32_0_RXD (MTK_PIN_NO(32) | 2)
+
+#define PINMUX_GPIO33__FUNC_GPIO33 (MTK_PIN_NO(33) | 0)
+#define PINMUX_GPIO33__FUNC_UTXD1 (MTK_PIN_NO(33) | 1)
+#define PINMUX_GPIO33__FUNC_VADSP_UTXD0 (MTK_PIN_NO(33) | 2)
+#define PINMUX_GPIO33__FUNC_TP_UTXD1_VLP (MTK_PIN_NO(33) | 3)
+#define PINMUX_GPIO33__FUNC_MD32_1_TXD (MTK_PIN_NO(33) | 4)
+#define PINMUX_GPIO33__FUNC_CONN_BGF_UART0_TXD (MTK_PIN_NO(33) | 5)
+#define PINMUX_GPIO33__FUNC_CONN_WIFI_TXD (MTK_PIN_NO(33) | 6)
+
+#define PINMUX_GPIO34__FUNC_GPIO34 (MTK_PIN_NO(34) | 0)
+#define PINMUX_GPIO34__FUNC_URXD1 (MTK_PIN_NO(34) | 1)
+#define PINMUX_GPIO34__FUNC_VADSP_URXD0 (MTK_PIN_NO(34) | 2)
+#define PINMUX_GPIO34__FUNC_TP_URXD1_VLP (MTK_PIN_NO(34) | 3)
+#define PINMUX_GPIO34__FUNC_MD32_1_RXD (MTK_PIN_NO(34) | 4)
+#define PINMUX_GPIO34__FUNC_CONN_BGF_UART0_RXD (MTK_PIN_NO(34) | 5)
+
+#define PINMUX_GPIO35__FUNC_GPIO35 (MTK_PIN_NO(35) | 0)
+#define PINMUX_GPIO35__FUNC_UTXD2 (MTK_PIN_NO(35) | 1)
+#define PINMUX_GPIO35__FUNC_UCTS1 (MTK_PIN_NO(35) | 2)
+#define PINMUX_GPIO35__FUNC_TP_UCTS1_VLP (MTK_PIN_NO(35) | 3)
+#define PINMUX_GPIO35__FUNC_SSPM_UTXD_AO_VLP (MTK_PIN_NO(35) | 4)
+#define PINMUX_GPIO35__FUNC_VADSP_UTXD0 (MTK_PIN_NO(35) | 5)
+#define PINMUX_GPIO35__FUNC_CONN_BT_TXD (MTK_PIN_NO(35) | 6)
+
+#define PINMUX_GPIO36__FUNC_GPIO36 (MTK_PIN_NO(36) | 0)
+#define PINMUX_GPIO36__FUNC_URXD2 (MTK_PIN_NO(36) | 1)
+#define PINMUX_GPIO36__FUNC_URTS1 (MTK_PIN_NO(36) | 2)
+#define PINMUX_GPIO36__FUNC_TP_URTS1_VLP (MTK_PIN_NO(36) | 3)
+#define PINMUX_GPIO36__FUNC_SSPM_URXD_AO_VLP (MTK_PIN_NO(36) | 4)
+#define PINMUX_GPIO36__FUNC_VADSP_URXD0 (MTK_PIN_NO(36) | 5)
+
+#define PINMUX_GPIO37__FUNC_GPIO37 (MTK_PIN_NO(37) | 0)
+#define PINMUX_GPIO37__FUNC_UTXD3 (MTK_PIN_NO(37) | 1)
+#define PINMUX_GPIO37__FUNC_UCTS0 (MTK_PIN_NO(37) | 2)
+#define PINMUX_GPIO37__FUNC_TP_UTXD1_VCORE (MTK_PIN_NO(37) | 3)
+#define PINMUX_GPIO37__FUNC_SSPM_UTXD_AO_VCORE (MTK_PIN_NO(37) | 4)
+#define PINMUX_GPIO37__FUNC_MD32_0_TXD (MTK_PIN_NO(37) | 6)
+#define PINMUX_GPIO37__FUNC_CONN_BGF_UART0_TXD (MTK_PIN_NO(37) | 7)
+
+#define PINMUX_GPIO38__FUNC_GPIO38 (MTK_PIN_NO(38) | 0)
+#define PINMUX_GPIO38__FUNC_URXD3 (MTK_PIN_NO(38) | 1)
+#define PINMUX_GPIO38__FUNC_URTS0 (MTK_PIN_NO(38) | 2)
+#define PINMUX_GPIO38__FUNC_TP_URXD1_VCORE (MTK_PIN_NO(38) | 3)
+#define PINMUX_GPIO38__FUNC_SSPM_URXD_AO_VCORE (MTK_PIN_NO(38) | 4)
+#define PINMUX_GPIO38__FUNC_MD32_0_RXD (MTK_PIN_NO(38) | 6)
+#define PINMUX_GPIO38__FUNC_CONN_BGF_UART0_RXD (MTK_PIN_NO(38) | 7)
+
+#define PINMUX_GPIO39__FUNC_GPIO39 (MTK_PIN_NO(39) | 0)
+#define PINMUX_GPIO39__FUNC_JTMS_SEL1 (MTK_PIN_NO(39) | 1)
+
+#define PINMUX_GPIO40__FUNC_GPIO40 (MTK_PIN_NO(40) | 0)
+#define PINMUX_GPIO40__FUNC_JTCK_SEL1 (MTK_PIN_NO(40) | 1)
+
+#define PINMUX_GPIO41__FUNC_GPIO41 (MTK_PIN_NO(41) | 0)
+#define PINMUX_GPIO41__FUNC_JTDI_SEL1 (MTK_PIN_NO(41) | 1)
+
+#define PINMUX_GPIO42__FUNC_GPIO42 (MTK_PIN_NO(42) | 0)
+#define PINMUX_GPIO42__FUNC_JTDO_SEL1 (MTK_PIN_NO(42) | 1)
+
+#define PINMUX_GPIO43__FUNC_GPIO43 (MTK_PIN_NO(43) | 0)
+#define PINMUX_GPIO43__FUNC_JTRSTn_SEL1 (MTK_PIN_NO(43) | 1)
+
+#define PINMUX_GPIO44__FUNC_GPIO44 (MTK_PIN_NO(44) | 0)
+#define PINMUX_GPIO44__FUNC_KPCOL0 (MTK_PIN_NO(44) | 1)
+
+#define PINMUX_GPIO45__FUNC_GPIO45 (MTK_PIN_NO(45) | 0)
+#define PINMUX_GPIO45__FUNC_KPCOL1 (MTK_PIN_NO(45) | 1)
+#define PINMUX_GPIO45__FUNC_TP_GPIO0_AO (MTK_PIN_NO(45) | 2)
+#define PINMUX_GPIO45__FUNC_SRCLKENAI1 (MTK_PIN_NO(45) | 3)
+#define PINMUX_GPIO45__FUNC_DBG_MON_A31 (MTK_PIN_NO(45) | 7)
+
+#define PINMUX_GPIO46__FUNC_GPIO46 (MTK_PIN_NO(46) | 0)
+#define PINMUX_GPIO46__FUNC_KPROW0 (MTK_PIN_NO(46) | 1)
+#define PINMUX_GPIO46__FUNC_TP_GPIO1_AO (MTK_PIN_NO(46) | 2)
+
+#define PINMUX_GPIO47__FUNC_GPIO47 (MTK_PIN_NO(47) | 0)
+#define PINMUX_GPIO47__FUNC_KPROW1 (MTK_PIN_NO(47) | 1)
+#define PINMUX_GPIO47__FUNC_TP_GPIO2_AO (MTK_PIN_NO(47) | 2)
+#define PINMUX_GPIO47__FUNC_SRCLKENAI0 (MTK_PIN_NO(47) | 3)
+#define PINMUX_GPIO47__FUNC_DBG_MON_A32 (MTK_PIN_NO(47) | 7)
+
+#define PINMUX_GPIO48__FUNC_GPIO48 (MTK_PIN_NO(48) | 0)
+#define PINMUX_GPIO48__FUNC_WAKEN (MTK_PIN_NO(48) | 1)
+#define PINMUX_GPIO48__FUNC_TP_GPIO3_AO (MTK_PIN_NO(48) | 2)
+#define PINMUX_GPIO48__FUNC_SPMI_P_TRIG_FLAG (MTK_PIN_NO(48) | 3)
+
+#define PINMUX_GPIO49__FUNC_GPIO49 (MTK_PIN_NO(49) | 0)
+#define PINMUX_GPIO49__FUNC_PERSTN (MTK_PIN_NO(49) | 1)
+#define PINMUX_GPIO49__FUNC_MD32_0_GPIO0 (MTK_PIN_NO(49) | 2)
+#define PINMUX_GPIO49__FUNC_UFS_MPHY_SCL (MTK_PIN_NO(49) | 3)
+#define PINMUX_GPIO49__FUNC_ANT_SEL3 (MTK_PIN_NO(49) | 7)
+
+#define PINMUX_GPIO50__FUNC_GPIO50 (MTK_PIN_NO(50) | 0)
+#define PINMUX_GPIO50__FUNC_CLKREQN (MTK_PIN_NO(50) | 1)
+#define PINMUX_GPIO50__FUNC_MD32_1_GPIO0 (MTK_PIN_NO(50) | 2)
+#define PINMUX_GPIO50__FUNC_UFS_MPHY_SDA (MTK_PIN_NO(50) | 3)
+#define PINMUX_GPIO50__FUNC_ANT_SEL4 (MTK_PIN_NO(50) | 7)
+
+#define PINMUX_GPIO51__FUNC_GPIO51 (MTK_PIN_NO(51) | 0)
+#define PINMUX_GPIO51__FUNC_SCP_SCL0 (MTK_PIN_NO(51) | 1)
+#define PINMUX_GPIO51__FUNC_SCL0 (MTK_PIN_NO(51) | 2)
+
+#define PINMUX_GPIO52__FUNC_GPIO52 (MTK_PIN_NO(52) | 0)
+#define PINMUX_GPIO52__FUNC_SCP_SDA0 (MTK_PIN_NO(52) | 1)
+#define PINMUX_GPIO52__FUNC_SDA0 (MTK_PIN_NO(52) | 2)
+
+#define PINMUX_GPIO53__FUNC_GPIO53 (MTK_PIN_NO(53) | 0)
+#define PINMUX_GPIO53__FUNC_SCP_SCL1 (MTK_PIN_NO(53) | 1)
+#define PINMUX_GPIO53__FUNC_SCL1 (MTK_PIN_NO(53) | 2)
+
+#define PINMUX_GPIO54__FUNC_GPIO54 (MTK_PIN_NO(54) | 0)
+#define PINMUX_GPIO54__FUNC_SCP_SDA1 (MTK_PIN_NO(54) | 1)
+#define PINMUX_GPIO54__FUNC_SDA1 (MTK_PIN_NO(54) | 2)
+
+#define PINMUX_GPIO55__FUNC_GPIO55 (MTK_PIN_NO(55) | 0)
+#define PINMUX_GPIO55__FUNC_SCL2 (MTK_PIN_NO(55) | 1)
+#define PINMUX_GPIO55__FUNC_UFS_MPHY_SCL (MTK_PIN_NO(55) | 2)
+#define PINMUX_GPIO55__FUNC_SSUSB_U2SIF_SCL (MTK_PIN_NO(55) | 3)
+
+#define PINMUX_GPIO56__FUNC_GPIO56 (MTK_PIN_NO(56) | 0)
+#define PINMUX_GPIO56__FUNC_SDA2 (MTK_PIN_NO(56) | 1)
+#define PINMUX_GPIO56__FUNC_UFS_MPHY_SDA (MTK_PIN_NO(56) | 2)
+#define PINMUX_GPIO56__FUNC_SSUSB_U2SIF_SDA (MTK_PIN_NO(56) | 3)
+
+#define PINMUX_GPIO57__FUNC_GPIO57 (MTK_PIN_NO(57) | 0)
+#define PINMUX_GPIO57__FUNC_SCL3 (MTK_PIN_NO(57) | 1)
+#define PINMUX_GPIO57__FUNC_PCIE_PHY_I2C_SCL (MTK_PIN_NO(57) | 2)
+#define PINMUX_GPIO57__FUNC_SSUSB_U2SIF_SCL_1P (MTK_PIN_NO(57) | 3)
+
+#define PINMUX_GPIO58__FUNC_GPIO58 (MTK_PIN_NO(58) | 0)
+#define PINMUX_GPIO58__FUNC_SDA3 (MTK_PIN_NO(58) | 1)
+#define PINMUX_GPIO58__FUNC_PCIE_PHY_I2C_SDA (MTK_PIN_NO(58) | 2)
+#define PINMUX_GPIO58__FUNC_SSUSB_U2SIF_SDA_1P (MTK_PIN_NO(58) | 3)
+
+#define PINMUX_GPIO59__FUNC_GPIO59 (MTK_PIN_NO(59) | 0)
+#define PINMUX_GPIO59__FUNC_SCL4 (MTK_PIN_NO(59) | 1)
+#define PINMUX_GPIO59__FUNC_SSUSB_U3PHY_I2C_SCL (MTK_PIN_NO(59) | 2)
+
+#define PINMUX_GPIO60__FUNC_GPIO60 (MTK_PIN_NO(60) | 0)
+#define PINMUX_GPIO60__FUNC_SDA4 (MTK_PIN_NO(60) | 1)
+#define PINMUX_GPIO60__FUNC_SSUSB_U3PHY_I2C_SDA (MTK_PIN_NO(60) | 2)
+
+#define PINMUX_GPIO61__FUNC_GPIO61 (MTK_PIN_NO(61) | 0)
+#define PINMUX_GPIO61__FUNC_SCL5 (MTK_PIN_NO(61) | 1)
+#define PINMUX_GPIO61__FUNC_SSPXTP_U3PHY_I2C_SCL (MTK_PIN_NO(61) | 2)
+
+#define PINMUX_GPIO62__FUNC_GPIO62 (MTK_PIN_NO(62) | 0)
+#define PINMUX_GPIO62__FUNC_SDA5 (MTK_PIN_NO(62) | 1)
+#define PINMUX_GPIO62__FUNC_SSPXTP_U3PHY_I2C_SDA (MTK_PIN_NO(62) | 2)
+
+#define PINMUX_GPIO63__FUNC_GPIO63 (MTK_PIN_NO(63) | 0)
+#define PINMUX_GPIO63__FUNC_SCL6 (MTK_PIN_NO(63) | 1)
+
+#define PINMUX_GPIO64__FUNC_GPIO64 (MTK_PIN_NO(64) | 0)
+#define PINMUX_GPIO64__FUNC_SDA6 (MTK_PIN_NO(64) | 1)
+
+#define PINMUX_GPIO65__FUNC_GPIO65 (MTK_PIN_NO(65) | 0)
+#define PINMUX_GPIO65__FUNC_SCL7 (MTK_PIN_NO(65) | 1)
+
+#define PINMUX_GPIO66__FUNC_GPIO66 (MTK_PIN_NO(66) | 0)
+#define PINMUX_GPIO66__FUNC_SDA7 (MTK_PIN_NO(66) | 1)
+
+#define PINMUX_GPIO67__FUNC_GPIO67 (MTK_PIN_NO(67) | 0)
+#define PINMUX_GPIO67__FUNC_SCL8 (MTK_PIN_NO(67) | 1)
+
+#define PINMUX_GPIO68__FUNC_GPIO68 (MTK_PIN_NO(68) | 0)
+#define PINMUX_GPIO68__FUNC_SDA8 (MTK_PIN_NO(68) | 1)
+
+#define PINMUX_GPIO69__FUNC_GPIO69 (MTK_PIN_NO(69) | 0)
+#define PINMUX_GPIO69__FUNC_SPIM0_CSB (MTK_PIN_NO(69) | 1)
+#define PINMUX_GPIO69__FUNC_SCP_SPI0_CS (MTK_PIN_NO(69) | 2)
+#define PINMUX_GPIO69__FUNC_SPM_JTAG_TMS_VCORE (MTK_PIN_NO(69) | 3)
+#define PINMUX_GPIO69__FUNC_VADSP_JTAG0_TMS (MTK_PIN_NO(69) | 4)
+#define PINMUX_GPIO69__FUNC_SPM_JTAG_TMS (MTK_PIN_NO(69) | 5)
+#define PINMUX_GPIO69__FUNC_SSPM_JTAG_TMS_VLP (MTK_PIN_NO(69) | 6)
+#define PINMUX_GPIO69__FUNC_SCP_JTAG0_TMS_VLP (MTK_PIN_NO(69) | 7)
+
+#define PINMUX_GPIO70__FUNC_GPIO70 (MTK_PIN_NO(70) | 0)
+#define PINMUX_GPIO70__FUNC_SPIM0_CLK (MTK_PIN_NO(70) | 1)
+#define PINMUX_GPIO70__FUNC_SCP_SPI0_CK (MTK_PIN_NO(70) | 2)
+#define PINMUX_GPIO70__FUNC_SPM_JTAG_TCK_VCORE (MTK_PIN_NO(70) | 3)
+#define PINMUX_GPIO70__FUNC_VADSP_JTAG0_TCK (MTK_PIN_NO(70) | 4)
+#define PINMUX_GPIO70__FUNC_SPM_JTAG_TCK (MTK_PIN_NO(70) | 5)
+#define PINMUX_GPIO70__FUNC_SSPM_JTAG_TCK_VLP (MTK_PIN_NO(70) | 6)
+#define PINMUX_GPIO70__FUNC_SCP_JTAG0_TCK_VLP (MTK_PIN_NO(70) | 7)
+
+#define PINMUX_GPIO71__FUNC_GPIO71 (MTK_PIN_NO(71) | 0)
+#define PINMUX_GPIO71__FUNC_SPIM0_MO (MTK_PIN_NO(71) | 1)
+#define PINMUX_GPIO71__FUNC_SCP_SPI0_MO (MTK_PIN_NO(71) | 2)
+#define PINMUX_GPIO71__FUNC_SPM_JTAG_TDI_VCORE (MTK_PIN_NO(71) | 3)
+#define PINMUX_GPIO71__FUNC_VADSP_JTAG0_TDI (MTK_PIN_NO(71) | 4)
+#define PINMUX_GPIO71__FUNC_SPM_JTAG_TDI (MTK_PIN_NO(71) | 5)
+#define PINMUX_GPIO71__FUNC_SSPM_JTAG_TDI_VLP (MTK_PIN_NO(71) | 6)
+#define PINMUX_GPIO71__FUNC_SCP_JTAG0_TDI_VLP (MTK_PIN_NO(71) | 7)
+
+#define PINMUX_GPIO72__FUNC_GPIO72 (MTK_PIN_NO(72) | 0)
+#define PINMUX_GPIO72__FUNC_SPIM0_MI (MTK_PIN_NO(72) | 1)
+#define PINMUX_GPIO72__FUNC_SCP_SPI0_MI (MTK_PIN_NO(72) | 2)
+#define PINMUX_GPIO72__FUNC_SPM_JTAG_TDO_VCORE (MTK_PIN_NO(72) | 3)
+#define PINMUX_GPIO72__FUNC_VADSP_JTAG0_TDO (MTK_PIN_NO(72) | 4)
+#define PINMUX_GPIO72__FUNC_SPM_JTAG_TDO (MTK_PIN_NO(72) | 5)
+#define PINMUX_GPIO72__FUNC_SSPM_JTAG_TDO_VLP (MTK_PIN_NO(72) | 6)
+#define PINMUX_GPIO72__FUNC_SCP_JTAG0_TDO_VLP (MTK_PIN_NO(72) | 7)
+
+#define PINMUX_GPIO73__FUNC_GPIO73 (MTK_PIN_NO(73) | 0)
+#define PINMUX_GPIO73__FUNC_SPIM1_CSB (MTK_PIN_NO(73) | 1)
+#define PINMUX_GPIO73__FUNC_SCP_SPI1_CS (MTK_PIN_NO(73) | 2)
+#define PINMUX_GPIO73__FUNC_SPM_JTAG_TRSTN_VCORE (MTK_PIN_NO(73) | 3)
+#define PINMUX_GPIO73__FUNC_VADSP_JTAG0_TRSTN (MTK_PIN_NO(73) | 4)
+#define PINMUX_GPIO73__FUNC_SPM_JTAG_TRSTN (MTK_PIN_NO(73) | 5)
+#define PINMUX_GPIO73__FUNC_SSPM_JTAG_TRSTN_VLP (MTK_PIN_NO(73) | 6)
+#define PINMUX_GPIO73__FUNC_SCP_JTAG0_TRSTN_VLP (MTK_PIN_NO(73) | 7)
+
+#define PINMUX_GPIO74__FUNC_GPIO74 (MTK_PIN_NO(74) | 0)
+#define PINMUX_GPIO74__FUNC_SPIM1_CLK (MTK_PIN_NO(74) | 1)
+#define PINMUX_GPIO74__FUNC_SCP_SPI1_CK (MTK_PIN_NO(74) | 2)
+
+#define PINMUX_GPIO75__FUNC_GPIO75 (MTK_PIN_NO(75) | 0)
+#define PINMUX_GPIO75__FUNC_SPIM1_MO (MTK_PIN_NO(75) | 1)
+#define PINMUX_GPIO75__FUNC_SCP_SPI1_MO (MTK_PIN_NO(75) | 2)
+
+#define PINMUX_GPIO76__FUNC_GPIO76 (MTK_PIN_NO(76) | 0)
+#define PINMUX_GPIO76__FUNC_SPIM1_MI (MTK_PIN_NO(76) | 1)
+#define PINMUX_GPIO76__FUNC_SCP_SPI1_MI (MTK_PIN_NO(76) | 2)
+
+#define PINMUX_GPIO77__FUNC_GPIO77 (MTK_PIN_NO(77) | 0)
+#define PINMUX_GPIO77__FUNC_SPIM2_CSB (MTK_PIN_NO(77) | 1)
+#define PINMUX_GPIO77__FUNC_PCM0_SYNC (MTK_PIN_NO(77) | 2)
+#define PINMUX_GPIO77__FUNC_SSUSB_U2SIF_SCL (MTK_PIN_NO(77) | 3)
+#define PINMUX_GPIO77__FUNC_DBG_MON_A27 (MTK_PIN_NO(77) | 7)
+
+#define PINMUX_GPIO78__FUNC_GPIO78 (MTK_PIN_NO(78) | 0)
+#define PINMUX_GPIO78__FUNC_SPIM2_CLK (MTK_PIN_NO(78) | 1)
+#define PINMUX_GPIO78__FUNC_PCM0_CLK (MTK_PIN_NO(78) | 2)
+#define PINMUX_GPIO78__FUNC_SSUSB_U2SIF_SDA (MTK_PIN_NO(78) | 3)
+#define PINMUX_GPIO78__FUNC_DBG_MON_A28 (MTK_PIN_NO(78) | 7)
+
+#define PINMUX_GPIO79__FUNC_GPIO79 (MTK_PIN_NO(79) | 0)
+#define PINMUX_GPIO79__FUNC_SPIM2_MO (MTK_PIN_NO(79) | 1)
+#define PINMUX_GPIO79__FUNC_PCM0_DO (MTK_PIN_NO(79) | 2)
+#define PINMUX_GPIO79__FUNC_SSUSB_U2SIF_SCL_1P (MTK_PIN_NO(79) | 3)
+#define PINMUX_GPIO79__FUNC_DBG_MON_A29 (MTK_PIN_NO(79) | 7)
+
+#define PINMUX_GPIO80__FUNC_GPIO80 (MTK_PIN_NO(80) | 0)
+#define PINMUX_GPIO80__FUNC_SPIM2_MI (MTK_PIN_NO(80) | 1)
+#define PINMUX_GPIO80__FUNC_PCM0_DI (MTK_PIN_NO(80) | 2)
+#define PINMUX_GPIO80__FUNC_SSUSB_U2SIF_SDA_1P (MTK_PIN_NO(80) | 3)
+#define PINMUX_GPIO80__FUNC_DBG_MON_A30 (MTK_PIN_NO(80) | 7)
+
+#define PINMUX_GPIO81__FUNC_GPIO81 (MTK_PIN_NO(81) | 0)
+#define PINMUX_GPIO81__FUNC_IDDIG (MTK_PIN_NO(81) | 1)
+#define PINMUX_GPIO81__FUNC_DBG_MON_B32 (MTK_PIN_NO(81) | 7)
+
+#define PINMUX_GPIO82__FUNC_GPIO82 (MTK_PIN_NO(82) | 0)
+#define PINMUX_GPIO82__FUNC_USB_DRVVBUS (MTK_PIN_NO(82) | 1)
+
+#define PINMUX_GPIO83__FUNC_GPIO83 (MTK_PIN_NO(83) | 0)
+#define PINMUX_GPIO83__FUNC_VBUSVALID (MTK_PIN_NO(83) | 1)
+
+#define PINMUX_GPIO84__FUNC_GPIO84 (MTK_PIN_NO(84) | 0)
+#define PINMUX_GPIO84__FUNC_USB_DRVVBUS_1P (MTK_PIN_NO(84) | 1)
+#define PINMUX_GPIO84__FUNC_DBG_MON_A16 (MTK_PIN_NO(84) | 7)
+
+#define PINMUX_GPIO85__FUNC_GPIO85 (MTK_PIN_NO(85) | 0)
+#define PINMUX_GPIO85__FUNC_USB_DRVVBUS_2P (MTK_PIN_NO(85) | 1)
+#define PINMUX_GPIO85__FUNC_DBG_MON_A17 (MTK_PIN_NO(85) | 7)
+
+#define PINMUX_GPIO86__FUNC_GPIO86 (MTK_PIN_NO(86) | 0)
+#define PINMUX_GPIO86__FUNC_USB_DRVVBUS_3P (MTK_PIN_NO(86) | 1)
+#define PINMUX_GPIO86__FUNC_DBG_MON_A18 (MTK_PIN_NO(86) | 7)
+
+#define PINMUX_GPIO87__FUNC_GPIO87 (MTK_PIN_NO(87) | 0)
+#define PINMUX_GPIO87__FUNC_USB_DRVVBUS_4P (MTK_PIN_NO(87) | 1)
+#define PINMUX_GPIO87__FUNC_CMVREF4 (MTK_PIN_NO(87) | 6)
+#define PINMUX_GPIO87__FUNC_DBG_MON_A19 (MTK_PIN_NO(87) | 7)
+
+#define PINMUX_GPIO88__FUNC_GPIO88 (MTK_PIN_NO(88) | 0)
+#define PINMUX_GPIO88__FUNC_PWRAP_SPI0_CSN (MTK_PIN_NO(88) | 1)
+
+#define PINMUX_GPIO89__FUNC_GPIO89 (MTK_PIN_NO(89) | 0)
+#define PINMUX_GPIO89__FUNC_PWRAP_SPI0_CK (MTK_PIN_NO(89) | 1)
+
+#define PINMUX_GPIO90__FUNC_GPIO90 (MTK_PIN_NO(90) | 0)
+#define PINMUX_GPIO90__FUNC_PWRAP_SPI0_MO (MTK_PIN_NO(90) | 1)
+
+#define PINMUX_GPIO91__FUNC_GPIO91 (MTK_PIN_NO(91) | 0)
+#define PINMUX_GPIO91__FUNC_PWRAP_SPI0_MI (MTK_PIN_NO(91) | 1)
+
+#define PINMUX_GPIO92__FUNC_GPIO92 (MTK_PIN_NO(92) | 0)
+#define PINMUX_GPIO92__FUNC_SRCLKENA0 (MTK_PIN_NO(92) | 1)
+
+#define PINMUX_GPIO93__FUNC_GPIO93 (MTK_PIN_NO(93) | 0)
+#define PINMUX_GPIO93__FUNC_SRCLKENA1 (MTK_PIN_NO(93) | 1)
+
+#define PINMUX_GPIO94__FUNC_GPIO94 (MTK_PIN_NO(94) | 0)
+#define PINMUX_GPIO94__FUNC_SCP_VREQ_VAO (MTK_PIN_NO(94) | 1)
+
+#define PINMUX_GPIO95__FUNC_GPIO95 (MTK_PIN_NO(95) | 0)
+#define PINMUX_GPIO95__FUNC_RTC32K_CK (MTK_PIN_NO(95) | 1)
+
+#define PINMUX_GPIO96__FUNC_GPIO96 (MTK_PIN_NO(96) | 0)
+#define PINMUX_GPIO96__FUNC_WATCHDOG (MTK_PIN_NO(96) | 1)
+
+#define PINMUX_GPIO97__FUNC_GPIO97 (MTK_PIN_NO(97) | 0)
+#define PINMUX_GPIO97__FUNC_AUD_CLK_MOSI (MTK_PIN_NO(97) | 1)
+
+#define PINMUX_GPIO98__FUNC_GPIO98 (MTK_PIN_NO(98) | 0)
+#define PINMUX_GPIO98__FUNC_AUD_SYNC_MOSI (MTK_PIN_NO(98) | 1)
+
+#define PINMUX_GPIO99__FUNC_GPIO99 (MTK_PIN_NO(99) | 0)
+#define PINMUX_GPIO99__FUNC_AUD_DAT_MOSI0 (MTK_PIN_NO(99) | 1)
+
+#define PINMUX_GPIO100__FUNC_GPIO100 (MTK_PIN_NO(100) | 0)
+#define PINMUX_GPIO100__FUNC_AUD_DAT_MOSI1 (MTK_PIN_NO(100) | 1)
+
+#define PINMUX_GPIO101__FUNC_GPIO101 (MTK_PIN_NO(101) | 0)
+#define PINMUX_GPIO101__FUNC_AUD_DAT_MISO0 (MTK_PIN_NO(101) | 1)
+
+#define PINMUX_GPIO102__FUNC_GPIO102 (MTK_PIN_NO(102) | 0)
+#define PINMUX_GPIO102__FUNC_AUD_DAT_MISO1 (MTK_PIN_NO(102) | 1)
+
+#define PINMUX_GPIO103__FUNC_GPIO103 (MTK_PIN_NO(103) | 0)
+#define PINMUX_GPIO103__FUNC_I2SIN0_MCK (MTK_PIN_NO(103) | 1)
+#define PINMUX_GPIO103__FUNC_SPIM3_B_CSB (MTK_PIN_NO(103) | 2)
+#define PINMUX_GPIO103__FUNC_APU_JTAG_TMS (MTK_PIN_NO(103) | 3)
+#define PINMUX_GPIO103__FUNC_SCP_JTAG0_TMS_VCORE (MTK_PIN_NO(103) | 4)
+#define PINMUX_GPIO103__FUNC_CONN_WF_MCU_TMS (MTK_PIN_NO(103) | 5)
+#define PINMUX_GPIO103__FUNC_SSPM_JTAG_TMS_VCORE (MTK_PIN_NO(103) | 6)
+#define PINMUX_GPIO103__FUNC_IPU_JTAG_TMS (MTK_PIN_NO(103) | 7)
+
+#define PINMUX_GPIO104__FUNC_GPIO104 (MTK_PIN_NO(104) | 0)
+#define PINMUX_GPIO104__FUNC_I2SIN0_BCK (MTK_PIN_NO(104) | 1)
+#define PINMUX_GPIO104__FUNC_SPIM3_B_CLK (MTK_PIN_NO(104) | 2)
+#define PINMUX_GPIO104__FUNC_APU_JTAG_TCK (MTK_PIN_NO(104) | 3)
+#define PINMUX_GPIO104__FUNC_SCP_JTAG0_TCK_VCORE (MTK_PIN_NO(104) | 4)
+#define PINMUX_GPIO104__FUNC_CONN_WF_MCU_TCK (MTK_PIN_NO(104) | 5)
+#define PINMUX_GPIO104__FUNC_SSPM_JTAG_TCK_VCORE (MTK_PIN_NO(104) | 6)
+#define PINMUX_GPIO104__FUNC_IPU_JTAG_TCK (MTK_PIN_NO(104) | 7)
+
+#define PINMUX_GPIO105__FUNC_GPIO105 (MTK_PIN_NO(105) | 0)
+#define PINMUX_GPIO105__FUNC_I2SIN0_LRCK (MTK_PIN_NO(105) | 1)
+#define PINMUX_GPIO105__FUNC_SPIM3_B_MO (MTK_PIN_NO(105) | 2)
+#define PINMUX_GPIO105__FUNC_APU_JTAG_TDI (MTK_PIN_NO(105) | 3)
+#define PINMUX_GPIO105__FUNC_SCP_JTAG0_TDI_VCORE (MTK_PIN_NO(105) | 4)
+#define PINMUX_GPIO105__FUNC_CONN_WF_MCU_TDI (MTK_PIN_NO(105) | 5)
+#define PINMUX_GPIO105__FUNC_SSPM_JTAG_TDI_VCORE (MTK_PIN_NO(105) | 6)
+#define PINMUX_GPIO105__FUNC_IPU_JTAG_TDI (MTK_PIN_NO(105) | 7)
+
+#define PINMUX_GPIO106__FUNC_GPIO106 (MTK_PIN_NO(106) | 0)
+#define PINMUX_GPIO106__FUNC_I2SIN0_DI (MTK_PIN_NO(106) | 1)
+#define PINMUX_GPIO106__FUNC_SPIM3_B_MI (MTK_PIN_NO(106) | 2)
+#define PINMUX_GPIO106__FUNC_APU_JTAG_TDO (MTK_PIN_NO(106) | 3)
+#define PINMUX_GPIO106__FUNC_SCP_JTAG0_TDO_VCORE (MTK_PIN_NO(106) | 4)
+#define PINMUX_GPIO106__FUNC_CONN_WF_MCU_TDO (MTK_PIN_NO(106) | 5)
+#define PINMUX_GPIO106__FUNC_SSPM_JTAG_TDO_VCORE (MTK_PIN_NO(106) | 6)
+#define PINMUX_GPIO106__FUNC_IPU_JTAG_TDO (MTK_PIN_NO(106) | 7)
+
+#define PINMUX_GPIO107__FUNC_GPIO107 (MTK_PIN_NO(107) | 0)
+#define PINMUX_GPIO107__FUNC_I2SOUT0_MCK (MTK_PIN_NO(107) | 1)
+#define PINMUX_GPIO107__FUNC_SPIM4_B_CSB (MTK_PIN_NO(107) | 2)
+#define PINMUX_GPIO107__FUNC_APU_JTAG_TRST (MTK_PIN_NO(107) | 3)
+#define PINMUX_GPIO107__FUNC_SCP_JTAG0_TRSTN_VCORE (MTK_PIN_NO(107) | 4)
+#define PINMUX_GPIO107__FUNC_CONN_WF_MCU_TRST_B (MTK_PIN_NO(107) | 5)
+#define PINMUX_GPIO107__FUNC_SSPM_JTAG_TRSTN_VCORE (MTK_PIN_NO(107) | 6)
+#define PINMUX_GPIO107__FUNC_IPU_JTAG_TRST (MTK_PIN_NO(107) | 7)
+
+#define PINMUX_GPIO108__FUNC_GPIO108 (MTK_PIN_NO(108) | 0)
+#define PINMUX_GPIO108__FUNC_I2SOUT0_BCK (MTK_PIN_NO(108) | 1)
+#define PINMUX_GPIO108__FUNC_SPIM4_B_CLK (MTK_PIN_NO(108) | 2)
+#define PINMUX_GPIO108__FUNC_EXTIF0_ACT (MTK_PIN_NO(108) | 3)
+#define PINMUX_GPIO108__FUNC_SPM_JTAG_TMS_VCORE (MTK_PIN_NO(108) | 4)
+#define PINMUX_GPIO108__FUNC_CLKM2 (MTK_PIN_NO(108) | 6)
+#define PINMUX_GPIO108__FUNC_DBG_MON_A20 (MTK_PIN_NO(108) | 7)
+
+#define PINMUX_GPIO109__FUNC_GPIO109 (MTK_PIN_NO(109) | 0)
+#define PINMUX_GPIO109__FUNC_I2SOUT0_LRCK (MTK_PIN_NO(109) | 1)
+#define PINMUX_GPIO109__FUNC_SPIM4_B_MO (MTK_PIN_NO(109) | 2)
+#define PINMUX_GPIO109__FUNC_EXTIF0_PRI (MTK_PIN_NO(109) | 3)
+#define PINMUX_GPIO109__FUNC_SPM_JTAG_TCK_VCORE (MTK_PIN_NO(109) | 4)
+#define PINMUX_GPIO109__FUNC_CLKM3 (MTK_PIN_NO(109) | 6)
+#define PINMUX_GPIO109__FUNC_DBG_MON_A21 (MTK_PIN_NO(109) | 7)
+
+#define PINMUX_GPIO110__FUNC_GPIO110 (MTK_PIN_NO(110) | 0)
+#define PINMUX_GPIO110__FUNC_I2SOUT0_DO (MTK_PIN_NO(110) | 1)
+#define PINMUX_GPIO110__FUNC_SPIM4_B_MI (MTK_PIN_NO(110) | 2)
+#define PINMUX_GPIO110__FUNC_EXTIF0_GNT_B (MTK_PIN_NO(110) | 3)
+#define PINMUX_GPIO110__FUNC_SPM_JTAG_TDI_VCORE (MTK_PIN_NO(110) | 4)
+#define PINMUX_GPIO110__FUNC_DBG_MON_A22 (MTK_PIN_NO(110) | 7)
+
+#define PINMUX_GPIO111__FUNC_GPIO111 (MTK_PIN_NO(111) | 0)
+#define PINMUX_GPIO111__FUNC_DMIC0_CLK (MTK_PIN_NO(111) | 1)
+#define PINMUX_GPIO111__FUNC_I2SIN1_MCK (MTK_PIN_NO(111) | 2)
+#define PINMUX_GPIO111__FUNC_I2SOUT1_MCK (MTK_PIN_NO(111) | 3)
+#define PINMUX_GPIO111__FUNC_SPM_JTAG_TDO_VCORE (MTK_PIN_NO(111) | 4)
+#define PINMUX_GPIO111__FUNC_CONN_MIPI0_SDATA (MTK_PIN_NO(111) | 6)
+#define PINMUX_GPIO111__FUNC_DBG_MON_A23 (MTK_PIN_NO(111) | 7)
+
+#define PINMUX_GPIO112__FUNC_GPIO112 (MTK_PIN_NO(112) | 0)
+#define PINMUX_GPIO112__FUNC_DMIC0_DAT0 (MTK_PIN_NO(112) | 1)
+#define PINMUX_GPIO112__FUNC_I2SIN1_BCK (MTK_PIN_NO(112) | 2)
+#define PINMUX_GPIO112__FUNC_I2SOUT1_BCK (MTK_PIN_NO(112) | 3)
+#define PINMUX_GPIO112__FUNC_SPM_JTAG_TRSTN_VCORE (MTK_PIN_NO(112) | 4)
+#define PINMUX_GPIO112__FUNC_CONN_MIPI0_SCLK (MTK_PIN_NO(112) | 6)
+#define PINMUX_GPIO112__FUNC_DBG_MON_A24 (MTK_PIN_NO(112) | 7)
+
+#define PINMUX_GPIO113__FUNC_GPIO113 (MTK_PIN_NO(113) | 0)
+#define PINMUX_GPIO113__FUNC_DMIC1_CLK (MTK_PIN_NO(113) | 1)
+#define PINMUX_GPIO113__FUNC_I2SIN1_LRCK (MTK_PIN_NO(113) | 2)
+#define PINMUX_GPIO113__FUNC_I2SOUT1_LRCK (MTK_PIN_NO(113) | 3)
+#define PINMUX_GPIO113__FUNC_PMSR_SMAP (MTK_PIN_NO(113) | 4)
+#define PINMUX_GPIO113__FUNC_CONN_MIPI1_SDATA (MTK_PIN_NO(113) | 6)
+#define PINMUX_GPIO113__FUNC_DBG_MON_A25 (MTK_PIN_NO(113) | 7)
+
+#define PINMUX_GPIO114__FUNC_GPIO114 (MTK_PIN_NO(114) | 0)
+#define PINMUX_GPIO114__FUNC_DMIC1_DAT0 (MTK_PIN_NO(114) | 1)
+#define PINMUX_GPIO114__FUNC_I2SIN1_DI (MTK_PIN_NO(114) | 2)
+#define PINMUX_GPIO114__FUNC_I2SOUT1_DO (MTK_PIN_NO(114) | 3)
+#define PINMUX_GPIO114__FUNC_CONN_MIPI1_SCLK (MTK_PIN_NO(114) | 6)
+#define PINMUX_GPIO114__FUNC_DBG_MON_A26 (MTK_PIN_NO(114) | 7)
+
+#define PINMUX_GPIO115__FUNC_GPIO115 (MTK_PIN_NO(115) | 0)
+#define PINMUX_GPIO115__FUNC_PCM0_CLK (MTK_PIN_NO(115) | 1)
+#define PINMUX_GPIO115__FUNC_USB_DRVVBUS_1P (MTK_PIN_NO(115) | 2)
+#define PINMUX_GPIO115__FUNC_PCIE_PHY_I2C_SCL (MTK_PIN_NO(115) | 3)
+#define PINMUX_GPIO115__FUNC_SSUSB_U3PHY_I2C_SCL (MTK_PIN_NO(115) | 4)
+#define PINMUX_GPIO115__FUNC_CMFLASH0 (MTK_PIN_NO(115) | 6)
+#define PINMUX_GPIO115__FUNC_EXTIF0_ACT (MTK_PIN_NO(115) | 7)
+
+#define PINMUX_GPIO116__FUNC_GPIO116 (MTK_PIN_NO(116) | 0)
+#define PINMUX_GPIO116__FUNC_PCM0_SYNC (MTK_PIN_NO(116) | 1)
+#define PINMUX_GPIO116__FUNC_USB_DRVVBUS_2P (MTK_PIN_NO(116) | 2)
+#define PINMUX_GPIO116__FUNC_PCIE_PHY_I2C_SDA (MTK_PIN_NO(116) | 3)
+#define PINMUX_GPIO116__FUNC_SSUSB_U3PHY_I2C_SDA (MTK_PIN_NO(116) | 4)
+#define PINMUX_GPIO116__FUNC_CMFLASH1 (MTK_PIN_NO(116) | 6)
+#define PINMUX_GPIO116__FUNC_EXTIF0_PRI (MTK_PIN_NO(116) | 7)
+
+#define PINMUX_GPIO117__FUNC_GPIO117 (MTK_PIN_NO(117) | 0)
+#define PINMUX_GPIO117__FUNC_PCM0_DI (MTK_PIN_NO(117) | 1)
+#define PINMUX_GPIO117__FUNC_USB_DRVVBUS_3P (MTK_PIN_NO(117) | 2)
+#define PINMUX_GPIO117__FUNC_DP_TX_HPD (MTK_PIN_NO(117) | 3)
+#define PINMUX_GPIO117__FUNC_SSPXTP_U3PHY_I2C_SCL (MTK_PIN_NO(117) | 4)
+#define PINMUX_GPIO117__FUNC_CMVREF0 (MTK_PIN_NO(117) | 6)
+#define PINMUX_GPIO117__FUNC_EXTIF0_GNT_B (MTK_PIN_NO(117) | 7)
+
+#define PINMUX_GPIO118__FUNC_GPIO118 (MTK_PIN_NO(118) | 0)
+#define PINMUX_GPIO118__FUNC_PCM0_DO (MTK_PIN_NO(118) | 1)
+#define PINMUX_GPIO118__FUNC_USB_DRVVBUS_4P (MTK_PIN_NO(118) | 2)
+#define PINMUX_GPIO118__FUNC_EDP_TX_HPD (MTK_PIN_NO(118) | 3)
+#define PINMUX_GPIO118__FUNC_SSPXTP_U3PHY_I2C_SDA (MTK_PIN_NO(118) | 4)
+#define PINMUX_GPIO118__FUNC_CMVREF1 (MTK_PIN_NO(118) | 6)
+
+#define PINMUX_GPIO119__FUNC_GPIO119 (MTK_PIN_NO(119) | 0)
+#define PINMUX_GPIO119__FUNC_GBE_TXD3 (MTK_PIN_NO(119) | 1)
+#define PINMUX_GPIO119__FUNC_DMIC0_CLK (MTK_PIN_NO(119) | 2)
+#define PINMUX_GPIO119__FUNC_LVTS_FOUT (MTK_PIN_NO(119) | 3)
+#define PINMUX_GPIO119__FUNC_CONN_BGF_MCU_TMS (MTK_PIN_NO(119) | 4)
+#define PINMUX_GPIO119__FUNC_UDI_TMS (MTK_PIN_NO(119) | 5)
+#define PINMUX_GPIO119__FUNC_ANT_SEL5 (MTK_PIN_NO(119) | 6)
+#define PINMUX_GPIO119__FUNC_DBG_MON_B0 (MTK_PIN_NO(119) | 7)
+
+#define PINMUX_GPIO120__FUNC_GPIO120 (MTK_PIN_NO(120) | 0)
+#define PINMUX_GPIO120__FUNC_GBE_TXD2 (MTK_PIN_NO(120) | 1)
+#define PINMUX_GPIO120__FUNC_DMIC0_DAT0 (MTK_PIN_NO(120) | 2)
+#define PINMUX_GPIO120__FUNC_LVTS_SDO (MTK_PIN_NO(120) | 3)
+#define PINMUX_GPIO120__FUNC_CONN_BGF_MCU_TCK (MTK_PIN_NO(120) | 4)
+#define PINMUX_GPIO120__FUNC_UDI_TCK (MTK_PIN_NO(120) | 5)
+#define PINMUX_GPIO120__FUNC_ANT_SEL6 (MTK_PIN_NO(120) | 6)
+#define PINMUX_GPIO120__FUNC_DBG_MON_B1 (MTK_PIN_NO(120) | 7)
+
+#define PINMUX_GPIO121__FUNC_GPIO121 (MTK_PIN_NO(121) | 0)
+#define PINMUX_GPIO121__FUNC_GBE_TXD1 (MTK_PIN_NO(121) | 1)
+#define PINMUX_GPIO121__FUNC_DMIC0_DAT1 (MTK_PIN_NO(121) | 2)
+#define PINMUX_GPIO121__FUNC_LVTS_26M (MTK_PIN_NO(121) | 3)
+#define PINMUX_GPIO121__FUNC_CONN_BGF_MCU_TDI (MTK_PIN_NO(121) | 4)
+#define PINMUX_GPIO121__FUNC_UDI_TDI (MTK_PIN_NO(121) | 5)
+#define PINMUX_GPIO121__FUNC_ANT_SEL7 (MTK_PIN_NO(121) | 6)
+#define PINMUX_GPIO121__FUNC_DBG_MON_B2 (MTK_PIN_NO(121) | 7)
+
+#define PINMUX_GPIO122__FUNC_GPIO122 (MTK_PIN_NO(122) | 0)
+#define PINMUX_GPIO122__FUNC_GBE_TXD0 (MTK_PIN_NO(122) | 1)
+#define PINMUX_GPIO122__FUNC_DMIC1_CLK (MTK_PIN_NO(122) | 2)
+#define PINMUX_GPIO122__FUNC_LVTS_SCF (MTK_PIN_NO(122) | 3)
+#define PINMUX_GPIO122__FUNC_CONN_BGF_MCU_TDO (MTK_PIN_NO(122) | 4)
+#define PINMUX_GPIO122__FUNC_UDI_TDO (MTK_PIN_NO(122) | 5)
+#define PINMUX_GPIO122__FUNC_ANT_SEL8 (MTK_PIN_NO(122) | 6)
+#define PINMUX_GPIO122__FUNC_DBG_MON_B3 (MTK_PIN_NO(122) | 7)
+
+#define PINMUX_GPIO123__FUNC_GPIO123 (MTK_PIN_NO(123) | 0)
+#define PINMUX_GPIO123__FUNC_GBE_RXD3 (MTK_PIN_NO(123) | 1)
+#define PINMUX_GPIO123__FUNC_DMIC1_DAT0 (MTK_PIN_NO(123) | 2)
+#define PINMUX_GPIO123__FUNC_LVTS_SCK (MTK_PIN_NO(123) | 3)
+#define PINMUX_GPIO123__FUNC_CONN_BGF_MCU_TRST_B (MTK_PIN_NO(123) | 4)
+#define PINMUX_GPIO123__FUNC_UDI_NTRST (MTK_PIN_NO(123) | 5)
+#define PINMUX_GPIO123__FUNC_ANT_SEL9 (MTK_PIN_NO(123) | 6)
+#define PINMUX_GPIO123__FUNC_DBG_MON_B4 (MTK_PIN_NO(123) | 7)
+
+#define PINMUX_GPIO124__FUNC_GPIO124 (MTK_PIN_NO(124) | 0)
+#define PINMUX_GPIO124__FUNC_GBE_RXD2 (MTK_PIN_NO(124) | 1)
+#define PINMUX_GPIO124__FUNC_DMIC1_DAT1 (MTK_PIN_NO(124) | 2)
+#define PINMUX_GPIO124__FUNC_LVTS_SDI (MTK_PIN_NO(124) | 3)
+#define PINMUX_GPIO124__FUNC_CONN_WF_MCU_TMS (MTK_PIN_NO(124) | 4)
+#define PINMUX_GPIO124__FUNC_SCP_JTAG0_TMS_VCORE (MTK_PIN_NO(124) | 5)
+#define PINMUX_GPIO124__FUNC_ANT_SEL10 (MTK_PIN_NO(124) | 6)
+#define PINMUX_GPIO124__FUNC_DBG_MON_B5 (MTK_PIN_NO(124) | 7)
+
+#define PINMUX_GPIO125__FUNC_GPIO125 (MTK_PIN_NO(125) | 0)
+#define PINMUX_GPIO125__FUNC_GBE_RXD1 (MTK_PIN_NO(125) | 1)
+#define PINMUX_GPIO125__FUNC_CLKM2 (MTK_PIN_NO(125) | 2)
+#define PINMUX_GPIO125__FUNC_CONN_WF_MCU_TCK (MTK_PIN_NO(125) | 4)
+#define PINMUX_GPIO125__FUNC_SCP_JTAG0_TCK_VCORE (MTK_PIN_NO(125) | 5)
+#define PINMUX_GPIO125__FUNC_ANT_SEL11 (MTK_PIN_NO(125) | 6)
+#define PINMUX_GPIO125__FUNC_DBG_MON_B6 (MTK_PIN_NO(125) | 7)
+
+#define PINMUX_GPIO126__FUNC_GPIO126 (MTK_PIN_NO(126) | 0)
+#define PINMUX_GPIO126__FUNC_GBE_RXD0 (MTK_PIN_NO(126) | 1)
+#define PINMUX_GPIO126__FUNC_CLKM3 (MTK_PIN_NO(126) | 2)
+#define PINMUX_GPIO126__FUNC_CONN_WF_MCU_TDI (MTK_PIN_NO(126) | 4)
+#define PINMUX_GPIO126__FUNC_SCP_JTAG0_TDI_VCORE (MTK_PIN_NO(126) | 5)
+#define PINMUX_GPIO126__FUNC_ANT_SEL12 (MTK_PIN_NO(126) | 6)
+#define PINMUX_GPIO126__FUNC_DBG_MON_B7 (MTK_PIN_NO(126) | 7)
+
+#define PINMUX_GPIO127__FUNC_GPIO127 (MTK_PIN_NO(127) | 0)
+#define PINMUX_GPIO127__FUNC_GBE_TXC (MTK_PIN_NO(127) | 1)
+#define PINMUX_GPIO127__FUNC_I2SIN1_MCK (MTK_PIN_NO(127) | 2)
+#define PINMUX_GPIO127__FUNC_CONN_WF_MCU_TDO (MTK_PIN_NO(127) | 4)
+#define PINMUX_GPIO127__FUNC_SCP_JTAG0_TDO_VCORE (MTK_PIN_NO(127) | 5)
+#define PINMUX_GPIO127__FUNC_ANT_SEL13 (MTK_PIN_NO(127) | 6)
+#define PINMUX_GPIO127__FUNC_DBG_MON_B8 (MTK_PIN_NO(127) | 7)
+
+#define PINMUX_GPIO128__FUNC_GPIO128 (MTK_PIN_NO(128) | 0)
+#define PINMUX_GPIO128__FUNC_GBE_RXC (MTK_PIN_NO(128) | 1)
+#define PINMUX_GPIO128__FUNC_I2SIN1_BCK (MTK_PIN_NO(128) | 2)
+#define PINMUX_GPIO128__FUNC_CONN_WF_MCU_TRST_B (MTK_PIN_NO(128) | 4)
+#define PINMUX_GPIO128__FUNC_SCP_JTAG0_TRSTN_VCORE (MTK_PIN_NO(128) | 5)
+#define PINMUX_GPIO128__FUNC_ANT_SEL14 (MTK_PIN_NO(128) | 6)
+#define PINMUX_GPIO128__FUNC_DBG_MON_B9 (MTK_PIN_NO(128) | 7)
+
+#define PINMUX_GPIO129__FUNC_GPIO129 (MTK_PIN_NO(129) | 0)
+#define PINMUX_GPIO129__FUNC_GBE_RXDV (MTK_PIN_NO(129) | 1)
+#define PINMUX_GPIO129__FUNC_I2SIN1_LRCK (MTK_PIN_NO(129) | 2)
+#define PINMUX_GPIO129__FUNC_CONN_BGF_MCU_AICE_TMSC (MTK_PIN_NO(129) | 4)
+#define PINMUX_GPIO129__FUNC_IPU_JTAG_TMS (MTK_PIN_NO(129) | 5)
+#define PINMUX_GPIO129__FUNC_ANT_SEL15 (MTK_PIN_NO(129) | 6)
+#define PINMUX_GPIO129__FUNC_DBG_MON_B10 (MTK_PIN_NO(129) | 7)
+
+#define PINMUX_GPIO130__FUNC_GPIO130 (MTK_PIN_NO(130) | 0)
+#define PINMUX_GPIO130__FUNC_GBE_TXEN (MTK_PIN_NO(130) | 1)
+#define PINMUX_GPIO130__FUNC_I2SIN1_DI (MTK_PIN_NO(130) | 2)
+#define PINMUX_GPIO130__FUNC_CONN_BGF_MCU_AICE_TCKC (MTK_PIN_NO(130) | 4)
+#define PINMUX_GPIO130__FUNC_IPU_JTAG_TCK (MTK_PIN_NO(130) | 5)
+#define PINMUX_GPIO130__FUNC_ANT_SEL16 (MTK_PIN_NO(130) | 6)
+#define PINMUX_GPIO130__FUNC_DBG_MON_B11 (MTK_PIN_NO(130) | 7)
+
+#define PINMUX_GPIO131__FUNC_GPIO131 (MTK_PIN_NO(131) | 0)
+#define PINMUX_GPIO131__FUNC_GBE_MDC (MTK_PIN_NO(131) | 1)
+#define PINMUX_GPIO131__FUNC_CLKM0 (MTK_PIN_NO(131) | 2)
+#define PINMUX_GPIO131__FUNC_MBISTREADEN_TRIGGER (MTK_PIN_NO(131) | 3)
+#define PINMUX_GPIO131__FUNC_CONN_BGF_UART0_TXD (MTK_PIN_NO(131) | 4)
+#define PINMUX_GPIO131__FUNC_IPU_JTAG_TDI (MTK_PIN_NO(131) | 5)
+#define PINMUX_GPIO131__FUNC_ANT_SEL17 (MTK_PIN_NO(131) | 6)
+#define PINMUX_GPIO131__FUNC_DBG_MON_B12 (MTK_PIN_NO(131) | 7)
+
+#define PINMUX_GPIO132__FUNC_GPIO132 (MTK_PIN_NO(132) | 0)
+#define PINMUX_GPIO132__FUNC_GBE_MDIO (MTK_PIN_NO(132) | 1)
+#define PINMUX_GPIO132__FUNC_CLKM1 (MTK_PIN_NO(132) | 2)
+#define PINMUX_GPIO132__FUNC_MBISTWRITEEN_TRIGGER (MTK_PIN_NO(132) | 3)
+#define PINMUX_GPIO132__FUNC_CONN_BGF_UART0_RXD (MTK_PIN_NO(132) | 4)
+#define PINMUX_GPIO132__FUNC_IPU_JTAG_TDO (MTK_PIN_NO(132) | 5)
+#define PINMUX_GPIO132__FUNC_ANT_SEL18 (MTK_PIN_NO(132) | 6)
+#define PINMUX_GPIO132__FUNC_DBG_MON_B13 (MTK_PIN_NO(132) | 7)
+
+#define PINMUX_GPIO133__FUNC_GPIO133 (MTK_PIN_NO(133) | 0)
+#define PINMUX_GPIO133__FUNC_GBE_TXER (MTK_PIN_NO(133) | 1)
+#define PINMUX_GPIO133__FUNC_GBE_AUX_PPS2 (MTK_PIN_NO(133) | 2)
+#define PINMUX_GPIO133__FUNC_CONN_BT_TXD (MTK_PIN_NO(133) | 4)
+#define PINMUX_GPIO133__FUNC_IPU_JTAG_TRST (MTK_PIN_NO(133) | 5)
+#define PINMUX_GPIO133__FUNC_ANT_SEL19 (MTK_PIN_NO(133) | 6)
+#define PINMUX_GPIO133__FUNC_DBG_MON_B14 (MTK_PIN_NO(133) | 7)
+
+#define PINMUX_GPIO134__FUNC_GPIO134 (MTK_PIN_NO(134) | 0)
+#define PINMUX_GPIO134__FUNC_GBE_RXER (MTK_PIN_NO(134) | 1)
+#define PINMUX_GPIO134__FUNC_GBE_AUX_PPS3 (MTK_PIN_NO(134) | 2)
+#define PINMUX_GPIO134__FUNC_MCUPM_JTAG_TMS (MTK_PIN_NO(134) | 3)
+#define PINMUX_GPIO134__FUNC_CONN_WF_MCU_AICE_TMSC (MTK_PIN_NO(134) | 4)
+#define PINMUX_GPIO134__FUNC_APU_JTAG_TMS (MTK_PIN_NO(134) | 5)
+#define PINMUX_GPIO134__FUNC_ANT_SEL20 (MTK_PIN_NO(134) | 6)
+#define PINMUX_GPIO134__FUNC_DBG_MON_B15 (MTK_PIN_NO(134) | 7)
+
+#define PINMUX_GPIO135__FUNC_GPIO135 (MTK_PIN_NO(135) | 0)
+#define PINMUX_GPIO135__FUNC_GBE_COL (MTK_PIN_NO(135) | 1)
+#define PINMUX_GPIO135__FUNC_I2SOUT1_MCK (MTK_PIN_NO(135) | 2)
+#define PINMUX_GPIO135__FUNC_MCUPM_JTAG_TCK (MTK_PIN_NO(135) | 3)
+#define PINMUX_GPIO135__FUNC_CONN_WF_MCU_AICE_TCKC (MTK_PIN_NO(135) | 4)
+#define PINMUX_GPIO135__FUNC_APU_JTAG_TCK (MTK_PIN_NO(135) | 5)
+#define PINMUX_GPIO135__FUNC_ANT_SEL21 (MTK_PIN_NO(135) | 6)
+#define PINMUX_GPIO135__FUNC_DBG_MON_B16 (MTK_PIN_NO(135) | 7)
+
+#define PINMUX_GPIO136__FUNC_GPIO136 (MTK_PIN_NO(136) | 0)
+#define PINMUX_GPIO136__FUNC_GBE_INTR (MTK_PIN_NO(136) | 1)
+#define PINMUX_GPIO136__FUNC_I2SOUT1_BCK (MTK_PIN_NO(136) | 2)
+#define PINMUX_GPIO136__FUNC_MCUPM_JTAG_TDI (MTK_PIN_NO(136) | 3)
+#define PINMUX_GPIO136__FUNC_CONN_WIFI_TXD (MTK_PIN_NO(136) | 4)
+#define PINMUX_GPIO136__FUNC_APU_JTAG_TDI (MTK_PIN_NO(136) | 5)
+#define PINMUX_GPIO136__FUNC_PWM_0 (MTK_PIN_NO(136) | 6)
+#define PINMUX_GPIO136__FUNC_DBG_MON_B17 (MTK_PIN_NO(136) | 7)
+
+#define PINMUX_GPIO137__FUNC_GPIO137 (MTK_PIN_NO(137) | 0)
+#define PINMUX_GPIO137__FUNC_GBE_AUX_PPS0 (MTK_PIN_NO(137) | 1)
+#define PINMUX_GPIO137__FUNC_I2SOUT1_LRCK (MTK_PIN_NO(137) | 2)
+#define PINMUX_GPIO137__FUNC_MCUPM_JTAG_TDO (MTK_PIN_NO(137) | 3)
+#define PINMUX_GPIO137__FUNC_DP_TX_HPD (MTK_PIN_NO(137) | 4)
+#define PINMUX_GPIO137__FUNC_APU_JTAG_TDO (MTK_PIN_NO(137) | 5)
+#define PINMUX_GPIO137__FUNC_PWM_1 (MTK_PIN_NO(137) | 6)
+#define PINMUX_GPIO137__FUNC_DBG_MON_B18 (MTK_PIN_NO(137) | 7)
+
+#define PINMUX_GPIO138__FUNC_GPIO138 (MTK_PIN_NO(138) | 0)
+#define PINMUX_GPIO138__FUNC_GBE_AUX_PPS1 (MTK_PIN_NO(138) | 1)
+#define PINMUX_GPIO138__FUNC_I2SOUT1_DO (MTK_PIN_NO(138) | 2)
+#define PINMUX_GPIO138__FUNC_MCUPM_JTAG_TRSTN (MTK_PIN_NO(138) | 3)
+#define PINMUX_GPIO138__FUNC_EDP_TX_HPD (MTK_PIN_NO(138) | 4)
+#define PINMUX_GPIO138__FUNC_APU_JTAG_TRST (MTK_PIN_NO(138) | 5)
+#define PINMUX_GPIO138__FUNC_PWM_2 (MTK_PIN_NO(138) | 6)
+#define PINMUX_GPIO138__FUNC_DBG_MON_B19 (MTK_PIN_NO(138) | 7)
+
+#define PINMUX_GPIO139__FUNC_GPIO139 (MTK_PIN_NO(139) | 0)
+#define PINMUX_GPIO139__FUNC_CONN_TOP_CLK (MTK_PIN_NO(139) | 1)
+
+#define PINMUX_GPIO140__FUNC_GPIO140 (MTK_PIN_NO(140) | 0)
+#define PINMUX_GPIO140__FUNC_CONN_TOP_DATA (MTK_PIN_NO(140) | 1)
+
+#define PINMUX_GPIO141__FUNC_GPIO141 (MTK_PIN_NO(141) | 0)
+#define PINMUX_GPIO141__FUNC_CONN_BT_CLK (MTK_PIN_NO(141) | 1)
+
+#define PINMUX_GPIO142__FUNC_GPIO142 (MTK_PIN_NO(142) | 0)
+#define PINMUX_GPIO142__FUNC_CONN_BT_DATA (MTK_PIN_NO(142) | 1)
+
+#define PINMUX_GPIO143__FUNC_GPIO143 (MTK_PIN_NO(143) | 0)
+#define PINMUX_GPIO143__FUNC_CONN_HRST_B (MTK_PIN_NO(143) | 1)
+
+#define PINMUX_GPIO144__FUNC_GPIO144 (MTK_PIN_NO(144) | 0)
+#define PINMUX_GPIO144__FUNC_CONN_WB_PTA (MTK_PIN_NO(144) | 1)
+
+#define PINMUX_GPIO145__FUNC_GPIO145 (MTK_PIN_NO(145) | 0)
+#define PINMUX_GPIO145__FUNC_CONN_WF_CTRL0 (MTK_PIN_NO(145) | 1)
+
+#define PINMUX_GPIO146__FUNC_GPIO146 (MTK_PIN_NO(146) | 0)
+#define PINMUX_GPIO146__FUNC_CONN_WF_CTRL1 (MTK_PIN_NO(146) | 1)
+
+#define PINMUX_GPIO147__FUNC_GPIO147 (MTK_PIN_NO(147) | 0)
+#define PINMUX_GPIO147__FUNC_CONN_WF_CTRL2 (MTK_PIN_NO(147) | 1)
+
+#define PINMUX_GPIO148__FUNC_GPIO148 (MTK_PIN_NO(148) | 0)
+#define PINMUX_GPIO148__FUNC_CONN_WF_CTRL3 (MTK_PIN_NO(148) | 1)
+
+#define PINMUX_GPIO149__FUNC_GPIO149 (MTK_PIN_NO(149) | 0)
+#define PINMUX_GPIO149__FUNC_CONN_WF_CTRL4 (MTK_PIN_NO(149) | 1)
+
+#define PINMUX_GPIO150__FUNC_GPIO150 (MTK_PIN_NO(150) | 0)
+#define PINMUX_GPIO150__FUNC_SPINOR_CK (MTK_PIN_NO(150) | 1)
+#define PINMUX_GPIO150__FUNC_DMIC0_CLK (MTK_PIN_NO(150) | 2)
+#define PINMUX_GPIO150__FUNC_DP_TX_HPD (MTK_PIN_NO(150) | 3)
+#define PINMUX_GPIO150__FUNC_PWM_0 (MTK_PIN_NO(150) | 4)
+#define PINMUX_GPIO150__FUNC_CONN_BPI_BUS17_ANT0 (MTK_PIN_NO(150) | 5)
+#define PINMUX_GPIO150__FUNC_LVTS_FOUT (MTK_PIN_NO(150) | 6)
+#define PINMUX_GPIO150__FUNC_DBG_MON_B26 (MTK_PIN_NO(150) | 7)
+
+#define PINMUX_GPIO151__FUNC_GPIO151 (MTK_PIN_NO(151) | 0)
+#define PINMUX_GPIO151__FUNC_SPINOR_CS (MTK_PIN_NO(151) | 1)
+#define PINMUX_GPIO151__FUNC_DMIC0_DAT0 (MTK_PIN_NO(151) | 2)
+#define PINMUX_GPIO151__FUNC_EDP_TX_HPD (MTK_PIN_NO(151) | 3)
+#define PINMUX_GPIO151__FUNC_PWM_1 (MTK_PIN_NO(151) | 4)
+#define PINMUX_GPIO151__FUNC_CONN_BPI_BUS18_ANT1 (MTK_PIN_NO(151) | 5)
+#define PINMUX_GPIO151__FUNC_LVTS_SDO (MTK_PIN_NO(151) | 6)
+#define PINMUX_GPIO151__FUNC_DBG_MON_B27 (MTK_PIN_NO(151) | 7)
+
+#define PINMUX_GPIO152__FUNC_GPIO152 (MTK_PIN_NO(152) | 0)
+#define PINMUX_GPIO152__FUNC_SPINOR_IO0 (MTK_PIN_NO(152) | 1)
+#define PINMUX_GPIO152__FUNC_DMIC0_DAT1 (MTK_PIN_NO(152) | 2)
+#define PINMUX_GPIO152__FUNC_UTXD2 (MTK_PIN_NO(152) | 3)
+#define PINMUX_GPIO152__FUNC_USB_DRVVBUS_1P (MTK_PIN_NO(152) | 4)
+#define PINMUX_GPIO152__FUNC_CONN_BPI_BUS19_ANT2 (MTK_PIN_NO(152) | 5)
+#define PINMUX_GPIO152__FUNC_LVTS_26M (MTK_PIN_NO(152) | 6)
+#define PINMUX_GPIO152__FUNC_DBG_MON_B28 (MTK_PIN_NO(152) | 7)
+
+#define PINMUX_GPIO153__FUNC_GPIO153 (MTK_PIN_NO(153) | 0)
+#define PINMUX_GPIO153__FUNC_SPINOR_IO1 (MTK_PIN_NO(153) | 1)
+#define PINMUX_GPIO153__FUNC_DMIC1_CLK (MTK_PIN_NO(153) | 2)
+#define PINMUX_GPIO153__FUNC_UCTS2 (MTK_PIN_NO(153) | 3)
+#define PINMUX_GPIO153__FUNC_USB_DRVVBUS_2P (MTK_PIN_NO(153) | 4)
+#define PINMUX_GPIO153__FUNC_CONN_BPI_BUS20_ANT3 (MTK_PIN_NO(153) | 5)
+#define PINMUX_GPIO153__FUNC_LVTS_SCF (MTK_PIN_NO(153) | 6)
+#define PINMUX_GPIO153__FUNC_DBG_MON_B29 (MTK_PIN_NO(153) | 7)
+
+#define PINMUX_GPIO154__FUNC_GPIO154 (MTK_PIN_NO(154) | 0)
+#define PINMUX_GPIO154__FUNC_SPINOR_IO2 (MTK_PIN_NO(154) | 1)
+#define PINMUX_GPIO154__FUNC_DMIC1_DAT0 (MTK_PIN_NO(154) | 2)
+#define PINMUX_GPIO154__FUNC_URTS2 (MTK_PIN_NO(154) | 3)
+#define PINMUX_GPIO154__FUNC_USB_DRVVBUS_3P (MTK_PIN_NO(154) | 4)
+#define PINMUX_GPIO154__FUNC_CONN_BPI_BUS21_ANT4 (MTK_PIN_NO(154) | 5)
+#define PINMUX_GPIO154__FUNC_LVTS_SCK (MTK_PIN_NO(154) | 6)
+#define PINMUX_GPIO154__FUNC_DBG_MON_B30 (MTK_PIN_NO(154) | 7)
+
+#define PINMUX_GPIO155__FUNC_GPIO155 (MTK_PIN_NO(155) | 0)
+#define PINMUX_GPIO155__FUNC_SPINOR_IO3 (MTK_PIN_NO(155) | 1)
+#define PINMUX_GPIO155__FUNC_DMIC1_DAT1 (MTK_PIN_NO(155) | 2)
+#define PINMUX_GPIO155__FUNC_URXD2 (MTK_PIN_NO(155) | 3)
+#define PINMUX_GPIO155__FUNC_USB_DRVVBUS_4P (MTK_PIN_NO(155) | 4)
+#define PINMUX_GPIO155__FUNC_DISP_PWM1 (MTK_PIN_NO(155) | 5)
+#define PINMUX_GPIO155__FUNC_LVTS_SDI (MTK_PIN_NO(155) | 6)
+#define PINMUX_GPIO155__FUNC_DBG_MON_B31 (MTK_PIN_NO(155) | 7)
+
+#define PINMUX_GPIO156__FUNC_GPIO156 (MTK_PIN_NO(156) | 0)
+#define PINMUX_GPIO156__FUNC_MSDC0_DAT7 (MTK_PIN_NO(156) | 1)
+
+#define PINMUX_GPIO157__FUNC_GPIO157 (MTK_PIN_NO(157) | 0)
+#define PINMUX_GPIO157__FUNC_MSDC0_DAT6 (MTK_PIN_NO(157) | 1)
+
+#define PINMUX_GPIO158__FUNC_GPIO158 (MTK_PIN_NO(158) | 0)
+#define PINMUX_GPIO158__FUNC_MSDC0_DAT5 (MTK_PIN_NO(158) | 1)
+
+#define PINMUX_GPIO159__FUNC_GPIO159 (MTK_PIN_NO(159) | 0)
+#define PINMUX_GPIO159__FUNC_MSDC0_DAT4 (MTK_PIN_NO(159) | 1)
+
+#define PINMUX_GPIO160__FUNC_GPIO160 (MTK_PIN_NO(160) | 0)
+#define PINMUX_GPIO160__FUNC_MSDC0_RSTB (MTK_PIN_NO(160) | 1)
+
+#define PINMUX_GPIO161__FUNC_GPIO161 (MTK_PIN_NO(161) | 0)
+#define PINMUX_GPIO161__FUNC_MSDC0_CMD (MTK_PIN_NO(161) | 1)
+
+#define PINMUX_GPIO162__FUNC_GPIO162 (MTK_PIN_NO(162) | 0)
+#define PINMUX_GPIO162__FUNC_MSDC0_CLK (MTK_PIN_NO(162) | 1)
+
+#define PINMUX_GPIO163__FUNC_GPIO163 (MTK_PIN_NO(163) | 0)
+#define PINMUX_GPIO163__FUNC_MSDC0_DAT3 (MTK_PIN_NO(163) | 1)
+
+#define PINMUX_GPIO164__FUNC_GPIO164 (MTK_PIN_NO(164) | 0)
+#define PINMUX_GPIO164__FUNC_MSDC0_DAT2 (MTK_PIN_NO(164) | 1)
+
+#define PINMUX_GPIO165__FUNC_GPIO165 (MTK_PIN_NO(165) | 0)
+#define PINMUX_GPIO165__FUNC_MSDC0_DAT1 (MTK_PIN_NO(165) | 1)
+
+#define PINMUX_GPIO166__FUNC_GPIO166 (MTK_PIN_NO(166) | 0)
+#define PINMUX_GPIO166__FUNC_MSDC0_DAT0 (MTK_PIN_NO(166) | 1)
+
+#define PINMUX_GPIO167__FUNC_GPIO167 (MTK_PIN_NO(167) | 0)
+#define PINMUX_GPIO167__FUNC_MSDC0_DSL (MTK_PIN_NO(167) | 1)
+
+#define PINMUX_GPIO168__FUNC_GPIO168 (MTK_PIN_NO(168) | 0)
+#define PINMUX_GPIO168__FUNC_MSDC1_CMD (MTK_PIN_NO(168) | 1)
+#define PINMUX_GPIO168__FUNC_CONN_WF_MCU_AICE_TMSC (MTK_PIN_NO(168) | 2)
+#define PINMUX_GPIO168__FUNC_UCTS1 (MTK_PIN_NO(168) | 3)
+#define PINMUX_GPIO168__FUNC_UDI_TMS (MTK_PIN_NO(168) | 4)
+#define PINMUX_GPIO168__FUNC_SSPM_JTAG_TMS_VCORE (MTK_PIN_NO(168) | 5)
+#define PINMUX_GPIO168__FUNC_MCUPM_JTAG_TMS (MTK_PIN_NO(168) | 6)
+#define PINMUX_GPIO168__FUNC_CONN_BGF_MCU_TMS (MTK_PIN_NO(168) | 7)
+
+#define PINMUX_GPIO169__FUNC_GPIO169 (MTK_PIN_NO(169) | 0)
+#define PINMUX_GPIO169__FUNC_MSDC1_CLK (MTK_PIN_NO(169) | 1)
+#define PINMUX_GPIO169__FUNC_CONN_WF_MCU_AICE_TCKC (MTK_PIN_NO(169) | 2)
+#define PINMUX_GPIO169__FUNC_URTS1 (MTK_PIN_NO(169) | 3)
+#define PINMUX_GPIO169__FUNC_UDI_TCK (MTK_PIN_NO(169) | 4)
+#define PINMUX_GPIO169__FUNC_SSPM_JTAG_TCK_VCORE (MTK_PIN_NO(169) | 5)
+#define PINMUX_GPIO169__FUNC_MCUPM_JTAG_TCK (MTK_PIN_NO(169) | 6)
+#define PINMUX_GPIO169__FUNC_CONN_BGF_MCU_TCK (MTK_PIN_NO(169) | 7)
+
+#define PINMUX_GPIO170__FUNC_GPIO170 (MTK_PIN_NO(170) | 0)
+#define PINMUX_GPIO170__FUNC_MSDC1_DAT0 (MTK_PIN_NO(170) | 1)
+#define PINMUX_GPIO170__FUNC_SPIM5_B_CSB (MTK_PIN_NO(170) | 2)
+#define PINMUX_GPIO170__FUNC_UCTS2 (MTK_PIN_NO(170) | 3)
+#define PINMUX_GPIO170__FUNC_UDI_TDI (MTK_PIN_NO(170) | 4)
+#define PINMUX_GPIO170__FUNC_SSPM_JTAG_TDI_VCORE (MTK_PIN_NO(170) | 5)
+#define PINMUX_GPIO170__FUNC_MCUPM_JTAG_TDI (MTK_PIN_NO(170) | 6)
+#define PINMUX_GPIO170__FUNC_CONN_BGF_MCU_TDI (MTK_PIN_NO(170) | 7)
+
+#define PINMUX_GPIO171__FUNC_GPIO171 (MTK_PIN_NO(171) | 0)
+#define PINMUX_GPIO171__FUNC_MSDC1_DAT1 (MTK_PIN_NO(171) | 1)
+#define PINMUX_GPIO171__FUNC_SPIM5_B_CLK (MTK_PIN_NO(171) | 2)
+#define PINMUX_GPIO171__FUNC_URTS2 (MTK_PIN_NO(171) | 3)
+#define PINMUX_GPIO171__FUNC_UDI_TDO (MTK_PIN_NO(171) | 4)
+#define PINMUX_GPIO171__FUNC_SSPM_JTAG_TDO_VCORE (MTK_PIN_NO(171) | 5)
+#define PINMUX_GPIO171__FUNC_MCUPM_JTAG_TDO (MTK_PIN_NO(171) | 6)
+#define PINMUX_GPIO171__FUNC_CONN_BGF_MCU_TDO (MTK_PIN_NO(171) | 7)
+
+#define PINMUX_GPIO172__FUNC_GPIO172 (MTK_PIN_NO(172) | 0)
+#define PINMUX_GPIO172__FUNC_MSDC1_DAT2 (MTK_PIN_NO(172) | 1)
+#define PINMUX_GPIO172__FUNC_SPIM5_B_MO (MTK_PIN_NO(172) | 2)
+#define PINMUX_GPIO172__FUNC_UCTS3 (MTK_PIN_NO(172) | 3)
+#define PINMUX_GPIO172__FUNC_UDI_NTRST (MTK_PIN_NO(172) | 4)
+#define PINMUX_GPIO172__FUNC_SSPM_JTAG_TRSTN_VCORE (MTK_PIN_NO(172) | 5)
+#define PINMUX_GPIO172__FUNC_MCUPM_JTAG_TRSTN (MTK_PIN_NO(172) | 6)
+#define PINMUX_GPIO172__FUNC_CONN_BGF_MCU_TRST_B (MTK_PIN_NO(172) | 7)
+
+#define PINMUX_GPIO173__FUNC_GPIO173 (MTK_PIN_NO(173) | 0)
+#define PINMUX_GPIO173__FUNC_MSDC1_DAT3 (MTK_PIN_NO(173) | 1)
+#define PINMUX_GPIO173__FUNC_SPIM5_B_MI (MTK_PIN_NO(173) | 2)
+#define PINMUX_GPIO173__FUNC_URTS3 (MTK_PIN_NO(173) | 3)
+#define PINMUX_GPIO173__FUNC_CLKM0 (MTK_PIN_NO(173) | 4)
+#define PINMUX_GPIO173__FUNC_PWM_2 (MTK_PIN_NO(173) | 5)
+
+#define PINMUX_GPIO174__FUNC_GPIO174 (MTK_PIN_NO(174) | 0)
+#define PINMUX_GPIO174__FUNC_MSDC2_CMD (MTK_PIN_NO(174) | 1)
+#define PINMUX_GPIO174__FUNC_CONN_BGF_MCU_AICE_TMSC (MTK_PIN_NO(174) | 2)
+#define PINMUX_GPIO174__FUNC_UTXD1 (MTK_PIN_NO(174) | 3)
+#define PINMUX_GPIO174__FUNC_VADSP_JTAG0_TMS (MTK_PIN_NO(174) | 4)
+#define PINMUX_GPIO174__FUNC_SSPM_JTAG_TMS_VLP (MTK_PIN_NO(174) | 5)
+#define PINMUX_GPIO174__FUNC_SPM_JTAG_TMS (MTK_PIN_NO(174) | 6)
+#define PINMUX_GPIO174__FUNC_SCP_JTAG0_TMS_VLP (MTK_PIN_NO(174) | 7)
+
+#define PINMUX_GPIO175__FUNC_GPIO175 (MTK_PIN_NO(175) | 0)
+#define PINMUX_GPIO175__FUNC_MSDC2_CLK (MTK_PIN_NO(175) | 1)
+#define PINMUX_GPIO175__FUNC_CONN_BGF_MCU_AICE_TCKC (MTK_PIN_NO(175) | 2)
+#define PINMUX_GPIO175__FUNC_URXD1 (MTK_PIN_NO(175) | 3)
+#define PINMUX_GPIO175__FUNC_VADSP_JTAG0_TCK (MTK_PIN_NO(175) | 4)
+#define PINMUX_GPIO175__FUNC_SSPM_JTAG_TCK_VLP (MTK_PIN_NO(175) | 5)
+#define PINMUX_GPIO175__FUNC_SPM_JTAG_TCK (MTK_PIN_NO(175) | 6)
+#define PINMUX_GPIO175__FUNC_SCP_JTAG0_TCK_VLP (MTK_PIN_NO(175) | 7)
+
+#define PINMUX_GPIO176__FUNC_GPIO176 (MTK_PIN_NO(176) | 0)
+#define PINMUX_GPIO176__FUNC_MSDC2_DAT0 (MTK_PIN_NO(176) | 1)
+#define PINMUX_GPIO176__FUNC_SRCLKENAI0 (MTK_PIN_NO(176) | 2)
+#define PINMUX_GPIO176__FUNC_UTXD2 (MTK_PIN_NO(176) | 3)
+#define PINMUX_GPIO176__FUNC_VADSP_JTAG0_TDI (MTK_PIN_NO(176) | 4)
+#define PINMUX_GPIO176__FUNC_SSPM_JTAG_TDI_VLP (MTK_PIN_NO(176) | 5)
+#define PINMUX_GPIO176__FUNC_SPM_JTAG_TDI (MTK_PIN_NO(176) | 6)
+#define PINMUX_GPIO176__FUNC_SCP_JTAG0_TDI_VLP (MTK_PIN_NO(176) | 7)
+
+#define PINMUX_GPIO177__FUNC_GPIO177 (MTK_PIN_NO(177) | 0)
+#define PINMUX_GPIO177__FUNC_MSDC2_DAT1 (MTK_PIN_NO(177) | 1)
+#define PINMUX_GPIO177__FUNC_SRCLKENAI1 (MTK_PIN_NO(177) | 2)
+#define PINMUX_GPIO177__FUNC_URXD2 (MTK_PIN_NO(177) | 3)
+#define PINMUX_GPIO177__FUNC_VADSP_JTAG0_TDO (MTK_PIN_NO(177) | 4)
+#define PINMUX_GPIO177__FUNC_SSPM_JTAG_TDO_VLP (MTK_PIN_NO(177) | 5)
+#define PINMUX_GPIO177__FUNC_SPM_JTAG_TDO (MTK_PIN_NO(177) | 6)
+#define PINMUX_GPIO177__FUNC_SCP_JTAG0_TDO_VLP (MTK_PIN_NO(177) | 7)
+
+#define PINMUX_GPIO178__FUNC_GPIO178 (MTK_PIN_NO(178) | 0)
+#define PINMUX_GPIO178__FUNC_MSDC2_DAT2 (MTK_PIN_NO(178) | 1)
+#define PINMUX_GPIO178__FUNC_UTXD3 (MTK_PIN_NO(178) | 3)
+#define PINMUX_GPIO178__FUNC_VADSP_JTAG0_TRSTN (MTK_PIN_NO(178) | 4)
+#define PINMUX_GPIO178__FUNC_SSPM_JTAG_TRSTN_VLP (MTK_PIN_NO(178) | 5)
+#define PINMUX_GPIO178__FUNC_SPM_JTAG_TRSTN (MTK_PIN_NO(178) | 6)
+#define PINMUX_GPIO178__FUNC_SCP_JTAG0_TRSTN_VLP (MTK_PIN_NO(178) | 7)
+
+#define PINMUX_GPIO179__FUNC_GPIO179 (MTK_PIN_NO(179) | 0)
+#define PINMUX_GPIO179__FUNC_MSDC2_DAT3 (MTK_PIN_NO(179) | 1)
+#define PINMUX_GPIO179__FUNC_URXD3 (MTK_PIN_NO(179) | 3)
+#define PINMUX_GPIO179__FUNC_CLKM1 (MTK_PIN_NO(179) | 4)
+#define PINMUX_GPIO179__FUNC_PWM_vlp (MTK_PIN_NO(179) | 5)
+#define PINMUX_GPIO179__FUNC_TP_GPIO7_AO (MTK_PIN_NO(179) | 7)
+
+#define PINMUX_GPIO180__FUNC_GPIO180 (MTK_PIN_NO(180) | 0)
+#define PINMUX_GPIO180__FUNC_SPMI_P_SCL (MTK_PIN_NO(180) | 1)
+
+#define PINMUX_GPIO181__FUNC_GPIO181 (MTK_PIN_NO(181) | 0)
+#define PINMUX_GPIO181__FUNC_SPMI_P_SDA (MTK_PIN_NO(181) | 1)
+
+#define PINMUX_GPIO182__FUNC_GPIO182 (MTK_PIN_NO(182) | 0)
+#define PINMUX_GPIO182__FUNC_DDR_PAD_RRESETB (MTK_PIN_NO(182) | 1)
+
+#endif /* __MT8189_PINFUNC_H */
-- 
2.45.2



From wangzhou1 at hisilicon.com  Thu Dec  4 22:47:09 2025
From: wangzhou1 at hisilicon.com (Zhou Wang)
Date: Fri, 5 Dec 2025 14:47:09 +0800
Subject: [PATCH v7 5/7] arm64: Add support for FEAT_{LS64, LS64_V}
In-Reply-To: <7d2ea8c6-e54f-4a57-843c-e0c6c33c02c5@app.fastmail.com>
References: <20251107072127.448953-1-wangzhou1@hisilicon.com>
 <20251107072127.448953-6-wangzhou1@hisilicon.com>
 <861pm4vn02.wl-maz@kernel.org>
 <b1407660-9b69-7e21-328a-0f969fffa554@hisilicon.com>
 <c72411f9-a77e-4a72-a401-5110b919a2df@app.fastmail.com>
 <1ed610f5-3f0b-614d-5e7f-2c643238bec3@hisilicon.com>
 <113db0fb-d879-49d7-a5f2-7755558f29dd@app.fastmail.com>
 <6d6fad8d-e4e4-b973-6431-34a37003d363@hisilicon.com>
 <f641d3f2-dac9-4a9e-92a4-0805e6561418@app.fastmail.com>
 <e6cffbce-7cd4-3fe3-a9bd-935efedaebd0@hisilicon.com>
 <7d2ea8c6-e54f-4a57-843c-e0c6c33c02c5@app.fastmail.com>
Message-ID: <734163cd-3692-3be2-9f2a-5364d9f5980c@hisilicon.com>

On 2025/11/27 23:37, Arnd Bergmann wrote:
> On Thu, Nov 27, 2025, at 04:51, Zhou Wang wrote:
>> On 2025/11/18 15:36, Arnd Bergmann wrote:
>>> On Tue, Nov 18, 2025, at 03:31, Zhou Wang wrote:
>>>
>>> The easiest setup I can think of that still supports your machine
>>> would look something like:
>>>
>>> - have the kernel choose between st64bv and st64bv0 at early boot,
>>>   based on platform configuration, use st64bv0 by default if
>>>   available in hardware and not disabled in EL3, EL2 or kernel
>>>   command line.
>>> - Change pasid handling in iommu_sva_bind_device() so drivers
>>>   have to explicitly request one of the modes before establishing
>>>   a pasid, refuse this on incompatible systems, update the
>>>   three existing callers (idxd, amdxdna, uacce) accordingly.
>>> - on systems with st64bv but no st64bv0, enable st64bv for
>>>   all CPUs at boot time to avoid context switch overhead, but
>>>   forbid mapping shared hardware workqueues into userspace.
>>> - postpone full support for st64bv0 until we have a device that
>>>   actually uses this and can be tested. I think most of it is
>>>   already there in the iommu code, but the ACCDATA setup needs
>>>   to be integrated into the switch_mm()/__switch_to() code
>>>   and possibly a trap handler like on x86.
>>
>> Hi Arnd,
>>
>> Sorry for late to reply, I double checked with our SoC and device
>> colleagues, currently only st64b has been used in our system.
>>
>> So I think we could upstream FEAT_LS64 firstly as it seems easy
>> to be merged. After this, we continue to discuss FEAT_LS64V and
>> FEAT_LS64_ACCDATA solution if there is a real system need them.
> 
> As I understand it, using ST64B is usually more efficient than
> ST64BV if you can use either, since it is a normal posted bus
> transaction rather than a synchronous atomic. If that works for
> you, I think what we should plan for is to let you use ST64B
> on this particular hardware and never support ST64BV from
> userspace, the same way we do it on Intel hardware with ENQCMD.

I missed the email as it has been filtered into other fold, my bad :(
I think it works fine in our system. I planned to remove whole ST64BV
support in next version, so what you suggested is not to export
ST64BV to userspace?

> 
> As there are already CPUs out there that do include ST64BV0,
> I think we also want to support those soon. Not having to
> support both ST64BV and ST64BV0 from userspace makes it a lot
> easier, but I think we'd still want to only enable ST64BV0
> on a per-task base when mapping a shared workqueued into the
> user address space on a task that has an active mm->iommu_mm.
> 
> If that makes sense to you, I can try to come up with a
> prototype based on your current patches to add the context
> switching and enable logic.

I am OK with this, even though currently we do not have a real
hardware to test ST64BV0 related codes.

Best,
Zhou

> 
>       Arnd
> .


From ebiggers at kernel.org  Thu Dec  4 22:48:09 2025
From: ebiggers at kernel.org (Eric Biggers)
Date: Thu, 4 Dec 2025 22:48:09 -0800
Subject: [PATCH] arm64/simd: Avoid pointless clearing of FP/SIMD buffer
In-Reply-To: <20251204162815.522879-2-ardb@kernel.org>
References: <20251204162815.522879-2-ardb@kernel.org>
Message-ID: <20251205064809.GA26371@sol>

On Thu, Dec 04, 2025 at 05:28:15PM +0100, Ard Biesheuvel wrote:
> The buffer provided to kernel_neon_begin() is only used if the task is
> scheduled out while the FP/SIMD is in use by the kernel, or when such a
> section is interrupted by a softirq that also uses the FP/SIMD.
> 
> IOW, this happens rarely, and even if it happened often, there is still
> no reason for this buffer to be cleared beforehand, which happens by
> default when using a compiler that supports -ftrivial-auto-var-init.
> 
> So mark the buffer as __uninitialized. Given that this is a variable
> attribute not a type attribute, this requires that the expression is
> tweaked a bit.
> 
> Cc: Will Deacon <will at kernel.org>,
> Cc: Catalin Marinas <catalin.marinas at arm.com>,
> Cc: Kees Cook <keescook at chromium.org>
> Cc: Eric Biggers <ebiggers at kernel.org>
> Cc: Justin Stitt <justinstitt at google.com>
> Signed-off-by: Ard Biesheuvel <ardb at kernel.org>
> ---
>  arch/arm64/include/asm/simd.h | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> The issue here is that returning a pointer to an automatic variable as
> it goes out of scope is slightly dodgy, especially in the context of
> __attribute__((cleanup())), on which the scoped guard API relies
> heavily. However, in this case it should be safe, given that this
> expression is the input to the guarded variable type's constructor.
> 
> It is definitely not pretty, though, so hopefully here is a better way
> to attach this.
> 
> diff --git a/arch/arm64/include/asm/simd.h b/arch/arm64/include/asm/simd.h
> index 0941f6f58a14..825b7fe94003 100644
> --- a/arch/arm64/include/asm/simd.h
> +++ b/arch/arm64/include/asm/simd.h
> @@ -48,6 +48,7 @@ DEFINE_LOCK_GUARD_1(ksimd,
>  		    kernel_neon_begin(_T->lock),
>  		    kernel_neon_end(_T->lock))
>  
> -#define scoped_ksimd()	scoped_guard(ksimd, &(struct user_fpsimd_state){})
> +#define scoped_ksimd()	\
> +	scoped_guard(ksimd, ({ struct user_fpsimd_state __uninitialized s; &s; }))

Ick.  I should have looked at the generated code more closely.

It's actually worse than you describe, because the zeroing is there even
without CONFIG_INIT_STACK_ALL_ZERO=y, simply because the
user_fpsimd_state struct is declared using a compound literal.

I'm afraid that this patch probably isn't a good idea, as it relies on
undefined behavior.  Before this patch, the user_fpsimd_state is
declared using a compound literal, which takes on its enclosing scope,
i.e. the 'for' statement generated by scoped_guard().  After this patch,
it's in a new inner scope, and the pointer to it escapes from it.

Unfortunately I don't think there's any way to solve this while keeping
the scoped_ksimd() API as-is.

Best I can come up with is to leave it to the callers to allocate the
state, and then use scoped_guard() similar to a regular lock:

        struct user_fpsimd_state __uninitialized fpsimd_state;                   
                                                                                 
        scoped_guard(ksimd, &fpsimd_state)                                       
                foo_neon(...)

Maybe wrap the state declaration with a macro:
DECLARE_FPSIMD_STATE_ONSTACK(fpsimd_state);

- Eric


From yang.yicong at picoheart.com  Thu Dec  4 22:53:00 2025
From: yang.yicong at picoheart.com (Yicong Yang)
Date: Fri, 5 Dec 2025 14:53:00 +0800
Subject: [PATCH v6 1/2] watchdog: move arm64 watchdog_hld into common code
In-Reply-To: <20251114033243.76509-2-cuiyunhui@bytedance.com>
References: <20251114033243.76509-1-cuiyunhui@bytedance.com> <20251114033243.76509-2-cuiyunhui@bytedance.com>
Message-ID: <af5765d2-ba72-481c-8c7a-6fb09fe44709@picoheart.com>

On 2025/11/14 11:32, Yunhui Cui wrote:
> Move the contents of arch/arm64/watchdog_hld.c to kernel/watchdog_perf.c
> to create a generic implementation that can be reused by other arch,
> such as RISC-V.
> 
> Signed-off-by: Yunhui Cui <cuiyunhui at bytedance.com>
> Reviewed-by: Douglas Anderson <dianders at chromium.org>
> ---
>  arch/arm64/Kconfig               |  1 +
>  arch/arm64/kernel/Makefile       |  1 -
>  arch/arm64/kernel/watchdog_hld.c | 94 --------------------------------
>  drivers/perf/arm_pmu.c           | 10 +++-
>  include/linux/perf/arm_pmu.h     |  2 -
>  kernel/watchdog_perf.c           | 83 ++++++++++++++++++++++++++++
>  lib/Kconfig.debug                |  8 +++
>  7 files changed, 101 insertions(+), 98 deletions(-)
>  delete mode 100644 arch/arm64/kernel/watchdog_hld.c
> 
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 6663ffd23f252..6614ff45b1e06 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -231,6 +231,7 @@ config ARM64
>  	select HAVE_GCC_PLUGINS
>  	select HAVE_HARDLOCKUP_DETECTOR_PERF if PERF_EVENTS && \
>  		HW_PERF_EVENTS && HAVE_PERF_EVENTS_NMI
> +	select WATCHDOG_PERF_ADJUST_PERIOD if HARDLOCKUP_DETECTOR_PERF
>  	select HAVE_HW_BREAKPOINT if PERF_EVENTS
>  	select HAVE_IOREMAP_PROT
>  	select HAVE_IRQ_TIME_ACCOUNTING
> diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
> index 76f32e424065e..12d77f373fea4 100644
> --- a/arch/arm64/kernel/Makefile
> +++ b/arch/arm64/kernel/Makefile
> @@ -44,7 +44,6 @@ obj-$(CONFIG_KUSER_HELPERS)		+= kuser32.o
>  obj-$(CONFIG_FUNCTION_TRACER)		+= ftrace.o entry-ftrace.o
>  obj-$(CONFIG_MODULES)			+= module.o module-plts.o
>  obj-$(CONFIG_PERF_EVENTS)		+= perf_regs.o perf_callchain.o
> -obj-$(CONFIG_HARDLOCKUP_DETECTOR_PERF)	+= watchdog_hld.o
>  obj-$(CONFIG_HAVE_HW_BREAKPOINT)	+= hw_breakpoint.o
>  obj-$(CONFIG_CPU_PM)			+= sleep.o suspend.o
>  obj-$(CONFIG_KGDB)			+= kgdb.o
> diff --git a/arch/arm64/kernel/watchdog_hld.c b/arch/arm64/kernel/watchdog_hld.c
> deleted file mode 100644
> index 3093037dcb7be..0000000000000
> --- a/arch/arm64/kernel/watchdog_hld.c
> +++ /dev/null
> @@ -1,94 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0
> -#include <linux/nmi.h>
> -#include <linux/cpufreq.h>
> -#include <linux/perf/arm_pmu.h>
> -
> -/*
> - * Safe maximum CPU frequency in case a particular platform doesn't implement
> - * cpufreq driver. Although, architecture doesn't put any restrictions on
> - * maximum frequency but 5 GHz seems to be safe maximum given the available
> - * Arm CPUs in the market which are clocked much less than 5 GHz. On the other
> - * hand, we can't make it much higher as it would lead to a large hard-lockup
> - * detection timeout on parts which are running slower (eg. 1GHz on
> - * Developerbox) and doesn't possess a cpufreq driver.
> - */
> -#define SAFE_MAX_CPU_FREQ	5000000000UL // 5 GHz
> -u64 hw_nmi_get_sample_period(int watchdog_thresh)
> -{
> -	unsigned int cpu = smp_processor_id();
> -	unsigned long max_cpu_freq;
> -
> -	max_cpu_freq = cpufreq_get_hw_max_freq(cpu) * 1000UL;
> -	if (!max_cpu_freq)
> -		max_cpu_freq = SAFE_MAX_CPU_FREQ;
> -
> -	return (u64)max_cpu_freq * watchdog_thresh;
> -}
> -
> -bool __init arch_perf_nmi_is_available(void)
> -{
> -	/*
> -	 * hardlockup_detector_perf_init() will success even if Pseudo-NMI turns off,
> -	 * however, the pmu interrupts will act like a normal interrupt instead of
> -	 * NMI and the hardlockup detector would be broken.
> -	 */
> -	return arm_pmu_irq_is_nmi();
> -}
> -
> -static int watchdog_perf_update_period(void *data)
> -{
> -	int cpu = smp_processor_id();
> -	u64 max_cpu_freq, new_period;
> -
> -	max_cpu_freq = cpufreq_get_hw_max_freq(cpu) * 1000UL;
> -	if (!max_cpu_freq)
> -		return 0;
> -
> -	new_period = watchdog_thresh * max_cpu_freq;
> -	hardlockup_detector_perf_adjust_period(new_period);
> -
> -	return 0;
> -}
> -
> -static int watchdog_freq_notifier_callback(struct notifier_block *nb,
> -					   unsigned long val, void *data)
> -{
> -	struct cpufreq_policy *policy = data;
> -	int cpu;
> -
> -	if (val != CPUFREQ_CREATE_POLICY)
> -		return NOTIFY_DONE;
> -
> -	/*
> -	 * Let each online CPU related to the policy update the period by their
> -	 * own. This will serialize with the framework on start/stop the lockup
> -	 * detector (softlockup_{start,stop}_all) and avoid potential race
> -	 * condition. Otherwise we may have below theoretical race condition:
> -	 * (core 0/1 share the same policy)
> -	 * [core 0]                      [core 1]
> -	 *                               hardlockup_detector_event_create()
> -	 *                                 hw_nmi_get_sample_period()
> -	 * (cpufreq registered, notifier callback invoked)
> -	 * watchdog_freq_notifier_callback()
> -	 *   watchdog_perf_update_period()
> -	 *   (since core 1's event's not yet created,
> -	 *    the period is not set)
> -	 *                                 perf_event_create_kernel_counter()
> -	 *                                 (event's period is SAFE_MAX_CPU_FREQ)
> -	 */
> -	for_each_cpu(cpu, policy->cpus)
> -		smp_call_on_cpu(cpu, watchdog_perf_update_period, NULL, false);
> -
> -	return NOTIFY_DONE;
> -}
> -
> -static struct notifier_block watchdog_freq_notifier = {
> -	.notifier_call = watchdog_freq_notifier_callback,
> -};
> -
> -static int __init init_watchdog_freq_notifier(void)
> -{
> -	return cpufreq_register_notifier(&watchdog_freq_notifier,
> -					 CPUFREQ_POLICY_NOTIFIER);
> -}
> -core_initcall(init_watchdog_freq_notifier);
> diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
> index 973a027d90639..294a5c3438ad1 100644
> --- a/drivers/perf/arm_pmu.c
> +++ b/drivers/perf/arm_pmu.c
> @@ -17,6 +17,7 @@
>  #include <linux/cpu_pm.h>
>  #include <linux/export.h>
>  #include <linux/kernel.h>
> +#include <linux/nmi.h>
>  #include <linux/perf/arm_pmu.h>
>  #include <linux/slab.h>
>  #include <linux/sched/clock.h>
> @@ -703,10 +704,17 @@ static int armpmu_get_cpu_irq(struct arm_pmu *pmu, int cpu)
>  	return per_cpu(hw_events->irq, cpu);
>  }
>  
> -bool arm_pmu_irq_is_nmi(void)
> +#ifdef CONFIG_HARDLOCKUP_DETECTOR_PERF
> +bool arch_perf_nmi_is_available(void)
>  {
> +	/*
> +	 * watchdog_hardlockup_probe() will success even if Pseudo-NMI turns off,
> +	 * however, the pmu interrupts will act like a normal interrupt instead of
> +	 * NMI and the hardlockup detector would be broken.
> +	 */

the comment makes me a bit confused. we'll only declare the NMI support if we successfully
registered the PMU interrupt as NMI interrupt. If pseudo-nmi is turned off, we'll
failed to register the NMI interrupt since neither the gicv3 irqchip will declare NMI
suppport [1] nor the irq_chip::irq_nmi_setup() will success [2], then the has_nmi will
be false. In this case the hardlockup detector is not probed at all [3].

[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/irqchip/irq-gic-v3.c#n1956
[2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/irqchip/irq-gic-v3.c#n602
[3] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/kernel/watchdog_perf.c#n268

>  	return has_nmi;
>  }
> +#endif
>  
>  /*
>   * PMU hardware loses all context when a CPU goes offline.
> diff --git a/include/linux/perf/arm_pmu.h b/include/linux/perf/arm_pmu.h
> index 52b37f7bdbf9e..8f06751f1e176 100644
> --- a/include/linux/perf/arm_pmu.h
> +++ b/include/linux/perf/arm_pmu.h
> @@ -183,8 +183,6 @@ void kvm_host_pmu_init(struct arm_pmu *pmu);
>  #define kvm_host_pmu_init(x)	do { } while(0)
>  #endif
>  
> -bool arm_pmu_irq_is_nmi(void);
> -
>  /* Internal functions only for core arm_pmu code */
>  struct arm_pmu *armpmu_alloc(void);
>  void armpmu_free(struct arm_pmu *pmu);
> diff --git a/kernel/watchdog_perf.c b/kernel/watchdog_perf.c
> index d3ca70e3c256a..8aa5e9a0ba20a 100644
> --- a/kernel/watchdog_perf.c
> +++ b/kernel/watchdog_perf.c
> @@ -15,6 +15,7 @@
>  #include <linux/panic.h>
>  #include <linux/nmi.h>
>  #include <linux/atomic.h>
> +#include <linux/cpufreq.h>
>  #include <linux/module.h>
>  #include <linux/sched/debug.h>
>  
> @@ -306,3 +307,85 @@ void __init hardlockup_config_perf_event(const char *str)
>  	wd_hw_attr.type = PERF_TYPE_RAW;
>  	wd_hw_attr.config = config;
>  }
> +
> +#ifdef CONFIG_WATCHDOG_PERF_ADJUST_PERIOD
> +/*
> + * Safe maximum CPU frequency in case a particular platform doesn't implement
> + * cpufreq driver. Although, architecture doesn't put any restrictions on
> + * maximum frequency but 5 GHz seems to be safe maximum given the available
> + * CPUs in the market which are clocked much less than 5 GHz. On the other
> + * hand, we can't make it much higher as it would lead to a large hard-lockup
> + * detection timeout on parts which are running slower (eg. 1GHz on
> + * Developerbox) and doesn't possess a cpufreq driver.
> + */
> +#define SAFE_MAX_CPU_FREQ	5000000000UL // 5 GHz
> +u64 hw_nmi_get_sample_period(int watchdog_thresh)
> +{
> +	unsigned int cpu = smp_processor_id();
> +	unsigned long max_cpu_freq;
> +
> +	max_cpu_freq = cpufreq_get_hw_max_freq(cpu) * 1000UL;
> +	if (!max_cpu_freq)
> +		max_cpu_freq = SAFE_MAX_CPU_FREQ;
> +
> +	return (u64)max_cpu_freq * watchdog_thresh;
> +}
> +
> +static int watchdog_perf_update_period(void *data)
> +{
> +	int cpu = smp_processor_id();
> +	u64 max_cpu_freq, new_period;
> +
> +	max_cpu_freq = cpufreq_get_hw_max_freq(cpu) * 1000UL;
> +	if (!max_cpu_freq)
> +		return 0;
> +
> +	new_period = watchdog_thresh * max_cpu_freq;
> +	hardlockup_detector_perf_adjust_period(new_period);
> +
> +	return 0;
> +}
> +
> +static int watchdog_freq_notifier_callback(struct notifier_block *nb,
> +					   unsigned long val, void *data)
> +{
> +	struct cpufreq_policy *policy = data;
> +	int cpu;
> +
> +	if (val != CPUFREQ_CREATE_POLICY)
> +		return NOTIFY_DONE;
> +
> +	/*
> +	 * Let each online CPU related to the policy update the period by their
> +	 * own. This will serialize with the framework on start/stop the lockup
> +	 * detector (softlockup_{start,stop}_all) and avoid potential race
> +	 * condition. Otherwise we may have below theoretical race condition:
> +	 * (core 0/1 share the same policy)
> +	 * [core 0]                      [core 1]
> +	 *                               hardlockup_detector_event_create()
> +	 *                                 hw_nmi_get_sample_period()
> +	 * (cpufreq registered, notifier callback invoked)
> +	 * watchdog_freq_notifier_callback()
> +	 *   watchdog_perf_update_period()
> +	 *   (since core 1's event's not yet created,
> +	 *    the period is not set)
> +	 *                                 perf_event_create_kernel_counter()
> +	 *                                 (event's period is SAFE_MAX_CPU_FREQ)
> +	 */
> +	for_each_cpu(cpu, policy->cpus)
> +		smp_call_on_cpu(cpu, watchdog_perf_update_period, NULL, false);
> +
> +	return NOTIFY_DONE;
> +}
> +
> +static struct notifier_block watchdog_freq_notifier = {
> +	.notifier_call = watchdog_freq_notifier_callback,
> +};
> +
> +static int __init init_watchdog_freq_notifier(void)
> +{
> +	return cpufreq_register_notifier(&watchdog_freq_notifier,
> +					 CPUFREQ_POLICY_NOTIFIER);
> +}
> +core_initcall(init_watchdog_freq_notifier);
> +#endif
> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> index 2cbfa3dead0be..85fdfa9b52346 100644
> --- a/lib/Kconfig.debug
> +++ b/lib/Kconfig.debug
> @@ -1193,6 +1193,14 @@ config HARDLOCKUP_DETECTOR_PERF
>  	depends on !HAVE_HARDLOCKUP_DETECTOR_ARCH
>  	select HARDLOCKUP_DETECTOR_COUNTS_HRTIMER
>  
> +config WATCHDOG_PERF_ADJUST_PERIOD
> +	bool

it's reasonable to make it depends on HARDLOCKUP_DETECTOR_PERF.

otherwise looks good to me :)

Thanks.

> +	help
> +	  Adjust the watchdog hardlockup detector's period based on CPU max
> +	  frequency. Uses cpufreq if available; falls back to a safe 5 GHz
> +	  default otherwise. Registers a cpufreq notifier to update the period
> +	  automatically.
> +
>  config HARDLOCKUP_DETECTOR_BUDDY
>  	bool
>  	depends on HARDLOCKUP_DETECTOR


From amhetre at nvidia.com  Thu Dec  4 22:58:48 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Fri, 5 Dec 2025 06:58:48 +0000
Subject: [PATCH V4 1/3] iommu/arm-smmu-v3: Add device-tree support for CMDQV driver
In-Reply-To: <20251205065850.3841834-1-amhetre@nvidia.com>
References: <20251205065850.3841834-1-amhetre@nvidia.com>
Message-ID: <20251205065850.3841834-2-amhetre@nvidia.com>

Add device tree support to the CMDQV driver to enable usage on Tegra264
SoCs. The implementation parses the nvidia,cmdqv phandle from the SMMU
device tree node to associate each SMMU with its corresponding CMDQV
instance based on compatible string.

Remove the dependency from Kconfig as the driver now supports both ACPI
and device tree initialization through conditional compilation and
ARM_SMMU_V3 depends on ARM64 which implies at least OF.

Reviewed-by: Nicolin Chen <nicolinc at nvidia.com>
Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
---
 drivers/iommu/arm/Kconfig                     |  1 -
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 32 +++++++++++++++++++
 .../iommu/arm/arm-smmu-v3/tegra241-cmdqv.c    | 27 +++++++++++++++-
 3 files changed, 58 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/arm/Kconfig b/drivers/iommu/arm/Kconfig
index ef42bbe07dbe..5fac08b89dee 100644
--- a/drivers/iommu/arm/Kconfig
+++ b/drivers/iommu/arm/Kconfig
@@ -121,7 +121,6 @@ config ARM_SMMU_V3_KUNIT_TEST
 
 config TEGRA241_CMDQV
 	bool "NVIDIA Tegra241 CMDQ-V extension support for ARM SMMUv3"
-	depends on ACPI
 	help
 	  Support for NVIDIA CMDQ-Virtualization extension for ARM SMMUv3. The
 	  CMDQ-V extension is similar to v3.3 ECMDQ for multi command queues
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index d16d35c78c06..9433cd91c68f 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -4530,6 +4530,35 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
 	return 0;
 }
 
+#ifdef CONFIG_TEGRA241_CMDQV
+static void tegra_cmdqv_dt_probe(struct device_node *smmu_node,
+				 struct arm_smmu_device *smmu)
+{
+	struct platform_device *pdev;
+	struct device_node *np;
+
+	np = of_parse_phandle(smmu_node, "nvidia,cmdqv", 0);
+	if (!np)
+		return;
+
+	pdev = of_find_device_by_node(np);
+	of_node_put(np);
+	if (!pdev)
+		return;
+
+	smmu->impl_dev = &pdev->dev;
+	smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
+	dev_info(smmu->dev, "found companion CMDQV device: %s\n",
+		 dev_name(smmu->impl_dev));
+	put_device(&pdev->dev);
+}
+#else
+static void tegra_cmdqv_dt_probe(struct device_node *smmu_node,
+				 struct arm_smmu_device *smmu)
+{
+}
+#endif
+
 #ifdef CONFIG_ACPI
 #ifdef CONFIG_TEGRA241_CMDQV
 static void acpi_smmu_dsdt_probe_tegra241_cmdqv(struct acpi_iort_node *node,
@@ -4634,6 +4663,9 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev,
 	if (of_dma_is_coherent(dev->of_node))
 		smmu->features |= ARM_SMMU_FEAT_COHERENCY;
 
+	if (of_device_is_compatible(dev->of_node, "nvidia,tegra264-smmu"))
+		tegra_cmdqv_dt_probe(dev->of_node, smmu);
+
 	return ret;
 }
 
diff --git a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
index 378104cd395e..c096c8229c5d 100644
--- a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
+++ b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
@@ -11,6 +11,8 @@
 #include <linux/iommufd.h>
 #include <linux/iopoll.h>
 #include <uapi/linux/iommufd.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
 
 #include <acpi/acpixf.h>
 
@@ -917,6 +919,26 @@ tegra241_cmdqv_find_acpi_resource(struct device *dev, int *irq)
 	return res;
 }
 
+static struct resource *
+tegra241_cmdqv_find_dt_resource(struct device *dev, int *irq)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "no memory resource found for CMDQV\n");
+		return NULL;
+	}
+
+	if (irq)
+		*irq = platform_get_irq_optional(pdev, 0);
+	if (!irq || *irq <= 0)
+		dev_warn(dev, "no interrupt. errors will not be reported\n");
+
+	return res;
+}
+
 static int tegra241_cmdqv_init_structures(struct arm_smmu_device *smmu)
 {
 	struct tegra241_cmdqv *cmdqv =
@@ -1048,11 +1070,14 @@ struct arm_smmu_device *tegra241_cmdqv_probe(struct arm_smmu_device *smmu)
 
 	if (!smmu->dev->of_node)
 		res = tegra241_cmdqv_find_acpi_resource(smmu->impl_dev, &irq);
+	else
+		res = tegra241_cmdqv_find_dt_resource(smmu->impl_dev, &irq);
 	if (!res)
 		goto out_fallback;
 
 	new_smmu = __tegra241_cmdqv_probe(smmu, res, irq);
-	kfree(res);
+	if (!smmu->dev->of_node)
+		kfree(res);
 
 	if (new_smmu)
 		return new_smmu;
-- 
2.25.1



From amhetre at nvidia.com  Thu Dec  4 22:58:47 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Fri, 5 Dec 2025 06:58:47 +0000
Subject: [PATCH V4 0/3] Add device tree support for NVIDIA Tegra CMDQV
Message-ID: <20251205065850.3841834-1-amhetre@nvidia.com>

This series adds device tree support for the CMDQ-Virtualization (CMDQV)
hardware on NVIDIA Tegra264 SoCs.

CMDQV is a hardware block that works alongside the ARM SMMUv3 to assist in
virtualizing the command queue. It was previously only supported through
ACPI on Tegra241. This series extends the existing driver to support device
tree based initialization, which is required for Tegra264 platforms.

The series is structured as follows:

Patch 1: Extends the tegra241-cmdqv driver to support device tree probing
         alongside the existing ACPI support. The SMMU driver now parses
         the nvidia,cmdqv phandle to associate each SMMU with its
         corresponding CMDQV instance.

Patch 2: Adds device tree binding documentation for nvidia,tegra264-cmdqv
         and extends the arm,smmu-v3 binding with an optional nvidia,cmdqv
         property.

Patch 3: Adds CMDQV device nodes to the Tegra264 device tree and enables
         them on the tegra264-p3834 platform.

The implementation follows the existing ACPI probe path to minimize code
divergence and maintain consistency with Tegra241 support.

Changes in V4:
- Removed platform driver registration from tegra241-cmdqv.c to avoid
  duplicate module init/cleanup symbols
- Fixed the ordering of properties in CMDQV device tree nodes
- Added "Reviewed-by: Rob Herring" for binding documentation patch(2/3)
  carry-forwarding from V3.

Changes in V3:
- Remove the Kconfig dependency for CONFIG_TEGRA241_CMDQV
- Drop the reference on the platform device after getting it from
  of_find_device_by_node()
- Remove the unnecessary "nvidia,tegra264-smmu" compatible string from
  arm-smmu-v3 match table
- Order CMDQV nodes in device tree files according to its address

Changes in V2:
- Updated dependency for CONFIG_TEGRA241_CMDQV on OF || ACPI
- Changed maintainer to Nicolin Chen
- Removed interrupt-names property
- Added nvidia,tegra264-smmu to compatible enum for arm-smmu-v3
- Added allOf constraint to restrict nvidia,cmdqv property to
  nvidia,tegra264-smmu only
- Updated SMMU nodes in device tree to use nvidia,tegra264-smmu compatible
  string

Ashish Mhetre (3):
  iommu/arm-smmu-v3: Add device-tree support for CMDQV driver
  dt-bindings: iommu: Add NVIDIA Tegra CMDQV support
  arm64: dts: nvidia: Add nodes for CMDQV

 .../bindings/iommu/arm,smmu-v3.yaml           | 30 ++++++++++-
 .../bindings/iommu/nvidia,tegra264-cmdqv.yaml | 42 ++++++++++++++++
 .../arm64/boot/dts/nvidia/tegra264-p3834.dtsi |  8 +++
 arch/arm64/boot/dts/nvidia/tegra264.dtsi      | 50 +++++++++++++++++--
 drivers/iommu/arm/Kconfig                     |  1 -
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 32 ++++++++++++
 .../iommu/arm/arm-smmu-v3/tegra241-cmdqv.c    | 27 +++++++++-
 7 files changed, 181 insertions(+), 9 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/iommu/nvidia,tegra264-cmdqv.yaml

-- 
2.25.1



From amhetre at nvidia.com  Thu Dec  4 22:58:50 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Fri, 5 Dec 2025 06:58:50 +0000
Subject: [PATCH V4 3/3] arm64: dts: nvidia: Add nodes for CMDQV
In-Reply-To: <20251205065850.3841834-1-amhetre@nvidia.com>
References: <20251205065850.3841834-1-amhetre@nvidia.com>
Message-ID: <20251205065850.3841834-4-amhetre@nvidia.com>

The Command Queue Virtualization (CMDQV) hardware is part of the
SMMUv3 implementation on NVIDIA Tegra SoCs. It assists in
virtualizing the command queue for the SMMU.

Update SMMU compatible strings to use nvidia,tegra264-smmu to enable
CMDQV support. Add device tree nodes for the CMDQV hardware and enable
them on the tegra264-p3834 platform where SMMUs are enabled. Each SMMU
instance is paired with its corresponding CMDQV instance via the
nvidia,cmdqv property.

Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
---
 .../arm64/boot/dts/nvidia/tegra264-p3834.dtsi |  8 +++
 arch/arm64/boot/dts/nvidia/tegra264.dtsi      | 50 +++++++++++++++++--
 2 files changed, 53 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi b/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
index 06795c82427a..7e2c3e66c2ab 100644
--- a/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
@@ -23,8 +23,16 @@ iommu at 5000000 {
 			status = "okay";
 		};
 
+		cmdqv at 5200000 {
+			status = "okay";
+		};
+
 		iommu at 6000000 {
 			status = "okay";
 		};
+
+		cmdqv at 6200000 {
+			status = "okay";
+		};
 	};
 };
diff --git a/arch/arm64/boot/dts/nvidia/tegra264.dtsi b/arch/arm64/boot/dts/nvidia/tegra264.dtsi
index f137565da804..9eb7058e3149 100644
--- a/arch/arm64/boot/dts/nvidia/tegra264.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra264.dtsi
@@ -3361,7 +3361,7 @@ bus at 8100000000 {
 			 <0x02 0x00000000 0xd0 0x00000000 0x08 0x80000000>; /* ECAM, prefetchable memory, I/O */
 
 		smmu1: iommu at 5000000 {
-			compatible = "arm,smmu-v3";
+			compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
 			reg = <0x00 0x5000000 0x0 0x200000>;
 			interrupts = <GIC_SPI 12 IRQ_TYPE_EDGE_RISING>,
 				     <GIC_SPI 13 IRQ_TYPE_EDGE_RISING>;
@@ -3370,10 +3370,18 @@ smmu1: iommu at 5000000 {
 
 			#iommu-cells = <1>;
 			dma-coherent;
+			nvidia,cmdqv = <&cmdqv1>;
+		};
+
+		cmdqv1: cmdqv at 5200000 {
+			compatible = "nvidia,tegra264-cmdqv";
+			reg = <0x00 0x5200000 0x0 0x830000>;
+			interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
 		};
 
 		smmu2: iommu at 6000000 {
-			compatible = "arm,smmu-v3";
+			compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
 			reg = <0x00 0x6000000 0x0 0x200000>;
 			interrupts = <GIC_SPI 1 IRQ_TYPE_EDGE_RISING>,
 				     <GIC_SPI 2 IRQ_TYPE_EDGE_RISING>;
@@ -3382,6 +3390,14 @@ smmu2: iommu at 6000000 {
 
 			#iommu-cells = <1>;
 			dma-coherent;
+			nvidia,cmdqv = <&cmdqv2>;
+		};
+
+		cmdqv2: cmdqv at 6200000 {
+			compatible = "nvidia,tegra264-cmdqv";
+			reg = <0x00 0x6200000 0x0 0x830000>;
+			interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
 		};
 
 		mc: memory-controller at 8020000 {
@@ -3437,7 +3453,7 @@ emc: external-memory-controller at 8800000 {
 		};
 
 		smmu0: iommu at a000000 {
-			compatible = "arm,smmu-v3";
+			compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
 			reg = <0x00 0xa000000 0x0 0x200000>;
 			interrupts = <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>,
 				     <GIC_SPI 22 IRQ_TYPE_EDGE_RISING>;
@@ -3446,10 +3462,18 @@ smmu0: iommu at a000000 {
 
 			#iommu-cells = <1>;
 			dma-coherent;
+			nvidia,cmdqv = <&cmdqv0>;
+		};
+
+		cmdqv0: cmdqv at a200000 {
+			compatible = "nvidia,tegra264-cmdqv";
+			reg = <0x00 0xa200000 0x0 0x830000>;
+			interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
 		};
 
 		smmu4: iommu at b000000 {
-			compatible = "arm,smmu-v3";
+			compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
 			reg = <0x00 0xb000000 0x0 0x200000>;
 			interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
 				     <GIC_SPI 31 IRQ_TYPE_EDGE_RISING>;
@@ -3458,6 +3482,14 @@ smmu4: iommu at b000000 {
 
 			#iommu-cells = <1>;
 			dma-coherent;
+			nvidia,cmdqv = <&cmdqv4>;
+		};
+
+		cmdqv4: cmdqv at b200000 {
+			compatible = "nvidia,tegra264-cmdqv";
+			reg = <0x00 0xb200000 0x0 0x830000>;
+			interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
 		};
 
 		i2c14: i2c at c410000 {
@@ -3690,7 +3722,7 @@ bus at 8800000000 {
 		ranges = <0x00 0x00000000 0x88 0x00000000 0x01 0x00000000>;
 
 		smmu3: iommu at 6000000 {
-			compatible = "arm,smmu-v3";
+			compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
 			reg = <0x00 0x6000000 0x0 0x200000>;
 			interrupts = <GIC_SPI 225 IRQ_TYPE_EDGE_RISING>,
 				     <GIC_SPI 226 IRQ_TYPE_EDGE_RISING>;
@@ -3699,6 +3731,14 @@ smmu3: iommu at 6000000 {
 
 			#iommu-cells = <1>;
 			dma-coherent;
+			nvidia,cmdqv = <&cmdqv3>;
+		};
+
+		cmdqv3: cmdqv at 6200000 {
+			compatible = "nvidia,tegra264-cmdqv";
+			reg = <0x00 0x6200000 0x0 0x830000>;
+			interrupts = <GIC_SPI 232 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
 		};
 
 		hda at 90b0000 {
-- 
2.25.1



From amhetre at nvidia.com  Thu Dec  4 22:58:49 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Fri, 5 Dec 2025 06:58:49 +0000
Subject: [PATCH V4 2/3] dt-bindings: iommu: Add NVIDIA Tegra CMDQV support
In-Reply-To: <20251205065850.3841834-1-amhetre@nvidia.com>
References: <20251205065850.3841834-1-amhetre@nvidia.com>
Message-ID: <20251205065850.3841834-3-amhetre@nvidia.com>

The Command Queue Virtualization (CMDQV) hardware is part of the
SMMUv3 implementation on NVIDIA Tegra SoCs. It assists in
virtualizing the command queue for the SMMU.

Add a new device tree binding document for nvidia,tegra264-cmdqv.

Also update the arm,smmu-v3 binding to include an optional nvidia,cmdqv
property. This property is a phandle to the CMDQV device node, allowing
the SMMU driver to associate with its corresponding CMDQV instance.
Restrict this property usage to Nvidia Tegra264 only.

Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
---
 .../bindings/iommu/arm,smmu-v3.yaml           | 30 ++++++++++++-
 .../bindings/iommu/nvidia,tegra264-cmdqv.yaml | 42 +++++++++++++++++++
 2 files changed, 70 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/iommu/nvidia,tegra264-cmdqv.yaml

diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
index 75fcf4cb52d9..1c03482e4c61 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
@@ -20,7 +20,12 @@ properties:
   $nodename:
     pattern: "^iommu@[0-9a-f]*"
   compatible:
-    const: arm,smmu-v3
+    oneOf:
+      - const: arm,smmu-v3
+      - items:
+          - enum:
+              - nvidia,tegra264-smmu
+          - const: arm,smmu-v3
 
   reg:
     maxItems: 1
@@ -58,6 +63,15 @@ properties:
 
   msi-parent: true
 
+  nvidia,cmdqv:
+    description: |
+      A phandle to its pairing CMDQV extension for an implementation on NVIDIA
+      Tegra SoC.
+
+      If this property is absent, CMDQ-Virtualization won't be used and SMMU
+      will only use its own CMDQ.
+    $ref: /schemas/types.yaml#/definitions/phandle
+
   hisilicon,broken-prefetch-cmd:
     type: boolean
     description: Avoid sending CMD_PREFETCH_* commands to the SMMU.
@@ -69,6 +83,17 @@ properties:
       register access with page 0 offsets. Set for Cavium ThunderX2 silicon that
       doesn't support SMMU page1 register space.
 
+allOf:
+  - if:
+      not:
+        properties:
+          compatible:
+            contains:
+              const: nvidia,tegra264-smmu
+    then:
+      properties:
+        nvidia,cmdqv: false
+
 required:
   - compatible
   - reg
@@ -82,7 +107,7 @@ examples:
     #include <dt-bindings/interrupt-controller/irq.h>
 
     iommu at 2b400000 {
-            compatible = "arm,smmu-v3";
+            compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
             reg = <0x2b400000 0x20000>;
             interrupts = <GIC_SPI 74 IRQ_TYPE_EDGE_RISING>,
                          <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>,
@@ -92,4 +117,5 @@ examples:
             dma-coherent;
             #iommu-cells = <1>;
             msi-parent = <&its 0xff0000>;
+            nvidia,cmdqv = <&cmdqv>;
     };
diff --git a/Documentation/devicetree/bindings/iommu/nvidia,tegra264-cmdqv.yaml b/Documentation/devicetree/bindings/iommu/nvidia,tegra264-cmdqv.yaml
new file mode 100644
index 000000000000..3f5006a59805
--- /dev/null
+++ b/Documentation/devicetree/bindings/iommu/nvidia,tegra264-cmdqv.yaml
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iommu/nvidia,tegra264-cmdqv.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra264 CMDQV
+
+description:
+  The CMDQ-Virtualization hardware block is part of the SMMUv3 implementation
+  on Tegra264 SoCs. It assists in virtualizing the command queue for the SMMU.
+
+maintainers:
+  - Nicolin Chen <nicolinc at nvidia.com>
+
+properties:
+  compatible:
+    const: nvidia,tegra264-cmdqv
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    cmdqv at 5200000 {
+            compatible = "nvidia,tegra264-cmdqv";
+            reg = <0x5200000 0x830000>;
+            interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+    };
-- 
2.25.1



From arnd at arndb.de  Thu Dec  4 23:09:18 2025
From: arnd at arndb.de (Arnd Bergmann)
Date: Fri, 05 Dec 2025 08:09:18 +0100
Subject: [PATCH v7 5/7] arm64: Add support for FEAT_{LS64, LS64_V}
In-Reply-To: <734163cd-3692-3be2-9f2a-5364d9f5980c@hisilicon.com>
References: <20251107072127.448953-1-wangzhou1@hisilicon.com>
 <20251107072127.448953-6-wangzhou1@hisilicon.com>
 <861pm4vn02.wl-maz@kernel.org>
 <b1407660-9b69-7e21-328a-0f969fffa554@hisilicon.com>
 <c72411f9-a77e-4a72-a401-5110b919a2df@app.fastmail.com>
 <1ed610f5-3f0b-614d-5e7f-2c643238bec3@hisilicon.com>
 <113db0fb-d879-49d7-a5f2-7755558f29dd@app.fastmail.com>
 <6d6fad8d-e4e4-b973-6431-34a37003d363@hisilicon.com>
 <f641d3f2-dac9-4a9e-92a4-0805e6561418@app.fastmail.com>
 <e6cffbce-7cd4-3fe3-a9bd-935efedaebd0@hisilicon.com>
 <7d2ea8c6-e54f-4a57-843c-e0c6c33c02c5@app.fastmail.com>
 <734163cd-3692-3be2-9f2a-5364d9f5980c@hisilicon.com>
Message-ID: <007cc7c9-b466-4437-b113-cddd85599766@app.fastmail.com>

On Fri, Dec 5, 2025, at 07:47, Zhou Wang wrote:
> On 2025/11/27 23:37, Arnd Bergmann wrote:
>> On Thu, Nov 27, 2025, at 04:51, Zhou Wang wrote:
>> 
>> As I understand it, using ST64B is usually more efficient than
>> ST64BV if you can use either, since it is a normal posted bus
>> transaction rather than a synchronous atomic. If that works for
>> you, I think what we should plan for is to let you use ST64B
>> on this particular hardware and never support ST64BV from
>> userspace, the same way we do it on Intel hardware with ENQCMD.
>
> I missed the email as it has been filtered into other fold, my bad :(
> I think it works fine in our system. I planned to remove whole ST64BV
> support in next version, so what you suggested is not to export
> ST64BV to userspace?

Exactly: In line with how this works on x86, we'd always use
ST64B for userspace access to dedicated workqueues, or ST64BV0
for shared hardware workqueues, while ST64BV remains reserved
for in-kernel users.

>> As there are already CPUs out there that do include ST64BV0,
>> I think we also want to support those soon. Not having to
>> support both ST64BV and ST64BV0 from userspace makes it a lot
>> easier, but I think we'd still want to only enable ST64BV0
>> on a per-task base when mapping a shared workqueued into the
>> user address space on a task that has an active mm->iommu_mm.
>> 
>> If that makes sense to you, I can try to come up with a
>> prototype based on your current patches to add the context
>> switching and enable logic.
>
> I am OK with this, even though currently we do not have a real
> hardware to test ST64BV0 related codes.

Thanks for confirming!

        Arnd


From ao.xu at amlogic.com  Thu Dec  4 23:09:47 2025
From: ao.xu at amlogic.com (Ao Xu)
Date: Fri, 5 Dec 2025 15:09:47 +0800
Subject: [PATCH 01/11] dt-bindings: display: meson-dw-hdmi: Add compatible
 for S4 HDMI controller
In-Reply-To: <070eb0a3-2f6e-41ef-8310-0c592a2816dc@amlogic.com>
References: <20250110-drm-s4-v1-0-cbc2d5edaae8@amlogic.com>
 <20250110-drm-s4-v1-1-cbc2d5edaae8@amlogic.com>
 <3AC316FA-A633-4B6C-81BA-CCCA290E7F03@gmail.com>
 <8c3b9fa4-326e-4791-8154-07b268faa132@amlogic.com>
 <7703796D-35D4-4AD2-B7F8-B75D2BE0F7AD@gmail.com>
 <a71f24c9-1f40-45a1-8fdb-6075bbf89930@amlogic.com>
 <F04DC684-AD64-447F-87EC-F503D411F25D@gmail.com>
 <070eb0a3-2f6e-41ef-8310-0c592a2816dc@amlogic.com>
Message-ID: <b6b8203d-2a51-428f-8124-fa65d2c073a0@amlogic.com>

Hi Piotr?

 ? ??I applied this 
patch:?https://github.com/warpme/minimyth2/blob/master/script/kernel/linux-6.18/files/0312-drm-meson-add-vpu-clk-setting-for-S4.patch,?and 
ran it on the board.

 ? ??I encountered the same issue?the system froze.

 ? ??I found that the patch has a few minor problems. After fixing them, 
the system runs normally. Could you try the following patch?


? 2025/12/3 13:56, Ao Xu ??:
> Hi Piotr?
>
> ??? I will need about two more days to look into it. I will follow up 
> with you ASAP.
>
>
> ? 2025/12/2 16:29, Piotr Oniszczuk ??:
>> [You don't often get email from piotr.oniszczuk at gmail.com. Learn why 
>> this is important at https://aka.ms/LearnAboutSenderIdentification ]
>>
>> [ EXTERNAL EMAIL ]
>>
>> Ao,
>> Any chance for updated s4 hdmi series for 6.18?
>>
>>
>>> Wiadomo?? napisana przez Ao Xu <ao.xu at amlogic.com> w dniu 21 lis 
>>> 2025, o godz. 03:55:
>>>
>>> Hi Piotr?
>>>
>>> ???? I will check this issue
>>>
>>> ? 2025/11/19 18:27, Piotr Oniszczuk ??:
>>>> [You don't often get email from piotr.oniszczuk at gmail.com. Learn 
>>>> why this is important at 
>>>> https://aka.ms/LearnAboutSenderIdentification ]
>>>>
>>>> [ EXTERNAL EMAIL ]
>>>>
>>>> Pls see inline
>>>>
>>>>> Wiadomo?? napisana przez Chuan Liu <chuan.liu at amlogic.com> w dniu 
>>>>> 19 lis 2025, o godz. 03:57:
>>>>>
>>>>> Hi Piotr,
>>>>>
>>>>>
>>>>> On 11/18/2025 10:50 PM, Piotr Oniszczuk wrote:
>>>>>> [You don't often get email from piotr.oniszczuk at gmail.com. Learn 
>>>>>> why this is important at 
>>>>>> https://aka.ms/LearnAboutSenderIdentification ]
>>>>>> [ EXTERNAL EMAIL ]
>>>>>> Ao,
>>>>>> Is there any chance to get this s4 drm hdmi series for current 6.18?
>>>>>> (i tried backport this series to 6.18 but have some issues with 
>>>>>> reparent vpu_0_sel to sysclk_b_sel)
>>>>> Why do we need to reparent vpu_0_sel to sysclk_b_sel? is there any
>>>>> background here?
>>>> Well - it looks it is because bug....
>>>> Martin Blumenstingl had perfect eye and catch typo in patch 
>>>> https://lore.kernel.org/all/20250110-drm-s4-v1-11-cbc2d5edaae8 at amlogic.com/: 
>>>>
>>>>
>>>> By replacing:
>>>> assigned-clock-parents = <&clkc_periphs CLKID_FCLK_DIV3>,
>>>> <0>, /* Do Nothing */
>>>> <&clkc_periphs CLKID_VPU_0>,
>>>> <&clkc_periphs CLKID_FCLK_DIV4>,
>>>> <0>, /* Do Nothing */
>>>> <&clkc_periphs CLKID_VAPB_0>;
>>>>
>>>> with:
>>>> assigned-clock-parents = <&clkc_pll CLKID_FCLK_DIV3>,
>>>> <0>, /* Do Nothing */
>>>> <&clkc_periphs CLKID_VPU_0>,
>>>> <&clkc_pll CLKID_FCLK_DIV4>,
>>>> <0>, /* Do Nothing */
>>>> <&clkc_periphs CLKID_VAPB_0>;
>>>>
>>>> dmesg is like this https://termbin.com/6020
>>>>
>>>> So i'm getting hdmi working - but only when device boots _without_ 
>>>> connected hdmi at boot (and connected later)
>>>> If hdmi is connected at boot - boot hangs at:
>>>>
>>>> ???? 0.341676] meson-dw-hdmi fe300000.hdmi-tx: Detected HDMI TX 
>>>> controller v2.01a with HDCP (meson_dw_hdmi_phy)
>>>> [??? 0.342750] meson-dw-hdmi fe300000.hdmi-tx: registered 
>>>> DesignWare HDMI I2C bus driver
>>>> [??? 0.343660] meson-drm ff000000.vpu: bound fe300000.hdmi-tx (ops 
>>>> meson_dw_hdmi_ops)
>>>> [??? 0.344832] [drm] Initialized meson 1.0.0 for ff000000.vpu on 
>>>> minor 0
>>>>
>>>> FYI: It is after applying 
>>>> https://patchwork.kernel.org/project/linux-amlogic/cover/20250110-drm-s4-v1-0-cbc2d5edaae8 at amlogic.com/ 
>>>> on mainline 6.18 (with some my adjustments on this series required 
>>>> by changes in 6.18).
>>>> For VPU clk changes see 
>>>> https://github.com/warpme/minimyth2/blob/master/script/kernel/linux-6.18/files/0312-drm-meson-add-vpu-clk-setting-for-S4.patch
>>>> It is 6.18 adaptation of 
>>>> https://patchwork.kernel.org/project/linux-amlogic/patch/20250110-drm-s4-v1-9-cbc2d5edaae8 at amlogic.com/
>>>>
>>>> As kernel hangs - i have limited caps to drill where root cause is.
>>>>
>>>> Maybe above hang is reason of my backports or missing any pre-req 
>>>> required to get s4 drm working?
>>>> Anyway - it will be good to test with updated to 6.18 series of Add 
>>>> DRM support for Amlogic S4 (plus info about any pre-req required to 
>>>> get s4 drm working)
>>>>
>>>>
>>>>> The vpu_clk on S4 doesn't support sysclk_b_sel as one of its
>>>>> selectable clock sources, so this reparent operation will definitely
>>>>> fail. This has nothing to do with the kernel version.
>>>>>
>>>>>>> Wiadomo?? napisana przez Ao Xu via B4 Relay 
>>>>>>> <devnull+ao.xu.amlogic.com at kernel.org> w dniu 10 sty 2025, o 
>>>>>>> godz. 06:39:
>>>>>>>
>>>>>>> From: Ao Xu <ao.xu at amlogic.com>
>>>>>>>
>>>>>>> Add devicetree document for S4 HDMI controller
>>>>>>>
>>>>>>> Signed-off-by: Ao Xu <ao.xu at amlogic.com>
>>>>>>> ---
>>>>>>> Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml 
>>>>>>> | 1 +
>>>>>>> 1 file changed, 1 insertion(+)
>>>>>>>
>>>>>>> diff --git 
>>>>>>> a/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml 
>>>>>>> b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml 
>>>>>>>
>>>>>>> index 
>>>>>>> 84d68b8cfccc86fd87a6a0fd2b70af12e51eb8a4..6e0a8369eee915fab55af24d450a6c40e08def38 
>>>>>>> 100644
>>>>>>> --- 
>>>>>>> a/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml 
>>>>>>>
>>>>>>> +++ 
>>>>>>> b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml 
>>>>>>>
>>>>>>> @@ -55,6 +55,7 @@ properties:
>>>>>>> ?????????? - const: amlogic,meson-gx-dw-hdmi
>>>>>>> ?????? - enum:
>>>>>>> ?????????? - amlogic,meson-g12a-dw-hdmi # G12A (S905X2, S905Y2, 
>>>>>>> S905D2)
>>>>>>> +????????? - amlogic,meson-s4-dw-hdmi # S4 (S905Y4)
>>>>>>>
>>>>>>> ?? reg:
>>>>>>> ???? maxItems: 1
>>>>>>>
>>>>>>> -- 
>>>>>>> 2.43.0
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> _______________________________________________
>>>>>>> linux-amlogic mailing list
>>>>>>> linux-amlogic at lists.infradead.org
>>>>>>> http://lists.infradead.org/mailman/listinfo/linux-amlogic
>>>>>> _______________________________________________
>>>>>> linux-amlogic mailing list
>>>>>> linux-amlogic at lists.infradead.org
>>>>>> http://lists.infradead.org/mailman/listinfo/linux-amlogic
-------------- next part --------------
Index: linux-next/meson_vclk.c
===================================================================
--- linux-next.orig/meson_vclk.c	2025-12-05 14:58:29.031454174 +0800
+++ linux-next/meson_vclk.c	2025-12-05 15:00:34.935204219 +0800
@@ -597,11 +597,11 @@
 		.vclk_div = 1,
 	},
 	[MESON_VCLK_HDMI_27000] = {
-		.pll_freq = 4320000,
-		.phy_freq = 270000,
-		.vclk_freq = 54000,
-		.venc_freq = 27000,
-		.pixel_freq = 27000,
+		.pll_freq = 4320000000,
+		.phy_freq = 270000000,
+		.vclk_freq = 54000000,
+		.venc_freq = 27000000,
+		.pixel_freq = 27000000,
 		.pll_od1 = 4,
 		.pll_od2 = 4,
 		.pll_od3 = 1,
@@ -1148,15 +1148,15 @@
 		meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
 	} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_S4)) {
 		switch (pll_base_freq) {
-		case 2970000:
+		case 2970000000:
 			m = 0x7b;
 			frac = vic_alternate_clock ? 0x140b4 : 0x18000;
 			break;
-		case 4320000:
+		case 4320000000:
 			m = vic_alternate_clock ? 0xb3 : 0xb4;
 			frac = vic_alternate_clock ? 0x1a3ee : 0;
 			break;
-		case 5940000:
+		case 5940000000:
 			m = 0xf7;
 			frac = vic_alternate_clock ? 0x8148 : 0x10000;
 			break;

From royluo at google.com  Thu Dec  4 23:14:39 2025
From: royluo at google.com (Roy Luo)
Date: Thu, 4 Dec 2025 23:14:39 -0800
Subject: [PATCH v9 2/2] usb: dwc3: Add Google Tensor SoC DWC3 glue driver
In-Reply-To: <2025120553-suffrage-divisive-5890@gregkh>
References: <20251205-controller-v9-0-9f158b18f979@google.com>
 <20251205-controller-v9-2-9f158b18f979@google.com> <2025120553-suffrage-divisive-5890@gregkh>
Message-ID: <CA+zupgzL7v5MZDpxKDQQCqAZaqTdHbiG9-xTr+8RnigMFZJ_7Q@mail.gmail.com>

On Thu, Dec 4, 2025 at 10:05?PM Greg Kroah-Hartman
<gregkh at linuxfoundation.org> wrote:
>
> On Fri, Dec 05, 2025 at 02:26:38AM +0000, Roy Luo wrote:
> > +config USB_DWC3_GOOGLE
> > +     tristate "Google Platform"
> > +     depends on ARCH_GOOGLE || COMPILE_TEST
>
> There is no ARCH_GOOGLE in the tree now, so how is this supposed to
> work?  Shouldn't tools that check for "invalid config options" trigger
> on this?
>
> thanks,
>
> greg k-h

Hi Greg,

The menuconfig looks like the following and it doesn't complain:
| Symbol: ARCH_GOOGLE [=ARCH_GOOGLE]
| Type  : unknown
|
| Symbol: PHY_GOOGLE_USB [=y]
| Type  : tristate
| Defined at drivers/phy/Kconfig:104
|     Prompt: Google Tensor SoC USB PHY driver
|     Depends on: ARCH_GOOGLE || COMPILE_TEST [=y]

According to Kconfig documentation [1], the unknown symbol
would simply be evaluated as an "n", which is what we want.
"Convert the symbol into an expression. Boolean and tristate
symbols are simply converted into the respective expression
values. All other symbol types result in ?n?."

In a different Kconfig documentation, an environment variable
"KCONFIG_WARN_UNKNOWN_SYMBOLS" is there to detect
undefined symbols in the "config input", but I can't find one that
catches undefined symbols in the Kconfig tree itself.

That is, the tool seems to allow this.
However, if this turns out to be a major problem. I think we
can either:
- Remove ARCH_GOOGLE and leave COMPILE_TEST as
  the only dependency. Then add ARCH_GOOGLE back
  later once it's in the tree.
- Defer the whole patch series until ARCH_GOOGLE is
  present (I hope not).

[1] https://docs.kernel.org/kbuild/kconfig-language.html#menu-dependencies
[2] https://www.kernel.org/doc/Documentation/kbuild/kconfig.rst

Regards,
Roy Luo


From ziniu.wang_1 at nxp.com  Thu Dec  4 23:17:29 2025
From: ziniu.wang_1 at nxp.com (ziniu.wang_1 at nxp.com)
Date: Fri,  5 Dec 2025 15:17:29 +0800
Subject: [PATCH v2] mmc: sdhci-esdhc-imx: wait for data transfer completion before reset
Message-ID: <20251205071729.83857-1-ziniu.wang_1@nxp.com>

From: Luke Wang <ziniu.wang_1 at nxp.com>

On IMX7ULP platforms, certain SD cards (e.g. Kingston Canvas Go! Plus)
cause system hangs and reboots during manual tuning. These cards exhibit
large gaps (~16us) between tuning command response and data transmission.
When cmd CRC errors occur during tuning, the code assumes data errors even
tuning data hasn't been fully received and then reset host data circuit.

Per IMX7ULP reference manual, reset operations (RESET_DATA/ALL) need to
make sure no active data transfers. Previously, resetting while data was
in-flight would clear data circuit, including ADMA/SDMA address, causing
data to be transmitted to incorrect memory address. This patch adds
polling for data transfer completion before executing resets.

Signed-off-by: Luke Wang <ziniu.wang_1 at nxp.com>
---
v2: amend commit message
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index a7a5df673b0f..affde1936510 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -1453,6 +1453,21 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
 
 static void esdhc_reset(struct sdhci_host *host, u8 mask)
 {
+	u32 present_state;
+	int ret;
+
+	/*
+	 * For data or full reset, ensure any active data transfer completes
+	 * before resetting to avoid system hang.
+	 */
+	if (mask & (SDHCI_RESET_DATA | SDHCI_RESET_ALL)) {
+		ret = readl_poll_timeout_atomic(host->ioaddr + ESDHC_PRSSTAT, present_state,
+						!(present_state & SDHCI_DATA_INHIBIT), 2, 100000);
+		if (ret == -ETIMEDOUT)
+			dev_warn(mmc_dev(host->mmc),
+				 "timeout waiting for data transfer completion\n");
+	}
+
 	sdhci_and_cqhci_reset(host, mask);
 
 	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
-- 
2.34.1



From wenst at chromium.org  Thu Dec  4 23:57:09 2025
From: wenst at chromium.org (Chen-Yu Tsai)
Date: Fri, 5 Dec 2025 15:57:09 +0800
Subject: Proposal: Officially allow "incomplete" trees as a base
In-Reply-To: <CAD=FV=U54Uwny=kHY+VjG5DGCSHeRUCcWMG=hG88ov8hC6Ynew@mail.gmail.com>
References: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
 <CAD++jLkuRQKoiEN928GtAj7wUts5PxH905bLp6ZhKsJ3NnenEA@mail.gmail.com>
 <CAD=FV=X5=AK4XMANv+fatn3d9Y5vo9AXsHWb_47HmNaMWUtMwA@mail.gmail.com>
 <CAGXv+5HyMYgKmLc+jmkj-gytm9SNVg9dS7Vn3dQ-dsH8Wo+4sg@mail.gmail.com>
 <CAD=FV=Uq9yfUkLUgg116G+2AvEKkEPmdRgUJ5f1bj229j=LxUg@mail.gmail.com>
 <CAGXv+5HU2y-8AZhXDjneaTdD1yr2h06OXbkozcQJj2mBcR1HmQ@mail.gmail.com> <CAD=FV=U54Uwny=kHY+VjG5DGCSHeRUCcWMG=hG88ov8hC6Ynew@mail.gmail.com>
Message-ID: <CAGXv+5EXBimfLyK7bmyyHmNcPBNQ=wN+i1_siaMUcibiB7BCPQ@mail.gmail.com>

On Thu, Dec 4, 2025 at 12:32?AM Doug Anderson <dianders at chromium.org> wrote:
>
> Hi,
>
> On Tue, Dec 2, 2025 at 11:34?PM Chen-Yu Tsai <wenst at chromium.org> wrote:
> >
> > On Wed, Dec 3, 2025 at 6:11?AM Doug Anderson <dianders at chromium.org> wrote:
> > >
> > > > In the simplest example we could have one base dts and two overlays
> > > > for two different DSI panel models:
> > > >
> > > >   - base.dtb
> > > >     - panel-model-a.dtbo
> > > >     - panel-model-b.dtbo
> > > >
> > > > The problem we then run into is that the base.dtb will only have the
> > > > generic model compatible "google,foo", not the sku and revision
> > > > specific ones like "google,foo-sku1-rev2".
> > > >
> > > > And we'd really like to avoid having _more_ overlays just to add the
> > > > final specific compatible string, as that kind of defeats the purpose
> > > > of using overlays to reduce the number of dts files.
> > >
> > > I think you may have simplified the above a little too much to the
> > > point where it's confusing. At least I'm a bit confused. I _think_ the
> > > problems you're talking about are the kinds of things we run into when
> > > we take overlays above just two levels. I'm imagining:
> > >
> > > - base.dtb
> > > - board1-rev1.dtbo
> > > - board2-rev1.dtbo
> > > - board1-rev2.dtbo
> > > - board2-rev2.dtbo
> > > - panel-a.dtbo
> > > - panel-b.dtbo
> > >
> > > So I think you're saying that you'd start with the "base.dtb" and then
> > > extend it with exactly one of the "board" overlays and then exactly
> > > one of the "panel" overlays. Is that right?
> >
> > For now I think we just experiment with having one end "model" or
> > "product" as the base.dtb. The panel-*.dtbo selected describe the
> > optional components, while the board-rev??.dtbo just provides the
> > top level compatible and model.
> >
> > In an example that I plan to send out this week, I would rework:
> >
> >   - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri.dtsi
> >     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku0.dts
> >     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku1.dts
> >     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku2.dts
> >     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku3.dts
> >     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku4.dts
> >     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku5.dts
> >     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku6.dts
> >     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku7.dts
> >
> > into:
> >
> >   - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri.dts
> >     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-audio-max98390-es8326.dtso
> >     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-audio-max98390-rt5682s.dtso
> >     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-audio-tas2563-es8326.dtso
> >     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-audio-tas2563-rt5682s.dtso
> >     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-panel-boe.dtso
> >     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-panel-ivo.dtso
> >     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku0.dtso
> >     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku1.dtso
> >     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku2.dtso
> >     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku3.dtso
> >     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku4.dtso
> >     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku5.dtso
> >     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku6.dtso
> >     - arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku7.dtso
> >
> > The "mt8188-geralt-ciri-sku?.dtso" files only contain the following
> > boilerplate:
> >
> >     /dts-v1/;
> >     /plugin/;
> >
> >     &{/} {
> >         model = "Google Ciri sku? board (rev4)";
> >         compatible = "google,ciri-sku?", "google,ciri", "mediatek,mt8188";
> >     };
> >
> > The base "mt8188-geralt-ciri.dts" would already have a generic board-
> > specific compatible:
> >
> >     model = "Google Ciri board";
> >     compatible = "google,ciri", "mediatek,mt8188";
> >
> > > So I'd imagine that each of the "board" overlays could have "full"
> > > compatible strings. For instance, I'd imagine "board2-rev2" could
> > > have:
> > >
> > > compatible = "google,booard2-rev2", "socVendor,soc"
> > >
> > >
> > > The problem you're struggling with (I think) is that the panel
> > > overlays won't be represented in the compatible string (and "model")
> > > even though (historically) we always did in ChromeOS (they were
> > > included in the "sku" part of the compatible string).
> > >
> > > Did I get that right?
> >
> > In a sense you've generalized the problem I was describing.
> >
> > In my example, the top level compatible gets fixed up by the final
> > SKU-specific overlay. But that's 8 extra files to do one bit of
> > fixup that supposedly the bootloader could be taught to do, and
> > could do even better. The bootloader knows exactly which SKU and
> > revision it's running on and can insert the information appropriately.
> > We could get rid of those awkwardly long compatible string sequences:
> >
> >   compatible = "google,tentacruel-sku262147", "google,tentacruel-sku262146",
> >                "google,tentacruel-sku262145", "google,tentacruel-sku262144",
> >                "google,tentacruel", "mediatek,mt8186";
> >
> > Going back to what I think you're describing, is that instead of one
> > base board DTB for each product, we could have one base DTB for the
> > reference design (in place of the .dtsi file we currently have), and
> > make products and component selection all use overlays.
> >
> > If we do that, then inserting the correct top level compatible and model
> > becomes more important, since we do have things such as the ChromeOS OF
> > component prober working based on top level compatible. Also, the model
> > is present in logs, and would be very misleading to say one device name
> > while in reality it is a different one.
>
> I wasn't saying that you'd just have the same "compatible" for every
> derivative of a reference board. That seems over the top. I was
> thinking that you'd even have a unique "compatible" for each revision
> of each board instance. I'm simply suggesting that you don't need a
> per-SKU "compatible". Those don't add any real benefit, do they?
>
> In your Ciri example above, you could get rid of all of the "sku"
> overlay files since you've said that all they're doing is updating the
> "compatible". Since (I think) you're only trying to support "rev4"
> based on your model string, that would leave you just one file for
> Ciri. If you had more than one revision then you'd have more than one,
> but it doesn't need to be multiplied by the SKUs, right?

That's right. What I was saying was that the final device tree only has
a simplified compatible, but maybe someone would want a proper one inserted.

ChenYu


From yanan.yang at nxp.com  Fri Dec  5 00:03:57 2025
From: yanan.yang at nxp.com (Yanan.Yang)
Date: Fri, 05 Dec 2025 17:03:57 +0900
Subject: [PATCH 0/2] Add NXP FRDM-IMX91S board support
Message-ID: <20251205-imx91s-frdm-v1-0-afd6cd01c299@nxp.com>

This patch set introduces DeviceTree support for the NXP FRDM-IMX91S
development board based on the i.MX91 SoC. FRDM-IMX91S is a cost-optimized
variant of FRDM-IMX91 and differs in several hardware aspects:

- 512MB LPDDR4 (FRDM-IMX91 uses 1GB)
- 256MB FlexSPI-NAND (FRDM-IMX91 uses 8GB eMMC)
- Single GbE port (FRDM-IMX91 has dual GbE)
- PMIC PF9453 (FRDM-IMX91 uses PCA9451A)

This patch has been tested on FRDM-IMX91S board and verified for basic
functionality.

For more details about the FRDM-IMX91S board, see:
https://www.nxp.com/design/design-center/development-boards-and-designs/FRDM-IMX91S

Signed-off-by: Yanan.Yang <yanan.yang at nxp.com>
---
Yanan.Yang (2):
      dt-bindings: arm: fsl: Add FRDM-IMX91S board
      arm64: dts: freescale: add NXP FRDM-IMX91S board support

 Documentation/devicetree/bindings/arm/fsl.yaml     |   1 +
 arch/arm64/boot/dts/freescale/Makefile             |   1 +
 .../boot/dts/freescale/imx91-11x11-frdm-s.dts      | 692 +++++++++++++++++++++
 3 files changed, 694 insertions(+)
---
base-commit: bc04acf4aeca588496124a6cf54bfce3db327039
change-id: 20251205-imx91s-frdm-2c339bcc2f6f

Best regards,
-- 
Yanan.Yang <yanan.yang at nxp.com>



From yanan.yang at nxp.com  Fri Dec  5 00:03:58 2025
From: yanan.yang at nxp.com (Yanan.Yang)
Date: Fri, 05 Dec 2025 17:03:58 +0900
Subject: [PATCH 1/2] dt-bindings: arm: fsl: Add FRDM-IMX91S board
In-Reply-To: <20251205-imx91s-frdm-v1-0-afd6cd01c299@nxp.com>
References: <20251205-imx91s-frdm-v1-0-afd6cd01c299@nxp.com>
Message-ID: <20251205-imx91s-frdm-v1-1-afd6cd01c299@nxp.com>

Add DT compatible string for NXP FRDM-IMX91S board

The FRDM i.MX 91S development board is an low-cost and compact
development board featuring the i.MX 91 applications processor.

Signed-off-by: Yanan.Yang <yanan.yang at nxp.com>
---
 Documentation/devicetree/bindings/arm/fsl.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
index 68a2d5fecc43..82f28be401b8 100644
--- a/Documentation/devicetree/bindings/arm/fsl.yaml
+++ b/Documentation/devicetree/bindings/arm/fsl.yaml
@@ -1412,6 +1412,7 @@ properties:
         items:
           - enum:
               - fsl,imx91-11x11-evk       # i.MX91 11x11 EVK Board
+              - fsl,imx91-11x11-frdm-s    # FRDM-IMX91S Board
           - const: fsl,imx91
 
       - description: i.MX93 based Boards

-- 
2.43.0



From yanan.yang at nxp.com  Fri Dec  5 00:03:59 2025
From: yanan.yang at nxp.com (Yanan.Yang)
Date: Fri, 05 Dec 2025 17:03:59 +0900
Subject: [PATCH 2/2] arm64: dts: freescale: add NXP FRDM-IMX91S board
 support
In-Reply-To: <20251205-imx91s-frdm-v1-0-afd6cd01c299@nxp.com>
References: <20251205-imx91s-frdm-v1-0-afd6cd01c299@nxp.com>
Message-ID: <20251205-imx91s-frdm-v1-2-afd6cd01c299@nxp.com>

Add DeviceTree support for the NXP FRDM-IMX91S development board based
on the i.MX91 SoC. FRDM-IMX91S is a cost-optimized variant of FRDM-IMX91
and differs in memory, storage, Ethernet, and PMIC configuration:

- 512MB LPDDR4 (FRDM-IMX91 uses 1GB)
- 256MB FlexSPI-NAND (FRDM-IMX91 uses 8GB eMMC)
- Single GbE port (FRDM-IMX91 has dual GbE)
- PMIC PF9453 (FRDM-IMX91 uses PCA9451A)

This DT enables:
- ADC1
- UART1 and UART5
- I2C bus and children nodes
- USB and related nodes
- uSDHC1 and uSDHC2
- FlexSPI NAND flash
- Watchdog3
- Ethernet (eqos)
- FlexCAN
- MQS

Link: https://www.nxp.com/design/design-center/development-boards-and-designs/FRDM-IMX91S
(FRDM-IMX91S board page)
Link: https://www.nxp.com/design/design-center/development-boards-and-designs/FRDM-IMX91
(FRDM-IMX91 board page)

Co-developed-by: Lei Xu <lei.xu at nxp.com>
Signed-off-by: Lei Xu <lei.xu at nxp.com>
Co-developed-by: Xiaofeng Wei <xiaofeng.wei at nxp.com>
Signed-off-by: Xiaofeng Wei <xiaofeng.wei at nxp.com>
Signed-off-by: Yanan.Yang <yanan.yang at nxp.com>
---
 arch/arm64/boot/dts/freescale/Makefile             |   1 +
 .../boot/dts/freescale/imx91-11x11-frdm-s.dts      | 692 +++++++++++++++++++++
 2 files changed, 693 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index f30d3fd724d0..927bf76a05f3 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -368,6 +368,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8qxp-tqma8xqps-mb-smarc-2.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8ulp-9x9-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8ulp-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx91-11x11-evk.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx91-11x11-frdm-s.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx91-phyboard-segin.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx91-tqma9131-mba91xxca.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx93-9x9-qsb.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx91-11x11-frdm-s.dts b/arch/arm64/boot/dts/freescale/imx91-11x11-frdm-s.dts
new file mode 100644
index 000000000000..0952a685c3f5
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx91-11x11-frdm-s.dts
@@ -0,0 +1,692 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2025 NXP
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/usb/pd.h>
+#include "imx91.dtsi"
+
+/ {
+	compatible = "fsl,imx91-11x11-frdm-s", "fsl,imx91";
+	model = "NXP FRDM-IMX91S board";
+
+	aliases {
+		ethernet0 = &fec;
+		ethernet1 = &eqos;
+		gpio0 = &gpio1;
+		gpio1 = &gpio2;
+		gpio2 = &gpio3;
+		gpio3 = &gpio4;
+		i2c0 = &lpi2c1;
+		i2c1 = &lpi2c2;
+		i2c2 = &lpi2c3;
+		i2c3 = &lpi2c4;
+		i2c4 = &lpi2c5;
+		i2c5 = &lpi2c6;
+		i2c6 = &lpi2c7;
+		i2c7 = &lpi2c8;
+		mmc0 = &usdhc1;
+		mmc1 = &usdhc2;
+		mmc2 = &usdhc3;
+		rtc0 = &bbnsm_rtc;
+		serial0 = &lpuart1;
+		serial1 = &lpuart2;
+		serial2 = &lpuart3;
+		serial3 = &lpuart4;
+		serial4 = &lpuart5;
+		serial5 = &lpuart6;
+		serial6 = &lpuart7;
+		serial7 = &lpuart8;
+	};
+
+	chosen {
+		stdout-path = &lpuart1;
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+		pinctrl-0 = <&pinctrl_gpio_key>;
+		pinctrl-names = "default";
+
+		button {
+			interrupt-parent = <&gpio3>;
+			interrupts = <26 IRQ_TYPE_EDGE_FALLING>;
+			gpios = <&gpio3 26 GPIO_PULL_UP>;
+			label = "User Button";
+			linux,code = <BTN_1>;
+		};
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+
+		status {
+			default-state = "on";
+			gpios = <&pcal6524 7 GPIO_ACTIVE_LOW>;
+			label = "green:status";
+		};
+	};
+
+	reg_vref_1v8: regulator-adc-vref {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <1800000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-name = "vref_1v8";
+	};
+
+	reg_can_stby: regulator-can-stby {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "can-stby";
+		gpio = <&gpio1 10 GPIO_ACTIVE_LOW>;
+	};
+
+	reg_usdhc1_vmmc: regulator-usdhc1 {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "WLAN_EN";
+		startup-delay-us = <20000>;
+		gpio = <&pcal6524 3 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_usdhc2_vmmc: regulator-usdhc2 {
+		compatible = "regulator-fixed";
+		off-on-delay-us = <12000>;
+		pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
+		pinctrl-names = "default";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "VSD_3V3";
+		gpio = <&gpio3 7 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_usb_vbus: regulator-vbus {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <5000000>;
+		regulator-min-microvolt = <5000000>;
+		regulator-name = "USB_VBUS";
+		gpio = <&pcal6524 15 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reserved-memory {
+		ranges;
+		#address-cells = <2>;
+		#size-cells = <2>;
+
+		linux,cma {
+			compatible = "shared-dma-pool";
+			alloc-ranges = <0 0x80000000 0 0x20000000>;
+			reusable;
+			size = <0 0x2000000>;
+			linux,cma-default;
+		};
+	};
+
+	sound-mqs {
+		compatible = "fsl,imx6sx-sdb-mqs", "fsl,imx-audio-mqs";
+		audio-codec = <&mqs1>;
+		audio-cpu = <&sai1>;
+		model = "mqs-audio";
+	};
+
+	usdhc1_pwrseq: usdhc1_pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&pcal6524 18 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&adc1 {
+	vref-supply = <&reg_vref_1v8>;
+	status = "okay";
+};
+
+&eqos {
+	phy-handle = <&ethphy1>;
+	phy-mode = "rgmii-id";
+	pinctrl-0 = <&pinctrl_eqos>;
+	pinctrl-1 = <&pinctrl_eqos_sleep>;
+	pinctrl-names = "default", "sleep";
+	status = "okay";
+
+	mdio {
+		compatible = "snps,dwmac-mdio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-frequency = <5000000>;
+
+		ethphy1: ethernet-phy at 4 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <4>;
+		};
+	};
+};
+
+&flexcan1 {
+	pinctrl-0 = <&pinctrl_flexcan1>;
+	pinctrl-1 = <&pinctrl_flexcan1_sleep>;
+	pinctrl-names = "default", "sleep";
+	xceiver-supply = <&reg_can_stby>;
+	status = "okay";
+};
+
+&flexspi1 {
+	pinctrl-0 = <&pinctrl_flexspi1>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	flash at 0 {
+		compatible = "spi-nand";
+		reg = <0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		spi-max-frequency = <104000000>;
+		spi-rx-bus-width = <4>;
+		spi-tx-bus-width = <4>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition at 0 {
+				reg = <0x000000 0x800000>;
+				label = "bootloader";
+			};
+
+			partition at 1 {
+				reg = <0x800000 0x800000>;
+				label = "env";
+			};
+
+			partition at 2 {
+				reg = <0x1000000 0x2800000>;
+				label = "kernel";
+			};
+
+			partition at 3 {
+				reg = <0x3800000 0x20000>;
+				label = "dtb";
+			};
+
+			partition at 4 {
+				reg = <0x3820000 0xFFFFFFFF>;
+				label = "rootfs";
+				linux,rootfs;
+			};
+		};
+	};
+};
+
+&iomuxc {
+	pinctrl_eqos: eqosgrp {
+		fsl,pins = <
+			MX91_PAD_ENET1_MDC__ENET1_MDC                           0x57e
+			MX91_PAD_ENET1_MDIO__ENET_QOS_MDIO                      0x57e
+			MX91_PAD_ENET1_RD0__ENET_QOS_RGMII_RD0                  0x57e
+			MX91_PAD_ENET1_RD1__ENET_QOS_RGMII_RD1                  0x57e
+			MX91_PAD_ENET1_RD2__ENET_QOS_RGMII_RD2                  0x57e
+			MX91_PAD_ENET1_RD3__ENET_QOS_RGMII_RD3                  0x57e
+			MX91_PAD_ENET1_RXC__ENET_QOS_RGMII_RXC                  0x5fe
+			MX91_PAD_ENET1_RX_CTL__ENET_QOS_RGMII_RX_CTL            0x57e
+			MX91_PAD_ENET1_TD0__ENET_QOS_RGMII_TD0                  0x57e
+			MX91_PAD_ENET1_TD1__ENET1_RGMII_TD1                     0x57e
+			MX91_PAD_ENET1_TD2__ENET_QOS_RGMII_TD2                  0x57e
+			MX91_PAD_ENET1_TD3__ENET_QOS_RGMII_TD3                  0x57e
+			MX91_PAD_ENET1_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK  0x5fe
+			MX91_PAD_ENET1_TX_CTL__ENET_QOS_RGMII_TX_CTL            0x57e
+		>;
+	};
+
+	pinctrl_eqos_sleep: eqossleepgrp {
+		fsl,pins = <
+			MX91_PAD_ENET1_MDC__GPIO4_IO0                           0x31e
+			MX91_PAD_ENET1_MDIO__GPIO4_IO1                          0x31e
+			MX91_PAD_ENET1_RD0__GPIO4_IO10                          0x31e
+			MX91_PAD_ENET1_RD1__GPIO4_IO11                          0x31e
+			MX91_PAD_ENET1_RD2__GPIO4_IO12                          0x31e
+			MX91_PAD_ENET1_RD3__GPIO4_IO13                          0x31e
+			MX91_PAD_ENET1_RXC__GPIO4_IO9                           0x31e
+			MX91_PAD_ENET1_RX_CTL__GPIO4_IO8                        0x31e
+			MX91_PAD_ENET1_TD0__GPIO4_IO5                           0x31e
+			MX91_PAD_ENET1_TD1__GPIO4_IO4                           0x31e
+			MX91_PAD_ENET1_TD2__GPIO4_IO3                           0x31e
+			MX91_PAD_ENET1_TD3__GPIO4_IO2                           0x31e
+			MX91_PAD_ENET1_TXC__GPIO4_IO7                           0x31e
+			MX91_PAD_ENET1_TX_CTL__GPIO4_IO6                        0x31e
+		>;
+	};
+
+	pinctrl_flexcan1: flexcan1grp {
+		fsl,pins = <
+			MX91_PAD_GPIO_IO28__CAN1_TX			0x139e
+			MX91_PAD_GPIO_IO29__CAN1_RX			0x139e
+			MX91_PAD_PDM_BIT_STREAM1__GPIO1_IO10		0x31e
+		>;
+	};
+
+	pinctrl_flexcan1_sleep: flexcan1sleepgrp {
+		fsl,pins = <
+			MX91_PAD_GPIO_IO28__GPIO2_IO28			0x31e
+			MX91_PAD_GPIO_IO29__GPIO2_IO29			0x31e
+			MX91_PAD_PDM_BIT_STREAM1__GPIO1_IO10		0x31e
+		>;
+	};
+
+	pinctrl_flexspi1: flexspi1grp {
+		fsl,pins = <
+			MX91_PAD_SD3_CLK__FLEXSPI1_A_SCLK	0x3fe
+			MX91_PAD_SD3_CMD__FLEXSPI1_A_SS0_B	0x3fe
+			MX91_PAD_SD3_DATA0__FLEXSPI1_A_DATA0	0x3fe
+			MX91_PAD_SD3_DATA1__FLEXSPI1_A_DATA1	0x3fe
+			MX91_PAD_SD3_DATA2__FLEXSPI1_A_DATA2	0x3fe
+			MX91_PAD_SD3_DATA3__FLEXSPI1_A_DATA3	0x3fe
+		>;
+	};
+
+	pinctrl_gpio_key: gpiokeysgrp {
+		fsl,pins = <
+			MX91_PAD_CCM_CLKO1__GPIO3_IO26             0x0000031E
+		>;
+	};
+
+	pinctrl_lpi2c1: lpi2c1grp {
+		fsl,pins = <
+			MX91_PAD_I2C1_SCL__LPI2C1_SCL                           0x40000b9e
+			MX91_PAD_I2C1_SDA__LPI2C1_SDA                           0x40000b9e
+		>;
+	};
+
+	pinctrl_lpi2c2: lpi2c2grp {
+		fsl,pins = <
+			MX91_PAD_I2C2_SCL__LPI2C2_SCL                           0x40000b9e
+			MX91_PAD_I2C2_SDA__LPI2C2_SDA                           0x40000b9e
+		>;
+	};
+
+	pinctrl_mqs1: mqs1grp {
+		fsl,pins = <
+			MX91_PAD_PDM_CLK__MQS1_LEFT			0x31e
+			MX91_PAD_PDM_BIT_STREAM0__MQS1_RIGHT		0x31e
+		>;
+	};
+
+	pinctrl_pcal6524: pcal6524grp {
+		fsl,pins = <
+			MX91_PAD_CCM_CLKO2__GPIO3_IO27                          0x31e
+			MX91_PAD_SD1_DATA5__GPIO3_IO15			0x31e
+		>;
+	};
+
+	pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
+		fsl,pins = <
+			MX91_PAD_SD2_RESET_B__GPIO3_IO7                         0x31e
+		>;
+	};
+
+	pinctrl_uart1: uart1grp {
+		fsl,pins = <
+			MX91_PAD_UART1_RXD__LPUART1_RX                          0x31e
+			MX91_PAD_UART1_TXD__LPUART1_TX                          0x31e
+		>;
+	};
+
+	pinctrl_uart5: uart5grp {
+		fsl,pins = <
+			MX91_PAD_DAP_TDO_TRACESWO__LPUART5_TX                   0x31e
+			MX91_PAD_DAP_TDI__LPUART5_RX                            0x31e
+			MX91_PAD_DAP_TMS_SWDIO__LPUART5_RTS_B                   0x31e
+			MX91_PAD_DAP_TCLK_SWCLK__LPUART5_CTS_B                  0x31e
+		>;
+	};
+
+	pinctrl_usdhc1: usdhc1grp {
+		fsl,pins = <
+			MX91_PAD_SD1_CLK__USDHC1_CLK                            0x1582
+			MX91_PAD_SD1_CMD__USDHC1_CMD                            0x1382
+			MX91_PAD_SD1_DATA0__USDHC1_DATA0                        0x1382
+			MX91_PAD_SD1_DATA1__USDHC1_DATA1                        0x1382
+			MX91_PAD_SD1_DATA2__USDHC1_DATA2                        0x1382
+			MX91_PAD_SD1_DATA3__USDHC1_DATA3                        0x1382
+			MX91_PAD_SD1_DATA4__GPIO3_IO14		0x031E
+			MX91_PAD_SD1_STROBE__GPIO3_IO18		0x031E
+		>;
+	};
+
+	pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp {
+		fsl,pins = <
+			MX91_PAD_SD1_CLK__USDHC1_CLK                            0x158e
+			MX91_PAD_SD1_CMD__USDHC1_CMD                            0x138e
+			MX91_PAD_SD1_DATA0__USDHC1_DATA0                        0x138e
+			MX91_PAD_SD1_DATA1__USDHC1_DATA1                        0x138e
+			MX91_PAD_SD1_DATA2__USDHC1_DATA2                        0x138e
+			MX91_PAD_SD1_DATA3__USDHC1_DATA3                        0x138e
+			MX91_PAD_SD1_DATA4__GPIO3_IO14		0x031E
+			MX91_PAD_SD1_STROBE__GPIO3_IO18		0x031E
+		>;
+	};
+
+	pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp {
+		fsl,pins = <
+			MX91_PAD_SD1_CLK__USDHC1_CLK                            0x15fe
+			MX91_PAD_SD1_CMD__USDHC1_CMD                            0x13fe
+			MX91_PAD_SD1_DATA0__USDHC1_DATA0                        0x13fe
+			MX91_PAD_SD1_DATA1__USDHC1_DATA1                        0x13fe
+			MX91_PAD_SD1_DATA2__USDHC1_DATA2                        0x13fe
+			MX91_PAD_SD1_DATA3__USDHC1_DATA3                        0x13fe
+			MX91_PAD_SD1_DATA4__GPIO3_IO14		0x031E
+			MX91_PAD_SD1_STROBE__GPIO3_IO18		0x031E
+		>;
+	};
+
+	pinctrl_usdhc2_gpio: usdhc2gpiogrp {
+		fsl,pins = <
+			MX91_PAD_SD2_CD_B__GPIO3_IO0                            0x31e
+		>;
+	};
+
+	pinctrl_usdhc2_gpio_sleep: usdhc2gpiosleepgrp {
+		fsl,pins = <
+			MX91_PAD_SD2_CD_B__GPIO3_IO0                            0x51e
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			MX91_PAD_SD2_CLK__USDHC2_CLK                            0x1582
+			MX91_PAD_SD2_CMD__USDHC2_CMD                            0x1382
+			MX91_PAD_SD2_DATA0__USDHC2_DATA0                        0x1382
+			MX91_PAD_SD2_DATA1__USDHC2_DATA1                        0x1382
+			MX91_PAD_SD2_DATA2__USDHC2_DATA2                        0x1382
+			MX91_PAD_SD2_DATA3__USDHC2_DATA3                        0x1382
+			MX91_PAD_SD2_VSELECT__USDHC2_VSELECT                    0x51e
+		>;
+	};
+
+	pinctrl_usdhc2_sleep: usdhc2sleepgrp {
+		fsl,pins = <
+			MX91_PAD_SD2_CLK__GPIO3_IO1                             0x51e
+			MX91_PAD_SD2_CMD__GPIO3_IO2                             0x51e
+			MX91_PAD_SD2_DATA0__GPIO3_IO3                           0x51e
+			MX91_PAD_SD2_DATA1__GPIO3_IO4                           0x51e
+			MX91_PAD_SD2_DATA2__GPIO3_IO5                           0x51e
+			MX91_PAD_SD2_DATA3__GPIO3_IO6                           0x51e
+			MX91_PAD_SD2_VSELECT__GPIO3_IO19                        0x51e
+		>;
+	};
+
+	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+		fsl,pins = <
+			MX91_PAD_SD2_CLK__USDHC2_CLK                            0x158e
+			MX91_PAD_SD2_CMD__USDHC2_CMD                            0x138e
+			MX91_PAD_SD2_DATA0__USDHC2_DATA0                        0x138e
+			MX91_PAD_SD2_DATA1__USDHC2_DATA1                        0x138e
+			MX91_PAD_SD2_DATA2__USDHC2_DATA2                        0x138e
+			MX91_PAD_SD2_DATA3__USDHC2_DATA3                        0x138e
+			MX91_PAD_SD2_VSELECT__USDHC2_VSELECT                    0x51e
+		>;
+	};
+
+	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+		fsl,pins = <
+			MX91_PAD_SD2_CLK__USDHC2_CLK                            0x15fe
+			MX91_PAD_SD2_CMD__USDHC2_CMD                            0x13fe
+			MX91_PAD_SD2_DATA0__USDHC2_DATA0                        0x13fe
+			MX91_PAD_SD2_DATA1__USDHC2_DATA1                        0x13fe
+			MX91_PAD_SD2_DATA2__USDHC2_DATA2                        0x13fe
+			MX91_PAD_SD2_DATA3__USDHC2_DATA3                        0x13fe
+			MX91_PAD_SD2_VSELECT__USDHC2_VSELECT                    0x51e
+		>;
+	};
+
+	pinctrl_wdog: wdoggrp {
+		fsl,pins = <
+			MX91_PAD_WDOG_ANY__WDOG1_WDOG_ANY       0x31e
+		>;
+	};
+};
+
+&lpi2c1 {
+	clock-frequency = <400000>;
+	pinctrl-0 = <&pinctrl_lpi2c1>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	pcf2131: rtc at 53 {
+		compatible = "nxp,pcf2131";
+		reg = <0x53>;
+		interrupt-parent = <&pcal6524>;
+		interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
+	};
+};
+
+&lpi2c2 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	clock-frequency = <400000>;
+	pinctrl-0 = <&pinctrl_lpi2c2>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	pcal6524: gpio at 22 {
+		compatible = "nxp,pcal6524";
+		reg = <0x22>;
+		#interrupt-cells = <2>;
+		interrupt-controller;
+		interrupt-parent = <&gpio3>;
+		interrupts = <27 IRQ_TYPE_LEVEL_LOW>;
+		#gpio-cells = <2>;
+		gpio-controller;
+		pinctrl-0 = <&pinctrl_pcal6524>;
+		pinctrl-names = "default";
+		reset-gpios = <&gpio3 15 GPIO_ACTIVE_LOW>;
+	};
+
+	pmic at 32 {
+		compatible = "nxp,pf9453";
+		reg = <0x32>;
+		interrupt-parent = <&pcal6524>;
+		interrupts = <10 IRQ_TYPE_EDGE_FALLING>;
+
+		regulators {
+			buck1: BUCK1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <3775000>;
+				regulator-min-microvolt = <600000>;
+				regulator-name = "BUCK1";
+			};
+
+			buck2: BUCK2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <2187500>;
+				regulator-min-microvolt = <600000>;
+				regulator-name = "BUCK2";
+				regulator-ramp-delay = <12500>;
+			};
+
+			buck3: BUCK3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <3775000>;
+				regulator-min-microvolt = <600000>;
+				regulator-name = "BUCK3";
+			};
+
+			buck4: BUCK4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <3775000>;
+				regulator-min-microvolt = <600000>;
+				regulator-name = "BUCK4";
+			};
+
+			ldo1: LDO1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <3300000>;
+				regulator-min-microvolt = <800000>;
+				regulator-name = "LDO1";
+			};
+
+			ldo2: LDO2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <1950000>;
+				regulator-min-microvolt = <500000>;
+				regulator-name = "LDO2";
+			};
+
+			ldo_snvs: LDO-SNVS {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <3400000>;
+				regulator-min-microvolt = <1200000>;
+				regulator-name = "LDO-SNVS";
+			};
+		};
+	};
+
+	ptn5110: tcpc at 52 {
+		compatible = "nxp,ptn5110", "tcpci";
+		reg = <0x52>;
+		interrupt-parent = <&gpio3>;
+		interrupts = <27 IRQ_TYPE_LEVEL_LOW>;
+
+		typec1_con: connector {
+			compatible = "usb-c-connector";
+			data-role = "dual";
+			label = "USB-C";
+			op-sink-microwatt = <15000000>;
+			power-role = "dual";
+			self-powered;
+			sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)
+				     PDO_VAR(5000, 20000, 3000)>;
+			source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
+			try-power-role = "sink";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+
+					typec1_dr_sw: endpoint {
+						remote-endpoint = <&usb1_drd_sw>;
+					};
+				};
+			};
+		};
+	};
+};
+
+&lpuart1 {
+	pinctrl-0 = <&pinctrl_uart1>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&lpuart5 {
+	pinctrl-0 = <&pinctrl_uart5>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	bluetooth {
+		compatible = "nxp,88w8987-bt";
+	};
+};
+
+&media_blk_ctrl {
+	status = "okay";
+};
+
+&mqs1 {
+	clocks = <&clk IMX93_CLK_MQS1_GATE>;
+	clock-names = "mclk";
+	pinctrl-0 = <&pinctrl_mqs1>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&sai1 {
+	clocks = <&clk IMX93_CLK_SAI1_IPG>, <&clk IMX93_CLK_DUMMY>,
+		 <&clk IMX93_CLK_SAI1_GATE>, <&clk IMX93_CLK_DUMMY>,
+		 <&clk IMX93_CLK_DUMMY>, <&clk IMX93_CLK_AUDIO_PLL>;
+	clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3", "pll8k";
+	assigned-clocks = <&clk IMX93_CLK_SAI1>;
+	assigned-clock-parents = <&clk IMX93_CLK_AUDIO_PLL>;
+	assigned-clock-rates = <24576000>;
+	#sound-dai-cells = <0>;
+	fsl,sai-mclk-direction-output;
+	status = "okay";
+};
+
+&usbotg1 {
+	adp-disable;
+	disable-over-current;
+	dr_mode = "otg";
+	hnp-disable;
+	srp-disable;
+	usb-role-switch;
+	samsung,picophy-dc-vol-level-adjust = <7>;
+	samsung,picophy-pre-emp-curr-control = <3>;
+	status = "okay";
+
+	port {
+		usb1_drd_sw: endpoint {
+			remote-endpoint = <&typec1_dr_sw>;
+		};
+	};
+};
+
+&usbotg2 {
+	disable-over-current;
+	dr_mode = "host";
+	vbus-supply = <&reg_usb_vbus>;
+	samsung,picophy-dc-vol-level-adjust = <7>;
+	samsung,picophy-pre-emp-curr-control = <3>;
+	status = "okay";
+};
+
+&usdhc1 {
+	bus-width = <8>;
+	keep-power-in-suspend;
+	mmc-pwrseq = <&usdhc1_pwrseq>;
+	non-removable;
+	pinctrl-0 = <&pinctrl_usdhc1>;
+	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	vmmc-supply = <&reg_usdhc1_vmmc>;
+	wakeup-source;
+	status = "okay";
+};
+
+&usdhc2 {
+	bus-width = <4>;
+	cd-gpios = <&gpio3 00 GPIO_ACTIVE_LOW>;
+	no-mmc;
+	no-sdio;
+	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-3 = <&pinctrl_usdhc2_sleep>, <&pinctrl_usdhc2_gpio_sleep>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	status = "okay";
+};
+
+&wdog3 {
+	pinctrl-0 = <&pinctrl_wdog>;
+	pinctrl-names = "default";
+	fsl,ext-reset-output;
+	status = "okay";
+};

-- 
2.43.0



From krzk at kernel.org  Fri Dec  5 00:08:54 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 5 Dec 2025 09:08:54 +0100
Subject: [RFC PATCH] arm64: broadcom: bcm2712: Rework rp1 overlay handling
In-Reply-To: <20251117211503.728354-2-robh@kernel.org>
References: <20251117211503.728354-2-robh@kernel.org>
Message-ID: <ae5d1a37-9af9-46a2-9ca0-83c276248931@kernel.org>

On 17/11/2025 22:15, Rob Herring (Arm) wrote:
> It's a requirement that DT overlays be applied at build time in order to
> validate them as overlays are not validated on their own.
> 
> Simply adding a build time target is possible, but it's also not desirable
> to have targets which include the overlay contents and apply the same
> overlay.
> 
> Rework the targets such that there are 2 overlays: the existing RP1 overlay
> and the board specific configuration of the RP1 (bcm2712-rpi-5-b.dtso).
> 
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> ---
> The missing applying of rp1.dtbo will soon be a warning[1].
> 
> The comment in bcm2712-rpi-5-b.dts(o) needs updating or removing. The RP1
> driver or userspace handling of the overlay probably needs updating to
> handle the 2 overlays. IIRC, I think we can apply overlays to overlays
> which may be useful here. If not, adding that to the tools should be
> possible.
> 
> [1] https://lore.kernel.org/all/20251114222759.4181152-1-robh at kernel.org/
> ---
>  arch/arm64/boot/dts/broadcom/Makefile                 | 10 ++++++++--
>  ...m2712-d-rpi-5-b.dts => bcm2712-d-rpi-5-b-base.dts} |  2 +-
>  .../{bcm2712-rpi-5-b.dts => bcm2712-rpi-5-b.dtso}     | 11 +++++------


So now Linus' tree has warnings. Can this be applied by anyone around
Broadcom and sent as fixes?


Best regards,
Krzysztof


From krzk at kernel.org  Fri Dec  5 00:10:12 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 5 Dec 2025 09:10:12 +0100
Subject: [PATCH v1 1/2] arm64: dts: mediatek: mt7986: add dtbs with
 applied overlays for bpi-r3
In-Reply-To: <20251119175124.48947-2-linux@fw-web.de>
References: <20251119175124.48947-1-linux@fw-web.de>
 <20251119175124.48947-2-linux@fw-web.de>
Message-ID: <fc5c9829-96fa-4028-a642-0792699e92a5@kernel.org>

On 19/11/2025 18:51, Frank Wunderlich wrote:
> From: Frank Wunderlich <frank-w at public-files.de>
> 
> Build devicetree binaries for testing overlays and providing users
> full dtb without using overlays.
> 
> Suggested-by: Rob Herring <robh+dt at kernel.org>
> Signed-off-by: Frank Wunderlich <frank-w at public-files.de>
> ---
> resend of
> https://patchwork.kernel.org/project/linux-mediatek/patch/20240608080530.9436-2-linux at fw-web.de/
> due to discussions here:
> https://patchwork.kernel.org/project/linux-mediatek/patch/20251117211306.725678-1-robh at kernel.org/
> 
> changes:
> - updated sd-nand with sata-overlay
> ---
>  arch/arm64/boot/dts/mediatek/Makefile | 21 +++++++++++++++++++++
>  1 file changed, 21 insertions(+)


This looks like still not being applied and now it is a warning in
Linus' tree.

Can this be applied and sent as fixes?

Best regards,
Krzysztof


From haibo.chen at nxp.com  Fri Dec  5 00:12:12 2025
From: haibo.chen at nxp.com (Bough Chen)
Date: Fri, 5 Dec 2025 08:12:12 +0000
Subject: [PATCH v2] mmc: sdhci-esdhc-imx: wait for data transfer
 completion before reset
In-Reply-To: <20251205071729.83857-1-ziniu.wang_1@nxp.com>
References: <20251205071729.83857-1-ziniu.wang_1@nxp.com>
Message-ID: <DU0PR04MB94962D103B1A92354CDD1FE690A7A@DU0PR04MB9496.eurprd04.prod.outlook.com>

> -----Original Message-----
> From: Luke Wang <ziniu.wang_1 at nxp.com>
> Sent: 2025?12?5? 15:17
> To: adrian.hunter at intel.com; Bough Chen <haibo.chen at nxp.com>;
> ulf.hansson at linaro.org
> Cc: shawnguo at kernel.org; s.hauer at pengutronix.de; kernel at pengutronix.de;
> festevam at gmail.com; linux-mmc at vger.kernel.org; imx at lists.linux.dev; dl-S32
> <S32 at nxp.com>; linux-arm-kernel at lists.infradead.org;
> linux-kernel at vger.kernel.org
> Subject: [PATCH v2] mmc: sdhci-esdhc-imx: wait for data transfer completion
> before reset
> 
> From: Luke Wang <ziniu.wang_1 at nxp.com>
> 
> On IMX7ULP platforms, certain SD cards (e.g. Kingston Canvas Go! Plus) cause
> system hangs and reboots during manual tuning. These cards exhibit large gaps
> (~16us) between tuning command response and data transmission.
> When cmd CRC errors occur during tuning, the code assumes data errors even
> tuning data hasn't been fully received and then reset host data circuit.
> 
> Per IMX7ULP reference manual, reset operations (RESET_DATA/ALL) need to
> make sure no active data transfers. Previously, resetting while data was in-flight
> would clear data circuit, including ADMA/SDMA address, causing data to be
> transmitted to incorrect memory address. This patch adds polling for data
> transfer completion before executing resets.
> 
> Signed-off-by: Luke Wang <ziniu.wang_1 at nxp.com>
> ---
> v2: amend commit message
> ---
>  drivers/mmc/host/sdhci-esdhc-imx.c | 15 +++++++++++++++
>  1 file changed, 15 insertions(+)
> 
> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c
> b/drivers/mmc/host/sdhci-esdhc-imx.c
> index a7a5df673b0f..affde1936510 100644
> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> @@ -1453,6 +1453,21 @@ static void esdhc_set_uhs_signaling(struct
> sdhci_host *host, unsigned timing)
> 
>  static void esdhc_reset(struct sdhci_host *host, u8 mask)  {
> +	u32 present_state;
> +	int ret;
> +
> +	/*
> +	 * For data or full reset, ensure any active data transfer completes
> +	 * before resetting to avoid system hang.
> +	 */
> +	if (mask & (SDHCI_RESET_DATA | SDHCI_RESET_ALL)) {
> +		ret = readl_poll_timeout_atomic(host->ioaddr + ESDHC_PRSSTAT,
> present_state,

I'm okay with the patch, but I find one thing here:

I notice you use _atomic here, I guess you want to cover the case when the reset function is called in hardware irq handler sdhci_irq().
I'm not sure whether it is suitable to add delay in hardware iqr handler, I find there is also udelay in sdhci_reset(), sdhci_reset can also be called in hardware irq handler when there is cmd_crc/data_crc error.
Adrian/Ulf, do you notice this issue before? Any comments?

Regards
Haibo Chen


> +						!(present_state & SDHCI_DATA_INHIBIT), 2,
> 100000);
> +		if (ret == -ETIMEDOUT)
> +			dev_warn(mmc_dev(host->mmc),
> +				 "timeout waiting for data transfer completion\n");
> +	}
> +
>  	sdhci_and_cqhci_reset(host, mask);
> 
>  	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
> --
> 2.34.1


From ardb at kernel.org  Fri Dec  5 00:13:46 2025
From: ardb at kernel.org (Ard Biesheuvel)
Date: Fri, 5 Dec 2025 09:13:46 +0100
Subject: [PATCH] arm64/simd: Avoid pointless clearing of FP/SIMD buffer
In-Reply-To: <20251205064809.GA26371@sol>
References: <20251204162815.522879-2-ardb@kernel.org> <20251205064809.GA26371@sol>
Message-ID: <CAMj1kXE8qn7MSY1A31CrHRSxw+NXqNGLo=FLo4D-COMhxPAMiw@mail.gmail.com>

On Fri, 5 Dec 2025 at 07:50, Eric Biggers <ebiggers at kernel.org> wrote:
>
> On Thu, Dec 04, 2025 at 05:28:15PM +0100, Ard Biesheuvel wrote:
> > The buffer provided to kernel_neon_begin() is only used if the task is
> > scheduled out while the FP/SIMD is in use by the kernel, or when such a
> > section is interrupted by a softirq that also uses the FP/SIMD.
> >
> > IOW, this happens rarely, and even if it happened often, there is still
> > no reason for this buffer to be cleared beforehand, which happens by
> > default when using a compiler that supports -ftrivial-auto-var-init.
> >
> > So mark the buffer as __uninitialized. Given that this is a variable
> > attribute not a type attribute, this requires that the expression is
> > tweaked a bit.
> >
> > Cc: Will Deacon <will at kernel.org>,
> > Cc: Catalin Marinas <catalin.marinas at arm.com>,
> > Cc: Kees Cook <keescook at chromium.org>
> > Cc: Eric Biggers <ebiggers at kernel.org>
> > Cc: Justin Stitt <justinstitt at google.com>
> > Signed-off-by: Ard Biesheuvel <ardb at kernel.org>
> > ---
> >  arch/arm64/include/asm/simd.h | 3 ++-
> >  1 file changed, 2 insertions(+), 1 deletion(-)
> >
> > The issue here is that returning a pointer to an automatic variable as
> > it goes out of scope is slightly dodgy, especially in the context of
> > __attribute__((cleanup())), on which the scoped guard API relies
> > heavily. However, in this case it should be safe, given that this
> > expression is the input to the guarded variable type's constructor.
> >
> > It is definitely not pretty, though, so hopefully here is a better way
> > to attach this.
> >
> > diff --git a/arch/arm64/include/asm/simd.h b/arch/arm64/include/asm/simd.h
> > index 0941f6f58a14..825b7fe94003 100644
> > --- a/arch/arm64/include/asm/simd.h
> > +++ b/arch/arm64/include/asm/simd.h
> > @@ -48,6 +48,7 @@ DEFINE_LOCK_GUARD_1(ksimd,
> >                   kernel_neon_begin(_T->lock),
> >                   kernel_neon_end(_T->lock))
> >
> > -#define scoped_ksimd()       scoped_guard(ksimd, &(struct user_fpsimd_state){})
> > +#define scoped_ksimd()       \
> > +     scoped_guard(ksimd, ({ struct user_fpsimd_state __uninitialized s; &s; }))
>
> Ick.  I should have looked at the generated code more closely.
>
> It's actually worse than you describe, because the zeroing is there even
> without CONFIG_INIT_STACK_ALL_ZERO=y, simply because the
> user_fpsimd_state struct is declared using a compound literal.
>
> I'm afraid that this patch probably isn't a good idea, as it relies on
> undefined behavior.  Before this patch, the user_fpsimd_state is
> declared using a compound literal, which takes on its enclosing scope,
> i.e. the 'for' statement generated by scoped_guard().  After this patch,
> it's in a new inner scope, and the pointer to it escapes from it.
>
> Unfortunately I don't think there's any way to solve this while keeping
> the scoped_ksimd() API as-is.
>

How about

--- a/arch/arm64/include/asm/simd.h
+++ b/arch/arm64/include/asm/simd.h
@@ -48,6 +48,8 @@ DEFINE_LOCK_GUARD_1(ksimd,
                    kernel_neon_begin(_T->lock),
                    kernel_neon_end(_T->lock))

-#define scoped_ksimd() scoped_guard(ksimd, &(struct user_fpsimd_state){})
+#define scoped_ksimd()         __scoped_ksimd(__UNIQUE_ID(fpsimd_state))
+#define __scoped_ksimd(id)     struct user_fpsimd_state __uninitialized id; \
+                               scoped_guard(ksimd, &id)

 #endif


From jiyu.yang at oss.nxp.com  Fri Dec  5 00:17:52 2025
From: jiyu.yang at oss.nxp.com (Rain Yang)
Date: Fri, 5 Dec 2025 16:17:52 +0800
Subject: [PATCH] arm64: dts: imx95: Use GPU_CGC as core clock for GPU
In-Reply-To: <5944d872-01a3-47e9-977b-029f3be4fd83@mailbox.org>
References: <20251129143220.14834-1-marek.vasut@mailbox.org>
 <aS-lEibp3zTsaR6T@oss.nxp.com>
 <c6e0e55a-06da-4665-972e-e9b5b8c08bf7@mailbox.org>
 <aTACuRjC_Zpf8IOU@oss.nxp.com>
 <de36091e-c890-4897-b3e3-2a7575029a5d@mailbox.org>
 <aTD5np-HGaJqhzkD@oss.nxp.com>
 <5944d872-01a3-47e9-977b-029f3be4fd83@mailbox.org>
Message-ID: <aTKVMAMQ6v_BwD6R@oss.nxp.com>

On Thu, Dec 04, 2025 at 04:25:38AM +0100, Marek Vasut wrote:
>On 12/4/25 4:01 AM, Rain Yang wrote:
>
>[...]
>> > > For the Linux working environment,
>> > > CLK_GPU and CLK_GPUAPB are always-on, while CLK_GPU_CGC can be gated off.
>> > > 
>> > > Regarding the IMX95_CLK_GPUAPB handle, my suggestion was based on the absence
>> > > of its frequency in any OPP entry within the frequency table. Removing it
>> > > could simplify the OPP handling logic and reduce unnecessary complexity.
>> > 
>> > If the clock can be disabled by SM, Linux has to make sure they are NOT
>> > disabled, so they must be described in DT, right ?
>> > 
>> > > [1] https://github.com/nxp-imx/linux-imx/commit/695f2bdc57b869ca5189313e4b5fa7eb5a12f622
>> Currently, only CLK_GPU_CGC shall be described in the Device Tree[1], as it can be gated.
>> The other clocks (CLK_GPU and CLK_GPUAPB) are always-on in the Linux environment,
>> so describing any of them in DT is not necessary and would not be proper in this context.
>
>Since this discussion is in fact unrelated to this bugfix, I would propose to
>fork the discussion into a separate patch. Can you please submit a patch for
>the GPUAPB clock ? Note that I believe GPUAPB clock have to be described in
>DT, if only because DT is a hardware description, and to make sure the GPUAPB
>clock are correctly enabled by the driver.

Okay, I?ll submit a patch later.
The commit message should reflect that only CLK_GPU_CGC is enabled.


From krzk at kernel.org  Fri Dec  5 00:21:55 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 5 Dec 2025 09:21:55 +0100
Subject: [PATCH 1/2] dt-bindings: arm: fsl: Add FRDM-IMX91S board
In-Reply-To: <20251205-imx91s-frdm-v1-1-afd6cd01c299@nxp.com>
References: <20251205-imx91s-frdm-v1-0-afd6cd01c299@nxp.com>
 <20251205-imx91s-frdm-v1-1-afd6cd01c299@nxp.com>
Message-ID: <4b29cc46-28a1-45f1-b24e-548513178884@kernel.org>

On 05/12/2025 09:03, Yanan.Yang wrote:
> Add DT compatible string for NXP FRDM-IMX91S board
> 
> The FRDM i.MX 91S development board is an low-cost and compact
> development board featuring the i.MX 91 applications processor.
> 
> Signed-off-by: Yanan.Yang <yanan.yang at nxp.com>

Are you sure your Latin name contains '.' character? Or you just copied
login?

> ---
>  Documentation/devicetree/bindings/arm/fsl.yaml | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
> index 68a2d5fecc43..82f28be401b8 100644
> --- a/Documentation/devicetree/bindings/arm/fsl.yaml
> +++ b/Documentation/devicetree/bindings/arm/fsl.yaml
> @@ -1412,6 +1412,7 @@ properties:
>          items:
>            - enum:
>                - fsl,imx91-11x11-evk       # i.MX91 11x11 EVK Board
> +              - fsl,imx91-11x11-frdm-s    # FRDM-IMX91S Board

Anyway, this was sent, or something almost the same.

Align internally before posting duplicates or at least explain why this
is not a duplicate It is not the job of the community to coordinate how
NXP employees should work. Srsly, it's NXP's job.



Best regards,
Krzysztof


From krzk at kernel.org  Fri Dec  5 00:23:25 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 5 Dec 2025 09:23:25 +0100
Subject: [PATCH 2/2] arm64: dts: freescale: add NXP FRDM-IMX91S board
 support
In-Reply-To: <20251205-imx91s-frdm-v1-2-afd6cd01c299@nxp.com>
References: <20251205-imx91s-frdm-v1-0-afd6cd01c299@nxp.com>
 <20251205-imx91s-frdm-v1-2-afd6cd01c299@nxp.com>
Message-ID: <4ce9756d-fd5a-4678-811d-be19eea1f626@kernel.org>

On 05/12/2025 09:03, Yanan.Yang wrote:
> Add DeviceTree support for the NXP FRDM-IMX91S development board based
> on the i.MX91 SoC. FRDM-IMX91S is a cost-optimized variant of FRDM-IMX91
> and differs in memory, storage, Ethernet, and PMIC configuration:
> 
> - 512MB LPDDR4 (FRDM-IMX91 uses 1GB)
> - 256MB FlexSPI-NAND (FRDM-IMX91 uses 8GB eMMC)
> - Single GbE port (FRDM-IMX91 has dual GbE)
> - PMIC PF9453 (FRDM-IMX91 uses PCA9451A)
> 
> This DT enables:
> - ADC1
> - UART1 and UART5
> - I2C bus and children nodes
> - USB and related nodes
> - uSDHC1 and uSDHC2
> - FlexSPI NAND flash
> - Watchdog3
> - Ethernet (eqos)
> - FlexCAN
> - MQS
> 
> Link: https://www.nxp.com/design/design-center/development-boards-and-designs/FRDM-IMX91S
> (FRDM-IMX91S board page)
> Link: https://www.nxp.com/design/design-center/development-boards-and-designs/FRDM-IMX91
> (FRDM-IMX91 board page)
> 
> Co-developed-by: Lei Xu <lei.xu at nxp.com>
> Signed-off-by: Lei Xu <lei.xu at nxp.com>
> Co-developed-by: Xiaofeng Wei <xiaofeng.wei at nxp.com>
> Signed-off-by: Xiaofeng Wei <xiaofeng.wei at nxp.com>
> Signed-off-by: Yanan.Yang <yanan.yang at nxp.com>
> ---
>  arch/arm64/boot/dts/freescale/Makefile             |   1 +
>  .../boot/dts/freescale/imx91-11x11-frdm-s.dts      | 692 +++++++++++++++++++++
>  2 files changed, 693 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
> index f30d3fd724d0..927bf76a05f3 100644
> --- a/arch/arm64/boot/dts/freescale/Makefile
> +++ b/arch/arm64/boot/dts/freescale/Makefile
> @@ -368,6 +368,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8qxp-tqma8xqps-mb-smarc-2.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx8ulp-9x9-evk.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx8ulp-evk.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx91-11x11-evk.dtb
> +dtb-$(CONFIG_ARCH_MXC) += imx91-11x11-frdm-s.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx91-phyboard-segin.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx91-tqma9131-mba91xxca.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx93-9x9-qsb.dtb
> diff --git a/arch/arm64/boot/dts/freescale/imx91-11x11-frdm-s.dts b/arch/arm64/boot/dts/freescale/imx91-11x11-frdm-s.dts
> new file mode 100644
> index 000000000000..0952a685c3f5
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx91-11x11-frdm-s.dts
> @@ -0,0 +1,692 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright 2025 NXP
> + */
> +
> +/dts-v1/;
> +
> +#include <dt-bindings/usb/pd.h>
> +#include "imx91.dtsi"
> +
> +/ {
> +	compatible = "fsl,imx91-11x11-frdm-s", "fsl,imx91";
> +	model = "NXP FRDM-IMX91S board";
> +
> +	aliases {
> +		ethernet0 = &fec;
> +		ethernet1 = &eqos;
> +		gpio0 = &gpio1;
> +		gpio1 = &gpio2;
> +		gpio2 = &gpio3;
> +		gpio3 = &gpio4;
> +		i2c0 = &lpi2c1;
> +		i2c1 = &lpi2c2;
> +		i2c2 = &lpi2c3;
> +		i2c3 = &lpi2c4;
> +		i2c4 = &lpi2c5;
> +		i2c5 = &lpi2c6;
> +		i2c6 = &lpi2c7;
> +		i2c7 = &lpi2c8;
> +		mmc0 = &usdhc1;
> +		mmc1 = &usdhc2;
> +		mmc2 = &usdhc3;
> +		rtc0 = &bbnsm_rtc;
> +		serial0 = &lpuart1;
> +		serial1 = &lpuart2;
> +		serial2 = &lpuart3;
> +		serial3 = &lpuart4;
> +		serial4 = &lpuart5;
> +		serial5 = &lpuart6;
> +		serial6 = &lpuart7;
> +		serial7 = &lpuart8;
> +	};
> +
> +	chosen {
> +		stdout-path = &lpuart1;
> +	};
> +
> +	gpio-keys {
> +		compatible = "gpio-keys";
> +		pinctrl-0 = <&pinctrl_gpio_key>;
> +		pinctrl-names = "default";
> +
> +		button {
> +			interrupt-parent = <&gpio3>;
> +			interrupts = <26 IRQ_TYPE_EDGE_FALLING>;
> +			gpios = <&gpio3 26 GPIO_PULL_UP>;
> +			label = "User Button";
> +			linux,code = <BTN_1>;
> +		};
> +	};
> +
> +	gpio-leds {
> +		compatible = "gpio-leds";
> +
> +		status {

It does not look like you tested the DTS against bindings. Please run
`make dtbs_check W=1` (see
Documentation/devicetree/bindings/writing-schema.rst or
https://www.linaro.org/blog/tips-and-tricks-for-validating-devicetree-sources-with-the-devicetree-schema/
for instructions).
Maybe you need to update your dtschema and yamllint. Don't rely on
distro packages for dtschema and be sure you are using the latest
released dtschema.


> +			default-state = "on";
> +			gpios = <&pcal6524 7 GPIO_ACTIVE_LOW>;
> +			label = "green:status";
> +		};
> +	};
> +
> +	reg_vref_1v8: regulator-adc-vref {
> +		compatible = "regulator-fixed";
> +		regulator-max-microvolt = <1800000>;
> +		regulator-min-microvolt = <1800000>;
> +		regulator-name = "vref_1v8";
> +	};
> +
> +	reg_can_stby: regulator-can-stby {
> +		compatible = "regulator-fixed";
> +		regulator-max-microvolt = <3300000>;
> +		regulator-min-microvolt = <3300000>;
> +		regulator-name = "can-stby";
> +		gpio = <&gpio1 10 GPIO_ACTIVE_LOW>;
> +	};
> +
> +	reg_usdhc1_vmmc: regulator-usdhc1 {
> +		compatible = "regulator-fixed";
> +		regulator-max-microvolt = <3300000>;
> +		regulator-min-microvolt = <3300000>;
> +		regulator-name = "WLAN_EN";
> +		startup-delay-us = <20000>;
> +		gpio = <&pcal6524 3 GPIO_ACTIVE_HIGH>;
> +		enable-active-high;
> +	};
> +
> +	reg_usdhc2_vmmc: regulator-usdhc2 {
> +		compatible = "regulator-fixed";
> +		off-on-delay-us = <12000>;
> +		pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
> +		pinctrl-names = "default";
> +		regulator-max-microvolt = <3300000>;
> +		regulator-min-microvolt = <3300000>;
> +		regulator-name = "VSD_3V3";
> +		gpio = <&gpio3 7 GPIO_ACTIVE_HIGH>;
> +		enable-active-high;
> +	};
> +
> +	reg_usb_vbus: regulator-vbus {
> +		compatible = "regulator-fixed";
> +		regulator-max-microvolt = <5000000>;
> +		regulator-min-microvolt = <5000000>;
> +		regulator-name = "USB_VBUS";
> +		gpio = <&pcal6524 15 GPIO_ACTIVE_HIGH>;
> +		enable-active-high;
> +	};
> +
> +	reserved-memory {
> +		ranges;
> +		#address-cells = <2>;
> +		#size-cells = <2>;
> +
> +		linux,cma {
> +			compatible = "shared-dma-pool";
> +			alloc-ranges = <0 0x80000000 0 0x20000000>;
> +			reusable;
> +			size = <0 0x2000000>;
> +			linux,cma-default;
> +		};
> +	};
> +
> +	sound-mqs {
> +		compatible = "fsl,imx6sx-sdb-mqs", "fsl,imx-audio-mqs";
> +		audio-codec = <&mqs1>;
> +		audio-cpu = <&sai1>;
> +		model = "mqs-audio";
> +	};
> +
> +	usdhc1_pwrseq: usdhc1_pwrseq {

No, NAK. Don't send us downstream code ever. I am not reviewing the
rest. Please start working with mainline code, not downstream. Take
MAINLINE DTS as your starting point, not downstream.

Best regards,
Krzysztof


From krzk at kernel.org  Fri Dec  5 00:24:40 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 5 Dec 2025 09:24:40 +0100
Subject: [PATCH v2] arm64: dts: mediatek: mt8189: Add pinmux macro header
 file
In-Reply-To: <20251205064357.13591-1-ot_cathy.xu@mediatek.com>
References: <20251205064357.13591-1-ot_cathy.xu@mediatek.com>
Message-ID: <ea71abc9-a661-4a78-8503-bac9d34bf8a4@kernel.org>

On 05/12/2025 07:43, Cathy Xu wrote:
> Add the pinctrl header file on MediaTek mt8189.

Why? There is no user of this. Why do we dead code in unused heders?

Best regards,
Krzysztof


From linux.amoon at gmail.com  Fri Dec  5 00:30:29 2025
From: linux.amoon at gmail.com (Anand Moon)
Date: Fri, 5 Dec 2025 14:00:29 +0530
Subject: [PATCH v7 0/7] Exynos Thermal code improvement
In-Reply-To: <20250813131007.343402-1-linux.amoon@gmail.com>
References: <20250813131007.343402-1-linux.amoon@gmail.com>
Message-ID: <CANAwSgRqFsRvCzrK7NXfqa91xhQLLVU_u2irLBBrRcpiK9gGkA@mail.gmail.com>

Hi All,

On Wed, 13 Aug 2025 at 18:40, Anand Moon <linux.amoon at gmail.com> wrote:
>
> Hi All,
>
> This patch series is a rework of my previous patch series [1],
> where the code changes were not adequately justified.
>
> In this new series, I have improved the commit subject
> and commit message to better explain the changes.
>
> v7: Integrated my RFC patch which improves the IRQ framework
>     for all the SoC link below.
>     [6] https://lore.kernel.org/all/20250616163831.8138-1-linux.amoon at gmail.com/
>
> v6: Add new patch to use devm_clk_get_enabled
>     and Fix few typo in subject as suggested by Daniel.
> v5: Drop the guard mutex patch
> v4: Tried to address Lukasz review comments.
>
> I dont have any Arm64 device the test and verify
> Tested on 32 bit Arch Odroid U3 amd XU4 SoC boards.
> Build with clang with W=1 enable.
>
> Please sare the feedback on this.

Can you review the first 5 patches of this series?
Do you want me to resend

Thanks
-Anand


From krzk at kernel.org  Fri Dec  5 00:39:03 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 5 Dec 2025 09:39:03 +0100
Subject: [PATCH v3 1/2] dt-bindings: thermal: mediatek: Add MT8189 LVTS
 thermal controller bindings
In-Reply-To: <20251202091056.1761229-2-hanchien.lin@mediatek.com>
References: <20251202091056.1761229-1-hanchien.lin@mediatek.com>
 <20251202091056.1761229-2-hanchien.lin@mediatek.com>
Message-ID: <20251205-nostalgic-just-mussel-5cbf89@quoll>

On Tue, Dec 02, 2025 at 05:10:55PM +0800, Hanchien Lin wrote:
> Add support for the MediaTek MT8189 LVTS thermal controller to the device tree bindings.

Please wrap commit message according to Linux coding style / submission
process (neither too early nor over the limit):
https://elixir.bootlin.com/linux/v6.4-rc1/source/Documentation/process/submitting-patches.rst#L597

> This includes new compatible strings and required properties for MT8189.

Drop, redundant. Don't explain the obvious. Can you document new device
wihout "new compatible strings"?

Your commit msg should explain non obvious things, e.g. why this is not
compatible with existing devices.

A nit, subject: drop second/last, redundant "bindings". The
"dt-bindings" prefix is already stating that these are bindings.
See also:
https://elixir.bootlin.com/linux/v6.17-rc3/source/Documentation/devicetree/bindings/submitting-patches.rst#L18


> 
> Signed-off-by: Hanchien Lin <hanchien.lin at mediatek.com>
> ---
>  .../thermal/mediatek,lvts-thermal.yaml        | 27 +++++++++++++++++--
>  .../thermal/mediatek,lvts-thermal.h           | 20 ++++++++++++++
>  2 files changed, 45 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml b/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml
> index 0259cd3ce9c5..0f7fd69f5fdf 100644
> --- a/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml
> +++ b/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml
> @@ -22,6 +22,8 @@ properties:
>        - mediatek,mt8186-lvts
>        - mediatek,mt8188-lvts-ap
>        - mediatek,mt8188-lvts-mcu
> +      - mediatek,mt8189-lvts-ap
> +      - mediatek,mt8189-lvts-mcu
>        - mediatek,mt8192-lvts-ap
>        - mediatek,mt8192-lvts-mcu
>        - mediatek,mt8195-lvts-ap
> @@ -58,6 +60,21 @@ properties:
>  allOf:
>    - $ref: thermal-sensor.yaml#
>  
> +  - if:
> +      properties:
> +        compatible:
> +          contains:
> +            enum:
> +              - mediatek,mt8189-lvts-ap
> +              - mediatek,mt8189-lvts-mcu

Why new if:then? Why cannot it be part of existing block? I don't see
differences.

> +    then:
> +      properties:
> +        nvmem-cells:
> +          minItems: 2
> +
> +        nvmem-cell-names:
> +          minItems: 2
> +
>    - if:
>        properties:
>          compatible:
> @@ -75,6 +92,10 @@ allOf:
>          nvmem-cell-names:
>            maxItems: 1
>  
> +      required:
> +        - clocks
> +        - resets
> +
>    - if:
>        properties:
>          compatible:
> @@ -91,12 +112,14 @@ allOf:
>          nvmem-cell-names:
>            minItems: 2
>  
> +      required:
> +        - clocks
> +        - resets
> +
>  required:
>    - compatible
>    - reg
>    - interrupts
> -  - clocks
> -  - resets


Maybe that's the difference, but commit msg explained nothing. Your
commit is just redundant - tells zero, but all the unexpected things are
totally not explained.

Device cannot work without resets and clocks. If you think otherwise,
prove your point in commit msg (in terms of datasheet, hardware, not
drivers!).

>    - nvmem-cells
>    - nvmem-cell-names

Best regards,
Krzysztof



From krzk at kernel.org  Fri Dec  5 01:01:56 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 5 Dec 2025 10:01:56 +0100
Subject: [PATCH v2 1/3] dt-bindings: arm: fsl: moduline-display: fix
 compatible
In-Reply-To: <20251201-disp_fix-v2-1-9b03026311b6@gocontroll.com>
References: <20251201-disp_fix-v2-0-9b03026311b6@gocontroll.com>
 <20251201-disp_fix-v2-1-9b03026311b6@gocontroll.com>
Message-ID: <20251205-futuristic-hysterical-salamander-dce94c@quoll>

On Mon, Dec 01, 2025 at 12:56:50PM +0100, Maud Spierings wrote:
> The compatibles should include the SoM compatible, this board is based
> on the Ka-Ro TX8P-ML81 SoM, so add it to allow using shared code in the
> bootloader which uses upstream Linux devicetrees as a base.
> 
> Also add the hardware revision to the board compatible to handle
> revision specific quirks in the bootloader/userspace.
> 
> This is a breaking change, but it is early enough that it can be
> corrected without causing any issues.
> 
> Fixes: 24e67d28ef95 ("dt-bindings: arm: fsl: Add GOcontroll Moduline Display")
> Signed-off-by: Maud Spierings <maudspierings at gocontroll.com>
> ---
>  Documentation/devicetree/bindings/arm/fsl.yaml | 9 ++++++++-
>  1 file changed, 8 insertions(+), 1 deletion(-)

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof



From francesco at dolcini.it  Fri Dec  5 01:04:08 2025
From: francesco at dolcini.it (Francesco Dolcini)
Date: Fri, 5 Dec 2025 10:04:08 +0100
Subject: [PATCH 2/2] arm64: dts: freescale: add NXP FRDM-IMX91S board
 support
In-Reply-To: <20251205-imx91s-frdm-v1-2-afd6cd01c299@nxp.com>
References: <20251205-imx91s-frdm-v1-0-afd6cd01c299@nxp.com>
 <20251205-imx91s-frdm-v1-2-afd6cd01c299@nxp.com>
Message-ID: <20251205090408.GA48399@francesco-nb>

On Fri, Dec 05, 2025 at 05:03:59PM +0900, Yanan.Yang wrote:
> Add DeviceTree support for the NXP FRDM-IMX91S development board based
> on the i.MX91 SoC. FRDM-IMX91S is a cost-optimized variant of FRDM-IMX91
> and differs in memory, storage, Ethernet, and PMIC configuration:
> 
> - 512MB LPDDR4 (FRDM-IMX91 uses 1GB)
> - 256MB FlexSPI-NAND (FRDM-IMX91 uses 8GB eMMC)
> - Single GbE port (FRDM-IMX91 has dual GbE)

...

> +
> +	aliases {
> +		ethernet0 = &fec;
> +		ethernet1 = &eqos;

Single ethernet port, and 2 ethernet aliases. Please fix

Francesco



From krzk at kernel.org  Fri Dec  5 01:04:47 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 5 Dec 2025 10:04:47 +0100
Subject: [PATCH 1/3] dt-bindings: mmc: mtk-sd: Add support for MT8189 SoC
In-Reply-To: <20251203-mt8189-add-mmc-support-v1-1-f5ce43212fe9@collabora.com>
References: <20251203-mt8189-add-mmc-support-v1-0-f5ce43212fe9@collabora.com>
 <20251203-mt8189-add-mmc-support-v1-1-f5ce43212fe9@collabora.com>
Message-ID: <20251205-funky-coucal-from-eldorado-7f8bea@quoll>

On Wed, Dec 03, 2025 at 12:45:34PM +0100, Louis-Alexis Eyraud wrote:
> Add a new compatible for MMC IP in MT8189 SoC.
> Even though this is partially compatible with the one found in MT8196
> SoC, the MT8189 SoC register layout has some slight differences and
> additional features.
> 
> Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
> ---
>  Documentation/devicetree/bindings/mmc/mtk-sd.yaml | 3 +++
>  1 file changed, 3 insertions(+)

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof



From patrice.chotard at foss.st.com  Fri Dec  5 01:04:54 2025
From: patrice.chotard at foss.st.com (Patrice Chotard)
Date: Fri, 5 Dec 2025 10:04:54 +0100
Subject: [PATCH 4/8] spi: stm32-ospi: Simplify SMIE interrupt test
In-Reply-To: <20251205-upstream_qspi_ospi_updates-v1-0-7e6c8b9f5141@foss.st.com>
References: <20251205-upstream_qspi_ospi_updates-v1-0-7e6c8b9f5141@foss.st.com>
Message-ID: <20251205-upstream_qspi_ospi_updates-v1-4-7e6c8b9f5141@foss.st.com>

SR_SMF status bit can only be set if CR_SMIE was previously set,
keep status bit check only.

Signed-off-by: Patrice Chotard <patrice.chotard at foss.st.com>
---
 drivers/spi/spi-stm32-ospi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/spi/spi-stm32-ospi.c b/drivers/spi/spi-stm32-ospi.c
index d8d72e2fb4bd..8f7bf6c582c9 100644
--- a/drivers/spi/spi-stm32-ospi.c
+++ b/drivers/spi/spi-stm32-ospi.c
@@ -279,7 +279,7 @@ static irqreturn_t stm32_ospi_irq(int irq, void *dev_id)
 	cr = readl_relaxed(regs_base + OSPI_CR);
 	sr = readl_relaxed(regs_base + OSPI_SR);
 
-	if (cr & CR_SMIE && sr & SR_SMF) {
+	if (sr & SR_SMF) {
 		/* disable irq */
 		cr &= ~CR_SMIE;
 		writel_relaxed(cr, regs_base + OSPI_CR);

-- 
2.43.0



From patrice.chotard at foss.st.com  Fri Dec  5 01:04:51 2025
From: patrice.chotard at foss.st.com (Patrice Chotard)
Date: Fri, 5 Dec 2025 10:04:51 +0100
Subject: [PATCH 1/8] spi: stm32-ospi: Set DMA maxburst dynamically
In-Reply-To: <20251205-upstream_qspi_ospi_updates-v1-0-7e6c8b9f5141@foss.st.com>
References: <20251205-upstream_qspi_ospi_updates-v1-0-7e6c8b9f5141@foss.st.com>
Message-ID: <20251205-upstream_qspi_ospi_updates-v1-1-7e6c8b9f5141@foss.st.com>

Set src_maxburst and dst_maxburst dynamically from DMA
capabilities.

Signed-off-by: Patrice Chotard <patrice.chotard at foss.st.com>
---
 drivers/spi/spi-stm32-ospi.c | 27 ++++++++++++++++++++++-----
 1 file changed, 22 insertions(+), 5 deletions(-)

diff --git a/drivers/spi/spi-stm32-ospi.c b/drivers/spi/spi-stm32-ospi.c
index f36fd36da269..d733e37f0435 100644
--- a/drivers/spi/spi-stm32-ospi.c
+++ b/drivers/spi/spi-stm32-ospi.c
@@ -278,10 +278,19 @@ static irqreturn_t stm32_ospi_irq(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-static void stm32_ospi_dma_setup(struct stm32_ospi *ospi,
-			 struct dma_slave_config *dma_cfg)
+static int stm32_ospi_dma_setup(struct stm32_ospi *ospi,
+				struct dma_slave_config *dma_cfg)
 {
+	struct dma_slave_caps caps;
+	int ret = 0;
+
 	if (dma_cfg && ospi->dma_chrx) {
+		ret = dma_get_slave_caps(ospi->dma_chrx, &caps);
+		if (ret)
+			return ret;
+
+		dma_cfg->src_maxburst = caps.max_burst / dma_cfg->src_addr_width;
+
 		if (dmaengine_slave_config(ospi->dma_chrx, dma_cfg)) {
 			dev_err(ospi->dev, "dma rx config failed\n");
 			dma_release_channel(ospi->dma_chrx);
@@ -290,6 +299,12 @@ static void stm32_ospi_dma_setup(struct stm32_ospi *ospi,
 	}
 
 	if (dma_cfg && ospi->dma_chtx) {
+		ret = dma_get_slave_caps(ospi->dma_chtx, &caps);
+		if (ret)
+			return ret;
+
+		dma_cfg->dst_maxburst = caps.max_burst / dma_cfg->dst_addr_width;
+
 		if (dmaengine_slave_config(ospi->dma_chtx, dma_cfg)) {
 			dev_err(ospi->dev, "dma tx config failed\n");
 			dma_release_channel(ospi->dma_chtx);
@@ -298,6 +313,8 @@ static void stm32_ospi_dma_setup(struct stm32_ospi *ospi,
 	}
 
 	init_completion(&ospi->dma_completion);
+
+	return ret;
 }
 
 static int stm32_ospi_tx_mm(struct stm32_ospi *ospi,
@@ -899,9 +916,9 @@ static int stm32_ospi_probe(struct platform_device *pdev)
 	dma_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
 	dma_cfg.src_addr = ospi->regs_phys_base + OSPI_DR;
 	dma_cfg.dst_addr = ospi->regs_phys_base + OSPI_DR;
-	dma_cfg.src_maxburst = 4;
-	dma_cfg.dst_maxburst = 4;
-	stm32_ospi_dma_setup(ospi, &dma_cfg);
+	ret = stm32_ospi_dma_setup(ospi, &dma_cfg);
+	if (ret)
+		return ret;
 
 	mutex_init(&ospi->lock);
 

-- 
2.43.0



From patrice.chotard at foss.st.com  Fri Dec  5 01:04:53 2025
From: patrice.chotard at foss.st.com (Patrice Chotard)
Date: Fri, 5 Dec 2025 10:04:53 +0100
Subject: [PATCH 3/8] spi: stm32-ospi: Remove CR_TCIE and CR_TEIE irq usage
In-Reply-To: <20251205-upstream_qspi_ospi_updates-v1-0-7e6c8b9f5141@foss.st.com>
References: <20251205-upstream_qspi_ospi_updates-v1-0-7e6c8b9f5141@foss.st.com>
Message-ID: <20251205-upstream_qspi_ospi_updates-v1-3-7e6c8b9f5141@foss.st.com>

Replace CR_TCIE and CR_TEIE irq usage by a read_poll_timeout_atomic() in
stm32_ospi_wait_cmd(). It will reduce the time waiting for TCF or TEF flags
to optimize throughput.

                                           before     after
average time spent in stm32_omi_wait_cmd:  5685 ns    923 ns

Signed-off-by: Patrice Chotard <patrice.chotard at foss.st.com>
---
 drivers/spi/spi-stm32-ospi.c | 31 ++++++-------------------------
 1 file changed, 6 insertions(+), 25 deletions(-)

diff --git a/drivers/spi/spi-stm32-ospi.c b/drivers/spi/spi-stm32-ospi.c
index a6f53f06200e..d8d72e2fb4bd 100644
--- a/drivers/spi/spi-stm32-ospi.c
+++ b/drivers/spi/spi-stm32-ospi.c
@@ -34,8 +34,6 @@
 #define CR_ABORT		BIT(1)
 #define CR_DMAEN		BIT(2)
 #define CR_FTHRES_SHIFT		8
-#define CR_TEIE			BIT(16)
-#define CR_TCIE			BIT(17)
 #define CR_SMIE			BIT(19)
 #define CR_APMS			BIT(22)
 #define CR_CSSEL		BIT(24)
@@ -106,7 +104,7 @@
 #define STM32_ABT_TIMEOUT_US		100000
 #define STM32_COMP_TIMEOUT_MS		5000
 #define STM32_BUSY_TIMEOUT_US		100000
-
+#define STM32_WAIT_CMD_TIMEOUT_US	5000
 
 #define STM32_AUTOSUSPEND_DELAY -1
 
@@ -116,7 +114,6 @@ struct stm32_ospi {
 	struct clk *clk;
 	struct reset_control *rstc;
 
-	struct completion data_completion;
 	struct completion match_completion;
 
 	struct dma_chan *dma_chtx;
@@ -240,22 +237,16 @@ static int stm32_ospi_wait_nobusy(struct stm32_ospi *ospi)
 static int stm32_ospi_wait_cmd(struct stm32_ospi *ospi)
 {
 	void __iomem *regs_base = ospi->regs_base;
-	u32 cr, sr;
+	u32 sr;
 	int err = 0;
 
-	if ((readl_relaxed(regs_base + OSPI_SR) & SR_TCF) ||
-	    ospi->fmode == CR_FMODE_APM)
+	if (ospi->fmode == CR_FMODE_APM)
 		goto out;
 
-	reinit_completion(&ospi->data_completion);
-	cr = readl_relaxed(regs_base + OSPI_CR);
-	writel_relaxed(cr | CR_TCIE | CR_TEIE, regs_base + OSPI_CR);
-
-	if (!wait_for_completion_timeout(&ospi->data_completion,
-				msecs_to_jiffies(STM32_COMP_TIMEOUT_MS)))
-		err = -ETIMEDOUT;
+	err = readl_relaxed_poll_timeout_atomic(ospi->io_base + OSPI_SR, sr,
+						(sr & (SR_TEF | SR_TCF)), 1,
+						STM32_WAIT_CMD_TIMEOUT_US);
 
-	sr = readl_relaxed(regs_base + OSPI_SR);
 	if (sr & SR_TCF)
 		/* avoid false timeout */
 		err = 0;
@@ -293,15 +284,6 @@ static irqreturn_t stm32_ospi_irq(int irq, void *dev_id)
 		cr &= ~CR_SMIE;
 		writel_relaxed(cr, regs_base + OSPI_CR);
 		complete(&ospi->match_completion);
-
-		return IRQ_HANDLED;
-	}
-
-	if (sr & (SR_TEF | SR_TCF)) {
-		/* disable irq */
-		cr &= ~CR_TCIE & ~CR_TEIE;
-		writel_relaxed(cr, regs_base + OSPI_CR);
-		complete(&ospi->data_completion);
 	}
 
 	return IRQ_HANDLED;
@@ -884,7 +866,6 @@ static int stm32_ospi_get_resources(struct platform_device *pdev)
 		dev_info(dev, "No memory-map region found\n");
 	}
 
-	init_completion(&ospi->data_completion);
 	init_completion(&ospi->match_completion);
 
 	return 0;

-- 
2.43.0



From patrice.chotard at foss.st.com  Fri Dec  5 01:04:50 2025
From: patrice.chotard at foss.st.com (Patrice Chotard)
Date: Fri, 5 Dec 2025 10:04:50 +0100
Subject: [PATCH 0/8] spi: stm32: Update for OSPI and QSPI drivers
Message-ID: <20251205-upstream_qspi_ospi_updates-v1-0-7e6c8b9f5141@foss.st.com>

This serie applies the following updates on the spi-stm32-ospi and
spi-stm32-qspi dirvers :

  _ Update FIFO accesses using u16 and u32 when possible instead of u8
    only to optimize throughput.
  _ Replace Transmit Complete and Transmit Error interrupt management by
    usage of read_poll_timeout_atomic() to optimize throughtput.
  _ Simplify Status Match interrupt check.
  _ Set DMA burst configuration dynamically.

Signed-off-by: Patrice Chotard <patrice.chotard at foss.st.com>
---
Patrice Chotard (8):
      spi: stm32-ospi: Set DMA maxburst dynamically
      spi: stm32-ospi: Optimize FIFO accesses using u16 or u32
      spi: stm32-ospi: Remove CR_TCIE and CR_TEIE irq usage
      spi: stm32-ospi: Simplify SMIE interrupt test
      spi: stm32-qspi: Set DMA maxburst dynamically
      spi: stm32-qspi: Optimize FIFO accesses using u16 or u32
      spi: stm32-qspi: Remove CR_TCIE and CR_TEIE irq usage
      spi: stm32-qspi: Simplify SMIE interrupt test

 drivers/spi/spi-stm32-ospi.c | 107 +++++++++++++++++++++++++----------------
 drivers/spi/spi-stm32-qspi.c | 111 +++++++++++++++++++++++++------------------
 2 files changed, 132 insertions(+), 86 deletions(-)
---
base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
change-id: 20251205-upstream_qspi_ospi_updates-4faf7a3b098c

Best regards,
-- 
Patrice Chotard <patrice.chotard at foss.st.com>



From patrice.chotard at foss.st.com  Fri Dec  5 01:04:55 2025
From: patrice.chotard at foss.st.com (Patrice Chotard)
Date: Fri, 5 Dec 2025 10:04:55 +0100
Subject: [PATCH 5/8] spi: stm32-qspi: Set DMA maxburst dynamically
In-Reply-To: <20251205-upstream_qspi_ospi_updates-v1-0-7e6c8b9f5141@foss.st.com>
References: <20251205-upstream_qspi_ospi_updates-v1-0-7e6c8b9f5141@foss.st.com>
Message-ID: <20251205-upstream_qspi_ospi_updates-v1-5-7e6c8b9f5141@foss.st.com>

Set src_maxburst and dst_maxburst dynamically from DMA
capabilities.

Signed-off-by: Patrice Chotard <patrice.chotard at foss.st.com>
---
 drivers/spi/spi-stm32-qspi.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c
index f2d19f1c5ab1..c131441e4dd4 100644
--- a/drivers/spi/spi-stm32-qspi.c
+++ b/drivers/spi/spi-stm32-qspi.c
@@ -689,6 +689,7 @@ static int stm32_qspi_dma_setup(struct stm32_qspi *qspi)
 {
 	struct dma_slave_config dma_cfg;
 	struct device *dev = qspi->dev;
+	struct dma_slave_caps caps;
 	int ret = 0;
 
 	memset(&dma_cfg, 0, sizeof(dma_cfg));
@@ -697,8 +698,6 @@ static int stm32_qspi_dma_setup(struct stm32_qspi *qspi)
 	dma_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
 	dma_cfg.src_addr = qspi->phys_base + QSPI_DR;
 	dma_cfg.dst_addr = qspi->phys_base + QSPI_DR;
-	dma_cfg.src_maxburst = 4;
-	dma_cfg.dst_maxburst = 4;
 
 	qspi->dma_chrx = dma_request_chan(dev, "rx");
 	if (IS_ERR(qspi->dma_chrx)) {
@@ -707,6 +706,11 @@ static int stm32_qspi_dma_setup(struct stm32_qspi *qspi)
 		if (ret == -EPROBE_DEFER)
 			goto out;
 	} else {
+		ret = dma_get_slave_caps(qspi->dma_chrx, &caps);
+		if (ret)
+			return ret;
+
+		dma_cfg.src_maxburst = caps.max_burst / dma_cfg.src_addr_width;
 		if (dmaengine_slave_config(qspi->dma_chrx, &dma_cfg)) {
 			dev_err(dev, "dma rx config failed\n");
 			dma_release_channel(qspi->dma_chrx);
@@ -719,6 +723,11 @@ static int stm32_qspi_dma_setup(struct stm32_qspi *qspi)
 		ret = PTR_ERR(qspi->dma_chtx);
 		qspi->dma_chtx = NULL;
 	} else {
+		ret = dma_get_slave_caps(qspi->dma_chtx, &caps);
+		if (ret)
+			return ret;
+
+		dma_cfg.dst_maxburst = caps.max_burst / dma_cfg.dst_addr_width;
 		if (dmaengine_slave_config(qspi->dma_chtx, &dma_cfg)) {
 			dev_err(dev, "dma tx config failed\n");
 			dma_release_channel(qspi->dma_chtx);

-- 
2.43.0



From patrice.chotard at foss.st.com  Fri Dec  5 01:04:57 2025
From: patrice.chotard at foss.st.com (Patrice Chotard)
Date: Fri, 5 Dec 2025 10:04:57 +0100
Subject: [PATCH 7/8] spi: stm32-qspi: Remove CR_TCIE and CR_TEIE irq usage
In-Reply-To: <20251205-upstream_qspi_ospi_updates-v1-0-7e6c8b9f5141@foss.st.com>
References: <20251205-upstream_qspi_ospi_updates-v1-0-7e6c8b9f5141@foss.st.com>
Message-ID: <20251205-upstream_qspi_ospi_updates-v1-7-7e6c8b9f5141@foss.st.com>

Replace CR_TCIE and CR_TEIE irq usage by a read_poll_timeout_atomic() in
stm32_qspi_wait_cmd(). It will reduce the time waiting for TCF or TEF flags
to optimize throughput.
						before		after
average time spent in stm32_qspi_wait_cmd:	2615 ns		712 ns

Signed-off-by: Patrice Chotard <patrice.chotard at foss.st.com>
---
 drivers/spi/spi-stm32-qspi.c | 45 +++++++++++++-------------------------------
 1 file changed, 13 insertions(+), 32 deletions(-)

diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c
index c7f2b435d5ee..d6f6f9d4e5be 100644
--- a/drivers/spi/spi-stm32-qspi.c
+++ b/drivers/spi/spi-stm32-qspi.c
@@ -31,8 +31,6 @@
 #define CR_DFM			BIT(6)
 #define CR_FSEL			BIT(7)
 #define CR_FTHRES_SHIFT		8
-#define CR_TEIE			BIT(16)
-#define CR_TCIE			BIT(17)
 #define CR_FTIE			BIT(18)
 #define CR_SMIE			BIT(19)
 #define CR_TOIE			BIT(20)
@@ -86,11 +84,12 @@
 #define STM32_QSPI_MAX_MMAP_SZ	SZ_256M
 #define STM32_QSPI_MAX_NORCHIP	2
 
-#define STM32_FIFO_TIMEOUT_US 30000
-#define STM32_BUSY_TIMEOUT_US 100000
-#define STM32_ABT_TIMEOUT_US 100000
-#define STM32_COMP_TIMEOUT_MS 1000
-#define STM32_AUTOSUSPEND_DELAY -1
+#define STM32_FIFO_TIMEOUT_US		30000
+#define STM32_BUSY_TIMEOUT_US		100000
+#define STM32_ABT_TIMEOUT_US		100000
+#define STM32_WAIT_CMD_TIMEOUT_US	5000
+#define STM32_COMP_TIMEOUT_MS		1000
+#define STM32_AUTOSUSPEND_DELAY		-1
 
 struct stm32_qspi_flash {
 	u32 cs;
@@ -107,7 +106,6 @@ struct stm32_qspi {
 	struct clk *clk;
 	u32 clk_rate;
 	struct stm32_qspi_flash flash[STM32_QSPI_MAX_NORCHIP];
-	struct completion data_completion;
 	struct completion match_completion;
 	u32 fmode;
 
@@ -139,15 +137,6 @@ static irqreturn_t stm32_qspi_irq(int irq, void *dev_id)
 		cr &= ~CR_SMIE;
 		writel_relaxed(cr, qspi->io_base + QSPI_CR);
 		complete(&qspi->match_completion);
-
-		return IRQ_HANDLED;
-	}
-
-	if (sr & (SR_TEF | SR_TCF)) {
-		/* disable irq */
-		cr &= ~CR_TCIE & ~CR_TEIE;
-		writel_relaxed(cr, qspi->io_base + QSPI_CR);
-		complete(&qspi->data_completion);
 	}
 
 	return IRQ_HANDLED;
@@ -330,25 +319,18 @@ static int stm32_qspi_wait_nobusy(struct stm32_qspi *qspi)
 
 static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi)
 {
-	u32 cr, sr;
+	u32 sr;
 	int err = 0;
 
-	if ((readl_relaxed(qspi->io_base + QSPI_SR) & SR_TCF) ||
-	    qspi->fmode == CCR_FMODE_APM)
+	if (qspi->fmode == CCR_FMODE_APM)
 		goto out;
 
-	reinit_completion(&qspi->data_completion);
-	cr = readl_relaxed(qspi->io_base + QSPI_CR);
-	writel_relaxed(cr | CR_TCIE | CR_TEIE, qspi->io_base + QSPI_CR);
+	err = readl_relaxed_poll_timeout_atomic(qspi->io_base + QSPI_SR, sr,
+						(sr & (SR_TEF | SR_TCF)), 1,
+						STM32_WAIT_CMD_TIMEOUT_US);
 
-	if (!wait_for_completion_timeout(&qspi->data_completion,
-				msecs_to_jiffies(STM32_COMP_TIMEOUT_MS))) {
-		err = -ETIMEDOUT;
-	} else {
-		sr = readl_relaxed(qspi->io_base + QSPI_SR);
-		if (sr & SR_TEF)
-			err = -EIO;
-	}
+	if (sr & SR_TEF)
+		err = -EIO;
 
 out:
 	/* clear flags */
@@ -835,7 +817,6 @@ static int stm32_qspi_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	init_completion(&qspi->data_completion);
 	init_completion(&qspi->match_completion);
 
 	qspi->clk = devm_clk_get(dev, NULL);

-- 
2.43.0



From patrice.chotard at foss.st.com  Fri Dec  5 01:04:56 2025
From: patrice.chotard at foss.st.com (Patrice Chotard)
Date: Fri, 5 Dec 2025 10:04:56 +0100
Subject: [PATCH 6/8] spi: stm32-qspi: Optimize FIFO accesses using u16 or
 u32
In-Reply-To: <20251205-upstream_qspi_ospi_updates-v1-0-7e6c8b9f5141@foss.st.com>
References: <20251205-upstream_qspi_ospi_updates-v1-0-7e6c8b9f5141@foss.st.com>
Message-ID: <20251205-upstream_qspi_ospi_updates-v1-6-7e6c8b9f5141@foss.st.com>

FIFO accesses uses u8 only for read/write.
In order to optimize throughput, add u16 or u32 read/write
accesses when possible.

Running mtd_speedtest on a 4MB sNOR partition using a
stm32mp257f-ev1 board gives the following results:

           before        after   gain
Read :  5773 KiB/s  22170 KiB/s   384%
Write:   796 KiB/s    890 KiB/s    12%

Signed-off-by: Patrice Chotard <patrice.chotard at foss.st.com>
---
 drivers/spi/spi-stm32-qspi.c | 51 ++++++++++++++++++++++++++++++++++----------
 1 file changed, 40 insertions(+), 11 deletions(-)

diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c
index c131441e4dd4..c7f2b435d5ee 100644
--- a/drivers/spi/spi-stm32-qspi.c
+++ b/drivers/spi/spi-stm32-qspi.c
@@ -153,34 +153,53 @@ static irqreturn_t stm32_qspi_irq(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-static void stm32_qspi_read_fifo(u8 *val, void __iomem *addr)
+static void stm32_qspi_read_fifo(void *val, void __iomem *addr, u8 len)
 {
-	*val = readb_relaxed(addr);
+	switch (len) {
+	case sizeof(u32):
+		*((u32 *)val) = readl_relaxed(addr);
+		break;
+	case sizeof(u16):
+		*((u16 *)val) = readw_relaxed(addr);
+		break;
+	case sizeof(u8):
+		*((u8 *)val) = readb_relaxed(addr);
+	};
 }
 
-static void stm32_qspi_write_fifo(u8 *val, void __iomem *addr)
+static void stm32_qspi_write_fifo(void *val, void __iomem *addr, u8 len)
 {
-	writeb_relaxed(*val, addr);
+	switch (len) {
+	case sizeof(u32):
+		writel_relaxed(*((u32 *)val), addr);
+		break;
+	case sizeof(u16):
+		writew_relaxed(*((u16 *)val), addr);
+		break;
+	case sizeof(u8):
+		writeb_relaxed(*((u8 *)val), addr);
+	};
 }
 
 static int stm32_qspi_tx_poll(struct stm32_qspi *qspi,
 			      const struct spi_mem_op *op)
 {
-	void (*tx_fifo)(u8 *val, void __iomem *addr);
+	void (*fifo)(void *val, void __iomem *addr, u8 len);
 	u32 len = op->data.nbytes, sr;
-	u8 *buf;
+	void *buf;
 	int ret;
+	u8 step;
 
 	if (op->data.dir == SPI_MEM_DATA_IN) {
-		tx_fifo = stm32_qspi_read_fifo;
+		fifo = stm32_qspi_read_fifo;
 		buf = op->data.buf.in;
 
 	} else {
-		tx_fifo = stm32_qspi_write_fifo;
-		buf = (u8 *)op->data.buf.out;
+		fifo = stm32_qspi_write_fifo;
+		buf = (void *)op->data.buf.out;
 	}
 
-	while (len--) {
+	while (len) {
 		ret = readl_relaxed_poll_timeout_atomic(qspi->io_base + QSPI_SR,
 							sr, (sr & SR_FTF), 1,
 							STM32_FIFO_TIMEOUT_US);
@@ -189,7 +208,17 @@ static int stm32_qspi_tx_poll(struct stm32_qspi *qspi,
 				len, sr);
 			return ret;
 		}
-		tx_fifo(buf++, qspi->io_base + QSPI_DR);
+
+		if (len >= sizeof(u32))
+			step = sizeof(u32);
+		else if (len >= sizeof(u16))
+			step = sizeof(u16);
+		else
+			step = sizeof(u8);
+
+		fifo(buf, qspi->io_base + QSPI_DR, step);
+		len -= step;
+		buf += step;
 	}
 
 	return 0;

-- 
2.43.0



From patrice.chotard at foss.st.com  Fri Dec  5 01:04:58 2025
From: patrice.chotard at foss.st.com (Patrice Chotard)
Date: Fri, 5 Dec 2025 10:04:58 +0100
Subject: [PATCH 8/8] spi: stm32-qspi: Simplify SMIE interrupt test
In-Reply-To: <20251205-upstream_qspi_ospi_updates-v1-0-7e6c8b9f5141@foss.st.com>
References: <20251205-upstream_qspi_ospi_updates-v1-0-7e6c8b9f5141@foss.st.com>
Message-ID: <20251205-upstream_qspi_ospi_updates-v1-8-7e6c8b9f5141@foss.st.com>

SR_SMF status bit can only be set if CR_SMIE was previously set,
keep status bit check only.

Signed-off-by: Patrice Chotard <patrice.chotard at foss.st.com>
---
 drivers/spi/spi-stm32-qspi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c
index d6f6f9d4e5be..2a0ee96786fa 100644
--- a/drivers/spi/spi-stm32-qspi.c
+++ b/drivers/spi/spi-stm32-qspi.c
@@ -132,7 +132,7 @@ static irqreturn_t stm32_qspi_irq(int irq, void *dev_id)
 	cr = readl_relaxed(qspi->io_base + QSPI_CR);
 	sr = readl_relaxed(qspi->io_base + QSPI_SR);
 
-	if (cr & CR_SMIE && sr & SR_SMF) {
+	if (sr & SR_SMF) {
 		/* disable irq */
 		cr &= ~CR_SMIE;
 		writel_relaxed(cr, qspi->io_base + QSPI_CR);

-- 
2.43.0



From patrice.chotard at foss.st.com  Fri Dec  5 01:04:52 2025
From: patrice.chotard at foss.st.com (Patrice Chotard)
Date: Fri, 5 Dec 2025 10:04:52 +0100
Subject: [PATCH 2/8] spi: stm32-ospi: Optimize FIFO accesses using u16 or
 u32
In-Reply-To: <20251205-upstream_qspi_ospi_updates-v1-0-7e6c8b9f5141@foss.st.com>
References: <20251205-upstream_qspi_ospi_updates-v1-0-7e6c8b9f5141@foss.st.com>
Message-ID: <20251205-upstream_qspi_ospi_updates-v1-2-7e6c8b9f5141@foss.st.com>

FIFO accesses uses u8 only for read/write.
In order to optimize throughput, add u16 or u32 read/write
accesses when possible.

Running mtd_speedtest on a 4MB sNOR partition using a
stm32mp257f-ev1 board gives the following results:

           before        after   gain
Read :  5693 KiB/s  21139 KiB/s   371%
Write:   765 KiB/s    910 KiB/s    19%

Signed-off-by: Patrice Chotard <patrice.chotard at foss.st.com>
---
 drivers/spi/spi-stm32-ospi.c | 47 +++++++++++++++++++++++++++++++++++---------
 1 file changed, 38 insertions(+), 9 deletions(-)

diff --git a/drivers/spi/spi-stm32-ospi.c b/drivers/spi/spi-stm32-ospi.c
index d733e37f0435..a6f53f06200e 100644
--- a/drivers/spi/spi-stm32-ospi.c
+++ b/drivers/spi/spi-stm32-ospi.c
@@ -142,14 +142,32 @@ struct stm32_ospi {
 	struct mutex lock;
 };
 
-static void stm32_ospi_read_fifo(u8 *val, void __iomem *addr)
+static void stm32_ospi_read_fifo(void *val, void __iomem *addr, u8 len)
 {
-	*val = readb_relaxed(addr);
+	switch (len) {
+	case sizeof(u32):
+		*((u32 *)val) = readl_relaxed(addr);
+		break;
+	case sizeof(u16):
+		*((u16 *)val) = readw_relaxed(addr);
+		break;
+	case sizeof(u8):
+		*((u8 *)val) = readb_relaxed(addr);
+	};
 }
 
-static void stm32_ospi_write_fifo(u8 *val, void __iomem *addr)
+static void stm32_ospi_write_fifo(void *val, void __iomem *addr, u8 len)
 {
-	writeb_relaxed(*val, addr);
+	switch (len) {
+	case sizeof(u32):
+		writel_relaxed(*((u32 *)val), addr);
+		break;
+	case sizeof(u16):
+		writew_relaxed(*((u16 *)val), addr);
+		break;
+	case sizeof(u8):
+		writeb_relaxed(*((u8 *)val), addr);
+	};
 }
 
 static int stm32_ospi_abort(struct stm32_ospi *ospi)
@@ -172,19 +190,20 @@ static int stm32_ospi_abort(struct stm32_ospi *ospi)
 	return timeout;
 }
 
-static int stm32_ospi_poll(struct stm32_ospi *ospi, u8 *buf, u32 len, bool read)
+static int stm32_ospi_poll(struct stm32_ospi *ospi, void *buf, u32 len, bool read)
 {
 	void __iomem *regs_base = ospi->regs_base;
-	void (*fifo)(u8 *val, void __iomem *addr);
+	void (*fifo)(void *val, void __iomem *addr, u8 len);
 	u32 sr;
 	int ret;
+	u8 step;
 
 	if (read)
 		fifo = stm32_ospi_read_fifo;
 	else
 		fifo = stm32_ospi_write_fifo;
 
-	while (len--) {
+	while (len) {
 		ret = readl_relaxed_poll_timeout_atomic(regs_base + OSPI_SR,
 							sr, sr & SR_FTF, 1,
 							STM32_FIFO_TIMEOUT_US);
@@ -193,7 +212,17 @@ static int stm32_ospi_poll(struct stm32_ospi *ospi, u8 *buf, u32 len, bool read)
 				len, sr);
 			return ret;
 		}
-		fifo(buf++, regs_base + OSPI_DR);
+
+		if (len >= sizeof(u32))
+			step = sizeof(u32);
+		else if (len >= sizeof(u16))
+			step = sizeof(u16);
+		else
+			step = sizeof(u8);
+
+		fifo(buf, regs_base + OSPI_DR, step);
+		len -= step;
+		buf += step;
 	}
 
 	return 0;
@@ -408,7 +437,7 @@ static int stm32_ospi_xfer(struct stm32_ospi *ospi, const struct spi_mem_op *op)
 	if (op->data.dir == SPI_MEM_DATA_IN)
 		buf = op->data.buf.in;
 	else
-		buf = (u8 *)op->data.buf.out;
+		buf = (void *)op->data.buf.out;
 
 	return stm32_ospi_poll(ospi, buf, op->data.nbytes,
 			       op->data.dir == SPI_MEM_DATA_IN);

-- 
2.43.0



From angelogioacchino.delregno at collabora.com  Fri Dec  5 01:05:45 2025
From: angelogioacchino.delregno at collabora.com (AngeloGioacchino Del Regno)
Date: Fri, 5 Dec 2025 10:05:45 +0100
Subject: [PATCH v1 1/2] arm64: dts: mediatek: mt7986: add dtbs with
 applied overlays for bpi-r3
In-Reply-To: <fc5c9829-96fa-4028-a642-0792699e92a5@kernel.org>
References: <20251119175124.48947-1-linux@fw-web.de>
 <20251119175124.48947-2-linux@fw-web.de>
 <fc5c9829-96fa-4028-a642-0792699e92a5@kernel.org>
Message-ID: <ddad2f21-4853-41c9-acfb-1613f5000f0c@collabora.com>

Il 05/12/25 09:10, Krzysztof Kozlowski ha scritto:
> On 19/11/2025 18:51, Frank Wunderlich wrote:
>> From: Frank Wunderlich <frank-w at public-files.de>
>>
>> Build devicetree binaries for testing overlays and providing users
>> full dtb without using overlays.
>>
>> Suggested-by: Rob Herring <robh+dt at kernel.org>
>> Signed-off-by: Frank Wunderlich <frank-w at public-files.de>
>> ---
>> resend of
>> https://patchwork.kernel.org/project/linux-mediatek/patch/20240608080530.9436-2-linux at fw-web.de/
>> due to discussions here:
>> https://patchwork.kernel.org/project/linux-mediatek/patch/20251117211306.725678-1-robh at kernel.org/
>>
>> changes:
>> - updated sd-nand with sata-overlay
>> ---
>>   arch/arm64/boot/dts/mediatek/Makefile | 21 +++++++++++++++++++++
>>   1 file changed, 21 insertions(+)
> 
> 
> This looks like still not being applied and now it is a warning in
> Linus' tree.
> 
> Can this be applied and sent as fixes?
> 
> Best regards,
> Krzysztof


Acked-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>

Matthias, can you please take care of sending this?

Cheers,
Angelo


From guoniu.zhou at oss.nxp.com  Fri Dec  5 01:07:42 2025
From: guoniu.zhou at oss.nxp.com (Guoniu Zhou)
Date: Fri, 05 Dec 2025 17:07:42 +0800
Subject: [PATCH v10 0/5] Add MIPI CSI-2 support for i.MX8ULP
Message-ID: <20251205-csi2_imx8ulp-v10-0-190cdadb20a3@nxp.com>

The serial adds MIPI CSI-2 support for i.MX8ULP.

Signed-off-by: Guoniu Zhou <guoniu.zhou at nxp.com>
---
Changes in v10:
- Make state->num_clks unsigned as suggested in bellow instead of making i signed.
  https://lore.kernel.org/linux-media/20251121024714.GD11519 at pendragon.ideasonboard.com/
  media: imx8mq-mipi-csi2: Use devm_clk_bulk_get_all() to fetch clocks
- Rebased on latest media/next.
- Link to v9: https://lore.kernel.org/r/20251121-csi2_imx8ulp-v9-0-05b41b897e50 at nxp.com

Changes in v9:
- Make state->num_clks signed int.
- Link to v8: https://lore.kernel.org/r/20251113-csi2_imx8ulp-v8-0-2ebe378f7111 at nxp.com

Changes in v8:
- Rebased on latest media/next.
- Sort the conditional blocks by alphabetical order of the compatible strings
- Get esc_clk when probe and cache it in csi_state structure to avoid looking
  it up multiple times at runtime.
- Make state->num_clks unsigned.
- Return error when failed to get esc_clk.
- Link to v7: https://lore.kernel.org/r/20251023-csi2_imx8ulp-v7-0-5ecb081ce79b at nxp.com

Changes in v7:
- No functional changes, only move patch 2 after patch 4 to avoid dependency issues.
- Rebased on latest media/next
- Link to v6: https://lore.kernel.org/r/20250917-csi2_imx8ulp-v6-0-23a355982eff at nxp.com

Changes in v6:
- s/existed/existing/ in patch 1 commit log.
- Delete the compatible between 8ulp and 8qxp since 8ulp need one more clock.
- Update compatible string in dts for csi node.
- Add one new patch to handle 8ulp in driver.
    media: imx8mq-mipi-csi2: Add support for i.MX8ULP
- Link to v5: https://lore.kernel.org/r/20250901-csi2_imx8ulp-v5-0-67964d1471f3 at nxp.com

Changes in v5:
- Delete else: block and move clock constrains to each case.
- List exact cases, but put imx8qxp/qm in one if:then: block to avoid
  repetitive code since they are same.
- Link to v4: https://lore.kernel.org/all/20250828-csi2_imx8ulp-v4-0-a2f97b15bb98 at nxp.com

Changes in v4:
- Change csr clock name to pclk which is more readability.
- Add restriction to i.MX8ULP and the other variants remain the same as previous versions.
- Update commit log in patch 1 to describe why add new compatible string for i.MX8ULP.
- Link to v3: https://lore.kernel.org/all/20250825-csi2_imx8ulp-v3-0-35885aba62bc at nxp.com

Changes in v3:
- Correct the order of "fsl,imx8qm-mipi-csi2","fsl,imx8qm-mipi-csi2".
- Correct the order of minItems and maxItems.
- Restict all variants.
- Change pclk clock name to csr to match IP port name.
- Align description about csr clock with IP datasheet.
- Add reasons for adding a fourth clock(csr) in patch 1 commit log.
- Link to v2: https://lore.kernel.org/all/20250822-csi2_imx8ulp-v2-0-26a444394965 at nxp.com

Changes in v2:
- Add more description about pclk clock.
- Change minItems/maxItems to 2 for resets property.
- Better to handle "fsl,imx8ulp-mipi-csi2" variant.
- Move comment to the top of reset_control_deassert().
- Move dts patch as the last one.
- Add "fsl,imx8qxp-mipi-csi2" to compatible string list of csi node.
- Remove patch 5 in v1.
- Link to v1: https://lore.kernel.org/all/20250812081923.1019345-1-guoniu.zhou at oss.nxp.com

---
Guoniu Zhou (5):
      media: dt-bindings: nxp,imx8mq-mipi-csi2: Add i.MX8ULP compatible string
      media: imx8mq-mipi-csi2: Use devm_clk_bulk_get_all() to fetch clocks
      media: imx8mq-mipi-csi2: Explicitly release reset
      media: imx8mq-mipi-csi2: Add support for i.MX8ULP
      arm64: dts: imx8ulp: Add CSI and ISI Nodes

 .../bindings/media/nxp,imx8mq-mipi-csi2.yaml       | 49 ++++++++++++++--
 arch/arm64/boot/dts/freescale/imx8ulp.dtsi         | 67 ++++++++++++++++++++++
 drivers/media/platform/nxp/imx8mq-mipi-csi2.c      | 64 ++++++++-------------
 3 files changed, 133 insertions(+), 47 deletions(-)
---
base-commit: 1f2353f5a1af995efbf7bea44341aa0d03460b28
change-id: 20250819-csi2_imx8ulp-9db386dd6bdf

Best regards,
-- 
Guoniu Zhou <guoniu.zhou at nxp.com>



From guoniu.zhou at oss.nxp.com  Fri Dec  5 01:07:43 2025
From: guoniu.zhou at oss.nxp.com (Guoniu Zhou)
Date: Fri, 05 Dec 2025 17:07:43 +0800
Subject: [PATCH v10 1/5] media: dt-bindings: nxp,imx8mq-mipi-csi2: Add
 i.MX8ULP compatible string
In-Reply-To: <20251205-csi2_imx8ulp-v10-0-190cdadb20a3@nxp.com>
References: <20251205-csi2_imx8ulp-v10-0-190cdadb20a3@nxp.com>
Message-ID: <20251205-csi2_imx8ulp-v10-1-190cdadb20a3@nxp.com>

From: Guoniu Zhou <guoniu.zhou at nxp.com>

The CSI-2 receiver in the i.MX8ULP is almost identical to the version
present in the i.MX8QXP/QM, but i.MX8ULP CSI-2 controller needs pclk
clock as the input clock for its APB interface of Control and Status
register(CSR). So add compatible string fsl,imx8ulp-mipi-csi2 and
increase maxItems of Clocks (clock-names) to 4 from 3.  And keep the
same restriction for existing compatible.

Reviewed-by: Frank Li <Frank.Li at nxp.com>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
Signed-off-by: Guoniu Zhou <guoniu.zhou at nxp.com>
---
 .../bindings/media/nxp,imx8mq-mipi-csi2.yaml       | 49 +++++++++++++++++++---
 1 file changed, 43 insertions(+), 6 deletions(-)

diff --git a/Documentation/devicetree/bindings/media/nxp,imx8mq-mipi-csi2.yaml b/Documentation/devicetree/bindings/media/nxp,imx8mq-mipi-csi2.yaml
index 3389bab266a9adbda313c8ad795b998641df12f3..4fcfc4fd35651e0cd6e80b97cc0b12301b65b684 100644
--- a/Documentation/devicetree/bindings/media/nxp,imx8mq-mipi-csi2.yaml
+++ b/Documentation/devicetree/bindings/media/nxp,imx8mq-mipi-csi2.yaml
@@ -20,6 +20,7 @@ properties:
       - enum:
           - fsl,imx8mq-mipi-csi2
           - fsl,imx8qxp-mipi-csi2
+          - fsl,imx8ulp-mipi-csi2
       - items:
           - const: fsl,imx8qm-mipi-csi2
           - const: fsl,imx8qxp-mipi-csi2
@@ -39,12 +40,16 @@ properties:
                      clock that the RX DPHY receives.
       - description: ui is the pixel clock (phy_ref up to 333Mhz).
                      See the reference manual for details.
+      - description: pclk is clock for csr APB interface.
+    minItems: 3
 
   clock-names:
     items:
       - const: core
       - const: esc
       - const: ui
+      - const: pclk
+    minItems: 3
 
   power-domains:
     maxItems: 1
@@ -130,21 +135,53 @@ allOf:
         compatible:
           contains:
             enum:
-              - fsl,imx8qxp-mipi-csi2
+              - fsl,imx8mq-mipi-csi2
+    then:
+      properties:
+        reg:
+          maxItems: 1
+        resets:
+          minItems: 3
+        clocks:
+          maxItems: 3
+        clock-names:
+          maxItems: 3
+      required:
+        - fsl,mipi-phy-gpr
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: fsl,imx8qxp-mipi-csi2
     then:
       properties:
         reg:
           minItems: 2
         resets:
           maxItems: 1
-    else:
+        clocks:
+          maxItems: 3
+        clock-names:
+          maxItems: 3
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - fsl,imx8ulp-mipi-csi2
+    then:
       properties:
         reg:
-          maxItems: 1
+          minItems: 2
         resets:
-          minItems: 3
-      required:
-        - fsl,mipi-phy-gpr
+          minItems: 2
+          maxItems: 2
+        clocks:
+          minItems: 4
+        clock-names:
+          minItems: 4
 
 additionalProperties: false
 

-- 
2.34.1



From guoniu.zhou at oss.nxp.com  Fri Dec  5 01:07:44 2025
From: guoniu.zhou at oss.nxp.com (Guoniu Zhou)
Date: Fri, 05 Dec 2025 17:07:44 +0800
Subject: [PATCH v10 2/5] media: imx8mq-mipi-csi2: Use
 devm_clk_bulk_get_all() to fetch clocks
In-Reply-To: <20251205-csi2_imx8ulp-v10-0-190cdadb20a3@nxp.com>
References: <20251205-csi2_imx8ulp-v10-0-190cdadb20a3@nxp.com>
Message-ID: <20251205-csi2_imx8ulp-v10-2-190cdadb20a3@nxp.com>

From: Guoniu Zhou <guoniu.zhou at nxp.com>

Use devm_clk_bulk_get_all() helper to simplify clock handle code.

No functional changes intended.

Reviewed-by: Frank Li <Frank.Li at nxp.com>
Signed-off-by: Guoniu Zhou <guoniu.zhou at nxp.com>
---
 drivers/media/platform/nxp/imx8mq-mipi-csi2.c | 55 ++++++++++-----------------
 1 file changed, 20 insertions(+), 35 deletions(-)

diff --git a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
index 371b4e81328c107269f89da23818ab0abd0179da..0e3a41cd35edfefc51b5631e2c36fd76e3e14d83 100644
--- a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
+++ b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
@@ -71,21 +71,6 @@ enum {
 	ST_SUSPENDED	= 4,
 };
 
-enum imx8mq_mipi_csi_clk {
-	CSI2_CLK_CORE,
-	CSI2_CLK_ESC,
-	CSI2_CLK_UI,
-	CSI2_NUM_CLKS,
-};
-
-static const char * const imx8mq_mipi_csi_clk_id[CSI2_NUM_CLKS] = {
-	[CSI2_CLK_CORE] = "core",
-	[CSI2_CLK_ESC] = "esc",
-	[CSI2_CLK_UI] = "ui",
-};
-
-#define CSI2_NUM_CLKS	ARRAY_SIZE(imx8mq_mipi_csi_clk_id)
-
 struct imx8mq_plat_data {
 	int (*enable)(struct csi_state *state, u32 hs_settle);
 	void (*disable)(struct csi_state *state);
@@ -111,7 +96,9 @@ struct csi_state {
 	struct device *dev;
 	const struct imx8mq_plat_data *pdata;
 	void __iomem *regs;
-	struct clk_bulk_data clks[CSI2_NUM_CLKS];
+	struct clk_bulk_data *clks;
+	struct clk *esc_clk;
+	u32 num_clks;
 	struct reset_control *rst;
 	struct regulator *mipi_phy_regulator;
 
@@ -384,24 +371,16 @@ static void imx8mq_mipi_csi_set_params(struct csi_state *state)
 			      CSI2RX_SEND_LEVEL);
 }
 
-static int imx8mq_mipi_csi_clk_enable(struct csi_state *state)
-{
-	return clk_bulk_prepare_enable(CSI2_NUM_CLKS, state->clks);
-}
-
-static void imx8mq_mipi_csi_clk_disable(struct csi_state *state)
-{
-	clk_bulk_disable_unprepare(CSI2_NUM_CLKS, state->clks);
-}
-
-static int imx8mq_mipi_csi_clk_get(struct csi_state *state)
+static struct clk *find_esc_clk(struct csi_state *state)
 {
 	unsigned int i;
 
-	for (i = 0; i < CSI2_NUM_CLKS; i++)
-		state->clks[i].id = imx8mq_mipi_csi_clk_id[i];
+	for (i = 0; i < state->num_clks; i++) {
+		if (!strcmp(state->clks[i].id, "esc"))
+			return state->clks[i].clk;
+	}
 
-	return devm_clk_bulk_get(state->dev, CSI2_NUM_CLKS, state->clks);
+	return ERR_PTR(-ENODEV);
 }
 
 static int imx8mq_mipi_csi_calc_hs_settle(struct csi_state *state,
@@ -456,7 +435,7 @@ static int imx8mq_mipi_csi_calc_hs_settle(struct csi_state *state,
 	 * documentation recommends picking a value away from the boundaries.
 	 * Let's pick the average.
 	 */
-	esc_clk_rate = clk_get_rate(state->clks[CSI2_CLK_ESC].clk);
+	esc_clk_rate = clk_get_rate(state->esc_clk);
 	if (!esc_clk_rate) {
 		dev_err(state->dev, "Could not get esc clock rate.\n");
 		return -EINVAL;
@@ -783,7 +762,7 @@ static void imx8mq_mipi_csi_pm_suspend(struct device *dev)
 
 	if (state->state & ST_POWERED) {
 		imx8mq_mipi_csi_stop_stream(state);
-		imx8mq_mipi_csi_clk_disable(state);
+		clk_bulk_disable_unprepare(state->num_clks, state->clks);
 		state->state &= ~ST_POWERED;
 	}
 
@@ -801,7 +780,7 @@ static int imx8mq_mipi_csi_pm_resume(struct device *dev)
 
 	if (!(state->state & ST_POWERED)) {
 		state->state |= ST_POWERED;
-		ret = imx8mq_mipi_csi_clk_enable(state);
+		ret = clk_bulk_prepare_enable(state->num_clks, state->clks);
 	}
 	if (state->state & ST_STREAMING) {
 		sd_state = v4l2_subdev_lock_and_get_active_state(sd);
@@ -1027,9 +1006,15 @@ static int imx8mq_mipi_csi_probe(struct platform_device *pdev)
 	if (IS_ERR(state->regs))
 		return PTR_ERR(state->regs);
 
-	ret = imx8mq_mipi_csi_clk_get(state);
+	ret = devm_clk_bulk_get_all(dev, &state->clks);
 	if (ret < 0)
-		return ret;
+		return dev_err_probe(dev, ret, "Failed to get clocks\n");
+
+	state->num_clks = ret;
+
+	state->esc_clk = find_esc_clk(state);
+	if (IS_ERR(state->esc_clk))
+		return dev_err_probe(dev, PTR_ERR(state->esc_clk), "Couldn't find esc clock\n");
 
 	platform_set_drvdata(pdev, &state->sd);
 

-- 
2.34.1



From guoniu.zhou at oss.nxp.com  Fri Dec  5 01:07:45 2025
From: guoniu.zhou at oss.nxp.com (Guoniu Zhou)
Date: Fri, 05 Dec 2025 17:07:45 +0800
Subject: [PATCH v10 3/5] media: imx8mq-mipi-csi2: Explicitly release reset
In-Reply-To: <20251205-csi2_imx8ulp-v10-0-190cdadb20a3@nxp.com>
References: <20251205-csi2_imx8ulp-v10-0-190cdadb20a3@nxp.com>
Message-ID: <20251205-csi2_imx8ulp-v10-3-190cdadb20a3@nxp.com>

From: Guoniu Zhou <guoniu.zhou at nxp.com>

Call reset_control_deassert() to explicitly release reset to make sure
reset bits are cleared since platform like i.MX8ULP can't clear reset
bits automatically.

Reviewed-by: Frank Li <Frank.Li at nxp.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
Signed-off-by: Guoniu Zhou <guoniu.zhou at nxp.com>
---
 drivers/media/platform/nxp/imx8mq-mipi-csi2.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
index 0e3a41cd35edfefc51b5631e2c36fd76e3e14d83..0ede273f7ff82f288404316c9fd7f1e751e169c5 100644
--- a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
+++ b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
@@ -338,18 +338,14 @@ static int imx8mq_mipi_csi_sw_reset(struct csi_state *state)
 {
 	int ret;
 
-	/*
-	 * these are most likely self-clearing reset bits. to make it
-	 * more clear, the reset-imx7 driver should implement the
-	 * .reset() operation.
-	 */
 	ret = reset_control_assert(state->rst);
 	if (ret < 0) {
 		dev_err(state->dev, "Failed to assert resets: %d\n", ret);
 		return ret;
 	}
 
-	return 0;
+	/* Explicitly release reset to make sure reset bits are cleared. */
+	return reset_control_deassert(state->rst);
 }
 
 static void imx8mq_mipi_csi_set_params(struct csi_state *state)

-- 
2.34.1



From guoniu.zhou at oss.nxp.com  Fri Dec  5 01:07:46 2025
From: guoniu.zhou at oss.nxp.com (Guoniu Zhou)
Date: Fri, 05 Dec 2025 17:07:46 +0800
Subject: [PATCH v10 4/5] media: imx8mq-mipi-csi2: Add support for i.MX8ULP
In-Reply-To: <20251205-csi2_imx8ulp-v10-0-190cdadb20a3@nxp.com>
References: <20251205-csi2_imx8ulp-v10-0-190cdadb20a3@nxp.com>
Message-ID: <20251205-csi2_imx8ulp-v10-4-190cdadb20a3@nxp.com>

From: Guoniu Zhou <guoniu.zhou at nxp.com>

The CSI-2 receiver in i.MX8ULP is almost same as i.MX8QXP/QM except
clocks and resets, so add compatible string for i.MX8ULP to handle
the difference and reuse platform data of i.MX8QXP/QM.

Reviewed-by: Frank Li <Frank.Li at nxp.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
Signed-off-by: Guoniu Zhou <guoniu.zhou at nxp.com>
---
 drivers/media/platform/nxp/imx8mq-mipi-csi2.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
index 0ede273f7ff82f288404316c9fd7f1e751e169c5..1b80e872cf38293c03d216cbee869eaa02e55458 100644
--- a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
+++ b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
@@ -1076,6 +1076,7 @@ static void imx8mq_mipi_csi_remove(struct platform_device *pdev)
 static const struct of_device_id imx8mq_mipi_csi_of_match[] = {
 	{ .compatible = "fsl,imx8mq-mipi-csi2", .data = &imx8mq_data },
 	{ .compatible = "fsl,imx8qxp-mipi-csi2", .data = &imx8qxp_data },
+	{ .compatible = "fsl,imx8ulp-mipi-csi2", .data = &imx8qxp_data },
 	{ /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, imx8mq_mipi_csi_of_match);

-- 
2.34.1



From guoniu.zhou at oss.nxp.com  Fri Dec  5 01:07:47 2025
From: guoniu.zhou at oss.nxp.com (Guoniu Zhou)
Date: Fri, 05 Dec 2025 17:07:47 +0800
Subject: [PATCH v10 5/5] arm64: dts: imx8ulp: Add CSI and ISI Nodes
In-Reply-To: <20251205-csi2_imx8ulp-v10-0-190cdadb20a3@nxp.com>
References: <20251205-csi2_imx8ulp-v10-0-190cdadb20a3@nxp.com>
Message-ID: <20251205-csi2_imx8ulp-v10-5-190cdadb20a3@nxp.com>

From: Guoniu Zhou <guoniu.zhou at nxp.com>

The CSI-2 in the i.MX8ULP is almost identical to the version present
in the i.MX8QXP/QM and is routed to the ISI. Add both the ISI and CSI
nodes and mark them as disabled by default since capture is dependent
on an attached camera.

Reviewed-by: Frank Li <Frank.Li at nxp.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
Signed-off-by: Guoniu Zhou <guoniu.zhou at nxp.com>
---
 arch/arm64/boot/dts/freescale/imx8ulp.dtsi | 67 ++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8ulp.dtsi b/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
index 13b01f3aa2a4950c37e72e04f6bfb5995dc19178..99271d55dfb60ed2cbfe664d928be179eb257674 100644
--- a/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
@@ -7,6 +7,7 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/power/imx8ulp-power.h>
+#include <dt-bindings/reset/imx8ulp-pcc-reset.h>
 #include <dt-bindings/thermal/thermal.h>
 
 #include "imx8ulp-pinfunc.h"
@@ -842,6 +843,72 @@ spdif: spdif at 2dab0000 {
 				dma-names = "rx", "tx";
 				status = "disabled";
 			};
+
+			isi: isi at 2dac0000 {
+				compatible = "fsl,imx8ulp-isi";
+				reg = <0x2dac0000 0x10000>;
+				interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&pcc5 IMX8ULP_CLK_ISI>,
+					 <&cgc2 IMX8ULP_CLK_LPAV_AXI_DIV>;
+				clock-names = "axi", "apb";
+				power-domains = <&scmi_devpd IMX8ULP_PD_ISI>;
+				status = "disabled";
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port at 0 {
+						reg = <0>;
+						isi_in: endpoint {
+							remote-endpoint = <&mipi_csi_out>;
+						};
+					};
+				};
+			};
+
+			mipi_csi: csi at 2daf0000 {
+				compatible = "fsl,imx8ulp-mipi-csi2";
+				reg = <0x2daf0000 0x10000>,
+				      <0x2dad0000 0x10000>;
+				clocks = <&pcc5 IMX8ULP_CLK_CSI>,
+					 <&pcc5 IMX8ULP_CLK_CSI_CLK_ESC>,
+					 <&pcc5 IMX8ULP_CLK_CSI_CLK_UI>,
+					 <&pcc5 IMX8ULP_CLK_CSI_REGS>;
+				clock-names = "core", "esc", "ui", "pclk";
+				assigned-clocks = <&pcc5 IMX8ULP_CLK_CSI>,
+						  <&pcc5 IMX8ULP_CLK_CSI_CLK_ESC>,
+						  <&pcc5 IMX8ULP_CLK_CSI_CLK_UI>,
+						  <&pcc5 IMX8ULP_CLK_CSI_REGS>;
+				assigned-clock-parents = <&cgc2 IMX8ULP_CLK_PLL4_PFD1_DIV1>,
+							 <&cgc2 IMX8ULP_CLK_PLL4_PFD1_DIV2>,
+							 <&cgc2 IMX8ULP_CLK_PLL4_PFD0_DIV1>;
+				assigned-clock-rates = <200000000>,
+						       <80000000>,
+						       <100000000>,
+						       <79200000>;
+				power-domains = <&scmi_devpd IMX8ULP_PD_MIPI_CSI>;
+				resets = <&pcc5 PCC5_CSI_SWRST>,
+					 <&pcc5 PCC5_CSI_REGS_SWRST>;
+				status = "disabled";
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port at 0 {
+						reg = <0>;
+					};
+
+					port at 1 {
+						reg = <1>;
+
+						mipi_csi_out: endpoint {
+							remote-endpoint = <&isi_in>;
+						};
+					};
+				};
+			};
 		};
 
 		gpiod: gpio at 2e200000 {

-- 
2.34.1



From danielt at kernel.org  Fri Dec  5 01:19:47 2025
From: danielt at kernel.org (Daniel Thompson)
Date: Fri, 5 Dec 2025 09:19:47 +0000
Subject: [PATCH v4 16/26] genirq: Allow per-cpu interrupt sharing for
 non-overlapping affinities
In-Reply-To: <867bv2pbsw.wl-maz@kernel.org>
References: <20251020122944.3074811-1-maz@kernel.org>
 <20251020122944.3074811-17-maz@kernel.org>
 <aTFozefMQRg7lYxh@aspen.lan>
 <867bv2pbsw.wl-maz@kernel.org>
Message-ID: <aTKjsz4TkqmPN678@aspen.lan>

On Thu, Dec 04, 2025 at 02:21:51PM +0000, Marc Zyngier wrote:
> On Thu, 04 Dec 2025 10:56:13 +0000,
> Daniel Thompson <danielt at kernel.org> wrote:
> > CPU 0 Unable to handle kernel paging request at virtual address 0000000000000000, epc == ffffffff801c2398, ra == ffffffff801bab00
> > Oops[#1]:
> > CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted 6.18.0-next-20251204 #20 NONE
> > Hardware name: mti,malta
> > $ 0   : 0000000000000000 0000000000000001 0000000000000000 0000000000000000
> > $ 4   : 0000000000000001 a8000000020e8008 0000000000000000 ffffffff80c23b80
> > $ 8   : 0000000000000004 0000000000000000 0000000000000000 000000000000002f
> > $12   : a8000000020f4000 0000000000003ff0 0000000000003000 0000000000000003
> > $16   : ffffffff80d095c0 ffffffff80ceb410 0000000000000019 ffffffff80c378c0
> > $20   : ffffffff80c4bec8 0000000000000000 ffffffff80e00000 ffffffff80de0000
> > $24   : 0000000000000000 0000000000000010
> > $28   : ffffffff80c20000 a8000000020f7ec0 a800000000e12fcd ffffffff801bab00
> > epc   : ffffffff801c2398 handle_percpu_devid_irq+0xb8/0x250
> > ra    : ffffffff801bab00 handle_irq_desc+0x48/0x88
> > Status: 1400a4e2	KX SX UX KERNEL EXL
> > Cause : 00800408 (ExcCode 02)
> > BadVA : 0000000000000000
> > PrId  : 0001a900 (MIPS I6400)
> > Modules linked in:
> > Process swapper/0 (pid: 0, threadinfo=(____ptrval____), task=(____ptrval____), tls=0000000000000000)
> > Stack : ffffffff80c35a2c 0000000000000002 ffffffff80e00000 0fffffffffffffff
> >         ffffffff80c50000 0000000000000001 0000000000000003 ffffffff801bab00
> >         0000000000000000 ffffffff805d82a8 0000000000000000 0000000000000008
> >         0000000000000000 0000000000000000 0000000000000000 5189d95a7a4f4800
> >         a800000002014300 0000000000000002 0000000000000001 000000000000001f
> >         ffffffff80e00000 0000000000000004 0000000000000000 ffffffff801bab00
> >         0000000000000000 ffffffff809ec128 0000000000000001 fffffffffffffffb
> >         0000000000000001 ffffffff805d7ebc 0000000000000000 0000000000000000
> >         ffffffff80c23c80 ffffffff80c50000 ffffffff80de0000 ffffffff80db0000
> >         0000000000000000 ffffffff80112f10 ffffffff80c23c80 0000000000000000
> > Call Trace:
> > [<ffffffff801c2398>] handle_percpu_devid_irq+0xb8/0x250
> > [<ffffffff801bab00>] handle_irq_desc+0x48/0x88
> > [<ffffffff805d82a8>] gic_irq_dispatch+0xc0/0x288
> > [<ffffffff801bab00>] handle_irq_desc+0x48/0x88
> > [<ffffffff809ec128>] do_domain_IRQ+0x28/0x40
> > [<ffffffff805d7ebc>] plat_irq_dispatch+0x64/0xe8
> > [<ffffffff80112f10>] handle_int+0x134/0x140
> > [<ffffffff80110dc8>] calibrate_delay+0x158/0x290
> > [<ffffffff80d58e48>] start_kernel+0x754/0x7a4
>
> This hack fixes it for me, but really, mips needs to grow up and stop
> using these antiquated APIs.

I can't comment on that. Literally the only thing I ever do on MIPS is
test kgdb ;-) .


> Can please you give it a go?

Looks good to me.

Local testing on MIPS worked nicely and I got a successful build back
for the kgdb tests:
https://gitlab.com/daniel-thompson/linux/-/pipelines/2196473049


Daniel.


From vulab at iscas.ac.cn  Fri Dec  5 01:33:08 2025
From: vulab at iscas.ac.cn (Haotian Zhang)
Date: Fri,  5 Dec 2025 17:33:08 +0800
Subject: [PATCH] pinctrl: imx: handle radix_tree_insert() errors in imx_pinctrl_parse_functions()
Message-ID: <20251205093308.1498-1-vulab@iscas.ac.cn>

imx_pinctrl_parse_functions() doesn't check the result of
radix_tree_insert() which may return a negative error code
if the insertion fails.

Check the return value of radix_tree_insert() and return upon failure.

Fixes: a51c158bf0f7 ("pinctrl: imx: use radix trees for groups and functions")
Signed-off-by: Haotian Zhang <vulab at iscas.ac.cn>
---
 drivers/pinctrl/freescale/pinctrl-imx.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c
index 731c58ad43ee..c20bba7ea306 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx.c
@@ -624,8 +624,14 @@ static int imx_pinctrl_parse_functions(struct device_node *np,
 		 * FIXME: This should use pinctrl_generic_add_group() and not
 		 * access the private radix tree directly.
 		 */
-		radix_tree_insert(&pctl->pin_group_tree,
-				  ipctl->group_index++, grp);
+		ret = radix_tree_insert(&pctl->pin_group_tree,
+				  ipctl->group_index, grp);
+		if (ret) {
+			mutex_unlock(&ipctl->mutex);
+			dev_err(ipctl->dev, "radix_tree_insert failed\n");
+			return ret;
+		}
+		ipctl->group_index++;
 		mutex_unlock(&ipctl->mutex);
 
 		imx_pinctrl_parse_groups(child, grp, ipctl, i++);
-- 
2.25.1



From y.moog at phytec.de  Fri Dec  5 01:33:26 2025
From: y.moog at phytec.de (Yannic Moog)
Date: Fri, 5 Dec 2025 10:33:26 +0100
Subject: [PATCH v2 2/4] arm64: dts: imx8mp-phycore-som: add spi-nor supply
 vcc
In-Reply-To: <20251205-imx8mp-dts-additions-v2-0-d4db54fbadd0@phytec.de>
References: <20251205-imx8mp-dts-additions-v2-0-d4db54fbadd0@phytec.de>
Message-ID: <20251205-imx8mp-dts-additions-v2-2-d4db54fbadd0@phytec.de>

The spi flash on the SoM is missing its vcc supply definition. Add
missing regulator which supplies the flash with 1.8V.

Signed-off-by: Yannic Moog <y.moog at phytec.de>
---
 arch/arm64/boot/dts/freescale/imx8mp-phycore-som.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-phycore-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-phycore-som.dtsi
index 88831c0fbb7be3db18910385e4e15691b1c74ef2..63adb1c4b3ebc9e1f588e8c7c00acf92f5a04e94 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-phycore-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-phycore-som.dtsi
@@ -28,6 +28,13 @@ reg_vdd_io: regulator-vdd-io {
 		regulator-min-microvolt = <3300000>;
 		regulator-name = "VDD_IO";
 	};
+
+	reg_vdd_1v8: regulator-vdd-1v8 {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <1800000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-name = "VDD_1V8";
+	};
 };
 
 &A53_0 {
@@ -83,6 +90,7 @@ som_flash: flash at 0 {
 		spi-max-frequency = <80000000>;
 		spi-rx-bus-width = <4>;
 		spi-tx-bus-width = <1>;
+		vcc-supply = <&reg_vdd_1v8>;
 	};
 };
 

-- 
2.43.0



From y.moog at phytec.de  Fri Dec  5 01:33:25 2025
From: y.moog at phytec.de (Yannic Moog)
Date: Fri, 5 Dec 2025 10:33:25 +0100
Subject: [PATCH v2 1/4] arm64: dts: imx8mp-phyboard-pollux: add fan-supply
In-Reply-To: <20251205-imx8mp-dts-additions-v2-0-d4db54fbadd0@phytec.de>
References: <20251205-imx8mp-dts-additions-v2-0-d4db54fbadd0@phytec.de>
Message-ID: <20251205-imx8mp-dts-additions-v2-1-d4db54fbadd0@phytec.de>

Add 5v regulator to gpio fan node.

Reviewed-by: Frank Li <Frank.Li at nxp.com>
Signed-off-by: Yannic Moog <y.moog at phytec.de>
---
 arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts b/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts
index 9687b4ded8f4c98fe68bcbeedcb5ea03434e27a3..6203e39bc01be476f16f5ac80b6365bce150ae37 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts
@@ -31,6 +31,7 @@ fan0: fan {
 		compatible = "gpio-fan";
 		pinctrl-names = "default";
 		pinctrl-0 = <&pinctrl_fan>;
+		fan-supply = <&reg_vcc_5v_sw>;
 		gpio-fan,speed-map = <0     0
 				      13000 1>;
 		gpios = <&gpio5 4 GPIO_ACTIVE_HIGH>;

-- 
2.43.0



From y.moog at phytec.de  Fri Dec  5 01:33:27 2025
From: y.moog at phytec.de (Yannic Moog)
Date: Fri, 5 Dec 2025 10:33:27 +0100
Subject: [PATCH v2 3/4] arm64: dts: imx8mp-phyboard-pollux: Enable i2c3
In-Reply-To: <20251205-imx8mp-dts-additions-v2-0-d4db54fbadd0@phytec.de>
References: <20251205-imx8mp-dts-additions-v2-0-d4db54fbadd0@phytec.de>
Message-ID: <20251205-imx8mp-dts-additions-v2-3-d4db54fbadd0@phytec.de>

From: Stefan Riedmueller <s.riedmueller at phytec.de>

The i2c3 of the phyBOARD-Pollux is used on the CSI1 interface to connect
to imaging sensors. Thus define it so it can be easily enabled if
required.

Signed-off-by: Stefan Riedmueller <s.riedmueller at phytec.de>
Signed-off-by: Teresa Remmet <t.remmet at phytec.de>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
Signed-off-by: Yannic Moog <y.moog at phytec.de>
---
 .../dts/freescale/imx8mp-phyboard-pollux-rdk.dts   | 23 ++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts b/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts
index 6203e39bc01be476f16f5ac80b6365bce150ae37..7d34b820e3213a3832c5be47444d4e9c636a6202 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts
@@ -228,6 +228,15 @@ led-3 {
 	};
 };
 
+&i2c3 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default", "gpio";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	pinctrl-1 = <&pinctrl_i2c3_gpio>;
+	sda-gpios = <&gpio5 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	scl-gpios = <&gpio5 19 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+};
+
 &ldb_lvds_ch1 {
 	remote-endpoint = <&panel1_in>;
 };
@@ -442,6 +451,20 @@ MX8MP_IOMUXC_I2C2_SDA__GPIO5_IO17	0x1e2
 		>;
 	};
 
+	pinctrl_i2c3: i2c3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL		0x400001c2
+			MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA		0x400001c2
+		>;
+	};
+
+	pinctrl_i2c3_gpio: i2c3gpiogrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C3_SCL__GPIO5_IO18	0x1e2
+			MX8MP_IOMUXC_I2C3_SDA__GPIO5_IO19	0x1e2
+		>;
+	};
+
 	pinctrl_lvds1: lvds1grp {
 		fsl,pins = <
 			MX8MP_IOMUXC_SD2_WP__GPIO2_IO20		0x12

-- 
2.43.0



From y.moog at phytec.de  Fri Dec  5 01:33:24 2025
From: y.moog at phytec.de (Yannic Moog)
Date: Fri, 5 Dec 2025 10:33:24 +0100
Subject: [PATCH v2 0/4] arm64: dts: additions for imx8mp-phyboard-pollux
Message-ID: <20251205-imx8mp-dts-additions-v2-0-d4db54fbadd0@phytec.de>

This series adds missing miscellaneous hardware description to the
respective device tree files as well as a bluetooth/wifi expansion
board.

- i2c3 (basis for camera overlays)
- missing supply voltages
- PEB-WLBT-05 expansion board

---
Changes in v2:
- improved wording of i2c3 commit description
- removed regulator-always-on and regulator-boot-on properties
- rebased
- Link to v1: https://lore.kernel.org/r/20251020-imx8mp-dts-additions-v1-0-ea9ac5652b8b at phytec.de

---
Stefan Riedmueller (1):
      arm64: dts: imx8mp-phyboard-pollux: Enable i2c3

Yannic Moog (3):
      arm64: dts: imx8mp-phyboard-pollux: add fan-supply
      arm64: dts: imx8mp-phycore-som: add spi-nor supply vcc
      arm64: dts: imx8mp-phyboard-pollux: add PEB-WLBT-05 expansion board

 arch/arm64/boot/dts/freescale/Makefile             |   3 +
 .../imx8mp-phyboard-pollux-peb-wlbt-05.dtso        | 108 +++++++++++++++++++++
 .../dts/freescale/imx8mp-phyboard-pollux-rdk.dts   |  31 ++++++
 .../boot/dts/freescale/imx8mp-phycore-som.dtsi     |   8 ++
 4 files changed, 150 insertions(+)
---
base-commit: 89d95dbad2a3857f06cb6002566bbdcbe53bbfef
change-id: 20251014-imx8mp-dts-additions-81fac0750e3c

Best regards,
-- 
Yannic Moog <y.moog at phytec.de>



From y.moog at phytec.de  Fri Dec  5 01:33:28 2025
From: y.moog at phytec.de (Yannic Moog)
Date: Fri, 5 Dec 2025 10:33:28 +0100
Subject: [PATCH v2 4/4] arm64: dts: imx8mp-phyboard-pollux: add PEB-WLBT-05
 expansion board
In-Reply-To: <20251205-imx8mp-dts-additions-v2-0-d4db54fbadd0@phytec.de>
References: <20251205-imx8mp-dts-additions-v2-0-d4db54fbadd0@phytec.de>
Message-ID: <20251205-imx8mp-dts-additions-v2-4-d4db54fbadd0@phytec.de>

PEB-WLBT-05 is an expansion board that provides WIFI and Bluetooth
functionality. It features the Ezurio Sterling LWB module [1].
Add missing regulator to baseboard dts.

[1] https://www.ezurio.com/wireless-modules/wifi-modules-bluetooth/sterling-lwb-24-ghz-wifi-4-bt-51-module

Signed-off-by: Yannic Moog <y.moog at phytec.de>
---
 arch/arm64/boot/dts/freescale/Makefile             |   3 +
 .../imx8mp-phyboard-pollux-peb-wlbt-05.dtso        | 108 +++++++++++++++++++++
 .../dts/freescale/imx8mp-phyboard-pollux-rdk.dts   |   7 ++
 3 files changed, 118 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index f30d3fd724d0ce6b38f7bef10e3970ac34f70f4a..20b5f97671ddc5462493f3c90bda64d06476ca72 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -243,12 +243,15 @@ imx8mp-phyboard-pollux-peb-av-10-ph128800t006-dtbs += imx8mp-phyboard-pollux-rdk
 imx8mp-phyboard-pollux-ph128800t006-dtbs += imx8mp-phyboard-pollux-rdk.dtb \
 	imx8mp-phyboard-pollux-ph128800t006.dtbo
 imx8mp-phyboard-pollux-rdk-no-eth-dtbs += imx8mp-phyboard-pollux-rdk.dtb imx8mp-phycore-no-eth.dtbo
+imx8mp-phyboard-pollux-wlbt-dtbs += imx8mp-phyboard-pollux-rdk.dtb \
+	imx8mp-phyboard-pollux-peb-wlbt-05.dtbo
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-phyboard-pollux-etml1010g3dra.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-phyboard-pollux-peb-av-10.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-phyboard-pollux-peb-av-10-etml1010g3dra.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-phyboard-pollux-peb-av-10-ph128800t006.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-phyboard-pollux-ph128800t006.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-phyboard-pollux-rdk-no-eth.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-phyboard-pollux-wlbt.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-prt8ml.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-skov-basic.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-skov-revb-hdmi.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-peb-wlbt-05.dtso b/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-peb-wlbt-05.dtso
new file mode 100644
index 0000000000000000000000000000000000000000..0e98f4d942716e57f5bc1567924460b618eb0930
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-peb-wlbt-05.dtso
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright (C) 2025 PHYTEC Messtechnik GmbH
+ */
+
+#include <dt-bindings/clock/imx8mp-clock.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include "imx8mp-pinfunc.h"
+
+/dts-v1/;
+/plugin/;
+
+&{/} {
+	wlbt_clock: clock-32768 {
+		compatible = "fixed-clock";
+		clock-accuracy = <20000>;
+		clock-frequency = <32768>;
+		clock-output-names = "WIFIBT_SLOW_CLK";
+		#clock-cells = <0>;
+	};
+
+	usdhc1_pwrseq: pwr-seq {
+		compatible = "mmc-pwrseq-simple";
+		post-power-on-delay-ms = <250>;
+		reset-gpios = <&gpio5 5 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&iomuxc {
+	pinctrl_uart3: uart3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_RESET_B__UART3_DCE_RTS	0x140	/* RTS */
+			MX8MP_IOMUXC_SD1_STROBE__UART3_DCE_CTS	0x140	/* CTS */
+			MX8MP_IOMUXC_UART3_RXD__UART3_DCE_RX	0x140	/* RX */
+			MX8MP_IOMUXC_UART3_TXD__UART3_DCE_TX	0x140	/* TX */
+		>;
+	};
+
+	pinctrl_bluetooth: bluetoothgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_DATA4__GPIO2_IO06	0x106	/* BT_DEV_WAKE_EXP */
+			MX8MP_IOMUXC_SD1_DATA5__GPIO2_IO07	0x106	/* BT_REG_ON_EXP */
+			MX8MP_IOMUXC_SD1_DATA7__GPIO2_IO09	0x106	/* BT_HOST_WAKE_EXP */
+		>;
+	};
+
+	pinctrl_usdhc1: usdhc1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK	0x190	/* SDIO_CLK */
+			MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD	0x1d0	/* SDIO_CMD */
+			MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0	0x1d0	/* SDIO_D0 */
+			MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1	0x1d0	/* SDIO_D1 */
+			MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2	0x1d0	/* SDIO_D2 */
+			MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3	0x1d0	/* SDIO_D3 */
+		>;
+	};
+
+	pinctrl_wifi: wifigrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SPDIF_EXT_CLK__GPIO5_IO05	0x106	/* WL_REG_ON_EXP */
+		>;
+	};
+};
+
+&uart3 {
+	assigned-clocks = <&clk IMX8MP_CLK_UART3>;
+	assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_80M>;
+	pinctrl-0 = <&pinctrl_uart3>;
+	pinctrl-names = "default";
+	uart-has-rtscts;
+	status = "okay";
+
+	bluetooth {
+		compatible = "brcm,bcm43438-bt";
+		pinctrl-0 = <&pinctrl_bluetooth>;
+		pinctrl-names = "default";
+		clock-names = "lpo";
+		clocks = <&wlbt_clock>;
+		device-wakeup-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>;
+		host-wakeup-gpios = <&gpio2 9 GPIO_ACTIVE_HIGH>;
+		max-speed = <3000000>;
+		shutdown-gpios = <&gpio2 7 GPIO_ACTIVE_HIGH>;
+		vbat-supply = <&reg_vcc_3v3_sw>;
+		vddio-supply = <&reg_vcc_1v8_exp_con>;
+	};
+};
+
+&usdhc1 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	pinctrl-0 = <&pinctrl_usdhc1>;
+	pinctrl-names = "default";
+	bus-width = <4>;
+	max-frequency = <50000000>;
+	mmc-pwrseq = <&usdhc1_pwrseq>;
+	non-removable;
+	vmmc-supply = <&reg_vcc_3v3_sw>;
+	status = "okay";
+
+	wifi at 1 {
+		compatible = "brcm,bcm4329-fmac";
+		reg = <1>;
+		pinctrl-0 = <&pinctrl_wifi>;
+		pinctrl-names = "default";
+		reset-gpios = <&gpio5 5 GPIO_ACTIVE_LOW>;
+	};
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts b/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts
index 7d34b820e3213a3832c5be47444d4e9c636a6202..90ec73068a6deb71554b62be951f3010a4e8c5c5 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts
@@ -119,6 +119,13 @@ reg_vcc_3v3_sw: regulator-vcc-3v3-sw {
 		regulator-max-microvolt = <3300000>;
 	};
 
+	reg_vcc_1v8_exp_con: regulator-vcc-1v8 {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <1800000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-name = "VCC_1V8_EXP_CON";
+	};
+
 	thermal-zones {
 		soc-thermal {
 			trips {

-- 
2.43.0



From tomi.valkeinen at ideasonboard.com  Fri Dec  5 01:51:47 2025
From: tomi.valkeinen at ideasonboard.com (Tomi Valkeinen)
Date: Fri, 05 Dec 2025 11:51:47 +0200
Subject: [PATCH 0/4] drm: Revert and fix enable/disable sequence
Message-ID: <20251205-drm-seq-fix-v1-0-fda68fa1b3de@ideasonboard.com>

Changing the enable/disable sequence in commit c9b1150a68d9
("drm/atomic-helper: Re-order bridge chain pre-enable and post-disable")
has caused regressions on multiple platforms: R-Car, MCDE, Rockchip.

This is an alternate series to Linus' series:

https://lore.kernel.org/all/20251202-mcde-drm-regression-thirdfix-v6-0-f1bffd4ec0fa%40kernel.org/

This series first reverts the original commit and reverts a fix for
mediatek which is no longer needed. It then exposes helper functions
from DRM core, and finally implements the new sequence only in the tidss
driver.

There is one more fix in upstream for the original commit, commit
5d91394f2361 ("drm/exynos: fimd: Guard display clock control with
runtime PM calls"), but I have not reverted that one as it looks like a
valid patch in its own.

I added Cc stable v6.17+ to all patches, but I didn't add Fixes tags, as
I wasn't sure what should they point to. But I could perhaps add Fixes:
<original commit> to all of these.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
---
Linus Walleij (1):
      drm/atomic-helper: Export and namespace some functions

Tomi Valkeinen (3):
      Revert "drm/atomic-helper: Re-order bridge chain pre-enable and post-disable"
      Revert "drm/mediatek: dsi: Fix DSI host and panel bridge pre-enable order"
      drm/tidss: Fix enable/disable order

 drivers/gpu/drm/drm_atomic_helper.c | 122 ++++++++++++++----
 drivers/gpu/drm/mediatek/mtk_dsi.c  |   6 -
 drivers/gpu/drm/tidss/tidss_kms.c   |  30 ++++-
 include/drm/drm_atomic_helper.h     |  22 ++++
 include/drm/drm_bridge.h            | 249 ++++++++++--------------------------
 5 files changed, 214 insertions(+), 215 deletions(-)
---
base-commit: 88e721ab978a86426aa08da520de77430fa7bb84
change-id: 20251205-drm-seq-fix-b4ed1f56604b

Best regards,
-- 
Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>



From tomi.valkeinen at ideasonboard.com  Fri Dec  5 01:51:48 2025
From: tomi.valkeinen at ideasonboard.com (Tomi Valkeinen)
Date: Fri, 05 Dec 2025 11:51:48 +0200
Subject: [PATCH 1/4] Revert "drm/atomic-helper: Re-order bridge chain
 pre-enable and post-disable"
In-Reply-To: <20251205-drm-seq-fix-v1-0-fda68fa1b3de@ideasonboard.com>
References: <20251205-drm-seq-fix-v1-0-fda68fa1b3de@ideasonboard.com>
Message-ID: <20251205-drm-seq-fix-v1-1-fda68fa1b3de@ideasonboard.com>

This reverts commit c9b1150a68d9362a0827609fc0dc1664c0d8bfe1.

Changing the enable/disable sequence has caused regressions on multiple
platforms: R-Car, MCDE, Rockchip. A series (see link below)  was sent to
fix these, but it was decided that it's better to revert the original
patch and change the enable/disable sequence only in the tidss driver.

Reverting this commit breaks tidss's DSI and OLDI outputs, which will be
fixed in the following commits.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
Link: https://lore.kernel.org/all/20251202-mcde-drm-regression-thirdfix-v6-0-f1bffd4ec0fa%40kernel.org/
Fixes: c9b1150a68d9 ("drm/atomic-helper: Re-order bridge chain pre-enable and post-disable")
Cc: stable at vger.kernel.org # v6.17+
---
 drivers/gpu/drm/drm_atomic_helper.c |   8 +-
 include/drm/drm_bridge.h            | 249 ++++++++++--------------------------
 2 files changed, 70 insertions(+), 187 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 10adac9397cf..ef97f37560b2 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1341,9 +1341,9 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *state)
 {
 	encoder_bridge_disable(dev, state);
 
-	crtc_disable(dev, state);
-
 	encoder_bridge_post_disable(dev, state);
+
+	crtc_disable(dev, state);
 }
 
 /**
@@ -1682,10 +1682,10 @@ encoder_bridge_enable(struct drm_device *dev, struct drm_atomic_state *state)
 void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
 					      struct drm_atomic_state *state)
 {
-	encoder_bridge_pre_enable(dev, state);
-
 	crtc_enable(dev, state);
 
+	encoder_bridge_pre_enable(dev, state);
+
 	encoder_bridge_enable(dev, state);
 
 	drm_atomic_helper_commit_writebacks(dev, state);
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 0ff7ab4aa868..dbafe136833f 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -176,33 +176,17 @@ struct drm_bridge_funcs {
 	/**
 	 * @disable:
 	 *
-	 * The @disable callback should disable the bridge.
+	 * This callback should disable the bridge. It is called right before
+	 * the preceding element in the display pipe is disabled. If the
+	 * preceding element is a bridge this means it's called before that
+	 * bridge's @disable vfunc. If the preceding element is a &drm_encoder
+	 * it's called right before the &drm_encoder_helper_funcs.disable,
+	 * &drm_encoder_helper_funcs.prepare or &drm_encoder_helper_funcs.dpms
+	 * hook.
 	 *
 	 * The bridge can assume that the display pipe (i.e. clocks and timing
 	 * signals) feeding it is still running when this callback is called.
 	 *
-	 *
-	 * If the preceding element is a &drm_bridge, then this is called before
-	 * that bridge is disabled via one of:
-	 *
-	 * - &drm_bridge_funcs.disable
-	 * - &drm_bridge_funcs.atomic_disable
-	 *
-	 * If the preceding element of the bridge is a display controller, then
-	 * this callback is called before the encoder is disabled via one of:
-	 *
-	 * - &drm_encoder_helper_funcs.atomic_disable
-	 * - &drm_encoder_helper_funcs.prepare
-	 * - &drm_encoder_helper_funcs.disable
-	 * - &drm_encoder_helper_funcs.dpms
-	 *
-	 * and the CRTC is disabled via one of:
-	 *
-	 * - &drm_crtc_helper_funcs.prepare
-	 * - &drm_crtc_helper_funcs.atomic_disable
-	 * - &drm_crtc_helper_funcs.disable
-	 * - &drm_crtc_helper_funcs.dpms.
-	 *
 	 * The @disable callback is optional.
 	 *
 	 * NOTE:
@@ -215,34 +199,17 @@ struct drm_bridge_funcs {
 	/**
 	 * @post_disable:
 	 *
-	 * The bridge must assume that the display pipe (i.e. clocks and timing
-	 * signals) feeding this bridge is no longer running when the
-	 * @post_disable is called.
+	 * This callback should disable the bridge. It is called right after the
+	 * preceding element in the display pipe is disabled. If the preceding
+	 * element is a bridge this means it's called after that bridge's
+	 * @post_disable function. If the preceding element is a &drm_encoder
+	 * it's called right after the encoder's
+	 * &drm_encoder_helper_funcs.disable, &drm_encoder_helper_funcs.prepare
+	 * or &drm_encoder_helper_funcs.dpms hook.
 	 *
-	 * This callback should perform all the actions required by the hardware
-	 * after it has stopped receiving signals from the preceding element.
-	 *
-	 * If the preceding element is a &drm_bridge, then this is called after
-	 * that bridge is post-disabled (unless marked otherwise by the
-	 * @pre_enable_prev_first flag) via one of:
-	 *
-	 * - &drm_bridge_funcs.post_disable
-	 * - &drm_bridge_funcs.atomic_post_disable
-	 *
-	 * If the preceding element of the bridge is a display controller, then
-	 * this callback is called after the encoder is disabled via one of:
-	 *
-	 * - &drm_encoder_helper_funcs.atomic_disable
-	 * - &drm_encoder_helper_funcs.prepare
-	 * - &drm_encoder_helper_funcs.disable
-	 * - &drm_encoder_helper_funcs.dpms
-	 *
-	 * and the CRTC is disabled via one of:
-	 *
-	 * - &drm_crtc_helper_funcs.prepare
-	 * - &drm_crtc_helper_funcs.atomic_disable
-	 * - &drm_crtc_helper_funcs.disable
-	 * - &drm_crtc_helper_funcs.dpms
+	 * The bridge must assume that the display pipe (i.e. clocks and timing
+	 * signals) feeding it is no longer running when this callback is
+	 * called.
 	 *
 	 * The @post_disable callback is optional.
 	 *
@@ -285,30 +252,18 @@ struct drm_bridge_funcs {
 	/**
 	 * @pre_enable:
 	 *
-	 * The display pipe (i.e. clocks and timing signals) feeding this bridge
-	 * will not yet be running when the @pre_enable is called.
-	 *
-	 * This callback should perform all the necessary actions to prepare the
-	 * bridge to accept signals from the preceding element.
-	 *
-	 * If the preceding element is a &drm_bridge, then this is called before
-	 * that bridge is pre-enabled (unless marked otherwise by
-	 * @pre_enable_prev_first flag) via one of:
-	 *
-	 * - &drm_bridge_funcs.pre_enable
-	 * - &drm_bridge_funcs.atomic_pre_enable
-	 *
-	 * If the preceding element of the bridge is a display controller, then
-	 * this callback is called before the CRTC is enabled via one of:
-	 *
-	 * - &drm_crtc_helper_funcs.atomic_enable
-	 * - &drm_crtc_helper_funcs.commit
-	 *
-	 * and the encoder is enabled via one of:
+	 * This callback should enable the bridge. It is called right before
+	 * the preceding element in the display pipe is enabled. If the
+	 * preceding element is a bridge this means it's called before that
+	 * bridge's @pre_enable function. If the preceding element is a
+	 * &drm_encoder it's called right before the encoder's
+	 * &drm_encoder_helper_funcs.enable, &drm_encoder_helper_funcs.commit or
+	 * &drm_encoder_helper_funcs.dpms hook.
 	 *
-	 * - &drm_encoder_helper_funcs.atomic_enable
-	 * - &drm_encoder_helper_funcs.enable
-	 * - &drm_encoder_helper_funcs.commit
+	 * The display pipe (i.e. clocks and timing signals) feeding this bridge
+	 * will not yet be running when this callback is called. The bridge must
+	 * not enable the display link feeding the next bridge in the chain (if
+	 * there is one) when this callback is called.
 	 *
 	 * The @pre_enable callback is optional.
 	 *
@@ -322,31 +277,19 @@ struct drm_bridge_funcs {
 	/**
 	 * @enable:
 	 *
-	 * The @enable callback should enable the bridge.
+	 * This callback should enable the bridge. It is called right after
+	 * the preceding element in the display pipe is enabled. If the
+	 * preceding element is a bridge this means it's called after that
+	 * bridge's @enable function. If the preceding element is a
+	 * &drm_encoder it's called right after the encoder's
+	 * &drm_encoder_helper_funcs.enable, &drm_encoder_helper_funcs.commit or
+	 * &drm_encoder_helper_funcs.dpms hook.
 	 *
 	 * The bridge can assume that the display pipe (i.e. clocks and timing
 	 * signals) feeding it is running when this callback is called. This
 	 * callback must enable the display link feeding the next bridge in the
 	 * chain if there is one.
 	 *
-	 * If the preceding element is a &drm_bridge, then this is called after
-	 * that bridge is enabled via one of:
-	 *
-	 * - &drm_bridge_funcs.enable
-	 * - &drm_bridge_funcs.atomic_enable
-	 *
-	 * If the preceding element of the bridge is a display controller, then
-	 * this callback is called after the CRTC is enabled via one of:
-	 *
-	 * - &drm_crtc_helper_funcs.atomic_enable
-	 * - &drm_crtc_helper_funcs.commit
-	 *
-	 * and the encoder is enabled via one of:
-	 *
-	 * - &drm_encoder_helper_funcs.atomic_enable
-	 * - &drm_encoder_helper_funcs.enable
-	 * - drm_encoder_helper_funcs.commit
-	 *
 	 * The @enable callback is optional.
 	 *
 	 * NOTE:
@@ -359,30 +302,17 @@ struct drm_bridge_funcs {
 	/**
 	 * @atomic_pre_enable:
 	 *
-	 * The display pipe (i.e. clocks and timing signals) feeding this bridge
-	 * will not yet be running when the @atomic_pre_enable is called.
-	 *
-	 * This callback should perform all the necessary actions to prepare the
-	 * bridge to accept signals from the preceding element.
-	 *
-	 * If the preceding element is a &drm_bridge, then this is called before
-	 * that bridge is pre-enabled (unless marked otherwise by
-	 * @pre_enable_prev_first flag) via one of:
-	 *
-	 * - &drm_bridge_funcs.pre_enable
-	 * - &drm_bridge_funcs.atomic_pre_enable
+	 * This callback should enable the bridge. It is called right before
+	 * the preceding element in the display pipe is enabled. If the
+	 * preceding element is a bridge this means it's called before that
+	 * bridge's @atomic_pre_enable or @pre_enable function. If the preceding
+	 * element is a &drm_encoder it's called right before the encoder's
+	 * &drm_encoder_helper_funcs.atomic_enable hook.
 	 *
-	 * If the preceding element of the bridge is a display controller, then
-	 * this callback is called before the CRTC is enabled via one of:
-	 *
-	 * - &drm_crtc_helper_funcs.atomic_enable
-	 * - &drm_crtc_helper_funcs.commit
-	 *
-	 * and the encoder is enabled via one of:
-	 *
-	 * - &drm_encoder_helper_funcs.atomic_enable
-	 * - &drm_encoder_helper_funcs.enable
-	 * - &drm_encoder_helper_funcs.commit
+	 * The display pipe (i.e. clocks and timing signals) feeding this bridge
+	 * will not yet be running when this callback is called. The bridge must
+	 * not enable the display link feeding the next bridge in the chain (if
+	 * there is one) when this callback is called.
 	 *
 	 * The @atomic_pre_enable callback is optional.
 	 */
@@ -392,31 +322,18 @@ struct drm_bridge_funcs {
 	/**
 	 * @atomic_enable:
 	 *
-	 * The @atomic_enable callback should enable the bridge.
+	 * This callback should enable the bridge. It is called right after
+	 * the preceding element in the display pipe is enabled. If the
+	 * preceding element is a bridge this means it's called after that
+	 * bridge's @atomic_enable or @enable function. If the preceding element
+	 * is a &drm_encoder it's called right after the encoder's
+	 * &drm_encoder_helper_funcs.atomic_enable hook.
 	 *
 	 * The bridge can assume that the display pipe (i.e. clocks and timing
 	 * signals) feeding it is running when this callback is called. This
 	 * callback must enable the display link feeding the next bridge in the
 	 * chain if there is one.
 	 *
-	 * If the preceding element is a &drm_bridge, then this is called after
-	 * that bridge is enabled via one of:
-	 *
-	 * - &drm_bridge_funcs.enable
-	 * - &drm_bridge_funcs.atomic_enable
-	 *
-	 * If the preceding element of the bridge is a display controller, then
-	 * this callback is called after the CRTC is enabled via one of:
-	 *
-	 * - &drm_crtc_helper_funcs.atomic_enable
-	 * - &drm_crtc_helper_funcs.commit
-	 *
-	 * and the encoder is enabled via one of:
-	 *
-	 * - &drm_encoder_helper_funcs.atomic_enable
-	 * - &drm_encoder_helper_funcs.enable
-	 * - drm_encoder_helper_funcs.commit
-	 *
 	 * The @atomic_enable callback is optional.
 	 */
 	void (*atomic_enable)(struct drm_bridge *bridge,
@@ -424,32 +341,16 @@ struct drm_bridge_funcs {
 	/**
 	 * @atomic_disable:
 	 *
-	 * The @atomic_disable callback should disable the bridge.
+	 * This callback should disable the bridge. It is called right before
+	 * the preceding element in the display pipe is disabled. If the
+	 * preceding element is a bridge this means it's called before that
+	 * bridge's @atomic_disable or @disable vfunc. If the preceding element
+	 * is a &drm_encoder it's called right before the
+	 * &drm_encoder_helper_funcs.atomic_disable hook.
 	 *
 	 * The bridge can assume that the display pipe (i.e. clocks and timing
 	 * signals) feeding it is still running when this callback is called.
 	 *
-	 * If the preceding element is a &drm_bridge, then this is called before
-	 * that bridge is disabled via one of:
-	 *
-	 * - &drm_bridge_funcs.disable
-	 * - &drm_bridge_funcs.atomic_disable
-	 *
-	 * If the preceding element of the bridge is a display controller, then
-	 * this callback is called before the encoder is disabled via one of:
-	 *
-	 * - &drm_encoder_helper_funcs.atomic_disable
-	 * - &drm_encoder_helper_funcs.prepare
-	 * - &drm_encoder_helper_funcs.disable
-	 * - &drm_encoder_helper_funcs.dpms
-	 *
-	 * and the CRTC is disabled via one of:
-	 *
-	 * - &drm_crtc_helper_funcs.prepare
-	 * - &drm_crtc_helper_funcs.atomic_disable
-	 * - &drm_crtc_helper_funcs.disable
-	 * - &drm_crtc_helper_funcs.dpms.
-	 *
 	 * The @atomic_disable callback is optional.
 	 */
 	void (*atomic_disable)(struct drm_bridge *bridge,
@@ -458,34 +359,16 @@ struct drm_bridge_funcs {
 	/**
 	 * @atomic_post_disable:
 	 *
-	 * The bridge must assume that the display pipe (i.e. clocks and timing
-	 * signals) feeding this bridge is no longer running when the
-	 * @atomic_post_disable is called.
-	 *
-	 * This callback should perform all the actions required by the hardware
-	 * after it has stopped receiving signals from the preceding element.
+	 * This callback should disable the bridge. It is called right after the
+	 * preceding element in the display pipe is disabled. If the preceding
+	 * element is a bridge this means it's called after that bridge's
+	 * @atomic_post_disable or @post_disable function. If the preceding
+	 * element is a &drm_encoder it's called right after the encoder's
+	 * &drm_encoder_helper_funcs.atomic_disable hook.
 	 *
-	 * If the preceding element is a &drm_bridge, then this is called after
-	 * that bridge is post-disabled (unless marked otherwise by the
-	 * @pre_enable_prev_first flag) via one of:
-	 *
-	 * - &drm_bridge_funcs.post_disable
-	 * - &drm_bridge_funcs.atomic_post_disable
-	 *
-	 * If the preceding element of the bridge is a display controller, then
-	 * this callback is called after the encoder is disabled via one of:
-	 *
-	 * - &drm_encoder_helper_funcs.atomic_disable
-	 * - &drm_encoder_helper_funcs.prepare
-	 * - &drm_encoder_helper_funcs.disable
-	 * - &drm_encoder_helper_funcs.dpms
-	 *
-	 * and the CRTC is disabled via one of:
-	 *
-	 * - &drm_crtc_helper_funcs.prepare
-	 * - &drm_crtc_helper_funcs.atomic_disable
-	 * - &drm_crtc_helper_funcs.disable
-	 * - &drm_crtc_helper_funcs.dpms
+	 * The bridge must assume that the display pipe (i.e. clocks and timing
+	 * signals) feeding it is no longer running when this callback is
+	 * called.
 	 *
 	 * The @atomic_post_disable callback is optional.
 	 */

-- 
2.43.0



From tomi.valkeinen at ideasonboard.com  Fri Dec  5 01:51:49 2025
From: tomi.valkeinen at ideasonboard.com (Tomi Valkeinen)
Date: Fri, 05 Dec 2025 11:51:49 +0200
Subject: [PATCH 2/4] Revert "drm/mediatek: dsi: Fix DSI host and panel
 bridge pre-enable order"
In-Reply-To: <20251205-drm-seq-fix-v1-0-fda68fa1b3de@ideasonboard.com>
References: <20251205-drm-seq-fix-v1-0-fda68fa1b3de@ideasonboard.com>
Message-ID: <20251205-drm-seq-fix-v1-2-fda68fa1b3de@ideasonboard.com>

This reverts commit f5b1819193667bf62c3c99d3921b9429997a14b2.

As the original commit (c9b1150a68d9 ("drm/atomic-helper: Re-order
bridge chain pre-enable and post-disable")) causing the issue has been
reverted, let's revert the fix for mediatek.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
Cc: stable at vger.kernel.org # v6.17+
---
 drivers/gpu/drm/mediatek/mtk_dsi.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
index 0e2bcd5f67b7..d7726091819c 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -1002,12 +1002,6 @@ static int mtk_dsi_host_attach(struct mipi_dsi_host *host,
 			return PTR_ERR(dsi->next_bridge);
 	}
 
-	/*
-	 * set flag to request the DSI host bridge be pre-enabled before device bridge
-	 * in the chain, so the DSI host is ready when the device bridge is pre-enabled
-	 */
-	dsi->next_bridge->pre_enable_prev_first = true;
-
 	drm_bridge_add(&dsi->bridge);
 
 	ret = component_add(host->dev, &mtk_dsi_component_ops);

-- 
2.43.0



From tomi.valkeinen at ideasonboard.com  Fri Dec  5 01:51:50 2025
From: tomi.valkeinen at ideasonboard.com (Tomi Valkeinen)
Date: Fri, 05 Dec 2025 11:51:50 +0200
Subject: [PATCH 3/4] drm/atomic-helper: Export and namespace some functions
In-Reply-To: <20251205-drm-seq-fix-v1-0-fda68fa1b3de@ideasonboard.com>
References: <20251205-drm-seq-fix-v1-0-fda68fa1b3de@ideasonboard.com>
Message-ID: <20251205-drm-seq-fix-v1-3-fda68fa1b3de@ideasonboard.com>

From: Linus Walleij <linusw at kernel.org>

Export and namespace those not prefixed with drm_* so
it becomes possible to write custom commit tail functions
in individual drivers using the helper infrastructure.

Tested-by: Marek Vasut <marek.vasut+renesas at mailbox.org>
Reviewed-by: Maxime Ripard <mripard at kernel.org>
Signed-off-by: Linus Walleij <linusw at kernel.org>
[Tomi: Resolved conflicts, fixed indentation]
Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
Cc: stable at vger.kernel.org # v6.17+
---
 drivers/gpu/drm/drm_atomic_helper.c | 122 +++++++++++++++++++++++++++++-------
 include/drm/drm_atomic_helper.h     |  22 +++++++
 2 files changed, 121 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index ef97f37560b2..5beea645035f 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1162,8 +1162,18 @@ crtc_needs_disable(struct drm_crtc_state *old_state,
 	       new_state->self_refresh_active;
 }
 
-static void
-encoder_bridge_disable(struct drm_device *dev, struct drm_atomic_state *state)
+/**
+ * drm_atomic_helper_commit_encoder_bridge_disable - disable bridges and encoder
+ * @dev: DRM device
+ * @state: the driver state object
+ *
+ * Loops over all connectors in the current state and if the CRTC needs
+ * it, disables the bridge chain all the way, then disables the encoder
+ * afterwards.
+ */
+void
+drm_atomic_helper_commit_encoder_bridge_disable(struct drm_device *dev,
+						struct drm_atomic_state *state)
 {
 	struct drm_connector *connector;
 	struct drm_connector_state *old_conn_state, *new_conn_state;
@@ -1229,9 +1239,18 @@ encoder_bridge_disable(struct drm_device *dev, struct drm_atomic_state *state)
 		}
 	}
 }
+EXPORT_SYMBOL(drm_atomic_helper_commit_encoder_bridge_disable);
 
-static void
-crtc_disable(struct drm_device *dev, struct drm_atomic_state *state)
+/**
+ * drm_atomic_helper_commit_crtc_disable - disable CRTSs
+ * @dev: DRM device
+ * @state: the driver state object
+ *
+ * Loops over all CRTCs in the current state and if the CRTC needs
+ * it, disables it.
+ */
+void
+drm_atomic_helper_commit_crtc_disable(struct drm_device *dev, struct drm_atomic_state *state)
 {
 	struct drm_crtc *crtc;
 	struct drm_crtc_state *old_crtc_state, *new_crtc_state;
@@ -1282,9 +1301,18 @@ crtc_disable(struct drm_device *dev, struct drm_atomic_state *state)
 			drm_crtc_vblank_put(crtc);
 	}
 }
+EXPORT_SYMBOL(drm_atomic_helper_commit_crtc_disable);
 
-static void
-encoder_bridge_post_disable(struct drm_device *dev, struct drm_atomic_state *state)
+/**
+ * drm_atomic_helper_commit_encoder_bridge_post_disable - post-disable encoder bridges
+ * @dev: DRM device
+ * @state: the driver state object
+ *
+ * Loops over all connectors in the current state and if the CRTC needs
+ * it, post-disables all encoder bridges.
+ */
+void
+drm_atomic_helper_commit_encoder_bridge_post_disable(struct drm_device *dev, struct drm_atomic_state *state)
 {
 	struct drm_connector *connector;
 	struct drm_connector_state *old_conn_state, *new_conn_state;
@@ -1335,15 +1363,16 @@ encoder_bridge_post_disable(struct drm_device *dev, struct drm_atomic_state *sta
 		drm_bridge_put(bridge);
 	}
 }
+EXPORT_SYMBOL(drm_atomic_helper_commit_encoder_bridge_post_disable);
 
 static void
 disable_outputs(struct drm_device *dev, struct drm_atomic_state *state)
 {
-	encoder_bridge_disable(dev, state);
+	drm_atomic_helper_commit_encoder_bridge_disable(dev, state);
 
-	encoder_bridge_post_disable(dev, state);
+	drm_atomic_helper_commit_encoder_bridge_post_disable(dev, state);
 
-	crtc_disable(dev, state);
+	drm_atomic_helper_commit_crtc_disable(dev, state);
 }
 
 /**
@@ -1446,8 +1475,17 @@ void drm_atomic_helper_calc_timestamping_constants(struct drm_atomic_state *stat
 }
 EXPORT_SYMBOL(drm_atomic_helper_calc_timestamping_constants);
 
-static void
-crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *state)
+/**
+ * drm_atomic_helper_commit_crtc_set_mode - set the new mode
+ * @dev: DRM device
+ * @state: the driver state object
+ *
+ * Loops over all connectors in the current state and if the mode has
+ * changed, change the mode of the CRTC, then call down the bridge
+ * chain and change the mode in all bridges as well.
+ */
+void
+drm_atomic_helper_commit_crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *state)
 {
 	struct drm_crtc *crtc;
 	struct drm_crtc_state *new_crtc_state;
@@ -1508,6 +1546,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *state)
 		drm_bridge_put(bridge);
 	}
 }
+EXPORT_SYMBOL(drm_atomic_helper_commit_crtc_set_mode);
 
 /**
  * drm_atomic_helper_commit_modeset_disables - modeset commit to disable outputs
@@ -1531,12 +1570,21 @@ void drm_atomic_helper_commit_modeset_disables(struct drm_device *dev,
 	drm_atomic_helper_update_legacy_modeset_state(dev, state);
 	drm_atomic_helper_calc_timestamping_constants(state);
 
-	crtc_set_mode(dev, state);
+	drm_atomic_helper_commit_crtc_set_mode(dev, state);
 }
 EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_disables);
 
-static void drm_atomic_helper_commit_writebacks(struct drm_device *dev,
-						struct drm_atomic_state *state)
+/**
+ * drm_atomic_helper_commit_writebacks - issue writebacks
+ * @dev: DRM device
+ * @state: atomic state object being committed
+ *
+ * This loops over the connectors, checks if the new state requires
+ * a writeback job to be issued and in that case issues an atomic
+ * commit on each connector.
+ */
+void drm_atomic_helper_commit_writebacks(struct drm_device *dev,
+					 struct drm_atomic_state *state)
 {
 	struct drm_connector *connector;
 	struct drm_connector_state *new_conn_state;
@@ -1555,9 +1603,18 @@ static void drm_atomic_helper_commit_writebacks(struct drm_device *dev,
 		}
 	}
 }
+EXPORT_SYMBOL(drm_atomic_helper_commit_writebacks);
 
-static void
-encoder_bridge_pre_enable(struct drm_device *dev, struct drm_atomic_state *state)
+/**
+ * drm_atomic_helper_commit_encoder_bridge_pre_enable - pre-enable bridges
+ * @dev: DRM device
+ * @state: atomic state object being committed
+ *
+ * This loops over the connectors and if the CRTC needs it, pre-enables
+ * the entire bridge chain.
+ */
+void
+drm_atomic_helper_commit_encoder_bridge_pre_enable(struct drm_device *dev, struct drm_atomic_state *state)
 {
 	struct drm_connector *connector;
 	struct drm_connector_state *new_conn_state;
@@ -1588,9 +1645,18 @@ encoder_bridge_pre_enable(struct drm_device *dev, struct drm_atomic_state *state
 		drm_bridge_put(bridge);
 	}
 }
+EXPORT_SYMBOL(drm_atomic_helper_commit_encoder_bridge_pre_enable);
 
-static void
-crtc_enable(struct drm_device *dev, struct drm_atomic_state *state)
+/**
+ * drm_atomic_helper_commit_crtc_enable - enables the CRTCs
+ * @dev: DRM device
+ * @state: atomic state object being committed
+ *
+ * This loops over CRTCs in the new state, and of the CRTC needs
+ * it, enables it.
+ */
+void
+drm_atomic_helper_commit_crtc_enable(struct drm_device *dev, struct drm_atomic_state *state)
 {
 	struct drm_crtc *crtc;
 	struct drm_crtc_state *old_crtc_state;
@@ -1619,9 +1685,18 @@ crtc_enable(struct drm_device *dev, struct drm_atomic_state *state)
 		}
 	}
 }
+EXPORT_SYMBOL(drm_atomic_helper_commit_crtc_enable);
 
-static void
-encoder_bridge_enable(struct drm_device *dev, struct drm_atomic_state *state)
+/**
+ * drm_atomic_helper_commit_encoder_bridge_enable - enables the bridges
+ * @dev: DRM device
+ * @state: atomic state object being committed
+ *
+ * This loops over all connectors in the new state, and of the CRTC needs
+ * it, enables the entire bridge chain.
+ */
+void
+drm_atomic_helper_commit_encoder_bridge_enable(struct drm_device *dev, struct drm_atomic_state *state)
 {
 	struct drm_connector *connector;
 	struct drm_connector_state *new_conn_state;
@@ -1664,6 +1739,7 @@ encoder_bridge_enable(struct drm_device *dev, struct drm_atomic_state *state)
 		drm_bridge_put(bridge);
 	}
 }
+EXPORT_SYMBOL(drm_atomic_helper_commit_encoder_bridge_enable);
 
 /**
  * drm_atomic_helper_commit_modeset_enables - modeset commit to enable outputs
@@ -1682,11 +1758,11 @@ encoder_bridge_enable(struct drm_device *dev, struct drm_atomic_state *state)
 void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
 					      struct drm_atomic_state *state)
 {
-	crtc_enable(dev, state);
+	drm_atomic_helper_commit_crtc_enable(dev, state);
 
-	encoder_bridge_pre_enable(dev, state);
+	drm_atomic_helper_commit_encoder_bridge_pre_enable(dev, state);
 
-	encoder_bridge_enable(dev, state);
+	drm_atomic_helper_commit_encoder_bridge_enable(dev, state);
 
 	drm_atomic_helper_commit_writebacks(dev, state);
 }
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index 53382fe93537..e154ee4f0696 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -60,6 +60,12 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state,
 int drm_atomic_helper_check_planes(struct drm_device *dev,
 			       struct drm_atomic_state *state);
 int drm_atomic_helper_check_crtc_primary_plane(struct drm_crtc_state *crtc_state);
+void drm_atomic_helper_commit_encoder_bridge_disable(struct drm_device *dev,
+						     struct drm_atomic_state *state);
+void drm_atomic_helper_commit_crtc_disable(struct drm_device *dev,
+					   struct drm_atomic_state *state);
+void drm_atomic_helper_commit_encoder_bridge_post_disable(struct drm_device *dev,
+							  struct drm_atomic_state *state);
 int drm_atomic_helper_check(struct drm_device *dev,
 			    struct drm_atomic_state *state);
 void drm_atomic_helper_commit_tail(struct drm_atomic_state *state);
@@ -89,8 +95,24 @@ drm_atomic_helper_update_legacy_modeset_state(struct drm_device *dev,
 void
 drm_atomic_helper_calc_timestamping_constants(struct drm_atomic_state *state);
 
+void drm_atomic_helper_commit_crtc_set_mode(struct drm_device *dev,
+					    struct drm_atomic_state *state);
+
 void drm_atomic_helper_commit_modeset_disables(struct drm_device *dev,
 					       struct drm_atomic_state *state);
+
+void drm_atomic_helper_commit_writebacks(struct drm_device *dev,
+					 struct drm_atomic_state *state);
+
+void drm_atomic_helper_commit_encoder_bridge_pre_enable(struct drm_device *dev,
+							struct drm_atomic_state *state);
+
+void drm_atomic_helper_commit_crtc_enable(struct drm_device *dev,
+					  struct drm_atomic_state *state);
+
+void drm_atomic_helper_commit_encoder_bridge_enable(struct drm_device *dev,
+						    struct drm_atomic_state *state);
+
 void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
 					  struct drm_atomic_state *old_state);
 

-- 
2.43.0



From tomi.valkeinen at ideasonboard.com  Fri Dec  5 01:51:51 2025
From: tomi.valkeinen at ideasonboard.com (Tomi Valkeinen)
Date: Fri, 05 Dec 2025 11:51:51 +0200
Subject: [PATCH 4/4] drm/tidss: Fix enable/disable order
In-Reply-To: <20251205-drm-seq-fix-v1-0-fda68fa1b3de@ideasonboard.com>
References: <20251205-drm-seq-fix-v1-0-fda68fa1b3de@ideasonboard.com>
Message-ID: <20251205-drm-seq-fix-v1-4-fda68fa1b3de@ideasonboard.com>

TI's OLDI and DSI encoders need to be set up before the crtc is enabled,
but the DRM helpers will enable the crtc first. This causes various
issues on TI platforms, like visual artifacts or crtc sync lost
warnings.

Thus drm_atomic_helper_commit_modeset_enables() and
drm_atomic_helper_commit_modeset_disables() cannot be used, as they
enable the crtc before bridges' pre-enable, and disable the crtc after
bridges' post-disable.

Open code the drm_atomic_helper_commit_modeset_enables() and
drm_atomic_helper_commit_modeset_disables(), and first call the bridges'
pre-enables, then crtc enable, then bridges' post-enable (and vice versa
for disable).

Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
Cc: stable at vger.kernel.org # v6.17+
---
 drivers/gpu/drm/tidss/tidss_kms.c | 30 +++++++++++++++++++++++++++---
 1 file changed, 27 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/tidss/tidss_kms.c b/drivers/gpu/drm/tidss/tidss_kms.c
index 86eb5d97410b..8bb93194e5ac 100644
--- a/drivers/gpu/drm/tidss/tidss_kms.c
+++ b/drivers/gpu/drm/tidss/tidss_kms.c
@@ -26,9 +26,33 @@ static void tidss_atomic_commit_tail(struct drm_atomic_state *old_state)
 
 	tidss_runtime_get(tidss);
 
-	drm_atomic_helper_commit_modeset_disables(ddev, old_state);
-	drm_atomic_helper_commit_planes(ddev, old_state, DRM_PLANE_COMMIT_ACTIVE_ONLY);
-	drm_atomic_helper_commit_modeset_enables(ddev, old_state);
+	/*
+	 * TI's OLDI and DSI encoders need to be set up before the crtc is
+	 * enabled. Thus drm_atomic_helper_commit_modeset_enables() and
+	 * drm_atomic_helper_commit_modeset_disables() cannot be used here, as
+	 * they enable the crtc before bridges' pre-enable, and disable the crtc
+	 * after bridges' post-disable.
+	 *
+	 * Open code the functions here and first call the bridges' pre-enables,
+	 * then crtc enable, then bridges' post-enable (and vice versa for
+	 * disable).
+	 */
+
+	drm_atomic_helper_commit_encoder_bridge_disable(ddev, old_state);
+	drm_atomic_helper_commit_crtc_disable(ddev, old_state);
+	drm_atomic_helper_commit_encoder_bridge_post_disable(ddev, old_state);
+
+	drm_atomic_helper_update_legacy_modeset_state(ddev, old_state);
+	drm_atomic_helper_calc_timestamping_constants(old_state);
+	drm_atomic_helper_commit_crtc_set_mode(ddev, old_state);
+
+	drm_atomic_helper_commit_planes(ddev, old_state,
+					DRM_PLANE_COMMIT_ACTIVE_ONLY);
+
+	drm_atomic_helper_commit_encoder_bridge_pre_enable(ddev, old_state);
+	drm_atomic_helper_commit_crtc_enable(ddev, old_state);
+	drm_atomic_helper_commit_encoder_bridge_enable(ddev, old_state);
+	drm_atomic_helper_commit_writebacks(ddev, old_state);
 
 	drm_atomic_helper_commit_hw_done(old_state);
 	drm_atomic_helper_wait_for_flip_done(ddev, old_state);

-- 
2.43.0



From jacky_chou at aspeedtech.com  Fri Dec  5 01:53:14 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Fri, 5 Dec 2025 17:53:14 +0800
Subject: [PATCH net-next v5 0/4] Add AST2600 RGMII delay into ftgmac100
Message-ID: <20251205-rgmii_delay_2600-v5-0-bd2820ad3da7@aspeedtech.com>

This patch series adds support for configuring RGMII internal delays for the
Aspeed AST2600 FTGMAC100 Ethernet MACs. It introduces new compatible strings to
distinguish between MAC0/1 and MAC2/3, as their delay chains and configuration
units differ.
The device tree bindings are updated to restrict the allowed phy-mode and delay
properties for each MAC type. Corresponding changes are made to the device tree
source files and the FTGMAC100 driver to support the new delay configuration.

This enables precise RGMII timing configuration for AST2600-based platforms,
improving interoperability with various PHYs

Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
---
Changes in v5:
- Remove the new property, "aspeed,rgmii-delay-ps" from yaml and driver
- Add aspeed,scu to aspeed-g6 dtsi back
- Determine delay value from bootloader and tx/rx-internal-delay-ps to
  configure RGMII delay value with phy-mode
- Add a helper for AST2600 to get phy driver handle
- Link to v4: https://lore.kernel.org/r/20251110-rgmii_delay_2600-v4-0-5cad32c766f7 at aspeedtech.com

Changes in v4:
- Remove the compatible "aspeed,ast2600-mac01" and
  "aspeed,ast2600-mac23"
- Add new property to specify the RGMII delay step for each MACs
- Add default value of rx/tx-internal-delay-ps
- For legacy dts, a warning message reminds users to update phy-mode
- If lack rx/tx-internal-delay-ps, driver will use default value to
  configure the RGMII delay
- Link to v3: https://lore.kernel.org/r/20251103-rgmii_delay_2600-v3-0-e2af2656f7d7 at aspeedtech.com

Changes in v3:
- Add new item on compatible property for new compatible strings
- Remove the new compatible and scu handle of MAC from aspeed-g6.dtsi
- Add new compatible and scu handle to MAC node in
  aspeed-ast2600-evb.dts
- Change all phy-mode of MACs to "rgmii-id"
- Keep "aspeed,ast2600-mac" compatible in ftgmac100.c and configure the
  rgmii delay with "aspeed,ast2600-mac01" and "aspeed,ast2600-mac23"
- Link to v2: https://lore.kernel.org/r/20250813063301.338851-1-jacky_chou at aspeedtech.com

Changes in v2:
- added new compatible strings for MAC0/1 and MAC2/3
- updated device tree bindings to restrict phy-mode and delay properties
- refactored driver code to handle rgmii delay configuration
- Link to v1: https://lore.kernel.org/r/20250317025922.1526937-1-jacky_chou at aspeedtech.com

---
Jacky Chou (4):
      dt-bindings: net: ftgmac100: Add delay properties for AST2600
      ARM: dts: aspeed-g6: add aspeed,scu property for MAC
      net: ftgmac100: Add RGMII delay support for AST2600
      ARM: dts: aspeed: ast2600-evb: Configure RGMII delay for MAC

 .../devicetree/bindings/net/faraday,ftgmac100.yaml |  27 ++
 arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts    |  20 +-
 arch/arm/boot/dts/aspeed/aspeed-g6.dtsi            |   4 +
 drivers/net/ethernet/faraday/ftgmac100.c           | 288 ++++++++++++++++++++-
 drivers/net/ethernet/faraday/ftgmac100.h           |  25 ++
 5 files changed, 358 insertions(+), 6 deletions(-)
---
base-commit: 8f7aa3d3c7323f4ca2768a9e74ebbe359c4f8f88
change-id: 20251031-rgmii_delay_2600-a00b0248c7e6

Best regards,
-- 
Jacky Chou <jacky_chou at aspeedtech.com>



From jacky_chou at aspeedtech.com  Fri Dec  5 01:53:15 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Fri, 5 Dec 2025 17:53:15 +0800
Subject: [PATCH net-next v5 1/4] dt-bindings: net: ftgmac100: Add delay
 properties for AST2600
In-Reply-To: <20251205-rgmii_delay_2600-v5-0-bd2820ad3da7@aspeedtech.com>
References: <20251205-rgmii_delay_2600-v5-0-bd2820ad3da7@aspeedtech.com>
Message-ID: <20251205-rgmii_delay_2600-v5-1-bd2820ad3da7@aspeedtech.com>

The AST2600 contains two dies, each with its own MAC, and these MACs
require different delay configurations.
Previously, these delay values were configured during the bootloader
stage rather than in the driver. This change introduces the use of the
standard properties defined in ethernet-controller.yaml to configure
the delay values directly in the driver.

Each Aspeed platform has its own delay step value. And for Aspeed platform,
the total steps of RGMII delay configuraion is 32 steps, so the total delay
is delay-step-ps * 32.
Default delay values are declared so that tx-internal-delay-ps and
rx-internal-delay-ps become optional. If these properties are not present,
the driver will use the default values instead.
Add conditional schema constraints for Aspeed AST2600 MAC controllers:
- For MAC0/1, per delay step for rgmii is 45 ps
- For MAC2/3, per delay step for rgmii is 250 ps
- Both require the "aspeed,scu" and "aspeed,rgmii-delay-ps" properties.
Other compatible values remain unrestricted.

Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
---
 .../devicetree/bindings/net/faraday,ftgmac100.yaml | 27 ++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/Documentation/devicetree/bindings/net/faraday,ftgmac100.yaml b/Documentation/devicetree/bindings/net/faraday,ftgmac100.yaml
index d14410018bcf..00f7a0e56106 100644
--- a/Documentation/devicetree/bindings/net/faraday,ftgmac100.yaml
+++ b/Documentation/devicetree/bindings/net/faraday,ftgmac100.yaml
@@ -69,6 +69,30 @@ properties:
   mdio:
     $ref: /schemas/net/mdio.yaml#
 
+  aspeed,scu:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      Phandle to the SCU (System Control Unit) syscon node for Aspeed platform.
+      This reference is used by the MAC controller to configure the RGMII delays.
+
+  rx-internal-delay-ps:
+    description:
+      RGMII Receive Clock Delay defined in pico seconds. There are 32
+      steps of RGMII delay for Aspeed platform. Each Aspeed platform has its
+      own delay step value, it is fixed by hardware design. Total delay is
+      calculated by delay-step * 32. A value of 0 ps will disable any
+      delay. The Default is no delay.
+    default: 0
+
+  tx-internal-delay-ps:
+    description:
+      RGMII Transmit Clock Delay defined in pico seconds. There are 32
+      steps of RGMII delay for Aspeed platform. Each Aspeed platform has its
+      own delay step value, it is fixed by hardware design. Total delay is
+      calculated by delay-step * 32. A value of 0 ps will disable any
+      delay. The Default is no delay.
+    default: 0
+
 required:
   - compatible
   - reg
@@ -85,6 +109,9 @@ allOf:
     then:
       properties:
         resets: true
+        aspeed,scu: true
+        rx-internal-delay-ps: true
+        tx-internal-delay-ps: true
     else:
       properties:
         resets: false

-- 
2.34.1



From jacky_chou at aspeedtech.com  Fri Dec  5 01:53:16 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Fri, 5 Dec 2025 17:53:16 +0800
Subject: [PATCH net-next v5 2/4] ARM: dts: aspeed-g6: add aspeed,scu
 property for MAC
In-Reply-To: <20251205-rgmii_delay_2600-v5-0-bd2820ad3da7@aspeedtech.com>
References: <20251205-rgmii_delay_2600-v5-0-bd2820ad3da7@aspeedtech.com>
Message-ID: <20251205-rgmii_delay_2600-v5-2-bd2820ad3da7@aspeedtech.com>

Add aspeed,scu property to let MAC driver to configure RGMII delay with
scu register.

Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
---
 arch/arm/boot/dts/aspeed/aspeed-g6.dtsi | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
index f8662c8ac089..d85b3be63107 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
+++ b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
@@ -236,6 +236,7 @@ mac0: ethernet at 1e660000 {
 			reg = <0x1e660000 0x180>;
 			interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>;
+			aspeed,scu = <&syscon>;
 			status = "disabled";
 		};
 
@@ -244,6 +245,7 @@ mac1: ethernet at 1e680000 {
 			reg = <0x1e680000 0x180>;
 			interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&syscon ASPEED_CLK_GATE_MAC2CLK>;
+			aspeed,scu = <&syscon>;
 			status = "disabled";
 		};
 
@@ -252,6 +254,7 @@ mac2: ethernet at 1e670000 {
 			reg = <0x1e670000 0x180>;
 			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&syscon ASPEED_CLK_GATE_MAC3CLK>;
+			aspeed,scu = <&syscon>;
 			status = "disabled";
 		};
 
@@ -260,6 +263,7 @@ mac3: ethernet at 1e690000 {
 			reg = <0x1e690000 0x180>;
 			interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&syscon ASPEED_CLK_GATE_MAC4CLK>;
+			aspeed,scu = <&syscon>;
 			status = "disabled";
 		};
 

-- 
2.34.1



From jacky_chou at aspeedtech.com  Fri Dec  5 01:53:17 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Fri, 5 Dec 2025 17:53:17 +0800
Subject: [PATCH net-next v5 3/4] net: ftgmac100: Add RGMII delay support
 for AST2600
In-Reply-To: <20251205-rgmii_delay_2600-v5-0-bd2820ad3da7@aspeedtech.com>
References: <20251205-rgmii_delay_2600-v5-0-bd2820ad3da7@aspeedtech.com>
Message-ID: <20251205-rgmii_delay_2600-v5-3-bd2820ad3da7@aspeedtech.com>

On the AST2600 platform, the RGMII delay is controlled via the
SCU registers. The delay chain configuration differs between MAC0/1
and MAC2/3, even though all four MACs use a 32-stage delay chain.
+------+----------+-----------+-------------+-------------+
|      |Delay Unit|Delay Stage|TX Edge Stage|RX Edge Stage|
+------+----------+-----------+-------------+-------------+
|MAC0/1|     45 ps|        32 |           0 |           0 |
+------+----------+-----------+-------------+-------------+
|MAC2/3|    250 ps|        32 |           0 |          26 |
+------+----------+-----------+-------------+-------------+
For MAC2/3, the "no delay" condition starts from stage 26.
Setting the RX delay stage to 26 means that no additional RX
delay is applied.
Here lists the RX delay setting of MAC2/3 below.
26 -> 0   ns, 27 -> 0.25 ns, ... , 31 -> 1.25 ns,
0  -> 1.5 ns, 1  -> 1.75 ns, ... , 25 -> 7.75 ns

Therefore, we calculate the delay stage from the
rx-internal-delay-ps of MAC2/3 to add 26. If the stage is equel
to or bigger than 32, the delay stage will be mask 0x1f to get
the correct setting.
The delay chain is like a ring for configuration.
Example for the rx-internal-delay-ps of MAC2/3 is 2000 ps,
we will get the delay stage is 2.

Strating to this patch, driver will remind the legacy dts to update the
"phy-mode" to "rgmii-id, and if necessary, add small
"rx-internal-delay-ps" and "tx-internal-delay-ps.
If lack the two properties, driver will accord to the original delay
value from bootloader to disable RGMII delay and to change the phy
interface to phy driver.

Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
---
 drivers/net/ethernet/faraday/ftgmac100.c | 288 ++++++++++++++++++++++++++++++-
 drivers/net/ethernet/faraday/ftgmac100.h |  25 +++
 2 files changed, 311 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c
index a863f7841210..bf92dc0b7260 100644
--- a/drivers/net/ethernet/faraday/ftgmac100.c
+++ b/drivers/net/ethernet/faraday/ftgmac100.c
@@ -26,6 +26,9 @@
 #include <linux/if_vlan.h>
 #include <linux/of_net.h>
 #include <linux/phy_fixed.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/bitfield.h>
 #include <net/ip.h>
 #include <net/ncsi.h>
 
@@ -1833,12 +1836,281 @@ static bool ftgmac100_has_child_node(struct device_node *np, const char *name)
 	return ret;
 }
 
+static int ftgmac100_get_ast2600_rgmii_flag(u32 delay)
+{
+	if ((delay > 500 && delay < 1500) ||
+	    (delay > 2500 && delay < 7500))
+		return AST2600_RGMII_KEEP_DELAY;
+
+	return AST2600_RGMII_DIS_DELAY;
+}
+
+static int ftgmac100_check_ast2600_rgmii_delay(struct regmap *scu,
+					       u32 delay_unit,
+					       int mac_id, int dly_reg)
+{
+	u32 delay_value;
+	u32 tx_delay;
+	u32 rx_delay;
+	int tx_flag;
+	int rx_flag;
+
+	regmap_read(scu, dly_reg, &delay_value);
+	if (mac_id == 0 || mac_id == 2) {
+		tx_delay = FIELD_GET(ASPEED_MAC0_2_TX_DLY, delay_value);
+		rx_delay = FIELD_GET(ASPEED_MAC0_2_RX_DLY, delay_value);
+	} else {
+		tx_delay = FIELD_GET(ASPEED_MAC1_3_TX_DLY, delay_value);
+		rx_delay = FIELD_GET(ASPEED_MAC1_3_RX_DLY, delay_value);
+	}
+
+	/* Due to the hardware design reason, for MAC2/3 on AST2600,
+	 * the zero delay ns on RX is configured by setting value 0x1a.
+	 * List as below:
+	 * 0x1a, 0x1b, ... , 0x1f, 0x00, 0x01, ... , 0x19
+	 * Covert for calculation purpose.
+	 * 0x00, 0x01, ... , 0x19, 0x1a, 0x1b, ... , 0x1f
+	 */
+	if (mac_id == 2 || mac_id == 3)
+		rx_delay = (rx_delay + 0x06) & 0x1f;
+
+	tx_delay *= delay_unit;
+	rx_delay *= delay_unit;
+
+	tx_flag = ftgmac100_get_ast2600_rgmii_flag(tx_delay);
+	rx_flag = ftgmac100_get_ast2600_rgmii_flag(rx_delay);
+
+	if (tx_flag == AST2600_RGMII_KEEP_DELAY ||
+	    rx_flag == AST2600_RGMII_KEEP_DELAY) {
+		return AST2600_RGMII_KEEP_DELAY;
+	}
+
+	return AST2600_RGMII_DIS_DELAY;
+}
+
+static int ftgmac100_set_ast2600_rgmii_delay(struct ftgmac100 *priv,
+					     s32 rgmii_tx_delay,
+					     s32 rgmii_rx_delay,
+					     phy_interface_t *phy_intf)
+{
+	struct device *dev = priv->dev;
+	struct device_node *np;
+	u32 rgmii_delay_unit;
+	u32 rx_delay_index;
+	u32 tx_delay_index;
+	struct regmap *scu;
+	int dly_mask;
+	int dly_reg;
+	int mac_id;
+
+	np = dev->of_node;
+
+	scu = syscon_regmap_lookup_by_phandle(np, "aspeed,scu");
+	if (IS_ERR(scu)) {
+		dev_err(dev, "failed to get aspeed,scu");
+		return PTR_ERR(scu);
+	}
+
+	/* According to the register base address to specify the corresponding
+	 * values.
+	 */
+	switch (priv->res->start) {
+	case AST2600_MAC0_BASE_ADDR:
+		mac_id = 0;
+		rgmii_delay_unit = AST2600_MAC01_CLK_DLY_UNIT;
+		dly_reg = AST2600_MAC01_CLK_DLY;
+		break;
+	case AST2600_MAC1_BASE_ADDR:
+		mac_id = 1;
+		rgmii_delay_unit = AST2600_MAC01_CLK_DLY_UNIT;
+		dly_reg = AST2600_MAC01_CLK_DLY;
+		break;
+	case AST2600_MAC2_BASE_ADDR:
+		mac_id = 2;
+		rgmii_delay_unit = AST2600_MAC23_CLK_DLY_UNIT;
+		dly_reg = AST2600_MAC23_CLK_DLY;
+		break;
+	case AST2600_MAC3_BASE_ADDR:
+		mac_id = 3;
+		rgmii_delay_unit = AST2600_MAC23_CLK_DLY_UNIT;
+		dly_reg = AST2600_MAC23_CLK_DLY;
+		break;
+	default:
+		dev_err(dev, "Invalid mac base address");
+		return -EINVAL;
+	}
+
+	if (of_phy_is_fixed_link(np)) {
+		if (rgmii_tx_delay < 0 || rgmii_rx_delay < 0) {
+			dev_err(dev,
+				"Add rx/tx-internal-delay-ps for fixed-link\n");
+			/* Keep original RGMII delay value*/
+			return 0;
+		}
+
+		/* Must have both of rx/tx-internal-delay-ps for fixed-link */
+		goto conf_delay;
+	}
+
+	if (*phy_intf == PHY_INTERFACE_MODE_RGMII_RXID ||
+	    *phy_intf == PHY_INTERFACE_MODE_RGMII_TXID)
+		goto out_warn;
+
+	if (*phy_intf != PHY_INTERFACE_MODE_RGMII &&
+	    *phy_intf != PHY_INTERFACE_MODE_RGMII_ID)
+		return 0;
+
+	/* Both rx/tx-internal-delay-ps are not existed. */
+	if (rgmii_tx_delay < 0 && rgmii_rx_delay < 0) {
+		int flag;
+
+		flag = ftgmac100_check_ast2600_rgmii_delay(scu,
+							   rgmii_delay_unit,
+							   mac_id,
+							   dly_reg);
+		if (flag == AST2600_RGMII_KEEP_DELAY)
+			goto out_warn;
+
+		if (*phy_intf == PHY_INTERFACE_MODE_RGMII) {
+			dev_err(dev, "Update phy-mode to 'rgmii-id'\n");
+			/* Forced phy interface to RGMII_ID and MAC will disable
+			 * RGMII delay.
+			 */
+			*phy_intf = PHY_INTERFACE_MODE_RGMII_ID;
+		}
+	} else {
+		/* Please refer to ethernet-controller.yaml. */
+		if (*phy_intf == PHY_INTERFACE_MODE_RGMII &&
+		    (rgmii_tx_delay == 2000 || rgmii_rx_delay == 2000)) {
+			dev_warn(dev,
+				 "RX/TX delay cannot set to 2000 on 'rgmii'\n");
+			return -EINVAL;
+		}
+	}
+
+	/* The value is negative, which means the rx/tx-internal-delay-ps
+	 * property is not existed in dts. Therefore, set to default 0.
+	 */
+	if (rgmii_tx_delay < 0)
+		rgmii_tx_delay = 0;
+	if (rgmii_rx_delay < 0)
+		rgmii_rx_delay = 0;
+
+conf_delay:
+	tx_delay_index = DIV_ROUND_CLOSEST(rgmii_tx_delay, rgmii_delay_unit);
+	if (tx_delay_index >= 32) {
+		dev_err(dev, "The %u ps of TX delay is out of range\n",
+			rgmii_tx_delay);
+		return -EINVAL;
+	}
+
+	rx_delay_index = DIV_ROUND_CLOSEST(rgmii_rx_delay, rgmii_delay_unit);
+	if (rx_delay_index >= 32) {
+		dev_err(dev, "The %u ps of RX delay is out of range\n",
+			rgmii_rx_delay);
+		return -EINVAL;
+	}
+
+	/* Due to the hardware design reason, for MAC2/3 on AST2600, the zero
+	 * delay ns on RX is configured by setting value 0x1a.
+	 * List as below:
+	 * 0x1a -> 0   ns, 0x1b -> 0.25 ns, ... , 0x1f -> 1.25 ns,
+	 * 0x00 -> 1.5 ns, 0x01 -> 1.75 ns, ... , 0x19 -> 7.75 ns, 0x1a -> 0 ns
+	 */
+	if (mac_id == 2 || mac_id == 3)
+		rx_delay_index = (AST2600_MAC23_RX_DLY_0_NS + rx_delay_index) &
+				 AST2600_MAC_TX_RX_DLY_MASK;
+
+	if (mac_id == 0 || mac_id == 2) {
+		dly_mask = ASPEED_MAC0_2_TX_DLY | ASPEED_MAC0_2_RX_DLY;
+		tx_delay_index = FIELD_PREP(ASPEED_MAC0_2_TX_DLY, tx_delay_index);
+		rx_delay_index = FIELD_PREP(ASPEED_MAC0_2_RX_DLY, rx_delay_index);
+	} else {
+		dly_mask = ASPEED_MAC1_3_TX_DLY | ASPEED_MAC1_3_RX_DLY;
+		tx_delay_index = FIELD_PREP(ASPEED_MAC1_3_TX_DLY, tx_delay_index);
+		rx_delay_index = FIELD_PREP(ASPEED_MAC1_3_RX_DLY, rx_delay_index);
+	}
+
+	regmap_update_bits(scu, dly_reg, dly_mask, tx_delay_index | rx_delay_index);
+
+	return 0;
+
+out_warn:
+	/* Print the warning message. Keep the phy-mode and the RGMII delay value. */
+	dev_warn(dev, "Update phy-mode to 'rgmii-id' and add rx/tx-internal-delay-ps\n");
+
+	return 0;
+}
+
+static int ftgmac100_set_internal_delay(struct ftgmac100 *priv,
+					phy_interface_t *phy_intf)
+{
+	struct device_node *np = priv->dev->of_node;
+	s32 rgmii_tx_delay;
+	s32 rgmii_rx_delay;
+	int err;
+
+	err = of_get_phy_mode(np, phy_intf);
+	if (err) {
+		dev_err(priv->dev, "Failed to get phy mode: %d\n", err);
+		return err;
+	}
+
+	if (!(of_device_is_compatible(np, "aspeed,ast2600-mac")))
+		return 0;
+
+	/* AST2600 needs to know if the "tx/rx-internal-delay-ps" properties
+	 * are existed in dts. If not existed, set -1 and delay is equal to 0.
+	 */
+	if (of_property_read_u32(np, "tx-internal-delay-ps", &rgmii_tx_delay))
+		rgmii_tx_delay = -1;
+	if (of_property_read_u32(np, "rx-internal-delay-ps", &rgmii_rx_delay))
+		rgmii_rx_delay = -1;
+
+	err = ftgmac100_set_ast2600_rgmii_delay(priv,
+						rgmii_tx_delay,
+						rgmii_rx_delay,
+						phy_intf);
+
+	return err;
+}
+
+static struct phy_device *ftgmac100_ast2600_phy_get(struct net_device *dev,
+						    struct device_node *np,
+						    void (*hndlr)(struct net_device *),
+						    phy_interface_t phy_intf)
+{
+	struct device_node *phy_np;
+	struct phy_device *phy;
+	int ret;
+
+	if (of_phy_is_fixed_link(np)) {
+		ret = of_phy_register_fixed_link(np);
+		if (ret < 0) {
+			netdev_err(dev, "broken fixed-link specification\n");
+			return NULL;
+		}
+		phy_np = of_node_get(np);
+	} else {
+		phy_np = of_parse_phandle(np, "phy-handle", 0);
+		if (!phy_np)
+			return NULL;
+	}
+
+	phy = of_phy_connect(dev, phy_np, hndlr, 0, phy_intf);
+
+	of_node_put(phy_np);
+
+	return phy;
+}
+
 static int ftgmac100_probe(struct platform_device *pdev)
 {
 	struct resource *res;
 	int irq;
 	struct net_device *netdev;
 	struct phy_device *phydev;
+	phy_interface_t phy_intf;
 	struct ftgmac100 *priv;
 	struct device_node *np;
 	int err = 0;
@@ -1907,6 +2179,10 @@ static int ftgmac100_probe(struct platform_device *pdev)
 		priv->rxdes0_edorr_mask = BIT(30);
 		priv->txdes0_edotr_mask = BIT(30);
 		priv->is_aspeed = true;
+		/* Configure RGMII delay if there are the corresponding compatibles */
+		err = ftgmac100_set_internal_delay(priv, &phy_intf);
+		if (err)
+			goto err_phy_connect;
 	} else {
 		priv->rxdes0_edorr_mask = BIT(15);
 		priv->txdes0_edotr_mask = BIT(15);
@@ -1955,8 +2231,16 @@ static int ftgmac100_probe(struct platform_device *pdev)
 				goto err_setup_mdio;
 		}
 
-		phy = of_phy_get_and_connect(priv->netdev, np,
-					     &ftgmac100_adjust_link);
+		/* Because AST2600 will use the RGMII delay to determine
+		 * which phy interface to use.
+		 */
+		if (of_device_is_compatible(np, "aspeed,ast2600-mac"))
+			phy = ftgmac100_ast2600_phy_get(priv->netdev, np,
+							&ftgmac100_adjust_link,
+							phy_intf);
+		else
+			phy = of_phy_get_and_connect(priv->netdev, np,
+						     &ftgmac100_adjust_link);
 		if (!phy) {
 			dev_err(&pdev->dev, "Failed to connect to phy\n");
 			err = -EINVAL;
diff --git a/drivers/net/ethernet/faraday/ftgmac100.h b/drivers/net/ethernet/faraday/ftgmac100.h
index 4968f6f0bdbc..1b2f79a104ea 100644
--- a/drivers/net/ethernet/faraday/ftgmac100.h
+++ b/drivers/net/ethernet/faraday/ftgmac100.h
@@ -271,4 +271,29 @@ struct ftgmac100_rxdes {
 #define FTGMAC100_RXDES1_UDP_CHKSUM_ERR	(1 << 26)
 #define FTGMAC100_RXDES1_IP_CHKSUM_ERR	(1 << 27)
 
+/* Aspeed SCU */
+#define AST2600_MAC01_CLK_DLY	0x340
+#define AST2600_MAC23_CLK_DLY	0x350
+#define AST2600_MAC01_CLK_DLY_UNIT	45	/* ps */
+#define AST2600_MAC01_TX_DLY_0_NS	0
+#define AST2600_MAC01_RX_DLY_0_NS	0
+#define AST2600_MAC23_CLK_DLY_UNIT	250	/* ps */
+#define AST2600_MAC23_TX_DLY_0_NS	0
+#define AST2600_MAC23_RX_DLY_0_NS	0x1a
+#define AST2600_MAC_TX_RX_DLY_MASK	0x1f
+#define ASPEED_MAC0_2_TX_DLY		GENMASK(5, 0)
+#define ASPEED_MAC0_2_RX_DLY		GENMASK(17, 12)
+#define ASPEED_MAC1_3_TX_DLY		GENMASK(11, 6)
+#define ASPEED_MAC1_3_RX_DLY		GENMASK(23, 18)
+
+#define AST2600_MAC0_BASE_ADDR		0x1e660000
+#define AST2600_MAC1_BASE_ADDR		0x1e680000
+#define AST2600_MAC2_BASE_ADDR		0x1e670000
+#define AST2600_MAC3_BASE_ADDR		0x1e690000
+
+/* Keep original delay */
+#define AST2600_RGMII_KEEP_DELAY	0x01
+/* Need to disable delay on MAC side */
+#define AST2600_RGMII_DIS_DELAY		0x02
+
 #endif /* __FTGMAC100_H */

-- 
2.34.1



From jacky_chou at aspeedtech.com  Fri Dec  5 01:53:18 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Fri, 5 Dec 2025 17:53:18 +0800
Subject: [PATCH net-next v5 4/4] ARM: dts: aspeed: ast2600-evb: Configure
 RGMII delay for MAC
In-Reply-To: <20251205-rgmii_delay_2600-v5-0-bd2820ad3da7@aspeedtech.com>
References: <20251205-rgmii_delay_2600-v5-0-bd2820ad3da7@aspeedtech.com>
Message-ID: <20251205-rgmii_delay_2600-v5-4-bd2820ad3da7@aspeedtech.com>

This change sets the rx-internal-delay-ps and tx-internal-delay-ps
properties to control the RGMII signal delay.
The phy-mode for MAC0?MAC3 is updated to "rgmii-id" to enable TX/RX
internal delay on the PHY and disable the corresponding delay
on the MAC.

Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
---
 arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts b/arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts
index de83c0eb1d6e..f8f0d5c98514 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts
+++ b/arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts
@@ -123,42 +123,54 @@ ethphy3: ethernet-phy at 0 {
 &mac0 {
 	status = "okay";
 
-	phy-mode = "rgmii-rxid";
+	phy-mode = "rgmii-id";
 	phy-handle = <&ethphy0>;
 
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_rgmii1_default>;
+
+	rx-internal-delay-ps = <0>;
+	tx-internal-delay-ps = <0>;
 };
 
 
 &mac1 {
 	status = "okay";
 
-	phy-mode = "rgmii-rxid";
+	phy-mode = "rgmii-id";
 	phy-handle = <&ethphy1>;
 
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_rgmii2_default>;
+
+	rx-internal-delay-ps = <0>;
+	tx-internal-delay-ps = <0>;
 };
 
 &mac2 {
 	status = "okay";
 
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	phy-handle = <&ethphy2>;
 
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_rgmii3_default>;
+
+	rx-internal-delay-ps = <0>;
+	tx-internal-delay-ps = <0>;
 };
 
 &mac3 {
 	status = "okay";
 
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	phy-handle = <&ethphy3>;
 
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_rgmii4_default>;
+
+	rx-internal-delay-ps = <0>;
+	tx-internal-delay-ps = <0>;
 };
 
 &emmc_controller {

-- 
2.34.1



From sudeep.holla at arm.com  Fri Dec  5 01:54:58 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Fri, 5 Dec 2025 09:54:58 +0000
Subject: [PATCH 1/2] dt-bindings: firmware: arm,scmi: Document
 arm,poll-transport property
In-Reply-To: <e25c690c-e74d-4641-a97e-8eae81a59168@mailbox.org>
References: <5ae0a793-d3e7-45d1-bf5c-3c46593d1824@mailbox.org>
 <aRW7BZimWdpq4TyX@pluto>
 <20251202-evasive-neon-rhino-d2745e@sudeepholla>
 <66257fcf-9024-454f-b776-4ba584963ebe@mailbox.org>
 <aS82GSN8c2SnRn4S@bogus>
 <8d773671-5e2e-4e21-ade6-2bf9a3b75066@mailbox.org>
 <20251203-thick-didactic-cockatoo-deaa1d@sudeepholla>
 <4ccbcffd-bcc7-478b-a525-a4a11e3092ee@mailbox.org>
 <20251204-calm-peacock-of-fantasy-6b8cbe@sudeepholla>
 <e25c690c-e74d-4641-a97e-8eae81a59168@mailbox.org>
Message-ID: <20251205-winged-quizzical-pigeon-ed692d@sudeepholla>

On Thu, Dec 04, 2025 at 07:59:20PM +0100, Marek Vasut wrote:
> On 12/4/25 1:33 PM, Sudeep Holla wrote:
> 
> Hello Sudeep,
> 
> > > Wouldn't such a setup use separate mailbox channels, therefore even if
> > > mailbox driver calls mbox_chan_received_data(), it would be called for a
> > > specific mailbox channel , and it won't interfere with the SCMI mailbox
> > > channel.
> > > 
> > 
> > Ideally yes. Because PCC uses shared interrupts and provides no mechanism to
> > identify the channel that raised the interrupt, we must run the handler for
> > every registered channel. This behaviour is specific to PCC; other controllers
> > that support interrupt source detection may not need to do this. But SCMI
> > must work with any mailbox or other transports.
> 
> It seems the pcc_mbox_irq() operates per-channel, so it seems even the PCC
> can demux channels for each IRQ and does trigger mbox_chan_received_data()
> for correct channel ?
> 
> What exactly happens on the PCC mailbox driver with this polling mode
> enabled ?
> 
> > > > Also IIUC, the irq request happens
> > > > as part of channel startup and there are no explicit APIs for the mbox client
> > > > driver to control that. SCMI is mbox client in this case.
> > > 
> > > Sure, but the mailbox driver has to make sure it is correctly demuxing the
> > > IRQs it handles and correctly sends received_data notifications to the right
> > > channel(s) .
> > > 
> > 
> > Agreed, but the concern is that if SCMI is forced to use polling when the
> > channel is opened, and IRQs are enabled by default with no way for SCMI to
> > disable them in polling mode, we could run into issues.
> 
> This constellation seems odd -- if the channel can do IRQs, then this
> property should not be present in DT.
> 

Yes, but there is no way to validate or check this and that is the root
cause for all my worries.

> > I realise it?s a very
> > specific corner case, but every time I?ve assumed such scenarios wouldn?t
> > occur, we eventually ended up encountering them. So sorry if I am very
> > pedantic, but I prefer to start smaller and restrictive and expand if and
> > when necessary or required only.
> 
> I don't think this case, where mailbox channel does IRQs and polling is
> enabled, can/should even be considered valid. Either the channel does not do
> IRQs and then it should do polling, or it does IRQs and then it should use
> IRQs, but not both.
> 

Yes ideally, but having loose ends like this binding which allows someone
to add it to their DT complicates though it is invalid. We have no way to
detect and I don't want to work around such configs in the future.

> > > > > > I am aware of systems that implement such sharing, which is why I prefer to be
> > > > > > explicit that this type of design is challenging to support within this
> > > > > > binding. The intent is to support only minimal, constrained cases - essentially
> > > > > > systems that are already somewhat broken. I do not see value in broadening the
> > > > > > binding to cover every conceivable scenario.
> > > > > > 
> > > > > > > > Clearly defining these constraints would be helpful. It may also be useful to
> > > > > > > > note that this is primarily intended for mailbox transports, if that?s
> > > > > > > > accurate. Alternatively, we could keep the DT binding definition broader but
> > > > > > > > emit warnings when a transport other than mailbox is used. That approach might
> > > > > > > > make it easier to move forward.
> > > > > > > 
> > > > > > > DEN0056F refers to this polling mode in Shared memory based transports, that
> > > > > > > can be other than mailbox transports, it includes e.g. SMC or OPTEE
> > > > > > > transports.
> > > > > > > 
> > > > > > 
> > > > > > However, polling does not make sense in the context of SMC. Once control
> > > > > > returns from an SMC call, the command has completed. What form of polling in
> > > > > > an SMC workflow do you have in mind?
> > > > > 
> > > > > I think the polling happens on the SHMEM and the SMC transport is capable of
> > > > > that too, see :
> > > > > 
> > > > > drivers/firmware/arm_scmi/transports/smc.c
> > > > > 
> > > > > 175         /*
> > > > > 176          * If there is an interrupt named "a2p", then the service and
> > > > > 177          * completion of a message is signaled by an interrupt rather
> > > > > than by
> > > > > 178          * the return of the SMC call.
> > > > > 179          */
> > > > > 180         scmi_info->irq = of_irq_get_byname(cdev->of_node, "a2p");
> > > > > 
> > > > 
> > > > Ah this one, is actually implemented to avoid sort of implicit polling
> > > > mode we get with any SMC/HVC. I don't know how the platform deals with it
> > > > but SMC/HVC is synchronous and doesn't need this polling. The irq introduced
> > > > here is again a sort of workaround to get some sort of async/non-polling
> > > > mode with SMC/HVC. So, to repeat polling mode make absolutely no sense
> > > > whatsoever for SMC/OPTEE(based on pure SMC) transports.
> > > 
> > > I can drop the SMC part from this patch if you think that's helpful ?
> > > 
> > 
> > Yes, that?s essential, because polling in an SMC context is meaningless in my
> > opinion.
> 
> Maybe the "a2p" IRQ is also used for notifications from longer running
> operations ?
> 

Yes, it is some sort of work around some platforms implemented as by design
when the SMC returns, the synchronous commands must complete and it is had
to support async SCMI commands without platform specific interrupt(p2a). This
a2p is sort of completion interrupt for synchronous command. I assume the
platform may offload the task from secure f/w to something else otherwise
secure side needs to be given CPU cycles to complete which complicates this.
In short SMC is synchronous and if the execution returns from it in NS world,
the command is complete.

> [...]
> 
> > > > Yes it can be minimalistic but not restrictive. As I already clearly mentioned
> > > > I don't see it makes any sense to enable this for SMC/OPTEE. Lets start with
> > > > just mailbox to start with and extend to other transports if and when needed.
> > > > It would be good to impose that restriction in the binding as well but that
> > > > is not a must IMO. I am fine if the bindings for whatever reasons(though I
> > > > don't see the need) to apply for any transport.
> > > So I should simply drop the smc.c changes , keep the rest, and send V2 ?
> > 
> > Not just that. Unless DT maintainers oppose, I just want to keep this
> > new property valid only for mailbox transport(i.e. "arm,scmi" compatible
> > not otherwise) so that we can catch any other use in binding checks and
> > interested parties must discuss on the list and expand that if they require.
> > 
> > Also we can explore if we can parse and scan this in mailbox transport for
> > now.
> I feel that this only adds more implementation complexity and makes the
> solution less generic, while it does win us very little in the end ? The
> generic solution implementation is actually easier to implement.

Yes I want it less generic to start with. Why you want to start making
this workaround on your platform a generic implementation just because
the specification has provision for it ?

-- 
Regards,
Sudeep


From m.szyprowski at samsung.com  Fri Dec  5 01:55:20 2025
From: m.szyprowski at samsung.com (Marek Szyprowski)
Date: Fri, 5 Dec 2025 10:55:20 +0100
Subject: [PATCH v7 0/6] Add module support for Arm64 Exynos MCT driver
In-Reply-To: <20251205011027.720512-1-willmcvicker@google.com>
References: <CGME20251205011037eucas1p2bfaec27d78550b53099ebb0ca8713b2f@eucas1p2.samsung.com>
	<20251205011027.720512-1-willmcvicker@google.com>
Message-ID: <b81adc49-6e8a-49a6-9377-acd304ccfbc4@samsung.com>

On 05.12.2025 02:10, Will McVicker wrote:
> This series adds support to build the Arm64 Exynos MCT driver as a module.
> This is only possible on Arm64 SoCs since they can use the Arm architected
> timer as the clocksource. Once the Exynos MCT module is loaded and the device
> probes, the MCT is used as the wakeup source for the arch_timer to ensure the
> device can wakeup from the "c2" idle state.
>
> These patches are originally from the downstream Pixel 6 (gs101) kernel found
> at [1] and have been adapted for upstream. Not only has the Exynos MCT driver
> been shipping as a module in the field with Android, but I've also tested this
> series with the upstream kernel on my Pixel 6 Pro.
>
> To the driver changes (both as built-in and as module) on Pixel 6 Pro, I ran
> these tests:
>
> # cat /proc/interrupts | grep -E "mct|arch_timer"
>   23:       6823      10938       7795       5607       8935      12828      21947       2200    GICv3  30 Level     arch_timer
> 104:          1          0          0          0          0          0          0          0    GICv3 785 Level     mct_comp_irq
> 105:        547          0          0          0          0          0          0          0    GICv3 789 Level     mct_tick0
> 106:          0       1333          0          0          0          0          0          0    GICv3 790 Level     mct_tick1
> 107:          0          0       1467          0          0          0          0          0    GICv3 791 Level     mct_tick2
> 108:          0          0          0        583          0          0          0          0    GICv3 792 Level     mct_tick3
> 109:          0          0          0          0        206          0          0          0    GICv3 793 Level     mct_tick4
> 110:          0          0          0          0          0        153          0          0    GICv3 794 Level     mct_tick5
> 111:          0          0          0          0          0          0         13          0    GICv3 795 Level     mct_tick6
> 112:          0          0          0          0          0          0          0         87    GICv3 796 Level     mct_tick7
>
> # cat /sys/devices/system/clocksource/clocksource0/current_clocksource
> arch_sys_counter
>
> When built and loaded as a module, you can verify via:
>
> # lsmod | grep exynos_mct
> exynos_mct             20480  9
>
> I also compile tested for ARCH=ARM DEFCONFIG=multi_v7_defconfig with the
> following debug configs to ensure the section mismatches are fixed:
>    CONFIG_DEBUG_SECTION_MISMATCH=y
>    # CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
>
> Any additional testing is much appreciated!
>
> Thanks,
> Will
>
> Note1, instructions to build and flash a Pixel 6 device with the upstream
> kernel can be found at [2].
>
> Note2, this series is based off of krzk/for-next commit bca42080637c (Merge
> branch 'next/drivers-late' into for-next).
>
> [1] https://android.googlesource.com/kernel/gs/+log/refs/heads/android-gs-raviole-5.10-android12-d1
> [2] https://gitlab.com/LinaroLtd/googlelt/pixelscripts/-/blob/clo/main/README.md?ref_type=heads
>
> Cc: Alim Akhtar <alim.akhtar at samsung.com>
> Cc: Daniel Lezcano <daniel.lezcano at linaro.org>
> Cc: Donghoon Yu <hoony.yu at samsung.com>
> Cc: Rob Herring <robh at kernel.org>
> Cc: John Stultz <jstultz at google.com>
> Cc: Thomas Gleixner <tglx at linutronix.de>
> Cc: Youngmin Nam <youngmin.nam at samsung.com>
> Cc: Peter Griffin <peter.griffin at linaro.org>
> Cc: Tudor Ambarus <tudor.ambarus at linaro.org>
> Cc: Andr? Draszik <andre.draszik at linaro.org>
> Cc: Will Deacon <will at kernel.org>
> Cc: Conor Dooley <conor+dt at kernel.org>
> Cc: Krzysztof Kozlowski <krzk at kernel.org>
> Cc: Marek Szyprowski <m.szyprowski at samsung.com>
> Cc: "Russell King (Oracle)" <linux at armlinux.org.uk>
> Cc: linux-samsung-soc at vger.kernel.org
> Cc: kernel-team at android.com
> Cc: linux-arm-kernel at lists.infradead.org
> Cc: linux-kernel at vger.kernel.org

Works fine on ARM Exynos 32bit based boards.

Tested-by: Marek Szyprowski <m.szyprowski at samsung.com>


> ---
>
> Changes in v7:
> - Dropped v6 patch 1/6 that removed __init from register_current_timer_delay()
> - Refactored the init function in patch 4/7 to handle the case of registering
>    the timer delay function for ARM 32-bit systems from an __init tagged function.
>    This addresses the original section mismatch issues reported in v4.
> - Rebased series onto base commit bca42080637c (Merge branch
>    'next/drivers-late' into for-next).
>
> Changes in v6:
> - Updated module support to only register the MCT driver as a platform driver
>    for ARM64 to ensure ARM 32-bit SoCs continue to probe the MCT driver very
>    early.
> - Squashed the percpu fix suggested by Marek Szyprowski in
>    https://lore.kernel.org/all/20250827102645.1964659-1-m.szyprowski at samsung.com/
>    together with patch 3/6.
>
> Changes in v5:
> - Fixed section mismatch issues.
> - Addressed Arnd's concerns regarding potential issues with unloading and/or
>    unbinding the driver.
> - Fixed SoB concerns to clarify the development chain from AOSP to Linux.
> - Pulled in https://lore.kernel.org/all/20250827102645.1964659-1-m.szyprowski at samsung.com/
>    to limit percpu interrupts only for ARM64.
>
> Changes in v4:
> - Missed the "v3" string in the previous series for the actual patches
> - Re-generated patches with --base a15edf91668beefdb5171c53fa698c9b43dd1e0d
>    for kernel test robot.
>
> Changes in v3:
> - Rebased on top of Daniel's timer modularization prep series [3] and
>    krzk/for-next commit a15edf91668b ("Merge branch 'next/dt64' into
>    for-next")
> - Added owner references to Exynos MCT clocksource and clockevent objects.
> - Dropped #ifdef MODULE conditional section in favor of just using
>    module_platform_driver() which will properly handle setting up the
>    of_device_id table based on if the driver is built-in or a module.
> - Update commit message for patch 2 based on John's feedback.
> - Dropped DT change from v2 as it was picked up by Krzysztof for CPU Idle.
>
> Changes in v2:
> - Re-worked patch v1 5 based on Rob Herring's review to use the compatible
>    data for retrieving the mct_init function pointer.
> - Updated the Kconfig logic to disallow building the Exynos MCT driver as
>    a module for ARM32 configurations based on Krzysztof Kozlowski's findings.
> - Added comments and clarified commit messages in patches 1 and 2 based on
>    reviews from John Stultz and Youngmin Nam.
> - Fixed an issue found during testing that resulted in the device getting
>    stuck on boot. This is included in v2 as patch 5.
> - Collected *-by tags
> - Rebased to the latest linux-next/master.
> ---
>
> Donghoon Yu (1):
>    clocksource/drivers/exynos_mct: Don't register as a sched_clock on
>      arm64
>
> Hosung Kim (1):
>    clocksource/drivers/exynos_mct: Set percpu local timer interrupts for
>      ARM64
>
> Will McVicker (4):
>    clocksource/drivers/exynos_mct: Fix uninitialized irq name warning
>    clocksource/drivers/exynos_mct: Refactor driver init
>    clocksource/drivers/exynos_mct: Add module support for ARM64
>    arm64: exynos: Drop select CLKSRC_EXYNOS_MCT
>
>   arch/arm64/Kconfig.platforms     |   1 -
>   drivers/clocksource/Kconfig      |   3 +-
>   drivers/clocksource/exynos_mct.c | 255 ++++++++++++++++++++++---------
>   3 files changed, 182 insertions(+), 77 deletions(-)
>
>
> base-commit: bca42080637ce3a21092fc0f7d5411e853b0c3b3

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland



From richard.genoud at bootlin.com  Fri Dec  5 02:02:35 2025
From: richard.genoud at bootlin.com (Richard Genoud)
Date: Fri,  5 Dec 2025 11:02:35 +0100
Subject: [PATCH 0/4] Introduce Allwinner H616 PWM controller
Message-ID: <20251205100239.1563353-1-richard.genoud@bootlin.com>

Allwinner H616 PWM controller is quite different from the A10 one.

It can drive 6 PWM channels, and like for the A10, each channel has a
bypass that permits to output a clock, bypassing the PWM logic, when
enabled.

But, the channels are paired 2 by 2, sharing a first set of
MUX/prescaler/gate.
Then, for each channel, there's another prescaler (that will be bypassed
if the bypass is enabled for this channel).

It looks like that:
            _____      ______      ________
OSC24M --->|     |    |      |    |        |
APB1 ----->| Mux |--->| Gate |--->| /div_m |-----> PWM_clock_src_xy
           |_____|    |______|    |________|
                          ________
                         |        |
                      +->| /div_k |---> PWM_clock_x
                      |  |________|
                      |    ______
                      |   |      |
                      +-->| Gate |----> PWM_bypass_clock_x
                      |   |______|
PWM_clock_src_xy -----+   ________
                      |  |        |
                      +->| /div_k |---> PWM_clock_y
                      |  |________|
                      |    ______
                      |   |      |
                      +-->| Gate |----> PWM_bypass_clock_y
                          |______|

Where xy can be 0/1, 2/3, 4/5

PWM_clock_x/y serve for the PWM purpose.
PWM_bypass_clock_x/y serve for the clock-provider purpose.
The common clock framework has been used to manage those clocks.

This PWM driver serves as a clock-provider for PWM_bypass_clocks.
This is needed for example by the embedded AC300 PHY which clock comes
from PMW5 pin (PB12).

This series is based onto next-20251205

Richard Genoud (4):
  dt-bindings: pwm: sunxi: add PWM controller for Allwinner H616
  pwm: sun50i: Add H616 PWM support
  arm64: dts: allwinner: h616: add PWM controller
  MAINTAINERS: Add entry on Allwinner H616 PWM driver

 .../pwm/allwinner,sun50i-h616-pwm.yaml        |  67 ++
 MAINTAINERS                                   |   6 +
 .../arm64/boot/dts/allwinner/sun50i-h616.dtsi |  47 +
 drivers/pwm/Kconfig                           |  12 +
 drivers/pwm/Makefile                          |   1 +
 drivers/pwm/pwm-sun50i-h616.c                 | 874 ++++++++++++++++++
 6 files changed, 1007 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pwm/allwinner,sun50i-h616-pwm.yaml
 create mode 100644 drivers/pwm/pwm-sun50i-h616.c


base-commit: 6987d58a9cbc5bd57c983baa514474a86c945d56
-- 
2.47.3



From richard.genoud at bootlin.com  Fri Dec  5 02:02:36 2025
From: richard.genoud at bootlin.com (Richard Genoud)
Date: Fri,  5 Dec 2025 11:02:36 +0100
Subject: [PATCH 1/4] dt-bindings: pwm: sunxi: add PWM controller for Allwinner H616
In-Reply-To: <20251205100239.1563353-1-richard.genoud@bootlin.com>
References: <20251205100239.1563353-1-richard.genoud@bootlin.com>
Message-ID: <20251205100239.1563353-2-richard.genoud@bootlin.com>

Allwinner H616 SoC contains a PWM controller quite different from the A10.
It has 6 channels than can generate PWM waveforms or clocks if bypass is
enabled.

Signed-off-by: Richard Genoud <richard.genoud at bootlin.com>
---
 .../pwm/allwinner,sun50i-h616-pwm.yaml        | 67 +++++++++++++++++++
 1 file changed, 67 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pwm/allwinner,sun50i-h616-pwm.yaml

diff --git a/Documentation/devicetree/bindings/pwm/allwinner,sun50i-h616-pwm.yaml b/Documentation/devicetree/bindings/pwm/allwinner,sun50i-h616-pwm.yaml
new file mode 100644
index 000000000000..b89735ad3a43
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/allwinner,sun50i-h616-pwm.yaml
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pwm/allwinner,sun50i-h616-pwm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner H616 PWM
+
+maintainers:
+  - Richard Genoud <richard.genoud at bootlin.com>
+
+description: |
+  Allwinner H616 PWM can generate standard PWM signals with variable pulse width
+  and period.
+  Also, instead of a PWM signal, a channel can be used to provide a clock.
+
+properties:
+  compatible:
+    const: allwinner,sun50i-h616-pwm
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: Bus Clock
+
+  clock-names:
+    items:
+      - const: bus
+
+  resets:
+    maxItems: 1
+
+  "#clock-cells":
+    const: 1
+
+  "#pwm-cells":
+    const: 3
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - resets
+
+allOf:
+  - $ref: pwm.yaml#
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/sun50i-h616-ccu.h>
+    #include <dt-bindings/reset/sun50i-h616-ccu.h>
+
+    pwm at 300a000 {
+      compatible = "allwinner,sun50i-h616-pwm";
+      reg = <0x0300a000 0x400>;
+      clocks = <&ccu CLK_BUS_PWM>;
+      clock-names = "bus";
+      resets = <&ccu RST_BUS_PWM>;
+      #pwm-cells = <3>;
+      #clock-cells = <1>;
+    };
+...
-- 
2.47.3



From richard.genoud at bootlin.com  Fri Dec  5 02:02:37 2025
From: richard.genoud at bootlin.com (Richard Genoud)
Date: Fri,  5 Dec 2025 11:02:37 +0100
Subject: [PATCH 2/4] pwm: sun50i: Add H616 PWM support
In-Reply-To: <20251205100239.1563353-1-richard.genoud@bootlin.com>
References: <20251205100239.1563353-1-richard.genoud@bootlin.com>
Message-ID: <20251205100239.1563353-3-richard.genoud@bootlin.com>

Add driver for Allwinner H616 PWM controller, supporting up to 6
channels.
Those channels output can be either a PWM signal output or a clock
output, thanks to the bypass.

The channels are paired (0/1, 2/3 and 4/5) and each pair has a
prescaler/mux/gate.
Moreover, each channel has its own prescaler and bypass.

Signed-off-by: Richard Genoud <richard.genoud at bootlin.com>
---
 drivers/pwm/Kconfig           |  12 +
 drivers/pwm/Makefile          |   1 +
 drivers/pwm/pwm-sun50i-h616.c | 874 ++++++++++++++++++++++++++++++++++
 3 files changed, 887 insertions(+)
 create mode 100644 drivers/pwm/pwm-sun50i-h616.c

diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index bf2d101f67a1..1f724e1cf992 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -736,6 +736,18 @@ config PWM_SUN4I
 	  To compile this driver as a module, choose M here: the module
 	  will be called pwm-sun4i.
 
+config PWM_SUN50I_H616
+	tristate "Allwinner H616 PWM support"
+	depends on ARCH_SUNXI || COMPILE_TEST
+	depends on HAS_IOMEM && COMMON_CLK
+	help
+	  Generic PWM framework driver for Allwinner H616 SoCs.
+	  It supports generic PWM, but can also provides a plain clock.
+	  The AC300 PHY integrated in H616 SoC needs such a clock.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called pwm-h616.
+
 config PWM_SUNPLUS
 	tristate "Sunplus PWM support"
 	depends on ARCH_SUNPLUS || COMPILE_TEST
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 0dc0d2b69025..a16ae9eef9e5 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_PWM_STM32)		+= pwm-stm32.o
 obj-$(CONFIG_PWM_STM32_LP)	+= pwm-stm32-lp.o
 obj-$(CONFIG_PWM_STMPE)		+= pwm-stmpe.o
 obj-$(CONFIG_PWM_SUN4I)		+= pwm-sun4i.o
+obj-$(CONFIG_PWM_SUN50I_H616)	+= pwm-sun50i-h616.o
 obj-$(CONFIG_PWM_SUNPLUS)	+= pwm-sunplus.o
 obj-$(CONFIG_PWM_TEGRA)		+= pwm-tegra.o
 obj-$(CONFIG_PWM_TH1520)	+= pwm_th1520.o
diff --git a/drivers/pwm/pwm-sun50i-h616.c b/drivers/pwm/pwm-sun50i-h616.c
new file mode 100644
index 000000000000..82b4a30d34f1
--- /dev/null
+++ b/drivers/pwm/pwm-sun50i-h616.c
@@ -0,0 +1,874 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for Allwinner H616 Pulse Width Modulation Controller
+ *
+ * (C) Copyright 2025 Richard Genoud, Bootlin <richard.genoud at bootlin.com>
+ *
+ * Based on drivers/pwm/pwm-sun4i.c with Copyright:
+ *
+ * Copyright (C) 2014 Alexandre Belloni <alexandre.belloni at bootlin.com>
+ *
+ * Limitations:
+ * - When outputing the source clock directly, the PWM logic is bypassed and the
+ *   currently running period is not guaranteed to be completed.
+ * - As the channels are paired (0/1, 2/3, 4/5), they share the same clock
+ *   source and prescaler(div_m), but they also have their own prescaler(div_k)
+ *   and bypass.
+ *
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/reset.h>
+
+#ifndef UINT32_MAX
+#define UINT32_MAX 0xffffffffU
+#endif
+
+/* PWM IRQ Enable Register */
+#define PWM_IER				0x0
+
+/* PWM IRQ Status Register */
+#define PWM_ISR				0x4
+
+/* PWM Capture IRQ Enable Register */
+#define PWM_CIER			0x10
+
+/* PWM Capture IRQ Status Register */
+#define PWM_CISR			0x14
+
+/* PWMCC Pairs Clock Configuration Registers */
+#define PWM_XY_CLK_CR(pair)		(0x20 + ((pair) * 0x4))
+#define PWM_XY_CLK_CR_SRC_SHIFT		7
+#define PWM_XY_CLK_CR_SRC_MASK		1
+#define PWM_XY_CLK_CR_GATE_BIT		4
+#define PWM_XY_CLK_CR_BYPASS_BIT(chan)	((chan) % 2 + 5)
+#define PWM_XY_CLK_CR_DIV_M_SHIFT	0
+
+/* PWMCC Pairs Dead Zone Control Registers */
+#define PWM_XY_DZ(pair)			(0x30 + ((pair) * 0x4))
+
+/* PWM Enable Register */
+#define PWM_ENR				0x40
+#define PWM_ENABLE(x)			BIT(x)
+
+/* PWM Capture Enable Register */
+#define PWM_CER				0x44
+
+/* PWM Control Register */
+#define PWM_CTRL_REG(chan)		(0x60 + (chan) * 0x20)
+#define PWM_CTRL_PRESCAL_K_SHIFT	0
+#define PWM_CTRL_PRESCAL_K_WIDTH	8
+#define PWM_CTRL_ACTIVE_STATE		BIT(8)
+
+/* PWM Period Register */
+#define PWM_PERIOD_REG(ch)		(0x64 + (ch) * 0x20)
+#define PWM_PERIOD_MASK			GENMASK(31, 16)
+#define PWM_DUTY_MASK			GENMASK(15, 0)
+#define PWM_REG_PERIOD(reg)		(FIELD_GET(PWM_PERIOD_MASK, reg) + 1)
+#define PWM_REG_DUTY(reg)		FIELD_GET(PWM_DUTY_MASK, reg)
+#define PWM_PERIOD(prd)			FIELD_PREP(PWM_PERIOD_MASK, (prd) - 1)
+#define PWM_DUTY(dty)			FIELD_PREP(PWM_DUTY_MASK, dty)
+#define PWM_PERIOD_MAX			FIELD_MAX(PWM_PERIOD_MASK)
+
+
+/* PWM Count Register */
+#define PWM_CNT_REG(x)			(0x68 + (x) * 0x20)
+
+/* PWM Capture Control Register */
+#define PWM_CCR(x)			(0x6c + (x) * 0x20)
+
+/* PWM Capture Rise Lock Register */
+#define PWM_CRLR(x)			(0x70 + (x) * 0x20)
+
+/* PWM Capture Fall Lock Register */
+#define PWM_CFLR(x)			(0x74 + (x) * 0x20)
+
+#define PWM_PAIR_IDX(chan)		((chan) >> 2)
+
+/*
+ * Block diagram of the PWM clock controller:
+ *
+ *             _____      ______      ________
+ * OSC24M --->|     |    |      |    |        |
+ * APB1 ----->| Mux |--->| Gate |--->| /div_m |-----> PWM_clock_src_xy
+ *            |_____|    |______|    |________|
+ *                           ________
+ *                          |        |
+ *                       +->| /div_k |---> PWM_clock_x
+ *                       |  |________|
+ *                       |    ______
+ *                       |   |      |
+ *                       +-->| Gate |----> PWM_bypass_clock_x
+ *                       |   |______|
+ * PWM_clock_src_xy -----+   ________
+ *                       |  |        |
+ *                       +->| /div_k |---> PWM_clock_y
+ *                       |  |________|
+ *                       |    ______
+ *                       |   |      |
+ *                       +-->| Gate |----> PWM_bypass_clock_y
+ *                           |______|
+ *
+ * NB: when the bypass is set, all the PWM logic is bypassed.
+ * So, the duty cycle and polarity can't be modified (we just have a clock).
+ * The bypass in PWM mode is used to achieve a 1/2 duty cycle with the fastest
+ * clock.
+ *
+ * PWM_clock_x/y serve for the PWM purpose.
+ * PWM_bypass_clock_x/y serve for the clock-provider purpose.
+ *
+ */
+
+/*
+ * Table used for /div_m (diviser before obtaining PWM_clock_src_xy)
+ * It's actually CLK_DIVIDER_POWER_OF_TWO, but limited to /256
+ */
+static const struct clk_div_table clk_table_div_m[] = {
+	{ .val = 0, .div = 1, },
+	{ .val = 1, .div = 2, },
+	{ .val = 2, .div = 4, },
+	{ .val = 3, .div = 8, },
+	{ .val = 4, .div = 16, },
+	{ .val = 5, .div = 32, },
+	{ .val = 6, .div = 64, },
+	{ .val = 7, .div = 128, },
+	{ .val = 8, .div = 256, },
+	{ .val = 0, .div = 0, }, /* last entry */
+};
+
+#define PWM_XY_SRC_GATE(_pair, _reg)			\
+struct clk_gate gate_xy_##_pair = {			\
+	.reg = (void *)_reg,				\
+	.bit_idx = PWM_XY_CLK_CR_GATE_BIT,		\
+	.hw.init = &(struct clk_init_data){		\
+		.ops =  &clk_gate_ops,			\
+	}						\
+}
+
+#define PWM_XY_SRC_MUX(_pair, _reg)			\
+struct clk_mux mux_xy_##_pair = {			\
+	.reg = (void *)_reg,				\
+	.shift = PWM_XY_CLK_CR_SRC_SHIFT,		\
+	.mask = PWM_XY_CLK_CR_SRC_MASK,			\
+	.flags = CLK_MUX_ROUND_CLOSEST,			\
+	.hw.init = &(struct clk_init_data){		\
+		.ops =  &clk_mux_ops,			\
+	}						\
+}
+
+#define PWM_XY_SRC_DIV(_pair, _reg)			\
+struct clk_divider rate_xy_##_pair = {			\
+	.reg = (void *)_reg,				\
+	.shift = PWM_XY_CLK_CR_DIV_M_SHIFT,		\
+	.table = clk_table_div_m,			\
+	.hw.init = &(struct clk_init_data){		\
+		.ops =  &clk_divider_ops,		\
+	}						\
+}
+
+#define PWM_X_DIV(_idx, _reg)				\
+struct clk_divider rate_x_##_idx = {			\
+	.reg = (void *)_reg,				\
+	.shift = PWM_CTRL_PRESCAL_K_SHIFT,		\
+	.width = PWM_CTRL_PRESCAL_K_WIDTH,		\
+	.hw.init = &(struct clk_init_data){		\
+		.ops =  &clk_divider_ops,		\
+	}						\
+}
+
+#define PWM_X_BYPASS_GATE(_idx)				\
+struct clk_gate gate_x_bypass_##_idx = {		\
+	.reg = (void *)PWM_ENR,				\
+	.bit_idx = _idx,				\
+	.hw.init = &(struct clk_init_data){		\
+		.ops =  &clk_gate_ops,			\
+	}						\
+}
+
+#define PWM_XY_CLK_SRC(_pair, _reg)			\
+	static PWM_XY_SRC_MUX(_pair, _reg);		\
+	static PWM_XY_SRC_GATE(_pair, _reg);		\
+	static PWM_XY_SRC_DIV(_pair, _reg)
+
+#define PWM_X_CLK(_idx)					\
+	static PWM_X_DIV(_idx, PWM_CTRL_REG(_idx))
+
+#define PWM_X_BYPASS_CLK(_idx)						\
+	PWM_X_BYPASS_GATE(_idx)
+
+#define REF_CLK_XY_SRC(_pair)						\
+	{								\
+		.name = "pwm-clk-src" #_pair,				\
+		.parent_names = (const char *[]){ "osc24M", "apb1" },	\
+		.num_parents = 2,					\
+		.mux_hw = &mux_xy_##_pair.hw,				\
+		.gate_hw = &gate_xy_##_pair.hw,				\
+		.rate_hw = &rate_xy_##_pair.hw,				\
+	}
+
+#define REF_CLK_X(_idx, _pair)						\
+	{								\
+		.name = "pwm-clk" #_idx,				\
+		.parent_names = (const char *[]){ "pwm-clk-src" #_pair }, \
+		.num_parents = 1,					\
+		.rate_hw = &rate_x_##_idx.hw,				\
+		.flags = CLK_SET_RATE_PARENT,				\
+	}
+
+#define REF_CLK_BYPASS(_idx, _pair)					\
+	{								\
+		.name = "pwm-clk-bypass" #_idx,				\
+		.parent_names = (const char *[]){ "pwm-clk-src" #_pair }, \
+		.num_parents = 1,					\
+		.gate_hw = &gate_x_bypass_##_idx.hw,			\
+		.flags = CLK_SET_RATE_PARENT,	\
+	}
+
+/*
+ * PWM_clock_src_xy generation:
+ *             _____      ______      ________
+ * OSC24M --->|     |    |      |    |        |
+ * APB1 ----->| Mux |--->| Gate |--->| /div_m |-----> PWM_clock_src_xy
+ *            |_____|    |______|    |________|
+ */
+PWM_XY_CLK_SRC(01, PWM_XY_CLK_CR(0));
+PWM_XY_CLK_SRC(23, PWM_XY_CLK_CR(1));
+PWM_XY_CLK_SRC(45, PWM_XY_CLK_CR(2));
+
+/*
+ * PWM_clock_x_div generation:
+ *                       ________
+ *                      |        | PWM_clock_x/y
+ * PWM_clock_src_xy --->| /div_k |--------------->
+ *                      |________|
+ */
+PWM_X_CLK(0);
+PWM_X_CLK(1);
+PWM_X_CLK(2);
+PWM_X_CLK(3);
+PWM_X_CLK(4);
+PWM_X_CLK(5);
+
+/*
+ * PWM_bypass_clock_xy generation:
+ *                        ______
+ *                       |      |
+ * PWM_clock_src_xy ---->| Gate |-------> PWM_bypass_clock_x
+ *                       |______|
+ *
+ * The gate is actually PWM_ENR register.
+ */
+PWM_X_BYPASS_CLK(0);
+PWM_X_BYPASS_CLK(1);
+PWM_X_BYPASS_CLK(2);
+PWM_X_BYPASS_CLK(3);
+PWM_X_BYPASS_CLK(4);
+PWM_X_BYPASS_CLK(5);
+
+struct clk_pwm_data {
+	const char *name;
+	const char * const *parent_names;
+	int num_parents;
+	struct clk_hw *mux_hw;
+	struct clk_hw *rate_hw;
+	struct clk_hw *gate_hw;
+	unsigned long flags;
+};
+
+#define CLK_BYPASS(h616chip, ch) ((h616chip)->data->npwm + (ch))
+#define CLK_XY_SRC_IDX(h616chip, ch) ((h616chip)->data->npwm * 2 + ((ch) >> 1))
+static struct clk_pwm_data pwmcc_data[] = {
+	REF_CLK_X(0, 01),
+	REF_CLK_X(1, 01),
+	REF_CLK_X(2, 23),
+	REF_CLK_X(3, 23),
+	REF_CLK_X(4, 45),
+	REF_CLK_X(5, 45),
+	REF_CLK_BYPASS(0, 01),
+	REF_CLK_BYPASS(1, 01),
+	REF_CLK_BYPASS(2, 23),
+	REF_CLK_BYPASS(3, 23),
+	REF_CLK_BYPASS(4, 45),
+	REF_CLK_BYPASS(5, 45),
+	REF_CLK_XY_SRC(01),
+	REF_CLK_XY_SRC(23),
+	REF_CLK_XY_SRC(45),
+	{ /* sentinel */ },
+};
+
+enum h616_pwm_mode {
+	H616_PWM_MODE_NONE,
+	H616_PWM_MODE_PWM,
+	H616_PWM_MODE_CLK,
+};
+
+struct h616_pwm_data {
+	unsigned int npwm;
+};
+
+struct h616_pwm_channel {
+	struct clk *pwm_clk;
+	unsigned long rate;
+	unsigned int entire_cycles;
+	unsigned int active_cycles;
+	enum h616_pwm_mode mode;
+	bool bypass;
+};
+
+struct clk_pwm_pdata {
+	struct clk_hw_onecell_data *hw_data;
+	spinlock_t lock;
+	void __iomem *reg;
+};
+
+struct h616_pwm_chip {
+	struct clk_pwm_pdata *clk_pdata;
+	struct h616_pwm_channel *channels;
+	struct clk *bus_clk;
+	struct reset_control *rst;
+	void __iomem *base;
+	const struct h616_pwm_data *data;
+};
+
+static inline struct h616_pwm_chip *to_h616_pwm_chip(struct pwm_chip *chip)
+{
+	return pwmchip_get_drvdata(chip);
+}
+
+static inline u32 h616_pwm_readl(struct h616_pwm_chip *h616chip,
+				 unsigned long offset)
+{
+	return readl(h616chip->base + offset);
+}
+
+static inline void h616_pwm_writel(struct h616_pwm_chip *h616chip,
+				   u32 val, unsigned long offset)
+{
+	writel(val, h616chip->base + offset);
+}
+
+static void h616_pwm_set_bypass(struct h616_pwm_chip *h616chip, unsigned int idx,
+				bool en_bypass)
+{
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&h616chip->clk_pdata->lock, flags);
+
+	val = h616_pwm_readl(h616chip, PWM_XY_CLK_CR(PWM_PAIR_IDX(idx)));
+	if (en_bypass)
+		val |= BIT(PWM_XY_CLK_CR_BYPASS_BIT(idx));
+	else
+		val &= ~BIT(PWM_XY_CLK_CR_BYPASS_BIT(idx));
+
+	h616_pwm_writel(h616chip, val, PWM_XY_CLK_CR(PWM_PAIR_IDX(idx)));
+
+	spin_unlock_irqrestore(&h616chip->clk_pdata->lock, flags);
+}
+
+static int h616_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct h616_pwm_chip *h616chip = to_h616_pwm_chip(chip);
+	struct h616_pwm_channel *chan = &h616chip->channels[pwm->hwpwm];
+	struct device *dev = pwmchip_parent(chip);
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&h616chip->clk_pdata->lock, flags);
+
+	if (chan->mode == H616_PWM_MODE_CLK)
+		ret = -EBUSY;
+	else
+		chan->mode = H616_PWM_MODE_PWM;
+
+	spin_unlock_irqrestore(&h616chip->clk_pdata->lock, flags);
+	if (ret)
+		goto out;
+
+	ret = clk_prepare_enable(chan->pwm_clk);
+	if (ret < 0) {
+		dev_err(dev, "Failed to enable clock %s: %d\n",
+			__clk_get_name(chan->pwm_clk), ret);
+	}
+out:
+	return ret;
+}
+
+static void h616_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct h616_pwm_chip *h616chip = to_h616_pwm_chip(chip);
+	struct h616_pwm_channel *chan = &h616chip->channels[pwm->hwpwm];
+
+	clk_disable_unprepare(chan->pwm_clk);
+	chan->mode = H616_PWM_MODE_NONE;
+}
+
+static int h616_pwm_get_state(struct pwm_chip *chip,
+			      struct pwm_device *pwm,
+			      struct pwm_state *state)
+{
+	struct h616_pwm_chip *h616chip = to_h616_pwm_chip(chip);
+	struct h616_pwm_channel *chan = &h616chip->channels[pwm->hwpwm];
+	u64 clk_rate, tmp;
+	u32 val;
+
+	clk_rate = clk_get_rate(chan->pwm_clk);
+	if (!clk_rate)
+		return -EINVAL;
+
+	val = h616_pwm_readl(h616chip, PWM_ENR);
+	state->enabled = !!(PWM_ENABLE(pwm->hwpwm) & val);
+
+	val = h616_pwm_readl(h616chip, PWM_XY_CLK_CR(PWM_PAIR_IDX(pwm->hwpwm)));
+	if (val & BIT(PWM_XY_CLK_CR_BYPASS_BIT(pwm->hwpwm))) {
+		/*
+		 * When bypass is enabled, the PWM logic is inactive.
+		 * The PWM_clock_src_xy is directly routed to PWM_clock_x
+		 */
+		state->period = DIV_ROUND_UP_ULL(NSEC_PER_SEC, clk_rate);
+		state->duty_cycle = DIV_ROUND_UP_ULL(state->period, 2);
+		state->polarity = PWM_POLARITY_NORMAL;
+		return 0;
+	}
+
+	state->enabled &= !!(BIT(PWM_XY_CLK_CR_GATE_BIT) & val);
+
+	val = h616_pwm_readl(h616chip, PWM_CTRL_REG(pwm->hwpwm));
+	if (val & PWM_CTRL_ACTIVE_STATE)
+		state->polarity = PWM_POLARITY_NORMAL;
+	else
+		state->polarity = PWM_POLARITY_INVERSED;
+
+	val = h616_pwm_readl(h616chip, PWM_PERIOD_REG(pwm->hwpwm));
+
+	tmp = NSEC_PER_SEC * PWM_REG_DUTY(val);
+	state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate);
+
+	tmp = NSEC_PER_SEC * PWM_REG_PERIOD(val);
+	state->period = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate);
+
+	return 0;
+}
+
+static int h616_pwm_calc(struct pwm_chip *chip, unsigned int idx,
+			 const struct pwm_state *state)
+{
+	struct h616_pwm_chip *h616chip = to_h616_pwm_chip(chip);
+	struct h616_pwm_channel *chan = &h616chip->channels[idx];
+	unsigned int cnt, duty_cnt;
+	unsigned long max_rate;
+	long calc_rate;
+	u64 duty, period, freq;
+
+	duty = state->duty_cycle;
+	period = state->period;
+
+	max_rate = clk_round_rate(chan->pwm_clk, UINT32_MAX);
+
+	dev_dbg(pwmchip_parent(chip), "max_rate: %ld Hz\n", max_rate);
+
+	if ((period * max_rate >= NSEC_PER_SEC) &&
+	    (period * max_rate < 2 * NSEC_PER_SEC) &&
+	    (duty * max_rate * 2 >= NSEC_PER_SEC)) {
+		/*
+		 * If the requested period is to small to be generated by the
+		 * PWM, we can just select the highest clock and bypass the
+		 * PWM logic
+		 */
+		dev_dbg(pwmchip_parent(chip), "Setting bypass (period=%lld)\n",
+			period);
+		freq = div64_u64(NSEC_PER_SEC, period);
+		chan->bypass = true;
+		duty = period / 2;
+	} else {
+		chan->bypass = false;
+		freq = div64_u64(NSEC_PER_SEC * (u64)PWM_PERIOD_MAX, period);
+		if (freq > UINT32_MAX)
+			freq = UINT32_MAX;
+	}
+
+	calc_rate = clk_round_rate(chan->pwm_clk, freq);
+	if (calc_rate <= 0) {
+		dev_err(pwmchip_parent(chip),
+			"Invalid source clock frequency %llu\n", freq);
+		return calc_rate ? calc_rate : -EINVAL;
+	}
+
+	dev_dbg(pwmchip_parent(chip), "calc_rate: %ld Hz\n", calc_rate);
+
+	cnt = mul_u64_u64_div_u64(calc_rate, period, NSEC_PER_SEC);
+	if ((cnt == 0) || (cnt > PWM_PERIOD_MAX)) {
+		dev_err(pwmchip_parent(chip), "Period out of range\n");
+		return -EINVAL;
+	}
+
+	duty_cnt = mul_u64_u64_div_u64(calc_rate, duty, NSEC_PER_SEC);
+
+	if (duty_cnt >= cnt)
+		duty_cnt = cnt - 1;
+
+	dev_dbg(pwmchip_parent(chip), "period=%llu cnt=%u duty=%llu duty_cnt=%u\n",
+		period, cnt, duty, duty_cnt);
+
+	chan->active_cycles = duty_cnt;
+	chan->entire_cycles = cnt;
+
+	chan->rate = calc_rate;
+
+	return 0;
+}
+
+static int h616_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+			  const struct pwm_state *state)
+{
+	struct h616_pwm_chip *h616chip = to_h616_pwm_chip(chip);
+	struct h616_pwm_channel *chan = &h616chip->channels[pwm->hwpwm];
+	struct pwm_state cstate;
+	unsigned long flags;
+	u32 val;
+	int ret;
+
+	ret = h616_pwm_calc(chip, pwm->hwpwm, state);
+	if (ret) {
+		dev_err(pwmchip_parent(chip), "period exceeds the maximum value\n");
+		return ret;
+	}
+
+	pwm_get_state(pwm, &cstate);
+
+	ret = clk_set_rate(chan->pwm_clk, chan->rate);
+	if (ret) {
+		dev_err(pwmchip_parent(chip), "failed to set PWM %d clock rate to %lu\n",
+			pwm->hwpwm, chan->rate);
+		return ret;
+	}
+
+	h616_pwm_set_bypass(h616chip, pwm->hwpwm, chan->bypass);
+
+	/*
+	 * If bypass is set, the PWM logic (polarity, duty) can't be applied
+	 */
+
+	if (chan->bypass && (state->polarity == PWM_POLARITY_INVERSED)) {
+		dev_warn(pwmchip_parent(chip),
+			 "Can't set inversed polarity with bypass enabled\n");
+	} else {
+		val = h616_pwm_readl(h616chip, PWM_CTRL_REG(pwm->hwpwm));
+		val &= ~PWM_CTRL_ACTIVE_STATE;
+		if (state->polarity == PWM_POLARITY_NORMAL)
+			val |= PWM_CTRL_ACTIVE_STATE;
+		h616_pwm_writel(h616chip, val, PWM_CTRL_REG(pwm->hwpwm));
+	}
+
+	if (chan->bypass && (state->duty_cycle * 2 != state->period)) {
+		dev_warn(pwmchip_parent(chip),
+			 "Can't set a duty cycle with bypass enabled\n");
+	}
+
+	if (!chan->bypass) {
+		val = PWM_DUTY(chan->active_cycles);
+		val |= PWM_PERIOD(chan->entire_cycles);
+		h616_pwm_writel(h616chip, val, PWM_PERIOD_REG(pwm->hwpwm));
+	}
+
+	if (state->enabled == cstate.enabled)
+		return 0;
+
+	if (cstate.enabled) {
+		unsigned long delay_us;
+
+		/*
+		 * We need a full period to elapse before
+		 * disabling the channel.
+		 */
+		delay_us = DIV_ROUND_UP_ULL(cstate.period, NSEC_PER_USEC);
+		fsleep(delay_us);
+	}
+
+	spin_lock_irqsave(&h616chip->clk_pdata->lock, flags);
+
+	val = h616_pwm_readl(h616chip, PWM_ENR);
+	if (state->enabled)
+		val |= PWM_ENABLE(pwm->hwpwm);
+	else
+		val &= ~PWM_ENABLE(pwm->hwpwm);
+	h616_pwm_writel(h616chip, val, PWM_ENR);
+
+	spin_unlock_irqrestore(&h616chip->clk_pdata->lock, flags);
+
+	return 0;
+}
+
+static const struct pwm_ops h616_pwm_ops = {
+	.apply = h616_pwm_apply,
+	.get_state = h616_pwm_get_state,
+	.request = h616_pwm_request,
+	.free = h616_pwm_free,
+};
+
+static struct clk_hw *h616_pwm_of_clk_get(struct of_phandle_args *clkspec,
+					  void *data)
+{
+	struct h616_pwm_chip *h616chip = data;
+	struct clk_hw_onecell_data *hw_data = h616chip->clk_pdata->hw_data;
+	unsigned int idx = clkspec->args[0];
+	struct h616_pwm_channel *chan;
+	struct clk_hw *ret_clk = NULL;
+	unsigned long flags;
+
+	if (idx >= h616chip->data->npwm)
+		return ERR_PTR(-EINVAL);
+
+	chan = &h616chip->channels[idx];
+
+	spin_lock_irqsave(&h616chip->clk_pdata->lock, flags);
+
+	if (chan->mode == H616_PWM_MODE_PWM) {
+		ret_clk = ERR_PTR(-EBUSY);
+	} else {
+		chan->mode = H616_PWM_MODE_CLK;
+		ret_clk = hw_data->hws[CLK_BYPASS(h616chip, idx)];
+	}
+	spin_unlock_irqrestore(&h616chip->clk_pdata->lock, flags);
+
+	if (IS_ERR(ret_clk))
+		goto out;
+
+	chan->bypass = true;
+	h616_pwm_set_bypass(h616chip, idx, chan->bypass);
+out:
+	return ret_clk;
+}
+
+static int h616_add_composite_clk(const struct clk_pwm_data *data,
+				  void __iomem *reg, spinlock_t *lock,
+				  struct device *dev, struct clk_hw **hw)
+{
+	const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, *rate_ops = NULL;
+	struct clk_hw *mux_hw = NULL, *gate_hw = NULL, *rate_hw = NULL;
+
+
+	if (data->mux_hw) {
+		struct clk_mux *mux;
+
+		mux_hw = data->mux_hw;
+		mux = to_clk_mux(mux_hw);
+		mux->lock = lock;
+		mux_ops = mux_hw->init->ops;
+		mux->reg = (u64)mux->reg + reg;
+	}
+
+	if (data->gate_hw) {
+		struct clk_gate *gate;
+
+		gate_hw = data->gate_hw;
+		gate = to_clk_gate(gate_hw);
+		gate->lock = lock;
+		gate_ops = gate_hw->init->ops;
+		gate->reg = (u64)gate->reg + reg;
+	}
+
+	if (data->rate_hw) {
+		struct clk_divider *rate;
+
+		rate_hw = data->rate_hw;
+		rate = to_clk_divider(rate_hw);
+		rate_ops = rate_hw->init->ops;
+		rate->lock = lock;
+		rate->reg = (u64)rate->reg + reg;
+
+		if (rate->table) {
+			const struct clk_div_table *clkt;
+			int table_size = 0;
+
+			for (clkt = rate->table; clkt->div; clkt++)
+				table_size++;
+			rate->width = order_base_2(table_size);
+		}
+	}
+
+	*hw = clk_hw_register_composite(dev, data->name, data->parent_names,
+					data->num_parents, mux_hw,
+					mux_ops, rate_hw, rate_ops,
+					gate_hw, gate_ops, data->flags);
+
+	return PTR_ERR_OR_ZERO(*hw);
+}
+
+static int h616_pwm_init_clocks(struct platform_device *pdev,
+				struct h616_pwm_chip *h616chip)
+{
+	struct clk_pwm_pdata *pdata;
+	struct device *dev = &pdev->dev;
+	int num_clocks = 0;
+	int ret;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	while (pwmcc_data[num_clocks].name)
+		num_clocks++;
+
+	pdata->hw_data = devm_kzalloc(dev, struct_size(pdata->hw_data, hws, num_clocks),
+				      GFP_KERNEL);
+	if (!pdata->hw_data)
+		return -ENOMEM;
+
+	pdata->hw_data->num = num_clocks;
+	pdata->reg = h616chip->base;
+
+	spin_lock_init(&pdata->lock);
+
+	for (int i = 0; i < num_clocks; i++) {
+		struct clk_hw **hw = &pdata->hw_data->hws[i];
+
+		ret = h616_add_composite_clk(&pwmcc_data[i], pdata->reg,
+					     &pdata->lock, dev, hw);
+		if (ret) {
+			dev_err_probe(dev, ret,
+				      "Failed to register hw clock %s\n",
+				      pwmcc_data[i].name);
+			for (i--; i >= 0; i--)
+				clk_hw_unregister_composite(pdata->hw_data->hws[i]);
+			return ret;
+		}
+	}
+
+	h616chip->clk_pdata = pdata;
+
+	return 0;
+}
+
+static int h616_pwm_probe(struct platform_device *pdev)
+{
+	const struct h616_pwm_data *data;
+	struct device *dev = &pdev->dev;
+	struct h616_pwm_chip *h616chip;
+	struct pwm_chip *chip;
+	int ret;
+
+	data = of_device_get_match_data(dev);
+	if (!data)
+		return -ENODEV;
+
+	chip = devm_pwmchip_alloc(dev, data->npwm, sizeof(*h616chip));
+	if (IS_ERR(chip))
+		return dev_err_probe(dev, PTR_ERR(chip),
+				     "Failed to allocate pwmchip\n");
+
+	h616chip = to_h616_pwm_chip(chip);
+	h616chip->data = data;
+	h616chip->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(h616chip->base))
+		return dev_err_probe(dev, PTR_ERR(h616chip->base),
+				     "Failed to get PWM base address\n");
+
+	h616chip->bus_clk = devm_clk_get_enabled(dev, "bus");
+	if (IS_ERR(h616chip->bus_clk))
+		return dev_err_probe(dev, PTR_ERR(h616chip->bus_clk),
+				     "Failed to get bus clock\n");
+
+	h616chip->channels = devm_kmalloc_array(dev, data->npwm,
+						sizeof(*(h616chip->channels)),
+						GFP_KERNEL);
+	if (!h616chip->channels)
+		return dev_err_probe(dev, -ENOMEM,
+				     "Failed to allocate %d channels array\n",
+				     data->npwm);
+
+	h616chip->rst = devm_reset_control_get_shared(dev, NULL);
+	if (IS_ERR(h616chip->rst))
+		return dev_err_probe(dev, PTR_ERR(h616chip->rst),
+				     "Failed to get reset control\n");
+
+	chip->ops = &h616_pwm_ops;
+
+	ret = h616_pwm_init_clocks(pdev, h616chip);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to initialize clocks\n");
+
+	for (unsigned int i = 0; i < data->npwm; i++) {
+		struct h616_pwm_channel *chan = &h616chip->channels[i];
+		struct clk_hw **hw = &h616chip->clk_pdata->hw_data->hws[i];
+
+		chan->pwm_clk = devm_clk_hw_get_clk(dev, *hw, NULL);
+		if (IS_ERR(chan->pwm_clk)) {
+			ret = dev_err_probe(dev, PTR_ERR(chan->pwm_clk),
+					    "Failed to register PWM clock %d\n", i);
+			goto err_get_clk;
+		}
+		chan->mode = H616_PWM_MODE_NONE;
+	}
+
+	ret = devm_of_clk_add_hw_provider(dev, h616_pwm_of_clk_get, h616chip);
+	if (ret) {
+		dev_err_probe(dev, ret, "Failed to add HW clock provider\n");
+		goto err_add_clk_provider;
+	}
+
+	/* Deassert reset */
+	ret = reset_control_deassert(h616chip->rst);
+	if (ret) {
+		dev_err_probe(dev, ret, "Cannot deassert reset control\n");
+		goto err_ctrl_deassert;
+	}
+
+	ret = pwmchip_add(chip);
+	if (ret < 0) {
+		dev_err_probe(dev, ret, "Failed to add PWM chip\n");
+		goto err_pwm_add;
+	}
+
+	platform_set_drvdata(pdev, chip);
+
+	return 0;
+
+err_pwm_add:
+	reset_control_assert(h616chip->rst);
+
+err_ctrl_deassert:
+err_add_clk_provider:
+err_get_clk:
+	for (int i = 0; i < h616chip->clk_pdata->hw_data->num; i++)
+		clk_hw_unregister_composite(h616chip->clk_pdata->hw_data->hws[i]);
+
+	return ret;
+}
+
+static const struct h616_pwm_data sun50i_h616_pwm_data = {
+	.npwm = 6,
+};
+
+static const struct of_device_id h616_pwm_dt_ids[] = {
+	{
+		.compatible = "allwinner,sun50i-h616-pwm",
+		.data = &sun50i_h616_pwm_data,
+	}, {
+		/* sentinel */
+	},
+};
+MODULE_DEVICE_TABLE(of, h616_pwm_dt_ids);
+
+
+static struct platform_driver h616_pwm_driver = {
+	.driver = {
+		.name = "h616-pwm",
+		.of_match_table = h616_pwm_dt_ids,
+	},
+	.probe = h616_pwm_probe,
+};
+module_platform_driver(h616_pwm_driver);
+
+MODULE_ALIAS("platform:h616-pwm");
+MODULE_AUTHOR("Richard Genoud <richard.genoud at bootlin.com>");
+MODULE_DESCRIPTION("Allwinner H616 PWM driver");
+MODULE_LICENSE("GPL");
-- 
2.47.3



From richard.genoud at bootlin.com  Fri Dec  5 02:02:39 2025
From: richard.genoud at bootlin.com (Richard Genoud)
Date: Fri,  5 Dec 2025 11:02:39 +0100
Subject: [PATCH 4/4] MAINTAINERS: Add entry on Allwinner H616 PWM driver
In-Reply-To: <20251205100239.1563353-1-richard.genoud@bootlin.com>
References: <20251205100239.1563353-1-richard.genoud@bootlin.com>
Message-ID: <20251205100239.1563353-5-richard.genoud@bootlin.com>

Add myself as maintainer of Allwinner H616 PWM driver and device-tree
bindings.

Signed-off-by: Richard Genoud <richard.genoud at bootlin.com>
---
 MAINTAINERS | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 578c068b738b..b336c0fff4e4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -903,6 +903,12 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/sound/allwinner,sun50i-h6-dmic.yaml
 F:	sound/soc/sunxi/sun50i-dmic.c
 
+ALLWINNER H616 PWM DRIVER
+M:	Richard Genoud <richard.genoud at bootlin.com>
+S:	Maintained
+F:	Documentation/devicetree/bindings/pwm/allwinner,sun50i-h616-pwm.yaml
+F:	drivers/pwm/pwm-sun50i-h616.c
+
 ALLWINNER HARDWARE SPINLOCK SUPPORT
 M:	Wilken Gottwalt <wilken.gottwalt at posteo.net>
 S:	Maintained
-- 
2.47.3



From richard.genoud at bootlin.com  Fri Dec  5 02:02:38 2025
From: richard.genoud at bootlin.com (Richard Genoud)
Date: Fri,  5 Dec 2025 11:02:38 +0100
Subject: [PATCH 3/4] arm64: dts: allwinner: h616: add PWM controller
In-Reply-To: <20251205100239.1563353-1-richard.genoud@bootlin.com>
References: <20251205100239.1563353-1-richard.genoud@bootlin.com>
Message-ID: <20251205100239.1563353-4-richard.genoud@bootlin.com>

The H616 has a PWM controller that can provide PWM signals, but also
plain clocks.

Add the PWM controller node and pins in the device tree.

Signed-off-by: Richard Genoud <richard.genoud at bootlin.com>
---
 .../arm64/boot/dts/allwinner/sun50i-h616.dtsi | 47 +++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi
index 8d1110c14bad..6bfb234e3075 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi
@@ -236,6 +236,17 @@ watchdog: watchdog at 30090a0 {
 			clocks = <&osc24M>;
 		};
 
+		pwm: pwm at 300a000 {
+			compatible = "allwinner,sun50i-h616-pwm";
+			reg = <0x0300a000 0x400>;
+			clocks = <&ccu CLK_BUS_PWM>;
+			clock-names = "bus";
+			resets = <&ccu RST_BUS_PWM>;
+			#pwm-cells = <3>;
+			#clock-cells = <1>;
+			status = "disabled";
+		};
+
 		pio: pinctrl at 300b000 {
 			compatible = "allwinner,sun50i-h616-pinctrl";
 			reg = <0x0300b000 0x400>;
@@ -340,6 +351,42 @@ nand_rb1_pin: nand-rb1-pin {
 				bias-pull-up;
 			};
 
+			/omit-if-no-ref/
+			pwm0_pin: pwm0-pin {
+				pins = "PD28";
+				function = "pwm0";
+			};
+
+			/omit-if-no-ref/
+			pwm1_pin: pwm1-pin {
+				pins = "PG19";
+				function = "pwm1";
+			};
+
+			/omit-if-no-ref/
+			pwm2_pin: pwm2-pin {
+				pins = "PH2";
+				function = "pwm2";
+			};
+
+			/omit-if-no-ref/
+			pwm3_pin: pwm3-pin {
+				pins = "PH0";
+				function = "pwm3";
+			};
+
+			/omit-if-no-ref/
+			pwm4_pin: pwm4-pin {
+				pins = "PI14";
+				function = "pwm4";
+			};
+
+			/omit-if-no-ref/
+			pwm5_pin: pwm5-pin {
+				pins = "PA12";
+				function = "pwm5";
+			};
+
 			/omit-if-no-ref/
 			spi0_pins: spi0-pins {
 				pins = "PC0", "PC2", "PC4";
-- 
2.47.3



From piotr.oniszczuk at gmail.com  Fri Dec  5 02:03:44 2025
From: piotr.oniszczuk at gmail.com (Piotr Oniszczuk)
Date: Fri, 5 Dec 2025 11:03:44 +0100
Subject: [PATCH 01/11] dt-bindings: display: meson-dw-hdmi: Add compatible
 for S4 HDMI controller
In-Reply-To: <b6b8203d-2a51-428f-8124-fa65d2c073a0@amlogic.com>
References: <20250110-drm-s4-v1-0-cbc2d5edaae8@amlogic.com>
 <20250110-drm-s4-v1-1-cbc2d5edaae8@amlogic.com>
 <3AC316FA-A633-4B6C-81BA-CCCA290E7F03@gmail.com>
 <8c3b9fa4-326e-4791-8154-07b268faa132@amlogic.com>
 <7703796D-35D4-4AD2-B7F8-B75D2BE0F7AD@gmail.com>
 <a71f24c9-1f40-45a1-8fdb-6075bbf89930@amlogic.com>
 <F04DC684-AD64-447F-87EC-F503D411F25D@gmail.com>
 <070eb0a3-2f6e-41ef-8310-0c592a2816dc@amlogic.com>
 <b6b8203d-2a51-428f-8124-fa65d2c073a0@amlogic.com>
Message-ID: <9BCB2E8F-F8FA-4CA4-9039-FADE0D875404@gmail.com>

Ao,

Thx!

Indeed patch helps with boot freeze.
I started to see on monitor - with correct resolution - 4 tuxes in upper left corner :-)

Now i'm getting user space oops like this: 

https://gist.github.com/warpme/b8b757bc1444be8a137849301698ee4b

i'm pretty sure it is related to lack of (or issue with) console at kernel early init in user space.

As kernel with s4 hdmi code works for you - but traps for me - i think there is still issue with s4 hdmi code.
I suspect it is because diff between: my kernel config and yours.
(so it is exposing existing hidden issue)

btw: I'm not surprised by this as my kernel config is multi-soc (common for bcm25xx/27xx/s905/s912/g12/sm1/s4/h6/h616/a523/h700/rk33xx/rk35xx/qcs6490)
Usually kernel configs done for single soc (probably config you are using to test s4 hdmi code) are not exposing hidden issues exposed by multi-soc config (like mine config). 
I deal with such issues multiple times in past.

multi-soc config i'm using is like this: https://github.com/warpme/minimyth2/blob/master/script/kernel/linux-6.18/files/linux-6.18-arm64-armv8.config

May you pls try to compile your s4 hdmi code with above config?
I'm quite sure it will expose to you issue i'm getting....




> Wiadomo?? napisana przez Ao Xu <ao.xu at amlogic.com> w dniu 5 gru 2025, o godz. 08:09:
> 
> Hi Piotr?
> 
>     I applied this patch: https://github.com/warpme/minimyth2/blob/master/script/kernel/linux-6.18/files/0312-drm-meson-add-vpu-clk-setting-for-S4.patch, and ran it on the board.
> 
>     I encountered the same issue?the system froze.
> 
>     I found that the patch has a few minor problems. After fixing them, the system runs normally. Could you try the following patch?
> 
> 
> ? 2025/12/3 13:56, Ao Xu ??:
>> Hi Piotr?
>> 
>>     I will need about two more days to look into it. I will follow up with you ASAP.
>> 
>> 
>> ? 2025/12/2 16:29, Piotr Oniszczuk ??:
>>> [You don't often get email from piotr.oniszczuk at gmail.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
>>> 
>>> [ EXTERNAL EMAIL ]
>>> 
>>> Ao,
>>> Any chance for updated s4 hdmi series for 6.18?
>>> 
>>> 
>>>> Wiadomo?? napisana przez Ao Xu <ao.xu at amlogic.com> w dniu 21 lis 2025, o godz. 03:55:
>>>> 
>>>> Hi Piotr?
>>>> 
>>>>      I will check this issue
>>>> 
>>>> ? 2025/11/19 18:27, Piotr Oniszczuk ??:
>>>>> [You don't often get email from piotr.oniszczuk at gmail.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
>>>>> 
>>>>> [ EXTERNAL EMAIL ]
>>>>> 
>>>>> Pls see inline
>>>>> 
>>>>>> Wiadomo?? napisana przez Chuan Liu <chuan.liu at amlogic.com> w dniu 19 lis 2025, o godz. 03:57:
>>>>>> 
>>>>>> Hi Piotr,
>>>>>> 
>>>>>> 
>>>>>> On 11/18/2025 10:50 PM, Piotr Oniszczuk wrote:
>>>>>>> [You don't often get email from piotr.oniszczuk at gmail.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
>>>>>>> [ EXTERNAL EMAIL ]
>>>>>>> Ao,
>>>>>>> Is there any chance to get this s4 drm hdmi series for current 6.18?
>>>>>>> (i tried backport this series to 6.18 but have some issues with reparent vpu_0_sel to sysclk_b_sel)
>>>>>> Why do we need to reparent vpu_0_sel to sysclk_b_sel? is there any
>>>>>> background here?
>>>>> Well - it looks it is because bug....
>>>>> Martin Blumenstingl had perfect eye and catch typo in patch https://lore.kernel.org/all/20250110-drm-s4-v1-11-cbc2d5edaae8 at amlogic.com/: 
>>>>> 
>>>>> By replacing:
>>>>> assigned-clock-parents = <&clkc_periphs CLKID_FCLK_DIV3>,
>>>>> <0>, /* Do Nothing */
>>>>> <&clkc_periphs CLKID_VPU_0>,
>>>>> <&clkc_periphs CLKID_FCLK_DIV4>,
>>>>> <0>, /* Do Nothing */
>>>>> <&clkc_periphs CLKID_VAPB_0>;
>>>>> 
>>>>> with:
>>>>> assigned-clock-parents = <&clkc_pll CLKID_FCLK_DIV3>,
>>>>> <0>, /* Do Nothing */
>>>>> <&clkc_periphs CLKID_VPU_0>,
>>>>> <&clkc_pll CLKID_FCLK_DIV4>,
>>>>> <0>, /* Do Nothing */
>>>>> <&clkc_periphs CLKID_VAPB_0>;
>>>>> 
>>>>> dmesg is like this https://termbin.com/6020
>>>>> 
>>>>> So i'm getting hdmi working - but only when device boots _without_ connected hdmi at boot (and connected later)
>>>>> If hdmi is connected at boot - boot hangs at:
>>>>> 
>>>>>      0.341676] meson-dw-hdmi fe300000.hdmi-tx: Detected HDMI TX controller v2.01a with HDCP (meson_dw_hdmi_phy)
>>>>> [    0.342750] meson-dw-hdmi fe300000.hdmi-tx: registered DesignWare HDMI I2C bus driver
>>>>> [    0.343660] meson-drm ff000000.vpu: bound fe300000.hdmi-tx (ops meson_dw_hdmi_ops)
>>>>> [    0.344832] [drm] Initialized meson 1.0.0 for ff000000.vpu on minor 0
>>>>> 
>>>>> FYI: It is after applying https://patchwork.kernel.org/project/linux-amlogic/cover/20250110-drm-s4-v1-0-cbc2d5edaae8 at amlogic.com/ on mainline 6.18 (with some my adjustments on this series required by changes in 6.18).
>>>>> For VPU clk changes see https://github.com/warpme/minimyth2/blob/master/script/kernel/linux-6.18/files/0312-drm-meson-add-vpu-clk-setting-for-S4.patch
>>>>> It is 6.18 adaptation of https://patchwork.kernel.org/project/linux-amlogic/patch/20250110-drm-s4-v1-9-cbc2d5edaae8 at amlogic.com/
>>>>> 
>>>>> As kernel hangs - i have limited caps to drill where root cause is.
>>>>> 
>>>>> Maybe above hang is reason of my backports or missing any pre-req required to get s4 drm working?
>>>>> Anyway - it will be good to test with updated to 6.18 series of Add DRM support for Amlogic S4 (plus info about any pre-req required to get s4 drm working)
>>>>> 
>>>>> 
>>>>>> The vpu_clk on S4 doesn't support sysclk_b_sel as one of its
>>>>>> selectable clock sources, so this reparent operation will definitely
>>>>>> fail. This has nothing to do with the kernel version.
>>>>>> 
>>>>>>>> Wiadomo?? napisana przez Ao Xu via B4 Relay <devnull+ao.xu.amlogic.com at kernel.org> w dniu 10 sty 2025, o godz. 06:39:
>>>>>>>> 
>>>>>>>> From: Ao Xu <ao.xu at amlogic.com>
>>>>>>>> 
>>>>>>>> Add devicetree document for S4 HDMI controller
>>>>>>>> 
>>>>>>>> Signed-off-by: Ao Xu <ao.xu at amlogic.com>
>>>>>>>> ---
>>>>>>>> Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml | 1 +
>>>>>>>> 1 file changed, 1 insertion(+)
>>>>>>>> 
>>>>>>>> diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml 
>>>>>>>> index 84d68b8cfccc86fd87a6a0fd2b70af12e51eb8a4..6e0a8369eee915fab55af24d450a6c40e08def38 100644
>>>>>>>> --- a/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml 
>>>>>>>> +++ b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml 
>>>>>>>> @@ -55,6 +55,7 @@ properties:
>>>>>>>>            - const: amlogic,meson-gx-dw-hdmi
>>>>>>>>        - enum:
>>>>>>>>            - amlogic,meson-g12a-dw-hdmi # G12A (S905X2, S905Y2, S905D2)
>>>>>>>> +          - amlogic,meson-s4-dw-hdmi # S4 (S905Y4)
>>>>>>>> 
>>>>>>>>    reg:
>>>>>>>>      maxItems: 1
>>>>>>>> 
>>>>>>>> -- 
>>>>>>>> 2.43.0
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> _______________________________________________
>>>>>>>> linux-amlogic mailing list
>>>>>>>> linux-amlogic at lists.infradead.org
>>>>>>>> http://lists.infradead.org/mailman/listinfo/linux-amlogic
>>>>>>> _______________________________________________
>>>>>>> linux-amlogic mailing list
>>>>>>> linux-amlogic at lists.infradead.org
>>>>>>> http://lists.infradead.org/mailman/listinfo/linux-amlogic
> <fix-vpu-clk-setting-for-s4.patch>




From leo.yan at arm.com  Fri Dec  5 02:04:32 2025
From: leo.yan at arm.com (Leo Yan)
Date: Fri, 5 Dec 2025 10:04:32 +0000
Subject: [PATCH v6 2/2] coresight: cti: Add Qualcomm extended CTI support
In-Reply-To: <CAJ9a7VjHHkkTz9XJqjdQ+11_XX9zXuY0ZcQzPtq=Zvi4CN__0A@mail.gmail.com>
References: <20251202-extended_cti-v6-0-ab68bb15c4f5@oss.qualcomm.com>
 <20251202-extended_cti-v6-2-ab68bb15c4f5@oss.qualcomm.com>
 <20251203182944.GG724103@e132581.arm.com>
 <CAJ9a7VjWDBEwdmMf53geACBWGusC8BC3pJuOLETeecw24+N35Q@mail.gmail.com>
 <20251204103151.GK724103@e132581.arm.com>
 <CAJ9a7VjHHkkTz9XJqjdQ+11_XX9zXuY0ZcQzPtq=Zvi4CN__0A@mail.gmail.com>
Message-ID: <20251205100432.GO724103@e132581.arm.com>

Hi Mike,

On Thu, Dec 04, 2025 at 04:17:35PM +0000, Mike Leach wrote:

[...]

> The tables in the patch are
> 
>     [reg_type_array_index] = offset_address;
> 
> e.g.
> 
>   [INDEX_CTIINTACK]  = QCOM_CTIINTACK
> 
> which resolves to
> 
>  [1] = 0x020
> 
> where index is constant for a given register type,
> 
> As far as I can tell what you have suggested above is a table that is
> 
>   [std_addr_offset] = qcom_addr_offset;
> 
> e.g.
> 
> [CTIINTACK]             = QCOM_CTIINTACK,
> 
> which resolves to
> 
> [0x10]  = 0x020
> 
> which does not appear to work correctly?
> 
> The registers are sparsely spread across the memory map, so a simple
> mapping does not work, even if we divide the original offset by 4 to
> create a register number.

This should work.  Though the array is not filled for each item, but
it will return back 0x20 when we access array[0x10], I don't see
problem here.

> The largest standard offset we have is ITTRIGIN = 0xEF8, so assuming
> the compiler allows us to sparselly populate the array (which I think
> it does, along with some padding), we end up with an array of at least
> 0xEF8 elements, rather then the indexed 21?

I tested locally and did not see the GCC complaint for this approach.
And this is a global structure with about 16KiB (~4K items x
sizeof(u32)), we don't need to worry about scaling issue as it is
shared by device instances.

If you dislike this way, then a static function also can fulfill the
same task, something like:

    static noinline u32 cti_qcom_reg_off(u32 offset)
    {
            switch (offset) {
            CTIINTACK: return QCOM_CTIINTACK;
            CTIAPPSET: return QCOM_CTIAPPSET;
            ...
            default:
                WARN(1, "Unknown offset=%u\n", offset);
                return 0;
            }

            /* Should not run here, just for compiling */
	    return 0;
    }

Thanks,
Leo


From linux at fw-web.de  Fri Dec  5 02:12:18 2025
From: linux at fw-web.de (Frank Wunderlich (linux))
Date: Fri, 05 Dec 2025 11:12:18 +0100
Subject: [PATCH v1 1/2] arm64: dts: mediatek: mt7986: add dtbs with
 applied overlays for bpi-r3
In-Reply-To: <fc5c9829-96fa-4028-a642-0792699e92a5@kernel.org>
References: <20251119175124.48947-1-linux@fw-web.de>
 <20251119175124.48947-2-linux@fw-web.de>
 <fc5c9829-96fa-4028-a642-0792699e92a5@kernel.org>
Message-ID: <942df0f5995a2929eecd38e4066865c0@fw-web.de>

Hi

Am 2025-12-05 09:10, schrieb Krzysztof Kozlowski:
> On 19/11/2025 18:51, Frank Wunderlich wrote:
>> From: Frank Wunderlich <frank-w at public-files.de>
>> 
>> Build devicetree binaries for testing overlays and providing users
>> full dtb without using overlays.
>> 
>> Suggested-by: Rob Herring <robh+dt at kernel.org>
>> Signed-off-by: Frank Wunderlich <frank-w at public-files.de>
>> ---
>> resend of
>> https://patchwork.kernel.org/project/linux-mediatek/patch/20240608080530.9436-2-linux at fw-web.de/
>> due to discussions here:
>> https://patchwork.kernel.org/project/linux-mediatek/patch/20251117211306.725678-1-robh at kernel.org/
>> 
>> changes:
>> - updated sd-nand with sata-overlay
>> ---
>>  arch/arm64/boot/dts/mediatek/Makefile | 21 +++++++++++++++++++++
>>  1 file changed, 21 insertions(+)
> 
> 
> This looks like still not being applied and now it is a warning in
> Linus' tree.
> 
> Can this be applied and sent as fixes?

afair the series was sent after the pull-request from angelo and maybe 
he waited
for an ack from you/rob before applying ;)

if it helps i collected the commits for (possibly) sending as fix

Fixes: a58c36806741 ("arm64: dts: mediatek: mt7988a-bpi-r4pro: Add mmc 
overlays")
Fixes: dec929e61a42 ("arm64: dts: mediatek: mt7988a-bpi-r4-pro: Add PCIe 
overlays")
Fixes: 714a80ced07a ("arm64: dts: mediatek: mt7988a-bpi-r4: Add dt 
overlays for sd + emmc")
Fixes: 312189ebb802 ("arm64: dts: mt7986: add overlay for SATA power 
socket on BPI-R3")
Fixes: 8e01fb15b815 ("arm64: dts: mt7986: add Bananapi R3")

> Best regards,
> Krzysztof

regards Frank


From lorenzo at kernel.org  Fri Dec  5 02:24:35 2025
From: lorenzo at kernel.org (Lorenzo Bianconi)
Date: Fri, 05 Dec 2025 11:24:35 +0100
Subject: [PATCH mt76 v2 0/4] wifi: mt76: mt7996: Some MLO link management
 fixes
Message-ID: <20251205-mt76-txq-wicd-fix-v2-0-f19ba48af7c1@kernel.org>


---
Changes in v2:
- Add missing changes in mt7996_mac_reset_sta_iter() for patch 3/4
- Add patch 4/4 to the series
- Link to v1: https://lore.kernel.org/r/20251204-mt76-txq-wicd-fix-v1-0-1f4b2f2b3b2c at kernel.org

---
Lorenzo Bianconi (4):
      wifi: mt76: mt7996: Set mtxq->wcid just for primary link
      wifi: mt76: mt7996: Reset mtxq->idx if primary link is removed in mt7996_vif_link_remove()
      wifi: mt76: mt7996: Switch to the secondary link if the default one is removed
      wifi: mt76: mt7996: Clear wcid pointer in mt7996_mac_sta_deinit_link()

 drivers/net/wireless/mediatek/mt76/mt7996/mac.c  | 12 ++--
 drivers/net/wireless/mediatek/mt76/mt7996/main.c | 85 ++++++++++++++++--------
 2 files changed, 64 insertions(+), 33 deletions(-)
---
base-commit: 53d1548612670aa8b5d89745116cc33d9d172863
change-id: 20251204-mt76-txq-wicd-fix-267a4941622e

Best regards,
-- 
Lorenzo Bianconi <lorenzo at kernel.org>



From lorenzo at kernel.org  Fri Dec  5 02:24:36 2025
From: lorenzo at kernel.org (Lorenzo Bianconi)
Date: Fri, 05 Dec 2025 11:24:36 +0100
Subject: [PATCH mt76 v2 1/4] wifi: mt76: mt7996: Set mtxq->wcid just for
 primary link
In-Reply-To: <20251205-mt76-txq-wicd-fix-v2-0-f19ba48af7c1@kernel.org>
References: <20251205-mt76-txq-wicd-fix-v2-0-f19ba48af7c1@kernel.org>
Message-ID: <20251205-mt76-txq-wicd-fix-v2-1-f19ba48af7c1@kernel.org>

Set WCID index in mt76_txq struct just for the primary link in
mt7996_vif_link_add routine.

Fixes: 69d54ce7491d0 ("wifi: mt76: mt7996: switch to single multi-radio wiphy")
Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
---
 drivers/net/wireless/mediatek/mt76/mt7996/main.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index beed795edb24c67e1b7b44fe87fd5de125a21d94..0ad0152478a7e1b11bfe5d68d750cb8332d54290 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -300,7 +300,6 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
 		.cmd = SET_KEY,
 		.link_id = link_conf->link_id,
 	};
-	struct mt76_txq *mtxq;
 	int mld_idx, idx, ret;
 
 	mlink->idx = __ffs64(~dev->mt76.vif_mask);
@@ -343,11 +342,6 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
 	mt7996_mac_wtbl_update(dev, idx,
 			       MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
 
-	if (vif->txq) {
-		mtxq = (struct mt76_txq *)vif->txq->drv_priv;
-		mtxq->wcid = idx;
-	}
-
 	if (vif->type != NL80211_IFTYPE_AP &&
 	    (!mlink->omac_idx || mlink->omac_idx > 3))
 		vif->offload_flags = 0;
@@ -371,8 +365,15 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
 	ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, &it);
 
 	if (!mlink->wcid->offchannel &&
-	    mvif->mt76.deflink_id == IEEE80211_LINK_UNSPECIFIED)
+	    mvif->mt76.deflink_id == IEEE80211_LINK_UNSPECIFIED) {
+		if (vif->txq) {
+			struct mt76_txq *mtxq;
+
+			mtxq = (struct mt76_txq *)vif->txq->drv_priv;
+			mtxq->wcid = idx;
+		}
 		mvif->mt76.deflink_id = link_conf->link_id;
+	}
 
 	return 0;
 }

-- 
2.52.0



From lorenzo at kernel.org  Fri Dec  5 02:24:37 2025
From: lorenzo at kernel.org (Lorenzo Bianconi)
Date: Fri, 05 Dec 2025 11:24:37 +0100
Subject: [PATCH mt76 v2 2/4] wifi: mt76: mt7996: Reset mtxq->idx if primary
 link is removed in mt7996_vif_link_remove()
In-Reply-To: <20251205-mt76-txq-wicd-fix-v2-0-f19ba48af7c1@kernel.org>
References: <20251205-mt76-txq-wicd-fix-v2-0-f19ba48af7c1@kernel.org>
Message-ID: <20251205-mt76-txq-wicd-fix-v2-2-f19ba48af7c1@kernel.org>

Reset WCID index in mt76_txq struct if primary link is removed in
mt7996_vif_link_remove routine.

Fixes: a3316d2fc669f ("wifi: mt76: mt7996: set vif default link_id adding/removing vif links")
Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
---
 drivers/net/wireless/mediatek/mt76/mt7996/main.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index 0ad0152478a7e1b11bfe5d68d750cb8332d54290..8bf85a9beee7dc8c6741568af5b36cf89f0c1a88 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -409,12 +409,23 @@ void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif,
 		struct ieee80211_bss_conf *iter;
 		unsigned int link_id;
 
+		/* Primary link will be removed, look for a new one */
 		mvif->mt76.deflink_id = IEEE80211_LINK_UNSPECIFIED;
 		for_each_vif_active_link(vif, iter, link_id) {
-			if (link_id != IEEE80211_LINK_UNSPECIFIED) {
-				mvif->mt76.deflink_id = link_id;
-				break;
+			struct mt7996_vif_link *link;
+
+			link = mt7996_vif_link(dev, vif, link_id);
+			if (!link)
+				continue;
+
+			if (vif->txq) {
+				struct mt76_txq *mtxq;
+
+				mtxq = (struct mt76_txq *)vif->txq->drv_priv;
+				mtxq->wcid = link->msta_link.wcid.idx;
 			}
+			mvif->mt76.deflink_id = link_id;
+			break;
 		}
 	}
 

-- 
2.52.0



From lorenzo at kernel.org  Fri Dec  5 02:24:38 2025
From: lorenzo at kernel.org (Lorenzo Bianconi)
Date: Fri, 05 Dec 2025 11:24:38 +0100
Subject: [PATCH mt76 v2 3/4] wifi: mt76: mt7996: Switch to the secondary
 link if the default one is removed
In-Reply-To: <20251205-mt76-txq-wicd-fix-v2-0-f19ba48af7c1@kernel.org>
References: <20251205-mt76-txq-wicd-fix-v2-0-f19ba48af7c1@kernel.org>
Message-ID: <20251205-mt76-txq-wicd-fix-v2-3-f19ba48af7c1@kernel.org>

Switch to the secondary link if available in mt7996_mac_sta_remove_links
routine if the primary one is removed.
Moreover reset secondary link index for single link scenario.

Fixes: 85cd5534a3f2e ("wifi: mt76: mt7996: use correct link_id when filling TXD and TXP")
Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
---
 drivers/net/wireless/mediatek/mt76/mt7996/mac.c  | 12 +++---
 drivers/net/wireless/mediatek/mt76/mt7996/main.c | 52 ++++++++++++++++--------
 2 files changed, 41 insertions(+), 23 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
index 2560e2f46e89a4bc46e21d796fca80b7decefa5c..4d33265971e2e00c788541a5c780dc20619e7396 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
@@ -2403,14 +2403,12 @@ mt7996_mac_reset_sta_iter(void *data, struct ieee80211_sta *sta)
 			continue;
 
 		mt7996_mac_sta_deinit_link(dev, msta_link);
-
-		if (msta->deflink_id == i) {
-			msta->deflink_id = IEEE80211_LINK_UNSPECIFIED;
-			continue;
-		}
-
-		kfree_rcu(msta_link, rcu_head);
+		if (msta_link != &msta->deflink)
+			kfree_rcu(msta_link, rcu_head);
 	}
+
+	msta->deflink_id = IEEE80211_LINK_UNSPECIFIED;
+	msta->seclink_id = msta->deflink_id;
 }
 
 static void
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index 8bf85a9beee7dc8c6741568af5b36cf89f0c1a88..1baace971ec3511dba3e8a64c236a2b55f9dbd36 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -945,6 +945,22 @@ mt7996_channel_switch_beacon(struct ieee80211_hw *hw,
 	mutex_unlock(&dev->mt76.mutex);
 }
 
+static void
+mt7996_sta_init_txq_wcid(struct ieee80211_sta *sta, int idx)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
+		struct mt76_txq *mtxq;
+
+		if (!sta->txq[i])
+			continue;
+
+		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
+		mtxq->wcid = idx;
+	}
+}
+
 static int
 mt7996_mac_sta_init_link(struct mt7996_dev *dev,
 			 struct ieee80211_bss_conf *link_conf,
@@ -962,21 +978,10 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev,
 		return -ENOSPC;
 
 	if (msta->deflink_id == IEEE80211_LINK_UNSPECIFIED) {
-		int i;
-
 		msta_link = &msta->deflink;
 		msta->deflink_id = link_id;
 		msta->seclink_id = msta->deflink_id;
-
-		for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
-			struct mt76_txq *mtxq;
-
-			if (!sta->txq[i])
-				continue;
-
-			mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
-			mtxq->wcid = idx;
-		}
+		mt7996_sta_init_txq_wcid(sta, idx);
 	} else {
 		msta_link = kzalloc(sizeof(*msta_link), GFP_KERNEL);
 		if (!msta_link)
@@ -1058,13 +1063,28 @@ mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif,
 
 		mphy->num_sta--;
 		if (msta->deflink_id == link_id) {
-			msta->deflink_id = IEEE80211_LINK_UNSPECIFIED;
-			continue;
+			if (msta->seclink_id == msta->deflink_id) {
+				/* no secondary link available */
+				msta->deflink_id = IEEE80211_LINK_UNSPECIFIED;
+				msta->seclink_id = msta->deflink_id;
+			} else {
+				struct mt7996_sta_link *msta_seclink;
+
+				/* switch to the secondary link */
+				msta->deflink_id = msta->seclink_id;
+				msta_seclink = mt76_dereference(
+						msta->link[msta->seclink_id],
+						mdev);
+				if (msta_seclink)
+					mt7996_sta_init_txq_wcid(sta,
+						msta_seclink->wcid.idx);
+			}
 		} else if (msta->seclink_id == link_id) {
-			msta->seclink_id = IEEE80211_LINK_UNSPECIFIED;
+			msta->seclink_id = msta->deflink_id;
 		}
 
-		kfree_rcu(msta_link, rcu_head);
+		if (msta_link != &msta->deflink)
+			kfree_rcu(msta_link, rcu_head);
 	}
 }
 

-- 
2.52.0



From lorenzo at kernel.org  Fri Dec  5 02:24:39 2025
From: lorenzo at kernel.org (Lorenzo Bianconi)
Date: Fri, 05 Dec 2025 11:24:39 +0100
Subject: [PATCH mt76 v2 4/4] wifi: mt76: mt7996: Clear wcid pointer in
 mt7996_mac_sta_deinit_link()
In-Reply-To: <20251205-mt76-txq-wicd-fix-v2-0-f19ba48af7c1@kernel.org>
References: <20251205-mt76-txq-wicd-fix-v2-0-f19ba48af7c1@kernel.org>
Message-ID: <20251205-mt76-txq-wicd-fix-v2-4-f19ba48af7c1@kernel.org>

Clear WCID pointer removing the sta link in mt7996_mac_sta_deinit_link
routine.

Fixes: dd82a9e02c054 ("wifi: mt76: mt7996: Rely on mt7996_sta_link in sta_add/sta_remove callbacks")
Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
---
 drivers/net/wireless/mediatek/mt76/mt7996/main.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index 1baace971ec3511dba3e8a64c236a2b55f9dbd36..78151197feccb0197e44f3f73c0f01c4589314ae 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -1027,6 +1027,7 @@ void mt7996_mac_sta_deinit_link(struct mt7996_dev *dev,
 		list_del_init(&msta_link->rc_list);
 	spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
+	rcu_assign_pointer(dev->mt76.wcid[msta_link->wcid.idx], NULL);
 	mt76_wcid_cleanup(&dev->mt76, &msta_link->wcid);
 	mt76_wcid_mask_clear(dev->mt76.wcid_mask, msta_link->wcid.idx);
 }

-- 
2.52.0



From leo.yan at arm.com  Fri Dec  5 02:27:20 2025
From: leo.yan at arm.com (Leo Yan)
Date: Fri, 5 Dec 2025 10:27:20 +0000
Subject: [PATCH v6 2/2] coresight: cti: Add Qualcomm extended CTI support
In-Reply-To: <CAJ9a7VgV6chvWmeG2xta11YqyNpdRZqx4=EF7vC7k=J2utpRYQ@mail.gmail.com>
References: <20251202-extended_cti-v6-0-ab68bb15c4f5@oss.qualcomm.com>
 <20251202-extended_cti-v6-2-ab68bb15c4f5@oss.qualcomm.com>
 <20251203182944.GG724103@e132581.arm.com>
 <CAJ9a7VhcSxTTaxMR4SS+GbHoPHXm0honykjXy92fbv0HG=1o4Q@mail.gmail.com>
 <20251204104713.GL724103@e132581.arm.com>
 <CAJ9a7VgV6chvWmeG2xta11YqyNpdRZqx4=EF7vC7k=J2utpRYQ@mail.gmail.com>
Message-ID: <20251205102720.GP724103@e132581.arm.com>

On Thu, Dec 04, 2025 at 03:07:10PM +0000, Mike Leach wrote:

[...]

> > > > > +             /*
> > > > > +              * QCOM CTI does not implement Claimtag functionality as
> > > > > +              * per CoreSight specification, but its CLAIMSET register
> > > > > +              * is incorrectly initialized to 0xF. This can mislead
> > > > > +              * tools or drivers into thinking the component is claimed.
> > > > > +              *
> > > > > +              * Reset CLAIMSET to 0 to reflect that no claims are active.
> > > > > +              */
> > > > > +             writel_relaxed(0, drvdata->base + CORESIGHT_CLAIMSET);
> > > >
> > > > I am confused for this.  If QCOM CTI does not implement claim tag,
> > > > then what is the designed register at the offset CORESIGHT_CLAIMSET?
> > > >
> > > > Should you bypass all claim tag related operations for QCOM CTI case?
> > > > (I don't see you touch anything for claim and declaim tags).
> > > >
> > >
> > > The patch I have created to handle systems without correct claim tag
> > > operation is a dependency for this patch set. Thus no need for
> > > override here as the core code will handle this correctly.
> > >
> > > The only issue is ensuring the non-CTI spec implementation will result
> > > in the correct detection of no claim tags present.
> >
> > Your patch works only when a module has implemented claim registers.
> >
> 
> Per the Coresight spec - unimplemented registers must be RAZ/WI- so
> this still works for non implemented claim registers.

QCOM CTI does not follow the spec in two aspects:

- Given the patch's comment: "QCOM CTI does not implement Claim tag
  functionality as per CoreSight specification", I am suspect the CLAIM
  registers are not implemented at all in QCOM CTI.

- It neither follows up the "unimplemented registers must be RAZ/WI" -
  the patch says its reset value is 0xF and then even can write 0 to it.

> > This leads to two issues: we end up clearing an unknown register in the
> > CTI driver, and then the coresight core layer assumes it is reading a
> > claim register even though it is not.
> 
> Again RAZ will simply read 0x0 - which is an indication that there are
> no claim bits implemented.
> 
> >
> > For QCOM CTI, combined with your patch, I would suggest directly
> > setting csdev->access.claim_tag_impl to false (perhaps using a helper).
> 
> That would be a better solution, though as Qcom appear to have
> implemented a pair of standard RW registers rather than the claim tag
> functionality, the write solution works for this particular
> implementation.

If an IP violates both the rules for implemented claim registers and
the rules for non-implemented claim registers, how can we rely on
these registers to detect the claim feature?

My feeling is we are building a house on sand - these registers are not
used for claim tags purpose at all.

Thanks,
Leo


From a.shimko.dev at gmail.com  Fri Dec  5 02:36:23 2025
From: a.shimko.dev at gmail.com (Artem Shimko)
Date: Fri, 5 Dec 2025 13:36:23 +0300
Subject: [PATCH v4] firmware: arm_scmi: refactor reset domain handling
In-Reply-To: <20251204-slick-granite-chameleon-58ebc2@sudeepholla>
References: <aRW4PpPjVw1-melm@pluto> <20251123163557.230530-1-a.shimko.dev@gmail.com>
 <20251204-slick-granite-chameleon-58ebc2@sudeepholla>
Message-ID: <CAOPX747pTsnTzKnaai-ytnmcf6reraTTSk+mssvHri4GMhCsOA@mail.gmail.com>

On Thu, Dec 4, 2025 at 7:26?PM Sudeep Holla <sudeep.holla at arm.com> wrote:
>
> On Sun, Nov 23, 2025 at 07:35:57PM +0300, Artem Shimko wrote:
> > Improve the SCMI reset protocol implementation by centralizing domain
> > validation and enhancing error handling.
> >
> > Add scmi_reset_domain_lookup() helper function to validate
> > domain ids and return appropriate error codes. Refactor all
> > domain-specific functions to use this helper, ensuring consistent
> > error handling throughout the reset protocol.
> >
> > Suggested-by: Cristian Marussi <cristian.marussi at arm.com>
> > Signed-off-by: Artem Shimko <a.shimko.dev at gmail.com>
> > ---
> >
> > Hi Cristian,
> >
> > Thank you for suggesting! If it works for you I'll try to improve the others protocols.
> >
> > It was tested on my board in QEMU and on real hardware.
> > The functionality didn't break, and peripherals that are reseted via SCMI work correctly.
> >
> > As an example, I can provide DMA test results (as one of the processor units dependent on SCMI reset).
> >
> > [    2.559040] dw_axi_dmac_platform 1000nda0.nda_dma_0: DesignWare AXI DMA Controller, nda channels
> > [    2.569265] dw_axi_dmac_platform 1000nda0.nda_dma_1: DesignWare AXI DMA Controller, nda channels
> > [    2.580601] dw_axi_dmac_platform 1000nda0.nda_dma_2: DesignWare AXI DMA Controller, nda channels
> >
> > # echo 2000 > /sys/module/dmatest/parameters/timeout
> > # echo 1000 > /sys/module/dmatest/parameters/iterations
> > # echo dma0chan0 > /sys/module/dmatest/parameters/channel
> > [   95.917504] dmatest: Added 1 threads using dma0chan0
> > # echo 1 > /sys/module/dmatest/parameters/run
> > [  101.931372] dmatest: Started 1 threads using dma0chan0
> > [  102.731009] dmatest: dma0chan0-copy0: summary 1000 tests, 0 failures 2508.42 iops 19706 KB/s (0)
> >
> > And vice versa:
> >
> > 1. Confirmed that the DMA module is non-functional without a proper reset via SCMI.
> > Disabling the reset logic causes a system crash on first access to its registers.
> >
> > 2. Requesting a non-existent reset domain:
> >
> > [    2.463400] dw_axi_dmac_platform 1000nda0.nda_dma_0: error -EINVAL: Failed to deassert resets
> > [    2.472091] dw_axi_dmac_platform 1000nda0.nda_dma_0: probe with driver dw_axi_dmac_platform failed with error -22
> > [    2.482911] dw_axi_dmac_platform 1000nda0.nda_dma_1: error -EINVAL: Failed to deassert resets
> > [    2.491553] dw_axi_dmac_platform 1000nda0.nda_dma_1: probe with driver dw_axi_dmac_platform failed with error -22
> > [    2.502256] dw_axi_dmac_platform 1000nda0.nda_dma_2: error -EINVAL: Failed to deassert resets
> > [    2.510735] dw_axi_dmac_platform 1000nda0.nda_dma_2: probe with driver dw_axi_dmac_platform failed with error -22
> >
> > --
> > Regards,
> > Artem
> >
> > ---
> > ChangeLog:
> >   v4: Add Suggested-by tag
> >
> >  drivers/firmware/arm_scmi/reset.c | 59 ++++++++++++++++++++-----------
> >  1 file changed, 39 insertions(+), 20 deletions(-)
> >
> > diff --git a/drivers/firmware/arm_scmi/reset.c b/drivers/firmware/arm_scmi/reset.c
> > index 0aa82b96f41b..9854a3016d13 100644
> > --- a/drivers/firmware/arm_scmi/reset.c
> > +++ b/drivers/firmware/arm_scmi/reset.c
> > @@ -100,6 +100,7 @@ static int scmi_reset_attributes_get(const struct scmi_protocol_handle *ph,
> >
> >  static int
> >  scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph,
> > +                              struct reset_dom_info *dom_info,
>
> Instead of changing this, ...
>
> >                                struct scmi_reset_info *pinfo,
> >                                u32 domain, u32 version)
> >  {
> > @@ -107,7 +108,6 @@ scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph,
> >       u32 attributes;
> >       struct scmi_xfer *t;
> >       struct scmi_msg_resp_reset_domain_attributes *attr;
> > -     struct reset_dom_info *dom_info = pinfo->dom_info + domain;
> >
>
> ... You can just follow the pattern you have done everywhere else in this
> change like:
>
> struct reset_dom_info *dom_info;
>
> dom_info = scmi_reset_domain_lookup(ph, domain);
> if (IS_ERR(dom_info))
>         return PTR_ERR(dom_info);
>
> Any particular reason for not doing that ?

Hi Sudeep,

Based on perf.c, I added this pattern only to functions that can be
called externally with an invalid domain value.
Therefore, I decided it would be better to change the signature of
scmi_reset_domain_attributes_get (similar to
scmi_perf_domain_attributes_get from pref.c)
to ensure consistency across drivers when working with domain numbers.

If you believe this pattern should be used in
scmi_reset_domain_attributes_get, I'll send you the next version of
the patch.

Thank you very much for reviewing my changes =)

Regards,
Artem


From heikki.krogerus at linux.intel.com  Fri Dec  5 02:50:04 2025
From: heikki.krogerus at linux.intel.com (Heikki Krogerus)
Date: Fri, 5 Dec 2025 12:50:04 +0200
Subject: [RESEND PATCH v11 03/11] drm/bridge: Implement generic USB
 Type-C DP HPD bridge
In-Reply-To: <84f06c0f-3ec7-4a43-bba2-1979c3a07127@rock-chips.com>
References: <20251204063109.104-1-kernel@airkyi.com>
 <20251204063109.104-4-kernel@airkyi.com>
 <aTGPaJmwd7uHfrnV@kuha>
 <84f06c0f-3ec7-4a43-bba2-1979c3a07127@rock-chips.com>
Message-ID: <aTK4n8WnQm_FvpW3@kuha>

Fri, Dec 05, 2025 at 10:26:20AM +0800, Chaoyi Chen kirjoitti:
> Hi Heikki,
> 
> On 12/4/2025 9:40 PM, Heikki Krogerus wrote:
> > Hi,
> > 
> > I don't know what's going on here - this series is the 12th?
> > In any case, you need to fix this..
> > 
> 
> It is 11th. Patch 1 was missing the Signed-off-by line, so I've resent
> it. Sorry for the confusion.

That's a change too, i.e. this is v12.

> >> diff --git a/drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c b/drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c
> >> new file mode 100644
> >> index 000000000000..94be3d5f69e9
> >> --- /dev/null
> >> +++ b/drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c
> >> @@ -0,0 +1,51 @@
> >> +// SPDX-License-Identifier: GPL-2.0+
> >> +#include <linux/of.h>
> >> +#include <linux/usb/typec_altmode.h>
> >> +#include <linux/usb/typec_dp.h>
> >> +
> >> +#include <drm/bridge/aux-bridge.h>
> >> +
> >> +static int drm_typec_bus_event(struct notifier_block *nb,
> >> +			       unsigned long action, void *data)
> >> +{
> >> +	struct device *dev = (struct device *)data;
> >> +	struct typec_altmode *alt = to_typec_altmode(dev);
> >> +
> >> +	if (action != BUS_NOTIFY_ADD_DEVICE)
> >> +		goto done;
> >> +
> >> +	if (is_typec_partner_altmode(&alt->dev) || alt->svid != USB_TYPEC_DP_SID)
> >> +		goto done;
> > 
> > That's still not enough because of the plug altmodes. You need to
> > check that it's a port altmode:
> > 
> >         if (is_typec_port_altmode(&alt->dev) && alt->svid == USB_TYPEC_DP_SID)
> >         	drm_dp_hpd_bridge_register(alt->dev.parent->parent,
> >         				   to_of_node(alt->dev.parent->fwnode));
> >
> 
> Oh, it is. Will fix in v12. Thank you.

v13. Don't forget to update changelog.

thanks,

-- 
heikki


From konrad.dybcio at oss.qualcomm.com  Fri Dec  5 03:58:27 2025
From: konrad.dybcio at oss.qualcomm.com (Konrad Dybcio)
Date: Fri, 5 Dec 2025 12:58:27 +0100
Subject: [PATCH v6 2/3] arm64: dts: qcom: qcs8300: Add CCI definitions
In-Reply-To: <3f1dbf91-f967-44dc-bb21-25fdcbbc8db2@quicinc.com>
References: <DS0PR02MB11311CE33DFFE0739BE747590E3D8A@DS0PR02MB11311.namprd02.prod.outlook.com>
 <d49920eb-0b4e-4042-b0c6-28d1ba348ddc@quicinc.com>
 <3f1dbf91-f967-44dc-bb21-25fdcbbc8db2@quicinc.com>
Message-ID: <6e6ecdbf-f3cb-4d7e-a679-4640d6603ac8@oss.qualcomm.com>

On 12/2/25 8:35 AM, Nihal Kumar Gupta wrote:
> 
> 
> On 11/26/25 9:10 AM, Vikram Sharma wrote:
>>> From: Nihal Kumar Gupta <quic_nihalkum at quicinc.com>
>>>
>>> Qualcomm QCS8300 SoC contains three Camera Control Interface (CCI).
>>> Compared to Lemans, the key difference is in SDA/SCL GPIO assignments
>>> and number of CCIs.
>> [...]
>>
>>> @@ -5071,6 +5182,240 @@ tlmm: pinctrl at f100000 {
>>>                       #interrupt-cells = <2>;
>>>                       wakeup-parent = <&pdc>;
>>>
>>> +                     cam0_avdd_2v8_en_default: cam0-avdd-2v8-en-state {
>>> +                             pins = "gpio73";
>>> +                             function = "gpio";
>>> +                             drive-strength = <2>;
>>> +                             bias-disable;
>>> +                     };
>> I'm not sure whether I was unclear, but my intention was to ask you to move the MCLK pin definitions to the SoC DTSI, because that comes from the design of the platform and doesn't vary between end products.
>>
>> GPIO_73 being related to a voltage regulator is strictly a property of the EVK.
> 
> MCLK pin definitions are already present under the tlmm block in SoC dtsi(monaco.dtsi) as required by the pinctrl subsystem(qcom,qcs8300-tlmm.yaml).

The latter part of your sentence refers to the pin definition having to end
up under TLMM in the final DT, which it will be regardless of where exactly
in the source files it appears.

What I'm alluding to is that we organize some of these definitions in a
specific source file to make logical sense and keep them within relevant
scope (i.e. you shouldn't be able to refer to a board X-specific setting
from board Y DT - that's unnecessary room for error, whereas pin definitions
that are a result of the SoC design make sense to be shared)

> Are you suggesting they shouldn?t be part of TLMM in the SoC DTSI? This doesn?t align with the YAML file.

That's not exactly true, the YAML file you're referencing only lists the
allowed entries in the 'function' property of the pinmux subnodes.

The DT checker makes no effort to analyze your file structure, it only
makes sure that you're not adding illegal properties (or lacking required
ones) for a given device described by a binding.

> Regarding GPIO_73: Noted. I will move it to monaco-evk.dts under the tlmm section.
> 
> Below are the example snippets:
> In monaco.dtsi (SoC level):
> tlmm: pinctrl at ... {
>     cam_mclk0_default: cam-mclk0-default-state {
>         pins = "gpio67"; 
>         function = "cam_mclk";
>         drive-strength = <2>;
>     };
>     ....
> };
> 
> In monaco-evk.dts (Board level):
> &tlmm {
>     cam0_avdd_2v8_en_default: cam0-avdd-2v8-en-state {
>         pins = "gpio73";
>         function = "gpio";
>         drive-strength = <2>;
>         bias-disable;
>     };

That was my entire points, thanks

Konrad


From linux at armlinux.org.uk  Fri Dec  5 04:08:14 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Fri, 5 Dec 2025 12:08:14 +0000
Subject: [Bug report] hash_name() may cross page boundary and trigger
 sleep in RCU context
In-Reply-To: <20251203014800.4988-1-xieyuanbin1@huawei.com>
References: <CAHk-=wg4ZnsfpgXYL5qhjYDYo1Gnssz+VxnKZzHXMEmE7qrnQQ@mail.gmail.com>
 <20251203014800.4988-1-xieyuanbin1@huawei.com>
Message-ID: <aTLLLuup7TeAqFVL@shell.armlinux.org.uk>

On Wed, Dec 03, 2025 at 09:48:00AM +0800, Xie Yuanbin wrote:
> On Tue, 2 Dec 2025 14:07:25 -0800, Linus Torvalds wrote:
> > On Tue, 2 Dec 2025 at 04:43, Russell King (Oracle)
> > <linux at armlinux.org.uk> wrote:
> >>
> >> What I'm thinking is to address both of these by handling kernel space
> >> page faults (which will be permission or PTE-not-present) separately
> >> (not even build tested):
> >
> > That patch looks sane to me.
> >
> > But I also didn't build test it, just scanned it visually ;)
> 
> That patch removes harden_branch_predictor() from __do_user_fault(), and
> moves it to do_page_fault()->do_kernel_address_page_fault(). 
> This resolves previously mentioned kernel warning issue. However,
> __do_user_fault() is not only called by do_page_fault(), it is
> alse called by do_bad_area(), do_sect_fault() and do_translation_fault().
> 
> So I think that some harden_branch_predictor() is missing on other paths.
> According to my tests, when CONFIG_ARM_LPAE=n, harden_branch_predictor()
> will never be called anymore, even if a user program trys to access the
> kernel address.
> 
> Or perhaps I've misunderstood something, could you please point it out?
> Thank you very much.

Right, let's split these issues into separate patches. Please test this
patch, which should address only the hash_name() fault issue, and
provides the basis for fixing the branch predictor issue.

Yes, at the moment, do_kernel_address_page_fault() looks very much like
do_bad_area(), but with the addition of the IRQ-enable if the parent
context was enabled, but the following patch to address the branch
predictor hardening will show why its different.

In my opinion, this approach makes the handling for kernel address
page faults (non-present pages and page permission faults) much easier
to understand.

Note that this will call __do_user_fault() with interrupts disabled.

Build tested, and remotely boot tested on Cortex-A5 hardware but
without kfence enabled. Also tested usermode access to kernel space
which fails with SEGV:
- read from 0xc0000000 (section permission fault, do_sect_fault)
- read from 0xffff2000 (page translation fault, do_page_fault)
- read from 0xffff0000 (vectors page - read possible as expected)
- write to 0xffff0000 (page permission fault, do_page_fault)

8<===
From: "Russell King (Oracle)" <rmk+kernel at armlinux.org.uk>
Subject: [PATCH] ARM: fix hash_name() fault

Zizhi Wo reports:

"During the execution of hash_name()->load_unaligned_zeropad(), a
 potential memory access beyond the PAGE boundary may occur. For
 example, when the filename length is near the PAGE_SIZE boundary.
 This triggers a page fault, which leads to a call to
 do_page_fault()->mmap_read_trylock(). If we can't acquire the lock,
 we have to fall back to the mmap_read_lock() path, which calls
 might_sleep(). This breaks RCU semantics because path lookup occurs
 under an RCU read-side critical section."

This is seen with CONFIG_DEBUG_ATOMIC_SLEEP=y and CONFIG_KFENCE=y.

Kernel addresses (with the exception of the vectors/kuser helper
page) do not have VMAs associated with them. If the vectors/kuser
helper page faults, then there are two possibilities:

1. if the fault happened while in kernel mode, then we're basically
   dead, because the CPU won't be able to vector through this page
   to handle the fault.
2. if the fault happened while in user mode, that means the page was
   protected from user access, and we want to fault anyway.

Thus, we can handle kernel addresses from any context entirely
separately without going anywhere near the mmap lock. This gives us
an entirely non-sleeping path for all kernel mode kernel address
faults.

Reported-by: Zizhi Wo <wozizhi at huaweicloud.com>
Reported-by: Xie Yuanbin <xieyuanbin1 at huawei.com>
Link: https://lore.kernel.org/r/20251126090505.3057219-1-wozizhi at huaweicloud.com
Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
---
 arch/arm/mm/fault.c | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 46169fe42c61..2bbec38ced97 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -260,6 +260,35 @@ static inline bool ttbr0_usermode_access_allowed(struct pt_regs *regs)
 }
 #endif
 
+static int __kprobes
+do_kernel_address_page_fault(struct mm_struct *mm, unsigned long addr,
+			     unsigned int fsr, struct pt_regs *regs)
+{
+	if (user_mode(regs)) {
+		/*
+		 * Fault from user mode for a kernel space address. User mode
+		 * should not be faulting in kernel space, which includes the
+		 * vector/khelper page. Send a SIGSEGV.
+		 */
+		__do_user_fault(addr, fsr, SIGSEGV, SEGV_MAPERR, regs);
+	} else {
+		/*
+		 * Fault from kernel mode. Enable interrupts if they were
+		 * enabled in the parent context. Section (upper page table)
+		 * translation faults are handled via do_translation_fault(),
+		 * so we will only get here for a non-present kernel space
+		 * PTE or PTE permission fault. This may happen in exceptional
+		 * circumstances and need the fixup tables to be walked.
+		 */
+		if (interrupts_enabled(regs))
+			local_irq_enable();
+
+		__do_kernel_fault(mm, addr, fsr, regs);
+	}
+
+	return 0;
+}
+
 static int __kprobes
 do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 {
@@ -273,6 +302,12 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 	if (kprobe_page_fault(regs, fsr))
 		return 0;
 
+	/*
+	 * Handle kernel addresses faults separately, which avoids touching
+	 * the mmap lock from contexts that are not able to sleep.
+	 */
+	if (addr >= TASK_SIZE)
+		return do_kernel_address_page_fault(mm, addr, fsr, regs);
 
 	/* Enable interrupts if they were enabled in the parent context. */
 	if (interrupts_enabled(regs))
-- 
2.47.3

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From sudeep.holla at arm.com  Fri Dec  5 04:14:07 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Fri, 5 Dec 2025 12:14:07 +0000
Subject: [PATCH v4] firmware: arm_scmi: refactor reset domain handling
In-Reply-To: <CAOPX747pTsnTzKnaai-ytnmcf6reraTTSk+mssvHri4GMhCsOA@mail.gmail.com>
References: <aRW4PpPjVw1-melm@pluto>
 <20251123163557.230530-1-a.shimko.dev@gmail.com>
 <20251204-slick-granite-chameleon-58ebc2@sudeepholla>
 <CAOPX747pTsnTzKnaai-ytnmcf6reraTTSk+mssvHri4GMhCsOA@mail.gmail.com>
Message-ID: <20251205-calculating-unique-ibex-de824e@sudeepholla>

On Fri, Dec 05, 2025 at 01:36:23PM +0300, Artem Shimko wrote:
> On Thu, Dec 4, 2025 at 7:26?PM Sudeep Holla <sudeep.holla at arm.com> wrote:
> >
> > On Sun, Nov 23, 2025 at 07:35:57PM +0300, Artem Shimko wrote:
> > > Improve the SCMI reset protocol implementation by centralizing domain
> > > validation and enhancing error handling.
> > >
> > > Add scmi_reset_domain_lookup() helper function to validate
> > > domain ids and return appropriate error codes. Refactor all
> > > domain-specific functions to use this helper, ensuring consistent
> > > error handling throughout the reset protocol.
> > >
> > > Suggested-by: Cristian Marussi <cristian.marussi at arm.com>
> > > Signed-off-by: Artem Shimko <a.shimko.dev at gmail.com>
> > > ---
> > >
> > > Hi Cristian,
> > >
> > > Thank you for suggesting! If it works for you I'll try to improve the others protocols.
> > >
> > > It was tested on my board in QEMU and on real hardware.
> > > The functionality didn't break, and peripherals that are reseted via SCMI work correctly.
> > >
> > > As an example, I can provide DMA test results (as one of the processor units dependent on SCMI reset).
> > >
> > > [    2.559040] dw_axi_dmac_platform 1000nda0.nda_dma_0: DesignWare AXI DMA Controller, nda channels
> > > [    2.569265] dw_axi_dmac_platform 1000nda0.nda_dma_1: DesignWare AXI DMA Controller, nda channels
> > > [    2.580601] dw_axi_dmac_platform 1000nda0.nda_dma_2: DesignWare AXI DMA Controller, nda channels
> > >
> > > # echo 2000 > /sys/module/dmatest/parameters/timeout
> > > # echo 1000 > /sys/module/dmatest/parameters/iterations
> > > # echo dma0chan0 > /sys/module/dmatest/parameters/channel
> > > [   95.917504] dmatest: Added 1 threads using dma0chan0
> > > # echo 1 > /sys/module/dmatest/parameters/run
> > > [  101.931372] dmatest: Started 1 threads using dma0chan0
> > > [  102.731009] dmatest: dma0chan0-copy0: summary 1000 tests, 0 failures 2508.42 iops 19706 KB/s (0)
> > >
> > > And vice versa:
> > >
> > > 1. Confirmed that the DMA module is non-functional without a proper reset via SCMI.
> > > Disabling the reset logic causes a system crash on first access to its registers.
> > >
> > > 2. Requesting a non-existent reset domain:
> > >
> > > [    2.463400] dw_axi_dmac_platform 1000nda0.nda_dma_0: error -EINVAL: Failed to deassert resets
> > > [    2.472091] dw_axi_dmac_platform 1000nda0.nda_dma_0: probe with driver dw_axi_dmac_platform failed with error -22
> > > [    2.482911] dw_axi_dmac_platform 1000nda0.nda_dma_1: error -EINVAL: Failed to deassert resets
> > > [    2.491553] dw_axi_dmac_platform 1000nda0.nda_dma_1: probe with driver dw_axi_dmac_platform failed with error -22
> > > [    2.502256] dw_axi_dmac_platform 1000nda0.nda_dma_2: error -EINVAL: Failed to deassert resets
> > > [    2.510735] dw_axi_dmac_platform 1000nda0.nda_dma_2: probe with driver dw_axi_dmac_platform failed with error -22
> > >
> > > --
> > > Regards,
> > > Artem
> > >
> > > ---
> > > ChangeLog:
> > >   v4: Add Suggested-by tag
> > >
> > >  drivers/firmware/arm_scmi/reset.c | 59 ++++++++++++++++++++-----------
> > >  1 file changed, 39 insertions(+), 20 deletions(-)
> > >
> > > diff --git a/drivers/firmware/arm_scmi/reset.c b/drivers/firmware/arm_scmi/reset.c
> > > index 0aa82b96f41b..9854a3016d13 100644
> > > --- a/drivers/firmware/arm_scmi/reset.c
> > > +++ b/drivers/firmware/arm_scmi/reset.c
> > > @@ -100,6 +100,7 @@ static int scmi_reset_attributes_get(const struct scmi_protocol_handle *ph,
> > >
> > >  static int
> > >  scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph,
> > > +                              struct reset_dom_info *dom_info,
> >
> > Instead of changing this, ...
> >
> > >                                struct scmi_reset_info *pinfo,
> > >                                u32 domain, u32 version)
> > >  {
> > > @@ -107,7 +108,6 @@ scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph,
> > >       u32 attributes;
> > >       struct scmi_xfer *t;
> > >       struct scmi_msg_resp_reset_domain_attributes *attr;
> > > -     struct reset_dom_info *dom_info = pinfo->dom_info + domain;
> > >
> >
> > ... You can just follow the pattern you have done everywhere else in this
> > change like:
> >
> > struct reset_dom_info *dom_info;
> >
> > dom_info = scmi_reset_domain_lookup(ph, domain);
> > if (IS_ERR(dom_info))
> >         return PTR_ERR(dom_info);
> >
> > Any particular reason for not doing that ?
> 
> Hi Sudeep,
> 
> Based on perf.c, I added this pattern only to functions that can be
> called externally with an invalid domain value.
> Therefore, I decided it would be better to change the signature of
> scmi_reset_domain_attributes_get (similar to
> scmi_perf_domain_attributes_get from pref.c)
> to ensure consistency across drivers when working with domain numbers.
> 
> If you believe this pattern should be used in
> scmi_reset_domain_attributes_get, I'll send you the next version of
> the patch.
>

No need to post yet, I fixed it up here[1], let's see if Cristian agrees
with that. Let me know if you are happy too with that change. I will rebase
at -rc1 and apply it officially then.

-- 
Regards,
Sudeep

[1] https://git.kernel.org/sudeep.holla/c/8bc55f21a345


From robh at kernel.org  Fri Dec  5 04:31:37 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Fri, 05 Dec 2025 06:31:37 -0600
Subject: [PATCH v3 3/3] dt-bindings: hwmon: (aspeed,g5-pwm-tacho) Move
 info from txt to yaml
In-Reply-To: <20251204210238.40742-4-rebecca@bsdio.com>
References: <20251204210238.40742-1-rebecca@bsdio.com>
 <20251204210238.40742-4-rebecca@bsdio.com>
Message-ID: <176493761251.3641290.13291920660908033862.robh@kernel.org>


On Thu, 04 Dec 2025 14:02:36 -0700, Rebecca Cran wrote:
> Move the documentation for the aspeed,ast2400-pwm-tacho and
> aspeed,ast2500-pwm-tacho devices from a text file to yaml file.
> 
> This allows for dts files containing these devices to be validated.
> 
> Where the text file documenation of required properties differ from the
> implementation, prefer the implementation and update the schema to
> match.
> 
> "#size-cells" was 1 but implementation is 0.
> "#cooling-cells" was marked as required but appears optional.
> 
> In the fan subnode, "cooling-levels" is optional according to the code
> in drivers/hwmon/aspeed-pwm-tacho.c.
> 
> Signed-off-by: Rebecca Cran <rebecca at bsdio.com>
> ---
>  Documentation/devicetree/bindings/hwmon/aspeed,pwm-tacho.yaml | 91 ++++++++++++++++++++
>  Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt  | 73 ----------------
>  2 files changed, 91 insertions(+), 73 deletions(-)
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/hwmon/aspeed,pwm-tacho.yaml: $id: Cannot determine base path from $id, relative path/filename doesn't match actual path or filename
 	 $id: http://devicetree.org/schemas/hwmon/aspeed,g5-pwm-tacho.yaml
 	file: /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/hwmon/aspeed,pwm-tacho.yaml
cooling-levels: size (6) error for type uint32-array
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/hwmon/aspeed,pwm-tacho.example.dtb: pwmtachocontroller at 1e786000 (aspeed,ast2500-pwm-tacho): '#cooling-cells' does not match any of the regexes: '^fan@[0-9]+$', '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/hwmon/aspeed,g5-pwm-tacho.yaml
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/hwmon/aspeed,pwm-tacho.example.dtb: pwmtachocontroller at 1e786000 (aspeed,ast2500-pwm-tacho): fan at 0:cooling-levels: b'}\x97\xb1\xcb\xe5\xff' is not of type 'array'
	from schema $id: http://devicetree.org/schemas/hwmon/aspeed,g5-pwm-tacho.yaml
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/hwmon/aspeed,pwm-tacho.example.dtb: fan at 0: cooling-levels: b'}\x97\xb1\xcb\xe5\xff' is not of type 'object', 'integer', 'array', 'boolean', 'null'
	from schema $id: http://devicetree.org/schemas/dt-core.yaml

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20251204210238.40742-4-rebecca at bsdio.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.



From parvathi at couthit.com  Fri Dec  5 04:29:10 2025
From: parvathi at couthit.com (Parvathi Pudi)
Date: Fri,  5 Dec 2025 17:59:10 +0530
Subject: [RFC PATCH net-next v9 0/3] STP/RSTP SWITCH support for PRU-ICSSM Ethernet driver
Message-ID: <20251205123146.462397-1-parvathi@couthit.com>

Hi,

The DUAL-EMAC patch series for Megabit Industrial Communication Sub-system
(ICSSM), which provides the foundational support for Ethernet functionality
over PRU-ICSS on the TI SOCs (AM335x, AM437x, and AM57x), was merged into
net-next recently [1].

This patch series enhances the PRU-ICSSM Ethernet driver to support bridge
(STP/RSTP) SWITCH mode, which has been implemented using the "switchdev"
framework and interacts with the "mstp daemon" for STP and RSTP management
in userspace.

When the  SWITCH mode is enabled, forwarding of Ethernet packets using
either the traditional store-and-forward mechanism or via cut-through is
offloaded to the two PRU based Ethernet interfaces available within the
ICSSM. The firmware running on the PRU inspects the bridge port states and
performs necessary checks before forwarding a packet. This improves the
overall system performance and significantly reduces the packet forwarding
latency.

Protocol switching from Dual-EMAC to bridge (STP/RSTP) SWITCH mode can be
done as follows.

Assuming eth2 and eth3 are the two physical ports of the ICSS2 instance:

>> brctl addbr br0
>> ip maddr add 01:80:c2:00:00:00 dev br0
>> ip link set dev br0 address $(cat /sys/class/net/eth2/address)
>> brctl addif br0 eth2
>> brctl addif br0 eth3
>> mstpd
>> brctl stp br0 on
# STP to RSTP mode
>> mstpctl setforcevers br0 rstp
>> ip link set dev br0 up

To revert back to the default dual EMAC mode, the steps are as follows:

>> ip link set dev br0 down
>> brctl delif br0 eth2
>> brctl delif br0 eth3
>> brctl delbr br0

The patches presented in this series have gone through the patch verification
tools and no warnings or errors are reported.

Sample test logs obtained from AM33x, AM43x and AM57x verifying the
functionality on Linux next kernel are available here:

[Interface up Testing](https://gist.github.com/ParvathiPudi/dec8bd097ae1bc2670eae3018ecf2706)

[Ping Testing](https://gist.github.com/ParvathiPudi/8ca7d7a6e58df812dd31cbd0bd51696d)

[Iperf Testing](https://gist.github.com/ParvathiPudi/49687cb411f1459cf1ab7eb82b359e6f)

[1] https://lore.kernel.org/all/20250912104741.528721-1-parvathi at couthit.com/

This is the v9 of the patch series [v1]. This version of the patchset
addresses the comments made on [v8] of the series.

Changes from v8 to v9:

*) Added RFC tag as net-next is closed now.
*) Addressed  Jakub Kicinski comments on patch 1 and 2 of the series.
*) Rebased the series on latest net-next.

Changes from v7 to v8:

*) Modified dev_hold/dev_put reference to netdev_hold/netdev_put in patch 2 of the series.
*) Rebased the series on latest net-next.

Changes from v6 to v7:

*) Addressed Jakub Kicinski comments on patch 2 of the series.
*) Rebased the series on latest net-next.

Changes from v5 to v6:

*) Addressed Simon Horman comments on patch 1, 2 and 3 of the series.
*) Rebased the series on latest net-next.

Changes from v4 to v5:

*) Addressed ALOK TIWARI comments on patch 1 of the series.
*) Rebased the series on latest net-next.

Changes from v3 to v4:

*) Addressed Andrew Lunn comments on patch 1 and 2 of the series.
*) Rebased the series on latest net-next.

Changes from v2 to v3:

*) Dropped the RFC tag.
*) Addressed  MD Danish Anwar comments on patch 3 of the series.
*) Rebased the series on latest net-next.

Changes from v1 to v2 :

*) Added RFC tag as net-next is closed now.
*) Updated the cover letter of the series to generalize and indicate support for
both STP and RSTP along with subject change as per Andrew Lunn's suggestion.
*) Addressed the Andrew Lunn's comments on patch 1 of the series.
*) Rebased the series on latest net-next.

[v1] https://lore.kernel.org/all/20250925141246.3433603-1-parvathi at couthit.com/
[v2] https://lore.kernel.org/all/20251006104908.775891-1-parvathi at couthit.com/
[v3] https://lore.kernel.org/all/20251014124018.1596900-1-parvathi at couthit.com/
[v4] https://lore.kernel.org/all/20251110125539.31052-1-parvathi at couthit.com/
[v5] https://lore.kernel.org/all/20251113101229.675141-1-parvathi at couthit.com/
[v6] https://lore.kernel.org/all/20251124135800.2219431-1-parvathi at couthit.com/
[v7] https://lore.kernel.org/all/20251126124602.2624264-1-parvathi at couthit.com/
[v8] https://lore.kernel.org/all/20251126163056.2697668-1-parvathi at couthit.com/

Thanks and Regards,
Parvathi.

Roger Quadros (3):
  net: ti: icssm-prueth: Add helper functions to configure and maintain
    FDB
  net: ti: icssm-prueth: Add switchdev support for icssm_prueth driver
  net: ti: icssm-prueth: Add support for ICSSM RSTP switch

 drivers/net/ethernet/ti/Makefile              |    2 +-
 drivers/net/ethernet/ti/icssm/icssm_prueth.c  |  517 +++++++-
 drivers/net/ethernet/ti/icssm/icssm_prueth.h  |   20 +-
 .../ethernet/ti/icssm/icssm_prueth_fdb_tbl.h  |   76 ++
 .../ethernet/ti/icssm/icssm_prueth_switch.c   | 1060 +++++++++++++++++
 .../ethernet/ti/icssm/icssm_prueth_switch.h   |   37 +
 drivers/net/ethernet/ti/icssm/icssm_switch.h  |  103 ++
 .../net/ethernet/ti/icssm/icssm_switchdev.c   |  333 ++++++
 .../net/ethernet/ti/icssm/icssm_switchdev.h   |   13 +
 .../ti/icssm/icssm_vlan_mcast_filter_mmap.h   |  120 ++
 10 files changed, 2258 insertions(+), 23 deletions(-)
 create mode 100644 drivers/net/ethernet/ti/icssm/icssm_prueth_fdb_tbl.h
 create mode 100644 drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c
 create mode 100644 drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h
 create mode 100644 drivers/net/ethernet/ti/icssm/icssm_switchdev.c
 create mode 100644 drivers/net/ethernet/ti/icssm/icssm_switchdev.h
 create mode 100644 drivers/net/ethernet/ti/icssm/icssm_vlan_mcast_filter_mmap.h

-- 
2.43.0



From parvathi at couthit.com  Fri Dec  5 04:29:13 2025
From: parvathi at couthit.com (Parvathi Pudi)
Date: Fri,  5 Dec 2025 17:59:13 +0530
Subject: [RFC PATCH net-next v9 3/3] net: ti: icssm-prueth: Add support for ICSSM RSTP switch
In-Reply-To: <20251205123146.462397-1-parvathi@couthit.com>
References: <20251205123146.462397-1-parvathi@couthit.com>
Message-ID: <20251205123146.462397-4-parvathi@couthit.com>

From: Roger Quadros <rogerq at ti.com>

Add support for RSTP switch mode by enhancing the existing ICSSM dual EMAC
driver with switchdev support.

Enable the PRU-ICSSM to operate in switch mode, with the 2 PRU ports acting
as external ports and the host acting as an internal port. Packets received
from the PRU ports will be forwarded to the host (store and forward mode)
and also to the other PRU port (either using store and forward mode or via
cut-through mode). Packets coming from the host will be transmitted either
from one or both of the PRU ports (depending on the FDB decision).

By default, the dual EMAC firmware will be loaded in the PRU-ICSS
subsystem. To configure the PRU-ICSS to operate as a switch, a different
firmware must to be loaded.

Signed-off-by: Roger Quadros <rogerq at ti.com>
Signed-off-by: Andrew F. Davis <afd at ti.com>
Signed-off-by: Basharath Hussain Khaja <basharath at couthit.com>
Signed-off-by: Parvathi Pudi <parvathi at couthit.com>
---
 drivers/net/ethernet/ti/icssm/icssm_prueth.c  | 337 ++++++++++++++-
 drivers/net/ethernet/ti/icssm/icssm_prueth.h  |   6 +
 .../ethernet/ti/icssm/icssm_prueth_switch.c   | 385 ++++++++++++++++++
 .../ethernet/ti/icssm/icssm_prueth_switch.h   |   8 +
 drivers/net/ethernet/ti/icssm/icssm_switch.h  |  77 ++++
 5 files changed, 792 insertions(+), 21 deletions(-)

diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.c b/drivers/net/ethernet/ti/icssm/icssm_prueth.c
index b779096c09e8..b89fe71cf4a6 100644
--- a/drivers/net/ethernet/ti/icssm/icssm_prueth.c
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.c
@@ -147,7 +147,7 @@ static const struct prueth_queue_info queue_infos[][NUM_QUEUES] = {
 	},
 };
 
-static const struct prueth_queue_desc queue_descs[][NUM_QUEUES] = {
+const struct prueth_queue_desc queue_descs[][NUM_QUEUES] = {
 	[PRUETH_PORT_QUEUE_HOST] = {
 		{ .rd_ptr = P0_Q1_BD_OFFSET, .wr_ptr = P0_Q1_BD_OFFSET, },
 		{ .rd_ptr = P0_Q2_BD_OFFSET, .wr_ptr = P0_Q2_BD_OFFSET, },
@@ -207,9 +207,9 @@ static void icssm_prueth_hostconfig(struct prueth *prueth)
 
 static void icssm_prueth_mii_init(struct prueth *prueth)
 {
+	u32 txcfg_reg, txcfg, txcfg2;
 	struct regmap *mii_rt;
 	u32 rxcfg_reg, rxcfg;
-	u32 txcfg_reg, txcfg;
 
 	mii_rt = prueth->mii_rt;
 
@@ -237,17 +237,23 @@ static void icssm_prueth_mii_init(struct prueth *prueth)
 		(TX_START_DELAY << PRUSS_MII_RT_TXCFG_TX_START_DELAY_SHIFT) |
 		(TX_CLK_DELAY_100M << PRUSS_MII_RT_TXCFG_TX_CLK_DELAY_SHIFT);
 
+	txcfg2 = txcfg;
+	if (!PRUETH_IS_EMAC(prueth))
+		txcfg2 |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
+
 	/* Configuration of Port 0 Tx */
 	txcfg_reg = PRUSS_MII_RT_TXCFG0;
 
-	regmap_write(mii_rt, txcfg_reg, txcfg);
+	regmap_write(mii_rt, txcfg_reg, txcfg2);
 
-	txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
+	txcfg2 = txcfg;
+	if (PRUETH_IS_EMAC(prueth))
+		txcfg2 |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
 
 	/* Configuration of Port 1 Tx */
 	txcfg_reg = PRUSS_MII_RT_TXCFG1;
 
-	regmap_write(mii_rt, txcfg_reg, txcfg);
+	regmap_write(mii_rt, txcfg_reg, txcfg2);
 
 	txcfg_reg = PRUSS_MII_RT_RX_FRMS0;
 
@@ -294,7 +300,10 @@ static void icssm_prueth_hostinit(struct prueth *prueth)
 		icssm_prueth_clearmem(prueth, PRUETH_MEM_DRAM1);
 
 	/* Initialize host queues in shared RAM */
-	icssm_prueth_hostconfig(prueth);
+	if (!PRUETH_IS_EMAC(prueth))
+		icssm_prueth_sw_hostconfig(prueth);
+	else
+		icssm_prueth_hostconfig(prueth);
 
 	/* Configure MII_RT */
 	icssm_prueth_mii_init(prueth);
@@ -501,19 +510,24 @@ static int icssm_prueth_tx_enqueue(struct prueth_emac *emac,
 	struct prueth_queue_desc __iomem *queue_desc;
 	const struct prueth_queue_info *txqueue;
 	struct net_device *ndev = emac->ndev;
+	struct prueth *prueth = emac->prueth;
 	unsigned int buffer_desc_count;
 	int free_blocks, update_block;
 	bool buffer_wrapped = false;
 	int write_block, read_block;
 	void *src_addr, *dst_addr;
 	int pkt_block_size;
+	void __iomem *sram;
 	void __iomem *dram;
 	int txport, pktlen;
 	u16 update_wr_ptr;
 	u32 wr_buf_desc;
 	void *ocmc_ram;
 
-	dram = emac->prueth->mem[emac->dram].va;
+	if (!PRUETH_IS_EMAC(prueth))
+		dram = prueth->mem[PRUETH_MEM_DRAM1].va;
+	else
+		dram = emac->prueth->mem[emac->dram].va;
 	if (eth_skb_pad(skb)) {
 		if (netif_msg_tx_err(emac) && net_ratelimit())
 			netdev_err(ndev, "packet pad failed\n");
@@ -526,7 +540,10 @@ static int icssm_prueth_tx_enqueue(struct prueth_emac *emac,
 	pktlen = skb->len;
 	/* Get the tx queue */
 	queue_desc = emac->tx_queue_descs + queue_id;
-	txqueue = &queue_infos[txport][queue_id];
+	if (!PRUETH_IS_EMAC(prueth))
+		txqueue = &sw_queue_infos[txport][queue_id];
+	else
+		txqueue = &queue_infos[txport][queue_id];
 
 	buffer_desc_count = icssm_get_buff_desc_count(txqueue);
 
@@ -592,7 +609,11 @@ static int icssm_prueth_tx_enqueue(struct prueth_emac *emac,
        /* update first buffer descriptor */
 	wr_buf_desc = (pktlen << PRUETH_BD_LENGTH_SHIFT) &
 		       PRUETH_BD_LENGTH_MASK;
-	writel(wr_buf_desc, dram + readw(&queue_desc->wr_ptr));
+	sram = prueth->mem[PRUETH_MEM_SHARED_RAM].va;
+	if (!PRUETH_IS_EMAC(prueth))
+		writel(wr_buf_desc, sram + readw(&queue_desc->wr_ptr));
+	else
+		writel(wr_buf_desc, dram + readw(&queue_desc->wr_ptr));
 
 	/* update the write pointer in this queue descriptor, the firmware
 	 * polls for this change so this will signal the start of transmission
@@ -606,7 +627,6 @@ static int icssm_prueth_tx_enqueue(struct prueth_emac *emac,
 void icssm_parse_packet_info(struct prueth *prueth, u32 buffer_descriptor,
 			     struct prueth_packet_info *pkt_info)
 {
-	pkt_info->shadow = !!(buffer_descriptor & PRUETH_BD_SHADOW_MASK);
 	pkt_info->port = (buffer_descriptor & PRUETH_BD_PORT_MASK) >>
 			 PRUETH_BD_PORT_SHIFT;
 	pkt_info->length = (buffer_descriptor & PRUETH_BD_LENGTH_MASK) >>
@@ -715,11 +735,19 @@ int icssm_emac_rx_packet(struct prueth_emac *emac, u16 *bd_rd_ptr,
 		src_addr += actual_pkt_len;
 	}
 
+	if (PRUETH_IS_SWITCH(emac->prueth)) {
+		skb->offload_fwd_mark = emac->offload_fwd_mark;
+		if (!pkt_info->lookup_success)
+			icssm_prueth_sw_learn_fdb(emac, skb->data + ETH_ALEN);
+	}
+
 	skb_put(skb, actual_pkt_len);
 
 	/* send packet up the stack */
 	skb->protocol = eth_type_trans(skb, ndev);
+	local_bh_disable();
 	netif_receive_skb(skb);
+	local_bh_enable();
 
 	/* update stats */
 	emac->stats.rx_bytes += actual_pkt_len;
@@ -745,6 +773,7 @@ static int icssm_emac_rx_packets(struct prueth_emac *emac, int budget)
 
 	shared_ram = emac->prueth->mem[PRUETH_MEM_SHARED_RAM].va;
 
+	/* Start and end queue is made common for EMAC, RSTP */
 	start_queue = emac->rx_queue_start;
 	end_queue = emac->rx_queue_end;
 
@@ -755,8 +784,10 @@ static int icssm_emac_rx_packets(struct prueth_emac *emac, int budget)
 	/* search host queues for packets */
 	for (i = start_queue; i <= end_queue; i++) {
 		queue_desc = emac->rx_queue_descs + i;
-		rxqueue = &queue_infos[PRUETH_PORT_HOST][i];
-
+		if (PRUETH_IS_SWITCH(emac->prueth))
+			rxqueue = &sw_queue_infos[PRUETH_PORT_HOST][i];
+		else
+			rxqueue = &queue_infos[PRUETH_PORT_HOST][i];
 		overflow_cnt = readb(&queue_desc->overflow_cnt);
 		if (overflow_cnt > 0) {
 			emac->stats.rx_over_errors += overflow_cnt;
@@ -881,6 +912,13 @@ static int icssm_emac_request_irqs(struct prueth_emac *emac)
 	return ret;
 }
 
+/* Function to free memory related to sw */
+static void icssm_prueth_free_memory(struct prueth *prueth)
+{
+	if (PRUETH_IS_SWITCH(prueth))
+		icssm_prueth_sw_free_fdb_table(prueth);
+}
+
 static void icssm_ptp_dram_init(struct prueth_emac *emac)
 {
 	void __iomem *sram = emac->prueth->mem[PRUETH_MEM_SHARED_RAM].va;
@@ -943,20 +981,38 @@ static int icssm_emac_ndo_open(struct net_device *ndev)
 	if (!prueth->emac_configured)
 		icssm_prueth_init_ethernet_mode(prueth);
 
-	icssm_prueth_emac_config(emac);
+	/* reset and start PRU firmware */
+	if (PRUETH_IS_SWITCH(prueth)) {
+		ret = icssm_prueth_sw_emac_config(emac);
+		if (ret)
+			return ret;
+
+		ret = icssm_prueth_sw_init_fdb_table(prueth);
+		if (ret)
+			return ret;
+	} else {
+		icssm_prueth_emac_config(emac);
+	}
 
 	if (!prueth->emac_configured) {
 		icssm_ptp_dram_init(emac);
 		ret = icss_iep_init(prueth->iep, NULL, NULL, 0);
 		if (ret) {
 			netdev_err(ndev, "Failed to initialize iep: %d\n", ret);
-			goto iep_exit;
+			goto free_mem;
 		}
 	}
 
-	ret = icssm_emac_set_boot_pru(emac, ndev);
-	if (ret)
-		goto iep_exit;
+	if (!PRUETH_IS_EMAC(prueth)) {
+		ret = icssm_prueth_sw_boot_prus(prueth, ndev);
+		if (ret)
+			goto iep_exit;
+	} else {
+		/* boot the PRU */
+		ret = icssm_emac_set_boot_pru(emac, ndev);
+		if (ret)
+			goto iep_exit;
+	}
 
 	ret = icssm_emac_request_irqs(emac);
 	if (ret)
@@ -971,19 +1027,25 @@ static int icssm_emac_ndo_open(struct net_device *ndev)
 	icssm_prueth_port_enable(emac, true);
 
 	prueth->emac_configured |= BIT(emac->port_id);
-
+	if (PRUETH_IS_SWITCH(prueth))
+		icssm_prueth_sw_set_stp_state(prueth, emac->port_id,
+					      BR_STATE_LEARNING);
 	if (netif_msg_drv(emac))
 		dev_notice(&ndev->dev, "started\n");
 
 	return 0;
 
 rproc_shutdown:
-	rproc_shutdown(emac->pru);
+	if (!PRUETH_IS_EMAC(prueth))
+		icssm_prueth_sw_shutdown_prus(emac, ndev);
+	else
+		rproc_shutdown(emac->pru);
 
 iep_exit:
 	if (!prueth->emac_configured)
 		icss_iep_exit(prueth->iep);
-
+free_mem:
+	icssm_prueth_free_memory(emac->prueth);
 	return ret;
 }
 
@@ -1012,17 +1074,73 @@ static int icssm_emac_ndo_stop(struct net_device *ndev)
 	hrtimer_cancel(&emac->tx_hrtimer);
 
 	/* stop the PRU */
-	rproc_shutdown(emac->pru);
+	if (!PRUETH_IS_EMAC(prueth))
+		icssm_prueth_sw_shutdown_prus(emac, ndev);
+	else
+		rproc_shutdown(emac->pru);
 
 	/* free rx interrupts */
 	free_irq(emac->rx_irq, ndev);
 
+	/* free memory related to sw */
+	icssm_prueth_free_memory(emac->prueth);
+
+	if (!prueth->emac_configured)
+		icss_iep_exit(prueth->iep);
+
 	if (netif_msg_drv(emac))
 		dev_notice(&ndev->dev, "stopped\n");
 
 	return 0;
 }
 
+static int icssm_prueth_change_mode(struct prueth *prueth,
+				    enum pruss_ethtype mode)
+{
+	bool portstatus[PRUETH_NUM_MACS];
+	struct prueth_emac *emac;
+	struct net_device *ndev;
+	int i, ret;
+
+	for (i = 0; i < PRUETH_NUM_MACS; i++) {
+		emac = prueth->emac[i];
+		ndev = emac->ndev;
+
+		portstatus[i] = netif_running(ndev);
+		if (!portstatus[i])
+			continue;
+
+		ret = ndev->netdev_ops->ndo_stop(ndev);
+		if (ret < 0) {
+			netdev_err(ndev, "failed to stop: %d", ret);
+			return ret;
+		}
+	}
+
+	if (mode == PRUSS_ETHTYPE_EMAC || mode == PRUSS_ETHTYPE_SWITCH) {
+		prueth->eth_type = mode;
+	} else {
+		dev_err(prueth->dev, "unknown mode\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < PRUETH_NUM_MACS; i++) {
+		emac = prueth->emac[i];
+		ndev = emac->ndev;
+
+		if (!portstatus[i])
+			continue;
+
+		ret = ndev->netdev_ops->ndo_open(ndev);
+		if (ret < 0) {
+			netdev_err(ndev, "failed to start: %d", ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
 /* VLAN-tag PCP to priority queue map for EMAC/Switch/HSR/PRP used by driver
  * Index is PCP val / 2.
  *   low  - pcp 0..3 maps to Q4 for Host
@@ -1291,6 +1409,15 @@ static void icssm_emac_ndo_set_rx_mode(struct net_device *ndev)
 		icssm_emac_mc_filter_bin_allow(emac, hash);
 	}
 
+	/* Add bridge device's MC addresses as well */
+	if (prueth->hw_bridge_dev) {
+		netdev_for_each_mc_addr(ha, prueth->hw_bridge_dev) {
+			hash = icssm_emac_get_mc_hash(ha->addr,
+						      emac->mc_filter_mask);
+			icssm_emac_mc_filter_bin_allow(emac, hash);
+		}
+	}
+
 unlock:
 	spin_unlock_irqrestore(&emac->addr_lock, flags);
 }
@@ -1353,6 +1480,7 @@ static enum hrtimer_restart icssm_emac_tx_timer_callback(struct hrtimer *timer)
 static int icssm_prueth_netdev_init(struct prueth *prueth,
 				    struct device_node *eth_node)
 {
+	const struct prueth_private_data *fw_data = prueth->fw_data;
 	struct prueth_emac *emac;
 	struct net_device *ndev;
 	enum prueth_port port;
@@ -1443,6 +1571,14 @@ static int icssm_prueth_netdev_init(struct prueth *prueth,
 	phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_Pause_BIT);
 	phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_Asym_Pause_BIT);
 
+	/* Protocol switching
+	 * Enabling L2 Firmware offloading
+	 */
+	if (fw_data->support_switch) {
+		ndev->features |= NETIF_F_HW_L2FW_DOFFLOAD;
+		ndev->hw_features |= NETIF_F_HW_L2FW_DOFFLOAD;
+	}
+
 	ndev->dev.of_node = eth_node;
 	ndev->netdev_ops = &emac_netdev_ops;
 
@@ -1490,6 +1626,140 @@ bool icssm_prueth_sw_port_dev_check(const struct net_device *ndev)
 	return false;
 }
 
+static int icssm_prueth_port_offload_fwd_mark_update(struct prueth *prueth)
+{
+	int set_val = 0;
+	int i, ret = 0;
+	u8 all_slaves;
+
+	all_slaves = BIT(PRUETH_PORT_MII0) | BIT(PRUETH_PORT_MII1);
+
+	if (prueth->br_members == all_slaves)
+		set_val = 1;
+
+	dev_dbg(prueth->dev, "set offload_fwd_mark %d, mbrs=0x%x\n",
+		set_val, prueth->br_members);
+
+	for (i = 0; i < PRUETH_NUM_MACS; i++)
+		prueth->emac[i]->offload_fwd_mark = set_val;
+
+	/* Bridge is created, load switch firmware,
+	 * if not already in that mode
+	 */
+	if (set_val && !PRUETH_IS_SWITCH(prueth)) {
+		ret = icssm_prueth_change_mode(prueth, PRUSS_ETHTYPE_SWITCH);
+		if (ret < 0)
+			dev_err(prueth->dev, "Failed to enable Switch mode\n");
+		else
+			dev_info(prueth->dev,
+				 "TI PRU ethernet now in Switch mode\n");
+	}
+
+	/* Bridge is deleted, switch to Dual EMAC mode */
+	if (!prueth->br_members && !PRUETH_IS_EMAC(prueth)) {
+		ret = icssm_prueth_change_mode(prueth, PRUSS_ETHTYPE_EMAC);
+		if (ret < 0)
+			dev_err(prueth->dev, "Failed to enable Dual EMAC mode\n");
+		else
+			dev_info(prueth->dev,
+				 "TI PRU ethernet now in Dual EMAC mode\n");
+	}
+
+	return ret;
+}
+
+static int icssm_prueth_ndev_port_link(struct net_device *ndev,
+				       struct net_device *br_ndev)
+{
+	struct prueth_emac *emac = netdev_priv(ndev);
+	struct prueth *prueth = emac->prueth;
+	int ret = 0;
+
+	dev_dbg(prueth->dev, "%s: br_mbrs=0x%x %s\n",
+		__func__, prueth->br_members, ndev->name);
+
+	if (!prueth->br_members) {
+		prueth->hw_bridge_dev = br_ndev;
+	} else {
+		/* This is adding the port to a second bridge,
+		 * this is unsupported
+		 */
+		if (prueth->hw_bridge_dev != br_ndev)
+			return -EOPNOTSUPP;
+	}
+
+	prueth->br_members |= BIT(emac->port_id);
+
+	ret = icssm_prueth_port_offload_fwd_mark_update(prueth);
+
+	return ret;
+}
+
+static int icssm_prueth_ndev_port_unlink(struct net_device *ndev)
+{
+	struct prueth_emac *emac = netdev_priv(ndev);
+	struct prueth *prueth = emac->prueth;
+	int ret = 0;
+
+	dev_dbg(prueth->dev, "emac_sw_ndev_port_unlink\n");
+
+	prueth->br_members &= ~BIT(emac->port_id);
+
+	ret = icssm_prueth_port_offload_fwd_mark_update(prueth);
+
+	if (!prueth->br_members)
+		prueth->hw_bridge_dev = NULL;
+
+	return ret;
+}
+
+static int icssm_prueth_ndev_event(struct notifier_block *unused,
+				   unsigned long event, void *ptr)
+{
+	struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
+	struct netdev_notifier_changeupper_info *info;
+	int ret = NOTIFY_DONE;
+
+	if (!icssm_prueth_sw_port_dev_check(ndev))
+		return NOTIFY_DONE;
+
+	switch (event) {
+	case NETDEV_CHANGEUPPER:
+		info = ptr;
+		if (netif_is_bridge_master(info->upper_dev)) {
+			if (info->linking)
+				ret = icssm_prueth_ndev_port_link
+					(ndev, info->upper_dev);
+			else
+				ret = icssm_prueth_ndev_port_unlink(ndev);
+		}
+		break;
+	default:
+		return NOTIFY_DONE;
+	}
+
+	return notifier_from_errno(ret);
+}
+
+static int icssm_prueth_register_notifiers(struct prueth *prueth)
+{
+	int ret = 0;
+
+	prueth->prueth_netdevice_nb.notifier_call = icssm_prueth_ndev_event;
+	ret = register_netdevice_notifier(&prueth->prueth_netdevice_nb);
+	if (ret) {
+		dev_err(prueth->dev,
+			"register netdevice notifier failed ret: %d\n", ret);
+		return ret;
+	}
+
+	ret = icssm_prueth_sw_register_notifiers(prueth);
+	if (ret)
+		unregister_netdevice_notifier(&prueth->prueth_netdevice_nb);
+
+	return ret;
+}
+
 static int icssm_prueth_probe(struct platform_device *pdev)
 {
 	struct device_node *eth0_node = NULL, *eth1_node = NULL;
@@ -1709,6 +1979,12 @@ static int icssm_prueth_probe(struct platform_device *pdev)
 			prueth->emac[PRUETH_MAC1]->ndev;
 	}
 
+	ret = icssm_prueth_register_notifiers(prueth);
+	if (ret) {
+		dev_err(dev, "can't register switchdev notifiers");
+		goto netdev_unregister;
+	}
+
 	dev_info(dev, "TI PRU ethernet driver initialized: %s EMAC mode\n",
 		 (!eth0_node || !eth1_node) ? "single" : "dual");
 
@@ -1769,6 +2045,9 @@ static void icssm_prueth_remove(struct platform_device *pdev)
 	struct device_node *eth_node;
 	int i;
 
+	unregister_netdevice_notifier(&prueth->prueth_netdevice_nb);
+	icssm_prueth_sw_unregister_notifiers(prueth);
+
 	for (i = 0; i < PRUETH_NUM_MACS; i++) {
 		if (!prueth->registered_netdevs[i])
 			continue;
@@ -1868,11 +2147,16 @@ static struct prueth_private_data am335x_prueth_pdata = {
 	.fw_pru[PRUSS_PRU0] = {
 		.fw_name[PRUSS_ETHTYPE_EMAC] =
 			"ti-pruss/am335x-pru0-prueth-fw.elf",
+		.fw_name[PRUSS_ETHTYPE_SWITCH] =
+			"ti-pruss/am335x-pru0-prusw-fw.elf",
 	},
 	.fw_pru[PRUSS_PRU1] = {
 		.fw_name[PRUSS_ETHTYPE_EMAC] =
 			"ti-pruss/am335x-pru1-prueth-fw.elf",
+		.fw_name[PRUSS_ETHTYPE_SWITCH] =
+			"ti-pruss/am335x-pru1-prusw-fw.elf",
 	},
+	.support_switch = true,
 };
 
 /* AM437x SoC-specific firmware data */
@@ -1881,11 +2165,16 @@ static struct prueth_private_data am437x_prueth_pdata = {
 	.fw_pru[PRUSS_PRU0] = {
 		.fw_name[PRUSS_ETHTYPE_EMAC] =
 			"ti-pruss/am437x-pru0-prueth-fw.elf",
+		.fw_name[PRUSS_ETHTYPE_SWITCH] =
+			"ti-pruss/am437x-pru0-prusw-fw.elf",
 	},
 	.fw_pru[PRUSS_PRU1] = {
 		.fw_name[PRUSS_ETHTYPE_EMAC] =
 			"ti-pruss/am437x-pru1-prueth-fw.elf",
+		.fw_name[PRUSS_ETHTYPE_SWITCH] =
+			"ti-pruss/am437x-pru1-prusw-fw.elf",
 	},
+	.support_switch = true,
 };
 
 /* AM57xx SoC-specific firmware data */
@@ -1894,11 +2183,17 @@ static struct prueth_private_data am57xx_prueth_pdata = {
 	.fw_pru[PRUSS_PRU0] = {
 		.fw_name[PRUSS_ETHTYPE_EMAC] =
 			"ti-pruss/am57xx-pru0-prueth-fw.elf",
+	.fw_name[PRUSS_ETHTYPE_SWITCH] =
+			"ti-pruss/am57xx-pru0-prusw-fw.elf",
 	},
 	.fw_pru[PRUSS_PRU1] = {
 		.fw_name[PRUSS_ETHTYPE_EMAC] =
 			"ti-pruss/am57xx-pru1-prueth-fw.elf",
+		.fw_name[PRUSS_ETHTYPE_SWITCH] =
+			"ti-pruss/am57xx-pru1-prusw-fw.elf",
+
 	},
+	.support_switch = true,
 };
 
 static const struct of_device_id prueth_dt_match[] = {
diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.h b/drivers/net/ethernet/ti/icssm/icssm_prueth.h
index f95c8c3a7ee5..d5b49b462c24 100644
--- a/drivers/net/ethernet/ti/icssm/icssm_prueth.h
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.h
@@ -182,10 +182,12 @@ enum pruss_device {
  * struct prueth_private_data - PRU Ethernet private data
  * @driver_data: PRU Ethernet device name
  * @fw_pru: firmware names to be used for PRUSS ethernet usecases
+ * @support_switch: boolean to indicate if switch is enabled
  */
 struct prueth_private_data {
 	enum pruss_device driver_data;
 	const struct prueth_firmware fw_pru[PRUSS_NUM_PRUS];
+	bool support_switch;
 };
 
 struct prueth_emac_stats {
@@ -233,6 +235,7 @@ struct prueth_emac {
 
 	struct hrtimer tx_hrtimer;
 	struct prueth_emac_stats stats;
+	int offload_fwd_mark;
 };
 
 struct prueth {
@@ -261,8 +264,11 @@ struct prueth {
 	unsigned int eth_type;
 	size_t ocmc_ram_size;
 	u8 emac_configured;
+	u8 br_members;
 };
 
+extern const struct prueth_queue_desc queue_descs[][NUM_QUEUES];
+
 void icssm_parse_packet_info(struct prueth *prueth, u32 buffer_descriptor,
 			     struct prueth_packet_info *pkt_info);
 int icssm_emac_rx_packet(struct prueth_emac *emac, u16 *bd_rd_ptr,
diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c
index dd7f24469ab2..a8819dbb2224 100644
--- a/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c
@@ -29,6 +29,176 @@ struct icssm_prueth_sw_fdb_work {
 	int event;
 };
 
+const struct prueth_queue_info sw_queue_infos[][NUM_QUEUES] = {
+	[PRUETH_PORT_QUEUE_HOST] = {
+		[PRUETH_QUEUE1] = {
+			P0_Q1_BUFFER_OFFSET,
+			P0_QUEUE_DESC_OFFSET,
+			P0_Q1_BD_OFFSET,
+			P0_Q1_BD_OFFSET + ((HOST_QUEUE_1_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE2] = {
+			P0_Q2_BUFFER_OFFSET,
+			P0_QUEUE_DESC_OFFSET + 8,
+			P0_Q2_BD_OFFSET,
+			P0_Q2_BD_OFFSET + ((HOST_QUEUE_2_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE3] = {
+			P0_Q3_BUFFER_OFFSET,
+			P0_QUEUE_DESC_OFFSET + 16,
+			P0_Q3_BD_OFFSET,
+			P0_Q3_BD_OFFSET + ((HOST_QUEUE_3_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE4] = {
+			P0_Q4_BUFFER_OFFSET,
+			P0_QUEUE_DESC_OFFSET + 24,
+			P0_Q4_BD_OFFSET,
+			P0_Q4_BD_OFFSET + ((HOST_QUEUE_4_SIZE - 1) * BD_SIZE),
+		},
+	},
+	[PRUETH_PORT_QUEUE_MII0] = {
+		[PRUETH_QUEUE1] = {
+			P1_Q1_BUFFER_OFFSET,
+			P1_Q1_BUFFER_OFFSET +
+				((QUEUE_1_SIZE - 1) * ICSS_BLOCK_SIZE),
+			P1_Q1_BD_OFFSET,
+			P1_Q1_BD_OFFSET + ((QUEUE_1_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE2] = {
+			P1_Q2_BUFFER_OFFSET,
+			P1_Q2_BUFFER_OFFSET +
+				((QUEUE_2_SIZE - 1) * ICSS_BLOCK_SIZE),
+			P1_Q2_BD_OFFSET,
+			P1_Q2_BD_OFFSET + ((QUEUE_2_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE3] = {
+			P1_Q3_BUFFER_OFFSET,
+			P1_Q3_BUFFER_OFFSET +
+				((QUEUE_3_SIZE - 1) * ICSS_BLOCK_SIZE),
+			P1_Q3_BD_OFFSET,
+			P1_Q3_BD_OFFSET + ((QUEUE_3_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE4] = {
+			P1_Q4_BUFFER_OFFSET,
+			P1_Q4_BUFFER_OFFSET +
+				((QUEUE_4_SIZE - 1) * ICSS_BLOCK_SIZE),
+			P1_Q4_BD_OFFSET,
+			P1_Q4_BD_OFFSET + ((QUEUE_4_SIZE - 1) * BD_SIZE),
+		},
+	},
+	[PRUETH_PORT_QUEUE_MII1] = {
+		[PRUETH_QUEUE1] = {
+			P2_Q1_BUFFER_OFFSET,
+			P2_Q1_BUFFER_OFFSET +
+				((QUEUE_1_SIZE - 1) * ICSS_BLOCK_SIZE),
+			P2_Q1_BD_OFFSET,
+			P2_Q1_BD_OFFSET + ((QUEUE_1_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE2] = {
+			P2_Q2_BUFFER_OFFSET,
+			P2_Q2_BUFFER_OFFSET +
+				((QUEUE_2_SIZE - 1) * ICSS_BLOCK_SIZE),
+			P2_Q2_BD_OFFSET,
+			P2_Q2_BD_OFFSET + ((QUEUE_2_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE3] = {
+			P2_Q3_BUFFER_OFFSET,
+			P2_Q3_BUFFER_OFFSET +
+				((QUEUE_3_SIZE - 1) * ICSS_BLOCK_SIZE),
+			P2_Q3_BD_OFFSET,
+			P2_Q3_BD_OFFSET + ((QUEUE_3_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE4] = {
+			P2_Q4_BUFFER_OFFSET,
+			P2_Q4_BUFFER_OFFSET +
+				((QUEUE_4_SIZE - 1) * ICSS_BLOCK_SIZE),
+			P2_Q4_BD_OFFSET,
+			P2_Q4_BD_OFFSET + ((QUEUE_4_SIZE - 1) * BD_SIZE),
+		},
+	},
+};
+
+static const struct prueth_queue_info rx_queue_infos[][NUM_QUEUES] = {
+	[PRUETH_PORT_QUEUE_HOST] = {
+		[PRUETH_QUEUE1] = {
+			P0_Q1_BUFFER_OFFSET,
+			HOST_QUEUE_DESC_OFFSET,
+			P0_Q1_BD_OFFSET,
+			P0_Q1_BD_OFFSET + ((HOST_QUEUE_1_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE2] = {
+			P0_Q2_BUFFER_OFFSET,
+			HOST_QUEUE_DESC_OFFSET + 8,
+			P0_Q2_BD_OFFSET,
+			P0_Q2_BD_OFFSET + ((HOST_QUEUE_2_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE3] = {
+			P0_Q3_BUFFER_OFFSET,
+			HOST_QUEUE_DESC_OFFSET + 16,
+			P0_Q3_BD_OFFSET,
+			P0_Q3_BD_OFFSET + ((HOST_QUEUE_3_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE4] = {
+			P0_Q4_BUFFER_OFFSET,
+			HOST_QUEUE_DESC_OFFSET + 24,
+			P0_Q4_BD_OFFSET,
+			P0_Q4_BD_OFFSET + ((HOST_QUEUE_4_SIZE - 1) * BD_SIZE),
+		},
+	},
+	[PRUETH_PORT_QUEUE_MII0] = {
+		[PRUETH_QUEUE1] = {
+			P1_Q1_BUFFER_OFFSET,
+			P1_QUEUE_DESC_OFFSET,
+			P1_Q1_BD_OFFSET,
+			P1_Q1_BD_OFFSET + ((QUEUE_1_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE2] = {
+			P1_Q2_BUFFER_OFFSET,
+			P1_QUEUE_DESC_OFFSET + 8,
+			P1_Q2_BD_OFFSET,
+			P1_Q2_BD_OFFSET + ((QUEUE_2_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE3] = {
+			P1_Q3_BUFFER_OFFSET,
+			P1_QUEUE_DESC_OFFSET + 16,
+			P1_Q3_BD_OFFSET,
+			P1_Q3_BD_OFFSET + ((QUEUE_3_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE4] = {
+			P1_Q4_BUFFER_OFFSET,
+			P1_QUEUE_DESC_OFFSET + 24,
+			P1_Q4_BD_OFFSET,
+			P1_Q4_BD_OFFSET + ((QUEUE_4_SIZE - 1) * BD_SIZE),
+		},
+	},
+	[PRUETH_PORT_QUEUE_MII1] = {
+		[PRUETH_QUEUE1] = {
+			P2_Q1_BUFFER_OFFSET,
+			P2_QUEUE_DESC_OFFSET,
+			P2_Q1_BD_OFFSET,
+			P2_Q1_BD_OFFSET + ((QUEUE_1_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE2] = {
+			P2_Q2_BUFFER_OFFSET,
+			P2_QUEUE_DESC_OFFSET + 8,
+			P2_Q2_BD_OFFSET,
+			P2_Q2_BD_OFFSET + ((QUEUE_2_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE3] = {
+			P2_Q3_BUFFER_OFFSET,
+			P2_QUEUE_DESC_OFFSET + 16,
+			P2_Q3_BD_OFFSET,
+			P2_Q3_BD_OFFSET + ((QUEUE_3_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE4] = {
+			P2_Q4_BUFFER_OFFSET,
+			P2_QUEUE_DESC_OFFSET + 24,
+			P2_Q4_BD_OFFSET,
+			P2_Q4_BD_OFFSET + ((QUEUE_4_SIZE - 1) * BD_SIZE),
+		},
+	},
+};
+
 void icssm_prueth_sw_free_fdb_table(struct prueth *prueth)
 {
 	if (prueth->emac_configured)
@@ -673,3 +843,218 @@ int icssm_prueth_sw_purge_fdb(struct prueth_emac *emac)
 	queue_work(system_long_wq, &fdb_work->work);
 	return 0;
 }
+
+void icssm_prueth_sw_hostconfig(struct prueth *prueth)
+{
+	void __iomem *dram1_base = prueth->mem[PRUETH_MEM_DRAM1].va;
+	void __iomem *dram;
+
+	/* queue information table */
+	dram = dram1_base + P0_Q1_RX_CONTEXT_OFFSET;
+	memcpy_toio(dram, sw_queue_infos[PRUETH_PORT_QUEUE_HOST],
+		    sizeof(sw_queue_infos[PRUETH_PORT_QUEUE_HOST]));
+
+	/* buffer descriptor offset table*/
+	dram = dram1_base + QUEUE_DESCRIPTOR_OFFSET_ADDR;
+	writew(P0_Q1_BD_OFFSET, dram);
+	writew(P0_Q2_BD_OFFSET, dram + 2);
+	writew(P0_Q3_BD_OFFSET, dram + 4);
+	writew(P0_Q4_BD_OFFSET, dram + 6);
+
+	/* buffer offset table */
+	dram = dram1_base + QUEUE_OFFSET_ADDR;
+	writew(P0_Q1_BUFFER_OFFSET, dram);
+	writew(P0_Q2_BUFFER_OFFSET, dram + 2);
+	writew(P0_Q3_BUFFER_OFFSET, dram + 4);
+	writew(P0_Q4_BUFFER_OFFSET, dram + 6);
+
+	/* queue size lookup table */
+	dram = dram1_base + QUEUE_SIZE_ADDR;
+	writew(HOST_QUEUE_1_SIZE, dram);
+	writew(HOST_QUEUE_1_SIZE, dram + 2);
+	writew(HOST_QUEUE_1_SIZE, dram + 4);
+	writew(HOST_QUEUE_1_SIZE, dram + 6);
+
+	/* queue table */
+	dram = dram1_base + P0_QUEUE_DESC_OFFSET;
+	memcpy_toio(dram, queue_descs[PRUETH_PORT_QUEUE_HOST],
+		    sizeof(queue_descs[PRUETH_PORT_QUEUE_HOST]));
+}
+
+static int icssm_prueth_sw_port_config(struct prueth *prueth,
+				       enum prueth_port port_id)
+{
+	unsigned int tx_context_ofs_addr, rx_context_ofs, queue_desc_ofs;
+	void __iomem *dram, *dram_base, *dram_mac;
+	struct prueth_emac *emac;
+	void __iomem *dram1_base;
+
+	dram1_base = prueth->mem[PRUETH_MEM_DRAM1].va;
+	emac = prueth->emac[port_id - 1];
+	switch (port_id) {
+	case PRUETH_PORT_MII0:
+		tx_context_ofs_addr     = TX_CONTEXT_P1_Q1_OFFSET_ADDR;
+		rx_context_ofs          = P1_Q1_RX_CONTEXT_OFFSET;
+		queue_desc_ofs          = P1_QUEUE_DESC_OFFSET;
+
+		/* for switch PORT MII0 mac addr is in DRAM0. */
+		dram_mac = prueth->mem[PRUETH_MEM_DRAM0].va;
+		break;
+	case PRUETH_PORT_MII1:
+		tx_context_ofs_addr     = TX_CONTEXT_P2_Q1_OFFSET_ADDR;
+		rx_context_ofs          = P2_Q1_RX_CONTEXT_OFFSET;
+		queue_desc_ofs          = P2_QUEUE_DESC_OFFSET;
+
+		/* for switch PORT MII1 mac addr is in DRAM1. */
+		dram_mac = prueth->mem[PRUETH_MEM_DRAM1].va;
+		break;
+	default:
+		netdev_err(emac->ndev, "invalid port\n");
+		return -EINVAL;
+	}
+
+	/* setup mac address */
+	memcpy_toio(dram_mac + PORT_MAC_ADDR, emac->mac_addr, 6);
+
+	/* Remaining switch port configs are in DRAM1 */
+	dram_base = prueth->mem[PRUETH_MEM_DRAM1].va;
+
+	/* queue information table */
+	memcpy_toio(dram_base + tx_context_ofs_addr,
+		    sw_queue_infos[port_id],
+		    sizeof(sw_queue_infos[port_id]));
+
+	memcpy_toio(dram_base + rx_context_ofs,
+		    rx_queue_infos[port_id],
+		    sizeof(rx_queue_infos[port_id]));
+
+	/* buffer descriptor offset table*/
+	dram = dram_base + QUEUE_DESCRIPTOR_OFFSET_ADDR +
+	       (port_id * NUM_QUEUES * sizeof(u16));
+	writew(sw_queue_infos[port_id][PRUETH_QUEUE1].buffer_desc_offset, dram);
+	writew(sw_queue_infos[port_id][PRUETH_QUEUE2].buffer_desc_offset,
+	       dram + 2);
+	writew(sw_queue_infos[port_id][PRUETH_QUEUE3].buffer_desc_offset,
+	       dram + 4);
+	writew(sw_queue_infos[port_id][PRUETH_QUEUE4].buffer_desc_offset,
+	       dram + 6);
+
+	/* buffer offset table */
+	dram = dram_base + QUEUE_OFFSET_ADDR +
+	       port_id * NUM_QUEUES * sizeof(u16);
+	writew(sw_queue_infos[port_id][PRUETH_QUEUE1].buffer_offset, dram);
+	writew(sw_queue_infos[port_id][PRUETH_QUEUE2].buffer_offset,
+	       dram + 2);
+	writew(sw_queue_infos[port_id][PRUETH_QUEUE3].buffer_offset,
+	       dram + 4);
+	writew(sw_queue_infos[port_id][PRUETH_QUEUE4].buffer_offset,
+	       dram + 6);
+
+	/* queue size lookup table */
+	dram = dram_base + QUEUE_SIZE_ADDR +
+	       port_id * NUM_QUEUES * sizeof(u16);
+	writew(QUEUE_1_SIZE, dram);
+	writew(QUEUE_2_SIZE, dram + 2);
+	writew(QUEUE_3_SIZE, dram + 4);
+	writew(QUEUE_4_SIZE, dram + 6);
+
+	/* queue table */
+	memcpy_toio(dram_base + queue_desc_ofs,
+		    &queue_descs[port_id][0],
+		    4 * sizeof(queue_descs[port_id][0]));
+
+	emac->rx_queue_descs = dram1_base + P0_QUEUE_DESC_OFFSET;
+	emac->tx_queue_descs = dram1_base +
+		rx_queue_infos[port_id][PRUETH_QUEUE1].queue_desc_offset;
+
+	return 0;
+}
+
+int icssm_prueth_sw_emac_config(struct prueth_emac *emac)
+{
+	struct prueth *prueth = emac->prueth;
+	u32 sharedramaddr, ocmcaddr;
+	int ret;
+
+	/* PRU needs local shared RAM address for C28 */
+	sharedramaddr = ICSS_LOCAL_SHARED_RAM;
+	/* PRU needs real global OCMC address for C30*/
+	ocmcaddr = (u32)prueth->mem[PRUETH_MEM_OCMC].pa;
+
+	if (prueth->emac_configured & BIT(emac->port_id))
+		return 0;
+
+	ret = icssm_prueth_sw_port_config(prueth, emac->port_id);
+	if (ret)
+		return ret;
+
+	if (!prueth->emac_configured) {
+		/* Set in constant table C28 of PRUn to ICSS Shared memory */
+		pru_rproc_set_ctable(prueth->pru0, PRU_C28, sharedramaddr);
+		pru_rproc_set_ctable(prueth->pru1, PRU_C28, sharedramaddr);
+
+		/* Set in constant table C30 of PRUn to OCMC memory */
+		pru_rproc_set_ctable(prueth->pru0, PRU_C30, ocmcaddr);
+		pru_rproc_set_ctable(prueth->pru1, PRU_C30, ocmcaddr);
+	}
+	return 0;
+}
+
+int icssm_prueth_sw_boot_prus(struct prueth *prueth, struct net_device *ndev)
+{
+	const struct prueth_firmware *pru_firmwares;
+	const char *fw_name, *fw_name1;
+	int ret;
+
+	if (prueth->emac_configured)
+		return 0;
+
+	pru_firmwares = &prueth->fw_data->fw_pru[PRUSS_PRU0];
+	fw_name = pru_firmwares->fw_name[prueth->eth_type];
+	pru_firmwares = &prueth->fw_data->fw_pru[PRUSS_PRU1];
+	fw_name1 = pru_firmwares->fw_name[prueth->eth_type];
+
+	ret = rproc_set_firmware(prueth->pru0, fw_name);
+	if (ret) {
+		netdev_err(ndev, "failed to set PRU0 firmware %s: %d\n",
+			   fw_name, ret);
+		return ret;
+	}
+	ret = rproc_boot(prueth->pru0);
+	if (ret) {
+		netdev_err(ndev, "failed to boot PRU0: %d\n", ret);
+		return ret;
+	}
+
+	ret = rproc_set_firmware(prueth->pru1, fw_name1);
+	if (ret) {
+		netdev_err(ndev, "failed to set PRU1 firmware %s: %d\n",
+			   fw_name1, ret);
+		goto rproc0_shutdown;
+	}
+	ret = rproc_boot(prueth->pru1);
+	if (ret) {
+		netdev_err(ndev, "failed to boot PRU1: %d\n", ret);
+		goto rproc0_shutdown;
+	}
+
+	return 0;
+
+rproc0_shutdown:
+	rproc_shutdown(prueth->pru0);
+	return ret;
+}
+
+int icssm_prueth_sw_shutdown_prus(struct prueth_emac *emac,
+				  struct net_device *ndev)
+{
+	struct prueth *prueth = emac->prueth;
+
+	if (prueth->emac_configured)
+		return 0;
+
+	rproc_shutdown(prueth->pru0);
+	rproc_shutdown(prueth->pru1);
+
+	return 0;
+}
diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h
index 218cbe1d3c50..e6111bba166e 100644
--- a/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h
@@ -16,6 +16,8 @@ void icssm_prueth_sw_set_stp_state(struct prueth *prueth,
 u8 icssm_prueth_sw_get_stp_state(struct prueth *prueth,
 				 enum prueth_port port);
 
+extern const struct prueth_queue_info sw_queue_infos[][4];
+
 void icssm_prueth_sw_fdb_tbl_init(struct prueth *prueth);
 int icssm_prueth_sw_init_fdb_table(struct prueth *prueth);
 void icssm_prueth_sw_free_fdb_table(struct prueth *prueth);
@@ -26,4 +28,10 @@ void icssm_prueth_sw_fdb_del(struct prueth_emac *emac,
 			     struct switchdev_notifier_fdb_info *fdb);
 int icssm_prueth_sw_learn_fdb(struct prueth_emac *emac, u8 *src_mac);
 int icssm_prueth_sw_purge_fdb(struct prueth_emac *emac);
+void icssm_prueth_sw_hostconfig(struct prueth *prueth);
+int icssm_prueth_sw_emac_config(struct prueth_emac *emac);
+int icssm_prueth_sw_boot_prus(struct prueth *prueth, struct net_device *ndev);
+int icssm_prueth_sw_shutdown_prus(struct prueth_emac *emac,
+				  struct net_device *ndev);
+
 #endif /* __NET_TI_PRUETH_SWITCH_H */
diff --git a/drivers/net/ethernet/ti/icssm/icssm_switch.h b/drivers/net/ethernet/ti/icssm/icssm_switch.h
index 4200ccb1b425..5ba9ce14da44 100644
--- a/drivers/net/ethernet/ti/icssm/icssm_switch.h
+++ b/drivers/net/ethernet/ti/icssm/icssm_switch.h
@@ -117,6 +117,15 @@
 #define STATISTICS_OFFSET	0x1F00
 #define STAT_SIZE		0x98
 
+/* The following offsets indicate which sections of the memory are used
+ * for switch internal tasks
+ */
+#define SWITCH_SPECIFIC_DRAM0_START_SIZE		0x100
+#define SWITCH_SPECIFIC_DRAM0_START_OFFSET		0x1F00
+
+#define SWITCH_SPECIFIC_DRAM1_START_SIZE		0x300
+#define SWITCH_SPECIFIC_DRAM1_START_OFFSET		0x1D00
+
 /* Offset for storing
  * 1. Storm Prevention Params
  * 2. PHY Speed Offset
@@ -146,6 +155,74 @@
 /* 4 bytes ? */
 #define STP_INVALID_STATE_OFFSET	(STATISTICS_OFFSET + STAT_SIZE + 33)
 
+/* DRAM1 Offsets for Switch */
+/* 4 queue descriptors for port 0 (host receive) */
+#define P0_QUEUE_DESC_OFFSET		0x1E7C
+#define P1_QUEUE_DESC_OFFSET		0x1E9C
+#define P2_QUEUE_DESC_OFFSET		0x1EBC
+/* collision descriptor of port 0 */
+#define P0_COL_QUEUE_DESC_OFFSET	0x1E64
+#define P1_COL_QUEUE_DESC_OFFSET	0x1E6C
+#define P2_COL_QUEUE_DESC_OFFSET	0x1E74
+/* Collision Status Register
+ *    P0: bit 0 is pending flag, bit 1..2 indicates which queue,
+ *    P1: bit 8 is pending flag, 9..10 is queue number
+ *    P2: bit 16 is pending flag, 17..18 is queue number, remaining bits are 0.
+ */
+#define COLLISION_STATUS_ADDR		0x1E60
+
+#define INTERFACE_MAC_ADDR		0x1E58
+#define P2_MAC_ADDR			0x1E50
+#define P1_MAC_ADDR			0x1E48
+
+#define QUEUE_SIZE_ADDR			0x1E30
+#define QUEUE_OFFSET_ADDR		0x1E18
+#define QUEUE_DESCRIPTOR_OFFSET_ADDR	0x1E00
+
+#define COL_RX_CONTEXT_P2_OFFSET_ADDR	(COL_RX_CONTEXT_P1_OFFSET_ADDR + 12)
+#define COL_RX_CONTEXT_P1_OFFSET_ADDR	(COL_RX_CONTEXT_P0_OFFSET_ADDR + 12)
+#define COL_RX_CONTEXT_P0_OFFSET_ADDR	(P2_Q4_RX_CONTEXT_OFFSET + 8)
+
+/* Port 2 Rx Context */
+#define P2_Q4_RX_CONTEXT_OFFSET		(P2_Q3_RX_CONTEXT_OFFSET + 8)
+#define P2_Q3_RX_CONTEXT_OFFSET		(P2_Q2_RX_CONTEXT_OFFSET + 8)
+#define P2_Q2_RX_CONTEXT_OFFSET		(P2_Q1_RX_CONTEXT_OFFSET + 8)
+#define P2_Q1_RX_CONTEXT_OFFSET		RX_CONTEXT_P2_Q1_OFFSET_ADDR
+#define RX_CONTEXT_P2_Q1_OFFSET_ADDR	(P1_Q4_RX_CONTEXT_OFFSET + 8)
+
+/* Port 1 Rx Context */
+#define P1_Q4_RX_CONTEXT_OFFSET		(P1_Q3_RX_CONTEXT_OFFSET + 8)
+#define P1_Q3_RX_CONTEXT_OFFSET		(P1_Q2_RX_CONTEXT_OFFSET + 8)
+#define P1_Q2_RX_CONTEXT_OFFSET		(P1_Q1_RX_CONTEXT_OFFSET + 8)
+#define P1_Q1_RX_CONTEXT_OFFSET		(RX_CONTEXT_P1_Q1_OFFSET_ADDR)
+#define RX_CONTEXT_P1_Q1_OFFSET_ADDR	(P0_Q4_RX_CONTEXT_OFFSET + 8)
+
+/* Host Port Rx Context */
+#define P0_Q4_RX_CONTEXT_OFFSET		(P0_Q3_RX_CONTEXT_OFFSET + 8)
+#define P0_Q3_RX_CONTEXT_OFFSET		(P0_Q2_RX_CONTEXT_OFFSET + 8)
+#define P0_Q2_RX_CONTEXT_OFFSET		(P0_Q1_RX_CONTEXT_OFFSET + 8)
+#define P0_Q1_RX_CONTEXT_OFFSET		RX_CONTEXT_P0_Q1_OFFSET_ADDR
+#define RX_CONTEXT_P0_Q1_OFFSET_ADDR	(COL_TX_CONTEXT_P2_Q1_OFFSET_ADDR + 8)
+
+/* Port 2 Tx Collision Context */
+#define COL_TX_CONTEXT_P2_Q1_OFFSET_ADDR (COL_TX_CONTEXT_P1_Q1_OFFSET_ADDR + 8)
+/* Port 1 Tx Collision Context */
+#define COL_TX_CONTEXT_P1_Q1_OFFSET_ADDR (P2_Q4_TX_CONTEXT_OFFSET + 8)
+
+/* Port 2 */
+#define P2_Q4_TX_CONTEXT_OFFSET		(P2_Q3_TX_CONTEXT_OFFSET + 8)
+#define P2_Q3_TX_CONTEXT_OFFSET		(P2_Q2_TX_CONTEXT_OFFSET + 8)
+#define P2_Q2_TX_CONTEXT_OFFSET		(P2_Q1_TX_CONTEXT_OFFSET + 8)
+#define P2_Q1_TX_CONTEXT_OFFSET		TX_CONTEXT_P2_Q1_OFFSET_ADDR
+#define TX_CONTEXT_P2_Q1_OFFSET_ADDR	(P1_Q4_TX_CONTEXT_OFFSET + 8)
+
+/* Port 1 */
+#define P1_Q4_TX_CONTEXT_OFFSET		(P1_Q3_TX_CONTEXT_OFFSET + 8)
+#define P1_Q3_TX_CONTEXT_OFFSET		(P1_Q2_TX_CONTEXT_OFFSET + 8)
+#define P1_Q2_TX_CONTEXT_OFFSET		(P1_Q1_TX_CONTEXT_OFFSET + 8)
+#define P1_Q1_TX_CONTEXT_OFFSET		TX_CONTEXT_P1_Q1_OFFSET_ADDR
+#define TX_CONTEXT_P1_Q1_OFFSET_ADDR	SWITCH_SPECIFIC_DRAM1_START_OFFSET
+
 /* DRAM Offsets for EMAC
  * Present on Both DRAM0 and DRAM1
  */
-- 
2.43.0



From parvathi at couthit.com  Fri Dec  5 04:29:11 2025
From: parvathi at couthit.com (Parvathi Pudi)
Date: Fri,  5 Dec 2025 17:59:11 +0530
Subject: [RFC PATCH net-next v9 1/3] net: ti: icssm-prueth: Add helper functions to configure and maintain FDB
In-Reply-To: <20251205123146.462397-1-parvathi@couthit.com>
References: <20251205123146.462397-1-parvathi@couthit.com>
Message-ID: <20251205123146.462397-2-parvathi@couthit.com>

From: Roger Quadros <rogerq at ti.com>

Introduce helper functions to configure and maintain Forwarding
Database (FDB) tables to aid with the switch mode feature for PRU-ICSS
ports. The PRU-ICSS FDB is maintained such that it is always in sync with
the Linux bridge driver FDB.

The FDB is used by the driver to determine whether to flood a packet,
received from the user plane, to both ports or direct it to a specific port
using the flags in the FDB table entry.

The FDB is implemented in two main components: the Index table and the
MAC Address table. Adding, deleting, and maintaining entries are handled
by the PRUETH driver. There are two types of entries:

Dynamic: created from the received packets and are subject to aging.
Static: created by the user and these entries never age out.

8-bit hash value obtained using the source MAC address is used to identify
the index to the Index/Hash table. A bucket-based approach is used to
collate source MAC addresses with the same hash value. The Index/Hash table
holds the bucket index (16-bit value) and the number of entries in the
bucket with the same hash value (16-bit value). This table can hold up to
256 entries, with each entry consuming 4 bytes of memory. The bucket index
value points to the MAC address table indicating the start of MAC addresses
having the same hash values.

Each entry in the MAC Address table consists of:
1. 6 bytes of the MAC address,
2. 2-byte aging time, and
3. 1-byte each for port information and flags respectively.

When a new entry is added to the FDB, the hash value is calculated using an
XOR operation on the 6-byte MAC address. The result is used as an index
into the Hash/Index table to check if any entries exist. If no entries are
present, the first available empty slot in the MAC Address table is
allocated to insert this MAC address. If entries with the same hash value
are already present, the new MAC address entry is added to the MAC Address
table in such a way that it ensures all entries are grouped together and
sorted in ascending MAC address order. This approach helps efficiently
manage FDB entries.

Signed-off-by: Roger Quadros <rogerq at ti.com>
Signed-off-by: Andrew F. Davis <afd at ti.com>
Signed-off-by: Basharath Hussain Khaja <basharath at couthit.com>
Signed-off-by: Parvathi Pudi <parvathi at couthit.com>
---
 drivers/net/ethernet/ti/Makefile              |   2 +-
 drivers/net/ethernet/ti/icssm/icssm_prueth.h  |   3 +
 .../ethernet/ti/icssm/icssm_prueth_fdb_tbl.h  |  76 +++
 .../ethernet/ti/icssm/icssm_prueth_switch.c   | 598 ++++++++++++++++++
 .../ethernet/ti/icssm/icssm_prueth_switch.h   |  20 +
 drivers/net/ethernet/ti/icssm/icssm_switch.h  |  26 +
 6 files changed, 724 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ethernet/ti/icssm/icssm_prueth_fdb_tbl.h
 create mode 100644 drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c
 create mode 100644 drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h

diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile
index 93c0a4d0e33a..1fd149dd6115 100644
--- a/drivers/net/ethernet/ti/Makefile
+++ b/drivers/net/ethernet/ti/Makefile
@@ -4,7 +4,7 @@
 #
 
 obj-$(CONFIG_TI_PRUETH) += icssm-prueth.o
-icssm-prueth-y := icssm/icssm_prueth.o
+icssm-prueth-y := icssm/icssm_prueth.o icssm/icssm_prueth_switch.o
 
 obj-$(CONFIG_TI_CPSW) += cpsw-common.o
 obj-$(CONFIG_TI_DAVINCI_EMAC) += cpsw-common.o
diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.h b/drivers/net/ethernet/ti/icssm/icssm_prueth.h
index 8e7e0af08144..4b50133c5a72 100644
--- a/drivers/net/ethernet/ti/icssm/icssm_prueth.h
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.h
@@ -15,6 +15,7 @@
 
 #include "icssm_switch.h"
 #include "icssm_prueth_ptp.h"
+#include "icssm_prueth_fdb_tbl.h"
 
 /* ICSSM size of redundancy tag */
 #define ICSSM_LRE_TAG_SIZE	6
@@ -248,6 +249,8 @@ struct prueth {
 	struct prueth_emac *emac[PRUETH_NUM_MACS];
 	struct net_device *registered_netdevs[PRUETH_NUM_MACS];
 
+	struct fdb_tbl *fdb_tbl;
+
 	unsigned int eth_type;
 	size_t ocmc_ram_size;
 	u8 emac_configured;
diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth_fdb_tbl.h b/drivers/net/ethernet/ti/icssm/icssm_prueth_fdb_tbl.h
new file mode 100644
index 000000000000..9089259d96ea
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth_fdb_tbl.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019-2021 Texas Instruments Incorporated - https://www.ti.com */
+#ifndef __NET_TI_PRUSS_FDB_TBL_H
+#define __NET_TI_PRUSS_FDB_TBL_H
+
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include "icssm_prueth.h"
+
+/* 4 bytes */
+struct fdb_index_tbl_entry {
+	/* Bucket Table index of first Bucket with this MAC address */
+	u16 bucket_idx;
+	u16 bucket_entries; /* Number of entries in this bucket */
+};
+
+/* 4 * 256 = 1024 = 0x200 bytes */
+struct fdb_index_array {
+	struct fdb_index_tbl_entry index_tbl_entry[FDB_INDEX_TBL_MAX_ENTRIES];
+};
+
+/* 10 bytes */
+struct fdb_mac_tbl_entry {
+	u8  mac[ETH_ALEN];
+	u16 age;
+	u8  port; /* 0 based: 0=port1, 1=port2 */
+	union {
+		struct {
+			u8  is_static:1;
+			u8  active:1;
+		};
+		u8 flags;
+	};
+};
+
+/* 10 * 256 = 2560 = 0xa00 bytes */
+struct fdb_mac_tbl_array {
+	struct fdb_mac_tbl_entry mac_tbl_entry[FDB_MAC_TBL_MAX_ENTRIES];
+};
+
+/* 1 byte */
+struct fdb_stp_config {
+	u8  state; /* per-port STP state (defined in FW header) */
+};
+
+/* 1 byte */
+struct fdb_flood_config {
+	u8 host_flood_enable:1;
+	u8 port1_flood_enable:1;
+	u8 port2_flood_enable:1;
+};
+
+/* 2 byte */
+struct fdb_arbitration {
+	u8  host_lock;
+	u8  pru_locks;
+};
+
+struct fdb_tbl {
+	/* fdb index table */
+	struct fdb_index_array __iomem *index_a;
+	/* fdb MAC table */
+	struct fdb_mac_tbl_array __iomem *mac_tbl_a;
+	/* port 1 stp config */
+	struct fdb_stp_config __iomem *port1_stp_cfg;
+	/* port 2 stp config */
+	struct fdb_stp_config __iomem *port2_stp_cfg;
+	/* per-port flood enable */
+	struct fdb_flood_config __iomem *flood_enable_flags;
+	/* fdb locking mechanism */
+	struct fdb_arbitration __iomem *locks;
+	/* total number of entries in hash table */
+	u16 total_entries;
+};
+
+#endif
diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c
new file mode 100644
index 000000000000..82851d38cd46
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c
@@ -0,0 +1,598 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Texas Instruments PRUETH Switch Driver
+ *
+ * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com
+ */
+#include <linux/etherdevice.h>
+#include <linux/kernel.h>
+#include <linux/remoteproc.h>
+#include <net/switchdev.h>
+#include "icssm_prueth.h"
+#include "icssm_prueth_switch.h"
+#include "icssm_prueth_fdb_tbl.h"
+
+#define FDB_IDX_TBL_ENTRY(n) (&prueth->fdb_tbl->index_a->index_tbl_entry[n])
+
+#define FDB_MAC_TBL_ENTRY(n) (&prueth->fdb_tbl->mac_tbl_a->mac_tbl_entry[n])
+
+#define FLAG_IS_STATIC	BIT(0)
+#define FLAG_ACTIVE	BIT(1)
+
+void icssm_prueth_sw_free_fdb_table(struct prueth *prueth)
+{
+	if (prueth->emac_configured)
+		return;
+
+	kfree(prueth->fdb_tbl);
+	prueth->fdb_tbl = NULL;
+}
+
+void icssm_prueth_sw_fdb_tbl_init(struct prueth *prueth)
+{
+	struct fdb_tbl *t = prueth->fdb_tbl;
+	void __iomem *sram_base;
+	u8 val;
+
+	sram_base = prueth->mem[PRUETH_MEM_SHARED_RAM].va;
+
+	t->index_a = sram_base + V2_1_FDB_TBL_OFFSET;
+	t->mac_tbl_a = sram_base + FDB_MAC_TBL_OFFSET;
+	t->port1_stp_cfg = sram_base + FDB_PORT1_STP_CFG_OFFSET;
+	t->port2_stp_cfg = sram_base + FDB_PORT2_STP_CFG_OFFSET;
+	t->flood_enable_flags = sram_base + FDB_FLOOD_ENABLE_FLAGS_OFFSET;
+	t->locks = sram_base + FDB_LOCKS_OFFSET;
+
+	val = readb(t->flood_enable_flags);
+	/* host_flood_enable = 1 */
+	val |= BIT(0);
+	/* port1_flood_enable = 1 */
+	val |= BIT(1);
+	/* port2_flood_enable = 1 */
+	val |= BIT(2);
+	writeb(val, t->flood_enable_flags);
+
+	writeb(0, &t->locks->host_lock);
+	t->total_entries = 0;
+}
+
+static u8 icssm_pru_lock_done(struct fdb_tbl *fdb_tbl)
+{
+	return readb(&fdb_tbl->locks->pru_locks);
+}
+
+static int icssm_prueth_sw_fdb_spin_lock(struct fdb_tbl *fdb_tbl)
+{
+	u8 done;
+	int ret;
+
+	/* Take the host lock */
+	writeb(1, &fdb_tbl->locks->host_lock);
+
+	/* Wait for the PRUs to release their locks */
+	ret = read_poll_timeout(icssm_pru_lock_done, done, done == 0,
+				1, 10, false, fdb_tbl);
+	return ret;
+}
+
+static void icssm_prueth_sw_fdb_spin_unlock(struct fdb_tbl *fdb_tbl)
+{
+	writeb(0, &fdb_tbl->locks->host_lock);
+}
+
+static u8 icssm_prueth_sw_fdb_hash(const u8 *mac)
+{
+	return (mac[0] ^ mac[1] ^ mac[2] ^ mac[3] ^ mac[4] ^ mac[5]);
+}
+
+static int
+icssm_prueth_sw_fdb_search(struct fdb_mac_tbl_array __iomem *mac_tbl,
+			   struct fdb_index_tbl_entry __iomem *bucket_info,
+			   const u8 *mac)
+{
+	unsigned int bucket_entries, mac_tbl_idx;
+	u8 tmp_mac[ETH_ALEN];
+	int i;
+
+	mac_tbl_idx = readw(&bucket_info->bucket_idx);
+	bucket_entries = readw(&bucket_info->bucket_entries);
+	for (i = 0; i < bucket_entries; i++, mac_tbl_idx++) {
+		memcpy_fromio(tmp_mac, mac_tbl->mac_tbl_entry[mac_tbl_idx].mac,
+			      ETH_ALEN);
+		if (ether_addr_equal(mac, tmp_mac))
+			return mac_tbl_idx;
+	}
+
+	return -ENODATA;
+}
+
+static int icssm_prueth_sw_fdb_find_open_slot(struct fdb_tbl *fdb_tbl)
+{
+	unsigned int i;
+	u8 flags;
+
+	for (i = 0; i < FDB_MAC_TBL_MAX_ENTRIES; i++) {
+		flags = readb(&fdb_tbl->mac_tbl_a->mac_tbl_entry[i].flags);
+		if (!(flags & FLAG_ACTIVE))
+			break;
+	}
+
+	return i;
+}
+
+static int
+icssm_prueth_sw_find_fdb_insert(struct fdb_tbl *fdb, struct prueth *prueth,
+				struct fdb_index_tbl_entry __iomem *bkt_info,
+				const u8 *mac, const u8 port)
+{
+	struct fdb_mac_tbl_array __iomem *mac_tbl = fdb->mac_tbl_a;
+	unsigned int bucket_entries, mac_tbl_idx;
+	struct fdb_mac_tbl_entry __iomem *e;
+	u8 mac_from_hw[ETH_ALEN];
+	s8 cmp;
+	int i;
+
+	mac_tbl_idx = readw(&bkt_info->bucket_idx);
+	bucket_entries = readw(&bkt_info->bucket_entries);
+
+	for (i = 0; i < bucket_entries; i++, mac_tbl_idx++) {
+		e = &mac_tbl->mac_tbl_entry[mac_tbl_idx];
+		memcpy_fromio(mac_from_hw, e->mac, ETH_ALEN);
+		cmp = memcmp(mac, mac_from_hw, ETH_ALEN);
+		if (cmp < 0) {
+			return mac_tbl_idx;
+		} else if (cmp == 0) {
+			if (readb(&e->port) != port) {
+				/* MAC is already in FDB, only port is
+				 * different. So just update the port.
+				 * Note: total_entries and bucket_entries
+				 * remain the same.
+				 */
+				writeb(port, &e->port);
+			}
+
+			/* MAC and port are the same, touch the fdb */
+			writew(0, &e->age);
+			return -EEXIST;
+		}
+	}
+
+	return mac_tbl_idx;
+}
+
+static int
+icssm_prueth_sw_fdb_empty_slot_left(struct fdb_mac_tbl_array __iomem *mac_tbl,
+				    unsigned int mac_tbl_idx)
+{
+	u8 flags;
+	int i;
+
+	for (i = mac_tbl_idx - 1; i > -1; i--) {
+		flags = readb(&mac_tbl->mac_tbl_entry[i].flags);
+		if (!(flags & FLAG_ACTIVE))
+			break;
+	}
+
+	return i;
+}
+
+static int
+icssm_prueth_sw_fdb_empty_slot_right(struct fdb_mac_tbl_array __iomem *mac_tbl,
+				     unsigned int mac_tbl_idx)
+{
+	u8 flags;
+	int i;
+
+	for (i = mac_tbl_idx; i < FDB_MAC_TBL_MAX_ENTRIES; i++) {
+		flags = readb(&mac_tbl->mac_tbl_entry[i].flags);
+		if (!(flags & FLAG_ACTIVE))
+			return i;
+	}
+
+	return -1;
+}
+
+static void icssm_prueth_sw_fdb_move_range_left(struct prueth *prueth,
+						u16 left, u16 right)
+{
+	struct fdb_mac_tbl_entry entry;
+	u32 sz = 0;
+	u16 i;
+
+	sz = sizeof(struct fdb_mac_tbl_entry);
+	for (i = left; i < right; i++) {
+		memcpy_fromio(&entry, FDB_MAC_TBL_ENTRY(i + 1), sz);
+		memcpy_toio(FDB_MAC_TBL_ENTRY(i), &entry, sz);
+	}
+}
+
+static void icssm_prueth_sw_fdb_move_range_right(struct prueth *prueth,
+						 u16 left, u16 right)
+{
+	struct fdb_mac_tbl_entry entry;
+	u32 sz = 0;
+	u16 i;
+
+	sz = sizeof(struct fdb_mac_tbl_entry);
+	for (i = right; i > left; i--) {
+		memcpy_fromio(&entry, FDB_MAC_TBL_ENTRY(i - 1), sz);
+		memcpy_toio(FDB_MAC_TBL_ENTRY(i), &entry, sz);
+	}
+}
+
+static void icssm_prueth_sw_fdb_update_index_tbl(struct prueth *prueth,
+						 u16 left, u16 right)
+{
+	unsigned int hash, hash_prev;
+	u8 mac[ETH_ALEN];
+	unsigned int i;
+
+	/* To ensure we don't improperly update the
+	 * bucket index, initialize with an invalid
+	 * hash in case we are in leftmost slot
+	 */
+	hash_prev = 0xff;
+
+	if (left > 0) {
+		memcpy_fromio(mac, FDB_MAC_TBL_ENTRY(left - 1)->mac, ETH_ALEN);
+		hash_prev = icssm_prueth_sw_fdb_hash(mac);
+	}
+
+	/* For each moved element, update the bucket index */
+	for (i = left; i <= right; i++) {
+		memcpy_fromio(mac, FDB_MAC_TBL_ENTRY(i)->mac, ETH_ALEN);
+		hash = icssm_prueth_sw_fdb_hash(mac);
+
+		/* Only need to update buckets once */
+		if (hash != hash_prev)
+			writew(i, &FDB_IDX_TBL_ENTRY(hash)->bucket_idx);
+
+		hash_prev = hash;
+	}
+}
+
+static struct fdb_mac_tbl_entry __iomem *
+icssm_prueth_sw_find_free_mac(struct prueth *prueth, struct fdb_index_tbl_entry
+			      __iomem *bucket_info, u8 suggested_mac_tbl_idx,
+			      bool *update_indexes, const u8 *mac)
+{
+	s16 empty_slot_idx = 0, left = 0, right = 0;
+	unsigned int mti = suggested_mac_tbl_idx;
+	struct fdb_mac_tbl_array __iomem *mt;
+	struct fdb_tbl *fdb;
+	u8 flags;
+
+	fdb = prueth->fdb_tbl;
+	mt = fdb->mac_tbl_a;
+
+	flags = readb(&FDB_MAC_TBL_ENTRY(mti)->flags);
+	if (!(flags & FLAG_ACTIVE)) {
+		/* Claim the entry */
+		flags |= FLAG_ACTIVE;
+		writeb(flags, &FDB_MAC_TBL_ENTRY(mti)->flags);
+
+		return FDB_MAC_TBL_ENTRY(mti);
+	}
+
+	if (fdb->total_entries == FDB_MAC_TBL_MAX_ENTRIES)
+		return NULL;
+
+	empty_slot_idx = icssm_prueth_sw_fdb_empty_slot_left(mt, mti);
+	if (empty_slot_idx == -1) {
+		/* Nothing available on the left. But table isn't full
+		 * so there must be space to the right,
+		 */
+		empty_slot_idx = icssm_prueth_sw_fdb_empty_slot_right(mt, mti);
+
+		/* Shift right */
+		left = mti;
+		right = empty_slot_idx;
+		icssm_prueth_sw_fdb_move_range_right(prueth, left, right);
+
+		/* Claim the entry */
+		flags = readb(&FDB_MAC_TBL_ENTRY(mti)->flags);
+		flags |= FLAG_ACTIVE;
+		writeb(flags, &FDB_MAC_TBL_ENTRY(mti)->flags);
+
+		memcpy_toio(FDB_MAC_TBL_ENTRY(mti)->mac, mac, ETH_ALEN);
+
+		/* There is a chance we moved something in a
+		 * different bucket, update index table
+		 */
+		icssm_prueth_sw_fdb_update_index_tbl(prueth, left, right);
+
+		return FDB_MAC_TBL_ENTRY(mti);
+	}
+
+	if (empty_slot_idx == mti - 1) {
+		/* There is space immediately left of the open slot,
+		 * which means the inserted MAC address
+		 * must be the lowest-valued MAC address in bucket.
+		 * Update bucket pointer accordingly.
+		 */
+		writew(empty_slot_idx, &bucket_info->bucket_idx);
+
+		/* Claim the entry */
+		flags = readb(&FDB_MAC_TBL_ENTRY(mti)->flags);
+		flags |= FLAG_ACTIVE;
+		writeb(flags, &FDB_MAC_TBL_ENTRY(mti)->flags);
+
+		return FDB_MAC_TBL_ENTRY(empty_slot_idx);
+	}
+
+	/* There is empty space to the left, shift MAC table entries left */
+	left = empty_slot_idx;
+	right = mti - 1;
+	icssm_prueth_sw_fdb_move_range_left(prueth, left, right);
+
+	/* Claim the entry */
+	flags = readb(&FDB_MAC_TBL_ENTRY(mti - 1)->flags);
+	flags |= FLAG_ACTIVE;
+	writeb(flags, &FDB_MAC_TBL_ENTRY(mti - 1)->flags);
+
+	memcpy_toio(FDB_MAC_TBL_ENTRY(mti - 1)->mac, mac, ETH_ALEN);
+
+	/* There is a chance we moved something in a
+	 * different bucket, update index table
+	 */
+	icssm_prueth_sw_fdb_update_index_tbl(prueth, left, right);
+
+	return FDB_MAC_TBL_ENTRY(mti - 1);
+}
+
+static int icssm_prueth_sw_insert_fdb_entry(struct prueth_emac *emac,
+					    const u8 *mac, u8 is_static)
+{
+	struct fdb_index_tbl_entry __iomem *bucket_info;
+	struct fdb_mac_tbl_entry __iomem *mac_info;
+	struct prueth *prueth = emac->prueth;
+	unsigned int hash_val, mac_tbl_idx;
+	struct prueth_emac *other_emac;
+	enum prueth_port other_port_id;
+	int total_fdb_entries;
+	struct fdb_tbl *fdb;
+	u8 flags;
+	s16 ret;
+	int err;
+	u16 val;
+
+	fdb = prueth->fdb_tbl;
+	other_port_id = (emac->port_id == PRUETH_PORT_MII0) ?
+			 PRUETH_PORT_MII1 : PRUETH_PORT_MII0;
+
+	other_emac = prueth->emac[other_port_id - 1];
+
+	err = icssm_prueth_sw_fdb_spin_lock(fdb);
+	if (err) {
+		dev_err(prueth->dev, "PRU lock timeout %d\n", err);
+		return err;
+	}
+
+	if (fdb->total_entries == FDB_MAC_TBL_MAX_ENTRIES) {
+		icssm_prueth_sw_fdb_spin_unlock(fdb);
+		return -ENOMEM;
+	}
+
+	if (ether_addr_equal(mac, emac->mac_addr) ||
+	    ether_addr_equal(mac, other_emac->mac_addr)) {
+		icssm_prueth_sw_fdb_spin_unlock(fdb);
+		/* Don't insert fdb of own mac addr */
+		return -EINVAL;
+	}
+
+	/* Get the bucket that the mac belongs to */
+	hash_val = icssm_prueth_sw_fdb_hash(mac);
+	bucket_info = FDB_IDX_TBL_ENTRY(hash_val);
+
+	if (!readw(&bucket_info->bucket_entries)) {
+		mac_tbl_idx = icssm_prueth_sw_fdb_find_open_slot(fdb);
+		writew(mac_tbl_idx, &bucket_info->bucket_idx);
+	}
+
+	ret = icssm_prueth_sw_find_fdb_insert(fdb, prueth, bucket_info, mac,
+					      emac->port_id - 1);
+	if (ret < 0) {
+		icssm_prueth_sw_fdb_spin_unlock(fdb);
+		/* mac is already in fdb table */
+		return 0;
+	}
+
+	mac_tbl_idx = ret;
+
+	mac_info = icssm_prueth_sw_find_free_mac(prueth, bucket_info,
+						 mac_tbl_idx, NULL,
+						 mac);
+	if (!mac_info) {
+		/* Should not happen */
+		dev_warn(prueth->dev, "OUT of FDB MEM\n");
+		icssm_prueth_sw_fdb_spin_unlock(fdb);
+		return -ENOMEM;
+	}
+
+	memcpy_toio(mac_info->mac, mac, ETH_ALEN);
+	writew(0, &mac_info->age);
+	writeb(emac->port_id - 1, &mac_info->port);
+
+	flags = readb(&mac_info->flags);
+	if (is_static)
+		flags |= FLAG_IS_STATIC;
+	else
+		flags &= ~FLAG_IS_STATIC;
+
+	/* bit 1 - active */
+	flags |= FLAG_ACTIVE;
+	writeb(flags, &mac_info->flags);
+
+	val = readw(&bucket_info->bucket_entries);
+	val++;
+	writew(val, &bucket_info->bucket_entries);
+
+	fdb->total_entries++;
+
+	total_fdb_entries = fdb->total_entries;
+
+	icssm_prueth_sw_fdb_spin_unlock(fdb);
+
+	dev_dbg(prueth->dev, "added fdb: %pM port=%d total_entries=%u\n",
+		mac, emac->port_id, total_fdb_entries);
+
+	return 0;
+}
+
+static int icssm_prueth_sw_delete_fdb_entry(struct prueth_emac *emac,
+					    const u8 *mac, u8 is_static)
+{
+	struct fdb_index_tbl_entry __iomem *bucket_info;
+	struct fdb_mac_tbl_entry __iomem *mac_info;
+	struct fdb_mac_tbl_array __iomem *mt;
+	unsigned int hash_val, mac_tbl_idx;
+	unsigned int idx, entries;
+	struct prueth *prueth;
+	int total_fdb_entries;
+	s16 ret, left, right;
+	struct fdb_tbl *fdb;
+	u8 flags;
+	int err;
+	u16 val;
+
+	prueth = emac->prueth;
+	fdb = prueth->fdb_tbl;
+	mt = fdb->mac_tbl_a;
+
+	err = icssm_prueth_sw_fdb_spin_lock(fdb);
+	if (err) {
+		dev_err(prueth->dev, "PRU lock timeout %d\n", err);
+		return err;
+	}
+
+	if (fdb->total_entries == 0) {
+		icssm_prueth_sw_fdb_spin_unlock(fdb);
+		return 0;
+	}
+
+	/* Get the bucket that the mac belongs to */
+	hash_val = icssm_prueth_sw_fdb_hash(mac);
+	bucket_info = FDB_IDX_TBL_ENTRY(hash_val);
+
+	ret = icssm_prueth_sw_fdb_search(mt, bucket_info, mac);
+	if (ret < 0) {
+		icssm_prueth_sw_fdb_spin_unlock(fdb);
+		return ret;
+	}
+
+	mac_tbl_idx = ret;
+	mac_info = FDB_MAC_TBL_ENTRY(mac_tbl_idx);
+
+	/* Shift all elements in bucket to the left. No need to
+	 * update index table since only shifting within bucket.
+	 */
+	left = mac_tbl_idx;
+	idx = readw(&bucket_info->bucket_idx);
+	entries = readw(&bucket_info->bucket_entries);
+	right = idx + entries - 1;
+	icssm_prueth_sw_fdb_move_range_left(prueth, left, right);
+
+	/* Remove end of bucket from table */
+	mac_info = FDB_MAC_TBL_ENTRY(right);
+	flags = readb(&mac_info->flags);
+	/* active = 0 */
+	flags &= ~FLAG_ACTIVE;
+	writeb(flags, &mac_info->flags);
+	val = readw(&bucket_info->bucket_entries);
+	val--;
+	writew(val, &bucket_info->bucket_entries);
+	fdb->total_entries--;
+
+	total_fdb_entries = fdb->total_entries;
+
+	icssm_prueth_sw_fdb_spin_unlock(fdb);
+
+	dev_dbg(prueth->dev, "del fdb: %pM total_entries=%u\n",
+		mac, total_fdb_entries);
+
+	return 0;
+}
+
+int icssm_prueth_sw_do_purge_fdb(struct prueth_emac *emac)
+{
+	struct fdb_index_tbl_entry __iomem *bucket_info;
+	struct prueth *prueth = emac->prueth;
+	u8 flags, mac[ETH_ALEN];
+	unsigned int hash_val;
+	struct fdb_tbl *fdb;
+	int ret, i;
+	u16 val;
+
+	fdb = prueth->fdb_tbl;
+
+	ret = icssm_prueth_sw_fdb_spin_lock(fdb);
+	if (ret) {
+		dev_err(prueth->dev, "PRU lock timeout %d\n", ret);
+		return ret;
+	}
+
+	if (fdb->total_entries == 0) {
+		icssm_prueth_sw_fdb_spin_unlock(fdb);
+		return 0;
+	}
+
+	for (i = 0; i < FDB_MAC_TBL_MAX_ENTRIES; i++) {
+		flags = readb(&fdb->mac_tbl_a->mac_tbl_entry[i].flags);
+		if ((flags & FLAG_ACTIVE) && !(flags & FLAG_IS_STATIC)) {
+			/* Get the bucket that the mac belongs to */
+			memcpy_fromio(mac, FDB_MAC_TBL_ENTRY(i)->mac,
+				      ETH_ALEN);
+			hash_val = icssm_prueth_sw_fdb_hash(mac);
+			bucket_info = FDB_IDX_TBL_ENTRY(hash_val);
+			flags &= ~FLAG_ACTIVE;
+			writeb(flags,
+			       &fdb->mac_tbl_a->mac_tbl_entry[i].flags);
+			val = readw(&bucket_info->bucket_entries);
+			val--;
+			writew(val, &bucket_info->bucket_entries);
+			fdb->total_entries--;
+		}
+	}
+
+	icssm_prueth_sw_fdb_spin_unlock(fdb);
+	return 0;
+}
+
+int icssm_prueth_sw_init_fdb_table(struct prueth *prueth)
+{
+	if (prueth->emac_configured)
+		return 0;
+
+	prueth->fdb_tbl = kmalloc(sizeof(*prueth->fdb_tbl), GFP_KERNEL);
+	if (!prueth->fdb_tbl)
+		return -ENOMEM;
+
+	icssm_prueth_sw_fdb_tbl_init(prueth);
+
+	return 0;
+}
+
+/**
+ * icssm_prueth_sw_fdb_add - insert fdb entry
+ *
+ * @emac: EMAC data structure
+ * @fdb: fdb info
+ *
+ */
+void icssm_prueth_sw_fdb_add(struct prueth_emac *emac,
+			     struct switchdev_notifier_fdb_info *fdb)
+{
+	icssm_prueth_sw_insert_fdb_entry(emac, fdb->addr, 1);
+}
+
+/**
+ * icssm_prueth_sw_fdb_del - delete fdb entry
+ *
+ * @emac: EMAC data structure
+ * @fdb: fdb info
+ *
+ */
+void icssm_prueth_sw_fdb_del(struct prueth_emac *emac,
+			     struct switchdev_notifier_fdb_info *fdb)
+{
+	icssm_prueth_sw_delete_fdb_entry(emac, fdb->addr, 1);
+}
diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h
new file mode 100644
index 000000000000..fd013ecdc707
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com
+ */
+
+#ifndef __NET_TI_PRUETH_SWITCH_H
+#define __NET_TI_PRUETH_SWITCH_H
+
+#include "icssm_prueth.h"
+#include "icssm_prueth_fdb_tbl.h"
+
+void icssm_prueth_sw_fdb_tbl_init(struct prueth *prueth);
+int icssm_prueth_sw_init_fdb_table(struct prueth *prueth);
+void icssm_prueth_sw_free_fdb_table(struct prueth *prueth);
+int icssm_prueth_sw_do_purge_fdb(struct prueth_emac *emac);
+void icssm_prueth_sw_fdb_add(struct prueth_emac *emac,
+			     struct switchdev_notifier_fdb_info *fdb);
+void icssm_prueth_sw_fdb_del(struct prueth_emac *emac,
+			     struct switchdev_notifier_fdb_info *fdb);
+
+#endif /* __NET_TI_PRUETH_SWITCH_H */
diff --git a/drivers/net/ethernet/ti/icssm/icssm_switch.h b/drivers/net/ethernet/ti/icssm/icssm_switch.h
index 8b494ffdcde7..4200ccb1b425 100644
--- a/drivers/net/ethernet/ti/icssm/icssm_switch.h
+++ b/drivers/net/ethernet/ti/icssm/icssm_switch.h
@@ -254,4 +254,30 @@
 #define P0_COL_BUFFER_OFFSET	0xEE00
 #define P0_Q1_BUFFER_OFFSET	0x0000
 
+#define V2_1_FDB_TBL_LOC          PRUETH_MEM_SHARED_RAM
+#define V2_1_FDB_TBL_OFFSET       0x2000
+
+#define FDB_INDEX_TBL_MAX_ENTRIES     256
+#define FDB_MAC_TBL_MAX_ENTRIES       256
+
+#define FDB_INDEX_TBL_OFFSET    V2_1_FDB_TBL_OFFSET
+#define FDB_INDEX_TBL_SIZE      (FDB_INDEX_TBL_MAX_ENTRIES * \
+				 sizeof(struct fdb_index_tbl_entry))
+
+#define FDB_MAC_TBL_OFFSET      (FDB_INDEX_TBL_OFFSET + FDB_INDEX_TBL_SIZE)
+#define FDB_MAC_TBL_SIZE        (FDB_MAC_TBL_MAX_ENTRIES * \
+				 sizeof(struct fdb_mac_tbl_entry))
+
+#define FDB_PORT1_STP_CFG_OFFSET        (FDB_MAC_TBL_OFFSET + FDB_MAC_TBL_SIZE)
+#define FDB_PORT_STP_CFG_SIZE           sizeof(struct fdb_stp_config)
+#define FDB_PORT2_STP_CFG_OFFSET        (FDB_PORT1_STP_CFG_OFFSET + \
+					 FDB_PORT_STP_CFG_SIZE)
+
+#define FDB_FLOOD_ENABLE_FLAGS_OFFSET   (FDB_PORT2_STP_CFG_OFFSET + \
+					FDB_PORT_STP_CFG_SIZE)
+#define FDB_FLOOD_ENABLE_FLAGS_SIZE     sizeof(struct fdb_flood_config)
+
+#define FDB_LOCKS_OFFSET        (FDB_FLOOD_ENABLE_FLAGS_OFFSET + \
+				 FDB_FLOOD_ENABLE_FLAGS_SIZE)
+
 #endif /* __ICSS_SWITCH_H */
-- 
2.43.0



From parvathi at couthit.com  Fri Dec  5 04:29:12 2025
From: parvathi at couthit.com (Parvathi Pudi)
Date: Fri,  5 Dec 2025 17:59:12 +0530
Subject: [RFC PATCH net-next v9 2/3] net: ti: icssm-prueth: Add switchdev support for icssm_prueth driver
In-Reply-To: <20251205123146.462397-1-parvathi@couthit.com>
References: <20251205123146.462397-1-parvathi@couthit.com>
Message-ID: <20251205123146.462397-3-parvathi@couthit.com>

From: Roger Quadros <rogerq at ti.com>

Add support for offloading the RSTP switch feature to the PRU-ICSS
subsystem by adding switchdev support. PRU-ICSS is capable of operating
in RSTP switch mode with two external ports and one host port.

PRUETH driver and firmware interface support will be added into
icssm_prueth in the subsequent commits.

Signed-off-by: Roger Quadros <rogerq at ti.com>
Signed-off-by: Andrew F. Davis <afd at ti.com>
Signed-off-by: Basharath Hussain Khaja <basharath at couthit.com>
Signed-off-by: Parvathi Pudi <parvathi at couthit.com>
---
 drivers/net/ethernet/ti/Makefile              |   2 +-
 drivers/net/ethernet/ti/icssm/icssm_prueth.c  | 180 ++++++++++
 drivers/net/ethernet/ti/icssm/icssm_prueth.h  |  11 +-
 .../ethernet/ti/icssm/icssm_prueth_switch.c   |  77 ++++
 .../ethernet/ti/icssm/icssm_prueth_switch.h   |  11 +-
 .../net/ethernet/ti/icssm/icssm_switchdev.c   | 333 ++++++++++++++++++
 .../net/ethernet/ti/icssm/icssm_switchdev.h   |  13 +
 .../ti/icssm/icssm_vlan_mcast_filter_mmap.h   | 120 +++++++
 8 files changed, 744 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/ethernet/ti/icssm/icssm_switchdev.c
 create mode 100644 drivers/net/ethernet/ti/icssm/icssm_switchdev.h
 create mode 100644 drivers/net/ethernet/ti/icssm/icssm_vlan_mcast_filter_mmap.h

diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile
index 1fd149dd6115..6da50f4b7c2e 100644
--- a/drivers/net/ethernet/ti/Makefile
+++ b/drivers/net/ethernet/ti/Makefile
@@ -4,7 +4,7 @@
 #
 
 obj-$(CONFIG_TI_PRUETH) += icssm-prueth.o
-icssm-prueth-y := icssm/icssm_prueth.o icssm/icssm_prueth_switch.o
+icssm-prueth-y := icssm/icssm_prueth.o icssm/icssm_prueth_switch.o icssm/icssm_switchdev.o
 
 obj-$(CONFIG_TI_CPSW) += cpsw-common.o
 obj-$(CONFIG_TI_DAVINCI_EMAC) += cpsw-common.o
diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.c b/drivers/net/ethernet/ti/icssm/icssm_prueth.c
index 293b7af04263..b779096c09e8 100644
--- a/drivers/net/ethernet/ti/icssm/icssm_prueth.c
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.c
@@ -29,6 +29,8 @@
 #include <net/pkt_cls.h>
 
 #include "icssm_prueth.h"
+#include "icssm_prueth_switch.h"
+#include "icssm_vlan_mcast_filter_mmap.h"
 #include "../icssg/icssg_mii_rt.h"
 #include "../icssg/icss_iep.h"
 
@@ -1131,11 +1133,174 @@ static void icssm_emac_ndo_get_stats64(struct net_device *ndev,
 	stats->rx_length_errors = emac->stats.rx_length_errors;
 }
 
+/* enable/disable MC filter */
+static void icssm_emac_mc_filter_ctrl(struct prueth_emac *emac, bool enable)
+{
+	struct prueth *prueth = emac->prueth;
+	void __iomem *mc_filter_ctrl;
+	void __iomem *ram;
+	u32 reg;
+
+	ram = prueth->mem[emac->dram].va;
+	mc_filter_ctrl = ram + ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_OFFSET;
+
+	if (enable)
+		reg = ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_ENABLED;
+	else
+		reg = ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_DISABLED;
+
+	writeb(reg, mc_filter_ctrl);
+}
+
+/* reset MC filter bins */
+static void icssm_emac_mc_filter_reset(struct prueth_emac *emac)
+{
+	struct prueth *prueth = emac->prueth;
+	void __iomem *mc_filter_tbl;
+	u32 mc_filter_tbl_base;
+	void __iomem *ram;
+
+	ram = prueth->mem[emac->dram].va;
+	mc_filter_tbl_base = ICSS_EMAC_FW_MULTICAST_FILTER_TABLE;
+
+	mc_filter_tbl = ram + mc_filter_tbl_base;
+	memset_io(mc_filter_tbl, 0, ICSS_EMAC_FW_MULTICAST_TABLE_SIZE_BYTES);
+}
+
+/* set MC filter hashmask */
+static void icssm_emac_mc_filter_hashmask
+		(struct prueth_emac *emac,
+		 u8 mask[ICSS_EMAC_FW_MULTICAST_FILTER_MASK_SIZE_BYTES])
+{
+	struct prueth *prueth = emac->prueth;
+	void __iomem *mc_filter_mask;
+	void __iomem *ram;
+
+	ram = prueth->mem[emac->dram].va;
+
+	mc_filter_mask = ram + ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OFFSET;
+	memcpy_toio(mc_filter_mask, mask,
+		    ICSS_EMAC_FW_MULTICAST_FILTER_MASK_SIZE_BYTES);
+}
+
+static void icssm_emac_mc_filter_bin_update(struct prueth_emac *emac, u8 hash,
+					    u8 val)
+{
+	struct prueth *prueth = emac->prueth;
+	void __iomem *mc_filter_tbl;
+	void __iomem *ram;
+
+	ram = prueth->mem[emac->dram].va;
+
+	mc_filter_tbl = ram + ICSS_EMAC_FW_MULTICAST_FILTER_TABLE;
+	writeb(val, mc_filter_tbl + hash);
+}
+
+void icssm_emac_mc_filter_bin_allow(struct prueth_emac *emac, u8 hash)
+{
+	icssm_emac_mc_filter_bin_update
+		(emac, hash,
+		 ICSS_EMAC_FW_MULTICAST_FILTER_HOST_RCV_ALLOWED);
+}
+
+void icssm_emac_mc_filter_bin_disallow(struct prueth_emac *emac, u8 hash)
+{
+	icssm_emac_mc_filter_bin_update
+		(emac, hash,
+		 ICSS_EMAC_FW_MULTICAST_FILTER_HOST_RCV_NOT_ALLOWED);
+}
+
+u8 icssm_emac_get_mc_hash(u8 *mac, u8 *mask)
+{
+	u8 hash;
+	int j;
+
+	for (j = 0, hash = 0; j < ETH_ALEN; j++)
+		hash ^= (mac[j] & mask[j]);
+
+	return hash;
+}
+
+/**
+ * icssm_emac_ndo_set_rx_mode - EMAC set receive mode function
+ * @ndev: The EMAC network adapter
+ *
+ * Called when system wants to set the receive mode of the device.
+ *
+ */
+static void icssm_emac_ndo_set_rx_mode(struct net_device *ndev)
+{
+	struct prueth_emac *emac = netdev_priv(ndev);
+	bool promisc = ndev->flags & IFF_PROMISC;
+	struct netdev_hw_addr *ha;
+	struct prueth *prueth;
+	unsigned long flags;
+	void __iomem *sram;
+	u32 mask, reg;
+	u8 hash;
+
+	prueth = emac->prueth;
+	sram = prueth->mem[PRUETH_MEM_SHARED_RAM].va;
+	reg = readl(sram + EMAC_PROMISCUOUS_MODE_OFFSET);
+
+	/* It is a shared table. So lock the access */
+	spin_lock_irqsave(&emac->addr_lock, flags);
+
+	/* Disable and reset multicast filter, allows allmulti */
+	icssm_emac_mc_filter_ctrl(emac, false);
+	icssm_emac_mc_filter_reset(emac);
+	icssm_emac_mc_filter_hashmask(emac, emac->mc_filter_mask);
+
+	if (PRUETH_IS_EMAC(prueth)) {
+		switch (emac->port_id) {
+		case PRUETH_PORT_MII0:
+			mask = EMAC_P1_PROMISCUOUS_BIT;
+			break;
+		case PRUETH_PORT_MII1:
+			mask = EMAC_P2_PROMISCUOUS_BIT;
+			break;
+		default:
+			netdev_err(ndev, "%s: invalid port\n", __func__);
+			goto unlock;
+		}
+
+		if (promisc) {
+			/* Enable promiscuous mode */
+			reg |= mask;
+		} else {
+			/* Disable promiscuous mode */
+			reg &= ~mask;
+		}
+
+		writel(reg, sram + EMAC_PROMISCUOUS_MODE_OFFSET);
+
+		if (promisc)
+			goto unlock;
+	}
+
+	if (ndev->flags & IFF_ALLMULTI && !PRUETH_IS_SWITCH(prueth))
+		goto unlock;
+
+	icssm_emac_mc_filter_ctrl(emac, true);	/* all multicast blocked */
+
+	if (netdev_mc_empty(ndev))
+		goto unlock;
+
+	netdev_for_each_mc_addr(ha, ndev) {
+		hash = icssm_emac_get_mc_hash(ha->addr, emac->mc_filter_mask);
+		icssm_emac_mc_filter_bin_allow(emac, hash);
+	}
+
+unlock:
+	spin_unlock_irqrestore(&emac->addr_lock, flags);
+}
+
 static const struct net_device_ops emac_netdev_ops = {
 	.ndo_open = icssm_emac_ndo_open,
 	.ndo_stop = icssm_emac_ndo_stop,
 	.ndo_start_xmit = icssm_emac_ndo_start_xmit,
 	.ndo_get_stats64 = icssm_emac_ndo_get_stats64,
+	.ndo_set_rx_mode = icssm_emac_ndo_set_rx_mode,
 };
 
 /* get emac_port corresponding to eth_node name */
@@ -1212,6 +1377,7 @@ static int icssm_prueth_netdev_init(struct prueth *prueth,
 	emac->prueth = prueth;
 	emac->ndev = ndev;
 	emac->port_id = port;
+	memset(&emac->mc_filter_mask[0], 0xff, ETH_ALEN);
 
 	/* by default eth_type is EMAC */
 	switch (port) {
@@ -1247,6 +1413,9 @@ static int icssm_prueth_netdev_init(struct prueth *prueth,
 		goto free;
 	}
 
+	spin_lock_init(&emac->lock);
+	spin_lock_init(&emac->addr_lock);
+
 	/* get mac address from DT and set private and netdev addr */
 	ret = of_get_ethdev_address(eth_node, ndev);
 	if (!is_valid_ether_addr(ndev->dev_addr)) {
@@ -1310,6 +1479,17 @@ static void icssm_prueth_netdev_exit(struct prueth *prueth,
 	prueth->emac[mac] = NULL;
 }
 
+bool icssm_prueth_sw_port_dev_check(const struct net_device *ndev)
+{
+	if (ndev->netdev_ops != &emac_netdev_ops)
+		return false;
+
+	if (ndev->features & NETIF_F_HW_L2FW_DOFFLOAD)
+		return true;
+
+	return false;
+}
+
 static int icssm_prueth_probe(struct platform_device *pdev)
 {
 	struct device_node *eth0_node = NULL, *eth1_node = NULL;
diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.h b/drivers/net/ethernet/ti/icssm/icssm_prueth.h
index 4b50133c5a72..f95c8c3a7ee5 100644
--- a/drivers/net/ethernet/ti/icssm/icssm_prueth.h
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.h
@@ -222,12 +222,14 @@ struct prueth_emac {
 	const char *phy_id;
 	u32 msg_enable;
 	u8 mac_addr[6];
+	unsigned char mc_filter_mask[ETH_ALEN]; /* for multicast filtering */
 	phy_interface_t phy_if;
 
 	/* spin lock used to protect
 	 * during link configuration
 	 */
 	spinlock_t lock;
+	spinlock_t addr_lock;   /* serialize access to VLAN/MC filter table */
 
 	struct hrtimer tx_hrtimer;
 	struct prueth_emac_stats stats;
@@ -249,8 +251,13 @@ struct prueth {
 	struct prueth_emac *emac[PRUETH_NUM_MACS];
 	struct net_device *registered_netdevs[PRUETH_NUM_MACS];
 
+	struct net_device *hw_bridge_dev;
 	struct fdb_tbl *fdb_tbl;
 
+	struct notifier_block prueth_netdevice_nb;
+	struct notifier_block prueth_switchdev_nb;
+	struct notifier_block prueth_switchdev_bl_nb;
+
 	unsigned int eth_type;
 	size_t ocmc_ram_size;
 	u8 emac_configured;
@@ -261,5 +268,7 @@ void icssm_parse_packet_info(struct prueth *prueth, u32 buffer_descriptor,
 int icssm_emac_rx_packet(struct prueth_emac *emac, u16 *bd_rd_ptr,
 			 struct prueth_packet_info *pkt_info,
 			 const struct prueth_queue_info *rxqueue);
-
+void icssm_emac_mc_filter_bin_allow(struct prueth_emac *emac, u8 hash);
+void icssm_emac_mc_filter_bin_disallow(struct prueth_emac *emac, u8 hash);
+u8 icssm_emac_get_mc_hash(u8 *mac, u8 *mask);
 #endif /* __NET_TI_PRUETH_H */
diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c
index 82851d38cd46..dd7f24469ab2 100644
--- a/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c
@@ -18,6 +18,17 @@
 #define FLAG_IS_STATIC	BIT(0)
 #define FLAG_ACTIVE	BIT(1)
 
+#define FDB_LEARN  1
+#define FDB_PURGE  2
+
+struct icssm_prueth_sw_fdb_work {
+	netdevice_tracker ndev_tracker;
+	struct work_struct work;
+	struct prueth_emac *emac;
+	u8 addr[ETH_ALEN];
+	int event;
+};
+
 void icssm_prueth_sw_free_fdb_table(struct prueth *prueth)
 {
 	if (prueth->emac_configured)
@@ -596,3 +607,69 @@ void icssm_prueth_sw_fdb_del(struct prueth_emac *emac,
 {
 	icssm_prueth_sw_delete_fdb_entry(emac, fdb->addr, 1);
 }
+
+static void icssm_prueth_sw_fdb_work(struct work_struct *work)
+{
+	struct icssm_prueth_sw_fdb_work *fdb_work =
+		container_of(work, struct icssm_prueth_sw_fdb_work, work);
+	struct prueth_emac *emac = fdb_work->emac;
+
+	rtnl_lock();
+
+	/* Interface is not up */
+	if (!emac->prueth->fdb_tbl)
+		goto free;
+
+	switch (fdb_work->event) {
+	case FDB_LEARN:
+		icssm_prueth_sw_insert_fdb_entry(emac, fdb_work->addr, 0);
+		break;
+	case FDB_PURGE:
+		icssm_prueth_sw_do_purge_fdb(emac);
+		break;
+	default:
+		break;
+	}
+
+free:
+	rtnl_unlock();
+	netdev_put(emac->ndev, &fdb_work->ndev_tracker);
+	kfree(fdb_work);
+}
+
+int icssm_prueth_sw_learn_fdb(struct prueth_emac *emac, u8 *src_mac)
+{
+	struct icssm_prueth_sw_fdb_work *fdb_work;
+
+	fdb_work = kzalloc(sizeof(*fdb_work), GFP_ATOMIC);
+	if (WARN_ON(!fdb_work))
+		return -ENOMEM;
+
+	INIT_WORK(&fdb_work->work, icssm_prueth_sw_fdb_work);
+
+	fdb_work->event = FDB_LEARN;
+	fdb_work->emac  = emac;
+	ether_addr_copy(fdb_work->addr, src_mac);
+
+	netdev_hold(emac->ndev, &fdb_work->ndev_tracker, GFP_ATOMIC);
+	queue_work(system_long_wq, &fdb_work->work);
+	return 0;
+}
+
+int icssm_prueth_sw_purge_fdb(struct prueth_emac *emac)
+{
+	struct icssm_prueth_sw_fdb_work *fdb_work;
+
+	fdb_work = kzalloc(sizeof(*fdb_work), GFP_ATOMIC);
+	if (WARN_ON(!fdb_work))
+		return -ENOMEM;
+
+	INIT_WORK(&fdb_work->work, icssm_prueth_sw_fdb_work);
+
+	fdb_work->event = FDB_PURGE;
+	fdb_work->emac  = emac;
+
+	netdev_hold(emac->ndev, &fdb_work->ndev_tracker, GFP_ATOMIC);
+	queue_work(system_long_wq, &fdb_work->work);
+	return 0;
+}
diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h
index fd013ecdc707..218cbe1d3c50 100644
--- a/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h
@@ -5,8 +5,16 @@
 #ifndef __NET_TI_PRUETH_SWITCH_H
 #define __NET_TI_PRUETH_SWITCH_H
 
+#include <net/switchdev.h>
+
 #include "icssm_prueth.h"
 #include "icssm_prueth_fdb_tbl.h"
+#include "icssm_switchdev.h"
+
+void icssm_prueth_sw_set_stp_state(struct prueth *prueth,
+				   enum prueth_port port, u8 state);
+u8 icssm_prueth_sw_get_stp_state(struct prueth *prueth,
+				 enum prueth_port port);
 
 void icssm_prueth_sw_fdb_tbl_init(struct prueth *prueth);
 int icssm_prueth_sw_init_fdb_table(struct prueth *prueth);
@@ -16,5 +24,6 @@ void icssm_prueth_sw_fdb_add(struct prueth_emac *emac,
 			     struct switchdev_notifier_fdb_info *fdb);
 void icssm_prueth_sw_fdb_del(struct prueth_emac *emac,
 			     struct switchdev_notifier_fdb_info *fdb);
-
+int icssm_prueth_sw_learn_fdb(struct prueth_emac *emac, u8 *src_mac);
+int icssm_prueth_sw_purge_fdb(struct prueth_emac *emac);
 #endif /* __NET_TI_PRUETH_SWITCH_H */
diff --git a/drivers/net/ethernet/ti/icssm/icssm_switchdev.c b/drivers/net/ethernet/ti/icssm/icssm_switchdev.c
new file mode 100644
index 000000000000..414ec9fc02a0
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssm/icssm_switchdev.c
@@ -0,0 +1,333 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* Texas Instruments ICSSM Ethernet Driver
+ *
+ * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/kernel.h>
+#include <linux/remoteproc.h>
+#include <net/switchdev.h>
+
+#include "icssm_prueth.h"
+#include "icssm_prueth_switch.h"
+#include "icssm_prueth_fdb_tbl.h"
+
+/* switchev event work */
+struct icssm_sw_event_work {
+	netdevice_tracker ndev_tracker;
+	struct work_struct work;
+	struct switchdev_notifier_fdb_info fdb_info;
+	struct prueth_emac *emac;
+	unsigned long event;
+};
+
+void icssm_prueth_sw_set_stp_state(struct prueth *prueth,
+				   enum prueth_port port, u8 state)
+{
+	struct fdb_tbl *t = prueth->fdb_tbl;
+
+	writeb(state, port - 1 ? (void __iomem *)&t->port2_stp_cfg->state :
+			(void __iomem *)&t->port1_stp_cfg->state);
+}
+
+u8 icssm_prueth_sw_get_stp_state(struct prueth *prueth, enum prueth_port port)
+{
+	struct fdb_tbl *t = prueth->fdb_tbl;
+	u8 state;
+
+	state = readb(port - 1 ? (void __iomem *)&t->port2_stp_cfg->state :
+			(void __iomem *)&t->port1_stp_cfg->state);
+	return state;
+}
+
+static int icssm_prueth_sw_attr_set(struct net_device *ndev, const void *ctx,
+				    const struct switchdev_attr *attr,
+				    struct netlink_ext_ack *extack)
+{
+	struct prueth_emac *emac = netdev_priv(ndev);
+	struct prueth *prueth = emac->prueth;
+	int err = 0;
+	u8 o_state;
+
+	/* Interface is not up */
+	if (!prueth->fdb_tbl)
+		return 0;
+
+	switch (attr->id) {
+	case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
+		o_state = icssm_prueth_sw_get_stp_state(prueth, emac->port_id);
+		icssm_prueth_sw_set_stp_state(prueth, emac->port_id,
+					      attr->u.stp_state);
+
+		if (o_state != attr->u.stp_state)
+			icssm_prueth_sw_purge_fdb(emac);
+
+		dev_dbg(prueth->dev, "attr set: stp state:%u port:%u\n",
+			attr->u.stp_state, emac->port_id);
+		break;
+	default:
+		err = -EOPNOTSUPP;
+		break;
+	}
+
+	return err;
+}
+
+static void icssm_prueth_sw_fdb_offload(struct net_device *ndev,
+					struct switchdev_notifier_fdb_info *rcv)
+{
+	struct switchdev_notifier_fdb_info info;
+
+	info.addr = rcv->addr;
+	info.vid = rcv->vid;
+	call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, ndev, &info.info,
+				 NULL);
+}
+
+/**
+ * icssm_sw_event_work - insert/delete fdb entry
+ *
+ * @work: work structure
+ *
+ */
+static void icssm_sw_event_work(struct work_struct *work)
+{
+	struct icssm_sw_event_work *switchdev_work =
+		container_of(work, struct icssm_sw_event_work, work);
+	struct prueth_emac *emac = switchdev_work->emac;
+	struct switchdev_notifier_fdb_info *fdb;
+	struct prueth *prueth = emac->prueth;
+	int port = emac->port_id;
+
+	rtnl_lock();
+
+	/* Interface is not up */
+	if (!emac->prueth->fdb_tbl)
+		goto free;
+
+	switch (switchdev_work->event) {
+	case SWITCHDEV_FDB_ADD_TO_DEVICE:
+		fdb = &switchdev_work->fdb_info;
+		dev_dbg(prueth->dev,
+			"prueth fdb add: MACID = %pM vid = %u flags = %u -- port %d\n",
+			fdb->addr, fdb->vid, fdb->added_by_user, port);
+
+		if (!fdb->added_by_user)
+			break;
+
+		if (fdb->is_local)
+			break;
+
+		icssm_prueth_sw_fdb_add(emac, fdb);
+		icssm_prueth_sw_fdb_offload(emac->ndev, fdb);
+		break;
+	case SWITCHDEV_FDB_DEL_TO_DEVICE:
+		fdb = &switchdev_work->fdb_info;
+		dev_dbg(prueth->dev,
+			"prueth fdb del: MACID = %pM vid = %u flags = %u -- port %d\n",
+			fdb->addr, fdb->vid, fdb->added_by_user, port);
+
+		if (fdb->is_local)
+			break;
+
+		icssm_prueth_sw_fdb_del(emac, fdb);
+		break;
+	default:
+		break;
+	}
+
+free:
+	rtnl_unlock();
+
+	netdev_put(emac->ndev, &switchdev_work->ndev_tracker);
+	kfree(switchdev_work->fdb_info.addr);
+	kfree(switchdev_work);
+}
+
+/* called under rcu_read_lock() */
+static int icssm_prueth_sw_switchdev_event(struct notifier_block *unused,
+					   unsigned long event, void *ptr)
+{
+	struct net_device *ndev = switchdev_notifier_info_to_dev(ptr);
+	struct switchdev_notifier_fdb_info *fdb_info = ptr;
+	struct prueth_emac *emac = netdev_priv(ndev);
+	struct icssm_sw_event_work *switchdev_work;
+	int err;
+
+	if (!icssm_prueth_sw_port_dev_check(ndev))
+		return NOTIFY_DONE;
+
+	if (event == SWITCHDEV_PORT_ATTR_SET) {
+		err = switchdev_handle_port_attr_set
+			(ndev, ptr, icssm_prueth_sw_port_dev_check,
+			 icssm_prueth_sw_attr_set);
+		return notifier_from_errno(err);
+	}
+
+	switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC);
+	if (WARN_ON(!switchdev_work))
+		return NOTIFY_BAD;
+
+	INIT_WORK(&switchdev_work->work, icssm_sw_event_work);
+	switchdev_work->emac = emac;
+	switchdev_work->event = event;
+
+	switch (event) {
+	case SWITCHDEV_FDB_ADD_TO_DEVICE:
+	case SWITCHDEV_FDB_DEL_TO_DEVICE:
+		memcpy(&switchdev_work->fdb_info, ptr,
+		       sizeof(switchdev_work->fdb_info));
+		switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC);
+		if (!switchdev_work->fdb_info.addr)
+			goto err_addr_alloc;
+		ether_addr_copy((u8 *)switchdev_work->fdb_info.addr,
+				fdb_info->addr);
+		netdev_hold(ndev, &switchdev_work->ndev_tracker, GFP_ATOMIC);
+		break;
+	default:
+		kfree(switchdev_work);
+		return NOTIFY_DONE;
+	}
+
+	queue_work(system_long_wq, &switchdev_work->work);
+
+	return NOTIFY_DONE;
+
+err_addr_alloc:
+	kfree(switchdev_work);
+	return NOTIFY_BAD;
+}
+
+static int icssm_prueth_switchdev_obj_add(struct net_device *ndev,
+					  const void *ctx,
+					  const struct switchdev_obj *obj,
+					  struct netlink_ext_ack *extack)
+{
+	struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj);
+	struct prueth_emac *emac = netdev_priv(ndev);
+	struct prueth *prueth = emac->prueth;
+	int ret = 0;
+	u8 hash;
+
+	switch (obj->id) {
+	case SWITCHDEV_OBJ_ID_HOST_MDB:
+		dev_dbg(prueth->dev, "MDB add: %s: vid %u:%pM  port: %x\n",
+			ndev->name, mdb->vid, mdb->addr, emac->port_id);
+		hash = icssm_emac_get_mc_hash(mdb->addr, emac->mc_filter_mask);
+		icssm_emac_mc_filter_bin_allow(emac, hash);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+	return ret;
+}
+
+static int icssm_prueth_switchdev_obj_del(struct net_device *ndev,
+					  const void *ctx,
+					  const struct switchdev_obj *obj)
+{
+	struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj);
+	struct prueth_emac *emac = netdev_priv(ndev);
+	struct prueth *prueth = emac->prueth;
+	struct netdev_hw_addr *ha;
+	u8 hash, tmp_hash;
+	int ret = 0;
+	u8 *mask;
+
+	switch (obj->id) {
+	case SWITCHDEV_OBJ_ID_HOST_MDB:
+		dev_dbg(prueth->dev, "MDB del: %s: vid %u:%pM  port: %x\n",
+			ndev->name, mdb->vid, mdb->addr, emac->port_id);
+		if (prueth->hw_bridge_dev) {
+			mask = emac->mc_filter_mask;
+			hash = icssm_emac_get_mc_hash(mdb->addr, mask);
+			netdev_for_each_mc_addr(ha, prueth->hw_bridge_dev) {
+				tmp_hash = icssm_emac_get_mc_hash(ha->addr,
+								  mask);
+				/* Another MC address is in the bin.
+				 * Don't disable.
+				 */
+				if (tmp_hash == hash)
+					return 0;
+			}
+			icssm_emac_mc_filter_bin_disallow(emac, hash);
+		}
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+	return ret;
+}
+
+/* switchdev notifiers */
+static int icssm_prueth_sw_blocking_event(struct notifier_block *unused,
+					  unsigned long event, void *ptr)
+{
+	struct net_device *ndev = switchdev_notifier_info_to_dev(ptr);
+	int err;
+
+	switch (event) {
+	case SWITCHDEV_PORT_OBJ_ADD:
+		err = switchdev_handle_port_obj_add
+			(ndev, ptr, icssm_prueth_sw_port_dev_check,
+			 icssm_prueth_switchdev_obj_add);
+		return notifier_from_errno(err);
+
+	case SWITCHDEV_PORT_OBJ_DEL:
+		err = switchdev_handle_port_obj_del
+			(ndev, ptr, icssm_prueth_sw_port_dev_check,
+			 icssm_prueth_switchdev_obj_del);
+		return notifier_from_errno(err);
+
+	case SWITCHDEV_PORT_ATTR_SET:
+		err = switchdev_handle_port_attr_set
+			(ndev, ptr, icssm_prueth_sw_port_dev_check,
+			 icssm_prueth_sw_attr_set);
+		return notifier_from_errno(err);
+
+	default:
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+int icssm_prueth_sw_register_notifiers(struct prueth *prueth)
+{
+	int ret = 0;
+
+	prueth->prueth_switchdev_nb.notifier_call =
+		&icssm_prueth_sw_switchdev_event;
+	ret = register_switchdev_notifier(&prueth->prueth_switchdev_nb);
+	if (ret) {
+		dev_err(prueth->dev,
+			"register switchdev notifier failed ret:%d\n", ret);
+		return ret;
+	}
+
+	prueth->prueth_switchdev_bl_nb.notifier_call =
+		&icssm_prueth_sw_blocking_event;
+	ret = register_switchdev_blocking_notifier
+		(&prueth->prueth_switchdev_bl_nb);
+	if (ret) {
+		dev_err(prueth->dev,
+			"register switchdev blocking notifier failed ret:%d\n",
+			ret);
+		unregister_switchdev_notifier(&prueth->prueth_switchdev_nb);
+	}
+
+	return ret;
+}
+
+void icssm_prueth_sw_unregister_notifiers(struct prueth *prueth)
+{
+	unregister_switchdev_blocking_notifier(&prueth->prueth_switchdev_bl_nb);
+	unregister_switchdev_notifier(&prueth->prueth_switchdev_nb);
+}
diff --git a/drivers/net/ethernet/ti/icssm/icssm_switchdev.h b/drivers/net/ethernet/ti/icssm/icssm_switchdev.h
new file mode 100644
index 000000000000..b03a98e3472e
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssm/icssm_switchdev.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com
+ */
+
+#ifndef __NET_TI_ICSSM_SWITCHDEV_H
+#define __NET_TI_ICSSM_SWITCHDEV_H
+
+#include "icssm_prueth.h"
+
+int icssm_prueth_sw_register_notifiers(struct prueth *prueth);
+void icssm_prueth_sw_unregister_notifiers(struct prueth *prueth);
+bool icssm_prueth_sw_port_dev_check(const struct net_device *ndev);
+#endif /* __NET_TI_ICSSM_SWITCHDEV_H */
diff --git a/drivers/net/ethernet/ti/icssm/icssm_vlan_mcast_filter_mmap.h b/drivers/net/ethernet/ti/icssm/icssm_vlan_mcast_filter_mmap.h
new file mode 100644
index 000000000000..c177c19a36ef
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssm/icssm_vlan_mcast_filter_mmap.h
@@ -0,0 +1,120 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* Copyright (C) 2015-2021 Texas Instruments Incorporated - https://www.ti.com
+ *
+ * This file contains VLAN/Multicast filtering feature memory map
+ *
+ */
+
+#ifndef ICSS_VLAN_MULTICAST_FILTER_MM_H
+#define ICSS_VLAN_MULTICAST_FILTER_MM_H
+
+/* VLAN/Multicast filter defines & offsets,
+ * present on both PRU0 and PRU1 DRAM
+ */
+
+/* Feature enable/disable values for multicast filtering */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_DISABLED		0x00
+#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_ENABLED		0x01
+
+/* Feature enable/disable values for VLAN filtering */
+#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_DISABLED			0x00
+#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_ENABLED			0x01
+
+/* Add/remove multicast mac id for filtering bin */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_HOST_RCV_ALLOWED		0x01
+#define ICSS_EMAC_FW_MULTICAST_FILTER_HOST_RCV_NOT_ALLOWED	0x00
+
+/* Default HASH value for the multicast filtering Mask */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_INIT_VAL			0xFF
+
+/* Size requirements for Multicast filtering feature */
+#define ICSS_EMAC_FW_MULTICAST_TABLE_SIZE_BYTES			       256
+#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_SIZE_BYTES			 6
+#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_SIZE_BYTES			 1
+#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_STATUS_SIZE_BYTES	 1
+#define ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_SIZE_BYTES		 4
+
+/* Size requirements for VLAN filtering feature : 4096 bits = 512 bytes */
+#define ICSS_EMAC_FW_VLAN_FILTER_TABLE_SIZE_BYTES		       512
+#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_SIZE_BYTES			 1
+#define ICSS_EMAC_FW_VLAN_FILTER_DROP_CNT_SIZE_BYTES			 4
+
+/* Mask override set status */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_SET			 1
+/* Mask override not set status */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_NOT_SET		 0
+/* 6 bytes HASH Mask for the MAC */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OFFSET	  0xF4
+/* 0 -> multicast filtering disabled | 1 -> multicast filtering enabled */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_OFFSET	\
+	(ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OFFSET +	\
+	 ICSS_EMAC_FW_MULTICAST_FILTER_MASK_SIZE_BYTES)
+/* Status indicating if the HASH override is done or not: 0: no, 1: yes */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_OVERRIDE_STATUS	\
+	(ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_OFFSET +	\
+	 ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_SIZE_BYTES)
+/* Multicast drop statistics */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_OFFSET	\
+	(ICSS_EMAC_FW_MULTICAST_FILTER_OVERRIDE_STATUS +\
+	 ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_STATUS_SIZE_BYTES)
+/* Multicast table */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_TABLE		\
+	(ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_OFFSET +\
+	 ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_SIZE_BYTES)
+
+/* Multicast filter defines & offsets for LRE
+ */
+#define ICSS_LRE_FW_MULTICAST_TABLE_SEARCH_OP_CONTROL_BIT	0xE0
+/* one byte field :
+ * 0 -> multicast filtering disabled
+ * 1 -> multicast filtering enabled
+ */
+#define ICSS_LRE_FW_MULTICAST_FILTER_MASK			 0xE4
+#define ICSS_LRE_FW_MULTICAST_FILTER_TABLE			 0x100
+
+/* VLAN table Offsets */
+#define ICSS_EMAC_FW_VLAN_FLTR_TBL_BASE_ADDR		 0x200
+#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_BITMAP_OFFSET	 0xEF
+#define ICSS_EMAC_FW_VLAN_FILTER_DROP_CNT_OFFSET	\
+	(ICSS_EMAC_FW_VLAN_FILTER_CTRL_BITMAP_OFFSET +	\
+	 ICSS_EMAC_FW_VLAN_FILTER_CTRL_SIZE_BYTES)
+
+/* VLAN filter Control Bit maps */
+/* one bit field, bit 0: | 0 : VLAN filter disabled (default),
+ * 1: VLAN filter enabled
+ */
+#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_ENABLE_BIT		       0
+/* one bit field, bit 1: | 0 : untagged host rcv allowed (default),
+ * 1: untagged host rcv not allowed
+ */
+#define ICSS_EMAC_FW_VLAN_FILTER_UNTAG_HOST_RCV_ALLOW_CTRL_BIT	       1
+/* one bit field, bit 1: | 0 : priotag host rcv allowed (default),
+ * 1: priotag host rcv not allowed
+ */
+#define ICSS_EMAC_FW_VLAN_FILTER_PRIOTAG_HOST_RCV_ALLOW_CTRL_BIT       2
+/* one bit field, bit 1: | 0 : skip sv vlan flow
+ * :1 : take sv vlan flow  (not applicable for dual emac )
+ */
+#define ICSS_EMAC_FW_VLAN_FILTER_SV_VLAN_FLOW_HOST_RCV_ALLOW_CTRL_BIT  3
+
+/* VLAN IDs */
+#define ICSS_EMAC_FW_VLAN_FILTER_PRIOTAG_VID			       0
+#define ICSS_EMAC_FW_VLAN_FILTER_VID_MIN			       0x0000
+#define ICSS_EMAC_FW_VLAN_FILTER_VID_MAX			       0x0FFF
+
+/* VLAN Filtering Commands */
+#define ICSS_EMAC_FW_VLAN_FILTER_ADD_VLAN_VID_CMD		       0x00
+#define ICSS_EMAC_FW_VLAN_FILTER_REMOVE_VLAN_VID_CMD		       0x01
+
+/* Switch defines for VLAN/MC filtering */
+/* SRAM
+ * VLAN filter defines & offsets
+ */
+#define ICSS_LRE_FW_VLAN_FLTR_CTRL_BYTE				 0x1FE
+/* one bit field | 0 : VLAN filter disabled
+ *		 | 1 : VLAN filter enabled
+ */
+#define ICSS_LRE_FW_VLAN_FLTR_TBL_BASE_ADDR			 0x200
+
+#endif /* ICSS_MULTICAST_FILTER_MM_H */
-- 
2.43.0



From linusw at kernel.org  Fri Dec  5 04:36:15 2025
From: linusw at kernel.org (Linus Walleij)
Date: Fri, 5 Dec 2025 13:36:15 +0100
Subject: [PATCH 0/4] drm: Revert and fix enable/disable sequence
In-Reply-To: <20251205-drm-seq-fix-v1-0-fda68fa1b3de@ideasonboard.com>
References: <20251205-drm-seq-fix-v1-0-fda68fa1b3de@ideasonboard.com>
Message-ID: <CAD++jLkpWoHe5qYSABF1GeDq-9hZh7ZdL-+8Xqu5MA_erzNqsA@mail.gmail.com>

On Fri, Dec 5, 2025 at 10:52?AM Tomi Valkeinen
<tomi.valkeinen at ideasonboard.com> wrote:

> Changing the enable/disable sequence in commit c9b1150a68d9
> ("drm/atomic-helper: Re-order bridge chain pre-enable and post-disable")
> has caused regressions on multiple platforms: R-Car, MCDE, Rockchip.
>
> This is an alternate series to Linus' series:
>
> https://lore.kernel.org/all/20251202-mcde-drm-regression-thirdfix-v6-0-f1bffd4ec0fa%40kernel.org/
>
> This series first reverts the original commit and reverts a fix for
> mediatek which is no longer needed. It then exposes helper functions
> from DRM core, and finally implements the new sequence only in the tidss
> driver.
>
> There is one more fix in upstream for the original commit, commit
> 5d91394f2361 ("drm/exynos: fimd: Guard display clock control with
> runtime PM calls"), but I have not reverted that one as it looks like a
> valid patch in its own.
>
> I added Cc stable v6.17+ to all patches, but I didn't add Fixes tags, as
> I wasn't sure what should they point to. But I could perhaps add Fixes:
> <original commit> to all of these.
>
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>

The series:
Reviewed-by: Linus Walleij <linusw at kernel.org>
Tested-by: Linus Walleij <linusw at kernel.org>

In my opinion Laurent is the more senior maintainer and my
trust level in him is the highest of all the maintainers, so
I think we should apply this revert series if
Laurent ACKs that this is what he thinks is best for DRI.

Yours,
Linus Walleij


From mikko.rapeli at linaro.org  Fri Dec  5 04:37:49 2025
From: mikko.rapeli at linaro.org (Mikko Rapeli)
Date: Fri,  5 Dec 2025 14:37:49 +0200
Subject: [PATCH 0/2] drm: xlnx: zynqmp_kms: 16 bpp fixes for Xorg startup on AMD KV260
Message-ID: <20251205123751.2257694-1-mikko.rapeli@linaro.org>

Hi,

Currently on default yocto images Xorg fails to start on AMD KV260
because 24/32 color depth gets detected but does not actually work.

These two patches fix the issue and now 16 bpp gets detected
and Xorg starts and draws on external HDMI display using
kernel.org based linux-yocto kernel.

Anatoliy Klymenko (1):
  drm: xlnx: zynqmp_kms: Init fbdev with 16 bit color

Mikko Rapeli (1):
  drm: xlnx: zynqmp_kms: set preferred_depth to 16 bpp

 drivers/gpu/drm/xlnx/zynqmp_kms.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

-- 
2.34.1



From mikko.rapeli at linaro.org  Fri Dec  5 04:37:50 2025
From: mikko.rapeli at linaro.org (Mikko Rapeli)
Date: Fri,  5 Dec 2025 14:37:50 +0200
Subject: [PATCH 1/2] drm: xlnx: zynqmp_kms: Init fbdev with 16 bit color
In-Reply-To: <20251205123751.2257694-1-mikko.rapeli@linaro.org>
References: <20251205123751.2257694-1-mikko.rapeli@linaro.org>
Message-ID: <20251205123751.2257694-2-mikko.rapeli@linaro.org>

From: Anatoliy Klymenko <anatoliy.klymenko at amd.com>

Use RG16 buffer format for fbdev emulation. Fbdev backend is being used
by Mali 400 userspace driver which expects 16 bit RGB pixel color format.
This change should not affect console or other fbdev applications as we
still have plenty of colors left.

Cc: Bill Mills <bill.mills at linaro.org>
Cc: Ilias Apalodimas <ilias.apalodimas at linaro.org>
Cc: stable at vger.kernel.org
Signed-off-by: Anatoliy Klymenko <anatoliy.klymenko at amd.com>
Signed-off-by: Mikko Rapeli <mikko.rapeli at linaro.org>
---
 drivers/gpu/drm/xlnx/zynqmp_kms.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c b/drivers/gpu/drm/xlnx/zynqmp_kms.c
index 2bee0a2275ede..ccc35cacd10cb 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_kms.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_kms.c
@@ -525,7 +525,7 @@ int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub)
 		goto err_poll_fini;
 
 	/* Initialize fbdev generic emulation. */
-	drm_client_setup_with_fourcc(drm, DRM_FORMAT_RGB888);
+	drm_client_setup_with_fourcc(drm, DRM_FORMAT_RGB565);
 
 	return 0;
 
-- 
2.34.1



From mikko.rapeli at linaro.org  Fri Dec  5 04:37:51 2025
From: mikko.rapeli at linaro.org (Mikko Rapeli)
Date: Fri,  5 Dec 2025 14:37:51 +0200
Subject: [PATCH 2/2] drm: xlnx: zynqmp_kms: set preferred_depth to 16 bpp
In-Reply-To: <20251205123751.2257694-1-mikko.rapeli@linaro.org>
References: <20251205123751.2257694-1-mikko.rapeli@linaro.org>
Message-ID: <20251205123751.2257694-3-mikko.rapeli@linaro.org>

Xorg fails to start with defaults on AMD KV260, /var/log/Xorg.0.log:

[    23.491] (II) Loading /usr/lib/xorg/modules/drivers/fbdev_drv.so
[    23.491] (II) Module fbdev: vendor="X.Org Foundation"
[    23.491]    compiled for 1.21.1.18, module version = 0.5.1
[    23.491]    Module class: X.Org Video Driver
[    23.491]    ABI class: X.Org Video Driver, version 25.2
[    23.491] (II) modesetting: Driver for Modesetting Kernel Drivers:
kms
[    23.491] (II) FBDEV: driver for framebuffer: fbdev
[    23.510] (II) modeset(0): using drv /dev/dri/card1
[    23.511] (WW) Falling back to old probe method for fbdev
[    23.511] (II) Loading sub module "fbdevhw"
[    23.511] (II) LoadModule: "fbdevhw"
[    23.511] (II) Loading /usr/lib/xorg/modules/libfbdevhw.so
[    23.511] (II) Module fbdevhw: vendor="X.Org Foundation"
[    23.511]    compiled for 1.21.1.18, module version = 0.0.2
[    23.511]    ABI class: X.Org Video Driver, version 25.2
[    23.512] (II) modeset(0): Creating default Display subsection in
Screen section
        "Default Screen Section" for depth/fbbpp 24/32
[    23.512] (==) modeset(0): Depth 24, (==) framebuffer bpp 32
[    23.512] (==) modeset(0): RGB weight 888
[    23.512] (==) modeset(0): Default visual is TrueColor
...
[    23.911] (II) Loading sub module "fb"
[    23.911] (II) LoadModule: "fb"
[    23.911] (II) Module "fb" already built-in
[    23.911] (II) UnloadModule: "fbdev"
[    23.911] (II) Unloading fbdev
[    23.912] (II) UnloadSubModule: "fbdevhw"
[    23.912] (II) Unloading fbdevhw
[    24.238] (==) modeset(0): Backing store enabled
[    24.238] (==) modeset(0): Silken mouse enabled
[    24.249] (II) modeset(0): Initializing kms color map for depth 24, 8
bpc.
[    24.250] (==) modeset(0): DPMS enabled
[    24.250] (II) modeset(0): [DRI2] Setup complete
[    24.250] (II) modeset(0): [DRI2]   DRI driver: kms_swrast
[    24.250] (II) modeset(0): [DRI2]   VDPAU driver: kms_swrast
...
[    24.770] (II) modeset(0): Disabling kernel dirty updates, not
required.
[    24.770] (EE) modeset(0): failed to set mode: Invalid argument

xorg tries to use 24 and 32 bpp which pass on the fb API but which
don't actually work on AMD KV260 when Xorg starts. As a workaround
Xorg config can set color depth to 16 using /etc/X11/xorg.conf snippet:

Section "Screen"
        Identifier     "Default Screen"
        Monitor        "Configured Monitor"
        Device         "Configured Video Device"
        DefaultDepth   16
EndSection

But this is cumbersome on images meant for multiple different arm64
devices and boards. So instead set 16 bpp as preferred depth
in zynqmp_kms fb driver which is used by Xorg in the logic to find
out a working depth.

Now Xorg startup and bpp query using fb API works and HDMI display
shows graphics. /var/log/Xorg.0.log shows:

[    23.219] (II) LoadModule: "fbdev"
[    23.219] (II) Loading /usr/lib/xorg/modules/drivers/fbdev_drv.so
[    23.219] (II) Module fbdev: vendor="X.Org Foundation"
[    23.219]    compiled for 1.21.1.18, module version = 0.5.1
[    23.219]    Module class: X.Org Video Driver
[    23.219]    ABI class: X.Org Video Driver, version 25.2
[    23.219] (II) modesetting: Driver for Modesetting Kernel Drivers:
kms
[    23.219] (II) FBDEV: driver for framebuffer: fbdev
[    23.238] (II) modeset(0): using drv /dev/dri/card1
[    23.238] (WW) Falling back to old probe method for fbdev
[    23.238] (II) Loading sub module "fbdevhw"
[    23.238] (II) LoadModule: "fbdevhw"
[    23.239] (II) Loading /usr/lib/xorg/modules/libfbdevhw.so
[    23.239] (II) Module fbdevhw: vendor="X.Org Foundation"
[    23.239]    compiled for 1.21.1.18, module version = 0.0.2
[    23.239]    ABI class: X.Org Video Driver, version 25.2
[    23.240] (II) modeset(0): Creating default Display subsection in Screen section
        "Default Screen Section" for depth/fbbpp 16/16
[    23.240] (==) modeset(0): Depth 16, (==) framebuffer bpp 16
[    23.240] (==) modeset(0): RGB weight 565
[    23.240] (==) modeset(0): Default visual is TrueColor
...
[    24.015] (==) modeset(0): Backing store enabled
[    24.015] (==) modeset(0): Silken mouse enabled
[    24.027] (II) modeset(0): Initializing kms color map for depth 16, 6 bpc.
[    24.028] (==) modeset(0): DPMS enabled
[    24.028] (II) modeset(0): [DRI2] Setup complete
[    24.028] (II) modeset(0): [DRI2]   DRI driver: kms_swrast
[    24.028] (II) modeset(0): [DRI2]   VDPAU driver: kms_swrast

Cc: Bill Mills <bill.mills at linaro.org>
Cc: Ilias Apalodimas <ilias.apalodimas at linaro.org>
Cc: Anatoliy Klymenko <anatoliy.klymenko at amd.com>
Cc: stable at vger.kernel.org
Signed-off-by: Mikko Rapeli <mikko.rapeli at linaro.org>
---
 drivers/gpu/drm/xlnx/zynqmp_kms.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c b/drivers/gpu/drm/xlnx/zynqmp_kms.c
index ccc35cacd10cb..a42192c827af0 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_kms.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_kms.c
@@ -506,6 +506,7 @@ int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub)
 	drm->mode_config.min_height = 0;
 	drm->mode_config.max_width = ZYNQMP_DISP_MAX_WIDTH;
 	drm->mode_config.max_height = ZYNQMP_DISP_MAX_HEIGHT;
+	drm->mode_config.preferred_depth = 16;
 
 	ret = drm_vblank_init(drm, 1);
 	if (ret)
-- 
2.34.1



From kevin.brodsky at arm.com  Fri Dec  5 04:47:12 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Fri, 5 Dec 2025 13:47:12 +0100
Subject: [PATCH v5 06/12] mm: introduce generic lazy_mmu helpers
In-Reply-To: <e43c147f-bff8-462a-88dc-4345500f4ed7@arm.com>
References: <20251124132228.622678-1-kevin.brodsky@arm.com>
 <20251124132228.622678-7-kevin.brodsky@arm.com>
 <e43c147f-bff8-462a-88dc-4345500f4ed7@arm.com>
Message-ID: <573881f1-60f7-4eb3-a484-1df4858aa1b4@arm.com>

On 04/12/2025 05:17, Anshuman Khandual wrote:
> On 24/11/25 6:52 PM, Kevin Brodsky wrote:
>> The implementation of the lazy MMU mode is currently entirely
>> arch-specific; core code directly calls arch helpers:
>> arch_{enter,leave}_lazy_mmu_mode().
>>
>> We are about to introduce support for nested lazy MMU sections.
>> As things stand we'd have to duplicate that logic in every arch
>> implementing lazy_mmu - adding to a fair amount of logic
>> already duplicated across lazy_mmu implementations.
>>
>> This patch therefore introduces a new generic layer that calls the
>> existing arch_* helpers. Two pair of calls are introduced:
>>
>> * lazy_mmu_mode_enable() ... lazy_mmu_mode_disable()
>>     This is the standard case where the mode is enabled for a given
>>     block of code by surrounding it with enable() and disable()
>>     calls.
>>
>> * lazy_mmu_mode_pause() ... lazy_mmu_mode_resume()
>>     This is for situations where the mode is temporarily disabled
>>     by first calling pause() and then resume() (e.g. to prevent any
>>     batching from occurring in a critical section).
>>
>> The documentation in <linux/pgtable.h> will be updated in a
>> subsequent patch.
>>> No functional change should be introduced at this stage.
>> The implementation of enable()/resume() and disable()/pause() is
>> currently identical, but nesting support will change that.
>>
>> Most of the call sites have been updated using the following
>> Coccinelle script:
>>
>> @@
>> @@
>> {
>> ...
>> - arch_enter_lazy_mmu_mode();
>> + lazy_mmu_mode_enable();
>> ...
>> - arch_leave_lazy_mmu_mode();
>> + lazy_mmu_mode_disable();
>> ...
>> }
>>
>> @@
>> @@
>> {
>> ...
>> - arch_leave_lazy_mmu_mode();
>> + lazy_mmu_mode_pause();
>> ...
>> - arch_enter_lazy_mmu_mode();
>> + lazy_mmu_mode_resume();
>> ...
>> }
> At this point arch_enter/leave_lazy_mmu_mode() helpers are still
> present on a given platform but now being called from new generic
> helpers lazy_mmu_mode_enable/disable(). Well except x86, there is
> direct call sites for those old helpers.

Indeed, see notes below regarding x86. The direct calls to arch_flush()
are specific to x86 and there shouldn't be a need for a generic abstraction.

- Kevin

> arch/arm64/include/asm/pgtable.h:static inline void arch_enter_lazy_mmu_mode(void)
> arch/arm64/include/asm/pgtable.h:static inline void arch_leave_lazy_mmu_mode(void)
>
> arch/arm64/mm/mmu.c:    lazy_mmu_mode_enable();
> arch/arm64/mm/pageattr.c:       lazy_mmu_mode_enable();
>
> arch/arm64/mm/mmu.c:    lazy_mmu_mode_disable();
> arch/arm64/mm/pageattr.c:       lazy_mmu_mode_disable();
>
>> A couple of notes regarding x86:
>>
>> * Xen is currently the only case where explicit handling is required
>>   for lazy MMU when context-switching. This is purely an
>>   implementation detail and using the generic lazy_mmu_mode_*
>>   functions would cause trouble when nesting support is introduced,
>>   because the generic functions must be called from the current task.
>>   For that reason we still use arch_leave() and arch_enter() there.
>>
>> * x86 calls arch_flush_lazy_mmu_mode() unconditionally in a few
>>   places, but only defines it if PARAVIRT_XXL is selected, and we
>>   are removing the fallback in <linux/pgtable.h>. Add a new fallback
>>   definition to <asm/pgtable.h> to keep things building.
>>
>> [...]


From kevin.brodsky at arm.com  Fri Dec  5 04:50:40 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Fri, 5 Dec 2025 13:50:40 +0100
Subject: [PATCH v5 08/12] mm: enable lazy_mmu sections to nest
In-Reply-To: <93d04ef8-0364-4013-8839-ba599d930cb2@kernel.org>
References: <20251124132228.622678-1-kevin.brodsky@arm.com>
 <20251124132228.622678-9-kevin.brodsky@arm.com>
 <2dfd54d7-fe2a-4921-85ff-a581392a777a@arm.com>
 <93d04ef8-0364-4013-8839-ba599d930cb2@kernel.org>
Message-ID: <093f814e-ce49-43c9-951b-b0d0ef583cea@arm.com>

On 04/12/2025 12:52, David Hildenbrand (Red Hat) wrote:
> Some comments from my side:
>
>
>>> ? static inline void arch_enter_lazy_mmu_mode(void)
>>> ? {
>>> -??? /*
>>> -???? * lazy_mmu_mode is not supposed to permit nesting. But in
>>> practice this
>>> -???? * does happen with CONFIG_DEBUG_PAGEALLOC, where a page
>>> allocation
>>> -???? * inside a lazy_mmu_mode section (such as zap_pte_range())
>>> will change
>>> -???? * permissions on the linear map with apply_to_page_range(), which
>>> -???? * re-enters lazy_mmu_mode. So we tolerate nesting in our
>>> -???? * implementation. The first call to arch_leave_lazy_mmu_mode()
>>> will
>>> -???? * flush and clear the flag such that the remainder of the work
>>> in the
>>> -???? * outer nest behaves as if outside of lazy mmu mode. This is
>>> safe and
>>> -???? * keeps tracking simple.
>>> -???? */
>>> -
>>> ????? set_thread_flag(TIF_LAZY_MMU);>? }
>>
>> Should not platform specific changes be deferred to subsequent
>> patches until
>> nesting is completely enabled in generic first ? Although no problem
>> as such
>> but would be bit cleaner.
>
> This could indeed be done in a separate patch. But I also don't see a
> problem with updating the doc in this patch.

I think it is consistent to remove that comment in this patch, since
nesting is fully supported from this patch onwards. Subsequent patches
are cleanups/optimisations that aren't functionally required.

Patch 7 takes the same approach: add handling in the generic layer,
remove anything now superfluous from arm64.

>
>>
>>> ? diff --git a/include/linux/mm_types_task.h
>>> b/include/linux/mm_types_task.h
>>> index a82aa80c0ba4..11bf319d78ec 100644
>>> --- a/include/linux/mm_types_task.h
>>> +++ b/include/linux/mm_types_task.h
>>> @@ -88,4 +88,9 @@ struct tlbflush_unmap_batch {
>>> ? #endif
>>> ? };
>>> ? +struct lazy_mmu_state {
>>> +??? u8 enable_count;
>>> +??? u8 pause_count;
>>> +};
>>> +
>>
>> Should not this be wrapped with CONFIG_ARCH_HAS_LAZY_MMU_MODE as the
>> task_struct
>> element 'lazy_mmu_state' is only available with the feature.
>
> No strong opinion; the compiler will ignore it either way. And less
> ifdef is good, right? :)
>
> ... and there is nothing magical in there that would result in other
> dependencies.?

Agreed, #ifdef'ing types should only be done if necessary.

>
>> Besides, is a depth
>> of 256 really expected here ? 4 bits for each element would not be
>> sufficient for
>> a depth of 16 ?
>
>
> We could indeed use something like
>
> struct lazy_mmu_state {
> ????u8 enable_count : 4;
> ????u8 pause_count : 4;
> };
>
> but then, the individual operations on enable_count/pause_count need
> more instructions.

Indeed.

>
> Further, as discussed, this 1 additional byte barely matters given the
> existing size of the task struct.

In fact it would almost certainly make no difference (depending on
randomized_struct) since almost all members in task_struct have an
alignment of at least 2.

>
> [...]
>
>>> +/**
>>> + * lazy_mmu_mode_pause() - Resume the lazy MMU mode.
>>> + *
>>> + * Resumes the lazy MMU mode; if it was active at the point where
>>> the matching
>>> + * call to lazy_mmu_mode_pause() was made, re-enables it and calls
>>> + * arch_enter_lazy_mmu_mode().
>>> + *
>>> + * Must match a call to lazy_mmu_mode_pause().
>>> + *
>>> + * Has no effect if called:
>>> + * - While paused (inside another pause()/resume() pair)
>>> + * - In interrupt context
>>> + */
>>> ? static inline void lazy_mmu_mode_resume(void)
>>> ? {
>>> +??? struct lazy_mmu_state *state = &current->lazy_mmu_state;
>>> +
>>> ????? if (in_interrupt())
>>> ????????? return;
>>> ? -??? arch_enter_lazy_mmu_mode();
>>> +??? VM_WARN_ON_ONCE(state->pause_count == 0);
>>> +
>>> +??? if (--state->pause_count == 0 && state->enable_count > 0)
>>> +??????? arch_enter_lazy_mmu_mode();
>>> ? }
>>
>> Should not state->pause/enable_count tests and increment/decrement be
>> handled
>> inside include/linux/sched via helpers like in_lazy_mmu_mode() ? This
>> is will
>> ensure cleaner abstraction with respect to task_struct.
>
> I don't think this is required given that this code here implements
> CONFIG_ARCH_HAS_LAZY_MMU_MODE support.

Agreed, in fact I'd rather not expose helpers that should only be used
in the lazy_mmu implementation itself.

- Kevin


From kevin.brodsky at arm.com  Fri Dec  5 04:56:11 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Fri, 5 Dec 2025 13:56:11 +0100
Subject: [PATCH v5 08/12] mm: enable lazy_mmu sections to nest
In-Reply-To: <2dfd54d7-fe2a-4921-85ff-a581392a777a@arm.com>
References: <20251124132228.622678-1-kevin.brodsky@arm.com>
 <20251124132228.622678-9-kevin.brodsky@arm.com>
 <2dfd54d7-fe2a-4921-85ff-a581392a777a@arm.com>
Message-ID: <89e76670-4a7b-46b6-ba55-d225dbb68cbd@arm.com>

On 04/12/2025 07:23, Anshuman Khandual wrote:
>> [...]
>>
>> diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
>> index 8ff6fdb4b13d..24fdb6f5c2e1 100644
>> --- a/include/linux/pgtable.h
>> +++ b/include/linux/pgtable.h
>> @@ -230,39 +230,140 @@ static inline int pmd_dirty(pmd_t pmd)
>>   * (In practice, for user PTE updates, the appropriate page table lock(s) are
>>   * held, but for kernel PTE updates, no lock is held). The mode is disabled in
>>   * interrupt context and calls to the lazy_mmu API have no effect.
>> - * Nesting is not permitted.
>> + *
>> + * The lazy MMU mode is enabled for a given block of code using:
>> + *
>> + *   lazy_mmu_mode_enable();
>> + *   <code>
>> + *   lazy_mmu_mode_disable();
>> + *
>> + * Nesting is permitted: <code> may itself use an enable()/disable() pair.
>> + * A nested call to enable() has no functional effect; however disable() causes
>> + * any batched architectural state to be flushed regardless of nesting. After a
> Just wondering if there is a method for these generic helpers to ensure that platform
> really does the required flushing on _disable() or the expected platform semantics is
> only described via this comment alone ?

>From the generic layer's perspective, flushing means calling
arch_flush_lazy_mmu_mode(). Like the other arch_*_lazy_mmu_mode helpers,
the actual semantics is unspecified - an arch could choose not to do
anything on flush if that's not required for page table changes to be
visible. There is actually an example of this in the kpkeys page table
hardening series [1] (this isn't doing any batching so there is nothing
to flush either).

[1]
https://lore.kernel.org/linux-hardening/20250815085512.2182322-19-kevin.brodsky at arm.com/

>> + * call to disable(), the caller can therefore rely on all previous page table
>> + * modifications to have taken effect, but the lazy MMU mode may still be
>> + * enabled.
>> + *
>> + * In certain cases, it may be desirable to temporarily pause the lazy MMU mode.
>> + * This can be done using:
>> + *
>> + *   lazy_mmu_mode_pause();
>> + *   <code>
>> + *   lazy_mmu_mode_resume();
>> + *
>> + * pause() ensures that the mode is exited regardless of the nesting level;
>> + * resume() re-enters the mode at the same nesting level. Any call to the
>> + * lazy_mmu_mode_* API between those two calls has no effect. In particular,
>> + * this means that pause()/resume() pairs may nest.
>> + *
>> + * in_lazy_mmu_mode() can be used to check whether the lazy MMU mode is
>> + * currently enabled.
> Just wondering - could a corresponding test be included probably via KUNIT_TEST
> to ensure the above described semantics are being followed.

Checking that is_lazy_mmu_mode_active() returns the right value at
different call depths should be doable, yes. I suppose that could live
in some file under mm/tests/ (doesn't exist yet but that's the preferred
approach for KUnit tests).

- Kevin


From kevin.brodsky at arm.com  Fri Dec  5 05:00:37 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Fri, 5 Dec 2025 14:00:37 +0100
Subject: [PATCH v5 00/12] Nesting support for lazy MMU mode
In-Reply-To: <94889730-1AEF-458F-B623-04092C0D6819@linux.ibm.com>
References: <20251124132228.622678-1-kevin.brodsky@arm.com>
 <94889730-1AEF-458F-B623-04092C0D6819@linux.ibm.com>
Message-ID: <f07f5f70-eb4c-4e45-b7d6-96c8455255d2@arm.com>

On 03/12/2025 17:08, Venkat wrote:
> [...]
> Tested this patch series by applying on top of mm-unstable, on both HASH and RADIX MMU, and all tests are passed on both MMU?s.
>
> Ran: cache_shape, copyloops, mm from linux source, selftests/powerpc/ and ran memory-hotplug from selftests/. Also ran below tests from avocado misc-test repo.
>
> Link to repo: https://github.com/avocado-framework-tests/avocado-misc-tests
>
> avocado-misc-tests/memory/stutter.py
> avocado-misc-tests/memory/eatmemory.py
> avocado-misc-tests/memory/hugepage_sanity.py
> avocado-misc-tests/memory/fork_mem.py
> avocado-misc-tests/memory/memory_api.py
> avocado-misc-tests/memory/mprotect.py
> avocado-misc-tests/memory/vatest.py avocado-misc-tests/memory/vatest.py.data/vatest.yaml
> avocado-misc-tests/memory/transparent_hugepages.py
> avocado-misc-tests/memory/transparent_hugepages_swapping.py
> avocado-misc-tests/memory/transparent_hugepages_defrag.py
> avocado-misc-tests/memory/ksm_poison.py
>
> If its good enough, please add below tag for PowerPC changes.
>
> Tested-by: Venkat Rao Bagalkote <venkat88 at linux.ibm.com>

Many thanks for the testing! Will add your tag to patch 1, 3 and 10.

- Kevin


From nm at ti.com  Fri Dec  5 05:01:21 2025
From: nm at ti.com (Nishanth Menon)
Date: Fri, 5 Dec 2025 07:01:21 -0600
Subject: [PATCH v4] dt-bindings: arm: keystone: add boot_* mboxes to
 ti,sci
In-Reply-To: <20251205-k3_syscon_add_boot_mailboxes-v4-1-8e216fb88941@ti.com>
References: <20251205-k3_syscon_add_boot_mailboxes-v4-1-8e216fb88941@ti.com>
Message-ID: <20251205130121.7cqsy5zihelh6ity@launch>

On 11:45-20251205, Anshul Dalal wrote:
> The bootloader on K3 devices makes use of mailboxes as per the ROM spec
> which might be different than one's available to the kernel (firmware
> spec).
> 
> Therefore, this patch adds the missing mailbox entries to the DT binding
> if the matching compatible is ti,am654-sci to represent the mailboxes
> exposed by the hardware during boot for the purpose of loading the
> firmware.
> 
> Signed-off-by: Anshul Dalal <anshuld at ti.com>
> ---
> Changes in v4:
> - Make new boot_* mboxes conditional on ti,am654-sci compatible
> - Link to v3: https://lore.kernel.org/r/20251112-k3_syscon_add_boot_mailboxes-v3-1-66155a4236dc at ti.com
> 
> Changes in v3:
> - Drop [1/2] of the last patch series
> - Update existing example with boot_* mailboxes instead of adding a new one
> - Link to v2: https://lore.kernel.org/r/20251112-k3_syscon_add_boot_mailboxes-v2-0-aebc1e47b391 at ti.com
> 
> Changes in v2:
> - Remove maxItems entry
> - Remove RFC tag from patch (added by mistake in v1)
> - Document the new mailboxes in mboxes instead of mbox-names
> - Provide example with all the mailboxes set
> - Update commit title to have "ti,sci"
> - Split into two patches
> - Link to v1: https://lore.kernel.org/r/20251111-k3_syscon_add_boot_mailboxes-v1-1-529a27f21076 at ti.com
> ---
>  .../devicetree/bindings/arm/keystone/ti,sci.yaml   | 50 +++++++++++++++++++---
>  1 file changed, 43 insertions(+), 7 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
> index 25a2b42105e5..d9eb2a81e539 100644
> --- a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
> +++ b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
> @@ -51,15 +51,15 @@ properties:
>      minItems: 1
>  
>    mbox-names:
> +    minItems: 2
> +    maxItems: 6
>      description: |
>        Specifies the mailboxes used to communicate with TI-SCI Controller
>        made available from TI-SCI controller.
> -    items:
> -      - const: rx
> -      - const: tx
>  
>    mboxes:
>      minItems: 2
> +    maxItems: 6
>  
>    ti,host-id:
>      $ref: /schemas/types.yaml#/definitions/uint32
> @@ -79,6 +79,42 @@ properties:
>      type: object
>      $ref: /schemas/reset/ti,sci-reset.yaml#
>  
> +if:
> +  properties:
> +    compatible:
> +      contains:
> +        const: ti,am654-sci
> +then:
> +  properties:
> +    mbox-names:
> +      minItems: 2
> +      items:
> +        - const: rx
> +        - const: tx
> +        - const: notify
> +        - const: boot_rx
> +        - const: boot_tx
> +        - const: boot_notify
> +    mboxes:
> +      minItems: 2
> +      items:
> +        - description: RX thread
> +        - description: TX thread
> +        - description: Notify thread
> +        - description: boot stage RX thread
> +        - description: boot stage TX thread
> +        - description: boot stage Notify thread
> +else:
> +  properties:
> +    mbox-names:
> +      items:
> +        - const: rx
> +        - const: tx
> +    mboxes:
> +      items:
> +        - description: RX thread
> +        - description: TX thread
> +
>  required:
>    - compatible
>    - mbox-names
> @@ -99,11 +135,11 @@ examples:
>  
>    - |
>      dmsc: system-controller at 44083000 {
> -      compatible = "ti,k2g-sci";
> +      compatible = "ti,am654-sci";
>        ti,host-id = <12>;
> -      mbox-names = "rx", "tx";
> -      mboxes = <&secure_proxy_main 11>,
> -               <&secure_proxy_main 13>;
> +      mbox-names = "rx", "tx", "notify", "boot_rx", "boot_tx";
> +      mboxes= <&secure_proxy_mcu 6>, <&secure_proxy_mcu 8>,
> +        <&secure_proxy_mcu 5>, <&secure_proxy_mcu 5>, <&secure_proxy_mcu 4>;
>        reg-names = "debug_messages";
>        reg = <0x44083000 0x1000>;

Create another example. why are we dropping k2g-sci - that is still
valid and the schema must continue to support - so functions as a
validation.

However, i'd like to make sure this can handle two different patterns -
example: AM62x and j784s4.

>  
> 
> ---
> base-commit: 4427259cc7f7571a157fbc9b5011e1ef6fe0a4a8
> change-id: 20251105-k3_syscon_add_boot_mailboxes-8452bdd98962
> 
> Best regards,
> -- 
> Anshul Dalal <anshuld at ti.com>
> 

-- 
Regards,
Nishanth Menon
Key (0xDDB5849D1736249D) / Fingerprint: F8A2 8693 54EB 8232 17A3  1A34 DDB5 849D 1736 249D
https://ti.com/opensource


From punit.agrawal at oss.qualcomm.com  Fri Dec  5 05:08:40 2025
From: punit.agrawal at oss.qualcomm.com (Punit Agrawal)
Date: Fri, 05 Dec 2025 13:08:40 +0000
Subject: [PATCH v6 00/34] arm_mpam: Add basic mpam driver
In-Reply-To: <642767c9-f926-490a-83a1-160978c37553@arm.com> (James Morse's
	message of "Wed, 3 Dec 2025 17:34:37 +0000")
References: <20251119122305.302149-1-ben.horgan@arm.com>
	<877bvfa23i.fsf@stealth>
	<a04aa337-a3eb-42a0-855b-500ba549e2d8@arm.com>
	<87sedrlsjk.fsf@stealth>
	<642767c9-f926-490a-83a1-160978c37553@arm.com>
Message-ID: <871pl9krdz.fsf@stealth>

James Morse <james.morse at arm.com> writes:

> Hi Punit,
>
> On 03/12/2025 11:21, Punit Agrawal wrote:
>> Ben Horgan <ben.horgan at arm.com> writes:
>>> On 11/24/25 15:21, Punit Agrawal wrote:
>>>> Although a little late to the party,
>
> There was a party?!
>
>
>>>> I've managed to throw together
>>>> enough firmware to describe the MPAM hardware and take this set (more
>>>> specifically mpam/snapshot/v6.18-rc4-v5 branch from James' repository)
>>>> for a spin. Using the branch, the kernel is able to probe the hardware
>>>> and discover the advertised features. Yay! We are in business.
>>>
>>> Thanks for giving it a go. :)
>>>
>>>>
>>>> Having said that, there are a few quirks of the platform that run into
>>>> issues with later patches in the branch.
>
> So something in the resctrl support code is causing this.
> Any idea which patch causes this to happen?
>
> There are a load of pr_debug() in the picking logic, if you enable DYNDEBUG and add:
> | dyndbg="file mpam_resctrl.c +pl"
>
> to the commandline, you should get some snotty messages about what non-Xeon-like property
> your platform has.

Thanks - I've got this enabled.

The platform looks very different to a Xeon. One notable difference
being a shared L2. Hence all the MSCs attached there.

>>>> The platform has MSCs attached
>>>> to shared L2 caches which are being skipped during later stages of
>>>> initialisation. IIUC, the L2 MSCs' limitations stems from the
>>>> assumptions in the resctrl interface.
>>>
>>> What in particualar is being skipped?
>
>> The registration of the discovered MSCs with resctrl and subsequent
>> exposing it to the user.
>
> resctrl's 'L2' support is limited to the CPOR bitmap.
> If you have controls, there is no resctrl 'event' that can exposed them.
> (the problem being they all have 'L3' in the name!)

>>>> I was wondering if there are any patches available to relax these
>>>> limitations?

> Knowing which property it is will help - but some of these things are checked
> to match resctrl's ABI. They can't necessarily be relaxed without breaking
> user-space.

This platform has portion, capacity and priority partitioning, as well
as memory bandwidth and cache storage monitoring. The MPAM code seems to
correctly parse the properties.

But as you point out, the resctrl 'L2' support doesn't have anything
other than CPOR bitmap yet. Have you looked at what's needed to extend
resctrl to support some of the others?

> Others are sanity checks, e.g. all CPUs are represented. This is to avoid tasks
> that run on cpu-9 escaping the resctrl controls. Platforms that did this may as
> well not bother with resctrl at all.
>
>
>>>> I can give them a try. Or do these need to be put together
>>>> from the ground up? Any pointers greatly appreciated.
>>>
>>> There are some extra things added in the extras branch [1] e.g. cache
>>> maximum usage controls (cmax). However, lots of possible things are
>>> still missing e.g. any monitors on L2. If it doesn't fit with the
>>> topology expected by resctrl then it is unlikely to have been considered
>>> yet.
>> 
>> Thanks for the pointer. I'll give the snapshot+extras branch[1] a try.
>> 
>> The platform does have both controls and monitors attached to L2. If
>> this isn't being looked at, I can try and put something together. Thanks
>> for confirming that the limitation is likely due to resctrl.
>
> My view on 'extra' counters is to try and expose them via perf, as this would also
> allow platform specific counters. I worry that if we start adding 'easy' ones like
> l2_mbm_total to resctrl, someone will want
> left_hand_side_of_soc_mbm_total.

I wouldn't club L2 in the same category as 'left_hand_side_of_soc'. You
call it 'easy' for a reason. L2 is pretty well understood and resctrl
already exposes an interface for it. I would avoid creating a new
interface for users.

For some of the other boundaries, things like 'left_hand_side_of_soc' I
wonder if firmware provided topology (e.g., PPTT, SRAT, etc) could be
used to make even this work.


From konrad.dybcio at oss.qualcomm.com  Fri Dec  5 05:38:33 2025
From: konrad.dybcio at oss.qualcomm.com (Konrad Dybcio)
Date: Fri, 5 Dec 2025 14:38:33 +0100
Subject: [PATCH V4] iommu/arm-smmu: add actlr settings for mdss on
 Qualcomm platforms
In-Reply-To: <20251202125447.2102658-1-charan.kalla@oss.qualcomm.com>
References: <20251202125447.2102658-1-charan.kalla@oss.qualcomm.com>
Message-ID: <95d5d066-0fd0-4fad-bf83-64deae6b5ce0@oss.qualcomm.com>

On 12/2/25 1:54 PM, Charan Teja Kalla wrote:
> Add ACTLR settings for missing MDSS devices on Qualcomm platforms.
> 
> These are QoS settings and are specific to per SoC thus different
> settings, eg: some have shallow prefetch while others have no
> prefetch.
> 
> Aswell, this prefetch feature is not implemented for all the
> platforms, capturing to those are implemented to the best of my
> knowledge.
> 
> Signed-off-by: Charan Teja Kalla <charan.kalla at oss.qualcomm.com>
> ---
> Changes from V3:
>  1) Add actlr setting for missing sc8180x & sm6115.

Thanks for digging them all up!

Reviewed-by: Konrad Dybcio <konrad.dybcio at oss.qualcomm.com>

Konrad


From robh at kernel.org  Fri Dec  5 05:46:45 2025
From: robh at kernel.org (Rob Herring)
Date: Fri, 5 Dec 2025 07:46:45 -0600
Subject: [PATCH v1 1/2] arm64: dts: mediatek: mt7986: add dtbs with
 applied overlays for bpi-r3
In-Reply-To: <ddad2f21-4853-41c9-acfb-1613f5000f0c@collabora.com>
References: <20251119175124.48947-1-linux@fw-web.de> <20251119175124.48947-2-linux@fw-web.de>
 <fc5c9829-96fa-4028-a642-0792699e92a5@kernel.org> <ddad2f21-4853-41c9-acfb-1613f5000f0c@collabora.com>
Message-ID: <CAL_Jsq+Zu14ojvNNjgOFWA40iaqYrgGQsrHNWraooOML98fXyw@mail.gmail.com>

On Fri, Dec 5, 2025 at 3:05?AM AngeloGioacchino Del Regno
<angelogioacchino.delregno at collabora.com> wrote:
>
> Il 05/12/25 09:10, Krzysztof Kozlowski ha scritto:
> > On 19/11/2025 18:51, Frank Wunderlich wrote:
> >> From: Frank Wunderlich <frank-w at public-files.de>
> >>
> >> Build devicetree binaries for testing overlays and providing users
> >> full dtb without using overlays.
> >>
> >> Suggested-by: Rob Herring <robh+dt at kernel.org>
> >> Signed-off-by: Frank Wunderlich <frank-w at public-files.de>
> >> ---
> >> resend of
> >> https://patchwork.kernel.org/project/linux-mediatek/patch/20240608080530.9436-2-linux at fw-web.de/
> >> due to discussions here:
> >> https://patchwork.kernel.org/project/linux-mediatek/patch/20251117211306.725678-1-robh at kernel.org/
> >>
> >> changes:
> >> - updated sd-nand with sata-overlay
> >> ---
> >>   arch/arm64/boot/dts/mediatek/Makefile | 21 +++++++++++++++++++++
> >>   1 file changed, 21 insertions(+)
> >
> >
> > This looks like still not being applied and now it is a warning in
> > Linus' tree.
> >
> > Can this be applied and sent as fixes?

There's still one warning remaining after applying this series which I reported:

scripts/Makefile.dtbs:20: .dtbo is not applied to any base:
mt8395-radxa-nio-12l-8-hd-panel.dtbo

It's fixed in my original patch. Can you all take that and drop the bpi hunks.

FWIW:

Acked-by: Rob Herring (Arm) <robh at kernel.org>


From suzuki.poulose at arm.com  Fri Dec  5 05:51:25 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Fri, 5 Dec 2025 13:51:25 +0000
Subject: [PATCH v8 0/7] Provides support for Trigger Generation Unit
In-Reply-To: <b2f3c31a-76fa-4f59-9ba4-0f93f861ffb2@oss.qualcomm.com>
References: <20251203090055.2432719-1-songwei.chai@oss.qualcomm.com>
 <4f53766f-6338-4d94-a947-19b95952e08a@arm.com>
 <b2f3c31a-76fa-4f59-9ba4-0f93f861ffb2@oss.qualcomm.com>
Message-ID: <a3d2f8a8-900d-4cf7-bd12-2d2ec85c4da2@arm.com>

On 05/12/2025 01:13, Songwei Chai wrote:
> 
> 
> On 12/3/2025 11:48 PM, Suzuki K Poulose wrote:
>> Cc: Greg
>>
>> On 03/12/2025 09:00, Songwei Chai wrote:
>>> We propose creating a new qcom directory under drivers/hwtracing
>>> to host this TGU driver, as well as additional Qualcomm-specific
>>> hwtracing drivers that we plan to submit in the coming months.
>>> This structure will help organize vendor-specific implementations
>>> and facilitate future development and maintenance.
>>>
>>> Feedback from the community on this proposal is highly appreciated.
>>>
>>> - Why we are proposing this:
>>>
>>> TGU has the ability to monitor signal conditions and trigger debug- 
>>> related
>>> actions, serving as a programmable hardware component that enhances 
>>> system
>>> trace and debug capabilities. Placing it under drivers/hwtracing 
>>> aligns with
>>> its function as a trace generation utility.
>>>
>>> We previously attempted to push this driver to drivers/hwtracing/ 
>>> coresight,
>>> but did not receive support from the maintainers of the CoreSight 
>>> subsystem.
>>> The reason provided was: ?This component is primarily a part of the
>>> Qualcomm proprietary QPMDA subsystem, and is capable of operating
>>> independently from the CoreSight hardware trace generation system.?
>>>
>>> Chat history : https://lore.kernel.org/all/ 
>>> CAJ9a7ViKxHThyZfFFDV_FkNRimk4uo1NrMtQ-kcaj1qO4ZcGnA at mail.gmail.com/
>>>
>>> Given this, we have been considering whether it would be appropriate
>>> to create a dedicated drivers/hwtracing/qcom directory for
>>> Qualcomm-related hwtracing drivers. This would follow the precedent set
>>> by Intel, which maintains its own directory at drivers/hwtracing/ 
>>> intel_th.
>>> We believe this structure would significantly facilitate
>>> future submissions of related Qualcomm drivers.
>>>
>>> - Maintenance of drivers/hwtracing/qcom:
>>>
>>
>> Fine by, me.
>>
>>
>>> Bjorn, who maintains linux-arm-msm, will be the maintainer of this
>>> directory ? we?ve discussed this with him and he?s aware that his task
>>> list may grow accordingly. Additionally, Qualcomm engineers familiar 
>>> with
>>> the debug hardware ? such as [Tingwei Zhang, Jinlong Mao, Songwei Chai],
>>> will be available to review incoming patches and support ongoing
>>> development.
>>>
>>> - Detail for TGU:
>>>
>>> This component can be utilized to sense a plurality of signals and
>>> create a trigger into the CTI or generate interrupts to processors
>>> once the input signal meets the conditions. We can treat the TGU?s
>>> workflow as a flowsheet, it has some ?steps? regions for customization.
>>> In each step region, we can set the signals that we want with priority
>>> in priority_group, set the conditions in each step via condition_decode,
>>> and set the resultant action by condition_select. Meanwhile,
>>> some TGUs (not all) also provide timer/counter functionality.
>>> Based on the characteristics described above, we consider the TGU as a
>>> helper in the CoreSight subsystem. Its master device is the TPDM, which
>>> can transmit signals from other subsystems, and we reuse the existing
>>> ports mechanism to link the TPDM to the connected TGU.
>>
>> Please remove the coresight_device and other dependencies. You may use
>> generic bits, CS_LOCK/UNLOCK etc. But including coresight-priv.h is
>> not something I would prefer. It brings in unnecessary dependencies
>> between two subsystems and I don't see any reason for using -priv.h.
>> It is named as it is, for a reason, coresight private definitions.
>>
>>
>>>
>>> Here is a detailed example to explain how to use the TGU:
>>>
>>> In this example, the TGU is configured to use 2 conditions, 2 steps, and
>>> the timer. The goal is to look for one of two patterns which are 
>>> generated
>>> from TPDM, giving priority to one, and then generate a trigger once the
>>> timer reaches a certain value. In other words, two conditions are used
>>> for the first step to look for the two patterns, where the one with the
>>> highest priority is used in the first condition. Then, in the second 
>>> step,
>>> the timer is enabled and set to be compared to the given value at each
>>> clock cycle. These steps are better shown below.
>>> ?????????????? |-----------------|
>>> ?????????????? |???????????????? |
>>> ?????????????? |?????? TPDM????? |
>>> ?????????????? |???????????????? |
>>> ?????????????? |-----------------|
>>> ??????????????????????? |
>>> ??????????????????????? |
>>> ???? --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- 
>>> ------
>>> ???? |????????????????? | 
>>> ???????????????????????????????????????????????? |
>>> ???? |????????????????? | |--------------------| |
>>> ???? |??? |---- --->??? |????????????????????????? |? Go to next 
>>> steps? | |
>>> ???? |??? |???????????? |??????????????? |--- ---> |? Enable 
>>> timer????? | |
>>> ???? |??? |???????????? v??????????????? |???????? | 
>>> ??????????????????? | |
>>> ???? |??? |??? |-----------------|?????? | |--------------------| |
>>> ???? |??? |??? |???????????????? |? Yes? |??????????????????? | 
>>> ?????????? |
>>> ???? |??? |??? |?? inputs==0xB?? | ----->|??????????????????? | 
>>> <-------- |
>>> ???? |??? |??? |???????????????? |?????? |??????????????????? | No | |
>>> ???? | No |??? |-----------------|?????? | v???????? | |
>>> ???? |??? |???????????? |??????????????? | |-----------------| | |
>>> ???? |??? |???????????? |??????????????? |????????? | | | |
>>> ???? |??? |???????????? |??????????????? |????????? |????? timer>=3 
>>> |-- |
>>> ???? |??? |???????????? v??????????????? |????????? | |?? |
>>> ???? |??? |??? |-----------------|?????? | |-----------------|?? |
>>> ???? |??? |??? |???????????????? |? Yes? |??????????????????? | 
>>> ?????????? |
>>> ???? |??? |--- |?? inputs==0xA?? | ----->|??????????????????? | 
>>> Yes?????? |
>>> ???? |???????? |???????????????? |??????????????????????????? | 
>>> ?????????? |
>>> ???? |???????? |-----------------| v?????????? |
>>> ???? | |-----------------|?? |
>>> ???? |????????????????????????????????????????????? | |?? |
>>> ???? |????????????????????????????????????????????? |????? Trigger |?? |
>>> ???? |????????????????????????????????????????????? | |?? |
>>> ???? | |-----------------|?? |
>>> ???? |? TGU?????????????????????????????????????????????????? | 
>>> ?????????? |
>>> ???? |--- --- --- --- --- --- --- --- --- --- --- --- --- --- |--- 
>>> --- -- |
>>> ????????????????????????????????????????????????????????????? |
>>> ????????????????????????????????????????????????????????????? v
>>> ???????????????????????????????????????????????????? |-----------------|
>>> ???????????????????????????????????????????????????? |The controllers? |
>>> ???????????????????????????????????????????????????? |which will use?? |
>>> ???????????????????????????????????????????????????? |triggers further |
>>> ???????????????????????????????????????????????????? |-----------------|
>>>
>>> steps:
>>> ???? 1. Reset TGU /*it will disable tgu and reset dataset*/
>>> ???? - echo 1 > /sys/bus/coresight/devices/<tgu-name>/reset_tgu
>>>
>>> ???? 2. Set the pattern match for priority0 to 0xA = 0b1010 and for
>>> ??????? priority 1 to 0xB = 0b1011.
>>> ???? - echo 0x11113232 > /sys/bus/coresight/devices/<tgu-name>/ 
>>> step0_priority0/reg0
>>> ???? - echo 0x11113233 > /sys/bus/coresight/devices/<tgu-name>/ 
>>> step0_priority1/reg0
>>
>> Why do they need to be coresight devices and appear on the coresight 
>> bus if they are not coresight devices ? As I understand they are simply
>> devices with some sysfs knobs.
>>
>> Otherwise, happy with the proposal
>>
>>
>> Suzuki
> 
> Hi Suzuki,
> 
> Would it be a good idea to register the TGU device as a platform device 
> so that it will appear under "/sys/devices/platform/" and the code could 
> also be decoupled from coresight-priv.h

It is already an AMBA device, why do you need this as a platform device 
? You are welcome to add a sysfs group "tgu" under the device.

Suzuki


> 
> BRs,
> Songwei>
>>
>>
>>
>>>
>>> ???? Note:
>>> ???????? Bit distribution diagram for each priority register
>>> |-------------------------------------------------------------------|
>>> ???? |?? Bits????????? |?????? Field Nam?? | Description????????????? |
>>> |-------------------------------------------------------------------|
>>> ???? |???????????????? |?????????????????? | 00 = bypass for OR 
>>> output?? |
>>> ???? |???? 29:28?????? |?? SEL_BIT7_TYPE2? | 01 = bypass for AND 
>>> output? |
>>> ???? |???????????????? |?????????????????? | 10 = sense input '0' is 
>>> true|
>>> ???? |???????????????? |?????????????????? | 11 = sense input '1' is 
>>> true|
>>> |-------------------------------------------------------------------|
>>> ???? |???????????????? |?????????????????? | 00 = bypass for OR 
>>> output?? |
>>> ???? |???? 25:24?????? |?? SEL_BIT6_TYPE2? | 01 = bypass for AND 
>>> output? |
>>> ???? |???????????????? |?????????????????? | 10 = sense input '0' is 
>>> true|
>>> ???? |???????????????? |?????????????????? | 11 = sense input '1' is 
>>> true|
>>> |-------------------------------------------------------------------|
>>> ???? |???????????????? |?????????????????? | 00 = bypass for OR 
>>> output?? |
>>> ???? |???? 21:20?????? |?? SEL_BIT5_TYPE2? | 01 = bypass for AND 
>>> output? |
>>> ???? |???????????????? |?????????????????? | 10 = sense input '0' is 
>>> true|
>>> ???? |???????????????? |?????????????????? | 11 = sense input '1' is 
>>> true|
>>> |-------------------------------------------------------------------|
>>> ???? |???????????????? |?????????????????? | 00 = bypass for OR 
>>> output?? |
>>> ???? |???? 17:16?????? |?? SEL_BIT4_TYPE2? | 01 = bypass for AND 
>>> output? |
>>> ???? |???????????????? |?????????????????? | 10 = sense input '0' is 
>>> true|
>>> ???? |???????????????? |?????????????????? | 11 = sense input '1' is 
>>> true|
>>> |-------------------------------------------------------------------|
>>> ???? |???????????????? |?????????????????? | 00 = bypass for OR 
>>> output?? |
>>> ???? |???? 13:12?????? |?? SEL_BIT3_TYPE2? | 01 = bypass for AND 
>>> output? |
>>> ???? |???????????????? |?????????????????? | 10 = sense input '0' is 
>>> true|
>>> ???? |???????????????? |?????????????????? | 11 = sense input '1' is 
>>> true|
>>> |-------------------------------------------------------------------|
>>> ???? |???????????????? |?????????????????? | 00 = bypass for OR 
>>> output?? |
>>> ???? |????? 9:8??????? |?? SEL_BIT2_TYPE2? | 01 = bypass for AND 
>>> output? |
>>> ???? |???????????????? |?????????????????? | 10 = sense input '0' is 
>>> true|
>>> ???? |???????????????? |?????????????????? | 11 = sense input '1' is 
>>> true|
>>> |-------------------------------------------------------------------|
>>> ???? |???????????????? |?????????????????? | 00 = bypass for OR 
>>> output?? |
>>> ???? |????? 5:4??????? |? SEL_BIT1_TYPE2?? | 01 = bypass for AND 
>>> output? |
>>> ???? |???????????????? |?????????????????? | 10 = sense input '0' is 
>>> true|
>>> ???? |???????????????? |?????????????????? | 11 = sense input '1' is 
>>> true|
>>> |-------------------------------------------------------------------|
>>> ???? |???????????????? |?????????????????? | 00 = bypass for OR 
>>> output?? |
>>> ???? |????? 1:0??????? |? SEL_BIT0_TYPE2?? | 01 = bypass for AND 
>>> output? |
>>> ???? |???????????????? |?????????????????? | 10 = sense input '0' is 
>>> true|
>>> ???? |???????????????? |?????????????????? | 11 = sense input '1' is 
>>> true|
>>> |-------------------------------------------------------------------|
>>> ???? These bits are used to identify the signals we want to sense, with
>>> ???? a maximum signal number of 140. For example, to sense the signal
>>> ???? 0xA (binary 1010), we set the value of bits 0 to 13 to 3232, which
>>> ???? represents 1010. The remaining bits are set to 1, as we want to use
>>> ???? AND gate to summarize all the signals we want to sense here. For
>>> ???? rising or falling edge detection of any input to the priority, set
>>> ???? the remaining bits to 0 to use an OR gate.
>>>
>>> ???? 3. look for the pattern for priority_i i=0,1.
>>> ???? - echo 0x3 > /sys/bus/coresight/devices/<tgu-name>/ 
>>> step0_condition_decode/reg0
>>> ???? - echo 0x30 > /sys/bus/coresight/devices/<tgu-name>/ 
>>> step0_condition_decode/reg1
>>>
>>> |-------------------------------------------------------------------------------|
>>> ???? |?? Bits????????? |??? Field Nam??????? | 
>>> Description??????????????? |
>>> |-------------------------------------------------------------------------------|
>>> ???? |???????????????? |???????????????????? |For each decoded 
>>> condition, this?????? |
>>> ???? |????? 24???????? |?????? NOT?????????? |inverts the output. If 
>>> the condition?? |
>>> ???? |???????????????? |???????????????????? |decodes to true, and 
>>> the NOT field???? |
>>> ???? |???????????????? |???????????????????? |is '1', then the output 
>>> is NOT true.?? |
>>> |-------------------------------------------------------------------------------|
>>> ???? |???????????????? |???????????????????? |When '1' the output 
>>> from the associated|
>>> ???? |????? 21???????? |? BC0_COMP_ACTIVE??? |comparator will be 
>>> actively included in|
>>> ???? |???????????????? |???????????????????? |the decoding of this 
>>> particular??????? |
>>> ???? |???????????????? |???????????????????? | 
>>> condition.???????????????????????????? |
>>> |-------------------------------------------------------------------------------|
>>> ???? |???????????????? |???????????????????? |When '1' the output 
>>> from the associated|
>>> ???? |???????????????? |???????????????????? |comparator will need to 
>>> be 1 to affect |
>>> ???? |????? 20???????? |?? BC0_COMP_HIGH???? |the decoding of this 
>>> condition.??????? |
>>> ???? |???????????????? |???????????????????? |Conversely, a '0' here 
>>> requires a '0'? |
>>> ???? |???????????????? |???????????????????? |from the 
>>> comparator??????????????????? |
>>> |-------------------------------------------------------------------------------|
>>> ???? |???????????????? |???????????????????? |When '1' the output 
>>> from the associated|
>>> ???? |????? 17???????? |???????????????????? |comparator will be 
>>> actively included in|
>>> ???? |???????????????? |? TC0_COMP_ACTIVE??? |the decoding of this 
>>> particular??????? |
>>> ???? |???????????????? |???????????????????? | 
>>> condition.???????????????????????????? |
>>> |-------------------------------------------------------------------------------|
>>> ???? |???????????????? |???????????????????? |When '1' the output 
>>> from the associated|
>>> ???? |???????????????? |???????????????????? |comparator will need to 
>>> be 1 to affect |
>>> ???? |????? 16???????? |? TC0_COMP_HIGH????? |the decoding of this 
>>> particular??????? |
>>> ???? |???????????????? |???????????????????? |condition.Conversely, a 
>>> 0 here???????? |
>>> ???? |???????????????? |???????????????????? |requires a '0' from the 
>>> comparator???? |
>>> |-------------------------------------------------------------------------------|
>>> ???? |???????????????? |???????????????????? |When '1' the output 
>>> from Priority_n??? |
>>> ???? |???????????????? |???????????????????? |OR logic will be 
>>> actively????????????? |
>>> ???? |???? 4n+3??????? | Priority_n_OR_ACTIVE|included in the 
>>> decoding of??????????? |
>>> ???? |???????????????? |??? (n=0,1,2,3)????? |this particular 
>>> condition.???????????? |
>>> ???? |???????????????? |???????????????????? | 
>>> ?????????????????????????????????????? |
>>> |-------------------------------------------------------------------------------|
>>> ???? |???????????????? |???????????????????? |When '1' the output 
>>> from Priority_n??? |
>>> ???? |???????????????? |???????????????????? |will need to be '1' to 
>>> affect the????? |
>>> ???? |???? 4n+2??????? |? Priority_n_OR_HIGH |decoding of this 
>>> particular??????????? |
>>> ???? |???????????????? |??? (n=0,1,2,3)????? |condition. Conversely, 
>>> a '0' here????? |
>>> ???? |???????????????? |???????????????????? |requires a '0' from 
>>> Priority_n OR logic|
>>> |-------------------------------------------------------------------------------|
>>> ???? |???????????????? |???????????????????? |When '1' the output 
>>> from Priority_n??? |
>>> ???? |???????????????? |???????????????????? |AND logic will be 
>>> actively???????????? |
>>> ???? |???? 4n+1??????? |Priority_n_AND_ACTIVE|included in the 
>>> decoding of this?????? |
>>> ???? |???????????????? |? (n=0,1,2,3)??????? |particular 
>>> condition.????????????????? |
>>> ???? |???????????????? |???????????????????? | 
>>> ?????????????????????????????????????? |
>>> |-------------------------------------------------------------------------------|
>>> ???? |???????????????? |???????????????????? |When '1' the output 
>>> from Priority_n??? |
>>> ???? |???????????????? |???????????????????? |AND logic will need to 
>>> be '1' to?????? |
>>> ???? |????? 4n???????? | Priority_n_AND_HIGH |affect the decoding of 
>>> this??????????? |
>>> ???? |???????????????? |?? (n=0,1,2,3)?????? |particular condition. 
>>> Conversely,????? |
>>> ???? |???????????????? |???????????????????? |a '0' here requires a 
>>> '0' from???????? |
>>> ???? |???????????????? |???????????????????? |Priority_n AND 
>>> logic.????????????????? |
>>> |-------------------------------------------------------------------------------|
>>> ???? Since we use `priority_0` and `priority_1` with an AND output in 
>>> step 2, we set `0x3`
>>> ???? and `0x30` here to activate them.
>>>
>>> ???? 4. Set NEXT_STEP = 1 and TC0_ENABLE = 1 so that when the conditions
>>> ??????? are met then the next step will be step 1 and the timer will 
>>> be enabled.
>>> ???? - echo 0x20008 > /sys/bus/coresight/devices/<tgu-name>/ 
>>> step0_condition_select/reg0
>>> ???? - echo 0x20008 > /sys/bus/coresight/devices/<tgu-name>/ 
>>> step0_condition_select/reg1
>>>
>>> |-----------------------------------------------------------------------------|
>>> ???? |?? Bits????????? |?????? Field Nam?? | 
>>> Description??????????????? |
>>> |-----------------------------------------------------------------------------|
>>> ???? |???????????????? |?????????????????? |This field defines the 
>>> next step the?? |
>>> ???? |??? 18:17??????? |???? NEXT_STEP???? |TGU will 'goto' for the 
>>> associated???? |
>>> ???? |???????????????? |?????????????????? |Condition and 
>>> Step.??????????????????? |
>>> |-----------------------------------------------------------------------------|
>>> ???? |???????????????? |?????????????????? |For each possible output 
>>> trigger?????? |
>>> ???? |??? 13?????????? |???? TRIGGER?????? |available, set a '1' if 
>>> you want?????? |
>>> ???? |???????????????? |?????????????????? |the trigger to go active 
>>> for the?????? |
>>> ???? |???????????????? |?????????????????? |associated condition and 
>>> Step.???????? |
>>> |-----------------------------------------------------------------------------|
>>> ???? |???????????????? |?????????????????? |This will cause BC0 to 
>>> increment if the|
>>> ???? |??? 9??????????? |???? BC0_INC?????? |associated Condition is 
>>> decoded for??? |
>>> ???? |???????????????? |?????????????????? |this 
>>> step.???????????????????????????? |
>>> |-----------------------------------------------------------------------------|
>>> ???? |???????????????? |?????????????????? |This will cause BC0 to 
>>> decrement if the|
>>> ???? |??? 8??????????? |???? BC0_DEC?????? |associated Condition is 
>>> decoded for??? |
>>> ???? |???????????????? |?????????????????? |this 
>>> step.???????????????????????????? |
>>> |-----------------------------------------------------------------------------|
>>> ???? |???????????????? |?????????????????? |This will clear BC0 count 
>>> value to 0 if|
>>> ???? |??? 7??????????? |???? BC0_CLEAR???? |the associated Condition 
>>> is decoded??? |
>>> ???? |???????????????? |?????????????????? |for this 
>>> step.???????????????????????? |
>>> |-----------------------------------------------------------------------------|
>>> ???? |???????????????? |?????????????????? |This will cause TC0 to 
>>> increment until |
>>> ???? |??? 3??????????? |???? TC0_ENABLE??? |paused or cleared if the 
>>> associated??? |
>>> ???? |???????????????? |?????????????????? |Condition is decoded for 
>>> this step.??? |
>>> |-----------------------------------------------------------------------------|
>>> ???? |???????????????? |?????????????????? |This will cause TC0 to 
>>> pause until???? |
>>> ???? |??? 2??????????? |???? TC0_PAUSE???? |enabled if the associated 
>>> Condition??? |
>>> ???? |???????????????? |?????????????????? |is decoded for this 
>>> step.????????????? |
>>> |-----------------------------------------------------------------------------|
>>> ???? |???????????????? |?????????????????? |This will clear TC0 count 
>>> value to 0?? |
>>> ???? |??? 1??????????? |???? TC0_CLEAR???? |if the associated 
>>> Condition is???????? |
>>> ???? |???????????????? |?????????????????? |decoded for this 
>>> step.???????????????? |
>>> |-----------------------------------------------------------------------------|
>>> ???? |???????????????? |?????????????????? |This will set the done 
>>> signal to the?? |
>>> ???? |??? 0??????????? |???? DONE????????? |TGU FSM if the associated 
>>> Condition??? |
>>> ???? |???????????????? |?????????????????? |is decoded for this 
>>> step.????????????? |
>>> |-----------------------------------------------------------------------------|
>>> ???? Based on the distribution diagram, we set `0x20008` for 
>>> `priority0` and `priority1` to
>>> ???? achieve "jump to step 1 and enable TC0" once the signal is sensed.
>>>
>>> ???? 5. activate the timer comparison for this step.
>>> ???? -? echo 0x30000? > /sys/bus/coresight/devices/<tgu-name>/ 
>>> step1_condition_decode/reg0
>>>
>>> |-------------------------------------------------------------------------------|
>>> ???? |???????????????? |???????????????????? |When '1' the output 
>>> from the associated|
>>> ???? |????? 17???????? |???????????????????? |comparator will be 
>>> actively included in|
>>> ???? |???????????????? |? TC0_COMP_ACTIVE??? |the decoding of this 
>>> particular??????? |
>>> ???? |???????????????? |???????????????????? | 
>>> condition.???????????????????????????? |
>>> |-------------------------------------------------------------------------------|
>>> ???? |???????????????? |???????????????????? |When '1' the output 
>>> from the associated|
>>> ???? |???????????????? |???????????????????? |comparator will need to 
>>> be 1 to affect |
>>> ???? |????? 16???????? |? TC0_COMP_HIGH????? |the decoding of this 
>>> particular??????? |
>>> ???? |???????????????? |???????????????????? |condition.Conversely, a 
>>> 0 here???????? |
>>> ???? |???????????????? |???????????????????? |requires a '0' from the 
>>> comparator???? |
>>> |-------------------------------------------------------------------------------|
>>> ???? Accroding to the decode distribution diagram , we give 0x30000 
>>> here to set 16th&17th bit
>>> ???? to enable timer comparison.
>>>
>>> ???? 6. Set the NEXT_STEP = 0 and TC0_PAUSE = 1 and TC0_CLEAR = 1 
>>> once the timer
>>> ??????? has reached the given value.
>>> ???? - echo 0x6 > /sys/bus/coresight/devices/<tgu-name>/ 
>>> step1_condition_select/reg0
>>>
>>> ???? 7. Enable Trigger 0 for TGU when the condition 0 is met in step1,
>>> ??????? i.e. when the timer reaches 3.
>>> ???? - echo 0x2000 > /sys/bus/coresight/devices/<tgu-name>/ 
>>> step1_condition_select/default
>>>
>>> ???? Note:
>>> ???????? 1. 'default' register allows for establishing the resultant 
>>> action for
>>> ???????? the default condition
>>>
>>> ???????? 2. Trigger:For each possible output trigger available from
>>> ???????? the Design document, there are three triggers: interrupts, CTI,
>>> ???????? and Cross-TGU mapping.All three triggers can occur, but
>>> ???????? the choice of which trigger to use depends on the user's
>>> ???????? needs.
>>>
>>> ???? 8. Compare the timer to 3 in step 1.
>>> ???? - echo 0x3 > /sys/bus/coresight/devices/<tgu-name>/step1_timer/reg0
>>>
>>> ???? 9. enale tgu
>>> ???? - echo 1 > /sys/bus/coresight/devices/<tgu-name>/enable_tgu
>>> ---
>>> Link to V7: https://lore.kernel.org/all/20251104064043.88972-1- 
>>> songwei.chai at oss.qualcomm.com/
>>>
>>> Changes in V8:
>>> - Add "select" section in bindings.
>>> - Update publish date in "sysfs-bus-coresight-devices-tgu".
>>> ---
>>> Link to V6: https://lore.kernel.org/all/20250709104114.22240-1- 
>>> songchai at qti.qualcomm.com/
>>>
>>> Changes in V7:
>>> - Move the TGU code location from 'drivers/hwtracing/coresight/' to 
>>> 'drivers/hwtracing/qcom/'.
>>> - Rename the spinlock used in the code from 'spinlock' to 'lock'.
>>> - Perform the 'calculate_array_location' separately, instead of doing 
>>> it within the function.
>>> - Update the sender email address.
>>> ---
>>> Link to V5: https://lore.kernel.org/all/20250529081949.26493-1- 
>>> quic_songchai at quicinc.com/
>>>
>>> Changes in V6:
>>> - Replace spinlock with guard(spinlock) in tgu_enable.
>>> - Remove redundant blank line.
>>> - Update publish date and contact member's name in "sysfs-bus- 
>>> coresight-devices-tgu".
>>> ---
>>> Link to V4: https://patchwork.kernel.org/project/linux-arm-msm/ 
>>> cover/20250423101054.954066-1-quic_songchai at quicinc.com/
>>>
>>> Changes in V5:
>>> - Update publish date and kernel_version in "sysfs-bus-coresight- 
>>> devices-tgu"
>>> ---
>>> Link to V3: https://lore.kernel.org/all/20250227092640.2666894-1- 
>>> quic_songchai at quicinc.com/
>>>
>>> Changes in V4:
>>> - Add changlog in coverletter.
>>> - Correct 'year' in Copyright in patch1.
>>> - Correct port mechansim description in patch1.
>>> - Remove 'tgu-steps','tgu-regs','tgu-conditions','tgu-timer-counters' 
>>> from dt-binding
>>> and set them through reading DEVID register as per Mike's suggestion.
>>> - Modify tgu_disable func to make it have single return point in 
>>> patch2 as per
>>> Mike's suggestion.
>>> - Use sysfs_emit in enable_tgu_show func in ptach2.
>>> - Remove redundant judgement in enable_tgu_store in patch2.
>>> - Correct typo in description in patch3.
>>> - Set default ret as SYSFS_GROUP_INVISIBLE, and returnret at end in 
>>> pacth3 as
>>> per Mike's suggestion.
>>> - Remove tgu_dataset_ro definition in patch3
>>> - Use #define constants with explanations of what they are rather than
>>> arbitrary magic numbers in patch3 and patch4.
>>> - Check -EINVAL before using 'calculate_array_location()' in array in 
>>> patch4.
>>> - Add 'default' in 'tgu_dataset_show''s switch part in patch4.
>>> - Document the value needed to initiate the reset in pacth7.
>>> - Check "value" in 'reset_tgu_store' and bail out with an error code 
>>> if 0 in patch7.
>>> - Remove dev_dbg in 'reset_tgu_store' in patch7.
>>> ---
>>> Link to V2: https://lore.kernel.org/all/20241010073917.16023-1- 
>>> quic_songchai at quicinc.com/
>>>
>>> Changes in V3:
>>> - Correct typo and format in dt-binding in patch1
>>> - Rebase to the latest kernel version
>>> ---
>>> Link to V1: https://lore.kernel.org/all/20240830092311.14400-1- 
>>> quic_songchai at quicinc.com/
>>>
>>> Changes in V2:
>>> ? - Use real name instead of login name,
>>> ? - Correct typo and format in dt-binding and code.
>>> ? - Bring order in tgu_prob(declarations with and without 
>>> assignments) as per
>>> Krzysztof's suggestion.
>>> ? - Add module device table in patch2.
>>> ? - Set const for tgu_common_grp and tgu_ids in patch2.
>>> ? - Initialize 'data' in tgu_ids to fix the warning in pacth2.
>>> ---
>>>
>>> Songwei Chai (7):
>>> ?? dt-bindings: arm: Add support for Qualcomm TGU trace
>>> ?? qcom-tgu: Add TGU driver
>>> ?? qcom-tgu: Add signal priority support
>>> ?? qcom-tgu: Add TGU decode support
>>> ?? qcom-tgu: Add support to configure next action
>>> ?? qcom-tgu: Add timer/counter functionality for TGU
>>> ?? qcom-tgu: Add reset node to initialize
>>>
>>> ? .../testing/sysfs-bus-coresight-devices-tgu?? |? 51 ++
>>> ? .../devicetree/bindings/arm/qcom,tgu.yaml???? |? 92 +++
>>> ? drivers/Makefile????????????????????????????? |?? 1 +
>>> ? drivers/hwtracing/Kconfig???????????????????? |?? 2 +
>>> ? drivers/hwtracing/qcom/Kconfig??????????????? |? 18 +
>>> ? drivers/hwtracing/qcom/Makefile?????????????? |?? 3 +
>>> ? drivers/hwtracing/qcom/tgu.c????????????????? | 737 ++++++++++++++++++
>>> ? drivers/hwtracing/qcom/tgu.h????????????????? | 252 ++++++
>>> ? 8 files changed, 1156 insertions(+)
>>> ? create mode 100644 Documentation/ABI/testing/sysfs-bus-coresight- 
>>> devices-tgu
>>> ? create mode 100644 Documentation/devicetree/bindings/arm/qcom,tgu.yaml
>>> ? create mode 100644 drivers/hwtracing/qcom/Kconfig
>>> ? create mode 100644 drivers/hwtracing/qcom/Makefile
>>> ? create mode 100644 drivers/hwtracing/qcom/tgu.c
>>> ? create mode 100644 drivers/hwtracing/qcom/tgu.h
>>>
>>
> 



From andrew at lunn.ch  Fri Dec  5 05:52:11 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Fri, 5 Dec 2025 14:52:11 +0100
Subject: [PATCH net-next] net: mdio: aspeed: add dummy read to avoid
 read-after-write issue
In-Reply-To: <20251205-aspeed_mdio_add_dummy_read-v1-1-60145ae20ea7@aspeedtech.com>
References: <20251205-aspeed_mdio_add_dummy_read-v1-1-60145ae20ea7@aspeedtech.com>
Message-ID: <230147e8-e27b-48e1-9a62-7aa8abc3f492@lunn.ch>

On Fri, Dec 05, 2025 at 09:37:22AM +0800, Jacky Chou wrote:
> The Aspeed MDIO controller may return incorrect data when a read operation
> follows immediately after a write. Due to a controller bug, the subsequent
> read can latch stale data, causing the polling logic to terminate earlier
> than expected.
> 
> To work around this hardware issue, insert a dummy read after each write
> operation. This ensures that the next actual read returns the correct
> data and prevents premature polling exit.
> 
> This workaround has been verified to stabilize MDIO transactions on
> affected Aspeed platforms.
> 
> Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>

This seems like a bug fix. Please add a Fixes: tag, for base it on
net, not net-next.

> ---
>  drivers/net/mdio/mdio-aspeed.c | 6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/drivers/net/mdio/mdio-aspeed.c b/drivers/net/mdio/mdio-aspeed.c
> index e55be6dc9ae7..00e61b922876 100644
> --- a/drivers/net/mdio/mdio-aspeed.c
> +++ b/drivers/net/mdio/mdio-aspeed.c
> @@ -62,6 +62,12 @@ static int aspeed_mdio_op(struct mii_bus *bus, u8 st, u8 op, u8 phyad, u8 regad,
>  		| FIELD_PREP(ASPEED_MDIO_DATA_MIIRDATA, data);
>  
>  	iowrite32(ctrl, ctx->base + ASPEED_MDIO_CTRL);
> +	/* Workaround for read-after-write issue.

Blank line before the comment please.

    Andrew

---
pw-bot: cr




From tan.siewert at hetzner.com  Fri Dec  5 06:08:12 2025
From: tan.siewert at hetzner.com (Tan Siewert)
Date: Fri, 5 Dec 2025 15:08:12 +0100
Subject: [PATCH v3 2/3] ARM: dts: aspeed: add device tree for ASRock Rack
 ALTRAD8 BMC
In-Reply-To: <aa75c5a4-27cf-4cc2-9851-07713999f469@hetzner.com>
References: <20251204210238.40742-1-rebecca@bsdio.com>
 <20251204210238.40742-3-rebecca@bsdio.com>
 <aa75c5a4-27cf-4cc2-9851-07713999f469@hetzner.com>
Message-ID: <a8b5df46-edd1-4e35-a8d4-8842526df8d0@hetzner.com>

On 04.12.25 23:29, Tan Siewert wrote:
> On 04.12.25 22:02, Rebecca Cran wrote:
>> The ALTRAD8 BMC is an Aspeed AST2500-based BMC for the ASRock Rack
>> ALTRAD8UD-1L2T and ALTRAD8UD2-1L2Q boards.
>>
>> Signed-off-by: Rebecca Cran <rebecca at bsdio.com>
>> ---
>> ? arch/arm/boot/dts/aspeed/Makefile????????????????????? |?? 1 +
>> ? arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts | 612 +++++++ 
>> +++++++++++++
>> ? 2 files changed, 613 insertions(+)

*snip*

>> diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts b/ 
>> arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts
>> new file mode 100644
>> index 000000000000..2696a8692607
>> --- /dev/null
>> +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts

*snip*

>> +&gpio {
>> +??? gpio-line-names =
>> +??? /*A0-A7*/??? "","","","bmc-ready","","","","",
>> +??? /*B0-B7*/??? "i2c-backup-sel","","","","","","","host0-shd-ack-n",
>> +??? /*C0-C7*/??? "","","","","","","","",
>> +??? /*D0-D7*/??? "power-button","power-out","button-reset",

I just noticed that I overlooked the power buttons in my recent review.

power-button = button-power-n (active low)

power-out = control-power-n (active low)

button-reset = button-reset-n (active low)

The other review comments remain.

-- Tan

>> +??????????? "host0-sysreset-n","","","power-chassis-good","",
>> +??? /*E0-E7*/??? "","s0-vrd1-vddq0123-fault-n",
>> +??????????? "s0-vrd1-vddq4567-fault-n","s0-vrd0-vddc-fault-n",
>> +??????????? "s0-vrd3-p0v75-fault-n","","","",
>> +??? /*F0-F7*/??? "","","ps-atx-on-n","","","","","",
>> +??? /*G0-G7*/??? "led-identify","button-identify","","","uboot-ready",\
> 
> `button-identify` should be `button-identify-n` (active-low).
> 
> `led-system-fault-n` is GPIOG3.
> 
> `led-identify-n` _could_ be at GPIOQ6 (seems to be wired to the CPLD (?!)).
> 
>> +??????????? "bmc-salt2-n","","",
>> +??? /*H0-H7*/??? "ps-pwr-ok","uart1-mode1","uart2-mode1","uart3-mode1",
>> +??????????? "uart4-mode1","","led-bmc-heartbeat","",
> 
> GPIOH6 is `BMC_JTAG_SEL_S0`. The `led-bmc-hearbeat-n` should be GPIOG0.
> 
>> +??? /*I0-I7*/??? "","","","","","","","",
>> +??? /*J0-J7*/??? "s0-hightemp-n","","","","","","","",
>> +??? /*K0-K7*/??? "","","","","","","","",
>> +??? /*L0-L7*/??? "","","","","","","","",
>> +??? /*M0-M7*/??? "","","","","","s0-spi-auth-fail-n","","",
>> +??? /*N0-N7*/??? "","","","","","","","",
>> +??? /*O0-O7*/??? "","","","","","","","",
>> +??? /*P0-P7*/??? "","","cpld-disable-bmc","","","","","",
> 
> `cpld-disable-bmc` should be `cpld-disable-bmc-n` and at GPIOM0 
> (`CPLD_DISABLE_BMC_L` in schematic). GPIOP2 is a fan tacho.
> 
>> +??? /*Q0-Q7*/??? "","","ext-hightemp-n","","","","",
> 
> double assignment of `ext-hightemp-n`. Correct one is GPIOR2. Please 
> remove it.
> 
>> +??????????? "chassis-intrusion",
> 
> `chassis-intrusion-n` (active-low).
> 
>> +??? /*R0-R7*/??? "","","ext-hightemp-n","spi0-program-sel","",
>> +??????????? "hwm-bat-en","","",
> 
> `hwm-bat-en` could be prefixed with `output-`.
> 
>> +??? /*S0-S7*/??? "s0-vr-hot-n","","","bmc-sysreset-n","","","","",
> 
> GPIOS2 (`input-salt5-n`) _could_ be useful (comes from the X550 for WoL 
> (`LAN_3V3STBY_ALRT_N` in schematic)).
> 
>> +??? /*T0-T7*/??? "","","","","","","","",
>> +??? /*U0-U7*/??? "","","","","","","","",
>> +??? /*V0-V7*/??? "","","","","","","","",
>> +??? /*W0-W7*/??? "","","","","","","","",
>> +??? /*X0-X7*/??? "","","","","","","","",
>> +??? /*Y0-Y7*/??? "sio-s3","sio-s5","sio-pwr-req","sio-on- 
>> ctrl","","","","",
>> +??? /*Z0-Z7*/??? "","sio-pwr-good","","s0-rtc-lock","","","","",
> 
> System has no Super-IO. Please remove the `sio-` assignments.
> 
>> +??? /*AA0-AA7*/??? "rtc-int","","","","","pmbus-sel-n","","",
> 
> `rtc-int` should be `s0-rtc-int-n`.
> 
>> +??? /*AB0-AB7*/??? "host0-reboot-ack-n","s0-sys-auth-failure-n",
>> +??????????? "","","","","","",
>> +??? /*AC0-AC7*/??? "s0-fault-alert","host0-ready","s0-overtemp-n",
>> +??????????? "","bmc-ok","host0-special-boot","presence-cpu0",
>> +??????????? "host0-shd-req-n";
>> +
>> +??? status = "okay";
>> +};

-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature.asc
Type: application/pgp-signature
Size: 840 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251205/fb023189/attachment.sig>

From diederik at cknow-tech.com  Fri Dec  5 06:15:39 2025
From: diederik at cknow-tech.com (Diederik de Haas)
Date: Fri, 05 Dec 2025 15:15:39 +0100
Subject: [PATCH] regulator: fixed: Rely on the core freeing the enable
 GPIO
In-Reply-To: <20251204-regulator-fixed-fix-gpiod-leak-v1-1-48efea5b82c2@kernel.org>
References: <20251204-regulator-fixed-fix-gpiod-leak-v1-1-48efea5b82c2@kernel.org>
Message-ID: <DEQCHCIUQ8KK.DXHGCLW95XUC@cknow-tech.com>

On Thu Dec 4, 2025 at 8:39 PM CET, Mark Brown wrote:

s/enable GPIO/enabled GPIOs/ ? (in Subject)

> In order to simplify ownership rules for enable GPIOs supplied by drivers
> regulator_register() always takes ownership of them, even if it ends up
> failing for some other reason. We therefore should	not free the GPIO if
> registration fails but just let the core worry about things.

I built a 6.18 kernel with this patch added and that fixed the problem.
Thanks :-) Feel free to add:

Tested-by: Diederik de Haas <diederik at cknow-tech.com>

Cheers,
  Diederik

> Fixes: 636f4618b1cd (regulator: fixed: fix GPIO descriptor leak on register failure)
> Reported-by: Diederik de Haas <diederik at cknow-tech.com>
> Closes: https://lore.kernel.org/r/DEPEYUF5BRGY.UKFBWRRE8HNP at cknow-tech.com
> Signed-off-by: Mark Brown <broonie at kernel.org>
> ---
>  drivers/regulator/fixed.c | 11 ++++-------
>  1 file changed, 4 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
> index a2d16e9abfb5..254c0a8a4555 100644
> --- a/drivers/regulator/fixed.c
> +++ b/drivers/regulator/fixed.c
> @@ -330,13 +330,10 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
>  
>  	drvdata->dev = devm_regulator_register(&pdev->dev, &drvdata->desc,
>  					       &cfg);
> -	if (IS_ERR(drvdata->dev)) {
> -		ret = dev_err_probe(&pdev->dev, PTR_ERR(drvdata->dev),
> -				    "Failed to register regulator: %ld\n",
> -				    PTR_ERR(drvdata->dev));
> -		gpiod_put(cfg.ena_gpiod);
> -		return ret;
> -	}
> +	if (IS_ERR(drvdata->dev))
> +		return dev_err_probe(&pdev->dev, PTR_ERR(drvdata->dev),
> +				     "Failed to register regulator: %ld\n",
> +				     PTR_ERR(drvdata->dev));
>  
>  	platform_set_drvdata(pdev, drvdata);
>  
>
> ---
> base-commit: 81d431130ae1af4e64030f6a956ee9137e6fc1b0
> change-id: 20251204-regulator-fixed-fix-gpiod-leak-b1f50fb8c388
>
> Best regards,
> --  
> Mark Brown <broonie at kernel.org>



From a.shimko.dev at gmail.com  Fri Dec  5 06:16:32 2025
From: a.shimko.dev at gmail.com (Artem Shimko)
Date: Fri, 5 Dec 2025 17:16:32 +0300
Subject: [PATCH v4] firmware: arm_scmi: refactor reset domain handling
In-Reply-To: <20251205-calculating-unique-ibex-de824e@sudeepholla>
References: <aRW4PpPjVw1-melm@pluto> <20251123163557.230530-1-a.shimko.dev@gmail.com>
 <20251204-slick-granite-chameleon-58ebc2@sudeepholla> <CAOPX747pTsnTzKnaai-ytnmcf6reraTTSk+mssvHri4GMhCsOA@mail.gmail.com>
 <20251205-calculating-unique-ibex-de824e@sudeepholla>
Message-ID: <CAOPX747Nk5jOYREOYKO2=Zn0C-Zb=TY-nDbL_LzxbR2qcteexQ@mail.gmail.com>

On Fri, Dec 5, 2025 at 3:14?PM Sudeep Holla <sudeep.holla at arm.com> wrote:

> Let me know if you are happy too with that change.
Yes, sure, I'm happy with the change. Thank you!

--
Regards,
Artem


From louisalexis.eyraud at collabora.com  Fri Dec  5 06:22:25 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Fri, 05 Dec 2025 15:22:25 +0100
Subject: [PATCH 0/2] drm/mediatek: HDMI DDC v2 driver fixes
Message-ID: <20251205-mtk-hdmi-ddc-v2-fixes-v1-0-260dd0d320f4@collabora.com>

This patch series fixes two issues in the Mediatek HDMI DDC v2
driver (mtk_hdmi_ddc_v2).

Patch 1 fixes a potential issue on transfer timeout cases to properly
abort read/write transfers.
Patch 2 fixes DDC communication errors that occur when getting
or modifying display features with ddcutil with subcommands such as
detect, getvcp or setvcp:
```
$ ddcutil getvcp 10 -b 4 # read brightness
DDC communication failed for monitor on bus /dev/i2c-4

$ ddcutil setvcp 10 75 -b 4 # change brightness
DDC communication failed for monitor on bus /dev/i2c-4
```

These patches were tested on Mediatek Genio 510-EVK and 1200-EVK boards
with a kernel based on next-20251205 tag plus devicetree patches to
enable HDMI output.

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
Louis-Alexis Eyraud (2):
      drm/mediatek: mtk_hdmi_ddc_v2: Add transfer abort on timeout cases
      drm/mediatek: mtk_hdmi_ddc_v2: Fix multi-byte writes

 drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c | 58 +++++++++++++++++-------------
 1 file changed, 33 insertions(+), 25 deletions(-)
---
base-commit: 4e5a9b630580faea139e9837b4fba666db6bd728
change-id: 20251204-mtk-hdmi-ddc-v2-fixes-b5d61fdea639

Best regards,
-- 
Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>



From louisalexis.eyraud at collabora.com  Fri Dec  5 06:22:26 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Fri, 05 Dec 2025 15:22:26 +0100
Subject: [PATCH 1/2] drm/mediatek: mtk_hdmi_ddc_v2: Add transfer abort on
 timeout cases
In-Reply-To: <20251205-mtk-hdmi-ddc-v2-fixes-v1-0-260dd0d320f4@collabora.com>
References: <20251205-mtk-hdmi-ddc-v2-fixes-v1-0-260dd0d320f4@collabora.com>
Message-ID: <20251205-mtk-hdmi-ddc-v2-fixes-v1-1-260dd0d320f4@collabora.com>

During a read or write transfer, the mtk_hdmi_ddc_v2 driver polls the
DDC_I2C_IN_PROG bit of HPD_DDC_STATUS register to check if the transfer
completes but do no particular action if a timeout is reached. It could
lead the next transfer attempts to fail because the faulty transfer was
not aborted. So, add in both low level read and write functions a abort
action by writing the DDC_CTRL register with the ABORT_XFER command
value.

Fixes: 8d0f79886273 ("drm/mediatek: Introduce HDMI/DDC v2 for MT8195/MT8188")
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c b/drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c
index b844e2c10f28060baef64bd36c5464758b08e162..6ae7cbba8cb6dacf46c2f7ab74a2d7446d698b69 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c
@@ -96,6 +96,11 @@ static int mtk_ddc_wr_one(struct mtk_hdmi_ddc *ddc, u16 addr_id,
 				       !(val & DDC_I2C_IN_PROG), 500, 1000);
 	if (ret) {
 		dev_err(ddc->dev, "DDC I2C write timeout\n");
+
+		/* Abort transfer if it is still in progress */
+		regmap_update_bits(ddc->regs, DDC_CTRL, DDC_CTRL_CMD,
+				   FIELD_PREP(DDC_CTRL_CMD, DDC_CMD_ABORT_XFER));
+
 		return ret;
 	}
 
@@ -179,6 +184,11 @@ static int mtk_ddcm_read_hdmi(struct mtk_hdmi_ddc *ddc, u16 uc_dev,
 					       500 * (temp_length + 5));
 		if (ret) {
 			dev_err(ddc->dev, "Timeout waiting for DDC I2C\n");
+
+			/* Abort transfer if it is still in progress */
+			regmap_update_bits(ddc->regs, DDC_CTRL, DDC_CTRL_CMD,
+					   FIELD_PREP(DDC_CTRL_CMD, DDC_CMD_ABORT_XFER));
+
 			return ret;
 		}
 

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Fri Dec  5 06:22:27 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Fri, 05 Dec 2025 15:22:27 +0100
Subject: [PATCH 2/2] drm/mediatek: mtk_hdmi_ddc_v2: Fix multi-byte writes
In-Reply-To: <20251205-mtk-hdmi-ddc-v2-fixes-v1-0-260dd0d320f4@collabora.com>
References: <20251205-mtk-hdmi-ddc-v2-fixes-v1-0-260dd0d320f4@collabora.com>
Message-ID: <20251205-mtk-hdmi-ddc-v2-fixes-v1-2-260dd0d320f4@collabora.com>

Currently, the mtk_hdmi_ddc_v2 driver sends a i2c message by calling
the mtk_ddc_wr_one function for each byte of the payload to setup
SI2C_CTRL and DDC_CTRL registers, and perform a sequential write
transfer of one byte at a time to the target device. This leads to
incorrect transfers as the target address (at least) is also sent each
time.

So, rename mtk_ddc_wr_one function to mtk_ddcm_write_hdmi to match the
read function name (mtk_ddcm_read_hdmi) and modify its behaviour to
send all payload data in a single sequential write transfer by filling
the transfer fifo first then starting the transfer with a size equal to
the payload size and not one anymore.

Fixes: 8d0f79886273 ("drm/mediatek: Introduce HDMI/DDC v2 for MT8195/MT8188")
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c | 48 ++++++++++++++----------------
 1 file changed, 23 insertions(+), 25 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c b/drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c
index 6ae7cbba8cb6dacf46c2f7ab74a2d7446d698b69..d937219fdb7ee0ed6a4ac25e950f69f90ff431a3 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c
@@ -66,11 +66,19 @@ static int mtk_ddc_check_and_rise_low_bus(struct mtk_hdmi_ddc *ddc)
 	return 0;
 }
 
-static int mtk_ddc_wr_one(struct mtk_hdmi_ddc *ddc, u16 addr_id,
-			  u16 offset_id, u8 *wr_data)
+static int mtk_ddcm_write_hdmi(struct mtk_hdmi_ddc *ddc, u16 addr_id,
+			       u16 offset_id, u16 data_cnt, u8 *wr_data)
 {
 	u32 val;
-	int ret;
+	int ret, i;
+
+	/* Don't allow transfer with a size over than the transfer fifo size
+	 * (16 byte)
+	 */
+	if (data_cnt > 16) {
+		dev_err(ddc->dev, "Invalid DDCM write request\n");
+		return -EINVAL;
+	}
 
 	/* If down, rise bus for write operation */
 	mtk_ddc_check_and_rise_low_bus(ddc);
@@ -78,16 +86,21 @@ static int mtk_ddc_wr_one(struct mtk_hdmi_ddc *ddc, u16 addr_id,
 	regmap_update_bits(ddc->regs, HPD_DDC_CTRL, HPD_DDC_DELAY_CNT,
 			   FIELD_PREP(HPD_DDC_DELAY_CNT, DDC2_DLY_CNT));
 
+	/* In case there is no payload data, just do a single write for the
+	 * address only
+	 */
 	if (wr_data) {
-		regmap_write(ddc->regs, SI2C_CTRL,
-			     FIELD_PREP(SI2C_ADDR, SI2C_ADDR_READ) |
-			     FIELD_PREP(SI2C_WDATA, *wr_data) |
-			     SI2C_WR);
+		/* Fill transfer fifo with payload data */
+		for (i = 0; i < data_cnt; i++) {
+			regmap_write(ddc->regs, SI2C_CTRL,
+				     FIELD_PREP(SI2C_ADDR, SI2C_ADDR_READ) |
+				     FIELD_PREP(SI2C_WDATA, wr_data[i]) |
+				     SI2C_WR);
+		}
 	}
-
 	regmap_write(ddc->regs, DDC_CTRL,
 		     FIELD_PREP(DDC_CTRL_CMD, DDC_CMD_SEQ_WRITE) |
-		     FIELD_PREP(DDC_CTRL_DIN_CNT, wr_data == NULL ? 0 : 1) |
+		     FIELD_PREP(DDC_CTRL_DIN_CNT, wr_data == NULL ? 0 : data_cnt) |
 		     FIELD_PREP(DDC_CTRL_OFFSET, offset_id) |
 		     FIELD_PREP(DDC_CTRL_ADDR, addr_id));
 	usleep_range(1000, 1250);
@@ -260,24 +273,9 @@ static int mtk_hdmi_fg_ddc_data_read(struct mtk_hdmi_ddc *ddc, u16 b_dev,
 static int mtk_hdmi_ddc_fg_data_write(struct mtk_hdmi_ddc *ddc, u16 b_dev,
 				      u8 data_addr, u16 data_cnt, u8 *pr_data)
 {
-	int i, ret;
-
 	regmap_set_bits(ddc->regs, HDCP2X_POL_CTRL, HDCP2X_DIS_POLL_EN);
-	/*
-	 * In case there is no payload data, just do a single write for the
-	 * address only
-	 */
-	if (data_cnt == 0)
-		return mtk_ddc_wr_one(ddc, b_dev, data_addr, NULL);
-
-	i = 0;
-	do {
-		ret = mtk_ddc_wr_one(ddc, b_dev, data_addr + i, pr_data + i);
-		if (ret)
-			return ret;
-	} while (++i < data_cnt);
 
-	return 0;
+	return mtk_ddcm_write_hdmi(ddc, b_dev, data_addr, data_cnt, pr_data);
 }
 
 static int mtk_hdmi_ddc_v2_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)

-- 
2.52.0



From m.szyprowski at samsung.com  Fri Dec  5 06:25:52 2025
From: m.szyprowski at samsung.com (Marek Szyprowski)
Date: Fri, 5 Dec 2025 15:25:52 +0100
Subject: [PATCH 0/4] drm: Revert and fix enable/disable sequence
In-Reply-To: <20251205-drm-seq-fix-v1-0-fda68fa1b3de@ideasonboard.com>
References: <CGME20251205095238eucas1p1b7cf95d86a9aecf19877ac568148e265@eucas1p1.samsung.com>
	<20251205-drm-seq-fix-v1-0-fda68fa1b3de@ideasonboard.com>
Message-ID: <b2f3e15c-1a15-427d-90d9-ea0e33b50ecb@samsung.com>

On 05.12.2025 10:51, Tomi Valkeinen wrote:
> Changing the enable/disable sequence in commit c9b1150a68d9
> ("drm/atomic-helper: Re-order bridge chain pre-enable and post-disable")
> has caused regressions on multiple platforms: R-Car, MCDE, Rockchip.
>
> This is an alternate series to Linus' series:
>
> https://lore.kernel.org/all/20251202-mcde-drm-regression-thirdfix-v6-0-f1bffd4ec0fa%40kernel.org/
>
> This series first reverts the original commit and reverts a fix for
> mediatek which is no longer needed. It then exposes helper functions
> from DRM core, and finally implements the new sequence only in the tidss
> driver.
>
> There is one more fix in upstream for the original commit, commit
> 5d91394f2361 ("drm/exynos: fimd: Guard display clock control with
> runtime PM calls"), but I have not reverted that one as it looks like a
> valid patch in its own.

Right, that patch is a fix on its own, the changes in the atomic 
sequence just revealed the issue.

> I added Cc stable v6.17+ to all patches, but I didn't add Fixes tags, as
> I wasn't sure what should they point to. But I could perhaps add Fixes:
> <original commit> to all of these.
>
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
> ---
> Linus Walleij (1):
>        drm/atomic-helper: Export and namespace some functions
>
> Tomi Valkeinen (3):
>        Revert "drm/atomic-helper: Re-order bridge chain pre-enable and post-disable"
>        Revert "drm/mediatek: dsi: Fix DSI host and panel bridge pre-enable order"
>        drm/tidss: Fix enable/disable order
>
>   drivers/gpu/drm/drm_atomic_helper.c | 122 ++++++++++++++----
>   drivers/gpu/drm/mediatek/mtk_dsi.c  |   6 -
>   drivers/gpu/drm/tidss/tidss_kms.c   |  30 ++++-
>   include/drm/drm_atomic_helper.h     |  22 ++++
>   include/drm/drm_bridge.h            | 249 ++++++++++--------------------------
>   5 files changed, 214 insertions(+), 215 deletions(-)
> ---
> base-commit: 88e721ab978a86426aa08da520de77430fa7bb84
> change-id: 20251205-drm-seq-fix-b4ed1f56604b

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland



From thomas.richard at bootlin.com  Fri Dec  5 06:28:22 2025
From: thomas.richard at bootlin.com (Thomas Richard (TI.com))
Date: Fri, 05 Dec 2025 15:28:22 +0100
Subject: [PATCH v3 0/4] firmware: ti_sci: Introduce BOARDCFG_MANAGED mode
 for Jacinto family
Message-ID: <20251205-ti-sci-jacinto-s2r-restore-irq-v3-0-d06963974ad4@bootlin.com>

This is the fourth iteration. In this new version the sci-clk driver also
restores the clock rate. I rebased the series on linux-next so we should
not have conflict with next rc1.

Signed-off-by: Thomas Richard (TI.com) <thomas.richard at bootlin.com>
---
Changes in v3:
- rebased on linux-next
- sci-clk: context_restore() operation restores also rate.
- Link to v2: https://lore.kernel.org/r/20251127-ti-sci-jacinto-s2r-restore-irq-v2-0-a487fa3ff221 at bootlin.com

Changes in v2:
- ti_sci: use hlist to store IRQs.
- sci-clk: add context_restore operation
- ti_sci: restore clock parents during resume 
- Link to v1: https://lore.kernel.org/r/20251017-ti-sci-jacinto-s2r-restore-irq-v1-0-34d4339d247a at bootlin.com

---
Thomas Richard (TI.com) (4):
      firmware: ti_sci: add BOARDCFG_MANAGED mode support
      firmware: ti_sci: handle IRQ restore in BOARDCFG_MANAGED mode during resume
      clk: keystone: sci-clk: add restore_context() operation
      firmware: ti_sci: restore clock context during resume in BOARDCFG_MANAGED mode

 drivers/clk/keystone/sci-clk.c |  42 ++++++++---
 drivers/firmware/ti_sci.c      | 160 +++++++++++++++++++++++++++++++++++++----
 drivers/firmware/ti_sci.h      |   2 +
 3 files changed, 184 insertions(+), 20 deletions(-)
---
base-commit: 6c95d7e679d5d01fa48d6a8b8bdb92b6effe34f6
change-id: 20251010-ti-sci-jacinto-s2r-restore-irq-428e008fd10c

Best regards,
-- 
Thomas Richard (TI.com) <thomas.richard at bootlin.com>



From thomas.richard at bootlin.com  Fri Dec  5 06:28:23 2025
From: thomas.richard at bootlin.com (Thomas Richard (TI.com))
Date: Fri, 05 Dec 2025 15:28:23 +0100
Subject: [PATCH v3 1/4] firmware: ti_sci: add BOARDCFG_MANAGED mode support
In-Reply-To: <20251205-ti-sci-jacinto-s2r-restore-irq-v3-0-d06963974ad4@bootlin.com>
References: <20251205-ti-sci-jacinto-s2r-restore-irq-v3-0-d06963974ad4@bootlin.com>
Message-ID: <20251205-ti-sci-jacinto-s2r-restore-irq-v3-1-d06963974ad4@bootlin.com>

In BOARDCFG_MANAGED mode, the low power mode configuration is done
statically for the DM via the boardcfg. Constraints are not supported, and
prepare_sleep() is not needed.

Signed-off-by: Thomas Richard (TI.com) <thomas.richard at bootlin.com>
---
 drivers/firmware/ti_sci.c | 10 +++++++---
 drivers/firmware/ti_sci.h |  2 ++
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index 4a277937211f6..d77b631d9c855 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -3772,8 +3772,11 @@ static int ti_sci_prepare_system_suspend(struct ti_sci_info *info)
 			return ti_sci_cmd_prepare_sleep(&info->handle,
 							TISCI_MSG_VALUE_SLEEP_MODE_DM_MANAGED,
 							0, 0, 0);
+		} else if (info->fw_caps & MSG_FLAG_CAPS_LPM_BOARDCFG_MANAGED) {
+			/* Nothing to do in the BOARDCFG_MANAGED mode */
+			return 0;
 		} else {
-			/* DM Managed is not supported by the firmware. */
+			/* DM Managed and BoardCfg Managed are not supported by the firmware. */
 			dev_err(info->dev, "Suspend to memory is not supported by the firmware\n");
 			return -EOPNOTSUPP;
 		}
@@ -4011,12 +4014,13 @@ static int ti_sci_probe(struct platform_device *pdev)
 	}
 
 	ti_sci_msg_cmd_query_fw_caps(&info->handle, &info->fw_caps);
-	dev_dbg(dev, "Detected firmware capabilities: %s%s%s%s%s\n",
+	dev_dbg(dev, "Detected firmware capabilities: %s%s%s%s%s%s\n",
 		info->fw_caps & MSG_FLAG_CAPS_GENERIC ? "Generic" : "",
 		info->fw_caps & MSG_FLAG_CAPS_LPM_PARTIAL_IO ? " Partial-IO" : "",
 		info->fw_caps & MSG_FLAG_CAPS_LPM_DM_MANAGED ? " DM-Managed" : "",
 		info->fw_caps & MSG_FLAG_CAPS_LPM_ABORT ? " LPM-Abort" : "",
-		info->fw_caps & MSG_FLAG_CAPS_IO_ISOLATION ? " IO-Isolation" : ""
+		info->fw_caps & MSG_FLAG_CAPS_IO_ISOLATION ? " IO-Isolation" : "",
+		info->fw_caps & MSG_FLAG_CAPS_LPM_BOARDCFG_MANAGED ? " BoardConfig-Managed" : ""
 	);
 
 	ti_sci_setup_ops(info);
diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h
index 91f234550c438..5f5c1ae7a19a8 100644
--- a/drivers/firmware/ti_sci.h
+++ b/drivers/firmware/ti_sci.h
@@ -150,6 +150,7 @@ struct ti_sci_msg_req_reboot {
  *		MSG_FLAG_CAPS_LPM_DM_MANAGED: LPM can be managed by DM
  *		MSG_FLAG_CAPS_LPM_ABORT: Abort entry to LPM
  *		MSG_FLAG_CAPS_IO_ISOLATION: IO Isolation support
+ *		MSG_FLAG_CAPS_LPM_BOARDCFG_MANAGED: LPM config done statically for the DM via boardcfg
  *
  * Response to a generic message with message type TI_SCI_MSG_QUERY_FW_CAPS
  * providing currently available SOC/firmware capabilities. SoC that don't
@@ -162,6 +163,7 @@ struct ti_sci_msg_resp_query_fw_caps {
 #define MSG_FLAG_CAPS_LPM_DM_MANAGED	TI_SCI_MSG_FLAG(5)
 #define MSG_FLAG_CAPS_LPM_ABORT		TI_SCI_MSG_FLAG(9)
 #define MSG_FLAG_CAPS_IO_ISOLATION	TI_SCI_MSG_FLAG(7)
+#define MSG_FLAG_CAPS_LPM_BOARDCFG_MANAGED	TI_SCI_MSG_FLAG(10)
 #define MSG_MASK_CAPS_LPM		GENMASK_ULL(4, 1)
 	u64 fw_caps;
 } __packed;

-- 
2.51.0



From thomas.richard at bootlin.com  Fri Dec  5 06:28:24 2025
From: thomas.richard at bootlin.com (Thomas Richard (TI.com))
Date: Fri, 05 Dec 2025 15:28:24 +0100
Subject: [PATCH v3 2/4] firmware: ti_sci: handle IRQ restore in
 BOARDCFG_MANAGED mode during resume
In-Reply-To: <20251205-ti-sci-jacinto-s2r-restore-irq-v3-0-d06963974ad4@bootlin.com>
References: <20251205-ti-sci-jacinto-s2r-restore-irq-v3-0-d06963974ad4@bootlin.com>
Message-ID: <20251205-ti-sci-jacinto-s2r-restore-irq-v3-2-d06963974ad4@bootlin.com>

In BOARDCFG_MANAGED mode, the firmware cannot restore IRQs during
resume. This responsibility is delegated to the ti_sci driver,
which maintains an internal list of all requested IRQs. This list
is updated on each set/free operation, and all IRQs are restored
during the resume_noirq() phase.

Signed-off-by: Thomas Richard (TI.com) <thomas.richard at bootlin.com>
---
 drivers/firmware/ti_sci.c | 147 +++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 138 insertions(+), 9 deletions(-)

diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index d77b631d9c855..8d94745376e2a 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -12,6 +12,7 @@
 #include <linux/cpu.h>
 #include <linux/debugfs.h>
 #include <linux/export.h>
+#include <linux/hashtable.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/kernel.h>
@@ -87,6 +88,16 @@ struct ti_sci_desc {
 	int max_msg_size;
 };
 
+/**
+ * struct ti_sci_irq - Description of allocated irqs
+ * @node: Link to hash table
+ * @desc: Description of the irq
+ */
+struct ti_sci_irq {
+	struct hlist_node node;
+	struct ti_sci_msg_req_manage_irq desc;
+};
+
 /**
  * struct ti_sci_info - Structure representing a TI SCI instance
  * @dev:	Device pointer
@@ -101,6 +112,7 @@ struct ti_sci_desc {
  * @chan_rx:	Receive mailbox channel
  * @minfo:	Message info
  * @node:	list head
+ * @irqs:	List of allocated irqs
  * @host_id:	Host ID
  * @fw_caps:	FW/SoC low power capabilities
  * @users:	Number of users of this instance
@@ -117,6 +129,7 @@ struct ti_sci_info {
 	struct mbox_chan *chan_tx;
 	struct mbox_chan *chan_rx;
 	struct ti_sci_xfers_info minfo;
+	DECLARE_HASHTABLE(irqs, 8);
 	struct list_head node;
 	u8 host_id;
 	u64 fw_caps;
@@ -2301,6 +2314,32 @@ static int ti_sci_manage_irq(const struct ti_sci_handle *handle,
 	return ret;
 }
 
+/**
+ * ti_sci_irq_hash() - Helper API to compute irq hash for the hash table.
+ * @irq:	irq to hash
+ *
+ * Return: the computed hash value.
+ */
+static int ti_sci_irq_hash(struct ti_sci_msg_req_manage_irq *irq)
+{
+	return irq->src_id ^ irq->src_index;
+}
+
+/**
+ * ti_sci_irq_equal() - Helper API to compare two irqs (generic headers are not
+ *                       compared)
+ * @irq_a:	irq_a to compare
+ * @irq_b:	irq_b to compare
+ *
+ * Return: true if the two irqs are equal, else false.
+ */
+static bool ti_sci_irq_equal(struct ti_sci_msg_req_manage_irq *irq_a,
+			     struct ti_sci_msg_req_manage_irq *irq_b)
+{
+	return !memcmp(&irq_a->valid_params, &irq_b->valid_params,
+		       sizeof(*irq_a) - sizeof(irq_a->hdr));
+}
+
 /**
  * ti_sci_set_irq() - Helper api to configure the irq route between the
  *		      requested source and destination
@@ -2324,15 +2363,43 @@ static int ti_sci_set_irq(const struct ti_sci_handle *handle, u32 valid_params,
 			  u16 dst_host_irq, u16 ia_id, u16 vint,
 			  u16 global_event, u8 vint_status_bit, u8 s_host)
 {
+	struct ti_sci_info *info = handle_to_ti_sci_info(handle);
+	struct ti_sci_msg_req_manage_irq *desc;
+	struct ti_sci_irq *irq;
+	int ret;
+
 	pr_debug("%s: IRQ set with valid_params = 0x%x from src = %d, index = %d, to dst = %d, irq = %d,via ia_id = %d, vint = %d, global event = %d,status_bit = %d\n",
 		 __func__, valid_params, src_id, src_index,
 		 dst_id, dst_host_irq, ia_id, vint, global_event,
 		 vint_status_bit);
 
-	return ti_sci_manage_irq(handle, valid_params, src_id, src_index,
-				 dst_id, dst_host_irq, ia_id, vint,
-				 global_event, vint_status_bit, s_host,
-				 TI_SCI_MSG_SET_IRQ);
+	ret = ti_sci_manage_irq(handle, valid_params, src_id, src_index,
+				dst_id, dst_host_irq, ia_id, vint,
+				global_event, vint_status_bit, s_host,
+				TI_SCI_MSG_SET_IRQ);
+
+	if (ret)
+		return ret;
+
+	irq = kzalloc(sizeof(*irq), GFP_KERNEL);
+	if (!irq)
+		return -ENOMEM;
+
+	desc = &irq->desc;
+	desc->valid_params = valid_params;
+	desc->src_id = src_id;
+	desc->src_index = src_index;
+	desc->dst_id = dst_id;
+	desc->dst_host_irq = dst_host_irq;
+	desc->ia_id = ia_id;
+	desc->vint = vint;
+	desc->global_event = global_event;
+	desc->vint_status_bit = vint_status_bit;
+	desc->secondary_host = s_host;
+
+	hash_add(info->irqs, &irq->node, ti_sci_irq_hash(desc));
+
+	return 0;
 }
 
 /**
@@ -2358,15 +2425,46 @@ static int ti_sci_free_irq(const struct ti_sci_handle *handle, u32 valid_params,
 			   u16 dst_host_irq, u16 ia_id, u16 vint,
 			   u16 global_event, u8 vint_status_bit, u8 s_host)
 {
+	struct ti_sci_info *info = handle_to_ti_sci_info(handle);
+	struct ti_sci_msg_req_manage_irq irq_desc;
+	struct ti_sci_irq *this_irq;
+	struct hlist_node *tmp_node;
+	int ret;
+
 	pr_debug("%s: IRQ release with valid_params = 0x%x from src = %d, index = %d, to dst = %d, irq = %d,via ia_id = %d, vint = %d, global event = %d,status_bit = %d\n",
 		 __func__, valid_params, src_id, src_index,
 		 dst_id, dst_host_irq, ia_id, vint, global_event,
 		 vint_status_bit);
 
-	return ti_sci_manage_irq(handle, valid_params, src_id, src_index,
-				 dst_id, dst_host_irq, ia_id, vint,
-				 global_event, vint_status_bit, s_host,
-				 TI_SCI_MSG_FREE_IRQ);
+	ret = ti_sci_manage_irq(handle, valid_params, src_id, src_index,
+				dst_id, dst_host_irq, ia_id, vint,
+				global_event, vint_status_bit, s_host,
+				TI_SCI_MSG_FREE_IRQ);
+
+	if (ret)
+		return ret;
+
+	irq_desc.valid_params = valid_params;
+	irq_desc.src_id = src_id;
+	irq_desc.src_index = src_index;
+	irq_desc.dst_id = dst_id;
+	irq_desc.dst_host_irq = dst_host_irq;
+	irq_desc.ia_id = ia_id;
+	irq_desc.vint = vint;
+	irq_desc.global_event = global_event;
+	irq_desc.vint_status_bit = vint_status_bit;
+	irq_desc.secondary_host = s_host;
+
+	hash_for_each_possible_safe(info->irqs, this_irq, tmp_node, node,
+				    ti_sci_irq_hash(&irq_desc)) {
+		if (ti_sci_irq_equal(&irq_desc, &this_irq->desc)) {
+			hlist_del(&this_irq->node);
+			kfree(this_irq);
+			return 0;
+		}
+	}
+
+	return 0;
 }
 
 /**
@@ -3847,7 +3945,10 @@ static int ti_sci_suspend_noirq(struct device *dev)
 static int ti_sci_resume_noirq(struct device *dev)
 {
 	struct ti_sci_info *info = dev_get_drvdata(dev);
-	int ret = 0;
+	struct ti_sci_msg_req_manage_irq *irq_desc;
+	struct ti_sci_irq *irq;
+	struct hlist_node *tmp_node;
+	int ret = 0, i;
 	u32 source;
 	u64 time;
 	u8 pin;
@@ -3859,6 +3960,32 @@ static int ti_sci_resume_noirq(struct device *dev)
 			return ret;
 	}
 
+	switch (pm_suspend_target_state) {
+	case PM_SUSPEND_MEM:
+		if (info->fw_caps & MSG_FLAG_CAPS_LPM_BOARDCFG_MANAGED) {
+			hash_for_each_safe(info->irqs, i, tmp_node, irq, node) {
+				irq_desc = &irq->desc;
+				ret = ti_sci_manage_irq(&info->handle,
+							irq_desc->valid_params,
+							irq_desc->src_id,
+							irq_desc->src_index,
+							irq_desc->dst_id,
+							irq_desc->dst_host_irq,
+							irq_desc->ia_id,
+							irq_desc->vint,
+							irq_desc->global_event,
+							irq_desc->vint_status_bit,
+							irq_desc->secondary_host,
+							TI_SCI_MSG_SET_IRQ);
+				if (ret)
+					return ret;
+			}
+		}
+		break;
+	default:
+		break;
+	}
+
 	ret = ti_sci_msg_cmd_lpm_wake_reason(&info->handle, &source, &time, &pin, &mode);
 	/* Do not fail to resume on error as the wake reason is not critical */
 	if (!ret)
@@ -4053,6 +4180,8 @@ static int ti_sci_probe(struct platform_device *pdev)
 	list_add_tail(&info->node, &ti_sci_list);
 	mutex_unlock(&ti_sci_list_mutex);
 
+	hash_init(info->irqs);
+
 	ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
 	if (ret) {
 		dev_err(dev, "platform_populate failed %pe\n", ERR_PTR(ret));

-- 
2.51.0



From thomas.richard at bootlin.com  Fri Dec  5 06:28:25 2025
From: thomas.richard at bootlin.com (Thomas Richard (TI.com))
Date: Fri, 05 Dec 2025 15:28:25 +0100
Subject: [PATCH v3 3/4] clk: keystone: sci-clk: add restore_context()
 operation
In-Reply-To: <20251205-ti-sci-jacinto-s2r-restore-irq-v3-0-d06963974ad4@bootlin.com>
References: <20251205-ti-sci-jacinto-s2r-restore-irq-v3-0-d06963974ad4@bootlin.com>
Message-ID: <20251205-ti-sci-jacinto-s2r-restore-irq-v3-3-d06963974ad4@bootlin.com>

Implement the restore_context() operation to restore the clock rate and the
clock parent state. The clock rate is saved in sci_clk struct during
set_rate() operation. The parent index is saved in sci_clk struct during
set_parent() operation. During clock registration, the core retrieves each
clock?s parent using get_parent() operation to ensure the internal clock
tree reflects the actual hardware state, including any configurations made
by the bootloader. So we also save the parent index in get_parent().

Signed-off-by: Thomas Richard (TI.com) <thomas.richard at bootlin.com>
---
 drivers/clk/keystone/sci-clk.c | 42 ++++++++++++++++++++++++++++++++++--------
 1 file changed, 34 insertions(+), 8 deletions(-)

diff --git a/drivers/clk/keystone/sci-clk.c b/drivers/clk/keystone/sci-clk.c
index 9d5071223f4cb..428050a05de31 100644
--- a/drivers/clk/keystone/sci-clk.c
+++ b/drivers/clk/keystone/sci-clk.c
@@ -47,6 +47,8 @@ struct sci_clk_provider {
  * @node:	 Link for handling clocks probed via DT
  * @cached_req:	 Cached requested freq for determine rate calls
  * @cached_res:	 Cached result freq for determine rate calls
+ * @parent_id:	 Parent index for this clock
+ * @rate:	 Clock rate
  */
 struct sci_clk {
 	struct clk_hw hw;
@@ -58,6 +60,8 @@ struct sci_clk {
 	struct list_head node;
 	unsigned long cached_req;
 	unsigned long cached_res;
+	u8 parent_id;
+	unsigned long rate;
 };
 
 #define to_sci_clk(_hw) container_of(_hw, struct sci_clk, hw)
@@ -210,10 +214,16 @@ static int sci_clk_set_rate(struct clk_hw *hw, unsigned long rate,
 			    unsigned long parent_rate)
 {
 	struct sci_clk *clk = to_sci_clk(hw);
+	int ret;
+
+	ret = clk->provider->ops->set_freq(clk->provider->sci, clk->dev_id,
+					   clk->clk_id, rate / 10 * 9, rate,
+					   rate / 10 * 11);
 
-	return clk->provider->ops->set_freq(clk->provider->sci, clk->dev_id,
-					    clk->clk_id, rate / 10 * 9, rate,
-					    rate / 10 * 11);
+	if (!ret)
+		clk->rate = rate;
+
+	return ret;
 }
 
 /**
@@ -237,9 +247,9 @@ static u8 sci_clk_get_parent(struct clk_hw *hw)
 		return 0;
 	}
 
-	parent_id = parent_id - clk->clk_id - 1;
+	clk->parent_id = (u8)(parent_id - clk->clk_id - 1);
 
-	return (u8)parent_id;
+	return clk->parent_id;
 }
 
 /**
@@ -252,12 +262,27 @@ static u8 sci_clk_get_parent(struct clk_hw *hw)
 static int sci_clk_set_parent(struct clk_hw *hw, u8 index)
 {
 	struct sci_clk *clk = to_sci_clk(hw);
+	int ret;
 
 	clk->cached_req = 0;
 
-	return clk->provider->ops->set_parent(clk->provider->sci, clk->dev_id,
-					      clk->clk_id,
-					      index + 1 + clk->clk_id);
+	ret = clk->provider->ops->set_parent(clk->provider->sci, clk->dev_id,
+					     clk->clk_id,
+					     index + 1 + clk->clk_id);
+	if (!ret)
+		clk->parent_id = index;
+
+	return ret;
+}
+
+static void sci_clk_restore_context(struct clk_hw *hw)
+{
+	struct sci_clk *clk = to_sci_clk(hw);
+
+	sci_clk_set_parent(hw, clk->parent_id);
+
+	if (clk->rate)
+		sci_clk_set_rate(hw, clk->rate, 0);
 }
 
 static const struct clk_ops sci_clk_ops = {
@@ -269,6 +294,7 @@ static const struct clk_ops sci_clk_ops = {
 	.set_rate = sci_clk_set_rate,
 	.get_parent = sci_clk_get_parent,
 	.set_parent = sci_clk_set_parent,
+	.restore_context = sci_clk_restore_context,
 };
 
 /**

-- 
2.51.0



From thomas.richard at bootlin.com  Fri Dec  5 06:28:26 2025
From: thomas.richard at bootlin.com (Thomas Richard (TI.com))
Date: Fri, 05 Dec 2025 15:28:26 +0100
Subject: [PATCH v3 4/4] firmware: ti_sci: restore clock context during
 resume in BOARDCFG_MANAGED mode
In-Reply-To: <20251205-ti-sci-jacinto-s2r-restore-irq-v3-0-d06963974ad4@bootlin.com>
References: <20251205-ti-sci-jacinto-s2r-restore-irq-v3-0-d06963974ad4@bootlin.com>
Message-ID: <20251205-ti-sci-jacinto-s2r-restore-irq-v3-4-d06963974ad4@bootlin.com>

In BOARDCFG_MANAGED mode, the firmware cannot restore the clock rates and
the clock parents. This responsibility is therefore delegated to the ti_sci
driver, which uses clk_restore_context() to trigger the context_restore()
operation for all registered clocks, including those managed by the sci-clk
driver. The sci-clk driver implements the context_restore() operation to
ensure rates and clock parents are correctly restored.

Signed-off-by: Thomas Richard (TI.com) <thomas.richard at bootlin.com>
---
 drivers/firmware/ti_sci.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index 8d94745376e2a..6ef687e481c49 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -9,6 +9,7 @@
 #define pr_fmt(fmt) "%s: " fmt, __func__
 
 #include <linux/bitmap.h>
+#include <linux/clk.h>
 #include <linux/cpu.h>
 #include <linux/debugfs.h>
 #include <linux/export.h>
@@ -3980,6 +3981,8 @@ static int ti_sci_resume_noirq(struct device *dev)
 				if (ret)
 					return ret;
 			}
+
+			clk_restore_context();
 		}
 		break;
 	default:

-- 
2.51.0



From richardcochran at gmail.com  Fri Dec  5 06:38:01 2025
From: richardcochran at gmail.com (Richard Cochran)
Date: Fri, 5 Dec 2025 06:38:01 -0800
Subject: [PATCH net v2] net: stmmac: Fix E2E delay mechanism
In-Reply-To: <aTFuJUiLMnHrnpW5@shell.armlinux.org.uk>
References: <20251129-ext-ptp-2v-v2-1-d23aca3e694f@altera.com>
 <26656845-d9d6-4fd2-bfff-99996cf03741@redhat.com>
 <aTFuJUiLMnHrnpW5@shell.armlinux.org.uk>
Message-ID: <aTLuSZugpZDNCRzf@hoboy.vegasvil.org>

On Thu, Dec 04, 2025 at 11:19:01AM +0000, Russell King (Oracle) wrote:

> Basically, the conclusion I am coming to is that Synopsys's idea
> of "lets tell the hardware what _kind_ of PTP clock we want to be,
> whether we're master, etc" is subject to multiple revisions in
> terms of which messages each mode selects, and it would have been
> _far_ simpler and easier to understand had they just provided a
> 16-bit bitfield of message types to accept.

Encoding the PTP role in the hardware is a fundamentally stupid idea,
because it makes changing roles (which is a normal and expected)
impossible without losing time stamps during the transition.  Some
early PTP hardware designs had this defect, but vendors figured it out
in the second generation of cards.

Thanks,
Richard


From robh at kernel.org  Fri Dec  5 06:49:29 2025
From: robh at kernel.org (Rob Herring)
Date: Fri, 5 Dec 2025 08:49:29 -0600
Subject: [PATCH v3 3/3] dt-bindings: hwmon: (aspeed,g5-pwm-tacho) Move
 info from txt to yaml
In-Reply-To: <20251204210238.40742-4-rebecca@bsdio.com>
References: <20251204210238.40742-1-rebecca@bsdio.com>
 <20251204210238.40742-4-rebecca@bsdio.com>
Message-ID: <20251205144929.GA76422-robh@kernel.org>

On Thu, Dec 04, 2025 at 02:02:36PM -0700, Rebecca Cran wrote:
> Move the documentation for the aspeed,ast2400-pwm-tacho and
> aspeed,ast2500-pwm-tacho devices from a text file to yaml file.
> 
> This allows for dts files containing these devices to be validated.
> 
> Where the text file documenation of required properties differ from the
> implementation, prefer the implementation and update the schema to
> match.
> 
> "#size-cells" was 1 but implementation is 0.
> "#cooling-cells" was marked as required but appears optional.
> 
> In the fan subnode, "cooling-levels" is optional according to the code
> in drivers/hwmon/aspeed-pwm-tacho.c.

Please see this one:

https://lore.kernel.org/all/20251029185448.2121857-1-robh at kernel.org/

> 
> Signed-off-by: Rebecca Cran <rebecca at bsdio.com>
> ---
>  Documentation/devicetree/bindings/hwmon/aspeed,pwm-tacho.yaml | 91 ++++++++++++++++++++
>  Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt  | 73 ----------------
>  2 files changed, 91 insertions(+), 73 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/hwmon/aspeed,pwm-tacho.yaml b/Documentation/devicetree/bindings/hwmon/aspeed,pwm-tacho.yaml
> new file mode 100644
> index 000000000000..b23c3519604b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/hwmon/aspeed,pwm-tacho.yaml
> @@ -0,0 +1,91 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +# Copyright (C) 2023 Aspeed, Inc.
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/hwmon/aspeed,g5-pwm-tacho.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: ASPEED AST2400/AST2500 PWM and Fan Tacho controller
> +
> +maintainers:
> +  - Billy Tsai <billy_tsai at aspeedtech.com>
> +
> +description: |
> +  The ASPEED PWM controller can support up to 8 PWM outputs. The ASPEED Fan
> +  Tacho controller can support up to 16 Fan tachometer inputs.
> +
> +  There can be up to 8 fans supported. Each fan can have one PWM output and
> +  one/two Fan tach inputs.
> +
> +properties:
> +  compatible:
> +    enum:
> +      - aspeed,ast2400-pwm-tacho
> +      - aspeed,ast2500-pwm-tacho
> +
> +  "#address-cells":
> +    const: 1
> +
> +  "#size-cells":
> +    const: 0
> +
> +  reg:
> +    maxItems: 1
> +
> +  clocks:
> +    maxItems: 1
> +
> +  resets:
> +    maxItems: 1
> +
> +patternProperties:
> +  "^fan@[0-9]+$":
> +    $ref: fan-common.yaml#
> +    unevaluatedProperties: false
> +    properties:
> +      aspeed,fan-tach-ch:
> +        description:
> +          The tach channel used for the fan.
> +        $ref: /schemas/types.yaml#/definitions/uint8-array
> +
> +    required:
> +      - reg
> +      - aspeed,fan-tach-ch
> +
> +required:
> +  - compatible
> +  - "#address-cells"
> +  - "#size-cells"
> +  - reg
> +  - pinctrl-names
> +  - pinctrl-0
> +  - clocks
> +  - resets
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/clock/aspeed-clock.h>
> +    pwm_tacho: pwmtachocontroller at 1e786000 {
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +        #cooling-cells = <2>;
> +        reg = <0x1E786000 0x1000>;
> +        compatible = "aspeed,ast2500-pwm-tacho";
> +        clocks = <&syscon ASPEED_CLK_APB>;
> +        resets = <&syscon ASPEED_RESET_PWM>;
> +        pinctrl-names = "default";
> +        pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default>;
> +
> +        fan at 0 {
> +                reg = <0x00>;
> +                cooling-levels = /bits/ 8 <125 151 177 203 229 255>;
> +                aspeed,fan-tach-ch = /bits/ 8 <0x00>;
> +        };
> +
> +        fan at 1 {
> +                reg = <0x01>;
> +                aspeed,fan-tach-ch = /bits/ 8 <0x01 0x02>;
> +        };
> +    };
> diff --git a/Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt b/Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt
> deleted file mode 100644
> index 8645cd3b867a..000000000000
> --- a/Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt
> +++ /dev/null
> @@ -1,73 +0,0 @@
> -ASPEED AST2400/AST2500 PWM and Fan Tacho controller device driver
> -
> -The ASPEED PWM controller can support upto 8 PWM outputs. The ASPEED Fan Tacho
> -controller can support upto 16 Fan tachometer inputs.
> -
> -There can be upto 8 fans supported. Each fan can have one PWM output and
> -one/two Fan tach inputs.
> -
> -Required properties for pwm-tacho node:
> -- #address-cells : should be 1.
> -
> -- #size-cells : should be 1.
> -
> -- #cooling-cells: should be 2.
> -
> -- reg : address and length of the register set for the device.
> -
> -- pinctrl-names : a pinctrl state named "default" must be defined.
> -
> -- pinctrl-0 : phandle referencing pin configuration of the PWM ports.
> -
> -- compatible : should be "aspeed,ast2400-pwm-tacho" for AST2400 and
> -	       "aspeed,ast2500-pwm-tacho" for AST2500.
> -
> -- clocks : phandle to clock provider with the clock number in the second cell
> -
> -- resets : phandle to reset controller with the reset number in the second cell
> -
> -fan subnode format:
> -===================
> -Under fan subnode there can upto 8 child nodes, with each child node
> -representing a fan. If there are 8 fans each fan can have one PWM port and
> -one/two Fan tach inputs.
> -For PWM port can be configured cooling-levels to create cooling device.
> -Cooling device could be bound to a thermal zone for the thermal control.
> -
> -Required properties for each child node:
> -- reg : should specify PWM source port.
> -	integer value in the range 0 to 7 with 0 indicating PWM port A and
> -	7 indicating PWM port H.
> -
> -- cooling-levels: PWM duty cycle values in a range from 0 to 255
> -                  which correspond to thermal cooling states.
> -
> -- aspeed,fan-tach-ch : should specify the Fan tach input channel.
> -                integer value in the range 0 through 15, with 0 indicating
> -		Fan tach channel 0 and 15 indicating Fan tach channel 15.
> -		At least one Fan tach input channel is required.
> -
> -Examples:
> -
> -pwm_tacho: pwmtachocontroller at 1e786000 {
> -	#address-cells = <1>;
> -	#size-cells = <1>;
> -	#cooling-cells = <2>;
> -	reg = <0x1E786000 0x1000>;
> -	compatible = "aspeed,ast2500-pwm-tacho";
> -	clocks = <&syscon ASPEED_CLK_APB>;
> -	resets = <&syscon ASPEED_RESET_PWM>;
> -	pinctrl-names = "default";
> -	pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default>;
> -
> -	fan at 0 {
> -		reg = <0x00>;
> -		cooling-levels = /bits/ 8 <125 151 177 203 229 255>;
> -		aspeed,fan-tach-ch = /bits/ 8 <0x00>;
> -	};
> -
> -	fan at 1 {
> -		reg = <0x01>;
> -		aspeed,fan-tach-ch = /bits/ 8 <0x01 0x02>;
> -	};
> -};
> -- 
> 2.47.3
> 


From afd at ti.com  Fri Dec  5 06:58:26 2025
From: afd at ti.com (Andrew Davis)
Date: Fri, 5 Dec 2025 08:58:26 -0600
Subject: [PATCH v4] dt-bindings: arm: keystone: add boot_* mboxes to
 ti,sci
In-Reply-To: <20251205-k3_syscon_add_boot_mailboxes-v4-1-8e216fb88941@ti.com>
References: <20251205-k3_syscon_add_boot_mailboxes-v4-1-8e216fb88941@ti.com>
Message-ID: <533a5027-0942-41e3-87c6-bfef4a98ebcb@ti.com>

On 12/5/25 12:15 AM, Anshul Dalal wrote:
> The bootloader on K3 devices makes use of mailboxes as per the ROM spec
> which might be different than one's available to the kernel (firmware
> spec).
> 

See this was the part that confused me earlier into thinking this was
for different processing elements. But really even the same processor
could need both sets of mailboxes, pre and post loading the SCI firmware.
It isn't about "boot" vs "kernel", it is "ROM" vs "Firmware".

How about instead of boot_* you call them rom_*? Or at very least update
this commit message and the "description" in the schema to not simply
say "boot stage".

> Therefore, this patch adds the missing mailbox entries to the DT binding
> if the matching compatible is ti,am654-sci to represent the mailboxes
> exposed by the hardware during boot for the purpose of loading the
> firmware.
> 
> Signed-off-by: Anshul Dalal <anshuld at ti.com>
> ---
> Changes in v4:
> - Make new boot_* mboxes conditional on ti,am654-sci compatible
> - Link to v3: https://lore.kernel.org/r/20251112-k3_syscon_add_boot_mailboxes-v3-1-66155a4236dc at ti.com
> 
> Changes in v3:
> - Drop [1/2] of the last patch series
> - Update existing example with boot_* mailboxes instead of adding a new one
> - Link to v2: https://lore.kernel.org/r/20251112-k3_syscon_add_boot_mailboxes-v2-0-aebc1e47b391 at ti.com
> 
> Changes in v2:
> - Remove maxItems entry
> - Remove RFC tag from patch (added by mistake in v1)
> - Document the new mailboxes in mboxes instead of mbox-names
> - Provide example with all the mailboxes set
> - Update commit title to have "ti,sci"
> - Split into two patches
> - Link to v1: https://lore.kernel.org/r/20251111-k3_syscon_add_boot_mailboxes-v1-1-529a27f21076 at ti.com
> ---
>   .../devicetree/bindings/arm/keystone/ti,sci.yaml   | 50 +++++++++++++++++++---
>   1 file changed, 43 insertions(+), 7 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
> index 25a2b42105e5..d9eb2a81e539 100644
> --- a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
> +++ b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
> @@ -51,15 +51,15 @@ properties:
>       minItems: 1
>   
>     mbox-names:
> +    minItems: 2
> +    maxItems: 6

This doesn't seem right, why add these here when you set the exact
items allowed down below in the if/then block?

>       description: |
>         Specifies the mailboxes used to communicate with TI-SCI Controller
>         made available from TI-SCI controller.
> -    items:
> -      - const: rx
> -      - const: tx
>   
>     mboxes:
>       minItems: 2
> +    maxItems: 6
>   
>     ti,host-id:
>       $ref: /schemas/types.yaml#/definitions/uint32
> @@ -79,6 +79,42 @@ properties:
>       type: object
>       $ref: /schemas/reset/ti,sci-reset.yaml#
>   
> +if:
> +  properties:
> +    compatible:
> +      contains:
> +        const: ti,am654-sci
> +then:
> +  properties:
> +    mbox-names:
> +      minItems: 2

If you are listing 6 items, then the number needed is exactly 6, no
need for a minimum less than that. I also think this is enforced without
needing to set min/max if you list the items explicitly.

> +      items:
> +        - const: rx
> +        - const: tx
> +        - const: notify
> +        - const: boot_rx
> +        - const: boot_tx
> +        - const: boot_notify
> +    mboxes:
> +      minItems: 2
> +      items:
> +        - description: RX thread
> +        - description: TX thread
> +        - description: Notify thread
> +        - description: boot stage RX thread
> +        - description: boot stage TX thread
> +        - description: boot stage Notify thread
> +else:
> +  properties:
> +    mbox-names:
> +      items:
> +        - const: rx
> +        - const: tx
> +    mboxes:
> +      items:
> +        - description: RX thread
> +        - description: TX thread
> +
>   required:
>     - compatible
>     - mbox-names
> @@ -99,11 +135,11 @@ examples:
>   
>     - |
>       dmsc: system-controller at 44083000 {
> -      compatible = "ti,k2g-sci";
> +      compatible = "ti,am654-sci";
>         ti,host-id = <12>;
> -      mbox-names = "rx", "tx";
> -      mboxes = <&secure_proxy_main 11>,
> -               <&secure_proxy_main 13>;
> +      mbox-names = "rx", "tx", "notify", "boot_rx", "boot_tx";
> +      mboxes= <&secure_proxy_mcu 6>, <&secure_proxy_mcu 8>,
> +        <&secure_proxy_mcu 5>, <&secure_proxy_mcu 5>, <&secure_proxy_mcu 4>;

nit, how about:

     mboxes= <&secure_proxy_mcu 6>,
             <&secure_proxy_mcu 8>,
             <&secure_proxy_mcu 5>,
             <&secure_proxy_mcu 5>,
             <&secure_proxy_mcu 4>;

Much easier to parse out the mailbox numbers visually. And to notice
you only have 5 items, but you list 6 in the schema, where is boot_notify?

Andrew

>         reg-names = "debug_messages";
>         reg = <0x44083000 0x1000>;
>   
> 
> ---
> base-commit: 4427259cc7f7571a157fbc9b5011e1ef6fe0a4a8
> change-id: 20251105-k3_syscon_add_boot_mailboxes-8452bdd98962
> 
> Best regards,



From broonie at kernel.org  Fri Dec  5 07:04:05 2025
From: broonie at kernel.org (Mark Brown)
Date: Fri, 5 Dec 2025 15:04:05 +0000
Subject: [PATCH 2/8] spi: stm32-ospi: Optimize FIFO accesses using u16 or
 u32
In-Reply-To: <20251205-upstream_qspi_ospi_updates-v1-2-7e6c8b9f5141@foss.st.com>
References: <20251205-upstream_qspi_ospi_updates-v1-0-7e6c8b9f5141@foss.st.com>
 <20251205-upstream_qspi_ospi_updates-v1-2-7e6c8b9f5141@foss.st.com>
Message-ID: <3c621482-ba56-4136-aabb-f7614568ecab@sirena.org.uk>

On Fri, Dec 05, 2025 at 10:04:52AM +0100, Patrice Chotard wrote:

>            before        after   gain
> Read :  5693 KiB/s  21139 KiB/s   371%
> Write:   765 KiB/s    910 KiB/s    19%

Nice!
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251205/f3db1fb2/attachment.sig>

From Frank.li at nxp.com  Fri Dec  5 07:07:34 2025
From: Frank.li at nxp.com (Frank Li)
Date: Fri, 5 Dec 2025 10:07:34 -0500
Subject: [PATCH v3 3/3] media: verisilicon: Avoid G2 bus error while
 decoding H.264 and HEVC
In-Reply-To: <b45a73845e66355080cfad0f0040b6e7a9d78241.camel@ndufresne.ca>
References: <20251204090813.595-1-ming.qian@oss.nxp.com>
 <20251204090813.595-3-ming.qian@oss.nxp.com>
 <aTHGJzVKa7PbEifJ@lizhi-Precision-Tower-5810>
 <9f38bda2f1753645a1ae392ce5364ea0165fdc01.camel@ndufresne.ca>
 <aTIRwcocnye0Y6yV@lizhi-Precision-Tower-5810>
 <b45a73845e66355080cfad0f0040b6e7a9d78241.camel@ndufresne.ca>
Message-ID: <aTL1NrZyeq8g/4Ft@lizhi-Precision-Tower-5810>

On Thu, Dec 04, 2025 at 07:05:01PM -0500, Nicolas Dufresne wrote:
> Le jeudi 04 d?cembre 2025 ? 17:57 -0500, Frank Li a ?crit?:
> > On Thu, Dec 04, 2025 at 01:15:35PM -0500, Nicolas Dufresne wrote:
> > > Hi Frank,
> > >
> > > Le jeudi 04 d?cembre 2025 ? 12:34 -0500, Frank Li a ?crit?:
> > > > > +static struct v4l2_m2m_dev *hantro_get_v4l2_m2m_dev(struct hantro_dev *vpu)
> > > > > +{
> > > > > +	struct device_node *node;
> > > > > +	struct hantro_dev *shared_vpu;
> > > > > +
> > > > > +	if (!vpu->variant || !vpu->variant->shared_devices)
> > > > > +		goto init_new_m2m_dev;
> > > >
> > > > I found only use shared_devices here, how to? ensure that g1 and g2 operate
> > > > alternately by using shared_devices?
> > >
> > > shared_devices is an array of of_device_id we match against. All the matching
> > > devices will share the same v4l2_m2m_dev (aka m2m scheduler). Typically, both
> > > cores will be schedule as one. This achieve what alternate operations without
> > > active polling or blocking locks/mutex.
> >
> > Okay, but this code require shared_devices==NULL's device probe firstly.
> > generally not order guaranteed, if there are not depentance at DT.
>
> shared_devices is a constant array that is set inside the variant. It is
> normally NULL, except for the imx8mq SoC, for which its always set.
>
> >
> > Does VPU always probe before g1/g2?
> >
> > and if there are two VPU instances, what's happen?
>
> Since there is two VPU, g1 and g2, we will enter this loop:
>
> > +	for_each_matching_node(node, vpu->variant->shared_devices) {
>
> On imx8mq, this will match twice.
>
> > +		struct platform_device *pdev;
> > +		struct v4l2_m2m_dev *m2m_dev;
> > +
> > +		pdev = of_find_device_by_node(node);
> > +		of_node_put(node);
> > +
> > +		if (!pdev)
> > +			continue;
>
> If the match does not have a device yet (not probe yet), we skip.
>
> > +
> > +		shared_vpu = platform_get_drvdata(pdev);
> > +		if (IS_ERR_OR_NULL(shared_vpu) || shared_vpu == vpu) {
> > +			platform_device_put(pdev);
> > +			continue;
> > +		}
>
> If its the current VPU, we also skip.
>
> > +
> > +		v4l2_m2m_get(shared_vpu->m2m_dev);
> > +		m2m_dev = shared_vpu->m2m_dev;
> > +		platform_device_put(pdev);
>
> Finally, if the other VPU was initialized, we ref the v4l2_m2m_dev. We will then
> create m2m_ctx from it which will cause the two VPU to be scheduled one after
> the other.
>
> > +
> > +		return m2m_dev;
> > +	}
>
> > +
> > +init_new_m2m_dev:
> > +	return v4l2_m2m_init(&vpu_m2m_ops);
>
> Otherwhise we create a fresh one.
>
> Does it make sense now ?

Yes, thanks for detial explain.

Frank

>
> Nicolas




From robh at kernel.org  Fri Dec  5 07:07:51 2025
From: robh at kernel.org (Rob Herring)
Date: Fri, 5 Dec 2025 09:07:51 -0600
Subject: [PATCH v6 1/4] dt-bindings: backlight: Add max25014 support
In-Reply-To: <20251201-max25014-v6-1-88e3ac8112ff@gocontroll.com>
References: <20251201-max25014-v6-0-88e3ac8112ff@gocontroll.com>
 <20251201-max25014-v6-1-88e3ac8112ff@gocontroll.com>
Message-ID: <20251205150751.GA124954-robh@kernel.org>

On Mon, Dec 01, 2025 at 12:53:20PM +0100, Maud Spierings wrote:
> The Maxim MAX25014 is a 4-channel automotive grade backlight driver IC
> with integrated boost controller.
>
> Signed-off-by: Maud Spierings <maudspierings at gocontroll.com>
> 
> ---
> 
> In the current implementation the control registers for channel 1,
> control all channels. So only one led subnode with led-sources is
> supported right now. If at some point the driver functionality is
> expanded the bindings can be easily extended with it.

What's the relationship between the LEDs and backlight? It's a backlight 
plus LEDs or just 4 identical channels.

> 
> ---
>  .../bindings/leds/backlight/maxim,max25014.yaml    | 107 +++++++++++++++++++++
>  MAINTAINERS                                        |   5 +
>  2 files changed, 112 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml b/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
> new file mode 100644
> index 000000000000..e83723224b07
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
> @@ -0,0 +1,107 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/leds/backlight/maxim,max25014.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Maxim max25014 backlight controller
> +
> +maintainers:
> +  - Maud Spierings <maudspierings at gocontroll.com>
> +
> +properties:
> +  compatible:
> +    enum:
> +      - maxim,max25014
> +
> +  reg:
> +    maxItems: 1
> +
> +  "#address-cells":
> +    const: 1
> +
> +  "#size-cells":
> +    const: 0
> +
> +  enable-gpios:
> +    maxItems: 1
> +
> +  interrupts:
> +    maxItems: 1
> +
> +  power-supply:
> +    description: Regulator which controls the boost converter input rail.
> +
> +  pwms:
> +    maxItems: 1
> +
> +  maxim,iset:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    maximum: 15
> +    default: 11
> +    description:
> +      Value of the ISET field in the ISET register. This controls the current
> +      scale of the outputs, a higher number means more current.

We have properties for setting the current (in uA). That can't work 
here?

> +
> +  led at 0:
> +    type: object
> +    description: Properties for a string of connected LEDs.
> +    $ref: common.yaml#
> +
> +    properties:
> +      reg:
> +        const: 0
> +
> +      led-sources:
> +        allOf:
> +          - minItems: 1
> +            maxItems: 4
> +            items:
> +              minimum: 0
> +              maximum: 3
> +            default: [0, 1, 2, 3]
> +
> +      default-brightness:
> +        minimum: 0
> +        maximum: 100
> +        default: 50
> +
> +    required:
> +      - reg
> +
> +    additionalProperties: false
> +
> +required:
> +  - compatible
> +  - reg
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/gpio/gpio.h>
> +    #include <dt-bindings/interrupt-controller/irq.h>
> +
> +    i2c {
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +
> +        backlight at 6f {
> +            compatible = "maxim,max25014";
> +            reg = <0x6f>;
> +            #address-cells = <1>;
> +            #size-cells = <0>;
> +            enable-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
> +            interrupt-parent = <&gpio1>;
> +            interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
> +            power-supply = <&reg_backlight>;
> +            pwms = <&pwm1>;
> +            maxim,iset = <7>;
> +
> +            led at 0 {
> +                reg = <0>;
> +                led-sources = <0 1 2 3>;
> +                default-brightness = <50>;
> +            };
> +        };
> +    };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 58c7e3f678d8..606ce086f758 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -15261,6 +15261,11 @@ F:	Documentation/userspace-api/media/drivers/max2175.rst
>  F:	drivers/media/i2c/max2175*
>  F:	include/uapi/linux/max2175.h
>  
> +MAX25014 BACKLIGHT DRIVER
> +M:	Maud Spierings <maudspierings at gocontroll.com>
> +S:	Maintained
> +F:	Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
> +
>  MAX31335 RTC DRIVER
>  M:	Antoniu Miclaus <antoniu.miclaus at analog.com>
>  L:	linux-rtc at vger.kernel.org
> 
> -- 
> 2.52.0
> 


From Frank.li at nxp.com  Fri Dec  5 07:08:06 2025
From: Frank.li at nxp.com (Frank Li)
Date: Fri, 5 Dec 2025 10:08:06 -0500
Subject: [PATCH v4 1/3] media: v4l2-mem2mem: Add a kref to the
 v4l2_m2m_dev structure
In-Reply-To: <20251205015428.643-2-ming.qian@oss.nxp.com>
References: <20251205015428.643-1-ming.qian@oss.nxp.com>
 <20251205015428.643-2-ming.qian@oss.nxp.com>
Message-ID: <aTL1VleoygCIap3N@lizhi-Precision-Tower-5810>

On Fri, Dec 05, 2025 at 09:54:24AM +0800, ming.qian at oss.nxp.com wrote:
> From: Nicolas Dufresne <nicolas.dufresne at collabora.com>
>
> Adding a reference count to the v4l2_m2m_dev structure allow safely
> sharing it across multiple hardware nodes. This can be used to prevent
> running jobs concurrently on m2m cores that have some internal resource
> sharing.
>
> Signed-off-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
> Signed-off-by: Ming Qian <ming.qian at oss.nxp.com>
> ---

Reviewed-by: Frank Li <Frank.Li at nxp.com>

> v4
> - Add my Signed-off-by
>
>  drivers/media/v4l2-core/v4l2-mem2mem.c | 23 +++++++++++++++++++++++
>  include/media/v4l2-mem2mem.h           | 21 +++++++++++++++++++++
>  2 files changed, 44 insertions(+)
>
> diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c
> index fec93c1a9231..ae0de54d4c3e 100644
> --- a/drivers/media/v4l2-core/v4l2-mem2mem.c
> +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
> @@ -90,6 +90,7 @@ static const char * const m2m_entity_name[] = {
>   * @job_work:		worker to run queued jobs.
>   * @job_queue_flags:	flags of the queue status, %QUEUE_PAUSED.
>   * @m2m_ops:		driver callbacks
> + * @kref:		device reference count
>   */
>  struct v4l2_m2m_dev {
>  	struct v4l2_m2m_ctx	*curr_ctx;
> @@ -109,6 +110,8 @@ struct v4l2_m2m_dev {
>  	unsigned long		job_queue_flags;
>
>  	const struct v4l2_m2m_ops *m2m_ops;
> +
> +	struct kref kref;
>  };
>
>  static struct v4l2_m2m_queue_ctx *get_queue_ctx(struct v4l2_m2m_ctx *m2m_ctx,
> @@ -1200,6 +1203,7 @@ struct v4l2_m2m_dev *v4l2_m2m_init(const struct v4l2_m2m_ops *m2m_ops)
>  	INIT_LIST_HEAD(&m2m_dev->job_queue);
>  	spin_lock_init(&m2m_dev->job_spinlock);
>  	INIT_WORK(&m2m_dev->job_work, v4l2_m2m_device_run_work);
> +	kref_init(&m2m_dev->kref);
>
>  	return m2m_dev;
>  }
> @@ -1211,6 +1215,25 @@ void v4l2_m2m_release(struct v4l2_m2m_dev *m2m_dev)
>  }
>  EXPORT_SYMBOL_GPL(v4l2_m2m_release);
>
> +void v4l2_m2m_get(struct v4l2_m2m_dev *m2m_dev)
> +{
> +	kref_get(&m2m_dev->kref);
> +}
> +EXPORT_SYMBOL_GPL(v4l2_m2m_get);
> +
> +static void v4l2_m2m_release_from_kref(struct kref *kref)
> +{
> +	struct v4l2_m2m_dev *m2m_dev = container_of(kref, struct v4l2_m2m_dev, kref);
> +
> +	v4l2_m2m_release(m2m_dev);
> +}
> +
> +void v4l2_m2m_put(struct v4l2_m2m_dev *m2m_dev)
> +{
> +	kref_put(&m2m_dev->kref, v4l2_m2m_release_from_kref);
> +}
> +EXPORT_SYMBOL_GPL(v4l2_m2m_put);
> +
>  struct v4l2_m2m_ctx *v4l2_m2m_ctx_init(struct v4l2_m2m_dev *m2m_dev,
>  		void *drv_priv,
>  		int (*queue_init)(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq))
> diff --git a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h
> index bf6a09a04dcf..ca295c660c7f 100644
> --- a/include/media/v4l2-mem2mem.h
> +++ b/include/media/v4l2-mem2mem.h
> @@ -547,6 +547,27 @@ v4l2_m2m_register_media_controller(struct v4l2_m2m_dev *m2m_dev,
>   */
>  void v4l2_m2m_release(struct v4l2_m2m_dev *m2m_dev);
>
> +/**
> + * v4l2_m2m_get() - take a reference to the m2m_dev structure
> + *
> + * @m2m_dev: opaque pointer to the internal data to handle M2M context
> + *
> + * This is used to share the M2M device across multiple devices. This
> + * can be used to avoid scheduling two hardware nodes concurrently.
> + */
> +void v4l2_m2m_get(struct v4l2_m2m_dev *m2m_dev);
> +
> +/**
> + * v4l2_m2m_put() - remove a reference to the m2m_dev structure
> + *
> + * @m2m_dev: opaque pointer to the internal data to handle M2M context
> + *
> + * Once the M2M device have no more references, v4l2_m2m_realse() will be
> + * called automatically. Users of this method should never call
> + * v4l2_m2m_release() directly. See v4l2_m2m_get() for more details.
> + */
> +void v4l2_m2m_put(struct v4l2_m2m_dev *m2m_dev);
> +
>  /**
>   * v4l2_m2m_ctx_init() - allocate and initialize a m2m context
>   *
> --
> 2.52.0
>


From Frank.li at nxp.com  Fri Dec  5 07:09:19 2025
From: Frank.li at nxp.com (Frank Li)
Date: Fri, 5 Dec 2025 10:09:19 -0500
Subject: [PATCH v4 3/3] media: verisilicon: Avoid G2 bus error while
 decoding H.264 and HEVC
In-Reply-To: <20251205015428.643-4-ming.qian@oss.nxp.com>
References: <20251205015428.643-1-ming.qian@oss.nxp.com>
 <20251205015428.643-4-ming.qian@oss.nxp.com>
Message-ID: <aTL1nzFxWl8zKUGD@lizhi-Precision-Tower-5810>

On Fri, Dec 05, 2025 at 09:54:26AM +0800, ming.qian at oss.nxp.com wrote:
> From: Ming Qian <ming.qian at oss.nxp.com>
>
> For the i.MX8MQ platform, there is a hardware limitation: the g1 VPU and
> g2 VPU cannot decode simultaneously; otherwise, it will cause below bus
> error and produce corrupted pictures, even potentially lead to system hang.
>
> [  110.527986] hantro-vpu 38310000.video-codec: frame decode timed out.
> [  110.583517] hantro-vpu 38310000.video-codec: bus error detected.
>
> Therefore, it is necessary to ensure that g1 and g2 operate alternately.
> This allows for successful multi-instance decoding of H.264 and HEVC.
>
> To achieve this, g1 and g2 share the same v4l2_m2m_dev, and then the
> v4l2_m2m_dev can handle the scheduling.
>
> Fixes: cb5dd5a0fa518 ("media: hantro: Introduce G2/HEVC decoder")
> Co-developed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
> Signed-off-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
> Signed-off-by: Ming Qian <ming.qian at oss.nxp.com>
> ---

Reviewed-by: Frank Li <Frank.Li at nxp.com>

> v4
> - Avoid double put device node in for_each_matching_node
> v3
> - Add some comments
> v2
> - Update commit message
>
>  drivers/media/platform/verisilicon/hantro.h   |  2 +
>  .../media/platform/verisilicon/hantro_drv.c   | 42 +++++++++++++++++--
>  .../media/platform/verisilicon/imx8m_vpu_hw.c |  8 ++++
>  3 files changed, 49 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/media/platform/verisilicon/hantro.h b/drivers/media/platform/verisilicon/hantro.h
> index e0fdc4535b2d..0353de154a1e 100644
> --- a/drivers/media/platform/verisilicon/hantro.h
> +++ b/drivers/media/platform/verisilicon/hantro.h
> @@ -77,6 +77,7 @@ struct hantro_irq {
>   * @double_buffer:		core needs double buffering
>   * @legacy_regs:		core uses legacy register set
>   * @late_postproc:		postproc must be set up at the end of the job
> + * @shared_devices:		an array of device ids that cannot run concurrently
>   */
>  struct hantro_variant {
>  	unsigned int enc_offset;
> @@ -101,6 +102,7 @@ struct hantro_variant {
>  	unsigned int double_buffer : 1;
>  	unsigned int legacy_regs : 1;
>  	unsigned int late_postproc : 1;
> +	const struct of_device_id *shared_devices;
>  };
>
>  /**
> diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c
> index 60b95b5d8565..94f58f4e4a4e 100644
> --- a/drivers/media/platform/verisilicon/hantro_drv.c
> +++ b/drivers/media/platform/verisilicon/hantro_drv.c
> @@ -13,6 +13,7 @@
>  #include <linux/clk.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
> +#include <linux/of_platform.h>
>  #include <linux/platform_device.h>
>  #include <linux/pm.h>
>  #include <linux/pm_runtime.h>
> @@ -1035,6 +1036,41 @@ static int hantro_disable_multicore(struct hantro_dev *vpu)
>  	return 0;
>  }
>
> +static struct v4l2_m2m_dev *hantro_get_v4l2_m2m_dev(struct hantro_dev *vpu)
> +{
> +	struct device_node *node;
> +	struct hantro_dev *shared_vpu;
> +
> +	if (!vpu->variant || !vpu->variant->shared_devices)
> +		goto init_new_m2m_dev;
> +
> +	for_each_matching_node(node, vpu->variant->shared_devices) {
> +		struct platform_device *pdev;
> +		struct v4l2_m2m_dev *m2m_dev;
> +
> +		pdev = of_find_device_by_node(node);
> +		if (!pdev)
> +			continue;
> +
> +		shared_vpu = platform_get_drvdata(pdev);
> +		if (IS_ERR_OR_NULL(shared_vpu) || shared_vpu == vpu) {
> +			platform_device_put(pdev);
> +			continue;
> +		}
> +
> +		v4l2_m2m_get(shared_vpu->m2m_dev);
> +		m2m_dev = shared_vpu->m2m_dev;
> +		platform_device_put(pdev);
> +
> +		of_node_put(node);
> +
> +		return m2m_dev;
> +	}
> +
> +init_new_m2m_dev:
> +	return v4l2_m2m_init(&vpu_m2m_ops);
> +}
> +
>  static int hantro_probe(struct platform_device *pdev)
>  {
>  	const struct of_device_id *match;
> @@ -1186,7 +1222,7 @@ static int hantro_probe(struct platform_device *pdev)
>  	}
>  	platform_set_drvdata(pdev, vpu);
>
> -	vpu->m2m_dev = v4l2_m2m_init(&vpu_m2m_ops);
> +	vpu->m2m_dev = hantro_get_v4l2_m2m_dev(vpu);
>  	if (IS_ERR(vpu->m2m_dev)) {
>  		v4l2_err(&vpu->v4l2_dev, "Failed to init mem2mem device\n");
>  		ret = PTR_ERR(vpu->m2m_dev);
> @@ -1225,7 +1261,7 @@ static int hantro_probe(struct platform_device *pdev)
>  	hantro_remove_enc_func(vpu);
>  err_m2m_rel:
>  	media_device_cleanup(&vpu->mdev);
> -	v4l2_m2m_release(vpu->m2m_dev);
> +	v4l2_m2m_put(vpu->m2m_dev);
>  err_v4l2_unreg:
>  	v4l2_device_unregister(&vpu->v4l2_dev);
>  err_clk_unprepare:
> @@ -1248,7 +1284,7 @@ static void hantro_remove(struct platform_device *pdev)
>  	hantro_remove_dec_func(vpu);
>  	hantro_remove_enc_func(vpu);
>  	media_device_cleanup(&vpu->mdev);
> -	v4l2_m2m_release(vpu->m2m_dev);
> +	v4l2_m2m_put(vpu->m2m_dev);
>  	v4l2_device_unregister(&vpu->v4l2_dev);
>  	clk_bulk_unprepare(vpu->variant->num_clocks, vpu->clocks);
>  	reset_control_assert(vpu->resets);
> diff --git a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
> index 5be0e2e76882..6f8e43b7f157 100644
> --- a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
> +++ b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
> @@ -343,6 +343,12 @@ const struct hantro_variant imx8mq_vpu_variant = {
>  	.num_regs = ARRAY_SIZE(imx8mq_reg_names)
>  };
>
> +static const struct of_device_id imx8mq_vpu_shared_resources[] __initconst = {
> +	{ .compatible = "nxp,imx8mq-vpu-g1", },
> +	{ .compatible = "nxp,imx8mq-vpu-g2", },
> +	{ /* sentinel */ }
> +};
> +
>  const struct hantro_variant imx8mq_vpu_g1_variant = {
>  	.dec_fmts = imx8m_vpu_dec_fmts,
>  	.num_dec_fmts = ARRAY_SIZE(imx8m_vpu_dec_fmts),
> @@ -356,6 +362,7 @@ const struct hantro_variant imx8mq_vpu_g1_variant = {
>  	.num_irqs = ARRAY_SIZE(imx8mq_irqs),
>  	.clk_names = imx8mq_g1_clk_names,
>  	.num_clocks = ARRAY_SIZE(imx8mq_g1_clk_names),
> +	.shared_devices = imx8mq_vpu_shared_resources,
>  };
>
>  const struct hantro_variant imx8mq_vpu_g2_variant = {
> @@ -371,6 +378,7 @@ const struct hantro_variant imx8mq_vpu_g2_variant = {
>  	.num_irqs = ARRAY_SIZE(imx8mq_g2_irqs),
>  	.clk_names = imx8mq_g2_clk_names,
>  	.num_clocks = ARRAY_SIZE(imx8mq_g2_clk_names),
> +	.shared_devices = imx8mq_vpu_shared_resources,
>  };
>
>  const struct hantro_variant imx8mm_vpu_g1_variant = {
> --
> 2.52.0
>


From Frank.li at nxp.com  Fri Dec  5 07:12:09 2025
From: Frank.li at nxp.com (Frank Li)
Date: Fri, 5 Dec 2025 10:12:09 -0500
Subject: [PATCH v2 2/3] usb: dwc3: imx8mp: rename dwc3 to dwc3_pdev in
 struct dwc3_imx8mp
In-Reply-To: <20251205032942.2259671-2-xu.yang_2@nxp.com>
References: <20251205032942.2259671-1-xu.yang_2@nxp.com>
 <20251205032942.2259671-2-xu.yang_2@nxp.com>
Message-ID: <aTL2ScHJNTjj9AU3@lizhi-Precision-Tower-5810>

On Fri, Dec 05, 2025 at 11:29:41AM +0800, Xu Yang wrote:
> It's confuse to let "dwc3" represent a platform_device, because "dwc3"
> may also represent a dwc3 core structure. Rename it for better
> distinction.
>
> Signed-off-by: Xu Yang <xu.yang_2 at nxp.com>
>

Reviewed-by: Frank Li <Frank.Li at nxp.com>

> ---
> Changes in v2:
>  - new patch
> ---
>  drivers/usb/dwc3/dwc3-imx8mp.c | 16 ++++++++--------
>  1 file changed, 8 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/usb/dwc3/dwc3-imx8mp.c b/drivers/usb/dwc3/dwc3-imx8mp.c
> index 050da327f785..8bece4baecbf 100644
> --- a/drivers/usb/dwc3/dwc3-imx8mp.c
> +++ b/drivers/usb/dwc3/dwc3-imx8mp.c
> @@ -51,7 +51,7 @@
>
>  struct dwc3_imx8mp {
>  	struct device			*dev;
> -	struct platform_device		*dwc3;
> +	struct platform_device		*dwc3_pdev;
>  	void __iomem			*hsio_blk_base;
>  	void __iomem			*glue_base;
>  	struct clk			*hsio_clk;
> @@ -100,7 +100,7 @@ static void imx8mp_configure_glue(struct dwc3_imx8mp *dwc3_imx)
>  static void dwc3_imx8mp_wakeup_enable(struct dwc3_imx8mp *dwc3_imx,
>  				      pm_message_t msg)
>  {
> -	struct dwc3	*dwc3 = platform_get_drvdata(dwc3_imx->dwc3);
> +	struct dwc3	*dwc3 = platform_get_drvdata(dwc3_imx->dwc3_pdev);
>  	u32		val;
>
>  	if (!dwc3)
> @@ -142,7 +142,7 @@ static const struct software_node dwc3_imx8mp_swnode = {
>  static irqreturn_t dwc3_imx8mp_interrupt(int irq, void *_dwc3_imx)
>  {
>  	struct dwc3_imx8mp	*dwc3_imx = _dwc3_imx;
> -	struct dwc3		*dwc = platform_get_drvdata(dwc3_imx->dwc3);
> +	struct dwc3		*dwc = platform_get_drvdata(dwc3_imx->dwc3_pdev);
>
>  	if (!dwc3_imx->pm_suspended)
>  		return IRQ_HANDLED;
> @@ -233,8 +233,8 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev)
>  		goto remove_swnode;
>  	}
>
> -	dwc3_imx->dwc3 = of_find_device_by_node(dwc3_np);
> -	if (!dwc3_imx->dwc3) {
> +	dwc3_imx->dwc3_pdev = of_find_device_by_node(dwc3_np);
> +	if (!dwc3_imx->dwc3_pdev) {
>  		dev_err(dev, "failed to get dwc3 platform device\n");
>  		err = -ENODEV;
>  		goto depopulate;
> @@ -253,7 +253,7 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev)
>  	return 0;
>
>  put_dwc3:
> -	put_device(&dwc3_imx->dwc3->dev);
> +	put_device(&dwc3_imx->dwc3_pdev->dev);
>  depopulate:
>  	of_platform_depopulate(dev);
>  remove_swnode:
> @@ -270,7 +270,7 @@ static void dwc3_imx8mp_remove(struct platform_device *pdev)
>  	struct dwc3_imx8mp *dwc3_imx = platform_get_drvdata(pdev);
>  	struct device *dev = &pdev->dev;
>
> -	put_device(&dwc3_imx->dwc3->dev);
> +	put_device(&dwc3_imx->dwc3_pdev->dev);
>
>  	pm_runtime_get_sync(dev);
>  	of_platform_depopulate(dev);
> @@ -296,7 +296,7 @@ static int dwc3_imx8mp_suspend(struct dwc3_imx8mp *dwc3_imx, pm_message_t msg)
>
>  static int dwc3_imx8mp_resume(struct dwc3_imx8mp *dwc3_imx, pm_message_t msg)
>  {
> -	struct dwc3	*dwc = platform_get_drvdata(dwc3_imx->dwc3);
> +	struct dwc3	*dwc = platform_get_drvdata(dwc3_imx->dwc3_pdev);
>  	int ret = 0;
>
>  	if (!dwc3_imx->pm_suspended)
> --
> 2.34.1
>


From maudspierings at gocontroll.com  Fri Dec  5 07:12:42 2025
From: maudspierings at gocontroll.com (Maud Spierings)
Date: Fri, 5 Dec 2025 16:12:42 +0100
Subject: [PATCH v6 1/4] dt-bindings: backlight: Add max25014 support
In-Reply-To: <20251205150751.GA124954-robh@kernel.org>
References: <20251201-max25014-v6-0-88e3ac8112ff@gocontroll.com>
 <20251201-max25014-v6-1-88e3ac8112ff@gocontroll.com>
 <20251205150751.GA124954-robh@kernel.org>
Message-ID: <a290ab5f-c6e7-49df-98f4-6e809c58c625@gocontroll.com>

Thanks for the review.

On 12/5/25 16:07, Rob Herring wrote:
> On Mon, Dec 01, 2025 at 12:53:20PM +0100, Maud Spierings wrote:
>> The Maxim MAX25014 is a 4-channel automotive grade backlight driver IC
>> with integrated boost controller.
>>
>> Signed-off-by: Maud Spierings <maudspierings at gocontroll.com>
>>
>> ---
>>
>> In the current implementation the control registers for channel 1,
>> control all channels. So only one led subnode with led-sources is
>> supported right now. If at some point the driver functionality is
>> expanded the bindings can be easily extended with it.
> 
> What's the relationship between the LEDs and backlight? It's a backlight
> plus LEDs or just 4 identical channels.

it is just 4 identical channels, represented as leds, or in this case 1 
led. I still feel a bit weird about this representation when there is 
also led-backlight. But it was requested to map it in this way.

>>
>> ---
>>   .../bindings/leds/backlight/maxim,max25014.yaml    | 107 +++++++++++++++++++++
>>   MAINTAINERS                                        |   5 +
>>   2 files changed, 112 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml b/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
>> new file mode 100644
>> index 000000000000..e83723224b07
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
>> @@ -0,0 +1,107 @@
>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/leds/backlight/maxim,max25014.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Maxim max25014 backlight controller
>> +
>> +maintainers:
>> +  - Maud Spierings <maudspierings at gocontroll.com>
>> +
>> +properties:
>> +  compatible:
>> +    enum:
>> +      - maxim,max25014
>> +
>> +  reg:
>> +    maxItems: 1
>> +
>> +  "#address-cells":
>> +    const: 1
>> +
>> +  "#size-cells":
>> +    const: 0
>> +
>> +  enable-gpios:
>> +    maxItems: 1
>> +
>> +  interrupts:
>> +    maxItems: 1
>> +
>> +  power-supply:
>> +    description: Regulator which controls the boost converter input rail.
>> +
>> +  pwms:
>> +    maxItems: 1
>> +
>> +  maxim,iset:
>> +    $ref: /schemas/types.yaml#/definitions/uint32
>> +    maximum: 15
>> +    default: 11
>> +    description:
>> +      Value of the ISET field in the ISET register. This controls the current
>> +      scale of the outputs, a higher number means more current.
> 
> We have properties for setting the current (in uA). That can't work
> here?

please refer to [1] and [2].

Link: 
https://lore.kernel.org/all/5c5cf363-db5c-4d0b-902f-97c6ef06c08f at gocontroll.com/ 
[1]

Link: 
https://lore.kernel.org/all/20251009-overjoyed-unpopular-54f69e9bd82c at spud/ 
[2]

kind regards,
Maud




From rafael at kernel.org  Fri Dec  5 07:13:24 2025
From: rafael at kernel.org (Rafael J. Wysocki)
Date: Fri, 5 Dec 2025 16:13:24 +0100
Subject: [PATCH v4 1/3] ACPI: CPPC: Factor out and export per-cpu cppc_perf_ctrs_in_pcc_cpu()
In-Reply-To: <20251203032422.3232957-2-zhanjie9@hisilicon.com>
References: <20251203032422.3232957-1-zhanjie9@hisilicon.com> <20251203032422.3232957-2-zhanjie9@hisilicon.com>
Message-ID: <CAJZ5v0jvk+gs+h+76__LLZDa=OGzLxQQsWEMDHXzeV8aV6UYsA@mail.gmail.com>

On Wed, Dec 3, 2025 at 4:25?AM Jie Zhan <zhanjie9 at hisilicon.com> wrote:
>
> Factor out cppc_perf_ctrs_in_pcc_cpu() for checking whether per-cpu CPC
> regs are defined in PCC channels, and export it out for further use.
>
> Signed-off-by: Jie Zhan <zhanjie9 at hisilicon.com>
> ---
>  drivers/acpi/cppc_acpi.c | 45 +++++++++++++++++++++-------------------
>  include/acpi/cppc_acpi.h |  5 +++++
>  2 files changed, 29 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
> index 3bdeeee3414e..aa80dbcf42c0 100644
> --- a/drivers/acpi/cppc_acpi.c
> +++ b/drivers/acpi/cppc_acpi.c
> @@ -1422,6 +1422,29 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
>  }
>  EXPORT_SYMBOL_GPL(cppc_get_perf_caps);
>
> +bool cppc_perf_ctrs_in_pcc_cpu(unsigned int cpu)
> +{
> +       struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu);
> +       struct cpc_register_resource *ref_perf_reg;
> +
> +       /*
> +        * If reference perf register is not supported then we should use the
> +        * nominal perf value
> +        */
> +       ref_perf_reg = &cpc_desc->cpc_regs[REFERENCE_PERF];
> +       if (!CPC_SUPPORTED(ref_perf_reg))
> +               ref_perf_reg = &cpc_desc->cpc_regs[NOMINAL_PERF];
> +
> +       if (CPC_IN_PCC(&cpc_desc->cpc_regs[DELIVERED_CTR]) ||
> +           CPC_IN_PCC(&cpc_desc->cpc_regs[REFERENCE_CTR]) ||
> +           CPC_IN_PCC(&cpc_desc->cpc_regs[CTR_WRAP_TIME]) ||
> +           CPC_IN_PCC(ref_perf_reg))
> +               return true;
> +
> +       return false;

Why not

return CPC_IN_PCC(&cpc_desc->cpc_regs[DELIVERED_CTR]) ||
          CPC_IN_PCC(&cpc_desc->cpc_regs[REFERENCE_CTR]) ||
          CPC_IN_PCC(&cpc_desc->cpc_regs[CTR_WRAP_TIME]) ||
          CPC_IN_PCC(ref_perf_reg);

> +}
> +EXPORT_SYMBOL_GPL(cppc_perf_ctrs_in_pcc_cpu);
> +
>  /**
>   * cppc_perf_ctrs_in_pcc - Check if any perf counters are in a PCC region.
>   *
> @@ -1436,27 +1459,7 @@ bool cppc_perf_ctrs_in_pcc(void)
>         int cpu;
>
>         for_each_online_cpu(cpu) {
> -               struct cpc_register_resource *ref_perf_reg;
> -               struct cpc_desc *cpc_desc;
> -
> -               cpc_desc = per_cpu(cpc_desc_ptr, cpu);
> -
> -               if (CPC_IN_PCC(&cpc_desc->cpc_regs[DELIVERED_CTR]) ||
> -                   CPC_IN_PCC(&cpc_desc->cpc_regs[REFERENCE_CTR]) ||
> -                   CPC_IN_PCC(&cpc_desc->cpc_regs[CTR_WRAP_TIME]))
> -                       return true;
> -
> -
> -               ref_perf_reg = &cpc_desc->cpc_regs[REFERENCE_PERF];
> -
> -               /*
> -                * If reference perf register is not supported then we should
> -                * use the nominal perf value
> -                */
> -               if (!CPC_SUPPORTED(ref_perf_reg))
> -                       ref_perf_reg = &cpc_desc->cpc_regs[NOMINAL_PERF];
> -
> -               if (CPC_IN_PCC(ref_perf_reg))
> +               if (cppc_perf_ctrs_in_pcc_cpu(cpu))
>                         return true;
>         }
>
> diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h
> index 13fa81504844..4bcdcaf8bf2c 100644
> --- a/include/acpi/cppc_acpi.h
> +++ b/include/acpi/cppc_acpi.h
> @@ -154,6 +154,7 @@ extern int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_ctrs);
>  extern int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls);
>  extern int cppc_set_enable(int cpu, bool enable);
>  extern int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps);
> +extern bool cppc_perf_ctrs_in_pcc_cpu(unsigned int cpu);
>  extern bool cppc_perf_ctrs_in_pcc(void);
>  extern unsigned int cppc_perf_to_khz(struct cppc_perf_caps *caps, unsigned int perf);
>  extern unsigned int cppc_khz_to_perf(struct cppc_perf_caps *caps, unsigned int freq);
> @@ -204,6 +205,10 @@ static inline int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps)
>  {
>         return -EOPNOTSUPP;
>  }
> +static inline bool cppc_perf_ctrs_in_pcc_cpu(unsigned int cpu)
> +{
> +       return false;
> +}
>  static inline bool cppc_perf_ctrs_in_pcc(void)
>  {
>         return false;
> --
> 2.33.0
>
>


From maudspierings at gocontroll.com  Fri Dec  5 07:20:55 2025
From: maudspierings at gocontroll.com (Maud Spierings)
Date: Fri, 5 Dec 2025 16:20:55 +0100
Subject: [PATCH v6 2/4] backlight: add max25014atg backlight
In-Reply-To: <aTG0EK_zuSB-U_bb@aspen.lan>
References: <20251201-max25014-v6-0-88e3ac8112ff@gocontroll.com>
 <20251201-max25014-v6-2-88e3ac8112ff@gocontroll.com>
 <aTG0EK_zuSB-U_bb@aspen.lan>
Message-ID: <8a9a59b8-d5c0-46b3-8f86-a4cd910b7af3@gocontroll.com>

Thanks for the review.

On 12/4/25 17:17, Daniel Thompson wrote:
> On Mon, Dec 01, 2025 at 12:53:21PM +0100, Maud Spierings via B4 Relay wrote:
>> From: Maud Spierings <maudspierings at gocontroll.com>
>>
>> The Maxim MAX25014 is a 4-channel automotive grade backlight driver IC
>> with integrated boost controller.
>>
>> Signed-off-by: Maud Spierings <maudspierings at gocontroll.com>
> 
>> <snip>
> 
>> +static int max25014_check_errors(struct max25014 *maxim)
>> +{
>> +	uint32_t val;
>> +	uint8_t i;
>> +	int ret;
>> +
>> +	ret = regmap_read(maxim->regmap, MAX25014_OPEN, &val);
>> +	if (ret)
>> +		return ret;
>> +	if (val) {
>> +		dev_err(&maxim->client->dev, "Open led strings detected on:\n");
>> +		for (i = 0; i < 4; i++) {
>> +			if (val & 1 << i)
>> +				dev_err(&maxim->client->dev, "string %d\n", i + 1);
>> +		}
>> +		return -EIO;
>> +	}
>> +
>> +	ret = regmap_read(maxim->regmap, MAX25014_SHORT_GND, &val);
>> +	if (ret)
>> +		return ret;
>> +	if (val) {
>> +		dev_err(&maxim->client->dev, "Short to ground detected on:\n");
>> +		for (i = 0; i < 4; i++) {
>> +			if (val & 1 << i)
>> +				dev_err(&maxim->client->dev, "string %d\n", i + 1);
>> +		}
>> +		return -EIO;
>> +	}
>> +
>> +	ret = regmap_read(maxim->regmap, MAX25014_SHORT_GND, &val);
> 
> Shouldn't this be MAX25014_SHORT_LED?

yep you are absolutely right

> 
>> +	if (ret)
>> +		return ret;
>> +	if (val) {
>> +		dev_err(&maxim->client->dev, "Shorted led detected on:\n");
>> +		for (i = 0; i < 4; i++) {
>> +			if (val & 1 << i)
>> +				dev_err(&maxim->client->dev, "string %d\n", i + 1);
>> +		}
>> +		return -EIO;
>> +	}
>> +
>> +	ret = regmap_read(maxim->regmap, MAX25014_DIAG, &val);
>> +	if (ret)
>> +		return ret;
>> +	/*
>> +	 * The HW_RST bit always starts at 1 after power up.
>> +	 * It is reset on first read, does not indicate an error.
>> +	 */
>> +	if (val && val != MAX25014_DIAG_HW_RST) {
>> +		if (val & MAX25014_DIAG_OT)
>> +			dev_err(&maxim->client->dev,
>> +				"Overtemperature shutdown\n");
>> +		if (val & MAX25014_DIAG_OTW)
>> +			dev_err(&maxim->client->dev,
>> +				 "Chip is getting too hot (>125C)\n");
>> +		if (val & MAX25014_DIAG_BSTOV)
>> +			dev_err(&maxim->client->dev,
>> +				"Boost converter overvoltage\n");
>> +		if (val & MAX25014_DIAG_BSTUV)
>> +			dev_err(&maxim->client->dev,
>> +				"Boost converter undervoltage\n");
>> +		if (val & MAX25014_DIAG_IREFOOR)
>> +			dev_err(&maxim->client->dev, "IREF out of range\n");
>> +		return -EIO;
>> +	}
>> +	return 0;
>> +}
>> +
>> +/*
>> + * 1. disable unused strings
>> + * 2. set dim mode
>> + * 3. set setting register
>> + * 4. enable the backlight
>> + */
>> +static int max25014_configure(struct max25014 *maxim, int initial_state)
>> +{
>> +	uint32_t val;
>> +	int ret;
>> +
>> +	/*
>> +	 * Strings can only be disabled when MAX25014_ISET_ENA == 0, check if
>> +	 * it needs to be changed at all to prevent the backlight flashing when
>> +	 * it is configured correctly by the bootloader
>> +	 */
> 
> Attach the comment to the if statement rather than the read.

will do

> 
>> +	ret = regmap_read(maxim->regmap, MAX25014_DISABLE, &val);
>> +	if (ret)
>> +		return ret;
>> +
>> +	if (!((val & MAX25014_DISABLE_DIS_MASK) == maxim->strings_mask)) {
>> +		if (initial_state == BACKLIGHT_POWER_ON) {
>> +			ret = regmap_write(maxim->regmap, MAX25014_ISET, 0);
>> +			if (ret)
>> +				return ret;
>> +		}
>> +		ret = regmap_write(maxim->regmap, MAX25014_DISABLE, maxim->strings_mask);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +
>> +	ret = regmap_write(maxim->regmap, MAX25014_IMODE, MAX25014_IMODE_HDIM);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = regmap_read(maxim->regmap, MAX25014_SETTING, &val);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = regmap_write(maxim->regmap, MAX25014_SETTING,
>> +			   val & ~MAX25014_SETTING_FPWM);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = regmap_write(maxim->regmap, MAX25014_ISET,
>> +			   maxim->iset | MAX25014_ISET_ENA |
>> +			   MAX25014_ISET_PSEN);
>> +	return ret;
>> +}
>> +
>> +static int max25014_update_status(struct backlight_device *bl_dev)
>> +{
>> +	struct max25014 *maxim = bl_get_data(bl_dev);
>> +	uint32_t reg;
>> +	int ret;
>> +
>> +	if (backlight_is_blank(maxim->bl))
>> +		bl_dev->props.brightness = 0;
> 
> This isn't right. Why would you change the backlight level just because
> it is currently blanked (and sorry I missed this one last time).

so just remove this bit then jeah?

>> +
>> +	reg  = TON_STEP * bl_dev->props.brightness;
> 
> The correct way to honour blanking is just go call
> backlight_get_brightness() instead of reading the property directly.

will do.

> 
>> +
>> +	/*
>> +	 * 18 bit number lowest, 2 bits in first register,
>> +	 * next lowest 8 in the L register, next 8 in the H register
>> +	 * Seemingly setting the strength of only one string controls all of
>> +	 * them, individual settings don't affect the outcome.
>> +	 */
>> +
>> +	ret = regmap_write(maxim->regmap, MAX25014_TON_1_4_LSB, reg & 0b00000011);
>> +	if (ret != 0)
>> +		return ret;
>> +	ret = regmap_write(maxim->regmap, MAX25014_TON1L, (reg >> 2) & 0b11111111);
>> +	if (ret != 0)
>> +		return ret;
>> +	return regmap_write(maxim->regmap, MAX25014_TON1H, (reg >> 10) & 0b11111111);
>> +}
>> +
>> +static const struct backlight_ops max25014_bl_ops = {
>> +	.options = BL_CORE_SUSPENDRESUME,
>> +	.update_status = max25014_update_status,
>> +};
>> +
>> +static int max25014_parse_dt(struct max25014 *maxim,
>> +			     uint32_t *initial_brightness)
>> +{
>> +	struct device *dev = &maxim->client->dev;
>> +	struct device_node *node = dev->of_node;
>> +	struct fwnode_handle *child;
>> +	uint32_t strings[4];
>> +	int res, i;
>> +
>> +	if (!node)
>> +		return dev_err_probe(dev, -EINVAL, "no platform data\n");
>> +
>> +	child = device_get_next_child_node(dev, NULL);
>> +	if (child) {
>> +		res = fwnode_property_count_u32(child, "led-sources");
>> +		if (res > 0) {
>> +			fwnode_property_read_u32_array(child, "led-sources",
>> +						       strings, res);
>> +
>> +			/* set all strings as disabled, then enable those in led-sources*/
>> +			maxim->strings_mask = 0xf;
>> +			for (i = 0; i < res; i++) {
>> +				if (strings[i] <= 4)
>> +					maxim->strings_mask &= ~BIT(strings[i]);
>> +			}
>> +		}
>> +
>> +		fwnode_property_read_u32(child, "default-brightness",
>> +					 initial_brightness);
>> +
>> +		fwnode_handle_put(child);
>> +	}
>> +
>> +	maxim->iset = MAX25014_ISET_DEFAULT_100;
>> +	of_property_read_u32(node, "maxim,iset", &maxim->iset);
>> +
>> +	if (maxim->iset > 15)
>> +		return dev_err_probe(dev, -EINVAL,
>> +				     "Invalid iset, should be a value from 0-15, entered was %d\n",
>> +				     maxim->iset);
>> +
>> +	if (*initial_brightness > 100)
>> +		return dev_err_probe(dev, -EINVAL,
>> +				     "Invalid initial brightness, should be a value from 0-100, entered was %d\n",
>> +				     *initial_brightness);
>> +
>> +	return 0;
>> +}
>> +
>> +static int max25014_probe(struct i2c_client *cl)
>> +{
>> +	const struct i2c_device_id *id = i2c_client_get_device_id(cl);
>> +	struct backlight_properties props;
>> +	uint32_t initial_brightness = 50;
>> +	struct backlight_device *bl;
>> +	struct max25014 *maxim;
>> +	int ret;
>> +
>> +	maxim = devm_kzalloc(&cl->dev, sizeof(struct max25014), GFP_KERNEL);
>> +	if (!maxim)
>> +		return -ENOMEM;
>> +
>> +	maxim->client = cl;
>> +
>> +	ret = max25014_parse_dt(maxim, &initial_brightness);
>> +	if (ret)
>> +		return ret;
>> +
>> +	maxim->vin = devm_regulator_get(&maxim->client->dev, "power");
>> +	if (IS_ERR(maxim->vin)) {
>> +		return dev_err_probe(&maxim->client->dev, PTR_ERR(maxim->vin),
>> +				     "failed to get power-supply");
>> +	}
>> +
>> +	ret = regulator_enable(maxim->vin);
>> +	if (ret)
>> +		return dev_err_probe(&maxim->client->dev, ret,
>> +			"failed to enable power-supply\n");
> 
> Can this use devm_regulator_get_enable()?

Yeah guess I'll just switch to that for now, if ever power management 
gets implemented it can be figured out if regulator control is desired.

> 
>> +
>> +	maxim->enable = devm_gpiod_get_optional(&maxim->client->dev, "enable",
>> +						GPIOD_OUT_HIGH);
>> +	if (IS_ERR(maxim->enable)) {
>> +		ret = dev_err_probe(&maxim->client->dev, PTR_ERR(maxim->enable),
>> +				    "failed to get enable gpio\n");
>> +		goto disable_vin;
>> +	}
>> +
>> +	/* Datasheet Electrical Characteristics tSTARTUP 2ms */
>> +	fsleep(2000);
>> +
>> +	maxim->regmap = devm_regmap_init_i2c(cl, &max25014_regmap_config);
>> +	if (IS_ERR(maxim->regmap)) {
>> +		ret = dev_err_probe(&maxim->client->dev, PTR_ERR(maxim->regmap),
>> +			"failed to initialize the i2c regmap\n");
>> +		goto disable_full;
>> +	}
>> +
>> +	i2c_set_clientdata(cl, maxim);
>> +
>> +	ret = max25014_check_errors(maxim);
>> +	if (ret) { /* error is already reported in the above function */
>> +		goto disable_full;
>> +	}
>> +
>> +	ret = max25014_initial_power_state(maxim);
>> +	if (ret < 0) {
>> +		dev_err_probe(&maxim->client->dev, ret, "Could not get enabled state\n");
>> +		goto disable_full;
>> +	}
>> +
>> +	memset(&props, 0, sizeof(struct backlight_properties));
>> +	props.type = BACKLIGHT_PLATFORM;
>> +	props.max_brightness = MAX_BRIGHTNESS;
>> +	props.brightness = initial_brightness;
>> +	props.scale = BACKLIGHT_SCALE_LINEAR;
>> +	props.power = ret;
>> +
>> +	ret = max25014_configure(maxim, ret);
>> +	if (ret) {
>> +		dev_err_probe(&maxim->client->dev, ret, "device config error");
>> +		goto disable_full;
>> +	}
>> +
>> +	bl = devm_backlight_device_register(&maxim->client->dev, id->name,
>> +					    &maxim->client->dev, maxim,
>> +					    &max25014_bl_ops, &props);
>> +	if (IS_ERR(bl)) {
>> +		ret = dev_err_probe(&maxim->client->dev, PTR_ERR(bl),
>> +				    "failed to register backlight\n");
>> +		goto disable_full;
>> +	}
>> +
>> +	maxim->bl = bl;
>> +
>> +	backlight_update_status(maxim->bl);
>> +
>> +	return 0;
>> +
>> +disable_full:
>> +	gpiod_set_value_cansleep(maxim->enable, 0);
> 
> Why is this needed? It was only ever set by devm_gpiod_get_optional().

oops thats a leftover from before that change, good spot.

>> +disable_vin:
>> +	regulator_disable(maxim->vin);
> 
> This is also not needed if you use devm_regulator_get_enable().

jeah I'll drop this then too

kind regards,
Maud



From frank-w at public-files.de  Fri Dec  5 07:41:59 2025
From: frank-w at public-files.de (Frank Wunderlich)
Date: Fri, 05 Dec 2025 16:41:59 +0100
Subject: =?US-ASCII?Q?Re=3A_=5BPATCH_v1_1/2=5D_arm64=3A_dts=3A_mediatek=3A_mt79?=
 =?US-ASCII?Q?86=3A_add_dtbs_with_applied_overlays_for_bpi-r3?=
In-Reply-To: <CAL_Jsq+Zu14ojvNNjgOFWA40iaqYrgGQsrHNWraooOML98fXyw@mail.gmail.com>
References: <20251119175124.48947-1-linux@fw-web.de> <20251119175124.48947-2-linux@fw-web.de> <fc5c9829-96fa-4028-a642-0792699e92a5@kernel.org> <ddad2f21-4853-41c9-acfb-1613f5000f0c@collabora.com> <CAL_Jsq+Zu14ojvNNjgOFWA40iaqYrgGQsrHNWraooOML98fXyw@mail.gmail.com>
Message-ID: <9C47E860-BE37-4EDF-8C9A-613CAE509053@public-files.de>

Am 5. Dezember 2025 14:46:45 MEZ schrieb Rob Herring <robh at kernel.org>:
>On Fri, Dec 5, 2025 at 3:05?AM AngeloGioacchino Del Regno
><angelogioacchino.delregno at collabora.com> wrote:
>>
>> Il 05/12/25 09:10, Krzysztof Kozlowski ha scritto:
>> > On 19/11/2025 18:51, Frank Wunderlich wrote:
>> >> From: Frank Wunderlich <frank-w at public-files.de>
>> >>
>> >> Build devicetree binaries for testing overlays and providing users
>> >> full dtb without using overlays.
>> >>
>> >> Suggested-by: Rob Herring <robh+dt at kernel.org>
>> >> Signed-off-by: Frank Wunderlich <frank-w at public-files.de>
>> >> ---
>> >> resend of
>> >> https://patchwork.kernel.org/project/linux-mediatek/patch/20240608080530.9436-2-linux at fw-web.de/
>> >> due to discussions here:
>> >> https://patchwork.kernel.org/project/linux-mediatek/patch/20251117211306.725678-1-robh at kernel.org/
>> >>
>> >> changes:
>> >> - updated sd-nand with sata-overlay
>> >> ---
>> >>   arch/arm64/boot/dts/mediatek/Makefile | 21 +++++++++++++++++++++
>> >>   1 file changed, 21 insertions(+)
>> >
>> >
>> > This looks like still not being applied and now it is a warning in
>> > Linus' tree.
>> >
>> > Can this be applied and sent as fixes?
>
>There's still one warning remaining after applying this series which I reported:
>
>scripts/Makefile.dtbs:20: .dtbo is not applied to any base:
>mt8395-radxa-nio-12l-8-hd-panel.dtbo
>
>It's fixed in my original patch. Can you all take that and drop the bpi hunks.

Sorry, missed this part and i do not have this board,so
I'm not sure if this should be applied this way.
But if it helps i can separate it from robs patch and send tomorrow.

>FWIW:
>
>Acked-by: Rob Herring (Arm) <robh at kernel.org>


regards Frank


From florian.fainelli at broadcom.com  Fri Dec  5 08:41:38 2025
From: florian.fainelli at broadcom.com (Florian Fainelli)
Date: Fri, 5 Dec 2025 08:41:38 -0800
Subject: [RFC PATCH] arm64: broadcom: bcm2712: Rework rp1 overlay handling
In-Reply-To: <ae5d1a37-9af9-46a2-9ca0-83c276248931@kernel.org>
References: <20251117211503.728354-2-robh@kernel.org>
 <ae5d1a37-9af9-46a2-9ca0-83c276248931@kernel.org>
Message-ID: <7f051318-0aaf-454d-8a85-b6d16fa10d2b@broadcom.com>

On 12/5/25 00:08, Krzysztof Kozlowski wrote:
> On 17/11/2025 22:15, Rob Herring (Arm) wrote:
>> It's a requirement that DT overlays be applied at build time in order to
>> validate them as overlays are not validated on their own.
>>
>> Simply adding a build time target is possible, but it's also not desirable
>> to have targets which include the overlay contents and apply the same
>> overlay.
>>
>> Rework the targets such that there are 2 overlays: the existing RP1 overlay
>> and the board specific configuration of the RP1 (bcm2712-rpi-5-b.dtso).
>>
>> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
>> ---
>> The missing applying of rp1.dtbo will soon be a warning[1].
>>
>> The comment in bcm2712-rpi-5-b.dts(o) needs updating or removing. The RP1
>> driver or userspace handling of the overlay probably needs updating to
>> handle the 2 overlays. IIRC, I think we can apply overlays to overlays
>> which may be useful here. If not, adding that to the tools should be
>> possible.
>>
>> [1] https://lore.kernel.org/all/20251114222759.4181152-1-robh at kernel.org/
>> ---
>>   arch/arm64/boot/dts/broadcom/Makefile                 | 10 ++++++++--
>>   ...m2712-d-rpi-5-b.dts => bcm2712-d-rpi-5-b-base.dts} |  2 +-
>>   .../{bcm2712-rpi-5-b.dts => bcm2712-rpi-5-b.dtso}     | 11 +++++------
> 
> 
> So now Linus' tree has warnings. Can this be applied by anyone around
> Broadcom and sent as fixes?

It's an RFC and I was hoping to get Andrea to comment on this patch 
before applying.
-- 
Florian


From will at kernel.org  Fri Dec  5 09:00:15 2025
From: will at kernel.org (Will Deacon)
Date: Fri, 5 Dec 2025 17:00:15 +0000
Subject: [PATCH v1 0/5] KVM: arm64: Enforce MTE disablement at EL2
In-Reply-To: <aS9rmMgNna7I5g4F@kernel.org>
References: <20251127122210.4111702-1-tabba@google.com>
 <aS9rmMgNna7I5g4F@kernel.org>
Message-ID: <aTMPn0dBbSVUwwJ1@willie-the-truck>

On Tue, Dec 02, 2025 at 02:43:36PM -0800, Oliver Upton wrote:
> On Thu, Nov 27, 2025 at 12:22:05PM +0000, Fuad Tabba wrote:
> > pKVM never exposes MTE to protected guests (pVM), but we must also
> > ensure a malicious host cannot use MTE to attack the hypervisor or a
> > pVM.
> > 
> > If MTE is supported by the hardware (and is enabled at EL3), it remains
> > available to lower exception levels by default. Disabling it in the host
> > kernel (e.g., via 'arm64.nomte') only stops the kernel from advertising
> > the feature; it does not physically disable MTE in the hardware.
> > 
> > In this scenario, a malicious host could still access tags in pages
> > donated to a guest using MTE instructions (e.g., STG and LDG), bypassing
> > the kernel's configuration.
> > 
> > To prevent this, explicitly disable MTE at EL2 (by clearing HCR_EL2.ATA)
> > when the host has MTE disabled. This causes any MTE instruction usage to
> > generate a Data Abort (trap) to the hypervisor.
> > 
> > Additionally, to faithfully mimic hardware that does not support MTE,
> > trap accesses to MTE system registers (e.g., GCR_EL1) and inject an
> > Undefined Instruction exception back to the host.
> > 
> > This logic is applied in all non-VHE modes. For non-protected modes,
> > this remains beneficial as it prevents unpredictable behavior caused by
> > accessing allocation tags when the system considers them disabled.
> > 
> > Note that this ties into my other outgoing patch series [1], which also
> > has some MTE-related fixes, but is not dependent on it.
> 
> To be honest, I've actually been having a bit of a hard time
> rationalizing some of these targeted fixes for pKVM. It has been in a
> half working state upstream for O(years) and we haven't made forward
> progress on enabling pVMs.
> 
> Fully aware that guest_memfd has been one of the long poles here, but
> I'm becoming less interested in fixes addressing "pKVM policy is XYZ"
> without having the full picture of the feature.

That's completely understandable and we're similarly frustrated.

> What are the upstream plans on enabling some basic implementation of
> protected VMs?

Funnily enough, I've been hacking on this recently and I've ended up
with something that I think serves as a good basis for enabling pvms
incrementally upstream. I need to clean the patches up but I'll be
flying to Japan and back next week so that gives me a good opportunity
to do exactly that!

In the meantime, I hope you'll still consider fixes for non-protected
guests under pKVM (e.g. [1]), as that is an area where I think we've
made some reasonable progress.

Will

[1] https://lore.kernel.org/all/20251128141710.19472-1-will at kernel.org/


From krzk at kernel.org  Fri Dec  5 09:13:26 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 5 Dec 2025 18:13:26 +0100
Subject: [PATCH v8 1/2] dt-bindings: phy: google: Add Google Tensor G5 USB
 PHY
In-Reply-To: <20251205-phyb4-v8-1-c59ea80a4458@google.com>
References: <20251205-phyb4-v8-0-c59ea80a4458@google.com>
 <20251205-phyb4-v8-1-c59ea80a4458@google.com>
Message-ID: <18eeb1c5-d21b-4505-b6a4-472f6e191864@kernel.org>

On 05/12/2025 04:54, Roy Luo wrote:
> Document the device tree bindings for the USB PHY interfaces integrated
> with the DWC3 controller on Google Tensor SoCs, starting with G5
> generation (Laguna). The USB PHY on Tensor G5 includes two integrated
> Synopsys PHY IPs: the eUSB 2.0 PHY IP and the USB 3.2/DisplayPort combo
> PHY IP.
> 
> Due to a complete architectural overhaul in the Google Tensor G5, the
> existing Samsung/Exynos USB PHY binding for older generations of Google
> silicons such as gs101 are no longer compatible, necessitating this new
> device tree binding.
> 
> Signed-off-by: Roy Luo <royluo at google.com>

Why intentionally dropping the tag? How are you handling this patchset?
Rewrite every time from scratch?

<form letter>
This is a friendly reminder during the review process.

It looks like you received a tag and forgot to add it.

If you do not know the process, here is a short explanation:
Please add Acked-by/Reviewed-by/Tested-by tags when posting new versions
of patchset, under or above your Signed-off-by tag, unless patch changed
significantly (e.g. new properties added to the DT bindings). Tag is
"received", when provided in a message replied to you on the mailing
list. Tools like b4 can help here. However, there's no need to repost
patches *only* to add the tags. The upstream maintainer will do that for
tags received on the version they apply.

Please read:
https://elixir.bootlin.com/linux/v6.12-rc3/source/Documentation/process/submitting-patches.rst#L577

If a tag was not added on purpose, please state why and what changed.
</form letter>

Best regards,
Krzysztof


From krzk at kernel.org  Fri Dec  5 09:14:12 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 5 Dec 2025 18:14:12 +0100
Subject: [PATCH v9 1/2] dt-bindings: usb: dwc3: Add Google Tensor G5 DWC3
In-Reply-To: <20251205-controller-v9-1-9f158b18f979@google.com>
References: <20251205-controller-v9-0-9f158b18f979@google.com>
 <20251205-controller-v9-1-9f158b18f979@google.com>
Message-ID: <3b367841-326c-4697-9fe9-041a32001d94@kernel.org>

On 05/12/2025 03:26, Roy Luo wrote:
> Document the device tree bindings for the DWC3 USB controller found in
> Google Tensor SoCs, starting with the G5 generation (codename: laguna).
> 
> The Tensor G5 silicon represents a complete architectural departure from
> previous generations (like gs101), including entirely new clock/reset
> schemes, top-level wrapper and register interface. Consequently,
> existing Samsung/Exynos DWC3 USB bindings are incompatible, necessitating
> this new device tree binding.
> 
> The USB controller on Tensor G5 is based on Synopsys DWC3 IP and features
> Dual-Role Device single port with hibernation support.
> 
> Signed-off-by: Roy Luo <royluo at google.com>
> ---
>  .../devicetree/bindings/usb/google,lga-dwc3.yaml   | 140 +++++++++++++++++++++
>  MAINTAINERS                                        |   1 +
>  2 files changed, 141 insertions(+)
> 

Nothing explains reason to ignore review. I am not doing same work
twice, please respect maintainers' time.

<form letter>
This is a friendly reminder during the review process.

It looks like you received a tag and forgot to add it.

If you do not know the process, here is a short explanation:
Please add Acked-by/Reviewed-by/Tested-by tags when posting new versions
of patchset, under or above your Signed-off-by tag, unless patch changed
significantly (e.g. new properties added to the DT bindings). Tag is
"received", when provided in a message replied to you on the mailing
list. Tools like b4 can help here. However, there's no need to repost
patches *only* to add the tags. The upstream maintainer will do that for
tags received on the version they apply.

Please read:
https://elixir.bootlin.com/linux/v6.12-rc3/source/Documentation/process/submitting-patches.rst#L577

If a tag was not added on purpose, please state why and what changed.
</form letter>

Best regards,
Krzysztof


From vdonnefort at google.com  Fri Dec  5 09:33:21 2025
From: vdonnefort at google.com (Vincent Donnefort)
Date: Fri, 5 Dec 2025 17:33:21 +0000
Subject: [PATCH v3 2/3] KVM: selftests: Enable pre_fault_memory_test for
 arm64
In-Reply-To: <20251119154910.97716-3-jackabt.amazon@gmail.com>
References: <20251119154910.97716-1-jackabt.amazon@gmail.com>
 <20251119154910.97716-3-jackabt.amazon@gmail.com>
Message-ID: <aTMXYZgZM3QvZP2i@google.com>

On Wed, Nov 19, 2025 at 03:49:09PM +0000, Jack Thomson wrote:
> From: Jack Thomson <jackabt at amazon.com>
> 
> Enable the pre_fault_memory_test to run on arm64 by making it work with
> different guest page sizes and testing multiple guest configurations.
> 
> Update the test_assert to compare against the UCALL_EXIT_REASON, for
> portability, as arm64 exits with KVM_EXIT_MMIO while x86 uses
> KVM_EXIT_IO.
> 
> Signed-off-by: Jack Thomson <jackabt at amazon.com>
> ---
>  tools/testing/selftests/kvm/Makefile.kvm      |  1 +
>  .../selftests/kvm/pre_fault_memory_test.c     | 78 ++++++++++++++-----
>  2 files changed, 58 insertions(+), 21 deletions(-)
> 
> diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
> index 148d427ff24b..0ddd8db60197 100644
> --- a/tools/testing/selftests/kvm/Makefile.kvm
> +++ b/tools/testing/selftests/kvm/Makefile.kvm
> @@ -183,6 +183,7 @@ TEST_GEN_PROGS_arm64 += memslot_perf_test
>  TEST_GEN_PROGS_arm64 += mmu_stress_test
>  TEST_GEN_PROGS_arm64 += rseq_test
>  TEST_GEN_PROGS_arm64 += steal_time
> +TEST_GEN_PROGS_arm64 += pre_fault_memory_test
>  
>  TEST_GEN_PROGS_s390 = $(TEST_GEN_PROGS_COMMON)
>  TEST_GEN_PROGS_s390 += s390/memop
> diff --git a/tools/testing/selftests/kvm/pre_fault_memory_test.c b/tools/testing/selftests/kvm/pre_fault_memory_test.c
> index f04768c1d2e4..674931e7bb3a 100644
> --- a/tools/testing/selftests/kvm/pre_fault_memory_test.c
> +++ b/tools/testing/selftests/kvm/pre_fault_memory_test.c
> @@ -11,19 +11,29 @@
>  #include <kvm_util.h>
>  #include <processor.h>
>  #include <pthread.h>
> +#include <guest_modes.h>
>  
>  /* Arbitrarily chosen values */
> -#define TEST_SIZE		(SZ_2M + PAGE_SIZE)
> -#define TEST_NPAGES		(TEST_SIZE / PAGE_SIZE)

After applying on top of the base commit
8a4821412cf2c1429fffa07c012dd150f2edf78c, it does not build.

That TEST_NPAGES seems to still be used in delete_slot_worker(). I believe
that's because of

  "KVM: selftests: Test prefault memory during concurrent memslot removal"

Related issues with the pre_fault_memory() prototype.

Is that the correct base-commit or shall I use something else?

> +#define TEST_BASE_SIZE		SZ_2M
>  #define TEST_SLOT		10
>

[...]


From stefano.r at variscite.com  Fri Dec  5 10:22:53 2025
From: stefano.r at variscite.com (Stefano Radaelli)
Date: Fri,  5 Dec 2025 19:22:53 +0100
Subject: [PATCH v1 0/4] arm64: dts: imx93-var-som-symphony: align DTS with hw revision
Message-ID: <20251205182258.50397-1-stefano.r@variscite.com>

This series adds support for several peripherals available on the
Variscite Symphony carrier board for the VAR-SOM-MX93 module.

The patches introduce:

- GPIO aliases cleanup to better expose available GPIOs
- FT5x06 capacitive touch controller
- USB1 (OTG, via PTN5150 Type-C controller) and USB2 (host-only) support
- LPSPI6 controller exposed on the expansion connector

These changes describe real hardware connections and make the exposed
interfaces available to user applications.

Tested on the Symphony board with a VAR-SOM-MX93.

Stefano Radaelli (4):
  arm64: dts: imx93-var-som-symphony: Update gpio aliases
  arm64: dts: imx93-var-som-symphony: Add support for ft5x06 touch
    controller
  arm64: dts: imx93-var-som-symphony: Add USB support
  arm64: dts: imx93-var-som-symphony: Enable LPSPI6 controller

 .../dts/freescale/imx93-var-som-symphony.dts  | 84 +++++++++++++++++++
 1 file changed, 84 insertions(+)


base-commit: 3f9f0252130e7dd60d41be0802bf58f6471c691d
-- 
2.47.3



From stefano.r at variscite.com  Fri Dec  5 10:22:54 2025
From: stefano.r at variscite.com (Stefano Radaelli)
Date: Fri,  5 Dec 2025 19:22:54 +0100
Subject: [PATCH v1 1/4] arm64: dts: imx93-var-som-symphony: Update gpio aliases
In-Reply-To: <20251205182258.50397-1-stefano.r@variscite.com>
References: <20251205182258.50397-1-stefano.r@variscite.com>
Message-ID: <20251205182258.50397-2-stefano.r@variscite.com>

This patch introduces 2 simple aliases:

Add a gpio3->gpio4 alias to allow flexible access to these GPIOs

Add a gpio4 alias for the PCA9534 GPIO expander.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 arch/arm64/boot/dts/freescale/imx93-var-som-symphony.dts | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx93-var-som-symphony.dts b/arch/arm64/boot/dts/freescale/imx93-var-som-symphony.dts
index c789c1f24bdc..00bdd3b91fdc 100644
--- a/arch/arm64/boot/dts/freescale/imx93-var-som-symphony.dts
+++ b/arch/arm64/boot/dts/freescale/imx93-var-som-symphony.dts
@@ -20,6 +20,8 @@ aliases {
 		gpio0 = &gpio1;
 		gpio1 = &gpio2;
 		gpio2 = &gpio3;
+		gpio3 = &gpio4;
+		gpio4 = &pca9534;
 		i2c0 = &lpi2c1;
 		i2c1 = &lpi2c2;
 		i2c2 = &lpi2c3;
-- 
2.47.3



From stefano.r at variscite.com  Fri Dec  5 10:22:55 2025
From: stefano.r at variscite.com (Stefano Radaelli)
Date: Fri,  5 Dec 2025 19:22:55 +0100
Subject: [PATCH v1 2/4] arm64: dts: imx93-var-som-symphony: Add support for ft5x06 touch controller
In-Reply-To: <20251205182258.50397-1-stefano.r@variscite.com>
References: <20251205182258.50397-1-stefano.r@variscite.com>
Message-ID: <20251205182258.50397-3-stefano.r@variscite.com>

The Symphony carrier board exposes a capacitive touch interface through an
FFC/FPC connector. This interface is wired to an FT5x06 touch controller
on the I2C bus when using Variscite?s 7-inch capacitive touch display.

This patch adds the FT5x06 device node to describe the actual hardware
connection and enables touch functionality on the Symphony board

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../dts/freescale/imx93-var-som-symphony.dts  | 21 +++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx93-var-som-symphony.dts b/arch/arm64/boot/dts/freescale/imx93-var-som-symphony.dts
index 00bdd3b91fdc..39bfbd0428a9 100644
--- a/arch/arm64/boot/dts/freescale/imx93-var-som-symphony.dts
+++ b/arch/arm64/boot/dts/freescale/imx93-var-som-symphony.dts
@@ -208,6 +208,21 @@ &lpi2c1 {
 	sda-gpios = <&gpio1 1 GPIO_ACTIVE_HIGH>;
 	status = "okay";
 
+	/* Capacitive touch controller */
+	ft5x06_ts: touchscreen at 38 {
+		compatible = "edt,edt-ft5206";
+		reg = <0x38>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_captouch>;
+		interrupt-parent = <&gpio2>;
+		interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
+		touchscreen-size-x = <800>;
+		touchscreen-size-y = <480>;
+		touchscreen-inverted-x;
+		touchscreen-inverted-y;
+		wakeup-source;
+	};
+
 	/* DS1337 RTC module */
 	rtc at 68 {
 		compatible = "dallas,ds1337";
@@ -272,6 +287,12 @@ &wdog3 {
 };
 
 &iomuxc {
+	pinctrl_captouch: captouchgrp {
+		fsl,pins = <
+			MX93_PAD_GPIO_IO25__GPIO2_IO25                  0x31e
+		>;
+	};
+
 	pinctrl_fec: fecgrp {
 		fsl,pins = <
 			MX93_PAD_ENET2_RD0__ENET1_RGMII_RD0		0x57e
-- 
2.47.3



From stefano.r at variscite.com  Fri Dec  5 10:22:56 2025
From: stefano.r at variscite.com (Stefano Radaelli)
Date: Fri,  5 Dec 2025 19:22:56 +0100
Subject: [PATCH v1 3/4] arm64: dts: imx93-var-som-symphony: Add USB support
In-Reply-To: <20251205182258.50397-1-stefano.r@variscite.com>
References: <20251205182258.50397-1-stefano.r@variscite.com>
Message-ID: <20251205182258.50397-4-stefano.r@variscite.com>

The Symphony carrier board includes a USB Type-C connector on the USB1
port through an NXP PTN5150 Type-C controller connected on the I2C bus.
The PTN5150 provides cable orientation detection and role switching
information to the USB controller.

This patch adds the PTN5150 node, its interrupt line, the required pin
muxing, and wires the controller to the USB1 OTG dual-role device using
the USB role-switch framework.

This patch adds also USB2 support, that remains in host-only mode,
matching the hardware capabilities of the Symphony board.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../dts/freescale/imx93-var-som-symphony.dts  | 45 +++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx93-var-som-symphony.dts b/arch/arm64/boot/dts/freescale/imx93-var-som-symphony.dts
index 39bfbd0428a9..ee69d6b268a4 100644
--- a/arch/arm64/boot/dts/freescale/imx93-var-som-symphony.dts
+++ b/arch/arm64/boot/dts/freescale/imx93-var-som-symphony.dts
@@ -251,6 +251,22 @@ pca9534: gpio at 20 {
 		#gpio-cells = <2>;
 		wakeup-source;
 	};
+
+	/* USB Type-C Controller */
+	ptn5150: typec at 3d {
+		compatible = "nxp,ptn5150";
+		reg = <0x3d>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_ptn5150>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <10 IRQ_TYPE_NONE>;
+
+		port {
+			typec1_dr_sw: endpoint {
+				remote-endpoint = <&usb1_drd_sw>;
+			};
+		};
+	};
 };
 
 /* Console */
@@ -267,6 +283,29 @@ &lpuart6 {
 	status = "okay";
 };
 
+&usbotg1 {
+	dr_mode = "otg";
+	hnp-disable;
+	srp-disable;
+	adp-disable;
+	usb-role-switch;
+	samsung,picophy-pre-emp-curr-control = <3>;
+	samsung,picophy-dc-vol-level-adjust = <7>;
+	status = "okay";
+
+	port {
+		usb1_drd_sw: endpoint {
+			remote-endpoint = <&typec1_dr_sw>;
+		};
+	};
+};
+
+&usbotg2 {
+	dr_mode = "host";
+	disable-over-current;
+	status = "okay";
+};
+
 /* SD */
 &usdhc2 {
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
@@ -351,6 +390,12 @@ MX93_PAD_CCM_CLKO1__GPIO3_IO26		0x31e
 		>;
 	};
 
+	pinctrl_ptn5150: ptn5150grp {
+		fsl,pins = <
+			MX93_PAD_PDM_BIT_STREAM1__GPIO1_IO10            0x31e
+		>;
+	};
+
 	pinctrl_uart1: uart1grp {
 		fsl,pins = <
 			MX93_PAD_UART1_RXD__LPUART1_RX			0x31e
-- 
2.47.3



From stefano.r at variscite.com  Fri Dec  5 10:22:57 2025
From: stefano.r at variscite.com (Stefano Radaelli)
Date: Fri,  5 Dec 2025 19:22:57 +0100
Subject: [PATCH v1 4/4] arm64: dts: imx93-var-som-symphony: Enable LPSPI6 controller
In-Reply-To: <20251205182258.50397-1-stefano.r@variscite.com>
References: <20251205182258.50397-1-stefano.r@variscite.com>
Message-ID: <20251205182258.50397-5-stefano.r@variscite.com>

Enable the LPSPI6 controller so it can be used by user applications
through the board?s expansion connector.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../dts/freescale/imx93-var-som-symphony.dts     | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx93-var-som-symphony.dts b/arch/arm64/boot/dts/freescale/imx93-var-som-symphony.dts
index ee69d6b268a4..c0842fb3cfa3 100644
--- a/arch/arm64/boot/dts/freescale/imx93-var-som-symphony.dts
+++ b/arch/arm64/boot/dts/freescale/imx93-var-som-symphony.dts
@@ -276,6 +276,13 @@ &lpuart1 {
 	status = "okay";
 };
 
+&lpspi6 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_lpspi6>;
+	cs-gpios = <&gpio2 0 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
 /* J18.7, J18.9 */
 &lpuart6 {
 	pinctrl-names = "default";
@@ -384,6 +391,15 @@ MX93_PAD_GPIO_IO22__GPIO2_IO22			0x31e
 		>;
 	};
 
+	 pinctrl_lpspi6: lpspi6grp {
+		fsl,pins = <
+			MX93_PAD_GPIO_IO00__GPIO2_IO00                  0x31e
+			MX93_PAD_GPIO_IO01__LPSPI6_SIN                  0x31e
+			MX93_PAD_GPIO_IO02__LPSPI6_SOUT                 0x31e
+			MX93_PAD_GPIO_IO03__LPSPI6_SCK                  0x31e
+		>;
+	};
+
 	pinctrl_pca9534: pca9534grp {
 		fsl,pins = <
 			MX93_PAD_CCM_CLKO1__GPIO3_IO26		0x31e
-- 
2.47.3



From arnd at arndb.de  Fri Dec  5 10:26:11 2025
From: arnd at arndb.de (Arnd Bergmann)
Date: Fri, 05 Dec 2025 19:26:11 +0100
Subject: [GIT PULL 0/6] soc: updates for 6.19
Message-ID: <334684ec-5796-47a4-b9f4-96c60f449634@app.fastmail.com>

Hi Linus,

This merge window is not quite as big as the last one for us,
but it still has 974 commits from 274 developers, mostly for
arm64 devicetree files. 

Despite the size, not much sticks out. There are six new SoC
types, with three of them being completely new platforms from
smaller companies (Tenstorrent, Black Sesame and Anlogic).

The most active developers this time, by number of patches were

     44 Frank Li
     26 Kuninori Morimoto
     26 Dmitry Baryshkov
     22 Wolfram Sang
     20 Alexander Stein
     19 Krzysztof Kozlowski
     16 Geert Uytterhoeven
     14 Richard Zhu
     14 Aaron Kling
     13 Luca Weiss
     12 Heiko Stuebner
     11 Lothar Rubusch
     11 Chen-Yu Tsai
     10 Duje Mihanovi?
     10 Cristian Cozzolino
     10 Conor Dooley
     10 Chris Morgan

Dirstat:
   0.3% Documentation/devicetree/bindings/arm/
   0.3% Documentation/devicetree/bindings/display/tegra/
   0.3% Documentation/devicetree/bindings/mmc/
   1.2% Documentation/devicetree/bindings/
   4.7% arch/arm/boot/dts/aspeed/
   1.3% arch/arm/boot/dts/intel/socfpga/
   0.3% arch/arm/boot/dts/mediatek/
   5.1% arch/arm/boot/dts/nvidia/
   0.7% arch/arm/boot/dts/nxp/imx/
   0.5% arch/arm/boot/dts/qcom/
   0.6% arch/arm/boot/dts/renesas/
   1.5% arch/arm/boot/dts/ti/omap/
   0.3% arch/arm/boot/dts/
   0.4% arch/arm/
   0.5% arch/arm64/boot/dts/allwinner/
   0.6% arch/arm64/boot/dts/amlogic/
   1.9% arch/arm64/boot/dts/cix/
   0.4% arch/arm64/boot/dts/exynos/google/
   0.3% arch/arm64/boot/dts/exynos/
   9.5% arch/arm64/boot/dts/freescale/
   0.4% arch/arm64/boot/dts/intel/
   0.5% arch/arm64/boot/dts/marvell/mmp/
  10.6% arch/arm64/boot/dts/mediatek/
   4.6% arch/arm64/boot/dts/nvidia/
  11.4% arch/arm64/boot/dts/qcom/
   5.8% arch/arm64/boot/dts/renesas/
   6.7% arch/arm64/boot/dts/rockchip/
   9.2% arch/arm64/boot/dts/ti/
   0.4% arch/arm64/boot/dts/
   0.3% arch/riscv/boot/dts/sophgo/
   1.2% arch/riscv/boot/dts/spacemit/
   0.4% arch/riscv/boot/dts/starfive/
   0.6% arch/riscv/boot/dts/
   0.3% arch/x86/kernel/
   0.5% arch/
   0.8% drivers/bus/
   0.3% drivers/cache/
   0.3% drivers/clk/
   0.6% drivers/firmware/
   0.5% drivers/irqchip/
   1.2% drivers/memory/tegra/
   2.5% drivers/reset/
   1.1% drivers/soc/qcom/
   0.5% drivers/soc/renesas/
   1.4% drivers/soc/samsung/
   0.5% drivers/soc/
   0.7% drivers/
   0.3% include/dt-bindings/clock/
   1.2% include/dt-bindings/reset/
   1.1% include/linux/soc/samsung/
   0.3% include/linux/
 982 files changed, 59312 insertions(+), 7066 deletions(-)

There was a slight delay sending it out as I was still in the
process of setting up my randconfig tests earlier this week
and I wanted to ensure everything is well tested this time.

      Arnd


From arnd at arndb.de  Fri Dec  5 10:26:47 2025
From: arnd at arndb.de (Arnd Bergmann)
Date: Fri, 05 Dec 2025 19:26:47 +0100
Subject: [GIT PULL 1/6] soc: defconfig for 6.19
In-Reply-To: <334684ec-5796-47a4-b9f4-96c60f449634@app.fastmail.com>
References: <334684ec-5796-47a4-b9f4-96c60f449634@app.fastmail.com>
Message-ID: <347a999a-037b-42f7-b4ba-b05b81207fea@app.fastmail.com>

The following changes since commit dcb6fa37fd7bc9c3d2b066329b0d27dedf8becaa:

  Linux 6.18-rc3 (2025-10-26 15:59:49 -0700)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git tags/soc-defconfig-6.19

for you to fetch changes up to 00de4ef9d3abc0b195988c23aea2fefe5f76d3c4:

  Merge tag 'riscv-config-for-v6.19' of https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux into soc/defconfig (2025-11-27 23:03:34 +0100)

----------------------------------------------------------------
soc: defconfig for 6.19

As usual, a number of newly added drivers get enabled in the arm64 defconfig,
in addition to minor housekeeping work on defconfig files for arm32, arm64 and
riscv.

----------------------------------------------------------------
Alex Elder (1):
      riscv: defconfig: enable SPI_FSL_QUADSPI as a module

Andy Yan (1):
      arm64: defconfig: Enable Rockchip extensions for Synopsys DW DP

Arnd Bergmann (10):
      Merge tag 'renesas-arm-defconfig-for-v6.19-tag1' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-devel into soc/defconfig
      Merge tag 'mtk-defconfig-for-v6.19' of https://git.kernel.org/pub/scm/linux/kernel/git/mediatek/linux into soc/defconfig
      Merge tag 'tegra-for-6.19-arm-defconfig' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into soc/defconfig
      Merge tag 'tegra-for-6.19-arm64-defconfig' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into soc/defconfig
      Merge tag 'imx-defconfig-6.19' of https://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux into soc/defconfig
      Merge tag 'at91-defconfig-6.19' of https://git.kernel.org/pub/scm/linux/kernel/git/at91/linux into soc/defconfig
      Merge tag 'omap-for-v6.19/defconfig-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-omap into soc/defconfig
      Merge tag 'qcom-arm64-defconfig-for-6.19' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux into soc/defconfig
      Merge tag 'v6.19-rockchip-defconfig64-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip into soc/defconfig
      Merge tag 'riscv-config-for-v6.19' of https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux into soc/defconfig

Claudiu Beznea (1):
      arm64: defconfig: Enable Renesas RZ/G3S thermal driver

Cosmin Tanislav (1):
      arm64: defconfig: Enable RZ/T2H / RZ/N2H ADC driver

Cristian Ciocaltea (1):
      arm64: defconfig: Enable DW HDMI QP CEC support

Dario Binacchi (1):
      ARM: mxs_defconfig: enable sound drivers for imx28-amarula-rmm

Fange Zhang (1):
      arm64: defconfig: Enable SX150x GPIO expander driver

Geert Uytterhoeven (1):
      ARM: shmobile: defconfig: Refresh for v6.18-rc1

Huang Shijie (1):
      arm64: defconfig: Remove the redundant SCHED_MC/SCHED_SMT

John Madieu (1):
      arm64: defconfig: Enable the Renesas RZ/G3E thermal driver

Jon Hunter (1):
      ARM: tegra: Enable EXT4 for Tegra

Jo?o Paulo Gon?alves (1):
      arm64: defconfig: Enable i.MX95 drivers for pinctrl, Ethernet and PCIe

Krzysztof Kozlowski (1):
      arm64: defconfig: Enable two Novatek display panels for MTP8750 and Tianma

Laurentiu Mihalcea (1):
      arm64: defconfig: enable i.MX AIPSTZ driver

Luca Weiss (1):
      arm64: defconfig: Enable configs for Fairphone 3, 4, 5 smartphones

Luo Jie (1):
      arm64: defconfig: Build NSS clock controller driver for IPQ5424

Macpaul Lin (1):
      arm64: defconfig: Enable UFS support for MediaTek Genio 1200 EVK UFS board

Manikandan Muralidharan (1):
      ARM: at91: at91_dt_defconfig: set MMC_SPI to module

Manivannan Sadhasivam (1):
      arm64: defconfig: Enable SCSI UFS Crypto and Block Inline encryption drivers

Melody Olvera (1):
      arm64: defconfig: Add M31 eUSB2 PHY config

Michael Riesch (1):
      arm64: defconfig: enable rockchip camera interface

Parvathi Pudi (1):
      ARM: multi_v7_defconfig: Enable TI PRU Ethernet driver

Shubhi Garg (1):
      arm64: defconfig: Enable NVIDIA VRS PSEQ RTC

Tudor Ambarus (1):
      arm64: defconfig: enable Exynos ACPM clocks

 arch/arm/configs/at91_dt_defconfig  |  2 +-
 arch/arm/configs/multi_v7_defconfig |  2 ++
 arch/arm/configs/mxs_defconfig      |  2 ++
 arch/arm/configs/shmobile_defconfig |  4 ++-
 arch/arm/configs/tegra_defconfig    |  4 ---
 arch/arm64/configs/defconfig        | 49 +++++++++++++++++++++++++++++++++++--
 arch/riscv/configs/defconfig        |  1 +
 7 files changed, 56 insertions(+), 8 deletions(-)


From arnd at arndb.de  Fri Dec  5 10:27:20 2025
From: arnd at arndb.de (Arnd Bergmann)
Date: Fri, 05 Dec 2025 19:27:20 +0100
Subject: [GIT PULL 2/6] soc: arm code changes for 6.19
In-Reply-To: <334684ec-5796-47a4-b9f4-96c60f449634@app.fastmail.com>
References: <334684ec-5796-47a4-b9f4-96c60f449634@app.fastmail.com>
Message-ID: <b4048b25-c1a8-4442-8594-c604bcef9e29@app.fastmail.com>

The following changes since commit dcb6fa37fd7bc9c3d2b066329b0d27dedf8becaa:

  Linux 6.18-rc3 (2025-10-26 15:59:49 -0700)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git tags/soc-arm-6.19

for you to fetch changes up to 3ce8f4a501f61edbb5cb3fe13520f09ffb33396e:

  ARM: omap1: avoid symbol clashes in fiq handler (2025-12-05 15:25:13 +0100)

----------------------------------------------------------------
soc: arm code changes for 6.19

These are very minimal changes for 32-bit Arm platform code, enabling
SMP bringup for one more SoC variant (mt6582) among spelling changes
and a build warning fix.

----------------------------------------------------------------
Ali Khan (1):
      ARM: OMAP2+: Fix falg->flag typo in omap_smc2()

Arnd Bergmann (3):
      Merge tag 'mtk-arm32-for-v6.19' of https://git.kernel.org/pub/scm/linux/kernel/git/mediatek/linux into soc/arm
      Merge tag 'omap-for-v6.19/soc-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-omap into soc/arm
      ARM: omap1: avoid symbol clashes in fiq handler

Cristian Cozzolino (2):
      ARM: mediatek: add board_dt_compat entry for the MT6582 SoC
      ARM: mediatek: add MT6582 smp bring up code

Julia Lawall (1):
      ARM: gemini: fix typos in comments

Shivam Chaudhary (1):
      ARM: versatile: Fix typo in versatile.c

 arch/arm/mach-gemini/board-dt.c             |  2 +-
 arch/arm/mach-mediatek/Kconfig              |  4 +++
 arch/arm/mach-mediatek/mediatek.c           |  1 +
 arch/arm/mach-mediatek/platsmp.c            |  1 +
 arch/arm/mach-omap1/ams-delta-fiq-handler.S | 38 ++++++++++++++---------------
 arch/arm/mach-omap2/omap-secure.h           |  2 +-
 arch/arm/mach-omap2/omap-smc.S              |  2 +-
 arch/arm/mach-versatile/versatile.c         |  2 +-
 8 files changed, 29 insertions(+), 23 deletions(-)


From arnd at arndb.de  Fri Dec  5 10:28:42 2025
From: arnd at arndb.de (Arnd Bergmann)
Date: Fri, 05 Dec 2025 19:28:42 +0100
Subject: [GIT PULL 4/6] soc: sew SoC familes for 6.19
In-Reply-To: <334684ec-5796-47a4-b9f4-96c60f449634@app.fastmail.com>
References: <334684ec-5796-47a4-b9f4-96c60f449634@app.fastmail.com>
Message-ID: <46536f6a-6225-4d5b-ba9e-5cfc64b414ac@app.fastmail.com>

The following changes since commit dcb6fa37fd7bc9c3d2b066329b0d27dedf8becaa:

  Linux 6.18-rc3 (2025-10-26 15:59:49 -0700)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git tags/soc-newsoc-6.19

for you to fetch changes up to 9b418a3bfdd421c01002424958fbd86a1001c2c2:

  Merge tag 'anlogic-initial-6.19-v2' of https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux into soc/newsoc (2025-11-21 21:29:57 +0100)

----------------------------------------------------------------
soc: sew SoC familes for 6.19

These three new families of SoC are split out into a separate branch
because they touch multiple parts of the source tree and are better
left separate for the initial merge.

 - Black Sesame Technologies C1200 is an automotive SoC using
   Cortex-A78 CPU cores

 - Anlogic dr1v90 (not to be confused with Amlogic) is an FPGA
   platform using a single nuclei ux900 RISC-V core

 - Tenstorrent Blackhole is a Neural Processing Unit using
   custom "Tensix" cores for computation offload managed by
   Linux running on SiFive X280 RISC-V cores.

Support for all three is rather rudimentary at the moment and will get
improved as device drivers are merged through other tree.

----------------------------------------------------------------
Albert Yang (6):
      dt-bindings: vendor-prefixes: Add Black Sesame Technologies Co., Ltd.
      dt-bindings: arm: add Black Sesame Technologies (bst) SoC
      arm64: Kconfig: add ARCH_BST for Black Sesame Technologies SoCs
      arm64: dts: bst: add support for Black Sesame Technologies C1200 CDCU1.0 board
      arm64: defconfig: enable BST platform support
      MAINTAINERS: add Black Sesame Technologies (BST) ARM SoC support

Arnd Bergmann (3):
      Merge tag 'tenstorrent-dt-for-v6.19' of https://github.com/tenstorrent/linux into soc/newsoc
      Merge branch 'bst/newsoc' into soc/newsoc
      Merge tag 'anlogic-initial-6.19-v2' of https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux into soc/newsoc

Conor Dooley (1):
      MAINTAINERS: Setup support for Anlogic tree

Drew Fustini (8):
      dt-bindings: vendor-prefixes: Add Tenstorrent AI ULC
      dt-bindings: riscv: Add Tenstorrent Blackhole compatible
      dt-bindings: riscv: cpus: Add SiFive X280 compatible
      dt-bindings: timers: Add Tenstorrent Blackhole compatible
      dt-bindings: interrupt-controller: Add Tenstorrent Blackhole compatible
      riscv: dts: Add Tenstorrent Blackhole SoC PCIe cards
      riscv: Kconfig.socs: Add ARCH_TENSTORRENT for Tenstorrent SoCs
      riscv: defconfig: Enable Tenstorrent SoCs

Junhui Liu (9):
      dt-bindings: vendor-prefixes: Add Anlogic, Milianke and Nuclei
      dt-bindings: riscv: Add Nuclei UX900 compatibles
      dt-bindings: riscv: Add Anlogic DR1V90
      dt-bindings: timer: Add Anlogic DR1V90 ACLINT MTIMER
      dt-bindings: serial: snps-dw-apb-uart: Add Anlogic DR1V90 uart
      riscv: Add Anlogic SoC famly Kconfig support
      riscv: dts: Add initial Anlogic DR1V90 SoC device tree
      riscv: dts: anlogic: Add Milianke MLKPAI FS01 board
      riscv: defconfig: Enable Anlogic SoC

 Documentation/devicetree/bindings/arm/bst.yaml     |  31 ++++++
 .../interrupt-controller/sifive,plic-1.0.0.yaml    |   1 +
 .../devicetree/bindings/riscv/anlogic.yaml         |  27 ++++++
 Documentation/devicetree/bindings/riscv/cpus.yaml  |   2 +
 .../devicetree/bindings/riscv/tenstorrent.yaml     |  28 ++++++
 .../bindings/serial/snps-dw-apb-uart.yaml          |   1 +
 .../devicetree/bindings/timer/sifive,clint.yaml    |   1 +
 .../bindings/timer/thead,c900-aclint-mtimer.yaml   |  17 ++--
 .../devicetree/bindings/vendor-prefixes.yaml       |  10 ++
 MAINTAINERS                                        |  25 +++++
 arch/arm64/Kconfig.platforms                       |   8 ++
 arch/arm64/boot/dts/Makefile                       |   1 +
 arch/arm64/boot/dts/bst/Makefile                   |   2 +
 .../boot/dts/bst/bstc1200-cdcu1.0-adas_4c2g.dts    |  24 +++++
 arch/arm64/boot/dts/bst/bstc1200.dtsi              |  97 ++++++++++++++++++
 arch/arm64/configs/defconfig                       |   1 +
 arch/riscv/Kconfig.socs                            |  13 +++
 arch/riscv/boot/dts/Makefile                       |   2 +
 arch/riscv/boot/dts/anlogic/Makefile               |   2 +
 arch/riscv/boot/dts/anlogic/dr1v90-mlkpai-fs01.dts |  28 ++++++
 arch/riscv/boot/dts/anlogic/dr1v90.dtsi            | 100 +++++++++++++++++++
 arch/riscv/boot/dts/tenstorrent/Makefile           |   2 +
 arch/riscv/boot/dts/tenstorrent/blackhole-card.dts |  14 +++
 arch/riscv/boot/dts/tenstorrent/blackhole.dtsi     | 108 +++++++++++++++++++++
 arch/riscv/configs/defconfig                       |   2 +
 25 files changed, 541 insertions(+), 6 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/bst.yaml
 create mode 100644 Documentation/devicetree/bindings/riscv/anlogic.yaml
 create mode 100644 Documentation/devicetree/bindings/riscv/tenstorrent.yaml
 create mode 100644 arch/arm64/boot/dts/bst/Makefile
 create mode 100644 arch/arm64/boot/dts/bst/bstc1200-cdcu1.0-adas_4c2g.dts
 create mode 100644 arch/arm64/boot/dts/bst/bstc1200.dtsi
 create mode 100644 arch/riscv/boot/dts/anlogic/Makefile
 create mode 100644 arch/riscv/boot/dts/anlogic/dr1v90-mlkpai-fs01.dts
 create mode 100644 arch/riscv/boot/dts/anlogic/dr1v90.dtsi
 create mode 100644 arch/riscv/boot/dts/tenstorrent/Makefile
 create mode 100644 arch/riscv/boot/dts/tenstorrent/blackhole-card.dts
 create mode 100644 arch/riscv/boot/dts/tenstorrent/blackhole.dtsi


From arnd at arndb.de  Fri Dec  5 10:29:18 2025
From: arnd at arndb.de (Arnd Bergmann)
Date: Fri, 05 Dec 2025 19:29:18 +0100
Subject: [GIT PULL 5/6] soc: driver updates for 6.19
In-Reply-To: <334684ec-5796-47a4-b9f4-96c60f449634@app.fastmail.com>
References: <334684ec-5796-47a4-b9f4-96c60f449634@app.fastmail.com>
Message-ID: <dceb9f99-cb69-498f-9717-34e3f28c8fc1@app.fastmail.com>

The following changes since commit 3a8660878839faadb4f1a6dd72c3179c1df56787:

  Linux 6.18-rc1 (2025-10-12 13:42:36 -0700)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git tags/soc-drivers-6.19

for you to fetch changes up to 4b1e81570144f03521482f7659fee060d8f63481:

  Merge tag 'mtk-soc-for-v6.19' of https://git.kernel.org/pub/scm/linux/kernel/git/mediatek/linux into soc/drivers (2025-11-25 14:52:14 +0100)

----------------------------------------------------------------
soc: driver updates for 6.19

This is the first half of the driver changes:

 - A treewide interface change to the "syscore" operations for
   power management, as a preparation for future Tegra specific
   changes.

 - Reset controller updates with added drivers for LAN969x, eic770
   and RZ/G3S SoCs.

 - Protection of system controller registers on Renesas and Google SoCs,
   to prevent trivially triggering a system crash from e.g. debugfs
   access.

 - soc_device identification updates on Nvidia, Exynos and Mediatek

 - debugfs support in the ST STM32 firewall driver

 - Minor updates for SoC drivers on AMD/Xilinx, Renesas,  Allwinner, TI

 - Cleanups for memory controller support on Nvidia and Renesas

----------------------------------------------------------------
Aaron Kling (2):
      soc/tegra: fuse: speedo-tegra210: Update speedo IDs
      soc/tegra: fuse: speedo-tegra210: Add SoC speedo 2

Abel Vesa (1):
      soc: qcom: ubwc: Add configuration Glymur platform

Akhil P Oommen (1):
      soc: qcom: ubwc: Add config for Kaanapali

Alexandru Chimac (2):
      dt-bindings: hwinfo: samsung,exynos-chipid: add exynos9610 compatible
      soc: samsung: exynos-chipid: Add exynos9610 SoC support

Andr? Draszik (4):
      soc: samsung: exynos-pmu: allow specifying read & write access tables for secure regmap
      soc: samsung: exynos-pmu: move some gs101 related code into new file
      soc: samsung: gs101-pmu: implement access tables for read and write
      dt-bindings: soc: samsung: exynos-sysreg: add power-domains

Anjelique Melendez (1):
      soc: qcom: pmic_glink: Add support for SOCCP remoteproc channels

Arnd Bergmann (17):
      Merge tag 'zynqmp-soc-for-6.18' of https://github.com/Xilinx/linux-xlnx into soc/drivers
      Merge tag 'renesas-drivers-for-v6.19-tag1' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-devel into soc/drivers
      Merge tag 'memory-controller-drv-6.19-2' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl into soc/drivers
      Merge tag 'samsung-drivers-6.19' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux into soc/drivers
      Merge tag 'renesas-drivers-for-v6.19-tag2' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-devel into soc/drivers
      Merge tag 'tegra-for-6.19-core' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into soc/drivers
      Merge tag 'tegra-for-6.19-syscore' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into soc/drivers
      Merge tag 'tegra-for-6.19-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into soc/drivers
      Merge tag 'sunxi-drivers-for-6.19' of https://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux into soc/drivers
      Merge tag 'imx-drivers-6.19' of https://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux into soc/drivers
      Merge tag 'ti-driver-soc-for-v6.19' of https://git.kernel.org/pub/scm/linux/kernel/git/ti/linux into soc/drivers
      Merge tag 'omap-for-v6.19/drivers-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-omap into soc/drivers
      Merge tag 'qcom-drivers-for-6.19' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux into soc/drivers
      Merge tag 'v6.19-rockchip-drivers1' of git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip into soc/drivers
      Merge tag 'stm32-bus-firewall-for-v6.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/atorgue/stm32 into soc/drivers
      Merge tag 'reset-for-v6.19' of https://git.pengutronix.de/git/pza/linux into soc/drivers
      Merge tag 'mtk-soc-for-v6.19' of https://git.kernel.org/pub/scm/linux/kernel/git/mediatek/linux into soc/drivers

Bartosz Golaszewski (2):
      clk: davinci: psc: drop unused reset lookup
      reset: remove legacy reset lookup code

Biju Das (1):
      memory: renesas-rpc-if: Add suspend/resume support

Bruno Sobreira Fran?a (1):
      soc/tegra: Resolve a spelling error in the tegra194-cbb.c

Christian Marangi (2):
      err.h: add INIT_ERR_PTR() macro
      soc: qcom: smem: better track SMEM uninitialized state

Claudiu Beznea (5):
      soc: renesas: r9a09g056-sys: Populate max_register
      soc: renesas: rz-sysc: Populate readable_reg/writeable_reg in regmap config
      dt-bindings: reset: renesas,rzg2l-usbphy-ctrl: Document RZ/G3S support
      reset: rzg2l-usbphy-ctrl: Add support for USB PWRRDY
      reset: rzg2l-usbphy-ctrl: Add support for RZ/G3S SoC

Dan Carpenter (1):
      reset: rzg2l-usbphy-ctrl: Fix a NULL vs IS_ERR() bug in probe

Denzeel Oliva (1):
      dt-bindings: soc: samsung: exynos-sysreg: Add Exynos990 PERIC0/1 compatibles

Encrow Thorne (1):
      reset: fix BIT macro reference

Gabor Juhos (2):
      soc: qcom: mdt_loader: merge __qcom_mdt_load() and qcom_mdt_load_no_init()
      soc: qcom: mdt_loader: rename 'firmware' parameter of qcom_mdt_load()

Gatien Chevallier (2):
      dt-bindings: bus: add stm32mp21 RIFSC compatible
      bus: rifsc: add debugfs entry to dump the firewall configuration

Haotian Zhang (2):
      soc: qcom: gsbi: fix double disable caused by devm
      soc: qcom: smem: fix hwspinlock resource leak in probe error paths

Haotien Hsu (1):
      soc/tegra: pmc: Add USB wake events for Tegra234

Heiko Stuebner (1):
      soc: rockchip: grf: Add select correct PWM implementation on RK3368

Ivaylo Ivanov (3):
      dt-bindings: soc: samsung: exynos-pmu: add exynos8890 compatible
      dt-bindings: hwinfo: samsung,exynos-chipid: add exynos8890-chipid compatible
      soc: samsung: exynos-chipid: add exynos8890 SoC support

Jay Buddhabhatti (3):
      firmware: xilinx: Add Versal NET platform compatible string
      drivers: firmware: xilinx: Add unique family code for all platforms
      drivers: firmware: xilinx: Switch to new family code in zynqmp_pm_get_family_info()

Jingyi Wang (6):
      dt-bindings: cache: qcom,llcc: Document the Kaanapali LLCC
      soc: qcom: llcc-qcom: Add support for Kaanapali
      dt-bindings: arm: qcom,ids: Add SoC ID for SM8850
      soc: qcom: socinfo: Add SM8850 SoC ID
      dt-bindings: soc: qcom,aoss-qmp: Document the Kaanapali AOSS channel
      dt-bindings: firmware: qcom,scm: Document SCM on Kaanapali SOC

Johan Hovold (3):
      soc: qcom: ocmem: fix device leak on lookup
      soc: qcom: pbs: fix device leak on lookup
      amba: tegra-ahb: Fix device leak on SMMU enable

Jon Hunter (1):
      memory: tegra186-emc: Fix missing put_bpmp

Kartik Rajput (1):
      soc/tegra: fuse: Do not register SoC device on ACPI boot

Kathiravan Thirumoorthy (4):
      soc: qcom: socinfo: arrange the socinfo_image_names array in alphabetical order
      soc: qcom: socinfo: add the missing entries to the smem image table
      soc: qcom: smem: drop the WARN_ON() on SMEM item validation
      soc: qcom: socinfo: add support to extract more than 32 image versions

Kaustabh Chakraborty (2):
      dt-bindings: samsung: exynos-sysreg: add exynos7870 sysregs
      dt-bindings: soc: samsung: exynos-pmu: allow mipi-phy subnode for Exynos7870 PMU

Komal Bajaj (2):
      dt-bindings: arm: qcom,ids: Add SoC ID for QCS6490
      soc: qcom: socinfo: Add SoC ID for QCS6490

Krzysztof Kozlowski (14):
      memory: tegra124-emc: Simplify return of emc_init()
      memory: tegra124-emc: Do not print error on icc_node_create() failure
      memory: tegra186-emc: Do not print error on icc_node_create() failure
      memory: tegra20-emc: Do not print error on icc_node_create() failure
      memory: tegra30-emc: Do not print error on icc_node_create() failure
      memory: tegra30-emc: Simplify and handle deferred probe with dev_err_probe()
      memory: tegra20-emc: Simplify and handle deferred probe with dev_err_probe()
      memory: tegra186-emc: Simplify and handle deferred probe with dev_err_probe()
      memory: tegra124-emc: Simplify and handle deferred probe with dev_err_probe()
      memory: tegra124-emc: Add the SoC model prefix to functions
      memory: tegra186-emc: Add the SoC model prefix to functions
      memory: tegra20-emc: Add the SoC model prefix to functions
      memory: tegra30-emc: Add the SoC model prefix to functions
      soc: samsung: exynos-pmu: Annotate online/offline functions with __must_hold

Louis-Alexis Eyraud (2):
      soc: mediatek: mtk-socinfo: Add entry for MT8391AV/AZA Genio 720
      dt-bindings: soc: mediatek: pwrap: Add compatible for MT8189 SoC

Madhav Bhatt (1):
      firmware: xilinx: Add debugfs support for PM_GET_NODE_STATUS

Markus Schneider-Pargmann (TI.com) (2):
      firmware: ti_sci: Support transfers without response
      firmware: ti_sci: Partial-IO support

Matthias Schiffer (1):
      ti-sysc: allow OMAP2 and OMAP4 timers to be reserved on AM33xx

Mukesh Ojha (2):
      soc: qcom: socinfo: Add support for new fields in revision 20
      soc: qcom: socinfo: Add reserve field to support future extension

Neeraj Soni (1):
      soc: qcom: ice: Add HWKM v1 support for wrapped keys

Pankaj Patil (1):
      dt-bindings: firmware: qcom,scm: Document Glymur scm

Peng Fan (8):
      firmware: imx: scu-irq: fix OF node leak in
      firmware: imx: scu-irq: Free mailbox client on failure at imx_scu_enable_general_irq_channel()
      firmware: imx: scu-irq: Init workqueue before request mbox channel
      firmware: imx: scu-irq: Set mu_resource_id before get handle
      firmware: imx: scu-irq: Remove unused export of imx_scu_enable_general_irq_channel
      firmware: imx: scu: Update error code
      firmware: imx: scu: Suppress bind attrs
      firmware: imx: scu: Use devm_mutex_init

Peter Griffin (1):
      dt-bindings: soc: samsung: exynos-sysreg: add gs101 hsi0 and misc compatibles

Prasad Kumpatla (1):
      soc: qcom: pd-mapper: Add Kaanapali compatible

Prathamesh Shete (1):
      soc/tegra: pmc: Don't fail if "aotag" is not present

Randy Dunlap (1):
      firmware: qcom: tzmem: fix qcom_tzmem_policy kernel-doc

Robert Marko (2):
      dt-bindings: reset: microchip: Add LAN969x support
      reset: sparx5: add LAN969x support

Sakari Ailus (1):
      bus: sunxi-rsb: Remove redundant pm_runtime_mark_last_busy() calls

Sibi Sankar (1):
      dt-bindings: soc: qcom,aoss-qmp: Document the Glymur AOSS side channel

Sirius Wang (1):
      soc: mediatek: mtk-socinfo: Add extra entry for MT8189

Thierry Reding (2):
      syscore: Pass context data to callbacks
      soc/tegra: pmc: Document tegra_pmc.syscore field

Thomas Richard (TI.com) (2):
      firmware: ti_sci: Replace ifdeffery by pm_sleep_ptr() macro
      firmware: ti_sci: Set IO Isolation only if the firmware is capable

Tudor Ambarus (1):
      soc: samsung: exynos-chipid: use a local dev variable

WeiHao Li (1):
      soc: rockchip: grf: Set pwm2/xin32k pad default to xin32k for rk3368

Wolfram Sang (1):
      soc: renesas: rcar-rst: Keep RESBAR2S in default state

Xuyang Dong (2):
      dt-bindings: reset: eswin: Documentation for eic7700 SoC
      reset: eswin: Add eic7700 reset driver

Yao Zi (4):
      dt-bindings: reset: thead,th1520-reset: Remove non-VO-subsystem resets
      dt-bindings: reset: thead,th1520-reset: Add controllers for more subsys
      reset: th1520: Prepare for supporting multiple controllers
      reset: th1520: Support reset controllers in more subsystems

Yongxing Mou (1):
      soc: qcom: ubwc: Add QCS8300 UBWC cfg

Yue Haibing (1):
      Documentation: reset: Remove reset_controller_add_lookup()

 .../bindings/bus/st,stm32mp25-rifsc.yaml           |   8 +-
 .../devicetree/bindings/cache/qcom,llcc.yaml       |   2 +
 .../devicetree/bindings/firmware/qcom,scm.yaml     |   3 +
 .../bindings/hwinfo/samsung,exynos-chipid.yaml     |   2 +
 .../bindings/reset/eswin,eic7700-reset.yaml        |  42 ++
 .../devicetree/bindings/reset/microchip,rst.yaml   |  11 +-
 .../bindings/reset/renesas,rzg2l-usbphy-ctrl.yaml  |  41 +-
 .../bindings/reset/thead,th1520-reset.yaml         |   8 +-
 .../bindings/soc/mediatek/mediatek,pwrap.yaml      |   1 +
 .../bindings/soc/qcom/qcom,aoss-qmp.yaml           |   2 +
 .../bindings/soc/samsung/exynos-pmu.yaml           |   2 +
 .../soc/samsung/samsung,exynos-sysreg.yaml         |  23 +
 Documentation/driver-api/reset.rst                 |   1 -
 MAINTAINERS                                        |   1 +
 arch/arm/mach-exynos/mcpm-exynos.c                 |  12 +-
 arch/arm/mach-exynos/suspend.c                     |  48 +-
 arch/arm/mach-pxa/generic.h                        |   6 +-
 arch/arm/mach-pxa/irq.c                            |  10 +-
 arch/arm/mach-pxa/mfp-pxa2xx.c                     |  10 +-
 arch/arm/mach-pxa/mfp-pxa3xx.c                     |  10 +-
 arch/arm/mach-pxa/pxa25x.c                         |   4 +-
 arch/arm/mach-pxa/pxa27x.c                         |   4 +-
 arch/arm/mach-pxa/pxa3xx.c                         |   4 +-
 arch/arm/mach-pxa/smemc.c                          |  12 +-
 arch/arm/mach-s3c/irq-pm-s3c64xx.c                 |  12 +-
 arch/arm/mach-s5pv210/pm.c                         |  10 +-
 arch/arm/mach-versatile/integrator_ap.c            |  12 +-
 arch/arm/mm/cache-b15-rac.c                        |  12 +-
 arch/loongarch/kernel/smp.c                        |  12 +-
 arch/mips/alchemy/common/dbdma.c                   |  12 +-
 arch/mips/alchemy/common/irq.c                     |  24 +-
 arch/mips/alchemy/common/usb.c                     |  12 +-
 arch/mips/pci/pci-alchemy.c                        |  16 +-
 arch/powerpc/platforms/cell/spu_base.c             |  10 +-
 arch/powerpc/platforms/powermac/pic.c              |  12 +-
 arch/powerpc/sysdev/fsl_lbc.c                      |  12 +-
 arch/powerpc/sysdev/fsl_pci.c                      |  12 +-
 arch/powerpc/sysdev/ipic.c                         |  12 +-
 arch/powerpc/sysdev/mpic.c                         |  14 +-
 arch/powerpc/sysdev/mpic_timer.c                   |  10 +-
 arch/sh/mm/pmb.c                                   |  10 +-
 arch/x86/events/amd/ibs.c                          |  12 +-
 arch/x86/hyperv/hv_init.c                          |  12 +-
 arch/x86/kernel/amd_gart_64.c                      |  10 +-
 arch/x86/kernel/apic/apic.c                        |  12 +-
 arch/x86/kernel/apic/io_apic.c                     |  17 +-
 arch/x86/kernel/cpu/aperfmperf.c                   |  20 +-
 arch/x86/kernel/cpu/intel_epb.c                    |  16 +-
 arch/x86/kernel/cpu/mce/core.c                     |  14 +-
 arch/x86/kernel/cpu/microcode/core.c               |  15 +-
 arch/x86/kernel/cpu/mtrr/legacy.c                  |  12 +-
 arch/x86/kernel/cpu/umwait.c                       |  10 +-
 arch/x86/kernel/i8237.c                            |  10 +-
 arch/x86/kernel/i8259.c                            |  14 +-
 arch/x86/kernel/kvm.c                              |  12 +-
 drivers/acpi/pci_link.c                            |  10 +-
 drivers/acpi/sleep.c                               |  12 +-
 drivers/amba/tegra-ahb.c                           |   1 +
 drivers/base/firmware_loader/main.c                |  12 +-
 drivers/base/syscore.c                             |  82 +-
 drivers/bus/mvebu-mbus.c                           |  16 +-
 drivers/bus/stm32_rifsc.c                          | 597 ++++++++++++++-
 drivers/bus/sunxi-rsb.c                            |   2 -
 drivers/bus/ti-sysc.c                              |  11 +-
 drivers/clk/at91/pmc.c                             |  12 +-
 drivers/clk/davinci/psc-da850.c                    |   7 -
 drivers/clk/imx/clk-vf610.c                        |  12 +-
 drivers/clk/ingenic/jz4725b-cgu.c                  |   2 +-
 drivers/clk/ingenic/jz4740-cgu.c                   |   2 +-
 drivers/clk/ingenic/jz4755-cgu.c                   |   2 +-
 drivers/clk/ingenic/jz4760-cgu.c                   |   2 +-
 drivers/clk/ingenic/jz4770-cgu.c                   |   2 +-
 drivers/clk/ingenic/jz4780-cgu.c                   |   2 +-
 drivers/clk/ingenic/pm.c                           |  14 +-
 drivers/clk/ingenic/pm.h                           |   2 +-
 drivers/clk/ingenic/tcu.c                          |  12 +-
 drivers/clk/ingenic/x1000-cgu.c                    |   2 +-
 drivers/clk/ingenic/x1830-cgu.c                    |   2 +-
 drivers/clk/mvebu/common.c                         |  12 +-
 drivers/clk/rockchip/clk-rk3288.c                  |  12 +-
 drivers/clk/samsung/clk-s5pv210-audss.c            |  12 +-
 drivers/clk/samsung/clk.c                          |  12 +-
 drivers/clk/tegra/clk-tegra210.c                   |  12 +-
 drivers/clocksource/timer-armada-370-xp.c          |  12 +-
 drivers/cpuidle/cpuidle-psci.c                     |  12 +-
 drivers/firmware/imx/imx-scu-irq.c                 |  32 +-
 drivers/firmware/imx/imx-scu.c                     |  11 +-
 drivers/firmware/ti_sci.c                          | 155 +++-
 drivers/firmware/ti_sci.h                          |   7 +
 drivers/firmware/xilinx/zynqmp-debug.c             |  13 +
 drivers/firmware/xilinx/zynqmp.c                   | 114 ++-
 drivers/gpio/gpio-mxc.c                            |  12 +-
 drivers/gpio/gpio-pxa.c                            |  12 +-
 drivers/gpio/gpio-sa1100.c                         |  12 +-
 drivers/hv/vmbus_drv.c                             |  14 +-
 drivers/iommu/amd/init.c                           |  16 +-
 drivers/iommu/intel/iommu.c                        |  12 +-
 drivers/irqchip/exynos-combiner.c                  |  14 +-
 drivers/irqchip/irq-armada-370-xp.c                |  12 +-
 drivers/irqchip/irq-bcm7038-l1.c                   |  12 +-
 drivers/irqchip/irq-gic-v3-its.c                   |  12 +-
 drivers/irqchip/irq-i8259.c                        |  12 +-
 drivers/irqchip/irq-imx-gpcv2.c                    |  16 +-
 drivers/irqchip/irq-loongson-eiointc.c             |  12 +-
 drivers/irqchip/irq-loongson-htpic.c               |  10 +-
 drivers/irqchip/irq-loongson-htvec.c               |  12 +-
 drivers/irqchip/irq-loongson-pch-lpc.c             |  12 +-
 drivers/irqchip/irq-loongson-pch-pic.c             |  12 +-
 drivers/irqchip/irq-mchp-eic.c                     |  12 +-
 drivers/irqchip/irq-mst-intc.c                     |  12 +-
 drivers/irqchip/irq-mtk-cirq.c                     |  12 +-
 drivers/irqchip/irq-renesas-rzg2l.c                |  12 +-
 drivers/irqchip/irq-sa11x0.c                       |  12 +-
 drivers/irqchip/irq-sifive-plic.c                  |  12 +-
 drivers/irqchip/irq-sun6i-r.c                      |  18 +-
 drivers/irqchip/irq-tegra.c                        |  12 +-
 drivers/irqchip/irq-vic.c                          |  12 +-
 drivers/leds/trigger/ledtrig-cpu.c                 |  14 +-
 drivers/macintosh/via-pmu.c                        |  12 +-
 drivers/memory/renesas-rpc-if.c                    |  58 +-
 drivers/memory/tegra/tegra124-emc.c                | 140 ++--
 drivers/memory/tegra/tegra186-emc.c                |  35 +-
 drivers/memory/tegra/tegra20-emc.c                 | 150 ++--
 drivers/memory/tegra/tegra30-emc.c                 | 119 ++-
 drivers/pinctrl/pinctrl-zynqmp.c                   |   7 +-
 drivers/power/reset/sc27xx-poweroff.c              |  10 +-
 drivers/reset/Kconfig                              |  13 +-
 drivers/reset/Makefile                             |   1 +
 drivers/reset/core.c                               | 124 +--
 drivers/reset/reset-eic7700.c                      | 429 +++++++++++
 drivers/reset/reset-rzg2l-usbphy-ctrl.c            |  60 ++
 drivers/reset/reset-th1520.c                       | 835 ++++++++++++++++++++-
 drivers/sh/clk/core.c                              |  10 +-
 drivers/sh/intc/core.c                             |  12 +-
 drivers/soc/bcm/brcmstb/biuctrl.c                  |  12 +-
 drivers/soc/mediatek/mtk-socinfo.c                 |   3 +
 drivers/soc/qcom/ice.c                             |  81 +-
 drivers/soc/qcom/llcc-qcom.c                       | 373 +++++++++
 drivers/soc/qcom/mdt_loader.c                      |  52 +-
 drivers/soc/qcom/ocmem.c                           |   2 +-
 drivers/soc/qcom/pmic_glink.c                      |   9 +-
 drivers/soc/qcom/qcom-pbs.c                        |   2 +
 drivers/soc/qcom/qcom_gsbi.c                       |   8 -
 drivers/soc/qcom/qcom_pd_mapper.c                  |  10 +
 drivers/soc/qcom/smem.c                            |  33 +-
 drivers/soc/qcom/socinfo.c                         | 102 ++-
 drivers/soc/qcom/ubwc_config.c                     |  24 +
 drivers/soc/renesas/r9a08g045-sysc.c               |  69 ++
 drivers/soc/renesas/r9a09g047-sys.c                |  79 ++
 drivers/soc/renesas/r9a09g056-sys.c                |  69 ++
 drivers/soc/renesas/r9a09g057-sys.c                | 101 +++
 drivers/soc/renesas/rcar-rst.c                     |   3 +-
 drivers/soc/renesas/rz-sysc.c                      |   2 +
 drivers/soc/renesas/rz-sysc.h                      |   4 +
 drivers/soc/rockchip/grf.c                         |  15 +
 drivers/soc/samsung/Makefile                       |   3 +-
 drivers/soc/samsung/exynos-chipid.c                |  18 +-
 drivers/soc/samsung/exynos-pmu.c                   | 138 +---
 drivers/soc/samsung/exynos-pmu.h                   |  37 +
 drivers/soc/samsung/gs101-pmu.c                    | 446 +++++++++++
 drivers/soc/tegra/cbb/tegra194-cbb.c               |   2 +-
 drivers/soc/tegra/fuse/fuse-tegra.c                |   2 -
 drivers/soc/tegra/fuse/speedo-tegra210.c           |  63 +-
 drivers/soc/tegra/pmc.c                            |  38 +-
 drivers/soc/xilinx/xlnx_event_manager.c            |   8 +-
 drivers/soc/xilinx/zynqmp_power.c                  |  10 +-
 drivers/thermal/intel/intel_hfi.c                  |  12 +-
 drivers/xen/xen-acpi-processor.c                   |  12 +-
 include/dt-bindings/arm/qcom,ids.h                 |   2 +
 include/dt-bindings/reset/eswin,eic7700-reset.h    | 298 ++++++++
 include/dt-bindings/reset/thead,th1520-reset.h     | 219 +++++-
 include/linux/err.h                                |   8 +
 include/linux/firmware/qcom/qcom_tzmem.h           |  15 +-
 include/linux/firmware/xlnx-zynqmp.h               |  30 +-
 include/linux/reset-controller.h                   |  33 -
 include/linux/reset.h                              |   1 +
 include/linux/soc/qcom/llcc-qcom.h                 |   7 +
 include/linux/soc/qcom/socinfo.h                   |   4 +
 include/linux/soc/qcom/ubwc.h                      |   1 +
 include/linux/soc/samsung/exynos-regs-pmu.h        | 343 ++++++++-
 include/linux/syscore_ops.h                        |  15 +-
 kernel/cpu_pm.c                                    |  12 +-
 kernel/irq/generic-chip.c                          |  14 +-
 kernel/irq/pm.c                                    |  11 +-
 kernel/printk/printk.c                             |  11 +-
 kernel/time/sched_clock.c                          |  22 +-
 kernel/time/timekeeping.c                          |  22 +-
 virt/kvm/kvm_main.c                                |  18 +-
 188 files changed, 5896 insertions(+), 1290 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/reset/eswin,eic7700-reset.yaml
 create mode 100644 drivers/reset/reset-eic7700.c
 create mode 100644 drivers/soc/samsung/gs101-pmu.c
 create mode 100644 include/dt-bindings/reset/eswin,eic7700-reset.h


From arnd at arndb.de  Fri Dec  5 10:33:21 2025
From: arnd at arndb.de (Arnd Bergmann)
Date: Fri, 05 Dec 2025 19:33:21 +0100
Subject: [GIT PULL 6/6] soc: driver updates for 6.19, part 2
In-Reply-To: <334684ec-5796-47a4-b9f4-96c60f449634@app.fastmail.com>
References: <334684ec-5796-47a4-b9f4-96c60f449634@app.fastmail.com>
Message-ID: <16f9deb7-8717-4983-99b7-91a6e84eb560@app.fastmail.com>

The following changes since commit 6a23ae0a96a600d1d12557add110e0bb6e32730c:

  Linux 6.18-rc6 (2025-11-16 14:25:38 -0800)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git tags/soc-drivers-6.19-2

for you to fetch changes up to 68f9bbf4dfc356ccc6586ba6e7dd79576c48f7f0:

  Merge tag 'samsung-drivers-6.19-2-late' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux into soc/drivers-late (2025-12-05 15:31:33 +0100)

----------------------------------------------------------------
soc: driver updates for 6.19, part 2

These updates came a little late, or were based on a later 6.18-rc
tag than the others:

 - A new driver for cache management on cxl devices with memory shared
   in a coherent cluster. This is part of the drivers/cache/ tree, but
   unlike the other drivers that back the dma-mapping interfaces, this
   one is needed only during CPU hotplug.

 - A shared branch for reset controllers using swnode infrastructure

 - Added support for new SoC variants in the Amlogic soc_device
   identification

 - Minor updates in Freescale, Microchip, Samsung, and Apple SoC drivers

----------------------------------------------------------------
Arnd Bergmann (8):
      Merge tag 'reset-gpio-for-v6.19' of https://git.pengutronix.de/git/pza/linux into soc/drivers-late
      Merge tag 'reset-gpio-for-v6.19-2' of https://git.pengutronix.de/git/pza/linux into soc/drivers-late
      Merge tag 'amlogic-drivers-for-v6.19' of https://git.kernel.org/pub/scm/linux/kernel/git/amlogic/linux into soc/drivers-late
      Merge tag 'soc_fsl-6.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/chleroy/linux into soc/drivers-late
      Merge tag 'apple-soc-drivers-6.19' of https://git.kernel.org/pub/scm/linux/kernel/git/sven/linux into soc/drivers-late
      Merge tag 'soc-drivers-for-v6.19' of https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux into soc/drivers-late
      Merge tag 'cache-for-v6.19' of https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux into soc/drivers-late
      Merge tag 'samsung-drivers-6.19-2-late' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux into soc/drivers-late

Bartosz Golaszewski (9):
      software node: read the reference args via the fwnode API
      software node: increase the reference of the swnode by its fwnode
      software node: allow referencing firmware nodes
      gpio: swnode: allow referencing GPIO chips by firmware nodes
      reset: order includes alphabetically in reset/core.c
      reset: make the provider of reset-gpios the parent of the reset device
      reset: gpio: convert the driver to using the auxiliary bus
      reset: gpio: use software nodes to setup the GPIO lookup
      platform/x86: intel: chtwc_int33fe: don't dereference swnode args

Charles Keepax (1):
      spi: cs42l43: Use actual ACPI firmware node for chip selects

Christophe Leroy (CS GROUP) (1):
      MAINTAINERS: Update email address for Christophe Leroy

Conor Dooley (4):
      dt-bindings: soc: microchip: document the simple-mfd syscon on PolarFire SoC
      soc: microchip: add mfd drivers for two syscon regions on PolarFire SoC
      MAINTAINERS: add new soc drivers to Microchip RISC-V entry
      MAINTAINERS: rename Microchip RISC-V entry

Gongwei Li (1):
      soc: fsl: qbman: use kmalloc_array() instead of kmalloc()

Johan Hovold (5):
      soc: apple: mailbox: fix device leak on lookup
      soc: apple: sart: drop device reference after lookup
      soc: amlogic: canvas: fix device leak on lookup
      soc: amlogic: canvas: simplify lookup error handling
      soc: samsung: exynos-pmu: fix device leak on regmap lookup

Jonathan Cameron (4):
      memregion: Drop unused IORES_DESC_* parameter from cpu_cache_invalidate_memregion()
      arm64: Select GENERIC_CPU_CACHE_MAINTENANCE
      MAINTAINERS: Add Jonathan Cameron to drivers/cache and add lib/cache_maint.c + header
      cache: Make top level Kconfig menu a boolean dependent on RISCV

Lukas Bulwahn (1):
      MAINTAINERS: refer to intended file in STANDALONE CACHE CONTROLLER DRIVERS

Marco Crivellari (1):
      soc: fsl: qbman: add WQ_PERCPU to alloc_workqueue users

Marek Szyprowski (1):
      soc: samsung: exynos-pmu: Fix structure initialization

Pierre-Henry Moussay (1):
      dt-bindings: cache: sifive,ccache0: add a pic64gx compatible

Xianwei Zhao (2):
      dt-bindings: arm: amlogic: meson-gx-ao-secure: support more SoCs
      soc: amlogic: meson-gx-socinfo: add new SoCs id

Yicong Yang (2):
      memregion: Support fine grained invalidate by cpu_cache_invalidate_memregion()
      lib: Support ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION

Yushan Wang (1):
      cache: Support cache maintenance for HiSilicon SoC Hydra Home Agent

 .mailmap                                           |   3 +
 .../arm/amlogic/amlogic,meson-gx-ao-secure.yaml    |   3 +
 .../devicetree/bindings/cache/sifive,ccache0.yaml  |   5 +
 .../microchip/microchip,mpfs-mss-top-sysreg.yaml   |  47 +++++
 MAINTAINERS                                        |  17 +-
 arch/arm64/Kconfig                                 |   2 +
 arch/x86/mm/pat/set_memory.c                       |   2 +-
 drivers/base/swnode.c                              |  30 +++-
 drivers/cache/Kconfig                              |  37 +++-
 drivers/cache/Makefile                             |   2 +
 drivers/cache/hisi_soc_hha.c                       | 194 +++++++++++++++++++++
 drivers/cxl/core/region.c                          |   5 +-
 drivers/gpio/gpiolib-swnode.c                      |   3 +-
 drivers/nvdimm/region.c                            |   2 +-
 drivers/nvdimm/region_devs.c                       |   2 +-
 drivers/platform/x86/intel/chtwc_int33fe.c         |  29 ++-
 drivers/reset/Kconfig                              |   1 +
 drivers/reset/core.c                               | 138 +++++++++------
 drivers/reset/reset-gpio.c                         |  19 +-
 drivers/soc/amlogic/meson-canvas.c                 |  12 +-
 drivers/soc/amlogic/meson-gx-socinfo.c             |   6 +
 drivers/soc/apple/mailbox.c                        |  15 +-
 drivers/soc/apple/sart.c                           |  13 +-
 drivers/soc/fsl/qbman/qman.c                       |   2 +-
 drivers/soc/fsl/qbman/qman_test_stash.c            |   2 +-
 drivers/soc/microchip/Kconfig                      |  12 ++
 drivers/soc/microchip/Makefile                     |   1 +
 drivers/soc/microchip/mpfs-control-scb.c           |  38 ++++
 drivers/soc/microchip/mpfs-mss-top-sysreg.c        |  44 +++++
 drivers/soc/samsung/exynos-pmu.c                   |   9 +-
 drivers/spi/spi-cs42l43.c                          |  40 ++---
 include/linux/cache_coherency.h                    |  61 +++++++
 include/linux/memregion.h                          |  16 +-
 include/linux/property.h                           |  13 +-
 lib/Kconfig                                        |   3 +
 lib/Makefile                                       |   2 +
 lib/cache_maint.c                                  | 138 +++++++++++++++
 37 files changed, 805 insertions(+), 163 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/soc/microchip/microchip,mpfs-mss-top-sysreg.yaml
 create mode 100644 drivers/cache/hisi_soc_hha.c
 create mode 100644 drivers/soc/microchip/mpfs-control-scb.c
 create mode 100644 drivers/soc/microchip/mpfs-mss-top-sysreg.c
 create mode 100644 include/linux/cache_coherency.h
 create mode 100644 lib/cache_maint.c


From royluo at google.com  Fri Dec  5 10:47:57 2025
From: royluo at google.com (Roy Luo)
Date: Fri, 5 Dec 2025 10:47:57 -0800
Subject: [PATCH v8 1/2] dt-bindings: phy: google: Add Google Tensor G5 USB PHY
In-Reply-To: <18eeb1c5-d21b-4505-b6a4-472f6e191864@kernel.org>
References: <20251205-phyb4-v8-0-c59ea80a4458@google.com> <20251205-phyb4-v8-1-c59ea80a4458@google.com>
 <18eeb1c5-d21b-4505-b6a4-472f6e191864@kernel.org>
Message-ID: <CA+zupgwa+m8Pa=+8shORaOA1OO6zoo6zYEojFS2UDuP0doBq7A@mail.gmail.com>

On Fri, Dec 5, 2025 at 9:13?AM Krzysztof Kozlowski <krzk at kernel.org> wrote:
>
> On 05/12/2025 04:54, Roy Luo wrote:
> > Document the device tree bindings for the USB PHY interfaces integrated
> > with the DWC3 controller on Google Tensor SoCs, starting with G5
> > generation (Laguna). The USB PHY on Tensor G5 includes two integrated
> > Synopsys PHY IPs: the eUSB 2.0 PHY IP and the USB 3.2/DisplayPort combo
> > PHY IP.
> >
> > Due to a complete architectural overhaul in the Google Tensor G5, the
> > existing Samsung/Exynos USB PHY binding for older generations of Google
> > silicons such as gs101 are no longer compatible, necessitating this new
> > device tree binding.
> >
> > Signed-off-by: Roy Luo <royluo at google.com>
>
> Why intentionally dropping the tag? How are you handling this patchset?
> Rewrite every time from scratch?

Hi Krzysztof,

I dropped the tag because a new file is being modified in this version,
Although it's just MAINTAINER file but I thought you might also want
to take a look. I wasn't sure if modifying a new file qualifies as
"substantial" so I erred on the side of caution. I should've called it
out specifically in the change log. Sorry for the inconvenience.

Regards,
Roy Luo

>
> <form letter>
> This is a friendly reminder during the review process.
>
> It looks like you received a tag and forgot to add it.
>
> If you do not know the process, here is a short explanation:
> Please add Acked-by/Reviewed-by/Tested-by tags when posting new versions
> of patchset, under or above your Signed-off-by tag, unless patch changed
> significantly (e.g. new properties added to the DT bindings). Tag is
> "received", when provided in a message replied to you on the mailing
> list. Tools like b4 can help here. However, there's no need to repost
> patches *only* to add the tags. The upstream maintainer will do that for
> tags received on the version they apply.
>
> Please read:
> https://elixir.bootlin.com/linux/v6.12-rc3/source/Documentation/process/submitting-patches.rst#L577
>
> If a tag was not added on purpose, please state why and what changed.
> </form letter>
>
> Best regards,
> Krzysztof


From krzk at kernel.org  Fri Dec  5 10:52:28 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 5 Dec 2025 19:52:28 +0100
Subject: [PATCH v8 1/2] dt-bindings: phy: google: Add Google Tensor G5 USB
 PHY
In-Reply-To: <CA+zupgwa+m8Pa=+8shORaOA1OO6zoo6zYEojFS2UDuP0doBq7A@mail.gmail.com>
References: <20251205-phyb4-v8-0-c59ea80a4458@google.com>
 <20251205-phyb4-v8-1-c59ea80a4458@google.com>
 <18eeb1c5-d21b-4505-b6a4-472f6e191864@kernel.org>
 <CA+zupgwa+m8Pa=+8shORaOA1OO6zoo6zYEojFS2UDuP0doBq7A@mail.gmail.com>
Message-ID: <f32e0810-56f9-417e-abf6-0cc7b361bd15@kernel.org>

On 05/12/2025 19:47, Roy Luo wrote:
> On Fri, Dec 5, 2025 at 9:13?AM Krzysztof Kozlowski <krzk at kernel.org> wrote:
>>
>> On 05/12/2025 04:54, Roy Luo wrote:
>>> Document the device tree bindings for the USB PHY interfaces integrated
>>> with the DWC3 controller on Google Tensor SoCs, starting with G5
>>> generation (Laguna). The USB PHY on Tensor G5 includes two integrated
>>> Synopsys PHY IPs: the eUSB 2.0 PHY IP and the USB 3.2/DisplayPort combo
>>> PHY IP.
>>>
>>> Due to a complete architectural overhaul in the Google Tensor G5, the
>>> existing Samsung/Exynos USB PHY binding for older generations of Google
>>> silicons such as gs101 are no longer compatible, necessitating this new
>>> device tree binding.
>>>
>>> Signed-off-by: Roy Luo <royluo at google.com>
>>
>> Why intentionally dropping the tag? How are you handling this patchset?
>> Rewrite every time from scratch?
> 
> Hi Krzysztof,
> 
> I dropped the tag because a new file is being modified in this version,
> Although it's just MAINTAINER file but I thought you might also want
> to take a look. I wasn't sure if modifying a new file qualifies as
> "substantial" so I erred on the side of caution. I should've called it
> out specifically in the change log. Sorry for the inconvenience.

1. so just squeeze that change into second patch and no need to ask for
re-review
2. You did not read my complain fully, look:

> 
> Regards,
> Roy Luo
> 
>>
>> <form letter>
>> This is a friendly reminder during the review process.
>>
>> It looks like you received a tag and forgot to add it.
>>
>> If you do not know the process, here is a short explanation:
>> Please add Acked-by/Reviewed-by/Tested-by tags when posting new versions
>> of patchset, under or above your Signed-off-by tag, unless patch changed
>> significantly (e.g. new properties added to the DT bindings). Tag is
>> "received", when provided in a message replied to you on the mailing
>> list. Tools like b4 can help here. However, there's no need to repost
>> patches *only* to add the tags. The upstream maintainer will do that for
>> tags received on the version they apply.
>>
>> Please read:
>> https://elixir.bootlin.com/linux/v6.12-rc3/source/Documentation/process/submitting-patches.rst#L577
>>
>> If a tag was not added on purpose, please state why and what changed.

Where did you address this? You dropped the tag silently.


Best regards,
Krzysztof


From reinette.chatre at intel.com  Fri Dec  5 11:11:34 2025
From: reinette.chatre at intel.com (Reinette Chatre)
Date: Fri, 5 Dec 2025 11:11:34 -0800
Subject: [PATCH v6 00/34] arm_mpam: Add basic mpam driver
In-Reply-To: <871pl9krdz.fsf@stealth>
References: <20251119122305.302149-1-ben.horgan@arm.com>
 <877bvfa23i.fsf@stealth> <a04aa337-a3eb-42a0-855b-500ba549e2d8@arm.com>
 <87sedrlsjk.fsf@stealth> <642767c9-f926-490a-83a1-160978c37553@arm.com>
 <871pl9krdz.fsf@stealth>
Message-ID: <5261337c-337d-44ca-aff1-0a927b81e593@intel.com>

Hi Punit,

On 12/5/25 5:08 AM, Punit Agrawal wrote:
> James Morse <james.morse at arm.com> writes:
>> On 03/12/2025 11:21, Punit Agrawal wrote:
>>> Ben Horgan <ben.horgan at arm.com> writes:
>>>> On 11/24/25 15:21, Punit Agrawal wrote:

>>>>> The platform has MSCs attached
>>>>> to shared L2 caches which are being skipped during later stages of
>>>>> initialisation. IIUC, the L2 MSCs' limitations stems from the
>>>>> assumptions in the resctrl interface.
>>>>
>>>> What in particualar is being skipped?
>>
>>> The registration of the discovered MSCs with resctrl and subsequent
>>> exposing it to the user.
>>
>> resctrl's 'L2' support is limited to the CPOR bitmap.
>> If you have controls, there is no resctrl 'event' that can exposed them.
>> (the problem being they all have 'L3' in the name!)
> 
>>>>> I was wondering if there are any patches available to relax these
>>>>> limitations?
> 
>> Knowing which property it is will help - but some of these things are checked
>> to match resctrl's ABI. They can't necessarily be relaxed without breaking
>> user-space.
> 
> This platform has portion, capacity and priority partitioning, as well
> as memory bandwidth and cache storage monitoring. The MPAM code seems to
> correctly parse the properties.
> 
> But as you point out, the resctrl 'L2' support doesn't have anything
> other than CPOR bitmap yet. Have you looked at what's needed to extend
> resctrl to support some of the others?

Please see [1] for a summary of ideas on how resctrl can support multiple
controls. Nothing is final, please do add your ideas and requirements.

There are a couple of opens not included in the summary. If interested
[2] is where a lot of discussion happened that prompted the need for
a summary.

Reinette

[1] https://lore.kernel.org/lkml/aPtfMFfLV1l%2FRB0L at e133380.arm.com/
[2] https://lore.kernel.org/lkml/aNFliMZTTUiXyZzd at e133380.arm.com/


From royluo at google.com  Fri Dec  5 11:11:21 2025
From: royluo at google.com (Roy Luo)
Date: Fri, 5 Dec 2025 11:11:21 -0800
Subject: [PATCH v8 1/2] dt-bindings: phy: google: Add Google Tensor G5 USB PHY
In-Reply-To: <f32e0810-56f9-417e-abf6-0cc7b361bd15@kernel.org>
References: <20251205-phyb4-v8-0-c59ea80a4458@google.com> <20251205-phyb4-v8-1-c59ea80a4458@google.com>
 <18eeb1c5-d21b-4505-b6a4-472f6e191864@kernel.org> <CA+zupgwa+m8Pa=+8shORaOA1OO6zoo6zYEojFS2UDuP0doBq7A@mail.gmail.com>
 <f32e0810-56f9-417e-abf6-0cc7b361bd15@kernel.org>
Message-ID: <CA+zupgyxQisYBnLj9_3DtcN3R1Ugfv+-p-wimFp-hnqkhrrgyA@mail.gmail.com>

On Fri, Dec 5, 2025 at 10:52?AM Krzysztof Kozlowski <krzk at kernel.org> wrote:
>
> On 05/12/2025 19:47, Roy Luo wrote:
> > On Fri, Dec 5, 2025 at 9:13?AM Krzysztof Kozlowski <krzk at kernel.org> wrote:
> >>
> >> On 05/12/2025 04:54, Roy Luo wrote:
> >>> Document the device tree bindings for the USB PHY interfaces integrated
> >>> with the DWC3 controller on Google Tensor SoCs, starting with G5
> >>> generation (Laguna). The USB PHY on Tensor G5 includes two integrated
> >>> Synopsys PHY IPs: the eUSB 2.0 PHY IP and the USB 3.2/DisplayPort combo
> >>> PHY IP.
> >>>
> >>> Due to a complete architectural overhaul in the Google Tensor G5, the
> >>> existing Samsung/Exynos USB PHY binding for older generations of Google
> >>> silicons such as gs101 are no longer compatible, necessitating this new
> >>> device tree binding.
> >>>
> >>> Signed-off-by: Roy Luo <royluo at google.com>
> >>
> >> Why intentionally dropping the tag? How are you handling this patchset?
> >> Rewrite every time from scratch?
> >
> > Hi Krzysztof,
> >
> > I dropped the tag because a new file is being modified in this version,
> > Although it's just MAINTAINER file but I thought you might also want
> > to take a look. I wasn't sure if modifying a new file qualifies as
> > "substantial" so I erred on the side of caution. I should've called it
> > out specifically in the change log. Sorry for the inconvenience.
>
> 1. so just squeeze that change into second patch and no need to ask for
> re-review

That's a fair point. I will be more mindful of the review overhead
going forward.

> 2. You did not read my complain fully, look:
>
> >
> > Regards,
> > Roy Luo
> >
> >>
> >> <form letter>
> >> This is a friendly reminder during the review process.
> >>
> >> It looks like you received a tag and forgot to add it.
> >>
> >> If you do not know the process, here is a short explanation:
> >> Please add Acked-by/Reviewed-by/Tested-by tags when posting new versions
> >> of patchset, under or above your Signed-off-by tag, unless patch changed
> >> significantly (e.g. new properties added to the DT bindings). Tag is
> >> "received", when provided in a message replied to you on the mailing
> >> list. Tools like b4 can help here. However, there's no need to repost
> >> patches *only* to add the tags. The upstream maintainer will do that for
> >> tags received on the version they apply.
> >>
> >> Please read:
> >> https://elixir.bootlin.com/linux/v6.12-rc3/source/Documentation/process/submitting-patches.rst#L577
> >>
> >> If a tag was not added on purpose, please state why and what changed.
>
> Where did you address this? You dropped the tag silently.

Why: a new file is being modified.
What changed: MAINTAINER
What's not changed:
Documentation/devicetree/bindings/phy/google,lga-usb-phy.yaml

Could you consider re-reviewing this patch?

Thanks,
Roy Luo

>
>
> Best regards,
> Krzysztof


From krzk at kernel.org  Fri Dec  5 11:26:41 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 5 Dec 2025 20:26:41 +0100
Subject: [PATCH v8 1/2] dt-bindings: phy: google: Add Google Tensor G5 USB
 PHY
In-Reply-To: <CA+zupgyxQisYBnLj9_3DtcN3R1Ugfv+-p-wimFp-hnqkhrrgyA@mail.gmail.com>
References: <20251205-phyb4-v8-0-c59ea80a4458@google.com>
 <20251205-phyb4-v8-1-c59ea80a4458@google.com>
 <18eeb1c5-d21b-4505-b6a4-472f6e191864@kernel.org>
 <CA+zupgwa+m8Pa=+8shORaOA1OO6zoo6zYEojFS2UDuP0doBq7A@mail.gmail.com>
 <f32e0810-56f9-417e-abf6-0cc7b361bd15@kernel.org>
 <CA+zupgyxQisYBnLj9_3DtcN3R1Ugfv+-p-wimFp-hnqkhrrgyA@mail.gmail.com>
Message-ID: <988b3fcb-44db-45ca-823b-5ab13206bd04@kernel.org>

On 05/12/2025 20:11, Roy Luo wrote:
> On Fri, Dec 5, 2025 at 10:52?AM Krzysztof Kozlowski <krzk at kernel.org> wrote:
>>
>> On 05/12/2025 19:47, Roy Luo wrote:
>>> On Fri, Dec 5, 2025 at 9:13?AM Krzysztof Kozlowski <krzk at kernel.org> wrote:
>>>>
>>>> On 05/12/2025 04:54, Roy Luo wrote:
>>>>> Document the device tree bindings for the USB PHY interfaces integrated
>>>>> with the DWC3 controller on Google Tensor SoCs, starting with G5
>>>>> generation (Laguna). The USB PHY on Tensor G5 includes two integrated
>>>>> Synopsys PHY IPs: the eUSB 2.0 PHY IP and the USB 3.2/DisplayPort combo
>>>>> PHY IP.
>>>>>
>>>>> Due to a complete architectural overhaul in the Google Tensor G5, the
>>>>> existing Samsung/Exynos USB PHY binding for older generations of Google
>>>>> silicons such as gs101 are no longer compatible, necessitating this new
>>>>> device tree binding.
>>>>>
>>>>> Signed-off-by: Roy Luo <royluo at google.com>
>>>>
>>>> Why intentionally dropping the tag? How are you handling this patchset?
>>>> Rewrite every time from scratch?
>>>
>>> Hi Krzysztof,
>>>
>>> I dropped the tag because a new file is being modified in this version,
>>> Although it's just MAINTAINER file but I thought you might also want
>>> to take a look. I wasn't sure if modifying a new file qualifies as
>>> "substantial" so I erred on the side of caution. I should've called it
>>> out specifically in the change log. Sorry for the inconvenience.
>>
>> 1. so just squeeze that change into second patch and no need to ask for
>> re-review
> 
> That's a fair point. I will be more mindful of the review overhead
> going forward.
> 
>> 2. You did not read my complain fully, look:
>>
>>>
>>> Regards,
>>> Roy Luo
>>>
>>>>
>>>> <form letter>
>>>> This is a friendly reminder during the review process.
>>>>
>>>> It looks like you received a tag and forgot to add it.
>>>>
>>>> If you do not know the process, here is a short explanation:
>>>> Please add Acked-by/Reviewed-by/Tested-by tags when posting new versions
>>>> of patchset, under or above your Signed-off-by tag, unless patch changed
>>>> significantly (e.g. new properties added to the DT bindings). Tag is
>>>> "received", when provided in a message replied to you on the mailing
>>>> list. Tools like b4 can help here. However, there's no need to repost
>>>> patches *only* to add the tags. The upstream maintainer will do that for
>>>> tags received on the version they apply.
>>>>
>>>> Please read:
>>>> https://elixir.bootlin.com/linux/v6.12-rc3/source/Documentation/process/submitting-patches.rst#L577
>>>>
>>>> If a tag was not added on purpose, please state why and what changed.
>>
>> Where did you address this? You dropped the tag silently.
> 
> Why: a new file is being modified.
> What changed: MAINTAINER
> What's not changed:
> Documentation/devicetree/bindings/phy/google,lga-usb-phy.yaml

I don't know if you still did not get the problem or you think that I
really need that clear answer. So no, I do not need that clear answer, I
understood with first reply, but you kept explaining instead of
admitting that your changelog needs fixes. So I still do not believe you
understood the problem here and you might repeat the mistake.

I think you need someone in Google to coach in this process, because I
even gave you the exact link describing the process and what was
expected. I even pointed specific paragraph, so you don't need to read
entire file!

I assume you understood what should be done instead in this patchset.
Anyway, my previous tag applies if there were no bindings changes, but I
wasted too much time here to care anymore. The expectation from big
companies is they do not ask community to coach on basic submission
process. It's quite unfair to my spare, personal time after work,
considering how much big company is making. Big company should invest in
this coaching.


Best regards,
Krzysztof


From royluo at google.com  Fri Dec  5 12:18:59 2025
From: royluo at google.com (Roy Luo)
Date: Fri, 5 Dec 2025 12:18:59 -0800
Subject: [PATCH v8 1/2] dt-bindings: phy: google: Add Google Tensor G5 USB PHY
In-Reply-To: <988b3fcb-44db-45ca-823b-5ab13206bd04@kernel.org>
References: <20251205-phyb4-v8-0-c59ea80a4458@google.com> <20251205-phyb4-v8-1-c59ea80a4458@google.com>
 <18eeb1c5-d21b-4505-b6a4-472f6e191864@kernel.org> <CA+zupgwa+m8Pa=+8shORaOA1OO6zoo6zYEojFS2UDuP0doBq7A@mail.gmail.com>
 <f32e0810-56f9-417e-abf6-0cc7b361bd15@kernel.org> <CA+zupgyxQisYBnLj9_3DtcN3R1Ugfv+-p-wimFp-hnqkhrrgyA@mail.gmail.com>
 <988b3fcb-44db-45ca-823b-5ab13206bd04@kernel.org>
Message-ID: <CA+zupgzi55svWK4gHsFtdQSD9jFKbxHx_0GE2R1R5DafmYyGNA@mail.gmail.com>

On Fri, Dec 5, 2025 at 11:26?AM Krzysztof Kozlowski <krzk at kernel.org> wrote:
>
> On 05/12/2025 20:11, Roy Luo wrote:
> > On Fri, Dec 5, 2025 at 10:52?AM Krzysztof Kozlowski <krzk at kernel.org> wrote:
> >>
> >> On 05/12/2025 19:47, Roy Luo wrote:
> >>> On Fri, Dec 5, 2025 at 9:13?AM Krzysztof Kozlowski <krzk at kernel.org> wrote:
> >>>>
> >>>> On 05/12/2025 04:54, Roy Luo wrote:
> >>>>> Document the device tree bindings for the USB PHY interfaces integrated
> >>>>> with the DWC3 controller on Google Tensor SoCs, starting with G5
> >>>>> generation (Laguna). The USB PHY on Tensor G5 includes two integrated
> >>>>> Synopsys PHY IPs: the eUSB 2.0 PHY IP and the USB 3.2/DisplayPort combo
> >>>>> PHY IP.
> >>>>>
> >>>>> Due to a complete architectural overhaul in the Google Tensor G5, the
> >>>>> existing Samsung/Exynos USB PHY binding for older generations of Google
> >>>>> silicons such as gs101 are no longer compatible, necessitating this new
> >>>>> device tree binding.
> >>>>>
> >>>>> Signed-off-by: Roy Luo <royluo at google.com>
> >>>>
> >>>> Why intentionally dropping the tag? How are you handling this patchset?
> >>>> Rewrite every time from scratch?
> >>>
> >>> Hi Krzysztof,
> >>>
> >>> I dropped the tag because a new file is being modified in this version,
> >>> Although it's just MAINTAINER file but I thought you might also want
> >>> to take a look. I wasn't sure if modifying a new file qualifies as
> >>> "substantial" so I erred on the side of caution. I should've called it
> >>> out specifically in the change log. Sorry for the inconvenience.
> >>
> >> 1. so just squeeze that change into second patch and no need to ask for
> >> re-review
> >
> > That's a fair point. I will be more mindful of the review overhead
> > going forward.
> >
> >> 2. You did not read my complain fully, look:
> >>
> >>>
> >>> Regards,
> >>> Roy Luo
> >>>
> >>>>
> >>>> <form letter>
> >>>> This is a friendly reminder during the review process.
> >>>>
> >>>> It looks like you received a tag and forgot to add it.
> >>>>
> >>>> If you do not know the process, here is a short explanation:
> >>>> Please add Acked-by/Reviewed-by/Tested-by tags when posting new versions
> >>>> of patchset, under or above your Signed-off-by tag, unless patch changed
> >>>> significantly (e.g. new properties added to the DT bindings). Tag is
> >>>> "received", when provided in a message replied to you on the mailing
> >>>> list. Tools like b4 can help here. However, there's no need to repost
> >>>> patches *only* to add the tags. The upstream maintainer will do that for
> >>>> tags received on the version they apply.
> >>>>
> >>>> Please read:
> >>>> https://elixir.bootlin.com/linux/v6.12-rc3/source/Documentation/process/submitting-patches.rst#L577
> >>>>
> >>>> If a tag was not added on purpose, please state why and what changed.
> >>
> >> Where did you address this? You dropped the tag silently.
> >
> > Why: a new file is being modified.
> > What changed: MAINTAINER
> > What's not changed:
> > Documentation/devicetree/bindings/phy/google,lga-usb-phy.yaml
>
> I don't know if you still did not get the problem or you think that I
> really need that clear answer. So no, I do not need that clear answer, I
> understood with first reply, but you kept explaining instead of
> admitting that your changelog needs fixes. So I still do not believe you
> understood the problem here and you might repeat the mistake.

I admitted that my changelog needs fixes in my first reply.
"I should've called it out specifically in the change log. Sorry for the
inconvenience.".
Maybe you think I didn't read through because my reply was placed
before the <form letter> section, but that's a misunderstanding.
I did read through the paragraph, that's why I mentioned the
changelog in my first reply.

I also misunderstood your question of "Where did you address
this?". If you were asking where this should have been addressed,
obviously the answer is to address it in the changelog,
but I thought that was already made clear in the first reply and
you might be asking for a clear answer.

>
> I think you need someone in Google to coach in this process, because I
> even gave you the exact link describing the process and what was
> expected. I even pointed specific paragraph, so you don't need to read
> entire file!

I appreciate you pointing out the specific paragraph, I understand
you're going above and beyond here. I did read and understand
what should've been done instead for this patch.

>
> I assume you understood what should be done instead in this patchset.
> Anyway, my previous tag applies if there were no bindings changes, but I
> wasted too much time here to care anymore. The expectation from big
> companies is they do not ask community to coach on basic submission
> process. It's quite unfair to my spare, personal time after work,
> considering how much big company is making. Big company should invest in
> this coaching.
>
>
> Best regards,
> Krzysztof

Thank you for the feedback. I understand your frustration, and I
apologize for taking up your time. I will be sure to be more thorough
in the future.

Thanks,
Roy Luo


From dmitry.baryshkov at oss.qualcomm.com  Fri Dec  5 12:54:39 2025
From: dmitry.baryshkov at oss.qualcomm.com (Dmitry Baryshkov)
Date: Fri, 5 Dec 2025 22:54:39 +0200
Subject: [PATCH V4] iommu/arm-smmu: add actlr settings for mdss on
 Qualcomm platforms
In-Reply-To: <20251202125447.2102658-1-charan.kalla@oss.qualcomm.com>
References: <20251202125447.2102658-1-charan.kalla@oss.qualcomm.com>
Message-ID: <ombtqnvej7vxot7fzhtbgt7doqky4b4wwtockyvorpfi2hl4zz@wslecjpuhmmj>

On Tue, Dec 02, 2025 at 06:24:47PM +0530, Charan Teja Kalla wrote:
> Add ACTLR settings for missing MDSS devices on Qualcomm platforms.
> 
> These are QoS settings and are specific to per SoC thus different
> settings, eg: some have shallow prefetch while others have no
> prefetch.
> 
> Aswell, this prefetch feature is not implemented for all the
> platforms, capturing to those are implemented to the best of my
> knowledge.
> 
> Signed-off-by: Charan Teja Kalla <charan.kalla at oss.qualcomm.com>
> ---
> Changes from V3:
>  1) Add actlr setting for missing sc8180x & sm6115.

Thanks!


Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>


> 

-- 
With best wishes
Dmitry


From andersson at kernel.org  Fri Dec  5 13:06:04 2025
From: andersson at kernel.org (Bjorn Andersson)
Date: Fri, 5 Dec 2025 15:06:04 -0600
Subject: [PATCH V4] iommu/arm-smmu: add actlr settings for mdss on
 Qualcomm platforms
In-Reply-To: <20251202125447.2102658-1-charan.kalla@oss.qualcomm.com>
References: <20251202125447.2102658-1-charan.kalla@oss.qualcomm.com>
Message-ID: <gsjyj3arwoqcjln6nlmyhohlowyvkwqmxppdq5y7c3m4khoyq3@npzixjpibh5g>

On Tue, Dec 02, 2025 at 06:24:47PM +0530, Charan Teja Kalla wrote:

Based on the other changes to this file, the subject prefix should be
"iommu/arm-smmu-qcom:"

Regards,
Bjorn

> Add ACTLR settings for missing MDSS devices on Qualcomm platforms.
> 
> These are QoS settings and are specific to per SoC thus different
> settings, eg: some have shallow prefetch while others have no
> prefetch.
> 
> Aswell, this prefetch feature is not implemented for all the
> platforms, capturing to those are implemented to the best of my
> knowledge.
> 
> Signed-off-by: Charan Teja Kalla <charan.kalla at oss.qualcomm.com>
> ---
> Changes from V3:
>  1) Add actlr setting for missing sc8180x & sm6115.
>  2) Improved commit message.
> https://lore.kernel.org/all/20251124171030.323989-1-charan.kalla at oss.qualcomm.com/
> 
> Changes from V2:
>  1) Add actlr settings for all the mdss devices on Qualcomm platforms.
>  2) Improved the commit message that explain why different ACTLR
>     settings
> https://lore.kernel.org/lkml/20251118171822.3539062-1-charan.kalla at oss.qualcomm.com/#t
> 
> Changes from V1:
>   1) Added actlr setting only for MDSS and dropped for fastrpc. --
> konrad
>   2) ACTLR table is updated per alphanumeric order -- konrad 
>   https://lore.kernel.org/all/20251105075307.1658329-1-charan.kalla at oss.qualcomm.com/
> 
>  drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 26 ++++++++++++++++++++++
>  1 file changed, 26 insertions(+)
> 
> diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
> index c21a401c71eb..149da53091de 100644
> --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
> +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
> @@ -41,12 +41,38 @@ static const struct of_device_id qcom_smmu_actlr_client_of_match[] = {
>  			.data = (const void *) (PREFETCH_DEEP | CPRE | CMTLB) },
>  	{ .compatible = "qcom,fastrpc",
>  			.data = (const void *) (PREFETCH_DEEP | CPRE | CMTLB) },
> +	{ .compatible = "qcom,qcm2290-mdss",
> +			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
>  	{ .compatible = "qcom,sc7280-mdss",
>  			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
>  	{ .compatible = "qcom,sc7280-venus",
>  			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
> +	{ .compatible = "qcom,sc8180x-mdss",
> +			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
> +	{ .compatible = "qcom,sc8280xp-mdss",
> +			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
> +	{ .compatible = "qcom,sm6115-mdss",
> +			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
> +	{ .compatible = "qcom,sm6125-mdss",
> +			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
> +	{ .compatible = "qcom,sm6350-mdss",
> +			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
> +	{ .compatible = "qcom,sm8150-mdss",
> +			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
> +	{ .compatible = "qcom,sm8250-mdss",
> +			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
> +	{ .compatible = "qcom,sm8350-mdss",
> +			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
> +	{ .compatible = "qcom,sm8450-mdss",
> +			.data = (const void *) (PREFETCH_DEFAULT | CMTLB) },
>  	{ .compatible = "qcom,sm8550-mdss",
>  			.data = (const void *) (PREFETCH_DEFAULT | CMTLB) },
> +	{ .compatible = "qcom,sm8650-mdss",
> +			.data = (const void *) (PREFETCH_DEFAULT | CMTLB) },
> +	{ .compatible = "qcom,sm8750-mdss",
> +			.data = (const void *) (PREFETCH_DEFAULT | CMTLB) },
> +	{ .compatible = "qcom,x1e80100-mdss",
> +			.data = (const void *) (PREFETCH_DEFAULT | CMTLB) },
>  	{ }
>  };
>  
> -- 
> 2.34.1
> 
> 


From james.morse at arm.com  Fri Dec  5 13:58:23 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:23 +0000
Subject: [RFC PATCH 00/38] arm_mpam: Add KVM/arm64 and resctrl glue code
Message-ID: <20251205215901.17772-1-james.morse@arm.com>

This is the missing piece to make MPAM usable resctrl in user-space. This has
shed its debugfs code and the read/write 'event configuration' for the monitors
to make the series smaller.

This adds the arch code and KVM support first. I anticipate the whole thing
going via arm64, but if goes via tip instead, the an immutable branch with those
patches should be easy to do.

I've not CC'd all the relevant maintainers because its the merge window.
(...and yet there are folk chomping at the bit to see this posted...)


Generally the resctrl glue code works by picking what MPAM features it can expose
from the MPAM drive, then configuring the structs that back the resctrl helpers.
If your platform is sufficiently Xeon shaped, you should be able to get L2/L3 CPOR
bitmaps exposed via resctrl. CSU counters work if they are on/after the L3. MBWU
counters are considerably more hairy, and depend on hueristics around the topology,
and a bunch of stuff trying to emulate ABMC.
If it didn't pick what you wanted it to, please share the debug messages produced
when enabling dynamic debug and booting with:
| dyndbg="file mpam_resctrl.c +pl"

I've not found a platform that can test all the behaviours around the monitors,
so this is where I'd expect the most bugs.

The MPAM spec that describes all the system and MMIO registers can be found here:
https://developer.arm.com/documentation/ddi0598/db/?lang=en
(Ignored the 'RETIRED' warning - that is just arm moving the documentation around.
 This document has the best overview)


This series is based on arm64/for-next/core, and can be retrieved from:
https://git.kernel.org/pub/scm/linux/kernel/git/morse/linux.git mpam/glue/rfc

There is no snapshot branch - this is it!
I'll push the extras branch once I've gotten a handle on the DT shaped mess in
there.

What is MPAM? Set your time-machine to 2020:
https://lore.kernel.org/lkml/20201030161120.227225-1-james.morse at arm.com/


Thanks,

James Morse (32):
  arm64: mpam: Context switch the MPAM registers
  arm64: mpam: Re-initialise MPAM regs when CPU comes online
  arm64: mpam: Advertise the CPUs MPAM limits to the driver
  arm64: mpam: Add cpu_pm notifier to restore MPAM sysregs
  arm64: mpam: Add helpers to change a task or cpu's MPAM PARTID/PMG
    values
  KVM: arm64: Force guest EL1 to use user-space's partid configuration
  arm_mpam: resctrl: Add boilerplate cpuhp and domain allocation
  arm_mpam: resctrl: Pick the caches we will use as resctrl resources
  arm_mpam: resctrl: Implement resctrl_arch_reset_all_ctrls()
  arm_mpam: resctrl: Add resctrl_arch_get_config()
  arm_mpam: resctrl: Implement helpers to update configuration
  arm_mpam: resctrl: Add plumbing against arm64 task and cpu hooks
  arm_mpam: resctrl: Add CDP emulation
  arm_mpam: resctrl: Add rmid index helpers
  arm_mpam: resctrl: Add support for 'MB' resource
  arm_mpam: resctrl: Add support for csu counters
  arm_mpam: resctrl: pick classes for use as mbm counters
  arm_mpam: resctrl: Pre-allocate free running monitors
  arm_mpam: resctrl: Pre-allocate assignable monitors
  arm_mpam: resctrl: Add kunit test for ABMC/CDP interactions
  arm_mpam: resctrl: Add resctrl_arch_config_cntr() for ABMC use
  arm_mpam: resctrl: Allow resctrl to allocate monitors
  arm_mpam: resctrl: Add resctrl_arch_rmid_read() and
    resctrl_arch_reset_rmid()
  arm_mpam: resctrl: Add resctrl_arch_cntr_read() &
    resctrl_arch_reset_cntr()
  arm_mpam: resctrl: Add empty definitions for assorted resctrl
    functions
  arm64: mpam: Select ARCH_HAS_CPU_RESCTRL
  arm_mpam: resctrl: Call resctrl_init() on platforms that can support
    resctrl
  arm_mpam: resctrl: Call resctrl_exit() in the event of errors
  arm_mpam: resctrl: Update the rmid reallocation limit
  arm_mpam: resctrl: Sort the order of the domain lists
  arm_mpam: Generate a configuration for min controls
  arm_mpam: Quirk CMN-650's CSU NRDY behaviour

Dave Martin (2):
  arm_mpam: resctrl: Convert to/from MPAMs fixed-point formats
  arm_mpam: resctrl: Add kunit test for control format conversions

Shanker Donthineni (4):
  arm_mpam: Add quirk framework
  arm_mpam: Add workaround for T241-MPAM-1
  arm_mpam: Add workaround for T241-MPAM-4
  arm_mpam: Add workaround for T241-MPAM-6

 Documentation/arch/arm64/silicon-errata.rst |    9 +
 arch/arm64/Kconfig                          |    6 +-
 arch/arm64/include/asm/kvm_host.h           |    1 +
 arch/arm64/include/asm/mpam.h               |  105 +
 arch/arm64/include/asm/resctrl.h            |    2 +
 arch/arm64/include/asm/thread_info.h        |    3 +
 arch/arm64/kernel/Makefile                  |    1 +
 arch/arm64/kernel/cpufeature.c              |   18 +-
 arch/arm64/kernel/mpam.c                    |   55 +
 arch/arm64/kernel/process.c                 |    7 +
 arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h  |   16 +
 arch/arm64/kvm/hyp/nvhe/switch.c            |   12 +
 arch/arm64/kvm/hyp/vhe/sysreg-sr.c          |    1 +
 drivers/resctrl/Kconfig                     |    9 +-
 drivers/resctrl/Makefile                    |    1 +
 drivers/resctrl/mpam_devices.c              |  298 ++-
 drivers/resctrl/mpam_internal.h             |  120 +-
 drivers/resctrl/mpam_resctrl.c              | 1926 +++++++++++++++++++
 drivers/resctrl/test_mpam_devices.c         |   66 +
 drivers/resctrl/test_mpam_resctrl.c         |  374 ++++
 include/linux/arm_mpam.h                    |   32 +
 21 files changed, 3038 insertions(+), 24 deletions(-)
 create mode 100644 arch/arm64/include/asm/mpam.h
 create mode 100644 arch/arm64/include/asm/resctrl.h
 create mode 100644 arch/arm64/kernel/mpam.c
 create mode 100644 drivers/resctrl/mpam_resctrl.c
 create mode 100644 drivers/resctrl/test_mpam_resctrl.c

-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:24 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:24 +0000
Subject: [RFC PATCH 01/38] arm64: mpam: Context switch the MPAM registers
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-2-james.morse@arm.com>

MPAM allows traffic in the SoC to be labeled by the OS, these labels
are used to apply policy in caches and bandwidth regulators, and to
monitor traffic in the SoC. The label is made up of a PARTID and PMG
value. The x86 equivalent calls these CLOSID and RMID, but they don't
map precisely.

MPAM has two CPU system registers that is used to hold the PARTID and PMG
values that traffic generated at each exception level will use. These can be
set per-task by the resctrl file system. (resctrl is the defacto interface
for controlling this stuff).

Add a helper to switch this.

struct task_struct's separate CLOSID and RMID fields are insufficient
to implement resctrl using MPAM, as resctrl can change the PARTID (CLOSID)
and PMG (sort of like the RMID) separately. On x86, the rmid is an
independent number, so a race that writes a mismatched  closid and rmid
into hardware is benign. On arm64, the pmg bits extend the partid.
(i.e. partid-5 has a pmg-0 that is not the same as partid-6's pmg-0).
In this case, mismatching the values will 'dirty' a pmg value that
resctrl believes is clean, and is not tracking with its 'limbo' code.

To avoid this, the partid and pmg are always read and written as a pair.
Instead of making struct task_struct's closid and rmid fields an
endian-unsafe union, add the value to struct thread_info and always use
READ_ONCE()/WRITE_ONCE() when accessing this field.

Resctrl allows a per-cpu 'default' value to be set, this overrides the
values when scheduling a task in the default control-group, which has
PARTID 0. The way 'code data prioritisation' gets emulated means the
register value for the default group needs to be a variable.

The current system register value is kept in a per-cpu variable to
avoid writing to the system register if the value isn't going to change.
Writes to this register may reset the hardware state for regulating
bandwidth.

Finally, there is no reason to context switch these registers unless
there is a driver changing the values in struct task_struct. Hide
the whole thing behind a static key. This also allows the driver to
disable MPAM in response to errors reported by hardware. Move the
existing static key to belong to the arch code, as in the future
the MPAM driver may become a loadable module.

All this should depend on whether there is an MPAM driver, hide
it behind CONFIG_MPAM.

CC: Amit Singh Tomar <amitsinght at marvell.com>
Signed-off-by: James Morse <james.morse at arm.com>
---
 arch/arm64/Kconfig                   |  2 +
 arch/arm64/include/asm/mpam.h        | 74 ++++++++++++++++++++++++++++
 arch/arm64/include/asm/thread_info.h |  3 ++
 arch/arm64/kernel/Makefile           |  1 +
 arch/arm64/kernel/mpam.c             | 13 +++++
 arch/arm64/kernel/process.c          |  7 +++
 drivers/resctrl/mpam_devices.c       |  2 -
 drivers/resctrl/mpam_internal.h      |  2 +
 8 files changed, 102 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm64/include/asm/mpam.h
 create mode 100644 arch/arm64/kernel/mpam.c

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 004d58cfbff8..558baa9e7c08 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -2048,6 +2048,8 @@ config ARM64_MPAM
 
 	  MPAM is exposed to user-space via the resctrl pseudo filesystem.
 
+	  This option enables the extra context switch code.
+
 endmenu # "ARMv8.4 architectural features"
 
 menu "ARMv8.5 architectural features"
diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/mpam.h
new file mode 100644
index 000000000000..86a55176f884
--- /dev/null
+++ b/arch/arm64/include/asm/mpam.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2025 Arm Ltd. */
+
+#ifndef __ASM__MPAM_H
+#define __ASM__MPAM_H
+
+#include <linux/bitops.h>
+#include <linux/init.h>
+#include <linux/jump_label.h>
+#include <linux/percpu.h>
+#include <linux/sched.h>
+
+#include <asm/cpucaps.h>
+#include <asm/cpufeature.h>
+#include <asm/sysreg.h>
+
+DECLARE_STATIC_KEY_FALSE(mpam_enabled);
+DECLARE_PER_CPU(u64, arm64_mpam_default);
+DECLARE_PER_CPU(u64, arm64_mpam_current);
+
+/*
+ * The value of the MPAM0_EL1 sysreg when a task is in resctrl's default group.
+ * This is used by the context switch code to use the resctrl CPU property
+ * instead. The value is modified when CDP is enabled/disabled by mounting
+ * the resctrl filesystem.
+ */
+extern u64 arm64_mpam_global_default;
+
+/*
+ * The resctrl filesystem writes to the partid/pmg values for threads and CPUs,
+ * which may race with reads in __mpam_sched_in(). Ensure only one of the old
+ * or new values are used. Particular care should be taken with the pmg field
+ * as __mpam_sched_in() may read a partid and pmg that don't match, causing
+ * this value to be stored with cache allocations, despite being considered
+ * 'free' by resctrl.
+ *
+ * A value in struct thread_info is used instead of struct task_struct as the
+ * cpu's u64 register format is used, but struct task_struct has two u32'.
+ */
+static inline u64 mpam_get_regval(struct task_struct *tsk)
+{
+#ifdef CONFIG_ARM64_MPAM
+	return READ_ONCE(task_thread_info(tsk)->mpam_partid_pmg);
+#else
+	return 0;
+#endif
+}
+
+static inline void mpam_thread_switch(struct task_struct *tsk)
+{
+	u64 oldregval;
+	int cpu = smp_processor_id();
+	u64 regval = mpam_get_regval(tsk);
+
+	if (!IS_ENABLED(CONFIG_ARM64_MPAM) ||
+	    !static_branch_likely(&mpam_enabled))
+		return;
+
+	if (regval == READ_ONCE(arm64_mpam_global_default))
+		regval = READ_ONCE(per_cpu(arm64_mpam_default, cpu));
+
+	oldregval = READ_ONCE(per_cpu(arm64_mpam_current, cpu));
+	if (oldregval == regval)
+		return;
+
+	write_sysreg_s(regval, SYS_MPAM1_EL1);
+	isb();
+
+	/* Synchronising the EL0 write is left until the ERET to EL0 */
+	write_sysreg_s(regval, SYS_MPAM0_EL1);
+
+	WRITE_ONCE(per_cpu(arm64_mpam_current, cpu), regval);
+}
+#endif /* __ASM__MPAM_H */
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index f241b8601ebd..c226dabd5019 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -41,6 +41,9 @@ struct thread_info {
 #ifdef CONFIG_SHADOW_CALL_STACK
 	void			*scs_base;
 	void			*scs_sp;
+#endif
+#ifdef CONFIG_ARM64_MPAM
+	u64			mpam_partid_pmg;
 #endif
 	u32			cpu;
 };
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 76f32e424065..15979f366519 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_CRASH_DUMP)		+= crash_dump.o
 obj-$(CONFIG_VMCORE_INFO)		+= vmcore_info.o
 obj-$(CONFIG_ARM_SDE_INTERFACE)		+= sdei.o
 obj-$(CONFIG_ARM64_PTR_AUTH)		+= pointer_auth.o
+obj-$(CONFIG_ARM64_MPAM)		+= mpam.o
 obj-$(CONFIG_ARM64_MTE)			+= mte.o
 obj-y					+= vdso-wrap.o
 obj-$(CONFIG_COMPAT_VDSO)		+= vdso32-wrap.o
diff --git a/arch/arm64/kernel/mpam.c b/arch/arm64/kernel/mpam.c
new file mode 100644
index 000000000000..9866d2ca0faa
--- /dev/null
+++ b/arch/arm64/kernel/mpam.c
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2025 Arm Ltd. */
+
+#include <asm/mpam.h>
+
+#include <linux/jump_label.h>
+#include <linux/percpu.h>
+
+DEFINE_STATIC_KEY_FALSE(mpam_enabled);
+DEFINE_PER_CPU(u64, arm64_mpam_default);
+DEFINE_PER_CPU(u64, arm64_mpam_current);
+
+u64 arm64_mpam_global_default;
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index fba7ca102a8c..b510c0699313 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -51,6 +51,7 @@
 #include <asm/fpsimd.h>
 #include <asm/gcs.h>
 #include <asm/mmu_context.h>
+#include <asm/mpam.h>
 #include <asm/mte.h>
 #include <asm/processor.h>
 #include <asm/pointer_auth.h>
@@ -737,6 +738,12 @@ struct task_struct *__switch_to(struct task_struct *prev,
 	if (prev->thread.sctlr_user != next->thread.sctlr_user)
 		update_sctlr_el1(next->thread.sctlr_user);
 
+	/*
+	 * MPAM thread switch happens after the DSB to ensure prev's accesses
+	 * use prev's MPAM settings.
+	 */
+	mpam_thread_switch(next);
+
 	/* the actual thread switch */
 	last = cpu_switch_to(prev, next);
 
diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index 0b5b158e1aaf..2996ad93fc3e 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -29,8 +29,6 @@
 
 #include "mpam_internal.h"
 
-DEFINE_STATIC_KEY_FALSE(mpam_enabled); /* This moves to arch code */
-
 /*
  * mpam_list_lock protects the SRCU lists when writing. Once the
  * mpam_enabled key is enabled these lists are read-only,
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index e79c3c47259c..4508a6654fe0 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -17,6 +17,8 @@
 #include <linux/srcu.h>
 #include <linux/types.h>
 
+#include <asm/mpam.h>
+
 #define MPAM_MSC_MAX_NUM_RIS	16
 
 struct platform_device;
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:25 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:25 +0000
Subject: [RFC PATCH 02/38] arm64: mpam: Re-initialise MPAM regs when CPU comes online
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-3-james.morse@arm.com>

Now that the MPAM system registers are expected to have values that change,
reprogram them based on struct task_struct when a CPU is brought online.

Previously MPAM's 'default PARTID' of 0 was used this is the PARTID that
hardware guarantees to reset. Because there are a limited number of
PARTID, this value is exposed to user space, meaning resctrl changes
to the resctrl default group would also affect kernel threads.
Instead, use the task's PARTID value for kernel work on behalf of
user-space too.

Signed-off-by: James Morse <james.morse at arm.com>
---
 arch/arm64/kernel/cpufeature.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 5ed401ff79e3..429128a181ac 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -86,6 +86,7 @@
 #include <asm/kvm_host.h>
 #include <asm/mmu.h>
 #include <asm/mmu_context.h>
+#include <asm/mpam.h>
 #include <asm/mte.h>
 #include <asm/hypervisor.h>
 #include <asm/processor.h>
@@ -2439,13 +2440,16 @@ test_has_mpam(const struct arm64_cpu_capabilities *entry, int scope)
 static void
 cpu_enable_mpam(const struct arm64_cpu_capabilities *entry)
 {
-	/*
-	 * Access by the kernel (at EL1) should use the reserved PARTID
-	 * which is configured unrestricted. This avoids priority-inversion
-	 * where latency sensitive tasks have to wait for a task that has
-	 * been throttled to release the lock.
-	 */
-	write_sysreg_s(0, SYS_MPAM1_EL1);
+	int cpu = smp_processor_id();
+	u64 regval = 0;
+
+	if (IS_ENABLED(CONFIG_MPAM))
+		regval = READ_ONCE(per_cpu(arm64_mpam_current, cpu));
+
+	write_sysreg_s(regval, SYS_MPAM1_EL1);
+	isb();
+
+	write_sysreg_s(regval, SYS_MPAM0_EL1);
 }
 
 static bool
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:27 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:27 +0000
Subject: [RFC PATCH 04/38] arm64: mpam: Add cpu_pm notifier to restore MPAM sysregs
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-5-james.morse@arm.com>

The MPAM system registers will be lost if the CPU is reset during
PSCI's CPU_SUSPEND.

Add a PM notifier to restore them.

mpam_thread_switch(current) can't be used as this won't make any
changes if the in-memory copy says the register already has the
correct value. In reality the system register is UNKNOWN out of reset.

Signed-off-by: James Morse <james.morse at arm.com>
---
 arch/arm64/kernel/mpam.c | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/arch/arm64/kernel/mpam.c b/arch/arm64/kernel/mpam.c
index e6feff2324ac..dbe0a2d05abb 100644
--- a/arch/arm64/kernel/mpam.c
+++ b/arch/arm64/kernel/mpam.c
@@ -4,6 +4,7 @@
 #include <asm/mpam.h>
 
 #include <linux/arm_mpam.h>
+#include <linux/cpu_pm.h>
 #include <linux/jump_label.h>
 #include <linux/percpu.h>
 
@@ -13,12 +14,41 @@ DEFINE_PER_CPU(u64, arm64_mpam_current);
 
 u64 arm64_mpam_global_default;
 
+static int mpam_pm_notifier(struct notifier_block *self,
+			    unsigned long cmd, void *v)
+{
+	u64 regval;
+	int cpu = smp_processor_id();
+
+	switch (cmd) {
+	case CPU_PM_EXIT:
+		/*
+		 * Don't use mpam_thread_switch() as the system register
+		 * value has changed under our feet.
+		 */
+		regval = READ_ONCE(per_cpu(arm64_mpam_current, cpu));
+		write_sysreg_s(regval, SYS_MPAM1_EL1);
+		isb();
+
+		write_sysreg_s(regval, SYS_MPAM0_EL1);
+
+		return NOTIFY_OK;
+	default:
+		return NOTIFY_DONE;
+	}
+}
+
+static struct notifier_block mpam_pm_nb = {
+	.notifier_call = mpam_pm_notifier,
+};
+
 static int __init arm64_mpam_register_cpus(void)
 {
 	u64 mpamidr = read_sanitised_ftr_reg(SYS_MPAMIDR_EL1);
 	u16 partid_max = FIELD_GET(MPAMIDR_EL1_PARTID_MAX, mpamidr);
 	u8 pmg_max = FIELD_GET(MPAMIDR_EL1_PMG_MAX, mpamidr);
 
+	cpu_pm_register_notifier(&mpam_pm_nb);
 	return mpam_register_requestor(partid_max, pmg_max);
 }
 /* Must occur before mpam_msc_driver_init() from subsys_initcall() */
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:28 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:28 +0000
Subject: [RFC PATCH 05/38] arm64: mpam: Add helpers to change a task or cpu's MPAM PARTID/PMG values
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-6-james.morse@arm.com>

Care must be taken when modifying the PARTID and PMG of a task in any
per-task structure as writing these values may race with the task being
scheduled in, and reading the modified values.

Add helpers to set the task properties, and the CPU default value.
These use WRITE_ONCE() that pairs with the READ_ONCE() in mpam_get_regval()
to avoid causing torn values.

CC: Dave Martin <Dave.Martin at arm.com>
CC: Ben Horgan <ben.horgan at arm.com>
Signed-off-by: James Morse <james.morse at arm.com>
---
 arch/arm64/include/asm/mpam.h | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/mpam.h
index 86a55176f884..2960ffaf6574 100644
--- a/arch/arm64/include/asm/mpam.h
+++ b/arch/arm64/include/asm/mpam.h
@@ -5,6 +5,7 @@
 #define __ASM__MPAM_H
 
 #include <linux/bitops.h>
+#include <linux/bitfield.h>
 #include <linux/init.h>
 #include <linux/jump_label.h>
 #include <linux/percpu.h>
@@ -37,6 +38,35 @@ extern u64 arm64_mpam_global_default;
  * A value in struct thread_info is used instead of struct task_struct as the
  * cpu's u64 register format is used, but struct task_struct has two u32'.
  */
+static inline void mpam_set_cpu_defaults(int cpu, u16 partid_d, u16 partid_i,
+					 u8 pmg_d, u8 pmg_i)
+{
+	u64 default_val;
+
+	default_val = FIELD_PREP(MPAM0_EL1_PARTID_D, partid_d);
+	default_val |= FIELD_PREP(MPAM0_EL1_PARTID_I, partid_i);
+	default_val |= FIELD_PREP(MPAM0_EL1_PMG_D, pmg_d);
+	default_val |= FIELD_PREP(MPAM0_EL1_PMG_I, pmg_i);
+
+	WRITE_ONCE(per_cpu(arm64_mpam_default, cpu), default_val);
+}
+
+static inline void mpam_set_task_partid_pmg(struct task_struct *tsk,
+					    u16 partid_d, u16 partid_i,
+					    u8 pmg_d, u8 pmg_i)
+{
+#ifdef CONFIG_ARM64_MPAM
+	u64 regval;
+
+	regval = FIELD_PREP(MPAM0_EL1_PARTID_D, partid_d);
+	regval |= FIELD_PREP(MPAM0_EL1_PARTID_I, partid_i);
+	regval |= FIELD_PREP(MPAM0_EL1_PMG_D, pmg_d);
+	regval |= FIELD_PREP(MPAM0_EL1_PMG_I, pmg_i);
+
+	WRITE_ONCE(task_thread_info(tsk)->mpam_partid_pmg, regval);
+#endif
+}
+
 static inline u64 mpam_get_regval(struct task_struct *tsk)
 {
 #ifdef CONFIG_ARM64_MPAM
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:29 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:29 +0000
Subject: [RFC PATCH 06/38] KVM: arm64: Force guest EL1 to use user-space's partid configuration
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-7-james.morse@arm.com>

While we trap the guest's attempts to read/write the MPAM control
registers, the hardware continues to use them. Guest-EL0 uses KVM's
user-space's configuration, as the value is left in the register, and
guest-EL1 uses either the host kernel's configuration, or in the case of
VHE, the UNKNOWN reset value of MPAM1_EL1.

On nVHE systems, EL2 continues to use partid-0 for world-switch, even
when the host may have configured its kernel threads to use a different
partid. 0 may have been assigned to another task.

We want to force the guest-EL1 to use KVM's user-space's MPAM
configuration, and EL2s to match the host's EL1 config.

On a nVHE system, copy the EL1 MPAM register to EL2. This ensures
world-switch uses the same partid as the kernel thread does on the host.

When loading the guest's EL1 registers, copy the VMM's EL0 partid to
the EL1 register.

For VHE systems, we can skip restoring the EL1 register for the host,
as it is out-of-context once HCR_EL2.TGE is set.

This is done outside the usual sysreg save/restore as the values can
change behind KVMs back, so should not be stored in the guest context.

Signed-off-by: James Morse <james.morse at arm.com>
---
 arch/arm64/include/asm/kvm_host.h          |  1 +
 arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h | 16 ++++++++++++++++
 arch/arm64/kvm/hyp/nvhe/switch.c           | 12 ++++++++++++
 arch/arm64/kvm/hyp/vhe/sysreg-sr.c         |  1 +
 4 files changed, 30 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index b763293281c8..baba23b7ce97 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -447,6 +447,7 @@ enum vcpu_sysreg {
 	MDCCINT_EL1,	/* Monitor Debug Comms Channel Interrupt Enable Reg */
 	OSLSR_EL1,	/* OS Lock Status Register */
 	DISR_EL1,	/* Deferred Interrupt Status Register */
+	MPAM1_EL1,	/* Memory Partitioning And Monitoring register */
 
 	/* Performance Monitors Registers */
 	PMCR_EL0,	/* Control Register */
diff --git a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
index a17cbe7582de..d8ab0ced0403 100644
--- a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
+++ b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
@@ -166,6 +166,9 @@ static inline void __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
 		ctxt_sys_reg(ctxt, TFSRE0_EL1) = read_sysreg_s(SYS_TFSRE0_EL1);
 	}
 
+	if (system_supports_mpam())
+		ctxt_sys_reg(ctxt, MPAM1_EL1) = read_sysreg_el1(SYS_MPAM1);
+
 	ctxt_sys_reg(ctxt, SP_EL1)	= read_sysreg(sp_el1);
 	ctxt_sys_reg(ctxt, ELR_EL1)	= read_sysreg_el1(SYS_ELR);
 	ctxt_sys_reg(ctxt, SPSR_EL1)	= read_sysreg_el1(SYS_SPSR);
@@ -261,6 +264,9 @@ static inline void __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt,
 		write_sysreg_s(ctxt_sys_reg(ctxt, TFSRE0_EL1), SYS_TFSRE0_EL1);
 	}
 
+	if (system_supports_mpam())
+		write_sysreg_el1(ctxt_sys_reg(ctxt, MPAM1_EL1), SYS_MPAM1);
+
 	if (!has_vhe() &&
 	    cpus_have_final_cap(ARM64_WORKAROUND_SPECULATIVE_AT) &&
 	    ctxt->__hyp_running_vcpu) {
@@ -374,4 +380,14 @@ static inline void __sysreg32_restore_state(struct kvm_vcpu *vcpu)
 		write_sysreg(__vcpu_sys_reg(vcpu, DBGVCR32_EL2), dbgvcr32_el2);
 }
 
+/*
+ * The _EL0 value was written by the host's context switch and belongs to the
+ * VMM. Copy this into the guest's _EL1 register.
+ */
+static inline void __mpam_guest_load(void)
+{
+	if (system_supports_mpam())
+		write_sysreg_el1(read_sysreg_s(SYS_MPAM0_EL1), SYS_MPAM1);
+}
+
 #endif /* __ARM64_KVM_HYP_SYSREG_SR_H__ */
diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c
index d3b9ec8a7c28..b785977aa61e 100644
--- a/arch/arm64/kvm/hyp/nvhe/switch.c
+++ b/arch/arm64/kvm/hyp/nvhe/switch.c
@@ -238,6 +238,15 @@ static inline bool fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
 	return __fixup_guest_exit(vcpu, exit_code, handlers);
 }
 
+/* Use the host thread's partid and pmg for world switch */
+static void __mpam_copy_el1_to_el2(void)
+{
+	if (system_supports_mpam()) {
+		write_sysreg_s(read_sysreg_s(SYS_MPAM1_EL1), SYS_MPAM2_EL2);
+		isb();
+	}
+}
+
 /* Switch to the guest for legacy non-VHE systems */
 int __kvm_vcpu_run(struct kvm_vcpu *vcpu)
 {
@@ -247,6 +256,8 @@ int __kvm_vcpu_run(struct kvm_vcpu *vcpu)
 	bool pmu_switch_needed;
 	u64 exit_code;
 
+	__mpam_copy_el1_to_el2();
+
 	/*
 	 * Having IRQs masked via PMR when entering the guest means the GIC
 	 * will not signal the CPU of interrupts of lower priority, and the
@@ -306,6 +317,7 @@ int __kvm_vcpu_run(struct kvm_vcpu *vcpu)
 	__timer_enable_traps(vcpu);
 
 	__debug_switch_to_guest(vcpu);
+	__mpam_guest_load();
 
 	do {
 		/* Jump in the fire! */
diff --git a/arch/arm64/kvm/hyp/vhe/sysreg-sr.c b/arch/arm64/kvm/hyp/vhe/sysreg-sr.c
index f28c6cf4fe1b..2a84edc90465 100644
--- a/arch/arm64/kvm/hyp/vhe/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/vhe/sysreg-sr.c
@@ -222,6 +222,7 @@ void __vcpu_load_switch_sysregs(struct kvm_vcpu *vcpu)
 	 */
 	__sysreg32_restore_state(vcpu);
 	__sysreg_restore_user_state(guest_ctxt);
+	__mpam_guest_load();
 
 	if (unlikely(is_hyp_ctxt(vcpu))) {
 		__sysreg_restore_vel2_state(vcpu);
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:31 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:31 +0000
Subject: [RFC PATCH 08/38] arm_mpam: resctrl: Pick the caches we will use as resctrl resources
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-9-james.morse@arm.com>

Systems with MPAM support may have a variety of control types at any
point of their system layout. We can only expose certain types of
control, and only if they exist at particular locations.

Start with the well-know caches. These have to be depth 2 or 3
and support MPAM's cache portion bitmap controls, with a number
of portions fewer than resctrl's limit.

Signed-off-by: James Morse <james.morse at arm.com>
---
 drivers/resctrl/mpam_resctrl.c | 91 +++++++++++++++++++++++++++++++++-
 1 file changed, 89 insertions(+), 2 deletions(-)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 320cebbd37ce..ceaf11af4fc1 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -60,10 +60,96 @@ struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l)
 	return &mpam_resctrl_controls[l].resctrl_res;
 }
 
+static bool cache_has_usable_cpor(struct mpam_class *class)
+{
+	struct mpam_props *cprops = &class->props;
+
+	if (!mpam_has_feature(mpam_feat_cpor_part, cprops))
+		return false;
+
+	/* resctrl uses u32 for all bitmap configurations */
+	return (class->props.cpbm_wd <= 32);
+}
+
+/* Test whether we can export MPAM_CLASS_CACHE:{2,3}? */
+static void mpam_resctrl_pick_caches(void)
+{
+	struct mpam_class *class;
+	struct mpam_resctrl_res *res;
+
+	lockdep_assert_cpus_held();
+
+	guard(srcu)(&mpam_srcu);
+	list_for_each_entry_srcu(class, &mpam_classes, classes_list,
+				 srcu_read_lock_held(&mpam_srcu)) {
+		if (class->type != MPAM_CLASS_CACHE) {
+			pr_debug("class %u is not a cache\n", class->level);
+			continue;
+		}
+
+		if (class->level != 2 && class->level != 3) {
+			pr_debug("class %u is not L2 or L3\n", class->level);
+			continue;
+		}
+
+		if (!cache_has_usable_cpor(class)) {
+			pr_debug("class %u cache misses CPOR\n", class->level);
+			continue;
+		}
+
+		if (!cpumask_equal(&class->affinity, cpu_possible_mask)) {
+			pr_debug("class %u has missing CPUs\n", class->level);
+			pr_debug("class %u mask %*pb != %*pb\n", class->level,
+				 cpumask_pr_args(&class->affinity),
+				 cpumask_pr_args(cpu_possible_mask));
+			continue;
+		}
+
+		if (class->level == 2)
+			res = &mpam_resctrl_controls[RDT_RESOURCE_L2];
+		else
+			res = &mpam_resctrl_controls[RDT_RESOURCE_L3];
+		res->class = class;
+		exposed_alloc_capable = true;
+	}
+}
+
 static int mpam_resctrl_control_init(struct mpam_resctrl_res *res,
 				     enum resctrl_res_level type)
 {
-	/* TODO: initialise the resctrl resources */
+	struct mpam_class *class = res->class;
+	struct rdt_resource *r = &res->resctrl_res;
+
+	switch (res->resctrl_res.rid) {
+	case RDT_RESOURCE_L2:
+	case RDT_RESOURCE_L3:
+		r->alloc_capable = true;
+		r->schema_fmt = RESCTRL_SCHEMA_BITMAP;
+		r->cache.arch_has_sparse_bitmasks = true;
+
+		r->cache.cbm_len = class->props.cpbm_wd;
+		/* mpam_devices will reject empty bitmaps */
+		r->cache.min_cbm_bits = 1;
+
+		if (r->rid == RDT_RESOURCE_L2) {
+			r->name = "L2";
+			r->ctrl_scope = RESCTRL_L2_CACHE;
+		} else {
+			r->name = "L3";
+			r->ctrl_scope = RESCTRL_L3_CACHE;
+		}
+
+		/*
+		 * Which bits are shared with other ...things...
+		 * Unknown devices use partid-0 which uses all the bitmap
+		 * fields. Until we configured the SMMU and GIC not to do this
+		 * 'all the bits' is the correct answer here.
+		 */
+		r->cache.shareable_bits = resctrl_get_default_ctrl(r);
+		break;
+	default:
+		break;
+	}
 
 	return 0;
 }
@@ -286,7 +372,8 @@ int mpam_resctrl_setup(void)
 		res->resctrl_res.rid = i;
 	}
 
-	/* TODO: pick MPAM classes to map to resctrl resources */
+	/* Find some classes to use for controls */
+	mpam_resctrl_pick_caches();
 
 	/* Initialise the resctrl structures from the classes */
 	for (i = 0; i < RDT_NUM_RESOURCES; i++) {
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:32 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:32 +0000
Subject: [RFC PATCH 09/38] arm_mpam: resctrl: Implement resctrl_arch_reset_all_ctrls()
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-10-james.morse@arm.com>

We already have a helper for resetting an mpam class and component.
Hook it up to resctrl_arch_reset_all_ctrls() and the domain offline
path.

Signed-off-by: James Morse <james.morse at arm.com>
---
 drivers/resctrl/mpam_devices.c  |  6 +++---
 drivers/resctrl/mpam_internal.h |  7 +++++++
 drivers/resctrl/mpam_resctrl.c  | 15 +++++++++++++++
 3 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index efaf7633bc35..fccebfd980d8 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -2543,7 +2543,7 @@ static void mpam_enable_once(void)
 	       mpam_partid_max + 1, mpam_pmg_max + 1);
 }
 
-static void mpam_reset_component_locked(struct mpam_component *comp)
+void mpam_reset_component_locked(struct mpam_component *comp)
 {
 	struct mpam_vmsc *vmsc;
 
@@ -2567,7 +2567,7 @@ static void mpam_reset_component_locked(struct mpam_component *comp)
 	}
 }
 
-static void mpam_reset_class_locked(struct mpam_class *class)
+void mpam_reset_class_locked(struct mpam_class *class)
 {
 	struct mpam_component *comp;
 
@@ -2579,7 +2579,7 @@ static void mpam_reset_class_locked(struct mpam_class *class)
 		mpam_reset_component_locked(comp);
 }
 
-static void mpam_reset_class(struct mpam_class *class)
+void mpam_reset_class(struct mpam_class *class)
 {
 	cpus_read_lock();
 	mpam_reset_class_locked(class);
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index dfd3512ac924..8684bd35d4ab 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -392,6 +392,13 @@ extern u8 mpam_pmg_max;
 void mpam_enable(struct work_struct *work);
 void mpam_disable(struct work_struct *work);
 
+/* Reset all the RIS in a class, optionally while holding cpus_read_lock() */
+void mpam_reset_class_locked(struct mpam_class *class);
+void mpam_reset_class(struct mpam_class *class);
+
+/* Reset all the RIS in a component under cpus_read_lock() */
+void mpam_reset_component_locked(struct mpam_component *comp);
+
 int mpam_apply_config(struct mpam_component *comp, u16 partid,
 		      struct mpam_config *cfg);
 
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index ceaf11af4fc1..a2deea1f4818 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -168,6 +168,19 @@ static int mpam_resctrl_pick_domain_id(int cpu, struct mpam_component *comp)
 	return comp->comp_id;
 }
 
+void resctrl_arch_reset_all_ctrls(struct rdt_resource *r)
+{
+	struct mpam_resctrl_res *res;
+
+	lockdep_assert_cpus_held();
+
+	if (!mpam_is_enabled())
+		return;
+
+	res = container_of(r, struct mpam_resctrl_res, resctrl_res);
+	mpam_reset_class_locked(res->class);
+}
+
 static void mpam_resctrl_domain_hdr_init(int cpu, struct mpam_component *comp,
 					 struct rdt_domain_hdr *hdr)
 {
@@ -339,6 +352,8 @@ void mpam_resctrl_offline_cpu(unsigned int cpu)
 
 		ctrl_dom_empty = true;
 		if (exposed_alloc_capable) {
+			mpam_reset_component_locked(dom->ctrl_comp);
+
 			ctrl_d = &dom->resctrl_ctrl_dom;
 			ctrl_dom_empty = mpam_resctrl_offline_domain_hdr(cpu, &ctrl_d->hdr);
 			if (ctrl_dom_empty)
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:33 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:33 +0000
Subject: [RFC PATCH 10/38] arm_mpam: resctrl: Add resctrl_arch_get_config()
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-11-james.morse@arm.com>

Implement resctrl_arch_get_config() by testing the live configuration for
a CPOR bitmap. For any other configuration type return the default.

Signed-off-by: James Morse <james.morse at arm.com>
---
 drivers/resctrl/mpam_resctrl.c | 43 ++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index a2deea1f4818..a26eb1f3efd0 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -168,6 +168,49 @@ static int mpam_resctrl_pick_domain_id(int cpu, struct mpam_component *comp)
 	return comp->comp_id;
 }
 
+u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
+			    u32 closid, enum resctrl_conf_type type)
+{
+	u32 partid;
+	struct mpam_config *cfg;
+	struct mpam_props *cprops;
+	struct mpam_resctrl_res *res;
+	struct mpam_resctrl_dom *dom;
+	enum mpam_device_features configured_by;
+
+	lockdep_assert_cpus_held();
+
+	if (!mpam_is_enabled())
+		return resctrl_get_default_ctrl(r);
+
+	res = container_of(r, struct mpam_resctrl_res, resctrl_res);
+	dom = container_of(d, struct mpam_resctrl_dom, resctrl_ctrl_dom);
+	cprops = &res->class->props;
+
+	partid = resctrl_get_config_index(closid, type);
+	cfg = &dom->ctrl_comp->cfg[partid];
+
+	switch (r->rid) {
+	case RDT_RESOURCE_L2:
+	case RDT_RESOURCE_L3:
+		configured_by = mpam_feat_cpor_part;
+		break;
+	default:
+		return resctrl_get_default_ctrl(r);
+	}
+
+	if (!r->alloc_capable || partid >= resctrl_arch_get_num_closid(r) ||
+	    !mpam_has_feature(configured_by, cfg))
+		return resctrl_get_default_ctrl(r);
+
+	switch (configured_by) {
+	case mpam_feat_cpor_part:
+		return cfg->cpbm;
+	default:
+		return resctrl_get_default_ctrl(r);
+	}
+}
+
 void resctrl_arch_reset_all_ctrls(struct rdt_resource *r)
 {
 	struct mpam_resctrl_res *res;
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:34 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:34 +0000
Subject: [RFC PATCH 11/38] arm_mpam: resctrl: Implement helpers to update configuration
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-12-james.morse@arm.com>

resctrl has two helpers for updating the configuration.
resctrl_arch_update_one() updates a single value, and is used by the
software-controller to apply feedback to the bandwidth controls,
it has to be called on one of the CPUs in the resctrl:domain.

resctrl_arch_update_domains() copies multiple staged configurations,
it can be called from anywhere.

Both helpers should update any changes to the underlying hardware.

Imlpement resctrl_arch_update_domains() to use
resctrl_arch_update_one(). Neither need to be called on a specific
CPU as the mpam driver will send IPIs as needed.

Signed-off-by: James Morse <james.morse at arm.com>
---
 drivers/resctrl/mpam_resctrl.c | 71 ++++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index a26eb1f3efd0..ae0d17857b78 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -211,6 +211,77 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 	}
 }
 
+int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
+			    u32 closid, enum resctrl_conf_type t, u32 cfg_val)
+{
+	u32 partid;
+	struct mpam_config cfg;
+	struct mpam_props *cprops;
+	struct mpam_resctrl_res *res;
+	struct mpam_resctrl_dom *dom;
+
+	lockdep_assert_cpus_held();
+	lockdep_assert_irqs_enabled();
+
+	/*
+	 * No need to check the CPU as mpam_apply_config() doesn't care, and
+	 * resctrl_arch_update_domains() relies on this.
+	 */
+	res = container_of(r, struct mpam_resctrl_res, resctrl_res);
+	dom = container_of(d, struct mpam_resctrl_dom, resctrl_ctrl_dom);
+	cprops = &res->class->props;
+
+	partid = resctrl_get_config_index(closid, t);
+	if (!r->alloc_capable || partid >= resctrl_arch_get_num_closid(r)) {
+		pr_debug("Not alloc capable or computed PARTID out of range\n");
+		return -EINVAL;
+	}
+
+       /*
+	* Copy the current config to avoid clearing other resources when the
+	* same component is exposed multiple times through resctrl.
+	*/
+	cfg = dom->ctrl_comp->cfg[partid];
+
+	switch (r->rid) {
+	case RDT_RESOURCE_L2:
+	case RDT_RESOURCE_L3:
+		cfg.cpbm = cfg_val;
+		mpam_set_feature(mpam_feat_cpor_part, &cfg);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return mpam_apply_config(dom->ctrl_comp, partid, &cfg);
+}
+
+int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid)
+{
+	int err = 0;
+	enum resctrl_conf_type t;
+	struct rdt_ctrl_domain *d;
+	struct resctrl_staged_config *cfg;
+
+	lockdep_assert_cpus_held();
+	lockdep_assert_irqs_enabled();
+
+	list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
+		for (t = 0; t < CDP_NUM_TYPES; t++) {
+			cfg = &d->staged_config[t];
+			if (!cfg->have_new_ctrl)
+				continue;
+
+			err = resctrl_arch_update_one(r, d, closid, t,
+						      cfg->new_ctrl);
+			if (err)
+				return err;
+		}
+	}
+
+	return err;
+}
+
 void resctrl_arch_reset_all_ctrls(struct rdt_resource *r)
 {
 	struct mpam_resctrl_res *res;
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:35 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:35 +0000
Subject: [RFC PATCH 12/38] arm_mpam: resctrl: Add plumbing against arm64 task and cpu hooks
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-13-james.morse@arm.com>

arm64 provides helpers for changing a tasks and a cpus mpam partid/pmg
values.

These are used to back a number of resctrl_arch_ functions. Connect them
up.

Signed-off-by: James Morse <james.morse at arm.com>
---
 drivers/resctrl/mpam_resctrl.c | 58 ++++++++++++++++++++++++++++++++++
 include/linux/arm_mpam.h       |  5 +++
 2 files changed, 63 insertions(+)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index ae0d17857b78..c2650abb99ec 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -8,6 +8,7 @@
 #include <linux/cpu.h>
 #include <linux/cpumask.h>
 #include <linux/errno.h>
+#include <linux/limits.h>
 #include <linux/list.h>
 #include <linux/printk.h>
 #include <linux/rculist.h>
@@ -32,6 +33,8 @@ static DEFINE_MUTEX(domain_list_lock);
 static bool exposed_alloc_capable;
 static bool exposed_mon_capable;
 
+static bool cdp_enabled;
+
 bool resctrl_arch_alloc_capable(void)
 {
 	return exposed_alloc_capable;
@@ -52,6 +55,61 @@ u32 resctrl_arch_get_num_closid(struct rdt_resource *ignored)
 	return mpam_partid_max + 1;
 }
 
+void resctrl_arch_sched_in(struct task_struct *tsk)
+{
+	lockdep_assert_preemption_disabled();
+
+	mpam_thread_switch(tsk);
+}
+
+void resctrl_arch_set_cpu_default_closid_rmid(int cpu, u32 closid, u32 rmid)
+{
+	WARN_ON_ONCE(closid > U16_MAX);
+	WARN_ON_ONCE(rmid > U8_MAX);
+
+	if (!cdp_enabled) {
+		mpam_set_cpu_defaults(cpu, closid, closid, rmid, rmid);
+	} else {
+		/*
+		 * When CDP is enabled, resctrl halves the closid range and we
+		 * use odd/even partid for one closid.
+		 */
+		u32 partid_d = resctrl_get_config_index(closid, CDP_DATA);
+		u32 partid_i = resctrl_get_config_index(closid, CDP_CODE);
+
+		mpam_set_cpu_defaults(cpu, partid_d, partid_i, rmid, rmid);
+	}
+}
+
+void resctrl_arch_sync_cpu_closid_rmid(void *info)
+{
+	struct resctrl_cpu_defaults *r = info;
+
+	lockdep_assert_preemption_disabled();
+
+	if (r) {
+		resctrl_arch_set_cpu_default_closid_rmid(smp_processor_id(),
+							 r->closid, r->rmid);
+	}
+
+	resctrl_arch_sched_in(current);
+}
+
+void resctrl_arch_set_closid_rmid(struct task_struct *tsk, u32 closid, u32 rmid)
+{
+	WARN_ON_ONCE(closid > U16_MAX);
+	WARN_ON_ONCE(rmid > U8_MAX);
+
+	if (!cdp_enabled) {
+		mpam_set_task_partid_pmg(tsk, closid, closid, rmid, rmid);
+	} else {
+		u32 partid_d = resctrl_get_config_index(closid, CDP_DATA);
+		u32 partid_i = resctrl_get_config_index(closid, CDP_CODE);
+
+		mpam_set_task_partid_pmg(tsk, partid_d, partid_i, rmid, rmid);
+	}
+}
+
 struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l)
 {
 	if (l >= RDT_NUM_RESOURCES)
diff --git a/include/linux/arm_mpam.h b/include/linux/arm_mpam.h
index 2c7d1413a401..5a78299ec464 100644
--- a/include/linux/arm_mpam.h
+++ b/include/linux/arm_mpam.h
@@ -52,6 +52,11 @@ static inline int mpam_ris_create(struct mpam_msc *msc, u8 ris_idx,
 bool resctrl_arch_alloc_capable(void);
 bool resctrl_arch_mon_capable(void);
 
+void resctrl_arch_set_cpu_default_closid(int cpu, u32 closid);
+void resctrl_arch_set_closid_rmid(struct task_struct *tsk, u32 closid, u32 rmid);
+void resctrl_arch_set_cpu_default_closid_rmid(int cpu, u32 closid, u32 rmid);
+void resctrl_arch_sched_in(struct task_struct *tsk);
+
 /**
  * mpam_register_requestor() - Register a requestor with the MPAM driver
  * @partid_max:		The maximum PARTID value the requestor can generate.
-- 
2.39.5



From linux at fw-web.de  Fri Dec  5 13:59:38 2025
From: linux at fw-web.de (Frank Wunderlich)
Date: Fri,  5 Dec 2025 22:59:38 +0100
Subject: [PATCH] arm64: dts: mediatek: Apply mt8395-radxa DT overlay at build time
Message-ID: <20251205215940.19287-1-linux@fw-web.de>

From: "Rob Herring (Arm)" <robh at kernel.org>

It's a requirement that DT overlays be applied at build time in order to
validate them as overlays are not validated on their own.

Add missing target for mt8395-radxa hd panel overlay.

Fixes: 4c8ff61199a7 ("arm64: dts: mediatek: mt8395-radxa-nio-12l: Add Radxa 8 HD panel")
Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Frank Wunderlich <frank-w at public-files.de>
---
This will show a warning [1] in upcoming 6.19.

Note that if it is desired that the combined .dtb is not installed, then
the combined .dtb should be added to 'dtb-' variable instead.
---
extracted missing part from [2] with updated commit title/description
after my bananapi series [3] to solve all warnings. Added Fixes-tag to
make sure it lands in 6.19.

[1] https://lore.kernel.org/all/20251114222759.4181152-1-robh at kernel.org/
[2] https://patchwork.kernel.org/project/linux-mediatek/patch/20251117211306.725678-1-robh at kernel.org/
[3] https://patchwork.kernel.org/project/linux-mediatek/cover/20251119175124.48947-1-linux at fw-web.de/
---
 arch/arm64/boot/dts/mediatek/Makefile | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile
index cac8f4c6d76f..3f76d9ce9879 100644
--- a/arch/arm64/boot/dts/mediatek/Makefile
+++ b/arch/arm64/boot/dts/mediatek/Makefile
@@ -166,6 +166,8 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-grinn-genio-700-sbc.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-kontron-3-5-sbc-i1200.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-radxa-nio-12l.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-radxa-nio-12l-8-hd-panel.dtbo
+mt8395-radxa-nio-12l-8-hd-panel-dtbs := mt8395-radxa-nio-12l.dtb mt8395-radxa-nio-12l-8-hd-panel.dtbo
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-radxa-nio-12l-8-hd-panel.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8516-pumpkin.dtb
 
 # Device tree overlays support
-- 
2.43.0



From james.morse at arm.com  Fri Dec  5 13:58:36 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:36 +0000
Subject: [RFC PATCH 13/38] arm_mpam: resctrl: Add CDP emulation
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-14-james.morse@arm.com>

Intel RDT's CDP feature allows the cache to use a different control value
depending on whether the accesses was for instruction fetch or a data
access. MPAM's equivalent feature is the other way up: the CPU assigns a
different partid label to traffic depending on whether it was instruction
fetch or a data access, which causes the cache to use a different control
value based solely on the partid.

MPAM can emulate CDP, with the side effect that the alternative partid is
seen by all MSC, it can't be enabled per-MSC.

Add the resctrl hooks to turn this on or off. Add the helpers that
match a closid against a task, which need to be aware that the value
written to hardware is not the same as the one resctrl is using.

Update the 'arm64_mpam_global_default' variable the arch code uses
during context switch to know when the per-cpu value should be used
instead.

Awkwardly, the MB controls don't implement CDP. To emulate this, the
MPAM equivalent needs programming twice by the resctrl glue, as
resctrl expects the bandwidth controls to be applied independently for
both data and isntruction-fetch.

CC: Dave Martin <Dave.Martin at arm.com>
CC: Ben Horgan <ben.horgan at arm.com>
CC: Amit Singh Tomar <amitsinght at marvell.com>
Signed-off-by: James Morse <james.morse at arm.com>
---
 arch/arm64/include/asm/mpam.h  |   1 +
 drivers/resctrl/mpam_resctrl.c | 115 ++++++++++++++++++++++++++++++++-
 include/linux/arm_mpam.h       |   3 +
 3 files changed, 118 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/mpam.h
index 2960ffaf6574..689285c4c61f 100644
--- a/arch/arm64/include/asm/mpam.h
+++ b/arch/arm64/include/asm/mpam.h
@@ -4,6 +4,7 @@
 #ifndef __ASM__MPAM_H
 #define __ASM__MPAM_H
 
+#include <linux/arm_mpam.h>
 #include <linux/bitops.h>
 #include <linux/bitfield.h>
 #include <linux/init.h>
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index c2650abb99ec..d5f75ed67e46 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -33,6 +33,10 @@ static DEFINE_MUTEX(domain_list_lock);
 static bool exposed_alloc_capable;
 static bool exposed_mon_capable;
 
+/*
+ * MPAM emulates CDP by setting different PARTID in the I/D fields of MPAM0_EL1.
+ * This applies globally to all traffic the CPU generates.
+ */
 static bool cdp_enabled;
 
 bool resctrl_arch_alloc_capable(void)
@@ -45,6 +49,67 @@ bool resctrl_arch_mon_capable(void)
 	return exposed_mon_capable;
 }
 
+bool resctrl_arch_get_cdp_enabled(enum resctrl_res_level rid)
+{
+	switch (rid) {
+	case RDT_RESOURCE_L2:
+	case RDT_RESOURCE_L3:
+		return cdp_enabled;
+	case RDT_RESOURCE_MBA:
+	default:
+		/*
+		 * x86's MBA control doesn't support CDP, so user-space doesn't
+		 * expect it.
+		 */
+		return false;
+	}
+}
+
+/**
+ * resctrl_reset_task_closids() - Reset the PARTID/PMG values for all tasks.
+ *
+ * At boot, all existing tasks use partid zero for D and I.
+ * To enable/disable CDP emulation, all these tasks need relabelling.
+ */
+static void resctrl_reset_task_closids(void)
+{
+	struct task_struct *p, *t;
+
+	read_lock(&tasklist_lock);
+	for_each_process_thread(p, t) {
+		resctrl_arch_set_closid_rmid(t, RESCTRL_RESERVED_CLOSID,
+					     RESCTRL_RESERVED_RMID);
+	}
+	read_unlock(&tasklist_lock);
+}
+
+int resctrl_arch_set_cdp_enabled(enum resctrl_res_level ignored, bool enable)
+{
+	u32 partid_i, partid_d;
+
+	cdp_enabled = enable;
+	partid_i = partid_d = RESCTRL_RESERVED_CLOSID;
+
+	if (enable) {
+		u32 partid = RESCTRL_RESERVED_CLOSID;
+
+		partid_d = resctrl_get_config_index(partid, CDP_CODE);
+		partid_i = resctrl_get_config_index(partid, CDP_DATA);
+	}
+
+	mpam_set_task_partid_pmg(current, partid_d, partid_i, 0, 0);
+	WRITE_ONCE(arm64_mpam_global_default, mpam_get_regval(current));
+
+	resctrl_reset_task_closids();
+
+	return 0;
+}
+
+static bool mpam_resctrl_hide_cdp(enum resctrl_res_level rid)
+{
+	return cdp_enabled && !resctrl_arch_get_cdp_enabled(rid);
+}
+
 /*
  * MSC may raise an error interrupt if it sees an out or range partid/pmg,
  * and go on to truncate the value. Regardless of what the hardware supports,
@@ -110,6 +175,30 @@ void resctrl_arch_set_closid_rmid(struct task_struct *tsk, u32 closid, u32 rmid)
 	}
 }
 
+bool resctrl_arch_match_closid(struct task_struct *tsk, u32 closid)
+{
+	u64 regval = mpam_get_regval(tsk);
+	u32 tsk_closid = FIELD_GET(MPAM0_EL1_PARTID_D, regval);
+
+	if (cdp_enabled)
+		tsk_closid >>= 1;
+
+	return tsk_closid == closid;
+}
+
+/* The task's pmg is not unique, the partid must be considered too */
+bool resctrl_arch_match_rmid(struct task_struct *tsk, u32 closid, u32 rmid)
+{
+	u64 regval = mpam_get_regval(tsk);
+	u32 tsk_closid = FIELD_GET(MPAM0_EL1_PARTID_D, regval);
+	u32 tsk_rmid = FIELD_GET(MPAM0_EL1_PMG_D, regval);
+
+	if (cdp_enabled)
+		tsk_closid >>= 1;
+
+	return (tsk_closid == closid) && (tsk_rmid == rmid);
+}
+
 struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l)
 {
 	if (l >= RDT_NUM_RESOURCES)
@@ -245,6 +334,14 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 	dom = container_of(d, struct mpam_resctrl_dom, resctrl_ctrl_dom);
 	cprops = &res->class->props;
 
+	/*
+	 * When CDP is enabled, but the resource doesn't support it,
+	 * the control is cloned across both partids.
+	 * Pick one at random to read:
+	 */
+	if (mpam_resctrl_hide_cdp(r->rid))
+		type = CDP_DATA;
+
 	partid = resctrl_get_config_index(closid, type);
 	cfg = &dom->ctrl_comp->cfg[partid];
 
@@ -272,6 +369,7 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 			    u32 closid, enum resctrl_conf_type t, u32 cfg_val)
 {
+	int err;
 	u32 partid;
 	struct mpam_config cfg;
 	struct mpam_props *cprops;
@@ -311,7 +409,22 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 		return -EINVAL;
 	}
 
-	return mpam_apply_config(dom->ctrl_comp, partid, &cfg);
+	/*
+	 * When CDP is enabled, but the resource doesn't support it, we need to
+	 * apply the same configuration to the other partid.
+	 */
+	if (mpam_resctrl_hide_cdp(r->rid)) {
+		partid = resctrl_get_config_index(closid, CDP_CODE);
+		err = mpam_apply_config(dom->ctrl_comp, partid, &cfg);
+		if (err)
+			return err;
+
+		partid = resctrl_get_config_index(closid, CDP_DATA);
+		return mpam_apply_config(dom->ctrl_comp, partid, &cfg);
+
+	} else {
+		return mpam_apply_config(dom->ctrl_comp, partid, &cfg);
+	}
 }
 
 int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid)
diff --git a/include/linux/arm_mpam.h b/include/linux/arm_mpam.h
index 5a78299ec464..ba0312b55d9f 100644
--- a/include/linux/arm_mpam.h
+++ b/include/linux/arm_mpam.h
@@ -5,6 +5,7 @@
 #define __LINUX_ARM_MPAM_H
 
 #include <linux/acpi.h>
+#include <linux/resctrl_types.h>
 #include <linux/types.h>
 
 struct mpam_msc;
@@ -56,6 +57,8 @@ void resctrl_arch_set_cpu_default_closid(int cpu, u32 closid);
 void resctrl_arch_set_closid_rmid(struct task_struct *tsk, u32 closid, u32 rmid);
 void resctrl_arch_set_cpu_default_closid_rmid(int cpu, u32 closid, u32 rmid);
 void resctrl_arch_sched_in(struct task_struct *tsk);
+bool resctrl_arch_match_closid(struct task_struct *tsk, u32 closid);
+bool resctrl_arch_match_rmid(struct task_struct *tsk, u32 closid, u32 rmid);
 
 /**
  * mpam_register_requestor() - Register a requestor with the MPAM driver
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:37 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:37 +0000
Subject: [RFC PATCH 14/38] arm_mpam: resctrl: Add rmid index helpers
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-15-james.morse@arm.com>

Because MPAM's pmg aren't identical to RDT's rmid, resctrl handles
some data structures by index. This allows x86 to map indexes to
RMID, and MPAM to map them to partid-and-pmg.

Add the helpers to do this.

Signed-off-by: James Morse <james.morse at arm.com>
---
 drivers/resctrl/mpam_resctrl.c | 28 ++++++++++++++++++++++++++++
 include/linux/arm_mpam.h       |  3 +++
 2 files changed, 31 insertions(+)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index d5f75ed67e46..19d70d00bbcc 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -120,6 +120,34 @@ u32 resctrl_arch_get_num_closid(struct rdt_resource *ignored)
 	return mpam_partid_max + 1;
 }
 
+u32 resctrl_arch_system_num_rmid_idx(void)
+{
+	u8 closid_shift = fls(mpam_pmg_max);
+	u32 num_partid = resctrl_arch_get_num_closid(NULL);
+
+	return num_partid << closid_shift;
+}
+
+u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid)
+{
+	u8 closid_shift = fls(mpam_pmg_max);
+
+	WARN_ON_ONCE(closid_shift > 8);
+
+	return (closid << closid_shift) | rmid;
+}
+
+void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid)
+{
+	u8 closid_shift = fls(mpam_pmg_max);
+	u32 pmg_mask = ~(~0 << closid_shift);
+
+	WARN_ON_ONCE(closid_shift > 8);
+
+	*closid = idx >> closid_shift;
+	*rmid = idx & pmg_mask;
+}
+
 void resctrl_arch_sched_in(struct task_struct *tsk)
 {
 	lockdep_assert_preemption_disabled();
diff --git a/include/linux/arm_mpam.h b/include/linux/arm_mpam.h
index ba0312b55d9f..385554ceb452 100644
--- a/include/linux/arm_mpam.h
+++ b/include/linux/arm_mpam.h
@@ -59,6 +59,9 @@ void resctrl_arch_set_cpu_default_closid_rmid(int cpu, u32 closid, u32 rmid);
 void resctrl_arch_sched_in(struct task_struct *tsk);
 bool resctrl_arch_match_closid(struct task_struct *tsk, u32 closid);
 bool resctrl_arch_match_rmid(struct task_struct *tsk, u32 closid, u32 rmid);
+u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid);
+void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid);
+u32 resctrl_arch_system_num_rmid_idx(void);
 
 /**
  * mpam_register_requestor() - Register a requestor with the MPAM driver
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:38 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:38 +0000
Subject: [RFC PATCH 15/38] arm_mpam: resctrl: Convert to/from MPAMs fixed-point formats
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-16-james.morse@arm.com>

From: Dave Martin <Dave.Martin at arm.com>

MPAM uses a fixed-point formats for some hardware controls.
Resctrl provides the bandwidth controls as a percentage. Add helpers to
convert between these.

Signed-off-by: Dave Martin <Dave.Martin at arm.com>
Signed-off-by: James Morse <james.morse at arm.com>
---
 drivers/resctrl/mpam_resctrl.c | 41 ++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 19d70d00bbcc..55576d0caf12 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -10,6 +10,7 @@
 #include <linux/errno.h>
 #include <linux/limits.h>
 #include <linux/list.h>
+#include <linux/math.h>
 #include <linux/printk.h>
 #include <linux/rculist.h>
 #include <linux/resctrl.h>
@@ -246,6 +247,46 @@ static bool cache_has_usable_cpor(struct mpam_class *class)
 	return (class->props.cpbm_wd <= 32);
 }
 
+/*
+ * Each fixed-point hardware value architecturally represents a range
+ * of values: the full range 0% - 100% is split contiguously into
+ * (1 << cprops->bwa_wd) equal bands.
+ * Find the nearest percentage value to the upper bound of the selected band:
+ */
+static u32 mbw_max_to_percent(u16 mbw_max, struct mpam_props *cprops)
+{
+	u32 val = mbw_max;
+
+	val >>= 16 - cprops->bwa_wd;
+	val += 1;
+	val *= MAX_MBA_BW;
+	val = DIV_ROUND_CLOSEST(val, 1 << cprops->bwa_wd);
+
+	return val;
+}
+
+/*
+ * Find the band whose upper bound is closest to the specified percentage.
+ *
+ * A round-to-nearest policy is followed here as a balanced compromise
+ * between unexpected under-commit of the resource (where the total of
+ * a set of resource allocations after conversion is less than the
+ * expected total, due to rounding of the individual converted
+ * percentages) and over-commit (where the total of the converted
+ * allocations is greater than expected).
+ */
+static u16 percent_to_mbw_max(u8 pc, struct mpam_props *cprops)
+{
+	u32 val = pc;
+
+	val <<= cprops->bwa_wd;
+	val = DIV_ROUND_CLOSEST(val, MAX_MBA_BW);
+	val = max(val, 1) - 1;
+	val <<= 16 - cprops->bwa_wd;
+
+	return val;
+}
+
 /* Test whether we can export MPAM_CLASS_CACHE:{2,3}? */
 static void mpam_resctrl_pick_caches(void)
 {
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:39 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:39 +0000
Subject: [RFC PATCH 16/38] arm_mpam: resctrl: Add support for 'MB' resource
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-17-james.morse@arm.com>

resctrl supports 'MB', as a percentage throttling of traffic somewhere
after the L3. This is the control that mba_sc uses, so ideally the
class chosen should be as close as possible to the counters used for
mba_local.

MB's percentage control should be backed either with the fixed point
fraction MBW_MAX. The bandwidth portion bitmaps is not used as its
tricky to pick which bits to use to avoid contention, and may be
possible to expose this as something other than a percentage in the
future.

CC: Zeng Heng <zengheng4 at huawei.com>
Co-developed-by: Dave Martin <Dave.Martin at arm.com>
Signed-off-by: Dave Martin <Dave.Martin at arm.com>
Signed-off-by: James Morse <james.morse at arm.com>>
---
 drivers/resctrl/mpam_resctrl.c | 212 ++++++++++++++++++++++++++++++++-
 1 file changed, 211 insertions(+), 1 deletion(-)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 55576d0caf12..b9f3f00d8cad 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -247,6 +247,33 @@ static bool cache_has_usable_cpor(struct mpam_class *class)
 	return (class->props.cpbm_wd <= 32);
 }
 
+static bool mba_class_use_mbw_max(struct mpam_props *cprops)
+{
+	return (mpam_has_feature(mpam_feat_mbw_max, cprops) &&
+		cprops->bwa_wd);
+}
+
+static bool class_has_usable_mba(struct mpam_props *cprops)
+{
+	return mba_class_use_mbw_max(cprops);
+}
+
+/*
+ * Calculate the worst-case percentage change from each implemented step
+ * in the control.
+ */
+static u32 get_mba_granularity(struct mpam_props *cprops)
+{
+	if (!mba_class_use_mbw_max(cprops))
+		return 0;
+
+	/*
+	 * bwa_wd is the number of bits implemented in the 0.xxx
+	 * fixed point fraction. 1 bit is 50%, 2 is 25% etc.
+	 */
+	return DIV_ROUND_UP(MAX_MBA_BW, 1 << cprops->bwa_wd);
+}
+
 /*
  * Each fixed-point hardware value architecturally represents a range
  * of values: the full range 0% - 100% is split contiguously into
@@ -287,6 +314,96 @@ static u16 percent_to_mbw_max(u8 pc, struct mpam_props *cprops)
 	return val;
 }
 
+static u32 get_mba_min(struct mpam_props *cprops)
+{
+	u32 val = 0;
+
+	if (mba_class_use_mbw_max(cprops))
+		val = mbw_max_to_percent(val, cprops);
+	else
+		WARN_ON_ONCE(1);
+
+	return val;
+}
+
+/* Find the L3 cache that has affinity with this CPU */
+static int find_l3_equivalent_bitmask(int cpu, cpumask_var_t tmp_cpumask)
+{
+	u32 cache_id = get_cpu_cacheinfo_id(cpu, 3);
+
+	lockdep_assert_cpus_held();
+
+	return mpam_get_cpumask_from_cache_id(cache_id, 3, tmp_cpumask);
+}
+
+/*
+ * topology_matches_l3() - Is the provided class the same shape as L3
+ * @victim:		The class we'd like to pretend is L3.
+ *
+ * resctrl expects all the world's a Xeon, and all counters are on the
+ * L3. We play fast and loose with this, mapping counters on other
+ * classes - provided the CPU->domain mapping is the same kind of shape.
+ *
+ * Using cacheinfo directly would make this work even if resctrl can't
+ * use the L3 - but cacheinfo can't tell us anything about offline CPUs.
+ * Using the L3 resctrl domain list also depends on CPUs being online.
+ * Using the mpam_class we picked for L3 so we can use its domain list
+ * assumes that there are MPAM controls on the L3.
+ * Instead, this path eventually uses the mpam_get_cpumask_from_cache_id()
+ * helper which can tell us about offline CPUs ... but getting the cache_id
+ * to start with relies on at least one CPU per L3 cache being online at
+ * boot.
+ *
+ * Walk the victim component list and compare the affinity mask with the
+ * corresponding L3. The topology matches if each victim:component's affinity
+ * mask is the same as the CPU's corresponding L3's. These lists/masks are
+ * computed from firmware tables so don't change at runtime.
+ */
+static bool topology_matches_l3(struct mpam_class *victim)
+{
+	int cpu, err;
+	struct mpam_component *victim_iter;
+	cpumask_var_t __free(free_cpumask_var) tmp_cpumask;
+
+	if (!alloc_cpumask_var(&tmp_cpumask, GFP_KERNEL))
+		return false;
+
+	guard(srcu)(&mpam_srcu);
+	list_for_each_entry_srcu(victim_iter, &victim->components, class_list,
+				 srcu_read_lock_held(&mpam_srcu)) {
+		if (cpumask_empty(&victim_iter->affinity)) {
+			pr_debug("class %u has CPU-less component %u - can't match L3!\n",
+				 victim->level, victim_iter->comp_id);
+			return false;
+		}
+
+		cpu = cpumask_any(&victim_iter->affinity);
+		if (WARN_ON_ONCE(cpu >= nr_cpu_ids))
+			return false;
+
+		cpumask_clear(tmp_cpumask);
+		err = find_l3_equivalent_bitmask(cpu, tmp_cpumask);
+		if (err) {
+			pr_debug("Failed to find L3's equivalent component to class %u component %u\n",
+				 victim->level, victim_iter->comp_id);
+			return false;
+		}
+
+		/* Any differing bits in the affinity mask? */
+		if (!cpumask_equal(tmp_cpumask, &victim_iter->affinity)) {
+			pr_debug("class %u component %u has Mismatched CPU mask with L3 equivalent\n"
+				 "L3:%*pbl != victim:%*pbl\n",
+				 victim->level, victim_iter->comp_id,
+				 cpumask_pr_args(tmp_cpumask),
+				 cpumask_pr_args(&victim_iter->affinity));
+
+			return false;
+		}
+	}
+
+	return true;
+}
+
 /* Test whether we can export MPAM_CLASS_CACHE:{2,3}? */
 static void mpam_resctrl_pick_caches(void)
 {
@@ -330,10 +447,63 @@ static void mpam_resctrl_pick_caches(void)
 	}
 }
 
+static void mpam_resctrl_pick_mba(void)
+{
+	struct mpam_class *class, *candidate_class = NULL;
+	struct mpam_resctrl_res *res;
+
+	lockdep_assert_cpus_held();
+
+	guard(srcu)(&mpam_srcu);
+	list_for_each_entry_srcu(class, &mpam_classes, classes_list,
+				 srcu_read_lock_held(&mpam_srcu)) {
+		struct mpam_props *cprops = &class->props;
+
+		if (class->level < 3) {
+			pr_debug("class %u is before L3\n", class->level);
+			continue;
+		}
+
+		if (!class_has_usable_mba(cprops)) {
+			pr_debug("class %u has no bandwidth control\n",
+				 class->level);
+			continue;
+		}
+
+		if (!cpumask_equal(&class->affinity, cpu_possible_mask)) {
+			pr_debug("class %u has missing CPUs\n", class->level);
+			continue;
+		}
+
+		if (!topology_matches_l3(class)) {
+			pr_debug("class %u topology doesn't match L3\n",
+				 class->level);
+			continue;
+		}
+
+		/*
+		 * mba_sc reads the mbm_local counter, and waggles the MBA
+		 * controls. mbm_local is implicitly part of the L3, pick a
+		 * resource to be MBA that as close as possible to the L3.
+		 */
+		if (!candidate_class || class->level < candidate_class->level)
+			candidate_class = class;
+	}
+
+	if (candidate_class) {
+		pr_debug("selected class %u to back MBA\n",
+			 candidate_class->level);
+		res = &mpam_resctrl_controls[RDT_RESOURCE_MBA];
+		res->class = candidate_class;
+		exposed_alloc_capable = true;
+	}
+}
+
 static int mpam_resctrl_control_init(struct mpam_resctrl_res *res,
 				     enum resctrl_res_level type)
 {
 	struct mpam_class *class = res->class;
+	struct mpam_props *cprops = &class->props;
 	struct rdt_resource *r = &res->resctrl_res;
 
 	switch (res->resctrl_res.rid) {
@@ -362,6 +532,20 @@ static int mpam_resctrl_control_init(struct mpam_resctrl_res *res,
 		 * 'all the bits' is the correct answer here.
 		 */
 		r->cache.shareable_bits = resctrl_get_default_ctrl(r);
+		break;
+	case RDT_RESOURCE_MBA:
+		r->alloc_capable = true;
+		r->schema_fmt = RESCTRL_SCHEMA_RANGE;
+		r->ctrl_scope = RESCTRL_L3_CACHE;
+
+		r->membw.delay_linear = true;
+		r->membw.throttle_mode = THREAD_THROTTLE_UNDEFINED;
+		r->membw.min_bw = get_mba_min(cprops);
+		r->membw.max_bw = MAX_MBA_BW;
+		r->membw.bw_gran = get_mba_granularity(cprops);
+
+		r->name = "MB";
+
 		break;
 	default:
 		break;
@@ -377,7 +561,17 @@ static int mpam_resctrl_pick_domain_id(int cpu, struct mpam_component *comp)
 	if (class->type == MPAM_CLASS_CACHE)
 		return comp->comp_id;
 
-	/* TODO: repaint domain ids to match the L3 domain ids */
+	if (topology_matches_l3(class)) {
+		/* Use the corresponding L3 component ID as the domain ID */
+		int id = get_cpu_cacheinfo_id(cpu, 3);
+
+		/* Implies topology_matches_l3() made a mistake */
+		if (WARN_ON_ONCE(id == -1))
+			return comp->comp_id;
+
+		return id;
+	}
+
 	/*
 	 * Otherwise, expose the ID used by the firmware table code.
 	 */
@@ -419,6 +613,12 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 	case RDT_RESOURCE_L3:
 		configured_by = mpam_feat_cpor_part;
 		break;
+	case RDT_RESOURCE_MBA:
+		if (mpam_has_feature(mpam_feat_mbw_max, cprops)) {
+			configured_by = mpam_feat_mbw_max;
+			break;
+		}
+		fallthrough;
 	default:
 		return resctrl_get_default_ctrl(r);
 	}
@@ -430,6 +630,8 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 	switch (configured_by) {
 	case mpam_feat_cpor_part:
 		return cfg->cpbm;
+	case mpam_feat_mbw_max:
+		return mbw_max_to_percent(cfg->mbw_max, cprops);
 	default:
 		return resctrl_get_default_ctrl(r);
 	}
@@ -474,6 +676,13 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 		cfg.cpbm = cfg_val;
 		mpam_set_feature(mpam_feat_cpor_part, &cfg);
 		break;
+	case RDT_RESOURCE_MBA:
+		if (mpam_has_feature(mpam_feat_mbw_max, cprops)) {
+			cfg.mbw_max = percent_to_mbw_max(cfg_val, cprops);
+			mpam_set_feature(mpam_feat_mbw_max, &cfg);
+			break;
+		}
+		fallthrough;
 	default:
 		return -EINVAL;
 	}
@@ -743,6 +952,7 @@ int mpam_resctrl_setup(void)
 
 	/* Find some classes to use for controls */
 	mpam_resctrl_pick_caches();
+	mpam_resctrl_pick_mba();
 
 	/* Initialise the resctrl structures from the classes */
 	for (i = 0; i < RDT_NUM_RESOURCES; i++) {
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:40 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:40 +0000
Subject: [RFC PATCH 17/38] arm_mpam: resctrl: Add kunit test for control format conversions
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-18-james.morse@arm.com>

From: Dave Martin <Dave.Martin at arm.com>

resctrl specifies the format of the control schemes, and these don't
match the hardware.

Some of the conversions are a bit hairy - add some kunit tests.

Signed-off-by: Dave Martin <Dave.Martin at arm.com>
[morse: squashed enough of Dave's fixes in here that it's his patch now!]
Signed-off-by: James Morse <james.morse at arm.com>
---
 drivers/resctrl/mpam_resctrl.c      |   4 +
 drivers/resctrl/test_mpam_resctrl.c | 312 ++++++++++++++++++++++++++++
 2 files changed, 316 insertions(+)
 create mode 100644 drivers/resctrl/test_mpam_resctrl.c

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index b9f3f00d8cad..fe830524639e 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -993,3 +993,7 @@ int mpam_resctrl_setup(void)
 
 	return err;
 }
+
+#ifdef CONFIG_MPAM_KUNIT_TEST
+#include "test_mpam_resctrl.c"
+#endif
diff --git a/drivers/resctrl/test_mpam_resctrl.c b/drivers/resctrl/test_mpam_resctrl.c
new file mode 100644
index 000000000000..d0615aa7671c
--- /dev/null
+++ b/drivers/resctrl/test_mpam_resctrl.c
@@ -0,0 +1,312 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2025 Arm Ltd.
+/* This file is intended to be included into mpam_resctrl.c */
+
+#include <kunit/test.h>
+#include <linux/array_size.h>
+#include <linux/bits.h>
+#include <linux/math.h>
+#include <linux/sprintf.h>
+
+struct percent_value_case {
+	u8	pc;
+	u8	width;
+	u16	value;
+};
+
+/*
+ * Mysterious inscriptions taken from ARM DDI 0598D.b,
+ * "Arm Architecture Reference Manual Supplement - Memory System
+ * Resource Partitioning and Monitoring (MPAM), for A-profile
+ * architecture", Section 9.8, "About the fixed-point fractional
+ * format" (exact percentage entries only):
+ */
+static const struct percent_value_case percent_value_cases[] = {
+	/* Architectural cases: */
+	{   1,  8,    1 },	{   1, 12,  0x27 },	{   1, 16,  0x28e },
+	{  25,  8, 0x3f },	{  25, 12, 0x3ff },	{  25, 16, 0x3fff },
+	{  35,  8, 0x58 },	{  35, 12, 0x598 },	{  35, 16, 0x5998 },
+	{  45,  8, 0x72 },	{  45, 12, 0x732 },	{  45, 16, 0x7332 },
+	{  50,  8, 0x7f },	{  50, 12, 0x7ff },	{  50, 16, 0x7fff },
+	{  52,  8, 0x84 },	{  52, 12, 0x850 },	{  52, 16, 0x851d },
+	{  55,  8, 0x8b },	{  55, 12, 0x8cb },	{  55, 16, 0x8ccb },
+	{  58,  8, 0x93 },	{  58, 12, 0x946 },	{  58, 16, 0x9479 },
+	{  75,  8, 0xbf },	{  75, 12, 0xbff },	{  75, 16, 0xbfff },
+	{  88,  8, 0xe0 },	{  88, 12, 0xe13 },	{  88, 16, 0xe146 },
+	{  95,  8, 0xf2 },	{  95, 12, 0xf32 },	{  95, 16, 0xf332 },
+	{ 100,  8, 0xff },	{ 100, 12, 0xfff },	{ 100, 16, 0xffff },
+
+};
+
+static void test_percent_value_desc(const struct percent_value_case *param,
+				    char *desc)
+{
+	snprintf(desc, KUNIT_PARAM_DESC_SIZE,
+		 "pc=%d, width=%d, value=0x%.*x\n",
+		 param->pc, param->width,
+		 DIV_ROUND_UP(param->width, 4), param->value);
+}
+
+KUNIT_ARRAY_PARAM(test_percent_value, percent_value_cases,
+		  test_percent_value_desc);
+
+struct percent_value_test_info {
+	u32 pc;			/* result of value-to-percent conversion */
+	u32 value;		/* result of percent-to-value conversion */
+	u32 max_value;		/* maximum raw value allowed by test params */
+	unsigned int shift;	/* promotes raw testcase value to 16 bits */
+};
+
+/*
+ * Convert a reference percentage to a fixed-point MAX value and
+ * vice-versa, based on param (not test->param_value!)
+ */
+static void __prepare_percent_value_test(struct kunit *test,
+					 struct percent_value_test_info *res,
+					 const struct percent_value_case *param)
+{
+	struct mpam_props fake_props = { };
+
+	/* Reject bogus test parameters that would break the tests: */
+	KUNIT_ASSERT_GE(test, param->width, 1);
+	KUNIT_ASSERT_LE(test, param->width, 16);
+	KUNIT_ASSERT_LT(test, param->value, 1 << param->width);
+
+	mpam_set_feature(mpam_feat_mbw_max, &fake_props);
+	fake_props.bwa_wd = param->width;
+
+	res->shift = 16 - param->width;
+	res->max_value = GENMASK_U32(param->width - 1, 0);
+	res->value = percent_to_mbw_max(param->pc, &fake_props);
+	res->pc = mbw_max_to_percent(param->value << res->shift, &fake_props);
+}
+
+static void test_get_mba_granularity(struct kunit *test)
+{
+	int ret;
+	struct mpam_props fake_props = { };
+
+	/* Use MBW_MAX */
+	mpam_set_feature(mpam_feat_mbw_max, &fake_props);
+
+	fake_props.bwa_wd = 0;
+	KUNIT_EXPECT_FALSE(test, mba_class_use_mbw_max(&fake_props));
+
+	fake_props.bwa_wd = 1;
+	KUNIT_EXPECT_TRUE(test, mba_class_use_mbw_max(&fake_props));
+
+	/* Architectural maximum: */
+	fake_props.bwa_wd = 16;
+	KUNIT_EXPECT_TRUE(test, mba_class_use_mbw_max(&fake_props));
+
+	/* No usable control... */
+	fake_props.bwa_wd = 0;
+	ret = get_mba_granularity(&fake_props);
+	KUNIT_EXPECT_EQ(test, ret, 0);
+
+	fake_props.bwa_wd = 1;
+	ret = get_mba_granularity(&fake_props);
+	KUNIT_EXPECT_EQ(test, ret, 50);	/* DIV_ROUND_UP(100, 1 << 1)% = 50% */
+
+	fake_props.bwa_wd = 2;
+	ret = get_mba_granularity(&fake_props);
+	KUNIT_EXPECT_EQ(test, ret, 25);	/* DIV_ROUND_UP(100, 1 << 2)% = 25% */
+
+	fake_props.bwa_wd = 3;
+	ret = get_mba_granularity(&fake_props);
+	KUNIT_EXPECT_EQ(test, ret, 13);	/* DIV_ROUND_UP(100, 1 << 3)% = 13% */
+
+	fake_props.bwa_wd = 6;
+	ret = get_mba_granularity(&fake_props);
+	KUNIT_EXPECT_EQ(test, ret, 2);	/* DIV_ROUND_UP(100, 1 << 6)% = 2% */
+
+	fake_props.bwa_wd = 7;
+	ret = get_mba_granularity(&fake_props);
+	KUNIT_EXPECT_EQ(test, ret, 1);	/* DIV_ROUND_UP(100, 1 << 7)% = 1% */
+
+	/* Granularity saturates at 1% */
+	fake_props.bwa_wd = 16; /* architectural maximum */
+	ret = get_mba_granularity(&fake_props);
+	KUNIT_EXPECT_EQ(test, ret, 1);	/* DIV_ROUND_UP(100, 1 << 16)% = 1% */
+}
+
+static void test_mbw_max_to_percent(struct kunit *test)
+{
+	const struct percent_value_case *param = test->param_value;
+	struct percent_value_test_info res;
+
+	/*
+	 * Since the reference values in percent_value_cases[] all
+	 * correspond to exact percentages, round-to-nearest will
+	 * always give the exact percentage back when the MPAM max
+	 * value has precision of 0.5% or finer.  (Always true for the
+	 * reference data, since they all specify 8 bits or more of
+	 * precision.
+	 *
+	 * So, keep it simple and demand an exact match:
+	 */
+	__prepare_percent_value_test(test, &res, param);
+	KUNIT_EXPECT_EQ(test, res.pc, param->pc);
+}
+
+static void test_percent_to_mbw_max(struct kunit *test)
+{
+	const struct percent_value_case *param = test->param_value;
+	struct percent_value_test_info res;
+
+	__prepare_percent_value_test(test, &res, param);
+
+	KUNIT_EXPECT_GE(test, res.value, param->value << res.shift);
+	KUNIT_EXPECT_LE(test, res.value, (param->value + 1) << res.shift);
+	KUNIT_EXPECT_LE(test, res.value, res.max_value << res.shift);
+
+	/* No flexibility allowed for 0% and 100%! */
+
+	if (param->pc == 0)
+		KUNIT_EXPECT_EQ(test, res.value, 0);
+
+	if (param->pc == 100)
+		KUNIT_EXPECT_EQ(test, res.value, res.max_value << res.shift);
+}
+
+static const void *test_all_bwa_wd_gen_params(struct kunit *test, const void *prev,
+					      char *desc)
+{
+	uintptr_t param = (uintptr_t)prev;
+
+	if (param > 15)
+		return NULL;
+
+	param++;
+
+	snprintf(desc, KUNIT_PARAM_DESC_SIZE, "wd=%u\n", (unsigned int)param);
+
+	return (void *)param;
+}
+
+static unsigned int test_get_bwa_wd(struct kunit *test)
+{
+	uintptr_t param = (uintptr_t)test->param_value;
+
+	KUNIT_ASSERT_GE(test, param, 1);
+	KUNIT_ASSERT_LE(test, param, 16);
+
+	return param;
+}
+
+static void test_mbw_max_to_percent_limits(struct kunit *test)
+{
+	struct mpam_props fake_props = {0};
+	u32 max_value;
+
+	mpam_set_feature(mpam_feat_mbw_max, &fake_props);
+	fake_props.bwa_wd = test_get_bwa_wd(test);
+	max_value = GENMASK(15, 16 - fake_props.bwa_wd);
+
+	KUNIT_EXPECT_EQ(test, mbw_max_to_percent(max_value, &fake_props),
+			MAX_MBA_BW);
+	KUNIT_EXPECT_EQ(test, mbw_max_to_percent(0, &fake_props),
+			get_mba_min(&fake_props));
+
+	/*
+	 * Rounding policy dependent 0% sanity-check:
+	 * With round-to-nearest, the minimum mbw_max value really
+	 * should map to 0% if there are at least 200 steps.
+	 * (100 steps may be enough for some other rounding policies.)
+	 */
+	if (fake_props.bwa_wd >= 8)
+		KUNIT_EXPECT_EQ(test, mbw_max_to_percent(0, &fake_props), 0);
+
+	if (fake_props.bwa_wd < 8 &&
+	    mbw_max_to_percent(0, &fake_props) == 0)
+		kunit_warn(test, "wd=%d: Testsuite/driver Rounding policy mismatch?",
+			   fake_props.bwa_wd);
+}
+
+/*
+ * Check that converting a percentage to mbw_max and back again (or, as
+ * appropriate, vice-versa) always restores the original value:
+ */
+static void test_percent_max_roundtrip_stability(struct kunit *test)
+{
+	struct mpam_props fake_props = {0};
+	unsigned int shift;
+	u32 pc, max, pc2, max2;
+
+	mpam_set_feature(mpam_feat_mbw_max, &fake_props);
+	fake_props.bwa_wd = test_get_bwa_wd(test);
+	shift = 16 - fake_props.bwa_wd;
+
+	/*
+	 * Converting a valid value from the coarser scale to the finer
+	 * scale and back again must yield the original value:
+	 */
+	if (fake_props.bwa_wd >= 7) {
+		/* More than 100 steps: only test exact pc values: */
+		for (pc = get_mba_min(&fake_props); pc <= MAX_MBA_BW; pc++) {
+			max = percent_to_mbw_max(pc, &fake_props);
+			pc2 = mbw_max_to_percent(max, &fake_props);
+			KUNIT_EXPECT_EQ(test, pc2, pc);
+		}
+	} else {
+		/* Fewer than 100 steps: only test exact mbw_max values: */
+		for (max = 0; max < 1 << 16; max += 1 << shift) {
+			pc = mbw_max_to_percent(max, &fake_props);
+			max2 = percent_to_mbw_max(pc, &fake_props);
+			KUNIT_EXPECT_EQ(test, max2, max);
+		}
+	}
+}
+
+static void test_percent_to_max_rounding(struct kunit *test)
+{
+	const struct percent_value_case *param = test->param_value;
+	unsigned int num_rounded_up = 0, total = 0;
+	struct percent_value_test_info res;
+
+	for (param = percent_value_cases, total = 0;
+	     param < &percent_value_cases[ARRAY_SIZE(percent_value_cases)];
+	     param++, total++) {
+		__prepare_percent_value_test(test, &res, param);
+		if (res.value > param->value << res.shift)
+			num_rounded_up++;
+	}
+
+	/*
+	 * The MPAM driver applies a round-to-nearest policy, whereas a
+	 * round-down policy seems to have been applied in the
+	 * reference table from which the test vectors were selected.
+	 *
+	 * For a large and well-distributed suite of test vectors,
+	 * about half should be rounded up and half down compared with
+	 * the reference table.  The actual test vectors are few in
+	 * number and probably not very well distributed however, so
+	 * tolerate a round-up rate of between 1/4 and 3/4 before
+	 * crying foul:
+	 */
+
+	kunit_info(test, "Round-up rate: %u%% (%u/%u)\n",
+		   DIV_ROUND_CLOSEST(num_rounded_up * 100, total),
+		   num_rounded_up, total);
+
+	KUNIT_EXPECT_GE(test, 4 * num_rounded_up, 1 * total);
+	KUNIT_EXPECT_LE(test, 4 * num_rounded_up, 3 * total);
+}
+
+static struct kunit_case mpam_resctrl_test_cases[] = {
+	KUNIT_CASE(test_get_mba_granularity),
+	KUNIT_CASE_PARAM(test_mbw_max_to_percent, test_percent_value_gen_params),
+	KUNIT_CASE_PARAM(test_percent_to_mbw_max, test_percent_value_gen_params),
+	KUNIT_CASE_PARAM(test_mbw_max_to_percent_limits, test_all_bwa_wd_gen_params),
+	KUNIT_CASE(test_percent_to_max_rounding),
+	KUNIT_CASE_PARAM(test_percent_max_roundtrip_stability,
+			 test_all_bwa_wd_gen_params),
+	{}
+};
+
+static struct kunit_suite mpam_resctrl_test_suite = {
+	.name = "mpam_resctrl_test_suite",
+	.test_cases = mpam_resctrl_test_cases,
+};
+
+kunit_test_suites(&mpam_resctrl_test_suite);
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:41 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:41 +0000
Subject: [RFC PATCH 18/38] arm_mpam: resctrl: Add support for csu counters
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-19-james.morse@arm.com>

resctrl exposes a counter via a file named llc_occupancy. This isn't really
a counter as its value goes up and down, this is a snapshot of the cache
storage usage monitor.

Add some picking code to find a cache as close as possible to the L3 that
supports the CSU monitor.

If there is an L3, but it doesn't have any controls, force the L3 resource
to exist. The existing topology_matches_l3() and
mpam_resctrl_domain_hdr_init() code will ensure this looks like the L3,
even if the class belongs to a later cache.

Signed-off-by: James Morse <james.morse at arm.com>
---
 drivers/resctrl/mpam_internal.h |   6 ++
 drivers/resctrl/mpam_resctrl.c  | 148 ++++++++++++++++++++++++++++++++
 2 files changed, 154 insertions(+)

diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index 8684bd35d4ab..f9d2a1004c32 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -348,6 +348,12 @@ struct mpam_resctrl_res {
 	struct rdt_resource	resctrl_res;
 };
 
+struct mpam_resctrl_mon {
+	struct mpam_class	*class;
+
+	/* per-class data that resctrl needs will live here */
+};
+
 static inline int mpam_alloc_csu_mon(struct mpam_class *class)
 {
 	struct mpam_props *cprops = &class->props;
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index fe830524639e..fc1f054f187e 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -31,6 +31,16 @@ static struct mpam_resctrl_res mpam_resctrl_controls[RDT_NUM_RESOURCES];
 /* The lock for modifying resctrl's domain lists from cpuhp callbacks. */
 static DEFINE_MUTEX(domain_list_lock);
 
+/*
+ * The classes we've picked to map to resctrl events.
+ * Resctrl believes all the worlds a Xeon, and these are all on the L3. This
+ * array lets us find the actual class backing the event counters. e.g.
+ * the only memory bandwidth counters may be on the memory controller, but to
+ * make use of them, we pretend they are on L3.
+ * Class pointer may be NULL.
+ */
+static struct mpam_resctrl_mon mpam_resctrl_counters[QOS_NUM_EVENTS];
+
 static bool exposed_alloc_capable;
 static bool exposed_mon_capable;
 
@@ -258,6 +268,28 @@ static bool class_has_usable_mba(struct mpam_props *cprops)
 	return mba_class_use_mbw_max(cprops);
 }
 
+static bool cache_has_usable_csu(struct mpam_class *class)
+{
+	struct mpam_props *cprops;
+
+	if (!class)
+		return false;
+
+	cprops = &class->props;
+
+	if (!mpam_has_feature(mpam_feat_msmon_csu, cprops))
+		return false;
+
+	/*
+	 * CSU counters settle on the value, so we can get away with
+	 * having only one.
+	 */
+	if (!cprops->num_csu_mon)
+		return false;
+
+	return (mpam_partid_max > 1) || (mpam_pmg_max != 0);
+}
+
 /*
  * Calculate the worst-case percentage change from each implemented step
  * in the control.
@@ -499,6 +531,64 @@ static void mpam_resctrl_pick_mba(void)
 	}
 }
 
+static void counter_update_class(enum resctrl_event_id evt_id,
+				 struct mpam_class *class)
+{
+	struct mpam_class *existing_class = mpam_resctrl_counters[evt_id].class;
+
+	if (existing_class) {
+		if (class->level == 3) {
+			pr_debug("Existing class is L3 - L3 wins\n");
+			return;
+		} else if (existing_class->level < class->level) {
+			pr_debug("Existing class is closer to L3, %u versus %u - closer is better\n",
+				 existing_class->level, class->level);
+			return;
+		}
+	}
+
+	mpam_resctrl_counters[evt_id].class = class;
+	exposed_mon_capable = true;
+}
+
+static void mpam_resctrl_pick_counters(void)
+{
+	struct mpam_class *class;
+	bool has_csu;
+
+	lockdep_assert_cpus_held();
+
+	guard(srcu)(&mpam_srcu);
+	list_for_each_entry_srcu(class, &mpam_classes, classes_list,
+				 srcu_read_lock_held(&mpam_srcu)) {
+		if (class->level < 3) {
+			pr_debug("class %u is before L3", class->level);
+			continue;
+		}
+
+		if (!cpumask_equal(&class->affinity, cpu_possible_mask)) {
+			pr_debug("class %u does not cover all CPUs",
+				 class->level);
+			continue;
+		}
+
+		has_csu = cache_has_usable_csu(class);
+		if (has_csu && topology_matches_l3(class)) {
+			pr_debug("class %u has usable CSU, and matches L3 topology",
+				 class->level);
+
+			/* CSU counters only make sense on a cache. */
+			switch (class->type) {
+			case MPAM_CLASS_CACHE:
+				counter_update_class(QOS_L3_OCCUP_EVENT_ID, class);
+				return;
+			default:
+				return;
+			}
+		}
+	}
+}
+
 static int mpam_resctrl_control_init(struct mpam_resctrl_res *res,
 				     enum resctrl_res_level type)
 {
@@ -578,6 +668,50 @@ static int mpam_resctrl_pick_domain_id(int cpu, struct mpam_component *comp)
 	return comp->comp_id;
 }
 
+static void mpam_resctrl_monitor_init(struct mpam_resctrl_mon *mon,
+				      enum resctrl_event_id type)
+{
+	struct mpam_resctrl_res *res = &mpam_resctrl_controls[RDT_RESOURCE_L3];
+	struct rdt_resource *l3 = &res->resctrl_res;
+
+	lockdep_assert_cpus_held();
+
+	/* There also needs to be an L3 cache present */
+	if (get_cpu_cacheinfo_id(smp_processor_id(), 3) == -1)
+		return;
+
+	/*
+	 * If there are no MPAM resources on L3, force it into existence.
+	 * topology_matches_l3() already ensures this looks like the L3.
+	 * The domain-ids will be fixed up by mpam_resctrl_domain_hdr_init().
+	 */
+	if (!res->class) {
+		pr_warn_once("Faking L3 MSC to enable counters.\n");
+		res->class = mpam_resctrl_counters[type].class;
+	}
+
+	/* Called multiple times!, once per event type */
+	if (exposed_mon_capable) {
+		l3->mon_capable = true;
+
+		/* Setting name is necessary on monitor only platforms */
+		l3->name = "L3";
+		l3->mon_scope = RESCTRL_L3_CACHE;
+
+		resctrl_enable_mon_event(type);
+
+		/*
+		 * Unfortunately, num_rmid doesn't mean anything for
+		 * mpam, and its exposed to user-space!
+		 * num-rmid is supposed to mean the number of groups
+		 * that can be created, both control or monitor groups.
+		 * For mpam, each control group has its own pmg/rmid
+		 * space.
+		 */
+		l3->mon.num_rmid = 1;
+	}
+}
+
 u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 			    u32 closid, enum resctrl_conf_type type)
 {
@@ -939,8 +1073,10 @@ void mpam_resctrl_offline_cpu(unsigned int cpu)
 int mpam_resctrl_setup(void)
 {
 	int err = 0;
+	enum resctrl_event_id j;
 	enum resctrl_res_level i;
 	struct mpam_resctrl_res *res;
+	struct mpam_resctrl_mon *mon;
 
 	cpus_read_lock();
 	for (i = 0; i < RDT_NUM_RESOURCES; i++) {
@@ -966,6 +1102,18 @@ int mpam_resctrl_setup(void)
 			break;
 		}
 	}
+
+	/* Find some classes to use for monitors */
+	mpam_resctrl_pick_counters();
+
+	for (j = 0; j < QOS_NUM_EVENTS; j++) {
+		mon = &mpam_resctrl_counters[j];
+		if (!mon->class)
+			continue;	// dummy resource
+
+		mpam_resctrl_monitor_init(mon, j);
+	}
+
 	cpus_read_unlock();
 
 	if (err || (!exposed_alloc_capable && !exposed_mon_capable)) {
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:42 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:42 +0000
Subject: [RFC PATCH 19/38] arm_mpam: resctrl: pick classes for use as mbm counters
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-20-james.morse@arm.com>

resctrl has two types of counters, NUMA-local and global. MPAM has only
bandwidth counters, but the position of the MSC may mean it counts
NUMA-local, or global traffic.

But the topology information is not available.

Apply a heuristic: the L2 or L3 supports bandwidth monitors, these are
probably NUMA-local. If the memory controller supports bandwidth
monitors, they are probably global.

This also allows us to assert that we don't have the same class
backing two different resctrl events.

Because the class or component backing the event may not be 'the L3',
it is necessary for mpam_resctrl_get_domain_from_cpu() to search
the monitor domains too. This matters the most for 'monitor only'
systems, where 'the L3' control domains may be empty, and the
ctrl_comp pointer NULL.

resctrl expects there to be enough monitors for every possible control
and monitor group to have one. Such a system gets called 'free running'
as the monitors can be programmed once and left running.
Any other platform will need to emulate ABMC.

Signed-off-by: James Morse <james.morse at arm.com>
---
 drivers/resctrl/mpam_internal.h |   8 ++
 drivers/resctrl/mpam_resctrl.c  | 141 ++++++++++++++++++++++++++++++--
 2 files changed, 144 insertions(+), 5 deletions(-)

diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index f9d2a1004c32..0984ac32f303 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -339,6 +339,14 @@ struct mpam_msc_ris {
 
 struct mpam_resctrl_dom {
 	struct mpam_component	*ctrl_comp;
+
+	/*
+	 * There is no single mon_comp because different events may be backed
+	 * by different class/components. mon_comp is indexed by the event
+	 * number.
+	 */
+	struct mpam_component   *mon_comp[QOS_NUM_EVENTS];
+
 	struct rdt_ctrl_domain	resctrl_ctrl_dom;
 	struct rdt_mon_domain	resctrl_mon_dom;
 };
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index fc1f054f187e..9978eb48c1f4 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -50,6 +50,14 @@ static bool exposed_mon_capable;
  */
 static bool cdp_enabled;
 
+/* Whether this num_mbw_mon could result in a free_running system */
+static int __mpam_monitors_free_running(u16 num_mbwu_mon)
+{
+	if (num_mbwu_mon >= resctrl_arch_system_num_rmid_idx())
+		return resctrl_arch_system_num_rmid_idx();
+	return 0;
+}
+
 bool resctrl_arch_alloc_capable(void)
 {
 	return exposed_alloc_capable;
@@ -290,6 +298,26 @@ static bool cache_has_usable_csu(struct mpam_class *class)
 	return (mpam_partid_max > 1) || (mpam_pmg_max != 0);
 }
 
+static bool class_has_usable_mbwu(struct mpam_class *class)
+{
+	struct mpam_props *cprops = &class->props;
+
+	if (!mpam_has_feature(mpam_feat_msmon_mbwu, cprops))
+		return false;
+
+	/*
+	 * resctrl expects the bandwidth counters to be free running,
+	 * which means we need as many monitors as resctrl has
+	 * control/monitor groups.
+	 */
+	if (__mpam_monitors_free_running(cprops->num_mbwu_mon)) {
+		pr_debug("monitors usable in free-running mode\n");
+		return true;
+	}
+
+	return false;
+}
+
 /*
  * Calculate the worst-case percentage change from each implemented step
  * in the control.
@@ -554,7 +582,7 @@ static void counter_update_class(enum resctrl_event_id evt_id,
 static void mpam_resctrl_pick_counters(void)
 {
 	struct mpam_class *class;
-	bool has_csu;
+	bool has_csu, has_mbwu;
 
 	lockdep_assert_cpus_held();
 
@@ -586,7 +614,37 @@ static void mpam_resctrl_pick_counters(void)
 				return;
 			}
 		}
+
+		has_mbwu = class_has_usable_mbwu(class);
+		if (has_mbwu && topology_matches_l3(class)) {
+			pr_debug("class %u has usable MBWU, and matches L3 topology",
+				 class->level);
+
+			/*
+			 * MBWU counters may be 'local' or 'total' depending on
+			 * where they are in the topology. Counters on caches
+			 * are assumed to be local. If it's on the memory
+			 * controller, its assumed to be global.
+			 */
+			switch (class->type) {
+			case MPAM_CLASS_CACHE:
+				counter_update_class(QOS_L3_MBM_LOCAL_EVENT_ID,
+						     class);
+				break;
+			case MPAM_CLASS_MEMORY:
+				counter_update_class(QOS_L3_MBM_TOTAL_EVENT_ID,
+						     class);
+				break;
+			default:
+				break;
+			}
+		}
 	}
+
+	/* Allocation of MBWU monitors assumes that the class is unique... */
+	if (mpam_resctrl_counters[QOS_L3_MBM_LOCAL_EVENT_ID].class)
+		WARN_ON_ONCE(mpam_resctrl_counters[QOS_L3_MBM_LOCAL_EVENT_ID].class ==
+			     mpam_resctrl_counters[QOS_L3_MBM_TOTAL_EVENT_ID].class);
 }
 
 static int mpam_resctrl_control_init(struct mpam_resctrl_res *res,
@@ -910,6 +968,20 @@ static bool mpam_resctrl_offline_domain_hdr(unsigned int cpu,
 	return false;
 }
 
+static struct mpam_component *find_component(struct mpam_class *victim, int cpu)
+{
+	struct mpam_component *victim_comp;
+
+	guard(srcu)(&mpam_srcu);
+	list_for_each_entry_srcu(victim_comp, &victim->components, class_list,
+				 srcu_read_lock_held(&mpam_srcu)) {
+		if (cpumask_test_cpu(cpu, &victim_comp->affinity))
+			return victim_comp;
+	}
+
+	return NULL;
+}
+
 static struct mpam_resctrl_dom *
 mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
 {
@@ -959,8 +1031,32 @@ mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
 	}
 
 	if (exposed_mon_capable) {
+		int i;
+		struct mpam_component *mon_comp, *any_mon_comp;
+
+		/*
+		 * Even if the monitor domain is backed by a different
+		 * component, the L3 component IDs need to be used... only
+		 * there may be no ctrl_comp for the L3.
+		 * Search each event's class list for a component with
+		 * overlapping CPUs and set up the dom->mon_comp array.
+		 */
+		for (i = 0; i < QOS_NUM_EVENTS; i++) {
+			struct mpam_resctrl_mon *mon;
+
+			mon = &mpam_resctrl_counters[i];
+			if (!mon->class)
+				continue;       // dummy resource
+
+			mon_comp = find_component(mon->class, cpu);
+			dom->mon_comp[i] = mon_comp;
+			if (mon_comp)
+				any_mon_comp = mon_comp;
+		}
+		WARN_ON_ONCE(!any_mon_comp);
+
 		mon_d = &dom->resctrl_mon_dom;
-		mpam_resctrl_domain_hdr_init(cpu, ctrl_comp, &mon_d->hdr);
+		mpam_resctrl_domain_hdr_init(cpu, any_mon_comp, &mon_d->hdr);
 		mon_d->hdr.type = RESCTRL_MON_DOMAIN;
 		/* TODO: this list should be sorted */
 		list_add_tail_rcu(&mon_d->hdr.list, &r->mon_domains);
@@ -982,16 +1078,47 @@ mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
 	return dom;
 }
 
+/*
+ * We know all the monitors are associated with the L3, even if there are no
+ * controls and therefore no control component. Find the cache-id for the CPU
+ * and use that to search for existing resctrl domains.
+ * This relies on mpam_resctrl_pick_domain_id() using the L3 cache-id
+ * for anything that is not a cache.
+ */
+static struct mpam_resctrl_dom *mpam_resctrl_get_mon_domain_from_cpu(int cpu)
+{
+	u32 cache_id;
+	struct rdt_mon_domain *mon_d;
+	struct mpam_resctrl_dom *dom;
+	struct mpam_resctrl_res *l3 = &mpam_resctrl_controls[RDT_RESOURCE_L3];
+
+	if (!l3->class)
+		return NULL;
+	/* TODO: how does this order with cacheinfo updates under cpuhp? */
+	cache_id = get_cpu_cacheinfo_id(cpu, 3);
+	if (cache_id == ~0)
+		return NULL;
+
+	list_for_each_entry(mon_d, &l3->resctrl_res.mon_domains, hdr.list) {
+		dom = container_of(mon_d, struct mpam_resctrl_dom, resctrl_mon_dom);
+
+		if (mon_d->hdr.id == cache_id)
+			return dom;
+	}
+
+	return NULL;
+}
+
 static struct mpam_resctrl_dom *
 mpam_resctrl_get_domain_from_cpu(int cpu, struct mpam_resctrl_res *res)
 {
 	struct mpam_resctrl_dom *dom;
 	struct rdt_ctrl_domain *ctrl_d;
+	struct rdt_resource *r = &res->resctrl_res;
 
 	lockdep_assert_cpus_held();
 
-	list_for_each_entry_rcu(ctrl_d, &res->resctrl_res.ctrl_domains,
-				hdr.list) {
+	list_for_each_entry_rcu(ctrl_d, &r->ctrl_domains, hdr.list) {
 		dom = container_of(ctrl_d, struct mpam_resctrl_dom,
 				   resctrl_ctrl_dom);
 
@@ -999,7 +1126,11 @@ mpam_resctrl_get_domain_from_cpu(int cpu, struct mpam_resctrl_res *res)
 			return dom;
 	}
 
-	return NULL;
+	if (r->rid != RDT_RESOURCE_L3)
+		return NULL;
+
+	/* Search the mon domain list too - needed on monitor only platforms. */
+	return mpam_resctrl_get_mon_domain_from_cpu(cpu);
 }
 
 int mpam_resctrl_online_cpu(unsigned int cpu)
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:43 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:43 +0000
Subject: [RFC PATCH 20/38] arm_mpam: resctrl: Pre-allocate free running monitors
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-21-james.morse@arm.com>

When there are enough monitors, the resctrl mbm local and total
files can be exposed. These need all the monitors that resctrl
may use to be allocated up front.

Add helpers to do this.

If a different candidate class is discovered, the old array
should be free'd and the allocated monitors returned to the
driver.

Signed-off-by: James Morse <james.morse at arm.com>
---
 drivers/resctrl/mpam_internal.h |  8 +++-
 drivers/resctrl/mpam_resctrl.c  | 84 ++++++++++++++++++++++++++++++++-
 2 files changed, 89 insertions(+), 3 deletions(-)

diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index 0984ac32f303..b7c914febeb4 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -359,7 +359,13 @@ struct mpam_resctrl_res {
 struct mpam_resctrl_mon {
 	struct mpam_class	*class;
 
-	/* per-class data that resctrl needs will live here */
+	/*
+	 * Array of allocated MBWU monitors, indexed by (closid, rmid).
+	 * When ABMC is not in use, this array directly maps (closid, rmid)
+	 * to the allocated monitor. Otherwise this array is sparse, and
+	 * un-assigned (closid, rmid) are -1.
+	 */
+	int			*mbwu_idx_to_mon;
 };
 
 static inline int mpam_alloc_csu_mon(struct mpam_class *class)
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 9978eb48c1f4..de5220fed97d 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -559,10 +559,58 @@ static void mpam_resctrl_pick_mba(void)
 	}
 }
 
+static void __free_mbwu_mon(struct mpam_class *class, int *array,
+			    u16 num_mbwu_mon)
+{
+	for (int i = 0; i < num_mbwu_mon; i++) {
+		if (array[i] < 0)
+			continue;
+
+		mpam_free_mbwu_mon(class, array[i]);
+		array[i] = ~0;
+	}
+}
+
+static int __alloc_mbwu_mon(struct mpam_class *class, int *array,
+			    u16 num_mbwu_mon)
+{
+	for (int i = 0; i < num_mbwu_mon; i++) {
+		int mbwu_mon = mpam_alloc_mbwu_mon(class);
+
+		if (mbwu_mon < 0) {
+			__free_mbwu_mon(class, array, num_mbwu_mon);
+			return mbwu_mon;
+		}
+		array[i] = mbwu_mon;
+	}
+
+	return 0;
+}
+
+static int *__alloc_mbwu_array(struct mpam_class *class, u16 num_mbwu_mon)
+{
+	int err;
+	size_t array_size = num_mbwu_mon * sizeof(int);
+	int *array __free(kfree) = kmalloc(array_size, GFP_KERNEL);
+
+	if (!array)
+		return ERR_PTR(-ENOMEM);
+
+	memset(array, -1, array_size);
+
+	err = __alloc_mbwu_mon(class, array, num_mbwu_mon);
+	if (err)
+		return ERR_PTR(err);
+	return_ptr(array);
+}
+
 static void counter_update_class(enum resctrl_event_id evt_id,
 				 struct mpam_class *class)
 {
-	struct mpam_class *existing_class = mpam_resctrl_counters[evt_id].class;
+	struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[evt_id];
+	struct mpam_class *existing_class = mon->class;
+	u16 num_mbwu_mon = class->props.num_mbwu_mon;
+	int *existing_array = mon->mbwu_idx_to_mon;
 
 	if (existing_class) {
 		if (class->level == 3) {
@@ -575,8 +623,40 @@ static void counter_update_class(enum resctrl_event_id evt_id,
 		}
 	}
 
-	mpam_resctrl_counters[evt_id].class = class;
+	pr_debug("Updating event %u to use class %u\n", evt_id, class->level);
+	mon->class = class;
 	exposed_mon_capable = true;
+
+	if (evt_id == QOS_L3_OCCUP_EVENT_ID)
+		return;
+
+	/* Might not need all the monitors */
+	num_mbwu_mon = __mpam_monitors_free_running(num_mbwu_mon);
+	if (!num_mbwu_mon) {
+		pr_debug("Not pre-allocating free-running counters\n");
+		return;
+	}
+
+	/*
+	 * This is the pre-allocated free-running monitors path. It always
+	 * allocates one monitor per PARTID * PMG.
+	 */
+	WARN_ON_ONCE(num_mbwu_mon != resctrl_arch_system_num_rmid_idx());
+
+	mon->mbwu_idx_to_mon = __alloc_mbwu_array(class, num_mbwu_mon);
+	if (IS_ERR(mon->mbwu_idx_to_mon)) {
+		pr_debug("Failed to allocate MBWU array\n");
+		mon->class = existing_class;
+		mon->mbwu_idx_to_mon = existing_array;
+		return;
+	}
+
+	if (existing_array) {
+		pr_debug("Releasing previous class %u's monitors\n",
+			 existing_class->level);
+		__free_mbwu_mon(existing_class, existing_array, num_mbwu_mon);
+		kfree(existing_array);
+	}
 }
 
 static void mpam_resctrl_pick_counters(void)
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:44 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:44 +0000
Subject: [RFC PATCH 21/38] arm_mpam: resctrl: Pre-allocate assignable monitors
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-22-james.morse@arm.com>

When there are not enough monitors, MPAM is able to emulate ABMC by making
a smaller number of monitors assignable. These monitors still need to be
allocated from the driver, and mapped to whichever control/monitor group
resctrl wants to use them with.

Add a second array to hold the monitor values indexed by resctrl's
cntr_id.

When CDP is in use, two monitors are needed so the available number of
counters halves. Platforms with one monitor will have zero monitors
when CDP is in use.

Signed-off-by: James Morse <james.morse at arm.com>
---
 drivers/resctrl/mpam_internal.h |   7 +++
 drivers/resctrl/mpam_resctrl.c  | 102 ++++++++++++++++++++++++++++++++
 2 files changed, 109 insertions(+)

diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index b7c914febeb4..05101186af17 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -366,6 +366,13 @@ struct mpam_resctrl_mon {
 	 * un-assigned (closid, rmid) are -1.
 	 */
 	int			*mbwu_idx_to_mon;
+
+	/*
+	 * Array of assigned MBWU monitors, indexed by idx argument.
+	 * When ABMC is not in use, this array can be NULL. Otherwise
+	 * it maps idx to the allocated monitor.
+	 */
+	int			*assigned_counters;
 };
 
 static inline int mpam_alloc_csu_mon(struct mpam_class *class)
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index de5220fed97d..f607feaf0126 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -50,6 +50,12 @@ static bool exposed_mon_capable;
  */
 static bool cdp_enabled;
 
+/*
+ * L3 local/total may come from different classes - what is the number of MBWU
+ * 'on L3'?
+ */
+static unsigned int l3_num_allocated_mbwu = ~0;
+
 /* Whether this num_mbw_mon could result in a free_running system */
 static int __mpam_monitors_free_running(u16 num_mbwu_mon)
 {
@@ -58,6 +64,15 @@ static int __mpam_monitors_free_running(u16 num_mbwu_mon)
 	return 0;
 }
 
+/*
+ * If l3_num_allocated_mbwu is forced below PARTID * PMG, then the counters
+ * are not free running, and ABMC's user-interface must be used to assign them.
+ */
+static bool mpam_resctrl_abmc_enabled(void)
+{
+	return l3_num_allocated_mbwu < resctrl_arch_system_num_rmid_idx();
+}
+
 bool resctrl_arch_alloc_capable(void)
 {
 	return exposed_alloc_capable;
@@ -102,8 +117,25 @@ static void resctrl_reset_task_closids(void)
 	read_unlock(&tasklist_lock);
 }
 
+static void mpam_resctrl_monitor_sync_abmc_vals(struct rdt_resource *l3)
+{
+	l3->mon.num_mbm_cntrs = l3_num_allocated_mbwu;
+	if (cdp_enabled)
+		l3->mon.num_mbm_cntrs /= 2;
+
+	if (l3->mon.num_mbm_cntrs) {
+		l3->mon.mbm_cntr_assignable = mpam_resctrl_abmc_enabled();
+		l3->mon.mbm_assign_on_mkdir = mpam_resctrl_abmc_enabled();
+	} else {
+		l3->mon.mbm_cntr_assignable = false;
+		l3->mon.mbm_assign_on_mkdir = false;
+	}
+}
+
 int resctrl_arch_set_cdp_enabled(enum resctrl_res_level ignored, bool enable)
 {
+	struct mpam_resctrl_res *res = &mpam_resctrl_controls[RDT_RESOURCE_L3];
+	struct rdt_resource *l3 = &res->resctrl_res;
 	u32 partid_i, partid_d;
 
 	cdp_enabled = enable;
@@ -120,6 +152,7 @@ int resctrl_arch_set_cdp_enabled(enum resctrl_res_level ignored, bool enable)
 	WRITE_ONCE(arm64_mpam_global_default, mpam_get_regval(current));
 
 	resctrl_reset_task_closids();
+	mpam_resctrl_monitor_sync_abmc_vals(l3);
 
 	return 0;
 }
@@ -315,6 +348,11 @@ static bool class_has_usable_mbwu(struct mpam_class *class)
 		return true;
 	}
 
+	if (cprops->num_mbwu_mon) {
+		pr_debug("monitors usable via ABMC assignment\n");
+		return true;
+	}
+
 	return false;
 }
 
@@ -584,6 +622,8 @@ static int __alloc_mbwu_mon(struct mpam_class *class, int *array,
 		array[i] = mbwu_mon;
 	}
 
+	l3_num_allocated_mbwu = min(l3_num_allocated_mbwu, num_mbwu_mon);
+
 	return 0;
 }
 
@@ -727,6 +767,23 @@ static void mpam_resctrl_pick_counters(void)
 			     mpam_resctrl_counters[QOS_L3_MBM_TOTAL_EVENT_ID].class);
 }
 
+bool resctrl_arch_mbm_cntr_assign_enabled(struct rdt_resource *r)
+{
+	if (r != &mpam_resctrl_controls[RDT_RESOURCE_L3].resctrl_res)
+		return false;
+
+	return mpam_resctrl_abmc_enabled();
+}
+
+int resctrl_arch_mbm_cntr_assign_set(struct rdt_resource *r, bool enable)
+{
+	lockdep_assert_cpus_held();
+
+	WARN_ON_ONCE(1);
+
+	return 0;
+}
+
 static int mpam_resctrl_control_init(struct mpam_resctrl_res *res,
 				     enum resctrl_res_level type)
 {
@@ -806,6 +863,41 @@ static int mpam_resctrl_pick_domain_id(int cpu, struct mpam_component *comp)
 	return comp->comp_id;
 }
 
+/*
+ * This must run after all event counters have been picked so that any free
+ * running counters have already been allocated.
+ */
+static int mpam_resctrl_monitor_init_abmc(struct mpam_resctrl_mon *mon)
+{
+	struct mpam_resctrl_res *res = &mpam_resctrl_controls[RDT_RESOURCE_L3];
+	size_t array_size = resctrl_arch_system_num_rmid_idx() * sizeof(int);
+	int *rmid_array __free(kfree) = kmalloc(array_size, GFP_KERNEL);
+	struct rdt_resource *l3 = &res->resctrl_res;
+	struct mpam_class *class = mon->class;
+	u16 num_mbwu_mon;
+
+	if (mon->mbwu_idx_to_mon) {
+		pr_debug("monitors free running\n");
+		return 0;
+	}
+
+	if (!rmid_array) {
+		pr_debug("Failed to allocate RMID array\n");
+		return -ENOMEM;
+	}
+	memset(rmid_array, -1, array_size);
+
+	num_mbwu_mon = class->props.num_mbwu_mon;
+	mon->assigned_counters = __alloc_mbwu_array(mon->class, num_mbwu_mon);
+	if (IS_ERR(mon->assigned_counters))
+		return PTR_ERR(mon->assigned_counters);
+	mon->mbwu_idx_to_mon = no_free_ptr(rmid_array);
+
+	mpam_resctrl_monitor_sync_abmc_vals(l3);
+
+	return 0;
+}
+
 static void mpam_resctrl_monitor_init(struct mpam_resctrl_mon *mon,
 				      enum resctrl_event_id type)
 {
@@ -847,6 +939,16 @@ static void mpam_resctrl_monitor_init(struct mpam_resctrl_mon *mon,
 		 * space.
 		 */
 		l3->mon.num_rmid = 1;
+
+		switch (type) {
+		case QOS_L3_MBM_LOCAL_EVENT_ID:
+		case QOS_L3_MBM_TOTAL_EVENT_ID:
+			mpam_resctrl_monitor_init_abmc(mon);
+
+			return;
+		default:
+			return;
+		}
 	}
 }
 
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:45 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:45 +0000
Subject: [RFC PATCH 22/38] arm_mpam: resctrl: Add kunit test for ABMC/CDP interactions
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-23-james.morse@arm.com>

ABMC exposes a fun corner case where a platform with one monitor can
use ABMC for assignable counters - but not when CDP is enabled.

Add some tests.

Signed-off-by: James Morse <james.morse at arm.com>
---
 drivers/resctrl/test_mpam_resctrl.c | 62 +++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)

diff --git a/drivers/resctrl/test_mpam_resctrl.c b/drivers/resctrl/test_mpam_resctrl.c
index d0615aa7671c..c83d54f21fa0 100644
--- a/drivers/resctrl/test_mpam_resctrl.c
+++ b/drivers/resctrl/test_mpam_resctrl.c
@@ -293,6 +293,67 @@ static void test_percent_to_max_rounding(struct kunit *test)
 	KUNIT_EXPECT_LE(test, 4 * num_rounded_up, 3 * total);
 }
 
+static void test_num_assignable_counters(struct kunit *test)
+{
+	unsigned int orig_l3_num_allocated_mbwu = l3_num_allocated_mbwu;
+	u32 orig_mpam_partid_max = mpam_partid_max;
+	u32 orig_mpam_pmg_max = mpam_pmg_max;
+	bool orig_cdp_enabled = cdp_enabled;
+	struct rdt_resource fake_l3;
+
+	/* Force there to be some PARTID/PMG */
+	mpam_partid_max = 3;
+	mpam_pmg_max = 1;
+
+	cdp_enabled = false;
+
+	/* ABMC off, CDP off */
+	l3_num_allocated_mbwu = resctrl_arch_system_num_rmid_idx();
+	mpam_resctrl_monitor_sync_abmc_vals(&fake_l3);
+	KUNIT_EXPECT_EQ(test, fake_l3.mon.num_mbm_cntrs, resctrl_arch_system_num_rmid_idx());
+	KUNIT_EXPECT_FALSE(test, fake_l3.mon.mbm_cntr_assignable);
+	KUNIT_EXPECT_FALSE(test, fake_l3.mon.mbm_assign_on_mkdir);
+
+	/* ABMC on, CDP off */
+	l3_num_allocated_mbwu = 4;
+	mpam_resctrl_monitor_sync_abmc_vals(&fake_l3);
+	KUNIT_EXPECT_EQ(test, fake_l3.mon.num_mbm_cntrs, 4);
+	KUNIT_EXPECT_TRUE(test, fake_l3.mon.mbm_cntr_assignable);
+	KUNIT_EXPECT_TRUE(test, fake_l3.mon.mbm_assign_on_mkdir);
+
+	cdp_enabled = true;
+
+	/* ABMC off, CDP on */
+	l3_num_allocated_mbwu = resctrl_arch_system_num_rmid_idx();
+	mpam_resctrl_monitor_sync_abmc_vals(&fake_l3);
+
+	/* (value not consumed by resctrl) */
+	KUNIT_EXPECT_EQ(test, fake_l3.mon.num_mbm_cntrs, resctrl_arch_system_num_rmid_idx() / 2);
+
+	KUNIT_EXPECT_FALSE(test, fake_l3.mon.mbm_cntr_assignable);
+	KUNIT_EXPECT_FALSE(test, fake_l3.mon.mbm_assign_on_mkdir);
+
+	/* ABMC on, CDP on */
+	l3_num_allocated_mbwu = 4;
+	mpam_resctrl_monitor_sync_abmc_vals(&fake_l3);
+	KUNIT_EXPECT_EQ(test, fake_l3.mon.num_mbm_cntrs, 2);
+	KUNIT_EXPECT_TRUE(test, fake_l3.mon.mbm_cntr_assignable);
+	KUNIT_EXPECT_TRUE(test, fake_l3.mon.mbm_assign_on_mkdir);
+
+	/* ABMC 'on', CDP on - but not enough counters */
+	l3_num_allocated_mbwu = 1;
+	mpam_resctrl_monitor_sync_abmc_vals(&fake_l3);
+	KUNIT_EXPECT_EQ(test, fake_l3.mon.num_mbm_cntrs, 0);
+	KUNIT_EXPECT_FALSE(test, fake_l3.mon.mbm_cntr_assignable);
+	KUNIT_EXPECT_FALSE(test, fake_l3.mon.mbm_assign_on_mkdir);
+
+	/* Restore global variables that were messed with */
+	l3_num_allocated_mbwu = orig_l3_num_allocated_mbwu;
+	mpam_partid_max = orig_mpam_partid_max;
+	mpam_pmg_max = orig_mpam_pmg_max;
+	cdp_enabled = orig_cdp_enabled;
+}
+
 static struct kunit_case mpam_resctrl_test_cases[] = {
 	KUNIT_CASE(test_get_mba_granularity),
 	KUNIT_CASE_PARAM(test_mbw_max_to_percent, test_percent_value_gen_params),
@@ -301,6 +362,7 @@ static struct kunit_case mpam_resctrl_test_cases[] = {
 	KUNIT_CASE(test_percent_to_max_rounding),
 	KUNIT_CASE_PARAM(test_percent_max_roundtrip_stability,
 			 test_all_bwa_wd_gen_params),
+	KUNIT_CASE(test_num_assignable_counters),
 	{}
 };
 
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:46 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:46 +0000
Subject: [RFC PATCH 23/38] arm_mpam: resctrl: Add resctrl_arch_config_cntr() for ABMC use
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-24-james.morse@arm.com>

ABMC has a helper resctrl_arch_config_cntr() for changing the mapping
between 'cntr_id' and a CLOSID/RMID pair.

Add the helper.

For MPAM this is done by updating the mon->mbwu_idx_to_mon[] array,
and as usual CDP means it needs doing in three different ways.

Signed-off-by: James Morse <james.morse at arm.com>
---
 drivers/resctrl/mpam_resctrl.c | 37 ++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index f607feaf0126..22ad5dd3c383 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -767,6 +767,43 @@ static void mpam_resctrl_pick_counters(void)
 			     mpam_resctrl_counters[QOS_L3_MBM_TOTAL_EVENT_ID].class);
 }
 
+static void __config_cntr(struct mpam_resctrl_mon *mon, u32 cntr_id,
+			  enum resctrl_conf_type cdp_type, u32 closid, u32 rmid,
+			  bool assign)
+{
+	u32 mbwu_idx, mon_idx = resctrl_get_config_index(cntr_id, cdp_type);
+
+	closid = resctrl_get_config_index(closid, cdp_type);
+	mbwu_idx = resctrl_arch_rmid_idx_encode(closid, rmid);
+	WARN_ON_ONCE(mon_idx > l3_num_allocated_mbwu);
+
+	if (assign)
+		mon->mbwu_idx_to_mon[mbwu_idx] = mon->assigned_counters[mon_idx];
+	else
+		mon->mbwu_idx_to_mon[mbwu_idx] = -1;
+}
+
+void resctrl_arch_config_cntr(struct rdt_resource *r, struct rdt_mon_domain *d,
+			      enum resctrl_event_id evtid, u32 rmid, u32 closid,
+			      u32 cntr_id, bool assign)
+{
+	struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[evtid];
+
+	if (!mon->mbwu_idx_to_mon || !mon->assigned_counters) {
+		pr_debug("monitor arrays not allocated\n");
+		return;
+	}
+
+	if (cdp_enabled) {
+		__config_cntr(mon, cntr_id, CDP_CODE, closid, rmid, assign);
+		__config_cntr(mon, cntr_id, CDP_DATA, closid, rmid, assign);
+	} else {
+		__config_cntr(mon, cntr_id, CDP_NONE, closid, rmid, assign);
+	}
+
+	resctrl_arch_reset_rmid(r, d, closid, rmid, evtid);
+}
+
 bool resctrl_arch_mbm_cntr_assign_enabled(struct rdt_resource *r)
 {
 	if (r != &mpam_resctrl_controls[RDT_RESOURCE_L3].resctrl_res)
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:26 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:26 +0000
Subject: [RFC PATCH 03/38] arm64: mpam: Advertise the CPUs MPAM limits to the driver
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-4-james.morse@arm.com>

Requestors need to populate the MPAM fields for any traffic they send
on the interconnect. For the CPUs these values are taken from the
corresponding MPAMy_ELx register. Each requestor may have a limit on
the largest PARTID or PMG value that can be used. The MPAM driver has
to determine the system-wide minimum supported PARTID and PMG values.

To do this, the driver needs to be told what each requestor's
limit is.

CPUs are special, but this infrastructure is also needed for the
SMMU and GIC ITS. Call the helper to tell the MPAM driver what the
CPUs can do.

The return value can be ignored by the arch code as it runs well
before the MPAM driver starts probing.

Signed-off-by: James Morse <james.morse at arm.com>
---
 arch/arm64/kernel/mpam.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/arm64/kernel/mpam.c b/arch/arm64/kernel/mpam.c
index 9866d2ca0faa..e6feff2324ac 100644
--- a/arch/arm64/kernel/mpam.c
+++ b/arch/arm64/kernel/mpam.c
@@ -3,6 +3,7 @@
 
 #include <asm/mpam.h>
 
+#include <linux/arm_mpam.h>
 #include <linux/jump_label.h>
 #include <linux/percpu.h>
 
@@ -11,3 +12,14 @@ DEFINE_PER_CPU(u64, arm64_mpam_default);
 DEFINE_PER_CPU(u64, arm64_mpam_current);
 
 u64 arm64_mpam_global_default;
+
+static int __init arm64_mpam_register_cpus(void)
+{
+	u64 mpamidr = read_sanitised_ftr_reg(SYS_MPAMIDR_EL1);
+	u16 partid_max = FIELD_GET(MPAMIDR_EL1_PARTID_MAX, mpamidr);
+	u8 pmg_max = FIELD_GET(MPAMIDR_EL1_PMG_MAX, mpamidr);
+
+	return mpam_register_requestor(partid_max, pmg_max);
+}
+/* Must occur before mpam_msc_driver_init() from subsys_initcall() */
+arch_initcall(arm64_mpam_register_cpus)
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:49 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:49 +0000
Subject: [RFC PATCH 26/38] arm_mpam: resctrl: Add resctrl_arch_cntr_read() & resctrl_arch_reset_cntr()
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-27-james.morse@arm.com>

When used in ABMC mode, resctrl uses a different set of helpers to
read and reset the counters.

Add these.

Signed-off-by: James Morse <james.morse at arm.com>
---
 drivers/resctrl/mpam_resctrl.c | 43 ++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index dc8a819d0976..1333dc40714a 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -454,6 +454,28 @@ int resctrl_arch_rmid_read(struct rdt_resource	*r, struct rdt_mon_domain *d,
 				 closid, rmid, val);
 }
 
+/* MBWU counters when in ABMC mode */
+int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_mon_domain *d,
+			   u32 closid, u32 rmid, int mon_idx,
+			   enum resctrl_event_id eventid, u64 *val)
+{
+	struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[eventid];
+	struct mpam_resctrl_dom *l3_dom;
+	struct mpam_component *mon_comp;
+
+	if (!mpam_is_enabled())
+		return -EINVAL;
+
+	if (eventid == QOS_L3_OCCUP_EVENT_ID || !mon->class)
+		return -EINVAL;
+
+	l3_dom = container_of(d, struct mpam_resctrl_dom, resctrl_mon_dom);
+	mon_comp = l3_dom->mon_comp[eventid];
+
+	return read_mon_cdp_safe(mon, mon_comp, mpam_feat_msmon_mbwu, mon_idx,
+				 closid, rmid, val);
+}
+
 static void __reset_mon(struct mpam_resctrl_mon *mon, struct mpam_component *mon_comp,
 			int mon_idx,
 			enum resctrl_conf_type cdp_type, u32 closid, u32 rmid)
@@ -509,6 +531,27 @@ void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_mon_domain *d,
 	reset_mon_cdp_safe(mon, mon_comp, USE_PRE_ALLOCATED, closid, rmid);
 }
 
+/* Reset an assigned counter */
+void resctrl_arch_reset_cntr(struct rdt_resource *r, struct rdt_mon_domain *d,
+			     u32 closid, u32 rmid, int cntr_id,
+			     enum resctrl_event_id eventid)
+{
+	struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[eventid];
+	struct mpam_resctrl_dom *l3_dom;
+	struct mpam_component *mon_comp;
+
+	if (!mpam_is_enabled())
+		return;
+
+	if (eventid == QOS_L3_OCCUP_EVENT_ID || !mon->class)
+		return;
+
+	l3_dom = container_of(d, struct mpam_resctrl_dom, resctrl_mon_dom);
+	mon_comp = l3_dom->mon_comp[eventid];
+
+	reset_mon_cdp_safe(mon, mon_comp, USE_PRE_ALLOCATED, closid, rmid);
+}
+
 static bool cache_has_usable_cpor(struct mpam_class *class)
 {
 	struct mpam_props *cprops = &class->props;
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:30 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:30 +0000
Subject: [RFC PATCH 07/38] arm_mpam: resctrl: Add boilerplate cpuhp and domain allocation
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-8-james.morse@arm.com>

resctrl has its own data structures to describe its resources. We
can't use these directly as we play tricks with the 'MBA' resource,
picking the MPAM controls or monitors that best apply. We may export
the same component as both L3 and MBA.

Add mpam_resctrl_exports[] as the array of class->resctrl mappings we
are exporting, and add the cpuhp hooks that allocated and free the
resctrl domain structures.

While we're here, plumb in a few other obvious things.

CONFIG_ARM_CPU_RESCTRL is used to allow this code to be built
even though it can't yet be linked against resctrl.

Signed-off-by: James Morse <james.morse at arm.com>
---
 drivers/resctrl/Makefile        |   1 +
 drivers/resctrl/mpam_devices.c  |  12 ++
 drivers/resctrl/mpam_internal.h |  22 +++
 drivers/resctrl/mpam_resctrl.c  | 329 ++++++++++++++++++++++++++++++++
 include/linux/arm_mpam.h        |   3 +
 5 files changed, 367 insertions(+)
 create mode 100644 drivers/resctrl/mpam_resctrl.c

diff --git a/drivers/resctrl/Makefile b/drivers/resctrl/Makefile
index 898199dcf80d..40beaf999582 100644
--- a/drivers/resctrl/Makefile
+++ b/drivers/resctrl/Makefile
@@ -1,4 +1,5 @@
 obj-$(CONFIG_ARM64_MPAM_DRIVER)			+= mpam.o
 mpam-y						+= mpam_devices.o
+mpam-$(CONFIG_ARM_CPU_RESCTRL)			+= mpam_resctrl.o
 
 ccflags-$(CONFIG_ARM64_MPAM_DRIVER_DEBUG)	+= -DDEBUG
diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index 2996ad93fc3e..efaf7633bc35 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -1627,6 +1627,9 @@ static int mpam_cpu_online(unsigned int cpu)
 			mpam_reprogram_msc(msc);
 	}
 
+	if (mpam_is_enabled())
+		mpam_resctrl_online_cpu(cpu);
+
 	return 0;
 }
 
@@ -1670,6 +1673,9 @@ static int mpam_cpu_offline(unsigned int cpu)
 {
 	struct mpam_msc *msc;
 
+	if (mpam_is_enabled())
+		mpam_resctrl_offline_cpu(cpu);
+
 	guard(srcu)(&mpam_srcu);
 	list_for_each_entry_srcu(msc, &mpam_all_msc, all_msc_list,
 				 srcu_read_lock_held(&mpam_srcu)) {
@@ -2516,6 +2522,12 @@ static void mpam_enable_once(void)
 	mutex_unlock(&mpam_list_lock);
 	cpus_read_unlock();
 
+	if (!err) {
+		err = mpam_resctrl_setup();
+		if (err)
+			pr_err("Failed to initialise resctrl: %d\n", err);
+	}
+
 	if (err) {
 		mpam_disable_reason = "Failed to enable.";
 		schedule_work(&mpam_broken_work);
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index 4508a6654fe0..dfd3512ac924 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -12,6 +12,7 @@
 #include <linux/jump_label.h>
 #include <linux/llist.h>
 #include <linux/mutex.h>
+#include <linux/resctrl.h>
 #include <linux/srcu.h>
 #include <linux/spinlock.h>
 #include <linux/srcu.h>
@@ -336,6 +337,17 @@ struct mpam_msc_ris {
 	struct mpam_garbage	garbage;
 };
 
+struct mpam_resctrl_dom {
+	struct mpam_component	*ctrl_comp;
+	struct rdt_ctrl_domain	resctrl_ctrl_dom;
+	struct rdt_mon_domain	resctrl_mon_dom;
+};
+
+struct mpam_resctrl_res {
+	struct mpam_class	*class;
+	struct rdt_resource	resctrl_res;
+};
+
 static inline int mpam_alloc_csu_mon(struct mpam_class *class)
 {
 	struct mpam_props *cprops = &class->props;
@@ -390,6 +402,16 @@ void mpam_msmon_reset_mbwu(struct mpam_component *comp, struct mon_cfg *ctx);
 int mpam_get_cpumask_from_cache_id(unsigned long cache_id, u32 cache_level,
 				   cpumask_t *affinity);
 
+#ifdef CONFIG_RESCTRL_FS
+int mpam_resctrl_setup(void);
+int mpam_resctrl_online_cpu(unsigned int cpu);
+void mpam_resctrl_offline_cpu(unsigned int cpu);
+#else
+static inline int mpam_resctrl_setup(void) { return 0; }
+static inline int mpam_resctrl_online_cpu(unsigned int cpu) { return 0; }
+static inline void mpam_resctrl_offline_cpu(unsigned int cpu) { }
+#endif /* CONFIG_RESCTRL_FS */
+
 /*
  * MPAM MSCs have the following register layout. See:
  * Arm Memory System Resource Partitioning and Monitoring (MPAM) System
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
new file mode 100644
index 000000000000..320cebbd37ce
--- /dev/null
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -0,0 +1,329 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2025 Arm Ltd.
+
+#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__
+
+#include <linux/arm_mpam.h>
+#include <linux/cacheinfo.h>
+#include <linux/cpu.h>
+#include <linux/cpumask.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/printk.h>
+#include <linux/rculist.h>
+#include <linux/resctrl.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <asm/mpam.h>
+
+#include "mpam_internal.h"
+
+/*
+ * The classes we've picked to map to resctrl resources, wrapped
+ * in with their resctrl structure.
+ * Class pointer may be NULL.
+ */
+static struct mpam_resctrl_res mpam_resctrl_controls[RDT_NUM_RESOURCES];
+
+/* The lock for modifying resctrl's domain lists from cpuhp callbacks. */
+static DEFINE_MUTEX(domain_list_lock);
+
+static bool exposed_alloc_capable;
+static bool exposed_mon_capable;
+
+bool resctrl_arch_alloc_capable(void)
+{
+	return exposed_alloc_capable;
+}
+
+bool resctrl_arch_mon_capable(void)
+{
+	return exposed_mon_capable;
+}
+
+/*
+ * MSC may raise an error interrupt if it sees an out or range partid/pmg,
+ * and go on to truncate the value. Regardless of what the hardware supports,
+ * only the system wide safe value is safe to use.
+ */
+u32 resctrl_arch_get_num_closid(struct rdt_resource *ignored)
+{
+	return mpam_partid_max + 1;
+}
+
+struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l)
+{
+	if (l >= RDT_NUM_RESOURCES)
+		return NULL;
+
+	return &mpam_resctrl_controls[l].resctrl_res;
+}
+
+static int mpam_resctrl_control_init(struct mpam_resctrl_res *res,
+				     enum resctrl_res_level type)
+{
+	/* TODO: initialise the resctrl resources */
+
+	return 0;
+}
+
+static int mpam_resctrl_pick_domain_id(int cpu, struct mpam_component *comp)
+{
+	struct mpam_class *class = comp->class;
+
+	if (class->type == MPAM_CLASS_CACHE)
+		return comp->comp_id;
+
+	/* TODO: repaint domain ids to match the L3 domain ids */
+	/*
+	 * Otherwise, expose the ID used by the firmware table code.
+	 */
+	return comp->comp_id;
+}
+
+static void mpam_resctrl_domain_hdr_init(int cpu, struct mpam_component *comp,
+					 struct rdt_domain_hdr *hdr)
+{
+	lockdep_assert_cpus_held();
+
+	INIT_LIST_HEAD(&hdr->list);
+	hdr->id = mpam_resctrl_pick_domain_id(cpu, comp);
+	cpumask_set_cpu(cpu, &hdr->cpu_mask);
+}
+
+/**
+ * mpam_resctrl_offline_domain_hdr() - Update the domain header to remove a CPU.
+ * @cpu:	The CPU to remove from the domain.
+ * @hdr:	The domain's header.
+ *
+ * Removes @cpu from the header mask. If this was the last CPU in the domain,
+ * the domain header is removed from its parent list and true is returned,
+ * indicating the parent structure can be freed.
+ * If there are other CPUs in the domain, returns false.
+ */
+static bool mpam_resctrl_offline_domain_hdr(unsigned int cpu,
+					    struct rdt_domain_hdr *hdr)
+{
+	cpumask_clear_cpu(cpu, &hdr->cpu_mask);
+	if (cpumask_empty(&hdr->cpu_mask)) {
+		list_del(&hdr->list);
+		return true;
+	}
+
+	return false;
+}
+
+static struct mpam_resctrl_dom *
+mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
+{
+	int err;
+	struct mpam_resctrl_dom *dom;
+	struct rdt_mon_domain *mon_d;
+	struct rdt_ctrl_domain *ctrl_d;
+	struct mpam_class *class = res->class;
+	struct mpam_component *comp_iter, *ctrl_comp;
+	struct rdt_resource *r = &res->resctrl_res;
+
+	lockdep_assert_held(&domain_list_lock);
+
+	ctrl_comp = NULL;
+	guard(srcu)(&mpam_srcu);
+	list_for_each_entry_srcu(comp_iter, &class->components, class_list,
+				 srcu_read_lock_held(&mpam_srcu)) {
+		if (cpumask_test_cpu(cpu, &comp_iter->affinity)) {
+			ctrl_comp = comp_iter;
+			break;
+		}
+	}
+
+	/* class has no component for this CPU */
+	if (WARN_ON_ONCE(!ctrl_comp))
+		return ERR_PTR(-EINVAL);
+
+	dom = kzalloc_node(sizeof(*dom), GFP_KERNEL, cpu_to_node(cpu));
+	if (!dom)
+		return ERR_PTR(-ENOMEM);
+
+	if (exposed_alloc_capable) {
+		dom->ctrl_comp = ctrl_comp;
+
+		ctrl_d = &dom->resctrl_ctrl_dom;
+		mpam_resctrl_domain_hdr_init(cpu, ctrl_comp, &ctrl_d->hdr);
+		ctrl_d->hdr.type = RESCTRL_CTRL_DOMAIN;
+		/* TODO: this list should be sorted */
+		list_add_tail_rcu(&ctrl_d->hdr.list, &r->ctrl_domains);
+		err = resctrl_online_ctrl_domain(r, ctrl_d);
+		if (err) {
+			dom = ERR_PTR(err);
+			goto offline_ctrl_domain;
+		}
+	} else {
+		pr_debug("Skipped control domain online - no controls\n");
+	}
+
+	if (exposed_mon_capable) {
+		mon_d = &dom->resctrl_mon_dom;
+		mpam_resctrl_domain_hdr_init(cpu, ctrl_comp, &mon_d->hdr);
+		mon_d->hdr.type = RESCTRL_MON_DOMAIN;
+		/* TODO: this list should be sorted */
+		list_add_tail_rcu(&mon_d->hdr.list, &r->mon_domains);
+		err = resctrl_online_mon_domain(r, mon_d);
+		if (err) {
+			dom = ERR_PTR(err);
+			goto offline_mon_hdr;
+		}
+	} else {
+		pr_debug("Skipped monitor domain online - no monitors\n");
+	}
+	goto out;
+
+offline_mon_hdr:
+	mpam_resctrl_offline_domain_hdr(cpu, &mon_d->hdr);
+offline_ctrl_domain:
+	resctrl_offline_ctrl_domain(r, ctrl_d);
+out:
+	return dom;
+}
+
+static struct mpam_resctrl_dom *
+mpam_resctrl_get_domain_from_cpu(int cpu, struct mpam_resctrl_res *res)
+{
+	struct mpam_resctrl_dom *dom;
+	struct rdt_ctrl_domain *ctrl_d;
+
+	lockdep_assert_cpus_held();
+
+	list_for_each_entry_rcu(ctrl_d, &res->resctrl_res.ctrl_domains,
+				hdr.list) {
+		dom = container_of(ctrl_d, struct mpam_resctrl_dom,
+				   resctrl_ctrl_dom);
+
+		if (cpumask_test_cpu(cpu, &dom->ctrl_comp->affinity))
+			return dom;
+	}
+
+	return NULL;
+}
+
+int mpam_resctrl_online_cpu(unsigned int cpu)
+{
+	int i;
+	struct mpam_resctrl_dom *dom;
+	struct mpam_resctrl_res *res;
+
+	guard(mutex)(&domain_list_lock);
+	for (i = 0; i < RDT_NUM_RESOURCES; i++) {
+		res = &mpam_resctrl_controls[i];
+		if (!res->class)
+			continue;	// dummy_resource;
+
+		dom = mpam_resctrl_get_domain_from_cpu(cpu, res);
+		if (!dom)
+			dom = mpam_resctrl_alloc_domain(cpu, res);
+		if (IS_ERR(dom))
+			return PTR_ERR(dom);
+	}
+
+	resctrl_online_cpu(cpu);
+
+	return 0;
+}
+
+void mpam_resctrl_offline_cpu(unsigned int cpu)
+{
+	int i;
+	struct mpam_resctrl_res *res;
+	struct mpam_resctrl_dom *dom;
+	struct rdt_mon_domain *mon_d;
+	struct rdt_ctrl_domain *ctrl_d;
+	bool ctrl_dom_empty, mon_dom_empty;
+
+	resctrl_offline_cpu(cpu);
+
+	guard(mutex)(&domain_list_lock);
+	for (i = 0; i < RDT_NUM_RESOURCES; i++) {
+		res = &mpam_resctrl_controls[i];
+		if (!res->class)
+			continue;	// dummy resource
+
+		dom = mpam_resctrl_get_domain_from_cpu(cpu, res);
+		if (WARN_ON_ONCE(!dom))
+			continue;
+
+		ctrl_dom_empty = true;
+		if (exposed_alloc_capable) {
+			ctrl_d = &dom->resctrl_ctrl_dom;
+			ctrl_dom_empty = mpam_resctrl_offline_domain_hdr(cpu, &ctrl_d->hdr);
+			if (ctrl_dom_empty)
+				resctrl_offline_ctrl_domain(&res->resctrl_res, ctrl_d);
+		}
+
+		mon_dom_empty = true;
+		if (exposed_mon_capable) {
+			mon_d = &dom->resctrl_mon_dom;
+			mon_dom_empty = mpam_resctrl_offline_domain_hdr(cpu, &mon_d->hdr);
+			if (mon_dom_empty)
+				resctrl_offline_mon_domain(&res->resctrl_res, mon_d);
+		}
+
+		if (ctrl_dom_empty && mon_dom_empty)
+			kfree(dom);
+	}
+}
+
+int mpam_resctrl_setup(void)
+{
+	int err = 0;
+	enum resctrl_res_level i;
+	struct mpam_resctrl_res *res;
+
+	cpus_read_lock();
+	for (i = 0; i < RDT_NUM_RESOURCES; i++) {
+		res = &mpam_resctrl_controls[i];
+		INIT_LIST_HEAD_RCU(&res->resctrl_res.ctrl_domains);
+		INIT_LIST_HEAD_RCU(&res->resctrl_res.mon_domains);
+		res->resctrl_res.rid = i;
+	}
+
+	/* TODO: pick MPAM classes to map to resctrl resources */
+
+	/* Initialise the resctrl structures from the classes */
+	for (i = 0; i < RDT_NUM_RESOURCES; i++) {
+		res = &mpam_resctrl_controls[i];
+		if (!res->class)
+			continue;	// dummy resource
+
+		err = mpam_resctrl_control_init(res, i);
+		if (err) {
+			pr_debug("Failed to initialise rid %u\n", i);
+			break;
+		}
+	}
+	cpus_read_unlock();
+
+	if (err || (!exposed_alloc_capable && !exposed_mon_capable)) {
+		if (err)
+			pr_debug("Internal error %d - resctrl not supported\n",
+				 err);
+		else
+			pr_debug("No alloc(%u) or monitor(%u) found - resctrl not supported\n",
+				 exposed_alloc_capable, exposed_mon_capable);
+		err = -EOPNOTSUPP;
+	}
+
+	if (!err) {
+		if (!is_power_of_2(mpam_pmg_max + 1)) {
+			/*
+			 * If not all the partid*pmg values are valid indexes,
+			 * resctrl may allocate pmg that don't exist. This
+			 * should cause an error interrupt.
+			 */
+			pr_warn("Number of PMG is not a power of 2! resctrl may misbehave");
+		}
+
+		/* TODO: call resctrl_init() */
+	}
+
+	return err;
+}
diff --git a/include/linux/arm_mpam.h b/include/linux/arm_mpam.h
index 7f00c5285a32..2c7d1413a401 100644
--- a/include/linux/arm_mpam.h
+++ b/include/linux/arm_mpam.h
@@ -49,6 +49,9 @@ static inline int mpam_ris_create(struct mpam_msc *msc, u8 ris_idx,
 }
 #endif
 
+bool resctrl_arch_alloc_capable(void);
+bool resctrl_arch_mon_capable(void);
+
 /**
  * mpam_register_requestor() - Register a requestor with the MPAM driver
  * @partid_max:		The maximum PARTID value the requestor can generate.
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:47 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:47 +0000
Subject: [RFC PATCH 24/38] arm_mpam: resctrl: Allow resctrl to allocate monitors
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-25-james.morse@arm.com>

When resctrl wants to read a domain's 'QOS_L3_OCCUP', it needs
to allocate a monitor on the corresponding resource. Monitors are
allocated by class instead of component.

MBM monitors are much more complicated, if there are enough monitors,
they will be pre-allocated and free-running. If ABMC is in use instead
then 'some' are pre-allocated in a different way, and need assigning.

Add helpers to allocate a CSU monitor. These helper return an out
of range value for MBM counters.

Allocating a montitor context is expected to block until hardware
resources become available. This only makes sense for QOS_L3_OCCUP
as unallocated MBM counters are losing data.

Signed-off-by: James Morse <james.morse at arm.com>
---
Since ABMC got merged it may be possible to remove the monitor alloc
call for MBM counters from resctrl as this work is now done by ABMC's
assign call.
---
 drivers/resctrl/mpam_internal.h | 14 ++++++-
 drivers/resctrl/mpam_resctrl.c  | 68 +++++++++++++++++++++++++++++++++
 include/linux/arm_mpam.h        |  4 ++
 3 files changed, 85 insertions(+), 1 deletion(-)

diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index 05101186af17..3a68ebd498fa 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -32,6 +32,14 @@ DECLARE_STATIC_KEY_FALSE(mpam_enabled);
 #define PACKED_FOR_KUNIT
 #endif
 
+/*
+ * This 'mon' values must not alias an actual monitor, so must be larger than
+ * U16_MAX, but not be confused with an errno value, so smaller than
+ * (u32)-SZ_4K.
+ * USE_PRE_ALLOCATED is used to avoid confusion with an actual monitor.
+ */
+#define USE_PRE_ALLOCATED      (U16_MAX + 1)
+
 static inline bool mpam_is_enabled(void)
 {
 	return static_branch_likely(&mpam_enabled);
@@ -215,7 +223,11 @@ enum mon_filter_options {
 };
 
 struct mon_cfg {
-	u16			mon;
+	/*
+	 * mon must be large enough to hold out of range values like
+	 * USE_RMID_IDX
+	 */
+	u32                     mon;
 	u8			pmg;
 	bool			match_pmg;
 	bool			csu_exclude_clean;
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 22ad5dd3c383..a2b238d47117 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -21,6 +21,8 @@
 
 #include "mpam_internal.h"
 
+DECLARE_WAIT_QUEUE_HEAD(resctrl_mon_ctx_waiters);
+
 /*
  * The classes we've picked to map to resctrl resources, wrapped
  * in with their resctrl structure.
@@ -287,6 +289,72 @@ struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l)
 	return &mpam_resctrl_controls[l].resctrl_res;
 }
 
+static int resctrl_arch_mon_ctx_alloc_no_wait(enum resctrl_event_id evtid)
+{
+	struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[evtid];
+
+	if (!mon->class)
+		return -EINVAL;
+
+	switch (evtid) {
+	case QOS_L3_OCCUP_EVENT_ID:
+		/* With CDP, one monitor gets used for both code/data reads */
+		return mpam_alloc_csu_mon(mon->class);
+	case QOS_L3_MBM_LOCAL_EVENT_ID:
+	case QOS_L3_MBM_TOTAL_EVENT_ID:
+		return USE_PRE_ALLOCATED;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r,
+				 enum resctrl_event_id evtid)
+{
+	DEFINE_WAIT(wait);
+	int *ret;
+
+	ret = kmalloc(sizeof(*ret), GFP_KERNEL);
+	if (!ret)
+		return ERR_PTR(-ENOMEM);
+
+	do {
+		prepare_to_wait(&resctrl_mon_ctx_waiters, &wait,
+				TASK_INTERRUPTIBLE);
+		*ret = resctrl_arch_mon_ctx_alloc_no_wait(evtid);
+		if (*ret == -ENOSPC)
+			schedule();
+	} while (*ret == -ENOSPC && !signal_pending(current));
+	finish_wait(&resctrl_mon_ctx_waiters, &wait);
+
+	return ret;
+}
+
+static void resctrl_arch_mon_ctx_free_no_wait(enum resctrl_event_id evtid,
+					      u32 mon_idx)
+{
+	struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[evtid];
+
+	if (!mon->class)
+		return;
+
+	if (evtid == QOS_L3_OCCUP_EVENT_ID)
+		mpam_free_csu_mon(mon->class, mon_idx);
+
+	wake_up(&resctrl_mon_ctx_waiters);
+}
+
+void resctrl_arch_mon_ctx_free(struct rdt_resource *r,
+			       enum resctrl_event_id evtid, void *arch_mon_ctx)
+{
+	u32 mon_idx = *(u32 *)arch_mon_ctx;
+
+	kfree(arch_mon_ctx);
+	arch_mon_ctx = NULL;
+
+	resctrl_arch_mon_ctx_free_no_wait(evtid, mon_idx);
+}
+
 static bool cache_has_usable_cpor(struct mpam_class *class)
 {
 	struct mpam_props *cprops = &class->props;
diff --git a/include/linux/arm_mpam.h b/include/linux/arm_mpam.h
index 385554ceb452..e1461e32af75 100644
--- a/include/linux/arm_mpam.h
+++ b/include/linux/arm_mpam.h
@@ -63,6 +63,10 @@ u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid);
 void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid);
 u32 resctrl_arch_system_num_rmid_idx(void);
 
+struct rdt_resource;
+void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r, enum resctrl_event_id evtid);
+void resctrl_arch_mon_ctx_free(struct rdt_resource *r, enum resctrl_event_id evtid, void *ctx);
+
 /**
  * mpam_register_requestor() - Register a requestor with the MPAM driver
  * @partid_max:		The maximum PARTID value the requestor can generate.
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:51 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:51 +0000
Subject: [RFC PATCH 28/38] arm64: mpam: Select ARCH_HAS_CPU_RESCTRL
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-29-james.morse@arm.com>

Enough MPAM support is present to enable ARCH_HAS_CPU_RESCTRL.
Let it rip^Wlink!

ARCH_HAS_CPU_RESCTRL indicates resctrl can be enabled. It is enabled
by the arch code sipmly because it has 'arch' in its name.

This removes ARM_CPU_RESCTRL as a mimic of X86_CPU_RESCTRL.
While here, move the ACPI dependency to the driver's Kconfig file.

Signed-off-by: James Morse <james.morse at arm.com>
---
 arch/arm64/Kconfig               | 4 ++--
 arch/arm64/include/asm/resctrl.h | 2 ++
 drivers/resctrl/Kconfig          | 9 ++++++++-
 drivers/resctrl/Makefile         | 2 +-
 4 files changed, 13 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm64/include/asm/resctrl.h

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 558baa9e7c08..e67885ac7717 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -2025,8 +2025,8 @@ config ARM64_TLB_RANGE
 
 config ARM64_MPAM
 	bool "Enable support for MPAM"
-	select ARM64_MPAM_DRIVER if EXPERT	# does nothing yet
-	select ACPI_MPAM if ACPI
+	select ARM64_MPAM_DRIVER
+	select ARCH_HAS_CPU_RESCTRL
 	help
 	  Memory System Resource Partitioning and Monitoring (MPAM) is an
 	  optional extension to the Arm architecture that allows each
diff --git a/arch/arm64/include/asm/resctrl.h b/arch/arm64/include/asm/resctrl.h
new file mode 100644
index 000000000000..b506e95cf6e3
--- /dev/null
+++ b/arch/arm64/include/asm/resctrl.h
@@ -0,0 +1,2 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/arm_mpam.h>
diff --git a/drivers/resctrl/Kconfig b/drivers/resctrl/Kconfig
index c808e0470394..672abea3b03c 100644
--- a/drivers/resctrl/Kconfig
+++ b/drivers/resctrl/Kconfig
@@ -1,6 +1,7 @@
 menuconfig ARM64_MPAM_DRIVER
 	bool "MPAM driver"
-	depends on ARM64 && ARM64_MPAM && EXPERT
+	depends on ARM64 && ARM64_MPAM
+	select ACPI_MPAM if ACPI
 	help
 	  Memory System Resource Partitioning and Monitoring (MPAM) driver for
 	  System IP, e.g. caches and memory controllers.
@@ -22,3 +23,9 @@ config MPAM_KUNIT_TEST
 	  If unsure, say N.
 
 endif
+
+config ARM64_MPAM_RESCTRL_FS
+	bool
+	default y if ARM64_MPAM_DRIVER && RESCTRL_FS
+	select RESCTRL_RMID_DEPENDS_ON_CLOSID
+	select RESCTRL_ASSIGN_FIXED
diff --git a/drivers/resctrl/Makefile b/drivers/resctrl/Makefile
index 40beaf999582..4f6d0e81f9b8 100644
--- a/drivers/resctrl/Makefile
+++ b/drivers/resctrl/Makefile
@@ -1,5 +1,5 @@
 obj-$(CONFIG_ARM64_MPAM_DRIVER)			+= mpam.o
 mpam-y						+= mpam_devices.o
-mpam-$(CONFIG_ARM_CPU_RESCTRL)			+= mpam_resctrl.o
+mpam-$(CONFIG_ARM64_MPAM_RESCTRL_FS)		+= mpam_resctrl.o
 
 ccflags-$(CONFIG_ARM64_MPAM_DRIVER_DEBUG)	+= -DDEBUG
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:50 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:50 +0000
Subject: [RFC PATCH 27/38] arm_mpam: resctrl: Add empty definitions for assorted resctrl functions
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-28-james.morse@arm.com>

A few resctrl features and hooks need to be provided, but aren't needed
or supported on MPAM platforms.

resctrl has individual hooks to separately enable and disable the
closid/partid and rmid/pmg context switching code. For MPAM this is all
the same thing, as the value in struct task_struct is used to cache the
value that should be written to hardware. arm64's context switching code
is enabled once MPAM is usable, but doesn't touch the hardware unless
the value has changed.

For now event configuration is not supported, and can be turned off
by returning 'false' from resctrl_arch_is_evt_configurable().

Add this, and empty definitions for the other hooks.

Signed-off-by: James Morse <james.morse at arm.com>
---
 drivers/resctrl/mpam_resctrl.c | 17 +++++++++++++++++
 include/linux/arm_mpam.h       |  9 +++++++++
 2 files changed, 26 insertions(+)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 1333dc40714a..00455de3efe9 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -85,6 +85,23 @@ bool resctrl_arch_mon_capable(void)
 	return exposed_mon_capable;
 }
 
+bool resctrl_arch_is_evt_configurable(enum resctrl_event_id evt)
+{
+	return false;
+}
+
+void resctrl_arch_mon_event_config_read(void *info)
+{
+}
+
+void resctrl_arch_mon_event_config_write(void *info)
+{
+}
+
+void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_mon_domain *d)
+{
+}
+
 bool resctrl_arch_get_cdp_enabled(enum resctrl_res_level rid)
 {
 	switch (rid) {
diff --git a/include/linux/arm_mpam.h b/include/linux/arm_mpam.h
index 86d5e326d2bd..f92a36187a52 100644
--- a/include/linux/arm_mpam.h
+++ b/include/linux/arm_mpam.h
@@ -67,6 +67,15 @@ struct rdt_resource;
 void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r, enum resctrl_event_id evtid);
 void resctrl_arch_mon_ctx_free(struct rdt_resource *r, enum resctrl_event_id evtid, void *ctx);
 
+/*
+ * The CPU configuration for MPAM is cheap to write, and is only written if it
+ * has changed. No need for fine grained enables.
+ */
+static inline void resctrl_arch_enable_mon(void) { }
+static inline void resctrl_arch_disable_mon(void) { }
+static inline void resctrl_arch_enable_alloc(void) { }
+static inline void resctrl_arch_disable_alloc(void) { }
+
 static inline unsigned int resctrl_arch_round_mon_val(unsigned int val)
 {
 	return val;
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:53 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:53 +0000
Subject: [RFC PATCH 30/38] arm_mpam: resctrl: Call resctrl_exit() in the event of errors
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-31-james.morse@arm.com>

All of MPAMs errors indicate a software bug, e.g. an out-of-bounds
partid has been generated. When this happens, the mpam driver
is disabled.

If resctrl_init() succeeded, also call resctrl_exit() to
remove resctrl.

mpam_devices.c calls mpam_resctrl_teardown_class() when a class
becomes incomplete, and can no longer be used by resctrl. If
resctrl was using this class, then resctrl_exit() is called.
This in turn removes the kernfs hierarchy from the filesystem
and free()s memory that was allocated by resctrl.

Signed-off-by: James Morse <james.morse at arm.com>
---
 drivers/resctrl/mpam_devices.c  | 32 +++++++++++--
 drivers/resctrl/mpam_internal.h |  4 ++
 drivers/resctrl/mpam_resctrl.c  | 80 +++++++++++++++++++++++++++++++++
 3 files changed, 112 insertions(+), 4 deletions(-)

diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index fccebfd980d8..1334093fc03e 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -73,6 +73,14 @@ static DECLARE_WORK(mpam_broken_work, &mpam_disable);
 /* When mpam is disabled, the printed reason to aid debugging */
 static char *mpam_disable_reason;
 
+/*
+ * Whether resctrl has been setup. Used by cpuhp in preference to
+ * mpam_is_enabled(). The disable call after an error interrupt makes
+ * mpam_is_enabled() false before the cpuhp callbacks are made.
+ * Reads/writes should hold mpam_cpuhp_state_lock, (or be cpuhp callbacks).
+ */
+static bool mpam_resctrl_enabled;
+
 /*
  * An MSC is a physical container for controls and monitors, each identified by
  * their RIS index. These share a base-address, interrupts and some MMIO
@@ -1627,7 +1635,7 @@ static int mpam_cpu_online(unsigned int cpu)
 			mpam_reprogram_msc(msc);
 	}
 
-	if (mpam_is_enabled())
+	if (mpam_resctrl_enabled)
 		mpam_resctrl_online_cpu(cpu);
 
 	return 0;
@@ -1673,7 +1681,7 @@ static int mpam_cpu_offline(unsigned int cpu)
 {
 	struct mpam_msc *msc;
 
-	if (mpam_is_enabled())
+	if (mpam_resctrl_enabled)
 		mpam_resctrl_offline_cpu(cpu);
 
 	guard(srcu)(&mpam_srcu);
@@ -2535,6 +2543,7 @@ static void mpam_enable_once(void)
 	}
 
 	static_branch_enable(&mpam_enabled);
+	mpam_resctrl_enabled = true;
 	mpam_register_cpuhp_callbacks(mpam_cpu_online, mpam_cpu_offline,
 				      "mpam:online");
 
@@ -2594,24 +2603,39 @@ void mpam_reset_class(struct mpam_class *class)
 void mpam_disable(struct work_struct *ignored)
 {
 	int idx;
+	bool do_resctrl_exit;
 	struct mpam_class *class;
 	struct mpam_msc *msc, *tmp;
 
+	if (mpam_is_enabled())
+		static_branch_disable(&mpam_enabled);
+
 	mutex_lock(&mpam_cpuhp_state_lock);
 	if (mpam_cpuhp_state) {
 		cpuhp_remove_state(mpam_cpuhp_state);
 		mpam_cpuhp_state = 0;
 	}
+
+	/*
+	 * Removing the cpuhp state called mpam_cpu_offline() and told resctrl
+	 * all the CPUs are offline.
+	 */
+	do_resctrl_exit = mpam_resctrl_enabled;
+	mpam_resctrl_enabled = false;
 	mutex_unlock(&mpam_cpuhp_state_lock);
 
-	static_branch_disable(&mpam_enabled);
+	if (do_resctrl_exit)
+		mpam_resctrl_exit();
 
 	mpam_unregister_irqs();
 
 	idx = srcu_read_lock(&mpam_srcu);
 	list_for_each_entry_srcu(class, &mpam_classes, classes_list,
-				 srcu_read_lock_held(&mpam_srcu))
+				 srcu_read_lock_held(&mpam_srcu)) {
 		mpam_reset_class(class);
+		if (do_resctrl_exit)
+			mpam_resctrl_teardown_class(class);
+	}
 	srcu_read_unlock(&mpam_srcu, idx);
 
 	mutex_lock(&mpam_list_lock);
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index 3a68ebd498fa..b13d5e55e701 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -450,12 +450,16 @@ int mpam_get_cpumask_from_cache_id(unsigned long cache_id, u32 cache_level,
 
 #ifdef CONFIG_RESCTRL_FS
 int mpam_resctrl_setup(void);
+void mpam_resctrl_exit(void);
 int mpam_resctrl_online_cpu(unsigned int cpu);
 void mpam_resctrl_offline_cpu(unsigned int cpu);
+void mpam_resctrl_teardown_class(struct mpam_class *class);
 #else
 static inline int mpam_resctrl_setup(void) { return 0; }
+static inline void mpam_resctrl_exit(void) { }
 static inline int mpam_resctrl_online_cpu(unsigned int cpu) { return 0; }
 static inline void mpam_resctrl_offline_cpu(unsigned int cpu) { }
+static inline void mpam_resctrl_teardown_class(struct mpam_class *class) { }
 #endif /* CONFIG_RESCTRL_FS */
 
 /*
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index eb3caee45470..506063bd3348 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -52,6 +52,12 @@ static bool exposed_mon_capable;
  */
 static bool cdp_enabled;
 
+/*
+ * If resctrl_init() succeeded, resctrl_exit() can be used to remove support
+ * for the filesystem in the event of an error.
+ */
+static bool resctrl_enabled;
+
 /*
  * L3 local/total may come from different classes - what is the number of MBWU
  * 'on L3'?
@@ -310,6 +316,9 @@ static int resctrl_arch_mon_ctx_alloc_no_wait(enum resctrl_event_id evtid)
 {
 	struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[evtid];
 
+	if (!mpam_is_enabled())
+		return -EINVAL;
+
 	if (!mon->class)
 		return -EINVAL;
 
@@ -352,6 +361,9 @@ static void resctrl_arch_mon_ctx_free_no_wait(enum resctrl_event_id evtid,
 {
 	struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[evtid];
 
+	if (!mpam_is_enabled())
+		return;
+
 	if (!mon->class)
 		return;
 
@@ -449,6 +461,9 @@ int resctrl_arch_rmid_read(struct rdt_resource	*r, struct rdt_mon_domain *d,
 
 	resctrl_arch_rmid_read_context_check();
 
+	if (!mpam_is_enabled())
+		return -EINVAL;
+
 	if (eventid >= QOS_NUM_EVENTS || !mon->class)
 		return -EINVAL;
 
@@ -1343,6 +1358,9 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 	lockdep_assert_cpus_held();
 	lockdep_assert_irqs_enabled();
 
+	if (!mpam_is_enabled())
+		return -EINVAL;
+
 	/*
 	 * No need to check the CPU as mpam_apply_config() doesn't care, and
 	 * resctrl_arch_update_domains() relies on this.
@@ -1408,6 +1426,9 @@ int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid)
 	lockdep_assert_cpus_held();
 	lockdep_assert_irqs_enabled();
 
+	if (!mpam_is_enabled())
+		return -EINVAL;
+
 	list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
 		for (t = 0; t < CDP_NUM_TYPES; t++) {
 			cfg = &d->staged_config[t];
@@ -1769,11 +1790,70 @@ int mpam_resctrl_setup(void)
 		}
 
 		err = resctrl_init();
+		if (!err)
+			WRITE_ONCE(resctrl_enabled, true);
 	}
 
 	return err;
 }
 
+void mpam_resctrl_exit(void)
+{
+	if (!READ_ONCE(resctrl_enabled))
+		return;
+
+	WRITE_ONCE(resctrl_enabled, false);
+	resctrl_exit();
+}
+
+static void mpam_resctrl_teardown_mon(struct mpam_resctrl_mon *mon, struct mpam_class *class)
+{
+	u32 num_mbwu_mon = l3_num_allocated_mbwu;
+
+	if (!mon->mbwu_idx_to_mon)
+		return;
+
+	if (mon->assigned_counters) {
+		__free_mbwu_mon(class, mon->assigned_counters, num_mbwu_mon);
+		mon->assigned_counters = NULL;
+		kfree(mon->mbwu_idx_to_mon);
+	} else {
+		__free_mbwu_mon(class, mon->mbwu_idx_to_mon, num_mbwu_mon);
+	}
+	mon->mbwu_idx_to_mon = NULL;
+}
+
+/*
+ * The driver is detaching an MSC from this class, if resctrl was using it,
+ * pull on resctrl_exit().
+ */
+void mpam_resctrl_teardown_class(struct mpam_class *class)
+{
+	int i;
+	struct mpam_resctrl_res *res;
+	struct mpam_resctrl_mon *mon;
+
+	might_sleep();
+
+	for (i = 0; i < RDT_NUM_RESOURCES; i++) {
+		res = &mpam_resctrl_controls[i];
+		if (res->class == class) {
+			res->class = NULL;
+			break;
+		}
+	}
+	for (i = 0; i < QOS_NUM_EVENTS; i++) {
+		mon = &mpam_resctrl_counters[i];
+		if (mon->class == class) {
+			mon->class = NULL;
+
+			mpam_resctrl_teardown_mon(mon, class);
+
+			break;
+		}
+	}
+}
+
 #ifdef CONFIG_MPAM_KUNIT_TEST
 #include "test_mpam_resctrl.c"
 #endif
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:54 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:54 +0000
Subject: [RFC PATCH 31/38] arm_mpam: resctrl: Update the rmid reallocation limit
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-32-james.morse@arm.com>

resctrl's limbo code needs to be told when the data left in a cache is
small enough for the partid+pmg value to be re-allocated.

x86 uses the cache size divided by the number of rmid users the cache
may have. Do the same, but for the smallest cache, and with the
number of partid-and-pmg users.

Querying the cache size can't happen until after cacheinfo_sysfs_init()
has run, so mpam_resctrl_setup() must wait until then.

Signed-off-by: James Morse <james.morse at arm.com>
---
 drivers/resctrl/mpam_resctrl.c | 54 ++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 506063bd3348..ccdf8db742c9 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -16,6 +16,7 @@
 #include <linux/resctrl.h>
 #include <linux/slab.h>
 #include <linux/types.h>
+#include <linux/wait.h>
 
 #include <asm/mpam.h>
 
@@ -58,6 +59,13 @@ static bool cdp_enabled;
  */
 static bool resctrl_enabled;
 
+/*
+ * mpam_resctrl_pick_caches() needs to know the size of the caches. cacheinfo
+ * populates this from a device_initcall(). mpam_resctrl_setup() must wait.
+ */
+static bool cacheinfo_ready;
+static DECLARE_WAIT_QUEUE_HEAD(wait_cacheinfo_ready);
+
 /*
  * L3 local/total may come from different classes - what is the number of MBWU
  * 'on L3'?
@@ -584,6 +592,38 @@ void resctrl_arch_reset_cntr(struct rdt_resource *r, struct rdt_mon_domain *d,
 	reset_mon_cdp_safe(mon, mon_comp, USE_PRE_ALLOCATED, closid, rmid);
 }
 
+/*
+ * The rmid realloc threshold should be for the smallest cache exposed to
+ * resctrl.
+ */
+static int update_rmid_limits(struct mpam_class *class)
+{
+	u32 num_unique_pmg = resctrl_arch_system_num_rmid_idx();
+	struct mpam_props *cprops = &class->props;
+	struct cacheinfo *ci;
+
+	lockdep_assert_cpus_held();
+
+	/* Assume cache levels are the same size for all CPUs... */
+	ci = get_cpu_cacheinfo_level(smp_processor_id(), class->level);
+	if (!ci || ci->size == 0) {
+		pr_debug("Could not read cache size for class %u\n",
+			 class->level);
+		return -EINVAL;
+	}
+
+	if (!mpam_has_feature(mpam_feat_msmon_csu, cprops))
+		return 0;
+
+	if (!resctrl_rmid_realloc_limit ||
+	    ci->size < resctrl_rmid_realloc_limit) {
+		resctrl_rmid_realloc_limit = ci->size;
+		resctrl_rmid_realloc_threshold = ci->size / num_unique_pmg;
+	}
+
+	return 0;
+}
+
 static bool cache_has_usable_cpor(struct mpam_class *class)
 {
 	struct mpam_props *cprops = &class->props;
@@ -1025,6 +1065,9 @@ static void mpam_resctrl_pick_counters(void)
 			/* CSU counters only make sense on a cache. */
 			switch (class->type) {
 			case MPAM_CLASS_CACHE:
+				if (update_rmid_limits(class))
+					continue;
+
 				counter_update_class(QOS_L3_OCCUP_EVENT_ID, class);
 				return;
 			default:
@@ -1731,6 +1774,8 @@ int mpam_resctrl_setup(void)
 	struct mpam_resctrl_res *res;
 	struct mpam_resctrl_mon *mon;
 
+	wait_event(wait_cacheinfo_ready, cacheinfo_ready);
+
 	cpus_read_lock();
 	for (i = 0; i < RDT_NUM_RESOURCES; i++) {
 		res = &mpam_resctrl_controls[i];
@@ -1854,6 +1899,15 @@ void mpam_resctrl_teardown_class(struct mpam_class *class)
 	}
 }
 
+static int __init __cacheinfo_ready(void)
+{
+	cacheinfo_ready = true;
+	wake_up(&wait_cacheinfo_ready);
+
+	return 0;
+}
+device_initcall_sync(__cacheinfo_ready);
+
 #ifdef CONFIG_MPAM_KUNIT_TEST
 #include "test_mpam_resctrl.c"
 #endif
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:55 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:55 +0000
Subject: [RFC PATCH 32/38] arm_mpam: resctrl: Sort the order of the domain lists
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-33-james.morse@arm.com>

resctrl documents that the domains appear in numeric order in the
schemata file. This means a little more work is needed when bringing
a domain online.

Add the support for this, using resctrl_find_domain() to find the
point to insert in the list.

Signed-off-by: James Morse <james.morse at arm.com>
---
 drivers/resctrl/mpam_resctrl.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index ccdf8db742c9..84ef3c1b4f53 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -1547,6 +1547,21 @@ static struct mpam_component *find_component(struct mpam_class *victim, int cpu)
 	return NULL;
 }
 
+static void mpam_resctrl_domain_insert(struct list_head *list,
+				       struct rdt_domain_hdr *new)
+{
+	struct rdt_domain_hdr *err;
+	struct list_head *pos = NULL;
+
+	lockdep_assert_held(&domain_list_lock);
+
+	err = resctrl_find_domain(list, new->id, &pos);
+	if (WARN_ON_ONCE(err))
+		return;
+
+	list_add_tail_rcu(&new->list, pos);
+}
+
 static struct mpam_resctrl_dom *
 mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
 {
@@ -1584,8 +1599,7 @@ mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
 		ctrl_d = &dom->resctrl_ctrl_dom;
 		mpam_resctrl_domain_hdr_init(cpu, ctrl_comp, &ctrl_d->hdr);
 		ctrl_d->hdr.type = RESCTRL_CTRL_DOMAIN;
-		/* TODO: this list should be sorted */
-		list_add_tail_rcu(&ctrl_d->hdr.list, &r->ctrl_domains);
+		mpam_resctrl_domain_insert(&r->ctrl_domains, &ctrl_d->hdr);
 		err = resctrl_online_ctrl_domain(r, ctrl_d);
 		if (err) {
 			dom = ERR_PTR(err);
@@ -1623,8 +1637,7 @@ mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
 		mon_d = &dom->resctrl_mon_dom;
 		mpam_resctrl_domain_hdr_init(cpu, any_mon_comp, &mon_d->hdr);
 		mon_d->hdr.type = RESCTRL_MON_DOMAIN;
-		/* TODO: this list should be sorted */
-		list_add_tail_rcu(&mon_d->hdr.list, &r->mon_domains);
+		mpam_resctrl_domain_insert(&r->mon_domains, &mon_d->hdr);
 		err = resctrl_online_mon_domain(r, mon_d);
 		if (err) {
 			dom = ERR_PTR(err);
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:56 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:56 +0000
Subject: [RFC PATCH 33/38] arm_mpam: Generate a configuration for min controls
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-34-james.morse@arm.com>

MPAM supports a minimum and maximum control for memory bandwidth. The
purpose of the minimum control is to give priority to tasks that are
below their minimum value. Resctrl only provides one value for the
bandwidth configuration, which is used for the maximum.

The minimum control is always programmed to zero on hardware that
supports it.

Generate a minimum bandwidth value that is 5% lower than the
value provided by resctrl. This means tasks that are not
receiving their target bandwidth can be prioritised by the
hardware.

CC: Zeng Heng <zengheng4 at huawei.com>
Signed-off-by: James Morse <james.morse at arm.com>
---
 drivers/resctrl/mpam_devices.c      | 68 +++++++++++++++++++++++++++--
 drivers/resctrl/mpam_internal.h     |  2 +
 drivers/resctrl/test_mpam_devices.c | 66 ++++++++++++++++++++++++++++
 3 files changed, 132 insertions(+), 4 deletions(-)

diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index 1334093fc03e..741e14e1e6cf 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -721,6 +721,13 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris)
 			mpam_set_feature(mpam_feat_mbw_part, props);
 
 		props->bwa_wd = FIELD_GET(MPAMF_MBW_IDR_BWA_WD, mbw_features);
+
+		/*
+		 * The BWA_WD field can represent 0-63, but the control fields it
+		 * describes have a maximum of 16 bits.
+		 */
+		props->bwa_wd = min(props->bwa_wd, 16);
+
 		if (props->bwa_wd && FIELD_GET(MPAMF_MBW_IDR_HAS_MAX, mbw_features))
 			mpam_set_feature(mpam_feat_mbw_max, props);
 
@@ -1387,7 +1394,7 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
 
 	if (mpam_has_feature(mpam_feat_mbw_min, rprops) &&
 	    mpam_has_feature(mpam_feat_mbw_min, cfg))
-		mpam_write_partsel_reg(msc, MBW_MIN, 0);
+		mpam_write_partsel_reg(msc, MBW_MIN, cfg->mbw_min);
 
 	if (mpam_has_feature(mpam_feat_mbw_max, rprops) &&
 	    mpam_has_feature(mpam_feat_mbw_max, cfg)) {
@@ -2693,24 +2700,77 @@ static bool mpam_update_config(struct mpam_config *cfg,
 	maybe_update_config(cfg, mpam_feat_cpor_part, newcfg, cpbm, has_changes);
 	maybe_update_config(cfg, mpam_feat_mbw_part, newcfg, mbw_pbm, has_changes);
 	maybe_update_config(cfg, mpam_feat_mbw_max, newcfg, mbw_max, has_changes);
+	maybe_update_config(cfg, mpam_feat_mbw_min, newcfg, mbw_min, has_changes);
 
 	return has_changes;
 }
 
+static void mpam_extend_config(struct mpam_class *class, struct mpam_config *cfg)
+{
+	struct mpam_props *cprops = &class->props;
+	u16 min, min_hw_granule, delta;
+	u16 max_hw_value, res0_bits;
+
+	/*
+	 * MAX and MIN should be set together. If only one is provided,
+	 * generate a configuration for the other. If only one control
+	 * type is supported, the other value will be ignored.
+	 *
+	 * Resctrl can only configure the MAX.
+	 */
+	if (mpam_has_feature(mpam_feat_mbw_max, cfg) &&
+	    !mpam_has_feature(mpam_feat_mbw_min, cfg)) {
+		/*
+		 * Calculate the values the 'min' control can hold.
+		 * e.g. on a platform with bwa_wd = 8, min_hw_granule is 0x00ff
+		 * because those bits are RES0. Configurations of this value
+		 * are effectively zero. But configurations need to saturate
+		 * at min_hw_granule on systems with mismatched bwa_wd, where
+		 * the 'less than 0' values are implemented on some MSC, but
+		 * not others.
+		 */
+		res0_bits = 16 - cprops->bwa_wd;
+		max_hw_value = ((1 << cprops->bwa_wd) - 1) << res0_bits;
+		min_hw_granule = ~max_hw_value;
+
+		delta = ((5 * MPAMCFG_MBW_MAX_MAX) / 100) - 1;
+		if (cfg->mbw_max > delta)
+			min = cfg->mbw_max - delta;
+		else
+			min = 0;
+
+		cfg->mbw_min = max(min, min_hw_granule);
+		mpam_set_feature(mpam_feat_mbw_min, cfg);
+	}
+}
+
 int mpam_apply_config(struct mpam_component *comp, u16 partid,
-		      struct mpam_config *cfg)
+		      struct mpam_config *user_cfg)
 {
 	struct mpam_write_config_arg arg;
 	struct mpam_msc_ris *ris;
+	struct mpam_config cfg;
 	struct mpam_vmsc *vmsc;
 	struct mpam_msc *msc;
 
 	lockdep_assert_cpus_held();
 
+
 	/* Don't pass in the current config! */
-	WARN_ON_ONCE(&comp->cfg[partid] == cfg);
+	WARN_ON_ONCE(&comp->cfg[partid] == user_cfg);
 
-	if (!mpam_update_config(&comp->cfg[partid], cfg))
+	/*
+	 * Copy the config to avoid writing back the 'extended' version to
+	 * the caller.
+	 * This avoids mpam_devices.c setting a mbm_min that mpam_resctrl.c
+	 * is unaware of ... when it then changes mbm_max to be lower than
+	 * mbm_min.
+	 */
+	cfg = *user_cfg;
+
+	mpam_extend_config(comp->class, &cfg);
+
+	if (!mpam_update_config(&comp->cfg[partid], &cfg))
 		return 0;
 
 	arg.comp = comp;
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index b13d5e55e701..d381906545ed 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -277,6 +277,7 @@ struct mpam_config {
 	u32	cpbm;
 	u32	mbw_pbm;
 	u16	mbw_max;
+	u16	mbw_min;
 
 	bool	reset_cpbm;
 	bool	reset_mbw_pbm;
@@ -618,6 +619,7 @@ static inline void mpam_resctrl_teardown_class(struct mpam_class *class) { }
  * MPAMCFG_MBW_MAX - MPAM memory maximum bandwidth partitioning configuration
  *                   register
  */
+#define MPAMCFG_MBW_MAX_MAX_NR_BITS	16
 #define MPAMCFG_MBW_MAX_MAX		GENMASK(15, 0)
 #define MPAMCFG_MBW_MAX_HARDLIM		BIT(31)
 
diff --git a/drivers/resctrl/test_mpam_devices.c b/drivers/resctrl/test_mpam_devices.c
index 3e8d564a0c64..2f802fd9f249 100644
--- a/drivers/resctrl/test_mpam_devices.c
+++ b/drivers/resctrl/test_mpam_devices.c
@@ -322,6 +322,71 @@ static void test_mpam_enable_merge_features(struct kunit *test)
 	mutex_unlock(&mpam_list_lock);
 }
 
+static void test_mpam_extend_config(struct kunit *test)
+{
+	struct mpam_config fake_cfg = { };
+	struct mpam_class fake_class = { };
+
+	/* Configurations with both are not modified */
+	fake_class.props.bwa_wd = 16;
+	fake_cfg.mbw_max = 0xfeef;
+	fake_cfg.mbw_min = 0xfeef;
+	bitmap_zero(fake_cfg.features, MPAM_FEATURE_LAST);
+	mpam_set_feature(mpam_feat_mbw_max, &fake_cfg);
+	mpam_set_feature(mpam_feat_mbw_min, &fake_cfg);
+	mpam_extend_config(&fake_class, &fake_cfg);
+	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_max, &fake_cfg));
+	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_min, &fake_cfg));
+	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_max, 0xfeef);
+	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_min, 0xfeef);
+
+	/* When a min is missing, it is generated */
+	fake_class.props.bwa_wd = 16;
+	fake_cfg.mbw_max = 0xfeef;
+	fake_cfg.mbw_min = 0;
+	bitmap_zero(fake_cfg.features, MPAM_FEATURE_LAST);
+	mpam_set_feature(mpam_feat_mbw_max, &fake_cfg);
+	mpam_extend_config(&fake_class, &fake_cfg);
+	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_max, &fake_cfg));
+	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_min, &fake_cfg));
+	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_max, 0xfeef);
+	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_min, 0xf224);
+
+	fake_class.props.bwa_wd = 8;
+	fake_cfg.mbw_max = 0xfeef;
+	fake_cfg.mbw_min = 0;
+	bitmap_zero(fake_cfg.features, MPAM_FEATURE_LAST);
+	mpam_set_feature(mpam_feat_mbw_max, &fake_cfg);
+	mpam_extend_config(&fake_class, &fake_cfg);
+	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_max, &fake_cfg));
+	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_min, &fake_cfg));
+	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_max, 0xfeef);
+	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_min, 0xf224);
+
+	/* 5% below the minimum granule, is still the minimum granule */
+	fake_class.props.bwa_wd = 12;
+	fake_cfg.mbw_max = 0xf;
+	fake_cfg.mbw_min = 0;
+	bitmap_zero(fake_cfg.features, MPAM_FEATURE_LAST);
+	mpam_set_feature(mpam_feat_mbw_max, &fake_cfg);
+	mpam_extend_config(&fake_class, &fake_cfg);
+	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_max, &fake_cfg));
+	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_min, &fake_cfg));
+	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_max, 0xf);
+	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_min, 0xf);
+
+	fake_class.props.bwa_wd = 16;
+	fake_cfg.mbw_max = 0x4;
+	fake_cfg.mbw_min = 0;
+	bitmap_zero(fake_cfg.features, MPAM_FEATURE_LAST);
+	mpam_set_feature(mpam_feat_mbw_max, &fake_cfg);
+	mpam_extend_config(&fake_class, &fake_cfg);
+	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_max, &fake_cfg));
+	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_min, &fake_cfg));
+	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_max, 0x4);
+	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_min, 0x0);
+}
+
 static void test_mpam_reset_msc_bitmap(struct kunit *test)
 {
 	char __iomem *buf = kunit_kzalloc(test, SZ_16K, GFP_KERNEL);
@@ -378,6 +443,7 @@ static struct kunit_case mpam_devices_test_cases[] = {
 	KUNIT_CASE(test_mpam_reset_msc_bitmap),
 	KUNIT_CASE(test_mpam_enable_merge_features),
 	KUNIT_CASE(test__props_mismatch),
+	KUNIT_CASE(test_mpam_extend_config),
 	{}
 };
 
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:58 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:58 +0000
Subject: [RFC PATCH 35/38] arm_mpam: Add workaround for T241-MPAM-1
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-36-james.morse@arm.com>

From: Shanker Donthineni <sdonthineni at nvidia.com>

The MPAM bandwidth partitioning controls will not be correctly configured,
and hardware will retain default configuration register values, meaning
generally that bandwidth will remain unprovisioned.

To address the issue, follow the below steps after updating the MBW_MIN
and/or MBW_MAX registers.

 - Perform 64b reads from all 12 bridge MPAM shadow registers at offsets
   (0x360048 + slice*0x10000 + partid*8). These registers are read-only.
 - Continue iterating until all 12 shadow register values match in a loop.
   pr_warn_once if the values fail to match within the loop count 1000.
 - Perform 64b writes with the value 0x0 to the two spare registers at
   offsets 0x1b0000 and 0x1c0000.

In the hardware, writes to the MPAMCFG_MBW_MAX MPAMCFG_MBW_MIN registers
are transformed into broadcast writes to the 12 shadow registers. The
final two writes to the spare registers cause a final rank of downstream
micro-architectural MPAM registers to be updated from the shadow copies.
The intervening loop to read the 12 shadow registers helps avoid a race
condition where writes to the spare registers occur before all shadow
registers have been updated.

Signed-off-by: Shanker Donthineni <sdonthineni at nvidia.com>
[ morse: Merged the min/max update into a single
  mpam_quirk_post_config_change() helper. Stashed the t241_id in the msc
  instead of carrying the physical address around. Test the msc quirk bit
  instead of a static key. ]
Signed-off-by: James Morse <james.morse at arm.com>
---
 Documentation/arch/arm64/silicon-errata.rst |  2 +
 drivers/resctrl/mpam_devices.c              | 87 +++++++++++++++++++++
 drivers/resctrl/mpam_internal.h             |  9 +++
 3 files changed, 98 insertions(+)

diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst
index a7ec57060f64..4e86b85fe3d6 100644
--- a/Documentation/arch/arm64/silicon-errata.rst
+++ b/Documentation/arch/arm64/silicon-errata.rst
@@ -246,6 +246,8 @@ stable kernels.
 +----------------+-----------------+-----------------+-----------------------------+
 | NVIDIA         | T241 GICv3/4.x  | T241-FABRIC-4   | N/A                         |
 +----------------+-----------------+-----------------+-----------------------------+
+| NVIDIA         | T241 MPAM       | T241-MPAM-1     | N/A                         |
++----------------+-----------------+-----------------+-----------------------------+
 +----------------+-----------------+-----------------+-----------------------------+
 | Freescale/NXP  | LS2080A/LS1043A | A-008585        | FSL_ERRATUM_A008585         |
 +----------------+-----------------+-----------------+-----------------------------+
diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index f0f6f9b55ad4..f1f03ceade0a 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -29,6 +29,16 @@
 
 #include "mpam_internal.h"
 
+/* Values for the T241 errata workaround */
+#define T241_CHIPS_MAX			4
+#define T241_CHIP_NSLICES		12
+#define T241_SPARE_REG0_OFF		0x1b0000
+#define T241_SPARE_REG1_OFF		0x1c0000
+#define T241_CHIP_ID(phys)		FIELD_GET(GENMASK_ULL(44, 43), phys)
+#define T241_SHADOW_REG_OFF(sidx, pid)	(0x360048 + (sidx) * 0x10000 + (pid) * 8)
+#define SMCCC_SOC_ID_T241		0x036b0241
+static void __iomem *t241_scratch_regs[T241_CHIPS_MAX];
+
 /*
  * mpam_list_lock protects the SRCU lists when writing. Once the
  * mpam_enabled key is enabled these lists are read-only,
@@ -630,7 +640,44 @@ static struct mpam_msc_ris *mpam_get_or_create_ris(struct mpam_msc *msc,
 	return ERR_PTR(-ENOENT);
 }
 
+static void mpam_enable_quirk_nvidia_t241(struct mpam_msc *msc,
+					  const struct mpam_quirk *quirk)
+{
+	s32 soc_id = arm_smccc_get_soc_id_version();
+	struct resource *r;
+	phys_addr_t phys;
+
+	/*
+	 * A mapping to a device other than the MSC is needed, check
+	 * SOC_ID is  NVIDIA T241 chip (036b:0241)
+	 */
+	if (soc_id < 0 || soc_id != SMCCC_SOC_ID_T241)
+		return;
+
+	r = platform_get_resource(msc->pdev, IORESOURCE_MEM, 0);
+	if (!r)
+		return;
+
+	/* Find the internal registers base addr from the CHIP ID */
+	msc->t241_id = T241_CHIP_ID(r->start);
+	phys = FIELD_PREP(GENMASK_ULL(45, 44), msc->t241_id) | 0x19000000ULL;
+
+	t241_scratch_regs[msc->t241_id] = ioremap(phys, SZ_8M);
+	if (WARN_ON_ONCE(!t241_scratch_regs[msc->t241_id]))
+		return;
+
+	mpam_set_quirk(quirk->workaround, msc);
+	pr_info_once("Enabled workaround for NVIDIA T241 erratum T241-MPAM-1\n");
+}
+
 static const struct mpam_quirk mpam_quirks[] = {
+	{
+	/* NVIDIA t241 erratum T241-MPAM-1 */
+	.init       = mpam_enable_quirk_nvidia_t241,
+	.iidr       = MPAM_IIDR_NVIDIA_T421,
+	.iidr_mask  = MPAM_IIDR_MATCH_ONE,
+	.workaround = T241_SCRUB_SHADOW_REGS,
+	},
 	{ NULL }, /* Sentinel */
 };
 
@@ -1372,6 +1419,44 @@ static void mpam_reset_msc_bitmap(struct mpam_msc *msc, u16 reg, u16 wd)
 	__mpam_write_reg(msc, reg, bm);
 }
 
+static void mpam_apply_t241_erratum(struct mpam_msc_ris *ris, u16 partid)
+{
+	int sidx, i, lcount = 1000;
+	void __iomem *regs;
+	u64 val0, val;
+
+	regs = t241_scratch_regs[ris->vmsc->msc->t241_id];
+
+	for (i = 0; i < lcount; i++) {
+		/* Read the shadow register at index 0 */
+		val0 = readq_relaxed(regs + T241_SHADOW_REG_OFF(0, partid));
+
+		/* Check if all the shadow registers have the same value */
+		for (sidx = 1; sidx < T241_CHIP_NSLICES; sidx++) {
+			val = readq_relaxed(regs +
+					    T241_SHADOW_REG_OFF(sidx, partid));
+			if (val != val0)
+				break;
+		}
+		if (sidx == T241_CHIP_NSLICES)
+			break;
+	}
+
+	if (i == lcount)
+		pr_warn_once("t241: inconsistent values in shadow regs");
+
+	/* Write a value zero to spare registers to take effect of MBW conf */
+	writeq_relaxed(0, regs + T241_SPARE_REG0_OFF);
+	writeq_relaxed(0, regs + T241_SPARE_REG1_OFF);
+}
+
+static void mpam_quirk_post_config_change(struct mpam_msc_ris *ris, u16 partid,
+					  struct mpam_config *cfg)
+{
+	if (mpam_has_quirk(T241_SCRUB_SHADOW_REGS, ris->vmsc->msc))
+		mpam_apply_t241_erratum(ris, partid);
+}
+
 /* Called via IPI. Call while holding an SRCU reference */
 static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
 				      struct mpam_config *cfg)
@@ -1455,6 +1540,8 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
 		mpam_write_partsel_reg(msc, PRI, pri_val);
 	}
 
+	mpam_quirk_post_config_change(ris, partid, cfg);
+
 	mutex_unlock(&msc->part_sel_lock);
 }
 
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index de3e5faa12b2..70b78cfd1f5b 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -133,6 +133,9 @@ struct mpam_msc {
 	void __iomem		*mapped_hwpage;
 	size_t			mapped_hwpage_sz;
 
+	/* Values only used on some platforms for quirks */
+	u32			t241_id;
+
 	struct mpam_garbage	garbage;
 };
 
@@ -219,6 +222,7 @@ struct mpam_props {
 
 /* Workaround bits for msc->quirks */
 enum mpam_device_quirks {
+	T241_SCRUB_SHADOW_REGS,
 	MPAM_QUIRK_LAST,
 };
 
@@ -239,6 +243,11 @@ struct mpam_quirk {
 				FIELD_PREP_CONST(MPAMF_IIDR_REVISION,    0xf  ) | \
 				FIELD_PREP_CONST(MPAMF_IIDR_IMPLEMENTER, 0xfff)
 
+#define MPAM_IIDR_NVIDIA_T421   FIELD_PREP_CONST(MPAMF_IIDR_PRODUCTID,   0x241) | \
+				FIELD_PREP_CONST(MPAMF_IIDR_VARIANT,     0    ) | \
+				FIELD_PREP_CONST(MPAMF_IIDR_REVISION,    0    ) | \
+				FIELD_PREP_CONST(MPAMF_IIDR_IMPLEMENTER, 0x36b)
+
 
 /* The values for MSMON_CFG_MBWU_FLT.RWBW */
 enum mon_filter_options {
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:59 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:59 +0000
Subject: [RFC PATCH 36/38] arm_mpam: Add workaround for T241-MPAM-4
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-37-james.morse@arm.com>

From: Shanker Donthineni <sdonthineni at nvidia.com>

In the T241 implementation of memory-bandwidth partitioning, in the
absence of contention for bandwidth, the minimum bandwidth setting
can affect the amount of achieved bandwidth. Specifically, the
achieved bandwidth in the absence of contention can settle to any
value between the values of MPAMCFG_MBW_MIN and MPAMCFG_MBW_MAX.
Also, if MPAMCFG_MBW_MIN is set zero (below 0.78125%), once a core
enters a throttled state, it will never leave that state.

The first issue is not a cocern if the MPAM software allows to
program MPAMCFG_MBW_MIN through the sysfs interface. This patch
ensures program MBW_MIN=1 (0.78125%) whenever MPAMCFG_MBW_MIN=0
is programmed.

In the scenario where the resctrl doesn't support the MBW_MIN
interface via sysfs, to achieve bandwidth closer to MW_MAX in the
absence of contention, software should configure a relatively narrow
gap between MBW_MIN and MBW_MAX. The recommendation is to use a 5%
gap to mitigate the problem.

Signed-off-by: Shanker Donthineni <sdonthineni at nvidia.com>
[ morse: Added as second quirk, adapted to use the new intermediate values
  in mpam_extend_config() ]
Signed-off-by: James Morse <james.morse at arm.com>
---
 Documentation/arch/arm64/silicon-errata.rst |  2 +
 drivers/resctrl/mpam_devices.c              | 60 ++++++++++++++++-----
 drivers/resctrl/mpam_internal.h             |  1 +
 3 files changed, 49 insertions(+), 14 deletions(-)

diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst
index 4e86b85fe3d6..b18bc704d4a1 100644
--- a/Documentation/arch/arm64/silicon-errata.rst
+++ b/Documentation/arch/arm64/silicon-errata.rst
@@ -248,6 +248,8 @@ stable kernels.
 +----------------+-----------------+-----------------+-----------------------------+
 | NVIDIA         | T241 MPAM       | T241-MPAM-1     | N/A                         |
 +----------------+-----------------+-----------------+-----------------------------+
+| NVIDIA         | T241 MPAM       | T241-MPAM-4     | N/A                         |
++----------------+-----------------+-----------------+-----------------------------+
 +----------------+-----------------+-----------------+-----------------------------+
 | Freescale/NXP  | LS2080A/LS1043A | A-008585        | FSL_ERRATUM_A008585         |
 +----------------+-----------------+-----------------+-----------------------------+
diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index f1f03ceade0a..5ba0aa703807 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -678,6 +678,12 @@ static const struct mpam_quirk mpam_quirks[] = {
 	.iidr_mask  = MPAM_IIDR_MATCH_ONE,
 	.workaround = T241_SCRUB_SHADOW_REGS,
 	},
+	{
+	/* NVIDIA t241 erratum T241-MPAM-4 */
+	.iidr       = MPAM_IIDR_NVIDIA_T421,
+	.iidr_mask  = MPAM_IIDR_MATCH_ONE,
+	.workaround = T241_FORCE_MBW_MIN_TO_ONE,
+	},
 	{ NULL }, /* Sentinel */
 };
 
@@ -1622,6 +1628,22 @@ static void mpam_init_reset_cfg(struct mpam_config *reset_cfg)
 	bitmap_fill(reset_cfg->features, MPAM_FEATURE_LAST);
 }
 
+/*
+ * This is not part of mpam_init_reset_cfg() as high level callers have the
+ * class, and low level callers a ris.
+ */
+static void mpam_wa_t241_force_mbw_min_to_one(struct mpam_config *cfg,
+					      struct mpam_props *props)
+{
+	u16 max_hw_value, min_hw_granule, res0_bits;
+
+	res0_bits = 16 - props->bwa_wd;
+	max_hw_value = ((1 << props->bwa_wd) - 1) << res0_bits;
+	min_hw_granule = ~max_hw_value;
+
+	cfg->mbw_min = min_hw_granule + 1;
+}
+
 /*
  * Called via smp_call_on_cpu() to prevent migration, while still being
  * pre-emptible. Caller must hold mpam_srcu.
@@ -2524,7 +2546,8 @@ static void __destroy_component_cfg(struct mpam_component *comp)
 static void mpam_reset_component_cfg(struct mpam_component *comp)
 {
 	int i;
-	struct mpam_props *cprops = &comp->class->props;
+	struct mpam_class *class = comp->class;
+	struct mpam_props *cprops = &class->props;
 
 	mpam_assert_partid_sizes_fixed();
 
@@ -2539,6 +2562,10 @@ static void mpam_reset_component_cfg(struct mpam_component *comp)
 			comp->cfg[i].mbw_pbm = GENMASK(cprops->mbw_pbm_bits - 1, 0);
 		if (cprops->bwa_wd)
 			comp->cfg[i].mbw_max = GENMASK(15, 16 - cprops->bwa_wd);
+
+		if (mpam_has_quirk(T241_FORCE_MBW_MIN_TO_ONE, class))
+			mpam_wa_t241_force_mbw_min_to_one(&comp->cfg[i],
+							  &class->props);
 	}
 }
 
@@ -2825,6 +2852,18 @@ static void mpam_extend_config(struct mpam_class *class, struct mpam_config *cfg
 	u16 min, min_hw_granule, delta;
 	u16 max_hw_value, res0_bits;
 
+	/*
+	 * Calculate the values the 'min' control can hold.
+	 * e.g. on a platform with bwa_wd = 8, min_hw_granule is 0x00ff because
+	 * those bits are RES0. Configurations of this value are effectively
+	 * zero. But configurations need to saturate at min_hw_granule on
+	 * systems with mismatched bwa_wd, where the 'less than 0' values are
+	 * implemented on some MSC, but not others.
+	 */
+	res0_bits = 16 - cprops->bwa_wd;
+	max_hw_value = ((1 << cprops->bwa_wd) - 1) << res0_bits;
+	min_hw_granule = ~max_hw_value;
+
 	/*
 	 * MAX and MIN should be set together. If only one is provided,
 	 * generate a configuration for the other. If only one control
@@ -2834,19 +2873,6 @@ static void mpam_extend_config(struct mpam_class *class, struct mpam_config *cfg
 	 */
 	if (mpam_has_feature(mpam_feat_mbw_max, cfg) &&
 	    !mpam_has_feature(mpam_feat_mbw_min, cfg)) {
-		/*
-		 * Calculate the values the 'min' control can hold.
-		 * e.g. on a platform with bwa_wd = 8, min_hw_granule is 0x00ff
-		 * because those bits are RES0. Configurations of this value
-		 * are effectively zero. But configurations need to saturate
-		 * at min_hw_granule on systems with mismatched bwa_wd, where
-		 * the 'less than 0' values are implemented on some MSC, but
-		 * not others.
-		 */
-		res0_bits = 16 - cprops->bwa_wd;
-		max_hw_value = ((1 << cprops->bwa_wd) - 1) << res0_bits;
-		min_hw_granule = ~max_hw_value;
-
 		delta = ((5 * MPAMCFG_MBW_MAX_MAX) / 100) - 1;
 		if (cfg->mbw_max > delta)
 			min = cfg->mbw_max - delta;
@@ -2856,6 +2882,12 @@ static void mpam_extend_config(struct mpam_class *class, struct mpam_config *cfg
 		cfg->mbw_min = max(min, min_hw_granule);
 		mpam_set_feature(mpam_feat_mbw_min, cfg);
 	}
+
+	if (mpam_has_quirk(T241_FORCE_MBW_MIN_TO_ONE, class) &&
+	    cfg->mbw_min <= min_hw_granule) {
+		cfg->mbw_min = min_hw_granule + 1;
+		mpam_set_feature(mpam_feat_mbw_min, cfg);
+	}
 }
 
 int mpam_apply_config(struct mpam_component *comp, u16 partid,
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index 70b78cfd1f5b..01882f0acee2 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -223,6 +223,7 @@ struct mpam_props {
 /* Workaround bits for msc->quirks */
 enum mpam_device_quirks {
 	T241_SCRUB_SHADOW_REGS,
+	T241_FORCE_MBW_MIN_TO_ONE,
 	MPAM_QUIRK_LAST,
 };
 
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:57 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:57 +0000
Subject: [RFC PATCH 34/38] arm_mpam: Add quirk framework
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-35-james.morse@arm.com>

From: Shanker Donthineni <sdonthineni at nvidia.com>

The MPAM specification includes the MPAMF_IIDR, which serves to
uniquely identify the MSC implementation through a combination of
implementer details, product ID, variant, and revision. Certain
hardware issues/errata can be resolved using software workarounds.

Introduce a quirk framework to allow workarounds to be enabled based
on the MPAMF_IIDR value.

Signed-off-by: Shanker Donthineni <sdonthineni at nvidia.com>
[ morse: Stash the IIDR so this doesn't need an IPI, enable quirks only
  once, move the description to the callback so it can be pr_once()d, add
  an enum of workarounds for popular errata. Add macros for making lists
  of product/revision/vendor half readable ]
Signed-off-by: James Morse <james.morse at arm.com>
---
 drivers/resctrl/mpam_devices.c  | 27 +++++++++++++++++++++++++++
 drivers/resctrl/mpam_internal.h | 26 ++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)

diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index 741e14e1e6cf..f0f6f9b55ad4 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -630,6 +630,25 @@ static struct mpam_msc_ris *mpam_get_or_create_ris(struct mpam_msc *msc,
 	return ERR_PTR(-ENOENT);
 }
 
+static const struct mpam_quirk mpam_quirks[] = {
+	{ NULL }, /* Sentinel */
+};
+
+static void mpam_enable_quirks(struct mpam_msc *msc)
+{
+	const struct mpam_quirk *quirk;
+
+	for (quirk = &mpam_quirks[0]; quirk->iidr_mask; quirk++) {
+		if (quirk->iidr != (msc->iidr & quirk->iidr_mask))
+			continue;
+
+		if (quirk->init)
+			quirk->init(msc, quirk);
+		else
+			mpam_set_quirk(quirk->workaround, msc);
+	}
+}
+
 /*
  * IHI009A.a has this nugget: "If a monitor does not support automatic behaviour
  * of NRDY, software can use this bit for any purpose" - so hardware might not
@@ -864,8 +883,11 @@ static int mpam_msc_hw_probe(struct mpam_msc *msc)
 	/* Grab an IDR value to find out how many RIS there are */
 	mutex_lock(&msc->part_sel_lock);
 	idr = mpam_msc_read_idr(msc);
+	msc->iidr = mpam_read_partsel_reg(msc, IIDR);
 	mutex_unlock(&msc->part_sel_lock);
 
+	mpam_enable_quirks(msc);
+
 	msc->ris_max = FIELD_GET(MPAMF_IDR_RIS_MAX, idr);
 
 	/* Use these values so partid/pmg always starts with a valid value */
@@ -1987,6 +2009,7 @@ static bool mpam_has_cmax_wd_feature(struct mpam_props *props)
  * resulting safe value must be compatible with both. When merging values in
  * the tree, all the aliasing resources must be handled first.
  * On mismatch, parent is modified.
+ * Quirks on an MSC will apply to all MSC in that class.
  */
 static void __props_mismatch(struct mpam_props *parent,
 			     struct mpam_props *child, bool alias)
@@ -2106,6 +2129,7 @@ static void __props_mismatch(struct mpam_props *parent,
  * nobble the class feature, as we can't configure all the resources.
  * e.g. The L3 cache is composed of two resources with 13 and 17 portion
  * bitmaps respectively.
+ * Quirks on an MSC will apply to all MSC in that class.
  */
 static void
 __class_props_mismatch(struct mpam_class *class, struct mpam_vmsc *vmsc)
@@ -2119,6 +2143,9 @@ __class_props_mismatch(struct mpam_class *class, struct mpam_vmsc *vmsc)
 	dev_dbg(dev, "Merging features for class:0x%lx &= vmsc:0x%lx\n",
 		(long)cprops->features, (long)vprops->features);
 
+	/* Merge quirks */
+	class->quirks |= vmsc->msc->quirks;
+
 	/* Take the safe value for any common features */
 	__props_mismatch(cprops, vprops, false);
 }
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index d381906545ed..de3e5faa12b2 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -88,6 +88,8 @@ struct mpam_msc {
 	u8			pmg_max;
 	unsigned long		ris_idxs;
 	u32			ris_max;
+	u32			iidr;
+	u16			quirks;
 
 	/*
 	 * error_irq_lock is taken when registering/unregistering the error
@@ -215,6 +217,29 @@ struct mpam_props {
 #define mpam_set_feature(_feat, x)	set_bit(_feat, (x)->features)
 #define mpam_clear_feature(_feat, x)	clear_bit(_feat, (x)->features)
 
+/* Workaround bits for msc->quirks */
+enum mpam_device_quirks {
+	MPAM_QUIRK_LAST,
+};
+
+#define mpam_has_quirk(_quirk, x)	((1 << (_quirk) & (x)->quirks))
+#define mpam_set_quirk(_quirk, x)	((x)->quirks |= (1 << (_quirk)))
+
+struct mpam_quirk {
+	void (*init)(struct mpam_msc *msc, const struct mpam_quirk *quirk);
+
+	u32 iidr;
+	u32 iidr_mask;
+
+	enum mpam_device_quirks workaround;
+};
+
+#define MPAM_IIDR_MATCH_ONE	FIELD_PREP_CONST(MPAMF_IIDR_PRODUCTID,   0xfff) | \
+				FIELD_PREP_CONST(MPAMF_IIDR_VARIANT,     0xf  ) | \
+				FIELD_PREP_CONST(MPAMF_IIDR_REVISION,    0xf  ) | \
+				FIELD_PREP_CONST(MPAMF_IIDR_IMPLEMENTER, 0xfff)
+
+
 /* The values for MSMON_CFG_MBWU_FLT.RWBW */
 enum mon_filter_options {
 	COUNT_BOTH	= 0,
@@ -258,6 +283,7 @@ struct mpam_class {
 
 	struct mpam_props	props;
 	u32			nrdy_usec;
+	u16			quirks;
 	u8			level;
 	enum mpam_class_types	type;
 
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:59:01 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:59:01 +0000
Subject: [RFC PATCH 38/38] arm_mpam: Quirk CMN-650's CSU NRDY behaviour
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-39-james.morse@arm.com>

CMN-650 is afflicted with an erratum where the CSU NRDY bit never clears.
This tells us the monitor never finishes scanning the cache. The erratum
document says to wait the maximum time, then ignore the field.

Add a flag to indicate whether this is the final attempt to read the
counter, and when this quirk is applied, ignore the NRDY field.

This means accesses to this counter will always retry, even if the
counter was previously programmed to the same values.

The counter value is not expected to be stable, it drifts up and down
with each allocation and eviction. The CSU register provides the value
for a point in time.

Signed-off-by: James Morse <james.morse at arm.com>
---
 Documentation/arch/arm64/silicon-errata.rst |  3 +++
 drivers/resctrl/mpam_devices.c              | 12 ++++++++++++
 drivers/resctrl/mpam_internal.h             |  5 +++++
 3 files changed, 20 insertions(+)

diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst
index e810b2a8f40e..3667650036fb 100644
--- a/Documentation/arch/arm64/silicon-errata.rst
+++ b/Documentation/arch/arm64/silicon-errata.rst
@@ -213,6 +213,9 @@ stable kernels.
 | ARM            | GIC-700         | #2941627        | ARM64_ERRATUM_2941627       |
 +----------------+-----------------+-----------------+-----------------------------+
 +----------------+-----------------+-----------------+-----------------------------+
+| ARM            | CMN-650         | #3642720        | N/A                         |
++----------------+-----------------+-----------------+-----------------------------+
++----------------+-----------------+-----------------+-----------------------------+
 | Broadcom       | Brahma-B53      | N/A             | ARM64_ERRATUM_845719        |
 +----------------+-----------------+-----------------+-----------------------------+
 | Broadcom       | Brahma-B53      | N/A             | ARM64_ERRATUM_843419        |
diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index c17a6fdea982..174a0224ed62 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -690,6 +690,12 @@ static const struct mpam_quirk mpam_quirks[] = {
 	.iidr_mask  = MPAM_IIDR_MATCH_ONE,
 	.workaround = T241_MBW_COUNTER_SCALE_64,
 	},
+	{
+	/* ARM CMN-650 CSU erratum 3642720 */
+	.iidr       = MPAM_IIDR_ARM_CMN_650,
+	.iidr_mask  = MPAM_IIDR_MATCH_ONE,
+	.workaround = IGNORE_CSU_NRDY,
+	},
 	{ NULL }, /* Sentinel */
 };
 
@@ -997,6 +1003,7 @@ struct mon_read {
 	enum mpam_device_features	type;
 	u64				*val;
 	int				err;
+	bool				waited_timeout;
 };
 
 static bool mpam_ris_has_mbwu_long_counter(struct mpam_msc_ris *ris)
@@ -1242,6 +1249,10 @@ static void __ris_msmon_read(void *arg)
 		if (mpam_has_feature(mpam_feat_msmon_csu_hw_nrdy, rprops))
 			nrdy = now & MSMON___NRDY;
 		now = FIELD_GET(MSMON___VALUE, now);
+
+		if (mpam_has_quirk(IGNORE_CSU_NRDY, msc) && m->waited_timeout)
+			nrdy = false;
+
 		break;
 	case mpam_feat_msmon_mbwu_31counter:
 	case mpam_feat_msmon_mbwu_44counter:
@@ -1377,6 +1388,7 @@ int mpam_msmon_read(struct mpam_component *comp, struct mon_cfg *ctx,
 			.ctx = ctx,
 			.type = type,
 			.val = val,
+			.waited_timeout = true,
 		};
 		*val = 0;
 
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index 108a8373901c..00a61e4277f5 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -225,6 +225,7 @@ enum mpam_device_quirks {
 	T241_SCRUB_SHADOW_REGS,
 	T241_FORCE_MBW_MIN_TO_ONE,
 	T241_MBW_COUNTER_SCALE_64,
+	IGNORE_CSU_NRDY,
 	MPAM_QUIRK_LAST,
 };
 
@@ -250,6 +251,10 @@ struct mpam_quirk {
 				FIELD_PREP_CONST(MPAMF_IIDR_REVISION,    0    ) | \
 				FIELD_PREP_CONST(MPAMF_IIDR_IMPLEMENTER, 0x36b)
 
+#define MPAM_IIDR_ARM_CMN_650   FIELD_PREP_CONST(MPAMF_IIDR_PRODUCTID,   0    ) | \
+				FIELD_PREP_CONST(MPAMF_IIDR_VARIANT,     0    ) | \
+				FIELD_PREP_CONST(MPAMF_IIDR_REVISION,    0    ) | \
+				FIELD_PREP_CONST(MPAMF_IIDR_IMPLEMENTER, 0x43b)
 
 /* The values for MSMON_CFG_MBWU_FLT.RWBW */
 enum mon_filter_options {
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:59:00 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:59:00 +0000
Subject: [RFC PATCH 37/38] arm_mpam: Add workaround for T241-MPAM-6
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-38-james.morse@arm.com>

From: Shanker Donthineni <sdonthineni at nvidia.com>

The registers MSMON_MBWU_L and MSMON_MBWU return the number of
requests rather than the number of bytes transferred.

Bandwidth resource monitoring is performed at the last level cache,
where each request arrive in 64Byte granularity. The current
implementation returns the number of transactions received at the
last level cache but does not provide the value in bytes. Scaling
by 64 gives an accurate byte count to match the MPAM specification
for the MSMON_MBWU and MSMON_MBWU_L registers. This patch fixes
the issue by reporting the actual number of bytes instead of the
number of transactions from __ris_msmon_read().

Signed-off-by: Shanker Donthineni <sdonthineni at nvidia.com>
Signed-off-by: James Morse <james.morse at arm.com>
---
 Documentation/arch/arm64/silicon-errata.rst |  2 ++
 drivers/resctrl/mpam_devices.c              | 24 +++++++++++++++++++--
 drivers/resctrl/mpam_internal.h             |  1 +
 3 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst
index b18bc704d4a1..e810b2a8f40e 100644
--- a/Documentation/arch/arm64/silicon-errata.rst
+++ b/Documentation/arch/arm64/silicon-errata.rst
@@ -250,6 +250,8 @@ stable kernels.
 +----------------+-----------------+-----------------+-----------------------------+
 | NVIDIA         | T241 MPAM       | T241-MPAM-4     | N/A                         |
 +----------------+-----------------+-----------------+-----------------------------+
+| NVIDIA         | T241 MPAM       | T241-MPAM-6     | N/A                         |
++----------------+-----------------+-----------------+-----------------------------+
 +----------------+-----------------+-----------------+-----------------------------+
 | Freescale/NXP  | LS2080A/LS1043A | A-008585        | FSL_ERRATUM_A008585         |
 +----------------+-----------------+-----------------+-----------------------------+
diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index 5ba0aa703807..c17a6fdea982 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -684,6 +684,12 @@ static const struct mpam_quirk mpam_quirks[] = {
 	.iidr_mask  = MPAM_IIDR_MATCH_ONE,
 	.workaround = T241_FORCE_MBW_MIN_TO_ONE,
 	},
+	{
+	/* NVIDIA t241 erratum T241-MPAM-6 */
+	.iidr       = MPAM_IIDR_NVIDIA_T421,
+	.iidr_mask  = MPAM_IIDR_MATCH_ONE,
+	.workaround = T241_MBW_COUNTER_SCALE_64,
+	},
 	{ NULL }, /* Sentinel */
 };
 
@@ -1140,7 +1146,7 @@ static void write_msmon_ctl_flt_vals(struct mon_read *m, u32 ctl_val,
 	}
 }
 
-static u64 mpam_msmon_overflow_val(enum mpam_device_features type)
+static u64 __mpam_msmon_overflow_val(enum mpam_device_features type)
 {
 	/* TODO: implement scaling counters */
 	switch (type) {
@@ -1155,6 +1161,17 @@ static u64 mpam_msmon_overflow_val(enum mpam_device_features type)
 	}
 }
 
+static u64 mpam_msmon_overflow_val(enum mpam_device_features type,
+				   struct mpam_msc *msc)
+{
+	u64 overflow_val = __mpam_msmon_overflow_val(type);
+
+	if (mpam_has_quirk(T241_MBW_COUNTER_SCALE_64, msc))
+		overflow_val *= 64;
+
+	return overflow_val;
+}
+
 static void __ris_msmon_read(void *arg)
 {
 	u64 now;
@@ -1245,13 +1262,16 @@ static void __ris_msmon_read(void *arg)
 			now = FIELD_GET(MSMON___VALUE, now);
 		}
 
+		if (mpam_has_quirk(T241_MBW_COUNTER_SCALE_64, msc))
+			now *= 64;
+
 		if (nrdy)
 			break;
 
 		mbwu_state = &ris->mbwu_state[ctx->mon];
 
 		if (overflow)
-			mbwu_state->correction += mpam_msmon_overflow_val(m->type);
+			mbwu_state->correction += mpam_msmon_overflow_val(m->type, msc);
 
 		/*
 		 * Include bandwidth consumed before the last hardware reset and
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index 01882f0acee2..108a8373901c 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -224,6 +224,7 @@ struct mpam_props {
 enum mpam_device_quirks {
 	T241_SCRUB_SHADOW_REGS,
 	T241_FORCE_MBW_MIN_TO_ONE,
+	T241_MBW_COUNTER_SCALE_64,
 	MPAM_QUIRK_LAST,
 };
 
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:52 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:52 +0000
Subject: [RFC PATCH 29/38] arm_mpam: resctrl: Call resctrl_init() on platforms that can support resctrl
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-30-james.morse@arm.com>

Now that MPAM links against resctrl, call resctrl_init() to register
the filesystem and setup resctrl's strutures.

Signed-off-by: James Morse <james.morse at arm.com>
---
 drivers/resctrl/mpam_resctrl.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 00455de3efe9..eb3caee45470 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -1768,7 +1768,7 @@ int mpam_resctrl_setup(void)
 			pr_warn("Number of PMG is not a power of 2! resctrl may misbehave");
 		}
 
-		/* TODO: call resctrl_init() */
+		err = resctrl_init();
 	}
 
 	return err;
-- 
2.39.5



From james.morse at arm.com  Fri Dec  5 13:58:48 2025
From: james.morse at arm.com (James Morse)
Date: Fri,  5 Dec 2025 21:58:48 +0000
Subject: [RFC PATCH 25/38] arm_mpam: resctrl: Add resctrl_arch_rmid_read() and resctrl_arch_reset_rmid()
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <20251205215901.17772-26-james.morse@arm.com>

resctrl uses resctrl_arch_rmid_read() to read counters. CDP emulation
means the counter may need reading in three different ways. The same
goes for reset.

The helpers behind the resctrl_arch_ functions will be re-used for the
ABMC equivalent functions.

Add the rounding helper for checking monitor values while we're here.

Signed-off-by: James Morse <james.morse at arm.com>
---
 drivers/resctrl/mpam_resctrl.c | 154 +++++++++++++++++++++++++++++++++
 include/linux/arm_mpam.h       |   5 ++
 2 files changed, 159 insertions(+)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index a2b238d47117..dc8a819d0976 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -355,6 +355,160 @@ void resctrl_arch_mon_ctx_free(struct rdt_resource *r,
 	resctrl_arch_mon_ctx_free_no_wait(evtid, mon_idx);
 }
 
+static int
+__read_mon(struct mpam_resctrl_mon *mon, struct mpam_component *mon_comp,
+	   enum mpam_device_features mon_type,
+	   int mon_idx,
+	   enum resctrl_conf_type cdp_type, u32 closid, u32 rmid, u64 *val)
+{
+	struct mon_cfg cfg = { };
+
+	if (!mpam_is_enabled())
+		return -EINVAL;
+
+	/* Shift closid to account for CDP */
+	closid = resctrl_get_config_index(closid, cdp_type);
+
+	if (mon_idx == USE_PRE_ALLOCATED) {
+		int mbwu_idx = resctrl_arch_rmid_idx_encode(closid, rmid);
+		mon_idx = mon->mbwu_idx_to_mon[mbwu_idx];
+		if (mon_idx == -1) {
+			if (mpam_resctrl_abmc_enabled()) {
+				/* Report Unassigned */
+				return -ENOENT;
+			}
+			/* Report Unavailable */
+			return -EINVAL;
+		}
+	}
+
+	cfg.mon = mon_idx;
+	cfg.match_pmg = true;
+	cfg.partid = closid;
+	cfg.pmg = rmid;
+
+	if (irqs_disabled()) {
+		/* Check if we can access this domain without an IPI */
+		return -EIO;
+	}
+
+	return mpam_msmon_read(mon_comp, &cfg, mon_type, val);
+}
+
+static int read_mon_cdp_safe(struct mpam_resctrl_mon *mon, struct mpam_component *mon_comp,
+			     enum mpam_device_features mon_type,
+			     int mon_idx, u32 closid, u32 rmid, u64 *val)
+{
+	if (cdp_enabled) {
+		u64 code_val = 0, data_val = 0;
+		int err;
+
+		err = __read_mon(mon, mon_comp, mon_type, mon_idx,
+				 CDP_CODE, closid, rmid, &code_val);
+		if (err)
+			return err;
+
+		err = __read_mon(mon, mon_comp, mon_type, mon_idx,
+				 CDP_DATA, closid, rmid, &data_val);
+		if (!err)
+			*val += code_val + data_val;
+		return err;
+	}
+
+	return __read_mon(mon, mon_comp, mon_type, mon_idx,
+			  CDP_NONE, closid, rmid, val);
+}
+
+/* MBWU when not in ABMC mode, and CSU counters. */
+int resctrl_arch_rmid_read(struct rdt_resource	*r, struct rdt_mon_domain *d,
+			   u32 closid, u32 rmid, enum resctrl_event_id eventid,
+			   u64 *val, void *arch_mon_ctx)
+{
+	struct mpam_resctrl_dom *l3_dom;
+	struct mpam_component *mon_comp;
+	u32 mon_idx = *(u32 *)arch_mon_ctx;
+	enum mpam_device_features mon_type;
+	struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[eventid];
+
+	resctrl_arch_rmid_read_context_check();
+
+	if (eventid >= QOS_NUM_EVENTS || !mon->class)
+		return -EINVAL;
+
+	l3_dom = container_of(d, struct mpam_resctrl_dom, resctrl_mon_dom);
+	mon_comp = l3_dom->mon_comp[eventid];
+
+	switch (eventid) {
+	case QOS_L3_OCCUP_EVENT_ID:
+		mon_type = mpam_feat_msmon_csu;
+		break;
+	case QOS_L3_MBM_LOCAL_EVENT_ID:
+	case QOS_L3_MBM_TOTAL_EVENT_ID:
+		mon_type = mpam_feat_msmon_mbwu;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return read_mon_cdp_safe(mon, mon_comp, mon_type, mon_idx,
+				 closid, rmid, val);
+}
+
+static void __reset_mon(struct mpam_resctrl_mon *mon, struct mpam_component *mon_comp,
+			int mon_idx,
+			enum resctrl_conf_type cdp_type, u32 closid, u32 rmid)
+{
+	struct mon_cfg cfg = { };
+
+	if (!mpam_is_enabled())
+		return;
+
+	/* Shift closid to account for CDP */
+	closid = resctrl_get_config_index(closid, cdp_type);
+
+	if (mon_idx == USE_PRE_ALLOCATED) {
+		int mbwu_idx = resctrl_arch_rmid_idx_encode(closid, rmid);
+		mon_idx = mon->mbwu_idx_to_mon[mbwu_idx];
+	}
+
+	if (mon_idx == -1)
+		return;
+	cfg.mon = mon_idx;
+	mpam_msmon_reset_mbwu(mon_comp, &cfg);
+}
+
+static void reset_mon_cdp_safe(struct mpam_resctrl_mon *mon, struct mpam_component *mon_comp,
+			       int mon_idx, u32 closid, u32 rmid)
+{
+	if (cdp_enabled) {
+		__reset_mon(mon, mon_comp, mon_idx, CDP_CODE, closid, rmid);
+		__reset_mon(mon, mon_comp, mon_idx, CDP_DATA, closid, rmid);
+	} else {
+		__reset_mon(mon, mon_comp, mon_idx, CDP_NONE, closid, rmid);
+	}
+}
+
+/* Called via IPI. Call with read_cpus_lock() held. */
+void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_mon_domain *d,
+			     u32 closid, u32 rmid, enum resctrl_event_id eventid)
+{
+	struct mpam_resctrl_dom *l3_dom;
+	struct mpam_component *mon_comp;
+	struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[eventid];
+
+	if (!mpam_is_enabled())
+		return;
+
+	/* Only MBWU counters are relevant, and for supported event types. */
+	if (eventid == QOS_L3_OCCUP_EVENT_ID || !mon->class)
+		return;
+
+	l3_dom = container_of(d, struct mpam_resctrl_dom, resctrl_mon_dom);
+	mon_comp = l3_dom->mon_comp[eventid];
+
+	reset_mon_cdp_safe(mon, mon_comp, USE_PRE_ALLOCATED, closid, rmid);
+}
+
 static bool cache_has_usable_cpor(struct mpam_class *class)
 {
 	struct mpam_props *cprops = &class->props;
diff --git a/include/linux/arm_mpam.h b/include/linux/arm_mpam.h
index e1461e32af75..86d5e326d2bd 100644
--- a/include/linux/arm_mpam.h
+++ b/include/linux/arm_mpam.h
@@ -67,6 +67,11 @@ struct rdt_resource;
 void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r, enum resctrl_event_id evtid);
 void resctrl_arch_mon_ctx_free(struct rdt_resource *r, enum resctrl_event_id evtid, void *ctx);
 
+static inline unsigned int resctrl_arch_round_mon_val(unsigned int val)
+{
+	return val;
+}
+
 /**
  * mpam_register_requestor() - Register a requestor with the MPAM driver
  * @partid_max:		The maximum PARTID value the requestor can generate.
-- 
2.39.5



From robh at kernel.org  Fri Dec  5 14:36:37 2025
From: robh at kernel.org (Rob Herring)
Date: Fri, 05 Dec 2025 16:36:37 -0600
Subject: [PATCH 0/4] Add support for the Mediatek Genio 520-EVK and
 720-EVK boards
In-Reply-To: <20251203-add-mediatek-genio-520-720-evk-v1-0-df794b2a30ae@collabora.com>
References: <20251203-add-mediatek-genio-520-720-evk-v1-0-df794b2a30ae@collabora.com>
Message-ID: <176497381380.863373.5448430069012667069.robh@kernel.org>


On Wed, 03 Dec 2025 14:59:25 +0100, Louis-Alexis Eyraud wrote:
> This patch series adds the support for the Mediatek Genio 520-EVK (based
> on MT8371 SoC) and Mediatek Genio 720-EVK (based on MT8391 SoC).
> 
> MT8371 and MT8391 SoC are less powerful variants of MT8189 SoC
> with the following differences:
>   - Arm Cortex-A78 CPU core maximum frequency (2.2 Ghz for MT8371, 2.6
>     Ghz for MT8391, 3 Ghz for MT8189).
>   - Arm Mali G57 MC2 GPU core maximum frequency (880 Mhz for MT8371,
>     1.1 Ghz for MT8189 and MT8391)
>   - ISP engine number (1 for MT8371, 2 for MT8189 and MT8391)
> MT8371 and MT8391 SoC hardware register maps are identical to MT8189.
> 
> The Genio 520/720-EVK boards have following features:
>   - MT8371 (or MT8391) SoC
>   - MT6365 PMIC
>   - MT6319 Buck IC
>   - MT6375 Charger IC
>   - 8GB LPDDR5 RAM
>   - 64GB eMMC 5.1
>   - 128GB UFS
>   - 20V DC Jack
>   - USB Type-C Power Adapter
>   - Micro SD card slot
>   - Push Button x 4 (Power, Reset, Download and Home Key)
>   - LED x 3 (System Power, Reset, DC-IN Power)
>   - USB Type-C Connector (USB 3.2) x 2
>   - USB Type-C Connector (USB 2.0) x 1
>   - 3.5mm Earphone Jack x 1 (with Microphone Input)
>   - 3.5mm Line Out Audio Jack x 1
>   - Analog Microphone x 1
>   - Digital Microphone x 2
>   - Gigabit Ethernet with RJ45 connector
>   - DP x 1 (Mode over USB Type-C)
>   - LVDS port x 1
>   - eDP port x 1
>   - UART x2 with serial-to-usb converters and USB Type-C connectors
>   - UART Port x 2 on Pin Header
>   - M.2 Slot x 2
>   - I2C Capacitive Touch Pad
>   - 4-Lane DSI x 1
>   - 4-Data Lane CSI x 2
>   - I2S Pin header
>   - 40-Pin 2.54mm Pin Header x 1
>   - CAN Bus x 1 (RS232 Connector)
> 
> The series adds two include files for mt8189 (mt8189.dtsi) and common
> board definitions (mt8391-genio-common.dtsi) and a devicetree file for
> each board. In regard to the current MT8189 SoC upstream support and in
> order to limit the number of prerequisite patches, this series provides
> the following basic hardware enablement for:
>   - cpu
>   - clocks
>   - spmi and regulators
>   - UART 0/1/2/3
>   - eMMC and SD card
>   - watchdog
>   - timer
>   - efuse and socinfo
>   - auxadc
> 
> The series is based on linux-next next-20251203 tag, and the
> following patch series are currently required:
> - I2C dt-bindings [1]
> - SPMI dt-bindings [2]
> - timer dt-bindings [3]
> - Add support for MT8189 clock/power controller [4]
> - Add SD/MMC Card driver support for Mediatek MT8189 SoC [5]
> - mt8189: Add pinmux macro header file [6]
> 
> Note:
> The v3 revision of [4] patch series is causing the following `make dtbs_check`
> issue for both board devicetrees:
> ```
> arch/arm64/boot/dts/mediatek/mt8391-genio-720-evk.dtb: /soc/clock-controller at 1c000800:
>   failed to match any schema with compatible: ['mediatek,mt8189-vlp-ao', 'syscon']
> ```
> The mismatch between compatible string in driver and dt-bindings has
> already been reported during the series review ([7]) and hopefully will be
> fixed in its future revision.
> 
> [1] https://lore.kernel.org/linux-mediatek/20251030-mt8189-dt-bindings-i2c-v1-1-5b60914c6453 at collabora.com/
> [2] https://lore.kernel.org/linux-mediatek/20251029-mt8189-dt-bindings-spmi-v1-1-fbea12a4ed5e at collabora.com/
> [3] https://lore.kernel.org/linux-mediatek/20250825033136.7705-1-zhanzhan.ge at mediatek.com/
> [4] https://lore.kernel.org/linux-mediatek/20251106124330.1145600-1-irving-ch.lin at mediatek.com/
> [5] https://lore.kernel.org/linux-mediatek/20251203-mt8189-add-mmc-support-v1-0-f5ce43212fe9 at collabora.com/
> [6] https://lore.kernel.org/linux-mediatek/20250919020525.7904-1-ot_cathy.xu at mediatek.com/
> [7] https://lore.kernel.org/linux-mediatek/a50e6d433afcf8b08a47694bc5a52acc28871ee5.camel at collabora.com/
> 
> Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
> ---
> Louis-Alexis Eyraud (4):
>       dt-bindings: serial: mediatek,uart: Add compatible for MT8189 SoC
>       dt-bindings: arm: mediatek: add compatibles for Mediatek Genio 520/720-EVK boards
>       arm64: dts: mediatek: add device-tree for Genio 720-EVK board
>       arm64: dts: mediatek: add device-tree for Genio 520-EVK board
> 
>  .../devicetree/bindings/arm/mediatek.yaml          |  10 +
>  .../devicetree/bindings/serial/mediatek,uart.yaml  |   1 +
>  arch/arm64/boot/dts/mediatek/Makefile              |   2 +
>  arch/arm64/boot/dts/mediatek/mt8189.dtsi           | 860 +++++++++++++++++++++
>  .../boot/dts/mediatek/mt8371-genio-520-evk.dts     |  19 +
>  .../boot/dts/mediatek/mt8391-genio-720-evk.dts     |  15 +
>  .../boot/dts/mediatek/mt8391-genio-common.dtsi     | 555 +++++++++++++
>  7 files changed, 1462 insertions(+)
> ---
> base-commit: e47d97576181b31291cf58e77d737d21def0e160
> change-id: 20251128-add-mediatek-genio-520-720-evk-06162377974d
> prerequisite-message-id: <20251030-mt8189-dt-bindings-i2c-v1-1-5b60914c6453 at collabora.com>
> prerequisite-patch-id: af92e103b9f50af16560a11d4eabc644bd724b07
> prerequisite-message-id: <20251029-mt8189-dt-bindings-spmi-v1-1-fbea12a4ed5e at collabora.com>
> prerequisite-patch-id: c82ad0d3145322fea43aed2e1d830ebc8eae8180
> prerequisite-message-id: <20250825033136.7705-1-zhanzhan.ge at mediatek.com>
> prerequisite-patch-id: 7aeee7d452186b3bc1c11722b7ddb7dfbae7d396
> prerequisite-message-id: <20251106124330.1145600-1-irving-ch.lin at mediatek.com>
> prerequisite-patch-id: ea3e5cf891c9753a77f126ad1ddad455a0752883
> prerequisite-patch-id: ae9a4cb1daadb56cc298b87142b29b749dc11835
> prerequisite-patch-id: 3df47b0207d75102032975e6811f71a5e7909e43
> prerequisite-patch-id: 1c25a1327d50152cef227f58c08076072d65cee3
> prerequisite-patch-id: f2cd301aea79253adb85bd3f62c012dd3850e1a7
> prerequisite-patch-id: 81dc09321182c48f6928582e8b9d22f35a757515
> prerequisite-patch-id: e0a251231fd14fa582800db8f3bb77011f6836f9
> prerequisite-patch-id: da7c54c83cb8566df39beac753c80615523479e5
> prerequisite-patch-id: 2f3d41e32b230ddc016fd75ace5b286cd11b2127
> prerequisite-patch-id: 309f350ed5c942b640b5c3434737fee28d6825b0
> prerequisite-patch-id: 7579b6db7ec7a31e28db616c73b4c1b0eb4ee106
> prerequisite-patch-id: 0cdea5380c8d35cfd89e01bf843ef7fdafbc7830
> prerequisite-patch-id: 3dc3e377981d3c894fc39122200a0f0d46f5d71b
> prerequisite-patch-id: b57bf39e50a5316d2f9264e1eb89071d3e8e8b0a
> prerequisite-patch-id: 56fd80d33667839823794173064860c613f911cd
> prerequisite-patch-id: 963a3ed54fb5fd9fd518f28254eaf93a70b2f603
> prerequisite-patch-id: 3c9cbc33093f754d867ca324cc7e689fbbaae8af
> prerequisite-patch-id: 336ba35d1924706d1d21c6e46718d973277f207a
> prerequisite-patch-id: f3322d6494603585fc4728074484055d07484dd6
> prerequisite-patch-id: f5a70e41fe9df7df0ab29538701bdfdb401a9d01
> prerequisite-patch-id: b46a91afc38bea2ee6a8440f59e71e39728df6ad
> prerequisite-message-id: <20251203-mt8189-add-mmc-support-v1-0-f5ce43212fe9 at collabora.com>
> prerequisite-patch-id: feab935ed7d0d7234dcc1980185300782c61620e
> prerequisite-patch-id: efbd41a9926397f9b3ffd19235a04791b61f35c7
> prerequisite-patch-id: 5b12a1056dfe87e4d39af584d8b16c31a1a00a04
> prerequisite-message-id: <20250919020525.7904-1-ot_cathy.xu at mediatek.com>
> prerequisite-patch-id: 7f2d960cde2f0e0a307721150e83b7b05b9a60d7
> 
> Best regards,
> --
> Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
> 
> 
> 


My bot found new DTB warnings on the .dts files added or changed in this
series.

Some warnings may be from an existing SoC .dtsi. Or perhaps the warnings
are fixed by another series. Ultimately, it is up to the platform
maintainer whether these warnings are acceptable or not. No need to reply
unless the platform maintainer has comments.

If you already ran DT checks and didn't see these error(s), then
make sure dt-schema is up to date:

  pip3 install dtschema --upgrade


This patch series was applied (using b4) to base:
 Deps: looking for dependencies matching 28 patch-ids
 Deps: Applying prerequisite patch: [PATCH] dt-bindings: i2c: i2c-mt65xx: Add compatible for MT8189 SoC
 Deps: Applying prerequisite patch: [PATCH] dt-bindings: spmi: spmi-mtk-pmif: Add compatible for MT8189 SoC
 Deps: Applying prerequisite patch: [PATCH v7 4/9] dt-bindings: timer: Support MediaTek MT8189 timer
 Deps: Applying prerequisite patch: [PATCH v3 01/21] dt-bindings: clock: mediatek: Add MT8189 clock definitions
 Deps: Applying prerequisite patch: [PATCH v3 02/21] dt-bindings: power: mediatek: Add MT8189 power domain definitions
 Deps: Applying prerequisite patch: [PATCH v3 03/21] clk: mediatek: fix mfg mux issue
 Deps: Applying prerequisite patch: [PATCH v3 04/21] clk: mediatek: Add MT8189 apmixedsys clock support
 Deps: Applying prerequisite patch: [PATCH v3 05/21] clk: mediatek: Add MT8189 topckgen clock support
 Deps: Applying prerequisite patch: [PATCH v3 06/21] clk: mediatek: Add MT8189 vlpckgen clock support
 Deps: Applying prerequisite patch: [PATCH v3 07/21] clk: mediatek: Add MT8189 vlpcfg clock support
 Deps: Applying prerequisite patch: [PATCH v3 08/21] clk: mediatek: Add MT8189 bus clock support
 Deps: Applying prerequisite patch: [PATCH v3 09/21] clk: mediatek: Add MT8189 cam clock support
 Deps: Applying prerequisite patch: [PATCH v3 10/21] clk: mediatek: Add MT8189 dbgao clock support
 Deps: Applying prerequisite patch: [PATCH v3 11/21] clk: mediatek: Add MT8189 dvfsrc clock support
 Deps: Applying prerequisite patch: [PATCH v3 12/21] clk: mediatek: Add MT8189 i2c clock support
 Deps: Applying prerequisite patch: [PATCH v3 13/21] clk: mediatek: Add MT8189 img clock support
 Deps: Applying prerequisite patch: [PATCH v3 14/21] clk: mediatek: Add MT8189 mdp clock support
 Deps: Applying prerequisite patch: [PATCH v3 15/21] clk: mediatek: Add MT8189 mfg clock support
 Deps: Applying prerequisite patch: [PATCH v3 16/21] clk: mediatek: Add MT8189 mmsys clock support
 Deps: Applying prerequisite patch: [PATCH v3 17/21] clk: mediatek: Add MT8189 scp clock support
 Deps: Applying prerequisite patch: [PATCH v3 18/21] clk: mediatek: Add MT8189 ufs clock support
 Deps: Applying prerequisite patch: [PATCH v3 19/21] clk: mediatek: Add MT8189 vcodec clock support
 Deps: Applying prerequisite patch: [PATCH v3 20/21] pmdomain: mediatek: Add bus protect control flow for MT8189
 Deps: Applying prerequisite patch: [PATCH v3 21/21] pmdomain: mediatek: Add power domain driver for MT8189 SoC
 Deps: Applying prerequisite patch: [PATCH 1/3] dt-bindings: mmc: mtk-sd: Add support for MT8189 SoC
 Deps: Applying prerequisite patch: [PATCH 2/3] mmc: mtk-sd: add support for SPM resource release control
 Deps: Applying prerequisite patch: [PATCH 3/3] mmc: mtk-sd: add support for MT8189 SoC
 Deps: Applying prerequisite patch: [PATCH v2] arm64: dts: mediatek: mt8189: Add pinmux macro header file
 Base: e47d97576181b31291cf58e77d737d21def0e160 (use --merge-base to override)

If this is not the correct base, please add 'base-commit' tag
(or use b4 which does this automatically)

New warnings running 'make CHECK_DTBS=y for arch/arm64/boot/dts/mediatek/' for 20251203-add-mediatek-genio-520-720-evk-v1-0-df794b2a30ae at collabora.com:

arch/arm64/boot/dts/mediatek/mt8371-genio-520-evk.dtb: /soc/clock-controller at 1c000800: failed to match any schema with compatible: ['mediatek,mt8189-vlp-ao', 'syscon']
arch/arm64/boot/dts/mediatek/mt8371-genio-520-evk.dtb: pmic (mediatek,mt6359): '#sound-dai-cells' does not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/mfd/mediatek,mt6397.yaml
arch/arm64/boot/dts/mediatek/mt8391-genio-720-evk.dtb: /soc/clock-controller at 1c000800: failed to match any schema with compatible: ['mediatek,mt8189-vlp-ao', 'syscon']
arch/arm64/boot/dts/mediatek/mt8391-genio-720-evk.dtb: pmic (mediatek,mt6359): '#sound-dai-cells' does not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/mfd/mediatek,mt6397.yaml







From robh at kernel.org  Fri Dec  5 14:36:42 2025
From: robh at kernel.org (Rob Herring)
Date: Fri, 05 Dec 2025 16:36:42 -0600
Subject: [PATCH v2 00/22] media: platform: rga: Add RGA3 support
In-Reply-To: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
Message-ID: <176497381501.863435.1795850437776571533.robh@kernel.org>


On Wed, 03 Dec 2025 16:52:22 +0100, Sven P?schel wrote:
> This series adds support for the Raster Graphic Acceleration 3 (RGA3)
> peripheral, which is included in the RK3588 SoC. The RK3588
> contains one RGA2 core (which is already implemented by the rockchip rga
> driver) and two independent RGA3 cores. RGA2 and RGA3 feature
> a similar functionality of scaling, cropping and rotating of up to two input
> images into one output image. Key differences of the RGA3 are:
> 
> - supports 10bit YUV output formats
> - supports 8x8 tiles and FBCD as inputs and outputs
> - supports BT2020 color space conversion
> - max output resolution of (8192-64)x(8192-64)
> - MMU can map up to 32G DDR RAM
> - fully planar formats (3 planes) are not supported
> - max scale up/down factor of 8
> 
> This patch set adds support for one RGA3 core in the existing
> rga m2m driver. The feature set of the PR is limited to scaling and
> format conversions between common 8bit RGB/YUV formats.
> Also the color space conversion is fixed to BT601F.
> This already allows a practical usage of the RGA3.
> 
> This was tested on a Radxa Rock 5T. Around 80 fps were measured when
> scaling and converting from RGBA 480x360 to NV12 3840x2160 in a single
> gstreamer pipeline. Format conversions were tested with a single
> gstreamer pipeline converting a fixed input to a given input format.
> Afterwards it's piped through the RGA3 and the result is converted back
> to rgba and compared against a given hash value (generated after
> comparing the output manually to the input).
> 
> The v4l2-compliance tests still complain about
> the failing colorspace propagation for the RGA2.
> For the RGA3 they complain about the ycbcr_enc
> not being adopted with S_FMT, which is by design,
> as the RGA3 currently has the BT601 full range
> transfer hard coded:
> 
>   v4l2-compliance 1.28.1, 64 bits, 64-bit time_t
>   ...
>   	Card type        : rga2
>   ...
>   		fail: v4l2-test-formats.cpp(923): fmt_cap.g_colorspace() != col
>   	test VIDIOC_S_FMT: FAIL
>   ...
>   Total for rockchip-rga device /dev/video0: 47, Succeeded: 46, Failed: 1, Warnings: 0
> 
>   v4l2-compliance 1.28.1, 64 bits, 64-bit time_t
>   ...
>   	Card type        : rga3
>   ...
>   		fail: v4l2-test-formats.cpp(920): fmt_out.g_ycbcr_enc() != ycbcr_enc
>   	test VIDIOC_S_FMT: FAIL
>   ...
>   Total for rockchip-rga device /dev/video1: 47, Succeeded: 46, Failed: 1, Warnings: 0
> 
> To distinguish the RGA2 core from the RGA3 cores the Card type is set
> accordingly. Scheduling operations between both RGA3 cores to double
> the possible frame rate might be a future improvement. Until then
> additional RGA3 cores are disabled to only provide one video device to
> the user space. This prevents a potential ABI breakage when multi core
> support is implemented.
> 
> The DTS change at the end is just as a preview, as this series targets
> media/next. After it's merged the DTS change will be sent as a new
> patch not targeting media.
> 
> Patch 1 documments the RGA3 compatible value
> Patch 2-3 extend v4l2 common functionality
> Patch 4-6 are general cleanups
> Patch 7-20 prepare the rga driver for the RGA3
> Patch 21 adds RGA3 support to the rga driver
> Patch 22 dtsi additions for the RGA3
> 
> Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
> ---
> Changes in v2:
> - Removed overclocking (assigning higher clock speeds in the dts)
> - Disable the second RGA3 core
> - Improved RGA3 feature documentation and code comments
> - Don't write the whole command buffer in each frame
> - Don't announce CIDs for the RGA3 and error out on s_selection
> - Check the max scaling factor of 16 (RGA2) and 8 (RGA3)
> - Move stride alignment and alpha checking to v4l2 common
> - Register the interrupt as shared for an external IOMMU
> - Add IOMMU patch as dependency to fix sporadic hangups
> - Link to v1: https://lore.kernel.org/r/20251007-spu-rga3-v1-0-36ad85570402 at pengutronix.de
> 
> ---
> Michael Olbrich (1):
>       media: rockchip: rga: share the interrupt when an external iommu is used
> 
> Sven P?schel (21):
>       media: dt-bindings: media: rockchip-rga: add rockchip,rk3588-rga3
>       media: v4l2-common: add has_alpha to v4l2_format_info
>       media: v4l2-common: add v4l2_fill_pixfmt_mp_aligned helper
>       media: rockchip: rga: use clk_bulk api
>       media: rockchip: rga: use stride for offset calculation
>       media: rockchip: rga: remove redundant rga_frame variables
>       media: rockchip: rga: move hw specific parts to a dedicated struct
>       media: rockchip: rga: move cmdbuf to rga_ctx
>       media: rockchip: rga: align stride to 4 bytes
>       media: rockchip: rga: prepare cmdbuf on streamon
>       media: rockchip: rga: check scaling factor
>       media: rockchip: rga: use card type to specify rga type
>       media: rockchip: rga: change offset to dma_addresses
>       media: rockchip: rga: support external iommus
>       media: rockchip: rga: remove size from rga_frame
>       media: rockchip: rga: remove stride from rga_frame
>       media: rockchip: rga: move rga_fmt to rga-hw.h
>       media: rockchip: rga: add feature flags
>       media: rockchip: rga: disable multi-core support
>       media: rockchip: rga: add rga3 support
>       arm64: dts: rockchip: add rga3 dt nodes
> 
>  .../devicetree/bindings/media/rockchip-rga.yaml    |   5 +-
>  arch/arm64/boot/dts/rockchip/rk3588-base.dtsi      |  46 ++
>  drivers/media/platform/rockchip/rga/Makefile       |   2 +-
>  drivers/media/platform/rockchip/rga/rga-buf.c      |  78 ++--
>  drivers/media/platform/rockchip/rga/rga-hw.c       | 404 ++++++++++++----
>  drivers/media/platform/rockchip/rga/rga-hw.h       |  18 +-
>  drivers/media/platform/rockchip/rga/rga.c          | 518 ++++++++-------------
>  drivers/media/platform/rockchip/rga/rga.h          |  82 ++--
>  drivers/media/platform/rockchip/rga/rga3-hw.c      | 471 +++++++++++++++++++
>  drivers/media/platform/rockchip/rga/rga3-hw.h      | 190 ++++++++
>  drivers/media/v4l2-core/v4l2-common.c              |  48 +-
>  include/media/v4l2-common.h                        |   6 +
>  12 files changed, 1375 insertions(+), 493 deletions(-)
> ---
> base-commit: 1f2353f5a1af995efbf7bea44341aa0d03460b28
> change-id: 20251001-spu-rga3-8a00e018b120
> prerequisite-change-id: 20251126-spu-iommudtefix-cd0c5244c74a:v1
> prerequisite-patch-id: 10c6c977c0f71400931941b42da73adcaf63e810
> 
> Best regards,
> --
> Sven P?schel <s.pueschel at pengutronix.de>
> 
> 
> 


My bot found new DTB warnings on the .dts files added or changed in this
series.

Some warnings may be from an existing SoC .dtsi. Or perhaps the warnings
are fixed by another series. Ultimately, it is up to the platform
maintainer whether these warnings are acceptable or not. No need to reply
unless the platform maintainer has comments.

If you already ran DT checks and didn't see these error(s), then
make sure dt-schema is up to date:

  pip3 install dtschema --upgrade


This patch series was applied (using b4) to base:
 Deps: looking for dependencies matching 1 patch-ids
 Deps: Applying prerequisite patch: [PATCH] iommu/rockchip: disable fetch dte time limit
 Base: 1f2353f5a1af995efbf7bea44341aa0d03460b28 (use --merge-base to override)

If this is not the correct base, please add 'base-commit' tag
(or use b4 which does this automatically)

New warnings running 'make CHECK_DTBS=y for arch/arm64/boot/dts/rockchip/' for 20251203-spu-rga3-v2-0-989a67947f71 at pengutronix.de:

arch/arm64/boot/dts/rockchip/rk3588s-odroid-m2.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-odroid-m2.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-genbook.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-genbook.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5b.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5b.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-roc-rt.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-roc-rt.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-h96-max-v58.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-h96-max-v58.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-armsom-w3.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-armsom-w3.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-ultra.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-ultra.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-jaguar.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-jaguar.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6b-io.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6b-io.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-ok3588-c.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-ok3588-c.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-tiger-haikou.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-tiger-haikou.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3582-radxa-e52c.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3582-radxa-e52c.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-rock-5b-plus.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-rock-5b-plus.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-coolpi-4b.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-coolpi-4b.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-toybrick-x0.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-toybrick-x0.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-io.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-io.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-rock-5-itx.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-rock-5-itx.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-evb1-v10.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-evb1-v10.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-turing-rk1.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-turing-rk1.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-mnt-reform2.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-mnt-reform2.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6-lts.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6-lts.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6c.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6c.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-max.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-max.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6s.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6s.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-rock-5c.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-rock-5c.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-firefly-itx-3588j.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-firefly-itx-3588j.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-evb2-v10.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-evb2-v10.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-roc-pc.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-roc-pc.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-evb.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-evb.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dtb: rga at fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dtb: rga at fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml







From robh at kernel.org  Fri Dec  5 14:36:40 2025
From: robh at kernel.org (Rob Herring)
Date: Fri, 05 Dec 2025 16:36:40 -0600
Subject: [PATCH v5 0/5] Add support for Ezurio MediaTek platforms
In-Reply-To: <20251203-review-v5-0-b26d5512c6af@gmail.com>
References: <20251203-review-v5-0-b26d5512c6af@gmail.com>
Message-ID: <176497381428.863411.12977178737118474815.robh@kernel.org>


On Wed, 03 Dec 2025 22:20:36 +0100, Gary Bisson wrote:
> This series adds support for Ezurio MediaTek platforms called
> "Tungsten". It includes support for MT8370-based Tungsten 510 and
> MT8390-based Tungsten 700 SOMs.
> 
> Changes in v2:
> - Use b4 to cc all maintainers properly
> - Squashed patches 2/3 together
> - Updated dts node names to be generic
> 
> Changes in v3:
> - Added per-commit changelog
> - Added missing Acked-by on 1st patch
> - Link to v2: https://lore.kernel.org/r/20251201-review-v2-0-dc2df44eec7e at gmail.com
> 
> Changes in v4:
> - Fixed remaining DTB warnings
> - Link to v3: https://lore.kernel.org/r/20251201-review-v3-0-07f9af7341fd at gmail.com
> 
> Changes in v5:
> - Fixed DTB per Angelo's comments
> - Added a MT8188 patch for easier mmc eint interrupt change
> - Link to v4: https://lore.kernel.org/r/20251202-review-v4-0-93f5cd2a0d4a at gmail.com
> 
> Regards,
> 
> Gary Bisson (5):
>   dt-bindings: vendor-prefixes: Add Ezurio LLC
>   dt-bindings: arm: mediatek: Add Ezurio Tungsten entries
>   arm64: dts: mediatek: mt8188: switch mmc nodes to interrupts-extended
>   arm64: dts: mediatek: add device tree for Tungsten 510 board
>   arm64: dts: mediatek: add device tree for Tungsten 700 board
> 
>  .../devicetree/bindings/arm/mediatek.yaml     |    2 +
>  .../devicetree/bindings/vendor-prefixes.yaml  |    2 +
>  arch/arm64/boot/dts/mediatek/Makefile         |    2 +
>  arch/arm64/boot/dts/mediatek/mt8188.dtsi      |    6 +-
>  .../dts/mediatek/mt8370-tungsten-smarc.dts    |   14 +
>  .../dts/mediatek/mt8390-tungsten-smarc.dts    |   22 +
>  .../dts/mediatek/mt8390-tungsten-smarc.dtsi   | 1489 +++++++++++++++++
>  7 files changed, 1534 insertions(+), 3 deletions(-)
>  create mode 100644 arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dts
>  create mode 100644 arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dts
>  create mode 100644 arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtsi
> 
> --
> 2.43.0
> 
> ---
> To: Rob Herring <robh at kernel.org>
> To: Krzysztof Kozlowski <krzk+dt at kernel.org>
> To: Conor Dooley <conor+dt at kernel.org>
> To: Matthias Brugger <matthias.bgg at gmail.com>
> To: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
> To: Sean Wang <sean.wang at mediatek.com>
> Cc: devicetree at vger.kernel.org
> Cc: linux-kernel at vger.kernel.org
> Cc: linux-arm-kernel at lists.infradead.org
> Cc: linux-mediatek at lists.infradead.org
> 
> ---
> Gary Bisson (5):
>       dt-bindings: vendor-prefixes: Add Ezurio LLC
>       dt-bindings: arm: mediatek: Add Ezurio Tungsten entries
>       arm64: dts: mediatek: mt8188: switch mmc nodes to interrupts-extended
>       arm64: dts: mediatek: add device tree for Tungsten 510 board
>       arm64: dts: mediatek: add device tree for Tungsten 700 board
> 
>  .../devicetree/bindings/arm/mediatek.yaml          |    2 +
>  .../devicetree/bindings/vendor-prefixes.yaml       |    2 +
>  arch/arm64/boot/dts/mediatek/Makefile              |    2 +
>  arch/arm64/boot/dts/mediatek/mt8188.dtsi           |    6 +-
>  .../boot/dts/mediatek/mt8370-tungsten-smarc.dts    |   14 +
>  .../boot/dts/mediatek/mt8390-tungsten-smarc.dts    |   22 +
>  .../boot/dts/mediatek/mt8390-tungsten-smarc.dtsi   | 1489 ++++++++++++++++++++
>  7 files changed, 1534 insertions(+), 3 deletions(-)
> ---
> base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
> change-id: 20251201-review-750072579991
> 
> Best regards,
> --
> Gary Bisson <bisson.gary at gmail.com>
> 
> 
> 


My bot found new DTB warnings on the .dts files added or changed in this
series.

Some warnings may be from an existing SoC .dtsi. Or perhaps the warnings
are fixed by another series. Ultimately, it is up to the platform
maintainer whether these warnings are acceptable or not. No need to reply
unless the platform maintainer has comments.

If you already ran DT checks and didn't see these error(s), then
make sure dt-schema is up to date:

  pip3 install dtschema --upgrade


This patch series was applied (using b4) to base:
 Base: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449 (use --merge-base to override)

If this is not the correct base, please add 'base-commit' tag
(or use b4 which does this automatically)

New warnings running 'make CHECK_DTBS=y for arch/arm64/boot/dts/mediatek/' for 20251203-review-v5-0-b26d5512c6af at gmail.com:

arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: pmic (mediatek,mt6359): '#sound-dai-cells' does not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/mfd/mediatek,mt6397.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: scp at 10720000 (mediatek,mt8188-scp-dual): reg-names: ['cfg'] is too short
	from schema $id: http://devicetree.org/schemas/remoteproc/mtk,scp.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: scp at 10720000 (mediatek,mt8188-scp-dual): reg: [[0, 275906560, 0, 917504]] is too short
	from schema $id: http://devicetree.org/schemas/remoteproc/mtk,scp.yaml
arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtb: scp at 10720000 (mediatek,mt8188-scp-dual): reg-names: ['cfg'] is too short
	from schema $id: http://devicetree.org/schemas/remoteproc/mtk,scp.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: pmic (mediatek,mt6359): '#sound-dai-cells' does not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/mfd/mediatek,mt6397.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: scp at 10720000 (mediatek,mt8188-scp-dual): reg-names: ['cfg'] is too short
	from schema $id: http://devicetree.org/schemas/remoteproc/mtk,scp.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: scp at 10720000 (mediatek,mt8188-scp-dual): reg: [[0, 275906560, 0, 917504]] is too short
	from schema $id: http://devicetree.org/schemas/remoteproc/mtk,scp.yaml
arch/arm64/boot/dts/mediatek/mt8370-tungsten-smarc.dtb: scp at 10720000 (mediatek,mt8188-scp-dual): reg-names: ['cfg'] is too short
	from schema $id: http://devicetree.org/schemas/remoteproc/mtk,scp.yaml







From robh at kernel.org  Fri Dec  5 14:36:46 2025
From: robh at kernel.org (Rob Herring)
Date: Fri, 05 Dec 2025 16:36:46 -0600
Subject: [PATCH] ARM: dts: integrator: Fix DMA ranges mismatch warning
 on IM-PD1
In-Reply-To: <20251204164228.113587-1-visitorckw@gmail.com>
References: <20251204164228.113587-1-visitorckw@gmail.com>
Message-ID: <176497381720.863571.13455719382013086980.robh@kernel.org>


On Thu, 04 Dec 2025 16:42:28 +0000, Kuan-Wei Chiu wrote:
> When compiling the device tree for the Integrator/AP with IM-PD1, the
> following warning is observed regarding the display controller node:
> 
> arch/arm/boot/dts/arm/integratorap-im-pd1.dts:251.3-14: Warning
> (dma_ranges_format):
> /bus at c0000000/bus at c0000000/display at 1000000:dma-ranges: empty
> "dma-ranges" property but its #address-cells (2) differs from
> /bus at c0000000/bus at c0000000 (1)
> 
> The display node specifies an empty "dma-ranges" property, intended to
> describe a 1:1 identity mapping. However, the node lacks explicit
> "#address-cells" and "#size-cells" properties. In this case, the device
> tree compiler defaults the address cells to 2 (64-bit), which conflicts
> with the parent bus configuration (32-bit, 1 cell).
> 
> Fix this by explicitly defining "#address-cells" and "#size-cells" as
> 1. This matches the 32-bit architecture of the Integrator platform and
> ensures the address translation range is correctly parsed by the
> compiler.
> 
> Fixes: 7bea67a99430 ("ARM: dts: integrator: Fix DMA ranges")
> Cc: stable at vger.kernel.org
> Signed-off-by: Kuan-Wei Chiu <visitorckw at gmail.com>
> ---
>  arch/arm/boot/dts/arm/integratorap-im-pd1.dts | 2 ++
>  1 file changed, 2 insertions(+)
> 


My bot found new DTB warnings on the .dts files added or changed in this
series.

Some warnings may be from an existing SoC .dtsi. Or perhaps the warnings
are fixed by another series. Ultimately, it is up to the platform
maintainer whether these warnings are acceptable or not. No need to reply
unless the platform maintainer has comments.

If you already ran DT checks and didn't see these error(s), then
make sure dt-schema is up to date:

  pip3 install dtschema --upgrade


This patch series was applied (using b4) to base:
 Base: attempting to guess base-commit...
 Base: tags/v6.18-rc6-2004-g29bce9c8b41d (exact match)
 Base: tags/v6.18-rc6-2004-g29bce9c8b41d (use --merge-base to override)

If this is not the correct base, please add 'base-commit' tag
(or use b4 which does this automatically)

New warnings running 'make CHECK_DTBS=y for arch/arm/boot/dts/arm/' for 20251204164228.113587-1-visitorckw at gmail.com:

arch/arm/boot/dts/arm/integratorap-im-pd1.dtb: display at 1000000 (arm,pl110): '#address-cells', '#size-cells', 'dma-ranges', 'port at 0' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/display/arm,pl11x.yaml







From justinstitt at google.com  Fri Dec  5 14:51:41 2025
From: justinstitt at google.com (Justin Stitt)
Date: Fri, 05 Dec 2025 14:51:41 -0800
Subject: [PATCH 6.1.y RESEND v2] KVM: arm64: sys_regs: disable
 -Wuninitialized-const-pointer warning
Message-ID: <20251205-stable-disable-unit-ptr-warn-v2-1-cec53a8f736b@google.com>

A new warning in Clang 22 [1] complains that @clidr passed to
get_clidr_el1() is an uninitialized const pointer. get_clidr_el1()
doesn't really care since it casts away the const-ness anyways -- it is
a false positive.

This patch isn't needed for anything past 6.1 as this code section was
reworked in Commit 7af0c2534f4c ("KVM: arm64: Normalize cache
configuration") which incidentally removed the aforementioned warning.
Since there is no upstream equivalent, this patch just needs to be
applied to 6.1.

Disable this warning for sys_regs.o instead of backporting the patches
from 6.2+ that modified this code area.

Cc: stable at vger.kernel.org
Fixes: 7c8c5e6a9101e ("arm64: KVM: system register handling")
Link: https://github.com/llvm/llvm-project/commit/00dacf8c22f065cb52efb14cd091d441f19b319e [1]
Reviewed-by: Nathan Chancellor <nathan at kernel.org>
Signed-off-by: Justin Stitt <justinstitt at google.com>
---
Changes in v2:
- disable warning for TU instead of initialising the struct
- update commit message
- Link to v1: https://lore.kernel.org/all/20250724-b4-clidr-unint-const-ptr-v1-1-67c4d620b6b6 at google.com/
- Link to v1 resend (sent wrong diff, thanks Nathan): https://lore.kernel.org/all/20251204-b4-clidr-unint-const-ptr-v1-1-95161315ad92 at google.com/
---
 arch/arm64/kvm/Makefile | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index 5e33c2d4645a..5fdb5331bfad 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -24,6 +24,9 @@ kvm-y += arm.o mmu.o mmio.o psci.o hypercalls.o pvtime.o \
 
 kvm-$(CONFIG_HW_PERF_EVENTS)  += pmu-emul.o pmu.o
 
+# Work around a false positive Clang 22 -Wuninitialized-const-pointer warning
+CFLAGS_sys_regs.o := $(call cc-disable-warning, uninitialized-const-pointer)
+
 always-y := hyp_constants.h hyp-constants.s
 
 define rule_gen_hyp_constants

---
base-commit: 830b3c68c1fb1e9176028d02ef86f3cf76aa2476
change-id: 20250728-stable-disable-unit-ptr-warn-281fee82539c

Best regards,
--
Justin Stitt <justinstitt at google.com>



From justinstitt at google.com  Fri Dec  5 14:53:49 2025
From: justinstitt at google.com (Justin Stitt)
Date: Fri, 5 Dec 2025 14:53:49 -0800
Subject: [PATCH 6.1.y RESEND] KVM: arm64: silence
 -Wuninitialized-const-pointer warning
In-Reply-To: <20251205002245.GA3463270@ax162>
References: <20251204-b4-clidr-unint-const-ptr-v1-1-95161315ad92@google.com>
 <2lse2swdqrovimdsakgtriadki2fsvikhuetjzxztoui5hpsai@6mmc64ugt22k>
 <20251205002245.GA3463270@ax162>
Message-ID: <hafkvcj6frhjrzqotsdwws2buy7c6tfwjt5kkjkjc2emuxud7n@cv5vp4ftwvdv>

Hi,

On Thu, Dec 04, 2025 at 05:22:45PM -0700, Nathan Chancellor wrote:
> On Thu, Dec 04, 2025 at 12:53:58PM -0800, Justin Stitt wrote:
> > Quick correction:
> > 
> > On Thu, Dec 04, 2025 at 12:50:11PM -0800, Justin Stitt wrote:
> > > A new warning in Clang 22 [1] complains that @clidr passed to
> > > get_clidr_el1() is an uninitialized const pointer. get_clidr_el1()
> > > doesn't really care since it casts away the const-ness anyways.
> > > 
> > > Silence the warning by initializing the struct.
> > > 
> > > This patch won't apply to anything past v6.1 as this code section was
> > > reworked in Commit 7af0c2534f4c ("KVM: arm64: Normalize cache
> > > configuration"). There is no upstream equivalent so this patch only
> > > needs to be applied (stable only) to 6.1.
> > > 
> > > Cc: stable at vger.kernel.org
> > > Fixes: 7c8c5e6a9101e ("arm64: KVM: system register handling")
> > > Link: https://github.com/llvm/llvm-project/commit/00dacf8c22f065cb52efb14cd091d441f19b319e [1]
> > > Signed-off-by: Justin Stitt <justinstitt at google.com>
> > > ---
> > > Resending this with Nathan's RB tag, an updated commit log and better
> > > recipients from checkpatch.pl.
> > 
> > My usage of $ b4 trailers must've not been correct because this 6.1
> > version didn't pick up Nathan's RB tag. Whoops! Hopefully whoever picks
> > this up can add that for me :)
> 
> Looks like you resent the first iteration of this change [1] instead of
> the second [2], hence why 'b4 trailers -u' did not work, since I never
> reviewed the first iteration after Marc rejected it :)
> 
> Your 5.15 resend looks correct though.
> 
> [1]: https://lore.kernel.org/20250724-b4-clidr-unint-const-ptr-v1-1-67c4d620b6b6 at google.com/
> [2]: https://lore.kernel.org/20250728-stable-disable-unit-ptr-warn-v1-1-958be9b66520 at google.com/

Thanks for spotting this, I got lost in my b4 branches. I've sent the v2
resend [1]. Hopefully all is good there :)

> 
> Cheers,
> Nathan

[1]: https://lore.kernel.org/r/20251205-stable-disable-unit-ptr-warn-v2-1-cec53a8f736b at google.com

Justin


From seanjc at google.com  Fri Dec  5 15:26:55 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 15:26:55 -0800
Subject: [PATCH] KVM: Remove subtle "struct kvm_stats_desc" pseudo-overlay
Message-ID: <20251205232655.445294-1-seanjc@google.com>

Remove KVM's internal pseudo-overlay of kvm_stats_desc, which subtly
aliases the flexible name[] in the uAPI definition with a fixed-size array
of the same name.  The unusual embedded structure results in compiler
warnings due to -Wflex-array-member-not-at-end, and also necessitates an
extra level of dereferencing in KVM.  To avoid the "overlay", define the
uAPI structure to have a fixed-size name when building for the kernel.

Opportunistically clean up the indentation for the stats macros, and
replace spaces with tabs.

No functional change intended.

Reported-by: Gustavo A. R. Silva <gustavoars at kernel.org>
Closes: https://lore.kernel.org/all/aPfNKRpLfhmhYqfP at kspp
Signed-off-by: Sean Christopherson <seanjc at google.com>
---

Posting this as a standalone patch/email to make review and merging easier
(assuming no one hates on the __KERNEL__ shenanigans).
 
 arch/arm64/kvm/guest.c    |  4 +-
 arch/loongarch/kvm/vcpu.c |  2 +-
 arch/loongarch/kvm/vm.c   |  2 +-
 arch/mips/kvm/mips.c      |  4 +-
 arch/powerpc/kvm/book3s.c |  4 +-
 arch/powerpc/kvm/booke.c  |  4 +-
 arch/riscv/kvm/vcpu.c     |  2 +-
 arch/riscv/kvm/vm.c       |  2 +-
 arch/s390/kvm/kvm-s390.c  |  4 +-
 arch/x86/kvm/x86.c        |  4 +-
 include/linux/kvm_host.h  | 83 +++++++++++++++++----------------------
 include/uapi/linux/kvm.h  |  8 ++++
 virt/kvm/binary_stats.c   |  2 +-
 virt/kvm/kvm_main.c       | 20 +++++-----
 14 files changed, 70 insertions(+), 75 deletions(-)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 1c87699fd886..332c453b87cf 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -29,7 +29,7 @@
 
 #include "trace.h"
 
-const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
+const struct kvm_stats_desc kvm_vm_stats_desc[] = {
 	KVM_GENERIC_VM_STATS()
 };
 
@@ -42,7 +42,7 @@ const struct kvm_stats_header kvm_vm_stats_header = {
 		       sizeof(kvm_vm_stats_desc),
 };
 
-const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
+const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {
 	KVM_GENERIC_VCPU_STATS(),
 	STATS_DESC_COUNTER(VCPU, hvc_exit_stat),
 	STATS_DESC_COUNTER(VCPU, wfe_exit_stat),
diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
index 6d833599ef2e..2bcbd27f1152 100644
--- a/arch/loongarch/kvm/vcpu.c
+++ b/arch/loongarch/kvm/vcpu.c
@@ -13,7 +13,7 @@
 #define CREATE_TRACE_POINTS
 #include "trace.h"
 
-const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
+const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {
 	KVM_GENERIC_VCPU_STATS(),
 	STATS_DESC_COUNTER(VCPU, int_exits),
 	STATS_DESC_COUNTER(VCPU, idle_exits),
diff --git a/arch/loongarch/kvm/vm.c b/arch/loongarch/kvm/vm.c
index 194ccbcdc3b3..7deff56e0e1a 100644
--- a/arch/loongarch/kvm/vm.c
+++ b/arch/loongarch/kvm/vm.c
@@ -10,7 +10,7 @@
 #include <asm/kvm_eiointc.h>
 #include <asm/kvm_pch_pic.h>
 
-const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
+const struct kvm_stats_desc kvm_vm_stats_desc[] = {
 	KVM_GENERIC_VM_STATS(),
 	STATS_DESC_ICOUNTER(VM, pages),
 	STATS_DESC_ICOUNTER(VM, hugepages),
diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c
index b0fb92fda4d4..23e69baad453 100644
--- a/arch/mips/kvm/mips.c
+++ b/arch/mips/kvm/mips.c
@@ -38,7 +38,7 @@
 #define VECTORSPACING 0x100	/* for EI/VI mode */
 #endif
 
-const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
+const struct kvm_stats_desc kvm_vm_stats_desc[] = {
 	KVM_GENERIC_VM_STATS()
 };
 
@@ -51,7 +51,7 @@ const struct kvm_stats_header kvm_vm_stats_header = {
 		       sizeof(kvm_vm_stats_desc),
 };
 
-const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
+const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {
 	KVM_GENERIC_VCPU_STATS(),
 	STATS_DESC_COUNTER(VCPU, wait_exits),
 	STATS_DESC_COUNTER(VCPU, cache_exits),
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
index d79c5d1098c0..2efbe05caed7 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -38,7 +38,7 @@
 
 /* #define EXIT_DEBUG */
 
-const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
+const struct kvm_stats_desc kvm_vm_stats_desc[] = {
 	KVM_GENERIC_VM_STATS(),
 	STATS_DESC_ICOUNTER(VM, num_2M_pages),
 	STATS_DESC_ICOUNTER(VM, num_1G_pages)
@@ -53,7 +53,7 @@ const struct kvm_stats_header kvm_vm_stats_header = {
 		       sizeof(kvm_vm_stats_desc),
 };
 
-const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
+const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {
 	KVM_GENERIC_VCPU_STATS(),
 	STATS_DESC_COUNTER(VCPU, sum_exits),
 	STATS_DESC_COUNTER(VCPU, mmio_exits),
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index 3401b96be475..f3ddb24ece74 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -36,7 +36,7 @@
 
 unsigned long kvmppc_booke_handlers;
 
-const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
+const struct kvm_stats_desc kvm_vm_stats_desc[] = {
 	KVM_GENERIC_VM_STATS(),
 	STATS_DESC_ICOUNTER(VM, num_2M_pages),
 	STATS_DESC_ICOUNTER(VM, num_1G_pages)
@@ -51,7 +51,7 @@ const struct kvm_stats_header kvm_vm_stats_header = {
 		       sizeof(kvm_vm_stats_desc),
 };
 
-const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
+const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {
 	KVM_GENERIC_VCPU_STATS(),
 	STATS_DESC_COUNTER(VCPU, sum_exits),
 	STATS_DESC_COUNTER(VCPU, mmio_exits),
diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c
index a55a95da54d0..fdd99ac1e714 100644
--- a/arch/riscv/kvm/vcpu.c
+++ b/arch/riscv/kvm/vcpu.c
@@ -24,7 +24,7 @@
 #define CREATE_TRACE_POINTS
 #include "trace.h"
 
-const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
+const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {
 	KVM_GENERIC_VCPU_STATS(),
 	STATS_DESC_COUNTER(VCPU, ecall_exit_stat),
 	STATS_DESC_COUNTER(VCPU, wfi_exit_stat),
diff --git a/arch/riscv/kvm/vm.c b/arch/riscv/kvm/vm.c
index 66d91ae6e9b2..715a06ae8c13 100644
--- a/arch/riscv/kvm/vm.c
+++ b/arch/riscv/kvm/vm.c
@@ -13,7 +13,7 @@
 #include <linux/kvm_host.h>
 #include <asm/kvm_mmu.h>
 
-const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
+const struct kvm_stats_desc kvm_vm_stats_desc[] = {
 	KVM_GENERIC_VM_STATS()
 };
 static_assert(ARRAY_SIZE(kvm_vm_stats_desc) ==
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 70dd9ce8cf2b..1cc90b8cf768 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -65,7 +65,7 @@
 #define VCPU_IRQS_MAX_BUF (sizeof(struct kvm_s390_irq) * \
 			   (KVM_MAX_VCPUS + LOCAL_IRQS))
 
-const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
+const struct kvm_stats_desc kvm_vm_stats_desc[] = {
 	KVM_GENERIC_VM_STATS(),
 	STATS_DESC_COUNTER(VM, inject_io),
 	STATS_DESC_COUNTER(VM, inject_float_mchk),
@@ -91,7 +91,7 @@ const struct kvm_stats_header kvm_vm_stats_header = {
 		       sizeof(kvm_vm_stats_desc),
 };
 
-const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
+const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {
 	KVM_GENERIC_VCPU_STATS(),
 	STATS_DESC_COUNTER(VCPU, exit_userspace),
 	STATS_DESC_COUNTER(VCPU, exit_null),
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 0c6d899d53dd..62ee4816e573 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -237,7 +237,7 @@ EXPORT_SYMBOL_FOR_KVM_INTERNAL(enable_ipiv);
 bool __read_mostly enable_device_posted_irqs = true;
 EXPORT_SYMBOL_FOR_KVM_INTERNAL(enable_device_posted_irqs);
 
-const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
+const struct kvm_stats_desc kvm_vm_stats_desc[] = {
 	KVM_GENERIC_VM_STATS(),
 	STATS_DESC_COUNTER(VM, mmu_shadow_zapped),
 	STATS_DESC_COUNTER(VM, mmu_pte_write),
@@ -263,7 +263,7 @@ const struct kvm_stats_header kvm_vm_stats_header = {
 		       sizeof(kvm_vm_stats_desc),
 };
 
-const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
+const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {
 	KVM_GENERIC_VCPU_STATS(),
 	STATS_DESC_COUNTER(VCPU, pf_taken),
 	STATS_DESC_COUNTER(VCPU, pf_fixed),
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index d93f75b05ae2..7428d9949382 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -1927,56 +1927,43 @@ enum kvm_stat_kind {
 
 struct kvm_stat_data {
 	struct kvm *kvm;
-	const struct _kvm_stats_desc *desc;
+	const struct kvm_stats_desc *desc;
 	enum kvm_stat_kind kind;
 };
 
-struct _kvm_stats_desc {
-	struct kvm_stats_desc desc;
-	char name[KVM_STATS_NAME_SIZE];
-};
-
-#define STATS_DESC_COMMON(type, unit, base, exp, sz, bsz)		       \
-	.flags = type | unit | base |					       \
-		 BUILD_BUG_ON_ZERO(type & ~KVM_STATS_TYPE_MASK) |	       \
-		 BUILD_BUG_ON_ZERO(unit & ~KVM_STATS_UNIT_MASK) |	       \
-		 BUILD_BUG_ON_ZERO(base & ~KVM_STATS_BASE_MASK),	       \
-	.exponent = exp,						       \
-	.size = sz,							       \
+#define STATS_DESC_COMMON(type, unit, base, exp, sz, bsz)		\
+	.flags = type | unit | base |					\
+		 BUILD_BUG_ON_ZERO(type & ~KVM_STATS_TYPE_MASK) |       \
+		 BUILD_BUG_ON_ZERO(unit & ~KVM_STATS_UNIT_MASK) |	\
+		 BUILD_BUG_ON_ZERO(base & ~KVM_STATS_BASE_MASK),	\
+	.exponent = exp,						\
+	.size = sz,							\
 	.bucket_size = bsz
 
-#define VM_GENERIC_STATS_DESC(stat, type, unit, base, exp, sz, bsz)	       \
-	{								       \
-		{							       \
-			STATS_DESC_COMMON(type, unit, base, exp, sz, bsz),     \
-			.offset = offsetof(struct kvm_vm_stat, generic.stat)   \
-		},							       \
-		.name = #stat,						       \
-	}
-#define VCPU_GENERIC_STATS_DESC(stat, type, unit, base, exp, sz, bsz)	       \
-	{								       \
-		{							       \
-			STATS_DESC_COMMON(type, unit, base, exp, sz, bsz),     \
-			.offset = offsetof(struct kvm_vcpu_stat, generic.stat) \
-		},							       \
-		.name = #stat,						       \
-	}
-#define VM_STATS_DESC(stat, type, unit, base, exp, sz, bsz)		       \
-	{								       \
-		{							       \
-			STATS_DESC_COMMON(type, unit, base, exp, sz, bsz),     \
-			.offset = offsetof(struct kvm_vm_stat, stat)	       \
-		},							       \
-		.name = #stat,						       \
-	}
-#define VCPU_STATS_DESC(stat, type, unit, base, exp, sz, bsz)		       \
-	{								       \
-		{							       \
-			STATS_DESC_COMMON(type, unit, base, exp, sz, bsz),     \
-			.offset = offsetof(struct kvm_vcpu_stat, stat)	       \
-		},							       \
-		.name = #stat,						       \
-	}
+#define VM_GENERIC_STATS_DESC(stat, type, unit, base, exp, sz, bsz)	\
+{									\
+	STATS_DESC_COMMON(type, unit, base, exp, sz, bsz),		\
+	.offset = offsetof(struct kvm_vm_stat, generic.stat),		\
+	.name = #stat,							\
+}
+#define VCPU_GENERIC_STATS_DESC(stat, type, unit, base, exp, sz, bsz)	\
+{									\
+	STATS_DESC_COMMON(type, unit, base, exp, sz, bsz),		\
+	.offset = offsetof(struct kvm_vcpu_stat, generic.stat),		\
+	.name = #stat,							\
+}
+#define VM_STATS_DESC(stat, type, unit, base, exp, sz, bsz)		\
+{									\
+	STATS_DESC_COMMON(type, unit, base, exp, sz, bsz),		\
+	.offset = offsetof(struct kvm_vm_stat, stat),			\
+	.name = #stat,							\
+}
+#define VCPU_STATS_DESC(stat, type, unit, base, exp, sz, bsz)		\
+{									\
+	STATS_DESC_COMMON(type, unit, base, exp, sz, bsz),		\
+	.offset = offsetof(struct kvm_vcpu_stat, stat),			\
+	.name = #stat,							\
+}
 /* SCOPE: VM, VM_GENERIC, VCPU, VCPU_GENERIC */
 #define STATS_DESC(SCOPE, stat, type, unit, base, exp, sz, bsz)		       \
 	SCOPE##_STATS_DESC(stat, type, unit, base, exp, sz, bsz)
@@ -2053,7 +2040,7 @@ struct _kvm_stats_desc {
 	STATS_DESC_IBOOLEAN(VCPU_GENERIC, blocking)
 
 ssize_t kvm_stats_read(char *id, const struct kvm_stats_header *header,
-		       const struct _kvm_stats_desc *desc,
+		       const struct kvm_stats_desc *desc,
 		       void *stats, size_t size_stats,
 		       char __user *user_buffer, size_t size, loff_t *offset);
 
@@ -2098,9 +2085,9 @@ static inline void kvm_stats_log_hist_update(u64 *data, size_t size, u64 value)
 
 
 extern const struct kvm_stats_header kvm_vm_stats_header;
-extern const struct _kvm_stats_desc kvm_vm_stats_desc[];
+extern const struct kvm_stats_desc kvm_vm_stats_desc[];
 extern const struct kvm_stats_header kvm_vcpu_stats_header;
-extern const struct _kvm_stats_desc kvm_vcpu_stats_desc[];
+extern const struct kvm_stats_desc kvm_vcpu_stats_desc[];
 
 #ifdef CONFIG_KVM_GENERIC_MMU_NOTIFIER
 static inline int mmu_invalidate_retry(struct kvm *kvm, unsigned long mmu_seq)
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index dddb781b0507..76bd54848b11 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -14,6 +14,10 @@
 #include <linux/ioctl.h>
 #include <asm/kvm.h>
 
+#ifdef __KERNEL__
+#include <linux/kvm_types.h>
+#endif
+
 #define KVM_API_VERSION 12
 
 /*
@@ -1579,7 +1583,11 @@ struct kvm_stats_desc {
 	__u16 size;
 	__u32 offset;
 	__u32 bucket_size;
+#ifdef __KERNEL__
+	char name[KVM_STATS_NAME_SIZE];
+#else
 	char name[];
+#endif
 };
 
 #define KVM_GET_STATS_FD  _IO(KVMIO,  0xce)
diff --git a/virt/kvm/binary_stats.c b/virt/kvm/binary_stats.c
index eefca6c69f51..76ce697c773b 100644
--- a/virt/kvm/binary_stats.c
+++ b/virt/kvm/binary_stats.c
@@ -50,7 +50,7 @@
  * Return: the number of bytes that has been successfully read
  */
 ssize_t kvm_stats_read(char *id, const struct kvm_stats_header *header,
-		       const struct _kvm_stats_desc *desc,
+		       const struct kvm_stats_desc *desc,
 		       void *stats, size_t size_stats,
 		       char __user *user_buffer, size_t size, loff_t *offset)
 {
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 74e1afd67b44..6ebf1936c8d4 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -982,9 +982,9 @@ static void kvm_free_memslots(struct kvm *kvm, struct kvm_memslots *slots)
 		kvm_free_memslot(kvm, memslot);
 }
 
-static umode_t kvm_stats_debugfs_mode(const struct _kvm_stats_desc *pdesc)
+static umode_t kvm_stats_debugfs_mode(const struct kvm_stats_desc *desc)
 {
-	switch (pdesc->desc.flags & KVM_STATS_TYPE_MASK) {
+	switch (desc->flags & KVM_STATS_TYPE_MASK) {
 	case KVM_STATS_TYPE_INSTANT:
 		return 0444;
 	case KVM_STATS_TYPE_CUMULATIVE:
@@ -1019,7 +1019,7 @@ static int kvm_create_vm_debugfs(struct kvm *kvm, const char *fdname)
 	struct dentry *dent;
 	char dir_name[ITOA_MAX_LEN * 2];
 	struct kvm_stat_data *stat_data;
-	const struct _kvm_stats_desc *pdesc;
+	const struct kvm_stats_desc *pdesc;
 	int i, ret = -ENOMEM;
 	int kvm_debugfs_num_entries = kvm_vm_stats_header.num_desc +
 				      kvm_vcpu_stats_header.num_desc;
@@ -6160,11 +6160,11 @@ static int kvm_stat_data_get(void *data, u64 *val)
 	switch (stat_data->kind) {
 	case KVM_STAT_VM:
 		r = kvm_get_stat_per_vm(stat_data->kvm,
-					stat_data->desc->desc.offset, val);
+					stat_data->desc->offset, val);
 		break;
 	case KVM_STAT_VCPU:
 		r = kvm_get_stat_per_vcpu(stat_data->kvm,
-					  stat_data->desc->desc.offset, val);
+					  stat_data->desc->offset, val);
 		break;
 	}
 
@@ -6182,11 +6182,11 @@ static int kvm_stat_data_clear(void *data, u64 val)
 	switch (stat_data->kind) {
 	case KVM_STAT_VM:
 		r = kvm_clear_stat_per_vm(stat_data->kvm,
-					  stat_data->desc->desc.offset);
+					  stat_data->desc->offset);
 		break;
 	case KVM_STAT_VCPU:
 		r = kvm_clear_stat_per_vcpu(stat_data->kvm,
-					    stat_data->desc->desc.offset);
+					    stat_data->desc->offset);
 		break;
 	}
 
@@ -6334,7 +6334,7 @@ static void kvm_uevent_notify_change(unsigned int type, struct kvm *kvm)
 static void kvm_init_debug(void)
 {
 	const struct file_operations *fops;
-	const struct _kvm_stats_desc *pdesc;
+	const struct kvm_stats_desc *pdesc;
 	int i;
 
 	kvm_debugfs_dir = debugfs_create_dir("kvm", NULL);
@@ -6347,7 +6347,7 @@ static void kvm_init_debug(void)
 			fops = &vm_stat_readonly_fops;
 		debugfs_create_file(pdesc->name, kvm_stats_debugfs_mode(pdesc),
 				kvm_debugfs_dir,
-				(void *)(long)pdesc->desc.offset, fops);
+				(void *)(long)pdesc->offset, fops);
 	}
 
 	for (i = 0; i < kvm_vcpu_stats_header.num_desc; ++i) {
@@ -6358,7 +6358,7 @@ static void kvm_init_debug(void)
 			fops = &vcpu_stat_readonly_fops;
 		debugfs_create_file(pdesc->name, kvm_stats_debugfs_mode(pdesc),
 				kvm_debugfs_dir,
-				(void *)(long)pdesc->desc.offset, fops);
+				(void *)(long)pdesc->offset, fops);
 	}
 }
 

base-commit: e0c26d47def7382d7dbd9cad58bc653aed75737a
-- 
2.52.0.223.gf5cc29aaa4-goog



From lkp at intel.com  Fri Dec  5 15:27:43 2025
From: lkp at intel.com (kernel test robot)
Date: Sat, 6 Dec 2025 07:27:43 +0800
Subject: [PATCH v7 5/6] clocksource/drivers/exynos_mct: Add module
 support for ARM64
In-Reply-To: <20251205011027.720512-6-willmcvicker@google.com>
References: <20251205011027.720512-6-willmcvicker@google.com>
Message-ID: <202512060730.wBnpCnQv-lkp@intel.com>

Hi Will,

kernel test robot noticed the following build warnings:

[auto build test WARNING on bca42080637ce3a21092fc0f7d5411e853b0c3b3]

url:    https://github.com/intel-lab-lkp/linux/commits/Will-McVicker/clocksource-drivers-exynos_mct-Don-t-register-as-a-sched_clock-on-arm64/20251205-091403
base:   bca42080637ce3a21092fc0f7d5411e853b0c3b3
patch link:    https://lore.kernel.org/r/20251205011027.720512-6-willmcvicker%40google.com
patch subject: [PATCH v7 5/6] clocksource/drivers/exynos_mct: Add module support for ARM64
config: arm64-randconfig-004-20251205 (https://download.01.org/0day-ci/archive/20251206/202512060730.wBnpCnQv-lkp at intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 14bf95b06a18b9b59c89601cbc0e5a6f2176b118)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251206/202512060730.wBnpCnQv-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512060730.wBnpCnQv-lkp at intel.com/

All warnings (new ones prefixed by >>, old ones prefixed by <<):

>> WARNING: modpost: vmlinux: section mismatch in reference: exynos4_mct_probe+0x70 (section: .text.exynos4_mct_probe) -> mct_init_dt (section: .init.text)

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From fenghuay at nvidia.com  Fri Dec  5 15:53:36 2025
From: fenghuay at nvidia.com (Fenghua Yu)
Date: Fri, 5 Dec 2025 15:53:36 -0800
Subject: [RFC PATCH 01/38] arm64: mpam: Context switch the MPAM registers
In-Reply-To: <20251205215901.17772-2-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-2-james.morse@arm.com>
Message-ID: <a3305659-929d-45f6-823d-a886f197d652@nvidia.com>

Hi, James,

On 12/5/25 13:58, James Morse wrote:
> MPAM allows traffic in the SoC to be labeled by the OS, these labels
> are used to apply policy in caches and bandwidth regulators, and to
> monitor traffic in the SoC. The label is made up of a PARTID and PMG
> value. The x86 equivalent calls these CLOSID and RMID, but they don't
> map precisely.
> 
> MPAM has two CPU system registers that is used to hold the PARTID and PMG
> values that traffic generated at each exception level will use. These can be
> set per-task by the resctrl file system. (resctrl is the defacto interface
> for controlling this stuff).
> 
> Add a helper to switch this.
> 
> struct task_struct's separate CLOSID and RMID fields are insufficient
> to implement resctrl using MPAM, as resctrl can change the PARTID (CLOSID)
> and PMG (sort of like the RMID) separately. On x86, the rmid is an
> independent number, so a race that writes a mismatched  closid and rmid
> into hardware is benign. On arm64, the pmg bits extend the partid.
> (i.e. partid-5 has a pmg-0 that is not the same as partid-6's pmg-0).
> In this case, mismatching the values will 'dirty' a pmg value that
> resctrl believes is clean, and is not tracking with its 'limbo' code.
> 
> To avoid this, the partid and pmg are always read and written as a pair.
> Instead of making struct task_struct's closid and rmid fields an
> endian-unsafe union, add the value to struct thread_info and always use
> READ_ONCE()/WRITE_ONCE() when accessing this field.
> 
> Resctrl allows a per-cpu 'default' value to be set, this overrides the
> values when scheduling a task in the default control-group, which has
> PARTID 0. The way 'code data prioritisation' gets emulated means the
> register value for the default group needs to be a variable.
> 
> The current system register value is kept in a per-cpu variable to
> avoid writing to the system register if the value isn't going to change.
> Writes to this register may reset the hardware state for regulating
> bandwidth.
> 
> Finally, there is no reason to context switch these registers unless
> there is a driver changing the values in struct task_struct. Hide
> the whole thing behind a static key. This also allows the driver to
> disable MPAM in response to errors reported by hardware. Move the
> existing static key to belong to the arch code, as in the future
> the MPAM driver may become a loadable module.
> 
> All this should depend on whether there is an MPAM driver, hide
> it behind CONFIG_MPAM.
> 
> CC: Amit Singh Tomar <amitsinght at marvell.com>
> Signed-off-by: James Morse <james.morse at arm.com>
> ---
>   arch/arm64/Kconfig                   |  2 +
>   arch/arm64/include/asm/mpam.h        | 74 ++++++++++++++++++++++++++++
>   arch/arm64/include/asm/thread_info.h |  3 ++
>   arch/arm64/kernel/Makefile           |  1 +
>   arch/arm64/kernel/mpam.c             | 13 +++++
>   arch/arm64/kernel/process.c          |  7 +++
>   drivers/resctrl/mpam_devices.c       |  2 -
>   drivers/resctrl/mpam_internal.h      |  2 +
>   8 files changed, 102 insertions(+), 2 deletions(-)
>   create mode 100644 arch/arm64/include/asm/mpam.h
>   create mode 100644 arch/arm64/kernel/mpam.c
> 
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 004d58cfbff8..558baa9e7c08 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -2048,6 +2048,8 @@ config ARM64_MPAM
>   
>   	  MPAM is exposed to user-space via the resctrl pseudo filesystem.
>   
> +	  This option enables the extra context switch code.
> +
>   endmenu # "ARMv8.4 architectural features"
>   
>   menu "ARMv8.5 architectural features"
> diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/mpam.h
> new file mode 100644
> index 000000000000..86a55176f884
> --- /dev/null
> +++ b/arch/arm64/include/asm/mpam.h
> @@ -0,0 +1,74 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2025 Arm Ltd. */
> +
> +#ifndef __ASM__MPAM_H
> +#define __ASM__MPAM_H
> +
> +#include <linux/bitops.h>
> +#include <linux/init.h>
> +#include <linux/jump_label.h>
> +#include <linux/percpu.h>
> +#include <linux/sched.h>
> +
> +#include <asm/cpucaps.h>
> +#include <asm/cpufeature.h>
> +#include <asm/sysreg.h>
> +
> +DECLARE_STATIC_KEY_FALSE(mpam_enabled);
> +DECLARE_PER_CPU(u64, arm64_mpam_default);
> +DECLARE_PER_CPU(u64, arm64_mpam_current);
> +
> +/*
> + * The value of the MPAM0_EL1 sysreg when a task is in resctrl's default group.
> + * This is used by the context switch code to use the resctrl CPU property
> + * instead. The value is modified when CDP is enabled/disabled by mounting
> + * the resctrl filesystem.
> + */
> +extern u64 arm64_mpam_global_default;
> +
> +/*
> + * The resctrl filesystem writes to the partid/pmg values for threads and CPUs,
> + * which may race with reads in __mpam_sched_in(). Ensure only one of the old
> + * or new values are used. Particular care should be taken with the pmg field
> + * as __mpam_sched_in() may read a partid and pmg that don't match, causing
> + * this value to be stored with cache allocations, despite being considered
> + * 'free' by resctrl.
> + *
> + * A value in struct thread_info is used instead of struct task_struct as the
> + * cpu's u64 register format is used, but struct task_struct has two u32'.
> + */
> +static inline u64 mpam_get_regval(struct task_struct *tsk)
> +{
> +#ifdef CONFIG_ARM64_MPAM
> +	return READ_ONCE(task_thread_info(tsk)->mpam_partid_pmg);
> +#else
> +	return 0;
> +#endif
> +}
> +
> +static inline void mpam_thread_switch(struct task_struct *tsk)
> +{
> +	u64 oldregval;
> +	int cpu = smp_processor_id();
> +	u64 regval = mpam_get_regval(tsk);
> +
> +	if (!IS_ENABLED(CONFIG_ARM64_MPAM) ||
> +	    !static_branch_likely(&mpam_enabled))
> +		return;
> +
> +	if (regval == READ_ONCE(arm64_mpam_global_default))
Why is this check needed? We need to read arm64_mpam_default in any 
case, right?> +		regval = READ_ONCE(per_cpu(arm64_mpam_default, cpu));
> +
> +	oldregval = READ_ONCE(per_cpu(arm64_mpam_current, cpu));
> +	if (oldregval == regval)
> +		return;
> +
> +	write_sysreg_s(regval, SYS_MPAM1_EL1);
> +	isb();
> +
> +	/* Synchronising the EL0 write is left until the ERET to EL0 */
> +	write_sysreg_s(regval, SYS_MPAM0_EL1);
> +
> +	WRITE_ONCE(per_cpu(arm64_mpam_current, cpu), regval);
> +}
> +#endif /* __ASM__MPAM_H */

[SNIP]
Thanks.

-Fenghua



From robh at kernel.org  Fri Dec  5 16:08:06 2025
From: robh at kernel.org (Rob Herring)
Date: Fri, 5 Dec 2025 18:08:06 -0600
Subject: [PATCH v6 0/7] Add ASPEED PCIe Root Complex support
In-Reply-To: <SEYPR06MB5134D0D5911E3C86D869151E9DA7A@SEYPR06MB5134.apcprd06.prod.outlook.com>
References: <20251201-upstream_pcie_rc-v6-0-8c8800c56b16@aspeedtech.com>
 <20251204195355.GA1975043-robh@kernel.org>
 <SEYPR06MB5134D0D5911E3C86D869151E9DA7A@SEYPR06MB5134.apcprd06.prod.outlook.com>
Message-ID: <20251206000806.GA969079-robh@kernel.org>

On Fri, Dec 05, 2025 at 12:12:35AM +0000, Jacky Chou wrote:
> Hi Rob,
> 
> Thanks for your comments.
> 
> > > Changes in v6:
> > > - Refer to pci-cpi-bridge.yaml to update aspeed,ast2600-pcie.yaml and
> > >   the pcie node of aspeed-g6.dtsi.
> > 
> > Where is this? You don't describe the root port and its properties at all now.
> > 
> 
> May I confirm whether the pcie at 8,0 in aspeed-g6.dtsi is not considered the 
> root port? From my understanding, that node represents the root port, so I 
> want to make sure I'm aligning with your expectation before updating the binding.

I believe you told me it was the root port.

> Could you help clarify how you would like the root port and its properties to 
> be described in the schema?

properties:
  pcie at 8,0:
    $ref: /schemas/pci/pci-pci-bridge.yaml#
    unevaluatedProperties: false

    properties:

And then add all the properties you have which are not defined in 
pci-pci-bridge.yaml (and pci-device.yaml by reference) (i.e. clocks, 
resets, phys, etc.).

Rob


From fenghuay at nvidia.com  Fri Dec  5 16:06:58 2025
From: fenghuay at nvidia.com (Fenghua Yu)
Date: Fri, 5 Dec 2025 16:06:58 -0800
Subject: [RFC PATCH 31/38] arm_mpam: resctrl: Update the rmid reallocation
 limit
In-Reply-To: <20251205215901.17772-32-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-32-james.morse@arm.com>
Message-ID: <1cc804d5-9d14-4d71-9da1-a660a2569e4e@nvidia.com>

Hi, James,

On 12/5/25 13:58, James Morse wrote:
> resctrl's limbo code needs to be told when the data left in a cache is
> small enough for the partid+pmg value to be re-allocated.
> 
> x86 uses the cache size divided by the number of rmid users the cache
> may have. Do the same, but for the smallest cache, and with the
> number of partid-and-pmg users.
> 
> Querying the cache size can't happen until after cacheinfo_sysfs_init()
> has run, so mpam_resctrl_setup() must wait until then.
> 
> Signed-off-by: James Morse <james.morse at arm.com>
> ---
>   drivers/resctrl/mpam_resctrl.c | 54 ++++++++++++++++++++++++++++++++++
>   1 file changed, 54 insertions(+)
> 
> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
> index 506063bd3348..ccdf8db742c9 100644
> --- a/drivers/resctrl/mpam_resctrl.c
> +++ b/drivers/resctrl/mpam_resctrl.c
> @@ -16,6 +16,7 @@
>   #include <linux/resctrl.h>
>   #include <linux/slab.h>
>   #include <linux/types.h>
> +#include <linux/wait.h>
>   
>   #include <asm/mpam.h>
>   
> @@ -58,6 +59,13 @@ static bool cdp_enabled;
>    */
>   static bool resctrl_enabled;
>   
> +/*
> + * mpam_resctrl_pick_caches() needs to know the size of the caches. cacheinfo
> + * populates this from a device_initcall(). mpam_resctrl_setup() must wait.
> + */
> +static bool cacheinfo_ready;
> +static DECLARE_WAIT_QUEUE_HEAD(wait_cacheinfo_ready);
> +
>   /*
>    * L3 local/total may come from different classes - what is the number of MBWU
>    * 'on L3'?
> @@ -584,6 +592,38 @@ void resctrl_arch_reset_cntr(struct rdt_resource *r, struct rdt_mon_domain *d,
>   	reset_mon_cdp_safe(mon, mon_comp, USE_PRE_ALLOCATED, closid, rmid);
>   }
>   
> +/*
> + * The rmid realloc threshold should be for the smallest cache exposed to
> + * resctrl.
> + */
> +static int update_rmid_limits(struct mpam_class *class)
> +{
> +	u32 num_unique_pmg = resctrl_arch_system_num_rmid_idx();
> +	struct mpam_props *cprops = &class->props;
> +	struct cacheinfo *ci;
> +
> +	lockdep_assert_cpus_held();
> +
> +	/* Assume cache levels are the same size for all CPUs... */
> +	ci = get_cpu_cacheinfo_level(smp_processor_id(), class->level);
> +	if (!ci || ci->size == 0) {
> +		pr_debug("Could not read cache size for class %u\n",
> +			 class->level);
> +		return -EINVAL;
> +	}
> +
> +	if (!mpam_has_feature(mpam_feat_msmon_csu, cprops))
> +		return 0;
> +
> +	if (!resctrl_rmid_realloc_limit ||
> +	    ci->size < resctrl_rmid_realloc_limit) {
> +		resctrl_rmid_realloc_limit = ci->size;
> +		resctrl_rmid_realloc_threshold = ci->size / num_unique_pmg;
> +	}
> +
> +	return 0;
> +}
> +
>   static bool cache_has_usable_cpor(struct mpam_class *class)
>   {
>   	struct mpam_props *cprops = &class->props;
> @@ -1025,6 +1065,9 @@ static void mpam_resctrl_pick_counters(void)
>   			/* CSU counters only make sense on a cache. */
>   			switch (class->type) {
>   			case MPAM_CLASS_CACHE:
> +				if (update_rmid_limits(class))
> +					continue;
> +
>   				counter_update_class(QOS_L3_OCCUP_EVENT_ID, class);
>   				return;
>   			default:
> @@ -1731,6 +1774,8 @@ int mpam_resctrl_setup(void)
>   	struct mpam_resctrl_res *res;
>   	struct mpam_resctrl_mon *mon;
>   
> +	wait_event(wait_cacheinfo_ready, cacheinfo_ready);

This may cause system hang for any hw/fw issue that causes cacheinfo 
failure. Instead of hang, is it better to have a timeout wait here? Like
	errowait_event_timeout(wait_cache_info_read, cacheinfo_ready, 5 * HZ);
and report failure when cacheinfo is not ready.

Thanks.

-Fenghua


From seanjc at google.com  Fri Dec  5 16:16:36 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:16:36 -0800
Subject: [PATCH v6 00/44] KVM: x86: Add support for mediated vPMUs
Message-ID: <20251206001720.468579-1-seanjc@google.com>

This series is based on 'https://github.com/kvm-x86/linux next', but except
for one minor conflict in perf should apply on Linus' tree once the KVM 6.19
pull request lands.  I considered waiting until 6.19-rc1 to post this, but
I've had this in a "ready" state for a few weeks and want to get it out there.

My hope/plan is that the perf changes will go through the tip tree with a
stable tag/branch, and the KVM changes will go the kvm-x86 tree.

Non-x86 KVM folks, y'all are getting Cc'd due to minor changes in "KVM: Add a
simplified wrapper for registering perf callbacks".

The full set is also available at:

  https://github.com/sean-jc/linux.git tags/mediated-vpmu-v6

Add support for mediated vPMUs in KVM x86, where "mediated" aligns with the
standard definition of intercepting control operations (e.g. event selectors),
while allowing the guest to perform data operations (e.g. read PMCs, toggle
counters on/off) without KVM getting involed.

For an in-depth description of the what and why, please see the cover letter
from the original RFC:

  https://lore.kernel.org/all/20240126085444.324918-1-xiong.y.zhang at linux.intel.com

All KVM tests pass (or fail the same before and after), and I've manually
verified MSR/PMC are passed through as expected, but I haven't done much at all
to actually utilize the PMU in a guest.

Despite merging almost all of the tangentially related prep work for 6.19,
the patch count remains the same as v5 thanks to the VMX MSR auto-store
cleanup and support for pre-SPR Intel CPUs.

v6:
 - Add back support for pre-SPR Intel CPUs, i.e. CPUs with PMU v4 but not
   "save PERF_GLOBAL_CTRL on VM-Exit".  See 
   https://lore.kernel.org/all/aSUK8FuWT4lpMP3F at google.com for details.
 - Add an x86-only API to update the LVTPC entry on load/put of a mediated
   vPMU. [PeterZ]
 - Don't tie RDPMC interception to PERF_GLOBAL_CTRL interception, as AMD
   CPUs have scenarios where KVM needs to intercept PERF_GLOBAL_CTRL, but
   not all PMC accesses. [Sandipan]
 - Fix a s/Turing/Turin typo. [Manali]
 - Collect tags. [Anup, Sandipan, Xudong]

v5:
 -  https://lore.kernel.org/all/20250806195706.1650976-1-seanjc at google.com
 - Add a patch to call security_perf_event_free() from __free_event()
   instead of _free_event() (necessitated by the __cleanup() changes).
 - Add CONFIG_PERF_GUEST_MEDIATED_PMU to guard the new perf functionality.
 - Ensure the PMU is fully disabled in perf_{load,put}_guest_context() when
   when switching between guest and host context. [Kan, Namhyung]
 - Route the new system IRQ, PERF_GUEST_MEDIATED_PMI_VECTOR, through perf,
   not KVM, and play nice with FRED.
 - Rename and combine perf_{guest,host}_{enter,exit}() to a single set of
   APIs, perf_{load,put}_guest_context().
 - Rename perf_{get,put}_mediated_pmu() to perf_{create,release}_mediated_pmu()
   to (hopefully) better differentiate them from perf_{load,put}_guest_context().
 - Change the param to the load/put APIs from "u32 guest_lvtpc" to
   "unsigned long data" to decouple arch code as much as possible.  E.g. if
   a non-x86 arch were to ever support a mediated vPMU, @data could be used
   to pass a pointer to a struct.
 - Use pmu->version to detect if a vCPU has a mediated PMU.
 - Use a kvm_x86_ops hook to check for mediated PMU support.
 - Cull "passthrough" from as many places as I could find.
 - Improve the changelog/documentation related to RDPMC interception.
 - Check harware capabilities, not KVM capabilities, when calculating
   MSR and RDPMC intercepts.
 - Rework intercept (re)calculation to use a request and the existing (well,
   will be existing as of 6.17-rc1) vendor hooks for recalculating intercepts.
 - Always read PERF_GLOBAL_CTRL on VM-Exit if writes weren't intercepted while
   running the vCPU.
 - Call setup_vmcs_config() before kvm_x86_vendor_init() so that the golden
   VMCS configuration is known before kvm_init_pmu_capability() is called.
 - Keep as much refresh/init code in common x86 as possible.
 - Context switch PMCs and event selectors in common x86, not vendor code.
 - Bail from the VM-Exit fastpath if the guest is counting instructions
   retired and the mediated PMU is enabled (because guest state hasn't yet
   been synchronized with hardware).
 - Don't require an userspace to opt-in via KVM_CAP_PMU_CAPABILITY, and instead
   automatically "create" a mediated PMU on the first KVM_CREATE_VCPU call if
   the VM has an in-kernel local APIC.
 - Add entries in kernel-parameters.txt for the PMU params.
 - Add a patch to elide PMC writes when possible.
 - Many more fixups and tweaks...

v4:
 - https://lore.kernel.org/all/20250324173121.1275209-1-mizhang at google.com
 - Rebase whole patchset on 6.14-rc3 base.
 - Address Peter's comments on Perf part.
 - Address Sean's comments on KVM part.
   * Change key word "passthrough" to "mediated" in all patches
   * Change static enabling to user space dynamic enabling via KVM_CAP_PMU_CAPABILITY.
   * Only support GLOBAL_CTRL save/restore with VMCS exec_ctrl, drop the MSR
     save/retore list support for GLOBAL_CTRL, thus the support of mediated
     vPMU is constrained to SapphireRapids and later CPUs on Intel side.
   * Merge some small changes into a single patch.
 - Address Sandipan's comment on invalid pmu pointer.
 - Add back "eventsel_hw" and "fixed_ctr_ctrl_hw" to avoid to directly
   manipulate pmc->eventsel and pmu->fixed_ctr_ctrl.

v3: https://lore.kernel.org/all/20240801045907.4010984-1-mizhang at google.com
v2: https://lore.kernel.org/all/20240506053020.3911940-1-mizhang at google.com
v1: https://lore.kernel.org/all/20240126085444.324918-1-xiong.y.zhang at linux.intel.com

Dapeng Mi (11):
  KVM: x86/pmu: Start stubbing in mediated PMU support
  KVM: x86/pmu: Implement Intel mediated PMU requirements and
    constraints
  KVM: x86/pmu: Disable RDPMC interception for compatible mediated vPMU
  KVM: x86/pmu: Load/save GLOBAL_CTRL via entry/exit fields for mediated
    PMU
  KVM: x86/pmu: Disable interception of select PMU MSRs for mediated
    vPMUs
  KVM: x86/pmu: Bypass perf checks when emulating mediated PMU counter
    accesses
  KVM: x86/pmu: Reprogram mediated PMU event selectors on event filter
    updates
  KVM: x86/pmu: Load/put mediated PMU context when entering/exiting
    guest
  KVM: x86/pmu: Handle emulated instruction for mediated vPMU
  KVM: nVMX: Add macros to simplify nested MSR interception setting
  KVM: x86/pmu: Expose enable_mediated_pmu parameter to user space

Kan Liang (7):
  perf: Skip pmu_ctx based on event_type
  perf: Add generic exclude_guest support
  perf: Add APIs to create/release mediated guest vPMUs
  perf: Clean up perf ctx time
  perf: Add a EVENT_GUEST flag
  perf: Add APIs to load/put guest mediated PMU context
  perf/x86/intel: Support PERF_PMU_CAP_MEDIATED_VPMU

Mingwei Zhang (3):
  perf/x86/core: Plumb mediated PMU capability from x86_pmu to
    x86_pmu_cap
  KVM: x86/pmu: Introduce eventsel_hw to prepare for pmu event filtering
  KVM: nVMX: Disable PMU MSR interception as appropriate while running
    L2

Sandipan Das (3):
  perf/x86/core: Do not set bit width for unavailable counters
  perf/x86/amd: Support PERF_PMU_CAP_MEDIATED_VPMU for AMD host
  KVM: x86/pmu: Always stuff GuestOnly=1,HostOnly=0 for mediated PMCs on
    AMD

Sean Christopherson (19):
  perf: Move security_perf_event_free() call to __free_event()
  perf/x86/core: Register a new vector for handling mediated guest PMIs
  perf/x86/core: Add APIs to switch to/from mediated PMI vector (for
    KVM)
  KVM: Add a simplified wrapper for registering perf callbacks
  KVM: x86/pmu: Snapshot host (i.e. perf's) reported PMU capabilities
  KVM: x86/pmu: Implement AMD mediated PMU requirements
  KVM: x86/pmu: Disallow emulation in the fastpath if mediated PMCs are
    active
  KVM: nSVM: Disable PMU MSR interception as appropriate while running
    L2
  KVM: x86/pmu: Elide WRMSRs when loading guest PMCs if values already
    match
  KVM: VMX: Drop intermediate "guest" field from msr_autostore
  KVM: nVMX: Don't update msr_autostore count when saving TSC for vmcs12
  KVM: VMX: Dedup code for removing MSR from VMCS's auto-load list
  KVM: VMX: Drop unused @entry_only param from add_atomic_switch_msr()
  KVM: VMX: Bug the VM if either MSR auto-load list is full
  KVM: VMX: Set MSR index auto-load entry if and only if entry is "new"
  KVM: VMX: Compartmentalize adding MSRs to host vs. guest auto-load
    list
  KVM: VMX: Dedup code for adding MSR to VMCS's auto list
  KVM: VMX: Initialize vmcs01.VM_EXIT_MSR_STORE_ADDR with list address
  KVM: VMX: Add mediated PMU support for CPUs without "save perf global
    ctrl"

Xiong Zhang (1):
  KVM: x86/pmu: Register PMI handler for mediated vPMU

 .../admin-guide/kernel-parameters.txt         |  49 ++
 arch/arm64/kvm/arm.c                          |   2 +-
 arch/loongarch/kvm/main.c                     |   2 +-
 arch/riscv/kvm/main.c                         |   2 +-
 arch/x86/entry/entry_fred.c                   |   1 +
 arch/x86/events/amd/core.c                    |   2 +
 arch/x86/events/core.c                        |  37 +-
 arch/x86/events/intel/core.c                  |   5 +
 arch/x86/include/asm/hardirq.h                |   3 +
 arch/x86/include/asm/idtentry.h               |   6 +
 arch/x86/include/asm/irq_vectors.h            |   4 +-
 arch/x86/include/asm/kvm-x86-pmu-ops.h        |   4 +
 arch/x86/include/asm/kvm_host.h               |   3 +
 arch/x86/include/asm/msr-index.h              |   1 +
 arch/x86/include/asm/perf_event.h             |   6 +
 arch/x86/include/asm/vmx.h                    |   1 +
 arch/x86/kernel/idt.c                         |   3 +
 arch/x86/kernel/irq.c                         |  19 +
 arch/x86/kvm/Kconfig                          |   1 +
 arch/x86/kvm/pmu.c                            | 271 ++++++++-
 arch/x86/kvm/pmu.h                            |  37 +-
 arch/x86/kvm/svm/nested.c                     |  18 +-
 arch/x86/kvm/svm/pmu.c                        |  44 ++
 arch/x86/kvm/svm/svm.c                        |  46 ++
 arch/x86/kvm/vmx/capabilities.h               |   9 +-
 arch/x86/kvm/vmx/nested.c                     | 144 ++---
 arch/x86/kvm/vmx/pmu_intel.c                  |  92 +++-
 arch/x86/kvm/vmx/pmu_intel.h                  |  15 +
 arch/x86/kvm/vmx/vmx.c                        | 212 +++++--
 arch/x86/kvm/vmx/vmx.h                        |   9 +-
 arch/x86/kvm/x86.c                            |  54 +-
 arch/x86/kvm/x86.h                            |   1 +
 include/linux/kvm_host.h                      |  11 +-
 include/linux/perf_event.h                    |  35 +-
 init/Kconfig                                  |   4 +
 kernel/events/core.c                          | 517 ++++++++++++++----
 .../beauty/arch/x86/include/asm/irq_vectors.h |   3 +-
 virt/kvm/kvm_main.c                           |   6 +-
 38 files changed, 1396 insertions(+), 283 deletions(-)


base-commit: 5d3e2d9ba9ed68576c70c127e4f7446d896f2af2
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:16:37 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:16:37 -0800
Subject: [PATCH v6 01/44] perf: Skip pmu_ctx based on event_type
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-2-seanjc@google.com>

From: Kan Liang <kan.liang at linux.intel.com>

To optimize the cgroup context switch, the perf_event_pmu_context
iteration skips the PMUs without cgroup events. A bool cgroup was
introduced to indicate the case. It can work, but this way is hard to
extend for other cases, e.g. skipping non-mediated PMUs. It doesn't
make sense to keep adding bool variables.

Pass the event_type instead of the specific bool variable. Check both
the event_type and related pmu_ctx variables to decide whether skipping
a PMU.

Event flags, e.g., EVENT_CGROUP, should be cleard in the ctx->is_active.
Add EVENT_FLAGS to indicate such event flags.

No functional change.

Signed-off-by: Kan Liang <kan.liang at linux.intel.com>
Tested-by: Yongwei Ma <yongwei.ma at intel.com>
Signed-off-by: Mingwei Zhang <mizhang at google.com>
Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 kernel/events/core.c | 74 ++++++++++++++++++++++++--------------------
 1 file changed, 40 insertions(+), 34 deletions(-)

diff --git a/kernel/events/core.c b/kernel/events/core.c
index 2c35acc2722b..4cc95dd15620 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -164,7 +164,7 @@ enum event_type_t {
 	/* see ctx_resched() for details */
 	EVENT_CPU	= 0x10,
 	EVENT_CGROUP	= 0x20,
-
+	EVENT_FLAGS	= EVENT_CGROUP,
 	/* compound helpers */
 	EVENT_ALL         = EVENT_FLEXIBLE | EVENT_PINNED,
 	EVENT_TIME_FROZEN = EVENT_TIME | EVENT_FROZEN,
@@ -778,27 +778,37 @@ do {									\
 	___p;								\
 })
 
-#define for_each_epc(_epc, _ctx, _pmu, _cgroup)				\
+static bool perf_skip_pmu_ctx(struct perf_event_pmu_context *pmu_ctx,
+			      enum event_type_t event_type)
+{
+	if ((event_type & EVENT_CGROUP) && !pmu_ctx->nr_cgroups)
+		return true;
+	return false;
+}
+
+#define for_each_epc(_epc, _ctx, _pmu, _event_type)			\
 	list_for_each_entry(_epc, &((_ctx)->pmu_ctx_list), pmu_ctx_entry) \
-		if (_cgroup && !_epc->nr_cgroups)			\
+		if (perf_skip_pmu_ctx(_epc, _event_type))		\
 			continue;					\
 		else if (_pmu && _epc->pmu != _pmu)			\
 			continue;					\
 		else
 
-static void perf_ctx_disable(struct perf_event_context *ctx, bool cgroup)
+static void perf_ctx_disable(struct perf_event_context *ctx,
+			     enum event_type_t event_type)
 {
 	struct perf_event_pmu_context *pmu_ctx;
 
-	for_each_epc(pmu_ctx, ctx, NULL, cgroup)
+	for_each_epc(pmu_ctx, ctx, NULL, event_type)
 		perf_pmu_disable(pmu_ctx->pmu);
 }
 
-static void perf_ctx_enable(struct perf_event_context *ctx, bool cgroup)
+static void perf_ctx_enable(struct perf_event_context *ctx,
+			    enum event_type_t event_type)
 {
 	struct perf_event_pmu_context *pmu_ctx;
 
-	for_each_epc(pmu_ctx, ctx, NULL, cgroup)
+	for_each_epc(pmu_ctx, ctx, NULL, event_type)
 		perf_pmu_enable(pmu_ctx->pmu);
 }
 
@@ -963,8 +973,7 @@ static void perf_cgroup_switch(struct task_struct *task)
 		return;
 
 	WARN_ON_ONCE(cpuctx->ctx.nr_cgroups == 0);
-
-	perf_ctx_disable(&cpuctx->ctx, true);
+	perf_ctx_disable(&cpuctx->ctx, EVENT_CGROUP);
 
 	ctx_sched_out(&cpuctx->ctx, NULL, EVENT_ALL|EVENT_CGROUP);
 	/*
@@ -980,7 +989,7 @@ static void perf_cgroup_switch(struct task_struct *task)
 	 */
 	ctx_sched_in(&cpuctx->ctx, NULL, EVENT_ALL|EVENT_CGROUP);
 
-	perf_ctx_enable(&cpuctx->ctx, true);
+	perf_ctx_enable(&cpuctx->ctx, EVENT_CGROUP);
 }
 
 static int perf_cgroup_ensure_storage(struct perf_event *event,
@@ -2904,11 +2913,11 @@ static void ctx_resched(struct perf_cpu_context *cpuctx,
 
 	event_type &= EVENT_ALL;
 
-	for_each_epc(epc, &cpuctx->ctx, pmu, false)
+	for_each_epc(epc, &cpuctx->ctx, pmu, 0)
 		perf_pmu_disable(epc->pmu);
 
 	if (task_ctx) {
-		for_each_epc(epc, task_ctx, pmu, false)
+		for_each_epc(epc, task_ctx, pmu, 0)
 			perf_pmu_disable(epc->pmu);
 
 		task_ctx_sched_out(task_ctx, pmu, event_type);
@@ -2928,11 +2937,11 @@ static void ctx_resched(struct perf_cpu_context *cpuctx,
 
 	perf_event_sched_in(cpuctx, task_ctx, pmu);
 
-	for_each_epc(epc, &cpuctx->ctx, pmu, false)
+	for_each_epc(epc, &cpuctx->ctx, pmu, 0)
 		perf_pmu_enable(epc->pmu);
 
 	if (task_ctx) {
-		for_each_epc(epc, task_ctx, pmu, false)
+		for_each_epc(epc, task_ctx, pmu, 0)
 			perf_pmu_enable(epc->pmu);
 	}
 }
@@ -3481,11 +3490,10 @@ static void
 ctx_sched_out(struct perf_event_context *ctx, struct pmu *pmu, enum event_type_t event_type)
 {
 	struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context);
+	enum event_type_t active_type = event_type & ~EVENT_FLAGS;
 	struct perf_event_pmu_context *pmu_ctx;
 	int is_active = ctx->is_active;
-	bool cgroup = event_type & EVENT_CGROUP;
 
-	event_type &= ~EVENT_CGROUP;
 
 	lockdep_assert_held(&ctx->lock);
 
@@ -3516,7 +3524,7 @@ ctx_sched_out(struct perf_event_context *ctx, struct pmu *pmu, enum event_type_t
 	 * see __load_acquire() in perf_event_time_now()
 	 */
 	barrier();
-	ctx->is_active &= ~event_type;
+	ctx->is_active &= ~active_type;
 
 	if (!(ctx->is_active & EVENT_ALL)) {
 		/*
@@ -3537,7 +3545,7 @@ ctx_sched_out(struct perf_event_context *ctx, struct pmu *pmu, enum event_type_t
 
 	is_active ^= ctx->is_active; /* changed bits */
 
-	for_each_epc(pmu_ctx, ctx, pmu, cgroup)
+	for_each_epc(pmu_ctx, ctx, pmu, event_type)
 		__pmu_ctx_sched_out(pmu_ctx, is_active);
 }
 
@@ -3693,7 +3701,7 @@ perf_event_context_sched_out(struct task_struct *task, struct task_struct *next)
 		raw_spin_lock_nested(&next_ctx->lock, SINGLE_DEPTH_NESTING);
 		if (context_equiv(ctx, next_ctx)) {
 
-			perf_ctx_disable(ctx, false);
+			perf_ctx_disable(ctx, 0);
 
 			/* PMIs are disabled; ctx->nr_no_switch_fast is stable. */
 			if (local_read(&ctx->nr_no_switch_fast) ||
@@ -3717,7 +3725,7 @@ perf_event_context_sched_out(struct task_struct *task, struct task_struct *next)
 
 			perf_ctx_sched_task_cb(ctx, task, false);
 
-			perf_ctx_enable(ctx, false);
+			perf_ctx_enable(ctx, 0);
 
 			/*
 			 * RCU_INIT_POINTER here is safe because we've not
@@ -3741,13 +3749,13 @@ perf_event_context_sched_out(struct task_struct *task, struct task_struct *next)
 
 	if (do_switch) {
 		raw_spin_lock(&ctx->lock);
-		perf_ctx_disable(ctx, false);
+		perf_ctx_disable(ctx, 0);
 
 inside_switch:
 		perf_ctx_sched_task_cb(ctx, task, false);
 		task_ctx_sched_out(ctx, NULL, EVENT_ALL);
 
-		perf_ctx_enable(ctx, false);
+		perf_ctx_enable(ctx, 0);
 		raw_spin_unlock(&ctx->lock);
 	}
 }
@@ -4056,11 +4064,9 @@ static void
 ctx_sched_in(struct perf_event_context *ctx, struct pmu *pmu, enum event_type_t event_type)
 {
 	struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context);
+	enum event_type_t active_type = event_type & ~EVENT_FLAGS;
 	struct perf_event_pmu_context *pmu_ctx;
 	int is_active = ctx->is_active;
-	bool cgroup = event_type & EVENT_CGROUP;
-
-	event_type &= ~EVENT_CGROUP;
 
 	lockdep_assert_held(&ctx->lock);
 
@@ -4078,7 +4084,7 @@ ctx_sched_in(struct perf_event_context *ctx, struct pmu *pmu, enum event_type_t
 		barrier();
 	}
 
-	ctx->is_active |= (event_type | EVENT_TIME);
+	ctx->is_active |= active_type | EVENT_TIME;
 	if (ctx->task) {
 		if (!(is_active & EVENT_ALL))
 			cpuctx->task_ctx = ctx;
@@ -4093,13 +4099,13 @@ ctx_sched_in(struct perf_event_context *ctx, struct pmu *pmu, enum event_type_t
 	 * in order to give them the best chance of going on.
 	 */
 	if (is_active & EVENT_PINNED) {
-		for_each_epc(pmu_ctx, ctx, pmu, cgroup)
+		for_each_epc(pmu_ctx, ctx, pmu, event_type)
 			__pmu_ctx_sched_in(pmu_ctx, EVENT_PINNED);
 	}
 
 	/* Then walk through the lower prio flexible groups */
 	if (is_active & EVENT_FLEXIBLE) {
-		for_each_epc(pmu_ctx, ctx, pmu, cgroup)
+		for_each_epc(pmu_ctx, ctx, pmu, event_type)
 			__pmu_ctx_sched_in(pmu_ctx, EVENT_FLEXIBLE);
 	}
 }
@@ -4116,11 +4122,11 @@ static void perf_event_context_sched_in(struct task_struct *task)
 
 	if (cpuctx->task_ctx == ctx) {
 		perf_ctx_lock(cpuctx, ctx);
-		perf_ctx_disable(ctx, false);
+		perf_ctx_disable(ctx, 0);
 
 		perf_ctx_sched_task_cb(ctx, task, true);
 
-		perf_ctx_enable(ctx, false);
+		perf_ctx_enable(ctx, 0);
 		perf_ctx_unlock(cpuctx, ctx);
 		goto rcu_unlock;
 	}
@@ -4133,7 +4139,7 @@ static void perf_event_context_sched_in(struct task_struct *task)
 	if (!ctx->nr_events)
 		goto unlock;
 
-	perf_ctx_disable(ctx, false);
+	perf_ctx_disable(ctx, 0);
 	/*
 	 * We want to keep the following priority order:
 	 * cpu pinned (that don't need to move), task pinned,
@@ -4143,7 +4149,7 @@ static void perf_event_context_sched_in(struct task_struct *task)
 	 * events, no need to flip the cpuctx's events around.
 	 */
 	if (!RB_EMPTY_ROOT(&ctx->pinned_groups.tree)) {
-		perf_ctx_disable(&cpuctx->ctx, false);
+		perf_ctx_disable(&cpuctx->ctx, 0);
 		ctx_sched_out(&cpuctx->ctx, NULL, EVENT_FLEXIBLE);
 	}
 
@@ -4152,9 +4158,9 @@ static void perf_event_context_sched_in(struct task_struct *task)
 	perf_ctx_sched_task_cb(cpuctx->task_ctx, task, true);
 
 	if (!RB_EMPTY_ROOT(&ctx->pinned_groups.tree))
-		perf_ctx_enable(&cpuctx->ctx, false);
+		perf_ctx_enable(&cpuctx->ctx, 0);
 
-	perf_ctx_enable(ctx, false);
+	perf_ctx_enable(ctx, 0);
 
 unlock:
 	perf_ctx_unlock(cpuctx, ctx);
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:16:38 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:16:38 -0800
Subject: [PATCH v6 02/44] perf: Add generic exclude_guest support
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-3-seanjc@google.com>

From: Kan Liang <kan.liang at linux.intel.com>

Only KVM knows the exact time when a guest is entering/exiting. Expose
two interfaces to KVM to switch the ownership of the PMU resources.

All the pinned events must be scheduled in first. Extend the
perf_event_sched_in() helper to support extra flag, e.g., EVENT_GUEST.

Signed-off-by: Kan Liang <kan.liang at linux.intel.com>
Signed-off-by: Mingwei Zhang <mizhang at google.com>
Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 kernel/events/core.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/kernel/events/core.c b/kernel/events/core.c
index 4cc95dd15620..1e37ab90b815 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -2872,14 +2872,15 @@ static void task_ctx_sched_out(struct perf_event_context *ctx,
 
 static void perf_event_sched_in(struct perf_cpu_context *cpuctx,
 				struct perf_event_context *ctx,
-				struct pmu *pmu)
+				struct pmu *pmu,
+				enum event_type_t event_type)
 {
-	ctx_sched_in(&cpuctx->ctx, pmu, EVENT_PINNED);
+	ctx_sched_in(&cpuctx->ctx, pmu, EVENT_PINNED | event_type);
 	if (ctx)
-		 ctx_sched_in(ctx, pmu, EVENT_PINNED);
-	ctx_sched_in(&cpuctx->ctx, pmu, EVENT_FLEXIBLE);
+		ctx_sched_in(ctx, pmu, EVENT_PINNED | event_type);
+	ctx_sched_in(&cpuctx->ctx, pmu, EVENT_FLEXIBLE | event_type);
 	if (ctx)
-		 ctx_sched_in(ctx, pmu, EVENT_FLEXIBLE);
+		ctx_sched_in(ctx, pmu, EVENT_FLEXIBLE | event_type);
 }
 
 /*
@@ -2935,7 +2936,7 @@ static void ctx_resched(struct perf_cpu_context *cpuctx,
 	else if (event_type & EVENT_PINNED)
 		ctx_sched_out(&cpuctx->ctx, pmu, EVENT_FLEXIBLE);
 
-	perf_event_sched_in(cpuctx, task_ctx, pmu);
+	perf_event_sched_in(cpuctx, task_ctx, pmu, 0);
 
 	for_each_epc(epc, &cpuctx->ctx, pmu, 0)
 		perf_pmu_enable(epc->pmu);
@@ -4153,7 +4154,7 @@ static void perf_event_context_sched_in(struct task_struct *task)
 		ctx_sched_out(&cpuctx->ctx, NULL, EVENT_FLEXIBLE);
 	}
 
-	perf_event_sched_in(cpuctx, ctx, NULL);
+	perf_event_sched_in(cpuctx, ctx, NULL, 0);
 
 	perf_ctx_sched_task_cb(cpuctx->task_ctx, task, true);
 
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:16:39 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:16:39 -0800
Subject: [PATCH v6 03/44] perf: Move security_perf_event_free() call to __free_event()
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-4-seanjc@google.com>

Move the freeing of any security state associated with a perf event from
_free_event() to __free_event(), i.e. invoke security_perf_event_free() in
the error paths for perf_event_alloc().  This will allow adding potential
error paths in perf_event_alloc() that can occur after allocating security
state.

Note, kfree() and thus security_perf_event_free() is a nop if
event->security is NULL, i.e. calling security_perf_event_free() even if
security_perf_event_alloc() fails or is never reached is functionality ok.

Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 kernel/events/core.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/kernel/events/core.c b/kernel/events/core.c
index 1e37ab90b815..e34112df8b31 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -5602,6 +5602,8 @@ static void __free_event(struct perf_event *event)
 {
 	struct pmu *pmu = event->pmu;
 
+	security_perf_event_free(event);
+
 	if (event->attach_state & PERF_ATTACH_CALLCHAIN)
 		put_callchain_buffers();
 
@@ -5665,8 +5667,6 @@ static void _free_event(struct perf_event *event)
 
 	unaccount_event(event);
 
-	security_perf_event_free(event);
-
 	if (event->rb) {
 		/*
 		 * Can happen when we close an event with re-directed output.
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:16:40 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:16:40 -0800
Subject: [PATCH v6 04/44] perf: Add APIs to create/release mediated guest vPMUs
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-5-seanjc@google.com>

From: Kan Liang <kan.liang at linux.intel.com>

Currently, exposing PMU capabilities to a KVM guest is done by emulating
guest PMCs via host perf events, i.e. by having KVM be "just" another user
of perf.  As a result, the guest and host are effectively competing for
resources, and emulating guest accesses to vPMU resources requires
expensive actions (expensive relative to the native instruction).  The
overhead and resource competition results in degraded guest performance
and ultimately very poor vPMU accuracy.

To address the issues with the perf-emulated vPMU, introduce a "mediated
vPMU", where the data plane (PMCs and enable/disable knobs) is exposed
directly to the guest, but the control plane (event selectors and access
to fixed counters) is managed by KVM (via MSR interceptions).  To allow
host perf usage of the PMU to (partially) co-exist with KVM/guest usage
of the PMU, KVM and perf will coordinate to a world switch between host
perf context and guest vPMU context near VM-Enter/VM-Exit.

Add two exported APIs, perf_{create,release}_mediated_pmu(), to allow KVM
to create and release a mediated PMU instance (per VM).  Because host perf
context will be deactivated while the guest is running, mediated PMU usage
will be mutually exclusive with perf analysis of the guest, i.e. perf
events that do NOT exclude the guest will not behave as expected.

To avoid silent failure of !exclude_guest perf events, disallow creating a
mediated PMU if there are active !exclude_guest events, and on the perf
side, disallowing creating new !exclude_guest perf events while there is
at least one active mediated PMU.

Exempt PMU resources that do not support mediated PMU usage, i.e. that are
outside the scope/view of KVM's vPMU and will not be swapped out while the
guest is running.

Guard mediated PMU with a new kconfig to help readers identify code paths
that are unique to mediated PMU support, and to allow for adding arch-
specific hooks without stubs.  KVM x86 is expected to be the only KVM
architecture to support a mediated PMU in the near future (e.g. arm64 is
trending toward a partitioned PMU implementation), and KVM x86 will select
PERF_GUEST_MEDIATED_PMU unconditionally, i.e. won't need stubs.

Immediately select PERF_GUEST_MEDIATED_PMU when KVM x86 is enabled so that
all paths are compile tested.  Full KVM support is on its way...

Suggested-by: Sean Christopherson <seanjc at google.com>
Signed-off-by: Kan Liang <kan.liang at linux.intel.com>
Signed-off-by: Mingwei Zhang <mizhang at google.com>
[sean: add kconfig and WARNing, rewrite changelog, swizzle patch ordering]
Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/kvm/Kconfig       |  1 +
 include/linux/perf_event.h |  6 +++
 init/Kconfig               |  4 ++
 kernel/events/core.c       | 82 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 93 insertions(+)

diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
index 278f08194ec8..d916bd766c94 100644
--- a/arch/x86/kvm/Kconfig
+++ b/arch/x86/kvm/Kconfig
@@ -37,6 +37,7 @@ config KVM_X86
 	select SCHED_INFO
 	select PERF_EVENTS
 	select GUEST_PERF_EVENTS
+	select PERF_GUEST_MEDIATED_PMU
 	select HAVE_KVM_MSI
 	select HAVE_KVM_CPU_RELAX_INTERCEPT
 	select HAVE_KVM_NO_POLL
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index fd1d91017b99..94f679634ef6 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -305,6 +305,7 @@ struct perf_event_pmu_context;
 #define PERF_PMU_CAP_EXTENDED_HW_TYPE	0x0100
 #define PERF_PMU_CAP_AUX_PAUSE		0x0200
 #define PERF_PMU_CAP_AUX_PREFER_LARGE	0x0400
+#define PERF_PMU_CAP_MEDIATED_VPMU	0x0800
 
 /**
  * pmu::scope
@@ -1914,6 +1915,11 @@ extern int perf_event_account_interrupt(struct perf_event *event);
 extern int perf_event_period(struct perf_event *event, u64 value);
 extern u64 perf_event_pause(struct perf_event *event, bool reset);
 
+#ifdef CONFIG_PERF_GUEST_MEDIATED_PMU
+int perf_create_mediated_pmu(void);
+void perf_release_mediated_pmu(void);
+#endif
+
 #else /* !CONFIG_PERF_EVENTS: */
 
 static inline void *
diff --git a/init/Kconfig b/init/Kconfig
index cab3ad28ca49..45b9ac626829 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -2010,6 +2010,10 @@ config GUEST_PERF_EVENTS
 	bool
 	depends on HAVE_PERF_EVENTS
 
+config PERF_GUEST_MEDIATED_PMU
+	bool
+	depends on GUEST_PERF_EVENTS
+
 config PERF_USE_VMALLOC
 	bool
 	help
diff --git a/kernel/events/core.c b/kernel/events/core.c
index e34112df8b31..cfeea7d330f9 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -5657,6 +5657,8 @@ static void __free_event(struct perf_event *event)
 	call_rcu(&event->rcu_head, free_event_rcu);
 }
 
+static void mediated_pmu_unaccount_event(struct perf_event *event);
+
 DEFINE_FREE(__free_event, struct perf_event *, if (_T) __free_event(_T))
 
 /* vs perf_event_alloc() success */
@@ -5666,6 +5668,7 @@ static void _free_event(struct perf_event *event)
 	irq_work_sync(&event->pending_disable_irq);
 
 	unaccount_event(event);
+	mediated_pmu_unaccount_event(event);
 
 	if (event->rb) {
 		/*
@@ -6188,6 +6191,81 @@ u64 perf_event_pause(struct perf_event *event, bool reset)
 }
 EXPORT_SYMBOL_GPL(perf_event_pause);
 
+#ifdef CONFIG_PERF_GUEST_MEDIATED_PMU
+static atomic_t nr_include_guest_events __read_mostly;
+
+static atomic_t nr_mediated_pmu_vms __read_mostly;
+static DEFINE_MUTEX(perf_mediated_pmu_mutex);
+
+/* !exclude_guest event of PMU with PERF_PMU_CAP_MEDIATED_VPMU */
+static inline bool is_include_guest_event(struct perf_event *event)
+{
+	if ((event->pmu->capabilities & PERF_PMU_CAP_MEDIATED_VPMU) &&
+	    !event->attr.exclude_guest)
+		return true;
+
+	return false;
+}
+
+static int mediated_pmu_account_event(struct perf_event *event)
+{
+	if (!is_include_guest_event(event))
+		return 0;
+
+	guard(mutex)(&perf_mediated_pmu_mutex);
+
+	if (atomic_read(&nr_mediated_pmu_vms))
+		return -EOPNOTSUPP;
+
+	atomic_inc(&nr_include_guest_events);
+	return 0;
+}
+
+static void mediated_pmu_unaccount_event(struct perf_event *event)
+{
+	if (!is_include_guest_event(event))
+		return;
+
+	atomic_dec(&nr_include_guest_events);
+}
+
+/*
+ * Currently invoked at VM creation to
+ * - Check whether there are existing !exclude_guest events of PMU with
+ *   PERF_PMU_CAP_MEDIATED_VPMU
+ * - Set nr_mediated_pmu_vms to prevent !exclude_guest event creation on
+ *   PMUs with PERF_PMU_CAP_MEDIATED_VPMU
+ *
+ * No impact for the PMU without PERF_PMU_CAP_MEDIATED_VPMU. The perf
+ * still owns all the PMU resources.
+ */
+int perf_create_mediated_pmu(void)
+{
+	guard(mutex)(&perf_mediated_pmu_mutex);
+	if (atomic_inc_not_zero(&nr_mediated_pmu_vms))
+		return 0;
+
+	if (atomic_read(&nr_include_guest_events))
+		return -EBUSY;
+
+	atomic_inc(&nr_mediated_pmu_vms);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(perf_create_mediated_pmu);
+
+void perf_release_mediated_pmu(void)
+{
+	if (WARN_ON_ONCE(!atomic_read(&nr_mediated_pmu_vms)))
+		return;
+
+	atomic_dec(&nr_mediated_pmu_vms);
+}
+EXPORT_SYMBOL_GPL(perf_release_mediated_pmu);
+#else
+static int mediated_pmu_account_event(struct perf_event *event) { return 0; }
+static void mediated_pmu_unaccount_event(struct perf_event *event) {}
+#endif
+
 /*
  * Holding the top-level event's child_mutex means that any
  * descendant process that has inherited this event will block
@@ -13078,6 +13156,10 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
 	if (err)
 		return ERR_PTR(err);
 
+	err = mediated_pmu_account_event(event);
+	if (err)
+		return ERR_PTR(err);
+
 	/* symmetric to unaccount_event() in _free_event() */
 	account_event(event);
 
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:16:41 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:16:41 -0800
Subject: [PATCH v6 05/44] perf: Clean up perf ctx time
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-6-seanjc@google.com>

From: Kan Liang <kan.liang at linux.intel.com>

The current perf tracks two timestamps for the normal ctx and cgroup.
The same type of variables and similar codes are used to track the
timestamps. In the following patch, the third timestamp to track the
guest time will be introduced.
To avoid the code duplication, add a new struct perf_time_ctx and factor
out a generic function update_perf_time_ctx().

No functional change.

Suggested-by: Peter Zijlstra (Intel) <peterz at infradead.org>
Signed-off-by: Kan Liang <kan.liang at linux.intel.com>
Signed-off-by: Mingwei Zhang <mizhang at google.com>
Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 include/linux/perf_event.h | 13 +++----
 kernel/events/core.c       | 70 +++++++++++++++++---------------------
 2 files changed, 39 insertions(+), 44 deletions(-)

diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 94f679634ef6..42d1debc519f 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -999,6 +999,11 @@ struct perf_event_groups {
 	u64				index;
 };
 
+struct perf_time_ctx {
+	u64		time;
+	u64		stamp;
+	u64		offset;
+};
 
 /**
  * struct perf_event_context - event context structure
@@ -1037,9 +1042,7 @@ struct perf_event_context {
 	/*
 	 * Context clock, runs when context enabled.
 	 */
-	u64				time;
-	u64				timestamp;
-	u64				timeoffset;
+	struct perf_time_ctx		time;
 
 	/*
 	 * These fields let us detect when two contexts have both
@@ -1172,9 +1175,7 @@ struct bpf_perf_event_data_kern {
  * This is a per-cpu dynamically allocated data structure.
  */
 struct perf_cgroup_info {
-	u64				time;
-	u64				timestamp;
-	u64				timeoffset;
+	struct perf_time_ctx		time;
 	int				active;
 };
 
diff --git a/kernel/events/core.c b/kernel/events/core.c
index cfeea7d330f9..5db8f4c60b9e 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -815,6 +815,24 @@ static void perf_ctx_enable(struct perf_event_context *ctx,
 static void ctx_sched_out(struct perf_event_context *ctx, struct pmu *pmu, enum event_type_t event_type);
 static void ctx_sched_in(struct perf_event_context *ctx, struct pmu *pmu, enum event_type_t event_type);
 
+static inline void update_perf_time_ctx(struct perf_time_ctx *time, u64 now, bool adv)
+{
+	if (adv)
+		time->time += now - time->stamp;
+	time->stamp = now;
+
+	/*
+	 * The above: time' = time + (now - timestamp), can be re-arranged
+	 * into: time` = now + (time - timestamp), which gives a single value
+	 * offset to compute future time without locks on.
+	 *
+	 * See perf_event_time_now(), which can be used from NMI context where
+	 * it's (obviously) not possible to acquire ctx->lock in order to read
+	 * both the above values in a consistent manner.
+	 */
+	WRITE_ONCE(time->offset, time->time - time->stamp);
+}
+
 #ifdef CONFIG_CGROUP_PERF
 
 static inline bool
@@ -856,7 +874,7 @@ static inline u64 perf_cgroup_event_time(struct perf_event *event)
 	struct perf_cgroup_info *t;
 
 	t = per_cpu_ptr(event->cgrp->info, event->cpu);
-	return t->time;
+	return t->time.time;
 }
 
 static inline u64 perf_cgroup_event_time_now(struct perf_event *event, u64 now)
@@ -865,22 +883,11 @@ static inline u64 perf_cgroup_event_time_now(struct perf_event *event, u64 now)
 
 	t = per_cpu_ptr(event->cgrp->info, event->cpu);
 	if (!__load_acquire(&t->active))
-		return t->time;
-	now += READ_ONCE(t->timeoffset);
+		return t->time.time;
+	now += READ_ONCE(t->time.offset);
 	return now;
 }
 
-static inline void __update_cgrp_time(struct perf_cgroup_info *info, u64 now, bool adv)
-{
-	if (adv)
-		info->time += now - info->timestamp;
-	info->timestamp = now;
-	/*
-	 * see update_context_time()
-	 */
-	WRITE_ONCE(info->timeoffset, info->time - info->timestamp);
-}
-
 static inline void update_cgrp_time_from_cpuctx(struct perf_cpu_context *cpuctx, bool final)
 {
 	struct perf_cgroup *cgrp = cpuctx->cgrp;
@@ -894,7 +901,7 @@ static inline void update_cgrp_time_from_cpuctx(struct perf_cpu_context *cpuctx,
 			cgrp = container_of(css, struct perf_cgroup, css);
 			info = this_cpu_ptr(cgrp->info);
 
-			__update_cgrp_time(info, now, true);
+			update_perf_time_ctx(&info->time, now, true);
 			if (final)
 				__store_release(&info->active, 0);
 		}
@@ -917,7 +924,7 @@ static inline void update_cgrp_time_from_event(struct perf_event *event)
 	 * Do not update time when cgroup is not active
 	 */
 	if (info->active)
-		__update_cgrp_time(info, perf_clock(), true);
+		update_perf_time_ctx(&info->time, perf_clock(), true);
 }
 
 static inline void
@@ -941,7 +948,7 @@ perf_cgroup_set_timestamp(struct perf_cpu_context *cpuctx)
 	for (css = &cgrp->css; css; css = css->parent) {
 		cgrp = container_of(css, struct perf_cgroup, css);
 		info = this_cpu_ptr(cgrp->info);
-		__update_cgrp_time(info, ctx->timestamp, false);
+		update_perf_time_ctx(&info->time, ctx->time.stamp, false);
 		__store_release(&info->active, 1);
 	}
 }
@@ -1562,20 +1569,7 @@ static void __update_context_time(struct perf_event_context *ctx, bool adv)
 
 	lockdep_assert_held(&ctx->lock);
 
-	if (adv)
-		ctx->time += now - ctx->timestamp;
-	ctx->timestamp = now;
-
-	/*
-	 * The above: time' = time + (now - timestamp), can be re-arranged
-	 * into: time` = now + (time - timestamp), which gives a single value
-	 * offset to compute future time without locks on.
-	 *
-	 * See perf_event_time_now(), which can be used from NMI context where
-	 * it's (obviously) not possible to acquire ctx->lock in order to read
-	 * both the above values in a consistent manner.
-	 */
-	WRITE_ONCE(ctx->timeoffset, ctx->time - ctx->timestamp);
+	update_perf_time_ctx(&ctx->time, now, adv);
 }
 
 static void update_context_time(struct perf_event_context *ctx)
@@ -1593,7 +1587,7 @@ static u64 perf_event_time(struct perf_event *event)
 	if (is_cgroup_event(event))
 		return perf_cgroup_event_time(event);
 
-	return ctx->time;
+	return ctx->time.time;
 }
 
 static u64 perf_event_time_now(struct perf_event *event, u64 now)
@@ -1607,9 +1601,9 @@ static u64 perf_event_time_now(struct perf_event *event, u64 now)
 		return perf_cgroup_event_time_now(event, now);
 
 	if (!(__load_acquire(&ctx->is_active) & EVENT_TIME))
-		return ctx->time;
+		return ctx->time.time;
 
-	now += READ_ONCE(ctx->timeoffset);
+	now += READ_ONCE(ctx->time.offset);
 	return now;
 }
 
@@ -12044,7 +12038,7 @@ static void task_clock_event_update(struct perf_event *event, u64 now)
 static void task_clock_event_start(struct perf_event *event, int flags)
 {
 	event->hw.state = 0;
-	local64_set(&event->hw.prev_count, event->ctx->time);
+	local64_set(&event->hw.prev_count, event->ctx->time.time);
 	perf_swevent_start_hrtimer(event);
 }
 
@@ -12053,7 +12047,7 @@ static void task_clock_event_stop(struct perf_event *event, int flags)
 	event->hw.state = PERF_HES_STOPPED;
 	perf_swevent_cancel_hrtimer(event);
 	if (flags & PERF_EF_UPDATE)
-		task_clock_event_update(event, event->ctx->time);
+		task_clock_event_update(event, event->ctx->time.time);
 }
 
 static int task_clock_event_add(struct perf_event *event, int flags)
@@ -12073,8 +12067,8 @@ static void task_clock_event_del(struct perf_event *event, int flags)
 static void task_clock_event_read(struct perf_event *event)
 {
 	u64 now = perf_clock();
-	u64 delta = now - event->ctx->timestamp;
-	u64 time = event->ctx->time + delta;
+	u64 delta = now - event->ctx->time.stamp;
+	u64 time = event->ctx->time.time + delta;
 
 	task_clock_event_update(event, time);
 }
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:16:42 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:16:42 -0800
Subject: [PATCH v6 06/44] perf: Add a EVENT_GUEST flag
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-7-seanjc@google.com>

From: Kan Liang <kan.liang at linux.intel.com>

Current perf doesn't explicitly schedule out all exclude_guest events
while the guest is running. There is no problem with the current
emulated vPMU. Because perf owns all the PMU counters. It can mask the
counter which is assigned to an exclude_guest event when a guest is
running (Intel way), or set the corresponding HOSTONLY bit in evsentsel
(AMD way). The counter doesn't count when a guest is running.

However, either way doesn't work with the introduced mediated vPMU.
A guest owns all the PMU counters when it's running. The host should not
mask any counters. The counter may be used by the guest. The evsentsel
may be overwritten.

Perf should explicitly schedule out all exclude_guest events to release
the PMU resources when entering a guest, and resume the counting when
exiting the guest.

It's possible that an exclude_guest event is created when a guest is
running. The new event should not be scheduled in as well.

The ctx time is shared among different PMUs. The time cannot be stopped
when a guest is running. It is required to calculate the time for events
from other PMUs, e.g., uncore events. Add timeguest to track the guest
run time. For an exclude_guest event, the elapsed time equals
the ctx time - guest time.
Cgroup has dedicated times. Use the same method to deduct the guest time
from the cgroup time as well.

Co-developed-by: Peter Zijlstra (Intel) <peterz at infradead.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz at infradead.org>
Signed-off-by: Kan Liang <kan.liang at linux.intel.com>
Signed-off-by: Mingwei Zhang <mizhang at google.com>
[sean: massage comments]
Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 include/linux/perf_event.h |   6 +
 kernel/events/core.c       | 232 ++++++++++++++++++++++++++++---------
 2 files changed, 186 insertions(+), 52 deletions(-)

diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 42d1debc519f..eaab830c9bf5 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -1044,6 +1044,11 @@ struct perf_event_context {
 	 */
 	struct perf_time_ctx		time;
 
+	/*
+	 * Context clock, runs when in the guest mode.
+	 */
+	struct perf_time_ctx		timeguest;
+
 	/*
 	 * These fields let us detect when two contexts have both
 	 * been cloned (inherited) from a common ancestor.
@@ -1176,6 +1181,7 @@ struct bpf_perf_event_data_kern {
  */
 struct perf_cgroup_info {
 	struct perf_time_ctx		time;
+	struct perf_time_ctx		timeguest;
 	int				active;
 };
 
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 5db8f4c60b9e..f72d4844b05e 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -164,7 +164,19 @@ enum event_type_t {
 	/* see ctx_resched() for details */
 	EVENT_CPU	= 0x10,
 	EVENT_CGROUP	= 0x20,
-	EVENT_FLAGS	= EVENT_CGROUP,
+
+	/*
+	 * EVENT_GUEST is set when scheduling in/out events between the host
+	 * and a guest with a mediated vPMU.  Among other things, EVENT_GUEST
+	 * is used:
+	 *
+	 * - In for_each_epc() to skip PMUs that don't support events in a
+	 *   MEDIATED_VPMU guest, i.e. don't need to be context switched.
+	 * - To indicate the start/end point of the events in a guest.  Guest
+	 *   running time is deducted for host-only (exclude_guest) events.
+	 */
+	EVENT_GUEST	= 0x40,
+	EVENT_FLAGS	= EVENT_CGROUP | EVENT_GUEST,
 	/* compound helpers */
 	EVENT_ALL         = EVENT_FLEXIBLE | EVENT_PINNED,
 	EVENT_TIME_FROZEN = EVENT_TIME | EVENT_FROZEN,
@@ -457,6 +469,11 @@ static cpumask_var_t perf_online_pkg_mask;
 static cpumask_var_t perf_online_sys_mask;
 static struct kmem_cache *perf_event_cache;
 
+static __always_inline bool is_guest_mediated_pmu_loaded(void)
+{
+	return false;
+}
+
 /*
  * perf event paranoia level:
  *  -1 - not paranoid at all
@@ -783,6 +800,9 @@ static bool perf_skip_pmu_ctx(struct perf_event_pmu_context *pmu_ctx,
 {
 	if ((event_type & EVENT_CGROUP) && !pmu_ctx->nr_cgroups)
 		return true;
+	if ((event_type & EVENT_GUEST) &&
+	    !(pmu_ctx->pmu->capabilities & PERF_PMU_CAP_MEDIATED_VPMU))
+		return true;
 	return false;
 }
 
@@ -833,6 +853,39 @@ static inline void update_perf_time_ctx(struct perf_time_ctx *time, u64 now, boo
 	WRITE_ONCE(time->offset, time->time - time->stamp);
 }
 
+static_assert(offsetof(struct perf_event_context, timeguest) -
+	      offsetof(struct perf_event_context, time) ==
+	      sizeof(struct perf_time_ctx));
+
+#define T_TOTAL		0
+#define T_GUEST		1
+
+static inline u64 __perf_event_time_ctx(struct perf_event *event,
+					struct perf_time_ctx *times)
+{
+	u64 time = times[T_TOTAL].time;
+
+	if (event->attr.exclude_guest)
+		time -= times[T_GUEST].time;
+
+	return time;
+}
+
+static inline u64 __perf_event_time_ctx_now(struct perf_event *event,
+					    struct perf_time_ctx *times,
+					    u64 now)
+{
+	if (is_guest_mediated_pmu_loaded() && event->attr.exclude_guest) {
+		/*
+		 * (now + times[total].offset) - (now + times[guest].offset) :=
+		 * times[total].offset - times[guest].offset
+		 */
+		return READ_ONCE(times[T_TOTAL].offset) - READ_ONCE(times[T_GUEST].offset);
+	}
+
+	return now + READ_ONCE(times[T_TOTAL].offset);
+}
+
 #ifdef CONFIG_CGROUP_PERF
 
 static inline bool
@@ -869,12 +922,16 @@ static inline int is_cgroup_event(struct perf_event *event)
 	return event->cgrp != NULL;
 }
 
+static_assert(offsetof(struct perf_cgroup_info, timeguest) -
+	      offsetof(struct perf_cgroup_info, time) ==
+	      sizeof(struct perf_time_ctx));
+
 static inline u64 perf_cgroup_event_time(struct perf_event *event)
 {
 	struct perf_cgroup_info *t;
 
 	t = per_cpu_ptr(event->cgrp->info, event->cpu);
-	return t->time.time;
+	return __perf_event_time_ctx(event, &t->time);
 }
 
 static inline u64 perf_cgroup_event_time_now(struct perf_event *event, u64 now)
@@ -883,9 +940,21 @@ static inline u64 perf_cgroup_event_time_now(struct perf_event *event, u64 now)
 
 	t = per_cpu_ptr(event->cgrp->info, event->cpu);
 	if (!__load_acquire(&t->active))
-		return t->time.time;
-	now += READ_ONCE(t->time.offset);
-	return now;
+		return __perf_event_time_ctx(event, &t->time);
+
+	return __perf_event_time_ctx_now(event, &t->time, now);
+}
+
+static inline void __update_cgrp_guest_time(struct perf_cgroup_info *info, u64 now, bool adv)
+{
+	update_perf_time_ctx(&info->timeguest, now, adv);
+}
+
+static inline void update_cgrp_time(struct perf_cgroup_info *info, u64 now)
+{
+	update_perf_time_ctx(&info->time, now, true);
+	if (is_guest_mediated_pmu_loaded())
+		__update_cgrp_guest_time(info, now, true);
 }
 
 static inline void update_cgrp_time_from_cpuctx(struct perf_cpu_context *cpuctx, bool final)
@@ -901,7 +970,7 @@ static inline void update_cgrp_time_from_cpuctx(struct perf_cpu_context *cpuctx,
 			cgrp = container_of(css, struct perf_cgroup, css);
 			info = this_cpu_ptr(cgrp->info);
 
-			update_perf_time_ctx(&info->time, now, true);
+			update_cgrp_time(info, now);
 			if (final)
 				__store_release(&info->active, 0);
 		}
@@ -924,11 +993,11 @@ static inline void update_cgrp_time_from_event(struct perf_event *event)
 	 * Do not update time when cgroup is not active
 	 */
 	if (info->active)
-		update_perf_time_ctx(&info->time, perf_clock(), true);
+		update_cgrp_time(info, perf_clock());
 }
 
 static inline void
-perf_cgroup_set_timestamp(struct perf_cpu_context *cpuctx)
+perf_cgroup_set_timestamp(struct perf_cpu_context *cpuctx, bool guest)
 {
 	struct perf_event_context *ctx = &cpuctx->ctx;
 	struct perf_cgroup *cgrp = cpuctx->cgrp;
@@ -948,8 +1017,12 @@ perf_cgroup_set_timestamp(struct perf_cpu_context *cpuctx)
 	for (css = &cgrp->css; css; css = css->parent) {
 		cgrp = container_of(css, struct perf_cgroup, css);
 		info = this_cpu_ptr(cgrp->info);
-		update_perf_time_ctx(&info->time, ctx->time.stamp, false);
-		__store_release(&info->active, 1);
+		if (guest) {
+			__update_cgrp_guest_time(info, ctx->time.stamp, false);
+		} else {
+			update_perf_time_ctx(&info->time, ctx->time.stamp, false);
+			__store_release(&info->active, 1);
+		}
 	}
 }
 
@@ -1153,7 +1226,7 @@ static inline int perf_cgroup_connect(pid_t pid, struct perf_event *event,
 }
 
 static inline void
-perf_cgroup_set_timestamp(struct perf_cpu_context *cpuctx)
+perf_cgroup_set_timestamp(struct perf_cpu_context *cpuctx, bool guest)
 {
 }
 
@@ -1565,16 +1638,24 @@ static void perf_unpin_context(struct perf_event_context *ctx)
  */
 static void __update_context_time(struct perf_event_context *ctx, bool adv)
 {
-	u64 now = perf_clock();
+	lockdep_assert_held(&ctx->lock);
+
+	update_perf_time_ctx(&ctx->time, perf_clock(), adv);
+}
 
+static void __update_context_guest_time(struct perf_event_context *ctx, bool adv)
+{
 	lockdep_assert_held(&ctx->lock);
 
-	update_perf_time_ctx(&ctx->time, now, adv);
+	/* must be called after __update_context_time(); */
+	update_perf_time_ctx(&ctx->timeguest, ctx->time.stamp, adv);
 }
 
 static void update_context_time(struct perf_event_context *ctx)
 {
 	__update_context_time(ctx, true);
+	if (is_guest_mediated_pmu_loaded())
+		__update_context_guest_time(ctx, true);
 }
 
 static u64 perf_event_time(struct perf_event *event)
@@ -1587,7 +1668,7 @@ static u64 perf_event_time(struct perf_event *event)
 	if (is_cgroup_event(event))
 		return perf_cgroup_event_time(event);
 
-	return ctx->time.time;
+	return __perf_event_time_ctx(event, &ctx->time);
 }
 
 static u64 perf_event_time_now(struct perf_event *event, u64 now)
@@ -1601,10 +1682,9 @@ static u64 perf_event_time_now(struct perf_event *event, u64 now)
 		return perf_cgroup_event_time_now(event, now);
 
 	if (!(__load_acquire(&ctx->is_active) & EVENT_TIME))
-		return ctx->time.time;
+		return __perf_event_time_ctx(event, &ctx->time);
 
-	now += READ_ONCE(ctx->time.offset);
-	return now;
+	return __perf_event_time_ctx_now(event, &ctx->time, now);
 }
 
 static enum event_type_t get_event_type(struct perf_event *event)
@@ -2427,20 +2507,23 @@ group_sched_out(struct perf_event *group_event, struct perf_event_context *ctx)
 }
 
 static inline void
-__ctx_time_update(struct perf_cpu_context *cpuctx, struct perf_event_context *ctx, bool final)
+__ctx_time_update(struct perf_cpu_context *cpuctx, struct perf_event_context *ctx,
+		  bool final, enum event_type_t event_type)
 {
 	if (ctx->is_active & EVENT_TIME) {
 		if (ctx->is_active & EVENT_FROZEN)
 			return;
+
 		update_context_time(ctx);
-		update_cgrp_time_from_cpuctx(cpuctx, final);
+		/* vPMU should not stop time */
+		update_cgrp_time_from_cpuctx(cpuctx, !(event_type & EVENT_GUEST) && final);
 	}
 }
 
 static inline void
 ctx_time_update(struct perf_cpu_context *cpuctx, struct perf_event_context *ctx)
 {
-	__ctx_time_update(cpuctx, ctx, false);
+	__ctx_time_update(cpuctx, ctx, false, 0);
 }
 
 /*
@@ -3512,7 +3595,7 @@ ctx_sched_out(struct perf_event_context *ctx, struct pmu *pmu, enum event_type_t
 	 *
 	 * would only update time for the pinned events.
 	 */
-	__ctx_time_update(cpuctx, ctx, ctx == &cpuctx->ctx);
+	__ctx_time_update(cpuctx, ctx, ctx == &cpuctx->ctx, event_type);
 
 	/*
 	 * CPU-release for the below ->is_active store,
@@ -3538,7 +3621,18 @@ ctx_sched_out(struct perf_event_context *ctx, struct pmu *pmu, enum event_type_t
 			cpuctx->task_ctx = NULL;
 	}
 
-	is_active ^= ctx->is_active; /* changed bits */
+	if (event_type & EVENT_GUEST) {
+		/*
+		 * Schedule out all exclude_guest events of PMU
+		 * with PERF_PMU_CAP_MEDIATED_VPMU.
+		 */
+		is_active = EVENT_ALL;
+		__update_context_guest_time(ctx, false);
+		perf_cgroup_set_timestamp(cpuctx, true);
+		barrier();
+	} else {
+		is_active ^= ctx->is_active; /* changed bits */
+	}
 
 	for_each_epc(pmu_ctx, ctx, pmu, event_type)
 		__pmu_ctx_sched_out(pmu_ctx, is_active);
@@ -3997,10 +4091,15 @@ static inline void group_update_userpage(struct perf_event *group_event)
 		event_update_userpage(event);
 }
 
+struct merge_sched_data {
+	int can_add_hw;
+	enum event_type_t event_type;
+};
+
 static int merge_sched_in(struct perf_event *event, void *data)
 {
 	struct perf_event_context *ctx = event->ctx;
-	int *can_add_hw = data;
+	struct merge_sched_data *msd = data;
 
 	if (event->state <= PERF_EVENT_STATE_OFF)
 		return 0;
@@ -4008,13 +4107,22 @@ static int merge_sched_in(struct perf_event *event, void *data)
 	if (!event_filter_match(event))
 		return 0;
 
-	if (group_can_go_on(event, *can_add_hw)) {
+	/*
+	 * Don't schedule in any host events from PMU with
+	 * PERF_PMU_CAP_MEDIATED_VPMU, while a guest is running.
+	 */
+	if (is_guest_mediated_pmu_loaded() &&
+	    event->pmu_ctx->pmu->capabilities & PERF_PMU_CAP_MEDIATED_VPMU &&
+	    !(msd->event_type & EVENT_GUEST))
+		return 0;
+
+	if (group_can_go_on(event, msd->can_add_hw)) {
 		if (!group_sched_in(event, ctx))
 			list_add_tail(&event->active_list, get_event_list(event));
 	}
 
 	if (event->state == PERF_EVENT_STATE_INACTIVE) {
-		*can_add_hw = 0;
+		msd->can_add_hw = 0;
 		if (event->attr.pinned) {
 			perf_cgroup_event_disable(event, ctx);
 			perf_event_set_state(event, PERF_EVENT_STATE_ERROR);
@@ -4037,11 +4145,15 @@ static int merge_sched_in(struct perf_event *event, void *data)
 
 static void pmu_groups_sched_in(struct perf_event_context *ctx,
 				struct perf_event_groups *groups,
-				struct pmu *pmu)
+				struct pmu *pmu,
+				enum event_type_t event_type)
 {
-	int can_add_hw = 1;
+	struct merge_sched_data msd = {
+		.can_add_hw = 1,
+		.event_type = event_type,
+	};
 	visit_groups_merge(ctx, groups, smp_processor_id(), pmu,
-			   merge_sched_in, &can_add_hw);
+			   merge_sched_in, &msd);
 }
 
 static void __pmu_ctx_sched_in(struct perf_event_pmu_context *pmu_ctx,
@@ -4050,9 +4162,9 @@ static void __pmu_ctx_sched_in(struct perf_event_pmu_context *pmu_ctx,
 	struct perf_event_context *ctx = pmu_ctx->ctx;
 
 	if (event_type & EVENT_PINNED)
-		pmu_groups_sched_in(ctx, &ctx->pinned_groups, pmu_ctx->pmu);
+		pmu_groups_sched_in(ctx, &ctx->pinned_groups, pmu_ctx->pmu, event_type);
 	if (event_type & EVENT_FLEXIBLE)
-		pmu_groups_sched_in(ctx, &ctx->flexible_groups, pmu_ctx->pmu);
+		pmu_groups_sched_in(ctx, &ctx->flexible_groups, pmu_ctx->pmu, event_type);
 }
 
 static void
@@ -4069,9 +4181,11 @@ ctx_sched_in(struct perf_event_context *ctx, struct pmu *pmu, enum event_type_t
 		return;
 
 	if (!(is_active & EVENT_TIME)) {
+		/* EVENT_TIME should be active while the guest runs */
+		WARN_ON_ONCE(event_type & EVENT_GUEST);
 		/* start ctx time */
 		__update_context_time(ctx, false);
-		perf_cgroup_set_timestamp(cpuctx);
+		perf_cgroup_set_timestamp(cpuctx, false);
 		/*
 		 * CPU-release for the below ->is_active store,
 		 * see __load_acquire() in perf_event_time_now()
@@ -4087,7 +4201,23 @@ ctx_sched_in(struct perf_event_context *ctx, struct pmu *pmu, enum event_type_t
 			WARN_ON_ONCE(cpuctx->task_ctx != ctx);
 	}
 
-	is_active ^= ctx->is_active; /* changed bits */
+	if (event_type & EVENT_GUEST) {
+		/*
+		 * Schedule in the required exclude_guest events of PMU
+		 * with PERF_PMU_CAP_MEDIATED_VPMU.
+		 */
+		is_active = event_type & EVENT_ALL;
+
+		/*
+		 * Update ctx time to set the new start time for
+		 * the exclude_guest events.
+		 */
+		update_context_time(ctx);
+		update_cgrp_time_from_cpuctx(cpuctx, false);
+		barrier();
+	} else {
+		is_active ^= ctx->is_active; /* changed bits */
+	}
 
 	/*
 	 * First go through the list and put on any pinned groups
@@ -4095,13 +4225,13 @@ ctx_sched_in(struct perf_event_context *ctx, struct pmu *pmu, enum event_type_t
 	 */
 	if (is_active & EVENT_PINNED) {
 		for_each_epc(pmu_ctx, ctx, pmu, event_type)
-			__pmu_ctx_sched_in(pmu_ctx, EVENT_PINNED);
+			__pmu_ctx_sched_in(pmu_ctx, EVENT_PINNED | (event_type & EVENT_GUEST));
 	}
 
 	/* Then walk through the lower prio flexible groups */
 	if (is_active & EVENT_FLEXIBLE) {
 		for_each_epc(pmu_ctx, ctx, pmu, event_type)
-			__pmu_ctx_sched_in(pmu_ctx, EVENT_FLEXIBLE);
+			__pmu_ctx_sched_in(pmu_ctx, EVENT_FLEXIBLE | (event_type & EVENT_GUEST));
 	}
 }
 
@@ -6627,23 +6757,23 @@ void perf_event_update_userpage(struct perf_event *event)
 	if (!rb)
 		goto unlock;
 
-	/*
-	 * compute total_time_enabled, total_time_running
-	 * based on snapshot values taken when the event
-	 * was last scheduled in.
-	 *
-	 * we cannot simply called update_context_time()
-	 * because of locking issue as we can be called in
-	 * NMI context
-	 */
-	calc_timer_values(event, &now, &enabled, &running);
-
-	userpg = rb->user_page;
 	/*
 	 * Disable preemption to guarantee consistent time stamps are stored to
 	 * the user page.
 	 */
 	preempt_disable();
+
+	/*
+	 * Compute total_time_enabled, total_time_running based on snapshot
+	 * values taken when the event was last scheduled in.
+	 *
+	 * We cannot simply call update_context_time() because doing so would
+	 * lead to deadlock when called from NMI context.
+	 */
+	calc_timer_values(event, &now, &enabled, &running);
+
+	userpg = rb->user_page;
+
 	++userpg->lock;
 	barrier();
 	userpg->index = perf_event_index(event);
@@ -7940,13 +8070,11 @@ static void perf_output_read(struct perf_output_handle *handle,
 	u64 read_format = event->attr.read_format;
 
 	/*
-	 * compute total_time_enabled, total_time_running
-	 * based on snapshot values taken when the event
-	 * was last scheduled in.
+	 * Compute total_time_enabled, total_time_running based on snapshot
+	 * values taken when the event was last scheduled in.
 	 *
-	 * we cannot simply called update_context_time()
-	 * because of locking issue as we are called in
-	 * NMI context
+	 * We cannot simply call update_context_time() because doing so would
+	 * lead to deadlock when called from NMI context.
 	 */
 	if (read_format & PERF_FORMAT_TOTAL_TIMES)
 		calc_timer_values(event, &now, &enabled, &running);
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:16:43 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:16:43 -0800
Subject: [PATCH v6 07/44] perf: Add APIs to load/put guest mediated PMU context
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-8-seanjc@google.com>

From: Kan Liang <kan.liang at linux.intel.com>

Add exported APIs to load/put a guest mediated PMU context.  KVM will
load the guest PMU shortly before VM-Enter, and put the guest PMU shortly
after VM-Exit.

On the perf side of things, schedule out all exclude_guest events when the
guest context is loaded, and schedule them back in when the guest context
is put.  I.e. yield the hardware PMU resources to the guest, by way of KVM.

Note, perf is only responsible for managing host context.  KVM is
responsible for loading/storing guest state to/from hardware.

Suggested-by: Sean Christopherson <seanjc at google.com>
Signed-off-by: Kan Liang <kan.liang at linux.intel.com>
Signed-off-by: Mingwei Zhang <mizhang at google.com>
[sean: shuffle patches around, write changelog]
Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 include/linux/perf_event.h |  2 ++
 kernel/events/core.c       | 61 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 63 insertions(+)

diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index eaab830c9bf5..cfc8cd86c409 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -1925,6 +1925,8 @@ extern u64 perf_event_pause(struct perf_event *event, bool reset);
 #ifdef CONFIG_PERF_GUEST_MEDIATED_PMU
 int perf_create_mediated_pmu(void);
 void perf_release_mediated_pmu(void);
+void perf_load_guest_context(void);
+void perf_put_guest_context(void);
 #endif
 
 #else /* !CONFIG_PERF_EVENTS: */
diff --git a/kernel/events/core.c b/kernel/events/core.c
index f72d4844b05e..81c35859e6ea 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -469,10 +469,19 @@ static cpumask_var_t perf_online_pkg_mask;
 static cpumask_var_t perf_online_sys_mask;
 static struct kmem_cache *perf_event_cache;
 
+#ifdef CONFIG_PERF_GUEST_MEDIATED_PMU
+static DEFINE_PER_CPU(bool, guest_ctx_loaded);
+
+static __always_inline bool is_guest_mediated_pmu_loaded(void)
+{
+	return __this_cpu_read(guest_ctx_loaded);
+}
+#else
 static __always_inline bool is_guest_mediated_pmu_loaded(void)
 {
 	return false;
 }
+#endif
 
 /*
  * perf event paranoia level:
@@ -6385,6 +6394,58 @@ void perf_release_mediated_pmu(void)
 	atomic_dec(&nr_mediated_pmu_vms);
 }
 EXPORT_SYMBOL_GPL(perf_release_mediated_pmu);
+
+/* When loading a guest's mediated PMU, schedule out all exclude_guest events. */
+void perf_load_guest_context(void)
+{
+	struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context);
+
+	lockdep_assert_irqs_disabled();
+
+	guard(perf_ctx_lock)(cpuctx, cpuctx->task_ctx);
+
+	if (WARN_ON_ONCE(__this_cpu_read(guest_ctx_loaded)))
+		return;
+
+	perf_ctx_disable(&cpuctx->ctx, EVENT_GUEST);
+	ctx_sched_out(&cpuctx->ctx, NULL, EVENT_GUEST);
+	if (cpuctx->task_ctx) {
+		perf_ctx_disable(cpuctx->task_ctx, EVENT_GUEST);
+		task_ctx_sched_out(cpuctx->task_ctx, NULL, EVENT_GUEST);
+	}
+
+	perf_ctx_enable(&cpuctx->ctx, EVENT_GUEST);
+	if (cpuctx->task_ctx)
+		perf_ctx_enable(cpuctx->task_ctx, EVENT_GUEST);
+
+	__this_cpu_write(guest_ctx_loaded, true);
+}
+EXPORT_SYMBOL_GPL(perf_load_guest_context);
+
+void perf_put_guest_context(void)
+{
+	struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context);
+
+	lockdep_assert_irqs_disabled();
+
+	guard(perf_ctx_lock)(cpuctx, cpuctx->task_ctx);
+
+	if (WARN_ON_ONCE(!__this_cpu_read(guest_ctx_loaded)))
+		return;
+
+	perf_ctx_disable(&cpuctx->ctx, EVENT_GUEST);
+	if (cpuctx->task_ctx)
+		perf_ctx_disable(cpuctx->task_ctx, EVENT_GUEST);
+
+	perf_event_sched_in(cpuctx, cpuctx->task_ctx, NULL, EVENT_GUEST);
+
+	if (cpuctx->task_ctx)
+		perf_ctx_enable(cpuctx->task_ctx, EVENT_GUEST);
+	perf_ctx_enable(&cpuctx->ctx, EVENT_GUEST);
+
+	__this_cpu_write(guest_ctx_loaded, false);
+}
+EXPORT_SYMBOL_GPL(perf_put_guest_context);
 #else
 static int mediated_pmu_account_event(struct perf_event *event) { return 0; }
 static void mediated_pmu_unaccount_event(struct perf_event *event) {}
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:16:44 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:16:44 -0800
Subject: [PATCH v6 08/44] perf/x86/core: Register a new vector for handling
 mediated guest PMIs
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-9-seanjc@google.com>

Wire up system vector 0xf5 for handling PMIs (i.e. interrupts delivered
through the LVTPC) while running KVM guests with a mediated PMU.  Perf
currently delivers all PMIs as NMIs, e.g. so that events that trigger while
IRQs are disabled aren't delayed and generate useless records, but due to
the multiplexing of NMIs throughout the system, correctly identifying NMIs
for a mediated PMU is practically infeasible.

To (greatly) simplify identifying guest mediated PMU PMIs, perf will
switch the CPU's LVTPC between PERF_GUEST_MEDIATED_PMI_VECTOR and NMI when
guest PMU context is loaded/put.  I.e. PMIs that are generated by the CPU
while the guest is active will be identified purely based on the IRQ
vector.

Route the vector through perf, e.g. as opposed to letting KVM attach a
handler directly a la posted interrupt notification vectors, as perf owns
the LVTPC and thus is the rightful owner of PERF_GUEST_MEDIATED_PMI_VECTOR.
Functionally, having KVM directly own the vector would be fine (both KVM
and perf will be completely aware of when a mediated PMU is active), but
would lead to an undesirable split in ownership: perf would be responsible
for installing the vector, but not handling the resulting IRQs.

Add a new perf_guest_info_callbacks hook (and static call) to allow KVM to
register its handler with perf when running guests with mediated PMUs.

Note, because KVM always runs guests with host IRQs enabled, there is no
danger of a PMI being delayed from the guest's perspective due to using a
regular IRQ instead of an NMI.

Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/entry/entry_fred.c                   |  1 +
 arch/x86/include/asm/hardirq.h                |  3 +++
 arch/x86/include/asm/idtentry.h               |  6 ++++++
 arch/x86/include/asm/irq_vectors.h            |  4 +++-
 arch/x86/kernel/idt.c                         |  3 +++
 arch/x86/kernel/irq.c                         | 19 +++++++++++++++++++
 include/linux/perf_event.h                    |  8 ++++++++
 kernel/events/core.c                          |  9 +++++++--
 .../beauty/arch/x86/include/asm/irq_vectors.h |  3 ++-
 virt/kvm/kvm_main.c                           |  3 +++
 10 files changed, 55 insertions(+), 4 deletions(-)

diff --git a/arch/x86/entry/entry_fred.c b/arch/x86/entry/entry_fred.c
index f004a4dc74c2..d80861a4cd00 100644
--- a/arch/x86/entry/entry_fred.c
+++ b/arch/x86/entry/entry_fred.c
@@ -114,6 +114,7 @@ static idtentry_t sysvec_table[NR_SYSTEM_VECTORS] __ro_after_init = {
 
 	SYSVEC(IRQ_WORK_VECTOR,			irq_work),
 
+	SYSVEC(PERF_GUEST_MEDIATED_PMI_VECTOR,	perf_guest_mediated_pmi_handler),
 	SYSVEC(POSTED_INTR_VECTOR,		kvm_posted_intr_ipi),
 	SYSVEC(POSTED_INTR_WAKEUP_VECTOR,	kvm_posted_intr_wakeup_ipi),
 	SYSVEC(POSTED_INTR_NESTED_VECTOR,	kvm_posted_intr_nested_ipi),
diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h
index 6b6d472baa0b..9314642ae93c 100644
--- a/arch/x86/include/asm/hardirq.h
+++ b/arch/x86/include/asm/hardirq.h
@@ -18,6 +18,9 @@ typedef struct {
 	unsigned int kvm_posted_intr_ipis;
 	unsigned int kvm_posted_intr_wakeup_ipis;
 	unsigned int kvm_posted_intr_nested_ipis;
+#endif
+#ifdef CONFIG_GUEST_PERF_EVENTS
+	unsigned int perf_guest_mediated_pmis;
 #endif
 	unsigned int x86_platform_ipis;	/* arch dependent */
 	unsigned int apic_perf_irqs;
diff --git a/arch/x86/include/asm/idtentry.h b/arch/x86/include/asm/idtentry.h
index abd637e54e94..e64294c906bc 100644
--- a/arch/x86/include/asm/idtentry.h
+++ b/arch/x86/include/asm/idtentry.h
@@ -746,6 +746,12 @@ DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_NESTED_VECTOR,	sysvec_kvm_posted_intr_nested
 # define fred_sysvec_kvm_posted_intr_nested_ipi		NULL
 #endif
 
+# ifdef CONFIG_GUEST_PERF_EVENTS
+DECLARE_IDTENTRY_SYSVEC(PERF_GUEST_MEDIATED_PMI_VECTOR,	sysvec_perf_guest_mediated_pmi_handler);
+#else
+# define fred_sysvec_perf_guest_mediated_pmi_handler	NULL
+#endif
+
 # ifdef CONFIG_X86_POSTED_MSI
 DECLARE_IDTENTRY_SYSVEC(POSTED_MSI_NOTIFICATION_VECTOR,	sysvec_posted_msi_notification);
 #else
diff --git a/arch/x86/include/asm/irq_vectors.h b/arch/x86/include/asm/irq_vectors.h
index 47051871b436..85253fc8e384 100644
--- a/arch/x86/include/asm/irq_vectors.h
+++ b/arch/x86/include/asm/irq_vectors.h
@@ -77,7 +77,9 @@
  */
 #define IRQ_WORK_VECTOR			0xf6
 
-/* 0xf5 - unused, was UV_BAU_MESSAGE */
+/* IRQ vector for PMIs when running a guest with a mediated PMU. */
+#define PERF_GUEST_MEDIATED_PMI_VECTOR	0xf5
+
 #define DEFERRED_ERROR_VECTOR		0xf4
 
 /* Vector on which hypervisor callbacks will be delivered */
diff --git a/arch/x86/kernel/idt.c b/arch/x86/kernel/idt.c
index f445bec516a0..260456588756 100644
--- a/arch/x86/kernel/idt.c
+++ b/arch/x86/kernel/idt.c
@@ -158,6 +158,9 @@ static const __initconst struct idt_data apic_idts[] = {
 	INTG(POSTED_INTR_WAKEUP_VECTOR,		asm_sysvec_kvm_posted_intr_wakeup_ipi),
 	INTG(POSTED_INTR_NESTED_VECTOR,		asm_sysvec_kvm_posted_intr_nested_ipi),
 # endif
+#ifdef CONFIG_GUEST_PERF_EVENTS
+	INTG(PERF_GUEST_MEDIATED_PMI_VECTOR,	asm_sysvec_perf_guest_mediated_pmi_handler),
+#endif
 # ifdef CONFIG_IRQ_WORK
 	INTG(IRQ_WORK_VECTOR,			asm_sysvec_irq_work),
 # endif
diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
index 10721a125226..e9050e69717e 100644
--- a/arch/x86/kernel/irq.c
+++ b/arch/x86/kernel/irq.c
@@ -191,6 +191,13 @@ int arch_show_interrupts(struct seq_file *p, int prec)
 			   irq_stats(j)->kvm_posted_intr_wakeup_ipis);
 	seq_puts(p, "  Posted-interrupt wakeup event\n");
 #endif
+#ifdef CONFIG_GUEST_PERF_EVENTS
+	seq_printf(p, "%*s: ", prec, "VPMI");
+	for_each_online_cpu(j)
+		seq_printf(p, "%10u ",
+			   irq_stats(j)->perf_guest_mediated_pmis);
+	seq_puts(p, " Perf Guest Mediated PMI\n");
+#endif
 #ifdef CONFIG_X86_POSTED_MSI
 	seq_printf(p, "%*s: ", prec, "PMN");
 	for_each_online_cpu(j)
@@ -348,6 +355,18 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_x86_platform_ipi)
 }
 #endif
 
+#ifdef CONFIG_GUEST_PERF_EVENTS
+/*
+ * Handler for PERF_GUEST_MEDIATED_PMI_VECTOR.
+ */
+DEFINE_IDTENTRY_SYSVEC(sysvec_perf_guest_mediated_pmi_handler)
+{
+	 apic_eoi();
+	 inc_irq_stat(perf_guest_mediated_pmis);
+	 perf_guest_handle_mediated_pmi();
+}
+#endif
+
 #if IS_ENABLED(CONFIG_KVM)
 static void dummy_handler(void) {}
 static void (*kvm_posted_intr_wakeup_handler)(void) = dummy_handler;
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index cfc8cd86c409..9abfca6cf655 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -1677,6 +1677,8 @@ struct perf_guest_info_callbacks {
 	unsigned int			(*state)(void);
 	unsigned long			(*get_ip)(void);
 	unsigned int			(*handle_intel_pt_intr)(void);
+
+	void				(*handle_mediated_pmi)(void);
 };
 
 #ifdef CONFIG_GUEST_PERF_EVENTS
@@ -1686,6 +1688,7 @@ extern struct perf_guest_info_callbacks __rcu *perf_guest_cbs;
 DECLARE_STATIC_CALL(__perf_guest_state, *perf_guest_cbs->state);
 DECLARE_STATIC_CALL(__perf_guest_get_ip, *perf_guest_cbs->get_ip);
 DECLARE_STATIC_CALL(__perf_guest_handle_intel_pt_intr, *perf_guest_cbs->handle_intel_pt_intr);
+DECLARE_STATIC_CALL(__perf_guest_handle_mediated_pmi, *perf_guest_cbs->handle_mediated_pmi);
 
 static inline unsigned int perf_guest_state(void)
 {
@@ -1702,6 +1705,11 @@ static inline unsigned int perf_guest_handle_intel_pt_intr(void)
 	return static_call(__perf_guest_handle_intel_pt_intr)();
 }
 
+static inline void perf_guest_handle_mediated_pmi(void)
+{
+	static_call(__perf_guest_handle_mediated_pmi)();
+}
+
 extern void perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *cbs);
 extern void perf_unregister_guest_info_callbacks(struct perf_guest_info_callbacks *cbs);
 
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 81c35859e6ea..c6368c64b866 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -7645,6 +7645,7 @@ struct perf_guest_info_callbacks __rcu *perf_guest_cbs;
 DEFINE_STATIC_CALL_RET0(__perf_guest_state, *perf_guest_cbs->state);
 DEFINE_STATIC_CALL_RET0(__perf_guest_get_ip, *perf_guest_cbs->get_ip);
 DEFINE_STATIC_CALL_RET0(__perf_guest_handle_intel_pt_intr, *perf_guest_cbs->handle_intel_pt_intr);
+DEFINE_STATIC_CALL_RET0(__perf_guest_handle_mediated_pmi, *perf_guest_cbs->handle_mediated_pmi);
 
 void perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *cbs)
 {
@@ -7659,6 +7660,10 @@ void perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *cbs)
 	if (cbs->handle_intel_pt_intr)
 		static_call_update(__perf_guest_handle_intel_pt_intr,
 				   cbs->handle_intel_pt_intr);
+
+	if (cbs->handle_mediated_pmi)
+		static_call_update(__perf_guest_handle_mediated_pmi,
+				   cbs->handle_mediated_pmi);
 }
 EXPORT_SYMBOL_GPL(perf_register_guest_info_callbacks);
 
@@ -7670,8 +7675,8 @@ void perf_unregister_guest_info_callbacks(struct perf_guest_info_callbacks *cbs)
 	rcu_assign_pointer(perf_guest_cbs, NULL);
 	static_call_update(__perf_guest_state, (void *)&__static_call_return0);
 	static_call_update(__perf_guest_get_ip, (void *)&__static_call_return0);
-	static_call_update(__perf_guest_handle_intel_pt_intr,
-			   (void *)&__static_call_return0);
+	static_call_update(__perf_guest_handle_intel_pt_intr, (void *)&__static_call_return0);
+	static_call_update(__perf_guest_handle_mediated_pmi, (void *)&__static_call_return0);
 	synchronize_rcu();
 }
 EXPORT_SYMBOL_GPL(perf_unregister_guest_info_callbacks);
diff --git a/tools/perf/trace/beauty/arch/x86/include/asm/irq_vectors.h b/tools/perf/trace/beauty/arch/x86/include/asm/irq_vectors.h
index 47051871b436..6e1d5b955aae 100644
--- a/tools/perf/trace/beauty/arch/x86/include/asm/irq_vectors.h
+++ b/tools/perf/trace/beauty/arch/x86/include/asm/irq_vectors.h
@@ -77,7 +77,8 @@
  */
 #define IRQ_WORK_VECTOR			0xf6
 
-/* 0xf5 - unused, was UV_BAU_MESSAGE */
+#define PERF_GUEST_MEDIATED_PMI_VECTOR	0xf5
+
 #define DEFERRED_ERROR_VECTOR		0xf4
 
 /* Vector on which hypervisor callbacks will be delivered */
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index f1f6a71b2b5f..4954cbbb05e8 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -6471,11 +6471,14 @@ static struct perf_guest_info_callbacks kvm_guest_cbs = {
 	.state			= kvm_guest_state,
 	.get_ip			= kvm_guest_get_ip,
 	.handle_intel_pt_intr	= NULL,
+	.handle_mediated_pmi	= NULL,
 };
 
 void kvm_register_perf_callbacks(unsigned int (*pt_intr_handler)(void))
 {
 	kvm_guest_cbs.handle_intel_pt_intr = pt_intr_handler;
+	kvm_guest_cbs.handle_mediated_pmi = NULL;
+
 	perf_register_guest_info_callbacks(&kvm_guest_cbs);
 }
 void kvm_unregister_perf_callbacks(void)
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:16:45 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:16:45 -0800
Subject: [PATCH v6 09/44] perf/x86/core: Add APIs to switch to/from mediated
 PMI vector (for KVM)
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-10-seanjc@google.com>

Add APIs (exported only for KVM) to switch PMIs to the dedicated mediated
PMU IRQ vector when loading guest context, and back to perf's standard NMI
when the guest context is put.  I.e. route PMIs to
PERF_GUEST_MEDIATED_PMI_VECTOR when the guest context is active, and to
NMIs while the host context is active.

While running with guest context loaded, ignore all NMIs (in perf).  Any
NMI that arrives while the LVTPC points at the mediated PMU IRQ vector
can't possibly be due to a host perf event.

Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/events/core.c            | 32 +++++++++++++++++++++++++++++++
 arch/x86/include/asm/perf_event.h |  5 +++++
 2 files changed, 37 insertions(+)

diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index fa6c47b50989..abe6a129a87f 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -55,6 +55,8 @@ DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = {
 	.pmu = &pmu,
 };
 
+static DEFINE_PER_CPU(bool, guest_lvtpc_loaded);
+
 DEFINE_STATIC_KEY_FALSE(rdpmc_never_available_key);
 DEFINE_STATIC_KEY_FALSE(rdpmc_always_available_key);
 DEFINE_STATIC_KEY_FALSE(perf_is_hybrid);
@@ -1749,6 +1751,25 @@ void perf_events_lapic_init(void)
 	apic_write(APIC_LVTPC, APIC_DM_NMI);
 }
 
+#ifdef CONFIG_PERF_GUEST_MEDIATED_PMU
+void perf_load_guest_lvtpc(u32 guest_lvtpc)
+{
+	u32 masked = guest_lvtpc & APIC_LVT_MASKED;
+
+	apic_write(APIC_LVTPC,
+		   APIC_DM_FIXED | PERF_GUEST_MEDIATED_PMI_VECTOR | masked);
+	this_cpu_write(guest_lvtpc_loaded, true);
+}
+EXPORT_SYMBOL_FOR_MODULES(perf_load_guest_lvtpc, "kvm");
+
+void perf_put_guest_lvtpc(void)
+{
+	this_cpu_write(guest_lvtpc_loaded, false);
+	apic_write(APIC_LVTPC, APIC_DM_NMI);
+}
+EXPORT_SYMBOL_FOR_MODULES(perf_put_guest_lvtpc, "kvm");
+#endif /* CONFIG_PERF_GUEST_MEDIATED_PMU */
+
 static int
 perf_event_nmi_handler(unsigned int cmd, struct pt_regs *regs)
 {
@@ -1756,6 +1777,17 @@ perf_event_nmi_handler(unsigned int cmd, struct pt_regs *regs)
 	u64 finish_clock;
 	int ret;
 
+	/*
+	 * Ignore all NMIs when the CPU's LVTPC is configured to route PMIs to
+	 * PERF_GUEST_MEDIATED_PMI_VECTOR, i.e. when an NMI time can't be due
+	 * to a PMI.  Attempting to handle a PMI while the guest's context is
+	 * loaded will generate false positives and clobber guest state.  Note,
+	 * the LVTPC is switched to/from the dedicated mediated PMI IRQ vector
+	 * while host events are quiesced.
+	 */
+	if (this_cpu_read(guest_lvtpc_loaded))
+		return NMI_DONE;
+
 	/*
 	 * All PMUs/events that share this PMI handler should make sure to
 	 * increment active_events for their events.
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h
index 49a4d442f3fc..4cd38b9da0ba 100644
--- a/arch/x86/include/asm/perf_event.h
+++ b/arch/x86/include/asm/perf_event.h
@@ -651,6 +651,11 @@ static inline void perf_events_lapic_init(void)	{ }
 static inline void perf_check_microcode(void) { }
 #endif
 
+#ifdef CONFIG_PERF_GUEST_MEDIATED_PMU
+extern void perf_load_guest_lvtpc(u32 guest_lvtpc);
+extern void perf_put_guest_lvtpc(void);
+#endif
+
 #if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_INTEL)
 extern struct perf_guest_switch_msr *perf_guest_get_msrs(int *nr, void *data);
 extern void x86_perf_get_lbr(struct x86_pmu_lbr *lbr);
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:16:46 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:16:46 -0800
Subject: [PATCH v6 10/44] perf/x86/core: Do not set bit width for unavailable counters
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-11-seanjc@google.com>

From: Sandipan Das <sandipan.das at amd.com>

Not all x86 processors have fixed counters. It may also be the case that
a processor has only fixed counters and no general-purpose counters. Set
the bit widths corresponding to each counter type only if such counters
are available.

Fixes: b3d9468a8bd2 ("perf, x86: Expose perf capability to other modules")
Signed-off-by: Sandipan Das <sandipan.das at amd.com>
Co-developed-by: Dapeng Mi <dapeng1.mi at linux.intel.com>
Signed-off-by: Dapeng Mi <dapeng1.mi at linux.intel.com>
Signed-off-by: Mingwei Zhang <mizhang at google.com>
Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/events/core.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index abe6a129a87f..bd9abe298469 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -3132,8 +3132,8 @@ void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap)
 	cap->version		= x86_pmu.version;
 	cap->num_counters_gp	= x86_pmu_num_counters(NULL);
 	cap->num_counters_fixed	= x86_pmu_num_counters_fixed(NULL);
-	cap->bit_width_gp	= x86_pmu.cntval_bits;
-	cap->bit_width_fixed	= x86_pmu.cntval_bits;
+	cap->bit_width_gp	= cap->num_counters_gp ? x86_pmu.cntval_bits : 0;
+	cap->bit_width_fixed	= cap->num_counters_fixed ? x86_pmu.cntval_bits : 0;
 	cap->events_mask	= (unsigned int)x86_pmu.events_maskl;
 	cap->events_mask_len	= x86_pmu.events_mask_len;
 	cap->pebs_ept		= x86_pmu.pebs_ept;
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:16:47 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:16:47 -0800
Subject: [PATCH v6 11/44] perf/x86/core: Plumb mediated PMU capability from
 x86_pmu to x86_pmu_cap
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-12-seanjc@google.com>

From: Mingwei Zhang <mizhang at google.com>

Plumb mediated PMU capability to x86_pmu_cap in order to let any kernel
entity such as KVM know that host PMU support mediated PMU mode and has
the implementation.

Signed-off-by: Mingwei Zhang <mizhang at google.com>
Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/events/core.c            | 1 +
 arch/x86/include/asm/perf_event.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index bd9abe298469..1b50f0117876 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -3137,6 +3137,7 @@ void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap)
 	cap->events_mask	= (unsigned int)x86_pmu.events_maskl;
 	cap->events_mask_len	= x86_pmu.events_mask_len;
 	cap->pebs_ept		= x86_pmu.pebs_ept;
+	cap->mediated		= !!(pmu.capabilities & PERF_PMU_CAP_MEDIATED_VPMU);
 }
 EXPORT_SYMBOL_GPL(perf_get_x86_pmu_capability);
 
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h
index 4cd38b9da0ba..4714bdee17b2 100644
--- a/arch/x86/include/asm/perf_event.h
+++ b/arch/x86/include/asm/perf_event.h
@@ -296,6 +296,7 @@ struct x86_pmu_capability {
 	unsigned int	events_mask;
 	int		events_mask_len;
 	unsigned int	pebs_ept	:1;
+	unsigned int	mediated	:1;
 };
 
 /*
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:16:48 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:16:48 -0800
Subject: [PATCH v6 12/44] perf/x86/intel: Support PERF_PMU_CAP_MEDIATED_VPMU
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-13-seanjc@google.com>

From: Kan Liang <kan.liang at linux.intel.com>

Apply the PERF_PMU_CAP_MEDIATED_VPMU for Intel core PMU. It only indicates
that the perf side of core PMU is ready to support the mediated vPMU.
Besides the capability, the hypervisor, a.k.a. KVM, still needs to check
the PMU version and other PMU features/capabilities to decide whether to
enable support mediated vPMUs.

Signed-off-by: Kan Liang <kan.liang at linux.intel.com>
Signed-off-by: Mingwei Zhang <mizhang at google.com>
[sean: massage changelog]
Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/events/intel/core.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
index fe65be0b9d9c..5d53da858714 100644
--- a/arch/x86/events/intel/core.c
+++ b/arch/x86/events/intel/core.c
@@ -5319,6 +5319,8 @@ static void intel_pmu_check_hybrid_pmus(struct x86_hybrid_pmu *pmu)
 	else
 		pmu->intel_ctrl &= ~GLOBAL_CTRL_EN_PERF_METRICS;
 
+	pmu->pmu.capabilities |= PERF_PMU_CAP_MEDIATED_VPMU;
+
 	intel_pmu_check_event_constraints(pmu->event_constraints,
 					  pmu->cntr_mask64,
 					  pmu->fixed_cntr_mask64,
@@ -6936,6 +6938,9 @@ __init int intel_pmu_init(void)
 			pr_cont(" AnyThread deprecated, ");
 	}
 
+	/* The perf side of core PMU is ready to support the mediated vPMU. */
+	x86_get_pmu(smp_processor_id())->capabilities |= PERF_PMU_CAP_MEDIATED_VPMU;
+
 	/*
 	 * Many features on and after V6 require dynamic constraint,
 	 * e.g., Arch PEBS, ACR.
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:16:49 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:16:49 -0800
Subject: [PATCH v6 13/44] perf/x86/amd: Support PERF_PMU_CAP_MEDIATED_VPMU for
 AMD host
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-14-seanjc@google.com>

From: Sandipan Das <sandipan.das at amd.com>

Apply the PERF_PMU_CAP_MEDIATED_VPMU flag for version 2 and later
implementations of the core PMU. Aside from having Global Control and
Status registers, virtualizing the PMU using the mediated model requires
an interface to set or clear the overflow bits in the Global Status MSRs
while restoring or saving the PMU context of a vCPU.

PerfMonV2-capable hardware has additional MSRs for this purpose, namely
PerfCntrGlobalStatusSet and PerfCntrGlobalStatusClr, thereby making it
suitable for use with mediated vPMU.

Signed-off-by: Sandipan Das <sandipan.das at amd.com>
Signed-off-by: Mingwei Zhang <mizhang at google.com>
Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/events/amd/core.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/x86/events/amd/core.c b/arch/x86/events/amd/core.c
index b20661b8621d..8179fb5f1ee3 100644
--- a/arch/x86/events/amd/core.c
+++ b/arch/x86/events/amd/core.c
@@ -1433,6 +1433,8 @@ static int __init amd_core_pmu_init(void)
 
 		amd_pmu_global_cntr_mask = x86_pmu.cntr_mask64;
 
+		x86_get_pmu(smp_processor_id())->capabilities |= PERF_PMU_CAP_MEDIATED_VPMU;
+
 		/* Update PMC handling functions */
 		x86_pmu.enable_all = amd_pmu_v2_enable_all;
 		x86_pmu.disable_all = amd_pmu_v2_disable_all;
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:16:50 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:16:50 -0800
Subject: [PATCH v6 14/44] KVM: Add a simplified wrapper for registering perf callbacks
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-15-seanjc@google.com>

Add a parameter-less API for registering perf callbacks in anticipation of
introducing another x86-only parameter for handling mediated PMU PMIs.

No functional change intended.

Acked-by: Anup Patel <anup at brainfault.org>
Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/arm64/kvm/arm.c      |  2 +-
 arch/loongarch/kvm/main.c |  2 +-
 arch/riscv/kvm/main.c     |  2 +-
 arch/x86/kvm/x86.c        |  2 +-
 include/linux/kvm_host.h  | 11 +++++++++--
 virt/kvm/kvm_main.c       |  5 +++--
 6 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 97627638e802..153166ca626a 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -2357,7 +2357,7 @@ static int __init init_subsystems(void)
 	if (err)
 		goto out;
 
-	kvm_register_perf_callbacks(NULL);
+	kvm_register_perf_callbacks();
 
 out:
 	if (err)
diff --git a/arch/loongarch/kvm/main.c b/arch/loongarch/kvm/main.c
index 80ea63d465b8..f62326fe29fa 100644
--- a/arch/loongarch/kvm/main.c
+++ b/arch/loongarch/kvm/main.c
@@ -394,7 +394,7 @@ static int kvm_loongarch_env_init(void)
 	}
 
 	kvm_init_gcsr_flag();
-	kvm_register_perf_callbacks(NULL);
+	kvm_register_perf_callbacks();
 
 	/* Register LoongArch IPI interrupt controller interface. */
 	ret = kvm_loongarch_register_ipi_device();
diff --git a/arch/riscv/kvm/main.c b/arch/riscv/kvm/main.c
index 45536af521f0..0f3fe3986fc0 100644
--- a/arch/riscv/kvm/main.c
+++ b/arch/riscv/kvm/main.c
@@ -174,7 +174,7 @@ static int __init riscv_kvm_init(void)
 
 	kvm_riscv_setup_vendor_features();
 
-	kvm_register_perf_callbacks(NULL);
+	kvm_register_perf_callbacks();
 
 	rc = kvm_init(sizeof(struct kvm_vcpu), 0, THIS_MODULE);
 	if (rc) {
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 0c6d899d53dd..1b2827cecf38 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -10107,7 +10107,7 @@ int kvm_x86_vendor_init(struct kvm_x86_init_ops *ops)
 		set_hv_tscchange_cb(kvm_hyperv_tsc_notifier);
 #endif
 
-	kvm_register_perf_callbacks(ops->handle_intel_pt_intr);
+	__kvm_register_perf_callbacks(ops->handle_intel_pt_intr, NULL);
 
 	if (IS_ENABLED(CONFIG_KVM_SW_PROTECTED_VM) && tdp_mmu_enabled)
 		kvm_caps.supported_vm_types |= BIT(KVM_X86_SW_PROTECTED_VM);
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index d93f75b05ae2..8e410d1a63df 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -1749,10 +1749,17 @@ static inline bool kvm_arch_intc_initialized(struct kvm *kvm)
 #ifdef CONFIG_GUEST_PERF_EVENTS
 unsigned long kvm_arch_vcpu_get_ip(struct kvm_vcpu *vcpu);
 
-void kvm_register_perf_callbacks(unsigned int (*pt_intr_handler)(void));
+void __kvm_register_perf_callbacks(unsigned int (*pt_intr_handler)(void),
+				   void (*mediated_pmi_handler)(void));
+
+static inline void kvm_register_perf_callbacks(void)
+{
+	__kvm_register_perf_callbacks(NULL, NULL);
+}
+
 void kvm_unregister_perf_callbacks(void);
 #else
-static inline void kvm_register_perf_callbacks(void *ign) {}
+static inline void kvm_register_perf_callbacks(void) {}
 static inline void kvm_unregister_perf_callbacks(void) {}
 #endif /* CONFIG_GUEST_PERF_EVENTS */
 
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 4954cbbb05e8..16b24da9cda5 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -6474,10 +6474,11 @@ static struct perf_guest_info_callbacks kvm_guest_cbs = {
 	.handle_mediated_pmi	= NULL,
 };
 
-void kvm_register_perf_callbacks(unsigned int (*pt_intr_handler)(void))
+void __kvm_register_perf_callbacks(unsigned int (*pt_intr_handler)(void),
+				   void (*mediated_pmi_handler)(void))
 {
 	kvm_guest_cbs.handle_intel_pt_intr = pt_intr_handler;
-	kvm_guest_cbs.handle_mediated_pmi = NULL;
+	kvm_guest_cbs.handle_mediated_pmi = mediated_pmi_handler;
 
 	perf_register_guest_info_callbacks(&kvm_guest_cbs);
 }
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:16:51 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:16:51 -0800
Subject: [PATCH v6 15/44] KVM: x86/pmu: Snapshot host (i.e. perf's) reported
 PMU capabilities
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-16-seanjc@google.com>

Take a snapshot of the unadulterated PMU capabilities provided by perf so
that KVM can compare guest vPMU capabilities against hardware capabilities
when determining whether or not to intercept PMU MSRs (and RDPMC).

Reviewed-by: Sandipan Das <sandipan.das at amd.com>
Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/kvm/pmu.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index 487ad19a236e..7c219305b61d 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -108,6 +108,8 @@ void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops)
 	bool is_intel = boot_cpu_data.x86_vendor == X86_VENDOR_INTEL;
 	int min_nr_gp_ctrs = pmu_ops->MIN_NR_GP_COUNTERS;
 
+	perf_get_x86_pmu_capability(&kvm_host_pmu);
+
 	/*
 	 * Hybrid PMUs don't play nice with virtualization without careful
 	 * configuration by userspace, and KVM's APIs for reporting supported
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:16:52 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:16:52 -0800
Subject: [PATCH v6 16/44] KVM: x86/pmu: Start stubbing in mediated PMU support
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-17-seanjc@google.com>

From: Dapeng Mi <dapeng1.mi at linux.intel.com>

Introduce enable_mediated_pmu as a global variable, with the intent of
exposing it to userspace a vendor module parameter, to control and reflect
mediated vPMU support.  Wire up the perf plumbing to create+release a
mediated PMU, but defer exposing the parameter to userspace until KVM
support for a mediated PMUs is fully landed.

To (a) minimize compatibility issues, (b) to give userspace a chance to
opt out of the restrictive side-effects of perf_create_mediated_pmu(),
and (c) to avoid adding new dependencies between enabling an in-kernel
irqchip and a mediated vPMU, defer "creating" a mediated PMU in perf
until the first vCPU is created.

Regarding userspace compatibility, an alternative solution would be to
make the mediated PMU fully opt-in, e.g. to avoid unexpected failure due
to perf_create_mediated_pmu() failing.  Ironically, that approach creates
an even bigger compatibility issue, as turning on enable_mediated_pmu
would silently break VMMs that don't utilize KVM_CAP_PMU_CAPABILITY (well,
silently until the guest tried to access PMU assets).

Regarding an in-kernel irqchip, create a mediated PMU if and only if the
VM has an in-kernel local APIC, as the mediated PMU will take a hard
dependency on forwarding PMIs to the guest without bouncing through host
userspace.  Silently "drop" the PMU instead of rejecting KVM_CREATE_VCPU,
as KVM's existing vPMU support doesn't function correctly if the local
APIC is emulated by userspace, e.g. PMIs will never be delivered.  I.e.
it's far, far more likely that rejecting KVM_CREATE_VCPU would cause
problems, e.g. for tests or userspace daemons that just want to probe
basic KVM functionality.

Note!  Deliberately make mediated PMU creation "sticky", i.e. don't unwind
it on failure to create a vCPU.  Practically speaking, there's no harm to
having a VM with a mediated PMU and no vCPUs.  To avoid an "impossible" VM
setup, reject KVM_CAP_PMU_CAPABILITY if a mediated PMU has been created,
i.e. don't let userspace disable PMU support after failed vCPU creation
(with PMU support enabled).

Defer vendor specific requirements and constraints to the future.

Suggested-by: Sean Christopherson <seanjc at google.com>
Signed-off-by: Dapeng Mi <dapeng1.mi at linux.intel.com>
Co-developed-by: Mingwei Zhang <mizhang at google.com>
Signed-off-by: Mingwei Zhang <mizhang at google.com>
Tested-by: Xudong Hao <xudong.hao at intel.com>
Co-developed-by: Sean Christopherson <seanjc at google.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/include/asm/kvm_host.h |  1 +
 arch/x86/kvm/pmu.c              |  4 ++++
 arch/x86/kvm/pmu.h              |  7 +++++++
 arch/x86/kvm/x86.c              | 37 +++++++++++++++++++++++++++++++--
 arch/x86/kvm/x86.h              |  1 +
 5 files changed, 48 insertions(+), 2 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 5a3bfa293e8b..defd979003be 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1484,6 +1484,7 @@ struct kvm_arch {
 
 	bool bus_lock_detection_enabled;
 	bool enable_pmu;
+	bool created_mediated_pmu;
 
 	u32 notify_window;
 	u32 notify_vmexit_flags;
diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index 7c219305b61d..0de0af5c6e4f 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -137,6 +137,10 @@ void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops)
 			enable_pmu = false;
 	}
 
+	if (!enable_pmu || !enable_mediated_pmu || !kvm_host_pmu.mediated ||
+	    !pmu_ops->is_mediated_pmu_supported(&kvm_host_pmu))
+		enable_mediated_pmu = false;
+
 	if (!enable_pmu) {
 		memset(&kvm_pmu_cap, 0, sizeof(kvm_pmu_cap));
 		return;
diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h
index 5c3939e91f1d..a5c7c026b919 100644
--- a/arch/x86/kvm/pmu.h
+++ b/arch/x86/kvm/pmu.h
@@ -37,6 +37,8 @@ struct kvm_pmu_ops {
 	void (*deliver_pmi)(struct kvm_vcpu *vcpu);
 	void (*cleanup)(struct kvm_vcpu *vcpu);
 
+	bool (*is_mediated_pmu_supported)(struct x86_pmu_capability *host_pmu);
+
 	const u64 EVENTSEL_EVENT;
 	const int MAX_NR_GP_COUNTERS;
 	const int MIN_NR_GP_COUNTERS;
@@ -58,6 +60,11 @@ static inline bool kvm_pmu_has_perf_global_ctrl(struct kvm_pmu *pmu)
 	return pmu->version > 1;
 }
 
+static inline bool kvm_vcpu_has_mediated_pmu(struct kvm_vcpu *vcpu)
+{
+	return enable_mediated_pmu && vcpu_to_pmu(vcpu)->version;
+}
+
 /*
  * KVM tracks all counters in 64-bit bitmaps, with general purpose counters
  * mapped to bits 31:0 and fixed counters mapped to 63:32, e.g. fixed counter 0
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 1b2827cecf38..fb3a5e861553 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -183,6 +183,10 @@ bool __read_mostly enable_pmu = true;
 EXPORT_SYMBOL_FOR_KVM_INTERNAL(enable_pmu);
 module_param(enable_pmu, bool, 0444);
 
+/* Enable/disabled mediated PMU virtualization. */
+bool __read_mostly enable_mediated_pmu;
+EXPORT_SYMBOL_FOR_KVM_INTERNAL(enable_mediated_pmu);
+
 bool __read_mostly eager_page_split = true;
 module_param(eager_page_split, bool, 0644);
 
@@ -6854,7 +6858,7 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
 			break;
 
 		mutex_lock(&kvm->lock);
-		if (!kvm->created_vcpus) {
+		if (!kvm->created_vcpus && !kvm->arch.created_mediated_pmu) {
 			kvm->arch.enable_pmu = !(cap->args[0] & KVM_PMU_CAP_DISABLE);
 			r = 0;
 		}
@@ -12641,8 +12645,13 @@ static int sync_regs(struct kvm_vcpu *vcpu)
 	return 0;
 }
 
+#define PERF_MEDIATED_PMU_MSG \
+	"Failed to enable mediated vPMU, try disabling system wide perf events and nmi_watchdog.\n"
+
 int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
 {
+	int r;
+
 	if (kvm_check_tsc_unstable() && kvm->created_vcpus)
 		pr_warn_once("SMP vm created on host with unstable TSC; "
 			     "guest TSC will not be reliable\n");
@@ -12653,7 +12662,29 @@ int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
 	if (id >= kvm->arch.max_vcpu_ids)
 		return -EINVAL;
 
-	return kvm_x86_call(vcpu_precreate)(kvm);
+	/*
+	 * Note, any actions done by .vcpu_create() must be idempotent with
+	 * respect to creating multiple vCPUs, and therefore are not undone if
+	 * creating a vCPU fails (including failure during pre-create).
+	 */
+	r = kvm_x86_call(vcpu_precreate)(kvm);
+	if (r)
+		return r;
+
+	if (enable_mediated_pmu && kvm->arch.enable_pmu &&
+	    !kvm->arch.created_mediated_pmu) {
+		if (irqchip_in_kernel(kvm)) {
+			r = perf_create_mediated_pmu();
+			if (r) {
+				pr_warn_ratelimited(PERF_MEDIATED_PMU_MSG);
+				return r;
+			}
+			kvm->arch.created_mediated_pmu = true;
+		} else {
+			kvm->arch.enable_pmu = false;
+		}
+	}
+	return 0;
 }
 
 int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
@@ -13319,6 +13350,8 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
 		__x86_set_memory_region(kvm, TSS_PRIVATE_MEMSLOT, 0, 0);
 		mutex_unlock(&kvm->slots_lock);
 	}
+	if (kvm->arch.created_mediated_pmu)
+		perf_release_mediated_pmu();
 	kvm_destroy_vcpus(kvm);
 	kvm_free_msr_filter(srcu_dereference_check(kvm->arch.msr_filter, &kvm->srcu, 1));
 #ifdef CONFIG_KVM_IOAPIC
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index fdab0ad49098..6e1fb1680c0a 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -470,6 +470,7 @@ extern struct kvm_caps kvm_caps;
 extern struct kvm_host_values kvm_host;
 
 extern bool enable_pmu;
+extern bool enable_mediated_pmu;
 
 /*
  * Get a filtered version of KVM's supported XCR0 that strips out dynamic
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:16:54 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:16:54 -0800
Subject: [PATCH v6 18/44] KVM: x86/pmu: Implement AMD mediated PMU requirements
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-19-seanjc@google.com>

Require host PMU version 2+ for AMD mediated PMU support, as
PERF_GLOBAL_CTRL and friends are hard requirements for the mediated PMU.

Signed-off-by: Dapeng Mi <dapeng1.mi at linux.intel.com>
Co-developed-by: Mingwei Zhang <mizhang at google.com>
Signed-off-by: Mingwei Zhang <mizhang at google.com>
[sean: extract to separate patch, write changelog]
Reviewed-by: Sandipan Das <sandipan.das at amd.com>
Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/kvm/svm/pmu.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c
index bc062285fbf5..16c88b2a2eb8 100644
--- a/arch/x86/kvm/svm/pmu.c
+++ b/arch/x86/kvm/svm/pmu.c
@@ -227,6 +227,11 @@ static void amd_pmu_init(struct kvm_vcpu *vcpu)
 	}
 }
 
+static bool amd_pmu_is_mediated_pmu_supported(struct x86_pmu_capability *host_pmu)
+{
+	return host_pmu->version >= 2;
+}
+
 struct kvm_pmu_ops amd_pmu_ops __initdata = {
 	.rdpmc_ecx_to_pmc = amd_rdpmc_ecx_to_pmc,
 	.msr_idx_to_pmc = amd_msr_idx_to_pmc,
@@ -236,6 +241,9 @@ struct kvm_pmu_ops amd_pmu_ops __initdata = {
 	.set_msr = amd_pmu_set_msr,
 	.refresh = amd_pmu_refresh,
 	.init = amd_pmu_init,
+
+	.is_mediated_pmu_supported = amd_pmu_is_mediated_pmu_supported,
+
 	.EVENTSEL_EVENT = AMD64_EVENTSEL_EVENT,
 	.MAX_NR_GP_COUNTERS = KVM_MAX_NR_AMD_GP_COUNTERS,
 	.MIN_NR_GP_COUNTERS = AMD64_NUM_COUNTERS,
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:16:53 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:16:53 -0800
Subject: [PATCH v6 17/44] KVM: x86/pmu: Implement Intel mediated PMU
 requirements and constraints
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-18-seanjc@google.com>

From: Dapeng Mi <dapeng1.mi at linux.intel.com>

Implement Intel PMU requirements and constraints for mediated PMU support.
Require host PMU version 4+ so that PERF_GLOBAL_STATUS_SET can be used to
precisely load the guest's status value into hardware, and require full-
width writes so that KVM can precisely load guest counter values.

Disable PEBS and LBRs if mediated PMU support is enabled, as they won't be
supported in the initial implementation.

Signed-off-by: Dapeng Mi <dapeng1.mi at linux.intel.com>
Co-developed-by: Mingwei Zhang <mizhang at google.com>
Signed-off-by: Mingwei Zhang <mizhang at google.com>
[sean: split to separate patch, add full-width writes dependency]
Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/kvm/vmx/capabilities.h |  3 ++-
 arch/x86/kvm/vmx/pmu_intel.c    | 17 +++++++++++++++++
 arch/x86/kvm/vmx/vmx.c          |  3 ++-
 3 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kvm/vmx/capabilities.h b/arch/x86/kvm/vmx/capabilities.h
index 02aadb9d730e..26302fd6dd9c 100644
--- a/arch/x86/kvm/vmx/capabilities.h
+++ b/arch/x86/kvm/vmx/capabilities.h
@@ -395,7 +395,8 @@ static inline bool vmx_pt_mode_is_host_guest(void)
 
 static inline bool vmx_pebs_supported(void)
 {
-	return boot_cpu_has(X86_FEATURE_PEBS) && kvm_pmu_cap.pebs_ept;
+	return boot_cpu_has(X86_FEATURE_PEBS) && kvm_pmu_cap.pebs_ept &&
+	       !enable_mediated_pmu;
 }
 
 static inline bool cpu_has_notify_vmexit(void)
diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
index de1d9785c01f..050c21298213 100644
--- a/arch/x86/kvm/vmx/pmu_intel.c
+++ b/arch/x86/kvm/vmx/pmu_intel.c
@@ -767,6 +767,20 @@ void intel_pmu_cross_mapped_check(struct kvm_pmu *pmu)
 	}
 }
 
+static bool intel_pmu_is_mediated_pmu_supported(struct x86_pmu_capability *host_pmu)
+{
+	u64 host_perf_cap = 0;
+
+	if (boot_cpu_has(X86_FEATURE_PDCM))
+		rdmsrq(MSR_IA32_PERF_CAPABILITIES, host_perf_cap);
+
+	/*
+	 * Require v4+ for MSR_CORE_PERF_GLOBAL_STATUS_SET, and full-width
+	 * writes so that KVM can precisely load guest counter values.
+	 */
+	return host_pmu->version >= 4 && host_perf_cap & PERF_CAP_FW_WRITES;
+}
+
 struct kvm_pmu_ops intel_pmu_ops __initdata = {
 	.rdpmc_ecx_to_pmc = intel_rdpmc_ecx_to_pmc,
 	.msr_idx_to_pmc = intel_msr_idx_to_pmc,
@@ -778,6 +792,9 @@ struct kvm_pmu_ops intel_pmu_ops __initdata = {
 	.reset = intel_pmu_reset,
 	.deliver_pmi = intel_pmu_deliver_pmi,
 	.cleanup = intel_pmu_cleanup,
+
+	.is_mediated_pmu_supported = intel_pmu_is_mediated_pmu_supported,
+
 	.EVENTSEL_EVENT = ARCH_PERFMON_EVENTSEL_EVENT,
 	.MAX_NR_GP_COUNTERS = KVM_MAX_NR_INTEL_GP_COUNTERS,
 	.MIN_NR_GP_COUNTERS = 1,
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 4cbe8c84b636..fdd18ad1ede3 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -7958,7 +7958,8 @@ static __init u64 vmx_get_perf_capabilities(void)
 	if (boot_cpu_has(X86_FEATURE_PDCM))
 		rdmsrq(MSR_IA32_PERF_CAPABILITIES, host_perf_cap);
 
-	if (!cpu_feature_enabled(X86_FEATURE_ARCH_LBR)) {
+	if (!cpu_feature_enabled(X86_FEATURE_ARCH_LBR) &&
+	    !enable_mediated_pmu) {
 		x86_perf_get_lbr(&vmx_lbr_caps);
 
 		/*
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:16:55 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:16:55 -0800
Subject: [PATCH v6 19/44] KVM: x86/pmu: Register PMI handler for mediated vPMU
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-20-seanjc@google.com>

From: Xiong Zhang <xiong.y.zhang at linux.intel.com>

Register a dedicated PMI handler with perf's callback when mediated PMU
support is enabled.  Perf routes PMIs that arrive while guest context is
loaded to the provided callback, by modifying the CPU's LVTPC to point at
a dedicated mediated PMI IRQ vector.

WARN upon receipt of a mediated PMI if there is no active vCPU, or if the
vCPU doesn't have a mediated PMU.  Even if a PMI manages to skid past
VM-Exit, it should never be delayed all the way beyond unloading the vCPU.
And while running vCPUs without a mediated PMU, the LVTPC should never be
wired up to the mediated PMI IRQ vector, i.e. should always be routed
through perf's NMI handler.

Signed-off-by: Xiong Zhang <xiong.y.zhang at linux.intel.com>
Signed-off-by: Mingwei Zhang <mizhang at google.com>
Tested-by: Xudong Hao <xudong.hao at intel.com>
Co-developed-by: Sean Christopherson <seanjc at google.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/kvm/pmu.c | 10 ++++++++++
 arch/x86/kvm/pmu.h |  2 ++
 arch/x86/kvm/x86.c |  3 ++-
 3 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index 0de0af5c6e4f..b3dde9a836ea 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -159,6 +159,16 @@ void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops)
 		perf_get_hw_event_config(PERF_COUNT_HW_BRANCH_INSTRUCTIONS);
 }
 
+void kvm_handle_guest_mediated_pmi(void)
+{
+	struct kvm_vcpu *vcpu = kvm_get_running_vcpu();
+
+	if (WARN_ON_ONCE(!vcpu || !kvm_vcpu_has_mediated_pmu(vcpu)))
+		return;
+
+	kvm_make_request(KVM_REQ_PMI, vcpu);
+}
+
 static inline void __kvm_perf_overflow(struct kvm_pmc *pmc, bool in_pmi)
 {
 	struct kvm_pmu *pmu = pmc_to_pmu(pmc);
diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h
index a5c7c026b919..9849c2bb720d 100644
--- a/arch/x86/kvm/pmu.h
+++ b/arch/x86/kvm/pmu.h
@@ -46,6 +46,8 @@ struct kvm_pmu_ops {
 
 void kvm_pmu_ops_update(const struct kvm_pmu_ops *pmu_ops);
 
+void kvm_handle_guest_mediated_pmi(void);
+
 static inline bool kvm_pmu_has_perf_global_ctrl(struct kvm_pmu *pmu)
 {
 	/*
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index fb3a5e861553..1623afddff3b 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -10111,7 +10111,8 @@ int kvm_x86_vendor_init(struct kvm_x86_init_ops *ops)
 		set_hv_tscchange_cb(kvm_hyperv_tsc_notifier);
 #endif
 
-	__kvm_register_perf_callbacks(ops->handle_intel_pt_intr, NULL);
+	__kvm_register_perf_callbacks(ops->handle_intel_pt_intr,
+				      enable_mediated_pmu ? kvm_handle_guest_mediated_pmi : NULL);
 
 	if (IS_ENABLED(CONFIG_KVM_SW_PROTECTED_VM) && tdp_mmu_enabled)
 		kvm_caps.supported_vm_types |= BIT(KVM_X86_SW_PROTECTED_VM);
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:16:56 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:16:56 -0800
Subject: [PATCH v6 20/44] KVM: x86/pmu: Disable RDPMC interception for
 compatible mediated vPMU
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-21-seanjc@google.com>

From: Dapeng Mi <dapeng1.mi at linux.intel.com>

Disable RDPMC interception for vCPUs with a mediated vPMU that is
compatible with the host PMU, i.e. that doesn't require KVM emulation of
RDPMC to honor the guest's vCPU model.  With a mediated vPMU, all guest
state accessible via RDPMC is loaded into hardware while the guest is
running.

Adust RDPMC interception only for non-TDX guests, as the TDX module is
responsible for managing RDPMC intercepts based on the TD configuration.

Co-developed-by: Mingwei Zhang <mizhang at google.com>
Signed-off-by: Mingwei Zhang <mizhang at google.com>
Co-developed-by: Sandipan Das <sandipan.das at amd.com>
Signed-off-by: Sandipan Das <sandipan.das at amd.com>
Signed-off-by: Dapeng Mi <dapeng1.mi at linux.intel.com>
Tested-by: Xudong Hao <xudong.hao at intel.com>
Co-developed-by: Sean Christopherson <seanjc at google.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/kvm/pmu.c     | 26 ++++++++++++++++++++++++++
 arch/x86/kvm/pmu.h     |  1 +
 arch/x86/kvm/svm/svm.c |  5 +++++
 arch/x86/kvm/vmx/vmx.c |  7 +++++++
 arch/x86/kvm/x86.c     |  1 +
 5 files changed, 40 insertions(+)

diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index b3dde9a836ea..182ff2d8d119 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -716,6 +716,32 @@ int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned idx, u64 *data)
 	return 0;
 }
 
+bool kvm_need_rdpmc_intercept(struct kvm_vcpu *vcpu)
+{
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+
+	if (!kvm_vcpu_has_mediated_pmu(vcpu))
+		return true;
+
+	/*
+	 * VMware allows access to these Pseduo-PMCs even when read via RDPMC
+	 * in Ring3 when CR4.PCE=0.
+	 */
+	if (enable_vmware_backdoor)
+		return true;
+
+	/*
+	 * Note!  Check *host* PMU capabilities, not KVM's PMU capabilities, as
+	 * KVM's capabilities are constrained based on KVM support, i.e. KVM's
+	 * capabilities themselves may be a subset of hardware capabilities.
+	 */
+	return pmu->nr_arch_gp_counters != kvm_host_pmu.num_counters_gp ||
+	       pmu->nr_arch_fixed_counters != kvm_host_pmu.num_counters_fixed ||
+	       pmu->counter_bitmask[KVM_PMC_GP] != (BIT_ULL(kvm_host_pmu.bit_width_gp) - 1) ||
+	       pmu->counter_bitmask[KVM_PMC_FIXED] != (BIT_ULL(kvm_host_pmu.bit_width_fixed) - 1);
+}
+EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_need_rdpmc_intercept);
+
 void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu)
 {
 	if (lapic_in_kernel(vcpu)) {
diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h
index 9849c2bb720d..506c203587ea 100644
--- a/arch/x86/kvm/pmu.h
+++ b/arch/x86/kvm/pmu.h
@@ -238,6 +238,7 @@ void kvm_pmu_instruction_retired(struct kvm_vcpu *vcpu);
 void kvm_pmu_branch_retired(struct kvm_vcpu *vcpu);
 
 bool is_vmware_backdoor_pmc(u32 pmc_idx);
+bool kvm_need_rdpmc_intercept(struct kvm_vcpu *vcpu);
 
 extern struct kvm_pmu_ops intel_pmu_ops;
 extern struct kvm_pmu_ops amd_pmu_ops;
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 24d59ccfa40d..11913574de88 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -1011,6 +1011,11 @@ static void svm_recalc_instruction_intercepts(struct kvm_vcpu *vcpu)
 			svm->vmcb->control.virt_ext |= VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK;
 		}
 	}
+
+	if (kvm_need_rdpmc_intercept(vcpu))
+		svm_set_intercept(svm, INTERCEPT_RDPMC);
+	else
+		svm_clr_intercept(svm, INTERCEPT_RDPMC);
 }
 
 static void svm_recalc_intercepts(struct kvm_vcpu *vcpu)
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index fdd18ad1ede3..9f71ba99cf70 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -4300,8 +4300,15 @@ static void vmx_recalc_msr_intercepts(struct kvm_vcpu *vcpu)
 	 */
 }
 
+static void vmx_recalc_instruction_intercepts(struct kvm_vcpu *vcpu)
+{
+	exec_controls_changebit(to_vmx(vcpu), CPU_BASED_RDPMC_EXITING,
+				kvm_need_rdpmc_intercept(vcpu));
+}
+
 void vmx_recalc_intercepts(struct kvm_vcpu *vcpu)
 {
+	vmx_recalc_instruction_intercepts(vcpu);
 	vmx_recalc_msr_intercepts(vcpu);
 }
 
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 1623afddff3b..76e86eb358df 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3945,6 +3945,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 
 		vcpu->arch.perf_capabilities = data;
 		kvm_pmu_refresh(vcpu);
+		kvm_make_request(KVM_REQ_RECALC_INTERCEPTS, vcpu);
 		break;
 	case MSR_IA32_PRED_CMD: {
 		u64 reserved_bits = ~(PRED_CMD_IBPB | PRED_CMD_SBPB);
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:16:57 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:16:57 -0800
Subject: [PATCH v6 21/44] KVM: x86/pmu: Load/save GLOBAL_CTRL via entry/exit
 fields for mediated PMU
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-22-seanjc@google.com>

From: Dapeng Mi <dapeng1.mi at linux.intel.com>

When running a guest with a mediated PMU, context switch PERF_GLOBAL_CTRL
via the dedicated VMCS fields for both host and guest.  For the host,
always zero GLOBAL_CTRL on exit as the guest's state will still be loaded
in hardware (KVM will context switch the bulk of PMU state outside of the
inner run loop).  For the guest, use the dedicated fields to atomically
load and save PERF_GLOBAL_CTRL on all entry/exits.

For now, require VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL support (introduced by
Sapphire Rapids).  KVM can support such CPUs by saving PERF_GLOBAL_CTRL
via the MSR save list, a.k.a. the MSR auto-store list, but defer that
support as it adds a small amount of complexity and is somewhat unique.

To minimize VM-Entry latency, propagate IA32_PERF_GLOBAL_CTRL to the VMCS
on-demand.  But to minimize complexity, read IA32_PERF_GLOBAL_CTRL out of
the VMCS on all non-failing VM-Exits.  I.e. partially cache the MSR.
KVM could track GLOBAL_CTRL as an EXREG and defer all reads, but writes
are rare, i.e. the dirty tracking for an EXREG is unnecessary, and it's
not obvious that shaving ~15-20 cycles per exit is meaningful given the
total overhead associated with mediated PMU context switches.

Suggested-by: Sean Christopherson <seanjc at google.com>
Signed-off-by: Dapeng Mi <dapeng1.mi at linux.intel.com>
Co-developed-by: Mingwei Zhang <mizhang at google.com>
Signed-off-by: Mingwei Zhang <mizhang at google.com>
Tested-by: Xudong Hao <xudong.hao at intel.com>
Co-developed-by: Sean Christopherson <seanjc at google.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/include/asm/kvm-x86-pmu-ops.h |  2 ++
 arch/x86/include/asm/vmx.h             |  1 +
 arch/x86/kvm/pmu.c                     | 13 +++++++++--
 arch/x86/kvm/pmu.h                     |  3 ++-
 arch/x86/kvm/vmx/capabilities.h        |  6 +++++
 arch/x86/kvm/vmx/pmu_intel.c           | 25 ++++++++++++++++++++-
 arch/x86/kvm/vmx/vmx.c                 | 31 +++++++++++++++++++++++++-
 arch/x86/kvm/vmx/vmx.h                 |  3 ++-
 8 files changed, 78 insertions(+), 6 deletions(-)

diff --git a/arch/x86/include/asm/kvm-x86-pmu-ops.h b/arch/x86/include/asm/kvm-x86-pmu-ops.h
index 9159bf1a4730..ad2cc82abf79 100644
--- a/arch/x86/include/asm/kvm-x86-pmu-ops.h
+++ b/arch/x86/include/asm/kvm-x86-pmu-ops.h
@@ -23,5 +23,7 @@ KVM_X86_PMU_OP_OPTIONAL(reset)
 KVM_X86_PMU_OP_OPTIONAL(deliver_pmi)
 KVM_X86_PMU_OP_OPTIONAL(cleanup)
 
+KVM_X86_PMU_OP_OPTIONAL(write_global_ctrl)
+
 #undef KVM_X86_PMU_OP
 #undef KVM_X86_PMU_OP_OPTIONAL
diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
index c85c50019523..b92ff87e3560 100644
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -107,6 +107,7 @@
 #define VM_EXIT_PT_CONCEAL_PIP			0x01000000
 #define VM_EXIT_CLEAR_IA32_RTIT_CTL		0x02000000
 #define VM_EXIT_LOAD_CET_STATE                  0x10000000
+#define VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL	0x40000000
 
 #define VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR	0x00036dff
 
diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index 182ff2d8d119..c4a32bfb26f5 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -103,7 +103,7 @@ void kvm_pmu_ops_update(const struct kvm_pmu_ops *pmu_ops)
 #undef __KVM_X86_PMU_OP
 }
 
-void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops)
+void kvm_init_pmu_capability(struct kvm_pmu_ops *pmu_ops)
 {
 	bool is_intel = boot_cpu_data.x86_vendor == X86_VENDOR_INTEL;
 	int min_nr_gp_ctrs = pmu_ops->MIN_NR_GP_COUNTERS;
@@ -141,6 +141,9 @@ void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops)
 	    !pmu_ops->is_mediated_pmu_supported(&kvm_host_pmu))
 		enable_mediated_pmu = false;
 
+	if (!enable_mediated_pmu)
+		pmu_ops->write_global_ctrl = NULL;
+
 	if (!enable_pmu) {
 		memset(&kvm_pmu_cap, 0, sizeof(kvm_pmu_cap));
 		return;
@@ -836,6 +839,9 @@ int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 			diff = pmu->global_ctrl ^ data;
 			pmu->global_ctrl = data;
 			reprogram_counters(pmu, diff);
+
+			if (kvm_vcpu_has_mediated_pmu(vcpu))
+				kvm_pmu_call(write_global_ctrl)(data);
 		}
 		break;
 	case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
@@ -930,8 +936,11 @@ void kvm_pmu_refresh(struct kvm_vcpu *vcpu)
 	 * in the global controls).  Emulate that behavior when refreshing the
 	 * PMU so that userspace doesn't need to manually set PERF_GLOBAL_CTRL.
 	 */
-	if (kvm_pmu_has_perf_global_ctrl(pmu) && pmu->nr_arch_gp_counters)
+	if (kvm_pmu_has_perf_global_ctrl(pmu) && pmu->nr_arch_gp_counters) {
 		pmu->global_ctrl = GENMASK_ULL(pmu->nr_arch_gp_counters - 1, 0);
+		if (kvm_vcpu_has_mediated_pmu(vcpu))
+			kvm_pmu_call(write_global_ctrl)(pmu->global_ctrl);
+	}
 
 	bitmap_set(pmu->all_valid_pmc_idx, 0, pmu->nr_arch_gp_counters);
 	bitmap_set(pmu->all_valid_pmc_idx, KVM_FIXED_PMC_BASE_IDX,
diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h
index 506c203587ea..2ff469334c1a 100644
--- a/arch/x86/kvm/pmu.h
+++ b/arch/x86/kvm/pmu.h
@@ -38,6 +38,7 @@ struct kvm_pmu_ops {
 	void (*cleanup)(struct kvm_vcpu *vcpu);
 
 	bool (*is_mediated_pmu_supported)(struct x86_pmu_capability *host_pmu);
+	void (*write_global_ctrl)(u64 global_ctrl);
 
 	const u64 EVENTSEL_EVENT;
 	const int MAX_NR_GP_COUNTERS;
@@ -183,7 +184,7 @@ static inline bool pmc_is_locally_enabled(struct kvm_pmc *pmc)
 
 extern struct x86_pmu_capability kvm_pmu_cap;
 
-void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops);
+void kvm_init_pmu_capability(struct kvm_pmu_ops *pmu_ops);
 
 void kvm_pmu_recalc_pmc_emulation(struct kvm_pmu *pmu, struct kvm_pmc *pmc);
 
diff --git a/arch/x86/kvm/vmx/capabilities.h b/arch/x86/kvm/vmx/capabilities.h
index 26302fd6dd9c..4e371c93ae16 100644
--- a/arch/x86/kvm/vmx/capabilities.h
+++ b/arch/x86/kvm/vmx/capabilities.h
@@ -109,6 +109,12 @@ static inline bool cpu_has_load_cet_ctrl(void)
 {
 	return (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_CET_STATE);
 }
+
+static inline bool cpu_has_save_perf_global_ctrl(void)
+{
+	return vmcs_config.vmexit_ctrl & VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL;
+}
+
 static inline bool cpu_has_vmx_mpx(void)
 {
 	return vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_BNDCFGS;
diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
index 050c21298213..dbab7cca7a62 100644
--- a/arch/x86/kvm/vmx/pmu_intel.c
+++ b/arch/x86/kvm/vmx/pmu_intel.c
@@ -778,7 +778,29 @@ static bool intel_pmu_is_mediated_pmu_supported(struct x86_pmu_capability *host_
 	 * Require v4+ for MSR_CORE_PERF_GLOBAL_STATUS_SET, and full-width
 	 * writes so that KVM can precisely load guest counter values.
 	 */
-	return host_pmu->version >= 4 && host_perf_cap & PERF_CAP_FW_WRITES;
+	if (host_pmu->version < 4 || !(host_perf_cap & PERF_CAP_FW_WRITES))
+		return false;
+
+	/*
+	 * All CPUs that support a mediated PMU are expected to support loading
+	 * PERF_GLOBAL_CTRL via dedicated VMCS fields.
+	 */
+	if (WARN_ON_ONCE(!cpu_has_load_perf_global_ctrl()))
+		return false;
+
+	/*
+	 * KVM doesn't yet support mediated PMU on CPUs without support for
+	 * saving PERF_GLOBAL_CTRL via a dedicated VMCS field.
+	 */
+	if (!cpu_has_save_perf_global_ctrl())
+		return false;
+
+	return true;
+}
+
+static void intel_pmu_write_global_ctrl(u64 global_ctrl)
+{
+	vmcs_write64(GUEST_IA32_PERF_GLOBAL_CTRL, global_ctrl);
 }
 
 struct kvm_pmu_ops intel_pmu_ops __initdata = {
@@ -794,6 +816,7 @@ struct kvm_pmu_ops intel_pmu_ops __initdata = {
 	.cleanup = intel_pmu_cleanup,
 
 	.is_mediated_pmu_supported = intel_pmu_is_mediated_pmu_supported,
+	.write_global_ctrl = intel_pmu_write_global_ctrl,
 
 	.EVENTSEL_EVENT = ARCH_PERFMON_EVENTSEL_EVENT,
 	.MAX_NR_GP_COUNTERS = KVM_MAX_NR_INTEL_GP_COUNTERS,
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 9f71ba99cf70..72b92cea9d72 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -4294,6 +4294,18 @@ static void vmx_recalc_msr_intercepts(struct kvm_vcpu *vcpu)
 		vmx_set_intercept_for_msr(vcpu, MSR_IA32_S_CET, MSR_TYPE_RW, intercept);
 	}
 
+	if (enable_mediated_pmu) {
+		bool is_mediated_pmu = kvm_vcpu_has_mediated_pmu(vcpu);
+		struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+		vm_entry_controls_changebit(vmx,
+					    VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL, is_mediated_pmu);
+
+		vm_exit_controls_changebit(vmx,
+					   VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL |
+					   VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL, is_mediated_pmu);
+	}
+
 	/*
 	 * x2APIC and LBR MSR intercepts are modified on-demand and cannot be
 	 * filtered by userspace.
@@ -4476,6 +4488,16 @@ void vmx_set_constant_host_state(struct vcpu_vmx *vmx)
 		vmcs_writel(HOST_SSP, 0);
 		vmcs_writel(HOST_INTR_SSP_TABLE, 0);
 	}
+
+	/*
+	 * When running a guest with a mediated PMU, guest state is resident in
+	 * hardware after VM-Exit.  Zero PERF_GLOBAL_CTRL on exit so that host
+	 * activity doesn't bleed into the guest counters.  When running with
+	 * an emulated PMU, PERF_GLOBAL_CTRL is dynamically computed on every
+	 * entry/exit to merge guest and host PMU usage.
+	 */
+	if (enable_mediated_pmu)
+		vmcs_write64(HOST_IA32_PERF_GLOBAL_CTRL, 0);
 }
 
 void set_cr4_guest_host_mask(struct vcpu_vmx *vmx)
@@ -4543,7 +4565,8 @@ static u32 vmx_get_initial_vmexit_ctrl(void)
 				 VM_EXIT_CLEAR_IA32_RTIT_CTL);
 	/* Loading of EFER and PERF_GLOBAL_CTRL are toggled dynamically */
 	return vmexit_ctrl &
-		~(VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | VM_EXIT_LOAD_IA32_EFER);
+		~(VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | VM_EXIT_LOAD_IA32_EFER |
+		  VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL);
 }
 
 void vmx_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
@@ -7270,6 +7293,9 @@ static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx)
 	struct perf_guest_switch_msr *msrs;
 	struct kvm_pmu *pmu = vcpu_to_pmu(&vmx->vcpu);
 
+	if (kvm_vcpu_has_mediated_pmu(&vmx->vcpu))
+		return;
+
 	pmu->host_cross_mapped_mask = 0;
 	if (pmu->pebs_enable & pmu->global_ctrl)
 		intel_pmu_cross_mapped_check(pmu);
@@ -7572,6 +7598,9 @@ fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu, u64 run_flags)
 
 	vmx->loaded_vmcs->launched = 1;
 
+	if (!msr_write_intercepted(vmx, MSR_CORE_PERF_GLOBAL_CTRL))
+		vcpu_to_pmu(vcpu)->global_ctrl = vmcs_read64(GUEST_IA32_PERF_GLOBAL_CTRL);
+
 	vmx_recover_nmi_blocking(vmx);
 	vmx_complete_interrupts(vmx);
 
diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h
index bc3ed3145d7e..d7a96c84371f 100644
--- a/arch/x86/kvm/vmx/vmx.h
+++ b/arch/x86/kvm/vmx/vmx.h
@@ -510,7 +510,8 @@ static inline u8 vmx_get_rvi(void)
 	       VM_EXIT_CLEAR_BNDCFGS |					\
 	       VM_EXIT_PT_CONCEAL_PIP |					\
 	       VM_EXIT_CLEAR_IA32_RTIT_CTL |				\
-	       VM_EXIT_LOAD_CET_STATE)
+	       VM_EXIT_LOAD_CET_STATE |					\
+	       VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL)
 
 #define KVM_REQUIRED_VMX_PIN_BASED_VM_EXEC_CONTROL			\
 	(PIN_BASED_EXT_INTR_MASK |					\
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:16:58 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:16:58 -0800
Subject: [PATCH v6 22/44] KVM: x86/pmu: Disable interception of select PMU
 MSRs for mediated vPMUs
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-23-seanjc@google.com>

From: Dapeng Mi <dapeng1.mi at linux.intel.com>

For vCPUs with a mediated vPMU, disable interception of counter MSRs for
PMCs that are exposed to the guest, and for GLOBAL_CTRL and related MSRs
if they are fully supported according to the vCPU model, i.e. if the MSRs
and all bits supported by hardware exist from the guest's point of view.

Do NOT passthrough event selector or fixed counter control MSRs, so that
KVM can enforce userspace-defined event filters, e.g. to prevent use of
AnyThread events (which is unfortunately a setting in the fixed counter
control MSR).

Defer support for nested passthrough of mediated PMU MSRs to the future,
as the logic for nested MSR interception is unfortunately vendor specific.

Suggested-by: Sean Christopherson <seanjc at google.com>
Co-developed-by: Mingwei Zhang <mizhang at google.com>
Signed-off-by: Mingwei Zhang <mizhang at google.com>
Co-developed-by: Sandipan Das <sandipan.das at amd.com>
Signed-off-by: Sandipan Das <sandipan.das at amd.com>
Signed-off-by: Dapeng Mi <dapeng1.mi at linux.intel.com>
[sean: squash patches, massage changelog, refresh VMX MSRs on filter change]
Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/kvm/pmu.c           | 41 +++++++++++++++++--------
 arch/x86/kvm/pmu.h           |  1 +
 arch/x86/kvm/svm/svm.c       | 36 ++++++++++++++++++++++
 arch/x86/kvm/vmx/pmu_intel.c | 13 --------
 arch/x86/kvm/vmx/pmu_intel.h | 15 +++++++++
 arch/x86/kvm/vmx/vmx.c       | 59 +++++++++++++++++++++++++++++-------
 6 files changed, 128 insertions(+), 37 deletions(-)

diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index c4a32bfb26f5..57833f29a746 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -719,27 +719,41 @@ int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned idx, u64 *data)
 	return 0;
 }
 
-bool kvm_need_rdpmc_intercept(struct kvm_vcpu *vcpu)
+static bool kvm_need_any_pmc_intercept(struct kvm_vcpu *vcpu)
 {
 	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
 
 	if (!kvm_vcpu_has_mediated_pmu(vcpu))
 		return true;
 
-	/*
-	 * VMware allows access to these Pseduo-PMCs even when read via RDPMC
-	 * in Ring3 when CR4.PCE=0.
-	 */
-	if (enable_vmware_backdoor)
-		return true;
-
 	/*
 	 * Note!  Check *host* PMU capabilities, not KVM's PMU capabilities, as
 	 * KVM's capabilities are constrained based on KVM support, i.e. KVM's
 	 * capabilities themselves may be a subset of hardware capabilities.
 	 */
 	return pmu->nr_arch_gp_counters != kvm_host_pmu.num_counters_gp ||
-	       pmu->nr_arch_fixed_counters != kvm_host_pmu.num_counters_fixed ||
+	       pmu->nr_arch_fixed_counters != kvm_host_pmu.num_counters_fixed;
+}
+
+bool kvm_need_perf_global_ctrl_intercept(struct kvm_vcpu *vcpu)
+{
+	return kvm_need_any_pmc_intercept(vcpu) ||
+	       !kvm_pmu_has_perf_global_ctrl(vcpu_to_pmu(vcpu));
+}
+EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_need_perf_global_ctrl_intercept);
+
+bool kvm_need_rdpmc_intercept(struct kvm_vcpu *vcpu)
+{
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+
+	/*
+	 * VMware allows access to these Pseduo-PMCs even when read via RDPMC
+	 * in Ring3 when CR4.PCE=0.
+	 */
+	if (enable_vmware_backdoor)
+		return true;
+
+	return kvm_need_any_pmc_intercept(vcpu) ||
 	       pmu->counter_bitmask[KVM_PMC_GP] != (BIT_ULL(kvm_host_pmu.bit_width_gp) - 1) ||
 	       pmu->counter_bitmask[KVM_PMC_FIXED] != (BIT_ULL(kvm_host_pmu.bit_width_fixed) - 1);
 }
@@ -936,11 +950,12 @@ void kvm_pmu_refresh(struct kvm_vcpu *vcpu)
 	 * in the global controls).  Emulate that behavior when refreshing the
 	 * PMU so that userspace doesn't need to manually set PERF_GLOBAL_CTRL.
 	 */
-	if (kvm_pmu_has_perf_global_ctrl(pmu) && pmu->nr_arch_gp_counters) {
+	if (pmu->nr_arch_gp_counters &&
+	    (kvm_pmu_has_perf_global_ctrl(pmu) || kvm_vcpu_has_mediated_pmu(vcpu)))
 		pmu->global_ctrl = GENMASK_ULL(pmu->nr_arch_gp_counters - 1, 0);
-		if (kvm_vcpu_has_mediated_pmu(vcpu))
-			kvm_pmu_call(write_global_ctrl)(pmu->global_ctrl);
-	}
+
+	if (kvm_vcpu_has_mediated_pmu(vcpu))
+		kvm_pmu_call(write_global_ctrl)(pmu->global_ctrl);
 
 	bitmap_set(pmu->all_valid_pmc_idx, 0, pmu->nr_arch_gp_counters);
 	bitmap_set(pmu->all_valid_pmc_idx, KVM_FIXED_PMC_BASE_IDX,
diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h
index 2ff469334c1a..356b08e92bc9 100644
--- a/arch/x86/kvm/pmu.h
+++ b/arch/x86/kvm/pmu.h
@@ -239,6 +239,7 @@ void kvm_pmu_instruction_retired(struct kvm_vcpu *vcpu);
 void kvm_pmu_branch_retired(struct kvm_vcpu *vcpu);
 
 bool is_vmware_backdoor_pmc(u32 pmc_idx);
+bool kvm_need_perf_global_ctrl_intercept(struct kvm_vcpu *vcpu);
 bool kvm_need_rdpmc_intercept(struct kvm_vcpu *vcpu);
 
 extern struct kvm_pmu_ops intel_pmu_ops;
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 11913574de88..fa04e58ff524 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -730,6 +730,40 @@ void svm_vcpu_free_msrpm(void *msrpm)
 	__free_pages(virt_to_page(msrpm), get_order(MSRPM_SIZE));
 }
 
+static void svm_recalc_pmu_msr_intercepts(struct kvm_vcpu *vcpu)
+{
+	bool intercept = !kvm_vcpu_has_mediated_pmu(vcpu);
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+	int i;
+
+	if (!enable_mediated_pmu)
+		return;
+
+	/* Legacy counters are always available for AMD CPUs with a PMU. */
+	for (i = 0; i < min(pmu->nr_arch_gp_counters, AMD64_NUM_COUNTERS); i++)
+		svm_set_intercept_for_msr(vcpu, MSR_K7_PERFCTR0 + i,
+					  MSR_TYPE_RW, intercept);
+
+	intercept |= !guest_cpu_cap_has(vcpu, X86_FEATURE_PERFCTR_CORE);
+	for (i = 0; i < pmu->nr_arch_gp_counters; i++)
+		svm_set_intercept_for_msr(vcpu, MSR_F15H_PERF_CTR + 2 * i,
+					  MSR_TYPE_RW, intercept);
+
+	for ( ; i < kvm_pmu_cap.num_counters_gp; i++)
+		svm_enable_intercept_for_msr(vcpu, MSR_F15H_PERF_CTR + 2 * i,
+					     MSR_TYPE_RW);
+
+	intercept = kvm_need_perf_global_ctrl_intercept(vcpu);
+	svm_set_intercept_for_msr(vcpu, MSR_AMD64_PERF_CNTR_GLOBAL_CTL,
+				  MSR_TYPE_RW, intercept);
+	svm_set_intercept_for_msr(vcpu, MSR_AMD64_PERF_CNTR_GLOBAL_STATUS,
+				  MSR_TYPE_RW, intercept);
+	svm_set_intercept_for_msr(vcpu, MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR,
+				  MSR_TYPE_RW, intercept);
+	svm_set_intercept_for_msr(vcpu, MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_SET,
+				  MSR_TYPE_RW, intercept);
+}
+
 static void svm_recalc_msr_intercepts(struct kvm_vcpu *vcpu)
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
@@ -798,6 +832,8 @@ static void svm_recalc_msr_intercepts(struct kvm_vcpu *vcpu)
 	if (sev_es_guest(vcpu->kvm))
 		sev_es_recalc_msr_intercepts(vcpu);
 
+	svm_recalc_pmu_msr_intercepts(vcpu);
+
 	/*
 	 * x2APIC intercepts are modified on-demand and cannot be filtered by
 	 * userspace.
diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
index dbab7cca7a62..820da47454d7 100644
--- a/arch/x86/kvm/vmx/pmu_intel.c
+++ b/arch/x86/kvm/vmx/pmu_intel.c
@@ -128,19 +128,6 @@ static struct kvm_pmc *intel_rdpmc_ecx_to_pmc(struct kvm_vcpu *vcpu,
 	return &counters[array_index_nospec(idx, num_counters)];
 }
 
-static inline u64 vcpu_get_perf_capabilities(struct kvm_vcpu *vcpu)
-{
-	if (!guest_cpu_cap_has(vcpu, X86_FEATURE_PDCM))
-		return 0;
-
-	return vcpu->arch.perf_capabilities;
-}
-
-static inline bool fw_writes_is_enabled(struct kvm_vcpu *vcpu)
-{
-	return (vcpu_get_perf_capabilities(vcpu) & PERF_CAP_FW_WRITES) != 0;
-}
-
 static inline struct kvm_pmc *get_fw_gp_pmc(struct kvm_pmu *pmu, u32 msr)
 {
 	if (!fw_writes_is_enabled(pmu_to_vcpu(pmu)))
diff --git a/arch/x86/kvm/vmx/pmu_intel.h b/arch/x86/kvm/vmx/pmu_intel.h
index 5620d0882cdc..5d9357640aa1 100644
--- a/arch/x86/kvm/vmx/pmu_intel.h
+++ b/arch/x86/kvm/vmx/pmu_intel.h
@@ -4,6 +4,21 @@
 
 #include <linux/kvm_host.h>
 
+#include "cpuid.h"
+
+static inline u64 vcpu_get_perf_capabilities(struct kvm_vcpu *vcpu)
+{
+	if (!guest_cpu_cap_has(vcpu, X86_FEATURE_PDCM))
+		return 0;
+
+	return vcpu->arch.perf_capabilities;
+}
+
+static inline bool fw_writes_is_enabled(struct kvm_vcpu *vcpu)
+{
+	return (vcpu_get_perf_capabilities(vcpu) & PERF_CAP_FW_WRITES) != 0;
+}
+
 bool intel_pmu_lbr_is_enabled(struct kvm_vcpu *vcpu);
 int intel_pmu_create_guest_lbr_event(struct kvm_vcpu *vcpu);
 
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 72b92cea9d72..f0a20ff2a941 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -4228,6 +4228,53 @@ void pt_update_intercept_for_msr(struct kvm_vcpu *vcpu)
 	}
 }
 
+static void vmx_recalc_pmu_msr_intercepts(struct kvm_vcpu *vcpu)
+{
+	bool has_mediated_pmu = kvm_vcpu_has_mediated_pmu(vcpu);
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+	struct vcpu_vmx *vmx = to_vmx(vcpu);
+	bool intercept = !has_mediated_pmu;
+	int i;
+
+	if (!enable_mediated_pmu)
+		return;
+
+	vm_entry_controls_changebit(vmx, VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL,
+				    has_mediated_pmu);
+
+	vm_exit_controls_changebit(vmx, VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL |
+					VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL,
+				   has_mediated_pmu);
+
+	for (i = 0; i < pmu->nr_arch_gp_counters; i++) {
+		vmx_set_intercept_for_msr(vcpu, MSR_IA32_PERFCTR0 + i,
+					  MSR_TYPE_RW, intercept);
+		vmx_set_intercept_for_msr(vcpu, MSR_IA32_PMC0 + i, MSR_TYPE_RW,
+					  intercept || !fw_writes_is_enabled(vcpu));
+	}
+	for ( ; i < kvm_pmu_cap.num_counters_gp; i++) {
+		vmx_set_intercept_for_msr(vcpu, MSR_IA32_PERFCTR0 + i,
+					  MSR_TYPE_RW, true);
+		vmx_set_intercept_for_msr(vcpu, MSR_IA32_PMC0 + i,
+					  MSR_TYPE_RW, true);
+	}
+
+	for (i = 0; i < pmu->nr_arch_fixed_counters; i++)
+		vmx_set_intercept_for_msr(vcpu, MSR_CORE_PERF_FIXED_CTR0 + i,
+					  MSR_TYPE_RW, intercept);
+	for ( ; i < kvm_pmu_cap.num_counters_fixed; i++)
+		vmx_set_intercept_for_msr(vcpu, MSR_CORE_PERF_FIXED_CTR0 + i,
+					  MSR_TYPE_RW, true);
+
+	intercept = kvm_need_perf_global_ctrl_intercept(vcpu);
+	vmx_set_intercept_for_msr(vcpu, MSR_CORE_PERF_GLOBAL_STATUS,
+				  MSR_TYPE_RW, intercept);
+	vmx_set_intercept_for_msr(vcpu, MSR_CORE_PERF_GLOBAL_CTRL,
+				  MSR_TYPE_RW, intercept);
+	vmx_set_intercept_for_msr(vcpu, MSR_CORE_PERF_GLOBAL_OVF_CTRL,
+				  MSR_TYPE_RW, intercept);
+}
+
 static void vmx_recalc_msr_intercepts(struct kvm_vcpu *vcpu)
 {
 	bool intercept;
@@ -4294,17 +4341,7 @@ static void vmx_recalc_msr_intercepts(struct kvm_vcpu *vcpu)
 		vmx_set_intercept_for_msr(vcpu, MSR_IA32_S_CET, MSR_TYPE_RW, intercept);
 	}
 
-	if (enable_mediated_pmu) {
-		bool is_mediated_pmu = kvm_vcpu_has_mediated_pmu(vcpu);
-		struct vcpu_vmx *vmx = to_vmx(vcpu);
-
-		vm_entry_controls_changebit(vmx,
-					    VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL, is_mediated_pmu);
-
-		vm_exit_controls_changebit(vmx,
-					   VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL |
-					   VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL, is_mediated_pmu);
-	}
+	vmx_recalc_pmu_msr_intercepts(vcpu);
 
 	/*
 	 * x2APIC and LBR MSR intercepts are modified on-demand and cannot be
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:16:59 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:16:59 -0800
Subject: [PATCH v6 23/44] KVM: x86/pmu: Bypass perf checks when emulating
 mediated PMU counter accesses
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-24-seanjc@google.com>

From: Dapeng Mi <dapeng1.mi at linux.intel.com>

When emulating a PMC counter read or write for a mediated PMU, bypass the
perf checks and emulated_counter logic as the counters aren't proxied
through perf, i.e. pmc->counter always holds the guest's up-to-date value,
and thus there's no need to defer emulated overflow checks.

Suggested-by: Sean Christopherson <seanjc at google.com>
Signed-off-by: Dapeng Mi <dapeng1.mi at linux.intel.com>
Co-developed-by: Mingwei Zhang <mizhang at google.com>
Signed-off-by: Mingwei Zhang <mizhang at google.com>
[sean: split from event filtering change, write shortlog+changelog]
Reviewed-by: Sandipan Das <sandipan.das at amd.com>
Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/kvm/pmu.c | 5 +++++
 arch/x86/kvm/pmu.h | 3 +++
 2 files changed, 8 insertions(+)

diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index 57833f29a746..621722e8cc7e 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -381,6 +381,11 @@ static void pmc_update_sample_period(struct kvm_pmc *pmc)
 
 void pmc_write_counter(struct kvm_pmc *pmc, u64 val)
 {
+	if (kvm_vcpu_has_mediated_pmu(pmc->vcpu)) {
+		pmc->counter = val & pmc_bitmask(pmc);
+		return;
+	}
+
 	/*
 	 * Drop any unconsumed accumulated counts, the WRMSR is a write, not a
 	 * read-modify-write.  Adjust the counter value so that its value is
diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h
index 356b08e92bc9..9a199109d672 100644
--- a/arch/x86/kvm/pmu.h
+++ b/arch/x86/kvm/pmu.h
@@ -111,6 +111,9 @@ static inline u64 pmc_read_counter(struct kvm_pmc *pmc)
 {
 	u64 counter, enabled, running;
 
+	if (kvm_vcpu_has_mediated_pmu(pmc->vcpu))
+		return pmc->counter & pmc_bitmask(pmc);
+
 	counter = pmc->counter + pmc->emulated_counter;
 
 	if (pmc->perf_event && !pmc->is_paused)
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:17:00 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:17:00 -0800
Subject: [PATCH v6 24/44] KVM: x86/pmu: Introduce eventsel_hw to prepare for
 pmu event filtering
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-25-seanjc@google.com>

From: Mingwei Zhang <mizhang at google.com>

Introduce eventsel_hw and fixed_ctr_ctrl_hw to store the actual HW value in
PMU event selector MSRs. In mediated PMU checks events before allowing the
event values written to the PMU MSRs. However, to match the HW behavior,
when PMU event checks fails, KVM should allow guest to read the value back.

This essentially requires an extra variable to separate the guest requested
value from actual PMU MSR value. Note this only applies to event selectors.

Signed-off-by: Mingwei Zhang <mizhang at google.com>
Co-developed-by: Dapeng Mi <dapeng1.mi at linux.intel.com>
Signed-off-by: Dapeng Mi <dapeng1.mi at linux.intel.com>
Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/include/asm/kvm_host.h | 2 ++
 arch/x86/kvm/pmu.c              | 7 +++++--
 arch/x86/kvm/svm/pmu.c          | 1 +
 arch/x86/kvm/vmx/pmu_intel.c    | 2 ++
 4 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index defd979003be..e72357f64b19 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -529,6 +529,7 @@ struct kvm_pmc {
 	 */
 	u64 emulated_counter;
 	u64 eventsel;
+	u64 eventsel_hw;
 	struct perf_event *perf_event;
 	struct kvm_vcpu *vcpu;
 	/*
@@ -557,6 +558,7 @@ struct kvm_pmu {
 	unsigned nr_arch_fixed_counters;
 	unsigned available_event_types;
 	u64 fixed_ctr_ctrl;
+	u64 fixed_ctr_ctrl_hw;
 	u64 fixed_ctr_ctrl_rsvd;
 	u64 global_ctrl;
 	u64 global_status;
diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index 621722e8cc7e..36eebc1c7e70 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -902,11 +902,14 @@ static void kvm_pmu_reset(struct kvm_vcpu *vcpu)
 		pmc->counter = 0;
 		pmc->emulated_counter = 0;
 
-		if (pmc_is_gp(pmc))
+		if (pmc_is_gp(pmc)) {
 			pmc->eventsel = 0;
+			pmc->eventsel_hw = 0;
+		}
 	}
 
-	pmu->fixed_ctr_ctrl = pmu->global_ctrl = pmu->global_status = 0;
+	pmu->fixed_ctr_ctrl = pmu->fixed_ctr_ctrl_hw = 0;
+	pmu->global_ctrl = pmu->global_status = 0;
 
 	kvm_pmu_call(reset)(vcpu);
 }
diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c
index 16c88b2a2eb8..c1ec1962314e 100644
--- a/arch/x86/kvm/svm/pmu.c
+++ b/arch/x86/kvm/svm/pmu.c
@@ -166,6 +166,7 @@ static int amd_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 		data &= ~pmu->reserved_bits;
 		if (data != pmc->eventsel) {
 			pmc->eventsel = data;
+			pmc->eventsel_hw = data;
 			kvm_pmu_request_counter_reprogram(pmc);
 		}
 		return 0;
diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
index 820da47454d7..855240678300 100644
--- a/arch/x86/kvm/vmx/pmu_intel.c
+++ b/arch/x86/kvm/vmx/pmu_intel.c
@@ -61,6 +61,7 @@ static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data)
 	int i;
 
 	pmu->fixed_ctr_ctrl = data;
+	pmu->fixed_ctr_ctrl_hw = data;
 	for (i = 0; i < pmu->nr_arch_fixed_counters; i++) {
 		u8 new_ctrl = fixed_ctrl_field(data, i);
 		u8 old_ctrl = fixed_ctrl_field(old_fixed_ctr_ctrl, i);
@@ -430,6 +431,7 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 
 			if (data != pmc->eventsel) {
 				pmc->eventsel = data;
+				pmc->eventsel_hw = data;
 				kvm_pmu_request_counter_reprogram(pmc);
 			}
 			break;
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:17:03 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:17:03 -0800
Subject: [PATCH v6 27/44] KVM: x86/pmu: Load/put mediated PMU context when
 entering/exiting guest
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-28-seanjc@google.com>

From: Dapeng Mi <dapeng1.mi at linux.intel.com>

Implement the PMU "world switch" between host perf and guest mediated PMU.
When loading guest state, call into perf to switch from host to guest, and
then load guest state into hardware, and then reverse those actions when
putting guest state.

On the KVM side, when loading guest state, zero PERF_GLOBAL_CTRL to ensure
all counters are disabled, then load selectors and counters, and finally
call into vendor code to load control/status information.  While VMX and
SVM use different mechanisms to avoid counting host activity while guest
controls are loaded, both implementations require PERF_GLOBAL_CTRL to be
zeroed when the event selectors are in flux.

When putting guest state, reverse the order, and save and zero controls
and status prior to saving+zeroing selectors and counters.  Defer clearing
PERF_GLOBAL_CTRL to vendor code, as only SVM needs to manually clear the
MSR; VMX configures PERF_GLOBAL_CTRL to be atomically cleared by the CPU
on VM-Exit.

Handle the difference in MSR layouts between Intel and AMD by communicating
the bases and stride via kvm_pmu_ops.  Because KVM requires Intel v4 (and
full-width writes) and AMD v2, the MSRs to load/save are constant for a
given vendor, i.e. do not vary based on the guest PMU, and do not vary
based on host PMU (because KVM will simply disable mediated PMU support if
the necessary MSRs are unsupported).

Except for retrieving the guest's PERF_GLOBAL_CTRL, which needs to be read
before invoking any fastpath handler (spoiler alert), perform the context
switch around KVM's inner run loop.  State only needs to be synchronized
from hardware before KVM can access the software "caches".

Note, VMX already grabs the guest's PERF_GLOBAL_CTRL immediately after
VM-Exit, as hardware saves value into the VMCS.

Co-developed-by: Mingwei Zhang <mizhang at google.com>
Signed-off-by: Mingwei Zhang <mizhang at google.com>
Co-developed-by: Sandipan Das <sandipan.das at amd.com>
Signed-off-by: Sandipan Das <sandipan.das at amd.com>
Signed-off-by: Dapeng Mi <dapeng1.mi at linux.intel.com>
Tested-by: Xudong Hao <xudong.hao at intel.com>
Co-developed-by: Sean Christopherson <seanjc at google.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/include/asm/kvm-x86-pmu-ops.h |   2 +
 arch/x86/include/asm/msr-index.h       |   1 +
 arch/x86/kvm/pmu.c                     | 130 ++++++++++++++++++++++++-
 arch/x86/kvm/pmu.h                     |  10 ++
 arch/x86/kvm/svm/pmu.c                 |  34 +++++++
 arch/x86/kvm/svm/svm.c                 |   3 +
 arch/x86/kvm/vmx/pmu_intel.c           |  44 +++++++++
 arch/x86/kvm/x86.c                     |   4 +
 8 files changed, 225 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/asm/kvm-x86-pmu-ops.h b/arch/x86/include/asm/kvm-x86-pmu-ops.h
index ad2cc82abf79..f0aa6996811f 100644
--- a/arch/x86/include/asm/kvm-x86-pmu-ops.h
+++ b/arch/x86/include/asm/kvm-x86-pmu-ops.h
@@ -24,6 +24,8 @@ KVM_X86_PMU_OP_OPTIONAL(deliver_pmi)
 KVM_X86_PMU_OP_OPTIONAL(cleanup)
 
 KVM_X86_PMU_OP_OPTIONAL(write_global_ctrl)
+KVM_X86_PMU_OP(mediated_load)
+KVM_X86_PMU_OP(mediated_put)
 
 #undef KVM_X86_PMU_OP
 #undef KVM_X86_PMU_OP_OPTIONAL
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index 9e1720d73244..0ba08fd4ac3f 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -1191,6 +1191,7 @@
 #define MSR_CORE_PERF_GLOBAL_STATUS	0x0000038e
 #define MSR_CORE_PERF_GLOBAL_CTRL	0x0000038f
 #define MSR_CORE_PERF_GLOBAL_OVF_CTRL	0x00000390
+#define MSR_CORE_PERF_GLOBAL_STATUS_SET	0x00000391
 
 #define MSR_PERF_METRICS		0x00000329
 
diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index 39904e6fd227..578bf996bda2 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -882,10 +882,13 @@ int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 			diff = pmu->global_ctrl ^ data;
 			pmu->global_ctrl = data;
 			reprogram_counters(pmu, diff);
-
-			if (kvm_vcpu_has_mediated_pmu(vcpu))
-				kvm_pmu_call(write_global_ctrl)(data);
 		}
+		/*
+		 * Unconditionally forward writes to vendor code, i.e. to the
+		 * VMC{B,S}, as pmu->global_ctrl is per-VCPU, not per-VMC{B,S}.
+		 */
+		if (kvm_vcpu_has_mediated_pmu(vcpu))
+			kvm_pmu_call(write_global_ctrl)(data);
 		break;
 	case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
 		/*
@@ -1246,3 +1249,124 @@ int kvm_vm_ioctl_set_pmu_event_filter(struct kvm *kvm, void __user *argp)
 	kfree(filter);
 	return r;
 }
+
+static __always_inline u32 fixed_counter_msr(u32 idx)
+{
+	return kvm_pmu_ops.FIXED_COUNTER_BASE + idx * kvm_pmu_ops.MSR_STRIDE;
+}
+
+static __always_inline u32 gp_counter_msr(u32 idx)
+{
+	return kvm_pmu_ops.GP_COUNTER_BASE + idx * kvm_pmu_ops.MSR_STRIDE;
+}
+
+static __always_inline u32 gp_eventsel_msr(u32 idx)
+{
+	return kvm_pmu_ops.GP_EVENTSEL_BASE + idx * kvm_pmu_ops.MSR_STRIDE;
+}
+
+static void kvm_pmu_load_guest_pmcs(struct kvm_vcpu *vcpu)
+{
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+	struct kvm_pmc *pmc;
+	u32 i;
+
+	/*
+	 * No need to zero out unexposed GP/fixed counters/selectors since RDPMC
+	 * is intercepted if hardware has counters that aren't visible to the
+	 * guest (KVM will inject #GP as appropriate).
+	 */
+	for (i = 0; i < pmu->nr_arch_gp_counters; i++) {
+		pmc = &pmu->gp_counters[i];
+
+		wrmsrl(gp_counter_msr(i), pmc->counter);
+		wrmsrl(gp_eventsel_msr(i), pmc->eventsel_hw);
+	}
+	for (i = 0; i < pmu->nr_arch_fixed_counters; i++) {
+		pmc = &pmu->fixed_counters[i];
+
+		wrmsrl(fixed_counter_msr(i), pmc->counter);
+	}
+}
+
+void kvm_mediated_pmu_load(struct kvm_vcpu *vcpu)
+{
+	if (!kvm_vcpu_has_mediated_pmu(vcpu) ||
+	    KVM_BUG_ON(!lapic_in_kernel(vcpu), vcpu->kvm))
+		return;
+
+	lockdep_assert_irqs_disabled();
+
+	perf_load_guest_context();
+
+	/*
+	 * Explicitly clear PERF_GLOBAL_CTRL, as "loading" the guest's context
+	 * disables all individual counters (if any were enabled), but doesn't
+	 * globally disable the entire PMU.  Loading event selectors and PMCs
+	 * with guest values while PERF_GLOBAL_CTRL is non-zero will generate
+	 * unexpected events and PMIs.
+	 *
+	 * VMX will enable/disable counters at VM-Enter/VM-Exit by atomically
+	 * loading PERF_GLOBAL_CONTROL.  SVM effectively performs the switch by
+	 * configuring all events to be GUEST_ONLY.  Clear PERF_GLOBAL_CONTROL
+	 * even for SVM to minimize the damage if a perf event is left enabled,
+	 * and to ensure a consistent starting state.
+	 */
+	wrmsrq(kvm_pmu_ops.PERF_GLOBAL_CTRL, 0);
+
+	perf_load_guest_lvtpc(kvm_lapic_get_reg(vcpu->arch.apic, APIC_LVTPC));
+
+	kvm_pmu_load_guest_pmcs(vcpu);
+
+	kvm_pmu_call(mediated_load)(vcpu);
+}
+
+static void kvm_pmu_put_guest_pmcs(struct kvm_vcpu *vcpu)
+{
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+	struct kvm_pmc *pmc;
+	u32 i;
+
+	/*
+	 * Clear selectors and counters to ensure hardware doesn't count using
+	 * guest controls when the host (perf) restores its state.
+	 */
+	for (i = 0; i < pmu->nr_arch_gp_counters; i++) {
+		pmc = &pmu->gp_counters[i];
+
+		pmc->counter = rdpmc(i);
+		if (pmc->counter)
+			wrmsrq(gp_counter_msr(i), 0);
+		if (pmc->eventsel_hw)
+			wrmsrq(gp_eventsel_msr(i), 0);
+	}
+
+	for (i = 0; i < pmu->nr_arch_fixed_counters; i++) {
+		pmc = &pmu->fixed_counters[i];
+
+		pmc->counter = rdpmc(INTEL_PMC_FIXED_RDPMC_BASE | i);
+		if (pmc->counter)
+			wrmsrq(fixed_counter_msr(i), 0);
+	}
+}
+
+void kvm_mediated_pmu_put(struct kvm_vcpu *vcpu)
+{
+	if (!kvm_vcpu_has_mediated_pmu(vcpu) ||
+	    KVM_BUG_ON(!lapic_in_kernel(vcpu), vcpu->kvm))
+		return;
+
+	lockdep_assert_irqs_disabled();
+
+	/*
+	 * Defer handling of PERF_GLOBAL_CTRL to vendor code.  On Intel, it's
+	 * atomically cleared on VM-Exit, i.e. doesn't need to be clear here.
+	 */
+	kvm_pmu_call(mediated_put)(vcpu);
+
+	kvm_pmu_put_guest_pmcs(vcpu);
+
+	perf_put_guest_lvtpc();
+
+	perf_put_guest_context();
+}
diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h
index 9a199109d672..25b583da9ee2 100644
--- a/arch/x86/kvm/pmu.h
+++ b/arch/x86/kvm/pmu.h
@@ -38,11 +38,19 @@ struct kvm_pmu_ops {
 	void (*cleanup)(struct kvm_vcpu *vcpu);
 
 	bool (*is_mediated_pmu_supported)(struct x86_pmu_capability *host_pmu);
+	void (*mediated_load)(struct kvm_vcpu *vcpu);
+	void (*mediated_put)(struct kvm_vcpu *vcpu);
 	void (*write_global_ctrl)(u64 global_ctrl);
 
 	const u64 EVENTSEL_EVENT;
 	const int MAX_NR_GP_COUNTERS;
 	const int MIN_NR_GP_COUNTERS;
+
+	const u32 PERF_GLOBAL_CTRL;
+	const u32 GP_EVENTSEL_BASE;
+	const u32 GP_COUNTER_BASE;
+	const u32 FIXED_COUNTER_BASE;
+	const u32 MSR_STRIDE;
 };
 
 void kvm_pmu_ops_update(const struct kvm_pmu_ops *pmu_ops);
@@ -240,6 +248,8 @@ void kvm_pmu_destroy(struct kvm_vcpu *vcpu);
 int kvm_vm_ioctl_set_pmu_event_filter(struct kvm *kvm, void __user *argp);
 void kvm_pmu_instruction_retired(struct kvm_vcpu *vcpu);
 void kvm_pmu_branch_retired(struct kvm_vcpu *vcpu);
+void kvm_mediated_pmu_load(struct kvm_vcpu *vcpu);
+void kvm_mediated_pmu_put(struct kvm_vcpu *vcpu);
 
 bool is_vmware_backdoor_pmc(u32 pmc_idx);
 bool kvm_need_perf_global_ctrl_intercept(struct kvm_vcpu *vcpu);
diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c
index 6d5f791126b1..7aa298eeb072 100644
--- a/arch/x86/kvm/svm/pmu.c
+++ b/arch/x86/kvm/svm/pmu.c
@@ -234,6 +234,32 @@ static bool amd_pmu_is_mediated_pmu_supported(struct x86_pmu_capability *host_pm
 	return host_pmu->version >= 2;
 }
 
+static void amd_mediated_pmu_load(struct kvm_vcpu *vcpu)
+{
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+	u64 global_status;
+
+	rdmsrq(MSR_AMD64_PERF_CNTR_GLOBAL_STATUS, global_status);
+	/* Clear host global_status MSR if non-zero. */
+	if (global_status)
+		wrmsrq(MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR, global_status);
+
+	wrmsrq(MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_SET, pmu->global_status);
+	wrmsrq(MSR_AMD64_PERF_CNTR_GLOBAL_CTL, pmu->global_ctrl);
+}
+
+static void amd_mediated_pmu_put(struct kvm_vcpu *vcpu)
+{
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+
+	wrmsrq(MSR_AMD64_PERF_CNTR_GLOBAL_CTL, 0);
+	rdmsrq(MSR_AMD64_PERF_CNTR_GLOBAL_STATUS, pmu->global_status);
+
+	/* Clear global status bits if non-zero */
+	if (pmu->global_status)
+		wrmsrq(MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR, pmu->global_status);
+}
+
 struct kvm_pmu_ops amd_pmu_ops __initdata = {
 	.rdpmc_ecx_to_pmc = amd_rdpmc_ecx_to_pmc,
 	.msr_idx_to_pmc = amd_msr_idx_to_pmc,
@@ -245,8 +271,16 @@ struct kvm_pmu_ops amd_pmu_ops __initdata = {
 	.init = amd_pmu_init,
 
 	.is_mediated_pmu_supported = amd_pmu_is_mediated_pmu_supported,
+	.mediated_load = amd_mediated_pmu_load,
+	.mediated_put = amd_mediated_pmu_put,
 
 	.EVENTSEL_EVENT = AMD64_EVENTSEL_EVENT,
 	.MAX_NR_GP_COUNTERS = KVM_MAX_NR_AMD_GP_COUNTERS,
 	.MIN_NR_GP_COUNTERS = AMD64_NUM_COUNTERS,
+
+	.PERF_GLOBAL_CTRL = MSR_AMD64_PERF_CNTR_GLOBAL_CTL,
+	.GP_EVENTSEL_BASE = MSR_F15H_PERF_CTL0,
+	.GP_COUNTER_BASE = MSR_F15H_PERF_CTR0,
+	.FIXED_COUNTER_BASE = 0,
+	.MSR_STRIDE = 2,
 };
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index fa04e58ff524..cbebd3a18918 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -4368,6 +4368,9 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu, u64 run_flags)
 
 	vcpu->arch.regs_avail &= ~SVM_REGS_LAZY_LOAD_SET;
 
+	if (!msr_write_intercepted(vcpu, MSR_AMD64_PERF_CNTR_GLOBAL_CTL))
+		rdmsrq(MSR_AMD64_PERF_CNTR_GLOBAL_CTL, vcpu_to_pmu(vcpu)->global_ctrl);
+
 	trace_kvm_exit(vcpu, KVM_ISA_SVM);
 
 	svm_complete_interrupts(vcpu);
diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
index 855240678300..55249fa4db95 100644
--- a/arch/x86/kvm/vmx/pmu_intel.c
+++ b/arch/x86/kvm/vmx/pmu_intel.c
@@ -792,6 +792,42 @@ static void intel_pmu_write_global_ctrl(u64 global_ctrl)
 	vmcs_write64(GUEST_IA32_PERF_GLOBAL_CTRL, global_ctrl);
 }
 
+
+static void intel_mediated_pmu_load(struct kvm_vcpu *vcpu)
+{
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+	u64 global_status, toggle;
+
+	rdmsrq(MSR_CORE_PERF_GLOBAL_STATUS, global_status);
+	toggle = pmu->global_status ^ global_status;
+	if (global_status & toggle)
+		wrmsrq(MSR_CORE_PERF_GLOBAL_OVF_CTRL, global_status & toggle);
+	if (pmu->global_status & toggle)
+		wrmsrq(MSR_CORE_PERF_GLOBAL_STATUS_SET, pmu->global_status & toggle);
+
+	wrmsrq(MSR_CORE_PERF_FIXED_CTR_CTRL, pmu->fixed_ctr_ctrl_hw);
+}
+
+static void intel_mediated_pmu_put(struct kvm_vcpu *vcpu)
+{
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+
+	/* MSR_CORE_PERF_GLOBAL_CTRL is already saved at VM-exit. */
+	rdmsrq(MSR_CORE_PERF_GLOBAL_STATUS, pmu->global_status);
+
+	/* Clear hardware MSR_CORE_PERF_GLOBAL_STATUS MSR, if non-zero. */
+	if (pmu->global_status)
+		wrmsrq(MSR_CORE_PERF_GLOBAL_OVF_CTRL, pmu->global_status);
+
+	/*
+	 * Clear hardware FIXED_CTR_CTRL MSR to avoid information leakage and
+	 * also to avoid accidentally enabling fixed counters (based on guest
+	 * state) while running in the host, e.g. when setting global ctrl.
+	 */
+	if (pmu->fixed_ctr_ctrl_hw)
+		wrmsrq(MSR_CORE_PERF_FIXED_CTR_CTRL, 0);
+}
+
 struct kvm_pmu_ops intel_pmu_ops __initdata = {
 	.rdpmc_ecx_to_pmc = intel_rdpmc_ecx_to_pmc,
 	.msr_idx_to_pmc = intel_msr_idx_to_pmc,
@@ -805,9 +841,17 @@ struct kvm_pmu_ops intel_pmu_ops __initdata = {
 	.cleanup = intel_pmu_cleanup,
 
 	.is_mediated_pmu_supported = intel_pmu_is_mediated_pmu_supported,
+	.mediated_load = intel_mediated_pmu_load,
+	.mediated_put = intel_mediated_pmu_put,
 	.write_global_ctrl = intel_pmu_write_global_ctrl,
 
 	.EVENTSEL_EVENT = ARCH_PERFMON_EVENTSEL_EVENT,
 	.MAX_NR_GP_COUNTERS = KVM_MAX_NR_INTEL_GP_COUNTERS,
 	.MIN_NR_GP_COUNTERS = 1,
+
+	.PERF_GLOBAL_CTRL = MSR_CORE_PERF_GLOBAL_CTRL,
+	.GP_EVENTSEL_BASE = MSR_P6_EVNTSEL0,
+	.GP_COUNTER_BASE = MSR_IA32_PMC0,
+	.FIXED_COUNTER_BASE = MSR_CORE_PERF_FIXED_CTR0,
+	.MSR_STRIDE = 1,
 };
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 76e86eb358df..589a309259f4 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -11334,6 +11334,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 		run_flags |= KVM_RUN_LOAD_DEBUGCTL;
 	vcpu->arch.host_debugctl = debug_ctl;
 
+	kvm_mediated_pmu_load(vcpu);
+
 	guest_timing_enter_irqoff();
 
 	/*
@@ -11372,6 +11374,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 
 	kvm_load_host_pkru(vcpu);
 
+	kvm_mediated_pmu_put(vcpu);
+
 	/*
 	 * Do this here before restoring debug registers on the host.  And
 	 * since we do this before handling the vmexit, a DR access vmexit
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:17:01 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:17:01 -0800
Subject: [PATCH v6 25/44] KVM: x86/pmu: Reprogram mediated PMU event selectors
 on event filter updates
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-26-seanjc@google.com>

From: Dapeng Mi <dapeng1.mi at linux.intel.com>

Refresh the event selectors that are programmed into hardware when a PMC
is "reprogrammed" for a mediated PMU, i.e. if userspace changes the PMU
event filters

Note, KVM doesn't utilize the reprogramming infrastructure to handle
counter overflow for mediated PMUs, as there's no need to reprogram a
non-existent perf event.

Suggested-by: Sean Christopherson <seanjc at google.com>
Signed-off-by: Dapeng Mi <dapeng1.mi at linux.intel.com>
Co-developed-by: Mingwei Zhang <mizhang at google.com>
Signed-off-by: Mingwei Zhang <mizhang at google.com>
[sean: add a helper to document behavior, split patch and rewrite changelog]
Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/kvm/pmu.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index 36eebc1c7e70..39904e6fd227 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -522,6 +522,25 @@ static bool pmc_is_event_allowed(struct kvm_pmc *pmc)
 	return is_fixed_event_allowed(filter, pmc->idx);
 }
 
+static void kvm_mediated_pmu_refresh_event_filter(struct kvm_pmc *pmc)
+{
+	bool allowed = pmc_is_event_allowed(pmc);
+	struct kvm_pmu *pmu = pmc_to_pmu(pmc);
+
+	if (pmc_is_gp(pmc)) {
+		pmc->eventsel_hw &= ~ARCH_PERFMON_EVENTSEL_ENABLE;
+		if (allowed)
+			pmc->eventsel_hw |= pmc->eventsel &
+					    ARCH_PERFMON_EVENTSEL_ENABLE;
+	} else {
+		u64 mask = intel_fixed_bits_by_idx(pmc->idx - KVM_FIXED_PMC_BASE_IDX, 0xf);
+
+		pmu->fixed_ctr_ctrl_hw &= ~mask;
+		if (allowed)
+			pmu->fixed_ctr_ctrl_hw |= pmu->fixed_ctr_ctrl & mask;
+	}
+}
+
 static int reprogram_counter(struct kvm_pmc *pmc)
 {
 	struct kvm_pmu *pmu = pmc_to_pmu(pmc);
@@ -530,6 +549,11 @@ static int reprogram_counter(struct kvm_pmc *pmc)
 	bool emulate_overflow;
 	u8 fixed_ctr_ctrl;
 
+	if (kvm_vcpu_has_mediated_pmu(pmu_to_vcpu(pmu))) {
+		kvm_mediated_pmu_refresh_event_filter(pmc);
+		return 0;
+	}
+
 	emulate_overflow = pmc_pause_counter(pmc);
 
 	if (!pmc_is_globally_enabled(pmc) || !pmc_is_locally_enabled(pmc) ||
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:17:04 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:17:04 -0800
Subject: [PATCH v6 28/44] KVM: x86/pmu: Disallow emulation in the fastpath if
 mediated PMCs are active
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-29-seanjc@google.com>

Don't handle exits in the fastpath if emulation is required, i.e. if an
instruction needs to be skipped, the mediated PMU is enabled, and one or
more PMCs is counting instructions.  With the mediated PMU, KVM's cache of
PMU state is inconsistent with respect to hardware until KVM exits the
inner run loop (when the mediated PMU is "put").

Reviewed-by: Sandipan Das <sandipan.das at amd.com>
Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/kvm/pmu.h | 10 ++++++++++
 arch/x86/kvm/x86.c |  9 +++++++++
 2 files changed, 19 insertions(+)

diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h
index 25b583da9ee2..0925246731cb 100644
--- a/arch/x86/kvm/pmu.h
+++ b/arch/x86/kvm/pmu.h
@@ -234,6 +234,16 @@ static inline bool pmc_is_globally_enabled(struct kvm_pmc *pmc)
 	return test_bit(pmc->idx, (unsigned long *)&pmu->global_ctrl);
 }
 
+static inline bool kvm_pmu_is_fastpath_emulation_allowed(struct kvm_vcpu *vcpu)
+{
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+
+	return !kvm_vcpu_has_mediated_pmu(vcpu) ||
+	       !bitmap_intersects(pmu->pmc_counting_instructions,
+				  (unsigned long *)&pmu->global_ctrl,
+				  X86_PMC_IDX_MAX);
+}
+
 void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu);
 void kvm_pmu_handle_event(struct kvm_vcpu *vcpu);
 int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 589a309259f4..4683df775b0a 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2215,6 +2215,9 @@ EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_emulate_invd);
 
 fastpath_t handle_fastpath_invd(struct kvm_vcpu *vcpu)
 {
+	if (!kvm_pmu_is_fastpath_emulation_allowed(vcpu))
+		return EXIT_FASTPATH_NONE;
+
 	if (!kvm_emulate_invd(vcpu))
 		return EXIT_FASTPATH_EXIT_USERSPACE;
 
@@ -2271,6 +2274,9 @@ static inline bool kvm_vcpu_exit_request(struct kvm_vcpu *vcpu)
 
 static fastpath_t __handle_fastpath_wrmsr(struct kvm_vcpu *vcpu, u32 msr, u64 data)
 {
+	if (!kvm_pmu_is_fastpath_emulation_allowed(vcpu))
+		return EXIT_FASTPATH_NONE;
+
 	switch (msr) {
 	case APIC_BASE_MSR + (APIC_ICR >> 4):
 		if (!lapic_in_kernel(vcpu) || !apic_x2apic_mode(vcpu->arch.apic) ||
@@ -11714,6 +11720,9 @@ EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_emulate_halt);
 
 fastpath_t handle_fastpath_hlt(struct kvm_vcpu *vcpu)
 {
+	if (!kvm_pmu_is_fastpath_emulation_allowed(vcpu))
+		return EXIT_FASTPATH_NONE;
+
 	if (!kvm_emulate_halt(vcpu))
 		return EXIT_FASTPATH_EXIT_USERSPACE;
 
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:17:02 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:17:02 -0800
Subject: [PATCH v6 26/44] KVM: x86/pmu: Always stuff GuestOnly=1,HostOnly=0
 for mediated PMCs on AMD
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-27-seanjc@google.com>

From: Sandipan Das <sandipan.das at amd.com>

On AMD platforms, there is no way to restore PerfCntrGlobalCtl at
VM-Entry or clear it at VM-Exit. Since the register states will be
restored before entering and saved after exiting guest context, the
counters can keep ticking and even overflow leading to chaos while
still in host context.

To avoid this, intecept event selectors, which is already done by mediated
PMU. In addition, always set the GuestOnly bit and clear the HostOnly bit
for PMU selectors on AMD. Doing so allows the counters run only in guest
context even if their enable bits are still set after VM exit and before
host/guest PMU context switch.

Signed-off-by: Sandipan Das <sandipan.das at amd.com>
Signed-off-by: Mingwei Zhang <mizhang at google.com>
[sean: massage shortlog]
Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/kvm/svm/pmu.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c
index c1ec1962314e..6d5f791126b1 100644
--- a/arch/x86/kvm/svm/pmu.c
+++ b/arch/x86/kvm/svm/pmu.c
@@ -166,7 +166,8 @@ static int amd_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 		data &= ~pmu->reserved_bits;
 		if (data != pmc->eventsel) {
 			pmc->eventsel = data;
-			pmc->eventsel_hw = data;
+			pmc->eventsel_hw = (data & ~AMD64_EVENTSEL_HOSTONLY) |
+					   AMD64_EVENTSEL_GUESTONLY;
 			kvm_pmu_request_counter_reprogram(pmc);
 		}
 		return 0;
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:17:06 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:17:06 -0800
Subject: [PATCH v6 30/44] KVM: nVMX: Add macros to simplify nested MSR
 interception setting
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-31-seanjc@google.com>

From: Dapeng Mi <dapeng1.mi at linux.intel.com>

Add macros nested_vmx_merge_msr_bitmaps_xxx() to simplify nested MSR
interception setting. No function change intended.

Suggested-by: Sean Christopherson <seanjc at google.com>
Signed-off-by: Dapeng Mi <dapeng1.mi at linux.intel.com>
Signed-off-by: Mingwei Zhang <mizhang at google.com>
Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/kvm/vmx/nested.c | 35 +++++++++++++++++++----------------
 1 file changed, 19 insertions(+), 16 deletions(-)

diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index 40777278eabb..b56ed2b1ac67 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -617,6 +617,19 @@ static inline void nested_vmx_set_intercept_for_msr(struct vcpu_vmx *vmx,
 						   msr_bitmap_l0, msr);
 }
 
+#define nested_vmx_merge_msr_bitmaps(msr, type)	\
+	nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1,	\
+					 msr_bitmap_l0, msr, type)
+
+#define nested_vmx_merge_msr_bitmaps_read(msr) \
+	nested_vmx_merge_msr_bitmaps(msr, MSR_TYPE_R)
+
+#define nested_vmx_merge_msr_bitmaps_write(msr) \
+	nested_vmx_merge_msr_bitmaps(msr, MSR_TYPE_W)
+
+#define nested_vmx_merge_msr_bitmaps_rw(msr) \
+	nested_vmx_merge_msr_bitmaps(msr, MSR_TYPE_RW)
+
 /*
  * Merge L0's and L1's MSR bitmap, return false to indicate that
  * we do not use the hardware.
@@ -700,23 +713,13 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu,
 	 * other runtime changes to vmcs01's bitmap, e.g. dynamic pass-through.
 	 */
 #ifdef CONFIG_X86_64
-	nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1, msr_bitmap_l0,
-					 MSR_FS_BASE, MSR_TYPE_RW);
-
-	nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1, msr_bitmap_l0,
-					 MSR_GS_BASE, MSR_TYPE_RW);
-
-	nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1, msr_bitmap_l0,
-					 MSR_KERNEL_GS_BASE, MSR_TYPE_RW);
+	nested_vmx_merge_msr_bitmaps_rw(MSR_FS_BASE);
+	nested_vmx_merge_msr_bitmaps_rw(MSR_GS_BASE);
+	nested_vmx_merge_msr_bitmaps_rw(MSR_KERNEL_GS_BASE);
 #endif
-	nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1, msr_bitmap_l0,
-					 MSR_IA32_SPEC_CTRL, MSR_TYPE_RW);
-
-	nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1, msr_bitmap_l0,
-					 MSR_IA32_PRED_CMD, MSR_TYPE_W);
-
-	nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1, msr_bitmap_l0,
-					 MSR_IA32_FLUSH_CMD, MSR_TYPE_W);
+	nested_vmx_merge_msr_bitmaps_rw(MSR_IA32_SPEC_CTRL);
+	nested_vmx_merge_msr_bitmaps_write(MSR_IA32_PRED_CMD);
+	nested_vmx_merge_msr_bitmaps_write(MSR_IA32_FLUSH_CMD);
 
 	nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1, msr_bitmap_l0,
 					 MSR_IA32_APERF, MSR_TYPE_R);
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:17:05 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:17:05 -0800
Subject: [PATCH v6 29/44] KVM: x86/pmu: Handle emulated instruction for
 mediated vPMU
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-30-seanjc@google.com>

From: Dapeng Mi <dapeng1.mi at linux.intel.com>

Mediated vPMU needs to accumulate the emulated instructions into counter
and load the counter into HW at vm-entry.

Moreover, if the accumulation leads to counter overflow, KVM needs to
update GLOBAL_STATUS and inject PMI into guest as well.

Suggested-by: Sean Christopherson <seanjc at google.com>
Signed-off-by: Dapeng Mi <dapeng1.mi at linux.intel.com>
Signed-off-by: Mingwei Zhang <mizhang at google.com>
Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/kvm/pmu.c | 39 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 37 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index 578bf996bda2..cb07d9b62bee 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -1033,10 +1033,45 @@ void kvm_pmu_destroy(struct kvm_vcpu *vcpu)
 	kvm_pmu_reset(vcpu);
 }
 
+static bool pmc_is_pmi_enabled(struct kvm_pmc *pmc)
+{
+	u8 fixed_ctr_ctrl;
+
+	if (pmc_is_gp(pmc))
+		return pmc->eventsel & ARCH_PERFMON_EVENTSEL_INT;
+
+	fixed_ctr_ctrl = fixed_ctrl_field(pmc_to_pmu(pmc)->fixed_ctr_ctrl,
+					  pmc->idx - KVM_FIXED_PMC_BASE_IDX);
+	return fixed_ctr_ctrl & INTEL_FIXED_0_ENABLE_PMI;
+}
+
 static void kvm_pmu_incr_counter(struct kvm_pmc *pmc)
 {
-	pmc->emulated_counter++;
-	kvm_pmu_request_counter_reprogram(pmc);
+	struct kvm_vcpu *vcpu = pmc->vcpu;
+
+	/*
+	 * For perf-based PMUs, accumulate software-emulated events separately
+	 * from pmc->counter, as pmc->counter is offset by the count of the
+	 * associated perf event. Request reprogramming, which will consult
+	 * both emulated and hardware-generated events to detect overflow.
+	 */
+	if (!kvm_vcpu_has_mediated_pmu(vcpu)) {
+		pmc->emulated_counter++;
+		kvm_pmu_request_counter_reprogram(pmc);
+		return;
+	}
+
+	/*
+	 * For mediated PMUs, pmc->counter is updated when the vCPU's PMU is
+	 * put, and will be loaded into hardware when the PMU is loaded. Simply
+	 * increment the counter and signal overflow if it wraps to zero.
+	 */
+	pmc->counter = (pmc->counter + 1) & pmc_bitmask(pmc);
+	if (!pmc->counter) {
+		pmc_to_pmu(pmc)->global_status |= BIT_ULL(pmc->idx);
+		if (pmc_is_pmi_enabled(pmc))
+			kvm_make_request(KVM_REQ_PMI, vcpu);
+	}
 }
 
 static inline bool cpl_is_matched(struct kvm_pmc *pmc)
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:17:10 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:17:10 -0800
Subject: [PATCH v6 34/44] KVM: x86/pmu: Elide WRMSRs when loading guest PMCs
 if values already match
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-35-seanjc@google.com>

When loading a mediated PMU state, elide the WRMSRs to load PMCs with the
guest's value if the value in hardware already matches the guest's value.
For the relatively common case where neither the guest nor the host is
actively using the PMU, i.e. when all/many counters are '0', eliding the
WRMSRs reduces the latency of handling VM-Exit by a measurable amount
(WRMSR is significantly more expensive than RDPMC).

As measured by KVM-Unit-Tests' CPUID VM-Exit testcase, this provides a
a ~25% reduction in latency (4k => 3k cycles) on Intel Emerald Rapids,
and a ~13% reduction (6.2k => 5.3k cycles) on AMD Turin.

Cc: Manali Shukla <manali.shukla at amd.com>
Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/kvm/pmu.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index cb07d9b62bee..fdf1df3100eb 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -1314,13 +1314,15 @@ static void kvm_pmu_load_guest_pmcs(struct kvm_vcpu *vcpu)
 	for (i = 0; i < pmu->nr_arch_gp_counters; i++) {
 		pmc = &pmu->gp_counters[i];
 
-		wrmsrl(gp_counter_msr(i), pmc->counter);
+		if (pmc->counter != rdpmc(i))
+			wrmsrl(gp_counter_msr(i), pmc->counter);
 		wrmsrl(gp_eventsel_msr(i), pmc->eventsel_hw);
 	}
 	for (i = 0; i < pmu->nr_arch_fixed_counters; i++) {
 		pmc = &pmu->fixed_counters[i];
 
-		wrmsrl(fixed_counter_msr(i), pmc->counter);
+		if (pmc->counter != rdpmc(INTEL_PMC_FIXED_RDPMC_BASE | i))
+			wrmsrl(fixed_counter_msr(i), pmc->counter);
 	}
 }
 
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:17:07 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:17:07 -0800
Subject: [PATCH v6 31/44] KVM: nVMX: Disable PMU MSR interception as
 appropriate while running L2
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-32-seanjc@google.com>

From: Mingwei Zhang <mizhang at google.com>

Merge KVM's PMU MSR interception bitmaps with those of L1, i.e. merge the
bitmaps of vmcs01 and vmcs12, e.g. so that KVM doesn't interpose on MSR
accesses unnecessarily if L1 exposes a mediated PMU (or equivalent) to L2.

Signed-off-by: Mingwei Zhang <mizhang at google.com>
Co-developed-by: Dapeng Mi <dapeng1.mi at linux.intel.com>
Signed-off-by: Dapeng Mi <dapeng1.mi at linux.intel.com>
[sean: rewrite changelog and comment, omit MSRs that are always intercepted]
Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/kvm/vmx/nested.c | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index b56ed2b1ac67..729cc1f05ac8 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -630,6 +630,34 @@ static inline void nested_vmx_set_intercept_for_msr(struct vcpu_vmx *vmx,
 #define nested_vmx_merge_msr_bitmaps_rw(msr) \
 	nested_vmx_merge_msr_bitmaps(msr, MSR_TYPE_RW)
 
+static void nested_vmx_merge_pmu_msr_bitmaps(struct kvm_vcpu *vcpu,
+					     unsigned long *msr_bitmap_l1,
+					     unsigned long *msr_bitmap_l0)
+{
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+	struct vcpu_vmx *vmx = to_vmx(vcpu);
+	int i;
+
+	/*
+	 * Skip the merges if the vCPU doesn't have a mediated PMU MSR, i.e. if
+	 * none of the MSRs can possibly be passed through to L1.
+	 */
+	if (!kvm_vcpu_has_mediated_pmu(vcpu))
+		return;
+
+	for (i = 0; i < pmu->nr_arch_gp_counters; i++) {
+		nested_vmx_merge_msr_bitmaps_rw(MSR_IA32_PERFCTR0 + i);
+		nested_vmx_merge_msr_bitmaps_rw(MSR_IA32_PMC0 + i);
+	}
+
+	for (i = 0; i < pmu->nr_arch_fixed_counters; i++)
+		nested_vmx_merge_msr_bitmaps_rw(MSR_CORE_PERF_FIXED_CTR0 + i);
+
+	nested_vmx_merge_msr_bitmaps_rw(MSR_CORE_PERF_GLOBAL_CTRL);
+	nested_vmx_merge_msr_bitmaps_read(MSR_CORE_PERF_GLOBAL_STATUS);
+	nested_vmx_merge_msr_bitmaps_write(MSR_CORE_PERF_GLOBAL_OVF_CTRL);
+}
+
 /*
  * Merge L0's and L1's MSR bitmap, return false to indicate that
  * we do not use the hardware.
@@ -745,6 +773,8 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu,
 	nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1, msr_bitmap_l0,
 					 MSR_IA32_PL3_SSP, MSR_TYPE_RW);
 
+	nested_vmx_merge_pmu_msr_bitmaps(vcpu, msr_bitmap_l1, msr_bitmap_l0);
+
 	kvm_vcpu_unmap(vcpu, &map);
 
 	vmx->nested.force_msr_bitmap_recalc = false;
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:17:09 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:17:09 -0800
Subject: [PATCH v6 33/44] KVM: x86/pmu: Expose enable_mediated_pmu parameter
 to user space
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-34-seanjc@google.com>

From: Dapeng Mi <dapeng1.mi at linux.intel.com>

Expose enable_mediated_pmu parameter to user space, i.e. allow userspace
to enable/disable mediated vPMU support.

Document the mediated versus perf-based behavior as part of the
kernel-parameters.txt entry, and opportunistically add an entry for the
core enable_pmu param as well.

Signed-off-by: Dapeng Mi <dapeng1.mi at linux.intel.com>
Signed-off-by: Mingwei Zhang <mizhang at google.com>
Tested-by: Xudong Hao <xudong.hao at intel.com>
Co-developed-by: Sean Christopherson <seanjc at google.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 .../admin-guide/kernel-parameters.txt         | 49 +++++++++++++++++++
 arch/x86/kvm/svm/svm.c                        |  2 +
 arch/x86/kvm/vmx/vmx.c                        |  2 +
 3 files changed, 53 insertions(+)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 6c42061ca20e..ed6f2ed94756 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -2926,6 +2926,26 @@
 
 			Default is Y (on).
 
+	kvm.enable_pmu=[KVM,X86]
+			If enabled, KVM will virtualize PMU functionality based
+			on the virtual CPU model defined by userspace.  This
+			can be overridden on a per-VM basis via
+			KVM_CAP_PMU_CAPABILITY.
+
+			If disabled, KVM will not virtualize PMU functionality,
+			e.g. MSRs, PMCs, PMIs, etc., even if userspace defines
+			a virtual CPU model that contains PMU assets.
+
+			Note, KVM's vPMU support implicitly requires running
+			with an in-kernel local APIC, e.g. to deliver PMIs to
+			the guest.  Running without an in-kernel local APIC is
+			not supported, though KVM will allow such a combination
+			(with severely degraded functionality).
+
+			See also enable_mediated_pmu.
+
+			Default is Y (on).
+
 	kvm.enable_virt_at_load=[KVM,ARM64,LOONGARCH,MIPS,RISCV,X86]
 			If enabled, KVM will enable virtualization in hardware
 			when KVM is loaded, and disable virtualization when KVM
@@ -2972,6 +2992,35 @@
 			If the value is 0 (the default), KVM will pick a period based
 			on the ratio, such that a page is zapped after 1 hour on average.
 
+	kvm-{amd,intel}.enable_mediated_pmu=[KVM,AMD,INTEL]
+			If enabled, KVM will provide a mediated virtual PMU,
+			instead of the default perf-based virtual PMU (if
+			kvm.enable_pmu is true and PMU is enumerated via the
+			virtual CPU model).
+
+			With a perf-based vPMU, KVM operates as a user of perf,
+			i.e. emulates guest PMU counters using perf events.
+			KVM-created perf events are managed by perf as regular
+			(guest-only) events, e.g. are scheduled in/out, contend
+			for hardware resources, etc.  Using a perf-based vPMU
+			allows guest and host usage of the PMU to co-exist, but
+			incurs non-trivial overhead and can result in silently
+			dropped guest events (due to resource contention).
+
+			With a mediated vPMU, hardware PMU state is context
+			switched around the world switch to/from the guest.
+			KVM mediates which events the guest can utilize, but
+			gives the guest direct access to all other PMU assets
+			when possible (KVM may intercept some accesses if the
+			virtual CPU model provides a subset of hardware PMU
+			functionality).  Using a mediated vPMU significantly
+			reduces PMU virtualization overhead and eliminates lost
+			guest events, but is mutually exclusive with using perf
+			to profile KVM guests and adds latency to most VM-Exits
+			(to context switch PMU state).
+
+			Default is N (off).
+
 	kvm-amd.nested=	[KVM,AMD] Control nested virtualization feature in
 			KVM/SVM. Default is 1 (enabled).
 
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index cbebd3a18918..20fb7c38bf75 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -170,6 +170,8 @@ module_param(intercept_smi, bool, 0444);
 bool vnmi = true;
 module_param(vnmi, bool, 0444);
 
+module_param(enable_mediated_pmu, bool, 0444);
+
 static bool svm_gp_erratum_intercept = true;
 
 static u8 rsm_ins_bytes[] = "\x0f\xaa";
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index f0a20ff2a941..62ba2a2b9e98 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -150,6 +150,8 @@ module_param_named(preemption_timer, enable_preemption_timer, bool, S_IRUGO);
 extern bool __read_mostly allow_smaller_maxphyaddr;
 module_param(allow_smaller_maxphyaddr, bool, S_IRUGO);
 
+module_param(enable_mediated_pmu, bool, 0444);
+
 #define KVM_VM_CR0_ALWAYS_OFF (X86_CR0_NW | X86_CR0_CD)
 #define KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST X86_CR0_NE
 #define KVM_VM_CR0_ALWAYS_ON				\
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:17:13 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:17:13 -0800
Subject: [PATCH v6 37/44] KVM: VMX: Dedup code for removing MSR from VMCS's
 auto-load list
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-38-seanjc@google.com>

Add a helper to remove an MSR from an auto-{load,store} list to dedup the
msr_autoload code, and in anticipation of adding similar functionality for
msr_autostore.

No functional change intended.

Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/kvm/vmx/vmx.c | 31 ++++++++++++++++---------------
 1 file changed, 16 insertions(+), 15 deletions(-)

diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 52bcb817cc15..a51f66d1b201 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -1040,9 +1040,22 @@ static int vmx_find_loadstore_msr_slot(struct vmx_msrs *m, u32 msr)
 	return -ENOENT;
 }
 
+static void vmx_remove_auto_msr(struct vmx_msrs *m, u32 msr,
+				unsigned long vmcs_count_field)
+{
+	int i;
+
+	i = vmx_find_loadstore_msr_slot(m, msr);
+	if (i < 0)
+		return;
+
+	--m->nr;
+	m->val[i] = m->val[m->nr];
+	vmcs_write32(vmcs_count_field, m->nr);
+}
+
 static void clear_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr)
 {
-	int i;
 	struct msr_autoload *m = &vmx->msr_autoload;
 
 	switch (msr) {
@@ -1063,21 +1076,9 @@ static void clear_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr)
 		}
 		break;
 	}
-	i = vmx_find_loadstore_msr_slot(&m->guest, msr);
-	if (i < 0)
-		goto skip_guest;
-	--m->guest.nr;
-	m->guest.val[i] = m->guest.val[m->guest.nr];
-	vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->guest.nr);
 
-skip_guest:
-	i = vmx_find_loadstore_msr_slot(&m->host, msr);
-	if (i < 0)
-		return;
-
-	--m->host.nr;
-	m->host.val[i] = m->host.val[m->host.nr];
-	vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->host.nr);
+	vmx_remove_auto_msr(&m->guest, msr, VM_ENTRY_MSR_LOAD_COUNT);
+	vmx_remove_auto_msr(&m->host, msr, VM_EXIT_MSR_LOAD_COUNT);
 }
 
 static __always_inline void add_atomic_switch_msr_special(struct vcpu_vmx *vmx,
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:17:11 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:17:11 -0800
Subject: [PATCH v6 35/44] KVM: VMX: Drop intermediate "guest" field from msr_autostore
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-36-seanjc@google.com>

Drop the intermediate "guest" field from vcpu_vmx.msr_autostore as the
value saved on VM-Exit isn't guaranteed to be the guest's value, it's
purely whatever is in hardware at the time of VM-Exit.  E.g. KVM's only
use of the store list at the momemnt is to snapshot TSC at VM-Exit, and
the value saved is always the raw TSC even if TSC-offseting and/or
TSC-scaling is enabled for the guest.

And unlike msr_autoload, there is no need differentiate between "on-entry"
and "on-exit".

No functional change intended.

Cc: Jim Mattson <jmattson at google.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/kvm/vmx/nested.c | 10 +++++-----
 arch/x86/kvm/vmx/vmx.c    |  2 +-
 arch/x86/kvm/vmx/vmx.h    |  4 +---
 3 files changed, 7 insertions(+), 9 deletions(-)

diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index 729cc1f05ac8..486789dac515 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -1076,11 +1076,11 @@ static bool nested_vmx_get_vmexit_msr_value(struct kvm_vcpu *vcpu,
 	 * VM-exit in L0, use the more accurate value.
 	 */
 	if (msr_index == MSR_IA32_TSC) {
-		int i = vmx_find_loadstore_msr_slot(&vmx->msr_autostore.guest,
+		int i = vmx_find_loadstore_msr_slot(&vmx->msr_autostore,
 						    MSR_IA32_TSC);
 
 		if (i >= 0) {
-			u64 val = vmx->msr_autostore.guest.val[i].value;
+			u64 val = vmx->msr_autostore.val[i].value;
 
 			*data = kvm_read_l1_tsc(vcpu, val);
 			return true;
@@ -1167,7 +1167,7 @@ static void prepare_vmx_msr_autostore_list(struct kvm_vcpu *vcpu,
 					   u32 msr_index)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
-	struct vmx_msrs *autostore = &vmx->msr_autostore.guest;
+	struct vmx_msrs *autostore = &vmx->msr_autostore;
 	bool in_vmcs12_store_list;
 	int msr_autostore_slot;
 	bool in_autostore_list;
@@ -2366,7 +2366,7 @@ static void prepare_vmcs02_constant_state(struct vcpu_vmx *vmx)
 	 * addresses are constant (for vmcs02), the counts can change based
 	 * on L2's behavior, e.g. switching to/from long mode.
 	 */
-	vmcs_write64(VM_EXIT_MSR_STORE_ADDR, __pa(vmx->msr_autostore.guest.val));
+	vmcs_write64(VM_EXIT_MSR_STORE_ADDR, __pa(vmx->msr_autostore.val));
 	vmcs_write64(VM_EXIT_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.host.val));
 	vmcs_write64(VM_ENTRY_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.guest.val));
 
@@ -2704,7 +2704,7 @@ static void prepare_vmcs02_rare(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
 	 */
 	prepare_vmx_msr_autostore_list(&vmx->vcpu, MSR_IA32_TSC);
 
-	vmcs_write32(VM_EXIT_MSR_STORE_COUNT, vmx->msr_autostore.guest.nr);
+	vmcs_write32(VM_EXIT_MSR_STORE_COUNT, vmx->msr_autostore.nr);
 	vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.host.nr);
 	vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, vmx->msr_autoload.guest.nr);
 
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 62ba2a2b9e98..23c92c41fd83 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -6567,7 +6567,7 @@ void dump_vmcs(struct kvm_vcpu *vcpu)
 	if (vmcs_read32(VM_ENTRY_MSR_LOAD_COUNT) > 0)
 		vmx_dump_msrs("guest autoload", &vmx->msr_autoload.guest);
 	if (vmcs_read32(VM_EXIT_MSR_STORE_COUNT) > 0)
-		vmx_dump_msrs("guest autostore", &vmx->msr_autostore.guest);
+		vmx_dump_msrs("autostore", &vmx->msr_autostore);
 
 	if (vmentry_ctl & VM_ENTRY_LOAD_CET_STATE)
 		pr_err("S_CET = 0x%016lx, SSP = 0x%016lx, SSP TABLE = 0x%016lx\n",
diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h
index d7a96c84371f..4ce653d729ca 100644
--- a/arch/x86/kvm/vmx/vmx.h
+++ b/arch/x86/kvm/vmx/vmx.h
@@ -245,9 +245,7 @@ struct vcpu_vmx {
 		struct vmx_msrs host;
 	} msr_autoload;
 
-	struct msr_autostore {
-		struct vmx_msrs guest;
-	} msr_autostore;
+	struct vmx_msrs msr_autostore;
 
 	struct {
 		int vm86_active;
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:17:12 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:17:12 -0800
Subject: [PATCH v6 36/44] KVM: nVMX: Don't update msr_autostore count when
 saving TSC for vmcs12
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-37-seanjc@google.com>

Rework nVMX's use of the MSR auto-store list to snapshot TSC to sneak
MSR_IA32_TSC into the list _without_ updating KVM's software tracking,
and drop the generic functionality so that future usage of the store list
for nested specific logic needs to consider the implications of modifying
the list.  Updating the list only for vmcs02 and only on nested VM-Enter
is a disaster waiting to happen, as it means vmcs01 is stale relative to
the software tracking, and KVM could unintentionally leave an MSR in the
store list in perpetuity while running L1, e.g. if KVM addressed the first
issue and updated vmcs01 on nested VM-Exit without removing TSC from the
list.

Furthermore, mixing KVM's desire to save an MSR with L1's desire to save
an MSR result KVM clobbering/ignoring the needs of vmcs01 or vmcs02.
E.g. if KVM added MSR_IA32_TSC to the store list for its own purposes, and
then _removed_ MSR_IA32_TSC from the list after emulating nested VM-Enter,
then KVM would remove MSR_IA32_TSC from the list even though saving TSC on
VM-Exit from L2 is still desirable (to provide L1 with an accurate TSC).

Similarly, removing an MSR from the list based on vmcs12's settings could
drop an MSR that KVM wants to save for its own purposes.

In practice, the issues are currently benign, because KVM doesn't use the
store list for vmcs01.  But that will change with upcoming mediated PMU
support.

Alternatively, a "full" solution would be to track MSR list entries for
vmcs12 separately from KVM's standard lists, but MSR_IA32_TSC is likely
the only MSR that KVM would ever want to save on _every_ VM-Exit purely
based on vmcs12.  I.e. the added complexity isn't remotely justified at
this time.

Opportunistically escalate from a pr_warn_ratelimited() to a full WARN as
KVM reserves eight entries in each MSR list, and as above KVM uses at most
one entry.

Opportunistically make vmx_find_loadstore_msr_slot() local to vmx.c as
using it directly from nested code is unsafe due to the potential for
mixing vmcs01 and vmcs02 state (see above).

Cc: Jim Mattson <jmattson at google.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/kvm/vmx/nested.c | 71 ++++++++++++---------------------------
 arch/x86/kvm/vmx/vmx.c    |  2 +-
 arch/x86/kvm/vmx/vmx.h    |  2 +-
 3 files changed, 24 insertions(+), 51 deletions(-)

diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index 486789dac515..614b789ecf16 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -1075,16 +1075,12 @@ static bool nested_vmx_get_vmexit_msr_value(struct kvm_vcpu *vcpu,
 	 * does not include the time taken for emulation of the L2->L1
 	 * VM-exit in L0, use the more accurate value.
 	 */
-	if (msr_index == MSR_IA32_TSC) {
-		int i = vmx_find_loadstore_msr_slot(&vmx->msr_autostore,
-						    MSR_IA32_TSC);
+	if (msr_index == MSR_IA32_TSC && vmx->nested.tsc_autostore_slot >= 0) {
+		int slot = vmx->nested.tsc_autostore_slot;
+		u64 host_tsc = vmx->msr_autostore.val[slot].value;
 
-		if (i >= 0) {
-			u64 val = vmx->msr_autostore.val[i].value;
-
-			*data = kvm_read_l1_tsc(vcpu, val);
-			return true;
-		}
+		*data = kvm_read_l1_tsc(vcpu, host_tsc);
+		return true;
 	}
 
 	if (kvm_emulate_msr_read(vcpu, msr_index, data)) {
@@ -1163,42 +1159,6 @@ static bool nested_msr_store_list_has_msr(struct kvm_vcpu *vcpu, u32 msr_index)
 	return false;
 }
 
-static void prepare_vmx_msr_autostore_list(struct kvm_vcpu *vcpu,
-					   u32 msr_index)
-{
-	struct vcpu_vmx *vmx = to_vmx(vcpu);
-	struct vmx_msrs *autostore = &vmx->msr_autostore;
-	bool in_vmcs12_store_list;
-	int msr_autostore_slot;
-	bool in_autostore_list;
-	int last;
-
-	msr_autostore_slot = vmx_find_loadstore_msr_slot(autostore, msr_index);
-	in_autostore_list = msr_autostore_slot >= 0;
-	in_vmcs12_store_list = nested_msr_store_list_has_msr(vcpu, msr_index);
-
-	if (in_vmcs12_store_list && !in_autostore_list) {
-		if (autostore->nr == MAX_NR_LOADSTORE_MSRS) {
-			/*
-			 * Emulated VMEntry does not fail here.  Instead a less
-			 * accurate value will be returned by
-			 * nested_vmx_get_vmexit_msr_value() by reading KVM's
-			 * internal MSR state instead of reading the value from
-			 * the vmcs02 VMExit MSR-store area.
-			 */
-			pr_warn_ratelimited(
-				"Not enough msr entries in msr_autostore.  Can't add msr %x\n",
-				msr_index);
-			return;
-		}
-		last = autostore->nr++;
-		autostore->val[last].index = msr_index;
-	} else if (!in_vmcs12_store_list && in_autostore_list) {
-		last = --autostore->nr;
-		autostore->val[msr_autostore_slot] = autostore->val[last];
-	}
-}
-
 /*
  * Load guest's/host's cr3 at nested entry/exit.  @nested_ept is true if we are
  * emulating VM-Entry into a guest with EPT enabled.  On failure, the expected
@@ -2699,12 +2659,25 @@ static void prepare_vmcs02_rare(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
 	}
 
 	/*
-	 * Make sure the msr_autostore list is up to date before we set the
-	 * count in the vmcs02.
+	 * If vmcs12 is configured to save TSC on exit via the auto-store list,
+	 * append the MSR to vmcs02's auto-store list so that KVM effectively
+	 * reads TSC at the time of VM-Exit from L2.  The saved value will be
+	 * propagated to vmcs12's list on nested VM-Exit.
+	 *
+	 * Don't increment the number of MSRs in the vCPU structure, as saving
+	 * TSC is specific to this particular incarnation of vmcb02, i.e. must
+	 * not bleed into vmcs01.
 	 */
-	prepare_vmx_msr_autostore_list(&vmx->vcpu, MSR_IA32_TSC);
+	if (nested_msr_store_list_has_msr(&vmx->vcpu, MSR_IA32_TSC) &&
+	    !WARN_ON_ONCE(vmx->msr_autostore.nr >= ARRAY_SIZE(vmx->msr_autostore.val))) {
+		vmx->nested.tsc_autostore_slot = vmx->msr_autostore.nr;
+		vmx->msr_autostore.val[vmx->msr_autostore.nr].index = MSR_IA32_TSC;
 
-	vmcs_write32(VM_EXIT_MSR_STORE_COUNT, vmx->msr_autostore.nr);
+		vmcs_write32(VM_EXIT_MSR_STORE_COUNT, vmx->msr_autostore.nr + 1);
+	} else {
+		vmx->nested.tsc_autostore_slot = -1;
+		vmcs_write32(VM_EXIT_MSR_STORE_COUNT, vmx->msr_autostore.nr);
+	}
 	vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.host.nr);
 	vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, vmx->msr_autoload.guest.nr);
 
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 23c92c41fd83..52bcb817cc15 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -1029,7 +1029,7 @@ static __always_inline void clear_atomic_switch_msr_special(struct vcpu_vmx *vmx
 	vm_exit_controls_clearbit(vmx, exit);
 }
 
-int vmx_find_loadstore_msr_slot(struct vmx_msrs *m, u32 msr)
+static int vmx_find_loadstore_msr_slot(struct vmx_msrs *m, u32 msr)
 {
 	unsigned int i;
 
diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h
index 4ce653d729ca..3175fedb5a4d 100644
--- a/arch/x86/kvm/vmx/vmx.h
+++ b/arch/x86/kvm/vmx/vmx.h
@@ -191,6 +191,7 @@ struct nested_vmx {
 	u16 vpid02;
 	u16 last_vpid;
 
+	int tsc_autostore_slot;
 	struct nested_vmx_msrs msrs;
 
 	/* SMM related state */
@@ -383,7 +384,6 @@ void vmx_spec_ctrl_restore_host(struct vcpu_vmx *vmx, unsigned int flags);
 unsigned int __vmx_vcpu_run_flags(struct vcpu_vmx *vmx);
 bool __vmx_vcpu_run(struct vcpu_vmx *vmx, unsigned long *regs,
 		    unsigned int flags);
-int vmx_find_loadstore_msr_slot(struct vmx_msrs *m, u32 msr);
 void vmx_ept_load_pdptrs(struct kvm_vcpu *vcpu);
 
 void vmx_set_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr, int type, bool set);
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:17:14 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:17:14 -0800
Subject: [PATCH v6 38/44] KVM: VMX: Drop unused @entry_only param from add_atomic_switch_msr()
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-39-seanjc@google.com>

Drop the "on VM-Enter only" parameter from add_atomic_switch_msr() as it
is no longer used, and for all intents and purposes was never used.  The
functionality was added, under embargo, by commit 989e3992d2ec
("x86/KVM/VMX: Extend add_atomic_switch_msr() to allow VMENTER only MSRs"),
and then ripped out by commit 2f055947ae5e ("x86/kvm: Drop L1TF MSR list
approach") just a few commits later.

  2f055947ae5e x86/kvm: Drop L1TF MSR list approach
  72c6d2db64fa x86/litf: Introduce vmx status variable
  215af5499d9e cpu/hotplug: Online siblings when SMT control is turned on
  390d975e0c4e x86/KVM/VMX: Use MSR save list for IA32_FLUSH_CMD if required
  989e3992d2ec x86/KVM/VMX: Extend add_atomic_switch_msr() to allow VMENTER only MSRs

Furthermore, it's extremely unlikely KVM will ever _need_ to load an MSR
value via the auto-load lists only on VM-Enter.  MSRs writes via the lists
aren't optimized in any way, and so the only reason to use the lists
instead of a WRMSR are for cases where the MSR _must_ be load atomically
with respect to VM-Enter (and/or VM-Exit).  While one could argue that
command MSRs, e.g. IA32_FLUSH_CMD, "need" to be done exact at VM-Enter, in
practice doing such flushes within a few instructons of VM-Enter is more
than sufficient.

Note, the shortlog and changelog for commit 390d975e0c4e ("x86/KVM/VMX: Use
MSR save list for IA32_FLUSH_CMD if required") are misleading and wrong.
That commit added MSR_IA32_FLUSH_CMD to the VM-Enter _load_ list, not the
VM-Enter save list (which doesn't exist, only VM-Exit has a store/save
list).

Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/kvm/vmx/vmx.c | 13 ++++---------
 1 file changed, 4 insertions(+), 9 deletions(-)

diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index a51f66d1b201..38491962b2c1 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -1094,7 +1094,7 @@ static __always_inline void add_atomic_switch_msr_special(struct vcpu_vmx *vmx,
 }
 
 static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
-				  u64 guest_val, u64 host_val, bool entry_only)
+				  u64 guest_val, u64 host_val)
 {
 	int i, j = 0;
 	struct msr_autoload *m = &vmx->msr_autoload;
@@ -1132,8 +1132,7 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
 	}
 
 	i = vmx_find_loadstore_msr_slot(&m->guest, msr);
-	if (!entry_only)
-		j = vmx_find_loadstore_msr_slot(&m->host, msr);
+	j = vmx_find_loadstore_msr_slot(&m->host, msr);
 
 	if ((i < 0 && m->guest.nr == MAX_NR_LOADSTORE_MSRS) ||
 	    (j < 0 &&  m->host.nr == MAX_NR_LOADSTORE_MSRS)) {
@@ -1148,9 +1147,6 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
 	m->guest.val[i].index = msr;
 	m->guest.val[i].value = guest_val;
 
-	if (entry_only)
-		return;
-
 	if (j < 0) {
 		j = m->host.nr++;
 		vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->host.nr);
@@ -1190,8 +1186,7 @@ static bool update_transition_efer(struct vcpu_vmx *vmx)
 		if (!(guest_efer & EFER_LMA))
 			guest_efer &= ~EFER_LME;
 		if (guest_efer != kvm_host.efer)
-			add_atomic_switch_msr(vmx, MSR_EFER,
-					      guest_efer, kvm_host.efer, false);
+			add_atomic_switch_msr(vmx, MSR_EFER, guest_efer, kvm_host.efer);
 		else
 			clear_atomic_switch_msr(vmx, MSR_EFER);
 		return false;
@@ -7350,7 +7345,7 @@ static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx)
 			clear_atomic_switch_msr(vmx, msrs[i].msr);
 		else
 			add_atomic_switch_msr(vmx, msrs[i].msr, msrs[i].guest,
-					msrs[i].host, false);
+					      msrs[i].host);
 }
 
 static void vmx_update_hv_timer(struct kvm_vcpu *vcpu, bool force_immediate_exit)
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:17:15 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:17:15 -0800
Subject: [PATCH v6 39/44] KVM: VMX: Bug the VM if either MSR auto-load list is full
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-40-seanjc@google.com>

WARN and bug the VM if either MSR auto-load list is full when adding an
MSR to the lists, as the set of MSRs that KVM loads via the lists is
finite and entirely KVM controlled, i.e. overflowing the lists shouldn't
be possible in a fully released version of KVM.  Terminate the VM as the
core KVM infrastructure has no insight as to _why_ an MSR is being added
to the list, and failure to load an MSR on VM-Enter and/or VM-Exit could
be fatal to the host.  E.g. running the host with a guest-controlled PEBS
MSR could generate unexpected writes to the DS buffer and crash the host.

Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/kvm/vmx/vmx.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 38491962b2c1..2c50ebf4ff1b 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -1098,6 +1098,7 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
 {
 	int i, j = 0;
 	struct msr_autoload *m = &vmx->msr_autoload;
+	struct kvm *kvm = vmx->vcpu.kvm;
 
 	switch (msr) {
 	case MSR_EFER:
@@ -1134,12 +1135,10 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
 	i = vmx_find_loadstore_msr_slot(&m->guest, msr);
 	j = vmx_find_loadstore_msr_slot(&m->host, msr);
 
-	if ((i < 0 && m->guest.nr == MAX_NR_LOADSTORE_MSRS) ||
-	    (j < 0 &&  m->host.nr == MAX_NR_LOADSTORE_MSRS)) {
-		printk_once(KERN_WARNING "Not enough msr switch entries. "
-				"Can't add msr %x\n", msr);
+	if (KVM_BUG_ON(i < 0 && m->guest.nr == MAX_NR_LOADSTORE_MSRS, kvm) ||
+	    KVM_BUG_ON(j < 0 &&  m->host.nr == MAX_NR_LOADSTORE_MSRS, kvm))
 		return;
-	}
+
 	if (i < 0) {
 		i = m->guest.nr++;
 		vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->guest.nr);
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:17:16 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:17:16 -0800
Subject: [PATCH v6 40/44] KVM: VMX: Set MSR index auto-load entry if and only
 if entry is "new"
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-41-seanjc@google.com>

When adding an MSR to the auto-load lists, update the MSR index in the
list entry if and only if a new entry is being inserted, as 'i' can only
be non-negative if vmx_find_loadstore_msr_slot() found an entry with the
MSR's index.  Unnecessarily setting the index is benign, but it makes it
harder to see that updating the value is necessary even when an existing
entry for the MSR was found.

No functional change intended.

Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/kvm/vmx/vmx.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 2c50ebf4ff1b..be2a2580e8f1 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -1141,16 +1141,16 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
 
 	if (i < 0) {
 		i = m->guest.nr++;
+		m->guest.val[i].index = msr;
 		vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->guest.nr);
 	}
-	m->guest.val[i].index = msr;
 	m->guest.val[i].value = guest_val;
 
 	if (j < 0) {
 		j = m->host.nr++;
+		m->host.val[j].index = msr;
 		vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->host.nr);
 	}
-	m->host.val[j].index = msr;
 	m->host.val[j].value = host_val;
 }
 
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:17:18 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:17:18 -0800
Subject: [PATCH v6 42/44] KVM: VMX: Dedup code for adding MSR to VMCS's auto list
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-43-seanjc@google.com>

Add a helper to add an MSR to a VMCS's "auto" list to deduplicate the code
in add_atomic_switch_msr(), and so that the functionality can be used in
the future for managing the MSR auto-store list.

No functional change intended.

Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/kvm/vmx/vmx.c | 41 +++++++++++++++++++----------------------
 1 file changed, 19 insertions(+), 22 deletions(-)

diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 018e01daab68..3f64d4b1b19c 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -1093,12 +1093,28 @@ static __always_inline void add_atomic_switch_msr_special(struct vcpu_vmx *vmx,
 	vm_exit_controls_setbit(vmx, exit);
 }
 
+static void vmx_add_auto_msr(struct vmx_msrs *m, u32 msr, u64 value,
+			     unsigned long vmcs_count_field, struct kvm *kvm)
+{
+	int i;
+
+	i = vmx_find_loadstore_msr_slot(m, msr);
+	if (i < 0) {
+		if (KVM_BUG_ON(m->nr == MAX_NR_LOADSTORE_MSRS, kvm))
+			return;
+
+		i = m->nr++;
+		m->val[i].index = msr;
+		vmcs_write32(vmcs_count_field, m->nr);
+	}
+	m->val[i].value = value;
+}
+
 static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
 				  u64 guest_val, u64 host_val)
 {
 	struct msr_autoload *m = &vmx->msr_autoload;
 	struct kvm *kvm = vmx->vcpu.kvm;
-	int i;
 
 	switch (msr) {
 	case MSR_EFER:
@@ -1132,27 +1148,8 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
 		wrmsrq(MSR_IA32_PEBS_ENABLE, 0);
 	}
 
-	i = vmx_find_loadstore_msr_slot(&m->guest, msr);
-	if (i < 0) {
-		if (KVM_BUG_ON(m->guest.nr == MAX_NR_LOADSTORE_MSRS, kvm))
-			return;
-
-		i = m->guest.nr++;
-		m->guest.val[i].index = msr;
-		vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->guest.nr);
-	}
-	m->guest.val[i].value = guest_val;
-
-	i = vmx_find_loadstore_msr_slot(&m->host, msr);
-	if (i < 0) {
-		if (KVM_BUG_ON(m->host.nr == MAX_NR_LOADSTORE_MSRS, kvm))
-			return;
-
-		i = m->host.nr++;
-		m->host.val[i].index = msr;
-		vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->host.nr);
-	}
-	m->host.val[i].value = host_val;
+	vmx_add_auto_msr(&m->guest, msr, guest_val, VM_ENTRY_MSR_LOAD_COUNT, kvm);
+	vmx_add_auto_msr(&m->guest, msr, host_val, VM_EXIT_MSR_LOAD_COUNT, kvm);
 }
 
 static bool update_transition_efer(struct vcpu_vmx *vmx)
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:17:19 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:17:19 -0800
Subject: [PATCH v6 43/44] KVM: VMX: Initialize vmcs01.VM_EXIT_MSR_STORE_ADDR
 with list address
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-44-seanjc@google.com>

Initialize vmcs01.VM_EXIT_MSR_STORE_ADDR to point at the vCPU's
msr_autostore list in anticipation of utilizing the auto-store
functionality, and to harden KVM against stray reads to pfn 0 (or, in
theory, a random pfn if the underlying CPU uses a complex scheme for
encoding VMCS data).  The MSR auto lists are supposed to be ignored if the
associated COUNT VMCS field is '0', but leaving the ADDR field
zero-initialized in memory is an unnecessary risk (albeit a minuscule risk)
given that the cost is a single VMWRITE during vCPU creation.

Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/kvm/vmx/vmx.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 3f64d4b1b19c..6a17cb90eaf4 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -4933,6 +4933,7 @@ static void init_vmcs(struct vcpu_vmx *vmx)
 		vmcs_write64(VM_FUNCTION_CONTROL, 0);
 
 	vmcs_write32(VM_EXIT_MSR_STORE_COUNT, 0);
+	vmcs_write64(VM_EXIT_MSR_STORE_ADDR, __pa(vmx->msr_autostore.val));
 	vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, 0);
 	vmcs_write64(VM_EXIT_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.host.val));
 	vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, 0);
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:17:20 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:17:20 -0800
Subject: [PATCH v6 44/44] KVM: VMX: Add mediated PMU support for CPUs without
 "save perf global ctrl"
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-45-seanjc@google.com>

Extend mediated PMU support for Intel CPUs without support for saving
PERF_GLOBAL_CONTROL into the guest VMCS field on VM-Exit, e.g. for Skylake
and its derivatives, as well as Icelake.  While supporting CPUs without
VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL isn't completely trivial, it's not that
complex either.  And not supporting such CPUs would mean not supporting 7+
years of Intel CPUs released in the past 10 years.

On VM-Exit, immediately propagate the saved PERF_GLOBAL_CTRL to the VMCS
as well as KVM's software cache so that KVM doesn't need to add full EXREG
tracking of PERF_GLOBAL_CTRL.  In practice, the vast majority of VM-Exits
won't trigger software writes to guest PERF_GLOBAL_CTRL, so deferring the
VMWRITE to the next VM-Enter would only delay the inevitable without
batching/avoiding VMWRITEs.

Note!  Take care to refresh VM_EXIT_MSR_STORE_COUNT on nested VM-Exit, as
it's unfortunately possible that KVM could recalculate MSR intercepts
while L2 is active, e.g. if userspace loads nested state and _then_ sets
PERF_CAPABILITIES.  Eating the VMWRITE on every nested VM-Exit is
unfortunate, but that's a pre-existing problem and can/should be solved
separately, e.g. modifying the number of auto-load entries while L2 is
active is also uncommon on modern CPUs.

Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/kvm/vmx/nested.c    |  6 ++++-
 arch/x86/kvm/vmx/pmu_intel.c |  7 -----
 arch/x86/kvm/vmx/vmx.c       | 52 ++++++++++++++++++++++++++++++++----
 3 files changed, 52 insertions(+), 13 deletions(-)

diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index 614b789ecf16..1ee1edc8419d 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -5142,7 +5142,11 @@ void __nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
 
 	kvm_nested_vmexit_handle_ibrs(vcpu);
 
-	/* Update any VMCS fields that might have changed while L2 ran */
+	/*
+	 * Update any VMCS fields that might have changed while vmcs02 was the
+	 * active VMCS.  The tracking is per-vCPU, not per-VMCS.
+	 */
+	vmcs_write32(VM_EXIT_MSR_STORE_COUNT, vmx->msr_autostore.nr);
 	vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.host.nr);
 	vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, vmx->msr_autoload.guest.nr);
 	vmcs_write64(TSC_OFFSET, vcpu->arch.tsc_offset);
diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
index 55249fa4db95..27eb76e6b6a0 100644
--- a/arch/x86/kvm/vmx/pmu_intel.c
+++ b/arch/x86/kvm/vmx/pmu_intel.c
@@ -777,13 +777,6 @@ static bool intel_pmu_is_mediated_pmu_supported(struct x86_pmu_capability *host_
 	if (WARN_ON_ONCE(!cpu_has_load_perf_global_ctrl()))
 		return false;
 
-	/*
-	 * KVM doesn't yet support mediated PMU on CPUs without support for
-	 * saving PERF_GLOBAL_CTRL via a dedicated VMCS field.
-	 */
-	if (!cpu_has_save_perf_global_ctrl())
-		return false;
-
 	return true;
 }
 
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 6a17cb90eaf4..ba1262c3e3ff 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -1204,6 +1204,17 @@ static bool update_transition_efer(struct vcpu_vmx *vmx)
 	return true;
 }
 
+static void vmx_add_autostore_msr(struct vcpu_vmx *vmx, u32 msr)
+{
+	vmx_add_auto_msr(&vmx->msr_autostore, msr, 0, VM_EXIT_MSR_STORE_COUNT,
+			 vmx->vcpu.kvm);
+}
+
+static void vmx_remove_autostore_msr(struct vcpu_vmx *vmx, u32 msr)
+{
+	vmx_remove_auto_msr(&vmx->msr_autostore, msr, VM_EXIT_MSR_STORE_COUNT);
+}
+
 #ifdef CONFIG_X86_32
 /*
  * On 32-bit kernels, VM exits still load the FS and GS bases from the
@@ -4225,6 +4236,8 @@ void pt_update_intercept_for_msr(struct kvm_vcpu *vcpu)
 
 static void vmx_recalc_pmu_msr_intercepts(struct kvm_vcpu *vcpu)
 {
+	u64 vm_exit_controls_bits = VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL |
+				    VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL;
 	bool has_mediated_pmu = kvm_vcpu_has_mediated_pmu(vcpu);
 	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -4234,12 +4247,19 @@ static void vmx_recalc_pmu_msr_intercepts(struct kvm_vcpu *vcpu)
 	if (!enable_mediated_pmu)
 		return;
 
+	if (!cpu_has_save_perf_global_ctrl()) {
+		vm_exit_controls_bits &= ~VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL;
+
+		if (has_mediated_pmu)
+			vmx_add_autostore_msr(vmx, MSR_CORE_PERF_GLOBAL_CTRL);
+		else
+			vmx_remove_autostore_msr(vmx, MSR_CORE_PERF_GLOBAL_CTRL);
+	}
+
 	vm_entry_controls_changebit(vmx, VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL,
 				    has_mediated_pmu);
 
-	vm_exit_controls_changebit(vmx, VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL |
-					VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL,
-				   has_mediated_pmu);
+	vm_exit_controls_changebit(vmx, vm_exit_controls_bits, has_mediated_pmu);
 
 	for (i = 0; i < pmu->nr_arch_gp_counters; i++) {
 		vmx_set_intercept_for_msr(vcpu, MSR_IA32_PERFCTR0 + i,
@@ -7346,6 +7366,29 @@ static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx)
 					      msrs[i].host);
 }
 
+static void vmx_refresh_guest_perf_global_control(struct kvm_vcpu *vcpu)
+{
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+	struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+	if (msr_write_intercepted(vmx, MSR_CORE_PERF_GLOBAL_CTRL))
+		return;
+
+	if (!cpu_has_save_perf_global_ctrl()) {
+		int slot = vmx_find_loadstore_msr_slot(&vmx->msr_autostore,
+						       MSR_CORE_PERF_GLOBAL_CTRL);
+
+		if (WARN_ON_ONCE(slot < 0))
+			return;
+
+		pmu->global_ctrl = vmx->msr_autostore.val[slot].value;
+		vmcs_write64(GUEST_IA32_PERF_GLOBAL_CTRL, pmu->global_ctrl);
+		return;
+	}
+
+	pmu->global_ctrl = vmcs_read64(GUEST_IA32_PERF_GLOBAL_CTRL);
+}
+
 static void vmx_update_hv_timer(struct kvm_vcpu *vcpu, bool force_immediate_exit)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -7631,8 +7674,7 @@ fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu, u64 run_flags)
 
 	vmx->loaded_vmcs->launched = 1;
 
-	if (!msr_write_intercepted(vmx, MSR_CORE_PERF_GLOBAL_CTRL))
-		vcpu_to_pmu(vcpu)->global_ctrl = vmcs_read64(GUEST_IA32_PERF_GLOBAL_CTRL);
+	vmx_refresh_guest_perf_global_control(vcpu);
 
 	vmx_recover_nmi_blocking(vmx);
 	vmx_complete_interrupts(vmx);
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:17:17 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:17:17 -0800
Subject: [PATCH v6 41/44] KVM: VMX: Compartmentalize adding MSRs to host vs.
 guest auto-load list
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-42-seanjc@google.com>

Undo the bundling of the "host" and "guest" MSR auto-load list logic so
that the code can be deduplicated by factoring out the logic to a separate
helper.  Now that "list full" situations are treated as fatal to the VM,
there is no need to pre-check both lists.

For all intents and purposes, this reverts the add_atomic_switch_msr()
changes made by commit 3190709335dd ("x86/KVM/VMX: Separate the VMX
AUTOLOAD guest/host number accounting").

Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/kvm/vmx/vmx.c | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index be2a2580e8f1..018e01daab68 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -1096,9 +1096,9 @@ static __always_inline void add_atomic_switch_msr_special(struct vcpu_vmx *vmx,
 static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
 				  u64 guest_val, u64 host_val)
 {
-	int i, j = 0;
 	struct msr_autoload *m = &vmx->msr_autoload;
 	struct kvm *kvm = vmx->vcpu.kvm;
+	int i;
 
 	switch (msr) {
 	case MSR_EFER:
@@ -1133,25 +1133,26 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
 	}
 
 	i = vmx_find_loadstore_msr_slot(&m->guest, msr);
-	j = vmx_find_loadstore_msr_slot(&m->host, msr);
-
-	if (KVM_BUG_ON(i < 0 && m->guest.nr == MAX_NR_LOADSTORE_MSRS, kvm) ||
-	    KVM_BUG_ON(j < 0 &&  m->host.nr == MAX_NR_LOADSTORE_MSRS, kvm))
-		return;
-
 	if (i < 0) {
+		if (KVM_BUG_ON(m->guest.nr == MAX_NR_LOADSTORE_MSRS, kvm))
+			return;
+
 		i = m->guest.nr++;
 		m->guest.val[i].index = msr;
 		vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->guest.nr);
 	}
 	m->guest.val[i].value = guest_val;
 
-	if (j < 0) {
-		j = m->host.nr++;
-		m->host.val[j].index = msr;
+	i = vmx_find_loadstore_msr_slot(&m->host, msr);
+	if (i < 0) {
+		if (KVM_BUG_ON(m->host.nr == MAX_NR_LOADSTORE_MSRS, kvm))
+			return;
+
+		i = m->host.nr++;
+		m->host.val[i].index = msr;
 		vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->host.nr);
 	}
-	m->host.val[j].value = host_val;
+	m->host.val[i].value = host_val;
 }
 
 static bool update_transition_efer(struct vcpu_vmx *vmx)
-- 
2.52.0.223.gf5cc29aaa4-goog



From seanjc at google.com  Fri Dec  5 16:17:08 2025
From: seanjc at google.com (Sean Christopherson)
Date: Fri,  5 Dec 2025 16:17:08 -0800
Subject: [PATCH v6 32/44] KVM: nSVM: Disable PMU MSR interception as
 appropriate while running L2
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251206001720.468579-33-seanjc@google.com>

Add MSRs that might be passed through to L1 when running with a mediated
PMU to the nested SVM's set of to-be-merged MSR indices, i.e. disable
interception of PMU MSRs when running L2 if both KVM (L0) and L1 disable
interception.  There is no need for KVM to interpose on such MSR accesses,
e.g. if L1 exposes a mediated PMU (or equivalent) to L2.

Tested-by: Xudong Hao <xudong.hao at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 arch/x86/kvm/svm/nested.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
index ba0f11c68372..93140ccec95d 100644
--- a/arch/x86/kvm/svm/nested.c
+++ b/arch/x86/kvm/svm/nested.c
@@ -194,7 +194,7 @@ void recalc_intercepts(struct vcpu_svm *svm)
  * Hardcode the capacity of the array based on the maximum number of _offsets_.
  * MSRs are batched together, so there are fewer offsets than MSRs.
  */
-static int nested_svm_msrpm_merge_offsets[7] __ro_after_init;
+static int nested_svm_msrpm_merge_offsets[10] __ro_after_init;
 static int nested_svm_nr_msrpm_merge_offsets __ro_after_init;
 typedef unsigned long nsvm_msrpm_merge_t;
 
@@ -222,6 +222,22 @@ int __init nested_svm_init_msrpm_merge_offsets(void)
 		MSR_IA32_LASTBRANCHTOIP,
 		MSR_IA32_LASTINTFROMIP,
 		MSR_IA32_LASTINTTOIP,
+
+		MSR_K7_PERFCTR0,
+		MSR_K7_PERFCTR1,
+		MSR_K7_PERFCTR2,
+		MSR_K7_PERFCTR3,
+		MSR_F15H_PERF_CTR0,
+		MSR_F15H_PERF_CTR1,
+		MSR_F15H_PERF_CTR2,
+		MSR_F15H_PERF_CTR3,
+		MSR_F15H_PERF_CTR4,
+		MSR_F15H_PERF_CTR5,
+
+		MSR_AMD64_PERF_CNTR_GLOBAL_CTL,
+		MSR_AMD64_PERF_CNTR_GLOBAL_STATUS,
+		MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR,
+		MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_SET,
 	};
 	int i, j;
 
-- 
2.52.0.223.gf5cc29aaa4-goog



From nicolinc at nvidia.com  Fri Dec  5 16:52:00 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Fri, 5 Dec 2025 16:52:00 -0800
Subject: [PATCH rc v1 1/4] iommu/arm-smmu-v3: Add ignored bits to fix STE update sequence
In-Reply-To: <cover.1764982046.git.nicolinc@nvidia.com>
References: <cover.1764982046.git.nicolinc@nvidia.com>
Message-ID: <6ec73bb7cd03d90a0764f12c4b14071158163818.1764982046.git.nicolinc@nvidia.com>

From: Jason Gunthorpe <jgg at nvidia.com>

C_BAD_STE was observed when updating nested STE from an S1-bypass mode to
an S1DSS-bypass mode. As both modes enabled S2, the used bit is slightly
different than the normal S1-bypass and S1DSS-bypass modes. As a result,
fields like MEV and EATS in S2's used list marked the word1 as a critical
word that requested a STE.V=0. This breaks a hitless update.

However, both MEV and EATS aren't critical in terms of STE update. One
controls the merge of the events and the other controls the ATS that is
managed by the driver at the same time via pci_enable_ats().

Add an arm_smmu_get_ste_ignored() to allow STE update algorithm to ignore
those fields, avoiding the STE update breakages.

Note that this change is required by both MEV and EATS fields, which were
introduced in different kernel versions. So add this get_ignored() first.
The MEV and EATS will be added in arm_smmu_get_ste_ignored() separately.

Fixes: 1e8be08d1c91 ("iommu/arm-smmu-v3: Support IOMMU_DOMAIN_NESTED")
Cc: stable at vger.kernel.org
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  2 ++
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  | 17 ++++++++++---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 24 ++++++++++++-------
 3 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index ae23aacc3840..d5f0e5407b9f 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -900,6 +900,7 @@ struct arm_smmu_entry_writer {
 
 struct arm_smmu_entry_writer_ops {
 	void (*get_used)(const __le64 *entry, __le64 *used);
+	void (*get_ignored)(__le64 *ignored_bits);
 	void (*sync)(struct arm_smmu_entry_writer *writer);
 };
 
@@ -911,6 +912,7 @@ void arm_smmu_make_s2_domain_ste(struct arm_smmu_ste *target,
 
 #if IS_ENABLED(CONFIG_KUNIT)
 void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits);
+void arm_smmu_get_ste_ignored(__le64 *ignored_bits);
 void arm_smmu_write_entry(struct arm_smmu_entry_writer *writer, __le64 *cur,
 			  const __le64 *target);
 void arm_smmu_get_cd_used(const __le64 *ent, __le64 *used_bits);
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
index d2671bfd3798..9287904c93a2 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
@@ -37,6 +37,7 @@ enum arm_smmu_test_master_feat {
 
 static bool arm_smmu_entry_differs_in_used_bits(const __le64 *entry,
 						const __le64 *used_bits,
+						const __le64 *ignored,
 						const __le64 *target,
 						unsigned int length)
 {
@@ -44,7 +45,7 @@ static bool arm_smmu_entry_differs_in_used_bits(const __le64 *entry,
 	unsigned int i;
 
 	for (i = 0; i < length; i++) {
-		if ((entry[i] & used_bits[i]) != target[i])
+		if ((entry[i] & used_bits[i]) != (target[i] & ~ignored[i]))
 			differs = true;
 	}
 	return differs;
@@ -56,12 +57,18 @@ arm_smmu_test_writer_record_syncs(struct arm_smmu_entry_writer *writer)
 	struct arm_smmu_test_writer *test_writer =
 		container_of(writer, struct arm_smmu_test_writer, writer);
 	__le64 *entry_used_bits;
+	__le64 *ignored_bits;
 
 	entry_used_bits = kunit_kzalloc(
 		test_writer->test, sizeof(*entry_used_bits) * NUM_ENTRY_QWORDS,
 		GFP_KERNEL);
 	KUNIT_ASSERT_NOT_NULL(test_writer->test, entry_used_bits);
 
+	ignored_bits = kunit_kzalloc(test_writer->test,
+				     sizeof(*ignored_bits) * NUM_ENTRY_QWORDS,
+				     GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test_writer->test, ignored_bits);
+
 	pr_debug("STE value is now set to: ");
 	print_hex_dump_debug("    ", DUMP_PREFIX_NONE, 16, 8,
 			     test_writer->entry,
@@ -79,14 +86,17 @@ arm_smmu_test_writer_record_syncs(struct arm_smmu_entry_writer *writer)
 		 * configuration.
 		 */
 		writer->ops->get_used(test_writer->entry, entry_used_bits);
+		if (writer->ops->get_ignored)
+			writer->ops->get_ignored(ignored_bits);
 		KUNIT_EXPECT_FALSE(
 			test_writer->test,
 			arm_smmu_entry_differs_in_used_bits(
 				test_writer->entry, entry_used_bits,
-				test_writer->init_entry, NUM_ENTRY_QWORDS) &&
+				ignored_bits, test_writer->init_entry,
+				NUM_ENTRY_QWORDS) &&
 				arm_smmu_entry_differs_in_used_bits(
 					test_writer->entry, entry_used_bits,
-					test_writer->target_entry,
+					ignored_bits, test_writer->target_entry,
 					NUM_ENTRY_QWORDS));
 	}
 }
@@ -106,6 +116,7 @@ arm_smmu_v3_test_debug_print_used_bits(struct arm_smmu_entry_writer *writer,
 static const struct arm_smmu_entry_writer_ops test_ste_ops = {
 	.sync = arm_smmu_test_writer_record_syncs,
 	.get_used = arm_smmu_get_ste_used,
+	.get_ignored = arm_smmu_get_ste_ignored,
 };
 
 static const struct arm_smmu_entry_writer_ops test_cd_ops = {
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index d16d35c78c06..95a4cfc5882d 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1082,6 +1082,12 @@ void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits)
 }
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_used);
 
+VISIBLE_IF_KUNIT
+void arm_smmu_get_ste_ignored(__le64 *ignored_bits)
+{
+}
+EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_ignored);
+
 /*
  * Figure out if we can do a hitless update of entry to become target. Returns a
  * bit mask where 1 indicates that qword needs to be set disruptively.
@@ -1094,11 +1100,14 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
 {
 	__le64 target_used[NUM_ENTRY_QWORDS] = {};
 	__le64 cur_used[NUM_ENTRY_QWORDS] = {};
+	__le64 ignored[NUM_ENTRY_QWORDS] = {};
 	u8 used_qword_diff = 0;
 	unsigned int i;
 
 	writer->ops->get_used(entry, cur_used);
 	writer->ops->get_used(target, target_used);
+	if (writer->ops->get_ignored)
+		writer->ops->get_ignored(ignored);
 
 	for (i = 0; i != NUM_ENTRY_QWORDS; i++) {
 		/*
@@ -1106,16 +1115,17 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
 		 * allowed to set a bit to 1 if the used function doesn't say it
 		 * is used.
 		 */
-		WARN_ON_ONCE(target[i] & ~target_used[i]);
+		WARN_ON_ONCE(target[i] & ~target_used[i] & ~ignored[i]);
 
 		/* Bits can change because they are not currently being used */
-		unused_update[i] = (entry[i] & cur_used[i]) |
+		unused_update[i] = (entry[i] & (cur_used[i] | ignored[i])) |
 				   (target[i] & ~cur_used[i]);
 		/*
 		 * Each bit indicates that a used bit in a qword needs to be
 		 * changed after unused_update is applied.
 		 */
-		if ((unused_update[i] & target_used[i]) != target[i])
+		if ((unused_update[i] & target_used[i]) !=
+		    (target[i] & ~ignored[i]))
 			used_qword_diff |= 1 << i;
 	}
 	return used_qword_diff;
@@ -1207,12 +1217,9 @@ void arm_smmu_write_entry(struct arm_smmu_entry_writer *writer, __le64 *entry,
 		entry_set(writer, entry, target, 0, 1);
 	} else {
 		/*
-		 * No inuse bit changed. Sanity check that all unused bits are 0
-		 * in the entry. The target was already sanity checked by
-		 * compute_qword_diff().
+		 * No inuse bit changed, though ignored bits may have changed.
 		 */
-		WARN_ON_ONCE(
-			entry_set(writer, entry, target, 0, NUM_ENTRY_QWORDS));
+		entry_set(writer, entry, target, 0, NUM_ENTRY_QWORDS);
 	}
 }
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_write_entry);
@@ -1543,6 +1550,7 @@ static void arm_smmu_ste_writer_sync_entry(struct arm_smmu_entry_writer *writer)
 static const struct arm_smmu_entry_writer_ops arm_smmu_ste_writer_ops = {
 	.sync = arm_smmu_ste_writer_sync_entry,
 	.get_used = arm_smmu_get_ste_used,
+	.get_ignored = arm_smmu_get_ste_ignored,
 };
 
 static void arm_smmu_write_ste(struct arm_smmu_master *master, u32 sid,
-- 
2.43.0



From nicolinc at nvidia.com  Fri Dec  5 16:51:59 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Fri, 5 Dec 2025 16:51:59 -0800
Subject: [PATCH rc v1 0/4] iommu/arm-smmu-v3: Fix hitless STE update in nesting cases
Message-ID: <cover.1764982046.git.nicolinc@nvidia.com>

Occasional C_BAD_STE errors were observed in nesting setups where a device
attached to a nested bypass/identity domain enables PASID.

This occurred when the physical STE was updated from S2-only mode to S1+S2
nesting mode, but the update failed to use the hitless routine that it was
supposed to use. Instead, it cleared STE.V bit to load the CD table, while
the default substream was still actively performing DMA.

It was later found that the diff algorithm in arm_smmu_entry_qword_diff()
enforced an additional critical word due to misaligned MEV and EATS fields
between S2-only and S1+S2 modes.

Both fields are either well-managed or non-critical, so move them to the
"ignored" list to relax the qword diff algorithm.

Additionally, add KUnit test coverage for these nesting STE cases.

This is on Github:
https://github.com/nicolinc/iommufd/commits/smmuv3_ste_fixes/

A host kernel must apply this to fix the bug.

Jason Gunthorpe (3):
  iommu/arm-smmu-v3: Add ignored bits to fix STE update sequence
  iommu/arm-smmu-v3: Ignore STE MEV when computing the update sequence
  iommu/arm-smmu-v3: Ignore STE EATS when computing the update sequence

Nicolin Chen (1):
  iommu/arm-smmu-v3-test: Add nested s1bypass coverage

 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  2 +
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  | 49 +++++++++++++++++--
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 49 ++++++++++++++-----
 3 files changed, 85 insertions(+), 15 deletions(-)


base-commit: 0d081b16946ef449fcb35b6edc1ef6f9fea6f0a0
-- 
2.43.0



From nicolinc at nvidia.com  Fri Dec  5 16:52:01 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Fri, 5 Dec 2025 16:52:01 -0800
Subject: [PATCH rc v1 2/4] iommu/arm-smmu-v3: Ignore STE MEV when computing the update sequence
In-Reply-To: <cover.1764982046.git.nicolinc@nvidia.com>
References: <cover.1764982046.git.nicolinc@nvidia.com>
Message-ID: <caca8d769b1ca0d0ec196a4fb264b0e36b1a4074.1764982046.git.nicolinc@nvidia.com>

From: Jason Gunthorpe <jgg at nvidia.com>

Nested CD tables set the MEV bit to try to reduce multi-fault spamming on
the hypervisor. Since MEV is in STE word 1 this causes a breaking update
sequence that is not required and impacts real workloads.

For the purposes of STE updates the value of MEV doesn't matter, if it is
set/cleared early or late it just results in a change to the fault reports
that must be supported by the kernel anyhow. The spec says:

 Note: Software must expect, and be able to deal with, coalesced fault
 records even when MEV == 0.

So ignore MEV when computing the update sequence to avoid creating a
breaking update.

Fixes: da0c56520e88 ("iommu/arm-smmu-v3: Set MEV bit in nested STE for DoS mitigations")
Cc: stable at vger.kernel.org
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 95a4cfc5882d..2df657c87abd 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1052,7 +1052,7 @@ void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits)
 			cpu_to_le64(STRTAB_STE_1_S1DSS | STRTAB_STE_1_S1CIR |
 				    STRTAB_STE_1_S1COR | STRTAB_STE_1_S1CSH |
 				    STRTAB_STE_1_S1STALLD | STRTAB_STE_1_STRW |
-				    STRTAB_STE_1_EATS | STRTAB_STE_1_MEV);
+				    STRTAB_STE_1_EATS);
 		used_bits[2] |= cpu_to_le64(STRTAB_STE_2_S2VMID);
 
 		/*
@@ -1068,7 +1068,7 @@ void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits)
 	if (cfg & BIT(1)) {
 		used_bits[1] |=
 			cpu_to_le64(STRTAB_STE_1_S2FWB | STRTAB_STE_1_EATS |
-				    STRTAB_STE_1_SHCFG | STRTAB_STE_1_MEV);
+				    STRTAB_STE_1_SHCFG);
 		used_bits[2] |=
 			cpu_to_le64(STRTAB_STE_2_S2VMID | STRTAB_STE_2_VTCR |
 				    STRTAB_STE_2_S2AA64 | STRTAB_STE_2_S2ENDI |
@@ -1085,6 +1085,16 @@ EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_used);
 VISIBLE_IF_KUNIT
 void arm_smmu_get_ste_ignored(__le64 *ignored_bits)
 {
+	/*
+	 * MEV does not meaningfully impact the operation of the HW, it only
+	 * changes how many fault events are generated, thus we can ignore it
+	 * when computing the ordering. The spec notes the device can act like
+	 * MEV=1 anyhow:
+	 *
+	 *  Note: Software must expect, and be able to deal with, coalesced
+	 *  fault records even when MEV == 0.
+	 */
+	ignored_bits[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
 }
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_ignored);
 
-- 
2.43.0



From nicolinc at nvidia.com  Fri Dec  5 16:52:02 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Fri, 5 Dec 2025 16:52:02 -0800
Subject: [PATCH rc v1 3/4] iommu/arm-smmu-v3: Ignore STE EATS when computing the update sequence
In-Reply-To: <cover.1764982046.git.nicolinc@nvidia.com>
References: <cover.1764982046.git.nicolinc@nvidia.com>
Message-ID: <db1450e7a5989e51756a7ec3285d70ee90bae24f.1764982046.git.nicolinc@nvidia.com>

From: Jason Gunthorpe <jgg at nvidia.com>

If a VM want to toggle EATS off the hypervisor will see EATS change to 0
and insert a V=0 breaking update into the STE even though the VM did not
ask for that.

Relax the rules for EATS sequencing, we don't need it to be exact because
the enclosing code will always disable ATS at the PCI device if we are
changing EATS. This ensures there are no ATS transactions that can race
with an EATS change so we don't need to carefully sequence these bits.

Fixes: 1e8be08d1c91 ("iommu/arm-smmu-v3: Support IOMMU_DOMAIN_NESTED")
Cc: stable at vger.kernel.org
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 2df657c87abd..6a982051c3c2 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1051,8 +1051,7 @@ void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits)
 		used_bits[1] |=
 			cpu_to_le64(STRTAB_STE_1_S1DSS | STRTAB_STE_1_S1CIR |
 				    STRTAB_STE_1_S1COR | STRTAB_STE_1_S1CSH |
-				    STRTAB_STE_1_S1STALLD | STRTAB_STE_1_STRW |
-				    STRTAB_STE_1_EATS);
+				    STRTAB_STE_1_S1STALLD | STRTAB_STE_1_STRW);
 		used_bits[2] |= cpu_to_le64(STRTAB_STE_2_S2VMID);
 
 		/*
@@ -1067,8 +1066,7 @@ void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits)
 	/* S2 translates */
 	if (cfg & BIT(1)) {
 		used_bits[1] |=
-			cpu_to_le64(STRTAB_STE_1_S2FWB | STRTAB_STE_1_EATS |
-				    STRTAB_STE_1_SHCFG);
+			cpu_to_le64(STRTAB_STE_1_S2FWB | STRTAB_STE_1_SHCFG);
 		used_bits[2] |=
 			cpu_to_le64(STRTAB_STE_2_S2VMID | STRTAB_STE_2_VTCR |
 				    STRTAB_STE_2_S2AA64 | STRTAB_STE_2_S2ENDI |
@@ -1095,6 +1093,15 @@ void arm_smmu_get_ste_ignored(__le64 *ignored_bits)
 	 *  fault records even when MEV == 0.
 	 */
 	ignored_bits[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
+
+	/*
+	 * EATS is used to reject and control the ATS behavior of the device. If
+	 * we are changing it away from 0 then we already trust the device to
+	 * use ATS properly and we have sequenced the device's ATS enable in PCI
+	 * config space to prevent it from issuing ATS while we are changing
+	 * EATS.
+	 */
+	ignored_bits[1] |= cpu_to_le64(STRTAB_STE_1_EATS);
 }
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_ignored);
 
-- 
2.43.0



From nicolinc at nvidia.com  Fri Dec  5 16:52:03 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Fri, 5 Dec 2025 16:52:03 -0800
Subject: [PATCH rc v1 4/4] iommu/arm-smmu-v3-test: Add nested s1bypass coverage
In-Reply-To: <cover.1764982046.git.nicolinc@nvidia.com>
References: <cover.1764982046.git.nicolinc@nvidia.com>
Message-ID: <3c838833d8bbb69a72a85ddbcc325b22ae7a7d6d.1764982046.git.nicolinc@nvidia.com>

STE in a nested case requires both S1 and S2 fields. And this makes the use
case different from the existing one.

Add coverage for previously failed cases shifting between S2-only and S1+S2
STEs.

Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  | 32 +++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
index 9287904c93a2..56bdcf5a517e 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
@@ -553,6 +553,36 @@ static void arm_smmu_v3_write_ste_test_s2_to_s1_stall(struct kunit *test)
 						       NUM_EXPECTED_SYNCS(3));
 }
 
+static void
+arm_smmu_v3_write_ste_test_nested_s1dssbypass_to_s1bypass(struct kunit *test)
+{
+	struct arm_smmu_ste s1_ste;
+	struct arm_smmu_ste s2_ste;
+
+	arm_smmu_test_make_s2_ste(&s1_ste, ARM_SMMU_MASTER_TEST_ATS);
+	arm_smmu_test_make_cdtable_ste(&s1_ste, STRTAB_STE_1_S1DSS_SSID0,
+				       fake_cdtab_dma_addr,
+				       ARM_SMMU_MASTER_TEST_ATS);
+	arm_smmu_test_make_s2_ste(&s2_ste, 0);
+	arm_smmu_v3_test_ste_expect_hitless_transition(test, &s1_ste, &s2_ste,
+						       NUM_EXPECTED_SYNCS(3));
+}
+
+static void
+arm_smmu_v3_write_ste_test_nested_s1bypass_to_s1dssbypass(struct kunit *test)
+{
+	struct arm_smmu_ste s1_ste;
+	struct arm_smmu_ste s2_ste;
+
+	arm_smmu_test_make_s2_ste(&s1_ste, ARM_SMMU_MASTER_TEST_ATS);
+	arm_smmu_test_make_cdtable_ste(&s1_ste, STRTAB_STE_1_S1DSS_SSID0,
+				       fake_cdtab_dma_addr,
+				       ARM_SMMU_MASTER_TEST_ATS);
+	arm_smmu_test_make_s2_ste(&s2_ste, 0);
+	arm_smmu_v3_test_ste_expect_hitless_transition(test, &s2_ste, &s1_ste,
+						       NUM_EXPECTED_SYNCS(3));
+}
+
 static void arm_smmu_v3_write_cd_test_sva_clear(struct kunit *test)
 {
 	struct arm_smmu_cd cd = {};
@@ -599,6 +629,8 @@ static struct kunit_case arm_smmu_v3_test_cases[] = {
 	KUNIT_CASE(arm_smmu_v3_write_cd_test_s1_change_asid),
 	KUNIT_CASE(arm_smmu_v3_write_ste_test_s1_to_s2_stall),
 	KUNIT_CASE(arm_smmu_v3_write_ste_test_s2_to_s1_stall),
+	KUNIT_CASE(arm_smmu_v3_write_ste_test_nested_s1dssbypass_to_s1bypass),
+	KUNIT_CASE(arm_smmu_v3_write_ste_test_nested_s1bypass_to_s1dssbypass),
 	KUNIT_CASE(arm_smmu_v3_write_cd_test_sva_clear),
 	KUNIT_CASE(arm_smmu_v3_write_cd_test_sva_release),
 	{},
-- 
2.43.0



From pr-tracker-bot at kernel.org  Fri Dec  5 18:00:28 2025
From: pr-tracker-bot at kernel.org (pr-tracker-bot at kernel.org)
Date: Sat, 06 Dec 2025 02:00:28 +0000
Subject: [GIT PULL 1/6] soc: defconfig for 6.19
In-Reply-To: <347a999a-037b-42f7-b4ba-b05b81207fea@app.fastmail.com>
References: <334684ec-5796-47a4-b9f4-96c60f449634@app.fastmail.com> <347a999a-037b-42f7-b4ba-b05b81207fea@app.fastmail.com>
Message-ID: <176498642885.1925836.9314675250384268584.pr-tracker-bot@kernel.org>

The pull request you sent on Fri, 05 Dec 2025 19:26:47 +0100:

> https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git tags/soc-defconfig-6.19

has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/b4c6c76e4039366017a4f568672e4ea9fc82f97d

Thank you!

-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html


From pr-tracker-bot at kernel.org  Fri Dec  5 18:00:30 2025
From: pr-tracker-bot at kernel.org (pr-tracker-bot at kernel.org)
Date: Sat, 06 Dec 2025 02:00:30 +0000
Subject: [GIT PULL 2/6] soc: arm code changes for 6.19
In-Reply-To: <b4048b25-c1a8-4442-8594-c604bcef9e29@app.fastmail.com>
References: <334684ec-5796-47a4-b9f4-96c60f449634@app.fastmail.com> <b4048b25-c1a8-4442-8594-c604bcef9e29@app.fastmail.com>
Message-ID: <176498643093.1925836.1399760157687412457.pr-tracker-bot@kernel.org>

The pull request you sent on Fri, 05 Dec 2025 19:27:20 +0100:

> https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git tags/soc-arm-6.19

has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/09cab48db950b6fb8c114314a20c0fd5a80cf990

Thank you!

-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html


From pr-tracker-bot at kernel.org  Fri Dec  5 18:00:32 2025
From: pr-tracker-bot at kernel.org (pr-tracker-bot at kernel.org)
Date: Sat, 06 Dec 2025 02:00:32 +0000
Subject: [GIT PULL 4/6] soc: sew SoC familes for 6.19
In-Reply-To: <46536f6a-6225-4d5b-ba9e-5cfc64b414ac@app.fastmail.com>
References: <334684ec-5796-47a4-b9f4-96c60f449634@app.fastmail.com> <46536f6a-6225-4d5b-ba9e-5cfc64b414ac@app.fastmail.com>
Message-ID: <176498643269.1925836.17201281819804899057.pr-tracker-bot@kernel.org>

The pull request you sent on Fri, 05 Dec 2025 19:28:42 +0100:

> https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git tags/soc-newsoc-6.19

has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/66a1025f7f0bc00404ec6357af68815c70dadae2

Thank you!

-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html


From pr-tracker-bot at kernel.org  Fri Dec  5 18:00:34 2025
From: pr-tracker-bot at kernel.org (pr-tracker-bot at kernel.org)
Date: Sat, 06 Dec 2025 02:00:34 +0000
Subject: [GIT PULL 5/6] soc: driver updates for 6.19
In-Reply-To: <dceb9f99-cb69-498f-9717-34e3f28c8fc1@app.fastmail.com>
References: <334684ec-5796-47a4-b9f4-96c60f449634@app.fastmail.com> <dceb9f99-cb69-498f-9717-34e3f28c8fc1@app.fastmail.com>
Message-ID: <176498643469.1925836.14273165403476324157.pr-tracker-bot@kernel.org>

The pull request you sent on Fri, 05 Dec 2025 19:29:18 +0100:

> https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git tags/soc-drivers-6.19

has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/208eed95fc710827b100266c9450ae84d46727bd

Thank you!

-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html


From pr-tracker-bot at kernel.org  Fri Dec  5 18:00:36 2025
From: pr-tracker-bot at kernel.org (pr-tracker-bot at kernel.org)
Date: Sat, 06 Dec 2025 02:00:36 +0000
Subject: [GIT PULL 6/6] soc: driver updates for 6.19, part 2
In-Reply-To: <16f9deb7-8717-4983-99b7-91a6e84eb560@app.fastmail.com>
References: <334684ec-5796-47a4-b9f4-96c60f449634@app.fastmail.com> <16f9deb7-8717-4983-99b7-91a6e84eb560@app.fastmail.com>
Message-ID: <176498643691.1925836.6118525304815513749.pr-tracker-bot@kernel.org>

The pull request you sent on Fri, 05 Dec 2025 19:33:21 +0100:

> https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git tags/soc-drivers-6.19-2

has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/11efc1cb7016e300047822fd60e0f4b4158bd56d

Thank you!

-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html


From pr-tracker-bot at kernel.org  Fri Dec  5 18:01:52 2025
From: pr-tracker-bot at kernel.org (pr-tracker-bot at kernel.org)
Date: Sat, 06 Dec 2025 02:01:52 +0000
Subject: [GIT PULL 3/6] soc: devicetree updates for 6.19
In-Reply-To: <52068d9c-d677-4fa6-8ced-6a7fb190a935@app.fastmail.com>
References: <334684ec-5796-47a4-b9f4-96c60f449634@app.fastmail.com> <52068d9c-d677-4fa6-8ced-6a7fb190a935@app.fastmail.com>
Message-ID: <176498651213.1925836.5364884915425790784.pr-tracker-bot@kernel.org>

The pull request you sent on Fri, 05 Dec 2025 19:28:03 +0100:

> https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git tags/soc-dt-6.19

has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/0cac5ce06e524755b3dac1e0a060b05992076d93

Thank you!

-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html


From royluo at google.com  Fri Dec  5 18:44:31 2025
From: royluo at google.com (Roy Luo)
Date: Fri, 5 Dec 2025 18:44:31 -0800
Subject: [PATCH v8 1/2] dt-bindings: phy: google: Add Google Tensor G5 USB PHY
In-Reply-To: <CA+zupgzi55svWK4gHsFtdQSD9jFKbxHx_0GE2R1R5DafmYyGNA@mail.gmail.com>
References: <20251205-phyb4-v8-0-c59ea80a4458@google.com> <20251205-phyb4-v8-1-c59ea80a4458@google.com>
 <18eeb1c5-d21b-4505-b6a4-472f6e191864@kernel.org> <CA+zupgwa+m8Pa=+8shORaOA1OO6zoo6zYEojFS2UDuP0doBq7A@mail.gmail.com>
 <f32e0810-56f9-417e-abf6-0cc7b361bd15@kernel.org> <CA+zupgyxQisYBnLj9_3DtcN3R1Ugfv+-p-wimFp-hnqkhrrgyA@mail.gmail.com>
 <988b3fcb-44db-45ca-823b-5ab13206bd04@kernel.org> <CA+zupgzi55svWK4gHsFtdQSD9jFKbxHx_0GE2R1R5DafmYyGNA@mail.gmail.com>
Message-ID: <CA+zupgy5TKWiVGwt5dFye7ztk7O_n7JQm4j7H8BCC2gzjfkgqw@mail.gmail.com>

On Fri, Dec 5, 2025 at 12:18?PM Roy Luo <royluo at google.com> wrote:
>
> On Fri, Dec 5, 2025 at 11:26?AM Krzysztof Kozlowski <krzk at kernel.org> wrote:
> >
> > I assume you understood what should be done instead in this patchset.
> > Anyway, my previous tag applies if there were no bindings changes, but I
> > wasted too much time here to care anymore. The expectation from big
> > companies is they do not ask community to coach on basic submission
> > process. It's quite unfair to my spare, personal time after work,
> > considering how much big company is making. Big company should invest in
> > this coaching.
> >
> >
> > Best regards,
> > Krzysztof
>
> Thank you for the feedback. I understand your frustration, and I
> apologize for taking up your time. I will be sure to be more thorough
> in the future.
>
> Thanks,
> Roy Luo

To confirm my takeaway: for this patch, the changes I introduced
were not significant enough to remove your 'Reviewed-by' tag,
and I should have kept it. Moving forward, I will calibrate my
criteria for what changes are considered 'significant' (essentially
any changes to binding), and more importantly, always document
the rationale for dropping or keeping tags in the changelog when
I make non-trivial changes to patches.

I plan to send a new version for this patchset and the controller
patchset [1] next week with your tag re-added, please let me
know if you disagree.

[1] https://lore.kernel.org/linux-usb/20251205-controller-v9-0-9f158b18f979 at google.com

Thanks,
Roy Luo


From lkp at intel.com  Fri Dec  5 19:18:45 2025
From: lkp at intel.com (kernel test robot)
Date: Sat, 6 Dec 2025 11:18:45 +0800
Subject: [PATCH v6 4/5] clk: meson: t7: add support for the T7 SoC PLL
 clock
In-Reply-To: <20251204053635.1234150-5-jian.hu@amlogic.com>
References: <20251204053635.1234150-5-jian.hu@amlogic.com>
Message-ID: <202512061054.wsIzRCCd-lkp@intel.com>

Hi Jian,

kernel test robot noticed the following build errors:

[auto build test ERROR on clk/clk-next]
[also build test ERROR on linus/master v6.18 next-20251205]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Jian-Hu/dt-bindings-clock-add-Amlogic-T7-PLL-clock-controller/20251204-135351
base:   https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next
patch link:    https://lore.kernel.org/r/20251204053635.1234150-5-jian.hu%40amlogic.com
patch subject: [PATCH v6 4/5] clk: meson: t7: add support for the T7 SoC PLL clock
config: arm64-randconfig-003-20251206 (https://download.01.org/0day-ci/archive/20251206/202512061054.wsIzRCCd-lkp at intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 14bf95b06a18b9b59c89601cbc0e5a6f2176b118)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251206/202512061054.wsIzRCCd-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512061054.wsIzRCCd-lkp at intel.com/

All errors (new ones prefixed by >>):

>> ld.lld: error: undefined symbol: meson_clk_mpll_ops
   >>> referenced by t7-pll.c
   >>>               drivers/clk/meson/t7-pll.o:(.compoundliteral.51) in archive vmlinux.a
   >>> referenced by t7-pll.c
   >>>               drivers/clk/meson/t7-pll.o:(.compoundliteral.59) in archive vmlinux.a
   >>> referenced by t7-pll.c
   >>>               drivers/clk/meson/t7-pll.o:(.compoundliteral.67) in archive vmlinux.a
   >>> referenced 1 more times
   >>> did you mean: meson_clk_pll_ops
   >>> defined in: vmlinux.a(drivers/clk/meson/clk-pll.o)

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From gustavo at embeddedor.com  Fri Dec  5 19:38:14 2025
From: gustavo at embeddedor.com (Gustavo A. R. Silva)
Date: Sat, 6 Dec 2025 12:38:14 +0900
Subject: [PATCH] KVM: Remove subtle "struct kvm_stats_desc" pseudo-overlay
In-Reply-To: <20251205232655.445294-1-seanjc@google.com>
References: <20251205232655.445294-1-seanjc@google.com>
Message-ID: <0018d1c0-58ec-4b31-b016-472795990923@embeddedor.com>



On 12/6/25 08:26, Sean Christopherson wrote:
> Remove KVM's internal pseudo-overlay of kvm_stats_desc, which subtly
> aliases the flexible name[] in the uAPI definition with a fixed-size array
> of the same name.  The unusual embedded structure results in compiler
> warnings due to -Wflex-array-member-not-at-end, and also necessitates an
> extra level of dereferencing in KVM.  To avoid the "overlay", define the
> uAPI structure to have a fixed-size name when building for the kernel.

Nice. Thanks for this.

> 
> Opportunistically clean up the indentation for the stats macros, and
> replace spaces with tabs.
> 
> No functional change intended.
> 
> Reported-by: Gustavo A. R. Silva <gustavoars at kernel.org>
> Closes: https://lore.kernel.org/all/aPfNKRpLfhmhYqfP at kspp
> Signed-off-by: Sean Christopherson <seanjc at google.com>

Acked-by: Gustavo A. R. Silva <gustavoars at kernel.org>

-Gustavo


From dmitry.baryshkov at oss.qualcomm.com  Fri Dec  5 20:02:38 2025
From: dmitry.baryshkov at oss.qualcomm.com (Dmitry Baryshkov)
Date: Sat, 6 Dec 2025 06:02:38 +0200
Subject: [PATCH 3/3] clk: qcom: camcc: Add camera clock controller driver
 for SM8750 SoC
In-Reply-To: <20251202-sm8750_camcc-v1-3-b3f7ef6723f1@oss.qualcomm.com>
References: <20251202-sm8750_camcc-v1-0-b3f7ef6723f1@oss.qualcomm.com>
 <20251202-sm8750_camcc-v1-3-b3f7ef6723f1@oss.qualcomm.com>
Message-ID: <mcvwms5logao4sz2o4h5yfyi7kloj7pkx5qzq7byvtcmhbymnk@ynegs32kkxyw>

On Tue, Dec 02, 2025 at 03:56:27PM +0530, Taniya Das wrote:
> Add support for the Camera Clock Controller (CAMCC) on the SM8750
> platform.
> 
> The CAMCC block on SM8750 includes both the primary camera clock
> controller and the Camera BIST clock controller, which provides the
> functional MCLK required for camera operations.
> 
> Signed-off-by: Taniya Das <taniya.das at oss.qualcomm.com>
> ---
>  drivers/clk/qcom/Kconfig                |   10 +
>  drivers/clk/qcom/Makefile               |    1 +
>  drivers/clk/qcom/cambistmclkcc-sm8750.c |  454 ++++++
>  drivers/clk/qcom/camcc-sm8750.c         | 2710 +++++++++++++++++++++++++++++++
>  4 files changed, 3175 insertions(+)
> 

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>


-- 
With best wishes
Dmitry


From lkp at intel.com  Fri Dec  5 20:22:14 2025
From: lkp at intel.com (kernel test robot)
Date: Sat, 6 Dec 2025 12:22:14 +0800
Subject: [PATCH 2/4] pwm: sun50i: Add H616 PWM support
In-Reply-To: <20251205100239.1563353-3-richard.genoud@bootlin.com>
References: <20251205100239.1563353-3-richard.genoud@bootlin.com>
Message-ID: <202512061109.UxaYeMZ9-lkp@intel.com>

Hi Richard,

kernel test robot noticed the following build errors:

[auto build test ERROR on 6987d58a9cbc5bd57c983baa514474a86c945d56]

url:    https://github.com/intel-lab-lkp/linux/commits/Richard-Genoud/dt-bindings-pwm-sunxi-add-PWM-controller-for-Allwinner-H616/20251205-214804
base:   6987d58a9cbc5bd57c983baa514474a86c945d56
patch link:    https://lore.kernel.org/r/20251205100239.1563353-3-richard.genoud%40bootlin.com
patch subject: [PATCH 2/4] pwm: sun50i: Add H616 PWM support
config: hexagon-randconfig-r073-20251206 (https://download.01.org/0day-ci/archive/20251206/202512061109.UxaYeMZ9-lkp at intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 14bf95b06a18b9b59c89601cbc0e5a6f2176b118)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251206/202512061109.UxaYeMZ9-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512061109.UxaYeMZ9-lkp at intel.com/

All errors (new ones prefixed by >>):

>> drivers/pwm/pwm-sun50i-h616.c:452:23: error: call to undeclared function 'FIELD_GET'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     452 |         tmp = NSEC_PER_SEC * PWM_REG_DUTY(val);
         |                              ^
   drivers/pwm/pwm-sun50i-h616.c:76:28: note: expanded from macro 'PWM_REG_DUTY'
      76 | #define PWM_REG_DUTY(reg)               FIELD_GET(PWM_DUTY_MASK, reg)
         |                                         ^
>> drivers/pwm/pwm-sun50i-h616.c:493:40: error: call to undeclared function 'FIELD_MAX'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     493 |                 freq = div64_u64(NSEC_PER_SEC * (u64)PWM_PERIOD_MAX, period);
         |                                                      ^
   drivers/pwm/pwm-sun50i-h616.c:79:26: note: expanded from macro 'PWM_PERIOD_MAX'
      79 | #define PWM_PERIOD_MAX                  FIELD_MAX(PWM_PERIOD_MASK)
         |                                         ^
   drivers/pwm/pwm-sun50i-h616.c:508:27: error: call to undeclared function 'FIELD_MAX'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     508 |         if ((cnt == 0) || (cnt > PWM_PERIOD_MAX)) {
         |                                  ^
   drivers/pwm/pwm-sun50i-h616.c:79:26: note: expanded from macro 'PWM_PERIOD_MAX'
      79 | #define PWM_PERIOD_MAX                  FIELD_MAX(PWM_PERIOD_MASK)
         |                                         ^
>> drivers/pwm/pwm-sun50i-h616.c:577:9: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     577 |                 val = PWM_DUTY(chan->active_cycles);
         |                       ^
   drivers/pwm/pwm-sun50i-h616.c:78:25: note: expanded from macro 'PWM_DUTY'
      78 | #define PWM_DUTY(dty)                   FIELD_PREP(PWM_DUTY_MASK, dty)
         |                                         ^
   4 errors generated.


vim +/FIELD_GET +452 drivers/pwm/pwm-sun50i-h616.c

   413	
   414	static int h616_pwm_get_state(struct pwm_chip *chip,
   415				      struct pwm_device *pwm,
   416				      struct pwm_state *state)
   417	{
   418		struct h616_pwm_chip *h616chip = to_h616_pwm_chip(chip);
   419		struct h616_pwm_channel *chan = &h616chip->channels[pwm->hwpwm];
   420		u64 clk_rate, tmp;
   421		u32 val;
   422	
   423		clk_rate = clk_get_rate(chan->pwm_clk);
   424		if (!clk_rate)
   425			return -EINVAL;
   426	
   427		val = h616_pwm_readl(h616chip, PWM_ENR);
   428		state->enabled = !!(PWM_ENABLE(pwm->hwpwm) & val);
   429	
   430		val = h616_pwm_readl(h616chip, PWM_XY_CLK_CR(PWM_PAIR_IDX(pwm->hwpwm)));
   431		if (val & BIT(PWM_XY_CLK_CR_BYPASS_BIT(pwm->hwpwm))) {
   432			/*
   433			 * When bypass is enabled, the PWM logic is inactive.
   434			 * The PWM_clock_src_xy is directly routed to PWM_clock_x
   435			 */
   436			state->period = DIV_ROUND_UP_ULL(NSEC_PER_SEC, clk_rate);
   437			state->duty_cycle = DIV_ROUND_UP_ULL(state->period, 2);
   438			state->polarity = PWM_POLARITY_NORMAL;
   439			return 0;
   440		}
   441	
   442		state->enabled &= !!(BIT(PWM_XY_CLK_CR_GATE_BIT) & val);
   443	
   444		val = h616_pwm_readl(h616chip, PWM_CTRL_REG(pwm->hwpwm));
   445		if (val & PWM_CTRL_ACTIVE_STATE)
   446			state->polarity = PWM_POLARITY_NORMAL;
   447		else
   448			state->polarity = PWM_POLARITY_INVERSED;
   449	
   450		val = h616_pwm_readl(h616chip, PWM_PERIOD_REG(pwm->hwpwm));
   451	
 > 452		tmp = NSEC_PER_SEC * PWM_REG_DUTY(val);
   453		state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate);
   454	
   455		tmp = NSEC_PER_SEC * PWM_REG_PERIOD(val);
   456		state->period = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate);
   457	
   458		return 0;
   459	}
   460	
   461	static int h616_pwm_calc(struct pwm_chip *chip, unsigned int idx,
   462				 const struct pwm_state *state)
   463	{
   464		struct h616_pwm_chip *h616chip = to_h616_pwm_chip(chip);
   465		struct h616_pwm_channel *chan = &h616chip->channels[idx];
   466		unsigned int cnt, duty_cnt;
   467		unsigned long max_rate;
   468		long calc_rate;
   469		u64 duty, period, freq;
   470	
   471		duty = state->duty_cycle;
   472		period = state->period;
   473	
   474		max_rate = clk_round_rate(chan->pwm_clk, UINT32_MAX);
   475	
   476		dev_dbg(pwmchip_parent(chip), "max_rate: %ld Hz\n", max_rate);
   477	
   478		if ((period * max_rate >= NSEC_PER_SEC) &&
   479		    (period * max_rate < 2 * NSEC_PER_SEC) &&
   480		    (duty * max_rate * 2 >= NSEC_PER_SEC)) {
   481			/*
   482			 * If the requested period is to small to be generated by the
   483			 * PWM, we can just select the highest clock and bypass the
   484			 * PWM logic
   485			 */
   486			dev_dbg(pwmchip_parent(chip), "Setting bypass (period=%lld)\n",
   487				period);
   488			freq = div64_u64(NSEC_PER_SEC, period);
   489			chan->bypass = true;
   490			duty = period / 2;
   491		} else {
   492			chan->bypass = false;
 > 493			freq = div64_u64(NSEC_PER_SEC * (u64)PWM_PERIOD_MAX, period);
   494			if (freq > UINT32_MAX)
   495				freq = UINT32_MAX;
   496		}
   497	
   498		calc_rate = clk_round_rate(chan->pwm_clk, freq);
   499		if (calc_rate <= 0) {
   500			dev_err(pwmchip_parent(chip),
   501				"Invalid source clock frequency %llu\n", freq);
   502			return calc_rate ? calc_rate : -EINVAL;
   503		}
   504	
   505		dev_dbg(pwmchip_parent(chip), "calc_rate: %ld Hz\n", calc_rate);
   506	
   507		cnt = mul_u64_u64_div_u64(calc_rate, period, NSEC_PER_SEC);
   508		if ((cnt == 0) || (cnt > PWM_PERIOD_MAX)) {
   509			dev_err(pwmchip_parent(chip), "Period out of range\n");
   510			return -EINVAL;
   511		}
   512	
   513		duty_cnt = mul_u64_u64_div_u64(calc_rate, duty, NSEC_PER_SEC);
   514	
   515		if (duty_cnt >= cnt)
   516			duty_cnt = cnt - 1;
   517	
   518		dev_dbg(pwmchip_parent(chip), "period=%llu cnt=%u duty=%llu duty_cnt=%u\n",
   519			period, cnt, duty, duty_cnt);
   520	
   521		chan->active_cycles = duty_cnt;
   522		chan->entire_cycles = cnt;
   523	
   524		chan->rate = calc_rate;
   525	
   526		return 0;
   527	}
   528	
   529	static int h616_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
   530				  const struct pwm_state *state)
   531	{
   532		struct h616_pwm_chip *h616chip = to_h616_pwm_chip(chip);
   533		struct h616_pwm_channel *chan = &h616chip->channels[pwm->hwpwm];
   534		struct pwm_state cstate;
   535		unsigned long flags;
   536		u32 val;
   537		int ret;
   538	
   539		ret = h616_pwm_calc(chip, pwm->hwpwm, state);
   540		if (ret) {
   541			dev_err(pwmchip_parent(chip), "period exceeds the maximum value\n");
   542			return ret;
   543		}
   544	
   545		pwm_get_state(pwm, &cstate);
   546	
   547		ret = clk_set_rate(chan->pwm_clk, chan->rate);
   548		if (ret) {
   549			dev_err(pwmchip_parent(chip), "failed to set PWM %d clock rate to %lu\n",
   550				pwm->hwpwm, chan->rate);
   551			return ret;
   552		}
   553	
   554		h616_pwm_set_bypass(h616chip, pwm->hwpwm, chan->bypass);
   555	
   556		/*
   557		 * If bypass is set, the PWM logic (polarity, duty) can't be applied
   558		 */
   559	
   560		if (chan->bypass && (state->polarity == PWM_POLARITY_INVERSED)) {
   561			dev_warn(pwmchip_parent(chip),
   562				 "Can't set inversed polarity with bypass enabled\n");
   563		} else {
   564			val = h616_pwm_readl(h616chip, PWM_CTRL_REG(pwm->hwpwm));
   565			val &= ~PWM_CTRL_ACTIVE_STATE;
   566			if (state->polarity == PWM_POLARITY_NORMAL)
   567				val |= PWM_CTRL_ACTIVE_STATE;
   568			h616_pwm_writel(h616chip, val, PWM_CTRL_REG(pwm->hwpwm));
   569		}
   570	
   571		if (chan->bypass && (state->duty_cycle * 2 != state->period)) {
   572			dev_warn(pwmchip_parent(chip),
   573				 "Can't set a duty cycle with bypass enabled\n");
   574		}
   575	
   576		if (!chan->bypass) {
 > 577			val = PWM_DUTY(chan->active_cycles);
   578			val |= PWM_PERIOD(chan->entire_cycles);
   579			h616_pwm_writel(h616chip, val, PWM_PERIOD_REG(pwm->hwpwm));
   580		}
   581	
   582		if (state->enabled == cstate.enabled)
   583			return 0;
   584	
   585		if (cstate.enabled) {
   586			unsigned long delay_us;
   587	
   588			/*
   589			 * We need a full period to elapse before
   590			 * disabling the channel.
   591			 */
   592			delay_us = DIV_ROUND_UP_ULL(cstate.period, NSEC_PER_USEC);
   593			fsleep(delay_us);
   594		}
   595	
   596		spin_lock_irqsave(&h616chip->clk_pdata->lock, flags);
   597	
   598		val = h616_pwm_readl(h616chip, PWM_ENR);
   599		if (state->enabled)
   600			val |= PWM_ENABLE(pwm->hwpwm);
   601		else
   602			val &= ~PWM_ENABLE(pwm->hwpwm);
   603		h616_pwm_writel(h616chip, val, PWM_ENR);
   604	
   605		spin_unlock_irqrestore(&h616chip->clk_pdata->lock, flags);
   606	
   607		return 0;
   608	}
   609	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From lkp at intel.com  Fri Dec  5 20:32:50 2025
From: lkp at intel.com (kernel test robot)
Date: Sat, 6 Dec 2025 12:32:50 +0800
Subject: [PATCH 2/4] pwm: sun50i: Add H616 PWM support
In-Reply-To: <20251205100239.1563353-3-richard.genoud@bootlin.com>
References: <20251205100239.1563353-3-richard.genoud@bootlin.com>
Message-ID: <202512061246.jJ5UrB71-lkp@intel.com>

Hi Richard,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 6987d58a9cbc5bd57c983baa514474a86c945d56]

url:    https://github.com/intel-lab-lkp/linux/commits/Richard-Genoud/dt-bindings-pwm-sunxi-add-PWM-controller-for-Allwinner-H616/20251205-214804
base:   6987d58a9cbc5bd57c983baa514474a86c945d56
patch link:    https://lore.kernel.org/r/20251205100239.1563353-3-richard.genoud%40bootlin.com
patch subject: [PATCH 2/4] pwm: sun50i: Add H616 PWM support
config: parisc-allyesconfig (https://download.01.org/0day-ci/archive/20251206/202512061246.jJ5UrB71-lkp at intel.com/config)
compiler: hppa-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251206/202512061246.jJ5UrB71-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512061246.jJ5UrB71-lkp at intel.com/

All warnings (new ones prefixed by >>):

   drivers/pwm/pwm-sun50i-h616.c: In function 'h616_pwm_get_state':
   drivers/pwm/pwm-sun50i-h616.c:76:41: error: implicit declaration of function 'FIELD_GET' [-Wimplicit-function-declaration]
      76 | #define PWM_REG_DUTY(reg)               FIELD_GET(PWM_DUTY_MASK, reg)
         |                                         ^~~~~~~~~
   drivers/pwm/pwm-sun50i-h616.c:452:30: note: in expansion of macro 'PWM_REG_DUTY'
     452 |         tmp = NSEC_PER_SEC * PWM_REG_DUTY(val);
         |                              ^~~~~~~~~~~~
   drivers/pwm/pwm-sun50i-h616.c: In function 'h616_pwm_calc':
   drivers/pwm/pwm-sun50i-h616.c:79:41: error: implicit declaration of function 'FIELD_MAX' [-Wimplicit-function-declaration]
      79 | #define PWM_PERIOD_MAX                  FIELD_MAX(PWM_PERIOD_MASK)
         |                                         ^~~~~~~~~
   drivers/pwm/pwm-sun50i-h616.c:493:54: note: in expansion of macro 'PWM_PERIOD_MAX'
     493 |                 freq = div64_u64(NSEC_PER_SEC * (u64)PWM_PERIOD_MAX, period);
         |                                                      ^~~~~~~~~~~~~~
   drivers/pwm/pwm-sun50i-h616.c: In function 'h616_pwm_apply':
   drivers/pwm/pwm-sun50i-h616.c:78:41: error: implicit declaration of function 'FIELD_PREP' [-Wimplicit-function-declaration]
      78 | #define PWM_DUTY(dty)                   FIELD_PREP(PWM_DUTY_MASK, dty)
         |                                         ^~~~~~~~~~
   drivers/pwm/pwm-sun50i-h616.c:577:23: note: in expansion of macro 'PWM_DUTY'
     577 |                 val = PWM_DUTY(chan->active_cycles);
         |                       ^~~~~~~~
   drivers/pwm/pwm-sun50i-h616.c: In function 'h616_add_composite_clk':
>> drivers/pwm/pwm-sun50i-h616.c:666:28: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
     666 |                 mux->reg = (u64)mux->reg + reg;
         |                            ^
   drivers/pwm/pwm-sun50i-h616.c:676:29: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
     676 |                 gate->reg = (u64)gate->reg + reg;
         |                             ^
   drivers/pwm/pwm-sun50i-h616.c:686:29: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
     686 |                 rate->reg = (u64)rate->reg + reg;
         |                             ^


vim +666 drivers/pwm/pwm-sun50i-h616.c

   650	
   651	static int h616_add_composite_clk(const struct clk_pwm_data *data,
   652					  void __iomem *reg, spinlock_t *lock,
   653					  struct device *dev, struct clk_hw **hw)
   654	{
   655		const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, *rate_ops = NULL;
   656		struct clk_hw *mux_hw = NULL, *gate_hw = NULL, *rate_hw = NULL;
   657	
   658	
   659		if (data->mux_hw) {
   660			struct clk_mux *mux;
   661	
   662			mux_hw = data->mux_hw;
   663			mux = to_clk_mux(mux_hw);
   664			mux->lock = lock;
   665			mux_ops = mux_hw->init->ops;
 > 666			mux->reg = (u64)mux->reg + reg;
   667		}
   668	
   669		if (data->gate_hw) {
   670			struct clk_gate *gate;
   671	
   672			gate_hw = data->gate_hw;
   673			gate = to_clk_gate(gate_hw);
   674			gate->lock = lock;
   675			gate_ops = gate_hw->init->ops;
   676			gate->reg = (u64)gate->reg + reg;
   677		}
   678	
   679		if (data->rate_hw) {
   680			struct clk_divider *rate;
   681	
   682			rate_hw = data->rate_hw;
   683			rate = to_clk_divider(rate_hw);
   684			rate_ops = rate_hw->init->ops;
   685			rate->lock = lock;
   686			rate->reg = (u64)rate->reg + reg;
   687	
   688			if (rate->table) {
   689				const struct clk_div_table *clkt;
   690				int table_size = 0;
   691	
   692				for (clkt = rate->table; clkt->div; clkt++)
   693					table_size++;
   694				rate->width = order_base_2(table_size);
   695			}
   696		}
   697	
   698		*hw = clk_hw_register_composite(dev, data->name, data->parent_names,
   699						data->num_parents, mux_hw,
   700						mux_ops, rate_hw, rate_ops,
   701						gate_hw, gate_ops, data->flags);
   702	
   703		return PTR_ERR_OR_ZERO(*hw);
   704	}
   705	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From ye.zhang at rock-chips.com  Fri Dec  5 21:08:37 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Sat,  6 Dec 2025 13:08:37 +0800
Subject: [PATCH v2 1/8] dt-bindings: pinctrl: Add rk3506 pinctrl support
In-Reply-To: <20251206050844.402958-1-ye.zhang@rock-chips.com>
References: <20251206050844.402958-1-ye.zhang@rock-chips.com>
Message-ID: <20251206050844.402958-2-ye.zhang@rock-chips.com>

Add the compatible string for the rk3506 SoC.

Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
Reviewed-by: Heiko Stuebner <heiko at sntech.de>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
---
 Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
index 125af766b992..76e607281716 100644
--- a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
@@ -44,6 +44,7 @@ properties:
       - rockchip,rk3328-pinctrl
       - rockchip,rk3368-pinctrl
       - rockchip,rk3399-pinctrl
+      - rockchip,rk3506-pinctrl
       - rockchip,rk3528-pinctrl
       - rockchip,rk3562-pinctrl
       - rockchip,rk3568-pinctrl
-- 
2.34.1



From ye.zhang at rock-chips.com  Fri Dec  5 21:08:36 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Sat,  6 Dec 2025 13:08:36 +0800
Subject: [PATCH v2 0/8] pinctrl: rockchip: Add RK3506 and RV1126B pinctrl and RMIO support
Message-ID: <20251206050844.402958-1-ye.zhang@rock-chips.com>

This series adds pinctrl support for the Rockchip RK3506 and RV1126B SoC,
and adds support for RMIO (Rockchip Matrix I/O).

The series includes:
- RK3506 pinctrl driver implementation
- RV1126B pinctrl driver implementation
- RMIO controller binding and driver support
- GPIO driver update to support new version GPIO

Changes in v2:
- Added RV1126B pinctrl support (patches 3 and 4)
- Updated GPIO driver to support new version GPIO (patch 5)
- Added header file for RK3506 RMIO (patch 6)
- RMIO is now implemented as a separate pinctrl device (patches 7, 8)

Ye Zhang (8):
  dt-bindings: pinctrl: Add rk3506 pinctrl support
  pinctrl: rockchip: Add rk3506 pinctrl support
  dt-bindings: pinctrl: Add rv1126b pinctrl support
  pinctrl: rockchip: Add rv1126b pinctrl support
  gpio: rockchip: support new version GPIO
  dt-bindings: pinctrl: Add header for Rockchip RK3506 RMIO
  dt-bindings: pinctrl: rockchip: Add RMIO controller binding
  pinctrl: rockchip: add rmio support

 .../bindings/pinctrl/rockchip,pinctrl.yaml    |   11 +
 .../bindings/pinctrl/rockchip,rmio.yaml       |  130 ++
 drivers/gpio/gpio-rockchip.c                  |    2 +
 drivers/pinctrl/pinctrl-rockchip.c            | 1188 +++++++++++++++--
 drivers/pinctrl/pinctrl-rockchip.h            |   47 +
 .../pinctrl/rockchip,rk3506-rmio.h            |  143 ++
 6 files changed, 1427 insertions(+), 94 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml
 create mode 100644 include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h

-- 
2.34.1



From ye.zhang at rock-chips.com  Fri Dec  5 21:08:39 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Sat,  6 Dec 2025 13:08:39 +0800
Subject: [PATCH v2 3/8] dt-bindings: pinctrl: Add rv1126b pinctrl support
In-Reply-To: <20251206050844.402958-1-ye.zhang@rock-chips.com>
References: <20251206050844.402958-1-ye.zhang@rock-chips.com>
Message-ID: <20251206050844.402958-4-ye.zhang@rock-chips.com>

Add the compatible string for the rv1126b SoC.

Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
---
 Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
index 76e607281716..93bf8f352e48 100644
--- a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
@@ -52,6 +52,7 @@ properties:
       - rockchip,rk3588-pinctrl
       - rockchip,rv1108-pinctrl
       - rockchip,rv1126-pinctrl
+      - rockchip,rv1126b-pinctrl
 
   rockchip,grf:
     $ref: /schemas/types.yaml#/definitions/phandle
-- 
2.34.1



From ye.zhang at rock-chips.com  Fri Dec  5 21:08:40 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Sat,  6 Dec 2025 13:08:40 +0800
Subject: [PATCH v2 4/8] pinctrl: rockchip: Add rv1126b pinctrl support
In-Reply-To: <20251206050844.402958-1-ye.zhang@rock-chips.com>
References: <20251206050844.402958-1-ye.zhang@rock-chips.com>
Message-ID: <20251206050844.402958-5-ye.zhang@rock-chips.com>

Add support for the 8 rv1126b GPIO banks.

Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
---
 drivers/pinctrl/pinctrl-rockchip.c | 181 ++++++++++++++++++++++++++++-
 drivers/pinctrl/pinctrl-rockchip.h |   1 +
 2 files changed, 181 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index e44ef262beec..dc7ef12dfcb0 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -307,6 +307,20 @@
 #define RK3588_PIN_BANK_FLAGS(ID, PIN, LABEL, M, P)			\
 	PIN_BANK_IOMUX_FLAGS_PULL_FLAGS(ID, PIN, LABEL, M, M, M, M, P, P, P, P)
 
+#define PIN_BANK_IOMUX_4_OFFSET_DRV_8(id, pins, label, offset0,		\
+				      offset1, offset2, offset3)	\
+	PIN_BANK_IOMUX_FLAGS_OFFSET_DRV_FLAGS(id, pins, label,		\
+					      IOMUX_WIDTH_4BIT,		\
+					      IOMUX_WIDTH_4BIT,		\
+					      IOMUX_WIDTH_4BIT,		\
+					      IOMUX_WIDTH_4BIT,		\
+					      offset0, offset1,		\
+					      offset2, offset3,		\
+					      DRV_TYPE_IO_LEVEL_8_BIT,	\
+					      DRV_TYPE_IO_LEVEL_8_BIT,	\
+					      DRV_TYPE_IO_LEVEL_8_BIT,	\
+					      DRV_TYPE_IO_LEVEL_8_BIT)
+
 static struct regmap_config rockchip_regmap_config = {
 	.reg_bits = 32,
 	.val_bits = 32,
@@ -1701,6 +1715,136 @@ static int rv1126_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank,
 	return 0;
 }
 
+#define RV1126B_DRV_BITS_PER_PIN		8
+#define RV1126B_DRV_PINS_PER_REG		2
+#define RV1126B_DRV_GPIO0_A_OFFSET		0x100
+#define RV1126B_DRV_GPIO0_C_OFFSET		0x8120
+#define RV1126B_DRV_GPIO_OFFSET(GPION)		(0x8100 + GPION * 0x8040)
+
+static int rv1126b_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
+				       int pin_num, struct regmap **regmap,
+				       int *reg, u8 *bit)
+{
+	struct rockchip_pinctrl *info = bank->drvdata;
+
+	*regmap = info->regmap_base;
+	switch (bank->bank_num) {
+	case 0:
+		if (pin_num < 16)
+			*reg = RV1126B_DRV_GPIO0_A_OFFSET;
+		else
+			*reg = RV1126B_DRV_GPIO0_C_OFFSET - 0x20;
+		break;
+
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+	case 6:
+	case 7:
+		*reg = RV1126B_DRV_GPIO_OFFSET(bank->bank_num);
+		break;
+
+	default:
+		dev_err(info->dev, "unsupported bank_num %d\n", bank->bank_num);
+		break;
+	}
+
+	*reg += ((pin_num / RV1126B_DRV_PINS_PER_REG) * 4);
+	*bit = pin_num % RV1126B_DRV_PINS_PER_REG;
+	*bit *= RV1126B_DRV_BITS_PER_PIN;
+
+	return 0;
+}
+
+#define RV1126B_PULL_BITS_PER_PIN		2
+#define RV1126B_PULL_PINS_PER_REG		8
+#define RV1126B_PULL_GPIO0_A_OFFSET		0x300
+#define RV1126B_PULL_GPIO0_C_OFFSET		0x8308
+#define RV1126B_PULL_GPIO_OFFSET(GPION)		(0x8300 + GPION * 0x8010)
+
+static int rv1126b_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
+					int pin_num, struct regmap **regmap,
+					int *reg, u8 *bit)
+{
+	struct rockchip_pinctrl *info = bank->drvdata;
+
+	*regmap = info->regmap_base;
+	switch (bank->bank_num) {
+	case 0:
+		if (pin_num < 16)
+			*reg = RV1126B_PULL_GPIO0_A_OFFSET;
+		else
+			*reg = RV1126B_PULL_GPIO0_C_OFFSET - 0x8;
+		break;
+
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+	case 6:
+	case 7:
+		*reg = RV1126B_PULL_GPIO_OFFSET(bank->bank_num);
+		break;
+
+	default:
+		dev_err(info->dev, "unsupported bank_num %d\n", bank->bank_num);
+		break;
+	}
+
+	*reg += ((pin_num / RV1126B_PULL_PINS_PER_REG) * 4);
+	*bit = pin_num % RV1126B_PULL_PINS_PER_REG;
+	*bit *= RV1126B_PULL_BITS_PER_PIN;
+
+	return 0;
+}
+
+#define RV1126B_SMT_BITS_PER_PIN		1
+#define RV1126B_SMT_PINS_PER_REG		8
+#define RV1126B_SMT_GPIO0_A_OFFSET		0x500
+#define RV1126B_SMT_GPIO0_C_OFFSET		0x8508
+#define RV1126B_SMT_GPIO_OFFSET(GPION)		(0x8500 + GPION * 0x8010)
+
+static int rv1126b_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank,
+					   int pin_num,
+					   struct regmap **regmap,
+					   int *reg, u8 *bit)
+{
+	struct rockchip_pinctrl *info = bank->drvdata;
+
+	*regmap = info->regmap_base;
+	switch (bank->bank_num) {
+	case 0:
+		if (pin_num < 16)
+			*reg = RV1126B_SMT_GPIO0_A_OFFSET;
+		else
+			*reg = RV1126B_SMT_GPIO0_C_OFFSET - 0x8;
+		break;
+
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+	case 6:
+	case 7:
+		*reg = RV1126B_SMT_GPIO_OFFSET(bank->bank_num);
+		break;
+
+	default:
+		dev_err(info->dev, "unsupported bank_num %d\n", bank->bank_num);
+		break;
+	}
+
+	*reg += ((pin_num / RV1126B_SMT_PINS_PER_REG) * 4);
+	*bit = pin_num % RV1126B_SMT_PINS_PER_REG;
+	*bit *= RV1126B_SMT_BITS_PER_PIN;
+
+	return 0;
+}
+
 #define RK3308_SCHMITT_PINS_PER_REG		8
 #define RK3308_SCHMITT_BANK_STRIDE		16
 #define RK3308_SCHMITT_GRF_OFFSET		0x1a0
@@ -3071,7 +3215,8 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank,
 		rmask_bits = RK3588_DRV_BITS_PER_PIN;
 		ret = strength;
 		goto config;
-	} else if (ctrl->type == RK3506 ||
+	} else if (ctrl->type == RV1126B ||
+		   ctrl->type == RK3506 ||
 		   ctrl->type == RK3528 ||
 		   ctrl->type == RK3562 ||
 		   ctrl->type == RK3568) {
@@ -3237,6 +3382,7 @@ static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num)
 				: PIN_CONFIG_BIAS_DISABLE;
 	case PX30:
 	case RV1108:
+	case RV1126B:
 	case RK3188:
 	case RK3288:
 	case RK3308:
@@ -3299,6 +3445,7 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank,
 	case PX30:
 	case RV1108:
 	case RV1126:
+	case RV1126B:
 	case RK3188:
 	case RK3288:
 	case RK3308:
@@ -3582,6 +3729,7 @@ static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl,
 	case PX30:
 	case RV1108:
 	case RV1126:
+	case RV1126B:
 	case RK3188:
 	case RK3288:
 	case RK3308:
@@ -4386,6 +4534,35 @@ static struct rockchip_pin_ctrl rv1126_pin_ctrl = {
 	.schmitt_calc_reg	= rv1126_calc_schmitt_reg_and_bit,
 };
 
+static struct rockchip_pin_bank rv1126b_pin_banks[] = {
+	PIN_BANK_IOMUX_4_OFFSET_DRV_8(0, 32, "gpio0",
+				      0x0, 0x8, 0x8010, 0x8018),
+	PIN_BANK_IOMUX_4_OFFSET_DRV_8(1, 32, "gpio1",
+				      0x10020, 0x10028, 0x10030, 0x10038),
+	PIN_BANK_IOMUX_4_OFFSET_DRV_8(2, 32, "gpio2",
+				      0x18040, 0x18048, 0x18050, 0x18058),
+	PIN_BANK_IOMUX_4_OFFSET_DRV_8(3, 32, "gpio3",
+				      0x20060, 0x20068, 0x20070, 0x20078),
+	PIN_BANK_IOMUX_4_OFFSET_DRV_8(4, 32, "gpio4",
+				      0x28080, 0x28088, 0x28090, 0x28098),
+	PIN_BANK_IOMUX_4_OFFSET_DRV_8(5, 32, "gpio5",
+				      0x300a0, 0x300a8, 0x300b0, 0x300b8),
+	PIN_BANK_IOMUX_4_OFFSET_DRV_8(6, 32, "gpio6",
+				      0x380c0, 0x380c8, 0x380d0, 0x380d8),
+	PIN_BANK_IOMUX_4_OFFSET_DRV_8(7, 32, "gpio7",
+				      0x400e0, 0x400e8, 0x400f0, 0x400f8),
+};
+
+static struct rockchip_pin_ctrl rv1126b_pin_ctrl __maybe_unused = {
+	.pin_banks		= rv1126b_pin_banks,
+	.nr_banks		= ARRAY_SIZE(rv1126b_pin_banks),
+	.label			= "RV1126B-GPIO",
+	.type			= RV1126B,
+	.pull_calc_reg		= rv1126b_calc_pull_reg_and_bit,
+	.drv_calc_reg		= rv1126b_calc_drv_reg_and_bit,
+	.schmitt_calc_reg	= rv1126b_calc_schmitt_reg_and_bit,
+};
+
 static struct rockchip_pin_bank rk2928_pin_banks[] = {
 	PIN_BANK(0, 32, "gpio0"),
 	PIN_BANK(1, 32, "gpio1"),
@@ -4960,6 +5137,8 @@ static const struct of_device_id rockchip_pinctrl_dt_match[] = {
 		.data = &rv1108_pin_ctrl },
 	{ .compatible = "rockchip,rv1126-pinctrl",
 		.data = &rv1126_pin_ctrl },
+	{ .compatible = "rockchip,rv1126b-pinctrl",
+		.data = &rv1126b_pin_ctrl },
 	{ .compatible = "rockchip,rk2928-pinctrl",
 		.data = &rk2928_pin_ctrl },
 	{ .compatible = "rockchip,rk3036-pinctrl",
diff --git a/drivers/pinctrl/pinctrl-rockchip.h b/drivers/pinctrl/pinctrl-rockchip.h
index 4f4aff42a80a..fe18b62ed994 100644
--- a/drivers/pinctrl/pinctrl-rockchip.h
+++ b/drivers/pinctrl/pinctrl-rockchip.h
@@ -187,6 +187,7 @@ enum rockchip_pinctrl_type {
 	PX30,
 	RV1108,
 	RV1126,
+	RV1126B,
 	RK2928,
 	RK3066B,
 	RK3128,
-- 
2.34.1



From ye.zhang at rock-chips.com  Fri Dec  5 21:08:42 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Sat,  6 Dec 2025 13:08:42 +0800
Subject: [PATCH v2 6/8] dt-bindings: pinctrl: Add header for Rockchip RK3506 RMIO
In-Reply-To: <20251206050844.402958-1-ye.zhang@rock-chips.com>
References: <20251206050844.402958-1-ye.zhang@rock-chips.com>
Message-ID: <20251206050844.402958-7-ye.zhang@rock-chips.com>

Add header file with constants for RMIO pin and function IDs for the
Rockchip RK3506 SoC.

Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
---
 .../pinctrl/rockchip,rk3506-rmio.h            | 143 ++++++++++++++++++
 1 file changed, 143 insertions(+)
 create mode 100644 include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h

diff --git a/include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h b/include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h
new file mode 100644
index 000000000000..5d39690a0b28
--- /dev/null
+++ b/include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h
@@ -0,0 +1,143 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/*
+ * Copyright (c) 2025 Rockchip Electronics Co., Ltd.
+ */
+
+#ifndef __DT_BINDINGS_PINCTRL_ROCKCHIP_RK3506_RMIO_H
+#define __DT_BINDINGS_PINCTRL_ROCKCHIP_RK3506_RMIO_H
+
+/* RMIO pins definetion */
+#define RMIO_PIN0				0
+#define RMIO_PIN1				1
+#define RMIO_PIN2				2
+#define RMIO_PIN3				3
+#define RMIO_PIN4				4
+#define RMIO_PIN5				5
+#define RMIO_PIN6				6
+#define RMIO_PIN7				7
+#define RMIO_PIN8				8
+#define RMIO_PIN9				9
+#define RMIO_PIN10				10
+#define RMIO_PIN11				11
+#define RMIO_PIN12				12
+#define RMIO_PIN13				13
+#define RMIO_PIN14				14
+#define RMIO_PIN15				15
+#define RMIO_PIN16				16
+#define RMIO_PIN17				17
+#define RMIO_PIN18				18
+#define RMIO_PIN19				19
+#define RMIO_PIN20				20
+#define RMIO_PIN21				21
+#define RMIO_PIN22				22
+#define RMIO_PIN23				23
+#define RMIO_PIN24				24
+#define RMIO_PIN25				25
+#define RMIO_PIN26				26
+#define RMIO_PIN27				27
+#define RMIO_PIN28				28
+#define RMIO_PIN29				29
+#define RMIO_PIN30				30
+#define RMIO_PIN31				31
+
+/* RMIO function definetion */
+#define RMIO_UART1_TX			1
+#define RMIO_UART1_RX			2
+#define RMIO_UART2_TX			3
+#define RMIO_UART2_RX			4
+#define RMIO_UART3_TX			5
+#define RMIO_UART3_RX			6
+#define RMIO_UART3_CTSN			7
+#define RMIO_UART3_RTSN			8
+#define RMIO_UART4_TX			9
+#define RMIO_UART4_RX			10
+#define RMIO_UART4_CTSN			11
+#define RMIO_UART4_RTSN			12
+#define RMIO_MIPITE			13
+#define RMIO_CLK_32K			14
+#define RMIO_I2C0_SCL			15
+#define RMIO_I2C0_SDA			16
+#define RMIO_I2C1_SCL			17
+#define RMIO_I2C1_SDA			18
+#define RMIO_I2C2_SCL			19
+#define RMIO_I2C2_SDA			20
+#define RMIO_PDM_CLK0			21
+#define RMIO_PDM_SDI0			22
+#define RMIO_PDM_SDI1			23
+#define RMIO_PDM_SDI2			24
+#define RMIO_PDM_SDI3			25
+#define RMIO_CAN1_TX			26
+#define RMIO_CAN1_RX			27
+#define RMIO_CAN0_TX			28
+#define RMIO_CAN0_RX			29
+#define RMIO_PWM0_CH0			30
+#define RMIO_PWM0_CH1			31
+#define RMIO_PWM0_CH2			32
+#define RMIO_PWM0_CH3			33
+#define RMIO_PWM1_CH0			34
+#define RMIO_PWM1_CH1			35
+#define RMIO_PWM1_CH2			36
+#define RMIO_PWM1_CH3			37
+#define RMIO_PWM1_CH4			38
+#define RMIO_PWM1_CH5			39
+#define RMIO_PWM1_CH6			40
+#define RMIO_PWM1_CH7			41
+#define RMIO_TOUCH_KEY_DRIVE		42
+#define RMIO_TOUCH_KEY_IN0		43
+#define RMIO_TOUCH_KEY_IN1		44
+#define RMIO_TOUCH_KEY_IN2		45
+#define RMIO_TOUCH_KEY_IN3		46
+#define RMIO_TOUCH_KEY_IN4		47
+#define RMIO_TOUCH_KEY_IN5		48
+#define RMIO_TOUCH_KEY_IN6		49
+#define RMIO_TOUCH_KEY_IN7		50
+#define RMIO_SAI0_MCLK			51
+#define RMIO_SAI0_SCLK			52
+#define RMIO_SAI0_LRCK			53
+#define RMIO_SAI0_SDI0			54
+#define RMIO_SAI0_SDI1			55
+#define RMIO_SAI0_SDI2			56
+#define RMIO_SAI0_SDI3			57
+#define RMIO_SAI0_SDO			58
+#define RMIO_SAI1_MCLK			59
+#define RMIO_SAI1_SCLK			60
+#define RMIO_SAI1_LRCK			61
+#define RMIO_SAI1_SDI			62
+#define RMIO_SAI1_SDO0			63
+#define RMIO_SAI1_SDO1			64
+#define RMIO_SAI1_SDO2			65
+#define RMIO_SAI1_SDO3			66
+#define RMIO_SPI0_CLK			67
+#define RMIO_SPI0_MOSI			68
+#define RMIO_SPI0_MISO			69
+#define RMIO_SPI0_CSN0			70
+#define RMIO_SPI0_CSN1			71
+#define RMIO_SPI1_CLK			72
+#define RMIO_SPI1_MOSI			73
+#define RMIO_SPI1_MISO			74
+#define RMIO_SPI1_CSN0			75
+#define RMIO_SPI1_CSN1			76
+#define RMIO_WDT_TSADC_SHUT		77
+#define RMIO_PMU_SLEEP			78
+#define RMIO_CORE_POWER_OFF		79
+#define RMIO_SPDIF_TX			80
+#define RMIO_SPDIF_RX			81
+#define RMIO_PWM1_BIP_CNTR_A0		82
+#define RMIO_PWM1_BIP_CNTR_A1		83
+#define RMIO_PWM1_BIP_CNTR_A2		84
+#define RMIO_PWM1_BIP_CNTR_A3		85
+#define RMIO_PWM1_BIP_CNTR_A4		86
+#define RMIO_PWM1_BIP_CNTR_A5		87
+#define RMIO_PWM1_BIP_CNTR_B0		88
+#define RMIO_PWM1_BIP_CNTR_B1		89
+#define RMIO_PWM1_BIP_CNTR_B2		90
+#define RMIO_PWM1_BIP_CNTR_B3		91
+#define RMIO_PWM1_BIP_CNTR_B4		92
+#define RMIO_PWM1_BIP_CNTR_B5		93
+#define RMIO_PDM_CLK1			94
+#define RMIO_ETH_RMII0_PPSCLK		95
+#define RMIO_ETH_RMII0_PPSTRIG		96
+#define RMIO_ETH_RMII1_PPSCLK		97
+#define RMIO_ETH_RMII1_PPSTRIG		98
+
+#endif /* __DT_BINDINGS_PINCTRL_ROCKCHIP_RK3506_RMIO_H */
-- 
2.34.1



From ye.zhang at rock-chips.com  Fri Dec  5 21:08:43 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Sat,  6 Dec 2025 13:08:43 +0800
Subject: [PATCH v2 7/8] dt-bindings: pinctrl: rockchip: Add RMIO controller binding
In-Reply-To: <20251206050844.402958-1-ye.zhang@rock-chips.com>
References: <20251206050844.402958-1-ye.zhang@rock-chips.com>
Message-ID: <20251206050844.402958-8-ye.zhang@rock-chips.com>

Add device tree binding for the RMIO (Rockchip Matrix I/O) controller
which is a sub-device of the main pinctrl on some Rockchip SoCs.

Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
---
 .../bindings/pinctrl/rockchip,pinctrl.yaml    |   9 ++
 .../bindings/pinctrl/rockchip,rmio.yaml       | 130 ++++++++++++++++++
 2 files changed, 139 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml

diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
index 93bf8f352e48..01df0a51ff83 100644
--- a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
@@ -83,6 +83,15 @@ required:
   - rockchip,grf
 
 patternProperties:
+  "rmio[0-9]*$":
+    type: object
+
+    $ref: "/schemas/pinctrl/rockchip,rmio.yaml#"
+
+    description:
+      The RMIO (Rockchip Matrix I/O) controller node which functions as a
+      sub-device of the main pinctrl to handle flexible function routing.
+
   "gpio@[0-9a-f]+$":
     type: object
 
diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml b/Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml
new file mode 100644
index 000000000000..28ec5ad62061
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml
@@ -0,0 +1,130 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/rockchip,rmio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: RMIO (Rockchip Matrix I/O) Controller
+
+maintainers:
+  - Heiko Stuebner <heiko at sntech.de>
+
+description: |
+  The RMIO controller provides a flexible routing matrix that allows mapping
+  various internal peripheral functions (UART, SPI, PWM, etc.) to specific
+  physical pins. This block is typically a sub-block of the GRF
+  (General Register Files).
+
+properties:
+  compatible:
+    enum:
+      - rockchip,rmio
+
+  rockchip,grf:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      The phandle of the syscon node for the GRF registers.
+
+  rockchip,offset:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      The offset of the RMIO configuration registers within the GRF.
+
+  rockchip,pins-num:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      The number of physical pins supported by this RMIO instance.
+      Used for boundary checking and driver initialization.
+
+additionalProperties:
+  type: object
+  additionalProperties:
+    type: object
+    properties:
+      rockchip,rmio:
+        $ref: "/schemas/types.yaml#/definitions/uint32-matrix"
+        description: |
+          A list of pin-function pairs. The format is <pin_id function_id>.
+          - pin_id: The index of the RMIO pin (0 to pins-num - 1).
+          - function_id: The mux value selecting the peripheral function.
+        minItems: 1
+        items:
+          items:
+            - minimum: 0
+              maximum: 31
+              description:
+                RMIO Pin ID.
+            - minimum: 0
+              maximum: 98
+              description:
+                Function ID.
+
+    required:
+      - rockchip,rmio
+
+    additionalProperties: false
+
+  additionalProperties: false
+
+required:
+  - compatible
+  - rockchip,grf
+  - rockchip,offset
+  - rockchip,pins-num
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/pinctrl/rockchip.h>
+    #include <dt-bindings/pinctrl/rockchip,rk3506-rmio.h>
+
+    pinctrl {
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges;
+
+        rmio {
+            compatible = "rockchip,rmio";
+            rockchip,grf = <&grf_pmu>;
+            rockchip,offset = <0x80>;
+            rockchip,pins-num = <32>;
+
+            rmio-uart {
+                rmio_pin27_uart1_tx: rmio-pin27-uart1-tx {
+                    rockchip,rmio = <RMIO_PIN27 RMIO_UART1_TX>;
+                };
+
+                rmio_pin28_uart1_rx: rmio-pin28-uart1-rx {
+                    rockchip,rmio = <RMIO_PIN28 RMIO_UART1_RX>;
+                };
+            };
+        };
+
+        pcfg_pull_default: pcfg-pull-default {
+          bias-pull-pin-default;
+        };
+
+        rm {
+          rmio_pin27_pins: rmio-pin27-pins {
+            rockchip,pins = <1 RK_PC2 7 &pcfg-pull-default>;
+          };
+
+          rmio_pin28_pins: rmio-pin28-pins {
+            rockchip,pins = <1 RK_PC3 7 &pcfg-pull-default>;
+          };
+        };
+    };
+
+    uart1: serial at 20064000 {
+      compatible = "snps,dw-apb-uart";
+      reg = <0x20064000 0x400>;
+      interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+      clocks = <&mux_uart2>;
+      pinctrl-0 = <&rmio_pin27_pins &rmio_pin27_uart1_tx
+                   &rmio_pin28_pins &rmio_pin28_uart1_rx>;
+      pinctrl-names = "default";
+      reg-io-width = <1>;
+      reg-shift = <2>;
+    };
-- 
2.34.1



From ye.zhang at rock-chips.com  Fri Dec  5 21:08:38 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Sat,  6 Dec 2025 13:08:38 +0800
Subject: [PATCH v2 2/8] pinctrl: rockchip: Add rk3506 pinctrl support
In-Reply-To: <20251206050844.402958-1-ye.zhang@rock-chips.com>
References: <20251206050844.402958-1-ye.zhang@rock-chips.com>
Message-ID: <20251206050844.402958-3-ye.zhang@rock-chips.com>

Add support for the 5 rk3506 GPIO banks.

Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
Reviewed-by: Heiko Stuebner <heiko at sntech.de>
---
 drivers/pinctrl/pinctrl-rockchip.c | 442 ++++++++++++++++++++++++++++-
 drivers/pinctrl/pinctrl-rockchip.h |   4 +
 2 files changed, 438 insertions(+), 8 deletions(-)

diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index 7a68a6237649..e44ef262beec 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -105,6 +105,29 @@
 		.pull_type[3] = pull3,					\
 	}
 
+#define PIN_BANK_IOMUX_FLAGS_OFFSET_DRV_FLAGS(id, pins, label, iom0,	\
+					       iom1, iom2, iom3,	\
+					       offset0, offset1,	\
+					       offset2, offset3, drv0,	\
+					       drv1, drv2, drv3)	\
+	{								\
+		.bank_num	= id,					\
+		.nr_pins	= pins,					\
+		.name		= label,				\
+		.iomux		= {					\
+			{ .type = iom0, .offset = offset0 },		\
+			{ .type = iom1, .offset = offset1 },		\
+			{ .type = iom2, .offset = offset2 },		\
+			{ .type = iom3, .offset = offset3 },		\
+		},							\
+		.drv		= {					\
+			{ .drv_type = drv0, .offset = -1 },		\
+			{ .drv_type = drv1, .offset = -1 },		\
+			{ .drv_type = drv2, .offset = -1 },		\
+			{ .drv_type = drv3, .offset = -1 },		\
+		},							\
+	}
+
 #define PIN_BANK_DRV_FLAGS(id, pins, label, type0, type1, type2, type3) \
 	{								\
 		.bank_num	= id,					\
@@ -233,6 +256,35 @@
 		.pull_type[3] = pull3,					\
 	}
 
+#define PIN_BANK_IOMUX_FLAGS_OFFSET_DRV_FLAGS_PULL_FLAGS(id, pins,	\
+						label, iom0, iom1,	\
+						iom2, iom3, offset0,	\
+						offset1, offset2,	\
+						offset3, drv0, drv1,	\
+						drv2, drv3, pull0,	\
+						pull1, pull2, pull3)	\
+	{								\
+		.bank_num	= id,					\
+		.nr_pins	= pins,					\
+		.name		= label,				\
+		.iomux		= {					\
+			{ .type = iom0, .offset = offset0 },		\
+			{ .type = iom1, .offset = offset1 },		\
+			{ .type = iom2, .offset = offset2 },		\
+			{ .type = iom3, .offset = offset3 },		\
+		},							\
+		.drv		= {					\
+			{ .drv_type = drv0, .offset = -1 },		\
+			{ .drv_type = drv1, .offset = -1 },		\
+			{ .drv_type = drv2, .offset = -1 },		\
+			{ .drv_type = drv3, .offset = -1 },		\
+		},							\
+		.pull_type[0] = pull0,					\
+		.pull_type[1] = pull1,					\
+		.pull_type[2] = pull2,					\
+		.pull_type[3] = pull3,					\
+	}
+
 #define PIN_BANK_MUX_ROUTE_FLAGS(ID, PIN, FUNC, REG, VAL, FLAG)		\
 	{								\
 		.bank_num	= ID,					\
@@ -1120,6 +1172,13 @@ static int rockchip_get_mux(struct rockchip_pin_bank *bank, int pin)
 	else
 		regmap = info->regmap_base;
 
+	if (ctrl->type == RK3506) {
+		if (bank->bank_num == 1)
+			regmap = info->regmap_ioc1;
+		else if (bank->bank_num == 4)
+			return 0;
+	}
+
 	/* get basic quadrupel of mux registers and the correct reg inside */
 	mux_type = bank->iomux[iomux_num].type;
 	reg = bank->iomux[iomux_num].offset;
@@ -1239,6 +1298,13 @@ static int rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
 	else
 		regmap = info->regmap_base;
 
+	if (ctrl->type == RK3506) {
+		if (bank->bank_num == 1)
+			regmap = info->regmap_ioc1;
+		else if (bank->bank_num == 4)
+			return 0;
+	}
+
 	/* get basic quadrupel of mux registers and the correct reg inside */
 	mux_type = bank->iomux[iomux_num].type;
 	reg = bank->iomux[iomux_num].offset;
@@ -2003,6 +2069,262 @@ static int rk3399_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
 	return 0;
 }
 
+#define RK3506_DRV_BITS_PER_PIN		8
+#define RK3506_DRV_PINS_PER_REG		2
+#define RK3506_DRV_GPIO0_A_OFFSET	0x100
+#define RK3506_DRV_GPIO0_D_OFFSET	0x830
+#define RK3506_DRV_GPIO1_OFFSET		0x140
+#define RK3506_DRV_GPIO2_OFFSET		0x180
+#define RK3506_DRV_GPIO3_OFFSET		0x1c0
+#define RK3506_DRV_GPIO4_OFFSET		0x840
+
+static int rk3506_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
+					int pin_num, struct regmap **regmap,
+					int *reg, u8 *bit)
+{
+	struct rockchip_pinctrl *info = bank->drvdata;
+	int ret = 0;
+
+	switch (bank->bank_num) {
+	case 0:
+		*regmap = info->regmap_pmu;
+		if (pin_num > 24) {
+			ret = -EINVAL;
+		} else if (pin_num < 24) {
+			*reg = RK3506_DRV_GPIO0_A_OFFSET;
+		} else {
+			*reg = RK3506_DRV_GPIO0_D_OFFSET;
+			*bit = 3;
+
+			return 0;
+		}
+		break;
+
+	case 1:
+		*regmap = info->regmap_ioc1;
+		if (pin_num < 28)
+			*reg = RK3506_DRV_GPIO1_OFFSET;
+		else
+			ret = -EINVAL;
+		break;
+
+	case 2:
+		*regmap = info->regmap_base;
+		if (pin_num < 17)
+			*reg = RK3506_DRV_GPIO2_OFFSET;
+		else
+			ret = -EINVAL;
+		break;
+
+	case 3:
+		*regmap = info->regmap_base;
+		if (pin_num < 15)
+			*reg = RK3506_DRV_GPIO3_OFFSET;
+		else
+			ret = -EINVAL;
+		break;
+
+	case 4:
+		*regmap = info->regmap_base;
+		if (pin_num < 8 || pin_num > 11) {
+			ret = -EINVAL;
+		} else {
+			*reg = RK3506_DRV_GPIO4_OFFSET;
+			*bit = 10;
+
+			return 0;
+		}
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (ret) {
+		dev_err(info->dev, "unsupported bank_num %d pin_num %d\n", bank->bank_num, pin_num);
+
+		return ret;
+	}
+
+	*reg += ((pin_num / RK3506_DRV_PINS_PER_REG) * 4);
+	*bit = pin_num % RK3506_DRV_PINS_PER_REG;
+	*bit *= RK3506_DRV_BITS_PER_PIN;
+
+	return 0;
+}
+
+#define RK3506_PULL_BITS_PER_PIN	2
+#define RK3506_PULL_PINS_PER_REG	8
+#define RK3506_PULL_GPIO0_A_OFFSET	0x200
+#define RK3506_PULL_GPIO0_D_OFFSET	0x830
+#define RK3506_PULL_GPIO1_OFFSET	0x210
+#define RK3506_PULL_GPIO2_OFFSET	0x220
+#define RK3506_PULL_GPIO3_OFFSET	0x230
+#define RK3506_PULL_GPIO4_OFFSET	0x840
+
+static int rk3506_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
+					 int pin_num, struct regmap **regmap,
+					 int *reg, u8 *bit)
+{
+	struct rockchip_pinctrl *info = bank->drvdata;
+	int ret = 0;
+
+	switch (bank->bank_num) {
+	case 0:
+		*regmap = info->regmap_pmu;
+		if (pin_num > 24) {
+			ret = -EINVAL;
+		} else if (pin_num < 24) {
+			*reg = RK3506_PULL_GPIO0_A_OFFSET;
+		} else {
+			*reg = RK3506_PULL_GPIO0_D_OFFSET;
+			*bit = 5;
+
+			return 0;
+		}
+		break;
+
+	case 1:
+		*regmap = info->regmap_ioc1;
+		if (pin_num < 28)
+			*reg = RK3506_PULL_GPIO1_OFFSET;
+		else
+			ret = -EINVAL;
+		break;
+
+	case 2:
+		*regmap = info->regmap_base;
+		if (pin_num < 17)
+			*reg = RK3506_PULL_GPIO2_OFFSET;
+		else
+			ret = -EINVAL;
+		break;
+
+	case 3:
+		*regmap = info->regmap_base;
+		if (pin_num < 15)
+			*reg = RK3506_PULL_GPIO3_OFFSET;
+		else
+			ret = -EINVAL;
+		break;
+
+	case 4:
+		*regmap = info->regmap_base;
+		if (pin_num < 8 || pin_num > 11) {
+			ret = -EINVAL;
+		} else {
+			*reg = RK3506_PULL_GPIO4_OFFSET;
+			*bit = 13;
+
+			return 0;
+		}
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (ret) {
+		dev_err(info->dev, "unsupported bank_num %d pin_num %d\n", bank->bank_num, pin_num);
+
+		return ret;
+	}
+
+	*reg += ((pin_num / RK3506_PULL_PINS_PER_REG) * 4);
+	*bit = pin_num % RK3506_PULL_PINS_PER_REG;
+	*bit *= RK3506_PULL_BITS_PER_PIN;
+
+	return 0;
+}
+
+#define RK3506_SMT_BITS_PER_PIN		1
+#define RK3506_SMT_PINS_PER_REG		8
+#define RK3506_SMT_GPIO0_A_OFFSET	0x400
+#define RK3506_SMT_GPIO0_D_OFFSET	0x830
+#define RK3506_SMT_GPIO1_OFFSET		0x410
+#define RK3506_SMT_GPIO2_OFFSET		0x420
+#define RK3506_SMT_GPIO3_OFFSET		0x430
+#define RK3506_SMT_GPIO4_OFFSET		0x840
+
+static int rk3506_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank,
+					   int pin_num,
+					   struct regmap **regmap,
+					   int *reg, u8 *bit)
+{
+	struct rockchip_pinctrl *info = bank->drvdata;
+	int ret = 0;
+
+	switch (bank->bank_num) {
+	case 0:
+		*regmap = info->regmap_pmu;
+		if (pin_num > 24) {
+			ret = -EINVAL;
+		} else if (pin_num < 24) {
+			*reg = RK3506_SMT_GPIO0_A_OFFSET;
+		} else {
+			*reg = RK3506_SMT_GPIO0_D_OFFSET;
+			*bit = 9;
+
+			return 0;
+		}
+		break;
+
+	case 1:
+		*regmap = info->regmap_ioc1;
+		if (pin_num < 28)
+			*reg = RK3506_SMT_GPIO1_OFFSET;
+		else
+			ret = -EINVAL;
+		break;
+
+	case 2:
+		*regmap = info->regmap_base;
+		if (pin_num < 17)
+			*reg = RK3506_SMT_GPIO2_OFFSET;
+		else
+			ret = -EINVAL;
+		break;
+
+	case 3:
+		*regmap = info->regmap_base;
+		if (pin_num < 15)
+			*reg = RK3506_SMT_GPIO3_OFFSET;
+		else
+			ret = -EINVAL;
+		break;
+
+	case 4:
+		*regmap = info->regmap_base;
+		if (pin_num < 8 || pin_num > 11) {
+			ret = -EINVAL;
+		} else {
+			*reg = RK3506_SMT_GPIO4_OFFSET;
+			*bit = 8;
+
+			return 0;
+		}
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (ret) {
+		dev_err(info->dev, "unsupported bank_num %d pin_num %d\n", bank->bank_num, pin_num);
+
+		return ret;
+	}
+
+	*reg += ((pin_num / RK3506_SMT_PINS_PER_REG) * 4);
+	*bit = pin_num % RK3506_SMT_PINS_PER_REG;
+	*bit *= RK3506_SMT_BITS_PER_PIN;
+
+	return 0;
+}
+
 #define RK3528_DRV_BITS_PER_PIN		8
 #define RK3528_DRV_PINS_PER_REG		2
 #define RK3528_DRV_GPIO0_OFFSET		0x100
@@ -2749,7 +3071,8 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank,
 		rmask_bits = RK3588_DRV_BITS_PER_PIN;
 		ret = strength;
 		goto config;
-	} else if (ctrl->type == RK3528 ||
+	} else if (ctrl->type == RK3506 ||
+		   ctrl->type == RK3528 ||
 		   ctrl->type == RK3562 ||
 		   ctrl->type == RK3568) {
 		rmask_bits = RK3568_DRV_BITS_PER_PIN;
@@ -2828,12 +3151,37 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank,
 	case DRV_TYPE_IO_1V8_ONLY:
 		rmask_bits = RK3288_DRV_BITS_PER_PIN;
 		break;
+	case DRV_TYPE_IO_LEVEL_2_BIT:
+		ret = regmap_read(regmap, reg, &data);
+		if (ret)
+			return ret;
+		data >>= bit;
+
+		return data & 0x3;
+	case DRV_TYPE_IO_LEVEL_8_BIT:
+		ret = regmap_read(regmap, reg, &data);
+		if (ret)
+			return ret;
+		data >>= bit;
+		data &= (1 << 8) - 1;
+
+		ret = hweight8(data);
+		if (ret > 0)
+			return ret - 1;
+		else
+			return -EINVAL;
 	default:
 		dev_err(dev, "unsupported pinctrl drive type: %d\n", drv_type);
 		return -EINVAL;
 	}
 
 config:
+	if (ctrl->type == RK3506) {
+		if ((bank->bank_num == 0 && pin_num == 24) || bank->bank_num == 4) {
+			rmask_bits = 2;
+			ret = strength;
+		}
+	}
 	/* enable the write to the equivalent lower bits */
 	data = ((1 << rmask_bits) - 1) << (bit + 16);
 	rmask = data | (data >> 16);
@@ -2957,6 +3305,7 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank,
 	case RK3328:
 	case RK3368:
 	case RK3399:
+	case RK3506:
 	case RK3528:
 	case RK3562:
 	case RK3568:
@@ -3077,6 +3426,10 @@ static int rockchip_get_schmitt(struct rockchip_pin_bank *bank, int pin_num)
 		break;
 	}
 
+	if (ctrl->type == RK3506)
+		if ((bank->bank_num == 0 && pin_num == 24) ||  bank->bank_num == 4)
+			return data & 0x3;
+
 	return data & 0x1;
 }
 
@@ -3112,6 +3465,14 @@ static int rockchip_set_schmitt(struct rockchip_pin_bank *bank,
 		break;
 	}
 
+	if (ctrl->type == RK3506) {
+		if ((bank->bank_num == 0 && pin_num == 24) || bank->bank_num == 4) {
+			data = 0x3 << (bit + 16);
+			rmask = data | (data >> 16);
+			data |= ((enable ? 0x3 : 0) << bit);
+		}
+	}
+
 	return regmap_update_bits(regmap, reg, rmask, data);
 }
 
@@ -3227,6 +3588,7 @@ static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl,
 	case RK3328:
 	case RK3368:
 	case RK3399:
+	case RK3506:
 	case RK3528:
 	case RK3562:
 	case RK3568:
@@ -3880,13 +4242,10 @@ static int rockchip_pinctrl_probe(struct platform_device *pdev)
 	}
 
 	/* try to find the optional reference to the pmu syscon */
-	node = of_parse_phandle(np, "rockchip,pmu", 0);
-	if (node) {
-		info->regmap_pmu = syscon_node_to_regmap(node);
-		of_node_put(node);
-		if (IS_ERR(info->regmap_pmu))
-			return PTR_ERR(info->regmap_pmu);
-	}
+	info->regmap_pmu = syscon_regmap_lookup_by_phandle_optional(np, "rockchip,pmu");
+
+	/* try to find the optional reference to the ioc1 syscon */
+	info->regmap_ioc1 = syscon_regmap_lookup_by_phandle_optional(np, "rockchip,ioc1");
 
 	ret = rockchip_pinctrl_register(pdev, info);
 	if (ret)
@@ -4350,6 +4709,71 @@ static struct rockchip_pin_ctrl rk3399_pin_ctrl = {
 		.drv_calc_reg		= rk3399_calc_drv_reg_and_bit,
 };
 
+static struct rockchip_pin_bank rk3506_pin_banks[] = {
+	PIN_BANK_IOMUX_FLAGS_OFFSET_DRV_FLAGS_PULL_FLAGS(0, 32, "gpio0",
+				    IOMUX_WIDTH_4BIT | IOMUX_SOURCE_PMU,
+				    IOMUX_WIDTH_4BIT | IOMUX_SOURCE_PMU,
+				    IOMUX_WIDTH_4BIT | IOMUX_SOURCE_PMU,
+				    IOMUX_WIDTH_2BIT | IOMUX_SOURCE_PMU,
+				    0x0, 0x8, 0x10, 0x830,
+				    DRV_TYPE_IO_LEVEL_8_BIT,
+				    DRV_TYPE_IO_LEVEL_8_BIT,
+				    DRV_TYPE_IO_LEVEL_8_BIT,
+				    DRV_TYPE_IO_LEVEL_2_BIT,
+				    0, 0, 0, 1),
+	PIN_BANK_IOMUX_FLAGS_OFFSET_DRV_FLAGS(1, 32, "gpio1",
+				    IOMUX_WIDTH_4BIT,
+				    IOMUX_WIDTH_4BIT,
+				    IOMUX_WIDTH_4BIT,
+				    IOMUX_WIDTH_4BIT,
+				    0x20, 0x28, 0x30, 0x38,
+				    DRV_TYPE_IO_LEVEL_8_BIT,
+				    DRV_TYPE_IO_LEVEL_8_BIT,
+				    DRV_TYPE_IO_LEVEL_8_BIT,
+				    DRV_TYPE_IO_LEVEL_8_BIT),
+	PIN_BANK_IOMUX_FLAGS_OFFSET_DRV_FLAGS(2, 32, "gpio2",
+				    IOMUX_WIDTH_4BIT,
+				    IOMUX_WIDTH_4BIT,
+				    IOMUX_WIDTH_4BIT,
+				    IOMUX_WIDTH_4BIT,
+				    0x40, 0x48, 0x50, 0x58,
+				    DRV_TYPE_IO_LEVEL_8_BIT,
+				    DRV_TYPE_IO_LEVEL_8_BIT,
+				    DRV_TYPE_IO_LEVEL_8_BIT,
+				    DRV_TYPE_IO_LEVEL_8_BIT),
+	PIN_BANK_IOMUX_FLAGS_OFFSET_DRV_FLAGS(3, 32, "gpio3",
+				    IOMUX_WIDTH_4BIT,
+				    IOMUX_WIDTH_4BIT,
+				    IOMUX_WIDTH_4BIT,
+				    IOMUX_WIDTH_4BIT,
+				    0x60, 0x68, 0x70, 0x78,
+				    DRV_TYPE_IO_LEVEL_8_BIT,
+				    DRV_TYPE_IO_LEVEL_8_BIT,
+				    DRV_TYPE_IO_LEVEL_8_BIT,
+				    DRV_TYPE_IO_LEVEL_8_BIT),
+	PIN_BANK_IOMUX_FLAGS_OFFSET_DRV_FLAGS_PULL_FLAGS(4, 32, "gpio4",
+				    IOMUX_WIDTH_4BIT,
+				    IOMUX_WIDTH_4BIT,
+				    IOMUX_WIDTH_4BIT,
+				    IOMUX_WIDTH_4BIT,
+				    0x80, 0x88, 0x90, 0x98,
+				    DRV_TYPE_IO_LEVEL_2_BIT,
+				    DRV_TYPE_IO_LEVEL_2_BIT,
+				    DRV_TYPE_IO_LEVEL_2_BIT,
+				    DRV_TYPE_IO_LEVEL_2_BIT,
+				    1, 1, 1, 1),
+};
+
+static struct rockchip_pin_ctrl rk3506_pin_ctrl __maybe_unused = {
+	.pin_banks		= rk3506_pin_banks,
+	.nr_banks		= ARRAY_SIZE(rk3506_pin_banks),
+	.label			= "RK3506-GPIO",
+	.type			= RK3506,
+	.pull_calc_reg		= rk3506_calc_pull_reg_and_bit,
+	.drv_calc_reg		= rk3506_calc_drv_reg_and_bit,
+	.schmitt_calc_reg	= rk3506_calc_schmitt_reg_and_bit,
+};
+
 static struct rockchip_pin_bank rk3528_pin_banks[] = {
 	PIN_BANK_IOMUX_FLAGS_OFFSET(0, 32, "gpio0",
 				    IOMUX_WIDTH_4BIT,
@@ -4560,6 +4984,8 @@ static const struct of_device_id rockchip_pinctrl_dt_match[] = {
 		.data = &rk3368_pin_ctrl },
 	{ .compatible = "rockchip,rk3399-pinctrl",
 		.data = &rk3399_pin_ctrl },
+	{ .compatible = "rockchip,rk3506-pinctrl",
+		.data = &rk3506_pin_ctrl },
 	{ .compatible = "rockchip,rk3528-pinctrl",
 		.data = &rk3528_pin_ctrl },
 	{ .compatible = "rockchip,rk3562-pinctrl",
diff --git a/drivers/pinctrl/pinctrl-rockchip.h b/drivers/pinctrl/pinctrl-rockchip.h
index 35cd38079d1e..4f4aff42a80a 100644
--- a/drivers/pinctrl/pinctrl-rockchip.h
+++ b/drivers/pinctrl/pinctrl-rockchip.h
@@ -196,6 +196,7 @@ enum rockchip_pinctrl_type {
 	RK3328,
 	RK3368,
 	RK3399,
+	RK3506,
 	RK3528,
 	RK3562,
 	RK3568,
@@ -260,6 +261,8 @@ enum rockchip_pin_drv_type {
 	DRV_TYPE_IO_1V8_ONLY,
 	DRV_TYPE_IO_1V8_3V0_AUTO,
 	DRV_TYPE_IO_3V3_ONLY,
+	DRV_TYPE_IO_LEVEL_2_BIT,
+	DRV_TYPE_IO_LEVEL_8_BIT,
 	DRV_TYPE_MAX
 };
 
@@ -458,6 +461,7 @@ struct rockchip_pinctrl {
 	int				reg_size;
 	struct regmap			*regmap_pull;
 	struct regmap			*regmap_pmu;
+	struct regmap			*regmap_ioc1;
 	struct device			*dev;
 	struct rockchip_pin_ctrl	*ctrl;
 	struct pinctrl_desc		pctl;
-- 
2.34.1



From ye.zhang at rock-chips.com  Fri Dec  5 21:08:44 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Sat,  6 Dec 2025 13:08:44 +0800
Subject: [PATCH v2 8/8] pinctrl: rockchip: add rmio support
In-Reply-To: <20251206050844.402958-1-ye.zhang@rock-chips.com>
References: <20251206050844.402958-1-ye.zhang@rock-chips.com>
Message-ID: <20251206050844.402958-9-ye.zhang@rock-chips.com>

Support rockchip matrix io

Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
---
 drivers/pinctrl/pinctrl-rockchip.c | 397 ++++++++++++++++++++++++++++-
 drivers/pinctrl/pinctrl-rockchip.h |  42 +++
 2 files changed, 438 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index dc7ef12dfcb0..66bd4a981f62 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -3961,6 +3961,11 @@ static const struct of_device_id rockchip_bank_match[] = {
 	{},
 };
 
+static const struct of_device_id rockchip_rmio_dt_match[] = {
+	{ .compatible = "rockchip,rmio" },
+	{},
+};
+
 static void rockchip_pinctrl_child_count(struct rockchip_pinctrl *info,
 						struct device_node *np)
 {
@@ -3969,6 +3974,8 @@ static void rockchip_pinctrl_child_count(struct rockchip_pinctrl *info,
 	for_each_child_of_node(np, child) {
 		if (of_match_node(rockchip_bank_match, child))
 			continue;
+		if (of_match_node(rockchip_rmio_dt_match, child))
+			continue;
 
 		info->nfunctions++;
 		info->ngroups += of_get_child_count(child);
@@ -4101,6 +4108,8 @@ static int rockchip_pinctrl_parse_dt(struct platform_device *pdev,
 	for_each_child_of_node_scoped(np, child) {
 		if (of_match_node(rockchip_bank_match, child))
 			continue;
+		if (of_match_node(rockchip_rmio_dt_match, child))
+			continue;
 
 		ret = rockchip_pinctrl_parse_functions(child, info, i++);
 		if (ret) {
@@ -4431,6 +4440,384 @@ static void rockchip_pinctrl_remove(struct platform_device *pdev)
 	}
 }
 
+static int rockchip_rmio_set_mux(struct rockchip_rmio *info, int id, int func)
+{
+	struct device *dev = info->dev;
+
+	if (id >= info->nr_pins)
+		return -EINVAL;
+
+	dev_dbg(dev, "setting function of %s%d to %d\n", dev_name(dev), id, func);
+
+	return regmap_write(info->regmap, info->offset + id * 4,
+			    RK_RMIO_WRITE_ENABLE_MASK | func);
+}
+
+static int rockchip_rmio_parse_groups(struct device_node *np,
+				      struct rockchip_rmio_group *grp,
+				      struct rockchip_rmio *info,
+				      u32 index)
+{
+	struct device *dev = info->dev;
+	int count;
+	u32 *tmp;
+	int i;
+
+	dev_dbg(dev, "group(%d): %pOFn\n", index, np);
+
+	/*
+	 * the binding format is rockchip,rmio = <pin func>,
+	 * do sanity check and calculate pins number
+	 */
+	count = of_property_count_u32_elems(np, "rockchip,rmio");
+	if (count <= 0 || count % 2 != 0)
+		return -EINVAL;
+
+	tmp = kcalloc(count, sizeof(u32), GFP_KERNEL);
+	if (!tmp)
+		return -ENOMEM;
+
+	of_property_read_u32_array(np, "rockchip,rmio", tmp, count);
+
+	/* Initialise group */
+	grp->name = np->name;
+	grp->npins = count / 2;
+	grp->pins = devm_kcalloc(dev, grp->npins, sizeof(*grp->pins), GFP_KERNEL);
+	grp->func = devm_kcalloc(dev, grp->npins, sizeof(*grp->func), GFP_KERNEL);
+	if (!grp->pins || !grp->func)
+		return -ENOMEM;
+
+	for (i = 0; i < grp->npins; i++) {
+		grp->pins[i] = tmp[2 * i];
+		grp->func[i] = tmp[2 * i + 1];
+	}
+	kfree(tmp);
+
+	return 0;
+}
+
+static int rockchip_rmio_parse_functions(struct device_node *np,
+					 struct rockchip_rmio *info,
+					 u32 index)
+{
+	struct device *dev = info->dev;
+	struct device_node *child;
+	struct rockchip_rmio_func *func;
+	struct rockchip_rmio_group *grp;
+	int ret;
+	u32 i, grp_index = 0;
+
+	dev_dbg(dev, "parse function(%d): %pOFn\n", index, np);
+
+	for (i = 0, func = info->functions; i < index; i++, func++)
+		grp_index += func->ngroups;
+
+	func = &info->functions[index];
+
+	/* Initialise function */
+	func->name = np->name;
+	func->ngroups = of_get_child_count(np);
+	if (func->ngroups <= 0)
+		return 0;
+
+	func->groups = devm_kcalloc(dev, func->ngroups, sizeof(*func->groups), GFP_KERNEL);
+	if (!func->groups)
+		return -ENOMEM;
+
+	i = 0;
+	for_each_child_of_node(np, child) {
+		func->groups[i] = child->name;
+		grp = &info->groups[grp_index + i];
+		ret = rockchip_rmio_parse_groups(child, grp, info, i++);
+		if (ret) {
+			of_node_put(child);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int rockchip_rmio_parse_dt(struct platform_device *pdev,
+				  struct rockchip_rmio *info)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct device_node *child;
+	int ret;
+	int i = 0;
+
+	for_each_child_of_node(np, child) {
+		info->nfunctions++;
+		info->ngroups += of_get_child_count(child);
+	}
+
+	dev_dbg(dev, "nfunctions = %d\n", info->nfunctions);
+	dev_dbg(dev, "ngroups = %d\n", info->ngroups);
+
+	info->functions = devm_kcalloc(dev, info->nfunctions, sizeof(*info->functions), GFP_KERNEL);
+	if (!info->functions)
+		return -ENOMEM;
+
+	info->groups = devm_kcalloc(dev, info->ngroups, sizeof(*info->groups), GFP_KERNEL);
+	if (!info->groups)
+		return -ENOMEM;
+
+	for_each_child_of_node(np, child) {
+		ret = rockchip_rmio_parse_functions(child, info, i++);
+		if (ret) {
+			dev_err(dev, "failed to parse function, ret = %d\n", ret);
+			of_node_put(child);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int rockchip_rmio_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	struct rockchip_rmio *info = pinctrl_dev_get_drvdata(pctldev);
+
+	return info->ngroups;
+}
+
+static const char *rockchip_rmio_get_group_name(struct pinctrl_dev *pctldev,
+						unsigned int selector)
+{
+	struct rockchip_rmio *info = pinctrl_dev_get_drvdata(pctldev);
+
+	return info->groups[selector].name;
+}
+
+static int rockchip_rmio_get_group_pins(struct pinctrl_dev *pctldev,
+					unsigned int selector,
+					const unsigned int **pins,
+					unsigned int *npins)
+{
+	struct rockchip_rmio *info = pinctrl_dev_get_drvdata(pctldev);
+
+	if (selector >= info->ngroups)
+		return -EINVAL;
+
+	*pins = info->groups[selector].pins;
+	*npins = info->groups[selector].npins;
+
+	return 0;
+}
+
+static int rockchip_rmio_dt_node_to_map(struct pinctrl_dev *pctldev,
+					struct device_node *np,
+					struct pinctrl_map **map,
+					unsigned int *num_maps)
+{
+	struct rockchip_rmio *info = pinctrl_dev_get_drvdata(pctldev);
+	struct device *dev = info->dev;
+	struct pinctrl_map *new_map;
+	struct device_node *parent;
+
+	new_map = kcalloc(1, sizeof(*new_map), GFP_KERNEL);
+	if (!new_map)
+		return -ENOMEM;
+
+	*map = new_map;
+	*num_maps = 1;
+
+	/* the rmio only need to create mux map */
+	parent = of_get_parent(np);
+	if (!parent) {
+		kfree(new_map);
+		return -EINVAL;
+	}
+	new_map->type = PIN_MAP_TYPE_MUX_GROUP;
+	new_map->data.mux.function = parent->name;
+	new_map->data.mux.group = np->name;
+	of_node_put(parent);
+
+	dev_dbg(dev, "maps: function %s group %s\n",
+		(*map)->data.mux.function, (*map)->data.mux.group);
+
+	return 0;
+}
+
+static void rockchip_rmio_dt_free_map(struct pinctrl_dev *pctldev,
+				      struct pinctrl_map *map,
+				      unsigned int num_maps)
+{
+	kfree(map);
+}
+
+static const struct pinctrl_ops rockchip_rmio_pctrl_ops = {
+	.get_groups_count	= rockchip_rmio_get_groups_count,
+	.get_group_name		= rockchip_rmio_get_group_name,
+	.get_group_pins		= rockchip_rmio_get_group_pins,
+	.dt_node_to_map		= rockchip_rmio_dt_node_to_map,
+	.dt_free_map		= rockchip_rmio_dt_free_map,
+};
+
+static int rockchip_rmio_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+	struct rockchip_rmio *info = pinctrl_dev_get_drvdata(pctldev);
+
+	return info->nfunctions;
+}
+
+static const char *rockchip_rmio_get_func_name(struct pinctrl_dev *pctldev,
+					       unsigned int selector)
+{
+	struct rockchip_rmio *info = pinctrl_dev_get_drvdata(pctldev);
+
+	return info->functions[selector].name;
+}
+
+static int rockchip_rmio_get_groups(struct pinctrl_dev *pctldev,
+				    unsigned int selector,
+				    const char * const **groups,
+				    unsigned int * const num_groups)
+{
+	struct rockchip_rmio *info = pinctrl_dev_get_drvdata(pctldev);
+
+	*groups = info->functions[selector].groups;
+	*num_groups = info->functions[selector].ngroups;
+
+	return 0;
+}
+
+static int rockchip_rmio_pmx_set(struct pinctrl_dev *pctldev,
+				 unsigned int selector,
+				 unsigned int group)
+{
+	struct rockchip_rmio *info = pinctrl_dev_get_drvdata(pctldev);
+	const unsigned int *pins = info->groups[group].pins;
+	const unsigned int *func = info->groups[group].func;
+	struct device *dev = info->dev;
+	int cnt, ret = 0;
+
+	dev_dbg(dev, "enable function %s group %s\n",
+		info->functions[selector].name, info->groups[group].name);
+
+	/*
+	 * for each pin in the pin group selected, program the corresponding
+	 * pin function number in the config register.
+	 */
+	for (cnt = 0; cnt < info->groups[group].npins; cnt++) {
+		ret = rockchip_rmio_set_mux(info, pins[cnt], func[cnt]);
+		if (ret)
+			break;
+	}
+
+	if (ret && cnt) {
+		/* revert the already done pin settings */
+		for (cnt--; cnt >= 0; cnt--)
+			rockchip_rmio_set_mux(info, pins[cnt], RK_RMIO_NC);
+
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct pinmux_ops rockchip_rmio_pmx_ops = {
+	.get_functions_count	= rockchip_rmio_get_funcs_count,
+	.get_function_name	= rockchip_rmio_get_func_name,
+	.get_function_groups	= rockchip_rmio_get_groups,
+	.set_mux		= rockchip_rmio_pmx_set,
+};
+
+static int rockchip_rmio_register(struct platform_device *pdev,
+				  struct rockchip_rmio *info)
+{
+	struct pinctrl_desc *ctrldesc = &info->pctl;
+	struct pinctrl_pin_desc *pindesc, *pdesc;
+	struct device *dev = &pdev->dev;
+	char **pin_names;
+	int ret;
+	int i;
+	int nr_pins = info->nr_pins;
+
+	ctrldesc->name = dev_name(dev);
+	ctrldesc->owner = THIS_MODULE;
+	ctrldesc->pctlops = &rockchip_rmio_pctrl_ops;
+	ctrldesc->pmxops = &rockchip_rmio_pmx_ops;
+
+	pindesc = devm_kcalloc(dev, nr_pins, sizeof(*pindesc), GFP_KERNEL);
+	if (!pindesc)
+		return -ENOMEM;
+
+	ctrldesc->pins = pindesc;
+	ctrldesc->npins = nr_pins;
+
+	pdesc = pindesc;
+	pin_names = devm_kasprintf_strarray(dev, dev_name(dev), nr_pins);
+	if (IS_ERR(pin_names))
+		return PTR_ERR(pin_names);
+	for (i = 0; i < nr_pins; i++) {
+		pdesc->number = i;
+		pdesc->name = pin_names[i];
+		pdesc++;
+	}
+
+	ret = rockchip_rmio_parse_dt(pdev, info);
+	if (ret)
+		return ret;
+
+	info->pctl_dev = devm_pinctrl_register(dev, ctrldesc, info);
+	if (IS_ERR(info->pctl_dev))
+		return dev_err_probe(dev, PTR_ERR(info->pctl_dev),
+				     "could not register pinctrl driver\n");
+
+	return 0;
+}
+
+static int rockchip_rmio_probe(struct platform_device *pdev)
+{
+	struct rockchip_rmio *info;
+	struct device *dev = &pdev->dev;
+	struct device_node *np = pdev->dev.of_node;
+	int ret;
+
+	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->dev = dev;
+
+	info->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+	if (IS_ERR(info->regmap)) {
+		dev_err(&pdev->dev, "missing rockchip,grf property\n");
+		return PTR_ERR(info->regmap);
+	}
+
+	ret = of_property_read_u32(np, "rockchip,offset", &info->offset);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "missing rockchip,offset property\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(np, "rockchip,pins-num", &info->nr_pins);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "missing rockchip,pins-num property\n");
+		return ret;
+	}
+
+	ret = rockchip_rmio_register(pdev, info);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, info);
+	dev_info(dev, "probed %pfw\n", dev_fwnode(dev));
+
+	return 0;
+}
+
+static struct platform_driver rockchip_rmio_driver = {
+	.probe = rockchip_rmio_probe,
+	.driver = {
+		.name = "rockchip-rmio",
+		.of_match_table = rockchip_rmio_dt_match,
+	},
+};
+
 static struct rockchip_pin_bank px30_pin_banks[] = {
 	PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", IOMUX_SOURCE_PMU,
 					     IOMUX_SOURCE_PMU,
@@ -5190,12 +5577,19 @@ static struct platform_driver rockchip_pinctrl_driver = {
 
 static int __init rockchip_pinctrl_drv_register(void)
 {
-	return platform_driver_register(&rockchip_pinctrl_driver);
+	int ret;
+
+	ret = platform_driver_register(&rockchip_pinctrl_driver);
+	if (ret)
+		return ret;
+
+	return platform_driver_register(&rockchip_rmio_driver);
 }
 postcore_initcall(rockchip_pinctrl_drv_register);
 
 static void __exit rockchip_pinctrl_drv_unregister(void)
 {
+	platform_driver_unregister(&rockchip_rmio_driver);
 	platform_driver_unregister(&rockchip_pinctrl_driver);
 }
 module_exit(rockchip_pinctrl_drv_unregister);
@@ -5204,3 +5598,4 @@ MODULE_DESCRIPTION("ROCKCHIP Pin Controller Driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:pinctrl-rockchip");
 MODULE_DEVICE_TABLE(of, rockchip_pinctrl_dt_match);
+MODULE_DEVICE_TABLE(of, rockchip_rmio_dt_match);
diff --git a/drivers/pinctrl/pinctrl-rockchip.h b/drivers/pinctrl/pinctrl-rockchip.h
index fe18b62ed994..db875f7a3d2f 100644
--- a/drivers/pinctrl/pinctrl-rockchip.h
+++ b/drivers/pinctrl/pinctrl-rockchip.h
@@ -183,6 +183,9 @@
 #define RK_GPIO4_D6	158
 #define RK_GPIO4_D7	159
 
+#define RK_RMIO_NC			0
+#define RK_RMIO_WRITE_ENABLE_MASK	0xFFFF0000
+
 enum rockchip_pinctrl_type {
 	PX30,
 	RV1108,
@@ -473,4 +476,43 @@ struct rockchip_pinctrl {
 	unsigned int			nfunctions;
 };
 
+/**
+ * struct rockchip_rmio_group: represent a group of pins in RMIO controller.
+ * @name: name of the pin group, used to lookup the group.
+ * @pins: array of pins included in this group.
+ * @npins: number of pins included in this group.
+ * @func: local pins function select
+ */
+struct rockchip_rmio_group {
+	const char			*name;
+	unsigned int			npins;
+	unsigned int			*pins;
+	unsigned int			*func;
+};
+
+/**
+ * struct rockchip_rmio_func: represent a RMIO pin function.
+ * @name: name of the RMIO function, used to lookup the function.
+ * @groups: array of group names that can provide this RMIO function.
+ * @ngroups: number of groups included in @groups.
+ */
+struct rockchip_rmio_func {
+	const char		*name;
+	const char		**groups;
+	u8			ngroups;
+};
+
+struct rockchip_rmio {
+	struct regmap			*regmap;
+	u32				offset;
+	struct device			*dev;
+	struct pinctrl_desc		pctl;
+	struct pinctrl_dev		*pctl_dev;
+	unsigned int			nr_pins;
+	struct rockchip_rmio_group	*groups;
+	unsigned int			ngroups;
+	struct rockchip_rmio_func	*functions;
+	unsigned int			nfunctions;
+};
+
 #endif
-- 
2.34.1



From ye.zhang at rock-chips.com  Fri Dec  5 21:08:41 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Sat,  6 Dec 2025 13:08:41 +0800
Subject: [PATCH v2 5/8] gpio: rockchip: support new version GPIO
In-Reply-To: <20251206050844.402958-1-ye.zhang@rock-chips.com>
References: <20251206050844.402958-1-ye.zhang@rock-chips.com>
Message-ID: <20251206050844.402958-6-ye.zhang@rock-chips.com>

Support the next version GPIO controller on SoCs like rv1126b.

Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
---
 drivers/gpio/gpio-rockchip.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c
index 47174eb3ba76..c3e831c6bcf1 100644
--- a/drivers/gpio/gpio-rockchip.c
+++ b/drivers/gpio/gpio-rockchip.c
@@ -36,6 +36,7 @@
 #define GPIO_TYPE_V2		(0x01000C2B)
 #define GPIO_TYPE_V2_1		(0x0101157C)
 #define GPIO_TYPE_V2_2		(0x010219C8)
+#define GPIO_TYPE_V2_6          (0x01063F6E)
 
 static const struct rockchip_gpio_regs gpio_regs_v1 = {
 	.port_dr = 0x00,
@@ -674,6 +675,7 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank)
 	case GPIO_TYPE_V2:
 	case GPIO_TYPE_V2_1:
 	case GPIO_TYPE_V2_2:
+	case GPIO_TYPE_V2_6:
 		bank->gpio_regs = &gpio_regs_v2;
 		bank->gpio_type = GPIO_TYPE_V2;
 		bank->db_clk = of_clk_get(bank->of_node, 1);
-- 
2.34.1



From ye.zhang at rock-chips.com  Fri Dec  5 21:09:56 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Sat,  6 Dec 2025 13:09:56 +0800
Subject: [PATCH v2 0/8] pinctrl: rockchip: Add RK3506 and RV1126B pinctrl and RMIO support
Message-ID: <20251206051004.402991-1-ye.zhang@rock-chips.com>

This series adds pinctrl support for the Rockchip RK3506 and RV1126B SoC,
and adds support for RMIO (Rockchip Matrix I/O).

The series includes:
- RK3506 pinctrl driver implementation
- RV1126B pinctrl driver implementation
- RMIO controller binding and driver support
- GPIO driver update to support new version GPIO

Changes in v2:
- Added RV1126B pinctrl support (patches 3 and 4)
- Updated GPIO driver to support new version GPIO (patch 5)
- Added header file for RK3506 RMIO (patch 6)
- RMIO is now implemented as a separate pinctrl device (patches 7, 8)

Ye Zhang (8):
  dt-bindings: pinctrl: Add rk3506 pinctrl support
  pinctrl: rockchip: Add rk3506 pinctrl support
  dt-bindings: pinctrl: Add rv1126b pinctrl support
  pinctrl: rockchip: Add rv1126b pinctrl support
  gpio: rockchip: support new version GPIO
  dt-bindings: pinctrl: Add header for Rockchip RK3506 RMIO
  dt-bindings: pinctrl: rockchip: Add RMIO controller binding
  pinctrl: rockchip: add rmio support

 .../bindings/pinctrl/rockchip,pinctrl.yaml    |   11 +
 .../bindings/pinctrl/rockchip,rmio.yaml       |  130 ++
 drivers/gpio/gpio-rockchip.c                  |    2 +
 drivers/pinctrl/pinctrl-rockchip.c            | 1188 +++++++++++++++--
 drivers/pinctrl/pinctrl-rockchip.h            |   47 +
 .../pinctrl/rockchip,rk3506-rmio.h            |  143 ++
 6 files changed, 1427 insertions(+), 94 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml
 create mode 100644 include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h

-- 
2.34.1



From lkp at intel.com  Fri Dec  5 21:19:46 2025
From: lkp at intel.com (kernel test robot)
Date: Sat, 6 Dec 2025 13:19:46 +0800
Subject: [PATCH 3/8] spi: stm32-ospi: Remove CR_TCIE and CR_TEIE irq usage
In-Reply-To: <20251205-upstream_qspi_ospi_updates-v1-3-7e6c8b9f5141@foss.st.com>
References: <20251205-upstream_qspi_ospi_updates-v1-3-7e6c8b9f5141@foss.st.com>
Message-ID: <202512061327.9CDC4SNs-lkp@intel.com>

Hi Patrice,

kernel test robot noticed the following build errors:

[auto build test ERROR on 7d0a66e4bb9081d75c82ec4957c50034cb0ea449]

url:    https://github.com/intel-lab-lkp/linux/commits/Patrice-Chotard/spi-stm32-ospi-Set-DMA-maxburst-dynamically/20251205-174931
base:   7d0a66e4bb9081d75c82ec4957c50034cb0ea449
patch link:    https://lore.kernel.org/r/20251205-upstream_qspi_ospi_updates-v1-3-7e6c8b9f5141%40foss.st.com
patch subject: [PATCH 3/8] spi: stm32-ospi: Remove CR_TCIE and CR_TEIE irq usage
config: sparc64-randconfig-002-20251206 (https://download.01.org/0day-ci/archive/20251206/202512061327.9CDC4SNs-lkp at intel.com/config)
compiler: sparc64-linux-gcc (GCC) 8.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251206/202512061327.9CDC4SNs-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512061327.9CDC4SNs-lkp at intel.com/

All errors (new ones prefixed by >>):

   In file included from drivers/spi/spi-stm32-ospi.c:16:
   drivers/spi/spi-stm32-ospi.c: In function 'stm32_ospi_wait_cmd':
>> drivers/spi/spi-stm32-ospi.c:246:48: error: 'struct stm32_ospi' has no member named 'io_base'; did you mean 'mm_base'?
     err = readl_relaxed_poll_timeout_atomic(ospi->io_base + OSPI_SR, sr,
                                                   ^~~~~~~
   include/linux/iopoll.h:102:3: note: in definition of macro 'poll_timeout_us_atomic'
      op; \
      ^~
   include/linux/iopoll.h:213:2: note: in expansion of macro 'read_poll_timeout_atomic'
     read_poll_timeout_atomic(op, val, cond, delay_us, timeout_us, false, addr)
     ^~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/iopoll.h:255:2: note: in expansion of macro 'readx_poll_timeout_atomic'
     readx_poll_timeout_atomic(readl_relaxed, addr, val, cond, delay_us, timeout_us)
     ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/spi/spi-stm32-ospi.c:246:8: note: in expansion of macro 'readl_relaxed_poll_timeout_atomic'
     err = readl_relaxed_poll_timeout_atomic(ospi->io_base + OSPI_SR, sr,
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


vim +246 drivers/spi/spi-stm32-ospi.c

   236	
   237	static int stm32_ospi_wait_cmd(struct stm32_ospi *ospi)
   238	{
   239		void __iomem *regs_base = ospi->regs_base;
   240		u32 sr;
   241		int err = 0;
   242	
   243		if (ospi->fmode == CR_FMODE_APM)
   244			goto out;
   245	
 > 246		err = readl_relaxed_poll_timeout_atomic(ospi->io_base + OSPI_SR, sr,
   247							(sr & (SR_TEF | SR_TCF)), 1,
   248							STM32_WAIT_CMD_TIMEOUT_US);
   249	
   250		if (sr & SR_TCF)
   251			/* avoid false timeout */
   252			err = 0;
   253		if (sr & SR_TEF)
   254			err = -EIO;
   255	
   256	out:
   257		/* clear flags */
   258		writel_relaxed(FCR_CTCF | FCR_CTEF, regs_base + OSPI_FCR);
   259	
   260		if (!err)
   261			err = stm32_ospi_wait_nobusy(ospi);
   262	
   263		return err;
   264	}
   265	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From linux.amoon at gmail.com  Fri Dec  5 23:13:03 2025
From: linux.amoon at gmail.com (Anand Moon)
Date: Sat, 6 Dec 2025 12:43:03 +0530
Subject: [PATCH] arm64: dts: amlogic: meson-g12b: Fix L2 cache reference
 for S922X CPUs
In-Reply-To: <20251123-fixkhadas-v1-1-045348f0a4c2@baylibre.com>
References: <20251123-fixkhadas-v1-1-045348f0a4c2@baylibre.com>
Message-ID: <CANAwSgSqHR1kYxo8SaHcBfq=eij_YmVAidy8M+h1dFeK2nz1ug@mail.gmail.com>

Hi Guillaume,

On Sun, 23 Nov 2025 at 22:44, Guillaume La Roque <glaroque at baylibre.com> wrote:
>
> The original addition of cache information for the Amlogic S922X SoC
> used the wrong next-level cache node for CPU cores 100 and 101,
> incorrectly referencing `l2_cache_l`. These cores actually belong to
> the big cluster and should reference `l2_cache_b`. Update the device
> tree accordingly.
>
> Fixes: e7f85e6c155a ("arm64: dts: amlogic: Add cache information to the Amlogic S922X SoC")
> Signed-off-by: Guillaume La Roque <glaroque at baylibre.com>

Reviewed-by: Anand Moon <linux.amoon at gmail.com>

Thanks
-Anand
> ---
>  arch/arm64/boot/dts/amlogic/meson-g12b.dtsi | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi
> index f04efa828256..23358d94844c 100644
> --- a/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi
> +++ b/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi
> @@ -87,7 +87,7 @@ cpu100: cpu at 100 {
>                         i-cache-line-size = <32>;
>                         i-cache-size = <0x8000>;
>                         i-cache-sets = <32>;
> -                       next-level-cache = <&l2_cache_l>;
> +                       next-level-cache = <&l2_cache_b>;
>                         #cooling-cells = <2>;
>                 };
>
> @@ -103,7 +103,7 @@ cpu101: cpu at 101 {
>                         i-cache-line-size = <32>;
>                         i-cache-size = <0x8000>;
>                         i-cache-sets = <32>;
> -                       next-level-cache = <&l2_cache_l>;
> +                       next-level-cache = <&l2_cache_b>;
>                         #cooling-cells = <2>;
>                 };
>
>
> ---
> base-commit: 6a23ae0a96a600d1d12557add110e0bb6e32730c
> change-id: 20251123-fixkhadas-c84da7d7c47c
>
> Best regards,
> --
> Guillaume La Roque <glaroque at baylibre.com>
>


From lkp at intel.com  Fri Dec  5 23:18:20 2025
From: lkp at intel.com (kernel test robot)
Date: Sat, 6 Dec 2025 15:18:20 +0800
Subject: [PATCH 3/8] spi: stm32-ospi: Remove CR_TCIE and CR_TEIE irq usage
In-Reply-To: <20251205-upstream_qspi_ospi_updates-v1-3-7e6c8b9f5141@foss.st.com>
References: <20251205-upstream_qspi_ospi_updates-v1-3-7e6c8b9f5141@foss.st.com>
Message-ID: <202512061458.1wp2IbOG-lkp@intel.com>

Hi Patrice,

kernel test robot noticed the following build errors:

[auto build test ERROR on 7d0a66e4bb9081d75c82ec4957c50034cb0ea449]

url:    https://github.com/intel-lab-lkp/linux/commits/Patrice-Chotard/spi-stm32-ospi-Set-DMA-maxburst-dynamically/20251205-174931
base:   7d0a66e4bb9081d75c82ec4957c50034cb0ea449
patch link:    https://lore.kernel.org/r/20251205-upstream_qspi_ospi_updates-v1-3-7e6c8b9f5141%40foss.st.com
patch subject: [PATCH 3/8] spi: stm32-ospi: Remove CR_TCIE and CR_TEIE irq usage
config: riscv-randconfig-002-20251206 (https://download.01.org/0day-ci/archive/20251206/202512061458.1wp2IbOG-lkp at intel.com/config)
compiler: clang version 19.1.7 (https://github.com/llvm/llvm-project cd708029e0b2869e80abe31ddb175f7c35361f90)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251206/202512061458.1wp2IbOG-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512061458.1wp2IbOG-lkp at intel.com/

All errors (new ones prefixed by >>):

>> drivers/spi/spi-stm32-ospi.c:246:48: error: no member named 'io_base' in 'struct stm32_ospi'; did you mean 'mm_base'?
     246 |         err = readl_relaxed_poll_timeout_atomic(ospi->io_base + OSPI_SR, sr,
         |                                                       ^~~~~~~
         |                                                       mm_base
   include/linux/iopoll.h:255:43: note: expanded from macro 'readl_relaxed_poll_timeout_atomic'
     255 |         readx_poll_timeout_atomic(readl_relaxed, addr, val, cond, delay_us, timeout_us)
         |                                                  ^
   include/linux/iopoll.h:213:71: note: expanded from macro 'readx_poll_timeout_atomic'
     213 |         read_poll_timeout_atomic(op, val, cond, delay_us, timeout_us, false, addr)
         |                                                                              ^
   include/linux/iopoll.h:172:36: note: expanded from macro 'read_poll_timeout_atomic'
     172 |         poll_timeout_us_atomic((val) = op(args), cond, sleep_us, timeout_us, sleep_before_read)
         |                                           ^
   note: (skipping 1 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
   arch/riscv/include/asm/mmio.h:90:76: note: expanded from macro 'readl_cpu'
      90 | #define readl_cpu(c)            ({ u32 __r = le32_to_cpu((__force __le32)__raw_readl(c)); __r; })
         |                                                                                      ^
   include/uapi/linux/byteorder/little_endian.h:35:51: note: expanded from macro '__le32_to_cpu'
      35 | #define __le32_to_cpu(x) ((__force __u32)(__le32)(x))
         |                                                   ^
   include/linux/iopoll.h:102:3: note: expanded from macro 'poll_timeout_us_atomic'
     102 |                 op; \
         |                 ^
   drivers/spi/spi-stm32-ospi.c:124:16: note: 'mm_base' declared here
     124 |         void __iomem *mm_base;
         |                       ^
   1 error generated.


vim +246 drivers/spi/spi-stm32-ospi.c

   236	
   237	static int stm32_ospi_wait_cmd(struct stm32_ospi *ospi)
   238	{
   239		void __iomem *regs_base = ospi->regs_base;
   240		u32 sr;
   241		int err = 0;
   242	
   243		if (ospi->fmode == CR_FMODE_APM)
   244			goto out;
   245	
 > 246		err = readl_relaxed_poll_timeout_atomic(ospi->io_base + OSPI_SR, sr,
   247							(sr & (SR_TEF | SR_TCF)), 1,
   248							STM32_WAIT_CMD_TIMEOUT_US);
   249	
   250		if (sr & SR_TCF)
   251			/* avoid false timeout */
   252			err = 0;
   253		if (sr & SR_TEF)
   254			err = -EIO;
   255	
   256	out:
   257		/* clear flags */
   258		writel_relaxed(FCR_CTCF | FCR_CTEF, regs_base + OSPI_FCR);
   259	
   260		if (!err)
   261			err = stm32_ospi_wait_nobusy(ospi);
   262	
   263		return err;
   264	}
   265	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From maobibo at loongson.cn  Sat Dec  6 00:16:15 2025
From: maobibo at loongson.cn (Bibo Mao)
Date: Sat, 6 Dec 2025 16:16:15 +0800
Subject: [PATCH] KVM: Remove subtle "struct kvm_stats_desc" pseudo-overlay
In-Reply-To: <20251205232655.445294-1-seanjc@google.com>
References: <20251205232655.445294-1-seanjc@google.com>
Message-ID: <5a92dc4c-4d1c-544c-aee6-43432979c11a@loongson.cn>

Reviewed-by: Bibo Mao <maobibo at loongson.cn>

On 2025/12/6 ??7:26, Sean Christopherson wrote:
> Remove KVM's internal pseudo-overlay of kvm_stats_desc, which subtly
> aliases the flexible name[] in the uAPI definition with a fixed-size array
> of the same name.  The unusual embedded structure results in compiler
> warnings due to -Wflex-array-member-not-at-end, and also necessitates an
> extra level of dereferencing in KVM.  To avoid the "overlay", define the
> uAPI structure to have a fixed-size name when building for the kernel.
> 
> Opportunistically clean up the indentation for the stats macros, and
> replace spaces with tabs.
> 
> No functional change intended.
> 
> Reported-by: Gustavo A. R. Silva <gustavoars at kernel.org>
> Closes: https://lore.kernel.org/all/aPfNKRpLfhmhYqfP at kspp
> Signed-off-by: Sean Christopherson <seanjc at google.com>
> ---
> 
> Posting this as a standalone patch/email to make review and merging easier
> (assuming no one hates on the __KERNEL__ shenanigans).
>   
>   arch/arm64/kvm/guest.c    |  4 +-
>   arch/loongarch/kvm/vcpu.c |  2 +-
>   arch/loongarch/kvm/vm.c   |  2 +-
>   arch/mips/kvm/mips.c      |  4 +-
>   arch/powerpc/kvm/book3s.c |  4 +-
>   arch/powerpc/kvm/booke.c  |  4 +-
>   arch/riscv/kvm/vcpu.c     |  2 +-
>   arch/riscv/kvm/vm.c       |  2 +-
>   arch/s390/kvm/kvm-s390.c  |  4 +-
>   arch/x86/kvm/x86.c        |  4 +-
>   include/linux/kvm_host.h  | 83 +++++++++++++++++----------------------
>   include/uapi/linux/kvm.h  |  8 ++++
>   virt/kvm/binary_stats.c   |  2 +-
>   virt/kvm/kvm_main.c       | 20 +++++-----
>   14 files changed, 70 insertions(+), 75 deletions(-)
> 
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index 1c87699fd886..332c453b87cf 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -29,7 +29,7 @@
>   
>   #include "trace.h"
>   
> -const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
> +const struct kvm_stats_desc kvm_vm_stats_desc[] = {
>   	KVM_GENERIC_VM_STATS()
>   };
>   
> @@ -42,7 +42,7 @@ const struct kvm_stats_header kvm_vm_stats_header = {
>   		       sizeof(kvm_vm_stats_desc),
>   };
>   
> -const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
> +const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {
>   	KVM_GENERIC_VCPU_STATS(),
>   	STATS_DESC_COUNTER(VCPU, hvc_exit_stat),
>   	STATS_DESC_COUNTER(VCPU, wfe_exit_stat),
> diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
> index 6d833599ef2e..2bcbd27f1152 100644
> --- a/arch/loongarch/kvm/vcpu.c
> +++ b/arch/loongarch/kvm/vcpu.c
> @@ -13,7 +13,7 @@
>   #define CREATE_TRACE_POINTS
>   #include "trace.h"
>   
> -const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
> +const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {
>   	KVM_GENERIC_VCPU_STATS(),
>   	STATS_DESC_COUNTER(VCPU, int_exits),
>   	STATS_DESC_COUNTER(VCPU, idle_exits),
> diff --git a/arch/loongarch/kvm/vm.c b/arch/loongarch/kvm/vm.c
> index 194ccbcdc3b3..7deff56e0e1a 100644
> --- a/arch/loongarch/kvm/vm.c
> +++ b/arch/loongarch/kvm/vm.c
> @@ -10,7 +10,7 @@
>   #include <asm/kvm_eiointc.h>
>   #include <asm/kvm_pch_pic.h>
>   
> -const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
> +const struct kvm_stats_desc kvm_vm_stats_desc[] = {
>   	KVM_GENERIC_VM_STATS(),
>   	STATS_DESC_ICOUNTER(VM, pages),
>   	STATS_DESC_ICOUNTER(VM, hugepages),
> diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c
> index b0fb92fda4d4..23e69baad453 100644
> --- a/arch/mips/kvm/mips.c
> +++ b/arch/mips/kvm/mips.c
> @@ -38,7 +38,7 @@
>   #define VECTORSPACING 0x100	/* for EI/VI mode */
>   #endif
>   
> -const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
> +const struct kvm_stats_desc kvm_vm_stats_desc[] = {
>   	KVM_GENERIC_VM_STATS()
>   };
>   
> @@ -51,7 +51,7 @@ const struct kvm_stats_header kvm_vm_stats_header = {
>   		       sizeof(kvm_vm_stats_desc),
>   };
>   
> -const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
> +const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {
>   	KVM_GENERIC_VCPU_STATS(),
>   	STATS_DESC_COUNTER(VCPU, wait_exits),
>   	STATS_DESC_COUNTER(VCPU, cache_exits),
> diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
> index d79c5d1098c0..2efbe05caed7 100644
> --- a/arch/powerpc/kvm/book3s.c
> +++ b/arch/powerpc/kvm/book3s.c
> @@ -38,7 +38,7 @@
>   
>   /* #define EXIT_DEBUG */
>   
> -const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
> +const struct kvm_stats_desc kvm_vm_stats_desc[] = {
>   	KVM_GENERIC_VM_STATS(),
>   	STATS_DESC_ICOUNTER(VM, num_2M_pages),
>   	STATS_DESC_ICOUNTER(VM, num_1G_pages)
> @@ -53,7 +53,7 @@ const struct kvm_stats_header kvm_vm_stats_header = {
>   		       sizeof(kvm_vm_stats_desc),
>   };
>   
> -const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
> +const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {
>   	KVM_GENERIC_VCPU_STATS(),
>   	STATS_DESC_COUNTER(VCPU, sum_exits),
>   	STATS_DESC_COUNTER(VCPU, mmio_exits),
> diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
> index 3401b96be475..f3ddb24ece74 100644
> --- a/arch/powerpc/kvm/booke.c
> +++ b/arch/powerpc/kvm/booke.c
> @@ -36,7 +36,7 @@
>   
>   unsigned long kvmppc_booke_handlers;
>   
> -const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
> +const struct kvm_stats_desc kvm_vm_stats_desc[] = {
>   	KVM_GENERIC_VM_STATS(),
>   	STATS_DESC_ICOUNTER(VM, num_2M_pages),
>   	STATS_DESC_ICOUNTER(VM, num_1G_pages)
> @@ -51,7 +51,7 @@ const struct kvm_stats_header kvm_vm_stats_header = {
>   		       sizeof(kvm_vm_stats_desc),
>   };
>   
> -const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
> +const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {
>   	KVM_GENERIC_VCPU_STATS(),
>   	STATS_DESC_COUNTER(VCPU, sum_exits),
>   	STATS_DESC_COUNTER(VCPU, mmio_exits),
> diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c
> index a55a95da54d0..fdd99ac1e714 100644
> --- a/arch/riscv/kvm/vcpu.c
> +++ b/arch/riscv/kvm/vcpu.c
> @@ -24,7 +24,7 @@
>   #define CREATE_TRACE_POINTS
>   #include "trace.h"
>   
> -const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
> +const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {
>   	KVM_GENERIC_VCPU_STATS(),
>   	STATS_DESC_COUNTER(VCPU, ecall_exit_stat),
>   	STATS_DESC_COUNTER(VCPU, wfi_exit_stat),
> diff --git a/arch/riscv/kvm/vm.c b/arch/riscv/kvm/vm.c
> index 66d91ae6e9b2..715a06ae8c13 100644
> --- a/arch/riscv/kvm/vm.c
> +++ b/arch/riscv/kvm/vm.c
> @@ -13,7 +13,7 @@
>   #include <linux/kvm_host.h>
>   #include <asm/kvm_mmu.h>
>   
> -const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
> +const struct kvm_stats_desc kvm_vm_stats_desc[] = {
>   	KVM_GENERIC_VM_STATS()
>   };
>   static_assert(ARRAY_SIZE(kvm_vm_stats_desc) ==
> diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
> index 70dd9ce8cf2b..1cc90b8cf768 100644
> --- a/arch/s390/kvm/kvm-s390.c
> +++ b/arch/s390/kvm/kvm-s390.c
> @@ -65,7 +65,7 @@
>   #define VCPU_IRQS_MAX_BUF (sizeof(struct kvm_s390_irq) * \
>   			   (KVM_MAX_VCPUS + LOCAL_IRQS))
>   
> -const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
> +const struct kvm_stats_desc kvm_vm_stats_desc[] = {
>   	KVM_GENERIC_VM_STATS(),
>   	STATS_DESC_COUNTER(VM, inject_io),
>   	STATS_DESC_COUNTER(VM, inject_float_mchk),
> @@ -91,7 +91,7 @@ const struct kvm_stats_header kvm_vm_stats_header = {
>   		       sizeof(kvm_vm_stats_desc),
>   };
>   
> -const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
> +const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {
>   	KVM_GENERIC_VCPU_STATS(),
>   	STATS_DESC_COUNTER(VCPU, exit_userspace),
>   	STATS_DESC_COUNTER(VCPU, exit_null),
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 0c6d899d53dd..62ee4816e573 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -237,7 +237,7 @@ EXPORT_SYMBOL_FOR_KVM_INTERNAL(enable_ipiv);
>   bool __read_mostly enable_device_posted_irqs = true;
>   EXPORT_SYMBOL_FOR_KVM_INTERNAL(enable_device_posted_irqs);
>   
> -const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
> +const struct kvm_stats_desc kvm_vm_stats_desc[] = {
>   	KVM_GENERIC_VM_STATS(),
>   	STATS_DESC_COUNTER(VM, mmu_shadow_zapped),
>   	STATS_DESC_COUNTER(VM, mmu_pte_write),
> @@ -263,7 +263,7 @@ const struct kvm_stats_header kvm_vm_stats_header = {
>   		       sizeof(kvm_vm_stats_desc),
>   };
>   
> -const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
> +const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {
>   	KVM_GENERIC_VCPU_STATS(),
>   	STATS_DESC_COUNTER(VCPU, pf_taken),
>   	STATS_DESC_COUNTER(VCPU, pf_fixed),
> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> index d93f75b05ae2..7428d9949382 100644
> --- a/include/linux/kvm_host.h
> +++ b/include/linux/kvm_host.h
> @@ -1927,56 +1927,43 @@ enum kvm_stat_kind {
>   
>   struct kvm_stat_data {
>   	struct kvm *kvm;
> -	const struct _kvm_stats_desc *desc;
> +	const struct kvm_stats_desc *desc;
>   	enum kvm_stat_kind kind;
>   };
>   
> -struct _kvm_stats_desc {
> -	struct kvm_stats_desc desc;
> -	char name[KVM_STATS_NAME_SIZE];
> -};
> -
> -#define STATS_DESC_COMMON(type, unit, base, exp, sz, bsz)		       \
> -	.flags = type | unit | base |					       \
> -		 BUILD_BUG_ON_ZERO(type & ~KVM_STATS_TYPE_MASK) |	       \
> -		 BUILD_BUG_ON_ZERO(unit & ~KVM_STATS_UNIT_MASK) |	       \
> -		 BUILD_BUG_ON_ZERO(base & ~KVM_STATS_BASE_MASK),	       \
> -	.exponent = exp,						       \
> -	.size = sz,							       \
> +#define STATS_DESC_COMMON(type, unit, base, exp, sz, bsz)		\
> +	.flags = type | unit | base |					\
> +		 BUILD_BUG_ON_ZERO(type & ~KVM_STATS_TYPE_MASK) |       \
> +		 BUILD_BUG_ON_ZERO(unit & ~KVM_STATS_UNIT_MASK) |	\
> +		 BUILD_BUG_ON_ZERO(base & ~KVM_STATS_BASE_MASK),	\
> +	.exponent = exp,						\
> +	.size = sz,							\
>   	.bucket_size = bsz
>   
> -#define VM_GENERIC_STATS_DESC(stat, type, unit, base, exp, sz, bsz)	       \
> -	{								       \
> -		{							       \
> -			STATS_DESC_COMMON(type, unit, base, exp, sz, bsz),     \
> -			.offset = offsetof(struct kvm_vm_stat, generic.stat)   \
> -		},							       \
> -		.name = #stat,						       \
> -	}
> -#define VCPU_GENERIC_STATS_DESC(stat, type, unit, base, exp, sz, bsz)	       \
> -	{								       \
> -		{							       \
> -			STATS_DESC_COMMON(type, unit, base, exp, sz, bsz),     \
> -			.offset = offsetof(struct kvm_vcpu_stat, generic.stat) \
> -		},							       \
> -		.name = #stat,						       \
> -	}
> -#define VM_STATS_DESC(stat, type, unit, base, exp, sz, bsz)		       \
> -	{								       \
> -		{							       \
> -			STATS_DESC_COMMON(type, unit, base, exp, sz, bsz),     \
> -			.offset = offsetof(struct kvm_vm_stat, stat)	       \
> -		},							       \
> -		.name = #stat,						       \
> -	}
> -#define VCPU_STATS_DESC(stat, type, unit, base, exp, sz, bsz)		       \
> -	{								       \
> -		{							       \
> -			STATS_DESC_COMMON(type, unit, base, exp, sz, bsz),     \
> -			.offset = offsetof(struct kvm_vcpu_stat, stat)	       \
> -		},							       \
> -		.name = #stat,						       \
> -	}
> +#define VM_GENERIC_STATS_DESC(stat, type, unit, base, exp, sz, bsz)	\
> +{									\
> +	STATS_DESC_COMMON(type, unit, base, exp, sz, bsz),		\
> +	.offset = offsetof(struct kvm_vm_stat, generic.stat),		\
> +	.name = #stat,							\
> +}
> +#define VCPU_GENERIC_STATS_DESC(stat, type, unit, base, exp, sz, bsz)	\
> +{									\
> +	STATS_DESC_COMMON(type, unit, base, exp, sz, bsz),		\
> +	.offset = offsetof(struct kvm_vcpu_stat, generic.stat),		\
> +	.name = #stat,							\
> +}
> +#define VM_STATS_DESC(stat, type, unit, base, exp, sz, bsz)		\
> +{									\
> +	STATS_DESC_COMMON(type, unit, base, exp, sz, bsz),		\
> +	.offset = offsetof(struct kvm_vm_stat, stat),			\
> +	.name = #stat,							\
> +}
> +#define VCPU_STATS_DESC(stat, type, unit, base, exp, sz, bsz)		\
> +{									\
> +	STATS_DESC_COMMON(type, unit, base, exp, sz, bsz),		\
> +	.offset = offsetof(struct kvm_vcpu_stat, stat),			\
> +	.name = #stat,							\
> +}
>   /* SCOPE: VM, VM_GENERIC, VCPU, VCPU_GENERIC */
>   #define STATS_DESC(SCOPE, stat, type, unit, base, exp, sz, bsz)		       \
>   	SCOPE##_STATS_DESC(stat, type, unit, base, exp, sz, bsz)
> @@ -2053,7 +2040,7 @@ struct _kvm_stats_desc {
>   	STATS_DESC_IBOOLEAN(VCPU_GENERIC, blocking)
>   
>   ssize_t kvm_stats_read(char *id, const struct kvm_stats_header *header,
> -		       const struct _kvm_stats_desc *desc,
> +		       const struct kvm_stats_desc *desc,
>   		       void *stats, size_t size_stats,
>   		       char __user *user_buffer, size_t size, loff_t *offset);
>   
> @@ -2098,9 +2085,9 @@ static inline void kvm_stats_log_hist_update(u64 *data, size_t size, u64 value)
>   
>   
>   extern const struct kvm_stats_header kvm_vm_stats_header;
> -extern const struct _kvm_stats_desc kvm_vm_stats_desc[];
> +extern const struct kvm_stats_desc kvm_vm_stats_desc[];
>   extern const struct kvm_stats_header kvm_vcpu_stats_header;
> -extern const struct _kvm_stats_desc kvm_vcpu_stats_desc[];
> +extern const struct kvm_stats_desc kvm_vcpu_stats_desc[];
>   
>   #ifdef CONFIG_KVM_GENERIC_MMU_NOTIFIER
>   static inline int mmu_invalidate_retry(struct kvm *kvm, unsigned long mmu_seq)
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index dddb781b0507..76bd54848b11 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -14,6 +14,10 @@
>   #include <linux/ioctl.h>
>   #include <asm/kvm.h>
>   
> +#ifdef __KERNEL__
> +#include <linux/kvm_types.h>
> +#endif
> +
>   #define KVM_API_VERSION 12
>   
>   /*
> @@ -1579,7 +1583,11 @@ struct kvm_stats_desc {
>   	__u16 size;
>   	__u32 offset;
>   	__u32 bucket_size;
> +#ifdef __KERNEL__
> +	char name[KVM_STATS_NAME_SIZE];
> +#else
>   	char name[];
> +#endif
>   };
>   
>   #define KVM_GET_STATS_FD  _IO(KVMIO,  0xce)
> diff --git a/virt/kvm/binary_stats.c b/virt/kvm/binary_stats.c
> index eefca6c69f51..76ce697c773b 100644
> --- a/virt/kvm/binary_stats.c
> +++ b/virt/kvm/binary_stats.c
> @@ -50,7 +50,7 @@
>    * Return: the number of bytes that has been successfully read
>    */
>   ssize_t kvm_stats_read(char *id, const struct kvm_stats_header *header,
> -		       const struct _kvm_stats_desc *desc,
> +		       const struct kvm_stats_desc *desc,
>   		       void *stats, size_t size_stats,
>   		       char __user *user_buffer, size_t size, loff_t *offset)
>   {
> diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> index 74e1afd67b44..6ebf1936c8d4 100644
> --- a/virt/kvm/kvm_main.c
> +++ b/virt/kvm/kvm_main.c
> @@ -982,9 +982,9 @@ static void kvm_free_memslots(struct kvm *kvm, struct kvm_memslots *slots)
>   		kvm_free_memslot(kvm, memslot);
>   }
>   
> -static umode_t kvm_stats_debugfs_mode(const struct _kvm_stats_desc *pdesc)
> +static umode_t kvm_stats_debugfs_mode(const struct kvm_stats_desc *desc)
>   {
> -	switch (pdesc->desc.flags & KVM_STATS_TYPE_MASK) {
> +	switch (desc->flags & KVM_STATS_TYPE_MASK) {
>   	case KVM_STATS_TYPE_INSTANT:
>   		return 0444;
>   	case KVM_STATS_TYPE_CUMULATIVE:
> @@ -1019,7 +1019,7 @@ static int kvm_create_vm_debugfs(struct kvm *kvm, const char *fdname)
>   	struct dentry *dent;
>   	char dir_name[ITOA_MAX_LEN * 2];
>   	struct kvm_stat_data *stat_data;
> -	const struct _kvm_stats_desc *pdesc;
> +	const struct kvm_stats_desc *pdesc;
>   	int i, ret = -ENOMEM;
>   	int kvm_debugfs_num_entries = kvm_vm_stats_header.num_desc +
>   				      kvm_vcpu_stats_header.num_desc;
> @@ -6160,11 +6160,11 @@ static int kvm_stat_data_get(void *data, u64 *val)
>   	switch (stat_data->kind) {
>   	case KVM_STAT_VM:
>   		r = kvm_get_stat_per_vm(stat_data->kvm,
> -					stat_data->desc->desc.offset, val);
> +					stat_data->desc->offset, val);
>   		break;
>   	case KVM_STAT_VCPU:
>   		r = kvm_get_stat_per_vcpu(stat_data->kvm,
> -					  stat_data->desc->desc.offset, val);
> +					  stat_data->desc->offset, val);
>   		break;
>   	}
>   
> @@ -6182,11 +6182,11 @@ static int kvm_stat_data_clear(void *data, u64 val)
>   	switch (stat_data->kind) {
>   	case KVM_STAT_VM:
>   		r = kvm_clear_stat_per_vm(stat_data->kvm,
> -					  stat_data->desc->desc.offset);
> +					  stat_data->desc->offset);
>   		break;
>   	case KVM_STAT_VCPU:
>   		r = kvm_clear_stat_per_vcpu(stat_data->kvm,
> -					    stat_data->desc->desc.offset);
> +					    stat_data->desc->offset);
>   		break;
>   	}
>   
> @@ -6334,7 +6334,7 @@ static void kvm_uevent_notify_change(unsigned int type, struct kvm *kvm)
>   static void kvm_init_debug(void)
>   {
>   	const struct file_operations *fops;
> -	const struct _kvm_stats_desc *pdesc;
> +	const struct kvm_stats_desc *pdesc;
>   	int i;
>   
>   	kvm_debugfs_dir = debugfs_create_dir("kvm", NULL);
> @@ -6347,7 +6347,7 @@ static void kvm_init_debug(void)
>   			fops = &vm_stat_readonly_fops;
>   		debugfs_create_file(pdesc->name, kvm_stats_debugfs_mode(pdesc),
>   				kvm_debugfs_dir,
> -				(void *)(long)pdesc->desc.offset, fops);
> +				(void *)(long)pdesc->offset, fops);
>   	}
>   
>   	for (i = 0; i < kvm_vcpu_stats_header.num_desc; ++i) {
> @@ -6358,7 +6358,7 @@ static void kvm_init_debug(void)
>   			fops = &vcpu_stat_readonly_fops;
>   		debugfs_create_file(pdesc->name, kvm_stats_debugfs_mode(pdesc),
>   				kvm_debugfs_dir,
> -				(void *)(long)pdesc->desc.offset, fops);
> +				(void *)(long)pdesc->offset, fops);
>   	}
>   }
>   
> 
> base-commit: e0c26d47def7382d7dbd9cad58bc653aed75737a
> 



From christianshewitt at gmail.com  Sat Dec  6 00:28:06 2025
From: christianshewitt at gmail.com (Christian Hewitt)
Date: Sat,  6 Dec 2025 08:28:06 +0000
Subject: [PATCH DO-NOT-MERGE 1/4] media: rkvdec: minor fixes for current DETLEV patches
In-Reply-To: <20251206082809.2040679-1-christianshewitt@gmail.com>
References: <20251206082809.2040679-1-christianshewitt@gmail.com>
Message-ID: <20251206082809.2040679-2-christianshewitt@gmail.com>

RK3588 TRM Part 1 para 5.5.9 shows RKVDEC_SWREG12_SENCODARY_EN as
the register name so the 'secondary' typo looks maybe intentional,
but using correct spellings improves code readability.

RK3588 TRM Part 1 para 5.4.3 shows RKVDEC_1080P_PIXELS should use
1920x1088 (to be 4px aligned) not 1920x1080.

Also correct some H264 references in the H265 driver.

Signed-off-by: Christian Hewitt <christianshewitt at gmail.com>
---
 .../media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h    | 4 ++--
 .../media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c    | 6 +++---
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h
index 11b545e9ee7e..7cc6cbb8e549 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h
@@ -24,7 +24,7 @@
 
 #define MAX_SLICE_NUMBER	0x3fff
 
-#define RKVDEC_1080P_PIXELS		(1920 * 1080)
+#define RKVDEC_1080P_PIXELS		(1920 * 1088)
 #define RKVDEC_4K_PIXELS		(4096 * 2304)
 #define RKVDEC_8K_PIXELS		(7680 * 4320)
 #define RKVDEC_TIMEOUT_1080p		(0xefffff)
@@ -90,7 +90,7 @@ struct rkvdec_vdpu381_regs_common {
 		u32 reserved4			: 7;
 	} reg011;
 
-	struct rkvdec_vdpu381_sencodary_en {
+	struct rkvdec_vdpu381_secondary_en {
 		u32 wr_ddr_align_en		: 1;
 		u32 colmv_compress_en		: 1;
 		u32 fbc_e			: 1;
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c
index dd7481a4353d..b4fc0d423c16 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c
@@ -275,11 +275,11 @@ static void set_pps_ref_pic_poc(struct rkvdec_hevc_sps_pps *hw_ps, u32 poc, int
 static void assemble_hw_pps(struct rkvdec_ctx *ctx,
 			    struct rkvdec_hevc_run *run)
 {
-	struct rkvdec_hevc_ctx *h264_ctx = ctx->priv;
+	struct rkvdec_hevc_ctx *h265_ctx = ctx->priv;
 	const struct v4l2_ctrl_hevc_sps *sps = run->sps;
 	const struct v4l2_ctrl_hevc_pps *pps = run->pps;
 	const struct v4l2_ctrl_hevc_decode_params *dec_params = run->decode_params;
-	struct rkvdec_hevc_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu;
+	struct rkvdec_hevc_priv_tbl *priv_tbl = h265_ctx->priv_tbl.cpu;
 	struct rkvdec_hevc_sps_pps *hw_ps;
 	bool tiles_enabled;
 	s32 max_cu_width;
@@ -479,7 +479,7 @@ static void config_registers(struct rkvdec_ctx *ctx,
 
 	memset(regs, 0, sizeof(*regs));
 
-	/* Set H264 mode */
+	/* Set HEVC mode */
 	regs->common.reg008_dec_mode = VDPU383_MODE_HEVC;
 
 	/* Set input stream length */
-- 
2.34.1



From christianshewitt at gmail.com  Sat Dec  6 00:28:07 2025
From: christianshewitt at gmail.com (Christian Hewitt)
Date: Sat,  6 Dec 2025 08:28:07 +0000
Subject: [PATCH 2/4] media: dt-bindings: rockchip: Add RK3568 Video Decoder bindings
In-Reply-To: <20251206082809.2040679-1-christianshewitt@gmail.com>
References: <20251206082809.2040679-1-christianshewitt@gmail.com>
Message-ID: <20251206082809.2040679-3-christianshewitt@gmail.com>

The video decoder in RK356X (vdpu346) is described in the same way as
the one in RK3588 (vdpu381). A new compatible is added as the decoder
capabilities are a subset of the vdpu381 capabilities.

Signed-off-by: Christian Hewitt <christianshewitt at gmail.com>
---
nb: I've chosen to us rk3568-vdec not rk356x-vdec as other compatibles
for these chips are using rk3568.

 Documentation/devicetree/bindings/media/rockchip,vdec.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/media/rockchip,vdec.yaml b/Documentation/devicetree/bindings/media/rockchip,vdec.yaml
index 809fda45b3bd..656ceb1f116e 100644
--- a/Documentation/devicetree/bindings/media/rockchip,vdec.yaml
+++ b/Documentation/devicetree/bindings/media/rockchip,vdec.yaml
@@ -18,6 +18,7 @@ properties:
     oneOf:
       - const: rockchip,rk3288-vdec
       - const: rockchip,rk3399-vdec
+      - const: rockchip,rk3568-vdec
       - const: rockchip,rk3576-vdec
       - const: rockchip,rk3588-vdec
       - items:
@@ -107,6 +108,7 @@ allOf:
         compatible:
           contains:
             enum:
+              - rockchip,rk3568-vdec
               - rockchip,rk3576-vdec
               - rockchip,rk3588-vdec
     then:
-- 
2.34.1



From christianshewitt at gmail.com  Sat Dec  6 00:28:09 2025
From: christianshewitt at gmail.com (Christian Hewitt)
Date: Sat,  6 Dec 2025 08:28:09 +0000
Subject: [PATCH 4/4] arm64: dts: rockchip: Add the vdpu346 Video Decoders on RK356X
In-Reply-To: <20251206082809.2040679-1-christianshewitt@gmail.com>
References: <20251206082809.2040679-1-christianshewitt@gmail.com>
Message-ID: <20251206082809.2040679-5-christianshewitt@gmail.com>

Add the vdpu346 Video Decoders to the rk356x-base devicetree to
enable support on RK3566 and RK3568 boards. Also add the needed
sram and vdec_mmu nodes.

Suggested-by: Diederik de Haas <didi.debian at cknow.org>
Suggested-by: Piotr Oniszczuk <piotr.oniszczuk at gmail.com>
Signed-off-by: Christian Hewitt <christianshewitt at gmail.com>
---
 arch/arm64/boot/dts/rockchip/rk356x-base.dtsi | 49 +++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi b/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
index c005135089d4..c51179e13657 100644
--- a/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
@@ -383,6 +383,19 @@ usb2phy1_grf: syscon at fdca8000 {
 		reg = <0x0 0xfdca8000 0x0 0x8000>;
 	};
 
+	sram at fdcc0000 {
+		compatible = "mmio-sram";
+		reg = <0x0 0xfdcc0000 0x0 0xb000>;
+		ranges = <0x0 0x0 0xfdcc0000 0xb000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		vdec_sram: rkvdec-sram at 0 {
+			reg = <0x0 0xb000>;
+			pool;
+		};
+	};
+
 	pmucru: clock-controller at fdd00000 {
 		compatible = "rockchip,rk3568-pmucru";
 		reg = <0x0 0xfdd00000 0x0 0x1000>;
@@ -619,6 +632,42 @@ vepu_mmu: iommu at fdee0800 {
 		#iommu-cells = <0>;
 	};
 
+	vdec: video-codec at fdf80100 {
+		compatible = "rockchip,rk3568-vdec";
+		reg = <0x0 0xfdf80200 0x0 0x500>,
+		      <0x0 0xfdf80100 0x0 0x100>,
+		      <0x0 0xfdf80700 0x0 0x100>;
+		reg-names = "function", "link", "cache";
+		interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru ACLK_RKVDEC>, <&cru HCLK_RKVDEC>,
+			 <&cru CLK_RKVDEC_CA>, <&cru CLK_RKVDEC_CORE>,
+			 <&cru CLK_RKVDEC_HEVC_CA>;
+		clock-names = "axi", "ahb", "cabac", "core", "hevc_cabac";
+		assigned-clocks = <&cru ACLK_RKVDEC>,
+				  <&cru CLK_RKVDEC_CORE>,
+				  <&cru CLK_RKVDEC_CA>,
+				  <&cru CLK_RKVDEC_HEVC_CA>;
+		assigned-clock-rates = <297000000>, <297000000>,
+				       <297000000>, <600000000>;
+		iommus = <&vdec_mmu>;
+		power-domains = <&power RK3568_PD_RKVDEC>;
+		resets = <&cru SRST_A_RKVDEC>, <&cru SRST_H_RKVDEC>,
+			 <&cru SRST_RKVDEC_CA>, <&cru SRST_RKVDEC_CORE>,
+			 <&cru SRST_RKVDEC_HEVC_CA>;
+		reset-names = "axi", "ahb", "cabac", "core", "hevc_cabac";
+		sram = <&vdec_sram>;
+	};
+
+	vdec_mmu: iommu at fdf80800 {
+		compatible = "rockchip,rk3568-iommu";
+		reg = <0x0 0xfdf80800 0x0 0x40>, <0x0 0xfdf80840 0x0 0x40>;
+		interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru ACLK_RKVDEC>, <&cru HCLK_RKVDEC>;
+		clock-names = "aclk", "iface";
+		power-domains = <&power RK3568_PD_RKVDEC>;
+		#iommu-cells = <0>;
+	};
+
 	sdmmc2: mmc at fe000000 {
 		compatible = "rockchip,rk3568-dw-mshc", "rockchip,rk3288-dw-mshc";
 		reg = <0x0 0xfe000000 0x0 0x4000>;
-- 
2.34.1



From wbg at kernel.org  Sat Dec  6 01:34:17 2025
From: wbg at kernel.org (William Breathitt Gray)
Date: Sat,  6 Dec 2025 18:34:17 +0900
Subject: [PATCH v3 4/5] counter: Add rockchip-pwm-capture driver
In-Reply-To: <20251027-rk3576-pwm-v3-4-654a5cb1e3f8@collabora.com>
References: <20251027-rk3576-pwm-v3-4-654a5cb1e3f8@collabora.com>
Message-ID: <20251206093419.40067-1-wbg@kernel.org>

> +struct rockchip_pwm_capture {
> +	struct rockchip_mfpwm_func *pwmf;
> +	struct counter_device *counter;

Is this structure member used at all? If not, you should just remove it.

> +	bool is_enabled;

Does this device offer some way to probe whether PWM capture mode is
enabled? I suspect so, because I see PWM_ENABLE.pwm_en enables the
channel and PWM_CTRL.pwm_mode selects capture mode, so perhaps we're
able to read the current state of those registers. If you're able to
read those registers to determine the enable state, I'd suggest wrapping
that into a helper function and calling it when you need to determine
whether the capture mode is currently enabled.

If we're not able to probe the enable state, is it safe to assume we're
in a disabled state when the module loads, or should we ensure it by
unconditionally disabling PWM capture mode during
rockchip_pwm_capture_probe()?

> +	spinlock_t enable_lock;
> +};
> +
> +/*
> + * Channel 0 receives a state changed notification whenever the LPC interrupt
> + * fires.
> + *
> + * Channel 1 receives a state changed notification whenever the HPC interrupt
> + * fires.
> + */
> +static struct counter_signal rkpwmc_signals[] = {
> +	{
> +		.id = 0,
> +		.name = "Channel 0"
> +	},
> +	{
> +		.id = 1,
> +		.name = "Channel 1"
> +	},
> +};

>From "31.3.1 Capture Mode" of the Rockchip RK3506 Technical Reference
Manual[^1], it looks like "clk_pwm" is the only signal that is counted
for PWM_HPC AND PWM_LPC. So instead of two Signals, you would have just
one Signal named "PWM Clock" which sources your two Synapses defined below.

Technically, "pwm_in" is also a signal evaluated (its polarity is used
to determine whether we're counting for PWM_HPC or PWM_LPC) but the
respective Synapse would be COUNTER_SYNAPSE_ACTION_NONE because this
signal not actually triggering the change in the count value. You're
welcome to add the "pwm_in" signal here if you like, but I'd say it's
optional if you actually want to expose it here.

> +static const enum counter_synapse_action rkpwmc_hpc_lpc_actions[] = {
> +	COUNTER_SYNAPSE_ACTION_BOTH_EDGES,
> +
> +};

Add COUNTER_SYNAPSE_ACTION_NONE to this array. When the polarity is
high, the Synapse for PWM_HPC will be active with
COUNTER_SYNAPSE_ACTION_BOTH_EDGES, while the Synapse for PWM_LPC will be
inactive with COUNTER_SYNAPSE_ACTION_NONE; the inverse occurs when the
polarity switches to low.

> +static struct counter_synapse rkpwmc_pwm_synapses[] = {
> +	{
> +		.actions_list = rkpwmc_hpc_lpc_actions,
> +		.num_actions = ARRAY_SIZE(rkpwmc_hpc_lpc_actions),
> +		.signal = &rkpwmc_signals[0]
> +	},
> +	{
> +		.actions_list = rkpwmc_hpc_lpc_actions,
> +		.num_actions = ARRAY_SIZE(rkpwmc_hpc_lpc_actions),
> +		.signal = &rkpwmc_signals[1]
> +	},
> +};

Both Synapses are sourced by the same single Signal ("PWM Clock") so set
both "signal" members to &rkpwmc_signals[0].

> +enum rkpwmc_count_id {
> +	COUNT_LPC = 0,
> +	COUNT_HPC = 1,
> +};
> +
> +static struct counter_count rkpwmc_counts[] = {
> +	{
> +		.id = COUNT_LPC,
> +		.name = "PWM core clock cycles during which the signal was low",
> +		.functions_list = rkpwmc_functions,
> +		.num_functions = ARRAY_SIZE(rkpwmc_functions),
> +		.synapses = rkpwmc_pwm_synapses,
> +		.num_synapses = ARRAY_SIZE(rkpwmc_pwm_synapses),
> +		.ext = rkpwmc_ext,
> +		.num_ext = ARRAY_SIZE(rkpwmc_ext),
> +	},
> +	{
> +		.id = COUNT_HPC,
> +		.name = "PWM core clock cycles during which the signal was high",
> +		.functions_list = rkpwmc_functions,
> +		.num_functions = ARRAY_SIZE(rkpwmc_functions),
> +		.synapses = rkpwmc_pwm_synapses,
> +		.num_synapses = ARRAY_SIZE(rkpwmc_pwm_synapses),
> +		.ext = rkpwmc_ext,
> +		.num_ext = ARRAY_SIZE(rkpwmc_ext),
> +	},
> +};

Count names should be short and descriptive. I think the RK3506 manual
section "31.4.2 Registers Summary" description for the PWM_HPC and
PWM_LPC register do a pretty good job of that:

* Low Polarity Capture
* High Polarity Capture

How about changing the two Count names to those respectively?

> +static int rkpwmc_count_read(struct counter_device *counter,
> +			     struct counter_count *count, u64 *value)
> +{
> +	struct rockchip_pwm_capture *pc = counter_priv(counter);
> +
> +	guard(spinlock)(&pc->enable_lock);
> +
> +	if (!pc->is_enabled) {
> +		*value = 0;
> +		return 0;
> +	}

I don't think there's a need to check whether capture mode is disabled.
The user should be aware of the enable state of the Count by checking
the respective "enable" attribute; and if they ignore that, a value of
"0" doesn't inherently tell them that the Count is disabled which makes
it moot to do so. I'd suggest just removing this check entirely and
returning the register values unconditionally.

> +
> +	switch (count->id) {
> +	case COUNT_LPC:
> +		*value = mfpwm_reg_read(pc->pwmf->base, PWMV4_REG_LPC);
> +		return 0;
> +	case COUNT_HPC:
> +		*value = mfpwm_reg_read(pc->pwmf->base, PWMV4_REG_HPC);
> +		return 0;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static const struct counter_ops rkpwmc_ops = {
> +	.count_read = rkpwmc_count_read,
> +};

You should implement a signal_read() callback if its possible to probe
the current state of PWM Clock. You should implement action_read() if
its possible to probe the current polarity of "pwm_in" in order to set
which Synapse is currently active.

William Breathitt Gray

[^1] https://opensource.rock-chips.com/images/3/36/Rockchip_RK3506_TRM_Part_1_V1.2-20250811.pdf


From christianshewitt at gmail.com  Sat Dec  6 00:28:08 2025
From: christianshewitt at gmail.com (Christian Hewitt)
Date: Sat,  6 Dec 2025 08:28:08 +0000
Subject: [PATCH 3/4] media: rkvdec: Add support for the VDPU346 variant
In-Reply-To: <20251206082809.2040679-1-christianshewitt@gmail.com>
References: <20251206082809.2040679-1-christianshewitt@gmail.com>
Message-ID: <20251206082809.2040679-4-christianshewitt@gmail.com>

VDPU346 is derived from VDPU381 but with a single core and limited
to 4K60 media. It is also limited to H264 L5.1 and omits AV1 and
AVS2 capabilities. It is used with RK3566 and RK3568.

Signed-off-by: Christian Hewitt <christianshewitt at gmail.com>
---
 .../media/platform/rockchip/rkvdec/rkvdec.c   | 110 ++++++++++++++++++
 1 file changed, 110 insertions(+)

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index a1c02ef3a97c..cf68454b2217 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -295,6 +295,62 @@ static const struct rkvdec_ctrls rkvdec_h264_ctrls = {
 	.num_ctrls = ARRAY_SIZE(rkvdec_h264_ctrl_descs),
 };
 
+static const struct rkvdec_ctrl_desc vdpu346_hevc_ctrl_descs[] = {
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_SPS,
+		.cfg.ops = &rkvdec_ctrl_ops,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_PPS,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_MODE,
+		.cfg.min = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
+		.cfg.max = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
+		.cfg.def = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_START_CODE,
+		.cfg.min = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
+		.cfg.def = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
+		.cfg.max = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
+	},
+	{
+		.cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
+		.cfg.min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
+		.cfg.max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
+		.cfg.menu_skip_mask =
+			BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE),
+		.cfg.def = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
+	},
+	{
+		.cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
+		.cfg.min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
+		.cfg.max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS,
+		.cfg.ops = &rkvdec_ctrl_ops,
+		.cfg.dims = { 65 },
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS,
+		.cfg.ops = &rkvdec_ctrl_ops,
+		.cfg.dims = { 65 },
+	},
+};
+
+static const struct rkvdec_ctrls vdpu346_hevc_ctrls = {
+	.ctrls = vdpu346_hevc_ctrl_descs,
+	.num_ctrls = ARRAY_SIZE(vdpu346_hevc_ctrl_descs),
+};
+
 static const struct rkvdec_ctrl_desc vdpu38x_hevc_ctrl_descs[] = {
 	{
 		.cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS,
@@ -449,6 +505,43 @@ static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = {
 	}
 };
 
+static const struct rkvdec_coded_fmt_desc vdpu346_coded_fmts[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_H264_SLICE,
+		.frmsize = {
+			.min_width = 64,
+			.max_width =  65520,
+			.step_width = 64,
+			.min_height = 64,
+			.max_height =  65520,
+			.step_height = 16,
+		},
+		.ctrls = &rkvdec_h264_ctrls,
+		.ops = &rkvdec_vdpu381_h264_fmt_ops,
+		.num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts),
+		.decoded_fmts = rkvdec_h264_decoded_fmts,
+		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
+		.capability = RKVDEC_CAPABILITY_H264,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_HEVC_SLICE,
+		.frmsize = {
+			.min_width = 64,
+			.max_width = 65472,
+			.step_width = 64,
+			.min_height = 64,
+			.max_height = 65472,
+			.step_height = 16,
+		},
+		.ctrls = &vdpu346_hevc_ctrls,
+		.ops = &rkvdec_vdpu381_hevc_fmt_ops,
+		.num_decoded_fmts = ARRAY_SIZE(rkvdec_hevc_decoded_fmts),
+		.decoded_fmts = rkvdec_hevc_decoded_fmts,
+		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
+		.capability = RKVDEC_CAPABILITY_HEVC,
+	},
+};
+
 static const struct rkvdec_coded_fmt_desc vdpu381_coded_fmts[] = {
 	{
 		.fourcc = V4L2_PIX_FMT_H264_SLICE,
@@ -1654,6 +1747,19 @@ static const struct rkvdec_variant rk3399_rkvdec_variant = {
 			RKVDEC_CAPABILITY_VP9,
 };
 
+static const struct rkvdec_variant rk3568_vdpu346_variant = {
+	.coded_fmts = vdpu346_coded_fmts,
+	.num_coded_fmts = ARRAY_SIZE(vdpu346_coded_fmts),
+	.rcb_sizes = vdpu381_rcb_sizes,
+	.num_rcb_sizes = ARRAY_SIZE(vdpu381_rcb_sizes),
+	.irq_handler = vdpu381_irq_handler,
+	.colmv_size = rkvdec_colmv_size,
+	.flatten_matrices = transpose_and_flatten_matrices,
+	.named_regs = true,
+	.capabilities = RKVDEC_CAPABILITY_H264 |
+			RKVDEC_CAPABILITY_HEVC,
+};
+
 static const struct rkvdec_variant rk3588_vdpu381_variant = {
 	.coded_fmts = vdpu381_coded_fmts,
 	.num_coded_fmts = ARRAY_SIZE(vdpu381_coded_fmts),
@@ -1693,6 +1799,10 @@ static const struct of_device_id of_rkvdec_match[] = {
 		.compatible = "rockchip,rk3399-vdec",
 		.data = &rk3399_rkvdec_variant,
 	},
+	{
+		.compatible = "rockchip,rk3568-vdec",
+		.data = &rk3568_vdpu346_variant,
+	},
 	{
 		.compatible = "rockchip,rk3588-vdec",
 		.data = &rk3588_vdpu381_variant,
-- 
2.34.1



From christianshewitt at gmail.com  Sat Dec  6 00:28:05 2025
From: christianshewitt at gmail.com (Christian Hewitt)
Date: Sat,  6 Dec 2025 08:28:05 +0000
Subject: [PATCH 0/4] media: rockchip: rkvdec: add support for the VDPU346 variant
Message-ID: <20251206082809.2040679-1-christianshewitt@gmail.com>

This series depends upon Detlev Casanova's current v5 series for VDPU381 and
VDPU383 support [0]. Patch 1 is marked DO-NOT-MERGE as it contains fixups
for minor nits spotted in Detlev's series. I've flagged them on IRC after v2
but the messages may have been missed as they are still present in v5.

Patches 2/3/4 add support for the VDPU346 IP block used for H264, HEVC and
(in future work) VP9 on the RK356X boards. VDPU346 appears to be a close
relation to VDPU381 used with RK3588, except with a single core, output
limited to 4K, and minor feature differences, e.g. HEVC level 5.1 on VDPU346
vs 6.1 on VDPU381. To handle differences we declare a new compatible.

The device-tree changes are derived from prior-art in Detlev's patches for
RK3576 and RK3588, the vendor kernel [1], and some earlier patch attempts
from Piotr Oniszczuk and Diederik de Haas.

The register differences between VDPU346 and VDPU381 appear to be minimal so
we currently and intentionally reuse the VDPU381 h264, hevc, and regs files
to avoid duplicating code. If further register analysis requires separate
files for VDPU346 the refactoring to Detlev's drivers is a little beyond my
current beginner level c skills. As the overall minor changeset to VDPU381
it would be awesome if this series could be absorbed. I had some discussion
with Olivier Cr?te during VideoLan Dev Days last month that suggested this
might be possible? - hence sending now. If not, I'll wait until Detlev's
series has been merged before sending a next iteration of these patches.

Testing with Jellyfish files of varying bitrates shows that RK356X starts
to experience jerky playback above 10mbps, which seems rather low compared
to RK3588 which can play 300mbps media without issues. The vendor kernel
documents 'advanced' assigned-clock-rates but increasing them does not have
any obvious impact so the difference looks to be something deeper. NB: The
same is also seen with Detlev's patches for RK3576 (max 15mpbs) so further
or follow-up work is likely required. Despite the apparent limitation real-
world media from my collection plays well.

[0] https://patchwork.kernel.org/project/linux-rockchip/list/?series=1015221
[1] https://github.com/rockchip-linux/kernel/blob/develop-6.6/arch/arm64/boot/dts/rockchip/rk356x.dtsi#L1539

Christian Hewitt (4):
  media: rkvdec: minor fixes for current DETLEV patches
  media: dt-bindings: rockchip: Add RK3568 Video Decoder bindings
  media: rkvdec: Add support for the VDPU346 variant
  arm64: dts: rockchip: Add the vdpu346 Video Decoders on RK356X

 .../bindings/media/rockchip,vdec.yaml         |   2 +
 arch/arm64/boot/dts/rockchip/rk356x-base.dtsi |  49 ++++++++
 .../rockchip/rkvdec/rkvdec-vdpu381-regs.h     |   4 +-
 .../rockchip/rkvdec/rkvdec-vdpu383-hevc.c     |   6 +-
 .../media/platform/rockchip/rkvdec/rkvdec.c   | 110 ++++++++++++++++++
 5 files changed, 166 insertions(+), 5 deletions(-)

-- 
2.34.1



From krzk at kernel.org  Sat Dec  6 02:42:33 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sat, 6 Dec 2025 11:42:33 +0100
Subject: [PATCH v8 1/2] dt-bindings: phy: google: Add Google Tensor G5 USB
 PHY
In-Reply-To: <CA+zupgzi55svWK4gHsFtdQSD9jFKbxHx_0GE2R1R5DafmYyGNA@mail.gmail.com>
References: <20251205-phyb4-v8-0-c59ea80a4458@google.com>
 <20251205-phyb4-v8-1-c59ea80a4458@google.com>
 <18eeb1c5-d21b-4505-b6a4-472f6e191864@kernel.org>
 <CA+zupgwa+m8Pa=+8shORaOA1OO6zoo6zYEojFS2UDuP0doBq7A@mail.gmail.com>
 <f32e0810-56f9-417e-abf6-0cc7b361bd15@kernel.org>
 <CA+zupgyxQisYBnLj9_3DtcN3R1Ugfv+-p-wimFp-hnqkhrrgyA@mail.gmail.com>
 <988b3fcb-44db-45ca-823b-5ab13206bd04@kernel.org>
 <CA+zupgzi55svWK4gHsFtdQSD9jFKbxHx_0GE2R1R5DafmYyGNA@mail.gmail.com>
Message-ID: <b825fbfa-8f9c-4a7d-abd9-b9293edf5863@kernel.org>

On 05/12/2025 21:18, Roy Luo wrote:
> On Fri, Dec 5, 2025 at 11:26?AM Krzysztof Kozlowski <krzk at kernel.org> wrote:
>>
>> On 05/12/2025 20:11, Roy Luo wrote:
>>> On Fri, Dec 5, 2025 at 10:52?AM Krzysztof Kozlowski <krzk at kernel.org> wrote:
>>>>
>>>> On 05/12/2025 19:47, Roy Luo wrote:
>>>>> On Fri, Dec 5, 2025 at 9:13?AM Krzysztof Kozlowski <krzk at kernel.org> wrote:
>>>>>>
>>>>>> On 05/12/2025 04:54, Roy Luo wrote:
>>>>>>> Document the device tree bindings for the USB PHY interfaces integrated
>>>>>>> with the DWC3 controller on Google Tensor SoCs, starting with G5
>>>>>>> generation (Laguna). The USB PHY on Tensor G5 includes two integrated
>>>>>>> Synopsys PHY IPs: the eUSB 2.0 PHY IP and the USB 3.2/DisplayPort combo
>>>>>>> PHY IP.
>>>>>>>
>>>>>>> Due to a complete architectural overhaul in the Google Tensor G5, the
>>>>>>> existing Samsung/Exynos USB PHY binding for older generations of Google
>>>>>>> silicons such as gs101 are no longer compatible, necessitating this new
>>>>>>> device tree binding.
>>>>>>>
>>>>>>> Signed-off-by: Roy Luo <royluo at google.com>
>>>>>>
>>>>>> Why intentionally dropping the tag? How are you handling this patchset?
>>>>>> Rewrite every time from scratch?
>>>>>
>>>>> Hi Krzysztof,
>>>>>
>>>>> I dropped the tag because a new file is being modified in this version,
>>>>> Although it's just MAINTAINER file but I thought you might also want
>>>>> to take a look. I wasn't sure if modifying a new file qualifies as
>>>>> "substantial" so I erred on the side of caution. I should've called it
>>>>> out specifically in the change log. Sorry for the inconvenience.
>>>>
>>>> 1. so just squeeze that change into second patch and no need to ask for
>>>> re-review
>>>
>>> That's a fair point. I will be more mindful of the review overhead
>>> going forward.
>>>
>>>> 2. You did not read my complain fully, look:
>>>>
>>>>>
>>>>> Regards,
>>>>> Roy Luo
>>>>>
>>>>>>
>>>>>> <form letter>
>>>>>> This is a friendly reminder during the review process.
>>>>>>
>>>>>> It looks like you received a tag and forgot to add it.
>>>>>>
>>>>>> If you do not know the process, here is a short explanation:
>>>>>> Please add Acked-by/Reviewed-by/Tested-by tags when posting new versions
>>>>>> of patchset, under or above your Signed-off-by tag, unless patch changed
>>>>>> significantly (e.g. new properties added to the DT bindings). Tag is
>>>>>> "received", when provided in a message replied to you on the mailing
>>>>>> list. Tools like b4 can help here. However, there's no need to repost
>>>>>> patches *only* to add the tags. The upstream maintainer will do that for
>>>>>> tags received on the version they apply.
>>>>>>
>>>>>> Please read:
>>>>>> https://elixir.bootlin.com/linux/v6.12-rc3/source/Documentation/process/submitting-patches.rst#L577
>>>>>>
>>>>>> If a tag was not added on purpose, please state why and what changed.
>>>>
>>>> Where did you address this? You dropped the tag silently.
>>>
>>> Why: a new file is being modified.
>>> What changed: MAINTAINER
>>> What's not changed:
>>> Documentation/devicetree/bindings/phy/google,lga-usb-phy.yaml
>>
>> I don't know if you still did not get the problem or you think that I
>> really need that clear answer. So no, I do not need that clear answer, I
>> understood with first reply, but you kept explaining instead of
>> admitting that your changelog needs fixes. So I still do not believe you
>> understood the problem here and you might repeat the mistake.
> 
> I admitted that my changelog needs fixes in my first reply.
> "I should've called it out specifically in the change log. Sorry for the
> inconvenience.".
> Maybe you think I didn't read through because my reply was placed
> before the <form letter> section, but that's a misunderstanding.
> I did read through the paragraph, that's why I mentioned the
> changelog in my first reply.
> 
> I also misunderstood your question of "Where did you address
> this?". If you were asking where this should have been addressed,
> obviously the answer is to address it in the changelog,
> but I thought that was already made clear in the first reply and
> you might be asking for a clear answer.
> 
>>
>> I think you need someone in Google to coach in this process, because I
>> even gave you the exact link describing the process and what was
>> expected. I even pointed specific paragraph, so you don't need to read
>> entire file!
> 
> I appreciate you pointing out the specific paragraph, I understand
> you're going above and beyond here. I did read and understand
> what should've been done instead for this patch.


Ack, understood. Apologies for my previous over agitated email. That was
not professional of me.

Best regards,
Krzysztof


From krzk at kernel.org  Sat Dec  6 02:47:41 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sat, 6 Dec 2025 11:47:41 +0100
Subject: [PATCH v9 1/2] dt-bindings: usb: dwc3: Add Google Tensor G5 DWC3
In-Reply-To: <20251205-controller-v9-1-9f158b18f979@google.com>
References: <20251205-controller-v9-0-9f158b18f979@google.com>
 <20251205-controller-v9-1-9f158b18f979@google.com>
Message-ID: <20251206-perky-tentacled-lori-bc71d9@quoll>

On Fri, Dec 05, 2025 at 02:26:37AM +0000, Roy Luo wrote:
> Document the device tree bindings for the DWC3 USB controller found in
> Google Tensor SoCs, starting with the G5 generation (codename: laguna).
> 
> The Tensor G5 silicon represents a complete architectural departure from
> previous generations (like gs101), including entirely new clock/reset
> schemes, top-level wrapper and register interface. Consequently,
> existing Samsung/Exynos DWC3 USB bindings are incompatible, necessitating
> this new device tree binding.
> 
> The USB controller on Tensor G5 is based on Synopsys DWC3 IP and features
> Dual-Role Device single port with hibernation support.
> 
> Signed-off-by: Roy Luo <royluo at google.com>
> ---
>  .../devicetree/bindings/usb/google,lga-dwc3.yaml   | 140 +++++++++++++++++++++
>  MAINTAINERS                                        |   1 +
>  2 files changed, 141 insertions(+)

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof



From krzk at kernel.org  Sat Dec  6 02:48:23 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sat, 6 Dec 2025 11:48:23 +0100
Subject: [PATCH v8 1/2] dt-bindings: phy: google: Add Google Tensor G5
 USB PHY
In-Reply-To: <20251205-phyb4-v8-1-c59ea80a4458@google.com>
References: <20251205-phyb4-v8-0-c59ea80a4458@google.com>
 <20251205-phyb4-v8-1-c59ea80a4458@google.com>
Message-ID: <20251206-viridian-shrimp-of-growth-43ddd0@quoll>

On Fri, Dec 05, 2025 at 03:54:11AM +0000, Roy Luo wrote:
> Document the device tree bindings for the USB PHY interfaces integrated
> with the DWC3 controller on Google Tensor SoCs, starting with G5
> generation (Laguna). The USB PHY on Tensor G5 includes two integrated
> Synopsys PHY IPs: the eUSB 2.0 PHY IP and the USB 3.2/DisplayPort combo
> PHY IP.
> 
> Due to a complete architectural overhaul in the Google Tensor G5, the
> existing Samsung/Exynos USB PHY binding for older generations of Google
> silicons such as gs101 are no longer compatible, necessitating this new
> device tree binding.
> 
> Signed-off-by: Roy Luo <royluo at google.com>
> ---
>  .../bindings/phy/google,lga-usb-phy.yaml           | 133 +++++++++++++++++++++
>  MAINTAINERS                                        |   1 +
>  2 files changed, 134 insertions(+)

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof



From claudiu.beznea at tuxon.dev  Sat Dec  6 02:59:22 2025
From: claudiu.beznea at tuxon.dev (Claudiu Beznea)
Date: Sat, 6 Dec 2025 12:59:22 +0200
Subject: [PATCH v4 2/2] ARM: dts: Add support for pcb8385
In-Reply-To: <20251201082629.2326339-3-horatiu.vultur@microchip.com>
References: <20251201082629.2326339-1-horatiu.vultur@microchip.com>
 <20251201082629.2326339-3-horatiu.vultur@microchip.com>
Message-ID: <b8e4805e-c0fc-489f-941d-d052668cbe74@tuxon.dev>

Hi, Horatiu,

On 12/1/25 10:26, Horatiu Vultur wrote:
> Add basic support for pcb8385 [1]. It is a modular board which allows
> to add different daughter cards on which there are different PHYs.
> This adds support for UART, LEDs and I2C.
> 
> [1] https://www.microchip.com/en-us/development-tool/ev83e85a
> 
> Signed-off-by: Horatiu Vultur <horatiu.vultur at microchip.com>
> ---
>  arch/arm/boot/dts/microchip/Makefile          |   3 +-
>  .../boot/dts/microchip/lan966x-pcb8385.dts    | 131 ++++++++++++++++++
>  2 files changed, 133 insertions(+), 1 deletion(-)
>  create mode 100644 arch/arm/boot/dts/microchip/lan966x-pcb8385.dts
> 
> diff --git a/arch/arm/boot/dts/microchip/Makefile b/arch/arm/boot/dts/microchip/Makefile
> index 79cd38fdc7dab..08986c24a4700 100644
> --- a/arch/arm/boot/dts/microchip/Makefile
> +++ b/arch/arm/boot/dts/microchip/Makefile
> @@ -102,4 +102,5 @@ dtb-$(CONFIG_SOC_LAN966) += \
>  	lan966x-kontron-kswitch-d10-mmt-8g.dtb \
>  	lan966x-pcb8290.dtb \
>  	lan966x-pcb8291.dtb \
> -	lan966x-pcb8309.dtb
> +	lan966x-pcb8309.dtb \
> +	lan966x-pcb8385.dtb
> diff --git a/arch/arm/boot/dts/microchip/lan966x-pcb8385.dts b/arch/arm/boot/dts/microchip/lan966x-pcb8385.dts
> new file mode 100644
> index 0000000000000..6bbe1222f9106
> --- /dev/null
> +++ b/arch/arm/boot/dts/microchip/lan966x-pcb8385.dts
> @@ -0,0 +1,131 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * lan966x-pcb8385.dts - Device Tree file for PCB8385
> + */
> +/dts-v1/;
> +
> +#include "lan966x.dtsi"
> +#include "dt-bindings/phy/phy-lan966x-serdes.h"
> +
> +/ {
> +	model = "Microchip EVB - LAN9668";
> +	compatible = "microchip,lan9668-pcb8385", "microchip,lan9668", "microchip,lan966";
> +
> +	aliases {
> +		serial0 = &usart3;
> +	};
> +
> +	chosen {
> +		stdout-path = "serial0:115200n8";
> +	};
> +
> +	gpio-restart {
> +		compatible = "gpio-restart";
> +		gpios = <&gpio 59 GPIO_ACTIVE_LOW>;
> +		open-source;
> +		priority = <200>;
> +	};
> +
> +	leds {
> +		compatible = "gpio-leds";
> +
> +		led-p1-green {
> +			label = "cu0:green";
> +			gpios = <&sgpio_out 2 0 GPIO_ACTIVE_LOW>;
> +			default-state = "off";
> +		};
> +
> +		led-p1-yellow {
> +			label = "cu0:yellow";
> +			gpios = <&sgpio_out 2 1 GPIO_ACTIVE_LOW>;
> +			default-state = "off";
> +		};
> +
> +		led-p2-green {
> +			label = "cu1:green";
> +			gpios = <&sgpio_out 3 0 GPIO_ACTIVE_LOW>;
> +			default-state = "off";
> +		};
> +
> +		led-p2-yellow {
> +			label = "cu1:yellow";
> +			gpios = <&sgpio_out 3 1 GPIO_ACTIVE_LOW>;
> +			default-state = "off";
> +		};
> +	};
> +};
> +
> +&aes {
> +	status = "disabled"; /* Reserved by secure OS */

According to [1] this should be marked as reserved.

[1]
https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#status

Thank you,
Claudiu


From claudiu.beznea at tuxon.dev  Sat Dec  6 03:00:05 2025
From: claudiu.beznea at tuxon.dev (Claudiu Beznea)
Date: Sat, 6 Dec 2025 13:00:05 +0200
Subject: [PATCH v4 1/2] dt-bindings: arm: at91: add lan966 pcb8385 board
In-Reply-To: <20251201082629.2326339-2-horatiu.vultur@microchip.com>
References: <20251201082629.2326339-1-horatiu.vultur@microchip.com>
 <20251201082629.2326339-2-horatiu.vultur@microchip.com>
Message-ID: <190349af-77c5-45e3-beb3-d6f82ce1987f@tuxon.dev>



On 12/1/25 10:26, Horatiu Vultur wrote:
> Add documentation for Microchip LAN9668 PCB8385
> 
> Acked-by: Rob Herring (Arm) <robh at kernel.org>
> Signed-off-by: Horatiu Vultur <horatiu.vultur at microchip.com>

Reviewed-by: Claudiu Beznea <claudiu.beznea at tuxon.dev>

> ---
>  Documentation/devicetree/bindings/arm/atmel-at91.yaml | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.yaml b/Documentation/devicetree/bindings/arm/atmel-at91.yaml
> index 3a34b7a2e8d4e..68d306d17c2a1 100644
> --- a/Documentation/devicetree/bindings/arm/atmel-at91.yaml
> +++ b/Documentation/devicetree/bindings/arm/atmel-at91.yaml
> @@ -235,9 +235,11 @@ properties:
>            - const: microchip,lan9662
>            - const: microchip,lan966
>  
> -      - description: Microchip LAN9668 PCB8290 Evaluation Board.
> +      - description: Microchip LAN9668 Evaluation Board.
>          items:
> -          - const: microchip,lan9668-pcb8290
> +          - enum:
> +              - microchip,lan9668-pcb8290
> +              - microchip,lan9668-pcb8385
>            - const: microchip,lan9668
>            - const: microchip,lan966
>  



From claudiu.beznea at tuxon.dev  Sat Dec  6 03:03:24 2025
From: claudiu.beznea at tuxon.dev (Claudiu Beznea)
Date: Sat, 6 Dec 2025 13:03:24 +0200
Subject: [PATCH] ARM: dts: lan966x: Fix the access to the PHYs for pcb8290
In-Reply-To: <20251119134750.394655-1-horatiu.vultur@microchip.com>
References: <20251119134750.394655-1-horatiu.vultur@microchip.com>
Message-ID: <51908ef6-f777-4a20-acef-538d9e715790@tuxon.dev>



On 11/19/25 15:47, Horatiu Vultur wrote:
> The problem is that the MDIO controller can't detect any of the PHYs.
> The reason is that the lan966x is not pulling high the GPIO 53 that is
> connected to the PHYs reset GPIO. Without doing this the PHYs are kept
> in reset. The mdio controller framework has the possiblity to control a

s/possiblity/possibility

I can adjust it while applying

> GPIO to release the reset of the PHYs. So take advantage of this and set
> line to be high before accessing the PHYs.
> 
> Signed-off-by: Horatiu Vultur <horatiu.vultur at microchip.com>

Reviewed-by: Claudiu Beznea <claudiu.beznea at tuxon.dev>

> ---
>  arch/arm/boot/dts/microchip/lan966x-pcb8290.dts | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/arch/arm/boot/dts/microchip/lan966x-pcb8290.dts b/arch/arm/boot/dts/microchip/lan966x-pcb8290.dts
> index 3b7577e48b467..50bd29572f3ed 100644
> --- a/arch/arm/boot/dts/microchip/lan966x-pcb8290.dts
> +++ b/arch/arm/boot/dts/microchip/lan966x-pcb8290.dts
> @@ -54,6 +54,7 @@ udc_pins: ucd-pins {
>  &mdio0 {
>  	pinctrl-0 = <&miim_a_pins>;
>  	pinctrl-names = "default";
> +	reset-gpios = <&gpio 53 GPIO_ACTIVE_LOW>;
>  	status = "okay";
>  
>  	ext_phy0: ethernet-phy at 7 {



From brgl at kernel.org  Sat Dec  6 03:04:28 2025
From: brgl at kernel.org (Bartosz Golaszewski)
Date: Sat, 6 Dec 2025 03:04:28 -0800
Subject: [PATCH v2 5/8] gpio: rockchip: support new version GPIO
In-Reply-To: <20251206050844.402958-6-ye.zhang@rock-chips.com>
References: <20251206050844.402958-1-ye.zhang@rock-chips.com> <20251206050844.402958-6-ye.zhang@rock-chips.com>
Message-ID: <CAMRc=MdNNkQpXiaK7J12QjsQiL-DjxGUarvveeYze19-1wqfxw@mail.gmail.com>

On Sat, 6 Dec 2025 06:08:41 +0100, Ye Zhang <ye.zhang at rock-chips.com> said:
> Support the next version GPIO controller on SoCs like rv1126b.
>
> Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
> ---
>  drivers/gpio/gpio-rockchip.c | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c
> index 47174eb3ba76..c3e831c6bcf1 100644
> --- a/drivers/gpio/gpio-rockchip.c
> +++ b/drivers/gpio/gpio-rockchip.c
> @@ -36,6 +36,7 @@
>  #define GPIO_TYPE_V2		(0x01000C2B)
>  #define GPIO_TYPE_V2_1		(0x0101157C)
>  #define GPIO_TYPE_V2_2		(0x010219C8)
> +#define GPIO_TYPE_V2_6          (0x01063F6E)
>
>  static const struct rockchip_gpio_regs gpio_regs_v1 = {
>  	.port_dr = 0x00,
> @@ -674,6 +675,7 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank)
>  	case GPIO_TYPE_V2:
>  	case GPIO_TYPE_V2_1:
>  	case GPIO_TYPE_V2_2:
> +	case GPIO_TYPE_V2_6:
>  		bank->gpio_regs = &gpio_regs_v2;
>  		bank->gpio_type = GPIO_TYPE_V2;
>  		bank->db_clk = of_clk_get(bank->of_node, 1);
> --
> 2.34.1
>
>

Acked-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>


From claudiu.beznea at tuxon.dev  Sat Dec  6 03:27:50 2025
From: claudiu.beznea at tuxon.dev (Claudiu Beznea)
Date: Sat, 6 Dec 2025 13:27:50 +0200
Subject: [PATCH 1/4] dt-bindings: usb: Add Microchip LAN969x support
In-Reply-To: <20251203122313.1287950-1-robert.marko@sartura.hr>
References: <20251203122313.1287950-1-robert.marko@sartura.hr>
Message-ID: <99b0dbae-0014-4d09-8724-092c03393dac@tuxon.dev>

Hi, Robert,

On 12/3/25 14:21, Robert Marko wrote:
> Microchip LAN969x has DWC3 compatible controller, though limited to 2.0(HS)
> speed, so document it.
> 
> Signed-off-by: Robert Marko <robert.marko at sartura.hr>
> ---
>  .../bindings/usb/microchip,lan9691-dwc3.yaml  | 68 +++++++++++++++++++
>  1 file changed, 68 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/usb/microchip,lan9691-dwc3.yaml
> 
> diff --git a/Documentation/devicetree/bindings/usb/microchip,lan9691-dwc3.yaml b/Documentation/devicetree/bindings/usb/microchip,lan9691-dwc3.yaml
> new file mode 100644
> index 000000000000..7ffcbbd1e0f4
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/usb/microchip,lan9691-dwc3.yaml
> @@ -0,0 +1,68 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/usb/microchip,lan9691-dwc3.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Microchip LAN969x SuperSpeed DWC3 USB SoC controller
> +
> +maintainers:
> +  - Robert Marko <robert.marko at sartura.hr>
> +
> +select:
> +  properties:
> +    compatible:
> +      contains:
> +        enum:
> +          - microchip,lan9691-dwc3
> +  required:
> +    - compatible
> +
> +properties:
> +  compatible:
> +    items:
> +      - enum:
> +          - microchip,lan9691-dwc3
> +      - const: snps,dwc3
> +
> +  reg:
> +    maxItems: 1
> +
> +  interrupts:
> +    maxItems: 1
> +
> +  clocks:
> +    items:
> +      - description: Gated USB DRD clock
> +      - description: Controller reference clock
> +
> +  clock-names:
> +    items:
> +      - const: bus_early
> +      - const: ref
> +
> +unevaluatedProperties: false
> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts
> +  - clocks
> +  - clock-names
> +
> +allOf:
> +  - $ref: snps,dwc3.yaml#
> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +    #include <dt-bindings/clock/microchip,lan969x.h>
> +
> +    usb at 300000 {
> +      compatible = "microchip,lan9691-dwc3", "snps,dwc3";

AFICT, the examples should be indented by 4 spaces.

> +      reg = <0x300000 0x80000>;
> +      interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
> +      clocks = <&clks GCK_GATE_USB_DRD>,
> +               <&clks GCK_ID_USB_REFCLK>;
> +      clock-names = "bus_early", "ref";
> +    };



From dmitry.baryshkov at oss.qualcomm.com  Sat Dec  6 03:28:14 2025
From: dmitry.baryshkov at oss.qualcomm.com (Dmitry Baryshkov)
Date: Sat, 6 Dec 2025 13:28:14 +0200
Subject: [PATCH v3 00/11] drm/connector: hdmi: limit infoframes per
 driver capabilities
In-Reply-To: <20251201-enlightened-zebu-from-asgard-5a20be@houat>
References: <qx5ashx62pufott6hnsfna3qntnoyvxwxze4rihhuxcsdxi37s@bbdvc3sfsgne>
 <20250929-gregarious-worm-of-memory-c5354d@houat>
 <itgffxygopi7etkt7xhvmyuvyl5ad3k43nsxvjzw3ubtwiikn7@ocugfdaigtu7>
 <20251003-uptight-echidna-of-stamina-815305@houat>
 <zpygq4kapil3swsmhhqkdwny4ry2dznnzixsw5rkza5p2kqnvp@abvf2vxlbwif>
 <2a5fitdzr2bz235fj6rvqzxr6ckszkjbazjfszlvnizdh2cvbt@w3ypjo7vahhs>
 <pibxhl5hlcpuk3zsgyienfdlda5cwuxrnofwlw356scuzzplqy@zw3ofelgvwik>
 <bsoqyzxi45i67jpzhwr2d4illufa5ghqf25z6flbp67lsbvh22@rrlcihp2oxea>
 <cgzclxjubj5oca3rdnv44qwrkmpddxve4tlz76cc6p3b4hz3oc@3l7mt5ha7do6>
 <20251201-enlightened-zebu-from-asgard-5a20be@houat>
Message-ID: <5dyhjur3hkhvtlwrl4h2m342byor7f3ssvkunj4cggnhbhlmnb@l2mfz7ypjj37>

On Mon, Dec 01, 2025 at 06:01:56PM +0100, Maxime Ripard wrote:
> On Fri, Nov 21, 2025 at 07:09:01PM +0200, Dmitry Baryshkov wrote:
> > > So it's not really impossible, you just need some hardware and a day's
> > > worth of work.
> > > 
> > > There's no reason these should get a pass, it's breaking the spec for no
> > > reason.
> > > 
> > > > > For SPD, It's really not clear to me why atomic_check should do that in
> > > > > the first place. Your initial concern was about exposing infoframes in
> > > > > debugfs that wouldn't be used by the driver.
> > > > > 
> > > > > If the driver doesn't register a debugfs file for SPD, and ignores
> > > > > whatever is in the atomic state, what's should we force drivers to do
> > > > > that?
> > > > 
> > > > I really don't think that drivers should mess up with debugfs on their
> > > > own. Making atomic_check() disable the unsupported InfoFrames makes the
> > > > picture perfect: the DRM no longer tries to program them to the
> > > > hardware, DebugFS files stay empty, so the whole state becomes
> > > > consistent.
> > > 
> > > In the "bridge has no access to infoframes" case, there's really no
> > > infoframe. An empty file is "the infoframe can be there but isn't used",
> > > not "we don't have access to it and can't report them". Only drivers
> > > have those infos.
> > > 
> > > If we do split up write_infoframe into multiple functions though, I
> > > guess we could create the debugfs file only if the function pointer is
> > > set, which removes drivers' involvement if you don't like that.
> > 
> > I'm fine with not using HDMI connector framework for lt9611uxc.
> > Likewise, I think, it's fine to have empty files for the infoframes
> > which are not being sent over the wire for any reason (hw not supporting
> > it is one of the reasons).
> 
> I can't think of any other example in the kernel where an empty file
> means that the driver doesn't support something.

Okay. So we need to sort out implementing the split write_infoframes in
drm_bridge_connector. Any suggestions there? I'm asking, because I don't
want to end up exploding it.

-- 
With best wishes
Dmitry


From christianshewitt at gmail.com  Sat Dec  6 02:01:57 2025
From: christianshewitt at gmail.com (Christian Hewitt)
Date: Sat,  6 Dec 2025 10:01:57 +0000
Subject: [PATCH 0/4] media: rockchip: rkvdec: add support for the VDPU346 variant
Message-ID: <20251206100158.2041439-1-christianshewitt@gmail.com>

This series depends upon Detlev Casanova's current v5 series for VDPU381 and
VDPU383 support [0]. Patch 1 is marked DO-NOT-MERGE as it contains fixups
for minor nits spotted in Detlev's series. I've flagged them on IRC after v2
but the messages may have been missed as they are still present in v5.

Patches 2/3/4 add support for the VDPU346 IP block used for H264, HEVC and
(in future work) VP9 on the RK356X boards. VDPU346 appears to be a close
relation to VDPU381 used with RK3588, except with a single core, output
limited to 4K, and minor feature differences, e.g. HEVC level 5.1 on VDPU346
vs 6.1 on VDPU381. To handle differences we declare a new compatible.

The device-tree changes are derived from prior-art in Detlev's patches for
RK3576 and RK3588, the vendor kernel [1], and some earlier patch attempts
from Piotr Oniszczuk and Diederik de Haas.

The register differences between VDPU346 and VDPU381 appear to be minimal so
we currently and intentionally reuse the VDPU381 h264, hevc, and regs files
to avoid duplicating code. If further register analysis requires separate
files for VDPU346 the refactoring to Detlev's drivers is a little beyond my
current beginner level c skills. As the overall minor changeset to VDPU381
it would be awesome if this series could be absorbed. I had some discussion
with Olivier Cr?te during VideoLan Dev Days last month that suggested this
might be possible? - hence sending now. If not, I'll wait until Detlev's
series has been merged before sending a next iteration of these patches.

Testing with Jellyfish files of varying bitrates shows that RK356X starts
to experience jerky playback above 10mbps, which seems rather low compared
to RK3588 which can play 300mbps media without issues. The vendor kernel
documents 'advanced' assigned-clock-rates but increasing them does not have
any obvious impact so the difference looks to be something deeper. NB: The
same is also seen with Detlev's patches for RK3576 (max 15mpbs) so further
or follow-up work is likely required. Despite the apparent limitation real-
world media from my collection plays well.

[0] https://patchwork.kernel.org/project/linux-rockchip/list/?series=1015221
[1] https://github.com/rockchip-linux/kernel/blob/develop-6.6/arch/arm64/boot/dts/rockchip/rk356x.dtsi#L1539

Christian Hewitt (4):
  media: rkvdec: minor fixes for current DETLEV patches
  media: dt-bindings: rockchip: Add RK3568 Video Decoder bindings
  media: rkvdec: Add support for the VDPU346 variant
  arm64: dts: rockchip: Add the vdpu346 Video Decoders on RK356X

 .../bindings/media/rockchip,vdec.yaml         |   2 +
 arch/arm64/boot/dts/rockchip/rk356x-base.dtsi |  49 ++++++++
 .../rockchip/rkvdec/rkvdec-vdpu381-regs.h     |   4 +-
 .../rockchip/rkvdec/rkvdec-vdpu383-hevc.c     |   6 +-
 .../media/platform/rockchip/rkvdec/rkvdec.c   | 110 ++++++++++++++++++
 5 files changed, 166 insertions(+), 5 deletions(-)

-- 
2.34.1



From christianshewitt at gmail.com  Sat Dec  6 02:01:58 2025
From: christianshewitt at gmail.com (Christian Hewitt)
Date: Sat,  6 Dec 2025 10:01:58 +0000
Subject: [PATCH 3/4] media: rkvdec: Add support for the VDPU346 variant
In-Reply-To: <20251206100158.2041439-1-christianshewitt@gmail.com>
References: <20251206100158.2041439-1-christianshewitt@gmail.com>
Message-ID: <20251206100158.2041439-2-christianshewitt@gmail.com>

VDPU346 is derived from VDPU381 but with a single core and limited
to 4K60 media. It is also limited to H264 L5.1 and omits AV1 and
AVS2 capabilities. It is used with RK3566 and RK3568.

Signed-off-by: Christian Hewitt <christianshewitt at gmail.com>
---
 .../media/platform/rockchip/rkvdec/rkvdec.c   | 110 ++++++++++++++++++
 1 file changed, 110 insertions(+)

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index a1c02ef3a97c..cf68454b2217 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -295,6 +295,62 @@ static const struct rkvdec_ctrls rkvdec_h264_ctrls = {
 	.num_ctrls = ARRAY_SIZE(rkvdec_h264_ctrl_descs),
 };
 
+static const struct rkvdec_ctrl_desc vdpu346_hevc_ctrl_descs[] = {
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_SPS,
+		.cfg.ops = &rkvdec_ctrl_ops,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_PPS,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_MODE,
+		.cfg.min = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
+		.cfg.max = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
+		.cfg.def = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_START_CODE,
+		.cfg.min = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
+		.cfg.def = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
+		.cfg.max = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
+	},
+	{
+		.cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
+		.cfg.min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
+		.cfg.max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
+		.cfg.menu_skip_mask =
+			BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE),
+		.cfg.def = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
+	},
+	{
+		.cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
+		.cfg.min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
+		.cfg.max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS,
+		.cfg.ops = &rkvdec_ctrl_ops,
+		.cfg.dims = { 65 },
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS,
+		.cfg.ops = &rkvdec_ctrl_ops,
+		.cfg.dims = { 65 },
+	},
+};
+
+static const struct rkvdec_ctrls vdpu346_hevc_ctrls = {
+	.ctrls = vdpu346_hevc_ctrl_descs,
+	.num_ctrls = ARRAY_SIZE(vdpu346_hevc_ctrl_descs),
+};
+
 static const struct rkvdec_ctrl_desc vdpu38x_hevc_ctrl_descs[] = {
 	{
 		.cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS,
@@ -449,6 +505,43 @@ static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = {
 	}
 };
 
+static const struct rkvdec_coded_fmt_desc vdpu346_coded_fmts[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_H264_SLICE,
+		.frmsize = {
+			.min_width = 64,
+			.max_width =  65520,
+			.step_width = 64,
+			.min_height = 64,
+			.max_height =  65520,
+			.step_height = 16,
+		},
+		.ctrls = &rkvdec_h264_ctrls,
+		.ops = &rkvdec_vdpu381_h264_fmt_ops,
+		.num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts),
+		.decoded_fmts = rkvdec_h264_decoded_fmts,
+		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
+		.capability = RKVDEC_CAPABILITY_H264,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_HEVC_SLICE,
+		.frmsize = {
+			.min_width = 64,
+			.max_width = 65472,
+			.step_width = 64,
+			.min_height = 64,
+			.max_height = 65472,
+			.step_height = 16,
+		},
+		.ctrls = &vdpu346_hevc_ctrls,
+		.ops = &rkvdec_vdpu381_hevc_fmt_ops,
+		.num_decoded_fmts = ARRAY_SIZE(rkvdec_hevc_decoded_fmts),
+		.decoded_fmts = rkvdec_hevc_decoded_fmts,
+		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
+		.capability = RKVDEC_CAPABILITY_HEVC,
+	},
+};
+
 static const struct rkvdec_coded_fmt_desc vdpu381_coded_fmts[] = {
 	{
 		.fourcc = V4L2_PIX_FMT_H264_SLICE,
@@ -1654,6 +1747,19 @@ static const struct rkvdec_variant rk3399_rkvdec_variant = {
 			RKVDEC_CAPABILITY_VP9,
 };
 
+static const struct rkvdec_variant rk3568_vdpu346_variant = {
+	.coded_fmts = vdpu346_coded_fmts,
+	.num_coded_fmts = ARRAY_SIZE(vdpu346_coded_fmts),
+	.rcb_sizes = vdpu381_rcb_sizes,
+	.num_rcb_sizes = ARRAY_SIZE(vdpu381_rcb_sizes),
+	.irq_handler = vdpu381_irq_handler,
+	.colmv_size = rkvdec_colmv_size,
+	.flatten_matrices = transpose_and_flatten_matrices,
+	.named_regs = true,
+	.capabilities = RKVDEC_CAPABILITY_H264 |
+			RKVDEC_CAPABILITY_HEVC,
+};
+
 static const struct rkvdec_variant rk3588_vdpu381_variant = {
 	.coded_fmts = vdpu381_coded_fmts,
 	.num_coded_fmts = ARRAY_SIZE(vdpu381_coded_fmts),
@@ -1693,6 +1799,10 @@ static const struct of_device_id of_rkvdec_match[] = {
 		.compatible = "rockchip,rk3399-vdec",
 		.data = &rk3399_rkvdec_variant,
 	},
+	{
+		.compatible = "rockchip,rk3568-vdec",
+		.data = &rk3568_vdpu346_variant,
+	},
 	{
 		.compatible = "rockchip,rk3588-vdec",
 		.data = &rk3588_vdpu381_variant,
-- 
2.34.1



From xueshuai at linux.alibaba.com  Sat Dec  6 04:34:09 2025
From: xueshuai at linux.alibaba.com (Shuai Xue)
Date: Sat, 6 Dec 2025 20:34:09 +0800
Subject: [PATCH rc v1 4/4] iommu/arm-smmu-v3-test: Add nested s1bypass
 coverage
In-Reply-To: <3c838833d8bbb69a72a85ddbcc325b22ae7a7d6d.1764982046.git.nicolinc@nvidia.com>
References: <cover.1764982046.git.nicolinc@nvidia.com>
 <3c838833d8bbb69a72a85ddbcc325b22ae7a7d6d.1764982046.git.nicolinc@nvidia.com>
Message-ID: <703ba08f-eec0-44d8-a224-c96706df5fab@linux.alibaba.com>



? 2025/12/6 08:52, Nicolin Chen ??:
> STE in a nested case requires both S1 and S2 fields. And this makes the use
> case different from the existing one.
> 
> Add coverage for previously failed cases shifting between S2-only and S1+S2
> STEs.
> 
> Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
> ---
>   .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  | 32 +++++++++++++++++++
>   1 file changed, 32 insertions(+)
> 
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> index 9287904c93a2..56bdcf5a517e 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> @@ -553,6 +553,36 @@ static void arm_smmu_v3_write_ste_test_s2_to_s1_stall(struct kunit *test)
>   						       NUM_EXPECTED_SYNCS(3));
>   }
>   
> +static void
> +arm_smmu_v3_write_ste_test_nested_s1dssbypass_to_s1bypass(struct kunit *test)
> +{
> +	struct arm_smmu_ste s1_ste;
> +	struct arm_smmu_ste s2_ste;
> +
> +	arm_smmu_test_make_s2_ste(&s1_ste, ARM_SMMU_MASTER_TEST_ATS);
> +	arm_smmu_test_make_cdtable_ste(&s1_ste, STRTAB_STE_1_S1DSS_SSID0,

arm_smmu_test_make_s2_ste() makes a s2 ste and it will be overwrited by
arm_smmu_test_make_cdtable_ste(). Finnaly, we got a s1 STE, not a nested
s1dssbypass ste.

I think we need a function like arm_smmu_make_nested_cd_table_ste()
here.

Besides, from the function name, I think you mean
STRTAB_STE_1_S1DSS_BYPASS?

+	arm_smmu_test_make_s2_ste(&s2_ste, 0);
+	arm_smmu_v3_test_ste_expect_hitless_transition(test, &s1_ste, &s2_ste,
+						       NUM_EXPECTED_SYNCS(3));

With get_ignored(), a nested s1dssbypass STE to a nested s1bypass STE
will be hitless, a.k.a, NUM_EXPECTED_SYNCS(1).

Thanks.
Shuai


From claudiu.beznea at tuxon.dev  Sat Dec  6 05:53:42 2025
From: claudiu.beznea at tuxon.dev (Claudiu Beznea)
Date: Sat, 6 Dec 2025 15:53:42 +0200
Subject: [PATCH 4/4] arm64: dts: microchip: add LAN969x support
In-Reply-To: <20251203122313.1287950-4-robert.marko@sartura.hr>
References: <20251203122313.1287950-1-robert.marko@sartura.hr>
 <20251203122313.1287950-4-robert.marko@sartura.hr>
Message-ID: <a8185e0f-a3a2-44df-af37-1ad505ce9a7b@tuxon.dev>

Hi, Robert,

On 12/3/25 14:21, Robert Marko wrote:
> Add support for Microchip LAN969x switch SoC, including the EV23X71A
> EVB board.

Could you please split SoC and board device trees in different patches?

> 
> Signed-off-by: Robert Marko <robert.marko at sartura.hr>
> ---
>  arch/arm64/boot/dts/microchip/Makefile        |   2 +
>  .../boot/dts/microchip/lan9696-ev23x71a.dts   | 761 ++++++++++++++++++
>  arch/arm64/boot/dts/microchip/lan969x.dtsi    | 482 +++++++++++
>  3 files changed, 1245 insertions(+)
>  create mode 100644 arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts
>  create mode 100644 arch/arm64/boot/dts/microchip/lan969x.dtsi
> 
> diff --git a/arch/arm64/boot/dts/microchip/Makefile b/arch/arm64/boot/dts/microchip/Makefile
> index c6e0313eea0f..d02ac50aae79 100644
> --- a/arch/arm64/boot/dts/microchip/Makefile
> +++ b/arch/arm64/boot/dts/microchip/Makefile
> @@ -2,3 +2,5 @@
>  dtb-$(CONFIG_ARCH_SPARX5) += sparx5_pcb125.dtb
>  dtb-$(CONFIG_ARCH_SPARX5) += sparx5_pcb134.dtb sparx5_pcb134_emmc.dtb
>  dtb-$(CONFIG_ARCH_SPARX5) += sparx5_pcb135.dtb sparx5_pcb135_emmc.dtb
> +
> +dtb-$(CONFIG_ARCH_LAN969X) += lan9696-ev23x71a.dtb

Please keep it alphanumerically sorted, so before SPARCX5

> \ No newline at end of file
> diff --git a/arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts b/arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts
> new file mode 100644
> index 000000000000..6bbddad2a0b9
> --- /dev/null
> +++ b/arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts
> @@ -0,0 +1,761 @@
> +// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT)
> +/*
> + * Copyright (c) 2025 Microchip Technology Inc. and its subsidiaries.
> + */
> +
> +/dts-v1/;
> +
> +#include <dt-bindings/gpio/gpio.h>
> +#include <dt-bindings/leds/common.h>
> +#include "lan969x.dtsi"
> +
> +/ {
> +	model = "Microchip EV23X71A";
> +	compatible = "microchip,ev23x71a", "microchip,lan969x";
> +
> +	aliases {
> +		serial0 = &usart0;
> +	};
> +
> +	chosen {
> +		stdout-path = "serial0:115200n8";
> +	};
> +
> +	gpio-restart {
> +		compatible = "gpio-restart";
> +		gpios = <&gpio 60 GPIO_ACTIVE_LOW>;
> +		open-source;
> +		priority = <200>;
> +	};
> +
> +	i2c-mux {
> +		compatible = "i2c-mux-gpio";
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		i2c-parent = <&i2c3>;
> +

This line could be dropped.

> +		mux-gpios = <&sgpio_out 0 1 GPIO_ACTIVE_HIGH
> +			     &sgpio_out 0 2 GPIO_ACTIVE_HIGH
> +			     &sgpio_out 0 3 GPIO_ACTIVE_HIGH>;

Enclose each entry in <>. See
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/Documentation/devicetree/bindings/dts-coding-style.rst#n179

> +		idle-state = <0x8>;
> +
> +		i2c_sfp0: i2c at 0 {
> +			reg = <0x0>;
> +		};
> +
> +		i2c_sfp1: i2c at 1 {
> +			reg = <0x1>;
> +		};
> +
> +		i2c_sfp2: i2c at 2 {
> +			reg = <0x2>;
> +		};
> +
> +		i2c_sfp3: i2c at 3 {
> +			reg = <0x3>;
> +		};
> +
> +		i2c_poe: i2c at 7 {
> +			reg = <0x7>;
> +		};
> +	};
> +
> +	leds {
> +		compatible = "gpio-leds";
> +
> +		led-status {
> +			color = <LED_COLOR_ID_GREEN>;
> +			function = LED_FUNCTION_STATUS;
> +			gpios = <&gpio 61 GPIO_ACTIVE_LOW>;
> +		};
> +
> +		led-sfp1-green {
> +			color = <LED_COLOR_ID_GREEN>;
> +			function = LED_FUNCTION_LAN;
> +			function-enumerator = <0>;
> +			gpios = <&sgpio_out 6 0 GPIO_ACTIVE_LOW>;
> +			default-state = "off";
> +		};
> +
> +		led-sfp1-yellow {
> +			color = <LED_COLOR_ID_YELLOW>;
> +			function = LED_FUNCTION_LAN;
> +			function-enumerator = <0>;
> +			gpios = <&sgpio_out 6 1 GPIO_ACTIVE_LOW>;
> +			default-state = "off";
> +		};
> +
> +		led-sfp2-green {
> +			color = <LED_COLOR_ID_GREEN>;
> +			function = LED_FUNCTION_LAN;
> +			function-enumerator = <1>;
> +			gpios = <&sgpio_out 7 0 GPIO_ACTIVE_LOW>;
> +			default-state = "off";
> +		};
> +
> +		led-sfp2-yellow {
> +			color = <LED_COLOR_ID_YELLOW>;
> +			function = LED_FUNCTION_LAN;
> +			function-enumerator = <1>;
> +			gpios = <&sgpio_out 7 1 GPIO_ACTIVE_LOW>;
> +			default-state = "off";
> +		};
> +
> +		led-sfp3-green {
> +			color = <LED_COLOR_ID_GREEN>;
> +			function = LED_FUNCTION_LAN;
> +			function-enumerator = <2>;
> +			gpios = <&sgpio_out 8 0 GPIO_ACTIVE_LOW>;
> +			default-state = "off";
> +		};
> +
> +		led-sfp3-yellow {
> +			color = <LED_COLOR_ID_YELLOW>;
> +			function = LED_FUNCTION_LAN;
> +			function-enumerator = <2>;
> +			gpios = <&sgpio_out 8 1 GPIO_ACTIVE_LOW>;
> +			default-state = "off";
> +		};
> +
> +		led-sfp4-green {
> +			color = <LED_COLOR_ID_GREEN>;
> +			function = LED_FUNCTION_LAN;
> +			function-enumerator = <3>;
> +			gpios = <&sgpio_out 9 0 GPIO_ACTIVE_LOW>;
> +			default-state = "off";
> +		};
> +
> +		led-sfp4-yellow {
> +			color = <LED_COLOR_ID_YELLOW>;
> +			function = LED_FUNCTION_LAN;
> +			function-enumerator = <3>;
> +			gpios = <&sgpio_out 9 1 GPIO_ACTIVE_LOW>;
> +			default-state = "off";
> +		};
> +	};
> +
> +	mux-controller {
> +		compatible = "gpio-mux";
> +		#mux-control-cells = <0>;
> +

This line could be dropped.

> +		mux-gpios = <&sgpio_out 1 2 GPIO_ACTIVE_LOW>,
> +			    <&sgpio_out 1 3 GPIO_ACTIVE_LOW>;
> +	};
> +
> +	sfp0: sfp0 {
> +		compatible = "sff,sfp";
> +		i2c-bus = <&i2c_sfp0>;
> +		tx-disable-gpios = <&sgpio_out 6 2 GPIO_ACTIVE_HIGH>;
> +		los-gpios = <&sgpio_in 6 0 GPIO_ACTIVE_HIGH>;
> +		mod-def0-gpios = <&sgpio_in 6 1 GPIO_ACTIVE_LOW>;
> +		tx-fault-gpios = <&sgpio_in 6 2 GPIO_ACTIVE_HIGH>;
> +	};
> +
> +	sfp1: sfp1 {
> +		compatible = "sff,sfp";
> +		i2c-bus = <&i2c_sfp1>;
> +		tx-disable-gpios = <&sgpio_out 7 2 GPIO_ACTIVE_HIGH>;
> +		los-gpios = <&sgpio_in 7 0 GPIO_ACTIVE_HIGH>;
> +		mod-def0-gpios = <&sgpio_in 7 1 GPIO_ACTIVE_LOW>;
> +		tx-fault-gpios = <&sgpio_in 7 2 GPIO_ACTIVE_HIGH>;
> +	};
> +
> +	sfp2: sfp2 {
> +		compatible = "sff,sfp";
> +		i2c-bus = <&i2c_sfp2>;
> +		tx-disable-gpios = <&sgpio_out 8 2 GPIO_ACTIVE_HIGH>;
> +		los-gpios = <&sgpio_in 8 0 GPIO_ACTIVE_HIGH>;
> +		mod-def0-gpios = <&sgpio_in 8 1 GPIO_ACTIVE_LOW>;
> +		tx-fault-gpios = <&sgpio_in 8 2 GPIO_ACTIVE_HIGH>;
> +	};
> +
> +	sfp3: sfp3 {
> +		compatible = "sff,sfp";
> +		i2c-bus = <&i2c_sfp3>;
> +		tx-disable-gpios = <&sgpio_out 9 2 GPIO_ACTIVE_HIGH>;
> +		los-gpios = <&sgpio_in 9 0 GPIO_ACTIVE_HIGH>;
> +		mod-def0-gpios = <&sgpio_in 9 1 GPIO_ACTIVE_LOW>;
> +		tx-fault-gpios = <&sgpio_in 9 2 GPIO_ACTIVE_HIGH>;
> +	};
> +};
> +
> +&flx0 {
> +	atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_USART>;
> +	status = "okay";
> +};
> +
> +&usart0 {
> +	pinctrl-0 = <&fc0_pins>;
> +	pinctrl-names = "default";
> +	status = "okay";
> +};

Although, I understand why flexcom inner node labels were kept near their
corresponding parent labels (and I know there is at least one board file
that follow this approach), I tend to go forward with the approach that was
proposed by Horatiu in [1], thus everything alphanumerically sorted, if
everyone is OK with this.

[1]
https://lore.kernel.org/all/20251201082629.2326339-3-horatiu.vultur at microchip.com

> +
> +&flx2 {
> +	atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_SPI>;
> +	status = "okay";
> +};
> +
> +&spi2 {
> +	pinctrl-0 = <&fc2_pins>;
> +	pinctrl-names = "default";
> +	cs-gpios = <&gpio 63 GPIO_ACTIVE_LOW>;
> +	status = "okay";
> +};
> +
> +&flx3 {
> +	atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_TWI>;
> +	status = "okay";
> +};
> +
> +&i2c3 {
> +	pinctrl-0 = <&fc3_pins>;
> +	pinctrl-names = "default";
> +	i2c-analog-filter;
> +	i2c-digital-filter;
> +	i2c-digital-filter-width-ns = <35>;
> +	i2c-sda-hold-time-ns = <1500>;
> +	status = "okay";
> +};
> +
> +&gpio {
> +	emmc_sd_pins: emmc-sd-pins {
> +		/* eMMC_SD - CMD, CLK, D0, D1, D2, D3, D4, D5, D6, D7, RSTN */
> +		pins = "GPIO_14", "GPIO_15", "GPIO_16", "GPIO_17",
> +		       "GPIO_18", "GPIO_19", "GPIO_20", "GPIO_21",
> +		       "GPIO_22", "GPIO_23", "GPIO_24";
> +		function = "emmc_sd";
> +	};
> +
> +	fan_pins: fan-pins {
> +		pins = "GPIO_25", "GPIO_26";
> +		function = "fan";
> +	};
> +
> +	fc0_pins: fc0-pins {
> +		pins = "GPIO_3", "GPIO_4";
> +		function = "fc";
> +	};
> +
> +	fc2_pins: fc2-pins {
> +		pins = "GPIO_64", "GPIO_65", "GPIO_66";
> +		function = "fc";
> +	};
> +
> +	fc3_pins: fc3-pins {
> +		pins = "GPIO_55", "GPIO_56";
> +		function = "fc";
> +	};
> +
> +	mdio_pins: mdio-pins {
> +		pins = "GPIO_9", "GPIO_10";
> +		function = "miim";
> +	};
> +
> +	mdio_irq_pins: mdio-irq-pins {
> +		pins = "GPIO_11";
> +		function = "miim_irq";
> +	};
> +
> +	sgpio_pins: sgpio-pins {
> +		/* SCK, D0, D1, LD */
> +		pins = "GPIO_5", "GPIO_6", "GPIO_7", "GPIO_8";
> +		function = "sgpio_a";
> +	};
> +
> +	usb_ulpi_pins: usb-ulpi-pins {
> +		pins = "GPIO_30", "GPIO_31", "GPIO_32", "GPIO_33",
> +		"GPIO_34", "GPIO_35", "GPIO_36", "GPIO_37",

Please align it to the above "GPIO_30" as it has been done for emmc.

> +		"GPIO_38", "GPIO_39", "GPIO_40", "GPIO_41";
> +		function = "usb_ulpi";
> +	};
> +
> +	usb_rst_pins: usb-rst-pins {
> +		pins = "GPIO_12";
> +		function = "usb2phy_rst";
> +	};
> +
> +	usb_over_pins: usb-over-pins {
> +		pins = "GPIO_13";
> +		function = "usb_over_detect";
> +	};
> +
> +	usb_power_pins: usb-power-pins {
> +		pins = "GPIO_1";
> +		function = "usb_power";
> +	};
> +
> +	ptp_out_pins: ptp-out-pins {
> +		pins = "GPIO_58";
> +		function = "ptpsync_4";
> +	};
> +
> +	ptp_ext_pins: ptp-ext-pins {
> +		pins = "GPIO_59";
> +		function = "ptpsync_5";
> +	};
> +};
> +
> +&tmon {

Keep entries alphanumerically sorted, thus after mdio0.

> +	pinctrl-0 = <&fan_pins>;
> +	pinctrl-names = "default";
> +};
> +
> +&mdio0 {
> +	pinctrl-0 = <&mdio_pins>, <&mdio_irq_pins>;
> +	pinctrl-names = "default";
> +	reset-gpios = <&gpio 62 GPIO_ACTIVE_LOW>;
> +	status = "okay";
> +
> +	phy3: phy at 3 {
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reg = <3>;
> +		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-parent = <&gpio>;
> +	};
> +
> +	phy4: phy at 4 {
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reg = <4>;
> +		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-parent = <&gpio>;
> +	};
> +
> +	phy5: phy at 5 {
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reg = <5>;
> +		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-parent = <&gpio>;
> +	};
> +
> +	phy6: phy at 6 {
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reg = <6>;
> +		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-parent = <&gpio>;
> +	};
> +
> +	phy7: phy at 7 {
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reg = <7>;
> +		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-parent = <&gpio>;
> +	};
> +
> +	phy8: phy at 8 {
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reg = <8>;
> +		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-parent = <&gpio>;
> +	};
> +
> +	phy9: phy at 9 {
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reg = <9>;
> +		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-parent = <&gpio>;
> +	};
> +
> +	phy10: phy at 10 {
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reg = <10>;
> +		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-parent = <&gpio>;
> +	};
> +
> +	phy11: phy at 11 {
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reg = <11>;
> +		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-parent = <&gpio>;
> +	};
> +
> +	phy12: phy at 12 {
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reg = <12>;
> +		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-parent = <&gpio>;
> +	};
> +
> +	phy13: phy at 13 {
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reg = <13>;
> +		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-parent = <&gpio>;
> +	};
> +
> +	phy14: phy at 14 {
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reg = <14>;
> +		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-parent = <&gpio>;
> +	};
> +
> +	phy15: phy at 15 {
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reg = <15>;
> +		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-parent = <&gpio>;
> +	};
> +
> +	phy16: phy at 16 {
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reg = <16>;
> +		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-parent = <&gpio>;
> +	};
> +
> +	phy17: phy at 17 {
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reg = <17>;
> +		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-parent = <&gpio>;
> +	};
> +
> +	phy18: phy at 18 {
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reg = <18>;
> +		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-parent = <&gpio>;
> +	};
> +
> +	phy19: phy at 19 {
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reg = <19>;
> +		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-parent = <&gpio>;
> +	};
> +
> +	phy20: phy at 20 {
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reg = <20>;
> +		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-parent = <&gpio>;
> +	};
> +
> +	phy21: phy at 21 {
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reg = <21>;
> +		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-parent = <&gpio>;
> +	};
> +
> +	phy22: phy at 22 {
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reg = <22>;
> +		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-parent = <&gpio>;
> +	};
> +
> +	phy23: phy at 23 {
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reg = <23>;
> +		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-parent = <&gpio>;
> +	};
> +
> +	phy24: phy at 24 {
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reg = <24>;
> +		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-parent = <&gpio>;
> +	};
> +
> +	phy25: phy at 25 {
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reg = <25>;
> +		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-parent = <&gpio>;
> +	};
> +
> +	phy26: phy at 26 {
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reg = <26>;
> +		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-parent = <&gpio>;
> +	};
> +
> +	phy27: phy at 27 {
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reg = <27>;
> +		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-parent = <&gpio>;
> +	};
> +};
> +
> +&serdes {
> +	status = "okay";
> +};
> +
> +&sgpio {
> +	pinctrl-0 = <&sgpio_pins>;
> +	pinctrl-names = "default";
> +

Please drop this line.

> +	microchip,sgpio-port-ranges = <0 1>, <6 9>;
> +	status = "okay";
> +
> +	gpio at 0 {
> +		ngpios = <128>;
> +	};
> +	gpio at 1 {
> +		ngpios = <128>;
> +	};
> +};
> +
> +&switch {
> +	pinctrl-0 = <&ptp_out_pins>, <&ptp_ext_pins>;
> +	pinctrl-names = "default";
> +

Plese drop this line.

> +	status = "okay";

And add one here.

> +	ethernet-ports {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		port0: port at 0 {
> +			reg = <0>;
> +			microchip,bandwidth = <1000>;

Vendor specific properties goes at the end of the node, before status,
according to this:
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/Documentation/devicetree/bindings/dts-coding-style.rst#n122.
Valid for the rest of the port nodes.

> +			phy-handle = <&phy4>;
> +			phy-mode = "qsgmii";
> +			phys = <&serdes 0>;
> +		};
> +
> +		port1: port at 1 {
> +			reg = <1>;
> +			microchip,bandwidth = <1000>;
> +			phy-handle = <&phy5>;
> +			phy-mode = "qsgmii";
> +			phys = <&serdes 0>;
> +		};
> +
> +		port2: port at 2 {
> +			reg = <2>;
> +			microchip,bandwidth = <1000>;
> +			phy-handle = <&phy6>;
> +			phy-mode = "qsgmii";
> +			phys = <&serdes 0>;
> +		};
> +
> +		port3: port at 3 {
> +			reg = <3>;
> +			microchip,bandwidth = <1000>;
> +			phy-handle = <&phy7>;
> +			phy-mode = "qsgmii";
> +			phys = <&serdes 0>;
> +		};
> +
> +		port4: port at 4 {
> +			reg = <4>;
> +			microchip,bandwidth = <1000>;
> +			phy-handle = <&phy8>;
> +			phy-mode = "qsgmii";
> +			phys = <&serdes 1>;
> +		};
> +
> +		port5: port at 5 {
> +			reg = <5>;
> +			microchip,bandwidth = <1000>;
> +			phy-handle = <&phy9>;
> +			phy-mode = "qsgmii";
> +			phys = <&serdes 1>;
> +		};
> +
> +		port6: port at 6 {
> +			reg = <6>;
> +			microchip,bandwidth = <1000>;
> +			phy-handle = <&phy10>;
> +			phy-mode = "qsgmii";
> +			phys = <&serdes 1>;
> +		};
> +
> +		port7: port at 7 {
> +			reg = <7>;
> +			microchip,bandwidth = <1000>;
> +			phy-handle = <&phy11>;
> +			phy-mode = "qsgmii";
> +			phys = <&serdes 1>;
> +		};
> +
> +		port8: port at 8 {
> +			reg = <8>;
> +			microchip,bandwidth = <1000>;
> +			phy-handle = <&phy12>;
> +			phy-mode = "qsgmii";
> +			phys = <&serdes 2>;
> +		};
> +
> +		port9: port at 9 {
> +			reg = <9>;
> +			microchip,bandwidth = <1000>;
> +			phy-handle = <&phy13>;
> +			phy-mode = "qsgmii";
> +			phys = <&serdes 2>;
> +		};
> +
> +		port10: port at 10 {
> +			reg = <10>;
> +			microchip,bandwidth = <1000>;
> +			phy-handle = <&phy14>;
> +			phy-mode = "qsgmii";
> +			phys = <&serdes 2>;
> +		};
> +
> +		port11: port at 11 {
> +			reg = <11>;
> +			microchip,bandwidth = <1000>;
> +			phy-handle = <&phy15>;
> +			phy-mode = "qsgmii";
> +			phys = <&serdes 2>;
> +		};
> +
> +		port12: port at 12 {
> +			reg = <12>;
> +			microchip,bandwidth = <1000>;
> +			phy-handle = <&phy16>;
> +			phy-mode = "qsgmii";
> +			phys = <&serdes 3>;
> +		};
> +
> +		port13: port at 13 {
> +			reg = <13>;
> +			microchip,bandwidth = <1000>;
> +			phy-handle = <&phy17>;
> +			phy-mode = "qsgmii";
> +			phys = <&serdes 3>;
> +		};
> +
> +		port14: port at 14 {
> +			reg = <14>;
> +			microchip,bandwidth = <1000>;
> +			phy-handle = <&phy18>;
> +			phy-mode = "qsgmii";
> +			phys = <&serdes 3>;
> +		};
> +
> +		port15: port at 15 {
> +			reg = <15>;
> +			microchip,bandwidth = <1000>;
> +			phy-handle = <&phy19>;
> +			phy-mode = "qsgmii";
> +			phys = <&serdes 3>;
> +		};
> +
> +		port16: port at 16 {
> +			reg = <16>;
> +			microchip,bandwidth = <1000>;
> +			phy-handle = <&phy20>;
> +			phy-mode = "qsgmii";
> +			phys = <&serdes 4>;
> +		};
> +
> +		port17: port at 17 {
> +			reg = <17>;
> +			microchip,bandwidth = <1000>;
> +			phy-handle = <&phy21>;
> +			phy-mode = "qsgmii";
> +			phys = <&serdes 4>;
> +		};
> +
> +		port18: port at 18 {
> +			reg = <18>;
> +			microchip,bandwidth = <1000>;
> +			phy-handle = <&phy22>;
> +			phy-mode = "qsgmii";
> +			phys = <&serdes 4>;
> +		};
> +
> +		port19: port at 19 {
> +			reg = <19>;
> +			microchip,bandwidth = <1000>;
> +			phy-handle = <&phy23>;
> +			phy-mode = "qsgmii";
> +			phys = <&serdes 4>;
> +		};
> +
> +		port20: port at 20 {
> +			reg = <20>;
> +			microchip,bandwidth = <1000>;
> +			phy-handle = <&phy24>;
> +			phy-mode = "qsgmii";
> +			phys = <&serdes 5>;
> +		};
> +
> +		port21: port at 21 {
> +			reg = <21>;
> +			microchip,bandwidth = <1000>;
> +			phy-handle = <&phy25>;
> +			phy-mode = "qsgmii";
> +			phys = <&serdes 5>;
> +		};
> +
> +		port22: port at 22 {
> +			reg = <22>;
> +			microchip,bandwidth = <1000>;
> +			phy-handle = <&phy26>;
> +			phy-mode = "qsgmii";
> +			phys = <&serdes 5>;
> +		};
> +
> +		port23: port at 23 {
> +			reg = <23>;
> +			microchip,bandwidth = <1000>;
> +			phy-handle = <&phy27>;
> +			phy-mode = "qsgmii";
> +			phys = <&serdes 5>;
> +		};
> +
> +		port24: port at 24 {
> +			reg = <24>;
> +			microchip,bandwidth = <10000>;
> +			phys = <&serdes 6>;
> +			phy-mode = "10gbase-r";
> +			sfp = <&sfp0>;
> +			microchip,sd-sgpio = <24>;
> +			managed = "in-band-status";
> +		};
> +
> +		port25: port at 25 {
> +			reg = <25>;
> +			microchip,bandwidth = <10000>;
> +			phys = <&serdes 7>;
> +			phy-mode = "10gbase-r";
> +			sfp = <&sfp1>;
> +			microchip,sd-sgpio = <28>;
> +			managed = "in-band-status";
> +		};
> +
> +		port26: port at 26 {
> +			reg = <26>;
> +			microchip,bandwidth = <10000>;
> +			phys = <&serdes 8>;
> +			phy-mode = "10gbase-r";
> +			sfp = <&sfp2>;
> +			microchip,sd-sgpio = <32>;
> +			managed = "in-band-status";
> +		};
> +
> +		port27: port at 27 {
> +			reg = <27>;
> +			microchip,bandwidth = <10000>;
> +			phys = <&serdes 9>;
> +			phy-mode = "10gbase-r";
> +			sfp = <&sfp3>;
> +			microchip,sd-sgpio = <36>;
> +			managed = "in-band-status";
> +		};
> +
> +		port29: port at 29 {
> +			reg = <29>;
> +			microchip,bandwidth = <1000>;
> +			phys = <&serdes 11>;
> +			phy-handle = <&phy3>;
> +			phy-mode = "rgmii";

>From chekpatch:

WARNING: phy-mode "rgmii" without comment -- delays on the PCB should be
described, otherwise use "rgmii-id"
#779: FILE: arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts:750:
+                       phy-mode = "rgmii";

> +			rx-internal-delay-ps = <1000>;
> +			tx-internal-delay-ps = <1000>;
> +		};
> +	};
> +};
> +
> +&usb {
> +	status = "okay";

Status should be the last property in this node according to the links
shared above.

> +	pinctrl-0 = <&usb_ulpi_pins>, <&usb_rst_pins>, <&usb_over_pins>, <&usb_power_pins>;
> +	pinctrl-names = "default";
> +};
> diff --git a/arch/arm64/boot/dts/microchip/lan969x.dtsi b/arch/arm64/boot/dts/microchip/lan969x.dtsi
> new file mode 100644
> index 000000000000..39ea1999c801
> --- /dev/null
> +++ b/arch/arm64/boot/dts/microchip/lan969x.dtsi
> @@ -0,0 +1,482 @@
> +// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT)
> +/*
> + * Copyright (c) 2025 Microchip Technology Inc. and its subsidiaries.
> + */
> +
> +#include <dt-bindings/clock/microchip,lan969x.h>
> +#include <dt-bindings/dma/at91.h>
> +#include <dt-bindings/interrupt-controller/arm-gic.h>
> +#include <dt-bindings/mfd/at91-usart.h>
> +#include <dt-bindings/mfd/atmel-flexcom.h>
> +

As Conor mentioned, all nodes are missing SoC specific compatibles.

> +/ {
> +	#address-cells = <1>;
> +	#size-cells = <1>;
> +
> +	model = "Microchip LAN969x";
> +	compatible = "microchip,lan969x";
> +	interrupt-parent = <&gic>;
> +
> +	psci {
> +		compatible = "arm,psci-1.0";
> +		method = "smc";
> +	};

Keep it alphanumerically sorted.

> +
> +	clocks {
> +		fx100_clk: fx100-clk {
> +			compatible = "fixed-clock";
> +			#clock-cells = <0>;
> +			clock-frequency = <320000000>;
> +		};
> +
> +		cpu_clk: cpu-clk {
> +			compatible = "fixed-clock";
> +			#clock-cells = <0>;
> +			clock-frequency = <1000000000>;
> +		};
> +
> +		ddr_clk: ddr-clk {
> +			compatible = "fixed-clock";
> +			#clock-cells = <0>;
> +			clock-frequency = <600000000>;
> +		};
> +
> +		fabric_clk: fabric-clk {
> +			compatible = "fixed-clock";
> +			#clock-cells = <0>;
> +			clock-frequency = <250000000>;
> +		};
> +	};
> +
> +	cpus {
> +		#address-cells = <2>;
> +		#size-cells = <0>;
> +
> +		cpu0: cpu at 0 {
> +			compatible = "arm,cortex-a53";
> +			device_type = "cpu";
> +			reg = <0x0 0x0>;
> +			next-level-cache = <&l2_0>;
> +		};
> +
> +		l2_0: l2-cache {
> +			compatible = "cache";
> +			cache-level = <2>;
> +			cache-unified;
> +		};
> +	};
> +
> +	pmu {
> +		compatible = "arm,cortex-a53-pmu";
> +		interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
> +	};
> +
> +	timer {
> +		compatible = "arm,armv8-timer";
> +		interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>, /* Secure Phys IRQ */
> +			     <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>, /* Non-secure Phys IRQ */
> +			     <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>, /* Virt IRQ */
> +			     <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>; /* Hyp IRQ */
> +	};
> +
> +	axi: axi {
> +		compatible = "simple-bus";
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		ranges;
> +
> +		usb: usb at 300000 {
> +			compatible = "microchip,lan9691-dwc3", "snps,dwc3";
> +			reg = <0x300000 0x80000>;
> +			interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
> +			clocks = <&clks GCK_GATE_USB_DRD>,
> +				 <&clks GCK_ID_USB_REFCLK>;
> +			clock-names = "bus_early", "ref";
> +			assigned-clocks = <&clks GCK_ID_USB_REFCLK>;
> +			assigned-clock-rates = <60000000>;
> +			maximum-speed = "high-speed";
> +			dr_mode = "host";
> +			status = "disabled";
> +		};
> +
> +		flx0: flexcom at e0040000 {
> +			compatible = "atmel,sama5d2-flexcom";
> +			reg = <0xe0040000 0x100>;

ranges would be here according to the dts coding style pointed above.

> +			clocks = <&clks GCK_ID_FLEXCOM0>;
> +			#address-cells = <1>;
> +			#size-cells = <1>;
> +			ranges = <0x0 0xe0040000 0x800>;
> +			status = "disabled";
> +
> +			usart0: serial at 200 {
> +				compatible = "atmel,at91sam9260-usart";
> +				reg = <0x200 0x200>;
> +				atmel,usart-mode = <AT91_USART_MODE_SERIAL>;

Please keep vendor specific properties toward the end of the node as
pointed above.

> +				interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
> +				dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
> +				       <&dma AT91_XDMAC_DT_PERID(2)>;
> +				dma-names = "tx", "rx";
> +				clocks = <&fabric_clk>;
> +				clock-names = "usart";
> +				atmel,fifo-size = <32>;
> +				status = "disabled";
> +			};
> +
> +			spi0: spi at 400 {
> +				compatible = "atmel,at91rm9200-spi";
> +				reg = <0x400 0x200>;
> +				interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
> +				dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
> +				       <&dma AT91_XDMAC_DT_PERID(2)>;
> +				dma-names = "tx", "rx";
> +				clocks = <&fabric_clk>;
> +				clock-names = "spi_clk";
> +				atmel,fifo-size = <32>;

Please move this line before the status one.

> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +				status = "disabled";
> +			};
> +
> +			i2c0: i2c at 600 {
> +				compatible = "microchip,sam9x60-i2c";
> +				reg = <0x600 0x200>;
> +				interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
> +				dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
> +				       <&dma AT91_XDMAC_DT_PERID(2)>;
> +				dma-names = "tx", "rx";
> +				clocks = <&fabric_clk>;
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +				status = "disabled";
> +			};
> +		};
> +
> +		flx1: flexcom at e0044000 {
> +			compatible = "atmel,sama5d2-flexcom";
> +			reg = <0xe0044000 0x100>;

Please move the ranges here.

> +			clocks = <&clks GCK_ID_FLEXCOM1>;
> +			#address-cells = <1>;
> +			#size-cells = <1>;
> +			ranges = <0x0 0xe0044000 0x800>;
> +			status = "disabled";
> +
> +			usart1: serial at 200 {
> +				compatible = "atmel,at91sam9260-usart";
> +				reg = <0x200 0x200>;
> +				atmel,usart-mode = <AT91_USART_MODE_SERIAL>;

Please move this one close to atmel,fifo-size

> +				interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
> +				dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
> +				       <&dma AT91_XDMAC_DT_PERID(2)>;
> +				dma-names = "tx", "rx";
> +				clocks = <&fabric_clk>;
> +				clock-names = "usart";
> +				atmel,fifo-size = <32>;
> +				status = "disabled";
> +			};
> +
> +			spi1: spi at 400 {
> +				compatible = "atmel,at91rm9200-spi";
> +				reg = <0x400 0x200>;
> +				interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
> +				dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
> +				       <&dma AT91_XDMAC_DT_PERID(2)>;
> +				dma-names = "tx", "rx";
> +				clocks = <&fabric_clk>;
> +				clock-names = "spi_clk";
> +				atmel,fifo-size = <32>;

Please move this one before status.

> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +				status = "disabled";
> +			};
> +
> +			i2c1: i2c at 600 {
> +				compatible = "microchip,sam9x60-i2c";
> +				reg = <0x600 0x200>;
> +				interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
> +				dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
> +				       <&dma AT91_XDMAC_DT_PERID(2)>;
> +				dma-names = "tx", "rx";
> +				clocks = <&fabric_clk>;
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +				status = "disabled";
> +			};
> +		};
> +
> +		trng: rng at e0048000 {
> +			compatible = "atmel,at91sam9g45-trng";
> +			reg = <0xe0048000 0x100>;
> +			clocks = <&fabric_clk>;
> +			status = "disabled";
> +		};
> +
> +		aes: crypto at e004c000 {
> +			compatible = "atmel,at91sam9g46-aes";
> +			reg = <0xe004c000 0x100>;
> +			interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
> +			dmas = <&dma AT91_XDMAC_DT_PERID(12)>,
> +			       <&dma AT91_XDMAC_DT_PERID(13)>;
> +			dma-names = "tx", "rx";
> +			clocks = <&fabric_clk>;
> +			clock-names = "aes_clk";
> +			status = "disabled";
> +		};
> +
> +		flx2: flexcom at e0060000 {
> +			compatible = "atmel,sama5d2-flexcom";
> +			reg = <0xe0060000 0x100>;

ranges would go here.

> +			clocks = <&clks GCK_ID_FLEXCOM2>;
> +			#address-cells = <1>;
> +			#size-cells = <1>;
> +			ranges = <0x0 0xe0060000 0x800>;
> +			status = "disabled";
> +
> +			usart2: serial at 200 {
> +				compatible = "atmel,at91sam9260-usart";
> +				reg = <0x200 0x200>;
> +				atmel,usart-mode = <AT91_USART_MODE_SERIAL>;

Please move this close to atmel,fifo-size.

> +				interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
> +				dmas = <&dma AT91_XDMAC_DT_PERID(7)>,
> +				       <&dma AT91_XDMAC_DT_PERID(6)>;
> +				dma-names = "tx", "rx";
> +				clocks = <&fabric_clk>;
> +				clock-names = "usart";
> +				atmel,fifo-size = <32>;
> +				status = "disabled";
> +			};
> +
> +			spi2: spi at 400 {
> +				compatible = "atmel,at91rm9200-spi";
> +				reg = <0x400 0x200>;
> +				interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
> +				dmas = <&dma AT91_XDMAC_DT_PERID(7)>,
> +				       <&dma AT91_XDMAC_DT_PERID(6)>;
> +				dma-names = "tx", "rx";
> +				clocks = <&fabric_clk>;
> +				clock-names = "spi_clk";
> +				atmel,fifo-size = <32>;

Please move this one before status.

> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +				status = "disabled";
> +			};
> +
> +			i2c2: i2c at 600 {
> +				compatible = "microchip,sam9x60-i2c";
> +				reg = <0x600 0x200>;
> +				interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
> +				clocks = <&fabric_clk>;

No DMA for this node?

> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +				status = "disabled";
> +			};
> +		};
> +
> +		flx3: flexcom at e0064000 {
> +			compatible = "atmel,sama5d2-flexcom";
> +			reg = <0xe0064000 0x100>;

ranges would go here.

> +			clocks = <&clks GCK_ID_FLEXCOM3>;
> +			#address-cells = <1>;
> +			#size-cells = <1>;
> +			ranges = <0x0 0xe0064000 0x800>;
> +			status = "disabled";
> +
> +			usart3: serial at 200 {
> +				compatible = "atmel,at91sam9260-usart";
> +				reg = <0x200 0x200>;
> +				atmel,usart-mode = <AT91_USART_MODE_SERIAL>;

This line should go close to atmel,fifo-size

> +				interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
> +				dmas = <&dma AT91_XDMAC_DT_PERID(9)>,
> +				       <&dma AT91_XDMAC_DT_PERID(8)>;
> +				dma-names = "tx", "rx";
> +				clocks = <&fabric_clk>;
> +				clock-names = "usart";
> +				atmel,fifo-size = <32>;
> +				status = "disabled";
> +			};
> +
> +			spi3: spi at 400 {
> +				compatible = "atmel,at91rm9200-spi";
> +				reg = <0x400 0x200>;
> +				interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
> +				dmas = <&dma AT91_XDMAC_DT_PERID(9)>,
> +				       <&dma AT91_XDMAC_DT_PERID(8)>;
> +				dma-names = "tx", "rx";
> +				clocks = <&fabric_clk>;
> +				clock-names = "spi_clk";
> +				atmel,fifo-size = <32>;

Please move this one before status.

> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +				status = "disabled";
> +			};
> +
> +			i2c3: i2c at 600 {
> +				compatible = "microchip,sam9x60-i2c";
> +				reg = <0x600 0x200>;
> +				interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
> +				dmas = <&dma AT91_XDMAC_DT_PERID(9)>,
> +				       <&dma AT91_XDMAC_DT_PERID(8)>;
> +				dma-names = "tx", "rx";
> +				clocks = <&fabric_clk>;
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +				status = "disabled";
> +			};
> +		};
> +
> +		dma: dma-controller at e0068000 {
> +			compatible = "microchip,sama7g5-dma";
> +			reg = <0xe0068000 0x1000>;
> +			interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
> +			dma-channels = <16>;
> +			#dma-cells = <1>;
> +			clocks = <&fabric_clk>;
> +			clock-names = "dma_clk";
> +		};
> +
> +		sha: crypto at e006c000 {
> +			compatible = "atmel,at91sam9g46-sha";
> +			reg = <0xe006c000 0xec>;
> +			interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
> +			dmas = <&dma AT91_XDMAC_DT_PERID(14)>;
> +			dma-names = "tx";
> +			clocks = <&fabric_clk>;
> +			clock-names = "sha_clk";
> +			status = "disabled";
> +		};
> +
> +		timer: timer at e008c000 {
> +			compatible = "snps,dw-apb-timer";
> +			reg = <0xe008c000 0x400>;
> +			clocks = <&fabric_clk>;
> +			clock-names = "timer";
> +			interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
> +			status = "disabled";
> +		};
> +
> +		watchdog: watchdog at e0090000 {
> +			compatible = "snps,dw-wdt";
> +			reg = <0xe0090000 0x1000>;
> +			interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
> +			clocks = <&fabric_clk>;
> +		};
> +
> +		cpu_ctrl: syscon at e00c0000 {
> +			compatible = "microchip,lan966x-cpu-syscon", "syscon";
> +			reg = <0xe00c0000 0x350>;
> +		};
> +
> +		switch: switch at e00c0000 {
> +			compatible = "microchip,lan9691-switch";
> +			reg = <0xe00c0000 0x0010000>,
> +			      <0xe2010000 0x1410000>;
> +			reg-names = "cpu", "devices";
> +			interrupt-names = "xtr", "fdma", "ptp";
> +			interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
> +				     <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
> +				     <GIC_SPI  9 IRQ_TYPE_LEVEL_HIGH>;
> +			resets = <&reset 0>;
> +			reset-names = "switch";
> +			status = "disabled";
> +		};
> +
> +		clks: clock-controller at e00c00b4 {
> +			compatible = "microchip,lan9691-gck";
> +			#clock-cells = <1>;
> +			clocks = <&cpu_clk>, <&ddr_clk>, <&fx100_clk>;
> +			clock-names = "cpu", "ddr", "sys";
> +			reg = <0xe00c00b4 0x30>, <0xe00c0308 0x4>;

This line should go after compatible. Please check the dts coding style
pointed above.

> +		};
> +
> +		reset: reset-controller at e201000c {
> +			compatible = "microchip,lan9691-switch-reset",
> +				     "microchip,lan966x-switch-reset";
> +			reg = <0xe201000c 0x4>;
> +			reg-names = "gcb";
> +			#reset-cells = <1>;
> +			cpu-syscon = <&cpu_ctrl>;
> +		};
> +
> +		gpio: pinctrl at e20100d4 {
> +			compatible = "microchip,lan9691-pinctrl";
> +			reg = <0xe20100d4 0xd4>,
> +			      <0xe2010370 0xa8>;
> +			gpio-controller;
> +			#gpio-cells = <2>;
> +			gpio-ranges = <&gpio 0 0 66>;
> +			interrupt-controller;
> +			interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
> +			#interrupt-cells = <2>;
> +		};
> +
> +		mdio0: mdio at e20101a8 {
> +			compatible = "mscc,ocelot-miim";
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <0xe20101a8 0x24>;

Same here, please follow the dts coding style.

> +			clocks = <&fx100_clk>;
> +			status = "disabled";
> +		};
> +
> +		mdio1: mdio at e20101cc {
> +			compatible = "mscc,ocelot-miim";
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <0xe20101cc 0x24>;

Same here

> +			clocks = <&fx100_clk>;
> +			status = "disabled";
> +		};
> +
> +		sgpio: gpio at e2010230 {
> +			compatible = "microchip,sparx5-sgpio";
> +			reg = <0xe2010230 0x118>;
> +			clocks = <&fx100_clk>;
> +			resets = <&reset 0>;
> +			reset-names = "switch";
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			status = "disabled";
> +
> +			sgpio_in: gpio at 0 {
> +				compatible = "microchip,sparx5-sgpio-bank";
> +				reg = <0>;
> +				gpio-controller;
> +				#gpio-cells = <3>;
> +				interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
> +				interrupt-controller;
> +				#interrupt-cells = <3>;
> +			};
> +
> +			sgpio_out: gpio at 1 {
> +				compatible = "microchip,sparx5-sgpio-bank";
> +				reg = <1>;
> +				gpio-controller;
> +				#gpio-cells = <3>;
> +			};
> +		};
> +
> +		tmon: hwmon at e2020100 {
> +			compatible = "microchip,sparx5-temp";
> +			reg = <0xe2020100 0xc>;
> +			clocks = <&fx100_clk>;
> +			#thermal-sensor-cells = <0>;
> +		};
> +
> +		serdes: serdes at e3410000 {
> +			compatible = "microchip,lan9691-serdes";
> +			#phy-cells = <1>;
> +			clocks = <&fabric_clk>;
> +			reg = <0xe3410000 0x150000>;

Same here.

> +		};
> +
> +		gic: interrupt-controller at e8c11000 {
> +			compatible = "arm,gic-400";
> +			#interrupt-cells = <3>;
> +			interrupt-controller;
> +			reg = <0xe8c11000 0x1000>, /* Distributor GICD_ */
> +			      <0xe8c12000 0x2000>, /* CPU interface GICC_ */
> +			      <0xe8c14000 0x2000>, /* Virt interface control */
> +			      <0xe8c16000 0x2000>; /* Virt CPU interface */

Same here.

> +			interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
> +		};
> +	};
> +};

Thank you,
Claudiu


From sashal at kernel.org  Sat Dec  6 06:02:15 2025
From: sashal at kernel.org (Sasha Levin)
Date: Sat,  6 Dec 2025 09:02:15 -0500
Subject: [PATCH AUTOSEL 6.18-6.12] Bluetooth: btusb: MT7922: Add VID/PID 0489/e170
In-Reply-To: <20251206140252.645973-1-sashal@kernel.org>
References: <20251206140252.645973-1-sashal@kernel.org>
Message-ID: <20251206140252.645973-10-sashal@kernel.org>

From: Chris Lu <chris.lu at mediatek.com>

[ Upstream commit 5a6700a31c953af9a17a7e2681335f31d922614d ]

Add VID 0489 & PID e170 for MediaTek MT7922 USB Bluetooth chip.

The information in /sys/kernel/debug/usb/devices about the Bluetooth
device is listed as the below.

T:  Bus=06 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=480  MxCh= 0
D:  Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=0489 ProdID=e170 Rev= 1.00
S:  Manufacturer=MediaTek Inc.
S:  Product=Wireless_Device
S:  SerialNumber=000000000
C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA
A:  FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01
I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=125us
E:  Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
I:  If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
I:  If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
I:  If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
I:  If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
I:  If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
I:  If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  63 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  63 Ivl=1ms
I:* If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
E:  Ad=8a(I) Atr=03(Int.) MxPS=  64 Ivl=125us
E:  Ad=0a(O) Atr=03(Int.) MxPS=  64 Ivl=125us
I:  If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
E:  Ad=8a(I) Atr=03(Int.) MxPS= 512 Ivl=125us
E:  Ad=0a(O) Atr=03(Int.) MxPS= 512 Ivl=125us

Signed-off-by: Chris Lu <chris.lu at mediatek.com>
Reviewed-by: Paul Menzel <pmenzel at molgen.mpg.de>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz at intel.com>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---

LLM Generated explanations, may be completely bogus:



 drivers/bluetooth/btusb.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index c70e79e69be8d..36f18f2657ab8 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -685,6 +685,8 @@ static const struct usb_device_id quirks_table[] = {
 						     BTUSB_WIDEBAND_SPEECH },
 	{ USB_DEVICE(0x0489, 0xe153), .driver_info = BTUSB_MEDIATEK |
 						     BTUSB_WIDEBAND_SPEECH },
+	{ USB_DEVICE(0x0489, 0xe170), .driver_info = BTUSB_MEDIATEK |
+						     BTUSB_WIDEBAND_SPEECH },
 	{ USB_DEVICE(0x04ca, 0x3804), .driver_info = BTUSB_MEDIATEK |
 						     BTUSB_WIDEBAND_SPEECH },
 	{ USB_DEVICE(0x04ca, 0x38e4), .driver_info = BTUSB_MEDIATEK |
-- 
2.51.0



From sashal at kernel.org  Sat Dec  6 06:02:14 2025
From: sashal at kernel.org (Sasha Levin)
Date: Sat,  6 Dec 2025 09:02:14 -0500
Subject: [PATCH AUTOSEL 6.18-6.12] Bluetooth: btusb: MT7920: Add VID/PID 0489/e135
In-Reply-To: <20251206140252.645973-1-sashal@kernel.org>
References: <20251206140252.645973-1-sashal@kernel.org>
Message-ID: <20251206140252.645973-9-sashal@kernel.org>

From: Chris Lu <chris.lu at mediatek.com>

[ Upstream commit c126f98c011f5796ba118ef2093122d02809d30d ]

Add VID 0489 & PID e135 for MediaTek MT7920 USB Bluetooth chip.

The information in /sys/kernel/debug/usb/devices about the Bluetooth
device is listed as the below.

T:  Bus=06 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=480  MxCh= 0
D:  Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=0489 ProdID=e135 Rev= 1.00
S:  Manufacturer=MediaTek Inc.
S:  Product=Wireless_Device
S:  SerialNumber=000000000
C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA
A:  FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01
I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=125us
E:  Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
I:  If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
I:  If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
I:  If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
I:  If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
I:  If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
I:  If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  63 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  63 Ivl=1ms
I:* If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
E:  Ad=8a(I) Atr=03(Int.) MxPS=  64 Ivl=125us
E:  Ad=0a(O) Atr=03(Int.) MxPS=  64 Ivl=125us
I:  If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
E:  Ad=8a(I) Atr=03(Int.) MxPS=  64 Ivl=125us
E:  Ad=0a(O) Atr=03(Int.) MxPS=  64 Ivl=125us

Signed-off-by: Chris Lu <chris.lu at mediatek.com>
Reviewed-by: Paul Menzel <pmenzel at molgen.mpg.de>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz at intel.com>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---

LLM Generated explanations, may be completely bogus:



 drivers/bluetooth/btusb.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 36f18f2657ab8..cc03c8c38b16f 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -621,6 +621,8 @@ static const struct usb_device_id quirks_table[] = {
 	/* Additional MediaTek MT7920 Bluetooth devices */
 	{ USB_DEVICE(0x0489, 0xe134), .driver_info = BTUSB_MEDIATEK |
 						     BTUSB_WIDEBAND_SPEECH },
+	{ USB_DEVICE(0x0489, 0xe135), .driver_info = BTUSB_MEDIATEK |
+						     BTUSB_WIDEBAND_SPEECH },
 	{ USB_DEVICE(0x13d3, 0x3620), .driver_info = BTUSB_MEDIATEK |
 						     BTUSB_WIDEBAND_SPEECH },
 	{ USB_DEVICE(0x13d3, 0x3621), .driver_info = BTUSB_MEDIATEK |
-- 
2.51.0



From sashal at kernel.org  Sat Dec  6 06:02:29 2025
From: sashal at kernel.org (Sasha Levin)
Date: Sat,  6 Dec 2025 09:02:29 -0500
Subject: [PATCH AUTOSEL 6.18-6.12] wifi: mt76: mt792x: fix wifi init fail by setting MCU_RUNNING after CLC load
In-Reply-To: <20251206140252.645973-1-sashal@kernel.org>
References: <20251206140252.645973-1-sashal@kernel.org>
Message-ID: <20251206140252.645973-24-sashal@kernel.org>

From: Quan Zhou <quan.zhou at mediatek.com>

[ Upstream commit 066f417be5fd8c7fe581c5550206364735dad7a3 ]

Set the MT76_STATE_MCU_RUNNING bit only after mt7921_load_clc()
has successfully completed. Previously, the MCU_RUNNING state
was set before loading CLC, which could cause conflict between
chip mcu_init retry and mac_reset flow, result in chip init fail
and chip abnormal status. By moving the state set after CLC load,
firmware initialization becomes robust and resolves init fail issue.

Signed-off-by: Quan Zhou <quan.zhou at mediatek.com>
Reviewed-by: druth at chromium.org
Link: https://patch.msgid.link/19ec8e4465142e774f17801025accd0ae2214092.1763465933.git.quan.zhou at mediatek.com
Signed-off-by: Felix Fietkau <nbd at nbd.name>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---

LLM Generated explanations, may be completely bogus:

# Commit Analysis: wifi: mt76: mt792x: fix wifi init fail by setting
MCU_RUNNING after CLC load

## 1. COMMIT MESSAGE ANALYSIS

**Subject:** Clearly indicates a bug fix ("fix wifi init fail")

**Problem described:** Setting `MT76_STATE_MCU_RUNNING` bit before CLC
(Country/Legal Configuration) load completion could cause conflicts
between MCU init retry and mac_reset flows, resulting in chip
initialization failure and abnormal chip status.

**Tags present:**
- `Signed-off-by:` Quan Zhou (MediaTek - chip vendor) and Felix Fietkau
  (mt76 maintainer)
- `Reviewed-by:` druth at chromium.org (Chrome OS kernel team - indicates
  real-world Chromebook impact)
- No explicit `Cc: stable at vger.kernel.org` tag
- No explicit `Fixes:` tag

## 2. CODE CHANGE ANALYSIS

The change is extremely simple and surgical:

**Before the fix:**
```c
set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);  // State set here
err = mt7921_load_clc(dev, mt792x_ram_name(dev));   // CLC load after
```

**After the fix:**
```c
err = mt7921_load_clc(dev, mt792x_ram_name(dev));   // CLC load first
set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);  // State set after
success
```

**Technical mechanism:**
- `MT76_STATE_MCU_RUNNING` indicates the MCU is fully operational
- Setting this flag prematurely (before CLC load) could allow other code
  paths to think the MCU is ready when it's not
- If something triggers MCU init retry or mac_reset during CLC load,
  there's a race condition
- The conflict causes complete initialization failure and abnormal chip
  state

**Why fix is correct:**
- The state bit should only be set when initialization is truly complete
- This ensures no code sees MCU_RUNNING during the vulnerable CLC
  loading phase
- Error handling remains intact (if CLC load fails, function returns
  error)

## 3. CLASSIFICATION

- **Type:** Bug fix - initialization failure fix
- **NOT** a feature addition
- Fixes a real runtime bug affecting device usability

## 4. SCOPE AND RISK ASSESSMENT

| Factor | Assessment |
|--------|------------|
| Lines changed | ~6 lines (just moving 1 line in 2 files) |
| Files touched | 2 (mt7921/mcu.c, mt7925/mcu.c) |
| Complexity | Very low - simple reordering |
| Regression risk | LOW - no logic changes, just timing |
| Subsystem | Wireless driver (contained) |

The change is almost purely a reordering operation within the same
function. If CLC load succeeds, the state gets set (same as before, just
later). If it fails, function returns error anyway.

## 5. USER IMPACT

**Affected hardware:** MediaTek mt7921 and mt7925 WiFi chips

These are **extremely common** chips found in:
- Many Chromebooks (Chrome OS review indicates this)
- Consumer laptops (Dell, Lenovo, HP, etc.)
- USB WiFi adapters
- Various PC builds

**Severity:** HIGH
- WiFi initialization failure = device doesn't work at all
- "chip abnormal status" suggests chip may be left in broken state
- Users cannot use their WiFi until reboot or driver reload

## 6. STABILITY INDICATORS

- Reviewed by Chromium kernel team (indicates real-world testing on
  Chromebooks)
- From MediaTek engineer (hardware vendor knows their chip)
- Accepted by mt76 maintainer Felix Fietkau
- Clean, minimal change with clear rationale

## 7. DEPENDENCY CHECK

The change is self-contained. It only reorders existing function calls
within `mt7921_run_firmware()` and `mt7925_run_firmware()`. No new
dependencies are introduced.

The mt7921 driver has been in stable kernels for some time. The mt7925
is newer and may not exist in older stable trees, but the mt7921 portion
would still be valuable.

## STABLE KERNEL CRITERIA CHECK

| Criterion | Met? | Notes |
|-----------|------|-------|
| Obviously correct | ? | Simple reordering, logic is clear |
| Fixes real bug | ? | WiFi init failure - real user impact |
| Small and contained | ? | 6 lines, 2 files, same subsystem |
| No new features | ? | No new APIs or functionality |
| No architectural changes | ? | Minimal change |

## RISK vs BENEFIT

**Benefit:** High - Fixes WiFi initialization failure on widely-deployed
hardware. Without this fix, affected users may have non-functional WiFi.

**Risk:** Very low - The change is a trivial reordering of two
operations. The logic remains identical; only the timing of when the
state bit is set changes. The fix has been reviewed by the chip vendor
and Chrome OS team.

## CONCLUSION

This commit is an ideal candidate for stable backporting:

1. **Fixes a real, user-visible bug** - WiFi doesn't work
2. **Minimal change** - Just reordering one line in each of two files
3. **Well-reviewed** - MediaTek and Chrome OS review
4. **Low regression risk** - No logic changes, simple timing fix
5. **High user impact** - mt7921/mt7925 are very common chips
6. **Contained scope** - Only affects initialization path of specific
   driver

The lack of `Cc: stable` tag doesn't disqualify it - many legitimate
fixes don't include this tag. The important factors are all positive: it
fixes a real bug, is small, safe, and affects real users.

**YES**

 drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 2 +-
 drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index 86bd33b916a9d..edc1df3c071e5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -646,10 +646,10 @@ int mt7921_run_firmware(struct mt792x_dev *dev)
 	if (err)
 		return err;
 
-	set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
 	err = mt7921_load_clc(dev, mt792x_ram_name(dev));
 	if (err)
 		return err;
+	set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
 
 	return mt7921_mcu_fw_log_2_host(dev, 1);
 }
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index 8eda407e4135e..c12b71b71cfc7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -1003,10 +1003,10 @@ int mt7925_run_firmware(struct mt792x_dev *dev)
 	if (err)
 		return err;
 
-	set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
 	err = mt7925_load_clc(dev, mt792x_ram_name(dev));
 	if (err)
 		return err;
+	set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
 
 	return mt7925_mcu_fw_log_2_host(dev, 1);
 }
-- 
2.51.0



From xueshuai at linux.alibaba.com  Sat Dec  6 06:19:08 2025
From: xueshuai at linux.alibaba.com (Shuai Xue)
Date: Sat, 6 Dec 2025 22:19:08 +0800
Subject: [PATCH rc v1 1/4] iommu/arm-smmu-v3: Add ignored bits to fix STE
 update sequence
In-Reply-To: <6ec73bb7cd03d90a0764f12c4b14071158163818.1764982046.git.nicolinc@nvidia.com>
References: <cover.1764982046.git.nicolinc@nvidia.com>
 <6ec73bb7cd03d90a0764f12c4b14071158163818.1764982046.git.nicolinc@nvidia.com>
Message-ID: <1af0f768-4b3d-47a3-b59b-c56f034b1d1b@linux.alibaba.com>



? 2025/12/6 08:52, Nicolin Chen ??:
> From: Jason Gunthorpe <jgg at nvidia.com>
> 
> C_BAD_STE was observed when updating nested STE from an S1-bypass mode to
> an S1DSS-bypass mode. As both modes enabled S2, the used bit is slightly
> different than the normal S1-bypass and S1DSS-bypass modes. As a result,
> fields like MEV and EATS in S2's used list marked the word1 as a critical
> word that requested a STE.V=0. This breaks a hitless update.
> 
> However, both MEV and EATS aren't critical in terms of STE update. One
> controls the merge of the events and the other controls the ATS that is
> managed by the driver at the same time via pci_enable_ats().
> 
> Add an arm_smmu_get_ste_ignored() to allow STE update algorithm to ignore
> those fields, avoiding the STE update breakages.
> 
> Note that this change is required by both MEV and EATS fields, which were
> introduced in different kernel versions. So add this get_ignored() first.
> The MEV and EATS will be added in arm_smmu_get_ste_ignored() separately.
> 
> Fixes: 1e8be08d1c91 ("iommu/arm-smmu-v3: Support IOMMU_DOMAIN_NESTED")
> Cc: stable at vger.kernel.org
> Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
> Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
> ---
>   drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  2 ++
>   .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  | 17 ++++++++++---
>   drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 24 ++++++++++++-------
>   3 files changed, 32 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> index ae23aacc3840..d5f0e5407b9f 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> @@ -900,6 +900,7 @@ struct arm_smmu_entry_writer {
>   
>   struct arm_smmu_entry_writer_ops {
>   	void (*get_used)(const __le64 *entry, __le64 *used);
> +	void (*get_ignored)(__le64 *ignored_bits);
>   	void (*sync)(struct arm_smmu_entry_writer *writer);
>   };
>   
> @@ -911,6 +912,7 @@ void arm_smmu_make_s2_domain_ste(struct arm_smmu_ste *target,
>   
>   #if IS_ENABLED(CONFIG_KUNIT)
>   void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits);
> +void arm_smmu_get_ste_ignored(__le64 *ignored_bits);
>   void arm_smmu_write_entry(struct arm_smmu_entry_writer *writer, __le64 *cur,
>   			  const __le64 *target);
>   void arm_smmu_get_cd_used(const __le64 *ent, __le64 *used_bits);
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> index d2671bfd3798..9287904c93a2 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> @@ -37,6 +37,7 @@ enum arm_smmu_test_master_feat {
>   
>   static bool arm_smmu_entry_differs_in_used_bits(const __le64 *entry,
>   						const __le64 *used_bits,
> +						const __le64 *ignored,
>   						const __le64 *target,
>   						unsigned int length)
>   {
> @@ -44,7 +45,7 @@ static bool arm_smmu_entry_differs_in_used_bits(const __le64 *entry,
>   	unsigned int i;
>   
>   	for (i = 0; i < length; i++) {
> -		if ((entry[i] & used_bits[i]) != target[i])
> +		if ((entry[i] & used_bits[i]) != (target[i] & ~ignored[i]))
>   			differs = true;
>   	}
>   	return differs;
> @@ -56,12 +57,18 @@ arm_smmu_test_writer_record_syncs(struct arm_smmu_entry_writer *writer)
>   	struct arm_smmu_test_writer *test_writer =
>   		container_of(writer, struct arm_smmu_test_writer, writer);
>   	__le64 *entry_used_bits;
> +	__le64 *ignored_bits;
>   
>   	entry_used_bits = kunit_kzalloc(
>   		test_writer->test, sizeof(*entry_used_bits) * NUM_ENTRY_QWORDS,
>   		GFP_KERNEL);
>   	KUNIT_ASSERT_NOT_NULL(test_writer->test, entry_used_bits);
>   
> +	ignored_bits = kunit_kzalloc(test_writer->test,
> +				     sizeof(*ignored_bits) * NUM_ENTRY_QWORDS,
> +				     GFP_KERNEL);
> +	KUNIT_ASSERT_NOT_NULL(test_writer->test, ignored_bits);
> +
>   	pr_debug("STE value is now set to: ");
>   	print_hex_dump_debug("    ", DUMP_PREFIX_NONE, 16, 8,
>   			     test_writer->entry,
> @@ -79,14 +86,17 @@ arm_smmu_test_writer_record_syncs(struct arm_smmu_entry_writer *writer)
>   		 * configuration.
>   		 */
>   		writer->ops->get_used(test_writer->entry, entry_used_bits);
> +		if (writer->ops->get_ignored)
> +			writer->ops->get_ignored(ignored_bits);
>   		KUNIT_EXPECT_FALSE(
>   			test_writer->test,
>   			arm_smmu_entry_differs_in_used_bits(
>   				test_writer->entry, entry_used_bits,
> -				test_writer->init_entry, NUM_ENTRY_QWORDS) &&
> +				ignored_bits, test_writer->init_entry,
> +				NUM_ENTRY_QWORDS) &&
>   				arm_smmu_entry_differs_in_used_bits(
>   					test_writer->entry, entry_used_bits,
> -					test_writer->target_entry,
> +					ignored_bits, test_writer->target_entry,
>   					NUM_ENTRY_QWORDS));
>   	}
>   }
> @@ -106,6 +116,7 @@ arm_smmu_v3_test_debug_print_used_bits(struct arm_smmu_entry_writer *writer,
>   static const struct arm_smmu_entry_writer_ops test_ste_ops = {
>   	.sync = arm_smmu_test_writer_record_syncs,
>   	.get_used = arm_smmu_get_ste_used,
> +	.get_ignored = arm_smmu_get_ste_ignored,
>   };
>   
>   static const struct arm_smmu_entry_writer_ops test_cd_ops = {
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index d16d35c78c06..95a4cfc5882d 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -1082,6 +1082,12 @@ void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits)
>   }
>   EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_used);
>   
> +VISIBLE_IF_KUNIT
> +void arm_smmu_get_ste_ignored(__le64 *ignored_bits)
> +{
> +}
> +EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_ignored);
> +
>   /*
>    * Figure out if we can do a hitless update of entry to become target. Returns a
>    * bit mask where 1 indicates that qword needs to be set disruptively.
> @@ -1094,11 +1100,14 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
>   {
>   	__le64 target_used[NUM_ENTRY_QWORDS] = {};
>   	__le64 cur_used[NUM_ENTRY_QWORDS] = {};
> +	__le64 ignored[NUM_ENTRY_QWORDS] = {};
>   	u8 used_qword_diff = 0;
>   	unsigned int i;
>   
>   	writer->ops->get_used(entry, cur_used);
>   	writer->ops->get_used(target, target_used);
> +	if (writer->ops->get_ignored)
> +		writer->ops->get_ignored(ignored);
>   
>   	for (i = 0; i != NUM_ENTRY_QWORDS; i++) {
>   		/*
> @@ -1106,16 +1115,17 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
>   		 * allowed to set a bit to 1 if the used function doesn't say it
>   		 * is used.
>   		 */

Hi, Jason,

Instead of modifying the calculation logic, would it be cleaner to keep
the original arm_smmu_get_ste_used() semantics intact and simply exclude
ignored bits from cur_used after obtaining them?

For example, simply exclude the ignored bits from cur_used after
obtaining it:

         cur_used[i] &= ~ignored[i];

> -		WARN_ON_ONCE(target[i] & ~target_used[i]);
> +		WARN_ON_ONCE(target[i] & ~target_used[i] & ~ignored[i]);

Keep arm_smmu_get_ste_used() unchanged so target_used still accurately
reflects the bits actually used by hardware, then we do not need above
changes.


>   
>   		/* Bits can change because they are not currently being used */
> -		unused_update[i] = (entry[i] & cur_used[i]) |
> +		unused_update[i] = (entry[i] & (cur_used[i] | ignored[i])) |
>   				   (target[i] & ~cur_used[i]);
>   		/*
>   		 * Each bit indicates that a used bit in a qword needs to be
>   		 * changed after unused_update is applied.
>   		 */
> -		if ((unused_update[i] & target_used[i]) != target[i])
> +		if ((unused_update[i] & target_used[i]) !=
> +		    (target[i] & ~ignored[i]))
>   			used_qword_diff |= 1 << i;

And since `ignored` bits are cleared from cur_used, applying
unused_update to target will result in target itself. So we don't need
the above changes either.

The key insight is that we only need to exclude ignored bits from
cur_used (which determines what can be updated non-disruptively), while
keeping target_used intact for both the safety check and the final
comparison.

This way, we achieve the same goal with minimal changes to the existing
logic.

Thanks.
Shuai


From lkp at intel.com  Sat Dec  6 06:24:34 2025
From: lkp at intel.com (kernel test robot)
Date: Sat, 6 Dec 2025 22:24:34 +0800
Subject: [PATCH 2/4] pwm: sun50i: Add H616 PWM support
In-Reply-To: <20251205100239.1563353-3-richard.genoud@bootlin.com>
References: <20251205100239.1563353-3-richard.genoud@bootlin.com>
Message-ID: <202512062245.KFjCln1y-lkp@intel.com>

Hi Richard,

kernel test robot noticed the following build errors:

[auto build test ERROR on 6987d58a9cbc5bd57c983baa514474a86c945d56]

url:    https://github.com/intel-lab-lkp/linux/commits/Richard-Genoud/dt-bindings-pwm-sunxi-add-PWM-controller-for-Allwinner-H616/20251205-214804
base:   6987d58a9cbc5bd57c983baa514474a86c945d56
patch link:    https://lore.kernel.org/r/20251205100239.1563353-3-richard.genoud%40bootlin.com
patch subject: [PATCH 2/4] pwm: sun50i: Add H616 PWM support
config: parisc-allyesconfig (https://download.01.org/0day-ci/archive/20251206/202512062245.KFjCln1y-lkp at intel.com/config)
compiler: hppa-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251206/202512062245.KFjCln1y-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512062245.KFjCln1y-lkp at intel.com/

All errors (new ones prefixed by >>):

   drivers/pwm/pwm-sun50i-h616.c: In function 'h616_pwm_get_state':
>> drivers/pwm/pwm-sun50i-h616.c:76:41: error: implicit declaration of function 'FIELD_GET' [-Wimplicit-function-declaration]
      76 | #define PWM_REG_DUTY(reg)               FIELD_GET(PWM_DUTY_MASK, reg)
         |                                         ^~~~~~~~~
   drivers/pwm/pwm-sun50i-h616.c:452:30: note: in expansion of macro 'PWM_REG_DUTY'
     452 |         tmp = NSEC_PER_SEC * PWM_REG_DUTY(val);
         |                              ^~~~~~~~~~~~
   drivers/pwm/pwm-sun50i-h616.c: In function 'h616_pwm_calc':
>> drivers/pwm/pwm-sun50i-h616.c:79:41: error: implicit declaration of function 'FIELD_MAX' [-Wimplicit-function-declaration]
      79 | #define PWM_PERIOD_MAX                  FIELD_MAX(PWM_PERIOD_MASK)
         |                                         ^~~~~~~~~
   drivers/pwm/pwm-sun50i-h616.c:493:54: note: in expansion of macro 'PWM_PERIOD_MAX'
     493 |                 freq = div64_u64(NSEC_PER_SEC * (u64)PWM_PERIOD_MAX, period);
         |                                                      ^~~~~~~~~~~~~~
   drivers/pwm/pwm-sun50i-h616.c: In function 'h616_pwm_apply':
>> drivers/pwm/pwm-sun50i-h616.c:78:41: error: implicit declaration of function 'FIELD_PREP' [-Wimplicit-function-declaration]
      78 | #define PWM_DUTY(dty)                   FIELD_PREP(PWM_DUTY_MASK, dty)
         |                                         ^~~~~~~~~~
   drivers/pwm/pwm-sun50i-h616.c:577:23: note: in expansion of macro 'PWM_DUTY'
     577 |                 val = PWM_DUTY(chan->active_cycles);
         |                       ^~~~~~~~
   drivers/pwm/pwm-sun50i-h616.c: In function 'h616_add_composite_clk':
   drivers/pwm/pwm-sun50i-h616.c:666:28: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
     666 |                 mux->reg = (u64)mux->reg + reg;
         |                            ^
   drivers/pwm/pwm-sun50i-h616.c:676:29: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
     676 |                 gate->reg = (u64)gate->reg + reg;
         |                             ^
   drivers/pwm/pwm-sun50i-h616.c:686:29: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
     686 |                 rate->reg = (u64)rate->reg + reg;
         |                             ^


vim +/FIELD_GET +76 drivers/pwm/pwm-sun50i-h616.c

    70	
    71	/* PWM Period Register */
    72	#define PWM_PERIOD_REG(ch)		(0x64 + (ch) * 0x20)
    73	#define PWM_PERIOD_MASK			GENMASK(31, 16)
    74	#define PWM_DUTY_MASK			GENMASK(15, 0)
    75	#define PWM_REG_PERIOD(reg)		(FIELD_GET(PWM_PERIOD_MASK, reg) + 1)
  > 76	#define PWM_REG_DUTY(reg)		FIELD_GET(PWM_DUTY_MASK, reg)
    77	#define PWM_PERIOD(prd)			FIELD_PREP(PWM_PERIOD_MASK, (prd) - 1)
  > 78	#define PWM_DUTY(dty)			FIELD_PREP(PWM_DUTY_MASK, dty)
  > 79	#define PWM_PERIOD_MAX			FIELD_MAX(PWM_PERIOD_MASK)
    80	
    81	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From lkp at intel.com  Sat Dec  6 07:11:50 2025
From: lkp at intel.com (kernel test robot)
Date: Sat, 06 Dec 2025 23:11:50 +0800
Subject: [soc:soc/arm] BUILD SUCCESS
 3ce8f4a501f61edbb5cb3fe13520f09ffb33396e
Message-ID: <202512062338.3SWEMVBe-lkp@intel.com>

tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git soc/arm
branch HEAD: 3ce8f4a501f61edbb5cb3fe13520f09ffb33396e  ARM: omap1: avoid symbol clashes in fiq handler

elapsed time: 1460m

configs tested: 178
configs skipped: 10

The following configs have been built successfully.
More configs may be tested in the coming days.

tested configs:
alpha                             allnoconfig    gcc-15.1.0
alpha                            allyesconfig    gcc-15.1.0
arc                              allmodconfig    clang-16
arc                              allmodconfig    gcc-15.1.0
arc                               allnoconfig    gcc-15.1.0
arc                              allyesconfig    clang-22
arc                   randconfig-001-20251206    clang-16
arc                   randconfig-002-20251206    clang-16
arm                               allnoconfig    gcc-15.1.0
arm                              allyesconfig    clang-16
arm                              allyesconfig    gcc-15.1.0
arm                         at91_dt_defconfig    gcc-15.1.0
arm                            hisi_defconfig    gcc-15.1.0
arm                         lpc32xx_defconfig    gcc-15.1.0
arm                             pxa_defconfig    gcc-15.1.0
arm                   randconfig-001-20251206    clang-16
arm                   randconfig-002-20251206    clang-16
arm                   randconfig-003-20251206    clang-16
arm                   randconfig-004-20251206    clang-16
arm                           u8500_defconfig    gcc-15.1.0
arm64                            allmodconfig    clang-22
arm64                             allnoconfig    gcc-15.1.0
arm64                 randconfig-001-20251206    clang-22
arm64                 randconfig-002-20251206    clang-22
arm64                 randconfig-003-20251206    clang-22
arm64                 randconfig-004-20251206    clang-22
csky                             allmodconfig    gcc-15.1.0
csky                              allnoconfig    gcc-15.1.0
csky                  randconfig-001-20251206    clang-22
csky                  randconfig-002-20251206    clang-22
hexagon                          allmodconfig    gcc-15.1.0
hexagon                           allnoconfig    gcc-15.1.0
hexagon               randconfig-001-20251206    gcc-15.1.0
hexagon               randconfig-002-20251206    gcc-15.1.0
i386                             allmodconfig    clang-20
i386                              allnoconfig    gcc-15.1.0
i386                             allyesconfig    clang-20
i386        buildonly-randconfig-001-20251206    clang-20
i386        buildonly-randconfig-002-20251206    clang-20
i386        buildonly-randconfig-003-20251206    clang-20
i386        buildonly-randconfig-004-20251206    clang-20
i386        buildonly-randconfig-005-20251206    clang-20
i386        buildonly-randconfig-006-20251206    clang-20
i386                  randconfig-001-20251206    gcc-14
i386                  randconfig-002-20251206    gcc-14
i386                  randconfig-003-20251206    gcc-14
i386                  randconfig-004-20251206    gcc-14
i386                  randconfig-005-20251206    gcc-14
i386                  randconfig-006-20251206    gcc-14
i386                  randconfig-007-20251206    gcc-14
i386                  randconfig-011-20251206    gcc-14
i386                  randconfig-012-20251206    gcc-14
i386                  randconfig-013-20251206    gcc-14
i386                  randconfig-014-20251206    gcc-14
i386                  randconfig-015-20251206    gcc-14
i386                  randconfig-016-20251206    gcc-14
i386                  randconfig-017-20251206    gcc-14
loongarch                        allmodconfig    clang-22
loongarch                         allnoconfig    gcc-15.1.0
loongarch                           defconfig    clang-19
loongarch             randconfig-001-20251206    gcc-15.1.0
loongarch             randconfig-002-20251206    gcc-15.1.0
m68k                             allmodconfig    gcc-15.1.0
m68k                              allnoconfig    gcc-15.1.0
m68k                             allyesconfig    clang-16
m68k                             allyesconfig    gcc-15.1.0
m68k                                defconfig    clang-19
m68k                        m5307c3_defconfig    gcc-15.1.0
m68k                        stmark2_defconfig    gcc-15.1.0
microblaze                        allnoconfig    gcc-15.1.0
microblaze                       allyesconfig    gcc-15.1.0
microblaze                          defconfig    clang-19
mips                             allmodconfig    gcc-15.1.0
mips                              allnoconfig    gcc-15.1.0
mips                             allyesconfig    gcc-15.1.0
mips                          eyeq5_defconfig    gcc-15.1.0
nios2                            allmodconfig    clang-22
nios2                             allnoconfig    clang-22
nios2                               defconfig    clang-19
nios2                 randconfig-001-20251206    gcc-15.1.0
nios2                 randconfig-002-20251206    gcc-15.1.0
openrisc                         allmodconfig    clang-22
openrisc                          allnoconfig    clang-22
openrisc                            defconfig    gcc-15.1.0
parisc                           allmodconfig    gcc-15.1.0
parisc                            allnoconfig    clang-22
parisc                           allyesconfig    clang-19
parisc                              defconfig    gcc-15.1.0
parisc                randconfig-001-20251206    clang-22
parisc                randconfig-002-20251206    clang-22
parisc64                            defconfig    clang-19
powerpc                          allmodconfig    gcc-15.1.0
powerpc                           allnoconfig    clang-22
powerpc                       eiger_defconfig    gcc-15.1.0
powerpc                    mvme5100_defconfig    gcc-15.1.0
powerpc               randconfig-001-20251206    clang-22
powerpc               randconfig-002-20251206    clang-22
powerpc                     tqm5200_defconfig    gcc-15.1.0
powerpc64             randconfig-001-20251206    clang-22
powerpc64             randconfig-002-20251206    clang-22
riscv                            allmodconfig    clang-22
riscv                             allnoconfig    clang-22
riscv                            allyesconfig    clang-16
riscv                               defconfig    gcc-15.1.0
riscv                 randconfig-001-20251206    clang-22
riscv                 randconfig-002-20251206    clang-22
s390                             allmodconfig    clang-19
s390                              allnoconfig    clang-22
s390                             allyesconfig    gcc-15.1.0
s390                                defconfig    gcc-15.1.0
s390                  randconfig-001-20251206    clang-22
s390                  randconfig-002-20251206    clang-22
sh                               allmodconfig    gcc-15.1.0
sh                                allnoconfig    clang-22
sh                               allyesconfig    clang-19
sh                                  defconfig    gcc-14
sh                        edosk7705_defconfig    gcc-15.1.0
sh                             espt_defconfig    gcc-15.1.0
sh                            hp6xx_defconfig    gcc-15.1.0
sh                    randconfig-001-20251206    clang-22
sh                    randconfig-002-20251206    clang-22
sh                          rsk7203_defconfig    gcc-15.1.0
sparc                             allnoconfig    clang-22
sparc                               defconfig    gcc-15.1.0
sparc                 randconfig-001-20251206    gcc-14
sparc                 randconfig-002-20251206    gcc-14
sparc64                          allmodconfig    clang-22
sparc64                             defconfig    gcc-14
sparc64               randconfig-001-20251206    gcc-14
sparc64               randconfig-002-20251206    gcc-14
um                               allmodconfig    clang-19
um                                allnoconfig    clang-22
um                               allyesconfig    gcc-15.1.0
um                                  defconfig    gcc-14
um                             i386_defconfig    gcc-14
um                    randconfig-001-20251206    gcc-14
um                    randconfig-002-20251206    gcc-14
um                           x86_64_defconfig    gcc-14
x86_64                           allmodconfig    clang-20
x86_64                            allnoconfig    clang-22
x86_64                           allyesconfig    clang-20
x86_64      buildonly-randconfig-001-20251206    gcc-14
x86_64      buildonly-randconfig-002-20251206    gcc-14
x86_64      buildonly-randconfig-003-20251206    gcc-14
x86_64      buildonly-randconfig-004-20251206    gcc-14
x86_64      buildonly-randconfig-005-20251206    gcc-14
x86_64      buildonly-randconfig-006-20251206    gcc-14
x86_64                              defconfig    gcc-14
x86_64                                  kexec    clang-20
x86_64                randconfig-001-20251206    gcc-14
x86_64                randconfig-002-20251206    gcc-14
x86_64                randconfig-003-20251206    gcc-14
x86_64                randconfig-004-20251206    gcc-14
x86_64                randconfig-005-20251206    gcc-14
x86_64                randconfig-006-20251206    gcc-14
x86_64                randconfig-011-20251206    clang-20
x86_64                randconfig-012-20251206    clang-20
x86_64                randconfig-013-20251206    clang-20
x86_64                randconfig-014-20251206    clang-20
x86_64                randconfig-015-20251206    clang-20
x86_64                randconfig-016-20251206    clang-20
x86_64                randconfig-071-20251206    gcc-14
x86_64                randconfig-072-20251206    gcc-14
x86_64                randconfig-073-20251206    gcc-14
x86_64                randconfig-074-20251206    gcc-14
x86_64                randconfig-075-20251206    gcc-14
x86_64                randconfig-076-20251206    gcc-14
x86_64                               rhel-9.4    clang-20
x86_64                           rhel-9.4-bpf    gcc-14
x86_64                          rhel-9.4-func    clang-20
x86_64                    rhel-9.4-kselftests    clang-20
x86_64                         rhel-9.4-kunit    gcc-14
x86_64                           rhel-9.4-ltp    gcc-14
x86_64                          rhel-9.4-rust    clang-20
xtensa                            allnoconfig    clang-22
xtensa                           allyesconfig    clang-22
xtensa                randconfig-001-20251206    gcc-14
xtensa                randconfig-002-20251206    gcc-14

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From lkp at intel.com  Sat Dec  6 07:13:36 2025
From: lkp at intel.com (kernel test robot)
Date: Sat, 06 Dec 2025 23:13:36 +0800
Subject: [soc:soc/dt] BUILD SUCCESS
 79edb7f596db99c01b25c1deebeffede6b48b505
Message-ID: <202512062325.cHG08zKn-lkp@intel.com>

tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git soc/dt
branch HEAD: 79edb7f596db99c01b25c1deebeffede6b48b505  Merge tag 'samsung-dt-6.19' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux into soc/dt

elapsed time: 1462m

configs tested: 104
configs skipped: 1

The following configs have been built successfully.
More configs may be tested in the coming days.

tested configs:
alpha                            allyesconfig    gcc-15.1.0
alpha                               defconfig    gcc-15.1.0
arc                                 defconfig    gcc-15.1.0
arc                   randconfig-001-20251206    gcc-8.5.0
arc                   randconfig-002-20251206    gcc-14.3.0
arm                                 defconfig    clang-22
arm                   randconfig-001-20251206    clang-22
arm                   randconfig-002-20251206    clang-22
arm                   randconfig-003-20251206    clang-16
arm                   randconfig-004-20251206    clang-20
arm64                               defconfig    gcc-15.1.0
arm64                 randconfig-001-20251206    gcc-8.5.0
arm64                 randconfig-002-20251206    clang-22
arm64                 randconfig-003-20251206    clang-22
arm64                 randconfig-004-20251206    gcc-8.5.0
csky                                defconfig    gcc-15.1.0
csky                  randconfig-001-20251206    gcc-15.1.0
csky                  randconfig-002-20251206    gcc-15.1.0
hexagon                          allmodconfig    clang-17
hexagon                             defconfig    clang-22
hexagon               randconfig-001-20251206    clang-16
hexagon               randconfig-002-20251206    clang-22
i386                             allmodconfig    gcc-14
i386                             allyesconfig    gcc-14
i386        buildonly-randconfig-001-20251206    gcc-14
i386        buildonly-randconfig-002-20251206    gcc-14
i386        buildonly-randconfig-003-20251206    clang-20
i386        buildonly-randconfig-004-20251206    clang-20
i386        buildonly-randconfig-005-20251206    clang-20
i386        buildonly-randconfig-006-20251206    clang-20
i386                                defconfig    clang-20
i386                  randconfig-003-20251206    gcc-14
i386                  randconfig-004-20251206    gcc-14
loongarch                           defconfig    clang-19
loongarch             randconfig-001-20251206    gcc-15.1.0
loongarch             randconfig-002-20251206    gcc-12.5.0
m68k                                defconfig    gcc-15.1.0
microblaze                          defconfig    gcc-15.1.0
nios2                             allnoconfig    gcc-11.5.0
nios2                               defconfig    gcc-11.5.0
nios2                 randconfig-001-20251206    gcc-8.5.0
nios2                 randconfig-002-20251206    gcc-8.5.0
openrisc                          allnoconfig    gcc-15.1.0
openrisc                            defconfig    gcc-15.1.0
parisc                            allnoconfig    gcc-15.1.0
parisc                              defconfig    gcc-15.1.0
parisc                randconfig-001-20251206    gcc-11.5.0
parisc                randconfig-002-20251206    gcc-15.1.0
parisc64                            defconfig    gcc-15.1.0
powerpc                           allnoconfig    gcc-15.1.0
powerpc               randconfig-001-20251206    gcc-11.5.0
powerpc               randconfig-002-20251206    clang-22
powerpc64             randconfig-001-20251206    gcc-15.1.0
powerpc64             randconfig-002-20251206    clang-22
riscv                             allnoconfig    gcc-15.1.0
riscv                               defconfig    clang-22
riscv                 randconfig-001-20251206    clang-22
riscv                 randconfig-002-20251206    clang-19
s390                              allnoconfig    clang-22
s390                                defconfig    clang-22
s390                  randconfig-001-20251206    clang-22
s390                  randconfig-002-20251206    gcc-8.5.0
sh                               allmodconfig    gcc-15.1.0
sh                                allnoconfig    gcc-15.1.0
sh                                  defconfig    gcc-15.1.0
sh                    randconfig-001-20251206    gcc-15.1.0
sh                    randconfig-002-20251206    gcc-15.1.0
sparc                             allnoconfig    gcc-15.1.0
sparc                               defconfig    gcc-15.1.0
sparc                 randconfig-001-20251206    gcc-12.5.0
sparc                 randconfig-002-20251206    gcc-8.5.0
sparc64                             defconfig    clang-20
sparc64               randconfig-001-20251206    clang-22
sparc64               randconfig-002-20251206    gcc-8.5.0
um                                allnoconfig    clang-22
um                               allyesconfig    gcc-14
um                                  defconfig    clang-22
um                             i386_defconfig    gcc-14
um                    randconfig-001-20251206    gcc-14
um                    randconfig-002-20251206    gcc-14
um                           x86_64_defconfig    clang-22
x86_64                           allmodconfig    clang-20
x86_64                            allnoconfig    clang-20
x86_64                           allyesconfig    clang-20
x86_64      buildonly-randconfig-002-20251206    gcc-14
x86_64                              defconfig    gcc-14
x86_64                randconfig-001-20251206    clang-20
x86_64                randconfig-002-20251206    gcc-14
x86_64                randconfig-003-20251206    gcc-14
x86_64                randconfig-004-20251206    gcc-14
x86_64                randconfig-005-20251206    gcc-14
x86_64                randconfig-006-20251206    gcc-14
x86_64                randconfig-011-20251206    gcc-14
x86_64                randconfig-013-20251206    gcc-14
x86_64                randconfig-071-20251206    clang-20
x86_64                randconfig-072-20251206    clang-20
x86_64                randconfig-073-20251206    gcc-14
x86_64                randconfig-074-20251206    gcc-14
x86_64                randconfig-075-20251206    gcc-14
x86_64                randconfig-076-20251206    gcc-14
x86_64                          rhel-9.4-rust    clang-20
xtensa                            allnoconfig    gcc-15.1.0
xtensa                randconfig-001-20251206    gcc-8.5.0
xtensa                randconfig-002-20251206    gcc-8.5.0

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From lkp at intel.com  Sat Dec  6 08:51:28 2025
From: lkp at intel.com (kernel test robot)
Date: Sun, 07 Dec 2025 00:51:28 +0800
Subject: [soc:soc/drivers-late] BUILD SUCCESS
 68f9bbf4dfc356ccc6586ba6e7dd79576c48f7f0
Message-ID: <202512070017.9vRMuFUJ-lkp@intel.com>

tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git soc/drivers-late
branch HEAD: 68f9bbf4dfc356ccc6586ba6e7dd79576c48f7f0  Merge tag 'samsung-drivers-6.19-2-late' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux into soc/drivers-late

elapsed time: 1560m

configs tested: 104
configs skipped: 1

The following configs have been built successfully.
More configs may be tested in the coming days.

tested configs:
alpha                            allyesconfig    gcc-15.1.0
alpha                               defconfig    gcc-15.1.0
arc                                 defconfig    gcc-15.1.0
arc                   randconfig-001-20251206    gcc-8.5.0
arc                   randconfig-002-20251206    gcc-14.3.0
arm                                 defconfig    clang-22
arm                            mmp2_defconfig    gcc-15.1.0
arm                       multi_v4t_defconfig    clang-16
arm                   randconfig-001-20251206    clang-22
arm                   randconfig-002-20251206    clang-22
arm                   randconfig-003-20251206    clang-16
arm                   randconfig-004-20251206    clang-20
arm64                               defconfig    gcc-15.1.0
arm64                 randconfig-001-20251206    gcc-8.5.0
arm64                 randconfig-002-20251206    clang-22
arm64                 randconfig-003-20251206    clang-22
arm64                 randconfig-004-20251206    gcc-8.5.0
csky                             allmodconfig    gcc-15.1.0
csky                                defconfig    gcc-15.1.0
csky                  randconfig-001-20251206    gcc-15.1.0
csky                  randconfig-002-20251206    gcc-15.1.0
hexagon                          allmodconfig    clang-17
hexagon                             defconfig    clang-22
hexagon               randconfig-001-20251206    clang-16
hexagon               randconfig-002-20251206    clang-22
i386                             allmodconfig    gcc-14
i386                             allyesconfig    gcc-14
i386        buildonly-randconfig-001-20251206    gcc-14
i386        buildonly-randconfig-002-20251206    gcc-14
i386        buildonly-randconfig-004-20251206    clang-20
i386                                defconfig    clang-20
i386                  randconfig-003-20251206    gcc-14
i386                  randconfig-004-20251206    gcc-14
i386                  randconfig-012-20251206    gcc-14
loongarch                           defconfig    clang-19
loongarch             randconfig-001-20251206    gcc-15.1.0
loongarch             randconfig-002-20251206    gcc-12.5.0
m68k                             allmodconfig    gcc-15.1.0
m68k                                defconfig    gcc-15.1.0
microblaze                       allyesconfig    gcc-15.1.0
microblaze                          defconfig    gcc-15.1.0
mips                             allyesconfig    gcc-15.1.0
mips                       bmips_be_defconfig    gcc-15.1.0
mips                        maltaup_defconfig    clang-22
nios2                               defconfig    gcc-11.5.0
nios2                 randconfig-001-20251206    gcc-8.5.0
nios2                 randconfig-002-20251206    gcc-8.5.0
openrisc                            defconfig    gcc-15.1.0
parisc                              defconfig    gcc-15.1.0
parisc                randconfig-001-20251206    gcc-11.5.0
parisc                randconfig-002-20251206    gcc-15.1.0
parisc64                            defconfig    gcc-15.1.0
powerpc                    amigaone_defconfig    gcc-15.1.0
powerpc                 mpc8313_rdb_defconfig    gcc-15.1.0
powerpc               randconfig-001-20251206    gcc-11.5.0
powerpc               randconfig-002-20251206    clang-22
powerpc64             randconfig-001-20251206    gcc-15.1.0
powerpc64             randconfig-002-20251206    clang-22
riscv                               defconfig    clang-22
riscv                 randconfig-001-20251206    clang-22
riscv                 randconfig-002-20251206    clang-19
s390                                defconfig    clang-22
s390                  randconfig-001-20251206    clang-22
s390                  randconfig-002-20251206    gcc-8.5.0
sh                               allmodconfig    gcc-15.1.0
sh                                  defconfig    gcc-15.1.0
sh                    randconfig-001-20251206    gcc-15.1.0
sh                    randconfig-002-20251206    gcc-15.1.0
sparc                            alldefconfig    gcc-15.1.0
sparc                               defconfig    gcc-15.1.0
sparc                 randconfig-001-20251206    gcc-12.5.0
sparc                 randconfig-002-20251206    gcc-8.5.0
sparc64                             defconfig    clang-20
sparc64               randconfig-001-20251206    clang-22
sparc64               randconfig-002-20251206    gcc-8.5.0
um                               allyesconfig    gcc-14
um                                  defconfig    clang-22
um                             i386_defconfig    gcc-14
um                    randconfig-001-20251206    gcc-14
um                    randconfig-002-20251206    gcc-14
um                           x86_64_defconfig    clang-22
x86_64                           allmodconfig    clang-20
x86_64                           allyesconfig    clang-20
x86_64      buildonly-randconfig-001-20251206    clang-20
x86_64      buildonly-randconfig-002-20251206    gcc-14
x86_64      buildonly-randconfig-003-20251206    clang-20
x86_64      buildonly-randconfig-004-20251206    clang-20
x86_64      buildonly-randconfig-005-20251206    gcc-13
x86_64                              defconfig    gcc-14
x86_64                randconfig-001-20251206    clang-20
x86_64                randconfig-002-20251206    gcc-14
x86_64                randconfig-003-20251206    gcc-14
x86_64                randconfig-004-20251206    gcc-14
x86_64                randconfig-005-20251206    gcc-14
x86_64                randconfig-006-20251206    gcc-14
x86_64                randconfig-071-20251206    clang-20
x86_64                randconfig-072-20251206    clang-20
x86_64                randconfig-073-20251206    gcc-14
x86_64                randconfig-074-20251206    gcc-14
x86_64                randconfig-075-20251206    gcc-14
x86_64                randconfig-076-20251206    gcc-14
x86_64                          rhel-9.4-rust    clang-20
xtensa                randconfig-001-20251206    gcc-8.5.0
xtensa                randconfig-002-20251206    gcc-8.5.0

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From otto.pflueger at abscue.de  Sat Dec  6 09:53:51 2025
From: otto.pflueger at abscue.de (=?utf-8?q?Otto_Pfl=C3=BCger?=)
Date: Sat, 06 Dec 2025 18:53:51 +0100
Subject: [PATCH] arm64: dts: mediatek: mt8183: Add missing endpoint IDs to
 display graph
Message-ID: <20251206-mt8183-display-graph-v1-1-a30e54481f28@abscue.de>

The endpoint IDs in the display graph are expected to match the
associated display path number, i.e. all endpoints connected to
mmsys_ep_main must have reg = <0> and all endpoints connected to
mmsys_ep_ext must have reg = <1>.

Add the missing ID to all endpoints in the display graph, based on
mt8365.dtsi as an existing example that does this correctly.

Fixes: e72d63fa0563 ("arm64: dts: mediatek: mt8183: Migrate to display controller OF graph")
Reported-by: Evans Jahja <evansjahja13 at gmail.com>
Closes: https://lore.kernel.org/linux-mediatek/CAAq5pW9o3itC0G16LnJO7KMAQ_XoqXUpB=cuJ_7e3-H11zKd5Q at mail.gmail.com/
Signed-off-by: Otto Pfl?ger <otto.pflueger at abscue.de>
---
 arch/arm64/boot/dts/mediatek/mt8183.dtsi | 122 +++++++++++++++++++++++++------
 1 file changed, 98 insertions(+), 24 deletions(-)

diff --git a/arch/arm64/boot/dts/mediatek/mt8183.dtsi b/arch/arm64/boot/dts/mediatek/mt8183.dtsi
index 4e20a8f2eb25803057955401a7737c7f029a1424..0c73043c67fd01147179e8f9b065684f67749ec2 100644
--- a/arch/arm64/boot/dts/mediatek/mt8183.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8183.dtsi
@@ -1754,15 +1754,21 @@ ports {
 				#size-cells = <0>;
 
 				port at 0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
 					reg = <0>;
-					ovl0_in: endpoint {
+					ovl0_in: endpoint at 0 {
+						reg = <0>;
 						remote-endpoint = <&mmsys_ep_main>;
 					};
 				};
 
 				port at 1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
 					reg = <1>;
-					ovl0_out: endpoint {
+					ovl0_out: endpoint at 0 {
+						reg = <0>;
 						remote-endpoint = <&ovl_2l0_in>;
 					};
 				};
@@ -1783,15 +1789,21 @@ ports {
 				#size-cells = <0>;
 
 				port at 0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
 					reg = <0>;
-					ovl_2l0_in: endpoint {
+					ovl_2l0_in: endpoint at 0 {
+						reg = <0>;
 						remote-endpoint = <&ovl0_out>;
 					};
 				};
 
 				port at 1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
 					reg = <1>;
-					ovl_2l0_out: endpoint {
+					ovl_2l0_out: endpoint at 0 {
+						reg = <0>;
 						remote-endpoint = <&rdma0_in>;
 					};
 				};
@@ -1812,15 +1824,21 @@ ports {
 				#size-cells = <0>;
 
 				port at 0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
 					reg = <0>;
-					ovl_2l1_in: endpoint {
+					ovl_2l1_in: endpoint at 1 {
+						reg = <1>;
 						remote-endpoint = <&mmsys_ep_ext>;
 					};
 				};
 
 				port at 1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
 					reg = <1>;
-					ovl_2l1_out: endpoint {
+					ovl_2l1_out: endpoint at 1 {
+						reg = <1>;
 						remote-endpoint = <&rdma1_in>;
 					};
 				};
@@ -1842,15 +1860,21 @@ ports {
 				#size-cells = <0>;
 
 				port at 0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
 					reg = <0>;
-					rdma0_in: endpoint {
+					rdma0_in: endpoint at 0 {
+						reg = <0>;
 						remote-endpoint = <&ovl_2l0_out>;
 					};
 				};
 
 				port at 1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
 					reg = <1>;
-					rdma0_out: endpoint {
+					rdma0_out: endpoint at 0 {
+						reg = <0>;
 						remote-endpoint = <&color0_in>;
 					};
 				};
@@ -1872,15 +1896,21 @@ ports {
 				#size-cells = <0>;
 
 				port at 0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
 					reg = <0>;
-					rdma1_in: endpoint {
+					rdma1_in: endpoint at 1 {
+						reg = <1>;
 						remote-endpoint = <&ovl_2l1_out>;
 					};
 				};
 
 				port at 1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
 					reg = <1>;
-					rdma1_out: endpoint {
+					rdma1_out: endpoint at 1 {
+						reg = <1>;
 						remote-endpoint = <&dpi_in>;
 					};
 				};
@@ -1901,15 +1931,21 @@ ports {
 				#size-cells = <0>;
 
 				port at 0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
 					reg = <0>;
-					color0_in: endpoint {
+					color0_in: endpoint at 0 {
+						reg = <0>;
 						remote-endpoint = <&rdma0_out>;
 					};
 				};
 
 				port at 1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
 					reg = <1>;
-					color0_out: endpoint {
+					color0_out: endpoint at 0 {
+						reg = <0>;
 						remote-endpoint = <&ccorr0_in>;
 					};
 				};
@@ -1929,15 +1965,21 @@ ports {
 				#size-cells = <0>;
 
 				port at 0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
 					reg = <0>;
-					ccorr0_in: endpoint {
+					ccorr0_in: endpoint at 0 {
+						reg = <0>;
 						remote-endpoint = <&color0_out>;
 					};
 				};
 
 				port at 1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
 					reg = <1>;
-					ccorr0_out: endpoint {
+					ccorr0_out: endpoint at 0 {
+						reg = <0>;
 						remote-endpoint = <&aal0_in>;
 					};
 				};
@@ -1957,15 +1999,21 @@ ports {
 				#size-cells = <0>;
 
 				port at 0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
 					reg = <0>;
-					aal0_in: endpoint {
+					aal0_in: endpoint at 0 {
+						reg = <0>;
 						remote-endpoint = <&ccorr0_out>;
 					};
 				};
 
 				port at 1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
 					reg = <1>;
-					aal0_out: endpoint {
+					aal0_out: endpoint at 0 {
+						reg = <0>;
 						remote-endpoint = <&gamma0_in>;
 					};
 				};
@@ -1985,15 +2033,21 @@ ports {
 				#size-cells = <0>;
 
 				port at 0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
 					reg = <0>;
-					gamma0_in: endpoint {
+					gamma0_in: endpoint at 0 {
+						reg = <0>;
 						remote-endpoint = <&aal0_out>;
 					};
 				};
 
 				port at 1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
 					reg = <1>;
-					gamma0_out: endpoint {
+					gamma0_out: endpoint at 0 {
+						reg = <0>;
 						remote-endpoint = <&dither0_in>;
 					};
 				};
@@ -2013,15 +2067,21 @@ ports {
 				#size-cells = <0>;
 
 				port at 0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
 					reg = <0>;
-					dither0_in: endpoint {
+					dither0_in: endpoint at 0 {
+						reg = <0>;
 						remote-endpoint = <&gamma0_out>;
 					};
 				};
 
 				port at 1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
 					reg = <1>;
-					dither0_out: endpoint {
+					dither0_out: endpoint at 0 {
+						reg = <0>;
 						remote-endpoint = <&dsi_in>;
 					};
 				};
@@ -2047,15 +2107,22 @@ ports {
 				#size-cells = <0>;
 
 				port at 0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
 					reg = <0>;
-					dsi_in: endpoint {
+					dsi_in: endpoint at 0 {
+						reg = <0>;
 						remote-endpoint = <&dither0_out>;
 					};
 				};
 
 				port at 1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
 					reg = <1>;
-					dsi_out: endpoint { };
+					dsi_out: endpoint at 0 {
+						reg = <0>;
+					};
 				};
 			};
 		};
@@ -2076,15 +2143,22 @@ ports {
 				#size-cells = <0>;
 
 				port at 0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
 					reg = <0>;
-					dpi_in: endpoint {
+					dpi_in: endpoint at 1 {
+						reg = <1>;
 						remote-endpoint = <&rdma1_out>;
 					};
 				};
 
 				port at 1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
 					reg = <1>;
-					dpi_out: endpoint { };
+					dpi_out: endpoint at 1 {
+						reg = <1>;
+					};
 				};
 			};
 		};

---
base-commit: 6987d58a9cbc5bd57c983baa514474a86c945d56
change-id: 20251206-mt8183-display-graph-506183c68b3b

Best regards,
-- 
Otto Pfl?ger <otto.pflueger at abscue.de>



From andrew at lunn.ch  Sat Dec  6 10:06:41 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Sat, 6 Dec 2025 19:06:41 +0100
Subject: [PATCH 4/4] arm64: dts: microchip: add LAN969x support
In-Reply-To: <a8185e0f-a3a2-44df-af37-1ad505ce9a7b@tuxon.dev>
References: <20251203122313.1287950-1-robert.marko@sartura.hr>
 <20251203122313.1287950-4-robert.marko@sartura.hr>
 <a8185e0f-a3a2-44df-af37-1ad505ce9a7b@tuxon.dev>
Message-ID: <d98b3069-861c-456d-8637-67e36dc107bb@lunn.ch>

On Sat, Dec 06, 2025 at 03:53:42PM +0200, Claudiu Beznea wrote:
> > +		port29: port at 29 {
> > +			reg = <29>;
> > +			microchip,bandwidth = <1000>;
> > +			phys = <&serdes 11>;
> > +			phy-handle = <&phy3>;
> > +			phy-mode = "rgmii";
> 
> >From chekpatch:
> 
> WARNING: phy-mode "rgmii" without comment -- delays on the PCB should be
> described, otherwise use "rgmii-id"
> #779: FILE: arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts:750:
> +                       phy-mode = "rgmii";
> 
> > +			rx-internal-delay-ps = <1000>;
> > +			tx-internal-delay-ps = <1000>;
> > +		};

I did a very quick scan of the patch and missed that. It is great that
checkpatch is now commenting about "rgmii".

1ns is very odd. You need a total of 2ns, so where is the rest coming
from? This definitely needs a comment explaining what is going on.

Also, RGMII typically does not need a SERDES, unless there is
something like an SGMII to RGMII converter being used. So is the phys
property needed?

	Andrew


From andrew at lunn.ch  Sat Dec  6 10:30:30 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Sat, 6 Dec 2025 19:30:30 +0100
Subject: [PATCH net-next v5 3/4] net: ftgmac100: Add RGMII delay support
 for AST2600
In-Reply-To: <20251205-rgmii_delay_2600-v5-3-bd2820ad3da7@aspeedtech.com>
References: <20251205-rgmii_delay_2600-v5-0-bd2820ad3da7@aspeedtech.com>
 <20251205-rgmii_delay_2600-v5-3-bd2820ad3da7@aspeedtech.com>
Message-ID: <8a991b33-f653-4f0c-bbea-b5b3404cdfe6@lunn.ch>

> @@ -1907,6 +2179,10 @@ static int ftgmac100_probe(struct platform_device *pdev)
>  		priv->rxdes0_edorr_mask = BIT(30);
>  		priv->txdes0_edotr_mask = BIT(30);
>  		priv->is_aspeed = true;
> +		/* Configure RGMII delay if there are the corresponding compatibles */
> +		err = ftgmac100_set_internal_delay(priv, &phy_intf);
> +		if (err)
> +			goto err_phy_connect;

Thinking forward to when you add 2700 support, i really think you need
to break the probe up into helpers for 2500 and before, 2600 and in
the future 2700. You currently have a couple of tests on the
compatible which you can reduce to one.

In fact, this driver has 10 calls to of_device_is_compatible(). I
think you should first refactor the code to list each compatible in
ftgmac100_of_match[], and add a data structure which contains an enum
of the MAC type. You can then transfer this to priv, and replace all
the of_device_is_compatible() tests to just look at the enum value.

	Andrew


From ardb at kernel.org  Sat Dec  6 11:01:15 2025
From: ardb at kernel.org (Ard Biesheuvel)
Date: Sat,  6 Dec 2025 20:01:15 +0100
Subject: [PATCH v2 0/2] efi/arm64: Simplify SVE/SME state preserve/restore
Message-ID: <20251206190114.892262-4-ardb@kernel.org>

The EFI specific SVE/SME state preserve/restore logic is unneeded, and
can be removed. Patch #1 adds some lkdtm test cases to emulate the
condition under which this code might be called.

v2:
- Document that BUG_IN_HARDIRQ and PANIC_IN_HARDIRQ will crash the
  system.
- Add Kees's R-b
- Rebase onto torvalds's tree of today so it is expected to apply
  cleanly to -rc1

Cc: Will Deacon <will at kernel.org>
Cc: Mark Rutland <mark.rutland at arm.com>
Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Mark Brown <broonie at kernel.org>
Cc: Kees Cook <keescook at chromium.org>

Ard Biesheuvel (2):
  lkdtm/bugs: Add cases for BUG and PANIC occurring in hardirq context
  arm64/efi: Remove unneeded SVE/SME fallback preserve/store handling

 arch/arm64/kernel/fpsimd.c              | 130 +++-----------------
 drivers/misc/lkdtm/bugs.c               |  53 ++++++++
 tools/testing/selftests/lkdtm/tests.txt |   2 +
 3 files changed, 75 insertions(+), 110 deletions(-)

-- 
2.47.3



From ardb at kernel.org  Sat Dec  6 11:01:17 2025
From: ardb at kernel.org (Ard Biesheuvel)
Date: Sat,  6 Dec 2025 20:01:17 +0100
Subject: [PATCH v2 2/2] arm64/efi: Remove unneeded SVE/SME fallback preserve/store handling
In-Reply-To: <20251206190114.892262-4-ardb@kernel.org>
References: <20251206190114.892262-4-ardb@kernel.org>
Message-ID: <20251206190114.892262-6-ardb@kernel.org>

Since commit 7137a203b251 ("arm64/fpsimd: Permit kernel mode NEON with
IRQs off"), the only condition under which the fallback path is taken
for FP/SIMD preserve/restore across a EFI runtime call is when it is
called from hardirq or NMI context.

In practice, this only happens when the EFI pstore driver is called to
dump the kernel log buffer into a EFI variable under a panic, oops or
emergency_restart() condition, and none of these can be expected to
result in a return to user space for the task in question.

This means that the existing EFI-specific logic for preserving and
restoring SVE/SME state is pointless, and can be removed.

Instead, kill the task, so that an exceedingly unlikely inadvertent
return to user space does not proceed with a corrupted FP/SIMD state.
Also, retain the preserve and restore of the base FP/SIMD state, as that
might belong to kernel mode use of FP/SIMD. (Note that EFI runtime calls
are never invoked reentrantly, even in this case, and so any interrupted
kernel mode FP/SIMD usage will be unrelated to EFI)

Signed-off-by: Ard Biesheuvel <ardb at kernel.org>
---
 arch/arm64/kernel/fpsimd.c | 130 +++-----------------
 1 file changed, 20 insertions(+), 110 deletions(-)

diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index c154f72634e0..9de1d8a604cb 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -180,13 +180,6 @@ static inline void set_sve_default_vl(int val)
 	set_default_vl(ARM64_VEC_SVE, val);
 }
 
-static u8 *efi_sve_state;
-
-#else /* ! CONFIG_ARM64_SVE */
-
-/* Dummy declaration for code that will be optimised out: */
-extern u8 *efi_sve_state;
-
 #endif /* ! CONFIG_ARM64_SVE */
 
 #ifdef CONFIG_ARM64_SME
@@ -1095,36 +1088,6 @@ int vec_verify_vq_map(enum vec_type type)
 	return 0;
 }
 
-static void __init sve_efi_setup(void)
-{
-	int max_vl = 0;
-	int i;
-
-	if (!IS_ENABLED(CONFIG_EFI))
-		return;
-
-	for (i = 0; i < ARRAY_SIZE(vl_info); i++)
-		max_vl = max(vl_info[i].max_vl, max_vl);
-
-	/*
-	 * alloc_percpu() warns and prints a backtrace if this goes wrong.
-	 * This is evidence of a crippled system and we are returning void,
-	 * so no attempt is made to handle this situation here.
-	 */
-	if (!sve_vl_valid(max_vl))
-		goto fail;
-
-	efi_sve_state = kmalloc(SVE_SIG_REGS_SIZE(sve_vq_from_vl(max_vl)),
-				GFP_KERNEL);
-	if (!efi_sve_state)
-		goto fail;
-
-	return;
-
-fail:
-	panic("Cannot allocate memory for EFI SVE save/restore");
-}
-
 void cpu_enable_sve(const struct arm64_cpu_capabilities *__always_unused p)
 {
 	write_sysreg(read_sysreg(CPACR_EL1) | CPACR_EL1_ZEN_EL1EN, CPACR_EL1);
@@ -1185,8 +1148,6 @@ void __init sve_setup(void)
 	if (sve_max_virtualisable_vl() < sve_max_vl())
 		pr_warn("%s: unvirtualisable vector lengths present\n",
 			info->name);
-
-	sve_efi_setup();
 }
 
 /*
@@ -1947,9 +1908,6 @@ EXPORT_SYMBOL_GPL(kernel_neon_end);
 #ifdef CONFIG_EFI
 
 static struct user_fpsimd_state efi_fpsimd_state;
-static bool efi_fpsimd_state_used;
-static bool efi_sve_state_used;
-static bool efi_sm_state;
 
 /*
  * EFI runtime services support functions
@@ -1976,43 +1934,26 @@ void __efi_fpsimd_begin(void)
 	if (may_use_simd()) {
 		kernel_neon_begin(&efi_fpsimd_state);
 	} else {
-		WARN_ON(preemptible());
-
 		/*
-		 * If !efi_sve_state, SVE can't be in use yet and doesn't need
-		 * preserving:
+		 * We are running in hardirq or NMI context, and the only
+		 * legitimate case where this might happen is when EFI pstore
+		 * is attempting to record the system's dying gasps into EFI
+		 * variables. This could be due to an oops, a panic or a call
+		 * to emergency_restart(), and in none of those cases, we can
+		 * expect the current task to ever return to user space again,
+		 * or for the kernel to resume any normal execution, for that
+		 * matter (an oops in hardirq context triggers a panic too).
+		 *
+		 * Therefore, there is no point in attempting to preserve any
+		 * SVE/SME state here. On the off chance that we might have
+		 * ended up here for a different reason inadvertently, kill the
+		 * task and preserve/restore the base FP/SIMD state, which
+		 * might belong to kernel mode FP/SIMD.
 		 */
-		if (system_supports_sve() && efi_sve_state != NULL) {
-			bool ffr = true;
-			u64 svcr;
-
-			efi_sve_state_used = true;
-
-			if (system_supports_sme()) {
-				svcr = read_sysreg_s(SYS_SVCR);
-
-				efi_sm_state = svcr & SVCR_SM_MASK;
-
-				/*
-				 * Unless we have FA64 FFR does not
-				 * exist in streaming mode.
-				 */
-				if (!system_supports_fa64())
-					ffr = !(svcr & SVCR_SM_MASK);
-			}
-
-			sve_save_state(efi_sve_state + sve_ffr_offset(sve_max_vl()),
-				       &efi_fpsimd_state.fpsr, ffr);
-
-			if (system_supports_sme())
-				sysreg_clear_set_s(SYS_SVCR,
-						   SVCR_SM_MASK, 0);
-
-		} else {
-			fpsimd_save_state(&efi_fpsimd_state);
-		}
-
-		efi_fpsimd_state_used = true;
+		pr_warn_ratelimited("Calling EFI runtime from %s context\n",
+				    in_nmi() ? "NMI" : "hardirq");
+		force_signal_inject(SIGKILL, SI_KERNEL, 0, 0);
+		fpsimd_save_state(&efi_fpsimd_state);
 	}
 }
 
@@ -2024,41 +1965,10 @@ void __efi_fpsimd_end(void)
 	if (!system_supports_fpsimd())
 		return;
 
-	if (!efi_fpsimd_state_used) {
+	if (may_use_simd()) {
 		kernel_neon_end(&efi_fpsimd_state);
 	} else {
-		if (system_supports_sve() && efi_sve_state_used) {
-			bool ffr = true;
-
-			/*
-			 * Restore streaming mode; EFI calls are
-			 * normal function calls so should not return in
-			 * streaming mode.
-			 */
-			if (system_supports_sme()) {
-				if (efi_sm_state) {
-					sysreg_clear_set_s(SYS_SVCR,
-							   0,
-							   SVCR_SM_MASK);
-
-					/*
-					 * Unless we have FA64 FFR does not
-					 * exist in streaming mode.
-					 */
-					if (!system_supports_fa64())
-						ffr = false;
-				}
-			}
-
-			sve_load_state(efi_sve_state + sve_ffr_offset(sve_max_vl()),
-				       &efi_fpsimd_state.fpsr, ffr);
-
-			efi_sve_state_used = false;
-		} else {
-			fpsimd_load_state(&efi_fpsimd_state);
-		}
-
-		efi_fpsimd_state_used = false;
+		fpsimd_load_state(&efi_fpsimd_state);
 	}
 }
 
-- 
2.47.3



From ardb at kernel.org  Sat Dec  6 11:01:16 2025
From: ardb at kernel.org (Ard Biesheuvel)
Date: Sat,  6 Dec 2025 20:01:16 +0100
Subject: [PATCH v2 1/2] lkdtm/bugs: Add cases for BUG and PANIC occurring in hardirq context
In-Reply-To: <20251206190114.892262-4-ardb@kernel.org>
References: <20251206190114.892262-4-ardb@kernel.org>
Message-ID: <20251206190114.892262-5-ardb@kernel.org>

Add lkdtm cases to trigger a BUG() or panic() from hardirq context. This
is useful for testing pstore behavior being invoked from such contexts.

Reviewed-by: Kees Cook <kees at kernel.org>
Signed-off-by: Ard Biesheuvel <ardb at kernel.org>
---
 drivers/misc/lkdtm/bugs.c               | 53 ++++++++++++++++++++
 tools/testing/selftests/lkdtm/tests.txt |  2 +
 2 files changed, 55 insertions(+)

diff --git a/drivers/misc/lkdtm/bugs.c b/drivers/misc/lkdtm/bugs.c
index 376047beea3d..fa05d77acb55 100644
--- a/drivers/misc/lkdtm/bugs.c
+++ b/drivers/misc/lkdtm/bugs.c
@@ -8,6 +8,7 @@
 #include "lkdtm.h"
 #include <linux/cpu.h>
 #include <linux/list.h>
+#include <linux/hrtimer.h>
 #include <linux/sched.h>
 #include <linux/sched/signal.h>
 #include <linux/sched/task_stack.h>
@@ -100,11 +101,61 @@ static void lkdtm_PANIC_STOP_IRQOFF(void)
 	stop_machine(panic_stop_irqoff_fn, &v, cpu_online_mask);
 }
 
+static bool wait_for_panic;
+
+static enum hrtimer_restart panic_in_hardirq(struct hrtimer *timer)
+{
+	panic("from hard IRQ context");
+
+	wait_for_panic = false;
+	return HRTIMER_NORESTART;
+}
+
+static void lkdtm_PANIC_IN_HARDIRQ(void)
+{
+	struct hrtimer timer;
+
+	wait_for_panic = true;
+	hrtimer_setup_on_stack(&timer, panic_in_hardirq,
+			       CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD);
+	hrtimer_start(&timer, us_to_ktime(100), HRTIMER_MODE_REL_HARD);
+
+	while (wait_for_panic)
+		;
+
+	hrtimer_cancel(&timer);
+}
+
 static void lkdtm_BUG(void)
 {
 	BUG();
 }
 
+static bool wait_for_bug;
+
+static enum hrtimer_restart bug_in_hardirq(struct hrtimer *timer)
+{
+	BUG();
+
+	wait_for_bug = false;
+	return HRTIMER_NORESTART;
+}
+
+static void lkdtm_BUG_IN_HARDIRQ(void)
+{
+	struct hrtimer timer;
+
+	wait_for_bug = true;
+	hrtimer_setup_on_stack(&timer, bug_in_hardirq,
+			       CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD);
+	hrtimer_start(&timer, us_to_ktime(100), HRTIMER_MODE_REL_HARD);
+
+	while (wait_for_bug)
+		;
+
+	hrtimer_cancel(&timer);
+}
+
 static int warn_counter;
 
 static void lkdtm_WARNING(void)
@@ -696,7 +747,9 @@ static noinline void lkdtm_CORRUPT_PAC(void)
 static struct crashtype crashtypes[] = {
 	CRASHTYPE(PANIC),
 	CRASHTYPE(PANIC_STOP_IRQOFF),
+	CRASHTYPE(PANIC_IN_HARDIRQ),
 	CRASHTYPE(BUG),
+	CRASHTYPE(BUG_IN_HARDIRQ),
 	CRASHTYPE(WARNING),
 	CRASHTYPE(WARNING_MESSAGE),
 	CRASHTYPE(EXCEPTION),
diff --git a/tools/testing/selftests/lkdtm/tests.txt b/tools/testing/selftests/lkdtm/tests.txt
index cff124c1eddd..67cd53715d93 100644
--- a/tools/testing/selftests/lkdtm/tests.txt
+++ b/tools/testing/selftests/lkdtm/tests.txt
@@ -1,6 +1,8 @@
 #PANIC
 #PANIC_STOP_IRQOFF Crashes entire system
+#PANIC_IN_HARDIRQ Crashes entire system
 BUG kernel BUG at
+#BUG_IN_HARDIRQ Crashes entire system
 WARNING WARNING:
 WARNING_MESSAGE message trigger
 EXCEPTION
-- 
2.47.3



From jgg at nvidia.com  Sat Dec  6 11:34:08 2025
From: jgg at nvidia.com (Jason Gunthorpe)
Date: Sat, 6 Dec 2025 15:34:08 -0400
Subject: [PATCH rc v1 1/4] iommu/arm-smmu-v3: Add ignored bits to fix STE
 update sequence
In-Reply-To: <6ec73bb7cd03d90a0764f12c4b14071158163818.1764982046.git.nicolinc@nvidia.com>
References: <cover.1764982046.git.nicolinc@nvidia.com>
 <6ec73bb7cd03d90a0764f12c4b14071158163818.1764982046.git.nicolinc@nvidia.com>
Message-ID: <20251206193408.GD1219718@nvidia.com>

On Fri, Dec 05, 2025 at 04:52:00PM -0800, Nicolin Chen wrote:
> @@ -1106,16 +1115,17 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
>  		 * allowed to set a bit to 1 if the used function doesn't say it
>  		 * is used.
>  		 */
> -		WARN_ON_ONCE(target[i] & ~target_used[i]);
> +		WARN_ON_ONCE(target[i] & ~target_used[i] & ~ignored[i]);
>  
>  		/* Bits can change because they are not currently being used */
> -		unused_update[i] = (entry[i] & cur_used[i]) |
> +		unused_update[i] = (entry[i] & (cur_used[i] | ignored[i])) |
>  				   (target[i] & ~cur_used[i]);

This can't be right? We don't want to ever copy an ignored bit from
entry, the ignored bits should always come from target. The line
should be left alone.

Jason


From jgg at nvidia.com  Sat Dec  6 11:38:30 2025
From: jgg at nvidia.com (Jason Gunthorpe)
Date: Sat, 6 Dec 2025 15:38:30 -0400
Subject: [PATCH rc v1 1/4] iommu/arm-smmu-v3: Add ignored bits to fix STE
 update sequence
In-Reply-To: <1af0f768-4b3d-47a3-b59b-c56f034b1d1b@linux.alibaba.com>
References: <cover.1764982046.git.nicolinc@nvidia.com>
 <6ec73bb7cd03d90a0764f12c4b14071158163818.1764982046.git.nicolinc@nvidia.com>
 <1af0f768-4b3d-47a3-b59b-c56f034b1d1b@linux.alibaba.com>
Message-ID: <20251206193830.GF1219718@nvidia.com>

On Sat, Dec 06, 2025 at 10:19:08PM +0800, Shuai Xue wrote:
> Instead of modifying the calculation logic, would it be cleaner to keep
> the original arm_smmu_get_ste_used() semantics intact and simply exclude
> ignored bits from cur_used after obtaining them?

I'm OK with this idea

Jason


From jgg at nvidia.com  Sat Dec  6 11:42:25 2025
From: jgg at nvidia.com (Jason Gunthorpe)
Date: Sat, 6 Dec 2025 15:42:25 -0400
Subject: [PATCH rc v1 4/4] iommu/arm-smmu-v3-test: Add nested s1bypass
 coverage
In-Reply-To: <703ba08f-eec0-44d8-a224-c96706df5fab@linux.alibaba.com>
References: <cover.1764982046.git.nicolinc@nvidia.com>
 <3c838833d8bbb69a72a85ddbcc325b22ae7a7d6d.1764982046.git.nicolinc@nvidia.com>
 <703ba08f-eec0-44d8-a224-c96706df5fab@linux.alibaba.com>
Message-ID: <20251206194225.GG1219718@nvidia.com>

On Sat, Dec 06, 2025 at 08:34:09PM +0800, Shuai Xue wrote:
> 
> +	arm_smmu_test_make_s2_ste(&s2_ste, 0);
> +	arm_smmu_v3_test_ste_expect_hitless_transition(test, &s1_ste, &s2_ste,
> +						       NUM_EXPECTED_SYNCS(3));
> 
> With get_ignored(), a nested s1dssbypass STE to a nested s1bypass STE
> will be hitless, a.k.a, NUM_EXPECTED_SYNCS(1).

hitless is tested by the ste_expect_hitless in the function name. The
expected SYNCS have to do with how many updates are required to fix
the STE, 3 is still fine for a hitless update. One to set the unused
bits, one to set the critical qword, one to clear unused bits.

Jason


From nicolinc at nvidia.com  Sat Dec  6 11:45:40 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Sat, 6 Dec 2025 11:45:40 -0800
Subject: [PATCH rc v1 1/4] iommu/arm-smmu-v3: Add ignored bits to fix STE
 update sequence
In-Reply-To: <20251206193408.GD1219718@nvidia.com>
References: <cover.1764982046.git.nicolinc@nvidia.com>
 <6ec73bb7cd03d90a0764f12c4b14071158163818.1764982046.git.nicolinc@nvidia.com>
 <20251206193408.GD1219718@nvidia.com>
Message-ID: <aTSH5Eap7leYQtPl@nvidia.com>

On Sat, Dec 06, 2025 at 03:34:08PM -0400, Jason Gunthorpe wrote:
> On Fri, Dec 05, 2025 at 04:52:00PM -0800, Nicolin Chen wrote:
> > @@ -1106,16 +1115,17 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
> >  		 * allowed to set a bit to 1 if the used function doesn't say it
> >  		 * is used.
> >  		 */
> > -		WARN_ON_ONCE(target[i] & ~target_used[i]);
> > +		WARN_ON_ONCE(target[i] & ~target_used[i] & ~ignored[i]);
> >  
> >  		/* Bits can change because they are not currently being used */
> > -		unused_update[i] = (entry[i] & cur_used[i]) |
> > +		unused_update[i] = (entry[i] & (cur_used[i] | ignored[i])) |
> >  				   (target[i] & ~cur_used[i]);
> 
> This can't be right? We don't want to ever copy an ignored bit from
> entry, the ignored bits should always come from target. The line
> should be left alone.

Hmm, without this change, the following coverages will be broken:
  arm_smmu_v3_write_ste_test_s1dssbypass_to_stebypass
  arm_smmu_v3_write_ste_test_stebypass_to_s1dssbypass

Both were expect num_syncs=2, but it would be 3 if we don't include
the ignored bits to unused_update. Or should we update the num_syncs
instead?

Nicolin


From jgg at nvidia.com  Sat Dec  6 11:46:37 2025
From: jgg at nvidia.com (Jason Gunthorpe)
Date: Sat, 6 Dec 2025 15:46:37 -0400
Subject: [PATCH rc v1 3/4] iommu/arm-smmu-v3: Ignore STE EATS when
 computing the update sequence
In-Reply-To: <db1450e7a5989e51756a7ec3285d70ee90bae24f.1764982046.git.nicolinc@nvidia.com>
References: <cover.1764982046.git.nicolinc@nvidia.com>
 <db1450e7a5989e51756a7ec3285d70ee90bae24f.1764982046.git.nicolinc@nvidia.com>
Message-ID: <20251206194637.GH1219718@nvidia.com>

On Fri, Dec 05, 2025 at 04:52:02PM -0800, Nicolin Chen wrote:
> From: Jason Gunthorpe <jgg at nvidia.com>
> 
> If a VM want to toggle EATS off the hypervisor will see EATS change to 0
> and insert a V=0 breaking update into the STE even though the VM did not
> ask for that.

"EATS off at the same time as changing CFG"

In bare metal EATS is ignored by CFG=ABORT/BYPASS which is why this
doesn't cause a problem until we have nested where CFG is always a
variation of S2 trans that does use EATS.

Jason


From nicolinc at nvidia.com  Sat Dec  6 11:50:06 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Sat, 6 Dec 2025 11:50:06 -0800
Subject: [PATCH rc v1 4/4] iommu/arm-smmu-v3-test: Add nested s1bypass
 coverage
In-Reply-To: <703ba08f-eec0-44d8-a224-c96706df5fab@linux.alibaba.com>
References: <cover.1764982046.git.nicolinc@nvidia.com>
 <3c838833d8bbb69a72a85ddbcc325b22ae7a7d6d.1764982046.git.nicolinc@nvidia.com>
 <703ba08f-eec0-44d8-a224-c96706df5fab@linux.alibaba.com>
Message-ID: <aTSI7iFaS1BnmDg5@nvidia.com>

On Sat, Dec 06, 2025 at 08:34:09PM +0800, Shuai Xue wrote:
> 
> 
> ? 2025/12/6 08:52, Nicolin Chen ??:
> > STE in a nested case requires both S1 and S2 fields. And this makes the use
> > case different from the existing one.
> > 
> > Add coverage for previously failed cases shifting between S2-only and S1+S2
> > STEs.
> > 
> > Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
> > ---
> >   .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  | 32 +++++++++++++++++++
> >   1 file changed, 32 insertions(+)
> > 
> > diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> > index 9287904c93a2..56bdcf5a517e 100644
> > --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> > +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> > @@ -553,6 +553,36 @@ static void arm_smmu_v3_write_ste_test_s2_to_s1_stall(struct kunit *test)
> >   						       NUM_EXPECTED_SYNCS(3));
> >   }
> > +static void
> > +arm_smmu_v3_write_ste_test_nested_s1dssbypass_to_s1bypass(struct kunit *test)
> > +{
> > +	struct arm_smmu_ste s1_ste;
> > +	struct arm_smmu_ste s2_ste;
> > +
> > +	arm_smmu_test_make_s2_ste(&s1_ste, ARM_SMMU_MASTER_TEST_ATS);
> > +	arm_smmu_test_make_cdtable_ste(&s1_ste, STRTAB_STE_1_S1DSS_SSID0,
> 
> arm_smmu_test_make_s2_ste() makes a s2 ste and it will be overwrited by
> arm_smmu_test_make_cdtable_ste(). Finnaly, we got a s1 STE, not a nested
> s1dssbypass ste.

You are right. There is memset.

> I think we need a function like arm_smmu_make_nested_cd_table_ste()
> here.
> 
> Besides, from the function name, I think you mean
> STRTAB_STE_1_S1DSS_BYPASS?

Yes, I will fix these.

Thanks
Nicolin


From nicolinc at nvidia.com  Sat Dec  6 11:54:54 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Sat, 6 Dec 2025 11:54:54 -0800
Subject: [PATCH rc v1 3/4] iommu/arm-smmu-v3: Ignore STE EATS when
 computing the update sequence
In-Reply-To: <20251206194637.GH1219718@nvidia.com>
References: <cover.1764982046.git.nicolinc@nvidia.com>
 <db1450e7a5989e51756a7ec3285d70ee90bae24f.1764982046.git.nicolinc@nvidia.com>
 <20251206194637.GH1219718@nvidia.com>
Message-ID: <aTSKDmb2gqZb2Zne@nvidia.com>

On Sat, Dec 06, 2025 at 03:46:37PM -0400, Jason Gunthorpe wrote:
> On Fri, Dec 05, 2025 at 04:52:02PM -0800, Nicolin Chen wrote:
> > From: Jason Gunthorpe <jgg at nvidia.com>
> > 
> > If a VM want to toggle EATS off the hypervisor will see EATS change to 0
> > and insert a V=0 breaking update into the STE even though the VM did not
> > ask for that.
> 
> "EATS off at the same time as changing CFG"
> 
> In bare metal EATS is ignored by CFG=ABORT/BYPASS which is why this
> doesn't cause a problem until we have nested where CFG is always a
> variation of S2 trans that does use EATS.

Ack. Will add squash these two.

Nicolin


From jgg at nvidia.com  Sat Dec  6 11:57:52 2025
From: jgg at nvidia.com (Jason Gunthorpe)
Date: Sat, 6 Dec 2025 15:57:52 -0400
Subject: [PATCH rc v1 1/4] iommu/arm-smmu-v3: Add ignored bits to fix STE
 update sequence
In-Reply-To: <aTSH5Eap7leYQtPl@nvidia.com>
References: <cover.1764982046.git.nicolinc@nvidia.com>
 <6ec73bb7cd03d90a0764f12c4b14071158163818.1764982046.git.nicolinc@nvidia.com>
 <20251206193408.GD1219718@nvidia.com>
 <aTSH5Eap7leYQtPl@nvidia.com>
Message-ID: <20251206195752.GI1219718@nvidia.com>

On Sat, Dec 06, 2025 at 11:45:40AM -0800, Nicolin Chen wrote:
> On Sat, Dec 06, 2025 at 03:34:08PM -0400, Jason Gunthorpe wrote:
> > On Fri, Dec 05, 2025 at 04:52:00PM -0800, Nicolin Chen wrote:
> > > @@ -1106,16 +1115,17 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
> > >  		 * allowed to set a bit to 1 if the used function doesn't say it
> > >  		 * is used.
> > >  		 */
> > > -		WARN_ON_ONCE(target[i] & ~target_used[i]);
> > > +		WARN_ON_ONCE(target[i] & ~target_used[i] & ~ignored[i]);
> > >  
> > >  		/* Bits can change because they are not currently being used */
> > > -		unused_update[i] = (entry[i] & cur_used[i]) |
> > > +		unused_update[i] = (entry[i] & (cur_used[i] | ignored[i])) |
> > >  				   (target[i] & ~cur_used[i]);
> > 
> > This can't be right? We don't want to ever copy an ignored bit from
> > entry, the ignored bits should always come from target. The line
> > should be left alone.
> 
> Hmm, without this change, the following coverages will be broken:
>   arm_smmu_v3_write_ste_test_s1dssbypass_to_stebypass
>   arm_smmu_v3_write_ste_test_stebypass_to_s1dssbypass
> 
> Both were expect num_syncs=2, but it would be 3 if we don't include
> the ignored bits to unused_update. Or should we update the num_syncs
> instead?

Hmm!

I think that supports more that we should do what Shuai suggested and
keep used as-is.

Then ignored should be adjusted by the used: Only if both used are 1
should the bit become ignored. Otherwise we can rely on which ever
used is 0 to generate the hitless update.

That will preserve the tests and minimize the cases where we rely on
the ignored exception - though the reasoning for ignore is sound and
the two tests could be updated just fine to num_syncs=2 as well.

Like this?

--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1094,13 +1094,22 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
 {
        __le64 target_used[NUM_ENTRY_QWORDS] = {};
        __le64 cur_used[NUM_ENTRY_QWORDS] = {};
+       __le64 ignored[NUM_ENTRY_QWORDS] = {};
        u8 used_qword_diff = 0;
        unsigned int i;
 
        writer->ops->get_used(entry, cur_used);
        writer->ops->get_used(target, target_used);
+       if (writer->ops->get_ignored)
+               writer->ops->get_ignored(ignored);
 
        for (i = 0; i != NUM_ENTRY_QWORDS; i++) {
+               /*
+                * Ignored is only used for bits that are used by both entries,
+                * otherwise it is sequenced according to the unused entry.
+                */
+               ignored[i] &= target_used[i] & cur_used[i];
+
                /*
                 * Check that masks are up to date, the make functions are not
                 * allowed to set a bit to 1 if the used function doesn't say it
@@ -1109,6 +1118,7 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
                WARN_ON_ONCE(target[i] & ~target_used[i]);
 
                /* Bits can change because they are not currently being used */
+               cur_used[i] &= ~ignored[i];
                unused_update[i] = (entry[i] & cur_used[i]) |
                                   (target[i] & ~cur_used[i]);
                /*

Jason


From nicolas.frattaroli at collabora.com  Sat Dec  6 12:45:10 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Sat, 06 Dec 2025 21:45:10 +0100
Subject: [PATCH v2 0/8] drm/rockchip: No more post-atomic_check fixups
Message-ID: <20251206-vop2-atomic-fixups-v2-0-7fb45bbfbebd@collabora.com>

I'm taking over this series to get it across the finish line. Original
cover letter from Daniel Stone on v1:

> Hi,
> This series is a pretty small and consistent one for VOP2. The atomic
> uAPI very clearly specifies that drivers should either do what userspace
> requested (on a successful commit), or fail atomic_check if it is not
> for any reason possible to do what userspace requested.
> 
> VOP2 is unfortunately littered with a bunch of cases where it will apply
> fixups after atomic_check - doing something different to what userspace
> requested, e.g. clipping or aligning regions - or throw error messages
> into the log when userspace does request a condition which can't be met.
> 
> Doing something different to what was requested is bad because it
> results in unexpected visual output which can look like artifacts.
> Throwing errors into the log is bad because generic userspace will
> reasonably attempt to try any configuration it can. For example,
> throwing an error message on a plane not being aligned to a 16 pixel
> boundary can result in 15 frames' worth of error output in the log when
> a window is being animated across a screen.
> 
> This series removes all post-check fixups - failing the check if the
> configuration cannot be applied - and also demotes all messages about
> unsupported configurations to DEBUG_KMS.
> 
> Cheers,
> Daniel

Changes in v2:
- Dropped patches [1, 5] as they were already applied.
- Changed the patch subject to use prefix "drm/rockchip: vop2:" for the
  remaining ones.
- Fixed a checkpatch nag about commenting style in "Switch impossible
  pos conditional to WARN_ON".
- Reworded "eSmart" to "Esmart" for consistency, and to avoid drawing
  Tim Apple's ire.
- Make the hopefully impossible WARN_ON format conditional in
  vop2_plane_atomic_check still bubble the error up to userspace,
  instead of continuing on.
- Use dest_w instead of dsp_w in patch "Enforce scaling workaround
  in plane_check", to avoid a compiler error.
- Only reject non-multiple-of-4-pixel-wide framebuffers on
  RK3566/RK3568, as the other SoCs have no such limitation. (Thank you
  to Andy Yan for doing the research to confirm this!)
- Consequently also only WARN_ON if this condition is violated in
  atomic_update on those SoCs.
- Link to v1: https://lore.kernel.org/dri-devel/20251015110042.41273-1-daniels at collabora.com/

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
Daniel Stone (8):
      drm/rockchip: vop2: Switch impossible format conditional to WARN_ON
      drm/rockchip: vop2: Switch impossible pos conditional to WARN_ON
      drm/rockchip: vop2: Fix Esmart test condition
      drm/rockchip: vop2: Enforce scaling workaround in plane_check
      drm/rockchip: vop2: Enforce AFBC source alignment in plane_check
      drm/rockchip: vop2: Enforce AFBC transform stride align in plane_check
      drm/rockchip: vop2: Use drm_is_afbc helper function
      drm/rockchip: vop2: Simplify format_mod_supported

 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 137 ++++++++++++---------------
 1 file changed, 62 insertions(+), 75 deletions(-)
---
base-commit: 4e5a9b630580faea139e9837b4fba666db6bd728
change-id: 20251206-vop2-atomic-fixups-0c30e0980f85

Best regards,
-- 
Nicolas Frattaroli <nicolas.frattaroli at collabora.com>



From nicolas.frattaroli at collabora.com  Sat Dec  6 12:45:11 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Sat, 06 Dec 2025 21:45:11 +0100
Subject: [PATCH v2 1/8] drm/rockchip: vop2: Switch impossible format
 conditional to WARN_ON
In-Reply-To: <20251206-vop2-atomic-fixups-v2-0-7fb45bbfbebd@collabora.com>
References: <20251206-vop2-atomic-fixups-v2-0-7fb45bbfbebd@collabora.com>
Message-ID: <20251206-vop2-atomic-fixups-v2-1-7fb45bbfbebd@collabora.com>

From: Daniel Stone <daniels at collabora.com>

We should never be able to create a framebuffer with an unsupported
format, so throw a warning if this ever happens, instead of attempting
to stagger on.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 498df0ce4680..20b49209ddcd 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1030,7 +1030,8 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
 		return 0;
 
 	format = vop2_convert_format(fb->format->format);
-	if (format < 0)
+	/* We shouldn't be able to create a fb for an unsupported format */
+	if (WARN_ON(format < 0))
 		return format;
 
 	/* Co-ordinates have now been clipped */

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Sat Dec  6 12:45:12 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Sat, 06 Dec 2025 21:45:12 +0100
Subject: [PATCH v2 2/8] drm/rockchip: vop2: Switch impossible pos
 conditional to WARN_ON
In-Reply-To: <20251206-vop2-atomic-fixups-v2-0-7fb45bbfbebd@collabora.com>
References: <20251206-vop2-atomic-fixups-v2-0-7fb45bbfbebd@collabora.com>
Message-ID: <20251206-vop2-atomic-fixups-v2-2-7fb45bbfbebd@collabora.com>

From: Daniel Stone <daniels at collabora.com>

We already clip the plane to the display bounds in atomic_check, and
ensure that it is sufficiently sized. Instead of trying to catch this
and adjust for it in atomic_update, just assert that atomic_check has
done its job.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 29 +++++++++-------------------
 1 file changed, 9 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 20b49209ddcd..81b3eba07095 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1214,28 +1214,17 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
 	src_w = drm_rect_width(src) >> 16;
 	src_h = drm_rect_height(src) >> 16;
 	dsp_w = drm_rect_width(dest);
-
-	if (dest->x1 + dsp_w > adjusted_mode->hdisplay) {
-		drm_dbg_kms(vop2->drm,
-			    "vp%d %s dest->x1[%d] + dsp_w[%d] exceed mode hdisplay[%d]\n",
-			    vp->id, win->data->name, dest->x1, dsp_w, adjusted_mode->hdisplay);
-		dsp_w = adjusted_mode->hdisplay - dest->x1;
-		if (dsp_w < 4)
-			dsp_w = 4;
-		src_w = dsp_w * src_w / drm_rect_width(dest);
-	}
-
 	dsp_h = drm_rect_height(dest);
 
-	if (dest->y1 + dsp_h > adjusted_mode->vdisplay) {
-		drm_dbg_kms(vop2->drm,
-			    "vp%d %s dest->y1[%d] + dsp_h[%d] exceed mode vdisplay[%d]\n",
-			    vp->id, win->data->name, dest->y1, dsp_h, adjusted_mode->vdisplay);
-		dsp_h = adjusted_mode->vdisplay - dest->y1;
-		if (dsp_h < 4)
-			dsp_h = 4;
-		src_h = dsp_h * src_h / drm_rect_height(dest);
-	}
+	/* drm_atomic_helper_check_plane_state calls drm_rect_clip_scaled for
+	 * us, which keeps our planes bounded within the CRTC active area
+	 */
+	WARN_ON(dest->x1 + dsp_w > adjusted_mode->hdisplay);
+	WARN_ON(dest->y1 + dsp_h > adjusted_mode->vdisplay);
+	WARN_ON(dsp_w < 4);
+	WARN_ON(dsp_h < 4);
+	WARN_ON(src_w < 4);
+	WARN_ON(src_h < 4);
 
 	/*
 	 * This is workaround solution for IC design:

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Sat Dec  6 12:45:14 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Sat, 06 Dec 2025 21:45:14 +0100
Subject: [PATCH v2 4/8] drm/rockchip: vop2: Enforce scaling workaround in
 plane_check
In-Reply-To: <20251206-vop2-atomic-fixups-v2-0-7fb45bbfbebd@collabora.com>
References: <20251206-vop2-atomic-fixups-v2-0-7fb45bbfbebd@collabora.com>
Message-ID: <20251206-vop2-atomic-fixups-v2-4-7fb45bbfbebd@collabora.com>

From: Daniel Stone <daniels at collabora.com>

It seems only cluster windows are capable of applying downscaling when
the source region has an odd width. Instead of applying a workaround
inside atomic_update, fail the plane check if this is requested.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 9d715d7659af..bc1ed0ffede0 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -998,6 +998,7 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
 	struct drm_crtc *crtc = pstate->crtc;
 	struct drm_crtc_state *cstate;
 	struct vop2_video_port *vp;
+	struct vop2_win *win = to_vop2_win(plane);
 	struct vop2 *vop2;
 	const struct vop2_data *vop2_data;
 	struct drm_rect *dest = &pstate->dst;
@@ -1065,6 +1066,16 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
 		return -EINVAL;
 	}
 
+	/*
+	 * This is workaround solution for IC design:
+	 * esmart can't support scale down when src_w % 16 == 1.
+	 */
+	if (!vop2_cluster_window(win) && src_w > dest_w && (src_w & 1)) {
+		drm_dbg_kms(vop2->drm,
+			    "eSmart windows cannot downscale odd-width source regions\n");
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
@@ -1226,16 +1237,6 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
 	WARN_ON(src_w < 4);
 	WARN_ON(src_h < 4);
 
-	/*
-	 * This is workaround solution for IC design:
-	 * esmart can't support scale down when src_w % 16 == 1.
-	 */
-	if (!vop2_cluster_window(win) && src_w > dsp_w && (src_w & 1)) {
-		drm_dbg_kms(vop2->drm, "vp%d %s act_w[%d] MODE 16 == 1\n",
-			    vp->id, win->data->name, src_w);
-		src_w -= 1;
-	}
-
 	if (afbc_en && src_w % 4) {
 		drm_dbg_kms(vop2->drm, "vp%d %s src_w[%d] not 4 pixel aligned\n",
 			    vp->id, win->data->name, src_w);

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Sat Dec  6 12:45:13 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Sat, 06 Dec 2025 21:45:13 +0100
Subject: [PATCH v2 3/8] drm/rockchip: vop2: Fix Esmart test condition
In-Reply-To: <20251206-vop2-atomic-fixups-v2-0-7fb45bbfbebd@collabora.com>
References: <20251206-vop2-atomic-fixups-v2-0-7fb45bbfbebd@collabora.com>
Message-ID: <20251206-vop2-atomic-fixups-v2-3-7fb45bbfbebd@collabora.com>

From: Daniel Stone <daniels at collabora.com>

If we want to find out if a window is Esmart or not, test for not being
a cluster window, rather than AFBDC presence.

No functional effect as only cluster windows support AFBC decode.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 81b3eba07095..9d715d7659af 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1230,12 +1230,10 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
 	 * This is workaround solution for IC design:
 	 * esmart can't support scale down when src_w % 16 == 1.
 	 */
-	if (!(win->data->feature & WIN_FEATURE_AFBDC)) {
-		if (src_w > dsp_w && (src_w & 0xf) == 1) {
-			drm_dbg_kms(vop2->drm, "vp%d %s act_w[%d] MODE 16 == 1\n",
-				    vp->id, win->data->name, src_w);
-			src_w -= 1;
-		}
+	if (!vop2_cluster_window(win) && src_w > dsp_w && (src_w & 1)) {
+		drm_dbg_kms(vop2->drm, "vp%d %s act_w[%d] MODE 16 == 1\n",
+			    vp->id, win->data->name, src_w);
+		src_w -= 1;
 	}
 
 	if (afbc_en && src_w % 4) {

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Sat Dec  6 12:45:16 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Sat, 06 Dec 2025 21:45:16 +0100
Subject: [PATCH v2 6/8] drm/rockchip: vop2: Enforce AFBC transform stride
 align in plane_check
In-Reply-To: <20251206-vop2-atomic-fixups-v2-0-7fb45bbfbebd@collabora.com>
References: <20251206-vop2-atomic-fixups-v2-0-7fb45bbfbebd@collabora.com>
Message-ID: <20251206-vop2-atomic-fixups-v2-6-7fb45bbfbebd@collabora.com>

From: Daniel Stone <daniels at collabora.com>

Make sure we can't break the hardware by requesting an unsupported
configuration.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index e23213337104..2a308cc31632 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1083,6 +1083,15 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
 		return -EINVAL;
 	}
 
+	if (drm_is_afbc(fb->modifier) &&
+	    pstate->rotation &
+		(DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270) &&
+	    (fb->pitches[0] << 3) / vop2_get_bpp(fb->format) % 64) {
+		drm_dbg_kms(vop2->drm,
+			    "AFBC buffers must be 64-byte aligned for horizontal rotation or mirroring\n");
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
@@ -1290,9 +1299,6 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
 		 * with WIN_VIR_STRIDE.
 		 */
 		stride = (fb->pitches[0] << 3) / bpp;
-		if ((stride & 0x3f) && (xmirror || rotate_90 || rotate_270))
-			drm_dbg_kms(vop2->drm, "vp%d %s stride[%d] not 64 pixel aligned\n",
-				    vp->id, win->data->name, stride);
 
 		 /* It's for head stride, each head size is 16 byte */
 		stride = ALIGN(stride, block_w) / block_w * 16;

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Sat Dec  6 12:45:15 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Sat, 06 Dec 2025 21:45:15 +0100
Subject: [PATCH v2 5/8] drm/rockchip: vop2: Enforce AFBC source alignment
 in plane_check
In-Reply-To: <20251206-vop2-atomic-fixups-v2-0-7fb45bbfbebd@collabora.com>
References: <20251206-vop2-atomic-fixups-v2-0-7fb45bbfbebd@collabora.com>
Message-ID: <20251206-vop2-atomic-fixups-v2-5-7fb45bbfbebd@collabora.com>

From: Daniel Stone <daniels at collabora.com>

Planes can only source AFBC framebuffers at multiples of 4px wide on
RK3566/RK3568. Instead of clipping on all SoCs when the user asks for an
unaligned source rectangle, reject the configuration in the plane's
atomic check on RK3566/RK3568 only.

Signed-off-by: Daniel Stone <daniels at collabora.com>
[Make RK3566/RK3568 specific, reword message]
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index bc1ed0ffede0..e23213337104 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1076,6 +1076,13 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
 		return -EINVAL;
 	}
 
+	if (vop2->version == VOP_VERSION_RK3568 && drm_is_afbc(fb->modifier) && src_w % 4) {
+		drm_dbg_kms(vop2->drm,
+			    "AFBC source rectangles must be 4-byte aligned; is %d\n",
+			    src_w);
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
@@ -1237,11 +1244,8 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
 	WARN_ON(src_w < 4);
 	WARN_ON(src_h < 4);
 
-	if (afbc_en && src_w % 4) {
-		drm_dbg_kms(vop2->drm, "vp%d %s src_w[%d] not 4 pixel aligned\n",
-			    vp->id, win->data->name, src_w);
-		src_w = ALIGN_DOWN(src_w, 4);
-	}
+	if (vop2->version == VOP_VERSION_RK3568 && drm_is_afbc(fb->modifier))
+		WARN_ON(src_w % 4);
 
 	act_info = (src_h - 1) << 16 | ((src_w - 1) & 0xffff);
 	dsp_info = (dsp_h - 1) << 16 | ((dsp_w - 1) & 0xffff);

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Sat Dec  6 12:45:17 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Sat, 06 Dec 2025 21:45:17 +0100
Subject: [PATCH v2 7/8] drm/rockchip: vop2: Use drm_is_afbc helper function
In-Reply-To: <20251206-vop2-atomic-fixups-v2-0-7fb45bbfbebd@collabora.com>
References: <20251206-vop2-atomic-fixups-v2-0-7fb45bbfbebd@collabora.com>
Message-ID: <20251206-vop2-atomic-fixups-v2-7-7fb45bbfbebd@collabora.com>

From: Daniel Stone <daniels at collabora.com>

We don't need to do a long open-coded walk here; we can simply check the
modifier value.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 2a308cc31632..8e0727c3523f 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1207,7 +1207,7 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
 		return;
 	}
 
-	afbc_en = rockchip_afbc(plane, fb->modifier);
+	afbc_en = drm_is_afbc(fb->modifier);
 
 	offset = (src->x1 >> 16) * fb->format->cpp[0];
 

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Sat Dec  6 12:45:18 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Sat, 06 Dec 2025 21:45:18 +0100
Subject: [PATCH v2 8/8] drm/rockchip: vop2: Simplify format_mod_supported
In-Reply-To: <20251206-vop2-atomic-fixups-v2-0-7fb45bbfbebd@collabora.com>
References: <20251206-vop2-atomic-fixups-v2-0-7fb45bbfbebd@collabora.com>
Message-ID: <20251206-vop2-atomic-fixups-v2-8-7fb45bbfbebd@collabora.com>

From: Daniel Stone <daniels at collabora.com>

Make it a little less convoluted, and just directly check if the
combination of plane + format + modifier is supported.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 56 +++++++++++-----------------
 1 file changed, 22 insertions(+), 34 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 8e0727c3523f..10b59487019c 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -367,59 +367,47 @@ static bool is_yuv_output(u32 bus_format)
 	}
 }
 
-static bool rockchip_afbc(struct drm_plane *plane, u64 modifier)
-{
-	int i;
-
-	if (modifier == DRM_FORMAT_MOD_LINEAR)
-		return false;
-
-	for (i = 0 ; i < plane->modifier_count; i++)
-		if (plane->modifiers[i] == modifier)
-			return true;
-
-	return false;
-}
-
 static bool rockchip_vop2_mod_supported(struct drm_plane *plane, u32 format,
 					u64 modifier)
 {
 	struct vop2_win *win = to_vop2_win(plane);
 	struct vop2 *vop2 = win->vop2;
+	int i;
 
+	/* No support for implicit modifiers */
 	if (modifier == DRM_FORMAT_MOD_INVALID)
 		return false;
 
-	if (vop2->version == VOP_VERSION_RK3568) {
-		if (vop2_cluster_window(win)) {
-			if (modifier == DRM_FORMAT_MOD_LINEAR) {
-				drm_dbg_kms(vop2->drm,
-					    "Cluster window only supports format with afbc\n");
-				return false;
-			}
-		}
+	/* The cluster window on 3568 is AFBC-only */
+	if (vop2->version == VOP_VERSION_RK3568 && vop2_cluster_window(win) &&
+	    !drm_is_afbc(modifier)) {
+		drm_dbg_kms(vop2->drm,
+			    "Cluster window only supports format with afbc\n");
+		return false;
 	}
 
-	if (format == DRM_FORMAT_XRGB2101010 || format == DRM_FORMAT_XBGR2101010) {
-		if (vop2->version == VOP_VERSION_RK3588) {
-			if (!rockchip_afbc(plane, modifier)) {
-				drm_dbg_kms(vop2->drm, "Only support 32 bpp format with afbc\n");
-				return false;
-			}
-		}
+	/* 10bpc formats on 3588 are AFBC-only */
+	if (vop2->version == VOP_VERSION_RK3588 && !drm_is_afbc(modifier) &&
+	    (format == DRM_FORMAT_XRGB2101010 || format == DRM_FORMAT_XBGR2101010)) {
+		drm_dbg_kms(vop2->drm, "Only support 10bpc format with afbc\n");
+		return false;
 	}
 
+	/* Linear is otherwise supported everywhere */
 	if (modifier == DRM_FORMAT_MOD_LINEAR)
 		return true;
 
-	if (!rockchip_afbc(plane, modifier)) {
-		drm_dbg_kms(vop2->drm, "Unsupported format modifier 0x%llx\n",
-			    modifier);
-
+	/* Not all format+modifier combinations are allowable */
+	if (vop2_convert_afbc_format(format) == VOP2_AFBC_FMT_INVALID)
 		return false;
+
+	/* Different windows have different format/modifier support */
+	for (i = 0; i < plane->modifier_count; i++) {
+		if (plane->modifiers[i] == modifier)
+			return true;
 	}
 
-	return vop2_convert_afbc_format(format) >= 0;
+	return false;
 }
 
 /*

-- 
2.52.0



From ebiggers at kernel.org  Sat Dec  6 17:30:04 2025
From: ebiggers at kernel.org (Eric Biggers)
Date: Sat, 6 Dec 2025 17:30:04 -0800
Subject: [PATCH] arm64/simd: Avoid pointless clearing of FP/SIMD buffer
In-Reply-To: <CAMj1kXE8qn7MSY1A31CrHRSxw+NXqNGLo=FLo4D-COMhxPAMiw@mail.gmail.com>
References: <20251204162815.522879-2-ardb@kernel.org>
 <20251205064809.GA26371@sol>
 <CAMj1kXE8qn7MSY1A31CrHRSxw+NXqNGLo=FLo4D-COMhxPAMiw@mail.gmail.com>
Message-ID: <20251207013004.GA143349@sol>

On Fri, Dec 05, 2025 at 09:13:46AM +0100, Ard Biesheuvel wrote:
> On Fri, 5 Dec 2025 at 07:50, Eric Biggers <ebiggers at kernel.org> wrote:
> >
> > On Thu, Dec 04, 2025 at 05:28:15PM +0100, Ard Biesheuvel wrote:
> > > The buffer provided to kernel_neon_begin() is only used if the task is
> > > scheduled out while the FP/SIMD is in use by the kernel, or when such a
> > > section is interrupted by a softirq that also uses the FP/SIMD.
> > >
> > > IOW, this happens rarely, and even if it happened often, there is still
> > > no reason for this buffer to be cleared beforehand, which happens by
> > > default when using a compiler that supports -ftrivial-auto-var-init.
> > >
> > > So mark the buffer as __uninitialized. Given that this is a variable
> > > attribute not a type attribute, this requires that the expression is
> > > tweaked a bit.
> > >
> > > Cc: Will Deacon <will at kernel.org>,
> > > Cc: Catalin Marinas <catalin.marinas at arm.com>,
> > > Cc: Kees Cook <keescook at chromium.org>
> > > Cc: Eric Biggers <ebiggers at kernel.org>
> > > Cc: Justin Stitt <justinstitt at google.com>
> > > Signed-off-by: Ard Biesheuvel <ardb at kernel.org>
> > > ---
> > >  arch/arm64/include/asm/simd.h | 3 ++-
> > >  1 file changed, 2 insertions(+), 1 deletion(-)
> > >
> > > The issue here is that returning a pointer to an automatic variable as
> > > it goes out of scope is slightly dodgy, especially in the context of
> > > __attribute__((cleanup())), on which the scoped guard API relies
> > > heavily. However, in this case it should be safe, given that this
> > > expression is the input to the guarded variable type's constructor.
> > >
> > > It is definitely not pretty, though, so hopefully here is a better way
> > > to attach this.
> > >
> > > diff --git a/arch/arm64/include/asm/simd.h b/arch/arm64/include/asm/simd.h
> > > index 0941f6f58a14..825b7fe94003 100644
> > > --- a/arch/arm64/include/asm/simd.h
> > > +++ b/arch/arm64/include/asm/simd.h
> > > @@ -48,6 +48,7 @@ DEFINE_LOCK_GUARD_1(ksimd,
> > >                   kernel_neon_begin(_T->lock),
> > >                   kernel_neon_end(_T->lock))
> > >
> > > -#define scoped_ksimd()       scoped_guard(ksimd, &(struct user_fpsimd_state){})
> > > +#define scoped_ksimd()       \
> > > +     scoped_guard(ksimd, ({ struct user_fpsimd_state __uninitialized s; &s; }))
> >
> > Ick.  I should have looked at the generated code more closely.
> >
> > It's actually worse than you describe, because the zeroing is there even
> > without CONFIG_INIT_STACK_ALL_ZERO=y, simply because the
> > user_fpsimd_state struct is declared using a compound literal.
> >
> > I'm afraid that this patch probably isn't a good idea, as it relies on
> > undefined behavior.  Before this patch, the user_fpsimd_state is
> > declared using a compound literal, which takes on its enclosing scope,
> > i.e. the 'for' statement generated by scoped_guard().  After this patch,
> > it's in a new inner scope, and the pointer to it escapes from it.
> >
> > Unfortunately I don't think there's any way to solve this while keeping
> > the scoped_ksimd() API as-is.
> >
> 
> How about
> 
> --- a/arch/arm64/include/asm/simd.h
> +++ b/arch/arm64/include/asm/simd.h
> @@ -48,6 +48,8 @@ DEFINE_LOCK_GUARD_1(ksimd,
>                     kernel_neon_begin(_T->lock),
>                     kernel_neon_end(_T->lock))
> 
> -#define scoped_ksimd() scoped_guard(ksimd, &(struct user_fpsimd_state){})
> +#define scoped_ksimd()         __scoped_ksimd(__UNIQUE_ID(fpsimd_state))
> +#define __scoped_ksimd(id)     struct user_fpsimd_state __uninitialized id; \
> +                               scoped_guard(ksimd, &id)

I guess that will work.  It's not great that it will make scoped_ksimd()
expand into more than one statement, which is error-prone and not
normally allowed in macros.  But it looks okay for all the current users
of it.

- Eric


From nicolinc at nvidia.com  Sat Dec  6 20:37:30 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Sat, 6 Dec 2025 20:37:30 -0800
Subject: [PATCH rc v1 1/4] iommu/arm-smmu-v3: Add ignored bits to fix STE
 update sequence
In-Reply-To: <20251206195752.GI1219718@nvidia.com>
References: <cover.1764982046.git.nicolinc@nvidia.com>
 <6ec73bb7cd03d90a0764f12c4b14071158163818.1764982046.git.nicolinc@nvidia.com>
 <20251206193408.GD1219718@nvidia.com>
 <aTSH5Eap7leYQtPl@nvidia.com>
 <20251206195752.GI1219718@nvidia.com>
Message-ID: <aTUEikcWXWwKAS/1@nvidia.com>

On Sat, Dec 06, 2025 at 03:57:52PM -0400, Jason Gunthorpe wrote:
> I think that supports more that we should do what Shuai suggested and
> keep used as-is.

Yes, that will be probably cleaner.

> Then ignored should be adjusted by the used: Only if both used are 1
> should the bit become ignored. Otherwise we can rely on which ever
> used is 0 to generate the hitless update.

Hmm, not sure why it has to be both used.

The unused_update is computed using cur_used, and the equation for
used_qword_diff is computed using target_used, either of which can
be affected by ignored bits, right?

E.g.
if cur_used[] includes ING bit, target_used doesn't:
    // target must unset IGN bit, last equation isn't affected
    if cur sets IGN bit
        cur_used should exclude IGN bit
    if cur unsets IGN bit
        not affected
if cur_used[] doesn't include ignores, target_used does:
    // cur must unset IGN bit, cur_used isn't affected
    if target sets IGN bit:
        last equation must exclude IGN bit on both sides
    if target unsets IGN bit:
        not affected

> @@ -1109,6 +1118,7 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
>                 WARN_ON_ONCE(target[i] & ~target_used[i]);
>  
>                 /* Bits can change because they are not currently being used */
> +               cur_used[i] &= ~ignored[i];
>                 unused_update[i] = (entry[i] & cur_used[i]) |
>                                    (target[i] & ~cur_used[i]);

If one of ignored bits is set in entry[i] but unset in target[i],
the unused_update will first mask it away, resulting in an extra
unnecessary update (though it's still hitless).

So, I think this might be better:

-		cur_used[i] &= ~ignored[i];
+		cur_unused[i] = ~cur_used[i] | ignored[i];
 		unused_update[i] = (entry[i] & cur_used[i]) |
-				   (target[i] & ~cur_used[i]);
+				   (target[i] & cur_unused[i]);

Because cur_used includes ignored, the unused_update will retain
the ignored bits from entry. On the other hand, having cur_unused
will also retain the ignored bits from target.

One more change that we need is at the last equation:
-		if ((unused_update[i] & target_used[i]) != target[i])
+		if ((unused_update[i] & target_used[i] & ~ignored[i]) !=
+		    (target[i] & ~ignored[i]))

Either side might have the ignored bits, so we have to suppress
ignored on both sides, which is required in the similar routine
in arm_smmu_entry_differs_in_used_bits() of the kunit code.

With these additional changes, nesting sanity and kunit test are
both passing. I will do a few more tests to make sure things are
okay, before wrapping up the v2. Please let me know if all these
make sense to you.

Thanks
Nicolin


From daniel at gibson.sh  Sat Dec  6 20:55:15 2025
From: daniel at gibson.sh (Daniel Gibson)
Date: Sun, 7 Dec 2025 05:55:15 +0100
Subject: [PATCH 05/12] gpio: it87: use new line value setter callbacks
In-Reply-To: <20250423-gpiochip-set-rv-gpio-part2-v1-5-b22245cde81a@linaro.org>
References: <20250423-gpiochip-set-rv-gpio-part2-v1-0-b22245cde81a@linaro.org>
 <20250423-gpiochip-set-rv-gpio-part2-v1-5-b22245cde81a@linaro.org>
Message-ID: <bd0a00e3-9b8c-43e8-8772-e67b91f4c71e@gibson.sh>

Hi,
I got one nitpick/question about this, see below

On 4/23/25 09:15, Bartosz Golaszewski wrote:
> @@ -249,7 +250,9 @@ static int it87_gpio_direction_out(struct gpio_chip *chip,
>  	/* set the output enable bit */
>  	superio_set_mask(mask, group + it87_gpio->output_base);
>  
> -	it87_gpio_set(chip, gpio_num, val);
> +	rc = it87_gpio_set(chip, gpio_num, val);
> +	if (rc)
> +		goto exit;
>  >  	superio_exit();

Are you sure that superio_exit() should be skipped (with goto exit) in
case it87_gpio_set() fails?
After all, superio_enter() above (not visible here) succeeded,
only the it87_gpio_set() call failed.

Of course this is kinda academic because currently it87_gpio_set()
always returns 0, but if it ever doesn't, this might become a bug?

Cheers,
Daniel


From anup at brainfault.org  Sat Dec  6 21:14:13 2025
From: anup at brainfault.org (Anup Patel)
Date: Sun, 7 Dec 2025 10:44:13 +0530
Subject: [PATCH] KVM: Remove subtle "struct kvm_stats_desc" pseudo-overlay
In-Reply-To: <20251205232655.445294-1-seanjc@google.com>
References: <20251205232655.445294-1-seanjc@google.com>
Message-ID: <CAAhSdy1cPnxjntaR=cwZqG+oVgFpZKM0rKYAEdkHUCToMvN0Ag@mail.gmail.com>

On Sat, Dec 6, 2025 at 4:57?AM Sean Christopherson <seanjc at google.com> wrote:
>
> Remove KVM's internal pseudo-overlay of kvm_stats_desc, which subtly
> aliases the flexible name[] in the uAPI definition with a fixed-size array
> of the same name.  The unusual embedded structure results in compiler
> warnings due to -Wflex-array-member-not-at-end, and also necessitates an
> extra level of dereferencing in KVM.  To avoid the "overlay", define the
> uAPI structure to have a fixed-size name when building for the kernel.
>
> Opportunistically clean up the indentation for the stats macros, and
> replace spaces with tabs.
>
> No functional change intended.
>
> Reported-by: Gustavo A. R. Silva <gustavoars at kernel.org>
> Closes: https://lore.kernel.org/all/aPfNKRpLfhmhYqfP at kspp
> Signed-off-by: Sean Christopherson <seanjc at google.com>

For KVM RISC-V:
Acked-by: Anup Patel <anup at brainfault.org>

Thanks,
Anup


From lkp at intel.com  Sun Dec  7 00:42:15 2025
From: lkp at intel.com (kernel test robot)
Date: Sun, 7 Dec 2025 16:42:15 +0800
Subject: [PATCH v7 5/6] clocksource/drivers/exynos_mct: Add module
 support for ARM64
In-Reply-To: <20251205011027.720512-6-willmcvicker@google.com>
References: <20251205011027.720512-6-willmcvicker@google.com>
Message-ID: <202512071659.We0N43XW-lkp@intel.com>

Hi Will,

kernel test robot noticed the following build warnings:

[auto build test WARNING on bca42080637ce3a21092fc0f7d5411e853b0c3b3]

url:    https://github.com/intel-lab-lkp/linux/commits/Will-McVicker/clocksource-drivers-exynos_mct-Don-t-register-as-a-sched_clock-on-arm64/20251205-091403
base:   bca42080637ce3a21092fc0f7d5411e853b0c3b3
patch link:    https://lore.kernel.org/r/20251205011027.720512-6-willmcvicker%40google.com
patch subject: [PATCH v7 5/6] clocksource/drivers/exynos_mct: Add module support for ARM64
config: arm64-randconfig-001-20251207 (https://download.01.org/0day-ci/archive/20251207/202512071659.We0N43XW-lkp at intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project a805147ac1ba123916de182babb0831fbb148756)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251207/202512071659.We0N43XW-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512071659.We0N43XW-lkp at intel.com/

All warnings (new ones prefixed by >>, old ones prefixed by <<):

>> WARNING: modpost: vmlinux: section mismatch in reference: exynos4_mct_probe+0x84 (section: .text) -> mct_init_dt (section: .init.text)

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From marek.vasut at mailbox.org  Sun Dec  7 01:01:06 2025
From: marek.vasut at mailbox.org (Marek Vasut)
Date: Sun, 7 Dec 2025 10:01:06 +0100
Subject: [PATCH] arm64: dts: imx95: Use GPU_CGC as core clock for GPU
In-Reply-To: <aTKVMAMQ6v_BwD6R@oss.nxp.com>
References: <20251129143220.14834-1-marek.vasut@mailbox.org>
 <aS-lEibp3zTsaR6T@oss.nxp.com>
 <c6e0e55a-06da-4665-972e-e9b5b8c08bf7@mailbox.org>
 <aTACuRjC_Zpf8IOU@oss.nxp.com>
 <de36091e-c890-4897-b3e3-2a7575029a5d@mailbox.org>
 <aTD5np-HGaJqhzkD@oss.nxp.com>
 <5944d872-01a3-47e9-977b-029f3be4fd83@mailbox.org>
 <aTKVMAMQ6v_BwD6R@oss.nxp.com>
Message-ID: <9b593731-898f-46a7-8ee5-68f8c170351c@mailbox.org>

On 12/5/25 9:17 AM, Rain Yang wrote:
> On Thu, Dec 04, 2025 at 04:25:38AM +0100, Marek Vasut wrote:
>> On 12/4/25 4:01 AM, Rain Yang wrote:
>>
>> [...]
>>>>> For the Linux working environment,
>>>>> CLK_GPU and CLK_GPUAPB are always-on, while CLK_GPU_CGC can be gated off.
>>>>>
>>>>> Regarding the IMX95_CLK_GPUAPB handle, my suggestion was based on the absence
>>>>> of its frequency in any OPP entry within the frequency table. Removing it
>>>>> could simplify the OPP handling logic and reduce unnecessary complexity.
>>>>
>>>> If the clock can be disabled by SM, Linux has to make sure they are NOT
>>>> disabled, so they must be described in DT, right ?
>>>>
>>>>> [1] https://github.com/nxp-imx/linux-imx/commit/695f2bdc57b869ca5189313e4b5fa7eb5a12f622
>>> Currently, only CLK_GPU_CGC shall be described in the Device Tree[1], as it can be gated.
>>> The other clocks (CLK_GPU and CLK_GPUAPB) are always-on in the Linux environment,
>>> so describing any of them in DT is not necessary and would not be proper in this context.
>>
>> Since this discussion is in fact unrelated to this bugfix, I would propose to
>> fork the discussion into a separate patch. Can you please submit a patch for
>> the GPUAPB clock ? Note that I believe GPUAPB clock have to be described in
>> DT, if only because DT is a hardware description, and to make sure the GPUAPB
>> clock are correctly enabled by the driver.
> 
> Okay, I?ll submit a patch later.
> The commit message should reflect that only CLK_GPU_CGC is enabled.

The commit message , and this change , is unrelated to GPUAPB clock.


From marek.vasut at mailbox.org  Sun Dec  7 01:16:36 2025
From: marek.vasut at mailbox.org (Marek Vasut)
Date: Sun, 7 Dec 2025 10:16:36 +0100
Subject: [PATCH 1/2] dt-bindings: firmware: arm,scmi: Document
 arm,poll-transport property
In-Reply-To: <20251205-winged-quizzical-pigeon-ed692d@sudeepholla>
References: <5ae0a793-d3e7-45d1-bf5c-3c46593d1824@mailbox.org>
 <aRW7BZimWdpq4TyX@pluto> <20251202-evasive-neon-rhino-d2745e@sudeepholla>
 <66257fcf-9024-454f-b776-4ba584963ebe@mailbox.org> <aS82GSN8c2SnRn4S@bogus>
 <8d773671-5e2e-4e21-ade6-2bf9a3b75066@mailbox.org>
 <20251203-thick-didactic-cockatoo-deaa1d@sudeepholla>
 <4ccbcffd-bcc7-478b-a525-a4a11e3092ee@mailbox.org>
 <20251204-calm-peacock-of-fantasy-6b8cbe@sudeepholla>
 <e25c690c-e74d-4641-a97e-8eae81a59168@mailbox.org>
 <20251205-winged-quizzical-pigeon-ed692d@sudeepholla>
Message-ID: <06fc0557-6b7c-4092-aeec-e3e16bab2d72@mailbox.org>

On 12/5/25 10:54 AM, Sudeep Holla wrote:

Hello Sudeep,

>>>>> Also IIUC, the irq request happens
>>>>> as part of channel startup and there are no explicit APIs for the mbox client
>>>>> driver to control that. SCMI is mbox client in this case.
>>>>
>>>> Sure, but the mailbox driver has to make sure it is correctly demuxing the
>>>> IRQs it handles and correctly sends received_data notifications to the right
>>>> channel(s) .
>>>>
>>>
>>> Agreed, but the concern is that if SCMI is forced to use polling when the
>>> channel is opened, and IRQs are enabled by default with no way for SCMI to
>>> disable them in polling mode, we could run into issues.
>>
>> This constellation seems odd -- if the channel can do IRQs, then this
>> property should not be present in DT.
>>
> 
> Yes, but there is no way to validate or check this and that is the root
> cause for all my worries.

Should a configuration like that even be considered valid and relevant ?

>>> I realise it?s a very
>>> specific corner case, but every time I?ve assumed such scenarios wouldn?t
>>> occur, we eventually ended up encountering them. So sorry if I am very
>>> pedantic, but I prefer to start smaller and restrictive and expand if and
>>> when necessary or required only.
>>
>> I don't think this case, where mailbox channel does IRQs and polling is
>> enabled, can/should even be considered valid. Either the channel does not do
>> IRQs and then it should do polling, or it does IRQs and then it should use
>> IRQs, but not both.
>>
> 
> Yes ideally, but having loose ends like this binding which allows someone
> to add it to their DT complicates though it is invalid. We have no way to
> detect and I don't want to work around such configs in the future.

If the DT is invalid, bad things happen, but I would argue that is then 
a DT bug and the DT should be fixed.

[...]

>>> Yes, that?s essential, because polling in an SMC context is meaningless in my
>>> opinion.
>>
>> Maybe the "a2p" IRQ is also used for notifications from longer running
>> operations ?
>>
> 
> Yes, it is some sort of work around some platforms implemented as by design
> when the SMC returns, the synchronous commands must complete and it is had
> to support async SCMI commands without platform specific interrupt(p2a). This
> a2p is sort of completion interrupt for synchronous command. I assume the
> platform may offload the task from secure f/w to something else otherwise
> secure side needs to be given CPU cycles to complete which complicates this.
> In short SMC is synchronous and if the execution returns from it in NS world,
> the command is complete.

Wouldn't polling still be useful for the async case , even in SMC setup?
Note that the SMC setup does use shmem, and therefore can do polling on 
the shmem.

>> [...]
>>
>>>>> Yes it can be minimalistic but not restrictive. As I already clearly mentioned
>>>>> I don't see it makes any sense to enable this for SMC/OPTEE. Lets start with
>>>>> just mailbox to start with and extend to other transports if and when needed.
>>>>> It would be good to impose that restriction in the binding as well but that
>>>>> is not a must IMO. I am fine if the bindings for whatever reasons(though I
>>>>> don't see the need) to apply for any transport.
>>>> So I should simply drop the smc.c changes , keep the rest, and send V2 ?
>>>
>>> Not just that. Unless DT maintainers oppose, I just want to keep this
>>> new property valid only for mailbox transport(i.e. "arm,scmi" compatible
>>> not otherwise) so that we can catch any other use in binding checks and
>>> interested parties must discuss on the list and expand that if they require.
>>>
>>> Also we can explore if we can parse and scan this in mailbox transport for
>>> now.
>> I feel that this only adds more implementation complexity and makes the
>> solution less generic, while it does win us very little in the end ? The
>> generic solution implementation is actually easier to implement.
> 
> Yes I want it less generic to start with. Why you want to start making
> this workaround on your platform a generic implementation just because
> the specification has provision for it ?

Because this is generic kernel code, it seems counterintuitive to 
introduce less generic solution which requires more complex implementation.

Since the DEN0056 specification states this mode of operation is 
supported, I also wouldn't call it a workaround.


From ardb at kernel.org  Sun Dec  7 01:59:29 2025
From: ardb at kernel.org (Ard Biesheuvel)
Date: Sun, 7 Dec 2025 10:59:29 +0100
Subject: [PATCH] arm64/simd: Avoid pointless clearing of FP/SIMD buffer
In-Reply-To: <20251207013004.GA143349@sol>
References: <20251204162815.522879-2-ardb@kernel.org> <20251205064809.GA26371@sol>
 <CAMj1kXE8qn7MSY1A31CrHRSxw+NXqNGLo=FLo4D-COMhxPAMiw@mail.gmail.com> <20251207013004.GA143349@sol>
Message-ID: <CAMj1kXEWYQYW92=yRG6sJmmrjc8MBz-fdauxX2pq+P2rKhcxmg@mail.gmail.com>

On Sun, 7 Dec 2025 at 02:30, Eric Biggers <ebiggers at kernel.org> wrote:
>
> On Fri, Dec 05, 2025 at 09:13:46AM +0100, Ard Biesheuvel wrote:
> > On Fri, 5 Dec 2025 at 07:50, Eric Biggers <ebiggers at kernel.org> wrote:
> > >
> > > On Thu, Dec 04, 2025 at 05:28:15PM +0100, Ard Biesheuvel wrote:
> > > > The buffer provided to kernel_neon_begin() is only used if the task is
> > > > scheduled out while the FP/SIMD is in use by the kernel, or when such a
> > > > section is interrupted by a softirq that also uses the FP/SIMD.
> > > >
> > > > IOW, this happens rarely, and even if it happened often, there is still
> > > > no reason for this buffer to be cleared beforehand, which happens by
> > > > default when using a compiler that supports -ftrivial-auto-var-init.
> > > >
> > > > So mark the buffer as __uninitialized. Given that this is a variable
> > > > attribute not a type attribute, this requires that the expression is
> > > > tweaked a bit.
> > > >
> > > > Cc: Will Deacon <will at kernel.org>,
> > > > Cc: Catalin Marinas <catalin.marinas at arm.com>,
> > > > Cc: Kees Cook <keescook at chromium.org>
> > > > Cc: Eric Biggers <ebiggers at kernel.org>
> > > > Cc: Justin Stitt <justinstitt at google.com>
> > > > Signed-off-by: Ard Biesheuvel <ardb at kernel.org>
> > > > ---
> > > >  arch/arm64/include/asm/simd.h | 3 ++-
> > > >  1 file changed, 2 insertions(+), 1 deletion(-)
> > > >
> > > > The issue here is that returning a pointer to an automatic variable as
> > > > it goes out of scope is slightly dodgy, especially in the context of
> > > > __attribute__((cleanup())), on which the scoped guard API relies
> > > > heavily. However, in this case it should be safe, given that this
> > > > expression is the input to the guarded variable type's constructor.
> > > >
> > > > It is definitely not pretty, though, so hopefully here is a better way
> > > > to attach this.
> > > >
> > > > diff --git a/arch/arm64/include/asm/simd.h b/arch/arm64/include/asm/simd.h
> > > > index 0941f6f58a14..825b7fe94003 100644
> > > > --- a/arch/arm64/include/asm/simd.h
> > > > +++ b/arch/arm64/include/asm/simd.h
> > > > @@ -48,6 +48,7 @@ DEFINE_LOCK_GUARD_1(ksimd,
> > > >                   kernel_neon_begin(_T->lock),
> > > >                   kernel_neon_end(_T->lock))
> > > >
> > > > -#define scoped_ksimd()       scoped_guard(ksimd, &(struct user_fpsimd_state){})
> > > > +#define scoped_ksimd()       \
> > > > +     scoped_guard(ksimd, ({ struct user_fpsimd_state __uninitialized s; &s; }))
> > >
> > > Ick.  I should have looked at the generated code more closely.
> > >
> > > It's actually worse than you describe, because the zeroing is there even
> > > without CONFIG_INIT_STACK_ALL_ZERO=y, simply because the
> > > user_fpsimd_state struct is declared using a compound literal.
> > >
> > > I'm afraid that this patch probably isn't a good idea, as it relies on
> > > undefined behavior.  Before this patch, the user_fpsimd_state is
> > > declared using a compound literal, which takes on its enclosing scope,
> > > i.e. the 'for' statement generated by scoped_guard().  After this patch,
> > > it's in a new inner scope, and the pointer to it escapes from it.
> > >
> > > Unfortunately I don't think there's any way to solve this while keeping
> > > the scoped_ksimd() API as-is.
> > >
> >
> > How about
> >
> > --- a/arch/arm64/include/asm/simd.h
> > +++ b/arch/arm64/include/asm/simd.h
> > @@ -48,6 +48,8 @@ DEFINE_LOCK_GUARD_1(ksimd,
> >                     kernel_neon_begin(_T->lock),
> >                     kernel_neon_end(_T->lock))
> >
> > -#define scoped_ksimd() scoped_guard(ksimd, &(struct user_fpsimd_state){})
> > +#define scoped_ksimd()         __scoped_ksimd(__UNIQUE_ID(fpsimd_state))
> > +#define __scoped_ksimd(id)     struct user_fpsimd_state __uninitialized id; \
> > +                               scoped_guard(ksimd, &id)
>
> I guess that will work.  It's not great that it will make scoped_ksimd()
> expand into more than one statement, which is error-prone and not
> normally allowed in macros.  But it looks okay for all the current users
> of it.
>

We could always repeat the 'for()' trick that the cleanup helpers use, e.g.,

for (struct user_fpsimd_state __uninitialized __st; true; ({ goto label; }))
    if (0) {
label:    break;
    } else scoped_guard(ksimd, &__st)

Would you prefer that?


From tiwai at suse.de  Sun Dec  7 04:17:57 2025
From: tiwai at suse.de (Takashi Iwai)
Date: Sun, 07 Dec 2025 13:17:57 +0100
Subject: [PATCH] ALSA: Do not build obsolete API
In-Reply-To: <20251203-old-alsa-v1-1-ac80704f52c3@ixit.cz>
References: <20251203-old-alsa-v1-1-ac80704f52c3@ixit.cz>
Message-ID: <87pl8qv62y.wl-tiwai@suse.de>

On Wed, 03 Dec 2025 23:34:10 +0100,
David Heidelberg via B4 Relay wrote:
> 
> From: David Heidelberg <david at ixit.cz>
> 
> ALSA 0.9.0-rc3 is from 2002, 23 years old.
> 
> Signed-off-by: David Heidelberg <david at ixit.cz>
> ---
> Maybe I could drop also the code and Kconfig option?

Thanks, applied now.

I believe it's safer to have this default only off for 6.19, then
disable for 6.20, eventually drop the dead code later.


Takashi


From madhurkumar004 at gmail.com  Sun Dec  7 04:34:47 2025
From: madhurkumar004 at gmail.com (Madhur Kumar)
Date: Sun,  7 Dec 2025 18:04:47 +0530
Subject: [PATCH] drivers: net: wireless: Replace deprecated PCI function
Message-ID: <20251207123447.93233-1-madhurkumar004@gmail.com>

pcim_iomap_table() and pcim_iomap_regions() have been
deprecated.
Replace them with pcim_iomap_region().

Signed-off-by: Madhur Kumar <madhurkumar004 at gmail.com>
---
 drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
index ec9686183251..5a82c3bf471f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
@@ -284,10 +284,6 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
 	if (ret)
 		return ret;
 
-	ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev));
-	if (ret)
-		return ret;
-
 	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
 	if (!(cmd & PCI_COMMAND_MEMORY)) {
 		cmd |= PCI_COMMAND_MEMORY;
@@ -325,7 +321,7 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
 	dev->fw_features = features;
 	dev->hif_ops = &mt7921_pcie_ops;
 	dev->irq_map = &irq_map;
-	mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]);
+	mt76_mmio_init(&dev->mt76, pcim_iomap_region(pdev, 0, pci_name(pdev)));
 	tasklet_init(&mdev->irq_tasklet, mt792x_irq_tasklet, (unsigned long)dev);
 
 	dev->phy.dev = dev;
-- 
2.52.0



From maud_spierings at murena.io  Sun Dec  7 05:16:32 2025
From: maud_spierings at murena.io (Maud Spierings)
Date: Sun, 7 Dec 2025 14:16:32 +0100
Subject: [PATCH 0/4] Add HDMI 2.0 support to DW HDMI QP TX
In-Reply-To: <20251203-dw-hdmi-qp-scramb-v1-0-836fe7401a69@collabora.com>
References: <20251203-dw-hdmi-qp-scramb-v1-0-836fe7401a69@collabora.com>
Message-ID: <4ec78537-5184-4e6b-9ada-ff268fbe9c3e@murena.io>

Awesome work! I've been waiting for this feature!

I can now actually get 1440p100 on my display and 4k60 on my tv over HDMI.

Tested-by: Maud Spierings <maud_spierings at hotmail.com>

Kind regards,
Maud

> This patch series provides the missing support for high TMDS clock ratio
> and scrambling to DW HDMI QP TX library, required for handling HDMI 2.0
> display modes on RK3576 & RK3588 SoCs.
>
> In order to allow addressing the SCDC status lost on sink disconnects,
> it adds an atomic variant of the drm_bridge_funcs.detect callback and a
> new drm_bridge_detect_ctx() helper, which is further used in
> drm_bridge_connector to switch to ->detect_ctx hook.
>
> Furthermore, optimize HPD event handling in dw_hdmi_qp Rockchip platform
> driver to run the detect cycle on the affected connector only.
>
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
> ---
> Cristian Ciocaltea (4):
>        drm/bridge: Add ->detect_ctx hook and drm_bridge_detect_ctx()
>        drm/bridge-connector: Switch to using ->detect_ctx hook
>        drm/bridge: dw-hdmi-qp: Add high TMDS clock ratio and scrambling support
>        drm/rockchip: dw_hdmi_qp: Do not send HPD events for all connectors
>
>   drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c   | 174 +++++++++++++++++++++++--
>   drivers/gpu/drm/display/drm_bridge_connector.c |  73 ++++++-----
>   drivers/gpu/drm/drm_bridge.c                   |  58 +++++++++
>   drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c |  44 +++----
>   include/drm/drm_bridge.h                       |  30 +++++
>   5 files changed, 308 insertions(+), 71 deletions(-)
> ---
> base-commit: ac5b392a8c355001c4c3f230a0e4b1f904e359ca
> change-id: 20251203-dw-hdmi-qp-scramb-cdbd8b57ccf9



From lei.xu at nxp.com  Sun Dec  7 05:26:04 2025
From: lei.xu at nxp.com (Lei Xu)
Date: Sun, 07 Dec 2025 05:26:04 -0800
Subject: [PATCH 0/2] Add device tree support for NXP i.MX95 15x15 FRDM
 board
Message-ID: <20251207-127-v1-0-5a2eeb69f150@nxp.com>

The NXP i.MX95 15x15 FRDM board is a compact and cost-effective
development board based on the i.MX95 applications processor.

This patch set adds device tree support for the board:
 - Patch 1 introduces the DT compatible string.
 - Patch 2 provides the complete device tree description.

Signed-off-by: Lei Xu <lei.xu at nxp.com>
---
Lei Xu (2):
      dt-bindings: arm: fsl: Add compatible for i.MX95 15x15 FRDM board
      arm64: dts: freescale: imx95: Add support for i.MX95 15x15 FRDM board

 Documentation/devicetree/bindings/arm/fsl.yaml     |   1 +
 arch/arm64/boot/dts/freescale/Makefile             |   1 +
 arch/arm64/boot/dts/freescale/imx95-15x15-frdm.dts | 955 +++++++++++++++++++++
 3 files changed, 957 insertions(+)
---
base-commit: 6987d58a9cbc5bd57c983baa514474a86c945d56
change-id: 20251207-127-4e8551e8bdaf

Best regards,
-- 
Lei Xu <lei.xu at nxp.com>



From lei.xu at nxp.com  Sun Dec  7 05:26:05 2025
From: lei.xu at nxp.com (Lei Xu)
Date: Sun, 07 Dec 2025 05:26:05 -0800
Subject: [PATCH 1/2] dt-bindings: arm: fsl: Add compatible for i.MX95 15x15
 FRDM board
In-Reply-To: <20251207-127-v1-0-5a2eeb69f150@nxp.com>
References: <20251207-127-v1-0-5a2eeb69f150@nxp.com>
Message-ID: <20251207-127-v1-1-5a2eeb69f150@nxp.com>

Introduce a new DT compatible string for the NXP i.MX95 15x15 FRDM
development board, a compact and cost-effective platform based on
the i.MX95 applications processor.

Signed-off-by: Lei Xu <lei.xu at nxp.com>
---
 Documentation/devicetree/bindings/arm/fsl.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
index 68a2d5fecc43..4b6188d39be6 100644
--- a/Documentation/devicetree/bindings/arm/fsl.yaml
+++ b/Documentation/devicetree/bindings/arm/fsl.yaml
@@ -1432,6 +1432,7 @@ properties:
         items:
           - enum:
               - fsl,imx95-15x15-evk       # i.MX95 15x15 EVK Board
+              - fsl,imx95-15x15-frdm      # i.MX95 15x15 FRDM Board
               - fsl,imx95-19x19-evk       # i.MX95 19x19 EVK Board
               - toradex,verdin-imx95-19x19-evk  # i.MX95 Verdin Evaluation Kit (EVK)
           - const: fsl,imx95

-- 
2.34.1



From lei.xu at nxp.com  Sun Dec  7 05:26:06 2025
From: lei.xu at nxp.com (Lei Xu)
Date: Sun, 07 Dec 2025 05:26:06 -0800
Subject: [PATCH 2/2] arm64: dts: freescale: imx95: Add support for i.MX95
 15x15 FRDM board
In-Reply-To: <20251207-127-v1-0-5a2eeb69f150@nxp.com>
References: <20251207-127-v1-0-5a2eeb69f150@nxp.com>
Message-ID: <20251207-127-v1-2-5a2eeb69f150@nxp.com>

The i.MX95 15x15 FRDM board is a compact and cost-effective development
platform based on the i.MX95 applications processor.

Add device tree support for this board, including:
 - LPUART1 and LPUART5
 - NETC
 - USB
 - PCIe
 - uSDHC1, uSDHC2 and uSDHC3
 - FlexCAN2 and FlexCAN5
 - LPI2C2, LPI2C3, LPI2C4 and their child nodes
 - Watchdog3

Signed-off-by: Lei Xu <lei.xu at nxp.com>
---
 arch/arm64/boot/dts/freescale/Makefile             |   1 +
 arch/arm64/boot/dts/freescale/imx95-15x15-frdm.dts | 955 +++++++++++++++++++++
 2 files changed, 956 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index f30d3fd724d0..71308d19d35e 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -400,6 +400,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx93-tqma9352-mba93xxla.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx93-var-som-symphony.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx943-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx95-15x15-evk.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx95-15x15-frdm.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx95-19x19-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx95-19x19-evk-sof.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx95-toradex-smarc-dev.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx95-15x15-frdm.dts b/arch/arm64/boot/dts/freescale/imx95-15x15-frdm.dts
new file mode 100644
index 000000000000..61e815c858b8
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx95-15x15-frdm.dts
@@ -0,0 +1,955 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2025 NXP
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/phy/phy-imx8-pcie.h>
+#include <dt-bindings/pwm/pwm.h>
+#include <dt-bindings/usb/pd.h>
+#include "imx95.dtsi"
+
+#define BRD_SM_CTRL_SD3_WAKE		0x8000	/*!< PCAL6408A-0 */
+#define BRD_SM_CTRL_PCIE1_WAKE		0x8001	/*!< PCAL6408A-4 */
+#define BRD_SM_CTRL_BT_WAKE		0x8002	/*!< PCAL6408A-5 */
+#define BRD_SM_CTRL_PCIE2_WAKE		0x8003	/*!< PCAL6408A-6 */
+#define BRD_SM_CTRL_BUTTON		0x8004	/*!< PCAL6408A-7 */
+
+/ {
+	compatible = "fsl,imx95-15x15-frdm", "fsl,imx95";
+	model = "NXP i.MX95 15X15 FRDM board";
+
+	aliases {
+		ethernet0 = &enetc_port0;
+		ethernet1 = &enetc_port1;
+		gpio0 = &gpio1;
+		gpio1 = &gpio2;
+		gpio2 = &gpio3;
+		gpio3 = &gpio4;
+		gpio4 = &gpio5;
+		i2c0 = &lpi2c1;
+		i2c1 = &lpi2c2;
+		i2c2 = &lpi2c3;
+		i2c3 = &lpi2c4;
+		i2c4 = &lpi2c5;
+		i2c5 = &lpi2c6;
+		i2c6 = &lpi2c7;
+		i2c7 = &lpi2c8;
+		mmc0 = &usdhc1;
+		mmc1 = &usdhc2;
+		mmc2 = &usdhc3;
+		serial0 = &lpuart1;
+		serial4 = &lpuart5;
+	};
+
+	chosen {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		stdout-path = &lpuart1;
+	};
+
+	dmic: dmic {
+		compatible = "dmic-codec";
+		#sound-dai-cells = <0>;
+		num-channels = <2>;
+	};
+
+	reg_1p8v: regulator-1p8v {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <1800000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-name = "+V1.8_SW";
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "+V3.3_SW";
+	};
+
+	reg_5p0v: regulator-5p0v {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <5000000>;
+		regulator-min-microvolt = <5000000>;
+		regulator-name = "+V5.0_SW";
+	};
+
+	reg_can_stby: regulator-can-stby {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "can-stby";
+		gpio = <&pcal6524 7 GPIO_ACTIVE_LOW>;
+	};
+
+	reg_ext_3v3: regulator-ext-3v3 {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "VCCEXT_3V3";
+	};
+
+	reg_ext_5v: regulator-ext-5v {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-max-microvolt = <5000000>;
+		regulator-min-microvolt = <5000000>;
+		regulator-name = "VCCEXT_5V";
+		gpio = <&pcal6524 12 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_m2_ekey_pwr: regulator-m2-pwr {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "M.2-power-ekey";
+		gpio = <&pcal6524 16 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_m2_mkey_pwr: regulator-m2-mkey-pwr {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "M.2-mkey-power";
+		gpio = <&pcal6524 14 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_usdhc2_vmmc: regulator-usdhc2 {
+		compatible = "regulator-fixed";
+		off-on-delay-us = <12000>;
+		pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
+		pinctrl-names = "default";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "VDD_SD2_3V3";
+		gpio = <&gpio3 7 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_usdhc3_vmmc: regulator-usdhc3 {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "WLAN_EN";
+		vin-supply = <&reg_m2_ekey_pwr>;
+		gpio = <&pcal6524 9 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		/*
+		 * IW612 wifi chip needs more delay than other wifi chips to complete
+		 * the host interface initialization after power up, otherwise the
+		 * internal state of IW612 may be unstable, resulting in the failure of
+		 * the SDIO3.0 switch voltage.
+		 */
+		startup-delay-us = <20000>;
+	};
+
+	reg_usb_vbus: regulator-vbus {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <5000000>;
+		regulator-min-microvolt = <5000000>;
+		regulator-name = "USB_VBUS";
+		gpio = <&pcal6524 15 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_vref_1v8: regulator-adc-vref {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <1800000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-name = "vref_1v8";
+	};
+
+	reserved-memory {
+		ranges;
+		#address-cells = <2>;
+		#size-cells = <2>;
+
+		linux_cma: linux,cma {
+			compatible = "shared-dma-pool";
+			alloc-ranges = <0 0x80000000 0 0x7F000000>;
+			reusable;
+			size = <0 0x3c000000>;
+			linux,cma-default;
+		};
+
+		vdev0vring0: memory at 88000000 {
+			reg = <0 0x88000000 0 0x8000>;
+			no-map;
+		};
+
+		vdev0vring1: memory at 88008000 {
+			reg = <0 0x88008000 0 0x8000>;
+			no-map;
+		};
+
+		vdev1vring0: memory at 88010000 {
+			reg = <0 0x88010000 0 0x8000>;
+			no-map;
+		};
+
+		vdev1vring1: memory at 88018000 {
+			reg = <0 0x88018000 0 0x8000>;
+			no-map;
+		};
+
+		vdevbuffer: memory at 88020000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x88020000 0 0x100000>;
+			no-map;
+		};
+
+		rsc_table: memory at 88220000 {
+			reg = <0 0x88220000 0 0x1000>;
+			no-map;
+		};
+
+		vpu_boot: memory at a0000000 {
+			reg = <0 0xa0000000 0 0x100000>;
+			no-map;
+		};
+	};
+
+	sound-micfil {
+		compatible = "fsl,imx-audio-card";
+		model = "micfil-audio";
+
+		pri-dai-link {
+			link-name = "micfil hifi";
+			format = "i2s";
+
+			cpu {
+				sound-dai = <&micfil>;
+			};
+			codec {
+				sound-dai = <&dmic>;
+			};
+		};
+	};
+
+	usdhc3_pwrseq: usdhc3-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&pcal6524 8 GPIO_ACTIVE_LOW>;
+	};
+
+	memory at 80000000 {
+		reg = <0x0 0x80000000 0 0x80000000>;
+		device_type = "memory";
+	};
+};
+
+&adc1 {
+	vref-supply = <&reg_vref_1v8>;
+	status = "okay";
+};
+
+&enetc_port0 {
+	phy-handle = <&ethphy0>;
+	phy-mode = "rgmii-id";
+	pinctrl-0 = <&pinctrl_enetc0>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&enetc_port1 {
+	phy-handle = <&ethphy1>;
+	phy-mode = "rgmii-id";
+	pinctrl-0 = <&pinctrl_enetc1>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&flexcan2 {
+	pinctrl-0 = <&pinctrl_flexcan2>;
+	pinctrl-names = "default";
+	xceiver-supply = <&reg_can_stby>;
+	status = "okay";
+};
+
+&flexcan5 {
+	pinctrl-0 = <&pinctrl_flexcan5>;
+	pinctrl-names = "default";
+	xceiver-supply = <&reg_can_stby>;
+	status = "okay";
+};
+
+&lpi2c2 {
+	clock-frequency = <400000>;
+	pinctrl-0 = <&pinctrl_lpi2c2>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	pcal6524: gpio at 22 {
+		compatible = "nxp,pcal6524";
+		reg = <0x22>;
+		#interrupt-cells = <2>;
+		interrupt-controller;
+		interrupt-parent = <&gpio5>;
+		interrupts = <14 IRQ_TYPE_LEVEL_LOW>;
+		#gpio-cells = <2>;
+		gpio-controller;
+		pinctrl-0 = <&pinctrl_pcal6524>;
+		pinctrl-names = "default";
+		gpio-line-names = "ENET1 PHY reset",
+				  "ENET2 PHY reset",
+				  "SPI3/GPIO select",
+				  "UART3/GPIO select",
+				  "CAN2&5/GPIO select",
+				  "PWM/GPIO select",
+				  "Watch dog enable",
+				  "CAN1&2&5 silent",
+				  "SDIO_nRST",
+				  "WL_nDISABLE1",
+				  "WL_nDISABLE2",
+				  "M.2 Mkey NC06",
+				  "EXT_5V0_PWR_EN",
+				  "EXT_3V3_PWR_EN",
+				  "Mkey power control",
+				  "USB2 power control",
+				  "Ekey power control",
+				  "MIPI-DSICSI reset",
+				  "MIPI-DSI IO2",
+				  "MIPI-CSI reset",
+				  "LVDS TP reset",
+				  "LVDS BL enable",
+				  "LVDS BL power enable",
+				  "IT6263 reset";
+
+		lpspi-gpio-sel-hog {
+			gpio-hog;
+			gpios = <2 GPIO_ACTIVE_HIGH>;
+			output-low;
+		};
+
+		lpuart-gpio-sel-hog {
+			gpio-hog;
+			gpios = <3 GPIO_ACTIVE_HIGH>;
+			output-low;
+		};
+
+		can-gpio-sel-hog {
+			gpio-hog;
+			gpios = <4 GPIO_ACTIVE_HIGH>;
+			output-low;
+		};
+
+		pwm-gpio-sel-hog {
+			gpio-hog;
+			gpios = <5 GPIO_ACTIVE_HIGH>;
+			output-high;
+		};
+	};
+};
+
+&lpi2c3 {
+	clock-frequency = <400000>;
+	pinctrl-0 = <&pinctrl_lpi2c3>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	ptn5110: tcpc at 50 {
+		compatible = "nxp,ptn5110", "tcpci";
+		reg = <0x50>;
+		interrupt-parent = <&gpio5>;
+		interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-0 = <&pinctrl_ptn5110>;
+		pinctrl-names = "default";
+
+		typec_con: connector {
+			compatible = "usb-c-connector";
+			data-role = "dual";
+			label = "USB-C";
+			op-sink-microwatt = <15000000>;
+			power-role = "dual";
+			self-powered;
+			sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)
+				     PDO_VAR(5000, 20000, 3000)>;
+			source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
+			try-power-role = "sink";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+
+					typec_con_hs: endpoint {
+						remote-endpoint = <&usb3_data_hs>;
+					};
+				};
+
+				port at 1 {
+					reg = <1>;
+
+					typec_con_ss: endpoint {
+						remote-endpoint = <&usb3_data_ss>;
+					};
+				};
+			};
+		};
+	};
+};
+
+&lpi2c4 {
+	clock-frequency = <400000>;
+	pinctrl-0 = <&pinctrl_lpi2c4>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	pca9632: led-controller at 62 {
+		compatible = "nxp,pca9632";
+		reg = <0x62>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		nxp,inverted-out;
+
+		led_backlight0: led at 0 {
+			reg = <0>;
+			color = <LED_COLOR_ID_WHITE>;
+			function = LED_FUNCTION_BACKLIGHT;
+			function-enumerator = <0>;
+		};
+
+		led_backlight1: led at 1 {
+			reg = <1>;
+			color = <LED_COLOR_ID_WHITE>;
+			function = LED_FUNCTION_BACKLIGHT;
+			function-enumerator = <1>;
+		};
+	};
+};
+
+&lpuart1 {
+	pinctrl-0 = <&pinctrl_uart1>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&lpuart5 {
+	pinctrl-0 = <&pinctrl_uart5>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	bluetooth {
+		compatible = "nxp,88w8987-bt";
+	};
+};
+
+&micfil {
+	assigned-clocks = <&scmi_clk IMX95_CLK_AUDIOPLL1_VCO>,
+			  <&scmi_clk IMX95_CLK_AUDIOPLL2_VCO>,
+			  <&scmi_clk IMX95_CLK_AUDIOPLL1>,
+			  <&scmi_clk IMX95_CLK_AUDIOPLL2>,
+			  <&scmi_clk IMX95_CLK_PDM>;
+	assigned-clock-parents = <0>, <0>, <0>, <0>,
+				 <&scmi_clk IMX95_CLK_AUDIOPLL1>;
+	assigned-clock-rates = <3932160000>,
+			       <3612672000>, <393216000>,
+			       <361267200>, <49152000>;
+	#sound-dai-cells = <0>;
+	pinctrl-0 = <&pinctrl_pdm>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&mu7 {
+	status = "okay";
+};
+
+&netc_blk_ctrl {
+	status = "okay";
+};
+
+/* Default settings in i.mx95.dtsi are for i.MX95 19x19 package.
+ * Override here for the i.MX95 15x15 package.
+ */
+&netc_bus0 {
+	msi-map = <0x0 &its 0x60 0x1>,	//ENETC0 PF
+		  <0x10 &its 0x61 0x1>, //ENETC0 VF0
+		  <0x20 &its 0x62 0x1>, //ENETC0 VF1
+		  <0x40 &its 0x63 0x1>, //ENETC1 PF
+		  <0x50 &its 0x65 0x1>, //ENETC1 VF0
+		  <0x60 &its 0x66 0x1>, //ENETC1 VF1
+		  <0x80 &its 0x64 0x1>, //ENETC2 PF
+		  <0xc0 &its 0x67 0x1>; //NETC Timer
+	iommu-map = <0x0 &smmu 0x20 0x1>,
+		    <0x10 &smmu 0x21 0x1>,
+		    <0x20 &smmu 0x22 0x1>,
+		    <0x40 &smmu 0x23 0x1>,
+		    <0x50 &smmu 0x25 0x1>,
+		    <0x60 &smmu 0x26 0x1>,
+		    <0x80 &smmu 0x24 0x1>,
+		    <0xc0 &smmu 0x27 0x1>;
+};
+
+&netc_emdio {
+	pinctrl-0 = <&pinctrl_emdio>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	ethphy0: ethernet-phy at 1 {
+		reg = <1>;
+		reset-assert-us = <10000>;
+		reset-deassert-us = <80000>;
+		reset-gpios = <&pcal6524 0 GPIO_ACTIVE_LOW>;
+	};
+
+	ethphy1: ethernet-phy at 2 {
+		reg = <2>;
+		reset-assert-us = <10000>;
+		reset-deassert-us = <80000>;
+		reset-gpios = <&pcal6524 1 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&netc_timer {
+	status = "okay";
+};
+
+&netcmix_blk_ctrl {
+	status = "okay";
+};
+
+&pcie0 {
+	pinctrl-0 = <&pinctrl_pcie0>;
+	pinctrl-names = "default";
+	reset-gpio = <&gpio5 13 GPIO_ACTIVE_LOW>;
+	supports-clkreq;
+	vpcie-supply = <&reg_m2_mkey_pwr>;
+	status = "okay";
+};
+
+&scmi_iomuxc {
+	pinctrl_emdio: emdiogrp {
+		fsl,pins = <
+			IMX95_PAD_ENET2_MDC__NETCMIX_TOP_NETC_MDC		0x50e
+			IMX95_PAD_ENET2_MDIO__NETCMIX_TOP_NETC_MDIO		0x90e
+		>;
+	};
+
+	pinctrl_enetc0: enetc0grp {
+		fsl,pins = <
+			IMX95_PAD_ENET1_TD3__NETCMIX_TOP_ETH0_RGMII_TD3		0x50e
+			IMX95_PAD_ENET1_TD2__NETCMIX_TOP_ETH0_RGMII_TD2		0x50e
+			IMX95_PAD_ENET1_TD1__NETCMIX_TOP_ETH0_RGMII_TD1		0x50e
+			IMX95_PAD_ENET1_TD0__NETCMIX_TOP_ETH0_RGMII_TD0		0x50e
+			IMX95_PAD_ENET1_TX_CTL__NETCMIX_TOP_ETH0_RGMII_TX_CTL	0x57e
+			IMX95_PAD_ENET1_TXC__NETCMIX_TOP_ETH0_RGMII_TX_CLK	0x58e
+			IMX95_PAD_ENET1_RX_CTL__NETCMIX_TOP_ETH0_RGMII_RX_CTL	0x57e
+			IMX95_PAD_ENET1_RXC__NETCMIX_TOP_ETH0_RGMII_RX_CLK	0x58e
+			IMX95_PAD_ENET1_RD0__NETCMIX_TOP_ETH0_RGMII_RD0		0x57e
+			IMX95_PAD_ENET1_RD1__NETCMIX_TOP_ETH0_RGMII_RD1		0x57e
+			IMX95_PAD_ENET1_RD2__NETCMIX_TOP_ETH0_RGMII_RD2		0x57e
+			IMX95_PAD_ENET1_RD3__NETCMIX_TOP_ETH0_RGMII_RD3		0x57e
+		>;
+	};
+
+	pinctrl_enetc1: enetc1grp {
+		fsl,pins = <
+			IMX95_PAD_ENET2_TD3__NETCMIX_TOP_ETH1_RGMII_TD3		0x50e
+			IMX95_PAD_ENET2_TD2__NETCMIX_TOP_ETH1_RGMII_TD2		0x50e
+			IMX95_PAD_ENET2_TD1__NETCMIX_TOP_ETH1_RGMII_TD1		0x50e
+			IMX95_PAD_ENET2_TD0__NETCMIX_TOP_ETH1_RGMII_TD0		0x50e
+			IMX95_PAD_ENET2_TX_CTL__NETCMIX_TOP_ETH1_RGMII_TX_CTL	0x57e
+			IMX95_PAD_ENET2_TXC__NETCMIX_TOP_ETH1_RGMII_TX_CLK	0x58e
+			IMX95_PAD_ENET2_RX_CTL__NETCMIX_TOP_ETH1_RGMII_RX_CTL	0x57e
+			IMX95_PAD_ENET2_RXC__NETCMIX_TOP_ETH1_RGMII_RX_CLK	0x58e
+			IMX95_PAD_ENET2_RD0__NETCMIX_TOP_ETH1_RGMII_RD0		0x57e
+			IMX95_PAD_ENET2_RD1__NETCMIX_TOP_ETH1_RGMII_RD1		0x57e
+			IMX95_PAD_ENET2_RD2__NETCMIX_TOP_ETH1_RGMII_RD2		0x57e
+			IMX95_PAD_ENET2_RD3__NETCMIX_TOP_ETH1_RGMII_RD3		0x57e
+		>;
+	};
+
+	pinctrl_flexcan2: flexcan2grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO25__CAN2_TX				0x39e
+			IMX95_PAD_GPIO_IO27__CAN2_RX				0x39e
+		>;
+	};
+
+	pinctrl_flexcan5: flexcan5grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO22__CAN5_TX				0x39e
+			IMX95_PAD_GPIO_IO23__CAN5_RX				0x39e
+		>;
+	};
+
+	pinctrl_lpi2c1: lpi2c1grp {
+		fsl,pins = <
+			IMX95_PAD_I2C1_SCL__AONMIX_TOP_LPI2C1_SCL		0x40000b9e
+			IMX95_PAD_I2C1_SDA__AONMIX_TOP_LPI2C1_SDA		0x40000b9e
+		>;
+	};
+
+	pinctrl_lpi2c2: lpi2c2grp {
+		fsl,pins = <
+			IMX95_PAD_I2C2_SCL__AONMIX_TOP_LPI2C2_SCL		0x40000b9e
+			IMX95_PAD_I2C2_SDA__AONMIX_TOP_LPI2C2_SDA		0x40000b9e
+		>;
+	};
+
+	pinctrl_lpi2c3: lpi2c3grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO28__LPI2C3_SDA				0x40000b9e
+			IMX95_PAD_GPIO_IO29__LPI2C3_SCL				0x40000b9e
+		>;
+	};
+
+	pinctrl_lpi2c4: lpi2c4grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO30__LPI2C4_SDA				0x40000b9e
+			IMX95_PAD_GPIO_IO31__LPI2C4_SCL				0x40000b9e
+		>;
+	};
+
+	pinctrl_pcal6524: pcal6524grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO34__GPIO5_IO_BIT14			0x31e
+		>;
+	};
+
+	pinctrl_pcie0: pcie0grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO32__HSIOMIX_TOP_PCIE1_CLKREQ_B		0x40000b1e
+			IMX95_PAD_GPIO_IO33__GPIO5_IO_BIT13			0x31e
+		>;
+	};
+
+	pinctrl_pdm: pdmgrp {
+		fsl,pins = <
+			IMX95_PAD_PDM_CLK__AONMIX_TOP_PDM_CLK				0x31e
+			IMX95_PAD_PDM_BIT_STREAM0__AONMIX_TOP_PDM_BIT_STREAM_BIT0	0x31e
+		>;
+	};
+
+	pinctrl_ptn5110: ptn5110grp {
+		fsl,pins = <
+			IMX95_PAD_XSPI1_DATA3__GPIO5_IO_BIT3			0x31e
+		>;
+	};
+
+	pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
+		fsl,pins = <
+			IMX95_PAD_SD2_RESET_B__GPIO3_IO_BIT7			0x31e
+		>;
+	};
+
+	pinctrl_uart1: uart1grp {
+		fsl,pins = <
+			IMX95_PAD_UART1_RXD__AONMIX_TOP_LPUART1_RX		0x31e
+			IMX95_PAD_UART1_TXD__AONMIX_TOP_LPUART1_TX		0x31e
+		>;
+	};
+
+	pinctrl_uart5: uart5grp {
+		fsl,pins = <
+			IMX95_PAD_DAP_TDO_TRACESWO__LPUART5_TX			0x31e
+			IMX95_PAD_DAP_TDI__LPUART5_RX				0x31e
+			IMX95_PAD_DAP_TMS_SWDIO__LPUART5_RTS_B			0x31e
+			IMX95_PAD_DAP_TCLK_SWCLK__LPUART5_CTS_B			0x31e
+		>;
+	};
+
+	pinctrl_usdhc1: usdhc1grp {
+		fsl,pins = <
+			IMX95_PAD_SD1_CLK__USDHC1_CLK				0x158e
+			IMX95_PAD_SD1_CMD__USDHC1_CMD				0x138e
+			IMX95_PAD_SD1_DATA0__USDHC1_DATA0			0x138e
+			IMX95_PAD_SD1_DATA1__USDHC1_DATA1			0x138e
+			IMX95_PAD_SD1_DATA2__USDHC1_DATA2			0x138e
+			IMX95_PAD_SD1_DATA3__USDHC1_DATA3			0x138e
+			IMX95_PAD_SD1_DATA4__USDHC1_DATA4			0x138e
+			IMX95_PAD_SD1_DATA5__USDHC1_DATA5			0x138e
+			IMX95_PAD_SD1_DATA6__USDHC1_DATA6			0x138e
+			IMX95_PAD_SD1_DATA7__USDHC1_DATA7			0x138e
+			IMX95_PAD_SD1_STROBE__USDHC1_STROBE			0x158e
+		>;
+	};
+
+	pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp {
+		fsl,pins = <
+			IMX95_PAD_SD1_CLK__USDHC1_CLK				0x158e
+			IMX95_PAD_SD1_CMD__USDHC1_CMD				0x138e
+			IMX95_PAD_SD1_DATA0__USDHC1_DATA0			0x138e
+			IMX95_PAD_SD1_DATA1__USDHC1_DATA1			0x138e
+			IMX95_PAD_SD1_DATA2__USDHC1_DATA2			0x138e
+			IMX95_PAD_SD1_DATA3__USDHC1_DATA3			0x138e
+			IMX95_PAD_SD1_DATA4__USDHC1_DATA4			0x138e
+			IMX95_PAD_SD1_DATA5__USDHC1_DATA5			0x138e
+			IMX95_PAD_SD1_DATA6__USDHC1_DATA6			0x138e
+			IMX95_PAD_SD1_DATA7__USDHC1_DATA7			0x138e
+			IMX95_PAD_SD1_STROBE__USDHC1_STROBE			0x158e
+		>;
+	};
+
+	pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp {
+		fsl,pins = <
+			IMX95_PAD_SD1_CLK__USDHC1_CLK				0x15fe
+			IMX95_PAD_SD1_CMD__USDHC1_CMD				0x13fe
+			IMX95_PAD_SD1_DATA0__USDHC1_DATA0			0x13fe
+			IMX95_PAD_SD1_DATA1__USDHC1_DATA1			0x13fe
+			IMX95_PAD_SD1_DATA2__USDHC1_DATA2			0x13fe
+			IMX95_PAD_SD1_DATA3__USDHC1_DATA3			0x13fe
+			IMX95_PAD_SD1_DATA4__USDHC1_DATA4			0x13fe
+			IMX95_PAD_SD1_DATA5__USDHC1_DATA5			0x13fe
+			IMX95_PAD_SD1_DATA6__USDHC1_DATA6			0x13fe
+			IMX95_PAD_SD1_DATA7__USDHC1_DATA7			0x13fe
+			IMX95_PAD_SD1_STROBE__USDHC1_STROBE			0x15fe
+		>;
+	};
+
+	pinctrl_usdhc2_gpio: usdhc2gpiogrp {
+		fsl,pins = <
+			IMX95_PAD_SD2_CD_B__GPIO3_IO_BIT0			0x31e
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			IMX95_PAD_SD2_CLK__USDHC2_CLK				0x158e
+			IMX95_PAD_SD2_CMD__USDHC2_CMD				0x138e
+			IMX95_PAD_SD2_DATA0__USDHC2_DATA0			0x138e
+			IMX95_PAD_SD2_DATA1__USDHC2_DATA1			0x138e
+			IMX95_PAD_SD2_DATA2__USDHC2_DATA2			0x138e
+			IMX95_PAD_SD2_DATA3__USDHC2_DATA3			0x138e
+			IMX95_PAD_SD2_VSELECT__USDHC2_VSELECT			0x51e
+		>;
+	};
+
+	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+		fsl,pins = <
+			IMX95_PAD_SD2_CLK__USDHC2_CLK				0x158e
+			IMX95_PAD_SD2_CMD__USDHC2_CMD				0x138e
+			IMX95_PAD_SD2_DATA0__USDHC2_DATA0			0x138e
+			IMX95_PAD_SD2_DATA1__USDHC2_DATA1			0x138e
+			IMX95_PAD_SD2_DATA2__USDHC2_DATA2			0x138e
+			IMX95_PAD_SD2_DATA3__USDHC2_DATA3			0x138e
+			IMX95_PAD_SD2_VSELECT__USDHC2_VSELECT			0x51e
+		>;
+	};
+
+	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+		fsl,pins = <
+			IMX95_PAD_SD2_CLK__USDHC2_CLK				0x158e
+			IMX95_PAD_SD2_CMD__USDHC2_CMD				0x138e
+			IMX95_PAD_SD2_DATA0__USDHC2_DATA0			0x138e
+			IMX95_PAD_SD2_DATA1__USDHC2_DATA1			0x138e
+			IMX95_PAD_SD2_DATA2__USDHC2_DATA2			0x138e
+			IMX95_PAD_SD2_DATA3__USDHC2_DATA3			0x138e
+			IMX95_PAD_SD2_VSELECT__USDHC2_VSELECT			0x51e
+		>;
+	};
+
+	pinctrl_usdhc3: usdhc3grp {
+		fsl,pins = <
+			IMX95_PAD_SD3_CLK__USDHC3_CLK				0x158e
+			IMX95_PAD_SD3_CMD__USDHC3_CMD				0x138e
+			IMX95_PAD_SD3_DATA0__USDHC3_DATA0			0x138e
+			IMX95_PAD_SD3_DATA1__USDHC3_DATA1			0x138e
+			IMX95_PAD_SD3_DATA2__USDHC3_DATA2			0x138e
+			IMX95_PAD_SD3_DATA3__USDHC3_DATA3			0x138e
+		>;
+	};
+
+	pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp {
+		fsl,pins = <
+			IMX95_PAD_SD3_CLK__USDHC3_CLK				0x158e
+			IMX95_PAD_SD3_CMD__USDHC3_CMD				0x138e
+			IMX95_PAD_SD3_DATA0__USDHC3_DATA0			0x138e
+			IMX95_PAD_SD3_DATA1__USDHC3_DATA1			0x138e
+			IMX95_PAD_SD3_DATA2__USDHC3_DATA2			0x138e
+			IMX95_PAD_SD3_DATA3__USDHC3_DATA3			0x138e
+		>;
+	};
+
+	pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp {
+		fsl,pins = <
+			IMX95_PAD_SD3_CLK__USDHC3_CLK				0x15fe
+			IMX95_PAD_SD3_CMD__USDHC3_CMD				0x13fe
+			IMX95_PAD_SD3_DATA0__USDHC3_DATA0			0x13fe
+			IMX95_PAD_SD3_DATA1__USDHC3_DATA1			0x13fe
+			IMX95_PAD_SD3_DATA2__USDHC3_DATA2			0x13fe
+			IMX95_PAD_SD3_DATA3__USDHC3_DATA3			0x13fe
+		>;
+	};
+};
+
+&scmi_misc {
+	nxp,ctrl-ids = <BRD_SM_CTRL_SD3_WAKE		1
+			BRD_SM_CTRL_PCIE1_WAKE		1
+			BRD_SM_CTRL_BT_WAKE		1
+			BRD_SM_CTRL_PCIE2_WAKE		1
+			BRD_SM_CTRL_BUTTON		1>;
+};
+
+&thermal_zones {
+	pf09-thermal {
+		polling-delay = <2000>;
+		polling-delay-passive = <250>;
+		thermal-sensors = <&scmi_sensor 2>;
+
+		trips {
+			pf09_alert: trip0 {
+				hysteresis = <2000>;
+				temperature = <140000>;
+				type = "passive";
+			};
+
+			pf09_crit: trip1 {
+				hysteresis = <2000>;
+				temperature = <155000>;
+				type = "critical";
+			};
+		};
+	};
+
+	pf53arm-thermal {
+		polling-delay = <2000>;
+		polling-delay-passive = <250>;
+		thermal-sensors = <&scmi_sensor 4>;
+
+		cooling-maps {
+			map0 {
+				cooling-device = <&A55_0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+					<&A55_1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+					<&A55_2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+					<&A55_3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+					<&A55_4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+					<&A55_5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				trip = <&pf5301_alert>;
+			};
+		};
+
+		trips {
+			pf5301_alert: trip0 {
+				hysteresis = <2000>;
+				temperature = <140000>;
+				type = "passive";
+			};
+
+			pf5301_crit: trip1 {
+				hysteresis = <2000>;
+				temperature = <155000>;
+				type = "critical";
+			};
+		};
+	};
+
+	pf53soc-thermal {
+		polling-delay = <2000>;
+		polling-delay-passive = <250>;
+		thermal-sensors = <&scmi_sensor 3>;
+
+		trips {
+			pf5302_alert: trip0 {
+				hysteresis = <2000>;
+				temperature = <140000>;
+				type = "passive";
+			};
+
+			pf5302_crit: trip1 {
+				hysteresis = <2000>;
+				temperature = <155000>;
+				type = "critical";
+			};
+		};
+	};
+};
+
+&usb2 {
+	disable-over-current;
+	dr_mode = "host";
+	vbus-supply = <&reg_usb_vbus>;
+	status = "okay";
+};
+
+&usb3 {
+	status = "okay";
+};
+
+&usb3_dwc3 {
+	adp-disable;
+	dr_mode = "otg";
+	hnp-disable;
+	role-switch-default-mode = "peripheral";
+	srp-disable;
+	usb-role-switch;
+	snps,dis-u1-entry-quirk;
+	snps,dis-u2-entry-quirk;
+	status = "okay";
+
+	port {
+		usb3_data_hs: endpoint {
+			remote-endpoint = <&typec_con_hs>;
+		};
+	};
+};
+
+&usb3_phy {
+	orientation-switch;
+	fsl,phy-pcs-tx-deemph-3p5db-attenuation-db = <17>;
+	fsl,phy-pcs-tx-swing-full-percent = <100>;
+	fsl,phy-tx-preemp-amp-tune-microamp = <600>;
+	fsl,phy-tx-vboost-level-microvolt = <1156>;
+	fsl,phy-tx-vref-tune-percent = <100>;
+	status = "okay";
+
+	port {
+		usb3_data_ss: endpoint {
+			remote-endpoint = <&typec_con_ss>;
+		};
+	};
+};
+
+&usdhc1 {
+	bus-width = <8>;
+	non-removable;
+	no-sd;
+	no-sdio;
+	pinctrl-0 = <&pinctrl_usdhc1>;
+	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
+	pinctrl-3 = <&pinctrl_usdhc1>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
+	fsl,tuning-step = <1>;
+	status = "okay";
+};
+
+&usdhc2 {
+	bus-width = <4>;
+	cd-gpios = <&gpio3 00 GPIO_ACTIVE_LOW>;
+	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-3 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	fsl,tuning-step = <1>;
+	status = "okay";
+};
+
+&usdhc3 {
+	bus-width = <4>;
+	keep-power-in-suspend;
+	mmc-pwrseq = <&usdhc3_pwrseq>;
+	non-removable;
+	pinctrl-0 = <&pinctrl_usdhc3>;
+	pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
+	pinctrl-3 = <&pinctrl_usdhc3>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
+	vmmc-supply = <&reg_usdhc3_vmmc>;
+	wakeup-source;
+	status = "okay";
+};
+
+&wdog3 {
+	status = "okay";
+};

-- 
2.34.1



From jic23 at kernel.org  Sun Dec  7 06:04:25 2025
From: jic23 at kernel.org (Jonathan Cameron)
Date: Sun, 7 Dec 2025 14:04:25 +0000
Subject: [PATCH] MAINTAINERS: Change Linus Walleij mail address
In-Reply-To: <20251130-linusw-kernelorg-email-v1-1-bcdbff7b896c@kernel.org>
References: <20251130-linusw-kernelorg-email-v1-1-bcdbff7b896c@kernel.org>
Message-ID: <20251207140425.2e373873@jic23-huawei>

On Sun, 30 Nov 2025 17:14:45 +0100
Linus Walleij <linusw at kernel.org> wrote:

> I will be using my kernel.org mail address going forward.
> 
> There is no point in splitting this MAINTAINERS patch up
> per subsystem, I will just include it with the rest of my
> patches to pin control in the next merge window.

Trivial but wrap a tiny bit short of the normal 75 chars.

> 
> Signed-off-by: Linus Walleij <linusw at kernel.org>

FWIW
Acked-by: Jonathan Cameron <jonathan.cameron at huawei.com> #for-iio

Good opportunity to say thanks for all your effort in a broad range
of places!

Jonathan

> ---
>  MAINTAINERS | 58 +++++++++++++++++++++++++++++-----------------------------
>  1 file changed, 29 insertions(+), 29 deletions(-)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 181a58ec4a8d..13f61acdc8f7 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -195,7 +195,7 @@ F:	drivers/pinctrl/pinctrl-upboard.c
>  F:	include/linux/mfd/upboard-fpga.h
>  
>  AB8500 BATTERY AND CHARGER DRIVERS
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  F:	Documentation/devicetree/bindings/power/supply/*ab8500*
>  F:	drivers/power/supply/*ab8500*
>  
> @@ -2045,7 +2045,7 @@ F:	Documentation/devicetree/bindings/display/arm,hdlcd.yaml
>  F:	drivers/gpu/drm/arm/hdlcd_*
>  
>  ARM INTEGRATOR, VERSATILE AND REALVIEW SUPPORT
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  L:	linux-arm-kernel at lists.infradead.org (moderated for non-subscribers)
>  S:	Maintained
>  F:	Documentation/devicetree/bindings/arm/arm,integrator.yaml
> @@ -2203,7 +2203,7 @@ F:	Documentation/devicetree/bindings/memory-controllers/arm,pl35x-smc.yaml
>  F:	drivers/memory/pl353-smc.c
>  
>  ARM PRIMECELL SSP PL022 SPI DRIVER
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  L:	linux-arm-kernel at lists.infradead.org (moderated for non-subscribers)
>  S:	Maintained
>  F:	Documentation/devicetree/bindings/spi/spi-pl022.yaml
> @@ -2216,7 +2216,7 @@ F:	drivers/tty/serial/amba-pl01*.c
>  F:	include/linux/amba/serial.h
>  
>  ARM PRIMECELL VIC PL190/PL192 DRIVER
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  L:	linux-arm-kernel at lists.infradead.org (moderated for non-subscribers)
>  S:	Maintained
>  F:	Documentation/devicetree/bindings/interrupt-controller/arm,vic.yaml
> @@ -2633,7 +2633,7 @@ F:	tools/perf/util/cs-etm.*
>  
>  ARM/CORTINA SYSTEMS GEMINI ARM ARCHITECTURE
>  M:	Hans Ulli Kroll <ulli.kroll at googlemail.com>
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  L:	linux-arm-kernel at lists.infradead.org (moderated for non-subscribers)
>  S:	Maintained
>  T:	git https://github.com/ulli-kroll/linux.git
> @@ -3035,7 +3035,7 @@ F:	include/dt-bindings/clock/mstar-*
>  F:	include/dt-bindings/gpio/msc313-gpio.h
>  
>  ARM/NOMADIK/Ux500 ARCHITECTURES
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  L:	linux-arm-kernel at lists.infradead.org (moderated for non-subscribers)
>  S:	Maintained
>  T:	git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-nomadik.git
> @@ -3732,7 +3732,7 @@ F:	Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml
>  F:	drivers/media/i2c/ak7375.c
>  
>  ASAHI KASEI AK8974 DRIVER
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  L:	linux-iio at vger.kernel.org
>  S:	Supported
>  W:	http://www.akm.com/
> @@ -6758,7 +6758,7 @@ S:	Maintained
>  F:	drivers/pinctrl/pinctrl-cy8c95x0.c
>  
>  CYPRESS CY8CTMA140 TOUCHSCREEN DRIVER
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  L:	linux-input at vger.kernel.org
>  S:	Maintained
>  F:	drivers/input/touchscreen/cy8ctma140.c
> @@ -6778,13 +6778,13 @@ Q:	http://patchwork.linuxtv.org/project/linux-media/list/
>  F:	drivers/media/common/cypress_firmware*
>  
>  CYTTSP TOUCHSCREEN DRIVER
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  L:	linux-input at vger.kernel.org
>  S:	Maintained
>  F:	drivers/input/touchscreen/cyttsp*
>  
>  D-LINK DIR-685 TOUCHKEYS DRIVER
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  L:	linux-input at vger.kernel.org
>  S:	Supported
>  F:	drivers/input/keyboard/dlink-dir685-touchkeys.c
> @@ -7653,13 +7653,13 @@ T:	git https://gitlab.freedesktop.org/drm/misc/kernel.git
>  F:	drivers/gpu/drm/tiny/appletbdrm.c
>  
>  DRM DRIVER FOR ARM PL111 CLCD
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  S:	Maintained
>  T:	git https://gitlab.freedesktop.org/drm/misc/kernel.git
>  F:	drivers/gpu/drm/pl111/
>  
>  DRM DRIVER FOR ARM VERSATILE TFT PANELS
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  S:	Maintained
>  T:	git https://gitlab.freedesktop.org/drm/misc/kernel.git
>  F:	Documentation/devicetree/bindings/display/panel/arm,versatile-tft-panel.yaml
> @@ -7709,7 +7709,7 @@ F:	Documentation/devicetree/bindings/display/panel/ebbg,ft8719.yaml
>  F:	drivers/gpu/drm/panel/panel-ebbg-ft8719.c
>  
>  DRM DRIVER FOR FARADAY TVE200 TV ENCODER
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  S:	Maintained
>  T:	git https://gitlab.freedesktop.org/drm/misc/kernel.git
>  F:	drivers/gpu/drm/tve200/
> @@ -7903,14 +7903,14 @@ F:	include/dt-bindings/clock/qcom,dsi-phy-28nm.h
>  F:	include/uapi/drm/msm_drm.h
>  
>  DRM DRIVER FOR NOVATEK NT35510 PANELS
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  S:	Maintained
>  T:	git https://gitlab.freedesktop.org/drm/misc/kernel.git
>  F:	Documentation/devicetree/bindings/display/panel/novatek,nt35510.yaml
>  F:	drivers/gpu/drm/panel/panel-novatek-nt35510.c
>  
>  DRM DRIVER FOR NOVATEK NT35560 PANELS
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  S:	Maintained
>  T:	git https://gitlab.freedesktop.org/drm/misc/kernel.git
>  F:	Documentation/devicetree/bindings/display/panel/sony,acx424akp.yaml
> @@ -8028,7 +8028,7 @@ F:	Documentation/devicetree/bindings/display/panel/raydium,rm67191.yaml
>  F:	drivers/gpu/drm/panel/panel-raydium-rm67191.c
>  
>  DRM DRIVER FOR SAMSUNG DB7430 PANELS
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  S:	Maintained
>  T:	git https://gitlab.freedesktop.org/drm/misc/kernel.git
>  F:	Documentation/devicetree/bindings/display/panel/samsung,lms397kf04.yaml
> @@ -8112,7 +8112,7 @@ F:	Documentation/devicetree/bindings/display/solomon,ssd13*.yaml
>  F:	drivers/gpu/drm/solomon/ssd130x*
>  
>  DRM DRIVER FOR ST-ERICSSON MCDE
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  S:	Maintained
>  T:	git https://gitlab.freedesktop.org/drm/misc/kernel.git
>  F:	Documentation/devicetree/bindings/display/ste,mcde.yaml
> @@ -8144,7 +8144,7 @@ F:	Documentation/devicetree/bindings/display/bridge/ti,sn65dsi86.yaml
>  F:	drivers/gpu/drm/bridge/ti-sn65dsi86.c
>  
>  DRM DRIVER FOR TPO TPG110 PANELS
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  S:	Maintained
>  T:	git https://gitlab.freedesktop.org/drm/misc/kernel.git
>  F:	Documentation/devicetree/bindings/display/panel/tpo,tpg110.yaml
> @@ -8188,7 +8188,7 @@ F:	drivers/gpu/drm/vmwgfx/
>  F:	include/uapi/drm/vmwgfx_drm.h
>  
>  DRM DRIVER FOR WIDECHIPS WS2401 PANELS
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  S:	Maintained
>  T:	git https://gitlab.freedesktop.org/drm/misc/kernel.git
>  F:	Documentation/devicetree/bindings/display/panel/samsung,lms380kf01.yaml
> @@ -9482,7 +9482,7 @@ F:	include/linux/fanotify.h
>  F:	include/uapi/linux/fanotify.h
>  
>  FARADAY FOTG210 USB2 DUAL-ROLE CONTROLLER
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  L:	linux-usb at vger.kernel.org
>  S:	Maintained
>  F:	drivers/usb/fotg210/
> @@ -10669,7 +10669,7 @@ F:	drivers/gpio/gpio-sloppy-logic-analyzer.c
>  F:	tools/gpio/gpio-sloppy-logic-analyzer.sh
>  
>  GPIO SUBSYSTEM
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  M:	Bartosz Golaszewski <brgl at bgdev.pl>
>  L:	linux-gpio at vger.kernel.org
>  S:	Maintained
> @@ -13033,7 +13033,7 @@ F:	Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
>  F:	drivers/iio/imu/inv_icm42600/
>  
>  INVENSENSE MPU-3050 GYROSCOPE DRIVER
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  L:	linux-iio at vger.kernel.org
>  S:	Maintained
>  F:	Documentation/devicetree/bindings/iio/gyroscope/invensense,mpu3050.yaml
> @@ -13948,7 +13948,7 @@ F:	drivers/auxdisplay/ks0108.c
>  F:	include/linux/ks0108.h
>  
>  KTD253 BACKLIGHT DRIVER
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  S:	Maintained
>  F:	Documentation/devicetree/bindings/leds/backlight/kinetic,ktd253.yaml
>  F:	drivers/video/backlight/ktd253-backlight.c
> @@ -14159,7 +14159,7 @@ F:	drivers/ata/pata_arasan_cf.c
>  F:	include/linux/pata_arasan_cf_data.h
>  
>  LIBATA PATA FARADAY FTIDE010 AND GEMINI SATA BRIDGE DRIVERS
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  L:	linux-ide at vger.kernel.org
>  S:	Maintained
>  F:	drivers/ata/pata_ftide010.c
> @@ -19663,7 +19663,7 @@ F:	Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml
>  F:	drivers/pci/controller/dwc/*imx6*
>  
>  PCI DRIVER FOR INTEL IXP4XX
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  S:	Maintained
>  F:	Documentation/devicetree/bindings/pci/intel,ixp4xx-pci.yaml
>  F:	drivers/pci/controller/pci-ixp4xx.c
> @@ -19774,7 +19774,7 @@ F:	drivers/pci/controller/cadence/pci-j721e.c
>  F:	drivers/pci/controller/dwc/pci-dra7xx.c
>  
>  PCI DRIVER FOR V3 SEMICONDUCTOR V360EPC
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  L:	linux-pci at vger.kernel.org
>  S:	Maintained
>  F:	Documentation/devicetree/bindings/pci/v3,v360epc-pci.yaml
> @@ -20219,7 +20219,7 @@ K:	(?i)clone3
>  K:	\b(clone_args|kernel_clone_args)\b
>  
>  PIN CONTROL SUBSYSTEM
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  L:	linux-gpio at vger.kernel.org
>  S:	Maintained
>  T:	git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git
> @@ -21631,7 +21631,7 @@ F:	Documentation/devicetree/bindings/watchdog/realtek,otto-wdt.yaml
>  F:	drivers/watchdog/realtek_otto_wdt.c
>  
>  REALTEK RTL83xx SMI DSA ROUTER CHIPS
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  M:	Alvin ?ipraga <alsi at bang-olufsen.dk>
>  S:	Maintained
>  F:	Documentation/devicetree/bindings/net/dsa/realtek.yaml
> @@ -23384,7 +23384,7 @@ S:	Supported
>  F:	net/smc/
>  
>  SHARP GP2AP002A00F/GP2AP002S00F SENSOR DRIVER
> -M:	Linus Walleij <linus.walleij at linaro.org>
> +M:	Linus Walleij <linusw at kernel.org>
>  L:	linux-iio at vger.kernel.org
>  S:	Maintained
>  T:	git git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git
> 
> ---
> base-commit: 6156424a7d001cceeafe59b52209d6f36719b51d
> change-id: 20251130-linusw-kernelorg-email-0791125070f4
> 
> Best regards,



From jgg at nvidia.com  Sun Dec  7 08:09:10 2025
From: jgg at nvidia.com (Jason Gunthorpe)
Date: Sun, 7 Dec 2025 12:09:10 -0400
Subject: [PATCH rc v1 1/4] iommu/arm-smmu-v3: Add ignored bits to fix STE
 update sequence
In-Reply-To: <aTUEikcWXWwKAS/1@nvidia.com>
References: <cover.1764982046.git.nicolinc@nvidia.com>
 <6ec73bb7cd03d90a0764f12c4b14071158163818.1764982046.git.nicolinc@nvidia.com>
 <20251206193408.GD1219718@nvidia.com>
 <aTSH5Eap7leYQtPl@nvidia.com>
 <20251206195752.GI1219718@nvidia.com>
 <aTUEikcWXWwKAS/1@nvidia.com>
Message-ID: <aTWmpijaV75aixNb@nvidia.com>

On Sat, Dec 06, 2025 at 08:37:30PM -0800, Nicolin Chen wrote:
> > Then ignored should be adjusted by the used: Only if both used are 1
> > should the bit become ignored. Otherwise we can rely on which ever
> > used is 0 to generate the hitless update.
> 
> Hmm, not sure why it has to be both used.

Thats the only case that causes an issue, if only one is used then
there is no need to perform a breaking update.

If cur_used is 0 then the bit will be set in the first update, if
target_used is 0 then the bit will be set during the last update.

> >                 /* Bits can change because they are not currently being used */
> > +               cur_used[i] &= ~ignored[i];
> >                 unused_update[i] = (entry[i] & cur_used[i]) |
> >                                    (target[i] & ~cur_used[i]);
> 
> If one of ignored bits is set in entry[i] but unset in target[i],
> the unused_update will first mask it away, resulting in an extra
> unnecessary update (though it's still hitless).

Yes, this is how it has always worked. The point is to leave the
existing the same not try to optimize it using ignored.

> One more change that we need is at the last equation:
> -		if ((unused_update[i] & target_used[i]) != target[i])
> +		if ((unused_update[i] & target_used[i] & ~ignored[i]) !=
> +		    (target[i] & ~ignored[i]))
> 
> Either side might have the ignored bits, so we have to suppress
> ignored on both sides, which is required in the similar routine
> in arm_smmu_entry_differs_in_used_bits() of the kunit code.

The only way ignored is set is if both sides have it set and then we
update the bit in the firsy cycle meaning unused_update must have the
final value. There is no need to mask target since it will match. Not
changing this line is a big part of what makes this appealing because
it keeps the logic straightforward, in case ignored is used we shift
the update always to the first cycle then everything else is the same.

Jason


From nicolinc at nvidia.com  Sun Dec  7 11:35:01 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Sun, 7 Dec 2025 11:35:01 -0800
Subject: [PATCH rc v1 1/4] iommu/arm-smmu-v3: Add ignored bits to fix STE
 update sequence
In-Reply-To: <aTWmpijaV75aixNb@nvidia.com>
References: <cover.1764982046.git.nicolinc@nvidia.com>
 <6ec73bb7cd03d90a0764f12c4b14071158163818.1764982046.git.nicolinc@nvidia.com>
 <20251206193408.GD1219718@nvidia.com>
 <aTSH5Eap7leYQtPl@nvidia.com>
 <20251206195752.GI1219718@nvidia.com>
 <aTUEikcWXWwKAS/1@nvidia.com>
 <aTWmpijaV75aixNb@nvidia.com>
Message-ID: <aTXW5X4fAiEHAy6V@nvidia.com>

On Sun, Dec 07, 2025 at 12:09:10PM -0400, Jason Gunthorpe wrote:
> On Sat, Dec 06, 2025 at 08:37:30PM -0800, Nicolin Chen wrote:
> > > Then ignored should be adjusted by the used: Only if both used are 1
> > > should the bit become ignored. Otherwise we can rely on which ever
> > > used is 0 to generate the hitless update.
> > 
> > Hmm, not sure why it has to be both used.
> 
> Thats the only case that causes an issue, if only one is used then
> there is no need to perform a breaking update.
> 
> If cur_used is 0 then the bit will be set in the first update, if
> target_used is 0 then the bit will be set during the last update.

Ah, I see.

> > >                 /* Bits can change because they are not currently being used */
> > > +               cur_used[i] &= ~ignored[i];
> > >                 unused_update[i] = (entry[i] & cur_used[i]) |
> > >                                    (target[i] & ~cur_used[i]);
> > 
> > If one of ignored bits is set in entry[i] but unset in target[i],
> > the unused_update will first mask it away, resulting in an extra
> > unnecessary update (though it's still hitless).
> 
> Yes, this is how it has always worked. The point is to leave the
> existing the same not try to optimize it using ignored.

OK. Let's leave it and ask the test case to expect 3 v.s. 2.

> > One more change that we need is at the last equation:
> > -		if ((unused_update[i] & target_used[i]) != target[i])
> > +		if ((unused_update[i] & target_used[i] & ~ignored[i]) !=
> > +		    (target[i] & ~ignored[i]))
> > 
> > Either side might have the ignored bits, so we have to suppress
> > ignored on both sides, which is required in the similar routine
> > in arm_smmu_entry_differs_in_used_bits() of the kunit code.
> 
> The only way ignored is set is if both sides have it set and then we
> update the bit in the firsy cycle meaning unused_update must have the
> final value. There is no need to mask target since it will match. Not
> changing this line is a big part of what makes this appealing because
> it keeps the logic straightforward, in case ignored is used we shift
> the update always to the first cycle then everything else is the same.

The reason that I changed this is because the kunit tests failed
in arm_smmu_entry_differs_in_used_bits() when running the nested
cases:

STE initial value: 
    f800f0f0f0f0f0ef 00001000180800d5
    0449b6c400000000 000dbeefdeadbee0
    0000000000000000 0000000000000000
    0000000000000000 0000000000000000
STE used bits: 
    f80fffffffffffff 00003000fa0800ff
    065fffff0000ffff 000ffffffffffff0
    0000000000000000 0000000000000000
    0000000000000000 0000000000000000
STE target value: 
    000000000000000d 0000100000000000
    0449b6c400000000 000dbeefdeadbee0
    0000000000000000 0000000000000000
    0000000000000000 0000000000000000
STE used bits: 
    000000000000000f 0000300032080000
    065fffff0000ffff 000ffffffffffff0
    0000000000000000 0000000000000000
    0000000000000000 0000000000000000
STE value is now set to: 
    f800f0f0f0f0f0ef 00001000080000d5
    0449b6c400000000 000dbeefdeadbee0
    0000000000000000 0000000000000000
    0000000000000000 0000000000000000
    # arm_smmu_v3_write_ste_test_nested_s1dssbypass_to_s1bypass: EXPECTATION FAILED at drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c:92
                   Expected arm_smmu_entry_differs_in_used_bits( test_writer->entry, entry_used_bits, test_writer->init_entry, ignored, 8) && arm_smmu_entry_differs_in_used_bits( test_writer->entry, entry_used_bits, test_writer->target_entry, ignored, 8) to be false, but is true
STE value is now set to: 
    000000000000000d 00001000080000d5
    0449b6c400000000 000dbeefdeadbee0
    0000000000000000 0000000000000000
    0000000000000000 0000000000000000
STE value is now set to: 
    000000000000000d 0000100000000000
    0449b6c400000000 000dbeefdeadbee0
    0000000000000000 0000000000000000
    0000000000000000 0000000000000000
    not ok 21 arm_smmu_v3_write_ste_test_nested_s1dssbypass_to_s1bypass

STE initial value: 
    000000000000000d 0000100000000000
    0449b6c400000000 000dbeefdeadbee0
    0000000000000000 0000000000000000
    0000000000000000 0000000000000000
STE used bits: 
    000000000000000f 0000300032080000
    065fffff0000ffff 000ffffffffffff0
    0000000000000000 0000000000000000
    0000000000000000 0000000000000000
STE target value: 
    f800f0f0f0f0f0ef 00001000180800d5
    0449b6c400000000 000dbeefdeadbee0
    0000000000000000 0000000000000000
    0000000000000000 0000000000000000
STE used bits: 
    f80fffffffffffff 00003000fa0800ff
    065fffff0000ffff 000ffffffffffff0
    0000000000000000 0000000000000000
    0000000000000000 0000000000000000
STE value is now set to: 
    000000000000000d 00001000180800d5
    0449b6c400000000 000dbeefdeadbee0
    0000000000000000 0000000000000000
    0000000000000000 0000000000000000
    # arm_smmu_v3_write_ste_test_nested_s1bypass_to_s1dssbypass: EXPECTATION FAILED at drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c:92
                   Expected arm_smmu_entry_differs_in_used_bits( test_writer->entry, entry_used_bits, test_writer->init_entry, ignored, 8) && arm_smmu_entry_differs_in_used_bits( test_writer->entry, entry_used_bits, test_writer->target_entry, ignored, 8) to be false, but is true
STE value is now set to: 
    f800f0f0f0f0f0ef 00001000180800d5
    0449b6c400000000 000dbeefdeadbee0
    0000000000000000 0000000000000000
    0000000000000000 0000000000000000
    not ok 22 arm_smmu_v3_write_ste_test_nested_s1bypass_to_s1dssbypass

Any thought?

Thanks
Nicolin


From nicolinc at nvidia.com  Sun Dec  7 12:11:34 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Sun, 7 Dec 2025 12:11:34 -0800
Subject: [PATCH rc v1 1/4] iommu/arm-smmu-v3: Add ignored bits to fix STE
 update sequence
In-Reply-To: <aTXW5X4fAiEHAy6V@nvidia.com>
References: <cover.1764982046.git.nicolinc@nvidia.com>
 <6ec73bb7cd03d90a0764f12c4b14071158163818.1764982046.git.nicolinc@nvidia.com>
 <20251206193408.GD1219718@nvidia.com>
 <aTSH5Eap7leYQtPl@nvidia.com>
 <20251206195752.GI1219718@nvidia.com>
 <aTUEikcWXWwKAS/1@nvidia.com>
 <aTWmpijaV75aixNb@nvidia.com>
 <aTXW5X4fAiEHAy6V@nvidia.com>
Message-ID: <aTXfdr5iWS7vNBJT@nvidia.com>

On Sun, Dec 07, 2025 at 11:35:06AM -0800, Nicolin Chen wrote:
> On Sun, Dec 07, 2025 at 12:09:10PM -0400, Jason Gunthorpe wrote:
> > On Sat, Dec 06, 2025 at 08:37:30PM -0800, Nicolin Chen wrote:
> > > One more change that we need is at the last equation:
> > > -		if ((unused_update[i] & target_used[i]) != target[i])
> > > +		if ((unused_update[i] & target_used[i] & ~ignored[i]) !=
> > > +		    (target[i] & ~ignored[i]))
> > > 
> > > Either side might have the ignored bits, so we have to suppress
> > > ignored on both sides, which is required in the similar routine
> > > in arm_smmu_entry_differs_in_used_bits() of the kunit code.
> > 
> > The only way ignored is set is if both sides have it set and then we
> > update the bit in the firsy cycle meaning unused_update must have the
> > final value. There is no need to mask target since it will match. Not
> > changing this line is a big part of what makes this appealing because
> > it keeps the logic straightforward, in case ignored is used we shift
> > the update always to the first cycle then everything else is the same.
> 
> The reason that I changed this is because the kunit tests failed
> in arm_smmu_entry_differs_in_used_bits() when running the nested
> cases:
...
>     # arm_smmu_v3_write_ste_test_nested_s1dssbypass_to_s1bypass: EXPECTATION FAILED at drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c:92
>                    Expected arm_smmu_entry_differs_in_used_bits( test_writer->entry, entry_used_bits, test_writer->init_entry, ignored, 8) && arm_smmu_entry_differs_in_used_bits( test_writer->entry, entry_used_bits, test_writer->target_entry, ignored, 8) to be false, but is true

I think I figured it out. The driver one has included ignored bits
from target in unused_update[]. But the kunit one is comparing the
raw value.

So, we don't need to change the driver one as you remarked, but we
do need to mask the target[] in the kunit one:

@@ -46,7 +46,9 @@ static bool arm_smmu_entry_differs_in_used_bits(const __le64 *entry,
        unsigned int i;

        for (i = 0; i < length; i++) {
-               if ((entry[i] & used_bits[i]) != target[i])
+               __le64 used = used_bits[i] & ~ignored[i];
+
+               if ((entry[i] & used) != (target[i] & used))
                        differs = true;
        }
        return differs;

I will wrap up v2 and send it today.

Thanks
Nicolin


From nicolinc at nvidia.com  Sun Dec  7 12:49:14 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Sun, 7 Dec 2025 12:49:14 -0800
Subject: [PATCH rc v2 2/4] iommu/arm-smmu-v3: Ignore STE MEV when computing the update sequence
In-Reply-To: <cover.1765140287.git.nicolinc@nvidia.com>
References: <cover.1765140287.git.nicolinc@nvidia.com>
Message-ID: <08fd4d48e684732ad58064f690195f31a64979c4.1765140287.git.nicolinc@nvidia.com>

From: Jason Gunthorpe <jgg at nvidia.com>

Nested CD tables set the MEV bit to try to reduce multi-fault spamming on
the hypervisor. Since MEV is in STE word 1 this causes a breaking update
sequence that is not required and impacts real workloads.

For the purposes of STE updates the value of MEV doesn't matter, if it is
set/cleared early or late it just results in a change to the fault reports
that must be supported by the kernel anyhow. The spec says:

 Note: Software must expect, and be able to deal with, coalesced fault
 records even when MEV == 0.

So ignore MEV when computing the update sequence to avoid creating a
breaking update.

Fixes: da0c56520e88 ("iommu/arm-smmu-v3: Set MEV bit in nested STE for DoS mitigations")
Cc: stable at vger.kernel.org
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index e22c0890041b..3e161d8298d9 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1085,6 +1085,16 @@ EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_used);
 VISIBLE_IF_KUNIT
 void arm_smmu_get_ste_ignored(__le64 *ignored_bits)
 {
+	/*
+	 * MEV does not meaningfully impact the operation of the HW, it only
+	 * changes how many fault events are generated, thus we can ignore it
+	 * when computing the ordering. The spec notes the device can act like
+	 * MEV=1 anyhow:
+	 *
+	 *  Note: Software must expect, and be able to deal with, coalesced
+	 *  fault records even when MEV == 0.
+	 */
+	ignored_bits[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
 }
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_ignored);
 
-- 
2.43.0



From nicolinc at nvidia.com  Sun Dec  7 12:49:12 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Sun, 7 Dec 2025 12:49:12 -0800
Subject: [PATCH rc v2 0/4] iommu/arm-smmu-v3: Fix hitless STE update in nesting cases
Message-ID: <cover.1765140287.git.nicolinc@nvidia.com>

Occasional C_BAD_STE errors were observed in nesting setups where a device
attached to a nested bypass/identity domain enables PASID.

This occurred when the physical STE was updated from S2-only mode to S1+S2
nesting mode, but the update failed to use the hitless routine that it was
supposed to use. Instead, it cleared STE.V bit to load the CD table, while
the default substream was still actively performing DMA.

It was later found that the diff algorithm in arm_smmu_entry_qword_diff()
enforced an additional critical word due to misaligned MEV and EATS fields
between S2-only and S1+S2 modes.

Both fields are either well-managed or non-critical, so move them to the
"ignored" list to relax the qword diff algorithm.

Additionally, add KUnit test coverage for these nesting STE cases.

This is on Github:
https://github.com/nicolinc/iommufd/commits/smmuv3_ste_fixes/

A host kernel must apply this to fix the bug.

Changelog
v2:
 * Fix kunit tests
 * Update commit message
 * Keep MEV/EATS in used list by masking them away using ignored_bits
v1:
 https://lore.kernel.org/all/cover.1764982046.git.nicolinc at nvidia.com/

Jason Gunthorpe (3):
  iommu/arm-smmu-v3: Add ignored bits to fix STE update sequence
  iommu/arm-smmu-v3: Ignore STE MEV when computing the update sequence
  iommu/arm-smmu-v3: Ignore STE EATS when computing the update sequence

Nicolin Chen (1):
  iommu/arm-smmu-v3-test: Add nested s1bypass/s1dssbypass coverage

 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  2 +
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  | 80 ++++++++++++++++++-
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 43 ++++++++--
 3 files changed, 117 insertions(+), 8 deletions(-)

-- 
2.43.0



From nicolinc at nvidia.com  Sun Dec  7 12:49:16 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Sun, 7 Dec 2025 12:49:16 -0800
Subject: [PATCH rc v2 4/4] iommu/arm-smmu-v3-test: Add nested s1bypass/s1dssbypass coverage
In-Reply-To: <cover.1765140287.git.nicolinc@nvidia.com>
References: <cover.1765140287.git.nicolinc@nvidia.com>
Message-ID: <b6d87901f89c05dd9e1d0c1e819040d205f569a7.1765140287.git.nicolinc@nvidia.com>

STE in a nested case requires both S1 and S2 fields. And this makes the use
case different from the existing one.

Add coverage for previously failed cases shifting between S2-only and S1+S2
STEs.

Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  | 61 +++++++++++++++++++
 1 file changed, 61 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
index 3556e65cf9ac..1672e75ebffc 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
@@ -555,6 +555,65 @@ static void arm_smmu_v3_write_ste_test_s2_to_s1_stall(struct kunit *test)
 						       NUM_EXPECTED_SYNCS(3));
 }
 
+static void arm_smmu_test_make_nested_cdtable_ste(
+	struct arm_smmu_ste *ste, unsigned int s1dss, const dma_addr_t dma_addr,
+	enum arm_smmu_test_master_feat feat)
+{
+	bool stall_enabled = feat & ARM_SMMU_MASTER_TEST_STALL;
+	bool ats_enabled = feat & ARM_SMMU_MASTER_TEST_ATS;
+	struct arm_smmu_ste s1ste;
+
+	struct arm_smmu_master master = {
+		.ats_enabled = ats_enabled,
+		.cd_table.cdtab_dma = dma_addr,
+		.cd_table.s1cdmax = 0xFF,
+		.cd_table.s1fmt = STRTAB_STE_0_S1FMT_64K_L2,
+		.smmu = &smmu,
+		.stall_enabled = stall_enabled,
+	};
+
+	arm_smmu_test_make_s2_ste(ste, ARM_SMMU_MASTER_TEST_ATS);
+	arm_smmu_make_cdtable_ste(&s1ste, &master, ats_enabled, s1dss);
+
+	ste->data[0] = cpu_to_le64(
+		STRTAB_STE_0_V |
+		FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_NESTED));
+	ste->data[0] |= s1ste.data[0] & ~cpu_to_le64(STRTAB_STE_0_CFG);
+	ste->data[1] |= s1ste.data[1];
+	/* Merge events for DoS mitigations on eventq */
+	ste->data[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
+}
+
+static void
+arm_smmu_v3_write_ste_test_nested_s1dssbypass_to_s1bypass(struct kunit *test)
+{
+	struct arm_smmu_ste s1_ste;
+	struct arm_smmu_ste s2_ste;
+
+	arm_smmu_test_make_nested_cdtable_ste(&s1_ste,
+					      STRTAB_STE_1_S1DSS_BYPASS,
+					      fake_cdtab_dma_addr,
+					      ARM_SMMU_MASTER_TEST_ATS);
+	arm_smmu_test_make_s2_ste(&s2_ste, 0);
+	arm_smmu_v3_test_ste_expect_hitless_transition(test, &s1_ste, &s2_ste,
+						       NUM_EXPECTED_SYNCS(3));
+}
+
+static void
+arm_smmu_v3_write_ste_test_nested_s1bypass_to_s1dssbypass(struct kunit *test)
+{
+	struct arm_smmu_ste s1_ste;
+	struct arm_smmu_ste s2_ste;
+
+	arm_smmu_test_make_nested_cdtable_ste(&s1_ste,
+					      STRTAB_STE_1_S1DSS_BYPASS,
+					      fake_cdtab_dma_addr,
+					      ARM_SMMU_MASTER_TEST_ATS);
+	arm_smmu_test_make_s2_ste(&s2_ste, 0);
+	arm_smmu_v3_test_ste_expect_hitless_transition(test, &s2_ste, &s1_ste,
+						       NUM_EXPECTED_SYNCS(2));
+}
+
 static void arm_smmu_v3_write_cd_test_sva_clear(struct kunit *test)
 {
 	struct arm_smmu_cd cd = {};
@@ -601,6 +660,8 @@ static struct kunit_case arm_smmu_v3_test_cases[] = {
 	KUNIT_CASE(arm_smmu_v3_write_cd_test_s1_change_asid),
 	KUNIT_CASE(arm_smmu_v3_write_ste_test_s1_to_s2_stall),
 	KUNIT_CASE(arm_smmu_v3_write_ste_test_s2_to_s1_stall),
+	KUNIT_CASE(arm_smmu_v3_write_ste_test_nested_s1dssbypass_to_s1bypass),
+	KUNIT_CASE(arm_smmu_v3_write_ste_test_nested_s1bypass_to_s1dssbypass),
 	KUNIT_CASE(arm_smmu_v3_write_cd_test_sva_clear),
 	KUNIT_CASE(arm_smmu_v3_write_cd_test_sva_release),
 	{},
-- 
2.43.0



From nicolinc at nvidia.com  Sun Dec  7 12:49:13 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Sun, 7 Dec 2025 12:49:13 -0800
Subject: [PATCH rc v2 1/4] iommu/arm-smmu-v3: Add ignored bits to fix STE update sequence
In-Reply-To: <cover.1765140287.git.nicolinc@nvidia.com>
References: <cover.1765140287.git.nicolinc@nvidia.com>
Message-ID: <0db5caabdcdd8aa170f4c196e94d54664cc87fd3.1765140287.git.nicolinc@nvidia.com>

From: Jason Gunthorpe <jgg at nvidia.com>

C_BAD_STE was observed when updating nested STE from an S1-bypass mode to
an S1DSS-bypass mode. As both modes enabled S2, the used bit is slightly
different than the normal S1-bypass and S1DSS-bypass modes. As a result,
fields like MEV and EATS in S2's used list marked the word1 as a critical
word that requested a STE.V=0. This breaks a hitless update.

However, both MEV and EATS aren't critical in terms of STE update. One
controls the merge of the events and the other controls the ATS that is
managed by the driver at the same time via pci_enable_ats().

Add an arm_smmu_get_ste_ignored() to allow STE update algorithm to ignore
those fields, avoiding the STE update breakages.

Note that this change is required by both MEV and EATS fields, which were
introduced in different kernel versions. So add this get_ignored() first.
The MEV and EATS will be added in arm_smmu_get_ste_ignored() separately.

Fixes: 1e8be08d1c91 ("iommu/arm-smmu-v3: Support IOMMU_DOMAIN_NESTED")
Cc: stable at vger.kernel.org
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  2 ++
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  | 19 ++++++++++++---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 24 +++++++++++++++----
 3 files changed, 37 insertions(+), 8 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index ae23aacc3840..d5f0e5407b9f 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -900,6 +900,7 @@ struct arm_smmu_entry_writer {
 
 struct arm_smmu_entry_writer_ops {
 	void (*get_used)(const __le64 *entry, __le64 *used);
+	void (*get_ignored)(__le64 *ignored_bits);
 	void (*sync)(struct arm_smmu_entry_writer *writer);
 };
 
@@ -911,6 +912,7 @@ void arm_smmu_make_s2_domain_ste(struct arm_smmu_ste *target,
 
 #if IS_ENABLED(CONFIG_KUNIT)
 void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits);
+void arm_smmu_get_ste_ignored(__le64 *ignored_bits);
 void arm_smmu_write_entry(struct arm_smmu_entry_writer *writer, __le64 *cur,
 			  const __le64 *target);
 void arm_smmu_get_cd_used(const __le64 *ent, __le64 *used_bits);
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
index d2671bfd3798..3556e65cf9ac 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
@@ -38,13 +38,16 @@ enum arm_smmu_test_master_feat {
 static bool arm_smmu_entry_differs_in_used_bits(const __le64 *entry,
 						const __le64 *used_bits,
 						const __le64 *target,
+						const __le64 *ignored,
 						unsigned int length)
 {
 	bool differs = false;
 	unsigned int i;
 
 	for (i = 0; i < length; i++) {
-		if ((entry[i] & used_bits[i]) != target[i])
+		__le64 used = used_bits[i] & ~ignored[i];
+
+		if ((entry[i] & used) != (target[i] & used))
 			differs = true;
 	}
 	return differs;
@@ -56,12 +59,18 @@ arm_smmu_test_writer_record_syncs(struct arm_smmu_entry_writer *writer)
 	struct arm_smmu_test_writer *test_writer =
 		container_of(writer, struct arm_smmu_test_writer, writer);
 	__le64 *entry_used_bits;
+	__le64 *ignored;
 
 	entry_used_bits = kunit_kzalloc(
 		test_writer->test, sizeof(*entry_used_bits) * NUM_ENTRY_QWORDS,
 		GFP_KERNEL);
 	KUNIT_ASSERT_NOT_NULL(test_writer->test, entry_used_bits);
 
+	ignored = kunit_kzalloc(test_writer->test,
+				sizeof(*ignored) * NUM_ENTRY_QWORDS,
+				GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test_writer->test, ignored);
+
 	pr_debug("STE value is now set to: ");
 	print_hex_dump_debug("    ", DUMP_PREFIX_NONE, 16, 8,
 			     test_writer->entry,
@@ -79,14 +88,17 @@ arm_smmu_test_writer_record_syncs(struct arm_smmu_entry_writer *writer)
 		 * configuration.
 		 */
 		writer->ops->get_used(test_writer->entry, entry_used_bits);
+		if (writer->ops->get_ignored)
+			writer->ops->get_ignored(ignored);
 		KUNIT_EXPECT_FALSE(
 			test_writer->test,
 			arm_smmu_entry_differs_in_used_bits(
 				test_writer->entry, entry_used_bits,
-				test_writer->init_entry, NUM_ENTRY_QWORDS) &&
+				test_writer->init_entry, ignored,
+				NUM_ENTRY_QWORDS) &&
 				arm_smmu_entry_differs_in_used_bits(
 					test_writer->entry, entry_used_bits,
-					test_writer->target_entry,
+					test_writer->target_entry, ignored,
 					NUM_ENTRY_QWORDS));
 	}
 }
@@ -106,6 +118,7 @@ arm_smmu_v3_test_debug_print_used_bits(struct arm_smmu_entry_writer *writer,
 static const struct arm_smmu_entry_writer_ops test_ste_ops = {
 	.sync = arm_smmu_test_writer_record_syncs,
 	.get_used = arm_smmu_get_ste_used,
+	.get_ignored = arm_smmu_get_ste_ignored,
 };
 
 static const struct arm_smmu_entry_writer_ops test_cd_ops = {
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index d16d35c78c06..e22c0890041b 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1082,6 +1082,12 @@ void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits)
 }
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_used);
 
+VISIBLE_IF_KUNIT
+void arm_smmu_get_ste_ignored(__le64 *ignored_bits)
+{
+}
+EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_ignored);
+
 /*
  * Figure out if we can do a hitless update of entry to become target. Returns a
  * bit mask where 1 indicates that qword needs to be set disruptively.
@@ -1094,13 +1100,22 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
 {
 	__le64 target_used[NUM_ENTRY_QWORDS] = {};
 	__le64 cur_used[NUM_ENTRY_QWORDS] = {};
+	__le64 ignored[NUM_ENTRY_QWORDS] = {};
 	u8 used_qword_diff = 0;
 	unsigned int i;
 
 	writer->ops->get_used(entry, cur_used);
 	writer->ops->get_used(target, target_used);
+	if (writer->ops->get_ignored)
+		writer->ops->get_ignored(ignored);
 
 	for (i = 0; i != NUM_ENTRY_QWORDS; i++) {
+		/*
+		 * Ignored is only used for bits that are used by both entries,
+		 * otherwise it is sequenced according to the unused entry.
+		 */
+		ignored[i] &= target_used[i] & cur_used[i];
+
 		/*
 		 * Check that masks are up to date, the make functions are not
 		 * allowed to set a bit to 1 if the used function doesn't say it
@@ -1109,6 +1124,7 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
 		WARN_ON_ONCE(target[i] & ~target_used[i]);
 
 		/* Bits can change because they are not currently being used */
+		cur_used[i] &= ~ignored[i];
 		unused_update[i] = (entry[i] & cur_used[i]) |
 				   (target[i] & ~cur_used[i]);
 		/*
@@ -1207,12 +1223,9 @@ void arm_smmu_write_entry(struct arm_smmu_entry_writer *writer, __le64 *entry,
 		entry_set(writer, entry, target, 0, 1);
 	} else {
 		/*
-		 * No inuse bit changed. Sanity check that all unused bits are 0
-		 * in the entry. The target was already sanity checked by
-		 * compute_qword_diff().
+		 * No inuse bit changed, though ignored bits may have changed.
 		 */
-		WARN_ON_ONCE(
-			entry_set(writer, entry, target, 0, NUM_ENTRY_QWORDS));
+		entry_set(writer, entry, target, 0, NUM_ENTRY_QWORDS);
 	}
 }
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_write_entry);
@@ -1543,6 +1556,7 @@ static void arm_smmu_ste_writer_sync_entry(struct arm_smmu_entry_writer *writer)
 static const struct arm_smmu_entry_writer_ops arm_smmu_ste_writer_ops = {
 	.sync = arm_smmu_ste_writer_sync_entry,
 	.get_used = arm_smmu_get_ste_used,
+	.get_ignored = arm_smmu_get_ste_ignored,
 };
 
 static void arm_smmu_write_ste(struct arm_smmu_master *master, u32 sid,
-- 
2.43.0



From nicolinc at nvidia.com  Sun Dec  7 12:49:15 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Sun, 7 Dec 2025 12:49:15 -0800
Subject: [PATCH rc v2 3/4] iommu/arm-smmu-v3: Ignore STE EATS when computing the update sequence
In-Reply-To: <cover.1765140287.git.nicolinc@nvidia.com>
References: <cover.1765140287.git.nicolinc@nvidia.com>
Message-ID: <b3586cb03317fb2362e936e4d303566851b506d4.1765140287.git.nicolinc@nvidia.com>

From: Jason Gunthorpe <jgg at nvidia.com>

If a VM wants to toggle EATS off at the same time as changing the CFG, the
hypervisor will see EATS change to 0 and insert a V=0 breaking update into
the STE even though the VM did not ask for that.

In bare metal, EATS is ignored by CFG=ABORT/BYPASS, which is why this does
not cause a problem until we have nested where CFG is always a variation of
S2 trans that does use EATS.

Relax the rules for EATS sequencing, we don't need it to be exact because
the enclosing code will always disable ATS at the PCI device if we are
changing EATS. This ensures there are no ATS transactions that can race
with an EATS change so we don't need to carefully sequence these bits.

Fixes: 1e8be08d1c91 ("iommu/arm-smmu-v3: Support IOMMU_DOMAIN_NESTED")
Cc: stable at vger.kernel.org
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 3e161d8298d9..72ba41591fdb 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1095,6 +1095,15 @@ void arm_smmu_get_ste_ignored(__le64 *ignored_bits)
 	 *  fault records even when MEV == 0.
 	 */
 	ignored_bits[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
+
+	/*
+	 * EATS is used to reject and control the ATS behavior of the device. If
+	 * we are changing it away from 0 then we already trust the device to
+	 * use ATS properly and we have sequenced the device's ATS enable in PCI
+	 * config space to prevent it from issuing ATS while we are changing
+	 * EATS.
+	 */
+	ignored_bits[1] |= cpu_to_le64(STRTAB_STE_1_EATS);
 }
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_ignored);
 
-- 
2.43.0



From cristian.ciocaltea at collabora.com  Sun Dec  7 13:38:52 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Sun, 7 Dec 2025 23:38:52 +0200
Subject: [PATCH 0/4] Add HDMI 2.0 support to DW HDMI QP TX
In-Reply-To: <4ec78537-5184-4e6b-9ada-ff268fbe9c3e@murena.io>
References: <20251203-dw-hdmi-qp-scramb-v1-0-836fe7401a69@collabora.com>
 <4ec78537-5184-4e6b-9ada-ff268fbe9c3e@murena.io>
Message-ID: <ab0eee09-56bf-4a8e-8feb-f0bc355d476b@collabora.com>

On 12/7/25 3:16 PM, Maud Spierings wrote:
> Awesome work! I've been waiting for this feature!
> 
> I can now actually get 1440p100 on my display and 4k60 on my tv over HDMI.
> 
> Tested-by: Maud Spierings <maud_spierings at hotmail.com>

Thanks,
Cristian



From cristian.ciocaltea at collabora.com  Sun Dec  7 13:49:47 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Sun, 7 Dec 2025 23:49:47 +0200
Subject: [PATCH 0/4] Add HDMI 2.0 support to DW HDMI QP TX
In-Reply-To: <20251203-dw-hdmi-qp-scramb-v1-0-836fe7401a69@collabora.com>
References: <20251203-dw-hdmi-qp-scramb-v1-0-836fe7401a69@collabora.com>
Message-ID: <156efe34-93f6-4055-864c-29706088e63c@collabora.com>

On 12/3/25 8:27 PM, Cristian Ciocaltea wrote:
> This patch series provides the missing support for high TMDS clock ratio
> and scrambling to DW HDMI QP TX library, required for handling HDMI 2.0
> display modes on RK3576 & RK3588 SoCs.

Please also try the following PHY patch if you encounter issues while testing
1080p at 120Hz with 10-bit RGB:

https://lore.kernel.org/all/20251204-phy-hdptx-pll-fix-v1-1-d94fd6cfd59b at collabora.com/


From robh at kernel.org  Sun Dec  7 17:28:26 2025
From: robh at kernel.org (Rob Herring)
Date: Sun, 7 Dec 2025 19:28:26 -0600
Subject: [PATCH v7 1/3] dt-bindings: soc: imx93-media-blk-ctrl: Add PDFC
 subnode to schema and example
In-Reply-To: <20251202-v6-18-topic-imx93-parallel-display-v7-1-2cce31d64608@pengutronix.de>
References: <20251202-v6-18-topic-imx93-parallel-display-v7-0-2cce31d64608@pengutronix.de>
 <20251202-v6-18-topic-imx93-parallel-display-v7-1-2cce31d64608@pengutronix.de>
Message-ID: <20251208012826.GA340359-robh@kernel.org>

On Tue, Dec 02, 2025 at 02:32:58PM +0100, Marco Felsch wrote:
> From: Liu Ying <victor.liu at nxp.com>
> 
> i.MX93 SoC mediamix blk-ctrl contains one DISPLAY_MUX register which
> configures parallel display format by using the "PARALLEL_DISP_FORMAT"
> field. Document the Parallel Display Format Configuration(PDFC) subnode
> and add the subnode to example.
> 
> Signed-off-by: Liu Ying <victor.liu at nxp.com>
> [m.felsch at pengutronix.de: port to v6.18-rc1]
> [m.felsch at pengutronix.de: add bus-width]
> Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
> ---
>  .../bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml | 92 ++++++++++++++++++++++
>  1 file changed, 92 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> index 34aea58094e55365a2f9c86092f637e533f954ff..6e2d86d9341c75108b492bcbabc8a560d8e707cd 100644
> --- a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> +++ b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> @@ -26,6 +26,12 @@ properties:
>    reg:
>      maxItems: 1
>  
> +  '#address-cells':
> +    const: 1
> +
> +  '#size-cells':
> +    const: 1
> +

And 'ranges' needed.

>    '#power-domain-cells':
>      const: 1
>  
> @@ -40,6 +46,60 @@ properties:
>      minItems: 8
>      maxItems: 10
>  
> +  bridge at 60:
> +    type: object
> +    additionalProperties: false
> +
> +    properties:
> +      compatible:
> +        const: nxp,imx93-pdfc
> +
> +      reg:
> +        maxItems: 1
> +
> +      ports:
> +        $ref: /schemas/graph.yaml#/properties/ports
> +
> +        properties:
> +          port at 0:
> +            $ref: /schemas/graph.yaml#/properties/port
> +            description: Input port node to receive pixel data.
> +
> +          port at 1:
> +            $ref: /schemas/graph.yaml#/$defs/port-base
> +            unevaluatedProperties: false
> +            description: Output port node to downstream pixel data receivers.
> +
> +            properties:
> +              endpoint:
> +                $ref: /schemas/graph.yaml#/$defs/endpoint-base
> +                unevaluatedProperties: false
> +
> +                properties:
> +                  bus-width:
> +                    enum: [ 16, 18, 24 ]
> +                    description:
> +                      Specify the physical parallel bus width.
> +
> +                      This property is optional if the display bus-width
> +                      matches the SoC bus-width, e.g. a 18-bit RGB666 (display)
> +                      is connected and all 18-bit data lanes are muxed to the
> +                      parallel-output pads.
> +
> +                      This property must be set to 18 to cut only the LSBs
> +                      instead of the MSBs in case a 24-bit RGB888 display is
> +                      connected and only the lower 18-bit data lanes are muxed
> +                      to the parallel-output pads.
> +
> +        required:
> +          - port at 0
> +          - port at 1
> +
> +    required:
> +      - compatible
> +      - reg
> +      - ports
> +
>  allOf:
>    - if:
>        properties:
> @@ -81,9 +141,12 @@ allOf:
>              - const: isi
>              - const: csi
>              - const: dsi
> +
>  required:
>    - compatible
>    - reg
> +  - '#address-cells'
> +  - '#size-cells'
>    - power-domains
>    - clocks
>    - clock-names
> @@ -112,4 +175,33 @@ examples:
>                 clock-names = "apb", "axi", "nic", "disp", "cam",
>                               "pxp", "lcdif", "isi", "csi", "dsi";
>        #power-domain-cells = <1>;
> +      #address-cells = <1>;
> +      #size-cells = <1>;
> +
> +      bridge at 60 {
> +        compatible = "nxp,imx93-pdfc";
> +        reg = <0x60 0x4>;
> +
> +        ports {
> +          #address-cells = <1>;
> +          #size-cells = <0>;
> +
> +          port at 0 {
> +            reg = <0>;
> +
> +            pdfc_from_lcdif: endpoint {
> +              remote-endpoint = <&lcdif_to_pdfc>;
> +            };
> +          };
> +
> +          port at 1 {
> +            reg = <1>;
> +
> +            pdfc_to_panel: endpoint {
> +              remote-endpoint = <&panel_from_pdfc>;
> +              bus-width = <18>;
> +            };
> +          };
> +        };
> +      };
>      };
> 
> -- 
> 2.47.3
> 


From kernel at airkyi.com  Sun Dec  7 17:54:51 2025
From: kernel at airkyi.com (Chaoyi Chen)
Date: Mon,  8 Dec 2025 09:54:51 +0800
Subject: [PATCH v13 02/11] usb: typec: Export typec bus and typec altmode device type
In-Reply-To: <20251208015500.94-1-kernel@airkyi.com>
References: <20251208015500.94-1-kernel@airkyi.com>
Message-ID: <20251208015500.94-3-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

The DRM may want to register a notifier on the typec bus to know when
a typec altmode device is added, and distinguish between different
types of typec altmode device.

Export these things.

Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
Reviewed-by: Heikki Krogerus <heikki.krogerus at linux.intel.com>
---

(no changes since v12)

Changes in v11:
- Also export typec bus.
- Add more detailed comments.

(no changes since v9)

 drivers/usb/typec/bus.c           |  1 +
 drivers/usb/typec/bus.h           | 10 ----------
 drivers/usb/typec/class.c         |  3 +++
 include/linux/usb/typec.h         |  3 +++
 include/linux/usb/typec_altmode.h |  8 ++++++++
 5 files changed, 15 insertions(+), 10 deletions(-)

diff --git a/drivers/usb/typec/bus.c b/drivers/usb/typec/bus.c
index a33da7f458a5..e84b134a3381 100644
--- a/drivers/usb/typec/bus.c
+++ b/drivers/usb/typec/bus.c
@@ -569,3 +569,4 @@ const struct bus_type typec_bus = {
 	.probe = typec_probe,
 	.remove = typec_remove,
 };
+EXPORT_SYMBOL_GPL(typec_bus);
diff --git a/drivers/usb/typec/bus.h b/drivers/usb/typec/bus.h
index b58e131450d1..7df5deb1dd3a 100644
--- a/drivers/usb/typec/bus.h
+++ b/drivers/usb/typec/bus.h
@@ -5,7 +5,6 @@
 
 #include <linux/usb/typec_altmode.h>
 
-struct bus_type;
 struct typec_mux;
 struct typec_retimer;
 
@@ -28,13 +27,4 @@ struct altmode {
 
 #define to_altmode(d) container_of(d, struct altmode, adev)
 
-extern const struct bus_type typec_bus;
-extern const struct device_type typec_port_altmode_dev_type;
-extern const struct device_type typec_plug_altmode_dev_type;
-extern const struct device_type typec_partner_altmode_dev_type;
-
-#define is_typec_port_altmode(dev) ((dev)->type == &typec_port_altmode_dev_type)
-#define is_typec_plug_altmode(dev) ((dev)->type == &typec_plug_altmode_dev_type)
-#define is_typec_partner_altmode(dev) ((dev)->type == &typec_partner_altmode_dev_type)
-
 #endif /* __USB_TYPEC_ALTMODE_H__ */
diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index d6b88317f8a4..c4ff4310ff58 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -537,18 +537,21 @@ const struct device_type typec_port_altmode_dev_type = {
 	.groups = typec_altmode_groups,
 	.release = typec_altmode_release,
 };
+EXPORT_SYMBOL_GPL(typec_port_altmode_dev_type);
 
 const struct device_type typec_plug_altmode_dev_type = {
 	.name = "typec_plug_alternate_mode",
 	.groups = typec_altmode_groups,
 	.release = typec_altmode_release,
 };
+EXPORT_SYMBOL_GPL(typec_plug_altmode_dev_type);
 
 const struct device_type typec_partner_altmode_dev_type = {
 	.name = "typec_partner_alternate_mode",
 	.groups = typec_altmode_groups,
 	.release = typec_altmode_release,
 };
+EXPORT_SYMBOL_GPL(typec_partner_altmode_dev_type);
 
 static struct typec_altmode *
 typec_register_altmode(struct device *parent,
diff --git a/include/linux/usb/typec.h b/include/linux/usb/typec.h
index 309251572e2e..c6fd46902fce 100644
--- a/include/linux/usb/typec.h
+++ b/include/linux/usb/typec.h
@@ -20,12 +20,15 @@ struct typec_port;
 struct typec_altmode_ops;
 struct typec_cable_ops;
 
+struct bus_type;
 struct fwnode_handle;
 struct device;
 
 struct usb_power_delivery;
 struct usb_power_delivery_desc;
 
+extern const struct bus_type typec_bus;
+
 enum typec_port_type {
 	TYPEC_PORT_SRC,
 	TYPEC_PORT_SNK,
diff --git a/include/linux/usb/typec_altmode.h b/include/linux/usb/typec_altmode.h
index f7db3bd4c90e..9197a4637a93 100644
--- a/include/linux/usb/typec_altmode.h
+++ b/include/linux/usb/typec_altmode.h
@@ -9,6 +9,14 @@
 
 #define MODE_DISCOVERY_MAX	6
 
+extern const struct device_type typec_port_altmode_dev_type;
+extern const struct device_type typec_plug_altmode_dev_type;
+extern const struct device_type typec_partner_altmode_dev_type;
+
+#define is_typec_port_altmode(dev) ((dev)->type == &typec_port_altmode_dev_type)
+#define is_typec_plug_altmode(dev) ((dev)->type == &typec_plug_altmode_dev_type)
+#define is_typec_partner_altmode(dev) ((dev)->type == &typec_partner_altmode_dev_type)
+
 struct typec_altmode_ops;
 
 /**
-- 
2.51.1



From kernel at airkyi.com  Sun Dec  7 17:54:52 2025
From: kernel at airkyi.com (Chaoyi Chen)
Date: Mon,  8 Dec 2025 09:54:52 +0800
Subject: [PATCH v13 03/11] drm/bridge: Implement generic USB Type-C DP HPD bridge
In-Reply-To: <20251208015500.94-1-kernel@airkyi.com>
References: <20251208015500.94-1-kernel@airkyi.com>
Message-ID: <20251208015500.94-4-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

The HPD function of Type-C DP is implemented through
drm_connector_oob_hotplug_event(). For embedded DP, it is required
that the DRM connector fwnode corresponds to the Type-C port fwnode.

To describe the relationship between the DP controller and the Type-C
port device, we usually using drm_bridge to build a bridge chain.

Now several USB-C controller drivers have already implemented the DP
HPD bridge function provided by aux-hpd-bridge.c, it will build a DP
HPD bridge on USB-C connector port device.

But this requires the USB-C controller driver to manually register the
HPD bridge. If the driver does not implement this feature, the bridge
will not be create.

So this patch implements a generic DP HPD bridge based on
aux-hpd-bridge.c. It will monitor Type-C bus events, and when a
Type-C port device containing the DP svid is registered, it will
create an HPD bridge for it without the need for the USB-C controller
driver to implement it.

Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
Reviewed-by: Heikki Krogerus <heikki.krogerus at linux.intel.com>
---

Changes in v13:
- Only register drm dp hpd bridge for typec port altmode device.

(no changes since v12)

Changes in v11:
- Switch to using typec bus notifiers.

(no changes since v10)

Changes in v9:
- Remove the exposed DRM_AUX_HPD_BRIDGE option, and select
DRM_AUX_HPD_TYPEC_BRIDGE when it is available.
- Add more commit comment about problem background.

Changes in v8:
- Merge generic DP HPD bridge into one module.

 drivers/gpu/drm/bridge/Kconfig                | 10 ++++
 drivers/gpu/drm/bridge/Makefile               |  1 +
 .../gpu/drm/bridge/aux-hpd-typec-dp-bridge.c  | 49 +++++++++++++++++++
 3 files changed, 60 insertions(+)
 create mode 100644 drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index a250afd8d662..559487aa09a9 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -30,6 +30,16 @@ config DRM_AUX_HPD_BRIDGE
 	  Simple bridge that terminates the bridge chain and provides HPD
 	  support.
 
+if DRM_AUX_HPD_BRIDGE
+config DRM_AUX_HPD_TYPEC_BRIDGE
+	tristate
+	depends on TYPEC || !TYPEC
+	default TYPEC
+	help
+	  Simple bridge that terminates the bridge chain and provides HPD
+	  support. It build bridge on each USB-C connector device node.
+endif
+
 menu "Display Interface Bridges"
 	depends on DRM && DRM_BRIDGE
 
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index c7dc03182e59..a3a0393d2e72 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_DRM_AUX_BRIDGE) += aux-bridge.o
 obj-$(CONFIG_DRM_AUX_HPD_BRIDGE) += aux-hpd-bridge.o
+obj-$(CONFIG_DRM_AUX_HPD_TYPEC_BRIDGE) += aux-hpd-typec-dp-bridge.o
 obj-$(CONFIG_DRM_CHIPONE_ICN6211) += chipone-icn6211.o
 obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o
 obj-$(CONFIG_DRM_CROS_EC_ANX7688) += cros-ec-anx7688.o
diff --git a/drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c b/drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c
new file mode 100644
index 000000000000..d915e0fb0668
--- /dev/null
+++ b/drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0+
+#include <linux/of.h>
+#include <linux/usb/typec_altmode.h>
+#include <linux/usb/typec_dp.h>
+
+#include <drm/bridge/aux-bridge.h>
+
+static int drm_typec_bus_event(struct notifier_block *nb,
+			       unsigned long action, void *data)
+{
+	struct device *dev = (struct device *)data;
+	struct typec_altmode *alt = to_typec_altmode(dev);
+
+	if (action != BUS_NOTIFY_ADD_DEVICE)
+		goto done;
+
+	/*
+	 * alt->dev.parent->parent : USB-C controller device
+	 * alt->dev.parent         : USB-C connector device
+	 */
+	if (is_typec_port_altmode(&alt->dev) && alt->svid == USB_TYPEC_DP_SID)
+		drm_dp_hpd_bridge_register(alt->dev.parent->parent,
+					   to_of_node(alt->dev.parent->fwnode));
+
+done:
+	return NOTIFY_OK;
+}
+
+static struct notifier_block drm_typec_event_nb = {
+	.notifier_call = drm_typec_bus_event,
+};
+
+static void drm_aux_hpd_typec_dp_bridge_module_exit(void)
+{
+	bus_unregister_notifier(&typec_bus, &drm_typec_event_nb);
+}
+
+static int __init drm_aux_hpd_typec_dp_bridge_module_init(void)
+{
+	bus_register_notifier(&typec_bus, &drm_typec_event_nb);
+
+	return 0;
+}
+
+module_init(drm_aux_hpd_typec_dp_bridge_module_init);
+module_exit(drm_aux_hpd_typec_dp_bridge_module_exit);
+
+MODULE_DESCRIPTION("DRM TYPEC DP HPD BRIDGE");
+MODULE_LICENSE("GPL");
-- 
2.51.1



From kernel at airkyi.com  Sun Dec  7 17:54:50 2025
From: kernel at airkyi.com (Chaoyi Chen)
Date: Mon,  8 Dec 2025 09:54:50 +0800
Subject: [PATCH v13 01/11] usb: typec: Set the bus also for the port and plug altmodes
In-Reply-To: <20251208015500.94-1-kernel@airkyi.com>
References: <20251208015500.94-1-kernel@airkyi.com>
Message-ID: <20251208015500.94-2-kernel@airkyi.com>

From: Heikki Krogerus <heikki.krogerus at linux.intel.com>

The port and plug altmodes can't be bound to the altmode
drivers because the altmode drivers are meant for partner
communication using the VDM (vendor defined messages), but
they can still be part of the bus. The bus will make sure
that the normal bus notifications are available also with
the port altmodes.

The previously used common device type for all alternate
modes is replaced with separate dedicated device types for
port, plug, and partner alternate modes.

Signed-off-by: Heikki Krogerus <heikki.krogerus at linux.intel.com>
Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
---

(no changes since v13)

Changes in v12:
- Add missing Signed-off-by line.

 drivers/usb/typec/bus.c   | 24 +++++++++++++++++++++++-
 drivers/usb/typec/bus.h   |  8 ++++++--
 drivers/usb/typec/class.c | 33 ++++++++++++++++++++++-----------
 3 files changed, 51 insertions(+), 14 deletions(-)

diff --git a/drivers/usb/typec/bus.c b/drivers/usb/typec/bus.c
index a884cec9ab7e..a33da7f458a5 100644
--- a/drivers/usb/typec/bus.c
+++ b/drivers/usb/typec/bus.c
@@ -445,7 +445,23 @@ static struct attribute *typec_attrs[] = {
 	&dev_attr_description.attr,
 	NULL
 };
-ATTRIBUTE_GROUPS(typec);
+
+static umode_t typec_is_visible(struct kobject *kobj, struct attribute *attr, int n)
+{
+	if (is_typec_partner_altmode(kobj_to_dev(kobj)))
+		return attr->mode;
+	return 0;
+}
+
+static const struct attribute_group typec_group = {
+	.is_visible = typec_is_visible,
+	.attrs = typec_attrs,
+};
+
+static const struct attribute_group *typec_groups[] = {
+	&typec_group,
+	NULL
+};
 
 static int typec_match(struct device *dev, const struct device_driver *driver)
 {
@@ -453,6 +469,9 @@ static int typec_match(struct device *dev, const struct device_driver *driver)
 	struct typec_altmode *altmode = to_typec_altmode(dev);
 	const struct typec_device_id *id;
 
+	if (!is_typec_partner_altmode(dev))
+		return 0;
+
 	for (id = drv->id_table; id->svid; id++)
 		if (id->svid == altmode->svid)
 			return 1;
@@ -463,6 +482,9 @@ static int typec_uevent(const struct device *dev, struct kobj_uevent_env *env)
 {
 	const struct typec_altmode *altmode = to_typec_altmode(dev);
 
+	if (!is_typec_partner_altmode(dev))
+		return 0;
+
 	if (add_uevent_var(env, "SVID=%04X", altmode->svid))
 		return -ENOMEM;
 
diff --git a/drivers/usb/typec/bus.h b/drivers/usb/typec/bus.h
index 643b8c81786d..b58e131450d1 100644
--- a/drivers/usb/typec/bus.h
+++ b/drivers/usb/typec/bus.h
@@ -29,8 +29,12 @@ struct altmode {
 #define to_altmode(d) container_of(d, struct altmode, adev)
 
 extern const struct bus_type typec_bus;
-extern const struct device_type typec_altmode_dev_type;
+extern const struct device_type typec_port_altmode_dev_type;
+extern const struct device_type typec_plug_altmode_dev_type;
+extern const struct device_type typec_partner_altmode_dev_type;
 
-#define is_typec_altmode(_dev_) (_dev_->type == &typec_altmode_dev_type)
+#define is_typec_port_altmode(dev) ((dev)->type == &typec_port_altmode_dev_type)
+#define is_typec_plug_altmode(dev) ((dev)->type == &typec_plug_altmode_dev_type)
+#define is_typec_partner_altmode(dev) ((dev)->type == &typec_partner_altmode_dev_type)
 
 #endif /* __USB_TYPEC_ALTMODE_H__ */
diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index 9b2647cb199b..d6b88317f8a4 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -235,7 +235,7 @@ static int altmode_match(struct device *dev, const void *data)
 	struct typec_altmode *adev = to_typec_altmode(dev);
 	const struct typec_device_id *id = data;
 
-	if (!is_typec_altmode(dev))
+	if (!is_typec_port_altmode(dev))
 		return 0;
 
 	return (adev->svid == id->svid);
@@ -532,15 +532,28 @@ static void typec_altmode_release(struct device *dev)
 	kfree(alt);
 }
 
-const struct device_type typec_altmode_dev_type = {
-	.name = "typec_alternate_mode",
+const struct device_type typec_port_altmode_dev_type = {
+	.name = "typec_port_alternate_mode",
+	.groups = typec_altmode_groups,
+	.release = typec_altmode_release,
+};
+
+const struct device_type typec_plug_altmode_dev_type = {
+	.name = "typec_plug_alternate_mode",
+	.groups = typec_altmode_groups,
+	.release = typec_altmode_release,
+};
+
+const struct device_type typec_partner_altmode_dev_type = {
+	.name = "typec_partner_alternate_mode",
 	.groups = typec_altmode_groups,
 	.release = typec_altmode_release,
 };
 
 static struct typec_altmode *
 typec_register_altmode(struct device *parent,
-		       const struct typec_altmode_desc *desc)
+		       const struct typec_altmode_desc *desc,
+		       const struct device_type *type)
 {
 	unsigned int id = altmode_id_get(parent);
 	bool is_port = is_typec_port(parent);
@@ -575,7 +588,7 @@ typec_register_altmode(struct device *parent,
 
 	alt->adev.dev.parent = parent;
 	alt->adev.dev.groups = alt->groups;
-	alt->adev.dev.type = &typec_altmode_dev_type;
+	alt->adev.dev.type = type;
 	dev_set_name(&alt->adev.dev, "%s.%u", dev_name(parent), id);
 
 	get_device(alt->adev.dev.parent);
@@ -584,9 +597,7 @@ typec_register_altmode(struct device *parent,
 	if (!is_port)
 		typec_altmode_set_partner(alt);
 
-	/* The partners are bind to drivers */
-	if (is_typec_partner(parent))
-		alt->adev.dev.bus = &typec_bus;
+	alt->adev.dev.bus = &typec_bus;
 
 	/* Plug alt modes need a class to generate udev events. */
 	if (is_typec_plug(parent))
@@ -963,7 +974,7 @@ struct typec_altmode *
 typec_partner_register_altmode(struct typec_partner *partner,
 			       const struct typec_altmode_desc *desc)
 {
-	return typec_register_altmode(&partner->dev, desc);
+	return typec_register_altmode(&partner->dev, desc, &typec_partner_altmode_dev_type);
 }
 EXPORT_SYMBOL_GPL(typec_partner_register_altmode);
 
@@ -1193,7 +1204,7 @@ struct typec_altmode *
 typec_plug_register_altmode(struct typec_plug *plug,
 			    const struct typec_altmode_desc *desc)
 {
-	return typec_register_altmode(&plug->dev, desc);
+	return typec_register_altmode(&plug->dev, desc, &typec_plug_altmode_dev_type);
 }
 EXPORT_SYMBOL_GPL(typec_plug_register_altmode);
 
@@ -2493,7 +2504,7 @@ typec_port_register_altmode(struct typec_port *port,
 		return ERR_CAST(retimer);
 	}
 
-	adev = typec_register_altmode(&port->dev, desc);
+	adev = typec_register_altmode(&port->dev, desc, &typec_port_altmode_dev_type);
 	if (IS_ERR(adev)) {
 		typec_retimer_put(retimer);
 		typec_mux_put(mux);
-- 
2.51.1



From kernel at airkyi.com  Sun Dec  7 17:54:49 2025
From: kernel at airkyi.com (Chaoyi Chen)
Date: Mon,  8 Dec 2025 09:54:49 +0800
Subject: [PATCH v13 00/11] Add Type-C DP support for RK3399 EVB IND board
Message-ID: <20251208015500.94-1-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

This series focuses on adding Type-C DP support for USBDP PHY and DP
driver. The USBDP PHY and DP will perceive the changes in cable status
based on the USB PD and Type-C state machines provided by TCPM. Before
this, the USBDP PHY and DP controller of RK3399 sensed cable state
changes through extcon, and devices such as the RK3399 Gru-Chromebook
rely on them. This series should not break them.

====
1. DisplayPort HPD status notify

Before v7, I implemented a variety of DP HPD status notify. However,
they all had various problems and it was difficult to become a generic
solution.

Under the guidance of Heikki and Dmitry, a decoupled notification
method between the TypeC and DRM subsystems was introduced in v7.
First, a notification is sent when TypeC registers a new altmode.
Then, a generic DP AUX HPD bridge is implemented on the DRM side.

During v7-v10, we added a new notifier in typec to notify the altmode
device register event. With the help of Greg and Heikki, we implemented
the reuse of notifiers for the type bus itself in patch1 of v11.

That makes it redundant for each Type-C controller driver to implement
a similar DP AUX HPD bridge in embedded scenarios.

====
2. Altmode switching and orientation switching for USBDP PHY

For USB Type-C interfaces, an external Type-C controller chip assists
by detecting cable attachment, determining plug orientation, and
reporting USB PD message. The USB/DP combo PHY supports software
configurable pin mapping and DisplayPort lane assignment. Based on
these message, the combo PHY can perform both altmode switching and
orientation switching via software.

The RK3399 EVB IND board has a Type-C interface DisplayPort. It use
fusb302 chip as Type-C controller. The connection diagram is shown below:

fusb302 chip +---> USB2.0 PHY ----> DWC3 USB controller
             |
             +---> USB/DP PHY0 +--> CDN-DP controller
                               |
                               +--> DWC3 USB controller

====
3. Multiple bridge model for RK3399 CDN-DP

The RK3399 has two USB/DP combo PHY and one CDN-DP controller. And
the CDN-DP can be switched to output to one of the PHYs.

USB/DP PHY0 ---+
               | <----> CDN-DP controller
USB/DP PHY1 ---+

In previous versions, if both PHY ports were connected to DP,
the CDN-DP driver would select the first PHY port for output.

On Dmitry's suggestion, we introduced a multi-bridge model to support
flexible selection of the output PHY port. For each PHY port, a
separate encoder and bridge are registered.

The change is based on the DRM AUX HPD bridge, rather than the
extcon approach. This requires the DT to correctly describe the
connections between the first bridge in bridge chain and DP
controller. And Once the first bridge is obtained, we can get the
last bridge corresponding to the USB-C connector, and then set the
DRM connector's fwnode to the corresponding one to enable HPD
notification.

====
Patch1 set the bus also for the port and plug altmodes.
Patch2 export typec bus and typec altmode device types.
Patch3 add generic USB Type-C DP HPD bridge.
Patch4 add new API drm_aux_bridge_register_from_node().
Patch5 add new Type-C mode switch for RK3399 USBDP phy binding.
Patch6 add typec_mux and typec_switch for RK3399 USBDP PHY.
Patch7 add DRM AUX bridge support for RK3399 USBDP PHY.
Patch8 drops CDN-DP's extcon dependency when Type-C is present.
Patch9 add multiple bridges to support PHY port selection.
Patch10 add missing dp_out port for RK3399 CDN-DP.
Patch11 add Type-C DP support for RK3399 EVB IND board.

Changes in v13:
- Link to V12: https://lore.kernel.org/all/20251204063109.104-1-kernel at airkyi.com/
- Only register drm dp hpd bridge for typec port altmode device.

Changes in v12:
- Link to V11: https://lore.kernel.org/all/20251128020405.90-1-kernel at airkyi.com/
- Add missing Signed-off-by line.

Changes in v11:
- Link to V10: https://lore.kernel.org/all/20251120022343.250-1-kernel at airkyi.com/
- Switch to using typec bus notifiers.

Changes in v10:
- Link to V9: https://lore.kernel.org/all/20251111105040.94-1-kernel at airkyi.com/
- Notify TYPEC_ALTMODE_UNREGISTERED when altmode removed. 
- Add drm_aux_bridge_register_from_node().
- Fix refcount usage of drm_bridge.

Changes in v9:
- Link to V8: https://lore.kernel.org/all/20251029071435.88-1-kernel at airkyi.com/
- Remove the exposed DRM_AUX_HPD_BRIDGE option, and select
DRM_AUX_HPD_TYPEC_BRIDGE when it is available.
- Add usb role switch for Type-C.
- Remove USB2 PHY in Type-C connection.
- ...

Changes in v8:
- Link to V7: https://lore.kernel.org/all/20251023033009.90-1-kernel at airkyi.com/
- Export all typec device types for identification.
- Merge generic DP HPD bridge into one module.
- Fix coding style.

Changes in v7:
- Link to V6: https://lore.kernel.org/all/20251016022741.91-1-kernel at airkyi.com/
- Add notifier functions for Type-C core.
- Add generic USB Type-C DP HPD bridge.

Changes in v6:
- Link to V5: https://lore.kernel.org/all/20251011033233.97-1-kernel at airkyi.com/
- Fix depend in Kconfig.
- Check DP svid in tcphy_typec_mux_set().
- Remove mode setting in tcphy_orien_sw_set().
- Rename some variable names.
- Attach the DP bridge to the next bridge.

Changes in v5:
- Link to V4: https://lore.kernel.org/all/20250922012039.323-1-kernel at airkyi.com/
- Remove the calls related to `drm_aux_hpd_bridge_notify()`.
- Place the helper functions in the same compilation unit.
- Add more comments about parent device.
- Add DRM AUX bridge support for RK3399 USBDP PHY
- By parsing the HPD bridge chain, set the connector's of_node to the
of_node corresponding to the USB-C connector.
- Return EDID cache when other port is already enabled.

Changes in v4:
- Link to V3: https://lore.kernel.org/all/20250729090032.97-1-kernel at airkyi.com/
- Add default HPD device for DisplayPort altmode.
- Introduce multiple bridges for CDN-DP.
- ...

Changes in v3:
- Link to V2: https://lore.kernel.org/all/20250718062619.99-1-kernel at airkyi.com/
- Add more descriptions to clarify the role of the PHY in switching.
- Fix wrong vdo value.
- Fix port node in usb-c-connector.

Changes in v2:
- Link to V1: https://lore.kernel.org/all/20250715112456.101-1-kernel at airkyi.com/
- Reuse dp-port/usb3-port in rk3399-typec-phy binding.
- Fix compile error when CONFIG_TYPEC is not enabled.
- Notify DP HPD state by USB/DP PHY.
- Ignore duplicate HPD events.
- Add endpoint to link DP PHY and DP controller.
- Fix devicetree coding style.

Chaoyi Chen (10):
  usb: typec: Export typec bus and typec altmode device type
  drm/bridge: Implement generic USB Type-C DP HPD bridge
  drm/bridge: aux: Add drm_aux_bridge_register_from_node()
  dt-bindings: phy: rockchip: rk3399-typec-phy: Support mode-switch
  phy: rockchip: phy-rockchip-typec: Add typec_mux/typec_switch support
  phy: rockchip: phy-rockchip-typec: Add DRM AUX bridge
  drm/rockchip: cdn-dp: Support handle lane info without extcon
  drm/rockchip: cdn-dp: Add multiple bridges to support PHY port
    selection
  arm64: dts: rockchip: Add missing dp_out port for RK3399 CDN-DP
  arm64: dts: rockchip: rk3399-evb-ind: Add support for DisplayPort

Heikki Krogerus (1):
  usb: typec: Set the bus also for the port and plug altmodes

 .../phy/rockchip,rk3399-typec-phy.yaml        |   6 +
 arch/arm64/boot/dts/rockchip/rk3399-base.dtsi |  10 +-
 .../boot/dts/rockchip/rk3399-evb-ind.dts      | 147 +++++++
 drivers/gpu/drm/bridge/Kconfig                |  10 +
 drivers/gpu/drm/bridge/Makefile               |   1 +
 drivers/gpu/drm/bridge/aux-bridge.c           |  24 +-
 .../gpu/drm/bridge/aux-hpd-typec-dp-bridge.c  |  49 +++
 drivers/gpu/drm/rockchip/Kconfig              |   1 +
 drivers/gpu/drm/rockchip/cdn-dp-core.c        | 350 +++++++++++++---
 drivers/gpu/drm/rockchip/cdn-dp-core.h        |  18 +-
 drivers/phy/rockchip/Kconfig                  |   3 +
 drivers/phy/rockchip/phy-rockchip-typec.c     | 373 +++++++++++++++++-
 drivers/usb/typec/bus.c                       |  25 +-
 drivers/usb/typec/bus.h                       |   6 -
 drivers/usb/typec/class.c                     |  36 +-
 include/drm/bridge/aux-bridge.h               |   6 +
 include/linux/usb/typec.h                     |   3 +
 include/linux/usb/typec_altmode.h             |   8 +
 18 files changed, 974 insertions(+), 102 deletions(-)
 create mode 100644 drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c

-- 
2.51.1



From kernel at airkyi.com  Sun Dec  7 17:54:53 2025
From: kernel at airkyi.com (Chaoyi Chen)
Date: Mon,  8 Dec 2025 09:54:53 +0800
Subject: [PATCH v13 04/11] drm/bridge: aux: Add drm_aux_bridge_register_from_node()
In-Reply-To: <20251208015500.94-1-kernel@airkyi.com>
References: <20251208015500.94-1-kernel@airkyi.com>
Message-ID: <20251208015500.94-5-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

The drm_aux_bridge_register() uses the device->of_node as the
bridge->of_node.

This patch adds drm_aux_bridge_register_from_node() to allow
specifying the of_node corresponding to the bridge.

Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
Reviewed-by: Neil Armstrong <neil.armstrong at linaro.org>
---

(no changes since v11)

 drivers/gpu/drm/bridge/aux-bridge.c | 24 ++++++++++++++++++++++--
 include/drm/bridge/aux-bridge.h     |  6 ++++++
 2 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/bridge/aux-bridge.c b/drivers/gpu/drm/bridge/aux-bridge.c
index b3e4cdff61d6..52dff4601c2d 100644
--- a/drivers/gpu/drm/bridge/aux-bridge.c
+++ b/drivers/gpu/drm/bridge/aux-bridge.c
@@ -35,6 +35,7 @@ static void drm_aux_bridge_unregister_adev(void *_adev)
 /**
  * drm_aux_bridge_register - Create a simple bridge device to link the chain
  * @parent: device instance providing this bridge
+ * @np: device node pointer corresponding to this bridge instance
  *
  * Creates a simple DRM bridge that doesn't implement any drm_bridge
  * operations. Such bridges merely fill a place in the bridge chain linking
@@ -42,7 +43,7 @@ static void drm_aux_bridge_unregister_adev(void *_adev)
  *
  * Return: zero on success, negative error code on failure
  */
-int drm_aux_bridge_register(struct device *parent)
+int drm_aux_bridge_register_from_node(struct device *parent, struct device_node *np)
 {
 	struct auxiliary_device *adev;
 	int ret;
@@ -62,7 +63,10 @@ int drm_aux_bridge_register(struct device *parent)
 	adev->dev.parent = parent;
 	adev->dev.release = drm_aux_bridge_release;
 
-	device_set_of_node_from_dev(&adev->dev, parent);
+	if (np)
+		device_set_node(&adev->dev, of_fwnode_handle(np));
+	else
+		device_set_of_node_from_dev(&adev->dev, parent);
 
 	ret = auxiliary_device_init(adev);
 	if (ret) {
@@ -80,6 +84,22 @@ int drm_aux_bridge_register(struct device *parent)
 
 	return devm_add_action_or_reset(parent, drm_aux_bridge_unregister_adev, adev);
 }
+EXPORT_SYMBOL_GPL(drm_aux_bridge_register_from_node);
+
+/**
+ * drm_aux_bridge_register - Create a simple bridge device to link the chain
+ * @parent: device instance providing this bridge
+ *
+ * Creates a simple DRM bridge that doesn't implement any drm_bridge
+ * operations. Such bridges merely fill a place in the bridge chain linking
+ * surrounding DRM bridges.
+ *
+ * Return: zero on success, negative error code on failure
+ */
+int drm_aux_bridge_register(struct device *parent)
+{
+	return drm_aux_bridge_register_from_node(parent, NULL);
+}
 EXPORT_SYMBOL_GPL(drm_aux_bridge_register);
 
 struct drm_aux_bridge_data {
diff --git a/include/drm/bridge/aux-bridge.h b/include/drm/bridge/aux-bridge.h
index c2f5a855512f..7dd1f17a1354 100644
--- a/include/drm/bridge/aux-bridge.h
+++ b/include/drm/bridge/aux-bridge.h
@@ -13,11 +13,17 @@ struct auxiliary_device;
 
 #if IS_ENABLED(CONFIG_DRM_AUX_BRIDGE)
 int drm_aux_bridge_register(struct device *parent);
+int drm_aux_bridge_register_from_node(struct device *parent, struct device_node *np);
 #else
 static inline int drm_aux_bridge_register(struct device *parent)
 {
 	return 0;
 }
+
+static inline int drm_aux_bridge_register_from_node(struct device *parent, struct device_node *np)
+{
+	return 0;
+}
 #endif
 
 #if IS_ENABLED(CONFIG_DRM_AUX_HPD_BRIDGE)
-- 
2.51.1



From kernel at airkyi.com  Sun Dec  7 17:54:54 2025
From: kernel at airkyi.com (Chaoyi Chen)
Date: Mon,  8 Dec 2025 09:54:54 +0800
Subject: [PATCH v13 05/11] dt-bindings: phy: rockchip: rk3399-typec-phy: Support mode-switch
In-Reply-To: <20251208015500.94-1-kernel@airkyi.com>
References: <20251208015500.94-1-kernel@airkyi.com>
Message-ID: <20251208015500.94-6-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

The RK3399 SoC integrates two USB/DP combo PHYs, each of which
supports software-configurable pin mapping and DisplayPort lane
assignment. These capabilities enable the PHY itself to handle both
mode switching and orientation switching, based on the Type-C plug
orientation and USB PD negotiation results.

While an external Type-C controller is still required to detect cable
attachment and report USB PD events, the actual mode and orientation
switching is performed internally by the PHY through software
configuration. This allows the PHY to act as a Type-C multiplexer for
both data role and DP altmode configuration.

To reflect this hardware design, this patch introduces a new
"mode-switch" property for the dp-port node in the device tree bindings.
This property indicates that the connected PHY is capable of handling
Type-C mode switching itself.

Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
---

(no changes since v5)

Changes in v4:
- Remove "|" in description.

Changes in v3:
- Add more descriptions to clarify the role of the PHY in switching.

Changes in v2:
- Reuse dp-port/usb3-port in rk3399-typec-phy binding.

 .../devicetree/bindings/phy/rockchip,rk3399-typec-phy.yaml  | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/phy/rockchip,rk3399-typec-phy.yaml b/Documentation/devicetree/bindings/phy/rockchip,rk3399-typec-phy.yaml
index 91c011f68cd0..83ebcde096ea 100644
--- a/Documentation/devicetree/bindings/phy/rockchip,rk3399-typec-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/rockchip,rk3399-typec-phy.yaml
@@ -51,6 +51,12 @@ properties:
       '#phy-cells':
         const: 0
 
+      mode-switch:
+        description:
+          Indicates the PHY can handle altmode switching. In this case,
+          requires an external USB Type-C controller to report USB PD message.
+        type: boolean
+
       port:
         $ref: /schemas/graph.yaml#/properties/port
         description: Connection to USB Type-C connector
-- 
2.51.1



From kernel at airkyi.com  Sun Dec  7 17:54:55 2025
From: kernel at airkyi.com (Chaoyi Chen)
Date: Mon,  8 Dec 2025 09:54:55 +0800
Subject: [PATCH v13 06/11] phy: rockchip: phy-rockchip-typec: Add typec_mux/typec_switch support
In-Reply-To: <20251208015500.94-1-kernel@airkyi.com>
References: <20251208015500.94-1-kernel@airkyi.com>
Message-ID: <20251208015500.94-7-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

This patch add support for Type-C Port Controller Manager. Each PHY
will register typec_mux and typec_switch when external Type-C
controller is present. Type-C events are handled by TCPM without
extcon.

The extcon device should still be supported.

Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
---

(no changes since v7)

Changes in v6:
- Fix depend in Kconfig.
- Check DP svid in tcphy_typec_mux_set().
- Remove mode setting in tcphy_orien_sw_set().

(no changes since v5)

Changes in v4:
- Remove notify DP HPD state by USB/DP PHY.

(no changes since v3)

Changes in v2:
- Fix compile error when CONFIG_TYPEC is not enabled.
- Notify DP HPD state by USB/DP PHY.

 drivers/phy/rockchip/Kconfig              |   1 +
 drivers/phy/rockchip/phy-rockchip-typec.c | 368 +++++++++++++++++++++-
 2 files changed, 353 insertions(+), 16 deletions(-)

diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig
index 14698571b607..db4adc7c53da 100644
--- a/drivers/phy/rockchip/Kconfig
+++ b/drivers/phy/rockchip/Kconfig
@@ -119,6 +119,7 @@ config PHY_ROCKCHIP_SNPS_PCIE3
 config PHY_ROCKCHIP_TYPEC
 	tristate "Rockchip TYPEC PHY Driver"
 	depends on OF && (ARCH_ROCKCHIP || COMPILE_TEST)
+	depends on TYPEC || TYPEC=n
 	select EXTCON
 	select GENERIC_PHY
 	select RESET_CONTROLLER
diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c
index d9701b6106d5..1f5b4142cbe4 100644
--- a/drivers/phy/rockchip/phy-rockchip-typec.c
+++ b/drivers/phy/rockchip/phy-rockchip-typec.c
@@ -54,6 +54,8 @@
 
 #include <linux/mfd/syscon.h>
 #include <linux/phy/phy.h>
+#include <linux/usb/typec_dp.h>
+#include <linux/usb/typec_mux.h>
 
 #define CMN_SSM_BANDGAP			(0x21 << 2)
 #define CMN_SSM_BIAS			(0x22 << 2)
@@ -286,12 +288,23 @@
 #define RX_DIAG_SC2C_DELAY		(0x81e1 << 2)
 
 #define PMA_LANE_CFG			(0xc000 << 2)
+#define PMA_LANE3_DP_LANE_SEL(x)	(((x) & 0x3) << 14)
+#define PMA_LANE3_INTERFACE_SEL(x)	(((x) & 0x1) << 12)
+#define PMA_LANE2_DP_LANE_SEL(x)	(((x) & 0x3) << 10)
+#define PMA_LANE2_INTERFACE_SEL(x)	(((x) & 0x1) << 8)
+#define PMA_LANE1_DP_LANE_SEL(x)	(((x) & 0x3) << 6)
+#define PMA_LANE1_INTERFACE_SEL(x)	(((x) & 0x1) << 4)
+#define PMA_LANE0_DP_LANE_SEL(x)	(((x) & 0x3) << 2)
+#define PMA_LANE0_INTERFACE_SEL(x)	(((x) & 0x1) << 0)
 #define PIPE_CMN_CTRL1			(0xc001 << 2)
 #define PIPE_CMN_CTRL2			(0xc002 << 2)
 #define PIPE_COM_LOCK_CFG1		(0xc003 << 2)
 #define PIPE_COM_LOCK_CFG2		(0xc004 << 2)
 #define PIPE_RCV_DET_INH		(0xc005 << 2)
 #define DP_MODE_CTL			(0xc008 << 2)
+#define PHY_DP_POWER_STATE_ACK_MASK	GENMASK(7, 4)
+#define PHY_DP_POWER_STATE_ACK_SHIFT	4
+#define PHY_DP_POWER_STATE_MASK		GENMASK(3, 0)
 #define DP_CLK_CTL			(0xc009 << 2)
 #define STS				(0xc00F << 2)
 #define PHY_ISO_CMN_CTRL		(0xc010 << 2)
@@ -327,8 +340,15 @@
 
 #define DP_MODE_A0			BIT(4)
 #define DP_MODE_A2			BIT(6)
-#define DP_MODE_ENTER_A0		0xc101
-#define DP_MODE_ENTER_A2		0xc104
+
+#define DP_MODE_MASK			0xf
+#define DP_MODE_ENTER_A0		BIT(0)
+#define DP_MODE_ENTER_A2		BIT(2)
+#define DP_MODE_ENTER_A3		BIT(3)
+#define DP_MODE_A0_ACK			BIT(4)
+#define DP_MODE_A2_ACK			BIT(6)
+#define DP_MODE_A3_ACK			BIT(7)
+#define DP_LINK_RESET_DEASSERTED	BIT(8)
 
 #define PHY_MODE_SET_TIMEOUT		100000
 
@@ -340,6 +360,31 @@
 #define MODE_DFP_USB			BIT(1)
 #define MODE_DFP_DP			BIT(2)
 
+enum phy_dp_lane_num {
+	PHY_DP_LANE_0 = 0,
+	PHY_DP_LANE_1,
+	PHY_DP_LANE_2,
+	PHY_DP_LANE_3,
+};
+
+enum phy_pma_if {
+	PMA_IF_PIPE_PCS = 0,
+	PMA_IF_PHY_DP,
+};
+
+enum phy_typec_role {
+	TYPEC_PHY_USB = 0,
+	TYPEC_PHY_DP,
+	TYPEC_PHY_MAX,
+};
+
+enum phy_dp_power_state {
+	PHY_DP_POWER_STATE_A0 = 0,
+	PHY_DP_POWER_STATE_A1,
+	PHY_DP_POWER_STATE_A2,
+	PHY_DP_POWER_STATE_A3,
+};
+
 struct usb3phy_reg {
 	u32 offset;
 	u32 enable_bit;
@@ -372,18 +417,22 @@ struct rockchip_typec_phy {
 	struct device *dev;
 	void __iomem *base;
 	struct extcon_dev *extcon;
+	struct typec_mux_dev *mux;
+	struct typec_switch_dev *sw;
 	struct regmap *grf_regs;
 	struct clk *clk_core;
 	struct clk *clk_ref;
 	struct reset_control *uphy_rst;
 	struct reset_control *pipe_rst;
 	struct reset_control *tcphy_rst;
+	struct phy *phys[TYPEC_PHY_MAX];
 	const struct rockchip_usb3phy_port_cfg *port_cfgs;
 	/* mutex to protect access to individual PHYs */
 	struct mutex lock;
 
 	bool flip;
 	u8 mode;
+	u8 new_mode;
 };
 
 struct phy_reg {
@@ -454,6 +503,99 @@ static const struct rockchip_usb3phy_port_cfg rk3399_usb3phy_port_cfgs[] = {
 	{ /* sentinel */ }
 };
 
+static int tcphy_cfg_usb3_to_usb2_only(struct rockchip_typec_phy *tcphy,
+				       bool value);
+
+static int tcphy_dp_set_power_state(struct rockchip_typec_phy *tcphy,
+				    enum phy_dp_power_state state)
+{
+	u32 ack, reg, sts = BIT(state);
+	int ret;
+
+	/*
+	 * Power state changes must not be requested until after the cmn_ready
+	 * signal has gone active.
+	 */
+	reg = readl(tcphy->base + PMA_CMN_CTRL1);
+	if (!(reg & CMN_READY)) {
+		dev_err(tcphy->dev, "cmn_ready in the inactive state\n");
+		return -EINVAL;
+	}
+
+	reg = readl(tcphy->base + DP_MODE_CTL);
+	reg &= ~PHY_DP_POWER_STATE_MASK;
+	reg |= sts;
+	writel(reg, tcphy->base + DP_MODE_CTL);
+
+	ret = readl_poll_timeout(tcphy->base + DP_MODE_CTL,
+				 ack, (((ack & PHY_DP_POWER_STATE_ACK_MASK) >>
+				 PHY_DP_POWER_STATE_ACK_SHIFT) == sts), 10,
+				 PHY_MODE_SET_TIMEOUT);
+	if (ret < 0) {
+		dev_err(tcphy->dev, "failed to enter power state %d\n", state);
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+ * For the TypeC PHY, the 4 lanes are mapping to the USB TypeC receptacle pins
+ * as follows:
+ *   -------------------------------------------------------------------
+ *	PHY Lanes/Module Pins			TypeC Receptacle Pins
+ *   -------------------------------------------------------------------
+ *	Lane0 (tx_p/m_ln_0)			TX1+/TX1- (pins A2/A3)
+ *	Lane1 (tx_rx_p/m_ln_1)			RX1+/RX1- (pins B11/B10)
+ *	Lane2 (tx_rx_p/m_ln_2)			RX2+/RX2- (pins A11/A10)
+ *	Lane3 (tx_p/m_ln_3)			TX2+/TX2- (pins B2/B3)
+ *   -------------------------------------------------------------------
+ *
+ * USB and DP lanes mapping to TypeC PHY lanes for each of pin assignment
+ * options (normal connector orientation) described in the VESA DisplayPort
+ * Alt Mode on USB TypeC Standard as follows:
+ *
+ * ----------------------------------------------------------------------
+ *	PHY Lanes	A	B	C	D	E	F
+ * ----------------------------------------------------------------------
+ *	  0	       ML1     SSTX    ML2     SSTX    ML2     SSTX
+ *	  1	       ML3     SSRX    ML3     SSRX    ML3     SSRX
+ *	  2	       ML2     ML1     ML0     ML0     ML0     ML0
+ *	  3	       ML0     ML0     ML1     ML1     ML1     ML1
+ * ----------------------------------------------------------------------
+ */
+static void tcphy_set_lane_mapping(struct rockchip_typec_phy *tcphy, u8 mode)
+{
+	/*
+	 * The PMA_LANE_CFG register is used to select whether a PMA lane
+	 * is mapped for USB or PHY DP. The PMA_LANE_CFG register is
+	 * configured based on a normal connector orientation. Logic in the
+	 * PHY automatically handles the flipped connector case based on the
+	 * setting of orientation of TypeC PHY.
+	 */
+	if (mode == MODE_DFP_DP) {
+		/* This maps to VESA DP Alt Mode pin assignments C and E. */
+		writel(PMA_LANE3_DP_LANE_SEL(PHY_DP_LANE_1) |
+		       PMA_LANE3_INTERFACE_SEL(PMA_IF_PHY_DP) |
+		       PMA_LANE2_DP_LANE_SEL(PHY_DP_LANE_0) |
+		       PMA_LANE2_INTERFACE_SEL(PMA_IF_PHY_DP) |
+		       PMA_LANE1_DP_LANE_SEL(PHY_DP_LANE_3) |
+		       PMA_LANE1_INTERFACE_SEL(PMA_IF_PHY_DP) |
+		       PMA_LANE0_DP_LANE_SEL(PHY_DP_LANE_2) |
+		       PMA_LANE0_INTERFACE_SEL(PMA_IF_PHY_DP),
+		       tcphy->base + PMA_LANE_CFG);
+	} else {
+		/* This maps to VESA DP Alt Mode pin assignments D and F. */
+		writel(PMA_LANE3_DP_LANE_SEL(PHY_DP_LANE_1) |
+		       PMA_LANE3_INTERFACE_SEL(PMA_IF_PHY_DP) |
+		       PMA_LANE2_DP_LANE_SEL(PHY_DP_LANE_0) |
+		       PMA_LANE2_INTERFACE_SEL(PMA_IF_PHY_DP) |
+		       PMA_LANE1_INTERFACE_SEL(PMA_IF_PIPE_PCS) |
+		       PMA_LANE0_INTERFACE_SEL(PMA_IF_PIPE_PCS),
+		       tcphy->base + PMA_LANE_CFG);
+	}
+}
+
 static void tcphy_cfg_24m(struct rockchip_typec_phy *tcphy)
 {
 	u32 i, rdata;
@@ -743,8 +885,10 @@ static int tcphy_phy_init(struct rockchip_typec_phy *tcphy, u8 mode)
 	tcphy_dp_aux_set_flip(tcphy);
 
 	tcphy_cfg_24m(tcphy);
+	tcphy_set_lane_mapping(tcphy, mode);
 
 	if (mode == MODE_DFP_DP) {
+		tcphy_cfg_usb3_to_usb2_only(tcphy, true);
 		tcphy_cfg_dp_pll(tcphy);
 		for (i = 0; i < 4; i++)
 			tcphy_dp_cfg_lane(tcphy, i);
@@ -768,7 +912,10 @@ static int tcphy_phy_init(struct rockchip_typec_phy *tcphy, u8 mode)
 		writel(PIN_ASSIGN_D_F, tcphy->base + PMA_LANE_CFG);
 	}
 
-	writel(DP_MODE_ENTER_A2, tcphy->base + DP_MODE_CTL);
+	val = readl(tcphy->base + DP_MODE_CTL);
+	val &= ~DP_MODE_MASK;
+	val |= DP_MODE_ENTER_A2 | DP_LINK_RESET_DEASSERTED;
+	writel(val, tcphy->base + DP_MODE_CTL);
 
 	reset_control_deassert(tcphy->uphy_rst);
 
@@ -811,8 +958,9 @@ static int tcphy_get_mode(struct rockchip_typec_phy *tcphy)
 	u8 mode;
 	int ret, ufp, dp;
 
+	/* If extcon not exist, try to use tcpm mode */
 	if (!edev)
-		return MODE_DFP_USB;
+		return tcphy->new_mode;
 
 	ufp = extcon_get_state(edev, EXTCON_USB);
 	dp = extcon_get_state(edev, EXTCON_DISP_DP);
@@ -850,6 +998,71 @@ static int tcphy_get_mode(struct rockchip_typec_phy *tcphy)
 	return mode;
 }
 
+#if IS_ENABLED(CONFIG_TYPEC)
+static int tcphy_orien_sw_set(struct typec_switch_dev *sw,
+			      enum typec_orientation orien)
+{
+	struct rockchip_typec_phy *tcphy = typec_switch_get_drvdata(sw);
+
+	mutex_lock(&tcphy->lock);
+
+	if (orien == TYPEC_ORIENTATION_NONE) {
+		tcphy->new_mode = MODE_DISCONNECT;
+		goto unlock_ret;
+	}
+
+	tcphy->flip = (orien == TYPEC_ORIENTATION_REVERSE) ? true : false;
+
+unlock_ret:
+	mutex_unlock(&tcphy->lock);
+	return 0;
+}
+
+static void udphy_orien_switch_unregister(void *data)
+{
+	struct rockchip_typec_phy *tcphy = data;
+
+	typec_switch_unregister(tcphy->sw);
+}
+
+static int tcphy_setup_orien_switch(struct rockchip_typec_phy *tcphy)
+{
+	struct typec_switch_desc sw_desc = { };
+	struct device_node *np;
+	int ret = 0;
+
+	np = of_get_child_by_name(tcphy->dev->of_node, "usb3-port");
+	if (!np)
+		return 0;
+
+	if (!of_property_read_bool(np, "orientation-switch"))
+		goto put_np;
+
+	sw_desc.drvdata = tcphy;
+	sw_desc.fwnode = device_get_named_child_node(tcphy->dev, "usb3-port");
+	sw_desc.set = tcphy_orien_sw_set;
+
+	tcphy->sw = typec_switch_register(tcphy->dev, &sw_desc);
+	if (IS_ERR(tcphy->sw)) {
+		dev_err(tcphy->dev, "Error register typec orientation switch: %ld\n",
+			PTR_ERR(tcphy->sw));
+		ret = PTR_ERR(tcphy->sw);
+		goto put_np;
+	}
+
+	ret = devm_add_action_or_reset(tcphy->dev, udphy_orien_switch_unregister, tcphy);
+
+put_np:
+	of_node_put(np);
+	return ret;
+}
+#else
+static int tcphy_setup_orien_switch(struct rockchip_typec_phy *tcphy)
+{
+	return 0;
+}
+#endif
+
 static int tcphy_cfg_usb3_to_usb2_only(struct rockchip_typec_phy *tcphy,
 				       bool value)
 {
@@ -989,14 +1202,9 @@ static int rockchip_dp_phy_power_on(struct phy *phy)
 
 	tcphy_dp_aux_calibration(tcphy);
 
-	writel(DP_MODE_ENTER_A0, tcphy->base + DP_MODE_CTL);
-
-	ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL,
-				 val, val & DP_MODE_A0, 1000,
-				 PHY_MODE_SET_TIMEOUT);
-	if (ret < 0) {
-		writel(DP_MODE_ENTER_A2, tcphy->base + DP_MODE_CTL);
-		dev_err(tcphy->dev, "failed to wait TCPHY enter A0\n");
+	ret = tcphy_dp_set_power_state(tcphy, PHY_DP_POWER_STATE_A0);
+	if (ret) {
+		dev_err(tcphy->dev, "failed to enter A0 power state\n");
 		goto power_on_finish;
 	}
 
@@ -1013,6 +1221,7 @@ static int rockchip_dp_phy_power_on(struct phy *phy)
 static int rockchip_dp_phy_power_off(struct phy *phy)
 {
 	struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy);
+	int ret;
 
 	mutex_lock(&tcphy->lock);
 
@@ -1021,7 +1230,11 @@ static int rockchip_dp_phy_power_off(struct phy *phy)
 
 	tcphy->mode &= ~MODE_DFP_DP;
 
-	writel(DP_MODE_ENTER_A2, tcphy->base + DP_MODE_CTL);
+	ret = tcphy_dp_set_power_state(tcphy, PHY_DP_POWER_STATE_A2);
+	if (ret) {
+		dev_err(tcphy->dev, "failed to enter A2 power state\n");
+		goto unlock;
+	}
 
 	if (tcphy->mode == MODE_DISCONNECT)
 		tcphy_phy_deinit(tcphy);
@@ -1037,6 +1250,93 @@ static const struct phy_ops rockchip_dp_phy_ops = {
 	.owner		= THIS_MODULE,
 };
 
+#if IS_ENABLED(CONFIG_TYPEC)
+static int tcphy_typec_mux_set(struct typec_mux_dev *mux, struct typec_mux_state *state)
+{
+	struct rockchip_typec_phy *tcphy = typec_mux_get_drvdata(mux);
+	struct typec_displayport_data *data;
+	int hpd = 0;
+
+	mutex_lock(&tcphy->lock);
+
+	switch (state->mode) {
+	case TYPEC_STATE_SAFE:
+		fallthrough;
+	case TYPEC_STATE_USB:
+		tcphy->new_mode = MODE_DFP_USB;
+		phy_set_bus_width(tcphy->phys[TYPEC_PHY_DP], 0);
+		break;
+	case TYPEC_DP_STATE_C:
+	case TYPEC_DP_STATE_E:
+		if (state->alt->svid != USB_TYPEC_DP_SID)
+			break;
+		tcphy->new_mode = MODE_DFP_DP;
+		data = state->data;
+		hpd = !!(data->status & DP_STATUS_HPD_STATE);
+		phy_set_bus_width(tcphy->phys[TYPEC_PHY_DP], hpd ? 4 : 0);
+		break;
+	case TYPEC_DP_STATE_D:
+		if (state->alt->svid != USB_TYPEC_DP_SID)
+			break;
+		tcphy->new_mode = MODE_DFP_DP | MODE_DFP_USB;
+		data = state->data;
+		hpd = !!(data->status & DP_STATUS_HPD_STATE);
+		phy_set_bus_width(tcphy->phys[TYPEC_PHY_DP], hpd ? 2 : 0);
+		break;
+	default:
+		break;
+	}
+
+	mutex_unlock(&tcphy->lock);
+
+	return 0;
+}
+
+static void tcphy_typec_mux_unregister(void *data)
+{
+	struct rockchip_typec_phy *tcphy = data;
+
+	typec_mux_unregister(tcphy->mux);
+}
+
+static int tcphy_setup_typec_mux(struct rockchip_typec_phy *tcphy)
+{
+	struct typec_mux_desc mux_desc = {};
+	struct device_node *np;
+	int ret = 0;
+
+	np = of_get_child_by_name(tcphy->dev->of_node, "dp-port");
+	if (!np)
+		return 0;
+
+	if (!of_property_read_bool(np, "mode-switch"))
+		goto put_np;
+
+	mux_desc.drvdata = tcphy;
+	mux_desc.fwnode = device_get_named_child_node(tcphy->dev, "dp-port");
+	mux_desc.set = tcphy_typec_mux_set;
+
+	tcphy->mux = typec_mux_register(tcphy->dev, &mux_desc);
+	if (IS_ERR(tcphy->mux)) {
+		dev_err(tcphy->dev, "Error register typec mux: %ld\n",
+			PTR_ERR(tcphy->mux));
+		ret = PTR_ERR(tcphy->mux);
+		goto put_np;
+	}
+
+	ret = devm_add_action_or_reset(tcphy->dev, tcphy_typec_mux_unregister, tcphy);
+
+put_np:
+	of_node_put(np);
+	return ret;
+}
+#else
+static int tcphy_setup_typec_mux(struct rockchip_typec_phy *tcphy)
+{
+	return 0;
+}
+#endif
+
 static int tcphy_parse_dt(struct rockchip_typec_phy *tcphy,
 			  struct device *dev)
 {
@@ -1095,6 +1395,25 @@ static void typec_phy_pre_init(struct rockchip_typec_phy *tcphy)
 	tcphy->mode = MODE_DISCONNECT;
 }
 
+static int typec_dp_lane_get(struct rockchip_typec_phy *tcphy)
+{
+	int dp_lanes;
+
+	switch (tcphy->new_mode) {
+	case MODE_DFP_DP:
+		dp_lanes = 4;
+		break;
+	case MODE_DFP_DP | MODE_DFP_USB:
+		dp_lanes = 2;
+		break;
+	default:
+		dp_lanes = 0;
+		break;
+	}
+
+	return dp_lanes;
+}
+
 static int rockchip_typec_phy_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -1142,6 +1461,7 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev)
 		return ret;
 
 	tcphy->dev = dev;
+	tcphy->new_mode = MODE_DFP_USB;
 	platform_set_drvdata(pdev, tcphy);
 	mutex_init(&tcphy->lock);
 
@@ -1151,6 +1471,7 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev)
 	if (IS_ERR(tcphy->extcon)) {
 		if (PTR_ERR(tcphy->extcon) == -ENODEV) {
 			tcphy->extcon = NULL;
+			dev_info(dev, "extcon not exist, try to use typec mux\n");
 		} else {
 			if (PTR_ERR(tcphy->extcon) != -EPROBE_DEFER)
 				dev_err(dev, "Invalid or missing extcon\n");
@@ -1158,19 +1479,34 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev)
 		}
 	}
 
+	ret = tcphy_setup_orien_switch(tcphy);
+	if (ret)
+		return ret;
+
+	ret = tcphy_setup_typec_mux(tcphy);
+	if (ret)
+		return ret;
+
 	pm_runtime_enable(dev);
 
 	for_each_available_child_of_node(np, child_np) {
 		struct phy *phy;
 
-		if (of_node_name_eq(child_np, "dp-port"))
+		if (of_node_name_eq(child_np, "dp-port")) {
 			phy = devm_phy_create(dev, child_np,
 					      &rockchip_dp_phy_ops);
-		else if (of_node_name_eq(child_np, "usb3-port"))
+			if (!IS_ERR(phy)) {
+				tcphy->phys[TYPEC_PHY_DP] = phy;
+				phy_set_bus_width(phy, typec_dp_lane_get(tcphy));
+			}
+		} else if (of_node_name_eq(child_np, "usb3-port")) {
 			phy = devm_phy_create(dev, child_np,
 					      &rockchip_usb3_phy_ops);
-		else
+			if (!IS_ERR(phy))
+				tcphy->phys[TYPEC_PHY_USB] = phy;
+		} else {
 			continue;
+		}
 
 		if (IS_ERR(phy)) {
 			dev_err(dev, "failed to create phy: %pOFn\n",
-- 
2.51.1



From kernel at airkyi.com  Sun Dec  7 17:54:56 2025
From: kernel at airkyi.com (Chaoyi Chen)
Date: Mon,  8 Dec 2025 09:54:56 +0800
Subject: [PATCH v13 07/11] phy: rockchip: phy-rockchip-typec: Add DRM AUX bridge
In-Reply-To: <20251208015500.94-1-kernel@airkyi.com>
References: <20251208015500.94-1-kernel@airkyi.com>
Message-ID: <20251208015500.94-8-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

Using the DRM_AUX_BRIDGE helper to create the transparent DRM bridge
device.

Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
Reviewed-by: Neil Armstrong <neil.armstrong at linaro.org>
---

(no changes since v11)

Changes in v10:
- Use drm_aux_bridge_register_from_node() instead.

(no changes since v7)

Changes in v6:
- Fix depend in Kconfig.

 drivers/phy/rockchip/Kconfig              | 2 ++
 drivers/phy/rockchip/phy-rockchip-typec.c | 5 +++++
 2 files changed, 7 insertions(+)

diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig
index db4adc7c53da..bcb5476222fc 100644
--- a/drivers/phy/rockchip/Kconfig
+++ b/drivers/phy/rockchip/Kconfig
@@ -120,6 +120,8 @@ config PHY_ROCKCHIP_TYPEC
 	tristate "Rockchip TYPEC PHY Driver"
 	depends on OF && (ARCH_ROCKCHIP || COMPILE_TEST)
 	depends on TYPEC || TYPEC=n
+	depends on DRM || DRM=n
+	select DRM_AUX_BRIDGE if DRM_BRIDGE
 	select EXTCON
 	select GENERIC_PHY
 	select RESET_CONTROLLER
diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c
index 1f5b4142cbe4..e31b778c3537 100644
--- a/drivers/phy/rockchip/phy-rockchip-typec.c
+++ b/drivers/phy/rockchip/phy-rockchip-typec.c
@@ -56,6 +56,7 @@
 #include <linux/phy/phy.h>
 #include <linux/usb/typec_dp.h>
 #include <linux/usb/typec_mux.h>
+#include <drm/bridge/aux-bridge.h>
 
 #define CMN_SSM_BANDGAP			(0x21 << 2)
 #define CMN_SSM_BIAS			(0x22 << 2)
@@ -1312,6 +1313,10 @@ static int tcphy_setup_typec_mux(struct rockchip_typec_phy *tcphy)
 	if (!of_property_read_bool(np, "mode-switch"))
 		goto put_np;
 
+	ret = drm_aux_bridge_register_from_node(tcphy->dev, np);
+	if (ret)
+		goto put_np;
+
 	mux_desc.drvdata = tcphy;
 	mux_desc.fwnode = device_get_named_child_node(tcphy->dev, "dp-port");
 	mux_desc.set = tcphy_typec_mux_set;
-- 
2.51.1



From kernel at airkyi.com  Sun Dec  7 17:54:58 2025
From: kernel at airkyi.com (Chaoyi Chen)
Date: Mon,  8 Dec 2025 09:54:58 +0800
Subject: [PATCH v13 09/11] drm/rockchip: cdn-dp: Add multiple bridges to support PHY port selection
In-Reply-To: <20251208015500.94-1-kernel@airkyi.com>
References: <20251208015500.94-1-kernel@airkyi.com>
Message-ID: <20251208015500.94-10-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

The RK3399 has two USB/DP combo PHY and one CDN-DP controller. And
the CDN-DP can be switched to output to one of the PHYs. If both ports
are plugged into DP, DP will select the first port for output.

This patch adds support for multiple bridges, enabling users to flexibly
select the output port. For each PHY port, a separate encoder and bridge
are registered.

The change is based on the DRM AUX HPD bridge, rather than the
extcon approach. This requires the DT to correctly describe the
connections between the first bridge in bridge chain and DP
controller. For example, the bridge chain may be like this:

PHY aux birdge -> fsa4480 analog audio switch bridge ->
onnn,nb7vpq904m USB reminder bridge -> USB-C controller AUX HPD bridge

In this case, the connection relationships among the PHY aux bridge
and the DP contorller need to be described in DT.

In addition, the cdn_dp_parse_next_bridge_dt() will parses it and
determines whether to register one or two bridges.

Since there is only one DP controller, only one of the PHY ports can
output at a time. The key is how to switch between different PHYs,
which is handled by cdn_dp_switch_port() and cdn_dp_enable().

There are two cases:

1. Neither bridge is enabled. In this case, both bridges can
independently read the EDID, and the PHY port may switch before
reading the EDID.

2. One bridge is already enabled. In this case, other bridges are not
allowed to read the EDID. So we will try to return the cached EDID.

Since the scenario of two ports plug in at the same time is rare,
I don't have a board which support two TypeC connector to test this.
Therefore, I tested forced switching on a single PHY port, as well as
output using a fake PHY port alongside a real PHY port.

Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
---

(no changes since v11)

Changes in v10:
- Fix refcount usage of drm_bridge.
- Remove unused cdn_dp_next_bridge type.

Changes in v9:
- Select DRM_AUX_HPD_BRIDGE when using DP driver.

(no changes since v7)

Changes in v6:
- Rename some variable names.
- Attach the DP bridge to the next bridge.

Changes in v5:
- By parsing the HPD bridge chain, set the connector's of_node to the
of_node corresponding to the USB-C connector.
- Return EDID cache when other port is already enabled.

 drivers/gpu/drm/rockchip/Kconfig       |   1 +
 drivers/gpu/drm/rockchip/cdn-dp-core.c | 325 ++++++++++++++++++++-----
 drivers/gpu/drm/rockchip/cdn-dp-core.h |  18 +-
 3 files changed, 287 insertions(+), 57 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index b7b025814e72..10d9f29a3d44 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -56,6 +56,7 @@ config ROCKCHIP_CDN_DP
 	select DRM_DISPLAY_HELPER
 	select DRM_BRIDGE_CONNECTOR
 	select DRM_DISPLAY_DP_HELPER
+	select DRM_AUX_HPD_BRIDGE
 	help
 	  This selects support for Rockchip SoC specific extensions
 	  for the cdn DP driver. If you want to enable Dp on
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
index 1e27301584a4..0bc3d248c266 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
@@ -27,16 +27,17 @@
 #include "cdn-dp-core.h"
 #include "cdn-dp-reg.h"
 
-static inline struct cdn_dp_device *bridge_to_dp(struct drm_bridge *bridge)
+static int cdn_dp_switch_port(struct cdn_dp_device *dp, struct cdn_dp_port *prev_port,
+			      struct cdn_dp_port *port);
+
+static inline struct cdn_dp_bridge *bridge_to_dp_bridge(struct drm_bridge *bridge)
 {
-	return container_of(bridge, struct cdn_dp_device, bridge);
+	return container_of(bridge, struct cdn_dp_bridge, bridge);
 }
 
-static inline struct cdn_dp_device *encoder_to_dp(struct drm_encoder *encoder)
+static inline struct cdn_dp_device *bridge_to_dp(struct drm_bridge *bridge)
 {
-	struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
-
-	return container_of(rkencoder, struct cdn_dp_device, encoder);
+	return bridge_to_dp_bridge(bridge)->parent;
 }
 
 #define GRF_SOC_CON9		0x6224
@@ -191,14 +192,27 @@ static int cdn_dp_get_sink_count(struct cdn_dp_device *dp, u8 *sink_count)
 static struct cdn_dp_port *cdn_dp_connected_port(struct cdn_dp_device *dp)
 {
 	struct cdn_dp_port *port;
-	int i, lanes;
+	int i, lanes[MAX_PHY];
 
 	for (i = 0; i < dp->ports; i++) {
 		port = dp->port[i];
-		lanes = cdn_dp_get_port_lanes(port);
-		if (lanes)
+		lanes[i] = cdn_dp_get_port_lanes(port);
+		if (!dp->next_bridge_valid)
 			return port;
 	}
+
+	if (dp->next_bridge_valid) {
+		/* If more than one port is available, pick the last active port */
+		if (dp->active_port > 0 && lanes[dp->active_port])
+			return dp->port[dp->active_port];
+
+		/* If the last active port is not available, pick an available port in order */
+		for (i = 0; i < dp->bridge_count; i++) {
+			if (lanes[i])
+				return dp->port[i];
+		}
+	}
+
 	return NULL;
 }
 
@@ -253,12 +267,45 @@ static const struct drm_edid *
 cdn_dp_bridge_edid_read(struct drm_bridge *bridge, struct drm_connector *connector)
 {
 	struct cdn_dp_device *dp = bridge_to_dp(bridge);
-	const struct drm_edid *drm_edid;
+	struct cdn_dp_bridge *dp_bridge = bridge_to_dp_bridge(bridge);
+	struct cdn_dp_port *port = dp->port[dp_bridge->id];
+	struct cdn_dp_port *prev_port;
+	const struct drm_edid *drm_edid = NULL;
+	int i, ret;
 
 	mutex_lock(&dp->lock);
+
+	/* More than one port is available */
+	if (dp->bridge_count > 1 && !port->phy_enabled) {
+		for (i = 0; i < dp->bridge_count; i++) {
+			/* Another port already enable */
+			if (dp->bridge_list[i] != dp_bridge && dp->bridge_list[i]->enabled)
+				goto get_cache;
+			/* Find already enabled port */
+			if (dp->port[i]->phy_enabled)
+				prev_port = dp->port[i];
+		}
+
+		/* Switch to current port */
+		if (prev_port) {
+			ret = cdn_dp_switch_port(dp, prev_port, port);
+			if (ret)
+				goto get_cache;
+		}
+	}
+
 	drm_edid = drm_edid_read_custom(connector, cdn_dp_get_edid_block, dp);
+	/* replace edid cache */
+	if (dp->edid_cache[dp_bridge->id])
+		drm_edid_free(dp->edid_cache[dp_bridge->id]);
+	dp->edid_cache[dp_bridge->id] = drm_edid_dup(drm_edid);
+
 	mutex_unlock(&dp->lock);
+	return drm_edid;
 
+get_cache:
+	drm_edid = drm_edid_dup(dp->edid_cache[dp_bridge->id]);
+	mutex_unlock(&dp->lock);
 	return drm_edid;
 }
 
@@ -267,12 +314,13 @@ cdn_dp_bridge_mode_valid(struct drm_bridge *bridge,
 			 const struct drm_display_info *display_info,
 			 const struct drm_display_mode *mode)
 {
+	struct cdn_dp_bridge *dp_bridge = bridge_to_dp_bridge(bridge);
 	struct cdn_dp_device *dp = bridge_to_dp(bridge);
 	u32 requested, actual, rate, sink_max, source_max = 0;
 	u8 lanes, bpc;
 
 	/* If DP is disconnected, every mode is invalid */
-	if (!dp->connected)
+	if (!dp_bridge->connected || !dp->connected)
 		return MODE_BAD;
 
 	switch (display_info->bpc) {
@@ -550,6 +598,54 @@ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp)
 	return drm_dp_channel_eq_ok(link_status, min(port->lanes, sink_lanes));
 }
 
+static int cdn_dp_switch_port(struct cdn_dp_device *dp, struct cdn_dp_port *prev_port,
+			      struct cdn_dp_port *port)
+{
+	int ret;
+
+	if (dp->active)
+		return 0;
+
+	ret = cdn_dp_disable_phy(dp, prev_port);
+	if (ret)
+		goto out;
+	ret = cdn_dp_enable_phy(dp, port);
+	if (ret)
+		goto out;
+
+	ret = cdn_dp_get_sink_capability(dp);
+	if (ret) {
+		cdn_dp_disable_phy(dp, port);
+		goto out;
+	}
+
+	dp->active = true;
+	dp->lanes = port->lanes;
+
+	if (!cdn_dp_check_link_status(dp)) {
+		dev_info(dp->dev, "Connected with sink; re-train link\n");
+
+		ret = cdn_dp_train_link(dp);
+		if (ret) {
+			dev_err(dp->dev, "Training link failed: %d\n", ret);
+			goto out;
+		}
+
+		ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE);
+		if (ret) {
+			dev_err(dp->dev, "Failed to idle video %d\n", ret);
+			goto out;
+		}
+
+		ret = cdn_dp_config_video(dp);
+		if (ret)
+			dev_err(dp->dev, "Failed to configure video: %d\n", ret);
+	}
+
+out:
+	return ret;
+}
+
 static void cdn_dp_display_info_update(struct cdn_dp_device *dp,
 				       struct drm_display_info *display_info)
 {
@@ -571,6 +667,7 @@ static void cdn_dp_display_info_update(struct cdn_dp_device *dp,
 static void cdn_dp_bridge_atomic_enable(struct drm_bridge *bridge, struct drm_atomic_state *state)
 {
 	struct cdn_dp_device *dp = bridge_to_dp(bridge);
+	struct cdn_dp_bridge *dp_bridge = bridge_to_dp_bridge(bridge);
 	struct drm_connector *connector;
 	int ret, val;
 
@@ -580,7 +677,7 @@ static void cdn_dp_bridge_atomic_enable(struct drm_bridge *bridge, struct drm_at
 
 	cdn_dp_display_info_update(dp, &connector->display_info);
 
-	ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, &dp->encoder.encoder);
+	ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, &dp_bridge->encoder.encoder);
 	if (ret < 0) {
 		DRM_DEV_ERROR(dp->dev, "Could not get vop id, %d", ret);
 		return;
@@ -599,6 +696,9 @@ static void cdn_dp_bridge_atomic_enable(struct drm_bridge *bridge, struct drm_at
 
 	mutex_lock(&dp->lock);
 
+	if (dp->next_bridge_valid)
+		dp->active_port = dp_bridge->id;
+
 	ret = cdn_dp_enable(dp);
 	if (ret) {
 		DRM_DEV_ERROR(dp->dev, "Failed to enable bridge %d\n",
@@ -631,6 +731,7 @@ static void cdn_dp_bridge_atomic_enable(struct drm_bridge *bridge, struct drm_at
 		goto out;
 	}
 
+	dp_bridge->enabled = true;
 out:
 	mutex_unlock(&dp->lock);
 }
@@ -638,9 +739,11 @@ static void cdn_dp_bridge_atomic_enable(struct drm_bridge *bridge, struct drm_at
 static void cdn_dp_bridge_atomic_disable(struct drm_bridge *bridge, struct drm_atomic_state *state)
 {
 	struct cdn_dp_device *dp = bridge_to_dp(bridge);
+	struct cdn_dp_bridge *dp_bridge = bridge_to_dp_bridge(bridge);
 	int ret;
 
 	mutex_lock(&dp->lock);
+	dp_bridge->enabled = false;
 
 	if (dp->active) {
 		ret = cdn_dp_disable(dp);
@@ -827,6 +930,16 @@ static int cdn_dp_audio_mute_stream(struct drm_bridge *bridge,
 	return ret;
 }
 
+static void cdn_dp_bridge_hpd_notify(struct drm_bridge *bridge,
+			   enum drm_connector_status status)
+{
+	struct cdn_dp_bridge *dp_bridge = bridge_to_dp_bridge(bridge);
+	struct cdn_dp_device *dp = bridge_to_dp(bridge);
+
+	dp->bridge_list[dp_bridge->id]->connected = status == connector_status_connected;
+	schedule_work(&dp->event_work);
+}
+
 static const struct drm_bridge_funcs cdn_dp_bridge_funcs = {
 	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
@@ -837,6 +950,7 @@ static const struct drm_bridge_funcs cdn_dp_bridge_funcs = {
 	.atomic_disable = cdn_dp_bridge_atomic_disable,
 	.mode_valid = cdn_dp_bridge_mode_valid,
 	.mode_set = cdn_dp_bridge_mode_set,
+	.hpd_notify = cdn_dp_bridge_hpd_notify,
 
 	.dp_audio_prepare = cdn_dp_audio_prepare,
 	.dp_audio_mute_stream = cdn_dp_audio_mute_stream,
@@ -885,7 +999,8 @@ static void cdn_dp_pd_event_work(struct work_struct *work)
 {
 	struct cdn_dp_device *dp = container_of(work, struct cdn_dp_device,
 						event_work);
-	int ret;
+	bool connected;
+	int i, ret;
 
 	mutex_lock(&dp->lock);
 
@@ -944,9 +1059,12 @@ static void cdn_dp_pd_event_work(struct work_struct *work)
 
 out:
 	mutex_unlock(&dp->lock);
-	drm_bridge_hpd_notify(&dp->bridge,
-			      dp->connected ? connector_status_connected
-					    : connector_status_disconnected);
+	for (i = 0; i < dp->bridge_count; i++) {
+		connected = dp->connected && dp->bridge_list[i]->connected;
+		drm_bridge_hpd_notify(&dp->bridge_list[i]->bridge,
+				      connected ? connector_status_connected
+						: connector_status_disconnected);
+	}
 }
 
 static int cdn_dp_pd_event(struct notifier_block *nb,
@@ -966,28 +1084,16 @@ static int cdn_dp_pd_event(struct notifier_block *nb,
 	return NOTIFY_DONE;
 }
 
-static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
+static int cdn_bridge_add(struct device *dev,
+			  struct drm_bridge *bridge,
+			  struct drm_bridge *next_bridge,
+			  struct drm_encoder *encoder)
 {
 	struct cdn_dp_device *dp = dev_get_drvdata(dev);
-	struct drm_encoder *encoder;
+	struct drm_device *drm_dev = dp->drm_dev;
+	struct drm_bridge *last_bridge __free(drm_bridge_put) = NULL;
 	struct drm_connector *connector;
-	struct cdn_dp_port *port;
-	struct drm_device *drm_dev = data;
-	int ret, i;
-
-	ret = cdn_dp_parse_dt(dp);
-	if (ret < 0)
-		return ret;
-
-	dp->drm_dev = drm_dev;
-	dp->connected = false;
-	dp->active = false;
-	dp->active_port = -1;
-	dp->fw_loaded = false;
-
-	INIT_WORK(&dp->event_work, cdn_dp_pd_event_work);
-
-	encoder = &dp->encoder.encoder;
+	int ret;
 
 	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
 							     dev->of_node);
@@ -1002,26 +1108,35 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
 
 	drm_encoder_helper_add(encoder, &cdn_dp_encoder_helper_funcs);
 
-	dp->bridge.ops =
-			DRM_BRIDGE_OP_DETECT |
-			DRM_BRIDGE_OP_EDID |
-			DRM_BRIDGE_OP_HPD |
-			DRM_BRIDGE_OP_DP_AUDIO;
-	dp->bridge.of_node = dp->dev->of_node;
-	dp->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
-	dp->bridge.hdmi_audio_dev = dp->dev;
-	dp->bridge.hdmi_audio_max_i2s_playback_channels = 8;
-	dp->bridge.hdmi_audio_spdif_playback = 1;
-	dp->bridge.hdmi_audio_dai_port = -1;
-
-	ret = devm_drm_bridge_add(dev, &dp->bridge);
+	bridge->ops =
+		DRM_BRIDGE_OP_DETECT |
+		DRM_BRIDGE_OP_EDID |
+		DRM_BRIDGE_OP_HPD |
+		DRM_BRIDGE_OP_DP_AUDIO;
+	bridge->of_node = dp->dev->of_node;
+	bridge->type = DRM_MODE_CONNECTOR_DisplayPort;
+	bridge->hdmi_audio_dev = dp->dev;
+	bridge->hdmi_audio_max_i2s_playback_channels = 8;
+	bridge->hdmi_audio_spdif_playback = 1;
+	bridge->hdmi_audio_dai_port = -1;
+
+	ret = devm_drm_bridge_add(dev, bridge);
 	if (ret)
 		return ret;
 
-	ret = drm_bridge_attach(encoder, &dp->bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
+	ret = drm_bridge_attach(encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
 	if (ret)
 		return ret;
 
+	if (next_bridge) {
+		ret = drm_bridge_attach(encoder, next_bridge, bridge,
+					DRM_BRIDGE_ATTACH_NO_CONNECTOR);
+		if (ret)
+			return ret;
+
+		last_bridge = drm_bridge_chain_get_last_bridge(bridge->encoder);
+	}
+
 	connector = drm_bridge_connector_init(drm_dev, encoder);
 	if (IS_ERR(connector)) {
 		ret = PTR_ERR(connector);
@@ -1029,8 +1144,100 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
 		return ret;
 	}
 
+	if (last_bridge)
+		connector->fwnode = fwnode_handle_get(of_fwnode_handle(last_bridge->of_node));
+
 	drm_connector_attach_encoder(connector, encoder);
 
+	return 0;
+}
+
+static int cdn_dp_parse_next_bridge_dt(struct cdn_dp_device *dp)
+{
+	struct device_node *np = dp->dev->of_node;
+	struct device_node *port __free(device_node) = of_graph_get_port_by_id(np, 1);
+	struct drm_bridge *bridge;
+	int count = 0;
+	int ret = 0;
+	int i;
+
+	/* If device use extcon, do not use hpd bridge */
+	for (i = 0; i < dp->ports; i++) {
+		if (dp->port[i]->extcon) {
+			dp->bridge_count = 1;
+			return 0;
+		}
+	}
+
+	/* One endpoint may correspond to one next bridge. */
+	for_each_of_graph_port_endpoint(port, dp_ep) {
+		struct device_node *next_bridge_node __free(device_node) =
+			of_graph_get_remote_port_parent(dp_ep);
+
+		bridge = of_drm_find_bridge(next_bridge_node);
+		if (!bridge) {
+			ret = -EPROBE_DEFER;
+			goto out;
+		}
+
+		drm_bridge_get(bridge);
+		dp->next_bridge_valid = true;
+		dp->next_bridge_list[count] = bridge;
+		count++;
+	}
+
+out:
+	dp->bridge_count = count ? count : 1;
+	return ret;
+}
+
+static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
+{
+	struct cdn_dp_device *dp = dev_get_drvdata(dev);
+	struct drm_bridge *bridge, *next_bridge;
+	struct drm_encoder *encoder;
+	struct cdn_dp_port *port;
+	struct drm_device *drm_dev = data;
+	struct cdn_dp_bridge *dp_bridge;
+	int ret, i;
+
+	ret = cdn_dp_parse_dt(dp);
+	if (ret < 0)
+		return ret;
+
+	ret = cdn_dp_parse_next_bridge_dt(dp);
+	if (ret)
+		return ret;
+
+	dp->drm_dev = drm_dev;
+	dp->connected = false;
+	dp->active = false;
+	dp->active_port = -1;
+	dp->fw_loaded = false;
+
+	for (i = 0; i < dp->bridge_count; i++) {
+		dp_bridge = devm_drm_bridge_alloc(dev, struct cdn_dp_bridge, bridge,
+						    &cdn_dp_bridge_funcs);
+		if (IS_ERR(dp_bridge))
+			return PTR_ERR(dp_bridge);
+		dp_bridge->id = i;
+		dp_bridge->parent = dp;
+		if (!dp->next_bridge_valid)
+			dp_bridge->connected = true;
+		dp->bridge_list[i] = dp_bridge;
+	}
+
+	for (i = 0; i < dp->bridge_count; i++) {
+		encoder = &dp->bridge_list[i]->encoder.encoder;
+		bridge = &dp->bridge_list[i]->bridge;
+		next_bridge = dp->next_bridge_list[i];
+		ret = cdn_bridge_add(dev, bridge, next_bridge, encoder);
+		if (ret)
+			return ret;
+	}
+
+	INIT_WORK(&dp->event_work, cdn_dp_pd_event_work);
+
 	for (i = 0; i < dp->ports; i++) {
 		port = dp->port[i];
 
@@ -1058,10 +1265,18 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
 static void cdn_dp_unbind(struct device *dev, struct device *master, void *data)
 {
 	struct cdn_dp_device *dp = dev_get_drvdata(dev);
-	struct drm_encoder *encoder = &dp->encoder.encoder;
+	struct drm_encoder *encoder;
+	int i;
 
 	cancel_work_sync(&dp->event_work);
-	encoder->funcs->destroy(encoder);
+	for (i = 0; i < dp->bridge_count; i++) {
+		encoder = &dp->bridge_list[i]->encoder.encoder;
+		encoder->funcs->destroy(encoder);
+		drm_bridge_put(dp->next_bridge_list[i]);
+	}
+
+	for (i = 0; i < MAX_PHY; i++)
+		drm_edid_free(dp->edid_cache[i]);
 
 	pm_runtime_disable(dev);
 	if (dp->fw_loaded)
@@ -1112,10 +1327,10 @@ static int cdn_dp_probe(struct platform_device *pdev)
 	int ret;
 	int i;
 
-	dp = devm_drm_bridge_alloc(dev, struct cdn_dp_device, bridge,
-				   &cdn_dp_bridge_funcs);
-	if (IS_ERR(dp))
-		return PTR_ERR(dp);
+	dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
+	if (!dp)
+		return -ENOMEM;
+
 	dp->dev = dev;
 
 	match = of_match_node(cdn_dp_dt_ids, pdev->dev.of_node);
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h
index e9c30b9fd543..c10e423bbf06 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.h
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h
@@ -38,6 +38,8 @@ enum vic_pxl_encoding_format {
 	Y_ONLY = 0x10,
 };
 
+struct cdn_dp_device;
+
 struct video_info {
 	bool h_sync_polarity;
 	bool v_sync_polarity;
@@ -63,16 +65,28 @@ struct cdn_dp_port {
 	u8 id;
 };
 
+struct cdn_dp_bridge {
+	struct cdn_dp_device *parent;
+	struct drm_bridge bridge;
+	struct rockchip_encoder encoder;
+	bool connected;
+	bool enabled;
+	int id;
+};
+
 struct cdn_dp_device {
 	struct device *dev;
 	struct drm_device *drm_dev;
-	struct drm_bridge bridge;
-	struct rockchip_encoder encoder;
+	int bridge_count;
+	struct cdn_dp_bridge *bridge_list[MAX_PHY];
+	struct drm_bridge *next_bridge_list[MAX_PHY];
+	const struct drm_edid *edid_cache[MAX_PHY];
 	struct drm_display_mode mode;
 	struct platform_device *audio_pdev;
 	struct work_struct event_work;
 
 	struct mutex lock;
+	bool next_bridge_valid;
 	bool connected;
 	bool active;
 	bool suspended;
-- 
2.51.1



From kernel at airkyi.com  Sun Dec  7 17:54:57 2025
From: kernel at airkyi.com (Chaoyi Chen)
Date: Mon,  8 Dec 2025 09:54:57 +0800
Subject: [PATCH v13 08/11] drm/rockchip: cdn-dp: Support handle lane info without extcon
In-Reply-To: <20251208015500.94-1-kernel@airkyi.com>
References: <20251208015500.94-1-kernel@airkyi.com>
Message-ID: <20251208015500.94-9-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

This patch add support for get PHY lane info without help of extcon.

There is no extcon needed if the Type-C controller is present. In this
case, the lane info can be get from PHY instead of extcon.

The extcon device should still be supported if Type-C controller is
not present.

Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
---

(no changes since v5)

Changes in v4:
- Remove cdn_dp_hpd_notify().

(no changes since v3)

Changes in v2:
- Ignore duplicate HPD events.

 drivers/gpu/drm/rockchip/cdn-dp-core.c | 25 +++++++++++++++++--------
 1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
index b7e3f5dcf8d5..1e27301584a4 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
@@ -156,6 +156,9 @@ static int cdn_dp_get_port_lanes(struct cdn_dp_port *port)
 	int dptx;
 	u8 lanes;
 
+	if (!edev)
+		return phy_get_bus_width(port->phy);
+
 	dptx = extcon_get_state(edev, EXTCON_DISP_DP);
 	if (dptx > 0) {
 		extcon_get_property(edev, EXTCON_DISP_DP,
@@ -219,7 +222,7 @@ static bool cdn_dp_check_sink_connection(struct cdn_dp_device *dp)
 	 * some docks need more time to power up.
 	 */
 	while (time_before(jiffies, timeout)) {
-		if (!extcon_get_state(port->extcon, EXTCON_DISP_DP))
+		if (port->extcon && !extcon_get_state(port->extcon, EXTCON_DISP_DP))
 			return false;
 
 		if (!cdn_dp_get_sink_count(dp, &sink_count))
@@ -385,11 +388,14 @@ static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port)
 		goto err_power_on;
 	}
 
-	ret = extcon_get_property(port->extcon, EXTCON_DISP_DP,
-				  EXTCON_PROP_USB_TYPEC_POLARITY, &property);
-	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "get property failed\n");
-		goto err_power_on;
+	property.intval = 0;
+	if (port->extcon) {
+		ret = extcon_get_property(port->extcon, EXTCON_DISP_DP,
+					  EXTCON_PROP_USB_TYPEC_POLARITY, &property);
+		if (ret) {
+			DRM_DEV_ERROR(dp->dev, "get property failed\n");
+			goto err_power_on;
+		}
 	}
 
 	port->lanes = cdn_dp_get_port_lanes(port);
@@ -1028,6 +1034,9 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
 	for (i = 0; i < dp->ports; i++) {
 		port = dp->port[i];
 
+		if (!port->extcon)
+			continue;
+
 		port->event_nb.notifier_call = cdn_dp_pd_event;
 		ret = devm_extcon_register_notifier(dp->dev, port->extcon,
 						    EXTCON_DISP_DP,
@@ -1120,14 +1129,14 @@ static int cdn_dp_probe(struct platform_device *pdev)
 		    PTR_ERR(phy) == -EPROBE_DEFER)
 			return -EPROBE_DEFER;
 
-		if (IS_ERR(extcon) || IS_ERR(phy))
+		if (IS_ERR(phy) || PTR_ERR(extcon) != -ENODEV)
 			continue;
 
 		port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
 		if (!port)
 			return -ENOMEM;
 
-		port->extcon = extcon;
+		port->extcon = IS_ERR(extcon) ? NULL : extcon;
 		port->phy = phy;
 		port->dp = dp;
 		port->id = i;
-- 
2.51.1



From kernel at airkyi.com  Sun Dec  7 17:54:59 2025
From: kernel at airkyi.com (Chaoyi Chen)
Date: Mon,  8 Dec 2025 09:54:59 +0800
Subject: [PATCH v13 10/11] arm64: dts: rockchip: Add missing dp_out port for RK3399 CDN-DP
In-Reply-To: <20251208015500.94-1-kernel@airkyi.com>
References: <20251208015500.94-1-kernel@airkyi.com>
Message-ID: <20251208015500.94-11-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

Let's make the ports nodes of cdn_dp in the same style as the other
display interface, and match the style of ports's yaml.

Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
---

(no changes since v5)

Changes in v4:
- Remove unnecessary #address/#size-cells

(no changes since v1)

 arch/arm64/boot/dts/rockchip/rk3399-base.dtsi | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi
index 4dcceb9136b7..93b42820998f 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi
@@ -618,7 +618,11 @@ cdn_dp: dp at fec00000 {
 		status = "disabled";
 
 		ports {
-			dp_in: port {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			dp_in: port at 0 {
+				reg = <0>;
 				#address-cells = <1>;
 				#size-cells = <0>;
 
@@ -632,6 +636,10 @@ dp_in_vopl: endpoint at 1 {
 					remote-endpoint = <&vopl_out_dp>;
 				};
 			};
+
+			dp_out: port at 1 {
+				reg = <1>;
+			};
 		};
 	};
 
-- 
2.51.1



From kernel at airkyi.com  Sun Dec  7 17:55:00 2025
From: kernel at airkyi.com (Chaoyi Chen)
Date: Mon,  8 Dec 2025 09:55:00 +0800
Subject: [PATCH v13 11/11] arm64: dts: rockchip: rk3399-evb-ind: Add support for DisplayPort
In-Reply-To: <20251208015500.94-1-kernel@airkyi.com>
References: <20251208015500.94-1-kernel@airkyi.com>
Message-ID: <20251208015500.94-12-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

The RK3399 EVB IND board has a Type-C interface DisplayPort.
It use fusb302 chip as Type-C controller.

fusb302 chip ---> USB/DP PHY0 <----> CDN-DP controller

Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
---

(no changes since v10)

Changes in v9:
- Add usb role switch for Type-C.
- Remove USB2 PHY in Type-C connection.

(no changes since v4)

Changes in v3:
- Fix wrong vdo value.
- Fix port node in usb-c-connector.

Changes in v2:
- Add endpoint to link DP PHY and DP controller.
- Fix devicetree coding style.

 .../boot/dts/rockchip/rk3399-evb-ind.dts      | 147 ++++++++++++++++++
 1 file changed, 147 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-evb-ind.dts b/arch/arm64/boot/dts/rockchip/rk3399-evb-ind.dts
index 70aee1ab904c..be1e90f7a453 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-evb-ind.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-evb-ind.dts
@@ -4,6 +4,7 @@
  */
 
 /dts-v1/;
+#include <dt-bindings/usb/pd.h>
 #include "rk3399.dtsi"
 
 / {
@@ -19,6 +20,21 @@ chosen {
 		stdout-path = "serial2:1500000n8";
 	};
 
+	sound: sound {
+		compatible = "rockchip,rk3399-gru-sound";
+		rockchip,cpu = <&i2s0 &spdif>;
+	};
+
+	vbus_typec: regulator-vbus-typec {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpio1 RK_PC2 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&vcc5v0_typec0_en>;
+		regulator-name = "vbus_typec";
+		vin-supply = <&vcc5v0_sys>;
+	};
+
 	vcc5v0_sys: regulator-vcc5v0-sys {
 		compatible = "regulator-fixed";
 		enable-active-high;
@@ -31,6 +47,11 @@ vcc5v0_sys: regulator-vcc5v0-sys {
 	};
 };
 
+&cdn_dp {
+	phys = <&tcphy0_dp>;
+	status = "okay";
+};
+
 &cpu_b0 {
 	cpu-supply = <&vdd_cpu_b>;
 };
@@ -55,6 +76,12 @@ &cpu_l3 {
 	cpu-supply = <&vdd_cpu_l>;
 };
 
+&dp_out {
+	dp_controller_output: endpoint {
+		remote-endpoint = <&dp_phy_in>;
+	};
+};
+
 &emmc_phy {
 	status = "okay";
 };
@@ -341,6 +368,71 @@ regulator-state-mem {
 	};
 };
 
+&i2c4 {
+	i2c-scl-rising-time-ns = <475>;
+	i2c-scl-falling-time-ns = <26>;
+	status = "okay";
+
+	usbc0: typec-portc at 22 {
+		compatible = "fcs,fusb302";
+		reg = <0x22>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <RK_PA2 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&usbc0_int>;
+		vbus-supply = <&vbus_typec>;
+
+		usb_con: connector {
+			compatible = "usb-c-connector";
+			label = "USB-C";
+			data-role = "dual";
+			power-role = "dual";
+			try-power-role = "sink";
+			op-sink-microwatt = <1000000>;
+			sink-pdos =
+				<PDO_FIXED(5000, 2500, PDO_FIXED_USB_COMM)>;
+			source-pdos =
+				<PDO_FIXED(5000, 1500, PDO_FIXED_USB_COMM)>;
+
+			altmodes {
+				displayport {
+					svid = /bits/ 16 <0xff01>;
+					vdo = <0x00001c46>;
+				};
+			};
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+
+					usbc0_orien_sw: endpoint {
+						remote-endpoint = <&tcphy0_orientation_switch>;
+					};
+				};
+
+				port at 1 {
+					reg = <1>;
+
+					usbc0_role_sw: endpoint {
+						remote-endpoint = <&dwc3_0_role_switch>;
+					};
+				};
+
+				port at 2 {
+					reg = <2>;
+
+					dp_altmode_mux: endpoint {
+						remote-endpoint = <&tcphy0_typec_dp>;
+					};
+				};
+			};
+		};
+	};
+};
+
 &i2s2 {
 	status = "okay";
 };
@@ -354,6 +446,16 @@ &io_domains {
 };
 
 &pinctrl {
+	usb-typec {
+		usbc0_int: usbc0-int {
+			rockchip,pins = <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+
+		vcc5v0_typec0_en: vcc5v0-typec0-en {
+			rockchip,pins = <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
 	pmic {
 		pmic_int_l: pmic-int-l {
 			rockchip,pins = <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>;
@@ -400,10 +502,48 @@ &sdmmc {
 	status = "okay";
 };
 
+&sound {
+	rockchip,codec = <&cdn_dp>;
+	status = "okay";
+};
+
+&spdif {
+	status = "okay";
+};
+
 &tcphy0 {
 	status = "okay";
 };
 
+&tcphy0_dp {
+	mode-switch;
+
+	port {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		tcphy0_typec_dp: endpoint at 0 {
+			reg = <0>;
+			remote-endpoint = <&dp_altmode_mux>;
+		};
+
+		dp_phy_in: endpoint at 1 {
+			reg = <1>;
+			remote-endpoint = <&dp_controller_output>;
+		};
+	};
+};
+
+&tcphy0_usb3 {
+	orientation-switch;
+
+	port {
+		tcphy0_orientation_switch: endpoint {
+			remote-endpoint = <&usbc0_orien_sw>;
+		};
+	};
+};
+
 &tcphy1 {
 	status = "okay";
 };
@@ -461,7 +601,14 @@ &usb_host1_ohci {
 };
 
 &usbdrd_dwc3_0 {
+	usb-role-switch;
 	status = "okay";
+
+	port {
+		dwc3_0_role_switch: endpoint {
+			remote-endpoint = <&usbc0_role_sw>;
+		};
+	};
 };
 
 &usbdrd3_0 {
-- 
2.51.1



From jiyu.yang at oss.nxp.com  Sun Dec  7 18:02:03 2025
From: jiyu.yang at oss.nxp.com (Rain Yang)
Date: Mon, 8 Dec 2025 10:02:03 +0800
Subject: [PATCH] arm64: dts: imx95: Use GPU_CGC as core clock for GPU
In-Reply-To: <9b593731-898f-46a7-8ee5-68f8c170351c@mailbox.org>
References: <20251129143220.14834-1-marek.vasut@mailbox.org>
 <aS-lEibp3zTsaR6T@oss.nxp.com>
 <c6e0e55a-06da-4665-972e-e9b5b8c08bf7@mailbox.org>
 <aTACuRjC_Zpf8IOU@oss.nxp.com>
 <de36091e-c890-4897-b3e3-2a7575029a5d@mailbox.org>
 <aTD5np-HGaJqhzkD@oss.nxp.com>
 <5944d872-01a3-47e9-977b-029f3be4fd83@mailbox.org>
 <aTKVMAMQ6v_BwD6R@oss.nxp.com>
 <9b593731-898f-46a7-8ee5-68f8c170351c@mailbox.org>
Message-ID: <aTYxm_dfMwF4H0_b@oss.nxp.com>

On Sun, Dec 07, 2025 at 10:01:06AM +0100, Marek Vasut wrote:
>On 12/5/25 9:17 AM, Rain Yang wrote:
>> On Thu, Dec 04, 2025 at 04:25:38AM +0100, Marek Vasut wrote:
>> > On 12/4/25 4:01 AM, Rain Yang wrote:
>> > 
>> > [...]
>> > > > > For the Linux working environment,
>> > > > > CLK_GPU and CLK_GPUAPB are always-on, while CLK_GPU_CGC can be gated off.
>> > > > > 
>> > > > > Regarding the IMX95_CLK_GPUAPB handle, my suggestion was based on the absence
>> > > > > of its frequency in any OPP entry within the frequency table. Removing it
>> > > > > could simplify the OPP handling logic and reduce unnecessary complexity.
>> > > > 
>> > > > If the clock can be disabled by SM, Linux has to make sure they are NOT
>> > > > disabled, so they must be described in DT, right ?
>> > > > 
>> > > > > [1] https://github.com/nxp-imx/linux-imx/commit/695f2bdc57b869ca5189313e4b5fa7eb5a12f622
>> > > Currently, only CLK_GPU_CGC shall be described in the Device Tree[1], as it can be gated.
>> > > The other clocks (CLK_GPU and CLK_GPUAPB) are always-on in the Linux environment,
>> > > so describing any of them in DT is not necessary and would not be proper in this context.
>> > 
>> > Since this discussion is in fact unrelated to this bugfix, I would propose to
>> > fork the discussion into a separate patch. Can you please submit a patch for
>> > the GPUAPB clock ? Note that I believe GPUAPB clock have to be described in
>> > DT, if only because DT is a hardware description, and to make sure the GPUAPB
>> > clock are correctly enabled by the driver.
>> 
>> Okay, I?ll submit a patch later.
>> The commit message should reflect that only CLK_GPU_CGC is enabled.
>
>The commit message , and this change , is unrelated to GPUAPB clock.
The commit message is ambiguous. Could you clarify which parent clock
you are referring to, and whether it can be enabled by CLK_GPU_CGC?
If it was CLK_GPU, CLK_GPU_CGC can't be able to control it.     


From rdunlap at infradead.org  Sun Dec  7 18:04:09 2025
From: rdunlap at infradead.org (Randy Dunlap)
Date: Sun, 7 Dec 2025 18:04:09 -0800
Subject: Kconfig dangling references (BZ 216748)
Message-ID: <22b92ddf-6321-41b5-8073-f9c7064d3432@infradead.org>

from  https://bugzilla.kernel.org/show_bug.cgi?id=216748

The bugzilla entry includes a Perl script and a shell script.
This is the edited result of running them (I removed some entries that were noise).

I'll try to Cc: all of the relevant mailing lists or individuals.


ARCH_HAS_HOLES_MEMORYMODEL ---
arch/arm/mach-omap1/Kconfig:7:	select ARCH_HAS_HOLES_MEMORYMODEL

ARM_ERRATA_794072 ---
arch/arm/mach-npcm/Kconfig:33:	select ARM_ERRATA_794072

ARM_SMC_MBOX ---
arch/arm64/Kconfig.platforms:375:	select ARM_SMC_MBOX

CLK_FIXED_FCH ---
sound/soc/amd/Kconfig:11:	select CLK_FIXED_FCH
sound/soc/amd/Kconfig:48:	select CLK_FIXED_FCH
sound/soc/amd/acp/Kconfig:107:	select CLK_FIXED_FCH

CONFIG_STM ---
drivers/hwtracing/stm/Kconfig:16:	default CONFIG_STM  # should be STM
drivers/hwtracing/stm/Kconfig:31:	default CONFIG_STM

CPU_HAS_LOAD_STORE_LR ---
arch/mips/Kconfig:1411:	select CPU_HAS_LOAD_STORE_LR

DRM_KMS_DMA_HELPER ---
drivers/gpu/drm/adp/Kconfig:9:	select DRM_KMS_DMA_HELPER
drivers/gpu/drm/logicvc/Kconfig:7:	select DRM_KMS_DMA_HELPER

EXTCON_TCSS_CROS_EC ---
drivers/usb/typec/ucsi/Kconfig:76:	depends on !EXTCON_TCSS_CROS_EC

MACH_JZ4755 ---
drivers/clk/ingenic/Kconfig:20:	default MACH_JZ4755
drivers/pinctrl/pinctrl-ingenic.c:158:	IS_ENABLED(CONFIG_MACH_JZ4755) << ID_JZ4755 |
drivers/pinctrl/pinctrl-ingenic.c:4616:		.data = IF_ENABLED(CONFIG_MACH_JZ4755, &jz4755_chip_info)

MACH_JZ4760 ---
drivers/clk/ingenic/Kconfig:40:	default MACH_JZ4760
drivers/pinctrl/pinctrl-ingenic.c:159:	IS_ENABLED(CONFIG_MACH_JZ4760) << ID_JZ4760 |
drivers/pinctrl/pinctrl-ingenic.c:4620:		.data = IF_ENABLED(CONFIG_MACH_JZ4760, &jz4760_chip_info)
drivers/pinctrl/pinctrl-ingenic.c:4624:		.data = IF_ENABLED(CONFIG_MACH_JZ4760, &jz4760_chip_info)

MACH_STM32MP25 ---
drivers/pinctrl/stm32/Kconfig:58:	default MACH_STM32MP25 || (ARCH_STM32 && ARM64)

MFD_AIROHA_AN8855 ---
drivers/nvmem/Kconfig:33:	depends on MFD_AIROHA_AN8855 || COMPILE_TEST

MFD_TN48M_CPLD ---
drivers/gpio/Kconfig:1624:	depends on MFD_TN48M_CPLD || COMPILE_TEST
drivers/reset/Kconfig:365:	depends on MFD_TN48M_CPLD || COMPILE_TEST
drivers/reset/Kconfig:366:	default MFD_TN48M_CPLD

MIPS_BAIKAL_T1 ---
drivers/ata/Kconfig:197:	select MFD_SYSCON if (MIPS_BAIKAL_T1 || COMPILE_TEST)
drivers/bus/Kconfig:43:	depends on MIPS_BAIKAL_T1 || COMPILE_TEST
drivers/bus/Kconfig:58:	depends on MIPS_BAIKAL_T1 || COMPILE_TEST
drivers/clk/baikal-t1/Kconfig:4:	depends on (MIPS_BAIKAL_T1 && OF) || COMPILE_TEST
drivers/clk/baikal-t1/Kconfig:5:	default MIPS_BAIKAL_T1
drivers/clk/baikal-t1/Kconfig:20:	default MIPS_BAIKAL_T1
drivers/clk/baikal-t1/Kconfig:33:	default MIPS_BAIKAL_T1
drivers/clk/baikal-t1/Kconfig:45:	default MIPS_BAIKAL_T1
drivers/hwmon/Kconfig:462:	depends on MIPS_BAIKAL_T1 || COMPILE_TEST
drivers/i2c/busses/Kconfig:589:	select MFD_SYSCON if MIPS_BAIKAL_T1
drivers/memory/Kconfig:69:	depends on MIPS_BAIKAL_T1 || COMPILE_TEST
drivers/mtd/maps/Kconfig:81:	depends on MIPS_BAIKAL_T1 || COMPILE_TEST
drivers/pci/controller/dwc/Kconfig:89:	depends on MIPS_BAIKAL_T1 || COMPILE_TEST
drivers/spi/Kconfig:370:	depends on MIPS_BAIKAL_T1 || COMPILE_TEST

PINCTRL_MILBEAUT ---
arch/arm/mach-milbeaut/Kconfig:16:	select PINCTRL_MILBEAUT

SND_SOC_AC97_BUS_NEW ---
sound/soc/pxa/Kconfig:21:	select SND_SOC_AC97_BUS_NEW

SND_SOC_CS35L56_CAL_SYSFS_COMMON ---
sound/soc/codecs/Kconfig:920:	select SND_SOC_CS35L56_CAL_SYSFS_COMMON

TEST_KUNIT_DEVICE_HELPERS ---
drivers/iio/test/Kconfig:11:	select TEST_KUNIT_DEVICE_HELPERS

USB_HSIC_USB3613 ---
drivers/staging/greybus/Kconfig:209:	depends on USB_HSIC_USB3613 || COMPILE_TEST
drivers/staging/greybus/arche-platform.c:26:#if IS_ENABLED(CONFIG_USB_HSIC_USB3613)

USB_OHCI_SH ---
arch/sh/Kconfig:334:	select USB_OHCI_SH if USB_OHCI_HCD
arch/sh/Kconfig:344:	select USB_OHCI_SH if USB_OHCI_HCD
arch/sh/Kconfig:429:	select USB_OHCI_SH if USB_OHCI_HCD
arch/sh/Kconfig:455:	select USB_OHCI_SH if USB_OHCI_HCD
arch/sh/configs/sh7757lcr_defconfig:61:CONFIG_USB_OHCI_SH=y

X86_P6_NOP ---
arch/x86/Kconfig.cpufeatures:41:	depends on X86_64 || X86_P6_NOP
arch/x86/Makefile_32.cpu:48:ifneq ($(CONFIG_X86_P6_NOP),y)

XTENSA_PLATFORM_ESP32 ---
drivers/tty/serial/Kconfig:1598:	depends on XTENSA_PLATFORM_ESP32 || (COMPILE_TEST && OF)
drivers/tty/serial/Kconfig:1611:	depends on XTENSA_PLATFORM_ESP32 || (COMPILE_TEST && OF)


-- 
~Randy



From krzysztof.kozlowski at oss.qualcomm.com  Sun Dec  7 18:09:08 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Mon,  8 Dec 2025 03:09:08 +0100
Subject: [PATCH 1/2] firmware: arm_scmi: Fix confusing cleanup.h syntax
Message-ID: <20251208020907.5476-3-krzysztof.kozlowski@oss.qualcomm.com>

Initializing automatic __free variables to NULL without need (e.g.
branches with different allocations), followed by actual allocation is
in contrary to explicit coding rules guiding cleanup.h:

"Given that the "__free(...) = NULL" pattern for variables defined at
the top of the function poses this potential interdependency problem the
recommendation is to always define and assign variables in one statement
and not group variable definitions at the top of the function when
__free() is used."

Code does not have a bug, but is less readable and uses discouraged
coding practice, so fix that by moving declaration to the place of
assignment.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/firmware/arm_scmi/quirks.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/firmware/arm_scmi/quirks.c b/drivers/firmware/arm_scmi/quirks.c
index 03848283c2a0..4fb09bb8c6b3 100644
--- a/drivers/firmware/arm_scmi/quirks.c
+++ b/drivers/firmware/arm_scmi/quirks.c
@@ -218,7 +218,7 @@ static unsigned int scmi_quirk_signature(const char *vend, const char *sub_vend)
 
 static int scmi_quirk_range_parse(struct scmi_quirk *quirk)
 {
-	const char *last, *first __free(kfree) = NULL;
+	const char *last;
 	size_t len;
 	char *sep;
 	int ret;
@@ -229,7 +229,8 @@ static int scmi_quirk_range_parse(struct scmi_quirk *quirk)
 	if (!len)
 		return 0;
 
-	first = kmemdup(quirk->impl_ver_range, len + 1, GFP_KERNEL);
+	const char *first __free(kfree) = kmemdup(quirk->impl_ver_range, len + 1,
+						  GFP_KERNEL);
 	if (!first)
 		return -ENOMEM;
 
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Sun Dec  7 18:09:09 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Mon,  8 Dec 2025 03:09:09 +0100
Subject: [PATCH 2/2] firmware: cirrus: Fix confusing cleanup.h syntax
In-Reply-To: <20251208020907.5476-3-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251208020907.5476-3-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <20251208020907.5476-4-krzysztof.kozlowski@oss.qualcomm.com>

Initializing automatic __free variables to NULL without need (e.g.
branches with different allocations), followed by actual allocation is
in contrary to explicit coding rules guiding cleanup.h:

"Given that the "__free(...) = NULL" pattern for variables defined at
the top of the function poses this potential interdependency problem the
recommendation is to always define and assign variables in one statement
and not group variable definitions at the top of the function when
__free() is used."

Code does not have a bug, but is less readable and uses discouraged
coding practice, so fix that by moving declaration to the place of
assignment.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/firmware/cirrus/cs_dsp.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c
index 525ac0f0a75d..86d49dbc6fa6 100644
--- a/drivers/firmware/cirrus/cs_dsp.c
+++ b/drivers/firmware/cirrus/cs_dsp.c
@@ -375,13 +375,11 @@ static ssize_t cs_dsp_debugfs_string_read(struct cs_dsp *dsp,
 					  size_t count, loff_t *ppos,
 					  const char **pstr)
 {
-	const char *str __free(kfree) = NULL;
-
 	scoped_guard(mutex, &dsp->pwr_lock) {
 		if (!*pstr)
 			return 0;
 
-		str = kasprintf(GFP_KERNEL, "%s\n", *pstr);
+		const char *str __free(kfree) = kasprintf(GFP_KERNEL, "%s\n", *pstr);
 		if (!str)
 			return -ENOMEM;
 
-- 
2.51.0



From qijian.guo at nxp.com  Sun Dec  7 18:17:43 2025
From: qijian.guo at nxp.com (Joseph Guo)
Date: Mon, 8 Dec 2025 11:17:43 +0900
Subject: [PATCH 2/2] arm64: dts: freescale: add NXP FRDM-IMX91S board
 support
In-Reply-To: <20251205-imx91s-frdm-v1-2-afd6cd01c299@nxp.com>
References: <20251205-imx91s-frdm-v1-0-afd6cd01c299@nxp.com>
 <20251205-imx91s-frdm-v1-2-afd6cd01c299@nxp.com>
Message-ID: <aTY1R9x0J9zzGx+0@lsvm11u0000395.swis.ap-northeast-2.aws.nxp.com>

On Fri, Dec 05, 2025 at 05:03:59PM +0900, Yanan.Yang wrote:
> Add DeviceTree support for the NXP FRDM-IMX91S development board based
> on the i.MX91 SoC. FRDM-IMX91S is a cost-optimized variant of FRDM-IMX91
> and differs in memory, storage, Ethernet, and PMIC configuration:
> 
> - 512MB LPDDR4 (FRDM-IMX91 uses 1GB)
> - 256MB FlexSPI-NAND (FRDM-IMX91 uses 8GB eMMC)
> - Single GbE port (FRDM-IMX91 has dual GbE)
> - PMIC PF9453 (FRDM-IMX91 uses PCA9451A)
> 
> This DT enables:
> - ADC1
> - UART1 and UART5
> - I2C bus and children nodes
> - USB and related nodes
> - uSDHC1 and uSDHC2
> - FlexSPI NAND flash
> - Watchdog3
> - Ethernet (eqos)
> - FlexCAN
> - MQS
> 
> Link: https://www.nxp.com/design/design-center/development-boards-and-designs/FRDM-IMX91S
> (FRDM-IMX91S board page)
> Link: https://www.nxp.com/design/design-center/development-boards-and-designs/FRDM-IMX91
> (FRDM-IMX91 board page)
> 
> Co-developed-by: Lei Xu <lei.xu at nxp.com>
> Signed-off-by: Lei Xu <lei.xu at nxp.com>
> Co-developed-by: Xiaofeng Wei <xiaofeng.wei at nxp.com>
> Signed-off-by: Xiaofeng Wei <xiaofeng.wei at nxp.com>
> Signed-off-by: Yanan.Yang <yanan.yang at nxp.com>
> ---
>  arch/arm64/boot/dts/freescale/Makefile             |   1 +
>  .../boot/dts/freescale/imx91-11x11-frdm-s.dts      | 692 +++++++++++++++++++++
>  2 files changed, 693 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
> index f30d3fd724d0..927bf76a05f3 100644
> --- a/arch/arm64/boot/dts/freescale/Makefile
> +++ b/arch/arm64/boot/dts/freescale/Makefile
> @@ -368,6 +368,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8qxp-tqma8xqps-mb-smarc-2.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx8ulp-9x9-evk.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx8ulp-evk.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx91-11x11-evk.dtb
> +dtb-$(CONFIG_ARCH_MXC) += imx91-11x11-frdm-s.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx91-phyboard-segin.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx91-tqma9131-mba91xxca.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx93-9x9-qsb.dtb
> diff --git a/arch/arm64/boot/dts/freescale/imx91-11x11-frdm-s.dts b/arch/arm64/boot/dts/freescale/imx91-11x11-frdm-s.dts
> new file mode 100644
> index 000000000000..0952a685c3f5
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx91-11x11-frdm-s.dts
> @@ -0,0 +1,692 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright 2025 NXP
> + */
> +
> +/dts-v1/;
> +
> +#include <dt-bindings/usb/pd.h>
> +#include "imx91.dtsi"
> +
> +/ {
> +	compatible = "fsl,imx91-11x11-frdm-s", "fsl,imx91";
> +	model = "NXP FRDM-IMX91S board";
> +
> +	aliases {
> +		ethernet0 = &fec;
> +		ethernet1 = &eqos;
> +		gpio0 = &gpio1;
> +		gpio1 = &gpio2;
> +		gpio2 = &gpio3;
> +		gpio3 = &gpio4;
> +		i2c0 = &lpi2c1;
> +		i2c1 = &lpi2c2;
> +		i2c2 = &lpi2c3;
> +		i2c3 = &lpi2c4;
> +		i2c4 = &lpi2c5;
> +		i2c5 = &lpi2c6;
> +		i2c6 = &lpi2c7;
> +		i2c7 = &lpi2c8;
> +		mmc0 = &usdhc1;
> +		mmc1 = &usdhc2;
> +		mmc2 = &usdhc3;
> +		rtc0 = &bbnsm_rtc;
Hi Yanan,

Please add pcf2131 alias here.

[snip]
> +	};
> +};
> +
> +&iomuxc {

Please don't mix table and space here.
And all marcro value should keep alignment.
Please take care and fix. Thanks.

Regards,
Joseph

> +	pinctrl_eqos: eqosgrp {
> +		fsl,pins = <
> +			MX91_PAD_ENET1_MDC__ENET1_MDC                           0x57e
> +			MX91_PAD_ENET1_MDIO__ENET_QOS_MDIO                      0x57e
> +			MX91_PAD_ENET1_RD0__ENET_QOS_RGMII_RD0                  0x57e
> +			MX91_PAD_ENET1_RD1__ENET_QOS_RGMII_RD1                  0x57e
> +			MX91_PAD_ENET1_RD2__ENET_QOS_RGMII_RD2                  0x57e
> +			MX91_PAD_ENET1_RD3__ENET_QOS_RGMII_RD3                  0x57e
> +			MX91_PAD_ENET1_RXC__ENET_QOS_RGMII_RXC                  0x5fe
> +			MX91_PAD_ENET1_RX_CTL__ENET_QOS_RGMII_RX_CTL            0x57e
> +			MX91_PAD_ENET1_TD0__ENET_QOS_RGMII_TD0                  0x57e
> +			MX91_PAD_ENET1_TD1__ENET1_RGMII_TD1                     0x57e
> +			MX91_PAD_ENET1_TD2__ENET_QOS_RGMII_TD2                  0x57e
> +			MX91_PAD_ENET1_TD3__ENET_QOS_RGMII_TD3                  0x57e
> +			MX91_PAD_ENET1_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK  0x5fe
> +			MX91_PAD_ENET1_TX_CTL__ENET_QOS_RGMII_TX_CTL            0x57e
> +		>;
> +	};
> +
> +	pinctrl_eqos_sleep: eqossleepgrp {
> +		fsl,pins = <
> +			MX91_PAD_ENET1_MDC__GPIO4_IO0                           0x31e
> +			MX91_PAD_ENET1_MDIO__GPIO4_IO1                          0x31e
> +			MX91_PAD_ENET1_RD0__GPIO4_IO10                          0x31e
> +			MX91_PAD_ENET1_RD1__GPIO4_IO11                          0x31e
> +			MX91_PAD_ENET1_RD2__GPIO4_IO12                          0x31e
> +			MX91_PAD_ENET1_RD3__GPIO4_IO13                          0x31e
> +			MX91_PAD_ENET1_RXC__GPIO4_IO9                           0x31e
> +			MX91_PAD_ENET1_RX_CTL__GPIO4_IO8                        0x31e
> +			MX91_PAD_ENET1_TD0__GPIO4_IO5                           0x31e
> +			MX91_PAD_ENET1_TD1__GPIO4_IO4                           0x31e
> +			MX91_PAD_ENET1_TD2__GPIO4_IO3                           0x31e
> +			MX91_PAD_ENET1_TD3__GPIO4_IO2                           0x31e
> +			MX91_PAD_ENET1_TXC__GPIO4_IO7                           0x31e
> +			MX91_PAD_ENET1_TX_CTL__GPIO4_IO6                        0x31e
> +		>;
> +	};
> +
> +	pinctrl_flexcan1: flexcan1grp {
> +		fsl,pins = <
> +			MX91_PAD_GPIO_IO28__CAN1_TX			0x139e
> +			MX91_PAD_GPIO_IO29__CAN1_RX			0x139e
> +			MX91_PAD_PDM_BIT_STREAM1__GPIO1_IO10		0x31e
> +		>;
> +	};
> +
> +	pinctrl_flexcan1_sleep: flexcan1sleepgrp {
> +		fsl,pins = <
> +			MX91_PAD_GPIO_IO28__GPIO2_IO28			0x31e
> +			MX91_PAD_GPIO_IO29__GPIO2_IO29			0x31e
> +			MX91_PAD_PDM_BIT_STREAM1__GPIO1_IO10		0x31e
> +		>;
> +	};
> +
> +	pinctrl_flexspi1: flexspi1grp {
> +		fsl,pins = <
> +			MX91_PAD_SD3_CLK__FLEXSPI1_A_SCLK	0x3fe
> +			MX91_PAD_SD3_CMD__FLEXSPI1_A_SS0_B	0x3fe
> +			MX91_PAD_SD3_DATA0__FLEXSPI1_A_DATA0	0x3fe
> +			MX91_PAD_SD3_DATA1__FLEXSPI1_A_DATA1	0x3fe
> +			MX91_PAD_SD3_DATA2__FLEXSPI1_A_DATA2	0x3fe
> +			MX91_PAD_SD3_DATA3__FLEXSPI1_A_DATA3	0x3fe
> +		>;
> +	};
> +
> +	pinctrl_gpio_key: gpiokeysgrp {
> +		fsl,pins = <
> +			MX91_PAD_CCM_CLKO1__GPIO3_IO26             0x0000031E
> +		>;
> +	};
> +
> +	pinctrl_lpi2c1: lpi2c1grp {
> +		fsl,pins = <
> +			MX91_PAD_I2C1_SCL__LPI2C1_SCL                           0x40000b9e
> +			MX91_PAD_I2C1_SDA__LPI2C1_SDA                           0x40000b9e
> +		>;
> +	};
> +
> +	pinctrl_lpi2c2: lpi2c2grp {
> +		fsl,pins = <
> +			MX91_PAD_I2C2_SCL__LPI2C2_SCL                           0x40000b9e
> +			MX91_PAD_I2C2_SDA__LPI2C2_SDA                           0x40000b9e
> +		>;
> +	};
> +
> +	pinctrl_mqs1: mqs1grp {
> +		fsl,pins = <
> +			MX91_PAD_PDM_CLK__MQS1_LEFT			0x31e
> +			MX91_PAD_PDM_BIT_STREAM0__MQS1_RIGHT		0x31e
> +		>;
> +	};
> +
> +	pinctrl_pcal6524: pcal6524grp {
> +		fsl,pins = <
> +			MX91_PAD_CCM_CLKO2__GPIO3_IO27                          0x31e
> +			MX91_PAD_SD1_DATA5__GPIO3_IO15			0x31e
> +		>;
> +	};
> +
> +	pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
> +		fsl,pins = <
> +			MX91_PAD_SD2_RESET_B__GPIO3_IO7                         0x31e
> +		>;
> +	};
> +
> +	pinctrl_uart1: uart1grp {
> +		fsl,pins = <
> +			MX91_PAD_UART1_RXD__LPUART1_RX                          0x31e
> +			MX91_PAD_UART1_TXD__LPUART1_TX                          0x31e
> +		>;
> +	};
> +
> +	pinctrl_uart5: uart5grp {
> +		fsl,pins = <
> +			MX91_PAD_DAP_TDO_TRACESWO__LPUART5_TX                   0x31e
> +			MX91_PAD_DAP_TDI__LPUART5_RX                            0x31e
> +			MX91_PAD_DAP_TMS_SWDIO__LPUART5_RTS_B                   0x31e
> +			MX91_PAD_DAP_TCLK_SWCLK__LPUART5_CTS_B                  0x31e
> +		>;
> +	};
> +
> +	pinctrl_usdhc1: usdhc1grp {
> +		fsl,pins = <
> +			MX91_PAD_SD1_CLK__USDHC1_CLK                            0x1582
> +			MX91_PAD_SD1_CMD__USDHC1_CMD                            0x1382
> +			MX91_PAD_SD1_DATA0__USDHC1_DATA0                        0x1382
> +			MX91_PAD_SD1_DATA1__USDHC1_DATA1                        0x1382
> +			MX91_PAD_SD1_DATA2__USDHC1_DATA2                        0x1382
> +			MX91_PAD_SD1_DATA3__USDHC1_DATA3                        0x1382
> +			MX91_PAD_SD1_DATA4__GPIO3_IO14		0x031E
> +			MX91_PAD_SD1_STROBE__GPIO3_IO18		0x031E
> +		>;
> +	};
> +
> +	pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp {
> +		fsl,pins = <
> +			MX91_PAD_SD1_CLK__USDHC1_CLK                            0x158e
> +			MX91_PAD_SD1_CMD__USDHC1_CMD                            0x138e
> +			MX91_PAD_SD1_DATA0__USDHC1_DATA0                        0x138e
> +			MX91_PAD_SD1_DATA1__USDHC1_DATA1                        0x138e
> +			MX91_PAD_SD1_DATA2__USDHC1_DATA2                        0x138e
> +			MX91_PAD_SD1_DATA3__USDHC1_DATA3                        0x138e
> +			MX91_PAD_SD1_DATA4__GPIO3_IO14		0x031E
> +			MX91_PAD_SD1_STROBE__GPIO3_IO18		0x031E
> +		>;
> +	};
> +
> +	pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp {
> +		fsl,pins = <
> +			MX91_PAD_SD1_CLK__USDHC1_CLK                            0x15fe
> +			MX91_PAD_SD1_CMD__USDHC1_CMD                            0x13fe
> +			MX91_PAD_SD1_DATA0__USDHC1_DATA0                        0x13fe
> +			MX91_PAD_SD1_DATA1__USDHC1_DATA1                        0x13fe
> +			MX91_PAD_SD1_DATA2__USDHC1_DATA2                        0x13fe
> +			MX91_PAD_SD1_DATA3__USDHC1_DATA3                        0x13fe
> +			MX91_PAD_SD1_DATA4__GPIO3_IO14		0x031E
> +			MX91_PAD_SD1_STROBE__GPIO3_IO18		0x031E
> +		>;
> +	};
> +
> +	pinctrl_usdhc2_gpio: usdhc2gpiogrp {
> +		fsl,pins = <
> +			MX91_PAD_SD2_CD_B__GPIO3_IO0                            0x31e
> +		>;
> +	};
> +
> +	pinctrl_usdhc2_gpio_sleep: usdhc2gpiosleepgrp {
> +		fsl,pins = <
> +			MX91_PAD_SD2_CD_B__GPIO3_IO0                            0x51e
> +		>;
> +	};
> +
> +	pinctrl_usdhc2: usdhc2grp {
> +		fsl,pins = <
> +			MX91_PAD_SD2_CLK__USDHC2_CLK                            0x1582
> +			MX91_PAD_SD2_CMD__USDHC2_CMD                            0x1382
> +			MX91_PAD_SD2_DATA0__USDHC2_DATA0                        0x1382
> +			MX91_PAD_SD2_DATA1__USDHC2_DATA1                        0x1382
> +			MX91_PAD_SD2_DATA2__USDHC2_DATA2                        0x1382
> +			MX91_PAD_SD2_DATA3__USDHC2_DATA3                        0x1382
> +			MX91_PAD_SD2_VSELECT__USDHC2_VSELECT                    0x51e
> +		>;
> +	};
> +
> +	pinctrl_usdhc2_sleep: usdhc2sleepgrp {
> +		fsl,pins = <
> +			MX91_PAD_SD2_CLK__GPIO3_IO1                             0x51e
> +			MX91_PAD_SD2_CMD__GPIO3_IO2                             0x51e
> +			MX91_PAD_SD2_DATA0__GPIO3_IO3                           0x51e
> +			MX91_PAD_SD2_DATA1__GPIO3_IO4                           0x51e
> +			MX91_PAD_SD2_DATA2__GPIO3_IO5                           0x51e
> +			MX91_PAD_SD2_DATA3__GPIO3_IO6                           0x51e
> +			MX91_PAD_SD2_VSELECT__GPIO3_IO19                        0x51e
> +		>;
> +	};
> +
> +	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
> +		fsl,pins = <
> +			MX91_PAD_SD2_CLK__USDHC2_CLK                            0x158e
> +			MX91_PAD_SD2_CMD__USDHC2_CMD                            0x138e
> +			MX91_PAD_SD2_DATA0__USDHC2_DATA0                        0x138e
> +			MX91_PAD_SD2_DATA1__USDHC2_DATA1                        0x138e
> +			MX91_PAD_SD2_DATA2__USDHC2_DATA2                        0x138e
> +			MX91_PAD_SD2_DATA3__USDHC2_DATA3                        0x138e
> +			MX91_PAD_SD2_VSELECT__USDHC2_VSELECT                    0x51e
> +		>;
> +	};
> +
> +	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
> +		fsl,pins = <
> +			MX91_PAD_SD2_CLK__USDHC2_CLK                            0x15fe
> +			MX91_PAD_SD2_CMD__USDHC2_CMD                            0x13fe
> +			MX91_PAD_SD2_DATA0__USDHC2_DATA0                        0x13fe
> +			MX91_PAD_SD2_DATA1__USDHC2_DATA1                        0x13fe
> +			MX91_PAD_SD2_DATA2__USDHC2_DATA2                        0x13fe
> +			MX91_PAD_SD2_DATA3__USDHC2_DATA3                        0x13fe
> +			MX91_PAD_SD2_VSELECT__USDHC2_VSELECT                    0x51e
> +		>;
> +	};
> +
> +	pinctrl_wdog: wdoggrp {
> +		fsl,pins = <
> +			MX91_PAD_WDOG_ANY__WDOG1_WDOG_ANY       0x31e
> +		>;
> +	};
> +};
> +


From xieyuanbin1 at huawei.com  Sun Dec  7 18:32:06 2025
From: xieyuanbin1 at huawei.com (Xie Yuanbin)
Date: Mon, 8 Dec 2025 10:32:06 +0800
Subject: [Bug report] hash_name() may cross page boundary and trigger sleep in RCU context
In-Reply-To: <aTLLLuup7TeAqFVL@shell.armlinux.org.uk>
References: <aTLLLuup7TeAqFVL@shell.armlinux.org.uk>
Message-ID: <20251208023206.44238-1-xieyuanbin1@huawei.com>

On Fri, 5 Dec 2025 12:08:14 +0000, Russell King wrote:
> On Wed, Dec 03, 2025 at 09:48:00AM +0800, Xie Yuanbin wrote:
>> On Tue, 2 Dec 2025 14:07:25 -0800, Linus Torvalds wrote:
>> > On Tue, 2 Dec 2025 at 04:43, Russell King (Oracle)
>> > <linux at armlinux.org.uk> wrote:
>> >>
>> >> What I'm thinking is to address both of these by handling kernel space
>> >> page faults (which will be permission or PTE-not-present) separately
>> >> (not even build tested):
>> >
>> > That patch looks sane to me.
>> >
>> > But I also didn't build test it, just scanned it visually ;)
>>
>> That patch removes harden_branch_predictor() from __do_user_fault(), and
>> moves it to do_page_fault()->do_kernel_address_page_fault().
>> This resolves previously mentioned kernel warning issue. However,
>> __do_user_fault() is not only called by do_page_fault(), it is
>> alse called by do_bad_area(), do_sect_fault() and do_translation_fault().
>>
>> So I think that some harden_branch_predictor() is missing on other paths.
>> According to my tests, when CONFIG_ARM_LPAE=n, harden_branch_predictor()
>> will never be called anymore, even if a user program trys to access the
>> kernel address.
>>
>> Or perhaps I've misunderstood something, could you please point it out?
>> Thank you very much.
>
> Right, let's split these issues into separate patches. Please test this
> patch, which should address only the hash_name() fault issue, and
> provides the basis for fixing the branch predictor issue.

I conducted a simple test, and it seems that both the hash_name()
might sleep issue and the branch predictor issue have been fixed.

BTW, even with this patch, test cases may still fail. There is another
bug in hash_name() will also be triggered by the testcase, which will be
fixed in this patch:
Link: https://lore.kernel.org/20251127025848.363992-1-pangliyuan1 at huawei.com

Test case is from:
Link: https://lore.kernel.org/20251127140109.191657-1-xieyuanbin1 at huawei.com

Test in commit 6987d58a9cbc5bd57c98 ("Add linux-next specific files for
20251205") from linux-next branch.

I still have a question about this patch: Is 
```patch
+		if (interrupts_enabled(regs))
+			local_irq_enable();
```
necessary? Although this implementation is closer to the original code,
which can reduce side effects, do_bad_area(), do_sect_fault(),
and do_translation_fault() all call __do_kernel_fault() with interrupts
disabled.

Thanks very much!


From xueshuai at linux.alibaba.com  Sun Dec  7 18:33:01 2025
From: xueshuai at linux.alibaba.com (Shuai Xue)
Date: Mon, 8 Dec 2025 10:33:01 +0800
Subject: [PATCH rc v2 1/4] iommu/arm-smmu-v3: Add ignored bits to fix STE
 update sequence
In-Reply-To: <0db5caabdcdd8aa170f4c196e94d54664cc87fd3.1765140287.git.nicolinc@nvidia.com>
References: <cover.1765140287.git.nicolinc@nvidia.com>
 <0db5caabdcdd8aa170f4c196e94d54664cc87fd3.1765140287.git.nicolinc@nvidia.com>
Message-ID: <60060fca-b1e7-43d9-b1de-27bc9ec2f43f@linux.alibaba.com>



? 2025/12/8 04:49, Nicolin Chen ??:
> From: Jason Gunthorpe <jgg at nvidia.com>
> 
> C_BAD_STE was observed when updating nested STE from an S1-bypass mode to
> an S1DSS-bypass mode. As both modes enabled S2, the used bit is slightly
> different than the normal S1-bypass and S1DSS-bypass modes. As a result,
> fields like MEV and EATS in S2's used list marked the word1 as a critical
> word that requested a STE.V=0. This breaks a hitless update.
> 
> However, both MEV and EATS aren't critical in terms of STE update. One
> controls the merge of the events and the other controls the ATS that is
> managed by the driver at the same time via pci_enable_ats().
> 
> Add an arm_smmu_get_ste_ignored() to allow STE update algorithm to ignore
> those fields, avoiding the STE update breakages.
> 
> Note that this change is required by both MEV and EATS fields, which were
> introduced in different kernel versions. So add this get_ignored() first.
> The MEV and EATS will be added in arm_smmu_get_ste_ignored() separately.
> 
> Fixes: 1e8be08d1c91 ("iommu/arm-smmu-v3: Support IOMMU_DOMAIN_NESTED")
> Cc: stable at vger.kernel.org
> Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
> Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
> ---

Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>

Thanks.
Shuai



From xueshuai at linux.alibaba.com  Sun Dec  7 18:33:23 2025
From: xueshuai at linux.alibaba.com (Shuai Xue)
Date: Mon, 8 Dec 2025 10:33:23 +0800
Subject: [PATCH rc v2 2/4] iommu/arm-smmu-v3: Ignore STE MEV when
 computing the update sequence
In-Reply-To: <08fd4d48e684732ad58064f690195f31a64979c4.1765140287.git.nicolinc@nvidia.com>
References: <cover.1765140287.git.nicolinc@nvidia.com>
 <08fd4d48e684732ad58064f690195f31a64979c4.1765140287.git.nicolinc@nvidia.com>
Message-ID: <b4d96532-09b5-4162-8d9e-c41ca2baba0b@linux.alibaba.com>



? 2025/12/8 04:49, Nicolin Chen ??:
> From: Jason Gunthorpe <jgg at nvidia.com>
> 
> Nested CD tables set the MEV bit to try to reduce multi-fault spamming on
> the hypervisor. Since MEV is in STE word 1 this causes a breaking update
> sequence that is not required and impacts real workloads.
> 
> For the purposes of STE updates the value of MEV doesn't matter, if it is
> set/cleared early or late it just results in a change to the fault reports
> that must be supported by the kernel anyhow. The spec says:
> 
>   Note: Software must expect, and be able to deal with, coalesced fault
>   records even when MEV == 0.
> 
> So ignore MEV when computing the update sequence to avoid creating a
> breaking update.
> 
> Fixes: da0c56520e88 ("iommu/arm-smmu-v3: Set MEV bit in nested STE for DoS mitigations")
> Cc: stable at vger.kernel.org
> Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
> Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
> ---
>   drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 10 ++++++++++
>   1 file changed, 10 insertions(+)
> 
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index e22c0890041b..3e161d8298d9 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -1085,6 +1085,16 @@ EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_used);
>   VISIBLE_IF_KUNIT
>   void arm_smmu_get_ste_ignored(__le64 *ignored_bits)
>   {
> +	/*
> +	 * MEV does not meaningfully impact the operation of the HW, it only
> +	 * changes how many fault events are generated, thus we can ignore it
> +	 * when computing the ordering. The spec notes the device can act like
> +	 * MEV=1 anyhow:
> +	 *
> +	 *  Note: Software must expect, and be able to deal with, coalesced
> +	 *  fault records even when MEV == 0.
> +	 */
> +	ignored_bits[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
>   }
>   EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_ignored);
>   


Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>

Thanks.
Shuai


From xueshuai at linux.alibaba.com  Sun Dec  7 18:33:40 2025
From: xueshuai at linux.alibaba.com (Shuai Xue)
Date: Mon, 8 Dec 2025 10:33:40 +0800
Subject: [PATCH rc v2 3/4] iommu/arm-smmu-v3: Ignore STE EATS when
 computing the update sequence
In-Reply-To: <b3586cb03317fb2362e936e4d303566851b506d4.1765140287.git.nicolinc@nvidia.com>
References: <cover.1765140287.git.nicolinc@nvidia.com>
 <b3586cb03317fb2362e936e4d303566851b506d4.1765140287.git.nicolinc@nvidia.com>
Message-ID: <0b277ac2-e454-47b8-a592-d9f57936c3fb@linux.alibaba.com>



? 2025/12/8 04:49, Nicolin Chen ??:
> From: Jason Gunthorpe <jgg at nvidia.com>
> 
> If a VM wants to toggle EATS off at the same time as changing the CFG, the
> hypervisor will see EATS change to 0 and insert a V=0 breaking update into
> the STE even though the VM did not ask for that.
> 
> In bare metal, EATS is ignored by CFG=ABORT/BYPASS, which is why this does
> not cause a problem until we have nested where CFG is always a variation of
> S2 trans that does use EATS.
> 
> Relax the rules for EATS sequencing, we don't need it to be exact because
> the enclosing code will always disable ATS at the PCI device if we are
> changing EATS. This ensures there are no ATS transactions that can race
> with an EATS change so we don't need to carefully sequence these bits.
> 
> Fixes: 1e8be08d1c91 ("iommu/arm-smmu-v3: Support IOMMU_DOMAIN_NESTED")
> Cc: stable at vger.kernel.org
> Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
> Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
> ---
>   drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 9 +++++++++
>   1 file changed, 9 insertions(+)
> 
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index 3e161d8298d9..72ba41591fdb 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -1095,6 +1095,15 @@ void arm_smmu_get_ste_ignored(__le64 *ignored_bits)
>   	 *  fault records even when MEV == 0.
>   	 */
>   	ignored_bits[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
> +
> +	/*
> +	 * EATS is used to reject and control the ATS behavior of the device. If
> +	 * we are changing it away from 0 then we already trust the device to
> +	 * use ATS properly and we have sequenced the device's ATS enable in PCI
> +	 * config space to prevent it from issuing ATS while we are changing
> +	 * EATS.
> +	 */
> +	ignored_bits[1] |= cpu_to_le64(STRTAB_STE_1_EATS);
>   }
>   EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_ignored);
>   


Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>

Thanks.
Shuai


From chaoyi.chen at rock-chips.com  Sun Dec  7 18:48:24 2025
From: chaoyi.chen at rock-chips.com (Chaoyi Chen)
Date: Mon, 8 Dec 2025 10:48:24 +0800
Subject: [PATCH v2 5/8] drm/rockchip: vop2: Enforce AFBC source alignment
 in plane_check
In-Reply-To: <20251206-vop2-atomic-fixups-v2-5-7fb45bbfbebd@collabora.com>
References: <20251206-vop2-atomic-fixups-v2-0-7fb45bbfbebd@collabora.com>
 <20251206-vop2-atomic-fixups-v2-5-7fb45bbfbebd@collabora.com>
Message-ID: <f9f7b446-8575-4f16-aa96-5197b22846e3@rock-chips.com>

Hello Nicolas, Daniel,

On 12/7/2025 4:45 AM, Nicolas Frattaroli wrote:
> From: Daniel Stone <daniels at collabora.com>
> 
> Planes can only source AFBC framebuffers at multiples of 4px wide on
> RK3566/RK3568. Instead of clipping on all SoCs when the user asks for an
> unaligned source rectangle, reject the configuration in the plane's
> atomic check on RK3566/RK3568 only.
> 
> Signed-off-by: Daniel Stone <daniels at collabora.com>
> [Make RK3566/RK3568 specific, reword message]
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
> ---
>  drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 14 +++++++++-----
>  1 file changed, 9 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> index bc1ed0ffede0..e23213337104 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> @@ -1076,6 +1076,13 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
>  		return -EINVAL;
>  	}
>  
> +	if (vop2->version == VOP_VERSION_RK3568 && drm_is_afbc(fb->modifier) && src_w % 4) {
> +		drm_dbg_kms(vop2->drm,
> +			    "AFBC source rectangles must be 4-byte aligned; is %d\n",
> +			    src_w);
> +		return -EINVAL;
> +	}
> +
>  	return 0;
>  }
>  
> @@ -1237,11 +1244,8 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
>  	WARN_ON(src_w < 4);
>  	WARN_ON(src_h < 4);
>  
> -	if (afbc_en && src_w % 4) {
> -		drm_dbg_kms(vop2->drm, "vp%d %s src_w[%d] not 4 pixel aligned\n",
> -			    vp->id, win->data->name, src_w);
> -		src_w = ALIGN_DOWN(src_w, 4);
> -	}
> +	if (vop2->version == VOP_VERSION_RK3568 && drm_is_afbc(fb->modifier))
> +		WARN_ON(src_w % 4);
>  
>  	act_info = (src_h - 1) << 16 | ((src_w - 1) & 0xffff);
>  	dsp_info = (dsp_h - 1) << 16 | ((dsp_w - 1) & 0xffff);
> 

You haven't replied to Andy's comment yet [0].

[0] https://lore.kernel.org/dri-devel/7b4e26ec.75f3.19a77276b53.Coremail.andyshrk at 163.com/

-- 
Best, 
Chaoyi


From jacky_chou at aspeedtech.com  Sun Dec  7 19:01:10 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Mon, 8 Dec 2025 03:01:10 +0000
Subject: [PATCH v6 0/7] Add ASPEED PCIe Root Complex support
In-Reply-To: <20251206000806.GA969079-robh@kernel.org>
References: <20251201-upstream_pcie_rc-v6-0-8c8800c56b16@aspeedtech.com>
 <20251204195355.GA1975043-robh@kernel.org>
 <SEYPR06MB5134D0D5911E3C86D869151E9DA7A@SEYPR06MB5134.apcprd06.prod.outlook.com>
 <20251206000806.GA969079-robh@kernel.org>
Message-ID: <SEYPR06MB5134B4BF81E81717379797649DA2A@SEYPR06MB5134.apcprd06.prod.outlook.com>

> > May I confirm whether the pcie at 8,0 in aspeed-g6.dtsi is not considered
> > the root port? From my understanding, that node represents the root
> > port, so I want to make sure I'm aligning with your expectation before
> updating the binding.
> 
> I believe you told me it was the root port.
> 
> > Could you help clarify how you would like the root port and its
> > properties to be described in the schema?
> 
> properties:
>   pcie at 8,0:
>     $ref: /schemas/pci/pci-pci-bridge.yaml#
>     unevaluatedProperties: false
> 
>     properties:
> 
> And then add all the properties you have which are not defined in
> pci-pci-bridge.yaml (and pci-device.yaml by reference) (i.e. clocks, resets, phys,
> etc.).
> 

I understand your point now. I will update the binding and the corresponding DT 
node accordingly in the next revision.

Thanks again for your guidance.

Thanks,
Jacky


From jacky_chou at aspeedtech.com  Sun Dec  7 19:13:24 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Mon, 8 Dec 2025 03:13:24 +0000
Subject: [PATCH net-next] net: mdio: aspeed: add dummy read to avoid
 read-after-write issue
In-Reply-To: <230147e8-e27b-48e1-9a62-7aa8abc3f492@lunn.ch>
References: <20251205-aspeed_mdio_add_dummy_read-v1-1-60145ae20ea7@aspeedtech.com>
 <230147e8-e27b-48e1-9a62-7aa8abc3f492@lunn.ch>
Message-ID: <SEYPR06MB5134571388AC51EEAC45AF739DA2A@SEYPR06MB5134.apcprd06.prod.outlook.com>

Hi Andrew,

Thank you for your reply

> > The Aspeed MDIO controller may return incorrect data when a read
> > operation follows immediately after a write. Due to a controller bug,
> > the subsequent read can latch stale data, causing the polling logic to
> > terminate earlier than expected.
> >
> > To work around this hardware issue, insert a dummy read after each
> > write operation. This ensures that the next actual read returns the
> > correct data and prevents premature polling exit.
> >
> > This workaround has been verified to stabilize MDIO transactions on
> > affected Aspeed platforms.
> >
> > Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
> 
> This seems like a bug fix. Please add a Fixes: tag, for base it on net, not
> net-next.
> 

Yes, it is a bug fix on HW design.
I will send it to net again and add Fixes tag.

> > ---
> >  drivers/net/mdio/mdio-aspeed.c | 6 ++++++
> >  1 file changed, 6 insertions(+)
> >
> > diff --git a/drivers/net/mdio/mdio-aspeed.c
> > b/drivers/net/mdio/mdio-aspeed.c index e55be6dc9ae7..00e61b922876
> > 100644
> > --- a/drivers/net/mdio/mdio-aspeed.c
> > +++ b/drivers/net/mdio/mdio-aspeed.c
> > @@ -62,6 +62,12 @@ static int aspeed_mdio_op(struct mii_bus *bus, u8 st,
> u8 op, u8 phyad, u8 regad,
> >  		| FIELD_PREP(ASPEED_MDIO_DATA_MIIRDATA, data);
> >
> >  	iowrite32(ctrl, ctx->base + ASPEED_MDIO_CTRL);
> > +	/* Workaround for read-after-write issue.
> 
> Blank line before the comment please.
> 

Agreed.

Thanks,
Jacky


From xueshuai at linux.alibaba.com  Sun Dec  7 19:43:41 2025
From: xueshuai at linux.alibaba.com (Shuai Xue)
Date: Mon, 8 Dec 2025 11:43:41 +0800
Subject: [PATCH rc v2 4/4] iommu/arm-smmu-v3-test: Add nested
 s1bypass/s1dssbypass coverage
In-Reply-To: <b6d87901f89c05dd9e1d0c1e819040d205f569a7.1765140287.git.nicolinc@nvidia.com>
References: <cover.1765140287.git.nicolinc@nvidia.com>
 <b6d87901f89c05dd9e1d0c1e819040d205f569a7.1765140287.git.nicolinc@nvidia.com>
Message-ID: <f52c705d-6032-4d85-b902-dd6d0a40b9ec@linux.alibaba.com>



? 2025/12/8 04:49, Nicolin Chen ??:
> STE in a nested case requires both S1 and S2 fields. And this makes the use
> case different from the existing one.
> 
> Add coverage for previously failed cases shifting between S2-only and S1+S2
> STEs.
> 
> Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
> ---
>   .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  | 61 +++++++++++++++++++
>   1 file changed, 61 insertions(+)
> 
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> index 3556e65cf9ac..1672e75ebffc 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> @@ -555,6 +555,65 @@ static void arm_smmu_v3_write_ste_test_s2_to_s1_stall(struct kunit *test)
>   						       NUM_EXPECTED_SYNCS(3));
>   }
>   
> +static void arm_smmu_test_make_nested_cdtable_ste(
> +	struct arm_smmu_ste *ste, unsigned int s1dss, const dma_addr_t dma_addr,
> +	enum arm_smmu_test_master_feat feat)
> +{
> +	bool stall_enabled = feat & ARM_SMMU_MASTER_TEST_STALL;
> +	bool ats_enabled = feat & ARM_SMMU_MASTER_TEST_ATS;
> +	struct arm_smmu_ste s1ste;
> +
> +	struct arm_smmu_master master = {
> +		.ats_enabled = ats_enabled,
> +		.cd_table.cdtab_dma = dma_addr,
> +		.cd_table.s1cdmax = 0xFF,
> +		.cd_table.s1fmt = STRTAB_STE_0_S1FMT_64K_L2,
> +		.smmu = &smmu,
> +		.stall_enabled = stall_enabled,
> +	};
> +
> +	arm_smmu_test_make_s2_ste(ste, ARM_SMMU_MASTER_TEST_ATS);
> +	arm_smmu_make_cdtable_ste(&s1ste, &master, ats_enabled, s1dss);

Hi, Nicolin,

Nit. Instead of duplicating this code, we can leverage the existing
arm_smmu_test_make_cdtable_ste() helper here.

> +
> +	ste->data[0] = cpu_to_le64(
> +		STRTAB_STE_0_V |
> +		FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_NESTED));
> +	ste->data[0] |= s1ste.data[0] & ~cpu_to_le64(STRTAB_STE_0_CFG);
> +	ste->data[1] |= s1ste.data[1];
> +	/* Merge events for DoS mitigations on eventq */
> +	ste->data[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
> +}
> +
> +static void
> +arm_smmu_v3_write_ste_test_nested_s1dssbypass_to_s1bypass(struct kunit *test)
> +{
> +	struct arm_smmu_ste s1_ste;
> +	struct arm_smmu_ste s2_ste;
> +
> +	arm_smmu_test_make_nested_cdtable_ste(&s1_ste,
> +					      STRTAB_STE_1_S1DSS_BYPASS,
> +					      fake_cdtab_dma_addr,
> +					      ARM_SMMU_MASTER_TEST_ATS);
> +	arm_smmu_test_make_s2_ste(&s2_ste, 0);
> +	arm_smmu_v3_test_ste_expect_hitless_transition(test, &s1_ste, &s2_ste,
> +						       NUM_EXPECTED_SYNCS(3));
> +}
> +
> +static void
> +arm_smmu_v3_write_ste_test_nested_s1bypass_to_s1dssbypass(struct kunit *test)
> +{
> +	struct arm_smmu_ste s1_ste;
> +	struct arm_smmu_ste s2_ste;
> +
> +	arm_smmu_test_make_nested_cdtable_ste(&s1_ste,
> +					      STRTAB_STE_1_S1DSS_BYPASS,
> +					      fake_cdtab_dma_addr,
> +					      ARM_SMMU_MASTER_TEST_ATS);
> +	arm_smmu_test_make_s2_ste(&s2_ste, 0);
> +	arm_smmu_v3_test_ste_expect_hitless_transition(test, &s2_ste, &s1_ste,
> +						       NUM_EXPECTED_SYNCS(2));

It would be better to add comments explaining why the number of syncs differs
between the reverse transitions.

> +}
> +
>   static void arm_smmu_v3_write_cd_test_sva_clear(struct kunit *test)
>   {
>   	struct arm_smmu_cd cd = {};
> @@ -601,6 +660,8 @@ static struct kunit_case arm_smmu_v3_test_cases[] = {
>   	KUNIT_CASE(arm_smmu_v3_write_cd_test_s1_change_asid),
>   	KUNIT_CASE(arm_smmu_v3_write_ste_test_s1_to_s2_stall),
>   	KUNIT_CASE(arm_smmu_v3_write_ste_test_s2_to_s1_stall),
> +	KUNIT_CASE(arm_smmu_v3_write_ste_test_nested_s1dssbypass_to_s1bypass),
> +	KUNIT_CASE(arm_smmu_v3_write_ste_test_nested_s1bypass_to_s1dssbypass),
>   	KUNIT_CASE(arm_smmu_v3_write_cd_test_sva_clear),
>   	KUNIT_CASE(arm_smmu_v3_write_cd_test_sva_release),
>   	{},

Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>

Thanks.
Shuai


From zhanjie9 at hisilicon.com  Sun Dec  7 20:02:16 2025
From: zhanjie9 at hisilicon.com (Jie Zhan)
Date: Mon, 8 Dec 2025 12:02:16 +0800
Subject: [PATCH v4 1/3] ACPI: CPPC: Factor out and export per-cpu
 cppc_perf_ctrs_in_pcc_cpu()
In-Reply-To: <CAJZ5v0jvk+gs+h+76__LLZDa=OGzLxQQsWEMDHXzeV8aV6UYsA@mail.gmail.com>
References: <20251203032422.3232957-1-zhanjie9@hisilicon.com>
 <20251203032422.3232957-2-zhanjie9@hisilicon.com>
 <CAJZ5v0jvk+gs+h+76__LLZDa=OGzLxQQsWEMDHXzeV8aV6UYsA@mail.gmail.com>
Message-ID: <adeb19a3-da4a-41e9-948c-dac7002d034a@hisilicon.com>



On 12/5/2025 11:13 PM, Rafael J. Wysocki wrote:
> On Wed, Dec 3, 2025 at 4:25?AM Jie Zhan <zhanjie9 at hisilicon.com> wrote:
>>
>> Factor out cppc_perf_ctrs_in_pcc_cpu() for checking whether per-cpu CPC
>> regs are defined in PCC channels, and export it out for further use.
>>
>> Signed-off-by: Jie Zhan <zhanjie9 at hisilicon.com>
>> ---
>>  drivers/acpi/cppc_acpi.c | 45 +++++++++++++++++++++-------------------
>>  include/acpi/cppc_acpi.h |  5 +++++
>>  2 files changed, 29 insertions(+), 21 deletions(-)
>>
>> diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
>> index 3bdeeee3414e..aa80dbcf42c0 100644
>> --- a/drivers/acpi/cppc_acpi.c
>> +++ b/drivers/acpi/cppc_acpi.c
>> @@ -1422,6 +1422,29 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
>>  }
>>  EXPORT_SYMBOL_GPL(cppc_get_perf_caps);
>>
>> +bool cppc_perf_ctrs_in_pcc_cpu(unsigned int cpu)
>> +{
>> +       struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu);
>> +       struct cpc_register_resource *ref_perf_reg;
>> +
>> +       /*
>> +        * If reference perf register is not supported then we should use the
>> +        * nominal perf value
>> +        */
>> +       ref_perf_reg = &cpc_desc->cpc_regs[REFERENCE_PERF];
>> +       if (!CPC_SUPPORTED(ref_perf_reg))
>> +               ref_perf_reg = &cpc_desc->cpc_regs[NOMINAL_PERF];
>> +
>> +       if (CPC_IN_PCC(&cpc_desc->cpc_regs[DELIVERED_CTR]) ||
>> +           CPC_IN_PCC(&cpc_desc->cpc_regs[REFERENCE_CTR]) ||
>> +           CPC_IN_PCC(&cpc_desc->cpc_regs[CTR_WRAP_TIME]) ||
>> +           CPC_IN_PCC(ref_perf_reg))
>> +               return true;
>> +
>> +       return false;
> 
> Why not
> 
> return CPC_IN_PCC(&cpc_desc->cpc_regs[DELIVERED_CTR]) ||
>           CPC_IN_PCC(&cpc_desc->cpc_regs[REFERENCE_CTR]) ||
>           CPC_IN_PCC(&cpc_desc->cpc_regs[CTR_WRAP_TIME]) ||
>           CPC_IN_PCC(ref_perf_reg);
> 
Yes, that would save a few more lines.
Thanks!


From anshuman.khandual at arm.com  Sun Dec  7 20:42:06 2025
From: anshuman.khandual at arm.com (Anshuman Khandual)
Date: Mon, 8 Dec 2025 10:12:06 +0530
Subject: [PATCH v9 01/16] arm64: Remove unused _TIF_WORK_MASK
In-Reply-To: <20251204082123.2792067-2-ruanjinjie@huawei.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
 <20251204082123.2792067-2-ruanjinjie@huawei.com>
Message-ID: <b88a2a99-44c5-41bf-b986-fb3ca996e580@arm.com>

On 04/12/25 1:51 PM, Jinjie Ruan wrote:
> Since commit b3cf07851b6c ("arm64: entry: Switch to generic IRQ
> entry"), _TIF_WORK_MASK is never used, so remove it.
> 
> Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
> ---
>  arch/arm64/include/asm/thread_info.h | 6 ------
>  1 file changed, 6 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
> index f241b8601ebd..ff4998fa1844 100644
> --- a/arch/arm64/include/asm/thread_info.h
> +++ b/arch/arm64/include/asm/thread_info.h
> @@ -106,12 +106,6 @@ void arch_setup_new_exec(void);
>  #define _TIF_NOTIFY_SIGNAL	(1 << TIF_NOTIFY_SIGNAL)
>  #define _TIF_TSC_SIGSEGV	(1 << TIF_TSC_SIGSEGV)
>  
> -#define _TIF_WORK_MASK		(_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY | \
> -				 _TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE | \
> -				 _TIF_UPROBE | _TIF_MTE_ASYNC_FAULT | \
> -				 _TIF_NOTIFY_SIGNAL | _TIF_SIGPENDING | \
> -				 _TIF_PATCH_PENDING)
> -
>  #define _TIF_SYSCALL_WORK	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
>  				 _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \
>  				 _TIF_SYSCALL_EMU)

There are no more _TIF_WORK_MASK users left on arm64 platform.
 
Reviewed-by: Anshuman Khandual <anshuman.khandual at arm.com>


From brgl at kernel.org  Sun Dec  7 20:48:27 2025
From: brgl at kernel.org (Bartosz Golaszewski)
Date: Sun, 7 Dec 2025 20:48:27 -0800
Subject: [PATCH 05/12] gpio: it87: use new line value setter callbacks
In-Reply-To: <bd0a00e3-9b8c-43e8-8772-e67b91f4c71e@gibson.sh>
References: <20250423-gpiochip-set-rv-gpio-part2-v1-0-b22245cde81a@linaro.org>
 <20250423-gpiochip-set-rv-gpio-part2-v1-5-b22245cde81a@linaro.org> <bd0a00e3-9b8c-43e8-8772-e67b91f4c71e@gibson.sh>
Message-ID: <CAMRc=Mc8ViSPyTn9Brr-us2V+D7Jv3u+B8Ek2nuzF36yH70RAw@mail.gmail.com>

On Sun, 7 Dec 2025 05:55:15 +0100, Daniel Gibson <daniel at gibson.sh> said:
> Hi,
> I got one nitpick/question about this, see below
>
> On 4/23/25 09:15, Bartosz Golaszewski wrote:
>> @@ -249,7 +250,9 @@ static int it87_gpio_direction_out(struct gpio_chip *chip,
>>  	/* set the output enable bit */
>>  	superio_set_mask(mask, group + it87_gpio->output_base);
>>
>> -	it87_gpio_set(chip, gpio_num, val);
>> +	rc = it87_gpio_set(chip, gpio_num, val);
>> +	if (rc)
>> +		goto exit;
>>  >  	superio_exit();
>
> Are you sure that superio_exit() should be skipped (with goto exit) in
> case it87_gpio_set() fails?
> After all, superio_enter() above (not visible here) succeeded,
> only the it87_gpio_set() call failed.
>
> Of course this is kinda academic because currently it87_gpio_set()
> always returns 0, but if it ever doesn't, this might become a bug?
>

Thanks for bringing it to my attention, you're probably right and thats's
just an unintentional omission on my part. Do you want to send a patch that
will fix it or do you prefer me to do it?

Bart


From anshuman.khandual at arm.com  Sun Dec  7 21:02:12 2025
From: anshuman.khandual at arm.com (Anshuman Khandual)
Date: Mon, 8 Dec 2025 10:32:12 +0530
Subject: [PATCH v9 02/16] arm64/ptrace: Split report_syscall()
In-Reply-To: <20251204082123.2792067-3-ruanjinjie@huawei.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
 <20251204082123.2792067-3-ruanjinjie@huawei.com>
Message-ID: <b66f285f-20d8-4c29-ad0d-1ab0857b38b0@arm.com>

On 04/12/25 1:51 PM, Jinjie Ruan wrote:
> The generic syscall entry code has the form:
> 
> | syscall_trace_enter()
> | {
> |	ptrace_report_syscall_entry()
> | }
> |
> | syscall_exit_work()
> | {
> |	ptrace_report_syscall_exit()
> | }
> 
> In preparation for moving arm64 over to the generic entry code, split
> report_syscall() to two separate enter and exit functions to align
> the structure of the arm64 code with syscall_trace_enter() and
> syscall_exit_work() from the generic entry code.
> 
> No functional changes.
> 
> Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
> Suggested-by: Mark Rutland <mark.rutland at arm.com>
> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>

LGTM.

Reviewed-by: Anshuman Khandual <anshuman.khandual at arm.com>

> ---
> v8:
> - report_syscall_enter() -> report_syscall_entry().
> - Add ptrace_save_reg() helper.
> ---
>  arch/arm64/kernel/ptrace.c | 41 +++++++++++++++++++++++++++-----------
>  1 file changed, 29 insertions(+), 12 deletions(-)
> 
> diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
> index 4b001121c72d..4532e9831856 100644
> --- a/arch/arm64/kernel/ptrace.c
> +++ b/arch/arm64/kernel/ptrace.c
> @@ -2317,9 +2317,10 @@ enum ptrace_syscall_dir {
>  	PTRACE_SYSCALL_EXIT,
>  };
>  
> -static void report_syscall(struct pt_regs *regs, enum ptrace_syscall_dir dir)
> +static __always_inline unsigned long ptrace_save_reg(struct pt_regs *regs,
> +						     enum ptrace_syscall_dir dir,
> +						     int *regno)
>  {
> -	int regno;
>  	unsigned long saved_reg;
>  
>  	/*
> @@ -2338,15 +2339,31 @@ static void report_syscall(struct pt_regs *regs, enum ptrace_syscall_dir dir)
>  	 * - Syscall stops behave differently to seccomp and pseudo-step traps
>  	 *   (the latter do not nobble any registers).
>  	 */
> -	regno = (is_compat_task() ? 12 : 7);
> -	saved_reg = regs->regs[regno];
> -	regs->regs[regno] = dir;
> +	*regno = (is_compat_task() ? 12 : 7);
> +	saved_reg = regs->regs[*regno];
> +	regs->regs[*regno] = dir;
>  
> -	if (dir == PTRACE_SYSCALL_ENTER) {
> -		if (ptrace_report_syscall_entry(regs))
> -			forget_syscall(regs);
> -		regs->regs[regno] = saved_reg;
> -	} else if (!test_thread_flag(TIF_SINGLESTEP)) {
> +	return saved_reg;
> +}
> +
> +static void report_syscall_entry(struct pt_regs *regs)
> +{
> +	unsigned long saved_reg;
> +	int regno;
> +
> +	saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_ENTER, &regno);
> +	if (ptrace_report_syscall_entry(regs))
> +		forget_syscall(regs);
> +	regs->regs[regno] = saved_reg;
> +}
> +
> +static void report_syscall_exit(struct pt_regs *regs)
> +{
> +	unsigned long saved_reg;
> +	int regno;
> +
> +	saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_EXIT, &regno);
> +	if (!test_thread_flag(TIF_SINGLESTEP)) {
>  		ptrace_report_syscall_exit(regs, 0);
>  		regs->regs[regno] = saved_reg;
>  	} else {
> @@ -2366,7 +2383,7 @@ int syscall_trace_enter(struct pt_regs *regs)
>  	unsigned long flags = read_thread_flags();
>  
>  	if (flags & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE)) {
> -		report_syscall(regs, PTRACE_SYSCALL_ENTER);
> +		report_syscall_entry(regs);
>  		if (flags & _TIF_SYSCALL_EMU)
>  			return NO_SYSCALL;
>  	}
> @@ -2394,7 +2411,7 @@ void syscall_trace_exit(struct pt_regs *regs)
>  		trace_sys_exit(regs, syscall_get_return_value(current, regs));
>  
>  	if (flags & (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP))
> -		report_syscall(regs, PTRACE_SYSCALL_EXIT);
> +		report_syscall_exit(regs);
>  
>  	rseq_syscall(regs);
>  }



From anshuman.khandual at arm.com  Sun Dec  7 21:24:34 2025
From: anshuman.khandual at arm.com (Anshuman Khandual)
Date: Mon, 8 Dec 2025 10:54:34 +0530
Subject: [PATCH v9 03/16] arm64/ptrace: Return early for
 ptrace_report_syscall_entry() error
In-Reply-To: <20251204082123.2792067-4-ruanjinjie@huawei.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
 <20251204082123.2792067-4-ruanjinjie@huawei.com>
Message-ID: <7c7e5c66-f618-466f-b353-54fad71c0e14@arm.com>

On 04/12/25 1:51 PM, Jinjie Ruan wrote:
> The generic entry abort the syscall_trace_enter() sequence if
> ptrace_report_syscall_entry() errors out, but arm64 not.
> 
> As the ptrace_report_syscall_entry() comment said, the calling arch code
> should abort the system call and must prevent normal entry so no system
> call is made if ptrace_report_syscall_entry() return nonzero.
> 
> In preparation for moving arm64 over to the generic entry code,
> return early if ptrace_report_syscall_entry() encounters an error.
> 
> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
> ---
>  arch/arm64/kernel/ptrace.c | 14 +++++++++-----
>  1 file changed, 9 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
> index 4532e9831856..3926ce6aa268 100644
> --- a/arch/arm64/kernel/ptrace.c
> +++ b/arch/arm64/kernel/ptrace.c
> @@ -2346,15 +2346,18 @@ static __always_inline unsigned long ptrace_save_reg(struct pt_regs *regs,
>  	return saved_reg;
>  }
>  
> -static void report_syscall_entry(struct pt_regs *regs)
> +static int report_syscall_entry(struct pt_regs *regs)
>  {
>  	unsigned long saved_reg;
> -	int regno;
> +	int regno, ret;
>  
>  	saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_ENTER, &regno);
> -	if (ptrace_report_syscall_entry(regs))
> +	ret = ptrace_report_syscall_entry(regs);
> +	if (ret)
>  		forget_syscall(regs);
>  	regs->regs[regno] = saved_reg;
> +
> +	return ret;
>  }
>  
>  static void report_syscall_exit(struct pt_regs *regs)
> @@ -2381,10 +2384,11 @@ static void report_syscall_exit(struct pt_regs *regs)
>  int syscall_trace_enter(struct pt_regs *regs)
>  {
>  	unsigned long flags = read_thread_flags();
> +	int ret;
>  
>  	if (flags & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE)) {
> -		report_syscall_entry(regs);
> -		if (flags & _TIF_SYSCALL_EMU)
> +		ret = report_syscall_entry(regs);
> +		if (ret || (flags & _TIF_SYSCALL_EMU))

A small nit.

Could report_syscall_entry(regs) be checked directly in the 'if' conditional
code block thus dropping new 'ret' altogether ?

>  			return NO_SYSCALL;
>  	}
>  



From cassel at kernel.org  Sun Dec  7 21:45:59 2025
From: cassel at kernel.org (Niklas Cassel)
Date: Mon, 8 Dec 2025 06:45:59 +0100
Subject: [PATCH v2] PCI: dwc: Make Link Up IRQ logic handle already
 powered on PCIe switches
In-Reply-To: <20251201063634.4115762-2-cassel@kernel.org>
References: <20251201063634.4115762-2-cassel@kernel.org>
Message-ID: <aTZmF5AEJQhQld4Y@ryzen>

On Mon, Dec 01, 2025 at 07:36:35AM +0100, Niklas Cassel wrote:

Mani, could you perhaps try this series on Qcom?

I personally prefer this series over a revert because:
It allows to us to still use a PCIe endpoint that comes up after the
main system has booted, e.g. when the PCIe endpoint is a board running
pci-epf-test, without the need for a manual rescan on be bus.

If we go with revert instead, this very nice feature would be gone,
and the user would need to do a manual rescan of the bus.

One could even argue that that is a user visible regression.


Kind regards,
Niklas


From anshuman.khandual at arm.com  Sun Dec  7 21:48:14 2025
From: anshuman.khandual at arm.com (Anshuman Khandual)
Date: Mon, 8 Dec 2025 11:18:14 +0530
Subject: [PATCH v9 04/16] arm64/ptrace: Refactor
 syscall_trace_enter/exit()
In-Reply-To: <20251204082123.2792067-5-ruanjinjie@huawei.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
 <20251204082123.2792067-5-ruanjinjie@huawei.com>
Message-ID: <dd3a1421-dfb0-445e-b2f7-7c273fa4a020@arm.com>

On 04/12/25 1:51 PM, Jinjie Ruan wrote:
> The generic syscall entry code has the following form, which use
> the input syscall work flag and syscall number:
> 
> | syscall_trace_enter(struct pt_regs *regs, long syscall,
> |		      unsigned long work)
> |
> | syscall_exit_work(struct pt_regs *regs, unsigned long work)
> 
> In preparation for moving arm64 over to the generic entry code,
> refactor syscall_trace_enter/exit() to also pass thread flags, and
> get syscall number by syscall_get_nr() helper.
> 
> No functional changes.
> 
> Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
> ---
>  arch/arm64/include/asm/syscall.h |  4 ++--
>  arch/arm64/kernel/ptrace.c       | 25 ++++++++++++++++---------
>  arch/arm64/kernel/syscall.c      |  5 +++--
>  3 files changed, 21 insertions(+), 13 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
> index 5e4c7fc44f73..cef1d9ce6e1b 100644
> --- a/arch/arm64/include/asm/syscall.h
> +++ b/arch/arm64/include/asm/syscall.h
> @@ -120,7 +120,7 @@ static inline int syscall_get_arch(struct task_struct *task)
>  	return AUDIT_ARCH_AARCH64;
>  }
>  
> -int syscall_trace_enter(struct pt_regs *regs);
> -void syscall_trace_exit(struct pt_regs *regs);
> +int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags);
> +void syscall_trace_exit(struct pt_regs *regs, unsigned long flags);
>  
>  #endif	/* __ASM_SYSCALL_H */
> diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
> index 3926ce6aa268..b962cbcca11d 100644
> --- a/arch/arm64/kernel/ptrace.c
> +++ b/arch/arm64/kernel/ptrace.c
> @@ -2381,9 +2381,8 @@ static void report_syscall_exit(struct pt_regs *regs)
>  	}
>  }
>  
> -int syscall_trace_enter(struct pt_regs *regs)
> +int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags)
>  {
> -	unsigned long flags = read_thread_flags();
>  	int ret;
>  
>  	if (flags & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE)) {
> @@ -2396,19 +2395,27 @@ int syscall_trace_enter(struct pt_regs *regs)
>  	if (secure_computing() == -1)
>  		return NO_SYSCALL;
>  
> -	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> -		trace_sys_enter(regs, regs->syscallno);
> +	/* Either of the above might have changed the syscall number */
> +	syscall = syscall_get_nr(current, regs);
>  
> -	audit_syscall_entry(regs->syscallno, regs->orig_x0, regs->regs[1],
> +	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) {
> +		trace_sys_enter(regs, syscall);
> +
> +		/*
> +		 * Probes or BPF hooks in the tracepoint may have changed the
> +		 * system call number as well.
> +		 */
> +		 syscall = syscall_get_nr(current, regs);
> +	}
> +
> +	audit_syscall_entry(syscall, regs->orig_x0, regs->regs[1],
>  			    regs->regs[2], regs->regs[3]);
>  
> -	return regs->syscallno;
> +	return syscall;

regs->syscallno still remains unchanged even if syscall is evaluated to be different ?

>  }
>  
> -void syscall_trace_exit(struct pt_regs *regs)
> +void syscall_trace_exit(struct pt_regs *regs, unsigned long flags)
>  {
> -	unsigned long flags = read_thread_flags();
> -
>  	audit_syscall_exit(regs);
>  
>  	if (flags & _TIF_SYSCALL_TRACEPOINT)
> diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
> index aba7ca6bca2d..ec31f82d2e9f 100644
> --- a/arch/arm64/kernel/syscall.c
> +++ b/arch/arm64/kernel/syscall.c
> @@ -124,7 +124,7 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
>  		 */
>  		if (scno == NO_SYSCALL)
>  			syscall_set_return_value(current, regs, -ENOSYS, 0);
> -		scno = syscall_trace_enter(regs);
> +		scno = syscall_trace_enter(regs, scno, flags);
>  		if (scno == NO_SYSCALL)
>  			goto trace_exit;
>  	}
> @@ -143,7 +143,8 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
>  	}
>  
>  trace_exit:
> -	syscall_trace_exit(regs);
> +	flags = read_thread_flags();
> +	syscall_trace_exit(regs, flags);
>  }
>  
>  void do_el0_svc(struct pt_regs *regs)



From krzk at kernel.org  Sun Dec  7 22:09:16 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 8 Dec 2025 07:09:16 +0100
Subject: [PATCH 2/4] pwm: sun50i: Add H616 PWM support
In-Reply-To: <20251205100239.1563353-3-richard.genoud@bootlin.com>
References: <20251205100239.1563353-1-richard.genoud@bootlin.com>
 <20251205100239.1563353-3-richard.genoud@bootlin.com>
Message-ID: <b5731ee5-8a16-40f1-8418-07c45a97c609@kernel.org>

On 05/12/2025 11:02, Richard Genoud wrote:
> +static struct platform_driver h616_pwm_driver = {
> +	.driver = {
> +		.name = "h616-pwm",
> +		.of_match_table = h616_pwm_dt_ids,
> +	},
> +	.probe = h616_pwm_probe,
> +};
> +module_platform_driver(h616_pwm_driver);
> +
> +MODULE_ALIAS("platform:h616-pwm");

You should not need MODULE_ALIAS() in normal cases. If you need it,
usually it means your device ID table is wrong (e.g. misses either
entries or MODULE_DEVICE_TABLE()). MODULE_ALIAS() is not a substitute
for incomplete ID table.


> +MODULE_AUTHOR("Richard Genoud <richard.genoud at bootlin.com>");
> +MODULE_DESCRIPTION("Allwinner H616 PWM driver");
> +MODULE_LICENSE("GPL");


Best regards,
Krzysztof


From victor.liu at nxp.com  Sun Dec  7 22:14:27 2025
From: victor.liu at nxp.com (Liu Ying)
Date: Mon, 8 Dec 2025 14:14:27 +0800
Subject: [PATCH v7 1/3] dt-bindings: soc: imx93-media-blk-ctrl: Add PDFC
 subnode to schema and example
In-Reply-To: <20251202-v6-18-topic-imx93-parallel-display-v7-1-2cce31d64608@pengutronix.de>
References: <20251202-v6-18-topic-imx93-parallel-display-v7-0-2cce31d64608@pengutronix.de>
 <20251202-v6-18-topic-imx93-parallel-display-v7-1-2cce31d64608@pengutronix.de>
Message-ID: <705773fc-5aba-4bff-b05e-272e1cd0262c@nxp.com>

Hi Marco,

On 12/02/2025, Marco Felsch wrote:
> From: Liu Ying <victor.liu at nxp.com>
> 
> i.MX93 SoC mediamix blk-ctrl contains one DISPLAY_MUX register which
> configures parallel display format by using the "PARALLEL_DISP_FORMAT"
> field. Document the Parallel Display Format Configuration(PDFC) subnode
> and add the subnode to example.
> 
> Signed-off-by: Liu Ying <victor.liu at nxp.com>
> [m.felsch at pengutronix.de: port to v6.18-rc1]
> [m.felsch at pengutronix.de: add bus-width]
> Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
> ---
>  .../bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml | 92 ++++++++++++++++++++++
>  1 file changed, 92 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> index 34aea58094e55365a2f9c86092f637e533f954ff..6e2d86d9341c75108b492bcbabc8a560d8e707cd 100644
> --- a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> +++ b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> @@ -26,6 +26,12 @@ properties:
>    reg:
>      maxItems: 1
>  
> +  '#address-cells':
> +    const: 1
> +
> +  '#size-cells':
> +    const: 1
> +
>    '#power-domain-cells':
>      const: 1
>  
> @@ -40,6 +46,60 @@ properties:
>      minItems: 8
>      maxItems: 10
>  
> +  bridge at 60:

The dependency patch series mentioned in cover letter has two links in it's
cover letter.  Reading the patch sets pointed by the two links, we may find
Krzysztof's comments - the child nodes of the blk-ctrl should be completely
documented.

> +    type: object
> +    additionalProperties: false
> +
> +    properties:
> +      compatible:
> +        const: nxp,imx93-pdfc
> +
> +      reg:
> +        maxItems: 1
> +
> +      ports:
> +        $ref: /schemas/graph.yaml#/properties/ports
> +
> +        properties:
> +          port at 0:
> +            $ref: /schemas/graph.yaml#/properties/port
> +            description: Input port node to receive pixel data.
> +
> +          port at 1:
> +            $ref: /schemas/graph.yaml#/$defs/port-base
> +            unevaluatedProperties: false
> +            description: Output port node to downstream pixel data receivers.
> +
> +            properties:
> +              endpoint:
> +                $ref: /schemas/graph.yaml#/$defs/endpoint-base
> +                unevaluatedProperties: false
> +
> +                properties:
> +                  bus-width:

In v1-v5, I thought the output bus format can be determined by the sink
device(a panel or a bridge) hence properties like bus-width were not needed.
But, if this property is really needed, then reference video-interfaces.yaml
since bus-width is documented there.  Should we reference bus-type defined
in video-interfaces.yaml too?

> +                    enum: [ 16, 18, 24 ]

The PARALLEL_DISP_FORMAT field of DISPLAY_MUX register says this IP supports
below formats.  It seems that the enum here may tell RGB888, RGB666 and RGB565.
How can we tell RGB555, YCbCr 24 bits and YUV444 then?

000b RGB888 -> RGB888
001b RGB888 -> RGB666
010b RGB565 -> RGB565
011b RGB555 -> RGB555
100b YUV -> YCbCr 24 bits
101b YUV -> YUV444

> +                    description:
> +                      Specify the physical parallel bus width.
> +
> +                      This property is optional if the display bus-width
> +                      matches the SoC bus-width, e.g. a 18-bit RGB666 (display)
> +                      is connected and all 18-bit data lanes are muxed to the

Per video-interfaces.yaml, s/data lanes/data lines/.  "data lanes" is a
value for MIPI DSI/CSI, afaik.

> +                      parallel-output pads.

How about just saying that this property is optional and by default it's 24?

> +
> +                      This property must be set to 18 to cut only the LSBs
> +                      instead of the MSBs in case a 24-bit RGB888 display is
> +                      connected and only the lower 18-bit data lanes are muxed
> +                      to the parallel-output pads.

The __lower__ 18-bit?  Isn't it the __MSB__ 6bit in each color component?

> +
> +        required:
> +          - port at 0
> +          - port at 1
> +
> +    required:
> +      - compatible
> +      - reg
> +      - ports
> +
>  allOf:
>    - if:
>        properties:
> @@ -81,9 +141,12 @@ allOf:
>              - const: isi
>              - const: csi
>              - const: dsi
> +
>  required:
>    - compatible
>    - reg
> +  - '#address-cells'
> +  - '#size-cells'
>    - power-domains
>    - clocks
>    - clock-names
> @@ -112,4 +175,33 @@ examples:
>                 clock-names = "apb", "axi", "nic", "disp", "cam",
>                               "pxp", "lcdif", "isi", "csi", "dsi";
>        #power-domain-cells = <1>;
> +      #address-cells = <1>;
> +      #size-cells = <1>;
> +
> +      bridge at 60 {
> +        compatible = "nxp,imx93-pdfc";
> +        reg = <0x60 0x4>;
> +
> +        ports {
> +          #address-cells = <1>;
> +          #size-cells = <0>;
> +
> +          port at 0 {
> +            reg = <0>;
> +
> +            pdfc_from_lcdif: endpoint {
> +              remote-endpoint = <&lcdif_to_pdfc>;
> +            };
> +          };
> +
> +          port at 1 {
> +            reg = <1>;
> +
> +            pdfc_to_panel: endpoint {
> +              remote-endpoint = <&panel_from_pdfc>;
> +              bus-width = <18>;
> +            };
> +          };
> +        };
> +      };
>      };
> 


-- 
Regards,
Liu Ying


From krzk at kernel.org  Sun Dec  7 22:17:05 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 8 Dec 2025 07:17:05 +0100
Subject: [PATCH v6 2/5] dt-bindings: clock: add Amlogic T7 SCMI clock
 controller
In-Reply-To: <20251204053635.1234150-3-jian.hu@amlogic.com>
References: <20251204053635.1234150-1-jian.hu@amlogic.com>
 <20251204053635.1234150-3-jian.hu@amlogic.com>
Message-ID: <20251208-independent-warping-macaw-74a169@quoll>

On Thu, Dec 04, 2025 at 01:36:31PM +0800, Jian Hu wrote:
> Add DT bindings for the SCMI clock controller of the Amlogic T7 SoC family.
> 
> Signed-off-by: Jian Hu <jian.hu at amlogic.com>
> Acked-by: Rob Herring (Arm) <robh at kernel.org>
> ---
>  include/dt-bindings/clock/amlogic,t7-scmi.h | 47 +++++++++++++++++++++
>  1 file changed, 47 insertions(+)
>  create mode 100644 include/dt-bindings/clock/amlogic,t7-scmi.h
> 

Where is any binding doc for this? Why is this a separate patch?

Best regards,
Krzysztof



From krishna.chundru at oss.qualcomm.com  Sun Dec  7 22:20:26 2025
From: krishna.chundru at oss.qualcomm.com (Krishna Chaitanya Chundru)
Date: Mon, 8 Dec 2025 11:50:26 +0530
Subject: [PATCH v2] PCI: dwc: Make Link Up IRQ logic handle already
 powered on PCIe switches
In-Reply-To: <20251201063634.4115762-2-cassel@kernel.org>
References: <20251201063634.4115762-2-cassel@kernel.org>
Message-ID: <f1059d5d-3fa5-423a-8093-0e99b65d5f4c@oss.qualcomm.com>



On 12/1/2025 12:06 PM, Niklas Cassel wrote:
> The DWC glue drivers always call pci_host_probe() during probe(), which
> will allocate upstream bridge resources and enumerate the bus.
>
> For controllers without Link Up IRQ support, pci_host_probe() is called
> after dw_pcie_wait_for_link(), which will also wait the time required by
> the PCIe specification before performing PCI Configuration Space reads.
>
> For controllers with Link Up IRQ support, the pci_host_probe() call (which
> will perform PCI Configuration Space reads) is done without any of the
> delays mandated by the PCIe specification.
>
> For controllers with Link Up IRQ support, since the pci_host_probe() call
> is done without any delay (link training might still be ongoing), it is
> very unlikely that this scan will find any devices. Once the Link Up IRQ
> triggers, the Link Up IRQ handler will call pci_rescan_bus().
>
> This works fine for PCIe endpoints connected to the Root Port, since they
> don't extend the bus. However, if the pci_rescan_bus() call detects a PCIe
> switch, then there will be a problem when the downstream busses starts
> showing up, because the PCIe controller is not hotplug capable, so we are
> not allowed to extend the subordinate bus number after the initial scan,
> resulting in error messages such as:
>
> pci_bus 0004:43: busn_res: can not insert [bus 43-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci_bus 0004:43: busn_res: [bus 43-41] end is updated to 43
> pci_bus 0004:43: busn_res: can not insert [bus 43] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci 0004:42:00.0: devices behind bridge are unusable because [bus 43] cannot be assigned for them
> pci_bus 0004:44: busn_res: can not insert [bus 44-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci_bus 0004:44: busn_res: [bus 44-41] end is updated to 44
> pci_bus 0004:44: busn_res: can not insert [bus 44] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci 0004:42:02.0: devices behind bridge are unusable because [bus 44] cannot be assigned for them
> pci_bus 0004:45: busn_res: can not insert [bus 45-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci_bus 0004:45: busn_res: [bus 45-41] end is updated to 45
> pci_bus 0004:45: busn_res: can not insert [bus 45] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci 0004:42:06.0: devices behind bridge are unusable because [bus 45] cannot be assigned for them
> pci_bus 0004:46: busn_res: can not insert [bus 46-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci_bus 0004:46: busn_res: [bus 46-41] end is updated to 46
> pci_bus 0004:46: busn_res: can not insert [bus 46] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci 0004:42:0e.0: devices behind bridge are unusable because [bus 46] cannot be assigned for them
> pci_bus 0004:42: busn_res: [bus 42-41] end is updated to 46
> pci_bus 0004:42: busn_res: can not insert [bus 42-46] under [bus 41] (conflicts with (null) [bus 41])
> pci 0004:41:00.0: devices behind bridge are unusable because [bus 42-46] cannot be assigned for them
> pcieport 0004:40:00.0: bridge has subordinate 41 but max busn 46
>
> While we would like to set the is_hotplug_bridge flag
> (quirk_hotplug_bridge()), many embedded SoCs that use the DWC controller
> have synthesized the controller without hot-plug support.
> Thus, the Link Up IRQ logic is only mimicking hot-plug functionality, i.e.
> it is not compliant with the PCI Hot-Plug Specification, so we cannot make
> use of the is_hotplug_bridge flag.
>
> In order to let the Link Up IRQ logic handle PCIe switches that are already
> powered on (PCIe switches that not powered on already need to implement a
> pwrctrl driver), don't perform a pci_host_probe() call during probe()
> (which disregards the delays required by the PCIe specification).
>
> Instead let the first Link Up IRQ call pci_host_probe(). Any follow up
> Link Up IRQ will call pci_rescan_bus().
>
> The IRQ name in /proc/interrupts for the pcie-qcom driver is renamed in
> order to not dereference pp->bridge->bus before it has been assigned.
>
> Fixes: ec9fd499b9c6 ("PCI: dw-rockchip: Don't wait for link since we can detect Link Up")
> Fixes: 0e0b45ab5d77 ("PCI: dw-rockchip: Enumerate endpoints based on dll_link_up IRQ")
> Reported-by: FUKAUMI Naoki <naoki at radxa.com>
> Closes: https://lore.kernel.org/linux-pci/1E8E4DB773970CB5+5a52c9e1-01b8-4872-99b7-021099f04031 at radxa.com/
> Signed-off-by: Niklas Cassel <cassel at kernel.org>
> ---
> Changes since v1:
> -Rename the IRQ on pcie-qcom to not depend on pp->bridge->bus (Mani)
> -Make sure that ret is initialized in dw_pcie_host_init() error path (Dan)
>
>   .../pci/controller/dwc/pcie-designware-host.c | 71 ++++++++++++++++---
>   drivers/pci/controller/dwc/pcie-designware.h  |  5 ++
>   drivers/pci/controller/dwc/pcie-dw-rockchip.c |  5 +-
>   drivers/pci/controller/dwc/pcie-qcom.c        |  9 +--
>   4 files changed, 71 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
> index e92513c5bda51..bed7b309f6d9e 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-host.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
> @@ -565,6 +565,59 @@ static int dw_pcie_host_get_resources(struct dw_pcie_rp *pp)
>   	return 0;
>   }
>   
> +static int dw_pcie_host_initial_scan(struct dw_pcie_rp *pp)
> +{
> +	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> +	struct pci_host_bridge *bridge = pp->bridge;
> +	int ret;
> +
> +	ret = pci_host_probe(bridge);
> +	if (ret)
> +		return ret;
> +
> +	if (pp->ops->post_init)
> +		pp->ops->post_init(pp);
> +
> +	dwc_pcie_debugfs_init(pci, DW_PCIE_RC_TYPE);
> +
> +	return 0;
> +}
> +
> +void dw_pcie_handle_link_up_irq(struct dw_pcie_rp *pp)
> +{
> +	if (!pp->initial_linkup_irq_done) {
> +		int ret;
> +
> +		ret = dw_pcie_host_initial_scan(pp);
> +		if (ret) {
> +			struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> +			struct device *dev = pci->dev;
> +
> +			dev_err(dev, "Initial scan from IRQ failed: %d\n", ret);
> +
> +			dw_pcie_stop_link(pci);
> +
> +			dw_pcie_edma_remove(pci);
> +
> +			if (pp->has_msi_ctrl)
> +				dw_pcie_free_msi(pp);
> +
> +			if (pp->ops->deinit)
> +				pp->ops->deinit(pp);
> +
> +			if (pp->cfg)
> +				pci_ecam_free(pp->cfg);
> +		} else {
> +			pp->initial_linkup_irq_done = true;
> +		}
> +	} else {
> +		/* Rescan the bus to enumerate endpoint devices */
> +		pci_lock_rescan_remove();
> +		pci_rescan_bus(pp->bridge->bus);
> +		pci_unlock_rescan_remove();
> +	}
> +}
> +
>   int dw_pcie_host_init(struct dw_pcie_rp *pp)
>   {
>   	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> @@ -669,18 +722,18 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp)
>   	 * If there is no Link Up IRQ, we should not bypass the delay
>   	 * because that would require users to manually rescan for devices.
>   	 */
> -	if (!pp->use_linkup_irq)
> +	if (!pp->use_linkup_irq) {
>   		/* Ignore errors, the link may come up later */
>   		dw_pcie_wait_for_link(pci);
>   
> -	ret = pci_host_probe(bridge);
> -	if (ret)
> -		goto err_stop_link;
> -
> -	if (pp->ops->post_init)
> -		pp->ops->post_init(pp);
> -
> -	dwc_pcie_debugfs_init(pci, DW_PCIE_RC_TYPE);
> +		/*
> +		 * For platforms with Link Up IRQ, initial scan will be done
> +		 * on first Link Up IRQ.
> +		 */
> +		ret = dw_pcie_host_initial_scan(pp);
> +		if (ret)
> +			goto err_stop_link;
This will cause breakages in qcom platforms, qcom platforms use pwrctrl 
framework for
enabling power to the endpoints. And the pwrctrl drivers will be created 
as part of the initial scan.
As we skipping the initial scan here, pwrctrl driver will be never 
created and the power to the
endpoint will be never enabled. This will cause link to be never up.

- Krishna Chaitanya.
> +	}
>   
>   	return 0;
>   
> diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> index e995f692a1ecd..a31bd93490dcd 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.h
> +++ b/drivers/pci/controller/dwc/pcie-designware.h
> @@ -427,6 +427,7 @@ struct dw_pcie_rp {
>   	int			msg_atu_index;
>   	struct resource		*msg_res;
>   	bool			use_linkup_irq;
> +	bool			initial_linkup_irq_done;
>   	struct pci_eq_presets	presets;
>   	struct pci_config_window *cfg;
>   	bool			ecam_enabled;
> @@ -807,6 +808,7 @@ void dw_pcie_msi_init(struct dw_pcie_rp *pp);
>   int dw_pcie_msi_host_init(struct dw_pcie_rp *pp);
>   void dw_pcie_free_msi(struct dw_pcie_rp *pp);
>   int dw_pcie_setup_rc(struct dw_pcie_rp *pp);
> +void dw_pcie_handle_link_up_irq(struct dw_pcie_rp *pp);
>   int dw_pcie_host_init(struct dw_pcie_rp *pp);
>   void dw_pcie_host_deinit(struct dw_pcie_rp *pp);
>   int dw_pcie_allocate_domains(struct dw_pcie_rp *pp);
> @@ -844,6 +846,9 @@ static inline int dw_pcie_setup_rc(struct dw_pcie_rp *pp)
>   	return 0;
>   }
>   
> +static inline void dw_pcie_handle_link_up_irq(struct dw_pcie_rp *pp)
> +{ }
> +
>   static inline int dw_pcie_host_init(struct dw_pcie_rp *pp)
>   {
>   	return 0;
> diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
> index 3e2752c7dd096..8f2cc1ef25e3d 100644
> --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c
> +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
> @@ -466,10 +466,7 @@ static irqreturn_t rockchip_pcie_rc_sys_irq_thread(int irq, void *arg)
>   		if (rockchip_pcie_link_up(pci)) {
>   			msleep(PCIE_RESET_CONFIG_WAIT_MS);
>   			dev_dbg(dev, "Received Link up event. Starting enumeration!\n");
> -			/* Rescan the bus to enumerate endpoint devices */
> -			pci_lock_rescan_remove();
> -			pci_rescan_bus(pp->bridge->bus);
> -			pci_unlock_rescan_remove();
> +			dw_pcie_handle_link_up_irq(pp);
>   		}
>   	}
>   
> diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
> index c48a20602d7fa..04f29cd8d8881 100644
> --- a/drivers/pci/controller/dwc/pcie-qcom.c
> +++ b/drivers/pci/controller/dwc/pcie-qcom.c
> @@ -1617,10 +1617,7 @@ static irqreturn_t qcom_pcie_global_irq_thread(int irq, void *data)
>   	if (FIELD_GET(PARF_INT_ALL_LINK_UP, status)) {
>   		msleep(PCIE_RESET_CONFIG_WAIT_MS);
>   		dev_dbg(dev, "Received Link up event. Starting enumeration!\n");
> -		/* Rescan the bus to enumerate endpoint devices */
> -		pci_lock_rescan_remove();
> -		pci_rescan_bus(pp->bridge->bus);
> -		pci_unlock_rescan_remove();
> +		dw_pcie_handle_link_up_irq(pp);
>   
>   		qcom_pcie_icc_opp_update(pcie);
>   	} else {
> @@ -1937,8 +1934,8 @@ static int qcom_pcie_probe(struct platform_device *pdev)
>   		goto err_phy_exit;
>   	}
>   
> -	name = devm_kasprintf(dev, GFP_KERNEL, "qcom_pcie_global_irq%d",
> -			      pci_domain_nr(pp->bridge->bus));
> +	name = devm_kasprintf(dev, GFP_KERNEL, "qcom_pcie_global_irq_%pOFP",
> +			      dev->of_node);
>   	if (!name) {
>   		ret = -ENOMEM;
>   		goto err_host_deinit;



From krzk at kernel.org  Sun Dec  7 22:20:37 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 8 Dec 2025 07:20:37 +0100
Subject: [PATCH v4] dt-bindings: arm: keystone: add boot_* mboxes to
 ti,sci
In-Reply-To: <20251205-k3_syscon_add_boot_mailboxes-v4-1-8e216fb88941@ti.com>
References: <20251205-k3_syscon_add_boot_mailboxes-v4-1-8e216fb88941@ti.com>
Message-ID: <20251208-abiding-hedgehog-of-lightning-2fe7a2@quoll>

On Fri, Dec 05, 2025 at 11:45:43AM +0530, Anshul Dalal wrote:
> The bootloader on K3 devices makes use of mailboxes as per the ROM spec
> which might be different than one's available to the kernel (firmware
> spec).
> 
> Therefore, this patch adds the missing mailbox entries to the DT binding
> if the matching compatible is ti,am654-sci to represent the mailboxes
> exposed by the hardware during boot for the purpose of loading the
> firmware.
> 
> Signed-off-by: Anshul Dalal <anshuld at ti.com>
> ---
> Changes in v4:
> - Make new boot_* mboxes conditional on ti,am654-sci compatible
> - Link to v3: https://lore.kernel.org/r/20251112-k3_syscon_add_boot_mailboxes-v3-1-66155a4236dc at ti.com
> 
> Changes in v3:
> - Drop [1/2] of the last patch series
> - Update existing example with boot_* mailboxes instead of adding a new one
> - Link to v2: https://lore.kernel.org/r/20251112-k3_syscon_add_boot_mailboxes-v2-0-aebc1e47b391 at ti.com
> 
> Changes in v2:
> - Remove maxItems entry
> - Remove RFC tag from patch (added by mistake in v1)
> - Document the new mailboxes in mboxes instead of mbox-names
> - Provide example with all the mailboxes set
> - Update commit title to have "ti,sci"
> - Split into two patches
> - Link to v1: https://lore.kernel.org/r/20251111-k3_syscon_add_boot_mailboxes-v1-1-529a27f21076 at ti.com
> ---
>  .../devicetree/bindings/arm/keystone/ti,sci.yaml   | 50 +++++++++++++++++++---
>  1 file changed, 43 insertions(+), 7 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
> index 25a2b42105e5..d9eb2a81e539 100644
> --- a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
> +++ b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
> @@ -51,15 +51,15 @@ properties:
>      minItems: 1
>  
>    mbox-names:
> +    minItems: 2
> +    maxItems: 6
>      description: |
>        Specifies the mailboxes used to communicate with TI-SCI Controller
>        made available from TI-SCI controller.
> -    items:
> -      - const: rx
> -      - const: tx
>  
>    mboxes:
>      minItems: 2
> +    maxItems: 6
>  
>    ti,host-id:
>      $ref: /schemas/types.yaml#/definitions/uint32
> @@ -79,6 +79,42 @@ properties:
>      type: object
>      $ref: /schemas/reset/ti,sci-reset.yaml#
>  
> +if:
> +  properties:
> +    compatible:
> +      contains:
> +        const: ti,am654-sci
> +then:
> +  properties:
> +    mbox-names:
> +      minItems: 2

Why is this list flexible?

> +      items:
> +        - const: rx
> +        - const: tx
> +        - const: notify
> +        - const: boot_rx
> +        - const: boot_tx
> +        - const: boot_notify

So this list goes to top-level with minItems.

> +    mboxes:
> +      minItems: 2
> +      items:
> +        - description: RX thread
> +        - description: TX thread
> +        - description: Notify thread
> +        - description: boot stage RX thread
> +        - description: boot stage TX thread
> +        - description: boot stage Notify thread

This as well

> +else:

Best regards,
Krzysztof



From ruanjinjie at huawei.com  Sun Dec  7 22:24:41 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 8 Dec 2025 14:24:41 +0800
Subject: [PATCH v9 04/16] arm64/ptrace: Refactor
 syscall_trace_enter/exit()
In-Reply-To: <dd3a1421-dfb0-445e-b2f7-7c273fa4a020@arm.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
 <20251204082123.2792067-5-ruanjinjie@huawei.com>
 <dd3a1421-dfb0-445e-b2f7-7c273fa4a020@arm.com>
Message-ID: <9102697c-9159-395d-e1b5-78439aa5a8b9@huawei.com>



On 2025/12/8 13:48, Anshuman Khandual wrote:
> On 04/12/25 1:51 PM, Jinjie Ruan wrote:
>> The generic syscall entry code has the following form, which use
>> the input syscall work flag and syscall number:
>>
>> | syscall_trace_enter(struct pt_regs *regs, long syscall,
>> |		      unsigned long work)
>> |
>> | syscall_exit_work(struct pt_regs *regs, unsigned long work)
>>
>> In preparation for moving arm64 over to the generic entry code,
>> refactor syscall_trace_enter/exit() to also pass thread flags, and
>> get syscall number by syscall_get_nr() helper.
>>
>> No functional changes.
>>
>> Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
>> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
>> ---
>>  arch/arm64/include/asm/syscall.h |  4 ++--
>>  arch/arm64/kernel/ptrace.c       | 25 ++++++++++++++++---------
>>  arch/arm64/kernel/syscall.c      |  5 +++--
>>  3 files changed, 21 insertions(+), 13 deletions(-)
>>
>> diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
>> index 5e4c7fc44f73..cef1d9ce6e1b 100644
>> --- a/arch/arm64/include/asm/syscall.h
>> +++ b/arch/arm64/include/asm/syscall.h
>> @@ -120,7 +120,7 @@ static inline int syscall_get_arch(struct task_struct *task)
>>  	return AUDIT_ARCH_AARCH64;
>>  }
>>  
>> -int syscall_trace_enter(struct pt_regs *regs);
>> -void syscall_trace_exit(struct pt_regs *regs);
>> +int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags);
>> +void syscall_trace_exit(struct pt_regs *regs, unsigned long flags);
>>  
>>  #endif	/* __ASM_SYSCALL_H */
>> diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
>> index 3926ce6aa268..b962cbcca11d 100644
>> --- a/arch/arm64/kernel/ptrace.c
>> +++ b/arch/arm64/kernel/ptrace.c
>> @@ -2381,9 +2381,8 @@ static void report_syscall_exit(struct pt_regs *regs)
>>  	}
>>  }
>>  
>> -int syscall_trace_enter(struct pt_regs *regs)
>> +int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags)
>>  {
>> -	unsigned long flags = read_thread_flags();
>>  	int ret;
>>  
>>  	if (flags & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE)) {
>> @@ -2396,19 +2395,27 @@ int syscall_trace_enter(struct pt_regs *regs)
>>  	if (secure_computing() == -1)
>>  		return NO_SYSCALL;
>>  
>> -	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
>> -		trace_sys_enter(regs, regs->syscallno);
>> +	/* Either of the above might have changed the syscall number */
>> +	syscall = syscall_get_nr(current, regs);
>>  
>> -	audit_syscall_entry(regs->syscallno, regs->orig_x0, regs->regs[1],
>> +	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) {
>> +		trace_sys_enter(regs, syscall);
>> +
>> +		/*
>> +		 * Probes or BPF hooks in the tracepoint may have changed the
>> +		 * system call number as well.
>> +		 */
>> +		 syscall = syscall_get_nr(current, regs);
>> +	}
>> +
>> +	audit_syscall_entry(syscall, regs->orig_x0, regs->regs[1],
>>  			    regs->regs[2], regs->regs[3]);
>>  
>> -	return regs->syscallno;
>> +	return syscall;
> 
> regs->syscallno still remains unchanged even if syscall is evaluated to be different ?

No, arm64 syscall_get_nr() returns regs->syscallno, use syscall_get_nr()
helper here to get the local "syscall" is to stay consistent with the
generic entry, without any semantic change.

 23 static inline int syscall_get_nr(struct task_struct *task,
 24 >------->------->------->------- struct pt_regs *regs)
 25 {
 26 >-------return regs->syscallno;
 27 }

> 
>>  }
>>  
>> -void syscall_trace_exit(struct pt_regs *regs)
>> +void syscall_trace_exit(struct pt_regs *regs, unsigned long flags)
>>  {
>> -	unsigned long flags = read_thread_flags();
>> -
>>  	audit_syscall_exit(regs);
>>  
>>  	if (flags & _TIF_SYSCALL_TRACEPOINT)
>> diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
>> index aba7ca6bca2d..ec31f82d2e9f 100644
>> --- a/arch/arm64/kernel/syscall.c
>> +++ b/arch/arm64/kernel/syscall.c
>> @@ -124,7 +124,7 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
>>  		 */
>>  		if (scno == NO_SYSCALL)
>>  			syscall_set_return_value(current, regs, -ENOSYS, 0);
>> -		scno = syscall_trace_enter(regs);
>> +		scno = syscall_trace_enter(regs, scno, flags);
>>  		if (scno == NO_SYSCALL)
>>  			goto trace_exit;
>>  	}
>> @@ -143,7 +143,8 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
>>  	}
>>  
>>  trace_exit:
>> -	syscall_trace_exit(regs);
>> +	flags = read_thread_flags();
>> +	syscall_trace_exit(regs, flags);
>>  }
>>  
>>  void do_el0_svc(struct pt_regs *regs)
> 
> 


From krzk at kernel.org  Sun Dec  7 22:25:03 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 8 Dec 2025 07:25:03 +0100
Subject: [PATCH v2 3/8] dt-bindings: pinctrl: Add rv1126b pinctrl support
In-Reply-To: <20251206050844.402958-4-ye.zhang@rock-chips.com>
References: <20251206050844.402958-1-ye.zhang@rock-chips.com>
 <20251206050844.402958-4-ye.zhang@rock-chips.com>
Message-ID: <20251208-snobbish-curvy-mouse-67fafe@quoll>

On Sat, Dec 06, 2025 at 01:08:39PM +0800, Ye Zhang wrote:
> Add the compatible string for the rv1126b SoC.

Why? What is the difference against existing one? Please write useful
commit msgs, not something obvious being copy of the diff and subject.

Best regards,
Krzysztof



From krzk at kernel.org  Sun Dec  7 22:26:35 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 8 Dec 2025 07:26:35 +0100
Subject: [PATCH v2 1/8] dt-bindings: pinctrl: Add rk3506 pinctrl support
In-Reply-To: <20251206050844.402958-2-ye.zhang@rock-chips.com>
References: <20251206050844.402958-1-ye.zhang@rock-chips.com>
 <20251206050844.402958-2-ye.zhang@rock-chips.com>
Message-ID: <20251208-invisible-ingenious-lori-b8aeb2@quoll>

On Sat, Dec 06, 2025 at 01:08:37PM +0800, Ye Zhang wrote:
> Add the compatible string for the rk3506 SoC.
> 
> Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
> Reviewed-by: Heiko Stuebner <heiko at sntech.de>
> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>

Squash it, it is really  just churn to deal with one patch per
compatible. Especially without any explanation in commit msg justyfing
it.

Best regards,
Krzysztof



From krzk at kernel.org  Sun Dec  7 22:27:34 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 8 Dec 2025 07:27:34 +0100
Subject: [PATCH v2 6/8] dt-bindings: pinctrl: Add header for Rockchip
 RK3506 RMIO
In-Reply-To: <20251206050844.402958-7-ye.zhang@rock-chips.com>
References: <20251206050844.402958-1-ye.zhang@rock-chips.com>
 <20251206050844.402958-7-ye.zhang@rock-chips.com>
Message-ID: <20251208-tidy-kiwi-of-calibration-c9a8e4@quoll>

On Sat, Dec 06, 2025 at 01:08:42PM +0800, Ye Zhang wrote:
> Add header file with constants for RMIO pin and function IDs for the
> Rockchip RK3506 SoC.
> 
> Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
> ---
>  .../pinctrl/rockchip,rk3506-rmio.h            | 143 ++++++++++++++++++

That's not a separate commit. Don't inflate the patchset you just make
it more work to deal with it, this belongs to the binding.


>  1 file changed, 143 insertions(+)
>  create mode 100644 include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h
> 
> diff --git a/include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h b/include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h
> new file mode 100644
> index 000000000000..5d39690a0b28
> --- /dev/null
> +++ b/include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h

What is the compatible?

Best regards,
Krzysztof



From krzk at kernel.org  Sun Dec  7 22:29:50 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 8 Dec 2025 07:29:50 +0100
Subject: [PATCH v2 7/8] dt-bindings: pinctrl: rockchip: Add RMIO
 controller binding
In-Reply-To: <20251206050844.402958-8-ye.zhang@rock-chips.com>
References: <20251206050844.402958-1-ye.zhang@rock-chips.com>
 <20251206050844.402958-8-ye.zhang@rock-chips.com>
Message-ID: <20251208-invisible-crazy-squirrel-bb3af0@quoll>

On Sat, Dec 06, 2025 at 01:08:43PM +0800, Ye Zhang wrote:
> Add device tree binding for the RMIO (Rockchip Matrix I/O) controller
> which is a sub-device of the main pinctrl on some Rockchip SoCs.
> 
> Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
> ---
>  .../bindings/pinctrl/rockchip,pinctrl.yaml    |   9 ++
>  .../bindings/pinctrl/rockchip,rmio.yaml       | 130 ++++++++++++++++++
>  2 files changed, 139 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml
> 
> diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
> index 93bf8f352e48..01df0a51ff83 100644
> --- a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
> +++ b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
> @@ -83,6 +83,15 @@ required:
>    - rockchip,grf
>  
>  patternProperties:
> +  "rmio[0-9]*$":
> +    type: object
> +
> +    $ref: "/schemas/pinctrl/rockchip,rmio.yaml#"
> +
> +    description:
> +      The RMIO (Rockchip Matrix I/O) controller node which functions as a
> +      sub-device of the main pinctrl to handle flexible function routing.
> +
>    "gpio@[0-9a-f]+$":
>      type: object
>  
> diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml b/Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml
> new file mode 100644
> index 000000000000..28ec5ad62061
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml
> @@ -0,0 +1,130 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/pinctrl/rockchip,rmio.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: RMIO (Rockchip Matrix I/O) Controller
> +
> +maintainers:
> +  - Heiko Stuebner <heiko at sntech.de>
> +
> +description: |
> +  The RMIO controller provides a flexible routing matrix that allows mapping
> +  various internal peripheral functions (UART, SPI, PWM, etc.) to specific
> +  physical pins. This block is typically a sub-block of the GRF
> +  (General Register Files).
> +
> +properties:
> +  compatible:
> +    enum:
> +      - rockchip,rmio

Nope, you need Soc specific compatibles. Please see writing bindings
doc first.


> +
> +  rockchip,grf:
> +    $ref: /schemas/types.yaml#/definitions/phandle
> +    description:

Huh? That's already in the parent, no?

> +      The phandle of the syscon node for the GRF registers.
> +
> +  rockchip,offset:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    description:
> +      The offset of the RMIO configuration registers within the GRF.
> +
> +  rockchip,pins-num:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    description:
> +      The number of physical pins supported by this RMIO instance.
> +      Used for boundary checking and driver initialization.
> +
> +additionalProperties:
> +  type: object
> +  additionalProperties:
> +    type: object
> +    properties:
> +      rockchip,rmio:
> +        $ref: "/schemas/types.yaml#/definitions/uint32-matrix"
> +        description: |
> +          A list of pin-function pairs. The format is <pin_id function_id>.
> +          - pin_id: The index of the RMIO pin (0 to pins-num - 1).
> +          - function_id: The mux value selecting the peripheral function.
> +        minItems: 1
> +        items:
> +          items:
> +            - minimum: 0
> +              maximum: 31
> +              description:
> +                RMIO Pin ID.
> +            - minimum: 0
> +              maximum: 98
> +              description:
> +                Function ID.
> +
> +    required:
> +      - rockchip,rmio
> +
> +    additionalProperties: false
> +
> +  additionalProperties: false
> +
> +required:
> +  - compatible
> +  - rockchip,grf
> +  - rockchip,offset
> +  - rockchip,pins-num
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +    #include <dt-bindings/pinctrl/rockchip.h>
> +    #include <dt-bindings/pinctrl/rockchip,rk3506-rmio.h>
> +
> +    pinctrl {
> +        #address-cells = <1>;
> +        #size-cells = <1>;

Drop all this and below. Parent node should have complete example.

> +        ranges;
> +
> +        rmio {
> +            compatible = "rockchip,rmio";
> +            rockchip,grf = <&grf_pmu>;
> +            rockchip,offset = <0x80>;
> +            rockchip,pins-num = <32>;
> +
> +            rmio-uart {
> +                rmio_pin27_uart1_tx: rmio-pin27-uart1-tx {
> +                    rockchip,rmio = <RMIO_PIN27 RMIO_UART1_TX>;
> +                };
> +
> +                rmio_pin28_uart1_rx: rmio-pin28-uart1-rx {
> +                    rockchip,rmio = <RMIO_PIN28 RMIO_UART1_RX>;
> +                };
> +            };
> +        };
> +
> +        pcfg_pull_default: pcfg-pull-default {
> +          bias-pull-pin-default;
> +        };
> +
> +        rm {
> +          rmio_pin27_pins: rmio-pin27-pins {
> +            rockchip,pins = <1 RK_PC2 7 &pcfg-pull-default>;
> +          };
> +
> +          rmio_pin28_pins: rmio-pin28-pins {
> +            rockchip,pins = <1 RK_PC3 7 &pcfg-pull-default>;
> +          };
> +        };
> +    };
> +
> +    uart1: serial at 20064000 {
> +      compatible = "snps,dw-apb-uart";

Do not add irrelevant examples. Please read carefully writing bindings,
writing schema and for example by talk for beginners in DT.

This patchset does not make me happy, too many trivial issues.

Best regards,
Krzysztof



From ruanjinjie at huawei.com  Sun Dec  7 22:31:35 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 8 Dec 2025 14:31:35 +0800
Subject: [PATCH v9 03/16] arm64/ptrace: Return early for
 ptrace_report_syscall_entry() error
In-Reply-To: <7c7e5c66-f618-466f-b353-54fad71c0e14@arm.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
 <20251204082123.2792067-4-ruanjinjie@huawei.com>
 <7c7e5c66-f618-466f-b353-54fad71c0e14@arm.com>
Message-ID: <1f919820-2c8e-f041-b38d-963b55c8792d@huawei.com>



On 2025/12/8 13:24, Anshuman Khandual wrote:
> On 04/12/25 1:51 PM, Jinjie Ruan wrote:
>> The generic entry abort the syscall_trace_enter() sequence if
>> ptrace_report_syscall_entry() errors out, but arm64 not.
>>
>> As the ptrace_report_syscall_entry() comment said, the calling arch code
>> should abort the system call and must prevent normal entry so no system
>> call is made if ptrace_report_syscall_entry() return nonzero.
>>
>> In preparation for moving arm64 over to the generic entry code,
>> return early if ptrace_report_syscall_entry() encounters an error.
>>
>> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
>> ---
>>  arch/arm64/kernel/ptrace.c | 14 +++++++++-----
>>  1 file changed, 9 insertions(+), 5 deletions(-)
>>
>> diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
>> index 4532e9831856..3926ce6aa268 100644
>> --- a/arch/arm64/kernel/ptrace.c
>> +++ b/arch/arm64/kernel/ptrace.c
>> @@ -2346,15 +2346,18 @@ static __always_inline unsigned long ptrace_save_reg(struct pt_regs *regs,
>>  	return saved_reg;
>>  }
>>  
>> -static void report_syscall_entry(struct pt_regs *regs)
>> +static int report_syscall_entry(struct pt_regs *regs)
>>  {
>>  	unsigned long saved_reg;
>> -	int regno;
>> +	int regno, ret;
>>  
>>  	saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_ENTER, &regno);
>> -	if (ptrace_report_syscall_entry(regs))
>> +	ret = ptrace_report_syscall_entry(regs);
>> +	if (ret)
>>  		forget_syscall(regs);
>>  	regs->regs[regno] = saved_reg;
>> +
>> +	return ret;
>>  }
>>  
>>  static void report_syscall_exit(struct pt_regs *regs)
>> @@ -2381,10 +2384,11 @@ static void report_syscall_exit(struct pt_regs *regs)
>>  int syscall_trace_enter(struct pt_regs *regs)
>>  {
>>  	unsigned long flags = read_thread_flags();
>> +	int ret;
>>  
>>  	if (flags & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE)) {
>> -		report_syscall_entry(regs);
>> -		if (flags & _TIF_SYSCALL_EMU)
>> +		ret = report_syscall_entry(regs);
>> +		if (ret || (flags & _TIF_SYSCALL_EMU))
> 
> A small nit.
> 
> Could report_syscall_entry(regs) be checked directly in the 'if' conditional
> code block thus dropping new 'ret' altogether ?

It?s perfectly fine, but on the one hand, the upcoming refactor of the
secure_computing() patch will be able to use this ?ret?, and on the
other, the intent of this patch is to highlight the differences from the
generic entry so we can switch over smoothly later. Simplifying it here
therefore doesn?t help much for demonstrating those differences.

> 
>>  			return NO_SYSCALL;
>>  	}
>>  
> 
> 


From anshuld at ti.com  Sun Dec  7 22:31:29 2025
From: anshuld at ti.com (Anshul Dalal)
Date: Mon, 8 Dec 2025 12:01:29 +0530
Subject: [PATCH v4] dt-bindings: arm: keystone: add boot_* mboxes to
 ti,sci
In-Reply-To: <20251208-abiding-hedgehog-of-lightning-2fe7a2@quoll>
References: <20251205-k3_syscon_add_boot_mailboxes-v4-1-8e216fb88941@ti.com>
 <20251208-abiding-hedgehog-of-lightning-2fe7a2@quoll>
Message-ID: <DESMHL7FCYXE.3TE3SG6TDVJ39@ti.com>

On Mon Dec 8, 2025 at 11:50 AM IST, Krzysztof Kozlowski wrote:
> On Fri, Dec 05, 2025 at 11:45:43AM +0530, Anshul Dalal wrote:
>> The bootloader on K3 devices makes use of mailboxes as per the ROM spec
>> which might be different than one's available to the kernel (firmware
>> spec).
>> 
>> Therefore, this patch adds the missing mailbox entries to the DT binding
>> if the matching compatible is ti,am654-sci to represent the mailboxes
>> exposed by the hardware during boot for the purpose of loading the
>> firmware.
>> 
>> Signed-off-by: Anshul Dalal <anshuld at ti.com>
>> ---
>> Changes in v4:
>> - Make new boot_* mboxes conditional on ti,am654-sci compatible
>> - Link to v3: https://lore.kernel.org/r/20251112-k3_syscon_add_boot_mailboxes-v3-1-66155a4236dc at ti.com
>> 
>> Changes in v3:
>> - Drop [1/2] of the last patch series
>> - Update existing example with boot_* mailboxes instead of adding a new one
>> - Link to v2: https://lore.kernel.org/r/20251112-k3_syscon_add_boot_mailboxes-v2-0-aebc1e47b391 at ti.com
>> 
>> Changes in v2:
>> - Remove maxItems entry
>> - Remove RFC tag from patch (added by mistake in v1)
>> - Document the new mailboxes in mboxes instead of mbox-names
>> - Provide example with all the mailboxes set
>> - Update commit title to have "ti,sci"
>> - Split into two patches
>> - Link to v1: https://lore.kernel.org/r/20251111-k3_syscon_add_boot_mailboxes-v1-1-529a27f21076 at ti.com
>> ---
>>  .../devicetree/bindings/arm/keystone/ti,sci.yaml   | 50 +++++++++++++++++++---
>>  1 file changed, 43 insertions(+), 7 deletions(-)
>> 
>> diff --git a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
>> index 25a2b42105e5..d9eb2a81e539 100644
>> --- a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
>> +++ b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
>> @@ -51,15 +51,15 @@ properties:
>>      minItems: 1
>>  
>>    mbox-names:
>> +    minItems: 2
>> +    maxItems: 6
>>      description: |
>>        Specifies the mailboxes used to communicate with TI-SCI Controller
>>        made available from TI-SCI controller.
>> -    items:
>> -      - const: rx
>> -      - const: tx
>>  
>>    mboxes:
>>      minItems: 2
>> +    maxItems: 6
>>  
>>    ti,host-id:
>>      $ref: /schemas/types.yaml#/definitions/uint32
>> @@ -79,6 +79,42 @@ properties:
>>      type: object
>>      $ref: /schemas/reset/ti,sci-reset.yaml#
>>  
>> +if:
>> +  properties:
>> +    compatible:
>> +      contains:
>> +        const: ti,am654-sci
>> +then:
>> +  properties:
>> +    mbox-names:
>> +      minItems: 2
>
> Why is this list flexible?
>

The idea is to make the boot_* mboxes optional so the existing DTs that
only have rx and tx remain complaint. Also, the boot_notify mbox is not
supported by every SoC.

>> +      items:
>> +        - const: rx
>> +        - const: tx
>> +        - const: notify
>> +        - const: boot_rx
>> +        - const: boot_tx
>> +        - const: boot_notify
>
> So this list goes to top-level with minItems.
>
>> +    mboxes:
>> +      minItems: 2
>> +      items:
>> +        - description: RX thread
>> +        - description: TX thread
>> +        - description: Notify thread
>> +        - description: boot stage RX thread
>> +        - description: boot stage TX thread
>> +        - description: boot stage Notify thread
>
> This as well
>
>> +else:
>
> Best regards,
> Krzysztof



From mikhail.kshevetskiy at iopsys.eu  Sun Dec  7 22:36:36 2025
From: mikhail.kshevetskiy at iopsys.eu (Mikhail Kshevetskiy)
Date: Mon,  8 Dec 2025 09:36:36 +0300
Subject: [PATCH v2 0/2] ARM: dts: airoha: en7523: update dts
Message-ID: <20251208063638.3009460-1-mikhail.kshevetskiy@iopsys.eu>

These two patches updates dts for en7523 SoC with the recently
added features:
 * reset controller support
 * spinand flashes support

Initially these patches were parts of the following series:

  https://lore.kernel.org/lkml/20251012121707.2296160-1-mikhail.kshevetskiy at iopsys.eu/
  https://lore.kernel.org/lkml/20251017201126.493496-1-mikhail.kshevetskiy at iopsys.eu/

All other patches (except patches from this series) were already merged
to upsrtream linux. This series just groups remaining patches together.

The series was resend because of no any activity for more than a week.

Changes v2:
 * update cover letter
 * update patches description a bit

Mikhail Kshevetskiy (2):
  ARM: dts: airoha: en7523: add node to support spinand flashes
  ARM: dts: airoha: en7523: add reset-controller support

 arch/arm/boot/dts/airoha/en7523.dtsi | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

-- 
2.51.0



From mikhail.kshevetskiy at iopsys.eu  Sun Dec  7 22:36:37 2025
From: mikhail.kshevetskiy at iopsys.eu (Mikhail Kshevetskiy)
Date: Mon,  8 Dec 2025 09:36:37 +0300
Subject: [PATCH v2 1/2] ARM: dts: airoha: en7523: add node to support spinand flashes
In-Reply-To: <20251208063638.3009460-1-mikhail.kshevetskiy@iopsys.eu>
References: <20251208063638.3009460-1-mikhail.kshevetskiy@iopsys.eu>
Message-ID: <20251208063638.3009460-2-mikhail.kshevetskiy@iopsys.eu>

Add SNAND node to enable support of attached SPI-NAND on the EN7523 SoC.

Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy at iopsys.eu>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
---
 arch/arm/boot/dts/airoha/en7523.dtsi | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/arch/arm/boot/dts/airoha/en7523.dtsi b/arch/arm/boot/dts/airoha/en7523.dtsi
index b523a868c4ad..31191b8d1430 100644
--- a/arch/arm/boot/dts/airoha/en7523.dtsi
+++ b/arch/arm/boot/dts/airoha/en7523.dtsi
@@ -203,4 +203,24 @@ pcie_intc1: interrupt-controller {
 			#interrupt-cells = <1>;
 		};
 	};
+
+	spi_ctrl: spi at 1fa10000 {
+		compatible = "airoha,en7523-snand", "airoha,en7581-snand";
+		reg = <0x1fa10000 0x140>,
+		      <0x1fa11000 0x160>;
+
+		clocks = <&scu EN7523_CLK_SPI>;
+		clock-names = "spi";
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		nand: nand at 0 {
+			compatible = "spi-nand";
+			reg = <0>;
+			spi-max-frequency = <50000000>;
+			spi-tx-bus-width = <1>;
+			spi-rx-bus-width = <2>;
+		};
+	};
 };
-- 
2.51.0



From mikhail.kshevetskiy at iopsys.eu  Sun Dec  7 22:36:38 2025
From: mikhail.kshevetskiy at iopsys.eu (Mikhail Kshevetskiy)
Date: Mon,  8 Dec 2025 09:36:38 +0300
Subject: [PATCH v2 2/2] ARM: dts: airoha: en7523: add reset-controller support
In-Reply-To: <20251208063638.3009460-1-mikhail.kshevetskiy@iopsys.eu>
References: <20251208063638.3009460-1-mikhail.kshevetskiy@iopsys.eu>
Message-ID: <20251208063638.3009460-3-mikhail.kshevetskiy@iopsys.eu>

This patch updates EN7523 dtsi to reflect the reset-controller
support for EN7523 SoC.

Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy at iopsys.eu>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
---
 arch/arm/boot/dts/airoha/en7523.dtsi | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/boot/dts/airoha/en7523.dtsi b/arch/arm/boot/dts/airoha/en7523.dtsi
index 31191b8d1430..115cc44093ab 100644
--- a/arch/arm/boot/dts/airoha/en7523.dtsi
+++ b/arch/arm/boot/dts/airoha/en7523.dtsi
@@ -4,6 +4,7 @@
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/clock/en7523-clk.h>
+#include <dt-bindings/reset/airoha,en7523-reset.h>
 
 / {
 	interrupt-parent = <&gic>;
@@ -91,6 +92,7 @@ scu: system-controller at 1fa20000 {
 		reg = <0x1fa20000 0x400>,
 		      <0x1fb00000 0x1000>;
 		#clock-cells = <1>;
+		#reset-cells = <1>;
 	};
 
 	gic: interrupt-controller at 9000000 {
-- 
2.51.0



From jacky_chou at aspeedtech.com  Sun Dec  7 22:49:56 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Mon, 8 Dec 2025 14:49:56 +0800
Subject: [PATCH net] net: mdio: aspeed: add dummy read to avoid
 read-after-write issue
Message-ID: <20251208-aspeed_mdio_add_dummy_read-v1-1-0a1861ad2161@aspeedtech.com>

The Aspeed MDIO controller may return incorrect data when a read operation
follows immediately after a write. Due to a controller bug, the subsequent
read can latch stale data, causing the polling logic to terminate earlier
than expected.

To work around this hardware issue, insert a dummy read after each write
operation. This ensures that the next actual read returns the correct
data and prevents premature polling exit.

This workaround has been verified to stabilize MDIO transactions on
affected Aspeed platforms.

Fixes: 737ca352569e ("net: mdio: aspeed: move reg accessing part into separate functions")
Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
---
 drivers/net/mdio/mdio-aspeed.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/net/mdio/mdio-aspeed.c b/drivers/net/mdio/mdio-aspeed.c
index e55be6dc9ae7..7d11add3c05e 100644
--- a/drivers/net/mdio/mdio-aspeed.c
+++ b/drivers/net/mdio/mdio-aspeed.c
@@ -63,6 +63,13 @@ static int aspeed_mdio_op(struct mii_bus *bus, u8 st, u8 op, u8 phyad, u8 regad,
 
 	iowrite32(ctrl, ctx->base + ASPEED_MDIO_CTRL);
 
+	/* Workaround for read-after-write issue.
+	 * The controller may return stale data if a read follows immediately
+	 * after a write. A dummy read forces the hardware to update its
+	 * internal state, ensuring that the next real read returns correct data.
+	 */
+	(void)ioread32(ctx->base + ASPEED_MDIO_CTRL);
+
 	return readl_poll_timeout(ctx->base + ASPEED_MDIO_CTRL, ctrl,
 				!(ctrl & ASPEED_MDIO_CTRL_FIRE),
 				ASPEED_MDIO_INTERVAL_US,

---
base-commit: 0373d5c387f24de749cc22e694a14b3a7c7eb515
change-id: 20251208-aspeed_mdio_add_dummy_read-587ab8808817

Best regards,
-- 
Jacky Chou <jacky_chou at aspeedtech.com>



From krzk at kernel.org  Sun Dec  7 22:52:03 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 8 Dec 2025 07:52:03 +0100
Subject: [PATCH 1/4] dt-bindings: pwm: sunxi: add PWM controller for
 Allwinner H616
In-Reply-To: <20251205100239.1563353-2-richard.genoud@bootlin.com>
References: <20251205100239.1563353-1-richard.genoud@bootlin.com>
 <20251205100239.1563353-2-richard.genoud@bootlin.com>
Message-ID: <20251208-gorgeous-capuchin-of-protection-4ad0c2@quoll>

On Fri, Dec 05, 2025 at 11:02:36AM +0100, Richard Genoud wrote:
> Allwinner H616 SoC contains a PWM controller quite different from the A10.
> It has 6 channels than can generate PWM waveforms or clocks if bypass is
> enabled.
> 
> Signed-off-by: Richard Genoud <richard.genoud at bootlin.com>
> ---
>  .../pwm/allwinner,sun50i-h616-pwm.yaml        | 67 +++++++++++++++++++
>  1 file changed, 67 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/pwm/allwinner,sun50i-h616-pwm.yaml
> 
> diff --git a/Documentation/devicetree/bindings/pwm/allwinner,sun50i-h616-pwm.yaml b/Documentation/devicetree/bindings/pwm/allwinner,sun50i-h616-pwm.yaml
> new file mode 100644
> index 000000000000..b89735ad3a43
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pwm/allwinner,sun50i-h616-pwm.yaml
> @@ -0,0 +1,67 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/pwm/allwinner,sun50i-h616-pwm.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Allwinner H616 PWM
> +
> +maintainers:
> +  - Richard Genoud <richard.genoud at bootlin.com>
> +
> +description: |

Do not need '|' unless you need to preserve formatting.

> +  Allwinner H616 PWM can generate standard PWM signals with variable pulse width
> +  and period.
> +  Also, instead of a PWM signal, a channel can be used to provide a clock.
> +
> +properties:
> +  compatible:
> +    const: allwinner,sun50i-h616-pwm
> +
> +  reg:
> +    maxItems: 1
> +
> +  clocks:
> +    items:
> +      - description: Bus Clock
> +

Are you sure there is no first clock? Really, really sure? If you add it
later, I would be pretty sad, because that's unnecessary duplication of
binidngs....

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof



From victor.liu at nxp.com  Sun Dec  7 22:57:34 2025
From: victor.liu at nxp.com (Liu Ying)
Date: Mon, 8 Dec 2025 14:57:34 +0800
Subject: [PATCH v7 2/3] drm/bridge: imx: Add i.MX93 parallel display
 format configuration support
In-Reply-To: <20251202-v6-18-topic-imx93-parallel-display-v7-2-2cce31d64608@pengutronix.de>
References: <20251202-v6-18-topic-imx93-parallel-display-v7-0-2cce31d64608@pengutronix.de>
 <20251202-v6-18-topic-imx93-parallel-display-v7-2-2cce31d64608@pengutronix.de>
Message-ID: <f53be351-e059-4a71-bbbd-7a893e954169@nxp.com>

Hi Marco,

On 12/02/2025, Marco Felsch wrote:
> From: Liu Ying <victor.liu at nxp.com>
> 
> NXP i.MX93 mediamix blk-ctrl contains one DISPLAY_MUX register which
> configures parallel display format by using the "PARALLEL_DISP_FORMAT"
> field. Add a DRM bridge driver to support the display format configuration.
> 
> Signed-off-by: Liu Ying <victor.liu at nxp.com>
> [m.felsch at pengutronix.de: port to v6.18-rc1]
> [m.felsch at pengutronix.de: add review feedback (Alexander)]
> [m.felsch at pengutronix.de: fix to short Kconfig description (checkpath)]
> [m.felsch at pengutronix.de: use "GPL" instead of "GPL v2" (checkpatch)]
> [m.felsch at pengutronix.de: make use of reg property]
> [m.felsch at pengutronix.de: add bus-width support]
> Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
> ---
>  drivers/gpu/drm/bridge/imx/Kconfig      |  11 ++
>  drivers/gpu/drm/bridge/imx/Makefile     |   1 +
>  drivers/gpu/drm/bridge/imx/imx93-pdfc.c | 227 ++++++++++++++++++++++++++++++++
>  3 files changed, 239 insertions(+)
> 
> diff --git a/drivers/gpu/drm/bridge/imx/Kconfig b/drivers/gpu/drm/bridge/imx/Kconfig
> index 9a480c6abb856276df9b71d23b39a43b3a9c542d..28fd7a00473a0ec50bf0ffb5d50972abc209ceec 100644
> --- a/drivers/gpu/drm/bridge/imx/Kconfig
> +++ b/drivers/gpu/drm/bridge/imx/Kconfig
> @@ -88,4 +88,15 @@ config DRM_IMX93_MIPI_DSI
>  	  Choose this to enable MIPI DSI controller found in Freescale i.MX93
>  	  processor.
>  
> +config DRM_IMX93_PARALLEL_DISP_FMT_CONFIG
> +	tristate "NXP i.MX91/i.MX93 parallel display format configuration"
> +	depends on OF
> +	select DRM_KMS_HELPER
> +	help
> +	  On i.MX93 and i.MX91 SoCs the parallel display format output is
> +	  controlled via the MEDIAMIX BLK-CTRL DISPLAY_MUX.
> +
> +	  Say 'Y' or 'M' if you use the parallel display output path on a
> +	  i.MX93 or i.MX91 SoC.
> +
>  endif # ARCH_MXC || COMPILE_TEST
> diff --git a/drivers/gpu/drm/bridge/imx/Makefile b/drivers/gpu/drm/bridge/imx/Makefile
> index dd5d4858480663bade98bd58039d1cb6f8aa18da..f4ccc5cbef72a576443d5fecf666b76dfba8aa94 100644
> --- a/drivers/gpu/drm/bridge/imx/Makefile
> +++ b/drivers/gpu/drm/bridge/imx/Makefile
> @@ -8,3 +8,4 @@ obj-$(CONFIG_DRM_IMX8QXP_PIXEL_COMBINER) += imx8qxp-pixel-combiner.o
>  obj-$(CONFIG_DRM_IMX8QXP_PIXEL_LINK) += imx8qxp-pixel-link.o
>  obj-$(CONFIG_DRM_IMX8QXP_PIXEL_LINK_TO_DPI) += imx8qxp-pxl2dpi.o
>  obj-$(CONFIG_DRM_IMX93_MIPI_DSI) += imx93-mipi-dsi.o
> +obj-$(CONFIG_DRM_IMX93_PARALLEL_DISP_FMT_CONFIG) += imx93-pdfc.o
> diff --git a/drivers/gpu/drm/bridge/imx/imx93-pdfc.c b/drivers/gpu/drm/bridge/imx/imx93-pdfc.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..624389def0ac3f24158edc64a8913375a4cc2f12
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/imx/imx93-pdfc.c
> @@ -0,0 +1,227 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +
> +/*
> + * Copyright 2022-2025 NXP
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/bits.h>
> +#include <linux/media-bus-format.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_graph.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +
> +#include <drm/drm_atomic_state_helper.h>
> +#include <drm/drm_bridge.h>
> +#include <drm/drm_print.h>

Drop this header file if you won't use DRM_DEV_DEBUG_DRIVER() in v5.

> +
> +#define PARALLEL_DISP_FORMAT		GENMASK(10, 8)
> +#define FORMAT_RGB888_TO_RGB888		FIELD_PREP(PARALLEL_DISP_FORMAT, 0)
> +#define FORMAT_RGB888_TO_RGB666		FIELD_PREP(PARALLEL_DISP_FORMAT, 1)
> +#define FORMAT_RGB565_TO_RGB565		FIELD_PREP(PARALLEL_DISP_FORMAT, 2)
> +
> +struct imx93_pdfc {
> +	struct drm_bridge bridge;
> +	struct drm_bridge *next_bridge;
> +	struct device *dev;
> +	struct regmap *regmap;
> +	u64 disp_mux_reg_off;
> +	u32 phy_bus_width;
> +};
> +
> +static int
> +imx93_pdfc_bridge_attach(struct drm_bridge *bridge, struct drm_encoder *encoder,
> +			 enum drm_bridge_attach_flags flags)
> +{
> +	struct imx93_pdfc *pdfc = bridge->driver_private;
> +
> +	return drm_bridge_attach(bridge->encoder, pdfc->next_bridge, bridge, flags);
> +}
> +
> +static void imx93_pdfc_bridge_atomic_enable(struct drm_bridge *bridge,
> +					    struct drm_atomic_state *state)
> +{
> +	struct imx93_pdfc *pdfc = bridge->driver_private;
> +	const struct drm_bridge_state *bridge_state;
> +	unsigned int mask = PARALLEL_DISP_FORMAT;
> +	unsigned int val;
> +
> +	bridge_state = drm_atomic_get_new_bridge_state(state, bridge);
> +
> +	switch (bridge_state->output_bus_cfg.format) {
> +	case MEDIA_BUS_FMT_RGB888_1X24:
> +		val = FORMAT_RGB888_TO_RGB888;
> +		if (pdfc->phy_bus_width == 18) {
> +			/*
> +			 * Can be valid if physical bus limitation exist,

s/exist/exists/

> +			 * therefore use dev_dbg().
> +			 */
> +			dev_dbg(pdfc->dev, "Truncate two LSBs from each color\n");
> +			val = FORMAT_RGB888_TO_RGB666;
> +		}
> +		break;
> +	case MEDIA_BUS_FMT_RGB666_1X18:
> +		val = FORMAT_RGB888_TO_RGB666;
> +		break;
> +	case MEDIA_BUS_FMT_RGB565_1X16:
> +		val = FORMAT_RGB565_TO_RGB565;
> +		break;
> +	}
> +
> +	regmap_update_bits(pdfc->regmap, pdfc->disp_mux_reg_off, mask, val);
> +}
> +
> +static const u32 imx93_pdfc_bus_output_fmts[] = {
> +	MEDIA_BUS_FMT_RGB888_1X24,
> +	MEDIA_BUS_FMT_RGB666_1X18,
> +	MEDIA_BUS_FMT_RGB565_1X16,
> +	MEDIA_BUS_FMT_FIXED
> +};
> +
> +static bool imx93_pdfc_bus_output_fmt_supported(u32 fmt)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(imx93_pdfc_bus_output_fmts); i++) {
> +		if (imx93_pdfc_bus_output_fmts[i] == fmt)
> +			return true;
> +	}
> +
> +	return false;
> +}
> +
> +static u32 *
> +imx93_pdfc_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
> +					    struct drm_bridge_state *bridge_state,
> +					    struct drm_crtc_state *crtc_state,
> +					    struct drm_connector_state *conn_state,
> +					    u32 output_fmt,
> +					    unsigned int *num_input_fmts)
> +{
> +	u32 *input_fmts;
> +
> +	*num_input_fmts = 0;
> +
> +	if (!imx93_pdfc_bus_output_fmt_supported(output_fmt))
> +		return NULL;
> +
> +	input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
> +	if (!input_fmts)
> +		return NULL;
> +
> +	switch (output_fmt) {
> +	case MEDIA_BUS_FMT_RGB888_1X24:
> +	case MEDIA_BUS_FMT_RGB565_1X16:
> +		input_fmts[0] = output_fmt;
> +		break;
> +	case MEDIA_BUS_FMT_RGB666_1X18:
> +	case MEDIA_BUS_FMT_FIXED:
> +		input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24;
> +		break;
> +	}
> +
> +	*num_input_fmts = 1;
> +
> +	return input_fmts;
> +}
> +
> +static int imx93_pdfc_bridge_atomic_check(struct drm_bridge *bridge,
> +					  struct drm_bridge_state *bridge_state,
> +					  struct drm_crtc_state *crtc_state,
> +					  struct drm_connector_state *conn_state)
> +{
> +	struct imx93_pdfc *pdfc = bridge->driver_private;
> +
> +	switch (bridge_state->output_bus_cfg.format) {
> +	case MEDIA_BUS_FMT_RGB888_1X24:
> +	case MEDIA_BUS_FMT_RGB666_1X18:
> +	case MEDIA_BUS_FMT_RGB565_1X16:

The case MEDIA_BUS_FMT_FIXED is also valid.

> +		return 0;
> +	default:
> +		dev_warn(pdfc->dev, "Unsupported output bus format: 0x%x\n",
> +			 bridge_state->output_bus_cfg.format);
> +		return -EINVAL;
> +	}
> +}
> +
> +static const struct drm_bridge_funcs funcs = {
> +	.attach			= imx93_pdfc_bridge_attach,
> +	.atomic_enable		= imx93_pdfc_bridge_atomic_enable,
> +	.atomic_duplicate_state	= drm_atomic_helper_bridge_duplicate_state,
> +	.atomic_destroy_state	= drm_atomic_helper_bridge_destroy_state,
> +	.atomic_get_input_bus_fmts	= imx93_pdfc_bridge_atomic_get_input_bus_fmts,
> +	.atomic_check		= imx93_pdfc_bridge_atomic_check,
> +	.atomic_reset		= drm_atomic_helper_bridge_reset,
> +};
> +
> +static int imx93_pdfc_bridge_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct imx93_pdfc *pdfc;
> +	struct device_node *ep;
> +	int err;
> +
> +	pdfc = devm_drm_bridge_alloc(dev, struct imx93_pdfc, bridge, &funcs);
> +	if (IS_ERR(pdfc))
> +		return PTR_ERR(pdfc);
> +
> +	pdfc->regmap = syscon_node_to_regmap(dev->of_node->parent);
> +	if (IS_ERR(pdfc->regmap))
> +		return dev_err_probe(dev, PTR_ERR(pdfc->regmap),
> +				     "failed to get regmap\n");
> +
> +	err = of_property_read_reg(dev->of_node, 0, &pdfc->disp_mux_reg_off, NULL);
> +	if (err)
> +		return dev_err_probe(dev, err,
> +				     "failed to get display-mux reg\n");
> +
> +	/* No limits per default */
> +	pdfc->phy_bus_width = 24;
> +
> +	/* Get output ep (port1/endpoint0) */
> +	ep = of_graph_get_endpoint_by_regs(dev->of_node, 1, 0);

Nit: DT binding just defines endpoint not endpoint0, so set the reg parameter
to -1.

> +	if (ep) {
> +		err = of_property_read_u32(ep, "bus-width", &pdfc->phy_bus_width);
> +		of_node_put(ep);
> +
> +		/* bus-width is optional but it must have valid data if present */
> +		if (err && err != -EINVAL)
> +			return dev_err_probe(dev, err,
> +					     "failed to query bus-width\n");
> +	}
> +
> +	pdfc->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
> +	if (IS_ERR(pdfc->next_bridge))
> +		return dev_err_probe(dev, PTR_ERR(pdfc->next_bridge),
> +				     "failed to get next bridge\n");
> +
> +	pdfc->dev = dev;
> +	pdfc->bridge.driver_private = pdfc;
> +	pdfc->bridge.of_node = dev->of_node;
> +	pdfc->bridge.type = DRM_MODE_CONNECTOR_DPI;
> +
> +	return devm_drm_bridge_add(dev, &pdfc->bridge);
> +}
> +
> +static const struct of_device_id imx93_pdfc_dt_ids[] = {
> +	{ .compatible = "nxp,imx93-pdfc", },

The cover letter and Kconfig say that both i.MX91 and i.MX93 are supported,
so need an additional compatible string for i.MX91?

> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, imx93_pdfc_dt_ids);
> +
> +static struct platform_driver imx93_pdfc_bridge_driver = {
> +	.probe	= imx93_pdfc_bridge_probe,
> +	.driver	= {
> +		.of_match_table = imx93_pdfc_dt_ids,
> +		.name = "imx93_pdfc",
> +	},
> +};
> +module_platform_driver(imx93_pdfc_bridge_driver);
> +
> +MODULE_DESCRIPTION("NXP i.MX93 parallel display format configuration driver");
> +MODULE_AUTHOR("Liu Ying <victor.liu at nxp.com>");
> +MODULE_LICENSE("GPL");
> 


-- 
Regards,
Liu Ying


From francesco at dolcini.it  Sun Dec  7 22:57:07 2025
From: francesco at dolcini.it (Francesco Dolcini)
Date: Mon, 8 Dec 2025 07:57:07 +0100
Subject: [PATCH 2/2] arm64: dts: freescale: imx95: Add support for i.MX95
 15x15 FRDM board
In-Reply-To: <20251207-127-v1-2-5a2eeb69f150@nxp.com>
References: <20251207-127-v1-0-5a2eeb69f150@nxp.com>
 <20251207-127-v1-2-5a2eeb69f150@nxp.com>
Message-ID: <20251208065707.GA15128@francesco-nb>

Hello Lei,

On Sun, Dec 07, 2025 at 05:26:06AM -0800, Lei Xu wrote:
> The i.MX95 15x15 FRDM board is a compact and cost-effective development
> platform based on the i.MX95 applications processor.

...

> diff --git a/arch/arm64/boot/dts/freescale/imx95-15x15-frdm.dts b/arch/arm64/boot/dts/freescale/imx95-15x15-frdm.dts
> new file mode 100644
> index 000000000000..61e815c858b8
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx95-15x15-frdm.dts

...

> +
> +/* Default settings in i.mx95.dtsi are for i.MX95 19x19 package.
> + * Override here for the i.MX95 15x15 package.
> + */
> +&netc_bus0 {
> +	msi-map = <0x0 &its 0x60 0x1>,	//ENETC0 PF
> +		  <0x10 &its 0x61 0x1>, //ENETC0 VF0
> +		  <0x20 &its 0x62 0x1>, //ENETC0 VF1
> +		  <0x40 &its 0x63 0x1>, //ENETC1 PF
> +		  <0x50 &its 0x65 0x1>, //ENETC1 VF0
> +		  <0x60 &its 0x66 0x1>, //ENETC1 VF1
> +		  <0x80 &its 0x64 0x1>, //ENETC2 PF
> +		  <0xc0 &its 0x67 0x1>; //NETC Timer
> +	iommu-map = <0x0 &smmu 0x20 0x1>,
> +		    <0x10 &smmu 0x21 0x1>,
> +		    <0x20 &smmu 0x22 0x1>,
> +		    <0x40 &smmu 0x23 0x1>,
> +		    <0x50 &smmu 0x25 0x1>,
> +		    <0x60 &smmu 0x26 0x1>,
> +		    <0x80 &smmu 0x24 0x1>,
> +		    <0xc0 &smmu 0x27 0x1>;
> +};

If the 19x19 and 15x15 i.MX95 requires something different you should
have a different soc dtsi. Probably creating a new imx95-$something
dtsi, that includes the existing imx95.dtsi and override this property.

This solution does not scale, please fix it.

Francesco



From krzk at kernel.org  Sun Dec  7 23:13:22 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 8 Dec 2025 08:13:22 +0100
Subject: [PATCH 1/2] dt-bindings: arm: fsl: Add compatible for i.MX95
 15x15 FRDM board
In-Reply-To: <20251207-127-v1-1-5a2eeb69f150@nxp.com>
References: <20251207-127-v1-0-5a2eeb69f150@nxp.com>
 <20251207-127-v1-1-5a2eeb69f150@nxp.com>
Message-ID: <a2b4cad2-28a8-4fcf-857a-cd002f2c1211@kernel.org>

On 07/12/2025 14:26, Lei Xu wrote:
> Introduce a new DT compatible string for the NXP i.MX95 15x15 FRDM
> development board, a compact and cost-effective platform based on
> the i.MX95 applications processor.
> 
> Signed-off-by: Lei Xu <lei.xu at nxp.com>
> ---
>  Documentation/devicetree/bindings/arm/fsl.yaml | 1 +
>  1 file changed, 1 insertion(+)


Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof


From nicolas.frattaroli at collabora.com  Sun Dec  7 23:24:52 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Mon, 08 Dec 2025 08:24:52 +0100
Subject: [PATCH v2 5/8] drm/rockchip: vop2: Enforce AFBC source alignment in
 plane_check
In-Reply-To: <f9f7b446-8575-4f16-aa96-5197b22846e3@rock-chips.com>
References: <20251206-vop2-atomic-fixups-v2-0-7fb45bbfbebd@collabora.com>
 <20251206-vop2-atomic-fixups-v2-5-7fb45bbfbebd@collabora.com>
 <f9f7b446-8575-4f16-aa96-5197b22846e3@rock-chips.com>
Message-ID: <4696988.LvFx2qVVIh@workhorse>

On Monday, 8 December 2025 03:48:24 Central European Standard Time Chaoyi Chen wrote:
> Hello Nicolas, Daniel,
> 
> On 12/7/2025 4:45 AM, Nicolas Frattaroli wrote:
> > From: Daniel Stone <daniels at collabora.com>
> > 
> > Planes can only source AFBC framebuffers at multiples of 4px wide on
> > RK3566/RK3568. Instead of clipping on all SoCs when the user asks for an
> > unaligned source rectangle, reject the configuration in the plane's
> > atomic check on RK3566/RK3568 only.
> > 
> > Signed-off-by: Daniel Stone <daniels at collabora.com>
> > [Make RK3566/RK3568 specific, reword message]
> > Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
> > ---
> >  drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 14 +++++++++-----
> >  1 file changed, 9 insertions(+), 5 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> > index bc1ed0ffede0..e23213337104 100644
> > --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> > @@ -1076,6 +1076,13 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
> >  		return -EINVAL;
> >  	}
> >  
> > +	if (vop2->version == VOP_VERSION_RK3568 && drm_is_afbc(fb->modifier) && src_w % 4) {
> > +		drm_dbg_kms(vop2->drm,
> > +			    "AFBC source rectangles must be 4-byte aligned; is %d\n",
> > +			    src_w);
> > +		return -EINVAL;
> > +	}
> > +
> >  	return 0;
> >  }
> >  
> > @@ -1237,11 +1244,8 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
> >  	WARN_ON(src_w < 4);
> >  	WARN_ON(src_h < 4);
> >  
> > -	if (afbc_en && src_w % 4) {
> > -		drm_dbg_kms(vop2->drm, "vp%d %s src_w[%d] not 4 pixel aligned\n",
> > -			    vp->id, win->data->name, src_w);
> > -		src_w = ALIGN_DOWN(src_w, 4);
> > -	}
> > +	if (vop2->version == VOP_VERSION_RK3568 && drm_is_afbc(fb->modifier))
> > +		WARN_ON(src_w % 4);
> >  
> >  	act_info = (src_h - 1) << 16 | ((src_w - 1) & 0xffff);
> >  	dsp_info = (dsp_h - 1) << 16 | ((dsp_w - 1) & 0xffff);
> > 
> 
> You haven't replied to Andy's comment yet [0].
> 
> [0] https://lore.kernel.org/dri-devel/7b4e26ec.75f3.19a77276b53.Coremail.andyshrk at 163.com/
> 

Hello,

I addressed the follow-ups where it was clarified that the 4 pixel
limitation was RK3566/RK3568-only. I'm not going to bring back the
post-atomic_check modification for a fast path, but I'm open to
suggestions on how to do this differently.

One solution might be to modify the state with the ALIGN_DOWN stuff
in atomic_check instead, where userspace is then aware of the change
being done to its requested parameters. I'll need to double-check
whether this is in line with atomic modesetting's design.

Kind regards,
Nicolas Frattaroli




From patrice.chotard at foss.st.com  Sun Dec  7 23:29:15 2025
From: patrice.chotard at foss.st.com (Patrice Chotard)
Date: Mon, 8 Dec 2025 08:29:15 +0100
Subject: [PATCH v2 8/8] spi: stm32-qspi: Simplify SMIE interrupt test
In-Reply-To: <20251208-upstream_qspi_ospi_updates-v2-0-62526c9467dc@foss.st.com>
References: <20251208-upstream_qspi_ospi_updates-v2-0-62526c9467dc@foss.st.com>
Message-ID: <20251208-upstream_qspi_ospi_updates-v2-8-62526c9467dc@foss.st.com>

SR_SMF status bit can only be set if CR_SMIE was previously set,
keep status bit check only.

Signed-off-by: Patrice Chotard <patrice.chotard at foss.st.com>
---
 drivers/spi/spi-stm32-qspi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c
index d6f6f9d4e5be..2a0ee96786fa 100644
--- a/drivers/spi/spi-stm32-qspi.c
+++ b/drivers/spi/spi-stm32-qspi.c
@@ -132,7 +132,7 @@ static irqreturn_t stm32_qspi_irq(int irq, void *dev_id)
 	cr = readl_relaxed(qspi->io_base + QSPI_CR);
 	sr = readl_relaxed(qspi->io_base + QSPI_SR);
 
-	if (cr & CR_SMIE && sr & SR_SMF) {
+	if (sr & SR_SMF) {
 		/* disable irq */
 		cr &= ~CR_SMIE;
 		writel_relaxed(cr, qspi->io_base + QSPI_CR);

-- 
2.43.0



From patrice.chotard at foss.st.com  Sun Dec  7 23:29:07 2025
From: patrice.chotard at foss.st.com (Patrice Chotard)
Date: Mon, 8 Dec 2025 08:29:07 +0100
Subject: [PATCH v2 0/8] spi: stm32: Update for OSPI and QSPI drivers
Message-ID: <20251208-upstream_qspi_ospi_updates-v2-0-62526c9467dc@foss.st.com>

This serie applies the following updates on the spi-stm32-ospi and
spi-stm32-qspi dirvers :

  _ Update FIFO accesses using u16 and u32 when possible instead of u8
    only to optimize throughput.
  _ Replace Transmit Complete and Transmit Error interrupt management by
    usage of read_poll_timeout_atomic() to optimize throughtput.
  _ Simplify Status Match interrupt check.
  _ Set DMA burst configuration dynamically.

Signed-off-by: Patrice Chotard <patrice.chotard at foss.st.com>
---
Changes in v2:
- Fix compilation error in stm32_ospi_wait_cmd()
- Link to v1: https://lore.kernel.org/r/20251205-upstream_qspi_ospi_updates-v1-0-7e6c8b9f5141 at foss.st.com

---
Patrice Chotard (8):
      spi: stm32-ospi: Set DMA maxburst dynamically
      spi: stm32-ospi: Optimize FIFO accesses using u16 or u32
      spi: stm32-ospi: Remove CR_TCIE and CR_TEIE irq usage
      spi: stm32-ospi: Simplify SMIE interrupt test
      spi: stm32-qspi: Set DMA maxburst dynamically
      spi: stm32-qspi: Optimize FIFO accesses using u16 or u32
      spi: stm32-qspi: Remove CR_TCIE and CR_TEIE irq usage
      spi: stm32-qspi: Simplify SMIE interrupt test

 drivers/spi/spi-stm32-ospi.c | 107 +++++++++++++++++++++++++----------------
 drivers/spi/spi-stm32-qspi.c | 111 +++++++++++++++++++++++++------------------
 2 files changed, 132 insertions(+), 86 deletions(-)
---
base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
change-id: 20251205-upstream_qspi_ospi_updates-4faf7a3b098c

Best regards,
-- 
Patrice Chotard <patrice.chotard at foss.st.com>



From patrice.chotard at foss.st.com  Sun Dec  7 23:29:09 2025
From: patrice.chotard at foss.st.com (Patrice Chotard)
Date: Mon, 8 Dec 2025 08:29:09 +0100
Subject: [PATCH v2 2/8] spi: stm32-ospi: Optimize FIFO accesses using u16
 or u32
In-Reply-To: <20251208-upstream_qspi_ospi_updates-v2-0-62526c9467dc@foss.st.com>
References: <20251208-upstream_qspi_ospi_updates-v2-0-62526c9467dc@foss.st.com>
Message-ID: <20251208-upstream_qspi_ospi_updates-v2-2-62526c9467dc@foss.st.com>

FIFO accesses uses u8 only for read/write.
In order to optimize throughput, add u16 or u32 read/write
accesses when possible.

Running mtd_speedtest on a 4MB sNOR partition using a
stm32mp257f-ev1 board gives the following results:

           before        after   gain
Read :  5693 KiB/s  21139 KiB/s   371%
Write:   765 KiB/s    910 KiB/s    19%

Signed-off-by: Patrice Chotard <patrice.chotard at foss.st.com>
---
 drivers/spi/spi-stm32-ospi.c | 47 +++++++++++++++++++++++++++++++++++---------
 1 file changed, 38 insertions(+), 9 deletions(-)

diff --git a/drivers/spi/spi-stm32-ospi.c b/drivers/spi/spi-stm32-ospi.c
index d733e37f0435..a6f53f06200e 100644
--- a/drivers/spi/spi-stm32-ospi.c
+++ b/drivers/spi/spi-stm32-ospi.c
@@ -142,14 +142,32 @@ struct stm32_ospi {
 	struct mutex lock;
 };
 
-static void stm32_ospi_read_fifo(u8 *val, void __iomem *addr)
+static void stm32_ospi_read_fifo(void *val, void __iomem *addr, u8 len)
 {
-	*val = readb_relaxed(addr);
+	switch (len) {
+	case sizeof(u32):
+		*((u32 *)val) = readl_relaxed(addr);
+		break;
+	case sizeof(u16):
+		*((u16 *)val) = readw_relaxed(addr);
+		break;
+	case sizeof(u8):
+		*((u8 *)val) = readb_relaxed(addr);
+	};
 }
 
-static void stm32_ospi_write_fifo(u8 *val, void __iomem *addr)
+static void stm32_ospi_write_fifo(void *val, void __iomem *addr, u8 len)
 {
-	writeb_relaxed(*val, addr);
+	switch (len) {
+	case sizeof(u32):
+		writel_relaxed(*((u32 *)val), addr);
+		break;
+	case sizeof(u16):
+		writew_relaxed(*((u16 *)val), addr);
+		break;
+	case sizeof(u8):
+		writeb_relaxed(*((u8 *)val), addr);
+	};
 }
 
 static int stm32_ospi_abort(struct stm32_ospi *ospi)
@@ -172,19 +190,20 @@ static int stm32_ospi_abort(struct stm32_ospi *ospi)
 	return timeout;
 }
 
-static int stm32_ospi_poll(struct stm32_ospi *ospi, u8 *buf, u32 len, bool read)
+static int stm32_ospi_poll(struct stm32_ospi *ospi, void *buf, u32 len, bool read)
 {
 	void __iomem *regs_base = ospi->regs_base;
-	void (*fifo)(u8 *val, void __iomem *addr);
+	void (*fifo)(void *val, void __iomem *addr, u8 len);
 	u32 sr;
 	int ret;
+	u8 step;
 
 	if (read)
 		fifo = stm32_ospi_read_fifo;
 	else
 		fifo = stm32_ospi_write_fifo;
 
-	while (len--) {
+	while (len) {
 		ret = readl_relaxed_poll_timeout_atomic(regs_base + OSPI_SR,
 							sr, sr & SR_FTF, 1,
 							STM32_FIFO_TIMEOUT_US);
@@ -193,7 +212,17 @@ static int stm32_ospi_poll(struct stm32_ospi *ospi, u8 *buf, u32 len, bool read)
 				len, sr);
 			return ret;
 		}
-		fifo(buf++, regs_base + OSPI_DR);
+
+		if (len >= sizeof(u32))
+			step = sizeof(u32);
+		else if (len >= sizeof(u16))
+			step = sizeof(u16);
+		else
+			step = sizeof(u8);
+
+		fifo(buf, regs_base + OSPI_DR, step);
+		len -= step;
+		buf += step;
 	}
 
 	return 0;
@@ -408,7 +437,7 @@ static int stm32_ospi_xfer(struct stm32_ospi *ospi, const struct spi_mem_op *op)
 	if (op->data.dir == SPI_MEM_DATA_IN)
 		buf = op->data.buf.in;
 	else
-		buf = (u8 *)op->data.buf.out;
+		buf = (void *)op->data.buf.out;
 
 	return stm32_ospi_poll(ospi, buf, op->data.nbytes,
 			       op->data.dir == SPI_MEM_DATA_IN);

-- 
2.43.0



From patrice.chotard at foss.st.com  Sun Dec  7 23:29:08 2025
From: patrice.chotard at foss.st.com (Patrice Chotard)
Date: Mon, 8 Dec 2025 08:29:08 +0100
Subject: [PATCH v2 1/8] spi: stm32-ospi: Set DMA maxburst dynamically
In-Reply-To: <20251208-upstream_qspi_ospi_updates-v2-0-62526c9467dc@foss.st.com>
References: <20251208-upstream_qspi_ospi_updates-v2-0-62526c9467dc@foss.st.com>
Message-ID: <20251208-upstream_qspi_ospi_updates-v2-1-62526c9467dc@foss.st.com>

Set src_maxburst and dst_maxburst dynamically from DMA
capabilities.

Signed-off-by: Patrice Chotard <patrice.chotard at foss.st.com>
---
 drivers/spi/spi-stm32-ospi.c | 27 ++++++++++++++++++++++-----
 1 file changed, 22 insertions(+), 5 deletions(-)

diff --git a/drivers/spi/spi-stm32-ospi.c b/drivers/spi/spi-stm32-ospi.c
index f36fd36da269..d733e37f0435 100644
--- a/drivers/spi/spi-stm32-ospi.c
+++ b/drivers/spi/spi-stm32-ospi.c
@@ -278,10 +278,19 @@ static irqreturn_t stm32_ospi_irq(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-static void stm32_ospi_dma_setup(struct stm32_ospi *ospi,
-			 struct dma_slave_config *dma_cfg)
+static int stm32_ospi_dma_setup(struct stm32_ospi *ospi,
+				struct dma_slave_config *dma_cfg)
 {
+	struct dma_slave_caps caps;
+	int ret = 0;
+
 	if (dma_cfg && ospi->dma_chrx) {
+		ret = dma_get_slave_caps(ospi->dma_chrx, &caps);
+		if (ret)
+			return ret;
+
+		dma_cfg->src_maxburst = caps.max_burst / dma_cfg->src_addr_width;
+
 		if (dmaengine_slave_config(ospi->dma_chrx, dma_cfg)) {
 			dev_err(ospi->dev, "dma rx config failed\n");
 			dma_release_channel(ospi->dma_chrx);
@@ -290,6 +299,12 @@ static void stm32_ospi_dma_setup(struct stm32_ospi *ospi,
 	}
 
 	if (dma_cfg && ospi->dma_chtx) {
+		ret = dma_get_slave_caps(ospi->dma_chtx, &caps);
+		if (ret)
+			return ret;
+
+		dma_cfg->dst_maxburst = caps.max_burst / dma_cfg->dst_addr_width;
+
 		if (dmaengine_slave_config(ospi->dma_chtx, dma_cfg)) {
 			dev_err(ospi->dev, "dma tx config failed\n");
 			dma_release_channel(ospi->dma_chtx);
@@ -298,6 +313,8 @@ static void stm32_ospi_dma_setup(struct stm32_ospi *ospi,
 	}
 
 	init_completion(&ospi->dma_completion);
+
+	return ret;
 }
 
 static int stm32_ospi_tx_mm(struct stm32_ospi *ospi,
@@ -899,9 +916,9 @@ static int stm32_ospi_probe(struct platform_device *pdev)
 	dma_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
 	dma_cfg.src_addr = ospi->regs_phys_base + OSPI_DR;
 	dma_cfg.dst_addr = ospi->regs_phys_base + OSPI_DR;
-	dma_cfg.src_maxburst = 4;
-	dma_cfg.dst_maxburst = 4;
-	stm32_ospi_dma_setup(ospi, &dma_cfg);
+	ret = stm32_ospi_dma_setup(ospi, &dma_cfg);
+	if (ret)
+		return ret;
 
 	mutex_init(&ospi->lock);
 

-- 
2.43.0



From patrice.chotard at foss.st.com  Sun Dec  7 23:29:10 2025
From: patrice.chotard at foss.st.com (Patrice Chotard)
Date: Mon, 8 Dec 2025 08:29:10 +0100
Subject: [PATCH v2 3/8] spi: stm32-ospi: Remove CR_TCIE and CR_TEIE irq
 usage
In-Reply-To: <20251208-upstream_qspi_ospi_updates-v2-0-62526c9467dc@foss.st.com>
References: <20251208-upstream_qspi_ospi_updates-v2-0-62526c9467dc@foss.st.com>
Message-ID: <20251208-upstream_qspi_ospi_updates-v2-3-62526c9467dc@foss.st.com>

Replace CR_TCIE and CR_TEIE irq usage by a read_poll_timeout_atomic() in
stm32_ospi_wait_cmd(). It will reduce the time waiting for TCF or TEF flags
to optimize throughput.

                                           before     after
average time spent in stm32_omi_wait_cmd:  5685 ns    923 ns

Signed-off-by: Patrice Chotard <patrice.chotard at foss.st.com>
---
 drivers/spi/spi-stm32-ospi.c | 31 ++++++-------------------------
 1 file changed, 6 insertions(+), 25 deletions(-)

diff --git a/drivers/spi/spi-stm32-ospi.c b/drivers/spi/spi-stm32-ospi.c
index a6f53f06200e..06632cdd1630 100644
--- a/drivers/spi/spi-stm32-ospi.c
+++ b/drivers/spi/spi-stm32-ospi.c
@@ -34,8 +34,6 @@
 #define CR_ABORT		BIT(1)
 #define CR_DMAEN		BIT(2)
 #define CR_FTHRES_SHIFT		8
-#define CR_TEIE			BIT(16)
-#define CR_TCIE			BIT(17)
 #define CR_SMIE			BIT(19)
 #define CR_APMS			BIT(22)
 #define CR_CSSEL		BIT(24)
@@ -106,7 +104,7 @@
 #define STM32_ABT_TIMEOUT_US		100000
 #define STM32_COMP_TIMEOUT_MS		5000
 #define STM32_BUSY_TIMEOUT_US		100000
-
+#define STM32_WAIT_CMD_TIMEOUT_US	5000
 
 #define STM32_AUTOSUSPEND_DELAY -1
 
@@ -116,7 +114,6 @@ struct stm32_ospi {
 	struct clk *clk;
 	struct reset_control *rstc;
 
-	struct completion data_completion;
 	struct completion match_completion;
 
 	struct dma_chan *dma_chtx;
@@ -240,22 +237,16 @@ static int stm32_ospi_wait_nobusy(struct stm32_ospi *ospi)
 static int stm32_ospi_wait_cmd(struct stm32_ospi *ospi)
 {
 	void __iomem *regs_base = ospi->regs_base;
-	u32 cr, sr;
+	u32 sr;
 	int err = 0;
 
-	if ((readl_relaxed(regs_base + OSPI_SR) & SR_TCF) ||
-	    ospi->fmode == CR_FMODE_APM)
+	if (ospi->fmode == CR_FMODE_APM)
 		goto out;
 
-	reinit_completion(&ospi->data_completion);
-	cr = readl_relaxed(regs_base + OSPI_CR);
-	writel_relaxed(cr | CR_TCIE | CR_TEIE, regs_base + OSPI_CR);
-
-	if (!wait_for_completion_timeout(&ospi->data_completion,
-				msecs_to_jiffies(STM32_COMP_TIMEOUT_MS)))
-		err = -ETIMEDOUT;
+	err = readl_relaxed_poll_timeout_atomic(ospi->regs_base + OSPI_SR, sr,
+						(sr & (SR_TEF | SR_TCF)), 1,
+						STM32_WAIT_CMD_TIMEOUT_US);
 
-	sr = readl_relaxed(regs_base + OSPI_SR);
 	if (sr & SR_TCF)
 		/* avoid false timeout */
 		err = 0;
@@ -293,15 +284,6 @@ static irqreturn_t stm32_ospi_irq(int irq, void *dev_id)
 		cr &= ~CR_SMIE;
 		writel_relaxed(cr, regs_base + OSPI_CR);
 		complete(&ospi->match_completion);
-
-		return IRQ_HANDLED;
-	}
-
-	if (sr & (SR_TEF | SR_TCF)) {
-		/* disable irq */
-		cr &= ~CR_TCIE & ~CR_TEIE;
-		writel_relaxed(cr, regs_base + OSPI_CR);
-		complete(&ospi->data_completion);
 	}
 
 	return IRQ_HANDLED;
@@ -884,7 +866,6 @@ static int stm32_ospi_get_resources(struct platform_device *pdev)
 		dev_info(dev, "No memory-map region found\n");
 	}
 
-	init_completion(&ospi->data_completion);
 	init_completion(&ospi->match_completion);
 
 	return 0;

-- 
2.43.0



From patrice.chotard at foss.st.com  Sun Dec  7 23:29:11 2025
From: patrice.chotard at foss.st.com (Patrice Chotard)
Date: Mon, 8 Dec 2025 08:29:11 +0100
Subject: [PATCH v2 4/8] spi: stm32-ospi: Simplify SMIE interrupt test
In-Reply-To: <20251208-upstream_qspi_ospi_updates-v2-0-62526c9467dc@foss.st.com>
References: <20251208-upstream_qspi_ospi_updates-v2-0-62526c9467dc@foss.st.com>
Message-ID: <20251208-upstream_qspi_ospi_updates-v2-4-62526c9467dc@foss.st.com>

SR_SMF status bit can only be set if CR_SMIE was previously set,
keep status bit check only.

Signed-off-by: Patrice Chotard <patrice.chotard at foss.st.com>
---
 drivers/spi/spi-stm32-ospi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/spi/spi-stm32-ospi.c b/drivers/spi/spi-stm32-ospi.c
index 06632cdd1630..c36df8d3f5cb 100644
--- a/drivers/spi/spi-stm32-ospi.c
+++ b/drivers/spi/spi-stm32-ospi.c
@@ -279,7 +279,7 @@ static irqreturn_t stm32_ospi_irq(int irq, void *dev_id)
 	cr = readl_relaxed(regs_base + OSPI_CR);
 	sr = readl_relaxed(regs_base + OSPI_SR);
 
-	if (cr & CR_SMIE && sr & SR_SMF) {
+	if (sr & SR_SMF) {
 		/* disable irq */
 		cr &= ~CR_SMIE;
 		writel_relaxed(cr, regs_base + OSPI_CR);

-- 
2.43.0



From patrice.chotard at foss.st.com  Sun Dec  7 23:29:14 2025
From: patrice.chotard at foss.st.com (Patrice Chotard)
Date: Mon, 8 Dec 2025 08:29:14 +0100
Subject: [PATCH v2 7/8] spi: stm32-qspi: Remove CR_TCIE and CR_TEIE irq
 usage
In-Reply-To: <20251208-upstream_qspi_ospi_updates-v2-0-62526c9467dc@foss.st.com>
References: <20251208-upstream_qspi_ospi_updates-v2-0-62526c9467dc@foss.st.com>
Message-ID: <20251208-upstream_qspi_ospi_updates-v2-7-62526c9467dc@foss.st.com>

Replace CR_TCIE and CR_TEIE irq usage by a read_poll_timeout_atomic() in
stm32_qspi_wait_cmd(). It will reduce the time waiting for TCF or TEF flags
to optimize throughput.
						before		after
average time spent in stm32_qspi_wait_cmd:	2615 ns		712 ns

Signed-off-by: Patrice Chotard <patrice.chotard at foss.st.com>
---
 drivers/spi/spi-stm32-qspi.c | 45 +++++++++++++-------------------------------
 1 file changed, 13 insertions(+), 32 deletions(-)

diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c
index c7f2b435d5ee..d6f6f9d4e5be 100644
--- a/drivers/spi/spi-stm32-qspi.c
+++ b/drivers/spi/spi-stm32-qspi.c
@@ -31,8 +31,6 @@
 #define CR_DFM			BIT(6)
 #define CR_FSEL			BIT(7)
 #define CR_FTHRES_SHIFT		8
-#define CR_TEIE			BIT(16)
-#define CR_TCIE			BIT(17)
 #define CR_FTIE			BIT(18)
 #define CR_SMIE			BIT(19)
 #define CR_TOIE			BIT(20)
@@ -86,11 +84,12 @@
 #define STM32_QSPI_MAX_MMAP_SZ	SZ_256M
 #define STM32_QSPI_MAX_NORCHIP	2
 
-#define STM32_FIFO_TIMEOUT_US 30000
-#define STM32_BUSY_TIMEOUT_US 100000
-#define STM32_ABT_TIMEOUT_US 100000
-#define STM32_COMP_TIMEOUT_MS 1000
-#define STM32_AUTOSUSPEND_DELAY -1
+#define STM32_FIFO_TIMEOUT_US		30000
+#define STM32_BUSY_TIMEOUT_US		100000
+#define STM32_ABT_TIMEOUT_US		100000
+#define STM32_WAIT_CMD_TIMEOUT_US	5000
+#define STM32_COMP_TIMEOUT_MS		1000
+#define STM32_AUTOSUSPEND_DELAY		-1
 
 struct stm32_qspi_flash {
 	u32 cs;
@@ -107,7 +106,6 @@ struct stm32_qspi {
 	struct clk *clk;
 	u32 clk_rate;
 	struct stm32_qspi_flash flash[STM32_QSPI_MAX_NORCHIP];
-	struct completion data_completion;
 	struct completion match_completion;
 	u32 fmode;
 
@@ -139,15 +137,6 @@ static irqreturn_t stm32_qspi_irq(int irq, void *dev_id)
 		cr &= ~CR_SMIE;
 		writel_relaxed(cr, qspi->io_base + QSPI_CR);
 		complete(&qspi->match_completion);
-
-		return IRQ_HANDLED;
-	}
-
-	if (sr & (SR_TEF | SR_TCF)) {
-		/* disable irq */
-		cr &= ~CR_TCIE & ~CR_TEIE;
-		writel_relaxed(cr, qspi->io_base + QSPI_CR);
-		complete(&qspi->data_completion);
 	}
 
 	return IRQ_HANDLED;
@@ -330,25 +319,18 @@ static int stm32_qspi_wait_nobusy(struct stm32_qspi *qspi)
 
 static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi)
 {
-	u32 cr, sr;
+	u32 sr;
 	int err = 0;
 
-	if ((readl_relaxed(qspi->io_base + QSPI_SR) & SR_TCF) ||
-	    qspi->fmode == CCR_FMODE_APM)
+	if (qspi->fmode == CCR_FMODE_APM)
 		goto out;
 
-	reinit_completion(&qspi->data_completion);
-	cr = readl_relaxed(qspi->io_base + QSPI_CR);
-	writel_relaxed(cr | CR_TCIE | CR_TEIE, qspi->io_base + QSPI_CR);
+	err = readl_relaxed_poll_timeout_atomic(qspi->io_base + QSPI_SR, sr,
+						(sr & (SR_TEF | SR_TCF)), 1,
+						STM32_WAIT_CMD_TIMEOUT_US);
 
-	if (!wait_for_completion_timeout(&qspi->data_completion,
-				msecs_to_jiffies(STM32_COMP_TIMEOUT_MS))) {
-		err = -ETIMEDOUT;
-	} else {
-		sr = readl_relaxed(qspi->io_base + QSPI_SR);
-		if (sr & SR_TEF)
-			err = -EIO;
-	}
+	if (sr & SR_TEF)
+		err = -EIO;
 
 out:
 	/* clear flags */
@@ -835,7 +817,6 @@ static int stm32_qspi_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	init_completion(&qspi->data_completion);
 	init_completion(&qspi->match_completion);
 
 	qspi->clk = devm_clk_get(dev, NULL);

-- 
2.43.0



From patrice.chotard at foss.st.com  Sun Dec  7 23:29:13 2025
From: patrice.chotard at foss.st.com (Patrice Chotard)
Date: Mon, 8 Dec 2025 08:29:13 +0100
Subject: [PATCH v2 6/8] spi: stm32-qspi: Optimize FIFO accesses using u16
 or u32
In-Reply-To: <20251208-upstream_qspi_ospi_updates-v2-0-62526c9467dc@foss.st.com>
References: <20251208-upstream_qspi_ospi_updates-v2-0-62526c9467dc@foss.st.com>
Message-ID: <20251208-upstream_qspi_ospi_updates-v2-6-62526c9467dc@foss.st.com>

FIFO accesses uses u8 only for read/write.
In order to optimize throughput, add u16 or u32 read/write
accesses when possible.

Running mtd_speedtest on a 4MB sNOR partition using a
stm32mp257f-ev1 board gives the following results:

           before        after   gain
Read :  5773 KiB/s  22170 KiB/s   384%
Write:   796 KiB/s    890 KiB/s    12%

Signed-off-by: Patrice Chotard <patrice.chotard at foss.st.com>
---
 drivers/spi/spi-stm32-qspi.c | 51 ++++++++++++++++++++++++++++++++++----------
 1 file changed, 40 insertions(+), 11 deletions(-)

diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c
index c131441e4dd4..c7f2b435d5ee 100644
--- a/drivers/spi/spi-stm32-qspi.c
+++ b/drivers/spi/spi-stm32-qspi.c
@@ -153,34 +153,53 @@ static irqreturn_t stm32_qspi_irq(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-static void stm32_qspi_read_fifo(u8 *val, void __iomem *addr)
+static void stm32_qspi_read_fifo(void *val, void __iomem *addr, u8 len)
 {
-	*val = readb_relaxed(addr);
+	switch (len) {
+	case sizeof(u32):
+		*((u32 *)val) = readl_relaxed(addr);
+		break;
+	case sizeof(u16):
+		*((u16 *)val) = readw_relaxed(addr);
+		break;
+	case sizeof(u8):
+		*((u8 *)val) = readb_relaxed(addr);
+	};
 }
 
-static void stm32_qspi_write_fifo(u8 *val, void __iomem *addr)
+static void stm32_qspi_write_fifo(void *val, void __iomem *addr, u8 len)
 {
-	writeb_relaxed(*val, addr);
+	switch (len) {
+	case sizeof(u32):
+		writel_relaxed(*((u32 *)val), addr);
+		break;
+	case sizeof(u16):
+		writew_relaxed(*((u16 *)val), addr);
+		break;
+	case sizeof(u8):
+		writeb_relaxed(*((u8 *)val), addr);
+	};
 }
 
 static int stm32_qspi_tx_poll(struct stm32_qspi *qspi,
 			      const struct spi_mem_op *op)
 {
-	void (*tx_fifo)(u8 *val, void __iomem *addr);
+	void (*fifo)(void *val, void __iomem *addr, u8 len);
 	u32 len = op->data.nbytes, sr;
-	u8 *buf;
+	void *buf;
 	int ret;
+	u8 step;
 
 	if (op->data.dir == SPI_MEM_DATA_IN) {
-		tx_fifo = stm32_qspi_read_fifo;
+		fifo = stm32_qspi_read_fifo;
 		buf = op->data.buf.in;
 
 	} else {
-		tx_fifo = stm32_qspi_write_fifo;
-		buf = (u8 *)op->data.buf.out;
+		fifo = stm32_qspi_write_fifo;
+		buf = (void *)op->data.buf.out;
 	}
 
-	while (len--) {
+	while (len) {
 		ret = readl_relaxed_poll_timeout_atomic(qspi->io_base + QSPI_SR,
 							sr, (sr & SR_FTF), 1,
 							STM32_FIFO_TIMEOUT_US);
@@ -189,7 +208,17 @@ static int stm32_qspi_tx_poll(struct stm32_qspi *qspi,
 				len, sr);
 			return ret;
 		}
-		tx_fifo(buf++, qspi->io_base + QSPI_DR);
+
+		if (len >= sizeof(u32))
+			step = sizeof(u32);
+		else if (len >= sizeof(u16))
+			step = sizeof(u16);
+		else
+			step = sizeof(u8);
+
+		fifo(buf, qspi->io_base + QSPI_DR, step);
+		len -= step;
+		buf += step;
 	}
 
 	return 0;

-- 
2.43.0



From patrice.chotard at foss.st.com  Sun Dec  7 23:29:12 2025
From: patrice.chotard at foss.st.com (Patrice Chotard)
Date: Mon, 8 Dec 2025 08:29:12 +0100
Subject: [PATCH v2 5/8] spi: stm32-qspi: Set DMA maxburst dynamically
In-Reply-To: <20251208-upstream_qspi_ospi_updates-v2-0-62526c9467dc@foss.st.com>
References: <20251208-upstream_qspi_ospi_updates-v2-0-62526c9467dc@foss.st.com>
Message-ID: <20251208-upstream_qspi_ospi_updates-v2-5-62526c9467dc@foss.st.com>

Set src_maxburst and dst_maxburst dynamically from DMA
capabilities.

Signed-off-by: Patrice Chotard <patrice.chotard at foss.st.com>
---
 drivers/spi/spi-stm32-qspi.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c
index f2d19f1c5ab1..c131441e4dd4 100644
--- a/drivers/spi/spi-stm32-qspi.c
+++ b/drivers/spi/spi-stm32-qspi.c
@@ -689,6 +689,7 @@ static int stm32_qspi_dma_setup(struct stm32_qspi *qspi)
 {
 	struct dma_slave_config dma_cfg;
 	struct device *dev = qspi->dev;
+	struct dma_slave_caps caps;
 	int ret = 0;
 
 	memset(&dma_cfg, 0, sizeof(dma_cfg));
@@ -697,8 +698,6 @@ static int stm32_qspi_dma_setup(struct stm32_qspi *qspi)
 	dma_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
 	dma_cfg.src_addr = qspi->phys_base + QSPI_DR;
 	dma_cfg.dst_addr = qspi->phys_base + QSPI_DR;
-	dma_cfg.src_maxburst = 4;
-	dma_cfg.dst_maxburst = 4;
 
 	qspi->dma_chrx = dma_request_chan(dev, "rx");
 	if (IS_ERR(qspi->dma_chrx)) {
@@ -707,6 +706,11 @@ static int stm32_qspi_dma_setup(struct stm32_qspi *qspi)
 		if (ret == -EPROBE_DEFER)
 			goto out;
 	} else {
+		ret = dma_get_slave_caps(qspi->dma_chrx, &caps);
+		if (ret)
+			return ret;
+
+		dma_cfg.src_maxburst = caps.max_burst / dma_cfg.src_addr_width;
 		if (dmaengine_slave_config(qspi->dma_chrx, &dma_cfg)) {
 			dev_err(dev, "dma rx config failed\n");
 			dma_release_channel(qspi->dma_chrx);
@@ -719,6 +723,11 @@ static int stm32_qspi_dma_setup(struct stm32_qspi *qspi)
 		ret = PTR_ERR(qspi->dma_chtx);
 		qspi->dma_chtx = NULL;
 	} else {
+		ret = dma_get_slave_caps(qspi->dma_chtx, &caps);
+		if (ret)
+			return ret;
+
+		dma_cfg.dst_maxburst = caps.max_burst / dma_cfg.dst_addr_width;
 		if (dmaengine_slave_config(qspi->dma_chtx, &dma_cfg)) {
 			dev_err(dev, "dma tx config failed\n");
 			dma_release_channel(qspi->dma_chtx);

-- 
2.43.0



From wenst at chromium.org  Sun Dec  7 23:33:01 2025
From: wenst at chromium.org (Chen-Yu Tsai)
Date: Mon,  8 Dec 2025 15:33:01 +0800
Subject: [RFC PATCH 0/3] arm64: dts: mediatek: Split Ciri into overlays
Message-ID: <20251208073306.75279-1-wenst@chromium.org>

Hi everyone,

This series intends to serve as an example on how we could reorganize
the Chromebook device trees into a common design base DTB and split-out
DTBOs for component options. There will be no SKU-specific DTBO that
handles changing the top level compatible and "model" properties. If
these are important or needed in place of the generic board strings,
the bootloader could be made to insert the correct ones.

A separate YAML file is created to keep a mapping between the composite
DTB and SKU-specific top level compatible strings. These are needed to
build a FIT image that the bootloader can then match the correct DTB
with its own known compatible strings.

I expect the last patch, which drops the SKU specifities and adds the
YAML file to be quite contentious. However I think it would greatly
reduce the number of source files we have to manage, given we have
or will have dozens of SKUs for some models.

This is related to my "Device Tree Metadata: How Bootloaders Pick DTBs
and Apply Overlays" talk at the Device Tree MC at Plumbers [1].


Thanks
ChenYu

[1] https://lpc.events/event/19/contributions/2025/ 

Chen-Yu Tsai (3):
  dt-bindings: arm: mediatek: Add generic Ciri "base" board
  arm64: dts: mt8188-ciri: Split into base and overlays based on
    components
  [EXAMPLE] arm64: dts: mediatek: ciri: Drop SKU-specific overlays

 .../devicetree/bindings/arm/mediatek.yaml     |  4 +
 arch/arm64/boot/dts/mediatek/Makefile         | 26 ++++++
 ...88-geralt-ciri-audio-max98390-es8326.dtso} | 40 ++++++---
 ...88-geralt-ciri-audio-max98390-rt5682s.dtso | 81 +++++++++++++++++++
 ...188-geralt-ciri-audio-tas2563-es8326.dtso} | 18 ++---
 ...88-geralt-ciri-audio-tas2563-rt5682s.dtso} | 46 +++++------
 .../mt8188-geralt-ciri-panel-boe.dtso         | 10 +++
 .../mt8188-geralt-ciri-panel-ivo.dtso         | 10 +++
 .../dts/mediatek/mt8188-geralt-ciri-sku0.dts  | 32 --------
 .../dts/mediatek/mt8188-geralt-ciri-sku2.dts  | 59 --------------
 .../dts/mediatek/mt8188-geralt-ciri-sku3.dts  | 32 --------
 .../dts/mediatek/mt8188-geralt-ciri-sku4.dts  | 48 -----------
 .../dts/mediatek/mt8188-geralt-ciri-sku7.dts  | 48 -----------
 ...eralt-ciri.dtsi => mt8188-geralt-ciri.dts} | 54 ++-----------
 arch/arm64/boot/dts/mediatek/mt8188.yaml      | 51 ++++++++++++
 15 files changed, 244 insertions(+), 315 deletions(-)
 rename arch/arm64/boot/dts/mediatek/{mt8188-geralt-ciri-sku1.dts => mt8188-geralt-ciri-audio-max98390-es8326.dtso} (59%)
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-audio-max98390-rt5682s.dtso
 rename arch/arm64/boot/dts/mediatek/{mt8188-geralt-ciri-sku5.dts => mt8188-geralt-ciri-audio-tas2563-es8326.dtso} (78%)
 rename arch/arm64/boot/dts/mediatek/{mt8188-geralt-ciri-sku6.dts => mt8188-geralt-ciri-audio-tas2563-rt5682s.dtso} (52%)
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-panel-boe.dtso
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-panel-ivo.dtso
 delete mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku0.dts
 delete mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku2.dts
 delete mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku3.dts
 delete mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku4.dts
 delete mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku7.dts
 rename arch/arm64/boot/dts/mediatek/{mt8188-geralt-ciri.dtsi => mt8188-geralt-ciri.dts} (81%)
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8188.yaml

-- 
2.52.0.223.gf5cc29aaa4-goog



From wenst at chromium.org  Sun Dec  7 23:33:02 2025
From: wenst at chromium.org (Chen-Yu Tsai)
Date: Mon,  8 Dec 2025 15:33:02 +0800
Subject: [RFC PATCH 1/3] dt-bindings: arm: mediatek: Add generic Ciri "base" board
In-Reply-To: <20251208073306.75279-1-wenst@chromium.org>
References: <20251208073306.75279-1-wenst@chromium.org>
Message-ID: <20251208073306.75279-2-wenst@chromium.org>

To reorganize all the Ciri SKUs into device tree overlays, there needs
to be a base device tree with its own compatible string.

Add a new entry for the generic Ciri "base" with just the fallback
generic "google,ciri" compatible string.

Signed-off-by: Chen-Yu Tsai <wenst at chromium.org>
---
 Documentation/devicetree/bindings/arm/mediatek.yaml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/mediatek.yaml b/Documentation/devicetree/bindings/arm/mediatek.yaml
index 718d732174b9..9cff861c6e38 100644
--- a/Documentation/devicetree/bindings/arm/mediatek.yaml
+++ b/Documentation/devicetree/bindings/arm/mediatek.yaml
@@ -372,6 +372,10 @@ properties:
           - enum:
               - mediatek,mt8186-evb
           - const: mediatek,mt8186
+      - description: Google Ciri (Lenovo Chromebook Duet (11", 9))
+        items:
+          - const: google,ciri
+          - const: mediatek,mt8188
       - description: Google Ciri (Lenovo Chromebook Duet (11", 9))
         items:
           - enum:
-- 
2.52.0.223.gf5cc29aaa4-goog



From wenst at chromium.org  Sun Dec  7 23:33:03 2025
From: wenst at chromium.org (Chen-Yu Tsai)
Date: Mon,  8 Dec 2025 15:33:03 +0800
Subject: [RFC PATCH 2/3] arm64: dts: mt8188-ciri: Split into base and overlays based on components
In-Reply-To: <20251208073306.75279-1-wenst@chromium.org>
References: <20251208073306.75279-1-wenst@chromium.org>
Message-ID: <20251208073306.75279-3-wenst@chromium.org>

The MT8188-based Ciri device has 8 SKUs. These are derived from the
combinations of 3 types of components (headphone codec, speaker codec,
and display panel), each having 2 options.

Decompose the existing dtsi / dts files into 6 overlays for each
component option. The audio codec have combined audio routing and graph
connections,  cannot be easily separated into separate bits without
adding even more glue overlays. The per-SKU dts files are also converted
to overlays, though now they only contain the final board compatible and
model name.

Signed-off-by: Chen-Yu Tsai <wenst at chromium.org>
---
 arch/arm64/boot/dts/mediatek/Makefile         | 34 ++++++++
 ...88-geralt-ciri-audio-max98390-es8326.dtso} | 40 ++++++---
 ...88-geralt-ciri-audio-max98390-rt5682s.dtso | 81 +++++++++++++++++++
 ...188-geralt-ciri-audio-tas2563-es8326.dtso} | 18 ++---
 ...88-geralt-ciri-audio-tas2563-rt5682s.dtso} | 46 +++++------
 .../mt8188-geralt-ciri-panel-boe.dtso         | 10 +++
 .../mt8188-geralt-ciri-panel-ivo.dtso         | 10 +++
 .../dts/mediatek/mt8188-geralt-ciri-sku0.dts  | 32 --------
 .../dts/mediatek/mt8188-geralt-ciri-sku0.dtso | 11 +++
 .../dts/mediatek/mt8188-geralt-ciri-sku1.dtso | 11 +++
 .../dts/mediatek/mt8188-geralt-ciri-sku2.dts  | 59 --------------
 .../dts/mediatek/mt8188-geralt-ciri-sku2.dtso | 11 +++
 .../dts/mediatek/mt8188-geralt-ciri-sku3.dts  | 32 --------
 .../dts/mediatek/mt8188-geralt-ciri-sku3.dtso | 11 +++
 .../dts/mediatek/mt8188-geralt-ciri-sku4.dts  | 48 -----------
 .../dts/mediatek/mt8188-geralt-ciri-sku4.dtso | 11 +++
 .../dts/mediatek/mt8188-geralt-ciri-sku5.dtso | 11 +++
 .../dts/mediatek/mt8188-geralt-ciri-sku6.dtso | 11 +++
 .../dts/mediatek/mt8188-geralt-ciri-sku7.dts  | 48 -----------
 .../dts/mediatek/mt8188-geralt-ciri-sku7.dtso | 11 +++
 ...eralt-ciri.dtsi => mt8188-geralt-ciri.dts} | 54 ++-----------
 21 files changed, 285 insertions(+), 315 deletions(-)
 rename arch/arm64/boot/dts/mediatek/{mt8188-geralt-ciri-sku1.dts => mt8188-geralt-ciri-audio-max98390-es8326.dtso} (59%)
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-audio-max98390-rt5682s.dtso
 rename arch/arm64/boot/dts/mediatek/{mt8188-geralt-ciri-sku5.dts => mt8188-geralt-ciri-audio-tas2563-es8326.dtso} (78%)
 rename arch/arm64/boot/dts/mediatek/{mt8188-geralt-ciri-sku6.dts => mt8188-geralt-ciri-audio-tas2563-rt5682s.dtso} (52%)
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-panel-boe.dtso
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-panel-ivo.dtso
 delete mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku0.dts
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku0.dtso
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku1.dtso
 delete mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku2.dts
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku2.dtso
 delete mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku3.dts
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku3.dtso
 delete mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku4.dts
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku4.dtso
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku5.dtso
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku6.dtso
 delete mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku7.dts
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku7.dtso
 rename arch/arm64/boot/dts/mediatek/{mt8188-geralt-ciri.dtsi => mt8188-geralt-ciri.dts} (81%)

diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile
index c5fd6191a925..39a844386366 100644
--- a/arch/arm64/boot/dts/mediatek/Makefile
+++ b/arch/arm64/boot/dts/mediatek/Makefile
@@ -86,6 +86,40 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8186-corsola-tentacruel-sku262148.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8186-corsola-voltorb.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8186-evb.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8188-evb.dtb
+
+mt8188-geralt-ciri-sku0-dtbs := mt8188-geralt-ciri.dtb \
+				mt8188-geralt-ciri-panel-boe.dtbo \
+				mt8188-geralt-ciri-audio-max98390-rt5682s.dtbo \
+				mt8188-geralt-ciri-sku0.dtbo
+mt8188-geralt-ciri-sku1-dtbs := mt8188-geralt-ciri.dtb \
+				mt8188-geralt-ciri-panel-ivo.dtbo \
+				mt8188-geralt-ciri-audio-max98390-es8326.dtbo \
+				mt8188-geralt-ciri-sku1.dtbo
+mt8188-geralt-ciri-sku2-dtbs := mt8188-geralt-ciri.dtb \
+				mt8188-geralt-ciri-panel-boe.dtbo \
+				mt8188-geralt-ciri-audio-max98390-es8326.dtbo \
+				mt8188-geralt-ciri-sku2.dtbo
+mt8188-geralt-ciri-sku3-dtbs := mt8188-geralt-ciri.dtb \
+				mt8188-geralt-ciri-panel-ivo.dtbo \
+				mt8188-geralt-ciri-audio-max98390-rt5682s.dtbo \
+				mt8188-geralt-ciri-sku3.dtbo
+mt8188-geralt-ciri-sku4-dtbs := mt8188-geralt-ciri.dtb \
+				mt8188-geralt-ciri-panel-boe.dtbo \
+				mt8188-geralt-ciri-audio-tas2563-rt5682s.dtbo \
+				mt8188-geralt-ciri-sku4.dtbo
+mt8188-geralt-ciri-sku5-dtbs := mt8188-geralt-ciri.dtb \
+				mt8188-geralt-ciri-panel-ivo.dtbo \
+				mt8188-geralt-ciri-audio-tas2563-es8326.dtbo \
+				mt8188-geralt-ciri-sku5.dtbo
+mt8188-geralt-ciri-sku6-dtbs := mt8188-geralt-ciri.dtb \
+				mt8188-geralt-ciri-panel-boe.dtbo \
+				mt8188-geralt-ciri-audio-tas2563-es8326.dtbo \
+				mt8188-geralt-ciri-sku6.dtbo
+mt8188-geralt-ciri-sku7-dtbs := mt8188-geralt-ciri.dtb \
+				mt8188-geralt-ciri-panel-ivo.dtbo \
+				mt8188-geralt-ciri-audio-tas2563-rt5682s.dtbo \
+				mt8188-geralt-ciri-sku7.dtbo
+
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8188-geralt-ciri-sku0.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8188-geralt-ciri-sku1.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8188-geralt-ciri-sku2.dtb
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku1.dts b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-audio-max98390-es8326.dtso
similarity index 59%
rename from arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku1.dts
rename to arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-audio-max98390-es8326.dtso
index ef5ea9d12b1d..b99bd4c78ec5 100644
--- a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku1.dts
+++ b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-audio-max98390-es8326.dtso
@@ -2,20 +2,14 @@
 /*
  * Copyright 2023 Google LLC
  */
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
 /dts-v1/;
-#include "mt8188-geralt-ciri.dtsi"
-
-/ {
-	model = "Google Ciri sku1 board";
-	compatible = "google,ciri-sku1", "google,ciri", "mediatek,mt8188";
-};
-
-&dsi_panel {
-	compatible = "ivo,t109nw41", "himax,hx83102";
-};
+/plugin/;
 
 &i2c0 {
-	/delete-node/ audio-codec at 1a;
+	#address-cells = <1>;
+	#size-cells = <0>;
 
 	es8326: audio-codec at 19 {
 		compatible = "everest,es8326";
@@ -27,6 +21,23 @@ es8326: audio-codec at 19 {
 		everest,jack-pol = [0e];
 		everest,interrupt-clk = [00];
 	};
+
+	max98390_38: amplifier at 38 {
+		compatible = "maxim,max98390";
+		reg = <0x38>;
+		sound-name-prefix = "Front Right";
+		reset-gpios = <&pio 118 GPIO_ACTIVE_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&speaker_en>;
+		#sound-dai-cells = <0>;
+	};
+
+	max98390_39: amplifier at 39 {
+		compatible = "maxim,max98390";
+		reg = <0x39>;
+		sound-name-prefix = "Front Left";
+		#sound-dai-cells = <0>;
+	};
 };
 
 &sound {
@@ -45,6 +56,13 @@ &sound {
 		"Left Spk", "Front Left BE_OUT",
 		"Right Spk", "Front Right BE_OUT";
 
+	dai-link-1 {
+		codec {
+			sound-dai = <&max98390_38>,
+				    <&max98390_39>;
+		};
+	};
+
 	dai-link-2 {
 		codec {
 			sound-dai = <&es8326>;
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-audio-max98390-rt5682s.dtso b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-audio-max98390-rt5682s.dtso
new file mode 100644
index 000000000000..44dd82926280
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-audio-max98390-rt5682s.dtso
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2023 Google LLC
+ */
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+/dts-v1/;
+/plugin/;
+
+&i2c0 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	rt5682s: audio-codec at 1a {
+		compatible = "realtek,rt5682s";
+		reg = <0x1a>;
+		interrupts-extended = <&pio 108 IRQ_TYPE_EDGE_BOTH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&audio_codec_pins>;
+		#sound-dai-cells = <1>;
+
+		AVDD-supply = <&mt6359_vio18_ldo_reg>;
+		DBVDD-supply = <&mt6359_vio18_ldo_reg>;
+		LDO1-IN-supply = <&mt6359_vio18_ldo_reg>;
+		MICVDD-supply = <&pp3300_s3>;
+		realtek,jd-src = <1>;
+	};
+
+	max98390_38: amplifier at 38 {
+		compatible = "maxim,max98390";
+		reg = <0x38>;
+		sound-name-prefix = "Front Right";
+		reset-gpios = <&pio 118 GPIO_ACTIVE_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&speaker_en>;
+		#sound-dai-cells = <0>;
+	};
+
+	max98390_39: amplifier at 39 {
+		compatible = "maxim,max98390";
+		reg = <0x39>;
+		sound-name-prefix = "Front Left";
+		#sound-dai-cells = <0>;
+	};
+};
+
+&sound {
+	compatible = "mediatek,mt8188-rt5682s";
+	model = "mt8188_m98390_5682";
+
+	audio-routing =
+		"ETDM1_OUT", "ETDM_SPK_PIN",
+		"ETDM2_OUT", "ETDM_HP_PIN",
+		"ETDM1_IN", "ETDM_SPK_PIN",
+		"ETDM2_IN", "ETDM_HP_PIN",
+		"ADDA Capture", "MTKAIF_PIN",
+		"Headphone Jack", "HPOL",
+		"Headphone Jack", "HPOR",
+		"IN1P", "Headset Mic",
+		"Left Spk", "Front Left BE_OUT",
+		"Right Spk", "Front Right BE_OUT";
+
+	dai-link-1 {
+		codec {
+			sound-dai = <&max98390_38>,
+				    <&max98390_39>;
+		};
+	};
+
+	dai-link-2 {
+		codec {
+			sound-dai = <&rt5682s 0>;
+		};
+	};
+
+	dai-link-3 {
+		codec {
+			sound-dai = <&rt5682s 0>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku5.dts b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-audio-tas2563-es8326.dtso
similarity index 78%
rename from arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku5.dts
rename to arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-audio-tas2563-es8326.dtso
index bf87201ccf27..c64094c6c249 100644
--- a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku5.dts
+++ b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-audio-tas2563-es8326.dtso
@@ -2,22 +2,14 @@
 /*
  * Copyright 2024 Google LLC
  */
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
 /dts-v1/;
-#include "mt8188-geralt-ciri.dtsi"
-
-/ {
-	model = "Google Ciri sku5 board (rev4)";
-	compatible = "google,ciri-sku5", "google,ciri", "mediatek,mt8188";
-};
-
-&dsi_panel {
-	compatible = "ivo,t109nw41", "himax,hx83102";
-};
+/plugin/;
 
 &i2c0 {
-	/delete-node/ audio-codec at 1a;
-	/delete-node/ amplifier at 38;
-	/delete-node/ amplifier at 39;
+	#address-cells = <1>;
+	#size-cells = <0>;
 
 	es8326: audio-codec at 19 {
 		compatible = "everest,es8326";
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku6.dts b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-audio-tas2563-rt5682s.dtso
similarity index 52%
rename from arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku6.dts
rename to arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-audio-tas2563-rt5682s.dtso
index 17d7359dfb6a..b8e6220a449e 100644
--- a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku6.dts
+++ b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-audio-tas2563-rt5682s.dtso
@@ -2,32 +2,28 @@
 /*
  * Copyright 2024 Google LLC
  */
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
 /dts-v1/;
-#include "mt8188-geralt-ciri.dtsi"
-
-/ {
-	model = "Google Ciri sku6 board (rev4)";
-	compatible = "google,ciri-sku6", "google,ciri", "mediatek,mt8188";
-};
-
-&dsi_panel {
-	compatible = "boe,nv110wum-l60", "himax,hx83102";
-};
+/plugin/;
 
 &i2c0 {
-	/delete-node/ audio-codec at 1a;
-	/delete-node/ amplifier at 38;
-	/delete-node/ amplifier at 39;
+	#address-cells = <1>;
+	#size-cells = <0>;
 
-	es8326: audio-codec at 19 {
-		compatible = "everest,es8326";
-		reg = <0x19>;
-		interrupts-extended = <&pio 108 IRQ_TYPE_LEVEL_LOW>;
+	rt5682s: audio-codec at 1a {
+		compatible = "realtek,rt5682s";
+		reg = <0x1a>;
+		interrupts-extended = <&pio 108 IRQ_TYPE_EDGE_BOTH>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&audio_codec_pins>;
-		#sound-dai-cells = <0>;
-		everest,jack-pol = [0e];
-		everest,interrupt-clk = [00];
+		#sound-dai-cells = <1>;
+
+		AVDD-supply = <&mt6359_vio18_ldo_reg>;
+		DBVDD-supply = <&mt6359_vio18_ldo_reg>;
+		LDO1-IN-supply = <&mt6359_vio18_ldo_reg>;
+		MICVDD-supply = <&pp3300_s3>;
+		realtek,jd-src = <1>;
 	};
 
 	tas2563: amplifier at 4f {
@@ -39,8 +35,8 @@ tas2563: amplifier at 4f {
 };
 
 &sound {
-	compatible = "mediatek,mt8188-es8326";
-	model = "mt8188_tas2563_8326";
+	compatible = "mediatek,mt8188-rt5682s";
+	model = "mt8188_tas2563_5682";
 
 	audio-routing =
 		"ETDM1_OUT", "ETDM_SPK_PIN",
@@ -50,7 +46,7 @@ &sound {
 		"ADDA Capture", "MTKAIF_PIN",
 		"Headphone Jack", "HPOL",
 		"Headphone Jack", "HPOR",
-		"MIC1", "Headset Mic";
+		"IN1P", "Headset Mic";
 
 	dai-link-1 {
 		codec {
@@ -60,13 +56,13 @@ codec {
 
 	dai-link-2 {
 		codec {
-			sound-dai = <&es8326>;
+			sound-dai = <&rt5682s 0>;
 		};
 	};
 
 	dai-link-3 {
 		codec {
-			sound-dai = <&es8326>;
+			sound-dai = <&rt5682s 0>;
 		};
 	};
 };
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-panel-boe.dtso b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-panel-boe.dtso
new file mode 100644
index 000000000000..4d61226713bc
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-panel-boe.dtso
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2023 Google LLC
+ */
+/dts-v1/;
+/plugin/;
+
+&dsi_panel {
+	compatible = "boe,nv110wum-l60", "himax,hx83102";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-panel-ivo.dtso b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-panel-ivo.dtso
new file mode 100644
index 000000000000..8cdacf64c100
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-panel-ivo.dtso
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2023 Google LLC
+ */
+/dts-v1/;
+/plugin/;
+
+&dsi_panel {
+	compatible = "ivo,t109nw41", "himax,hx83102";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku0.dts b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku0.dts
deleted file mode 100644
index 79d6d12394b9..000000000000
--- a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku0.dts
+++ /dev/null
@@ -1,32 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
-/*
- * Copyright 2023 Google LLC
- */
-/dts-v1/;
-#include "mt8188-geralt-ciri.dtsi"
-
-/ {
-	model = "Google Ciri sku0 board";
-	compatible = "google,ciri-sku0", "google,ciri", "mediatek,mt8188";
-};
-
-&dsi_panel {
-	compatible = "boe,nv110wum-l60", "himax,hx83102";
-};
-
-&sound {
-	compatible = "mediatek,mt8188-rt5682s";
-	model = "mt8188_m98390_5682";
-
-	audio-routing =
-		"ETDM1_OUT", "ETDM_SPK_PIN",
-		"ETDM2_OUT", "ETDM_HP_PIN",
-		"ETDM1_IN", "ETDM_SPK_PIN",
-		"ETDM2_IN", "ETDM_HP_PIN",
-		"ADDA Capture", "MTKAIF_PIN",
-		"Headphone Jack", "HPOL",
-		"Headphone Jack", "HPOR",
-		"IN1P", "Headset Mic",
-		"Left Spk", "Front Left BE_OUT",
-		"Right Spk", "Front Right BE_OUT";
-};
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku0.dtso b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku0.dtso
new file mode 100644
index 000000000000..884a7b2d943c
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku0.dtso
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2023 Google LLC
+ */
+/dts-v1/;
+/plugin/;
+
+&{/} {
+	model = "Google Ciri sku0 board";
+	compatible = "google,ciri-sku0", "google,ciri", "mediatek,mt8188";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku1.dtso b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku1.dtso
new file mode 100644
index 000000000000..d3ed6ea535d7
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku1.dtso
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2023 Google LLC
+ */
+/dts-v1/;
+/plugin/;
+
+&{/} {
+	model = "Google Ciri sku1 board";
+	compatible = "google,ciri-sku1", "google,ciri", "mediatek,mt8188";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku2.dts b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku2.dts
deleted file mode 100644
index ef56786fc2be..000000000000
--- a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku2.dts
+++ /dev/null
@@ -1,59 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
-/*
- * Copyright 2024 Google LLC
- */
-/dts-v1/;
-#include "mt8188-geralt-ciri.dtsi"
-
-/ {
-	model = "Google Ciri sku2 board";
-	compatible = "google,ciri-sku2", "google,ciri", "mediatek,mt8188";
-};
-
-&dsi_panel {
-	compatible = "boe,nv110wum-l60", "himax,hx83102";
-};
-
-&i2c0 {
-	/delete-node/ audio-codec at 1a;
-
-	es8326: audio-codec at 19 {
-		compatible = "everest,es8326";
-		reg = <0x19>;
-		interrupts-extended = <&pio 108 IRQ_TYPE_LEVEL_LOW>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&audio_codec_pins>;
-		#sound-dai-cells = <0>;
-		everest,jack-pol = [0e];
-		everest,interrupt-clk = [00];
-	};
-};
-
-&sound {
-	compatible = "mediatek,mt8188-es8326";
-	model = "mt8188_m98390_8326";
-
-	audio-routing =
-		"ETDM1_OUT", "ETDM_SPK_PIN",
-		"ETDM2_OUT", "ETDM_HP_PIN",
-		"ETDM1_IN", "ETDM_SPK_PIN",
-		"ETDM2_IN", "ETDM_HP_PIN",
-		"ADDA Capture", "MTKAIF_PIN",
-		"Headphone Jack", "HPOL",
-		"Headphone Jack", "HPOR",
-		"MIC1", "Headset Mic",
-		"Left Spk", "Front Left BE_OUT",
-		"Right Spk", "Front Right BE_OUT";
-
-	dai-link-2 {
-		codec {
-			sound-dai = <&es8326>;
-		};
-	};
-
-	dai-link-3 {
-		codec {
-			sound-dai = <&es8326>;
-		};
-	};
-};
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku2.dtso b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku2.dtso
new file mode 100644
index 000000000000..3f9d38bc2ad2
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku2.dtso
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2024 Google LLC
+ */
+/dts-v1/;
+/plugin/;
+
+&{/} {
+	model = "Google Ciri sku2 board";
+	compatible = "google,ciri-sku2", "google,ciri", "mediatek,mt8188";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku3.dts b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku3.dts
deleted file mode 100644
index 524f7f0064c1..000000000000
--- a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku3.dts
+++ /dev/null
@@ -1,32 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
-/*
- * Copyright 2024 Google LLC
- */
-/dts-v1/;
-#include "mt8188-geralt-ciri.dtsi"
-
-/ {
-	model = "Google Ciri sku3 board";
-	compatible = "google,ciri-sku3", "google,ciri", "mediatek,mt8188";
-};
-
-&dsi_panel {
-	compatible = "ivo,t109nw41", "himax,hx83102";
-};
-
-&sound {
-	compatible = "mediatek,mt8188-rt5682s";
-	model = "mt8188_m98390_5682";
-
-	audio-routing =
-		"ETDM1_OUT", "ETDM_SPK_PIN",
-		"ETDM2_OUT", "ETDM_HP_PIN",
-		"ETDM1_IN", "ETDM_SPK_PIN",
-		"ETDM2_IN", "ETDM_HP_PIN",
-		"ADDA Capture", "MTKAIF_PIN",
-		"Headphone Jack", "HPOL",
-		"Headphone Jack", "HPOR",
-		"IN1P", "Headset Mic",
-		"Left Spk", "Front Left BE_OUT",
-		"Right Spk", "Front Right BE_OUT";
-};
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku3.dtso b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku3.dtso
new file mode 100644
index 000000000000..e6a6f8f06141
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku3.dtso
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2024 Google LLC
+ */
+/dts-v1/;
+/plugin/;
+
+&{/} {
+	model = "Google Ciri sku3 board";
+	compatible = "google,ciri-sku3", "google,ciri", "mediatek,mt8188";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku4.dts b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku4.dts
deleted file mode 100644
index ea953d7e1543..000000000000
--- a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku4.dts
+++ /dev/null
@@ -1,48 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
-/*
- * Copyright 2024 Google LLC
- */
-/dts-v1/;
-#include "mt8188-geralt-ciri.dtsi"
-
-/ {
-	model = "Google Ciri sku4 board (rev4)";
-	compatible = "google,ciri-sku4", "google,ciri", "mediatek,mt8188";
-};
-
-&dsi_panel {
-	compatible = "boe,nv110wum-l60", "himax,hx83102";
-};
-
-&i2c0 {
-	/delete-node/ amplifier at 38;
-	/delete-node/ amplifier at 39;
-
-	tas2563: amplifier at 4f {
-		compatible = "ti,tas2563", "ti,tas2781";
-		reg = <0x4f>, <0x4c>; /* left / right channel */
-		reset-gpios = <&pio 118 GPIO_ACTIVE_HIGH>;
-		#sound-dai-cells = <0>;
-	};
-};
-
-&sound {
-	compatible = "mediatek,mt8188-rt5682s";
-	model = "mt8188_tas2563_5682";
-
-	audio-routing =
-		"ETDM1_OUT", "ETDM_SPK_PIN",
-		"ETDM2_OUT", "ETDM_HP_PIN",
-		"ETDM1_IN", "ETDM_SPK_PIN",
-		"ETDM2_IN", "ETDM_HP_PIN",
-		"ADDA Capture", "MTKAIF_PIN",
-		"Headphone Jack", "HPOL",
-		"Headphone Jack", "HPOR",
-		"IN1P", "Headset Mic";
-
-	dai-link-1 {
-		codec {
-			sound-dai = <&tas2563>;
-		};
-	};
-};
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku4.dtso b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku4.dtso
new file mode 100644
index 000000000000..ee5b28c4ef00
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku4.dtso
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2024 Google LLC
+ */
+/dts-v1/;
+/plugin/;
+
+&{/} {
+	model = "Google Ciri sku4 board (rev4)";
+	compatible = "google,ciri-sku4", "google,ciri", "mediatek,mt8188";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku5.dtso b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku5.dtso
new file mode 100644
index 000000000000..ccf8d2f0eb70
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku5.dtso
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2024 Google LLC
+ */
+/dts-v1/;
+/plugin/;
+
+&{/} {
+	model = "Google Ciri sku5 board (rev4)";
+	compatible = "google,ciri-sku5", "google,ciri", "mediatek,mt8188";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku6.dtso b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku6.dtso
new file mode 100644
index 000000000000..773c702b59d8
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku6.dtso
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2024 Google LLC
+ */
+/dts-v1/;
+/plugin/;
+
+&{/} {
+	model = "Google Ciri sku6 board (rev4)";
+	compatible = "google,ciri-sku6", "google,ciri", "mediatek,mt8188";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku7.dts b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku7.dts
deleted file mode 100644
index 825015b452d5..000000000000
--- a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku7.dts
+++ /dev/null
@@ -1,48 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
-/*
- * Copyright 2024 Google LLC
- */
-/dts-v1/;
-#include "mt8188-geralt-ciri.dtsi"
-
-/ {
-	model = "Google Ciri sku7 board (rev4)";
-	compatible = "google,ciri-sku7", "google,ciri", "mediatek,mt8188";
-};
-
-&dsi_panel {
-	compatible = "ivo,t109nw41", "himax,hx83102";
-};
-
-&i2c0 {
-	/delete-node/ amplifier at 38;
-	/delete-node/ amplifier at 39;
-
-	tas2563: amplifier at 4f {
-		compatible = "ti,tas2563", "ti,tas2781";
-		reg = <0x4f>, <0x4c>; /* left / right channel */
-		reset-gpios = <&pio 118 GPIO_ACTIVE_HIGH>;
-		#sound-dai-cells = <0>;
-	};
-};
-
-&sound {
-	compatible = "mediatek,mt8188-rt5682s";
-	model = "mt8188_tas2563_5682";
-
-	audio-routing =
-		"ETDM1_OUT", "ETDM_SPK_PIN",
-		"ETDM2_OUT", "ETDM_HP_PIN",
-		"ETDM1_IN", "ETDM_SPK_PIN",
-		"ETDM2_IN", "ETDM_HP_PIN",
-		"ADDA Capture", "MTKAIF_PIN",
-		"Headphone Jack", "HPOL",
-		"Headphone Jack", "HPOR",
-		"IN1P", "Headset Mic";
-
-	dai-link-1 {
-		codec {
-			sound-dai = <&tas2563>;
-		};
-	};
-};
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku7.dtso b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku7.dtso
new file mode 100644
index 000000000000..c22860eab9f8
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku7.dtso
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2024 Google LLC
+ */
+/dts-v1/;
+/plugin/;
+
+&{/} {
+	model = "Google Ciri sku7 board (rev4)";
+	compatible = "google,ciri-sku7", "google,ciri", "mediatek,mt8188";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri.dtsi b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri.dts
similarity index 81%
rename from arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri.dtsi
rename to arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri.dts
index 6815c435a57e..2c9e9e67c8e2 100644
--- a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri.dts
@@ -5,6 +5,11 @@
 /dts-v1/;
 #include "mt8188-geralt.dtsi"
 
+/ {
+	model = "Google Ciri board";
+	compatible = "google,ciri", "mediatek,mt8188";
+};
+
 &aud_etdm_hp_on {
 	pins-mclk {
 		pinmux = <PINMUX_GPIO114__FUNC_O_I2SO2_MCK>;
@@ -19,40 +24,6 @@ pins-mclk {
 	};
 };
 
-&i2c0 {
-	rt5682s: audio-codec at 1a {
-		compatible = "realtek,rt5682s";
-		reg = <0x1a>;
-		interrupts-extended = <&pio 108 IRQ_TYPE_EDGE_BOTH>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&audio_codec_pins>;
-		#sound-dai-cells = <1>;
-
-		AVDD-supply = <&mt6359_vio18_ldo_reg>;
-		DBVDD-supply = <&mt6359_vio18_ldo_reg>;
-		LDO1-IN-supply = <&mt6359_vio18_ldo_reg>;
-		MICVDD-supply = <&pp3300_s3>;
-		realtek,jd-src = <1>;
-	};
-
-	max98390_38: amplifier at 38 {
-		compatible = "maxim,max98390";
-		reg = <0x38>;
-		sound-name-prefix = "Front Right";
-		reset-gpios = <&pio 118 GPIO_ACTIVE_LOW>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&speaker_en>;
-		#sound-dai-cells = <0>;
-	};
-
-	max98390_39: amplifier at 39 {
-		compatible = "maxim,max98390";
-		reg = <0x39>;
-		sound-name-prefix = "Front Left";
-		#sound-dai-cells = <0>;
-	};
-};
-
 &i2c_tunnel {
 	/*
 	 * The virtual battery I2C addr is 0xf on Ciri, so we describe it
@@ -77,6 +48,8 @@ &mt6359_vm18_ldo_reg {
 };
 
 &sound {
+	/* compatible, model, routing, and dai-link codecs added by overlays */
+
 	dai-link-0 {
 		link-name = "ETDM1_IN_BE";
 		dai-format = "i2s";
@@ -87,29 +60,16 @@ dai-link-1 {
 		link-name = "ETDM1_OUT_BE";
 		dai-format = "i2s";
 		mediatek,clk-provider = "cpu";
-
-		codec {
-			sound-dai = <&max98390_38>,
-				    <&max98390_39>;
-		};
 	};
 
 	dai-link-2 {
 		link-name = "ETDM2_IN_BE";
 		mediatek,clk-provider = "cpu";
-
-		codec {
-			sound-dai = <&rt5682s 0>;
-		};
 	};
 
 	dai-link-3 {
 		link-name = "ETDM2_OUT_BE";
 		mediatek,clk-provider = "cpu";
-
-		codec {
-			sound-dai = <&rt5682s 0>;
-		};
 	};
 
 	dai-link-4 {
-- 
2.52.0.223.gf5cc29aaa4-goog



From wenst at chromium.org  Sun Dec  7 23:33:04 2025
From: wenst at chromium.org (Chen-Yu Tsai)
Date: Mon,  8 Dec 2025 15:33:04 +0800
Subject: [RFC PATCH 3/3] [EXAMPLE] arm64: dts: mediatek: ciri: Drop SKU-specific overlays
In-Reply-To: <20251208073306.75279-1-wenst@chromium.org>
References: <20251208073306.75279-1-wenst@chromium.org>
Message-ID: <20251208073306.75279-4-wenst@chromium.org>

The final SKU-specific overlays only set the top level board compatible
and model, but add nothing else. The specifics are not super important
to the kernel, and could be removed so we don't have to have so many
source files.

However, the ChromeOS bootloader (coreboot / depthcharge) selects the
device tree blob to load basd on the compatible string, so the mapping
from a SKU-specific compatible to a DTB (or a series of DTB/DTBOs) needs
to be maintained somewhere to build the FIT image.

Move the SKU-specific top level compatible strings to a separate file
stored with the device tree sources, and drop the SKU specific files.

Signed-off-by: Chen-Yu Tsai <wenst at chromium.org>

---
This is meant to serve as an example for dropping SKU-specific files
that just have specific identifiers that the kernel doesn't care about,
i.e. doesn't need to be present in the DTB itself, but need to be
preserved for other purposes.
---
 arch/arm64/boot/dts/mediatek/Makefile         | 24 +++------
 .../dts/mediatek/mt8188-geralt-ciri-sku0.dtso | 11 ----
 .../dts/mediatek/mt8188-geralt-ciri-sku1.dtso | 11 ----
 .../dts/mediatek/mt8188-geralt-ciri-sku2.dtso | 11 ----
 .../dts/mediatek/mt8188-geralt-ciri-sku3.dtso | 11 ----
 .../dts/mediatek/mt8188-geralt-ciri-sku4.dtso | 11 ----
 .../dts/mediatek/mt8188-geralt-ciri-sku5.dtso | 11 ----
 .../dts/mediatek/mt8188-geralt-ciri-sku6.dtso | 11 ----
 .../dts/mediatek/mt8188-geralt-ciri-sku7.dtso | 11 ----
 arch/arm64/boot/dts/mediatek/mt8188.yaml      | 51 +++++++++++++++++++
 10 files changed, 59 insertions(+), 104 deletions(-)
 delete mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku0.dtso
 delete mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku1.dtso
 delete mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku2.dtso
 delete mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku3.dtso
 delete mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku4.dtso
 delete mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku5.dtso
 delete mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku6.dtso
 delete mode 100644 arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku7.dtso
 create mode 100644 arch/arm64/boot/dts/mediatek/mt8188.yaml

diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile
index 39a844386366..5123d15c62c1 100644
--- a/arch/arm64/boot/dts/mediatek/Makefile
+++ b/arch/arm64/boot/dts/mediatek/Makefile
@@ -89,36 +89,28 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8188-evb.dtb
 
 mt8188-geralt-ciri-sku0-dtbs := mt8188-geralt-ciri.dtb \
 				mt8188-geralt-ciri-panel-boe.dtbo \
-				mt8188-geralt-ciri-audio-max98390-rt5682s.dtbo \
-				mt8188-geralt-ciri-sku0.dtbo
+				mt8188-geralt-ciri-audio-max98390-rt5682s.dtbo
 mt8188-geralt-ciri-sku1-dtbs := mt8188-geralt-ciri.dtb \
 				mt8188-geralt-ciri-panel-ivo.dtbo \
-				mt8188-geralt-ciri-audio-max98390-es8326.dtbo \
-				mt8188-geralt-ciri-sku1.dtbo
+				mt8188-geralt-ciri-audio-max98390-es8326.dtbo
 mt8188-geralt-ciri-sku2-dtbs := mt8188-geralt-ciri.dtb \
 				mt8188-geralt-ciri-panel-boe.dtbo \
-				mt8188-geralt-ciri-audio-max98390-es8326.dtbo \
-				mt8188-geralt-ciri-sku2.dtbo
+				mt8188-geralt-ciri-audio-max98390-es8326.dtbo
 mt8188-geralt-ciri-sku3-dtbs := mt8188-geralt-ciri.dtb \
 				mt8188-geralt-ciri-panel-ivo.dtbo \
-				mt8188-geralt-ciri-audio-max98390-rt5682s.dtbo \
-				mt8188-geralt-ciri-sku3.dtbo
+				mt8188-geralt-ciri-audio-max98390-rt5682s.dtbo
 mt8188-geralt-ciri-sku4-dtbs := mt8188-geralt-ciri.dtb \
 				mt8188-geralt-ciri-panel-boe.dtbo \
-				mt8188-geralt-ciri-audio-tas2563-rt5682s.dtbo \
-				mt8188-geralt-ciri-sku4.dtbo
+				mt8188-geralt-ciri-audio-tas2563-rt5682s.dtbo
 mt8188-geralt-ciri-sku5-dtbs := mt8188-geralt-ciri.dtb \
 				mt8188-geralt-ciri-panel-ivo.dtbo \
-				mt8188-geralt-ciri-audio-tas2563-es8326.dtbo \
-				mt8188-geralt-ciri-sku5.dtbo
+				mt8188-geralt-ciri-audio-tas2563-es8326.dtbo
 mt8188-geralt-ciri-sku6-dtbs := mt8188-geralt-ciri.dtb \
 				mt8188-geralt-ciri-panel-boe.dtbo \
-				mt8188-geralt-ciri-audio-tas2563-es8326.dtbo \
-				mt8188-geralt-ciri-sku6.dtbo
+				mt8188-geralt-ciri-audio-tas2563-es8326.dtbo
 mt8188-geralt-ciri-sku7-dtbs := mt8188-geralt-ciri.dtb \
 				mt8188-geralt-ciri-panel-ivo.dtbo \
-				mt8188-geralt-ciri-audio-tas2563-rt5682s.dtbo \
-				mt8188-geralt-ciri-sku7.dtbo
+				mt8188-geralt-ciri-audio-tas2563-rt5682s.dtbo
 
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8188-geralt-ciri-sku0.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8188-geralt-ciri-sku1.dtb
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku0.dtso b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku0.dtso
deleted file mode 100644
index 884a7b2d943c..000000000000
--- a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku0.dtso
+++ /dev/null
@@ -1,11 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
-/*
- * Copyright 2023 Google LLC
- */
-/dts-v1/;
-/plugin/;
-
-&{/} {
-	model = "Google Ciri sku0 board";
-	compatible = "google,ciri-sku0", "google,ciri", "mediatek,mt8188";
-};
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku1.dtso b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku1.dtso
deleted file mode 100644
index d3ed6ea535d7..000000000000
--- a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku1.dtso
+++ /dev/null
@@ -1,11 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
-/*
- * Copyright 2023 Google LLC
- */
-/dts-v1/;
-/plugin/;
-
-&{/} {
-	model = "Google Ciri sku1 board";
-	compatible = "google,ciri-sku1", "google,ciri", "mediatek,mt8188";
-};
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku2.dtso b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku2.dtso
deleted file mode 100644
index 3f9d38bc2ad2..000000000000
--- a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku2.dtso
+++ /dev/null
@@ -1,11 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
-/*
- * Copyright 2024 Google LLC
- */
-/dts-v1/;
-/plugin/;
-
-&{/} {
-	model = "Google Ciri sku2 board";
-	compatible = "google,ciri-sku2", "google,ciri", "mediatek,mt8188";
-};
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku3.dtso b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku3.dtso
deleted file mode 100644
index e6a6f8f06141..000000000000
--- a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku3.dtso
+++ /dev/null
@@ -1,11 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
-/*
- * Copyright 2024 Google LLC
- */
-/dts-v1/;
-/plugin/;
-
-&{/} {
-	model = "Google Ciri sku3 board";
-	compatible = "google,ciri-sku3", "google,ciri", "mediatek,mt8188";
-};
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku4.dtso b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku4.dtso
deleted file mode 100644
index ee5b28c4ef00..000000000000
--- a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku4.dtso
+++ /dev/null
@@ -1,11 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
-/*
- * Copyright 2024 Google LLC
- */
-/dts-v1/;
-/plugin/;
-
-&{/} {
-	model = "Google Ciri sku4 board (rev4)";
-	compatible = "google,ciri-sku4", "google,ciri", "mediatek,mt8188";
-};
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku5.dtso b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku5.dtso
deleted file mode 100644
index ccf8d2f0eb70..000000000000
--- a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku5.dtso
+++ /dev/null
@@ -1,11 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
-/*
- * Copyright 2024 Google LLC
- */
-/dts-v1/;
-/plugin/;
-
-&{/} {
-	model = "Google Ciri sku5 board (rev4)";
-	compatible = "google,ciri-sku5", "google,ciri", "mediatek,mt8188";
-};
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku6.dtso b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku6.dtso
deleted file mode 100644
index 773c702b59d8..000000000000
--- a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku6.dtso
+++ /dev/null
@@ -1,11 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
-/*
- * Copyright 2024 Google LLC
- */
-/dts-v1/;
-/plugin/;
-
-&{/} {
-	model = "Google Ciri sku6 board (rev4)";
-	compatible = "google,ciri-sku6", "google,ciri", "mediatek,mt8188";
-};
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku7.dtso b/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku7.dtso
deleted file mode 100644
index c22860eab9f8..000000000000
--- a/arch/arm64/boot/dts/mediatek/mt8188-geralt-ciri-sku7.dtso
+++ /dev/null
@@ -1,11 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
-/*
- * Copyright 2024 Google LLC
- */
-/dts-v1/;
-/plugin/;
-
-&{/} {
-	model = "Google Ciri sku7 board (rev4)";
-	compatible = "google,ciri-sku7", "google,ciri", "mediatek,mt8188";
-};
diff --git a/arch/arm64/boot/dts/mediatek/mt8188.yaml b/arch/arm64/boot/dts/mediatek/mt8188.yaml
new file mode 100644
index 000000000000..7808ae20060f
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8188.yaml
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: (GPL-2.0 OR MIT)
+%YAML 1.2
+---
+- dtb: mt8188-geralt-ciri-sku0.dtb
+  description: Google Ciri board SKU0
+  compatibles:
+    - google,ciri-sku0
+    - google,ciri
+    - mediatek,mt8188
+- dtb: mt8188-geralt-ciri-sku1.dtb
+  description: Google Ciri board SKU1
+  compatibles:
+    - google,ciri-sku1
+    - google,ciri
+    - mediatek,mt8188
+- dtb: mt8188-geralt-ciri-sku2.dtb
+  description: Google Ciri board SKU2
+  compatibles:
+    - google,ciri-sku2
+    - google,ciri
+    - mediatek,mt8188
+- dtb: mt8188-geralt-ciri-sku3.dtb
+  description: Google Ciri board SKU3
+  compatibles:
+    - google,ciri-sku3
+    - google,ciri
+    - mediatek,mt8188
+- dtb: mt8188-geralt-ciri-sku4.dtb
+  description: Google Ciri board SKU4
+  compatibles:
+    - google,ciri-sku4
+    - google,ciri
+    - mediatek,mt8188
+- dtb: mt8188-geralt-ciri-sku5.dtb
+  description: Google Ciri board SKU5
+  compatibles:
+    - google,ciri-sku5
+    - google,ciri
+    - mediatek,mt8188
+- dtb: mt8188-geralt-ciri-sku6.dtb
+  description: Google Ciri board SKU6
+  compatibles:
+    - google,ciri-sku6
+    - google,ciri
+    - mediatek,mt8188
+- dtb: mt8188-geralt-ciri-sku7.dtb
+  description: Google Ciri board SKU7
+  compatibles:
+    - google,ciri-sku7
+    - google,ciri
+    - mediatek,mt8188
-- 
2.52.0.223.gf5cc29aaa4-goog



From victor.liu at nxp.com  Sun Dec  7 23:38:15 2025
From: victor.liu at nxp.com (Liu Ying)
Date: Mon, 8 Dec 2025 15:38:15 +0800
Subject: [PATCH 0/2] drm/atomic-helper: Support atomic flush with an
 optional kthread worker
In-Reply-To: <20251031-drm-crtc-flush-worker-v1-0-9edc94da0fb7@nxp.com>
References: <20251031-drm-crtc-flush-worker-v1-0-9edc94da0fb7@nxp.com>
Message-ID: <e4704da5-2532-4559-b0a5-58ebf087681e@nxp.com>

On 10/31/2025, Liu Ying wrote:
> Hi,
> 
> As drm_atomic_helper_commit_planes() calls atomic_flush for CRTCs
> sequentially and a driver's atomic_flush callback could be blocking,
> the performance for flushing multiple CRTCs in a single atomic commit
> could be low, like page flip for multiple CRTCs.  A real case is imx8-dc,
> which supports two CRTCs and does atomic_flush in a blocking way, i.e.,
> waits for a done event for loading shadow registers.
> 
> To resolve that, introduce an optional kthread worker to conduct
> flush in drm_atomic_helper_commit_planes(), so that flush can run in
> parallel for multiple CRTCs.
> 
> Drivers should call drmm_crtc_flush_worker_init() to initialize the
> kthread worker if they want to use it.
> 
> Patch 1 adds the optional kthread worker support.
> Patch 2 makes imx8-dc use the kthread worker.
> 
> Let me know your thoughts.  Thanks.

Gentle ping for review.

> 
> Signed-off-by: Liu Ying <victor.liu at nxp.com>
> ---
> Liu Ying (2):
>       drm/atomic-helper: Support atomic flush with an optional kthread worker
>       drm/imx: dc-crtc: Use flush worker
> 
>  drivers/gpu/drm/drm_atomic_helper.c | 27 ++++++++++++++++-
>  drivers/gpu/drm/drm_crtc.c          | 59 +++++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/imx/dc/dc-crtc.c    |  9 +++++-
>  include/drm/drm_crtc.h              | 45 ++++++++++++++++++++++++++++
>  4 files changed, 138 insertions(+), 2 deletions(-)
> ---
> base-commit: dcb6fa37fd7bc9c3d2b066329b0d27dedf8becaa
> change-id: 20251031-drm-crtc-flush-worker-0aac27acf40f
> 
> Best regards,

-- 
Regards,
Liu Ying


From mazziesaccount at gmail.com  Mon Dec  8 00:04:03 2025
From: mazziesaccount at gmail.com (Matti Vaittinen)
Date: Mon, 8 Dec 2025 10:04:03 +0200
Subject: Kconfig dangling references (BZ 216748)
In-Reply-To: <22b92ddf-6321-41b5-8073-f9c7064d3432@infradead.org>
References: <22b92ddf-6321-41b5-8073-f9c7064d3432@infradead.org>
Message-ID: <bcbe66b0-23bc-4ba1-93ab-f2c09262e07b@gmail.com>

On 08/12/2025 04:04, Randy Dunlap wrote:
> from  https://bugzilla.kernel.org/show_bug.cgi?id=216748
> 
> The bugzilla entry includes a Perl script and a shell script.
> This is the edited result of running them (I removed some entries that were noise).
> 
> I'll try to Cc: all of the relevant mailing lists or individuals.
> 

Thanks Randy! This is good.

> TEST_KUNIT_DEVICE_HELPERS ---
> drivers/iio/test/Kconfig:11:	select TEST_KUNIT_DEVICE_HELPERS
This is a config for stuff that never went upstream. It was replaced by 
more sophisticated kunit_device, which I believe is behind the 
'CONFIG_KUNIT'. So, this should be dropped, thanks!

Yours,
	-- Matti

---
Matti Vaittinen
Linux kernel developer at ROHM Semiconductors
Oulu Finland

~~ When things go utterly wrong vim users can always type :help! ~~


From krzk at kernel.org  Mon Dec  8 00:06:28 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 8 Dec 2025 09:06:28 +0100
Subject: [PATCH v4] dt-bindings: arm: keystone: add boot_* mboxes to
 ti,sci
In-Reply-To: <DESMHL7FCYXE.3TE3SG6TDVJ39@ti.com>
References: <20251205-k3_syscon_add_boot_mailboxes-v4-1-8e216fb88941@ti.com>
 <20251208-abiding-hedgehog-of-lightning-2fe7a2@quoll>
 <DESMHL7FCYXE.3TE3SG6TDVJ39@ti.com>
Message-ID: <96f61d12-2472-4179-a9ec-0dd7b1fdca8a@kernel.org>

On 08/12/2025 07:31, Anshul Dalal wrote:
>>>  
>>>    mboxes:
>>>      minItems: 2
>>> +    maxItems: 6
>>>  
>>>    ti,host-id:
>>>      $ref: /schemas/types.yaml#/definitions/uint32
>>> @@ -79,6 +79,42 @@ properties:
>>>      type: object
>>>      $ref: /schemas/reset/ti,sci-reset.yaml#
>>>  
>>> +if:
>>> +  properties:
>>> +    compatible:
>>> +      contains:
>>> +        const: ti,am654-sci
>>> +then:
>>> +  properties:
>>> +    mbox-names:
>>> +      minItems: 2
>>
>> Why is this list flexible?
>>
> 
> The idea is to make the boot_* mboxes optional so the existing DTs that

Then explain it in the commit msg.

> only have rx and tx remain complaint. Also, the boot_notify mbox is not
> supported by every SoC.

Not really relevant. This is one specific SoC. Not "every"...



Best regards,
Krzysztof


From songwei.chai at oss.qualcomm.com  Mon Dec  8 00:07:42 2025
From: songwei.chai at oss.qualcomm.com (Songwei Chai)
Date: Mon, 8 Dec 2025 16:07:42 +0800
Subject: [PATCH v8 0/7] Provides support for Trigger Generation Unit
In-Reply-To: <a3d2f8a8-900d-4cf7-bd12-2d2ec85c4da2@arm.com>
References: <20251203090055.2432719-1-songwei.chai@oss.qualcomm.com>
 <4f53766f-6338-4d94-a947-19b95952e08a@arm.com>
 <b2f3c31a-76fa-4f59-9ba4-0f93f861ffb2@oss.qualcomm.com>
 <a3d2f8a8-900d-4cf7-bd12-2d2ec85c4da2@arm.com>
Message-ID: <a99ccd44-1650-484e-a302-aee467461bfb@oss.qualcomm.com>



On 12/5/2025 9:51 PM, Suzuki K Poulose wrote:
> On 05/12/2025 01:13, Songwei Chai wrote:
>>
>>
>> On 12/3/2025 11:48 PM, Suzuki K Poulose wrote:
>>> Cc: Greg
>>>
>>> On 03/12/2025 09:00, Songwei Chai wrote:
>>>> We propose creating a new qcom directory under drivers/hwtracing
>>>> to host this TGU driver, as well as additional Qualcomm-specific
>>>> hwtracing drivers that we plan to submit in the coming months.
>>>> This structure will help organize vendor-specific implementations
>>>> and facilitate future development and maintenance.
>>>>
>>>> Feedback from the community on this proposal is highly appreciated.
>>>>
>>>> - Why we are proposing this:
>>>>
>>>> TGU has the ability to monitor signal conditions and trigger debug- 
>>>> related
>>>> actions, serving as a programmable hardware component that enhances 
>>>> system
>>>> trace and debug capabilities. Placing it under drivers/hwtracing 
>>>> aligns with
>>>> its function as a trace generation utility.
>>>>
>>>> We previously attempted to push this driver to drivers/hwtracing/ 
>>>> coresight,
>>>> but did not receive support from the maintainers of the CoreSight 
>>>> subsystem.
>>>> The reason provided was: ?This component is primarily a part of the
>>>> Qualcomm proprietary QPMDA subsystem, and is capable of operating
>>>> independently from the CoreSight hardware trace generation system.?
>>>>
>>>> Chat history : https://lore.kernel.org/all/ 
>>>> CAJ9a7ViKxHThyZfFFDV_FkNRimk4uo1NrMtQ-kcaj1qO4ZcGnA at mail.gmail.com/
>>>>
>>>> Given this, we have been considering whether it would be appropriate
>>>> to create a dedicated drivers/hwtracing/qcom directory for
>>>> Qualcomm-related hwtracing drivers. This would follow the precedent set
>>>> by Intel, which maintains its own directory at drivers/hwtracing/ 
>>>> intel_th.
>>>> We believe this structure would significantly facilitate
>>>> future submissions of related Qualcomm drivers.
>>>>
>>>> - Maintenance of drivers/hwtracing/qcom:
>>>>
>>>
>>> Fine by, me.
>>>
>>>
>>>> Bjorn, who maintains linux-arm-msm, will be the maintainer of this
>>>> directory ? we?ve discussed this with him and he?s aware that his task
>>>> list may grow accordingly. Additionally, Qualcomm engineers familiar 
>>>> with
>>>> the debug hardware ? such as [Tingwei Zhang, Jinlong Mao, Songwei 
>>>> Chai],
>>>> will be available to review incoming patches and support ongoing
>>>> development.
>>>>
>>>> - Detail for TGU:
>>>>
>>>> This component can be utilized to sense a plurality of signals and
>>>> create a trigger into the CTI or generate interrupts to processors
>>>> once the input signal meets the conditions. We can treat the TGU?s
>>>> workflow as a flowsheet, it has some ?steps? regions for customization.
>>>> In each step region, we can set the signals that we want with priority
>>>> in priority_group, set the conditions in each step via 
>>>> condition_decode,
>>>> and set the resultant action by condition_select. Meanwhile,
>>>> some TGUs (not all) also provide timer/counter functionality.
>>>> Based on the characteristics described above, we consider the TGU as a
>>>> helper in the CoreSight subsystem. Its master device is the TPDM, which
>>>> can transmit signals from other subsystems, and we reuse the existing
>>>> ports mechanism to link the TPDM to the connected TGU.
>>>
>>> Please remove the coresight_device and other dependencies. You may use
>>> generic bits, CS_LOCK/UNLOCK etc. But including coresight-priv.h is
>>> not something I would prefer. It brings in unnecessary dependencies
>>> between two subsystems and I don't see any reason for using -priv.h.
>>> It is named as it is, for a reason, coresight private definitions.
>>>
>>>
>>>>
>>>> Here is a detailed example to explain how to use the TGU:
>>>>
>>>> In this example, the TGU is configured to use 2 conditions, 2 steps, 
>>>> and
>>>> the timer. The goal is to look for one of two patterns which are 
>>>> generated
>>>> from TPDM, giving priority to one, and then generate a trigger once the
>>>> timer reaches a certain value. In other words, two conditions are used
>>>> for the first step to look for the two patterns, where the one with the
>>>> highest priority is used in the first condition. Then, in the second 
>>>> step,
>>>> the timer is enabled and set to be compared to the given value at each
>>>> clock cycle. These steps are better shown below.
>>>> ?????????????? |-----------------|
>>>> ?????????????? |???????????????? |
>>>> ?????????????? |?????? TPDM????? |
>>>> ?????????????? |???????????????? |
>>>> ?????????????? |-----------------|
>>>> ??????????????????????? |
>>>> ??????????????????????? |
>>>> ???? --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- 
>>>> ------
>>>> ???? |????????????????? | 
>>>> ???????????????????????????????????????????????? |
>>>> ???? |????????????????? | |--------------------| |
>>>> ???? |??? |---- --->??? |????????????????????????? |? Go to next 
>>>> steps? | |
>>>> ???? |??? |???????????? |??????????????? |--- ---> |? Enable 
>>>> timer????? | |
>>>> ???? |??? |???????????? v??????????????? |???????? | 
>>>> ??????????????????? | |
>>>> ???? |??? |??? |-----------------|?????? | |--------------------| |
>>>> ???? |??? |??? |???????????????? |? Yes? |??????????????????? | 
>>>> ?????????? |
>>>> ???? |??? |??? |?? inputs==0xB?? | ----->|??????????????????? | 
>>>> <-------- |
>>>> ???? |??? |??? |???????????????? |?????? |??????????????????? | No | |
>>>> ???? | No |??? |-----------------|?????? | v???????? | |
>>>> ???? |??? |???????????? |??????????????? | |-----------------| | |
>>>> ???? |??? |???????????? |??????????????? |????????? | | | |
>>>> ???? |??? |???????????? |??????????????? |????????? |????? timer>=3 
>>>> |-- |
>>>> ???? |??? |???????????? v??????????????? |????????? | |?? |
>>>> ???? |??? |??? |-----------------|?????? | |-----------------|?? |
>>>> ???? |??? |??? |???????????????? |? Yes? |??????????????????? | 
>>>> ?????????? |
>>>> ???? |??? |--- |?? inputs==0xA?? | ----->|??????????????????? | 
>>>> Yes?????? |
>>>> ???? |???????? |???????????????? |??????????????????????????? | 
>>>> ?????????? |
>>>> ???? |???????? |-----------------| v?????????? |
>>>> ???? | |-----------------|?? |
>>>> ???? |????????????????????????????????????????????? | |?? |
>>>> ???? |????????????????????????????????????????????? |????? Trigger | 
>>>> ?? |
>>>> ???? |????????????????????????????????????????????? | |?? |
>>>> ???? | |-----------------|?? |
>>>> ???? |? TGU?????????????????????????????????????????????????? | 
>>>> ?????????? |
>>>> ???? |--- --- --- --- --- --- --- --- --- --- --- --- --- --- |--- 
>>>> --- -- |
>>>> ????????????????????????????????????????????????????????????? |
>>>> ????????????????????????????????????????????????????????????? v
>>>>                                                      
>>>> |-----------------|
>>>> ???????????????????????????????????????????????????? |The 
>>>> controllers? |
>>>> ???????????????????????????????????????????????????? |which will 
>>>> use?? |
>>>> ???????????????????????????????????????????????????? |triggers 
>>>> further |
>>>>                                                      
>>>> |-----------------|
>>>>
>>>> steps:
>>>> ???? 1. Reset TGU /*it will disable tgu and reset dataset*/
>>>> ???? - echo 1 > /sys/bus/coresight/devices/<tgu-name>/reset_tgu
>>>>
>>>> ???? 2. Set the pattern match for priority0 to 0xA = 0b1010 and for
>>>> ??????? priority 1 to 0xB = 0b1011.
>>>> ???? - echo 0x11113232 > /sys/bus/coresight/devices/<tgu-name>/ 
>>>> step0_priority0/reg0
>>>> ???? - echo 0x11113233 > /sys/bus/coresight/devices/<tgu-name>/ 
>>>> step0_priority1/reg0
>>>
>>> Why do they need to be coresight devices and appear on the coresight 
>>> bus if they are not coresight devices ? As I understand they are simply
>>> devices with some sysfs knobs.
>>>
>>> Otherwise, happy with the proposal
>>>
>>>
>>> Suzuki
>>
>> Hi Suzuki,
>>
>> Would it be a good idea to register the TGU device as a platform 
>> device so that it will appear under "/sys/devices/platform/" and the 
>> code could also be decoupled from coresight-priv.h
> 
> It is already an AMBA device, why do you need this as a platform 
> device ? You are welcome to add a sysfs group "tgu" under the device.
> 
> Suzuki
Practical advice!

Will move it to "/sys/bus/amba/devices/."

Songwei>
> 
>>
>> BRs,
>> Songwei>
>>>
>>>
>>>
>>>>
>>>> ???? Note:
>>>> ???????? Bit distribution diagram for each priority register
>>>> |-------------------------------------------------------------------|
>>>> ???? |?? Bits????????? |?????? Field Nam?? | Description????????????? |
>>>> |-------------------------------------------------------------------|
>>>> ???? |???????????????? |?????????????????? | 00 = bypass for OR 
>>>> output?? |
>>>> ???? |???? 29:28?????? |?? SEL_BIT7_TYPE2? | 01 = bypass for AND 
>>>> output? |
>>>> ???? |???????????????? |?????????????????? | 10 = sense input '0' is 
>>>> true|
>>>> ???? |???????????????? |?????????????????? | 11 = sense input '1' is 
>>>> true|
>>>> |-------------------------------------------------------------------|
>>>> ???? |???????????????? |?????????????????? | 00 = bypass for OR 
>>>> output?? |
>>>> ???? |???? 25:24?????? |?? SEL_BIT6_TYPE2? | 01 = bypass for AND 
>>>> output? |
>>>> ???? |???????????????? |?????????????????? | 10 = sense input '0' is 
>>>> true|
>>>> ???? |???????????????? |?????????????????? | 11 = sense input '1' is 
>>>> true|
>>>> |-------------------------------------------------------------------|
>>>> ???? |???????????????? |?????????????????? | 00 = bypass for OR 
>>>> output?? |
>>>> ???? |???? 21:20?????? |?? SEL_BIT5_TYPE2? | 01 = bypass for AND 
>>>> output? |
>>>> ???? |???????????????? |?????????????????? | 10 = sense input '0' is 
>>>> true|
>>>> ???? |???????????????? |?????????????????? | 11 = sense input '1' is 
>>>> true|
>>>> |-------------------------------------------------------------------|
>>>> ???? |???????????????? |?????????????????? | 00 = bypass for OR 
>>>> output?? |
>>>> ???? |???? 17:16?????? |?? SEL_BIT4_TYPE2? | 01 = bypass for AND 
>>>> output? |
>>>> ???? |???????????????? |?????????????????? | 10 = sense input '0' is 
>>>> true|
>>>> ???? |???????????????? |?????????????????? | 11 = sense input '1' is 
>>>> true|
>>>> |-------------------------------------------------------------------|
>>>> ???? |???????????????? |?????????????????? | 00 = bypass for OR 
>>>> output?? |
>>>> ???? |???? 13:12?????? |?? SEL_BIT3_TYPE2? | 01 = bypass for AND 
>>>> output? |
>>>> ???? |???????????????? |?????????????????? | 10 = sense input '0' is 
>>>> true|
>>>> ???? |???????????????? |?????????????????? | 11 = sense input '1' is 
>>>> true|
>>>> |-------------------------------------------------------------------|
>>>> ???? |???????????????? |?????????????????? | 00 = bypass for OR 
>>>> output?? |
>>>> ???? |????? 9:8??????? |?? SEL_BIT2_TYPE2? | 01 = bypass for AND 
>>>> output? |
>>>> ???? |???????????????? |?????????????????? | 10 = sense input '0' is 
>>>> true|
>>>> ???? |???????????????? |?????????????????? | 11 = sense input '1' is 
>>>> true|
>>>> |-------------------------------------------------------------------|
>>>> ???? |???????????????? |?????????????????? | 00 = bypass for OR 
>>>> output?? |
>>>> ???? |????? 5:4??????? |? SEL_BIT1_TYPE2?? | 01 = bypass for AND 
>>>> output? |
>>>> ???? |???????????????? |?????????????????? | 10 = sense input '0' is 
>>>> true|
>>>> ???? |???????????????? |?????????????????? | 11 = sense input '1' is 
>>>> true|
>>>> |-------------------------------------------------------------------|
>>>> ???? |???????????????? |?????????????????? | 00 = bypass for OR 
>>>> output?? |
>>>> ???? |????? 1:0??????? |? SEL_BIT0_TYPE2?? | 01 = bypass for AND 
>>>> output? |
>>>> ???? |???????????????? |?????????????????? | 10 = sense input '0' is 
>>>> true|
>>>> ???? |???????????????? |?????????????????? | 11 = sense input '1' is 
>>>> true|
>>>> |-------------------------------------------------------------------|
>>>> ???? These bits are used to identify the signals we want to sense, with
>>>> ???? a maximum signal number of 140. For example, to sense the signal
>>>> ???? 0xA (binary 1010), we set the value of bits 0 to 13 to 3232, which
>>>> ???? represents 1010. The remaining bits are set to 1, as we want to 
>>>> use
>>>> ???? AND gate to summarize all the signals we want to sense here. For
>>>> ???? rising or falling edge detection of any input to the priority, set
>>>> ???? the remaining bits to 0 to use an OR gate.
>>>>
>>>> ???? 3. look for the pattern for priority_i i=0,1.
>>>> ???? - echo 0x3 > /sys/bus/coresight/devices/<tgu-name>/ 
>>>> step0_condition_decode/reg0
>>>> ???? - echo 0x30 > /sys/bus/coresight/devices/<tgu-name>/ 
>>>> step0_condition_decode/reg1
>>>>
>>>> |-------------------------------------------------------------------------------|
>>>> ???? |?? Bits????????? |??? Field Nam??????? | 
>>>> Description??????????????? |
>>>> |-------------------------------------------------------------------------------|
>>>> ???? |???????????????? |???????????????????? |For each decoded 
>>>> condition, this?????? |
>>>> ???? |????? 24???????? |?????? NOT?????????? |inverts the output. If 
>>>> the condition?? |
>>>> ???? |???????????????? |???????????????????? |decodes to true, and 
>>>> the NOT field???? |
>>>> ???? |???????????????? |???????????????????? |is '1', then the 
>>>> output is NOT true.?? |
>>>> |-------------------------------------------------------------------------------|
>>>> ???? |???????????????? |???????????????????? |When '1' the output 
>>>> from the associated|
>>>> ???? |????? 21???????? |? BC0_COMP_ACTIVE??? |comparator will be 
>>>> actively included in|
>>>> ???? |???????????????? |???????????????????? |the decoding of this 
>>>> particular??????? |
>>>> ???? |???????????????? |???????????????????? | 
>>>> condition.???????????????????????????? |
>>>> |-------------------------------------------------------------------------------|
>>>> ???? |???????????????? |???????????????????? |When '1' the output 
>>>> from the associated|
>>>> ???? |???????????????? |???????????????????? |comparator will need 
>>>> to be 1 to affect |
>>>> ???? |????? 20???????? |?? BC0_COMP_HIGH???? |the decoding of this 
>>>> condition.??????? |
>>>> ???? |???????????????? |???????????????????? |Conversely, a '0' here 
>>>> requires a '0'? |
>>>> ???? |???????????????? |???????????????????? |from the 
>>>> comparator??????????????????? |
>>>> |-------------------------------------------------------------------------------|
>>>> ???? |???????????????? |???????????????????? |When '1' the output 
>>>> from the associated|
>>>> ???? |????? 17???????? |???????????????????? |comparator will be 
>>>> actively included in|
>>>> ???? |???????????????? |? TC0_COMP_ACTIVE??? |the decoding of this 
>>>> particular??????? |
>>>> ???? |???????????????? |???????????????????? | 
>>>> condition.???????????????????????????? |
>>>> |-------------------------------------------------------------------------------|
>>>> ???? |???????????????? |???????????????????? |When '1' the output 
>>>> from the associated|
>>>> ???? |???????????????? |???????????????????? |comparator will need 
>>>> to be 1 to affect |
>>>> ???? |????? 16???????? |? TC0_COMP_HIGH????? |the decoding of this 
>>>> particular??????? |
>>>> ???? |???????????????? |???????????????????? |condition.Conversely, 
>>>> a 0 here???????? |
>>>> ???? |???????????????? |???????????????????? |requires a '0' from 
>>>> the comparator???? |
>>>> |-------------------------------------------------------------------------------|
>>>> ???? |???????????????? |???????????????????? |When '1' the output 
>>>> from Priority_n??? |
>>>> ???? |???????????????? |???????????????????? |OR logic will be 
>>>> actively????????????? |
>>>> ???? |???? 4n+3??????? | Priority_n_OR_ACTIVE|included in the 
>>>> decoding of??????????? |
>>>> ???? |???????????????? |??? (n=0,1,2,3)????? |this particular 
>>>> condition.???????????? |
>>>> ???? |???????????????? |???????????????????? | 
>>>> ?????????????????????????????????????? |
>>>> |-------------------------------------------------------------------------------|
>>>> ???? |???????????????? |???????????????????? |When '1' the output 
>>>> from Priority_n??? |
>>>> ???? |???????????????? |???????????????????? |will need to be '1' to 
>>>> affect the????? |
>>>> ???? |???? 4n+2??????? |? Priority_n_OR_HIGH |decoding of this 
>>>> particular??????????? |
>>>> ???? |???????????????? |??? (n=0,1,2,3)????? |condition. Conversely, 
>>>> a '0' here????? |
>>>> ???? |???????????????? |???????????????????? |requires a '0' from 
>>>> Priority_n OR logic|
>>>> |-------------------------------------------------------------------------------|
>>>> ???? |???????????????? |???????????????????? |When '1' the output 
>>>> from Priority_n??? |
>>>> ???? |???????????????? |???????????????????? |AND logic will be 
>>>> actively???????????? |
>>>> ???? |???? 4n+1??????? |Priority_n_AND_ACTIVE|included in the 
>>>> decoding of this?????? |
>>>> ???? |???????????????? |? (n=0,1,2,3)??????? |particular 
>>>> condition.????????????????? |
>>>> ???? |???????????????? |???????????????????? | 
>>>> ?????????????????????????????????????? |
>>>> |-------------------------------------------------------------------------------|
>>>> ???? |???????????????? |???????????????????? |When '1' the output 
>>>> from Priority_n??? |
>>>> ???? |???????????????? |???????????????????? |AND logic will need to 
>>>> be '1' to?????? |
>>>> ???? |????? 4n???????? | Priority_n_AND_HIGH |affect the decoding of 
>>>> this??????????? |
>>>> ???? |???????????????? |?? (n=0,1,2,3)?????? |particular condition. 
>>>> Conversely,????? |
>>>> ???? |???????????????? |???????????????????? |a '0' here requires a 
>>>> '0' from???????? |
>>>> ???? |???????????????? |???????????????????? |Priority_n AND 
>>>> logic.????????????????? |
>>>> |-------------------------------------------------------------------------------|
>>>> ???? Since we use `priority_0` and `priority_1` with an AND output 
>>>> in step 2, we set `0x3`
>>>> ???? and `0x30` here to activate them.
>>>>
>>>> ???? 4. Set NEXT_STEP = 1 and TC0_ENABLE = 1 so that when the 
>>>> conditions
>>>> ??????? are met then the next step will be step 1 and the timer will 
>>>> be enabled.
>>>> ???? - echo 0x20008 > /sys/bus/coresight/devices/<tgu-name>/ 
>>>> step0_condition_select/reg0
>>>> ???? - echo 0x20008 > /sys/bus/coresight/devices/<tgu-name>/ 
>>>> step0_condition_select/reg1
>>>>
>>>> |-----------------------------------------------------------------------------|
>>>> ???? |?? Bits????????? |?????? Field Nam?? | 
>>>> Description??????????????? |
>>>> |-----------------------------------------------------------------------------|
>>>> ???? |???????????????? |?????????????????? |This field defines the 
>>>> next step the?? |
>>>> ???? |??? 18:17??????? |???? NEXT_STEP???? |TGU will 'goto' for the 
>>>> associated???? |
>>>> ???? |???????????????? |?????????????????? |Condition and 
>>>> Step.??????????????????? |
>>>> |-----------------------------------------------------------------------------|
>>>> ???? |???????????????? |?????????????????? |For each possible output 
>>>> trigger?????? |
>>>> ???? |??? 13?????????? |???? TRIGGER?????? |available, set a '1' if 
>>>> you want?????? |
>>>> ???? |???????????????? |?????????????????? |the trigger to go active 
>>>> for the?????? |
>>>> ???? |???????????????? |?????????????????? |associated condition and 
>>>> Step.???????? |
>>>> |-----------------------------------------------------------------------------|
>>>> ???? |???????????????? |?????????????????? |This will cause BC0 to 
>>>> increment if the|
>>>> ???? |??? 9??????????? |???? BC0_INC?????? |associated Condition is 
>>>> decoded for??? |
>>>> ???? |???????????????? |?????????????????? |this 
>>>> step.???????????????????????????? |
>>>> |-----------------------------------------------------------------------------|
>>>> ???? |???????????????? |?????????????????? |This will cause BC0 to 
>>>> decrement if the|
>>>> ???? |??? 8??????????? |???? BC0_DEC?????? |associated Condition is 
>>>> decoded for??? |
>>>> ???? |???????????????? |?????????????????? |this 
>>>> step.???????????????????????????? |
>>>> |-----------------------------------------------------------------------------|
>>>> ???? |???????????????? |?????????????????? |This will clear BC0 
>>>> count value to 0 if|
>>>> ???? |??? 7??????????? |???? BC0_CLEAR???? |the associated Condition 
>>>> is decoded??? |
>>>> ???? |???????????????? |?????????????????? |for this 
>>>> step.???????????????????????? |
>>>> |-----------------------------------------------------------------------------|
>>>> ???? |???????????????? |?????????????????? |This will cause TC0 to 
>>>> increment until |
>>>> ???? |??? 3??????????? |???? TC0_ENABLE??? |paused or cleared if the 
>>>> associated??? |
>>>> ???? |???????????????? |?????????????????? |Condition is decoded for 
>>>> this step.??? |
>>>> |-----------------------------------------------------------------------------|
>>>> ???? |???????????????? |?????????????????? |This will cause TC0 to 
>>>> pause until???? |
>>>> ???? |??? 2??????????? |???? TC0_PAUSE???? |enabled if the 
>>>> associated Condition??? |
>>>> ???? |???????????????? |?????????????????? |is decoded for this 
>>>> step.????????????? |
>>>> |-----------------------------------------------------------------------------|
>>>> ???? |???????????????? |?????????????????? |This will clear TC0 
>>>> count value to 0?? |
>>>> ???? |??? 1??????????? |???? TC0_CLEAR???? |if the associated 
>>>> Condition is???????? |
>>>> ???? |???????????????? |?????????????????? |decoded for this 
>>>> step.???????????????? |
>>>> |-----------------------------------------------------------------------------|
>>>> ???? |???????????????? |?????????????????? |This will set the done 
>>>> signal to the?? |
>>>> ???? |??? 0??????????? |???? DONE????????? |TGU FSM if the 
>>>> associated Condition??? |
>>>> ???? |???????????????? |?????????????????? |is decoded for this 
>>>> step.????????????? |
>>>> |-----------------------------------------------------------------------------|
>>>> ???? Based on the distribution diagram, we set `0x20008` for 
>>>> `priority0` and `priority1` to
>>>> ???? achieve "jump to step 1 and enable TC0" once the signal is sensed.
>>>>
>>>> ???? 5. activate the timer comparison for this step.
>>>> ???? -? echo 0x30000? > /sys/bus/coresight/devices/<tgu-name>/ 
>>>> step1_condition_decode/reg0
>>>>
>>>> |-------------------------------------------------------------------------------|
>>>> ???? |???????????????? |???????????????????? |When '1' the output 
>>>> from the associated|
>>>> ???? |????? 17???????? |???????????????????? |comparator will be 
>>>> actively included in|
>>>> ???? |???????????????? |? TC0_COMP_ACTIVE??? |the decoding of this 
>>>> particular??????? |
>>>> ???? |???????????????? |???????????????????? | 
>>>> condition.???????????????????????????? |
>>>> |-------------------------------------------------------------------------------|
>>>> ???? |???????????????? |???????????????????? |When '1' the output 
>>>> from the associated|
>>>> ???? |???????????????? |???????????????????? |comparator will need 
>>>> to be 1 to affect |
>>>> ???? |????? 16???????? |? TC0_COMP_HIGH????? |the decoding of this 
>>>> particular??????? |
>>>> ???? |???????????????? |???????????????????? |condition.Conversely, 
>>>> a 0 here???????? |
>>>> ???? |???????????????? |???????????????????? |requires a '0' from 
>>>> the comparator???? |
>>>> |-------------------------------------------------------------------------------|
>>>> ???? Accroding to the decode distribution diagram , we give 0x30000 
>>>> here to set 16th&17th bit
>>>> ???? to enable timer comparison.
>>>>
>>>> ???? 6. Set the NEXT_STEP = 0 and TC0_PAUSE = 1 and TC0_CLEAR = 1 
>>>> once the timer
>>>> ??????? has reached the given value.
>>>> ???? - echo 0x6 > /sys/bus/coresight/devices/<tgu-name>/ 
>>>> step1_condition_select/reg0
>>>>
>>>> ???? 7. Enable Trigger 0 for TGU when the condition 0 is met in step1,
>>>> ??????? i.e. when the timer reaches 3.
>>>> ???? - echo 0x2000 > /sys/bus/coresight/devices/<tgu-name>/ 
>>>> step1_condition_select/default
>>>>
>>>> ???? Note:
>>>> ???????? 1. 'default' register allows for establishing the resultant 
>>>> action for
>>>> ???????? the default condition
>>>>
>>>> ???????? 2. Trigger:For each possible output trigger available from
>>>> ???????? the Design document, there are three triggers: interrupts, 
>>>> CTI,
>>>> ???????? and Cross-TGU mapping.All three triggers can occur, but
>>>> ???????? the choice of which trigger to use depends on the user's
>>>> ???????? needs.
>>>>
>>>> ???? 8. Compare the timer to 3 in step 1.
>>>> ???? - echo 0x3 > /sys/bus/coresight/devices/<tgu-name>/step1_timer/ 
>>>> reg0
>>>>
>>>> ???? 9. enale tgu
>>>> ???? - echo 1 > /sys/bus/coresight/devices/<tgu-name>/enable_tgu
>>>> ---
>>>> Link to V7: https://lore.kernel.org/all/20251104064043.88972-1- 
>>>> songwei.chai at oss.qualcomm.com/
>>>>
>>>> Changes in V8:
>>>> - Add "select" section in bindings.
>>>> - Update publish date in "sysfs-bus-coresight-devices-tgu".
>>>> ---
>>>> Link to V6: https://lore.kernel.org/all/20250709104114.22240-1- 
>>>> songchai at qti.qualcomm.com/
>>>>
>>>> Changes in V7:
>>>> - Move the TGU code location from 'drivers/hwtracing/coresight/' to 
>>>> 'drivers/hwtracing/qcom/'.
>>>> - Rename the spinlock used in the code from 'spinlock' to 'lock'.
>>>> - Perform the 'calculate_array_location' separately, instead of 
>>>> doing it within the function.
>>>> - Update the sender email address.
>>>> ---
>>>> Link to V5: https://lore.kernel.org/all/20250529081949.26493-1- 
>>>> quic_songchai at quicinc.com/
>>>>
>>>> Changes in V6:
>>>> - Replace spinlock with guard(spinlock) in tgu_enable.
>>>> - Remove redundant blank line.
>>>> - Update publish date and contact member's name in "sysfs-bus- 
>>>> coresight-devices-tgu".
>>>> ---
>>>> Link to V4: https://patchwork.kernel.org/project/linux-arm-msm/ 
>>>> cover/20250423101054.954066-1-quic_songchai at quicinc.com/
>>>>
>>>> Changes in V5:
>>>> - Update publish date and kernel_version in "sysfs-bus-coresight- 
>>>> devices-tgu"
>>>> ---
>>>> Link to V3: https://lore.kernel.org/all/20250227092640.2666894-1- 
>>>> quic_songchai at quicinc.com/
>>>>
>>>> Changes in V4:
>>>> - Add changlog in coverletter.
>>>> - Correct 'year' in Copyright in patch1.
>>>> - Correct port mechansim description in patch1.
>>>> - Remove 'tgu-steps','tgu-regs','tgu-conditions','tgu-timer- 
>>>> counters' from dt-binding
>>>> and set them through reading DEVID register as per Mike's suggestion.
>>>> - Modify tgu_disable func to make it have single return point in 
>>>> patch2 as per
>>>> Mike's suggestion.
>>>> - Use sysfs_emit in enable_tgu_show func in ptach2.
>>>> - Remove redundant judgement in enable_tgu_store in patch2.
>>>> - Correct typo in description in patch3.
>>>> - Set default ret as SYSFS_GROUP_INVISIBLE, and returnret at end in 
>>>> pacth3 as
>>>> per Mike's suggestion.
>>>> - Remove tgu_dataset_ro definition in patch3
>>>> - Use #define constants with explanations of what they are rather than
>>>> arbitrary magic numbers in patch3 and patch4.
>>>> - Check -EINVAL before using 'calculate_array_location()' in array 
>>>> in patch4.
>>>> - Add 'default' in 'tgu_dataset_show''s switch part in patch4.
>>>> - Document the value needed to initiate the reset in pacth7.
>>>> - Check "value" in 'reset_tgu_store' and bail out with an error code 
>>>> if 0 in patch7.
>>>> - Remove dev_dbg in 'reset_tgu_store' in patch7.
>>>> ---
>>>> Link to V2: https://lore.kernel.org/all/20241010073917.16023-1- 
>>>> quic_songchai at quicinc.com/
>>>>
>>>> Changes in V3:
>>>> - Correct typo and format in dt-binding in patch1
>>>> - Rebase to the latest kernel version
>>>> ---
>>>> Link to V1: https://lore.kernel.org/all/20240830092311.14400-1- 
>>>> quic_songchai at quicinc.com/
>>>>
>>>> Changes in V2:
>>>> ? - Use real name instead of login name,
>>>> ? - Correct typo and format in dt-binding and code.
>>>> ? - Bring order in tgu_prob(declarations with and without 
>>>> assignments) as per
>>>> Krzysztof's suggestion.
>>>> ? - Add module device table in patch2.
>>>> ? - Set const for tgu_common_grp and tgu_ids in patch2.
>>>> ? - Initialize 'data' in tgu_ids to fix the warning in pacth2.
>>>> ---
>>>>
>>>> Songwei Chai (7):
>>>> ?? dt-bindings: arm: Add support for Qualcomm TGU trace
>>>> ?? qcom-tgu: Add TGU driver
>>>> ?? qcom-tgu: Add signal priority support
>>>> ?? qcom-tgu: Add TGU decode support
>>>> ?? qcom-tgu: Add support to configure next action
>>>> ?? qcom-tgu: Add timer/counter functionality for TGU
>>>> ?? qcom-tgu: Add reset node to initialize
>>>>
>>>> ? .../testing/sysfs-bus-coresight-devices-tgu?? |? 51 ++
>>>> ? .../devicetree/bindings/arm/qcom,tgu.yaml???? |? 92 +++
>>>> ? drivers/Makefile????????????????????????????? |?? 1 +
>>>> ? drivers/hwtracing/Kconfig???????????????????? |?? 2 +
>>>> ? drivers/hwtracing/qcom/Kconfig??????????????? |? 18 +
>>>> ? drivers/hwtracing/qcom/Makefile?????????????? |?? 3 +
>>>> ? drivers/hwtracing/qcom/tgu.c????????????????? | 737 ++++++++++++++ 
>>>> ++++
>>>> ? drivers/hwtracing/qcom/tgu.h????????????????? | 252 ++++++
>>>> ? 8 files changed, 1156 insertions(+)
>>>> ? create mode 100644 Documentation/ABI/testing/sysfs-bus-coresight- 
>>>> devices-tgu
>>>> ? create mode 100644 Documentation/devicetree/bindings/arm/ 
>>>> qcom,tgu.yaml
>>>> ? create mode 100644 drivers/hwtracing/qcom/Kconfig
>>>> ? create mode 100644 drivers/hwtracing/qcom/Makefile
>>>> ? create mode 100644 drivers/hwtracing/qcom/tgu.c
>>>> ? create mode 100644 drivers/hwtracing/qcom/tgu.h
>>>>
>>>
>>
> 



From horatiu.vultur at microchip.com  Mon Dec  8 00:35:43 2025
From: horatiu.vultur at microchip.com (Horatiu Vultur)
Date: Mon, 8 Dec 2025 09:35:43 +0100
Subject: [PATCH v5 0/2] ARM: add support for pcb8385
Message-ID: <20251208083545.3642168-1-horatiu.vultur@microchip.com>

Add pcb8385 and the documentation for it.
This is a moduler board on which it can add different daughter cards.

v4->v5:
- change the status for aes node to be "reserved"

v3->v4:
- override i2c0 using labels instead of having it under flx0
- override usart3 using labels instead of having it under flx3

v2->v3:
- remove the linux,default-trigger properties

v1->v2:
- sort nodes in alphanumerical order
- move the eeprom nodes under i2c0

Horatiu Vultur (2):
  dt-bindings: arm: at91: add lan966 pcb8385 board
  ARM: dts: Add support for pcb8385

 .../devicetree/bindings/arm/atmel-at91.yaml   |   6 +-
 arch/arm/boot/dts/microchip/Makefile          |   3 +-
 .../boot/dts/microchip/lan966x-pcb8385.dts    | 131 ++++++++++++++++++
 3 files changed, 137 insertions(+), 3 deletions(-)
 create mode 100644 arch/arm/boot/dts/microchip/lan966x-pcb8385.dts

-- 
2.34.1



From horatiu.vultur at microchip.com  Mon Dec  8 00:35:44 2025
From: horatiu.vultur at microchip.com (Horatiu Vultur)
Date: Mon, 8 Dec 2025 09:35:44 +0100
Subject: [PATCH v5 1/2] dt-bindings: arm: at91: add lan966 pcb8385 board
In-Reply-To: <20251208083545.3642168-1-horatiu.vultur@microchip.com>
References: <20251208083545.3642168-1-horatiu.vultur@microchip.com>
Message-ID: <20251208083545.3642168-2-horatiu.vultur@microchip.com>

Add documentation for Microchip LAN9668 PCB8385

Acked-by: Rob Herring (Arm) <robh at kernel.org>
Reviewed-by: Claudiu Beznea <claudiu.beznea at tuxon.dev>
Signed-off-by: Horatiu Vultur <horatiu.vultur at microchip.com>
---
 Documentation/devicetree/bindings/arm/atmel-at91.yaml | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.yaml b/Documentation/devicetree/bindings/arm/atmel-at91.yaml
index 3a34b7a2e8d4e..68d306d17c2a1 100644
--- a/Documentation/devicetree/bindings/arm/atmel-at91.yaml
+++ b/Documentation/devicetree/bindings/arm/atmel-at91.yaml
@@ -235,9 +235,11 @@ properties:
           - const: microchip,lan9662
           - const: microchip,lan966
 
-      - description: Microchip LAN9668 PCB8290 Evaluation Board.
+      - description: Microchip LAN9668 Evaluation Board.
         items:
-          - const: microchip,lan9668-pcb8290
+          - enum:
+              - microchip,lan9668-pcb8290
+              - microchip,lan9668-pcb8385
           - const: microchip,lan9668
           - const: microchip,lan966
 
-- 
2.34.1



From horatiu.vultur at microchip.com  Mon Dec  8 00:35:45 2025
From: horatiu.vultur at microchip.com (Horatiu Vultur)
Date: Mon, 8 Dec 2025 09:35:45 +0100
Subject: [PATCH v5 2/2] ARM: dts: Add support for pcb8385
In-Reply-To: <20251208083545.3642168-1-horatiu.vultur@microchip.com>
References: <20251208083545.3642168-1-horatiu.vultur@microchip.com>
Message-ID: <20251208083545.3642168-3-horatiu.vultur@microchip.com>

Add basic support for pcb8385 [1]. It is a modular board which allows
to add different daughter cards on which there are different PHYs.
This adds support for UART, LEDs and I2C.

[1] https://www.microchip.com/en-us/development-tool/ev83e85a

Signed-off-by: Horatiu Vultur <horatiu.vultur at microchip.com>
---
 arch/arm/boot/dts/microchip/Makefile          |   3 +-
 .../boot/dts/microchip/lan966x-pcb8385.dts    | 131 ++++++++++++++++++
 2 files changed, 133 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/boot/dts/microchip/lan966x-pcb8385.dts

diff --git a/arch/arm/boot/dts/microchip/Makefile b/arch/arm/boot/dts/microchip/Makefile
index 79cd38fdc7dab..08986c24a4700 100644
--- a/arch/arm/boot/dts/microchip/Makefile
+++ b/arch/arm/boot/dts/microchip/Makefile
@@ -102,4 +102,5 @@ dtb-$(CONFIG_SOC_LAN966) += \
 	lan966x-kontron-kswitch-d10-mmt-8g.dtb \
 	lan966x-pcb8290.dtb \
 	lan966x-pcb8291.dtb \
-	lan966x-pcb8309.dtb
+	lan966x-pcb8309.dtb \
+	lan966x-pcb8385.dtb
diff --git a/arch/arm/boot/dts/microchip/lan966x-pcb8385.dts b/arch/arm/boot/dts/microchip/lan966x-pcb8385.dts
new file mode 100644
index 0000000000000..d18969275efea
--- /dev/null
+++ b/arch/arm/boot/dts/microchip/lan966x-pcb8385.dts
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * lan966x-pcb8385.dts - Device Tree file for PCB8385
+ */
+/dts-v1/;
+
+#include "lan966x.dtsi"
+#include "dt-bindings/phy/phy-lan966x-serdes.h"
+
+/ {
+	model = "Microchip EVB - LAN9668";
+	compatible = "microchip,lan9668-pcb8385", "microchip,lan9668", "microchip,lan966";
+
+	aliases {
+		serial0 = &usart3;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	gpio-restart {
+		compatible = "gpio-restart";
+		gpios = <&gpio 59 GPIO_ACTIVE_LOW>;
+		open-source;
+		priority = <200>;
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		led-p1-green {
+			label = "cu0:green";
+			gpios = <&sgpio_out 2 0 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-p1-yellow {
+			label = "cu0:yellow";
+			gpios = <&sgpio_out 2 1 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-p2-green {
+			label = "cu1:green";
+			gpios = <&sgpio_out 3 0 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-p2-yellow {
+			label = "cu1:yellow";
+			gpios = <&sgpio_out 3 1 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+	};
+};
+
+&aes {
+	status = "reserved"; /* Reserved by secure OS */
+};
+
+&flx0 {
+	atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_TWI>;
+	status = "okay";
+};
+
+&flx3 {
+	atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_USART>;
+	status = "okay";
+};
+
+&gpio {
+	fc0_b_pins: fc0-b-pins {
+		/* SCL, SDA */
+		pins = "GPIO_25", "GPIO_26";
+		function = "fc0_b";
+	};
+
+	fc3_b_pins: fc3-b-pins {
+		/* RX, TX */
+		pins = "GPIO_52", "GPIO_53";
+		function = "fc3_b";
+	};
+
+	sgpio_a_pins: sgpio-a-pins {
+		/* SCK, D0, D1, LD */
+		pins = "GPIO_32", "GPIO_33", "GPIO_34", "GPIO_35";
+		function = "sgpio_a";
+	};
+};
+
+&i2c0 {
+	pinctrl-0 = <&fc0_b_pins>;
+	pinctrl-names = "default";
+	dmas = <0>, <0>;
+	i2c-analog-filter;
+	i2c-digital-filter;
+	i2c-digital-filter-width-ns = <35>;
+	i2c-sda-hold-time-ns = <1500>;
+	status = "okay";
+
+	eeprom at 54 {
+		compatible = "atmel,24c01";
+		reg = <0x54>;
+	};
+
+	eeprom at 55 {
+		compatible = "atmel,24c01";
+		reg = <0x55>;
+	};
+};
+
+&sgpio {
+	pinctrl-0 = <&sgpio_a_pins>;
+	pinctrl-names = "default";
+	microchip,sgpio-port-ranges = <0 3>;
+	status = "okay";
+
+	gpio at 0 {
+		ngpios = <64>;
+	};
+	gpio at 1 {
+		ngpios = <64>;
+	};
+};
+
+&usart3 {
+	pinctrl-0 = <&fc3_b_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
-- 
2.34.1



From jian.hu at amlogic.com  Mon Dec  8 00:40:57 2025
From: jian.hu at amlogic.com (Jian Hu)
Date: Mon, 8 Dec 2025 16:40:57 +0800
Subject: [PATCH v6 2/5] dt-bindings: clock: add Amlogic T7 SCMI clock
 controller
In-Reply-To: <20251208-independent-warping-macaw-74a169@quoll>
References: <20251204053635.1234150-1-jian.hu@amlogic.com>
 <20251204053635.1234150-3-jian.hu@amlogic.com>
 <20251208-independent-warping-macaw-74a169@quoll>
Message-ID: <dd90b445-bafb-46d4-8cec-e0877cf425b3@amlogic.com>

Hi, Krzysztof


Thans for your review.

On 12/8/2025 2:17 PM, Krzysztof Kozlowski wrote:
> [ EXTERNAL EMAIL ]
>
> On Thu, Dec 04, 2025 at 01:36:31PM +0800, Jian Hu wrote:
>> Add DT bindings for the SCMI clock controller of the Amlogic T7 SoC family.
>>
>> Signed-off-by: Jian Hu <jian.hu at amlogic.com>
>> Acked-by: Rob Herring (Arm) <robh at kernel.org>
>> ---
>>   include/dt-bindings/clock/amlogic,t7-scmi.h | 47 +++++++++++++++++++++
>>   1 file changed, 47 insertions(+)
>>   create mode 100644 include/dt-bindings/clock/amlogic,t7-scmi.h
>>
> Where is any binding doc for this? Why is this a separate patch?


The ARM SCMI device tree binding specification is located at 
./Documentation/devicetree/bindings/firmware/arm,scmi.yaml.

Certain secure clocks on the T7 rely on the ARM SCMI driver stack, which 
is officially supported by ARM.

The kernel-side SCMI client implementation resides in 
./drivers/firmware/arm_scmi/.

To enable ARM SCMI on T7, three components are needed:

- Kernel-side definition of ARM SCMI clock indices (this patch addresses 
this component);
- SCMI server implementation in the ARM Trusted Firmware (ATF) running 
at Exception Level 3 (EL3), which has been integrated into the bootloader;
- Device Tree Source (DTS) configuration for ARM SCMI clock nodes (the 
DTS changes will be submitted after the T7 clock driver patches are 
merged upstream).


>
> Best regards,
> Krzysztof
>


From arnd at arndb.de  Mon Dec  8 00:55:38 2025
From: arnd at arndb.de (Arnd Bergmann)
Date: Mon, 08 Dec 2025 09:55:38 +0100
Subject: Kconfig dangling references (BZ 216748)
In-Reply-To: <22b92ddf-6321-41b5-8073-f9c7064d3432@infradead.org>
References: <22b92ddf-6321-41b5-8073-f9c7064d3432@infradead.org>
Message-ID: <5e335232-89b4-4c35-93bd-efad7e4d8995@app.fastmail.com>

On Mon, Dec 8, 2025, at 03:04, Randy Dunlap wrote:
> from  https://bugzilla.kernel.org/show_bug.cgi?id=216748
>
> The bugzilla entry includes a Perl script and a shell script.
> This is the edited result of running them (I removed some entries that 
> were noise).
>
> I'll try to Cc: all of the relevant mailing lists or individuals.
>
>
> ARCH_HAS_HOLES_MEMORYMODEL ---
> arch/arm/mach-omap1/Kconfig:7:	select ARCH_HAS_HOLES_MEMORYMODEL

My mistake, this was a botched rebase.

> ARM_ERRATA_794072 ---
> arch/arm/mach-npcm/Kconfig:33:	select ARM_ERRATA_794072

This apparently never made it upstream because it was unreliable
https://lists.infradead.org/pipermail/linux-arm-kernel/2014-April/244343.html

> MACH_JZ4755 ---
> drivers/clk/ingenic/Kconfig:20:	default MACH_JZ4755
> drivers/pinctrl/pinctrl-ingenic.c:158:	IS_ENABLED(CONFIG_MACH_JZ4755) 
> << ID_JZ4755 |
> drivers/pinctrl/pinctrl-ingenic.c:4616:		.data = 
> IF_ENABLED(CONFIG_MACH_JZ4755, &jz4755_chip_info)
>
> MACH_JZ4760 ---
> drivers/clk/ingenic/Kconfig:40:	default MACH_JZ4760
> drivers/pinctrl/pinctrl-ingenic.c:159:	IS_ENABLED(CONFIG_MACH_JZ4760) 
> << ID_JZ4760 |
> drivers/pinctrl/pinctrl-ingenic.c:4620:		.data = 
> IF_ENABLED(CONFIG_MACH_JZ4760, &jz4760_chip_info)
> drivers/pinctrl/pinctrl-ingenic.c:4624:		.data = 
> IF_ENABLED(CONFIG_MACH_JZ4760, &jz4760_chip_info)
>
> MACH_STM32MP25 ---
> drivers/pinctrl/stm32/Kconfig:58:	default MACH_STM32MP25 || (ARCH_STM32 
> && ARM64)

This was likely intended for 32-bit kernels on 64-bit STM32MP25
chips, which we don't support. I think this can go.

> MIPS_BAIKAL_T1 ---
> drivers/ata/Kconfig:197:	select MFD_SYSCON if (MIPS_BAIKAL_T1 || 
> COMPILE_TEST)
> drivers/bus/Kconfig:43:	depends on MIPS_BAIKAL_T1 || COMPILE_TEST
> drivers/bus/Kconfig:58:	depends on MIPS_BAIKAL_T1 || COMPILE_TEST
> drivers/clk/baikal-t1/Kconfig:4:	depends on (MIPS_BAIKAL_T1 && OF) || 

I don't think we'll merge the rest of Baikal, we should probably
remove the entire platform.

> PINCTRL_MILBEAUT ---
> arch/arm/mach-milbeaut/Kconfig:16:	select PINCTRL_MILBEAUT

Same for Milbeaut

> USB_OHCI_SH ---
> arch/sh/Kconfig:334:	select USB_OHCI_SH if USB_OHCI_HCD
> arch/sh/Kconfig:344:	select USB_OHCI_SH if USB_OHCI_HCD
> arch/sh/Kconfig:429:	select USB_OHCI_SH if USB_OHCI_HCD
> arch/sh/Kconfig:455:	select USB_OHCI_SH if USB_OHCI_HCD
> arch/sh/configs/sh7757lcr_defconfig:61:CONFIG_USB_OHCI_SH=y

Should have been removed as part of 7518f0763ecd ("sh: convert
boards to use the OHCI platform driver")

> X86_P6_NOP ---
> arch/x86/Kconfig.cpufeatures:41:	depends on X86_64 || X86_P6_NOP
> arch/x86/Makefile_32.cpu:48:ifneq ($(CONFIG_X86_P6_NOP),y)

I missed this in f388f60ca904 ("x86/cpu: Drop configuration options
for early 64-bit CPUs"). Both references can be removed, because
p6-nop was already disallowed for 32-bit CPUs at the time.

I don't know if any supported binutils still require -mtune=generic32

> XTENSA_PLATFORM_ESP32 ---
> drivers/tty/serial/Kconfig:1598:	depends on XTENSA_PLATFORM_ESP32 || 
> (COMPILE_TEST && OF)
> drivers/tty/serial/Kconfig:1611:	depends on XTENSA_PLATFORM_ESP32 || 
> (COMPILE_TEST && OF)

Max is still working on esp32 support as far as I know, it's just
slow progress, see
https://github.com/jcmvbkbc/linux-xtensa/commits/xtensa-6.16-esp32

       Arnd


From tiwai at suse.de  Mon Dec  8 01:06:40 2025
From: tiwai at suse.de (Takashi Iwai)
Date: Mon, 08 Dec 2025 10:06:40 +0100
Subject: Kconfig dangling references (BZ 216748)
In-Reply-To: <22b92ddf-6321-41b5-8073-f9c7064d3432@infradead.org>
References: <22b92ddf-6321-41b5-8073-f9c7064d3432@infradead.org>
Message-ID: <87fr9luyu7.wl-tiwai@suse.de>

On Mon, 08 Dec 2025 03:04:09 +0100,
Randy Dunlap wrote:
> 
> SND_SOC_AC97_BUS_NEW ---
> sound/soc/pxa/Kconfig:21:	select SND_SOC_AC97_BUS_NEW

This must be a bogus entry added in commit 1c8bc7b3de5e ("ASoC: pxa:
switch to new ac97 bus support"), which can be dropped.

> SND_SOC_CS35L56_CAL_SYSFS_COMMON ---
> sound/soc/codecs/Kconfig:920:	select SND_SOC_CS35L56_CAL_SYSFS_COMMON

The buggy commit was 32172cf3cb54 ("ASoC: cs35l56: Allow restoring
factory calibration through ALSA control").
This looks like a fallout at changing from sysfs to debugfs, so this
should be SND_SOC_CS35L56_CAL_DEBUGFS_COMMON instead.


thanks,

Takashi


From mkl at pengutronix.de  Mon Dec  8 01:13:15 2025
From: mkl at pengutronix.de (Marc Kleine-Budde)
Date: Mon, 8 Dec 2025 10:13:15 +0100
Subject: [PATCH 2/2] arm64: dts: freescale: add NXP FRDM-IMX91S board
 support
In-Reply-To: <20251205-imx91s-frdm-v1-2-afd6cd01c299@nxp.com>
References: <20251205-imx91s-frdm-v1-0-afd6cd01c299@nxp.com>
 <20251205-imx91s-frdm-v1-2-afd6cd01c299@nxp.com>
Message-ID: <20251208-free-barracuda-of-strength-4f8c3f-mkl@pengutronix.de>

On 05.12.2025 17:03:59, Yanan.Yang wrote:
> This DT enables:
[...]
> - FlexCAN

[...]

> +&flexcan1 {
> +	pinctrl-0 = <&pinctrl_flexcan1>;
> +	pinctrl-1 = <&pinctrl_flexcan1_sleep>;
> +	pinctrl-names = "default", "sleep";
> +	xceiver-supply = <&reg_can_stby>;

please use the "can-transceiver" instead of the "xceiver-supply"

> +	status = "okay";
> +};

regards,
Marc

-- 
Pengutronix e.K.                 | Marc Kleine-Budde          |
Embedded Linux                   | https://www.pengutronix.de |
Vertretung N?rnberg              | Phone: +49-5121-206917-129 |
Amtsgericht Hildesheim, HRA 2686 | Fax:   +49-5121-206917-9   |
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251208/9191567d/attachment.sig>

From dapeng1.mi at linux.intel.com  Mon Dec  8 01:14:56 2025
From: dapeng1.mi at linux.intel.com (Mi, Dapeng)
Date: Mon, 8 Dec 2025 17:14:56 +0800
Subject: [PATCH v6 35/44] KVM: VMX: Drop intermediate "guest" field from
 msr_autostore
In-Reply-To: <20251206001720.468579-36-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
 <20251206001720.468579-36-seanjc@google.com>
Message-ID: <0237b3eb-87f5-4758-b704-9f8d525f1f15@linux.intel.com>


On 12/6/2025 8:17 AM, Sean Christopherson wrote:
> Drop the intermediate "guest" field from vcpu_vmx.msr_autostore as the
> value saved on VM-Exit isn't guaranteed to be the guest's value, it's
> purely whatever is in hardware at the time of VM-Exit.  E.g. KVM's only
> use of the store list at the momemnt is to snapshot TSC at VM-Exit, and
> the value saved is always the raw TSC even if TSC-offseting and/or
> TSC-scaling is enabled for the guest.
>
> And unlike msr_autoload, there is no need differentiate between "on-entry"
> and "on-exit".
>
> No functional change intended.
>
> Cc: Jim Mattson <jmattson at google.com>
> Signed-off-by: Sean Christopherson <seanjc at google.com>
> ---
>  arch/x86/kvm/vmx/nested.c | 10 +++++-----
>  arch/x86/kvm/vmx/vmx.c    |  2 +-
>  arch/x86/kvm/vmx/vmx.h    |  4 +---
>  3 files changed, 7 insertions(+), 9 deletions(-)
>
> diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
> index 729cc1f05ac8..486789dac515 100644
> --- a/arch/x86/kvm/vmx/nested.c
> +++ b/arch/x86/kvm/vmx/nested.c
> @@ -1076,11 +1076,11 @@ static bool nested_vmx_get_vmexit_msr_value(struct kvm_vcpu *vcpu,
>  	 * VM-exit in L0, use the more accurate value.
>  	 */
>  	if (msr_index == MSR_IA32_TSC) {
> -		int i = vmx_find_loadstore_msr_slot(&vmx->msr_autostore.guest,
> +		int i = vmx_find_loadstore_msr_slot(&vmx->msr_autostore,
>  						    MSR_IA32_TSC);
>  
>  		if (i >= 0) {
> -			u64 val = vmx->msr_autostore.guest.val[i].value;
> +			u64 val = vmx->msr_autostore.val[i].value;
>  
>  			*data = kvm_read_l1_tsc(vcpu, val);
>  			return true;
> @@ -1167,7 +1167,7 @@ static void prepare_vmx_msr_autostore_list(struct kvm_vcpu *vcpu,
>  					   u32 msr_index)
>  {
>  	struct vcpu_vmx *vmx = to_vmx(vcpu);
> -	struct vmx_msrs *autostore = &vmx->msr_autostore.guest;
> +	struct vmx_msrs *autostore = &vmx->msr_autostore;
>  	bool in_vmcs12_store_list;
>  	int msr_autostore_slot;
>  	bool in_autostore_list;
> @@ -2366,7 +2366,7 @@ static void prepare_vmcs02_constant_state(struct vcpu_vmx *vmx)
>  	 * addresses are constant (for vmcs02), the counts can change based
>  	 * on L2's behavior, e.g. switching to/from long mode.
>  	 */
> -	vmcs_write64(VM_EXIT_MSR_STORE_ADDR, __pa(vmx->msr_autostore.guest.val));
> +	vmcs_write64(VM_EXIT_MSR_STORE_ADDR, __pa(vmx->msr_autostore.val));
>  	vmcs_write64(VM_EXIT_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.host.val));
>  	vmcs_write64(VM_ENTRY_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.guest.val));
>  
> @@ -2704,7 +2704,7 @@ static void prepare_vmcs02_rare(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
>  	 */
>  	prepare_vmx_msr_autostore_list(&vmx->vcpu, MSR_IA32_TSC);
>  
> -	vmcs_write32(VM_EXIT_MSR_STORE_COUNT, vmx->msr_autostore.guest.nr);
> +	vmcs_write32(VM_EXIT_MSR_STORE_COUNT, vmx->msr_autostore.nr);
>  	vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.host.nr);
>  	vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, vmx->msr_autoload.guest.nr);
>  
> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> index 62ba2a2b9e98..23c92c41fd83 100644
> --- a/arch/x86/kvm/vmx/vmx.c
> +++ b/arch/x86/kvm/vmx/vmx.c
> @@ -6567,7 +6567,7 @@ void dump_vmcs(struct kvm_vcpu *vcpu)
>  	if (vmcs_read32(VM_ENTRY_MSR_LOAD_COUNT) > 0)
>  		vmx_dump_msrs("guest autoload", &vmx->msr_autoload.guest);
>  	if (vmcs_read32(VM_EXIT_MSR_STORE_COUNT) > 0)
> -		vmx_dump_msrs("guest autostore", &vmx->msr_autostore.guest);
> +		vmx_dump_msrs("autostore", &vmx->msr_autostore);
>  
>  	if (vmentry_ctl & VM_ENTRY_LOAD_CET_STATE)
>  		pr_err("S_CET = 0x%016lx, SSP = 0x%016lx, SSP TABLE = 0x%016lx\n",
> diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h
> index d7a96c84371f..4ce653d729ca 100644
> --- a/arch/x86/kvm/vmx/vmx.h
> +++ b/arch/x86/kvm/vmx/vmx.h
> @@ -245,9 +245,7 @@ struct vcpu_vmx {
>  		struct vmx_msrs host;
>  	} msr_autoload;
>  
> -	struct msr_autostore {
> -		struct vmx_msrs guest;
> -	} msr_autostore;
> +	struct vmx_msrs msr_autostore;
>  
>  	struct {
>  		int vm86_active;

LGTM.

Reviewed-by: Dapeng Mi <dapeng1.mi at linux.intel.com>




From mkl at pengutronix.de  Mon Dec  8 01:15:20 2025
From: mkl at pengutronix.de (Marc Kleine-Budde)
Date: Mon, 8 Dec 2025 10:15:20 +0100
Subject: [PATCH 2/2] arm64: dts: freescale: imx95: Add support for i.MX95
 15x15 FRDM board
In-Reply-To: <20251207-127-v1-2-5a2eeb69f150@nxp.com>
References: <20251207-127-v1-0-5a2eeb69f150@nxp.com>
 <20251207-127-v1-2-5a2eeb69f150@nxp.com>
Message-ID: <20251208-watchful-fluorescent-piculet-4b55a8-mkl@pengutronix.de>

On 07.12.2025 05:26:06, Lei Xu wrote:
> The i.MX95 15x15 FRDM board is a compact and cost-effective development
> platform based on the i.MX95 applications processor.
>
> Add device tree support for this board, including:
[...]
>  - FlexCAN2 and FlexCAN5

[...]

> +&flexcan2 {
> +	pinctrl-0 = <&pinctrl_flexcan2>;
> +	pinctrl-names = "default";
> +	xceiver-supply = <&reg_can_stby>;
> +	status = "okay";
> +};
> +
> +&flexcan5 {
> +	pinctrl-0 = <&pinctrl_flexcan5>;
> +	pinctrl-names = "default";
> +	xceiver-supply = <&reg_can_stby>;
> +	status = "okay";
> +};

please use the "can-transceiver" instead of the "xceiver-supply" property.

regards,
Marc
--
Pengutronix e.K.                 | Marc Kleine-Budde          |
Embedded Linux                   | https://www.pengutronix.de |
Vertretung N?rnberg              | Phone: +49-5121-206917-129 |
Amtsgericht Hildesheim, HRA 2686 | Fax:   +49-5121-206917-9   |
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251208/9d0520b5/attachment.sig>

From david.laight.linux at gmail.com  Mon Dec  8 01:26:54 2025
From: david.laight.linux at gmail.com (David Laight)
Date: Mon, 8 Dec 2025 09:26:54 +0000
Subject: [Bug report] hash_name() may cross page boundary and trigger
 sleep in RCU context
In-Reply-To: <20251208023206.44238-1-xieyuanbin1@huawei.com>
References: <aTLLLuup7TeAqFVL@shell.armlinux.org.uk>
	<20251208023206.44238-1-xieyuanbin1@huawei.com>
Message-ID: <20251208092655.6d88af9f@pumpkin>

On Mon, 8 Dec 2025 10:32:06 +0800
Xie Yuanbin <xieyuanbin1 at huawei.com> wrote:

> On Fri, 5 Dec 2025 12:08:14 +0000, Russell King wrote:
> > On Wed, Dec 03, 2025 at 09:48:00AM +0800, Xie Yuanbin wrote:  
> >> On Tue, 2 Dec 2025 14:07:25 -0800, Linus Torvalds wrote:  
> >> > On Tue, 2 Dec 2025 at 04:43, Russell King (Oracle)
> >> > <linux at armlinux.org.uk> wrote:  
> >> >>
> >> >> What I'm thinking is to address both of these by handling kernel space
> >> >> page faults (which will be permission or PTE-not-present) separately
> >> >> (not even build tested):  
> >> >
> >> > That patch looks sane to me.
> >> >
> >> > But I also didn't build test it, just scanned it visually ;)  
> >>
> >> That patch removes harden_branch_predictor() from __do_user_fault(), and
> >> moves it to do_page_fault()->do_kernel_address_page_fault().
> >> This resolves previously mentioned kernel warning issue. However,
> >> __do_user_fault() is not only called by do_page_fault(), it is
> >> alse called by do_bad_area(), do_sect_fault() and do_translation_fault().
> >>
> >> So I think that some harden_branch_predictor() is missing on other paths.
> >> According to my tests, when CONFIG_ARM_LPAE=n, harden_branch_predictor()
> >> will never be called anymore, even if a user program trys to access the
> >> kernel address.
> >>
> >> Or perhaps I've misunderstood something, could you please point it out?
> >> Thank you very much.  
> >
> > Right, let's split these issues into separate patches. Please test this
> > patch, which should address only the hash_name() fault issue, and
> > provides the basis for fixing the branch predictor issue.  
> 
> I conducted a simple test, and it seems that both the hash_name()
> might sleep issue and the branch predictor issue have been fixed.
> 
> BTW, even with this patch, test cases may still fail. There is another
> bug in hash_name() will also be triggered by the testcase, which will be
> fixed in this patch:
> Link: https://lore.kernel.org/20251127025848.363992-1-pangliyuan1 at huawei.com
> 
> Test case is from:
> Link: https://lore.kernel.org/20251127140109.191657-1-xieyuanbin1 at huawei.com
> 
> Test in commit 6987d58a9cbc5bd57c98 ("Add linux-next specific files for
> 20251205") from linux-next branch.
> 
> I still have a question about this patch: Is 
> ```patch
> +		if (interrupts_enabled(regs))
> +			local_irq_enable();
> ```
> necessary? Although this implementation is closer to the original code,
> which can reduce side effects, do_bad_area(), do_sect_fault(),
> and do_translation_fault() all call __do_kernel_fault() with interrupts
> disabled.

It has to be safer to leave them disabled.
But you don't want to do that over long code paths.
But I'd have thought the 'act on an exception table entry or panic'
path wouldn't be long compared to an actual ISR (or other code that
disables interrupts) so there is no real point enabling them here.
But that is just my 2c.

	David

> 
> Thanks very much!
> 



From dapeng1.mi at linux.intel.com  Mon Dec  8 01:29:53 2025
From: dapeng1.mi at linux.intel.com (Mi, Dapeng)
Date: Mon, 8 Dec 2025 17:29:53 +0800
Subject: [PATCH v6 37/44] KVM: VMX: Dedup code for removing MSR from
 VMCS's auto-load list
In-Reply-To: <20251206001720.468579-38-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
 <20251206001720.468579-38-seanjc@google.com>
Message-ID: <2440b9bf-a2a1-4f66-94b2-71f47d62f3db@linux.intel.com>


On 12/6/2025 8:17 AM, Sean Christopherson wrote:
> Add a helper to remove an MSR from an auto-{load,store} list to dedup the
> msr_autoload code, and in anticipation of adding similar functionality for
> msr_autostore.
>
> No functional change intended.
>
> Signed-off-by: Sean Christopherson <seanjc at google.com>
> ---
>  arch/x86/kvm/vmx/vmx.c | 31 ++++++++++++++++---------------
>  1 file changed, 16 insertions(+), 15 deletions(-)
>
> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> index 52bcb817cc15..a51f66d1b201 100644
> --- a/arch/x86/kvm/vmx/vmx.c
> +++ b/arch/x86/kvm/vmx/vmx.c
> @@ -1040,9 +1040,22 @@ static int vmx_find_loadstore_msr_slot(struct vmx_msrs *m, u32 msr)
>  	return -ENOENT;
>  }
>  
> +static void vmx_remove_auto_msr(struct vmx_msrs *m, u32 msr,
> +				unsigned long vmcs_count_field)
> +{
> +	int i;
> +
> +	i = vmx_find_loadstore_msr_slot(m, msr);
> +	if (i < 0)
> +		return;
> +
> +	--m->nr;
> +	m->val[i] = m->val[m->nr];

Sometimes the order of MSR writing does matter, e.g., PERF_GLOBAL_CTRL MSR
should be written at last after all PMU MSR writing. So directly moving the
last MSR entry into cleared one could break the MSR writing sequence and
may cause issue in theory.

I know this won't really cause issue since currently vPMU won't use the MSR
auto-load feature to save any PMU MSR, but it's still unsafe for future uses.?

I'm not sure if it's worthy to do the strict MSR entry shift right now.
Perhaps we could add a message to warn users at least.

Thanks.


> +	vmcs_write32(vmcs_count_field, m->nr);
> +}
> +
>  static void clear_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr)
>  {
> -	int i;
>  	struct msr_autoload *m = &vmx->msr_autoload;
>  
>  	switch (msr) {
> @@ -1063,21 +1076,9 @@ static void clear_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr)
>  		}
>  		break;
>  	}
> -	i = vmx_find_loadstore_msr_slot(&m->guest, msr);
> -	if (i < 0)
> -		goto skip_guest;
> -	--m->guest.nr;
> -	m->guest.val[i] = m->guest.val[m->guest.nr];
> -	vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->guest.nr);
>  
> -skip_guest:
> -	i = vmx_find_loadstore_msr_slot(&m->host, msr);
> -	if (i < 0)
> -		return;
> -
> -	--m->host.nr;
> -	m->host.val[i] = m->host.val[m->host.nr];
> -	vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->host.nr);
> +	vmx_remove_auto_msr(&m->guest, msr, VM_ENTRY_MSR_LOAD_COUNT);
> +	vmx_remove_auto_msr(&m->host, msr, VM_EXIT_MSR_LOAD_COUNT);
>  }
>  
>  static __always_inline void add_atomic_switch_msr_special(struct vcpu_vmx *vmx,


From dapeng1.mi at linux.intel.com  Mon Dec  8 01:32:01 2025
From: dapeng1.mi at linux.intel.com (Mi, Dapeng)
Date: Mon, 8 Dec 2025 17:32:01 +0800
Subject: [PATCH v6 38/44] KVM: VMX: Drop unused @entry_only param from
 add_atomic_switch_msr()
In-Reply-To: <20251206001720.468579-39-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
 <20251206001720.468579-39-seanjc@google.com>
Message-ID: <f551c638-a8c8-4aab-9fb7-f04df124ff15@linux.intel.com>


On 12/6/2025 8:17 AM, Sean Christopherson wrote:
> Drop the "on VM-Enter only" parameter from add_atomic_switch_msr() as it
> is no longer used, and for all intents and purposes was never used.  The
> functionality was added, under embargo, by commit 989e3992d2ec
> ("x86/KVM/VMX: Extend add_atomic_switch_msr() to allow VMENTER only MSRs"),
> and then ripped out by commit 2f055947ae5e ("x86/kvm: Drop L1TF MSR list
> approach") just a few commits later.
>
>   2f055947ae5e x86/kvm: Drop L1TF MSR list approach
>   72c6d2db64fa x86/litf: Introduce vmx status variable
>   215af5499d9e cpu/hotplug: Online siblings when SMT control is turned on
>   390d975e0c4e x86/KVM/VMX: Use MSR save list for IA32_FLUSH_CMD if required
>   989e3992d2ec x86/KVM/VMX: Extend add_atomic_switch_msr() to allow VMENTER only MSRs
>
> Furthermore, it's extremely unlikely KVM will ever _need_ to load an MSR
> value via the auto-load lists only on VM-Enter.  MSRs writes via the lists
> aren't optimized in any way, and so the only reason to use the lists
> instead of a WRMSR are for cases where the MSR _must_ be load atomically
> with respect to VM-Enter (and/or VM-Exit).  While one could argue that
> command MSRs, e.g. IA32_FLUSH_CMD, "need" to be done exact at VM-Enter, in
> practice doing such flushes within a few instructons of VM-Enter is more
> than sufficient.
>
> Note, the shortlog and changelog for commit 390d975e0c4e ("x86/KVM/VMX: Use
> MSR save list for IA32_FLUSH_CMD if required") are misleading and wrong.
> That commit added MSR_IA32_FLUSH_CMD to the VM-Enter _load_ list, not the
> VM-Enter save list (which doesn't exist, only VM-Exit has a store/save
> list).
>
> Signed-off-by: Sean Christopherson <seanjc at google.com>
> ---
>  arch/x86/kvm/vmx/vmx.c | 13 ++++---------
>  1 file changed, 4 insertions(+), 9 deletions(-)
>
> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> index a51f66d1b201..38491962b2c1 100644
> --- a/arch/x86/kvm/vmx/vmx.c
> +++ b/arch/x86/kvm/vmx/vmx.c
> @@ -1094,7 +1094,7 @@ static __always_inline void add_atomic_switch_msr_special(struct vcpu_vmx *vmx,
>  }
>  
>  static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
> -				  u64 guest_val, u64 host_val, bool entry_only)
> +				  u64 guest_val, u64 host_val)
>  {
>  	int i, j = 0;
>  	struct msr_autoload *m = &vmx->msr_autoload;
> @@ -1132,8 +1132,7 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
>  	}
>  
>  	i = vmx_find_loadstore_msr_slot(&m->guest, msr);
> -	if (!entry_only)
> -		j = vmx_find_loadstore_msr_slot(&m->host, msr);
> +	j = vmx_find_loadstore_msr_slot(&m->host, msr);
>  
>  	if ((i < 0 && m->guest.nr == MAX_NR_LOADSTORE_MSRS) ||
>  	    (j < 0 &&  m->host.nr == MAX_NR_LOADSTORE_MSRS)) {
> @@ -1148,9 +1147,6 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
>  	m->guest.val[i].index = msr;
>  	m->guest.val[i].value = guest_val;
>  
> -	if (entry_only)
> -		return;
> -
>  	if (j < 0) {
>  		j = m->host.nr++;
>  		vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->host.nr);
> @@ -1190,8 +1186,7 @@ static bool update_transition_efer(struct vcpu_vmx *vmx)
>  		if (!(guest_efer & EFER_LMA))
>  			guest_efer &= ~EFER_LME;
>  		if (guest_efer != kvm_host.efer)
> -			add_atomic_switch_msr(vmx, MSR_EFER,
> -					      guest_efer, kvm_host.efer, false);
> +			add_atomic_switch_msr(vmx, MSR_EFER, guest_efer, kvm_host.efer);
>  		else
>  			clear_atomic_switch_msr(vmx, MSR_EFER);
>  		return false;
> @@ -7350,7 +7345,7 @@ static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx)
>  			clear_atomic_switch_msr(vmx, msrs[i].msr);
>  		else
>  			add_atomic_switch_msr(vmx, msrs[i].msr, msrs[i].guest,
> -					msrs[i].host, false);
> +					      msrs[i].host);
>  }
>  
>  static void vmx_update_hv_timer(struct kvm_vcpu *vcpu, bool force_immediate_exit)

LGTM.

Reviewed-by: Dapeng Mi <dapeng1.mi at linux.intel.com>




From dapeng1.mi at linux.intel.com  Mon Dec  8 01:32:41 2025
From: dapeng1.mi at linux.intel.com (Mi, Dapeng)
Date: Mon, 8 Dec 2025 17:32:41 +0800
Subject: [PATCH v6 39/44] KVM: VMX: Bug the VM if either MSR auto-load
 list is full
In-Reply-To: <20251206001720.468579-40-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
 <20251206001720.468579-40-seanjc@google.com>
Message-ID: <4b82ce2f-ff87-4d6b-9cee-565f56bb75ca@linux.intel.com>


On 12/6/2025 8:17 AM, Sean Christopherson wrote:
> WARN and bug the VM if either MSR auto-load list is full when adding an
> MSR to the lists, as the set of MSRs that KVM loads via the lists is
> finite and entirely KVM controlled, i.e. overflowing the lists shouldn't
> be possible in a fully released version of KVM.  Terminate the VM as the
> core KVM infrastructure has no insight as to _why_ an MSR is being added
> to the list, and failure to load an MSR on VM-Enter and/or VM-Exit could
> be fatal to the host.  E.g. running the host with a guest-controlled PEBS
> MSR could generate unexpected writes to the DS buffer and crash the host.
>
> Signed-off-by: Sean Christopherson <seanjc at google.com>
> ---
>  arch/x86/kvm/vmx/vmx.c | 9 ++++-----
>  1 file changed, 4 insertions(+), 5 deletions(-)
>
> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> index 38491962b2c1..2c50ebf4ff1b 100644
> --- a/arch/x86/kvm/vmx/vmx.c
> +++ b/arch/x86/kvm/vmx/vmx.c
> @@ -1098,6 +1098,7 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
>  {
>  	int i, j = 0;
>  	struct msr_autoload *m = &vmx->msr_autoload;
> +	struct kvm *kvm = vmx->vcpu.kvm;
>  
>  	switch (msr) {
>  	case MSR_EFER:
> @@ -1134,12 +1135,10 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
>  	i = vmx_find_loadstore_msr_slot(&m->guest, msr);
>  	j = vmx_find_loadstore_msr_slot(&m->host, msr);
>  
> -	if ((i < 0 && m->guest.nr == MAX_NR_LOADSTORE_MSRS) ||
> -	    (j < 0 &&  m->host.nr == MAX_NR_LOADSTORE_MSRS)) {
> -		printk_once(KERN_WARNING "Not enough msr switch entries. "
> -				"Can't add msr %x\n", msr);
> +	if (KVM_BUG_ON(i < 0 && m->guest.nr == MAX_NR_LOADSTORE_MSRS, kvm) ||
> +	    KVM_BUG_ON(j < 0 &&  m->host.nr == MAX_NR_LOADSTORE_MSRS, kvm))
>  		return;
> -	}
> +
>  	if (i < 0) {
>  		i = m->guest.nr++;
>  		vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->guest.nr);

Reviewed-by: Dapeng Mi <dapeng1.mi at linux.intel.com>




From dapeng1.mi at linux.intel.com  Mon Dec  8 01:34:27 2025
From: dapeng1.mi at linux.intel.com (Mi, Dapeng)
Date: Mon, 8 Dec 2025 17:34:27 +0800
Subject: [PATCH v6 39/44] KVM: VMX: Bug the VM if either MSR auto-load
 list is full
In-Reply-To: <20251206001720.468579-40-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
 <20251206001720.468579-40-seanjc@google.com>
Message-ID: <04c70698-e523-43ae-9092-f360c848d797@linux.intel.com>


On 12/6/2025 8:17 AM, Sean Christopherson wrote:
> WARN and bug the VM if either MSR auto-load list is full when adding an
> MSR to the lists, as the set of MSRs that KVM loads via the lists is
> finite and entirely KVM controlled, i.e. overflowing the lists shouldn't
> be possible in a fully released version of KVM.  Terminate the VM as the
> core KVM infrastructure has no insight as to _why_ an MSR is being added
> to the list, and failure to load an MSR on VM-Enter and/or VM-Exit could
> be fatal to the host.  E.g. running the host with a guest-controlled PEBS
> MSR could generate unexpected writes to the DS buffer and crash the host.
>
> Signed-off-by: Sean Christopherson <seanjc at google.com>
> ---
>  arch/x86/kvm/vmx/vmx.c | 9 ++++-----
>  1 file changed, 4 insertions(+), 5 deletions(-)
>
> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> index 38491962b2c1..2c50ebf4ff1b 100644
> --- a/arch/x86/kvm/vmx/vmx.c
> +++ b/arch/x86/kvm/vmx/vmx.c
> @@ -1098,6 +1098,7 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
>  {
>  	int i, j = 0;
>  	struct msr_autoload *m = &vmx->msr_autoload;
> +	struct kvm *kvm = vmx->vcpu.kvm;
>  
>  	switch (msr) {
>  	case MSR_EFER:
> @@ -1134,12 +1135,10 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
>  	i = vmx_find_loadstore_msr_slot(&m->guest, msr);
>  	j = vmx_find_loadstore_msr_slot(&m->host, msr);
>  
> -	if ((i < 0 && m->guest.nr == MAX_NR_LOADSTORE_MSRS) ||
> -	    (j < 0 &&  m->host.nr == MAX_NR_LOADSTORE_MSRS)) {
> -		printk_once(KERN_WARNING "Not enough msr switch entries. "
> -				"Can't add msr %x\n", msr);
> +	if (KVM_BUG_ON(i < 0 && m->guest.nr == MAX_NR_LOADSTORE_MSRS, kvm) ||
> +	    KVM_BUG_ON(j < 0 &&  m->host.nr == MAX_NR_LOADSTORE_MSRS, kvm))

nit: Remove one extra space before "m->host.nr".


>  		return;
> -	}
> +
>  	if (i < 0) {
>  		i = m->guest.nr++;
>  		vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->guest.nr);


From dapeng1.mi at linux.intel.com  Mon Dec  8 01:35:13 2025
From: dapeng1.mi at linux.intel.com (Mi, Dapeng)
Date: Mon, 8 Dec 2025 17:35:13 +0800
Subject: [PATCH v6 40/44] KVM: VMX: Set MSR index auto-load entry if and
 only if entry is "new"
In-Reply-To: <20251206001720.468579-41-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
 <20251206001720.468579-41-seanjc@google.com>
Message-ID: <c2562f0b-9d73-479d-acaf-27da2fbe0c1e@linux.intel.com>


On 12/6/2025 8:17 AM, Sean Christopherson wrote:
> When adding an MSR to the auto-load lists, update the MSR index in the
> list entry if and only if a new entry is being inserted, as 'i' can only
> be non-negative if vmx_find_loadstore_msr_slot() found an entry with the
> MSR's index.  Unnecessarily setting the index is benign, but it makes it
> harder to see that updating the value is necessary even when an existing
> entry for the MSR was found.
>
> No functional change intended.
>
> Signed-off-by: Sean Christopherson <seanjc at google.com>
> ---
>  arch/x86/kvm/vmx/vmx.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> index 2c50ebf4ff1b..be2a2580e8f1 100644
> --- a/arch/x86/kvm/vmx/vmx.c
> +++ b/arch/x86/kvm/vmx/vmx.c
> @@ -1141,16 +1141,16 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
>  
>  	if (i < 0) {
>  		i = m->guest.nr++;
> +		m->guest.val[i].index = msr;
>  		vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->guest.nr);
>  	}
> -	m->guest.val[i].index = msr;
>  	m->guest.val[i].value = guest_val;
>  
>  	if (j < 0) {
>  		j = m->host.nr++;
> +		m->host.val[j].index = msr;
>  		vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->host.nr);
>  	}
> -	m->host.val[j].index = msr;
>  	m->host.val[j].value = host_val;
>  }
>  

Reviewed-by: Dapeng Mi <dapeng1.mi at linux.intel.com>




From dapeng1.mi at linux.intel.com  Mon Dec  8 01:36:38 2025
From: dapeng1.mi at linux.intel.com (Mi, Dapeng)
Date: Mon, 8 Dec 2025 17:36:38 +0800
Subject: [PATCH v6 41/44] KVM: VMX: Compartmentalize adding MSRs to host
 vs. guest auto-load list
In-Reply-To: <20251206001720.468579-42-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
 <20251206001720.468579-42-seanjc@google.com>
Message-ID: <78fb04ca-59a2-493a-a82b-d59aaf6b557a@linux.intel.com>


On 12/6/2025 8:17 AM, Sean Christopherson wrote:
> Undo the bundling of the "host" and "guest" MSR auto-load list logic so
> that the code can be deduplicated by factoring out the logic to a separate
> helper.  Now that "list full" situations are treated as fatal to the VM,
> there is no need to pre-check both lists.
>
> For all intents and purposes, this reverts the add_atomic_switch_msr()
> changes made by commit 3190709335dd ("x86/KVM/VMX: Separate the VMX
> AUTOLOAD guest/host number accounting").
>
> Signed-off-by: Sean Christopherson <seanjc at google.com>
> ---
>  arch/x86/kvm/vmx/vmx.c | 23 ++++++++++++-----------
>  1 file changed, 12 insertions(+), 11 deletions(-)
>
> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> index be2a2580e8f1..018e01daab68 100644
> --- a/arch/x86/kvm/vmx/vmx.c
> +++ b/arch/x86/kvm/vmx/vmx.c
> @@ -1096,9 +1096,9 @@ static __always_inline void add_atomic_switch_msr_special(struct vcpu_vmx *vmx,
>  static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
>  				  u64 guest_val, u64 host_val)
>  {
> -	int i, j = 0;
>  	struct msr_autoload *m = &vmx->msr_autoload;
>  	struct kvm *kvm = vmx->vcpu.kvm;
> +	int i;
>  
>  	switch (msr) {
>  	case MSR_EFER:
> @@ -1133,25 +1133,26 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
>  	}
>  
>  	i = vmx_find_loadstore_msr_slot(&m->guest, msr);
> -	j = vmx_find_loadstore_msr_slot(&m->host, msr);
> -
> -	if (KVM_BUG_ON(i < 0 && m->guest.nr == MAX_NR_LOADSTORE_MSRS, kvm) ||
> -	    KVM_BUG_ON(j < 0 &&  m->host.nr == MAX_NR_LOADSTORE_MSRS, kvm))
> -		return;
> -
>  	if (i < 0) {
> +		if (KVM_BUG_ON(m->guest.nr == MAX_NR_LOADSTORE_MSRS, kvm))
> +			return;
> +
>  		i = m->guest.nr++;
>  		m->guest.val[i].index = msr;
>  		vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->guest.nr);
>  	}
>  	m->guest.val[i].value = guest_val;
>  
> -	if (j < 0) {
> -		j = m->host.nr++;
> -		m->host.val[j].index = msr;
> +	i = vmx_find_loadstore_msr_slot(&m->host, msr);
> +	if (i < 0) {
> +		if (KVM_BUG_ON(m->host.nr == MAX_NR_LOADSTORE_MSRS, kvm))
> +			return;
> +
> +		i = m->host.nr++;
> +		m->host.val[i].index = msr;
>  		vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->host.nr);
>  	}
> -	m->host.val[j].value = host_val;
> +	m->host.val[i].value = host_val;
>  }
>  
>  static bool update_transition_efer(struct vcpu_vmx *vmx)

Reviewed-by: Dapeng Mi <dapeng1.mi at linux.intel.com>




From dapeng1.mi at linux.intel.com  Mon Dec  8 01:37:18 2025
From: dapeng1.mi at linux.intel.com (Mi, Dapeng)
Date: Mon, 8 Dec 2025 17:37:18 +0800
Subject: [PATCH v6 42/44] KVM: VMX: Dedup code for adding MSR to VMCS's
 auto list
In-Reply-To: <20251206001720.468579-43-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
 <20251206001720.468579-43-seanjc@google.com>
Message-ID: <3025d575-4fba-41ff-b9dc-fab4eaf87dcc@linux.intel.com>


On 12/6/2025 8:17 AM, Sean Christopherson wrote:
> Add a helper to add an MSR to a VMCS's "auto" list to deduplicate the code
> in add_atomic_switch_msr(), and so that the functionality can be used in
> the future for managing the MSR auto-store list.
>
> No functional change intended.
>
> Signed-off-by: Sean Christopherson <seanjc at google.com>
> ---
>  arch/x86/kvm/vmx/vmx.c | 41 +++++++++++++++++++----------------------
>  1 file changed, 19 insertions(+), 22 deletions(-)
>
> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> index 018e01daab68..3f64d4b1b19c 100644
> --- a/arch/x86/kvm/vmx/vmx.c
> +++ b/arch/x86/kvm/vmx/vmx.c
> @@ -1093,12 +1093,28 @@ static __always_inline void add_atomic_switch_msr_special(struct vcpu_vmx *vmx,
>  	vm_exit_controls_setbit(vmx, exit);
>  }
>  
> +static void vmx_add_auto_msr(struct vmx_msrs *m, u32 msr, u64 value,
> +			     unsigned long vmcs_count_field, struct kvm *kvm)
> +{
> +	int i;
> +
> +	i = vmx_find_loadstore_msr_slot(m, msr);
> +	if (i < 0) {
> +		if (KVM_BUG_ON(m->nr == MAX_NR_LOADSTORE_MSRS, kvm))
> +			return;
> +
> +		i = m->nr++;
> +		m->val[i].index = msr;
> +		vmcs_write32(vmcs_count_field, m->nr);
> +	}
> +	m->val[i].value = value;
> +}
> +
>  static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
>  				  u64 guest_val, u64 host_val)
>  {
>  	struct msr_autoload *m = &vmx->msr_autoload;
>  	struct kvm *kvm = vmx->vcpu.kvm;
> -	int i;
>  
>  	switch (msr) {
>  	case MSR_EFER:
> @@ -1132,27 +1148,8 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
>  		wrmsrq(MSR_IA32_PEBS_ENABLE, 0);
>  	}
>  
> -	i = vmx_find_loadstore_msr_slot(&m->guest, msr);
> -	if (i < 0) {
> -		if (KVM_BUG_ON(m->guest.nr == MAX_NR_LOADSTORE_MSRS, kvm))
> -			return;
> -
> -		i = m->guest.nr++;
> -		m->guest.val[i].index = msr;
> -		vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->guest.nr);
> -	}
> -	m->guest.val[i].value = guest_val;
> -
> -	i = vmx_find_loadstore_msr_slot(&m->host, msr);
> -	if (i < 0) {
> -		if (KVM_BUG_ON(m->host.nr == MAX_NR_LOADSTORE_MSRS, kvm))
> -			return;
> -
> -		i = m->host.nr++;
> -		m->host.val[i].index = msr;
> -		vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->host.nr);
> -	}
> -	m->host.val[i].value = host_val;
> +	vmx_add_auto_msr(&m->guest, msr, guest_val, VM_ENTRY_MSR_LOAD_COUNT, kvm);
> +	vmx_add_auto_msr(&m->guest, msr, host_val, VM_EXIT_MSR_LOAD_COUNT, kvm);
>  }
>  
>  static bool update_transition_efer(struct vcpu_vmx *vmx)

Reviewed-by: Dapeng Mi <dapeng1.mi at linux.intel.com>




From dapeng1.mi at linux.intel.com  Mon Dec  8 01:39:18 2025
From: dapeng1.mi at linux.intel.com (Mi, Dapeng)
Date: Mon, 8 Dec 2025 17:39:18 +0800
Subject: [PATCH v6 44/44] KVM: VMX: Add mediated PMU support for CPUs
 without "save perf global ctrl"
In-Reply-To: <20251206001720.468579-45-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
 <20251206001720.468579-45-seanjc@google.com>
Message-ID: <ee30ed9c-6377-4d14-b930-f0e2c809df7c@linux.intel.com>


On 12/6/2025 8:17 AM, Sean Christopherson wrote:
> Extend mediated PMU support for Intel CPUs without support for saving
> PERF_GLOBAL_CONTROL into the guest VMCS field on VM-Exit, e.g. for Skylake
> and its derivatives, as well as Icelake.  While supporting CPUs without
> VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL isn't completely trivial, it's not that
> complex either.  And not supporting such CPUs would mean not supporting 7+
> years of Intel CPUs released in the past 10 years.
>
> On VM-Exit, immediately propagate the saved PERF_GLOBAL_CTRL to the VMCS
> as well as KVM's software cache so that KVM doesn't need to add full EXREG
> tracking of PERF_GLOBAL_CTRL.  In practice, the vast majority of VM-Exits
> won't trigger software writes to guest PERF_GLOBAL_CTRL, so deferring the
> VMWRITE to the next VM-Enter would only delay the inevitable without
> batching/avoiding VMWRITEs.
>
> Note!  Take care to refresh VM_EXIT_MSR_STORE_COUNT on nested VM-Exit, as
> it's unfortunately possible that KVM could recalculate MSR intercepts
> while L2 is active, e.g. if userspace loads nested state and _then_ sets
> PERF_CAPABILITIES.  Eating the VMWRITE on every nested VM-Exit is
> unfortunate, but that's a pre-existing problem and can/should be solved
> separately, e.g. modifying the number of auto-load entries while L2 is
> active is also uncommon on modern CPUs.
>
> Signed-off-by: Sean Christopherson <seanjc at google.com>
> ---
>  arch/x86/kvm/vmx/nested.c    |  6 ++++-
>  arch/x86/kvm/vmx/pmu_intel.c |  7 -----
>  arch/x86/kvm/vmx/vmx.c       | 52 ++++++++++++++++++++++++++++++++----
>  3 files changed, 52 insertions(+), 13 deletions(-)
>
> diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
> index 614b789ecf16..1ee1edc8419d 100644
> --- a/arch/x86/kvm/vmx/nested.c
> +++ b/arch/x86/kvm/vmx/nested.c
> @@ -5142,7 +5142,11 @@ void __nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
>  
>  	kvm_nested_vmexit_handle_ibrs(vcpu);
>  
> -	/* Update any VMCS fields that might have changed while L2 ran */
> +	/*
> +	 * Update any VMCS fields that might have changed while vmcs02 was the
> +	 * active VMCS.  The tracking is per-vCPU, not per-VMCS.
> +	 */
> +	vmcs_write32(VM_EXIT_MSR_STORE_COUNT, vmx->msr_autostore.nr);
>  	vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.host.nr);
>  	vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, vmx->msr_autoload.guest.nr);
>  	vmcs_write64(TSC_OFFSET, vcpu->arch.tsc_offset);
> diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
> index 55249fa4db95..27eb76e6b6a0 100644
> --- a/arch/x86/kvm/vmx/pmu_intel.c
> +++ b/arch/x86/kvm/vmx/pmu_intel.c
> @@ -777,13 +777,6 @@ static bool intel_pmu_is_mediated_pmu_supported(struct x86_pmu_capability *host_
>  	if (WARN_ON_ONCE(!cpu_has_load_perf_global_ctrl()))
>  		return false;
>  
> -	/*
> -	 * KVM doesn't yet support mediated PMU on CPUs without support for
> -	 * saving PERF_GLOBAL_CTRL via a dedicated VMCS field.
> -	 */
> -	if (!cpu_has_save_perf_global_ctrl())
> -		return false;
> -
>  	return true;
>  }
>  
> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> index 6a17cb90eaf4..ba1262c3e3ff 100644
> --- a/arch/x86/kvm/vmx/vmx.c
> +++ b/arch/x86/kvm/vmx/vmx.c
> @@ -1204,6 +1204,17 @@ static bool update_transition_efer(struct vcpu_vmx *vmx)
>  	return true;
>  }
>  
> +static void vmx_add_autostore_msr(struct vcpu_vmx *vmx, u32 msr)
> +{
> +	vmx_add_auto_msr(&vmx->msr_autostore, msr, 0, VM_EXIT_MSR_STORE_COUNT,
> +			 vmx->vcpu.kvm);
> +}
> +
> +static void vmx_remove_autostore_msr(struct vcpu_vmx *vmx, u32 msr)
> +{
> +	vmx_remove_auto_msr(&vmx->msr_autostore, msr, VM_EXIT_MSR_STORE_COUNT);
> +}
> +
>  #ifdef CONFIG_X86_32
>  /*
>   * On 32-bit kernels, VM exits still load the FS and GS bases from the
> @@ -4225,6 +4236,8 @@ void pt_update_intercept_for_msr(struct kvm_vcpu *vcpu)
>  
>  static void vmx_recalc_pmu_msr_intercepts(struct kvm_vcpu *vcpu)
>  {
> +	u64 vm_exit_controls_bits = VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL |
> +				    VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL;
>  	bool has_mediated_pmu = kvm_vcpu_has_mediated_pmu(vcpu);
>  	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
>  	struct vcpu_vmx *vmx = to_vmx(vcpu);
> @@ -4234,12 +4247,19 @@ static void vmx_recalc_pmu_msr_intercepts(struct kvm_vcpu *vcpu)
>  	if (!enable_mediated_pmu)
>  		return;
>  
> +	if (!cpu_has_save_perf_global_ctrl()) {
> +		vm_exit_controls_bits &= ~VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL;
> +
> +		if (has_mediated_pmu)
> +			vmx_add_autostore_msr(vmx, MSR_CORE_PERF_GLOBAL_CTRL);
> +		else
> +			vmx_remove_autostore_msr(vmx, MSR_CORE_PERF_GLOBAL_CTRL);
> +	}
> +
>  	vm_entry_controls_changebit(vmx, VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL,
>  				    has_mediated_pmu);
>  
> -	vm_exit_controls_changebit(vmx, VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL |
> -					VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL,
> -				   has_mediated_pmu);
> +	vm_exit_controls_changebit(vmx, vm_exit_controls_bits, has_mediated_pmu);
>  
>  	for (i = 0; i < pmu->nr_arch_gp_counters; i++) {
>  		vmx_set_intercept_for_msr(vcpu, MSR_IA32_PERFCTR0 + i,
> @@ -7346,6 +7366,29 @@ static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx)
>  					      msrs[i].host);
>  }
>  
> +static void vmx_refresh_guest_perf_global_control(struct kvm_vcpu *vcpu)
> +{
> +	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
> +	struct vcpu_vmx *vmx = to_vmx(vcpu);
> +
> +	if (msr_write_intercepted(vmx, MSR_CORE_PERF_GLOBAL_CTRL))
> +		return;
> +
> +	if (!cpu_has_save_perf_global_ctrl()) {
> +		int slot = vmx_find_loadstore_msr_slot(&vmx->msr_autostore,
> +						       MSR_CORE_PERF_GLOBAL_CTRL);
> +
> +		if (WARN_ON_ONCE(slot < 0))
> +			return;
> +
> +		pmu->global_ctrl = vmx->msr_autostore.val[slot].value;
> +		vmcs_write64(GUEST_IA32_PERF_GLOBAL_CTRL, pmu->global_ctrl);
> +		return;
> +	}
> +
> +	pmu->global_ctrl = vmcs_read64(GUEST_IA32_PERF_GLOBAL_CTRL);
> +}
> +
>  static void vmx_update_hv_timer(struct kvm_vcpu *vcpu, bool force_immediate_exit)
>  {
>  	struct vcpu_vmx *vmx = to_vmx(vcpu);
> @@ -7631,8 +7674,7 @@ fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu, u64 run_flags)
>  
>  	vmx->loaded_vmcs->launched = 1;
>  
> -	if (!msr_write_intercepted(vmx, MSR_CORE_PERF_GLOBAL_CTRL))
> -		vcpu_to_pmu(vcpu)->global_ctrl = vmcs_read64(GUEST_IA32_PERF_GLOBAL_CTRL);
> +	vmx_refresh_guest_perf_global_control(vcpu);
>  
>  	vmx_recover_nmi_blocking(vmx);
>  	vmx_complete_interrupts(vmx);

The change looks good to me, but I still have no bandwidth to test the code
on Ice lake, I would go back after I finish the tests. Thanks.




From vulab at iscas.ac.cn  Mon Dec  8 01:42:42 2025
From: vulab at iscas.ac.cn (Wentao Liang)
Date: Mon,  8 Dec 2025 09:42:42 +0000
Subject: [PATCH] pmdomain: imx: Fix reference count leak in imx_gpc_probe()
Message-ID: <20251208094242.17821-1-vulab@iscas.ac.cn>

of_get_child_by_name() returns a node pointer with refcount incremented,
we should use of_node_put() on it when not needed anymore. Add missing
of_node_put() calls in imx_gpc_probe() to avoid reference count leak.

This commit fixes the following issues:
1. Add of_node_put(pgc_node) before returning from imx_gpc_probe()
2. Use goto pattern to consolidate error handling

Fixes: 721cabf6c660 ("soc: imx: move PGC handling to a new GPC driver")
Cc: stable at vger.kernel.org
Signed-off-by: Wentao Liang <vulab at iscas.ac.cn>
---
 drivers/pmdomain/imx/gpc.c | 31 +++++++++++++++++++++----------
 1 file changed, 21 insertions(+), 10 deletions(-)

diff --git a/drivers/pmdomain/imx/gpc.c b/drivers/pmdomain/imx/gpc.c
index f18c7e6e75dd..754c60effc8a 100644
--- a/drivers/pmdomain/imx/gpc.c
+++ b/drivers/pmdomain/imx/gpc.c
@@ -416,8 +416,10 @@ static int imx_gpc_probe(struct platform_device *pdev)
 		return 0;
 
 	base = devm_platform_ioremap_resource(pdev, 0);
-	if (IS_ERR(base))
-		return PTR_ERR(base);
+	if (IS_ERR(base)) {
+		ret = PTR_ERR(base);
+		goto err_free;
+	}
 
 	regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL, base,
 					   &imx_gpc_regmap_config);
@@ -425,7 +427,7 @@ static int imx_gpc_probe(struct platform_device *pdev)
 		ret = PTR_ERR(regmap);
 		dev_err(&pdev->dev, "failed to init regmap: %d\n",
 			ret);
-		return ret;
+		goto err_free;
 	}
 
 	/*
@@ -460,29 +462,33 @@ static int imx_gpc_probe(struct platform_device *pdev)
 		int domain_index;
 
 		ipg_clk = devm_clk_get(&pdev->dev, "ipg");
-		if (IS_ERR(ipg_clk))
-			return PTR_ERR(ipg_clk);
+		if (IS_ERR(ipg_clk)) {
+			ret = PTR_ERR(ipg_clk);
+			goto err_free;
+		}
 		ipg_rate_mhz = clk_get_rate(ipg_clk) / 1000000;
 
 		for_each_child_of_node_scoped(pgc_node, np) {
 			ret = of_property_read_u32(np, "reg", &domain_index);
 			if (ret)
-				return ret;
+				goto err_free;
 
 			if (domain_index >= of_id_data->num_domains)
 				continue;
 
 			pd_pdev = platform_device_alloc("imx-pgc-power-domain",
 							domain_index);
-			if (!pd_pdev)
-				return -ENOMEM;
+			if (!pd_pdev) {
+				ret = -ENOMEM;
+				goto err_free;
+			}
 
 			ret = platform_device_add_data(pd_pdev,
 						       &imx_gpc_domains[domain_index],
 						       sizeof(imx_gpc_domains[domain_index]));
 			if (ret) {
 				platform_device_put(pd_pdev);
-				return ret;
+				goto err_free;
 			}
 			domain = pd_pdev->dev.platform_data;
 			domain->regmap = regmap;
@@ -495,12 +501,17 @@ static int imx_gpc_probe(struct platform_device *pdev)
 			ret = platform_device_add(pd_pdev);
 			if (ret) {
 				platform_device_put(pd_pdev);
-				return ret;
+				goto err_free;
 			}
 		}
 	}
 
+	of_node_put(pgc_node);
 	return 0;
+
+err_free:
+	of_node_put(pgc_node);
+	return ret;
 }
 
 static void imx_gpc_remove(struct platform_device *pdev)
-- 
2.34.1



From linux at armlinux.org.uk  Mon Dec  8 01:47:16 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 8 Dec 2025 09:47:16 +0000
Subject: [PATCH] ARM: fix input-only operand modification in
 load_unaligned_zeropad()
In-Reply-To: <20251127025848.363992-1-pangliyuan1@huawei.com>
References: <20251127025848.363992-1-pangliyuan1@huawei.com>
Message-ID: <aTaepMnRKqCM1IJe@shell.armlinux.org.uk>

On Thu, Nov 27, 2025 at 10:58:48AM +0800, Liyuan Pang wrote:
> In the inline assembly inside load_unaligned_zeropad(), the "addr" is
> constrained as input-only operand. The compiler assumes that on exit
> from the asm statement these operands contain the same values as they
> had before executing the statement, but when kernel page fault happened,
> the assembly fixup code "bic %2 %2, #0x3" modify the value of "addr",
> which may lead to an unexpected behavior.
> 
> Use a temporary variable "tmp" to handle it, instead of modifying the
> input-only operand, just like what arm64's load_unaligned_zeropad()
> does.
> 
> Fixes: b9a50f74905a ("ARM: 7450/1: dcache: select DCACHE_WORD_ACCESS for little-endian ARMv6+ CPUs")
> 
> Co-developed-by: Xie Yuanbin <xieyuanbin1 at huawei.com>
> Signed-off-by: Xie Yuanbin <xieyuanbin1 at huawei.com>
> Signed-off-by: Liyuan Pang <pangliyuan1 at huawei.com>

Sorry, I missed this email in the deluge. This looks entirely correct.
Please submit this to the patch system. Details in the signature below.
Thanks.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From antonio.borneo at foss.st.com  Mon Dec  8 01:48:04 2025
From: antonio.borneo at foss.st.com (Antonio Borneo)
Date: Mon, 8 Dec 2025 10:48:04 +0100
Subject: [Linux-stm32] Kconfig dangling references (BZ 216748)
In-Reply-To: <5e335232-89b4-4c35-93bd-efad7e4d8995@app.fastmail.com>
References: <22b92ddf-6321-41b5-8073-f9c7064d3432@infradead.org>
	 <5e335232-89b4-4c35-93bd-efad7e4d8995@app.fastmail.com>
Message-ID: <0220ec0592b6ef8936c25cffbc6cbfa0539fb71a.camel@foss.st.com>

On Mon, 2025-12-08 at 09:55 +0100, Arnd Bergmann wrote:
> On Mon, Dec 8, 2025, at 03:04, Randy Dunlap wrote:
> > from? https://bugzilla.kernel.org/show_bug.cgi?id=216748
> > 
> > The bugzilla entry includes a Perl script and a shell script.
> > This is the edited result of running them (I removed some entries that 
> > were noise).
> > 
> > I'll try to Cc: all of the relevant mailing lists or individuals.
> > 
> > ...
> > 
> > MACH_STM32MP25 ---
> > drivers/pinctrl/stm32/Kconfig:58:???????default MACH_STM32MP25 || (ARCH_STM32 
> > && ARM64)
> 
> This was likely intended for 32-bit kernels on 64-bit STM32MP25
> chips, which we don't support. I think this can go.

Yes, I fully agree!

I have a series pinctrl stm32 to be rebased on v6.19-rc1 and I can include the
drop of MACH_STM32MP25 inside it.

Thanks,
Antonio


From benjamin.gaignard at collabora.com  Mon Dec  8 01:52:26 2025
From: benjamin.gaignard at collabora.com (Benjamin Gaignard)
Date: Mon,  8 Dec 2025 10:52:26 +0100
Subject: [PATCH] media: verisilicon: AV1: Fix enable cdef computation
Message-ID: <20251208095227.19720-1-benjamin.gaignard@collabora.com>

Testing V4L2_AV1_SEQUENCE_FLAG_ENABLE_CDEF flag isn't enough
to know if cdef bit has to be set.
If any of the used cdef fields isn't zero then we must enable
cdef feature on the hardware.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard at collabora.com>
Fixes: 727a400686a2c ("media: verisilicon: Add Rockchip AV1 decoder")
---
 .../platform/verisilicon/rockchip_vpu981_hw_av1_dec.c  | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
index e4703bb6be7c..f4f7cb45b1f1 100644
--- a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
+++ b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
@@ -1396,8 +1396,16 @@ static void rockchip_vpu981_av1_dec_set_cdef(struct hantro_ctx *ctx)
 	u16 luma_sec_strength = 0;
 	u32 chroma_pri_strength = 0;
 	u16 chroma_sec_strength = 0;
+	bool enable_cdef;
 	int i;
 
+	enable_cdef = !(cdef->bits == 0 &&
+			cdef->damping_minus_3 == 0 &&
+			cdef->y_pri_strength[0] == 0 &&
+			cdef->y_sec_strength[0] == 0 &&
+			cdef->uv_pri_strength[0] == 0 &&
+			cdef->uv_sec_strength[0] == 0);
+	hantro_reg_write(vpu, &av1_enable_cdef, enable_cdef);
 	hantro_reg_write(vpu, &av1_cdef_bits, cdef->bits);
 	hantro_reg_write(vpu, &av1_cdef_damping, cdef->damping_minus_3);
 
@@ -1953,8 +1961,6 @@ static void rockchip_vpu981_av1_dec_set_parameters(struct hantro_ctx *ctx)
 			 !!(ctrls->frame->flags & V4L2_AV1_FRAME_FLAG_SHOW_FRAME));
 	hantro_reg_write(vpu, &av1_switchable_motion_mode,
 			 !!(ctrls->frame->flags & V4L2_AV1_FRAME_FLAG_IS_MOTION_MODE_SWITCHABLE));
-	hantro_reg_write(vpu, &av1_enable_cdef,
-			 !!(ctrls->sequence->flags & V4L2_AV1_SEQUENCE_FLAG_ENABLE_CDEF));
 	hantro_reg_write(vpu, &av1_allow_masked_compound,
 			 !!(ctrls->sequence->flags
 			    & V4L2_AV1_SEQUENCE_FLAG_ENABLE_MASKED_COMPOUND));
-- 
2.43.0



From benjamin.gaignard at collabora.com  Mon Dec  8 01:52:27 2025
From: benjamin.gaignard at collabora.com (Benjamin Gaignard)
Date: Mon,  8 Dec 2025 10:52:27 +0100
Subject: [PATCH] media: verisilicon: AV1: Fix tx mode bit setting
In-Reply-To: <20251208095227.19720-1-benjamin.gaignard@collabora.com>
References: <20251208095227.19720-1-benjamin.gaignard@collabora.com>
Message-ID: <20251208095227.19720-2-benjamin.gaignard@collabora.com>

If tx_mode field is non-zero then write it value + 2 else
write 0.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard at collabora.com>
Fixes: 727a400686a2c ("media: verisilicon: Add Rockchip AV1 decoder")
---
 drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
index f4f7cb45b1f1..fccdece51b1b 100644
--- a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
+++ b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
@@ -2005,7 +2005,7 @@ static void rockchip_vpu981_av1_dec_set_parameters(struct hantro_ctx *ctx)
 			 !!(ctrls->frame->flags & V4L2_AV1_FRAME_FLAG_ALLOW_HIGH_PRECISION_MV));
 	hantro_reg_write(vpu, &av1_comp_pred_mode,
 			 (ctrls->frame->flags & V4L2_AV1_FRAME_FLAG_REFERENCE_SELECT) ? 2 : 0);
-	hantro_reg_write(vpu, &av1_transform_mode, (ctrls->frame->tx_mode == 1) ? 3 : 4);
+	hantro_reg_write(vpu, &av1_transform_mode, ctrls->frame->tx_mode ? ctrls->frame->tx_mode + 2 : 0);
 	hantro_reg_write(vpu, &av1_max_cb_size,
 			 (ctrls->sequence->flags
 			  & V4L2_AV1_SEQUENCE_FLAG_USE_128X128_SUPERBLOCK) ? 7 : 6);
-- 
2.43.0



From linux at armlinux.org.uk  Mon Dec  8 02:07:25 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 8 Dec 2025 10:07:25 +0000
Subject: [Bug report] hash_name() may cross page boundary and trigger
 sleep in RCU context
In-Reply-To: <20251208023206.44238-1-xieyuanbin1@huawei.com>
References: <aTLLLuup7TeAqFVL@shell.armlinux.org.uk>
 <20251208023206.44238-1-xieyuanbin1@huawei.com>
Message-ID: <aTajXdAVYh9qJI6B@shell.armlinux.org.uk>

On Mon, Dec 08, 2025 at 10:32:06AM +0800, Xie Yuanbin wrote:
> On Fri, 5 Dec 2025 12:08:14 +0000, Russell King wrote:
> > Right, let's split these issues into separate patches. Please test this
> > patch, which should address only the hash_name() fault issue, and
> > provides the basis for fixing the branch predictor issue.
> 
> I conducted a simple test, and it seems that both the hash_name()
> might sleep issue and the branch predictor issue have been fixed.

This isn't entirely fixed. A data abort for an alignment fault (thus
calling do_alignment()) will enable interrupts, and then may call
do_bad_area(). We can't short-circuit this path like we can with
do_page_fault() as alignment faults from userspace can be valid for
the vectors page - not that we should see them, but that doesn't mean
that there isn't something in userspace that does.

> BTW, even with this patch, test cases may still fail. There is another
> bug in hash_name() will also be triggered by the testcase, which will be
> fixed in this patch:
> Link: https://lore.kernel.org/20251127025848.363992-1-pangliyuan1 at huawei.com

That patch got missed - I'm notoriously bad at catching every email.
There's just way too much email coming in.

> Test case is from:
> Link: https://lore.kernel.org/20251127140109.191657-1-xieyuanbin1 at huawei.com
> 
> Test in commit 6987d58a9cbc5bd57c98 ("Add linux-next specific files for
> 20251205") from linux-next branch.
> 
> I still have a question about this patch: Is 
> ```patch
> +		if (interrupts_enabled(regs))
> +			local_irq_enable();
> ```
> necessary? Although this implementation is closer to the original code,
> which can reduce side effects, do_bad_area(), do_sect_fault(),
> and do_translation_fault() all call __do_kernel_fault() with interrupts
> disabled.

It's to keep the behaviour closer to the original as possible, on the
principle of avoiding unnecessary behavioural changes to the code. As
noted above, do_bad_area() can be called with interrupts enabled.

Whether RT folk would be happy removing that is a different question,
given that they want as much of the kernel to be preemptable.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From pierre.gondois at arm.com  Mon Dec  8 02:08:28 2025
From: pierre.gondois at arm.com (Pierre Gondois)
Date: Mon, 8 Dec 2025 11:08:28 +0100
Subject: [PATCH v4 3/3] cpufreq: CPPC: Update FIE arch_freq_scale in ticks
 for non-PCC regs
In-Reply-To: <20251203032422.3232957-4-zhanjie9@hisilicon.com>
References: <20251203032422.3232957-1-zhanjie9@hisilicon.com>
 <20251203032422.3232957-4-zhanjie9@hisilicon.com>
Message-ID: <270216de-e7d1-4552-a04f-8b0fd7b79552@arm.com>

Hello Jie Zhan,


On 12/3/25 04:24, Jie Zhan wrote:
> Currently, the CPPC Frequency Invariance Engine (FIE) is invoked from the
> scheduler tick but defers the update of arch_freq_scale to a separate
> thread because cppc_get_perf_ctrs() would sleep if the CPC regs are in PCC.
>
> However, this deferred update mechanism is unnecessary and introduces extra
> overhead for non-PCC register spaces (e.g. System Memory or FFH), where
> accessing the regs won't sleep and can be safely performed from the tick
> context.
>
> Furthermore, with the CPPC FIE registered, it throws repeated warnings of
> "cppc_scale_freq_workfn: failed to read perf counters" on our platform with
> the CPC regs in System Memory and a power-down idle state enabled.  That's
> because the remote CPU can be in a power-down idle state, and reading its
> perf counters returns 0.  Moving the FIE handling back to the scheduler
> tick process makes the CPU handle its own perf counters, so it won't be
> idle and the issue would be inherently solved.
>
> To address the above issues, update arch_freq_scale directly in ticks for
> non-PCC regs and keep the deferred update mechanism for PCC regs.
>
> Signed-off-by: Jie Zhan<zhanjie9 at hisilicon.com>
> ---
>   drivers/cpufreq/cppc_cpufreq.c | 77 +++++++++++++++++++++++-----------
>   1 file changed, 52 insertions(+), 25 deletions(-)
>
> diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
> index 947b4e2e1d4e..36e8a75a37f1 100644
> --- a/drivers/cpufreq/cppc_cpufreq.c
> +++ b/drivers/cpufreq/cppc_cpufreq.c
[...]
> @@ -236,10 +265,8 @@ static void __init cppc_freq_invariance_init(void)
>   
>   static void cppc_freq_invariance_exit(void)
>   {
> -	if (fie_disabled)
> -		return;
> -
> -	kthread_destroy_worker(kworker_fie);
> +	if (kworker_fie)
> +		kthread_destroy_worker(kworker_fie);

Shouldn't we have:
 ? kworker_fie = NULL;
here aswell ?

>   }
>   
>   #else


Otherwise, for the 3 patches:

Reviewed-by: Pierre Gondois <pierre.gondois at arm.com>



From robert.marko at sartura.hr  Mon Dec  8 02:30:28 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Mon, 8 Dec 2025 11:30:28 +0100
Subject: [PATCH 2/4] dt-bindings: arm: Document Microchip LAN969x
In-Reply-To: <20251203-duly-leotard-86b83bd840c6@spud>
References: <20251203122313.1287950-1-robert.marko@sartura.hr>
 <20251203122313.1287950-2-robert.marko@sartura.hr> <20251203-duly-leotard-86b83bd840c6@spud>
Message-ID: <CA+HBbNH6wO2VWOp1Dn52ArrYg6z89FgYnT3x-jsHsTVJ5xSBSA@mail.gmail.com>

On Wed, Dec 3, 2025 at 8:19?PM Conor Dooley <conor at kernel.org> wrote:
>
> On Wed, Dec 03, 2025 at 01:21:30PM +0100, Robert Marko wrote:
> > Microchip LAN969x is a series of multi-port, multi-gigabit switches based
> > on ARMv8 Cortex-A53 CPU.
> >
> > Signed-off-by: Robert Marko <robert.marko at sartura.hr>
> > ---
> >  .../bindings/arm/microchip,lan969x.yaml       | 32 +++++++++++++++++++
>
> This should not be in a unique file, put it in with the other microchip
> arm devices please. Also, the wildcard in the compatible is not
> permitted, only way it'd make sense is if these are different binnings
> of the same silicon. If that's the case, you need to explain why,
> because compatibles are meant to be soc-specific.

Hi Conor,
The issue is that there is no unique place for Microchip SoC-s,
LAN966x series is in the AT91 bindings
while SparX-5 has its own bindings file.

What would you suggest in this case?

As for the wildcard, I understand, will get rid of it in v2.

Regards,
Robert

>
> pw-bot: changes-requested
>
> >  1 file changed, 32 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/arm/microchip,lan969x.yaml
> >
> > diff --git a/Documentation/devicetree/bindings/arm/microchip,lan969x.yaml b/Documentation/devicetree/bindings/arm/microchip,lan969x.yaml
> > new file mode 100644
> > index 000000000000..3fa1d4ed40d1
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/arm/microchip,lan969x.yaml
> > @@ -0,0 +1,32 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/arm/microchip,lan969x.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Microchip LAN969x Boards
> > +
> > +maintainers:
> > +  - Robert Marko <robert.marko at sartura.hr>
> > +
> > +description: |+
> > +   The Microchip LAN969x SoC is a ARMv8-based used in a family of
> > +   multi-port, multi-gigabit switches.
> > +
> > +properties:
> > +  $nodename:
> > +    const: '/'
> > +  compatible:
> > +    oneOf:
> > +      - description: The LAN969x EVB (EV23X71A) is a 24x 1G + 4x 10G
> > +          Ethernet development system board.
> > +        items:
> > +          - const: microchip,ev23x71a
> > +          - const: microchip,lan969x
> > +
> > +required:
> > +  - compatible
> > +
> > +additionalProperties: true
> > +
> > +...
> > --
> > 2.52.0
> >



-- 
Robert Marko
Staff Embedded Linux Engineer
Sartura d.d.
Lendavska ulica 16a
10000 Zagreb, Croatia
Email: robert.marko at sartura.hr
Web: www.sartura.hr


From borntraeger at linux.ibm.com  Mon Dec  8 02:32:27 2025
From: borntraeger at linux.ibm.com (Christian Borntraeger)
Date: Mon, 8 Dec 2025 11:32:27 +0100
Subject: [PATCH] KVM: Remove subtle "struct kvm_stats_desc" pseudo-overlay
In-Reply-To: <20251205232655.445294-1-seanjc@google.com>
References: <20251205232655.445294-1-seanjc@google.com>
Message-ID: <8f1c1b9e-2743-4326-9a6f-754885ae90f4@linux.ibm.com>

Am 06.12.25 um 00:26 schrieb Sean Christopherson:
> Remove KVM's internal pseudo-overlay of kvm_stats_desc, which subtly
> aliases the flexible name[] in the uAPI definition with a fixed-size array
> of the same name.  The unusual embedded structure results in compiler
> warnings due to -Wflex-array-member-not-at-end, and also necessitates an
> extra level of dereferencing in KVM.  To avoid the "overlay", define the
> uAPI structure to have a fixed-size name when building for the kernel.
> 
> Opportunistically clean up the indentation for the stats macros, and
> replace spaces with tabs.
> 
> No functional change intended.
> 
> Reported-by: Gustavo A. R. Silva <gustavoars at kernel.org>
> Closes: https://lore.kernel.org/all/aPfNKRpLfhmhYqfP at kspp
> Signed-off-by: Sean Christopherson <seanjc at google.com>

Acked-by: Christian Borntraeger <borntraeger at linux.ibm.com>
[..]

> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -14,6 +14,10 @@
>   #include <linux/ioctl.h>
>   #include <asm/kvm.h>
>   
> +#ifdef __KERNEL__
> +#include <linux/kvm_types.h>
> +#endif
> +
>   #define KVM_API_VERSION 12
>   
>   /*
> @@ -1579,7 +1583,11 @@ struct kvm_stats_desc {
>   	__u16 size;
>   	__u32 offset;
>   	__u32 bucket_size;
> +#ifdef __KERNEL__
> +	char name[KVM_STATS_NAME_SIZE];
> +#else
>   	char name[];
> +#endif
>   };

Not sure if we need a comment here or not. Maybe git blame is good enough.


From daniel at riscstar.com  Mon Dec  8 02:35:55 2025
From: daniel at riscstar.com (Daniel Thompson)
Date: Mon, 8 Dec 2025 10:35:55 +0000
Subject: [PATCH v6 2/4] backlight: add max25014atg backlight
In-Reply-To: <8a9a59b8-d5c0-46b3-8f86-a4cd910b7af3@gocontroll.com>
References: <20251201-max25014-v6-0-88e3ac8112ff@gocontroll.com>
 <20251201-max25014-v6-2-88e3ac8112ff@gocontroll.com>
 <aTG0EK_zuSB-U_bb@aspen.lan>
 <8a9a59b8-d5c0-46b3-8f86-a4cd910b7af3@gocontroll.com>
Message-ID: <aTaqCxsGj_waN92Y@aspen.lan>

On Fri, Dec 05, 2025 at 04:20:55PM +0100, Maud Spierings wrote:
> Thanks for the review.
>
> On 12/4/25 17:17, Daniel Thompson wrote:
> > On Mon, Dec 01, 2025 at 12:53:21PM +0100, Maud Spierings via B4 Relay wrote:
> > > The Maxim MAX25014 is a 4-channel automotive grade backlight driver IC
> > > with integrated boost controller.
> > >
> > > Signed-off-by: Maud Spierings <maudspierings at gocontroll.com>
>
> <snip>
>
> > > +static int max25014_update_status(struct backlight_device *bl_dev)
> > > +{
> > > +	struct max25014 *maxim = bl_get_data(bl_dev);
> > > +	uint32_t reg;
> > > +	int ret;
> > > +
> > > +	if (backlight_is_blank(maxim->bl))
> > > +		bl_dev->props.brightness = 0;
> >
> > This isn't right. Why would you change the backlight level just because
> > it is currently blanked (and sorry I missed this one last time).
>
> so just remove this bit then jeah?

Yes. backlight_get_brightness() is all you should need.


> > > +
> > > +	reg  = TON_STEP * bl_dev->props.brightness;
> >
> > The correct way to honour blanking is just go call
> > backlight_get_brightness() instead of reading the property directly.
>
> will do.

Thanks.


Daniel.


From maz at kernel.org  Mon Dec  8 02:42:15 2025
From: maz at kernel.org (Marc Zyngier)
Date: Mon, 08 Dec 2025 10:42:15 +0000
Subject: [PATCH] KVM: Remove subtle "struct kvm_stats_desc" pseudo-overlay
In-Reply-To: <20251205232655.445294-1-seanjc@google.com>
References: <20251205232655.445294-1-seanjc@google.com>
Message-ID: <865xahp854.wl-maz@kernel.org>

On Fri, 05 Dec 2025 23:26:55 +0000,
Sean Christopherson <seanjc at google.com> wrote:
> 
> Remove KVM's internal pseudo-overlay of kvm_stats_desc, which subtly
> aliases the flexible name[] in the uAPI definition with a fixed-size array
> of the same name.  The unusual embedded structure results in compiler
> warnings due to -Wflex-array-member-not-at-end, and also necessitates an
> extra level of dereferencing in KVM.  To avoid the "overlay", define the
> uAPI structure to have a fixed-size name when building for the kernel.
> 
> Opportunistically clean up the indentation for the stats macros, and
> replace spaces with tabs.
> 
> No functional change intended.
> 
> Reported-by: Gustavo A. R. Silva <gustavoars at kernel.org>
> Closes: https://lore.kernel.org/all/aPfNKRpLfhmhYqfP at kspp
> Signed-off-by: Sean Christopherson <seanjc at google.com>

Acked-by: Marc Zyngier <maz at kernel.org>

	M.

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


From mripard at kernel.org  Mon Dec  8 03:06:10 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Mon, 08 Dec 2025 11:06:10 +0000
Subject: [PATCH 0/4] drm: Revert and fix enable/disable sequence
In-Reply-To: <20251205-drm-seq-fix-v1-0-fda68fa1b3de@ideasonboard.com>
References: <20251205-drm-seq-fix-v1-0-fda68fa1b3de@ideasonboard.com>
Message-ID: <b2cd921b3682355b0c64d107f1dae998@kernel.org>

On Fri, 5 Dec 2025 11:51:47 +0200, Tomi Valkeinen wrote:
> Changing the enable/disable sequence in commit c9b1150a68d9
> ("drm/atomic-helper: Re-order bridge chain pre-enable and post-disable")
> has caused regressions on multiple platforms: R-Car, MCDE, Rockchip.
> 
> This is an alternate series to Linus' series:
> 
> [ ... ]

Reviewed-by: Maxime Ripard <mripard at kernel.org>

Thanks!
Maxime


From aradhya.bhatia at linux.dev  Mon Dec  8 03:23:17 2025
From: aradhya.bhatia at linux.dev (Aradhya Bhatia)
Date: Mon, 8 Dec 2025 11:23:17 +0000
Subject: [PATCH 1/4] Revert "drm/atomic-helper: Re-order bridge chain
 pre-enable and post-disable"
In-Reply-To: <20251205-drm-seq-fix-v1-1-fda68fa1b3de@ideasonboard.com>
References: <20251205-drm-seq-fix-v1-0-fda68fa1b3de@ideasonboard.com>
 <20251205-drm-seq-fix-v1-1-fda68fa1b3de@ideasonboard.com>
Message-ID: <6af17c1e-32fc-478a-8493-6c754c3020f0@linux.dev>

Hi Tomi,

Thank you for posting this series.

It makes sense to change the order in tidss _commit_tail(), than to
undo the order changes in the regressed drivers.

On 05/12/2025 09:51, Tomi Valkeinen wrote:
> This reverts commit c9b1150a68d9362a0827609fc0dc1664c0d8bfe1.
> 
> Changing the enable/disable sequence has caused regressions on multiple
> platforms: R-Car, MCDE, Rockchip. A series (see link below)  was sent to
> fix these, but it was decided that it's better to revert the original
> patch and change the enable/disable sequence only in the tidss driver.
> 
> Reverting this commit breaks tidss's DSI and OLDI outputs, which will be
> fixed in the following commits.
> 
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
> Link: https://lore.kernel.org/all/20251202-mcde-drm-regression-thirdfix-v6-0-f1bffd4ec0fa%40kernel.org/
> Fixes: c9b1150a68d9 ("drm/atomic-helper: Re-order bridge chain pre-enable and post-disable")
> Cc: stable at vger.kernel.org # v6.17+
> ---
>  drivers/gpu/drm/drm_atomic_helper.c |   8 +-
>  include/drm/drm_bridge.h            | 249 ++++++++++--------------------------
>  2 files changed, 70 insertions(+), 187 deletions(-)
> 

Reviewed-by: Aradhya Bhatia <aradhya.bhatia at linux.dev>



From aradhya.bhatia at linux.dev  Mon Dec  8 03:24:51 2025
From: aradhya.bhatia at linux.dev (Aradhya Bhatia)
Date: Mon, 8 Dec 2025 11:24:51 +0000
Subject: [PATCH 3/4] drm/atomic-helper: Export and namespace some
 functions
In-Reply-To: <20251205-drm-seq-fix-v1-3-fda68fa1b3de@ideasonboard.com>
References: <20251205-drm-seq-fix-v1-0-fda68fa1b3de@ideasonboard.com>
 <20251205-drm-seq-fix-v1-3-fda68fa1b3de@ideasonboard.com>
Message-ID: <e245ff67-1d71-48a0-bec4-f30056ef2e19@linux.dev>



On 05/12/2025 09:51, Tomi Valkeinen wrote:
> From: Linus Walleij <linusw at kernel.org>
> 
> Export and namespace those not prefixed with drm_* so
> it becomes possible to write custom commit tail functions
> in individual drivers using the helper infrastructure.
> 
> Tested-by: Marek Vasut <marek.vasut+renesas at mailbox.org>
> Reviewed-by: Maxime Ripard <mripard at kernel.org>
> Signed-off-by: Linus Walleij <linusw at kernel.org>
> [Tomi: Resolved conflicts, fixed indentation]
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
> Cc: stable at vger.kernel.org # v6.17+
> ---
>  drivers/gpu/drm/drm_atomic_helper.c | 122 +++++++++++++++++++++++++++++-------
>  include/drm/drm_atomic_helper.h     |  22 +++++++
>  2 files changed, 121 insertions(+), 23 deletions(-)
> 

Reviewed-by: Aradhya Bhatia <aradhya.bhatia at linux.dev>



From aradhya.bhatia at linux.dev  Mon Dec  8 03:26:54 2025
From: aradhya.bhatia at linux.dev (Aradhya Bhatia)
Date: Mon, 8 Dec 2025 11:26:54 +0000
Subject: [PATCH 4/4] drm/tidss: Fix enable/disable order
In-Reply-To: <20251205-drm-seq-fix-v1-4-fda68fa1b3de@ideasonboard.com>
References: <20251205-drm-seq-fix-v1-0-fda68fa1b3de@ideasonboard.com>
 <20251205-drm-seq-fix-v1-4-fda68fa1b3de@ideasonboard.com>
Message-ID: <3f2aee2b-578a-4d82-8dac-14cb9f2ada05@linux.dev>



On 05/12/2025 09:51, Tomi Valkeinen wrote:
> TI's OLDI and DSI encoders need to be set up before the crtc is enabled,
> but the DRM helpers will enable the crtc first. This causes various
> issues on TI platforms, like visual artifacts or crtc sync lost
> warnings.
> 
> Thus drm_atomic_helper_commit_modeset_enables() and
> drm_atomic_helper_commit_modeset_disables() cannot be used, as they
> enable the crtc before bridges' pre-enable, and disable the crtc after
> bridges' post-disable.
> 
> Open code the drm_atomic_helper_commit_modeset_enables() and
> drm_atomic_helper_commit_modeset_disables(), and first call the bridges'
> pre-enables, then crtc enable, then bridges' post-enable (and vice versa
> for disable).
> 
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
> Cc: stable at vger.kernel.org # v6.17+
> ---
>  drivers/gpu/drm/tidss/tidss_kms.c | 30 +++++++++++++++++++++++++++---
>  1 file changed, 27 insertions(+), 3 deletions(-)
> 

Reviewed-by: Aradhya Bhatia <aradhya.bhatia at linux.dev>


From cuiyunhui at bytedance.com  Mon Dec  8 03:40:39 2025
From: cuiyunhui at bytedance.com (yunhui cui)
Date: Mon, 8 Dec 2025 19:40:39 +0800
Subject: [External] Re: [PATCH v3 5/8] riscv: smp: use NMI for CPU stop
In-Reply-To: <DEPGLFUVHA0O.XSZVD2T1ENLD@ventanamicro.com>
References: <20251127125305.89961-1-cuiyunhui@bytedance.com>
 <20251127125305.89961-6-cuiyunhui@bytedance.com> <DEP4X1DAIOU5.2WLIV4BMWLMRR@ventanamicro.com>
 <CAEEQ3wmAn=9w=fR=OMTMF17_tAcEnsdJWL_w8fw-3wA-Bfi6xw@mail.gmail.com> <DEPGLFUVHA0O.XSZVD2T1ENLD@ventanamicro.com>
Message-ID: <CAEEQ3wngwxjiytt7g6XY0bC1PL4A1NEmirML7FiqXMA4_K0irw@mail.gmail.com>

Hi Radim,

On Thu, Dec 4, 2025 at 9:16?PM Radim Kr?m?? <rkrcmar at ventanamicro.com> wrote:
>
> 2025-12-04T13:28:45+08:00, yunhui cui <cuiyunhui at bytedance.com>:
> > Hi Radim,
> >
> > On Thu, Dec 4, 2025 at 12:07?PM Radim Kr?m?? <rkrcmar at ventanamicro.com> wrote:
> >>
> >> 2025-11-27T20:53:02+08:00, Yunhui Cui <cuiyunhui at bytedance.com>:
> >> > Use NMI instead of IPI for CPU stop if RISC-V SSE NMI is supported.
> >> >
> >> > Signed-off-by: Yunhui Cui <cuiyunhui at bytedance.com>
> >> > ---
> >> > diff --git a/drivers/firmware/riscv/riscv_sse_nmi.c b/drivers/firmware/riscv/riscv_sse_nmi.c
> >> > @@ -58,6 +58,7 @@ static int local_nmi_handler(u32 evt, void *arg, struct pt_regs *regs)
> >> >       type = atomic_read(this_cpu_ptr(&local_nmi));
> >> >
> >> >       NMI_HANDLE(LOCAL_NMI_CRASH, cpu_crash_stop, cpu, regs);
> >> > +     NMI_HANDLE(LOCAL_NMI_STOP, cpu_stop);
> >>
> >> Please document the intended preemption design for all SSE events,
> >> because it will be a nightmare if we forget some assumptions in the
> >> coming years.  (That includes the relative priorities of RAS/PMU/...)
> >
> > Actually, LOCAL_NMI_CRASH, LOCAL_NMI_STOP, LOCAL_NMI_BACKTRACE,
> > LOCAL_NMI_KGDB, ... are all implemented via the single SSE event
> > SBI_SSE_EVENT_LOCAL_SOFTWARE_INJECTED. Per the SSE design, no
> > preemption will occur among CRASH, STOP, BACKTRACE, and KGDB events.
>
> That is how it is.  I don't understand why it must be like that.
>
> For example: PMU_OVERFLOW has lower event_id than SOFTWARE_INJECTED, so
> it will currently interrupt NMI_CRASH as they both have priority 0,
> although NMI_CRASH probably shouldn't be masked by anything, and should
> preempt everything.
> NMI_BACKTRACE, on the other hand, probably shouldn't have that high
> priority as there seem more important events (e.g. RAS and NMI_CRASH).
>
> The issues can be avoided by event priorities, masking, or deemed as
> non-issue, but I think it would be beneficial to provide some reasoning
> behind the design, as the choices don't seem obvious to me.

Indeed, it is necessary to consider the priority among different
events. Should different priorities also be assigned to NMI_CRASH,
NMI_BACKTRACE, NMI_STOP, and NMI_KGDB? Do these operations need to be
visible to the BIOS? Could you kindly provide some good suggestions?

>
> Thanks.

Thanks,
Yunhui


From peterz at infradead.org  Mon Dec  8 03:51:56 2025
From: peterz at infradead.org (Peter Zijlstra)
Date: Mon, 8 Dec 2025 12:51:56 +0100
Subject: [PATCH v6 04/44] perf: Add APIs to create/release mediated guest
 vPMUs
In-Reply-To: <20251206001720.468579-5-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
 <20251206001720.468579-5-seanjc@google.com>
Message-ID: <20251208115156.GE3707891@noisy.programming.kicks-ass.net>

On Fri, Dec 05, 2025 at 04:16:40PM -0800, Sean Christopherson wrote:

> +static atomic_t nr_include_guest_events __read_mostly;
> +
> +static atomic_t nr_mediated_pmu_vms __read_mostly;
> +static DEFINE_MUTEX(perf_mediated_pmu_mutex);

> +static int mediated_pmu_account_event(struct perf_event *event)
> +{
> +	if (!is_include_guest_event(event))
> +		return 0;
> +
> +	guard(mutex)(&perf_mediated_pmu_mutex);
> +
> +	if (atomic_read(&nr_mediated_pmu_vms))
> +		return -EOPNOTSUPP;
> +
> +	atomic_inc(&nr_include_guest_events);
> +	return 0;
> +}
> +
> +static void mediated_pmu_unaccount_event(struct perf_event *event)
> +{
> +	if (!is_include_guest_event(event))
> +		return;
> +
> +	atomic_dec(&nr_include_guest_events);
> +}

> +int perf_create_mediated_pmu(void)
> +{
> +	guard(mutex)(&perf_mediated_pmu_mutex);
> +	if (atomic_inc_not_zero(&nr_mediated_pmu_vms))
> +		return 0;
> +
> +	if (atomic_read(&nr_include_guest_events))
> +		return -EBUSY;
> +
> +	atomic_inc(&nr_mediated_pmu_vms);
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(perf_create_mediated_pmu);
> +
> +void perf_release_mediated_pmu(void)
> +{
> +	if (WARN_ON_ONCE(!atomic_read(&nr_mediated_pmu_vms)))
> +		return;
> +
> +	atomic_dec(&nr_mediated_pmu_vms);
> +}
> +EXPORT_SYMBOL_GPL(perf_release_mediated_pmu);

These two things are supposed to be symmetric, but are implemented
differently; what gives?

That is, should not both have the general shape:

	if (atomic_inc_not_zero(&A))
		return 0;

	guard(mutex)(&lock);

	if (atomic_read(&B))
		return -EBUSY;

	atomic_inc(&A);
	return 0;

Similarly, I would imagine both release variants to have the underflow
warn on like:

	if (WARN_ON_ONCE(!atomic_read(&A)))
		return;

	atomic_dec(&A);

Hmm?

Also, EXPORT_SYMBOL_FOR_KVM() ?

I can make these edits when applying, if/when we get to applying. Let me
continue reading.



From linux at armlinux.org.uk  Mon Dec  8 04:34:27 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 8 Dec 2025 12:34:27 +0000
Subject: [PATCH 0/3] ARM: fix hash_name() and branch predictor issues
Message-ID: <aTbF009476Iufory@shell.armlinux.org.uk>

This series, which I'm intending to be part of my upcoming pull request
for this merge window (note - will be sent before Thursday, otherwise
it won't be until maybe the middle of January) fixes the recently
reported hash_name() issue, and also the long standing branch predictor
hardening smp_processor_id() warning which occurs due to interrupts
being enabled.

Fixing this isn't trivial because there are many paths through
do_page_fault() which are non-obvious.

For example, we detect page faults by the kernel attempting to execute
memory that it shouldn't and print such a warning. If we introduce an
early address check, we avoid that detection, making it become a
plain kernel oops without the informative error message.

The first patch adds an additional check in __do_kernel_fault() to
detect this condition. This patch is a non-obvious dependency for the
next patch.

The second patch handles faults above the top of userspace entirely
separately, meaning we have a simpler and more obvious fault path,
which avoids any possibility of taking any MM mutexes, which is the
cause of the hash_name() problem.

The third patch moves harden_branch_predictor() out of
__do_user_fault() and to appropriate places in the parent functions.
The reason this has been avoided thus far is because do_page_fault()
can be a hot path (since it's used for page aging as well) but with
kernel address faults being handled by an entirely separate path,
this avoids adding to that overhead.

I would like to get some attributations for this - specifically
tested-by.

Thanks.

 arch/arm/mm/alignment.c |  6 +++-
 arch/arm/mm/fault.c     | 74 +++++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 67 insertions(+), 13 deletions(-)

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From rmk+kernel at armlinux.org.uk  Mon Dec  8 04:34:54 2025
From: rmk+kernel at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 08 Dec 2025 12:34:54 +0000
Subject: [PATCH 1/3] ARM: allow __do_kernel_fault() to report execution of
 memory faults
In-Reply-To: <aTbF009476Iufory@shell.armlinux.org.uk>
References: <aTbF009476Iufory@shell.armlinux.org.uk>
Message-ID: <E1vSaS6-00000000Ni7-1FDb@rmk-PC.armlinux.org.uk>

Allow __do_kernel_fault() to detect the execution of memory, so we can
provide the same fault message as do_page_fault() would do. This is
required when we split the kernel address fault handling from the
main do_page_fault() code path.

Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
---
 arch/arm/mm/fault.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 2bc828a1940c..f0884bf91dfa 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -162,6 +162,8 @@ __do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
 	 */
 	if (addr < PAGE_SIZE) {
 		msg = "NULL pointer dereference";
+	} else if (is_permission_fault(fsr) && fsr & FSR_LNX_PF) {
+		msg = "execution of memory";
 	} else {
 		if (is_translation_fault(fsr) &&
 		    kfence_handle_page_fault(addr, is_write_fault(fsr), regs))
-- 
2.47.3



From rmk+kernel at armlinux.org.uk  Mon Dec  8 04:34:59 2025
From: rmk+kernel at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 08 Dec 2025 12:34:59 +0000
Subject: [PATCH 2/3] ARM: fix hash_name() fault
In-Reply-To: <aTbF009476Iufory@shell.armlinux.org.uk>
References: <aTbF009476Iufory@shell.armlinux.org.uk>
Message-ID: <E1vSaSB-00000000NiD-1mnP@rmk-PC.armlinux.org.uk>

Zizhi Wo reports:

"During the execution of hash_name()->load_unaligned_zeropad(), a
 potential memory access beyond the PAGE boundary may occur. For
 example, when the filename length is near the PAGE_SIZE boundary.
 This triggers a page fault, which leads to a call to
 do_page_fault()->mmap_read_trylock(). If we can't acquire the lock,
 we have to fall back to the mmap_read_lock() path, which calls
 might_sleep(). This breaks RCU semantics because path lookup occurs
 under an RCU read-side critical section."

This is seen with CONFIG_DEBUG_ATOMIC_SLEEP=y and CONFIG_KFENCE=y.

Kernel addresses (with the exception of the vectors/kuser helper
page) do not have VMAs associated with them. If the vectors/kuser
helper page faults, then there are two possibilities:

1. if the fault happened while in kernel mode, then we're basically
   dead, because the CPU won't be able to vector through this page
   to handle the fault.
2. if the fault happened while in user mode, that means the page was
   protected from user access, and we want to fault anyway.

Thus, we can handle kernel addresses from any context entirely
separately without going anywhere near the mmap lock. This gives us
an entirely non-sleeping path for all kernel mode kernel address
faults.

As we handle the kernel address faults before interrupts are enabled,
this change has the side effect of improving the branch predictor
hardening, but does not completely solve the issue.

Reported-by: Zizhi Wo <wozizhi at huaweicloud.com>
Reported-by: Xie Yuanbin <xieyuanbin1 at huawei.com>
Link: https://lore.kernel.org/r/20251126090505.3057219-1-wozizhi at huaweicloud.com
Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
---
 arch/arm/mm/fault.c | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index f0884bf91dfa..92fc70b56d72 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -261,6 +261,35 @@ static inline bool ttbr0_usermode_access_allowed(struct pt_regs *regs)
 }
 #endif
 
+static int __kprobes
+do_kernel_address_page_fault(struct mm_struct *mm, unsigned long addr,
+			     unsigned int fsr, struct pt_regs *regs)
+{
+	if (user_mode(regs)) {
+		/*
+		 * Fault from user mode for a kernel space address. User mode
+		 * should not be faulting in kernel space, which includes the
+		 * vector/khelper page. Send a SIGSEGV.
+		 */
+		__do_user_fault(addr, fsr, SIGSEGV, SEGV_MAPERR, regs);
+	} else {
+		/*
+		 * Fault from kernel mode. Enable interrupts if they were
+		 * enabled in the parent context. Section (upper page table)
+		 * translation faults are handled via do_translation_fault(),
+		 * so we will only get here for a non-present kernel space
+		 * PTE or PTE permission fault. This may happen in exceptional
+		 * circumstances and need the fixup tables to be walked.
+		 */
+		if (interrupts_enabled(regs))
+			local_irq_enable();
+
+		__do_kernel_fault(mm, addr, fsr, regs);
+	}
+
+	return 0;
+}
+
 static int __kprobes
 do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 {
@@ -274,6 +303,12 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 	if (kprobe_page_fault(regs, fsr))
 		return 0;
 
+	/*
+	 * Handle kernel addresses faults separately, which avoids touching
+	 * the mmap lock from contexts that are not able to sleep.
+	 */
+	if (addr >= TASK_SIZE)
+		return do_kernel_address_page_fault(mm, addr, fsr, regs);
 
 	/* Enable interrupts if they were enabled in the parent context. */
 	if (interrupts_enabled(regs))
-- 
2.47.3



From rmk+kernel at armlinux.org.uk  Mon Dec  8 04:35:04 2025
From: rmk+kernel at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 08 Dec 2025 12:35:04 +0000
Subject: [PATCH 3/3] ARM: fix branch predictor hardening
In-Reply-To: <aTbF009476Iufory@shell.armlinux.org.uk>
References: <aTbF009476Iufory@shell.armlinux.org.uk>
Message-ID: <E1vSaSG-00000000NiJ-2bRP@rmk-PC.armlinux.org.uk>

__do_user_fault() may be called with indeterminent interrupt enable
state, which means we may be preemptive at this point. This causes
problems when calling harden_branch_predictor(). For example, when
called from a data abort, do_alignment_fault()->do_bad_area().

Move harden_branch_predictor() out of __do_user_fault() and into the
calling contexts.

Moving it into do_kernel_address_page_fault(), we can be sure that
interrupts will be disabled here.

Converting do_translation_fault() to use do_kernel_address_page_fault()
rather than do_bad_area() means that we keep branch predictor handling
for translation faults. Interrupts will also be disabled at this call
site.

do_sect_fault() needs special handling, so detect user mode accesses
to kernel-addresses, and add an explicit call to branch predictor
hardening.

Finally, add branch predictor hardening to do_alignment() for the
faulting case (user mode accessing kernel addresses) before interrupts
are enabled.

This should cover all cases where harden_branch_predictor() is called,
ensuring that it is always has interrupts disabled, also ensuring that
it is called early in each call path.

Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
---
 arch/arm/mm/alignment.c |  6 +++++-
 arch/arm/mm/fault.c     | 39 ++++++++++++++++++++++++++-------------
 2 files changed, 31 insertions(+), 14 deletions(-)

diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
index 3c6ddb1afdc4..812380f30ae3 100644
--- a/arch/arm/mm/alignment.c
+++ b/arch/arm/mm/alignment.c
@@ -19,10 +19,11 @@
 #include <linux/init.h>
 #include <linux/sched/signal.h>
 #include <linux/uaccess.h>
+#include <linux/unaligned.h>
 
 #include <asm/cp15.h>
 #include <asm/system_info.h>
-#include <linux/unaligned.h>
+#include <asm/system_misc.h>
 #include <asm/opcodes.h>
 
 #include "fault.h"
@@ -809,6 +810,9 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 	int thumb2_32b = 0;
 	int fault;
 
+	if (addr >= TASK_SIZE && user_mode(regs))
+		harden_branch_predictor();
+
 	if (interrupts_enabled(regs))
 		local_irq_enable();
 
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 92fc70b56d72..6d7a7e639321 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -185,9 +185,6 @@ __do_user_fault(unsigned long addr, unsigned int fsr, unsigned int sig,
 {
 	struct task_struct *tsk = current;
 
-	if (addr > TASK_SIZE)
-		harden_branch_predictor();
-
 #ifdef CONFIG_DEBUG_USER
 	if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) ||
 	    ((user_debug & UDBG_BUS)  && (sig == SIGBUS))) {
@@ -269,8 +266,10 @@ do_kernel_address_page_fault(struct mm_struct *mm, unsigned long addr,
 		/*
 		 * Fault from user mode for a kernel space address. User mode
 		 * should not be faulting in kernel space, which includes the
-		 * vector/khelper page. Send a SIGSEGV.
+		 * vector/khelper page. Handle the branch predictor hardening
+		 * while interrupts are still disabled, then send a SIGSEGV.
 		 */
+		harden_branch_predictor();
 		__do_user_fault(addr, fsr, SIGSEGV, SEGV_MAPERR, regs);
 	} else {
 		/*
@@ -485,16 +484,20 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
  * We enter here because the first level page table doesn't contain
  * a valid entry for the address.
  *
- * If the address is in kernel space (>= TASK_SIZE), then we are
- * probably faulting in the vmalloc() area.
+ * If this is a user address (addr < TASK_SIZE), we handle this as a
+ * normal page fault. This leaves the remainder of the function to handle
+ * kernel address translation faults.
  *
- * If the init_task's first level page tables contains the relevant
- * entry, we copy the it to this task.  If not, we send the process
- * a signal, fixup the exception, or oops the kernel.
+ * Since user mode is not permitted to access kernel addresses, pass these
+ * directly to do_kernel_address_page_fault() to handle.
  *
- * NOTE! We MUST NOT take any locks for this case. We may be in an
- * interrupt or a critical region, and should only copy the information
- * from the master page table, nothing more.
+ * Otherwise, we're probably faulting in the vmalloc() area, so try to fix
+ * that up. Note that we must not take any locks or enable interrupts in
+ * this case.
+ *
+ * If vmalloc() fixup fails, that means the non-leaf page tables did not
+ * contain an entry for this address, so handle this via
+ * do_kernel_address_page_fault().
  */
 #ifdef CONFIG_MMU
 static int __kprobes
@@ -560,7 +563,8 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
 	return 0;
 
 bad_area:
-	do_bad_area(addr, fsr, regs);
+	do_kernel_address_page_fault(current->mm, addr, fsr, regs);
+
 	return 0;
 }
 #else					/* CONFIG_MMU */
@@ -580,7 +584,16 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
 static int
 do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 {
+	/*
+	 * If this is a kernel address, but from user mode, then userspace
+	 * is trying bad stuff. Invoke the branch predictor handling.
+	 * Interrupts are disabled here.
+	 */
+	if (addr >= TASK_SIZE && user_mode(regs))
+		harden_branch_predictor();
+
 	do_bad_area(addr, fsr, regs);
+
 	return 0;
 }
 #endif /* CONFIG_ARM_LPAE */
-- 
2.47.3



From m.szyprowski at samsung.com  Mon Dec  8 04:42:40 2025
From: m.szyprowski at samsung.com (Marek Szyprowski)
Date: Mon, 8 Dec 2025 13:42:40 +0100
Subject: [PATCH v7 2/2] remoteproc: qcom: Use of_reserved_mem_region_*
 functions for "memory-region"
In-Reply-To: <CAL_JsqJTrGAJx-fv8OQGDhsLVKavQzzQotssEq_E5f_aJe8bOg@mail.gmail.com>
References: <20251124182751.507624-1-robh@kernel.org>
	<CGME20251127142839eucas1p186846c6c1ea1d9e43369fbba9bb5d17c@eucas1p1.samsung.com>
	<20251124182751.507624-2-robh@kernel.org>
	<674efe8d-c299-4ce9-bf6b-c1920a5393eb@samsung.com>
	<CAL_JsqJTrGAJx-fv8OQGDhsLVKavQzzQotssEq_E5f_aJe8bOg@mail.gmail.com>
Message-ID: <2c274bd2-3bcc-4b75-9a37-9a6441bd7a50@samsung.com>

On 02.12.2025 15:15, Rob Herring wrote:
> On Thu, Nov 27, 2025 at 8:28?AM Marek Szyprowski
> <m.szyprowski at samsung.com> wrote:
>> On 24.11.2025 19:27, Rob Herring (Arm) wrote:
>>> Use the newly added of_reserved_mem_region_to_resource() and
>>> of_reserved_mem_region_count() functions to handle "memory-region"
>>> properties.
>>>
>>> The error handling is a bit different in some cases. Often
>>> "memory-region" is optional, so failed lookup is not an error. But then
>>> an error in of_reserved_mem_lookup() is treated as an error. However,
>>> that distinction is not really important. Either the region is available
>>> and usable or it is not. So now, it is just
>>> of_reserved_mem_region_to_resource() which is checked for an error.
>>>
>>> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
>> This patch landed in today's linux-next as commit c70b9d5fdcd7
>> ("remoteproc: qcom: Use of_reserved_mem_region_* functions for
>> "memory-region""). In my tests I found that it breaks booting of
>> DragonBoard410c (arch/arm64/boot/dts/qcom/apq8016-sbc.dts) by causing
>> the NULL pointer dereference. The issue is caused by replacing
>> devm_ioremap_wc() with devm_ioremap_resource_wc(), which fails on
>> devm_request_mem_region(), see comment in the code below. It looks that
>> the error handling is somewhere broken. Here is the the kernel log:
>>
>> remoteproc remoteproc0: 4080000.remoteproc is available
>> qcom-wcnss-pil a204000.remoteproc: error -EBUSY: can't request region
>> for resource [mem 0x8e200000-0x8e7fffff]
>> remoteproc remoteproc1: a204000.remoteproc is available
>> remoteproc remoteproc1: powering up a204000.remoteproc
>> remoteproc remoteproc1: Booting fw image qcom/apq8016/wcnss.mbn, size
>> 4111376
>> Unable to handle kernel paging request at virtual address fffffffffffffff0
>> Mem abort info:
>> ...
>> Internal error: Oops: 0000000096000046 [#1]  SMP
>> Modules linked in: cpufreq_powersave qcom_wcnss_pil cpufreq_conservative
>> coresight_stm coresight_replicator coresight_tmc coresight_tpiu stm_core
>> coresight_funnel coresight_cpu_debug coresight_cti(+) adv7511 coresight
>> nfc rfkill msm snd_soc_lpass_apq8016 snd_soc_apq8016_sbc
>> snd_soc_lpass_cpu snd_soc_msm8916_analog snd_soc_msm8916_digital
>> snd_soc_qcom_common snd_soc_lpass_platform snd_soc_core qrtr ubwc_config
>> snd_compress llcc_qcom snd_pcm_dmaengine qcom_q6v5_mss snd_pcm ocmem
>> qcom_pil_info qcom_spmi_vadc qcom_camss drm_gpuvm qcom_pon rtc_pm8xxx
>> qcom_q6v5 qcom_spmi_temp_alarm venus_core qcom_vadc_common snd_timer
>> drm_exec qcom_sysmon snd qcom_common gpu_sched videobuf2_dma_sg
>> v4l2_mem2mem qcom_glink_smem v4l2_fwnode soundcore drm_dp_aux_bus
>> qmi_helpers mdt_loader v4l2_async videobuf2_memops videobuf2_v4l2
>> videodev qnoc_msm8916 videobuf2_common qcom_rng drm_display_helper mc
>> qcom_stats rpmsg_ctrl rpmsg_char display_connector ramoops socinfo
>> rmtfs_mem reed_solomon ax88796b asix usbnet phy_qcom_usb_hs ipv6 libsha1
>> CPU: 2 UID: 0 PID: 28 Comm: kworker/2:0 Tainted: G W
>> 6.18.0-rc1+ #16209 PREEMPT
>> Tainted: [W]=WARN
>> lr : __qcom_mdt_load+0x210/0x304 [mdt_loader]
>> Call trace:
>>    __pi_memcpy_generic+0x128/0x22c (P)
>>    qcom_mdt_load+0x68/0x60c [mdt_loader]
>>    wcnss_load+0x2c/0x5c [qcom_wcnss_pil]
>>    rproc_start+0x30/0x1b4
>>    rproc_boot+0x19c/0x560
>>    rproc_auto_boot_callback+0x1c/0x34
>>    request_firmware_work_func+0x4c/0x98
>>    process_one_work+0x208/0x60c
>>    worker_thread+0x244/0x388
>>    kthread+0x150/0x228
>>    ret_from_fork+0x10/0x20
>> Code: 927cec03 cb0e0021 8b0e0042 a9411c26 (a900340c)
>> ---[ end trace 0000000000000000 ]---
>>
>>
>>> ---
>>> v7:
>>>    - Split QCom to separate patch
>>> ---
>>>    drivers/remoteproc/qcom_q6v5_adsp.c | 24 ++++------
>>>    drivers/remoteproc/qcom_q6v5_mss.c  | 60 ++++++++-----------------
>>>    drivers/remoteproc/qcom_q6v5_pas.c  | 69 +++++++++++------------------
>>>    drivers/remoteproc/qcom_q6v5_wcss.c | 25 +++++------
>>>    drivers/remoteproc/qcom_wcnss.c     | 23 ++++------
>>>    5 files changed, 72 insertions(+), 129 deletions(-)
>>>
>>> ...
>>> diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
>>> index 2c7e519a2254..14005fb049a2 100644
>>> --- a/drivers/remoteproc/qcom_wcnss.c
>>> +++ b/drivers/remoteproc/qcom_wcnss.c
>>> @@ -526,25 +526,20 @@ static int wcnss_request_irq(struct qcom_wcnss *wcnss,
>>>
>>>    static int wcnss_alloc_memory_region(struct qcom_wcnss *wcnss)
>>>    {
>>> -     struct reserved_mem *rmem = NULL;
>>> -     struct device_node *node;
>>> -
>>> -     node = of_parse_phandle(wcnss->dev->of_node, "memory-region", 0);
>>> -     if (node)
>>> -             rmem = of_reserved_mem_lookup(node);
>>> -     of_node_put(node);
>>> +     struct resource res;
>>> +     int ret;
>>>
>>> -     if (!rmem) {
>>> +     ret = of_reserved_mem_region_to_resource(wcnss->dev->of_node, 0, &res);
>>> +     if (ret) {
>>>                dev_err(wcnss->dev, "unable to resolve memory-region\n");
>>> -             return -EINVAL;
>>> +             return ret;
>>>        }
>>>
>>> -     wcnss->mem_phys = wcnss->mem_reloc = rmem->base;
>>> -     wcnss->mem_size = rmem->size;
>>> -     wcnss->mem_region = devm_ioremap_wc(wcnss->dev, wcnss->mem_phys, wcnss->mem_size);
>>> +     wcnss->mem_phys = wcnss->mem_reloc = res.start;
>>> +     wcnss->mem_size = resource_size(&res);
>>> +     wcnss->mem_region = devm_ioremap_resource_wc(wcnss->dev, &res);
>> The above line causes the failure. After restoring it to:
>>
>> wcnss->mem_region = devm_ioremap_wc(wcnss->dev, wcnss->mem_phys, wcnss->mem_size);
>>
>> the mentioned board boots fine again. I'm not sure about other drivers,
>> if they also fail the same way as they might not be used on the tested
>> board.
> Other platforms (non-QCom) were tested also use
> devm_ioremap_resource_wc(). So something else is claiming the same
> region? Can you dump out /proc/iomem?
>
> The region is dynamically allocated, so maybe that has something to do with it.

# dmesg | grep mem
OF: reserved mem: 0x000000008e200000..0x000000008e7fffff (6144 KiB) 
nomap non-reusable wcnss
OF: reserved mem: 0x000000008dd00000..0x000000008e1fffff (5120 KiB) 
nomap non-reusable venus
OF: reserved mem: 0x000000008dc00000..0x000000008dcfffff (1024 KiB) 
nomap non-reusable mba
OF: reserved mem: 0x0000000086000000..0x00000000862fffff (3072 KiB) 
nomap non-reusable tz-apps at 86000000
OF: reserved mem: 0x0000000086300000..0x00000000863fffff (1024 KiB) 
nomap non-reusable smem at 86300000
OF: reserved mem: 0x0000000086400000..0x00000000864fffff (1024 KiB) 
nomap non-reusable hypervisor at 86400000
OF: reserved mem: 0x0000000086500000..0x000000008667ffff (1536 KiB) 
nomap non-reusable tz at 86500000
OF: reserved mem: 0x0000000086680000..0x00000000866fffff (512 KiB) nomap 
non-reusable reserved at 86680000
OF: reserved mem: 0x0000000086700000..0x00000000867dffff (896 KiB) nomap 
non-reusable rmtfs at 86700000
OF: reserved mem: 0x00000000867e0000..0x00000000867fffff (128 KiB) nomap 
non-reusable rfsa at 867e0000
OF: reserved mem: 0x0000000086800000..0x00000000892fffff (44032 KiB) 
nomap non-reusable mpss at 86800000
OF: reserved mem: 0x00000000bff00000..0x00000000bfffffff (1024 KiB) map 
non-reusable ramoops at bff00000
NUMA: Faking a node at [mem 0x0000000080000000-0x00000000bd9fffff]
NODE_DATA(0) allocated [mem 0xbd7c6800-0xbd7c943f]
 ??DMA ?????[mem 0x0000000080000000-0x00000000bd9fffff]
Early memory node ranges
 ??node ??0: [mem 0x0000000080000000-0x0000000085ffffff]
 ??node ??0: [mem 0x0000000086000000-0x00000000892fffff]
 ??node ??0: [mem 0x0000000089300000-0x000000008dbfffff]
 ??node ??0: [mem 0x000000008dc00000-0x000000008e7fffff]
 ??node ??0: [mem 0x000000008e800000-0x00000000bd9fffff]

...


# cat /proc/iomem

...
80000000-85ffffff : System RAM
 ?80000000-821affff : Kernel code
 ?821b0000-82e5ffff : reserved
 ?82e60000-840fffff : Kernel data
 ?85000000-85013fff : reserved
86000000-892fffff : reserved
89300000-8dbfffff : System RAM
8dc00000-8e7fffff : reserved
 ?8dc00000-8e7fffff : reserved
8e800000-bd9fffff : System RAM
 ?b1000000-b6ffffff : reserved
 ?b7000000-bbe08fff : reserved
 ?bc480000-bd5fffff : reserved
 ?bd621000-bd623fff : reserved
 ?bd624000-bd724fff : reserved
 ?bd725000-bd7b0fff : reserved
 ?bd7b2000-bd7b4fff : reserved
 ?bd7b5000-bd7b5fff : reserved
 ?bd7b6000-bd7c9fff : reserved
 ?bd7ca000-bd9fffff : reserved


The devm_ioremap_resource_wc() requested region (0x8e200000-0x8e7fffff) 
is marked as 'reserved' in /proc/iomem.

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland



From xieyuanbin1 at huawei.com  Mon Dec  8 05:18:42 2025
From: xieyuanbin1 at huawei.com (Xie Yuanbin)
Date: Mon, 8 Dec 2025 21:18:42 +0800
Subject: [Bug report] hash_name() may cross page boundary and trigger sleep in RCU context
In-Reply-To: <aTajXdAVYh9qJI6B@shell.armlinux.org.uk>
References: <aTajXdAVYh9qJI6B@shell.armlinux.org.uk>
Message-ID: <20251208131842.76909-1-xieyuanbin1@huawei.com>

On Mon, 8 Dec 2025 10:07:25 +0000, Russell King wrote:
> This isn't entirely fixed. A data abort for an alignment fault (thus
> calling do_alignment()) will enable interrupts, and then may call
> do_bad_area(). We can't short-circuit this path like we can with
> do_page_fault() as alignment faults from userspace can be valid for
> the vectors page - not that we should see them, but that doesn't mean
> that there isn't something in userspace that does.

I had indeed been lacking in consideration regarding do_alignment()
before, so thank you for reply. But, may I ask that, is there a scenario
where user-mode access to kernel addresses causes an alignment fault
(do_alignment())?

In your last email, you described it as follows:
On Fri, 5 Dec 2025 12:08:14 +0000, Russell King wrote:
> Also tested usermode access to kernel space
> which fails with SEGV:
> - read from 0xc0000000 (section permission fault, do_sect_fault)
> - read from 0xffff2000 (page translation fault, do_page_fault)
> - read from 0xffff0000 (vectors page - read possible as expected)
> - write to 0xffff0000 (page permission fault, do_page_fault)

There seems to be no do_alignment()?

In other words, is there a way to construct a user-mode testcase which
accesses a kernel address and triggers do_alignment()?

> That patch got missed - I'm notoriously bad at catching every email.
> There's just way too much email coming in.

No need to worry.

> It's to keep the behaviour closer to the original as possible, on the
> principle of avoiding unnecessary behavioural changes to the code. As
> noted above, do_bad_area() can be called with interrupts enabled.
>
> Whether RT folk would be happy removing that is a different question,
> given that they want as much of the kernel to be preemptable.

Thank you for your reply. I have no objections to this, although it might
introduce some unnecessary code paths, at least it won't bring any new
issues.


From devnull+yassine.ouaissa.allegrodvt.com at kernel.org  Mon Dec  8 05:41:21 2025
From: devnull+yassine.ouaissa.allegrodvt.com at kernel.org (Yassine Ouaissa via B4 Relay)
Date: Mon, 08 Dec 2025 14:41:21 +0100
Subject: [PATCH v6 1/4] media: allegro-dvt: Move the current driver to a
 subdirectory
In-Reply-To: <20251208-allegro_dvt_al300_dec_driver-v6-0-2e51ab2e4ce9@allegrodvt.com>
References: <20251208-allegro_dvt_al300_dec_driver-v6-0-2e51ab2e4ce9@allegrodvt.com>
Message-ID: <20251208-allegro_dvt_al300_dec_driver-v6-1-2e51ab2e4ce9@allegrodvt.com>

From: Yassine Ouaissa <yassine.ouaissa at allegrodvt.com>

In preparation for the upcoming driver update, we need to relocate the
current driver.
This will help ensure a clean transition and avoid any potential
conflicts with the new driver.
This patch is crucial for keeping our directory organized and
facilitating a smooth integration of the new driver.

Signed-off-by: Yassine Ouaissa <yassine.ouaissa at allegrodvt.com>
---
 MAINTAINERS                                             |  2 +-
 drivers/media/platform/allegro-dvt/Kconfig              | 16 +---------------
 drivers/media/platform/allegro-dvt/Makefile             |  5 +----
 drivers/media/platform/allegro-dvt/zynqmp/Kconfig       | 17 +++++++++++++++++
 drivers/media/platform/allegro-dvt/zynqmp/Makefile      |  6 ++++++
 .../platform/allegro-dvt/{ => zynqmp}/allegro-core.c    |  0
 .../platform/allegro-dvt/{ => zynqmp}/allegro-mail.c    |  0
 .../platform/allegro-dvt/{ => zynqmp}/allegro-mail.h    |  0
 .../media/platform/allegro-dvt/{ => zynqmp}/nal-h264.c  |  0
 .../media/platform/allegro-dvt/{ => zynqmp}/nal-h264.h  |  0
 .../media/platform/allegro-dvt/{ => zynqmp}/nal-hevc.c  |  0
 .../media/platform/allegro-dvt/{ => zynqmp}/nal-hevc.h  |  0
 .../media/platform/allegro-dvt/{ => zynqmp}/nal-rbsp.c  |  0
 .../media/platform/allegro-dvt/{ => zynqmp}/nal-rbsp.h  |  0
 14 files changed, 26 insertions(+), 20 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index d701a4d5b00e..dc56841fa5e5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -838,7 +838,7 @@ R:	Pengutronix Kernel Team <kernel at pengutronix.de>
 L:	linux-media at vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/media/allegro,al5e.yaml
-F:	drivers/media/platform/allegro-dvt/
+F:	drivers/media/platform/allegro-dvt/zynqmp
 
 ALLIED VISION ALVIUM CAMERA DRIVER
 M:	Tommaso Merciai <tomm.merciai at gmail.com>
diff --git a/drivers/media/platform/allegro-dvt/Kconfig b/drivers/media/platform/allegro-dvt/Kconfig
index 2182e1277568..e9008614c27b 100644
--- a/drivers/media/platform/allegro-dvt/Kconfig
+++ b/drivers/media/platform/allegro-dvt/Kconfig
@@ -2,18 +2,4 @@
 
 comment "Allegro DVT media platform drivers"
 
-config VIDEO_ALLEGRO_DVT
-	tristate "Allegro DVT Video IP Core"
-	depends on V4L_MEM2MEM_DRIVERS
-	depends on VIDEO_DEV
-	depends on ARCH_ZYNQMP || COMPILE_TEST
-	select V4L2_MEM2MEM_DEV
-	select VIDEOBUF2_DMA_CONTIG
-	select REGMAP_MMIO
-	help
-	  Support for the encoder video IP core by Allegro DVT. This core is
-	  found for example on the Xilinx ZynqMP SoC in the EV family and is
-	  called VCU in the reference manual.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called allegro.
+source "drivers/media/platform/allegro-dvt/zynqmp/Kconfig"
diff --git a/drivers/media/platform/allegro-dvt/Makefile b/drivers/media/platform/allegro-dvt/Makefile
index 66108a303774..d2aa6875edcf 100644
--- a/drivers/media/platform/allegro-dvt/Makefile
+++ b/drivers/media/platform/allegro-dvt/Makefile
@@ -1,6 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0
 
-allegro-objs := allegro-core.o allegro-mail.o
-allegro-objs += nal-rbsp.o nal-h264.o nal-hevc.o
-
-obj-$(CONFIG_VIDEO_ALLEGRO_DVT) += allegro.o
+obj-y += zynqmp/
diff --git a/drivers/media/platform/allegro-dvt/zynqmp/Kconfig b/drivers/media/platform/allegro-dvt/zynqmp/Kconfig
new file mode 100644
index 000000000000..0a0a697c420d
--- /dev/null
+++ b/drivers/media/platform/allegro-dvt/zynqmp/Kconfig
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config VIDEO_ALLEGRO_DVT
+	tristate "Allegro DVT Video IP Core for ZynqMP"
+	depends on V4L_MEM2MEM_DRIVERS
+	depends on VIDEO_DEV
+	depends on ARCH_ZYNQMP || COMPILE_TEST
+	select V4L2_MEM2MEM_DEV
+	select VIDEOBUF2_DMA_CONTIG
+	select REGMAP_MMIO
+	help
+	  Support for the encoder video IP core by Allegro DVT. This core is
+	  found for example on the Xilinx ZynqMP SoC in the EV family and is
+	  called VCU in the reference manual.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called allegro.
diff --git a/drivers/media/platform/allegro-dvt/zynqmp/Makefile b/drivers/media/platform/allegro-dvt/zynqmp/Makefile
new file mode 100644
index 000000000000..66108a303774
--- /dev/null
+++ b/drivers/media/platform/allegro-dvt/zynqmp/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+
+allegro-objs := allegro-core.o allegro-mail.o
+allegro-objs += nal-rbsp.o nal-h264.o nal-hevc.o
+
+obj-$(CONFIG_VIDEO_ALLEGRO_DVT) += allegro.o
diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/zynqmp/allegro-core.c
similarity index 100%
rename from drivers/media/platform/allegro-dvt/allegro-core.c
rename to drivers/media/platform/allegro-dvt/zynqmp/allegro-core.c
diff --git a/drivers/media/platform/allegro-dvt/allegro-mail.c b/drivers/media/platform/allegro-dvt/zynqmp/allegro-mail.c
similarity index 100%
rename from drivers/media/platform/allegro-dvt/allegro-mail.c
rename to drivers/media/platform/allegro-dvt/zynqmp/allegro-mail.c
diff --git a/drivers/media/platform/allegro-dvt/allegro-mail.h b/drivers/media/platform/allegro-dvt/zynqmp/allegro-mail.h
similarity index 100%
rename from drivers/media/platform/allegro-dvt/allegro-mail.h
rename to drivers/media/platform/allegro-dvt/zynqmp/allegro-mail.h
diff --git a/drivers/media/platform/allegro-dvt/nal-h264.c b/drivers/media/platform/allegro-dvt/zynqmp/nal-h264.c
similarity index 100%
rename from drivers/media/platform/allegro-dvt/nal-h264.c
rename to drivers/media/platform/allegro-dvt/zynqmp/nal-h264.c
diff --git a/drivers/media/platform/allegro-dvt/nal-h264.h b/drivers/media/platform/allegro-dvt/zynqmp/nal-h264.h
similarity index 100%
rename from drivers/media/platform/allegro-dvt/nal-h264.h
rename to drivers/media/platform/allegro-dvt/zynqmp/nal-h264.h
diff --git a/drivers/media/platform/allegro-dvt/nal-hevc.c b/drivers/media/platform/allegro-dvt/zynqmp/nal-hevc.c
similarity index 100%
rename from drivers/media/platform/allegro-dvt/nal-hevc.c
rename to drivers/media/platform/allegro-dvt/zynqmp/nal-hevc.c
diff --git a/drivers/media/platform/allegro-dvt/nal-hevc.h b/drivers/media/platform/allegro-dvt/zynqmp/nal-hevc.h
similarity index 100%
rename from drivers/media/platform/allegro-dvt/nal-hevc.h
rename to drivers/media/platform/allegro-dvt/zynqmp/nal-hevc.h
diff --git a/drivers/media/platform/allegro-dvt/nal-rbsp.c b/drivers/media/platform/allegro-dvt/zynqmp/nal-rbsp.c
similarity index 100%
rename from drivers/media/platform/allegro-dvt/nal-rbsp.c
rename to drivers/media/platform/allegro-dvt/zynqmp/nal-rbsp.c
diff --git a/drivers/media/platform/allegro-dvt/nal-rbsp.h b/drivers/media/platform/allegro-dvt/zynqmp/nal-rbsp.h
similarity index 100%
rename from drivers/media/platform/allegro-dvt/nal-rbsp.h
rename to drivers/media/platform/allegro-dvt/zynqmp/nal-rbsp.h

-- 
2.50.1




From devnull+yassine.ouaissa.allegrodvt.com at kernel.org  Mon Dec  8 05:41:23 2025
From: devnull+yassine.ouaissa.allegrodvt.com at kernel.org (Yassine Ouaissa via B4 Relay)
Date: Mon, 08 Dec 2025 14:41:23 +0100
Subject: [PATCH v6 3/4] dt-bindings: vendor-prefixes: Update the
 description of allegro prefix
In-Reply-To: <20251208-allegro_dvt_al300_dec_driver-v6-0-2e51ab2e4ce9@allegrodvt.com>
References: <20251208-allegro_dvt_al300_dec_driver-v6-0-2e51ab2e4ce9@allegrodvt.com>
Message-ID: <20251208-allegro_dvt_al300_dec_driver-v6-3-2e51ab2e4ce9@allegrodvt.com>

From: Yassine Ouaissa <yassine.ouaissa at allegrodvt.com>

Add SAS (Soci?t? par actions simplifi?e) to the allegro of vendor
prefixe description to include French simplified joint-stock company
legal structure.

Acked-by: Conor Dooley <conor.dooley at microchip.com>
Signed-off-by: Yassine Ouaissa <yassine.ouaissa at allegrodvt.com>
---
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index c7591b2aec2a..8376312dd9e4 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -87,7 +87,7 @@ patternProperties:
   "^alfa-network,.*":
     description: ALFA Network Inc.
   "^allegro,.*":
-    description: Allegro DVT
+    description: Allegro DVT, SAS.
   "^allegromicro,.*":
     description: Allegro MicroSystems, Inc.
   "^alliedtelesis,.*":

-- 
2.50.1




From devnull+yassine.ouaissa.allegrodvt.com at kernel.org  Mon Dec  8 05:41:24 2025
From: devnull+yassine.ouaissa.allegrodvt.com at kernel.org (Yassine Ouaissa via B4 Relay)
Date: Mon, 08 Dec 2025 14:41:24 +0100
Subject: [PATCH v6 4/4] media: allegro-dvt: Add Gen 3 IP stateful decoder
 driver
In-Reply-To: <20251208-allegro_dvt_al300_dec_driver-v6-0-2e51ab2e4ce9@allegrodvt.com>
References: <20251208-allegro_dvt_al300_dec_driver-v6-0-2e51ab2e4ce9@allegrodvt.com>
Message-ID: <20251208-allegro_dvt_al300_dec_driver-v6-4-2e51ab2e4ce9@allegrodvt.com>

From: Yassine Ouaissa <yassine.ouaissa at allegrodvt.com>

This commit introduces a new allegro-dvt V4L2 stateful decoder driverfor
the Gen 3 IP with support for:
- AVC (H.264), HEVC (H.265), and JPEG decoding
- Output formats: NV12, NV16, I420, and P010 for capture

Signed-off-by: Yassine Ouaissa <yassine.ouaissa at allegrodvt.com>
---
 drivers/media/platform/allegro-dvt/Kconfig         |    1 +
 drivers/media/platform/allegro-dvt/Makefile        |    1 +
 drivers/media/platform/allegro-dvt/al300/Kconfig   |   23 +
 drivers/media/platform/allegro-dvt/al300/Makefile  |    9 +
 .../platform/allegro-dvt/al300/al_codec_common.c   |  764 ++++++++++
 .../platform/allegro-dvt/al300/al_codec_common.h   |  252 ++++
 .../platform/allegro-dvt/al300/al_codec_dbgfs.c    |  229 +++
 .../platform/allegro-dvt/al300/al_codec_dbgfs.h    |   71 +
 .../platform/allegro-dvt/al300/al_codec_util.c     |  180 +++
 .../platform/allegro-dvt/al300/al_codec_util.h     |  196 +++
 .../media/platform/allegro-dvt/al300/al_vdec_drv.c | 1514 ++++++++++++++++++++
 .../media/platform/allegro-dvt/al300/al_vdec_drv.h |   98 ++
 12 files changed, 3338 insertions(+)

diff --git a/drivers/media/platform/allegro-dvt/Kconfig b/drivers/media/platform/allegro-dvt/Kconfig
index e9008614c27b..0d01ed0ad08a 100644
--- a/drivers/media/platform/allegro-dvt/Kconfig
+++ b/drivers/media/platform/allegro-dvt/Kconfig
@@ -2,4 +2,5 @@
 
 comment "Allegro DVT media platform drivers"
 
+source "drivers/media/platform/allegro-dvt/al300/Kconfig"
 source "drivers/media/platform/allegro-dvt/zynqmp/Kconfig"
diff --git a/drivers/media/platform/allegro-dvt/Makefile b/drivers/media/platform/allegro-dvt/Makefile
index d2aa6875edcf..c70ca19a47fb 100644
--- a/drivers/media/platform/allegro-dvt/Makefile
+++ b/drivers/media/platform/allegro-dvt/Makefile
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
 
+obj-y += al300/
 obj-y += zynqmp/
diff --git a/drivers/media/platform/allegro-dvt/al300/Kconfig b/drivers/media/platform/allegro-dvt/al300/Kconfig
new file mode 100644
index 000000000000..0bc3d7a79f14
--- /dev/null
+++ b/drivers/media/platform/allegro-dvt/al300/Kconfig
@@ -0,0 +1,23 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config VIDEO_ALLEGRO_DVT_D300
+	tristate "Allegro DVT Video IP Decode Gen 3"
+	depends on V4L_MEM2MEM_DRIVERS
+	depends on VIDEO_DEV && OF && HAS_DMA
+	select V4L2_MEM2MEM_DEV
+	select VIDEOBUF2_DMA_CONTIG
+	help
+	  This is a video4linux2 driver for the Allegro DVT IP Decode Gen 3,
+	  that support codecs : AVC (H.264), HEVC (H.265), and JPEG.
+
+	  The driver provides hardware acceleration for video decoding operations,
+	  enabling efficient processing of compressed video streams on platforms
+	  featuring this IP block. It handles memory management, buffer allocation,
+	  and decoder command sequencing to deliver optimized performance.
+
+	  The driver integrates with the V4L2 framework and videobuf2 subsystem
+	  to provide a standard interface for applications requiring video
+	  decoding capabilities.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called al300-vdec.
diff --git a/drivers/media/platform/allegro-dvt/al300/Makefile b/drivers/media/platform/allegro-dvt/al300/Makefile
new file mode 100644
index 000000000000..e5bc317ee2a7
--- /dev/null
+++ b/drivers/media/platform/allegro-dvt/al300/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+
+al300-vdec-objs := al_codec_common.o al_codec_util.o al_vdec_drv.o
+
+ifneq ($(CONFIG_DEBUG_FS),)
+al300-vdec-objs += al_codec_dbgfs.o
+endif
+
+obj-$(CONFIG_VIDEO_ALLEGRO_DVT_D300) += al300-vdec.o
diff --git a/drivers/media/platform/allegro-dvt/al300/al_codec_common.c b/drivers/media/platform/allegro-dvt/al300/al_codec_common.c
new file mode 100644
index 000000000000..6c950a4022fb
--- /dev/null
+++ b/drivers/media/platform/allegro-dvt/al300/al_codec_common.c
@@ -0,0 +1,764 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Core MCU functionality including firmware loading,
+ * memory allocation, and general MCU interaction interfaces
+ *
+ * Copyright (c) 2025 Allegro DVT.
+ * Author: Yassine OUAISSA <yassine.ouaissa at allegrodvt.fr>
+ */
+
+#include <linux/cleanup.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "al_codec_common.h"
+
+#define AL_CODEC_UID 0x0000
+#define AL_CODEC_RESET 0x0010
+#define AL_CODEC_IRQ_MASK 0x0014
+#define AL_CODEC_IRQ_STATUS_CLEAR 0x0018
+#define AL_CODEC_MCU_CLK 0x0400
+#define AL_CODEC_MCU_RST 0x0404
+#define AL_CODEC_MCU_IRQ 0x040C
+#define AL_CODEC_MCU_BOOT_ADDR_HI 0x0410
+#define AL_CODEC_MCU_BOOT_ADDR_LO 0x0414
+#define AL_CODEC_MCU_IP_START_ADDR_HI 0x0418
+#define AL_CODEC_MCU_IP_START_ADDR_LO 0x041C
+#define AL_CODEC_MCU_IP_END_ADDR_HI 0x0420
+#define AL_CODEC_MCU_IP_END_ADDR_LO 0x0424
+#define AL_CODEC_MCU_PERIPH_ADDR_HI 0x0428
+#define AL_CODEC_MCU_PERIPH_ADDR_LO 0x042C
+#define AL_CODEC_MCU_IRQ_MASK 0x0440
+#define AL_CODEC_INST_OFFSET_HI 0x0450
+#define AL_CODEC_INST_OFFSET_LO 0x0454
+#define AL_CODEC_DATA_OFFSET_HI 0x0458
+#define AL_CODEC_DATA_OFFSET_LO 0x045C
+
+#define AL_CODEC_UID_ID 0x30AB6E51
+#define AL_CODEC_IRQ_MCU_2_CPU BIT(30)
+#define AL_CODEC_IP_OFFSET GENMASK(26, 25)
+#define AL_CODEC_APB_MASK GENMASK(26, 0)
+#define MCU_FLAT_MEMORY_SIZE (256ULL * 1024 * 1024 * 1024) /* 256GB */
+
+#define AL_CODEC_MCU_BOOT_RESET_WAIT 2 /* in ms */
+#define AL_CODEC_REG_ENABLE BIT(0)
+#define AL_CODEC_REG_DISABLE 0
+
+/*
+ * struct codec_dma_buf - Allocated dma buffer
+ *
+ * @list: list head for buffer queue
+ * @paddr: physical address of the allcated DMA buffer
+ * @vaddr: virtual address of the allocated DMA buffer
+ * @size: Size of allocated dma memory
+ */
+struct codec_dma_buf {
+	void *vaddr;
+	dma_addr_t paddr;
+	u32 size;
+	struct list_head list;
+};
+
+struct mb_header {
+	u64 start;
+	u64 end;
+} __packed;
+
+struct boot_header {
+	u32 bh_version;
+	u32 fw_version;
+	char model[16];
+	u64 vaddr_start;
+	u64 vaddr_end;
+	u64 vaddr_boot;
+	struct mb_header h2m;
+	struct mb_header m2h;
+	u64 machine_id;
+	/* fill by driver before fw boot */
+	u64 ip_start;
+	u64 ip_end;
+	u64 mcu_clk_rate;
+} __packed;
+
+static u32 al_common_read(struct al_codec_dev *codec, u32 offset)
+{
+	return readl(codec->regs + offset);
+}
+
+static void al_common_write(struct al_codec_dev *codec, u32 offset, u32 val)
+{
+	writel(val, codec->regs + offset);
+}
+
+static void al_common_trigger_mcu_irq(void *arg)
+{
+	struct al_codec_dev *codec = arg;
+
+	al_common_write(codec, AL_CODEC_MCU_IRQ, BIT(0));
+}
+
+static inline void al_common_reset(struct al_codec_dev *codec)
+{
+	/* reset ip */
+	al_common_write(codec, AL_CODEC_RESET, AL_CODEC_REG_ENABLE);
+
+	/* reset and stop mcu */
+	al_common_write(codec, AL_CODEC_MCU_CLK, AL_CODEC_REG_ENABLE);
+	al_common_write(codec, AL_CODEC_MCU_RST, AL_CODEC_REG_ENABLE);
+	/* time to reset the mct */
+	mdelay(AL_CODEC_MCU_BOOT_RESET_WAIT);
+	al_common_write(codec, AL_CODEC_MCU_CLK, AL_CODEC_REG_DISABLE);
+
+	al_common_write(codec, AL_CODEC_MCU_IRQ, AL_CODEC_REG_DISABLE);
+	al_common_write(codec, AL_CODEC_MCU_IRQ_MASK, AL_CODEC_REG_DISABLE);
+
+	mdelay(AL_CODEC_MCU_BOOT_RESET_WAIT * 5);
+	al_common_write(codec, AL_CODEC_MCU_RST, AL_CODEC_REG_DISABLE);
+}
+
+static int al_common_setup_hw_regs(struct al_codec_dev *codec)
+{
+	u64 reg_start, reg_end;
+	dma_addr_t boot_addr;
+	unsigned int id;
+
+	id = al_common_read(codec, AL_CODEC_UID);
+
+	if (id != AL_CODEC_UID_ID) {
+		al_codec_err(codec,
+			     "bad device id, expected 0x%08x, got 0x%08x",
+			     AL_CODEC_UID_ID, id);
+		return -ENODEV;
+	}
+
+	boot_addr = codec->firmware.phys + codec->firmware.bin_data.offset -
+		    codec->offset;
+
+	/* Reset MCU step */
+	al_common_reset(codec);
+
+	/* Configure the MCU*/
+	al_common_write(codec, AL_CODEC_IRQ_MASK, AL_CODEC_IRQ_MCU_2_CPU);
+	/* Set Instruction and data offset */
+	al_common_write(codec, AL_CODEC_INST_OFFSET_HI,
+			upper_32_bits(codec->offset));
+	al_common_write(codec, AL_CODEC_INST_OFFSET_LO,
+			lower_32_bits(codec->offset));
+	al_common_write(codec, AL_CODEC_DATA_OFFSET_HI,
+			upper_32_bits(codec->offset));
+	al_common_write(codec, AL_CODEC_DATA_OFFSET_LO,
+			lower_32_bits(codec->offset));
+
+	reg_start = codec->regs_info->start;
+	reg_end = reg_start + resource_size(codec->regs_info);
+	al_common_write(codec, AL_CODEC_MCU_IP_START_ADDR_HI,
+			upper_32_bits(reg_start));
+	al_common_write(codec, AL_CODEC_MCU_IP_START_ADDR_LO,
+			lower_32_bits(reg_start));
+	al_common_write(codec, AL_CODEC_MCU_IP_END_ADDR_HI,
+			upper_32_bits(reg_end));
+	al_common_write(codec, AL_CODEC_MCU_IP_END_ADDR_HI,
+			lower_32_bits(reg_end));
+
+	al_common_write(codec, AL_CODEC_MCU_PERIPH_ADDR_HI,
+			upper_32_bits(codec->apb));
+	al_common_write(codec, AL_CODEC_MCU_PERIPH_ADDR_LO,
+			lower_32_bits(codec->apb));
+
+	al_common_write(codec, AL_CODEC_MCU_BOOT_ADDR_HI,
+			upper_32_bits(boot_addr));
+	al_common_write(codec, AL_CODEC_MCU_BOOT_ADDR_LO,
+			lower_32_bits(boot_addr));
+
+	return 0;
+}
+
+static void al_common_dma_buf_insert(struct al_codec_dev *codec,
+				     struct codec_dma_buf *buf)
+{
+	guard(mutex)(&codec->buf_lock);
+	list_add(&buf->list, &codec->alloc_buffers);
+}
+
+static void al_common_dma_buf_remove(struct al_codec_dev *codec,
+				     struct codec_dma_buf *buf)
+{
+	struct device *dev = &codec->pdev->dev;
+
+	guard(mutex)(&codec->buf_lock);
+	dma_free_coherent(dev, buf->size, buf->vaddr, buf->paddr);
+	list_del(&buf->list);
+	kfree(buf);
+}
+
+static struct codec_dma_buf *
+al_common_dma_buf_lookup(struct al_codec_dev *codec, dma_addr_t buf_paddr)
+{
+	struct codec_dma_buf *buf = NULL;
+
+	guard(mutex)(&codec->buf_lock);
+	list_for_each_entry(buf, &codec->alloc_buffers, list)
+		if (likely(buf->paddr == buf_paddr))
+			break;
+
+	return list_entry_is_head(buf, &codec->alloc_buffers, list) ? NULL :
+								      buf;
+}
+
+static void al_common_dma_buf_cleanup(struct al_codec_dev *codec)
+{
+	struct device *dev = &codec->pdev->dev;
+	struct codec_dma_buf *buf, *tmp;
+
+	guard(mutex)(&codec->buf_lock);
+	list_for_each_entry_safe(buf, tmp, &codec->alloc_buffers, list) {
+		dma_free_coherent(dev, buf->size, buf->vaddr, buf->paddr);
+		list_del(&buf->list);
+		kfree(buf);
+	}
+}
+
+static inline uint64_t get_mcu_offset(uint64_t paddr)
+{
+	if (paddr < MCU_FLAT_MEMORY_SIZE)
+		return 0;
+
+	return paddr - MCU_FLAT_MEMORY_SIZE;
+}
+
+static int al_common_setup_dma(struct al_codec_dev *codec)
+{
+	struct device *dev = &codec->pdev->dev;
+	struct device_node *node;
+	struct resource r;
+	int ret;
+
+	/* setup dma memory mask */
+	if (!dev->coherent_dma_mask) {
+		ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64));
+		if (ret) {
+			al_codec_err(codec, "Failed to set dma mask %d\n", ret);
+			return ret;
+		}
+	}
+
+	node = of_parse_phandle(dev->of_node, "memory-region", 0);
+	if (!node) {
+		dev_warn(dev, "No reserved memory, use cma instead\n");
+		return 0;
+	}
+
+	/* Try to use reserved memory if we got one */
+	ret = of_reserved_mem_device_init(dev);
+	if (ret) {
+		al_codec_err(codec, "Couldn't get reserved memory (errno: %d)",
+			     ret);
+		return ret;
+	}
+
+	ret = of_address_to_resource(node, 0, &r);
+	of_node_put(node);
+	if (ret) {
+		al_codec_err(codec,
+			     "Failed to parse the memory-region resources");
+		return ret;
+	}
+
+	codec->offset = get_mcu_offset(r.start);
+
+	return 0;
+}
+
+void al_common_remove(struct al_codec_dev *codec)
+{
+	/* Cleanup allocated internal buffers used by the mcu*/
+	al_common_dma_buf_cleanup(codec);
+
+	/* reset codecice */
+	al_common_reset(codec);
+	clk_disable_unprepare(codec->clk);
+	/* Free the allocated memory for the firmware */
+	dma_free_coherent(&codec->pdev->dev, codec->firmware.size,
+			  codec->firmware.virt, codec->firmware.phys);
+
+	if (codec->firmware.firmware)
+		release_firmware(codec->firmware.firmware);
+}
+
+static void handle_alloc_memory_req(struct al_codec_dev *codec,
+				    struct msg_itf_header *hdr)
+{
+	struct device *dev = &codec->pdev->dev;
+	struct msg_itf_alloc_mem_req req;
+	struct msg_itf_alloc_mem_reply_full reply = {
+		.reply.phyAddr = 0,
+		.hdr.type = MSG_ITF_TYPE_ALLOC_MEM_REPLY,
+		.hdr.drv_ctx_hdl = hdr->drv_ctx_hdl,
+		.hdr.drv_cmd_hdl = hdr->drv_cmd_hdl,
+		.hdr.payload_len = sizeof(struct msg_itf_alloc_mem_reply),
+	};
+	struct codec_dma_buf *buf;
+	int ret;
+
+	ret = al_common_get_data(codec, (char *)&req, hdr->payload_len);
+	if (ret) {
+		al_codec_err(codec, "Unable to get cma req %d", ret);
+		return;
+	}
+
+	buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+	if (!buf)
+		goto send_reply;
+
+	buf->size = req.uSize;
+	buf->vaddr =
+		dma_alloc_coherent(dev, buf->size, &buf->paddr, GFP_KERNEL);
+	if (!buf->vaddr) {
+		dev_warn(dev, "Failed to allocate DMA buffer\n");
+		goto send_reply;
+	}
+
+	reply.reply.phyAddr = (u64)buf->paddr;
+	al_common_dma_buf_insert(codec, buf);
+
+send_reply:
+	ret = al_common_send(codec, &reply.hdr);
+	if (ret) {
+		al_codec_err(codec, "Unable to reply to cma alloc");
+		al_common_dma_buf_remove(codec, buf);
+	}
+}
+
+static void handle_free_memory_req(struct al_codec_dev *codec,
+				   struct msg_itf_header *hdr)
+{
+	struct msg_itf_free_mem_req req;
+	struct msg_itf_free_mem_reply_full reply = {
+		.hdr.type = MSG_ITF_TYPE_FREE_MEM_REPLY,
+		.hdr.drv_ctx_hdl = hdr->drv_ctx_hdl,
+		.hdr.drv_cmd_hdl = hdr->drv_cmd_hdl,
+		.hdr.payload_len = sizeof(struct msg_itf_free_mem_reply),
+		.reply.ret = -1,
+	};
+	struct codec_dma_buf *buf;
+	int ret;
+
+	ret = al_common_get_data(codec, (char *)&req, hdr->payload_len);
+	if (ret) {
+		al_codec_err(codec, "Unable to put cma req");
+		return;
+	}
+
+	buf = al_common_dma_buf_lookup(codec, req.phyAddr);
+	if (!buf) {
+		al_codec_err(codec, "Unable to get dma handle for %p",
+			     (void *)(long)req.phyAddr);
+		reply.reply.ret = -EINVAL;
+		goto send_reply;
+	}
+
+	al_codec_dbg(codec, "Free memory %p, size %d",
+		     (void *)(long)req.phyAddr, buf->size);
+
+	al_common_dma_buf_remove(codec, buf);
+	reply.reply.ret = 0;
+
+send_reply:
+	ret = al_common_send(codec, &reply.hdr);
+	if (ret)
+		al_codec_err(codec, "Unable to reply to cma free");
+}
+
+static void handle_mcu_console_print(struct al_codec_dev *codec,
+				     struct msg_itf_header *hdr)
+{
+	struct msg_itf_write_req *req;
+	int ret;
+
+	/* one more byte to be sure to have a zero terminated string */
+	req = kzalloc(hdr->payload_len + 1, GFP_KERNEL);
+	if (!req) {
+		al_common_skip_data(codec, hdr->payload_len);
+		al_codec_err(codec, "Unable to alloc memory");
+		return;
+	}
+
+	ret = al_codec_msg_get_data(&codec->mb_m2h, (char *)req,
+				    hdr->payload_len);
+	if (ret) {
+		al_codec_err(codec, "Unable to get request");
+		kfree(req);
+		return;
+	}
+
+	/* Print the mcu logs */
+	al_mcu_dbg(codec, "%s", (char *)(req + 1));
+	kfree(req);
+}
+
+static void process_one_message(struct al_codec_dev *codec,
+				struct msg_itf_header *hdr)
+{
+	switch (hdr->type) {
+	case MSG_ITF_TYPE_ALLOC_MEM_REQ:
+		handle_alloc_memory_req(codec, hdr);
+		break;
+	case MSG_ITF_TYPE_FREE_MEM_REQ:
+		handle_free_memory_req(codec, hdr);
+		break;
+	case MSG_ITF_TYPE_WRITE_REQ:
+		handle_mcu_console_print(codec, hdr);
+		break;
+	case MSG_ITF_TYPE_MCU_ALIVE:
+		complete(&codec->completion);
+		break;
+	default:
+		codec->process_msg_cb(codec->cb_arg, hdr);
+		break;
+	}
+}
+
+static irqreturn_t al_common_irq_handler(int irq, void *data)
+{
+	struct al_codec_dev *codec = data;
+	struct msg_itf_header hdr;
+
+	/* poll all messages */
+	while (al_codec_msg_get_header(&codec->mb_m2h, &hdr) == 0)
+		process_one_message(codec, &hdr);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t al_common_hardirq_handler(int irq, void *data)
+{
+	struct al_codec_dev *codec = data;
+
+	if (al_common_read(codec, AL_CODEC_IRQ_STATUS_CLEAR) == 0)
+		return IRQ_NONE;
+
+	al_common_write(codec, AL_CODEC_IRQ_STATUS_CLEAR,
+			AL_CODEC_IRQ_MCU_2_CPU);
+
+	return IRQ_WAKE_THREAD;
+}
+
+static int al_common_start_fw(struct al_codec_dev *codec)
+{
+	/* Enable the MCU clock */
+	al_common_write(codec, AL_CODEC_MCU_CLK, AL_CODEC_REG_ENABLE);
+
+	return !wait_for_completion_timeout(&codec->completion, 2 * HZ);
+}
+
+static void al_common_copy_firmware_image(struct al_codec_dev *codec)
+{
+	const struct firmware *firmware = codec->firmware.firmware;
+	u32 *virt = codec->firmware.virt;
+
+	/* copy the whole thing taking into account endianness */
+	for (size_t i = 0; i < firmware->size / sizeof(u32); i++)
+		virt[i] = le32_to_cpu(((__le32 *)firmware->data)[i]);
+}
+
+static int al_common_read_firmware(struct al_codec_dev *codec, const char *name)
+{
+	struct device *dev = &codec->pdev->dev;
+	const struct boot_header *bh;
+	int err;
+
+	/* request_firmware prints error if it fails */
+	err = request_firmware(&codec->firmware.firmware, name, dev);
+	if (err < 0)
+		return err;
+
+	bh = (struct boot_header *)codec->firmware.firmware->data;
+	codec->firmware.size = bh->vaddr_end - bh->vaddr_start;
+
+	return 0;
+}
+
+static int al_common_parse_firmware_image(struct al_codec_dev *codec)
+{
+	struct boot_header *bh = (void *)codec->firmware.virt;
+
+	if (bh->bh_version < AL_BOOT_VERSION(2, 0, 0) ||
+	    bh->bh_version >= AL_BOOT_VERSION(3, 0, 0)) {
+		al_codec_err(codec, "Unsupported firmware version");
+		return -EINVAL;
+	}
+
+	codec->firmware.bin_data.offset = bh->vaddr_boot - bh->vaddr_start;
+	codec->firmware.bin_data.size = bh->vaddr_end - bh->vaddr_start;
+
+	codec->firmware.mb_h2m.offset = bh->h2m.start - bh->vaddr_start;
+	codec->firmware.mb_h2m.size = bh->h2m.end - bh->h2m.start;
+	codec->firmware.mb_m2h.offset = bh->m2h.start - bh->vaddr_start;
+	codec->firmware.mb_m2h.size = bh->m2h.end - bh->m2h.start;
+
+	/* Override some data */
+	bh->ip_start = codec->apb + AL_CODEC_IP_OFFSET;
+	bh->ip_end = bh->ip_start + resource_size(codec->regs_info);
+	bh->mcu_clk_rate = clk_get_rate(codec->clk);
+
+	al_codec_dbg(codec, "bh version     = 0x%08x", bh->bh_version);
+	al_codec_dbg(codec, "fw version     = 0x%08x", bh->fw_version);
+	al_codec_dbg(codec, "fw model       = %s", bh->model);
+	al_codec_dbg(codec, "vaddress start = 0x%016llx", bh->vaddr_start);
+	al_codec_dbg(codec, "vaddress end   = 0x%016llx", bh->vaddr_end);
+	al_codec_dbg(codec, "boot address   = 0x%016llx", bh->vaddr_boot);
+	al_codec_dbg(codec, "machineid      = %lld", bh->machine_id);
+	al_codec_dbg(codec, "periph address = 0x%llx", (u64)codec->apb);
+	al_codec_dbg(codec, "ip start       = 0x%016llx", bh->ip_start);
+	al_codec_dbg(codec, "ip end         = 0x%016llx", bh->ip_end);
+	al_codec_dbg(codec, "mcu clk	      = %llu", bh->mcu_clk_rate);
+
+	return 0;
+}
+
+static int al_common_load_firmware_start(struct al_codec_dev *codec,
+					 const char *name)
+{
+	struct device *dev = &codec->pdev->dev;
+	dma_addr_t phys;
+	size_t size;
+	void *virt;
+	int err;
+
+	if (codec->firmware.virt)
+		return 0;
+
+	err = al_common_read_firmware(codec, name);
+	if (err)
+		return err;
+
+	size = codec->firmware.size;
+
+	virt = dma_alloc_coherent(dev, size, &phys, GFP_KERNEL);
+	err = dma_mapping_error(dev, phys);
+	if (err < 0)
+		return err;
+
+	codec->firmware.virt = virt;
+	codec->firmware.phys = phys;
+
+	al_common_copy_firmware_image(codec);
+	err = al_common_parse_firmware_image(codec);
+	if (err) {
+		al_codec_err(codec, "failed to parse firmware image");
+		goto cleanup;
+	}
+
+	err = al_common_setup_hw_regs(codec);
+	if (err) {
+		al_codec_err(codec, "Unable to setup hw registers");
+		goto cleanup;
+	}
+
+	al_codec_mb_init(&codec->mb_h2m, virt + codec->firmware.mb_h2m.offset,
+			 codec->firmware.mb_h2m.size, MB_IFT_MAGIC_H2M);
+
+	al_codec_mb_init(&codec->mb_m2h, virt + codec->firmware.mb_m2h.offset,
+			 codec->firmware.mb_m2h.size, MB_IFT_MAGIC_M2H);
+
+	err = al_common_start_fw(codec);
+	if (err) {
+		al_codec_err(codec, "fw start has failed");
+		goto cleanup;
+	}
+
+	al_codec_dbg(codec, "mcu has boot successfully !");
+	codec->fw_ready_cb(codec->cb_arg);
+
+	release_firmware(codec->firmware.firmware);
+	codec->firmware.firmware = NULL;
+
+	return 0;
+
+cleanup:
+	dma_free_coherent(dev, size, virt, phys);
+
+	return err;
+}
+
+static u64 al_common_get_periph_addr(struct al_codec_dev *codec)
+{
+	struct resource *res;
+
+	res = platform_get_resource_byname(codec->pdev, IORESOURCE_MEM, "apb");
+	if (!res) {
+		al_codec_err(codec, "Unable to find APB start address");
+		return 0;
+	}
+
+	if (res->start & AL_CODEC_APB_MASK) {
+		al_codec_err(codec, "APB start address is invalid");
+		return 0;
+	}
+
+	return res->start;
+}
+
+int al_common_probe(struct al_codec_dev *codec, const char *name)
+{
+	struct platform_device *pdev = codec->pdev;
+	int irq;
+	int ret;
+
+	mutex_init(&codec->buf_lock);
+	INIT_LIST_HEAD(&codec->alloc_buffers);
+	init_completion(&codec->completion);
+	codec->offset = 0;
+
+	/* setup dma memory */
+	ret = al_common_setup_dma(codec);
+	if (ret)
+		return ret;
+
+	/* Hw registers */
+	codec->regs_info =
+		platform_get_resource_byname(pdev, IORESOURCE_MEM, "top");
+	if (!codec->regs_info) {
+		al_codec_err(codec, "regs resource missing from device tree");
+		return -EINVAL;
+	}
+
+	codec->regs = devm_ioremap_resource(&pdev->dev, codec->regs_info);
+	if (!codec->regs) {
+		al_codec_err(codec, "failed to map registers");
+		return -ENOMEM;
+	}
+
+	codec->apb = al_common_get_periph_addr(codec);
+	if (!codec->apb)
+		return -EINVAL;
+
+	/* The MCU has already default clock value */
+	codec->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(codec->clk)) {
+		al_codec_err(codec, "failed to get MCU core clock");
+		return PTR_ERR(codec->clk);
+	}
+
+	ret = clk_prepare_enable(codec->clk);
+	if (ret) {
+		al_codec_err(codec, "Cannot enable MCU clock: %d\n", ret);
+		return ret;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		al_codec_err(codec, "Failed to get IRQ");
+		ret = -EINVAL;
+		goto disable_clk;
+	}
+
+	ret = devm_request_threaded_irq(&pdev->dev, irq,
+					al_common_hardirq_handler,
+					al_common_irq_handler, IRQF_SHARED,
+					dev_name(&pdev->dev), codec);
+	if (ret) {
+		al_codec_err(codec, "Unable to register irq handler");
+		goto disable_clk;
+	}
+
+	/* ok so request the fw */
+	ret = al_common_load_firmware_start(codec, name);
+	if (ret) {
+		al_codec_err(codec, "failed to load firmware : %s", name);
+		goto disable_clk;
+	}
+
+	return 0;
+
+disable_clk:
+	clk_disable_unprepare(codec->clk);
+
+	return ret;
+}
+
+int al_common_send(struct al_codec_dev *codec, struct msg_itf_header *hdr)
+{
+	return al_codec_msg_send(&codec->mb_h2m, hdr, al_common_trigger_mcu_irq,
+				 codec);
+}
+
+int al_common_send_req_reply(struct al_codec_dev *codec,
+			     struct list_head *cmd_list,
+			     struct msg_itf_header *hdr,
+			     struct al_common_mcu_req *req)
+{
+	struct al_codec_cmd *cmd = NULL;
+	int ret;
+
+	hdr->drv_cmd_hdl = 0;
+
+	if (req->reply_size && req->reply) {
+		cmd = al_codec_cmd_create(req->reply_size);
+		if (!cmd)
+			return -ENOMEM;
+
+		hdr->drv_cmd_hdl = al_virt_to_phys(cmd);
+	}
+
+	hdr->drv_ctx_hdl = req->pCtx;
+	hdr->type = req->req_type;
+	hdr->payload_len = req->req_size;
+
+	/* Add the list to the cmd list */
+	if (cmd)
+		list_add(&cmd->list, cmd_list);
+
+	ret = al_common_send(codec, hdr);
+	if (ret)
+		goto remove_cmd;
+
+	al_codec_dbg(codec, "Send req to mcu %d : %zu", req->req_type,
+		     req->req_size);
+
+	if (!cmd)
+		return 0;
+
+	ret = wait_for_completion_timeout(&cmd->done, 5 * HZ);
+	if (ret <= 0) {
+		al_codec_err(codec, "cmd %p has %d (%s)", cmd, ret,
+			     (ret == 0) ? "failed" : "timedout");
+		ret = -ETIMEDOUT;
+		goto remove_cmd;
+	}
+
+	ret = 0;
+	memcpy(req->reply, cmd->reply, req->reply_size);
+
+remove_cmd:
+
+	if (cmd) {
+		list_del(&cmd->list);
+		al_codec_cmd_put(cmd);
+	}
+	return ret;
+}
+
+bool al_common_mcu_is_alive(struct al_codec_dev *codec)
+{
+	static const struct msg_itf_header hdr = {
+		.type = MSG_ITF_TYPE_MCU_ALIVE,
+		.payload_len = 0,
+	};
+	int ret;
+
+	ret = al_common_send(codec, (struct msg_itf_header *)&hdr);
+	if (ret)
+		return false;
+
+	ret = wait_for_completion_timeout(&codec->completion, 5 * HZ);
+	if (ret <= 0)
+		return false;
+
+	return true;
+}
diff --git a/drivers/media/platform/allegro-dvt/al300/al_codec_common.h b/drivers/media/platform/allegro-dvt/al300/al_codec_common.h
new file mode 100644
index 000000000000..0d2f8d788a73
--- /dev/null
+++ b/drivers/media/platform/allegro-dvt/al300/al_codec_common.h
@@ -0,0 +1,252 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2025 Allegro DVT.
+ * Author: Yassine OUAISSA <yassine.ouaissa at allegrodvt.fr>
+ */
+
+#ifndef __AL_CODEC_COMMON__
+#define __AL_CODEC_COMMON__
+
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <media/v4l2-device.h>
+
+#include "al_codec_dbgfs.h"
+#include "al_codec_util.h"
+
+#define fh_to_ctx(ptr, type) container_of(ptr, type, fh)
+
+enum {
+	MSG_ITF_TYPE_CREATE_INST_REQ = MSG_ITF_TYPE_NEXT_REQ,
+	MSG_ITF_TYPE_DESTROY_INST_REQ,
+	MSG_ITF_TYPE_PUSH_BITSTREAM_BUFFER_REQ,
+	MSG_ITF_TYPE_PUT_DISPLAY_PICTURE_REQ,
+	MSG_ITF_TYPE_FLUSH_REQ,
+	MSG_ITF_TYPE_INFO_REQ,
+	MSG_ITF_TYPE_CREATE_INST_REPLY = MSG_ITF_TYPE_NEXT_REPLY,
+	MSG_ITF_TYPE_DESTROY_INST_REPLY,
+	MSG_ITF_TYPE_PUSH_BITSTREAM_BUFFER_REPLY,
+	MSG_ITF_TYPE_PUT_DISPLAY_PICTURE_REPLY,
+	MSG_ITF_TYPE_FLUSH_REPLY,
+	MSG_ITF_TYPE_INFO_REPLY,
+	MSG_ITF_TYPE_EVT_ERROR = MSG_ITF_TYPE_NEXT_EVT,
+};
+
+struct msg_itf_write_req {
+	u32 fd;
+	u32 len;
+	/* payload follow */
+} __packed;
+DECLARE_FULL_REQ(msg_itf_write_req);
+
+struct msg_itf_free_mem_req {
+	phys_addr_t phyAddr;
+} __packed;
+DECLARE_FULL_REQ(msg_itf_free_mem_req);
+
+struct msg_itf_alloc_mem_req {
+	u64 uSize;
+} __packed;
+DECLARE_FULL_REQ(msg_itf_alloc_mem_req);
+
+struct msg_itf_alloc_mem_reply {
+	phys_addr_t phyAddr;
+} __packed;
+DECLARE_FULL_REPLY(msg_itf_alloc_mem_reply);
+
+struct msg_itf_free_mem_reply {
+	s64 ret;
+};
+DECLARE_FULL_REPLY(msg_itf_free_mem_reply);
+
+struct msg_itf_create_codec_reply {
+	phys_addr_t hCodec;
+	s32 ret;
+} __packed;
+DECLARE_FULL_REPLY(msg_itf_create_codec_reply);
+
+struct msg_itf_destroy_codec_req {
+	phys_addr_t hCodec;
+} __packed;
+DECLARE_FULL_REQ(msg_itf_destroy_codec_req);
+
+/*
+ * Note : no need to know the status of this request
+ * The codec should be destroyed, in case of the mcu
+ * hasn't received any request with the codec handler
+ */
+struct msg_itf_destroy_codec_reply {
+	u32 unused;
+} __packed;
+DECLARE_FULL_REPLY(msg_itf_destroy_codec_reply);
+
+struct al_buffer_meta {
+	u64 timestamp;
+	struct v4l2_timecode timecode;
+	bool last;
+};
+
+struct msg_itf_push_src_buf_req {
+	phys_addr_t hCodec;
+	phys_addr_t bufferHandle;
+	phys_addr_t phyAddr;
+	u64 size;
+	struct al_buffer_meta meta;
+} __packed;
+DECLARE_FULL_REQ(msg_itf_push_src_buf_req);
+
+struct msg_itf_push_dst_buf_req {
+	phys_addr_t hCodec;
+	phys_addr_t bufferHandle;
+	phys_addr_t phyAddr;
+	u64 size;
+} __packed;
+DECLARE_FULL_REQ(msg_itf_push_dst_buf_req);
+
+struct msg_itf_push_buffer_req {
+	phys_addr_t hCodec;
+	phys_addr_t bufferHandle;
+	phys_addr_t phyAddr;
+	u64 size;
+} __packed;
+DECLARE_FULL_REQ(msg_itf_push_buffer_req);
+
+struct msg_itf_push_buffer_reply {
+	s32 res;
+} __packed;
+DECLARE_FULL_REPLY(msg_itf_push_buffer_reply);
+
+struct msg_itf_info_req {
+	u64 unused;
+} __packed;
+DECLARE_FULL_REQ(msg_itf_info_req);
+
+struct msg_itf_flush_req {
+	phys_addr_t hCodec;
+} __packed;
+DECLARE_FULL_REQ(msg_itf_flush_req);
+
+struct msg_itf_flush_reply {
+	int32_t unused;
+} __packed;
+DECLARE_FULL_REPLY(msg_itf_flush_reply);
+
+struct msg_itf_evt_error {
+	uint32_t errno;
+} __packed;
+DECLARE_FULL_EVENT(msg_itf_evt_error);
+
+struct al_match_data {
+	const char *fw_name;
+};
+
+struct al_common_mcu_req {
+	phys_addr_t pCtx;
+	int req_type;
+	size_t req_size;
+	size_t reply_size;
+	void *reply;
+} __packed;
+
+struct al_firmware_section {
+	u64 offset;
+	size_t size;
+};
+
+struct al_firmware {
+	/* Firmware after it is read but not loaded */
+	const struct firmware *firmware;
+
+	/* Raw firmware data */
+	dma_addr_t phys;
+	void *virt;
+	size_t size;
+
+	/* Parsed firmware information */
+	struct al_firmware_section bin_data;
+	struct al_firmware_section mb_m2h;
+	struct al_firmware_section mb_h2m;
+};
+
+struct al_codec_dev {
+	struct platform_device *pdev;
+	struct v4l2_device v4l2_dev;
+	struct v4l2_m2m_dev *m2m_dev;
+	struct video_device video_dev;
+
+	/* Firmware */
+	struct al_firmware firmware;
+	dma_addr_t apb;
+
+	struct clk *clk;
+	void __iomem *regs;
+	struct resource *regs_info;
+	u64 offset;
+
+	/* Mailbox structs */
+	struct al_codec_mb mb_h2m;
+	struct al_codec_mb mb_m2h;
+
+	/* list of buffers used by the MCU */
+	struct list_head alloc_buffers;
+	struct mutex buf_lock;
+
+	/* mutex protecting vb2_queue structure */
+	struct mutex lock;
+
+	/* list of ctx (aka decoder) */
+	struct mutex ctx_mlock;
+	struct list_head ctx_q_list;
+	struct al_codec_dbgfs dbgfs;
+	u64 ctx_counter;
+	bool init_done;
+
+	/* list of cap/out supported formats */
+	struct list_head codec_q_list;
+	struct al_codec_cmd *codec_info_cmd;
+
+	/* Command completion */
+	struct completion completion;
+	/* Resolution found completion */
+	struct completion res_done;
+
+	/* callbacks set by client before common_probe */
+	void *cb_arg;
+	void (*process_msg_cb)(void *cb_arg, struct msg_itf_header *hdr);
+	void (*fw_ready_cb)(void *cb_arg);
+};
+
+static inline int al_common_get_header(struct al_codec_dev *codec,
+				       struct msg_itf_header *hdr)
+{
+	return al_codec_msg_get_header(&codec->mb_m2h, hdr);
+}
+
+static inline int al_common_get_data(struct al_codec_dev *codec, char *data,
+				     int len)
+{
+	return al_codec_msg_get_data(&codec->mb_m2h, data, len);
+}
+
+static inline int al_common_skip_data(struct al_codec_dev *codec, int len)
+{
+	return al_common_get_data(codec, NULL, len);
+}
+
+int al_common_send(struct al_codec_dev *codec, struct msg_itf_header *hdr);
+int al_common_send_req_reply(struct al_codec_dev *codec,
+			     struct list_head *cmd_list,
+			     struct msg_itf_header *hdr,
+			     struct al_common_mcu_req *req);
+bool al_common_mcu_is_alive(struct al_codec_dev *codec);
+
+int al_common_probe(struct al_codec_dev *codec, const char *name);
+void al_common_remove(struct al_codec_dev *codec);
+
+#endif /*__AL_CODEC_COMMON__*/
diff --git a/drivers/media/platform/allegro-dvt/al300/al_codec_dbgfs.c b/drivers/media/platform/allegro-dvt/al300/al_codec_dbgfs.c
new file mode 100644
index 000000000000..9a9264d2aa22
--- /dev/null
+++ b/drivers/media/platform/allegro-dvt/al300/al_codec_dbgfs.c
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2025 Allegro DVT.
+ * Author: Yassine OUAISSA <yassine.ouaissa at allegrodvt.fr>
+ */
+
+#include <linux/debugfs.h>
+
+#include "al_codec_dbgfs.h"
+#include "al_vdec_drv.h"
+#include "al_codec_util.h"
+
+static void al_vdec_dbgfs_get_format_type(struct al_dec_ctx *ctx, char *buf,
+					  int *used, int total)
+{
+	struct al_frame *frame = &ctx->src;
+	int curr_len;
+
+	switch (frame->fmt->pixelformat) {
+	case V4L2_PIX_FMT_H264:
+		curr_len = snprintf(buf + *used, total - *used,
+				    "\toutput format: h264\n");
+		break;
+	case V4L2_PIX_FMT_HEVC:
+		curr_len = snprintf(buf + *used, total - *used,
+				    "\toutput format: hevc\n");
+		break;
+	case V4L2_PIX_FMT_JPEG:
+		curr_len = snprintf(buf + *used, total - *used,
+				    "\toutput format: jpeg\n");
+		break;
+	default:
+		curr_len = snprintf(buf + *used, total - *used,
+				    "\tunsupported output format: 0x%x\n",
+				    frame->fmt->pixelformat);
+	}
+	*used += curr_len;
+	frame = &ctx->dst;
+
+	switch (frame->fmt->pixelformat) {
+	case V4L2_PIX_FMT_NV12:
+		curr_len = snprintf(buf + *used, total - *used,
+				    "\tcapture format: NV12\n");
+		break;
+	case V4L2_PIX_FMT_NV16:
+		curr_len = snprintf(buf + *used, total - *used,
+				    "\tcapture format: NV16\n");
+		break;
+	case V4L2_PIX_FMT_P010:
+		curr_len = snprintf(buf + *used, total - *used,
+				    "\tcapture format: P010\n");
+		break;
+	case V4L2_PIX_FMT_YUV420:
+		curr_len = snprintf(buf + *used, total - *used,
+				    "\tcapture format: YUV420\n");
+		break;
+	case V4L2_PIX_FMT_YVU420:
+		curr_len = snprintf(buf + *used, total - *used,
+				    "\tcapture format: YVU420\n");
+		break;
+	default:
+		curr_len = snprintf(buf + *used, total - *used,
+				    "\tunsupported capture format: 0x%x\n",
+				    frame->fmt->pixelformat);
+	}
+	*used += curr_len;
+}
+
+static void al_vdec_dbgfs_get_help(char *buf, int *used, int total)
+{
+	int curr_len;
+
+	curr_len = snprintf(buf + *used, total - *used,
+			    "help: (1: echo -'info' > dec 2: cat dec)\n");
+	*used += curr_len;
+
+	curr_len = snprintf(buf + *used, total - *used,
+			    "\t-picinfo: get resolution\n");
+	*used += curr_len;
+
+	curr_len = snprintf(buf + *used, total - *used,
+			    "\t-format: get output & capture queue format\n");
+	*used += curr_len;
+}
+
+static ssize_t al_vdec_dbgfs_write(struct file *filp, const char __user *ubuf,
+				   size_t count, loff_t *ppos)
+{
+	struct al_codec_dev *codec = filp->private_data;
+	struct al_codec_dbgfs *dbgfs = &codec->dbgfs;
+
+	mutex_lock(&dbgfs->lock);
+	dbgfs->size = simple_write_to_buffer(dbgfs->buf, sizeof(dbgfs->buf),
+					     ppos, ubuf, count);
+	mutex_unlock(&dbgfs->lock);
+	if (dbgfs->size > 0)
+		return count;
+
+	return dbgfs->size;
+}
+
+static ssize_t al_vdec_dbgfs_read(struct file *filp, char __user *ubuf,
+				  size_t count, loff_t *ppos)
+{
+	struct al_codec_dev *codec = filp->private_data;
+	struct al_codec_dbgfs *dbgfs = &codec->dbgfs;
+	struct al_codec_dbgfs_ctx *dbgfs_ctx;
+	struct al_dec_ctx *ctx;
+	struct al_frame *frame;
+	int total_len = 200 * (dbgfs->ctx_count == 0 ? 1 : dbgfs->ctx_count);
+	int used_len = 0, curr_len, ret;
+	bool dbgfs_index[AL_VDEC_DBGFS_MAX] = { 0 };
+	char *buf = kmalloc(total_len, GFP_KERNEL);
+
+	if (!buf)
+		return -ENOMEM;
+
+	if (strstr(dbgfs->buf, "-help") || dbgfs->size == 1) {
+		al_vdec_dbgfs_get_help(buf, &used_len, total_len);
+		goto read_buffer;
+	}
+
+	if (strstr(dbgfs->buf, "-picinfo"))
+		dbgfs_index[AL_VDEC_DBGFS_PICINFO] = true;
+
+	if (strstr(dbgfs->buf, "-format"))
+		dbgfs_index[AL_VDEC_DBGFS_FORMAT] = true;
+
+	mutex_lock(&dbgfs->lock);
+	list_for_each_entry(dbgfs_ctx, &dbgfs->dbgfs_head, node) {
+		ctx = dbgfs_ctx->dec_ctx;
+		frame = &ctx->src;
+
+		curr_len = snprintf(buf + used_len, total_len - used_len,
+				    "inst[%lld]:\n ", ctx->id);
+		used_len += curr_len;
+
+		if (dbgfs_index[AL_VDEC_DBGFS_PICINFO]) {
+			curr_len = snprintf(buf + used_len,
+					    total_len - used_len,
+					    "\tOUTPUT: %dx%d\n", frame->width,
+					    frame->height);
+			used_len += curr_len;
+			frame = &ctx->dst;
+
+			curr_len = snprintf(buf + used_len,
+					    total_len - used_len,
+					    "\tCAPTURE: %dx%d\n", frame->width,
+					    frame->height);
+			used_len += curr_len;
+		}
+
+		if (dbgfs_index[AL_VDEC_DBGFS_FORMAT])
+			al_vdec_dbgfs_get_format_type(ctx, buf, &used_len,
+						      total_len);
+	}
+	mutex_unlock(&dbgfs->lock);
+read_buffer:
+	ret = simple_read_from_buffer(ubuf, count, ppos, buf, used_len);
+	kfree(buf);
+	return ret;
+}
+
+static const struct file_operations vdec_fops = {
+	.open = simple_open,
+	.write = al_vdec_dbgfs_write,
+	.read = al_vdec_dbgfs_read,
+};
+
+void al_codec_dbgfs_create(struct al_dec_ctx *ctx)
+{
+	struct al_codec_dbgfs_ctx *dbgfs_ctx;
+	struct al_codec_dev *codec = ctx->codec;
+
+	dbgfs_ctx = kzalloc(sizeof(*dbgfs_ctx), GFP_KERNEL);
+	if (!dbgfs_ctx)
+		return;
+
+	list_add_tail(&dbgfs_ctx->node, &codec->dbgfs.dbgfs_head);
+
+	codec->dbgfs.ctx_count++;
+
+	dbgfs_ctx->ctx_id = ctx->id;
+	dbgfs_ctx->dec_ctx = ctx;
+}
+
+void al_codec_dbgfs_remove(struct al_codec_dev *codec, int ctx_id)
+{
+	struct al_codec_dbgfs_ctx *dbgfs_ctx;
+
+	list_for_each_entry(dbgfs_ctx, &codec->dbgfs.dbgfs_head, node) {
+		if (dbgfs_ctx->ctx_id == ctx_id) {
+			codec->dbgfs.ctx_count--;
+			list_del(&dbgfs_ctx->node);
+			kfree(dbgfs_ctx);
+			return;
+		}
+	}
+}
+
+static void al_codec_dbgfs_vdec_init(struct al_codec_dev *codec)
+{
+	struct dentry *vcodec_root;
+
+	codec->dbgfs.vcodec_root = debugfs_create_dir("al-vdec", NULL);
+	if (IS_ERR(codec->dbgfs.vcodec_root))
+		dev_err(&codec->pdev->dev, "create al-vdec dir err:%ld\n",
+			PTR_ERR(codec->dbgfs.vcodec_root));
+
+	vcodec_root = codec->dbgfs.vcodec_root;
+	debugfs_create_x32("al_v4l2_dbg_level", 0644, vcodec_root,
+			   &al_v4l2_dbg_level);
+	debugfs_create_x32("al_codec_dbg", 0644, vcodec_root, &al_codec_dbg);
+
+	codec->dbgfs.ctx_count = 0;
+	INIT_LIST_HEAD(&codec->dbgfs.dbgfs_head);
+	debugfs_create_file("vdec", 0200, vcodec_root, codec, &vdec_fops);
+	mutex_init(&codec->dbgfs.lock);
+}
+
+void al_codec_dbgfs_init(void *codec)
+{
+	al_codec_dbgfs_vdec_init(codec);
+}
+
+void al_codec_dbgfs_deinit(struct al_codec_dbgfs *dbgfs)
+{
+	debugfs_remove_recursive(dbgfs->vcodec_root);
+}
diff --git a/drivers/media/platform/allegro-dvt/al300/al_codec_dbgfs.h b/drivers/media/platform/allegro-dvt/al300/al_codec_dbgfs.h
new file mode 100644
index 000000000000..0f205e505308
--- /dev/null
+++ b/drivers/media/platform/allegro-dvt/al300/al_codec_dbgfs.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2025 Allegro DVT.
+ * Author: Yassine OUAISSA <yassine.ouaissa at allegrodvt.fr>
+ */
+
+#ifndef __AL_CODEC_DBGFS_H__
+#define __AL_CODEC_DBGFS_H__
+
+struct al_codec_dev;
+struct al_dec_ctx;
+
+/*
+ * enum al_vdec_dbgfs_log_index  - used to get different debug information
+ */
+enum al_vdec_dbgfs_log_index {
+	AL_VDEC_DBGFS_PICINFO,
+	AL_VDEC_DBGFS_FORMAT,
+	AL_VDEC_DBGFS_MAX,
+};
+
+/**
+ * struct al_codec_dbgfs_ctx  - debugfs information for each context
+ * @node:       list node for each inst
+ * @dec_ctx:	struct al_dec_ctx
+ * @ctx_id:     index of the context that the same with ctx->id
+ */
+struct al_codec_dbgfs_ctx {
+	struct list_head node;
+	struct al_dec_ctx *dec_ctx;
+	int ctx_id;
+};
+
+/**
+ * struct al_codec_dbgfs  - dbgfs information
+ * @dbgfs_head:  list head used to link each context
+ * @vcodec_root: codec dbgfs entry
+ * @lock:	 lock used to protect dbgfs_buf
+ * @buf:	 dbgfs buf used to store dbgfs cmd
+ * @size:	 dbgfs buffer size
+ * @ctx_count:   the count of total context
+ */
+struct al_codec_dbgfs {
+	struct list_head dbgfs_head;
+	struct dentry *vcodec_root;
+	struct mutex lock;
+	char buf[1024];
+	int size;
+	int ctx_count;
+};
+
+#if defined(CONFIG_DEBUG_FS)
+void al_codec_dbgfs_create(struct al_dec_ctx *ctx);
+void al_codec_dbgfs_remove(struct al_codec_dev *codec, int ctx_id);
+void al_codec_dbgfs_init(void *codec);
+void al_codec_dbgfs_deinit(struct al_codec_dbgfs *dbgfs);
+#else
+static inline void al_codec_dbgfs_create(struct al_dec_ctx *ctx)
+{
+}
+static inline void al_codec_dbgfs_remove(struct al_codec_dev *codec, int ctx_id)
+{
+}
+static inline void al_codec_dbgfs_init(void *codec)
+{
+}
+static inline void al_codec_dbgfs_deinit(struct al_codec_dbgfs *dbgfs)
+{
+}
+#endif /* CONFIG_DEBUG_FS */
+#endif /* __AL_CODEC_DBGFS_H__ */
diff --git a/drivers/media/platform/allegro-dvt/al300/al_codec_util.c b/drivers/media/platform/allegro-dvt/al300/al_codec_util.c
new file mode 100644
index 000000000000..f59fedae0491
--- /dev/null
+++ b/drivers/media/platform/allegro-dvt/al300/al_codec_util.c
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Mailbox communication utilities for command creation
+ * and message exchange with the MCU
+ *
+ * Copyright (c) 2025 Allegro DVT.
+ * Author: Yassine OUAISSA <yassine.ouaissa at allegrodvt.fr>
+ */
+
+#include <asm-generic/errno.h>
+#include <linux/errno.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+
+#include "al_codec_util.h"
+
+#if defined(CONFIG_DEBUG_FS)
+/* Log level */
+int al_v4l2_dbg_level;
+int al_codec_dbg;
+#endif
+
+static int al_get_used_space(struct al_codec_mb *mb)
+{
+	u32 head = mb->hdr->head;
+	u32 tail = mb->hdr->tail;
+
+	return head >= tail ? head - tail : mb->size - (tail - head);
+}
+
+static int al_get_free_space(struct al_codec_mb *mb)
+{
+	return mb->size - al_get_used_space(mb) - 1;
+}
+
+static int al_has_enough_space(struct al_codec_mb *mb, int len)
+{
+	return al_get_free_space(mb) >= len;
+}
+
+static inline void al_copy_to_mb(struct al_codec_mb *mb, char *data, int len)
+{
+	u32 head = mb->hdr->head;
+	int copy_len = min(mb->size - head, (unsigned int)len);
+	int copied_len = len;
+
+	memcpy(&mb->data[head], data, copy_len);
+	len -= copy_len;
+	if (len)
+		memcpy(&mb->data[0], &data[copy_len], len);
+
+	/* Make sure that all messages are written before updating the head */
+	dma_wmb();
+	mb->hdr->head = (head + copied_len) % mb->size;
+	/* Make sure that the head is updated in DDR instead of cache */
+	dma_wmb();
+}
+
+static inline void al_copy_from_mb(struct al_codec_mb *mb, char *data, int len)
+{
+	u32 tail = mb->hdr->tail;
+	int copy_len = min(mb->size - tail, (unsigned int)len);
+	int copied_len = len;
+
+	if (!data)
+		goto update_tail;
+
+	memcpy(data, &mb->data[tail], copy_len);
+	len -= copy_len;
+	if (len)
+		memcpy(&data[copy_len], &mb->data[0], len);
+
+update_tail:
+	mb->hdr->tail = (tail + copied_len) % mb->size;
+	/* Make sure that the head is updated in DDR instead of cache */
+	dma_wmb();
+}
+
+static int al_codec_mb_send(struct al_codec_mb *mb, char *data, int len)
+{
+	if (!al_has_enough_space(mb, len))
+		return -ENOMEM;
+
+	al_copy_to_mb(mb, data, len);
+
+	return 0;
+}
+
+static int al_codec_mb_receive(struct al_codec_mb *mb, char *data, int len)
+{
+	if (al_get_used_space(mb) < len)
+		return -ENOMEM;
+
+	al_copy_from_mb(mb, data, len);
+
+	return 0;
+}
+
+void al_codec_mb_init(struct al_codec_mb *mb, char *addr, int size, u32 magic)
+{
+	mb->hdr = (struct al_mb_itf *)addr;
+	mb->hdr->magic = magic;
+	mb->hdr->version = MB_IFT_VERSION;
+	mb->hdr->head = 0;
+	mb->hdr->tail = 0;
+	mb->data = addr + sizeof(struct al_mb_itf);
+	mb->size = size - sizeof(struct al_mb_itf);
+	mutex_init(&mb->lock);
+}
+
+int al_codec_msg_get_header(struct al_codec_mb *mb, struct msg_itf_header *hdr)
+{
+	return al_codec_mb_receive(mb, (char *)hdr, sizeof(*hdr));
+}
+
+int al_codec_msg_get_data(struct al_codec_mb *mb, char *data, int len)
+{
+	return al_codec_mb_receive(mb, data, len);
+}
+
+int al_codec_msg_send(struct al_codec_mb *mb, struct msg_itf_header *hdr,
+		      void (*trigger)(void *), void *trigger_arg)
+{
+	const unsigned long timeout = jiffies + HZ;
+	int ret;
+
+	guard(mutex)(&mb->lock);
+	do {
+		if (time_after(jiffies, timeout))
+			return -ETIMEDOUT;
+
+		ret = al_codec_mb_send(mb, (char *)hdr,
+				       hdr->payload_len +
+					       sizeof(struct msg_itf_header));
+
+	} while (ret);
+
+	trigger(trigger_arg);
+
+	return 0;
+}
+
+static void al_codec_cmd_cleanup(struct kref *ref)
+{
+	struct al_codec_cmd *cmd = container_of(ref, typeof(*cmd), refcount);
+
+	kfree(cmd->reply);
+	kfree(cmd);
+}
+
+void al_codec_cmd_put(struct al_codec_cmd *cmd)
+{
+	if (WARN_ON(!cmd))
+		return;
+
+	kref_put(&cmd->refcount, al_codec_cmd_cleanup);
+}
+
+struct al_codec_cmd *al_codec_cmd_create(int reply_size)
+{
+	struct al_codec_cmd *cmd;
+
+	cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
+	if (!cmd)
+		return NULL;
+
+	cmd->reply = kmalloc(reply_size, GFP_KERNEL);
+	if (!cmd->reply) {
+		kfree(cmd);
+		return NULL;
+	}
+
+	kref_init(&cmd->refcount);
+	cmd->reply_size = reply_size;
+	init_completion(&cmd->done);
+
+	return cmd;
+}
diff --git a/drivers/media/platform/allegro-dvt/al300/al_codec_util.h b/drivers/media/platform/allegro-dvt/al300/al_codec_util.h
new file mode 100644
index 000000000000..a4d50792dbd6
--- /dev/null
+++ b/drivers/media/platform/allegro-dvt/al300/al_codec_util.h
@@ -0,0 +1,196 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2025 Allegro DVT.
+ * Author: Yassine OUAISSA <yassine.ouaissa at allegrodvt.fr>
+ */
+
+#ifndef __AL_CODEC_UTIL__
+#define __AL_CODEC_UTIL__
+
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/v4l2-common.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-v4l2.h>
+
+#define MB_IFT_MAGIC_H2M 0xabcd1230
+#define MB_IFT_MAGIC_M2H 0xabcd1231
+#define MB_IFT_VERSION 0x00010000
+
+#define MAJOR_SHIFT 20
+#define MAJOR_MASK 0xfff
+#define MINOR_SHIFT 8
+#define MINOR_MASK 0xfff
+#define PATCH_SHIFT 0
+#define PATCH_MASK 0xff
+
+/*
+ * AL_BOOT_VERSION() - Version format 32-bit, 12 bits for the major,
+ * the same for minor, 8bits for the patch
+ */
+#define AL_BOOT_VERSION(major, minor, patch)       \
+	((((major) & MAJOR_MASK) << MAJOR_SHIFT) | \
+	 (((minor) & MINOR_MASK) << MINOR_SHIFT) | \
+	 (((patch) & PATCH_MASK) << PATCH_SHIFT))
+
+#define al_phys_to_virt(x) ((void *)(uintptr_t)x)
+#define al_virt_to_phys(x) ((phys_addr_t)(uintptr_t)x)
+
+#define DECLARE_FULL_REQ(s)                \
+	struct s##_full {                  \
+		struct msg_itf_header hdr; \
+		struct s req;              \
+	} __packed
+
+#define DECLARE_FULL_REPLY(s)              \
+	struct s##_full {                  \
+		struct msg_itf_header hdr; \
+		struct s reply;            \
+	} __packed
+
+#define DECLARE_FULL_EVENT(s)              \
+	struct s##_full {                  \
+		struct msg_itf_header hdr; \
+		struct s event;            \
+	} __packed
+
+struct al_mb_itf {
+	u32 magic;
+	u32 version;
+	u32 head;
+	u32 tail;
+} __packed;
+
+struct al_codec_mb {
+	struct al_mb_itf *hdr;
+	struct mutex lock;
+	char *data;
+	int size;
+};
+
+struct al_codec_cmd {
+	struct kref refcount;
+	struct list_head list;
+	struct completion done;
+	int reply_size;
+	void *reply;
+};
+
+#define al_codec_err(codec, fmt, args...)                                     \
+	dev_err(&(codec)->pdev->dev, "[ALG_CODEC][ERROR] %s():%d: " fmt "\n", \
+		__func__, __LINE__, ##args)
+
+#define al_v4l2_err(codec, fmt, args...)                                     \
+	dev_err(&(codec)->pdev->dev, "[ALG_V4L2][ERROR] %s():%d: " fmt "\n", \
+		__func__, __LINE__, ##args)
+
+#if defined(CONFIG_DEBUG_FS)
+/* Log level */
+extern int al_v4l2_dbg_level;
+extern int al_codec_dbg;
+
+/* V4L2 logs */
+#define al_v4l2_dbg(codec, level, fmt, args...)                           \
+	do {                                                              \
+		if (al_v4l2_dbg_level >= level)                           \
+			dev_dbg(&(codec)->pdev->dev,                      \
+				"[ALG_V4L2] level=%d %s(),%d: " fmt "\n", \
+				level, __func__, __LINE__, ##args);       \
+	} while (0)
+
+/* Codec logs */
+#define al_codec_dbg(codec, fmt, args...)                                   \
+	do {                                                                \
+		if (al_codec_dbg)                                           \
+			dev_dbg(&(codec)->pdev->dev,                        \
+				"[ALG_CODEC] %s(),%d: " fmt "\n", __func__, \
+				__LINE__, ##args);                          \
+	} while (0)
+
+#define al_mcu_dbg(codec, fmt, args...)                                   \
+	do {                                                              \
+		if (al_codec_dbg)                                         \
+			dev_dbg(&(codec)->pdev->dev,                      \
+				"[ALG_MCU] %s(),%d: " fmt "\n", __func__, \
+				__LINE__, ##args);                        \
+	} while (0)
+
+#else
+
+#define al_v4l2_dbg(codec, level, fmt, args...)                                \
+	do {                                                                   \
+		(void)level;                                                   \
+		dev_dbg(&(codec)->pdev->dev, "[ALG_V4L2]: " fmt "\n", ##args); \
+	} while (0)
+
+#define al_codec_dbg(codec, fmt, args...) \
+	dev_dbg(&(codec)->pdev->dev, "[ALG_CODEC]: " fmt "\n", ##args)
+
+#define al_mcu_dbg(codec, fmt, args...) \
+	dev_dbg(&(codec)->pdev->dev, "[ALG_MCU]: " fmt "\n", ##args)
+
+#endif
+
+#define MSG_ITF_TYPE_LIMIT BIT(10)
+
+/* Message types host <-> mcu */
+enum {
+	MSG_ITF_TYPE_MCU_ALIVE = 0,
+	MSG_ITF_TYPE_WRITE_REQ = 2,
+	MSG_ITF_TYPE_FIRST_REQ = 1024,
+	MSG_ITF_TYPE_NEXT_REQ,
+	MSG_ITF_TYPE_FIRST_REPLY = 2048,
+	MSG_ITF_TYPE_NEXT_REPLY,
+	MSG_ITF_TYPE_ALLOC_MEM_REQ = 3072,
+	MSG_ITF_TYPE_FREE_MEM_REQ,
+	MSG_ITF_TYPE_ALLOC_MEM_REPLY = 4096,
+	MSG_ITF_TYPE_FREE_MEM_REPLY,
+	MSG_ITF_TYPE_FIRST_EVT = 5120,
+	MSG_ITF_TYPE_NEXT_EVT = MSG_ITF_TYPE_FIRST_EVT
+};
+
+struct msg_itf_header {
+	u64 drv_ctx_hdl;
+	u64 drv_cmd_hdl;
+	u16 type;
+	u16 payload_len;
+	u16 padding[2];
+} __packed;
+
+void al_codec_mb_init(struct al_codec_mb *mb, char *addr, int size, u32 magic);
+int al_codec_msg_get_header(struct al_codec_mb *mb, struct msg_itf_header *hdr);
+int al_codec_msg_get_data(struct al_codec_mb *mb, char *data, int len);
+int al_codec_msg_send(struct al_codec_mb *mb, struct msg_itf_header *hdr,
+		      void (*trigger)(void *), void *trigger_arg);
+
+static inline bool is_type_reply(uint16_t type)
+{
+	return type >= MSG_ITF_TYPE_FIRST_REPLY &&
+	       type < MSG_ITF_TYPE_FIRST_REPLY + MSG_ITF_TYPE_LIMIT;
+}
+
+static inline bool is_type_event(uint16_t type)
+{
+	return type >= MSG_ITF_TYPE_FIRST_EVT &&
+	       type < MSG_ITF_TYPE_FIRST_EVT + MSG_ITF_TYPE_LIMIT;
+}
+
+void al_codec_cmd_put(struct al_codec_cmd *cmd);
+
+struct al_codec_cmd *al_codec_cmd_create(int reply_size);
+
+static inline struct al_codec_cmd *al_codec_cmd_get(struct list_head *cmd_list,
+						    uint64_t hdl)
+{
+	struct al_codec_cmd *cmd = NULL;
+
+	list_for_each_entry(cmd, cmd_list, list) {
+		if (likely(cmd == al_phys_to_virt(hdl))) {
+			kref_get(&cmd->refcount);
+			break;
+		}
+	}
+	return list_entry_is_head(cmd, cmd_list, list) ? NULL : cmd;
+}
+
+#endif /* __AL_CODEC_UTIL__ */
diff --git a/drivers/media/platform/allegro-dvt/al300/al_vdec_drv.c b/drivers/media/platform/allegro-dvt/al300/al_vdec_drv.c
new file mode 100644
index 000000000000..66303efd6984
--- /dev/null
+++ b/drivers/media/platform/allegro-dvt/al300/al_vdec_drv.c
@@ -0,0 +1,1514 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2025 Allegro DVT.
+ * Author: Yassine OUAISSA <yassine.ouaissa at allegrodvt.fr>
+ *
+ * Allegro DVT stateful video decoder driver for the IP Gen 3
+ */
+
+#include <asm-generic/errno-base.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/string.h>
+#include <linux/v4l2-controls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "al_vdec_drv.h"
+
+/* default decoder params */
+#define DECODER_WIDTH_DEFAULT 640
+#define DECODER_HEIGHT_DEFAULT 480
+#define DECODER_WIDTH_MAX 3840
+#define DECODER_HEIGHT_MAX 2160
+#define DECODER_WIDTH_MIN 16
+#define DECODER_HEIGHT_MIN 16
+#define DEC_REQ_TIMEOUT msecs_to_jiffies(1000)
+#define DEC_RES_EVT_TIMEOUT DEC_REQ_TIMEOUT
+
+/* Supported formats */
+static const struct al_fmt al_src_formats[] = {
+	{
+		.pixelformat = V4L2_PIX_FMT_H264,
+		.bpp = 20,
+	},
+	{
+		.pixelformat = V4L2_PIX_FMT_HEVC,
+		.bpp = 20,
+	},
+	{
+		.pixelformat = V4L2_PIX_FMT_JPEG,
+		.bpp = 8,
+	}
+};
+
+static const struct al_fmt al_dst_formats[] = {
+	{
+		.pixelformat = V4L2_PIX_FMT_NV12,
+		.bpp = 12,
+	},
+	{
+		.pixelformat = V4L2_PIX_FMT_P010,
+		.bpp = 12,
+	},
+	{
+		.pixelformat = V4L2_PIX_FMT_NV16,
+		.bpp = 16,
+	},
+	{
+		.pixelformat = V4L2_PIX_FMT_YUV420, /* YUV 4:2:0 */
+		.bpp = 12,
+	},
+	{
+		.pixelformat = V4L2_PIX_FMT_YVU420, /* YVU 4:2:0 */
+		.bpp = 12,
+	},
+};
+
+/* Default format */
+static const struct al_frame al_default_fmt = {
+
+	.width = DECODER_WIDTH_DEFAULT,
+	.height = DECODER_HEIGHT_DEFAULT,
+	.bytesperline = DECODER_WIDTH_MAX * 4,
+	.sizeimage = DECODER_WIDTH_DEFAULT * DECODER_HEIGHT_DEFAULT * 4,
+	.nbuffers = 1,
+	.fmt = &al_dst_formats[0],
+	.field = V4L2_FIELD_NONE,
+	.colorspace = V4L2_COLORSPACE_REC709,
+	.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT,
+	.quantization = V4L2_QUANTIZATION_DEFAULT,
+	.xfer_func = V4L2_XFER_FUNC_DEFAULT
+};
+
+static struct al_frame *al_get_frame(struct al_dec_ctx *ctx,
+				     enum v4l2_buf_type type)
+{
+	if (WARN_ON(!ctx))
+		return ERR_PTR(-EINVAL);
+
+	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return &ctx->src;
+	else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return &ctx->dst;
+
+	al_v4l2_err(ctx->codec, "Unsupported type (%d)", type);
+
+	return ERR_PTR(-EINVAL);
+}
+
+static const struct al_fmt *al_find_fmt(u32 pixelformat)
+{
+	const struct al_fmt *fmt;
+	unsigned int i;
+
+	/* check if the pixelformat exist in the src formats list */
+	for (i = 0; i < ARRAY_SIZE(al_src_formats); i++) {
+		fmt = &al_src_formats[i];
+		if (fmt->pixelformat == pixelformat)
+			return fmt;
+	}
+
+	/* check if the pixelformat exist in the dst formats list */
+	for (i = 0; i < ARRAY_SIZE(al_dst_formats); i++) {
+		fmt = &al_dst_formats[i];
+		if (fmt->pixelformat == pixelformat)
+			return fmt;
+	}
+
+	return NULL;
+}
+
+static int dec_fw_create_decoder(struct al_dec_ctx *ctx)
+{
+	struct msg_itf_create_decoder_req_full req;
+	struct msg_itf_create_codec_reply reply;
+	const struct al_frame *frame = &ctx->src;
+	struct al_common_mcu_req mreq = {
+		.pCtx = al_virt_to_phys(ctx),
+		.req_type = MSG_ITF_TYPE_CREATE_INST_REQ,
+		.req_size = sizeof(req.req),
+		.reply_size = sizeof(reply),
+		.reply = &reply,
+	};
+	int ret;
+
+	if (ctx->hDec) {
+		al_v4l2_dbg(ctx->codec, 3, "fw decoder already exist\n");
+		return 0;
+	}
+
+	req.req.codec = frame->fmt->pixelformat;
+
+	ret = al_common_send_req_reply(ctx->codec, &ctx->cmd_q_list, &req.hdr,
+				       &mreq);
+
+	if (!ret && !reply.ret)
+		ctx->hDec = reply.hCodec;
+	else if (reply.ret)
+		ret = -ENODEV;
+
+	return ret;
+}
+
+static void dec_fw_destroy_decoder(struct al_dec_ctx *ctx)
+{
+	struct msg_itf_destroy_codec_req_full req;
+	struct msg_itf_destroy_codec_reply reply;
+	struct al_common_mcu_req mreq = {
+		.req_type = MSG_ITF_TYPE_DESTROY_INST_REQ,
+		.pCtx = al_virt_to_phys(ctx),
+		.req_size = sizeof(req.req),
+		.reply_size = sizeof(reply),
+		.reply = &reply,
+	};
+	int ret;
+
+	if (WARN(!ctx->hDec, "NULL Decoder to destroy !"))
+		return;
+
+	al_v4l2_dbg(ctx->codec, 3, "Destroy decoder %lld ", ctx->hDec);
+
+	req.req.hCodec = ctx->hDec;
+
+	ret = al_common_send_req_reply(ctx->codec, &ctx->cmd_q_list, &req.hdr,
+				       &mreq);
+
+	if (!ret)
+		ctx->hDec = 0;
+}
+
+static int al_dec_fw_push_frame_buf(struct al_dec_ctx *ctx,
+				    struct vb2_v4l2_buffer *vbuf)
+{
+	struct msg_itf_push_dst_buf_req_full req;
+	struct v4l2_m2m_buffer *m2m_buf;
+	struct al_common_mcu_req mreq = {
+		.req_type = MSG_ITF_TYPE_PUT_DISPLAY_PICTURE_REQ,
+		.pCtx = al_virt_to_phys(ctx),
+		.req_size = sizeof(req.req),
+	};
+	int ret;
+
+	if (WARN(!vbuf, "NULL frame Buffer to push!!"))
+		return -EINVAL;
+
+	m2m_buf = container_of(vbuf, struct v4l2_m2m_buffer, vb);
+	req.req.hCodec = ctx->hDec;
+	req.req.bufferHandle = al_virt_to_phys(m2m_buf);
+	req.req.phyAddr = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0);
+	req.req.size = vb2_plane_size(&vbuf->vb2_buf, 0);
+
+	ret = al_common_send_req_reply(ctx->codec, &ctx->cmd_q_list, &req.hdr,
+				       &mreq);
+	if (ret)
+		al_v4l2_err(ctx->codec, "Failed to push frame buffer %p %d",
+			    m2m_buf, ret);
+
+	return ret;
+}
+
+static int al_dec_fw_push_bitstream_buf(struct al_dec_ctx *ctx,
+					struct vb2_v4l2_buffer *vbuf)
+{
+	struct msg_itf_push_src_buf_req_full req;
+	struct v4l2_m2m_buffer *m2m_buf;
+	struct al_common_mcu_req mreq = {
+		.req_type = MSG_ITF_TYPE_PUSH_BITSTREAM_BUFFER_REQ,
+		.pCtx = al_virt_to_phys(ctx),
+		.req_size = sizeof(req.req),
+	};
+	int ret;
+
+	if (WARN(!vbuf, "NULL Buffer to push!!"))
+		return -EINVAL;
+
+	m2m_buf = container_of(vbuf, struct v4l2_m2m_buffer, vb);
+	req.req.hCodec = ctx->hDec;
+	req.req.bufferHandle = al_virt_to_phys(m2m_buf);
+	req.req.phyAddr = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0);
+	req.req.size = vb2_plane_size(&vbuf->vb2_buf, 0);
+
+	/* Fill the v4l2 metadata*/
+	req.req.meta.timestamp = vbuf->vb2_buf.timestamp;
+	req.req.meta.timecode = vbuf->timecode;
+	req.req.meta.last = vbuf->flags & V4L2_BUF_FLAG_LAST;
+
+	ret = al_common_send_req_reply(ctx->codec, &ctx->cmd_q_list, &req.hdr,
+				       &mreq);
+	if (ret)
+		al_v4l2_err(ctx->codec, "Failed to push bitstream buffer %p %d",
+			    m2m_buf, ret);
+
+	return ret;
+}
+
+static int dec_fw_flush_req(struct al_dec_ctx *ctx)
+{
+	struct msg_itf_flush_req_full req;
+	struct msg_itf_flush_reply reply;
+	struct al_common_mcu_req mreq = {
+		.req_type = MSG_ITF_TYPE_FLUSH_REQ,
+		.pCtx = al_virt_to_phys(ctx),
+		.req_size = sizeof(req.req),
+		.reply_size = sizeof(reply),
+		.reply = &reply,
+	};
+	int ret;
+
+	req.req.hCodec = ctx->hDec;
+
+	ret = al_common_send_req_reply(ctx->codec, &ctx->cmd_q_list, &req.hdr,
+				       &mreq);
+
+	if (ret)
+		al_v4l2_err(ctx->codec, "Failed to flush the decoder %d", ret);
+
+	return ret;
+}
+
+static struct vb2_v4l2_buffer *al_dec_dequeue_buf(struct al_dec_ctx *ctx,
+						  uint64_t hdl,
+						  struct list_head *buffer_list)
+{
+	struct v4l2_m2m_buffer *buf, *tmp;
+	struct vb2_v4l2_buffer *ret = NULL;
+
+	guard(mutex)(&ctx->buf_q_mlock);
+	list_for_each_entry_safe(buf, tmp, buffer_list, list) {
+		if (buf == al_phys_to_virt(hdl)) {
+			list_del(&buf->list);
+			ret = &buf->vb;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static struct vb2_v4l2_buffer *al_dec_dequeue_src_buf(struct al_dec_ctx *ctx,
+						      uint64_t hdl)
+{
+	return al_dec_dequeue_buf(ctx, hdl, &ctx->stream_q_list);
+}
+
+static struct vb2_v4l2_buffer *al_dec_dequeue_dst_buf(struct al_dec_ctx *ctx,
+						      uint64_t hdl)
+{
+	return al_dec_dequeue_buf(ctx, hdl, &ctx->frame_q_list);
+}
+
+static void al_ctx_cleanup(struct kref *ref)
+{
+	struct al_dec_ctx *ctx = container_of(ref, struct al_dec_ctx, refcount);
+
+	kfree(ctx);
+}
+
+static struct al_dec_ctx *al_ctx_get(struct al_codec_dev *codec, uint64_t hdl)
+{
+	struct al_dec_ctx *ctx;
+	struct al_dec_ctx *ret = NULL;
+
+	guard(mutex)(&codec->ctx_mlock);
+	list_for_each_entry(ctx, &codec->ctx_q_list, list) {
+		if (ctx == al_phys_to_virt(hdl)) {
+			kref_get(&ctx->refcount);
+			ret = ctx;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static void al_ctx_put(struct al_dec_ctx *ctx)
+{
+	kref_put(&ctx->refcount, al_ctx_cleanup);
+}
+
+static int al_dec_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct al_dec_ctx *ctx = vb2_get_drv_priv(q);
+	struct al_codec_dev *codec = ctx->codec;
+
+	v4l2_m2m_update_start_streaming_state(ctx->fh.m2m_ctx, q);
+
+	if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+		struct v4l2_m2m_buffer *buf;
+		int ret;
+
+		if (list_empty(&ctx->stream_q_list)) {
+			al_v4l2_err(codec, "Empty stream list.");
+			return -EINVAL;
+		}
+
+		if (!al_common_mcu_is_alive(codec)) {
+			al_v4l2_err(codec, "Unable to ping the mcu");
+			return -ENODEV;
+		}
+
+		ret = dec_fw_create_decoder(ctx);
+		if (ret) {
+			al_v4l2_err(codec, "Unable to create the fw decoder %d",
+				    ret);
+			return ret;
+		}
+
+		/* Get the first vid-out queued buffer */
+		buf = list_first_entry(&ctx->stream_q_list,
+				       struct v4l2_m2m_buffer, list);
+
+		if (al_dec_fw_push_bitstream_buf(ctx, &buf->vb)) {
+			al_v4l2_err(codec,
+				    "Unable to push the bitstream buffer");
+			return -EINVAL;
+		}
+
+		/* Wait until the mcu detect the resolution of the stream */
+		ret = wait_for_completion_timeout(&ctx->res_done,
+						  DEC_RES_EVT_TIMEOUT);
+		if (!ret) {
+			al_v4l2_err(codec, "unsupported stream");
+			ctx->aborting = true;
+		}
+	}
+
+	return 0;
+}
+
+static void al_dec_stop_streaming_cap(struct al_dec_ctx *ctx)
+{
+	struct vb2_v4l2_buffer *vbuf;
+	struct v4l2_m2m_buffer *entry, *tmp;
+
+	mutex_lock(&ctx->buf_q_mlock);
+	if (!list_empty(&ctx->frame_q_list))
+		list_for_each_entry_safe(entry, tmp, &ctx->frame_q_list, list) {
+			list_del(&entry->list);
+			vbuf = &entry->vb;
+			vb2_set_plane_payload(&vbuf->vb2_buf, 0, 0);
+			v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
+		}
+	mutex_unlock(&ctx->buf_q_mlock);
+
+	while (v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)) {
+		vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+		if (vbuf) {
+			vb2_set_plane_payload(&vbuf->vb2_buf, 0, 0);
+			v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
+		}
+	}
+
+	v4l2_m2m_mark_stopped(ctx->fh.m2m_ctx);
+}
+
+static void al_dec_stop_streaming_out(struct al_dec_ctx *ctx)
+{
+	struct vb2_v4l2_buffer *vbuf;
+	struct v4l2_m2m_buffer *entry, *tmp;
+
+	mutex_lock(&ctx->buf_q_mlock);
+	if (!list_empty(&ctx->stream_q_list))
+		list_for_each_entry_safe(entry, tmp, &ctx->stream_q_list,
+					 list) {
+			list_del(&entry->list);
+			v4l2_m2m_buf_done(&entry->vb, VB2_BUF_STATE_ERROR);
+		}
+	mutex_unlock(&ctx->buf_q_mlock);
+
+	if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx)) {
+		while ((vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx)))
+			if (vbuf->vb2_buf.state == VB2_BUF_STATE_ACTIVE)
+				v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
+	}
+
+	dec_fw_destroy_decoder(ctx);
+}
+
+static void al_dec_stop_streaming(struct vb2_queue *q)
+{
+	struct al_dec_ctx *ctx = vb2_get_drv_priv(q);
+
+	v4l2_m2m_update_stop_streaming_state(ctx->fh.m2m_ctx, q);
+
+	/* Releasing the dst and src buffers */
+	ctx->stopped = true;
+
+	if (V4L2_TYPE_IS_OUTPUT(q->type))
+		al_dec_stop_streaming_out(ctx);
+	else
+		al_dec_stop_streaming_cap(ctx);
+}
+
+static int al_dec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+			      unsigned int *nplanes, unsigned int sizes[],
+			      struct device *alloc_devs[])
+{
+	struct al_dec_ctx *ctx = vb2_get_drv_priv(vq);
+	struct al_frame *format = al_get_frame(ctx, vq->type);
+
+	if (IS_ERR(format)) {
+		al_v4l2_err(ctx->codec, "Invalid format %p", format);
+		return PTR_ERR(format);
+	}
+
+	if (*nplanes)
+		return ((sizes[0] < format->sizeimage) ? -EINVAL : 0);
+
+	/* update queue num buffers */
+	format->nbuffers = max(*nbuffers, format->nbuffers);
+
+	*nplanes = 1;
+	sizes[0] = format->sizeimage;
+	*nbuffers = format->nbuffers;
+
+	al_v4l2_dbg(ctx->codec, 2, "%s: Get %d buffers of size %d each ",
+		    (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ? "OUT" : "CAP",
+		    *nbuffers, sizes[0]);
+
+	return 0;
+}
+
+static int al_dec_buf_prepare(struct vb2_buffer *vb)
+{
+	struct al_dec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+	if (ctx->aborting)
+		return -EINVAL;
+
+	if (V4L2_TYPE_IS_CAPTURE(vb->type)) {
+		if (vbuf->field == V4L2_FIELD_ANY)
+			vbuf->field = V4L2_FIELD_NONE;
+		if (vbuf->field != V4L2_FIELD_NONE)
+			return -EINVAL;
+	}
+
+	al_v4l2_dbg(ctx->codec, 3, "%s : Buffer (%p) prepared ",
+		    (V4L2_TYPE_IS_OUTPUT(vb->type) ? "OUT" : "CAP"), vbuf);
+
+	return 0;
+}
+
+static inline void al_dec_fill_bitstream(struct al_dec_ctx *ctx)
+{
+	struct vb2_v4l2_buffer *src_buf;
+	struct v4l2_m2m_buffer *m2m_buf;
+	struct vb2_queue *src_vq;
+
+	lockdep_assert_held(&ctx->buf_q_mlock);
+
+	if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) {
+		src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+		if (!src_buf)
+			return;
+
+		/* Dump empty buffers */
+		if (!vb2_get_plane_payload(&src_buf->vb2_buf, 0)) {
+			src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+			v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
+			return;
+		}
+
+		src_vq = v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx);
+		src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+
+		if (src_buf) {
+			src_buf->sequence = ctx->osequence++;
+
+			if (vb2_is_streaming(src_vq) &&
+			    al_dec_fw_push_bitstream_buf(ctx, src_buf)) {
+				v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
+				return;
+			}
+
+			m2m_buf = container_of(src_buf, struct v4l2_m2m_buffer,
+					       vb);
+			list_add_tail(&m2m_buf->list, &ctx->stream_q_list);
+		}
+	}
+}
+
+static void al_dec_buf_queue(struct vb2_buffer *vb)
+{
+	struct al_dec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+	v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
+
+	if (V4L2_TYPE_IS_OUTPUT(vb->type)) {
+		mutex_lock(&ctx->buf_q_mlock);
+		al_dec_fill_bitstream(ctx);
+		mutex_unlock(&ctx->buf_q_mlock);
+	}
+
+	al_v4l2_dbg(ctx->codec, 3, "%s queued (%p) - (%d)",
+		    V4L2_TYPE_IS_OUTPUT(vb->type) ? "OUT" : "CAP", vbuf,
+		    vb->num_planes);
+}
+
+static const struct vb2_ops dec_queue_ops = {
+	.queue_setup = al_dec_queue_setup,
+	.buf_prepare = al_dec_buf_prepare,
+	.buf_queue = al_dec_buf_queue,
+	.start_streaming = al_dec_start_streaming,
+	.stop_streaming = al_dec_stop_streaming,
+	.wait_prepare = vb2_ops_wait_prepare,
+	.wait_finish = vb2_ops_wait_finish,
+};
+
+static int al_dec_queue_init(void *priv, struct vb2_queue *src_vq,
+			     struct vb2_queue *dst_vq)
+{
+	struct al_dec_ctx *ctx = priv;
+	struct al_codec_dev *codec = ctx->codec;
+	int ret;
+
+	src_vq->dev = &codec->pdev->dev;
+	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+	src_vq->non_coherent_mem = false;
+	src_vq->dma_attrs |= DMA_ATTR_FORCE_CONTIGUOUS;
+	src_vq->mem_ops = &vb2_dma_contig_memops;
+	src_vq->drv_priv = ctx;
+	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	src_vq->ops = &dec_queue_ops;
+	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	src_vq->lock = &ctx->codec->lock;
+	ret = vb2_queue_init(src_vq);
+	if (ret)
+		return ret;
+
+	dst_vq->dev = &codec->pdev->dev;
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+	dst_vq->non_coherent_mem = false;
+	dst_vq->dma_attrs |= DMA_ATTR_FORCE_CONTIGUOUS;
+	dst_vq->mem_ops = &vb2_dma_contig_memops;
+	dst_vq->drv_priv = ctx;
+	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	dst_vq->ops = &dec_queue_ops;
+	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	dst_vq->lock = &ctx->codec->lock;
+	ret = vb2_queue_init(dst_vq);
+	if (ret) {
+		vb2_queue_release(src_vq);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int al_dec_querycap(struct file *file, void *fh,
+			   struct v4l2_capability *cap)
+{
+	struct al_codec_dev *codec = video_drvdata(file);
+
+	strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
+	strscpy(cap->card, "Allegro DVT Video Decoder", sizeof(cap->card));
+	snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+		 dev_name(&codec->pdev->dev));
+
+	return 0;
+}
+
+static int al_dec_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+	const struct al_fmt *fmt;
+
+	if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+	    f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (V4L2_TYPE_IS_OUTPUT(f->type)) {
+		if (f->index >= ARRAY_SIZE(al_src_formats))
+			return -EINVAL;
+
+		fmt = &al_src_formats[f->index];
+	} else {
+		if (f->index >= ARRAY_SIZE(al_dst_formats))
+			return -EINVAL;
+
+		fmt = &al_dst_formats[f->index];
+	}
+
+	f->pixelformat = fmt->pixelformat;
+	return 0;
+}
+
+static int al_dec_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
+{
+	struct al_dec_ctx *ctx = fh_to_ctx(fh, struct al_dec_ctx);
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	struct al_frame *pix_fmt;
+
+	pix_fmt = al_get_frame(ctx, f->type);
+	if (IS_ERR(pix_fmt)) {
+		al_v4l2_err(ctx->codec, "Invalid frame (%p)", pix_fmt);
+		return PTR_ERR(pix_fmt);
+	}
+
+	pix_fmt->fmt = al_find_fmt(pix->pixelformat);
+	if (!pix_fmt->fmt) {
+		al_v4l2_err(ctx->codec, "Unknown format 0x%x",
+			    pix->pixelformat);
+		return -EINVAL;
+	}
+	pix->field = V4L2_FIELD_NONE;
+	pix->width = clamp_t(__u32, pix->width, DECODER_WIDTH_MIN,
+			     DECODER_WIDTH_MAX);
+	pix->height = clamp_t(__u32, pix->height, DECODER_HEIGHT_MIN,
+			      DECODER_HEIGHT_MAX);
+
+	pix->bytesperline = pix->width;
+	pix->sizeimage = (pix->width * pix->height * pix_fmt->fmt->bpp) / 8;
+
+	if (V4L2_TYPE_IS_CAPTURE(f->type))
+		if (pix->sizeimage < pix_fmt->sizeimage)
+			pix->sizeimage = pix_fmt->sizeimage;
+
+	al_v4l2_dbg(
+		ctx->codec, 3,
+		"%s : width (%d) , height (%d), bytesperline (%d), sizeimage (%d) ",
+		(f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ? "CAP" : "OUT",
+		pix->width, pix->height, pix->bytesperline, pix->sizeimage);
+
+	return 0;
+}
+
+static int al_dec_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
+{
+	struct al_dec_ctx *ctx = fh_to_ctx(fh, struct al_dec_ctx);
+	struct al_frame *pix_fmt = al_get_frame(ctx, f->type);
+	struct v4l2_pix_format *pix;
+
+	if (IS_ERR(pix_fmt)) {
+		al_v4l2_err(ctx->codec, "Invalid pixel format %p", pix_fmt);
+		return PTR_ERR(pix_fmt);
+	}
+
+	if (!pix_fmt->fmt) {
+		al_v4l2_err(ctx->codec, "Unknown format for %d", f->type);
+		return -EINVAL;
+	}
+
+	pix = &f->fmt.pix;
+	pix->width = pix_fmt->width;
+	pix->height = pix_fmt->height;
+	pix->bytesperline = pix_fmt->bytesperline;
+	pix->sizeimage = pix_fmt->sizeimage;
+	pix->pixelformat = pix_fmt->fmt->pixelformat;
+	pix->field = V4L2_FIELD_NONE;
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		pix->bytesperline = 0;
+
+	pix->ycbcr_enc = pix_fmt->ycbcr_enc;
+	pix->quantization = pix_fmt->quantization;
+	pix->xfer_func = pix_fmt->xfer_func;
+	pix->colorspace = pix_fmt->colorspace;
+
+	al_v4l2_dbg(
+		ctx->codec, 3,
+		"%s : width (%d) , height (%d), bytesperline (%d) , sizeimage (%d)",
+		(f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ? "CAP" : "OUT",
+		pix->width, pix->height, pix->bytesperline, pix->sizeimage);
+
+	return 0;
+}
+
+static int al_dec_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
+{
+	struct al_dec_ctx *ctx = fh_to_ctx(fh, struct al_dec_ctx);
+	struct v4l2_pix_format *pix;
+	struct al_frame *frame;
+	struct vb2_queue *vq;
+	int ret;
+
+	ret = al_dec_try_fmt(file, fh, f);
+	if (ret) {
+		al_v4l2_err(ctx->codec, "Cannot set format (%d)", f->type);
+		return ret;
+	}
+
+	frame = (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ? &ctx->src : &ctx->dst;
+
+	pix = &f->fmt.pix;
+	frame->fmt = al_find_fmt(pix->pixelformat);
+	if (!frame->fmt) {
+		al_v4l2_err(ctx->codec, "Unknown format for %d",
+			    pix->pixelformat);
+		return -EINVAL;
+	}
+
+	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+	if (vb2_is_streaming(vq)) {
+		al_v4l2_err(ctx->codec, "queue %d busy", f->type);
+		return -EBUSY;
+	}
+
+	frame->width = pix->width;
+	frame->height = pix->height;
+	frame->bytesperline = pix->bytesperline;
+	frame->sizeimage = pix->sizeimage;
+	frame->field = pix->field;
+
+	frame->ycbcr_enc = pix->ycbcr_enc;
+	frame->quantization = pix->quantization;
+	frame->xfer_func = pix->xfer_func;
+	frame->colorspace = pix->colorspace;
+
+	al_v4l2_dbg(
+		ctx->codec, 3,
+		" %s : width (%d) , height (%d), bytesperline (%d), sizeimage (%d)",
+		(f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ? "CAP" : "OUT",
+		pix->width, pix->height, pix->bytesperline, pix->sizeimage);
+
+	return 0;
+}
+
+static void al_queue_eos_event(struct al_dec_ctx *ctx)
+{
+	const struct v4l2_event eos_event = {
+		.id = 0,
+		.type = V4L2_EVENT_EOS,
+	};
+
+	v4l2_event_queue_fh(&ctx->fh, &eos_event);
+}
+
+static void al_queue_res_chg_event(struct al_dec_ctx *ctx)
+{
+	static const struct v4l2_event ev_src_ch = {
+		.id = 0,
+		.type = V4L2_EVENT_SOURCE_CHANGE,
+		.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
+	};
+
+	v4l2_event_queue_fh(&ctx->fh, &ev_src_ch);
+}
+
+static int al_dec_decoder_cmd(struct file *file, void *fh,
+			      struct v4l2_decoder_cmd *dcmd)
+{
+	struct al_dec_ctx *ctx = fh_to_ctx(fh, struct al_dec_ctx);
+	struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
+	struct vb2_v4l2_buffer *vbuf;
+	struct vb2_queue *dst_vq;
+	int ret;
+
+	ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dcmd);
+	if (ret)
+		return ret;
+
+	/* Get the vb2 queue for the Capture */
+	dst_vq = v4l2_m2m_get_dst_vq(m2m_ctx);
+
+	switch (dcmd->cmd) {
+	case V4L2_DEC_CMD_START:
+		vb2_clear_last_buffer_dequeued(dst_vq);
+		break;
+	case V4L2_DEC_CMD_STOP:
+		vbuf = v4l2_m2m_last_src_buf(m2m_ctx);
+		if (vbuf) {
+			al_v4l2_dbg(ctx->codec, 1,
+				    "marking last pending buffer");
+
+			vbuf->flags |= V4L2_BUF_FLAG_LAST;
+			if (v4l2_m2m_num_src_bufs_ready(m2m_ctx) == 0) {
+				al_v4l2_dbg(ctx->codec, 1,
+					    "all remaining buffers queued");
+				v4l2_m2m_try_schedule(m2m_ctx);
+			}
+		}
+		dec_fw_flush_req(ctx);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int al_dec_enum_framesizes(struct file *file, void *fh,
+				  struct v4l2_frmsizeenum *fsize)
+{
+	if (!al_find_fmt(fsize->pixel_format))
+		return -EINVAL;
+
+	/* FIXME : check step size */
+	fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+	fsize->stepwise.min_width = DECODER_WIDTH_MIN;
+	fsize->stepwise.max_width = DECODER_WIDTH_MAX;
+	fsize->stepwise.step_width = 8;
+	fsize->stepwise.min_height = DECODER_HEIGHT_MIN;
+	fsize->stepwise.max_height = DECODER_HEIGHT_MAX;
+	fsize->stepwise.step_height = 8;
+
+	return 0;
+}
+
+static int al_dec_subscribe_event(struct v4l2_fh *fh,
+				  const struct v4l2_event_subscription *sub)
+{
+	switch (sub->type) {
+	case V4L2_EVENT_EOS:
+		return v4l2_event_subscribe(fh, sub, 0, NULL);
+	case V4L2_EVENT_SOURCE_CHANGE:
+		return v4l2_src_change_event_subscribe(fh, sub);
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int al_dec_log_status(struct file *file, void *fh)
+{
+	struct al_codec_dev *codec = video_drvdata(file);
+
+	v4l2_device_call_all(&codec->v4l2_dev, 0, core, log_status);
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops al_dec_ioctl_ops = {
+	.vidioc_querycap = al_dec_querycap,
+	.vidioc_enum_fmt_vid_cap = al_dec_enum_fmt,
+	.vidioc_enum_fmt_vid_out = al_dec_enum_fmt,
+	.vidioc_g_fmt_vid_cap = al_dec_g_fmt,
+	.vidioc_g_fmt_vid_out = al_dec_g_fmt,
+	.vidioc_try_fmt_vid_cap = al_dec_try_fmt,
+	.vidioc_try_fmt_vid_out = al_dec_try_fmt,
+	.vidioc_s_fmt_vid_cap = al_dec_s_fmt,
+	.vidioc_s_fmt_vid_out = al_dec_s_fmt,
+
+	.vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+	.vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+
+	.vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+	.vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+	.vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+	.vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+	.vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+
+	.vidioc_streamon = v4l2_m2m_ioctl_streamon,
+	.vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+	.vidioc_log_status = al_dec_log_status,
+
+	.vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd,
+	.vidioc_decoder_cmd = al_dec_decoder_cmd,
+	.vidioc_enum_framesizes = al_dec_enum_framesizes,
+
+	.vidioc_subscribe_event = al_dec_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static void al_device_run(void *priv)
+{
+	struct al_dec_ctx *ctx = priv;
+	struct vb2_v4l2_buffer *dst_buf;
+	struct v4l2_m2m_buffer *m2m_buf;
+
+	if (unlikely(!ctx))
+		return;
+
+	if (ctx->aborting) {
+		vb2_queue_error(v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx));
+		vb2_queue_error(v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx));
+		return;
+	}
+
+	if (!v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx))
+		goto job_finish;
+
+	dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+	if (!dst_buf)
+		goto job_finish;
+
+	if (!al_common_mcu_is_alive(ctx->codec) ||
+	    al_dec_fw_push_frame_buf(ctx, dst_buf)) {
+		vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
+		v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
+		goto job_finish;
+	}
+
+	mutex_lock(&ctx->buf_q_mlock);
+	m2m_buf = container_of(dst_buf, struct v4l2_m2m_buffer, vb);
+	list_add_tail(&m2m_buf->list, &ctx->frame_q_list);
+	mutex_unlock(&ctx->buf_q_mlock);
+
+job_finish:
+	v4l2_m2m_job_finish(ctx->codec->m2m_dev, ctx->fh.m2m_ctx);
+}
+
+static const struct v4l2_m2m_ops al_dec_m2m_ops = {
+	.device_run = al_device_run,
+};
+
+static int al_dec_open(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct al_codec_dev *codec = video_get_drvdata(vdev);
+	struct al_dec_ctx *ctx = NULL;
+	int ret;
+
+	if (mutex_lock_interruptible(&codec->ctx_mlock))
+		return -ERESTARTSYS;
+
+	/* Aloocate memory for the dec ctx */
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx) {
+		ret = -ENOMEM;
+		goto unlock;
+	}
+
+	ctx->codec = codec;
+	/* Init ctx mutex */
+	mutex_init(&ctx->buf_q_mlock);
+	/* Init ctx LISTHEADs*/
+	INIT_LIST_HEAD(&ctx->cmd_q_list);
+	INIT_LIST_HEAD(&ctx->frame_q_list);
+	INIT_LIST_HEAD(&ctx->stream_q_list);
+
+	/* Init the irq queue */
+	init_completion(&ctx->res_done);
+
+	v4l2_fh_init(&ctx->fh, vdev);
+
+	v4l2_ctrl_handler_init(&ctx->ctrl_handler, 0);
+	if (ctx->ctrl_handler.error) {
+		ret = ctx->ctrl_handler.error;
+		al_v4l2_err(codec, "Failed to create control %d", ret);
+		goto handler_error;
+	}
+
+	ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+	v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+
+	file->private_data = &ctx->fh;
+	v4l2_fh_add(&ctx->fh, file);
+
+	/* Set default formats */
+	ctx->src = ctx->dst = al_default_fmt;
+	ctx->csequence = ctx->osequence = 0;
+
+	ctx->stopped = false;
+	ctx->aborting = false;
+	ctx->id = codec->ctx_counter++;
+
+	/* Setup the ctx for m2m mode */
+	ctx->fh.m2m_ctx =
+		v4l2_m2m_ctx_init(codec->m2m_dev, ctx, al_dec_queue_init);
+	if (IS_ERR(ctx->fh.m2m_ctx)) {
+		ret = PTR_ERR(ctx->fh.m2m_ctx);
+		al_v4l2_err(codec, "Failed to initialize m2m mode %d", ret);
+		goto error_ctrls;
+	}
+
+	v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true);
+
+	/* Add ctx to the LIST */
+	kref_init(&ctx->refcount);
+	list_add(&ctx->list, &codec->ctx_q_list);
+	al_codec_dbgfs_create(ctx);
+
+	mutex_unlock(&codec->ctx_mlock);
+
+	return 0;
+
+error_ctrls:
+	v4l2_fh_del(&ctx->fh, file);
+handler_error:
+	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+	v4l2_fh_exit(&ctx->fh);
+	kfree(ctx);
+
+unlock:
+	mutex_unlock(&codec->ctx_mlock);
+	return ret;
+}
+
+static int al_dec_release(struct file *file)
+{
+	struct al_dec_ctx *ctx =
+		fh_to_ctx(file->private_data, struct al_dec_ctx);
+	struct al_codec_dev *codec = ctx->codec;
+
+	guard(mutex)(&codec->ctx_mlock);
+
+	/* It is important to do this before removing ctx from dev list.
+	 * Those commands will trigger some traffic towards fw and so we
+	 * need completion to avoid deadlock if cmds can't find ctx.
+	 */
+	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+	v4l2_fh_del(&ctx->fh, file);
+	v4l2_fh_exit(&ctx->fh);
+
+	list_del(&ctx->list);
+	al_codec_dbgfs_remove(codec, ctx->id);
+	al_ctx_put(ctx);
+
+	return 0;
+}
+
+static inline bool al_mark_last_dst_buf(struct al_dec_ctx *ctx)
+{
+	struct vb2_v4l2_buffer *buf;
+	struct vb2_buffer *dst_vb;
+	struct vb2_queue *dst_vq;
+	unsigned long flags;
+
+	al_v4l2_dbg(ctx->codec, 1, "marking last capture buffer");
+
+	dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+	spin_lock_irqsave(&dst_vq->done_lock, flags);
+	if (list_empty(&dst_vq->done_list)) {
+		spin_unlock_irqrestore(&dst_vq->done_lock, flags);
+		return false;
+	}
+
+	dst_vb = list_last_entry(&dst_vq->done_list, struct vb2_buffer,
+				 done_entry);
+	buf = to_vb2_v4l2_buffer(dst_vb);
+	buf->flags |= V4L2_BUF_FLAG_LAST;
+
+	spin_unlock_irqrestore(&dst_vq->done_lock, flags);
+	return true;
+}
+
+static const struct v4l2_file_operations al_dec_file_ops = {
+	.owner = THIS_MODULE,
+	.open = al_dec_open,
+	.release = al_dec_release,
+	.poll = v4l2_m2m_fop_poll,
+	.unlocked_ioctl = video_ioctl2,
+	.mmap = v4l2_m2m_fop_mmap,
+};
+
+static void handle_error_evt(struct al_dec_ctx *ctx, struct msg_itf_header *hdr)
+{
+	struct al_codec_dev *codec = ctx->codec;
+	struct msg_itf_evt_error evt;
+	struct v4l2_m2m_buffer *vbuf;
+
+	if (al_common_get_data(codec, (char *)&evt, hdr->payload_len)) {
+		al_v4l2_err(codec, "Unable to get resolution found event");
+		return;
+	}
+
+	al_v4l2_err(codec, "Decoding error  %d", evt.errno);
+
+	guard(mutex)(&ctx->buf_q_mlock);
+	if (!list_empty(&ctx->stream_q_list)) {
+		vbuf = list_last_entry(&ctx->frame_q_list,
+				       struct v4l2_m2m_buffer, list);
+		list_del(&vbuf->list);
+		v4l2_m2m_buf_done(&vbuf->vb, VB2_BUF_STATE_ERROR);
+	}
+}
+
+static void handle_resolution_found_evt(struct al_dec_ctx *ctx,
+					struct msg_itf_header *hdr)
+{
+	struct msg_itf_evt_resolution_found evt;
+	struct al_codec_dev *codec = ctx->codec;
+	struct al_frame *frame;
+	struct vb2_queue *dst_vq;
+
+	if (al_common_get_data(codec, (char *)&evt, hdr->payload_len)) {
+		al_v4l2_err(codec, "Unable to get resolution found event");
+		return;
+	}
+
+	frame = &ctx->dst;
+
+	if (frame->width != evt.width || frame->height != evt.height ||
+	    frame->nbuffers < evt.buffer_nb) {
+		/* Update frame properties */
+		frame->width = evt.width;
+		frame->height = evt.height;
+		frame->bytesperline = evt.bytesperline;
+		frame->sizeimage = evt.sizeimage;
+		frame->nbuffers = evt.buffer_nb;
+		frame->fmt = al_find_fmt(evt.pixelformat);
+
+		/* This has to be changed */
+		if (!frame->fmt)
+			return;
+
+		al_queue_res_chg_event(ctx);
+	}
+
+	dst_vq = v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx);
+	if (!vb2_is_streaming(dst_vq))
+		complete(&ctx->res_done);
+
+	al_v4l2_dbg(
+		codec, 3,
+		"width(%d) , height(%d), bytesperline(%d), sizeimage(%d), n_bufs(%d)",
+		frame->width, frame->height, frame->bytesperline,
+		frame->sizeimage, frame->nbuffers);
+}
+
+static void handle_bitstream_buffer_release_evt(struct al_dec_ctx *ctx,
+						struct msg_itf_header *hdr)
+{
+	struct msg_itf_evt_bitstream_buffer_release evt;
+	struct al_codec_dev *codec = ctx->codec;
+	struct vb2_v4l2_buffer *vbuf;
+
+	if (al_common_get_data(codec, (char *)&evt, hdr->payload_len)) {
+		al_v4l2_err(codec, "Unable to get buffer release event");
+		return;
+	}
+
+	if (ctx->stopped)
+		return;
+
+	vbuf = al_dec_dequeue_src_buf(ctx, evt.bufferHandle);
+	if (!vbuf) {
+		al_v4l2_err(codec, "Unable to find bitsream buffer 0x%llx",
+			    evt.bufferHandle);
+		return;
+	}
+
+	al_v4l2_dbg(codec, 3, "Release bitstream buffer %p", vbuf);
+	v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
+}
+
+static void handle_eos_evt(struct al_dec_ctx *ctx, struct msg_itf_header *hdr)
+{
+	struct msg_itf_evt_frame_buffer_decode evt;
+	struct al_codec_dev *codec = ctx->codec;
+
+	if (al_common_get_data(codec, (char *)&evt, hdr->payload_len)) {
+		al_v4l2_err(codec, "Unable to get frame buffer event");
+		return;
+	}
+
+	/* set LAST_FLAG to the last done CAPTURE buffer*/
+	al_mark_last_dst_buf(ctx);
+	/* Set eos event */
+	al_queue_eos_event(ctx);
+}
+
+static void handle_frame_buffer_decode_evt(struct al_dec_ctx *ctx,
+					   struct msg_itf_header *hdr)
+{
+	struct msg_itf_evt_frame_buffer_decode evt;
+	struct al_codec_dev *codec = ctx->codec;
+	struct vb2_v4l2_buffer *vbuf;
+	struct al_buffer_meta *meta;
+
+	if (al_common_get_data(codec, (char *)&evt, hdr->payload_len)) {
+		al_v4l2_err(codec, "Unable to get frame buffer event");
+		return;
+	}
+
+	vbuf = al_dec_dequeue_dst_buf(ctx, evt.bufferHandle);
+	if (!vbuf) {
+		al_v4l2_err(codec, "Unable to find frame buffer 0x%llx",
+			    evt.bufferHandle);
+		return;
+	}
+
+	meta = &evt.meta;
+	al_v4l2_dbg(codec, 3, "Decoded frame done for buffer %p (%d) (%lld)",
+		    vbuf, meta->last, evt.size);
+
+	vb2_set_plane_payload(&vbuf->vb2_buf, 0, evt.size);
+	vbuf->field = V4L2_FIELD_NONE;
+	vbuf->sequence = ctx->csequence++;
+	vbuf->timecode = meta->timecode;
+	vbuf->vb2_buf.timestamp = meta->timestamp;
+
+	if (meta->last || (vbuf->flags & V4L2_BUF_FLAG_LAST)) {
+		vbuf->flags |= V4L2_BUF_FLAG_LAST;
+		v4l2_m2m_mark_stopped(ctx->fh.m2m_ctx);
+	}
+
+	v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
+}
+
+static int al_handle_cmd_reply(struct al_codec_dev *codec,
+			       struct msg_itf_header *hdr)
+{
+	struct al_dec_ctx *ctx;
+	struct al_codec_cmd *cmd = NULL;
+	int ret = 0;
+
+	ctx = al_ctx_get(codec, hdr->drv_ctx_hdl);
+	if (IS_ERR_OR_NULL(ctx)) {
+		al_v4l2_err(codec, "Unable to find ctx %p for reply %d",
+			    al_phys_to_virt(hdr->drv_ctx_hdl), hdr->type);
+		return -EINVAL;
+	}
+
+	cmd = al_codec_cmd_get(&ctx->cmd_q_list, hdr->drv_cmd_hdl);
+	if (!cmd) {
+		al_v4l2_err(codec, "Unable to find command %p for reply %d",
+			    al_phys_to_virt(hdr->drv_cmd_hdl), hdr->type);
+		ret = -EINVAL;
+		goto ctx_put;
+	}
+
+	if (cmd->reply_size != hdr->payload_len) {
+		al_v4l2_err(codec, "mismatch size %d %d", cmd->reply_size,
+			    hdr->payload_len);
+		ret = -EINVAL;
+		goto cmd_put;
+	}
+
+	ret = al_common_get_data(codec, cmd->reply, hdr->payload_len);
+	if (ret)
+		al_v4l2_err(codec, "Unable to copy reply");
+
+	complete(&cmd->done);
+	ret = 0;
+
+cmd_put:
+	al_codec_cmd_put(cmd);
+ctx_put:
+	al_ctx_put(ctx);
+
+	return ret;
+}
+
+static int al_handle_cmd_evt(struct al_codec_dev *dev,
+			     struct msg_itf_header *hdr, int type)
+{
+	static u32 evt_sizes[] = {
+		sizeof(struct msg_itf_evt_error),
+		sizeof(struct msg_itf_evt_resolution_found),
+		sizeof(struct msg_itf_evt_bitstream_buffer_release),
+		sizeof(struct msg_itf_evt_frame_buffer_decode),
+		sizeof(struct msg_itf_evt_eos),
+	};
+
+	u32 evt_size;
+	struct al_dec_ctx *ctx = NULL;
+	int ret = 0;
+
+	if (type < MSG_ITF_TYPE_NEXT_EVT || type > MSG_ITF_TYPE_END_EVT) {
+		al_v4l2_err(dev, "Unsupporting event type %d", type);
+		return -EINVAL;
+	}
+
+	ctx = al_ctx_get(dev, hdr->drv_ctx_hdl);
+	if (!ctx) {
+		al_v4l2_err(dev, "Unable to find ctx %p for evt %d",
+			    al_phys_to_virt(hdr->drv_ctx_hdl), type);
+		return -EINVAL;
+	}
+
+	// Check the received event size and the expected one
+	evt_size = evt_sizes[type - MSG_ITF_TYPE_NEXT_EVT];
+	if (hdr->payload_len != evt_size) {
+		al_v4l2_err(
+			dev,
+			"Invalid event size for client (%p) for evt (%d) : Got (%d), expected (%d)",
+			al_phys_to_virt(hdr->drv_ctx_hdl), type,
+			hdr->payload_len, evt_size);
+		ret = -EINVAL;
+		goto clean_ctx;
+	}
+
+	al_v4l2_dbg(dev, 3, "Event received from MCU (%d)", type);
+
+	switch (type) {
+	case MSG_ITF_TYPE_EVT_ERROR:
+		handle_error_evt(ctx, hdr);
+		break;
+	case MSG_ITF_TYPE_EVT_RESOLUTION_FOUND:
+		handle_resolution_found_evt(ctx, hdr);
+		break;
+	case MSG_ITF_TYPE_EVT_BITSTREAM_BUFFER_RELEASE:
+		handle_bitstream_buffer_release_evt(ctx, hdr);
+		break;
+	case MSG_ITF_TYPE_EVT_FRAME_BUFFER_DECODE:
+		handle_frame_buffer_decode_evt(ctx, hdr);
+		break;
+	case MSG_ITF_TYPE_EVT_EOS:
+		handle_eos_evt(ctx, hdr);
+		break;
+	default:
+		break;
+	}
+
+clean_ctx:
+	al_ctx_put(ctx);
+	return ret;
+}
+
+static void al_dec_process_msg(void *cb_arg, struct msg_itf_header *hdr)
+{
+	struct al_codec_dev *dev = cb_arg;
+	int ret;
+
+	if (is_type_reply(hdr->type))
+		ret = al_handle_cmd_reply(dev, hdr);
+	else if (is_type_event(hdr->type))
+		ret = al_handle_cmd_evt(dev, hdr, hdr->type);
+	else {
+		al_v4l2_err(dev, "Unsupported message type %d", hdr->type);
+		ret = -EINVAL;
+	}
+
+	if (ret) {
+		al_v4l2_err(dev, "Skip received data");
+		al_common_skip_data(dev, hdr->payload_len);
+	}
+}
+
+static const struct video_device al_videodev = {
+	.name = "allegro-decoder",
+	.fops = &al_dec_file_ops,
+	.ioctl_ops = &al_dec_ioctl_ops,
+	.minor = -1,
+	.release = video_device_release_empty,
+	.vfl_dir = VFL_DIR_M2M,
+	.device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
+};
+
+static void al_dec_register_v4l2(void *cb_arg)
+{
+	struct al_codec_dev *dev = cb_arg;
+	struct video_device *video_dev = NULL;
+	int ret;
+
+	ret = v4l2_device_register(&dev->pdev->dev, &dev->v4l2_dev);
+	if (ret) {
+		al_v4l2_err(dev, "Unable to register v4l2 device %d", ret);
+		return;
+	}
+
+	dev->m2m_dev = v4l2_m2m_init(&al_dec_m2m_ops);
+	if (IS_ERR(dev->m2m_dev)) {
+		ret = PTR_ERR(dev->m2m_dev);
+		al_v4l2_err(dev, "failed to init mem2mem device %d", ret);
+		goto v4l2_m2m_init_error;
+	}
+
+	video_dev = &dev->video_dev;
+	*video_dev = al_videodev;
+
+	video_dev->lock = &dev->lock;
+	video_dev->v4l2_dev = &dev->v4l2_dev;
+
+	video_set_drvdata(video_dev, dev);
+	ret = video_register_device(video_dev, VFL_TYPE_VIDEO, -1);
+	if (ret) {
+		al_v4l2_err(dev, "failed to register video device %d", ret);
+		goto video_register_device_error;
+	}
+
+	v4l2_info(&dev->v4l2_dev, "registered as /dev/video%d\n",
+		  dev->video_dev.num);
+
+	dev->init_done = true;
+
+	return;
+
+video_register_device_error:
+	v4l2_m2m_release(dev->m2m_dev);
+v4l2_m2m_init_error:
+	v4l2_device_unregister(&dev->v4l2_dev);
+}
+
+static int al_dec_probe(struct platform_device *pdev)
+{
+	struct al_codec_dev *codec;
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	const struct al_match_data *match_data;
+	const char *firmware;
+	int ret;
+
+	dev_info(dev, "Probing ...\n");
+
+	match_data = device_get_match_data(dev);
+	if (!match_data) {
+		dev_err(dev, "Missing device match data\n");
+		return -EINVAL;
+	}
+
+	codec = devm_kzalloc(dev, sizeof(*codec), GFP_KERNEL);
+	if (!codec)
+		return -ENOMEM;
+
+	codec->pdev = pdev;
+	codec->init_done = false;
+	codec->ctx_counter = 0;
+	mutex_init(&codec->lock);
+	mutex_init(&codec->ctx_mlock);
+	INIT_LIST_HEAD(&codec->ctx_q_list);
+
+	codec->cb_arg = codec;
+	codec->process_msg_cb = al_dec_process_msg;
+	codec->fw_ready_cb = al_dec_register_v4l2;
+
+	/* firmware-name is optional in DT */
+	of_property_read_string(np, "firmware-name", &firmware);
+	if (!firmware)
+		firmware = match_data->fw_name;
+
+	ret = al_common_probe(codec, firmware);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, codec);
+	al_codec_dbgfs_init(codec);
+	dev_info(dev, "Probing done successfully %p\n", codec);
+
+	return 0;
+}
+
+static void al_dec_remove(struct platform_device *pdev)
+{
+	struct al_codec_dev *dev = platform_get_drvdata(pdev);
+
+	dev_info(&pdev->dev, "remove %p\n", dev);
+
+	if (dev->init_done) {
+		video_unregister_device(&dev->video_dev);
+		if (dev->m2m_dev)
+			v4l2_m2m_release(dev->m2m_dev);
+		v4l2_device_unregister(&dev->v4l2_dev);
+	}
+	al_codec_dbgfs_deinit(&dev->dbgfs);
+	al_common_remove(dev);
+}
+
+static const struct al_match_data ald300_data = {
+	.fw_name = "al300-vdec.fw",
+};
+
+static const struct of_device_id __maybe_unused v4l2_al_dec_dt_match[] = {
+	{ .compatible = "allegro,al300-vdec", .data = &ald300_data },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, v4l2_al_dec_dt_match);
+
+static struct platform_driver al300_vdec_drv = {
+	.probe = al_dec_probe,
+	.remove = al_dec_remove,
+	.driver = {
+		.name = "al300_vdec",
+		.of_match_table = of_match_ptr(v4l2_al_dec_dt_match),
+	},
+};
+
+module_platform_driver(al300_vdec_drv);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:al300-vdec");
+MODULE_AUTHOR("Yassine OUAISSA <yassine.ouaissa at allegrodvt.com>");
+MODULE_DESCRIPTION("Allegro DVT V4l2 decoder driver gen 3");
diff --git a/drivers/media/platform/allegro-dvt/al300/al_vdec_drv.h b/drivers/media/platform/allegro-dvt/al300/al_vdec_drv.h
new file mode 100644
index 000000000000..a9f4818bcc94
--- /dev/null
+++ b/drivers/media/platform/allegro-dvt/al300/al_vdec_drv.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2025 Allegro DVT.
+ * Author: Yassine OUAISSA <yassine.ouaissa at allegrodvt.fr>
+ */
+
+#ifndef __AL_VDEC_DRV__
+#define __AL_VDEC_DRV__
+
+#include <media/v4l2-ctrls.h>
+#include <media/videobuf2-core.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "al_codec_common.h"
+
+enum {
+	MSG_ITF_TYPE_EVT_RESOLUTION_FOUND = MSG_ITF_TYPE_NEXT_EVT + 1,
+	MSG_ITF_TYPE_EVT_BITSTREAM_BUFFER_RELEASE,
+	MSG_ITF_TYPE_EVT_FRAME_BUFFER_DECODE,
+	MSG_ITF_TYPE_EVT_EOS,
+	/* Mark the end of the events list.*/
+	MSG_ITF_TYPE_END_EVT,
+};
+
+struct msg_itf_create_decoder_req {
+	unsigned int codec;
+} __packed;
+DECLARE_FULL_REQ(msg_itf_create_decoder_req);
+
+struct msg_itf_evt_resolution_found {
+	u16 buffer_nb;
+	u16 width;
+	u16 height;
+	u32 pixelformat;
+	u32 sizeimage;
+	u32 bytesperline;
+} __packed;
+DECLARE_FULL_EVENT(msg_itf_evt_resolution_found);
+
+struct msg_itf_evt_bitstream_buffer_release {
+	u64 bufferHandle;
+} __packed;
+DECLARE_FULL_EVENT(msg_itf_evt_bitstream_buffer_release);
+
+struct msg_itf_evt_frame_buffer_decode {
+	u64 bufferHandle;
+	u64 size;
+	struct al_buffer_meta meta;
+} __packed;
+DECLARE_FULL_EVENT(msg_itf_evt_frame_buffer_decode);
+
+struct msg_itf_evt_eos {
+	u32 unused;
+} __packed;
+DECLARE_FULL_EVENT(msg_itf_evt_eos);
+
+struct al_fmt {
+	u32 pixelformat;
+	u8 bpp;
+};
+
+struct al_frame {
+	u32 width;
+	u32 height;
+	u32 bytesperline;
+	u32 sizeimage;
+	u32 nbuffers;
+	const struct al_fmt *fmt;
+	enum v4l2_field field;
+	enum v4l2_colorspace colorspace;
+	enum v4l2_ycbcr_encoding ycbcr_enc;
+	enum v4l2_quantization quantization;
+	enum v4l2_xfer_func xfer_func;
+};
+
+struct al_dec_ctx {
+	struct al_codec_dev *codec;
+	struct v4l2_fh fh;
+	struct v4l2_ctrl_handler ctrl_handler;
+	struct kref refcount;
+	struct list_head list;
+	/* CAP and OUT frames */
+	struct al_frame src;
+	struct al_frame dst;
+	struct completion res_done; /* Resolution found event */
+	struct list_head cmd_q_list; /* Store active commands */
+	struct mutex buf_q_mlock;
+	struct list_head frame_q_list;
+	struct list_head stream_q_list;
+	u64 hDec;
+	u32 csequence;
+	u32 osequence;
+	u64 id;
+	bool stopped;
+	bool aborting;
+};
+
+#endif /*__AL_VDEC_DRV__*/

-- 
2.50.1




From devnull+yassine.ouaissa.allegrodvt.com at kernel.org  Mon Dec  8 05:41:22 2025
From: devnull+yassine.ouaissa.allegrodvt.com at kernel.org (Yassine Ouaissa via B4 Relay)
Date: Mon, 08 Dec 2025 14:41:22 +0100
Subject: [PATCH v6 2/4] dt-bindings: media: allegro: Add al300 decoder IPs
In-Reply-To: <20251208-allegro_dvt_al300_dec_driver-v6-0-2e51ab2e4ce9@allegrodvt.com>
References: <20251208-allegro_dvt_al300_dec_driver-v6-0-2e51ab2e4ce9@allegrodvt.com>
Message-ID: <20251208-allegro_dvt_al300_dec_driver-v6-2-2e51ab2e4ce9@allegrodvt.com>

From: Yassine Ouaissa <yassine.ouaissa at allegrodvt.com>

Add a schema for the allegro gen3 video decoder.

Acked-by: Conor Dooley <conor.dooley at microchip.com>
Signed-off-by: Yassine Ouaissa <yassine.ouaissa at allegrodvt.com>
---
 .../bindings/media/allegro,al300-vdec.yaml         | 76 ++++++++++++++++++++++
 MAINTAINERS                                        |  2 +
 2 files changed, 78 insertions(+)

diff --git a/Documentation/devicetree/bindings/media/allegro,al300-vdec.yaml b/Documentation/devicetree/bindings/media/allegro,al300-vdec.yaml
new file mode 100644
index 000000000000..12e86c306d55
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/allegro,al300-vdec.yaml
@@ -0,0 +1,76 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/allegro,al300-vdec.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allegro DVT Video IP Decoder Gen 3
+
+maintainers:
+  - Yassine OUAISSA <yassine.ouaissa at allegrodvt.com>
+
+description:
+  The al300-vdec represents the gen 3 of Allegro DVT IP video
+  decoding technology, offering significant advancements over its
+  predecessors. This new decoder features enhanced processing capabilities
+  with improved throughput and reduced latency.
+
+  Communication between the host driver software and the MCU is implemented
+  through a specialized mailbox interface mechanism. This mailbox system
+  provides a structured channel for exchanging commands, parameters, and
+  status information between the host CPU and the MCU controlling the codec
+  engines.
+
+properties:
+  compatible:
+    const: allegro,al300-vdec
+
+  reg:
+    maxItems: 2
+
+  reg-names:
+    items:
+      - const: top
+      - const: apb
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    description: MCU core clock
+    maxItems: 1
+
+  memory-region:
+    maxItems: 1
+
+  firmware-name:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - interrupts
+  - clocks
+
+additionalProperties: False
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    axi {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        video-decoder at a0120000 {
+            compatible = "allegro,al300-vdec";
+            reg = <0x00 0xa0120000 0x00 0x10000>, /*VDEC_TOP*/
+                  <0x01 0x80000000 0x00 0x8000>;  /*MCU_APB*/
+            reg-names = "top", "apb";
+            interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
+            clocks = <&mcu_core_clk>;
+            memory-region = <&vdec_mem>;
+            firmware-name = "al300_vdec.fw";
+        };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index dc56841fa5e5..67dfc2ee1725 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -837,7 +837,9 @@ M:	Michael Tretter <m.tretter at pengutronix.de>
 R:	Pengutronix Kernel Team <kernel at pengutronix.de>
 L:	linux-media at vger.kernel.org
 S:	Maintained
+F:	Documentation/devicetree/bindings/media/allegro,al300-vdec.yaml
 F:	Documentation/devicetree/bindings/media/allegro,al5e.yaml
+F:	drivers/media/platform/allegro-dvt/al300
 F:	drivers/media/platform/allegro-dvt/zynqmp
 
 ALLIED VISION ALVIUM CAMERA DRIVER

-- 
2.50.1




From devnull+yassine.ouaissa.allegrodvt.com at kernel.org  Mon Dec  8 05:41:20 2025
From: devnull+yassine.ouaissa.allegrodvt.com at kernel.org (Yassine Ouaissa via B4 Relay)
Date: Mon, 08 Dec 2025 14:41:20 +0100
Subject: [PATCH v6 0/4] media: Add Gen 3 IP stateful decoder driver
Message-ID: <20251208-allegro_dvt_al300_dec_driver-v6-0-2e51ab2e4ce9@allegrodvt.com>

This patch series introduces a new stateful decoder driver for the
allegrodvt GEN 3 IPs.

Changes in v6:
- Reset the file->private_data to NULL in v4l2_fh_del()
- Link to v5: https://lore.kernel.org/r/20250813-allegro_dvt_al300_dec_driver-v5-0-a312ddebc4d8 at allegrodvt.com

Changes in v5:
- Fix the include issues.
- Fix the faulty warning, by adding the __maybe_unused attribute to the 'v4l2_al_dec_dt_match'.
- Fix the get_mcu_offset(), the physical address limit is set to the
  flat memory size ( 264GB ).
- Get the mcu physical addresses offset at al_common_setup_dma.
- Link to v4: https://lore.kernel.org/r/20250716-allegro_dvt_al300_dec_driver-v4-0-f87c01c9f7b5 at allegrodvt.com

Changes in v4:
- Use debugfs instead of build time DEBUG (Michael Tretter).
- Add capture and output pixelformats and resolution to the debugfs.
- Support 64-bit of physical addresses, by configuring the mcu data and
  instruction offset registers.
- Link to v3: https://lore.kernel.org/r/20250616-allegro_dvt_al300_dec_driver-v3-0-7d746cb9e5f9 at allegrodvt.com

Changes in v3:
- Remove blank line after description.(Krzysztof Kozlowski)
- Drop minItems on the reg property.(Krzysztof Kozlowski)
- Reword the patch 2 subject and description.(Krzysztof Kozlowski)
- Add the memory-region property to the example.(Krzysztof Kozlowski)
- Rename the reg-name "regs" with top. the first reg is the
  video-decoder top registers.(Krzysztof Kozlowski)
- Link to v2: https://lore.kernel.org/r/20250605-allegro_dvt_al300_dec_driver-v2-0-1ef4839f5f06 at allegrodvt.com

Changes in v2:
- patch 2:
- Change the YAML file name, use the existing vendor-prefix.
- Improuve the dt-bindings description.
- Change the device compatible identifier, from "allegrodvt, al300-vdec",
  to "allegro, al300-vdec"
- Simplify the register property specification,
  by using the simple min/max items constraint (Krzysztof Kozlowski)
- Remove the clock-names property. And remove it from the required
  properties list (Krzysztof Kozlowski) (Conor Dooley)
- Use the simple maxItems constraint for the memory-region property.
  Also for the firmware-name (Krzysztof Kozlowski)
- Example changes:
  - Use header provides definitions for the interrupts (Conor Dooley)
  - Improuve Interrupt specification using GIC constants (Conor Dooley)
  - Use generic node name "video-decoder" (Krzysztof Kozlowski) (Conor Dooley)
  - Remove unused label (Krzysztof Kozlowski)
  - Change clock reference from <&mcu_clock_dec> to <&mcu_core_clk>
  - Use hex format for reg property (Krzysztof Kozlowski) (Conor Dooley)
  - Reduce memory region size (Krzysztof Kozlowski) (Conor Dooley)

- patch 4: Fix code reviews (Nicolas Dufresne)
- MAINTAINERS: Remove my self from the "ALLEGRO DVT VIDEO IP CORE
  DRIVER".
  Link to v1: https://lore.kernel.org/all/20250523134207.68481-1-yassine.ouaissa at allegrodvt.com/

# V4L2 Video Decoder Driver System Description

** Hardware Architecture **

The system implements a heterogeneous computing architecture with two primary components:

- **Host Subsystem**: Linux-based CPU running the V4L2 framework and associated drivers
- **IP Subsystem**: Dedicated hardware containing an MCU and a hardware video CODEC

The communication between the two subsystems uses a shared DDR shared memory with bidirectional interrupt mechanism for synchronization.

The architecture is represented in the following diagram:

```
+---------------------+                  +----------------------+
|       Host          |                  |        IP            |
|                     |                  |                      |
|  +---------------+  |                  |  +----------------+  |
|  |               |  |   DDR Shared     |  |                |  |
|  | Linux Kernel  |<-|----------------->|->|     MCU        |  |
|  | (CPU)         |  |    Memory        |  |                |  |
|  |   +--------+  |  |                  |  +----------------+  |
|  |   |        |  |  |    IRQ when      |           ^          |
|  |   | V4L2   |  |<-|----new message-->|           |          |
|  |   | Drivers|  |  |                  |           |          |
|  |   |        |  |  |                  |           | APB      |
|  |   +--------+  |  |                  |           |          |
|  |               |  |                  |           v          |
|  +---------------+  |                  |  +----------------+  |
|                     |                  |  |                |  |
|                     |                  |  |     CODEC      |  |
|                     |                  |  |                |  |
|                     |                  |  |                |  |
+---------------------+                  +----------------------+
```

** Communication Protocol **

-- Current Implementation - Custom Mailbox --

The host CPU and MCU currently communicate through a custom mailbox protocol implemented over shared memory. The protocol operates as follows:

1. When the host has a new message for the MCU:
   - The host writes data to a dedicated shared memory region
   - The host triggers an interrupt to the MCU
   - The MCU reads the shared memory to obtain the message type and data

2. Similarly, when the MCU has a message for the host:
   - The MCU writes to the shared memory
   - The MCU triggers an interrupt to the host
   - The host reads the shared memory to process the message

-- Migration to RPMSG --

The custom mailbox implementation will be replaced by the standard Linux RPMSG framework.

** Driver Implementation **

This driver implements a V4L2-compliant stateful video decoder with the following characteristics:

-- Technical Specifications --

- **Codec Support**: AVC (H.264), HEVC (H.265), and JPEG
- **Resolution Support**: Up to 4K
- **Pixel Formats**:
  - Currently supported: V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_NV16, V4L2_PIX_FMT_P010
  - Additional formats planned for future releases
- **Buffer Configuration**: Currently supports semi-planar format only; multiplanar support forthcoming

-- Initialization Sequence --

During probe, the driver performs the following operations:

1. Allocates memory for the MCU firmware
2. Loads the firmware into the allocated memory
3. Initializes the MCU by configuring internal registers (e.g BOOT_ADDR)
4. Establishes the shared memory communication interface (to be replaced by RPMSG)
5. Sets up interrupt handlers for MCU communication

-- Processing Model --

The driver implements a stateful decoding model with the following workflow:

-- Stream Initialization --

1. Upon `VIDIOC_STREAMON` on the OUTPUT queue:
   - The driver sends a context creation request to the MCU
   - This operation is blocking; the driver waits until the MCU responds with a context handler
   - The context handler is stored in a driver-maintained list for subsequent operations
   - Each context has its own unique handler to support multiple simultaneous streams

2. Initial stream analysis:
   - The driver submits the first compressed buffer (OUTPUT queue)
   - The MCU analyzes the stream and reports capability via:
     - `resolution_found_event`: Stream is supported, includes stream parameters
     - `error_event`: Stream format is unsupported or invalid

-- Decoding Pipeline --

1. After successful stream initialization and receiving the resolution_found_evt:
   - The driver can begin normal decoding operations
   - V4L2 framework can be informed of format requirements

2. For each compressed buffer (OUTPUT queue):
   - The driver submits buffer to MCU with the appropriate context handler
   - The MCU processes the buffer and sends `release_bitstream_evt` when complete
   - This event signals that the input buffer can be returned to the application

3. For each decoded buffer (CAPTURE queue):
   - The MCU fills the buffer with decoded frame data
   - The MCU sends `frame_buffer_decode_evt` with important metadata including:
     - Original source buffer timestamp
     - Flags
     - Timecode
     - Actual payload size (bytes used in the decoded frame)
   - This enables the driver to properly queue the filled buffer to the application

4. End-of-stream handling:
   - The MCU sends an event with `eos_evt` when reaching the end of stream
   - This allows proper handling of end-of-stream conditions

-- Multi-stream Support --

The driver architecture supports multiple simultaneous decoding contexts with the following characteristics:

1. Each context maintains separate state information
2. The driver manages multiple context handlers returned by the MCU
3. Buffer submissions include the appropriate context handler for routing
4. The system can decode multiple independent streams concurrently

-- Stream Termination --

When `VIDIOC_STREAMOFF` is called:

1. The driver sends a flush command to the MCU for the specific context
2. The driver issues a non-blocking destroy context message
3. All associated resources are released
4. The context handler is removed from the driver's context list

** Error Handling **

The driver implements comprehensive error handling including:

1. Firmware loading failures
2. MCU initialization errors
3. Context creation failures
4. Unsupported stream formats
5. Decoding errors reported by the MCU
6. Timeout handling for unresponsive hardware

** Memory Management **

The system uses the following memory management strategy:

1. Firmware memory is allocated during probe
2. Buffer memory is managed through the V4L2 buffer management interfaces
3. DMA-capable memory is used for buffer transfers between host and MCU
4. The driver properly synchronizes memory access to avoid coherency issues

** Future Enhancements **

Planned future enhancements include:

1. Migration from custom mailbox to RPMSG (in progress)
2. Support for additional pixel formats
3. Implementation of multiplanar buffer support

This comprehensive architecture enables efficient hardware-accelerated video decoding while adhering to standard V4L2 interfaces, making it suitable for upstream inclusion in the Linux kernel.

** Decoder Compliance Testing **

-- AVC and HEVC Fluster Report --

This section contains the compliance test results from Fluster framework for both AVC and HEVC decoders.
The reports validate the decoder's conformance to relevant standards and demonstrate compatibility with a wide range of video streams.

[FLUSTER REPORT FOR THE H.264]
 -- JVT-AVC_V1

| Test                     | FFmpeg-H.264-v4l2m2m |
| ------------------------ | -------------------- |
| TOTAL                    | 79/135               |
| TOTAL TIME               | 437.031s             |
| -                        | -                    |
| AUD_MW_E                 | OK                   |
| BA1_FT_C                 | OK                   |
| BA1_Sony_D               | OK                   |
| BA2_Sony_F               | OK                   |
| BA3_SVA_C                | OK                   |
| BA_MW_D                  | OK                   |
| BAMQ1_JVC_C              | OK                   |
| BAMQ2_JVC_C              | OK                   |
| BANM_MW_D                | OK                   |
| BASQP1_Sony_C            | OK                   |
| CABA1_Sony_D             | OK                   |
| CABA1_SVA_B              | OK                   |
| CABA2_Sony_E             | OK                   |
| CABA2_SVA_B              | OK                   |
| CABA3_Sony_C             | OK                   |
| CABA3_SVA_B              | OK                   |
| CABA3_TOSHIBA_E          | OK                   |
| cabac_mot_fld0_full      | ER                   |
| cabac_mot_frm0_full      | OK                   |
| cabac_mot_mbaff0_full    | ER                   |
| cabac_mot_picaff0_full   | KO                   |
| CABACI3_Sony_B           | OK                   |
| CABAST3_Sony_E           | OK                   |
| CABASTBR3_Sony_B         | OK                   |
| CABREF3_Sand_D           | ER                   |
| CACQP3_Sony_D            | OK                   |
| CAFI1_SVA_C              | ER                   |
| CAMA1_Sony_C             | ER                   |
| CAMA1_TOSHIBA_B          | ER                   |
| cama1_vtc_c              | ER                   |
| cama2_vtc_b              | ER                   |
| CAMA3_Sand_E             | ER                   |
| cama3_vtc_b              | ER                   |
| CAMACI3_Sony_C           | ER                   |
| CAMANL1_TOSHIBA_B        | ER                   |
| CAMANL2_TOSHIBA_B        | ER                   |
| CAMANL3_Sand_E           | ER                   |
| CAMASL3_Sony_B           | ER                   |
| CAMP_MOT_MBAFF_L30       | ER                   |
| CAMP_MOT_MBAFF_L31       | ER                   |
| CANL1_Sony_E             | OK                   |
| CANL1_SVA_B              | OK                   |
| CANL1_TOSHIBA_G          | OK                   |
| CANL2_Sony_E             | OK                   |
| CANL2_SVA_B              | OK                   |
| CANL3_Sony_C             | OK                   |
| CANL3_SVA_B              | OK                   |
| CANL4_SVA_B              | OK                   |
| CANLMA2_Sony_C           | ER                   |
| CANLMA3_Sony_C           | ER                   |
| CAPA1_TOSHIBA_B          | ER                   |
| CAPAMA3_Sand_F           | ER                   |
| CAPCM1_Sand_E            | OK                   |
| CAPCMNL1_Sand_E          | OK                   |
| CAPM3_Sony_D             | OK                   |
| CAQP1_Sony_B             | OK                   |
| cavlc_mot_fld0_full_B    | ER                   |
| cavlc_mot_frm0_full_B    | OK                   |
| cavlc_mot_mbaff0_full_B  | ER                   |
| cavlc_mot_picaff0_full_B | KO                   |
| CAWP1_TOSHIBA_E          | OK                   |
| CAWP5_TOSHIBA_E          | OK                   |
| CI1_FT_B                 | OK                   |
| CI_MW_D                  | OK                   |
| CVBS3_Sony_C             | OK                   |
| CVCANLMA2_Sony_C         | ER                   |
| CVFC1_Sony_C             | OK                   |
| CVFI1_Sony_D             | ER                   |
| CVFI1_SVA_C              | ER                   |
| CVFI2_Sony_H             | ER                   |
| CVFI2_SVA_C              | ER                   |
| CVMA1_Sony_D             | ER                   |
| CVMA1_TOSHIBA_B          | ER                   |
| CVMANL1_TOSHIBA_B        | ER                   |
| CVMANL2_TOSHIBA_B        | ER                   |
| CVMAPAQP3_Sony_E         | ER                   |
| CVMAQP2_Sony_G           | ER                   |
| CVMAQP3_Sony_D           | ER                   |
| CVMP_MOT_FLD_L30_B       | ER                   |
| CVMP_MOT_FRM_L31_B       | ER                   |
| CVNLFI1_Sony_C           | ER                   |
| CVNLFI2_Sony_H           | ER                   |
| CVPA1_TOSHIBA_B          | ER                   |
| CVPCMNL1_SVA_C           | OK                   |
| CVPCMNL2_SVA_C           | OK                   |
| CVSE2_Sony_B             | OK                   |
| CVSE3_Sony_H             | OK                   |
| CVSEFDFT3_Sony_E         | OK                   |
| CVWP1_TOSHIBA_E          | OK                   |
| CVWP2_TOSHIBA_E          | OK                   |
| CVWP3_TOSHIBA_E          | OK                   |
| CVWP5_TOSHIBA_E          | OK                   |
| FI1_Sony_E               | ER                   |
| FM1_BT_B                 | ER                   |
| FM1_FT_E                 | KO                   |
| FM2_SVA_C                | ER                   |
| HCBP1_HHI_A              | OK                   |
| HCBP2_HHI_A              | OK                   |
| HCMP1_HHI_A              | OK                   |
| LS_SVA_D                 | OK                   |
| MIDR_MW_D                | OK                   |
| MPS_MW_A                 | OK                   |
| MR1_BT_A                 | OK                   |
| MR1_MW_A                 | OK                   |
| MR2_MW_A                 | OK                   |
| MR2_TANDBERG_E           | OK                   |
| MR3_TANDBERG_B           | OK                   |
| MR4_TANDBERG_C           | OK                   |
| MR5_TANDBERG_C           | OK                   |
| MR6_BT_B                 | ER                   |
| MR7_BT_B                 | OK                   |
| MR8_BT_B                 | ER                   |
| MR9_BT_B                 | ER                   |
| MV1_BRCM_D               | OK                   |
| NL1_Sony_D               | OK                   |
| NL2_Sony_H               | OK                   |
| NL3_SVA_E                | OK                   |
| NLMQ1_JVC_C              | OK                   |
| NLMQ2_JVC_C              | OK                   |
| NRF_MW_E                 | OK                   |
| Sharp_MP_Field_1_B       | ER                   |
| Sharp_MP_Field_2_B       | ER                   |
| Sharp_MP_Field_3_B       | ER                   |
| Sharp_MP_PAFF_1r2        | ER                   |
| Sharp_MP_PAFF_2r         | ER                   |
| SL1_SVA_B                | OK                   |
| SP1_BT_A                 | ER                   |
| sp2_bt_b                 | ER                   |
| SVA_BA1_B                | OK                   |
| SVA_BA2_D                | OK                   |
| SVA_Base_B               | OK                   |
| SVA_CL1_E                | OK                   |
| SVA_FM1_E                | OK                   |
| SVA_NL1_B                | OK                   |
| SVA_NL2_E                | OK                   |
| -                        | -                    |
| Test                     | FFmpeg-H.264-v4l2m2m |
| TOTAL                    | 79/135               |
| TOTAL TIME               | 439.031s             |

NOTE: The ER (ERROR) streams are not supported by the decoder.
      The driver print error message "Unsupported stream"

- JVT-FR-EXT

| Test                | FFmpeg-H.264-v4l2m2m |
| ------------------- | -------------------- |
| TOTAL               | 23/69                |
| TOTAL TIME          | 182.362s             |
| -                   | -                    |
| alphaconformanceG   | OK                   |
| brcm_freh10         | ER                   |
| brcm_freh11         | ER                   |
| brcm_freh3          | OK                   |
| brcm_freh4          | ER                   |
| brcm_freh5          | ER                   |
| brcm_freh6          | ER                   |
| brcm_freh8          | OK                   |
| brcm_freh9          | OK                   |
| FREH10-1            | ER                   |
| FREH10-2            | ER                   |
| freh12_b            | OK                   |
| freh1_b             | OK                   |
| freh2_b             | OK                   |
| freh7_b             | ER                   |
| FREXT01_JVC_D       | ER                   |
| FREXT02_JVC_C       | ER                   |
| FRExt1_Panasonic_D  | OK                   |
| FREXT1_TANDBERG_A   | ER                   |
| FRExt2_Panasonic_C  | ER                   |
| FREXT2_TANDBERG_A   | ER                   |
| FRExt3_Panasonic_E  | OK                   |
| FREXT3_TANDBERG_A   | ER                   |
| FRExt4_Panasonic_B  | ER                   |
| FRExt_MMCO4_Sony_B  | OK                   |
| HCAFF1_HHI_B        | ER                   |
| HCAFR1_HHI_C        | OK                   |
| HCAFR2_HHI_A        | OK                   |
| HCAFR3_HHI_A        | OK                   |
| HCAFR4_HHI_A        | OK                   |
| HCAMFF1_HHI_B       | ER                   |
| HCHP1_HHI_B         | OK                   |
| HCHP2_HHI_A         | OK                   |
| HCHP3_HHI_A         | ER                   |
| Hi422FR10_SONY_A    | ER                   |
| Hi422FR11_SONY_A    | ER                   |
| Hi422FR12_SONY_A    | ER                   |
| Hi422FR13_SONY_A    | ER                   |
| Hi422FR14_SONY_A    | ER                   |
| Hi422FR15_SONY_A    | ER                   |
| Hi422FR1_SONY_A     | ER                   |
| Hi422FR2_SONY_A     | ER                   |
| Hi422FR3_SONY_A     | ER                   |
| Hi422FR4_SONY_A     | ER                   |
| Hi422FR6_SONY_A     | ER                   |
| Hi422FR7_SONY_A     | ER                   |
| Hi422FR8_SONY_A     | ER                   |
| Hi422FR9_SONY_A     | ER                   |
| Hi422FREXT16_SONY_A | ER                   |
| Hi422FREXT17_SONY_A | ER                   |
| Hi422FREXT18_SONY_A | ER                   |
| Hi422FREXT19_SONY_A | ER                   |
| HPCA_BRCM_C         | OK                   |
| HPCADQ_BRCM_B       | OK                   |
| HPCAFL_BRCM_C       | ER                   |
| HPCAFLNL_BRCM_C     | ER                   |
| HPCALQ_BRCM_B       | OK                   |
| HPCAMAPALQ_BRCM_B   | ER                   |
| HPCAMOLQ_BRCM_B     | ER                   |
| HPCANL_BRCM_C       | OK                   |
| HPCAQ2LQ_BRCM_B     | OK                   |
| HPCV_BRCM_A         | OK                   |
| HPCVFL_BRCM_A       | ER                   |
| HPCVFLNL_BRCM_A     | ER                   |
| HPCVMOLQ_BRCM_B     | ER                   |
| HPCVNL_BRCM_A       | OK                   |
| HVLCFI0_Sony_B      | ER                   |
| HVLCMFF0_Sony_B     | ER                   |
| HVLCPFF0_Sony_B     | ER                   |
| -                   | -                    |
| Test                | FFmpeg-H.264-v4l2m2m |
| TOTAL               | 23/69                |
| TOTAL TIME          | 182.362s             |

NOTE: The ER (ERROR) streams are not supported by the decoder.
      The driver print error message "Unsupported stream"

- JVT-MVC

| Test       | FFmpeg-H.264-v4l2m2m |
| ---------- | -------------------- |
| TOTAL      | 18/20                |
| TOTAL TIME | 147.076s             |
| -          | -                    |
| MVCDS-4    | OK                   |
| MVCDS-5    | OK                   |
| MVCDS-6    | OK                   |
| MVCDS1     | OK                   |
| MVCDS2     | OK                   |
| MVCDS3     | OK                   |
| MVCICT-1   | ER                   |
| MVCICT-2   | ER                   |
| MVCNV-2    | OK                   |
| MVCNV-3    | OK                   |
| MVCNV1     | OK                   |
| MVCNV4     | OK                   |
| MVCRP_1    | OK                   |
| MVCRP_2    | OK                   |
| MVCRP_3    | OK                   |
| MVCRP_4    | OK                   |
| MVCRP_5    | OK                   |
| MVCRP_6    | OK                   |
| MVCSPS-1   | OK                   |
| MVCSPS-2   | OK                   |
| -          | -                    |
| Test       | FFmpeg-H.264-v4l2m2m |
| TOTAL      | 18/20                |
| TOTAL TIME | 147.076s             |

- JVT-SVC

| Test            | FFmpeg-H.264-v4l2m2m |
| --------------- | -------------------- |
| TOTAL           | 75/185               |
| TOTAL TIME      | 727.240s             |
| -               | -                    |
| SVCBC-1-L0      | OK                   |
| SVCBC-1-L1      | KO                   |
| SVCBCT-1-L0     | OK                   |
| SVCBCT-1-L1     | KO                   |
| SVCBCTS-1-r1-L0 | OK                   |
| SVCBCTS-1-r1-L1 | KO                   |
| SVCBCTS-1-r1-L2 | KO                   |
| SVCBCTS-2-r1-L0 | OK                   |
| SVCBCTS-2-r1-L1 | KO                   |
| SVCBCTS-2-r1-L2 | KO                   |
| SVCBCTS-3-L0    | OK                   |
| SVCBCTS-3-L1    | KO                   |
| SVCBCTS-3-L2    | KO                   |
| SVCBM-1-L0      | OK                   |
| SVCBM-1-L1      | KO                   |
| SVCBM-2-L0      | OK                   |
| SVCBM-2-L1      | KO                   |
| SVCBM-3-L0      | OK                   |
| SVCBM-3-L1      | KO                   |
| SVCBM-4-r1-L0   | OK                   |
| SVCBM-4-r1-L1   | KO                   |
| SVCBM-4-r1-L2   | KO                   |
| SVCBM-5-L0      | OK                   |
| SVCBM-5-L1      | KO                   |
| SVCBM-5-L2      | KO                   |
| SVCBM-5-L3      | KO                   |
| SVCBMST-1-L0    | OK                   |
| SVCBMST-1-L1    | KO                   |
| SVCBMST-1-L2    | KO                   |
| SVCBMST-2-L0    | OK                   |
| SVCBMST-2-L1    | KO                   |
| SVCBMST-2-L2    | KO                   |
| SVCBMST-3-L0    | OK                   |
| SVCBMST-3-L1    | KO                   |
| SVCBMST-3-L2    | KO                   |
| SVCBMT-1-L0     | OK                   |
| SVCBMT-1-L1     | KO                   |
| SVCBMT-10-L0    | OK                   |
| SVCBMT-10-L1    | KO                   |
| SVCBMT-11-L0    | OK                   |
| SVCBMT-11-L1    | KO                   |
| SVCBMT-12-L0    | OK                   |
| SVCBMT-12-L1    | KO                   |
| SVCBMT-13-L0    | OK                   |
| SVCBMT-13-L1    | KO                   |
| SVCBMT-13-L2    | KO                   |
| SVCBMT-2-L0     | OK                   |
| SVCBMT-2-L1     | KO                   |
| SVCBMT-3-L0     | OK                   |
| SVCBMT-3-L1     | KO                   |
| SVCBMT-4-L0     | OK                   |
| SVCBMT-4-L1     | KO                   |
| SVCBMT-5-L0     | OK                   |
| SVCBMT-5-L1     | KO                   |
| SVCBMT-6-L0     | OK                   |
| SVCBMT-6-L1     | KO                   |
| SVCBMT-7-L0     | OK                   |
| SVCBMT-7-L1     | KO                   |
| SVCBMT-8-L0     | OK                   |
| SVCBMT-8-L1     | KO                   |
| SVCBMT-9-L0     | OK                   |
| SVCBMT-9-L1     | KO                   |
| SVCBS-1-L0      | OK                   |
| SVCBS-1-L1      | KO                   |
| SVCBS-2-L0      | OK                   |
| SVCBS-2-L1      | KO                   |
| SVCBS-3-r1-L0   | OK                   |
| SVCBS-3-r1-L1   | KO                   |
| SVCBS-4-r1-L0   | OK                   |
| SVCBS-4-r1-L1   | KO                   |
| SVCBS-5-r1-L0   | OK                   |
| SVCBS-5-r1-L1   | KO                   |
| SVCBS-6-r1-L0   | OK                   |
| SVCBS-6-r1-L1   | KO                   |
| SVCBS-6-r1-L2   | KO                   |
| SVCBS-7-L0      | OK                   |
| SVCBS-7-L1      | KO                   |
| SVCBS-8-L0      | OK                   |
| SVCBS-8-L1      | KO                   |
| SVCBST-1-L0     | OK                   |
| SVCBST-1-L1     | KO                   |
| SVCBST-10-r1-L0 | OK                   |
| SVCBST-10-r1-L1 | KO                   |
| SVCBST-11-r1-L0 | OK                   |
| SVCBST-11-r1-L1 | KO                   |
| SVCBST-12-r1-L0 | OK                   |
| SVCBST-12-r1-L1 | KO                   |
| SVCBST-13-L0    | OK                   |
| SVCBST-13-L1    | KO                   |
| SVCBST-14-L0    | OK                   |
| SVCBST-14-L1    | KO                   |
| SVCBST-14-L2    | KO                   |
| SVCBST-15-L0    | OK                   |
| SVCBST-15-L1    | KO                   |
| SVCBST-15-L2    | KO                   |
| SVCBST-16-r1-L0 | OK                   |
| SVCBST-16-r1-L1 | KO                   |
| SVCBST-16-r1-L2 | KO                   |
| SVCBST-17-r1-L0 | OK                   |
| SVCBST-17-r1-L1 | KO                   |
| SVCBST-17-r1-L2 | KO                   |
| SVCBST-18-r1-L0 | OK                   |
| SVCBST-18-r1-L1 | KO                   |
| SVCBST-18-r1-L2 | KO                   |
| SVCBST-19-L0    | OK                   |
| SVCBST-19-L1    | KO                   |
| SVCBST-2-L0     | OK                   |
| SVCBST-2-L1     | KO                   |
| SVCBST-20-L0    | OK                   |
| SVCBST-20-L1    | KO                   |
| SVCBST-3-L0     | OK                   |
| SVCBST-3-L1     | KO                   |
| SVCBST-4-L0     | OK                   |
| SVCBST-4-L1     | KO                   |
| SVCBST-5-L0     | OK                   |
| SVCBST-5-L1     | KO                   |
| SVCBST-6-r1-L0  | OK                   |
| SVCBST-6-r1-L1  | KO                   |
| SVCBST-7-r1-L0  | OK                   |
| SVCBST-7-r1-L1  | KO                   |
| SVCBST-8-r1-L0  | OK                   |
| SVCBST-8-r1-L1  | KO                   |
| SVCBST-9-r1-L0  | OK                   |
| SVCBST-9-r1-L1  | KO                   |
| SVCBSTC-1-L0    | OK                   |
| SVCBSTC-1-L1    | KO                   |
| SVCBSTC-1-L2    | KO                   |
| SVCHCTS-1-r1-L0 | OK                   |
| SVCHCTS-1-r1-L1 | KO                   |
| SVCHCTS-1-r1-L2 | KO                   |
| SVCHCTS-1-r1-L3 | KO                   |
| SVCHCTS-1-r1-L4 | KO                   |
| SVCHCTS-1-r1-L5 | KO                   |
| SVCHCTS-1-r1-L6 | KO                   |
| SVCHCTS-1-r1-L7 | KO                   |
| SVCHICS-1-L0    | OK                   |
| SVCHICS-1-L1    | KO                   |
| SVCHICS-1-L2    | KO                   |
| SVCHICS-1-L3    | KO                   |
| SVCHIS-1-L0     | OK                   |
| SVCHIS-1-L1     | KO                   |
| SVCHIS-1-L2     | KO                   |
| SVCHIS-2-L0     | OK                   |
| SVCHIS-2-L1     | KO                   |
| SVCHIS-2-L2     | KO                   |
| SVCHIS-3-L0     | OK                   |
| SVCHIS-3-L1     | KO                   |
| SVCHIS-3-L2     | KO                   |
| SVCHM-1-L0      | OK                   |
| SVCHM-1-L1      | KO                   |
| SVCHM-1-L2      | KO                   |
| SVCHM-1-L3      | KO                   |
| SVCHM-2-L0      | OK                   |
| SVCHM-2-L1      | OK                   |
| SVCHM-3-L0      | OK                   |
| SVCHM-3-L1      | OK                   |
| SVCHM-4-L0      | OK                   |
| SVCHM-4-L1      | OK                   |
| SVCHM-4-L2      | OK                   |
| SVCHMTS-1-r1-L0 | OK                   |
| SVCHMTS-1-r1-L1 | KO                   |
| SVCHMTS-1-r1-L2 | KO                   |
| SVCHMTS-1-r1-L3 | KO                   |
| SVCHMTS-1-r1-L4 | KO                   |
| SVCHMTS-1-r1-L5 | KO                   |
| SVCHMTS-2-r1-L0 | OK                   |
| SVCHMTS-2-r1-L1 | KO                   |
| SVCHMTS-2-r1-L2 | KO                   |
| SVCHS-1-r1-L0   | OK                   |
| SVCHS-1-r1-L1   | KO                   |
| SVCHS-2-r1-L0   | OK                   |
| SVCHS-2-r1-L1   | KO                   |
| SVCHST-1-r1-L0  | OK                   |
| SVCHST-1-r1-L1  | KO                   |
| SVCHST-1-r1-L2  | KO                   |
| SVCHST-2-r1-L0  | OK                   |
| SVCHST-2-r1-L1  | KO                   |
| SVCHST-2-r1-L2  | KO                   |
| SVCHST-3-r1-L0  | ER                   |
| SVCHST-3-r1-L1  | ER                   |
| SVCHST-4-r1-L0  | ER                   |
| SVCHST-4-r1-L1  | ER                   |
| SVCHSTC-1-r1-L0 | OK                   |
| SVCHSTC-1-r1-L1 | KO                   |
| SVCHSTC-1-r1-L2 | KO                   |
| -               | -                    |
| Test            | FFmpeg-H.264-v4l2m2m |
| TOTAL           | 75/185               |
| TOTAL TIME      | 727.240s             |

NOTE: The current implementation of the decoder only supports Layer 0 (base layer) processing.
When attempting to decode streams that contain multiple layers (such as scalable or multi-view content), the decoding operation fails.
This limitation means that enhanced features requiring layer-based processing beyond the base layer cannot be properly handled by the current decoder.
For successful decoding, input streams must be limited to single-layer content only.

[FLUSTER REPORT FOR THE H.265]

| -                               | -                    |
| AMP_A_Samsung_7                 | OK                   |
| AMP_B_Samsung_7                 | OK                   |
| AMP_D_Hisilicon_3               | OK                   |
| AMP_E_Hisilicon_3               | OK                   |
| AMP_F_Hisilicon_3               | ER                   |
| AMVP_A_MTK_4                    | ER                   |
| AMVP_B_MTK_4                    | OK                   |
| AMVP_C_Samsung_7                | ER                   |
| BUMPING_A_ericsson_1            | OK                   |
| CAINIT_A_SHARP_4                | OK                   |
| CAINIT_B_SHARP_4                | OK                   |
| CAINIT_C_SHARP_3                | OK                   |
| CAINIT_D_SHARP_3                | OK                   |
| CAINIT_E_SHARP_3                | OK                   |
| CAINIT_F_SHARP_3                | OK                   |
| CAINIT_G_SHARP_3                | OK                   |
| CAINIT_H_SHARP_3                | OK                   |
| CIP_A_Panasonic_3               | OK                   |
| cip_B_NEC_3                     | OK                   |
| CIP_C_Panasonic_2               | OK                   |
| CONFWIN_A_Sony_1                | OK                   |
| DBLK_A_MAIN10_VIXS_4            | ER                   |
| DBLK_A_SONY_3                   | OK                   |
| DBLK_B_SONY_3                   | OK                   |
| DBLK_C_SONY_3                   | OK                   |
| DBLK_D_VIXS_2                   | OK                   |
| DBLK_E_VIXS_2                   | OK                   |
| DBLK_F_VIXS_2                   | OK                   |
| DBLK_G_VIXS_2                   | OK                   |
| DELTAQP_A_BRCM_4                | OK                   |
| DELTAQP_B_SONY_3                | OK                   |
| DELTAQP_C_SONY_3                | OK                   |
| DSLICE_A_HHI_5                  | OK                   |
| DSLICE_B_HHI_5                  | OK                   |
| DSLICE_C_HHI_5                  | OK                   |
| ENTP_A_QUALCOMM_1               | OK                   |
| ENTP_B_Qualcomm_1               | OK                   |
| ENTP_C_Qualcomm_1               | OK                   |
| EXT_A_ericsson_4                | OK                   |
| FILLER_A_Sony_1                 | OK                   |
| HRD_A_Fujitsu_3                 | OK                   |
| INITQP_A_Sony_1                 | OK                   |
| INITQP_B_Main10_Sony_1          | ER                   |
| ipcm_A_NEC_3                    | OK                   |
| ipcm_B_NEC_3                    | OK                   |
| ipcm_C_NEC_3                    | OK                   |
| ipcm_D_NEC_3                    | OK                   |
| ipcm_E_NEC_2                    | OK                   |
| IPRED_A_docomo_2                | OK                   |
| IPRED_B_Nokia_3                 | OK                   |
| IPRED_C_Mitsubishi_3            | OK                   |
| LS_A_Orange_2                   | OK                   |
| LS_B_Orange_4                   | OK                   |
| LTRPSPS_A_Qualcomm_1            | KO                   |
| MAXBINS_A_TI_5                  | OK                   |
| MAXBINS_B_TI_5                  | OK                   |
| MAXBINS_C_TI_5                  | OK                   |
| MERGE_A_TI_3                    | OK                   |
| MERGE_B_TI_3                    | OK                   |
| MERGE_C_TI_3                    | OK                   |
| MERGE_D_TI_3                    | OK                   |
| MERGE_E_TI_3                    | OK                   |
| MERGE_F_MTK_4                   | OK                   |
| MERGE_G_HHI_4                   | OK                   |
| MVCLIP_A_qualcomm_3             | OK                   |
| MVDL1ZERO_A_docomo_4            | OK                   |
| MVEDGE_A_qualcomm_3             | OK                   |
| NoOutPrior_A_Qualcomm_1         | OK                   |
| NoOutPrior_B_Qualcomm_1         | OK                   |
| NUT_A_ericsson_5                | OK                   |
| OPFLAG_A_Qualcomm_1             | OK                   |
| OPFLAG_B_Qualcomm_1             | OK                   |
| OPFLAG_C_Qualcomm_1             | OK                   |
| PICSIZE_A_Bossen_1              | OK                   |
| PICSIZE_B_Bossen_1              | ER                   |
| PICSIZE_C_Bossen_1              | OK                   |
| PICSIZE_D_Bossen_1              | ER                   |
| PMERGE_A_TI_3                   | OK                   |
| PMERGE_B_TI_3                   | OK                   |
| PMERGE_C_TI_3                   | OK                   |
| PMERGE_D_TI_3                   | OK                   |
| PMERGE_E_TI_3                   | OK                   |
| POC_A_Bossen_3                  | OK                   |
| PPS_A_qualcomm_7                | OK                   |
| PS_B_VIDYO_3                    | ER                   |
| RAP_A_docomo_6                  | OK                   |
| RAP_B_Bossen_2                  | OK                   |
| RPLM_A_qualcomm_4               | OK                   |
| RPLM_B_qualcomm_4               | OK                   |
| RPS_A_docomo_5                  | OK                   |
| RPS_B_qualcomm_5                | OK                   |
| RPS_C_ericsson_5                | OK                   |
| RPS_D_ericsson_6                | OK                   |
| RPS_E_qualcomm_5                | OK                   |
| RPS_F_docomo_2                  | OK                   |
| RQT_A_HHI_4                     | OK                   |
| RQT_B_HHI_4                     | OK                   |
| RQT_C_HHI_4                     | OK                   |
| RQT_D_HHI_4                     | OK                   |
| RQT_E_HHI_4                     | OK                   |
| RQT_F_HHI_4                     | OK                   |
| RQT_G_HHI_4                     | OK                   |
| SAO_A_MediaTek_4                | OK                   |
| SAO_B_MediaTek_5                | OK                   |
| SAO_C_Samsung_5                 | OK                   |
| SAO_D_Samsung_5                 | OK                   |
| SAO_E_Canon_4                   | OK                   |
| SAO_F_Canon_3                   | OK                   |
| SAO_G_Canon_3                   | OK                   |
| SAO_H_Parabola_1                | OK                   |
| SAODBLK_A_MainConcept_4         | OK                   |
| SAODBLK_B_MainConcept_4         | OK                   |
| SDH_A_Orange_4                  | OK                   |
| SLICES_A_Rovi_3                 | OK                   |
| SLIST_A_Sony_5                  | OK                   |
| SLIST_B_Sony_9                  | OK                   |
| SLIST_C_Sony_4                  | OK                   |
| SLIST_D_Sony_9                  | OK                   |
| SLPPLP_A_VIDYO_2                | ER                   |
| STRUCT_A_Samsung_7              | ER                   |
| STRUCT_B_Samsung_7              | ER                   |
| TILES_A_Cisco_2                 | ER                   |
| TILES_B_Cisco_1                 | ER                   |
| TMVP_A_MS_3                     | OK                   |
| TSCL_A_VIDYO_5                  | OK                   |
| TSCL_B_VIDYO_4                  | ER                   |
| TSKIP_A_MS_3                    | OK                   |
| TSUNEQBD_A_MAIN10_Technicolor_2 | ER                   |
| TUSIZE_A_Samsung_1              | OK                   |
| VPSID_A_VIDYO_2                 | ER                   |
| VPSSPSPPS_A_MainConcept_1       | KO                   |
| WP_A_MAIN10_Toshiba_3           | ER                   |
| WP_A_Toshiba_3                  | ER                   |
| WP_B_Toshiba_3                  | OK                   |
| WP_MAIN10_B_Toshiba_3           | ER                   |
| WPP_A_ericsson_MAIN10_2         | ER                   |
| WPP_A_ericsson_MAIN_2           | OK                   |
| WPP_B_ericsson_MAIN10_2         | ER                   |
| WPP_B_ericsson_MAIN_2           | OK                   |
| WPP_C_ericsson_MAIN10_2         | ER                   |
| WPP_C_ericsson_MAIN_2           | OK                   |
| WPP_D_ericsson_MAIN10_2         | ER                   |
| WPP_D_ericsson_MAIN_2           | OK                   |
| WPP_E_ericsson_MAIN10_2         | ER                   |
| WPP_E_ericsson_MAIN_2           | OK                   |
| WPP_F_ericsson_MAIN10_2         | ER                   |
| WPP_F_ericsson_MAIN_2           | OK                   |
| -                               | -                    |
| Test                            | FFmpeg-H.265-v4l2m2m |
| TOTAL                           | 120/147              |
| TOTAL TIME                      | 12669.641s           |

Failed streams :
 - VPSSPSPPS_A_MainConcept_1 : Failed due to evolutive dynamic resolution increases. The decoder cannot properly handle upward resolution changes within the same stream.
 - LTRPSPS_A_Qualcomm_1

Yassine Ouaissa (5):
  media: allegro-dvt: Move the current driver to a subdirectory
  dt-bindings: media: allegro-dvt: add decoder dt-bindings for Gen3 IP
  MAINTAINERS: Add entry for allegrodvt Gen 3 drivers
  dt-bindings: vendor-prefixes: Update the description of allegro prefix
  media: allegro-dvt: Add Gen 3 IP stateful decoder driver

 .../bindings/media/allegro,al300-vdec.yaml    |   75 +
 .../devicetree/bindings/vendor-prefixes.yaml  |    2 +-
 MAINTAINERS                                   |    5 +-
 drivers/media/platform/allegro-dvt/Kconfig    |   17 +-
 drivers/media/platform/allegro-dvt/Makefile   |    6 +-
 .../media/platform/allegro-dvt/al300/Kconfig  |   23 +
 .../media/platform/allegro-dvt/al300/Makefile |    6 +
 .../allegro-dvt/al300/al_codec_common.c       |  754 ++++++++
 .../allegro-dvt/al300/al_codec_common.h       |  247 +++
 .../allegro-dvt/al300/al_codec_util.c         |  177 ++
 .../allegro-dvt/al300/al_codec_util.h         |  185 ++
 .../platform/allegro-dvt/al300/al_vdec_drv.c  | 1530 +++++++++++++++++
 .../platform/allegro-dvt/al300/al_vdec_drv.h  |   94 +
 .../media/platform/allegro-dvt/zynqmp/Kconfig |   17 +
 .../platform/allegro-dvt/zynqmp/Makefile      |    6 +
 .../allegro-dvt/{ => zynqmp}/allegro-core.c   |    0
 .../allegro-dvt/{ => zynqmp}/allegro-mail.c   |    0
 .../allegro-dvt/{ => zynqmp}/allegro-mail.h   |    0
 .../allegro-dvt/{ => zynqmp}/nal-h264.c       |    0
 .../allegro-dvt/{ => zynqmp}/nal-h264.h       |    0
 .../allegro-dvt/{ => zynqmp}/nal-hevc.c       |    0
 .../allegro-dvt/{ => zynqmp}/nal-hevc.h       |    0
 .../allegro-dvt/{ => zynqmp}/nal-rbsp.c       |    0
 .../allegro-dvt/{ => zynqmp}/nal-rbsp.h       |    0
 24 files changed, 3123 insertions(+), 21 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/media/allegro,al300-vdec.yaml
 create mode 100644 drivers/media/platform/allegro-dvt/al300/Kconfig
 create mode 100644 drivers/media/platform/allegro-dvt/al300/Makefile
 create mode 100644 drivers/media/platform/allegro-dvt/al300/al_codec_common.c
 create mode 100644 drivers/media/platform/allegro-dvt/al300/al_codec_common.h
 create mode 100644 drivers/media/platform/allegro-dvt/al300/al_codec_util.c
 create mode 100644 drivers/media/platform/allegro-dvt/al300/al_codec_util.h
 create mode 100644 drivers/media/platform/allegro-dvt/al300/al_vdec_drv.c
 create mode 100644 drivers/media/platform/allegro-dvt/al300/al_vdec_drv.h
 create mode 100644 drivers/media/platform/allegro-dvt/zynqmp/Kconfig
 create mode 100644 drivers/media/platform/allegro-dvt/zynqmp/Makefile
 rename drivers/media/platform/allegro-dvt/{ => zynqmp}/allegro-core.c (100%)
 rename drivers/media/platform/allegro-dvt/{ => zynqmp}/allegro-mail.c (100%)
 rename drivers/media/platform/allegro-dvt/{ => zynqmp}/allegro-mail.h (100%)
 rename drivers/media/platform/allegro-dvt/{ => zynqmp}/nal-h264.c (100%)
 rename drivers/media/platform/allegro-dvt/{ => zynqmp}/nal-h264.h (100%)
 rename drivers/media/platform/allegro-dvt/{ => zynqmp}/nal-hevc.c (100%)
 rename drivers/media/platform/allegro-dvt/{ => zynqmp}/nal-hevc.h (100%)
 rename drivers/media/platform/allegro-dvt/{ => zynqmp}/nal-rbsp.c (100%)
 rename drivers/media/platform/allegro-dvt/{ => zynqmp}/nal-rbsp.h (100%)

--
2.30.2

---
Yassine Ouaissa (4):
      media: allegro-dvt: Move the current driver to a subdirectory
      dt-bindings: media: allegro: Add al300 decoder IPs
      dt-bindings: vendor-prefixes: Update the description of allegro prefix
      media: allegro-dvt: Add Gen 3 IP stateful decoder driver

 .../bindings/media/allegro,al300-vdec.yaml         |   76 +
 .../devicetree/bindings/vendor-prefixes.yaml       |    2 +-
 MAINTAINERS                                        |    4 +-
 drivers/media/platform/allegro-dvt/Kconfig         |   17 +-
 drivers/media/platform/allegro-dvt/Makefile        |    6 +-
 drivers/media/platform/allegro-dvt/al300/Kconfig   |   23 +
 drivers/media/platform/allegro-dvt/al300/Makefile  |    9 +
 .../platform/allegro-dvt/al300/al_codec_common.c   |  764 ++++++++++
 .../platform/allegro-dvt/al300/al_codec_common.h   |  252 ++++
 .../platform/allegro-dvt/al300/al_codec_dbgfs.c    |  229 +++
 .../platform/allegro-dvt/al300/al_codec_dbgfs.h    |   71 +
 .../platform/allegro-dvt/al300/al_codec_util.c     |  180 +++
 .../platform/allegro-dvt/al300/al_codec_util.h     |  196 +++
 .../media/platform/allegro-dvt/al300/al_vdec_drv.c | 1514 ++++++++++++++++++++
 .../media/platform/allegro-dvt/al300/al_vdec_drv.h |   98 ++
 drivers/media/platform/allegro-dvt/zynqmp/Kconfig  |   17 +
 drivers/media/platform/allegro-dvt/zynqmp/Makefile |    6 +
 .../allegro-dvt/{ => zynqmp}/allegro-core.c        |    0
 .../allegro-dvt/{ => zynqmp}/allegro-mail.c        |    0
 .../allegro-dvt/{ => zynqmp}/allegro-mail.h        |    0
 .../platform/allegro-dvt/{ => zynqmp}/nal-h264.c   |    0
 .../platform/allegro-dvt/{ => zynqmp}/nal-h264.h   |    0
 .../platform/allegro-dvt/{ => zynqmp}/nal-hevc.c   |    0
 .../platform/allegro-dvt/{ => zynqmp}/nal-hevc.h   |    0
 .../platform/allegro-dvt/{ => zynqmp}/nal-rbsp.c   |    0
 .../platform/allegro-dvt/{ => zynqmp}/nal-rbsp.h   |    0
 26 files changed, 3443 insertions(+), 21 deletions(-)
---
base-commit: c2f2b01b74be8b40a2173372bcd770723f87e7b2
change-id: 20250527-allegro_dvt_al300_dec_driver-4e75a94af6dc

Best regards,
-- 
Yassine Ouaissa <yassine.ouaissa at allegrodvt.com>




From andrew at lunn.ch  Mon Dec  8 05:46:47 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Mon, 8 Dec 2025 14:46:47 +0100
Subject: [PATCH net] net: mdio: aspeed: add dummy read to avoid
 read-after-write issue
In-Reply-To: <20251208-aspeed_mdio_add_dummy_read-v1-1-0a1861ad2161@aspeedtech.com>
References: <20251208-aspeed_mdio_add_dummy_read-v1-1-0a1861ad2161@aspeedtech.com>
Message-ID: <57860c7c-2294-4ea6-a998-8bc92dda2ed2@lunn.ch>

On Mon, Dec 08, 2025 at 02:49:56PM +0800, Jacky Chou wrote:
> The Aspeed MDIO controller may return incorrect data when a read operation
> follows immediately after a write. Due to a controller bug, the subsequent
> read can latch stale data, causing the polling logic to terminate earlier
> than expected.
> 
> To work around this hardware issue, insert a dummy read after each write
> operation. This ensures that the next actual read returns the correct
> data and prevents premature polling exit.
> 
> This workaround has been verified to stabilize MDIO transactions on
> affected Aspeed platforms.
> 
> Fixes: 737ca352569e ("net: mdio: aspeed: move reg accessing part into separate functions")

That seems like an odd Fixes: tag. That is just moving code around,
but the write followed by a read existed before that. Why not:

commit f160e99462c68ab5b9e2b9097a4867459730b49a
Author: Andrew Jeffery <andrew at aj.id.au>
Date:   Wed Jul 31 15:09:57 2019 +0930

    net: phy: Add mdio-aspeed
    
    The AST2600 design separates the MDIO controllers from the MAC, which is
    where they were placed in the AST2400 and AST2500. Further, the register
    interface is reworked again, so now we have three possible different
    interface implementations, however this driver only supports the
    interface provided by the AST2600. The AST2400 and AST2500 will continue
    to be supported by the MDIO support embedded in the FTGMAC100 driver.
    
    The hardware supports both C22 and C45 mode, but for the moment only C22
    support is implemented.
    
    Signed-off-by: Andrew Jeffery <andrew at aj.id.au>
    Reviewed-by: Andrew Lunn <andrew at lunn.ch>
    Signed-off-by: David S. Miller <davem at davemloft.net>


    Andrew

---
pw-bot: cr


From robh at kernel.org  Mon Dec  8 05:56:22 2025
From: robh at kernel.org (Rob Herring)
Date: Mon, 08 Dec 2025 07:56:22 -0600
Subject: [PATCH v5 0/2] ARM: add support for pcb8385
In-Reply-To: <20251208083545.3642168-1-horatiu.vultur@microchip.com>
References: <20251208083545.3642168-1-horatiu.vultur@microchip.com>
Message-ID: <176520193900.1461308.2377381391783792991.robh@kernel.org>


On Mon, 08 Dec 2025 09:35:43 +0100, Horatiu Vultur wrote:
> Add pcb8385 and the documentation for it.
> This is a moduler board on which it can add different daughter cards.
> 
> v4->v5:
> - change the status for aes node to be "reserved"
> 
> v3->v4:
> - override i2c0 using labels instead of having it under flx0
> - override usart3 using labels instead of having it under flx3
> 
> v2->v3:
> - remove the linux,default-trigger properties
> 
> v1->v2:
> - sort nodes in alphanumerical order
> - move the eeprom nodes under i2c0
> 
> Horatiu Vultur (2):
>   dt-bindings: arm: at91: add lan966 pcb8385 board
>   ARM: dts: Add support for pcb8385
> 
>  .../devicetree/bindings/arm/atmel-at91.yaml   |   6 +-
>  arch/arm/boot/dts/microchip/Makefile          |   3 +-
>  .../boot/dts/microchip/lan966x-pcb8385.dts    | 131 ++++++++++++++++++
>  3 files changed, 137 insertions(+), 3 deletions(-)
>  create mode 100644 arch/arm/boot/dts/microchip/lan966x-pcb8385.dts
> 
> --
> 2.34.1
> 
> 
> 


My bot found new DTB warnings on the .dts files added or changed in this
series.

Some warnings may be from an existing SoC .dtsi. Or perhaps the warnings
are fixed by another series. Ultimately, it is up to the platform
maintainer whether these warnings are acceptable or not. No need to reply
unless the platform maintainer has comments.

If you already ran DT checks and didn't see these error(s), then
make sure dt-schema is up to date:

  pip3 install dtschema --upgrade


This patch series was applied (using b4) to base:
 Base: attempting to guess base-commit...
 Base: tags/next-20251208 (exact match)
 Base: tags/next-20251208 (use --merge-base to override)

If this is not the correct base, please add 'base-commit' tag
(or use b4 which does this automatically)

New warnings running 'make CHECK_DTBS=y for arch/arm/boot/dts/microchip/' for 20251208083545.3642168-1-horatiu.vultur at microchip.com:

arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: /soc/usb at 200000: failed to match any schema with compatible: ['microchip,lan9662-udc', 'atmel,sama5d3-udc']
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: /soc/usb at 200000: failed to match any schema with compatible: ['microchip,lan9662-udc', 'atmel,sama5d3-udc']
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: serial at 200 (atmel,at91sam9260-usart): $nodename:0: 'serial at 200' does not match '^spi(@.*|-([0-9]|[1-9][0-9]+))?$'
	from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: serial at 200 (atmel,at91sam9260-usart): False schema does not allow 32
	from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: serial at 200 (atmel,at91sam9260-usart): $nodename:0: 'serial at 200' does not match '^spi(@.*|-([0-9]|[1-9][0-9]+))?$'
	from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: serial at 200 (atmel,at91sam9260-usart): False schema does not allow 32
	from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: rng at e0048000 (atmel,at91sam9g45-trng): 'oneOf' conditional failed, one must be fixed:
	'interrupts' is a required property
	'interrupts-extended' is a required property
	from schema $id: http://devicetree.org/schemas/rng/atmel,at91-trng.yaml
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: serial at 200 (atmel,at91sam9260-usart): $nodename:0: 'serial at 200' does not match '^spi(@.*|-([0-9]|[1-9][0-9]+))?$'
	from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: serial at 200 (atmel,at91sam9260-usart): False schema does not allow 32
	from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: serial at 200 (atmel,at91sam9260-usart): $nodename:0: 'serial at 200' does not match '^spi(@.*|-([0-9]|[1-9][0-9]+))?$'
	from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: serial at 200 (atmel,at91sam9260-usart): False schema does not allow 32
	from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: serial at 200 (atmel,at91sam9260-usart): '#size-cells' is a required property
	from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: serial at 200 (atmel,at91sam9260-usart): '#address-cells' is a required property
	from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: serial at 200 (atmel,at91sam9260-usart): 'atmel,usart-mode' is a required property
	from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: serial at 200 (atmel,at91sam9260-usart): $nodename:0: 'serial at 200' does not match '^spi(@.*|-([0-9]|[1-9][0-9]+))?$'
	from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml
arch/arm/boot/dts/microchip/lan966x-pcb8385.dtb: serial at 200 (atmel,at91sam9260-usart): False schema does not allow 32
	from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml







From maudspierings at gocontroll.com  Mon Dec  8 05:56:50 2025
From: maudspierings at gocontroll.com (Maud Spierings)
Date: Mon, 8 Dec 2025 14:56:50 +0100
Subject: [PATCH v6 1/4] dt-bindings: backlight: Add max25014 support
In-Reply-To: <aS79eKc9Ac4np6Nf@lizhi-Precision-Tower-5810>
References: <20251201-max25014-v6-0-88e3ac8112ff@gocontroll.com>
 <20251201-max25014-v6-1-88e3ac8112ff@gocontroll.com>
 <aS3H1qzSMKHamqpP@lizhi-Precision-Tower-5810>
 <b9fe6df7-fdc6-4a32-919b-8f3b44eace7d@gocontroll.com>
 <aS79eKc9Ac4np6Nf@lizhi-Precision-Tower-5810>
Message-ID: <e428c3a9-49e2-4af5-b597-2cdfef7028f5@gocontroll.com>

On 12/2/25 15:53, Frank Li wrote:
> On Tue, Dec 02, 2025 at 08:46:21AM +0100, Maud Spierings wrote:
>> On 12/1/25 17:52, Frank Li wrote:
>>> On Mon, Dec 01, 2025 at 12:53:20PM +0100, Maud Spierings via B4 Relay wrote:
>>>> From: Maud Spierings <maudspierings at gocontroll.com>
>>>>
>>>> The Maxim MAX25014 is a 4-channel automotive grade backlight driver IC
>>>> with integrated boost controller.
>>>>
>>>> Signed-off-by: Maud Spierings <maudspierings at gocontroll.com>
>>>>
>>>> ---
>>>>
>>>> In the current implementation the control registers for channel 1,
>>>> control all channels. So only one led subnode with led-sources is
>>>> supported right now. If at some point the driver functionality is
>>>> expanded the bindings can be easily extended with it.
>>>> ---
>>>>    .../bindings/leds/backlight/maxim,max25014.yaml    | 107 +++++++++++++++++++++
>>>>    MAINTAINERS                                        |   5 +
>>>>    2 files changed, 112 insertions(+)
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml b/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
>>>> new file mode 100644
>>>> index 000000000000..e83723224b07
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
>>>> @@ -0,0 +1,107 @@
>>>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>>>> +%YAML 1.2
>>>> +---
>>>> +$id: http://devicetree.org/schemas/leds/backlight/maxim,max25014.yaml#
>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>>> +
>>>> +title: Maxim max25014 backlight controller
>>>> +
>>>> +maintainers:
>>>> +  - Maud Spierings <maudspierings at gocontroll.com>
>>>> +
>>>> +properties:
>>>> +  compatible:
>>>> +    enum:
>>>> +      - maxim,max25014
>>>> +
>>>> +  reg:
>>>> +    maxItems: 1
>>>> +
>>>> +  "#address-cells":
>>>> +    const: 1
>>>> +
>>>> +  "#size-cells":
>>>> +    const: 0
>>>> +
>>>> +  enable-gpios:
>>>> +    maxItems: 1
>>>> +
>>>> +  interrupts:
>>>> +    maxItems: 1
>>>> +
>>>> +  power-supply:
>>>> +    description: Regulator which controls the boost converter input rail.
>>>> +
>>>> +  pwms:
>>>> +    maxItems: 1
>>>> +
>>>> +  maxim,iset:
>>>> +    $ref: /schemas/types.yaml#/definitions/uint32
>>>> +    maximum: 15
>>>> +    default: 11
>>>> +    description:
>>>> +      Value of the ISET field in the ISET register. This controls the current
>>>> +      scale of the outputs, a higher number means more current.
>>>> +
>>>> +  led at 0:
>>>
>>> define whole binding, allow 0-3. binding is not related with driver's
>>> implement.
>>>
>>> it'd better put unders leds.
>>>
>>
>> so like:
>>
>> backlight: backlight at 6f {
>> 	compatible = "maxim,max25014";
>> 	reg = <0x6f>;
>> 	enable-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
>> 	pinctrl-names = "default";
>> 	pinctrl-0 = <&pinctrl_backlight>;
>> 	maxim,iset = <7>;
>>
>> 	leds {
>> 		#address-cells = <1>;
>> 		#size-cells = <0>;
>>
>> 		led at 0 {
>> 			reg = <0>;
>> 			led-sources = <0 1 2>;
>> 			default-brightness = <50>;
>> 		};
>>
>> 		optional led@#....
>> 	};
>> };
>>
>> right?
> 
> yes.
> 

I am feeling a bit weird about these led sub nodes, because it is not 
programmed as a led driver, it is programmed as a backlight. I am trying 
to figure out how this would be used later when the led strings are 
individually controllable.

it isn't possible to link the seperate strings to different displays 
because it is only one backlight device, so I don't seen any reason why 
it would ever be used in another way than what it is now, were all 
strings are programmed by one register.

The only way I can make sense of it is if instead I program this device 
as a led driver and then use the led_bl driver as the actual backlight.

Thats a pretty big step in a different direction, but then the led 
subnodes at least can be properly used I feel.

Kind regards,
Maud



From james.clark at linaro.org  Mon Dec  8 06:22:04 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 08 Dec 2025 14:22:04 +0000
Subject: [PATCH v2 01/12] perf parse-events: Refactor get_config_terms() to
 remove macros
In-Reply-To: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
References: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
Message-ID: <20251208-james-perf-config-bits-v2-1-4ac0281993b0@linaro.org>

The ADD_CONFIG_TERM() macros build the __type argument out of a partial
EVSEL__CONFIG_TERM_x enum name. This means that they can't be called
from a function where __type is a variable and it's also impossible to
grep the codebase to find usages of these enums as they're never typed
in full.

Fix this by removing the macros and replacing them with an
add_config_term() function. It seems the main reason these existed in
the first place was to avoid type punning and to write to a specific
field in the union, but the same thing can be achieved with a single
write to a u64 'val' field.

Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/util/evsel_config.h |   1 +
 tools/perf/util/parse-events.c | 146 ++++++++++++++++++++++++-----------------
 2 files changed, 86 insertions(+), 61 deletions(-)

diff --git a/tools/perf/util/evsel_config.h b/tools/perf/util/evsel_config.h
index bcd3a978f0c4..685fd8d5c4a8 100644
--- a/tools/perf/util/evsel_config.h
+++ b/tools/perf/util/evsel_config.h
@@ -50,6 +50,7 @@ struct evsel_config_term {
 		u64	      cfg_chg;
 		char	      *str;
 		int	      cpu;
+		u64	      val;
 	} val;
 	bool weak;
 };
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 17c1c36a7bf9..d5b009b4ebab 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1116,105 +1116,107 @@ static int config_attr(struct perf_event_attr *attr,
 	return 0;
 }
 
-static int get_config_terms(const struct parse_events_terms *head_config,
-			    struct list_head *head_terms)
+static struct evsel_config_term *add_config_term(enum evsel_term_type type,
+						 struct list_head *head_terms,
+						 bool weak)
 {
-#define ADD_CONFIG_TERM(__type, __weak)				\
-	struct evsel_config_term *__t;			\
-								\
-	__t = zalloc(sizeof(*__t));				\
-	if (!__t)						\
-		return -ENOMEM;					\
-								\
-	INIT_LIST_HEAD(&__t->list);				\
-	__t->type       = EVSEL__CONFIG_TERM_ ## __type;	\
-	__t->weak	= __weak;				\
-	list_add_tail(&__t->list, head_terms)
-
-#define ADD_CONFIG_TERM_VAL(__type, __name, __val, __weak)	\
-do {								\
-	ADD_CONFIG_TERM(__type, __weak);			\
-	__t->val.__name = __val;				\
-} while (0)
+	struct evsel_config_term *t;
 
-#define ADD_CONFIG_TERM_STR(__type, __val, __weak)		\
-do {								\
-	ADD_CONFIG_TERM(__type, __weak);			\
-	__t->val.str = strdup(__val);				\
-	if (!__t->val.str) {					\
-		zfree(&__t);					\
-		return -ENOMEM;					\
-	}							\
-	__t->free_str = true;					\
-} while (0)
+	t = zalloc(sizeof(*t));
+	if (!t)
+		return NULL;
+
+	INIT_LIST_HEAD(&t->list);
+	t->type = type;
+	t->weak	= weak;
+	list_add_tail(&t->list, head_terms);
 
+	return t;
+}
+
+static int get_config_terms(const struct parse_events_terms *head_config,
+			    struct list_head *head_terms)
+{
 	struct parse_events_term *term;
 
 	list_for_each_entry(term, &head_config->terms, list) {
+		struct evsel_config_term *new_term;
+		enum evsel_term_type new_type;
+		char *str = NULL;
+		u64 val;
+
 		switch (term->type_term) {
 		case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
-			ADD_CONFIG_TERM_VAL(PERIOD, period, term->val.num, term->weak);
+			new_type = EVSEL__CONFIG_TERM_PERIOD;
+			val = term->val.num;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ:
-			ADD_CONFIG_TERM_VAL(FREQ, freq, term->val.num, term->weak);
+			new_type = EVSEL__CONFIG_TERM_FREQ;
+			val = term->val.num;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_TIME:
-			ADD_CONFIG_TERM_VAL(TIME, time, term->val.num, term->weak);
+			new_type = EVSEL__CONFIG_TERM_TIME;
+			val = term->val.num;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_CALLGRAPH:
-			ADD_CONFIG_TERM_STR(CALLGRAPH, term->val.str, term->weak);
+			new_type = EVSEL__CONFIG_TERM_CALLGRAPH;
+			str = term->val.str;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
-			ADD_CONFIG_TERM_STR(BRANCH, term->val.str, term->weak);
+			new_type = EVSEL__CONFIG_TERM_BRANCH;
+			str = term->val.str;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
-			ADD_CONFIG_TERM_VAL(STACK_USER, stack_user,
-					    term->val.num, term->weak);
+			new_type = EVSEL__CONFIG_TERM_STACK_USER;
+			val = term->val.num;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_INHERIT:
-			ADD_CONFIG_TERM_VAL(INHERIT, inherit,
-					    term->val.num ? 1 : 0, term->weak);
+			new_type = EVSEL__CONFIG_TERM_INHERIT;
+			val = term->val.num ? 1 : 0;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_NOINHERIT:
-			ADD_CONFIG_TERM_VAL(INHERIT, inherit,
-					    term->val.num ? 0 : 1, term->weak);
+			new_type = EVSEL__CONFIG_TERM_INHERIT;
+			val = term->val.num ? 0 : 1;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_MAX_STACK:
-			ADD_CONFIG_TERM_VAL(MAX_STACK, max_stack,
-					    term->val.num, term->weak);
+			new_type = EVSEL__CONFIG_TERM_MAX_STACK;
+			val = term->val.num;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS:
-			ADD_CONFIG_TERM_VAL(MAX_EVENTS, max_events,
-					    term->val.num, term->weak);
+			new_type = EVSEL__CONFIG_TERM_MAX_EVENTS;
+			val = term->val.num;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_OVERWRITE:
-			ADD_CONFIG_TERM_VAL(OVERWRITE, overwrite,
-					    term->val.num ? 1 : 0, term->weak);
+			new_type = EVSEL__CONFIG_TERM_OVERWRITE;
+			val = term->val.num ? 1 : 0;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE:
-			ADD_CONFIG_TERM_VAL(OVERWRITE, overwrite,
-					    term->val.num ? 0 : 1, term->weak);
+			new_type = EVSEL__CONFIG_TERM_OVERWRITE;
+			val = term->val.num ? 0 : 1;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_DRV_CFG:
-			ADD_CONFIG_TERM_STR(DRV_CFG, term->val.str, term->weak);
+			new_type = EVSEL__CONFIG_TERM_DRV_CFG;
+			str = term->val.str;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_PERCORE:
-			ADD_CONFIG_TERM_VAL(PERCORE, percore,
-					    term->val.num ? true : false, term->weak);
+			new_type = EVSEL__CONFIG_TERM_PERCORE;
+			val = term->val.num ? true : false;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT:
-			ADD_CONFIG_TERM_VAL(AUX_OUTPUT, aux_output,
-					    term->val.num ? 1 : 0, term->weak);
+			new_type = EVSEL__CONFIG_TERM_AUX_OUTPUT;
+			val = term->val.num ? 1 : 0;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_AUX_ACTION:
-			ADD_CONFIG_TERM_STR(AUX_ACTION, term->val.str, term->weak);
+			new_type = EVSEL__CONFIG_TERM_AUX_ACTION;
+			str = term->val.str;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE:
-			ADD_CONFIG_TERM_VAL(AUX_SAMPLE_SIZE, aux_sample_size,
-					    term->val.num, term->weak);
+			new_type = EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE;
+			val = term->val.num;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV:
-			ADD_CONFIG_TERM_STR(RATIO_TO_PREV, term->val.str, term->weak);
+			new_type = EVSEL__CONFIG_TERM_RATIO_TO_PREV;
+			str = term->val.str;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_USER:
 		case PARSE_EVENTS__TERM_TYPE_CONFIG:
@@ -1229,7 +1231,23 @@ do {								\
 		case PARSE_EVENTS__TERM_TYPE_RAW:
 		case PARSE_EVENTS__TERM_TYPE_CPU:
 		default:
-			break;
+			/* Don't add a new term for these ones */
+			continue;
+		}
+
+		new_term = add_config_term(new_type, head_terms, term->weak);
+		if (!new_term)
+			return -ENOMEM;
+
+		if (str) {
+			new_term->val.str = strdup(str);
+			if (!new_term->val.str) {
+				zfree(&new_term);
+				return -ENOMEM;
+			}
+			new_term->free_str = true;
+		} else {
+			new_term->val.val = val;
 		}
 	}
 	return 0;
@@ -1290,10 +1308,16 @@ static int get_config_chgs(struct perf_pmu *pmu, struct parse_events_terms *head
 		}
 	}
 
-	if (bits)
-		ADD_CONFIG_TERM_VAL(CFG_CHG, cfg_chg, bits, false);
+	if (bits) {
+		struct evsel_config_term *new_term;
+
+		new_term = add_config_term(EVSEL__CONFIG_TERM_CFG_CHG,
+					   head_terms, false);
+		if (!new_term)
+			return -ENOMEM;
+		new_term->val.cfg_chg = bits;
+	}
 
-#undef ADD_CONFIG_TERM
 	return 0;
 }
 

-- 
2.34.1



From james.clark at linaro.org  Mon Dec  8 06:22:03 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 08 Dec 2025 14:22:03 +0000
Subject: [PATCH v2 00/12] perf cs-etm/arm-spe: Remove hard coded config
 fields
Message-ID: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>

The specific config field that an event format attribute is in is
consistently hard coded, even though the API is supposed to be that the
driver publishes the config field name. To stop this pattern from being
copy pasted and causing problems in the future, replace them all with
calls to a new helper that returns the value that a user set.

This reveals some issues in evsel__set_config_if_unset(). It doesn't
work with sparse bitfields, which are an unused but documented feature.
And it also only writes to the attr.config field. To fix it we need to
start tracking user changes for all config fields and then use existing
helper functions that support sparse bitfields. Some other refactoring
was also required and a test was added.

Signed-off-by: James Clark <james.clark at linaro.org>
---
Changes in v2:
- Remove macros in get_config_chgs() and some other refactoring.
- Support sparse bitfields in evsel__set_config_if_unset().
- Always track user changes instead of only when
  'pmu->perf_event_attr_init_default' is set.
- Add a test.
- Don't bail out in cs-etm.c if any format fields are missing (Leo).
- Rename 'guess' to 'synth' (Mike).
- Link to v1: https://lore.kernel.org/r/20251201-james-perf-config-bits-v1-0-22ecbbf8007c at linaro.org

---
James Clark (12):
      perf parse-events: Refactor get_config_terms() to remove macros
      perf evsel: Support sparse fields in evsel__set_config_if_unset()
      perf parse-events: Track all user changed config bits
      perf evsel: apply evsel__set_config_if_unset() to all config fields
      perf evsel: Add a helper to get the value of a config field
      perf parse-events: Always track user config changes
      perf tests: Test evsel__set_config_if_unset() and config change tracking
      perf cs-etm: Make a helper to find the Coresight evsel
      perf cs-etm: Don't use hard coded config bits when setting up ETMCR
      perf cs-etm: Don't use hard coded config bits when setting up TRCCONFIGR
      perf cs-etm: Don't hard code config attribute when configuring the event
      perf arm-spe: Don't hard code config attribute

 tools/perf/arch/arm/util/cs-etm.c    | 193 +++++++++++++++------------
 tools/perf/arch/arm64/util/arm-spe.c |  15 ++-
 tools/perf/tests/pmu.c               |  90 +++++++++++++
 tools/perf/util/evsel.c              |   6 +-
 tools/perf/util/evsel.h              |   2 +
 tools/perf/util/evsel_config.h       |   7 +-
 tools/perf/util/parse-events.c       | 248 ++++++++++++++++++++---------------
 tools/perf/util/pmu.c                | 112 ++++++++++++++--
 8 files changed, 459 insertions(+), 214 deletions(-)
---
base-commit: 2eeb09fe1c5173b659929f92fee4461796ca8c14
change-id: 20251112-james-perf-config-bits-bee7106f0f00

Best regards,
-- 
James Clark <james.clark at linaro.org>



From james.clark at linaro.org  Mon Dec  8 06:22:05 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 08 Dec 2025 14:22:05 +0000
Subject: [PATCH v2 02/12] perf evsel: Support sparse fields in
 evsel__set_config_if_unset()
In-Reply-To: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
References: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
Message-ID: <20251208-james-perf-config-bits-v2-2-4ac0281993b0@linaro.org>

Sparse config fields are technically supported although currently
unused. field_prep() only works for contiguous bitfields so replace it
with pmu_format_value().

Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/util/pmu.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 956ea273c2c7..2c26c8d76bed 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -144,6 +144,8 @@ struct perf_pmu_format {
 };
 
 static int pmu_aliases_parse(struct perf_pmu *pmu);
+static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
+			     bool zero);
 
 static struct perf_pmu_format *perf_pmu__new_format(struct list_head *list, char *name)
 {
@@ -1381,7 +1383,6 @@ bool evsel__is_aux_event(const struct evsel *evsel)
  * the bit pattern. It is shifted into position by this function, so to set
  * something to true, pass 1 for val rather than a pre shifted value.
  */
-#define field_prep(_mask, _val) (((_val) << (ffsll(_mask) - 1)) & (_mask))
 void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
 				const char *config_name, u64 val)
 {
@@ -1398,8 +1399,7 @@ void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
 		return;
 
 	/* Otherwise replace it */
-	evsel->core.attr.config &= ~bits;
-	evsel->core.attr.config |= field_prep(bits, val);
+	pmu_format_value(&bits, val, &evsel->core.attr.config, /*zero=*/true);
 }
 
 static struct perf_pmu_format *

-- 
2.34.1



From james.clark at linaro.org  Mon Dec  8 06:22:06 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 08 Dec 2025 14:22:06 +0000
Subject: [PATCH v2 03/12] perf parse-events: Track all user changed config
 bits
In-Reply-To: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
References: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
Message-ID: <20251208-james-perf-config-bits-v2-3-4ac0281993b0@linaro.org>

Currently we only track which bits were set by the user in attr->config.
But all configN fields should be treated equally as they can all have
default and user overridden values.

Track them all by making get_config_chgs() generic and calling it once
for each config value.

Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/util/evsel.c        |  6 ++-
 tools/perf/util/evsel_config.h |  6 ++-
 tools/perf/util/parse-events.c | 98 +++++++++++++++++++++++-------------------
 tools/perf/util/pmu.c          |  2 +-
 4 files changed, 65 insertions(+), 47 deletions(-)

diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 9cd706f62793..dcadf022405d 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1242,7 +1242,11 @@ static void evsel__apply_config_terms(struct evsel *evsel,
 		case EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE:
 			/* Already applied by auxtrace */
 			break;
-		case EVSEL__CONFIG_TERM_CFG_CHG:
+		case EVSEL__CONFIG_TERM_USR_CHG_CONFIG:
+		case EVSEL__CONFIG_TERM_USR_CHG_CONFIG1:
+		case EVSEL__CONFIG_TERM_USR_CHG_CONFIG2:
+		case EVSEL__CONFIG_TERM_USR_CHG_CONFIG3:
+		case EVSEL__CONFIG_TERM_USR_CHG_CONFIG4:
 			break;
 		case EVSEL__CONFIG_TERM_RATIO_TO_PREV:
 			rtp_buf = term->val.str;
diff --git a/tools/perf/util/evsel_config.h b/tools/perf/util/evsel_config.h
index 685fd8d5c4a8..7b565d76c0bc 100644
--- a/tools/perf/util/evsel_config.h
+++ b/tools/perf/util/evsel_config.h
@@ -27,7 +27,11 @@ enum evsel_term_type {
 	EVSEL__CONFIG_TERM_AUX_OUTPUT,
 	EVSEL__CONFIG_TERM_AUX_ACTION,
 	EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE,
-	EVSEL__CONFIG_TERM_CFG_CHG,
+	EVSEL__CONFIG_TERM_USR_CHG_CONFIG,
+	EVSEL__CONFIG_TERM_USR_CHG_CONFIG1,
+	EVSEL__CONFIG_TERM_USR_CHG_CONFIG2,
+	EVSEL__CONFIG_TERM_USR_CHG_CONFIG3,
+	EVSEL__CONFIG_TERM_USR_CHG_CONFIG4,
 	EVSEL__CONFIG_TERM_RATIO_TO_PREV,
 };
 
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index d5b009b4ebab..7a3a90377896 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1253,66 +1253,32 @@ static int get_config_terms(const struct parse_events_terms *head_config,
 	return 0;
 }
 
-/*
- * Add EVSEL__CONFIG_TERM_CFG_CHG where cfg_chg will have a bit set for
- * each bit of attr->config that the user has changed.
- */
-static int get_config_chgs(struct perf_pmu *pmu, struct parse_events_terms *head_config,
-			   struct list_head *head_terms)
+static int add_cfg_chg(struct perf_pmu *pmu,
+		       struct parse_events_terms *head_config,
+		       struct list_head *head_terms,
+		       int format_type,
+		       enum parse_events__term_type term_type,
+		       enum evsel_term_type new_term_type)
 {
 	struct parse_events_term *term;
 	u64 bits = 0;
 	int type;
 
 	list_for_each_entry(term, &head_config->terms, list) {
-		switch (term->type_term) {
-		case PARSE_EVENTS__TERM_TYPE_USER:
+		if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER) {
 			type = perf_pmu__format_type(pmu, term->config);
-			if (type != PERF_PMU_FORMAT_VALUE_CONFIG)
+			if (type != format_type)
 				continue;
 			bits |= perf_pmu__format_bits(pmu, term->config);
-			break;
-		case PARSE_EVENTS__TERM_TYPE_CONFIG:
+		} else if (term->type_term == term_type) {
 			bits = ~(u64)0;
-			break;
-		case PARSE_EVENTS__TERM_TYPE_CONFIG1:
-		case PARSE_EVENTS__TERM_TYPE_CONFIG2:
-		case PARSE_EVENTS__TERM_TYPE_CONFIG3:
-		case PARSE_EVENTS__TERM_TYPE_CONFIG4:
-		case PARSE_EVENTS__TERM_TYPE_LEGACY_HARDWARE_CONFIG:
-		case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE_CONFIG:
-		case PARSE_EVENTS__TERM_TYPE_NAME:
-		case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
-		case PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ:
-		case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
-		case PARSE_EVENTS__TERM_TYPE_TIME:
-		case PARSE_EVENTS__TERM_TYPE_CALLGRAPH:
-		case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
-		case PARSE_EVENTS__TERM_TYPE_NOINHERIT:
-		case PARSE_EVENTS__TERM_TYPE_INHERIT:
-		case PARSE_EVENTS__TERM_TYPE_MAX_STACK:
-		case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS:
-		case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE:
-		case PARSE_EVENTS__TERM_TYPE_OVERWRITE:
-		case PARSE_EVENTS__TERM_TYPE_DRV_CFG:
-		case PARSE_EVENTS__TERM_TYPE_PERCORE:
-		case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT:
-		case PARSE_EVENTS__TERM_TYPE_AUX_ACTION:
-		case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE:
-		case PARSE_EVENTS__TERM_TYPE_METRIC_ID:
-		case PARSE_EVENTS__TERM_TYPE_RAW:
-		case PARSE_EVENTS__TERM_TYPE_CPU:
-		case PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV:
-		default:
-			break;
 		}
 	}
 
 	if (bits) {
 		struct evsel_config_term *new_term;
 
-		new_term = add_config_term(EVSEL__CONFIG_TERM_CFG_CHG,
-					   head_terms, false);
+		new_term = add_config_term(new_term_type, head_terms, false);
 		if (!new_term)
 			return -ENOMEM;
 		new_term->val.cfg_chg = bits;
@@ -1321,6 +1287,50 @@ static int get_config_chgs(struct perf_pmu *pmu, struct parse_events_terms *head
 	return 0;
 }
 
+/*
+ * Add EVSEL__CONFIG_TERM_USR_CFG_CONFIGn where cfg_chg will have a bit set for
+ * each bit of attr->configN that the user has changed.
+ */
+static int get_config_chgs(struct perf_pmu *pmu,
+			   struct parse_events_terms *head_config,
+			   struct list_head *head_terms)
+{
+	int ret;
+
+	ret = add_cfg_chg(pmu, head_config, head_terms,
+			  PERF_PMU_FORMAT_VALUE_CONFIG,
+			  PARSE_EVENTS__TERM_TYPE_CONFIG,
+			  EVSEL__CONFIG_TERM_USR_CHG_CONFIG);
+	if (ret)
+		return ret;
+
+	ret = add_cfg_chg(pmu, head_config, head_terms,
+			  PERF_PMU_FORMAT_VALUE_CONFIG1,
+			  PARSE_EVENTS__TERM_TYPE_CONFIG1,
+			  EVSEL__CONFIG_TERM_USR_CHG_CONFIG1);
+	if (ret)
+		return ret;
+
+	ret = add_cfg_chg(pmu, head_config, head_terms,
+			  PERF_PMU_FORMAT_VALUE_CONFIG2,
+			  PARSE_EVENTS__TERM_TYPE_CONFIG2,
+			  EVSEL__CONFIG_TERM_USR_CHG_CONFIG2);
+	if (ret)
+		return ret;
+
+	ret = add_cfg_chg(pmu, head_config, head_terms,
+			  PERF_PMU_FORMAT_VALUE_CONFIG3,
+			  PARSE_EVENTS__TERM_TYPE_CONFIG3,
+			  EVSEL__CONFIG_TERM_USR_CHG_CONFIG3);
+	if (ret)
+		return ret;
+
+	return add_cfg_chg(pmu, head_config, head_terms,
+			   PERF_PMU_FORMAT_VALUE_CONFIG4,
+			   PARSE_EVENTS__TERM_TYPE_CONFIG4,
+			   EVSEL__CONFIG_TERM_USR_CHG_CONFIG4);
+}
+
 int parse_events_add_tracepoint(struct parse_events_state *parse_state,
 				struct list_head *list,
 				const char *sys, const char *event,
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 2c26c8d76bed..e02f74d4020c 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -1387,7 +1387,7 @@ void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
 				const char *config_name, u64 val)
 {
 	u64 user_bits = 0, bits;
-	struct evsel_config_term *term = evsel__get_config_term(evsel, CFG_CHG);
+	struct evsel_config_term *term = evsel__get_config_term(evsel, USR_CHG_CONFIG);
 
 	if (term)
 		user_bits = term->val.cfg_chg;

-- 
2.34.1



From james.clark at linaro.org  Mon Dec  8 06:22:07 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 08 Dec 2025 14:22:07 +0000
Subject: [PATCH v2 04/12] perf evsel: apply evsel__set_config_if_unset() to
 all config fields
In-Reply-To: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
References: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
Message-ID: <20251208-james-perf-config-bits-v2-4-4ac0281993b0@linaro.org>

Misleadingly, evsel__set_config_if_unset() only works with the config
field and not config1, config2, etc. This is fine at the moment because
all users of it happen to operate on bits that are in that config field.
Fix it before there are any new users of the function which operate on
bits in different config fields.

In theory it's also possible for a driver to move an existing bit to
another config field and this fixes that scenario too, although this
hasn't happened yet either.

Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/util/pmu.c | 37 +++++++++++++++++++++++++++++++++++--
 1 file changed, 35 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index e02f74d4020c..514cba91f5d9 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -146,6 +146,8 @@ struct perf_pmu_format {
 static int pmu_aliases_parse(struct perf_pmu *pmu);
 static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
 			     bool zero);
+static struct perf_pmu_format *pmu_find_format(const struct list_head *formats,
+					       const char *name);
 
 static struct perf_pmu_format *perf_pmu__new_format(struct list_head *list, char *name)
 {
@@ -1387,7 +1389,38 @@ void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
 				const char *config_name, u64 val)
 {
 	u64 user_bits = 0, bits;
-	struct evsel_config_term *term = evsel__get_config_term(evsel, USR_CHG_CONFIG);
+	struct evsel_config_term *term;
+	struct perf_pmu_format *format = pmu_find_format(&pmu->format, config_name);
+	__u64 *vp;
+
+	if (!format)
+		return;
+
+	switch (format->value) {
+	case PERF_PMU_FORMAT_VALUE_CONFIG:
+		term = evsel__get_config_term(evsel, USR_CHG_CONFIG);
+		vp = &evsel->core.attr.config;
+		break;
+	case PERF_PMU_FORMAT_VALUE_CONFIG1:
+		term = evsel__get_config_term(evsel, USR_CHG_CONFIG1);
+		vp = &evsel->core.attr.config1;
+		break;
+	case PERF_PMU_FORMAT_VALUE_CONFIG2:
+		term = evsel__get_config_term(evsel, USR_CHG_CONFIG2);
+		vp = &evsel->core.attr.config2;
+		break;
+	case PERF_PMU_FORMAT_VALUE_CONFIG3:
+		term = evsel__get_config_term(evsel, USR_CHG_CONFIG3);
+		vp = &evsel->core.attr.config3;
+		break;
+	case PERF_PMU_FORMAT_VALUE_CONFIG4:
+		term = evsel__get_config_term(evsel, USR_CHG_CONFIG4);
+		vp = &evsel->core.attr.config4;
+		break;
+	default:
+		pr_err("Unknown format value: %d\n", format->value);
+		return;
+	}
 
 	if (term)
 		user_bits = term->val.cfg_chg;
@@ -1399,7 +1432,7 @@ void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
 		return;
 
 	/* Otherwise replace it */
-	pmu_format_value(&bits, val, &evsel->core.attr.config, /*zero=*/true);
+	pmu_format_value(&bits, val, vp, /*zero=*/true);
 }
 
 static struct perf_pmu_format *

-- 
2.34.1



From james.clark at linaro.org  Mon Dec  8 06:22:08 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 08 Dec 2025 14:22:08 +0000
Subject: [PATCH v2 05/12] perf evsel: Add a helper to get the value of a
 config field
In-Reply-To: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
References: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
Message-ID: <20251208-james-perf-config-bits-v2-5-4ac0281993b0@linaro.org>

This will be used by aux PMUs to read an already written value for
configuring their events and for also testing.

Its helper pmu_format_unpack() does the opposite of the existing
pmu_format_value() so rename that one to pmu_format_pack() so it's clear
how they are related.

Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/util/evsel.h |  2 ++
 tools/perf/util/pmu.c   | 77 ++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 68 insertions(+), 11 deletions(-)

diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index a08130ff2e47..092904a61ec7 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -575,6 +575,8 @@ void evsel__uniquify_counter(struct evsel *counter);
 	((((src) >> (pos)) & ((1ull << (size)) - 1)) << (63 - ((pos) + (size) - 1)))
 
 u64 evsel__bitfield_swap_branch_flags(u64 value);
+int evsel__get_config_val(struct perf_pmu *pmu, struct evsel *evsel,
+			  const char *config_name, u64 *val);
 void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
 				const char *config_name, u64 val);
 
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 514cba91f5d9..ef7358ad1fb9 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -144,8 +144,8 @@ struct perf_pmu_format {
 };
 
 static int pmu_aliases_parse(struct perf_pmu *pmu);
-static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
-			     bool zero);
+static void pmu_format_pack(unsigned long *format, __u64 value, __u64 *v,
+			    bool zero);
 static struct perf_pmu_format *pmu_find_format(const struct list_head *formats,
 					       const char *name);
 
@@ -1377,6 +1377,61 @@ bool evsel__is_aux_event(const struct evsel *evsel)
 	return pmu && pmu->auxtrace;
 }
 
+/*
+ * Unpacks a raw config[n] value using the sparse bitfield that defines a
+ * format attr. For example "config1:1,6-7,44" defines a 4 bit value across non
+ * contiguous bits and this function returns those 4 bits as a value.
+ */
+static u64 pmu_format_unpack(u64 format, u64 config_val)
+{
+	int val_bit = 0;
+	u64 res = 0;
+	int fmt_bit;
+
+	for_each_set_bit(fmt_bit, &format, PERF_PMU_FORMAT_BITS) {
+		if (test_bit(fmt_bit, &config_val))
+			res |= BIT_ULL(val_bit);
+
+		val_bit++;
+	}
+	return res;
+}
+
+int evsel__get_config_val(struct perf_pmu *pmu, struct evsel *evsel,
+			  const char *config_name, u64 *val)
+{
+	struct perf_pmu_format *format = pmu_find_format(&pmu->format, config_name);
+	u64 bits = perf_pmu__format_bits(pmu, config_name);
+
+	if (!format || !bits) {
+		pr_err("Unknown/empty format name: %s\n", config_name);
+		*val = 0;
+		return -EINVAL;
+	}
+
+	switch (format->value) {
+	case PERF_PMU_FORMAT_VALUE_CONFIG:
+		*val = pmu_format_unpack(bits, evsel->core.attr.config);
+		return 0;
+	case PERF_PMU_FORMAT_VALUE_CONFIG1:
+		*val = pmu_format_unpack(bits, evsel->core.attr.config1);
+		return 0;
+	case PERF_PMU_FORMAT_VALUE_CONFIG2:
+		*val = pmu_format_unpack(bits, evsel->core.attr.config2);
+		return 0;
+	case PERF_PMU_FORMAT_VALUE_CONFIG3:
+		*val = pmu_format_unpack(bits, evsel->core.attr.config3);
+		return 0;
+	case PERF_PMU_FORMAT_VALUE_CONFIG4:
+		*val = pmu_format_unpack(bits, evsel->core.attr.config4);
+		return 0;
+	default:
+		pr_err("Unknown format value: %d\n", format->value);
+		*val = 0;
+		return -EINVAL;
+	}
+}
+
 /*
  * Set @config_name to @val as long as the user hasn't already set or cleared it
  * by passing a config term on the command line.
@@ -1432,7 +1487,7 @@ void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
 		return;
 
 	/* Otherwise replace it */
-	pmu_format_value(&bits, val, vp, /*zero=*/true);
+	pmu_format_pack(&bits, val, vp, /*zero=*/true);
 }
 
 static struct perf_pmu_format *
@@ -1477,8 +1532,8 @@ int perf_pmu__format_type(struct perf_pmu *pmu, const char *name)
  * Sets value based on the format definition (format parameter)
  * and unformatted value (value parameter).
  */
-static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
-			     bool zero)
+static void pmu_format_pack(unsigned long *format, __u64 value, __u64 *v,
+			    bool zero)
 {
 	unsigned long fbit, vbit;
 
@@ -1595,23 +1650,23 @@ static int pmu_config_term(const struct perf_pmu *pmu,
 		switch (term->type_term) {
 		case PARSE_EVENTS__TERM_TYPE_CONFIG:
 			assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
-			pmu_format_value(bits, term->val.num, &attr->config, zero);
+			pmu_format_pack(bits, term->val.num, &attr->config, zero);
 			break;
 		case PARSE_EVENTS__TERM_TYPE_CONFIG1:
 			assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
-			pmu_format_value(bits, term->val.num, &attr->config1, zero);
+			pmu_format_pack(bits, term->val.num, &attr->config1, zero);
 			break;
 		case PARSE_EVENTS__TERM_TYPE_CONFIG2:
 			assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
-			pmu_format_value(bits, term->val.num, &attr->config2, zero);
+			pmu_format_pack(bits, term->val.num, &attr->config2, zero);
 			break;
 		case PARSE_EVENTS__TERM_TYPE_CONFIG3:
 			assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
-			pmu_format_value(bits, term->val.num, &attr->config3, zero);
+			pmu_format_pack(bits, term->val.num, &attr->config3, zero);
 			break;
 		case PARSE_EVENTS__TERM_TYPE_CONFIG4:
 			assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
-			pmu_format_value(bits, term->val.num, &attr->config4, zero);
+			pmu_format_pack(bits, term->val.num, &attr->config4, zero);
 			break;
 		case PARSE_EVENTS__TERM_TYPE_LEGACY_HARDWARE_CONFIG:
 			assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
@@ -1749,7 +1804,7 @@ static int pmu_config_term(const struct perf_pmu *pmu,
 		 */
 	}
 
-	pmu_format_value(format->bits, val, vp, zero);
+	pmu_format_pack(format->bits, val, vp, zero);
 	return 0;
 }
 

-- 
2.34.1



From james.clark at linaro.org  Mon Dec  8 06:22:09 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 08 Dec 2025 14:22:09 +0000
Subject: [PATCH v2 06/12] perf parse-events: Always track user config
 changes
In-Reply-To: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
References: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
Message-ID: <20251208-james-perf-config-bits-v2-6-4ac0281993b0@linaro.org>

Requiring the 'pmu->perf_event_attr_init_default' callback to be set to
track user changes is a bit of a trap to fall in. It's hard to see that
this is required when depending on the user change tracking.

It's possible to want all 0 defaults so not set it, but at the same time
still do some programmatic setting of configs with
evsel__set_config_if_unset(). Also if a PMU reverts to 0 defaults and
deletes its existing callback, it will silently break existing uses of
evsel__set_config_if_unset().

One way to fix this would be to assert in evsel__set_config_if_unset()
if the changes weren't tracked, but that would be a possibly untested
runtime failure. Instead, always track it as it's harmless and
simplifies testing too.

Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/util/parse-events.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 7a3a90377896..c58829004fb4 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1528,12 +1528,8 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state,
 		return -ENOMEM;
 	}
 
-	/*
-	 * When using default config, record which bits of attr->config were
-	 * changed by the user.
-	 */
-	if (pmu->perf_event_attr_init_default &&
-	    get_config_chgs(pmu, &parsed_terms, &config_terms)) {
+	/* Record which bits of attr->config were changed by the user. */
+	if (get_config_chgs(pmu, &parsed_terms, &config_terms)) {
 		parse_events_terms__exit(&parsed_terms);
 		return -ENOMEM;
 	}

-- 
2.34.1



From james.clark at linaro.org  Mon Dec  8 06:22:10 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 08 Dec 2025 14:22:10 +0000
Subject: [PATCH v2 07/12] perf tests: Test evsel__set_config_if_unset() and
 config change tracking
In-Reply-To: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
References: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
Message-ID: <20251208-james-perf-config-bits-v2-7-4ac0281993b0@linaro.org>

Test that evsel__set_config_if_unset() behaves as expected. This also
tests the user config change tracking mechanism as it depends on it.

Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/tests/pmu.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 90 insertions(+)

diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c
index cbded2c6faa4..f938135e62aa 100644
--- a/tools/perf/tests/pmu.c
+++ b/tools/perf/tests/pmu.c
@@ -192,9 +192,98 @@ static int test__pmu_format(struct test_suite *test __maybe_unused, int subtest
 	}
 	if (attr.config2 != 0x0400000020041d07) {
 		pr_err("Unexpected config2 value %llx\n", attr.config2);
+	}
+
+	ret = TEST_OK;
+err_out:
+	parse_events_terms__exit(&terms);
+	test_pmu_put(dir, pmu);
+	return ret;
+}
+
+static int test__pmu_usr_chgs(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
+{
+	const char *event = "perf-pmu-test/config=15,config1=4,krava02=170,"
+			    "krava03=1,krava11=27,krava12=1/";
+	struct parse_events_terms terms;
+	struct parse_events_error err;
+	LIST_HEAD(config_terms);
+	struct evlist *evlist;
+	struct perf_pmu *pmu;
+	struct evsel *evsel;
+	int ret = TEST_FAIL;
+	char dir[PATH_MAX];
+	u64 val;
+
+	pmu = test_pmu_get(dir, sizeof(dir));
+	if (!pmu)
+		return TEST_FAIL;
+
+	evlist = evlist__new();
+	if (evlist == NULL) {
+		pr_err("Failed allocation");
 		goto err_out;
 	}
 
+	parse_events_terms__init(&terms);
+	ret = parse_events(evlist, event, &err);
+	if (ret) {
+		pr_debug("failed to parse event '%s', err %d\n", event, ret);
+		parse_events_error__print(&err, event);
+		if (parse_events_error__contains(&err, "can't access trace events"))
+			ret = TEST_SKIP;
+		goto err_out;
+	}
+	evsel = evlist__first(evlist);
+
+	/*
+	 * Set via config=15, krava01 bits 0-1
+	 * Set via config1=4, krava11 bit 1
+	 * Set values: krava02=170, krava03=1, krava11=27, krava12=1
+	 *
+	 * Test that already set values aren't overwritten.
+	 */
+	evsel__set_config_if_unset(pmu, evsel, "krava01", 16);
+	evsel__get_config_val(pmu, evsel, "krava01", &val);
+	TEST_ASSERT_EQUAL("krava01 overwritten", (int) val, (15 & 0b11));
+
+	evsel__set_config_if_unset(pmu, evsel, "krava11", 45);
+	evsel__get_config_val(pmu, evsel, "krava11", &val);
+	TEST_ASSERT_EQUAL("krava11 overwritten", (int) val, (27 | (4 << 1)));
+
+	evsel__set_config_if_unset(pmu, evsel, "krava02", 32);
+	evsel__get_config_val(pmu, evsel, "krava02", &val);
+	TEST_ASSERT_EQUAL("krava02 overwritten", (int) val, 170);
+
+	evsel__set_config_if_unset(pmu, evsel, "krava03", 0);
+	evsel__get_config_val(pmu, evsel, "krava03", &val);
+	TEST_ASSERT_EQUAL("krava03 overwritten", (int) val, 1);
+
+	/*
+	 * krava13 doesn't have any bits set by either krava13= or config1=
+	 * but setting _any_ raw value for config1 implies that krava13
+	 * shouldn't be overwritten. So it's value should remain as 0.
+	 */
+	evsel__set_config_if_unset(pmu, evsel, "krava13", 5);
+	evsel__get_config_val(pmu, evsel, "krava13", &val);
+	TEST_ASSERT_EQUAL("krava13 overwritten", (int) val, 0);
+
+	/*
+	 * Unset values: krava21, krava22, krava23
+	 *
+	 * Test that unset values are overwritten.
+	 */
+	evsel__set_config_if_unset(pmu, evsel, "krava21", 13905);
+	evsel__get_config_val(pmu, evsel, "krava21", &val);
+	TEST_ASSERT_EQUAL("krava21 not overwritten", (int) val, 13905);
+
+	evsel__set_config_if_unset(pmu, evsel, "krava22", 11);
+	evsel__get_config_val(pmu, evsel, "krava22", &val);
+	TEST_ASSERT_EQUAL("krava22 not overwritten", (int) val, 11);
+
+	evsel__set_config_if_unset(pmu, evsel, "krava23", 0);
+	evsel__get_config_val(pmu, evsel, "krava23", &val);
+	TEST_ASSERT_EQUAL("krava23 not overwritten", (int) val, 0);
 	ret = TEST_OK;
 err_out:
 	parse_events_terms__exit(&terms);
@@ -539,6 +628,7 @@ static struct test_case tests__pmu[] = {
 	TEST_CASE("PMU name combining", name_len),
 	TEST_CASE("PMU name comparison", name_cmp),
 	TEST_CASE("PMU cmdline match", pmu_match),
+	TEST_CASE("PMU user config changes", pmu_usr_chgs),
 	{	.name = NULL, }
 };
 

-- 
2.34.1



From james.clark at linaro.org  Mon Dec  8 06:22:11 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 08 Dec 2025 14:22:11 +0000
Subject: [PATCH v2 08/12] perf cs-etm: Make a helper to find the Coresight
 evsel
In-Reply-To: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
References: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
Message-ID: <20251208-james-perf-config-bits-v2-8-4ac0281993b0@linaro.org>

This pattern occurs a few times and we'll add another one later, so add
a helper function for it.

Reviewed-by: Leo Yan <leo.yan at arm.com>
Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/arch/arm/util/cs-etm.c | 50 +++++++++++++++++++++------------------
 1 file changed, 27 insertions(+), 23 deletions(-)

diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
index ea891d12f8f4..22c6272e8c36 100644
--- a/tools/perf/arch/arm/util/cs-etm.c
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -302,6 +302,19 @@ static int cs_etm_set_sink_attr(struct perf_pmu *pmu,
 	return 0;
 }
 
+static struct evsel *cs_etm_get_evsel(struct evlist *evlist,
+				      struct perf_pmu *cs_etm_pmu)
+{
+	struct evsel *evsel;
+
+	evlist__for_each_entry(evlist, evsel) {
+		if (evsel->core.attr.type == cs_etm_pmu->type)
+			return evsel;
+	}
+
+	return NULL;
+}
+
 static int cs_etm_recording_options(struct auxtrace_record *itr,
 				    struct evlist *evlist,
 				    struct record_opts *opts)
@@ -476,29 +489,21 @@ static int cs_etm_recording_options(struct auxtrace_record *itr,
 
 static u64 cs_etm_get_config(struct auxtrace_record *itr)
 {
-	u64 config = 0;
 	struct cs_etm_recording *ptr =
 			container_of(itr, struct cs_etm_recording, itr);
 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
 	struct evlist *evlist = ptr->evlist;
-	struct evsel *evsel;
+	struct evsel *evsel = cs_etm_get_evsel(evlist, cs_etm_pmu);
 
-	evlist__for_each_entry(evlist, evsel) {
-		if (evsel->core.attr.type == cs_etm_pmu->type) {
-			/*
-			 * Variable perf_event_attr::config is assigned to
-			 * ETMv3/PTM.  The bit fields have been made to match
-			 * the ETMv3.5 ETRMCR register specification.  See the
-			 * PMU_FORMAT_ATTR() declarations in
-			 * drivers/hwtracing/coresight/coresight-perf.c for
-			 * details.
-			 */
-			config = evsel->core.attr.config;
-			break;
-		}
-	}
-
-	return config;
+	/*
+	 * Variable perf_event_attr::config is assigned to
+	 * ETMv3/PTM.  The bit fields have been made to match
+	 * the ETMv3.5 ETRMCR register specification.  See the
+	 * PMU_FORMAT_ATTR() declarations in
+	 * drivers/hwtracing/coresight/coresight-perf.c for
+	 * details.
+	 */
+	return evsel ? evsel->core.attr.config : 0;
 }
 
 #ifndef BIT
@@ -832,12 +837,11 @@ static int cs_etm_snapshot_start(struct auxtrace_record *itr)
 {
 	struct cs_etm_recording *ptr =
 			container_of(itr, struct cs_etm_recording, itr);
-	struct evsel *evsel;
+	struct evsel *evsel = cs_etm_get_evsel(ptr->evlist, ptr->cs_etm_pmu);
+
+	if (evsel)
+		return evsel__disable(evsel);
 
-	evlist__for_each_entry(ptr->evlist, evsel) {
-		if (evsel->core.attr.type == ptr->cs_etm_pmu->type)
-			return evsel__disable(evsel);
-	}
 	return -EINVAL;
 }
 

-- 
2.34.1



From james.clark at linaro.org  Mon Dec  8 06:22:12 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 08 Dec 2025 14:22:12 +0000
Subject: [PATCH v2 09/12] perf cs-etm: Don't use hard coded config bits
 when setting up ETMCR
In-Reply-To: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
References: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
Message-ID: <20251208-james-perf-config-bits-v2-9-4ac0281993b0@linaro.org>

Perf only looks at attr.config when determining what was programmed into
ETMCR. These bits could theoretically be in any of the config fields.
Add a generic helper to find the value of any named format field in any
config field and then use it to get the attributes relevant to ETMCR.

The kernel will also stop publishing the ETMCR register bits in a header
[1] so preempt that by defining them here.

Move field_prep() to util.h so we can define it along side field_get().
Unfortunately FIELD_PREP() and FIELD_GET() from the kernel can't be used
as they require the mask to be a compile time constant.

[1]: https://lore.kernel.org/linux-arm-kernel/20251128-james-cs-syncfreq-v8-10-4d319764cc58 at linaro.org/
Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/arch/arm/util/cs-etm.c | 35 ++++++++++++++++++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)

diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
index 22c6272e8c36..a5135b743e6f 100644
--- a/tools/perf/arch/arm/util/cs-etm.c
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -68,6 +68,12 @@ static const char * const metadata_ete_ro[] = {
 
 enum cs_etm_version { CS_NOT_PRESENT, CS_ETMV3, CS_ETMV4, CS_ETE };
 
+
+/* ETMv3 ETMCR register bits */
+#define ETMCR_CYC_ACC		BIT(12)
+#define ETMCR_TIMESTAMP_EN	BIT(28)
+#define ETMCR_RETURN_STACK	BIT(29)
+
 static bool cs_etm_is_ete(struct perf_pmu *cs_etm_pmu, struct perf_cpu cpu);
 static int cs_etm_get_ro(struct perf_pmu *pmu, struct perf_cpu cpu, const char *path, __u64 *val);
 static bool cs_etm_pmu_path_exists(struct perf_pmu *pmu, struct perf_cpu cpu, const char *path);
@@ -487,6 +493,33 @@ static int cs_etm_recording_options(struct auxtrace_record *itr,
 	return err;
 }
 
+static u64 cs_etm_synth_etmcr(struct auxtrace_record *itr)
+{
+	struct cs_etm_recording *ptr =
+		container_of(itr, struct cs_etm_recording, itr);
+	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
+	struct evsel *evsel = cs_etm_get_evsel(ptr->evlist, cs_etm_pmu);
+	u64 etmcr = 0;
+	u64 val;
+
+	if (!evsel)
+		return 0;
+
+	/*
+	 * Synthesize what the kernel programmed into ETMCR based on
+	 * what options the event was opened with. This doesn't have to be
+	 * complete or 100% accurate, not all bits used by OpenCSD anyway.
+	 */
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "cycacc", &val) && val)
+		etmcr |= ETMCR_CYC_ACC;
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "timestamp", &val) && val)
+		etmcr |= ETMCR_TIMESTAMP_EN;
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "retstack", &val) && val)
+		etmcr |= ETMCR_RETURN_STACK;
+
+	return etmcr;
+}
+
 static u64 cs_etm_get_config(struct auxtrace_record *itr)
 {
 	struct cs_etm_recording *ptr =
@@ -746,7 +779,7 @@ static void cs_etm_get_metadata(struct perf_cpu cpu, u32 *offset,
 	case CS_ETMV3:
 		magic = __perf_cs_etmv3_magic;
 		/* Get configuration register */
-		info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr);
+		info->priv[*offset + CS_ETM_ETMCR] = cs_etm_synth_etmcr(itr);
 		/* traceID set to legacy value in case new perf running on old system */
 		info->priv[*offset + CS_ETM_ETMTRACEIDR] = cs_etm_get_legacy_trace_id(cpu);
 		/* Get read-only information from sysFS */

-- 
2.34.1



From james.clark at linaro.org  Mon Dec  8 06:22:13 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 08 Dec 2025 14:22:13 +0000
Subject: [PATCH v2 10/12] perf cs-etm: Don't use hard coded config bits
 when setting up TRCCONFIGR
In-Reply-To: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
References: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
Message-ID: <20251208-james-perf-config-bits-v2-10-4ac0281993b0@linaro.org>

Perf only looks at attr.config when determining what was programmed into
TRCCONFIGR. These bits could theoretically be in any of the config
fields. Use the evsel__get_config_val() helper so it's agnostic to
which config field they are in.

The kernel will also stop publishing the TRCCONFIGR register bits in a
header [1] so preempt that by defining them here.

[1]: https://lore.kernel.org/linux-arm-kernel/20251128-james-cs-syncfreq-v8-10-4d319764cc58 at linaro.org/
Reviewed-by: Leo Yan <leo.yan at arm.com>
Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/arch/arm/util/cs-etm.c | 79 +++++++++++++++++----------------------
 1 file changed, 34 insertions(+), 45 deletions(-)

diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
index a5135b743e6f..4a606b1e90f2 100644
--- a/tools/perf/arch/arm/util/cs-etm.c
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -68,6 +68,14 @@ static const char * const metadata_ete_ro[] = {
 
 enum cs_etm_version { CS_NOT_PRESENT, CS_ETMV3, CS_ETMV4, CS_ETE };
 
+/* ETMv4 CONFIGR register bits */
+#define TRCCONFIGR_BB		BIT(3)
+#define TRCCONFIGR_CCI		BIT(4)
+#define TRCCONFIGR_CID		BIT(6)
+#define TRCCONFIGR_VMID		BIT(7)
+#define TRCCONFIGR_TS		BIT(11)
+#define TRCCONFIGR_RS		BIT(12)
+#define TRCCONFIGR_VMIDOPT	BIT(15)
 
 /* ETMv3 ETMCR register bits */
 #define ETMCR_CYC_ACC		BIT(12)
@@ -520,56 +528,37 @@ static u64 cs_etm_synth_etmcr(struct auxtrace_record *itr)
 	return etmcr;
 }
 
-static u64 cs_etm_get_config(struct auxtrace_record *itr)
+static u64 cs_etmv4_synth_trcconfigr(struct auxtrace_record *itr)
 {
+	u64 trcconfigr = 0;
 	struct cs_etm_recording *ptr =
-			container_of(itr, struct cs_etm_recording, itr);
+		container_of(itr, struct cs_etm_recording, itr);
 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
-	struct evlist *evlist = ptr->evlist;
-	struct evsel *evsel = cs_etm_get_evsel(evlist, cs_etm_pmu);
-
-	/*
-	 * Variable perf_event_attr::config is assigned to
-	 * ETMv3/PTM.  The bit fields have been made to match
-	 * the ETMv3.5 ETRMCR register specification.  See the
-	 * PMU_FORMAT_ATTR() declarations in
-	 * drivers/hwtracing/coresight/coresight-perf.c for
-	 * details.
-	 */
-	return evsel ? evsel->core.attr.config : 0;
-}
-
-#ifndef BIT
-#define BIT(N) (1UL << (N))
-#endif
+	struct evsel *evsel = cs_etm_get_evsel(ptr->evlist, cs_etm_pmu);
+	u64 val;
 
-static u64 cs_etmv4_get_config(struct auxtrace_record *itr)
-{
-	u64 config = 0;
-	u64 config_opts = 0;
+	if (!evsel)
+		return 0;
 
 	/*
-	 * The perf event variable config bits represent both
-	 * the command line options and register programming
-	 * bits in ETMv3/PTM. For ETMv4 we must remap options
-	 * to real bits
+	 * Synthesize what the kernel programmed into TRCCONFIGR based on
+	 * what options the event was opened with. This doesn't have to be
+	 * complete or 100% accurate, not all bits used by OpenCSD anyway.
 	 */
-	config_opts = cs_etm_get_config(itr);
-	if (config_opts & BIT(ETM_OPT_CYCACC))
-		config |= BIT(ETM4_CFG_BIT_CYCACC);
-	if (config_opts & BIT(ETM_OPT_CTXTID))
-		config |= BIT(ETM4_CFG_BIT_CTXTID);
-	if (config_opts & BIT(ETM_OPT_TS))
-		config |= BIT(ETM4_CFG_BIT_TS);
-	if (config_opts & BIT(ETM_OPT_RETSTK))
-		config |= BIT(ETM4_CFG_BIT_RETSTK);
-	if (config_opts & BIT(ETM_OPT_CTXTID2))
-		config |= BIT(ETM4_CFG_BIT_VMID) |
-			  BIT(ETM4_CFG_BIT_VMID_OPT);
-	if (config_opts & BIT(ETM_OPT_BRANCH_BROADCAST))
-		config |= BIT(ETM4_CFG_BIT_BB);
-
-	return config;
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "cycacc", &val) && val)
+		trcconfigr |= TRCCONFIGR_CCI;
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "contextid1", &val) && val)
+		trcconfigr |= TRCCONFIGR_CID;
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "timestamp", &val) && val)
+		trcconfigr |= TRCCONFIGR_TS;
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "retstack", &val) && val)
+		trcconfigr |= TRCCONFIGR_RS;
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "contextid2", &val) && val)
+		trcconfigr |= TRCCONFIGR_VMID | TRCCONFIGR_VMIDOPT;
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "branch_broadcast", &val) && val)
+		trcconfigr |= TRCCONFIGR_BB;
+
+	return trcconfigr;
 }
 
 static size_t
@@ -691,7 +680,7 @@ static void cs_etm_save_etmv4_header(__u64 data[], struct auxtrace_record *itr,
 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
 
 	/* Get trace configuration register */
-	data[CS_ETMV4_TRCCONFIGR] = cs_etmv4_get_config(itr);
+	data[CS_ETMV4_TRCCONFIGR] = cs_etmv4_synth_trcconfigr(itr);
 	/* traceID set to legacy version, in case new perf running on older system */
 	data[CS_ETMV4_TRCTRACEIDR] = cs_etm_get_legacy_trace_id(cpu);
 
@@ -723,7 +712,7 @@ static void cs_etm_save_ete_header(__u64 data[], struct auxtrace_record *itr, st
 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
 
 	/* Get trace configuration register */
-	data[CS_ETE_TRCCONFIGR] = cs_etmv4_get_config(itr);
+	data[CS_ETE_TRCCONFIGR] = cs_etmv4_synth_trcconfigr(itr);
 	/* traceID set to legacy version, in case new perf running on older system */
 	data[CS_ETE_TRCTRACEIDR] = cs_etm_get_legacy_trace_id(cpu);
 

-- 
2.34.1



From james.clark at linaro.org  Mon Dec  8 06:22:14 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 08 Dec 2025 14:22:14 +0000
Subject: [PATCH v2 11/12] perf cs-etm: Don't hard code config attribute
 when configuring the event
In-Reply-To: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
References: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
Message-ID: <20251208-james-perf-config-bits-v2-11-4ac0281993b0@linaro.org>

These instances of hard coded config attributes are used for configuring
and validating the event options. Use the config attribute that's
published by the driver by replacing the open coded operations with
evsel__get_config_val() and evsel__set_config_if_unset().

Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/arch/arm/util/cs-etm.c | 57 +++++++++++++++++++--------------------
 1 file changed, 28 insertions(+), 29 deletions(-)

diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
index 4a606b1e90f2..bfb573cb5878 100644
--- a/tools/perf/arch/arm/util/cs-etm.c
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -103,13 +103,14 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
 				      struct perf_cpu cpu)
 {
 	int err;
-	__u64 val;
-	u64 contextid = evsel->core.attr.config &
-		(perf_pmu__format_bits(cs_etm_pmu, "contextid") |
-		 perf_pmu__format_bits(cs_etm_pmu, "contextid1") |
-		 perf_pmu__format_bits(cs_etm_pmu, "contextid2"));
+	u64 ctxt, ctxt1, ctxt2;
+	__u64 trcidr2;
 
-	if (!contextid)
+	evsel__get_config_val(cs_etm_pmu, evsel, "contextid", &ctxt);
+	evsel__get_config_val(cs_etm_pmu, evsel, "contextid1", &ctxt1);
+	evsel__get_config_val(cs_etm_pmu, evsel, "contextid2", &ctxt2);
+
+	if (!ctxt && !ctxt1 && !ctxt2)
 		return 0;
 
 	/* Not supported in etmv3 */
@@ -120,12 +121,11 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
 	}
 
 	/* Get a handle on TRCIDR2 */
-	err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2], &val);
+	err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2], &trcidr2);
 	if (err)
 		return err;
 
-	if (contextid &
-	    perf_pmu__format_bits(cs_etm_pmu, "contextid1")) {
+	if (ctxt1) {
 		/*
 		 * TRCIDR2.CIDSIZE, bit [9-5], indicates whether contextID
 		 * tracing is supported:
@@ -133,15 +133,14 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
 		 *  0b00100 Maximum of 32-bit Context ID size.
 		 *  All other values are reserved.
 		 */
-		if (BMVAL(val, 5, 9) != 0x4) {
+		if (BMVAL(trcidr2, 5, 9) != 0x4) {
 			pr_err("%s: CONTEXTIDR_EL1 isn't supported, disable with %s/contextid1=0/\n",
 			       CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME);
 			return -EINVAL;
 		}
 	}
 
-	if (contextid &
-	    perf_pmu__format_bits(cs_etm_pmu, "contextid2")) {
+	if (ctxt2) {
 		/*
 		 * TRCIDR2.VMIDOPT[30:29] != 0 and
 		 * TRCIDR2.VMIDSIZE[14:10] == 0b00100 (32bit virtual contextid)
@@ -149,7 +148,7 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
 		 * virtual context id is < 32bit.
 		 * Any value of VMIDSIZE >= 4 (i.e, > 32bit) is fine for us.
 		 */
-		if (!BMVAL(val, 29, 30) || BMVAL(val, 10, 14) < 4) {
+		if (!BMVAL(trcidr2, 29, 30) || BMVAL(trcidr2, 10, 14) < 4) {
 			pr_err("%s: CONTEXTIDR_EL2 isn't supported, disable with %s/contextid2=0/\n",
 			       CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME);
 			return -EINVAL;
@@ -163,10 +162,11 @@ static int cs_etm_validate_timestamp(struct perf_pmu *cs_etm_pmu, struct evsel *
 				     struct perf_cpu cpu)
 {
 	int err;
-	__u64 val;
+	u64 val;
+	__u64 trcidr0;
 
-	if (!(evsel->core.attr.config &
-	      perf_pmu__format_bits(cs_etm_pmu, "timestamp")))
+	evsel__get_config_val(cs_etm_pmu, evsel, "timestamp", &val);
+	if (!val)
 		return 0;
 
 	if (cs_etm_get_version(cs_etm_pmu, cpu) == CS_ETMV3) {
@@ -176,7 +176,7 @@ static int cs_etm_validate_timestamp(struct perf_pmu *cs_etm_pmu, struct evsel *
 	}
 
 	/* Get a handle on TRCIRD0 */
-	err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0], &val);
+	err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0], &trcidr0);
 	if (err)
 		return err;
 
@@ -187,10 +187,9 @@ static int cs_etm_validate_timestamp(struct perf_pmu *cs_etm_pmu, struct evsel *
 	 *  0b00110 Implementation supports a maximum timestamp of 48bits.
 	 *  0b01000 Implementation supports a maximum timestamp of 64bits.
 	 */
-	val &= GENMASK(28, 24);
-	if (!val) {
+	trcidr0 &= GENMASK(28, 24);
+	if (!trcidr0)
 		return -EINVAL;
-	}
 
 	return 0;
 }
@@ -273,16 +272,20 @@ static int cs_etm_parse_snapshot_options(struct auxtrace_record *itr,
 	return 0;
 }
 
+/*
+ * The sink name format "@sink_name" is used, lookup the sink by name to convert
+ * to "sinkid=sink_hash" format.
+ *
+ * If the user has already manually provided a hash then "sinkid" isn't
+ * overwritten. If neither are provided then the driver will pick the best sink.
+ */
 static int cs_etm_set_sink_attr(struct perf_pmu *pmu,
 				struct evsel *evsel)
 {
 	char msg[BUFSIZ], path[PATH_MAX], *sink;
 	struct evsel_config_term *term;
-	int ret = -EINVAL;
 	u32 hash;
-
-	if (evsel->core.attr.config2 & GENMASK(31, 0))
-		return 0;
+	int ret;
 
 	list_for_each_entry(term, &evsel->config_terms, list) {
 		if (term->type != EVSEL__CONFIG_TERM_DRV_CFG)
@@ -305,14 +308,10 @@ static int cs_etm_set_sink_attr(struct perf_pmu *pmu,
 			return ret;
 		}
 
-		evsel->core.attr.config2 |= hash;
+		evsel__set_config_if_unset(pmu, evsel, "sinkid", hash);
 		return 0;
 	}
 
-	/*
-	 * No sink was provided on the command line - allow the CoreSight
-	 * system to look for a default
-	 */
 	return 0;
 }
 

-- 
2.34.1



From james.clark at linaro.org  Mon Dec  8 06:22:15 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 08 Dec 2025 14:22:15 +0000
Subject: [PATCH v2 12/12] perf arm-spe: Don't hard code config attribute
In-Reply-To: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
References: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
Message-ID: <20251208-james-perf-config-bits-v2-12-4ac0281993b0@linaro.org>

Use the config attribute that's published by the driver instead of
hard coding "attr.config".

Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/arch/arm64/util/arm-spe.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c
index d5ec1408d0ae..6c3dc97fde30 100644
--- a/tools/perf/arch/arm64/util/arm-spe.c
+++ b/tools/perf/arch/arm64/util/arm-spe.c
@@ -256,7 +256,7 @@ static __u64 arm_spe_pmu__sample_period(const struct perf_pmu *arm_spe_pmu)
 
 static void arm_spe_setup_evsel(struct evsel *evsel, struct perf_cpu_map *cpus)
 {
-	u64 bit;
+	u64 pa_enable_bit;
 
 	evsel->core.attr.freq = 0;
 	evsel->core.attr.sample_period = arm_spe_pmu__sample_period(evsel->pmu);
@@ -288,9 +288,10 @@ static void arm_spe_setup_evsel(struct evsel *evsel, struct perf_cpu_map *cpus)
 	 * inform that the resulting output's SPE samples contain physical addresses
 	 * where applicable.
 	 */
-	bit = perf_pmu__format_bits(evsel->pmu, "pa_enable");
-	if (evsel->core.attr.config & bit)
-		evsel__set_sample_bit(evsel, PHYS_ADDR);
+
+	if (!evsel__get_config_val(evsel->pmu, evsel, "pa_enable", &pa_enable_bit))
+		if (pa_enable_bit)
+			evsel__set_sample_bit(evsel, PHYS_ADDR);
 }
 
 static int arm_spe_setup_aux_buffer(struct record_opts *opts)
@@ -397,6 +398,7 @@ static int arm_spe_recording_options(struct auxtrace_record *itr,
 	struct perf_cpu_map *cpus = evlist->core.user_requested_cpus;
 	bool discard = false;
 	int err;
+	u64 discard_bit;
 
 	sper->evlist = evlist;
 
@@ -425,9 +427,8 @@ static int arm_spe_recording_options(struct auxtrace_record *itr,
 	evlist__for_each_entry_safe(evlist, tmp, evsel) {
 		if (evsel__is_aux_event(evsel)) {
 			arm_spe_setup_evsel(evsel, cpus);
-			if (evsel->core.attr.config &
-			    perf_pmu__format_bits(evsel->pmu, "discard"))
-				discard = true;
+			if (!evsel__get_config_val(evsel->pmu, evsel, "discard", &discard_bit))
+				discard = !!discard_bit;
 		}
 	}
 

-- 
2.34.1



From mike.leach at linaro.org  Mon Dec  8 06:25:05 2025
From: mike.leach at linaro.org (Mike Leach)
Date: Mon, 8 Dec 2025 14:25:05 +0000
Subject: [PATCH v6 2/2] coresight: cti: Add Qualcomm extended CTI support
In-Reply-To: <20251205102720.GP724103@e132581.arm.com>
References: <20251202-extended_cti-v6-0-ab68bb15c4f5@oss.qualcomm.com>
 <20251202-extended_cti-v6-2-ab68bb15c4f5@oss.qualcomm.com>
 <20251203182944.GG724103@e132581.arm.com> <CAJ9a7VhcSxTTaxMR4SS+GbHoPHXm0honykjXy92fbv0HG=1o4Q@mail.gmail.com>
 <20251204104713.GL724103@e132581.arm.com> <CAJ9a7VgV6chvWmeG2xta11YqyNpdRZqx4=EF7vC7k=J2utpRYQ@mail.gmail.com>
 <20251205102720.GP724103@e132581.arm.com>
Message-ID: <CAJ9a7VgYoSZPsm1jPniVZWZk7MHRAsRJwQGBxyNmndCcfnso2g@mail.gmail.com>

Hi Leo,

On Fri, 5 Dec 2025 at 10:27, Leo Yan <leo.yan at arm.com> wrote:
>
> On Thu, Dec 04, 2025 at 03:07:10PM +0000, Mike Leach wrote:
>
> [...]
>
> > > > > > +             /*
> > > > > > +              * QCOM CTI does not implement Claimtag functionality as
> > > > > > +              * per CoreSight specification, but its CLAIMSET register
> > > > > > +              * is incorrectly initialized to 0xF. This can mislead
> > > > > > +              * tools or drivers into thinking the component is claimed.
> > > > > > +              *
> > > > > > +              * Reset CLAIMSET to 0 to reflect that no claims are active.
> > > > > > +              */
> > > > > > +             writel_relaxed(0, drvdata->base + CORESIGHT_CLAIMSET);
> > > > >
> > > > > I am confused for this.  If QCOM CTI does not implement claim tag,
> > > > > then what is the designed register at the offset CORESIGHT_CLAIMSET?
> > > > >
> > > > > Should you bypass all claim tag related operations for QCOM CTI case?
> > > > > (I don't see you touch anything for claim and declaim tags).
> > > > >
> > > >
> > > > The patch I have created to handle systems without correct claim tag
> > > > operation is a dependency for this patch set. Thus no need for
> > > > override here as the core code will handle this correctly.
> > > >
> > > > The only issue is ensuring the non-CTI spec implementation will result
> > > > in the correct detection of no claim tags present.
> > >
> > > Your patch works only when a module has implemented claim registers.
> > >
> >
> > Per the Coresight spec - unimplemented registers must be RAZ/WI- so
> > this still works for non implemented claim registers.
>
> QCOM CTI does not follow the spec in two aspects:
>
> - Given the patch's comment: "QCOM CTI does not implement Claim tag
>   functionality as per CoreSight specification", I am suspect the CLAIM
>   registers are not implemented at all in QCOM CTI.
>
> - It neither follows up the "unimplemented registers must be RAZ/WI" -
>   the patch says its reset value is 0xF and then even can write 0 to it.
>

Correct - but my point is that the patch to handle lack of claim tags
does work for both existent claim tags and unimplemented ones, where
the spec is followed.

> > > This leads to two issues: we end up clearing an unknown register in the
> > > CTI driver, and then the coresight core layer assumes it is reading a
> > > claim register even though it is not.
> >
> > Again RAZ will simply read 0x0 - which is an indication that there are
> > no claim bits implemented.
> >
> > >
> > > For QCOM CTI, combined with your patch, I would suggest directly
> > > setting csdev->access.claim_tag_impl to false (perhaps using a helper).
> >
> > That would be a better solution, though as Qcom appear to have
> > implemented a pair of standard RW registers rather than the claim tag
> > functionality, the write solution works for this particular
> > implementation.
>
> If an IP violates both the rules for implemented claim registers and
> the rules for non-implemented claim registers, how can we rely on
> these registers to detect the claim feature?
>
> My feeling is we are building a house on sand - these registers are not
> used for claim tags purpose at all.
>

No they are not, but by either writing the claim tag register with 0,
or by setting the csdev->access.claim_tag_impl to false, this
particular incorrect implementation instance can be made to work with
the existing claim tag code.

There are effectively two issues here:-

1) The existing core code does not correctly handle insufficient claim
tags or none existent claim tag register - per the coresight spec.
This needs fixing for all potential components - not just this one. My
claim tag patch does that.

2) This particular QCom CTI does not implement claim tags correctly.
This particular instance can be made to operate correctly as detailed
above as long as the core code can handle none-existent claim tags.
The alternative is to bracket every claim tag access call with an "if
!qcom_cti" statement. (which is what was happening in earlier
patches).

We need to fix the core code anyway, and the specific QCom CTI can
then be fixed in a single location without changes elsewhere in the
code. This is the cleanest and least disruptive solution.

Regards

Mike


> Thanks,
> Leo



-- 
Mike Leach
Principal Engineer, ARM Ltd.
Manchester Design Centre. UK


From mike.leach at linaro.org  Mon Dec  8 06:47:21 2025
From: mike.leach at linaro.org (Mike Leach)
Date: Mon, 8 Dec 2025 14:47:21 +0000
Subject: [PATCH v6 2/2] coresight: cti: Add Qualcomm extended CTI support
In-Reply-To: <20251205100432.GO724103@e132581.arm.com>
References: <20251202-extended_cti-v6-0-ab68bb15c4f5@oss.qualcomm.com>
 <20251202-extended_cti-v6-2-ab68bb15c4f5@oss.qualcomm.com>
 <20251203182944.GG724103@e132581.arm.com> <CAJ9a7VjWDBEwdmMf53geACBWGusC8BC3pJuOLETeecw24+N35Q@mail.gmail.com>
 <20251204103151.GK724103@e132581.arm.com> <CAJ9a7VjHHkkTz9XJqjdQ+11_XX9zXuY0ZcQzPtq=Zvi4CN__0A@mail.gmail.com>
 <20251205100432.GO724103@e132581.arm.com>
Message-ID: <CAJ9a7Vg9Efi-5eecfiUF82_Qq8Jg9imN5q1-VKYZoPVUxNpjhA@mail.gmail.com>

Hi Leo

On Fri, 5 Dec 2025 at 10:04, Leo Yan <leo.yan at arm.com> wrote:
>
> Hi Mike,
>
> On Thu, Dec 04, 2025 at 04:17:35PM +0000, Mike Leach wrote:
>
> [...]
>
> > The tables in the patch are
> >
> >     [reg_type_array_index] = offset_address;
> >
> > e.g.
> >
> >   [INDEX_CTIINTACK]  = QCOM_CTIINTACK
> >
> > which resolves to
> >
> >  [1] = 0x020
> >
> > where index is constant for a given register type,
> >
> > As far as I can tell what you have suggested above is a table that is
> >
> >   [std_addr_offset] = qcom_addr_offset;
> >
> > e.g.
> >
> > [CTIINTACK]             = QCOM_CTIINTACK,
> >
> > which resolves to
> >
> > [0x10]  = 0x020
> >
> > which does not appear to work correctly?

Sorry - what I mean here is the contiguous array that appears to be in
the source, does not match the reality when compiled into memory - not
that it doesn't work programmatically.

> >
> > The registers are sparsely spread across the memory map, so a simple
> > mapping does not work, even if we divide the original offset by 4 to
> > create a register number.
>
> This should work.  Though the array is not filled for each item, but
> it will return back 0x20 when we access array[0x10], I don't see
> problem here.
>
> > The largest standard offset we have is ITTRIGIN = 0xEF8, so assuming
> > the compiler allows us to sparselly populate the array (which I think
> > it does, along with some padding), we end up with an array of at least
> > 0xEF8 elements, rather then the indexed 21?
>
> I tested locally and did not see the GCC complaint for this approach.
> And this is a global structure with about 16KiB (~4K items x

Which is precisely the issue - why use 16k bytes of space when a pair
of indexed tables will use 21 x 32bit locations per table -> 168 bytes
- 100x smaller!

This space matters little to high end server systems but is much more
important in smaller embedded systems.

Moreover the table + inline helper is more efficient at extracting the
correct offset value. The helper is a simple de-reference - whereas
the helper functions you suggest require the code to make the
comparison at every register access.
The "if qcom ..." may be contained in one place in the source code,
but is called and executed for every access.

Why add inefficiencies, either in footprint or execution?

Regards

Mike


> sizeof(u32)), we don't need to worry about scaling issue as it is
> shared by device instances.
>
> If you dislike this way, then a static function also can fulfill the
> same task, something like:
>
>     static noinline u32 cti_qcom_reg_off(u32 offset)
>     {
>             switch (offset) {
>             CTIINTACK: return QCOM_CTIINTACK;
>             CTIAPPSET: return QCOM_CTIAPPSET;
>             ...
>             default:
>                 WARN(1, "Unknown offset=%u\n", offset);
>                 return 0;
>             }
>
>             /* Should not run here, just for compiling */
>             return 0;
>     }
>
> Thanks,
> Leo



-- 
Mike Leach
Principal Engineer, ARM Ltd.
Manchester Design Centre. UK


From jonas.gorski at gmail.com  Mon Dec  8 07:07:11 2025
From: jonas.gorski at gmail.com (Jonas Gorski)
Date: Mon, 8 Dec 2025 16:07:11 +0100
Subject: [PATCH] drivers: net: wireless: Replace deprecated PCI function
In-Reply-To: <20251207123447.93233-1-madhurkumar004@gmail.com>
References: <20251207123447.93233-1-madhurkumar004@gmail.com>
Message-ID: <CAOiHx=n8osZ=b=MVNsxAKEtxDvNgt1ESohLNMWoz43c9RwNfOA@mail.gmail.com>

Hi,

On Sun, Dec 7, 2025 at 1:35?PM Madhur Kumar <madhurkumar004 at gmail.com> wrote:
>
> pcim_iomap_table() and pcim_iomap_regions() have been
> deprecated.
> Replace them with pcim_iomap_region().

The patch subject is wrong, please read
https://wireless.docs.kernel.org/en/latest/en/developers/documentation/submittingpatches.html

>
> Signed-off-by: Madhur Kumar <madhurkumar004 at gmail.com>
> ---
>  drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 6 +-----
>  1 file changed, 1 insertion(+), 5 deletions(-)
>
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
> index ec9686183251..5a82c3bf471f 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
> @@ -284,10 +284,6 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
>         if (ret)
>                 return ret;
>
> -       ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev));
> -       if (ret)
> -               return ret;
> -
>         pci_read_config_word(pdev, PCI_COMMAND, &cmd);
>         if (!(cmd & PCI_COMMAND_MEMORY)) {
>                 cmd |= PCI_COMMAND_MEMORY;
> @@ -325,7 +321,7 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
>         dev->fw_features = features;
>         dev->hif_ops = &mt7921_pcie_ops;
>         dev->irq_map = &irq_map;
> -       mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]);
> +       mt76_mmio_init(&dev->mt76, pcim_iomap_region(pdev, 0, pci_name(pdev)));

You are effectively removing the error checking by directly passing
the result of pcim_iomap_region() to mt76_mmio_init(). You need to
first make sure that pcim_iomap_region() succeeded.

Best regards,
Jonas


From xieyuanbin1 at huawei.com  Mon Dec  8 07:08:40 2025
From: xieyuanbin1 at huawei.com (Xie Yuanbin)
Date: Mon, 8 Dec 2025 23:08:40 +0800
Subject: [PATCH 0/3] ARM: fix hash_name() and branch predictor issues
In-Reply-To: <aTbF009476Iufory@shell.armlinux.org.uk>
References: <aTbF009476Iufory@shell.armlinux.org.uk>
Message-ID: <20251208150840.92209-1-xieyuanbin1@huawei.com>

On Mon, 8 Dec 2025 12:34:27 +0000, Russell King wrote:
> The first patch adds an additional check in __do_kernel_fault() to
> detect this condition. This patch is a non-obvious dependency for the
> next patch.
>
> The second patch handles faults above the top of userspace entirely
> separately, meaning we have a simpler and more obvious fault path,
> which avoids any possibility of taking any MM mutexes, which is the
> cause of the hash_name() problem.
>
> The third patch moves harden_branch_predictor() out of
> __do_user_fault() and to appropriate places in the parent functions.
> The reason this has been avoided thus far is because do_page_fault()
> can be a hot path (since it's used for page aging as well) but with
> kernel address faults being handled by an entirely separate path,
> this avoids adding to that overhead.

I don't have any objections to the first and second patches. However,
for the third patch, I feel it complicates some things. It removes
harden_branch_predictor() from __do_user_fault() and adds it to various
previous calling points.

This seems to be solely for adapting to the scenario of do_alignment() &&
user_mode(regs) && addr >= TASK_SIZE. Does this scenario really exist?
Again, in your last email, you described it as follows:
On Fri, 5 Dec 2025 12:08:14 +0000, Russell King wrote:
> Also tested usermode access to kernel space
> which fails with SEGV:
> - read from 0xc0000000 (section permission fault, do_sect_fault)
> - read from 0xffff2000 (page translation fault, do_page_fault)
> - read from 0xffff0000 (vectors page - read possible as expected)
> - write to 0xffff0000 (page permission fault, do_page_fault)

In other words, if there is a BUG_ON():
```patch
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
index 3c6ddb1afdc4..d61c5adc7f96 100644
--- a/arch/arm/mm/alignment.c
+++ b/arch/arm/mm/alignment.c
@@ -833,10 +833,12 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 		}
 	} else {
 		fault = alignment_get_arm(regs, (void *)instrptr, &instr);
 	}
 
+	BUG_ON(user_mode(regs) && !fault && addr >= TASK_SIZE);
+
 	if (fault) {
 		type = TYPE_FAULT;
 		goto bad_or_fault;
 	}
```
Could this BUG_ON() be triggered?

If the answer is "no," then I think that something this may be enough:
```patch
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
index 3c6ddb1afdc4..03aa2cff8c16 100644
--- a/arch/arm/mm/alignment.c
+++ b/arch/arm/mm/alignment.c
@@ -809,6 +809,9 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 	int thumb2_32b = 0;
 	int fault;

+	if (unlikely(addr >= TASK_SIZE && user_mode(regs)))
+		return do_kernel_address_page_fault(current->mm, addr, fsr, regs);
+
 	if (interrupts_enabled(regs))
 		local_irq_enable();

```
And just keep harden_branch_predictor() stay in __do_user_fault().

If I have misunderstood anything, please point it out. Thanks very much.


From Sascha.Bischoff at arm.com  Mon Dec  8 07:28:23 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Mon, 8 Dec 2025 15:28:23 +0000
Subject: [PATCH 2/2] KVM: arm64: Correct test for ICH_HCR_EL2_TDIR cap for
 GICv5 hosts
In-Reply-To: <20251208152724.3637157-1-sascha.bischoff@arm.com>
References: <20251208152724.3637157-1-sascha.bischoff@arm.com>
Message-ID: <20251208152724.3637157-4-sascha.bischoff@arm.com>

The original order of checks in the ICH_HCR_EL2_TDIR test returned
with false early in the case where the native GICv3 CPUIF was not
present. The result was that on GICv5 hosts with legacy support -
which do not have the GICv3 CPUIF - the test always returned false.

Reshuffle the checks such that support for GICv5 legacy is checked
prior to checking for the native GICv3 CPUIF.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
Fixes: 2a28810cbb8b2 ("KVM: arm64: GICv3: Detect and work around the lack of ICV_DIR_EL1 trapping")
---
 arch/arm64/kernel/cpufeature.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index d34dcc5630865..fb5665c6cea01 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -2325,16 +2325,16 @@ static bool can_trap_icv_dir_el1(const struct arm64_cpu_capabilities *entry,
 
 	BUILD_BUG_ON(ARM64_HAS_ICH_HCR_EL2_TDIR <= ARM64_HAS_GICV3_CPUIF);
 	BUILD_BUG_ON(ARM64_HAS_ICH_HCR_EL2_TDIR <= ARM64_HAS_GICV5_LEGACY);
-	if (!this_cpu_has_cap(ARM64_HAS_GICV3_CPUIF) &&
-	    !is_midr_in_range_list(has_vgic_v3))
-		return false;
-
 	if (!is_hyp_mode_available())
 		return false;
 
 	if (this_cpu_has_cap(ARM64_HAS_GICV5_LEGACY))
 		return true;
 
+	if (!this_cpu_has_cap(ARM64_HAS_GICV3_CPUIF) &&
+	    !is_midr_in_range_list(has_vgic_v3))
+		return false;
+
 	if (is_kernel_in_hyp_mode())
 		res.a1 = read_sysreg_s(SYS_ICH_VTR_EL2);
 	else
-- 
2.34.1


From Sascha.Bischoff at arm.com  Mon Dec  8 07:28:22 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Mon, 8 Dec 2025 15:28:22 +0000
Subject: [PATCH 1/2] KVM: arm64: gic: Enable GICv3 CPUIF trapping on GICv5
 hosts if required
In-Reply-To: <20251208152724.3637157-1-sascha.bischoff@arm.com>
References: <20251208152724.3637157-1-sascha.bischoff@arm.com>
Message-ID: <20251208152724.3637157-3-sascha.bischoff@arm.com>

Factor out the enable (and printing of) the GICv3 CPUIF traps from the
main GICv3 probe into a separate function. Call said function from the
GICv5 probe for legacy support, ensuring that any required GICv3 CPUIF
traps on GICv5 hosts will be correctly handled, rather than injecting
an undef into the guest.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/vgic/vgic-v3.c | 25 +++++++++++++++----------
 arch/arm64/kvm/vgic/vgic-v5.c |  2 ++
 arch/arm64/kvm/vgic/vgic.h    |  1 +
 3 files changed, 18 insertions(+), 10 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic-v3.c b/arch/arm64/kvm/vgic/vgic-v3.c
index 968aa9d89be63..b06c72cd933de 100644
--- a/arch/arm64/kvm/vgic/vgic-v3.c
+++ b/arch/arm64/kvm/vgic/vgic-v3.c
@@ -879,6 +879,20 @@ void noinstr kvm_compute_ich_hcr_trap_bits(struct alt_instr *alt,
 	*updptr = cpu_to_le32(insn);
 }
 
+void vgic_v3_enable_cpuif_traps(void)
+{
+	u64 traps = vgic_ich_hcr_trap_bits();
+
+	if (traps) {
+		kvm_info("GICv3 sysreg trapping enabled ([%s%s%s%s], reduced performance)\n",
+			 (traps & ICH_HCR_EL2_TALL0) ? "G0" : "",
+			 (traps & ICH_HCR_EL2_TALL1) ? "G1" : "",
+			 (traps & ICH_HCR_EL2_TC)    ? "C"  : "",
+			 (traps & ICH_HCR_EL2_TDIR)  ? "D"  : "");
+		static_branch_enable(&vgic_v3_cpuif_trap);
+	}
+}
+
 /**
  * vgic_v3_probe - probe for a VGICv3 compatible interrupt controller
  * @info:	pointer to the GIC description
@@ -890,7 +904,6 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
 {
 	u64 ich_vtr_el2 = kvm_call_hyp_ret(__vgic_v3_get_gic_config);
 	bool has_v2;
-	u64 traps;
 	int ret;
 
 	has_v2 = ich_vtr_el2 >> 63;
@@ -954,15 +967,7 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
 		kvm_vgic_global_state.ich_vtr_el2 &= ~ICH_VTR_EL2_SEIS;
 	}
 
-	traps = vgic_ich_hcr_trap_bits();
-	if (traps) {
-		kvm_info("GICv3 sysreg trapping enabled ([%s%s%s%s], reduced performance)\n",
-			 (traps & ICH_HCR_EL2_TALL0) ? "G0" : "",
-			 (traps & ICH_HCR_EL2_TALL1) ? "G1" : "",
-			 (traps & ICH_HCR_EL2_TC)    ? "C"  : "",
-			 (traps & ICH_HCR_EL2_TDIR)  ? "D"  : "");
-		static_branch_enable(&vgic_v3_cpuif_trap);
-	}
+	vgic_v3_enable_cpuif_traps();
 
 	kvm_vgic_global_state.vctrl_base = NULL;
 	kvm_vgic_global_state.type = VGIC_V3;
diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index 2d3811f4e1174..331651087e2c7 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -48,5 +48,7 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
 	static_branch_enable(&kvm_vgic_global_state.gicv3_cpuif);
 	kvm_info("GCIE legacy system register CPU interface\n");
 
+	vgic_v3_enable_cpuif_traps();
+
 	return 0;
 }
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index 5f0fc96b4dc29..c9b3bb07e483c 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -324,6 +324,7 @@ void vgic_v3_configure_hcr(struct kvm_vcpu *vcpu, struct ap_list_summary *als);
 void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v3_reset(struct kvm_vcpu *vcpu);
+void vgic_v3_enable_cpuif_traps(void);
 int vgic_v3_probe(const struct gic_kvm_info *info);
 int vgic_v3_map_resources(struct kvm *kvm);
 int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq);
-- 
2.34.1


From Sascha.Bischoff at arm.com  Mon Dec  8 07:28:22 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Mon, 8 Dec 2025 15:28:22 +0000
Subject: [PATCH 0/2] Enable GICv5 Legacy CPUIF trapping & fix TDIR cap test
In-Reply-To: <20251208152724.3637157-1-sascha.bischoff@arm.com>
References: <20251208152724.3637157-1-sascha.bischoff@arm.com>
Message-ID: <20251208152724.3637157-2-sascha.bischoff@arm.com>

These changes address two trapping-related issues when running legacy
(i.e. GICv3) guests on GICv5 hosts.

The first change enables the vgic_v3_cpuif_trap static branch on GICv5
hosts with legacy support, if trapping is required. The missing enable
was caught as part of debugging why UNDEFs were being injected into
guests when the ICH_HCR_EL2.TC bit was set - the expected bahaviour
was that KVM should handle the trapped accesses, with the guest
remaining blissfully unaware.

The second change fixes the specific cause of the TC bit being set in
the first place. The test for the ICH_HCR_EL2_TDIR cap was checking
for GICv3 CPUIF support and returning false prior to checking for
GICv5 Legacy support. The result was that on GICv5 hosts, the test
always returned false, and therefore the TC bit was being set. The
issue is fixed by reordering the checks to check for GICv5 Legacy
support first.

These changes are based against kvmarm/next.

Thanks,
Sascha

Sascha Bischoff (2):
  KVM: arm64: gic: Enable GICv3 CPUIF trapping on GICv5 hosts if
    required
  KVM: arm64: Correct test for ICH_HCR_EL2_TDIR cap for GICv5 hosts

 arch/arm64/kernel/cpufeature.c |  8 ++++----
 arch/arm64/kvm/vgic/vgic-v3.c  | 25 +++++++++++++++----------
 arch/arm64/kvm/vgic/vgic-v5.c  |  2 ++
 arch/arm64/kvm/vgic/vgic.h     |  1 +
 4 files changed, 22 insertions(+), 14 deletions(-)

--
2.34.1

From Sascha.Bischoff at arm.com  Mon Dec  8 07:28:22 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Mon, 8 Dec 2025 15:28:22 +0000
Subject: [PATCH 0/2] Enable GICv5 Legacy CPUIF trapping & fix TDIR cap test
Message-ID: <20251208152724.3637157-1-sascha.bischoff@arm.com>

These changes address two trapping-related issues when running legacy
(i.e. GICv3) guests on GICv5 hosts.

The first change enables the vgic_v3_cpuif_trap static branch on GICv5
hosts with legacy support, if trapping is required. The missing enable
was caught as part of debugging why UNDEFs were being injected into
guests when the ICH_HCR_EL2.TC bit was set - the expected bahaviour
was that KVM should handle the trapped accesses, with the guest
remaining blissfully unaware.

The second change fixes the specific cause of the TC bit being set in
the first place. The test for the ICH_HCR_EL2_TDIR cap was checking
for GICv3 CPUIF support and returning false prior to checking for
GICv5 Legacy support. The result was that on GICv5 hosts, the test
always returned false, and therefore the TC bit was being set. The
issue is fixed by reordering the checks to check for GICv5 Legacy
support first.

These changes are based against kvmarm/next.

Thanks,
Sascha

Sascha Bischoff (2):
  KVM: arm64: gic: Enable GICv3 CPUIF trapping on GICv5 hosts if
    required
  KVM: arm64: Correct test for ICH_HCR_EL2_TDIR cap for GICv5 hosts

 arch/arm64/kernel/cpufeature.c |  8 ++++----
 arch/arm64/kvm/vgic/vgic-v3.c  | 25 +++++++++++++++----------
 arch/arm64/kvm/vgic/vgic-v5.c  |  2 ++
 arch/arm64/kvm/vgic/vgic.h     |  1 +
 4 files changed, 22 insertions(+), 14 deletions(-)

--
2.34.1

From Frank.li at nxp.com  Mon Dec  8 07:32:46 2025
From: Frank.li at nxp.com (Frank Li)
Date: Mon, 8 Dec 2025 10:32:46 -0500
Subject: [PATCH] pmdomain: imx: Fix reference count leak in
 imx_gpc_probe()
In-Reply-To: <20251208094242.17821-1-vulab@iscas.ac.cn>
References: <20251208094242.17821-1-vulab@iscas.ac.cn>
Message-ID: <aTbvntH908diTJ9U@lizhi-Precision-Tower-5810>

On Mon, Dec 08, 2025 at 09:42:42AM +0000, Wentao Liang wrote:
> of_get_child_by_name() returns a node pointer with refcount incremented,
> we should use of_node_put() on it when not needed anymore. Add missing
> of_node_put() calls in imx_gpc_probe() to avoid reference count leak.
>
> This commit fixes the following issues:
> 1. Add of_node_put(pgc_node) before returning from imx_gpc_probe()
> 2. Use goto pattern to consolidate error handling
>
> Fixes: 721cabf6c660 ("soc: imx: move PGC handling to a new GPC driver")
> Cc: stable at vger.kernel.org
> Signed-off-by: Wentao Liang <vulab at iscas.ac.cn>
> ---
>  drivers/pmdomain/imx/gpc.c | 31 +++++++++++++++++++++----------
>  1 file changed, 21 insertions(+), 10 deletions(-)


Just need one line change

struct device_node *pgc_node __free(pgc_node) pgc_node =
	of_get_child_by_name(pdev->dev.of_node, "pgc");


Frank

>
> diff --git a/drivers/pmdomain/imx/gpc.c b/drivers/pmdomain/imx/gpc.c
> index f18c7e6e75dd..754c60effc8a 100644
> --- a/drivers/pmdomain/imx/gpc.c
> +++ b/drivers/pmdomain/imx/gpc.c
> @@ -416,8 +416,10 @@ static int imx_gpc_probe(struct platform_device *pdev)
>  		return 0;
>
>  	base = devm_platform_ioremap_resource(pdev, 0);
> -	if (IS_ERR(base))
> -		return PTR_ERR(base);
> +	if (IS_ERR(base)) {
> +		ret = PTR_ERR(base);
> +		goto err_free;
> +	}
>
>  	regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL, base,
>  					   &imx_gpc_regmap_config);
> @@ -425,7 +427,7 @@ static int imx_gpc_probe(struct platform_device *pdev)
>  		ret = PTR_ERR(regmap);
>  		dev_err(&pdev->dev, "failed to init regmap: %d\n",
>  			ret);
> -		return ret;
> +		goto err_free;
>  	}
>
>  	/*
> @@ -460,29 +462,33 @@ static int imx_gpc_probe(struct platform_device *pdev)
>  		int domain_index;
>
>  		ipg_clk = devm_clk_get(&pdev->dev, "ipg");
> -		if (IS_ERR(ipg_clk))
> -			return PTR_ERR(ipg_clk);
> +		if (IS_ERR(ipg_clk)) {
> +			ret = PTR_ERR(ipg_clk);
> +			goto err_free;
> +		}
>  		ipg_rate_mhz = clk_get_rate(ipg_clk) / 1000000;
>
>  		for_each_child_of_node_scoped(pgc_node, np) {
>  			ret = of_property_read_u32(np, "reg", &domain_index);
>  			if (ret)
> -				return ret;
> +				goto err_free;
>
>  			if (domain_index >= of_id_data->num_domains)
>  				continue;
>
>  			pd_pdev = platform_device_alloc("imx-pgc-power-domain",
>  							domain_index);
> -			if (!pd_pdev)
> -				return -ENOMEM;
> +			if (!pd_pdev) {
> +				ret = -ENOMEM;
> +				goto err_free;
> +			}
>
>  			ret = platform_device_add_data(pd_pdev,
>  						       &imx_gpc_domains[domain_index],
>  						       sizeof(imx_gpc_domains[domain_index]));
>  			if (ret) {
>  				platform_device_put(pd_pdev);
> -				return ret;
> +				goto err_free;
>  			}
>  			domain = pd_pdev->dev.platform_data;
>  			domain->regmap = regmap;
> @@ -495,12 +501,17 @@ static int imx_gpc_probe(struct platform_device *pdev)
>  			ret = platform_device_add(pd_pdev);
>  			if (ret) {
>  				platform_device_put(pd_pdev);
> -				return ret;
> +				goto err_free;
>  			}
>  		}
>  	}
>
> +	of_node_put(pgc_node);
>  	return 0;
> +
> +err_free:
> +	of_node_put(pgc_node);
> +	return ret;
>  }
>
>  static void imx_gpc_remove(struct platform_device *pdev)
> --
> 2.34.1
>


From Markus.Elfring at web.de  Mon Dec  8 07:35:51 2025
From: Markus.Elfring at web.de (Markus Elfring)
Date: Mon, 8 Dec 2025 16:35:51 +0100
Subject: [PATCH] pmdomain: imx: Fix reference count leak in
 imx_gpc_probe()
In-Reply-To: <20251208094242.17821-1-vulab@iscas.ac.cn>
References: <20251208094242.17821-1-vulab@iscas.ac.cn>
Message-ID: <eaee9a11-bf8b-4f83-ac92-1d3a32eeb240@web.de>

?
> @@ -495,12 +501,17 @@ static int imx_gpc_probe(struct platform_device *pdev)
?
>  	}
>  
> +	of_node_put(pgc_node);
>  	return 0;
> +

A duplicate statement can be avoided here.

	ret = 0;


> +err_free:
> +	of_node_put(pgc_node);
> +	return ret;
>  }


Regards,
Markus


From peterz at infradead.org  Mon Dec  8 07:37:38 2025
From: peterz at infradead.org (Peter Zijlstra)
Date: Mon, 8 Dec 2025 16:37:38 +0100
Subject: [PATCH v6 00/44] KVM: x86: Add support for mediated vPMUs
In-Reply-To: <20251206001720.468579-1-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
Message-ID: <20251208153738.GC3707837@noisy.programming.kicks-ass.net>

On Fri, Dec 05, 2025 at 04:16:36PM -0800, Sean Christopherson wrote:
> My hope/plan is that the perf changes will go through the tip tree with a
> stable tag/branch, and the KVM changes will go the kvm-x86 tree.

> Kan Liang (7):
>   perf: Skip pmu_ctx based on event_type
>   perf: Add generic exclude_guest support
>   perf: Add APIs to create/release mediated guest vPMUs
>   perf: Clean up perf ctx time
>   perf: Add a EVENT_GUEST flag
>   perf: Add APIs to load/put guest mediated PMU context
>   perf/x86/intel: Support PERF_PMU_CAP_MEDIATED_VPMU
> 
> Mingwei Zhang (3):
>   perf/x86/core: Plumb mediated PMU capability from x86_pmu to
>     x86_pmu_cap
>
> Sandipan Das (3):
>   perf/x86/core: Do not set bit width for unavailable counters
>   perf/x86/amd: Support PERF_PMU_CAP_MEDIATED_VPMU for AMD host
> 
> Sean Christopherson (19):
>   perf: Move security_perf_event_free() call to __free_event()
>   perf/x86/core: Register a new vector for handling mediated guest PMIs
>   perf/x86/core: Add APIs to switch to/from mediated PMI vector (for
>     KVM)

That all looks to be in decent shape; lets go get this merged. There is
the nit on patch 4 and I think a number of the exports want to be
EXPORT_SYMBOL_FOR_KVM() instead, but we can do that on top.

I'll queue these patches after rc1.


From linux at armlinux.org.uk  Mon Dec  8 07:43:56 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 8 Dec 2025 15:43:56 +0000
Subject: [Bug report] hash_name() may cross page boundary and trigger
 sleep in RCU context
In-Reply-To: <20251208131842.76909-1-xieyuanbin1@huawei.com>
References: <aTajXdAVYh9qJI6B@shell.armlinux.org.uk>
 <20251208131842.76909-1-xieyuanbin1@huawei.com>
Message-ID: <aTbyPNINxjzU3Lua@shell.armlinux.org.uk>

On Mon, Dec 08, 2025 at 09:18:42PM +0800, Xie Yuanbin wrote:
> On Mon, 8 Dec 2025 10:07:25 +0000, Russell King wrote:
> > This isn't entirely fixed. A data abort for an alignment fault (thus
> > calling do_alignment()) will enable interrupts, and then may call
> > do_bad_area(). We can't short-circuit this path like we can with
> > do_page_fault() as alignment faults from userspace can be valid for
> > the vectors page - not that we should see them, but that doesn't mean
> > that there isn't something in userspace that does.
> 
> I had indeed been lacking in consideration regarding do_alignment()
> before, so thank you for reply. But, may I ask that, is there a scenario
> where user-mode access to kernel addresses causes an alignment fault
> (do_alignment())?

If you mean, won't permission errors be detected first, then no.
Alignment is one of the first things that is checked if alignment
faults are enabled.

So yes, if userspace attempts an unaigned load of a kernel address,
and the CPU does not support / have enabled unaigned load support,
then we will get a data abort with the FSR indicating an alignment
fault. So do_alignment() wil be entered.

Whether branch predictor handling needs to happen in this path is
a separate question, but as it's highly likely we'll take an
exception anyway and userspace is doing Bad Stuff, I feel it's
better to be over-cautious.

> In your last email, you described it as follows:
> On Fri, 5 Dec 2025 12:08:14 +0000, Russell King wrote:
> > Also tested usermode access to kernel space
> > which fails with SEGV:
> > - read from 0xc0000000 (section permission fault, do_sect_fault)
> > - read from 0xffff2000 (page translation fault, do_page_fault)
> > - read from 0xffff0000 (vectors page - read possible as expected)
> > - write to 0xffff0000 (page permission fault, do_page_fault)
> 
> There seems to be no do_alignment()?

Yes, I didn't test this case, because I was only concentrating on
the effects of the proposed patch which did not include moving the
branch predictor handling.

> In other words, is there a way to construct a user-mode testcase which
> accesses a kernel address and triggers do_alignment()?

Testing these mitigations is very difficult as there's no public
test cases for ARM.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From devnull+yassine.ouaissa.allegrodvt.com at kernel.org  Mon Dec  8 07:49:16 2025
From: devnull+yassine.ouaissa.allegrodvt.com at kernel.org (Yassine Ouaissa via B4 Relay)
Date: Mon, 08 Dec 2025 16:49:16 +0100
Subject: [PATCH RESEND v6 1/4] media: allegro-dvt: Move the current driver
 to a subdirectory
In-Reply-To: <20251208-allegro_dvt_al300_dec_driver-v6-0-128956555677@allegrodvt.com>
References: <20251208-allegro_dvt_al300_dec_driver-v6-0-128956555677@allegrodvt.com>
Message-ID: <20251208-allegro_dvt_al300_dec_driver-v6-1-128956555677@allegrodvt.com>

From: Yassine Ouaissa <yassine.ouaissa at allegrodvt.com>

In preparation for the upcoming driver update, we need to relocate the
current driver.
This will help ensure a clean transition and avoid any potential
conflicts with the new driver.
This patch is crucial for keeping our directory organized and
facilitating a smooth integration of the new driver.

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Signed-off-by: Yassine Ouaissa <yassine.ouaissa at allegrodvt.com>
---
 MAINTAINERS                                             |  2 +-
 drivers/media/platform/allegro-dvt/Kconfig              | 16 +---------------
 drivers/media/platform/allegro-dvt/Makefile             |  5 +----
 drivers/media/platform/allegro-dvt/zynqmp/Kconfig       | 17 +++++++++++++++++
 drivers/media/platform/allegro-dvt/zynqmp/Makefile      |  6 ++++++
 .../platform/allegro-dvt/{ => zynqmp}/allegro-core.c    |  0
 .../platform/allegro-dvt/{ => zynqmp}/allegro-mail.c    |  0
 .../platform/allegro-dvt/{ => zynqmp}/allegro-mail.h    |  0
 .../media/platform/allegro-dvt/{ => zynqmp}/nal-h264.c  |  0
 .../media/platform/allegro-dvt/{ => zynqmp}/nal-h264.h  |  0
 .../media/platform/allegro-dvt/{ => zynqmp}/nal-hevc.c  |  0
 .../media/platform/allegro-dvt/{ => zynqmp}/nal-hevc.h  |  0
 .../media/platform/allegro-dvt/{ => zynqmp}/nal-rbsp.c  |  0
 .../media/platform/allegro-dvt/{ => zynqmp}/nal-rbsp.h  |  0
 14 files changed, 26 insertions(+), 20 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index d701a4d5b00e..dc56841fa5e5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -838,7 +838,7 @@ R:	Pengutronix Kernel Team <kernel at pengutronix.de>
 L:	linux-media at vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/media/allegro,al5e.yaml
-F:	drivers/media/platform/allegro-dvt/
+F:	drivers/media/platform/allegro-dvt/zynqmp
 
 ALLIED VISION ALVIUM CAMERA DRIVER
 M:	Tommaso Merciai <tomm.merciai at gmail.com>
diff --git a/drivers/media/platform/allegro-dvt/Kconfig b/drivers/media/platform/allegro-dvt/Kconfig
index 2182e1277568..e9008614c27b 100644
--- a/drivers/media/platform/allegro-dvt/Kconfig
+++ b/drivers/media/platform/allegro-dvt/Kconfig
@@ -2,18 +2,4 @@
 
 comment "Allegro DVT media platform drivers"
 
-config VIDEO_ALLEGRO_DVT
-	tristate "Allegro DVT Video IP Core"
-	depends on V4L_MEM2MEM_DRIVERS
-	depends on VIDEO_DEV
-	depends on ARCH_ZYNQMP || COMPILE_TEST
-	select V4L2_MEM2MEM_DEV
-	select VIDEOBUF2_DMA_CONTIG
-	select REGMAP_MMIO
-	help
-	  Support for the encoder video IP core by Allegro DVT. This core is
-	  found for example on the Xilinx ZynqMP SoC in the EV family and is
-	  called VCU in the reference manual.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called allegro.
+source "drivers/media/platform/allegro-dvt/zynqmp/Kconfig"
diff --git a/drivers/media/platform/allegro-dvt/Makefile b/drivers/media/platform/allegro-dvt/Makefile
index 66108a303774..d2aa6875edcf 100644
--- a/drivers/media/platform/allegro-dvt/Makefile
+++ b/drivers/media/platform/allegro-dvt/Makefile
@@ -1,6 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0
 
-allegro-objs := allegro-core.o allegro-mail.o
-allegro-objs += nal-rbsp.o nal-h264.o nal-hevc.o
-
-obj-$(CONFIG_VIDEO_ALLEGRO_DVT) += allegro.o
+obj-y += zynqmp/
diff --git a/drivers/media/platform/allegro-dvt/zynqmp/Kconfig b/drivers/media/platform/allegro-dvt/zynqmp/Kconfig
new file mode 100644
index 000000000000..0a0a697c420d
--- /dev/null
+++ b/drivers/media/platform/allegro-dvt/zynqmp/Kconfig
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config VIDEO_ALLEGRO_DVT
+	tristate "Allegro DVT Video IP Core for ZynqMP"
+	depends on V4L_MEM2MEM_DRIVERS
+	depends on VIDEO_DEV
+	depends on ARCH_ZYNQMP || COMPILE_TEST
+	select V4L2_MEM2MEM_DEV
+	select VIDEOBUF2_DMA_CONTIG
+	select REGMAP_MMIO
+	help
+	  Support for the encoder video IP core by Allegro DVT. This core is
+	  found for example on the Xilinx ZynqMP SoC in the EV family and is
+	  called VCU in the reference manual.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called allegro.
diff --git a/drivers/media/platform/allegro-dvt/zynqmp/Makefile b/drivers/media/platform/allegro-dvt/zynqmp/Makefile
new file mode 100644
index 000000000000..66108a303774
--- /dev/null
+++ b/drivers/media/platform/allegro-dvt/zynqmp/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+
+allegro-objs := allegro-core.o allegro-mail.o
+allegro-objs += nal-rbsp.o nal-h264.o nal-hevc.o
+
+obj-$(CONFIG_VIDEO_ALLEGRO_DVT) += allegro.o
diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/zynqmp/allegro-core.c
similarity index 100%
rename from drivers/media/platform/allegro-dvt/allegro-core.c
rename to drivers/media/platform/allegro-dvt/zynqmp/allegro-core.c
diff --git a/drivers/media/platform/allegro-dvt/allegro-mail.c b/drivers/media/platform/allegro-dvt/zynqmp/allegro-mail.c
similarity index 100%
rename from drivers/media/platform/allegro-dvt/allegro-mail.c
rename to drivers/media/platform/allegro-dvt/zynqmp/allegro-mail.c
diff --git a/drivers/media/platform/allegro-dvt/allegro-mail.h b/drivers/media/platform/allegro-dvt/zynqmp/allegro-mail.h
similarity index 100%
rename from drivers/media/platform/allegro-dvt/allegro-mail.h
rename to drivers/media/platform/allegro-dvt/zynqmp/allegro-mail.h
diff --git a/drivers/media/platform/allegro-dvt/nal-h264.c b/drivers/media/platform/allegro-dvt/zynqmp/nal-h264.c
similarity index 100%
rename from drivers/media/platform/allegro-dvt/nal-h264.c
rename to drivers/media/platform/allegro-dvt/zynqmp/nal-h264.c
diff --git a/drivers/media/platform/allegro-dvt/nal-h264.h b/drivers/media/platform/allegro-dvt/zynqmp/nal-h264.h
similarity index 100%
rename from drivers/media/platform/allegro-dvt/nal-h264.h
rename to drivers/media/platform/allegro-dvt/zynqmp/nal-h264.h
diff --git a/drivers/media/platform/allegro-dvt/nal-hevc.c b/drivers/media/platform/allegro-dvt/zynqmp/nal-hevc.c
similarity index 100%
rename from drivers/media/platform/allegro-dvt/nal-hevc.c
rename to drivers/media/platform/allegro-dvt/zynqmp/nal-hevc.c
diff --git a/drivers/media/platform/allegro-dvt/nal-hevc.h b/drivers/media/platform/allegro-dvt/zynqmp/nal-hevc.h
similarity index 100%
rename from drivers/media/platform/allegro-dvt/nal-hevc.h
rename to drivers/media/platform/allegro-dvt/zynqmp/nal-hevc.h
diff --git a/drivers/media/platform/allegro-dvt/nal-rbsp.c b/drivers/media/platform/allegro-dvt/zynqmp/nal-rbsp.c
similarity index 100%
rename from drivers/media/platform/allegro-dvt/nal-rbsp.c
rename to drivers/media/platform/allegro-dvt/zynqmp/nal-rbsp.c
diff --git a/drivers/media/platform/allegro-dvt/nal-rbsp.h b/drivers/media/platform/allegro-dvt/zynqmp/nal-rbsp.h
similarity index 100%
rename from drivers/media/platform/allegro-dvt/nal-rbsp.h
rename to drivers/media/platform/allegro-dvt/zynqmp/nal-rbsp.h

-- 
2.50.1




From devnull+yassine.ouaissa.allegrodvt.com at kernel.org  Mon Dec  8 07:49:18 2025
From: devnull+yassine.ouaissa.allegrodvt.com at kernel.org (Yassine Ouaissa via B4 Relay)
Date: Mon, 08 Dec 2025 16:49:18 +0100
Subject: [PATCH RESEND v6 3/4] dt-bindings: vendor-prefixes: Update the
 description of allegro prefix
In-Reply-To: <20251208-allegro_dvt_al300_dec_driver-v6-0-128956555677@allegrodvt.com>
References: <20251208-allegro_dvt_al300_dec_driver-v6-0-128956555677@allegrodvt.com>
Message-ID: <20251208-allegro_dvt_al300_dec_driver-v6-3-128956555677@allegrodvt.com>

From: Yassine Ouaissa <yassine.ouaissa at allegrodvt.com>

Add SAS (Soci?t? par actions simplifi?e) to the allegro of vendor
prefixe description to include French simplified joint-stock company
legal structure.

Acked-by: Conor Dooley <conor.dooley at microchip.com>
Signed-off-by: Yassine Ouaissa <yassine.ouaissa at allegrodvt.com>
---
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index c7591b2aec2a..8376312dd9e4 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -87,7 +87,7 @@ patternProperties:
   "^alfa-network,.*":
     description: ALFA Network Inc.
   "^allegro,.*":
-    description: Allegro DVT
+    description: Allegro DVT, SAS.
   "^allegromicro,.*":
     description: Allegro MicroSystems, Inc.
   "^alliedtelesis,.*":

-- 
2.50.1




From devnull+yassine.ouaissa.allegrodvt.com at kernel.org  Mon Dec  8 07:49:17 2025
From: devnull+yassine.ouaissa.allegrodvt.com at kernel.org (Yassine Ouaissa via B4 Relay)
Date: Mon, 08 Dec 2025 16:49:17 +0100
Subject: [PATCH RESEND v6 2/4] dt-bindings: media: allegro: Add al300
 decoder IPs
In-Reply-To: <20251208-allegro_dvt_al300_dec_driver-v6-0-128956555677@allegrodvt.com>
References: <20251208-allegro_dvt_al300_dec_driver-v6-0-128956555677@allegrodvt.com>
Message-ID: <20251208-allegro_dvt_al300_dec_driver-v6-2-128956555677@allegrodvt.com>

From: Yassine Ouaissa <yassine.ouaissa at allegrodvt.com>

Add a schema for the allegro gen3 video decoder.

Acked-by: Conor Dooley <conor.dooley at microchip.com>
Signed-off-by: Yassine Ouaissa <yassine.ouaissa at allegrodvt.com>
---
 .../bindings/media/allegro,al300-vdec.yaml         | 76 ++++++++++++++++++++++
 MAINTAINERS                                        |  2 +
 2 files changed, 78 insertions(+)

diff --git a/Documentation/devicetree/bindings/media/allegro,al300-vdec.yaml b/Documentation/devicetree/bindings/media/allegro,al300-vdec.yaml
new file mode 100644
index 000000000000..12e86c306d55
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/allegro,al300-vdec.yaml
@@ -0,0 +1,76 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/allegro,al300-vdec.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allegro DVT Video IP Decoder Gen 3
+
+maintainers:
+  - Yassine OUAISSA <yassine.ouaissa at allegrodvt.com>
+
+description:
+  The al300-vdec represents the gen 3 of Allegro DVT IP video
+  decoding technology, offering significant advancements over its
+  predecessors. This new decoder features enhanced processing capabilities
+  with improved throughput and reduced latency.
+
+  Communication between the host driver software and the MCU is implemented
+  through a specialized mailbox interface mechanism. This mailbox system
+  provides a structured channel for exchanging commands, parameters, and
+  status information between the host CPU and the MCU controlling the codec
+  engines.
+
+properties:
+  compatible:
+    const: allegro,al300-vdec
+
+  reg:
+    maxItems: 2
+
+  reg-names:
+    items:
+      - const: top
+      - const: apb
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    description: MCU core clock
+    maxItems: 1
+
+  memory-region:
+    maxItems: 1
+
+  firmware-name:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - interrupts
+  - clocks
+
+additionalProperties: False
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    axi {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        video-decoder at a0120000 {
+            compatible = "allegro,al300-vdec";
+            reg = <0x00 0xa0120000 0x00 0x10000>, /*VDEC_TOP*/
+                  <0x01 0x80000000 0x00 0x8000>;  /*MCU_APB*/
+            reg-names = "top", "apb";
+            interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
+            clocks = <&mcu_core_clk>;
+            memory-region = <&vdec_mem>;
+            firmware-name = "al300_vdec.fw";
+        };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index dc56841fa5e5..67dfc2ee1725 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -837,7 +837,9 @@ M:	Michael Tretter <m.tretter at pengutronix.de>
 R:	Pengutronix Kernel Team <kernel at pengutronix.de>
 L:	linux-media at vger.kernel.org
 S:	Maintained
+F:	Documentation/devicetree/bindings/media/allegro,al300-vdec.yaml
 F:	Documentation/devicetree/bindings/media/allegro,al5e.yaml
+F:	drivers/media/platform/allegro-dvt/al300
 F:	drivers/media/platform/allegro-dvt/zynqmp
 
 ALLIED VISION ALVIUM CAMERA DRIVER

-- 
2.50.1




From devnull+yassine.ouaissa.allegrodvt.com at kernel.org  Mon Dec  8 07:49:15 2025
From: devnull+yassine.ouaissa.allegrodvt.com at kernel.org (Yassine Ouaissa via B4 Relay)
Date: Mon, 08 Dec 2025 16:49:15 +0100
Subject: [PATCH RESEND v6 0/4] media: Add Gen 3 IP stateful decoder driver
Message-ID: <20251208-allegro_dvt_al300_dec_driver-v6-0-128956555677@allegrodvt.com>

This patch series introduces a new stateful decoder driver for the
allegrodvt GEN 3 IPs.

Changes in v6:
- Reset the file->private_data to NULL in v4l2_fh_del()
- Link to v5: https://lore.kernel.org/r/20250813-allegro_dvt_al300_dec_driver-v5-0-a312ddebc4d8 at allegrodvt.com

Changes in v5:
- Fix the include issues.
- Fix the faulty warning, by adding the __maybe_unused attribute to the 'v4l2_al_dec_dt_match'.
- Fix the get_mcu_offset(), the physical address limit is set to the
  flat memory size ( 264GB ).
- Get the mcu physical addresses offset at al_common_setup_dma.
- Link to v4: https://lore.kernel.org/r/20250716-allegro_dvt_al300_dec_driver-v4-0-f87c01c9f7b5 at allegrodvt.com

Changes in v4:
- Use debugfs instead of build time DEBUG (Michael Tretter).
- Add capture and output pixelformats and resolution to the debugfs.
- Support 64-bit of physical addresses, by configuring the mcu data and
  instruction offset registers.
- Link to v3: https://lore.kernel.org/r/20250616-allegro_dvt_al300_dec_driver-v3-0-7d746cb9e5f9 at allegrodvt.com

Changes in v3:
- Remove blank line after description.(Krzysztof Kozlowski)
- Drop minItems on the reg property.(Krzysztof Kozlowski)
- Reword the patch 2 subject and description.(Krzysztof Kozlowski)
- Add the memory-region property to the example.(Krzysztof Kozlowski)
- Rename the reg-name "regs" with top. the first reg is the
  video-decoder top registers.(Krzysztof Kozlowski)
- Link to v2: https://lore.kernel.org/r/20250605-allegro_dvt_al300_dec_driver-v2-0-1ef4839f5f06 at allegrodvt.com

Changes in v2:
- patch 2:
- Change the YAML file name, use the existing vendor-prefix.
- Improuve the dt-bindings description.
- Change the device compatible identifier, from "allegrodvt, al300-vdec",
  to "allegro, al300-vdec"
- Simplify the register property specification,
  by using the simple min/max items constraint (Krzysztof Kozlowski)
- Remove the clock-names property. And remove it from the required
  properties list (Krzysztof Kozlowski) (Conor Dooley)
- Use the simple maxItems constraint for the memory-region property.
  Also for the firmware-name (Krzysztof Kozlowski)
- Example changes:
  - Use header provides definitions for the interrupts (Conor Dooley)
  - Improuve Interrupt specification using GIC constants (Conor Dooley)
  - Use generic node name "video-decoder" (Krzysztof Kozlowski) (Conor Dooley)
  - Remove unused label (Krzysztof Kozlowski)
  - Change clock reference from <&mcu_clock_dec> to <&mcu_core_clk>
  - Use hex format for reg property (Krzysztof Kozlowski) (Conor Dooley)
  - Reduce memory region size (Krzysztof Kozlowski) (Conor Dooley)

- patch 4: Fix code reviews (Nicolas Dufresne)
- MAINTAINERS: Remove my self from the "ALLEGRO DVT VIDEO IP CORE
  DRIVER".
  Link to v1: https://lore.kernel.org/all/20250523134207.68481-1-yassine.ouaissa at allegrodvt.com/

# V4L2 Video Decoder Driver System Description

** Hardware Architecture **

The system implements a heterogeneous computing architecture with two primary components:

- **Host Subsystem**: Linux-based CPU running the V4L2 framework and associated drivers
- **IP Subsystem**: Dedicated hardware containing an MCU and a hardware video CODEC

The communication between the two subsystems uses a shared DDR shared memory with bidirectional interrupt mechanism for synchronization.

The architecture is represented in the following diagram:

```
+---------------------+                  +----------------------+
|       Host          |                  |        IP            |
|                     |                  |                      |
|  +---------------+  |                  |  +----------------+  |
|  |               |  |   DDR Shared     |  |                |  |
|  | Linux Kernel  |<-|----------------->|->|     MCU        |  |
|  | (CPU)         |  |    Memory        |  |                |  |
|  |   +--------+  |  |                  |  +----------------+  |
|  |   |        |  |  |    IRQ when      |           ^          |
|  |   | V4L2   |  |<-|----new message-->|           |          |
|  |   | Drivers|  |  |                  |           |          |
|  |   |        |  |  |                  |           | APB      |
|  |   +--------+  |  |                  |           |          |
|  |               |  |                  |           v          |
|  +---------------+  |                  |  +----------------+  |
|                     |                  |  |                |  |
|                     |                  |  |     CODEC      |  |
|                     |                  |  |                |  |
|                     |                  |  |                |  |
+---------------------+                  +----------------------+
```

** Communication Protocol **

-- Current Implementation - Custom Mailbox --

The host CPU and MCU currently communicate through a custom mailbox protocol implemented over shared memory. The protocol operates as follows:

1. When the host has a new message for the MCU:
   - The host writes data to a dedicated shared memory region
   - The host triggers an interrupt to the MCU
   - The MCU reads the shared memory to obtain the message type and data

2. Similarly, when the MCU has a message for the host:
   - The MCU writes to the shared memory
   - The MCU triggers an interrupt to the host
   - The host reads the shared memory to process the message

-- Migration to RPMSG --

The custom mailbox implementation will be replaced by the standard Linux RPMSG framework.

** Driver Implementation **

This driver implements a V4L2-compliant stateful video decoder with the following characteristics:

-- Technical Specifications --

- **Codec Support**: AVC (H.264), HEVC (H.265), and JPEG
- **Resolution Support**: Up to 4K
- **Pixel Formats**:
  - Currently supported: V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_NV16, V4L2_PIX_FMT_P010
  - Additional formats planned for future releases
- **Buffer Configuration**: Currently supports semi-planar format only; multiplanar support forthcoming

-- Initialization Sequence --

During probe, the driver performs the following operations:

1. Allocates memory for the MCU firmware
2. Loads the firmware into the allocated memory
3. Initializes the MCU by configuring internal registers (e.g BOOT_ADDR)
4. Establishes the shared memory communication interface (to be replaced by RPMSG)
5. Sets up interrupt handlers for MCU communication

-- Processing Model --

The driver implements a stateful decoding model with the following workflow:

-- Stream Initialization --

1. Upon `VIDIOC_STREAMON` on the OUTPUT queue:
   - The driver sends a context creation request to the MCU
   - This operation is blocking; the driver waits until the MCU responds with a context handler
   - The context handler is stored in a driver-maintained list for subsequent operations
   - Each context has its own unique handler to support multiple simultaneous streams

2. Initial stream analysis:
   - The driver submits the first compressed buffer (OUTPUT queue)
   - The MCU analyzes the stream and reports capability via:
     - `resolution_found_event`: Stream is supported, includes stream parameters
     - `error_event`: Stream format is unsupported or invalid

-- Decoding Pipeline --

1. After successful stream initialization and receiving the resolution_found_evt:
   - The driver can begin normal decoding operations
   - V4L2 framework can be informed of format requirements

2. For each compressed buffer (OUTPUT queue):
   - The driver submits buffer to MCU with the appropriate context handler
   - The MCU processes the buffer and sends `release_bitstream_evt` when complete
   - This event signals that the input buffer can be returned to the application

3. For each decoded buffer (CAPTURE queue):
   - The MCU fills the buffer with decoded frame data
   - The MCU sends `frame_buffer_decode_evt` with important metadata including:
     - Original source buffer timestamp
     - Flags
     - Timecode
     - Actual payload size (bytes used in the decoded frame)
   - This enables the driver to properly queue the filled buffer to the application

4. End-of-stream handling:
   - The MCU sends an event with `eos_evt` when reaching the end of stream
   - This allows proper handling of end-of-stream conditions

-- Multi-stream Support --

The driver architecture supports multiple simultaneous decoding contexts with the following characteristics:

1. Each context maintains separate state information
2. The driver manages multiple context handlers returned by the MCU
3. Buffer submissions include the appropriate context handler for routing
4. The system can decode multiple independent streams concurrently

-- Stream Termination --

When `VIDIOC_STREAMOFF` is called:

1. The driver sends a flush command to the MCU for the specific context
2. The driver issues a non-blocking destroy context message
3. All associated resources are released
4. The context handler is removed from the driver's context list

** Error Handling **

The driver implements comprehensive error handling including:

1. Firmware loading failures
2. MCU initialization errors
3. Context creation failures
4. Unsupported stream formats
5. Decoding errors reported by the MCU
6. Timeout handling for unresponsive hardware

** Memory Management **

The system uses the following memory management strategy:

1. Firmware memory is allocated during probe
2. Buffer memory is managed through the V4L2 buffer management interfaces
3. DMA-capable memory is used for buffer transfers between host and MCU
4. The driver properly synchronizes memory access to avoid coherency issues

** Future Enhancements **

Planned future enhancements include:

1. Migration from custom mailbox to RPMSG (in progress)
2. Support for additional pixel formats
3. Implementation of multiplanar buffer support

This comprehensive architecture enables efficient hardware-accelerated video decoding while adhering to standard V4L2 interfaces, making it suitable for upstream inclusion in the Linux kernel.

** Decoder Compliance Testing **

-- AVC and HEVC Fluster Report --

This section contains the compliance test results from Fluster framework for both AVC and HEVC decoders.
The reports validate the decoder's conformance to relevant standards and demonstrate compatibility with a wide range of video streams.

[FLUSTER REPORT FOR THE H.264]
 -- JVT-AVC_V1

| Test                     | FFmpeg-H.264-v4l2m2m |
| ------------------------ | -------------------- |
| TOTAL                    | 79/135               |
| TOTAL TIME               | 437.031s             |
| -                        | -                    |
| AUD_MW_E                 | OK                   |
| BA1_FT_C                 | OK                   |
| BA1_Sony_D               | OK                   |
| BA2_Sony_F               | OK                   |
| BA3_SVA_C                | OK                   |
| BA_MW_D                  | OK                   |
| BAMQ1_JVC_C              | OK                   |
| BAMQ2_JVC_C              | OK                   |
| BANM_MW_D                | OK                   |
| BASQP1_Sony_C            | OK                   |
| CABA1_Sony_D             | OK                   |
| CABA1_SVA_B              | OK                   |
| CABA2_Sony_E             | OK                   |
| CABA2_SVA_B              | OK                   |
| CABA3_Sony_C             | OK                   |
| CABA3_SVA_B              | OK                   |
| CABA3_TOSHIBA_E          | OK                   |
| cabac_mot_fld0_full      | ER                   |
| cabac_mot_frm0_full      | OK                   |
| cabac_mot_mbaff0_full    | ER                   |
| cabac_mot_picaff0_full   | KO                   |
| CABACI3_Sony_B           | OK                   |
| CABAST3_Sony_E           | OK                   |
| CABASTBR3_Sony_B         | OK                   |
| CABREF3_Sand_D           | ER                   |
| CACQP3_Sony_D            | OK                   |
| CAFI1_SVA_C              | ER                   |
| CAMA1_Sony_C             | ER                   |
| CAMA1_TOSHIBA_B          | ER                   |
| cama1_vtc_c              | ER                   |
| cama2_vtc_b              | ER                   |
| CAMA3_Sand_E             | ER                   |
| cama3_vtc_b              | ER                   |
| CAMACI3_Sony_C           | ER                   |
| CAMANL1_TOSHIBA_B        | ER                   |
| CAMANL2_TOSHIBA_B        | ER                   |
| CAMANL3_Sand_E           | ER                   |
| CAMASL3_Sony_B           | ER                   |
| CAMP_MOT_MBAFF_L30       | ER                   |
| CAMP_MOT_MBAFF_L31       | ER                   |
| CANL1_Sony_E             | OK                   |
| CANL1_SVA_B              | OK                   |
| CANL1_TOSHIBA_G          | OK                   |
| CANL2_Sony_E             | OK                   |
| CANL2_SVA_B              | OK                   |
| CANL3_Sony_C             | OK                   |
| CANL3_SVA_B              | OK                   |
| CANL4_SVA_B              | OK                   |
| CANLMA2_Sony_C           | ER                   |
| CANLMA3_Sony_C           | ER                   |
| CAPA1_TOSHIBA_B          | ER                   |
| CAPAMA3_Sand_F           | ER                   |
| CAPCM1_Sand_E            | OK                   |
| CAPCMNL1_Sand_E          | OK                   |
| CAPM3_Sony_D             | OK                   |
| CAQP1_Sony_B             | OK                   |
| cavlc_mot_fld0_full_B    | ER                   |
| cavlc_mot_frm0_full_B    | OK                   |
| cavlc_mot_mbaff0_full_B  | ER                   |
| cavlc_mot_picaff0_full_B | KO                   |
| CAWP1_TOSHIBA_E          | OK                   |
| CAWP5_TOSHIBA_E          | OK                   |
| CI1_FT_B                 | OK                   |
| CI_MW_D                  | OK                   |
| CVBS3_Sony_C             | OK                   |
| CVCANLMA2_Sony_C         | ER                   |
| CVFC1_Sony_C             | OK                   |
| CVFI1_Sony_D             | ER                   |
| CVFI1_SVA_C              | ER                   |
| CVFI2_Sony_H             | ER                   |
| CVFI2_SVA_C              | ER                   |
| CVMA1_Sony_D             | ER                   |
| CVMA1_TOSHIBA_B          | ER                   |
| CVMANL1_TOSHIBA_B        | ER                   |
| CVMANL2_TOSHIBA_B        | ER                   |
| CVMAPAQP3_Sony_E         | ER                   |
| CVMAQP2_Sony_G           | ER                   |
| CVMAQP3_Sony_D           | ER                   |
| CVMP_MOT_FLD_L30_B       | ER                   |
| CVMP_MOT_FRM_L31_B       | ER                   |
| CVNLFI1_Sony_C           | ER                   |
| CVNLFI2_Sony_H           | ER                   |
| CVPA1_TOSHIBA_B          | ER                   |
| CVPCMNL1_SVA_C           | OK                   |
| CVPCMNL2_SVA_C           | OK                   |
| CVSE2_Sony_B             | OK                   |
| CVSE3_Sony_H             | OK                   |
| CVSEFDFT3_Sony_E         | OK                   |
| CVWP1_TOSHIBA_E          | OK                   |
| CVWP2_TOSHIBA_E          | OK                   |
| CVWP3_TOSHIBA_E          | OK                   |
| CVWP5_TOSHIBA_E          | OK                   |
| FI1_Sony_E               | ER                   |
| FM1_BT_B                 | ER                   |
| FM1_FT_E                 | KO                   |
| FM2_SVA_C                | ER                   |
| HCBP1_HHI_A              | OK                   |
| HCBP2_HHI_A              | OK                   |
| HCMP1_HHI_A              | OK                   |
| LS_SVA_D                 | OK                   |
| MIDR_MW_D                | OK                   |
| MPS_MW_A                 | OK                   |
| MR1_BT_A                 | OK                   |
| MR1_MW_A                 | OK                   |
| MR2_MW_A                 | OK                   |
| MR2_TANDBERG_E           | OK                   |
| MR3_TANDBERG_B           | OK                   |
| MR4_TANDBERG_C           | OK                   |
| MR5_TANDBERG_C           | OK                   |
| MR6_BT_B                 | ER                   |
| MR7_BT_B                 | OK                   |
| MR8_BT_B                 | ER                   |
| MR9_BT_B                 | ER                   |
| MV1_BRCM_D               | OK                   |
| NL1_Sony_D               | OK                   |
| NL2_Sony_H               | OK                   |
| NL3_SVA_E                | OK                   |
| NLMQ1_JVC_C              | OK                   |
| NLMQ2_JVC_C              | OK                   |
| NRF_MW_E                 | OK                   |
| Sharp_MP_Field_1_B       | ER                   |
| Sharp_MP_Field_2_B       | ER                   |
| Sharp_MP_Field_3_B       | ER                   |
| Sharp_MP_PAFF_1r2        | ER                   |
| Sharp_MP_PAFF_2r         | ER                   |
| SL1_SVA_B                | OK                   |
| SP1_BT_A                 | ER                   |
| sp2_bt_b                 | ER                   |
| SVA_BA1_B                | OK                   |
| SVA_BA2_D                | OK                   |
| SVA_Base_B               | OK                   |
| SVA_CL1_E                | OK                   |
| SVA_FM1_E                | OK                   |
| SVA_NL1_B                | OK                   |
| SVA_NL2_E                | OK                   |
| -                        | -                    |
| Test                     | FFmpeg-H.264-v4l2m2m |
| TOTAL                    | 79/135               |
| TOTAL TIME               | 439.031s             |

NOTE: The ER (ERROR) streams are not supported by the decoder.
      The driver print error message "Unsupported stream"

- JVT-FR-EXT

| Test                | FFmpeg-H.264-v4l2m2m |
| ------------------- | -------------------- |
| TOTAL               | 23/69                |
| TOTAL TIME          | 182.362s             |
| -                   | -                    |
| alphaconformanceG   | OK                   |
| brcm_freh10         | ER                   |
| brcm_freh11         | ER                   |
| brcm_freh3          | OK                   |
| brcm_freh4          | ER                   |
| brcm_freh5          | ER                   |
| brcm_freh6          | ER                   |
| brcm_freh8          | OK                   |
| brcm_freh9          | OK                   |
| FREH10-1            | ER                   |
| FREH10-2            | ER                   |
| freh12_b            | OK                   |
| freh1_b             | OK                   |
| freh2_b             | OK                   |
| freh7_b             | ER                   |
| FREXT01_JVC_D       | ER                   |
| FREXT02_JVC_C       | ER                   |
| FRExt1_Panasonic_D  | OK                   |
| FREXT1_TANDBERG_A   | ER                   |
| FRExt2_Panasonic_C  | ER                   |
| FREXT2_TANDBERG_A   | ER                   |
| FRExt3_Panasonic_E  | OK                   |
| FREXT3_TANDBERG_A   | ER                   |
| FRExt4_Panasonic_B  | ER                   |
| FRExt_MMCO4_Sony_B  | OK                   |
| HCAFF1_HHI_B        | ER                   |
| HCAFR1_HHI_C        | OK                   |
| HCAFR2_HHI_A        | OK                   |
| HCAFR3_HHI_A        | OK                   |
| HCAFR4_HHI_A        | OK                   |
| HCAMFF1_HHI_B       | ER                   |
| HCHP1_HHI_B         | OK                   |
| HCHP2_HHI_A         | OK                   |
| HCHP3_HHI_A         | ER                   |
| Hi422FR10_SONY_A    | ER                   |
| Hi422FR11_SONY_A    | ER                   |
| Hi422FR12_SONY_A    | ER                   |
| Hi422FR13_SONY_A    | ER                   |
| Hi422FR14_SONY_A    | ER                   |
| Hi422FR15_SONY_A    | ER                   |
| Hi422FR1_SONY_A     | ER                   |
| Hi422FR2_SONY_A     | ER                   |
| Hi422FR3_SONY_A     | ER                   |
| Hi422FR4_SONY_A     | ER                   |
| Hi422FR6_SONY_A     | ER                   |
| Hi422FR7_SONY_A     | ER                   |
| Hi422FR8_SONY_A     | ER                   |
| Hi422FR9_SONY_A     | ER                   |
| Hi422FREXT16_SONY_A | ER                   |
| Hi422FREXT17_SONY_A | ER                   |
| Hi422FREXT18_SONY_A | ER                   |
| Hi422FREXT19_SONY_A | ER                   |
| HPCA_BRCM_C         | OK                   |
| HPCADQ_BRCM_B       | OK                   |
| HPCAFL_BRCM_C       | ER                   |
| HPCAFLNL_BRCM_C     | ER                   |
| HPCALQ_BRCM_B       | OK                   |
| HPCAMAPALQ_BRCM_B   | ER                   |
| HPCAMOLQ_BRCM_B     | ER                   |
| HPCANL_BRCM_C       | OK                   |
| HPCAQ2LQ_BRCM_B     | OK                   |
| HPCV_BRCM_A         | OK                   |
| HPCVFL_BRCM_A       | ER                   |
| HPCVFLNL_BRCM_A     | ER                   |
| HPCVMOLQ_BRCM_B     | ER                   |
| HPCVNL_BRCM_A       | OK                   |
| HVLCFI0_Sony_B      | ER                   |
| HVLCMFF0_Sony_B     | ER                   |
| HVLCPFF0_Sony_B     | ER                   |
| -                   | -                    |
| Test                | FFmpeg-H.264-v4l2m2m |
| TOTAL               | 23/69                |
| TOTAL TIME          | 182.362s             |

NOTE: The ER (ERROR) streams are not supported by the decoder.
      The driver print error message "Unsupported stream"

- JVT-MVC

| Test       | FFmpeg-H.264-v4l2m2m |
| ---------- | -------------------- |
| TOTAL      | 18/20                |
| TOTAL TIME | 147.076s             |
| -          | -                    |
| MVCDS-4    | OK                   |
| MVCDS-5    | OK                   |
| MVCDS-6    | OK                   |
| MVCDS1     | OK                   |
| MVCDS2     | OK                   |
| MVCDS3     | OK                   |
| MVCICT-1   | ER                   |
| MVCICT-2   | ER                   |
| MVCNV-2    | OK                   |
| MVCNV-3    | OK                   |
| MVCNV1     | OK                   |
| MVCNV4     | OK                   |
| MVCRP_1    | OK                   |
| MVCRP_2    | OK                   |
| MVCRP_3    | OK                   |
| MVCRP_4    | OK                   |
| MVCRP_5    | OK                   |
| MVCRP_6    | OK                   |
| MVCSPS-1   | OK                   |
| MVCSPS-2   | OK                   |
| -          | -                    |
| Test       | FFmpeg-H.264-v4l2m2m |
| TOTAL      | 18/20                |
| TOTAL TIME | 147.076s             |

- JVT-SVC

| Test            | FFmpeg-H.264-v4l2m2m |
| --------------- | -------------------- |
| TOTAL           | 75/185               |
| TOTAL TIME      | 727.240s             |
| -               | -                    |
| SVCBC-1-L0      | OK                   |
| SVCBC-1-L1      | KO                   |
| SVCBCT-1-L0     | OK                   |
| SVCBCT-1-L1     | KO                   |
| SVCBCTS-1-r1-L0 | OK                   |
| SVCBCTS-1-r1-L1 | KO                   |
| SVCBCTS-1-r1-L2 | KO                   |
| SVCBCTS-2-r1-L0 | OK                   |
| SVCBCTS-2-r1-L1 | KO                   |
| SVCBCTS-2-r1-L2 | KO                   |
| SVCBCTS-3-L0    | OK                   |
| SVCBCTS-3-L1    | KO                   |
| SVCBCTS-3-L2    | KO                   |
| SVCBM-1-L0      | OK                   |
| SVCBM-1-L1      | KO                   |
| SVCBM-2-L0      | OK                   |
| SVCBM-2-L1      | KO                   |
| SVCBM-3-L0      | OK                   |
| SVCBM-3-L1      | KO                   |
| SVCBM-4-r1-L0   | OK                   |
| SVCBM-4-r1-L1   | KO                   |
| SVCBM-4-r1-L2   | KO                   |
| SVCBM-5-L0      | OK                   |
| SVCBM-5-L1      | KO                   |
| SVCBM-5-L2      | KO                   |
| SVCBM-5-L3      | KO                   |
| SVCBMST-1-L0    | OK                   |
| SVCBMST-1-L1    | KO                   |
| SVCBMST-1-L2    | KO                   |
| SVCBMST-2-L0    | OK                   |
| SVCBMST-2-L1    | KO                   |
| SVCBMST-2-L2    | KO                   |
| SVCBMST-3-L0    | OK                   |
| SVCBMST-3-L1    | KO                   |
| SVCBMST-3-L2    | KO                   |
| SVCBMT-1-L0     | OK                   |
| SVCBMT-1-L1     | KO                   |
| SVCBMT-10-L0    | OK                   |
| SVCBMT-10-L1    | KO                   |
| SVCBMT-11-L0    | OK                   |
| SVCBMT-11-L1    | KO                   |
| SVCBMT-12-L0    | OK                   |
| SVCBMT-12-L1    | KO                   |
| SVCBMT-13-L0    | OK                   |
| SVCBMT-13-L1    | KO                   |
| SVCBMT-13-L2    | KO                   |
| SVCBMT-2-L0     | OK                   |
| SVCBMT-2-L1     | KO                   |
| SVCBMT-3-L0     | OK                   |
| SVCBMT-3-L1     | KO                   |
| SVCBMT-4-L0     | OK                   |
| SVCBMT-4-L1     | KO                   |
| SVCBMT-5-L0     | OK                   |
| SVCBMT-5-L1     | KO                   |
| SVCBMT-6-L0     | OK                   |
| SVCBMT-6-L1     | KO                   |
| SVCBMT-7-L0     | OK                   |
| SVCBMT-7-L1     | KO                   |
| SVCBMT-8-L0     | OK                   |
| SVCBMT-8-L1     | KO                   |
| SVCBMT-9-L0     | OK                   |
| SVCBMT-9-L1     | KO                   |
| SVCBS-1-L0      | OK                   |
| SVCBS-1-L1      | KO                   |
| SVCBS-2-L0      | OK                   |
| SVCBS-2-L1      | KO                   |
| SVCBS-3-r1-L0   | OK                   |
| SVCBS-3-r1-L1   | KO                   |
| SVCBS-4-r1-L0   | OK                   |
| SVCBS-4-r1-L1   | KO                   |
| SVCBS-5-r1-L0   | OK                   |
| SVCBS-5-r1-L1   | KO                   |
| SVCBS-6-r1-L0   | OK                   |
| SVCBS-6-r1-L1   | KO                   |
| SVCBS-6-r1-L2   | KO                   |
| SVCBS-7-L0      | OK                   |
| SVCBS-7-L1      | KO                   |
| SVCBS-8-L0      | OK                   |
| SVCBS-8-L1      | KO                   |
| SVCBST-1-L0     | OK                   |
| SVCBST-1-L1     | KO                   |
| SVCBST-10-r1-L0 | OK                   |
| SVCBST-10-r1-L1 | KO                   |
| SVCBST-11-r1-L0 | OK                   |
| SVCBST-11-r1-L1 | KO                   |
| SVCBST-12-r1-L0 | OK                   |
| SVCBST-12-r1-L1 | KO                   |
| SVCBST-13-L0    | OK                   |
| SVCBST-13-L1    | KO                   |
| SVCBST-14-L0    | OK                   |
| SVCBST-14-L1    | KO                   |
| SVCBST-14-L2    | KO                   |
| SVCBST-15-L0    | OK                   |
| SVCBST-15-L1    | KO                   |
| SVCBST-15-L2    | KO                   |
| SVCBST-16-r1-L0 | OK                   |
| SVCBST-16-r1-L1 | KO                   |
| SVCBST-16-r1-L2 | KO                   |
| SVCBST-17-r1-L0 | OK                   |
| SVCBST-17-r1-L1 | KO                   |
| SVCBST-17-r1-L2 | KO                   |
| SVCBST-18-r1-L0 | OK                   |
| SVCBST-18-r1-L1 | KO                   |
| SVCBST-18-r1-L2 | KO                   |
| SVCBST-19-L0    | OK                   |
| SVCBST-19-L1    | KO                   |
| SVCBST-2-L0     | OK                   |
| SVCBST-2-L1     | KO                   |
| SVCBST-20-L0    | OK                   |
| SVCBST-20-L1    | KO                   |
| SVCBST-3-L0     | OK                   |
| SVCBST-3-L1     | KO                   |
| SVCBST-4-L0     | OK                   |
| SVCBST-4-L1     | KO                   |
| SVCBST-5-L0     | OK                   |
| SVCBST-5-L1     | KO                   |
| SVCBST-6-r1-L0  | OK                   |
| SVCBST-6-r1-L1  | KO                   |
| SVCBST-7-r1-L0  | OK                   |
| SVCBST-7-r1-L1  | KO                   |
| SVCBST-8-r1-L0  | OK                   |
| SVCBST-8-r1-L1  | KO                   |
| SVCBST-9-r1-L0  | OK                   |
| SVCBST-9-r1-L1  | KO                   |
| SVCBSTC-1-L0    | OK                   |
| SVCBSTC-1-L1    | KO                   |
| SVCBSTC-1-L2    | KO                   |
| SVCHCTS-1-r1-L0 | OK                   |
| SVCHCTS-1-r1-L1 | KO                   |
| SVCHCTS-1-r1-L2 | KO                   |
| SVCHCTS-1-r1-L3 | KO                   |
| SVCHCTS-1-r1-L4 | KO                   |
| SVCHCTS-1-r1-L5 | KO                   |
| SVCHCTS-1-r1-L6 | KO                   |
| SVCHCTS-1-r1-L7 | KO                   |
| SVCHICS-1-L0    | OK                   |
| SVCHICS-1-L1    | KO                   |
| SVCHICS-1-L2    | KO                   |
| SVCHICS-1-L3    | KO                   |
| SVCHIS-1-L0     | OK                   |
| SVCHIS-1-L1     | KO                   |
| SVCHIS-1-L2     | KO                   |
| SVCHIS-2-L0     | OK                   |
| SVCHIS-2-L1     | KO                   |
| SVCHIS-2-L2     | KO                   |
| SVCHIS-3-L0     | OK                   |
| SVCHIS-3-L1     | KO                   |
| SVCHIS-3-L2     | KO                   |
| SVCHM-1-L0      | OK                   |
| SVCHM-1-L1      | KO                   |
| SVCHM-1-L2      | KO                   |
| SVCHM-1-L3      | KO                   |
| SVCHM-2-L0      | OK                   |
| SVCHM-2-L1      | OK                   |
| SVCHM-3-L0      | OK                   |
| SVCHM-3-L1      | OK                   |
| SVCHM-4-L0      | OK                   |
| SVCHM-4-L1      | OK                   |
| SVCHM-4-L2      | OK                   |
| SVCHMTS-1-r1-L0 | OK                   |
| SVCHMTS-1-r1-L1 | KO                   |
| SVCHMTS-1-r1-L2 | KO                   |
| SVCHMTS-1-r1-L3 | KO                   |
| SVCHMTS-1-r1-L4 | KO                   |
| SVCHMTS-1-r1-L5 | KO                   |
| SVCHMTS-2-r1-L0 | OK                   |
| SVCHMTS-2-r1-L1 | KO                   |
| SVCHMTS-2-r1-L2 | KO                   |
| SVCHS-1-r1-L0   | OK                   |
| SVCHS-1-r1-L1   | KO                   |
| SVCHS-2-r1-L0   | OK                   |
| SVCHS-2-r1-L1   | KO                   |
| SVCHST-1-r1-L0  | OK                   |
| SVCHST-1-r1-L1  | KO                   |
| SVCHST-1-r1-L2  | KO                   |
| SVCHST-2-r1-L0  | OK                   |
| SVCHST-2-r1-L1  | KO                   |
| SVCHST-2-r1-L2  | KO                   |
| SVCHST-3-r1-L0  | ER                   |
| SVCHST-3-r1-L1  | ER                   |
| SVCHST-4-r1-L0  | ER                   |
| SVCHST-4-r1-L1  | ER                   |
| SVCHSTC-1-r1-L0 | OK                   |
| SVCHSTC-1-r1-L1 | KO                   |
| SVCHSTC-1-r1-L2 | KO                   |
| -               | -                    |
| Test            | FFmpeg-H.264-v4l2m2m |
| TOTAL           | 75/185               |
| TOTAL TIME      | 727.240s             |

NOTE: The current implementation of the decoder only supports Layer 0 (base layer) processing.
When attempting to decode streams that contain multiple layers (such as scalable or multi-view content), the decoding operation fails.
This limitation means that enhanced features requiring layer-based processing beyond the base layer cannot be properly handled by the current decoder.
For successful decoding, input streams must be limited to single-layer content only.

[FLUSTER REPORT FOR THE H.265]

| -                               | -                    |
| AMP_A_Samsung_7                 | OK                   |
| AMP_B_Samsung_7                 | OK                   |
| AMP_D_Hisilicon_3               | OK                   |
| AMP_E_Hisilicon_3               | OK                   |
| AMP_F_Hisilicon_3               | ER                   |
| AMVP_A_MTK_4                    | ER                   |
| AMVP_B_MTK_4                    | OK                   |
| AMVP_C_Samsung_7                | ER                   |
| BUMPING_A_ericsson_1            | OK                   |
| CAINIT_A_SHARP_4                | OK                   |
| CAINIT_B_SHARP_4                | OK                   |
| CAINIT_C_SHARP_3                | OK                   |
| CAINIT_D_SHARP_3                | OK                   |
| CAINIT_E_SHARP_3                | OK                   |
| CAINIT_F_SHARP_3                | OK                   |
| CAINIT_G_SHARP_3                | OK                   |
| CAINIT_H_SHARP_3                | OK                   |
| CIP_A_Panasonic_3               | OK                   |
| cip_B_NEC_3                     | OK                   |
| CIP_C_Panasonic_2               | OK                   |
| CONFWIN_A_Sony_1                | OK                   |
| DBLK_A_MAIN10_VIXS_4            | ER                   |
| DBLK_A_SONY_3                   | OK                   |
| DBLK_B_SONY_3                   | OK                   |
| DBLK_C_SONY_3                   | OK                   |
| DBLK_D_VIXS_2                   | OK                   |
| DBLK_E_VIXS_2                   | OK                   |
| DBLK_F_VIXS_2                   | OK                   |
| DBLK_G_VIXS_2                   | OK                   |
| DELTAQP_A_BRCM_4                | OK                   |
| DELTAQP_B_SONY_3                | OK                   |
| DELTAQP_C_SONY_3                | OK                   |
| DSLICE_A_HHI_5                  | OK                   |
| DSLICE_B_HHI_5                  | OK                   |
| DSLICE_C_HHI_5                  | OK                   |
| ENTP_A_QUALCOMM_1               | OK                   |
| ENTP_B_Qualcomm_1               | OK                   |
| ENTP_C_Qualcomm_1               | OK                   |
| EXT_A_ericsson_4                | OK                   |
| FILLER_A_Sony_1                 | OK                   |
| HRD_A_Fujitsu_3                 | OK                   |
| INITQP_A_Sony_1                 | OK                   |
| INITQP_B_Main10_Sony_1          | ER                   |
| ipcm_A_NEC_3                    | OK                   |
| ipcm_B_NEC_3                    | OK                   |
| ipcm_C_NEC_3                    | OK                   |
| ipcm_D_NEC_3                    | OK                   |
| ipcm_E_NEC_2                    | OK                   |
| IPRED_A_docomo_2                | OK                   |
| IPRED_B_Nokia_3                 | OK                   |
| IPRED_C_Mitsubishi_3            | OK                   |
| LS_A_Orange_2                   | OK                   |
| LS_B_Orange_4                   | OK                   |
| LTRPSPS_A_Qualcomm_1            | KO                   |
| MAXBINS_A_TI_5                  | OK                   |
| MAXBINS_B_TI_5                  | OK                   |
| MAXBINS_C_TI_5                  | OK                   |
| MERGE_A_TI_3                    | OK                   |
| MERGE_B_TI_3                    | OK                   |
| MERGE_C_TI_3                    | OK                   |
| MERGE_D_TI_3                    | OK                   |
| MERGE_E_TI_3                    | OK                   |
| MERGE_F_MTK_4                   | OK                   |
| MERGE_G_HHI_4                   | OK                   |
| MVCLIP_A_qualcomm_3             | OK                   |
| MVDL1ZERO_A_docomo_4            | OK                   |
| MVEDGE_A_qualcomm_3             | OK                   |
| NoOutPrior_A_Qualcomm_1         | OK                   |
| NoOutPrior_B_Qualcomm_1         | OK                   |
| NUT_A_ericsson_5                | OK                   |
| OPFLAG_A_Qualcomm_1             | OK                   |
| OPFLAG_B_Qualcomm_1             | OK                   |
| OPFLAG_C_Qualcomm_1             | OK                   |
| PICSIZE_A_Bossen_1              | OK                   |
| PICSIZE_B_Bossen_1              | ER                   |
| PICSIZE_C_Bossen_1              | OK                   |
| PICSIZE_D_Bossen_1              | ER                   |
| PMERGE_A_TI_3                   | OK                   |
| PMERGE_B_TI_3                   | OK                   |
| PMERGE_C_TI_3                   | OK                   |
| PMERGE_D_TI_3                   | OK                   |
| PMERGE_E_TI_3                   | OK                   |
| POC_A_Bossen_3                  | OK                   |
| PPS_A_qualcomm_7                | OK                   |
| PS_B_VIDYO_3                    | ER                   |
| RAP_A_docomo_6                  | OK                   |
| RAP_B_Bossen_2                  | OK                   |
| RPLM_A_qualcomm_4               | OK                   |
| RPLM_B_qualcomm_4               | OK                   |
| RPS_A_docomo_5                  | OK                   |
| RPS_B_qualcomm_5                | OK                   |
| RPS_C_ericsson_5                | OK                   |
| RPS_D_ericsson_6                | OK                   |
| RPS_E_qualcomm_5                | OK                   |
| RPS_F_docomo_2                  | OK                   |
| RQT_A_HHI_4                     | OK                   |
| RQT_B_HHI_4                     | OK                   |
| RQT_C_HHI_4                     | OK                   |
| RQT_D_HHI_4                     | OK                   |
| RQT_E_HHI_4                     | OK                   |
| RQT_F_HHI_4                     | OK                   |
| RQT_G_HHI_4                     | OK                   |
| SAO_A_MediaTek_4                | OK                   |
| SAO_B_MediaTek_5                | OK                   |
| SAO_C_Samsung_5                 | OK                   |
| SAO_D_Samsung_5                 | OK                   |
| SAO_E_Canon_4                   | OK                   |
| SAO_F_Canon_3                   | OK                   |
| SAO_G_Canon_3                   | OK                   |
| SAO_H_Parabola_1                | OK                   |
| SAODBLK_A_MainConcept_4         | OK                   |
| SAODBLK_B_MainConcept_4         | OK                   |
| SDH_A_Orange_4                  | OK                   |
| SLICES_A_Rovi_3                 | OK                   |
| SLIST_A_Sony_5                  | OK                   |
| SLIST_B_Sony_9                  | OK                   |
| SLIST_C_Sony_4                  | OK                   |
| SLIST_D_Sony_9                  | OK                   |
| SLPPLP_A_VIDYO_2                | ER                   |
| STRUCT_A_Samsung_7              | ER                   |
| STRUCT_B_Samsung_7              | ER                   |
| TILES_A_Cisco_2                 | ER                   |
| TILES_B_Cisco_1                 | ER                   |
| TMVP_A_MS_3                     | OK                   |
| TSCL_A_VIDYO_5                  | OK                   |
| TSCL_B_VIDYO_4                  | ER                   |
| TSKIP_A_MS_3                    | OK                   |
| TSUNEQBD_A_MAIN10_Technicolor_2 | ER                   |
| TUSIZE_A_Samsung_1              | OK                   |
| VPSID_A_VIDYO_2                 | ER                   |
| VPSSPSPPS_A_MainConcept_1       | KO                   |
| WP_A_MAIN10_Toshiba_3           | ER                   |
| WP_A_Toshiba_3                  | ER                   |
| WP_B_Toshiba_3                  | OK                   |
| WP_MAIN10_B_Toshiba_3           | ER                   |
| WPP_A_ericsson_MAIN10_2         | ER                   |
| WPP_A_ericsson_MAIN_2           | OK                   |
| WPP_B_ericsson_MAIN10_2         | ER                   |
| WPP_B_ericsson_MAIN_2           | OK                   |
| WPP_C_ericsson_MAIN10_2         | ER                   |
| WPP_C_ericsson_MAIN_2           | OK                   |
| WPP_D_ericsson_MAIN10_2         | ER                   |
| WPP_D_ericsson_MAIN_2           | OK                   |
| WPP_E_ericsson_MAIN10_2         | ER                   |
| WPP_E_ericsson_MAIN_2           | OK                   |
| WPP_F_ericsson_MAIN10_2         | ER                   |
| WPP_F_ericsson_MAIN_2           | OK                   |
| -                               | -                    |
| Test                            | FFmpeg-H.265-v4l2m2m |
| TOTAL                           | 120/147              |
| TOTAL TIME                      | 12669.641s           |

Failed streams :
 - VPSSPSPPS_A_MainConcept_1 : Failed due to evolutive dynamic resolution increases. The decoder cannot properly handle upward resolution changes within the same stream.
 - LTRPSPS_A_Qualcomm_1

Yassine Ouaissa (5):
  media: allegro-dvt: Move the current driver to a subdirectory
  dt-bindings: media: allegro-dvt: add decoder dt-bindings for Gen3 IP
  MAINTAINERS: Add entry for allegrodvt Gen 3 drivers
  dt-bindings: vendor-prefixes: Update the description of allegro prefix
  media: allegro-dvt: Add Gen 3 IP stateful decoder driver

 .../bindings/media/allegro,al300-vdec.yaml    |   75 +
 .../devicetree/bindings/vendor-prefixes.yaml  |    2 +-
 MAINTAINERS                                   |    5 +-
 drivers/media/platform/allegro-dvt/Kconfig    |   17 +-
 drivers/media/platform/allegro-dvt/Makefile   |    6 +-
 .../media/platform/allegro-dvt/al300/Kconfig  |   23 +
 .../media/platform/allegro-dvt/al300/Makefile |    6 +
 .../allegro-dvt/al300/al_codec_common.c       |  754 ++++++++
 .../allegro-dvt/al300/al_codec_common.h       |  247 +++
 .../allegro-dvt/al300/al_codec_util.c         |  177 ++
 .../allegro-dvt/al300/al_codec_util.h         |  185 ++
 .../platform/allegro-dvt/al300/al_vdec_drv.c  | 1530 +++++++++++++++++
 .../platform/allegro-dvt/al300/al_vdec_drv.h  |   94 +
 .../media/platform/allegro-dvt/zynqmp/Kconfig |   17 +
 .../platform/allegro-dvt/zynqmp/Makefile      |    6 +
 .../allegro-dvt/{ => zynqmp}/allegro-core.c   |    0
 .../allegro-dvt/{ => zynqmp}/allegro-mail.c   |    0
 .../allegro-dvt/{ => zynqmp}/allegro-mail.h   |    0
 .../allegro-dvt/{ => zynqmp}/nal-h264.c       |    0
 .../allegro-dvt/{ => zynqmp}/nal-h264.h       |    0
 .../allegro-dvt/{ => zynqmp}/nal-hevc.c       |    0
 .../allegro-dvt/{ => zynqmp}/nal-hevc.h       |    0
 .../allegro-dvt/{ => zynqmp}/nal-rbsp.c       |    0
 .../allegro-dvt/{ => zynqmp}/nal-rbsp.h       |    0
 24 files changed, 3123 insertions(+), 21 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/media/allegro,al300-vdec.yaml
 create mode 100644 drivers/media/platform/allegro-dvt/al300/Kconfig
 create mode 100644 drivers/media/platform/allegro-dvt/al300/Makefile
 create mode 100644 drivers/media/platform/allegro-dvt/al300/al_codec_common.c
 create mode 100644 drivers/media/platform/allegro-dvt/al300/al_codec_common.h
 create mode 100644 drivers/media/platform/allegro-dvt/al300/al_codec_util.c
 create mode 100644 drivers/media/platform/allegro-dvt/al300/al_codec_util.h
 create mode 100644 drivers/media/platform/allegro-dvt/al300/al_vdec_drv.c
 create mode 100644 drivers/media/platform/allegro-dvt/al300/al_vdec_drv.h
 create mode 100644 drivers/media/platform/allegro-dvt/zynqmp/Kconfig
 create mode 100644 drivers/media/platform/allegro-dvt/zynqmp/Makefile
 rename drivers/media/platform/allegro-dvt/{ => zynqmp}/allegro-core.c (100%)
 rename drivers/media/platform/allegro-dvt/{ => zynqmp}/allegro-mail.c (100%)
 rename drivers/media/platform/allegro-dvt/{ => zynqmp}/allegro-mail.h (100%)
 rename drivers/media/platform/allegro-dvt/{ => zynqmp}/nal-h264.c (100%)
 rename drivers/media/platform/allegro-dvt/{ => zynqmp}/nal-h264.h (100%)
 rename drivers/media/platform/allegro-dvt/{ => zynqmp}/nal-hevc.c (100%)
 rename drivers/media/platform/allegro-dvt/{ => zynqmp}/nal-hevc.h (100%)
 rename drivers/media/platform/allegro-dvt/{ => zynqmp}/nal-rbsp.c (100%)
 rename drivers/media/platform/allegro-dvt/{ => zynqmp}/nal-rbsp.h (100%)

--
2.30.2

---
Yassine Ouaissa (4):
      media: allegro-dvt: Move the current driver to a subdirectory
      dt-bindings: media: allegro: Add al300 decoder IPs
      dt-bindings: vendor-prefixes: Update the description of allegro prefix
      media: allegro-dvt: Add Gen 3 IP stateful decoder driver

 .../bindings/media/allegro,al300-vdec.yaml         |   76 +
 .../devicetree/bindings/vendor-prefixes.yaml       |    2 +-
 MAINTAINERS                                        |    4 +-
 drivers/media/platform/allegro-dvt/Kconfig         |   17 +-
 drivers/media/platform/allegro-dvt/Makefile        |    6 +-
 drivers/media/platform/allegro-dvt/al300/Kconfig   |   23 +
 drivers/media/platform/allegro-dvt/al300/Makefile  |    9 +
 .../platform/allegro-dvt/al300/al_codec_common.c   |  764 ++++++++++
 .../platform/allegro-dvt/al300/al_codec_common.h   |  252 ++++
 .../platform/allegro-dvt/al300/al_codec_dbgfs.c    |  229 +++
 .../platform/allegro-dvt/al300/al_codec_dbgfs.h    |   71 +
 .../platform/allegro-dvt/al300/al_codec_util.c     |  180 +++
 .../platform/allegro-dvt/al300/al_codec_util.h     |  196 +++
 .../media/platform/allegro-dvt/al300/al_vdec_drv.c | 1514 ++++++++++++++++++++
 .../media/platform/allegro-dvt/al300/al_vdec_drv.h |   98 ++
 drivers/media/platform/allegro-dvt/zynqmp/Kconfig  |   17 +
 drivers/media/platform/allegro-dvt/zynqmp/Makefile |    6 +
 .../allegro-dvt/{ => zynqmp}/allegro-core.c        |    0
 .../allegro-dvt/{ => zynqmp}/allegro-mail.c        |    0
 .../allegro-dvt/{ => zynqmp}/allegro-mail.h        |    0
 .../platform/allegro-dvt/{ => zynqmp}/nal-h264.c   |    0
 .../platform/allegro-dvt/{ => zynqmp}/nal-h264.h   |    0
 .../platform/allegro-dvt/{ => zynqmp}/nal-hevc.c   |    0
 .../platform/allegro-dvt/{ => zynqmp}/nal-hevc.h   |    0
 .../platform/allegro-dvt/{ => zynqmp}/nal-rbsp.c   |    0
 .../platform/allegro-dvt/{ => zynqmp}/nal-rbsp.h   |    0
 26 files changed, 3443 insertions(+), 21 deletions(-)
---
base-commit: c2f2b01b74be8b40a2173372bcd770723f87e7b2
change-id: 20250527-allegro_dvt_al300_dec_driver-4e75a94af6dc

Best regards,
-- 
Yassine Ouaissa <yassine.ouaissa at allegrodvt.com>




From devnull+yassine.ouaissa.allegrodvt.com at kernel.org  Mon Dec  8 07:49:19 2025
From: devnull+yassine.ouaissa.allegrodvt.com at kernel.org (Yassine Ouaissa via B4 Relay)
Date: Mon, 08 Dec 2025 16:49:19 +0100
Subject: [PATCH RESEND v6 4/4] media: allegro-dvt: Add Gen 3 IP stateful
 decoder driver
In-Reply-To: <20251208-allegro_dvt_al300_dec_driver-v6-0-128956555677@allegrodvt.com>
References: <20251208-allegro_dvt_al300_dec_driver-v6-0-128956555677@allegrodvt.com>
Message-ID: <20251208-allegro_dvt_al300_dec_driver-v6-4-128956555677@allegrodvt.com>

From: Yassine Ouaissa <yassine.ouaissa at allegrodvt.com>

This commit introduces a new allegro-dvt V4L2 stateful decoder driverfor
the Gen 3 IP with support for:
- AVC (H.264), HEVC (H.265), and JPEG decoding
- Output formats: NV12, NV16, I420, and P010 for capture

Signed-off-by: Yassine Ouaissa <yassine.ouaissa at allegrodvt.com>
---
 drivers/media/platform/allegro-dvt/Kconfig         |    1 +
 drivers/media/platform/allegro-dvt/Makefile        |    1 +
 drivers/media/platform/allegro-dvt/al300/Kconfig   |   23 +
 drivers/media/platform/allegro-dvt/al300/Makefile  |    9 +
 .../platform/allegro-dvt/al300/al_codec_common.c   |  764 ++++++++++
 .../platform/allegro-dvt/al300/al_codec_common.h   |  252 ++++
 .../platform/allegro-dvt/al300/al_codec_dbgfs.c    |  229 +++
 .../platform/allegro-dvt/al300/al_codec_dbgfs.h    |   71 +
 .../platform/allegro-dvt/al300/al_codec_util.c     |  180 +++
 .../platform/allegro-dvt/al300/al_codec_util.h     |  196 +++
 .../media/platform/allegro-dvt/al300/al_vdec_drv.c | 1514 ++++++++++++++++++++
 .../media/platform/allegro-dvt/al300/al_vdec_drv.h |   98 ++
 12 files changed, 3338 insertions(+)

diff --git a/drivers/media/platform/allegro-dvt/Kconfig b/drivers/media/platform/allegro-dvt/Kconfig
index e9008614c27b..0d01ed0ad08a 100644
--- a/drivers/media/platform/allegro-dvt/Kconfig
+++ b/drivers/media/platform/allegro-dvt/Kconfig
@@ -2,4 +2,5 @@
 
 comment "Allegro DVT media platform drivers"
 
+source "drivers/media/platform/allegro-dvt/al300/Kconfig"
 source "drivers/media/platform/allegro-dvt/zynqmp/Kconfig"
diff --git a/drivers/media/platform/allegro-dvt/Makefile b/drivers/media/platform/allegro-dvt/Makefile
index d2aa6875edcf..c70ca19a47fb 100644
--- a/drivers/media/platform/allegro-dvt/Makefile
+++ b/drivers/media/platform/allegro-dvt/Makefile
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
 
+obj-y += al300/
 obj-y += zynqmp/
diff --git a/drivers/media/platform/allegro-dvt/al300/Kconfig b/drivers/media/platform/allegro-dvt/al300/Kconfig
new file mode 100644
index 000000000000..0bc3d7a79f14
--- /dev/null
+++ b/drivers/media/platform/allegro-dvt/al300/Kconfig
@@ -0,0 +1,23 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config VIDEO_ALLEGRO_DVT_D300
+	tristate "Allegro DVT Video IP Decode Gen 3"
+	depends on V4L_MEM2MEM_DRIVERS
+	depends on VIDEO_DEV && OF && HAS_DMA
+	select V4L2_MEM2MEM_DEV
+	select VIDEOBUF2_DMA_CONTIG
+	help
+	  This is a video4linux2 driver for the Allegro DVT IP Decode Gen 3,
+	  that support codecs : AVC (H.264), HEVC (H.265), and JPEG.
+
+	  The driver provides hardware acceleration for video decoding operations,
+	  enabling efficient processing of compressed video streams on platforms
+	  featuring this IP block. It handles memory management, buffer allocation,
+	  and decoder command sequencing to deliver optimized performance.
+
+	  The driver integrates with the V4L2 framework and videobuf2 subsystem
+	  to provide a standard interface for applications requiring video
+	  decoding capabilities.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called al300-vdec.
diff --git a/drivers/media/platform/allegro-dvt/al300/Makefile b/drivers/media/platform/allegro-dvt/al300/Makefile
new file mode 100644
index 000000000000..e5bc317ee2a7
--- /dev/null
+++ b/drivers/media/platform/allegro-dvt/al300/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+
+al300-vdec-objs := al_codec_common.o al_codec_util.o al_vdec_drv.o
+
+ifneq ($(CONFIG_DEBUG_FS),)
+al300-vdec-objs += al_codec_dbgfs.o
+endif
+
+obj-$(CONFIG_VIDEO_ALLEGRO_DVT_D300) += al300-vdec.o
diff --git a/drivers/media/platform/allegro-dvt/al300/al_codec_common.c b/drivers/media/platform/allegro-dvt/al300/al_codec_common.c
new file mode 100644
index 000000000000..6c950a4022fb
--- /dev/null
+++ b/drivers/media/platform/allegro-dvt/al300/al_codec_common.c
@@ -0,0 +1,764 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Core MCU functionality including firmware loading,
+ * memory allocation, and general MCU interaction interfaces
+ *
+ * Copyright (c) 2025 Allegro DVT.
+ * Author: Yassine OUAISSA <yassine.ouaissa at allegrodvt.fr>
+ */
+
+#include <linux/cleanup.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "al_codec_common.h"
+
+#define AL_CODEC_UID 0x0000
+#define AL_CODEC_RESET 0x0010
+#define AL_CODEC_IRQ_MASK 0x0014
+#define AL_CODEC_IRQ_STATUS_CLEAR 0x0018
+#define AL_CODEC_MCU_CLK 0x0400
+#define AL_CODEC_MCU_RST 0x0404
+#define AL_CODEC_MCU_IRQ 0x040C
+#define AL_CODEC_MCU_BOOT_ADDR_HI 0x0410
+#define AL_CODEC_MCU_BOOT_ADDR_LO 0x0414
+#define AL_CODEC_MCU_IP_START_ADDR_HI 0x0418
+#define AL_CODEC_MCU_IP_START_ADDR_LO 0x041C
+#define AL_CODEC_MCU_IP_END_ADDR_HI 0x0420
+#define AL_CODEC_MCU_IP_END_ADDR_LO 0x0424
+#define AL_CODEC_MCU_PERIPH_ADDR_HI 0x0428
+#define AL_CODEC_MCU_PERIPH_ADDR_LO 0x042C
+#define AL_CODEC_MCU_IRQ_MASK 0x0440
+#define AL_CODEC_INST_OFFSET_HI 0x0450
+#define AL_CODEC_INST_OFFSET_LO 0x0454
+#define AL_CODEC_DATA_OFFSET_HI 0x0458
+#define AL_CODEC_DATA_OFFSET_LO 0x045C
+
+#define AL_CODEC_UID_ID 0x30AB6E51
+#define AL_CODEC_IRQ_MCU_2_CPU BIT(30)
+#define AL_CODEC_IP_OFFSET GENMASK(26, 25)
+#define AL_CODEC_APB_MASK GENMASK(26, 0)
+#define MCU_FLAT_MEMORY_SIZE (256ULL * 1024 * 1024 * 1024) /* 256GB */
+
+#define AL_CODEC_MCU_BOOT_RESET_WAIT 2 /* in ms */
+#define AL_CODEC_REG_ENABLE BIT(0)
+#define AL_CODEC_REG_DISABLE 0
+
+/*
+ * struct codec_dma_buf - Allocated dma buffer
+ *
+ * @list: list head for buffer queue
+ * @paddr: physical address of the allcated DMA buffer
+ * @vaddr: virtual address of the allocated DMA buffer
+ * @size: Size of allocated dma memory
+ */
+struct codec_dma_buf {
+	void *vaddr;
+	dma_addr_t paddr;
+	u32 size;
+	struct list_head list;
+};
+
+struct mb_header {
+	u64 start;
+	u64 end;
+} __packed;
+
+struct boot_header {
+	u32 bh_version;
+	u32 fw_version;
+	char model[16];
+	u64 vaddr_start;
+	u64 vaddr_end;
+	u64 vaddr_boot;
+	struct mb_header h2m;
+	struct mb_header m2h;
+	u64 machine_id;
+	/* fill by driver before fw boot */
+	u64 ip_start;
+	u64 ip_end;
+	u64 mcu_clk_rate;
+} __packed;
+
+static u32 al_common_read(struct al_codec_dev *codec, u32 offset)
+{
+	return readl(codec->regs + offset);
+}
+
+static void al_common_write(struct al_codec_dev *codec, u32 offset, u32 val)
+{
+	writel(val, codec->regs + offset);
+}
+
+static void al_common_trigger_mcu_irq(void *arg)
+{
+	struct al_codec_dev *codec = arg;
+
+	al_common_write(codec, AL_CODEC_MCU_IRQ, BIT(0));
+}
+
+static inline void al_common_reset(struct al_codec_dev *codec)
+{
+	/* reset ip */
+	al_common_write(codec, AL_CODEC_RESET, AL_CODEC_REG_ENABLE);
+
+	/* reset and stop mcu */
+	al_common_write(codec, AL_CODEC_MCU_CLK, AL_CODEC_REG_ENABLE);
+	al_common_write(codec, AL_CODEC_MCU_RST, AL_CODEC_REG_ENABLE);
+	/* time to reset the mct */
+	mdelay(AL_CODEC_MCU_BOOT_RESET_WAIT);
+	al_common_write(codec, AL_CODEC_MCU_CLK, AL_CODEC_REG_DISABLE);
+
+	al_common_write(codec, AL_CODEC_MCU_IRQ, AL_CODEC_REG_DISABLE);
+	al_common_write(codec, AL_CODEC_MCU_IRQ_MASK, AL_CODEC_REG_DISABLE);
+
+	mdelay(AL_CODEC_MCU_BOOT_RESET_WAIT * 5);
+	al_common_write(codec, AL_CODEC_MCU_RST, AL_CODEC_REG_DISABLE);
+}
+
+static int al_common_setup_hw_regs(struct al_codec_dev *codec)
+{
+	u64 reg_start, reg_end;
+	dma_addr_t boot_addr;
+	unsigned int id;
+
+	id = al_common_read(codec, AL_CODEC_UID);
+
+	if (id != AL_CODEC_UID_ID) {
+		al_codec_err(codec,
+			     "bad device id, expected 0x%08x, got 0x%08x",
+			     AL_CODEC_UID_ID, id);
+		return -ENODEV;
+	}
+
+	boot_addr = codec->firmware.phys + codec->firmware.bin_data.offset -
+		    codec->offset;
+
+	/* Reset MCU step */
+	al_common_reset(codec);
+
+	/* Configure the MCU*/
+	al_common_write(codec, AL_CODEC_IRQ_MASK, AL_CODEC_IRQ_MCU_2_CPU);
+	/* Set Instruction and data offset */
+	al_common_write(codec, AL_CODEC_INST_OFFSET_HI,
+			upper_32_bits(codec->offset));
+	al_common_write(codec, AL_CODEC_INST_OFFSET_LO,
+			lower_32_bits(codec->offset));
+	al_common_write(codec, AL_CODEC_DATA_OFFSET_HI,
+			upper_32_bits(codec->offset));
+	al_common_write(codec, AL_CODEC_DATA_OFFSET_LO,
+			lower_32_bits(codec->offset));
+
+	reg_start = codec->regs_info->start;
+	reg_end = reg_start + resource_size(codec->regs_info);
+	al_common_write(codec, AL_CODEC_MCU_IP_START_ADDR_HI,
+			upper_32_bits(reg_start));
+	al_common_write(codec, AL_CODEC_MCU_IP_START_ADDR_LO,
+			lower_32_bits(reg_start));
+	al_common_write(codec, AL_CODEC_MCU_IP_END_ADDR_HI,
+			upper_32_bits(reg_end));
+	al_common_write(codec, AL_CODEC_MCU_IP_END_ADDR_HI,
+			lower_32_bits(reg_end));
+
+	al_common_write(codec, AL_CODEC_MCU_PERIPH_ADDR_HI,
+			upper_32_bits(codec->apb));
+	al_common_write(codec, AL_CODEC_MCU_PERIPH_ADDR_LO,
+			lower_32_bits(codec->apb));
+
+	al_common_write(codec, AL_CODEC_MCU_BOOT_ADDR_HI,
+			upper_32_bits(boot_addr));
+	al_common_write(codec, AL_CODEC_MCU_BOOT_ADDR_LO,
+			lower_32_bits(boot_addr));
+
+	return 0;
+}
+
+static void al_common_dma_buf_insert(struct al_codec_dev *codec,
+				     struct codec_dma_buf *buf)
+{
+	guard(mutex)(&codec->buf_lock);
+	list_add(&buf->list, &codec->alloc_buffers);
+}
+
+static void al_common_dma_buf_remove(struct al_codec_dev *codec,
+				     struct codec_dma_buf *buf)
+{
+	struct device *dev = &codec->pdev->dev;
+
+	guard(mutex)(&codec->buf_lock);
+	dma_free_coherent(dev, buf->size, buf->vaddr, buf->paddr);
+	list_del(&buf->list);
+	kfree(buf);
+}
+
+static struct codec_dma_buf *
+al_common_dma_buf_lookup(struct al_codec_dev *codec, dma_addr_t buf_paddr)
+{
+	struct codec_dma_buf *buf = NULL;
+
+	guard(mutex)(&codec->buf_lock);
+	list_for_each_entry(buf, &codec->alloc_buffers, list)
+		if (likely(buf->paddr == buf_paddr))
+			break;
+
+	return list_entry_is_head(buf, &codec->alloc_buffers, list) ? NULL :
+								      buf;
+}
+
+static void al_common_dma_buf_cleanup(struct al_codec_dev *codec)
+{
+	struct device *dev = &codec->pdev->dev;
+	struct codec_dma_buf *buf, *tmp;
+
+	guard(mutex)(&codec->buf_lock);
+	list_for_each_entry_safe(buf, tmp, &codec->alloc_buffers, list) {
+		dma_free_coherent(dev, buf->size, buf->vaddr, buf->paddr);
+		list_del(&buf->list);
+		kfree(buf);
+	}
+}
+
+static inline uint64_t get_mcu_offset(uint64_t paddr)
+{
+	if (paddr < MCU_FLAT_MEMORY_SIZE)
+		return 0;
+
+	return paddr - MCU_FLAT_MEMORY_SIZE;
+}
+
+static int al_common_setup_dma(struct al_codec_dev *codec)
+{
+	struct device *dev = &codec->pdev->dev;
+	struct device_node *node;
+	struct resource r;
+	int ret;
+
+	/* setup dma memory mask */
+	if (!dev->coherent_dma_mask) {
+		ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64));
+		if (ret) {
+			al_codec_err(codec, "Failed to set dma mask %d\n", ret);
+			return ret;
+		}
+	}
+
+	node = of_parse_phandle(dev->of_node, "memory-region", 0);
+	if (!node) {
+		dev_warn(dev, "No reserved memory, use cma instead\n");
+		return 0;
+	}
+
+	/* Try to use reserved memory if we got one */
+	ret = of_reserved_mem_device_init(dev);
+	if (ret) {
+		al_codec_err(codec, "Couldn't get reserved memory (errno: %d)",
+			     ret);
+		return ret;
+	}
+
+	ret = of_address_to_resource(node, 0, &r);
+	of_node_put(node);
+	if (ret) {
+		al_codec_err(codec,
+			     "Failed to parse the memory-region resources");
+		return ret;
+	}
+
+	codec->offset = get_mcu_offset(r.start);
+
+	return 0;
+}
+
+void al_common_remove(struct al_codec_dev *codec)
+{
+	/* Cleanup allocated internal buffers used by the mcu*/
+	al_common_dma_buf_cleanup(codec);
+
+	/* reset codecice */
+	al_common_reset(codec);
+	clk_disable_unprepare(codec->clk);
+	/* Free the allocated memory for the firmware */
+	dma_free_coherent(&codec->pdev->dev, codec->firmware.size,
+			  codec->firmware.virt, codec->firmware.phys);
+
+	if (codec->firmware.firmware)
+		release_firmware(codec->firmware.firmware);
+}
+
+static void handle_alloc_memory_req(struct al_codec_dev *codec,
+				    struct msg_itf_header *hdr)
+{
+	struct device *dev = &codec->pdev->dev;
+	struct msg_itf_alloc_mem_req req;
+	struct msg_itf_alloc_mem_reply_full reply = {
+		.reply.phyAddr = 0,
+		.hdr.type = MSG_ITF_TYPE_ALLOC_MEM_REPLY,
+		.hdr.drv_ctx_hdl = hdr->drv_ctx_hdl,
+		.hdr.drv_cmd_hdl = hdr->drv_cmd_hdl,
+		.hdr.payload_len = sizeof(struct msg_itf_alloc_mem_reply),
+	};
+	struct codec_dma_buf *buf;
+	int ret;
+
+	ret = al_common_get_data(codec, (char *)&req, hdr->payload_len);
+	if (ret) {
+		al_codec_err(codec, "Unable to get cma req %d", ret);
+		return;
+	}
+
+	buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+	if (!buf)
+		goto send_reply;
+
+	buf->size = req.uSize;
+	buf->vaddr =
+		dma_alloc_coherent(dev, buf->size, &buf->paddr, GFP_KERNEL);
+	if (!buf->vaddr) {
+		dev_warn(dev, "Failed to allocate DMA buffer\n");
+		goto send_reply;
+	}
+
+	reply.reply.phyAddr = (u64)buf->paddr;
+	al_common_dma_buf_insert(codec, buf);
+
+send_reply:
+	ret = al_common_send(codec, &reply.hdr);
+	if (ret) {
+		al_codec_err(codec, "Unable to reply to cma alloc");
+		al_common_dma_buf_remove(codec, buf);
+	}
+}
+
+static void handle_free_memory_req(struct al_codec_dev *codec,
+				   struct msg_itf_header *hdr)
+{
+	struct msg_itf_free_mem_req req;
+	struct msg_itf_free_mem_reply_full reply = {
+		.hdr.type = MSG_ITF_TYPE_FREE_MEM_REPLY,
+		.hdr.drv_ctx_hdl = hdr->drv_ctx_hdl,
+		.hdr.drv_cmd_hdl = hdr->drv_cmd_hdl,
+		.hdr.payload_len = sizeof(struct msg_itf_free_mem_reply),
+		.reply.ret = -1,
+	};
+	struct codec_dma_buf *buf;
+	int ret;
+
+	ret = al_common_get_data(codec, (char *)&req, hdr->payload_len);
+	if (ret) {
+		al_codec_err(codec, "Unable to put cma req");
+		return;
+	}
+
+	buf = al_common_dma_buf_lookup(codec, req.phyAddr);
+	if (!buf) {
+		al_codec_err(codec, "Unable to get dma handle for %p",
+			     (void *)(long)req.phyAddr);
+		reply.reply.ret = -EINVAL;
+		goto send_reply;
+	}
+
+	al_codec_dbg(codec, "Free memory %p, size %d",
+		     (void *)(long)req.phyAddr, buf->size);
+
+	al_common_dma_buf_remove(codec, buf);
+	reply.reply.ret = 0;
+
+send_reply:
+	ret = al_common_send(codec, &reply.hdr);
+	if (ret)
+		al_codec_err(codec, "Unable to reply to cma free");
+}
+
+static void handle_mcu_console_print(struct al_codec_dev *codec,
+				     struct msg_itf_header *hdr)
+{
+	struct msg_itf_write_req *req;
+	int ret;
+
+	/* one more byte to be sure to have a zero terminated string */
+	req = kzalloc(hdr->payload_len + 1, GFP_KERNEL);
+	if (!req) {
+		al_common_skip_data(codec, hdr->payload_len);
+		al_codec_err(codec, "Unable to alloc memory");
+		return;
+	}
+
+	ret = al_codec_msg_get_data(&codec->mb_m2h, (char *)req,
+				    hdr->payload_len);
+	if (ret) {
+		al_codec_err(codec, "Unable to get request");
+		kfree(req);
+		return;
+	}
+
+	/* Print the mcu logs */
+	al_mcu_dbg(codec, "%s", (char *)(req + 1));
+	kfree(req);
+}
+
+static void process_one_message(struct al_codec_dev *codec,
+				struct msg_itf_header *hdr)
+{
+	switch (hdr->type) {
+	case MSG_ITF_TYPE_ALLOC_MEM_REQ:
+		handle_alloc_memory_req(codec, hdr);
+		break;
+	case MSG_ITF_TYPE_FREE_MEM_REQ:
+		handle_free_memory_req(codec, hdr);
+		break;
+	case MSG_ITF_TYPE_WRITE_REQ:
+		handle_mcu_console_print(codec, hdr);
+		break;
+	case MSG_ITF_TYPE_MCU_ALIVE:
+		complete(&codec->completion);
+		break;
+	default:
+		codec->process_msg_cb(codec->cb_arg, hdr);
+		break;
+	}
+}
+
+static irqreturn_t al_common_irq_handler(int irq, void *data)
+{
+	struct al_codec_dev *codec = data;
+	struct msg_itf_header hdr;
+
+	/* poll all messages */
+	while (al_codec_msg_get_header(&codec->mb_m2h, &hdr) == 0)
+		process_one_message(codec, &hdr);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t al_common_hardirq_handler(int irq, void *data)
+{
+	struct al_codec_dev *codec = data;
+
+	if (al_common_read(codec, AL_CODEC_IRQ_STATUS_CLEAR) == 0)
+		return IRQ_NONE;
+
+	al_common_write(codec, AL_CODEC_IRQ_STATUS_CLEAR,
+			AL_CODEC_IRQ_MCU_2_CPU);
+
+	return IRQ_WAKE_THREAD;
+}
+
+static int al_common_start_fw(struct al_codec_dev *codec)
+{
+	/* Enable the MCU clock */
+	al_common_write(codec, AL_CODEC_MCU_CLK, AL_CODEC_REG_ENABLE);
+
+	return !wait_for_completion_timeout(&codec->completion, 2 * HZ);
+}
+
+static void al_common_copy_firmware_image(struct al_codec_dev *codec)
+{
+	const struct firmware *firmware = codec->firmware.firmware;
+	u32 *virt = codec->firmware.virt;
+
+	/* copy the whole thing taking into account endianness */
+	for (size_t i = 0; i < firmware->size / sizeof(u32); i++)
+		virt[i] = le32_to_cpu(((__le32 *)firmware->data)[i]);
+}
+
+static int al_common_read_firmware(struct al_codec_dev *codec, const char *name)
+{
+	struct device *dev = &codec->pdev->dev;
+	const struct boot_header *bh;
+	int err;
+
+	/* request_firmware prints error if it fails */
+	err = request_firmware(&codec->firmware.firmware, name, dev);
+	if (err < 0)
+		return err;
+
+	bh = (struct boot_header *)codec->firmware.firmware->data;
+	codec->firmware.size = bh->vaddr_end - bh->vaddr_start;
+
+	return 0;
+}
+
+static int al_common_parse_firmware_image(struct al_codec_dev *codec)
+{
+	struct boot_header *bh = (void *)codec->firmware.virt;
+
+	if (bh->bh_version < AL_BOOT_VERSION(2, 0, 0) ||
+	    bh->bh_version >= AL_BOOT_VERSION(3, 0, 0)) {
+		al_codec_err(codec, "Unsupported firmware version");
+		return -EINVAL;
+	}
+
+	codec->firmware.bin_data.offset = bh->vaddr_boot - bh->vaddr_start;
+	codec->firmware.bin_data.size = bh->vaddr_end - bh->vaddr_start;
+
+	codec->firmware.mb_h2m.offset = bh->h2m.start - bh->vaddr_start;
+	codec->firmware.mb_h2m.size = bh->h2m.end - bh->h2m.start;
+	codec->firmware.mb_m2h.offset = bh->m2h.start - bh->vaddr_start;
+	codec->firmware.mb_m2h.size = bh->m2h.end - bh->m2h.start;
+
+	/* Override some data */
+	bh->ip_start = codec->apb + AL_CODEC_IP_OFFSET;
+	bh->ip_end = bh->ip_start + resource_size(codec->regs_info);
+	bh->mcu_clk_rate = clk_get_rate(codec->clk);
+
+	al_codec_dbg(codec, "bh version     = 0x%08x", bh->bh_version);
+	al_codec_dbg(codec, "fw version     = 0x%08x", bh->fw_version);
+	al_codec_dbg(codec, "fw model       = %s", bh->model);
+	al_codec_dbg(codec, "vaddress start = 0x%016llx", bh->vaddr_start);
+	al_codec_dbg(codec, "vaddress end   = 0x%016llx", bh->vaddr_end);
+	al_codec_dbg(codec, "boot address   = 0x%016llx", bh->vaddr_boot);
+	al_codec_dbg(codec, "machineid      = %lld", bh->machine_id);
+	al_codec_dbg(codec, "periph address = 0x%llx", (u64)codec->apb);
+	al_codec_dbg(codec, "ip start       = 0x%016llx", bh->ip_start);
+	al_codec_dbg(codec, "ip end         = 0x%016llx", bh->ip_end);
+	al_codec_dbg(codec, "mcu clk	      = %llu", bh->mcu_clk_rate);
+
+	return 0;
+}
+
+static int al_common_load_firmware_start(struct al_codec_dev *codec,
+					 const char *name)
+{
+	struct device *dev = &codec->pdev->dev;
+	dma_addr_t phys;
+	size_t size;
+	void *virt;
+	int err;
+
+	if (codec->firmware.virt)
+		return 0;
+
+	err = al_common_read_firmware(codec, name);
+	if (err)
+		return err;
+
+	size = codec->firmware.size;
+
+	virt = dma_alloc_coherent(dev, size, &phys, GFP_KERNEL);
+	err = dma_mapping_error(dev, phys);
+	if (err < 0)
+		return err;
+
+	codec->firmware.virt = virt;
+	codec->firmware.phys = phys;
+
+	al_common_copy_firmware_image(codec);
+	err = al_common_parse_firmware_image(codec);
+	if (err) {
+		al_codec_err(codec, "failed to parse firmware image");
+		goto cleanup;
+	}
+
+	err = al_common_setup_hw_regs(codec);
+	if (err) {
+		al_codec_err(codec, "Unable to setup hw registers");
+		goto cleanup;
+	}
+
+	al_codec_mb_init(&codec->mb_h2m, virt + codec->firmware.mb_h2m.offset,
+			 codec->firmware.mb_h2m.size, MB_IFT_MAGIC_H2M);
+
+	al_codec_mb_init(&codec->mb_m2h, virt + codec->firmware.mb_m2h.offset,
+			 codec->firmware.mb_m2h.size, MB_IFT_MAGIC_M2H);
+
+	err = al_common_start_fw(codec);
+	if (err) {
+		al_codec_err(codec, "fw start has failed");
+		goto cleanup;
+	}
+
+	al_codec_dbg(codec, "mcu has boot successfully !");
+	codec->fw_ready_cb(codec->cb_arg);
+
+	release_firmware(codec->firmware.firmware);
+	codec->firmware.firmware = NULL;
+
+	return 0;
+
+cleanup:
+	dma_free_coherent(dev, size, virt, phys);
+
+	return err;
+}
+
+static u64 al_common_get_periph_addr(struct al_codec_dev *codec)
+{
+	struct resource *res;
+
+	res = platform_get_resource_byname(codec->pdev, IORESOURCE_MEM, "apb");
+	if (!res) {
+		al_codec_err(codec, "Unable to find APB start address");
+		return 0;
+	}
+
+	if (res->start & AL_CODEC_APB_MASK) {
+		al_codec_err(codec, "APB start address is invalid");
+		return 0;
+	}
+
+	return res->start;
+}
+
+int al_common_probe(struct al_codec_dev *codec, const char *name)
+{
+	struct platform_device *pdev = codec->pdev;
+	int irq;
+	int ret;
+
+	mutex_init(&codec->buf_lock);
+	INIT_LIST_HEAD(&codec->alloc_buffers);
+	init_completion(&codec->completion);
+	codec->offset = 0;
+
+	/* setup dma memory */
+	ret = al_common_setup_dma(codec);
+	if (ret)
+		return ret;
+
+	/* Hw registers */
+	codec->regs_info =
+		platform_get_resource_byname(pdev, IORESOURCE_MEM, "top");
+	if (!codec->regs_info) {
+		al_codec_err(codec, "regs resource missing from device tree");
+		return -EINVAL;
+	}
+
+	codec->regs = devm_ioremap_resource(&pdev->dev, codec->regs_info);
+	if (!codec->regs) {
+		al_codec_err(codec, "failed to map registers");
+		return -ENOMEM;
+	}
+
+	codec->apb = al_common_get_periph_addr(codec);
+	if (!codec->apb)
+		return -EINVAL;
+
+	/* The MCU has already default clock value */
+	codec->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(codec->clk)) {
+		al_codec_err(codec, "failed to get MCU core clock");
+		return PTR_ERR(codec->clk);
+	}
+
+	ret = clk_prepare_enable(codec->clk);
+	if (ret) {
+		al_codec_err(codec, "Cannot enable MCU clock: %d\n", ret);
+		return ret;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		al_codec_err(codec, "Failed to get IRQ");
+		ret = -EINVAL;
+		goto disable_clk;
+	}
+
+	ret = devm_request_threaded_irq(&pdev->dev, irq,
+					al_common_hardirq_handler,
+					al_common_irq_handler, IRQF_SHARED,
+					dev_name(&pdev->dev), codec);
+	if (ret) {
+		al_codec_err(codec, "Unable to register irq handler");
+		goto disable_clk;
+	}
+
+	/* ok so request the fw */
+	ret = al_common_load_firmware_start(codec, name);
+	if (ret) {
+		al_codec_err(codec, "failed to load firmware : %s", name);
+		goto disable_clk;
+	}
+
+	return 0;
+
+disable_clk:
+	clk_disable_unprepare(codec->clk);
+
+	return ret;
+}
+
+int al_common_send(struct al_codec_dev *codec, struct msg_itf_header *hdr)
+{
+	return al_codec_msg_send(&codec->mb_h2m, hdr, al_common_trigger_mcu_irq,
+				 codec);
+}
+
+int al_common_send_req_reply(struct al_codec_dev *codec,
+			     struct list_head *cmd_list,
+			     struct msg_itf_header *hdr,
+			     struct al_common_mcu_req *req)
+{
+	struct al_codec_cmd *cmd = NULL;
+	int ret;
+
+	hdr->drv_cmd_hdl = 0;
+
+	if (req->reply_size && req->reply) {
+		cmd = al_codec_cmd_create(req->reply_size);
+		if (!cmd)
+			return -ENOMEM;
+
+		hdr->drv_cmd_hdl = al_virt_to_phys(cmd);
+	}
+
+	hdr->drv_ctx_hdl = req->pCtx;
+	hdr->type = req->req_type;
+	hdr->payload_len = req->req_size;
+
+	/* Add the list to the cmd list */
+	if (cmd)
+		list_add(&cmd->list, cmd_list);
+
+	ret = al_common_send(codec, hdr);
+	if (ret)
+		goto remove_cmd;
+
+	al_codec_dbg(codec, "Send req to mcu %d : %zu", req->req_type,
+		     req->req_size);
+
+	if (!cmd)
+		return 0;
+
+	ret = wait_for_completion_timeout(&cmd->done, 5 * HZ);
+	if (ret <= 0) {
+		al_codec_err(codec, "cmd %p has %d (%s)", cmd, ret,
+			     (ret == 0) ? "failed" : "timedout");
+		ret = -ETIMEDOUT;
+		goto remove_cmd;
+	}
+
+	ret = 0;
+	memcpy(req->reply, cmd->reply, req->reply_size);
+
+remove_cmd:
+
+	if (cmd) {
+		list_del(&cmd->list);
+		al_codec_cmd_put(cmd);
+	}
+	return ret;
+}
+
+bool al_common_mcu_is_alive(struct al_codec_dev *codec)
+{
+	static const struct msg_itf_header hdr = {
+		.type = MSG_ITF_TYPE_MCU_ALIVE,
+		.payload_len = 0,
+	};
+	int ret;
+
+	ret = al_common_send(codec, (struct msg_itf_header *)&hdr);
+	if (ret)
+		return false;
+
+	ret = wait_for_completion_timeout(&codec->completion, 5 * HZ);
+	if (ret <= 0)
+		return false;
+
+	return true;
+}
diff --git a/drivers/media/platform/allegro-dvt/al300/al_codec_common.h b/drivers/media/platform/allegro-dvt/al300/al_codec_common.h
new file mode 100644
index 000000000000..0d2f8d788a73
--- /dev/null
+++ b/drivers/media/platform/allegro-dvt/al300/al_codec_common.h
@@ -0,0 +1,252 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2025 Allegro DVT.
+ * Author: Yassine OUAISSA <yassine.ouaissa at allegrodvt.fr>
+ */
+
+#ifndef __AL_CODEC_COMMON__
+#define __AL_CODEC_COMMON__
+
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <media/v4l2-device.h>
+
+#include "al_codec_dbgfs.h"
+#include "al_codec_util.h"
+
+#define fh_to_ctx(ptr, type) container_of(ptr, type, fh)
+
+enum {
+	MSG_ITF_TYPE_CREATE_INST_REQ = MSG_ITF_TYPE_NEXT_REQ,
+	MSG_ITF_TYPE_DESTROY_INST_REQ,
+	MSG_ITF_TYPE_PUSH_BITSTREAM_BUFFER_REQ,
+	MSG_ITF_TYPE_PUT_DISPLAY_PICTURE_REQ,
+	MSG_ITF_TYPE_FLUSH_REQ,
+	MSG_ITF_TYPE_INFO_REQ,
+	MSG_ITF_TYPE_CREATE_INST_REPLY = MSG_ITF_TYPE_NEXT_REPLY,
+	MSG_ITF_TYPE_DESTROY_INST_REPLY,
+	MSG_ITF_TYPE_PUSH_BITSTREAM_BUFFER_REPLY,
+	MSG_ITF_TYPE_PUT_DISPLAY_PICTURE_REPLY,
+	MSG_ITF_TYPE_FLUSH_REPLY,
+	MSG_ITF_TYPE_INFO_REPLY,
+	MSG_ITF_TYPE_EVT_ERROR = MSG_ITF_TYPE_NEXT_EVT,
+};
+
+struct msg_itf_write_req {
+	u32 fd;
+	u32 len;
+	/* payload follow */
+} __packed;
+DECLARE_FULL_REQ(msg_itf_write_req);
+
+struct msg_itf_free_mem_req {
+	phys_addr_t phyAddr;
+} __packed;
+DECLARE_FULL_REQ(msg_itf_free_mem_req);
+
+struct msg_itf_alloc_mem_req {
+	u64 uSize;
+} __packed;
+DECLARE_FULL_REQ(msg_itf_alloc_mem_req);
+
+struct msg_itf_alloc_mem_reply {
+	phys_addr_t phyAddr;
+} __packed;
+DECLARE_FULL_REPLY(msg_itf_alloc_mem_reply);
+
+struct msg_itf_free_mem_reply {
+	s64 ret;
+};
+DECLARE_FULL_REPLY(msg_itf_free_mem_reply);
+
+struct msg_itf_create_codec_reply {
+	phys_addr_t hCodec;
+	s32 ret;
+} __packed;
+DECLARE_FULL_REPLY(msg_itf_create_codec_reply);
+
+struct msg_itf_destroy_codec_req {
+	phys_addr_t hCodec;
+} __packed;
+DECLARE_FULL_REQ(msg_itf_destroy_codec_req);
+
+/*
+ * Note : no need to know the status of this request
+ * The codec should be destroyed, in case of the mcu
+ * hasn't received any request with the codec handler
+ */
+struct msg_itf_destroy_codec_reply {
+	u32 unused;
+} __packed;
+DECLARE_FULL_REPLY(msg_itf_destroy_codec_reply);
+
+struct al_buffer_meta {
+	u64 timestamp;
+	struct v4l2_timecode timecode;
+	bool last;
+};
+
+struct msg_itf_push_src_buf_req {
+	phys_addr_t hCodec;
+	phys_addr_t bufferHandle;
+	phys_addr_t phyAddr;
+	u64 size;
+	struct al_buffer_meta meta;
+} __packed;
+DECLARE_FULL_REQ(msg_itf_push_src_buf_req);
+
+struct msg_itf_push_dst_buf_req {
+	phys_addr_t hCodec;
+	phys_addr_t bufferHandle;
+	phys_addr_t phyAddr;
+	u64 size;
+} __packed;
+DECLARE_FULL_REQ(msg_itf_push_dst_buf_req);
+
+struct msg_itf_push_buffer_req {
+	phys_addr_t hCodec;
+	phys_addr_t bufferHandle;
+	phys_addr_t phyAddr;
+	u64 size;
+} __packed;
+DECLARE_FULL_REQ(msg_itf_push_buffer_req);
+
+struct msg_itf_push_buffer_reply {
+	s32 res;
+} __packed;
+DECLARE_FULL_REPLY(msg_itf_push_buffer_reply);
+
+struct msg_itf_info_req {
+	u64 unused;
+} __packed;
+DECLARE_FULL_REQ(msg_itf_info_req);
+
+struct msg_itf_flush_req {
+	phys_addr_t hCodec;
+} __packed;
+DECLARE_FULL_REQ(msg_itf_flush_req);
+
+struct msg_itf_flush_reply {
+	int32_t unused;
+} __packed;
+DECLARE_FULL_REPLY(msg_itf_flush_reply);
+
+struct msg_itf_evt_error {
+	uint32_t errno;
+} __packed;
+DECLARE_FULL_EVENT(msg_itf_evt_error);
+
+struct al_match_data {
+	const char *fw_name;
+};
+
+struct al_common_mcu_req {
+	phys_addr_t pCtx;
+	int req_type;
+	size_t req_size;
+	size_t reply_size;
+	void *reply;
+} __packed;
+
+struct al_firmware_section {
+	u64 offset;
+	size_t size;
+};
+
+struct al_firmware {
+	/* Firmware after it is read but not loaded */
+	const struct firmware *firmware;
+
+	/* Raw firmware data */
+	dma_addr_t phys;
+	void *virt;
+	size_t size;
+
+	/* Parsed firmware information */
+	struct al_firmware_section bin_data;
+	struct al_firmware_section mb_m2h;
+	struct al_firmware_section mb_h2m;
+};
+
+struct al_codec_dev {
+	struct platform_device *pdev;
+	struct v4l2_device v4l2_dev;
+	struct v4l2_m2m_dev *m2m_dev;
+	struct video_device video_dev;
+
+	/* Firmware */
+	struct al_firmware firmware;
+	dma_addr_t apb;
+
+	struct clk *clk;
+	void __iomem *regs;
+	struct resource *regs_info;
+	u64 offset;
+
+	/* Mailbox structs */
+	struct al_codec_mb mb_h2m;
+	struct al_codec_mb mb_m2h;
+
+	/* list of buffers used by the MCU */
+	struct list_head alloc_buffers;
+	struct mutex buf_lock;
+
+	/* mutex protecting vb2_queue structure */
+	struct mutex lock;
+
+	/* list of ctx (aka decoder) */
+	struct mutex ctx_mlock;
+	struct list_head ctx_q_list;
+	struct al_codec_dbgfs dbgfs;
+	u64 ctx_counter;
+	bool init_done;
+
+	/* list of cap/out supported formats */
+	struct list_head codec_q_list;
+	struct al_codec_cmd *codec_info_cmd;
+
+	/* Command completion */
+	struct completion completion;
+	/* Resolution found completion */
+	struct completion res_done;
+
+	/* callbacks set by client before common_probe */
+	void *cb_arg;
+	void (*process_msg_cb)(void *cb_arg, struct msg_itf_header *hdr);
+	void (*fw_ready_cb)(void *cb_arg);
+};
+
+static inline int al_common_get_header(struct al_codec_dev *codec,
+				       struct msg_itf_header *hdr)
+{
+	return al_codec_msg_get_header(&codec->mb_m2h, hdr);
+}
+
+static inline int al_common_get_data(struct al_codec_dev *codec, char *data,
+				     int len)
+{
+	return al_codec_msg_get_data(&codec->mb_m2h, data, len);
+}
+
+static inline int al_common_skip_data(struct al_codec_dev *codec, int len)
+{
+	return al_common_get_data(codec, NULL, len);
+}
+
+int al_common_send(struct al_codec_dev *codec, struct msg_itf_header *hdr);
+int al_common_send_req_reply(struct al_codec_dev *codec,
+			     struct list_head *cmd_list,
+			     struct msg_itf_header *hdr,
+			     struct al_common_mcu_req *req);
+bool al_common_mcu_is_alive(struct al_codec_dev *codec);
+
+int al_common_probe(struct al_codec_dev *codec, const char *name);
+void al_common_remove(struct al_codec_dev *codec);
+
+#endif /*__AL_CODEC_COMMON__*/
diff --git a/drivers/media/platform/allegro-dvt/al300/al_codec_dbgfs.c b/drivers/media/platform/allegro-dvt/al300/al_codec_dbgfs.c
new file mode 100644
index 000000000000..9a9264d2aa22
--- /dev/null
+++ b/drivers/media/platform/allegro-dvt/al300/al_codec_dbgfs.c
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2025 Allegro DVT.
+ * Author: Yassine OUAISSA <yassine.ouaissa at allegrodvt.fr>
+ */
+
+#include <linux/debugfs.h>
+
+#include "al_codec_dbgfs.h"
+#include "al_vdec_drv.h"
+#include "al_codec_util.h"
+
+static void al_vdec_dbgfs_get_format_type(struct al_dec_ctx *ctx, char *buf,
+					  int *used, int total)
+{
+	struct al_frame *frame = &ctx->src;
+	int curr_len;
+
+	switch (frame->fmt->pixelformat) {
+	case V4L2_PIX_FMT_H264:
+		curr_len = snprintf(buf + *used, total - *used,
+				    "\toutput format: h264\n");
+		break;
+	case V4L2_PIX_FMT_HEVC:
+		curr_len = snprintf(buf + *used, total - *used,
+				    "\toutput format: hevc\n");
+		break;
+	case V4L2_PIX_FMT_JPEG:
+		curr_len = snprintf(buf + *used, total - *used,
+				    "\toutput format: jpeg\n");
+		break;
+	default:
+		curr_len = snprintf(buf + *used, total - *used,
+				    "\tunsupported output format: 0x%x\n",
+				    frame->fmt->pixelformat);
+	}
+	*used += curr_len;
+	frame = &ctx->dst;
+
+	switch (frame->fmt->pixelformat) {
+	case V4L2_PIX_FMT_NV12:
+		curr_len = snprintf(buf + *used, total - *used,
+				    "\tcapture format: NV12\n");
+		break;
+	case V4L2_PIX_FMT_NV16:
+		curr_len = snprintf(buf + *used, total - *used,
+				    "\tcapture format: NV16\n");
+		break;
+	case V4L2_PIX_FMT_P010:
+		curr_len = snprintf(buf + *used, total - *used,
+				    "\tcapture format: P010\n");
+		break;
+	case V4L2_PIX_FMT_YUV420:
+		curr_len = snprintf(buf + *used, total - *used,
+				    "\tcapture format: YUV420\n");
+		break;
+	case V4L2_PIX_FMT_YVU420:
+		curr_len = snprintf(buf + *used, total - *used,
+				    "\tcapture format: YVU420\n");
+		break;
+	default:
+		curr_len = snprintf(buf + *used, total - *used,
+				    "\tunsupported capture format: 0x%x\n",
+				    frame->fmt->pixelformat);
+	}
+	*used += curr_len;
+}
+
+static void al_vdec_dbgfs_get_help(char *buf, int *used, int total)
+{
+	int curr_len;
+
+	curr_len = snprintf(buf + *used, total - *used,
+			    "help: (1: echo -'info' > dec 2: cat dec)\n");
+	*used += curr_len;
+
+	curr_len = snprintf(buf + *used, total - *used,
+			    "\t-picinfo: get resolution\n");
+	*used += curr_len;
+
+	curr_len = snprintf(buf + *used, total - *used,
+			    "\t-format: get output & capture queue format\n");
+	*used += curr_len;
+}
+
+static ssize_t al_vdec_dbgfs_write(struct file *filp, const char __user *ubuf,
+				   size_t count, loff_t *ppos)
+{
+	struct al_codec_dev *codec = filp->private_data;
+	struct al_codec_dbgfs *dbgfs = &codec->dbgfs;
+
+	mutex_lock(&dbgfs->lock);
+	dbgfs->size = simple_write_to_buffer(dbgfs->buf, sizeof(dbgfs->buf),
+					     ppos, ubuf, count);
+	mutex_unlock(&dbgfs->lock);
+	if (dbgfs->size > 0)
+		return count;
+
+	return dbgfs->size;
+}
+
+static ssize_t al_vdec_dbgfs_read(struct file *filp, char __user *ubuf,
+				  size_t count, loff_t *ppos)
+{
+	struct al_codec_dev *codec = filp->private_data;
+	struct al_codec_dbgfs *dbgfs = &codec->dbgfs;
+	struct al_codec_dbgfs_ctx *dbgfs_ctx;
+	struct al_dec_ctx *ctx;
+	struct al_frame *frame;
+	int total_len = 200 * (dbgfs->ctx_count == 0 ? 1 : dbgfs->ctx_count);
+	int used_len = 0, curr_len, ret;
+	bool dbgfs_index[AL_VDEC_DBGFS_MAX] = { 0 };
+	char *buf = kmalloc(total_len, GFP_KERNEL);
+
+	if (!buf)
+		return -ENOMEM;
+
+	if (strstr(dbgfs->buf, "-help") || dbgfs->size == 1) {
+		al_vdec_dbgfs_get_help(buf, &used_len, total_len);
+		goto read_buffer;
+	}
+
+	if (strstr(dbgfs->buf, "-picinfo"))
+		dbgfs_index[AL_VDEC_DBGFS_PICINFO] = true;
+
+	if (strstr(dbgfs->buf, "-format"))
+		dbgfs_index[AL_VDEC_DBGFS_FORMAT] = true;
+
+	mutex_lock(&dbgfs->lock);
+	list_for_each_entry(dbgfs_ctx, &dbgfs->dbgfs_head, node) {
+		ctx = dbgfs_ctx->dec_ctx;
+		frame = &ctx->src;
+
+		curr_len = snprintf(buf + used_len, total_len - used_len,
+				    "inst[%lld]:\n ", ctx->id);
+		used_len += curr_len;
+
+		if (dbgfs_index[AL_VDEC_DBGFS_PICINFO]) {
+			curr_len = snprintf(buf + used_len,
+					    total_len - used_len,
+					    "\tOUTPUT: %dx%d\n", frame->width,
+					    frame->height);
+			used_len += curr_len;
+			frame = &ctx->dst;
+
+			curr_len = snprintf(buf + used_len,
+					    total_len - used_len,
+					    "\tCAPTURE: %dx%d\n", frame->width,
+					    frame->height);
+			used_len += curr_len;
+		}
+
+		if (dbgfs_index[AL_VDEC_DBGFS_FORMAT])
+			al_vdec_dbgfs_get_format_type(ctx, buf, &used_len,
+						      total_len);
+	}
+	mutex_unlock(&dbgfs->lock);
+read_buffer:
+	ret = simple_read_from_buffer(ubuf, count, ppos, buf, used_len);
+	kfree(buf);
+	return ret;
+}
+
+static const struct file_operations vdec_fops = {
+	.open = simple_open,
+	.write = al_vdec_dbgfs_write,
+	.read = al_vdec_dbgfs_read,
+};
+
+void al_codec_dbgfs_create(struct al_dec_ctx *ctx)
+{
+	struct al_codec_dbgfs_ctx *dbgfs_ctx;
+	struct al_codec_dev *codec = ctx->codec;
+
+	dbgfs_ctx = kzalloc(sizeof(*dbgfs_ctx), GFP_KERNEL);
+	if (!dbgfs_ctx)
+		return;
+
+	list_add_tail(&dbgfs_ctx->node, &codec->dbgfs.dbgfs_head);
+
+	codec->dbgfs.ctx_count++;
+
+	dbgfs_ctx->ctx_id = ctx->id;
+	dbgfs_ctx->dec_ctx = ctx;
+}
+
+void al_codec_dbgfs_remove(struct al_codec_dev *codec, int ctx_id)
+{
+	struct al_codec_dbgfs_ctx *dbgfs_ctx;
+
+	list_for_each_entry(dbgfs_ctx, &codec->dbgfs.dbgfs_head, node) {
+		if (dbgfs_ctx->ctx_id == ctx_id) {
+			codec->dbgfs.ctx_count--;
+			list_del(&dbgfs_ctx->node);
+			kfree(dbgfs_ctx);
+			return;
+		}
+	}
+}
+
+static void al_codec_dbgfs_vdec_init(struct al_codec_dev *codec)
+{
+	struct dentry *vcodec_root;
+
+	codec->dbgfs.vcodec_root = debugfs_create_dir("al-vdec", NULL);
+	if (IS_ERR(codec->dbgfs.vcodec_root))
+		dev_err(&codec->pdev->dev, "create al-vdec dir err:%ld\n",
+			PTR_ERR(codec->dbgfs.vcodec_root));
+
+	vcodec_root = codec->dbgfs.vcodec_root;
+	debugfs_create_x32("al_v4l2_dbg_level", 0644, vcodec_root,
+			   &al_v4l2_dbg_level);
+	debugfs_create_x32("al_codec_dbg", 0644, vcodec_root, &al_codec_dbg);
+
+	codec->dbgfs.ctx_count = 0;
+	INIT_LIST_HEAD(&codec->dbgfs.dbgfs_head);
+	debugfs_create_file("vdec", 0200, vcodec_root, codec, &vdec_fops);
+	mutex_init(&codec->dbgfs.lock);
+}
+
+void al_codec_dbgfs_init(void *codec)
+{
+	al_codec_dbgfs_vdec_init(codec);
+}
+
+void al_codec_dbgfs_deinit(struct al_codec_dbgfs *dbgfs)
+{
+	debugfs_remove_recursive(dbgfs->vcodec_root);
+}
diff --git a/drivers/media/platform/allegro-dvt/al300/al_codec_dbgfs.h b/drivers/media/platform/allegro-dvt/al300/al_codec_dbgfs.h
new file mode 100644
index 000000000000..0f205e505308
--- /dev/null
+++ b/drivers/media/platform/allegro-dvt/al300/al_codec_dbgfs.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2025 Allegro DVT.
+ * Author: Yassine OUAISSA <yassine.ouaissa at allegrodvt.fr>
+ */
+
+#ifndef __AL_CODEC_DBGFS_H__
+#define __AL_CODEC_DBGFS_H__
+
+struct al_codec_dev;
+struct al_dec_ctx;
+
+/*
+ * enum al_vdec_dbgfs_log_index  - used to get different debug information
+ */
+enum al_vdec_dbgfs_log_index {
+	AL_VDEC_DBGFS_PICINFO,
+	AL_VDEC_DBGFS_FORMAT,
+	AL_VDEC_DBGFS_MAX,
+};
+
+/**
+ * struct al_codec_dbgfs_ctx  - debugfs information for each context
+ * @node:       list node for each inst
+ * @dec_ctx:	struct al_dec_ctx
+ * @ctx_id:     index of the context that the same with ctx->id
+ */
+struct al_codec_dbgfs_ctx {
+	struct list_head node;
+	struct al_dec_ctx *dec_ctx;
+	int ctx_id;
+};
+
+/**
+ * struct al_codec_dbgfs  - dbgfs information
+ * @dbgfs_head:  list head used to link each context
+ * @vcodec_root: codec dbgfs entry
+ * @lock:	 lock used to protect dbgfs_buf
+ * @buf:	 dbgfs buf used to store dbgfs cmd
+ * @size:	 dbgfs buffer size
+ * @ctx_count:   the count of total context
+ */
+struct al_codec_dbgfs {
+	struct list_head dbgfs_head;
+	struct dentry *vcodec_root;
+	struct mutex lock;
+	char buf[1024];
+	int size;
+	int ctx_count;
+};
+
+#if defined(CONFIG_DEBUG_FS)
+void al_codec_dbgfs_create(struct al_dec_ctx *ctx);
+void al_codec_dbgfs_remove(struct al_codec_dev *codec, int ctx_id);
+void al_codec_dbgfs_init(void *codec);
+void al_codec_dbgfs_deinit(struct al_codec_dbgfs *dbgfs);
+#else
+static inline void al_codec_dbgfs_create(struct al_dec_ctx *ctx)
+{
+}
+static inline void al_codec_dbgfs_remove(struct al_codec_dev *codec, int ctx_id)
+{
+}
+static inline void al_codec_dbgfs_init(void *codec)
+{
+}
+static inline void al_codec_dbgfs_deinit(struct al_codec_dbgfs *dbgfs)
+{
+}
+#endif /* CONFIG_DEBUG_FS */
+#endif /* __AL_CODEC_DBGFS_H__ */
diff --git a/drivers/media/platform/allegro-dvt/al300/al_codec_util.c b/drivers/media/platform/allegro-dvt/al300/al_codec_util.c
new file mode 100644
index 000000000000..f59fedae0491
--- /dev/null
+++ b/drivers/media/platform/allegro-dvt/al300/al_codec_util.c
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Mailbox communication utilities for command creation
+ * and message exchange with the MCU
+ *
+ * Copyright (c) 2025 Allegro DVT.
+ * Author: Yassine OUAISSA <yassine.ouaissa at allegrodvt.fr>
+ */
+
+#include <asm-generic/errno.h>
+#include <linux/errno.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+
+#include "al_codec_util.h"
+
+#if defined(CONFIG_DEBUG_FS)
+/* Log level */
+int al_v4l2_dbg_level;
+int al_codec_dbg;
+#endif
+
+static int al_get_used_space(struct al_codec_mb *mb)
+{
+	u32 head = mb->hdr->head;
+	u32 tail = mb->hdr->tail;
+
+	return head >= tail ? head - tail : mb->size - (tail - head);
+}
+
+static int al_get_free_space(struct al_codec_mb *mb)
+{
+	return mb->size - al_get_used_space(mb) - 1;
+}
+
+static int al_has_enough_space(struct al_codec_mb *mb, int len)
+{
+	return al_get_free_space(mb) >= len;
+}
+
+static inline void al_copy_to_mb(struct al_codec_mb *mb, char *data, int len)
+{
+	u32 head = mb->hdr->head;
+	int copy_len = min(mb->size - head, (unsigned int)len);
+	int copied_len = len;
+
+	memcpy(&mb->data[head], data, copy_len);
+	len -= copy_len;
+	if (len)
+		memcpy(&mb->data[0], &data[copy_len], len);
+
+	/* Make sure that all messages are written before updating the head */
+	dma_wmb();
+	mb->hdr->head = (head + copied_len) % mb->size;
+	/* Make sure that the head is updated in DDR instead of cache */
+	dma_wmb();
+}
+
+static inline void al_copy_from_mb(struct al_codec_mb *mb, char *data, int len)
+{
+	u32 tail = mb->hdr->tail;
+	int copy_len = min(mb->size - tail, (unsigned int)len);
+	int copied_len = len;
+
+	if (!data)
+		goto update_tail;
+
+	memcpy(data, &mb->data[tail], copy_len);
+	len -= copy_len;
+	if (len)
+		memcpy(&data[copy_len], &mb->data[0], len);
+
+update_tail:
+	mb->hdr->tail = (tail + copied_len) % mb->size;
+	/* Make sure that the head is updated in DDR instead of cache */
+	dma_wmb();
+}
+
+static int al_codec_mb_send(struct al_codec_mb *mb, char *data, int len)
+{
+	if (!al_has_enough_space(mb, len))
+		return -ENOMEM;
+
+	al_copy_to_mb(mb, data, len);
+
+	return 0;
+}
+
+static int al_codec_mb_receive(struct al_codec_mb *mb, char *data, int len)
+{
+	if (al_get_used_space(mb) < len)
+		return -ENOMEM;
+
+	al_copy_from_mb(mb, data, len);
+
+	return 0;
+}
+
+void al_codec_mb_init(struct al_codec_mb *mb, char *addr, int size, u32 magic)
+{
+	mb->hdr = (struct al_mb_itf *)addr;
+	mb->hdr->magic = magic;
+	mb->hdr->version = MB_IFT_VERSION;
+	mb->hdr->head = 0;
+	mb->hdr->tail = 0;
+	mb->data = addr + sizeof(struct al_mb_itf);
+	mb->size = size - sizeof(struct al_mb_itf);
+	mutex_init(&mb->lock);
+}
+
+int al_codec_msg_get_header(struct al_codec_mb *mb, struct msg_itf_header *hdr)
+{
+	return al_codec_mb_receive(mb, (char *)hdr, sizeof(*hdr));
+}
+
+int al_codec_msg_get_data(struct al_codec_mb *mb, char *data, int len)
+{
+	return al_codec_mb_receive(mb, data, len);
+}
+
+int al_codec_msg_send(struct al_codec_mb *mb, struct msg_itf_header *hdr,
+		      void (*trigger)(void *), void *trigger_arg)
+{
+	const unsigned long timeout = jiffies + HZ;
+	int ret;
+
+	guard(mutex)(&mb->lock);
+	do {
+		if (time_after(jiffies, timeout))
+			return -ETIMEDOUT;
+
+		ret = al_codec_mb_send(mb, (char *)hdr,
+				       hdr->payload_len +
+					       sizeof(struct msg_itf_header));
+
+	} while (ret);
+
+	trigger(trigger_arg);
+
+	return 0;
+}
+
+static void al_codec_cmd_cleanup(struct kref *ref)
+{
+	struct al_codec_cmd *cmd = container_of(ref, typeof(*cmd), refcount);
+
+	kfree(cmd->reply);
+	kfree(cmd);
+}
+
+void al_codec_cmd_put(struct al_codec_cmd *cmd)
+{
+	if (WARN_ON(!cmd))
+		return;
+
+	kref_put(&cmd->refcount, al_codec_cmd_cleanup);
+}
+
+struct al_codec_cmd *al_codec_cmd_create(int reply_size)
+{
+	struct al_codec_cmd *cmd;
+
+	cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
+	if (!cmd)
+		return NULL;
+
+	cmd->reply = kmalloc(reply_size, GFP_KERNEL);
+	if (!cmd->reply) {
+		kfree(cmd);
+		return NULL;
+	}
+
+	kref_init(&cmd->refcount);
+	cmd->reply_size = reply_size;
+	init_completion(&cmd->done);
+
+	return cmd;
+}
diff --git a/drivers/media/platform/allegro-dvt/al300/al_codec_util.h b/drivers/media/platform/allegro-dvt/al300/al_codec_util.h
new file mode 100644
index 000000000000..a4d50792dbd6
--- /dev/null
+++ b/drivers/media/platform/allegro-dvt/al300/al_codec_util.h
@@ -0,0 +1,196 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2025 Allegro DVT.
+ * Author: Yassine OUAISSA <yassine.ouaissa at allegrodvt.fr>
+ */
+
+#ifndef __AL_CODEC_UTIL__
+#define __AL_CODEC_UTIL__
+
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/v4l2-common.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-v4l2.h>
+
+#define MB_IFT_MAGIC_H2M 0xabcd1230
+#define MB_IFT_MAGIC_M2H 0xabcd1231
+#define MB_IFT_VERSION 0x00010000
+
+#define MAJOR_SHIFT 20
+#define MAJOR_MASK 0xfff
+#define MINOR_SHIFT 8
+#define MINOR_MASK 0xfff
+#define PATCH_SHIFT 0
+#define PATCH_MASK 0xff
+
+/*
+ * AL_BOOT_VERSION() - Version format 32-bit, 12 bits for the major,
+ * the same for minor, 8bits for the patch
+ */
+#define AL_BOOT_VERSION(major, minor, patch)       \
+	((((major) & MAJOR_MASK) << MAJOR_SHIFT) | \
+	 (((minor) & MINOR_MASK) << MINOR_SHIFT) | \
+	 (((patch) & PATCH_MASK) << PATCH_SHIFT))
+
+#define al_phys_to_virt(x) ((void *)(uintptr_t)x)
+#define al_virt_to_phys(x) ((phys_addr_t)(uintptr_t)x)
+
+#define DECLARE_FULL_REQ(s)                \
+	struct s##_full {                  \
+		struct msg_itf_header hdr; \
+		struct s req;              \
+	} __packed
+
+#define DECLARE_FULL_REPLY(s)              \
+	struct s##_full {                  \
+		struct msg_itf_header hdr; \
+		struct s reply;            \
+	} __packed
+
+#define DECLARE_FULL_EVENT(s)              \
+	struct s##_full {                  \
+		struct msg_itf_header hdr; \
+		struct s event;            \
+	} __packed
+
+struct al_mb_itf {
+	u32 magic;
+	u32 version;
+	u32 head;
+	u32 tail;
+} __packed;
+
+struct al_codec_mb {
+	struct al_mb_itf *hdr;
+	struct mutex lock;
+	char *data;
+	int size;
+};
+
+struct al_codec_cmd {
+	struct kref refcount;
+	struct list_head list;
+	struct completion done;
+	int reply_size;
+	void *reply;
+};
+
+#define al_codec_err(codec, fmt, args...)                                     \
+	dev_err(&(codec)->pdev->dev, "[ALG_CODEC][ERROR] %s():%d: " fmt "\n", \
+		__func__, __LINE__, ##args)
+
+#define al_v4l2_err(codec, fmt, args...)                                     \
+	dev_err(&(codec)->pdev->dev, "[ALG_V4L2][ERROR] %s():%d: " fmt "\n", \
+		__func__, __LINE__, ##args)
+
+#if defined(CONFIG_DEBUG_FS)
+/* Log level */
+extern int al_v4l2_dbg_level;
+extern int al_codec_dbg;
+
+/* V4L2 logs */
+#define al_v4l2_dbg(codec, level, fmt, args...)                           \
+	do {                                                              \
+		if (al_v4l2_dbg_level >= level)                           \
+			dev_dbg(&(codec)->pdev->dev,                      \
+				"[ALG_V4L2] level=%d %s(),%d: " fmt "\n", \
+				level, __func__, __LINE__, ##args);       \
+	} while (0)
+
+/* Codec logs */
+#define al_codec_dbg(codec, fmt, args...)                                   \
+	do {                                                                \
+		if (al_codec_dbg)                                           \
+			dev_dbg(&(codec)->pdev->dev,                        \
+				"[ALG_CODEC] %s(),%d: " fmt "\n", __func__, \
+				__LINE__, ##args);                          \
+	} while (0)
+
+#define al_mcu_dbg(codec, fmt, args...)                                   \
+	do {                                                              \
+		if (al_codec_dbg)                                         \
+			dev_dbg(&(codec)->pdev->dev,                      \
+				"[ALG_MCU] %s(),%d: " fmt "\n", __func__, \
+				__LINE__, ##args);                        \
+	} while (0)
+
+#else
+
+#define al_v4l2_dbg(codec, level, fmt, args...)                                \
+	do {                                                                   \
+		(void)level;                                                   \
+		dev_dbg(&(codec)->pdev->dev, "[ALG_V4L2]: " fmt "\n", ##args); \
+	} while (0)
+
+#define al_codec_dbg(codec, fmt, args...) \
+	dev_dbg(&(codec)->pdev->dev, "[ALG_CODEC]: " fmt "\n", ##args)
+
+#define al_mcu_dbg(codec, fmt, args...) \
+	dev_dbg(&(codec)->pdev->dev, "[ALG_MCU]: " fmt "\n", ##args)
+
+#endif
+
+#define MSG_ITF_TYPE_LIMIT BIT(10)
+
+/* Message types host <-> mcu */
+enum {
+	MSG_ITF_TYPE_MCU_ALIVE = 0,
+	MSG_ITF_TYPE_WRITE_REQ = 2,
+	MSG_ITF_TYPE_FIRST_REQ = 1024,
+	MSG_ITF_TYPE_NEXT_REQ,
+	MSG_ITF_TYPE_FIRST_REPLY = 2048,
+	MSG_ITF_TYPE_NEXT_REPLY,
+	MSG_ITF_TYPE_ALLOC_MEM_REQ = 3072,
+	MSG_ITF_TYPE_FREE_MEM_REQ,
+	MSG_ITF_TYPE_ALLOC_MEM_REPLY = 4096,
+	MSG_ITF_TYPE_FREE_MEM_REPLY,
+	MSG_ITF_TYPE_FIRST_EVT = 5120,
+	MSG_ITF_TYPE_NEXT_EVT = MSG_ITF_TYPE_FIRST_EVT
+};
+
+struct msg_itf_header {
+	u64 drv_ctx_hdl;
+	u64 drv_cmd_hdl;
+	u16 type;
+	u16 payload_len;
+	u16 padding[2];
+} __packed;
+
+void al_codec_mb_init(struct al_codec_mb *mb, char *addr, int size, u32 magic);
+int al_codec_msg_get_header(struct al_codec_mb *mb, struct msg_itf_header *hdr);
+int al_codec_msg_get_data(struct al_codec_mb *mb, char *data, int len);
+int al_codec_msg_send(struct al_codec_mb *mb, struct msg_itf_header *hdr,
+		      void (*trigger)(void *), void *trigger_arg);
+
+static inline bool is_type_reply(uint16_t type)
+{
+	return type >= MSG_ITF_TYPE_FIRST_REPLY &&
+	       type < MSG_ITF_TYPE_FIRST_REPLY + MSG_ITF_TYPE_LIMIT;
+}
+
+static inline bool is_type_event(uint16_t type)
+{
+	return type >= MSG_ITF_TYPE_FIRST_EVT &&
+	       type < MSG_ITF_TYPE_FIRST_EVT + MSG_ITF_TYPE_LIMIT;
+}
+
+void al_codec_cmd_put(struct al_codec_cmd *cmd);
+
+struct al_codec_cmd *al_codec_cmd_create(int reply_size);
+
+static inline struct al_codec_cmd *al_codec_cmd_get(struct list_head *cmd_list,
+						    uint64_t hdl)
+{
+	struct al_codec_cmd *cmd = NULL;
+
+	list_for_each_entry(cmd, cmd_list, list) {
+		if (likely(cmd == al_phys_to_virt(hdl))) {
+			kref_get(&cmd->refcount);
+			break;
+		}
+	}
+	return list_entry_is_head(cmd, cmd_list, list) ? NULL : cmd;
+}
+
+#endif /* __AL_CODEC_UTIL__ */
diff --git a/drivers/media/platform/allegro-dvt/al300/al_vdec_drv.c b/drivers/media/platform/allegro-dvt/al300/al_vdec_drv.c
new file mode 100644
index 000000000000..66303efd6984
--- /dev/null
+++ b/drivers/media/platform/allegro-dvt/al300/al_vdec_drv.c
@@ -0,0 +1,1514 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2025 Allegro DVT.
+ * Author: Yassine OUAISSA <yassine.ouaissa at allegrodvt.fr>
+ *
+ * Allegro DVT stateful video decoder driver for the IP Gen 3
+ */
+
+#include <asm-generic/errno-base.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/string.h>
+#include <linux/v4l2-controls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "al_vdec_drv.h"
+
+/* default decoder params */
+#define DECODER_WIDTH_DEFAULT 640
+#define DECODER_HEIGHT_DEFAULT 480
+#define DECODER_WIDTH_MAX 3840
+#define DECODER_HEIGHT_MAX 2160
+#define DECODER_WIDTH_MIN 16
+#define DECODER_HEIGHT_MIN 16
+#define DEC_REQ_TIMEOUT msecs_to_jiffies(1000)
+#define DEC_RES_EVT_TIMEOUT DEC_REQ_TIMEOUT
+
+/* Supported formats */
+static const struct al_fmt al_src_formats[] = {
+	{
+		.pixelformat = V4L2_PIX_FMT_H264,
+		.bpp = 20,
+	},
+	{
+		.pixelformat = V4L2_PIX_FMT_HEVC,
+		.bpp = 20,
+	},
+	{
+		.pixelformat = V4L2_PIX_FMT_JPEG,
+		.bpp = 8,
+	}
+};
+
+static const struct al_fmt al_dst_formats[] = {
+	{
+		.pixelformat = V4L2_PIX_FMT_NV12,
+		.bpp = 12,
+	},
+	{
+		.pixelformat = V4L2_PIX_FMT_P010,
+		.bpp = 12,
+	},
+	{
+		.pixelformat = V4L2_PIX_FMT_NV16,
+		.bpp = 16,
+	},
+	{
+		.pixelformat = V4L2_PIX_FMT_YUV420, /* YUV 4:2:0 */
+		.bpp = 12,
+	},
+	{
+		.pixelformat = V4L2_PIX_FMT_YVU420, /* YVU 4:2:0 */
+		.bpp = 12,
+	},
+};
+
+/* Default format */
+static const struct al_frame al_default_fmt = {
+
+	.width = DECODER_WIDTH_DEFAULT,
+	.height = DECODER_HEIGHT_DEFAULT,
+	.bytesperline = DECODER_WIDTH_MAX * 4,
+	.sizeimage = DECODER_WIDTH_DEFAULT * DECODER_HEIGHT_DEFAULT * 4,
+	.nbuffers = 1,
+	.fmt = &al_dst_formats[0],
+	.field = V4L2_FIELD_NONE,
+	.colorspace = V4L2_COLORSPACE_REC709,
+	.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT,
+	.quantization = V4L2_QUANTIZATION_DEFAULT,
+	.xfer_func = V4L2_XFER_FUNC_DEFAULT
+};
+
+static struct al_frame *al_get_frame(struct al_dec_ctx *ctx,
+				     enum v4l2_buf_type type)
+{
+	if (WARN_ON(!ctx))
+		return ERR_PTR(-EINVAL);
+
+	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return &ctx->src;
+	else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return &ctx->dst;
+
+	al_v4l2_err(ctx->codec, "Unsupported type (%d)", type);
+
+	return ERR_PTR(-EINVAL);
+}
+
+static const struct al_fmt *al_find_fmt(u32 pixelformat)
+{
+	const struct al_fmt *fmt;
+	unsigned int i;
+
+	/* check if the pixelformat exist in the src formats list */
+	for (i = 0; i < ARRAY_SIZE(al_src_formats); i++) {
+		fmt = &al_src_formats[i];
+		if (fmt->pixelformat == pixelformat)
+			return fmt;
+	}
+
+	/* check if the pixelformat exist in the dst formats list */
+	for (i = 0; i < ARRAY_SIZE(al_dst_formats); i++) {
+		fmt = &al_dst_formats[i];
+		if (fmt->pixelformat == pixelformat)
+			return fmt;
+	}
+
+	return NULL;
+}
+
+static int dec_fw_create_decoder(struct al_dec_ctx *ctx)
+{
+	struct msg_itf_create_decoder_req_full req;
+	struct msg_itf_create_codec_reply reply;
+	const struct al_frame *frame = &ctx->src;
+	struct al_common_mcu_req mreq = {
+		.pCtx = al_virt_to_phys(ctx),
+		.req_type = MSG_ITF_TYPE_CREATE_INST_REQ,
+		.req_size = sizeof(req.req),
+		.reply_size = sizeof(reply),
+		.reply = &reply,
+	};
+	int ret;
+
+	if (ctx->hDec) {
+		al_v4l2_dbg(ctx->codec, 3, "fw decoder already exist\n");
+		return 0;
+	}
+
+	req.req.codec = frame->fmt->pixelformat;
+
+	ret = al_common_send_req_reply(ctx->codec, &ctx->cmd_q_list, &req.hdr,
+				       &mreq);
+
+	if (!ret && !reply.ret)
+		ctx->hDec = reply.hCodec;
+	else if (reply.ret)
+		ret = -ENODEV;
+
+	return ret;
+}
+
+static void dec_fw_destroy_decoder(struct al_dec_ctx *ctx)
+{
+	struct msg_itf_destroy_codec_req_full req;
+	struct msg_itf_destroy_codec_reply reply;
+	struct al_common_mcu_req mreq = {
+		.req_type = MSG_ITF_TYPE_DESTROY_INST_REQ,
+		.pCtx = al_virt_to_phys(ctx),
+		.req_size = sizeof(req.req),
+		.reply_size = sizeof(reply),
+		.reply = &reply,
+	};
+	int ret;
+
+	if (WARN(!ctx->hDec, "NULL Decoder to destroy !"))
+		return;
+
+	al_v4l2_dbg(ctx->codec, 3, "Destroy decoder %lld ", ctx->hDec);
+
+	req.req.hCodec = ctx->hDec;
+
+	ret = al_common_send_req_reply(ctx->codec, &ctx->cmd_q_list, &req.hdr,
+				       &mreq);
+
+	if (!ret)
+		ctx->hDec = 0;
+}
+
+static int al_dec_fw_push_frame_buf(struct al_dec_ctx *ctx,
+				    struct vb2_v4l2_buffer *vbuf)
+{
+	struct msg_itf_push_dst_buf_req_full req;
+	struct v4l2_m2m_buffer *m2m_buf;
+	struct al_common_mcu_req mreq = {
+		.req_type = MSG_ITF_TYPE_PUT_DISPLAY_PICTURE_REQ,
+		.pCtx = al_virt_to_phys(ctx),
+		.req_size = sizeof(req.req),
+	};
+	int ret;
+
+	if (WARN(!vbuf, "NULL frame Buffer to push!!"))
+		return -EINVAL;
+
+	m2m_buf = container_of(vbuf, struct v4l2_m2m_buffer, vb);
+	req.req.hCodec = ctx->hDec;
+	req.req.bufferHandle = al_virt_to_phys(m2m_buf);
+	req.req.phyAddr = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0);
+	req.req.size = vb2_plane_size(&vbuf->vb2_buf, 0);
+
+	ret = al_common_send_req_reply(ctx->codec, &ctx->cmd_q_list, &req.hdr,
+				       &mreq);
+	if (ret)
+		al_v4l2_err(ctx->codec, "Failed to push frame buffer %p %d",
+			    m2m_buf, ret);
+
+	return ret;
+}
+
+static int al_dec_fw_push_bitstream_buf(struct al_dec_ctx *ctx,
+					struct vb2_v4l2_buffer *vbuf)
+{
+	struct msg_itf_push_src_buf_req_full req;
+	struct v4l2_m2m_buffer *m2m_buf;
+	struct al_common_mcu_req mreq = {
+		.req_type = MSG_ITF_TYPE_PUSH_BITSTREAM_BUFFER_REQ,
+		.pCtx = al_virt_to_phys(ctx),
+		.req_size = sizeof(req.req),
+	};
+	int ret;
+
+	if (WARN(!vbuf, "NULL Buffer to push!!"))
+		return -EINVAL;
+
+	m2m_buf = container_of(vbuf, struct v4l2_m2m_buffer, vb);
+	req.req.hCodec = ctx->hDec;
+	req.req.bufferHandle = al_virt_to_phys(m2m_buf);
+	req.req.phyAddr = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0);
+	req.req.size = vb2_plane_size(&vbuf->vb2_buf, 0);
+
+	/* Fill the v4l2 metadata*/
+	req.req.meta.timestamp = vbuf->vb2_buf.timestamp;
+	req.req.meta.timecode = vbuf->timecode;
+	req.req.meta.last = vbuf->flags & V4L2_BUF_FLAG_LAST;
+
+	ret = al_common_send_req_reply(ctx->codec, &ctx->cmd_q_list, &req.hdr,
+				       &mreq);
+	if (ret)
+		al_v4l2_err(ctx->codec, "Failed to push bitstream buffer %p %d",
+			    m2m_buf, ret);
+
+	return ret;
+}
+
+static int dec_fw_flush_req(struct al_dec_ctx *ctx)
+{
+	struct msg_itf_flush_req_full req;
+	struct msg_itf_flush_reply reply;
+	struct al_common_mcu_req mreq = {
+		.req_type = MSG_ITF_TYPE_FLUSH_REQ,
+		.pCtx = al_virt_to_phys(ctx),
+		.req_size = sizeof(req.req),
+		.reply_size = sizeof(reply),
+		.reply = &reply,
+	};
+	int ret;
+
+	req.req.hCodec = ctx->hDec;
+
+	ret = al_common_send_req_reply(ctx->codec, &ctx->cmd_q_list, &req.hdr,
+				       &mreq);
+
+	if (ret)
+		al_v4l2_err(ctx->codec, "Failed to flush the decoder %d", ret);
+
+	return ret;
+}
+
+static struct vb2_v4l2_buffer *al_dec_dequeue_buf(struct al_dec_ctx *ctx,
+						  uint64_t hdl,
+						  struct list_head *buffer_list)
+{
+	struct v4l2_m2m_buffer *buf, *tmp;
+	struct vb2_v4l2_buffer *ret = NULL;
+
+	guard(mutex)(&ctx->buf_q_mlock);
+	list_for_each_entry_safe(buf, tmp, buffer_list, list) {
+		if (buf == al_phys_to_virt(hdl)) {
+			list_del(&buf->list);
+			ret = &buf->vb;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static struct vb2_v4l2_buffer *al_dec_dequeue_src_buf(struct al_dec_ctx *ctx,
+						      uint64_t hdl)
+{
+	return al_dec_dequeue_buf(ctx, hdl, &ctx->stream_q_list);
+}
+
+static struct vb2_v4l2_buffer *al_dec_dequeue_dst_buf(struct al_dec_ctx *ctx,
+						      uint64_t hdl)
+{
+	return al_dec_dequeue_buf(ctx, hdl, &ctx->frame_q_list);
+}
+
+static void al_ctx_cleanup(struct kref *ref)
+{
+	struct al_dec_ctx *ctx = container_of(ref, struct al_dec_ctx, refcount);
+
+	kfree(ctx);
+}
+
+static struct al_dec_ctx *al_ctx_get(struct al_codec_dev *codec, uint64_t hdl)
+{
+	struct al_dec_ctx *ctx;
+	struct al_dec_ctx *ret = NULL;
+
+	guard(mutex)(&codec->ctx_mlock);
+	list_for_each_entry(ctx, &codec->ctx_q_list, list) {
+		if (ctx == al_phys_to_virt(hdl)) {
+			kref_get(&ctx->refcount);
+			ret = ctx;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static void al_ctx_put(struct al_dec_ctx *ctx)
+{
+	kref_put(&ctx->refcount, al_ctx_cleanup);
+}
+
+static int al_dec_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct al_dec_ctx *ctx = vb2_get_drv_priv(q);
+	struct al_codec_dev *codec = ctx->codec;
+
+	v4l2_m2m_update_start_streaming_state(ctx->fh.m2m_ctx, q);
+
+	if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+		struct v4l2_m2m_buffer *buf;
+		int ret;
+
+		if (list_empty(&ctx->stream_q_list)) {
+			al_v4l2_err(codec, "Empty stream list.");
+			return -EINVAL;
+		}
+
+		if (!al_common_mcu_is_alive(codec)) {
+			al_v4l2_err(codec, "Unable to ping the mcu");
+			return -ENODEV;
+		}
+
+		ret = dec_fw_create_decoder(ctx);
+		if (ret) {
+			al_v4l2_err(codec, "Unable to create the fw decoder %d",
+				    ret);
+			return ret;
+		}
+
+		/* Get the first vid-out queued buffer */
+		buf = list_first_entry(&ctx->stream_q_list,
+				       struct v4l2_m2m_buffer, list);
+
+		if (al_dec_fw_push_bitstream_buf(ctx, &buf->vb)) {
+			al_v4l2_err(codec,
+				    "Unable to push the bitstream buffer");
+			return -EINVAL;
+		}
+
+		/* Wait until the mcu detect the resolution of the stream */
+		ret = wait_for_completion_timeout(&ctx->res_done,
+						  DEC_RES_EVT_TIMEOUT);
+		if (!ret) {
+			al_v4l2_err(codec, "unsupported stream");
+			ctx->aborting = true;
+		}
+	}
+
+	return 0;
+}
+
+static void al_dec_stop_streaming_cap(struct al_dec_ctx *ctx)
+{
+	struct vb2_v4l2_buffer *vbuf;
+	struct v4l2_m2m_buffer *entry, *tmp;
+
+	mutex_lock(&ctx->buf_q_mlock);
+	if (!list_empty(&ctx->frame_q_list))
+		list_for_each_entry_safe(entry, tmp, &ctx->frame_q_list, list) {
+			list_del(&entry->list);
+			vbuf = &entry->vb;
+			vb2_set_plane_payload(&vbuf->vb2_buf, 0, 0);
+			v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
+		}
+	mutex_unlock(&ctx->buf_q_mlock);
+
+	while (v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)) {
+		vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+		if (vbuf) {
+			vb2_set_plane_payload(&vbuf->vb2_buf, 0, 0);
+			v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
+		}
+	}
+
+	v4l2_m2m_mark_stopped(ctx->fh.m2m_ctx);
+}
+
+static void al_dec_stop_streaming_out(struct al_dec_ctx *ctx)
+{
+	struct vb2_v4l2_buffer *vbuf;
+	struct v4l2_m2m_buffer *entry, *tmp;
+
+	mutex_lock(&ctx->buf_q_mlock);
+	if (!list_empty(&ctx->stream_q_list))
+		list_for_each_entry_safe(entry, tmp, &ctx->stream_q_list,
+					 list) {
+			list_del(&entry->list);
+			v4l2_m2m_buf_done(&entry->vb, VB2_BUF_STATE_ERROR);
+		}
+	mutex_unlock(&ctx->buf_q_mlock);
+
+	if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx)) {
+		while ((vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx)))
+			if (vbuf->vb2_buf.state == VB2_BUF_STATE_ACTIVE)
+				v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
+	}
+
+	dec_fw_destroy_decoder(ctx);
+}
+
+static void al_dec_stop_streaming(struct vb2_queue *q)
+{
+	struct al_dec_ctx *ctx = vb2_get_drv_priv(q);
+
+	v4l2_m2m_update_stop_streaming_state(ctx->fh.m2m_ctx, q);
+
+	/* Releasing the dst and src buffers */
+	ctx->stopped = true;
+
+	if (V4L2_TYPE_IS_OUTPUT(q->type))
+		al_dec_stop_streaming_out(ctx);
+	else
+		al_dec_stop_streaming_cap(ctx);
+}
+
+static int al_dec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+			      unsigned int *nplanes, unsigned int sizes[],
+			      struct device *alloc_devs[])
+{
+	struct al_dec_ctx *ctx = vb2_get_drv_priv(vq);
+	struct al_frame *format = al_get_frame(ctx, vq->type);
+
+	if (IS_ERR(format)) {
+		al_v4l2_err(ctx->codec, "Invalid format %p", format);
+		return PTR_ERR(format);
+	}
+
+	if (*nplanes)
+		return ((sizes[0] < format->sizeimage) ? -EINVAL : 0);
+
+	/* update queue num buffers */
+	format->nbuffers = max(*nbuffers, format->nbuffers);
+
+	*nplanes = 1;
+	sizes[0] = format->sizeimage;
+	*nbuffers = format->nbuffers;
+
+	al_v4l2_dbg(ctx->codec, 2, "%s: Get %d buffers of size %d each ",
+		    (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ? "OUT" : "CAP",
+		    *nbuffers, sizes[0]);
+
+	return 0;
+}
+
+static int al_dec_buf_prepare(struct vb2_buffer *vb)
+{
+	struct al_dec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+	if (ctx->aborting)
+		return -EINVAL;
+
+	if (V4L2_TYPE_IS_CAPTURE(vb->type)) {
+		if (vbuf->field == V4L2_FIELD_ANY)
+			vbuf->field = V4L2_FIELD_NONE;
+		if (vbuf->field != V4L2_FIELD_NONE)
+			return -EINVAL;
+	}
+
+	al_v4l2_dbg(ctx->codec, 3, "%s : Buffer (%p) prepared ",
+		    (V4L2_TYPE_IS_OUTPUT(vb->type) ? "OUT" : "CAP"), vbuf);
+
+	return 0;
+}
+
+static inline void al_dec_fill_bitstream(struct al_dec_ctx *ctx)
+{
+	struct vb2_v4l2_buffer *src_buf;
+	struct v4l2_m2m_buffer *m2m_buf;
+	struct vb2_queue *src_vq;
+
+	lockdep_assert_held(&ctx->buf_q_mlock);
+
+	if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) {
+		src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+		if (!src_buf)
+			return;
+
+		/* Dump empty buffers */
+		if (!vb2_get_plane_payload(&src_buf->vb2_buf, 0)) {
+			src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+			v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
+			return;
+		}
+
+		src_vq = v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx);
+		src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+
+		if (src_buf) {
+			src_buf->sequence = ctx->osequence++;
+
+			if (vb2_is_streaming(src_vq) &&
+			    al_dec_fw_push_bitstream_buf(ctx, src_buf)) {
+				v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
+				return;
+			}
+
+			m2m_buf = container_of(src_buf, struct v4l2_m2m_buffer,
+					       vb);
+			list_add_tail(&m2m_buf->list, &ctx->stream_q_list);
+		}
+	}
+}
+
+static void al_dec_buf_queue(struct vb2_buffer *vb)
+{
+	struct al_dec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+	v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
+
+	if (V4L2_TYPE_IS_OUTPUT(vb->type)) {
+		mutex_lock(&ctx->buf_q_mlock);
+		al_dec_fill_bitstream(ctx);
+		mutex_unlock(&ctx->buf_q_mlock);
+	}
+
+	al_v4l2_dbg(ctx->codec, 3, "%s queued (%p) - (%d)",
+		    V4L2_TYPE_IS_OUTPUT(vb->type) ? "OUT" : "CAP", vbuf,
+		    vb->num_planes);
+}
+
+static const struct vb2_ops dec_queue_ops = {
+	.queue_setup = al_dec_queue_setup,
+	.buf_prepare = al_dec_buf_prepare,
+	.buf_queue = al_dec_buf_queue,
+	.start_streaming = al_dec_start_streaming,
+	.stop_streaming = al_dec_stop_streaming,
+	.wait_prepare = vb2_ops_wait_prepare,
+	.wait_finish = vb2_ops_wait_finish,
+};
+
+static int al_dec_queue_init(void *priv, struct vb2_queue *src_vq,
+			     struct vb2_queue *dst_vq)
+{
+	struct al_dec_ctx *ctx = priv;
+	struct al_codec_dev *codec = ctx->codec;
+	int ret;
+
+	src_vq->dev = &codec->pdev->dev;
+	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+	src_vq->non_coherent_mem = false;
+	src_vq->dma_attrs |= DMA_ATTR_FORCE_CONTIGUOUS;
+	src_vq->mem_ops = &vb2_dma_contig_memops;
+	src_vq->drv_priv = ctx;
+	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	src_vq->ops = &dec_queue_ops;
+	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	src_vq->lock = &ctx->codec->lock;
+	ret = vb2_queue_init(src_vq);
+	if (ret)
+		return ret;
+
+	dst_vq->dev = &codec->pdev->dev;
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+	dst_vq->non_coherent_mem = false;
+	dst_vq->dma_attrs |= DMA_ATTR_FORCE_CONTIGUOUS;
+	dst_vq->mem_ops = &vb2_dma_contig_memops;
+	dst_vq->drv_priv = ctx;
+	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	dst_vq->ops = &dec_queue_ops;
+	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	dst_vq->lock = &ctx->codec->lock;
+	ret = vb2_queue_init(dst_vq);
+	if (ret) {
+		vb2_queue_release(src_vq);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int al_dec_querycap(struct file *file, void *fh,
+			   struct v4l2_capability *cap)
+{
+	struct al_codec_dev *codec = video_drvdata(file);
+
+	strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
+	strscpy(cap->card, "Allegro DVT Video Decoder", sizeof(cap->card));
+	snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+		 dev_name(&codec->pdev->dev));
+
+	return 0;
+}
+
+static int al_dec_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+	const struct al_fmt *fmt;
+
+	if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+	    f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (V4L2_TYPE_IS_OUTPUT(f->type)) {
+		if (f->index >= ARRAY_SIZE(al_src_formats))
+			return -EINVAL;
+
+		fmt = &al_src_formats[f->index];
+	} else {
+		if (f->index >= ARRAY_SIZE(al_dst_formats))
+			return -EINVAL;
+
+		fmt = &al_dst_formats[f->index];
+	}
+
+	f->pixelformat = fmt->pixelformat;
+	return 0;
+}
+
+static int al_dec_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
+{
+	struct al_dec_ctx *ctx = fh_to_ctx(fh, struct al_dec_ctx);
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	struct al_frame *pix_fmt;
+
+	pix_fmt = al_get_frame(ctx, f->type);
+	if (IS_ERR(pix_fmt)) {
+		al_v4l2_err(ctx->codec, "Invalid frame (%p)", pix_fmt);
+		return PTR_ERR(pix_fmt);
+	}
+
+	pix_fmt->fmt = al_find_fmt(pix->pixelformat);
+	if (!pix_fmt->fmt) {
+		al_v4l2_err(ctx->codec, "Unknown format 0x%x",
+			    pix->pixelformat);
+		return -EINVAL;
+	}
+	pix->field = V4L2_FIELD_NONE;
+	pix->width = clamp_t(__u32, pix->width, DECODER_WIDTH_MIN,
+			     DECODER_WIDTH_MAX);
+	pix->height = clamp_t(__u32, pix->height, DECODER_HEIGHT_MIN,
+			      DECODER_HEIGHT_MAX);
+
+	pix->bytesperline = pix->width;
+	pix->sizeimage = (pix->width * pix->height * pix_fmt->fmt->bpp) / 8;
+
+	if (V4L2_TYPE_IS_CAPTURE(f->type))
+		if (pix->sizeimage < pix_fmt->sizeimage)
+			pix->sizeimage = pix_fmt->sizeimage;
+
+	al_v4l2_dbg(
+		ctx->codec, 3,
+		"%s : width (%d) , height (%d), bytesperline (%d), sizeimage (%d) ",
+		(f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ? "CAP" : "OUT",
+		pix->width, pix->height, pix->bytesperline, pix->sizeimage);
+
+	return 0;
+}
+
+static int al_dec_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
+{
+	struct al_dec_ctx *ctx = fh_to_ctx(fh, struct al_dec_ctx);
+	struct al_frame *pix_fmt = al_get_frame(ctx, f->type);
+	struct v4l2_pix_format *pix;
+
+	if (IS_ERR(pix_fmt)) {
+		al_v4l2_err(ctx->codec, "Invalid pixel format %p", pix_fmt);
+		return PTR_ERR(pix_fmt);
+	}
+
+	if (!pix_fmt->fmt) {
+		al_v4l2_err(ctx->codec, "Unknown format for %d", f->type);
+		return -EINVAL;
+	}
+
+	pix = &f->fmt.pix;
+	pix->width = pix_fmt->width;
+	pix->height = pix_fmt->height;
+	pix->bytesperline = pix_fmt->bytesperline;
+	pix->sizeimage = pix_fmt->sizeimage;
+	pix->pixelformat = pix_fmt->fmt->pixelformat;
+	pix->field = V4L2_FIELD_NONE;
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		pix->bytesperline = 0;
+
+	pix->ycbcr_enc = pix_fmt->ycbcr_enc;
+	pix->quantization = pix_fmt->quantization;
+	pix->xfer_func = pix_fmt->xfer_func;
+	pix->colorspace = pix_fmt->colorspace;
+
+	al_v4l2_dbg(
+		ctx->codec, 3,
+		"%s : width (%d) , height (%d), bytesperline (%d) , sizeimage (%d)",
+		(f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ? "CAP" : "OUT",
+		pix->width, pix->height, pix->bytesperline, pix->sizeimage);
+
+	return 0;
+}
+
+static int al_dec_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
+{
+	struct al_dec_ctx *ctx = fh_to_ctx(fh, struct al_dec_ctx);
+	struct v4l2_pix_format *pix;
+	struct al_frame *frame;
+	struct vb2_queue *vq;
+	int ret;
+
+	ret = al_dec_try_fmt(file, fh, f);
+	if (ret) {
+		al_v4l2_err(ctx->codec, "Cannot set format (%d)", f->type);
+		return ret;
+	}
+
+	frame = (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ? &ctx->src : &ctx->dst;
+
+	pix = &f->fmt.pix;
+	frame->fmt = al_find_fmt(pix->pixelformat);
+	if (!frame->fmt) {
+		al_v4l2_err(ctx->codec, "Unknown format for %d",
+			    pix->pixelformat);
+		return -EINVAL;
+	}
+
+	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+	if (vb2_is_streaming(vq)) {
+		al_v4l2_err(ctx->codec, "queue %d busy", f->type);
+		return -EBUSY;
+	}
+
+	frame->width = pix->width;
+	frame->height = pix->height;
+	frame->bytesperline = pix->bytesperline;
+	frame->sizeimage = pix->sizeimage;
+	frame->field = pix->field;
+
+	frame->ycbcr_enc = pix->ycbcr_enc;
+	frame->quantization = pix->quantization;
+	frame->xfer_func = pix->xfer_func;
+	frame->colorspace = pix->colorspace;
+
+	al_v4l2_dbg(
+		ctx->codec, 3,
+		" %s : width (%d) , height (%d), bytesperline (%d), sizeimage (%d)",
+		(f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ? "CAP" : "OUT",
+		pix->width, pix->height, pix->bytesperline, pix->sizeimage);
+
+	return 0;
+}
+
+static void al_queue_eos_event(struct al_dec_ctx *ctx)
+{
+	const struct v4l2_event eos_event = {
+		.id = 0,
+		.type = V4L2_EVENT_EOS,
+	};
+
+	v4l2_event_queue_fh(&ctx->fh, &eos_event);
+}
+
+static void al_queue_res_chg_event(struct al_dec_ctx *ctx)
+{
+	static const struct v4l2_event ev_src_ch = {
+		.id = 0,
+		.type = V4L2_EVENT_SOURCE_CHANGE,
+		.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
+	};
+
+	v4l2_event_queue_fh(&ctx->fh, &ev_src_ch);
+}
+
+static int al_dec_decoder_cmd(struct file *file, void *fh,
+			      struct v4l2_decoder_cmd *dcmd)
+{
+	struct al_dec_ctx *ctx = fh_to_ctx(fh, struct al_dec_ctx);
+	struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
+	struct vb2_v4l2_buffer *vbuf;
+	struct vb2_queue *dst_vq;
+	int ret;
+
+	ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dcmd);
+	if (ret)
+		return ret;
+
+	/* Get the vb2 queue for the Capture */
+	dst_vq = v4l2_m2m_get_dst_vq(m2m_ctx);
+
+	switch (dcmd->cmd) {
+	case V4L2_DEC_CMD_START:
+		vb2_clear_last_buffer_dequeued(dst_vq);
+		break;
+	case V4L2_DEC_CMD_STOP:
+		vbuf = v4l2_m2m_last_src_buf(m2m_ctx);
+		if (vbuf) {
+			al_v4l2_dbg(ctx->codec, 1,
+				    "marking last pending buffer");
+
+			vbuf->flags |= V4L2_BUF_FLAG_LAST;
+			if (v4l2_m2m_num_src_bufs_ready(m2m_ctx) == 0) {
+				al_v4l2_dbg(ctx->codec, 1,
+					    "all remaining buffers queued");
+				v4l2_m2m_try_schedule(m2m_ctx);
+			}
+		}
+		dec_fw_flush_req(ctx);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int al_dec_enum_framesizes(struct file *file, void *fh,
+				  struct v4l2_frmsizeenum *fsize)
+{
+	if (!al_find_fmt(fsize->pixel_format))
+		return -EINVAL;
+
+	/* FIXME : check step size */
+	fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+	fsize->stepwise.min_width = DECODER_WIDTH_MIN;
+	fsize->stepwise.max_width = DECODER_WIDTH_MAX;
+	fsize->stepwise.step_width = 8;
+	fsize->stepwise.min_height = DECODER_HEIGHT_MIN;
+	fsize->stepwise.max_height = DECODER_HEIGHT_MAX;
+	fsize->stepwise.step_height = 8;
+
+	return 0;
+}
+
+static int al_dec_subscribe_event(struct v4l2_fh *fh,
+				  const struct v4l2_event_subscription *sub)
+{
+	switch (sub->type) {
+	case V4L2_EVENT_EOS:
+		return v4l2_event_subscribe(fh, sub, 0, NULL);
+	case V4L2_EVENT_SOURCE_CHANGE:
+		return v4l2_src_change_event_subscribe(fh, sub);
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int al_dec_log_status(struct file *file, void *fh)
+{
+	struct al_codec_dev *codec = video_drvdata(file);
+
+	v4l2_device_call_all(&codec->v4l2_dev, 0, core, log_status);
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops al_dec_ioctl_ops = {
+	.vidioc_querycap = al_dec_querycap,
+	.vidioc_enum_fmt_vid_cap = al_dec_enum_fmt,
+	.vidioc_enum_fmt_vid_out = al_dec_enum_fmt,
+	.vidioc_g_fmt_vid_cap = al_dec_g_fmt,
+	.vidioc_g_fmt_vid_out = al_dec_g_fmt,
+	.vidioc_try_fmt_vid_cap = al_dec_try_fmt,
+	.vidioc_try_fmt_vid_out = al_dec_try_fmt,
+	.vidioc_s_fmt_vid_cap = al_dec_s_fmt,
+	.vidioc_s_fmt_vid_out = al_dec_s_fmt,
+
+	.vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+	.vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+
+	.vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+	.vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+	.vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+	.vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+	.vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+
+	.vidioc_streamon = v4l2_m2m_ioctl_streamon,
+	.vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+	.vidioc_log_status = al_dec_log_status,
+
+	.vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd,
+	.vidioc_decoder_cmd = al_dec_decoder_cmd,
+	.vidioc_enum_framesizes = al_dec_enum_framesizes,
+
+	.vidioc_subscribe_event = al_dec_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static void al_device_run(void *priv)
+{
+	struct al_dec_ctx *ctx = priv;
+	struct vb2_v4l2_buffer *dst_buf;
+	struct v4l2_m2m_buffer *m2m_buf;
+
+	if (unlikely(!ctx))
+		return;
+
+	if (ctx->aborting) {
+		vb2_queue_error(v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx));
+		vb2_queue_error(v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx));
+		return;
+	}
+
+	if (!v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx))
+		goto job_finish;
+
+	dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+	if (!dst_buf)
+		goto job_finish;
+
+	if (!al_common_mcu_is_alive(ctx->codec) ||
+	    al_dec_fw_push_frame_buf(ctx, dst_buf)) {
+		vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
+		v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
+		goto job_finish;
+	}
+
+	mutex_lock(&ctx->buf_q_mlock);
+	m2m_buf = container_of(dst_buf, struct v4l2_m2m_buffer, vb);
+	list_add_tail(&m2m_buf->list, &ctx->frame_q_list);
+	mutex_unlock(&ctx->buf_q_mlock);
+
+job_finish:
+	v4l2_m2m_job_finish(ctx->codec->m2m_dev, ctx->fh.m2m_ctx);
+}
+
+static const struct v4l2_m2m_ops al_dec_m2m_ops = {
+	.device_run = al_device_run,
+};
+
+static int al_dec_open(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct al_codec_dev *codec = video_get_drvdata(vdev);
+	struct al_dec_ctx *ctx = NULL;
+	int ret;
+
+	if (mutex_lock_interruptible(&codec->ctx_mlock))
+		return -ERESTARTSYS;
+
+	/* Aloocate memory for the dec ctx */
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx) {
+		ret = -ENOMEM;
+		goto unlock;
+	}
+
+	ctx->codec = codec;
+	/* Init ctx mutex */
+	mutex_init(&ctx->buf_q_mlock);
+	/* Init ctx LISTHEADs*/
+	INIT_LIST_HEAD(&ctx->cmd_q_list);
+	INIT_LIST_HEAD(&ctx->frame_q_list);
+	INIT_LIST_HEAD(&ctx->stream_q_list);
+
+	/* Init the irq queue */
+	init_completion(&ctx->res_done);
+
+	v4l2_fh_init(&ctx->fh, vdev);
+
+	v4l2_ctrl_handler_init(&ctx->ctrl_handler, 0);
+	if (ctx->ctrl_handler.error) {
+		ret = ctx->ctrl_handler.error;
+		al_v4l2_err(codec, "Failed to create control %d", ret);
+		goto handler_error;
+	}
+
+	ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+	v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+
+	file->private_data = &ctx->fh;
+	v4l2_fh_add(&ctx->fh, file);
+
+	/* Set default formats */
+	ctx->src = ctx->dst = al_default_fmt;
+	ctx->csequence = ctx->osequence = 0;
+
+	ctx->stopped = false;
+	ctx->aborting = false;
+	ctx->id = codec->ctx_counter++;
+
+	/* Setup the ctx for m2m mode */
+	ctx->fh.m2m_ctx =
+		v4l2_m2m_ctx_init(codec->m2m_dev, ctx, al_dec_queue_init);
+	if (IS_ERR(ctx->fh.m2m_ctx)) {
+		ret = PTR_ERR(ctx->fh.m2m_ctx);
+		al_v4l2_err(codec, "Failed to initialize m2m mode %d", ret);
+		goto error_ctrls;
+	}
+
+	v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true);
+
+	/* Add ctx to the LIST */
+	kref_init(&ctx->refcount);
+	list_add(&ctx->list, &codec->ctx_q_list);
+	al_codec_dbgfs_create(ctx);
+
+	mutex_unlock(&codec->ctx_mlock);
+
+	return 0;
+
+error_ctrls:
+	v4l2_fh_del(&ctx->fh, file);
+handler_error:
+	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+	v4l2_fh_exit(&ctx->fh);
+	kfree(ctx);
+
+unlock:
+	mutex_unlock(&codec->ctx_mlock);
+	return ret;
+}
+
+static int al_dec_release(struct file *file)
+{
+	struct al_dec_ctx *ctx =
+		fh_to_ctx(file->private_data, struct al_dec_ctx);
+	struct al_codec_dev *codec = ctx->codec;
+
+	guard(mutex)(&codec->ctx_mlock);
+
+	/* It is important to do this before removing ctx from dev list.
+	 * Those commands will trigger some traffic towards fw and so we
+	 * need completion to avoid deadlock if cmds can't find ctx.
+	 */
+	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+	v4l2_fh_del(&ctx->fh, file);
+	v4l2_fh_exit(&ctx->fh);
+
+	list_del(&ctx->list);
+	al_codec_dbgfs_remove(codec, ctx->id);
+	al_ctx_put(ctx);
+
+	return 0;
+}
+
+static inline bool al_mark_last_dst_buf(struct al_dec_ctx *ctx)
+{
+	struct vb2_v4l2_buffer *buf;
+	struct vb2_buffer *dst_vb;
+	struct vb2_queue *dst_vq;
+	unsigned long flags;
+
+	al_v4l2_dbg(ctx->codec, 1, "marking last capture buffer");
+
+	dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+	spin_lock_irqsave(&dst_vq->done_lock, flags);
+	if (list_empty(&dst_vq->done_list)) {
+		spin_unlock_irqrestore(&dst_vq->done_lock, flags);
+		return false;
+	}
+
+	dst_vb = list_last_entry(&dst_vq->done_list, struct vb2_buffer,
+				 done_entry);
+	buf = to_vb2_v4l2_buffer(dst_vb);
+	buf->flags |= V4L2_BUF_FLAG_LAST;
+
+	spin_unlock_irqrestore(&dst_vq->done_lock, flags);
+	return true;
+}
+
+static const struct v4l2_file_operations al_dec_file_ops = {
+	.owner = THIS_MODULE,
+	.open = al_dec_open,
+	.release = al_dec_release,
+	.poll = v4l2_m2m_fop_poll,
+	.unlocked_ioctl = video_ioctl2,
+	.mmap = v4l2_m2m_fop_mmap,
+};
+
+static void handle_error_evt(struct al_dec_ctx *ctx, struct msg_itf_header *hdr)
+{
+	struct al_codec_dev *codec = ctx->codec;
+	struct msg_itf_evt_error evt;
+	struct v4l2_m2m_buffer *vbuf;
+
+	if (al_common_get_data(codec, (char *)&evt, hdr->payload_len)) {
+		al_v4l2_err(codec, "Unable to get resolution found event");
+		return;
+	}
+
+	al_v4l2_err(codec, "Decoding error  %d", evt.errno);
+
+	guard(mutex)(&ctx->buf_q_mlock);
+	if (!list_empty(&ctx->stream_q_list)) {
+		vbuf = list_last_entry(&ctx->frame_q_list,
+				       struct v4l2_m2m_buffer, list);
+		list_del(&vbuf->list);
+		v4l2_m2m_buf_done(&vbuf->vb, VB2_BUF_STATE_ERROR);
+	}
+}
+
+static void handle_resolution_found_evt(struct al_dec_ctx *ctx,
+					struct msg_itf_header *hdr)
+{
+	struct msg_itf_evt_resolution_found evt;
+	struct al_codec_dev *codec = ctx->codec;
+	struct al_frame *frame;
+	struct vb2_queue *dst_vq;
+
+	if (al_common_get_data(codec, (char *)&evt, hdr->payload_len)) {
+		al_v4l2_err(codec, "Unable to get resolution found event");
+		return;
+	}
+
+	frame = &ctx->dst;
+
+	if (frame->width != evt.width || frame->height != evt.height ||
+	    frame->nbuffers < evt.buffer_nb) {
+		/* Update frame properties */
+		frame->width = evt.width;
+		frame->height = evt.height;
+		frame->bytesperline = evt.bytesperline;
+		frame->sizeimage = evt.sizeimage;
+		frame->nbuffers = evt.buffer_nb;
+		frame->fmt = al_find_fmt(evt.pixelformat);
+
+		/* This has to be changed */
+		if (!frame->fmt)
+			return;
+
+		al_queue_res_chg_event(ctx);
+	}
+
+	dst_vq = v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx);
+	if (!vb2_is_streaming(dst_vq))
+		complete(&ctx->res_done);
+
+	al_v4l2_dbg(
+		codec, 3,
+		"width(%d) , height(%d), bytesperline(%d), sizeimage(%d), n_bufs(%d)",
+		frame->width, frame->height, frame->bytesperline,
+		frame->sizeimage, frame->nbuffers);
+}
+
+static void handle_bitstream_buffer_release_evt(struct al_dec_ctx *ctx,
+						struct msg_itf_header *hdr)
+{
+	struct msg_itf_evt_bitstream_buffer_release evt;
+	struct al_codec_dev *codec = ctx->codec;
+	struct vb2_v4l2_buffer *vbuf;
+
+	if (al_common_get_data(codec, (char *)&evt, hdr->payload_len)) {
+		al_v4l2_err(codec, "Unable to get buffer release event");
+		return;
+	}
+
+	if (ctx->stopped)
+		return;
+
+	vbuf = al_dec_dequeue_src_buf(ctx, evt.bufferHandle);
+	if (!vbuf) {
+		al_v4l2_err(codec, "Unable to find bitsream buffer 0x%llx",
+			    evt.bufferHandle);
+		return;
+	}
+
+	al_v4l2_dbg(codec, 3, "Release bitstream buffer %p", vbuf);
+	v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
+}
+
+static void handle_eos_evt(struct al_dec_ctx *ctx, struct msg_itf_header *hdr)
+{
+	struct msg_itf_evt_frame_buffer_decode evt;
+	struct al_codec_dev *codec = ctx->codec;
+
+	if (al_common_get_data(codec, (char *)&evt, hdr->payload_len)) {
+		al_v4l2_err(codec, "Unable to get frame buffer event");
+		return;
+	}
+
+	/* set LAST_FLAG to the last done CAPTURE buffer*/
+	al_mark_last_dst_buf(ctx);
+	/* Set eos event */
+	al_queue_eos_event(ctx);
+}
+
+static void handle_frame_buffer_decode_evt(struct al_dec_ctx *ctx,
+					   struct msg_itf_header *hdr)
+{
+	struct msg_itf_evt_frame_buffer_decode evt;
+	struct al_codec_dev *codec = ctx->codec;
+	struct vb2_v4l2_buffer *vbuf;
+	struct al_buffer_meta *meta;
+
+	if (al_common_get_data(codec, (char *)&evt, hdr->payload_len)) {
+		al_v4l2_err(codec, "Unable to get frame buffer event");
+		return;
+	}
+
+	vbuf = al_dec_dequeue_dst_buf(ctx, evt.bufferHandle);
+	if (!vbuf) {
+		al_v4l2_err(codec, "Unable to find frame buffer 0x%llx",
+			    evt.bufferHandle);
+		return;
+	}
+
+	meta = &evt.meta;
+	al_v4l2_dbg(codec, 3, "Decoded frame done for buffer %p (%d) (%lld)",
+		    vbuf, meta->last, evt.size);
+
+	vb2_set_plane_payload(&vbuf->vb2_buf, 0, evt.size);
+	vbuf->field = V4L2_FIELD_NONE;
+	vbuf->sequence = ctx->csequence++;
+	vbuf->timecode = meta->timecode;
+	vbuf->vb2_buf.timestamp = meta->timestamp;
+
+	if (meta->last || (vbuf->flags & V4L2_BUF_FLAG_LAST)) {
+		vbuf->flags |= V4L2_BUF_FLAG_LAST;
+		v4l2_m2m_mark_stopped(ctx->fh.m2m_ctx);
+	}
+
+	v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
+}
+
+static int al_handle_cmd_reply(struct al_codec_dev *codec,
+			       struct msg_itf_header *hdr)
+{
+	struct al_dec_ctx *ctx;
+	struct al_codec_cmd *cmd = NULL;
+	int ret = 0;
+
+	ctx = al_ctx_get(codec, hdr->drv_ctx_hdl);
+	if (IS_ERR_OR_NULL(ctx)) {
+		al_v4l2_err(codec, "Unable to find ctx %p for reply %d",
+			    al_phys_to_virt(hdr->drv_ctx_hdl), hdr->type);
+		return -EINVAL;
+	}
+
+	cmd = al_codec_cmd_get(&ctx->cmd_q_list, hdr->drv_cmd_hdl);
+	if (!cmd) {
+		al_v4l2_err(codec, "Unable to find command %p for reply %d",
+			    al_phys_to_virt(hdr->drv_cmd_hdl), hdr->type);
+		ret = -EINVAL;
+		goto ctx_put;
+	}
+
+	if (cmd->reply_size != hdr->payload_len) {
+		al_v4l2_err(codec, "mismatch size %d %d", cmd->reply_size,
+			    hdr->payload_len);
+		ret = -EINVAL;
+		goto cmd_put;
+	}
+
+	ret = al_common_get_data(codec, cmd->reply, hdr->payload_len);
+	if (ret)
+		al_v4l2_err(codec, "Unable to copy reply");
+
+	complete(&cmd->done);
+	ret = 0;
+
+cmd_put:
+	al_codec_cmd_put(cmd);
+ctx_put:
+	al_ctx_put(ctx);
+
+	return ret;
+}
+
+static int al_handle_cmd_evt(struct al_codec_dev *dev,
+			     struct msg_itf_header *hdr, int type)
+{
+	static u32 evt_sizes[] = {
+		sizeof(struct msg_itf_evt_error),
+		sizeof(struct msg_itf_evt_resolution_found),
+		sizeof(struct msg_itf_evt_bitstream_buffer_release),
+		sizeof(struct msg_itf_evt_frame_buffer_decode),
+		sizeof(struct msg_itf_evt_eos),
+	};
+
+	u32 evt_size;
+	struct al_dec_ctx *ctx = NULL;
+	int ret = 0;
+
+	if (type < MSG_ITF_TYPE_NEXT_EVT || type > MSG_ITF_TYPE_END_EVT) {
+		al_v4l2_err(dev, "Unsupporting event type %d", type);
+		return -EINVAL;
+	}
+
+	ctx = al_ctx_get(dev, hdr->drv_ctx_hdl);
+	if (!ctx) {
+		al_v4l2_err(dev, "Unable to find ctx %p for evt %d",
+			    al_phys_to_virt(hdr->drv_ctx_hdl), type);
+		return -EINVAL;
+	}
+
+	// Check the received event size and the expected one
+	evt_size = evt_sizes[type - MSG_ITF_TYPE_NEXT_EVT];
+	if (hdr->payload_len != evt_size) {
+		al_v4l2_err(
+			dev,
+			"Invalid event size for client (%p) for evt (%d) : Got (%d), expected (%d)",
+			al_phys_to_virt(hdr->drv_ctx_hdl), type,
+			hdr->payload_len, evt_size);
+		ret = -EINVAL;
+		goto clean_ctx;
+	}
+
+	al_v4l2_dbg(dev, 3, "Event received from MCU (%d)", type);
+
+	switch (type) {
+	case MSG_ITF_TYPE_EVT_ERROR:
+		handle_error_evt(ctx, hdr);
+		break;
+	case MSG_ITF_TYPE_EVT_RESOLUTION_FOUND:
+		handle_resolution_found_evt(ctx, hdr);
+		break;
+	case MSG_ITF_TYPE_EVT_BITSTREAM_BUFFER_RELEASE:
+		handle_bitstream_buffer_release_evt(ctx, hdr);
+		break;
+	case MSG_ITF_TYPE_EVT_FRAME_BUFFER_DECODE:
+		handle_frame_buffer_decode_evt(ctx, hdr);
+		break;
+	case MSG_ITF_TYPE_EVT_EOS:
+		handle_eos_evt(ctx, hdr);
+		break;
+	default:
+		break;
+	}
+
+clean_ctx:
+	al_ctx_put(ctx);
+	return ret;
+}
+
+static void al_dec_process_msg(void *cb_arg, struct msg_itf_header *hdr)
+{
+	struct al_codec_dev *dev = cb_arg;
+	int ret;
+
+	if (is_type_reply(hdr->type))
+		ret = al_handle_cmd_reply(dev, hdr);
+	else if (is_type_event(hdr->type))
+		ret = al_handle_cmd_evt(dev, hdr, hdr->type);
+	else {
+		al_v4l2_err(dev, "Unsupported message type %d", hdr->type);
+		ret = -EINVAL;
+	}
+
+	if (ret) {
+		al_v4l2_err(dev, "Skip received data");
+		al_common_skip_data(dev, hdr->payload_len);
+	}
+}
+
+static const struct video_device al_videodev = {
+	.name = "allegro-decoder",
+	.fops = &al_dec_file_ops,
+	.ioctl_ops = &al_dec_ioctl_ops,
+	.minor = -1,
+	.release = video_device_release_empty,
+	.vfl_dir = VFL_DIR_M2M,
+	.device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
+};
+
+static void al_dec_register_v4l2(void *cb_arg)
+{
+	struct al_codec_dev *dev = cb_arg;
+	struct video_device *video_dev = NULL;
+	int ret;
+
+	ret = v4l2_device_register(&dev->pdev->dev, &dev->v4l2_dev);
+	if (ret) {
+		al_v4l2_err(dev, "Unable to register v4l2 device %d", ret);
+		return;
+	}
+
+	dev->m2m_dev = v4l2_m2m_init(&al_dec_m2m_ops);
+	if (IS_ERR(dev->m2m_dev)) {
+		ret = PTR_ERR(dev->m2m_dev);
+		al_v4l2_err(dev, "failed to init mem2mem device %d", ret);
+		goto v4l2_m2m_init_error;
+	}
+
+	video_dev = &dev->video_dev;
+	*video_dev = al_videodev;
+
+	video_dev->lock = &dev->lock;
+	video_dev->v4l2_dev = &dev->v4l2_dev;
+
+	video_set_drvdata(video_dev, dev);
+	ret = video_register_device(video_dev, VFL_TYPE_VIDEO, -1);
+	if (ret) {
+		al_v4l2_err(dev, "failed to register video device %d", ret);
+		goto video_register_device_error;
+	}
+
+	v4l2_info(&dev->v4l2_dev, "registered as /dev/video%d\n",
+		  dev->video_dev.num);
+
+	dev->init_done = true;
+
+	return;
+
+video_register_device_error:
+	v4l2_m2m_release(dev->m2m_dev);
+v4l2_m2m_init_error:
+	v4l2_device_unregister(&dev->v4l2_dev);
+}
+
+static int al_dec_probe(struct platform_device *pdev)
+{
+	struct al_codec_dev *codec;
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	const struct al_match_data *match_data;
+	const char *firmware;
+	int ret;
+
+	dev_info(dev, "Probing ...\n");
+
+	match_data = device_get_match_data(dev);
+	if (!match_data) {
+		dev_err(dev, "Missing device match data\n");
+		return -EINVAL;
+	}
+
+	codec = devm_kzalloc(dev, sizeof(*codec), GFP_KERNEL);
+	if (!codec)
+		return -ENOMEM;
+
+	codec->pdev = pdev;
+	codec->init_done = false;
+	codec->ctx_counter = 0;
+	mutex_init(&codec->lock);
+	mutex_init(&codec->ctx_mlock);
+	INIT_LIST_HEAD(&codec->ctx_q_list);
+
+	codec->cb_arg = codec;
+	codec->process_msg_cb = al_dec_process_msg;
+	codec->fw_ready_cb = al_dec_register_v4l2;
+
+	/* firmware-name is optional in DT */
+	of_property_read_string(np, "firmware-name", &firmware);
+	if (!firmware)
+		firmware = match_data->fw_name;
+
+	ret = al_common_probe(codec, firmware);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, codec);
+	al_codec_dbgfs_init(codec);
+	dev_info(dev, "Probing done successfully %p\n", codec);
+
+	return 0;
+}
+
+static void al_dec_remove(struct platform_device *pdev)
+{
+	struct al_codec_dev *dev = platform_get_drvdata(pdev);
+
+	dev_info(&pdev->dev, "remove %p\n", dev);
+
+	if (dev->init_done) {
+		video_unregister_device(&dev->video_dev);
+		if (dev->m2m_dev)
+			v4l2_m2m_release(dev->m2m_dev);
+		v4l2_device_unregister(&dev->v4l2_dev);
+	}
+	al_codec_dbgfs_deinit(&dev->dbgfs);
+	al_common_remove(dev);
+}
+
+static const struct al_match_data ald300_data = {
+	.fw_name = "al300-vdec.fw",
+};
+
+static const struct of_device_id __maybe_unused v4l2_al_dec_dt_match[] = {
+	{ .compatible = "allegro,al300-vdec", .data = &ald300_data },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, v4l2_al_dec_dt_match);
+
+static struct platform_driver al300_vdec_drv = {
+	.probe = al_dec_probe,
+	.remove = al_dec_remove,
+	.driver = {
+		.name = "al300_vdec",
+		.of_match_table = of_match_ptr(v4l2_al_dec_dt_match),
+	},
+};
+
+module_platform_driver(al300_vdec_drv);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:al300-vdec");
+MODULE_AUTHOR("Yassine OUAISSA <yassine.ouaissa at allegrodvt.com>");
+MODULE_DESCRIPTION("Allegro DVT V4l2 decoder driver gen 3");
diff --git a/drivers/media/platform/allegro-dvt/al300/al_vdec_drv.h b/drivers/media/platform/allegro-dvt/al300/al_vdec_drv.h
new file mode 100644
index 000000000000..a9f4818bcc94
--- /dev/null
+++ b/drivers/media/platform/allegro-dvt/al300/al_vdec_drv.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2025 Allegro DVT.
+ * Author: Yassine OUAISSA <yassine.ouaissa at allegrodvt.fr>
+ */
+
+#ifndef __AL_VDEC_DRV__
+#define __AL_VDEC_DRV__
+
+#include <media/v4l2-ctrls.h>
+#include <media/videobuf2-core.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "al_codec_common.h"
+
+enum {
+	MSG_ITF_TYPE_EVT_RESOLUTION_FOUND = MSG_ITF_TYPE_NEXT_EVT + 1,
+	MSG_ITF_TYPE_EVT_BITSTREAM_BUFFER_RELEASE,
+	MSG_ITF_TYPE_EVT_FRAME_BUFFER_DECODE,
+	MSG_ITF_TYPE_EVT_EOS,
+	/* Mark the end of the events list.*/
+	MSG_ITF_TYPE_END_EVT,
+};
+
+struct msg_itf_create_decoder_req {
+	unsigned int codec;
+} __packed;
+DECLARE_FULL_REQ(msg_itf_create_decoder_req);
+
+struct msg_itf_evt_resolution_found {
+	u16 buffer_nb;
+	u16 width;
+	u16 height;
+	u32 pixelformat;
+	u32 sizeimage;
+	u32 bytesperline;
+} __packed;
+DECLARE_FULL_EVENT(msg_itf_evt_resolution_found);
+
+struct msg_itf_evt_bitstream_buffer_release {
+	u64 bufferHandle;
+} __packed;
+DECLARE_FULL_EVENT(msg_itf_evt_bitstream_buffer_release);
+
+struct msg_itf_evt_frame_buffer_decode {
+	u64 bufferHandle;
+	u64 size;
+	struct al_buffer_meta meta;
+} __packed;
+DECLARE_FULL_EVENT(msg_itf_evt_frame_buffer_decode);
+
+struct msg_itf_evt_eos {
+	u32 unused;
+} __packed;
+DECLARE_FULL_EVENT(msg_itf_evt_eos);
+
+struct al_fmt {
+	u32 pixelformat;
+	u8 bpp;
+};
+
+struct al_frame {
+	u32 width;
+	u32 height;
+	u32 bytesperline;
+	u32 sizeimage;
+	u32 nbuffers;
+	const struct al_fmt *fmt;
+	enum v4l2_field field;
+	enum v4l2_colorspace colorspace;
+	enum v4l2_ycbcr_encoding ycbcr_enc;
+	enum v4l2_quantization quantization;
+	enum v4l2_xfer_func xfer_func;
+};
+
+struct al_dec_ctx {
+	struct al_codec_dev *codec;
+	struct v4l2_fh fh;
+	struct v4l2_ctrl_handler ctrl_handler;
+	struct kref refcount;
+	struct list_head list;
+	/* CAP and OUT frames */
+	struct al_frame src;
+	struct al_frame dst;
+	struct completion res_done; /* Resolution found event */
+	struct list_head cmd_q_list; /* Store active commands */
+	struct mutex buf_q_mlock;
+	struct list_head frame_q_list;
+	struct list_head stream_q_list;
+	u64 hDec;
+	u32 csequence;
+	u32 osequence;
+	u64 id;
+	bool stopped;
+	bool aborting;
+};
+
+#endif /*__AL_VDEC_DRV__*/

-- 
2.50.1




From maz at kernel.org  Mon Dec  8 07:53:41 2025
From: maz at kernel.org (Marc Zyngier)
Date: Mon, 08 Dec 2025 15:53:41 +0000
Subject: [PATCH 0/2] Enable GICv5 Legacy CPUIF trapping & fix TDIR cap test
In-Reply-To: <20251208152724.3637157-1-sascha.bischoff@arm.com>
References: <20251208152724.3637157-1-sascha.bischoff@arm.com>
Message-ID: <864iq1otq2.wl-maz@kernel.org>

On Mon, 08 Dec 2025 15:28:22 +0000,
Sascha Bischoff <Sascha.Bischoff at arm.com> wrote:
> 
> These changes address two trapping-related issues when running legacy
> (i.e. GICv3) guests on GICv5 hosts.
> 
> The first change enables the vgic_v3_cpuif_trap static branch on GICv5
> hosts with legacy support, if trapping is required. The missing enable
> was caught as part of debugging why UNDEFs were being injected into
> guests when the ICH_HCR_EL2.TC bit was set - the expected bahaviour
> was that KVM should handle the trapped accesses, with the guest
> remaining blissfully unaware.
> 
> The second change fixes the specific cause of the TC bit being set in
> the first place. The test for the ICH_HCR_EL2_TDIR cap was checking
> for GICv3 CPUIF support and returning false prior to checking for
> GICv5 Legacy support. The result was that on GICv5 hosts, the test
> always returned false, and therefore the TC bit was being set. The
> issue is fixed by reordering the checks to check for GICv5 Legacy
> support first.
> 
> These changes are based against kvmarm/next.
> 
> Thanks,
> Sascha
> 
> Sascha Bischoff (2):
>   KVM: arm64: gic: Enable GICv3 CPUIF trapping on GICv5 hosts if
>     required
>   KVM: arm64: Correct test for ICH_HCR_EL2_TDIR cap for GICv5 hosts
> 
>  arch/arm64/kernel/cpufeature.c |  8 ++++----
>  arch/arm64/kvm/vgic/vgic-v3.c  | 25 +++++++++++++++----------
>  arch/arm64/kvm/vgic/vgic-v5.c  |  2 ++
>  arch/arm64/kvm/vgic/vgic.h     |  1 +
>  4 files changed, 22 insertions(+), 14 deletions(-)

Thanks for the debugging, and putting this together!

Reviewed-by: Marc Zyngier <maz at kernel.org>

	M.

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


From linux at armlinux.org.uk  Mon Dec  8 07:59:49 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 8 Dec 2025 15:59:49 +0000
Subject: [PATCH 0/3] ARM: fix hash_name() and branch predictor issues
In-Reply-To: <20251208150840.92209-1-xieyuanbin1@huawei.com>
References: <aTbF009476Iufory@shell.armlinux.org.uk>
 <20251208150840.92209-1-xieyuanbin1@huawei.com>
Message-ID: <aTb19aN_8PNduyDY@shell.armlinux.org.uk>

On Mon, Dec 08, 2025 at 11:08:40PM +0800, Xie Yuanbin wrote:
> On Mon, 8 Dec 2025 12:34:27 +0000, Russell King wrote:
> > The first patch adds an additional check in __do_kernel_fault() to
> > detect this condition. This patch is a non-obvious dependency for the
> > next patch.
> >
> > The second patch handles faults above the top of userspace entirely
> > separately, meaning we have a simpler and more obvious fault path,
> > which avoids any possibility of taking any MM mutexes, which is the
> > cause of the hash_name() problem.
> >
> > The third patch moves harden_branch_predictor() out of
> > __do_user_fault() and to appropriate places in the parent functions.
> > The reason this has been avoided thus far is because do_page_fault()
> > can be a hot path (since it's used for page aging as well) but with
> > kernel address faults being handled by an entirely separate path,
> > this avoids adding to that overhead.
> 
> I don't have any objections to the first and second patches. However,
> for the third patch, I feel it complicates some things. It removes
> harden_branch_predictor() from __do_user_fault() and adds it to various
> previous calling points.
> 
> This seems to be solely for adapting to the scenario of do_alignment() &&
> user_mode(regs) && addr >= TASK_SIZE. Does this scenario really exist?

As explained in the other thread, alignment faults are the first thing
that are checked when enabled, before permission fauls, so we can end
up entering do_alignment() from userspace with an address in the
kernel address space.

However, there is a user accessible page above TASK_SIZE, that is the
vectors page which can have userspace helpers in. Userspace can read
from this page, and thus can perform unaligned loads to this page.

The system behaviour of unaligned loads has been configurable, ARMv4,
for example, had the ability to check for alignment faults and raise
this exception. If that was disabled, then unaligned loads would
load the equivalent 32-bit aligned address and rotate the data in
the register. Compilers knew about this, and would code for it,
which made it ABI. Later compilers stopped using that which cut down
on the unaligned loads that userspace issued. Modern CPUs (ARMv7)
tend to behave "sanely" in that unaligned loads are generally
supported in hardware.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From beata.michalska at arm.com  Mon Dec  8 08:17:30 2025
From: beata.michalska at arm.com (Beata Michalska)
Date: Mon, 8 Dec 2025 17:17:30 +0100
Subject: [PATCH v4 1/3] ACPI: CPPC: Factor out and export per-cpu
 cppc_perf_ctrs_in_pcc_cpu()
In-Reply-To: <20251203032422.3232957-2-zhanjie9@hisilicon.com>
References: <20251203032422.3232957-1-zhanjie9@hisilicon.com>
 <20251203032422.3232957-2-zhanjie9@hisilicon.com>
Message-ID: <aTb6Gvzvc9C7vnVP@arm.com>

On Wed, Dec 03, 2025 at 11:24:20AM +0800, Jie Zhan wrote:
> Factor out cppc_perf_ctrs_in_pcc_cpu() for checking whether per-cpu CPC
> regs are defined in PCC channels, and export it out for further use.
> 
> Signed-off-by: Jie Zhan <zhanjie9 at hisilicon.com>
> ---
>  drivers/acpi/cppc_acpi.c | 45 +++++++++++++++++++++-------------------
>  include/acpi/cppc_acpi.h |  5 +++++
>  2 files changed, 29 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
> index 3bdeeee3414e..aa80dbcf42c0 100644
> --- a/drivers/acpi/cppc_acpi.c
> +++ b/drivers/acpi/cppc_acpi.c
> @@ -1422,6 +1422,29 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
>  }
>  EXPORT_SYMBOL_GPL(cppc_get_perf_caps);
>  
> +bool cppc_perf_ctrs_in_pcc_cpu(unsigned int cpu)
> +{
> +	struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu);
> +	struct cpc_register_resource *ref_perf_reg;
> +
> +	/*
> +	 * If reference perf register is not supported then we should use the
> +	 * nominal perf value
> +	 */
> +	ref_perf_reg = &cpc_desc->cpc_regs[REFERENCE_PERF];
> +	if (!CPC_SUPPORTED(ref_perf_reg))
> +		ref_perf_reg = &cpc_desc->cpc_regs[NOMINAL_PERF];
> +
> +	if (CPC_IN_PCC(&cpc_desc->cpc_regs[DELIVERED_CTR]) ||
> +	    CPC_IN_PCC(&cpc_desc->cpc_regs[REFERENCE_CTR]) ||
> +	    CPC_IN_PCC(&cpc_desc->cpc_regs[CTR_WRAP_TIME]) ||
> +	    CPC_IN_PCC(ref_perf_reg))
> +		return true;
> +
> +	return false;
> +}
> +EXPORT_SYMBOL_GPL(cppc_perf_ctrs_in_pcc_cpu);
It is minor, but I would prefer the earlier version when we grab the reference
performance reg only when none of the other regs is in the PCC.

---
BR
Beata
> +
>  /**
>   * cppc_perf_ctrs_in_pcc - Check if any perf counters are in a PCC region.
>   *
> @@ -1436,27 +1459,7 @@ bool cppc_perf_ctrs_in_pcc(void)
>  	int cpu;
>  
>  	for_each_online_cpu(cpu) {
> -		struct cpc_register_resource *ref_perf_reg;
> -		struct cpc_desc *cpc_desc;
> -
> -		cpc_desc = per_cpu(cpc_desc_ptr, cpu);
> -
> -		if (CPC_IN_PCC(&cpc_desc->cpc_regs[DELIVERED_CTR]) ||
> -		    CPC_IN_PCC(&cpc_desc->cpc_regs[REFERENCE_CTR]) ||
> -		    CPC_IN_PCC(&cpc_desc->cpc_regs[CTR_WRAP_TIME]))
> -			return true;
> -
> -
> -		ref_perf_reg = &cpc_desc->cpc_regs[REFERENCE_PERF];
> -
> -		/*
> -		 * If reference perf register is not supported then we should
> -		 * use the nominal perf value
> -		 */
> -		if (!CPC_SUPPORTED(ref_perf_reg))
> -			ref_perf_reg = &cpc_desc->cpc_regs[NOMINAL_PERF];
> -
> -		if (CPC_IN_PCC(ref_perf_reg))
> +		if (cppc_perf_ctrs_in_pcc_cpu(cpu))
>  			return true;
>  	}
>  
> diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h
> index 13fa81504844..4bcdcaf8bf2c 100644
> --- a/include/acpi/cppc_acpi.h
> +++ b/include/acpi/cppc_acpi.h
> @@ -154,6 +154,7 @@ extern int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_ctrs);
>  extern int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls);
>  extern int cppc_set_enable(int cpu, bool enable);
>  extern int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps);
> +extern bool cppc_perf_ctrs_in_pcc_cpu(unsigned int cpu);
>  extern bool cppc_perf_ctrs_in_pcc(void);
>  extern unsigned int cppc_perf_to_khz(struct cppc_perf_caps *caps, unsigned int perf);
>  extern unsigned int cppc_khz_to_perf(struct cppc_perf_caps *caps, unsigned int freq);
> @@ -204,6 +205,10 @@ static inline int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps)
>  {
>  	return -EOPNOTSUPP;
>  }
> +static inline bool cppc_perf_ctrs_in_pcc_cpu(unsigned int cpu)
> +{
> +	return false;
> +}
>  static inline bool cppc_perf_ctrs_in_pcc(void)
>  {
>  	return false;
> -- 
> 2.33.0
> 


From sudeep.holla at arm.com  Mon Dec  8 08:30:00 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Mon, 8 Dec 2025 16:30:00 +0000
Subject: [PATCH 1/2] dt-bindings: firmware: arm,scmi: Document
 arm,poll-transport property
In-Reply-To: <06fc0557-6b7c-4092-aeec-e3e16bab2d72@mailbox.org>
References: <20251202-evasive-neon-rhino-d2745e@sudeepholla>
 <66257fcf-9024-454f-b776-4ba584963ebe@mailbox.org>
 <aS82GSN8c2SnRn4S@bogus>
 <8d773671-5e2e-4e21-ade6-2bf9a3b75066@mailbox.org>
 <20251203-thick-didactic-cockatoo-deaa1d@sudeepholla>
 <4ccbcffd-bcc7-478b-a525-a4a11e3092ee@mailbox.org>
 <20251204-calm-peacock-of-fantasy-6b8cbe@sudeepholla>
 <e25c690c-e74d-4641-a97e-8eae81a59168@mailbox.org>
 <20251205-winged-quizzical-pigeon-ed692d@sudeepholla>
 <06fc0557-6b7c-4092-aeec-e3e16bab2d72@mailbox.org>
Message-ID: <20251208-quixotic-cocky-emu-9a3916@sudeepholla>

On Sun, Dec 07, 2025 at 10:16:36AM +0100, Marek Vasut wrote:
> On 12/5/25 10:54 AM, Sudeep Holla wrote:
> 
> Hello Sudeep,
> 
> > > > > > Also IIUC, the irq request happens
> > > > > > as part of channel startup and there are no explicit APIs for the mbox client
> > > > > > driver to control that. SCMI is mbox client in this case.
> > > > > 
> > > > > Sure, but the mailbox driver has to make sure it is correctly demuxing the
> > > > > IRQs it handles and correctly sends received_data notifications to the right
> > > > > channel(s) .
> > > > > 
> > > > 
> > > > Agreed, but the concern is that if SCMI is forced to use polling when the
> > > > channel is opened, and IRQs are enabled by default with no way for SCMI to
> > > > disable them in polling mode, we could run into issues.
> > > 
> > > This constellation seems odd -- if the channel can do IRQs, then this
> > > property should not be present in DT.
> > > 
> > 
> > Yes, but there is no way to validate or check this and that is the root
> > cause for all my worries.
> 
> Should a configuration like that even be considered valid and relevant ?
> 

Yes, as I have mentioned, there is no way to validate the same in the kernel.

> > > > I realise it?s a very
> > > > specific corner case, but every time I?ve assumed such scenarios wouldn?t
> > > > occur, we eventually ended up encountering them. So sorry if I am very
> > > > pedantic, but I prefer to start smaller and restrictive and expand if and
> > > > when necessary or required only.
> > > 
> > > I don't think this case, where mailbox channel does IRQs and polling is
> > > enabled, can/should even be considered valid. Either the channel does not do
> > > IRQs and then it should do polling, or it does IRQs and then it should use
> > > IRQs, but not both.
> > > 
> > 
> > Yes ideally, but having loose ends like this binding which allows someone
> > to add it to their DT complicates though it is invalid. We have no way to
> > detect and I don't want to work around such configs in the future.
> 
> If the DT is invalid, bad things happen, but I would argue that is then a DT
> bug and the DT should be fixed.
> 

Well, ideally I would like that, but not always the reality.

> [...]
> 
> > > > Yes, that?s essential, because polling in an SMC context is meaningless in my
> > > > opinion.
> > > 
> > > Maybe the "a2p" IRQ is also used for notifications from longer running
> > > operations ?
> > > 
> > 
> > Yes, it is some sort of work around some platforms implemented as by design
> > when the SMC returns, the synchronous commands must complete and it is had
> > to support async SCMI commands without platform specific interrupt(p2a). This
> > a2p is sort of completion interrupt for synchronous command. I assume the
> > platform may offload the task from secure f/w to something else otherwise
> > secure side needs to be given CPU cycles to complete which complicates this.
> > In short SMC is synchronous and if the execution returns from it in NS world,
> > the command is complete.
> 
> Wouldn't polling still be useful for the async case , even in SMC setup?
> Note that the SMC setup does use shmem, and therefore can do polling on the
> shmem.
> 

No, it makes no sense for SMC as I have already mentioned few times.

> > > [...]
> > > 
> > > > > > Yes it can be minimalistic but not restrictive. As I already clearly mentioned
> > > > > > I don't see it makes any sense to enable this for SMC/OPTEE. Lets start with
> > > > > > just mailbox to start with and extend to other transports if and when needed.
> > > > > > It would be good to impose that restriction in the binding as well but that
> > > > > > is not a must IMO. I am fine if the bindings for whatever reasons(though I
> > > > > > don't see the need) to apply for any transport.
> > > > > So I should simply drop the smc.c changes , keep the rest, and send V2 ?
> > > > 
> > > > Not just that. Unless DT maintainers oppose, I just want to keep this
> > > > new property valid only for mailbox transport(i.e. "arm,scmi" compatible
> > > > not otherwise) so that we can catch any other use in binding checks and
> > > > interested parties must discuss on the list and expand that if they require.
> > > > 
> > > > Also we can explore if we can parse and scan this in mailbox transport for
> > > > now.
> > > I feel that this only adds more implementation complexity and makes the
> > > solution less generic, while it does win us very little in the end ? The
> > > generic solution implementation is actually easier to implement.
> > 
> > Yes I want it less generic to start with. Why you want to start making
> > this workaround on your platform a generic implementation just because
> > the specification has provision for it ?
> 
> Because this is generic kernel code, it seems counterintuitive to introduce
> less generic solution which requires more complex implementation.
> 

I would argue. Lot of code gets added as specific and gets generalised
eventually if there are more users and in different configurations.

> Since the DEN0056 specification states this mode of operation is supported,
> I also wouldn't call it a workaround.

Sure, I take back if I called it workaround. But why would we want to make
it generic when we can test only mailbox based platform with it. I don't see
how it can be useful with SMC/Optee. I am not sure if it is useful with
virtio and if there is a way to test this. All I am saying is I don't want to
enable something and advertise it as generic when we have no platform or way
to test it and keep it functionally correct.

-- 
Regards,
Sudeep


From linux at armlinux.org.uk  Mon Dec  8 08:47:24 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Mon, 8 Dec 2025 16:47:24 +0000
Subject: [PATCH 0/3] ARM: fix hash_name() and branch predictor issues
In-Reply-To: <aTb19aN_8PNduyDY@shell.armlinux.org.uk>
References: <aTbF009476Iufory@shell.armlinux.org.uk>
 <20251208150840.92209-1-xieyuanbin1@huawei.com>
 <aTb19aN_8PNduyDY@shell.armlinux.org.uk>
Message-ID: <aTcBHKFDBkSEp5mi@shell.armlinux.org.uk>

On Mon, Dec 08, 2025 at 03:59:49PM +0000, Russell King (Oracle) wrote:
> On Mon, Dec 08, 2025 at 11:08:40PM +0800, Xie Yuanbin wrote:
> > On Mon, 8 Dec 2025 12:34:27 +0000, Russell King wrote:
> > > The first patch adds an additional check in __do_kernel_fault() to
> > > detect this condition. This patch is a non-obvious dependency for the
> > > next patch.
> > >
> > > The second patch handles faults above the top of userspace entirely
> > > separately, meaning we have a simpler and more obvious fault path,
> > > which avoids any possibility of taking any MM mutexes, which is the
> > > cause of the hash_name() problem.
> > >
> > > The third patch moves harden_branch_predictor() out of
> > > __do_user_fault() and to appropriate places in the parent functions.
> > > The reason this has been avoided thus far is because do_page_fault()
> > > can be a hot path (since it's used for page aging as well) but with
> > > kernel address faults being handled by an entirely separate path,
> > > this avoids adding to that overhead.
> > 
> > I don't have any objections to the first and second patches. However,
> > for the third patch, I feel it complicates some things. It removes
> > harden_branch_predictor() from __do_user_fault() and adds it to various
> > previous calling points.
> > 
> > This seems to be solely for adapting to the scenario of do_alignment() &&
> > user_mode(regs) && addr >= TASK_SIZE. Does this scenario really exist?
> 
> As explained in the other thread, alignment faults are the first thing
> that are checked when enabled, before permission fauls, so we can end
> up entering do_alignment() from userspace with an address in the
> kernel address space.
> 
> However, there is a user accessible page above TASK_SIZE, that is the
> vectors page which can have userspace helpers in. Userspace can read
> from this page, and thus can perform unaligned loads to this page.
> 
> The system behaviour of unaligned loads has been configurable, ARMv4,
> for example, had the ability to check for alignment faults and raise
> this exception. If that was disabled, then unaligned loads would
> load the equivalent 32-bit aligned address and rotate the data in
> the register. Compilers knew about this, and would code for it,
> which made it ABI. Later compilers stopped using that which cut down
> on the unaligned loads that userspace issued. Modern CPUs (ARMv7)
> tend to behave "sanely" in that unaligned loads are generally
> supported in hardware.

Also, would you mind giving ASAP some tested-by/reviewed-by for these
patches so they can be pushed out to linux-next for a bit of testing
there pelase? I'm on vacation from Thursday, so time is very short
to get these out - if we're not ready by Wednesday, then it'll be the
new year, possibly after the 11th January, before I can do anything
further (medical stuff.)

Thanks.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From Frank.Li at nxp.com  Mon Dec  8 09:09:39 2025
From: Frank.Li at nxp.com (Frank Li)
Date: Mon, 08 Dec 2025 12:09:39 -0500
Subject: [PATCH 0/8] dmaengine: Add new API to combine onfiguration and
 descriptor preparation
Message-ID: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>

Previously, configuration and preparation required two separate calls. This
works well when configuration is done only once during initialization.

However, in cases where the burst length or source/destination address must
be adjusted for each transfer, calling two functions is verbose.

	if (dmaengine_slave_config(chan, &sconf)) {
		dev_err(dev, "DMA slave config fail\n");
		return -EIO;
	}

	tx = dmaengine_prep_slave_single(chan, dma_local, len, dir, flags);

After new API added

	tx = dmaengine_prep_slave_single(chan, dma_local, len, dir, flags, &sconf);

Additional, prevous two calls requires additional locking to ensure both
steps complete atomically.

    mutex_lock()
    dmaengine_slave_config()
    dmaengine_prep_slave_single()
    mutex_unlock()

after new API added, mutex lock can be moved. See patch
     nvmet: pci-epf: Use dmaengine_prep_slave_single_config() API

Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
Frank Li (8):
      dmaengine: Add API to combine configuration and preparation (sg and single)
      PCI: endpoint: pci-epf-test: use new DMA API to simple code
      dmaengine: dw-edma: Use new .device_prep_slave_sg_config() callback
      dmaengine: dw-edma: Pass dma_slave_config to dw_edma_device_transfer()
      nvmet: pci-epf: Remove unnecessary dmaengine_terminate_sync() on each DMA transfer
      nvmet: pci-epf: Use dmaengine_prep_slave_single_config() API
      PCI: epf-mhi:Using new API dmaengine_prep_slave_single_config() to simple code.
      crypto: atmel: Use dmaengine_prep_slave_single_config() API

 drivers/crypto/atmel-aes.c                    | 10 ++---
 drivers/dma/dw-edma/dw-edma-core.c            | 38 +++++++++++-----
 drivers/nvme/target/pci-epf.c                 | 21 +++------
 drivers/pci/endpoint/functions/pci-epf-mhi.c  | 52 +++++++---------------
 drivers/pci/endpoint/functions/pci-epf-test.c |  8 +---
 include/linux/dmaengine.h                     | 64 ++++++++++++++++++++++++---
 6 files changed, 111 insertions(+), 82 deletions(-)
---
base-commit: bc04acf4aeca588496124a6cf54bfce3db327039
change-id: 20251204-dma_prep_config-654170d245a2

Best regards,
--
Frank Li <Frank.Li at nxp.com>



From Frank.Li at nxp.com  Mon Dec  8 09:09:40 2025
From: Frank.Li at nxp.com (Frank Li)
Date: Mon, 08 Dec 2025 12:09:40 -0500
Subject: [PATCH 1/8] dmaengine: Add API to combine configuration and
 preparation (sg and single)
In-Reply-To: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
References: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
Message-ID: <20251208-dma_prep_config-v1-1-53490c5e1e2a@nxp.com>

Previously, configuration and preparation required two separate calls. This
works well when configuration is done only once during initialization.

However, in cases where the burst length or source/destination address must
be adjusted for each transfer, calling two functions is verbose and
requires additional locking to ensure both steps complete atomically.

Add a new API and callback device_prep_slave_sg_config that combines
configuration and preparation into a single operation. If the configuration
argument is passed as NULL, fall back to the existing implementation.

Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
 include/linux/dmaengine.h | 64 +++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 57 insertions(+), 7 deletions(-)

diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 99efe2b9b4ea9844ca6161208362ef18ef111d96..6c563549133a28e26f1bdc367372b1e4a748afcf 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -835,6 +835,8 @@ struct dma_filter {
  *	where the address and size of each segment is located in one entry of
  *	the dma_vec array.
  * @device_prep_slave_sg: prepares a slave dma operation
+ *	(Depericated, use @device_prep_slave_sg_config)
+ * @device_prep_slave_sg_config: prepares a slave dma operation
  * @device_prep_dma_cyclic: prepare a cyclic dma operation suitable for audio.
  *	The function takes a buffer of size buf_len. The callback function will
  *	be called after period_len bytes have been transferred.
@@ -934,6 +936,11 @@ struct dma_device {
 		struct dma_chan *chan, struct scatterlist *sgl,
 		unsigned int sg_len, enum dma_transfer_direction direction,
 		unsigned long flags, void *context);
+	struct dma_async_tx_descriptor *(*device_prep_slave_sg_config)(
+		struct dma_chan *chan, struct scatterlist *sgl,
+		unsigned int sg_len, enum dma_transfer_direction direction,
+		unsigned long flags, struct dma_slave_config *config,
+		void *context);
 	struct dma_async_tx_descriptor *(*device_prep_dma_cyclic)(
 		struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
 		size_t period_len, enum dma_transfer_direction direction,
@@ -974,22 +981,44 @@ static inline bool is_slave_direction(enum dma_transfer_direction direction)
 	       (direction == DMA_DEV_TO_DEV);
 }
 
-static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_single(
-	struct dma_chan *chan, dma_addr_t buf, size_t len,
-	enum dma_transfer_direction dir, unsigned long flags)
+static inline struct dma_async_tx_descriptor *
+dmaengine_prep_slave_single_config(struct dma_chan *chan, dma_addr_t buf,
+				   size_t len, enum dma_transfer_direction dir,
+				   unsigned long flags,
+				   struct dma_slave_config *config)
 {
 	struct scatterlist sg;
 	sg_init_table(&sg, 1);
 	sg_dma_address(&sg) = buf;
 	sg_dma_len(&sg) = len;
 
-	if (!chan || !chan->device || !chan->device->device_prep_slave_sg)
+	if (!chan || !chan->device)
+		return NULL;
+
+	if (chan->device->device_prep_slave_sg_config)
+		return chan->device->device_prep_slave_sg_config(chan, &sg, 1,
+					dir, flags, config, NULL);
+
+	if (config)
+		if (dmaengine_slave_config(chan, config))
+			return NULL;
+
+	if (!chan->device->device_prep_slave_sg)
 		return NULL;
 
 	return chan->device->device_prep_slave_sg(chan, &sg, 1,
 						  dir, flags, NULL);
 }
 
+static inline struct dma_async_tx_descriptor *
+dmaengine_prep_slave_single(struct dma_chan *chan, dma_addr_t buf, size_t len,
+			    enum dma_transfer_direction dir,
+			    unsigned long flags)
+{
+	return dmaengine_prep_slave_single_config(chan, buf, len, dir,
+						  flags, NULL);
+}
+
 /**
  * dmaengine_prep_peripheral_dma_vec() - Prepare a DMA scatter-gather descriptor
  * @chan: The channel to be used for this descriptor
@@ -1009,17 +1038,38 @@ static inline struct dma_async_tx_descriptor *dmaengine_prep_peripheral_dma_vec(
 							    dir, flags);
 }
 
-static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_sg(
+static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_sg_config(
 	struct dma_chan *chan, struct scatterlist *sgl,	unsigned int sg_len,
-	enum dma_transfer_direction dir, unsigned long flags)
+	enum dma_transfer_direction dir, unsigned long flags,
+	struct dma_slave_config *config)
 {
-	if (!chan || !chan->device || !chan->device->device_prep_slave_sg)
+	if (!chan || !chan->device)
+		return NULL;
+
+	if (chan->device->device_prep_slave_sg_config)
+		return chan->device->device_prep_slave_sg_config(chan, sgl,
+								 sg_len, dir,
+								 flags, config,
+								 NULL);
+	if (config)
+		if (dmaengine_slave_config(chan, config))
+			return NULL;
+
+	if (!chan->device->device_prep_slave_sg)
 		return NULL;
 
 	return chan->device->device_prep_slave_sg(chan, sgl, sg_len,
 						  dir, flags, NULL);
 }
 
+static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_sg(
+	struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len,
+	enum dma_transfer_direction dir, unsigned long flags)
+{
+	return dmaengine_prep_slave_sg_config(chan, sgl, sg_len, dir,
+					      flags, NULL);
+}
+
 #ifdef CONFIG_RAPIDIO_DMA_ENGINE
 struct rio_dma_ext;
 static inline struct dma_async_tx_descriptor *dmaengine_prep_rio_sg(

-- 
2.34.1



From Frank.Li at nxp.com  Mon Dec  8 09:09:41 2025
From: Frank.Li at nxp.com (Frank Li)
Date: Mon, 08 Dec 2025 12:09:41 -0500
Subject: [PATCH 2/8] PCI: endpoint: pci-epf-test: use new DMA API to simple
 code
In-Reply-To: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
References: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
Message-ID: <20251208-dma_prep_config-v1-2-53490c5e1e2a@nxp.com>

Using new API dmaengine_prep_slave_single_config() to simple code.

No functional change.

Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/pci/endpoint/functions/pci-epf-test.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index debd235253c5ba54eb8f06d13261c407ee3768ec..eef569db0784d37bd6468b87fd951a5a0799ae69 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -162,12 +162,8 @@ static int pci_epf_test_data_transfer(struct pci_epf_test *epf_test,
 		else
 			sconf.src_addr = dma_remote;
 
-		if (dmaengine_slave_config(chan, &sconf)) {
-			dev_err(dev, "DMA slave config fail\n");
-			return -EIO;
-		}
-		tx = dmaengine_prep_slave_single(chan, dma_local, len, dir,
-						 flags);
+		tx = dmaengine_prep_slave_single_config(chan, dma_local, len,
+							dir, flags, &sconf);
 	} else {
 		tx = dmaengine_prep_dma_memcpy(chan, dma_dst, dma_src, len,
 					       flags);

-- 
2.34.1



From Frank.Li at nxp.com  Mon Dec  8 09:09:42 2025
From: Frank.Li at nxp.com (Frank Li)
Date: Mon, 08 Dec 2025 12:09:42 -0500
Subject: [PATCH 3/8] dmaengine: dw-edma: Use new
 .device_prep_slave_sg_config() callback
In-Reply-To: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
References: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
Message-ID: <20251208-dma_prep_config-v1-3-53490c5e1e2a@nxp.com>

Use the new .device_prep_slave_sg_config() callback to combine
configuration and descriptor preparation.

No functional changes.

Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/dma/dw-edma/dw-edma-core.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 8e5f7defa6b678eefe0f312ebc59f654677c744f..58f98542f8329a3bfdc5455768e8394ae601ab5f 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -532,10 +532,13 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
 }
 
 static struct dma_async_tx_descriptor *
-dw_edma_device_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
-			     unsigned int len,
-			     enum dma_transfer_direction direction,
-			     unsigned long flags, void *context)
+dw_edma_device_prep_slave_sg_config(struct dma_chan *dchan,
+				    struct scatterlist *sgl,
+				    unsigned int len,
+				    enum dma_transfer_direction direction,
+				    unsigned long flags,
+				    struct dma_slave_config *config,
+				    void *context)
 {
 	struct dw_edma_transfer xfer;
 
@@ -546,6 +549,9 @@ dw_edma_device_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
 	xfer.flags = flags;
 	xfer.type = EDMA_XFER_SCATTER_GATHER;
 
+	if (config)
+		dw_edma_device_config(dchan, config);
+
 	return dw_edma_device_transfer(&xfer);
 }
 
@@ -815,7 +821,7 @@ static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc)
 	dma->device_terminate_all = dw_edma_device_terminate_all;
 	dma->device_issue_pending = dw_edma_device_issue_pending;
 	dma->device_tx_status = dw_edma_device_tx_status;
-	dma->device_prep_slave_sg = dw_edma_device_prep_slave_sg;
+	dma->device_prep_slave_sg_config = dw_edma_device_prep_slave_sg_config;
 	dma->device_prep_dma_cyclic = dw_edma_device_prep_dma_cyclic;
 	dma->device_prep_interleaved_dma = dw_edma_device_prep_interleaved_dma;
 

-- 
2.34.1



From Frank.Li at nxp.com  Mon Dec  8 09:09:43 2025
From: Frank.Li at nxp.com (Frank Li)
Date: Mon, 08 Dec 2025 12:09:43 -0500
Subject: [PATCH 4/8] dmaengine: dw-edma: Pass dma_slave_config to
 dw_edma_device_transfer()
In-Reply-To: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
References: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
Message-ID: <20251208-dma_prep_config-v1-4-53490c5e1e2a@nxp.com>

Pass dma_slave_config to dw_edma_device_transfer() to support atomic
configuration and descriptor preparation when a non-NULL config is
provided to device_prep_slave_sg_config().

Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/dma/dw-edma/dw-edma-core.c | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 58f98542f8329a3bfdc5455768e8394ae601ab5f..744c60ec964102287bd32b9e55d0f3024d1d39d9 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -230,6 +230,15 @@ static int dw_edma_device_config(struct dma_chan *dchan,
 	return 0;
 }
 
+static struct dma_slave_config *
+dw_edma_device_get_config(struct dma_chan *dchan,
+			  struct dma_slave_config *config)
+{
+	struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
+
+	return config ? config : &chan->config;
+}
+
 static int dw_edma_device_pause(struct dma_chan *dchan)
 {
 	struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
@@ -348,7 +357,8 @@ dw_edma_device_tx_status(struct dma_chan *dchan, dma_cookie_t cookie,
 }
 
 static struct dma_async_tx_descriptor *
-dw_edma_device_transfer(struct dw_edma_transfer *xfer)
+dw_edma_device_transfer(struct dw_edma_transfer *xfer,
+			struct dma_slave_config *config)
 {
 	struct dw_edma_chan *chan = dchan2dw_edma_chan(xfer->dchan);
 	enum dma_transfer_direction dir = xfer->direction;
@@ -427,8 +437,8 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
 		src_addr = xfer->xfer.il->src_start;
 		dst_addr = xfer->xfer.il->dst_start;
 	} else {
-		src_addr = chan->config.src_addr;
-		dst_addr = chan->config.dst_addr;
+		src_addr = config->src_addr;
+		dst_addr = config->dst_addr;
 	}
 
 	if (dir == DMA_DEV_TO_MEM)
@@ -552,7 +562,7 @@ dw_edma_device_prep_slave_sg_config(struct dma_chan *dchan,
 	if (config)
 		dw_edma_device_config(dchan, config);
 
-	return dw_edma_device_transfer(&xfer);
+	return dw_edma_device_transfer(&xfer, dw_edma_device_get_config(dchan, config));
 }
 
 static struct dma_async_tx_descriptor *
@@ -571,7 +581,7 @@ dw_edma_device_prep_dma_cyclic(struct dma_chan *dchan, dma_addr_t paddr,
 	xfer.flags = flags;
 	xfer.type = EDMA_XFER_CYCLIC;
 
-	return dw_edma_device_transfer(&xfer);
+	return dw_edma_device_transfer(&xfer, dw_edma_device_get_config(dchan, NULL));
 }
 
 static struct dma_async_tx_descriptor *
@@ -587,7 +597,7 @@ dw_edma_device_prep_interleaved_dma(struct dma_chan *dchan,
 	xfer.flags = flags;
 	xfer.type = EDMA_XFER_INTERLEAVED;
 
-	return dw_edma_device_transfer(&xfer);
+	return dw_edma_device_transfer(&xfer, dw_edma_device_get_config(dchan, NULL));
 }
 
 static void dw_hdma_set_callback_result(struct virt_dma_desc *vd,

-- 
2.34.1



From Frank.Li at nxp.com  Mon Dec  8 09:09:44 2025
From: Frank.Li at nxp.com (Frank Li)
Date: Mon, 08 Dec 2025 12:09:44 -0500
Subject: [PATCH 5/8] nvmet: pci-epf: Remove unnecessary
 dmaengine_terminate_sync() on each DMA transfer
In-Reply-To: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
References: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
Message-ID: <20251208-dma_prep_config-v1-5-53490c5e1e2a@nxp.com>

dmaengine_terminate_sync() cancels all pending requests. Calling it for
every DMA transfer is unnecessary and counterproductive. This function is
generally intended for cleanup paths such as module removal, device close,
or unbind operations.

Remove the redundant calls.

Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
This one also fix stress test failure after remove mutex and use new API
dmaengine_prep_slave_sg_config().
---
 drivers/nvme/target/pci-epf.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c
index 2e78397a7373a7d8ba67150f301f392123db88d1..85225a4f75b5bd7abb6897d064123766af021542 100644
--- a/drivers/nvme/target/pci-epf.c
+++ b/drivers/nvme/target/pci-epf.c
@@ -420,8 +420,6 @@ static int nvmet_pci_epf_dma_transfer(struct nvmet_pci_epf *nvme_epf,
 		ret = -EIO;
 	}
 
-	dmaengine_terminate_sync(chan);
-
 unmap:
 	dma_unmap_single(dma_dev, dma_addr, seg->length, dir);
 

-- 
2.34.1



From Frank.Li at nxp.com  Mon Dec  8 09:09:45 2025
From: Frank.Li at nxp.com (Frank Li)
Date: Mon, 08 Dec 2025 12:09:45 -0500
Subject: [PATCH 6/8] nvmet: pci-epf: Use
 dmaengine_prep_slave_single_config() API
In-Reply-To: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
References: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
Message-ID: <20251208-dma_prep_config-v1-6-53490c5e1e2a@nxp.com>

Use the new dmaengine_prep_slave_single_config() API to combine the
configuration and descriptor preparation into a single call.

Since dmaengine_prep_slave_single_config() performs the configuration
and preparation atomically, the mutex can be removed.

Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/nvme/target/pci-epf.c | 19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c
index 85225a4f75b5bd7abb6897d064123766af021542..223716b00715be2a81935e6920666c723fe98fe7 100644
--- a/drivers/nvme/target/pci-epf.c
+++ b/drivers/nvme/target/pci-epf.c
@@ -386,22 +386,16 @@ static int nvmet_pci_epf_dma_transfer(struct nvmet_pci_epf *nvme_epf,
 		return -EINVAL;
 	}
 
-	mutex_lock(lock);
-
 	dma_dev = dmaengine_get_dma_device(chan);
 	dma_addr = dma_map_single(dma_dev, seg->buf, seg->length, dir);
 	ret = dma_mapping_error(dma_dev, dma_addr);
 	if (ret)
-		goto unlock;
-
-	ret = dmaengine_slave_config(chan, &sconf);
-	if (ret) {
-		dev_err(dev, "Failed to configure DMA channel\n");
-		goto unmap;
-	}
+		return ret;
 
-	desc = dmaengine_prep_slave_single(chan, dma_addr, seg->length,
-					   sconf.direction, DMA_CTRL_ACK);
+	desc = dmaengine_prep_slave_single_config(chan, dma_addr, seg->length,
+						  sconf.direction,
+						  DMA_CTRL_ACK,
+						  &sconf);
 	if (!desc) {
 		dev_err(dev, "Failed to prepare DMA\n");
 		ret = -EIO;
@@ -423,9 +417,6 @@ static int nvmet_pci_epf_dma_transfer(struct nvmet_pci_epf *nvme_epf,
 unmap:
 	dma_unmap_single(dma_dev, dma_addr, seg->length, dir);
 
-unlock:
-	mutex_unlock(lock);
-
 	return ret;
 }
 

-- 
2.34.1



From conor at kernel.org  Mon Dec  8 09:10:33 2025
From: conor at kernel.org (Conor Dooley)
Date: Mon, 8 Dec 2025 17:10:33 +0000
Subject: [PATCH 2/4] dt-bindings: arm: Document Microchip LAN969x
In-Reply-To: <CA+HBbNH6wO2VWOp1Dn52ArrYg6z89FgYnT3x-jsHsTVJ5xSBSA@mail.gmail.com>
References: <20251203122313.1287950-1-robert.marko@sartura.hr>
 <20251203122313.1287950-2-robert.marko@sartura.hr>
 <20251203-duly-leotard-86b83bd840c6@spud>
 <CA+HBbNH6wO2VWOp1Dn52ArrYg6z89FgYnT3x-jsHsTVJ5xSBSA@mail.gmail.com>
Message-ID: <20251208-absolute-diploma-6575729ab43f@spud>

On Mon, Dec 08, 2025 at 11:30:28AM +0100, Robert Marko wrote:
> On Wed, Dec 3, 2025 at 8:19?PM Conor Dooley <conor at kernel.org> wrote:
> >
> > On Wed, Dec 03, 2025 at 01:21:30PM +0100, Robert Marko wrote:
> > > Microchip LAN969x is a series of multi-port, multi-gigabit switches based
> > > on ARMv8 Cortex-A53 CPU.
> > >
> > > Signed-off-by: Robert Marko <robert.marko at sartura.hr>
> > > ---
> > >  .../bindings/arm/microchip,lan969x.yaml       | 32 +++++++++++++++++++
> >
> > This should not be in a unique file, put it in with the other microchip
> > arm devices please. Also, the wildcard in the compatible is not
> > permitted, only way it'd make sense is if these are different binnings
> > of the same silicon. If that's the case, you need to explain why,
> > because compatibles are meant to be soc-specific.
> 
> Hi Conor,
> The issue is that there is no unique place for Microchip SoC-s,
> LAN966x series is in the AT91 bindings
> while SparX-5 has its own bindings file.
> 
> What would you suggest in this case?

Ideally, arm/atmel-at91.yaml and arm/microchip,sparx5.yaml would just
become arm/microchip.yaml. The axi at 600000000 thing in the sparx5 file
looks pointless and can be deleted IMO.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251208/9d152266/attachment.sig>

From Frank.Li at nxp.com  Mon Dec  8 09:09:46 2025
From: Frank.Li at nxp.com (Frank Li)
Date: Mon, 08 Dec 2025 12:09:46 -0500
Subject: [PATCH 7/8] PCI: epf-mhi:Using new API
 dmaengine_prep_slave_single_config() to simple code.
In-Reply-To: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
References: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
Message-ID: <20251208-dma_prep_config-v1-7-53490c5e1e2a@nxp.com>

No functional change.

Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
Keep mutex lock because sync with other function.
---
 drivers/pci/endpoint/functions/pci-epf-mhi.c | 52 +++++++++-------------------
 1 file changed, 16 insertions(+), 36 deletions(-)

diff --git a/drivers/pci/endpoint/functions/pci-epf-mhi.c b/drivers/pci/endpoint/functions/pci-epf-mhi.c
index 6643a88c7a0ce38161bc6253c09d29f1c36ba394..11999a7a156dee057f04f0f9277f6ac5a7f1d7ee 100644
--- a/drivers/pci/endpoint/functions/pci-epf-mhi.c
+++ b/drivers/pci/endpoint/functions/pci-epf-mhi.c
@@ -328,12 +328,6 @@ static int pci_epf_mhi_edma_read(struct mhi_ep_cntrl *mhi_cntrl,
 	config.direction = DMA_DEV_TO_MEM;
 	config.src_addr = buf_info->host_addr;
 
-	ret = dmaengine_slave_config(chan, &config);
-	if (ret) {
-		dev_err(dev, "Failed to configure DMA channel\n");
-		goto err_unlock;
-	}
-
 	dst_addr = dma_map_single(dma_dev, buf_info->dev_addr, buf_info->size,
 				  DMA_FROM_DEVICE);
 	ret = dma_mapping_error(dma_dev, dst_addr);
@@ -342,9 +336,10 @@ static int pci_epf_mhi_edma_read(struct mhi_ep_cntrl *mhi_cntrl,
 		goto err_unlock;
 	}
 
-	desc = dmaengine_prep_slave_single(chan, dst_addr, buf_info->size,
-					   DMA_DEV_TO_MEM,
-					   DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
+	desc = dmaengine_prep_slave_single_config(chan, dst_addr, buf_info->size,
+						  DMA_DEV_TO_MEM,
+						  DMA_CTRL_ACK | DMA_PREP_INTERRUPT,
+						  &config);
 	if (!desc) {
 		dev_err(dev, "Failed to prepare DMA\n");
 		ret = -EIO;
@@ -399,12 +394,6 @@ static int pci_epf_mhi_edma_write(struct mhi_ep_cntrl *mhi_cntrl,
 	config.direction = DMA_MEM_TO_DEV;
 	config.dst_addr = buf_info->host_addr;
 
-	ret = dmaengine_slave_config(chan, &config);
-	if (ret) {
-		dev_err(dev, "Failed to configure DMA channel\n");
-		goto err_unlock;
-	}
-
 	src_addr = dma_map_single(dma_dev, buf_info->dev_addr, buf_info->size,
 				  DMA_TO_DEVICE);
 	ret = dma_mapping_error(dma_dev, src_addr);
@@ -413,9 +402,10 @@ static int pci_epf_mhi_edma_write(struct mhi_ep_cntrl *mhi_cntrl,
 		goto err_unlock;
 	}
 
-	desc = dmaengine_prep_slave_single(chan, src_addr, buf_info->size,
-					   DMA_MEM_TO_DEV,
-					   DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
+	desc = dmaengine_prep_slave_single_config(chan, src_addr, buf_info->size,
+						  DMA_MEM_TO_DEV,
+						  DMA_CTRL_ACK | DMA_PREP_INTERRUPT,
+						  &config);
 	if (!desc) {
 		dev_err(dev, "Failed to prepare DMA\n");
 		ret = -EIO;
@@ -502,12 +492,6 @@ static int pci_epf_mhi_edma_read_async(struct mhi_ep_cntrl *mhi_cntrl,
 	config.direction = DMA_DEV_TO_MEM;
 	config.src_addr = buf_info->host_addr;
 
-	ret = dmaengine_slave_config(chan, &config);
-	if (ret) {
-		dev_err(dev, "Failed to configure DMA channel\n");
-		goto err_unlock;
-	}
-
 	dst_addr = dma_map_single(dma_dev, buf_info->dev_addr, buf_info->size,
 				  DMA_FROM_DEVICE);
 	ret = dma_mapping_error(dma_dev, dst_addr);
@@ -516,9 +500,10 @@ static int pci_epf_mhi_edma_read_async(struct mhi_ep_cntrl *mhi_cntrl,
 		goto err_unlock;
 	}
 
-	desc = dmaengine_prep_slave_single(chan, dst_addr, buf_info->size,
-					   DMA_DEV_TO_MEM,
-					   DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
+	desc = dmaengine_prep_slave_single_config(chan, dst_addr, buf_info->size,
+						  DMA_DEV_TO_MEM,
+						  DMA_CTRL_ACK | DMA_PREP_INTERRUPT,
+						  &config);
 	if (!desc) {
 		dev_err(dev, "Failed to prepare DMA\n");
 		ret = -EIO;
@@ -581,12 +566,6 @@ static int pci_epf_mhi_edma_write_async(struct mhi_ep_cntrl *mhi_cntrl,
 	config.direction = DMA_MEM_TO_DEV;
 	config.dst_addr = buf_info->host_addr;
 
-	ret = dmaengine_slave_config(chan, &config);
-	if (ret) {
-		dev_err(dev, "Failed to configure DMA channel\n");
-		goto err_unlock;
-	}
-
 	src_addr = dma_map_single(dma_dev, buf_info->dev_addr, buf_info->size,
 				  DMA_TO_DEVICE);
 	ret = dma_mapping_error(dma_dev, src_addr);
@@ -595,9 +574,10 @@ static int pci_epf_mhi_edma_write_async(struct mhi_ep_cntrl *mhi_cntrl,
 		goto err_unlock;
 	}
 
-	desc = dmaengine_prep_slave_single(chan, src_addr, buf_info->size,
-					   DMA_MEM_TO_DEV,
-					   DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
+	desc = dmaengine_prep_slave_single_config(chan, src_addr, buf_info->size,
+						  DMA_MEM_TO_DEV,
+						  DMA_CTRL_ACK | DMA_PREP_INTERRUPT,
+						  &config);
 	if (!desc) {
 		dev_err(dev, "Failed to prepare DMA\n");
 		ret = -EIO;

-- 
2.34.1



From Frank.Li at nxp.com  Mon Dec  8 09:09:47 2025
From: Frank.Li at nxp.com (Frank Li)
Date: Mon, 08 Dec 2025 12:09:47 -0500
Subject: [PATCH 8/8] crypto: atmel: Use
 dmaengine_prep_slave_single_config() API
In-Reply-To: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
References: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
Message-ID: <20251208-dma_prep_config-v1-8-53490c5e1e2a@nxp.com>

Using new API dmaengine_prep_slave_single_config() to simple code.

No functional change.

Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/crypto/atmel-aes.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c
index 3a2684208dda9ee45d71b4bc2958be293a4fb6fe..14d46186865a1a6d8a11486b8f3aca92341fb1f9 100644
--- a/drivers/crypto/atmel-aes.c
+++ b/drivers/crypto/atmel-aes.c
@@ -820,12 +820,10 @@ static int atmel_aes_dma_transfer_start(struct atmel_aes_dev *dd,
 		return -EINVAL;
 	}
 
-	err = dmaengine_slave_config(dma->chan, &config);
-	if (err)
-		return err;
-
-	desc = dmaengine_prep_slave_sg(dma->chan, dma->sg, dma->sg_len, dir,
-				       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	desc = dmaengine_prep_slave_sg_config(dma->chan, dma->sg, dma->sg_len,
+					      dir,
+					      DMA_PREP_INTERRUPT | DMA_CTRL_ACK,
+					      &config);
 	if (!desc)
 		return -ENOMEM;
 

-- 
2.34.1



From conor at kernel.org  Mon Dec  8 09:15:50 2025
From: conor at kernel.org (Conor Dooley)
Date: Mon, 8 Dec 2025 17:15:50 +0000
Subject: [PATCH 4/4] arm64: dts: microchip: add LAN969x support
In-Reply-To: <20251203122313.1287950-4-robert.marko@sartura.hr>
References: <20251203122313.1287950-1-robert.marko@sartura.hr>
 <20251203122313.1287950-4-robert.marko@sartura.hr>
Message-ID: <20251208-deprecate-privatize-c8ab771091b7@spud>

On Wed, Dec 03, 2025 at 01:21:32PM +0100, Robert Marko wrote:
> Add support for Microchip LAN969x switch SoC, including the EV23X71A
> EVB board.
> 
> Signed-off-by: Robert Marko <robert.marko at sartura.hr>
> ---
>  arch/arm64/boot/dts/microchip/Makefile        |   2 +
>  .../boot/dts/microchip/lan9696-ev23x71a.dts   | 761 ++++++++++++++++++
>  arch/arm64/boot/dts/microchip/lan969x.dtsi    | 482 +++++++++++
>  3 files changed, 1245 insertions(+)
>  create mode 100644 arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts
>  create mode 100644 arch/arm64/boot/dts/microchip/lan969x.dtsi
> 
> diff --git a/arch/arm64/boot/dts/microchip/Makefile b/arch/arm64/boot/dts/microchip/Makefile
> index c6e0313eea0f..d02ac50aae79 100644
> --- a/arch/arm64/boot/dts/microchip/Makefile
> +++ b/arch/arm64/boot/dts/microchip/Makefile
> @@ -2,3 +2,5 @@
>  dtb-$(CONFIG_ARCH_SPARX5) += sparx5_pcb125.dtb
>  dtb-$(CONFIG_ARCH_SPARX5) += sparx5_pcb134.dtb sparx5_pcb134_emmc.dtb
>  dtb-$(CONFIG_ARCH_SPARX5) += sparx5_pcb135.dtb sparx5_pcb135_emmc.dtb
> +

> +dtb-$(CONFIG_ARCH_LAN969X) += lan9696-ev23x71a.dtb

ngl, I wonder why this config even exists, it's not meaningfully different
to ARCH_SPARX5.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251208/52801499/attachment.sig>

From madhurkumar004 at gmail.com  Mon Dec  8 09:23:31 2025
From: madhurkumar004 at gmail.com (Madhur Kumar)
Date: Mon,  8 Dec 2025 22:53:31 +0530
Subject: [PATCH] wifi: mt76: mt7921: Replace deprecated PCI function
Message-ID: <20251208172331.89705-1-madhurkumar004@gmail.com>

pcim_iomap_table() and pcim_iomap_regions() have been
deprecated.
Replace them with pcim_iomap_region().

Signed-off-by: Madhur Kumar <madhurkumar004 at gmail.com>
---
 drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
index ec9686183251..65c7fe671137 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
@@ -276,6 +276,7 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
 	struct mt76_bus_ops *bus_ops;
 	struct mt792x_dev *dev;
 	struct mt76_dev *mdev;
+	void __iomem *regs;
 	u16 cmd, chipid;
 	u8 features;
 	int ret;
@@ -284,10 +285,6 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
 	if (ret)
 		return ret;
 
-	ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev));
-	if (ret)
-		return ret;
-
 	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
 	if (!(cmd & PCI_COMMAND_MEMORY)) {
 		cmd |= PCI_COMMAND_MEMORY;
@@ -321,11 +318,15 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
 
 	pci_set_drvdata(pdev, mdev);
 
+	regs =  pcim_iomap_region(pdev, 0, pci_name(pdev));
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
 	dev = container_of(mdev, struct mt792x_dev, mt76);
 	dev->fw_features = features;
 	dev->hif_ops = &mt7921_pcie_ops;
 	dev->irq_map = &irq_map;
-	mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]);
+	mt76_mmio_init(&dev->mt76, regs);
 	tasklet_init(&mdev->irq_tasklet, mt792x_irq_tasklet, (unsigned long)dev);
 
 	dev->phy.dev = dev;
-- 
2.52.0



From punit.agrawal at oss.qualcomm.com  Mon Dec  8 09:43:57 2025
From: punit.agrawal at oss.qualcomm.com (Punit Agrawal)
Date: Mon, 08 Dec 2025 17:43:57 +0000
Subject: [PATCH v6 00/34] arm_mpam: Add basic mpam driver
In-Reply-To: <5261337c-337d-44ca-aff1-0a927b81e593@intel.com> (Reinette
	Chatre's message of "Fri, 5 Dec 2025 11:11:34 -0800")
References: <20251119122305.302149-1-ben.horgan@arm.com>
	<877bvfa23i.fsf@stealth>
	<a04aa337-a3eb-42a0-855b-500ba549e2d8@arm.com>
	<87sedrlsjk.fsf@stealth>
	<642767c9-f926-490a-83a1-160978c37553@arm.com>
	<871pl9krdz.fsf@stealth>
	<5261337c-337d-44ca-aff1-0a927b81e593@intel.com>
Message-ID: <87tsy0kgwy.fsf@stealth>

Hi Reinette,

Reinette Chatre <reinette.chatre at intel.com> writes:

> Hi Punit,
>
> On 12/5/25 5:08 AM, Punit Agrawal wrote:
>> James Morse <james.morse at arm.com> writes:
>>> On 03/12/2025 11:21, Punit Agrawal wrote:
>>>> Ben Horgan <ben.horgan at arm.com> writes:
>>>>> On 11/24/25 15:21, Punit Agrawal wrote:
>
>>>>>> The platform has MSCs attached
>>>>>> to shared L2 caches which are being skipped during later stages of
>>>>>> initialisation. IIUC, the L2 MSCs' limitations stems from the
>>>>>> assumptions in the resctrl interface.
>>>>>
>>>>> What in particualar is being skipped?
>>>
>>>> The registration of the discovered MSCs with resctrl and subsequent
>>>> exposing it to the user.
>>>
>>> resctrl's 'L2' support is limited to the CPOR bitmap.
>>> If you have controls, there is no resctrl 'event' that can exposed them.
>>> (the problem being they all have 'L3' in the name!)
>> 
>>>>>> I was wondering if there are any patches available to relax these
>>>>>> limitations?
>> 
>>> Knowing which property it is will help - but some of these things are checked
>>> to match resctrl's ABI. They can't necessarily be relaxed without breaking
>>> user-space.
>> 
>> This platform has portion, capacity and priority partitioning, as well
>> as memory bandwidth and cache storage monitoring. The MPAM code seems to
>> correctly parse the properties.
>> 
>> But as you point out, the resctrl 'L2' support doesn't have anything
>> other than CPOR bitmap yet. Have you looked at what's needed to extend
>> resctrl to support some of the others?
>
> Please see [1] for a summary of ideas on how resctrl can support multiple
> controls. Nothing is final, please do add your ideas and requirements.
>
> There are a couple of opens not included in the summary. If interested
> [2] is where a lot of discussion happened that prompted the need for
> a summary.

Thanks a lot for the pointers.

Let me catch up with what's already discussed and raise any points that
are not clear / need refining.

>
> Reinette
>
> [1] https://lore.kernel.org/lkml/aPtfMFfLV1l%2FRB0L at e133380.arm.com/
> [2] https://lore.kernel.org/lkml/aNFliMZTTUiXyZzd at e133380.arm.com/


From seanjc at google.com  Mon Dec  8 10:07:57 2025
From: seanjc at google.com (Sean Christopherson)
Date: Mon, 8 Dec 2025 10:07:57 -0800
Subject: [PATCH v6 04/44] perf: Add APIs to create/release mediated guest vPMUs
In-Reply-To: <20251208115156.GE3707891@noisy.programming.kicks-ass.net>
References: <20251206001720.468579-1-seanjc@google.com> <20251206001720.468579-5-seanjc@google.com>
 <20251208115156.GE3707891@noisy.programming.kicks-ass.net>
Message-ID: <aTcT_QcQaqyHV_S-@google.com>

On Mon, Dec 08, 2025, Peter Zijlstra wrote:
> On Fri, Dec 05, 2025 at 04:16:40PM -0800, Sean Christopherson wrote:
> 
> > +static atomic_t nr_include_guest_events __read_mostly;
> > +
> > +static atomic_t nr_mediated_pmu_vms __read_mostly;
> > +static DEFINE_MUTEX(perf_mediated_pmu_mutex);
> 
> > +static int mediated_pmu_account_event(struct perf_event *event)
> > +{
> > +	if (!is_include_guest_event(event))
> > +		return 0;
> > +
> > +	guard(mutex)(&perf_mediated_pmu_mutex);
> > +
> > +	if (atomic_read(&nr_mediated_pmu_vms))
> > +		return -EOPNOTSUPP;
> > +
> > +	atomic_inc(&nr_include_guest_events);
> > +	return 0;
> > +}
> > +
> > +static void mediated_pmu_unaccount_event(struct perf_event *event)
> > +{
> > +	if (!is_include_guest_event(event))
> > +		return;
> > +
> > +	atomic_dec(&nr_include_guest_events);
> > +}
> 
> > +int perf_create_mediated_pmu(void)
> > +{
> > +	guard(mutex)(&perf_mediated_pmu_mutex);
> > +	if (atomic_inc_not_zero(&nr_mediated_pmu_vms))
> > +		return 0;
> > +
> > +	if (atomic_read(&nr_include_guest_events))
> > +		return -EBUSY;
> > +
> > +	atomic_inc(&nr_mediated_pmu_vms);
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(perf_create_mediated_pmu);
> > +
> > +void perf_release_mediated_pmu(void)
> > +{
> > +	if (WARN_ON_ONCE(!atomic_read(&nr_mediated_pmu_vms)))
> > +		return;
> > +
> > +	atomic_dec(&nr_mediated_pmu_vms);
> > +}
> > +EXPORT_SYMBOL_GPL(perf_release_mediated_pmu);
> 
> These two things are supposed to be symmetric, but are implemented
> differently; what gives?
> 
> That is, should not both have the general shape:
> 
> 	if (atomic_inc_not_zero(&A))
> 		return 0;
> 
> 	guard(mutex)(&lock);
> 
> 	if (atomic_read(&B))
> 		return -EBUSY;
> 
> 	atomic_inc(&A);
> 	return 0;
> 
> Similarly, I would imagine both release variants to have the underflow
> warn on like:
> 
> 	if (WARN_ON_ONCE(!atomic_read(&A)))
> 		return;
> 
> 	atomic_dec(&A);
> 
> Hmm?

IIUC, you're suggesting someting like this?  If so, that makes perfect sense to me.

diff --git a/kernel/events/core.c b/kernel/events/core.c
index c6368c64b866..fa2e7b722283 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -6356,7 +6356,8 @@ static int mediated_pmu_account_event(struct perf_event *event)
 
 static void mediated_pmu_unaccount_event(struct perf_event *event)
 {
-       if (!is_include_guest_event(event))
+       if (!is_include_guest_event(event) ||
+           WARN_ON_ONCE(!atomic_read(&nr_include_guest_events)))
                return;
 
        atomic_dec(&nr_include_guest_events);

> Also, EXPORT_SYMBOL_FOR_KVM() ?

Ya, for sure.  I posted this against a branch without EXPORT_SYMBOL_FOR_KVM(),
because there are also hard dependencies on the for-6.19 KVM pull requests, and
I didn't want to wait to post until 6.19-rc1 because of the impending winter
break.  Though I also simply forgot about these exports :-(

These could also use EXPORT_SYMBOL_FOR_KVM():

  EXPORT_SYMBOL_FOR_MODULES(perf_load_guest_lvtpc, "kvm");
  EXPORT_SYMBOL_FOR_MODULES(perf_put_guest_lvtpc, "kvm");


> I can make these edits when applying, if/when we get to applying. Let me
> continue reading.
> 


From paulk at sys-base.io  Mon Dec  8 10:13:50 2025
From: paulk at sys-base.io (Paul Kocialkowski)
Date: Mon, 8 Dec 2025 19:13:50 +0100
Subject: Kconfig dangling references (BZ 216748)
In-Reply-To: <22b92ddf-6321-41b5-8073-f9c7064d3432@infradead.org>
References: <22b92ddf-6321-41b5-8073-f9c7064d3432@infradead.org>
Message-ID: <aTcVXrUXVsyjaT22@shepard>

Hi Randy,

On Sun 07 Dec 25, 18:04, Randy Dunlap wrote:
> from  https://bugzilla.kernel.org/show_bug.cgi?id=216748
> 
> The bugzilla entry includes a Perl script and a shell script.
> This is the edited result of running them (I removed some entries that were noise).

[...]

> DRM_KMS_DMA_HELPER ---
> drivers/gpu/drm/adp/Kconfig:9:	select DRM_KMS_DMA_HELPER
> drivers/gpu/drm/logicvc/Kconfig:7:	select DRM_KMS_DMA_HELPER

For these two, the symbol was removed in commit
09717af7d13d63df141ae6e71686289989d17efd but these two drivers either were
missed by the batch rename or were introduced a bit later.

Since the symbol selected DRM_GEM_CMA_HELPER (which is still needed by the
drivers), it should be replaced with DRM_GEM_CMA_HELPER.

Are you expecting to craft a patch for fixing this or should I do it myself?

All the best,

Paul

-- 
Paul Kocialkowski,

Independent contractor - sys-base - https://www.sys-base.io/
Free software developer - https://www.paulk.fr/

Expert in multimedia, graphics and embedded hardware support with Linux.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251208/90fe417c/attachment-0001.sig>

From reinette.chatre at intel.com  Mon Dec  8 10:21:29 2025
From: reinette.chatre at intel.com (Reinette Chatre)
Date: Mon, 8 Dec 2025 10:21:29 -0800
Subject: [PATCH v6 00/34] arm_mpam: Add basic mpam driver
In-Reply-To: <87tsy0kgwy.fsf@stealth>
References: <20251119122305.302149-1-ben.horgan@arm.com>
 <877bvfa23i.fsf@stealth> <a04aa337-a3eb-42a0-855b-500ba549e2d8@arm.com>
 <87sedrlsjk.fsf@stealth> <642767c9-f926-490a-83a1-160978c37553@arm.com>
 <871pl9krdz.fsf@stealth> <5261337c-337d-44ca-aff1-0a927b81e593@intel.com>
 <87tsy0kgwy.fsf@stealth>
Message-ID: <f5095a4c-4617-441f-95af-9255cefdcf98@intel.com>

Hi Punit,

On 12/8/25 9:43 AM, Punit Agrawal wrote:
> Hi Reinette,
> 
> Reinette Chatre <reinette.chatre at intel.com> writes:
> 
>> Hi Punit,
>>
>> On 12/5/25 5:08 AM, Punit Agrawal wrote:
>>> James Morse <james.morse at arm.com> writes:
>>>> On 03/12/2025 11:21, Punit Agrawal wrote:
>>>>> Ben Horgan <ben.horgan at arm.com> writes:
>>>>>> On 11/24/25 15:21, Punit Agrawal wrote:
>>
>>>>>>> The platform has MSCs attached
>>>>>>> to shared L2 caches which are being skipped during later stages of
>>>>>>> initialisation. IIUC, the L2 MSCs' limitations stems from the
>>>>>>> assumptions in the resctrl interface.
>>>>>>
>>>>>> What in particualar is being skipped?
>>>>
>>>>> The registration of the discovered MSCs with resctrl and subsequent
>>>>> exposing it to the user.
>>>>
>>>> resctrl's 'L2' support is limited to the CPOR bitmap.
>>>> If you have controls, there is no resctrl 'event' that can exposed them.
>>>> (the problem being they all have 'L3' in the name!)
>>>
>>>>>>> I was wondering if there are any patches available to relax these
>>>>>>> limitations?
>>>
>>>> Knowing which property it is will help - but some of these things are checked
>>>> to match resctrl's ABI. They can't necessarily be relaxed without breaking
>>>> user-space.
>>>
>>> This platform has portion, capacity and priority partitioning, as well
>>> as memory bandwidth and cache storage monitoring. The MPAM code seems to
>>> correctly parse the properties.
>>>
>>> But as you point out, the resctrl 'L2' support doesn't have anything
>>> other than CPOR bitmap yet. Have you looked at what's needed to extend
>>> resctrl to support some of the others?
>>
>> Please see [1] for a summary of ideas on how resctrl can support multiple
>> controls. Nothing is final, please do add your ideas and requirements.
>>
>> There are a couple of opens not included in the summary. If interested
>> [2] is where a lot of discussion happened that prompted the need for
>> a summary.
> 
> Thanks a lot for the pointers.
> 
> Let me catch up with what's already discussed and raise any points that
> are not clear / need refining.

Please do. There are already a few known open issues. I plan to raise awareness
of these discussions (and the (so far known) sticky points still left to resolve) during
the resctrl session at LPC:
https://lpc.events/event/19/contributions/2093/

I am attending LPC remotely though so I hope increased awareness will result in more traffic
to [1] to help us get this right.

Reinette


> 
>>
>> Reinette
>>
>> [1] https://lore.kernel.org/lkml/aPtfMFfLV1l%2FRB0L at e133380.arm.com/
>> [2] https://lore.kernel.org/lkml/aNFliMZTTUiXyZzd at e133380.arm.com/



From rdunlap at infradead.org  Mon Dec  8 10:39:58 2025
From: rdunlap at infradead.org (Randy Dunlap)
Date: Mon, 8 Dec 2025 10:39:58 -0800
Subject: Kconfig dangling references (BZ 216748)
In-Reply-To: <aTcVXrUXVsyjaT22@shepard>
References: <22b92ddf-6321-41b5-8073-f9c7064d3432@infradead.org>
 <aTcVXrUXVsyjaT22@shepard>
Message-ID: <873236c8-4dab-4f1e-a2bf-d233ec74bd49@infradead.org>



On 12/8/25 10:13 AM, Paul Kocialkowski wrote:
> Hi Randy,
> 
> On Sun 07 Dec 25, 18:04, Randy Dunlap wrote:
>> from  https://bugzilla.kernel.org/show_bug.cgi?id=216748
>>
>> The bugzilla entry includes a Perl script and a shell script.
>> This is the edited result of running them (I removed some entries that were noise).
> 
> [...]
> 
>> DRM_KMS_DMA_HELPER ---
>> drivers/gpu/drm/adp/Kconfig:9:	select DRM_KMS_DMA_HELPER
>> drivers/gpu/drm/logicvc/Kconfig:7:	select DRM_KMS_DMA_HELPER
> 
> For these two, the symbol was removed in commit
> 09717af7d13d63df141ae6e71686289989d17efd but these two drivers either were
> missed by the batch rename or were introduced a bit later.
> 
> Since the symbol selected DRM_GEM_CMA_HELPER (which is still needed by the
> drivers), it should be replaced with DRM_GEM_CMA_HELPER.
> 
> Are you expecting to craft a patch for fixing this or should I do it myself?

Hi Paul,
Please take care of it yourself.

Thanks.
-- 
~Randy



From lorenzo at kernel.org  Mon Dec  8 10:54:08 2025
From: lorenzo at kernel.org (Lorenzo Bianconi)
Date: Mon, 08 Dec 2025 19:54:08 +0100
Subject: [PATCH mt76] wifi: mt76: Fix memory leak destroying device
Message-ID: <20251208-mt76-fix-memory-leak-v1-1-cba813fc62b8@kernel.org>

All MT76 rx queues have an associated page_pool even if the queue is not
associated to a NAPI (e.g. WED RRO queues with WED enabled). Destroy the
page_pool running mt76_dma_cleanup routine during module unload.
Moreover returns pages to the page pool if WED is not enabled for WED RRO
queues.

Fixes: 950d0abb5cd94 ("wifi: mt76: mt7996: add wed rx support")
Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
---
 drivers/net/wireless/mediatek/mt76/dma.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index f240016ed9f0ead27e98e350f4fdb818e1686781..893ac14285cab3c22f70945d490627a64b643efe 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -874,7 +874,12 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
 		if (!buf)
 			break;
 
-		if (!mt76_queue_is_wed_rro(q))
+		if (mtk_wed_device_active(&dev->mmio.wed) &&
+		    mt76_queue_is_wed_rro(q))
+			continue;
+
+		if (!mt76_queue_is_wed_rro_rxdmad_c(q) &&
+		    !mt76_queue_is_wed_rro_ind(q))
 			mt76_put_page_pool_buf(buf, false);
 	} while (1);
 
@@ -1168,10 +1173,6 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
 	mt76_for_each_q_rx(dev, i) {
 		struct mt76_queue *q = &dev->q_rx[i];
 
-		if (mtk_wed_device_active(&dev->mmio.wed) &&
-		    mt76_queue_is_wed_rro(q))
-			continue;
-
 		netif_napi_del(&dev->napi[i]);
 		mt76_dma_rx_cleanup(dev, q);
 

---
base-commit: 53d1548612670aa8b5d89745116cc33d9d172863
change-id: 20251208-mt76-fix-memory-leak-183680b1aff0

Best regards,
-- 
Lorenzo Bianconi <lorenzo at kernel.org>



From bibek.patro at oss.qualcomm.com  Mon Dec  8 11:28:24 2025
From: bibek.patro at oss.qualcomm.com (Bibek Kumar Patro)
Date: Tue, 9 Dec 2025 00:58:24 +0530
Subject: [PATCH V4] iommu/arm-smmu: add actlr settings for mdss on
 Qualcomm platforms
In-Reply-To: <gsjyj3arwoqcjln6nlmyhohlowyvkwqmxppdq5y7c3m4khoyq3@npzixjpibh5g>
References: <20251202125447.2102658-1-charan.kalla@oss.qualcomm.com>
 <gsjyj3arwoqcjln6nlmyhohlowyvkwqmxppdq5y7c3m4khoyq3@npzixjpibh5g>
Message-ID: <0bcd5a92-5213-4862-9a31-8ea539b1b72c@oss.qualcomm.com>



On 12/6/2025 2:36 AM, Bjorn Andersson wrote:
> On Tue, Dec 02, 2025 at 06:24:47PM +0530, Charan Teja Kalla wrote:
> 
> Based on the other changes to this file, the subject prefix should be
> "iommu/arm-smmu-qcom:"
> 

Sure Bjorn, I will address this in v4 RESEND and collect all reviewed-by
tags.
Let me know if you feel this change needs a revision update to v5
instead of v4-RESEND.

Thanks & regards,
Bibek

> Regards,
> Bjorn
> 
>> Add ACTLR settings for missing MDSS devices on Qualcomm platforms.
>>
>> These are QoS settings and are specific to per SoC thus different
>> settings, eg: some have shallow prefetch while others have no
>> prefetch.
>>
>> Aswell, this prefetch feature is not implemented for all the
>> platforms, capturing to those are implemented to the best of my
>> knowledge.
>>
>> Signed-off-by: Charan Teja Kalla <charan.kalla at oss.qualcomm.com>
>> ---
>> Changes from V3:
>>   1) Add actlr setting for missing sc8180x & sm6115.
>>   2) Improved commit message.
>> https://lore.kernel.org/all/20251124171030.323989-1-charan.kalla at oss.qualcomm.com/
>>
>> Changes from V2:
>>   1) Add actlr settings for all the mdss devices on Qualcomm platforms.
>>   2) Improved the commit message that explain why different ACTLR
>>      settings
>> https://lore.kernel.org/lkml/20251118171822.3539062-1-charan.kalla at oss.qualcomm.com/#t
>>
>> Changes from V1:
>>    1) Added actlr setting only for MDSS and dropped for fastrpc. --
>> konrad
>>    2) ACTLR table is updated per alphanumeric order -- konrad
>>    https://lore.kernel.org/all/20251105075307.1658329-1-charan.kalla at oss.qualcomm.com/
>>
>>   drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 26 ++++++++++++++++++++++
>>   1 file changed, 26 insertions(+)
>>
>> diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
>> index c21a401c71eb..149da53091de 100644
>> --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
>> +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
>> @@ -41,12 +41,38 @@ static const struct of_device_id qcom_smmu_actlr_client_of_match[] = {
>>   			.data = (const void *) (PREFETCH_DEEP | CPRE | CMTLB) },
>>   	{ .compatible = "qcom,fastrpc",
>>   			.data = (const void *) (PREFETCH_DEEP | CPRE | CMTLB) },
>> +	{ .compatible = "qcom,qcm2290-mdss",
>> +			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
>>   	{ .compatible = "qcom,sc7280-mdss",
>>   			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
>>   	{ .compatible = "qcom,sc7280-venus",
>>   			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
>> +	{ .compatible = "qcom,sc8180x-mdss",
>> +			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
>> +	{ .compatible = "qcom,sc8280xp-mdss",
>> +			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
>> +	{ .compatible = "qcom,sm6115-mdss",
>> +			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
>> +	{ .compatible = "qcom,sm6125-mdss",
>> +			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
>> +	{ .compatible = "qcom,sm6350-mdss",
>> +			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
>> +	{ .compatible = "qcom,sm8150-mdss",
>> +			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
>> +	{ .compatible = "qcom,sm8250-mdss",
>> +			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
>> +	{ .compatible = "qcom,sm8350-mdss",
>> +			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
>> +	{ .compatible = "qcom,sm8450-mdss",
>> +			.data = (const void *) (PREFETCH_DEFAULT | CMTLB) },
>>   	{ .compatible = "qcom,sm8550-mdss",
>>   			.data = (const void *) (PREFETCH_DEFAULT | CMTLB) },
>> +	{ .compatible = "qcom,sm8650-mdss",
>> +			.data = (const void *) (PREFETCH_DEFAULT | CMTLB) },
>> +	{ .compatible = "qcom,sm8750-mdss",
>> +			.data = (const void *) (PREFETCH_DEFAULT | CMTLB) },
>> +	{ .compatible = "qcom,x1e80100-mdss",
>> +			.data = (const void *) (PREFETCH_DEFAULT | CMTLB) },
>>   	{ }
>>   };
>>   
>> -- 
>> 2.34.1
>>
>>



From nicolas.dufresne at collabora.com  Mon Dec  8 11:32:46 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Mon, 08 Dec 2025 14:32:46 -0500
Subject: [PATCH] media: verisilicon: AV1: Fix tx mode bit setting
In-Reply-To: <20251208095227.19720-2-benjamin.gaignard@collabora.com>
References: <20251208095227.19720-1-benjamin.gaignard@collabora.com>
	 <20251208095227.19720-2-benjamin.gaignard@collabora.com>
Message-ID: <f03ed0ed3d5ffc780fb23d1945d75a6459ffbe22.camel@collabora.com>

Hi,

Le lundi 08 d?cembre 2025 ? 10:52 +0100, Benjamin Gaignard a ?crit?:
> If tx_mode field is non-zero then write it value + 2 else

it -> its



> write 0.


Please don't sent a an In-reply-to: email for a patch that isn't part of a
series.


> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard at collabora.com>
> Fixes: 727a400686a2c ("media: verisilicon: Add Rockchip AV1 decoder")
> ---
> ?drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c | 2 +-
> ?1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
> b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
> index f4f7cb45b1f1..fccdece51b1b 100644
> --- a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
> +++ b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
> @@ -2005,7 +2005,7 @@ static void
> rockchip_vpu981_av1_dec_set_parameters(struct hantro_ctx *ctx)
> ?			 !!(ctrls->frame->flags &
> V4L2_AV1_FRAME_FLAG_ALLOW_HIGH_PRECISION_MV));
> ?	hantro_reg_write(vpu, &av1_comp_pred_mode,
> ?			 (ctrls->frame->flags &
> V4L2_AV1_FRAME_FLAG_REFERENCE_SELECT) ? 2 : 0);
> -	hantro_reg_write(vpu, &av1_transform_mode, (ctrls->frame->tx_mode ==
> 1) ? 3 : 4);
> +	hantro_reg_write(vpu, &av1_transform_mode, ctrls->frame->tx_mode ?
> ctrls->frame->tx_mode + 2 : 0);

That all seem very hacky. Let's step back, and use that as inspiration for a
useful commit message. From bitstream we have:

tx_mode:
  0 == 4x4 only
  1 == SELECT
  2 == LARGEST

And the HW have:
  0 == 4x4 only
  1 == 8x8 and less
  2 == 16x16 and less
  3 == 32x32 and less
  4 == Select

Since the two enums have no relation (except for value 0), I'd suggest to
translate this in a switch (with nice enums so its readable).

  0 -> 0
  1 -> 4
  2 -> 3

Would be good to check if we can refine with some other params to reach HW value
1 and 2, but otherwise, that mapping is sufficient. Tha hacky +2 is really
obscure to me and I'd rather not do that upstream.

Nicolas

> ?	hantro_reg_write(vpu, &av1_max_cb_size,
> ?			 (ctrls->sequence->flags
> ?			? & V4L2_AV1_SEQUENCE_FLAG_USE_128X128_SUPERBLOCK) ?
> 7 : 6);
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251208/6965e3c9/attachment.sig>

From lkp at intel.com  Mon Dec  8 11:43:42 2025
From: lkp at intel.com (kernel test robot)
Date: Tue, 9 Dec 2025 03:43:42 +0800
Subject: [PATCH V4 1/3] iommu/arm-smmu-v3: Add device-tree support for
 CMDQV driver
In-Reply-To: <20251205065850.3841834-2-amhetre@nvidia.com>
References: <20251205065850.3841834-2-amhetre@nvidia.com>
Message-ID: <202512090331.QAFgb6vQ-lkp@intel.com>

Hi Ashish,

kernel test robot noticed the following build warnings:

[auto build test WARNING on next-20251204]
[also build test WARNING on v6.18]
[cannot apply to robh/for-next linus/master v6.18 v6.18-rc7 v6.18-rc6]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Ashish-Mhetre/iommu-arm-smmu-v3-Add-device-tree-support-for-CMDQV-driver/20251205-151258
base:   next-20251204
patch link:    https://lore.kernel.org/r/20251205065850.3841834-2-amhetre%40nvidia.com
patch subject: [PATCH V4 1/3] iommu/arm-smmu-v3: Add device-tree support for CMDQV driver
config: arm64-randconfig-004-20251209 (https://download.01.org/0day-ci/archive/20251209/202512090331.QAFgb6vQ-lkp at intel.com/config)
compiler: aarch64-linux-gcc (GCC) 11.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251209/202512090331.QAFgb6vQ-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512090331.QAFgb6vQ-lkp at intel.com/

All warnings (new ones prefixed by >>):

   drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c: In function 'tegra241_cmdqv_acpi_is_memory':
   drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c:863:17: error: implicit declaration of function 'acpi_dev_resource_address_space' [-Werror=implicit-function-declaration]
     863 |         return !acpi_dev_resource_address_space(res, &win);
         |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c: In function 'tegra241_cmdqv_acpi_get_irqs':
   drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c:871:26: error: implicit declaration of function 'acpi_dev_resource_interrupt' [-Werror=implicit-function-declaration]
     871 |         if (*irq <= 0 && acpi_dev_resource_interrupt(ares, 0, &r))
         |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c: In function 'tegra241_cmdqv_find_acpi_resource':
   drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c:879:36: error: implicit declaration of function 'to_acpi_device'; did you mean 'to_acpi_device_node'? [-Werror=implicit-function-declaration]
     879 |         struct acpi_device *adev = to_acpi_device(dev);
         |                                    ^~~~~~~~~~~~~~
         |                                    to_acpi_device_node
>> drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c:879:36: warning: initialization of 'struct acpi_device *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
   drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c:886:15: error: implicit declaration of function 'acpi_dev_get_resources'; did you mean 'acpi_get_event_resources'? [-Werror=implicit-function-declaration]
     886 |         ret = acpi_dev_get_resources(adev, &resource_list,
         |               ^~~~~~~~~~~~~~~~~~~~~~
         |               acpi_get_event_resources
   drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c:907:9: error: implicit declaration of function 'acpi_dev_free_resource_list' [-Werror=implicit-function-declaration]
     907 |         acpi_dev_free_resource_list(&resource_list);
         |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~
   cc1: some warnings being treated as errors


vim +879 drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c

918eb5c856f6ce Nate Watterson 2024-08-29  875  
918eb5c856f6ce Nate Watterson 2024-08-29  876  static struct resource *
918eb5c856f6ce Nate Watterson 2024-08-29  877  tegra241_cmdqv_find_acpi_resource(struct device *dev, int *irq)
918eb5c856f6ce Nate Watterson 2024-08-29  878  {
918eb5c856f6ce Nate Watterson 2024-08-29 @879  	struct acpi_device *adev = to_acpi_device(dev);
918eb5c856f6ce Nate Watterson 2024-08-29  880  	struct list_head resource_list;
918eb5c856f6ce Nate Watterson 2024-08-29  881  	struct resource_entry *rentry;
918eb5c856f6ce Nate Watterson 2024-08-29  882  	struct resource *res = NULL;
918eb5c856f6ce Nate Watterson 2024-08-29  883  	int ret;
918eb5c856f6ce Nate Watterson 2024-08-29  884  
918eb5c856f6ce Nate Watterson 2024-08-29  885  	INIT_LIST_HEAD(&resource_list);
918eb5c856f6ce Nate Watterson 2024-08-29  886  	ret = acpi_dev_get_resources(adev, &resource_list,
918eb5c856f6ce Nate Watterson 2024-08-29  887  				     tegra241_cmdqv_acpi_is_memory, NULL);
918eb5c856f6ce Nate Watterson 2024-08-29  888  	if (ret < 0) {
918eb5c856f6ce Nate Watterson 2024-08-29  889  		dev_err(dev, "failed to get memory resource: %d\n", ret);
918eb5c856f6ce Nate Watterson 2024-08-29  890  		return NULL;
918eb5c856f6ce Nate Watterson 2024-08-29  891  	}
918eb5c856f6ce Nate Watterson 2024-08-29  892  
918eb5c856f6ce Nate Watterson 2024-08-29  893  	rentry = list_first_entry_or_null(&resource_list,
918eb5c856f6ce Nate Watterson 2024-08-29  894  					  struct resource_entry, node);
918eb5c856f6ce Nate Watterson 2024-08-29  895  	if (!rentry) {
918eb5c856f6ce Nate Watterson 2024-08-29  896  		dev_err(dev, "failed to get memory resource entry\n");
918eb5c856f6ce Nate Watterson 2024-08-29  897  		goto free_list;
918eb5c856f6ce Nate Watterson 2024-08-29  898  	}
918eb5c856f6ce Nate Watterson 2024-08-29  899  
918eb5c856f6ce Nate Watterson 2024-08-29  900  	/* Caller must free the res */
918eb5c856f6ce Nate Watterson 2024-08-29  901  	res = kzalloc(sizeof(*res), GFP_KERNEL);
918eb5c856f6ce Nate Watterson 2024-08-29  902  	if (!res)
918eb5c856f6ce Nate Watterson 2024-08-29  903  		goto free_list;
918eb5c856f6ce Nate Watterson 2024-08-29  904  
918eb5c856f6ce Nate Watterson 2024-08-29  905  	*res = *rentry->res;
918eb5c856f6ce Nate Watterson 2024-08-29  906  
918eb5c856f6ce Nate Watterson 2024-08-29  907  	acpi_dev_free_resource_list(&resource_list);
918eb5c856f6ce Nate Watterson 2024-08-29  908  
918eb5c856f6ce Nate Watterson 2024-08-29  909  	INIT_LIST_HEAD(&resource_list);
918eb5c856f6ce Nate Watterson 2024-08-29  910  
918eb5c856f6ce Nate Watterson 2024-08-29  911  	if (irq)
918eb5c856f6ce Nate Watterson 2024-08-29  912  		ret = acpi_dev_get_resources(adev, &resource_list,
918eb5c856f6ce Nate Watterson 2024-08-29  913  					     tegra241_cmdqv_acpi_get_irqs, irq);
918eb5c856f6ce Nate Watterson 2024-08-29  914  	if (ret < 0 || !irq || *irq <= 0)
918eb5c856f6ce Nate Watterson 2024-08-29  915  		dev_warn(dev, "no interrupt. errors will not be reported\n");
918eb5c856f6ce Nate Watterson 2024-08-29  916  
918eb5c856f6ce Nate Watterson 2024-08-29  917  free_list:
918eb5c856f6ce Nate Watterson 2024-08-29  918  	acpi_dev_free_resource_list(&resource_list);
918eb5c856f6ce Nate Watterson 2024-08-29  919  	return res;
918eb5c856f6ce Nate Watterson 2024-08-29  920  }
918eb5c856f6ce Nate Watterson 2024-08-29  921  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From nicolas.dufresne at collabora.com  Mon Dec  8 11:45:02 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Mon, 08 Dec 2025 14:45:02 -0500
Subject: [PATCH] media: verisilicon: AV1: Fix enable cdef computation
In-Reply-To: <20251208095227.19720-1-benjamin.gaignard@collabora.com>
References: <20251208095227.19720-1-benjamin.gaignard@collabora.com>
Message-ID: <4545bc3df2592965388aee3f170cce577d8cf538.camel@collabora.com>

Hi,

Le lundi 08 d?cembre 2025 ? 10:52 +0100, Benjamin Gaignard a ?crit?:
> Testing V4L2_AV1_SEQUENCE_FLAG_ENABLE_CDEF flag isn't enough
> to know if cdef bit has to be set.
> If any of the used cdef fields isn't zero then we must enable
> cdef feature on the hardware.

I think the problem goes the other way around.

   If all the fields of the CDEF parameters are zero (which is the default), then
   av1_enable_cdef register needs to be unset (despite the
   V4L2_AV1_SEQUENCE_FLAG_ENABLE_CDEF possibly being set).

Its interesting to note that the other AV1 decoder also ignores this flag.
Though, I don't have enough data to add something to the doc to try and convince
future driver writers to not use it.

> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard at collabora.com>
> Fixes: 727a400686a2c ("media: verisilicon: Add Rockchip AV1 decoder")

This is missing:

Reported-by: Jianfeng Liu <liujianfeng1994 at gmail.com>
Link: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/4786

Please also include my Rb in v2 with correct commit message.

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

Nicolas

> ---
> ?.../platform/verisilicon/rockchip_vpu981_hw_av1_dec.c? | 10 ++++++++--
> ?1 file changed, 8 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
> index e4703bb6be7c..f4f7cb45b1f1 100644
> --- a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
> +++ b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
> @@ -1396,8 +1396,16 @@ static void rockchip_vpu981_av1_dec_set_cdef(struct hantro_ctx *ctx)
> ?	u16 luma_sec_strength = 0;
> ?	u32 chroma_pri_strength = 0;
> ?	u16 chroma_sec_strength = 0;
> +	bool enable_cdef;
> ?	int i;
> ?
> +	enable_cdef = !(cdef->bits == 0 &&
> +			cdef->damping_minus_3 == 0 &&
> +			cdef->y_pri_strength[0] == 0 &&
> +			cdef->y_sec_strength[0] == 0 &&
> +			cdef->uv_pri_strength[0] == 0 &&
> +			cdef->uv_sec_strength[0] == 0);
> +	hantro_reg_write(vpu, &av1_enable_cdef, enable_cdef);
> ?	hantro_reg_write(vpu, &av1_cdef_bits, cdef->bits);
> ?	hantro_reg_write(vpu, &av1_cdef_damping, cdef->damping_minus_3);
> ?
> @@ -1953,8 +1961,6 @@ static void rockchip_vpu981_av1_dec_set_parameters(struct hantro_ctx *ctx)
> ?			 !!(ctrls->frame->flags & V4L2_AV1_FRAME_FLAG_SHOW_FRAME));
> ?	hantro_reg_write(vpu, &av1_switchable_motion_mode,
> ?			 !!(ctrls->frame->flags & V4L2_AV1_FRAME_FLAG_IS_MOTION_MODE_SWITCHABLE));
> -	hantro_reg_write(vpu, &av1_enable_cdef,
> -			 !!(ctrls->sequence->flags & V4L2_AV1_SEQUENCE_FLAG_ENABLE_CDEF));
> ?	hantro_reg_write(vpu, &av1_allow_masked_compound,
> ?			 !!(ctrls->sequence->flags
> ?			??? & V4L2_AV1_SEQUENCE_FLAG_ENABLE_MASKED_COMPOUND));
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251208/22b034d4/attachment-0001.sig>

From j at jannau.net  Mon Dec  8 12:05:55 2025
From: j at jannau.net (Janne Grunau)
Date: Mon, 8 Dec 2025 21:05:55 +0100
Subject: Kconfig dangling references (BZ 216748)
In-Reply-To: <aTcVXrUXVsyjaT22@shepard>
References: <22b92ddf-6321-41b5-8073-f9c7064d3432@infradead.org>
 <aTcVXrUXVsyjaT22@shepard>
Message-ID: <20251208200555.GA333481@robin.jannau.net>

On Mon, Dec 08, 2025 at 07:13:50PM +0100, Paul Kocialkowski wrote:
> Hi Randy,
> 
> On Sun 07 Dec 25, 18:04, Randy Dunlap wrote:
> > from  https://bugzilla.kernel.org/show_bug.cgi?id=216748
> > 
> > The bugzilla entry includes a Perl script and a shell script.
> > This is the edited result of running them (I removed some entries that were noise).
> 
> [...]
> 
> > DRM_KMS_DMA_HELPER ---
> > drivers/gpu/drm/adp/Kconfig:9:	select DRM_KMS_DMA_HELPER
> > drivers/gpu/drm/logicvc/Kconfig:7:	select DRM_KMS_DMA_HELPER
> 
> For these two, the symbol was removed in commit
> 09717af7d13d63df141ae6e71686289989d17efd

That commit removed DRM_KMS_CMA_HELPER. Later commit 6bcfe8eaeef0
("drm/fb: rename FB CMA helpers to FB DMA helpers") renamed
DRM_KMS_CMA_HELPER erroneously to DRM_KMS_DMA_HELPER.

> but these two drivers either were
> missed by the batch rename or were introduced a bit later.

In the case of drivers/gpu/drm/adp/Kconfig it was missed much later
during review (but iirc went through the same rename out of tree).

> Since the symbol selected DRM_GEM_CMA_HELPER (which is still needed by the
> drivers), it should be replaced with DRM_GEM_CMA_HELPER.

That symbol doesn't exist anymore either. It's now DRM_GEM_DMA_HELPER
which is already present in both files.

So the "select DRM_KMS_DMA_HELPER" lines can be removed from both files.

Janne


From daniel at gibson.sh  Mon Dec  8 12:48:54 2025
From: daniel at gibson.sh (Daniel Gibson)
Date: Mon, 8 Dec 2025 21:48:54 +0100
Subject: [PATCH 05/12] gpio: it87: use new line value setter callbacks
In-Reply-To: <CAMRc=Mc8ViSPyTn9Brr-us2V+D7Jv3u+B8Ek2nuzF36yH70RAw@mail.gmail.com>
References: <20250423-gpiochip-set-rv-gpio-part2-v1-0-b22245cde81a@linaro.org>
 <20250423-gpiochip-set-rv-gpio-part2-v1-5-b22245cde81a@linaro.org>
 <bd0a00e3-9b8c-43e8-8772-e67b91f4c71e@gibson.sh>
 <CAMRc=Mc8ViSPyTn9Brr-us2V+D7Jv3u+B8Ek2nuzF36yH70RAw@mail.gmail.com>
Message-ID: <22ae55db-261d-4bb7-a83c-12fd00fa5527@gibson.sh>

On 12/8/25 05:48, Bartosz Golaszewski wrote:
> 
> Thanks for bringing it to my attention, you're probably right and thats's
> just an unintentional omission on my part. Do you want to send a patch that
> will fix it or do you prefer me to do it?
> 
> Bart

Thanks for the quick reply!

I'd prefer if you do it, I'm not too familiar with the kernel workflow.

Cheers,
Daniel




From alexandre.belloni at bootlin.com  Mon Dec  8 14:09:08 2025
From: alexandre.belloni at bootlin.com (Alexandre Belloni)
Date: Mon, 8 Dec 2025 23:09:08 +0100
Subject: (subset) [PATCH v5 00/11] mfd: macsmc: add rtc, hwmon and hid
 subdevices
In-Reply-To: <20251112-macsmc-subdevs-v5-0-728e4b91fe81@gmail.com>
References: <20251112-macsmc-subdevs-v5-0-728e4b91fe81@gmail.com>
Message-ID: <176523152354.342815.17888940507252789645.b4-ty@bootlin.com>

On Wed, 12 Nov 2025 21:16:46 +1000, James Calligeros wrote:
> This series adds support for the remaining SMC subdevices. These are the
> RTC, hwmon, and HID devices. They are being submitted together as the RTC
> and hwmon drivers both require changes to the SMC DT schema.
> 
> The RTC driver is responsible for getting and setting the system clock,
> and requires an NVMEM cell. This series replaces Sven's original RTC driver
> submission [1].
> 
> [...]

Applied, thanks!

[01/11] dt-bindings: rtc: Add Apple SMC RTC
        https://git.kernel.org/abelloni/c/07049187e830
[03/11] rtc: Add new rtc-macsmc driver for Apple Silicon Macs
        https://git.kernel.org/abelloni/c/49a51df427db

Best regards,

-- 
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From vvidwans at nvidia.com  Mon Dec  8 14:13:10 2025
From: vvidwans at nvidia.com (Vedashree Vidwans)
Date: Mon, 8 Dec 2025 22:13:10 +0000
Subject: [RFC PATCH 0/5] Arm LFA: Improvements and interrupt support
Message-ID: <20251208221319.1524888-1-vvidwans@nvidia.com>

Hello,

The patches update the proposed Arm Live Firmware Activation (LFA)
kernel driver [1] to incorporate review feedback [2] and refine the
activation flow while remaining aligned with the LFA specification
DEN0147 [3] and the SMCCC 1.2 calling convention. The series keeps
the existing functionality but restructures and extends it to improve
robustness, reviewability, and future extensibility.?

The SMCCC usage in the driver is updated to consistently use the
SMCCC 1.2 register-based calling convention, consolidating arguments
and results into a single struct to reduce stack usage and simplify
the SMC interface. The patches also split the original changes into
focused pieces and document the device node bindings in the commit
messages, making it easier to follow and validate the implementation
against the specification.?

The kernel driver is registered as a platform driver in accordence to
the LFA device defined by the specification [3]. The driver now extends
interface for interrupt-based enablement of LFA. During LFA, the
interrupt
thread refreshes firmware component details after each activation step
and iterates over all activable components until no further activation
is pending, matching the spec?s allowance for component detail changes
after activation. This ensures that sysfs exposure of LFA components
remains consistent with the authoritative information provided by the
secure firmware.?

The handling of CPU rendezvous is adjusted so that the kernel now
honors the rendezvous policy chosen by the firmware, instead of
unconditionally forcing a rendezvous. This reflects experience with
existing firmware deployments where mandatory rendezvous is not
required, while still allowing the firmware to request it when
needed.?

Thank you,
Veda

[1] https://lore.kernel.org/lkml/20250926123145.268728-1-salman.nabi at arm.com/
[2] https://lkml.org/lkml/2025/10/8/980
[3] https://developer.arm.com/documentation/den0147/latest/

Vedashree Vidwans (5):
  firmware: smccc: LFA: use smcc 1.2
  firmware: smccc: LFA: refactor
  firmware: smccc: add timeout, touch wdt
  firmware: smccc: register as platform driver
  firmware: smccc: lfa: refresh fw details

 drivers/firmware/smccc/Kconfig  |   3 +-
 drivers/firmware/smccc/lfa_fw.c | 478 +++++++++++++++++++++++++-------
 2 files changed, 380 insertions(+), 101 deletions(-)

-- 
2.43.0



From vvidwans at nvidia.com  Mon Dec  8 14:13:11 2025
From: vvidwans at nvidia.com (Vedashree Vidwans)
Date: Mon, 8 Dec 2025 22:13:11 +0000
Subject: [RFC PATCH 1/5] firmware: smccc: LFA: use smcc 1.2
In-Reply-To: <20251208221319.1524888-1-vvidwans@nvidia.com>
References: <20251208221319.1524888-1-vvidwans@nvidia.com>
Message-ID: <20251208221319.1524888-2-vvidwans@nvidia.com>

Update driver to use SMCCC 1.2+ version as mentioned in the LFA spec.

Signed-off-by: Vedashree Vidwans <vvidwans at nvidia.com>
---
 drivers/firmware/smccc/lfa_fw.c | 102 ++++++++++++++++++++------------
 1 file changed, 65 insertions(+), 37 deletions(-)

diff --git a/drivers/firmware/smccc/lfa_fw.c b/drivers/firmware/smccc/lfa_fw.c
index 1f333237271d..bdde14b66606 100644
--- a/drivers/firmware/smccc/lfa_fw.c
+++ b/drivers/firmware/smccc/lfa_fw.c
@@ -117,32 +117,38 @@ static struct kobject *lfa_dir;
 
 static int get_nr_lfa_components(void)
 {
-	struct arm_smccc_res res = { 0 };
+	struct arm_smccc_1_2_regs reg = { 0 };
 
-	arm_smccc_1_1_invoke(LFA_1_0_FN_GET_INFO, 0x0, &res);
-	if (res.a0 != LFA_SUCCESS)
-		return res.a0;
+	reg.a0 = LFA_1_0_FN_GET_INFO;
+	reg.a1 = 0; /* lfa_info_selector = 0 */
 
-	return res.a1;
+	arm_smccc_1_2_invoke(&reg, &reg);
+	if (reg.a0 != LFA_SUCCESS)
+		return reg.a0;
+
+	return reg.a1;
 }
 
 static int call_lfa_activate(void *data)
 {
 	struct image_props *attrs = data;
-	struct arm_smccc_res res = { 0 };
+	struct arm_smccc_1_2_regs args = { 0 };
+	struct arm_smccc_1_2_regs res = { 0 };
+
+	args.a0 = LFA_1_0_FN_ACTIVATE;
+	args.a1 = attrs->fw_seq_id; /* fw_seq_id under consideration */
+	/*
+	 * As we do not support updates requiring a CPU reset (yet),
+	 * we pass 0 in args.a3 and args.a4, holding the entry point and context
+	 * ID respectively.
+	 * We want to force CPU rendezvous if either cpu_rendezvous or
+	 * cpu_rendezvous_forced is set. The flag value is flipped as
+	 * it is called skip_cpu_rendezvous in the spec.
+	 */
+	args.a2 = !(attrs->cpu_rendezvous_forced || attrs->cpu_rendezvous);
 
 	do {
-		/*
-		 * As we do not support updates requiring a CPU reset (yet),
-		 * we pass 0 in x3 and x4, holding the entry point and context
-		 * ID respectively.
-		 * We want to force CPU rendezvous if either cpu_rendezvous or
-		 * cpu_rendezvous_forced is set. The flag value is flipped as
-		 * it is called skip_cpu_rendezvous in the spec.
-		 */
-		arm_smccc_1_1_invoke(LFA_1_0_FN_ACTIVATE, attrs->fw_seq_id,
-			!(attrs->cpu_rendezvous_forced || attrs->cpu_rendezvous),
-			0, 0, &res);
+		arm_smccc_1_2_invoke(&args, &res);
 	} while (res.a0 == 0 && res.a1 == 1);
 
 	return res.a0;
@@ -150,7 +156,8 @@ static int call_lfa_activate(void *data)
 
 static int activate_fw_image(struct image_props *attrs)
 {
-	struct arm_smccc_res res = { 0 };
+	struct arm_smccc_1_2_regs args = { 0 };
+	struct arm_smccc_1_2_regs res = { 0 };
 	int ret;
 
 	/*
@@ -159,8 +166,10 @@ static int activate_fw_image(struct image_props *attrs)
 	 * LFA_PRIME/ACTIVATE will need to be called again.
 	 * res.a1 will become 0 once the prime/activate process completes.
 	 */
+	args.a0 = LFA_1_0_FN_PRIME;
+	args.a1 = attrs->fw_seq_id; /* fw_seq_id under consideration */
 	do {
-		arm_smccc_1_1_invoke(LFA_1_0_FN_PRIME, attrs->fw_seq_id, &res);
+		arm_smccc_1_2_invoke(&args, &res);
 		if (res.a0 != LFA_SUCCESS) {
 			pr_err("LFA_PRIME failed: %s\n",
 				lfa_error_strings[-res.a0]);
@@ -211,15 +220,17 @@ static ssize_t activation_pending_show(struct kobject *kobj,
 {
 	struct image_props *attrs = container_of(attr, struct image_props,
 					 image_attrs[LFA_ATTR_ACT_PENDING]);
-	struct arm_smccc_res res = { 0 };
+	struct arm_smccc_1_2_regs reg = { 0 };
 
 	/*
 	 * Activation pending status can change anytime thus we need to update
 	 * and return its current value
 	 */
-	arm_smccc_1_1_invoke(LFA_1_0_FN_GET_INVENTORY, attrs->fw_seq_id, &res);
-	if (res.a0 == LFA_SUCCESS)
-		attrs->activation_pending = !!(res.a3 & BIT(1));
+	reg.a0 = LFA_1_0_FN_GET_INVENTORY;
+	reg.a1 = attrs->fw_seq_id;
+	arm_smccc_1_2_invoke(&reg, &reg);
+	if (reg.a0 == LFA_SUCCESS)
+		attrs->activation_pending = !!(reg.a3 & BIT(1));
 
 	return sysfs_emit(buf, "%d\n", attrs->activation_pending);
 }
@@ -298,21 +309,23 @@ static ssize_t cancel_store(struct kobject *kobj, struct kobj_attribute *attr,
 {
 	struct image_props *attrs = container_of(attr, struct image_props,
 						 image_attrs[LFA_ATTR_CANCEL]);
-	struct arm_smccc_res res = { 0 };
+	struct arm_smccc_1_2_regs reg = { 0 };
 
-	arm_smccc_1_1_invoke(LFA_1_0_FN_CANCEL, attrs->fw_seq_id, &res);
+	reg.a0 = LFA_1_0_FN_CANCEL;
+	reg.a1 = attrs->fw_seq_id;
+	arm_smccc_1_2_invoke(&reg, &reg);
 
 	/*
 	 * When firmware activation is called with "skip_cpu_rendezvous=1",
 	 * LFA_CANCEL can fail with LFA_BUSY if the activation could not be
 	 * cancelled.
 	 */
-	if (res.a0 == LFA_SUCCESS) {
+	if (reg.a0 == LFA_SUCCESS) {
 		pr_info("Activation cancelled for image %s\n",
 			attrs->image_name);
 	} else {
 		pr_err("Firmware activation could not be cancelled: %s\n",
-		       lfa_error_strings[-res.a0]);
+		       lfa_error_strings[-reg.a0]);
 		return -EINVAL;
 	}
 
@@ -395,21 +408,24 @@ static int create_fw_inventory(char *fw_uuid, int seq_id, u32 image_flags)
 
 static int create_fw_images_tree(void)
 {
-	struct arm_smccc_res res = { 0 };
+	struct arm_smccc_1_2_regs reg = { 0 };
 	struct uuid_regs image_uuid;
 	char image_id_str[40];
 	int ret, num_of_components;
 
 	num_of_components = get_nr_lfa_components();
+
 	for (int i = 0; i < num_of_components; i++) {
-		arm_smccc_1_1_invoke(LFA_1_0_FN_GET_INVENTORY, i, &res);
-		if (res.a0 == LFA_SUCCESS) {
-			image_uuid.uuid_lo = res.a1;
-			image_uuid.uuid_hi = res.a2;
+		reg.a0 = LFA_1_0_FN_GET_INVENTORY;
+		reg.a1 = i; /* fw_seq_id under consideration */
+		arm_smccc_1_2_invoke(&reg, &reg);
+		if (reg.a0 == LFA_SUCCESS) {
+			image_uuid.uuid_lo = reg.a1;
+			image_uuid.uuid_hi = reg.a2;
 
 			snprintf(image_id_str, sizeof(image_id_str), "%pUb",
 				 &image_uuid);
-			ret = create_fw_inventory(image_id_str, i, res.a3);
+			ret = create_fw_inventory(image_id_str, i, reg.a3);
 			if (ret)
 				return ret;
 		}
@@ -420,17 +436,29 @@ static int create_fw_images_tree(void)
 
 static int __init lfa_init(void)
 {
-	struct arm_smccc_res res = { 0 };
+	struct arm_smccc_1_2_regs reg = { 0 };
 	int err;
 
-	arm_smccc_1_1_invoke(LFA_1_0_FN_GET_VERSION, &res);
-	if (res.a0 == -LFA_NOT_SUPPORTED) {
+	/* LFA requires SMCCC version >= 1.2 */
+	if (arm_smccc_get_version() < ARM_SMCCC_VERSION_1_2) {
+		pr_err("Not supported with SMCCC version %u", arm_smccc_get_version());
+		return -ENODEV;
+	}
+
+	if (arm_smccc_1_1_get_conduit() == SMCCC_CONDUIT_NONE) {
+		pr_err("Invalid SMCCC conduit");
+		return -ENODEV;
+	}
+
+	reg.a0 = LFA_1_0_FN_GET_VERSION;
+	arm_smccc_1_2_invoke(&reg, &reg);
+	if (reg.a0 == -LFA_NOT_SUPPORTED) {
 		pr_err("Arm Live Firmware activation(LFA): no firmware agent found\n");
 		return -ENODEV;
 	}
 
 	pr_info("Arm Live Firmware Activation (LFA): detected v%ld.%ld\n",
-		res.a0 >> 16, res.a0 & 0xffff);
+		reg.a0 >> 16, reg.a0 & 0xffff);
 
 	lfa_dir = kobject_create_and_add("lfa", firmware_kobj);
 	if (!lfa_dir)
-- 
2.43.0



From vvidwans at nvidia.com  Mon Dec  8 14:13:13 2025
From: vvidwans at nvidia.com (Vedashree Vidwans)
Date: Mon, 8 Dec 2025 22:13:13 +0000
Subject: [RFC PATCH 3/5] firmware: smccc: add timeout, touch wdt
In-Reply-To: <20251208221319.1524888-1-vvidwans@nvidia.com>
References: <20251208221319.1524888-1-vvidwans@nvidia.com>
Message-ID: <20251208221319.1524888-4-vvidwans@nvidia.com>

Enhance PRIME/ACTIVATION functions to touch watchdog and implement
timeout mechanism. This update ensures that any potential hangs are
detected promptly and that the LFA process is allocated sufficient
execution time before the watchdog timer expires. These changes improve
overall system reliability by reducing the risk of undetected process
stalls and unexpected watchdog resets.

Signed-off-by: Vedashree Vidwans <vvidwans at nvidia.com>
---
 drivers/firmware/smccc/lfa_fw.c | 74 +++++++++++++++++++++++++++++----
 1 file changed, 67 insertions(+), 7 deletions(-)

diff --git a/drivers/firmware/smccc/lfa_fw.c b/drivers/firmware/smccc/lfa_fw.c
index df8b65324413..0e420cefa260 100644
--- a/drivers/firmware/smccc/lfa_fw.c
+++ b/drivers/firmware/smccc/lfa_fw.c
@@ -16,6 +16,9 @@
 #include <linux/uuid.h>
 #include <linux/array_size.h>
 #include <linux/list.h>
+#include <linux/nmi.h>
+#include <linux/ktime.h>
+#include <linux/delay.h>
 
 #define LFA_ERROR_STRING(name) \
 	[name] = #name
@@ -34,6 +37,18 @@
 #define LFA_1_0_FN_ACTIVATE		LFA_1_0_FN(5)
 #define LFA_1_0_FN_CANCEL		LFA_1_0_FN(6)
 
+/* CALL_AGAIN flags (returned by SMC) */
+#define LFA_PRIME_CALL_AGAIN		BIT(0)
+#define LFA_ACTIVATE_CALL_AGAIN		BIT(0)
+
+/* Prime loop limits, TODO: tune after testing */
+#define LFA_PRIME_BUDGET_US		30000000	/* 30s cap */
+#define LFA_PRIME_POLL_DELAY_US		10		/* 10us between polls */
+
+/* Activation loop limits, TODO: tune after testing */
+#define LFA_ACTIVATE_BUDGET_US		20000000	/* 20s cap */
+#define LFA_ACTIVATE_POLL_DELAY_US	10		/* 10us between polls */
+
 /* LFA return values */
 #define LFA_SUCCESS			0
 #define LFA_NOT_SUPPORTED		1
@@ -159,6 +174,8 @@ static int call_lfa_activate(void *data)
 	struct image_props *attrs = data;
 	struct arm_smccc_1_2_regs args = { 0 };
 	struct arm_smccc_1_2_regs res = { 0 };
+	ktime_t end = ktime_add_us(ktime_get(), LFA_ACTIVATE_BUDGET_US);
+	int ret;
 
 	args.a0 = LFA_1_0_FN_ACTIVATE;
 	args.a1 = attrs->fw_seq_id; /* fw_seq_id under consideration */
@@ -172,9 +189,34 @@ static int call_lfa_activate(void *data)
 	 */
 	args.a2 = !(attrs->cpu_rendezvous_forced || attrs->cpu_rendezvous);
 
-	do {
+	for (;;) {
+		/* Touch watchdog, ACTIVATE shouldn't take longer than watchdog_thresh */
+		touch_nmi_watchdog();
 		arm_smccc_1_2_invoke(&args, &res);
-	} while (res.a0 == 0 && res.a1 == 1);
+
+		if ((long)res.a0 < 0) {
+			pr_err("ACTIVATE for image %s failed: %s",
+				attrs->image_name, lfa_error_strings[-res.a0]);
+			return res.a0;
+		}
+
+		/* SMC returned with success */
+		if (!(res.a1 & LFA_ACTIVATE_CALL_AGAIN))
+			break; /* ACTIVATE successful */
+
+		/* SMC returned with call_again flag set */
+		if (ktime_before(ktime_get(), end)) {
+			udelay(LFA_ACTIVATE_POLL_DELAY_US);
+			continue;
+		}
+
+		pr_err("ACTIVATE timed out for image %s", attrs->image_name);
+		ret = lfa_cancel(attrs);
+		if (ret == 0)
+			return -ETIMEDOUT;
+		else
+			return ret;
+	}
 
 	return res.a0;
 }
@@ -183,6 +225,7 @@ static int activate_fw_image(struct image_props *attrs)
 {
 	struct arm_smccc_1_2_regs args = { 0 };
 	struct arm_smccc_1_2_regs res = { 0 };
+	ktime_t end = ktime_add_us(ktime_get(), LFA_PRIME_BUDGET_US);
 	int ret;
 
 	if (attrs->may_reset_cpu) {
@@ -198,15 +241,32 @@ static int activate_fw_image(struct image_props *attrs)
 	 */
 	args.a0 = LFA_1_0_FN_PRIME;
 	args.a1 = attrs->fw_seq_id; /* fw_seq_id under consideration */
-	do {
+	for (;;) {
+		/* Touch watchdog, PRIME shouldn't take longer than watchdog_thresh */
+		touch_nmi_watchdog();
 		arm_smccc_1_2_invoke(&args, &res);
-		if (res.a0 != LFA_SUCCESS) {
-			pr_err("LFA_PRIME failed: %s\n",
-				lfa_error_strings[-res.a0]);
 
+		if ((long)res.a0 < 0) {
+			pr_err("LFA_PRIME for image %s failed: %s\n",
+				attrs->image_name, lfa_error_strings[-res.a0]);
 			return res.a0;
 		}
-	} while (res.a1 == 1);
+		if (!(res.a1 & LFA_PRIME_CALL_AGAIN))
+			break; /* PRIME successful */
+
+		/* SMC returned with call_again flag set */
+		if (ktime_before(ktime_get(), end)) {
+			udelay(LFA_PRIME_POLL_DELAY_US);
+			continue;
+		}
+
+		pr_err("PRIME timed out for image %s", attrs->image_name);
+		ret = lfa_cancel(attrs);
+		if (ret == 0)
+			return -ETIMEDOUT;
+		else
+			return ret;
+	}
 
 	if (attrs->cpu_rendezvous_forced || attrs->cpu_rendezvous)
 		ret = stop_machine(call_lfa_activate, attrs, cpu_online_mask);
-- 
2.43.0



From vvidwans at nvidia.com  Mon Dec  8 14:13:12 2025
From: vvidwans at nvidia.com (Vedashree Vidwans)
Date: Mon, 8 Dec 2025 22:13:12 +0000
Subject: [RFC PATCH 2/5] firmware: smccc: LFA: refactor
In-Reply-To: <20251208221319.1524888-1-vvidwans@nvidia.com>
References: <20251208221319.1524888-1-vvidwans@nvidia.com>
Message-ID: <20251208221319.1524888-3-vvidwans@nvidia.com>

- Refactor LFA CANCEL logic into independent lfa_cancel() function.
- Use FW UUID as image_name for images not known by the driver.
- Move may_reset_cpu check to activate_fw_image(). This keeps all the
functionality within a function.

Signed-off-by: Vedashree Vidwans <vvidwans at nvidia.com>
---
 drivers/firmware/smccc/lfa_fw.c | 64 ++++++++++++++++++++-------------
 1 file changed, 40 insertions(+), 24 deletions(-)

diff --git a/drivers/firmware/smccc/lfa_fw.c b/drivers/firmware/smccc/lfa_fw.c
index bdde14b66606..df8b65324413 100644
--- a/drivers/firmware/smccc/lfa_fw.c
+++ b/drivers/firmware/smccc/lfa_fw.c
@@ -129,6 +129,31 @@ static int get_nr_lfa_components(void)
 	return reg.a1;
 }
 
+static int lfa_cancel(struct image_props *attrs)
+{
+	struct arm_smccc_1_2_regs reg = { 0 };
+
+	reg.a0 = LFA_1_0_FN_CANCEL;
+	reg.a1 = attrs->fw_seq_id;
+	arm_smccc_1_2_invoke(&reg, &reg);
+
+	/*
+	 * When firmware activation is called with "skip_cpu_rendezvous=1",
+	 * LFA_CANCEL can fail with LFA_BUSY if the activation could not be
+	 * cancelled.
+	 */
+	if (reg.a0 == LFA_SUCCESS) {
+		pr_info("Activation cancelled for image %s\n",
+			attrs->image_name);
+	} else {
+		pr_err("Firmware activation could not be cancelled: %s\n",
+		       lfa_error_strings[-reg.a0]);
+		return -EINVAL;
+	}
+
+	return reg.a0;
+}
+
 static int call_lfa_activate(void *data)
 {
 	struct image_props *attrs = data;
@@ -160,6 +185,11 @@ static int activate_fw_image(struct image_props *attrs)
 	struct arm_smccc_1_2_regs res = { 0 };
 	int ret;
 
+	if (attrs->may_reset_cpu) {
+		pr_err("CPU reset not supported by kernel driver\n");
+		return -EINVAL;
+	}
+
 	/*
 	 * LFA_PRIME/ACTIVATE will return 1 in res.a1 if the firmware
 	 * priming/activation is still in progress. In that case
@@ -284,12 +314,6 @@ static ssize_t activate_store(struct kobject *kobj, struct kobj_attribute *attr,
 					 image_attrs[LFA_ATTR_ACTIVATE]);
 	int ret;
 
-	if (attrs->may_reset_cpu) {
-		pr_err("Firmware component requires unsupported CPU reset\n");
-
-		return -EINVAL;
-	}
-
 	ret = activate_fw_image(attrs);
 	if (ret) {
 		pr_err("Firmware activation failed: %s\n",
@@ -309,25 +333,11 @@ static ssize_t cancel_store(struct kobject *kobj, struct kobj_attribute *attr,
 {
 	struct image_props *attrs = container_of(attr, struct image_props,
 						 image_attrs[LFA_ATTR_CANCEL]);
-	struct arm_smccc_1_2_regs reg = { 0 };
-
-	reg.a0 = LFA_1_0_FN_CANCEL;
-	reg.a1 = attrs->fw_seq_id;
-	arm_smccc_1_2_invoke(&reg, &reg);
+	int ret;
 
-	/*
-	 * When firmware activation is called with "skip_cpu_rendezvous=1",
-	 * LFA_CANCEL can fail with LFA_BUSY if the activation could not be
-	 * cancelled.
-	 */
-	if (reg.a0 == LFA_SUCCESS) {
-		pr_info("Activation cancelled for image %s\n",
-			attrs->image_name);
-	} else {
-		pr_err("Firmware activation could not be cancelled: %s\n",
-		       lfa_error_strings[-reg.a0]);
-		return -EINVAL;
-	}
+	ret = lfa_cancel(attrs);
+	if (ret != 0)
+		return ret;
 
 	return count;
 }
@@ -367,6 +377,8 @@ static int create_fw_inventory(char *fw_uuid, int seq_id, u32 image_flags)
 	for (int i = 0; i < ARRAY_SIZE(fw_images_uuids); i++) {
 		if (!strcmp(fw_images_uuids[i].uuid, fw_uuid))
 			image_name = fw_images_uuids[i].name;
+		else
+			image_name = fw_uuid;
 	}
 
 	attrs->image_dir = kobject_create_and_add(fw_uuid, lfa_dir);
@@ -414,6 +426,10 @@ static int create_fw_images_tree(void)
 	int ret, num_of_components;
 
 	num_of_components = get_nr_lfa_components();
+	if (num_of_components <= 0) {
+		pr_err("Error getting number of LFA components");
+		return -ENODEV;
+	}
 
 	for (int i = 0; i < num_of_components; i++) {
 		reg.a0 = LFA_1_0_FN_GET_INVENTORY;
-- 
2.43.0



From vvidwans at nvidia.com  Mon Dec  8 14:13:14 2025
From: vvidwans at nvidia.com (Vedashree Vidwans)
Date: Mon, 8 Dec 2025 22:13:14 +0000
Subject: [RFC PATCH 4/5] firmware: smccc: register as platform driver
In-Reply-To: <20251208221319.1524888-1-vvidwans@nvidia.com>
References: <20251208221319.1524888-1-vvidwans@nvidia.com>
Message-ID: <20251208221319.1524888-5-vvidwans@nvidia.com>

- Update driver to be in-built kernel module. This will ensure driver is
installed in kernel and would not require any user intervention.
- Register the LFA driver as a platform driver corresponding to
'armhf000' device. The driver will be invoked when the device is
detected on a platform.
- Add functionality to register LFA interrupt in the driver probe().
This LFA IRQ number will be retrived from the LFA device node.
- On IRQ, driver will query FW component details and trigger activation
of capable and pending FW component. The driver will loop to update FW
component details after every successful FW component activation.
- Mutex synchronization is implemented to avoid concurrent LFA updates
through interrupt and sysfs interfaces.

Device node snippet from LFA spec[1]:
fwu0 {
    compatible = "arm,armhf000";
    memory-region = <&fwu_payload>;
    interrupt-parent = <&ic>;
    interrupts = <0 100 1>; // SPI, Interrupt #100, Edge Rising
};

[1] https://developer.arm.com/documentation/den0147/latest/

Signed-off-by: Vedashree Vidwans <vvidwans at nvidia.com>
---
 drivers/firmware/smccc/Kconfig  |   3 +-
 drivers/firmware/smccc/lfa_fw.c | 124 +++++++++++++++++++++++++++++++-
 2 files changed, 125 insertions(+), 2 deletions(-)

diff --git a/drivers/firmware/smccc/Kconfig b/drivers/firmware/smccc/Kconfig
index 48b98c14f770..c21be43fbfed 100644
--- a/drivers/firmware/smccc/Kconfig
+++ b/drivers/firmware/smccc/Kconfig
@@ -25,8 +25,9 @@ config ARM_SMCCC_SOC_ID
 	  platforms providing some sysfs information about the SoC variant.
 
 config ARM_LFA
-	tristate "Arm Live Firmware activation support"
+	bool "Arm Live Firmware activation support"
 	depends on HAVE_ARM_SMCCC_DISCOVERY
+	default y
 	help
 	  Include support for triggering Live Firmware Activation, which
 	  allows to upgrade certain firmware components without a reboot.
diff --git a/drivers/firmware/smccc/lfa_fw.c b/drivers/firmware/smccc/lfa_fw.c
index 0e420cefa260..24916fc53420 100644
--- a/drivers/firmware/smccc/lfa_fw.c
+++ b/drivers/firmware/smccc/lfa_fw.c
@@ -19,7 +19,12 @@
 #include <linux/nmi.h>
 #include <linux/ktime.h>
 #include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/acpi.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
 
+#define DRIVER_NAME	"ARM_LFA"
 #define LFA_ERROR_STRING(name) \
 	[name] = #name
 #undef pr_fmt
@@ -129,6 +134,7 @@ static const struct fw_image_uuid {
 };
 
 static struct kobject *lfa_dir;
+static DEFINE_MUTEX(lfa_lock);
 
 static int get_nr_lfa_components(void)
 {
@@ -374,17 +380,23 @@ static ssize_t activate_store(struct kobject *kobj, struct kobj_attribute *attr,
 					 image_attrs[LFA_ATTR_ACTIVATE]);
 	int ret;
 
+	if (!mutex_trylock(&lfa_lock)) {
+		pr_err("Mutex locked, try again");
+		return -EAGAIN;
+	}
+
 	ret = activate_fw_image(attrs);
 	if (ret) {
 		pr_err("Firmware activation failed: %s\n",
 			lfa_error_strings[-ret]);
-
+		mutex_unlock(&lfa_lock);
 		return -ECANCELED;
 	}
 
 	pr_info("Firmware activation succeeded\n");
 
 	/* TODO: refresh image flags here*/
+	mutex_unlock(&lfa_lock);
 	return count;
 }
 
@@ -510,6 +522,106 @@ static int create_fw_images_tree(void)
 	return 0;
 }
 
+static irqreturn_t lfa_irq_thread(int irq, void *data)
+{
+	struct image_props *attrs = NULL;
+	int ret;
+	int num_of_components, curr_component;
+
+	mutex_lock(&lfa_lock);
+
+	/*
+	 * As per LFA spec, after activation of a component, the caller
+	 * is expected to re-enumerate the component states (using
+	 * LFA_GET_INFO then LFA_GET_INVENTORY).
+	 * Hence we need an unconditional loop.
+	 */
+
+	do {
+		/* TODO: refresh image flags here */
+		/* If refresh fails goto exit_unlock */
+
+		/* Initialize counters to track list traversal  */
+		num_of_components = get_nr_lfa_components();
+		curr_component = 0;
+
+		/* Execute PRIME and ACTIVATE for activable FW component */
+		list_for_each_entry(attrs, &lfa_fw_images, image_node) {
+			curr_component++;
+			if ((!attrs->activation_capable) || (!attrs->activation_pending)) {
+				/* LFA not applicable for this FW component */
+				continue;
+			}
+
+			ret = activate_fw_image(attrs);
+			if (ret) {
+				pr_err("Firmware %s activation failed: %s\n",
+					attrs->image_name, lfa_error_strings[-ret]);
+				goto exit_unlock;
+			}
+
+			pr_info("Firmware %s activation succeeded", attrs->image_name);
+			/* Refresh FW component details */
+			break;
+		}
+	} while (curr_component < num_of_components);
+
+	/* TODO: refresh image flags here */
+	/* If refresh fails goto exit_unlock */
+
+exit_unlock:
+	mutex_unlock(&lfa_lock);
+	return IRQ_HANDLED;
+}
+
+static int __init lfa_probe(struct platform_device *pdev)
+{
+	int err;
+	unsigned int irq;
+
+	err = platform_get_irq_byname_optional(pdev, "fw-store-updated-interrupt");
+	if (err < 0)
+		err = platform_get_irq(pdev, 0);
+	if (err < 0) {
+		pr_err("Interrupt not found, functionality will be unavailable.");
+
+		/* Bail out without failing the driver. */
+		return 0;
+	}
+	irq = err;
+
+	err = request_threaded_irq(irq, NULL, lfa_irq_thread, IRQF_ONESHOT, DRIVER_NAME, NULL);
+	if (err != 0) {
+		pr_err("Interrupt setup failed, functionality will be unavailable.");
+
+		/* Bail out without failing the driver. */
+		return 0;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id lfa_of_ids[] = {
+	{ .compatible = "arm,armhf000", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, lfa_of_ids);
+
+static const struct acpi_device_id lfa_acpi_ids[] = {
+	{"ARMHF000"},
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, lfa_acpi_ids);
+
+static struct platform_driver lfa_driver = {
+	.probe = lfa_probe,
+	.driver = {
+		.name = DRIVER_NAME,
+		.of_match_table = lfa_of_ids,
+		.acpi_match_table = ACPI_PTR(lfa_acpi_ids),
+	},
+};
+
 static int __init lfa_init(void)
 {
 	struct arm_smccc_1_2_regs reg = { 0 };
@@ -536,22 +648,32 @@ static int __init lfa_init(void)
 	pr_info("Arm Live Firmware Activation (LFA): detected v%ld.%ld\n",
 		reg.a0 >> 16, reg.a0 & 0xffff);
 
+	err = platform_driver_register(&lfa_driver);
+	if (err < 0)
+		pr_err("Platform driver register failed");
+
 	lfa_dir = kobject_create_and_add("lfa", firmware_kobj);
 	if (!lfa_dir)
 		return -ENOMEM;
 
+	mutex_lock(&lfa_lock);
 	err = create_fw_images_tree();
 	if (err != 0)
 		kobject_put(lfa_dir);
 
+	mutex_unlock(&lfa_lock);
 	return err;
 }
 module_init(lfa_init);
 
 static void __exit lfa_exit(void)
 {
+	mutex_lock(&lfa_lock);
 	clean_fw_images_tree();
+	mutex_unlock(&lfa_lock);
+
 	kobject_put(lfa_dir);
+	platform_driver_unregister(&lfa_driver);
 }
 module_exit(lfa_exit);
 
-- 
2.43.0



From vvidwans at nvidia.com  Mon Dec  8 14:13:15 2025
From: vvidwans at nvidia.com (Vedashree Vidwans)
Date: Mon, 8 Dec 2025 22:13:15 +0000
Subject: [RFC PATCH 5/5] firmware: smccc: lfa: refresh fw details
In-Reply-To: <20251208221319.1524888-1-vvidwans@nvidia.com>
References: <20251208221319.1524888-1-vvidwans@nvidia.com>
Message-ID: <20251208221319.1524888-6-vvidwans@nvidia.com>

FW image details are querried with a SMC call. Currently, these FW
details are added as nodes in a linked list. This patch updates the
FW node creation and update functions. Now the linked list is updated
based on the current value of num_lfa_components.
As per spec [1], FW inventory is updated after each activation.

[1] https://developer.arm.com/documentation/den0147/latest/

Signed-off-by: Vedashree Vidwans <vvidwans at nvidia.com>
---
 drivers/firmware/smccc/lfa_fw.c | 148 +++++++++++++++++++++-----------
 1 file changed, 100 insertions(+), 48 deletions(-)

diff --git a/drivers/firmware/smccc/lfa_fw.c b/drivers/firmware/smccc/lfa_fw.c
index 24916fc53420..334090708405 100644
--- a/drivers/firmware/smccc/lfa_fw.c
+++ b/drivers/firmware/smccc/lfa_fw.c
@@ -133,6 +133,7 @@ static const struct fw_image_uuid {
 	},
 };
 
+static int update_fw_images_tree(void);
 static struct kobject *lfa_dir;
 static DEFINE_MUTEX(lfa_lock);
 
@@ -282,17 +283,6 @@ static int activate_fw_image(struct image_props *attrs)
 	return ret;
 }
 
-static void set_image_flags(struct image_props *attrs, int seq_id,
-			    u32 image_flags)
-{
-	attrs->fw_seq_id = seq_id;
-	attrs->activation_capable = !!(image_flags & BIT(0));
-	attrs->activation_pending = !!(image_flags & BIT(1));
-	attrs->may_reset_cpu = !!(image_flags & BIT(2));
-	/* cpu_rendezvous_optional bit has inverse logic in the spec */
-	attrs->cpu_rendezvous = !(image_flags & BIT(3));
-}
-
 static ssize_t name_show(struct kobject *kobj, struct kobj_attribute *attr,
 			 char *buf)
 {
@@ -395,7 +385,9 @@ static ssize_t activate_store(struct kobject *kobj, struct kobj_attribute *attr,
 
 	pr_info("Firmware activation succeeded\n");
 
-	/* TODO: refresh image flags here*/
+	ret = update_fw_images_tree();
+	if (ret)
+		pr_err("Failed to update FW images tree");
 	mutex_unlock(&lfa_lock);
 	return count;
 }
@@ -425,20 +417,41 @@ static struct kobj_attribute image_attrs_group[LFA_ATTR_NR_IMAGES] = {
 	[LFA_ATTR_CANCEL]		= __ATTR_WO(cancel)
 };
 
+static void delete_fw_image_node(struct image_props *attrs)
+{
+	int i;
+
+	for (i = 0; i < LFA_ATTR_NR_IMAGES; i++)
+		sysfs_remove_file(attrs->image_dir, &attrs->image_attrs[i].attr);
+
+	kobject_put(attrs->image_dir);
+	attrs->image_dir = NULL;
+	list_del(&attrs->image_node);
+	kfree(attrs);
+}
+
 static void clean_fw_images_tree(void)
 {
 	struct image_props *attrs, *tmp;
 
-	list_for_each_entry_safe(attrs, tmp, &lfa_fw_images, image_node) {
-		kobject_put(attrs->image_dir);
-		list_del(&attrs->image_node);
-		kfree(attrs);
-	}
+	list_for_each_entry_safe(attrs, tmp, &lfa_fw_images, image_node)
+		delete_fw_image_node(attrs);
+}
+
+static void update_fw_image_node(struct image_props *attrs, int seq_id,
+			    char *fw_uuid, u32 image_flags)
+{
+	attrs->fw_seq_id = seq_id;
+	attrs->image_name = fw_uuid;
+	attrs->activation_capable = !!(image_flags & BIT(0));
+	attrs->activation_pending = !!(image_flags & BIT(1));
+	attrs->may_reset_cpu = !!(image_flags & BIT(2));
+	/* cpu_rendezvous_optional bit has inverse logic in the spec */
+	attrs->cpu_rendezvous = !(image_flags & BIT(3));
 }
 
-static int create_fw_inventory(char *fw_uuid, int seq_id, u32 image_flags)
+static int create_fw_image_node(int seq_id, char *fw_uuid, u32 image_flags)
 {
-	const char *image_name = "(unknown)";
 	struct image_props *attrs;
 	int ret;
 
@@ -446,21 +459,12 @@ static int create_fw_inventory(char *fw_uuid, int seq_id, u32 image_flags)
 	if (!attrs)
 		return -ENOMEM;
 
-	for (int i = 0; i < ARRAY_SIZE(fw_images_uuids); i++) {
-		if (!strcmp(fw_images_uuids[i].uuid, fw_uuid))
-			image_name = fw_images_uuids[i].name;
-		else
-			image_name = fw_uuid;
-	}
-
 	attrs->image_dir = kobject_create_and_add(fw_uuid, lfa_dir);
 	if (!attrs->image_dir)
 		return -ENOMEM;
 
-	INIT_LIST_HEAD(&attrs->image_node);
-	attrs->image_name = image_name;
-	attrs->cpu_rendezvous_forced = 1;
-	set_image_flags(attrs, seq_id, image_flags);
+	/* Update FW attributes */
+	update_fw_image_node(attrs, seq_id, fw_uuid, image_flags);
 
 	/*
 	 * The attributes for each sysfs file are constant (handler functions,
@@ -485,17 +489,19 @@ static int create_fw_inventory(char *fw_uuid, int seq_id, u32 image_flags)
 			return ret;
 		}
 	}
-	list_add(&attrs->image_node, &lfa_fw_images);
+	list_add_tail(&attrs->image_node, &lfa_fw_images);
 
 	return ret;
 }
 
-static int create_fw_images_tree(void)
+static int update_fw_images_tree(void)
 {
 	struct arm_smccc_1_2_regs reg = { 0 };
 	struct uuid_regs image_uuid;
+	struct image_props *attrs, *tmp;
 	char image_id_str[40];
 	int ret, num_of_components;
+	int node_idx = 0;
 
 	num_of_components = get_nr_lfa_components();
 	if (num_of_components <= 0) {
@@ -503,22 +509,67 @@ static int create_fw_images_tree(void)
 		return -ENODEV;
 	}
 
-	for (int i = 0; i < num_of_components; i++) {
-		reg.a0 = LFA_1_0_FN_GET_INVENTORY;
-		reg.a1 = i; /* fw_seq_id under consideration */
-		arm_smccc_1_2_invoke(&reg, &reg);
-		if (reg.a0 == LFA_SUCCESS) {
+	/*
+	 * Pass 1:
+	 *    For nodes < num_of_components, update fw_image_node
+	 *    For nodes >= num_of_components, delete
+	 */
+	list_for_each_entry_safe(attrs, tmp, &lfa_fw_images, image_node) {
+		if (attrs->fw_seq_id < num_of_components) {
+			/* Update this FW image node */
+
+			/* Get FW details */
+			reg.a0 = LFA_1_0_FN_GET_INVENTORY;
+			reg.a1 = attrs->fw_seq_id;
+			arm_smccc_1_2_invoke(&reg, &reg);
+
+			if (reg.a0 != LFA_SUCCESS)
+				return -EINVAL;
+
+			/* Build image name with UUID */
 			image_uuid.uuid_lo = reg.a1;
 			image_uuid.uuid_hi = reg.a2;
+			snprintf(image_id_str, sizeof(image_id_str), "%pUb", &image_uuid);
 
-			snprintf(image_id_str, sizeof(image_id_str), "%pUb",
-				 &image_uuid);
-			ret = create_fw_inventory(image_id_str, i, reg.a3);
-			if (ret)
-				return ret;
+			if (strcmp(attrs->image_name, image_id_str)) {
+				/* UUID doesn't match previous UUID for given FW, not expected */
+				pr_err("FW seq id %u: Previous UUID %s doesn't match current %s",
+					attrs->fw_seq_id, attrs->image_name, image_id_str);
+				return -EINVAL;
+			}
+
+			/* Update FW attributes */
+			update_fw_image_node(attrs, attrs->fw_seq_id, image_id_str, reg.a3);
+			node_idx++;
+		} else {
+			/* This node is beyond valid FW components list */
+			delete_fw_image_node(attrs);
 		}
 	}
 
+	/*
+	 * Pass 2:
+	 *    If current FW components number is more than previous list, add new component nodes.
+	 */
+	for (node_idx; node_idx < num_of_components; node_idx++) {
+		/* Get FW details */
+		reg.a0 = LFA_1_0_FN_GET_INVENTORY;
+		reg.a1 = node_idx;
+		arm_smccc_1_2_invoke(&reg, &reg);
+
+		if (reg.a0 != LFA_SUCCESS)
+			return -EINVAL;
+
+		/* Build image name with UUID */
+		image_uuid.uuid_lo = reg.a1;
+		image_uuid.uuid_hi = reg.a2;
+		snprintf(image_id_str, sizeof(image_id_str), "%pUb", &image_uuid);
+
+		ret = create_fw_image_node(node_idx, image_id_str, reg.a3);
+		if (ret)
+			return ret;
+	}
+
 	return 0;
 }
 
@@ -538,8 +589,9 @@ static irqreturn_t lfa_irq_thread(int irq, void *data)
 	 */
 
 	do {
-		/* TODO: refresh image flags here */
-		/* If refresh fails goto exit_unlock */
+		ret = update_fw_images_tree();
+		if (ret)
+			goto exit_unlock;
 
 		/* Initialize counters to track list traversal  */
 		num_of_components = get_nr_lfa_components();
@@ -561,13 +613,13 @@ static irqreturn_t lfa_irq_thread(int irq, void *data)
 			}
 
 			pr_info("Firmware %s activation succeeded", attrs->image_name);
-			/* Refresh FW component details */
 			break;
 		}
 	} while (curr_component < num_of_components);
 
-	/* TODO: refresh image flags here */
-	/* If refresh fails goto exit_unlock */
+	ret = update_fw_images_tree();
+	if (ret)
+		goto exit_unlock;
 
 exit_unlock:
 	mutex_unlock(&lfa_lock);
@@ -657,7 +709,7 @@ static int __init lfa_init(void)
 		return -ENOMEM;
 
 	mutex_lock(&lfa_lock);
-	err = create_fw_images_tree();
+	err = update_fw_images_tree();
 	if (err != 0)
 		kobject_put(lfa_dir);
 
-- 
2.43.0



From dmitry.baryshkov at oss.qualcomm.com  Mon Dec  8 14:58:51 2025
From: dmitry.baryshkov at oss.qualcomm.com (Dmitry Baryshkov)
Date: Tue, 9 Dec 2025 00:58:51 +0200
Subject: [PATCH V4] iommu/arm-smmu: add actlr settings for mdss on
 Qualcomm platforms
In-Reply-To: <0bcd5a92-5213-4862-9a31-8ea539b1b72c@oss.qualcomm.com>
References: <20251202125447.2102658-1-charan.kalla@oss.qualcomm.com>
 <gsjyj3arwoqcjln6nlmyhohlowyvkwqmxppdq5y7c3m4khoyq3@npzixjpibh5g> <0bcd5a92-5213-4862-9a31-8ea539b1b72c@oss.qualcomm.com>
Message-ID: <CAO9ioeW0fafwRnxvDJ7yHGcQYbgfkfRF1BMTpXpG=8tSKRptdw@mail.gmail.com>

On Mon, 8 Dec 2025 at 21:28, Bibek Kumar Patro
<bibek.patro at oss.qualcomm.com> wrote:
>
>
>
> On 12/6/2025 2:36 AM, Bjorn Andersson wrote:
> > On Tue, Dec 02, 2025 at 06:24:47PM +0530, Charan Teja Kalla wrote:
> >
> > Based on the other changes to this file, the subject prefix should be
> > "iommu/arm-smmu-qcom:"
> >
>
> Sure Bjorn, I will address this in v4 RESEND and collect all reviewed-by
> tags.
> Let me know if you feel this change needs a revision update to v5
> instead of v4-RESEND.

RESEND means that there were no changes to the patches. If you've
changed anything, it is a next iteration.

>
> Thanks & regards,
> Bibek
>
> > Regards,
> > Bjorn
> >
> >> Add ACTLR settings for missing MDSS devices on Qualcomm platforms.
> >>
> >> These are QoS settings and are specific to per SoC thus different
> >> settings, eg: some have shallow prefetch while others have no
> >> prefetch.
> >>
> >> Aswell, this prefetch feature is not implemented for all the
> >> platforms, capturing to those are implemented to the best of my
> >> knowledge.
> >>
> >> Signed-off-by: Charan Teja Kalla <charan.kalla at oss.qualcomm.com>
> >> ---
> >> Changes from V3:
> >>   1) Add actlr setting for missing sc8180x & sm6115.
> >>   2) Improved commit message.
> >> https://lore.kernel.org/all/20251124171030.323989-1-charan.kalla at oss.qualcomm.com/
> >>
> >> Changes from V2:
> >>   1) Add actlr settings for all the mdss devices on Qualcomm platforms.
> >>   2) Improved the commit message that explain why different ACTLR
> >>      settings
> >> https://lore.kernel.org/lkml/20251118171822.3539062-1-charan.kalla at oss.qualcomm.com/#t
> >>
> >> Changes from V1:
> >>    1) Added actlr setting only for MDSS and dropped for fastrpc. --
> >> konrad
> >>    2) ACTLR table is updated per alphanumeric order -- konrad
> >>    https://lore.kernel.org/all/20251105075307.1658329-1-charan.kalla at oss.qualcomm.com/
> >>
> >>   drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 26 ++++++++++++++++++++++
> >>   1 file changed, 26 insertions(+)
> >>
> >> diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
> >> index c21a401c71eb..149da53091de 100644
> >> --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
> >> +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
> >> @@ -41,12 +41,38 @@ static const struct of_device_id qcom_smmu_actlr_client_of_match[] = {
> >>                      .data = (const void *) (PREFETCH_DEEP | CPRE | CMTLB) },
> >>      { .compatible = "qcom,fastrpc",
> >>                      .data = (const void *) (PREFETCH_DEEP | CPRE | CMTLB) },
> >> +    { .compatible = "qcom,qcm2290-mdss",
> >> +                    .data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
> >>      { .compatible = "qcom,sc7280-mdss",
> >>                      .data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
> >>      { .compatible = "qcom,sc7280-venus",
> >>                      .data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
> >> +    { .compatible = "qcom,sc8180x-mdss",
> >> +                    .data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
> >> +    { .compatible = "qcom,sc8280xp-mdss",
> >> +                    .data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
> >> +    { .compatible = "qcom,sm6115-mdss",
> >> +                    .data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
> >> +    { .compatible = "qcom,sm6125-mdss",
> >> +                    .data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
> >> +    { .compatible = "qcom,sm6350-mdss",
> >> +                    .data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
> >> +    { .compatible = "qcom,sm8150-mdss",
> >> +                    .data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
> >> +    { .compatible = "qcom,sm8250-mdss",
> >> +                    .data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
> >> +    { .compatible = "qcom,sm8350-mdss",
> >> +                    .data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
> >> +    { .compatible = "qcom,sm8450-mdss",
> >> +                    .data = (const void *) (PREFETCH_DEFAULT | CMTLB) },
> >>      { .compatible = "qcom,sm8550-mdss",
> >>                      .data = (const void *) (PREFETCH_DEFAULT | CMTLB) },
> >> +    { .compatible = "qcom,sm8650-mdss",
> >> +                    .data = (const void *) (PREFETCH_DEFAULT | CMTLB) },
> >> +    { .compatible = "qcom,sm8750-mdss",
> >> +                    .data = (const void *) (PREFETCH_DEFAULT | CMTLB) },
> >> +    { .compatible = "qcom,x1e80100-mdss",
> >> +                    .data = (const void *) (PREFETCH_DEFAULT | CMTLB) },
> >>      { }
> >>   };
> >>
> >> --
> >> 2.34.1
> >>
> >>
>


-- 
With best wishes
Dmitry


From ebiggers at kernel.org  Mon Dec  8 15:24:22 2025
From: ebiggers at kernel.org (Eric Biggers)
Date: Mon, 8 Dec 2025 15:24:22 -0800
Subject: [PATCH] arm64/simd: Avoid pointless clearing of FP/SIMD buffer
In-Reply-To: <CAMj1kXEWYQYW92=yRG6sJmmrjc8MBz-fdauxX2pq+P2rKhcxmg@mail.gmail.com>
References: <20251204162815.522879-2-ardb@kernel.org>
 <20251205064809.GA26371@sol>
 <CAMj1kXE8qn7MSY1A31CrHRSxw+NXqNGLo=FLo4D-COMhxPAMiw@mail.gmail.com>
 <20251207013004.GA143349@sol>
 <CAMj1kXEWYQYW92=yRG6sJmmrjc8MBz-fdauxX2pq+P2rKhcxmg@mail.gmail.com>
Message-ID: <20251208232422.GD1853@quark>

On Sun, Dec 07, 2025 at 10:59:29AM +0100, Ard Biesheuvel wrote:
> On Sun, 7 Dec 2025 at 02:30, Eric Biggers <ebiggers at kernel.org> wrote:
> >
> > On Fri, Dec 05, 2025 at 09:13:46AM +0100, Ard Biesheuvel wrote:
> > > On Fri, 5 Dec 2025 at 07:50, Eric Biggers <ebiggers at kernel.org> wrote:
> > > >
> > > > On Thu, Dec 04, 2025 at 05:28:15PM +0100, Ard Biesheuvel wrote:
> > > > > The buffer provided to kernel_neon_begin() is only used if the task is
> > > > > scheduled out while the FP/SIMD is in use by the kernel, or when such a
> > > > > section is interrupted by a softirq that also uses the FP/SIMD.
> > > > >
> > > > > IOW, this happens rarely, and even if it happened often, there is still
> > > > > no reason for this buffer to be cleared beforehand, which happens by
> > > > > default when using a compiler that supports -ftrivial-auto-var-init.
> > > > >
> > > > > So mark the buffer as __uninitialized. Given that this is a variable
> > > > > attribute not a type attribute, this requires that the expression is
> > > > > tweaked a bit.
> > > > >
> > > > > Cc: Will Deacon <will at kernel.org>,
> > > > > Cc: Catalin Marinas <catalin.marinas at arm.com>,
> > > > > Cc: Kees Cook <keescook at chromium.org>
> > > > > Cc: Eric Biggers <ebiggers at kernel.org>
> > > > > Cc: Justin Stitt <justinstitt at google.com>
> > > > > Signed-off-by: Ard Biesheuvel <ardb at kernel.org>
> > > > > ---
> > > > >  arch/arm64/include/asm/simd.h | 3 ++-
> > > > >  1 file changed, 2 insertions(+), 1 deletion(-)
> > > > >
> > > > > The issue here is that returning a pointer to an automatic variable as
> > > > > it goes out of scope is slightly dodgy, especially in the context of
> > > > > __attribute__((cleanup())), on which the scoped guard API relies
> > > > > heavily. However, in this case it should be safe, given that this
> > > > > expression is the input to the guarded variable type's constructor.
> > > > >
> > > > > It is definitely not pretty, though, so hopefully here is a better way
> > > > > to attach this.
> > > > >
> > > > > diff --git a/arch/arm64/include/asm/simd.h b/arch/arm64/include/asm/simd.h
> > > > > index 0941f6f58a14..825b7fe94003 100644
> > > > > --- a/arch/arm64/include/asm/simd.h
> > > > > +++ b/arch/arm64/include/asm/simd.h
> > > > > @@ -48,6 +48,7 @@ DEFINE_LOCK_GUARD_1(ksimd,
> > > > >                   kernel_neon_begin(_T->lock),
> > > > >                   kernel_neon_end(_T->lock))
> > > > >
> > > > > -#define scoped_ksimd()       scoped_guard(ksimd, &(struct user_fpsimd_state){})
> > > > > +#define scoped_ksimd()       \
> > > > > +     scoped_guard(ksimd, ({ struct user_fpsimd_state __uninitialized s; &s; }))
> > > >
> > > > Ick.  I should have looked at the generated code more closely.
> > > >
> > > > It's actually worse than you describe, because the zeroing is there even
> > > > without CONFIG_INIT_STACK_ALL_ZERO=y, simply because the
> > > > user_fpsimd_state struct is declared using a compound literal.
> > > >
> > > > I'm afraid that this patch probably isn't a good idea, as it relies on
> > > > undefined behavior.  Before this patch, the user_fpsimd_state is
> > > > declared using a compound literal, which takes on its enclosing scope,
> > > > i.e. the 'for' statement generated by scoped_guard().  After this patch,
> > > > it's in a new inner scope, and the pointer to it escapes from it.
> > > >
> > > > Unfortunately I don't think there's any way to solve this while keeping
> > > > the scoped_ksimd() API as-is.
> > > >
> > >
> > > How about
> > >
> > > --- a/arch/arm64/include/asm/simd.h
> > > +++ b/arch/arm64/include/asm/simd.h
> > > @@ -48,6 +48,8 @@ DEFINE_LOCK_GUARD_1(ksimd,
> > >                     kernel_neon_begin(_T->lock),
> > >                     kernel_neon_end(_T->lock))
> > >
> > > -#define scoped_ksimd() scoped_guard(ksimd, &(struct user_fpsimd_state){})
> > > +#define scoped_ksimd()         __scoped_ksimd(__UNIQUE_ID(fpsimd_state))
> > > +#define __scoped_ksimd(id)     struct user_fpsimd_state __uninitialized id; \
> > > +                               scoped_guard(ksimd, &id)
> >
> > I guess that will work.  It's not great that it will make scoped_ksimd()
> > expand into more than one statement, which is error-prone and not
> > normally allowed in macros.  But it looks okay for all the current users
> > of it.
> >
> 
> We could always repeat the 'for()' trick that the cleanup helpers use, e.g.,
> 
> for (struct user_fpsimd_state __uninitialized __st; true; ({ goto label; }))
>     if (0) {
> label:    break;
>     } else scoped_guard(ksimd, &__st)
> 
> Would you prefer that?

Hmm, I didn't consider using nested 'for' statements.  It looks like
that should solve the problem.  It makes the implementation a bit harder
to understand, but at least the 'for' statement trick isn't new...
Could you send a patch?  Preferably with a clear comment that documents
why it's done this way.

- Eric


From shenwei.wang at nxp.com  Mon Dec  8 15:33:02 2025
From: shenwei.wang at nxp.com (Shenwei Wang)
Date: Mon,  8 Dec 2025 17:33:02 -0600
Subject: [PATCH] remoteproc: imx_rproc: Use strstarts for "rsc-table" check
Message-ID: <20251208233302.684139-1-shenwei.wang@nxp.com>

The resource name may include an address suffix, for example:
rsc-table at 1fff8000.

To handle such cases, use strstarts() instead of strcmp() when checking
for "rsc-table".

Signed-off-by: Shenwei Wang <shenwei.wang at nxp.com>
---
 drivers/remoteproc/imx_rproc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index 3be8790c14a2..33f21ab24c92 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -694,7 +694,7 @@ static int imx_rproc_addr_init(struct imx_rproc *priv,
 		}
 		priv->mem[b].sys_addr = res.start;
 		priv->mem[b].size = resource_size(&res);
-		if (!strcmp(res.name, "rsc-table"))
+		if (strstarts(res.name, "rsc-table"))
 			priv->rsc_table = priv->mem[b].cpu_addr;
 		b++;
 	}
-- 
2.43.0



From helgaas at kernel.org  Mon Dec  8 16:11:07 2025
From: helgaas at kernel.org (Bjorn Helgaas)
Date: Mon, 8 Dec 2025 18:11:07 -0600
Subject: [PATCH v6 6/7] PCI: aspeed: Add ASPEED PCIe RC driver
In-Reply-To: <20251201-upstream_pcie_rc-v6-6-8c8800c56b16@aspeedtech.com>
Message-ID: <20251209001107.GA3430423@bhelgaas>

On Mon, Dec 01, 2025 at 02:29:16PM +0800, Jacky Chou wrote:
> Introduce PCIe Root Complex driver for ASPEED SoCs. Support RC
> initialization, reset, clock, IRQ domain, and MSI domain setup.
> Implement platform-specific setup and register configuration for
> ASPEED. And provide PCI config space read/write and INTx/MSI
> interrupt handling.
> ...

> +struct aspeed_pcie {
> +	struct pci_host_bridge *host;
> +	struct device *dev;
> +	void __iomem *reg;
> +	struct regmap *ahbc;
> +	struct regmap *cfg;
> +	const struct aspeed_pcie_rc_platform *platform;
> +	struct list_head ports;
> +
> +	u8 tx_tag;
> +	int host_bus_num;

Only needs a u8.

> +static int aspeed_pcie_port_init(struct aspeed_pcie_port *port)
> +{
> +	struct aspeed_pcie *pcie = port->pcie;
> +	struct device *dev = pcie->dev;
> +	int ret;
> +
> +	ret = clk_prepare_enable(port->clk);
> +	if (ret)
> +		return dev_err_probe(dev, ret,
> +				     "failed to set clock for slot (%d)\n",
> +				     port->slot);
> +
> +	ret = phy_init(port->phy);
> +	if (ret)
> +		return dev_err_probe(dev, ret,
> +				     "failed to init phy pcie for slot (%d)\n",
> +				     port->slot);
> +
> +	ret = phy_set_mode_ext(port->phy, PHY_MODE_PCIE, PHY_MODE_PCIE_RC);
> +	if (ret)
> +		return dev_err_probe(dev, ret,
> +				     "failed to set phy mode for slot (%d)\n",
> +				     port->slot);
> +
> +	reset_control_deassert(port->perst);
> +	mdelay(PCIE_RESET_CONFIG_WAIT_MS);

I think this should use msleep().

> +static int aspeed_ast2600_setup(struct platform_device *pdev)
> +{
> +	struct aspeed_pcie *pcie = platform_get_drvdata(pdev);
> +	struct device *dev = pcie->dev;
> +
> +	pcie->ahbc = syscon_regmap_lookup_by_phandle(dev->of_node,
> +						     "aspeed,ahbc");
> +	if (IS_ERR(pcie->ahbc))
> +		return dev_err_probe(dev, PTR_ERR(pcie->ahbc),
> +				     "failed to map ahbc base\n");
> +
> +	aspeed_host_reset(pcie);
> +
> +	regmap_write(pcie->ahbc, ASPEED_AHBC_KEY, ASPEED_AHBC_UNLOCK_KEY);
> +	regmap_update_bits(pcie->ahbc, ASPEED_AHBC_ADDR_MAPPING,
> +			   ASPEED_PCIE_RC_MEMORY_EN, ASPEED_PCIE_RC_MEMORY_EN);
> +	regmap_write(pcie->ahbc, ASPEED_AHBC_KEY, ASPEED_AHBC_UNLOCK);
> +
> +	/* Due to the BAR assignment is fixed mapping on 0x6000_0000.*/
> +	writel(ASPEED_AHB_REMAP_LO_ADDR(0x600) | ASPEED_AHB_MASK_LO_ADDR(0xe00),
> +	       pcie->reg + ASPEED_H2X_AHB_ADDR_CONFIG0);
> +	writel(ASPEED_AHB_REMAP_HI_ADDR(0),
> +	       pcie->reg + ASPEED_H2X_AHB_ADDR_CONFIG1);

I assume this ASPEED_H2X_AHB_ADDR_CONFIG is doing basically the same
thing as aspeed_ast2700_remap_pci_addr() below, so see the comments
there.

> +	writel(ASPEED_AHB_MASK_HI_ADDR(~0),
> +	       pcie->reg + ASPEED_H2X_AHB_ADDR_CONFIG2);
> +	writel(ASPEED_H2X_BRIDGE_EN, pcie->reg + ASPEED_H2X_CTRL);
> +
> +	writel(ASPEED_PCIE_RX_DMA_EN | ASPEED_PCIE_RX_LINEAR |
> +	       ASPEED_PCIE_RX_MSI_SEL | ASPEED_PCIE_RX_MSI_EN |
> +	       ASPEED_PCIE_WAIT_RX_TLP_CLR | ASPEED_PCIE_RC_RX_ENABLE |
> +	       ASPEED_PCIE_RC_ENABLE,
> +	       pcie->reg + ASPEED_H2X_DEV_CTRL);
> +
> +	writel(ASPEED_RC_TLP_TX_TAG_NUM, pcie->reg + ASPEED_H2X_DEV_TX_TAG);
> +
> +	pcie->host->ops = &aspeed_ast2600_pcie_ops;
> +	pcie->host->child_ops = &aspeed_ast2600_pcie_child_ops;
> +
> +	return 0;
> +}
> +
> +static int aspeed_ast2700_remap_pci_addr(struct aspeed_pcie *pcie)
> +{
> +	struct device_node *dev_node = pcie->dev->of_node;
> +	struct of_pci_range range;
> +	struct of_pci_range_parser parser;
> +	int ret;
> +
> +	ret = of_pci_range_parser_init(&parser, dev_node);
> +	if (ret)
> +		return ret;
> +
> +	for_each_of_pci_range(&parser, &range) {
> +		if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM) {
> +			writel(ASPEED_REMAP_PCI_ADDR_31_12(range.pci_addr),
> +			       pcie->reg + ASPEED_H2X_REMAP_PCI_ADDR_LO);
> +			writel(ASPEED_REMAP_PCI_ADDR_63_32(range.pci_addr),
> +			       pcie->reg + ASPEED_H2X_REMAP_PCI_ADDR_HI);
> +			return 0;

It looks like this is essentially hardcoding the offset between the
parent-bus-address and the child-bus-address in the DT 'ranges'
property.  Since ASPEED_REMAP_PCI_ADDR_31_12() and
ASPEED_REMAP_PCI_ADDR_63_32() do nothing except mask out the low 12
bits, I assume that offset is zero.

But this should not be hard-coded at all; it should be extracted from
'ranges'.  I don't think we really have a consistent way of doing
this, but you can take a look at how these other drivers program
"outbound" mappings like this using bridge->windows:

  cdns_pcie_hpa_host_init_address_translation()
  dw_pcie_iatu_setup()
  mobiveil_host_init()
  xgene_pcie_map_ranges()
  iproc_pcie_map_ranges()
  rzg3s_pcie_parse_map_ranges()

> +static int aspeed_pcie_parse_dt(struct aspeed_pcie *pcie)
> +{
> +	struct device *dev = pcie->dev;
> +	struct device_node *node = dev->of_node;
> +	int ret;
> +
> +	for_each_available_child_of_node_scoped(node, child) {
> +		int slot;
> +		const char *type;
> +
> +		ret = of_property_read_string(child, "device_type", &type);
> +		if (ret || strcmp(type, "pci"))
> +			continue;
> +
> +		ret = of_pci_get_devfn(child);
> +		if (ret < 0)
> +			return dev_err_probe(dev, ret,
> +					     "failed to parse devfn\n");
> +
> +		slot = PCI_SLOT(ret);
> +
> +		ret = aspeed_pcie_parse_port(pcie, child, slot);
> +		if (ret)
> +			return ret;

It looks unnecessarily complicated to put each port on a list in
aspeed_pcie_parse_port() and then iterate over that list in
aspeed_pcie_init_ports().

I think you could just do something like:

  aspeed_pcie_parse_port();
  aspeed_pcie_port_init();

and get rid of the list completely.

> +	}
> +
> +	if (list_empty(&pcie->ports))
> +		return dev_err_probe(dev, -ENODEV,
> +				     "No PCIe port found in DT\n");
> +
> +	return 0;
> +}
> +
> +static int aspeed_pcie_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct pci_host_bridge *host;
> +	struct aspeed_pcie *pcie;
> +	struct resource_entry *entry;
> +	const struct aspeed_pcie_rc_platform *md;
> +	int irq, ret;
> +
> +	md = of_device_get_match_data(dev);
> +	if (!md)
> +		return -ENODEV;
> +
> +	host = devm_pci_alloc_host_bridge(dev, sizeof(*pcie));
> +	if (!host)
> +		return -ENOMEM;
> +
> +	pcie = pci_host_bridge_priv(host);
> +	pcie->dev = dev;
> +	pcie->tx_tag = 0;
> +	platform_set_drvdata(pdev, pcie);
> +
> +	pcie->platform = md;
> +	pcie->host = host;
> +	INIT_LIST_HEAD(&pcie->ports);
> +
> +	/* Get root bus num for cfg command to decide tlp type 0 or type 1 */
> +	entry = resource_list_first_type(&host->windows, IORESOURCE_BUS);
> +	if (entry)
> +		pcie->host_bus_num = entry->res->start;

s/host_bus_num/root_bus_nr/   to match struct altera_pcie


From sashal at kernel.org  Mon Dec  8 16:15:04 2025
From: sashal at kernel.org (Sasha Levin)
Date: Mon,  8 Dec 2025 19:15:04 -0500
Subject: [PATCH AUTOSEL 6.18-5.10] wifi: mt76: mmio_*_copy fix byte order and alignment
In-Reply-To: <20251209001610.611575-1-sashal@kernel.org>
References: <20251209001610.611575-1-sashal@kernel.org>
Message-ID: <20251209001610.611575-12-sashal@kernel.org>

From: Caleb James DeLisle <cjd at cjdns.fr>

[ Upstream commit 2df00805f7dbaa46b60c682aad0d76270b7ba266 ]

Update functions which copy to and from MMIO to load bytes as Little
Endian, and also support unaligned buffers.

PCI devices almost universally use Little Endian ordering for MMIO
registers, mt76 is no exception. PCI hardware that is designed to work
with Big Endian CPUs often (but not always) "helps" by transparently
byte-swapping MMIO reads and writes on the wire. If this is enabled
then it cannot be turned off for a single write. On hardware which does
not support this, writel() does the swap in software. When we are
transferring arbitrary bytes to MMIO space, we need them to arrive in
the same order they were in memory, so when the hardware swaps them
this is a problem. Rather than care about how our PCI host controller
works, we instead load bytes as Little Endian - so on a Big Endian
machine this will reverse them, then we use writel() which will put
them back in the right order again. This way we do not make it our
business whether the swapping is done in software or hardware.

Furthermore, inspection of the code shows that these functions are
often called with stack-allocated u8 arrays which have no alignment
guarantees so we now use (get|put)_unaligned_le32().

Fixes this issue:
mt76x2e 0000:02:00.0: ROM patch build: 20141115060606a
mt76x2e 0000:02:00.0: Firmware Version: 0.0.00
mt76x2e 0000:02:00.0: Build: 1
mt76x2e 0000:02:00.0: Build Time: 201607111443____
mt76x2e 0000:02:00.0: Firmware failed to start
mt76x2e 0000:02:00.0: probe with driver mt76x2e failed with error -145

Tested on:
SmartFiber XP8421-B (Big Endian MIPS 34Kc)
  - MT7612 -> 5g / ap / psk2
  - MT7603 -> 2g / sta / psk2
  - MT7603 -> 2g / ap / psk2
TpLink Archer v1200v-v2 (Big Endian MIPS 34Kc)
  - MT7613 -> 5g / ap / psk2
  - MT7603 -> 2g / sta / psk2

Signed-off-by: Caleb James DeLisle <cjd at cjdns.fr>
Link: https://patch.msgid.link/20251029184143.3991388-1-cjd at cjdns.fr
Signed-off-by: Felix Fietkau <nbd at nbd.name>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---

LLM Generated explanations, may be completely bogus:

## ANALYSIS SUMMARY

### 1. COMMIT MESSAGE ANALYSIS

**Bug Description:** The commit fixes two issues in mt76 WiFi driver's
MMIO copy functions:
1. **Byte order issue on Big Endian systems:** The original code uses
   `__iowrite32_copy()` and `__ioread32_copy()` which internally use
   `__raw_writel()`/`__raw_readl()` - these do NOT perform byte swapping
2. **Unaligned buffer issue:** Stack-allocated u8 arrays may not be
   4-byte aligned

**User-visible failure:** Complete driver probe failure with "Firmware
failed to start" error -145 on Big Endian systems. WiFi is totally non-
functional.

**Testing:** Tested on real hardware - multiple MT76 devices on Big
Endian MIPS platforms (SmartFiber, TP-Link Archer).

**Notable:** No `Fixes:` or `Cc: stable` tags present.

### 2. CODE CHANGE ANALYSIS

**Root cause:** The generic `__iowrite32_copy()` function (in
`lib/iomap_copy.c:20-28`) uses `__raw_writel()` which writes bytes in
host order without endian conversion. On Big Endian systems, bytes
arrive at the PCI device in the wrong order.

**The fix:**
- Replaces `__iowrite32_copy()` with explicit loop using `writel()` +
  `get_unaligned_le32()`
- Replaces `__ioread32_copy()` with explicit loop using `readl()` +
  `put_unaligned_le32()`

**Why it's correct:**
1. `get_unaligned_le32()` reads 4 bytes interpreting them as little-
   endian (safe for unaligned access)
2. `writel()` handles endian conversion (host?LE for PCI wire format)
3. Combined: bytes arrive at hardware in correct order regardless of
   host endianness
4. On Little Endian systems: behavior is functionally equivalent (no
   regression risk)

**Header dependency:** `<linux/unaligned.h>` is included transitively
via `mac80211.h` ? `mt76.h` ? `mmio.c`

### 3. CLASSIFICATION

- **Type:** Bug fix (not a feature)
- **Severity:** HIGH - Complete driver failure on affected systems
- **Scope:** mt76 WiFi devices on Big Endian architectures (MIPS
  routers, embedded systems)
- **Security:** Not a security issue

### 4. SCOPE AND RISK ASSESSMENT

| Factor | Assessment |
|--------|------------|
| Lines changed | ~10 lines (very small) |
| Files affected | 1 file (mmio.c) |
| Complexity | Low - uses standard kernel APIs |
| Risk of regression | Low - functionally equivalent on LE systems |
| Self-contained | Yes - no dependencies on other commits |

### 5. USER IMPACT

- **Affected users:** Big Endian systems with mt76 WiFi (OpenWrt
  routers, embedded MIPS devices)
- **Impact severity:** CRITICAL for affected users - WiFi doesn't work
  at all
- **Impact scope:** Minority use case (BE systems are uncommon)

### 6. STABILITY INDICATORS

- ? Signed off by subsystem maintainer (Felix Fietkau)
- ? Tested on multiple real hardware platforms
- ? Uses well-established kernel primitives
- ?? No Reviewed-by tags from others
- ?? No explicit stable request

### 7. DEPENDENCY CHECK

- ? Self-contained patch
- ? No prerequisite commits needed
- ? Code path exists in all stable trees with mt76 (since 2019)

## VERDICT

**Arguments FOR backporting:**
- Fixes a complete driver failure that makes WiFi unusable on Big Endian
  systems
- Small, surgical fix (~10 lines) with well-defined scope
- Uses standard, well-tested kernel APIs (`writel`,
  `get_unaligned_le32`)
- Self-contained with no dependencies
- Accepted by maintainer
- Functionally equivalent on Little Endian systems (no regression risk)

**Arguments AGAINST backporting:**
- No explicit `Cc: stable` tag from maintainer
- No `Fixes:` tag indicating when bug was introduced
- Big Endian systems are a minority use case

**Conclusion:** Despite the lack of explicit stable tagging, this commit
fixes a severe, user-visible bug (complete driver failure) with a small,
obviously correct fix using standard kernel patterns. The risk is low
and the benefit is high for affected users. Big Endian MIPS platforms
with mt76 WiFi (common in OpenWrt/embedded space) deserve working WiFi
support.

**YES**

 drivers/net/wireless/mediatek/mt76/mmio.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mmio.c b/drivers/net/wireless/mediatek/mt76/mmio.c
index cd2e9737c3bf9..865ec910f05a4 100644
--- a/drivers/net/wireless/mediatek/mt76/mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mmio.c
@@ -33,13 +33,21 @@ static u32 mt76_mmio_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val)
 static void mt76_mmio_write_copy(struct mt76_dev *dev, u32 offset,
 				 const void *data, int len)
 {
-	__iowrite32_copy(dev->mmio.regs + offset, data, DIV_ROUND_UP(len, 4));
+	int i;
+
+	for (i = 0; i < ALIGN(len, 4); i += 4)
+		writel(get_unaligned_le32(data + i),
+		       dev->mmio.regs + offset + i);
 }
 
 static void mt76_mmio_read_copy(struct mt76_dev *dev, u32 offset,
 				void *data, int len)
 {
-	__ioread32_copy(data, dev->mmio.regs + offset, DIV_ROUND_UP(len, 4));
+	int i;
+
+	for (i = 0; i < ALIGN(len, 4); i += 4)
+		put_unaligned_le32(readl(dev->mmio.regs + offset + i),
+				   data + i);
 }
 
 static int mt76_mmio_wr_rp(struct mt76_dev *dev, u32 base,
-- 
2.51.0



From sashal at kernel.org  Mon Dec  8 16:15:08 2025
From: sashal at kernel.org (Sasha Levin)
Date: Mon,  8 Dec 2025 19:15:08 -0500
Subject: [PATCH AUTOSEL 6.18-6.12] Bluetooth: btusb: MT7920: Add VID/PID 0489/e135
In-Reply-To: <20251209001610.611575-1-sashal@kernel.org>
References: <20251209001610.611575-1-sashal@kernel.org>
Message-ID: <20251209001610.611575-16-sashal@kernel.org>

From: Chris Lu <chris.lu at mediatek.com>

[ Upstream commit c126f98c011f5796ba118ef2093122d02809d30d ]

Add VID 0489 & PID e135 for MediaTek MT7920 USB Bluetooth chip.

The information in /sys/kernel/debug/usb/devices about the Bluetooth
device is listed as the below.

T:  Bus=06 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=480  MxCh= 0
D:  Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=0489 ProdID=e135 Rev= 1.00
S:  Manufacturer=MediaTek Inc.
S:  Product=Wireless_Device
S:  SerialNumber=000000000
C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA
A:  FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01
I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=125us
E:  Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
I:  If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
I:  If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
I:  If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
I:  If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
I:  If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
I:  If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  63 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  63 Ivl=1ms
I:* If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
E:  Ad=8a(I) Atr=03(Int.) MxPS=  64 Ivl=125us
E:  Ad=0a(O) Atr=03(Int.) MxPS=  64 Ivl=125us
I:  If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
E:  Ad=8a(I) Atr=03(Int.) MxPS=  64 Ivl=125us
E:  Ad=0a(O) Atr=03(Int.) MxPS=  64 Ivl=125us

Signed-off-by: Chris Lu <chris.lu at mediatek.com>
Reviewed-by: Paul Menzel <pmenzel at molgen.mpg.de>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz at intel.com>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---

LLM Generated explanations, may be completely bogus:

## Commit Analysis: Bluetooth btusb MT7920 VID/PID Addition

### 1. COMMIT MESSAGE ANALYSIS

**Subject:** Adding a new USB VID/PID (0489/e135) for MediaTek MT7920
Bluetooth chip

**Key observations:**
- No `Cc: stable at vger.kernel.org` tag (not unusual for device ID
  additions)
- No `Fixes:` tag (not applicable - this enables new hardware, doesn't
  fix a bug)
- Author is from MediaTek (hardware vendor)
- Has `Reviewed-by` from Paul Menzel
- Signed off by Bluetooth maintainer Luiz Augusto von Dentz

### 2. CODE CHANGE ANALYSIS

The change is minimal:
```c
+       { USB_DEVICE(0x0489, 0xe135), .driver_info = BTUSB_MEDIATEK |
+
BTUSB_WIDEBAND_SPEECH },
```

This adds a single USB device ID entry to the `quirks_table[]` in
`drivers/bluetooth/btusb.c`. The entry:
- Uses VID 0x0489, PID 0xe135
- Uses identical flags to the adjacent MT7920 entry (0x0489, 0xe134)
- Follows the exact pattern of all other MediaTek device entries

### 3. CLASSIFICATION

This falls squarely into the **"NEW DEVICE IDs"** exception category for
stable backports. Per the stable kernel rules:

> Adding PCI IDs, USB IDs, ACPI IDs, etc. to existing drivers - These
are trivial one-line additions that enable hardware support

The btusb driver already fully supports MediaTek MT7920 devices; this
just adds recognition for a new variant.

### 4. SCOPE AND RISK ASSESSMENT

| Factor | Assessment |
|--------|------------|
| Lines changed | 2 (effectively 1 entry) |
| Files touched | 1 |
| Complexity | Trivial |
| Risk | Essentially zero |

**Risk justification:** This only affects devices with exactly
VID=0x0489 and PID=0xe135. It cannot cause regressions for any other
hardware. The change is purely additive with no modification to existing
functionality.

### 5. USER IMPACT

**Without this patch:** Users with MT7920 Bluetooth USB adapters using
this VID/PID combination have no Bluetooth functionality - the kernel
doesn't recognize their device.

**With this patch:** Bluetooth works normally using the mature, existing
MediaTek btusb support.

The USB device information in the commit message confirms this is real
hardware that users possess.

### 6. STABILITY INDICATORS

- ? Reviewed by Paul Menzel
- ? Signed off by Bluetooth subsystem maintainer
- ? Author from hardware vendor (MediaTek)
- ? Identical pattern to many existing entries
- ? Same flags used as sister device (e134)

### 7. DEPENDENCY CHECK

- **No dependencies** on other commits
- Uses existing macros (`USB_DEVICE`) and flags (`BTUSB_MEDIATEK`,
  `BTUSB_WIDEBAND_SPEECH`)
- The btusb driver with MediaTek MT7920 support exists in stable kernels

### CONCLUSION

This is a textbook stable-appropriate device ID addition:

1. **Trivial 2-line change** - lowest possible complexity
2. **Zero regression risk** - only affects one specific hardware variant
3. **Real user impact** - enables Bluetooth for users with this hardware
4. **Well-reviewed** - proper sign-offs from maintainer and vendor
5. **No new code** - leverages existing, mature MediaTek btusb support
6. **No dependencies** - applies cleanly to any kernel with MT7920
   support

Device ID additions like this are routinely backported to stable trees
because they provide clear value (enabling hardware) with essentially no
risk. The pattern is identical to dozens of similar entries in the same
file.

**YES**

 drivers/bluetooth/btusb.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index fa683bb7f0b49..595afeff4afb5 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -621,6 +621,8 @@ static const struct usb_device_id quirks_table[] = {
 	/* Additional MediaTek MT7920 Bluetooth devices */
 	{ USB_DEVICE(0x0489, 0xe134), .driver_info = BTUSB_MEDIATEK |
 						     BTUSB_WIDEBAND_SPEECH },
+	{ USB_DEVICE(0x0489, 0xe135), .driver_info = BTUSB_MEDIATEK |
+						     BTUSB_WIDEBAND_SPEECH },
 	{ USB_DEVICE(0x13d3, 0x3620), .driver_info = BTUSB_MEDIATEK |
 						     BTUSB_WIDEBAND_SPEECH },
 	{ USB_DEVICE(0x13d3, 0x3621), .driver_info = BTUSB_MEDIATEK |
-- 
2.51.0



From sashal at kernel.org  Mon Dec  8 16:15:09 2025
From: sashal at kernel.org (Sasha Levin)
Date: Mon,  8 Dec 2025 19:15:09 -0500
Subject: [PATCH AUTOSEL 6.18-6.12] Bluetooth: btusb: MT7922: Add VID/PID 0489/e170
In-Reply-To: <20251209001610.611575-1-sashal@kernel.org>
References: <20251209001610.611575-1-sashal@kernel.org>
Message-ID: <20251209001610.611575-17-sashal@kernel.org>

From: Chris Lu <chris.lu at mediatek.com>

[ Upstream commit 5a6700a31c953af9a17a7e2681335f31d922614d ]

Add VID 0489 & PID e170 for MediaTek MT7922 USB Bluetooth chip.

The information in /sys/kernel/debug/usb/devices about the Bluetooth
device is listed as the below.

T:  Bus=06 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=480  MxCh= 0
D:  Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=0489 ProdID=e170 Rev= 1.00
S:  Manufacturer=MediaTek Inc.
S:  Product=Wireless_Device
S:  SerialNumber=000000000
C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA
A:  FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01
I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=125us
E:  Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
I:  If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
I:  If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
I:  If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
I:  If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
I:  If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
I:  If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  63 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  63 Ivl=1ms
I:* If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
E:  Ad=8a(I) Atr=03(Int.) MxPS=  64 Ivl=125us
E:  Ad=0a(O) Atr=03(Int.) MxPS=  64 Ivl=125us
I:  If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
E:  Ad=8a(I) Atr=03(Int.) MxPS= 512 Ivl=125us
E:  Ad=0a(O) Atr=03(Int.) MxPS= 512 Ivl=125us

Signed-off-by: Chris Lu <chris.lu at mediatek.com>
Reviewed-by: Paul Menzel <pmenzel at molgen.mpg.de>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz at intel.com>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---

LLM Generated explanations, may be completely bogus:

## Analysis: Bluetooth: btusb: MT7922: Add VID/PID 0489/e170

### 1. COMMIT MESSAGE ANALYSIS

**Subject**: Adding a new USB Vendor ID (VID) 0x0489 and Product ID
(PID) 0xe170 for a MediaTek MT7922 Bluetooth chip.

**Key Tags**:
- Signed-off-by: Chris Lu from MediaTek (the chip vendor)
- Reviewed-by: Paul Menzel
- Signed-off-by: Luiz Augusto von Dentz (Bluetooth maintainer)

No explicit `Cc: stable at vger.kernel.org` tag, but this is common for
device ID additions which are often handled implicitly.

### 2. CODE CHANGE ANALYSIS

The change is a 2-line addition to the `quirks_table[]` array:
```c
{ USB_DEVICE(0x0489, 0xe170), .driver_info = BTUSB_MEDIATEK |
                                             BTUSB_WIDEBAND_SPEECH },
```

This simply registers a new USB device ID with existing driver flags
(`BTUSB_MEDIATEK` and `BTUSB_WIDEBAND_SPEECH`) that are already fully
supported. The btusb driver already contains full MT7922 support - this
just adds another VID/PID variant to the recognition table.

### 3. CLASSIFICATION

This is a **NEW DEVICE ID** addition - one of the explicitly allowed
exception categories for stable backports:
- Adding a USB VID/PID to an existing, well-tested driver
- Trivial one-entry addition to a device table
- The driver code for MT7922 already exists; only recognition is missing

### 4. SCOPE AND RISK ASSESSMENT

| Metric | Assessment |
|--------|------------|
| Lines changed | 2 |
| Files touched | 1 |
| Complexity | Minimal - static table entry |
| Risk | **Extremely low** |

The change can only affect USB devices with VID=0x0489 and PID=0xe170.
Users without this specific hardware are completely unaffected. This is
about as low-risk as a kernel patch can be.

### 5. USER IMPACT

- **Affected users**: Those with this specific MediaTek MT7922 Bluetooth
  variant
- **Severity without fix**: Bluetooth hardware is completely non-
  functional (driver doesn't recognize the device)
- **Impact**: HIGH for affected users - their Bluetooth doesn't work at
  all

The commit includes detailed `/sys/kernel/debug/usb/devices` output
showing real hardware, indicating this comes from actual user/vendor
testing.

### 6. STABILITY INDICATORS

- Authored by MediaTek (chip vendor) with direct hardware knowledge
- Reviewed by community member
- Signed off by the Bluetooth subsystem maintainer
- Follows established pattern of many similar MT7922 device ID entries
  visible in the diff context

### 7. DEPENDENCY CHECK

- **No dependencies**: This is a self-contained table entry addition
- **Existing support**: The BTUSB_MEDIATEK and BTUSB_WIDEBAND_SPEECH
  flags and MT7922 support code exist in all recent stable trees
- **Clean application**: Should apply cleanly to any stable tree that
  has MT7922 support

### CONCLUSION

This commit is a textbook example of what SHOULD be backported to
stable:

1. **Falls under Device ID Exception**: Explicitly allowed category for
   stable
2. **Fixes Real User Problem**: Enables Bluetooth hardware that would
   otherwise be completely non-functional
3. **Minimal Risk**: 2-line table entry addition, cannot break anything
   else
4. **No New Features**: Just enables existing driver for new hardware
   variant
5. **Well-Reviewed**: Proper sign-offs from vendor and maintainer
6. **Clear Benefit**: Users with this hardware get working Bluetooth

The lack of explicit stable tag is typical for device ID additions -
stable maintainers routinely accept these. The benefit (enabling
hardware) far outweighs the near-zero risk.

**YES**

 drivers/bluetooth/btusb.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 595afeff4afb5..9b199da1c0d67 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -687,6 +687,8 @@ static const struct usb_device_id quirks_table[] = {
 						     BTUSB_WIDEBAND_SPEECH },
 	{ USB_DEVICE(0x0489, 0xe153), .driver_info = BTUSB_MEDIATEK |
 						     BTUSB_WIDEBAND_SPEECH },
+	{ USB_DEVICE(0x0489, 0xe170), .driver_info = BTUSB_MEDIATEK |
+						     BTUSB_WIDEBAND_SPEECH },
 	{ USB_DEVICE(0x04ca, 0x3804), .driver_info = BTUSB_MEDIATEK |
 						     BTUSB_WIDEBAND_SPEECH },
 	{ USB_DEVICE(0x04ca, 0x38e4), .driver_info = BTUSB_MEDIATEK |
-- 
2.51.0



From sashal at kernel.org  Mon Dec  8 16:15:33 2025
From: sashal at kernel.org (Sasha Levin)
Date: Mon,  8 Dec 2025 19:15:33 -0500
Subject: [PATCH AUTOSEL 6.18-6.12] wifi: mt76: mt792x: fix wifi init fail by setting MCU_RUNNING after CLC load
In-Reply-To: <20251209001610.611575-1-sashal@kernel.org>
References: <20251209001610.611575-1-sashal@kernel.org>
Message-ID: <20251209001610.611575-41-sashal@kernel.org>

From: Quan Zhou <quan.zhou at mediatek.com>

[ Upstream commit 066f417be5fd8c7fe581c5550206364735dad7a3 ]

Set the MT76_STATE_MCU_RUNNING bit only after mt7921_load_clc()
has successfully completed. Previously, the MCU_RUNNING state
was set before loading CLC, which could cause conflict between
chip mcu_init retry and mac_reset flow, result in chip init fail
and chip abnormal status. By moving the state set after CLC load,
firmware initialization becomes robust and resolves init fail issue.

Signed-off-by: Quan Zhou <quan.zhou at mediatek.com>
Reviewed-by: druth at chromium.org
Link: https://patch.msgid.link/19ec8e4465142e774f17801025accd0ae2214092.1763465933.git.quan.zhou at mediatek.com
Signed-off-by: Felix Fietkau <nbd at nbd.name>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---

LLM Generated explanations, may be completely bogus:

# Commit Analysis: wifi: mt76: mt792x: fix wifi init fail by setting
MCU_RUNNING after CLC load

## 1. COMMIT MESSAGE ANALYSIS

**Subject:** Clearly indicates a bug fix ("fix wifi init fail")

**Problem described:** Setting `MT76_STATE_MCU_RUNNING` bit before CLC
(Country/Legal Configuration) load completion could cause conflicts
between MCU init retry and mac_reset flows, resulting in chip
initialization failure and abnormal chip status.

**Tags present:**
- `Signed-off-by:` Quan Zhou (MediaTek - chip vendor) and Felix Fietkau
  (mt76 maintainer)
- `Reviewed-by:` druth at chromium.org (Chrome OS kernel team - indicates
  real-world Chromebook impact)
- No explicit `Cc: stable at vger.kernel.org` tag
- No explicit `Fixes:` tag

## 2. CODE CHANGE ANALYSIS

The change is extremely simple and surgical:

**Before the fix:**
```c
set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);  // State set here
err = mt7921_load_clc(dev, mt792x_ram_name(dev));   // CLC load after
```

**After the fix:**
```c
err = mt7921_load_clc(dev, mt792x_ram_name(dev));   // CLC load first
set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);  // State set after
success
```

**Technical mechanism:**
- `MT76_STATE_MCU_RUNNING` indicates the MCU is fully operational
- Setting this flag prematurely (before CLC load) could allow other code
  paths to think the MCU is ready when it's not
- If something triggers MCU init retry or mac_reset during CLC load,
  there's a race condition
- The conflict causes complete initialization failure and abnormal chip
  state

**Why fix is correct:**
- The state bit should only be set when initialization is truly complete
- This ensures no code sees MCU_RUNNING during the vulnerable CLC
  loading phase
- Error handling remains intact (if CLC load fails, function returns
  error)

## 3. CLASSIFICATION

- **Type:** Bug fix - initialization failure fix
- **NOT** a feature addition
- Fixes a real runtime bug affecting device usability

## 4. SCOPE AND RISK ASSESSMENT

| Factor | Assessment |
|--------|------------|
| Lines changed | ~6 lines (just moving 1 line in 2 files) |
| Files touched | 2 (mt7921/mcu.c, mt7925/mcu.c) |
| Complexity | Very low - simple reordering |
| Regression risk | LOW - no logic changes, just timing |
| Subsystem | Wireless driver (contained) |

The change is almost purely a reordering operation within the same
function. If CLC load succeeds, the state gets set (same as before, just
later). If it fails, function returns error anyway.

## 5. USER IMPACT

**Affected hardware:** MediaTek mt7921 and mt7925 WiFi chips

These are **extremely common** chips found in:
- Many Chromebooks (Chrome OS review indicates this)
- Consumer laptops (Dell, Lenovo, HP, etc.)
- USB WiFi adapters
- Various PC builds

**Severity:** HIGH
- WiFi initialization failure = device doesn't work at all
- "chip abnormal status" suggests chip may be left in broken state
- Users cannot use their WiFi until reboot or driver reload

## 6. STABILITY INDICATORS

- Reviewed by Chromium kernel team (indicates real-world testing on
  Chromebooks)
- From MediaTek engineer (hardware vendor knows their chip)
- Accepted by mt76 maintainer Felix Fietkau
- Clean, minimal change with clear rationale

## 7. DEPENDENCY CHECK

The change is self-contained. It only reorders existing function calls
within `mt7921_run_firmware()` and `mt7925_run_firmware()`. No new
dependencies are introduced.

The mt7921 driver has been in stable kernels for some time. The mt7925
is newer and may not exist in older stable trees, but the mt7921 portion
would still be valuable.

## STABLE KERNEL CRITERIA CHECK

| Criterion | Met? | Notes |
|-----------|------|-------|
| Obviously correct | ? | Simple reordering, logic is clear |
| Fixes real bug | ? | WiFi init failure - real user impact |
| Small and contained | ? | 6 lines, 2 files, same subsystem |
| No new features | ? | No new APIs or functionality |
| No architectural changes | ? | Minimal change |

## RISK vs BENEFIT

**Benefit:** High - Fixes WiFi initialization failure on widely-deployed
hardware. Without this fix, affected users may have non-functional WiFi.

**Risk:** Very low - The change is a trivial reordering of two
operations. The logic remains identical; only the timing of when the
state bit is set changes. The fix has been reviewed by the chip vendor
and Chrome OS team.

## CONCLUSION

This commit is an ideal candidate for stable backporting:

1. **Fixes a real, user-visible bug** - WiFi doesn't work
2. **Minimal change** - Just reordering one line in each of two files
3. **Well-reviewed** - MediaTek and Chrome OS review
4. **Low regression risk** - No logic changes, simple timing fix
5. **High user impact** - mt7921/mt7925 are very common chips
6. **Contained scope** - Only affects initialization path of specific
   driver

The lack of `Cc: stable` tag doesn't disqualify it - many legitimate
fixes don't include this tag. The important factors are all positive: it
fixes a real bug, is small, safe, and affects real users.

**YES**

 drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 2 +-
 drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index 86bd33b916a9d..edc1df3c071e5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -646,10 +646,10 @@ int mt7921_run_firmware(struct mt792x_dev *dev)
 	if (err)
 		return err;
 
-	set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
 	err = mt7921_load_clc(dev, mt792x_ram_name(dev));
 	if (err)
 		return err;
+	set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
 
 	return mt7921_mcu_fw_log_2_host(dev, 1);
 }
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index 8eda407e4135e..c12b71b71cfc7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -1003,10 +1003,10 @@ int mt7925_run_firmware(struct mt792x_dev *dev)
 	if (err)
 		return err;
 
-	set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
 	err = mt7925_load_clc(dev, mt792x_ram_name(dev));
 	if (err)
 		return err;
+	set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
 
 	return mt7925_mcu_fw_log_2_host(dev, 1);
 }
-- 
2.51.0



From xieyuanbin1 at huawei.com  Mon Dec  8 17:30:21 2025
From: xieyuanbin1 at huawei.com (Xie Yuanbin)
Date: Tue, 9 Dec 2025 09:30:21 +0800
Subject: [Bug report] hash_name() may cross page boundary and trigger sleep in RCU context
In-Reply-To: <aTbyPNINxjzU3Lua@shell.armlinux.org.uk>
References: <aTbyPNINxjzU3Lua@shell.armlinux.org.uk>
Message-ID: <20251209013021.2537-1-xieyuanbin1@huawei.com>

On Mon, 8 Dec 2025 15:43:56 +0000, Russell King wrote:
> On Mon, Dec 08, 2025 at 09:18:42PM +0800, Xie Yuanbin wrote:
>> I had indeed been lacking in consideration regarding do_alignment()
>> before, so thank you for reply. But, may I ask that, is there a scenario
>> where user-mode access to kernel addresses causes an alignment fault
>> (do_alignment())?
>
> If you mean, won't permission errors be detected first, then no.
> Alignment is one of the first things that is checked if alignment
> faults are enabled.
>
> So yes, if userspace attempts an unaigned load of a kernel address,
> and the CPU does not support / have enabled unaigned load support,
> then we will get a data abort with the FSR indicating an alignment
> fault. So do_alignment() wil be entered.
>
> Whether branch predictor handling needs to happen in this path is
> a separate question, but as it's highly likely we'll take an
> exception anyway and userspace is doing Bad Stuff, I feel it's
> better to be over-cautious.

Thanks for your reply. I know it now, and thank you.


From xieyuanbin1 at huawei.com  Mon Dec  8 18:15:19 2025
From: xieyuanbin1 at huawei.com (Xie Yuanbin)
Date: Tue, 9 Dec 2025 10:15:19 +0800
Subject: [PATCH 0/3] ARM: fix hash_name() and branch predictor issues
In-Reply-To: <aTb19aN_8PNduyDY@shell.armlinux.org.uk>
References: <aTb19aN_8PNduyDY@shell.armlinux.org.uk>
Message-ID: <20251209021519.8250-1-xieyuanbin1@huawei.com>

On Mon, 8 Dec 2025 15:59:49 +0000, Russell King wrote:
> However, there is a user accessible page above TASK_SIZE, that is the
> vectors page which can have userspace helpers in. Userspace can read
> from this page, and thus can perform unaligned loads to this page.

Thanks for your reply.

This is a key point, I think. This means that triggering an kernel
address's do_alignment() from user-mode is possible, and it's a normal
situation, not even a fault. And I also found that alignment_get_thumb()
and alignment_get_arm() might cause a fault, which will make things even
more complicated if we still keep harden_branch_predictor() inside
__do_user_fault().

In conclusion, this(these patches) should be the best solution; I can't
think of a better way.

> The system behaviour of unaligned loads has been configurable, ARMv4,
> for example, had the ability to check for alignment faults and raise
> this exception. If that was disabled, then unaligned loads would
> load the equivalent 32-bit aligned address and rotate the data in
> the register. Compilers knew about this, and would code for it,
> which made it ABI. Later compilers stopped using that which cut down
> on the unaligned loads that userspace issued. Modern CPUs (ARMv7)
> tend to behave "sanely" in that unaligned loads are generally
> supported in hardware.

Yes, I have a general understanding of this. Anyway, thanks for your
reply.


From xieyuanbin1 at huawei.com  Mon Dec  8 18:52:16 2025
From: xieyuanbin1 at huawei.com (Xie Yuanbin)
Date: Tue, 9 Dec 2025 10:52:16 +0800
Subject: [PATCH 0/3] ARM: fix hash_name() and branch predictor issues
In-Reply-To: <aTcBHKFDBkSEp5mi@shell.armlinux.org.uk>
References: <aTcBHKFDBkSEp5mi@shell.armlinux.org.uk>
Message-ID: <20251209025216.13282-1-xieyuanbin1@huawei.com>

On Mon, 8 Dec 2025 16:47:24 +0000, Russell King wrote:
> Also, would you mind giving ASAP some tested-by/reviewed-by for these
> patches so they can be pushed out to linux-next for a bit of testing
> there pelase? I'm on vacation from Thursday, so time is very short
> to get these out - if we're not ready by Wednesday, then it'll be the
> new year, possibly after the 11th January, before I can do anything
> further (medical stuff.)
>
> Thanks.

As mentioned in the previous email, this(these patches) should be the
best solution, I think. And I have carefully read the three patches, so:

Reviewed-by: Xie Yuanbin <xieyuanbin1 at huawei.com>

As for testing, I can perform some simple tests myself, and I am trying
to let the testing team to help with some further testing, like
syzkaller.


From xieyuanbin1 at huawei.com  Mon Dec  8 20:02:23 2025
From: xieyuanbin1 at huawei.com (Xie Yuanbin)
Date: Tue, 9 Dec 2025 12:02:23 +0800
Subject: [PATCH 1/3] ARM: allow __do_kernel_fault() to report execution of memory faults
In-Reply-To: <E1vSaS6-00000000Ni7-1FDb@rmk-PC.armlinux.org.uk>
References: <E1vSaS6-00000000Ni7-1FDb@rmk-PC.armlinux.org.uk>
Message-ID: <20251209040223.25069-1-xieyuanbin1@huawei.com>

On Mon, 08 Dec 2025 12:34:54 +0000, Russell King wrote:
> diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
> index 2bc828a1940c..f0884bf91dfa 100644
> --- a/arch/arm/mm/fault.c
> +++ b/arch/arm/mm/fault.c
> @@ -162,6 +162,8 @@ __do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
>  	 */
>  	if (addr < PAGE_SIZE) {
>  		msg = "NULL pointer dereference";
> +	} else if (is_permission_fault(fsr) && fsr & FSR_LNX_PF) {
> +		msg = "execution of memory";
>  	} else {
>  		if (is_translation_fault(fsr) &&
>  		    kfence_handle_page_fault(addr, is_write_fault(fsr), regs))

This patch caused a compilation error, is_permission_fault() is not
defined. Fixed with:
```patch
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 6ba5a11cc..066408523 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -192,6 +192,21 @@ static void die_kernel_fault(const char *msg, struct mm_struct *mm,
 	make_task_dead(SIGKILL);
 }

+static inline bool is_permission_fault(unsigned int fsr)
+{
+#ifdef CONFIG_MMU
+	int fs = fsr_fs(fsr);
+#ifdef CONFIG_ARM_LPAE
+	if ((fs & FS_MMU_NOLL_MASK) == FS_PERM_NOLL)
+		return true;
+#else
+	if (fs == FS_L1_PERM || fs == FS_L2_PERM)
+		return true;
+#endif
+#endif
+	return false;
+}
+
 /*
  * Oops.  The kernel tried to access some page that wasn't present.
  */
@@ -305,19 +320,6 @@ void do_bad_area_user_fixup(unsigned long addr, unsigned int fsr,
 #define VM_FAULT_BADMAP		0x010000
 #define VM_FAULT_BADACCESS	0x020000

-static inline bool is_permission_fault(unsigned int fsr)
-{
-	int fs = fsr_fs(fsr);
-#ifdef CONFIG_ARM_LPAE
-	if ((fs & FS_MMU_NOLL_MASK) == FS_PERM_NOLL)
-		return true;
-#else
-	if (fs == FS_L1_PERM || fs == FS_L2_PERM)
-		return true;
-#endif
-	return false;
-}
-
 static vm_fault_t __kprobes
 __do_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int flags,
 		unsigned long vma_flags, struct pt_regs *regs)
```


From cassel at kernel.org  Mon Dec  8 21:12:59 2025
From: cassel at kernel.org (Niklas Cassel)
Date: Tue, 9 Dec 2025 14:12:59 +0900
Subject: [PATCH v2] PCI: dwc: Make Link Up IRQ logic handle already
 powered on PCIe switches
In-Reply-To: <f1059d5d-3fa5-423a-8093-0e99b65d5f4c@oss.qualcomm.com>
References: <20251201063634.4115762-2-cassel@kernel.org>
 <f1059d5d-3fa5-423a-8093-0e99b65d5f4c@oss.qualcomm.com>
Message-ID: <aTev28wihes6iJqs@dhcp-10-89-81-223>

Hello Krishna,

Currently:
For controllers with Link Up IRQ support, the pci_host_probe() call (which
will perform PCI Configuration Space reads) is done without any of the
delays mandated by the PCIe specification.

This seems quite bad.

A device might not be fully initialized during during the time of these
PCI Configuration Space reads, but might still return some bogus values
that are actually different from the Configuration Space reads if done
after respecting the delays mandated by the PCIe specification.

I think the options are:
1) Keep the pci_host_probe() call in dw_pcie_host_init() for controllers
   with Link Up IRQ support, but make sure that we respect the delays also
   in this case.
or
2) Remove the pci_host_probe() call from dw_pcie_host_init(), and make sure
   that pci_host_probe() is done by the first Link Up IRQ
   (i.e. what this patch does).


One big thing with using the Link Up IRQ is to not do any delay during PCIe
controller driver's probe(), which reduces startup time, exactly as your
commit message in commit 36971d6c5a9a ("PCI: qcom: Don't wait for link if
we can detect Link Up") explains.
Therefore, I don't think that 1) is a good solution, so that leaves us with
2).


If pwrctrl drivers are created as part of the pci_host_probe() call,
I think that perhaps an alternative would be to create an explict
pwrctrl_init() function, and let the PCI controller drivers that actually
use pwrctrl call that from their probe().
(And just remove the same from pci_host_probe() ?)

In fact, looking at your suggested patches (that hasn't landed yet):
[PATCH 3/5] PCI/pwrctrl: Add APIs for explicitly creating and destroying pwrctrl devices
[PATCH 5/5] PCI/pwrctrl: Switch to the new pwrctrl APIs

https://lore.kernel.org/linux-pci/20251124-pci-pwrctrl-rework-v1-5-78a72627683d at oss.qualcomm.com/
https://lore.kernel.org/linux-pci/20251124-pci-pwrctrl-rework-v1-3-78a72627683d at oss.qualcomm.com/

Seem to do exactly that:
Call pci_pwrctrl_create_devices() explicitly from the PCIe controller drivers
directly, and removes the pci_pwrctrl_create_device() call from pci_host_probe().

So I don't really understand your concern with this series, at least not if
it goes on top of your series:
https://lore.kernel.org/linux-pci/20251124-pci-pwrctrl-rework-v1-0-78a72627683d at oss.qualcomm.com/


Kind regards,
Niklas


From bibek.patro at oss.qualcomm.com  Mon Dec  8 21:23:23 2025
From: bibek.patro at oss.qualcomm.com (bibek.patro at oss.qualcomm.com)
Date: Tue,  9 Dec 2025 10:53:23 +0530
Subject: [PATCH v5] iommu/arm-smmu-qcom: add actlr settings for mdss on Qualcomm platforms
Message-ID: <20251209052323.1133495-1-bibek.patro@oss.qualcomm.com>

From: Charan Teja Kalla <charan.kalla at oss.qualcomm.com>

Add ACTLR settings for missing MDSS devices on Qualcomm platforms.

These are QoS settings and are specific to per SoC thus different
settings, eg: some have shallow prefetch while others have no
prefetch.

Aswell, this prefetch feature is not implemented for all the
platforms, capturing to those are implemented to the best of my
knowledge.

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio at oss.qualcomm.com>
Signed-off-by: Charan Teja Kalla <charan.kalla at oss.qualcomm.com>
Signed-off-by: Bibek Kumar Patro <bibek.patro at oss.qualcomm.com>
---
Changes from V4:
 1) Change subject prefix to "iommu/arm-smmu-qcom:"
 based on the changes. -- Bjorn
https://lore.kernel.org/all/20251202125447.2102658-1-charan.kalla at oss.qualcomm.com/

Changes from V3:
 1) Add actlr setting for missing sc8180x & sm6115.
 2) Improved commit message.
https://lore.kernel.org/all/20251124171030.323989-1-charan.kalla at oss.qualcomm.com/

Changes from V2:
 1) Add actlr settings for all the mdss devices on Qualcomm platforms.
 2) Improved the commit message that explain why different ACTLR
    settings
https://lore.kernel.org/lkml/20251118171822.3539062-1-charan.kalla at oss.qualcomm.com/#t

Changes from V1:
  1) Added actlr setting only for MDSS and dropped for fastrpc. --
konrad
  2) ACTLR table is updated per alphanumeric order -- konrad 
  https://lore.kernel.org/all/20251105075307.1658329-1-charan.kalla at oss.qualcomm.com/

 drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 26 ++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
index 57c097e87613..c6645df97bbc 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
@@ -41,12 +41,38 @@ static const struct of_device_id qcom_smmu_actlr_client_of_match[] = {
 			.data = (const void *) (PREFETCH_DEEP | CPRE | CMTLB) },
 	{ .compatible = "qcom,fastrpc",
 			.data = (const void *) (PREFETCH_DEEP | CPRE | CMTLB) },
+	{ .compatible = "qcom,qcm2290-mdss",
+			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
 	{ .compatible = "qcom,sc7280-mdss",
 			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
 	{ .compatible = "qcom,sc7280-venus",
 			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
+	{ .compatible = "qcom,sc8180x-mdss",
+			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
+	{ .compatible = "qcom,sc8280xp-mdss",
+			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
+	{ .compatible = "qcom,sm6115-mdss",
+			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
+	{ .compatible = "qcom,sm6125-mdss",
+			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
+	{ .compatible = "qcom,sm6350-mdss",
+			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
+	{ .compatible = "qcom,sm8150-mdss",
+			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
+	{ .compatible = "qcom,sm8250-mdss",
+			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
+	{ .compatible = "qcom,sm8350-mdss",
+			.data = (const void *) (PREFETCH_SHALLOW | CPRE | CMTLB) },
+	{ .compatible = "qcom,sm8450-mdss",
+			.data = (const void *) (PREFETCH_DEFAULT | CMTLB) },
 	{ .compatible = "qcom,sm8550-mdss",
 			.data = (const void *) (PREFETCH_DEFAULT | CMTLB) },
+	{ .compatible = "qcom,sm8650-mdss",
+			.data = (const void *) (PREFETCH_DEFAULT | CMTLB) },
+	{ .compatible = "qcom,sm8750-mdss",
+			.data = (const void *) (PREFETCH_DEFAULT | CMTLB) },
+	{ .compatible = "qcom,x1e80100-mdss",
+			.data = (const void *) (PREFETCH_DEFAULT | CMTLB) },
 	{ }
 };
 
-- 
2.34.1



From krishna.chundru at oss.qualcomm.com  Mon Dec  8 21:27:18 2025
From: krishna.chundru at oss.qualcomm.com (Krishna Chaitanya Chundru)
Date: Tue, 9 Dec 2025 10:57:18 +0530
Subject: [PATCH v2] PCI: dwc: Make Link Up IRQ logic handle already
 powered on PCIe switches
In-Reply-To: <aTev28wihes6iJqs@dhcp-10-89-81-223>
References: <20251201063634.4115762-2-cassel@kernel.org>
 <f1059d5d-3fa5-423a-8093-0e99b65d5f4c@oss.qualcomm.com>
 <aTev28wihes6iJqs@dhcp-10-89-81-223>
Message-ID: <dad4957c-ca13-4742-b46d-03f0478911d5@oss.qualcomm.com>



On 12/9/2025 10:42 AM, Niklas Cassel wrote:
> Hello Krishna,
>
> Currently:
> For controllers with Link Up IRQ support, the pci_host_probe() call (which
> will perform PCI Configuration Space reads) is done without any of the
> delays mandated by the PCIe specification.
>
> This seems quite bad.
>
> A device might not be fully initialized during during the time of these
> PCI Configuration Space reads, but might still return some bogus values
> that are actually different from the Configuration Space reads if done
> after respecting the delays mandated by the PCIe specification.
>
> I think the options are:
> 1) Keep the pci_host_probe() call in dw_pcie_host_init() for controllers
>     with Link Up IRQ support, but make sure that we respect the delays also
>     in this case.
> or
> 2) Remove the pci_host_probe() call from dw_pcie_host_init(), and make sure
>     that pci_host_probe() is done by the first Link Up IRQ
>     (i.e. what this patch does).
>
>
> One big thing with using the Link Up IRQ is to not do any delay during PCIe
> controller driver's probe(), which reduces startup time, exactly as your
> commit message in commit 36971d6c5a9a ("PCI: qcom: Don't wait for link if
> we can detect Link Up") explains.
> Therefore, I don't think that 1) is a good solution, so that leaves us with
> 2).
>
>
> If pwrctrl drivers are created as part of the pci_host_probe() call,
> I think that perhaps an alternative would be to create an explict
> pwrctrl_init() function, and let the PCI controller drivers that actually
> use pwrctrl call that from their probe().
> (And just remove the same from pci_host_probe() ?)
>
> In fact, looking at your suggested patches (that hasn't landed yet):
> [PATCH 3/5] PCI/pwrctrl: Add APIs for explicitly creating and destroying pwrctrl devices
> [PATCH 5/5] PCI/pwrctrl: Switch to the new pwrctrl APIs
>
> https://lore.kernel.org/linux-pci/20251124-pci-pwrctrl-rework-v1-5-78a72627683d at oss.qualcomm.com/
> https://lore.kernel.org/linux-pci/20251124-pci-pwrctrl-rework-v1-3-78a72627683d at oss.qualcomm.com/
>
> Seem to do exactly that:
> Call pci_pwrctrl_create_devices() explicitly from the PCIe controller drivers
> directly, and removes the pci_pwrctrl_create_device() call from pci_host_probe().
>
> So I don't really understand your concern with this series, at least not if
> it goes on top of your series:
> https://lore.kernel.org/linux-pci/20251124-pci-pwrctrl-rework-v1-0-78a72627683d at oss.qualcomm.com/
Hi Niklas,

If this series goes on top of the our series i.e pwrctrl rework series, 
I don't have any concerns.
My only concern is link up IRQ never fires if this patch goes before series.

- Krishna Chaitanya.
>
>
> Kind regards,
> Niklas



From cassel at kernel.org  Mon Dec  8 21:36:44 2025
From: cassel at kernel.org (Niklas Cassel)
Date: Tue, 9 Dec 2025 14:36:44 +0900
Subject: [PATCH v2] PCI: dwc: Make Link Up IRQ logic handle already
 powered on PCIe switches
In-Reply-To: <dad4957c-ca13-4742-b46d-03f0478911d5@oss.qualcomm.com>
References: <20251201063634.4115762-2-cassel@kernel.org>
 <f1059d5d-3fa5-423a-8093-0e99b65d5f4c@oss.qualcomm.com>
 <aTev28wihes6iJqs@dhcp-10-89-81-223>
 <dad4957c-ca13-4742-b46d-03f0478911d5@oss.qualcomm.com>
Message-ID: <aTe1bA7lcVzFD5L7@dhcp-10-89-81-223>

On Tue, Dec 09, 2025 at 10:57:18AM +0530, Krishna Chaitanya Chundru wrote:
> On 12/9/2025 10:42 AM, Niklas Cassel wrote:
> > 
> > So I don't really understand your concern with this series, at least not if
> > it goes on top of your series:
> > https://lore.kernel.org/linux-pci/20251124-pci-pwrctrl-rework-v1-0-78a72627683d at oss.qualcomm.com/
> Hi Niklas,
> 
> If this series goes on top of the our series i.e pwrctrl rework series, I
> don't have any concerns.
> My only concern is link up IRQ never fires if this patch goes before series.
> 
> - Krishna Chaitanya.

This patch missed the v6.19 merge window (and so did the pwrctrl rework
series), so as long as Mani queues up both for v6.20 (with the pwrctrl
rework series getting applied first), I think we are good.


Kind regards,
Niklas


From ardb at kernel.org  Mon Dec  8 21:48:49 2025
From: ardb at kernel.org (Ard Biesheuvel)
Date: Tue,  9 Dec 2025 06:48:49 +0100
Subject: [PATCH v2] arm64/simd: Avoid pointless clearing of FP/SIMD buffer
Message-ID: <20251209054848.998878-2-ardb@kernel.org>

The buffer provided to kernel_neon_begin() is only used if the task is
scheduled out while the FP/SIMD is in use by the kernel, or when such a
section is interrupted by a softirq that also uses the FP/SIMD.

IOW, this happens rarely, and even if it happened often, there is still
no reason for this buffer to be cleared beforehand, which happens
unconditionally, due to the use of a compound literal expression.

So define that buffer variable explicitly, and mark it as
__uninitialized so that it will not get cleared, even when
-ftrivial-auto-var-init is in effect.

This requires some preprocessor gymnastics, due to the fact that the
variable must be defined throughout the entire guarded scope, and the
expression

  ({ struct user_fpsimd_state __uninitialized st; &st; })

is problematic in that regard, even though the compilers seem to
permit it. So instead, repeat for 'for ()' trick that is also used in
the implementation of the guarded scope helpers.

Cc: Will Deacon <will at kernel.org>,
Cc: Catalin Marinas <catalin.marinas at arm.com>,
Cc: Kees Cook <keescook at chromium.org>
Cc: Eric Biggers <ebiggers at kernel.org>
Signed-off-by: Ard Biesheuvel <ardb at kernel.org>
---
 arch/arm64/include/asm/simd.h | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/simd.h b/arch/arm64/include/asm/simd.h
index 0941f6f58a14..69ecbd69ca8c 100644
--- a/arch/arm64/include/asm/simd.h
+++ b/arch/arm64/include/asm/simd.h
@@ -48,6 +48,13 @@ DEFINE_LOCK_GUARD_1(ksimd,
 		    kernel_neon_begin(_T->lock),
 		    kernel_neon_end(_T->lock))
 
-#define scoped_ksimd()	scoped_guard(ksimd, &(struct user_fpsimd_state){})
+#define __scoped_ksimd(_label)					\
+	for (struct user_fpsimd_state __uninitialized __st;	\
+	     true; ({ goto _label; }))				\
+		if (0) {					\
+_label:			break;					\
+		} else scoped_guard(ksimd, &__st)
+
+#define scoped_ksimd()	__scoped_ksimd(__UNIQUE_ID(label))
 
 #endif

base-commit: 3f9f0252130e7dd60d41be0802bf58f6471c691d
-- 
2.47.3



From krzk at kernel.org  Mon Dec  8 22:01:44 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 9 Dec 2025 07:01:44 +0100
Subject: [PATCH v6 2/5] dt-bindings: clock: add Amlogic T7 SCMI clock
 controller
In-Reply-To: <dd90b445-bafb-46d4-8cec-e0877cf425b3@amlogic.com>
References: <20251204053635.1234150-1-jian.hu@amlogic.com>
 <20251204053635.1234150-3-jian.hu@amlogic.com>
 <20251208-independent-warping-macaw-74a169@quoll>
 <dd90b445-bafb-46d4-8cec-e0877cf425b3@amlogic.com>
Message-ID: <4f5ec838-f8d6-4c3b-94f2-b2a60cfe64ec@kernel.org>

On 08/12/2025 09:40, Jian Hu wrote:
> Hi, Krzysztof
> 
> 
> Thans for your review.
> 
> On 12/8/2025 2:17 PM, Krzysztof Kozlowski wrote:
>> [ EXTERNAL EMAIL ]
>>
>> On Thu, Dec 04, 2025 at 01:36:31PM +0800, Jian Hu wrote:
>>> Add DT bindings for the SCMI clock controller of the Amlogic T7 SoC family.
>>>
>>> Signed-off-by: Jian Hu <jian.hu at amlogic.com>
>>> Acked-by: Rob Herring (Arm) <robh at kernel.org>
>>> ---
>>>   include/dt-bindings/clock/amlogic,t7-scmi.h | 47 +++++++++++++++++++++
>>>   1 file changed, 47 insertions(+)
>>>   create mode 100644 include/dt-bindings/clock/amlogic,t7-scmi.h
>>>
>> Where is any binding doc for this? Why is this a separate patch?
> 
> 
> The ARM SCMI device tree binding specification is located at 
> ./Documentation/devicetree/bindings/firmware/arm,scmi.yaml.

Then git grep for the file name - there is no such compatible. Are you
sure you follow writing bindings doc?

Think how are you going to use these values. You will have phandle, yes?
To some controller, yes? Which one?

> 
> Certain secure clocks on the T7 rely on the ARM SCMI driver stack, which 
> is officially supported by ARM.
> 
> The kernel-side SCMI client implementation resides in 
> ./drivers/firmware/arm_scmi/.
> 
> To enable ARM SCMI on T7, three components are needed:
> 
> - Kernel-side definition of ARM SCMI clock indices (this patch addresses 
> this component);
> - SCMI server implementation in the ARM Trusted Firmware (ATF) running 
> at Exception Level 3 (EL3), which has been integrated into the bootloader;
> - Device Tree Source (DTS) configuration for ARM SCMI clock nodes (the 
> DTS changes will be submitted after the T7 clock driver patches are 
> merged upstream).

So silently you keep the users hidden? No, I want to see the users.


Best regards,
Krzysztof


From krzk at kernel.org  Mon Dec  8 22:04:13 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 9 Dec 2025 07:04:13 +0100
Subject: [PATCH v2 7/8] dt-bindings: pinctrl: rockchip: Add RMIO
 controller binding
In-Reply-To: <AGkAlwDSJz*Fj0POUP7xe4pV.3.1765201861250.Hmail.ye.zhang@rock-chips.com>
References: <20251206050844.402958-1-ye.zhang@rock-chips.com>
 <20251206050844.402958-8-ye.zhang@rock-chips.com>
 <20251208-invisible-crazy-squirrel-bb3af0@quoll>
 <AGkAlwDSJz*Fj0POUP7xe4pV.3.1765201861250.Hmail.ye.zhang@rock-chips.com>
Message-ID: <f48de0f4-4ebb-4634-8c3d-1d2b753eb232@kernel.org>

On 08/12/2025 14:51, ?? wrote:
> Hi Krzysztof,
> First of all, I sincerely apologize for the low quality of this patchset and the extra workload it caused. I appreciate your detailed review and strict checks, which help improve the code.
> 
> 
> Regarding your comments, I have the following questions and a proposal for v3. Could you please check if this aligns with your expectations?
> 


I have no clue what you are referring to. Please follow standard mailing
list discussion style. I am not reading the rest of whatever this is.

Best regards,
Krzysztof


From dapeng1.mi at linux.intel.com  Mon Dec  8 22:31:17 2025
From: dapeng1.mi at linux.intel.com (Mi, Dapeng)
Date: Tue, 9 Dec 2025 14:31:17 +0800
Subject: [PATCH v6 44/44] KVM: VMX: Add mediated PMU support for CPUs
 without "save perf global ctrl"
In-Reply-To: <ee30ed9c-6377-4d14-b930-f0e2c809df7c@linux.intel.com>
References: <20251206001720.468579-1-seanjc@google.com>
 <20251206001720.468579-45-seanjc@google.com>
 <ee30ed9c-6377-4d14-b930-f0e2c809df7c@linux.intel.com>
Message-ID: <8365c5ca-637d-4bef-a404-eb2166d384f5@linux.intel.com>


On 12/8/2025 5:39 PM, Mi, Dapeng wrote:
> On 12/6/2025 8:17 AM, Sean Christopherson wrote:
>> Extend mediated PMU support for Intel CPUs without support for saving
>> PERF_GLOBAL_CONTROL into the guest VMCS field on VM-Exit, e.g. for Skylake
>> and its derivatives, as well as Icelake.  While supporting CPUs without
>> VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL isn't completely trivial, it's not that
>> complex either.  And not supporting such CPUs would mean not supporting 7+
>> years of Intel CPUs released in the past 10 years.
>>
>> On VM-Exit, immediately propagate the saved PERF_GLOBAL_CTRL to the VMCS
>> as well as KVM's software cache so that KVM doesn't need to add full EXREG
>> tracking of PERF_GLOBAL_CTRL.  In practice, the vast majority of VM-Exits
>> won't trigger software writes to guest PERF_GLOBAL_CTRL, so deferring the
>> VMWRITE to the next VM-Enter would only delay the inevitable without
>> batching/avoiding VMWRITEs.
>>
>> Note!  Take care to refresh VM_EXIT_MSR_STORE_COUNT on nested VM-Exit, as
>> it's unfortunately possible that KVM could recalculate MSR intercepts
>> while L2 is active, e.g. if userspace loads nested state and _then_ sets
>> PERF_CAPABILITIES.  Eating the VMWRITE on every nested VM-Exit is
>> unfortunate, but that's a pre-existing problem and can/should be solved
>> separately, e.g. modifying the number of auto-load entries while L2 is
>> active is also uncommon on modern CPUs.
>>
>> Signed-off-by: Sean Christopherson <seanjc at google.com>
>> ---
>>  arch/x86/kvm/vmx/nested.c    |  6 ++++-
>>  arch/x86/kvm/vmx/pmu_intel.c |  7 -----
>>  arch/x86/kvm/vmx/vmx.c       | 52 ++++++++++++++++++++++++++++++++----
>>  3 files changed, 52 insertions(+), 13 deletions(-)
>>
>> diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
>> index 614b789ecf16..1ee1edc8419d 100644
>> --- a/arch/x86/kvm/vmx/nested.c
>> +++ b/arch/x86/kvm/vmx/nested.c
>> @@ -5142,7 +5142,11 @@ void __nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
>>  
>>  	kvm_nested_vmexit_handle_ibrs(vcpu);
>>  
>> -	/* Update any VMCS fields that might have changed while L2 ran */
>> +	/*
>> +	 * Update any VMCS fields that might have changed while vmcs02 was the
>> +	 * active VMCS.  The tracking is per-vCPU, not per-VMCS.
>> +	 */
>> +	vmcs_write32(VM_EXIT_MSR_STORE_COUNT, vmx->msr_autostore.nr);
>>  	vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.host.nr);
>>  	vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, vmx->msr_autoload.guest.nr);
>>  	vmcs_write64(TSC_OFFSET, vcpu->arch.tsc_offset);
>> diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
>> index 55249fa4db95..27eb76e6b6a0 100644
>> --- a/arch/x86/kvm/vmx/pmu_intel.c
>> +++ b/arch/x86/kvm/vmx/pmu_intel.c
>> @@ -777,13 +777,6 @@ static bool intel_pmu_is_mediated_pmu_supported(struct x86_pmu_capability *host_
>>  	if (WARN_ON_ONCE(!cpu_has_load_perf_global_ctrl()))
>>  		return false;
>>  
>> -	/*
>> -	 * KVM doesn't yet support mediated PMU on CPUs without support for
>> -	 * saving PERF_GLOBAL_CTRL via a dedicated VMCS field.
>> -	 */
>> -	if (!cpu_has_save_perf_global_ctrl())
>> -		return false;
>> -
>>  	return true;
>>  }
>>  
>> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
>> index 6a17cb90eaf4..ba1262c3e3ff 100644
>> --- a/arch/x86/kvm/vmx/vmx.c
>> +++ b/arch/x86/kvm/vmx/vmx.c
>> @@ -1204,6 +1204,17 @@ static bool update_transition_efer(struct vcpu_vmx *vmx)
>>  	return true;
>>  }
>>  
>> +static void vmx_add_autostore_msr(struct vcpu_vmx *vmx, u32 msr)
>> +{
>> +	vmx_add_auto_msr(&vmx->msr_autostore, msr, 0, VM_EXIT_MSR_STORE_COUNT,
>> +			 vmx->vcpu.kvm);
>> +}
>> +
>> +static void vmx_remove_autostore_msr(struct vcpu_vmx *vmx, u32 msr)
>> +{
>> +	vmx_remove_auto_msr(&vmx->msr_autostore, msr, VM_EXIT_MSR_STORE_COUNT);
>> +}
>> +
>>  #ifdef CONFIG_X86_32
>>  /*
>>   * On 32-bit kernels, VM exits still load the FS and GS bases from the
>> @@ -4225,6 +4236,8 @@ void pt_update_intercept_for_msr(struct kvm_vcpu *vcpu)
>>  
>>  static void vmx_recalc_pmu_msr_intercepts(struct kvm_vcpu *vcpu)
>>  {
>> +	u64 vm_exit_controls_bits = VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL |
>> +				    VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL;
>>  	bool has_mediated_pmu = kvm_vcpu_has_mediated_pmu(vcpu);
>>  	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
>>  	struct vcpu_vmx *vmx = to_vmx(vcpu);
>> @@ -4234,12 +4247,19 @@ static void vmx_recalc_pmu_msr_intercepts(struct kvm_vcpu *vcpu)
>>  	if (!enable_mediated_pmu)
>>  		return;
>>  
>> +	if (!cpu_has_save_perf_global_ctrl()) {
>> +		vm_exit_controls_bits &= ~VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL;
>> +
>> +		if (has_mediated_pmu)
>> +			vmx_add_autostore_msr(vmx, MSR_CORE_PERF_GLOBAL_CTRL);
>> +		else
>> +			vmx_remove_autostore_msr(vmx, MSR_CORE_PERF_GLOBAL_CTRL);
>> +	}
>> +
>>  	vm_entry_controls_changebit(vmx, VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL,
>>  				    has_mediated_pmu);
>>  
>> -	vm_exit_controls_changebit(vmx, VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL |
>> -					VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL,
>> -				   has_mediated_pmu);
>> +	vm_exit_controls_changebit(vmx, vm_exit_controls_bits, has_mediated_pmu);
>>  
>>  	for (i = 0; i < pmu->nr_arch_gp_counters; i++) {
>>  		vmx_set_intercept_for_msr(vcpu, MSR_IA32_PERFCTR0 + i,
>> @@ -7346,6 +7366,29 @@ static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx)
>>  					      msrs[i].host);
>>  }
>>  
>> +static void vmx_refresh_guest_perf_global_control(struct kvm_vcpu *vcpu)
>> +{
>> +	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
>> +	struct vcpu_vmx *vmx = to_vmx(vcpu);
>> +
>> +	if (msr_write_intercepted(vmx, MSR_CORE_PERF_GLOBAL_CTRL))
>> +		return;
>> +
>> +	if (!cpu_has_save_perf_global_ctrl()) {
>> +		int slot = vmx_find_loadstore_msr_slot(&vmx->msr_autostore,
>> +						       MSR_CORE_PERF_GLOBAL_CTRL);
>> +
>> +		if (WARN_ON_ONCE(slot < 0))
>> +			return;
>> +
>> +		pmu->global_ctrl = vmx->msr_autostore.val[slot].value;
>> +		vmcs_write64(GUEST_IA32_PERF_GLOBAL_CTRL, pmu->global_ctrl);
>> +		return;
>> +	}
>> +
>> +	pmu->global_ctrl = vmcs_read64(GUEST_IA32_PERF_GLOBAL_CTRL);
>> +}
>> +
>>  static void vmx_update_hv_timer(struct kvm_vcpu *vcpu, bool force_immediate_exit)
>>  {
>>  	struct vcpu_vmx *vmx = to_vmx(vcpu);
>> @@ -7631,8 +7674,7 @@ fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu, u64 run_flags)
>>  
>>  	vmx->loaded_vmcs->launched = 1;
>>  
>> -	if (!msr_write_intercepted(vmx, MSR_CORE_PERF_GLOBAL_CTRL))
>> -		vcpu_to_pmu(vcpu)->global_ctrl = vmcs_read64(GUEST_IA32_PERF_GLOBAL_CTRL);
>> +	vmx_refresh_guest_perf_global_control(vcpu);
>>  
>>  	vmx_recover_nmi_blocking(vmx);
>>  	vmx_complete_interrupts(vmx);
> The change looks good to me, but I still have no bandwidth to test the code
> on Ice lake, I would go back after I finish the tests. Thanks.

Tested below test cases on Skylake and Sapphire Rapids servers for both
mediated vPMU and Perf based emulated vPMU, no issue is found. Thanks.

Kselftests: pmu_counters_test/pmu_event_filter_test/vmx_pmu_caps_test

KVM-unit-tests: pmu/pmu_lbr/pmu_pebs

Reviewed-by: Dapeng Mi <dapeng1.mi at linux.intel.com>

Tested-by: Dapeng Mi <dapeng1.mi at linux.intel.com>


>
>


From hch at lst.de  Mon Dec  8 22:38:09 2025
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 9 Dec 2025 07:38:09 +0100
Subject: [PATCH 1/8] dmaengine: Add API to combine configuration and
 preparation (sg and single)
In-Reply-To: <20251208-dma_prep_config-v1-1-53490c5e1e2a@nxp.com>
References: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com> <20251208-dma_prep_config-v1-1-53490c5e1e2a@nxp.com>
Message-ID: <20251209063809.GA27728@lst.de>

On Mon, Dec 08, 2025 at 12:09:40PM -0500, Frank Li wrote:
> Previously, configuration and preparation required two separate calls. This
> works well when configuration is done only once during initialization.
> 
> However, in cases where the burst length or source/destination address must
> be adjusted for each transfer, calling two functions is verbose and
> requires additional locking to ensure both steps complete atomically.
> 
> Add a new API and callback device_prep_slave_sg_config that combines
> configuration and preparation into a single operation. If the configuration
> argument is passed as NULL, fall back to the existing implementation.

Maybe this would be a good time to start retiring the "slave" naming
and come up with shorter names as a win-win situation?



From hch at lst.de  Mon Dec  8 22:38:55 2025
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 9 Dec 2025 07:38:55 +0100
Subject: [PATCH 6/8] nvmet: pci-epf: Use
 dmaengine_prep_slave_single_config() API
In-Reply-To: <20251208-dma_prep_config-v1-6-53490c5e1e2a@nxp.com>
References: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com> <20251208-dma_prep_config-v1-6-53490c5e1e2a@nxp.com>
Message-ID: <20251209063855.GB27728@lst.de>

> +	desc = dmaengine_prep_slave_single_config(chan, dma_addr, seg->length,
> +						  sconf.direction,
> +						  DMA_CTRL_ACK,
> +						  &sconf);


If you stick to tab-indents this becomes a lot more readable:

	desc = dmaengine_prep_slave_single_config(chan, dma_addr, seg->length,
			sconf.direction, DMA_CTRL_ACK, &sconf);


From dan.carpenter at linaro.org  Mon Dec  8 22:53:36 2025
From: dan.carpenter at linaro.org (Dan Carpenter)
Date: Tue, 9 Dec 2025 09:53:36 +0300
Subject: [PATCH] phy: stm32-usphyc: Fix off by one in probe()
Message-ID: <aTfHcMJK1wFVnvEe@stanley.mountain>

The "index" variable is used as an index into the usbphyc->phys[] array
which has usbphyc->nphys elements.  So if it is equal to usbphyc->nphys
then it is one element out of bounds.  The "index" comes from the
device tree so it's data that we trust and it's unlikely to be wrong,
however it's obviously still worth fixing the bug.  Change the > to >=.

Fixes: 94c358da3a05 ("phy: stm32: add support for STM32 USB PHY Controller (USBPHYC)")
Signed-off-by: Dan Carpenter <dan.carpenter at linaro.org>
---
 drivers/phy/st/phy-stm32-usbphyc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/phy/st/phy-stm32-usbphyc.c b/drivers/phy/st/phy-stm32-usbphyc.c
index 27fe92f73f33..b44afbff8616 100644
--- a/drivers/phy/st/phy-stm32-usbphyc.c
+++ b/drivers/phy/st/phy-stm32-usbphyc.c
@@ -712,7 +712,7 @@ static int stm32_usbphyc_probe(struct platform_device *pdev)
 		}
 
 		ret = of_property_read_u32(child, "reg", &index);
-		if (ret || index > usbphyc->nphys) {
+		if (ret || index >= usbphyc->nphys) {
 			dev_err(&phy->dev, "invalid reg property: %d\n", ret);
 			if (!ret)
 				ret = -EINVAL;
-- 
2.51.0



From dan.carpenter at linaro.org  Mon Dec  8 22:54:16 2025
From: dan.carpenter at linaro.org (Dan Carpenter)
Date: Tue, 9 Dec 2025 09:54:16 +0300
Subject: [PATCH] irqchip/mchp-eic: Fix error code in mchp_eic_domain_alloc()
Message-ID: <aTfHmOz6IBpTIPU5@stanley.mountain>

If the irq_domain_translate_twocell() function sets "hwirq" to >=
MCHP_EIC_NIRQ (2) then it would result in an out of bounds access.
The code here checks for invalid values, but doesn't set the error
code.  Return -EINVAL in that case, instead of returning success.

Fixes: 00fa3461c86d ("irqchip/mchp-eic: Add support for the Microchip EIC")
Signed-off-by: Dan Carpenter <dan.carpenter at linaro.org>
---
 drivers/irqchip/irq-mchp-eic.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/irqchip/irq-mchp-eic.c b/drivers/irqchip/irq-mchp-eic.c
index 2474fa467a05..31093a8ab67c 100644
--- a/drivers/irqchip/irq-mchp-eic.c
+++ b/drivers/irqchip/irq-mchp-eic.c
@@ -170,7 +170,7 @@ static int mchp_eic_domain_alloc(struct irq_domain *domain, unsigned int virq,
 
 	ret = irq_domain_translate_twocell(domain, fwspec, &hwirq, &type);
 	if (ret || hwirq >= MCHP_EIC_NIRQ)
-		return ret;
+		return ret ?: -EINVAL;
 
 	switch (type) {
 	case IRQ_TYPE_EDGE_RISING:
-- 
2.51.0



From tomeu at tomeuvizoso.net  Mon Dec  8 22:55:59 2025
From: tomeu at tomeuvizoso.net (Tomeu Vizoso)
Date: Tue, 9 Dec 2025 07:55:59 +0100
Subject: Issues with DRM_ACCEL_ROCKET (Oops, power-domain, probe-ordering)
In-Reply-To: <fa82d11f-ce11-4feb-bdb4-c31d360a2a62@rock-chips.com>
References: <0b20d760-ad4f-41c0-b733-39db10d6cc41@cherry.de>
 <77685900-2c34-49b8-8c7e-14718841ef17@rock-chips.com> <fa82d11f-ce11-4feb-bdb4-c31d360a2a62@rock-chips.com>
Message-ID: <CAAObsKDYLXVf1GdYUNeaOya+pWD4jTOEf55ouXAL9iM_kWCcMw@mail.gmail.com>

On Tue, Dec 2, 2025 at 8:00?AM Chaoyi Chen <chaoyi.chen at rock-chips.com> wrote:
>
> Hi Quentin,
>
> I finally had time to look into this today, and I think I've run into
> the same issue you did. Please see the comment below :)
>
> On 12/1/2025 2:24 PM, Chaoyi Chen wrote:
> > Hi Quentin,
> >
> > On 11/29/2025 2:41 AM, Quentin Schulz wrote:
> >> Hi all,
> >>
> >> I've finally found the time to test the RK3588 NPU (aka Rocket, upstream) on our products and I've been hit with Oopses when loosely following the instructions from https://docs.mesa3d.org/teflon.html. After debugging for a while this is often (not always!) reproducible when DRM_ACCEL_ROCKET=y (but not when built as a module!). The fact it's "not always" is a dead giveaway timing or probe order is involved, more later on that.
> >>
> >
> > This looks like a power domain problem. What would happen if you tried
> > enabling the regulator for the NPU power domain in U-Boot?
> >
> > Or did you properly configure the corresponding regulator supply in
> > the power domain?
> >
> >
> >> I don't think the Oops is important as I believe it's a symptom of other issues, so I won't post it.
> >>
> >> I'll list the issue I've identified so far, some seem easier to fix than others (the biggest issue of course being the hardest to fix).
> >>
> >> 1. https://elixir.bootlin.com/linux/v6.18-rc7/source/drivers/accel/rocket/rocket_core.c#L79
> >>
> >> The error path after a failed pm_runtime_resume_and_get() probably should be calling rocket_core_fini(core) and not rocket_job_fini() (the former calls the latter) as to unwind everything that's been done in rocket_core_init() before this failed.
> >>
> >> The PM core complains about unbalanced something when the core fails to init and is retried later.
> >>
> >> I suggest the following:
> >>
> >> """
> >> diff --git a/drivers/accel/rocket/rocket_core.c b/drivers/accel/rocket/rocket_core.c
> >> index abe7719c1db46..95a732ab418c3 100644
> >> --- a/drivers/accel/rocket/rocket_core.c
> >> +++ b/drivers/accel/rocket/rocket_core.c
> >> @@ -76,7 +76,7 @@ int rocket_core_init(struct rocket_core *core)
> >>
> >>      err = pm_runtime_resume_and_get(dev);
> >>      if (err) {
> >> -        rocket_job_fini(core);
> >> +        rocket_core_fini(core);
> >>          return err;
> >>      }
> >>
>
> pm_runtime_resume_and_get() will fail here because the pmdomain
> isn't ready yet.
>
> I think we should return -EPROBE_DEFER in this case.
>
> >> """
> >>
> >> I can send a patch for that.
> >>
> >> 2. rocket_probe() (https://elixir.bootlin.com/linux/v6.18-rc7/source/drivers/accel/rocket/rocket_drv.c#L159) can result in out-of-bounds access when rocket_core_init() fails as rdev is a global variable (so rdev->num_cores persists between tries). Considering rdev->cores is allocated based on the number of available nodes in the DTB with the rknn compatible, if rocket_probe() is called more than the number of available nodes, rdev->cores[core] will result in out-of-bounds access.
> >>
> >> I believe we could do:
> >>
> >> """
> >> diff --git a/drivers/accel/rocket/rocket_drv.c b/drivers/accel/rocket/rocket_drv.c
> >> index 5c0b63f0a8f00..ad602ebd17c44 100644
> >> --- a/drivers/accel/rocket/rocket_drv.c
> >> +++ b/drivers/accel/rocket/rocket_drv.c
> >> @@ -158,6 +158,8 @@ static const struct drm_driver rocket_drm_driver = {
> >>
> >>  static int rocket_probe(struct platform_device *pdev)
> >>  {
> >> +    int ret;
> >> +
> >>      if (rdev == NULL) {
> >>          /* First core probing, initialize DRM device. */
> >>          rdev = rocket_device_init(drm_dev, &rocket_drm_driver);
> >> @@ -177,7 +179,15 @@ static int rocket_probe(struct platform_device *pdev)
> >>
> >>      rdev->num_cores++;
> >>
> >> -    return rocket_core_init(&rdev->cores[core]);
> >> +    ret = rocket_core_init(&rdev->cores[core]);
> >> +    if (ret) {
> >> +        rdev->num_cores--;
> >> +        if (rdev->num_cores == 0) {
> >> +            rocket_device_fini(rdev);
> >> +        }
> >> +    }
> >> +
> >> +    return ret;
> >>  }
> >>
> >>  static void rocket_remove(struct platform_device *pdev)
> >>
> >> """
> >>
> >
> > It seems hacky. I'm not sure whether this would be better
> > implemented as a component driver.
> >
>
> When I was looking at this code, it hadn't been merged yet,
> and there is a core0 device called "rknn_top". Likewise, there's
> a component over there. But in the latest version, it's gone :(
>
> And yes, core 0 is special [0]. So I think this change is make sense.
> But that's still not enough, because we may need to defer the probe.
> We have to make sure that when we probe next time, core 0 still gets
> index 0 here.
>
> [0] https://lore.kernel.org/all/20250721-6-10-rocket-v9-8-77ebd484941e at tomeuvizoso.net/
>
> >> I can send a patch for that.
> >>
> >> 3. I believe (but I may be wrong) that core 0 is special (do we need to schedule through core 0 maybe?). There's a hardcoded fetch of the device associated with core 0 via rocket_iommu_domain_create(rdev->cores[0].dev); (https://elixir.bootlin.com/linux/v6.18-rc7/source/drivers/accel/rocket/rocket_drv.c#L88). The issue is that this assumes that core 0 is always rdev->cores[0], which may not be true as it depends on the probe order (which is not guaranteed), which can be exacerbated by core 0 (HW index) probe being deferred for some reason. Is it necessary for core 0 to be the one initializing the DRM device or could we simply use any core for that (just the first to probe, whichever it actually is HW-wise)?
>
> I agree with you about the probe order problem. As I mentioned,
> in earlier versions core 0 was still "rknn_top". It looks like this
> would address many of the problem you raised. I don't know why
> that was dropped in the merged version.

This need was questioned during the review process, and during my
stress testing I didn't find a need for core 0 to be treated
specially. So it was considered unneeded complexity and the code was
dropped.

My testing involves running the supported models as a whole, and also
their individual operations as individual tests. I run them in 8
parallel processes, in batches so we have continuous bring up and down
of clients.

I'm a bit surprised that that testing worked stably but we have still
failures in some setups.

Regards,

Tomeu



> >
> > I think this is because multiple cores share the same IOMMU device.
> >
> >>
> >> If there's a need to know which of the three cores is core 0, we can have a vendor property for it or maybe aliases for the cores? We can also do a check on the base register address of the core in DT and then do a mapping in the driver. Any other suggestion?
> >>
> >> 4. The actual issue I'm unable to suggest something for comes now. The following is all happening in the context of DRM_ACCEL_ROCKET being built-in (that is DRM_ACCEL_ROCKET=y). You can use aarch64's default defconfig, then DRM=y, DRM_ACCEL=y and DRM_ACCEL_ROCKET=y via menuconfig. Remember that this is not 100% reproducible (more often happening than not).
> >>
> >> Points 1, 2 and 3 only are an issue if you hit some error-path during the probe of one of the cores, which is triggered by this point 4 here.
> >>
> >> rknn_core_0 depends on rknn_mmu_0 as highlighted by the iommus phandle property. rknn_mmu_0 depends on RK3588_PD_NPUTOP power-domain. The parent domain (RK3588_PD_NPU) of RK3588_PD_NPUTOP power-domain has a domain-supply on a regulator on i2c (i2c0 at 42 for Jaguar, patches on the ML at https://lore.kernel.org/linux-rockchip/20250812085213.1071106-2-heiko at sntech.de/). When the rocket driver calls platform_driver_register() in its module_init() function, the kernel core will try to probe the associated device, via driver_probe_device(), then __driver_probe_device() and more specifically pm_runtime_get_suppliers(dev) in there (https://elixir.bootlin.com/linux/v6.18-rc7/source/drivers/base/dd.c#L793). Then this calls pm_runtime_get_sync() on all links, c.f. https://elixir.bootlin.com/linux/v6.18-rc7/source/drivers/base/power/runtime.c#L1914. Note that pm_runtime_get_suppliers() returns void. One of the links is the rknn_mmu_0.
> >>
> >> Follow the next series of function calls, pm_runtime_get_sync() on rknn_mmu_0, rpm_resume(), rpm_callback(), __rpm_callback(). This then calls cb(). cb() is set via RPM_GET_CALLBACK(dev, runtime_resume). Due to rknn_mmu_0 device being probed with dev_pm_domain_attach() attaching the power-domain device to iommu via the pm_domain member, genpd_runtime_resume() (which goes to rockchip_pd_power_on()) is actually called. This then calls rockchip_pd_regulator_enable() which returns -EPROBE_DEFER. Going up in the call stack up to rpm_callback() you can see that retval = __rpm_callback(cb, dev); now is EPROBE_DEFER and thus, dev->power.runtime_error = EPROBE_DEFER at the end of the function.
> >>
> >> Then once pm_runtime_resume_and_get(dev); is called in rocket_core_init() during probe of the rocket device, it'll call into rpm_get_suppliers() in __rpm_callback() which in turn will call pm_runtime_get_sync() on rknn_mmu_0 which will go up to rpm_resume() where dev->power.runtime_error will be checked and if non-zero will return -EINVAL, effectively eating -EPROBE_DEFER and failing the probe of the rocket device instead of deferring the probe.
> >>
> >> Applying the below patch:
> >>
> >> """
> >> diff --git a/drivers/accel/rocket/rocket_core.c b/drivers/accel/rocket/rocket_core.c
> >> index abe7719c1db46..c4692189bbfc6 100644
> >> --- a/drivers/accel/rocket/rocket_core.c
> >> +++ b/drivers/accel/rocket/rocket_core.c
> >> @@ -72,22 +72,9 @@ int rocket_core_init(struct rocket_core *core)
> >>       */
> >>      pm_runtime_set_autosuspend_delay(dev, 50);
> >>
> >> +    pm_runtime_set_suspended(dev);
> >>      pm_runtime_enable(dev);
> >>
> >> -    err = pm_runtime_resume_and_get(dev);
> >> -    if (err) {
> >> -        rocket_job_fini(core);
> >> -        return err;
> >> -    }
> >> -
> >> -    version = rocket_pc_readl(core, VERSION);
> >> -    version += rocket_pc_readl(core, VERSION_NUM) & 0xffff;
> >> -
> >> -    pm_runtime_mark_last_busy(dev);
> >> -    pm_runtime_put_autosuspend(dev);
> >> -
> >> -    dev_info(dev, "Rockchip NPU core %d version: %d\n", core->index, version);
> >> -
> >>      return 0;
> >>  }
> >>
> >> """
> >>
>
> I believe that once the problems above are resolved, the complexity
> around point 4 will disappear as well.
>
> >> seems to make it possible to run mesa's example. If pm_runtime_set_suspended(dev); isn't added, we'll only ever get job timeouts.
> >>
> >> Note that I'm pretty sure this isn't the proper way to do it but wanted to give some of my debugging attempts at that.
> >>
> >> I'm not sure how much further I can go and specifically I have no clue how to handle that properly. Please also verify all the claims I'm making, I'm not entirely sure I got every call stack right, it is quite convoluted and I don't have experience with those frameworks.
> >>
> >> Does anyone have a clue how we can deal with that?
> >>
> >> The driver built as a module doesn't have this issue because the regulator has enough time to probe so that PD doesn't return EPROBE_DEFER when the rocket device gets probed once reaching userspace (where the module is). I'm not entirely sure if this could be reproduced by having the regulator driver as a module too for example?
> >>
> >> Cheers,
> >> Quentin
> >>
> >> _______________________________________________
> >> Linux-rockchip mailing list
> >> Linux-rockchip at lists.infradead.org
> >> http://lists.infradead.org/mailman/listinfo/linux-rockchip
> >
>
> --
> Best,
> Chaoyi


From dlemoal at kernel.org  Mon Dec  8 22:52:15 2025
From: dlemoal at kernel.org (Damien Le Moal)
Date: Tue, 9 Dec 2025 15:52:15 +0900
Subject: [PATCH 5/8] nvmet: pci-epf: Remove unnecessary
 dmaengine_terminate_sync() on each DMA transfer
In-Reply-To: <20251208-dma_prep_config-v1-5-53490c5e1e2a@nxp.com>
References: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
 <20251208-dma_prep_config-v1-5-53490c5e1e2a@nxp.com>
Message-ID: <f9107db3-491e-4224-a337-821a89f99132@kernel.org>

On 12/9/25 2:09 AM, Frank Li wrote:
> dmaengine_terminate_sync() cancels all pending requests. Calling it for
> every DMA transfer is unnecessary and counterproductive. This function is
> generally intended for cleanup paths such as module removal, device close,
> or unbind operations.
> 
> Remove the redundant calls.
> 
> Signed-off-by: Frank Li <Frank.Li at nxp.com>
> ---
> This one also fix stress test failure after remove mutex and use new API
> dmaengine_prep_slave_sg_config().
> ---
>  drivers/nvme/target/pci-epf.c | 2 --
>  1 file changed, 2 deletions(-)
> 
> diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c
> index 2e78397a7373a7d8ba67150f301f392123db88d1..85225a4f75b5bd7abb6897d064123766af021542 100644
> --- a/drivers/nvme/target/pci-epf.c
> +++ b/drivers/nvme/target/pci-epf.c
> @@ -420,8 +420,6 @@ static int nvmet_pci_epf_dma_transfer(struct nvmet_pci_epf *nvme_epf,
>  		ret = -EIO;
>  	}
>  
> -	dmaengine_terminate_sync(chan);

If the above dma_sync_wait failed, we better call this here as we have no idea
why we got the failure, no ?
For success case, we indeed may want to remove it.

> -
>  unmap:
>  	dma_unmap_single(dma_dev, dma_addr, seg->length, dir);
>  
> 


-- 
Damien Le Moal
Western Digital Research


From ilpo.jarvinen at linux.intel.com  Mon Dec  8 23:11:37 2025
From: ilpo.jarvinen at linux.intel.com (=?UTF-8?q?Ilpo=20J=C3=A4rvinen?=)
Date: Tue, 9 Dec 2025 09:11:37 +0200 (EET)
Subject: [PATCH v2] PCI: dwc: Make Link Up IRQ logic handle already
 powered on PCIe switches
In-Reply-To: <20251201063634.4115762-2-cassel@kernel.org>
References: <20251201063634.4115762-2-cassel@kernel.org>
Message-ID: <5cdf685c-5a37-1b65-3e87-9262f3ed7bd4@linux.intel.com>

On Mon, 1 Dec 2025, Niklas Cassel wrote:

> The DWC glue drivers always call pci_host_probe() during probe(), which
> will allocate upstream bridge resources and enumerate the bus.
> 
> For controllers without Link Up IRQ support, pci_host_probe() is called
> after dw_pcie_wait_for_link(), which will also wait the time required by
> the PCIe specification before performing PCI Configuration Space reads.
> 
> For controllers with Link Up IRQ support, the pci_host_probe() call (which
> will perform PCI Configuration Space reads) is done without any of the
> delays mandated by the PCIe specification.
> 
> For controllers with Link Up IRQ support, since the pci_host_probe() call
> is done without any delay (link training might still be ongoing), it is
> very unlikely that this scan will find any devices. Once the Link Up IRQ
> triggers, the Link Up IRQ handler will call pci_rescan_bus().
> 
> This works fine for PCIe endpoints connected to the Root Port, since they
> don't extend the bus. However, if the pci_rescan_bus() call detects a PCIe
> switch, then there will be a problem when the downstream busses starts
> showing up, because the PCIe controller is not hotplug capable, so we are
> not allowed to extend the subordinate bus number after the initial scan,
> resulting in error messages such as:
> 
> pci_bus 0004:43: busn_res: can not insert [bus 43-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci_bus 0004:43: busn_res: [bus 43-41] end is updated to 43
> pci_bus 0004:43: busn_res: can not insert [bus 43] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci 0004:42:00.0: devices behind bridge are unusable because [bus 43] cannot be assigned for them
> pci_bus 0004:44: busn_res: can not insert [bus 44-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci_bus 0004:44: busn_res: [bus 44-41] end is updated to 44
> pci_bus 0004:44: busn_res: can not insert [bus 44] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci 0004:42:02.0: devices behind bridge are unusable because [bus 44] cannot be assigned for them
> pci_bus 0004:45: busn_res: can not insert [bus 45-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci_bus 0004:45: busn_res: [bus 45-41] end is updated to 45
> pci_bus 0004:45: busn_res: can not insert [bus 45] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci 0004:42:06.0: devices behind bridge are unusable because [bus 45] cannot be assigned for them
> pci_bus 0004:46: busn_res: can not insert [bus 46-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci_bus 0004:46: busn_res: [bus 46-41] end is updated to 46
> pci_bus 0004:46: busn_res: can not insert [bus 46] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci 0004:42:0e.0: devices behind bridge are unusable because [bus 46] cannot be assigned for them
> pci_bus 0004:42: busn_res: [bus 42-41] end is updated to 46
> pci_bus 0004:42: busn_res: can not insert [bus 42-46] under [bus 41] (conflicts with (null) [bus 41])
> pci 0004:41:00.0: devices behind bridge are unusable because [bus 42-46] cannot be assigned for them
> pcieport 0004:40:00.0: bridge has subordinate 41 but max busn 46
> 
> While we would like to set the is_hotplug_bridge flag
> (quirk_hotplug_bridge()), many embedded SoCs that use the DWC controller
> have synthesized the controller without hot-plug support.
> Thus, the Link Up IRQ logic is only mimicking hot-plug functionality, i.e.
> it is not compliant with the PCI Hot-Plug Specification, so we cannot make
> use of the is_hotplug_bridge flag.
> 
> In order to let the Link Up IRQ logic handle PCIe switches that are already
> powered on (PCIe switches that not powered on already need to implement a
> pwrctrl driver), don't perform a pci_host_probe() call during probe()
> (which disregards the delays required by the PCIe specification).
> 
> Instead let the first Link Up IRQ call pci_host_probe(). Any follow up
> Link Up IRQ will call pci_rescan_bus().
> 
> The IRQ name in /proc/interrupts for the pcie-qcom driver is renamed in
> order to not dereference pp->bridge->bus before it has been assigned.
> 
> Fixes: ec9fd499b9c6 ("PCI: dw-rockchip: Don't wait for link since we can detect Link Up")
> Fixes: 0e0b45ab5d77 ("PCI: dw-rockchip: Enumerate endpoints based on dll_link_up IRQ")
> Reported-by: FUKAUMI Naoki <naoki at radxa.com>
> Closes: https://lore.kernel.org/linux-pci/1E8E4DB773970CB5+5a52c9e1-01b8-4872-99b7-021099f04031 at radxa.com/
> Signed-off-by: Niklas Cassel <cassel at kernel.org>

Hi Niklas,

Now this patch looks interesting (and managed to catch my attention 
despite being a controllers/ patch).

You're only talking about bus number allocations here but we did hit a 
similar problem with bridge window allocations where not enough 
information is available at the time of the initial scan + resource 
allocation (currently it is one of the issues that prevents fixing one 
resource overlap bug):

https://lore.kernel.org/linux-pci/8f9c9950-1612-6e2d-388a-ce69cf3aae1a at linux.intel.com/

(Please check also Mani's reply that relates to pwrctrl.)

So I definitely like the general direction this patch goes (though I'm a 
bit worried though if the downstream busses trickle in, the resource 
allocation problems will not be fully solved but maybe that fear is not 
warranted, I don't know).

-- 
 i.

> ---
> Changes since v1:
> -Rename the IRQ on pcie-qcom to not depend on pp->bridge->bus (Mani)
> -Make sure that ret is initialized in dw_pcie_host_init() error path (Dan)
> 
>  .../pci/controller/dwc/pcie-designware-host.c | 71 ++++++++++++++++---
>  drivers/pci/controller/dwc/pcie-designware.h  |  5 ++
>  drivers/pci/controller/dwc/pcie-dw-rockchip.c |  5 +-
>  drivers/pci/controller/dwc/pcie-qcom.c        |  9 +--
>  4 files changed, 71 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
> index e92513c5bda51..bed7b309f6d9e 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-host.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
> @@ -565,6 +565,59 @@ static int dw_pcie_host_get_resources(struct dw_pcie_rp *pp)
>  	return 0;
>  }
>  
> +static int dw_pcie_host_initial_scan(struct dw_pcie_rp *pp)
> +{
> +	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> +	struct pci_host_bridge *bridge = pp->bridge;
> +	int ret;
> +
> +	ret = pci_host_probe(bridge);
> +	if (ret)
> +		return ret;
> +
> +	if (pp->ops->post_init)
> +		pp->ops->post_init(pp);
> +
> +	dwc_pcie_debugfs_init(pci, DW_PCIE_RC_TYPE);
> +
> +	return 0;
> +}
> +
> +void dw_pcie_handle_link_up_irq(struct dw_pcie_rp *pp)
> +{
> +	if (!pp->initial_linkup_irq_done) {
> +		int ret;
> +
> +		ret = dw_pcie_host_initial_scan(pp);
> +		if (ret) {
> +			struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> +			struct device *dev = pci->dev;
> +
> +			dev_err(dev, "Initial scan from IRQ failed: %d\n", ret);
> +
> +			dw_pcie_stop_link(pci);
> +
> +			dw_pcie_edma_remove(pci);
> +
> +			if (pp->has_msi_ctrl)
> +				dw_pcie_free_msi(pp);
> +
> +			if (pp->ops->deinit)
> +				pp->ops->deinit(pp);
> +
> +			if (pp->cfg)
> +				pci_ecam_free(pp->cfg);
> +		} else {
> +			pp->initial_linkup_irq_done = true;
> +		}
> +	} else {
> +		/* Rescan the bus to enumerate endpoint devices */
> +		pci_lock_rescan_remove();
> +		pci_rescan_bus(pp->bridge->bus);
> +		pci_unlock_rescan_remove();
> +	}
> +}
> +
>  int dw_pcie_host_init(struct dw_pcie_rp *pp)
>  {
>  	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> @@ -669,18 +722,18 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp)
>  	 * If there is no Link Up IRQ, we should not bypass the delay
>  	 * because that would require users to manually rescan for devices.
>  	 */
> -	if (!pp->use_linkup_irq)
> +	if (!pp->use_linkup_irq) {
>  		/* Ignore errors, the link may come up later */
>  		dw_pcie_wait_for_link(pci);
>  
> -	ret = pci_host_probe(bridge);
> -	if (ret)
> -		goto err_stop_link;
> -
> -	if (pp->ops->post_init)
> -		pp->ops->post_init(pp);
> -
> -	dwc_pcie_debugfs_init(pci, DW_PCIE_RC_TYPE);
> +		/*
> +		 * For platforms with Link Up IRQ, initial scan will be done
> +		 * on first Link Up IRQ.
> +		 */
> +		ret = dw_pcie_host_initial_scan(pp);
> +		if (ret)
> +			goto err_stop_link;
> +	}
>  
>  	return 0;
>  
> diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> index e995f692a1ecd..a31bd93490dcd 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.h
> +++ b/drivers/pci/controller/dwc/pcie-designware.h
> @@ -427,6 +427,7 @@ struct dw_pcie_rp {
>  	int			msg_atu_index;
>  	struct resource		*msg_res;
>  	bool			use_linkup_irq;
> +	bool			initial_linkup_irq_done;
>  	struct pci_eq_presets	presets;
>  	struct pci_config_window *cfg;
>  	bool			ecam_enabled;
> @@ -807,6 +808,7 @@ void dw_pcie_msi_init(struct dw_pcie_rp *pp);
>  int dw_pcie_msi_host_init(struct dw_pcie_rp *pp);
>  void dw_pcie_free_msi(struct dw_pcie_rp *pp);
>  int dw_pcie_setup_rc(struct dw_pcie_rp *pp);
> +void dw_pcie_handle_link_up_irq(struct dw_pcie_rp *pp);
>  int dw_pcie_host_init(struct dw_pcie_rp *pp);
>  void dw_pcie_host_deinit(struct dw_pcie_rp *pp);
>  int dw_pcie_allocate_domains(struct dw_pcie_rp *pp);
> @@ -844,6 +846,9 @@ static inline int dw_pcie_setup_rc(struct dw_pcie_rp *pp)
>  	return 0;
>  }
>  
> +static inline void dw_pcie_handle_link_up_irq(struct dw_pcie_rp *pp)
> +{ }
> +
>  static inline int dw_pcie_host_init(struct dw_pcie_rp *pp)
>  {
>  	return 0;
> diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
> index 3e2752c7dd096..8f2cc1ef25e3d 100644
> --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c
> +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
> @@ -466,10 +466,7 @@ static irqreturn_t rockchip_pcie_rc_sys_irq_thread(int irq, void *arg)
>  		if (rockchip_pcie_link_up(pci)) {
>  			msleep(PCIE_RESET_CONFIG_WAIT_MS);
>  			dev_dbg(dev, "Received Link up event. Starting enumeration!\n");
> -			/* Rescan the bus to enumerate endpoint devices */
> -			pci_lock_rescan_remove();
> -			pci_rescan_bus(pp->bridge->bus);
> -			pci_unlock_rescan_remove();
> +			dw_pcie_handle_link_up_irq(pp);
>  		}
>  	}
>  
> diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
> index c48a20602d7fa..04f29cd8d8881 100644
> --- a/drivers/pci/controller/dwc/pcie-qcom.c
> +++ b/drivers/pci/controller/dwc/pcie-qcom.c
> @@ -1617,10 +1617,7 @@ static irqreturn_t qcom_pcie_global_irq_thread(int irq, void *data)
>  	if (FIELD_GET(PARF_INT_ALL_LINK_UP, status)) {
>  		msleep(PCIE_RESET_CONFIG_WAIT_MS);
>  		dev_dbg(dev, "Received Link up event. Starting enumeration!\n");
> -		/* Rescan the bus to enumerate endpoint devices */
> -		pci_lock_rescan_remove();
> -		pci_rescan_bus(pp->bridge->bus);
> -		pci_unlock_rescan_remove();
> +		dw_pcie_handle_link_up_irq(pp);
>  
>  		qcom_pcie_icc_opp_update(pcie);
>  	} else {
> @@ -1937,8 +1934,8 @@ static int qcom_pcie_probe(struct platform_device *pdev)
>  		goto err_phy_exit;
>  	}
>  
> -	name = devm_kasprintf(dev, GFP_KERNEL, "qcom_pcie_global_irq%d",
> -			      pci_domain_nr(pp->bridge->bus));
> +	name = devm_kasprintf(dev, GFP_KERNEL, "qcom_pcie_global_irq_%pOFP",
> +			      dev->of_node);
>  	if (!name) {
>  		ret = -ENOMEM;
>  		goto err_host_deinit;
> 


From cassel at kernel.org  Mon Dec  8 23:20:01 2025
From: cassel at kernel.org (Niklas Cassel)
Date: Tue, 9 Dec 2025 08:20:01 +0100
Subject: [PATCH 0/8] dmaengine: Add new API to combine onfiguration and
 descriptor preparation
In-Reply-To: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
References: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
Message-ID: <aTfNoU6fKBOcjL5j@ryzen>

On Mon, Dec 08, 2025 at 12:09:39PM -0500, Frank Li wrote:
> Frank Li (8):
>       dmaengine: Add API to combine configuration and preparation (sg and single)
>       PCI: endpoint: pci-epf-test: use new DMA API to simple code
>       dmaengine: dw-edma: Use new .device_prep_slave_sg_config() callback
>       dmaengine: dw-edma: Pass dma_slave_config to dw_edma_device_transfer()
>       nvmet: pci-epf: Remove unnecessary dmaengine_terminate_sync() on each DMA transfer
>       nvmet: pci-epf: Use dmaengine_prep_slave_single_config() API
>       PCI: epf-mhi:Using new API dmaengine_prep_slave_single_config() to simple code.
>       crypto: atmel: Use dmaengine_prep_slave_single_config() API
> 
>  drivers/crypto/atmel-aes.c                    | 10 ++---
>  drivers/dma/dw-edma/dw-edma-core.c            | 38 +++++++++++-----
>  drivers/nvme/target/pci-epf.c                 | 21 +++------
>  drivers/pci/endpoint/functions/pci-epf-mhi.c  | 52 +++++++---------------
>  drivers/pci/endpoint/functions/pci-epf-test.c |  8 +---
>  include/linux/dmaengine.h                     | 64 ++++++++++++++++++++++++---
>  6 files changed, 111 insertions(+), 82 deletions(-)
> ---
> base-commit: bc04acf4aeca588496124a6cf54bfce3db327039
> change-id: 20251204-dma_prep_config-654170d245a2

For the series (tested using drivers/nvme/target/pci-epf.c):
Tested-by: Niklas Cassel <cassel at kernel.org>

Mainline:
  Rnd read,    4KB,  QD=1, 1 job :  IOPS=5721, BW=22.3MiB/s (23.4MB/s)
  Rnd read,    4KB, QD=32, 1 job :  IOPS=51.8k, BW=202MiB/s (212MB/s)
  Rnd read,    4KB, QD=32, 4 jobs:  IOPS=109k, BW=426MiB/s (447MB/s)
  Rnd read,  128KB,  QD=1, 1 job :  IOPS=2678, BW=335MiB/s (351MB/s)
  Rnd read,  128KB, QD=32, 1 job :  IOPS=19.1k, BW=2388MiB/s (2504MB/s)
  Rnd read,  128KB, QD=32, 4 jobs:  IOPS=18.1k, BW=2258MiB/s (2368MB/s)
  Rnd read,  512KB,  QD=1, 1 job :  IOPS=1388, BW=694MiB/s (728MB/s)
  Rnd read,  512KB, QD=32, 1 job :  IOPS=4554, BW=2277MiB/s (2388MB/s)
  Rnd read,  512KB, QD=32, 4 jobs:  IOPS=4516, BW=2258MiB/s (2368MB/s)
  Rnd write,   4KB,  QD=1, 1 job :  IOPS=4679, BW=18.3MiB/s (19.2MB/s)
  Rnd write,   4KB, QD=32, 1 job :  IOPS=35.1k, BW=137MiB/s (144MB/s)
  Rnd write,   4KB, QD=32, 4 jobs:  IOPS=33.7k, BW=132MiB/s (138MB/s)
  Rnd write, 128KB,  QD=1, 1 job :  IOPS=2490, BW=311MiB/s (326MB/s)
  Rnd write, 128KB, QD=32, 1 job :  IOPS=4964, BW=621MiB/s (651MB/s)
  Rnd write, 128KB, QD=32, 4 jobs:  IOPS=4966, BW=621MiB/s (651MB/s)
  Seq read,  128KB,  QD=1, 1 job :  IOPS=2586, BW=323MiB/s (339MB/s)
  Seq read,  128KB, QD=32, 1 job :  IOPS=17.5k, BW=2190MiB/s (2296MB/s)
  Seq read,  512KB,  QD=1, 1 job :  IOPS=1614, BW=807MiB/s (847MB/s)
  Seq read,  512KB, QD=32, 1 job :  IOPS=4540, BW=2270MiB/s (2381MB/s)
  Seq read,    1MB, QD=32, 1 job :  IOPS=2283, BW=2284MiB/s (2395MB/s)
  Seq write, 128KB,  QD=1, 1 job :  IOPS=2313, BW=289MiB/s (303MB/s)
  Seq write, 128KB, QD=32, 1 job :  IOPS=4948, BW=619MiB/s (649MB/s)
  Seq write, 512KB,  QD=1, 1 job :  IOPS=901, BW=451MiB/s (473MB/s)
  Seq write, 512KB, QD=32, 1 job :  IOPS=1289, BW=645MiB/s (676MB/s)
  Seq write,   1MB, QD=32, 1 job :  IOPS=632, BW=633MiB/s (663MB/s)
  Rnd rdwr, 4K..1MB, QD=8, 4 jobs:  IOPS=1756, BW=880MiB/s (923MB/s)
 IOPS=1767, BW=886MiB/s (929MB/s)


Mainline + this series applied:
  Rnd read,    4KB,  QD=1, 1 job :  IOPS=3681, BW=14.4MiB/s (15.1MB/s)
  Rnd read,    4KB, QD=32, 1 job :  IOPS=54.8k, BW=214MiB/s (224MB/s)
  Rnd read,    4KB, QD=32, 4 jobs:  IOPS=123k, BW=479MiB/s (502MB/s)
  Rnd read,  128KB,  QD=1, 1 job :  IOPS=2132, BW=267MiB/s (280MB/s)
  Rnd read,  128KB, QD=32, 1 job :  IOPS=19.0k, BW=2369MiB/s (2485MB/s)
  Rnd read,  128KB, QD=32, 4 jobs:  IOPS=18.7k, BW=2341MiB/s (2454MB/s)
  Rnd read,  512KB,  QD=1, 1 job :  IOPS=1135, BW=568MiB/s (595MB/s)
  Rnd read,  512KB, QD=32, 1 job :  IOPS=4546, BW=2273MiB/s (2384MB/s)
  Rnd read,  512KB, QD=32, 4 jobs:  IOPS=4708, BW=2354MiB/s (2469MB/s)
  Rnd write,   4KB,  QD=1, 1 job :  IOPS=3369, BW=13.2MiB/s (13.8MB/s)
  Rnd write,   4KB, QD=32, 1 job :  IOPS=31.7k, BW=124MiB/s (130MB/s)
  Rnd write,   4KB, QD=32, 4 jobs:  IOPS=31.1k, BW=122MiB/s (127MB/s)
  Rnd write, 128KB,  QD=1, 1 job :  IOPS=1820, BW=228MiB/s (239MB/s)
  Rnd write, 128KB, QD=32, 1 job :  IOPS=5703, BW=713MiB/s (748MB/s)
  Rnd write, 128KB, QD=32, 4 jobs:  IOPS=5813, BW=727MiB/s (762MB/s)
  Seq read,  128KB,  QD=1, 1 job :  IOPS=1958, BW=245MiB/s (257MB/s)
  Seq read,  128KB, QD=32, 1 job :  IOPS=18.8k, BW=2345MiB/s (2459MB/s)
  Seq read,  512KB,  QD=1, 1 job :  IOPS=1319, BW=660MiB/s (692MB/s)
  Seq read,  512KB, QD=32, 1 job :  IOPS=4542, BW=2271MiB/s (2382MB/s)
  Seq read,    1MB, QD=32, 1 job :  IOPS=2325, BW=2325MiB/s (2438MB/s)
  Seq write, 128KB,  QD=1, 1 job :  IOPS=2174, BW=272MiB/s (285MB/s)
  Seq write, 128KB, QD=32, 1 job :  IOPS=5697, BW=712MiB/s (747MB/s)
  Seq write, 512KB,  QD=1, 1 job :  IOPS=1035, BW=518MiB/s (543MB/s)
  Seq write, 512KB, QD=32, 1 job :  IOPS=1462, BW=731MiB/s (767MB/s)
  Seq write,   1MB, QD=32, 1 job :  IOPS=720, BW=721MiB/s (756MB/s)
  Rnd rdwr, 4K..1MB, QD=8, 4 jobs:  IOPS=2029, BW=1018MiB/s (1067MB/s)
 IOPS=2037, BW=1023MiB/s (1072MB/s)


Small performance boost, but I think the nicest thing with this series is
to be able to remove the ugly mutex in pci-epf.c.


Kind regards,
Niklas


From cassel at kernel.org  Mon Dec  8 23:45:33 2025
From: cassel at kernel.org (Niklas Cassel)
Date: Tue, 9 Dec 2025 08:45:33 +0100
Subject: [PATCH v2] PCI: dwc: Make Link Up IRQ logic handle already
 powered on PCIe switches
In-Reply-To: <5cdf685c-5a37-1b65-3e87-9262f3ed7bd4@linux.intel.com>
References: <20251201063634.4115762-2-cassel@kernel.org>
 <5cdf685c-5a37-1b65-3e87-9262f3ed7bd4@linux.intel.com>
Message-ID: <aTfTnZfLDlt24ZKw@ryzen>

Hello Ilpo,

On Tue, Dec 09, 2025 at 09:11:37AM +0200, Ilpo J?rvinen wrote:
> 
> Now this patch looks interesting (and managed to catch my attention 
> despite being a controllers/ patch).
> 
> You're only talking about bus number allocations here but we did hit a 
> similar problem with bridge window allocations where not enough 
> information is available at the time of the initial scan + resource 
> allocation (currently it is one of the issues that prevents fixing one 
> resource overlap bug):
> 
> https://lore.kernel.org/linux-pci/8f9c9950-1612-6e2d-388a-ce69cf3aae1a at linux.intel.com/

I'm quite sure that Val's problem will be solved by applying:
https://lore.kernel.org/linux-pci/20251124-pci-pwrctrl-rework-v1-0-78a72627683d at oss.qualcomm.com/

If not, he could try applying the above series, and then this patch on top.


Kind regards,
Niklas



From dan.carpenter at linaro.org  Tue Dec  9 00:08:04 2025
From: dan.carpenter at linaro.org (Dan Carpenter)
Date: Tue, 9 Dec 2025 11:08:04 +0300
Subject: [PATCH v20 3/7] firmware: imx: add driver for NXP EdgeLock
 Enclave
In-Reply-To: <20251203-imx-se-if-v20-3-a04a25c4255f@nxp.com>
Message-ID: <202512091557.d5dOvFff-lkp@intel.com>

Hi Pankaj,

kernel test robot noticed the following build warnings:

url:    https://github.com/intel-lab-lkp/linux/commits/Pankaj-Gupta/Documentation-firmware-add-imx-se-to-other_interfaces/20251203-145202
base:   4a26e7032d7d57c998598c08a034872d6f0d3945
patch link:    https://lore.kernel.org/r/20251203-imx-se-if-v20-3-a04a25c4255f%40nxp.com
patch subject: [PATCH v20 3/7] firmware: imx: add driver for NXP EdgeLock Enclave
config: arm64-randconfig-r072-20251207 (https://download.01.org/0day-ci/archive/20251209/202512091557.d5dOvFff-lkp at intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project a805147ac1ba123916de182babb0831fbb148756)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Reported-by: Dan Carpenter <dan.carpenter at linaro.org>
| Closes: https://lore.kernel.org/r/202512091557.d5dOvFff-lkp at intel.com/

smatch warnings:
drivers/firmware/imx/ele_common.c:264 se_save_imem_state() warn: missing error code? 'ret'
drivers/firmware/imx/ele_common.c:302 se_restore_imem_state() warn: missing error code? 'ret'

vim +/ret +264 drivers/firmware/imx/ele_common.c

a9e23a74789346 Pankaj Gupta 2025-12-03  251  int se_save_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem)
a9e23a74789346 Pankaj Gupta 2025-12-03  252  {
a9e23a74789346 Pankaj Gupta 2025-12-03  253  	struct ele_dev_info s_info = {0};
a9e23a74789346 Pankaj Gupta 2025-12-03  254  	int ret;
a9e23a74789346 Pankaj Gupta 2025-12-03  255  
a9e23a74789346 Pankaj Gupta 2025-12-03  256  	ret = ele_get_info(priv, &s_info);
a9e23a74789346 Pankaj Gupta 2025-12-03  257  	if (ret) {
a9e23a74789346 Pankaj Gupta 2025-12-03  258  		dev_err(priv->dev, "Failed to get info from ELE.\n");
a9e23a74789346 Pankaj Gupta 2025-12-03  259  		return ret;
a9e23a74789346 Pankaj Gupta 2025-12-03  260  	}
a9e23a74789346 Pankaj Gupta 2025-12-03  261  
a9e23a74789346 Pankaj Gupta 2025-12-03  262  	/* Do not save the IMEM buffer, if the current IMEM state is BAD. */
a9e23a74789346 Pankaj Gupta 2025-12-03  263  	if (s_info.d_addn_info.imem_state == ELE_IMEM_STATE_BAD)
a9e23a74789346 Pankaj Gupta 2025-12-03 @264  		return ret;

This returns success if the state is _BAD.

a9e23a74789346 Pankaj Gupta 2025-12-03  265  
a9e23a74789346 Pankaj Gupta 2025-12-03  266  	/*
a9e23a74789346 Pankaj Gupta 2025-12-03  267  	 * EXPORT command will save encrypted IMEM to given address,
a9e23a74789346 Pankaj Gupta 2025-12-03  268  	 * so later in resume, IMEM can be restored from the given
a9e23a74789346 Pankaj Gupta 2025-12-03  269  	 * address.
a9e23a74789346 Pankaj Gupta 2025-12-03  270  	 *
a9e23a74789346 Pankaj Gupta 2025-12-03  271  	 * Size must be at least 64 kB.
a9e23a74789346 Pankaj Gupta 2025-12-03  272  	 */
a9e23a74789346 Pankaj Gupta 2025-12-03  273  	ret = ele_service_swap(priv, imem->phyaddr, ELE_IMEM_SIZE, ELE_IMEM_EXPORT);
a9e23a74789346 Pankaj Gupta 2025-12-03  274  	if (ret < 0) {
a9e23a74789346 Pankaj Gupta 2025-12-03  275  		dev_err(priv->dev, "Failed to export IMEM.");
a9e23a74789346 Pankaj Gupta 2025-12-03  276  		imem->size = 0;
a9e23a74789346 Pankaj Gupta 2025-12-03  277  	} else {
a9e23a74789346 Pankaj Gupta 2025-12-03  278  		dev_dbg(priv->dev,
a9e23a74789346 Pankaj Gupta 2025-12-03  279  			"Exported %d bytes of encrypted IMEM.",
a9e23a74789346 Pankaj Gupta 2025-12-03  280  			ret);
a9e23a74789346 Pankaj Gupta 2025-12-03  281  		imem->size = ret;
a9e23a74789346 Pankaj Gupta 2025-12-03  282  	}
a9e23a74789346 Pankaj Gupta 2025-12-03  283  
a9e23a74789346 Pankaj Gupta 2025-12-03  284  	return ret > 0 ? 0 : ret;
a9e23a74789346 Pankaj Gupta 2025-12-03  285  }
a9e23a74789346 Pankaj Gupta 2025-12-03  286  
a9e23a74789346 Pankaj Gupta 2025-12-03  287  int se_restore_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem)
a9e23a74789346 Pankaj Gupta 2025-12-03  288  {
a9e23a74789346 Pankaj Gupta 2025-12-03  289  	struct ele_dev_info s_info;
a9e23a74789346 Pankaj Gupta 2025-12-03  290  	int ret;
a9e23a74789346 Pankaj Gupta 2025-12-03  291  
a9e23a74789346 Pankaj Gupta 2025-12-03  292  	/* get info from ELE */
a9e23a74789346 Pankaj Gupta 2025-12-03  293  	ret = ele_get_info(priv, &s_info);
a9e23a74789346 Pankaj Gupta 2025-12-03  294  	if (ret) {
a9e23a74789346 Pankaj Gupta 2025-12-03  295  		dev_err(priv->dev, "Failed to get info from ELE.");
a9e23a74789346 Pankaj Gupta 2025-12-03  296  		return ret;
a9e23a74789346 Pankaj Gupta 2025-12-03  297  	}
a9e23a74789346 Pankaj Gupta 2025-12-03  298  	imem->state = s_info.d_addn_info.imem_state;
a9e23a74789346 Pankaj Gupta 2025-12-03  299  
a9e23a74789346 Pankaj Gupta 2025-12-03  300  	/* Get IMEM state, if 0xFE then import IMEM if imem size is non-zero. */

I really can't understand this comment at all.  :(

a9e23a74789346 Pankaj Gupta 2025-12-03  301  	if (s_info.d_addn_info.imem_state != ELE_IMEM_STATE_BAD || !imem->size)
a9e23a74789346 Pankaj Gupta 2025-12-03 @302  		return ret;

This feels like returning zero is intentional, but please return a
literal zero.  s/return ret;/return 0;/.


-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki



From yingchao.deng at oss.qualcomm.com  Tue Dec  9 00:16:28 2025
From: yingchao.deng at oss.qualcomm.com (Yingchao Deng)
Date: Tue,  9 Dec 2025 16:16:28 +0800
Subject: [PATCH v6 2/2] coresight: cti: Add Qualcomm extended CTI support
In-Reply-To: <CAJ9a7Vg9Efi-5eecfiUF82_Qq8Jg9imN5q1-VKYZoPVUxNpjhA@mail.gmail.com>
References: <CAJ9a7Vg9Efi-5eecfiUF82_Qq8Jg9imN5q1-VKYZoPVUxNpjhA@mail.gmail.com>
Message-ID: <20251209081649.105623-1-yingchao.deng@oss.qualcomm.com>

Hi Leo & Mike

Based on Leo???s suggestions, I created a new patch, but there are three points that do not fully align with his recommendations:

    1. The helper function for returning the register address now returns only the offset, because returning the full address would conflict with cti_write_single_reg.
    2. For registers such as triginstatus1...3, I defined additional macros CTITRIGINSTATUS1...3. This is because CTITRIGINSTATUS + 0x4 equals CTITRIGOUTSTATUS, and to avoid conflicts with existing macros, I chose numbers starting from 0x1000 for the new definitions.
    3. Regarding the visibility of attributes for triginstatus1...3, since coresight_cti_reg produces an anonymous variable that cannot be directly referenced, I used coresight_cti_regs_attrs[i] to obtain the attribute corresponding to triginstatus1.

I appreciate both suggestions. After reviewing them, I lean toward Mike's approach.

Signed-off-by: Yingchao Deng <yingchao.deng at oss.qualcomm.com>
---
 .../hwtracing/coresight/coresight-cti-core.c  |  52 +++++--
 .../hwtracing/coresight/coresight-cti-sysfs.c |  72 ++++++++--
 drivers/hwtracing/coresight/coresight-cti.h   |   3 +-
 drivers/hwtracing/coresight/qcom-cti.h        | 136 ++++++++++++++++++
 4 files changed, 238 insertions(+), 25 deletions(-)
 create mode 100644 drivers/hwtracing/coresight/qcom-cti.h

diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c
index f9970e40dd59..d2b0b46f2846 100644
--- a/drivers/hwtracing/coresight/coresight-cti-core.c
+++ b/drivers/hwtracing/coresight/coresight-cti-core.c
@@ -21,7 +21,7 @@

 #include "coresight-priv.h"
 #include "coresight-cti.h"
-
+#include "qcom-cti.h"
 /*
  * CTI devices can be associated with a PE, or be connected to CoreSight
  * hardware. We have a list of all CTIs irrespective of CPU bound or
@@ -70,15 +70,16 @@ void cti_write_all_hw_regs(struct cti_drvdata *drvdata)

     /* write the CTI trigger registers */
     for (i = 0; i < config->nr_trig_max; i++) {
-        writel_relaxed(config->ctiinen[i], drvdata->base + CTIINEN(i));
+        writel_relaxed(config->ctiinen[i],
+                drvdata->base + cti_reg_addr_with_nr(drvdata, CTIINEN(0), i));
         writel_relaxed(config->ctiouten[i],
-                   drvdata->base + CTIOUTEN(i));
+                drvdata->base + cti_reg_addr_with_nr(drvdata, CTIOUTEN(0), i));
     }

     /* other regs */
-    writel_relaxed(config->ctigate, drvdata->base + CTIGATE);
-    writel_relaxed(config->asicctl, drvdata->base + ASICCTL);
-    writel_relaxed(config->ctiappset, drvdata->base + CTIAPPSET);
+    writel_relaxed(config->ctigate, drvdata->base + cti_reg_addr(drvdata, CTIGATE));
+    writel_relaxed(config->asicctl, drvdata->base + cti_reg_addr(drvdata, ASICCTL));
+    writel_relaxed(config->ctiappset, drvdata->base + cti_reg_addr(drvdata, CTIAPPSET));

     /* re-enable CTI */
     writel_relaxed(1, drvdata->base + CTICONTROL);
@@ -201,7 +202,7 @@ void cti_write_intack(struct device *dev, u32 ackval)
     raw_spin_lock(&drvdata->spinlock);
     /* write if enabled */
     if (cti_active(config))
-        cti_write_single_reg(drvdata, CTIINTACK, ackval);
+        cti_write_single_reg(drvdata, cti_reg_addr(drvdata, CTIINTACK), ackval);
     raw_spin_unlock(&drvdata->spinlock);
 }

@@ -214,6 +215,9 @@ void cti_write_intack(struct device *dev, u32 ackval)
 /* DEVID[19:16] - number of CTM channels */
 #define CTI_DEVID_CTMCHANNELS(devid_val) ((int) BMVAL(devid_val, 16, 19))

+/* DEVARCH[31:21] - ARCHITECT */
+#define CTI_DEVARCH_ARCHITECT(devarch_val) ((int)BMVAL(devarch_val, 21, 31))
+
 static int cti_set_default_config(struct device *dev,
                   struct cti_drvdata *drvdata)
 {
@@ -394,9 +398,8 @@ int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,

     /* update the local register values */
     chan_bitmask = BIT(channel_idx);
-    reg_offset = (direction == CTI_TRIG_IN ? CTIINEN(trigger_idx) :
-              CTIOUTEN(trigger_idx));
-
+    reg_offset = (direction == CTI_TRIG_IN ? cti_reg_addr_with_nr(drvdata, CTIINEN(0), trigger_idx):
+                         cti_reg_addr_with_nr(drvdata, CTIOUTEN(0), trigger_idx));
     raw_spin_lock(&drvdata->spinlock);

     /* read - modify write - the trigger / channel enable value */
@@ -452,7 +455,7 @@ int cti_channel_gate_op(struct device *dev, enum cti_chan_gate_op op,
     if (err == 0) {
         config->ctigate = reg_value;
         if (cti_active(config))
-            cti_write_single_reg(drvdata, CTIGATE, reg_value);
+            cti_write_single_reg(drvdata, cti_reg_addr(drvdata, CTIGATE), reg_value);
     }
     raw_spin_unlock(&drvdata->spinlock);
     return err;
@@ -479,19 +482,19 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op,
     case CTI_CHAN_SET:
         config->ctiappset |= chan_bitmask;
         reg_value  = config->ctiappset;
-        reg_offset = CTIAPPSET;
+        reg_offset = cti_reg_addr(drvdata, CTIAPPSET);
         break;

     case CTI_CHAN_CLR:
         config->ctiappset &= ~chan_bitmask;
         reg_value = chan_bitmask;
-        reg_offset = CTIAPPCLEAR;
+        reg_offset = cti_reg_addr(drvdata, CTIAPPCLEAR);
         break;

     case CTI_CHAN_PULSE:
         config->ctiappset &= ~chan_bitmask;
         reg_value = chan_bitmask;
-        reg_offset = CTIAPPPULSE;
+        reg_offset = cti_reg_addr(drvdata, CTIAPPPULSE);
         break;

     default:
@@ -895,6 +898,7 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id)
     struct coresight_desc cti_desc;
     struct coresight_platform_data *pdata = NULL;
     struct resource *res = &adev->res;
+    u32 devarch;

     /* driver data*/
     drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
@@ -981,9 +985,27 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id)
     drvdata->csdev_release = drvdata->csdev->dev.release;
     drvdata->csdev->dev.release = cti_device_release;

+    /* check architect value*/
+    devarch = readl_relaxed(drvdata->base + CORESIGHT_DEVARCH);
+    if (CTI_DEVARCH_ARCHITECT(devarch) == ARCHITECT_QCOM) {
+        drvdata->is_qcom_cti = 1;
+
+        /*
+         * QCOM CTI does not implement Claimtag functionality as
+         * per CoreSight specification, but its CLAIMSET register
+         * is incorrectly initialized to 0xF. This can mislead
+         * tools or drivers into thinking the component is claimed.
+         *
+         * Reset CLAIMSET to 0 to reflect that no claims are active.
+         */
+        drvdata->csdev->claim_tag_info = CS_CLAIM_TAG_NOT_IMPL;
+        //writel_relaxed(0, drvdata->base + CORESIGHT_CLAIMSET);
+    }
+
     /* all done - dec pm refcount */
     pm_runtime_put(&adev->dev);
-    dev_info(&drvdata->csdev->dev, "CTI initialized\n");
+    dev_info(&drvdata->csdev->dev, "%s CTI initialized\n",
+                    drvdata->is_qcom_cti ? "QCOM" : "");
     return 0;

 pm_release:
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
index a9df77215141..5d23a138b4a7 100644
--- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
@@ -13,7 +13,7 @@
 #include <linux/sysfs.h>

 #include "coresight-cti.h"
-
+#include "qcom-cti.h"
 /*
  * Declare the number of static declared attribute groups
  * Value includes groups + NULL value at end of table.
@@ -183,7 +183,7 @@ static ssize_t coresight_cti_reg_show(struct device *dev,
     pm_runtime_get_sync(dev->parent);
     raw_spin_lock(&drvdata->spinlock);
     if (drvdata->config.hw_powered)
-        val = readl_relaxed(drvdata->base + cti_attr->off);
+        val = readl_relaxed(drvdata->base + cti_reg_addr(drvdata, cti_attr->off));
     raw_spin_unlock(&drvdata->spinlock);
     pm_runtime_put_sync(dev->parent);
     return sysfs_emit(buf, "0x%x\n", val);
@@ -204,7 +204,7 @@ static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,
     pm_runtime_get_sync(dev->parent);
     raw_spin_lock(&drvdata->spinlock);
     if (drvdata->config.hw_powered)
-        cti_write_single_reg(drvdata, cti_attr->off, val);
+        cti_write_single_reg(drvdata,  cti_reg_addr(drvdata, cti_attr->off), val);
     raw_spin_unlock(&drvdata->spinlock);
     pm_runtime_put_sync(dev->parent);
     return size;
@@ -267,7 +267,7 @@ static ssize_t cti_reg32_show(struct device *dev, char *buf,
     raw_spin_lock(&drvdata->spinlock);
     if ((reg_offset >= 0) && cti_active(config)) {
         CS_UNLOCK(drvdata->base);
-        val = readl_relaxed(drvdata->base + reg_offset);
+        val = readl_relaxed(drvdata->base + cti_reg_addr(drvdata, reg_offset));
         if (pcached_val)
             *pcached_val = val;
         CS_LOCK(drvdata->base);
@@ -300,7 +300,7 @@ static ssize_t cti_reg32_store(struct device *dev, const char *buf,

     /* write through if offset and enabled */
     if ((reg_offset >= 0) && cti_active(config))
-        cti_write_single_reg(drvdata, reg_offset, val);
+        cti_write_single_reg(drvdata,  cti_reg_addr(drvdata, reg_offset), val);
     raw_spin_unlock(&drvdata->spinlock);
     return size;
 }
@@ -389,7 +389,7 @@ static ssize_t inen_store(struct device *dev,

     /* write through if enabled */
     if (cti_active(config))
-        cti_write_single_reg(drvdata, CTIINEN(index), val);
+        cti_write_single_reg(drvdata, cti_reg_addr_with_nr(drvdata, CTIINEN(0), index), val);
     raw_spin_unlock(&drvdata->spinlock);
     return size;
 }
@@ -428,7 +428,7 @@ static ssize_t outen_store(struct device *dev,

     /* write through if enabled */
     if (cti_active(config))
-        cti_write_single_reg(drvdata, CTIOUTEN(index), val);
+        cti_write_single_reg(drvdata, cti_reg_addr_with_nr(drvdata, CTIOUTEN(0), index), val);
     raw_spin_unlock(&drvdata->spinlock);
     return size;
 }
@@ -470,7 +470,7 @@ static ssize_t appclear_store(struct device *dev,

     /* write through if enabled */
     if (cti_active(config))
-        cti_write_single_reg(drvdata, CTIAPPCLEAR, val);
+        cti_write_single_reg(drvdata,  cti_reg_addr(drvdata, CTIAPPCLEAR), val);
     raw_spin_unlock(&drvdata->spinlock);
     return size;
 }
@@ -491,7 +491,7 @@ static ssize_t apppulse_store(struct device *dev,

     /* write through if enabled */
     if (cti_active(config))
-        cti_write_single_reg(drvdata, CTIAPPPULSE, val);
+        cti_write_single_reg(drvdata,  cti_reg_addr(drvdata, CTIAPPPULSE), val);
     raw_spin_unlock(&drvdata->spinlock);
     return size;
 }
@@ -513,18 +513,36 @@ static struct attribute *coresight_cti_regs_attrs[] = {
     &dev_attr_appclear.attr,
     &dev_attr_apppulse.attr,
     coresight_cti_reg(triginstatus, CTITRIGINSTATUS),
+    coresight_cti_reg(triginstatus1, CTITRIGINSTATUS1),
+    coresight_cti_reg(triginstatus2, CTITRIGINSTATUS2),
+    coresight_cti_reg(triginstatus3, CTITRIGINSTATUS3),
     coresight_cti_reg(trigoutstatus, CTITRIGOUTSTATUS),
+    coresight_cti_reg(trigoutstatus1, CTITRIGOUTSTATUS1),
+    coresight_cti_reg(trigoutstatus2, CTITRIGOUTSTATUS2),
+    coresight_cti_reg(trigoutstatus3, CTITRIGOUTSTATUS3),
     coresight_cti_reg(chinstatus, CTICHINSTATUS),
     coresight_cti_reg(choutstatus, CTICHOUTSTATUS),
 #ifdef CONFIG_CORESIGHT_CTI_INTEGRATION_REGS
     coresight_cti_reg_rw(itctrl, CORESIGHT_ITCTRL),
     coresight_cti_reg(ittrigin, ITTRIGIN),
+    coresight_cti_reg(ittrigin1, ITTRIGIN1),
+    coresight_cti_reg(ittrigin2, ITTRIGIN2),
+    coresight_cti_reg(ittrigin3, ITTRIGIN3),
     coresight_cti_reg(itchin, ITCHIN),
     coresight_cti_reg_rw(ittrigout, ITTRIGOUT),
+    coresight_cti_reg_rw(ittrigout1, ITTRIGOUT1),
+    coresight_cti_reg_rw(ittrigout2, ITTRIGOUT2),
+    coresight_cti_reg_rw(ittrigout3, ITTRIGOUT3),
     coresight_cti_reg_rw(itchout, ITCHOUT),
     coresight_cti_reg(itchoutack, ITCHOUTACK),
     coresight_cti_reg(ittrigoutack, ITTRIGOUTACK),
+    coresight_cti_reg(ittrigoutack1, ITTRIGOUTACK1),
+    coresight_cti_reg(ittrigoutack2, ITTRIGOUTACK2),
+    coresight_cti_reg(ittrigoutack3, ITTRIGOUTACK3),
     coresight_cti_reg_wo(ittriginack, ITTRIGINACK),
+    coresight_cti_reg_wo(ittriginack1, ITTRIGINACK1),
+    coresight_cti_reg_wo(ittriginack2, ITTRIGINACK2),
+    coresight_cti_reg_wo(ittriginack3, ITTRIGINACK3),
     coresight_cti_reg_wo(itchinack, ITCHINACK),
 #endif
     NULL,
@@ -1153,6 +1171,41 @@ int cti_create_cons_sysfs(struct device *dev, struct cti_drvdata *drvdata)
     return err;
 }

+  static umode_t coresight_cti_regs_is_visible(struct kobject *kobj,
+                  struct attribute *attr, int n)
+  {
+    struct device *dev = container_of(kobj, struct device, kobj);
+    struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+    /* Mute QCOM CTI registers for standard CTI module */
+    if (!drvdata->is_qcom_cti) {
+        if (attr == coresight_cti_regs_attrs[10]
+         || attr == coresight_cti_regs_attrs[11]
+         || attr == coresight_cti_regs_attrs[12]
+         || attr == coresight_cti_regs_attrs[14]
+         || attr == coresight_cti_regs_attrs[15]
+         || attr == coresight_cti_regs_attrs[16]
+#ifdef CONFIG_CORESIGHT_CTI_INTEGRATION_REGS
+         || attr == coresight_cti_regs_attrs[21]
+         || attr == coresight_cti_regs_attrs[22]
+         || attr == coresight_cti_regs_attrs[23]
+         || attr == coresight_cti_regs_attrs[26]
+         || attr == coresight_cti_regs_attrs[27]
+         || attr == coresight_cti_regs_attrs[28]
+         || attr == coresight_cti_regs_attrs[32]
+         || attr == coresight_cti_regs_attrs[33]
+         || attr == coresight_cti_regs_attrs[34]
+         || attr == coresight_cti_regs_attrs[36]
+         || attr == coresight_cti_regs_attrs[37]
+         || attr == coresight_cti_regs_attrs[38]
+#endif
+         )
+                  return 0;
+          }
+
+          return attr->mode;
+  }
+
 /* attribute and group sysfs tables. */
 static const struct attribute_group coresight_cti_group = {
     .attrs = coresight_cti_attrs,
@@ -1166,6 +1219,7 @@ static const struct attribute_group coresight_cti_mgmt_group = {
 static const struct attribute_group coresight_cti_regs_group = {
     .attrs = coresight_cti_regs_attrs,
     .name = "regs",
+    .is_visible = coresight_cti_regs_is_visible,
 };

 static const struct attribute_group coresight_cti_channels_group = {
diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h
index e7b88b07cffe..413d5ef483e8 100644
--- a/drivers/hwtracing/coresight/coresight-cti.h
+++ b/drivers/hwtracing/coresight/coresight-cti.h
@@ -57,7 +57,7 @@ struct fwnode_handle;
  * Max of in and out defined in the DEVID register.
  * - pick up actual number used from .dts parameters if present.
  */
-#define CTIINOUTEN_MAX        32
+#define CTIINOUTEN_MAX        128

 /**
  * Group of related trigger signals
@@ -181,6 +181,7 @@ struct cti_drvdata {
     struct cti_config config;
     struct list_head node;
     void (*csdev_release)(struct device *dev);
+    bool is_qcom_cti;
 };

 /*
diff --git a/drivers/hwtracing/coresight/qcom-cti.h b/drivers/hwtracing/coresight/qcom-cti.h
new file mode 100644
index 000000000000..aa41f9425b36
--- /dev/null
+++ b/drivers/hwtracing/coresight/qcom-cti.h
@@ -0,0 +1,136 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+#include "coresight-cti.h"
+
+#define ARCHITECT_QCOM 0x477
+
+#define CTITRIGINSTATUS1 0x1000
+#define CTITRIGINSTATUS2 0x1001
+#define CTITRIGINSTATUS3 0x1002
+
+#define CTITRIGOUTSTATUS1 0x1003
+#define CTITRIGOUTSTATUS2 0x1004
+#define CTITRIGOUTSTATUS3 0x1005
+
+#define ITTRIGIN1 0x1006
+#define ITTRIGIN2 0x1007
+#define ITTRIGIN3 0x1008
+
+#define ITTRIGOUT1 0x1009
+#define ITTRIGOUT2 0x100A
+#define ITTRIGOUT3 0x100B
+
+#define ITTRIGINACK1 0x100C
+#define ITTRIGINACK2 0x100D
+#define ITTRIGINACK3 0x100E
+
+#define ITTRIGOUTACK1 0x100F
+#define ITTRIGOUTACK2 0x1010
+#define ITTRIGOUTACK3 0x1011
+/* CTI programming registers */
+#define    QCOM_CTIINTACK        0x020
+#define    QCOM_CTIAPPSET        0x004
+#define    QCOM_CTIAPPCLEAR    0x008
+#define    QCOM_CTIAPPPULSE    0x00C
+#define    QCOM_CTIINEN        0x400
+#define    QCOM_CTIOUTEN        0x800
+#define    QCOM_CTITRIGINSTATUS    0x040
+#define    QCOM_CTITRIGINSTATUS1    0x044
+#define    QCOM_CTITRIGINSTATUS2    0x048
+#define    QCOM_CTITRIGINSTATUS3    0x04C
+#define    QCOM_CTITRIGOUTSTATUS    0x060
+#define    QCOM_CTITRIGOUTSTATUS1    0x064
+#define    QCOM_CTITRIGOUTSTATUS2    0x068
+#define    QCOM_CTITRIGOUTSTATUS3    0x06C
+#define    QCOM_CTICHINSTATUS    0x080
+#define    QCOM_CTICHOUTSTATUS    0x084
+#define    QCOM_CTIGATE        0x088
+#define    QCOM_ASICCTL        0x08c
+/* Integration test registers */
+#define    QCOM_ITCHINACK        0xE70
+#define    QCOM_ITTRIGINACK    0xE80
+#define    QCOM_ITTRIGINACK1    0xE84
+#define    QCOM_ITTRIGINACK2    0xE88
+#define    QCOM_ITTRIGINACK3    0xE8C
+#define    QCOM_ITCHOUT        0xE74
+#define    QCOM_ITTRIGOUT        0xEA0
+#define    QCOM_ITTRIGOUT1        0xEA4
+#define    QCOM_ITTRIGOUT2        0xEA8
+#define    QCOM_ITTRIGOUT3        0xEAC
+#define    QCOM_ITCHOUTACK        0xE78
+#define    QCOM_ITTRIGOUTACK    0xEC0
+#define    QCOM_ITTRIGOUTACK1    0xEC4
+#define    QCOM_ITTRIGOUTACK2    0xEC8
+#define    QCOM_ITTRIGOUTACK3    0xECC
+#define    QCOM_ITCHIN        0xE7C
+#define    QCOM_ITTRIGIN        0xEE0
+#define    QCOM_ITTRIGIN1        0xEE4
+#define    QCOM_ITTRIGIN2        0xEE8
+#define    QCOM_ITTRIGIN3        0xEEC
+
+static noinline u32 cti_qcom_reg_off(u32 offset)
+{
+    switch (offset) {
+        case CTIINTACK:        return QCOM_CTIINTACK;
+        case CTIAPPSET:        return QCOM_CTIAPPSET;
+        case CTIAPPCLEAR:    return QCOM_CTIAPPCLEAR;
+        case CTIAPPPULSE:    return QCOM_CTIAPPPULSE;
+        case CTIINEN(0):    return QCOM_CTIINEN;
+        case CTIOUTEN(0):    return QCOM_CTIOUTEN;
+        case CTITRIGINSTATUS:    return QCOM_CTITRIGINSTATUS;
+        case CTITRIGINSTATUS1:    return QCOM_CTITRIGINSTATUS1;
+        case CTITRIGINSTATUS2:    return QCOM_CTITRIGINSTATUS2;
+        case CTITRIGINSTATUS3:    return QCOM_CTITRIGINSTATUS3;
+        case CTITRIGOUTSTATUS:    return QCOM_CTITRIGOUTSTATUS;
+        case CTITRIGOUTSTATUS1:    return QCOM_CTITRIGOUTSTATUS1;
+        case CTITRIGOUTSTATUS2:    return QCOM_CTITRIGOUTSTATUS2;
+        case CTITRIGOUTSTATUS3:    return QCOM_CTITRIGOUTSTATUS3;
+        case CTICHINSTATUS:        return QCOM_CTICHINSTATUS;
+        case CTICHOUTSTATUS:    return QCOM_CTICHOUTSTATUS;
+        case CTIGATE:        return QCOM_CTIGATE;
+        case ASICCTL:        return QCOM_ASICCTL;
+        case ITCHINACK:        return QCOM_ITCHINACK;
+        case ITTRIGINACK:    return QCOM_ITTRIGINACK;
+        case ITTRIGINACK1:    return QCOM_ITTRIGINACK1;
+        case ITTRIGINACK2:    return QCOM_ITTRIGINACK2;
+        case ITTRIGINACK3:    return QCOM_ITTRIGINACK3;
+        case ITCHOUT:        return QCOM_ITCHOUT;
+        case ITTRIGOUT:        return QCOM_ITTRIGOUT;
+        case ITTRIGOUT1:    return QCOM_ITTRIGOUT1;
+        case ITTRIGOUT2:    return QCOM_ITTRIGOUT2;
+        case ITTRIGOUT3:    return QCOM_ITTRIGOUT3;
+        case ITCHOUTACK:    return QCOM_ITCHOUTACK;
+        case ITTRIGOUTACK:    return QCOM_ITTRIGOUTACK;
+        case ITTRIGOUTACK1:    return QCOM_ITTRIGOUTACK1;
+        case ITTRIGOUTACK2:    return QCOM_ITTRIGOUTACK2;
+        case ITTRIGOUTACK3:    return QCOM_ITTRIGOUTACK3;
+        case ITCHIN:               return QCOM_ITCHIN;
+        case ITTRIGIN:            return QCOM_ITTRIGIN;
+        case ITTRIGIN1:        return QCOM_ITTRIGIN1;
+        case ITTRIGIN2:        return QCOM_ITTRIGIN2;
+        case ITTRIGIN3:        return QCOM_ITTRIGIN3;
+        default:
+                    WARN(1, "Unknown offset=%u\n", offset);
+                    return 0;
+    }
+
+    return 0;
+}
+
+static u32 cti_reg_addr_with_nr(struct cti_drvdata *drvdata,
+                                          u32 reg, u32 nr)
+{
+    /* convert to qcom specific offset */
+    if (unlikely(drvdata->is_qcom_cti))
+        reg = cti_qcom_reg_off(reg);
+
+    return reg + sizeof(u32) * nr;
+}
+
+static u32 cti_reg_addr(struct cti_drvdata *drvdata, u32 reg)
+{
+        return cti_reg_addr_with_nr(drvdata, reg, 0);
+}
+



From vulab at iscas.ac.cn  Tue Dec  9 00:19:09 2025
From: vulab at iscas.ac.cn (Wentao Liang)
Date: Tue,  9 Dec 2025 08:19:09 +0000
Subject: [PATCH v2] pmdomain: imx: Fix reference count leak in imx_gpc_probe()
Message-ID: <20251209081909.24982-1-vulab@iscas.ac.cn>

of_get_child_by_name() returns a node pointer with refcount incremented,
we should use the __free() attribute to manage the pgc_node reference.
This ensures automatic of_node_put() cleanup when pgc_node goes out of
scope, eliminating the need for explicit error handling paths and
avoiding reference count leaks.

Fixes: 721cabf6c660 ("soc: imx: move PGC handling to a new GPC driver")
Cc: stable at vger.kernel.org
Signed-off-by: Wentao Liang <vulab at iscas.ac.cn>

---
Change in V2:
- Use __free() attribute instead of explicit of_node_put() calls
---
 drivers/pmdomain/imx/gpc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/pmdomain/imx/gpc.c b/drivers/pmdomain/imx/gpc.c
index f18c7e6e75dd..89d5d68c055d 100644
--- a/drivers/pmdomain/imx/gpc.c
+++ b/drivers/pmdomain/imx/gpc.c
@@ -403,7 +403,7 @@ static int imx_gpc_old_dt_init(struct device *dev, struct regmap *regmap,
 static int imx_gpc_probe(struct platform_device *pdev)
 {
 	const struct imx_gpc_dt_data *of_id_data = device_get_match_data(&pdev->dev);
-	struct device_node *pgc_node;
+	struct device_node *pgc_node __free(pgc_node);
 	struct regmap *regmap;
 	void __iomem *base;
 	int ret;
-- 
2.34.1



From quic_nihalkum at quicinc.com  Tue Dec  9 00:27:25 2025
From: quic_nihalkum at quicinc.com (Nihal Kumar Gupta)
Date: Tue, 9 Dec 2025 13:57:25 +0530
Subject: [PATCH v6 2/3] arm64: dts: qcom: qcs8300: Add CCI definitions
In-Reply-To: <6e6ecdbf-f3cb-4d7e-a679-4640d6603ac8@oss.qualcomm.com>
References: <DS0PR02MB11311CE33DFFE0739BE747590E3D8A@DS0PR02MB11311.namprd02.prod.outlook.com>
 <d49920eb-0b4e-4042-b0c6-28d1ba348ddc@quicinc.com>
 <3f1dbf91-f967-44dc-bb21-25fdcbbc8db2@quicinc.com>
 <6e6ecdbf-f3cb-4d7e-a679-4640d6603ac8@oss.qualcomm.com>
Message-ID: <66d4d882-7cb3-4c8b-ba5d-42d6d83b0b59@quicinc.com>



On 05-12-2025 17:28, Konrad Dybcio wrote:
>> In monaco-evk.dts (Board level):
>> &tlmm {
>>     cam0_avdd_2v8_en_default: cam0-avdd-2v8-en-state {
>>         pins = "gpio73";
>>         function = "gpio";
>>         drive-strength = <2>;
>>         bias-disable;
>>     };
> That was my entire points, thanks

ACK. I will proceed with the example snippet.

As Vladimir suggested, the MCLK pad functions in this commit are unrelated to CCI, so I will split them into a separate commit.
GPIOs for enabling regulators are board-specific and will be moved to the EVK .dts in another commit.
Let me know if you see any ambiguity.

-- 
Regards,
Nihal Kumar Gupta



From francesco at dolcini.it  Tue Dec  9 00:41:25 2025
From: francesco at dolcini.it (Francesco Dolcini)
Date: Tue,  9 Dec 2025 09:41:25 +0100
Subject: [PATCH v1] arm64: dts: ti: am62p-verdin: Fix SD regulator startup delay
Message-ID: <20251209084126.33282-1-francesco@dolcini.it>

From: Francesco Dolcini <francesco.dolcini at toradex.com>

The power switch used to power the SD card interface might have
more than 2ms turn-on time, increase the startup delay to 20ms to
prevent failures.

Fixes: 87f95ea316ac ("arm64: dts: ti: Add Toradex Verdin AM62P")
Cc: stable at vger.kernel.org
Signed-off-by: Francesco Dolcini <francesco.dolcini at toradex.com>
---
 arch/arm64/boot/dts/ti/k3-am62p-verdin.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/ti/k3-am62p-verdin.dtsi b/arch/arm64/boot/dts/ti/k3-am62p-verdin.dtsi
index 5e050cbb9eaf..ec9dd931fe92 100644
--- a/arch/arm64/boot/dts/ti/k3-am62p-verdin.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am62p-verdin.dtsi
@@ -112,7 +112,7 @@ reg_sd1_vmmc: regulator-sdhci1-vmmc {
 		regulator-max-microvolt = <3300000>;
 		regulator-min-microvolt = <3300000>;
 		regulator-name = "+V3.3_SD";
-		startup-delay-us = <2000>;
+		startup-delay-us = <20000>;
 	};
 
 	reg_sd1_vqmmc: regulator-sdhci1-vqmmc {
-- 
2.47.3



From linux at armlinux.org.uk  Tue Dec  9 00:43:19 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Tue, 9 Dec 2025 08:43:19 +0000
Subject: [PATCH 1/3] ARM: allow __do_kernel_fault() to report execution
 of memory faults
In-Reply-To: <20251209040223.25069-1-xieyuanbin1@huawei.com>
References: <E1vSaS6-00000000Ni7-1FDb@rmk-PC.armlinux.org.uk>
 <20251209040223.25069-1-xieyuanbin1@huawei.com>
Message-ID: <aTfhJ1yN5fB3T-De@shell.armlinux.org.uk>

On Tue, Dec 09, 2025 at 12:02:23PM +0800, Xie Yuanbin wrote:
> On Mon, 08 Dec 2025 12:34:54 +0000, Russell King wrote:
> > diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
> > index 2bc828a1940c..f0884bf91dfa 100644
> > --- a/arch/arm/mm/fault.c
> > +++ b/arch/arm/mm/fault.c
> > @@ -162,6 +162,8 @@ __do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
> >  	 */
> >  	if (addr < PAGE_SIZE) {
> >  		msg = "NULL pointer dereference";
> > +	} else if (is_permission_fault(fsr) && fsr & FSR_LNX_PF) {
> > +		msg = "execution of memory";
> >  	} else {
> >  		if (is_translation_fault(fsr) &&
> >  		    kfence_handle_page_fault(addr, is_write_fault(fsr), regs))
> 
> This patch caused a compilation error, is_permission_fault() is not
> defined. Fixed with:

Thanks - as you've guessed I have some other patches on top of this
which move the is_xxx_fault() into fault.h.

However, for the sake of this series, my preferred fix is to group
all the is_xxx_fault() inline functions together as the first patch
of this series:

8<===
From: "Russell King (Oracle)" <rmk+kernel at armlinux.org.uk>
Subject: [PATCH] ARM: group is_permission_fault() with is_translation_fault()

Group is_permission_fault() with is_translation_fault(), which is
needed to use is_permission_fault() in __do_kernel_fault(). As
this is static inline, there is no need for this to be under
CONFIG_MMU.

Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
---
 arch/arm/mm/fault.c | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 2bc828a1940c..f87f353e5a8b 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -128,6 +128,19 @@ static inline bool is_translation_fault(unsigned int fsr)
 	return false;
 }
 
+static inline bool is_permission_fault(unsigned int fsr)
+{
+	int fs = fsr_fs(fsr);
+#ifdef CONFIG_ARM_LPAE
+	if ((fs & FS_MMU_NOLL_MASK) == FS_PERM_NOLL)
+		return true;
+#else
+	if (fs == FS_L1_PERM || fs == FS_L2_PERM)
+		return true;
+#endif
+	return false;
+}
+
 static void die_kernel_fault(const char *msg, struct mm_struct *mm,
 			     unsigned long addr, unsigned int fsr,
 			     struct pt_regs *regs)
@@ -225,19 +238,6 @@ void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 }
 
 #ifdef CONFIG_MMU
-static inline bool is_permission_fault(unsigned int fsr)
-{
-	int fs = fsr_fs(fsr);
-#ifdef CONFIG_ARM_LPAE
-	if ((fs & FS_MMU_NOLL_MASK) == FS_PERM_NOLL)
-		return true;
-#else
-	if (fs == FS_L1_PERM || fs == FS_L2_PERM)
-		return true;
-#endif
-	return false;
-}
-
 #ifdef CONFIG_CPU_TTBR0_PAN
 static inline bool ttbr0_usermode_access_allowed(struct pt_regs *regs)
 {
-- 
2.47.3

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From amelie.delaunay at foss.st.com  Tue Dec  9 00:52:41 2025
From: amelie.delaunay at foss.st.com (Amelie Delaunay)
Date: Tue, 9 Dec 2025 09:52:41 +0100
Subject: [Linux-stm32] [PATCH] phy: stm32-usphyc: Fix off by one in
 probe()
In-Reply-To: <aTfHcMJK1wFVnvEe@stanley.mountain>
References: <aTfHcMJK1wFVnvEe@stanley.mountain>
Message-ID: <274037fa-b881-49bb-9e93-c83fefb80438@foss.st.com>


On 12/9/25 07:53, Dan Carpenter wrote:
> The "index" variable is used as an index into the usbphyc->phys[] array
> which has usbphyc->nphys elements.  So if it is equal to usbphyc->nphys
> then it is one element out of bounds.  The "index" comes from the
> device tree so it's data that we trust and it's unlikely to be wrong,
> however it's obviously still worth fixing the bug.  Change the > to >=.
> 
> Fixes: 94c358da3a05 ("phy: stm32: add support for STM32 USB PHY Controller (USBPHYC)")
> Signed-off-by: Dan Carpenter <dan.carpenter at linaro.org>

Hi Dan, thanks for your patch.

Reviewed-by: Amelie Delaunay <amelie.delaunay at foss.st.com>

> ---
>   drivers/phy/st/phy-stm32-usbphyc.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/phy/st/phy-stm32-usbphyc.c b/drivers/phy/st/phy-stm32-usbphyc.c
> index 27fe92f73f33..b44afbff8616 100644
> --- a/drivers/phy/st/phy-stm32-usbphyc.c
> +++ b/drivers/phy/st/phy-stm32-usbphyc.c
> @@ -712,7 +712,7 @@ static int stm32_usbphyc_probe(struct platform_device *pdev)
>   		}
>   
>   		ret = of_property_read_u32(child, "reg", &index);
> -		if (ret || index > usbphyc->nphys) {
> +		if (ret || index >= usbphyc->nphys) {
>   			dev_err(&phy->dev, "invalid reg property: %d\n", ret);
>   			if (!ret)
>   				ret = -EINVAL;



From xieyuanbin1 at huawei.com  Tue Dec  9 00:56:27 2025
From: xieyuanbin1 at huawei.com (Xie Yuanbin)
Date: Tue, 9 Dec 2025 16:56:27 +0800
Subject: [PATCH 0/3] ARM: fix hash_name() and branch predictor issues
In-Reply-To: <aTcBHKFDBkSEp5mi@shell.armlinux.org.uk>
References: <aTcBHKFDBkSEp5mi@shell.armlinux.org.uk>
Message-ID: <20251209085627.64057-1-xieyuanbin1@huawei.com>

Hi, Russell!

TL; DR:
patch1 and patch2 with compilation error fixed:

Tested-by: Xie Yuanbin <xieyuanbin1 at huawei.com>

patch3:
The simple test case passed, but the syzkaller test (the original
scenario that triggered the branch predictor issue) is still running.
The syzkaller test is better to run for a day.

All patches with compilation error fixed:

Reviewed-by: Xie Yuanbin <xieyuanbin1 at huawei.com>


Detailed Description:

On Tue, 9 Dec 2025 10:52:16 +0800, Xie Yuanbin wrote:
> On Mon, 8 Dec 2025 16:47:24 +0000, Russell King wrote:
>> Also, would you mind giving ASAP some tested-by/reviewed-by for these
>> patches so they can be pushed out to linux-next for a bit of testing
>> there pelase? I'm on vacation from Thursday, so time is very short
>> to get these out - if we're not ready by Wednesday, then it'll be the
>> new year, possibly after the 11th January, before I can do anything
>> further (medical stuff.)
>>
>> Thanks.
>
> As mentioned in the previous email, this(these patches) should be the
> best solution, I think. And I have carefully read the three patches, so:
>
> Reviewed-by: Xie Yuanbin <xieyuanbin1 at huawei.com>
>
> As for testing, I can perform some simple tests myself, and I am trying
> to let the testing team to help with some further testing, like
> syzkaller.

Your first patch caused a compilation error: is_permission_fault() is not
defined. I fixed it with this patch:
```patch
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 2bc828a1940c..7082ba87e886 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -143,6 +143,21 @@ static void die_kernel_fault(const char *msg, struct mm_struct *mm,
 	make_task_dead(SIGKILL);
 }

+static inline bool is_permission_fault(unsigned int fsr)
+{
+#ifdef CONFIG_MMU
+	int fs = fsr_fs(fsr);
+#ifdef CONFIG_ARM_LPAE
+	if ((fs & FS_MMU_NOLL_MASK) == FS_PERM_NOLL)
+		return true;
+#else
+	if (fs == FS_L1_PERM || fs == FS_L2_PERM)
+		return true;
+#endif
+#endif
+	return false;
+}
+
 /*
  * Oops.  The kernel tried to access some page that wasn't present.
  */
@@ -225,19 +240,6 @@ void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 }

 #ifdef CONFIG_MMU
-static inline bool is_permission_fault(unsigned int fsr)
-{
-	int fs = fsr_fs(fsr);
-#ifdef CONFIG_ARM_LPAE
-	if ((fs & FS_MMU_NOLL_MASK) == FS_PERM_NOLL)
-		return true;
-#else
-	if (fs == FS_L1_PERM || fs == FS_L2_PERM)
-		return true;
-#endif
-	return false;
-}
-
 #ifdef CONFIG_CPU_TTBR0_PAN
 static inline bool ttbr0_usermode_access_allowed(struct pt_regs *regs)
 {
```
With the compilation error fixing patch first, and then your three
patches, and then Liyuan's patch:
Link: https://lore.kernel.org/20251127025848.363992-1-pangliyuan1 at huawei.com
The current testing situation is as follows:

1. About the hash_name() fault issue:
Simple test case:
Link: https://lore.kernel.org/20251127140109.191657-1-xieyuanbin1 at huawei.com
that can trigger this issue, as well as the original scenario which
trigger this issue, have passed the tests.

So patch1 and patch2:

Tested-by: Xie Yuanbin <xieyuanbin1 at huawei.com>

2. About the branch predictor issue:
Simple test cases (Link same as above) that can trigger this issue, has
passed the tests. However, the original scenario which trigger the issue
is the syzkaller test, which might take some time, possibly around a day.


From francesco at dolcini.it  Tue Dec  9 00:57:46 2025
From: francesco at dolcini.it (Francesco Dolcini)
Date: Tue,  9 Dec 2025 09:57:46 +0100
Subject: [PATCH v1] arm64: dts: freescale: imx8-apalis: Add ethernet alias
Message-ID: <20251209085747.39009-1-francesco@dolcini.it>

From: Francesco Dolcini <francesco.dolcini at toradex.com>

Add alias for the apalis first ethernet interface, this ensures
consistent interface naming (e.g. `end0`) and this is used by the
firmware to correctly set the MAC address.

Signed-off-by: Francesco Dolcini <francesco.dolcini at toradex.com>
---
 arch/arm64/boot/dts/freescale/imx8-apalis-v1.1.dtsi | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8-apalis-v1.1.dtsi b/arch/arm64/boot/dts/freescale/imx8-apalis-v1.1.dtsi
index 9153dddfd3b8..6fc82b5eb58c 100644
--- a/arch/arm64/boot/dts/freescale/imx8-apalis-v1.1.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8-apalis-v1.1.dtsi
@@ -6,6 +6,10 @@
 #include <dt-bindings/pwm/pwm.h>
 
 / {
+	aliases {
+		ethernet0 = &fec1;
+	};
+
 	chosen {
 		stdout-path = &lpuart1;
 	};
-- 
2.47.3



From linux at armlinux.org.uk  Tue Dec  9 00:59:24 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Tue, 9 Dec 2025 08:59:24 +0000
Subject: [PATCH 0/3] ARM: fix hash_name() and branch predictor issues
In-Reply-To: <20251209085627.64057-1-xieyuanbin1@huawei.com>
References: <aTcBHKFDBkSEp5mi@shell.armlinux.org.uk>
 <20251209085627.64057-1-xieyuanbin1@huawei.com>
Message-ID: <aTfk7Am4pg1tTeYZ@shell.armlinux.org.uk>

On Tue, Dec 09, 2025 at 04:56:27PM +0800, Xie Yuanbin wrote:
> Hi, Russell!
> 
> TL; DR:
> patch1 and patch2 with compilation error fixed:
> 
> Tested-by: Xie Yuanbin <xieyuanbin1 at huawei.com>
> 
> patch3:
> The simple test case passed, but the syzkaller test (the original
> scenario that triggered the branch predictor issue) is still running.
> The syzkaller test is better to run for a day.
> 
> All patches with compilation error fixed:
> 
> Reviewed-by: Xie Yuanbin <xieyuanbin1 at huawei.com>

To avoid any confusion, does this include my preferred fix that I sent
or your change?

Thanks.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From xieyuanbin1 at huawei.com  Tue Dec  9 01:09:38 2025
From: xieyuanbin1 at huawei.com (Xie Yuanbin)
Date: Tue, 9 Dec 2025 17:09:38 +0800
Subject: [PATCH 0/3] ARM: fix hash_name() and branch predictor issues
In-Reply-To: <aTfk7Am4pg1tTeYZ@shell.armlinux.org.uk>
References: <aTfk7Am4pg1tTeYZ@shell.armlinux.org.uk>
Message-ID: <20251209090938.65859-1-xieyuanbin1@huawei.com>

On Tue, 9 Dec 2025 08:59:24 +0000, Russell King wrote:
> On Tue, Dec 09, 2025 at 04:56:27PM +0800, Xie Yuanbin wrote:
>> Hi, Russell!
>>
>> TL; DR:
>> patch1 and patch2 with compilation error fixed:
>>
>> Tested-by: Xie Yuanbin <xieyuanbin1 at huawei.com>
>>
>> patch3:
>> The simple test case passed, but the syzkaller test (the original
>> scenario that triggered the branch predictor issue) is still running.
>> The syzkaller test is better to run for a day.
>>
>> All patches with compilation error fixed:
>>
>> Reviewed-by: Xie Yuanbin <xieyuanbin1 at huawei.com>
>
> To avoid any confusion, does this include my preferred fix that I sent
> or your change?
>
> Thanks.

I am using my change, which is detailed in the last email, because you
send your preferred fix just 10 mins ago.

Also, I do the test with Liyuan's patch as "suffix" patch, as mentioned
in the previous email.


From claudiu.beznea at tuxon.dev  Tue Dec  9 01:27:57 2025
From: claudiu.beznea at tuxon.dev (Claudiu Beznea)
Date: Tue, 9 Dec 2025 11:27:57 +0200
Subject: [PATCH] irqchip/mchp-eic: Fix error code in
 mchp_eic_domain_alloc()
In-Reply-To: <aTfHmOz6IBpTIPU5@stanley.mountain>
References: <aTfHmOz6IBpTIPU5@stanley.mountain>
Message-ID: <b0c8616b-24ec-4da0-abe7-4514069c1679@tuxon.dev>



On 12/9/25 08:54, Dan Carpenter wrote:
> If the irq_domain_translate_twocell() function sets "hwirq" to >=
> MCHP_EIC_NIRQ (2) then it would result in an out of bounds access.
> The code here checks for invalid values, but doesn't set the error
> code.  Return -EINVAL in that case, instead of returning success.
> 
> Fixes: 00fa3461c86d ("irqchip/mchp-eic: Add support for the Microchip EIC")
> Signed-off-by: Dan Carpenter <dan.carpenter at linaro.org>

Reviewed-by: Claudiu Beznea <claudiu.beznea at tuxon.dev>



From chaoyi.chen at rock-chips.com  Tue Dec  9 01:31:02 2025
From: chaoyi.chen at rock-chips.com (Chaoyi Chen)
Date: Tue, 9 Dec 2025 17:31:02 +0800
Subject: Issues with DRM_ACCEL_ROCKET (Oops, power-domain, probe-ordering)
In-Reply-To: <CAAObsKDYLXVf1GdYUNeaOya+pWD4jTOEf55ouXAL9iM_kWCcMw@mail.gmail.com>
References: <0b20d760-ad4f-41c0-b733-39db10d6cc41@cherry.de>
 <77685900-2c34-49b8-8c7e-14718841ef17@rock-chips.com>
 <fa82d11f-ce11-4feb-bdb4-c31d360a2a62@rock-chips.com>
 <CAAObsKDYLXVf1GdYUNeaOya+pWD4jTOEf55ouXAL9iM_kWCcMw@mail.gmail.com>
Message-ID: <75166475-d6a8-45b8-8092-f31d292d4206@rock-chips.com>

Hello Tomeu,

On 12/9/2025 2:55 PM, Tomeu Vizoso wrote:
> On Tue, Dec 2, 2025 at 8:00?AM Chaoyi Chen <chaoyi.chen at rock-chips.com> wrote:

[...]

> 
> This need was questioned during the review process, and during my
> stress testing I didn't find a need for core 0 to be treated
> specially. So it was considered unneeded complexity and the code was
> dropped.
>

Oh, I just noticed that the commit comment in the devicetree still
contains a relevant description.

> My testing involves running the supported models as a whole, and also
> their individual operations as individual tests. I run them in 8
> parallel processes, in batches so we have continuous bring up and down
> of clients.
> 
> I'm a bit surprised that that testing worked stably but we have still
> failures in some setups.

Could you please describe the failures that still exist? Thank you.

-- 
Best, 
Chaoyi


From jcalligeros99 at gmail.com  Tue Dec  9 01:31:13 2025
From: jcalligeros99 at gmail.com (James Calligeros)
Date: Tue, 09 Dec 2025 19:31:13 +1000
Subject: [PATCH 0/7] ASoC: basic support for configuring bus keepers
Message-ID: <20251209-tdm-idle-slots-v1-0-38dabf6bc01e@gmail.com>

Hi all,

This series introduces some infrastructure to allow platform drivers
to specify what a DAI should be doing when it is not active on the
bus. The primary use case for this is configuring bus keepers which
may be integrated into various codecs.

Consider a device with two codecs that report voice coil voltage and
current data back to the host via I2S. Codec A is configured to transmit
its V/ISENSE data on TDM slots 1 and 3, while Codec B is configured to
do so on slots 2 and 4. The receiving end sums the two together.
If Codec A transmits anything on slots 2 or 4 (and vice versa), the
result is a bus conflict.

Some codecs include configurable bus keepers to ameliorate this issue.
Notable examples are the TI TAS2764 and TAS2770. By default, these
codecs keep their SDOUT pin floating during unconfigured TDM slots,
however this can result in garbage data on the bus. TAS2764 can be
set up to fill specific TDM slots with zeroes, TAS2770 can hold its
SDOUT pin to ground.

This feature is necessary to properly drive the speaker systems found
on most Apple Silicon laptops. All but three models include six codecs
in two groups of three driving two woofers and a tweeter on both the left
and right channels. Each codec group has a single line for SDOUT, to
which all codecs are connected. The two groups are then summed on to
one I2S port. Each group must ensure that it is silent on the bus while
the other is supposed to be active.

In the downstream Asahi Linux kernel[1], we set up one codec in each
group to zero-fill or pull down its group's side of the bus for the
opposite group's transmit slots. This is done entirely in the codec
driver, however this approach is perhaps over-fit for our use case.
Following previous mailing list discussions[2], I have tried to
expose the functionality in a more configurable and generic way.

I have integrated this approach into our downstream platform driver
and select Devicetrees as an example of how this mechanism is intended
to be used[3].

Regards,
James

[1] https://github.com/AsahiLinux/linux/tree/bits/070-audio
[2] https://lore.kernel.org/asahi/20250227-apple-codec-changes-v3-17-cbb130030acf at gmail.com/
[3] https://github.com/chadmed/tree/tdm-revised2

---
James Calligeros (7):
      ASoC: dt-bindings: convert tdm-slot to YAML
      ASoC: dt-bindings: update tdm-slot.txt references to tdm-slot.yaml
      ASoC: dt-bindings: add TDM slot idle mode properties
      ASoC: soc-dai: define TDM idle behaviour modes
      ASoC: soc-dai: add common operation to set TDM idle mode
      ASoC: tas2764: expose SDOUT bus keeper via set_tdm_idle operation
      ASoC: tas2770: expose SDOUT bus keeper via set_tdm_idle

 .../bindings/sound/imx-audio-card.yaml   |  4 +-
 .../bindings/sound/simple-card.yaml      |  4 +-
 .../bindings/sound/tdm-slot.txt          | 29 --------
 .../bindings/sound/tdm-slot.yaml         | 66 +++++++++++++++++
 include/sound/soc-dai.h                  | 20 ++++++
 sound/soc/codecs/tas2764.c               | 95 +++++++++++++++++++++++++
 sound/soc/codecs/tas2764.h               | 11 +++
 sound/soc/codecs/tas2770.c               | 75 +++++++++++++++++++
 sound/soc/codecs/tas2770.h               | 12 ++++
 sound/soc/soc-dai.c                      | 40 +++++++++++
 10 files changed, 323 insertions(+), 33 deletions(-)
---
base-commit: e4deadb3e562aadf2825f28be3dcbbf01cf2ef17
change-id: 20251201-tdm-idle-slots-10ba92516da4

Best regards,
-- 
James Calligeros <jcalligeros99 at gmail.com>



From jcalligeros99 at gmail.com  Tue Dec  9 01:31:14 2025
From: jcalligeros99 at gmail.com (James Calligeros)
Date: Tue, 09 Dec 2025 19:31:14 +1000
Subject: [PATCH 1/7] ASoC: dt-bindings: convert tdm-slot to YAML
In-Reply-To: <20251209-tdm-idle-slots-v1-0-38dabf6bc01e@gmail.com>
References: <20251209-tdm-idle-slots-v1-0-38dabf6bc01e@gmail.com>
Message-ID: <20251209-tdm-idle-slots-v1-1-38dabf6bc01e@gmail.com>

This schema was still in plaintext form. Convert to YAML format.

Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
---
 .../bindings/sound/tdm-slot.txt          | 29 ---------------------
 .../bindings/sound/tdm-slot.yaml         | 34 +++++++++++++++++++++++++
 2 files changed, 34 insertions(+), 29 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/tdm-slot.txt b/Documentation/devicetree/bindings/sound/tdm-slot.txt
deleted file mode 100644
index 4bb513ae62fc..000000000000
--- a/Documentation/devicetree/bindings/sound/tdm-slot.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-TDM slot:
-
-This specifies audio DAI's TDM slot.
-
-TDM slot properties:
-dai-tdm-slot-num : Number of slots in use.
-dai-tdm-slot-width : Width in bits for each slot.
-dai-tdm-slot-tx-mask : Transmit direction slot mask, optional
-dai-tdm-slot-rx-mask : Receive direction slot mask, optional
-
-For instance:
-	dai-tdm-slot-num = <2>;
-	dai-tdm-slot-width = <8>;
-	dai-tdm-slot-tx-mask = <0 1>;
-	dai-tdm-slot-rx-mask = <1 0>;
-
-And for each specified driver, there could be one .of_xlate_tdm_slot_mask()
-to specify an explicit mapping of the channels and the slots. If it's absent
-the default snd_soc_of_xlate_tdm_slot_mask() will be used to generating the
-tx and rx masks.
-
-For snd_soc_of_xlate_tdm_slot_mask(), the tx and rx masks will use a 1 bit
-for an active slot as default, and the default active bits are at the LSB of
-the masks.
-
-The explicit masks are given as array of integers, where the first
-number presents bit-0 (LSB), second presents bit-1, etc. Any non zero
-number is considered 1 and 0 is 0. snd_soc_of_xlate_tdm_slot_mask()
-does not do anything, if either mask is set non zero value.
diff --git a/Documentation/devicetree/bindings/sound/tdm-slot.yaml b/Documentation/devicetree/bindings/sound/tdm-slot.yaml
new file mode 100644
index 000000000000..b67844e1dfd5
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/tdm-slot.yaml
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/tdm-slot.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Time Division Multiplexing (TDM) Slot Parameters
+
+maintainers:
+  - Liam Girdwood <lgirdwood at gmail.com>
+
+select: false
+
+definitions:
+  dai-tdm-slot-num:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Number of slots in use
+
+  dai-tdm-slot-width:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Width, in bits, of each slot
+
+  dai-tdm-slot-tx-mask:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    description: Transmit direction slot mask. Optional. Drivers may specify an
+      .xlate_tdm_slot_mask() to generate a slot mask dynamically. If neither
+      this property nor a driver-specific function are specified, the default
+      snd_soc_xlate_tdm_slot_mask() function will be used to generate a mask.
+      The first element of the array is slot 0 (LSB). Any nonzero value will be
+      treated as 1.
+
+  dai-tdm-slot-rx-mask:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    description: Receive direction slot mask. Optional. Identical to TX mask.

-- 
2.52.0



From jcalligeros99 at gmail.com  Tue Dec  9 01:31:15 2025
From: jcalligeros99 at gmail.com (James Calligeros)
Date: Tue, 09 Dec 2025 19:31:15 +1000
Subject: [PATCH 2/7] ASoC: dt-bindings: update tdm-slot.txt references to
 tdm-slot.yaml
In-Reply-To: <20251209-tdm-idle-slots-v1-0-38dabf6bc01e@gmail.com>
References: <20251209-tdm-idle-slots-v1-0-38dabf6bc01e@gmail.com>
Message-ID: <20251209-tdm-idle-slots-v1-2-38dabf6bc01e@gmail.com>

Ensure that all references to tdm-slot.txt have been updated to
tdm-slot.yaml.

Achieved by running "sed -i 's/tdm-slot.txt/tdm-slot.yaml/g' *"
against the bindings/sound. No other references to the file
were found in the tree.

Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
---
 .../bindings/sound/imx-audio-card.yaml   | 4 ++--
 .../bindings/sound/simple-card.yaml      | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/imx-audio-card.yaml b/Documentation/devicetree/bindings/sound/imx-audio-card.yaml
index 3c75c8c78987..1df29a556120 100644
--- a/Documentation/devicetree/bindings/sound/imx-audio-card.yaml
+++ b/Documentation/devicetree/bindings/sound/imx-audio-card.yaml
@@ -39,11 +39,11 @@ patternProperties:
             - dsp_b
 
       dai-tdm-slot-num:
-        description: see tdm-slot.txt.
+        description: see tdm-slot.yaml.
         $ref: /schemas/types.yaml#/definitions/uint32
 
       dai-tdm-slot-width:
-        description: see tdm-slot.txt.
+        description: see tdm-slot.yaml.
         $ref: /schemas/types.yaml#/definitions/uint32
 
       playback-only:
diff --git a/Documentation/devicetree/bindings/sound/simple-card.yaml b/Documentation/devicetree/bindings/sound/simple-card.yaml
index 533d0a1da56e..2e1a5b3216c5 100644
--- a/Documentation/devicetree/bindings/sound/simple-card.yaml
+++ b/Documentation/devicetree/bindings/sound/simple-card.yaml
@@ -28,11 +28,11 @@ definitions:
     $ref: /schemas/types.yaml#/definitions/flag
 
   dai-tdm-slot-num:
-    description: see tdm-slot.txt.
+    description: see tdm-slot.yaml.
     $ref: /schemas/types.yaml#/definitions/uint32
 
   dai-tdm-slot-width:
-    description: see tdm-slot.txt.
+    description: see tdm-slot.yaml.
     $ref: /schemas/types.yaml#/definitions/uint32
 
   system-clock-frequency:

-- 
2.52.0



From jcalligeros99 at gmail.com  Tue Dec  9 01:31:16 2025
From: jcalligeros99 at gmail.com (James Calligeros)
Date: Tue, 09 Dec 2025 19:31:16 +1000
Subject: [PATCH 3/7] ASoC: dt-bindings: add TDM slot idle mode properties
In-Reply-To: <20251209-tdm-idle-slots-v1-0-38dabf6bc01e@gmail.com>
References: <20251209-tdm-idle-slots-v1-0-38dabf6bc01e@gmail.com>
Message-ID: <20251209-tdm-idle-slots-v1-3-38dabf6bc01e@gmail.com>

Add properties to describe TDM slot idle behaviour.

Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
---
 .../bindings/sound/tdm-slot.yaml         | 32 +++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/Documentation/devicetree/bindings/sound/tdm-slot.yaml b/Documentation/devicetree/bindings/sound/tdm-slot.yaml
index b67844e1dfd5..b247b315d7f4 100644
--- a/Documentation/devicetree/bindings/sound/tdm-slot.yaml
+++ b/Documentation/devicetree/bindings/sound/tdm-slot.yaml
@@ -11,6 +11,16 @@ maintainers:
 
 select: false
 
+$defs:
+  dai-tdm-idle-mode:
+    $ref: /schemas/types.yaml#/definitions/string
+    enum:
+      - none
+      - off
+      - zero
+      - pulldown
+      - hiz
+
 definitions:
   dai-tdm-slot-num:
     $ref: /schemas/types.yaml#/definitions/uint32
@@ -32,3 +42,25 @@ definitions:
   dai-tdm-slot-rx-mask:
     $ref: /schemas/types.yaml#/definitions/uint32-array
     description: Receive direction slot mask. Optional. Identical to TX mask.
+
+  dai-tdm-slot-tx-idle-mode:
+    $ref: "#/$defs/dai-tdm-idle-mode"
+    description: Transmit direction idle slot mode. Optional. For hardware
+      that can configure its behaviour during idle TDM slots via
+      .set_tdm_idle(). "None" represents UB/unspecified behaviour and is the
+      same as not setting this property.
+
+  dai-tdm-slot-rx-idle-mode:
+    $ref: "#/$defs/dai-tdm-idle-mode"
+    description: Receive direction idle slot mode. Optional. Identical to TX
+      idle slot mode.
+
+  dai-tdm-slot-tx-idle-mask:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Transmit direction idle slot mask. Optional. 1 represents
+      an idle slot.
+
+  dai-tdm-slot-rx-idle-mask:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Receive direction idle slot mask. Optional. Identical to
+      TX mask.

-- 
2.52.0



From jcalligeros99 at gmail.com  Tue Dec  9 01:31:17 2025
From: jcalligeros99 at gmail.com (James Calligeros)
Date: Tue, 09 Dec 2025 19:31:17 +1000
Subject: [PATCH 4/7] ASoC: soc-dai: define TDM idle behaviour modes
In-Reply-To: <20251209-tdm-idle-slots-v1-0-38dabf6bc01e@gmail.com>
References: <20251209-tdm-idle-slots-v1-0-38dabf6bc01e@gmail.com>
Message-ID: <20251209-tdm-idle-slots-v1-4-38dabf6bc01e@gmail.com>

Some audio devices, such as certain Texas Instruments codecs,
include configurable bus keepers.

Imagine for example two codecs sharing a bus. When one codec is
transmitting, the other must ensure that it is holding its side
to 0, or data from the transmitting codec will be corrupted. We
can trust the "idle" codec to simply do this itself, however
this is undefined behaviour. Some devices may leave the line
floating, others still may pull the line high. We need a way to
control this behaviour.

Thus, we define five possible bus-keeping modes that a device can
be in: NONE (UB/as initialised), OFF (explicitly disabled), ZERO
(actively transmit a 0), PULLDOWN, and HIZ (floating).

These will be consumed by CODEC/CPU drivers via a common DAI
op, enabling the explicit configuration of bus keepers where
required.

Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
---
 include/sound/soc-dai.h | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 224396927aef..a5784ef8e3f7 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -52,6 +52,19 @@ struct snd_compr_stream;
 #define SND_SOC_POSSIBLE_DAIFMT_AC97		(1 << SND_SOC_DAI_FORMAT_AC97)
 #define SND_SOC_POSSIBLE_DAIFMT_PDM		(1 << SND_SOC_DAI_FORMAT_PDM)
 
+/*
+ * DAI TDM slot idle modes
+ *
+ * Describes a CODEC/CPU's behaviour when not actively receiving or
+ * transmitting on a given TDM slot. NONE is undefined behaviour.
+ * Add new modes to the end.
+ */
+#define SND_SOC_DAI_TDM_IDLE_NONE	0
+#define SND_SOC_DAI_TDM_IDLE_OFF	1
+#define SND_SOC_DAI_TDM_IDLE_ZERO	2
+#define SND_SOC_DAI_TDM_IDLE_PULLDOWN	3
+#define SND_SOC_DAI_TDM_IDLE_HIZ	4
+
 /*
  * DAI Clock gating.
  *

-- 
2.52.0



From jcalligeros99 at gmail.com  Tue Dec  9 01:31:18 2025
From: jcalligeros99 at gmail.com (James Calligeros)
Date: Tue, 09 Dec 2025 19:31:18 +1000
Subject: [PATCH 5/7] ASoC: soc-dai: add common operation to set TDM idle
 mode
In-Reply-To: <20251209-tdm-idle-slots-v1-0-38dabf6bc01e@gmail.com>
References: <20251209-tdm-idle-slots-v1-0-38dabf6bc01e@gmail.com>
Message-ID: <20251209-tdm-idle-slots-v1-5-38dabf6bc01e@gmail.com>

Some audio devices, like certain Texas Instruments codecs, can be
configured to alter their behaviour when idle on the bus. Now that we
have definitions for various idle modes, add a snd_soc_dai_set_tdm_idle()
operation to control this in a standardised way.

Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
---
 include/sound/soc-dai.h |  7 +++++
 sound/soc/soc-dai.c     | 40 +++++++++++++++++++++++++
 2 files changed, 47 insertions(+)

diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index a5784ef8e3f7..1f411237dde5 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -194,6 +194,10 @@ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt);
 int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
 	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width);
 
+int snd_soc_dai_set_tdm_idle(struct snd_soc_dai *dai,
+			     unsigned int tx_mask, unsigned int rx_mask,
+			     int tx_mode, int rx_mode);
+
 int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
 	unsigned int tx_num, const unsigned int *tx_slot,
 	unsigned int rx_num, const unsigned int *rx_slot);
@@ -310,6 +314,9 @@ struct snd_soc_dai_ops {
 	int (*set_tdm_slot)(struct snd_soc_dai *dai,
 		unsigned int tx_mask, unsigned int rx_mask,
 		int slots, int slot_width);
+	int (*set_tdm_idle)(struct snd_soc_dai *dai,
+			    unsigned int tx_mask, unsigned int rx_mask,
+			    int tx_mode, int rx_mode);
 	int (*set_channel_map)(struct snd_soc_dai *dai,
 		unsigned int tx_num, const unsigned int *tx_slot,
 		unsigned int rx_num, const unsigned int *rx_slot);
diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
index a1e05307067d..2f370fda1266 100644
--- a/sound/soc/soc-dai.c
+++ b/sound/soc/soc-dai.c
@@ -282,6 +282,46 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
 
+/**
+ * snd_soc_dai_set_tdm_idle() - Configure a DAI's TDM idle mode
+ * @dai: The DAI to configure
+ * @tx_mask: bitmask representing idle TX slots.
+ * @rx_mask: bitmask representing idle RX slots.
+ * @tx_mode: idle mode to set for TX slots.
+ * @rx_mode: idle mode to set for RX slots.
+ *
+ * This function configures the DAI to handle idle TDM slots in the
+ * specified manner. @tx_mode and @rx_mode can be one of
+ * SND_SOC_DAI_TDM_IDLE_NONE, SND_SOC_DAI_TDM_IDLE_ZERO,
+ * SND_SOC_DAI_TDM_IDLE_PULLDOWN, or SND_SOC_DAI_TDM_IDLE_HIZ.
+ * SND_SOC_TDM_IDLE_NONE represents the DAI's default/unset idle slot
+ * handling state and could be any of the other modes depending on the
+ * hardware behind the DAI. It is therefore undefined behaviour when set
+ * explicitly.
+ *
+ * Mode and mask can be set independently for both the TX and RX direction.
+ * Some hardware may ignore both TX and RX masks depending on its
+ * capabilities.
+ */
+int snd_soc_dai_set_tdm_idle(struct snd_soc_dai *dai,
+			     unsigned int tx_mask, unsigned int rx_mask,
+			     int tx_mode, int rx_mode)
+{
+	int ret = -EOPNOTSUPP;
+
+	/* You can't write to the RX line */
+	if (rx_mode == SND_SOC_DAI_TDM_IDLE_ZERO)
+		return soc_dai_ret(dai, -EINVAL);
+
+	if (dai->driver->ops &&
+	    dai->driver->ops->set_tdm_idle)
+		ret = dai->driver->ops->set_tdm_idle(dai, tx_mask, rx_mask,
+						     tx_mode, rx_mode);
+
+	return soc_dai_ret(dai, ret);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_idle);
+
 /**
  * snd_soc_dai_set_channel_map - configure DAI audio channel map
  * @dai: DAI

-- 
2.52.0



From jcalligeros99 at gmail.com  Tue Dec  9 01:31:19 2025
From: jcalligeros99 at gmail.com (James Calligeros)
Date: Tue, 09 Dec 2025 19:31:19 +1000
Subject: [PATCH 6/7] ASoC: tas2764: expose SDOUT bus keeper via
 set_tdm_idle operation
In-Reply-To: <20251209-tdm-idle-slots-v1-0-38dabf6bc01e@gmail.com>
References: <20251209-tdm-idle-slots-v1-0-38dabf6bc01e@gmail.com>
Message-ID: <20251209-tdm-idle-slots-v1-6-38dabf6bc01e@gmail.com>

TAS2764, and the Apple-exclusive variant SN012776, include bus keepers
on the SDOUT pin that can be configured to alter the behaviour of the
SDOUT pin during specified TDM slots. The chip can either leave the
bus floating (default/uninitialised behaviour) or fill the specified
slots with zeroes.

Expose the SDOUT bus keeper and allow it to be configured using the
set_tdm_idle DAI op. The mask must be cropped to only cover slots
valid for the configured BCLK ratio, so introduce a set_bclk_ratio
op that properly configures the bus keeper too.

Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
---
 sound/soc/codecs/tas2764.c | 95 +++++++++++++++++++++++++
 sound/soc/codecs/tas2764.h | 11 +++
 2 files changed, 106 insertions(+)

diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c
index 36e25e48b354..423b7073b302 100644
--- a/sound/soc/codecs/tas2764.c
+++ b/sound/soc/codecs/tas2764.c
@@ -44,6 +44,11 @@ struct tas2764_priv {
 
 	bool dac_powered;
 	bool unmuted;
+
+	struct {
+		int tx_mode;
+		unsigned int tx_mask;
+	} idle_slot_config;
 };
 
 #include "tas2764-quirks.h"
@@ -509,11 +514,101 @@ static int tas2764_set_dai_tdm_slot(struct snd_soc_dai *dai,
 	return 0;
 }
 
+static int tas2764_write_sdout_idle_mask(struct tas2764_priv *tas2764, u32 mask)
+{
+	struct snd_soc_component *component = tas2764->component;
+	int i, ret;
+
+	/* Hardware supports up to 64 slots, but we don't */
+	for (i = 0; i < 4; i++) {
+		ret = snd_soc_component_write(component,
+					      TAS2764_SDOUT_HIZ_1 + i,
+					      (mask >> (i * 8)) & 0xff);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int tas2764_set_dai_tdm_idle(struct snd_soc_dai *dai,
+				    unsigned int tx_mask, unsigned int rx_mask,
+				    int tx_mode, int rx_mode)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	/* We don't support setting anything on SDIN */
+	if (rx_mode)
+		return -EOPNOTSUPP;
+
+	if (tas2764->idle_slot_config.tx_mask == tx_mask &&
+	    tas2764->idle_slot_config.tx_mode == tx_mode)
+		return 0;
+
+	switch (tx_mode) {
+	case SND_SOC_DAI_TDM_IDLE_ZERO:
+		if (!tx_mask)
+			return -EINVAL;
+
+		ret = tas2764_write_sdout_idle_mask(tas2764, tx_mask);
+		if (ret < 0)
+			return ret;
+
+		ret = snd_soc_component_update_bits(component,
+						    TAS2764_SDOUT_HIZ_9,
+						    TAS2764_SDOUT_HIZ_9_FORCE_0_EN,
+						    TAS2764_SDOUT_HIZ_9_FORCE_0_EN);
+		if (ret < 0)
+			return ret;
+
+		tas2764->idle_slot_config.tx_mask = tx_mask;
+		tas2764->idle_slot_config.tx_mode = tx_mode;
+		break;
+	case SND_SOC_DAI_TDM_IDLE_HIZ:
+	case SND_SOC_DAI_TDM_IDLE_OFF:
+		/* HiZ mode does not support a slot mask */
+		ret = tas2764_write_sdout_idle_mask(tas2764, 0);
+		if (ret < 0)
+			return ret;
+
+		ret = snd_soc_component_update_bits(component,
+						    TAS2764_SDOUT_HIZ_9,
+						    TAS2764_SDOUT_HIZ_9_FORCE_0_EN, 0);
+		if (ret < 0)
+			return ret;
+
+		tas2764->idle_slot_config.tx_mask = 0;
+		tas2764->idle_slot_config.tx_mode = tx_mode;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+/* The SDOUT idle slot mask must be cropped based on the BCLK ratio */
+static int tas2764_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+	struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(dai->component);
+
+	if (!tas2764->idle_slot_config.tx_mask)
+		return 0;
+
+	tas2764->idle_slot_config.tx_mask &= GENMASK((ratio / 8) - 1, 0);
+
+	return tas2764_write_sdout_idle_mask(tas2764, tas2764->idle_slot_config.tx_mask);
+}
+
 static const struct snd_soc_dai_ops tas2764_dai_ops = {
 	.mute_stream = tas2764_mute,
 	.hw_params  = tas2764_hw_params,
 	.set_fmt    = tas2764_set_fmt,
+	.set_bclk_ratio = tas2764_set_bclk_ratio,
 	.set_tdm_slot = tas2764_set_dai_tdm_slot,
+	.set_tdm_idle = tas2764_set_dai_tdm_idle,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/tas2764.h b/sound/soc/codecs/tas2764.h
index 538290ed3d92..4494bc4889dc 100644
--- a/sound/soc/codecs/tas2764.h
+++ b/sound/soc/codecs/tas2764.h
@@ -126,4 +126,15 @@
 
 #define TAS2764_BOP_CFG0                TAS2764_REG(0X0, 0x1d)
 
+#define TAS2764_SDOUT_HIZ_1            TAS2764_REG(0x1, 0x3d)
+#define TAS2764_SDOUT_HIZ_2            TAS2764_REG(0x1, 0x3e)
+#define TAS2764_SDOUT_HIZ_3            TAS2764_REG(0x1, 0x3f)
+#define TAS2764_SDOUT_HIZ_4            TAS2764_REG(0x1, 0x40)
+#define TAS2764_SDOUT_HIZ_5            TAS2764_REG(0x1, 0x41)
+#define TAS2764_SDOUT_HIZ_6            TAS2764_REG(0x1, 0x42)
+#define TAS2764_SDOUT_HIZ_7            TAS2764_REG(0x1, 0x43)
+#define TAS2764_SDOUT_HIZ_8            TAS2764_REG(0x1, 0x44)
+#define TAS2764_SDOUT_HIZ_9            TAS2764_REG(0x1, 0x45)
+#define TAS2764_SDOUT_HIZ_9_FORCE_0_EN BIT(7)
+
 #endif /* __TAS2764__ */

-- 
2.52.0



From jcalligeros99 at gmail.com  Tue Dec  9 01:31:20 2025
From: jcalligeros99 at gmail.com (James Calligeros)
Date: Tue, 09 Dec 2025 19:31:20 +1000
Subject: [PATCH 7/7] ASoC: tas2770: expose SDOUT bus keeper via
 set_tdm_idle
In-Reply-To: <20251209-tdm-idle-slots-v1-0-38dabf6bc01e@gmail.com>
References: <20251209-tdm-idle-slots-v1-0-38dabf6bc01e@gmail.com>
Message-ID: <20251209-tdm-idle-slots-v1-7-38dabf6bc01e@gmail.com>

TAS2770 includes a bus keeper which can be used to control the behaviour
of the SDOUT pin during specified TDM slots. The chip can either pull
the pin to ground, actively transmit zeroes, or keep the pin floating
(default/uninitialised behaviour).

Expose the bus keeper via the set_tdm_idle DAI op so that it can be
configured by consumers.

Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
---
 sound/soc/codecs/tas2770.c | 75 +++++++++++++++++++++++++
 sound/soc/codecs/tas2770.h | 12 ++++
 2 files changed, 87 insertions(+)

diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c
index 6f878b01716f..d4d7d056141b 100644
--- a/sound/soc/codecs/tas2770.c
+++ b/sound/soc/codecs/tas2770.c
@@ -492,11 +492,86 @@ static int tas2770_set_dai_tdm_slot(struct snd_soc_dai *dai,
 	return 0;
 }
 
+static int tas2770_set_dai_tdm_idle(struct snd_soc_dai *dai,
+				    unsigned int tx_mask,
+				    unsigned int rx_mask,
+				    int tx_mode, int rx_mode)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas2770_priv *tas2770 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	/* We don't support setting anything for SDIN */
+	if (rx_mode)
+		return -EOPNOTSUPP;
+
+	if (tas2770->idle_tx_mode == tx_mode)
+		return 0;
+
+	switch (tx_mode) {
+	case SND_SOC_DAI_TDM_IDLE_PULLDOWN:
+		ret = snd_soc_component_update_bits(component, TAS2770_DIN_PD,
+						    TAS2770_DIN_PD_SDOUT,
+						    TAS2770_DIN_PD_SDOUT);
+		if (ret)
+			return ret;
+
+		break;
+	case SND_SOC_DAI_TDM_IDLE_ZERO:
+		ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG4,
+						    TAS2770_TDM_CFG_REG4_TX_KEEPER,
+						    TAS2770_TDM_CFG_REG4_TX_KEEPER);
+		if (ret)
+			return ret;
+
+		ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG4,
+						    TAS2770_TDM_CFG_REG4_TX_FILL, 0);
+		if (ret)
+			return ret;
+
+		break;
+	case SND_SOC_DAI_TDM_IDLE_HIZ:
+		ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG4,
+						    TAS2770_TDM_CFG_REG4_TX_KEEPER,
+						    TAS2770_TDM_CFG_REG4_TX_KEEPER);
+		if (ret)
+			return ret;
+
+		ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG4,
+						    TAS2770_TDM_CFG_REG4_TX_FILL,
+						    TAS2770_TDM_CFG_REG4_TX_FILL);
+		if (ret)
+			return ret;
+
+		break;
+	case SND_SOC_DAI_TDM_IDLE_OFF:
+		ret = snd_soc_component_update_bits(component, TAS2770_DIN_PD,
+						    TAS2770_DIN_PD_SDOUT, 0);
+		if (ret)
+			return ret;
+
+		ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG4,
+						    TAS2770_TDM_CFG_REG4_TX_KEEPER, 0);
+		if (ret)
+			return ret;
+
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	tas2770->idle_tx_mode = tx_mode;
+
+	return 0;
+}
+
 static const struct snd_soc_dai_ops tas2770_dai_ops = {
 	.mute_stream = tas2770_mute,
 	.hw_params  = tas2770_hw_params,
 	.set_fmt    = tas2770_set_fmt,
 	.set_tdm_slot = tas2770_set_dai_tdm_slot,
+	.set_tdm_idle = tas2770_set_dai_tdm_idle,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/tas2770.h b/sound/soc/codecs/tas2770.h
index 3fd2e7003c50..102040b6bdf8 100644
--- a/sound/soc/codecs/tas2770.h
+++ b/sound/soc/codecs/tas2770.h
@@ -67,6 +67,14 @@
 #define TAS2770_TDM_CFG_REG3_RXS_SHIFT 0x4
 #define TAS2770_TDM_CFG_REG3_30_MASK  GENMASK(3, 0)
 #define TAS2770_TDM_CFG_REG3_30_SHIFT 0
+    /* TDM Configuration Reg4 */
+#define TAS2770_TDM_CFG_REG4  TAS2770_REG(0X0, 0x0E)
+#define TAS2770_TDM_CFG_REG4_TX_LSB_CFG BIT(7)
+#define TAS2770_TDM_CFG_REG4_TX_KEEPER_CFG BIT(6)
+#define TAS2770_TDM_CFG_REG4_TX_KEEPER BIT(5)
+#define TAS2770_TDM_CFG_REG4_TX_FILL BIT(4)
+#define TAS2770_TDM_CFG_REG4_TX_OFFSET_MASK GENMASK(3, 1)
+#define TAS2770_TDM_CFG_REG4_TX_EDGE_FALLING BIT(0)
     /* TDM Configuration Reg5 */
 #define TAS2770_TDM_CFG_REG5  TAS2770_REG(0X0, 0x0F)
 #define TAS2770_TDM_CFG_REG5_VSNS_MASK  BIT(6)
@@ -115,6 +123,9 @@
 #define TAS2770_TEMP_LSB  TAS2770_REG(0X0, 0x2A)
     /* Interrupt Configuration */
 #define TAS2770_INT_CFG  TAS2770_REG(0X0, 0x30)
+    /* Data In Pull-Down */
+#define TAS2770_DIN_PD  TAS2770_REG(0X0, 0x31)
+#define TAS2770_DIN_PD_SDOUT BIT(7)
     /* Misc IRQ */
 #define TAS2770_MISC_IRQ  TAS2770_REG(0X0, 0x32)
     /* Clock Configuration */
@@ -146,6 +157,7 @@ struct tas2770_priv {
 	int pdm_slot;
 	bool dac_powered;
 	bool unmuted;
+	int idle_tx_mode;
 };
 
 #endif /* __TAS2770__ */

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Tue Dec  9 01:33:20 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Tue, 09 Dec 2025 10:33:20 +0100
Subject: [PATCH] soc: mediatek: mtk-socinfo: Add entry for MT8371AV/AZA
 Genio 520
Message-ID: <20251209-mtk-socinfo-mt8371-v1-1-155a9df851d0@collabora.com>

Add an entry for the MT8371 SoC with commercial name Genio 520.

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 drivers/soc/mediatek/mtk-socinfo.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/soc/mediatek/mtk-socinfo.c b/drivers/soc/mediatek/mtk-socinfo.c
index 978c43e9115ab29b20703621c60f1b8ef4d6f851..424a1eb82c20fa5226bd70ec0145f437560b40cf 100644
--- a/drivers/soc/mediatek/mtk-socinfo.c
+++ b/drivers/soc/mediatek/mtk-socinfo.c
@@ -59,6 +59,7 @@ static struct socinfo_data socinfo_data_table[] = {
 	MTK_SOCINFO_ENTRY("MT8195", "MT8195TV/EZA", "Kompanio 1380", 0x81950400, CELL_NOT_USED),
 	MTK_SOCINFO_ENTRY("MT8195", "MT8195TV/EHZA", "Kompanio 1380", 0x81950404, CELL_NOT_USED),
 	MTK_SOCINFO_ENTRY("MT8370", "MT8370AV/AZA", "Genio 510", 0x83700000, 0x00000081),
+	MTK_SOCINFO_ENTRY("MT8371", "MT8371AV/AZA", "Genio 520", 0x83710000, 0x00000081),
 	MTK_SOCINFO_ENTRY("MT8390", "MT8390AV/AZA", "Genio 700", 0x83900000, 0x00000080),
 	MTK_SOCINFO_ENTRY("MT8391", "MT8391AV/AZA", "Genio 720", 0x83910000, 0x00000080),
 	MTK_SOCINFO_ENTRY("MT8395", "MT8395AV/ZA", "Genio 1200", 0x83950100, CELL_NOT_USED),

---
base-commit: 8ebfd5290c6162d65f83f9a8acdbbf243b49a586
change-id: 20251209-mtk-socinfo-mt8371-ef9ef20e66e5

Best regards,
-- 
Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>



From rf at opensource.cirrus.com  Tue Dec  9 01:36:33 2025
From: rf at opensource.cirrus.com (Richard Fitzgerald)
Date: Tue, 9 Dec 2025 09:36:33 +0000
Subject: Kconfig dangling references (BZ 216748)
In-Reply-To: <87fr9luyu7.wl-tiwai@suse.de>
References: <22b92ddf-6321-41b5-8073-f9c7064d3432@infradead.org>
 <87fr9luyu7.wl-tiwai@suse.de>
Message-ID: <3b72f01e-698c-48da-a40e-431d08c7b847@opensource.cirrus.com>

On 08/12/2025 9:06 am, Takashi Iwai wrote:
> On Mon, 08 Dec 2025 03:04:09 +0100,
> Randy Dunlap wrote:
>>
>> SND_SOC_AC97_BUS_NEW ---
>> sound/soc/pxa/Kconfig:21:	select SND_SOC_AC97_BUS_NEW
> 
> This must be a bogus entry added in commit 1c8bc7b3de5e ("ASoC: pxa:
> switch to new ac97 bus support"), which can be dropped.
> 
>> SND_SOC_CS35L56_CAL_SYSFS_COMMON ---
>> sound/soc/codecs/Kconfig:920:	select SND_SOC_CS35L56_CAL_SYSFS_COMMON
> 
> The buggy commit was 32172cf3cb54 ("ASoC: cs35l56: Allow restoring
> factory calibration through ALSA control").
> This looks like a fallout at changing from sysfs to debugfs, so this
> should be SND_SOC_CS35L56_CAL_DEBUGFS_COMMON instead.
> 
> 

Oh! I checked multiple times that I'd changed all the sysfs to debugfs
and this STILL got through. I'll send a fix.


From jie.gan at oss.qualcomm.com  Tue Dec  9 01:40:57 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Tue, 9 Dec 2025 17:40:57 +0800
Subject: [PATCH v6 2/2] coresight: cti: Add Qualcomm extended CTI support
In-Reply-To: <20251209081649.105623-1-yingchao.deng@oss.qualcomm.com>
References: <CAJ9a7Vg9Efi-5eecfiUF82_Qq8Jg9imN5q1-VKYZoPVUxNpjhA@mail.gmail.com>
 <20251209081649.105623-1-yingchao.deng@oss.qualcomm.com>
Message-ID: <d54145e1-9d86-4660-972f-46b4b063eadb@oss.qualcomm.com>



On 12/9/2025 4:16 PM, Yingchao Deng wrote:
> Hi Leo & Mike
> 
> Based on Leo?s suggestions, I created a new patch, but there are three points that do not fully align with his recommendations:
> 
>      1. The helper function for returning the register address now returns only the offset, because returning the full address would conflict with cti_write_single_reg.
>      2. For registers such as triginstatus1...3, I defined additional macros CTITRIGINSTATUS1...3. This is because CTITRIGINSTATUS + 0x4 equals CTITRIGOUTSTATUS, and to avoid conflicts with existing macros, I chose numbers starting from 0x1000 for the new definitions.
>      3. Regarding the visibility of attributes for triginstatus1...3, since coresight_cti_reg produces an anonymous variable that cannot be directly referenced, I used coresight_cti_regs_attrs[i] to obtain the attribute corresponding to triginstatus1.
> 
> I appreciate both suggestions. After reviewing them, I lean toward Mike's approach.
> 
> Signed-off-by: Yingchao Deng <yingchao.deng at oss.qualcomm.com>
> ---
>   .../hwtracing/coresight/coresight-cti-core.c  |  52 +++++--
>   .../hwtracing/coresight/coresight-cti-sysfs.c |  72 ++++++++--
>   drivers/hwtracing/coresight/coresight-cti.h   |   3 +-
>   drivers/hwtracing/coresight/qcom-cti.h        | 136 ++++++++++++++++++
>   4 files changed, 238 insertions(+), 25 deletions(-)
>   create mode 100644 drivers/hwtracing/coresight/qcom-cti.h
> 
> diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c
> index f9970e40dd59..d2b0b46f2846 100644
> --- a/drivers/hwtracing/coresight/coresight-cti-core.c
> +++ b/drivers/hwtracing/coresight/coresight-cti-core.c
> @@ -21,7 +21,7 @@
> 
>   #include "coresight-priv.h"
>   #include "coresight-cti.h"
> -
> +#include "qcom-cti.h"
>   /*
>    * CTI devices can be associated with a PE, or be connected to CoreSight
>    * hardware. We have a list of all CTIs irrespective of CPU bound or
> @@ -70,15 +70,16 @@ void cti_write_all_hw_regs(struct cti_drvdata *drvdata)
> 
>       /* write the CTI trigger registers */
>       for (i = 0; i < config->nr_trig_max; i++) {
> -        writel_relaxed(config->ctiinen[i], drvdata->base + CTIINEN(i));
> +        writel_relaxed(config->ctiinen[i],
> +                drvdata->base + cti_reg_addr_with_nr(drvdata, CTIINEN(0), i));
>           writel_relaxed(config->ctiouten[i],
> -                   drvdata->base + CTIOUTEN(i));
> +                drvdata->base + cti_reg_addr_with_nr(drvdata, CTIOUTEN(0), i));
>       }
> 
>       /* other regs */
> -    writel_relaxed(config->ctigate, drvdata->base + CTIGATE);
> -    writel_relaxed(config->asicctl, drvdata->base + ASICCTL);
> -    writel_relaxed(config->ctiappset, drvdata->base + CTIAPPSET);
> +    writel_relaxed(config->ctigate, drvdata->base + cti_reg_addr(drvdata, CTIGATE));
> +    writel_relaxed(config->asicctl, drvdata->base + cti_reg_addr(drvdata, ASICCTL));
> +    writel_relaxed(config->ctiappset, drvdata->base + cti_reg_addr(drvdata, CTIAPPSET));
> 
>       /* re-enable CTI */
>       writel_relaxed(1, drvdata->base + CTICONTROL);
> @@ -201,7 +202,7 @@ void cti_write_intack(struct device *dev, u32 ackval)
>       raw_spin_lock(&drvdata->spinlock);
>       /* write if enabled */
>       if (cti_active(config))
> -        cti_write_single_reg(drvdata, CTIINTACK, ackval);
> +        cti_write_single_reg(drvdata, cti_reg_addr(drvdata, CTIINTACK), ackval);
>       raw_spin_unlock(&drvdata->spinlock);
>   }
> 
> @@ -214,6 +215,9 @@ void cti_write_intack(struct device *dev, u32 ackval)
>   /* DEVID[19:16] - number of CTM channels */
>   #define CTI_DEVID_CTMCHANNELS(devid_val) ((int) BMVAL(devid_val, 16, 19))
> 
> +/* DEVARCH[31:21] - ARCHITECT */
> +#define CTI_DEVARCH_ARCHITECT(devarch_val) ((int)BMVAL(devarch_val, 21, 31))
> +
>   static int cti_set_default_config(struct device *dev,
>                     struct cti_drvdata *drvdata)
>   {
> @@ -394,9 +398,8 @@ int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,
> 
>       /* update the local register values */
>       chan_bitmask = BIT(channel_idx);
> -    reg_offset = (direction == CTI_TRIG_IN ? CTIINEN(trigger_idx) :
> -              CTIOUTEN(trigger_idx));
> -
> +    reg_offset = (direction == CTI_TRIG_IN ? cti_reg_addr_with_nr(drvdata, CTIINEN(0), trigger_idx):
> +                         cti_reg_addr_with_nr(drvdata, CTIOUTEN(0), trigger_idx));
>       raw_spin_lock(&drvdata->spinlock);
> 
>       /* read - modify write - the trigger / channel enable value */
> @@ -452,7 +455,7 @@ int cti_channel_gate_op(struct device *dev, enum cti_chan_gate_op op,
>       if (err == 0) {
>           config->ctigate = reg_value;
>           if (cti_active(config))
> -            cti_write_single_reg(drvdata, CTIGATE, reg_value);
> +            cti_write_single_reg(drvdata, cti_reg_addr(drvdata, CTIGATE), reg_value);
>       }
>       raw_spin_unlock(&drvdata->spinlock);
>       return err;
> @@ -479,19 +482,19 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op,
>       case CTI_CHAN_SET:
>           config->ctiappset |= chan_bitmask;
>           reg_value  = config->ctiappset;
> -        reg_offset = CTIAPPSET;
> +        reg_offset = cti_reg_addr(drvdata, CTIAPPSET);
>           break;
> 
>       case CTI_CHAN_CLR:
>           config->ctiappset &= ~chan_bitmask;
>           reg_value = chan_bitmask;
> -        reg_offset = CTIAPPCLEAR;
> +        reg_offset = cti_reg_addr(drvdata, CTIAPPCLEAR);
>           break;
> 
>       case CTI_CHAN_PULSE:
>           config->ctiappset &= ~chan_bitmask;
>           reg_value = chan_bitmask;
> -        reg_offset = CTIAPPPULSE;
> +        reg_offset = cti_reg_addr(drvdata, CTIAPPPULSE);
>           break;
> 
>       default:
> @@ -895,6 +898,7 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id)
>       struct coresight_desc cti_desc;
>       struct coresight_platform_data *pdata = NULL;
>       struct resource *res = &adev->res;
> +    u32 devarch;
> 
>       /* driver data*/
>       drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
> @@ -981,9 +985,27 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id)
>       drvdata->csdev_release = drvdata->csdev->dev.release;
>       drvdata->csdev->dev.release = cti_device_release;
> 
> +    /* check architect value*/
> +    devarch = readl_relaxed(drvdata->base + CORESIGHT_DEVARCH);
> +    if (CTI_DEVARCH_ARCHITECT(devarch) == ARCHITECT_QCOM) {
> +        drvdata->is_qcom_cti = 1;
> +
> +        /*
> +         * QCOM CTI does not implement Claimtag functionality as
> +         * per CoreSight specification, but its CLAIMSET register
> +         * is incorrectly initialized to 0xF. This can mislead
> +         * tools or drivers into thinking the component is claimed.
> +         *
> +         * Reset CLAIMSET to 0 to reflect that no claims are active.
> +         */
> +        drvdata->csdev->claim_tag_info = CS_CLAIM_TAG_NOT_IMPL;
> +        //writel_relaxed(0, drvdata->base + CORESIGHT_CLAIMSET);
> +    }
> +
>       /* all done - dec pm refcount */
>       pm_runtime_put(&adev->dev);
> -    dev_info(&drvdata->csdev->dev, "CTI initialized\n");
> +    dev_info(&drvdata->csdev->dev, "%s CTI initialized\n",
> +                    drvdata->is_qcom_cti ? "QCOM" : "");
>       return 0;
> 
>   pm_release:
> diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
> index a9df77215141..5d23a138b4a7 100644
> --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c
> +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
> @@ -13,7 +13,7 @@
>   #include <linux/sysfs.h>
> 
>   #include "coresight-cti.h"
> -
> +#include "qcom-cti.h"
>   /*
>    * Declare the number of static declared attribute groups
>    * Value includes groups + NULL value at end of table.
> @@ -183,7 +183,7 @@ static ssize_t coresight_cti_reg_show(struct device *dev,
>       pm_runtime_get_sync(dev->parent);
>       raw_spin_lock(&drvdata->spinlock);
>       if (drvdata->config.hw_powered)
> -        val = readl_relaxed(drvdata->base + cti_attr->off);
> +        val = readl_relaxed(drvdata->base + cti_reg_addr(drvdata, cti_attr->off));
>       raw_spin_unlock(&drvdata->spinlock);
>       pm_runtime_put_sync(dev->parent);
>       return sysfs_emit(buf, "0x%x\n", val);
> @@ -204,7 +204,7 @@ static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,
>       pm_runtime_get_sync(dev->parent);
>       raw_spin_lock(&drvdata->spinlock);
>       if (drvdata->config.hw_powered)
> -        cti_write_single_reg(drvdata, cti_attr->off, val);
> +        cti_write_single_reg(drvdata,  cti_reg_addr(drvdata, cti_attr->off), val);
>       raw_spin_unlock(&drvdata->spinlock);
>       pm_runtime_put_sync(dev->parent);
>       return size;
> @@ -267,7 +267,7 @@ static ssize_t cti_reg32_show(struct device *dev, char *buf,
>       raw_spin_lock(&drvdata->spinlock);
>       if ((reg_offset >= 0) && cti_active(config)) {
>           CS_UNLOCK(drvdata->base);
> -        val = readl_relaxed(drvdata->base + reg_offset);
> +        val = readl_relaxed(drvdata->base + cti_reg_addr(drvdata, reg_offset));
>           if (pcached_val)
>               *pcached_val = val;
>           CS_LOCK(drvdata->base);
> @@ -300,7 +300,7 @@ static ssize_t cti_reg32_store(struct device *dev, const char *buf,
> 
>       /* write through if offset and enabled */
>       if ((reg_offset >= 0) && cti_active(config))
> -        cti_write_single_reg(drvdata, reg_offset, val);
> +        cti_write_single_reg(drvdata,  cti_reg_addr(drvdata, reg_offset), val);
>       raw_spin_unlock(&drvdata->spinlock);
>       return size;
>   }
> @@ -389,7 +389,7 @@ static ssize_t inen_store(struct device *dev,
> 
>       /* write through if enabled */
>       if (cti_active(config))
> -        cti_write_single_reg(drvdata, CTIINEN(index), val);
> +        cti_write_single_reg(drvdata, cti_reg_addr_with_nr(drvdata, CTIINEN(0), index), val);
>       raw_spin_unlock(&drvdata->spinlock);
>       return size;
>   }
> @@ -428,7 +428,7 @@ static ssize_t outen_store(struct device *dev,
> 
>       /* write through if enabled */
>       if (cti_active(config))
> -        cti_write_single_reg(drvdata, CTIOUTEN(index), val);
> +        cti_write_single_reg(drvdata, cti_reg_addr_with_nr(drvdata, CTIOUTEN(0), index), val);
>       raw_spin_unlock(&drvdata->spinlock);
>       return size;
>   }
> @@ -470,7 +470,7 @@ static ssize_t appclear_store(struct device *dev,
> 
>       /* write through if enabled */
>       if (cti_active(config))
> -        cti_write_single_reg(drvdata, CTIAPPCLEAR, val);
> +        cti_write_single_reg(drvdata,  cti_reg_addr(drvdata, CTIAPPCLEAR), val);
>       raw_spin_unlock(&drvdata->spinlock);
>       return size;
>   }
> @@ -491,7 +491,7 @@ static ssize_t apppulse_store(struct device *dev,
> 
>       /* write through if enabled */
>       if (cti_active(config))
> -        cti_write_single_reg(drvdata, CTIAPPPULSE, val);
> +        cti_write_single_reg(drvdata,  cti_reg_addr(drvdata, CTIAPPPULSE), val);
>       raw_spin_unlock(&drvdata->spinlock);
>       return size;
>   }
> @@ -513,18 +513,36 @@ static struct attribute *coresight_cti_regs_attrs[] = {
>       &dev_attr_appclear.attr,
>       &dev_attr_apppulse.attr,
>       coresight_cti_reg(triginstatus, CTITRIGINSTATUS),
> +    coresight_cti_reg(triginstatus1, CTITRIGINSTATUS1),
> +    coresight_cti_reg(triginstatus2, CTITRIGINSTATUS2),
> +    coresight_cti_reg(triginstatus3, CTITRIGINSTATUS3),
>       coresight_cti_reg(trigoutstatus, CTITRIGOUTSTATUS),
> +    coresight_cti_reg(trigoutstatus1, CTITRIGOUTSTATUS1),
> +    coresight_cti_reg(trigoutstatus2, CTITRIGOUTSTATUS2),
> +    coresight_cti_reg(trigoutstatus3, CTITRIGOUTSTATUS3),
>       coresight_cti_reg(chinstatus, CTICHINSTATUS),
>       coresight_cti_reg(choutstatus, CTICHOUTSTATUS),
>   #ifdef CONFIG_CORESIGHT_CTI_INTEGRATION_REGS
>       coresight_cti_reg_rw(itctrl, CORESIGHT_ITCTRL),
>       coresight_cti_reg(ittrigin, ITTRIGIN),
> +    coresight_cti_reg(ittrigin1, ITTRIGIN1),
> +    coresight_cti_reg(ittrigin2, ITTRIGIN2),
> +    coresight_cti_reg(ittrigin3, ITTRIGIN3),
>       coresight_cti_reg(itchin, ITCHIN),
>       coresight_cti_reg_rw(ittrigout, ITTRIGOUT),
> +    coresight_cti_reg_rw(ittrigout1, ITTRIGOUT1),
> +    coresight_cti_reg_rw(ittrigout2, ITTRIGOUT2),
> +    coresight_cti_reg_rw(ittrigout3, ITTRIGOUT3),
>       coresight_cti_reg_rw(itchout, ITCHOUT),
>       coresight_cti_reg(itchoutack, ITCHOUTACK),
>       coresight_cti_reg(ittrigoutack, ITTRIGOUTACK),
> +    coresight_cti_reg(ittrigoutack1, ITTRIGOUTACK1),
> +    coresight_cti_reg(ittrigoutack2, ITTRIGOUTACK2),
> +    coresight_cti_reg(ittrigoutack3, ITTRIGOUTACK3),
>       coresight_cti_reg_wo(ittriginack, ITTRIGINACK),
> +    coresight_cti_reg_wo(ittriginack1, ITTRIGINACK1),
> +    coresight_cti_reg_wo(ittriginack2, ITTRIGINACK2),
> +    coresight_cti_reg_wo(ittriginack3, ITTRIGINACK3),
>       coresight_cti_reg_wo(itchinack, ITCHINACK),
>   #endif
>       NULL,
> @@ -1153,6 +1171,41 @@ int cti_create_cons_sysfs(struct device *dev, struct cti_drvdata *drvdata)
>       return err;
>   }
> 
> +  static umode_t coresight_cti_regs_is_visible(struct kobject *kobj,
> +                  struct attribute *attr, int n)
> +  {
> +    struct device *dev = container_of(kobj, struct device, kobj);
> +    struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +
> +    /* Mute QCOM CTI registers for standard CTI module */
> +    if (!drvdata->is_qcom_cti) {
> +        if (attr == coresight_cti_regs_attrs[10]
> +         || attr == coresight_cti_regs_attrs[11]
> +         || attr == coresight_cti_regs_attrs[12]
> +         || attr == coresight_cti_regs_attrs[14]
> +         || attr == coresight_cti_regs_attrs[15]
> +         || attr == coresight_cti_regs_attrs[16]
> +#ifdef CONFIG_CORESIGHT_CTI_INTEGRATION_REGS
> +         || attr == coresight_cti_regs_attrs[21]
> +         || attr == coresight_cti_regs_attrs[22]
> +         || attr == coresight_cti_regs_attrs[23]
> +         || attr == coresight_cti_regs_attrs[26]
> +         || attr == coresight_cti_regs_attrs[27]
> +         || attr == coresight_cti_regs_attrs[28]
> +         || attr == coresight_cti_regs_attrs[32]
> +         || attr == coresight_cti_regs_attrs[33]
> +         || attr == coresight_cti_regs_attrs[34]
> +         || attr == coresight_cti_regs_attrs[36]
> +         || attr == coresight_cti_regs_attrs[37]
> +         || attr == coresight_cti_regs_attrs[38]
> +#endif
> +         )
> +                  return 0;
> +          }
> +
> +          return attr->mode;
> +  }
> +
>   /* attribute and group sysfs tables. */
>   static const struct attribute_group coresight_cti_group = {
>       .attrs = coresight_cti_attrs,
> @@ -1166,6 +1219,7 @@ static const struct attribute_group coresight_cti_mgmt_group = {
>   static const struct attribute_group coresight_cti_regs_group = {
>       .attrs = coresight_cti_regs_attrs,
>       .name = "regs",
> +    .is_visible = coresight_cti_regs_is_visible,
>   };
> 
>   static const struct attribute_group coresight_cti_channels_group = {
> diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h
> index e7b88b07cffe..413d5ef483e8 100644
> --- a/drivers/hwtracing/coresight/coresight-cti.h
> +++ b/drivers/hwtracing/coresight/coresight-cti.h
> @@ -57,7 +57,7 @@ struct fwnode_handle;
>    * Max of in and out defined in the DEVID register.
>    * - pick up actual number used from .dts parameters if present.
>    */
> -#define CTIINOUTEN_MAX        32
> +#define CTIINOUTEN_MAX        128
> 
>   /**
>    * Group of related trigger signals
> @@ -181,6 +181,7 @@ struct cti_drvdata {
>       struct cti_config config;
>       struct list_head node;
>       void (*csdev_release)(struct device *dev);
> +    bool is_qcom_cti;
>   };
> 
>   /*
> diff --git a/drivers/hwtracing/coresight/qcom-cti.h b/drivers/hwtracing/coresight/qcom-cti.h
> new file mode 100644
> index 000000000000..aa41f9425b36
> --- /dev/null
> +++ b/drivers/hwtracing/coresight/qcom-cti.h
> @@ -0,0 +1,136 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +#include "coresight-cti.h"
> +
> +#define ARCHITECT_QCOM 0x477
> +
> +#define CTITRIGINSTATUS1 0x1000
> +#define CTITRIGINSTATUS2 0x1001
> +#define CTITRIGINSTATUS3 0x1002
> +
> +#define CTITRIGOUTSTATUS1 0x1003
> +#define CTITRIGOUTSTATUS2 0x1004
> +#define CTITRIGOUTSTATUS3 0x1005
> +
> +#define ITTRIGIN1 0x1006
> +#define ITTRIGIN2 0x1007
> +#define ITTRIGIN3 0x1008
> +
> +#define ITTRIGOUT1 0x1009
> +#define ITTRIGOUT2 0x100A
> +#define ITTRIGOUT3 0x100B
> +
> +#define ITTRIGINACK1 0x100C
> +#define ITTRIGINACK2 0x100D
> +#define ITTRIGINACK3 0x100E
> +
> +#define ITTRIGOUTACK1 0x100F
> +#define ITTRIGOUTACK2 0x1010
> +#define ITTRIGOUTACK3 0x1011
> +/* CTI programming registers */
> +#define    QCOM_CTIINTACK        0x020
> +#define    QCOM_CTIAPPSET        0x004
> +#define    QCOM_CTIAPPCLEAR    0x008
> +#define    QCOM_CTIAPPPULSE    0x00C
> +#define    QCOM_CTIINEN        0x400
> +#define    QCOM_CTIOUTEN        0x800
> +#define    QCOM_CTITRIGINSTATUS    0x040
> +#define    QCOM_CTITRIGINSTATUS1    0x044
> +#define    QCOM_CTITRIGINSTATUS2    0x048
> +#define    QCOM_CTITRIGINSTATUS3    0x04C
> +#define    QCOM_CTITRIGOUTSTATUS    0x060
> +#define    QCOM_CTITRIGOUTSTATUS1    0x064
> +#define    QCOM_CTITRIGOUTSTATUS2    0x068
> +#define    QCOM_CTITRIGOUTSTATUS3    0x06C
> +#define    QCOM_CTICHINSTATUS    0x080
> +#define    QCOM_CTICHOUTSTATUS    0x084
> +#define    QCOM_CTIGATE        0x088
> +#define    QCOM_ASICCTL        0x08c
> +/* Integration test registers */
> +#define    QCOM_ITCHINACK        0xE70
> +#define    QCOM_ITTRIGINACK    0xE80
> +#define    QCOM_ITTRIGINACK1    0xE84
> +#define    QCOM_ITTRIGINACK2    0xE88
> +#define    QCOM_ITTRIGINACK3    0xE8C
> +#define    QCOM_ITCHOUT        0xE74
> +#define    QCOM_ITTRIGOUT        0xEA0
> +#define    QCOM_ITTRIGOUT1        0xEA4
> +#define    QCOM_ITTRIGOUT2        0xEA8
> +#define    QCOM_ITTRIGOUT3        0xEAC
> +#define    QCOM_ITCHOUTACK        0xE78
> +#define    QCOM_ITTRIGOUTACK    0xEC0
> +#define    QCOM_ITTRIGOUTACK1    0xEC4
> +#define    QCOM_ITTRIGOUTACK2    0xEC8
> +#define    QCOM_ITTRIGOUTACK3    0xECC
> +#define    QCOM_ITCHIN        0xE7C
> +#define    QCOM_ITTRIGIN        0xEE0
> +#define    QCOM_ITTRIGIN1        0xEE4
> +#define    QCOM_ITTRIGIN2        0xEE8
> +#define    QCOM_ITTRIGIN3        0xEEC
> +
> +static noinline u32 cti_qcom_reg_off(u32 offset)
> +{
> +    switch (offset) {
> +        case CTIINTACK:        return QCOM_CTIINTACK;
> +        case CTIAPPSET:        return QCOM_CTIAPPSET;
> +        case CTIAPPCLEAR:    return QCOM_CTIAPPCLEAR;
> +        case CTIAPPPULSE:    return QCOM_CTIAPPPULSE;
> +        case CTIINEN(0):    return QCOM_CTIINEN;
> +        case CTIOUTEN(0):    return QCOM_CTIOUTEN;
> +        case CTITRIGINSTATUS:    return QCOM_CTITRIGINSTATUS;
> +        case CTITRIGINSTATUS1:    return QCOM_CTITRIGINSTATUS1;
> +        case CTITRIGINSTATUS2:    return QCOM_CTITRIGINSTATUS2;
> +        case CTITRIGINSTATUS3:    return QCOM_CTITRIGINSTATUS3;
> +        case CTITRIGOUTSTATUS:    return QCOM_CTITRIGOUTSTATUS;
> +        case CTITRIGOUTSTATUS1:    return QCOM_CTITRIGOUTSTATUS1;
> +        case CTITRIGOUTSTATUS2:    return QCOM_CTITRIGOUTSTATUS2;
> +        case CTITRIGOUTSTATUS3:    return QCOM_CTITRIGOUTSTATUS3;
> +        case CTICHINSTATUS:        return QCOM_CTICHINSTATUS;
> +        case CTICHOUTSTATUS:    return QCOM_CTICHOUTSTATUS;
> +        case CTIGATE:        return QCOM_CTIGATE;
> +        case ASICCTL:        return QCOM_ASICCTL;
> +        case ITCHINACK:        return QCOM_ITCHINACK;
> +        case ITTRIGINACK:    return QCOM_ITTRIGINACK;
> +        case ITTRIGINACK1:    return QCOM_ITTRIGINACK1;
> +        case ITTRIGINACK2:    return QCOM_ITTRIGINACK2;
> +        case ITTRIGINACK3:    return QCOM_ITTRIGINACK3;
> +        case ITCHOUT:        return QCOM_ITCHOUT;
> +        case ITTRIGOUT:        return QCOM_ITTRIGOUT;
> +        case ITTRIGOUT1:    return QCOM_ITTRIGOUT1;
> +        case ITTRIGOUT2:    return QCOM_ITTRIGOUT2;
> +        case ITTRIGOUT3:    return QCOM_ITTRIGOUT3;
> +        case ITCHOUTACK:    return QCOM_ITCHOUTACK;
> +        case ITTRIGOUTACK:    return QCOM_ITTRIGOUTACK;
> +        case ITTRIGOUTACK1:    return QCOM_ITTRIGOUTACK1;
> +        case ITTRIGOUTACK2:    return QCOM_ITTRIGOUTACK2;
> +        case ITTRIGOUTACK3:    return QCOM_ITTRIGOUTACK3;
> +        case ITCHIN:               return QCOM_ITCHIN;
> +        case ITTRIGIN:            return QCOM_ITTRIGIN;
> +        case ITTRIGIN1:        return QCOM_ITTRIGIN1;
> +        case ITTRIGIN2:        return QCOM_ITTRIGIN2;
> +        case ITTRIGIN3:        return QCOM_ITTRIGIN3;
> +        default:
> +                    WARN(1, "Unknown offset=%u\n", offset);
> +                    return 0;
> +    }
> +
> +    return 0;
> +}
> +
> +static u32 cti_reg_addr_with_nr(struct cti_drvdata *drvdata,
> +                                          u32 reg, u32 nr)
> +{
> +    /* convert to qcom specific offset */
> +    if (unlikely(drvdata->is_qcom_cti))

Hi yingchao,

For standard ARM cti, it's unlikely to true, but for qcom_cti, it's 
likely to true, so I think the compile predication here is not mandatory?

Thanks,
Jie

> +        reg = cti_qcom_reg_off(reg);
> +
> +    return reg + sizeof(u32) * nr;
> +}
> +
> +static u32 cti_reg_addr(struct cti_drvdata *drvdata, u32 reg)
> +{
> +        return cti_reg_addr_with_nr(drvdata, reg, 0);
> +}
> +
> 
> 



From buaajxlj at 163.com  Tue Dec  9 02:02:17 2025
From: buaajxlj at 163.com (Liang Jie)
Date: Tue,  9 Dec 2025 18:02:17 +0800
Subject: [PATCH] pinctrl: mediatek: make devm allocations safer and clearer in mtk_eint_do_init()
Message-ID: <20251209100217.167581-1-buaajxlj@163.com>

From: Liang Jie <liangjie at lixiang.com>

mtk_eint_do_init() allocates several pointer arrays which are then
populated in a per-instance loop and freed on error. The arrays are
currently allocated with devm_kmalloc(), so their entries are left
uninitialised until the per-instance allocations succeed.

On a failure in the middle of the loop, the error path iterates over
the full nbase range and calls devm_kfree() on each element. For
indices which were never initialised, the corresponding array entries
contain stack garbage. If any of those happen to be non-zero,
devm_kfree() will pass them to devres_destroy(), which will WARN
because there is no matching devm_kmalloc() resource for such bogus
pointers.

Improve the robustness and readability by:

  - Using devm_kcalloc() for the pointer arrays so that all entries
    start as NULL, ensuring that only genuinely initialised elements
    may be freed and preventing spurious WARN_ON()s in the error path.
  - Switching the allocations to sizeof(*ptr) / sizeof(**ptr) forms,
    avoiding hard-coded element types and making the code more resilient
    to future type changes.
  - Dropping the redundant NULL checks before devm_kfree(), as
    devm_kfree() safely handles NULL pointers.

The functional behaviour in the successful initialisation path remains
unchanged, while the error handling becomes simpler and less
error-prone.

Reviewed-by: fanggeng <fanggeng at lixiang.com>
Signed-off-by: Liang Jie <liangjie at lixiang.com>
---
 drivers/pinctrl/mediatek/mtk-eint.c | 29 +++++++++++++++++------------
 1 file changed, 17 insertions(+), 12 deletions(-)

diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c
index 9f175c73613f..2ea0902b4f66 100644
--- a/drivers/pinctrl/mediatek/mtk-eint.c
+++ b/drivers/pinctrl/mediatek/mtk-eint.c
@@ -539,24 +539,32 @@ int mtk_eint_do_init(struct mtk_eint *eint, struct mtk_eint_pin *eint_pin)
 		}
 	}
 
-	eint->pin_list = devm_kmalloc(eint->dev, eint->nbase * sizeof(u16 *), GFP_KERNEL);
+	eint->pin_list = devm_kcalloc(eint->dev, eint->nbase,
+				      sizeof(*eint->pin_list), GFP_KERNEL);
 	if (!eint->pin_list)
 		goto err_pin_list;
 
-	eint->wake_mask = devm_kmalloc(eint->dev, eint->nbase * sizeof(u32 *), GFP_KERNEL);
+	eint->wake_mask = devm_kcalloc(eint->dev, eint->nbase,
+				       sizeof(*eint->wake_mask), GFP_KERNEL);
 	if (!eint->wake_mask)
 		goto err_wake_mask;
 
-	eint->cur_mask = devm_kmalloc(eint->dev, eint->nbase * sizeof(u32 *), GFP_KERNEL);
+	eint->cur_mask = devm_kcalloc(eint->dev, eint->nbase,
+				      sizeof(*eint->cur_mask), GFP_KERNEL);
 	if (!eint->cur_mask)
 		goto err_cur_mask;
 
 	for (i = 0; i < eint->nbase; i++) {
-		eint->pin_list[i] = devm_kzalloc(eint->dev, eint->base_pin_num[i] * sizeof(u16),
+		eint->pin_list[i] = devm_kzalloc(eint->dev,
+						 eint->base_pin_num[i] * sizeof(**eint->pin_list),
 						 GFP_KERNEL);
 		port = DIV_ROUND_UP(eint->base_pin_num[i], 32);
-		eint->wake_mask[i] = devm_kzalloc(eint->dev, port * sizeof(u32), GFP_KERNEL);
-		eint->cur_mask[i] = devm_kzalloc(eint->dev, port * sizeof(u32), GFP_KERNEL);
+		eint->wake_mask[i] = devm_kzalloc(eint->dev,
+						  port * sizeof(**eint->wake_mask),
+						  GFP_KERNEL);
+		eint->cur_mask[i] = devm_kzalloc(eint->dev,
+						 port * sizeof(**eint->cur_mask),
+						 GFP_KERNEL);
 		if (!eint->pin_list[i] || !eint->wake_mask[i] || !eint->cur_mask[i])
 			goto err_eint;
 	}
@@ -592,12 +600,9 @@ int mtk_eint_do_init(struct mtk_eint *eint, struct mtk_eint_pin *eint_pin)
 
 err_eint:
 	for (i = 0; i < eint->nbase; i++) {
-		if (eint->cur_mask[i])
-			devm_kfree(eint->dev, eint->cur_mask[i]);
-		if (eint->wake_mask[i])
-			devm_kfree(eint->dev, eint->wake_mask[i]);
-		if (eint->pin_list[i])
-			devm_kfree(eint->dev, eint->pin_list[i]);
+		devm_kfree(eint->dev, eint->cur_mask[i]);
+		devm_kfree(eint->dev, eint->wake_mask[i]);
+		devm_kfree(eint->dev, eint->pin_list[i]);
 	}
 	devm_kfree(eint->dev, eint->cur_mask);
 err_cur_mask:
-- 
2.25.1



From jbrunet at baylibre.com  Tue Dec  9 02:16:52 2025
From: jbrunet at baylibre.com (Jerome Brunet)
Date: Tue, 09 Dec 2025 11:16:52 +0100
Subject: [PATCH v6 2/5] dt-bindings: clock: add Amlogic T7 SCMI clock
 controller
In-Reply-To: <4f5ec838-f8d6-4c3b-94f2-b2a60cfe64ec@kernel.org> (Krzysztof
	Kozlowski's message of "Tue, 9 Dec 2025 07:01:44 +0100")
References: <20251204053635.1234150-1-jian.hu@amlogic.com>
	<20251204053635.1234150-3-jian.hu@amlogic.com>
	<20251208-independent-warping-macaw-74a169@quoll>
	<dd90b445-bafb-46d4-8cec-e0877cf425b3@amlogic.com>
	<4f5ec838-f8d6-4c3b-94f2-b2a60cfe64ec@kernel.org>
Message-ID: <1jy0ncvu23.fsf@starbuckisacylon.baylibre.com>

On Tue 09 Dec 2025 at 07:01, Krzysztof Kozlowski <krzk at kernel.org> wrote:

> On 08/12/2025 09:40, Jian Hu wrote:
>> Hi, Krzysztof
>> 
>> 
>> Thans for your review.
>> 
>> On 12/8/2025 2:17 PM, Krzysztof Kozlowski wrote:
>>> [ EXTERNAL EMAIL ]
>>>
>>> On Thu, Dec 04, 2025 at 01:36:31PM +0800, Jian Hu wrote:
>>>> Add DT bindings for the SCMI clock controller of the Amlogic T7 SoC family.
>>>>
>>>> Signed-off-by: Jian Hu <jian.hu at amlogic.com>
>>>> Acked-by: Rob Herring (Arm) <robh at kernel.org>
>>>> ---
>>>>   include/dt-bindings/clock/amlogic,t7-scmi.h | 47 +++++++++++++++++++++
>>>>   1 file changed, 47 insertions(+)
>>>>   create mode 100644 include/dt-bindings/clock/amlogic,t7-scmi.h
>>>>
>>> Where is any binding doc for this? Why is this a separate patch?
>> 
>> 
>> The ARM SCMI device tree binding specification is located at 
>> ./Documentation/devicetree/bindings/firmware/arm,scmi.yaml.
>
> Then git grep for the file name - there is no such compatible. Are you
> sure you follow writing bindings doc?
>
> Think how are you going to use these values. You will have phandle, yes?
> To some controller, yes? Which one?

For the C3 (I believe the T7 is the same), the compatible being used is
"arm,scmi-smc". It is a generic one documented here:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/firmware/arm,scmi.yaml?h=v6.18#n202

The phandle used is a subnode of that, to clock protocol:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi?h=v6.18#n116

Same things is done on imx, stm and rockchip platforms from what I can
see.

Jian is just adding the arbitrary IDs used to identify the clocks in the
FW. I don't think there is anything out of the ordirnary here.

Is there something else Rob and I missed reviewing this ?

>
>> 
>> Certain secure clocks on the T7 rely on the ARM SCMI driver stack, which 
>> is officially supported by ARM.
>> 
>> The kernel-side SCMI client implementation resides in 
>> ./drivers/firmware/arm_scmi/.
>> 
>> To enable ARM SCMI on T7, three components are needed:
>> 
>> - Kernel-side definition of ARM SCMI clock indices (this patch addresses 
>> this component);
>> - SCMI server implementation in the ARM Trusted Firmware (ATF) running 
>> at Exception Level 3 (EL3), which has been integrated into the bootloader;
>> - Device Tree Source (DTS) configuration for ARM SCMI clock nodes (the 
>> DTS changes will be submitted after the T7 clock driver patches are 
>> merged upstream).
>
> So silently you keep the users hidden? No, I want to see the users.
>

Is there a new requirement to submit the DTS file changes along with the
driver changes now ?

This has never been case before, especially since the changes are merged
through different trees.

>
> Best regards,
> Krzysztof

-- 
Jerome


From francesco at dolcini.it  Tue Dec  9 02:17:48 2025
From: francesco at dolcini.it (Francesco Dolcini)
Date: Tue,  9 Dec 2025 11:17:48 +0100
Subject: [PATCH v1 0/3] arm64: dts: freescale: imx8mp-(verdin|toradex-smarc): Add HDMI audio support
Message-ID: <20251209101754.54067-1-francesco@dolcini.it>

From: Francesco Dolcini <francesco.dolcini at toradex.com>

Add support for HDMI audio on Verdin and Toradex SMARC iMX8M Plus boards, as
done in commit b21f87b8322f ("arm64: dts: imx8mp-evk: enable hdmi_pai device")
on the NXP i.MX8MP EVK board.

In addition a small cleanup on spurious comments.

Francesco Dolcini (3):
  arm64: dts: freescale: imx8mp-verdin: Remove obsolete TODO comments
  arm64: dts: freescale: imx8mp-verdin: enable hdmi_pai device
  arm64: dts: freescale: imx8mp-toradex-smarc: enable hdmi_pai device

 arch/arm64/boot/dts/freescale/imx8mp-toradex-smarc-dev.dts | 4 ++++
 arch/arm64/boot/dts/freescale/imx8mp-verdin-dahlia.dtsi    | 4 ++++
 arch/arm64/boot/dts/freescale/imx8mp-verdin-dev.dtsi       | 4 ++++
 arch/arm64/boot/dts/freescale/imx8mp-verdin-mallow.dtsi    | 4 ++++
 arch/arm64/boot/dts/freescale/imx8mp-verdin-yavia.dtsi     | 4 ++++
 arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi           | 4 ----
 6 files changed, 20 insertions(+), 4 deletions(-)

-- 
2.47.3



From francesco at dolcini.it  Tue Dec  9 02:17:49 2025
From: francesco at dolcini.it (Francesco Dolcini)
Date: Tue,  9 Dec 2025 11:17:49 +0100
Subject: [PATCH v1 1/3] arm64: dts: freescale: imx8mp-verdin: Remove obsolete TODO comments
In-Reply-To: <20251209101754.54067-1-francesco@dolcini.it>
References: <20251209101754.54067-1-francesco@dolcini.it>
Message-ID: <20251209101754.54067-2-francesco@dolcini.it>

From: Francesco Dolcini <francesco.dolcini at toradex.com>

Remove obsolete TODO comments, I2S interface is supported since Linux v6.6.

Signed-off-by: Francesco Dolcini <francesco.dolcini at toradex.com>
---
 arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi
index d43ba0087126..d31f8082394f 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi
@@ -832,10 +832,6 @@ &pwm3 {
 	#pwm-cells = <3>;
 };
 
-/* TODO: Verdin I2S_1 */
-
-/* TODO: Verdin I2S_2 */
-
 &snvs_pwrkey {
 	status = "okay";
 };
-- 
2.47.3



From francesco at dolcini.it  Tue Dec  9 02:17:50 2025
From: francesco at dolcini.it (Francesco Dolcini)
Date: Tue,  9 Dec 2025 11:17:50 +0100
Subject: [PATCH v1 2/3] arm64: dts: freescale: imx8mp-verdin: enable hdmi_pai device
In-Reply-To: <20251209101754.54067-1-francesco@dolcini.it>
References: <20251209101754.54067-1-francesco@dolcini.it>
Message-ID: <20251209101754.54067-3-francesco@dolcini.it>

From: Francesco Dolcini <francesco.dolcini at toradex.com>

Enable the hdmi_pai device on the various iMX8M Plus Verdin boards that
feature the related HDMI interface.

The hdmi_pai device, together with aud2htx module, hdmi_pai and hdmi
controller compose the HDMI audio pipeline.

See commit b21f87b8322f ("arm64: dts: imx8mp-evk: enable hdmi_pai
device") for the equivalent change on the NXP i.MX8MP EVK board.

Signed-off-by: Francesco Dolcini <francesco.dolcini at toradex.com>
---
 arch/arm64/boot/dts/freescale/imx8mp-verdin-dahlia.dtsi | 4 ++++
 arch/arm64/boot/dts/freescale/imx8mp-verdin-dev.dtsi    | 4 ++++
 arch/arm64/boot/dts/freescale/imx8mp-verdin-mallow.dtsi | 4 ++++
 arch/arm64/boot/dts/freescale/imx8mp-verdin-yavia.dtsi  | 4 ++++
 4 files changed, 16 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-verdin-dahlia.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-verdin-dahlia.dtsi
index 1493319aa748..0e218e6b8e29 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-verdin-dahlia.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-verdin-dahlia.dtsi
@@ -112,6 +112,10 @@ &gpio4 {
 };
 
 /* Verdin HDMI_1 */
+&hdmi_pai {
+	status = "okay";
+};
+
 &hdmi_pvi {
 	status = "okay";
 };
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-verdin-dev.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-verdin-dev.dtsi
index a38e7c947a42..72a4f846d694 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-verdin-dev.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-verdin-dev.dtsi
@@ -121,6 +121,10 @@ &gpio_expander_21 {
 };
 
 /* Verdin HDMI_1 */
+&hdmi_pai {
+	status = "okay";
+};
+
 &hdmi_pvi {
 	status = "okay";
 };
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-verdin-mallow.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-verdin-mallow.dtsi
index 11cf3bdc95c4..846b36706821 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-verdin-mallow.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-verdin-mallow.dtsi
@@ -109,6 +109,10 @@ &flexcan2 {
 };
 
 /* Verdin HDMI_1 */
+&hdmi_pai {
+	status = "okay";
+};
+
 &hdmi_pvi {
 	status = "okay";
 };
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-verdin-yavia.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-verdin-yavia.dtsi
index cc389cda2af2..f3d28e23ba6c 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-verdin-yavia.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-verdin-yavia.dtsi
@@ -123,6 +123,10 @@ &gpio4 {
 };
 
 /* Verdin HDMI_1 */
+&hdmi_pai {
+	status = "okay";
+};
+
 &hdmi_pvi {
 	status = "okay";
 };
-- 
2.47.3



From francesco at dolcini.it  Tue Dec  9 02:17:51 2025
From: francesco at dolcini.it (Francesco Dolcini)
Date: Tue,  9 Dec 2025 11:17:51 +0100
Subject: [PATCH v1 3/3] arm64: dts: freescale: imx8mp-toradex-smarc: enable hdmi_pai device
In-Reply-To: <20251209101754.54067-1-francesco@dolcini.it>
References: <20251209101754.54067-1-francesco@dolcini.it>
Message-ID: <20251209101754.54067-4-francesco@dolcini.it>

From: Francesco Dolcini <francesco.dolcini at toradex.com>

Enable the hdmi_pai device on the Toradex SMARC iMX8M Plus Development
boards.

The hdmi_pai device, together with aud2htx module, hdmi_pai and hdmi
controller compose the HDMI audio pipeline.

See commit b21f87b8322f ("arm64: dts: imx8mp-evk: enable hdmi_pai
device") for the equivalent change on the NXP i.MX8MP EVK board.

Signed-off-by: Francesco Dolcini <francesco.dolcini at toradex.com>
---
 arch/arm64/boot/dts/freescale/imx8mp-toradex-smarc-dev.dts | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-toradex-smarc-dev.dts b/arch/arm64/boot/dts/freescale/imx8mp-toradex-smarc-dev.dts
index 6f9dcd3a75c8..b31de307093c 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-toradex-smarc-dev.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-toradex-smarc-dev.dts
@@ -107,6 +107,10 @@ &gpio4 {
 	pinctrl-0 = <&pinctrl_gpio4>, <&pinctrl_gpio6>;
 };
 
+&hdmi_pai {
+	status = "okay";
+};
+
 &hdmi_pvi {
 	status = "okay";
 };
-- 
2.47.3



From benjamin.gaignard at collabora.com  Tue Dec  9 02:34:01 2025
From: benjamin.gaignard at collabora.com (Benjamin Gaignard)
Date: Tue,  9 Dec 2025 11:34:01 +0100
Subject: [PATCH v2] media: verisilicon: AV1: Fix enable cdef computation
Message-ID: <20251209103401.21943-1-benjamin.gaignard@collabora.com>

If all the fields of the CDEF parameters are zero (which is the default),
then av1_enable_cdef register needs to be unset
(despite the V4L2_AV1_SEQUENCE_FLAG_ENABLE_CDEF possibly being set).

Signed-off-by: Benjamin Gaignard <benjamin.gaignard at collabora.com>
Fixes: 727a400686a2c ("media: verisilicon: Add Rockchip AV1 decoder")
Reported-by: Jianfeng Liu <liujianfeng1994 at gmail.com>
Closes: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/4786
Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
---
 .../platform/verisilicon/rockchip_vpu981_hw_av1_dec.c  | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
index e4703bb6be7c..f4f7cb45b1f1 100644
--- a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
+++ b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
@@ -1396,8 +1396,16 @@ static void rockchip_vpu981_av1_dec_set_cdef(struct hantro_ctx *ctx)
 	u16 luma_sec_strength = 0;
 	u32 chroma_pri_strength = 0;
 	u16 chroma_sec_strength = 0;
+	bool enable_cdef;
 	int i;
 
+	enable_cdef = !(cdef->bits == 0 &&
+			cdef->damping_minus_3 == 0 &&
+			cdef->y_pri_strength[0] == 0 &&
+			cdef->y_sec_strength[0] == 0 &&
+			cdef->uv_pri_strength[0] == 0 &&
+			cdef->uv_sec_strength[0] == 0);
+	hantro_reg_write(vpu, &av1_enable_cdef, enable_cdef);
 	hantro_reg_write(vpu, &av1_cdef_bits, cdef->bits);
 	hantro_reg_write(vpu, &av1_cdef_damping, cdef->damping_minus_3);
 
@@ -1953,8 +1961,6 @@ static void rockchip_vpu981_av1_dec_set_parameters(struct hantro_ctx *ctx)
 			 !!(ctrls->frame->flags & V4L2_AV1_FRAME_FLAG_SHOW_FRAME));
 	hantro_reg_write(vpu, &av1_switchable_motion_mode,
 			 !!(ctrls->frame->flags & V4L2_AV1_FRAME_FLAG_IS_MOTION_MODE_SWITCHABLE));
-	hantro_reg_write(vpu, &av1_enable_cdef,
-			 !!(ctrls->sequence->flags & V4L2_AV1_SEQUENCE_FLAG_ENABLE_CDEF));
 	hantro_reg_write(vpu, &av1_allow_masked_compound,
 			 !!(ctrls->sequence->flags
 			    & V4L2_AV1_SEQUENCE_FLAG_ENABLE_MASKED_COMPOUND));
-- 
2.43.0



From benjamin.gaignard at collabora.com  Tue Dec  9 02:34:17 2025
From: benjamin.gaignard at collabora.com (Benjamin Gaignard)
Date: Tue,  9 Dec 2025 11:34:17 +0100
Subject: [PATCH v2] media: verisilicon: AV1: Fix tx mode bit setting
Message-ID: <20251209103417.21966-1-benjamin.gaignard@collabora.com>

AV1 specification describes 3 possibles tx modes: 4x4 only,
largest and select.
Hardware allows 5 possibles tx modes: 4x4 only, 8x8, 16x16,
32x32 and select.
Since the both aren't exactly matching we need to add a mapping
function to set the correct mode on hardware.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard at collabora.com>
Fixes: 727a400686a2c ("media: verisilicon: Add Rockchip AV1 decoder")
---
 .../verisilicon/rockchip_vpu981_hw_av1_dec.c  | 27 ++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
index f4f7cb45b1f1..f52b8208e6b9 100644
--- a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
+++ b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
@@ -72,6 +72,14 @@
 		: AV1_DIV_ROUND_UP_POW2((_value_), (_n_)));		\
 })
 
+enum rockchip_av1_tx_mode {
+	ROCKCHIP_AV1_TX_MODE_ONLY_4X4	= 0,
+	ROCKCHIP_AV1_TX_MODE_8X8	= 1,
+	ROCKCHIP_AV1_TX_MODE_16x16	= 2,
+	ROCKCHIP_AV1_TX_MODE_32x32	= 3,
+	ROCKCHIP_AV1_TX_MODE_SELECT	= 4,
+};
+
 struct rockchip_av1_film_grain {
 	u8 scaling_lut_y[256];
 	u8 scaling_lut_cb[256];
@@ -1935,11 +1943,26 @@ static void rockchip_vpu981_av1_dec_set_reference_frames(struct hantro_ctx *ctx)
 	rockchip_vpu981_av1_dec_set_other_frames(ctx);
 }
 
+static int rockchip_vpu981_av1_get_hardware_tx_mode(enum v4l2_av1_tx_mode tx_mode)
+{
+	switch (tx_mode) {
+	case V4L2_AV1_TX_MODE_ONLY_4X4:
+		return ROCKCHIP_AV1_TX_MODE_ONLY_4X4;
+	case V4L2_AV1_TX_MODE_LARGEST:
+		return ROCKCHIP_AV1_TX_MODE_32x32;
+	case V4L2_AV1_TX_MODE_SELECT:
+		return ROCKCHIP_AV1_TX_MODE_SELECT;
+	}
+
+	return ROCKCHIP_AV1_TX_MODE_32x32;
+}
+
 static void rockchip_vpu981_av1_dec_set_parameters(struct hantro_ctx *ctx)
 {
 	struct hantro_dev *vpu = ctx->dev;
 	struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
 	struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
+	int tx_mode;
 
 	hantro_reg_write(vpu, &av1_skip_mode,
 			 !!(ctrls->frame->flags & V4L2_AV1_FRAME_FLAG_SKIP_MODE_PRESENT));
@@ -2005,7 +2028,9 @@ static void rockchip_vpu981_av1_dec_set_parameters(struct hantro_ctx *ctx)
 			 !!(ctrls->frame->flags & V4L2_AV1_FRAME_FLAG_ALLOW_HIGH_PRECISION_MV));
 	hantro_reg_write(vpu, &av1_comp_pred_mode,
 			 (ctrls->frame->flags & V4L2_AV1_FRAME_FLAG_REFERENCE_SELECT) ? 2 : 0);
-	hantro_reg_write(vpu, &av1_transform_mode, (ctrls->frame->tx_mode == 1) ? 3 : 4);
+
+	tx_mode = rockchip_vpu981_av1_get_hardware_tx_mode(ctrls->frame->tx_mode);
+	hantro_reg_write(vpu, &av1_transform_mode, tx_mode);
 	hantro_reg_write(vpu, &av1_max_cb_size,
 			 (ctrls->sequence->flags
 			  & V4L2_AV1_SEQUENCE_FLAG_USE_128X128_SUPERBLOCK) ? 7 : 6);
-- 
2.43.0



From robh at kernel.org  Tue Dec  9 02:38:20 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Tue, 09 Dec 2025 04:38:20 -0600
Subject: [PATCH 1/7] ASoC: dt-bindings: convert tdm-slot to YAML
In-Reply-To: <20251209-tdm-idle-slots-v1-1-38dabf6bc01e@gmail.com>
References: <20251209-tdm-idle-slots-v1-0-38dabf6bc01e@gmail.com>
 <20251209-tdm-idle-slots-v1-1-38dabf6bc01e@gmail.com>
Message-ID: <176527670059.4068182.12113080556311230046.robh@kernel.org>


On Tue, 09 Dec 2025 19:31:14 +1000, James Calligeros wrote:
> This schema was still in plaintext form. Convert to YAML format.
> 
> Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
> ---
>  .../bindings/sound/tdm-slot.txt          | 29 ---------------------
>  .../bindings/sound/tdm-slot.yaml         | 34 +++++++++++++++++++++++++
>  2 files changed, 34 insertions(+), 29 deletions(-)
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/sound/tdm-slot.yaml: 'oneOf' conditional failed, one must be fixed:
	'unevaluatedProperties' is a required property
	'additionalProperties' is a required property
	hint: Either unevaluatedProperties or additionalProperties must be present
	from schema $id: http://devicetree.org/meta-schemas/core.yaml
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/sound/tdm-slot.yaml: 'anyOf' conditional failed, one must be fixed:
	'properties' is a required property
	'patternProperties' is a required property
	hint: Metaschema for devicetree binding documentation
	from schema $id: http://devicetree.org/meta-schemas/core.yaml

doc reference errors (make refcheckdocs):

See https://patchwork.kernel.org/project/devicetree/patch/20251209-tdm-idle-slots-v1-1-38dabf6bc01e at gmail.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.



From alexander.stein at ew.tq-group.com  Tue Dec  9 02:53:07 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Tue,  9 Dec 2025 11:53:07 +0100
Subject: [PATCH v2 1/8] arm64: dts: tqma8mpql-mba8mpxl: Adjust copyright text format
In-Reply-To: <20251209105318.977102-1-alexander.stein@ew.tq-group.com>
References: <20251209105318.977102-1-alexander.stein@ew.tq-group.com>
Message-ID: <20251209105318.977102-2-alexander.stein@ew.tq-group.com>

Replace personal mail address by mailing list.

Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
index 59642a8a2c445..0605cf2faf83b 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
@@ -1,7 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0-or-later OR MIT
 /*
- * Copyright 2021-2022 TQ-Systems GmbH
- * Author: Alexander Stein <alexander.stein at tq-group.com>
+ * Copyright 2021-2025 TQ-Systems GmbH <linux at ew.tq-group.com>,
+ * D-82229 Seefeld, Germany.
+ * Author: Alexander Stein
  */
 
 /dts-v1/;
-- 
2.43.0



From alexander.stein at ew.tq-group.com  Tue Dec  9 02:53:06 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Tue,  9 Dec 2025 11:53:06 +0100
Subject: [PATCH v2 0/8] TQMa8MPxL DT fixes
Message-ID: <20251209105318.977102-1-alexander.stein@ew.tq-group.com>

Hi,

this seris includes small fixes for TQMa8MPxL both on MBa8MPxL and
MBa8MP-RAS314. The ethernet IRQ type has been changed to level-low and CEC
pad configuration has been fixed to use open-drain output.
For both boards the HDMI audio output support has been added as well as
the ENET event2 signal on MBa8MPxL, which can be enabled using
/sys/class/ptp/ptp1/period.

Best regards,
Alexander

Changes in v2:
* Collected R-b
* Fixed typos

Alexander Stein (8):
  arm64: dts: tqma8mpql-mba8mpxl: Adjust copyright text format
  arm64: dts: tqma8mpql-mba8mpxl: Fix Ethernet PHY IRQ support
  arm64: dts: tqma8mpql-mba8mpxl: Fix HDMI CEC pad control settings
  arm64: dts: tqma8mpql-mba8mpxl: Add HDMI audio output support
  arm64: dts: tqma8mpql-mba8mpxl: Configure IEEE 1588 event out signal
  arm64: dts: tqma8mpql-mba8mp-ras314: Fix Ethernet PHY IRQ support
  arm64: dts: tqma8mpql-mba8mp-ras314: Fix HDMI CEC pad control settings
  arm64: dts: tqma8mpql-mba8mp-ras314: Add HDMI audio output support

 .../imx8mp-tqma8mpql-mba8mp-ras314.dts        | 21 ++++++++++++--
 .../freescale/imx8mp-tqma8mpql-mba8mpxl.dts   | 29 +++++++++++++++----
 2 files changed, 41 insertions(+), 9 deletions(-)

-- 
2.43.0



From alexander.stein at ew.tq-group.com  Tue Dec  9 02:53:08 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Tue,  9 Dec 2025 11:53:08 +0100
Subject: [PATCH v2 2/8] arm64: dts: tqma8mpql-mba8mpxl: Fix Ethernet PHY IRQ support
In-Reply-To: <20251209105318.977102-1-alexander.stein@ew.tq-group.com>
References: <20251209105318.977102-1-alexander.stein@ew.tq-group.com>
Message-ID: <20251209105318.977102-3-alexander.stein@ew.tq-group.com>

Ethernet PHY interrupt mode is level triggered. Adjust the mode
accordingly.

Reviewed-by: Andrew Lunn <andrew at lunn.ch>
Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
index 0605cf2faf83b..ff2bacf24bfd2 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
@@ -345,7 +345,7 @@ ethphy3: ethernet-phy at 3 {
 			reset-deassert-us = <50000>;
 			enet-phy-lane-no-swap;
 			interrupt-parent = <&gpio4>;
-			interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
+			interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
 		};
 	};
 };
@@ -375,7 +375,7 @@ ethphy0: ethernet-phy at 0 {
 			reset-deassert-us = <50000>;
 			enet-phy-lane-no-swap;
 			interrupt-parent = <&gpio4>;
-			interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
+			interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
 		};
 	};
 };
-- 
2.43.0



From alexander.stein at ew.tq-group.com  Tue Dec  9 02:53:11 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Tue,  9 Dec 2025 11:53:11 +0100
Subject: [PATCH v2 5/8] arm64: dts: tqma8mpql-mba8mpxl: Configure IEEE 1588 event out signal
In-Reply-To: <20251209105318.977102-1-alexander.stein@ew.tq-group.com>
References: <20251209105318.977102-1-alexander.stein@ew.tq-group.com>
Message-ID: <20251209105318.977102-6-alexander.stein@ew.tq-group.com>

The event out signal on channel 2 is available on pad SAI2_RXD0 which is
connected to X63 pin 13.

Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
index ac889a69da69a..fdfe246c56407 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
@@ -807,7 +807,8 @@ pinctrl_eqos: eqosgrp {
 			   <MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2			0x12>,
 			   <MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3			0x12>,
 			   <MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL		0x12>,
-			   <MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK	0x14>;
+			   <MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK	0x14>,
+			   <MX8MP_IOMUXC_SAI2_RXD0__ENET_QOS_1588_EVENT2_OUT		0x16>;
 	};
 
 	pinctrl_eqos_event: eqosevtgrp {
-- 
2.43.0



From alexander.stein at ew.tq-group.com  Tue Dec  9 02:53:14 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Tue,  9 Dec 2025 11:53:14 +0100
Subject: [PATCH v2 8/8] arm64: dts: tqma8mpql-mba8mp-ras314: Add HDMI audio output support
In-Reply-To: <20251209105318.977102-1-alexander.stein@ew.tq-group.com>
References: <20251209105318.977102-1-alexander.stein@ew.tq-group.com>
Message-ID: <20251209105318.977102-9-alexander.stein@ew.tq-group.com>

Add the HDMI audio soundcard and enable necessary nodes.

Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 .../freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts  | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts
index 30f0e81c4be00..6e927ff1e967a 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts
@@ -159,6 +159,17 @@ sound {
 			"Headphone Jack", "HPL",
 			"Headphone Jack", "HPR";
 	};
+
+	sound-hdmi {
+		compatible = "fsl,imx-audio-hdmi";
+		model = "audio-hdmi";
+		audio-cpu = <&aud2htx>;
+		hdmi-out;
+	};
+};
+
+&aud2htx {
+	status = "okay";
 };
 
 &ecspi3 {
@@ -335,6 +346,10 @@ &gpt3 {
 	status = "disabled";
 };
 
+&hdmi_pai {
+	status = "okay";
+};
+
 &hdmi_pvi {
 	status = "okay";
 };
-- 
2.43.0



From alexander.stein at ew.tq-group.com  Tue Dec  9 02:53:09 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Tue,  9 Dec 2025 11:53:09 +0100
Subject: [PATCH v2 3/8] arm64: dts: tqma8mpql-mba8mpxl: Fix HDMI CEC pad control settings
In-Reply-To: <20251209105318.977102-1-alexander.stein@ew.tq-group.com>
References: <20251209105318.977102-1-alexander.stein@ew.tq-group.com>
Message-ID: <20251209105318.977102-4-alexander.stein@ew.tq-group.com>

As per datasheet of the HDMI protection IC the CEC_IC pin has been
configured as open-drain.

Fixes: 418d1d840e42 ("arm64: dts: freescale: add initial device tree for TQMa8MPQL with i.MX8MP")
Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
index ff2bacf24bfd2..03b75d4cf699a 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
@@ -868,7 +868,7 @@ pinctrl_hdmi: hdmigrp {
 		fsl,pins = <MX8MP_IOMUXC_HDMI_DDC_SCL__HDMIMIX_HDMI_SCL	0x400001c2>,
 			   <MX8MP_IOMUXC_HDMI_DDC_SDA__HDMIMIX_HDMI_SDA	0x400001c2>,
 			   <MX8MP_IOMUXC_HDMI_HPD__HDMIMIX_HDMI_HPD	0x40000010>,
-			   <MX8MP_IOMUXC_HDMI_CEC__HDMIMIX_HDMI_CEC	0x40000010>;
+			   <MX8MP_IOMUXC_HDMI_CEC__HDMIMIX_HDMI_CEC	0x40000030>;
 	};
 
 	pinctrl_hoggpio2: hoggpio2grp {
-- 
2.43.0



From alexander.stein at ew.tq-group.com  Tue Dec  9 02:53:10 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Tue,  9 Dec 2025 11:53:10 +0100
Subject: [PATCH v2 4/8] arm64: dts: tqma8mpql-mba8mpxl: Add HDMI audio output support
In-Reply-To: <20251209105318.977102-1-alexander.stein@ew.tq-group.com>
References: <20251209105318.977102-1-alexander.stein@ew.tq-group.com>
Message-ID: <20251209105318.977102-5-alexander.stein@ew.tq-group.com>

Add the HDMI audio soundcard and enable necessary nodes.

Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 .../dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts   | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
index 03b75d4cf699a..ac889a69da69a 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
@@ -248,6 +248,13 @@ sound {
 			"Line Out Jack", "LOR";
 	};
 
+	sound-hdmi {
+		compatible = "fsl,imx-audio-hdmi";
+		model = "audio-hdmi";
+		audio-cpu = <&aud2htx>;
+		hdmi-out;
+	};
+
 	thermal-zones {
 		soc-thermal {
 			trips {
@@ -290,6 +297,10 @@ map3 {
 	};
 };
 
+&aud2htx {
+	status = "okay";
+};
+
 &ecspi1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_ecspi1>;
@@ -486,6 +497,10 @@ &gpio5 {
 			  "", "", "", "";
 };
 
+&hdmi_pai {
+	status = "okay";
+};
+
 &hdmi_pvi {
 	status = "okay";
 };
-- 
2.43.0



From alexander.stein at ew.tq-group.com  Tue Dec  9 02:53:13 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Tue,  9 Dec 2025 11:53:13 +0100
Subject: [PATCH v2 7/8] arm64: dts: tqma8mpql-mba8mp-ras314: Fix HDMI CEC pad control settings
In-Reply-To: <20251209105318.977102-1-alexander.stein@ew.tq-group.com>
References: <20251209105318.977102-1-alexander.stein@ew.tq-group.com>
Message-ID: <20251209105318.977102-8-alexander.stein@ew.tq-group.com>

As per datasheet of the HDMI protection IC the CEC_IC pin has been
configured as open-drain.

Fixes: ddabb3ce3f90 ("arm64: dts: freescale: add TQMa8MPQL on MBa8MP-RAS314")
Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 .../arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts
index 67fe1f63fd93c..30f0e81c4be00 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts
@@ -704,7 +704,7 @@ pinctrl_hdmi: hdmigrp {
 		fsl,pins = <MX8MP_IOMUXC_HDMI_DDC_SCL__HDMIMIX_HDMI_SCL	0x400001c2>,
 			   <MX8MP_IOMUXC_HDMI_DDC_SDA__HDMIMIX_HDMI_SDA	0x400001c2>,
 			   <MX8MP_IOMUXC_HDMI_HPD__HDMIMIX_HDMI_HPD	0x40000010>,
-			   <MX8MP_IOMUXC_HDMI_CEC__HDMIMIX_HDMI_CEC	0x40000154>;
+			   <MX8MP_IOMUXC_HDMI_CEC__HDMIMIX_HDMI_CEC	0x40000030>;
 	};
 
 	pinctrl_gpt1: gpt1grp {
-- 
2.43.0



From alexander.stein at ew.tq-group.com  Tue Dec  9 02:53:12 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Tue,  9 Dec 2025 11:53:12 +0100
Subject: [PATCH v2 6/8] arm64: dts: tqma8mpql-mba8mp-ras314: Fix Ethernet PHY IRQ support
In-Reply-To: <20251209105318.977102-1-alexander.stein@ew.tq-group.com>
References: <20251209105318.977102-1-alexander.stein@ew.tq-group.com>
Message-ID: <20251209105318.977102-7-alexander.stein@ew.tq-group.com>

Ethernet PHY interrupt mode is level triggered. Adjust the mode
accordingly.

Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 .../boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts     | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts
index f7346b3d35fe5..67fe1f63fd93c 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts
@@ -190,7 +190,7 @@ ethphy3: ethernet-phy at 3 {
 			reset-deassert-us = <50000>;
 			enet-phy-lane-no-swap;
 			interrupt-parent = <&gpio4>;
-			interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
+			interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
 			ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
 			ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
 			ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
@@ -222,7 +222,7 @@ ethphy0: ethernet-phy at 0 {
 			reset-deassert-us = <50000>;
 			enet-phy-lane-no-swap;
 			interrupt-parent = <&gpio4>;
-			interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
+			interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
 			ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
 			ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
 			ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
-- 
2.43.0



From nicolas.frattaroli at collabora.com  Tue Dec  9 02:58:26 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Dec 2025 11:58:26 +0100
Subject: [PATCH v2 5/8] drm/rockchip: vop2: Enforce AFBC source alignment in
 plane_check
In-Reply-To: <4696988.LvFx2qVVIh@workhorse>
References: <20251206-vop2-atomic-fixups-v2-0-7fb45bbfbebd@collabora.com>
 <f9f7b446-8575-4f16-aa96-5197b22846e3@rock-chips.com>
 <4696988.LvFx2qVVIh@workhorse>
Message-ID: <8655687.NyiUUSuA9g@workhorse>

Hi Chaoyi Chen, Andy Yan,

On Monday, 8 December 2025 08:24:52 Central European Standard Time Nicolas Frattaroli wrote:
> On Monday, 8 December 2025 03:48:24 Central European Standard Time Chaoyi Chen wrote:
> > Hello Nicolas, Daniel,
> > 
> > On 12/7/2025 4:45 AM, Nicolas Frattaroli wrote:
> > > From: Daniel Stone <daniels at collabora.com>
> > > 
> > > Planes can only source AFBC framebuffers at multiples of 4px wide on
> > > RK3566/RK3568. Instead of clipping on all SoCs when the user asks for an
> > > unaligned source rectangle, reject the configuration in the plane's
> > > atomic check on RK3566/RK3568 only.
> > > 
> > > Signed-off-by: Daniel Stone <daniels at collabora.com>
> > > [Make RK3566/RK3568 specific, reword message]
> > > Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
> > > ---
> > >  drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 14 +++++++++-----
> > >  1 file changed, 9 insertions(+), 5 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> > > index bc1ed0ffede0..e23213337104 100644
> > > --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> > > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> > > @@ -1076,6 +1076,13 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
> > >  		return -EINVAL;
> > >  	}
> > >  
> > > +	if (vop2->version == VOP_VERSION_RK3568 && drm_is_afbc(fb->modifier) && src_w % 4) {
> > > +		drm_dbg_kms(vop2->drm,
> > > +			    "AFBC source rectangles must be 4-byte aligned; is %d\n",
> > > +			    src_w);
> > > +		return -EINVAL;
> > > +	}
> > > +
> > >  	return 0;
> > >  }
> > >  
> > > @@ -1237,11 +1244,8 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
> > >  	WARN_ON(src_w < 4);
> > >  	WARN_ON(src_h < 4);
> > >  
> > > -	if (afbc_en && src_w % 4) {
> > > -		drm_dbg_kms(vop2->drm, "vp%d %s src_w[%d] not 4 pixel aligned\n",
> > > -			    vp->id, win->data->name, src_w);
> > > -		src_w = ALIGN_DOWN(src_w, 4);
> > > -	}
> > > +	if (vop2->version == VOP_VERSION_RK3568 && drm_is_afbc(fb->modifier))
> > > +		WARN_ON(src_w % 4);
> > >  
> > >  	act_info = (src_h - 1) << 16 | ((src_w - 1) & 0xffff);
> > >  	dsp_info = (dsp_h - 1) << 16 | ((dsp_w - 1) & 0xffff);
> > > 
> > 
> > You haven't replied to Andy's comment yet [0].
> > 
> > [0] https://lore.kernel.org/dri-devel/7b4e26ec.75f3.19a77276b53.Coremail.andyshrk at 163.com/
> > 
> 
> Hello,
> 
> I addressed the follow-ups where it was clarified that the 4 pixel
> limitation was RK3566/RK3568-only. I'm not going to bring back the
> post-atomic_check modification for a fast path, but I'm open to
> suggestions on how to do this differently.
> 
> One solution might be to modify the state with the ALIGN_DOWN stuff
> in atomic_check instead, where userspace is then aware of the change
> being done to its requested parameters. I'll need to double-check
> whether this is in line with atomic modesetting's design.
> 
> Kind regards,
> Nicolas Frattaroli

Okay, so I've asked internally, and atomic_check isn't allowed to
modify any of the parameters either. There's efforts [0] underway
to allow error codes to be more specific, so that userspace knows
which constraint is being violated. That would allow userspace
applications to react by either adjusting their size or turning
off AFBC in this case. Turning off AFBC seems more generally
applicable here, since it means it won't need to resize the plane
and it'll save more than enough memory bandwidth by not going
through the GPU.

On that note: Andy, I didn't find a weston-simple-egl test in the
Weston 14.0.2 or git test suite, and weston-simple-egl itself does
not tell me whether GPU compositing is being used or not. Do you
have more information on how to test for this? I'd like to know
for when we have the necessary functionality in place to make
userspace smart enough to pick the fast path again.

In either case, I think adhering to the atomic API to ensure
artifact-free presentation is more important here than enabling
a fast-path on RK3568. I do think in most real-world use case
scenarios, the fallback won't degrade user experience, because
almost everything performance intensive I can think of (video
playback, games) will likely already use a plane geometry
where the width is divisible by 4. 800, 1024, 1280, 1600, 1920,
2560, 3840 are all divisible by 4, so a window or full-screen
playback of common content won't need to fall back to GPU
compositing.

I'll send a v2 to fix another instance of "eSmart" left in a
message, but beyond that I think we should be good.

Kind regards,
Nicolas Frattaroli

https://lore.kernel.org/dri-devel/20251009-atomic-v6-0-d209709cc3ba at intel.com/ [0]




From jie.gan at oss.qualcomm.com  Tue Dec  9 03:03:51 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Tue, 9 Dec 2025 19:03:51 +0800
Subject: [PATCH v6 2/2] coresight: cti: Add Qualcomm extended CTI support
In-Reply-To: <20251209081649.105623-1-yingchao.deng@oss.qualcomm.com>
References: <CAJ9a7Vg9Efi-5eecfiUF82_Qq8Jg9imN5q1-VKYZoPVUxNpjhA@mail.gmail.com>
 <20251209081649.105623-1-yingchao.deng@oss.qualcomm.com>
Message-ID: <d55ed203-b0f4-4453-81cf-1d8dcd6494ed@oss.qualcomm.com>



On 12/9/2025 4:16 PM, Yingchao Deng wrote:
> Hi Leo & Mike
> 
> Based on Leo?s suggestions, I created a new patch, but there are three points that do not fully align with his recommendations:
> 
>      1. The helper function for returning the register address now returns only the offset, because returning the full address would conflict with cti_write_single_reg.
>      2. For registers such as triginstatus1...3, I defined additional macros CTITRIGINSTATUS1...3. This is because CTITRIGINSTATUS + 0x4 equals CTITRIGOUTSTATUS, and to avoid conflicts with existing macros, I chose numbers starting from 0x1000 for the new definitions.
>      3. Regarding the visibility of attributes for triginstatus1...3, since coresight_cti_reg produces an anonymous variable that cannot be directly referenced, I used coresight_cti_regs_attrs[i] to obtain the attribute corresponding to triginstatus1.
> 
> I appreciate both suggestions. After reviewing them, I lean toward Mike's approach.
> 
> Signed-off-by: Yingchao Deng <yingchao.deng at oss.qualcomm.com>
> ---
>   .../hwtracing/coresight/coresight-cti-core.c  |  52 +++++--
>   .../hwtracing/coresight/coresight-cti-sysfs.c |  72 ++++++++--
>   drivers/hwtracing/coresight/coresight-cti.h   |   3 +-
>   drivers/hwtracing/coresight/qcom-cti.h        | 136 ++++++++++++++++++
>   4 files changed, 238 insertions(+), 25 deletions(-)
>   create mode 100644 drivers/hwtracing/coresight/qcom-cti.h
> 
> diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c
> index f9970e40dd59..d2b0b46f2846 100644
> --- a/drivers/hwtracing/coresight/coresight-cti-core.c
> +++ b/drivers/hwtracing/coresight/coresight-cti-core.c
> @@ -21,7 +21,7 @@
> 
>   #include "coresight-priv.h"
>   #include "coresight-cti.h"
> -
> +#include "qcom-cti.h"
>   /*
>    * CTI devices can be associated with a PE, or be connected to CoreSight
>    * hardware. We have a list of all CTIs irrespective of CPU bound or
> @@ -70,15 +70,16 @@ void cti_write_all_hw_regs(struct cti_drvdata *drvdata)
> 
>       /* write the CTI trigger registers */
>       for (i = 0; i < config->nr_trig_max; i++) {
> -        writel_relaxed(config->ctiinen[i], drvdata->base + CTIINEN(i));
> +        writel_relaxed(config->ctiinen[i],
> +                drvdata->base + cti_reg_addr_with_nr(drvdata, CTIINEN(0), i));
>           writel_relaxed(config->ctiouten[i],
> -                   drvdata->base + CTIOUTEN(i));
> +                drvdata->base + cti_reg_addr_with_nr(drvdata, CTIOUTEN(0), i));
>       }
> 
>       /* other regs */
> -    writel_relaxed(config->ctigate, drvdata->base + CTIGATE);
> -    writel_relaxed(config->asicctl, drvdata->base + ASICCTL);
> -    writel_relaxed(config->ctiappset, drvdata->base + CTIAPPSET);
> +    writel_relaxed(config->ctigate, drvdata->base + cti_reg_addr(drvdata, CTIGATE));
> +    writel_relaxed(config->asicctl, drvdata->base + cti_reg_addr(drvdata, ASICCTL));
> +    writel_relaxed(config->ctiappset, drvdata->base + cti_reg_addr(drvdata, CTIAPPSET));
> 
>       /* re-enable CTI */
>       writel_relaxed(1, drvdata->base + CTICONTROL);
> @@ -201,7 +202,7 @@ void cti_write_intack(struct device *dev, u32 ackval)
>       raw_spin_lock(&drvdata->spinlock);
>       /* write if enabled */
>       if (cti_active(config))
> -        cti_write_single_reg(drvdata, CTIINTACK, ackval);
> +        cti_write_single_reg(drvdata, cti_reg_addr(drvdata, CTIINTACK), ackval);
>       raw_spin_unlock(&drvdata->spinlock);
>   }
> 
> @@ -214,6 +215,9 @@ void cti_write_intack(struct device *dev, u32 ackval)
>   /* DEVID[19:16] - number of CTM channels */
>   #define CTI_DEVID_CTMCHANNELS(devid_val) ((int) BMVAL(devid_val, 16, 19))
> 
> +/* DEVARCH[31:21] - ARCHITECT */
> +#define CTI_DEVARCH_ARCHITECT(devarch_val) ((int)BMVAL(devarch_val, 21, 31))
> +
>   static int cti_set_default_config(struct device *dev,
>                     struct cti_drvdata *drvdata)
>   {
> @@ -394,9 +398,8 @@ int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,
> 
>       /* update the local register values */
>       chan_bitmask = BIT(channel_idx);
> -    reg_offset = (direction == CTI_TRIG_IN ? CTIINEN(trigger_idx) :
> -              CTIOUTEN(trigger_idx));
> -
> +    reg_offset = (direction == CTI_TRIG_IN ? cti_reg_addr_with_nr(drvdata, CTIINEN(0), trigger_idx):
> +                         cti_reg_addr_with_nr(drvdata, CTIOUTEN(0), trigger_idx));
>       raw_spin_lock(&drvdata->spinlock);
> 
>       /* read - modify write - the trigger / channel enable value */
> @@ -452,7 +455,7 @@ int cti_channel_gate_op(struct device *dev, enum cti_chan_gate_op op,
>       if (err == 0) {
>           config->ctigate = reg_value;
>           if (cti_active(config))
> -            cti_write_single_reg(drvdata, CTIGATE, reg_value);
> +            cti_write_single_reg(drvdata, cti_reg_addr(drvdata, CTIGATE), reg_value);
>       }
>       raw_spin_unlock(&drvdata->spinlock);
>       return err;
> @@ -479,19 +482,19 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op,
>       case CTI_CHAN_SET:
>           config->ctiappset |= chan_bitmask;
>           reg_value  = config->ctiappset;
> -        reg_offset = CTIAPPSET;
> +        reg_offset = cti_reg_addr(drvdata, CTIAPPSET);
>           break;
> 
>       case CTI_CHAN_CLR:
>           config->ctiappset &= ~chan_bitmask;
>           reg_value = chan_bitmask;
> -        reg_offset = CTIAPPCLEAR;
> +        reg_offset = cti_reg_addr(drvdata, CTIAPPCLEAR);
>           break;
> 
>       case CTI_CHAN_PULSE:
>           config->ctiappset &= ~chan_bitmask;
>           reg_value = chan_bitmask;
> -        reg_offset = CTIAPPPULSE;
> +        reg_offset = cti_reg_addr(drvdata, CTIAPPPULSE);
>           break;
> 
>       default:
> @@ -895,6 +898,7 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id)
>       struct coresight_desc cti_desc;
>       struct coresight_platform_data *pdata = NULL;
>       struct resource *res = &adev->res;
> +    u32 devarch;
> 
>       /* driver data*/
>       drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
> @@ -981,9 +985,27 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id)
>       drvdata->csdev_release = drvdata->csdev->dev.release;
>       drvdata->csdev->dev.release = cti_device_release;
> 
> +    /* check architect value*/
> +    devarch = readl_relaxed(drvdata->base + CORESIGHT_DEVARCH);
> +    if (CTI_DEVARCH_ARCHITECT(devarch) == ARCHITECT_QCOM) {
> +        drvdata->is_qcom_cti = 1;
> +
> +        /*
> +         * QCOM CTI does not implement Claimtag functionality as
> +         * per CoreSight specification, but its CLAIMSET register
> +         * is incorrectly initialized to 0xF. This can mislead
> +         * tools or drivers into thinking the component is claimed.
> +         *
> +         * Reset CLAIMSET to 0 to reflect that no claims are active.
> +         */
> +        drvdata->csdev->claim_tag_info = CS_CLAIM_TAG_NOT_IMPL;
> +        //writel_relaxed(0, drvdata->base + CORESIGHT_CLAIMSET);
> +    }
> +
>       /* all done - dec pm refcount */
>       pm_runtime_put(&adev->dev);
> -    dev_info(&drvdata->csdev->dev, "CTI initialized\n");
> +    dev_info(&drvdata->csdev->dev, "%s CTI initialized\n",
> +                    drvdata->is_qcom_cti ? "QCOM" : "");
>       return 0;
> 
>   pm_release:
> diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
> index a9df77215141..5d23a138b4a7 100644
> --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c
> +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
> @@ -13,7 +13,7 @@
>   #include <linux/sysfs.h>
> 
>   #include "coresight-cti.h"
> -
> +#include "qcom-cti.h"
>   /*
>    * Declare the number of static declared attribute groups
>    * Value includes groups + NULL value at end of table.
> @@ -183,7 +183,7 @@ static ssize_t coresight_cti_reg_show(struct device *dev,
>       pm_runtime_get_sync(dev->parent);
>       raw_spin_lock(&drvdata->spinlock);
>       if (drvdata->config.hw_powered)
> -        val = readl_relaxed(drvdata->base + cti_attr->off);
> +        val = readl_relaxed(drvdata->base + cti_reg_addr(drvdata, cti_attr->off));
>       raw_spin_unlock(&drvdata->spinlock);
>       pm_runtime_put_sync(dev->parent);
>       return sysfs_emit(buf, "0x%x\n", val);
> @@ -204,7 +204,7 @@ static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,
>       pm_runtime_get_sync(dev->parent);
>       raw_spin_lock(&drvdata->spinlock);
>       if (drvdata->config.hw_powered)
> -        cti_write_single_reg(drvdata, cti_attr->off, val);
> +        cti_write_single_reg(drvdata,  cti_reg_addr(drvdata, cti_attr->off), val);
>       raw_spin_unlock(&drvdata->spinlock);
>       pm_runtime_put_sync(dev->parent);
>       return size;
> @@ -267,7 +267,7 @@ static ssize_t cti_reg32_show(struct device *dev, char *buf,
>       raw_spin_lock(&drvdata->spinlock);
>       if ((reg_offset >= 0) && cti_active(config)) {
>           CS_UNLOCK(drvdata->base);
> -        val = readl_relaxed(drvdata->base + reg_offset);
> +        val = readl_relaxed(drvdata->base + cti_reg_addr(drvdata, reg_offset));
>           if (pcached_val)
>               *pcached_val = val;
>           CS_LOCK(drvdata->base);
> @@ -300,7 +300,7 @@ static ssize_t cti_reg32_store(struct device *dev, const char *buf,
> 
>       /* write through if offset and enabled */
>       if ((reg_offset >= 0) && cti_active(config))
> -        cti_write_single_reg(drvdata, reg_offset, val);
> +        cti_write_single_reg(drvdata,  cti_reg_addr(drvdata, reg_offset), val);
>       raw_spin_unlock(&drvdata->spinlock);
>       return size;
>   }
> @@ -389,7 +389,7 @@ static ssize_t inen_store(struct device *dev,
> 
>       /* write through if enabled */
>       if (cti_active(config))
> -        cti_write_single_reg(drvdata, CTIINEN(index), val);
> +        cti_write_single_reg(drvdata, cti_reg_addr_with_nr(drvdata, CTIINEN(0), index), val);
>       raw_spin_unlock(&drvdata->spinlock);
>       return size;
>   }
> @@ -428,7 +428,7 @@ static ssize_t outen_store(struct device *dev,
> 
>       /* write through if enabled */
>       if (cti_active(config))
> -        cti_write_single_reg(drvdata, CTIOUTEN(index), val);
> +        cti_write_single_reg(drvdata, cti_reg_addr_with_nr(drvdata, CTIOUTEN(0), index), val);
>       raw_spin_unlock(&drvdata->spinlock);
>       return size;
>   }
> @@ -470,7 +470,7 @@ static ssize_t appclear_store(struct device *dev,
> 
>       /* write through if enabled */
>       if (cti_active(config))
> -        cti_write_single_reg(drvdata, CTIAPPCLEAR, val);
> +        cti_write_single_reg(drvdata,  cti_reg_addr(drvdata, CTIAPPCLEAR), val);
>       raw_spin_unlock(&drvdata->spinlock);
>       return size;
>   }
> @@ -491,7 +491,7 @@ static ssize_t apppulse_store(struct device *dev,
> 
>       /* write through if enabled */
>       if (cti_active(config))
> -        cti_write_single_reg(drvdata, CTIAPPPULSE, val);
> +        cti_write_single_reg(drvdata,  cti_reg_addr(drvdata, CTIAPPPULSE), val);
>       raw_spin_unlock(&drvdata->spinlock);
>       return size;
>   }
> @@ -513,18 +513,36 @@ static struct attribute *coresight_cti_regs_attrs[] = {
>       &dev_attr_appclear.attr,
>       &dev_attr_apppulse.attr,
>       coresight_cti_reg(triginstatus, CTITRIGINSTATUS),
> +    coresight_cti_reg(triginstatus1, CTITRIGINSTATUS1),
> +    coresight_cti_reg(triginstatus2, CTITRIGINSTATUS2),
> +    coresight_cti_reg(triginstatus3, CTITRIGINSTATUS3),
>       coresight_cti_reg(trigoutstatus, CTITRIGOUTSTATUS),
> +    coresight_cti_reg(trigoutstatus1, CTITRIGOUTSTATUS1),
> +    coresight_cti_reg(trigoutstatus2, CTITRIGOUTSTATUS2),
> +    coresight_cti_reg(trigoutstatus3, CTITRIGOUTSTATUS3),
>       coresight_cti_reg(chinstatus, CTICHINSTATUS),
>       coresight_cti_reg(choutstatus, CTICHOUTSTATUS),
>   #ifdef CONFIG_CORESIGHT_CTI_INTEGRATION_REGS
>       coresight_cti_reg_rw(itctrl, CORESIGHT_ITCTRL),
>       coresight_cti_reg(ittrigin, ITTRIGIN),
> +    coresight_cti_reg(ittrigin1, ITTRIGIN1),
> +    coresight_cti_reg(ittrigin2, ITTRIGIN2),
> +    coresight_cti_reg(ittrigin3, ITTRIGIN3),
>       coresight_cti_reg(itchin, ITCHIN),
>       coresight_cti_reg_rw(ittrigout, ITTRIGOUT),
> +    coresight_cti_reg_rw(ittrigout1, ITTRIGOUT1),
> +    coresight_cti_reg_rw(ittrigout2, ITTRIGOUT2),
> +    coresight_cti_reg_rw(ittrigout3, ITTRIGOUT3),
>       coresight_cti_reg_rw(itchout, ITCHOUT),
>       coresight_cti_reg(itchoutack, ITCHOUTACK),
>       coresight_cti_reg(ittrigoutack, ITTRIGOUTACK),
> +    coresight_cti_reg(ittrigoutack1, ITTRIGOUTACK1),
> +    coresight_cti_reg(ittrigoutack2, ITTRIGOUTACK2),
> +    coresight_cti_reg(ittrigoutack3, ITTRIGOUTACK3),
>       coresight_cti_reg_wo(ittriginack, ITTRIGINACK),
> +    coresight_cti_reg_wo(ittriginack1, ITTRIGINACK1),
> +    coresight_cti_reg_wo(ittriginack2, ITTRIGINACK2),
> +    coresight_cti_reg_wo(ittriginack3, ITTRIGINACK3),
>       coresight_cti_reg_wo(itchinack, ITCHINACK),
>   #endif
>       NULL,
> @@ -1153,6 +1171,41 @@ int cti_create_cons_sysfs(struct device *dev, struct cti_drvdata *drvdata)
>       return err;
>   }
> 
> +  static umode_t coresight_cti_regs_is_visible(struct kobject *kobj,
> +                  struct attribute *attr, int n)
> +  {

I was thinking can we create a separate attribute_group for added Qcom 
regs? Let devarch to determine whether to create these sysfs nodes?

Thanks,
Jie

> +    struct device *dev = container_of(kobj, struct device, kobj);
> +    struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +
> +    /* Mute QCOM CTI registers for standard CTI module */
> +    if (!drvdata->is_qcom_cti) {
> +        if (attr == coresight_cti_regs_attrs[10]
> +         || attr == coresight_cti_regs_attrs[11]
> +         || attr == coresight_cti_regs_attrs[12]
> +         || attr == coresight_cti_regs_attrs[14]
> +         || attr == coresight_cti_regs_attrs[15]
> +         || attr == coresight_cti_regs_attrs[16]
> +#ifdef CONFIG_CORESIGHT_CTI_INTEGRATION_REGS
> +         || attr == coresight_cti_regs_attrs[21]
> +         || attr == coresight_cti_regs_attrs[22]
> +         || attr == coresight_cti_regs_attrs[23]
> +         || attr == coresight_cti_regs_attrs[26]
> +         || attr == coresight_cti_regs_attrs[27]
> +         || attr == coresight_cti_regs_attrs[28]
> +         || attr == coresight_cti_regs_attrs[32]
> +         || attr == coresight_cti_regs_attrs[33]
> +         || attr == coresight_cti_regs_attrs[34]
> +         || attr == coresight_cti_regs_attrs[36]
> +         || attr == coresight_cti_regs_attrs[37]
> +         || attr == coresight_cti_regs_attrs[38]
> +#endif
> +         )
> +                  return 0;
> +          }
> +
> +          return attr->mode;
> +  }
> +
>   /* attribute and group sysfs tables. */
>   static const struct attribute_group coresight_cti_group = {
>       .attrs = coresight_cti_attrs,
> @@ -1166,6 +1219,7 @@ static const struct attribute_group coresight_cti_mgmt_group = {
>   static const struct attribute_group coresight_cti_regs_group = {
>       .attrs = coresight_cti_regs_attrs,
>       .name = "regs",
> +    .is_visible = coresight_cti_regs_is_visible,
>   };
> 
>   static const struct attribute_group coresight_cti_channels_group = {
> diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h
> index e7b88b07cffe..413d5ef483e8 100644
> --- a/drivers/hwtracing/coresight/coresight-cti.h
> +++ b/drivers/hwtracing/coresight/coresight-cti.h
> @@ -57,7 +57,7 @@ struct fwnode_handle;
>    * Max of in and out defined in the DEVID register.
>    * - pick up actual number used from .dts parameters if present.
>    */
> -#define CTIINOUTEN_MAX        32
> +#define CTIINOUTEN_MAX        128
> 
>   /**
>    * Group of related trigger signals
> @@ -181,6 +181,7 @@ struct cti_drvdata {
>       struct cti_config config;
>       struct list_head node;
>       void (*csdev_release)(struct device *dev);
> +    bool is_qcom_cti;
>   };
> 
>   /*
> diff --git a/drivers/hwtracing/coresight/qcom-cti.h b/drivers/hwtracing/coresight/qcom-cti.h
> new file mode 100644
> index 000000000000..aa41f9425b36
> --- /dev/null
> +++ b/drivers/hwtracing/coresight/qcom-cti.h
> @@ -0,0 +1,136 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +#include "coresight-cti.h"
> +
> +#define ARCHITECT_QCOM 0x477
> +
> +#define CTITRIGINSTATUS1 0x1000
> +#define CTITRIGINSTATUS2 0x1001
> +#define CTITRIGINSTATUS3 0x1002
> +
> +#define CTITRIGOUTSTATUS1 0x1003
> +#define CTITRIGOUTSTATUS2 0x1004
> +#define CTITRIGOUTSTATUS3 0x1005
> +
> +#define ITTRIGIN1 0x1006
> +#define ITTRIGIN2 0x1007
> +#define ITTRIGIN3 0x1008
> +
> +#define ITTRIGOUT1 0x1009
> +#define ITTRIGOUT2 0x100A
> +#define ITTRIGOUT3 0x100B
> +
> +#define ITTRIGINACK1 0x100C
> +#define ITTRIGINACK2 0x100D
> +#define ITTRIGINACK3 0x100E
> +
> +#define ITTRIGOUTACK1 0x100F
> +#define ITTRIGOUTACK2 0x1010
> +#define ITTRIGOUTACK3 0x1011
> +/* CTI programming registers */
> +#define    QCOM_CTIINTACK        0x020
> +#define    QCOM_CTIAPPSET        0x004
> +#define    QCOM_CTIAPPCLEAR    0x008
> +#define    QCOM_CTIAPPPULSE    0x00C
> +#define    QCOM_CTIINEN        0x400
> +#define    QCOM_CTIOUTEN        0x800
> +#define    QCOM_CTITRIGINSTATUS    0x040
> +#define    QCOM_CTITRIGINSTATUS1    0x044
> +#define    QCOM_CTITRIGINSTATUS2    0x048
> +#define    QCOM_CTITRIGINSTATUS3    0x04C
> +#define    QCOM_CTITRIGOUTSTATUS    0x060
> +#define    QCOM_CTITRIGOUTSTATUS1    0x064
> +#define    QCOM_CTITRIGOUTSTATUS2    0x068
> +#define    QCOM_CTITRIGOUTSTATUS3    0x06C
> +#define    QCOM_CTICHINSTATUS    0x080
> +#define    QCOM_CTICHOUTSTATUS    0x084
> +#define    QCOM_CTIGATE        0x088
> +#define    QCOM_ASICCTL        0x08c
> +/* Integration test registers */
> +#define    QCOM_ITCHINACK        0xE70
> +#define    QCOM_ITTRIGINACK    0xE80
> +#define    QCOM_ITTRIGINACK1    0xE84
> +#define    QCOM_ITTRIGINACK2    0xE88
> +#define    QCOM_ITTRIGINACK3    0xE8C
> +#define    QCOM_ITCHOUT        0xE74
> +#define    QCOM_ITTRIGOUT        0xEA0
> +#define    QCOM_ITTRIGOUT1        0xEA4
> +#define    QCOM_ITTRIGOUT2        0xEA8
> +#define    QCOM_ITTRIGOUT3        0xEAC
> +#define    QCOM_ITCHOUTACK        0xE78
> +#define    QCOM_ITTRIGOUTACK    0xEC0
> +#define    QCOM_ITTRIGOUTACK1    0xEC4
> +#define    QCOM_ITTRIGOUTACK2    0xEC8
> +#define    QCOM_ITTRIGOUTACK3    0xECC
> +#define    QCOM_ITCHIN        0xE7C
> +#define    QCOM_ITTRIGIN        0xEE0
> +#define    QCOM_ITTRIGIN1        0xEE4
> +#define    QCOM_ITTRIGIN2        0xEE8
> +#define    QCOM_ITTRIGIN3        0xEEC
> +
> +static noinline u32 cti_qcom_reg_off(u32 offset)
> +{
> +    switch (offset) {
> +        case CTIINTACK:        return QCOM_CTIINTACK;
> +        case CTIAPPSET:        return QCOM_CTIAPPSET;
> +        case CTIAPPCLEAR:    return QCOM_CTIAPPCLEAR;
> +        case CTIAPPPULSE:    return QCOM_CTIAPPPULSE;
> +        case CTIINEN(0):    return QCOM_CTIINEN;
> +        case CTIOUTEN(0):    return QCOM_CTIOUTEN;
> +        case CTITRIGINSTATUS:    return QCOM_CTITRIGINSTATUS;
> +        case CTITRIGINSTATUS1:    return QCOM_CTITRIGINSTATUS1;
> +        case CTITRIGINSTATUS2:    return QCOM_CTITRIGINSTATUS2;
> +        case CTITRIGINSTATUS3:    return QCOM_CTITRIGINSTATUS3;
> +        case CTITRIGOUTSTATUS:    return QCOM_CTITRIGOUTSTATUS;
> +        case CTITRIGOUTSTATUS1:    return QCOM_CTITRIGOUTSTATUS1;
> +        case CTITRIGOUTSTATUS2:    return QCOM_CTITRIGOUTSTATUS2;
> +        case CTITRIGOUTSTATUS3:    return QCOM_CTITRIGOUTSTATUS3;
> +        case CTICHINSTATUS:        return QCOM_CTICHINSTATUS;
> +        case CTICHOUTSTATUS:    return QCOM_CTICHOUTSTATUS;
> +        case CTIGATE:        return QCOM_CTIGATE;
> +        case ASICCTL:        return QCOM_ASICCTL;
> +        case ITCHINACK:        return QCOM_ITCHINACK;
> +        case ITTRIGINACK:    return QCOM_ITTRIGINACK;
> +        case ITTRIGINACK1:    return QCOM_ITTRIGINACK1;
> +        case ITTRIGINACK2:    return QCOM_ITTRIGINACK2;
> +        case ITTRIGINACK3:    return QCOM_ITTRIGINACK3;
> +        case ITCHOUT:        return QCOM_ITCHOUT;
> +        case ITTRIGOUT:        return QCOM_ITTRIGOUT;
> +        case ITTRIGOUT1:    return QCOM_ITTRIGOUT1;
> +        case ITTRIGOUT2:    return QCOM_ITTRIGOUT2;
> +        case ITTRIGOUT3:    return QCOM_ITTRIGOUT3;
> +        case ITCHOUTACK:    return QCOM_ITCHOUTACK;
> +        case ITTRIGOUTACK:    return QCOM_ITTRIGOUTACK;
> +        case ITTRIGOUTACK1:    return QCOM_ITTRIGOUTACK1;
> +        case ITTRIGOUTACK2:    return QCOM_ITTRIGOUTACK2;
> +        case ITTRIGOUTACK3:    return QCOM_ITTRIGOUTACK3;
> +        case ITCHIN:               return QCOM_ITCHIN;
> +        case ITTRIGIN:            return QCOM_ITTRIGIN;
> +        case ITTRIGIN1:        return QCOM_ITTRIGIN1;
> +        case ITTRIGIN2:        return QCOM_ITTRIGIN2;
> +        case ITTRIGIN3:        return QCOM_ITTRIGIN3;
> +        default:
> +                    WARN(1, "Unknown offset=%u\n", offset);
> +                    return 0;
> +    }
> +
> +    return 0;
> +}
> +
> +static u32 cti_reg_addr_with_nr(struct cti_drvdata *drvdata,
> +                                          u32 reg, u32 nr)
> +{
> +    /* convert to qcom specific offset */
> +    if (unlikely(drvdata->is_qcom_cti))
> +        reg = cti_qcom_reg_off(reg);
> +
> +    return reg + sizeof(u32) * nr;
> +}
> +
> +static u32 cti_reg_addr(struct cti_drvdata *drvdata, u32 reg)
> +{
> +        return cti_reg_addr_with_nr(drvdata, reg, 0);
> +}
> +
> 
> 



From jacky_chou at aspeedtech.com  Tue Dec  9 03:08:34 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Tue, 9 Dec 2025 11:08:34 +0000
Subject: [PATCH net] net: mdio: aspeed: add dummy read to avoid
 read-after-write issue
In-Reply-To: <57860c7c-2294-4ea6-a998-8bc92dda2ed2@lunn.ch>
References: <20251208-aspeed_mdio_add_dummy_read-v1-1-0a1861ad2161@aspeedtech.com>
 <57860c7c-2294-4ea6-a998-8bc92dda2ed2@lunn.ch>
Message-ID: <SEYPR06MB5134A0B82901A8BAC9AAF4AB9DA3A@SEYPR06MB5134.apcprd06.prod.outlook.com>

Hi Andrew,

Thank you for your reply.

> >
> > Fixes: 737ca352569e ("net: mdio: aspeed: move reg accessing part into
> > separate functions")
> 
> That seems like an odd Fixes: tag. That is just moving code around, but the
> write followed by a read existed before that. Why not:
> 

Agreed.
I mistakenly thought I should reference the most recent integrated changes 
for the Fixes: tag.
I'll correct the Fixes: tag in the next revision.

> commit f160e99462c68ab5b9e2b9097a4867459730b49a
> Author: Andrew Jeffery <andrew at aj.id.au>
> Date:   Wed Jul 31 15:09:57 2019 +0930
> 
>     net: phy: Add mdio-aspeed
> 
>     The AST2600 design separates the MDIO controllers from the MAC, which
> is
>     where they were placed in the AST2400 and AST2500. Further, the register
>     interface is reworked again, so now we have three possible different
>     interface implementations, however this driver only supports the
>     interface provided by the AST2600. The AST2400 and AST2500 will
> continue
>     to be supported by the MDIO support embedded in the FTGMAC100
> driver.
> 
>     The hardware supports both C22 and C45 mode, but for the moment only
> C22
>     support is implemented.
> 
>     Signed-off-by: Andrew Jeffery <andrew at aj.id.au>
>     Reviewed-by: Andrew Lunn <andrew at lunn.ch>
>     Signed-off-by: David S. Miller <davem at davemloft.net>

Thanks,
Jacky



From nicolas.frattaroli at collabora.com  Tue Dec  9 03:14:13 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Dec 2025 12:14:13 +0100
Subject: [PATCH v3 0/8] drm/rockchip: No more post-atomic_check fixups
Message-ID: <20251209-vop2-atomic-fixups-v3-0-07c48f0f1f0d@collabora.com>

I'm taking over this series to get it across the finish line. Original
cover letter from Daniel Stone on v1:

> Hi,
> This series is a pretty small and consistent one for VOP2. The atomic
> uAPI very clearly specifies that drivers should either do what userspace
> requested (on a successful commit), or fail atomic_check if it is not
> for any reason possible to do what userspace requested.
> 
> VOP2 is unfortunately littered with a bunch of cases where it will apply
> fixups after atomic_check - doing something different to what userspace
> requested, e.g. clipping or aligning regions - or throw error messages
> into the log when userspace does request a condition which can't be met.
> 
> Doing something different to what was requested is bad because it
> results in unexpected visual output which can look like artifacts.
> Throwing errors into the log is bad because generic userspace will
> reasonably attempt to try any configuration it can. For example,
> throwing an error message on a plane not being aligned to a 16 pixel
> boundary can result in 15 frames' worth of error output in the log when
> a window is being animated across a screen.
> 
> This series removes all post-check fixups - failing the check if the
> configuration cannot be applied - and also demotes all messages about
> unsupported configurations to DEBUG_KMS.
> 
> Cheers,
> Daniel

Changes in v3:
- Change the AFBC source rectangle debug message to talk about 4-pixel
  alignment instead of 4-byte alignment.
- Fix another eSmart->Esmart casing case in a debug message
- Link to v2: https://lore.kernel.org/r/20251206-vop2-atomic-fixups-v2-0-7fb45bbfbebd at collabora.com

Changes in v2:
- Dropped patches [1, 5] as they were already applied.
- Changed the patch subject to use prefix "drm/rockchip: vop2:" for the
  remaining ones.
- Fixed a checkpatch nag about commenting style in "Switch impossible
  pos conditional to WARN_ON".
- Reworded "eSmart" to "Esmart" for consistency, and to avoid drawing
  Tim Apple's ire.
- Make the hopefully impossible WARN_ON format conditional in
  vop2_plane_atomic_check still bubble the error up to userspace,
  instead of continuing on.
- Use dest_w instead of dsp_w in patch "Enforce scaling workaround
  in plane_check", to avoid a compiler error.
- Only reject non-multiple-of-4-pixel-wide framebuffers on
  RK3566/RK3568, as the other SoCs have no such limitation. (Thank you
  to Andy Yan for doing the research to confirm this!)
- Consequently also only WARN_ON if this condition is violated in
  atomic_update on those SoCs.
- Link to v1: https://lore.kernel.org/dri-devel/20251015110042.41273-1-daniels at collabora.com/

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
Daniel Stone (8):
      drm/rockchip: vop2: Switch impossible format conditional to WARN_ON
      drm/rockchip: vop2: Switch impossible pos conditional to WARN_ON
      drm/rockchip: vop2: Fix Esmart test condition
      drm/rockchip: vop2: Enforce scaling workaround in plane_check
      drm/rockchip: vop2: Enforce AFBC source alignment in plane_check
      drm/rockchip: vop2: Enforce AFBC transform stride align in plane_check
      drm/rockchip: vop2: Use drm_is_afbc helper function
      drm/rockchip: vop2: Simplify format_mod_supported

 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 137 ++++++++++++---------------
 1 file changed, 62 insertions(+), 75 deletions(-)
---
base-commit: 4e5a9b630580faea139e9837b4fba666db6bd728
change-id: 20251206-vop2-atomic-fixups-0c30e0980f85

Best regards,
-- 
Nicolas Frattaroli <nicolas.frattaroli at collabora.com>



From nicolas.frattaroli at collabora.com  Tue Dec  9 03:14:14 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Dec 2025 12:14:14 +0100
Subject: [PATCH v3 1/8] drm/rockchip: vop2: Switch impossible format
 conditional to WARN_ON
In-Reply-To: <20251209-vop2-atomic-fixups-v3-0-07c48f0f1f0d@collabora.com>
References: <20251209-vop2-atomic-fixups-v3-0-07c48f0f1f0d@collabora.com>
Message-ID: <20251209-vop2-atomic-fixups-v3-1-07c48f0f1f0d@collabora.com>

From: Daniel Stone <daniels at collabora.com>

We should never be able to create a framebuffer with an unsupported
format, so throw a warning if this ever happens, instead of attempting
to stagger on.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 498df0ce4680..20b49209ddcd 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1030,7 +1030,8 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
 		return 0;
 
 	format = vop2_convert_format(fb->format->format);
-	if (format < 0)
+	/* We shouldn't be able to create a fb for an unsupported format */
+	if (WARN_ON(format < 0))
 		return format;
 
 	/* Co-ordinates have now been clipped */

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Tue Dec  9 03:14:18 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Dec 2025 12:14:18 +0100
Subject: [PATCH v3 5/8] drm/rockchip: vop2: Enforce AFBC source alignment
 in plane_check
In-Reply-To: <20251209-vop2-atomic-fixups-v3-0-07c48f0f1f0d@collabora.com>
References: <20251209-vop2-atomic-fixups-v3-0-07c48f0f1f0d@collabora.com>
Message-ID: <20251209-vop2-atomic-fixups-v3-5-07c48f0f1f0d@collabora.com>

From: Daniel Stone <daniels at collabora.com>

Planes can only source AFBC framebuffers at multiples of 4px wide on
RK3566/RK3568. Instead of clipping on all SoCs when the user asks for an
unaligned source rectangle, reject the configuration in the plane's
atomic check on RK3566/RK3568 only.

Signed-off-by: Daniel Stone <daniels at collabora.com>
[Make RK3566/RK3568 specific, reword message, s/byte/pixel/]
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 6d4f22872e67..a029ed73dda7 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1076,6 +1076,13 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
 		return -EINVAL;
 	}
 
+	if (vop2->version == VOP_VERSION_RK3568 && drm_is_afbc(fb->modifier) && src_w % 4) {
+		drm_dbg_kms(vop2->drm,
+			    "AFBC source rectangles must be 4-pixel aligned; is %d\n",
+			    src_w);
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
@@ -1237,11 +1244,8 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
 	WARN_ON(src_w < 4);
 	WARN_ON(src_h < 4);
 
-	if (afbc_en && src_w % 4) {
-		drm_dbg_kms(vop2->drm, "vp%d %s src_w[%d] not 4 pixel aligned\n",
-			    vp->id, win->data->name, src_w);
-		src_w = ALIGN_DOWN(src_w, 4);
-	}
+	if (vop2->version == VOP_VERSION_RK3568 && drm_is_afbc(fb->modifier))
+		WARN_ON(src_w % 4);
 
 	act_info = (src_h - 1) << 16 | ((src_w - 1) & 0xffff);
 	dsp_info = (dsp_h - 1) << 16 | ((dsp_w - 1) & 0xffff);

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Tue Dec  9 03:14:17 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Dec 2025 12:14:17 +0100
Subject: [PATCH v3 4/8] drm/rockchip: vop2: Enforce scaling workaround in
 plane_check
In-Reply-To: <20251209-vop2-atomic-fixups-v3-0-07c48f0f1f0d@collabora.com>
References: <20251209-vop2-atomic-fixups-v3-0-07c48f0f1f0d@collabora.com>
Message-ID: <20251209-vop2-atomic-fixups-v3-4-07c48f0f1f0d@collabora.com>

From: Daniel Stone <daniels at collabora.com>

It seems only cluster windows are capable of applying downscaling when
the source region has an odd width. Instead of applying a workaround
inside atomic_update, fail the plane check if this is requested.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 9d715d7659af..6d4f22872e67 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -998,6 +998,7 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
 	struct drm_crtc *crtc = pstate->crtc;
 	struct drm_crtc_state *cstate;
 	struct vop2_video_port *vp;
+	struct vop2_win *win = to_vop2_win(plane);
 	struct vop2 *vop2;
 	const struct vop2_data *vop2_data;
 	struct drm_rect *dest = &pstate->dst;
@@ -1065,6 +1066,16 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
 		return -EINVAL;
 	}
 
+	/*
+	 * This is workaround solution for IC design:
+	 * esmart can't support scale down when src_w % 16 == 1.
+	 */
+	if (!vop2_cluster_window(win) && src_w > dest_w && (src_w & 1)) {
+		drm_dbg_kms(vop2->drm,
+			    "Esmart windows cannot downscale odd-width source regions\n");
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
@@ -1226,16 +1237,6 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
 	WARN_ON(src_w < 4);
 	WARN_ON(src_h < 4);
 
-	/*
-	 * This is workaround solution for IC design:
-	 * esmart can't support scale down when src_w % 16 == 1.
-	 */
-	if (!vop2_cluster_window(win) && src_w > dsp_w && (src_w & 1)) {
-		drm_dbg_kms(vop2->drm, "vp%d %s act_w[%d] MODE 16 == 1\n",
-			    vp->id, win->data->name, src_w);
-		src_w -= 1;
-	}
-
 	if (afbc_en && src_w % 4) {
 		drm_dbg_kms(vop2->drm, "vp%d %s src_w[%d] not 4 pixel aligned\n",
 			    vp->id, win->data->name, src_w);

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Tue Dec  9 03:14:21 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Dec 2025 12:14:21 +0100
Subject: [PATCH v3 8/8] drm/rockchip: vop2: Simplify format_mod_supported
In-Reply-To: <20251209-vop2-atomic-fixups-v3-0-07c48f0f1f0d@collabora.com>
References: <20251209-vop2-atomic-fixups-v3-0-07c48f0f1f0d@collabora.com>
Message-ID: <20251209-vop2-atomic-fixups-v3-8-07c48f0f1f0d@collabora.com>

From: Daniel Stone <daniels at collabora.com>

Make it a little less convoluted, and just directly check if the
combination of plane + format + modifier is supported.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 56 +++++++++++-----------------
 1 file changed, 22 insertions(+), 34 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index ea84aa5c625e..579fe794a0b9 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -367,59 +367,47 @@ static bool is_yuv_output(u32 bus_format)
 	}
 }
 
-static bool rockchip_afbc(struct drm_plane *plane, u64 modifier)
-{
-	int i;
-
-	if (modifier == DRM_FORMAT_MOD_LINEAR)
-		return false;
-
-	for (i = 0 ; i < plane->modifier_count; i++)
-		if (plane->modifiers[i] == modifier)
-			return true;
-
-	return false;
-}
-
 static bool rockchip_vop2_mod_supported(struct drm_plane *plane, u32 format,
 					u64 modifier)
 {
 	struct vop2_win *win = to_vop2_win(plane);
 	struct vop2 *vop2 = win->vop2;
+	int i;
 
+	/* No support for implicit modifiers */
 	if (modifier == DRM_FORMAT_MOD_INVALID)
 		return false;
 
-	if (vop2->version == VOP_VERSION_RK3568) {
-		if (vop2_cluster_window(win)) {
-			if (modifier == DRM_FORMAT_MOD_LINEAR) {
-				drm_dbg_kms(vop2->drm,
-					    "Cluster window only supports format with afbc\n");
-				return false;
-			}
-		}
+	/* The cluster window on 3568 is AFBC-only */
+	if (vop2->version == VOP_VERSION_RK3568 && vop2_cluster_window(win) &&
+	    !drm_is_afbc(modifier)) {
+		drm_dbg_kms(vop2->drm,
+			    "Cluster window only supports format with afbc\n");
+		return false;
 	}
 
-	if (format == DRM_FORMAT_XRGB2101010 || format == DRM_FORMAT_XBGR2101010) {
-		if (vop2->version == VOP_VERSION_RK3588) {
-			if (!rockchip_afbc(plane, modifier)) {
-				drm_dbg_kms(vop2->drm, "Only support 32 bpp format with afbc\n");
-				return false;
-			}
-		}
+	/* 10bpc formats on 3588 are AFBC-only */
+	if (vop2->version == VOP_VERSION_RK3588 && !drm_is_afbc(modifier) &&
+	    (format == DRM_FORMAT_XRGB2101010 || format == DRM_FORMAT_XBGR2101010)) {
+		drm_dbg_kms(vop2->drm, "Only support 10bpc format with afbc\n");
+		return false;
 	}
 
+	/* Linear is otherwise supported everywhere */
 	if (modifier == DRM_FORMAT_MOD_LINEAR)
 		return true;
 
-	if (!rockchip_afbc(plane, modifier)) {
-		drm_dbg_kms(vop2->drm, "Unsupported format modifier 0x%llx\n",
-			    modifier);
-
+	/* Not all format+modifier combinations are allowable */
+	if (vop2_convert_afbc_format(format) == VOP2_AFBC_FMT_INVALID)
 		return false;
+
+	/* Different windows have different format/modifier support */
+	for (i = 0; i < plane->modifier_count; i++) {
+		if (plane->modifiers[i] == modifier)
+			return true;
 	}
 
-	return vop2_convert_afbc_format(format) >= 0;
+	return false;
 }
 
 /*

-- 
2.52.0



From jacky_chou at aspeedtech.com  Tue Dec  9 03:15:31 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Tue, 9 Dec 2025 19:15:31 +0800
Subject: [PATCH net v2] net: mdio: aspeed: add dummy read to avoid
 read-after-write issue
Message-ID: <20251209-aspeed_mdio_add_dummy_read-v2-1-5f6061641989@aspeedtech.com>

The Aspeed MDIO controller may return incorrect data when a read operation
follows immediately after a write. Due to a controller bug, the subsequent
read can latch stale data, causing the polling logic to terminate earlier
than expected.

To work around this hardware issue, insert a dummy read after each write
operation. This ensures that the next actual read returns the correct
data and prevents premature polling exit.

This workaround has been verified to stabilize MDIO transactions on
affected Aspeed platforms.

Fixes: f160e99462c6 ("net: phy: Add mdio-aspeed")
Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
---
Changes in v2:
- Updated the Fixes: tag
- Link to v1: https://lore.kernel.org/r/20251208-aspeed_mdio_add_dummy_read-v1-1-0a1861ad2161 at aspeedtech.com
---
 drivers/net/mdio/mdio-aspeed.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/net/mdio/mdio-aspeed.c b/drivers/net/mdio/mdio-aspeed.c
index e55be6dc9ae7..7d11add3c05e 100644
--- a/drivers/net/mdio/mdio-aspeed.c
+++ b/drivers/net/mdio/mdio-aspeed.c
@@ -63,6 +63,13 @@ static int aspeed_mdio_op(struct mii_bus *bus, u8 st, u8 op, u8 phyad, u8 regad,
 
 	iowrite32(ctrl, ctx->base + ASPEED_MDIO_CTRL);
 
+	/* Workaround for read-after-write issue.
+	 * The controller may return stale data if a read follows immediately
+	 * after a write. A dummy read forces the hardware to update its
+	 * internal state, ensuring that the next real read returns correct data.
+	 */
+	(void)ioread32(ctx->base + ASPEED_MDIO_CTRL);
+
 	return readl_poll_timeout(ctx->base + ASPEED_MDIO_CTRL, ctrl,
 				!(ctrl & ASPEED_MDIO_CTRL_FIRE),
 				ASPEED_MDIO_INTERVAL_US,

---
base-commit: 0373d5c387f24de749cc22e694a14b3a7c7eb515
change-id: 20251208-aspeed_mdio_add_dummy_read-587ab8808817

Best regards,
-- 
Jacky Chou <jacky_chou at aspeedtech.com>



From nicolas.frattaroli at collabora.com  Tue Dec  9 03:14:15 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Dec 2025 12:14:15 +0100
Subject: [PATCH v3 2/8] drm/rockchip: vop2: Switch impossible pos
 conditional to WARN_ON
In-Reply-To: <20251209-vop2-atomic-fixups-v3-0-07c48f0f1f0d@collabora.com>
References: <20251209-vop2-atomic-fixups-v3-0-07c48f0f1f0d@collabora.com>
Message-ID: <20251209-vop2-atomic-fixups-v3-2-07c48f0f1f0d@collabora.com>

From: Daniel Stone <daniels at collabora.com>

We already clip the plane to the display bounds in atomic_check, and
ensure that it is sufficiently sized. Instead of trying to catch this
and adjust for it in atomic_update, just assert that atomic_check has
done its job.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 29 +++++++++-------------------
 1 file changed, 9 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 20b49209ddcd..81b3eba07095 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1214,28 +1214,17 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
 	src_w = drm_rect_width(src) >> 16;
 	src_h = drm_rect_height(src) >> 16;
 	dsp_w = drm_rect_width(dest);
-
-	if (dest->x1 + dsp_w > adjusted_mode->hdisplay) {
-		drm_dbg_kms(vop2->drm,
-			    "vp%d %s dest->x1[%d] + dsp_w[%d] exceed mode hdisplay[%d]\n",
-			    vp->id, win->data->name, dest->x1, dsp_w, adjusted_mode->hdisplay);
-		dsp_w = adjusted_mode->hdisplay - dest->x1;
-		if (dsp_w < 4)
-			dsp_w = 4;
-		src_w = dsp_w * src_w / drm_rect_width(dest);
-	}
-
 	dsp_h = drm_rect_height(dest);
 
-	if (dest->y1 + dsp_h > adjusted_mode->vdisplay) {
-		drm_dbg_kms(vop2->drm,
-			    "vp%d %s dest->y1[%d] + dsp_h[%d] exceed mode vdisplay[%d]\n",
-			    vp->id, win->data->name, dest->y1, dsp_h, adjusted_mode->vdisplay);
-		dsp_h = adjusted_mode->vdisplay - dest->y1;
-		if (dsp_h < 4)
-			dsp_h = 4;
-		src_h = dsp_h * src_h / drm_rect_height(dest);
-	}
+	/* drm_atomic_helper_check_plane_state calls drm_rect_clip_scaled for
+	 * us, which keeps our planes bounded within the CRTC active area
+	 */
+	WARN_ON(dest->x1 + dsp_w > adjusted_mode->hdisplay);
+	WARN_ON(dest->y1 + dsp_h > adjusted_mode->vdisplay);
+	WARN_ON(dsp_w < 4);
+	WARN_ON(dsp_h < 4);
+	WARN_ON(src_w < 4);
+	WARN_ON(src_h < 4);
 
 	/*
 	 * This is workaround solution for IC design:

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Tue Dec  9 03:14:19 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Dec 2025 12:14:19 +0100
Subject: [PATCH v3 6/8] drm/rockchip: vop2: Enforce AFBC transform stride
 align in plane_check
In-Reply-To: <20251209-vop2-atomic-fixups-v3-0-07c48f0f1f0d@collabora.com>
References: <20251209-vop2-atomic-fixups-v3-0-07c48f0f1f0d@collabora.com>
Message-ID: <20251209-vop2-atomic-fixups-v3-6-07c48f0f1f0d@collabora.com>

From: Daniel Stone <daniels at collabora.com>

Make sure we can't break the hardware by requesting an unsupported
configuration.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index a029ed73dda7..337b01ed29a6 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1083,6 +1083,15 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
 		return -EINVAL;
 	}
 
+	if (drm_is_afbc(fb->modifier) &&
+	    pstate->rotation &
+		(DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270) &&
+	    (fb->pitches[0] << 3) / vop2_get_bpp(fb->format) % 64) {
+		drm_dbg_kms(vop2->drm,
+			    "AFBC buffers must be 64-byte aligned for horizontal rotation or mirroring\n");
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
@@ -1290,9 +1299,6 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
 		 * with WIN_VIR_STRIDE.
 		 */
 		stride = (fb->pitches[0] << 3) / bpp;
-		if ((stride & 0x3f) && (xmirror || rotate_90 || rotate_270))
-			drm_dbg_kms(vop2->drm, "vp%d %s stride[%d] not 64 pixel aligned\n",
-				    vp->id, win->data->name, stride);
 
 		 /* It's for head stride, each head size is 16 byte */
 		stride = ALIGN(stride, block_w) / block_w * 16;

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Tue Dec  9 03:14:16 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Dec 2025 12:14:16 +0100
Subject: [PATCH v3 3/8] drm/rockchip: vop2: Fix Esmart test condition
In-Reply-To: <20251209-vop2-atomic-fixups-v3-0-07c48f0f1f0d@collabora.com>
References: <20251209-vop2-atomic-fixups-v3-0-07c48f0f1f0d@collabora.com>
Message-ID: <20251209-vop2-atomic-fixups-v3-3-07c48f0f1f0d@collabora.com>

From: Daniel Stone <daniels at collabora.com>

If we want to find out if a window is Esmart or not, test for not being
a cluster window, rather than AFBDC presence.

No functional effect as only cluster windows support AFBC decode.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 81b3eba07095..9d715d7659af 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1230,12 +1230,10 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
 	 * This is workaround solution for IC design:
 	 * esmart can't support scale down when src_w % 16 == 1.
 	 */
-	if (!(win->data->feature & WIN_FEATURE_AFBDC)) {
-		if (src_w > dsp_w && (src_w & 0xf) == 1) {
-			drm_dbg_kms(vop2->drm, "vp%d %s act_w[%d] MODE 16 == 1\n",
-				    vp->id, win->data->name, src_w);
-			src_w -= 1;
-		}
+	if (!vop2_cluster_window(win) && src_w > dsp_w && (src_w & 1)) {
+		drm_dbg_kms(vop2->drm, "vp%d %s act_w[%d] MODE 16 == 1\n",
+			    vp->id, win->data->name, src_w);
+		src_w -= 1;
 	}
 
 	if (afbc_en && src_w % 4) {

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Tue Dec  9 03:14:20 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Dec 2025 12:14:20 +0100
Subject: [PATCH v3 7/8] drm/rockchip: vop2: Use drm_is_afbc helper function
In-Reply-To: <20251209-vop2-atomic-fixups-v3-0-07c48f0f1f0d@collabora.com>
References: <20251209-vop2-atomic-fixups-v3-0-07c48f0f1f0d@collabora.com>
Message-ID: <20251209-vop2-atomic-fixups-v3-7-07c48f0f1f0d@collabora.com>

From: Daniel Stone <daniels at collabora.com>

We don't need to do a long open-coded walk here; we can simply check the
modifier value.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 337b01ed29a6..ea84aa5c625e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1207,7 +1207,7 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
 		return;
 	}
 
-	afbc_en = rockchip_afbc(plane, fb->modifier);
+	afbc_en = drm_is_afbc(fb->modifier);
 
 	offset = (src->x1 >> 16) * fb->format->cpp[0];
 

-- 
2.52.0



From linux at armlinux.org.uk  Tue Dec  9 03:27:57 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Tue, 9 Dec 2025 11:27:57 +0000
Subject: [PATCH net v2] net: mdio: aspeed: add dummy read to avoid
 read-after-write issue
In-Reply-To: <20251209-aspeed_mdio_add_dummy_read-v2-1-5f6061641989@aspeedtech.com>
References: <20251209-aspeed_mdio_add_dummy_read-v2-1-5f6061641989@aspeedtech.com>
Message-ID: <aTgHva-UVEPl9EAR@shell.armlinux.org.uk>

On Tue, Dec 09, 2025 at 07:15:31PM +0800, Jacky Chou wrote:
> +	/* Workaround for read-after-write issue.
> +	 * The controller may return stale data if a read follows immediately
> +	 * after a write. A dummy read forces the hardware to update its
> +	 * internal state, ensuring that the next real read returns correct data.
> +	 */
> +	(void)ioread32(ctx->base + ASPEED_MDIO_CTRL);

What purpose does this cast to void achieve in an already void context?

We have plenty of functions that get called in the kernel that return a
value which the caller ignores, never assigning to a variable, none of
these warn.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From vulab at iscas.ac.cn  Tue Dec  9 03:33:32 2025
From: vulab at iscas.ac.cn (Haotian Zhang)
Date: Tue,  9 Dec 2025 19:33:32 +0800
Subject: [PATCH] iommu/rockchip: Check of_find_device_by_node() return value
Message-ID: <20251209113333.1086-1-vulab@iscas.ac.cn>

rk_iommu_of_xlate() calls of_find_device_by_node() without
verifying it is non-NULL, which can lead to a NULL pointer
dereference and crash.

Add a check for a NULL return from of_find_device_by_node()
and return -ENODEV upon failure.

Fixes: 5fd577c3eac3 ("iommu/rockchip: Use OF_IOMMU to attach devices automatically")
Signed-off-by: Haotian Zhang <vulab at iscas.ac.cn>
---
 drivers/iommu/rockchip-iommu.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 0861dd469bd8..e59d0617574b 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -1153,6 +1153,8 @@ static int rk_iommu_of_xlate(struct device *dev,
 	struct rk_iommudata *data;
 
 	iommu_dev = of_find_device_by_node(args->np);
+	if (!iommu_dev)
+		return -ENODEV;
 
 	data = devm_kzalloc(&iommu_dev->dev, sizeof(*data), GFP_KERNEL);
 	if (!data)
-- 
2.50.1.windows.1



From robin.murphy at arm.com  Tue Dec  9 03:34:34 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Tue, 9 Dec 2025 11:34:34 +0000
Subject: [PATCH] iommu/io-pgtable-arm: Add misisng concatenated PGD cases
In-Reply-To: <20251130194506.593700-1-smostafa@google.com>
References: <20251130194506.593700-1-smostafa@google.com>
Message-ID: <18a39079-2285-47fb-b306-040f2bc1bbaa@arm.com>

On 2025-11-30 7:45 pm, Mostafa Saleh wrote:
> arm_lpae_concat_mandatory() assumes that OAS >= IAS which is not
> correct for SMMUs supporting AArch32, and have OAS = 32/36 bits,
> as IAS would be 40 bits.

But that is only when *using* AArch32 format. The bit in chapter 3.4 of 
the SMMU architecture is talking about the maximum IAS that an SMMU 
implementation needs to be able to accommodate based on its 
configuration, but it does then attempt to clarify that the actual IPA 
size in use by any given context should depend on the VMSA format in use:

"VMSAv8-32 LPAE always supports an IPA size of 40 bits, whereas 
VMSAv8-64 and VMSAv9-128 limits the maximum IPA size to the maximum PA 
size."

Rule R_SRKBC in the Arm ARM lays out the exact T0SZ constraints with 
this AArch32/AArch64 detail.

> In that case, concatenation is mandatory in some cases.
> Document those and add the checks, this can be simplified; instead
> of adding extra checks we can say that concatenation is mandatory for:
> - 4K, start level = 0 and OAS <= 42 bits.
> - 16K, start level = 1 and OAS <= 40 bits.
> Which cover all the missing cases.

AArch32 uses a fixed 4K granule, so this cannot impact 16K. Note that we 
don't support AArch32 for SMMUv3 anyway, and while this does technically 
apply to SMMUv1/2, Arm's MMU-400/401/500 implementations all have OAS 
fixed at 40/40/48 bits respectively, so I'd imagine it's quite a rare 
case to encounter in practice.

Thanks,
Robin.

> Reported-by: Tomasz Nowicki <tnowicki at google.com>
> Fixes: 4dcac8407fe1 ("iommu/io-pgtable-arm: Fix stage-2 concatenation with 16K")
> Signed-off-by: Mostafa Saleh <smostafa at google.com>
> ---
>   drivers/iommu/io-pgtable-arm.c | 10 ++++++----
>   1 file changed, 6 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
> index e6626004b323..ecf27e86b429 100644
> --- a/drivers/iommu/io-pgtable-arm.c
> +++ b/drivers/iommu/io-pgtable-arm.c
> @@ -223,6 +223,8 @@ static inline int arm_lpae_max_entries(int i, struct arm_lpae_io_pgtable *data)
>    *   b) 40 bits PA size with 16K: use level 2 instead of level 1 (16 tables for ias = oas)
>    *   c) 42 bits PA size with 4K: use level 1 instead of level 0 (8 tables for ias = oas)
>    *   d) 48 bits PA size with 16K: use level 1 instead of level 0 (2 tables for ias = oas)
> + *   f) 32/36 bits PA size with 4K and 40 bits IAS: use level 1 instead of level 0
> + *   g) 32/36 bits PA size with 16K and 40 bits IAS: use level 2 instead of level 1
>    */
>   static inline bool arm_lpae_concat_mandatory(struct io_pgtable_cfg *cfg,
>   					     struct arm_lpae_io_pgtable *data)
> @@ -234,13 +236,13 @@ static inline bool arm_lpae_concat_mandatory(struct io_pgtable_cfg *cfg,
>   	if ((ARM_LPAE_GRANULE(data) == SZ_16K) && (data->start_level == 0))
>   		return (oas == 48) || (ias == 48);
>   
> -	/* Covers 2.a and 2.c */
> +	/* Covers 2.a, 2.c and 2.f */
>   	if ((ARM_LPAE_GRANULE(data) == SZ_4K) && (data->start_level == 0))
> -		return (oas == 40) || (oas == 42);
> +		return (oas <= 42);
>   
> -	/* Case 2.b */
> +	/* Case 2.b and 2.g */
>   	return (ARM_LPAE_GRANULE(data) == SZ_16K) &&
> -	       (data->start_level == 1) && (oas == 40);
> +	       (data->start_level == 1) && (oas <= 40);
>   }
>   
>   static dma_addr_t __arm_lpae_dma_addr(void *pages)



From sudeep.holla at arm.com  Tue Dec  9 03:39:40 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Tue, 9 Dec 2025 11:39:40 +0000
Subject: [RFC PATCH 0/5] Arm LFA: Improvements and interrupt support
In-Reply-To: <20251208221319.1524888-1-vvidwans@nvidia.com>
References: <20251208221319.1524888-1-vvidwans@nvidia.com>
Message-ID: <20251209-miniature-curassow-of-energy-b6a303@sudeepholla>

On Mon, Dec 08, 2025 at 10:13:10PM +0000, Vedashree Vidwans wrote:
> Hello,
> 
> The patches update the proposed Arm Live Firmware Activation (LFA)
> kernel driver [1] to incorporate review feedback [2] and refine the
> activation flow while remaining aligned with the LFA specification
> DEN0147 [3] and the SMCCC 1.2 calling convention. The series keeps
> the existing functionality but restructures and extends it to improve
> robustness, reviewability, and future extensibility.?
> 
> The SMCCC usage in the driver is updated to consistently use the
> SMCCC 1.2 register-based calling convention, consolidating arguments
> and results into a single struct to reduce stack usage and simplify
> the SMC interface. The patches also split the original changes into
> focused pieces and document the device node bindings in the commit
> messages, making it easier to follow and validate the implementation
> against the specification.?
> 
> The kernel driver is registered as a platform driver in accordence to
> the LFA device defined by the specification [3]. The driver now extends
> interface for interrupt-based enablement of LFA. During LFA, the
> interrupt
> thread refreshes firmware component details after each activation step
> and iterates over all activable components until no further activation
> is pending, matching the spec?s allowance for component detail changes
> after activation. This ensures that sysfs exposure of LFA components
> remains consistent with the authoritative information provided by the
> secure firmware.?
> 
> The handling of CPU rendezvous is adjusted so that the kernel now
> honors the rendezvous policy chosen by the firmware, instead of
> unconditionally forcing a rendezvous. This reflects experience with
> existing firmware deployments where mandatory rendezvous is not
> required, while still allowing the firmware to request it when
> needed.?
> 
> Thank you,
> Veda
> 
> [1] https://lore.kernel.org/lkml/20250926123145.268728-1-salman.nabi at arm.com/
> [2] https://lkml.org/lkml/2025/10/8/980
> [3] https://developer.arm.com/documentation/den0147/latest/
> 
> Vedashree Vidwans (5):
>   firmware: smccc: LFA: use smcc 1.2
>   firmware: smccc: LFA: refactor
>   firmware: smccc: add timeout, touch wdt
>   firmware: smccc: register as platform driver
>   firmware: smccc: lfa: refresh fw details
> 
>  drivers/firmware/smccc/Kconfig  |   3 +-
>  drivers/firmware/smccc/lfa_fw.c | 478 +++++++++++++++++++++++++-------

Same comment as before[1], looks like the feedback got ignored or missed.

-- 
Regards,
Sudeep

[1] https://lore.kernel.org/all/20251009-calculating-glorious-oriole-ceccf6 at sudeepholla


From angelogioacchino.delregno at collabora.com  Tue Dec  9 03:41:58 2025
From: angelogioacchino.delregno at collabora.com (AngeloGioacchino Del Regno)
Date: Tue, 9 Dec 2025 12:41:58 +0100
Subject: [PATCH] arm64: dts: mediatek: Apply mt8395-radxa DT overlay at
 build time
In-Reply-To: <20251205215940.19287-1-linux@fw-web.de>
References: <20251205215940.19287-1-linux@fw-web.de>
Message-ID: <0d03ed27-418b-4564-bf8d-739b253b2213@collabora.com>

Il 05/12/25 22:59, Frank Wunderlich ha scritto:
> From: "Rob Herring (Arm)" <robh at kernel.org>
> 
> It's a requirement that DT overlays be applied at build time in order to
> validate them as overlays are not validated on their own.
> 
> Add missing target for mt8395-radxa hd panel overlay.
> 
> Fixes: 4c8ff61199a7 ("arm64: dts: mediatek: mt8395-radxa-nio-12l: Add Radxa 8 HD panel")
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> Signed-off-by: Frank Wunderlich <frank-w at public-files.de>

Acked-by: AngeloGioacchino Del Regno <angelogiaocchino.delregno at collabora.com>

> ---
> This will show a warning [1] in upcoming 6.19.
> 
> Note that if it is desired that the combined .dtb is not installed, then
> the combined .dtb should be added to 'dtb-' variable instead.
> ---
> extracted missing part from [2] with updated commit title/description
> after my bananapi series [3] to solve all warnings. Added Fixes-tag to
> make sure it lands in 6.19.
> 
> [1] https://lore.kernel.org/all/20251114222759.4181152-1-robh at kernel.org/
> [2] https://patchwork.kernel.org/project/linux-mediatek/patch/20251117211306.725678-1-robh at kernel.org/
> [3] https://patchwork.kernel.org/project/linux-mediatek/cover/20251119175124.48947-1-linux at fw-web.de/
> ---
>   arch/arm64/boot/dts/mediatek/Makefile | 2 ++
>   1 file changed, 2 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile
> index cac8f4c6d76f..3f76d9ce9879 100644
> --- a/arch/arm64/boot/dts/mediatek/Makefile
> +++ b/arch/arm64/boot/dts/mediatek/Makefile
> @@ -166,6 +166,8 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8390-grinn-genio-700-sbc.dtb
>   dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-kontron-3-5-sbc-i1200.dtb
>   dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-radxa-nio-12l.dtb
>   dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-radxa-nio-12l-8-hd-panel.dtbo
> +mt8395-radxa-nio-12l-8-hd-panel-dtbs := mt8395-radxa-nio-12l.dtb mt8395-radxa-nio-12l-8-hd-panel.dtbo
> +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-radxa-nio-12l-8-hd-panel.dtb
>   dtb-$(CONFIG_ARCH_MEDIATEK) += mt8516-pumpkin.dtb
>   
>   # Device tree overlays support



From sudeep.holla at arm.com  Tue Dec  9 03:42:16 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Tue, 9 Dec 2025 11:42:16 +0000
Subject: [RFC PATCH 1/5] firmware: smccc: LFA: use smcc 1.2
In-Reply-To: <20251208221319.1524888-2-vvidwans@nvidia.com>
References: <20251208221319.1524888-1-vvidwans@nvidia.com>
 <20251208221319.1524888-2-vvidwans@nvidia.com>
Message-ID: <20251209-curvy-walrus-of-wonder-dbb178@sudeepholla>

On Mon, Dec 08, 2025 at 10:13:11PM +0000, Vedashree Vidwans wrote:
> Update driver to use SMCCC 1.2+ version as mentioned in the LFA spec.
> 

I would prefer if you work with Salman Nabi and get this incorporated
in the original patch by providing this as a review feedback.

There is no point in having this independent of the original patch as it
is not yet merged.

-- 
Regards,
Sudeep


From robin.murphy at arm.com  Tue Dec  9 03:43:55 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Tue, 9 Dec 2025 11:43:55 +0000
Subject: [PATCH] iommu/rockchip: Check of_find_device_by_node() return
 value
In-Reply-To: <20251209113333.1086-1-vulab@iscas.ac.cn>
References: <20251209113333.1086-1-vulab@iscas.ac.cn>
Message-ID: <e22ea775-84e3-4116-a81a-52031be9f176@arm.com>

On 2025-12-09 11:33 am, Haotian Zhang wrote:
> rk_iommu_of_xlate() calls of_find_device_by_node() without
> verifying it is non-NULL, which can lead to a NULL pointer
> dereference and crash.

No, it can't. Please look at how of_xlate is called - at this point we 
are looking up the IOMMU device, which has a driver bound to it, which 
has registered ops against this of_node that are the only way to reach 
this function in the first place. If the device could have somehow 
disappeared from underneath an active driver, this potential crash is 
the least of the kernel's worries...

Thanks,
Robin.

> Add a check for a NULL return from of_find_device_by_node()
> and return -ENODEV upon failure.
> 
> Fixes: 5fd577c3eac3 ("iommu/rockchip: Use OF_IOMMU to attach devices automatically")
> Signed-off-by: Haotian Zhang <vulab at iscas.ac.cn>
> ---
>   drivers/iommu/rockchip-iommu.c | 2 ++
>   1 file changed, 2 insertions(+)
> 
> diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
> index 0861dd469bd8..e59d0617574b 100644
> --- a/drivers/iommu/rockchip-iommu.c
> +++ b/drivers/iommu/rockchip-iommu.c
> @@ -1153,6 +1153,8 @@ static int rk_iommu_of_xlate(struct device *dev,
>   	struct rk_iommudata *data;
>   
>   	iommu_dev = of_find_device_by_node(args->np);
> +	if (!iommu_dev)
> +		return -ENODEV;
>   
>   	data = devm_kzalloc(&iommu_dev->dev, sizeof(*data), GFP_KERNEL);
>   	if (!data)



From sudeep.holla at arm.com  Tue Dec  9 03:47:48 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Tue, 9 Dec 2025 11:47:48 +0000
Subject: [RFC PATCH 4/5] firmware: smccc: register as platform driver
In-Reply-To: <20251208221319.1524888-5-vvidwans@nvidia.com>
References: <20251208221319.1524888-1-vvidwans@nvidia.com>
 <20251208221319.1524888-5-vvidwans@nvidia.com>
Message-ID: <20251209-hysterical-cobalt-viper-54433c@sudeepholla>

On Mon, Dec 08, 2025 at 10:13:14PM +0000, Vedashree Vidwans wrote:
> - Update driver to be in-built kernel module. This will ensure driver is
> installed in kernel and would not require any user intervention.
> - Register the LFA driver as a platform driver corresponding to
> 'armhf000' device. The driver will be invoked when the device is
> detected on a platform.
> - Add functionality to register LFA interrupt in the driver probe().
> This LFA IRQ number will be retrived from the LFA device node.
> - On IRQ, driver will query FW component details and trigger activation
> of capable and pending FW component. The driver will loop to update FW
> component details after every successful FW component activation.
> - Mutex synchronization is implemented to avoid concurrent LFA updates
> through interrupt and sysfs interfaces.
> 
> Device node snippet from LFA spec[1]:
> fwu0 {
>     compatible = "arm,armhf000";
>     memory-region = <&fwu_payload>;
>     interrupt-parent = <&ic>;
>     interrupts = <0 100 1>; // SPI, Interrupt #100, Edge Rising
> };
> 

This will be gone in the latest beta of LFA, so please discuss and get
an agreement for the LFA device tree bindings.

We don't just use ACPI HID as devicetree compatibles. There are more
aligned with ACPI CID IIUC but I don't expect you to use ACPI CID just to
match DT compatible as ACPI HID will be defined for LFA.

> [1] https://developer.arm.com/documentation/den0147/latest/
> 
> Signed-off-by: Vedashree Vidwans <vvidwans at nvidia.com>
> ---
>  drivers/firmware/smccc/Kconfig  |   3 +-
>  drivers/firmware/smccc/lfa_fw.c | 124 +++++++++++++++++++++++++++++++-
>  2 files changed, 125 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/firmware/smccc/Kconfig b/drivers/firmware/smccc/Kconfig
> index 48b98c14f770..c21be43fbfed 100644
> --- a/drivers/firmware/smccc/Kconfig
> +++ b/drivers/firmware/smccc/Kconfig
> @@ -25,8 +25,9 @@ config ARM_SMCCC_SOC_ID
>  	  platforms providing some sysfs information about the SoC variant.
>  
>  config ARM_LFA
> -	tristate "Arm Live Firmware activation support"
> +	bool "Arm Live Firmware activation support"
>  	depends on HAVE_ARM_SMCCC_DISCOVERY
> +	default y
>  	help
>  	  Include support for triggering Live Firmware Activation, which
>  	  allows to upgrade certain firmware components without a reboot.
> diff --git a/drivers/firmware/smccc/lfa_fw.c b/drivers/firmware/smccc/lfa_fw.c
> index 0e420cefa260..24916fc53420 100644
> --- a/drivers/firmware/smccc/lfa_fw.c
> +++ b/drivers/firmware/smccc/lfa_fw.c
> @@ -19,7 +19,12 @@
>  #include <linux/nmi.h>
>  #include <linux/ktime.h>
>  #include <linux/delay.h>
> +#include <linux/platform_device.h>
> +#include <linux/acpi.h>
> +#include <linux/interrupt.h>
> +#include <linux/mutex.h>
>  
> +#define DRIVER_NAME	"ARM_LFA"
>  #define LFA_ERROR_STRING(name) \
>  	[name] = #name
>  #undef pr_fmt
> @@ -129,6 +134,7 @@ static const struct fw_image_uuid {
>  };
>  
>  static struct kobject *lfa_dir;
> +static DEFINE_MUTEX(lfa_lock);
>  
>  static int get_nr_lfa_components(void)
>  {
> @@ -374,17 +380,23 @@ static ssize_t activate_store(struct kobject *kobj, struct kobj_attribute *attr,
>  					 image_attrs[LFA_ATTR_ACTIVATE]);
>  	int ret;
>  
> +	if (!mutex_trylock(&lfa_lock)) {
> +		pr_err("Mutex locked, try again");
> +		return -EAGAIN;
> +	}
> +
>  	ret = activate_fw_image(attrs);
>  	if (ret) {
>  		pr_err("Firmware activation failed: %s\n",
>  			lfa_error_strings[-ret]);
> -
> +		mutex_unlock(&lfa_lock);
>  		return -ECANCELED;
>  	}
>  
>  	pr_info("Firmware activation succeeded\n");
>  
>  	/* TODO: refresh image flags here*/
> +	mutex_unlock(&lfa_lock);
>  	return count;
>  }
>  
> @@ -510,6 +522,106 @@ static int create_fw_images_tree(void)
>  	return 0;
>  }
>  
> +static irqreturn_t lfa_irq_thread(int irq, void *data)
> +{
> +	struct image_props *attrs = NULL;
> +	int ret;
> +	int num_of_components, curr_component;
> +
> +	mutex_lock(&lfa_lock);
> +
> +	/*
> +	 * As per LFA spec, after activation of a component, the caller
> +	 * is expected to re-enumerate the component states (using
> +	 * LFA_GET_INFO then LFA_GET_INVENTORY).
> +	 * Hence we need an unconditional loop.
> +	 */
> +
> +	do {
> +		/* TODO: refresh image flags here */
> +		/* If refresh fails goto exit_unlock */
> +
> +		/* Initialize counters to track list traversal  */
> +		num_of_components = get_nr_lfa_components();
> +		curr_component = 0;
> +
> +		/* Execute PRIME and ACTIVATE for activable FW component */
> +		list_for_each_entry(attrs, &lfa_fw_images, image_node) {
> +			curr_component++;
> +			if ((!attrs->activation_capable) || (!attrs->activation_pending)) {
> +				/* LFA not applicable for this FW component */
> +				continue;
> +			}
> +
> +			ret = activate_fw_image(attrs);
> +			if (ret) {
> +				pr_err("Firmware %s activation failed: %s\n",
> +					attrs->image_name, lfa_error_strings[-ret]);
> +				goto exit_unlock;
> +			}
> +
> +			pr_info("Firmware %s activation succeeded", attrs->image_name);
> +			/* Refresh FW component details */
> +			break;
> +		}
> +	} while (curr_component < num_of_components);
> +
> +	/* TODO: refresh image flags here */
> +	/* If refresh fails goto exit_unlock */
> +
> +exit_unlock:
> +	mutex_unlock(&lfa_lock);
> +	return IRQ_HANDLED;
> +}
> +
> +static int __init lfa_probe(struct platform_device *pdev)
> +{
> +	int err;
> +	unsigned int irq;
> +
> +	err = platform_get_irq_byname_optional(pdev, "fw-store-updated-interrupt");

Nice, "fw-store-updated-interrupt" is not even mentioned in the example DT
node above, let alone proper DT bindings.

-- 
Regards,
Sudeep


From leo.yan at arm.com  Tue Dec  9 04:19:16 2025
From: leo.yan at arm.com (Leo Yan)
Date: Tue, 9 Dec 2025 12:19:16 +0000
Subject: [PATCH v6 2/2] coresight: cti: Add Qualcomm extended CTI support
In-Reply-To: <20251209081649.105623-1-yingchao.deng@oss.qualcomm.com>
References: <CAJ9a7Vg9Efi-5eecfiUF82_Qq8Jg9imN5q1-VKYZoPVUxNpjhA@mail.gmail.com>
 <20251209081649.105623-1-yingchao.deng@oss.qualcomm.com>
Message-ID: <20251209121916.GT724103@e132581.arm.com>

Hi Yingchao,

On Tue, Dec 09, 2025 at 04:16:28PM +0800, Yingchao Deng wrote:
> Hi Leo & Mike
> 
> Based on Leo?s suggestions, I created a new patch, but there are three points that do not fully align with his recommendations:
> 
>     1. The helper function for returning the register address now returns only the offset, because returning the full address would conflict with cti_write_single_reg.

No need to change each callsite for cti_write_single_reg().  You could
update cti_write_single_reg() instead:

  void cti_write_single_reg(struct cti_drvdata *drvdata,
                            int offset, u32 value)
  {
          CS_UNLOCK(drvdata->base);
          writel_relaxed(value, cti_reg_addr(drvdata, offset));
          CS_LOCK(drvdata->base);
  }

>     2. For registers such as triginstatus1...3, I defined additional macros CTITRIGINSTATUS1...3. This is because CTITRIGINSTATUS + 0x4 equals CTITRIGOUTSTATUS, and to avoid conflicts with existing macros, I chose numbers starting from 0x1000 for the new definitions.

To avoid the register naming pollution, please don't define the common
names but only used for Qcom registers.

AFAIK, you even don't need to define these registers.  These registers
are only used for sysfs knobs, we can define an extra "nr" field (e.g.,
bits[31..28] for indexing these registers, something like:

  #define CIT_REG_NR_SHIFT          28
  #define CIT_REG_NR_MASK           GENMASK(31, 28)
  #define CTI_REG_GET_NR(reg)       FIELD_GET(CIT_REG_NR_MASK, (reg))
  #define CTI_REG_SET_NR(reg, nr)   ((reg) | FIELD_PREP(CIT_REG_NR_MASK, (nr))

  static struct attribute *coresight_cti_regs_attrs[] = {
  ...
    coresight_cti_reg(triginstatus, CTITRIGINSTATUS),
    coresight_cti_reg(triginstatus1, CTI_REG_SET_NR(CTITRIGINSTATUS, 1)),
    coresight_cti_reg(triginstatus2, CTI_REG_SET_NR(CTITRIGINSTATUS, 2)),
    coresight_cti_reg(triginstatus3, CTI_REG_SET_NR(CTITRIGINSTATUS, 3)),
  ...

Then, you just need to decode "nr" fields in cti_qcom_reg_off().

>     3. Regarding the visibility of attributes for triginstatus1...3, since coresight_cti_reg produces an anonymous variable that cannot be directly referenced, I used coresight_cti_regs_attrs[i] to obtain the attribute corresponding to triginstatus1.

Okay, I get the meaning for "an anonymous variable" - there have no
field naming when define attr with the macro coresight_cti_reg().

but you could comparing the attr string?

  if (!strcmp(attr->name, "triginstatus1") ||
      !strcmp(attr->name, "triginstatus2") ||
      !strcmp(attr->name, "triginstatus3"))
      ...

Thanks,
Leo


From rohan.g.thomas at altera.com  Tue Dec  9 04:27:07 2025
From: rohan.g.thomas at altera.com (G Thomas, Rohan)
Date: Tue, 9 Dec 2025 17:57:07 +0530
Subject: [PATCH net v2] net: stmmac: Fix E2E delay mechanism
In-Reply-To: <26656845-d9d6-4fd2-bfff-99996cf03741@redhat.com>
References: <20251129-ext-ptp-2v-v2-1-d23aca3e694f@altera.com>
 <26656845-d9d6-4fd2-bfff-99996cf03741@redhat.com>
Message-ID: <29e1a620-1747-4a48-9ead-867c1e5734d0@altera.com>

Hi Paolo,

On 12/4/2025 3:28 PM, Paolo Abeni wrote:
> On 11/29/25 4:07 AM, Rohan G Thomas wrote:
>> For E2E delay mechanism, "received DELAY_REQ without timestamp" error
>> messages show up for dwmac v3.70+ and dwxgmac IPs.
>>
>> This issue affects socfpga platforms, Agilex7 (dwmac 3.70) and
>> Agilex5 (dwxgmac). According to the databook, to enable timestamping
>> for all events, the SNAPTYPSEL bits in the MAC_Timestamp_Control
>> register must be set to 2'b01, and the TSEVNTENA bit must be cleared
>> to 0'b0.
>>
>> Commit 3cb958027cb8 ("net: stmmac: Fix E2E delay mechanism") already
>> addresses this problem for all dwmacs above version v4.10. However,
>> same holds true for v3.70 and above, as well as for dwxgmac. Updates
>> the check accordingly.
>>
>> Fixes: 14f347334bf2 ("net: stmmac: Correctly take timestamp for PTPv2")
>> Fixes: f2fb6b6275eb ("net: stmmac: enable timestamp snapshot for required PTP packets in dwmac v5.10a")
>> Fixes: 3cb958027cb8 ("net: stmmac: Fix E2E delay mechanism")
>> Signed-off-by: Rohan G Thomas <rohan.g.thomas at altera.com>
>> ---
>> v1 -> v2:
>>     - Rebased patch to net tree
>>     - Replace core_type with has_xgmac
>>     - Nit changes in the commit message
>>     - Link: https://lore.kernel.org/all/20251125-ext-ptp-fix-v1-1-83f9f069cb36 at altera.com/
> 
> Given there is some uncertain WRT the exact oldest version to be used,
> it would be great to have some 3rd party testing/feedback on this. Let's
> wait a little more.

Thanks for reviewing the patch. Sure, will wait for additional feedback.

> 
> Thanks,
> 
> Paolo
> 

Best Regards,
Rohan



From rohan.g.thomas at altera.com  Tue Dec  9 04:31:05 2025
From: rohan.g.thomas at altera.com (G Thomas, Rohan)
Date: Tue, 9 Dec 2025 18:01:05 +0530
Subject: [PATCH net v2] net: stmmac: Fix E2E delay mechanism
In-Reply-To: <aTFuJUiLMnHrnpW5@shell.armlinux.org.uk>
References: <20251129-ext-ptp-2v-v2-1-d23aca3e694f@altera.com>
 <26656845-d9d6-4fd2-bfff-99996cf03741@redhat.com>
 <aTFuJUiLMnHrnpW5@shell.armlinux.org.uk>
Message-ID: <9f0da5db-e92a-42e2-b788-2b07b8d28cfa@altera.com>

Hi Russell,

Thanks for reviewing the patch.

On 12/4/2025 4:49 PM, Russell King (Oracle) wrote:
> On Thu, Dec 04, 2025 at 10:58:40AM +0100, Paolo Abeni wrote:
>> On 11/29/25 4:07 AM, Rohan G Thomas wrote:
>>> For E2E delay mechanism, "received DELAY_REQ without timestamp" error
>>> messages show up for dwmac v3.70+ and dwxgmac IPs.
>>>
>>> This issue affects socfpga platforms, Agilex7 (dwmac 3.70) and
>>> Agilex5 (dwxgmac). According to the databook, to enable timestamping
>>> for all events, the SNAPTYPSEL bits in the MAC_Timestamp_Control
>>> register must be set to 2'b01, and the TSEVNTENA bit must be cleared
>>> to 0'b0.
>>>
>>> Commit 3cb958027cb8 ("net: stmmac: Fix E2E delay mechanism") already
>>> addresses this problem for all dwmacs above version v4.10. However,
>>> same holds true for v3.70 and above, as well as for dwxgmac. Updates
>>> the check accordingly.
>>>
>>> Fixes: 14f347334bf2 ("net: stmmac: Correctly take timestamp for PTPv2")
>>> Fixes: f2fb6b6275eb ("net: stmmac: enable timestamp snapshot for required PTP packets in dwmac v5.10a")
>>> Fixes: 3cb958027cb8 ("net: stmmac: Fix E2E delay mechanism")
>>> Signed-off-by: Rohan G Thomas <rohan.g.thomas at altera.com>
>>> ---
>>> v1 -> v2:
>>>     - Rebased patch to net tree
>>>     - Replace core_type with has_xgmac
>>>     - Nit changes in the commit message
>>>     - Link: https://lore.kernel.org/all/20251125-ext-ptp-fix-v1-1-83f9f069cb36 at altera.com/
>>
>> Given there is some uncertain WRT the exact oldest version to be used,
>> it would be great to have some 3rd party testing/feedback on this. Let's
>> wait a little more.
> 
> As I said, in the v3.74 documentation, it is stated that the SNAPTYPSEL
> functions changed between v3.50 and v3.60, so I think it would be better
> to propose a patch to test for < v3.6.
> 

I tested this on socfpga platforms like Agilex7 which are using
3.7x, but don't have any platforms with dwmac <= v3.6.

> Alternatively, if someone has the pre-v3.6 databook to check what the
> SNAPTYPSEL definition is and compare it with the v3.6+ definition, that
> would also be a good thing to do.
> 
>  From the 3.74:
> 
> SNAPTYPSEL
> 00		?
> 01		?
> 10		Sync, Delay_Req
> 11		Sync, PDelay_Req, PDelay_Resp
> 
> TSEVNTENA
> 0		All messages except Announce, Management and Signalling
> 1		Sync, Delay_Req, PDelay_Req, PDelay_Resp
> 
> No table is provided, so it's difficult to know what all the bit
> combinations do for v3.74.

In 3.73a databook, Table 6-70 has the following information and this is
similar to v5.1 and v5.3. But don't have 3.74 databook.

SNAPTYPSEL	TSMSTRENA	TSEVNTENA	PTP Messages
00		X 		0 		SYNC, Follow_Up,
						Delay_Req, Delay_Resp
00 		0 		1 		SYNC
00 		1 		1 		Delay_Req
01 		X 		0 		SYNC, Follow_Up,
						Delay_Req, Delay_Resp,
						Pdelay_Req, Pdelay_Resp,
						Pdelay_Resp_Follow_Up
01 		0 		1 		SYNC, Pdelay_Req,
						Pdelay_Resp
01 		1 		1 		Delay_Req, Pdelay_Req,
						Pdelay_Resp
10 		X 		X 		SYNC, Delay_Req
11 		X 		X 		Pdelay_Req, Pdelay_Resp

> 
>  From STM32MP151 documentation (v4.2 according to GMAC4_VERSION
> register):
> 
> SNAPTYPSEL	TSMSTRENA	TSEVNTENA
> 00		x		0		Sync, Delay_Req
> 00		0		1		Delay_Req
> 00		1		1		Sync
> 01		x		0		Sync, PDelay_Req, PDelay_Resp
> 01		0		1		Sync, Delay_Req, PDelay_Req,
> 						PDelay_Resp
> 01		1		1		Sync, PDelay_Req, PDelay_Resp
> 10		x		x		Sync, Delay_Req
> 11		x		x		Sync, PDelay_Req, PDelay_Resp
> 
> For iMX8MP (v5.1) and STM32MP23/25xx (v5.3) documentatiion:
> 
> SNAPTYPSEL	TSMSTRENA	TSEVNTENA
> 00		x		0		Sync, Follow_Up, Delay_Req,
> 						Delay_Resp
> 00		0		1		Sync
> 00		1		1		Delay_Req
> 01		x		0		Sync, Follow_Up, Delay_Req,
> 						Delay_Resp, PDelay_Req,
> 						PDelay_Resp
> 01		0		1		Sync, PDelay_Req, PDelay_Resp
> 01		1		1		Delay_Req, PDelay_Req,
> 						PDelay_Resp
> 10		x		x		Sync, Delay_Req
> 11		x		x		PDelay_Req, PDelay_Resp
> 
> Differences:
> 00 x 0 - adds Follow_Up
> 00 X 1 - TSMSTRENA bit inverted
> 01 x 0 - adds Follow_Up, Delay_Req, Delay_Resp
> 01 0 1 - removes Delay_Req
> 01 1 1 - removes Sync, adds Delay_Req
> 11 x x - removes Sync
> 
> So, it looks like there's another difference between v4.2 and v5.1.
> 
> If the STM32MP151 (v4.2) documentation is correct, then from what I see
> in the driver, if HWTSTAMP_FILTER_PTP_V1_L4_SYNC is requested, we set
> SNAPTYPSEL=00 TSMSTRENA=0 TSEVNTENA=1, which semects Delay_Req messages
> only, but on iMX8MP this selects Sync messages.
> 
> HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ is the opposite (due to the
> inversion of TSMSTRENA) for SNAPTYPSEL=00.
> 
> For HWTSTAMP_FILTER_PTP_V2_EVENT, we currently set SNAPTYPSEL=01
> TSMSTRENA=0 and TSEVNTENA=1 for cores < v4.1:
> - For STM32MP151 (v4.2) we get Sync, PDelay_Req, PDelay_Resp but
>    _not_ Delay_Req. Seems broken.
> - For iMX8MP (v5.1) and STM32MP23/25xx (v5.3), we get
>    Sync, Follow_Up, Delay_Req, Delay_Resp, PDelay_Req, PDelay_Resp
> 
> Basically, the conclusion I am coming to is that Synopsys's idea
> of "lets tell the hardware what _kind_ of PTP clock we want to be,
> whether we're master, etc" is subject to multiple revisions in
> terms of which messages each mode selects, and it would have been
> _far_ simpler and easier to understand had they just provided a
> 16-bit bitfield of message types to accept.
> 
> So, I'm wary about this change - I think there's more "mess"
> here than just that single version check in
> HWTSTAMP_FILTER_PTP_V2_EVENT, I think it's a lot more complicated.
> I'm not sure what the best solution is right now, because I don't
> have the full information, but it looks to me like the current
> approach does not result in the expected configuration for each
> of the dwmac core versions, and there are multiple issues here.
> 

Best Regards,
Rohan


From isaac.scott at ideasonboard.com  Tue Dec  9 04:31:30 2025
From: isaac.scott at ideasonboard.com (Isaac Scott)
Date: Tue,  9 Dec 2025 12:31:30 +0000
Subject: [RFC PATCH 0/6] media: rkisp1: Add YUV bypass support for rkisp1 
Message-ID: <20251209123136.273938-1-isaac.scott@ideasonboard.com>

Hi All,

The rkisp1 features the capability to use YUV bypass, which lets input
YUV streams to bypass all ISP blocks, and be presented at the output of
the ISP without being modified. This functionality is uimplemented
currently.

At the moment, it is possible to get YUV streams at the output of the
rkisp1, but only if the input is a bayer format. This series allows
YUV to be accepted as both an input and output format, when the YUV data
contains embedded H/VSYNC signals, which are interpreted as the data
start/stop signals for frame data.

This series is tested and works on the Debix Model A iMX8 MPlus with a
GC2145 camera sensor outputting UYVY8_1X16, compiled on top of
media/next.

I am marking this series as RFC because I am keen to know if any other
developers have any ideas on how to improve the series, or if there are
other considerations / edge cases that I need to address.

Thank you very much!

Best wishes,
Isaac

Isaac Scott (6):
  media: rkisp1-resizer: Add YUV source formats to resizer
  media: rkisp1-isp: Add in_bypass flag for YUV bypass
  media: rkisp1-isp: Add target_format
  media: rkisp1: Set input configuration to data mode in bypass
  media: Propagate sink -> source format in YUV passthough
  media: rkisp1: Give buffers back instead of dropping in bypass mode

 .../platform/rockchip/rkisp1/rkisp1-capture.c |  5 ++++
 .../platform/rockchip/rkisp1/rkisp1-common.h  |  1 +
 .../platform/rockchip/rkisp1/rkisp1-isp.c     | 25 +++++++++++++------
 .../platform/rockchip/rkisp1/rkisp1-resizer.c | 16 ++++++++++++
 4 files changed, 40 insertions(+), 7 deletions(-)

-- 
2.43.0



From isaac.scott at ideasonboard.com  Tue Dec  9 04:31:31 2025
From: isaac.scott at ideasonboard.com (Isaac Scott)
Date: Tue,  9 Dec 2025 12:31:31 +0000
Subject: [RFC PATCH 1/6] media: rkisp1-resizer: Add YUV source formats to resizer
In-Reply-To: <20251209123136.273938-1-isaac.scott@ideasonboard.com>
References: <20251209123136.273938-1-isaac.scott@ideasonboard.com>
Message-ID: <20251209123136.273938-2-isaac.scott@ideasonboard.com>

To be able to use YUV bypass, YUV formats need to be available on the
source pad of the rkisp1 resizer. Add them.

Signed-off-by: Isaac Scott <isaac.scott at ideasonboard.com>
---
 .../platform/rockchip/rkisp1/rkisp1-resizer.c    | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c
index 8e6b753d3081..447adec8589b 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c
@@ -33,6 +33,22 @@ static const struct rkisp1_rsz_yuv_mbus_info rkisp1_rsz_yuv_src_formats[] = {
 		.hdiv		= 2,
 		.vdiv		= 2,
 	},
+	{
+		.mbus_code	= MEDIA_BUS_FMT_YUYV8_2X8, /* YUV420 */
+		.hdiv		= 1,
+		.vdiv		= 1,
+	},
+	{
+		.mbus_code	= MEDIA_BUS_FMT_VYUY8_2X8, /* YUV420 */
+		.hdiv		= 1,
+		.vdiv		= 1,
+	},
+	{
+		.mbus_code	= MEDIA_BUS_FMT_UYVY8_2X8, /* YUV420 */
+		.hdiv		= 1,
+		.vdiv		= 1,
+	},
+
 };
 
 static const struct rkisp1_rsz_yuv_mbus_info *rkisp1_rsz_get_yuv_mbus_info(u32 mbus_code)
-- 
2.43.0



From isaac.scott at ideasonboard.com  Tue Dec  9 04:31:32 2025
From: isaac.scott at ideasonboard.com (Isaac Scott)
Date: Tue,  9 Dec 2025 12:31:32 +0000
Subject: [RFC PATCH 2/6] media: rkisp1-isp: Add in_bypass flag for YUV bypass
In-Reply-To: <20251209123136.273938-1-isaac.scott@ideasonboard.com>
References: <20251209123136.273938-1-isaac.scott@ideasonboard.com>
Message-ID: <20251209123136.273938-3-isaac.scott@ideasonboard.com>

The rkisp1 features a 'bypass' mode for RAW and YUV formats. This
disables all ISP blocks, and makes the rkisp1 display input data from
the mipi csi receiver at the output, unmodified.

To determine whether we can activate bypass, we can detect whether both
the source and sink formats are YUV. If they are, we can set a new
in_bypass flag.

Signed-off-by: Isaac Scott <isaac.scott at ideasonboard.com>
---
 drivers/media/platform/rockchip/rkisp1/rkisp1-common.h | 1 +
 drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c    | 6 +++++-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
index 5e6a4d5f6fd1..d90233e31ad3 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
@@ -532,6 +532,7 @@ struct rkisp1_device {
 	struct rkisp1_debug debug;
 	const struct rkisp1_info *info;
 	int irqs[RKISP1_NUM_IRQS];
+	bool in_bypass;
 	bool irqs_enabled;
 };
 
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
index 2311672cedb1..7f0802ae3dcc 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
@@ -212,6 +212,8 @@ static int rkisp1_config_isp(struct rkisp1_isp *isp,
 	const struct v4l2_mbus_framefmt *sink_frm;
 	const struct v4l2_rect *sink_crop;
 
+	rkisp1->in_bypass = false;
+
 	sink_frm = v4l2_subdev_state_get_format(sd_state,
 						RKISP1_ISP_PAD_SINK_VIDEO);
 	sink_crop = v4l2_subdev_state_get_crop(sd_state,
@@ -240,7 +242,9 @@ static int rkisp1_config_isp(struct rkisp1_isp *isp,
 		}
 	} else if (sink_fmt->pixel_enc == V4L2_PIXEL_ENC_YUV) {
 		acq_mult = 2;
-		if (mbus_type == V4L2_MBUS_CSI2_DPHY) {
+		if (src_fmt->pixel_enc == V4L2_PIXEL_ENC_YUV) {
+			rkisp1->in_bypass = true;
+		} else if (mbus_type == V4L2_MBUS_CSI2_DPHY) {
 			isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU601;
 		} else {
 			if (mbus_type == V4L2_MBUS_BT656)
-- 
2.43.0



From isaac.scott at ideasonboard.com  Tue Dec  9 04:31:33 2025
From: isaac.scott at ideasonboard.com (Isaac Scott)
Date: Tue,  9 Dec 2025 12:31:33 +0000
Subject: [RFC PATCH 3/6] media: rkisp1-isp: Add target_format
In-Reply-To: <20251209123136.273938-1-isaac.scott@ideasonboard.com>
References: <20251209123136.273938-1-isaac.scott@ideasonboard.com>
Message-ID: <20251209123136.273938-4-isaac.scott@ideasonboard.com>

In passthough mode, we want to make sure the output format of the ISP is
identical to the input format. Add logic to ensure the format we
configure the output of the ISP with is the sink format when we are in
bypass, and the source format if we are not.

Signed-off-by: Isaac Scott <isaac.scott at ideasonboard.com>
---
 drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
index 7f0802ae3dcc..7c844e00808a 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
@@ -175,9 +175,10 @@ static void rkisp1_gasket_disable(struct rkisp1_device *rkisp1)
 static void rkisp1_config_ism(struct rkisp1_isp *isp,
 			      const struct v4l2_subdev_state *sd_state)
 {
-	const struct v4l2_rect *src_crop =
+	const struct v4l2_rect *target_crop =
 		v4l2_subdev_state_get_crop(sd_state,
-					   RKISP1_ISP_PAD_SOURCE_VIDEO);
+			(isp->rkisp1->in_bypass ?
+				RKISP1_ISP_PAD_SINK_VIDEO : RKISP1_ISP_PAD_SOURCE_VIDEO));
 	struct rkisp1_device *rkisp1 = isp->rkisp1;
 	u32 val;
 
@@ -185,10 +186,10 @@ static void rkisp1_config_ism(struct rkisp1_isp *isp,
 	rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_MAX_DX, 0);
 	rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_MAX_DY, 0);
 	rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_DISPLACE, 0);
-	rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_H_OFFS, src_crop->left);
-	rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_V_OFFS, src_crop->top);
-	rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_H_SIZE, src_crop->width);
-	rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_V_SIZE, src_crop->height);
+	rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_H_OFFS, target_crop->left);
+	rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_V_OFFS, target_crop->top);
+	rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_H_SIZE, target_crop->width);
+	rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_V_SIZE, target_crop->height);
 
 	/* IS(Image Stabilization) is always on, working as output crop */
 	rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_CTRL, 1);
-- 
2.43.0



From isaac.scott at ideasonboard.com  Tue Dec  9 04:31:34 2025
From: isaac.scott at ideasonboard.com (Isaac Scott)
Date: Tue,  9 Dec 2025 12:31:34 +0000
Subject: [RFC PATCH 4/6] media: rkisp1: Set input configuration to data mode in bypass
In-Reply-To: <20251209123136.273938-1-isaac.scott@ideasonboard.com>
References: <20251209123136.273938-1-isaac.scott@ideasonboard.com>
Message-ID: <20251209123136.273938-5-isaac.scott@ideasonboard.com>

For YUV bypass, we should configure the ISP input to interpret incoming
H/VSYNC signals as data enable / disable. Add this.

Signed-off-by: Isaac Scott <isaac.scott at ideasonboard.com>
---
 drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
index 7c844e00808a..716bd7f3c66d 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
@@ -244,6 +244,7 @@ static int rkisp1_config_isp(struct rkisp1_isp *isp,
 	} else if (sink_fmt->pixel_enc == V4L2_PIXEL_ENC_YUV) {
 		acq_mult = 2;
 		if (src_fmt->pixel_enc == V4L2_PIXEL_ENC_YUV) {
+			isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_DATA_MODE;
 			rkisp1->in_bypass = true;
 		} else if (mbus_type == V4L2_MBUS_CSI2_DPHY) {
 			isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU601;
-- 
2.43.0



From isaac.scott at ideasonboard.com  Tue Dec  9 04:31:35 2025
From: isaac.scott at ideasonboard.com (Isaac Scott)
Date: Tue,  9 Dec 2025 12:31:35 +0000
Subject: [RFC PATCH 5/6] media: Propagate sink -> source format in YUV passthough
In-Reply-To: <20251209123136.273938-1-isaac.scott@ideasonboard.com>
References: <20251209123136.273938-1-isaac.scott@ideasonboard.com>
Message-ID: <20251209123136.273938-6-isaac.scott@ideasonboard.com>

If we are in bypass mode, we should propagate the sink format of the ISP
to the source format to ensure the pipeline is valid.

Signed-off-by: Isaac Scott <isaac.scott at ideasonboard.com>
---
 drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
index 716bd7f3c66d..c457593526c5 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
@@ -630,6 +630,11 @@ static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp,
 	 */
 	sink_info = rkisp1_mbus_info_get_by_code(sink_fmt->code);
 
+	if (sink_info->pixel_enc == V4L2_PIXEL_ENC_YUV) {
+		format->code = sink_fmt->code;
+		dev_dbg(isp->rkisp1->dev, "ISP sink pad is YUV");
+	}
+
 	src_fmt->code = format->code;
 	src_info = rkisp1_mbus_info_get_by_code(src_fmt->code);
 	if (!src_info || !(src_info->direction & RKISP1_ISP_SD_SRC)) {
-- 
2.43.0



From isaac.scott at ideasonboard.com  Tue Dec  9 04:31:36 2025
From: isaac.scott at ideasonboard.com (Isaac Scott)
Date: Tue,  9 Dec 2025 12:31:36 +0000
Subject: [RFC PATCH 6/6] media: rkisp1: Give buffers back instead of dropping in bypass mode
In-Reply-To: <20251209123136.273938-1-isaac.scott@ideasonboard.com>
References: <20251209123136.273938-1-isaac.scott@ideasonboard.com>
Message-ID: <20251209123136.273938-7-isaac.scott@ideasonboard.com>

In the data mode used for YUV passthrough, falling VSYNC events are used
to determine when a buffer is complete. This means there is no 'Frame
End' signal.

Previously, all buffers would be dropped when bypass mode was active.
Instead of dropping every frame, we should return the buffer to user
space if it is marked as complete by a falling VSYNC signal.

Signed-off-by: Isaac Scott <isaac.scott at ideasonboard.com>
---
 drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
index 6dcefd144d5a..ffce08e45200 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
@@ -832,6 +832,11 @@ irqreturn_t rkisp1_capture_isr(int irq, void *ctx)
 	for (i = 0; i < dev_count; ++i) {
 		struct rkisp1_capture *cap = &rkisp1->capture_devs[i];
 
+		if (rkisp1->in_bypass) {
+			rkisp1_handle_buffer(cap);
+			continue;
+		}
+
 		if (!(status & RKISP1_CIF_MI_FRAME(cap)))
 			continue;
 		if (!cap->is_stopping) {
-- 
2.43.0



From daniel.baluta at gmail.com  Tue Dec  9 04:36:15 2025
From: daniel.baluta at gmail.com (Daniel Baluta)
Date: Tue, 9 Dec 2025 14:36:15 +0200
Subject: [PATCH] remoteproc: imx_rproc: Use strstarts for "rsc-table" check
In-Reply-To: <20251208233302.684139-1-shenwei.wang@nxp.com>
References: <20251208233302.684139-1-shenwei.wang@nxp.com>
Message-ID: <CAEnQRZB5_WngP+U0nVdW0dnopUD5YDtZEU91StywvNTQdNSPNA@mail.gmail.com>

On Tue, Dec 9, 2025 at 1:33?AM Shenwei Wang <shenwei.wang at nxp.com> wrote:
>
> The resource name may include an address suffix, for example:
> rsc-table at 1fff8000.
>
> To handle such cases, use strstarts() instead of strcmp() when checking
> for "rsc-table".
>
> Signed-off-by: Shenwei Wang <shenwei.wang at nxp.com>

Good catch.

Reviewed-by: Daniel Baluta <daniel.baluta at nxp.com>


From heiko at sntech.de  Tue Dec  9 04:35:25 2025
From: heiko at sntech.de (Heiko =?UTF-8?B?U3TDvGJuZXI=?=)
Date: Tue, 09 Dec 2025 13:35:25 +0100
Subject: [PATCH v2 1/8] dt-bindings: pinctrl: Add rk3506 pinctrl support
In-Reply-To: <20251206050844.402958-2-ye.zhang@rock-chips.com>
References: <20251206050844.402958-1-ye.zhang@rock-chips.com>
 <20251206050844.402958-2-ye.zhang@rock-chips.com>
Message-ID: <2043731.usQuhbGJ8B@diego>

Hi Ye Zhang,

Am Samstag, 6. Dezember 2025, 06:08:37 Mitteleurop?ische Normalzeit schrieb Ye Zhang:
> Add the compatible string for the rk3506 SoC.
> 
> Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
> Reviewed-by: Heiko Stuebner <heiko at sntech.de>
> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>

This patch was already merged into the pinctrl tree in v1 and entered
the mainline kernel during the 6.19 merge-window [0]

Same for the actual rk3506 driver change. So please base future versions
of your work on top of that.

Thanks a lot
Heiko


[0] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=13064950339ffc73a0e55e9b4898df861b04848e

> ---
>  Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
> index 125af766b992..76e607281716 100644
> --- a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
> +++ b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
> @@ -44,6 +44,7 @@ properties:
>        - rockchip,rk3328-pinctrl
>        - rockchip,rk3368-pinctrl
>        - rockchip,rk3399-pinctrl
> +      - rockchip,rk3506-pinctrl
>        - rockchip,rk3528-pinctrl
>        - rockchip,rk3562-pinctrl
>        - rockchip,rk3568-pinctrl
> 






From smostafa at google.com  Tue Dec  9 04:37:10 2025
From: smostafa at google.com (Mostafa Saleh)
Date: Tue, 9 Dec 2025 12:37:10 +0000
Subject: [PATCH] iommu/io-pgtable-arm: Add misisng concatenated PGD cases
In-Reply-To: <18a39079-2285-47fb-b306-040f2bc1bbaa@arm.com>
References: <20251130194506.593700-1-smostafa@google.com>
 <18a39079-2285-47fb-b306-040f2bc1bbaa@arm.com>
Message-ID: <aTgX9qhaLyrQ5iye@google.com>

On Tue, Dec 09, 2025 at 11:34:34AM +0000, Robin Murphy wrote:
> On 2025-11-30 7:45 pm, Mostafa Saleh wrote:
> > arm_lpae_concat_mandatory() assumes that OAS >= IAS which is not
> > correct for SMMUs supporting AArch32, and have OAS = 32/36 bits,
> > as IAS would be 40 bits.
> 
> But that is only when *using* AArch32 format. The bit in chapter 3.4 of the
> SMMU architecture is talking about the maximum IAS that an SMMU
> implementation needs to be able to accommodate based on its configuration,
> but it does then attempt to clarify that the actual IPA size in use by any
> given context should depend on the VMSA format in use:
> 
> "VMSAv8-32 LPAE always supports an IPA size of 40 bits, whereas VMSAv8-64
> and VMSAv9-128 limits the maximum IPA size to the maximum PA size."
> 
> Rule R_SRKBC in the Arm ARM lays out the exact T0SZ constraints with this
> AArch32/AArch64 detail.

I see, thanks a lot for the explanation, I got confused by the this
statement:
Note: If AArch32 is implemented, IAS == MAX(40, OAS), otherwise IAS == OAS.

However, I think this is still a bug but somewere else, as at the moment
the SMMUv3 dirver will use the SMMU IAS (40-bits) as input for AArch64
stage-2 page tables, so we need either to limit the IAS as:

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index d16d35c78c06..d21153156daa 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2561,7 +2561,7 @@ static int arm_smmu_domain_finalise(struct arm_smmu_domain *smmu_domain,
        case ARM_SMMU_DOMAIN_S2:
                if (enable_dirty)
                        return -EOPNOTSUPP;
-               pgtbl_cfg.ias = smmu->ias;
+               pgtbl_cfg.ias = min(smmu->ias, smmu->oas);
                pgtbl_cfg.oas = smmu->oas;
                fmt = ARM_64_LPAE_S2;
                finalise_stage_fn = arm_smmu_domain_finalise_s2;

Or, don't populate IAS depending on AArch32 support as the driver
doesn't support it, effectively reverting:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f0c453dbcce7767cd868deb809ba68083c93954e

> 
> > In that case, concatenation is mandatory in some cases.
> > Document those and add the checks, this can be simplified; instead
> > of adding extra checks we can say that concatenation is mandatory for:
> > - 4K, start level = 0 and OAS <= 42 bits.
> > - 16K, start level = 1 and OAS <= 40 bits.
> > Which cover all the missing cases.
> 
> AArch32 uses a fixed 4K granule, so this cannot impact 16K. Note that we
> don't support AArch32 for SMMUv3 anyway, and while this does technically
> apply to SMMUv1/2, Arm's MMU-400/401/500 implementations all have OAS fixed
> at 40/40/48 bits respectively, so I'd imagine it's quite a rare case to
> encounter in practice.

Yes, I don't have access to such HW.

Thanks,
Mostafa
> 
> Thanks,
> Robin.
> 
> > Reported-by: Tomasz Nowicki <tnowicki at google.com>
> > Fixes: 4dcac8407fe1 ("iommu/io-pgtable-arm: Fix stage-2 concatenation with 16K")
> > Signed-off-by: Mostafa Saleh <smostafa at google.com>
> > ---
> >   drivers/iommu/io-pgtable-arm.c | 10 ++++++----
> >   1 file changed, 6 insertions(+), 4 deletions(-)
> > 
> > diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
> > index e6626004b323..ecf27e86b429 100644
> > --- a/drivers/iommu/io-pgtable-arm.c
> > +++ b/drivers/iommu/io-pgtable-arm.c
> > @@ -223,6 +223,8 @@ static inline int arm_lpae_max_entries(int i, struct arm_lpae_io_pgtable *data)
> >    *   b) 40 bits PA size with 16K: use level 2 instead of level 1 (16 tables for ias = oas)
> >    *   c) 42 bits PA size with 4K: use level 1 instead of level 0 (8 tables for ias = oas)
> >    *   d) 48 bits PA size with 16K: use level 1 instead of level 0 (2 tables for ias = oas)
> > + *   f) 32/36 bits PA size with 4K and 40 bits IAS: use level 1 instead of level 0
> > + *   g) 32/36 bits PA size with 16K and 40 bits IAS: use level 2 instead of level 1
> >    */
> >   static inline bool arm_lpae_concat_mandatory(struct io_pgtable_cfg *cfg,
> >   					     struct arm_lpae_io_pgtable *data)
> > @@ -234,13 +236,13 @@ static inline bool arm_lpae_concat_mandatory(struct io_pgtable_cfg *cfg,
> >   	if ((ARM_LPAE_GRANULE(data) == SZ_16K) && (data->start_level == 0))
> >   		return (oas == 48) || (ias == 48);
> > -	/* Covers 2.a and 2.c */
> > +	/* Covers 2.a, 2.c and 2.f */
> >   	if ((ARM_LPAE_GRANULE(data) == SZ_4K) && (data->start_level == 0))
> > -		return (oas == 40) || (oas == 42);
> > +		return (oas <= 42);
> > -	/* Case 2.b */
> > +	/* Case 2.b and 2.g */
> >   	return (ARM_LPAE_GRANULE(data) == SZ_16K) &&
> > -	       (data->start_level == 1) && (oas == 40);
> > +	       (data->start_level == 1) && (oas <= 40);
> >   }
> >   static dma_addr_t __arm_lpae_dma_addr(void *pages)
> 


From heiko at sntech.de  Tue Dec  9 04:41:14 2025
From: heiko at sntech.de (Heiko =?UTF-8?B?U3TDvGJuZXI=?=)
Date: Tue, 09 Dec 2025 13:41:14 +0100
Subject: [PATCH v2 6/8] dt-bindings: pinctrl: Add header for Rockchip RK3506 RMIO
In-Reply-To: <20251206050844.402958-7-ye.zhang@rock-chips.com>
References: <20251206050844.402958-1-ye.zhang@rock-chips.com>
 <20251206050844.402958-7-ye.zhang@rock-chips.com>
Message-ID: <2681672.Lt9SDvczpP@diego>

Hi Ye Zhang,

Am Samstag, 6. Dezember 2025, 06:08:42 Mitteleurop?ische Normalzeit schrieb Ye Zhang:
> Add header file with constants for RMIO pin and function IDs for the
> Rockchip RK3506 SoC.
> 
> Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
> ---
>  .../pinctrl/rockchip,rk3506-rmio.h            | 143 ++++++++++++++++++
>  1 file changed, 143 insertions(+)
>  create mode 100644 include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h
> 
> diff --git a/include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h b/include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h
> new file mode 100644
> index 000000000000..5d39690a0b28
> --- /dev/null
> +++ b/include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h
> @@ -0,0 +1,143 @@
> +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
> +/*
> + * Copyright (c) 2025 Rockchip Electronics Co., Ltd.
> + */
> +
> +#ifndef __DT_BINDINGS_PINCTRL_ROCKCHIP_RK3506_RMIO_H
> +#define __DT_BINDINGS_PINCTRL_ROCKCHIP_RK3506_RMIO_H
> +
> +/* RMIO pins definetion */
> +#define RMIO_PIN0				0
> +#define RMIO_PIN1				1
> +#define RMIO_PIN2				2
> +#define RMIO_PIN3				3
> +#define RMIO_PIN4				4

[...]

> +#define RMIO_PIN29				29
> +#define RMIO_PIN30				30
> +#define RMIO_PIN31				31

additionally to Krzysztof's comments, please also don't introduce
unhelpful mappings. Having constants mapping pin31 to 31 is not
helpful at all, as there is no value added.

We'll already know that it's pin31 by reading the 31 when used.


In contrast, the constants below add a lot of value, because you can't
infer the that the function "14" means the  CLK_32K function without
consulting the TRM, so _those_ are helpful.

> +/* RMIO function definetion */

typeo "definition"

> +#define RMIO_UART1_TX			1
> +#define RMIO_UART1_RX			2
> +#define RMIO_UART2_TX			3
> +#define RMIO_UART2_RX			4
> +#define RMIO_UART3_TX			5


Thanks a lot
Heiko




From quic_yingdeng at quicinc.com  Tue Dec  9 04:42:24 2025
From: quic_yingdeng at quicinc.com (Yingchao Deng (Consultant))
Date: Tue, 9 Dec 2025 20:42:24 +0800
Subject: [PATCH v6 2/2] coresight: cti: Add Qualcomm extended CTI support
In-Reply-To: <d55ed203-b0f4-4453-81cf-1d8dcd6494ed@oss.qualcomm.com>
References: <CAJ9a7Vg9Efi-5eecfiUF82_Qq8Jg9imN5q1-VKYZoPVUxNpjhA@mail.gmail.com>
 <20251209081649.105623-1-yingchao.deng@oss.qualcomm.com>
 <d55ed203-b0f4-4453-81cf-1d8dcd6494ed@oss.qualcomm.com>
Message-ID: <008da9e5-e561-4eb0-8d08-c50294d7ac68@quicinc.com>


On 12/9/2025 7:03 PM, Jie Gan wrote:
>
>
> On 12/9/2025 4:16 PM, Yingchao Deng wrote:
>> Hi Leo & Mike
>>
>> Based on Leo?s suggestions, I created a new patch, but there are 
>> three points that do not fully align with his recommendations:
>>
>> ???? 1. The helper function for returning the register address now 
>> returns only the offset, because returning the full address would 
>> conflict with cti_write_single_reg.
>> ???? 2. For registers such as triginstatus1...3, I defined additional 
>> macros CTITRIGINSTATUS1...3. This is because CTITRIGINSTATUS + 0x4 
>> equals CTITRIGOUTSTATUS, and to avoid conflicts with existing macros, 
>> I chose numbers starting from 0x1000 for the new definitions.
>> ???? 3. Regarding the visibility of attributes for triginstatus1...3, 
>> since coresight_cti_reg produces an anonymous variable that cannot be 
>> directly referenced, I used coresight_cti_regs_attrs[i] to obtain the 
>> attribute corresponding to triginstatus1.
>>
>> I appreciate both suggestions. After reviewing them, I lean toward 
>> Mike's approach.
>>
>> Signed-off-by: Yingchao Deng <yingchao.deng at oss.qualcomm.com>
>> ---
>> ? .../hwtracing/coresight/coresight-cti-core.c? |? 52 +++++--
>> ? .../hwtracing/coresight/coresight-cti-sysfs.c |? 72 ++++++++--
>> ? drivers/hwtracing/coresight/coresight-cti.h?? |?? 3 +-
>> ? drivers/hwtracing/coresight/qcom-cti.h??????? | 136 ++++++++++++++++++
>> ? 4 files changed, 238 insertions(+), 25 deletions(-)
>> ? create mode 100644 drivers/hwtracing/coresight/qcom-cti.h
>>
>> diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c 
>> b/drivers/hwtracing/coresight/coresight-cti-core.c
>> index f9970e40dd59..d2b0b46f2846 100644
>> --- a/drivers/hwtracing/coresight/coresight-cti-core.c
>> +++ b/drivers/hwtracing/coresight/coresight-cti-core.c
>> @@ -21,7 +21,7 @@
>>
>> ? #include "coresight-priv.h"
>> ? #include "coresight-cti.h"
>> -
>> +#include "qcom-cti.h"
>> ? /*
>> ?? * CTI devices can be associated with a PE, or be connected to 
>> CoreSight
>> ?? * hardware. We have a list of all CTIs irrespective of CPU bound or
>> @@ -70,15 +70,16 @@ void cti_write_all_hw_regs(struct cti_drvdata 
>> *drvdata)
>>
>> ????? /* write the CTI trigger registers */
>> ????? for (i = 0; i < config->nr_trig_max; i++) {
>> -??????? writel_relaxed(config->ctiinen[i], drvdata->base + CTIINEN(i));
>> +??????? writel_relaxed(config->ctiinen[i],
>> +??????????????? drvdata->base + cti_reg_addr_with_nr(drvdata, 
>> CTIINEN(0), i));
>> ????????? writel_relaxed(config->ctiouten[i],
>> -?????????????????? drvdata->base + CTIOUTEN(i));
>> +??????????????? drvdata->base + cti_reg_addr_with_nr(drvdata, 
>> CTIOUTEN(0), i));
>> ????? }
>>
>> ????? /* other regs */
>> -??? writel_relaxed(config->ctigate, drvdata->base + CTIGATE);
>> -??? writel_relaxed(config->asicctl, drvdata->base + ASICCTL);
>> -??? writel_relaxed(config->ctiappset, drvdata->base + CTIAPPSET);
>> +??? writel_relaxed(config->ctigate, drvdata->base + 
>> cti_reg_addr(drvdata, CTIGATE));
>> +??? writel_relaxed(config->asicctl, drvdata->base + 
>> cti_reg_addr(drvdata, ASICCTL));
>> +??? writel_relaxed(config->ctiappset, drvdata->base + 
>> cti_reg_addr(drvdata, CTIAPPSET));
>>
>> ????? /* re-enable CTI */
>> ????? writel_relaxed(1, drvdata->base + CTICONTROL);
>> @@ -201,7 +202,7 @@ void cti_write_intack(struct device *dev, u32 
>> ackval)
>> ????? raw_spin_lock(&drvdata->spinlock);
>> ????? /* write if enabled */
>> ????? if (cti_active(config))
>> -??????? cti_write_single_reg(drvdata, CTIINTACK, ackval);
>> +??????? cti_write_single_reg(drvdata, cti_reg_addr(drvdata, 
>> CTIINTACK), ackval);
>> ????? raw_spin_unlock(&drvdata->spinlock);
>> ? }
>>
>> @@ -214,6 +215,9 @@ void cti_write_intack(struct device *dev, u32 
>> ackval)
>> ? /* DEVID[19:16] - number of CTM channels */
>> ? #define CTI_DEVID_CTMCHANNELS(devid_val) ((int) BMVAL(devid_val, 
>> 16, 19))
>>
>> +/* DEVARCH[31:21] - ARCHITECT */
>> +#define CTI_DEVARCH_ARCHITECT(devarch_val) ((int)BMVAL(devarch_val, 
>> 21, 31))
>> +
>> ? static int cti_set_default_config(struct device *dev,
>> ??????????????????? struct cti_drvdata *drvdata)
>> ? {
>> @@ -394,9 +398,8 @@ int cti_channel_trig_op(struct device *dev, enum 
>> cti_chan_op op,
>>
>> ????? /* update the local register values */
>> ????? chan_bitmask = BIT(channel_idx);
>> -??? reg_offset = (direction == CTI_TRIG_IN ? CTIINEN(trigger_idx) :
>> -????????????? CTIOUTEN(trigger_idx));
>> -
>> +??? reg_offset = (direction == CTI_TRIG_IN ? 
>> cti_reg_addr_with_nr(drvdata, CTIINEN(0), trigger_idx):
>> +???????????????????????? cti_reg_addr_with_nr(drvdata, CTIOUTEN(0), 
>> trigger_idx));
>> ????? raw_spin_lock(&drvdata->spinlock);
>>
>> ????? /* read - modify write - the trigger / channel enable value */
>> @@ -452,7 +455,7 @@ int cti_channel_gate_op(struct device *dev, enum 
>> cti_chan_gate_op op,
>> ????? if (err == 0) {
>> ????????? config->ctigate = reg_value;
>> ????????? if (cti_active(config))
>> -??????????? cti_write_single_reg(drvdata, CTIGATE, reg_value);
>> +??????????? cti_write_single_reg(drvdata, cti_reg_addr(drvdata, 
>> CTIGATE), reg_value);
>> ????? }
>> ????? raw_spin_unlock(&drvdata->spinlock);
>> ????? return err;
>> @@ -479,19 +482,19 @@ int cti_channel_setop(struct device *dev, enum 
>> cti_chan_set_op op,
>> ????? case CTI_CHAN_SET:
>> ????????? config->ctiappset |= chan_bitmask;
>> ????????? reg_value? = config->ctiappset;
>> -??????? reg_offset = CTIAPPSET;
>> +??????? reg_offset = cti_reg_addr(drvdata, CTIAPPSET);
>> ????????? break;
>>
>> ????? case CTI_CHAN_CLR:
>> ????????? config->ctiappset &= ~chan_bitmask;
>> ????????? reg_value = chan_bitmask;
>> -??????? reg_offset = CTIAPPCLEAR;
>> +??????? reg_offset = cti_reg_addr(drvdata, CTIAPPCLEAR);
>> ????????? break;
>>
>> ????? case CTI_CHAN_PULSE:
>> ????????? config->ctiappset &= ~chan_bitmask;
>> ????????? reg_value = chan_bitmask;
>> -??????? reg_offset = CTIAPPPULSE;
>> +??????? reg_offset = cti_reg_addr(drvdata, CTIAPPPULSE);
>> ????????? break;
>>
>> ????? default:
>> @@ -895,6 +898,7 @@ static int cti_probe(struct amba_device *adev, 
>> const struct amba_id *id)
>> ????? struct coresight_desc cti_desc;
>> ????? struct coresight_platform_data *pdata = NULL;
>> ????? struct resource *res = &adev->res;
>> +??? u32 devarch;
>>
>> ????? /* driver data*/
>> ????? drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
>> @@ -981,9 +985,27 @@ static int cti_probe(struct amba_device *adev, 
>> const struct amba_id *id)
>> ????? drvdata->csdev_release = drvdata->csdev->dev.release;
>> ????? drvdata->csdev->dev.release = cti_device_release;
>>
>> +??? /* check architect value*/
>> +??? devarch = readl_relaxed(drvdata->base + CORESIGHT_DEVARCH);
>> +??? if (CTI_DEVARCH_ARCHITECT(devarch) == ARCHITECT_QCOM) {
>> +??????? drvdata->is_qcom_cti = 1;
>> +
>> +??????? /*
>> +???????? * QCOM CTI does not implement Claimtag functionality as
>> +???????? * per CoreSight specification, but its CLAIMSET register
>> +???????? * is incorrectly initialized to 0xF. This can mislead
>> +???????? * tools or drivers into thinking the component is claimed.
>> +???????? *
>> +???????? * Reset CLAIMSET to 0 to reflect that no claims are active.
>> +???????? */
>> +??????? drvdata->csdev->claim_tag_info = CS_CLAIM_TAG_NOT_IMPL;
>> +??????? //writel_relaxed(0, drvdata->base + CORESIGHT_CLAIMSET);
>> +??? }
>> +
>> ????? /* all done - dec pm refcount */
>> ????? pm_runtime_put(&adev->dev);
>> -??? dev_info(&drvdata->csdev->dev, "CTI initialized\n");
>> +??? dev_info(&drvdata->csdev->dev, "%s CTI initialized\n",
>> +??????????????????? drvdata->is_qcom_cti ? "QCOM" : "");
>> ????? return 0;
>>
>> ? pm_release:
>> diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c 
>> b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
>> index a9df77215141..5d23a138b4a7 100644
>> --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c
>> +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
>> @@ -13,7 +13,7 @@
>> ? #include <linux/sysfs.h>
>>
>> ? #include "coresight-cti.h"
>> -
>> +#include "qcom-cti.h"
>> ? /*
>> ?? * Declare the number of static declared attribute groups
>> ?? * Value includes groups + NULL value at end of table.
>> @@ -183,7 +183,7 @@ static ssize_t coresight_cti_reg_show(struct 
>> device *dev,
>> ????? pm_runtime_get_sync(dev->parent);
>> ????? raw_spin_lock(&drvdata->spinlock);
>> ????? if (drvdata->config.hw_powered)
>> -??????? val = readl_relaxed(drvdata->base + cti_attr->off);
>> +??????? val = readl_relaxed(drvdata->base + cti_reg_addr(drvdata, 
>> cti_attr->off));
>> ????? raw_spin_unlock(&drvdata->spinlock);
>> ????? pm_runtime_put_sync(dev->parent);
>> ????? return sysfs_emit(buf, "0x%x\n", val);
>> @@ -204,7 +204,7 @@ static __maybe_unused ssize_t 
>> coresight_cti_reg_store(struct device *dev,
>> ????? pm_runtime_get_sync(dev->parent);
>> ????? raw_spin_lock(&drvdata->spinlock);
>> ????? if (drvdata->config.hw_powered)
>> -??????? cti_write_single_reg(drvdata, cti_attr->off, val);
>> +??????? cti_write_single_reg(drvdata,? cti_reg_addr(drvdata, 
>> cti_attr->off), val);
>> ????? raw_spin_unlock(&drvdata->spinlock);
>> ????? pm_runtime_put_sync(dev->parent);
>> ????? return size;
>> @@ -267,7 +267,7 @@ static ssize_t cti_reg32_show(struct device *dev, 
>> char *buf,
>> ????? raw_spin_lock(&drvdata->spinlock);
>> ????? if ((reg_offset >= 0) && cti_active(config)) {
>> ????????? CS_UNLOCK(drvdata->base);
>> -??????? val = readl_relaxed(drvdata->base + reg_offset);
>> +??????? val = readl_relaxed(drvdata->base + cti_reg_addr(drvdata, 
>> reg_offset));
>> ????????? if (pcached_val)
>> ????????????? *pcached_val = val;
>> ????????? CS_LOCK(drvdata->base);
>> @@ -300,7 +300,7 @@ static ssize_t cti_reg32_store(struct device 
>> *dev, const char *buf,
>>
>> ????? /* write through if offset and enabled */
>> ????? if ((reg_offset >= 0) && cti_active(config))
>> -??????? cti_write_single_reg(drvdata, reg_offset, val);
>> +??????? cti_write_single_reg(drvdata,? cti_reg_addr(drvdata, 
>> reg_offset), val);
>> ????? raw_spin_unlock(&drvdata->spinlock);
>> ????? return size;
>> ? }
>> @@ -389,7 +389,7 @@ static ssize_t inen_store(struct device *dev,
>>
>> ????? /* write through if enabled */
>> ????? if (cti_active(config))
>> -??????? cti_write_single_reg(drvdata, CTIINEN(index), val);
>> +??????? cti_write_single_reg(drvdata, cti_reg_addr_with_nr(drvdata, 
>> CTIINEN(0), index), val);
>> ????? raw_spin_unlock(&drvdata->spinlock);
>> ????? return size;
>> ? }
>> @@ -428,7 +428,7 @@ static ssize_t outen_store(struct device *dev,
>>
>> ????? /* write through if enabled */
>> ????? if (cti_active(config))
>> -??????? cti_write_single_reg(drvdata, CTIOUTEN(index), val);
>> +??????? cti_write_single_reg(drvdata, cti_reg_addr_with_nr(drvdata, 
>> CTIOUTEN(0), index), val);
>> ????? raw_spin_unlock(&drvdata->spinlock);
>> ????? return size;
>> ? }
>> @@ -470,7 +470,7 @@ static ssize_t appclear_store(struct device *dev,
>>
>> ????? /* write through if enabled */
>> ????? if (cti_active(config))
>> -??????? cti_write_single_reg(drvdata, CTIAPPCLEAR, val);
>> +??????? cti_write_single_reg(drvdata,? cti_reg_addr(drvdata, 
>> CTIAPPCLEAR), val);
>> ????? raw_spin_unlock(&drvdata->spinlock);
>> ????? return size;
>> ? }
>> @@ -491,7 +491,7 @@ static ssize_t apppulse_store(struct device *dev,
>>
>> ????? /* write through if enabled */
>> ????? if (cti_active(config))
>> -??????? cti_write_single_reg(drvdata, CTIAPPPULSE, val);
>> +??????? cti_write_single_reg(drvdata,? cti_reg_addr(drvdata, 
>> CTIAPPPULSE), val);
>> ????? raw_spin_unlock(&drvdata->spinlock);
>> ????? return size;
>> ? }
>> @@ -513,18 +513,36 @@ static struct attribute 
>> *coresight_cti_regs_attrs[] = {
>> ????? &dev_attr_appclear.attr,
>> ????? &dev_attr_apppulse.attr,
>> ????? coresight_cti_reg(triginstatus, CTITRIGINSTATUS),
>> +??? coresight_cti_reg(triginstatus1, CTITRIGINSTATUS1),
>> +??? coresight_cti_reg(triginstatus2, CTITRIGINSTATUS2),
>> +??? coresight_cti_reg(triginstatus3, CTITRIGINSTATUS3),
>> ????? coresight_cti_reg(trigoutstatus, CTITRIGOUTSTATUS),
>> +??? coresight_cti_reg(trigoutstatus1, CTITRIGOUTSTATUS1),
>> +??? coresight_cti_reg(trigoutstatus2, CTITRIGOUTSTATUS2),
>> +??? coresight_cti_reg(trigoutstatus3, CTITRIGOUTSTATUS3),
>> ????? coresight_cti_reg(chinstatus, CTICHINSTATUS),
>> ????? coresight_cti_reg(choutstatus, CTICHOUTSTATUS),
>> ? #ifdef CONFIG_CORESIGHT_CTI_INTEGRATION_REGS
>> ????? coresight_cti_reg_rw(itctrl, CORESIGHT_ITCTRL),
>> ????? coresight_cti_reg(ittrigin, ITTRIGIN),
>> +??? coresight_cti_reg(ittrigin1, ITTRIGIN1),
>> +??? coresight_cti_reg(ittrigin2, ITTRIGIN2),
>> +??? coresight_cti_reg(ittrigin3, ITTRIGIN3),
>> ????? coresight_cti_reg(itchin, ITCHIN),
>> ????? coresight_cti_reg_rw(ittrigout, ITTRIGOUT),
>> +??? coresight_cti_reg_rw(ittrigout1, ITTRIGOUT1),
>> +??? coresight_cti_reg_rw(ittrigout2, ITTRIGOUT2),
>> +??? coresight_cti_reg_rw(ittrigout3, ITTRIGOUT3),
>> ????? coresight_cti_reg_rw(itchout, ITCHOUT),
>> ????? coresight_cti_reg(itchoutack, ITCHOUTACK),
>> ????? coresight_cti_reg(ittrigoutack, ITTRIGOUTACK),
>> +??? coresight_cti_reg(ittrigoutack1, ITTRIGOUTACK1),
>> +??? coresight_cti_reg(ittrigoutack2, ITTRIGOUTACK2),
>> +??? coresight_cti_reg(ittrigoutack3, ITTRIGOUTACK3),
>> ????? coresight_cti_reg_wo(ittriginack, ITTRIGINACK),
>> +??? coresight_cti_reg_wo(ittriginack1, ITTRIGINACK1),
>> +??? coresight_cti_reg_wo(ittriginack2, ITTRIGINACK2),
>> +??? coresight_cti_reg_wo(ittriginack3, ITTRIGINACK3),
>> ????? coresight_cti_reg_wo(itchinack, ITCHINACK),
>> ? #endif
>> ????? NULL,
>> @@ -1153,6 +1171,41 @@ int cti_create_cons_sysfs(struct device *dev, 
>> struct cti_drvdata *drvdata)
>> ????? return err;
>> ? }
>>
>> +? static umode_t coresight_cti_regs_is_visible(struct kobject *kobj,
>> +????????????????? struct attribute *attr, int n)
>> +? {
>
> I was thinking can we create a separate attribute_group for added Qcom 
> regs? Let devarch to determine whether to create these sysfs nodes?
>
> Thanks,
> Jie
>
As there seems to be no interface to create an attribute_group within 
another attribute_group, the group would have to reside under the 
.../devices/cti-xxx/ directory. I'm uncertain whether this arrangement 
would be considered acceptable.

Thanks
Yingchao
>> +??? struct device *dev = container_of(kobj, struct device, kobj);
>> +??? struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +
>> +??? /* Mute QCOM CTI registers for standard CTI module */
>> +??? if (!drvdata->is_qcom_cti) {
>> +??????? if (attr == coresight_cti_regs_attrs[10]
>> +???????? || attr == coresight_cti_regs_attrs[11]
>> +???????? || attr == coresight_cti_regs_attrs[12]
>> +???????? || attr == coresight_cti_regs_attrs[14]
>> +???????? || attr == coresight_cti_regs_attrs[15]
>> +???????? || attr == coresight_cti_regs_attrs[16]
>> +#ifdef CONFIG_CORESIGHT_CTI_INTEGRATION_REGS
>> +???????? || attr == coresight_cti_regs_attrs[21]
>> +???????? || attr == coresight_cti_regs_attrs[22]
>> +???????? || attr == coresight_cti_regs_attrs[23]
>> +???????? || attr == coresight_cti_regs_attrs[26]
>> +???????? || attr == coresight_cti_regs_attrs[27]
>> +???????? || attr == coresight_cti_regs_attrs[28]
>> +???????? || attr == coresight_cti_regs_attrs[32]
>> +???????? || attr == coresight_cti_regs_attrs[33]
>> +???????? || attr == coresight_cti_regs_attrs[34]
>> +???????? || attr == coresight_cti_regs_attrs[36]
>> +???????? || attr == coresight_cti_regs_attrs[37]
>> +???????? || attr == coresight_cti_regs_attrs[38]
>> +#endif
>> +???????? )
>> +????????????????? return 0;
>> +????????? }
>> +
>> +????????? return attr->mode;
>> +? }
>> +
>> ? /* attribute and group sysfs tables. */
>> ? static const struct attribute_group coresight_cti_group = {
>> ????? .attrs = coresight_cti_attrs,
>> @@ -1166,6 +1219,7 @@ static const struct attribute_group 
>> coresight_cti_mgmt_group = {
>> ? static const struct attribute_group coresight_cti_regs_group = {
>> ????? .attrs = coresight_cti_regs_attrs,
>> ????? .name = "regs",
>> +??? .is_visible = coresight_cti_regs_is_visible,
>> ? };
>>
>> ? static const struct attribute_group coresight_cti_channels_group = {
>> diff --git a/drivers/hwtracing/coresight/coresight-cti.h 
>> b/drivers/hwtracing/coresight/coresight-cti.h
>> index e7b88b07cffe..413d5ef483e8 100644
>> --- a/drivers/hwtracing/coresight/coresight-cti.h
>> +++ b/drivers/hwtracing/coresight/coresight-cti.h
>> @@ -57,7 +57,7 @@ struct fwnode_handle;
>> ?? * Max of in and out defined in the DEVID register.
>> ?? * - pick up actual number used from .dts parameters if present.
>> ?? */
>> -#define CTIINOUTEN_MAX??????? 32
>> +#define CTIINOUTEN_MAX??????? 128
>>
>> ? /**
>> ?? * Group of related trigger signals
>> @@ -181,6 +181,7 @@ struct cti_drvdata {
>> ????? struct cti_config config;
>> ????? struct list_head node;
>> ????? void (*csdev_release)(struct device *dev);
>> +??? bool is_qcom_cti;
>> ? };
>>
>> ? /*
>> diff --git a/drivers/hwtracing/coresight/qcom-cti.h 
>> b/drivers/hwtracing/coresight/qcom-cti.h
>> new file mode 100644
>> index 000000000000..aa41f9425b36
>> --- /dev/null
>> +++ b/drivers/hwtracing/coresight/qcom-cti.h
>> @@ -0,0 +1,136 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/*
>> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
>> + */
>> +#include "coresight-cti.h"
>> +
>> +#define ARCHITECT_QCOM 0x477
>> +
>> +#define CTITRIGINSTATUS1 0x1000
>> +#define CTITRIGINSTATUS2 0x1001
>> +#define CTITRIGINSTATUS3 0x1002
>> +
>> +#define CTITRIGOUTSTATUS1 0x1003
>> +#define CTITRIGOUTSTATUS2 0x1004
>> +#define CTITRIGOUTSTATUS3 0x1005
>> +
>> +#define ITTRIGIN1 0x1006
>> +#define ITTRIGIN2 0x1007
>> +#define ITTRIGIN3 0x1008
>> +
>> +#define ITTRIGOUT1 0x1009
>> +#define ITTRIGOUT2 0x100A
>> +#define ITTRIGOUT3 0x100B
>> +
>> +#define ITTRIGINACK1 0x100C
>> +#define ITTRIGINACK2 0x100D
>> +#define ITTRIGINACK3 0x100E
>> +
>> +#define ITTRIGOUTACK1 0x100F
>> +#define ITTRIGOUTACK2 0x1010
>> +#define ITTRIGOUTACK3 0x1011
>> +/* CTI programming registers */
>> +#define??? QCOM_CTIINTACK??????? 0x020
>> +#define??? QCOM_CTIAPPSET??????? 0x004
>> +#define??? QCOM_CTIAPPCLEAR??? 0x008
>> +#define??? QCOM_CTIAPPPULSE??? 0x00C
>> +#define??? QCOM_CTIINEN??????? 0x400
>> +#define??? QCOM_CTIOUTEN??????? 0x800
>> +#define??? QCOM_CTITRIGINSTATUS??? 0x040
>> +#define??? QCOM_CTITRIGINSTATUS1??? 0x044
>> +#define??? QCOM_CTITRIGINSTATUS2??? 0x048
>> +#define??? QCOM_CTITRIGINSTATUS3??? 0x04C
>> +#define??? QCOM_CTITRIGOUTSTATUS??? 0x060
>> +#define??? QCOM_CTITRIGOUTSTATUS1??? 0x064
>> +#define??? QCOM_CTITRIGOUTSTATUS2??? 0x068
>> +#define??? QCOM_CTITRIGOUTSTATUS3??? 0x06C
>> +#define??? QCOM_CTICHINSTATUS??? 0x080
>> +#define??? QCOM_CTICHOUTSTATUS??? 0x084
>> +#define??? QCOM_CTIGATE??????? 0x088
>> +#define??? QCOM_ASICCTL??????? 0x08c
>> +/* Integration test registers */
>> +#define??? QCOM_ITCHINACK??????? 0xE70
>> +#define??? QCOM_ITTRIGINACK??? 0xE80
>> +#define??? QCOM_ITTRIGINACK1??? 0xE84
>> +#define??? QCOM_ITTRIGINACK2??? 0xE88
>> +#define??? QCOM_ITTRIGINACK3??? 0xE8C
>> +#define??? QCOM_ITCHOUT??????? 0xE74
>> +#define??? QCOM_ITTRIGOUT??????? 0xEA0
>> +#define??? QCOM_ITTRIGOUT1??????? 0xEA4
>> +#define??? QCOM_ITTRIGOUT2??????? 0xEA8
>> +#define??? QCOM_ITTRIGOUT3??????? 0xEAC
>> +#define??? QCOM_ITCHOUTACK??????? 0xE78
>> +#define??? QCOM_ITTRIGOUTACK??? 0xEC0
>> +#define??? QCOM_ITTRIGOUTACK1??? 0xEC4
>> +#define??? QCOM_ITTRIGOUTACK2??? 0xEC8
>> +#define??? QCOM_ITTRIGOUTACK3??? 0xECC
>> +#define??? QCOM_ITCHIN??????? 0xE7C
>> +#define??? QCOM_ITTRIGIN??????? 0xEE0
>> +#define??? QCOM_ITTRIGIN1??????? 0xEE4
>> +#define??? QCOM_ITTRIGIN2??????? 0xEE8
>> +#define??? QCOM_ITTRIGIN3??????? 0xEEC
>> +
>> +static noinline u32 cti_qcom_reg_off(u32 offset)
>> +{
>> +??? switch (offset) {
>> +??????? case CTIINTACK:??????? return QCOM_CTIINTACK;
>> +??????? case CTIAPPSET:??????? return QCOM_CTIAPPSET;
>> +??????? case CTIAPPCLEAR:??? return QCOM_CTIAPPCLEAR;
>> +??????? case CTIAPPPULSE:??? return QCOM_CTIAPPPULSE;
>> +??????? case CTIINEN(0):??? return QCOM_CTIINEN;
>> +??????? case CTIOUTEN(0):??? return QCOM_CTIOUTEN;
>> +??????? case CTITRIGINSTATUS:??? return QCOM_CTITRIGINSTATUS;
>> +??????? case CTITRIGINSTATUS1:??? return QCOM_CTITRIGINSTATUS1;
>> +??????? case CTITRIGINSTATUS2:??? return QCOM_CTITRIGINSTATUS2;
>> +??????? case CTITRIGINSTATUS3:??? return QCOM_CTITRIGINSTATUS3;
>> +??????? case CTITRIGOUTSTATUS:??? return QCOM_CTITRIGOUTSTATUS;
>> +??????? case CTITRIGOUTSTATUS1:??? return QCOM_CTITRIGOUTSTATUS1;
>> +??????? case CTITRIGOUTSTATUS2:??? return QCOM_CTITRIGOUTSTATUS2;
>> +??????? case CTITRIGOUTSTATUS3:??? return QCOM_CTITRIGOUTSTATUS3;
>> +??????? case CTICHINSTATUS:??????? return QCOM_CTICHINSTATUS;
>> +??????? case CTICHOUTSTATUS:??? return QCOM_CTICHOUTSTATUS;
>> +??????? case CTIGATE:??????? return QCOM_CTIGATE;
>> +??????? case ASICCTL:??????? return QCOM_ASICCTL;
>> +??????? case ITCHINACK:??????? return QCOM_ITCHINACK;
>> +??????? case ITTRIGINACK:??? return QCOM_ITTRIGINACK;
>> +??????? case ITTRIGINACK1:??? return QCOM_ITTRIGINACK1;
>> +??????? case ITTRIGINACK2:??? return QCOM_ITTRIGINACK2;
>> +??????? case ITTRIGINACK3:??? return QCOM_ITTRIGINACK3;
>> +??????? case ITCHOUT:??????? return QCOM_ITCHOUT;
>> +??????? case ITTRIGOUT:??????? return QCOM_ITTRIGOUT;
>> +??????? case ITTRIGOUT1:??? return QCOM_ITTRIGOUT1;
>> +??????? case ITTRIGOUT2:??? return QCOM_ITTRIGOUT2;
>> +??????? case ITTRIGOUT3:??? return QCOM_ITTRIGOUT3;
>> +??????? case ITCHOUTACK:??? return QCOM_ITCHOUTACK;
>> +??????? case ITTRIGOUTACK:??? return QCOM_ITTRIGOUTACK;
>> +??????? case ITTRIGOUTACK1:??? return QCOM_ITTRIGOUTACK1;
>> +??????? case ITTRIGOUTACK2:??? return QCOM_ITTRIGOUTACK2;
>> +??????? case ITTRIGOUTACK3:??? return QCOM_ITTRIGOUTACK3;
>> +??????? case ITCHIN:?????????????? return QCOM_ITCHIN;
>> +??????? case ITTRIGIN:??????????? return QCOM_ITTRIGIN;
>> +??????? case ITTRIGIN1:??????? return QCOM_ITTRIGIN1;
>> +??????? case ITTRIGIN2:??????? return QCOM_ITTRIGIN2;
>> +??????? case ITTRIGIN3:??????? return QCOM_ITTRIGIN3;
>> +??????? default:
>> +??????????????????? WARN(1, "Unknown offset=%u\n", offset);
>> +??????????????????? return 0;
>> +??? }
>> +
>> +??? return 0;
>> +}
>> +
>> +static u32 cti_reg_addr_with_nr(struct cti_drvdata *drvdata,
>> +????????????????????????????????????????? u32 reg, u32 nr)
>> +{
>> +??? /* convert to qcom specific offset */
>> +??? if (unlikely(drvdata->is_qcom_cti))
>> +??????? reg = cti_qcom_reg_off(reg);
>> +
>> +??? return reg + sizeof(u32) * nr;
>> +}
>> +
>> +static u32 cti_reg_addr(struct cti_drvdata *drvdata, u32 reg)
>> +{
>> +??????? return cti_reg_addr_with_nr(drvdata, reg, 0);
>> +}
>> +
>>
>>
>


From james.clark at linaro.org  Tue Dec  9 04:48:29 2025
From: james.clark at linaro.org (James Clark)
Date: Tue, 9 Dec 2025 12:48:29 +0000
Subject: [PATCH v2 01/12] perf parse-events: Refactor get_config_terms()
 to remove macros
In-Reply-To: <20251208-james-perf-config-bits-v2-1-4ac0281993b0@linaro.org>
References: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
 <20251208-james-perf-config-bits-v2-1-4ac0281993b0@linaro.org>
Message-ID: <6ba6bde3-f56b-4354-b336-4739cb1edb71@linaro.org>



On 08/12/2025 2:22 pm, James Clark wrote:
> The ADD_CONFIG_TERM() macros build the __type argument out of a partial
> EVSEL__CONFIG_TERM_x enum name. This means that they can't be called
> from a function where __type is a variable and it's also impossible to
> grep the codebase to find usages of these enums as they're never typed
> in full.
> 
> Fix this by removing the macros and replacing them with an
> add_config_term() function. It seems the main reason these existed in
> the first place was to avoid type punning and to write to a specific
> field in the union, but the same thing can be achieved with a single
> write to a u64 'val' field.
> 
> Signed-off-by: James Clark <james.clark at linaro.org>
> ---
>   tools/perf/util/evsel_config.h |   1 +
>   tools/perf/util/parse-events.c | 146 ++++++++++++++++++++++++-----------------
>   2 files changed, 86 insertions(+), 61 deletions(-)
> 
> diff --git a/tools/perf/util/evsel_config.h b/tools/perf/util/evsel_config.h
> index bcd3a978f0c4..685fd8d5c4a8 100644
> --- a/tools/perf/util/evsel_config.h
> +++ b/tools/perf/util/evsel_config.h
> @@ -50,6 +50,7 @@ struct evsel_config_term {
>   		u64	      cfg_chg;
>   		char	      *str;
>   		int	      cpu;
> +		u64	      val;
>   	} val;
>   	bool weak;
>   };
> diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
> index 17c1c36a7bf9..d5b009b4ebab 100644
> --- a/tools/perf/util/parse-events.c
> +++ b/tools/perf/util/parse-events.c
> @@ -1116,105 +1116,107 @@ static int config_attr(struct perf_event_attr *attr,
>   	return 0;
>   }
>   
> -static int get_config_terms(const struct parse_events_terms *head_config,
> -			    struct list_head *head_terms)
> +static struct evsel_config_term *add_config_term(enum evsel_term_type type,
> +						 struct list_head *head_terms,
> +						 bool weak)
>   {
> -#define ADD_CONFIG_TERM(__type, __weak)				\
> -	struct evsel_config_term *__t;			\
> -								\
> -	__t = zalloc(sizeof(*__t));				\
> -	if (!__t)						\
> -		return -ENOMEM;					\
> -								\
> -	INIT_LIST_HEAD(&__t->list);				\
> -	__t->type       = EVSEL__CONFIG_TERM_ ## __type;	\
> -	__t->weak	= __weak;				\
> -	list_add_tail(&__t->list, head_terms)
> -
> -#define ADD_CONFIG_TERM_VAL(__type, __name, __val, __weak)	\
> -do {								\
> -	ADD_CONFIG_TERM(__type, __weak);			\
> -	__t->val.__name = __val;				\
> -} while (0)
> +	struct evsel_config_term *t;
>   
> -#define ADD_CONFIG_TERM_STR(__type, __val, __weak)		\
> -do {								\
> -	ADD_CONFIG_TERM(__type, __weak);			\
> -	__t->val.str = strdup(__val);				\
> -	if (!__t->val.str) {					\
> -		zfree(&__t);					\
> -		return -ENOMEM;					\
> -	}							\
> -	__t->free_str = true;					\
> -} while (0)
> +	t = zalloc(sizeof(*t));
> +	if (!t)
> +		return NULL;
> +
> +	INIT_LIST_HEAD(&t->list);
> +	t->type = type;
> +	t->weak	= weak;
> +	list_add_tail(&t->list, head_terms);
>   
> +	return t;
> +}
> +
> +static int get_config_terms(const struct parse_events_terms *head_config,
> +			    struct list_head *head_terms)
> +{
>   	struct parse_events_term *term;
>   
>   	list_for_each_entry(term, &head_config->terms, list) {
> +		struct evsel_config_term *new_term;
> +		enum evsel_term_type new_type;
> +		char *str = NULL;
> +		u64 val;
> +
>   		switch (term->type_term) {
>   		case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
> -			ADD_CONFIG_TERM_VAL(PERIOD, period, term->val.num, term->weak);
> +			new_type = EVSEL__CONFIG_TERM_PERIOD;
> +			val = term->val.num;
>   			break;
>   		case PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ:
> -			ADD_CONFIG_TERM_VAL(FREQ, freq, term->val.num, term->weak);
> +			new_type = EVSEL__CONFIG_TERM_FREQ;
> +			val = term->val.num;
>   			break;
>   		case PARSE_EVENTS__TERM_TYPE_TIME:
> -			ADD_CONFIG_TERM_VAL(TIME, time, term->val.num, term->weak);
> +			new_type = EVSEL__CONFIG_TERM_TIME;
> +			val = term->val.num;
>   			break;
>   		case PARSE_EVENTS__TERM_TYPE_CALLGRAPH:
> -			ADD_CONFIG_TERM_STR(CALLGRAPH, term->val.str, term->weak);
> +			new_type = EVSEL__CONFIG_TERM_CALLGRAPH;
> +			str = term->val.str;
>   			break;
>   		case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
> -			ADD_CONFIG_TERM_STR(BRANCH, term->val.str, term->weak);
> +			new_type = EVSEL__CONFIG_TERM_BRANCH;
> +			str = term->val.str;
>   			break;
>   		case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
> -			ADD_CONFIG_TERM_VAL(STACK_USER, stack_user,
> -					    term->val.num, term->weak);
> +			new_type = EVSEL__CONFIG_TERM_STACK_USER;
> +			val = term->val.num;
>   			break;
>   		case PARSE_EVENTS__TERM_TYPE_INHERIT:
> -			ADD_CONFIG_TERM_VAL(INHERIT, inherit,
> -					    term->val.num ? 1 : 0, term->weak);
> +			new_type = EVSEL__CONFIG_TERM_INHERIT;
> +			val = term->val.num ? 1 : 0;
>   			break;
>   		case PARSE_EVENTS__TERM_TYPE_NOINHERIT:
> -			ADD_CONFIG_TERM_VAL(INHERIT, inherit,
> -					    term->val.num ? 0 : 1, term->weak);
> +			new_type = EVSEL__CONFIG_TERM_INHERIT;
> +			val = term->val.num ? 0 : 1;
>   			break;
>   		case PARSE_EVENTS__TERM_TYPE_MAX_STACK:
> -			ADD_CONFIG_TERM_VAL(MAX_STACK, max_stack,
> -					    term->val.num, term->weak);
> +			new_type = EVSEL__CONFIG_TERM_MAX_STACK;
> +			val = term->val.num;
>   			break;
>   		case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS:
> -			ADD_CONFIG_TERM_VAL(MAX_EVENTS, max_events,
> -					    term->val.num, term->weak);
> +			new_type = EVSEL__CONFIG_TERM_MAX_EVENTS;
> +			val = term->val.num;
>   			break;
>   		case PARSE_EVENTS__TERM_TYPE_OVERWRITE:
> -			ADD_CONFIG_TERM_VAL(OVERWRITE, overwrite,
> -					    term->val.num ? 1 : 0, term->weak);
> +			new_type = EVSEL__CONFIG_TERM_OVERWRITE;
> +			val = term->val.num ? 1 : 0;
>   			break;
>   		case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE:
> -			ADD_CONFIG_TERM_VAL(OVERWRITE, overwrite,
> -					    term->val.num ? 0 : 1, term->weak);
> +			new_type = EVSEL__CONFIG_TERM_OVERWRITE;
> +			val = term->val.num ? 0 : 1;
>   			break;
>   		case PARSE_EVENTS__TERM_TYPE_DRV_CFG:
> -			ADD_CONFIG_TERM_STR(DRV_CFG, term->val.str, term->weak);
> +			new_type = EVSEL__CONFIG_TERM_DRV_CFG;
> +			str = term->val.str;
>   			break;
>   		case PARSE_EVENTS__TERM_TYPE_PERCORE:
> -			ADD_CONFIG_TERM_VAL(PERCORE, percore,
> -					    term->val.num ? true : false, term->weak);
> +			new_type = EVSEL__CONFIG_TERM_PERCORE;
> +			val = term->val.num ? true : false;
>   			break;
>   		case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT:
> -			ADD_CONFIG_TERM_VAL(AUX_OUTPUT, aux_output,
> -					    term->val.num ? 1 : 0, term->weak);
> +			new_type = EVSEL__CONFIG_TERM_AUX_OUTPUT;
> +			val = term->val.num ? 1 : 0;
>   			break;
>   		case PARSE_EVENTS__TERM_TYPE_AUX_ACTION:
> -			ADD_CONFIG_TERM_STR(AUX_ACTION, term->val.str, term->weak);
> +			new_type = EVSEL__CONFIG_TERM_AUX_ACTION;
> +			str = term->val.str;
>   			break;
>   		case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE:
> -			ADD_CONFIG_TERM_VAL(AUX_SAMPLE_SIZE, aux_sample_size,
> -					    term->val.num, term->weak);
> +			new_type = EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE;
> +			val = term->val.num;
>   			break;
>   		case PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV:
> -			ADD_CONFIG_TERM_STR(RATIO_TO_PREV, term->val.str, term->weak);
> +			new_type = EVSEL__CONFIG_TERM_RATIO_TO_PREV;
> +			str = term->val.str;
>   			break;
>   		case PARSE_EVENTS__TERM_TYPE_USER:
>   		case PARSE_EVENTS__TERM_TYPE_CONFIG:
> @@ -1229,7 +1231,23 @@ do {								\
>   		case PARSE_EVENTS__TERM_TYPE_RAW:
>   		case PARSE_EVENTS__TERM_TYPE_CPU:
>   		default:
> -			break;
> +			/* Don't add a new term for these ones */
> +			continue;
> +		}
> +
> +		new_term = add_config_term(new_type, head_terms, term->weak);
> +		if (!new_term)
> +			return -ENOMEM;
> +
> +		if (str) {
> +			new_term->val.str = strdup(str);
> +			if (!new_term->val.str) {
> +				zfree(&new_term);
> +				return -ENOMEM;
> +			}
> +			new_term->free_str = true;
> +		} else {

This will incorrectly hit the else if term->val.str is NULL. Not sure if 
that can happen but will fix anyway.

> +			new_term->val.val = val;

There's an uninitialized variable warning for val here on release 
builds. Will fix too

>   		}
>   	}
>   	return 0;
> @@ -1290,10 +1308,16 @@ static int get_config_chgs(struct perf_pmu *pmu, struct parse_events_terms *head
>   		}
>   	}
>   
> -	if (bits)
> -		ADD_CONFIG_TERM_VAL(CFG_CHG, cfg_chg, bits, false);
> +	if (bits) {
> +		struct evsel_config_term *new_term;
> +
> +		new_term = add_config_term(EVSEL__CONFIG_TERM_CFG_CHG,
> +					   head_terms, false);
> +		if (!new_term)
> +			return -ENOMEM;
> +		new_term->val.cfg_chg = bits;
> +	}
>   
> -#undef ADD_CONFIG_TERM
>   	return 0;
>   }
>   
> 



From quic_yingdeng at quicinc.com  Tue Dec  9 04:51:38 2025
From: quic_yingdeng at quicinc.com (Yingchao Deng (Consultant))
Date: Tue, 9 Dec 2025 20:51:38 +0800
Subject: [PATCH v6 2/2] coresight: cti: Add Qualcomm extended CTI support
In-Reply-To: <20251209121916.GT724103@e132581.arm.com>
References: <CAJ9a7Vg9Efi-5eecfiUF82_Qq8Jg9imN5q1-VKYZoPVUxNpjhA@mail.gmail.com>
 <20251209081649.105623-1-yingchao.deng@oss.qualcomm.com>
 <20251209121916.GT724103@e132581.arm.com>
Message-ID: <1fbe140c-b960-4f13-83e2-b0a0733a67bc@quicinc.com>

Hi Leo,

On 12/9/2025 8:19 PM, Leo Yan wrote:
> Hi Yingchao,
>
> On Tue, Dec 09, 2025 at 04:16:28PM +0800, Yingchao Deng wrote:
>> Hi Leo & Mike
>>
>> Based on Leo?s suggestions, I created a new patch, but there are three points that do not fully align with his recommendations:
>>
>>      1. The helper function for returning the register address now returns only the offset, because returning the full address would conflict with cti_write_single_reg.
> No need to change each callsite for cti_write_single_reg().  You could
> update cti_write_single_reg() instead:
>
>    void cti_write_single_reg(struct cti_drvdata *drvdata,
>                              int offset, u32 value)
>    {
>            CS_UNLOCK(drvdata->base);
>            writel_relaxed(value, cti_reg_addr(drvdata, offset));
>            CS_LOCK(drvdata->base);
>    }

However, since we also need to handle cti_reg_addr_with_nr, it will be 
necessary to add an additional parameter "nr" to cti_write_single_reg?

Thanks
Yingchao
>>      2. For registers such as triginstatus1...3, I defined additional macros CTITRIGINSTATUS1...3. This is because CTITRIGINSTATUS + 0x4 equals CTITRIGOUTSTATUS, and to avoid conflicts with existing macros, I chose numbers starting from 0x1000 for the new definitions.
> To avoid the register naming pollution, please don't define the common
> names but only used for Qcom registers.
>
> AFAIK, you even don't need to define these registers.  These registers
> are only used for sysfs knobs, we can define an extra "nr" field (e.g.,
> bits[31..28] for indexing these registers, something like:
>
>    #define CIT_REG_NR_SHIFT          28
>    #define CIT_REG_NR_MASK           GENMASK(31, 28)
>    #define CTI_REG_GET_NR(reg)       FIELD_GET(CIT_REG_NR_MASK, (reg))
>    #define CTI_REG_SET_NR(reg, nr)   ((reg) | FIELD_PREP(CIT_REG_NR_MASK, (nr))
>
>    static struct attribute *coresight_cti_regs_attrs[] = {
>    ...
>      coresight_cti_reg(triginstatus, CTITRIGINSTATUS),
>      coresight_cti_reg(triginstatus1, CTI_REG_SET_NR(CTITRIGINSTATUS, 1)),
>      coresight_cti_reg(triginstatus2, CTI_REG_SET_NR(CTITRIGINSTATUS, 2)),
>      coresight_cti_reg(triginstatus3, CTI_REG_SET_NR(CTITRIGINSTATUS, 3)),
>    ...
>
> Then, you just need to decode "nr" fields in cti_qcom_reg_off().
>
>>      3. Regarding the visibility of attributes for triginstatus1...3, since coresight_cti_reg produces an anonymous variable that cannot be directly referenced, I used coresight_cti_regs_attrs[i] to obtain the attribute corresponding to triginstatus1.
> Okay, I get the meaning for "an anonymous variable" - there have no
> field naming when define attr with the macro coresight_cti_reg().
>
> but you could comparing the attr string?
>
>    if (!strcmp(attr->name, "triginstatus1") ||
>        !strcmp(attr->name, "triginstatus2") ||
>        !strcmp(attr->name, "triginstatus3"))
>        ...
>
> Thanks,
> Leo


From linux at armlinux.org.uk  Tue Dec  9 05:01:11 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Tue, 9 Dec 2025 13:01:11 +0000
Subject: [PATCH net v2] net: stmmac: Fix E2E delay mechanism
In-Reply-To: <9f0da5db-e92a-42e2-b788-2b07b8d28cfa@altera.com>
References: <20251129-ext-ptp-2v-v2-1-d23aca3e694f@altera.com>
 <26656845-d9d6-4fd2-bfff-99996cf03741@redhat.com>
 <aTFuJUiLMnHrnpW5@shell.armlinux.org.uk>
 <9f0da5db-e92a-42e2-b788-2b07b8d28cfa@altera.com>
Message-ID: <aTgdlykiar3SlNox@shell.armlinux.org.uk>

On Tue, Dec 09, 2025 at 06:01:05PM +0530, G Thomas, Rohan wrote:
> Hi Russell,
> 
> Thanks for reviewing the patch.
> 
> On 12/4/2025 4:49 PM, Russell King (Oracle) wrote:
> > On Thu, Dec 04, 2025 at 10:58:40AM +0100, Paolo Abeni wrote:
> > > On 11/29/25 4:07 AM, Rohan G Thomas wrote:
> > > > For E2E delay mechanism, "received DELAY_REQ without timestamp" error
> > > > messages show up for dwmac v3.70+ and dwxgmac IPs.
> > > > 
> > > > This issue affects socfpga platforms, Agilex7 (dwmac 3.70) and
> > > > Agilex5 (dwxgmac). According to the databook, to enable timestamping
> > > > for all events, the SNAPTYPSEL bits in the MAC_Timestamp_Control
> > > > register must be set to 2'b01, and the TSEVNTENA bit must be cleared
> > > > to 0'b0.
> > > > 
> > > > Commit 3cb958027cb8 ("net: stmmac: Fix E2E delay mechanism") already
> > > > addresses this problem for all dwmacs above version v4.10. However,
> > > > same holds true for v3.70 and above, as well as for dwxgmac. Updates
> > > > the check accordingly.
> > > > 
> > > > Fixes: 14f347334bf2 ("net: stmmac: Correctly take timestamp for PTPv2")
> > > > Fixes: f2fb6b6275eb ("net: stmmac: enable timestamp snapshot for required PTP packets in dwmac v5.10a")
> > > > Fixes: 3cb958027cb8 ("net: stmmac: Fix E2E delay mechanism")
> > > > Signed-off-by: Rohan G Thomas <rohan.g.thomas at altera.com>
> > > > ---
> > > > v1 -> v2:
> > > >     - Rebased patch to net tree
> > > >     - Replace core_type with has_xgmac
> > > >     - Nit changes in the commit message
> > > >     - Link: https://lore.kernel.org/all/20251125-ext-ptp-fix-v1-1-83f9f069cb36 at altera.com/
> > > 
> > > Given there is some uncertain WRT the exact oldest version to be used,
> > > it would be great to have some 3rd party testing/feedback on this. Let's
> > > wait a little more.
> > 
> > As I said, in the v3.74 documentation, it is stated that the SNAPTYPSEL
> > functions changed between v3.50 and v3.60, so I think it would be better
> > to propose a patch to test for < v3.6.
> > 
> 
> I tested this on socfpga platforms like Agilex7 which are using
> 3.7x, but don't have any platforms with dwmac <= v3.6.
> 
> > Alternatively, if someone has the pre-v3.6 databook to check what the
> > SNAPTYPSEL definition is and compare it with the v3.6+ definition, that
> > would also be a good thing to do.
> > 
> >  From the 3.74:
> > 
> > SNAPTYPSEL
> > 00		?
> > 01		?
> > 10		Sync, Delay_Req
> > 11		Sync, PDelay_Req, PDelay_Resp
> > 
> > TSEVNTENA
> > 0		All messages except Announce, Management and Signalling
> > 1		Sync, Delay_Req, PDelay_Req, PDelay_Resp
> > 
> > No table is provided, so it's difficult to know what all the bit
> > combinations do for v3.74.
> 
> In 3.73a databook, Table 6-70 has the following information and this is
> similar to v5.1 and v5.3. But don't have 3.74 databook.
> 
> SNAPTYPSEL	TSMSTRENA	TSEVNTENA	PTP Messages
> 00		X 		0 		SYNC, Follow_Up,
> 						Delay_Req, Delay_Resp
> 00 		0 		1 		SYNC
> 00 		1 		1 		Delay_Req
> 01 		X 		0 		SYNC, Follow_Up,
> 						Delay_Req, Delay_Resp,
> 						Pdelay_Req, Pdelay_Resp,
> 						Pdelay_Resp_Follow_Up
> 01 		0 		1 		SYNC, Pdelay_Req,
> 						Pdelay_Resp
> 01 		1 		1 		Delay_Req, Pdelay_Req,
> 						Pdelay_Resp
> 10 		X 		X 		SYNC, Delay_Req
> 11 		X 		X 		Pdelay_Req, Pdelay_Resp

I can't fathom why they would use this table in v3.73a, then put
something different in v4.2, and then go back to this table in
v5.1, so I'm wondering whether any of these tables can be relied
upon. This seems to be a complete mess.

I think the only way out of this is to test this - and I wonder
whether stmmac_selftests.c could have tests added to check which
PTP messages and in which direction get timestamped in each of
these modes.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From james.clark at linaro.org  Tue Dec  9 05:17:50 2025
From: james.clark at linaro.org (James Clark)
Date: Tue, 9 Dec 2025 13:17:50 +0000
Subject: [PATCH 06/19] coresight: trbe: Refactor syndrome decoding
In-Reply-To: <65c84357-0bda-454f-88c3-623b3ff9d29d@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-6-7da32b076b28@arm.com>
 <65c84357-0bda-454f-88c3-623b3ff9d29d@arm.com>
Message-ID: <1c1092e6-aa5d-4bb1-84e5-81151a02cc6f@linaro.org>



On 02/12/2025 11:06 am, Suzuki K Poulose wrote:
> Hi Leo
> 
> A couple of minor nits below. Otherwise looks like a nice cleanup
> 
> 
> On 01/12/2025 11:21, Leo Yan wrote:
>> It gives priority to TRBSR_EL1.EA (external abort); an external abort
>> will immediately bail out and return an error.
>>
>> Next, the syndrome decoding is refactored based on two levels of
>> information: the EC (Event Class) bits and the BSC (Trace Buffer Status
>> Code) bits.
>>
>> If TRBSR_EL1.EC==0b000000, the driver continues parsing TRBSR_EL1.BSC to
>> identify the specific trace buffer event.? Otherwise, any non-zero
>> TRBSR_EL1.EC is treated as an error.
>>
>> For error cases, the driver prints an error string and dumps registers
>> for debugging.
> 
> minor nit: Please avoid describing the code, which cod does well.
> Briefly mention what you are doing, giving any additional contexts
> that may not be evident from the code.
> 
> e.g:
> 
> "Add support for decoding the syndrome for TRBE, providing a verbose
> description of the code for Fatal/unhandled events.
> While at it add the new definitions from the latest Arm ARM for
> EC and BSC"
> 
> 
> 
> 
>>
>> No additional checks are required for wrap mode beyond verifying the
>> TRBSR_EL1.WRAP bit, even on units with overwrite errata, as this bit
> 
> 
>> reliably indicates a buffer wrap.
>>
>> Signed-off-by: Leo Yan <leo.yan at arm.com>
>> ---
>> ? drivers/hwtracing/coresight/coresight-trbe.c | 60 ++++++++++++++++++ 
>> +++-------
>> ? drivers/hwtracing/coresight/coresight-trbe.h |? 8 ++--
>> ? 2 files changed, 51 insertions(+), 17 deletions(-)
>>
>> diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/ 
>> hwtracing/coresight/coresight-trbe.c
>> index 
>> 9e565122816949b37b8ff5e4ba04cfbc317c6f25..28e2bfa68074f19ccaa4a737d00af577aea818fe 100644
>> --- a/drivers/hwtracing/coresight/coresight-trbe.c
>> +++ b/drivers/hwtracing/coresight/coresight-trbe.c
>> @@ -643,29 +643,61 @@ static void trbe_enable_hw(struct trbe_buf *buf)
>> ? static enum trbe_fault_action trbe_get_fault_act(struct 
>> perf_output_handle *handle,
>> ?????????????????????????? u64 trbsr)
>> ? {
>> +??? const char *err_str;
>> ????? int ec = get_trbe_ec(trbsr);
>> ????? int bsc = get_trbe_bsc(trbsr);
>> -??? struct trbe_buf *buf = etm_perf_sink_config(handle);
>> -??? struct trbe_cpudata *cpudata = buf->cpudata;
>> ????? WARN_ON(is_trbe_running(trbsr));
>> -??? if (is_trbe_trg(trbsr) || is_trbe_abort(trbsr))
>> -??????? return TRBE_FAULT_ACT_FATAL;
>> -??? if ((ec == TRBE_EC_STAGE1_ABORT) || (ec == TRBE_EC_STAGE2_ABORT))
>> -??????? return TRBE_FAULT_ACT_FATAL;
>> +??? if (is_trbe_abort(trbsr)) {
>> +??????? err_str = "External abort";
>> +??????? goto out_fatal;
>> +??? }
>> -??? /*
>> -???? * If the trbe is affected by TRBE_WORKAROUND_OVERWRITE_FILL_MODE,
>> -???? * it might write data after a WRAP event in the fill mode.
>> -???? * Thus the check TRBPTR == TRBBASER will not be honored.
>> -???? */
>> -??? if ((is_trbe_wrap(trbsr) && (ec == TRBE_EC_OTHERS) && (bsc == 
>> TRBE_BSC_FILLED)) &&
>> -??????? (trbe_may_overwrite_in_fill_mode(cpudata) ||
>> -???????? get_trbe_write_pointer() == get_trbe_base_pointer()))
>> +??? switch (ec) {
>> +??? case TRBE_EC_OTHERS:
>> +??????? break;
>> +??? case TRBE_EC_BUF_MGMT_IMPL:
>> +??????? err_str = "Unexpected implemented management";
> 
> minor nit: "Unexpected IMPDEF buffer management event"
> 
> 
> Suzuki
> 
>> +??????? goto out_fatal;
>> +??? case TRBE_EC_GP_CHECK_FAULT:
>> +??????? err_str = "Granule Protection Check fault";
>> +??????? goto out_fatal;
>> +??? case TRBE_EC_STAGE1_ABORT:
>> +??????? err_str = "Stage 1 data abort";
>> +??????? goto out_fatal;
>> +??? case TRBE_EC_STAGE2_ABORT:
>> +??????? err_str = "Stage 2 data abort";
>> +??????? goto out_fatal;
>> +??? default:
>> +??????? err_str = "Unknown error code";
>> +??????? goto out_fatal;
>> +??? }
>> +
>> +??? switch (bsc) {
>> +??? case TRBE_BSC_NOT_STOPPED:
>> +??????? break;
>> +??? case TRBE_BSC_FILLED:
>> +??????? break;
>> +??? case TRBE_BSC_TRIGGERED:
>> +??????? err_str = "Unexpected trigger status";
>> +??????? goto out_fatal;
>> +??? default:
>> +??????? err_str = "Unexpected buffer status code";
>> +??????? goto out_fatal;
>> +??? }
>> +
>> +??? if (is_trbe_wrap(trbsr))
>> ????????? return TRBE_FAULT_ACT_WRAP;
>> ????? return TRBE_FAULT_ACT_SPURIOUS;
>> +
>> +out_fatal:
>> +??? pr_err_ratelimited("%s on CPU %d [TRBSR=0x%016llx, 
>> TRBPTR=0x%016llx, TRBLIMITR=0x%016llx]\n",
>> +?????????????? err_str, smp_processor_id(), trbsr,
>> +?????????????? read_sysreg_s(SYS_TRBPTR_EL1),
>> +?????????????? read_sysreg_s(SYS_TRBLIMITR_EL1));

Don't you need to use %p to not leak pointers?

>> +??? return TRBE_FAULT_ACT_FATAL;
>> ? }
>> ? static unsigned long trbe_get_trace_size(struct perf_output_handle 
>> *handle,
>> diff --git a/drivers/hwtracing/coresight/coresight-trbe.h b/drivers/ 
>> hwtracing/coresight/coresight-trbe.h
>> index 
>> 45202c48accec7c86ba56130e2737bc2d1830fae..d7f7cd763c0c7139cf322b7336ee563073e3bea0 100644
>> --- a/drivers/hwtracing/coresight/coresight-trbe.h
>> +++ b/drivers/hwtracing/coresight/coresight-trbe.h
>> @@ -35,9 +35,11 @@ static inline bool is_trbe_enabled(void)
>> ????? return trblimitr & TRBLIMITR_EL1_E;
>> ? }
>> -#define TRBE_EC_OTHERS??????? 0
>> -#define TRBE_EC_STAGE1_ABORT??? 36
>> -#define TRBE_EC_STAGE2_ABORT??? 37
>> +#define TRBE_EC_OTHERS??????????? 0x0
>> +#define TRBE_EC_GP_CHECK_FAULT??????? 0X1e
>> +#define TRBE_EC_BUF_MGMT_IMPL??????? 0x1f
>> +#define TRBE_EC_STAGE1_ABORT??????? 0x24
>> +#define TRBE_EC_STAGE2_ABORT??????? 0x25

I know some were already defined here, but this should probably be an 
enum in sysreg.

>> ? static inline int get_trbe_ec(u64 trbsr)
>> ? {
>>
> 



From zhanjie9 at hisilicon.com  Tue Dec  9 05:23:58 2025
From: zhanjie9 at hisilicon.com (Jie Zhan)
Date: Tue, 9 Dec 2025 21:23:58 +0800
Subject: [PATCH v4 3/3] cpufreq: CPPC: Update FIE arch_freq_scale in ticks
 for non-PCC regs
In-Reply-To: <270216de-e7d1-4552-a04f-8b0fd7b79552@arm.com>
References: <20251203032422.3232957-1-zhanjie9@hisilicon.com>
 <20251203032422.3232957-4-zhanjie9@hisilicon.com>
 <270216de-e7d1-4552-a04f-8b0fd7b79552@arm.com>
Message-ID: <347f2003-1efd-44be-89e3-080ab169599e@hisilicon.com>



Hi Pierre,

On 12/8/2025 6:08 PM, Pierre Gondois wrote:
> Hello Jie Zhan,
> 
> 
> On 12/3/25 04:24, Jie Zhan wrote:
...
>> @@ -236,10 +265,8 @@ static void __init cppc_freq_invariance_init(void)
>>     static void cppc_freq_invariance_exit(void)
>>   {
>> -    if (fie_disabled)
>> -        return;
>> -
>> -    kthread_destroy_worker(kworker_fie);
>> +    if (kworker_fie)
>> +        kthread_destroy_worker(kworker_fie);
> 
> Shouldn't we have:
>   kworker_fie = NULL;
> here aswell ?
> 
I don't think it's needed.
This is where we unload the cppc_cpufreq module.  'kworker_fie' will no
longer be used after this, and it will be initialized to NULL again when
reloading the module.

I can't think of any other buggy scenarios.
>>   }
>>     #else
> 
> 
> Otherwise, for the 3 patches:
> 
> Reviewed-by: Pierre Gondois <pierre.gondois at arm.com>
> 
Thanks!
Jie


From robin.murphy at arm.com  Tue Dec  9 05:33:36 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Tue, 9 Dec 2025 13:33:36 +0000
Subject: [PATCH] iommu/io-pgtable-arm: Add misisng concatenated PGD cases
In-Reply-To: <aTgX9qhaLyrQ5iye@google.com>
References: <20251130194506.593700-1-smostafa@google.com>
 <18a39079-2285-47fb-b306-040f2bc1bbaa@arm.com> <aTgX9qhaLyrQ5iye@google.com>
Message-ID: <498bbad4-ea64-4a24-a63f-e131d271990a@arm.com>

On 2025-12-09 12:37 pm, Mostafa Saleh wrote:
> On Tue, Dec 09, 2025 at 11:34:34AM +0000, Robin Murphy wrote:
>> On 2025-11-30 7:45 pm, Mostafa Saleh wrote:
>>> arm_lpae_concat_mandatory() assumes that OAS >= IAS which is not
>>> correct for SMMUs supporting AArch32, and have OAS = 32/36 bits,
>>> as IAS would be 40 bits.
>>
>> But that is only when *using* AArch32 format. The bit in chapter 3.4 of the
>> SMMU architecture is talking about the maximum IAS that an SMMU
>> implementation needs to be able to accommodate based on its configuration,
>> but it does then attempt to clarify that the actual IPA size in use by any
>> given context should depend on the VMSA format in use:
>>
>> "VMSAv8-32 LPAE always supports an IPA size of 40 bits, whereas VMSAv8-64
>> and VMSAv9-128 limits the maximum IPA size to the maximum PA size."
>>
>> Rule R_SRKBC in the Arm ARM lays out the exact T0SZ constraints with this
>> AArch32/AArch64 detail.
> 
> I see, thanks a lot for the explanation, I got confused by the this
> statement:
> Note: If AArch32 is implemented, IAS == MAX(40, OAS), otherwise IAS == OAS.

Indeed, that appears confusingly contradictory; I've filed a bug.

> However, I think this is still a bug but somewere else, as at the moment
> the SMMUv3 dirver will use the SMMU IAS (40-bits) as input for AArch64
> stage-2 page tables, so we need either to limit the IAS as:
> 
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index d16d35c78c06..d21153156daa 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -2561,7 +2561,7 @@ static int arm_smmu_domain_finalise(struct arm_smmu_domain *smmu_domain,
>          case ARM_SMMU_DOMAIN_S2:
>                  if (enable_dirty)
>                          return -EOPNOTSUPP;
> -               pgtbl_cfg.ias = smmu->ias;
> +               pgtbl_cfg.ias = min(smmu->ias, smmu->oas);
>                  pgtbl_cfg.oas = smmu->oas;
>                  fmt = ARM_64_LPAE_S2;
>                  finalise_stage_fn = arm_smmu_domain_finalise_s2;
> 
> Or, don't populate IAS depending on AArch32 support as the driver
> doesn't support it, effectively reverting:
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f0c453dbcce7767cd868deb809ba68083c93954e

It does appear we've missed the detail here. TBH I'm not really sure why 
we're bothering to consider the theoretical maximum IAS at all when it 
only makes any difference to a format we've never cared about supporting 
anyway. Frankly I'd be inclined to just remove smmu->ias altogether - 
even if we did ever want to support LPAE format, it would be just as 
trivial for that to hard-code pgtbl_cfg.ias = 40 based on the 
architecture rules.

Thanks,
Robin.


From james.clark at linaro.org  Tue Dec  9 05:37:39 2025
From: james.clark at linaro.org (James Clark)
Date: Tue, 9 Dec 2025 13:37:39 +0000
Subject: [PATCH 07/19] coresight: trbe: Refactor AUX flag setting
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-7-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-7-7da32b076b28@arm.com>
Message-ID: <a638f74f-94bc-4052-b8e1-e940aca2d4ce@linaro.org>



On 01/12/2025 11:21 am, Leo Yan wrote:
> Rather than spreading AUX flag setting in different functions, use
> trbe_get_fault_act() as a central place for setting the flag.
> 
> Later we will support WRAP mode with continuous trace, so the WRAP
> event does not necessarily cause the trace discontinuity, change to
> check the stop status instead.
> 
> Signed-off-by: Leo Yan <leo.yan at arm.com>
> ---
>   drivers/hwtracing/coresight/coresight-trbe.c | 38 +++++++++++++---------------
>   1 file changed, 17 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
> index 28e2bfa68074f19ccaa4a737d00af577aea818fe..b06885a08e082fd34f68d9588518807b5c47c86e 100644
> --- a/drivers/hwtracing/coresight/coresight-trbe.c
> +++ b/drivers/hwtracing/coresight/coresight-trbe.c
> @@ -265,25 +265,6 @@ static void trbe_reset_local(struct trbe_cpudata *cpudata)
>   	write_sysreg_s(0, SYS_TRBSR_EL1);
>   }
>   
> -static void trbe_report_wrap_event(struct perf_output_handle *handle)
> -{
> -	/*
> -	 * Mark the buffer to indicate that there was a WRAP event by
> -	 * setting the COLLISION flag. This indicates to the user that
> -	 * the TRBE trace collection was stopped without stopping the
> -	 * ETE and thus there might be some amount of trace that was
> -	 * lost between the time the WRAP was detected and the IRQ
> -	 * was consumed by the CPU.
> -	 *
> -	 * Setting the TRUNCATED flag would move the event to STOPPED
> -	 * state unnecessarily, even when there is space left in the
> -	 * ring buffer. Using the COLLISION flag doesn't have this side
> -	 * effect. We only set TRUNCATED flag when there is no space
> -	 * left in the ring buffer.
> -	 */
> -	perf_aux_output_flag(handle, PERF_AUX_FLAG_COLLISION);
> -}
> -
>   static void trbe_truncate_event(struct perf_output_handle *handle)
>   {
>   	struct trbe_buf *buf = etm_perf_sink_config(handle);
> @@ -687,6 +668,23 @@ static enum trbe_fault_action trbe_get_fault_act(struct perf_output_handle *hand
>   		goto out_fatal;
>   	}
>   
> +	/*
> +	 * Mark the buffer to indicate that there was a WRAP event by
> +	 * setting the COLLISION flag. This indicates to the user that
> +	 * the TRBE trace collection was stopped without stopping the
> +	 * ETE and thus there might be some amount of trace that was
> +	 * lost between the time the WRAP was detected and the IRQ
> +	 * was consumed by the CPU.
> +	 *
> +	 * Setting the TRUNCATED flag would move the event to STOPPED
> +	 * state unnecessarily, even when there is space left in the
> +	 * ring buffer. Using the COLLISION flag doesn't have this side
> +	 * effect. We only set TRUNCATED flag when there is no space
> +	 * left in the ring buffer.
> +	 */
> +	if (!is_trbe_running(trbsr))
> +		perf_aux_output_flag(handle, PERF_AUX_FLAG_COLLISION);
> +

Do we need the complexity of COLLISION (changed to PARTIAL in a later 
commit) and TRUNCATED at the same time?

 From my understanding, TRUNCATED would be when Perf is too slow and we 
want to disable the event for it to catch up, and PARTIAL is when there 
was some buffer error so technically we don't need the event to be 
disabled, but Perf still needs to be notified if we want to start only 
resetting the decoder when a flag is set rather than on all aux records?

There is no happy path where there is a buffer error, so I'm not sure 
why we need the complexity of an extra case? There's no harm in 
disabling the event on a buffer error. Also it's hard to see what the 
exact scenario for PARTIAL is, because we set truncated anyway for fatal 
statuses. The comment in the later commit for the PARTIAL change just 
says "trace was stopped", but not why.

>   	if (is_trbe_wrap(trbsr))
>   		return TRBE_FAULT_ACT_WRAP;
>   
> @@ -878,7 +876,6 @@ static unsigned long arm_trbe_update_buffer(struct coresight_device *csdev,
>   			goto done;
>   		}
>   
> -		trbe_report_wrap_event(handle);
>   		wrap = true;
>   	}
>   
> @@ -1099,7 +1096,6 @@ static int trbe_handle_overflow(struct perf_output_handle *handle)
>   	if (buf->snapshot)
>   		handle->head += size;
>   
> -	trbe_report_wrap_event(handle);
>   	perf_aux_output_end(handle, size);
>   	event_data = perf_aux_output_begin(handle, event);
>   	if (!event_data) {
> 



From zhanjie9 at hisilicon.com  Tue Dec  9 05:37:49 2025
From: zhanjie9 at hisilicon.com (Jie Zhan)
Date: Tue, 9 Dec 2025 21:37:49 +0800
Subject: [PATCH v4 1/3] ACPI: CPPC: Factor out and export per-cpu
 cppc_perf_ctrs_in_pcc_cpu()
In-Reply-To: <aTb6Gvzvc9C7vnVP@arm.com>
References: <20251203032422.3232957-1-zhanjie9@hisilicon.com>
 <20251203032422.3232957-2-zhanjie9@hisilicon.com> <aTb6Gvzvc9C7vnVP@arm.com>
Message-ID: <4e850664-f883-4a26-b8d6-f484a9114ed2@hisilicon.com>



On 12/9/2025 12:17 AM, Beata Michalska wrote:
> On Wed, Dec 03, 2025 at 11:24:20AM +0800, Jie Zhan wrote:
>> Factor out cppc_perf_ctrs_in_pcc_cpu() for checking whether per-cpu CPC
>> regs are defined in PCC channels, and export it out for further use.
>>
>> Signed-off-by: Jie Zhan <zhanjie9 at hisilicon.com>
>> ---
>>  drivers/acpi/cppc_acpi.c | 45 +++++++++++++++++++++-------------------
>>  include/acpi/cppc_acpi.h |  5 +++++
>>  2 files changed, 29 insertions(+), 21 deletions(-)
>>
>> diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
>> index 3bdeeee3414e..aa80dbcf42c0 100644
>> --- a/drivers/acpi/cppc_acpi.c
>> +++ b/drivers/acpi/cppc_acpi.c
>> @@ -1422,6 +1422,29 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
>>  }
>>  EXPORT_SYMBOL_GPL(cppc_get_perf_caps);
>>  
>> +bool cppc_perf_ctrs_in_pcc_cpu(unsigned int cpu)
>> +{
>> +	struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu);
>> +	struct cpc_register_resource *ref_perf_reg;
>> +
>> +	/*
>> +	 * If reference perf register is not supported then we should use the
>> +	 * nominal perf value
>> +	 */
>> +	ref_perf_reg = &cpc_desc->cpc_regs[REFERENCE_PERF];
>> +	if (!CPC_SUPPORTED(ref_perf_reg))
>> +		ref_perf_reg = &cpc_desc->cpc_regs[NOMINAL_PERF];
>> +
>> +	if (CPC_IN_PCC(&cpc_desc->cpc_regs[DELIVERED_CTR]) ||
>> +	    CPC_IN_PCC(&cpc_desc->cpc_regs[REFERENCE_CTR]) ||
>> +	    CPC_IN_PCC(&cpc_desc->cpc_regs[CTR_WRAP_TIME]) ||
>> +	    CPC_IN_PCC(ref_perf_reg))
>> +		return true;
>> +
>> +	return false;
>> +}
>> +EXPORT_SYMBOL_GPL(cppc_perf_ctrs_in_pcc_cpu);
> It is minor, but I would prefer the earlier version when we grab the reference
> performance reg only when none of the other regs is in the PCC.
Why?

It could return a little bit earlier for the PCC reg case, but this is only
called in initialization so efficiency is not that important I guess.
> 
> ---
> BR
> Beata

...


From james.clark at linaro.org  Tue Dec  9 05:40:35 2025
From: james.clark at linaro.org (James Clark)
Date: Tue, 9 Dec 2025 13:40:35 +0000
Subject: [PATCH 08/19] coresight: trbe: Use PERF_AUX_FLAG_PARTIAL instead
 of PERF_AUX_FLAG_COLLISION
In-Reply-To: <5f6bcd93-b565-4b10-9a2d-6851141e5dbe@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-8-7da32b076b28@arm.com>
 <5f6bcd93-b565-4b10-9a2d-6851141e5dbe@arm.com>
Message-ID: <f1ac7190-bdd9-4725-8955-d82d6f1912fb@linaro.org>



On 05/12/2025 4:28 am, Anshuman Khandual wrote:
> On 01/12/25 4:51 PM, Leo Yan wrote:
>> When tracing stops, there is no collision with other samples, so using
>> PERF_AUX_FLAG_COLLISION does not accurately reflect the trace state and
>> may mislead userspace.
>>
>> Use PERF_AUX_FLAG_PARTIAL instead to indicate that tracing stopped and
>> the record may contain gaps.
>>
>> Signed-off-by: Leo Yan <leo.yan at arm.com>
>> ---
>>   drivers/hwtracing/coresight/coresight-trbe.c | 19 ++++++-------------
>>   1 file changed, 6 insertions(+), 13 deletions(-)
>>
>> diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
>> index b06885a08e082fd34f68d9588518807b5c47c86e..0caa4a6b437a3aa39fc6bcc72a23711b54f7c598 100644
>> --- a/drivers/hwtracing/coresight/coresight-trbe.c
>> +++ b/drivers/hwtracing/coresight/coresight-trbe.c
>> @@ -669,21 +669,14 @@ static enum trbe_fault_action trbe_get_fault_act(struct perf_output_handle *hand
>>   	}
>>   
>>   	/*
>> -	 * Mark the buffer to indicate that there was a WRAP event by
>> -	 * setting the COLLISION flag. This indicates to the user that
>> -	 * the TRBE trace collection was stopped without stopping the
>> -	 * ETE and thus there might be some amount of trace that was
>> -	 * lost between the time the WRAP was detected and the IRQ
>> -	 * was consumed by the CPU.
>> -	 *
>> -	 * Setting the TRUNCATED flag would move the event to STOPPED
>> -	 * state unnecessarily, even when there is space left in the
>> -	 * ring buffer. Using the COLLISION flag doesn't have this side
>> -	 * effect. We only set TRUNCATED flag when there is no space
>> -	 * left in the ring buffer.
>> +	 * Mark the buffer to indicate that the trace is stopped by setting
>> +	 * the PARTIAL flag. This indicates to the user that the TRBE trace
>> +	 * collection was stopped without stopping the ETE and thus there
>> +	 * might be some amount of trace that was lost between the time the
>> +	 * TRBE event was detected and the IRQ was consumed by the CPU.
>>   	 */
>>   	if (!is_trbe_running(trbsr))
>> -		perf_aux_output_flag(handle, PERF_AUX_FLAG_COLLISION);
>> +		perf_aux_output_flag(handle, PERF_AUX_FLAG_PARTIAL);
> 
> This is interesting. So there is a no possibility for the records to be
> overridden in the perf ring buffer and incomplete record is all that can
> happen when TRBE is stopped, without stopping the ETE first ? Could both
> of these scenarios might be possible as well ?
> 

There's no chance of overwriting because that would be the TRUNCATED 
case and the event would get disabled. PARTIAL seems to be when there 
was an error that's recoverable in the driver only, but as in my other 
comment I don't think the extra complexity is necessary and always using 
TRUNCATED would be enough.

>>   
>>   	if (is_trbe_wrap(trbsr))
>>   		return TRBE_FAULT_ACT_WRAP;
>>



From francesco at dolcini.it  Tue Dec  9 05:43:43 2025
From: francesco at dolcini.it (Francesco Dolcini)
Date: Tue, 9 Dec 2025 14:43:43 +0100
Subject: tps65219/am62p kernel oops
In-Reply-To: <23eeda43-a938-4c15-aee3-b1b9df217ff8@ti.com>
References: <aBDSTxALaOc-PD7X@gaggiata.pivistrello.it>
 <20250429185240.6a7644bf@akair>
 <20250430080109.GA65078@francesco-nb>
 <aBH5s7p2RxLGjTQD@gaggiata.pivistrello.it>
 <23eeda43-a938-4c15-aee3-b1b9df217ff8@ti.com>
Message-ID: <20251209134343.GA238880@francesco-nb>

Hello Shree,

On Thu, May 01, 2025 at 10:32:12AM -0500, Shree Ramamoorthy wrote:
> On 4/30/25 5:21 AM, Francesco Dolcini wrote:
> > On Wed, Apr 30, 2025 at 10:01:14AM +0200, Francesco Dolcini wrote:
> > > On Tue, Apr 29, 2025 at 06:52:40PM +0200, Andreas Kemnade wrote:
> > > > Am Tue, 29 Apr 2025 15:21:19 +0200
> > > > schrieb Francesco Dolcini <francesco at dolcini.it>:
> > > > 
> > > > > Hello all,
> > > > > while working on adding support in mainline for a new board based on TI
> > > > > AM62P SoC I noticed the following Kernel Oops.
> > > > > 
> > > > > This oops was reproduced running current Linux
> > > > > master, 6.15.0-rc4+, ca91b9500108d4cf083a635c2e11c884d5dd20ea, but I was able
> > > > > to reproduce the same with 6.14.4.
> > > > > 
> > > > [...]
> > > > > [  +0.000022] Call trace:
> > > > > [  +0.000011]  regulator_notifier_call_chain+0x20/0xa4 (P)
> > > > > [  +0.000018]  tps65219_regulator_irq_handler+0x34/0x80
> > > > wild guessing: maybe because irqdata->rdev is not initalized in
> > > > _probe()? At least I do not see where it would be initialized.
> > > your wild guess seems correct, I'll send a proper patch with your
> > > suggested-by after doing a couple of more tests, thanks.
> > so, the bug is clear, however the fix is not an obvious one liner as I was
> > wishing.
> > 
> > we would need to add a link from each of the interrupts to the specific
> > regulator. as of now such a connection is not existing in the code.
> I'll try out implementing and testing the solution, but will get to it early next week. Will email with any updates!

What's the status on this? Were you able to do any progress or work on
it?

Thanks
Francesco



From kevin.brodsky at arm.com  Tue Dec  9 05:46:06 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Tue, 9 Dec 2025 14:46:06 +0100
Subject: [PATCH v9 03/16] arm64/ptrace: Return early for
 ptrace_report_syscall_entry() error
In-Reply-To: <20251204082123.2792067-4-ruanjinjie@huawei.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
 <20251204082123.2792067-4-ruanjinjie@huawei.com>
Message-ID: <52f63e40-541f-4ed8-9d05-626eab4b39cb@arm.com>

On 04/12/2025 09:21, Jinjie Ruan wrote:
> The generic entry abort the syscall_trace_enter() sequence if
> ptrace_report_syscall_entry() errors out, but arm64 not.
>
> As the ptrace_report_syscall_entry() comment said, the calling arch code
> should abort the system call and must prevent normal entry so no system
> call is made if ptrace_report_syscall_entry() return nonzero.

This patch is now in the right position, which means that arm64 does
abort the syscall already without this patch. What we're changing here
is that the tracing sequence is interrupted. The comment you're
referring to says nothing about tracing so I'm not sure it helps to
refer to it.

Otherwise:

Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>

> In preparation for moving arm64 over to the generic entry code,
> return early if ptrace_report_syscall_entry() encounters an error.
>
> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
> ---
>  arch/arm64/kernel/ptrace.c | 14 +++++++++-----
>  1 file changed, 9 insertions(+), 5 deletions(-)
>
> diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
> index 4532e9831856..3926ce6aa268 100644
> --- a/arch/arm64/kernel/ptrace.c
> +++ b/arch/arm64/kernel/ptrace.c
> @@ -2346,15 +2346,18 @@ static __always_inline unsigned long ptrace_save_reg(struct pt_regs *regs,
>  	return saved_reg;
>  }
>  
> -static void report_syscall_entry(struct pt_regs *regs)
> +static int report_syscall_entry(struct pt_regs *regs)
>  {
>  	unsigned long saved_reg;
> -	int regno;
> +	int regno, ret;
>  
>  	saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_ENTER, &regno);
> -	if (ptrace_report_syscall_entry(regs))
> +	ret = ptrace_report_syscall_entry(regs);
> +	if (ret)
>  		forget_syscall(regs);
>  	regs->regs[regno] = saved_reg;
> +
> +	return ret;
>  }
>  
>  static void report_syscall_exit(struct pt_regs *regs)
> @@ -2381,10 +2384,11 @@ static void report_syscall_exit(struct pt_regs *regs)
>  int syscall_trace_enter(struct pt_regs *regs)
>  {
>  	unsigned long flags = read_thread_flags();
> +	int ret;
>  
>  	if (flags & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE)) {
> -		report_syscall_entry(regs);
> -		if (flags & _TIF_SYSCALL_EMU)
> +		ret = report_syscall_entry(regs);
> +		if (ret || (flags & _TIF_SYSCALL_EMU))
>  			return NO_SYSCALL;
>  	}
>  


From kevin.brodsky at arm.com  Tue Dec  9 05:47:35 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Tue, 9 Dec 2025 14:47:35 +0100
Subject: [PATCH v9 13/16] arm64: entry: Convert to generic entry
In-Reply-To: <20251204082123.2792067-14-ruanjinjie@huawei.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
 <20251204082123.2792067-14-ruanjinjie@huawei.com>
Message-ID: <ec404a91-2e24-4198-975b-e26c6a8330f8@arm.com>

On 04/12/2025 09:21, Jinjie Ruan wrote:
> Currently, x86, Riscv, Loongarch use the generic entry which makes
> maintainers' work easier and codes more elegant. arm64 has already
> switched to the generic IRQ entry, so completely convert arm64 to use
> the generic entry infrastructure from kernel/entry/*.
>
> The changes are below:
>  - Remove TIF_SYSCALL_* flag.
>
>  - Remove _TIF_SYSCALL_WORK and has_syscall_work(), as _TIF_SYSCALL_WORK
>    is equal with SYSCALL_WORK_ENTER.

Should be updated considering patch 7 (has_syscall_work() no longer
exists and there is also _TIF_SYSCALL_EXIT_WORK).

>  - Implement arch_ptrace_report_syscall_entry/exit() with
>    report_syscall_entry/exit() to do arm64-specific save/restore
>    during syscall entry/exit.
>
>  - Add "ARCH_SYSCALL_WORK_EXIT" to be defined as "_TIF_SECCOMP |
>    _TIF_SYSCALL_EMU" to keep the arm64 behaviour unchanged.

No longer the case.

>  - Remove arm64 syscall_trace_enter(), syscall_exit_to_user_mode_prepare(),
>    and related sub-functions including syscall_exit_work() and
>    syscall_enter_audit(), by calling generic entry's functions with similar
>    functionality.

Would be good to talk about SYSCALL_EXIT_TRAP as well.

Otherwise:

Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>

> - Implement arch_syscall_is_vdso_sigreturn() to support "Syscall User
>   Dispatch".
>
> Suggested-by: Kevin Brodsky <kevin.brodsky at arm.com>
> Suggested-by: Mark Rutland <mark.rutland at arm.com>
> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
>
> [...]


From ulf.hansson at linaro.org  Tue Dec  9 05:47:30 2025
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Tue, 9 Dec 2025 14:47:30 +0100
Subject: [PATCH v2] mmc: sdhci-esdhc-imx: wait for data transfer
 completion before reset
In-Reply-To: <DU0PR04MB94962D103B1A92354CDD1FE690A7A@DU0PR04MB9496.eurprd04.prod.outlook.com>
References: <20251205071729.83857-1-ziniu.wang_1@nxp.com> <DU0PR04MB94962D103B1A92354CDD1FE690A7A@DU0PR04MB9496.eurprd04.prod.outlook.com>
Message-ID: <CAPDyKFpYU3PZs-dSREyGyyyoptY0zCQmHP+mxMMgvYQL-xXQZA@mail.gmail.com>

On Fri, 5 Dec 2025 at 09:12, Bough Chen <haibo.chen at nxp.com> wrote:
>
> > -----Original Message-----
> > From: Luke Wang <ziniu.wang_1 at nxp.com>
> > Sent: 2025?12?5? 15:17
> > To: adrian.hunter at intel.com; Bough Chen <haibo.chen at nxp.com>;
> > ulf.hansson at linaro.org
> > Cc: shawnguo at kernel.org; s.hauer at pengutronix.de; kernel at pengutronix.de;
> > festevam at gmail.com; linux-mmc at vger.kernel.org; imx at lists.linux.dev; dl-S32
> > <S32 at nxp.com>; linux-arm-kernel at lists.infradead.org;
> > linux-kernel at vger.kernel.org
> > Subject: [PATCH v2] mmc: sdhci-esdhc-imx: wait for data transfer completion
> > before reset
> >
> > From: Luke Wang <ziniu.wang_1 at nxp.com>
> >
> > On IMX7ULP platforms, certain SD cards (e.g. Kingston Canvas Go! Plus) cause
> > system hangs and reboots during manual tuning. These cards exhibit large gaps
> > (~16us) between tuning command response and data transmission.
> > When cmd CRC errors occur during tuning, the code assumes data errors even
> > tuning data hasn't been fully received and then reset host data circuit.
> >
> > Per IMX7ULP reference manual, reset operations (RESET_DATA/ALL) need to
> > make sure no active data transfers. Previously, resetting while data was in-flight
> > would clear data circuit, including ADMA/SDMA address, causing data to be
> > transmitted to incorrect memory address. This patch adds polling for data
> > transfer completion before executing resets.
> >
> > Signed-off-by: Luke Wang <ziniu.wang_1 at nxp.com>
> > ---
> > v2: amend commit message
> > ---
> >  drivers/mmc/host/sdhci-esdhc-imx.c | 15 +++++++++++++++
> >  1 file changed, 15 insertions(+)
> >
> > diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c
> > b/drivers/mmc/host/sdhci-esdhc-imx.c
> > index a7a5df673b0f..affde1936510 100644
> > --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> > +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> > @@ -1453,6 +1453,21 @@ static void esdhc_set_uhs_signaling(struct
> > sdhci_host *host, unsigned timing)
> >
> >  static void esdhc_reset(struct sdhci_host *host, u8 mask)  {
> > +     u32 present_state;
> > +     int ret;
> > +
> > +     /*
> > +      * For data or full reset, ensure any active data transfer completes
> > +      * before resetting to avoid system hang.
> > +      */
> > +     if (mask & (SDHCI_RESET_DATA | SDHCI_RESET_ALL)) {
> > +             ret = readl_poll_timeout_atomic(host->ioaddr + ESDHC_PRSSTAT,
> > present_state,
>
> I'm okay with the patch, but I find one thing here:
>
> I notice you use _atomic here, I guess you want to cover the case when the reset function is called in hardware irq handler sdhci_irq().
> I'm not sure whether it is suitable to add delay in hardware iqr handler, I find there is also udelay in sdhci_reset(), sdhci_reset can also be called in hardware irq handler when there is cmd_crc/data_crc error.
> Adrian/Ulf, do you notice this issue before? Any comments?

You are right. In general it's certainly not preferred to poll/delay
in an atomic context. But if I understand correctly here, polling in
atomic context should not happen that frequently, right?

Moreover, I wonder if we really need to have a polling-timeout of
100ms? Where did that value come from?

In any case, please add a define to specify the timeout and make sure
the define-name has the suffix corresponding to the unit (_US,
_MS,...)

>
> Regards
> Haibo Chen
>
>
> > +                                             !(present_state & SDHCI_DATA_INHIBIT), 2,
> > 100000);
> > +             if (ret == -ETIMEDOUT)
> > +                     dev_warn(mmc_dev(host->mmc),
> > +                              "timeout waiting for data transfer completion\n");
> > +     }
> > +
> >       sdhci_and_cqhci_reset(host, mask);
> >
> >       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
> > --
> > 2.34.1
>

Kind regards
Uffe


From kevin.brodsky at arm.com  Tue Dec  9 05:48:09 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Tue, 9 Dec 2025 14:48:09 +0100
Subject: [PATCH v9 14/16] arm64: Inline el0_svc_common()
In-Reply-To: <20251204082123.2792067-15-ruanjinjie@huawei.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
 <20251204082123.2792067-15-ruanjinjie@huawei.com>
Message-ID: <746211f0-74b7-4935-a036-48a00bb5701b@arm.com>

On 04/12/2025 09:21, Jinjie Ruan wrote:
> After switch arm64 to Generic Entry, the compiler no longer inlines

Did it inline it before this series?

> el0_svc_common() into do_el0_svc(). So inline el0_svc_common() and it
> has 1% performance uplift on perf bench basic syscall on kunpeng920
> as below.
>
> | Metric     | W/O this patch | With this patch | Change    |
> | ---------- | -------------- | --------------- | --------- |
> | Total time | 2.195 [sec]    | 2.171 [sec]     |  ?1.1%   |
> | usecs/op   | 0.219575       | 0.217192        |  ?1.1%   |
> | ops/sec    | 4,554,260      | 4,604,225       |  ?1.1%    |
>
> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>

I think this is sensible - do_el0_svc() is clearly hot and the small
increase in code size is completely justified. It also removes a
performance regression when enabling CONFIG_COMPAT (without it
el0_svc_common() has only one caller so it should be inlined regardless).

Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>

> ---
>  arch/arm64/kernel/syscall.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
> index 47e193a1cfff..5aa51da9ec25 100644
> --- a/arch/arm64/kernel/syscall.c
> +++ b/arch/arm64/kernel/syscall.c
> @@ -66,8 +66,8 @@ static void invoke_syscall(struct pt_regs *regs, unsigned int scno,
>  	choose_random_kstack_offset(get_random_u16());
>  }
>  
> -static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
> -			   const syscall_fn_t syscall_table[])
> +static __always_inline void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
> +					   const syscall_fn_t syscall_table[])
>  {
>  	unsigned long work = READ_ONCE(current_thread_info()->syscall_work);
>  	unsigned long flags = read_thread_flags();


From kevin.brodsky at arm.com  Tue Dec  9 05:48:51 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Tue, 9 Dec 2025 14:48:51 +0100
Subject: [PATCH v9 15/16] entry: Inline syscall_exit_work()
In-Reply-To: <20251204082123.2792067-16-ruanjinjie@huawei.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
 <20251204082123.2792067-16-ruanjinjie@huawei.com>
Message-ID: <b382cc8a-3ce9-4fb1-bc0a-a3d9796251d1@arm.com>

On 04/12/2025 09:21, Jinjie Ruan wrote:
> After switch arm64 to Generic Entry, a new hotspot syscall_exit_work()
> appeared because syscall_exit_work() is no longer inlined. so inline

Before this series the call to syscall_trace_exit() in el0_svc_common()
could not be inlined, so "no longer inlined" doesn't seem to be accurate.

> syscall_exit_work(), and it has 2.6% performance uplift on perf bench
> basic syscall on kunpeng920 as below.

That seems strange. syscall_exit_work() is only called if some flag in
SYSCALL_WORK_EXIT is set, which means that we're doing something special
like tracing. That shouldn't be the case when running a simple perf
bench syscall.

Also worth nothing that its counterpart (syscall_trace_enter())) is not
currently inlined, the asymmetry would have to be justified.

>     | Metric     | W/O this patch | With this patch | Change    |
>     | ---------- | -------------- | --------------- | --------- |
>     | Total time | 2.171 [sec]    | 2.114 [sec]     |  ?2.6%    |
>     | usecs/op   | 0.217192       | 0.211453        |  ?2.6%    |
>     | ops/sec    | 4,604,225      | 4,729,178       |  ?2.7%    |
>
> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
> ---
>  include/linux/entry-common.h  | 63 ++++++++++++++++++++++++++++++++++-
>  kernel/entry/syscall-common.c | 59 ++------------------------------

These changes are purely generic, surely all architectures using
GENERIC_ENTRY should get similar benefits (assuming LTO isn't used)?

>  2 files changed, 64 insertions(+), 58 deletions(-)
>
> diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h
> index cd6dacb2d8bf..2f84377fb016 100644
> --- a/include/linux/entry-common.h
> +++ b/include/linux/entry-common.h
> @@ -2,6 +2,7 @@
>  #ifndef __LINUX_ENTRYCOMMON_H
>  #define __LINUX_ENTRYCOMMON_H
>  
> +#include <linux/audit.h>
>  #include <linux/irq-entry-common.h>
>  #include <linux/ptrace.h>
>  #include <linux/seccomp.h>
> @@ -128,6 +129,41 @@ static __always_inline long syscall_enter_from_user_mode(struct pt_regs *regs, l
>  	return ret;
>  }
>  
> +/*
> + * If SYSCALL_EMU is set, then the only reason to report is when
> + * SINGLESTEP is set (i.e. PTRACE_SYSEMU_SINGLESTEP).  This syscall
> + * instruction has been already reported in syscall_enter_from_user_mode().
> + */
> +static __always_inline bool report_single_step(unsigned long work)
> +{
> +	if (work & SYSCALL_WORK_SYSCALL_EMU)
> +		return false;
> +
> +	return work & SYSCALL_WORK_SYSCALL_EXIT_TRAP;
> +}
> +
> +/**
> + * arch_ptrace_report_syscall_exit - Architecture specific
> + *				     ptrace_report_syscall_exit.
> + *
> + * Invoked from syscall_exit_work() to wrap ptrace_report_syscall_exit().
> + *
> + * The main purpose is to support arch-specific ptrace_report_syscall_exit
> + * implementation.
> + */
> +static __always_inline void arch_ptrace_report_syscall_exit(struct pt_regs *regs,
> +							    int step);
> +
> +#ifndef arch_ptrace_report_syscall_exit
> +static __always_inline void arch_ptrace_report_syscall_exit(struct pt_regs *regs,
> +							    int step)
> +{
> +	ptrace_report_syscall_exit(regs, step);
> +}
> +#endif

If we want syscall_exit_work() to be inline, then why would we define
this hook in syscall-common.c in patch 12? Might as well define both
hooks in entry-common.h right away and avoid some noise here.

- Kevin

> [...]


From andrea.porta at suse.com  Tue Dec  9 05:58:52 2025
From: andrea.porta at suse.com (Andrea della Porta)
Date: Tue, 9 Dec 2025 14:58:52 +0100
Subject: [RFC PATCH] arm64: broadcom: bcm2712: Rework rp1 overlay handling
In-Reply-To: <20251117211503.728354-2-robh@kernel.org>
References: <20251117211503.728354-2-robh@kernel.org>
Message-ID: <aTgrHEoxl7J8_BuU@apocalypse>

Hi Rob,
sorry for the delay...

On 15:15 Mon 17 Nov     , Rob Herring (Arm) wrote:
> It's a requirement that DT overlays be applied at build time in order to
> validate them as overlays are not validated on their own.
> 
> Simply adding a build time target is possible, but it's also not desirable
> to have targets which include the overlay contents and apply the same
> overlay.
> 
> Rework the targets such that there are 2 overlays: the existing RP1 overlay
> and the board specific configuration of the RP1 (bcm2712-rpi-5-b.dtso).
> 
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> ---
> The missing applying of rp1.dtbo will soon be a warning[1].
> 
> The comment in bcm2712-rpi-5-b.dts(o) needs updating or removing. The RP1
> driver or userspace handling of the overlay probably needs updating to
> handle the 2 overlays. IIRC, I think we can apply overlays to overlays
> which may be useful here. If not, adding that to the tools should be
> possible.
> 
> [1] https://lore.kernel.org/all/20251114222759.4181152-1-robh at kernel.org/
> ---
>  arch/arm64/boot/dts/broadcom/Makefile                 | 10 ++++++++--
>  ...m2712-d-rpi-5-b.dts => bcm2712-d-rpi-5-b-base.dts} |  2 +-
>  .../{bcm2712-rpi-5-b.dts => bcm2712-rpi-5-b.dtso}     | 11 +++++------
>  3 files changed, 14 insertions(+), 9 deletions(-)
>  rename arch/arm64/boot/dts/broadcom/{bcm2712-d-rpi-5-b.dts => bcm2712-d-rpi-5-b-base.dts} (95%)
>  rename arch/arm64/boot/dts/broadcom/{bcm2712-rpi-5-b.dts => bcm2712-rpi-5-b.dtso} (92%)
> 
> diff --git a/arch/arm64/boot/dts/broadcom/Makefile b/arch/arm64/boot/dts/broadcom/Makefile
> index 83d45afc6588..4957edec9d9f 100644
> --- a/arch/arm64/boot/dts/broadcom/Makefile
> +++ b/arch/arm64/boot/dts/broadcom/Makefile
> @@ -6,9 +6,9 @@ DTC_FLAGS := -@
>  dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-400.dtb \
>  			      bcm2711-rpi-4-b.dtb \
>  			      bcm2711-rpi-cm4-io.dtb \
> -			      bcm2712-rpi-5-b.dtb \
> +			      bcm2712-rpi-5-b.dtbo \
>  			      bcm2712-rpi-5-b-ovl-rp1.dtb \
> -			      bcm2712-d-rpi-5-b.dtb \
> +			      bcm2712-d-rpi-5-b-base.dtb \
>  			      bcm2837-rpi-2-b.dtb \
>  			      bcm2837-rpi-3-a-plus.dtb \
>  			      bcm2837-rpi-3-b.dtb \
> @@ -17,6 +17,12 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-400.dtb \
>  			      bcm2837-rpi-zero-2-w.dtb \
>  			      rp1.dtbo
>  
> +bcm2712-rpi-5-b-dtbs := bcm2712-rpi-5-b-ovl-rp1.dtb rp1.dtbo bcm2712-rpi-5-b.dtbo
> +dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-5-b.dtb
> +
> +bcm2712-d-rpi-5-b-dtbs := bcm2712-d-rpi-5-b-base.dtb rp1.dtbo bcm2712-rpi-5-b.dtbo
> +dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-d-rpi-5-b.dtb
> +
>  subdir-y	+= bcmbca
>  subdir-y	+= northstar2
>  subdir-y	+= stingray
> diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-d-rpi-5-b.dts b/arch/arm64/boot/dts/broadcom/bcm2712-d-rpi-5-b-base.dts
> similarity index 95%
> rename from arch/arm64/boot/dts/broadcom/bcm2712-d-rpi-5-b.dts
> rename to arch/arm64/boot/dts/broadcom/bcm2712-d-rpi-5-b-base.dts
> index 7de24d60bcd1..48a0ae118839 100644
> --- a/arch/arm64/boot/dts/broadcom/bcm2712-d-rpi-5-b.dts
> +++ b/arch/arm64/boot/dts/broadcom/bcm2712-d-rpi-5-b-base.dts
> @@ -1,7 +1,7 @@
>  // SPDX-License-Identifier: (GPL-2.0 OR MIT)
>  /dts-v1/;
>  
> -#include "bcm2712-rpi-5-b.dts"
> +#include "bcm2712-rpi-5-b-ovl-rp1.dts"
>  
>  &gio_aon {
>  	brcm,gpio-bank-widths = <15 6>;
> diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dtso
> similarity index 92%
> rename from arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
> rename to arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dtso
> index b8f256545022..89d099c00035 100644
> --- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
> +++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dtso
> @@ -15,19 +15,18 @@
>   */
>  
>  /dts-v1/;
> +/plugin/;
>  
> -#include "bcm2712-rpi-5-b-ovl-rp1.dts"
> -
> -&pcie2 {
> -	#include "rp1-nexus.dtsi"
> -};
> +#include <dt-bindings/gpio/gpio.h>

Sounds reasonable to me, please let me have a full round of tests to check for
any issue with the driver and I'll come back with feedback.

>  
>  &rp1_eth {
>  	status = "okay";
>  	phy-mode = "rgmii-id";
>  	phy-handle = <&phy1>;
> +        #address-cells = <1>;
> +        #size-cells = <0>;

I think this should go in a separate patch.

>  
> -	mdio {
> +	mdio at 1 {

Ditto.

Many thanks,
Andrea

>  		reg = <0x1>;
>  		reset-gpios = <&rp1_gpio 32 GPIO_ACTIVE_LOW>;
>  		reset-delay-us = <5000>;
> -- 
> 2.51.0
> 


From leo.yan at arm.com  Tue Dec  9 05:59:07 2025
From: leo.yan at arm.com (Leo Yan)
Date: Tue, 9 Dec 2025 13:59:07 +0000
Subject: [PATCH v6 2/2] coresight: cti: Add Qualcomm extended CTI support
In-Reply-To: <CAJ9a7Vg9Efi-5eecfiUF82_Qq8Jg9imN5q1-VKYZoPVUxNpjhA@mail.gmail.com>
References: <20251202-extended_cti-v6-0-ab68bb15c4f5@oss.qualcomm.com>
 <20251202-extended_cti-v6-2-ab68bb15c4f5@oss.qualcomm.com>
 <20251203182944.GG724103@e132581.arm.com>
 <CAJ9a7VjWDBEwdmMf53geACBWGusC8BC3pJuOLETeecw24+N35Q@mail.gmail.com>
 <20251204103151.GK724103@e132581.arm.com>
 <CAJ9a7VjHHkkTz9XJqjdQ+11_XX9zXuY0ZcQzPtq=Zvi4CN__0A@mail.gmail.com>
 <20251205100432.GO724103@e132581.arm.com>
 <CAJ9a7Vg9Efi-5eecfiUF82_Qq8Jg9imN5q1-VKYZoPVUxNpjhA@mail.gmail.com>
Message-ID: <20251209135907.GU724103@e132581.arm.com>

Hi Mike,

On Mon, Dec 08, 2025 at 02:47:21PM +0000, Mike Leach wrote:

[...]

> > I tested locally and did not see the GCC complaint for this approach.
> > And this is a global structure with about 16KiB (~4K items x
> 
> Which is precisely the issue - why use 16k bytes of space when a pair
> of indexed tables will use 21 x 32bit locations per table -> 168 bytes
> - 100x smaller!
> 
> This space matters little to high end server systems but is much more
> important in smaller embedded systems.

For the concern of performance and footprint, my approach can
avoid any conversion for standard registers, we end up need to
convert registers for non-standard registers anyway.

I understand your concern for using an array for conversion, this is
cost 16KiB memory but this can benefit a bit performance.  It is a
trade-off between memory and speed.  As said, we can use a static
function for register conversion, the side effect is this might cause
more time.

Given the CTI MMIO register access, I don't think an extra branch
instruction (checking the flag) would cause significant panelty,
given the flag is set once at init and never changed afterwards.

> Moreover the table + inline helper is more efficient at extracting the
> correct offset value. The helper is a simple de-reference - whereas
> the helper functions you suggest require the code to make the
> comparison at every register access.
> The "if qcom ..." may be contained in one place in the source code,
> but is called and executed for every access.
> 
> Why add inefficiencies, either in footprint or execution?

This is about how we design a driver that supports both a standard IP
and non-standard implementations.

Because the standard IP is well defined, its register layout should be
the default; it keeps the code simple and makes future CTI extensions
easier.  For non-standard IPs, we only apply the register translations
needed.

TBH, the optimization topic is a bit over design for me now.  The CTI
module is configured once and remains untouched until it is disabled,
so it is not a hot path.

Thanks,
Leo


From daniel.baluta at nxp.com  Tue Dec  9 06:04:25 2025
From: daniel.baluta at nxp.com (Daniel Baluta)
Date: Tue,  9 Dec 2025 16:04:25 +0200
Subject: [RFC PATCH] remoteproc: imx_dsp_rproc: Fix multiple start/stop commands
Message-ID: <20251209140425.766742-1-daniel.baluta@nxp.com>

After commit 67a7bc7f0358 ("remoteproc: Use of reserved_mem_region_*
functions for "memory-region"") following commands with
imx-dsp-rproc started to fail:

$ echo zephyr.elf > /sys/class/remoteproc/remoteproc0/firmware
$ echo start > /sys/class/remoteproc/remoteproc0/state
$ echo stop > /sys/class/remoteproc/remoteproc0/state
$ echo start > /sys/class/remoteproc/remoteproc0/state #! This fails
-sh: echo: write error: Device or resource busy

This happens because aforementioned commit replaced devm_ioremap_wc with
devm_ioremap_resource_wc which will "reserve" the memory region with the
first start and then will fail at the second start if the memory
region is already reserved.

So prefer using devm_ioremap_wc as there is no easy way to undo
devm_iormep_resource_wc manually.

Fixes: 67a7bc7f0358 ("remoteproc: Use of_reserved_mem_region_* functions for "memory-region"")
Signed-off-by: Daniel Baluta <daniel.baluta at nxp.com>
---
 drivers/remoteproc/imx_dsp_rproc.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c
index 5130a35214c9..79d5c15319f3 100644
--- a/drivers/remoteproc/imx_dsp_rproc.c
+++ b/drivers/remoteproc/imx_dsp_rproc.c
@@ -709,10 +709,10 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv)
 		if (imx_dsp_rproc_sys_to_da(priv, res.start, resource_size(&res), &da))
 			return -EINVAL;
 
-		cpu_addr = devm_ioremap_resource_wc(dev, &res);
-		if (IS_ERR(cpu_addr)) {
+		cpu_addr = devm_ioremap_wc(dev, res.start, resource_size(&res));
+		if (!cpu_addr) {
 			dev_err(dev, "failed to map memory %pR\n", &res);
-			return PTR_ERR(cpu_addr);
+			return -ENOMEM;
 		}
 
 		/* Register memory region */
-- 
2.45.2



From daniel.baluta at gmail.com  Tue Dec  9 06:09:30 2025
From: daniel.baluta at gmail.com (Daniel Baluta)
Date: Tue, 9 Dec 2025 16:09:30 +0200
Subject: [PATCH v2 1/3] remoteproc: imx_dsp_rproc: Skip
 RP_MBOX_SUSPEND_SYSTEM when mailbox TX channel is uninitialized
In-Reply-To: <20251204122825.756106-1-iuliana.prodan@oss.nxp.com>
References: <20251204122825.756106-1-iuliana.prodan@oss.nxp.com>
Message-ID: <CAEnQRZCPX-enWtWYXM1KD95=bTD5-i46L2Bej7gXP+mggCUwPw@mail.gmail.com>

On Thu, Dec 4, 2025 at 2:29?PM Iuliana Prodan (OSS)
<iuliana.prodan at oss.nxp.com> wrote:
>
> From: Iuliana Prodan <iuliana.prodan at nxp.com>
>
> Firmwares that do not use mailbox communication (e.g., the hello_world
> sample) leave priv->tx_ch as NULL. The current suspend logic
> unconditionally sends RP_MBOX_SUSPEND_SYSTEM, which is invalid without
> an initialized TX channel.
>
> Detect the no_mailboxes case early and skip sending the suspend
> message. Instead, proceed directly to the runtime PM suspend path,
> which is the correct behavior for firmwares that cannot respond to
> mailbox requests.
>
> Signed-off-by: Iuliana Prodan <iuliana.prodan at nxp.com>

Reviewed-by: Daniel Baluta <daniel.baluta at nxp.com>


From daniel.baluta at gmail.com  Tue Dec  9 06:10:13 2025
From: daniel.baluta at gmail.com (Daniel Baluta)
Date: Tue, 9 Dec 2025 16:10:13 +0200
Subject: [PATCH v2 2/3] remoteproc: imx_dsp_rproc: Rename macro to reflect
 multiple contexts
In-Reply-To: <20251204122825.756106-2-iuliana.prodan@oss.nxp.com>
References: <20251204122825.756106-1-iuliana.prodan@oss.nxp.com> <20251204122825.756106-2-iuliana.prodan@oss.nxp.com>
Message-ID: <CAEnQRZAWAJ03u9LP33MXizJB6Rso+nL2FvRSKZE0Hx4o9ak+Uw@mail.gmail.com>

On Thu, Dec 4, 2025 at 2:29?PM Iuliana Prodan (OSS)
<iuliana.prodan at oss.nxp.com> wrote:
>
> From: Iuliana Prodan <iuliana.prodan at nxp.com>
>
> Rename WAIT_FW_READY to WAIT_FW_CONFIRMATION and FEATURE_DONT_WAIT_FW_READY
> to FEATURE_SKIP_FW_CONFIRMATION. This way, the term CONFIRMATION covers:
> - waiting for firmware to confirm it is ready to start;
> - waiting for any other confirmation from firmware.
>
> Signed-off-by: Iuliana Prodan <iuliana.prodan at nxp.com>

Reviewed-by: Daniel Baluta <daniel.baluta at nxp.com>


From daniel.baluta at gmail.com  Tue Dec  9 06:11:19 2025
From: daniel.baluta at gmail.com (Daniel Baluta)
Date: Tue, 9 Dec 2025 16:11:19 +0200
Subject: [PATCH v2 3/3] remoteproc: imx_dsp_rproc: Wait for suspend ACK
 only if WAIT_FW_CONFIRMATION is set
In-Reply-To: <20251204122825.756106-3-iuliana.prodan@oss.nxp.com>
References: <20251204122825.756106-1-iuliana.prodan@oss.nxp.com> <20251204122825.756106-3-iuliana.prodan@oss.nxp.com>
Message-ID: <CAEnQRZDw-jwpXdb3oi+-DZ+YD4aQfyON0gPNrGpox1v7m4Voig@mail.gmail.com>

On Thu, Dec 4, 2025 at 2:29?PM Iuliana Prodan (OSS)
<iuliana.prodan at oss.nxp.com> wrote:
>
> From: Iuliana Prodan <iuliana.prodan at nxp.com>
>
> The DSP suspend path currently waits unconditionally for a suspend ack
> from the firmware. This breaks firmwares that do not implement the
> mailbox-based CONFIRMATION handshake, as the DSP never responds and
> system suspend fails with -EBUSY.
>
> The driver already uses the WAIT_FW_CONFIRMATION flag to indicate that
> the firmware supports the CONFIRMATION handshake at boot. Apply the same
> logic during suspend: only send the suspend message and wait for the
> suspend ack when the firmware is expected to support it.
>
> Signed-off-by: Iuliana Prodan <iuliana.prodan at nxp.com>

Reviewed-by: Daniel Baluta <daniel.baluta at nxp.com>


From mripard at kernel.org  Tue Dec  9 06:11:19 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Tue, 9 Dec 2025 15:11:19 +0100
Subject: [PATCH v5 02/17] drm: Add new general DRM property "color format"
In-Reply-To: <20251128-color-format-v5-2-63e82f1db1e1@collabora.com>
References: <20251128-color-format-v5-0-63e82f1db1e1@collabora.com>
 <20251128-color-format-v5-2-63e82f1db1e1@collabora.com>
Message-ID: <20251209-gifted-coyote-of-endurance-b81bf5@houat>

Hi,

On Fri, Nov 28, 2025 at 10:05:38PM +0100, Nicolas Frattaroli wrote:
> From: Andri Yngvason <andri at yngvason.is>
> 
> Add a new general DRM property named "color format" which can be used by
> userspace to request the display driver to output a particular color
> format.
> 
> Possible options are:
>     - auto (setup by default, driver internally picks the color format)

I'm not entirely sure that's how we should document it. i915, amdgpu,
and every driver using the hdmi helpers uses the same algorithm: first
try with RGB, then fallback to YUV420 if it doesn't work.

I think we should document that, and every driver exposing this property
should behave that way. It's going to be a mess otherwise.

Maxime
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 273 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251209/2b6365fa/attachment.sig>

From mripard at kernel.org  Tue Dec  9 06:12:44 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Tue, 09 Dec 2025 14:12:44 +0000
Subject: [PATCH v5 03/17] drm: Add enum conversion from DRM_COLOR_FORMAT
 to HDMI_COLORSPACE
In-Reply-To: <20251128-color-format-v5-3-63e82f1db1e1@collabora.com>
References: <20251128-color-format-v5-3-63e82f1db1e1@collabora.com>
Message-ID: <6736385e287d063e19c8301550edcd17@kernel.org>

On Fri, 28 Nov 2025 22:05:39 +0100, Nicolas Frattaroli wrote:
> From: Marius Vlad <marius.vlad at collabora.com>
> 
> While the two enums have similar values, they're not identical, and
> HDMI's enum is defined as per the HDMI standard.
> 
> 
> [ ... ]

Reviewed-by: Maxime Ripard <mripard at kernel.org>

Thanks!
Maxime


From mripard at kernel.org  Tue Dec  9 06:16:58 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Tue, 9 Dec 2025 15:16:58 +0100
Subject: [PATCH v5 05/17] drm/display: hdmi-state-helper: Act on color
 format DRM property
In-Reply-To: <20251128-color-format-v5-5-63e82f1db1e1@collabora.com>
References: <20251128-color-format-v5-0-63e82f1db1e1@collabora.com>
 <20251128-color-format-v5-5-63e82f1db1e1@collabora.com>
Message-ID: <20251209-uptight-radical-chupacabra-ac3d6d@houat>

On Fri, Nov 28, 2025 at 10:05:41PM +0100, Nicolas Frattaroli wrote:
> With the introduction of the "color format" DRM property, which allows
> userspace to request a specific color format, the HDMI state helper
> should implement this.
> 
> Implement it by checking whether the property is set and set to
> something other than auto. If so, pass the requested color format, and
> otherwise set RGB.
> 
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
> ---
>  drivers/gpu/drm/display/drm_hdmi_state_helper.c | 12 +++++++++++-
>  1 file changed, 11 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> index a561f124be99..5da956bdd68c 100644
> --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> @@ -649,11 +649,21 @@ hdmi_compute_config(const struct drm_connector *connector,
>  	unsigned int max_bpc = clamp_t(unsigned int,
>  				       conn_state->max_bpc,
>  				       8, connector->max_bpc);
> +	enum hdmi_colorspace hdmi_colorspace =
> +		drm_color_format_to_hdmi_colorspace(conn_state->color_format);
>  	int ret;
>  
>  	ret = hdmi_compute_format_bpc(connector, conn_state, mode, max_bpc,
> -				      HDMI_COLORSPACE_RGB);
> +				      hdmi_colorspace);
>  	if (ret) {
> +		/* If a color format was explicitly requested, don't fall back */
> +		if (conn_state->color_format) {
> +			drm_dbg_kms(connector->dev,
> +				    "Explicitly set color format '%s' doesn't work.\n",
> +				    drm_get_color_format_name(conn_state->color_format));
> +			return ret;
> +		}
> +

I think the following would be more readable:


if (conn_state->color_format && conn_state->color_format != DRM_COLOR_FORMAT_AUTO) {
    enum hdmi_colorspace hdmi_colorspace =
        drm_color_format_to_hdmi_colorspace(conn_state->color_format);

    return hdmi_compute_format_bpc(connector, conn_state, mode, max_bpc, hdmi_colorspace)
}

ret = ret = hdmi_compute_format_bpc(connector, conn_state, mode, max_bpc,
                                    HDMI_COLORSPACE_RGB);

...

Maxime
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 273 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251209/066886a5/attachment.sig>

From daniel.baluta at gmail.com  Tue Dec  9 06:20:03 2025
From: daniel.baluta at gmail.com (Daniel Baluta)
Date: Tue, 9 Dec 2025 16:20:03 +0200
Subject: [PATCH v7 2/2] remoteproc: qcom: Use of_reserved_mem_region_*
 functions for "memory-region"
In-Reply-To: <CAL_JsqJTrGAJx-fv8OQGDhsLVKavQzzQotssEq_E5f_aJe8bOg@mail.gmail.com>
References: <20251124182751.507624-1-robh@kernel.org> <CGME20251127142839eucas1p186846c6c1ea1d9e43369fbba9bb5d17c@eucas1p1.samsung.com>
 <20251124182751.507624-2-robh@kernel.org> <674efe8d-c299-4ce9-bf6b-c1920a5393eb@samsung.com>
 <CAL_JsqJTrGAJx-fv8OQGDhsLVKavQzzQotssEq_E5f_aJe8bOg@mail.gmail.com>
Message-ID: <CAEnQRZDBZ52FoNRBJa1qScbkcEYKwbyP_ephutdkYFaY5b1yLw@mail.gmail.com>

> Other platforms (non-QCom) were tested also use
> devm_ioremap_resource_wc(). So something else is claiming the same
> region? Can you dump out /proc/iomem?
>
> The region is dynamically allocated, so maybe that has something to do with it.

We noticed a related issue with imx_dsp_rproc.

Because:
imx_dsp_rproc_prepare:
 -> imx_dsp_rproc_add_carveout
     -> /*... */ and this calls devm_ioremap_resource_wc
-> pm_runtime_get_sync

imx_dsp_rproc_unprepare:
 ->pm_runtime_put_sync

There is no easy way to manually undo devm_ioremap_resource_wc so I have
sent a patch to use devm_ioremap_wc.

https://lore.kernel.org/imx/20251209140425.766742-1-daniel.baluta at nxp.com/T/#u

In your case Marek at least you need to understand which driver
reserves    8dc00000-8e7fffff : reserved and why.

thanks,
Daniel.


From mripard at kernel.org  Tue Dec  9 06:18:25 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Tue, 9 Dec 2025 15:18:25 +0100
Subject: [PATCH v5 06/17] drm/display: hdmi-state-helper: Try subsampling
 in mode_valid
In-Reply-To: <20251128-color-format-v5-6-63e82f1db1e1@collabora.com>
References: <20251128-color-format-v5-0-63e82f1db1e1@collabora.com>
 <20251128-color-format-v5-6-63e82f1db1e1@collabora.com>
Message-ID: <20251209-dramatic-caiman-of-luck-db9d0f@houat>

On Fri, Nov 28, 2025 at 10:05:42PM +0100, Nicolas Frattaroli wrote:
> drm_hdmi_connector_mode_valid assumes modes are only valid if they work
> with RGB. The reality is more complex however: YCbCr 4:2:0
> chroma-subsampled modes only require half the pixel clock that the same
> mode would require in RGB.
> 
> This leads to drm_hdmi_connector_mode_valid rejecting perfectly valid
> 420-only modes.
> 
> Fix this by checking whether the mode is 420-only first. If so, then
> proceed by checking it with HDMI_COLORSPACE_YUV420 so long as the
> connector has legalized 420, otherwise error out. If the mode is not
> 420-only, check with RGB as was previously always the case.
> 
> Fixes: 47368ab437fd ("drm/display: hdmi: add generic mode_valid helper")
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
> ---
>  drivers/gpu/drm/display/drm_hdmi_state_helper.c | 12 +++++++++++-
>  1 file changed, 11 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> index 5da956bdd68c..1800e00b30c5 100644
> --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> @@ -892,8 +892,18 @@ drm_hdmi_connector_mode_valid(struct drm_connector *connector,
>  			      const struct drm_display_mode *mode)
>  {
>  	unsigned long long clock;
> +	enum hdmi_colorspace fmt;
> +
> +	if (drm_mode_is_420_only(&connector->display_info, mode)) {
> +		if (connector->ycbcr_420_allowed)
> +			fmt = HDMI_COLORSPACE_YUV420;
> +		else
> +			return MODE_NO_420;
> +	} else {
> +		fmt = HDMI_COLORSPACE_RGB;
> +	}
>  
> -	clock = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_RGB);
> +	clock = drm_hdmi_compute_mode_clock(mode, 8, fmt);

I agree on principle, but we need to have a test for this.

Maxime
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 273 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251209/f738dbd6/attachment.sig>

From mripard at kernel.org  Tue Dec  9 06:22:29 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Tue, 09 Dec 2025 14:22:29 +0000
Subject: [PATCH v5 16/17] drm/connector: Register color format property
 on HDMI connectors
In-Reply-To: <20251128-color-format-v5-16-63e82f1db1e1@collabora.com>
References: <20251128-color-format-v5-16-63e82f1db1e1@collabora.com>
Message-ID: <8d3b7bce998e1e48c752abbdabf50593@kernel.org>

On Fri, 28 Nov 2025 22:05:52 +0100, Nicolas Frattaroli wrote:
> The drmm_connector_hdmi_init function can figure out what DRM color
> formats are supported by a particular connector based on the supported
> HDMI format bitmask that's passed in.
> 
> Use it to register the drm color format property.
> 
> [ ... ]

Reviewed-by: Maxime Ripard <mripard at kernel.org>

Thanks!
Maxime


From leo.yan at arm.com  Tue Dec  9 06:24:38 2025
From: leo.yan at arm.com (Leo Yan)
Date: Tue, 9 Dec 2025 14:24:38 +0000
Subject: [PATCH v6 2/2] coresight: cti: Add Qualcomm extended CTI support
In-Reply-To: <1fbe140c-b960-4f13-83e2-b0a0733a67bc@quicinc.com>
References: <CAJ9a7Vg9Efi-5eecfiUF82_Qq8Jg9imN5q1-VKYZoPVUxNpjhA@mail.gmail.com>
 <20251209081649.105623-1-yingchao.deng@oss.qualcomm.com>
 <20251209121916.GT724103@e132581.arm.com>
 <1fbe140c-b960-4f13-83e2-b0a0733a67bc@quicinc.com>
Message-ID: <20251209142438.GV724103@e132581.arm.com>

On Tue, Dec 09, 2025 at 08:51:38PM +0800, Yingchao Deng (Consultant) wrote:

[...]

> >    void cti_write_single_reg(struct cti_drvdata *drvdata,
> >                              int offset, u32 value)
> >    {
> >            CS_UNLOCK(drvdata->base);
> >            writel_relaxed(value, cti_reg_addr(drvdata, offset));
> >            CS_LOCK(drvdata->base);
> >    }
> 
> However, since we also need to handle cti_reg_addr_with_nr, it will be
> necessary to add an additional parameter "nr" to cti_write_single_reg?

I expect the argument "offset" has already containted the nr in
bits[31..28], so don't need to pass "nr" parameter to
cti_write_single_reg().

You will change inen_store() / outen_store(), e.g.,:

    cti_write_single_reg(drvdata, CTI_REG_SET_NR(CTIINEN, index),
                         value);

Just remind, this might be a separate refactor for common code and you
need to write a patch for this, then is followed by QCOM CTI support
patch.

Thanks,
Leo


From mripard at kernel.org  Tue Dec  9 06:27:28 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Tue, 9 Dec 2025 15:27:28 +0100
Subject: [PATCH v5 04/17] drm/bridge: Act on the DRM color format property
In-Reply-To: <20251128-color-format-v5-4-63e82f1db1e1@collabora.com>
References: <20251128-color-format-v5-0-63e82f1db1e1@collabora.com>
 <20251128-color-format-v5-4-63e82f1db1e1@collabora.com>
Message-ID: <20251209-smart-oarfish-of-wind-0c1c8b@houat>

Hi,

On Fri, Nov 28, 2025 at 10:05:40PM +0100, Nicolas Frattaroli wrote:
> The new DRM color format property allows userspace to request a specific
> color format on a connector. In turn, this fills the connector state's
> color_format member to switch color formats.
> 
> Make drm_bridges consider the color_format set in the connector state
> during the atomic bridge check. Specifically, reject any output bus
> formats that do not correspond to the requested color format.
> 
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
> ---
>  drivers/gpu/drm/drm_bridge.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 45 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index 8f355df883d8..8aac9747f35e 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -1052,6 +1052,47 @@ static int select_bus_fmt_recursive(struct drm_bridge *first_bridge,
>  	return ret;
>  }
>  
> +static bool __pure bus_format_is_color_fmt(u32 bus_fmt, enum drm_color_format fmt)
> +{
> +	if (fmt == DRM_COLOR_FORMAT_AUTO)
> +		return true;
> +
> +	switch (bus_fmt) {
> +	case MEDIA_BUS_FMT_FIXED:
> +		return true;
> +	case MEDIA_BUS_FMT_RGB888_1X24:
> +	case MEDIA_BUS_FMT_RGB101010_1X30:
> +	case MEDIA_BUS_FMT_RGB121212_1X36:
> +	case MEDIA_BUS_FMT_RGB161616_1X48:
> +		return fmt == DRM_COLOR_FORMAT_RGB444;
> +	case MEDIA_BUS_FMT_YUV8_1X24:
> +	case MEDIA_BUS_FMT_YUV10_1X30:
> +	case MEDIA_BUS_FMT_YUV12_1X36:
> +	case MEDIA_BUS_FMT_YUV16_1X48:
> +		return fmt == DRM_COLOR_FORMAT_YCBCR444;
> +	case MEDIA_BUS_FMT_UYVY8_1X16:
> +	case MEDIA_BUS_FMT_VYUY8_1X16:
> +	case MEDIA_BUS_FMT_YUYV8_1X16:
> +	case MEDIA_BUS_FMT_YVYU8_1X16:
> +	case MEDIA_BUS_FMT_UYVY10_1X20:
> +	case MEDIA_BUS_FMT_YUYV10_1X20:
> +	case MEDIA_BUS_FMT_VYUY10_1X20:
> +	case MEDIA_BUS_FMT_YVYU10_1X20:
> +	case MEDIA_BUS_FMT_UYVY12_1X24:
> +	case MEDIA_BUS_FMT_VYUY12_1X24:
> +	case MEDIA_BUS_FMT_YUYV12_1X24:
> +	case MEDIA_BUS_FMT_YVYU12_1X24:
> +		return fmt == DRM_COLOR_FORMAT_YCBCR422;
> +	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
> +	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
> +	case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
> +	case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
> +		return fmt == DRM_COLOR_FORMAT_YCBCR420;
> +	default:
> +		return false;
> +	}
> +}
> +
>  /*
>   * This function is called by &drm_atomic_bridge_chain_check() just before
>   * calling &drm_bridge_funcs.atomic_check() on all elements of the chain.
> @@ -1137,6 +1178,10 @@ drm_atomic_bridge_chain_select_bus_fmts(struct drm_bridge *bridge,
>  	}
>  
>  	for (i = 0; i < num_out_bus_fmts; i++) {
> +		if (!bus_format_is_color_fmt(out_bus_fmts[i], conn_state->color_format)) {
> +			ret = -ENOTSUPP;
> +			continue;
> +		}

Sorry, I'm struggling a bit to understand how this would work if a bridge both supports the bus
format selection and HDMI state helpers? Can you expand on it?

Maxime
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 273 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251209/4f87cbd8/attachment.sig>

From ben.horgan at arm.com  Tue Dec  9 06:40:28 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Tue, 9 Dec 2025 14:40:28 +0000
Subject: [RFC PATCH 00/38] arm_mpam: Add KVM/arm64 and resctrl glue code
In-Reply-To: <20251205215901.17772-1-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
Message-ID: <41bcd0d2-d5b8-4f3d-b0b3-132387f547ed@arm.com>

Hi James and all,

As James is otherwise occupied, I am planning to post a follow up
version of this series once it's had time to be reviewed. I will be
posting my own review comments; please give them extra scrutiny.

On 12/5/25 21:58, James Morse wrote:
> This is the missing piece to make MPAM usable resctrl in user-space. This has
> shed its debugfs code and the read/write 'event configuration' for the monitors
> to make the series smaller.
> 
[...]
> 
> This series is based on arm64/for-next/core, and can be retrieved from:
> https://git.kernel.org/pub/scm/linux/kernel/git/morse/linux.git mpam/glue/rfc
> 
> There is no snapshot branch - this is it!
> I'll push the extras branch once I've gotten a handle on the DT shaped mess in
> there.

One major departure from the previous snapshot branches referenced in
the base driver series is that the same MPAM setting are used for
kernel-space and user-space. That is, MPAM1_EL1 is set to the same value
as MPAM0_EL1 rather than keeping the default value. The advantages of
this are that it is closer to the x86 model where the closid is globally
applicable, all partids are usable from user-space and user-space can't
bypass MPAM controls by doing the work in the kernel. However, this
causes some priority inversion where a high priority task waits to take
a mutex held by another whose resources are restricted by MPAM.
Thanks,

Ben



From ben.horgan at arm.com  Tue Dec  9 06:49:01 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Tue, 9 Dec 2025 14:49:01 +0000
Subject: [RFC PATCH 01/38] arm64: mpam: Context switch the MPAM registers
In-Reply-To: <20251205215901.17772-2-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-2-james.morse@arm.com>
Message-ID: <b1cb5da6-3e08-44b7-9d4d-cef34be15df4@arm.com>

Hi James,

On 12/5/25 21:58, James Morse wrote:
> MPAM allows traffic in the SoC to be labeled by the OS, these labels
> are used to apply policy in caches and bandwidth regulators, and to
> monitor traffic in the SoC. The label is made up of a PARTID and PMG
> value. The x86 equivalent calls these CLOSID and RMID, but they don't
> map precisely.
> 
[...]
> 
> All this should depend on whether there is an MPAM driver, hide
> it behind CONFIG_MPAM.

CONFIG_MPAM -> CONFIG_ARM64_MPAM

> 
> CC: Amit Singh Tomar <amitsinght at marvell.com>
> Signed-off-by: James Morse <james.morse at arm.com>
> ---
>  arch/arm64/Kconfig                   |  2 +
>  arch/arm64/include/asm/mpam.h        | 74 ++++++++++++++++++++++++++++
>  arch/arm64/include/asm/thread_info.h |  3 ++
>  arch/arm64/kernel/Makefile           |  1 +
>  arch/arm64/kernel/mpam.c             | 13 +++++
>  arch/arm64/kernel/process.c          |  7 +++
>  drivers/resctrl/mpam_devices.c       |  2 -
>  drivers/resctrl/mpam_internal.h      |  2 +
>  8 files changed, 102 insertions(+), 2 deletions(-)
>  create mode 100644 arch/arm64/include/asm/mpam.h
>  create mode 100644 arch/arm64/kernel/mpam.c
> 
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 004d58cfbff8..558baa9e7c08 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -2048,6 +2048,8 @@ config ARM64_MPAM
>  
>  	  MPAM is exposed to user-space via the resctrl pseudo filesystem.
>  
> +	  This option enables the extra context switch code.
> +
>  endmenu # "ARMv8.4 architectural features"
>  
>  menu "ARMv8.5 architectural features"
> diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/mpam.h
> new file mode 100644
> index 000000000000..86a55176f884
> --- /dev/null
> +++ b/arch/arm64/include/asm/mpam.h
> @@ -0,0 +1,74 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2025 Arm Ltd. */
> +
> +#ifndef __ASM__MPAM_H
> +#define __ASM__MPAM_H
> +
> +#include <linux/bitops.h>
> +#include <linux/init.h>
> +#include <linux/jump_label.h>
> +#include <linux/percpu.h>
> +#include <linux/sched.h>
> +
> +#include <asm/cpucaps.h>
> +#include <asm/cpufeature.h>
> +#include <asm/sysreg.h>
> +
> +DECLARE_STATIC_KEY_FALSE(mpam_enabled);
> +DECLARE_PER_CPU(u64, arm64_mpam_default);
> +DECLARE_PER_CPU(u64, arm64_mpam_current);
> +
> +/*
> + * The value of the MPAM0_EL1 sysreg when a task is in resctrl's default group.
> + * This is used by the context switch code to use the resctrl CPU property
> + * instead. The value is modified when CDP is enabled/disabled by mounting
> + * the resctrl filesystem.
> + */
> +extern u64 arm64_mpam_global_default;
> +
> +/*
> + * The resctrl filesystem writes to the partid/pmg values for threads and CPUs,
> + * which may race with reads in __mpam_sched_in(). Ensure only one of the old
> + * or new values are used. Particular care should be taken with the pmg field
> + * as __mpam_sched_in() may read a partid and pmg that don't match, causing
> + * this value to be stored with cache allocations, despite being considered
> + * 'free' by resctrl.

__mpam_sched_in() -> mpam_thread_switch()
This is called from resctrl_arch_sched_in().

> + *
> + * A value in struct thread_info is used instead of struct task_struct as the
> + * cpu's u64 register format is used, but struct task_struct has two u32'.
> + */
> +static inline u64 mpam_get_regval(struct task_struct *tsk)
> +{
> +#ifdef CONFIG_ARM64_MPAM
> +	return READ_ONCE(task_thread_info(tsk)->mpam_partid_pmg);
> +#else
> +	return 0;
> +#endif
> +}
> +
> +static inline void mpam_thread_switch(struct task_struct *tsk)
> +{
> +	u64 oldregval;
> +	int cpu = smp_processor_id();
> +	u64 regval = mpam_get_regval(tsk);
> +
> +	if (!IS_ENABLED(CONFIG_ARM64_MPAM) ||
> +	    !static_branch_likely(&mpam_enabled))
> +		return;
> +
> +	if (regval == READ_ONCE(arm64_mpam_global_default))
> +		regval = READ_ONCE(per_cpu(arm64_mpam_default, cpu));
> +
> +	oldregval = READ_ONCE(per_cpu(arm64_mpam_current, cpu));
> +	if (oldregval == regval)
> +		return;
> +
> +	write_sysreg_s(regval, SYS_MPAM1_EL1);
> +	isb();
> +
> +	/* Synchronising the EL0 write is left until the ERET to EL0 */
> +	write_sysreg_s(regval, SYS_MPAM0_EL1);
> +
> +	WRITE_ONCE(per_cpu(arm64_mpam_current, cpu), regval);
> +}
> +#endif /* __ASM__MPAM_H */
> diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
> index f241b8601ebd..c226dabd5019 100644
> --- a/arch/arm64/include/asm/thread_info.h
> +++ b/arch/arm64/include/asm/thread_info.h
> @@ -41,6 +41,9 @@ struct thread_info {
>  #ifdef CONFIG_SHADOW_CALL_STACK
>  	void			*scs_base;
>  	void			*scs_sp;
> +#endif
> +#ifdef CONFIG_ARM64_MPAM
> +	u64			mpam_partid_pmg;
>  #end if
>  	u32			cpu;
>  };
> diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
> index 76f32e424065..15979f366519 100644
> --- a/arch/arm64/kernel/Makefile
> +++ b/arch/arm64/kernel/Makefile
> @@ -67,6 +67,7 @@ obj-$(CONFIG_CRASH_DUMP)		+= crash_dump.o
>  obj-$(CONFIG_VMCORE_INFO)		+= vmcore_info.o
>  obj-$(CONFIG_ARM_SDE_INTERFACE)		+= sdei.o
>  obj-$(CONFIG_ARM64_PTR_AUTH)		+= pointer_auth.o
> +obj-$(CONFIG_ARM64_MPAM)		+= mpam.o
>  obj-$(CONFIG_ARM64_MTE)			+= mte.o
>  obj-y					+= vdso-wrap.o
>  obj-$(CONFIG_COMPAT_VDSO)		+= vdso32-wrap.o
> diff --git a/arch/arm64/kernel/mpam.c b/arch/arm64/kernel/mpam.c
> new file mode 100644
> index 000000000000..9866d2ca0faa
> --- /dev/null
> +++ b/arch/arm64/kernel/mpam.c
> @@ -0,0 +1,13 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (C) 2025 Arm Ltd. */
> +
> +#include <asm/mpam.h>
> +
> +#include <linux/jump_label.h>
> +#include <linux/percpu.h>
> +
> +DEFINE_STATIC_KEY_FALSE(mpam_enabled);
> +DEFINE_PER_CPU(u64, arm64_mpam_default);
> +DEFINE_PER_CPU(u64, arm64_mpam_current);
> +
> +u64 arm64_mpam_global_default;
> diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
> index fba7ca102a8c..b510c0699313 100644
> --- a/arch/arm64/kernel/process.c
> +++ b/arch/arm64/kernel/process.c
> @@ -51,6 +51,7 @@
>  #include <asm/fpsimd.h>
>  #include <asm/gcs.h>
>  #include <asm/mmu_context.h>
> +#include <asm/mpam.h>
>  #include <asm/mte.h>
>  #include <asm/processor.h>
>  #include <asm/pointer_auth.h>
> @@ -737,6 +738,12 @@ struct task_struct *__switch_to(struct task_struct *prev,
>  	if (prev->thread.sctlr_user != next->thread.sctlr_user)
>  		update_sctlr_el1(next->thread.sctlr_user);
>  
> +	/*
> +	 * MPAM thread switch happens after the DSB to ensure prev's accesses
> +	 * use prev's MPAM settings.
> +	 */
> +	mpam_thread_switch(next);
> +
>  	/* the actual thread switch */
>  	last = cpu_switch_to(prev, next);
>  
> diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
> index 0b5b158e1aaf..2996ad93fc3e 100644
> --- a/drivers/resctrl/mpam_devices.c
> +++ b/drivers/resctrl/mpam_devices.c
> @@ -29,8 +29,6 @@
>  
>  #include "mpam_internal.h"
>  
> -DEFINE_STATIC_KEY_FALSE(mpam_enabled); /* This moves to arch code */
> -
>  /*
>   * mpam_list_lock protects the SRCU lists when writing. Once the
>   * mpam_enabled key is enabled these lists are read-only,
> diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
> index e79c3c47259c..4508a6654fe0 100644
> --- a/drivers/resctrl/mpam_internal.h
> +++ b/drivers/resctrl/mpam_internal.h
> @@ -17,6 +17,8 @@
>  #include <linux/srcu.h>
>  #include <linux/types.h>
>  
> +#include <asm/mpam.h>
> +
>  #define MPAM_MSC_MAX_NUM_RIS	16
>  
>  struct platform_device;

The DECLARE_STATIC_KEY_FALSE(mpam_enabled) on the next line can now be
removed.

Thanks,

Ben



From james.clark at linaro.org  Tue Dec  9 06:54:19 2025
From: james.clark at linaro.org (James Clark)
Date: Tue, 9 Dec 2025 14:54:19 +0000
Subject: [PATCH 19/19] perf: cs-etm: Set watermark for AUX trace
In-Reply-To: <c22b084b-3853-405d-8b43-397786af7be9@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-19-7da32b076b28@arm.com>
 <c22b084b-3853-405d-8b43-397786af7be9@arm.com>
Message-ID: <5ebf1743-b01c-4664-961c-9e1e2aa7ffce@linaro.org>



On 05/12/2025 4:48 am, Anshuman Khandual wrote:
> On 01/12/25 4:52 PM, Leo Yan wrote:
>> The default watermark is half of the total buffer size. In many cases,
>> the tool can not be notified with sufficient free space, especially when
>> profiling with small AUX buffer (e.g., 64KiB).
> 
> Could not smaller AUX buffer be prevented for TRBE instead ?
> 

It's not really about the size of the buffer but where the wakeup points 
are. With only two wakeup points (middle and end) once you pass the 
first one you are immediately into the last chance end section.

Now the driver is writing into the end section, but Perf is still 
reading from the first one. Once the end one fills up, you end up with 
no space left without Perf having a chance to say it's finished reading.

To guarantee free space, there needs to be at least one additional 
section as a buffer zone. Ideally we'd set the wakeup point at thirds so 
there were fewer wakeups and still have one free section, but it might 
not always divide by 3, so 4 is also fine.

The commit message could probably explain it a bit better though.

The reason this is different now is because we want to be able to enable 
wrap mode as much as possible. If you imagine the scenario where a half 
way watermark is hit, you can't enable wrap mode without wrapping into 
Perf's part of the buffer (the beginning) as it's all that's left after 
the second half.

>>> Setting watermark to quarter of the buffer to notifies the tool to read
>> data earlier and prevents the data loss.
>>
>> Signed-off-by: Leo Yan <leo.yan at arm.com>
>> ---
>>   tools/perf/arch/arm/util/cs-etm.c | 7 +++++++
>>   1 file changed, 7 insertions(+)
>>
>> diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
>> index ea891d12f8f40beebf8dee1d3db71cad701f5666..649b8b0d0f92b4af45fb97db9da3c5ccf24a978b 100644
>> --- a/tools/perf/arch/arm/util/cs-etm.c
>> +++ b/tools/perf/arch/arm/util/cs-etm.c
>> @@ -424,6 +424,13 @@ static int cs_etm_recording_options(struct auxtrace_record *itr,
>>   		pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME,
>>   			  opts->auxtrace_snapshot_size);
>>   
>> +	if (!opts->auxtrace_snapshot_mode && !opts->auxtrace_sample_mode) {
>> +		size_t aw = opts->auxtrace_mmap_pages * (size_t)page_size / 4;
>> +		u32 aux_watermark = aw > UINT_MAX ? UINT_MAX : aw;
>> +
>> +		cs_etm_evsel->core.attr.aux_watermark = aux_watermark;
>> +	}
>> +
>>   	/*
>>   	 * To obtain the auxtrace buffer file descriptor, the auxtrace
>>   	 * event must come first.
>>
> 



From ben.horgan at arm.com  Tue Dec  9 07:08:43 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Tue, 9 Dec 2025 15:08:43 +0000
Subject: [RFC PATCH 01/38] arm64: mpam: Context switch the MPAM registers
In-Reply-To: <a3305659-929d-45f6-823d-a886f197d652@nvidia.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-2-james.morse@arm.com>
 <a3305659-929d-45f6-823d-a886f197d652@nvidia.com>
Message-ID: <47b3b953-1ab9-4b85-9cb4-e1ad8eb4a0f6@arm.com>

Hi Fenghua,

On 12/5/25 23:53, Fenghua Yu wrote:
> Hi, James,
> 
> On 12/5/25 13:58, James Morse wrote:
[...]
>>
>> Resctrl allows a per-cpu 'default' value to be set, this overrides the
>> values when scheduling a task in the default control-group, which has
>> PARTID 0. The way 'code data prioritisation' gets emulated means the
>> register value for the default group needs to be a variable.
>>
[...]
>> diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/
>> mpam.h
>> new file mode 100644
>> index 000000000000..86a55176f884
>> --- /dev/null
>> +++ b/arch/arm64/include/asm/mpam.h
[...]
>> +/*
>> + * The value of the MPAM0_EL1 sysreg when a task is in resctrl's
>> default group.
>> + * This is used by the context switch code to use the resctrl CPU
>> property
>> + * instead. The value is modified when CDP is enabled/disabled by
>> mounting
>> + * the resctrl filesystem.
>> + */
>> +extern u64 arm64_mpam_global_default;
>> +
>> +/*
>> + * The resctrl filesystem writes to the partid/pmg values for threads
>> and CPUs,
>> + * which may race with reads in __mpam_sched_in(). Ensure only one of
>> the old
>> + * or new values are used. Particular care should be taken with the
>> pmg field
>> + * as __mpam_sched_in() may read a partid and pmg that don't match,
>> causing
>> + * this value to be stored with cache allocations, despite being
>> considered
>> + * 'free' by resctrl.
>> + *
>> + * A value in struct thread_info is used instead of struct
>> task_struct as the
>> + * cpu's u64 register format is used, but struct task_struct has two
>> u32'.
>> + */
>> +static inline u64 mpam_get_regval(struct task_struct *tsk)
>> +{
>> +#ifdef CONFIG_ARM64_MPAM
>> +??? return READ_ONCE(task_thread_info(tsk)->mpam_partid_pmg);
>> +#else
>> +??? return 0;
>> +#endif
>> +}
>> +
>> +static inline void mpam_thread_switch(struct task_struct *tsk)
>> +{
>> +??? u64 oldregval;
>> +??? int cpu = smp_processor_id();
>> +??? u64 regval = mpam_get_regval(tsk);
>> +
>> +??? if (!IS_ENABLED(CONFIG_ARM64_MPAM) ||
>> +??????? !static_branch_likely(&mpam_enabled))
>> +??????? return;
>> +
>> +??? if (regval == READ_ONCE(arm64_mpam_global_default))
> Why is this check needed? We need to read arm64_mpam_default in any
> case, right?

If a task is in the default resctrl group then the per-cpu resctrl
configuration determines the mpam configuration. The way this is dealt
with here is that for a task in the default group mpam_partid_pmg is set
to arm64_mpam_global_default. When mpam_partid_pmg is
arm64_mpam_global_default we know the task is in the default group,
otherwise it would have a different partid, and so we consider the
per-cpu configuration, arm64_mpam_default. When the task is not in the
default resctrl group then we can just consider the per-task configuration.

As mentioned in the commit message, this is complicated by code data
prioritisation (cdp) and the value of arm64_mpam_global_default, depends
on whether this is enabled or not. See resctrl_arch_set_cdp_enabled()
added in a later patch. I'm not sure of a way to make this clearer in
the code while keeping the arch and drivers/resctrl patches separate.

> +??????? regval = READ_ONCE(per_cpu(arm64_mpam_default,
> cpu));
>> +
>> +??? oldregval = READ_ONCE(per_cpu(arm64_mpam_current, cpu));
>> +??? if (oldregval == regval)
>> +??????? return;
>> +
>> +??? write_sysreg_s(regval, SYS_MPAM1_EL1);
>> +??? isb();
>> +
>> +??? /* Synchronising the EL0 write is left until the ERET to EL0 */
>> +??? write_sysreg_s(regval, SYS_MPAM0_EL1);
>> +
>> +??? WRITE_ONCE(per_cpu(arm64_mpam_current, cpu), regval);
>> +}
>> +#endif /* __ASM__MPAM_H */
> 
> [SNIP]
> Thanks.
> 
> -Fenghua
> 
Thanks,

Ben



From ben.horgan at arm.com  Tue Dec  9 07:13:19 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Tue, 9 Dec 2025 15:13:19 +0000
Subject: [RFC PATCH 02/38] arm64: mpam: Re-initialise MPAM regs when CPU
 comes online
In-Reply-To: <20251205215901.17772-3-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-3-james.morse@arm.com>
Message-ID: <0ea282be-c44f-4562-9104-1efe57348a3e@arm.com>

Hi James,

On 12/5/25 21:58, James Morse wrote:
> Now that the MPAM system registers are expected to have values that change,
> reprogram them based on struct task_struct when a CPU is brought online.
> 
> Previously MPAM's 'default PARTID' of 0 was used this is the PARTID that
> hardware guarantees to reset. Because there are a limited number of
> PARTID, this value is exposed to user space, meaning resctrl changes
> to the resctrl default group would also affect kernel threads.
> Instead, use the task's PARTID value for kernel work on behalf of
> user-space too.
> 
> Signed-off-by: James Morse <james.morse at arm.com>
> ---
>  arch/arm64/kernel/cpufeature.c | 18 +++++++++++-------
>  1 file changed, 11 insertions(+), 7 deletions(-)
> 
> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
> index 5ed401ff79e3..429128a181ac 100644
> --- a/arch/arm64/kernel/cpufeature.c
> +++ b/arch/arm64/kernel/cpufeature.c
> @@ -86,6 +86,7 @@
>  #include <asm/kvm_host.h>
>  #include <asm/mmu.h>
>  #include <asm/mmu_context.h>
> +#include <asm/mpam.h>
>  #include <asm/mte.h>
>  #include <asm/hypervisor.h>
>  #include <asm/processor.h>
> @@ -2439,13 +2440,16 @@ test_has_mpam(const struct arm64_cpu_capabilities *entry, int scope)
>  static void
>  cpu_enable_mpam(const struct arm64_cpu_capabilities *entry)
>  {
> -	/*
> -	 * Access by the kernel (at EL1) should use the reserved PARTID
> -	 * which is configured unrestricted. This avoids priority-inversion
> -	 * where latency sensitive tasks have to wait for a task that has
> -	 * been throttled to release the lock.
> -	 */
> -	write_sysreg_s(0, SYS_MPAM1_EL1);
> +	int cpu = smp_processor_id();
> +	u64 regval = 0;
> +
> +	if (IS_ENABLED(CONFIG_MPAM))
> +		regval = READ_ONCE(per_cpu(arm64_mpam_current, cpu));

CONFIG_MPAM -> CONFIG_ARM64_MPAM

> +
> +	write_sysreg_s(regval, SYS_MPAM1_EL1);
> +	isb();
> +
> +	write_sysreg_s(regval, SYS_MPAM0_EL1);
>  }
>  
>  static bool

Thanks,

Ben



From robh at kernel.org  Tue Dec  9 07:27:20 2025
From: robh at kernel.org (Rob Herring)
Date: Tue, 9 Dec 2025 09:27:20 -0600
Subject: [RFC PATCH] remoteproc: imx_dsp_rproc: Fix multiple start/stop
 commands
In-Reply-To: <20251209140425.766742-1-daniel.baluta@nxp.com>
References: <20251209140425.766742-1-daniel.baluta@nxp.com>
Message-ID: <20251209152720.GA189083-robh@kernel.org>

On Tue, Dec 09, 2025 at 04:04:25PM +0200, Daniel Baluta wrote:
> After commit 67a7bc7f0358 ("remoteproc: Use of reserved_mem_region_*
> functions for "memory-region"") following commands with
> imx-dsp-rproc started to fail:
>
> $ echo zephyr.elf > /sys/class/remoteproc/remoteproc0/firmware
> $ echo start > /sys/class/remoteproc/remoteproc0/state
> $ echo stop > /sys/class/remoteproc/remoteproc0/state
> $ echo start > /sys/class/remoteproc/remoteproc0/state #! This fails
> -sh: echo: write error: Device or resource busy

So unlike Marek's case, the first time works. Can you confirm your 
region is fixed address?

> This happens because aforementioned commit replaced devm_ioremap_wc with
> devm_ioremap_resource_wc which will "reserve" the memory region with the
> first start and then will fail at the second start if the memory
> region is already reserved.
> 
> So prefer using devm_ioremap_wc as there is no easy way to undo
> devm_iormep_resource_wc manually.
> 
> Fixes: 67a7bc7f0358 ("remoteproc: Use of_reserved_mem_region_* functions for "memory-region"")
> Signed-off-by: Daniel Baluta <daniel.baluta at nxp.com>
> ---
>  drivers/remoteproc/imx_dsp_rproc.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c
> index 5130a35214c9..79d5c15319f3 100644
> --- a/drivers/remoteproc/imx_dsp_rproc.c
> +++ b/drivers/remoteproc/imx_dsp_rproc.c
> @@ -709,10 +709,10 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv)
>  		if (imx_dsp_rproc_sys_to_da(priv, res.start, resource_size(&res), &da))
>  			return -EINVAL;
>  
> -		cpu_addr = devm_ioremap_resource_wc(dev, &res);
> -		if (IS_ERR(cpu_addr)) {
> +		cpu_addr = devm_ioremap_wc(dev, res.start, resource_size(&res));

Best case this is reusing the same mapping and we just have unnecessary 
ioremap and iounmap calls and devm entries. Worst case, we get a new 
virtual mapping every time. IIRC, arm32 will reuse existing mapping, but 
arm64 does not. But that's 10+ years ago I looked into it.

Seems like devres is not the right lifetime. This should be just 
ioremap_wc() instead.

Rob


From leo.yan at arm.com  Tue Dec  9 07:29:06 2025
From: leo.yan at arm.com (Leo Yan)
Date: Tue, 9 Dec 2025 15:29:06 +0000
Subject: [PATCH 05/19] coresight: trbe: Refactor status clearing
In-Reply-To: <fb3b495a-3e04-417f-a674-e1753fd85177@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-5-7da32b076b28@arm.com>
 <fb3b495a-3e04-417f-a674-e1753fd85177@arm.com>
Message-ID: <20251209152906.GW724103@e132581.arm.com>

On Thu, Dec 04, 2025 at 06:27:27PM +0530, Anshuman Khandual wrote:
> On 01/12/25 4:51 PM, Leo Yan wrote:
> > If the driver does not clear the status when disabling the trace buffer
> > unit, stale state will carry over to the next enable, though the driver
> > clears it again on enable.
> 
> There is no problem now ! Because trbe_enable_hw() calls clr_trbe_status().
> 
> > 
> > Explicitly clear status after the trace is disabled in the interrupt
> > handling and when a perf session ends.  Keep the status for spurious
> > interrupts for continuous tracing.
> 
> But is not that the behaviour already without this change ?
> 
> clr_trbe_status() in trbe_enable_hw() ensures that no TRBE session can be
> started without first clearing the existing status. Still wondering what
> is the purpose of this change ?

It is about the driver's sanity.

The driver should clear the status immediately when the trace unit is
disabled, rather than waiting until the next enable.  This avoids
unexpected behaviour, such as a spurious TRBE interrupt.

Consider an edge case: if TRBE is being disabled at the same moment it
is about to raise an interrupt, arm_trbe_update_buffer() may miss the
IRQ bit due to latency.  If arm_trbe_disable() does not clear that bit,
arm_trbe_irq_handler() will still run after the perf event has been
stopped.  The interrupt handler then retrieves the trbe_buf pointer
from the perf output handle, which is dangerous because the perf
session has already ended.

Thanks,
Leo


From ben.horgan at arm.com  Tue Dec  9 07:32:00 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Tue, 9 Dec 2025 15:32:00 +0000
Subject: [RFC PATCH 06/38] KVM: arm64: Force guest EL1 to use user-space's
 partid configuration
In-Reply-To: <20251205215901.17772-7-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-7-james.morse@arm.com>
Message-ID: <f7011785-90df-4355-bc4c-f4be96799015@arm.com>

Hi James,

On 12/5/25 21:58, James Morse wrote:
> While we trap the guest's attempts to read/write the MPAM control
> registers, the hardware continues to use them. Guest-EL0 uses KVM's
> user-space's configuration, as the value is left in the register, and
> guest-EL1 uses either the host kernel's configuration, or in the case of
> VHE, the UNKNOWN reset value of MPAM1_EL1.
> 
> On nVHE systems, EL2 continues to use partid-0 for world-switch, even
> when the host may have configured its kernel threads to use a different
> partid. 0 may have been assigned to another task.
> > We want to force the guest-EL1 to use KVM's user-space's MPAM
> configuration, and EL2s to match the host's EL1 config.
> 
> On a nVHE system, copy the EL1 MPAM register to EL2. This ensures
> world-switch uses the same partid as the kernel thread does on the host.
> 
> When loading the guest's EL1 registers, copy the VMM's EL0 partid to
> the EL1 register.
> 
> For VHE systems, we can skip restoring the EL1 register for the host,
> as it is out-of-context once HCR_EL2.TGE is set.
> 
> This is done outside the usual sysreg save/restore as the values can
> change behind KVMs back, so should not be stored in the guest context.
> 
> Signed-off-by: James Morse <james.morse at arm.com>

One thing that is needed in kvm now that we are changing MPAM for EL1 is
an update to the __*activate_traps_mpam() to not assume partids and pmgs
are 0. I have an existing patch to deal with this.

Thanks,

Ben



From smostafa at google.com  Tue Dec  9 07:41:06 2025
From: smostafa at google.com (Mostafa Saleh)
Date: Tue, 9 Dec 2025 15:41:06 +0000
Subject: [PATCH] iommu/io-pgtable-arm: Add misisng concatenated PGD cases
In-Reply-To: <498bbad4-ea64-4a24-a63f-e131d271990a@arm.com>
References: <20251130194506.593700-1-smostafa@google.com>
 <18a39079-2285-47fb-b306-040f2bc1bbaa@arm.com>
 <aTgX9qhaLyrQ5iye@google.com>
 <498bbad4-ea64-4a24-a63f-e131d271990a@arm.com>
Message-ID: <aThDEnbbop8ZYAuG@google.com>

On Tue, Dec 09, 2025 at 01:33:36PM +0000, Robin Murphy wrote:
> On 2025-12-09 12:37 pm, Mostafa Saleh wrote:
> > On Tue, Dec 09, 2025 at 11:34:34AM +0000, Robin Murphy wrote:
> > > On 2025-11-30 7:45 pm, Mostafa Saleh wrote:
> > > > arm_lpae_concat_mandatory() assumes that OAS >= IAS which is not
> > > > correct for SMMUs supporting AArch32, and have OAS = 32/36 bits,
> > > > as IAS would be 40 bits.
> > > 
> > > But that is only when *using* AArch32 format. The bit in chapter 3.4 of the
> > > SMMU architecture is talking about the maximum IAS that an SMMU
> > > implementation needs to be able to accommodate based on its configuration,
> > > but it does then attempt to clarify that the actual IPA size in use by any
> > > given context should depend on the VMSA format in use:
> > > 
> > > "VMSAv8-32 LPAE always supports an IPA size of 40 bits, whereas VMSAv8-64
> > > and VMSAv9-128 limits the maximum IPA size to the maximum PA size."
> > > 
> > > Rule R_SRKBC in the Arm ARM lays out the exact T0SZ constraints with this
> > > AArch32/AArch64 detail.
> > 
> > I see, thanks a lot for the explanation, I got confused by the this
> > statement:
> > Note: If AArch32 is implemented, IAS == MAX(40, OAS), otherwise IAS == OAS.
> 
> Indeed, that appears confusingly contradictory; I've filed a bug.
> 
> > However, I think this is still a bug but somewere else, as at the moment
> > the SMMUv3 dirver will use the SMMU IAS (40-bits) as input for AArch64
> > stage-2 page tables, so we need either to limit the IAS as:
> > 
> > diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> > index d16d35c78c06..d21153156daa 100644
> > --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> > +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> > @@ -2561,7 +2561,7 @@ static int arm_smmu_domain_finalise(struct arm_smmu_domain *smmu_domain,
> >          case ARM_SMMU_DOMAIN_S2:
> >                  if (enable_dirty)
> >                          return -EOPNOTSUPP;
> > -               pgtbl_cfg.ias = smmu->ias;
> > +               pgtbl_cfg.ias = min(smmu->ias, smmu->oas);
> >                  pgtbl_cfg.oas = smmu->oas;
> >                  fmt = ARM_64_LPAE_S2;
> >                  finalise_stage_fn = arm_smmu_domain_finalise_s2;
> > 
> > Or, don't populate IAS depending on AArch32 support as the driver
> > doesn't support it, effectively reverting:
> > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f0c453dbcce7767cd868deb809ba68083c93954e
> 
> It does appear we've missed the detail here. TBH I'm not really sure why
> we're bothering to consider the theoretical maximum IAS at all when it only
> makes any difference to a format we've never cared about supporting anyway.
> Frankly I'd be inclined to just remove smmu->ias altogether - even if we did
> ever want to support LPAE format, it would be just as trivial for that to
> hard-code pgtbl_cfg.ias = 40 based on the architecture rules.
> 

Makes sense, I will prepare a patch.

Thanks,
Mostafa

> Thanks,
> Robin.


From ben.horgan at arm.com  Tue Dec  9 07:43:12 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Tue, 9 Dec 2025 15:43:12 +0000
Subject: [RFC PATCH 07/38] arm_mpam: resctrl: Add boilerplate cpuhp and
 domain allocation
In-Reply-To: <20251205215901.17772-8-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-8-james.morse@arm.com>
Message-ID: <357f747b-055c-4dcf-bd63-32600dab7fe7@arm.com>

Hi James,

On 12/5/25 21:58, James Morse wrote:
> resctrl has its own data structures to describe its resources. We
> can't use these directly as we play tricks with the 'MBA' resource,
> picking the MPAM controls or monitors that best apply. We may export
> the same component as both L3 and MBA.
> 
> Add mpam_resctrl_exports[] as the array of class->resctrl mappings we
> are exporting, and add the cpuhp hooks that allocated and free the
> resctrl domain structures.
> 
> While we're here, plumb in a few other obvious things.
> 
> CONFIG_ARM_CPU_RESCTRL is used to allow this code to be built
> even though it can't yet be linked against resctrl.
> 
> Signed-off-by: James Morse <james.morse at arm.com>
> ---
>  drivers/resctrl/Makefile        |   1 +
>  drivers/resctrl/mpam_devices.c  |  12 ++
>  drivers/resctrl/mpam_internal.h |  22 +++
>  drivers/resctrl/mpam_resctrl.c  | 329 ++++++++++++++++++++++++++++++++
>  include/linux/arm_mpam.h        |   3 +
>  5 files changed, 367 insertions(+)
>  create mode 100644 drivers/resctrl/mpam_resctrl.c
> 
[...]
> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
> new file mode 100644
> index 000000000000..320cebbd37ce
> --- /dev/null
> +++ b/drivers/resctrl/mpam_resctrl.c
> @@ -0,0 +1,329 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (C) 2025 Arm Ltd.
> +
> +#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__
> +
> +#include <linux/arm_mpam.h>
> +#include <linux/cacheinfo.h>
> +#include <linux/cpu.h>
> +#include <linux/cpumask.h>
> +#include <linux/errno.h>
> +#include <linux/list.h>
> +#include <linux/printk.h>
> +#include <linux/rculist.h>
> +#include <linux/resctrl.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
> +
> +#include <asm/mpam.h>
> +
> +#include "mpam_internal.h"
> +
> +/*
> + * The classes we've picked to map to resctrl resources, wrapped
> + * in with their resctrl structure.
> + * Class pointer may be NULL.
> + */
> +static struct mpam_resctrl_res mpam_resctrl_controls[RDT_NUM_RESOURCES];
> +
> +/* The lock for modifying resctrl's domain lists from cpuhp callbacks. */
> +static DEFINE_MUTEX(domain_list_lock);
> +
> +static bool exposed_alloc_capable;
> +static bool exposed_mon_capable;
> +
> +bool resctrl_arch_alloc_capable(void)
> +{
> +	return exposed_alloc_capable;
> +}
> +
> +bool resctrl_arch_mon_capable(void)
> +{
> +	return exposed_mon_capable;
> +}
> +
> +/*
> + * MSC may raise an error interrupt if it sees an out or range partid/pmg,
> + * and go on to truncate the value. Regardless of what the hardware supports,
> + * only the system wide safe value is safe to use.
> + */
> +u32 resctrl_arch_get_num_closid(struct rdt_resource *ignored)
> +{
> +	return mpam_partid_max + 1;
> +}
> +
> +struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l)
> +{
> +	if (l >= RDT_NUM_RESOURCES)
> +		return NULL;
> +
> +	return &mpam_resctrl_controls[l].resctrl_res;
> +}
> +
> +static int mpam_resctrl_control_init(struct mpam_resctrl_res *res,
> +				     enum resctrl_res_level type)
> +{
> +	/* TODO: initialise the resctrl resources */
> +
> +	return 0;
> +}
> +
> +static int mpam_resctrl_pick_domain_id(int cpu, struct mpam_component *comp)
> +{
> +	struct mpam_class *class = comp->class;
> +
> +	if (class->type == MPAM_CLASS_CACHE)
> +		return comp->comp_id;
> +
> +	/* TODO: repaint domain ids to match the L3 domain ids */
> +	/*
> +	 * Otherwise, expose the ID used by the firmware table code.
> +	 */
> +	return comp->comp_id;
> +}
> +
> +static void mpam_resctrl_domain_hdr_init(int cpu, struct mpam_component *comp,
> +					 struct rdt_domain_hdr *hdr)
> +{
> +	lockdep_assert_cpus_held();
> +
> +	INIT_LIST_HEAD(&hdr->list);
> +	hdr->id = mpam_resctrl_pick_domain_id(cpu, comp);
> +	cpumask_set_cpu(cpu, &hdr->cpu_mask);
> +}
> +
> +/**
> + * mpam_resctrl_offline_domain_hdr() - Update the domain header to remove a CPU.
> + * @cpu:	The CPU to remove from the domain.
> + * @hdr:	The domain's header.
> + *
> + * Removes @cpu from the header mask. If this was the last CPU in the domain,
> + * the domain header is removed from its parent list and true is returned,
> + * indicating the parent structure can be freed.
> + * If there are other CPUs in the domain, returns false.
> + */
> +static bool mpam_resctrl_offline_domain_hdr(unsigned int cpu,
> +					    struct rdt_domain_hdr *hdr)
> +{
> +	cpumask_clear_cpu(cpu, &hdr->cpu_mask);
> +	if (cpumask_empty(&hdr->cpu_mask)) {
> +		list_del(&hdr->list);

list_del_rcu(). I'll check some more as I'm not yet convinced we need
rcu for these lists.

> +		return true;
> +	}
> +
> +	return false;
> +}
> +
> +static struct mpam_resctrl_dom *
> +mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
> +{
> +	int err;
> +	struct mpam_resctrl_dom *dom;
> +	struct rdt_mon_domain *mon_d;
> +	struct rdt_ctrl_domain *ctrl_d;
> +	struct mpam_class *class = res->class;
> +	struct mpam_component *comp_iter, *ctrl_comp;
> +	struct rdt_resource *r = &res->resctrl_res;
> +
> +	lockdep_assert_held(&domain_list_lock);
> +
> +	ctrl_comp = NULL;
> +	guard(srcu)(&mpam_srcu);
> +	list_for_each_entry_srcu(comp_iter, &class->components, class_list,
> +				 srcu_read_lock_held(&mpam_srcu)) {
> +		if (cpumask_test_cpu(cpu, &comp_iter->affinity)) {
> +			ctrl_comp = comp_iter;
> +			break;
> +		}
> +	}
> +
> +	/* class has no component for this CPU */
> +	if (WARN_ON_ONCE(!ctrl_comp))
> +		return ERR_PTR(-EINVAL);
> +
> +	dom = kzalloc_node(sizeof(*dom), GFP_KERNEL, cpu_to_node(cpu));
> +	if (!dom)
> +		return ERR_PTR(-ENOMEM);
> +
> +	if (exposed_alloc_capable) {
> +		dom->ctrl_comp = ctrl_comp;
> +
> +		ctrl_d = &dom->resctrl_ctrl_dom;
> +		mpam_resctrl_domain_hdr_init(cpu, ctrl_comp, &ctrl_d->hdr);
> +		ctrl_d->hdr.type = RESCTRL_CTRL_DOMAIN;
> +		/* TODO: this list should be sorted */
> +		list_add_tail_rcu(&ctrl_d->hdr.list, &r->ctrl_domains);
> +		err = resctrl_online_ctrl_domain(r, ctrl_d);
> +		if (err) {
> +			dom = ERR_PTR(err);
> +			goto offline_ctrl_domain;
> +		}
> +	} else {
> +		pr_debug("Skipped control domain online - no controls\n");
> +	}
> +
> +	if (exposed_mon_capable) {
> +		mon_d = &dom->resctrl_mon_dom;
> +		mpam_resctrl_domain_hdr_init(cpu, ctrl_comp, &mon_d->hdr);
> +		mon_d->hdr.type = RESCTRL_MON_DOMAIN;
> +		/* TODO: this list should be sorted */
> +		list_add_tail_rcu(&mon_d->hdr.list, &r->mon_domains);
> +		err = resctrl_online_mon_domain(r, mon_d);
> +		if (err) {
> +			dom = ERR_PTR(err);
> +			goto offline_mon_hdr;
> +		}
> +	} else {
> +		pr_debug("Skipped monitor domain online - no monitors\n");
> +	}
> +	goto out;
> +
> +offline_mon_hdr:
> +	mpam_resctrl_offline_domain_hdr(cpu, &mon_d->hdr);
> +offline_ctrl_domain:
> +	resctrl_offline_ctrl_domain(r, ctrl_d);
> +out:
> +	return dom;
> +}
> +
> +static struct mpam_resctrl_dom *
> +mpam_resctrl_get_domain_from_cpu(int cpu, struct mpam_resctrl_res *res)
> +{
> +	struct mpam_resctrl_dom *dom;
> +	struct rdt_ctrl_domain *ctrl_d;
> +
> +	lockdep_assert_cpus_held();
> +
> +	list_for_each_entry_rcu(ctrl_d, &res->resctrl_res.ctrl_domains,
> +				hdr.list) {
> +		dom = container_of(ctrl_d, struct mpam_resctrl_dom,
> +				   resctrl_ctrl_dom);
> +
> +		if (cpumask_test_cpu(cpu, &dom->ctrl_comp->affinity))
> +			return dom;
> +	}
> +
> +	return NULL;
> +}
> +
> +int mpam_resctrl_online_cpu(unsigned int cpu)
> +{
> +	int i;
> +	struct mpam_resctrl_dom *dom;
> +	struct mpam_resctrl_res *res;
> +
> +	guard(mutex)(&domain_list_lock);
> +	for (i = 0; i < RDT_NUM_RESOURCES; i++) {
> +		res = &mpam_resctrl_controls[i];
> +		if (!res->class)
> +			continue;	// dummy_resource;
> +
> +		dom = mpam_resctrl_get_domain_from_cpu(cpu, res);
> +		if (!dom)
> +			dom = mpam_resctrl_alloc_domain(cpu, res);
> +		if (IS_ERR(dom))
> +			return PTR_ERR(dom);
> +	}
> +
> +	resctrl_online_cpu(cpu);
> +
> +	return 0;
> +}
> +
> +void mpam_resctrl_offline_cpu(unsigned int cpu)
> +{
> +	int i;
> +	struct mpam_resctrl_res *res;
> +	struct mpam_resctrl_dom *dom;
> +	struct rdt_mon_domain *mon_d;
> +	struct rdt_ctrl_domain *ctrl_d;
> +	bool ctrl_dom_empty, mon_dom_empty;
> +
> +	resctrl_offline_cpu(cpu);
> +
> +	guard(mutex)(&domain_list_lock);
> +	for (i = 0; i < RDT_NUM_RESOURCES; i++) {
> +		res = &mpam_resctrl_controls[i];
> +		if (!res->class)
> +			continue;	// dummy resource
> +
> +		dom = mpam_resctrl_get_domain_from_cpu(cpu, res);
> +		if (WARN_ON_ONCE(!dom))
> +			continue;
> +
> +		ctrl_dom_empty = true;
> +		if (exposed_alloc_capable) {
> +			ctrl_d = &dom->resctrl_ctrl_dom;
> +			ctrl_dom_empty = mpam_resctrl_offline_domain_hdr(cpu, &ctrl_d->hdr);
> +			if (ctrl_dom_empty)
> +				resctrl_offline_ctrl_domain(&res->resctrl_res, ctrl_d);
> +		}
> +
> +		mon_dom_empty = true;
> +		if (exposed_mon_capable) {
> +			mon_d = &dom->resctrl_mon_dom;
> +			mon_dom_empty = mpam_resctrl_offline_domain_hdr(cpu, &mon_d->hdr);
> +			if (mon_dom_empty)
> +				resctrl_offline_mon_domain(&res->resctrl_res, mon_d);
> +		}
> +
> +		if (ctrl_dom_empty && mon_dom_empty)
> +			kfree(dom);
> +	}
> +}
> +
> +int mpam_resctrl_setup(void)
> +{
> +	int err = 0;
> +	enum resctrl_res_level i;
> +	struct mpam_resctrl_res *res;
> +
> +	cpus_read_lock();
> +	for (i = 0; i < RDT_NUM_RESOURCES; i++) {
> +		res = &mpam_resctrl_controls[i];
> +		INIT_LIST_HEAD_RCU(&res->resctrl_res.ctrl_domains);
> +		INIT_LIST_HEAD_RCU(&res->resctrl_res.mon_domains);
> +		res->resctrl_res.rid = i;
> +	}
> +
> +	/* TODO: pick MPAM classes to map to resctrl resources */
> +
> +	/* Initialise the resctrl structures from the classes */
> +	for (i = 0; i < RDT_NUM_RESOURCES; i++) {
> +		res = &mpam_resctrl_controls[i];
> +		if (!res->class)
> +			continue;	// dummy resource
> +
> +		err = mpam_resctrl_control_init(res, i);
> +		if (err) {
> +			pr_debug("Failed to initialise rid %u\n", i);
> +			break;
> +		}
> +	}
> +	cpus_read_unlock();
> +
> +	if (err || (!exposed_alloc_capable && !exposed_mon_capable)) {
> +		if (err)
> +			pr_debug("Internal error %d - resctrl not supported\n",
> +				 err);
> +		else
> +			pr_debug("No alloc(%u) or monitor(%u) found - resctrl not supported\n",
> +				 exposed_alloc_capable, exposed_mon_capable);
> +		err = -EOPNOTSUPP;
> +	}
> +
> +	if (!err) {
> +		if (!is_power_of_2(mpam_pmg_max + 1)) {
> +			/*
> +			 * If not all the partid*pmg values are valid indexes,
> +			 * resctrl may allocate pmg that don't exist. This
> +			 * should cause an error interrupt.
> +			 */
> +			pr_warn("Number of PMG is not a power of 2! resctrl may misbehave");
> +		}
> +
> +		/* TODO: call resctrl_init() */
> +	}
> +
> +	return err;
> +}
> diff --git a/include/linux/arm_mpam.h b/include/linux/arm_mpam.h
> index 7f00c5285a32..2c7d1413a401 100644
> --- a/include/linux/arm_mpam.h
> +++ b/include/linux/arm_mpam.h
> @@ -49,6 +49,9 @@ static inline int mpam_ris_create(struct mpam_msc *msc, u8 ris_idx,
>  }
>  #endif
>  
> +bool resctrl_arch_alloc_capable(void);
> +bool resctrl_arch_mon_capable(void);
> +
>  /**
>   * mpam_register_requestor() - Register a requestor with the MPAM driver
>   * @partid_max:		The maximum PARTID value the requestor can generate.

Thanks,

Ben



From Frank.li at nxp.com  Tue Dec  9 07:44:55 2025
From: Frank.li at nxp.com (Frank Li)
Date: Tue, 9 Dec 2025 10:44:55 -0500
Subject: [PATCH 5/8] nvmet: pci-epf: Remove unnecessary
 dmaengine_terminate_sync() on each DMA transfer
In-Reply-To: <f9107db3-491e-4224-a337-821a89f99132@kernel.org>
References: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
 <20251208-dma_prep_config-v1-5-53490c5e1e2a@nxp.com>
 <f9107db3-491e-4224-a337-821a89f99132@kernel.org>
Message-ID: <aThD92lA2aiOKZCr@lizhi-Precision-Tower-5810>

On Tue, Dec 09, 2025 at 03:52:15PM +0900, Damien Le Moal wrote:
> On 12/9/25 2:09 AM, Frank Li wrote:
> > dmaengine_terminate_sync() cancels all pending requests. Calling it for
> > every DMA transfer is unnecessary and counterproductive. This function is
> > generally intended for cleanup paths such as module removal, device close,
> > or unbind operations.
> >
> > Remove the redundant calls.
> >
> > Signed-off-by: Frank Li <Frank.Li at nxp.com>
> > ---
> > This one also fix stress test failure after remove mutex and use new API
> > dmaengine_prep_slave_sg_config().
> > ---
> >  drivers/nvme/target/pci-epf.c | 2 --
> >  1 file changed, 2 deletions(-)
> >
> > diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c
> > index 2e78397a7373a7d8ba67150f301f392123db88d1..85225a4f75b5bd7abb6897d064123766af021542 100644
> > --- a/drivers/nvme/target/pci-epf.c
> > +++ b/drivers/nvme/target/pci-epf.c
> > @@ -420,8 +420,6 @@ static int nvmet_pci_epf_dma_transfer(struct nvmet_pci_epf *nvme_epf,
> >  		ret = -EIO;
> >  	}
> >
> > -	dmaengine_terminate_sync(chan);
>
> If the above dma_sync_wait failed, we better call this here as we have no idea
> why we got the failure, no ?

Yes, it should be call at only failure case.

Frank
> For success case, we indeed may want to remove it.
>
> > -
> >  unmap:
> >  	dma_unmap_single(dma_dev, dma_addr, seg->length, dir);
> >
> >
>
>
> --
> Damien Le Moal
> Western Digital Research


From Frank.li at nxp.com  Tue Dec  9 07:47:30 2025
From: Frank.li at nxp.com (Frank Li)
Date: Tue, 9 Dec 2025 10:47:30 -0500
Subject: [PATCH 1/8] dmaengine: Add API to combine configuration and
 preparation (sg and single)
In-Reply-To: <20251209063809.GA27728@lst.de>
References: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
 <20251208-dma_prep_config-v1-1-53490c5e1e2a@nxp.com>
 <20251209063809.GA27728@lst.de>
Message-ID: <aThEkqq79WwPvQ27@lizhi-Precision-Tower-5810>

On Tue, Dec 09, 2025 at 07:38:09AM +0100, Christoph Hellwig wrote:
> On Mon, Dec 08, 2025 at 12:09:40PM -0500, Frank Li wrote:
> > Previously, configuration and preparation required two separate calls. This
> > works well when configuration is done only once during initialization.
> >
> > However, in cases where the burst length or source/destination address must
> > be adjusted for each transfer, calling two functions is verbose and
> > requires additional locking to ensure both steps complete atomically.
> >
> > Add a new API and callback device_prep_slave_sg_config that combines
> > configuration and preparation into a single operation. If the configuration
> > argument is passed as NULL, fall back to the existing implementation.
>
> Maybe this would be a good time to start retiring the "slave" naming
> and come up with shorter names as a win-win situation?

Yes, 'prep_sg_config' or 'prep_sg' should be enough.

Frank
>


From peternewman at google.com  Tue Dec  9 07:53:58 2025
From: peternewman at google.com (Peter Newman)
Date: Tue, 9 Dec 2025 16:53:58 +0100
Subject: [RFC PATCH 00/38] arm_mpam: Add KVM/arm64 and resctrl glue code
In-Reply-To: <41bcd0d2-d5b8-4f3d-b0b3-132387f547ed@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com> <41bcd0d2-d5b8-4f3d-b0b3-132387f547ed@arm.com>
Message-ID: <CALPaoCgDuA1D+ubUv3UJ0+LyUfjCFKOcrEhg6Q80rNK5idjEmA@mail.gmail.com>

Hi Ben,

On Tue, Dec 9, 2025 at 3:40?PM Ben Horgan <ben.horgan at arm.com> wrote:
>
> Hi James and all,
>
> As James is otherwise occupied, I am planning to post a follow up
> version of this series once it's had time to be reviewed. I will be
> posting my own review comments; please give them extra scrutiny.
>
> On 12/5/25 21:58, James Morse wrote:
> > This is the missing piece to make MPAM usable resctrl in user-space. This has
> > shed its debugfs code and the read/write 'event configuration' for the monitors
> > to make the series smaller.
> >
> [...]
> >
> > This series is based on arm64/for-next/core, and can be retrieved from:
> > https://git.kernel.org/pub/scm/linux/kernel/git/morse/linux.git mpam/glue/rfc
> >
> > There is no snapshot branch - this is it!
> > I'll push the extras branch once I've gotten a handle on the DT shaped mess in
> > there.
>
> One major departure from the previous snapshot branches referenced in
> the base driver series is that the same MPAM setting are used for
> kernel-space and user-space. That is, MPAM1_EL1 is set to the same value
> as MPAM0_EL1 rather than keeping the default value. The advantages of
> this are that it is closer to the x86 model where the closid is globally
> applicable, all partids are usable from user-space and user-space can't
> bypass MPAM controls by doing the work in the kernel. However, this
> causes some priority inversion where a high priority task waits to take
> a mutex held by another whose resources are restricted by MPAM.
> Thanks,

In our experience, the disadvantages of the x86 model were worse
because they triggered on hosts unintentionally, while making the
kernel do work unrestricted on behalf of the user at least requires
intentional abuse.

-Peter


From ben.horgan at arm.com  Tue Dec  9 07:57:03 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Tue, 9 Dec 2025 15:57:03 +0000
Subject: [RFC PATCH 08/38] arm_mpam: resctrl: Pick the caches we will use
 as resctrl resources
In-Reply-To: <20251205215901.17772-9-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-9-james.morse@arm.com>
Message-ID: <c0139cdf-9263-4051-938d-cb86233399b0@arm.com>

Hi James,

On 12/5/25 21:58, James Morse wrote:
> Systems with MPAM support may have a variety of control types at any
> point of their system layout. We can only expose certain types of
> control, and only if they exist at particular locations.
> 
> Start with the well-know caches. These have to be depth 2 or 3
> and support MPAM's cache portion bitmap controls, with a number
> of portions fewer than resctrl's limit.
> 
> Signed-off-by: James Morse <james.morse at arm.com>
> ---
>  drivers/resctrl/mpam_resctrl.c | 91 +++++++++++++++++++++++++++++++++-
>  1 file changed, 89 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
> index 320cebbd37ce..ceaf11af4fc1 100644
> --- a/drivers/resctrl/mpam_resctrl.c
> +++ b/drivers/resctrl/mpam_resctrl.c
> @@ -60,10 +60,96 @@ struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l)
>  	return &mpam_resctrl_controls[l].resctrl_res;
>  }
>  
> +static bool cache_has_usable_cpor(struct mpam_class *class)
> +{
> +	struct mpam_props *cprops = &class->props;
> +
> +	if (!mpam_has_feature(mpam_feat_cpor_part, cprops))
> +		return false;
> +
> +	/* resctrl uses u32 for all bitmap configurations */
> +	return (class->props.cpbm_wd <= 32);
> +}

cpbm_wd > 32 is not support properly in mpam_devices.c (e.g. reset and
config value are limited to 32 bits.) and so we should consider just not
adding the feature to the class in that case.

Thanks,

Ben



From leo.yan at arm.com  Tue Dec  9 07:57:22 2025
From: leo.yan at arm.com (Leo Yan)
Date: Tue, 9 Dec 2025 15:57:22 +0000
Subject: [PATCH 06/19] coresight: trbe: Refactor syndrome decoding
In-Reply-To: <ae63c69c-eff9-4665-a9a6-d395e61bea86@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-6-7da32b076b28@arm.com>
 <ae63c69c-eff9-4665-a9a6-d395e61bea86@arm.com>
Message-ID: <20251209155722.GX724103@e132581.arm.com>

On Fri, Dec 05, 2025 at 09:40:33AM +0530, Anshuman Khandual wrote:
> On 01/12/25 4:51 PM, Leo Yan wrote:
> > It gives priority to TRBSR_EL1.EA (external abort); an external abort
> > will immediately bail out and return an error.
> 
> This is an abrupt starting for a commit message without giving context.
> The rationale for the change needs to be explained rather than details
> of implementation.

Agreed.  I will refine the commit log to state that we need to diagnose
the error code based on the hierarchy information (EC and BSC).

> > Next, the syndrome decoding is refactored based on two levels of
> > information: the EC (Event Class) bits and the BSC (Trace Buffer Status
> > Code) bits.
> > 
> > If TRBSR_EL1.EC==0b000000, the driver continues parsing TRBSR_EL1.BSC to
> > identify the specific trace buffer event.  Otherwise, any non-zero
> > TRBSR_EL1.EC is treated as an error.
> > 
> > For error cases, the driver prints an error string and dumps registers
> > for debugging.
> > 
> > No additional checks are required for wrap mode beyond verifying the
> > TRBSR_EL1.WRAP bit, even on units with overwrite errata, as this bit
> > reliably indicates a buffer wrap.
> 
> Should the errata related changes be done in a separate patch instead ?

Good point.  I will consider extracting the change; this would make
the review clearer.

[...]

> >  static enum trbe_fault_action trbe_get_fault_act(struct perf_output_handle *handle,
> >  						 u64 trbsr)
> >  {
> > +	const char *err_str;
> >  	int ec = get_trbe_ec(trbsr);
> >  	int bsc = get_trbe_bsc(trbsr);
> > -	struct trbe_buf *buf = etm_perf_sink_config(handle);
> > -	struct trbe_cpudata *cpudata = buf->cpudata;
> >  
> >  	WARN_ON(is_trbe_running(trbsr));
> > -	if (is_trbe_trg(trbsr) || is_trbe_abort(trbsr))
> > -		return TRBE_FAULT_ACT_FATAL;
> >  
> > -	if ((ec == TRBE_EC_STAGE1_ABORT) || (ec == TRBE_EC_STAGE2_ABORT))
> > -		return TRBE_FAULT_ACT_FATAL;
> > +	if (is_trbe_abort(trbsr)) {
> > +		err_str = "External abort";
> > +		goto out_fatal;
> > +	}
> >  
> > -	/*
> > -	 * If the trbe is affected by TRBE_WORKAROUND_OVERWRITE_FILL_MODE,
> > -	 * it might write data after a WRAP event in the fill mode.
> > -	 * Thus the check TRBPTR == TRBBASER will not be honored.
> > -	 */
> > -	if ((is_trbe_wrap(trbsr) && (ec == TRBE_EC_OTHERS) && (bsc == TRBE_BSC_FILLED)) &&
> > -	    (trbe_may_overwrite_in_fill_mode(cpudata) ||
> > -	     get_trbe_write_pointer() == get_trbe_base_pointer()))
> > +	switch (ec) {
> > +	case TRBE_EC_OTHERS:
> > +		break;
> 
> No message for this ?

No.  EC_OTHERS means "this is a normal maintenance interrupt".

> > +	case TRBE_EC_BUF_MGMT_IMPL:
> > +		err_str = "Unexpected implemented management";
> > +		goto out_fatal;
> > +	case TRBE_EC_GP_CHECK_FAULT:
> > +		err_str = "Granule Protection Check fault";
> > +		goto out_fatal;
> > +	case TRBE_EC_STAGE1_ABORT:
> > +		err_str = "Stage 1 data abort";
> > +		goto out_fatal;
> > +	case TRBE_EC_STAGE2_ABORT:
> > +		err_str = "Stage 2 data abort";
> > +		goto out_fatal;
> > +	default:
> > +		err_str = "Unknown error code";
> > +		goto out_fatal;
> > +	}
> > +
> > +	switch (bsc) {
> > +	case TRBE_BSC_NOT_STOPPED:
> > +		break;
> > +	case TRBE_BSC_FILLED:
> > +		break;
> > +	case TRBE_BSC_TRIGGERED:
> > +		err_str = "Unexpected trigger status";
> > +		goto out_fatal;
> > +	default:
> > +		err_str = "Unexpected buffer status code";
> > +		goto out_fatal;
> > +	}
> 
> Just wondering if it would be cleaner to add a const char * based
> static array mapping these EC/BSC codes with above error messages.

Now we have two level's (EC/BSC) error codes, it would be complex to
maintain a string array and map to two level's error codes.

> > +	if (is_trbe_wrap(trbsr))
> 
> But what about TRBE affected with trbe_may_overwrite_in_fill_mode()
> is that still being taken care of some how ?

The TRBSR_EL1.WRAP bit reliably indicates that the pointer has
wrapped.  I don't think we need any special handling for the overwrite
erratum here; we can simply return TRBE_FAULT_ACT_WRAP.

Afterward, trbe_get_trace_size() consumes the wrap flag and will
compute the trace size appropriately for the overwrite erratum when
the wrap flag is set.

[...]

> > -#define TRBE_EC_OTHERS		0
> > -#define TRBE_EC_STAGE1_ABORT	36
> > -#define TRBE_EC_STAGE2_ABORT	37
> > +#define TRBE_EC_OTHERS			0x0
> > +#define TRBE_EC_GP_CHECK_FAULT		0X1e
> > +#define TRBE_EC_BUF_MGMT_IMPL		0x1f
> > +#define TRBE_EC_STAGE1_ABORT		0x24
> > +#define TRBE_EC_STAGE2_ABORT		0x25
> 
> Please do mention the document source for these new EC codes in the
> commit message.

As James suggested in another reply, I will consider to add sysreg
enum.

Thanks,
Leo


From irogers at google.com  Tue Dec  9 07:58:31 2025
From: irogers at google.com (Ian Rogers)
Date: Tue, 9 Dec 2025 07:58:31 -0800
Subject: [PATCH v2 01/12] perf parse-events: Refactor get_config_terms()
 to remove macros
In-Reply-To: <6ba6bde3-f56b-4354-b336-4739cb1edb71@linaro.org>
References: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
 <20251208-james-perf-config-bits-v2-1-4ac0281993b0@linaro.org> <6ba6bde3-f56b-4354-b336-4739cb1edb71@linaro.org>
Message-ID: <CAP-5=fV_Y5W2RyJhBgnk49JuTf8EsyisY-LfL3sVhC4TVRC_gg@mail.gmail.com>

On Tue, Dec 9, 2025 at 4:48?AM James Clark <james.clark at linaro.org> wrote:
>
> On 08/12/2025 2:22 pm, James Clark wrote:
> > The ADD_CONFIG_TERM() macros build the __type argument out of a partial
> > EVSEL__CONFIG_TERM_x enum name. This means that they can't be called
> > from a function where __type is a variable and it's also impossible to
> > grep the codebase to find usages of these enums as they're never typed
> > in full.
> >
> > Fix this by removing the macros and replacing them with an
> > add_config_term() function. It seems the main reason these existed in
> > the first place was to avoid type punning and to write to a specific
> > field in the union, but the same thing can be achieved with a single
> > write to a u64 'val' field.
> >
> > Signed-off-by: James Clark <james.clark at linaro.org>
> > ---
> >   tools/perf/util/evsel_config.h |   1 +
> >   tools/perf/util/parse-events.c | 146 ++++++++++++++++++++++++-----------------
> >   2 files changed, 86 insertions(+), 61 deletions(-)
> >
> > diff --git a/tools/perf/util/evsel_config.h b/tools/perf/util/evsel_config.h
> > index bcd3a978f0c4..685fd8d5c4a8 100644
> > --- a/tools/perf/util/evsel_config.h
> > +++ b/tools/perf/util/evsel_config.h
> > @@ -50,6 +50,7 @@ struct evsel_config_term {
> >               u64           cfg_chg;
> >               char          *str;
> >               int           cpu;
> > +             u64           val;
> >       } val;
> >       bool weak;
> >   };
> > diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
> > index 17c1c36a7bf9..d5b009b4ebab 100644
> > --- a/tools/perf/util/parse-events.c
> > +++ b/tools/perf/util/parse-events.c
> > @@ -1116,105 +1116,107 @@ static int config_attr(struct perf_event_attr *attr,
> >       return 0;
> >   }
> >
> > -static int get_config_terms(const struct parse_events_terms *head_config,
> > -                         struct list_head *head_terms)
> > +static struct evsel_config_term *add_config_term(enum evsel_term_type type,
> > +                                              struct list_head *head_terms,
> > +                                              bool weak)
> >   {
> > -#define ADD_CONFIG_TERM(__type, __weak)                              \
> > -     struct evsel_config_term *__t;                  \
> > -                                                             \
> > -     __t = zalloc(sizeof(*__t));                             \
> > -     if (!__t)                                               \
> > -             return -ENOMEM;                                 \
> > -                                                             \
> > -     INIT_LIST_HEAD(&__t->list);                             \
> > -     __t->type       = EVSEL__CONFIG_TERM_ ## __type;        \
> > -     __t->weak       = __weak;                               \
> > -     list_add_tail(&__t->list, head_terms)
> > -
> > -#define ADD_CONFIG_TERM_VAL(__type, __name, __val, __weak)   \
> > -do {                                                         \
> > -     ADD_CONFIG_TERM(__type, __weak);                        \
> > -     __t->val.__name = __val;                                \
> > -} while (0)
> > +     struct evsel_config_term *t;
> >
> > -#define ADD_CONFIG_TERM_STR(__type, __val, __weak)           \
> > -do {                                                         \
> > -     ADD_CONFIG_TERM(__type, __weak);                        \
> > -     __t->val.str = strdup(__val);                           \
> > -     if (!__t->val.str) {                                    \
> > -             zfree(&__t);                                    \
> > -             return -ENOMEM;                                 \
> > -     }                                                       \
> > -     __t->free_str = true;                                   \
> > -} while (0)
> > +     t = zalloc(sizeof(*t));
> > +     if (!t)
> > +             return NULL;
> > +
> > +     INIT_LIST_HEAD(&t->list);
> > +     t->type = type;
> > +     t->weak = weak;
> > +     list_add_tail(&t->list, head_terms);
> >
> > +     return t;
> > +}
> > +
> > +static int get_config_terms(const struct parse_events_terms *head_config,
> > +                         struct list_head *head_terms)
> > +{
> >       struct parse_events_term *term;
> >
> >       list_for_each_entry(term, &head_config->terms, list) {
> > +             struct evsel_config_term *new_term;
> > +             enum evsel_term_type new_type;
> > +             char *str = NULL;
> > +             u64 val;
> > +
> >               switch (term->type_term) {
> >               case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
> > -                     ADD_CONFIG_TERM_VAL(PERIOD, period, term->val.num, term->weak);
> > +                     new_type = EVSEL__CONFIG_TERM_PERIOD;
> > +                     val = term->val.num;
> >                       break;
> >               case PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ:
> > -                     ADD_CONFIG_TERM_VAL(FREQ, freq, term->val.num, term->weak);
> > +                     new_type = EVSEL__CONFIG_TERM_FREQ;
> > +                     val = term->val.num;
> >                       break;
> >               case PARSE_EVENTS__TERM_TYPE_TIME:
> > -                     ADD_CONFIG_TERM_VAL(TIME, time, term->val.num, term->weak);
> > +                     new_type = EVSEL__CONFIG_TERM_TIME;
> > +                     val = term->val.num;
> >                       break;
> >               case PARSE_EVENTS__TERM_TYPE_CALLGRAPH:
> > -                     ADD_CONFIG_TERM_STR(CALLGRAPH, term->val.str, term->weak);
> > +                     new_type = EVSEL__CONFIG_TERM_CALLGRAPH;
> > +                     str = term->val.str;
> >                       break;
> >               case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
> > -                     ADD_CONFIG_TERM_STR(BRANCH, term->val.str, term->weak);
> > +                     new_type = EVSEL__CONFIG_TERM_BRANCH;
> > +                     str = term->val.str;
> >                       break;
> >               case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
> > -                     ADD_CONFIG_TERM_VAL(STACK_USER, stack_user,
> > -                                         term->val.num, term->weak);
> > +                     new_type = EVSEL__CONFIG_TERM_STACK_USER;
> > +                     val = term->val.num;
> >                       break;
> >               case PARSE_EVENTS__TERM_TYPE_INHERIT:
> > -                     ADD_CONFIG_TERM_VAL(INHERIT, inherit,
> > -                                         term->val.num ? 1 : 0, term->weak);
> > +                     new_type = EVSEL__CONFIG_TERM_INHERIT;
> > +                     val = term->val.num ? 1 : 0;
> >                       break;
> >               case PARSE_EVENTS__TERM_TYPE_NOINHERIT:
> > -                     ADD_CONFIG_TERM_VAL(INHERIT, inherit,
> > -                                         term->val.num ? 0 : 1, term->weak);
> > +                     new_type = EVSEL__CONFIG_TERM_INHERIT;
> > +                     val = term->val.num ? 0 : 1;
> >                       break;
> >               case PARSE_EVENTS__TERM_TYPE_MAX_STACK:
> > -                     ADD_CONFIG_TERM_VAL(MAX_STACK, max_stack,
> > -                                         term->val.num, term->weak);
> > +                     new_type = EVSEL__CONFIG_TERM_MAX_STACK;
> > +                     val = term->val.num;
> >                       break;
> >               case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS:
> > -                     ADD_CONFIG_TERM_VAL(MAX_EVENTS, max_events,
> > -                                         term->val.num, term->weak);
> > +                     new_type = EVSEL__CONFIG_TERM_MAX_EVENTS;
> > +                     val = term->val.num;
> >                       break;
> >               case PARSE_EVENTS__TERM_TYPE_OVERWRITE:
> > -                     ADD_CONFIG_TERM_VAL(OVERWRITE, overwrite,
> > -                                         term->val.num ? 1 : 0, term->weak);
> > +                     new_type = EVSEL__CONFIG_TERM_OVERWRITE;
> > +                     val = term->val.num ? 1 : 0;
> >                       break;
> >               case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE:
> > -                     ADD_CONFIG_TERM_VAL(OVERWRITE, overwrite,
> > -                                         term->val.num ? 0 : 1, term->weak);
> > +                     new_type = EVSEL__CONFIG_TERM_OVERWRITE;
> > +                     val = term->val.num ? 0 : 1;
> >                       break;
> >               case PARSE_EVENTS__TERM_TYPE_DRV_CFG:
> > -                     ADD_CONFIG_TERM_STR(DRV_CFG, term->val.str, term->weak);
> > +                     new_type = EVSEL__CONFIG_TERM_DRV_CFG;
> > +                     str = term->val.str;
> >                       break;
> >               case PARSE_EVENTS__TERM_TYPE_PERCORE:
> > -                     ADD_CONFIG_TERM_VAL(PERCORE, percore,
> > -                                         term->val.num ? true : false, term->weak);
> > +                     new_type = EVSEL__CONFIG_TERM_PERCORE;
> > +                     val = term->val.num ? true : false;
> >                       break;
> >               case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT:
> > -                     ADD_CONFIG_TERM_VAL(AUX_OUTPUT, aux_output,
> > -                                         term->val.num ? 1 : 0, term->weak);
> > +                     new_type = EVSEL__CONFIG_TERM_AUX_OUTPUT;
> > +                     val = term->val.num ? 1 : 0;
> >                       break;
> >               case PARSE_EVENTS__TERM_TYPE_AUX_ACTION:
> > -                     ADD_CONFIG_TERM_STR(AUX_ACTION, term->val.str, term->weak);
> > +                     new_type = EVSEL__CONFIG_TERM_AUX_ACTION;
> > +                     str = term->val.str;
> >                       break;
> >               case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE:
> > -                     ADD_CONFIG_TERM_VAL(AUX_SAMPLE_SIZE, aux_sample_size,
> > -                                         term->val.num, term->weak);
> > +                     new_type = EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE;
> > +                     val = term->val.num;
> >                       break;
> >               case PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV:
> > -                     ADD_CONFIG_TERM_STR(RATIO_TO_PREV, term->val.str, term->weak);
> > +                     new_type = EVSEL__CONFIG_TERM_RATIO_TO_PREV;
> > +                     str = term->val.str;
> >                       break;
> >               case PARSE_EVENTS__TERM_TYPE_USER:
> >               case PARSE_EVENTS__TERM_TYPE_CONFIG:
> > @@ -1229,7 +1231,23 @@ do {                                                           \
> >               case PARSE_EVENTS__TERM_TYPE_RAW:
> >               case PARSE_EVENTS__TERM_TYPE_CPU:
> >               default:
> > -                     break;
> > +                     /* Don't add a new term for these ones */
> > +                     continue;
> > +             }
> > +
> > +             new_term = add_config_term(new_type, head_terms, term->weak);
> > +             if (!new_term)
> > +                     return -ENOMEM;
> > +
> > +             if (str) {
> > +                     new_term->val.str = strdup(str);
> > +                     if (!new_term->val.str) {
> > +                             zfree(&new_term);
> > +                             return -ENOMEM;
> > +                     }
> > +                     new_term->free_str = true;
> > +             } else {
>
> This will incorrectly hit the else if term->val.str is NULL. Not sure if
> that can happen but will fix anyway.
>
> > +                     new_term->val.val = val;
>
> There's an uninitialized variable warning for val here on release
> builds. Will fix too

I'm not sure how I feel about the change, but did you check that it is
ubsan clean? I worry it is introducing writes to "val" and then reads
from say "period" in the evsel_config_term val union. I believe ubsan
will flag this as:
https://en.cppreference.com/w/cpp/language/union.html
"It is undefined behavior to read from the member of the union that
wasn't most recently written."

Thanks,
Ian

> >               }
> >       }
> >       return 0;
> > @@ -1290,10 +1308,16 @@ static int get_config_chgs(struct perf_pmu *pmu, struct parse_events_terms *head
> >               }
> >       }
> >
> > -     if (bits)
> > -             ADD_CONFIG_TERM_VAL(CFG_CHG, cfg_chg, bits, false);
> > +     if (bits) {
> > +             struct evsel_config_term *new_term;
> > +
> > +             new_term = add_config_term(EVSEL__CONFIG_TERM_CFG_CHG,
> > +                                        head_terms, false);
> > +             if (!new_term)
> > +                     return -ENOMEM;
> > +             new_term->val.cfg_chg = bits;
> > +     }
> >
> > -#undef ADD_CONFIG_TERM
> >       return 0;
> >   }
> >
> >
>


From Frank.li at nxp.com  Tue Dec  9 08:05:05 2025
From: Frank.li at nxp.com (Frank Li)
Date: Tue, 9 Dec 2025 11:05:05 -0500
Subject: [PATCH] remoteproc: imx_rproc: Use strstarts for "rsc-table"
 check
In-Reply-To: <20251208233302.684139-1-shenwei.wang@nxp.com>
References: <20251208233302.684139-1-shenwei.wang@nxp.com>
Message-ID: <aThIsUU22pdulMrJ@lizhi-Precision-Tower-5810>

On Mon, Dec 08, 2025 at 05:33:02PM -0600, Shenwei Wang wrote:
> The resource name may include an address suffix, for example:
> rsc-table at 1fff8000.
>
> To handle such cases, use strstarts() instead of strcmp() when checking
> for "rsc-table".
>
> Signed-off-by: Shenwei Wang <shenwei.wang at nxp.com>
> ---

Reviewed-by: Frank Li <Frank.Li at nxp.com>

>  drivers/remoteproc/imx_rproc.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
> index 3be8790c14a2..33f21ab24c92 100644
> --- a/drivers/remoteproc/imx_rproc.c
> +++ b/drivers/remoteproc/imx_rproc.c
> @@ -694,7 +694,7 @@ static int imx_rproc_addr_init(struct imx_rproc *priv,
>  		}
>  		priv->mem[b].sys_addr = res.start;
>  		priv->mem[b].size = resource_size(&res);
> -		if (!strcmp(res.name, "rsc-table"))
> +		if (strstarts(res.name, "rsc-table"))
>  			priv->rsc_table = priv->mem[b].cpu_addr;
>  		b++;
>  	}
> --
> 2.43.0
>


From leo.yan at arm.com  Tue Dec  9 08:06:10 2025
From: leo.yan at arm.com (Leo Yan)
Date: Tue, 9 Dec 2025 16:06:10 +0000
Subject: [PATCH 06/19] coresight: trbe: Refactor syndrome decoding
In-Reply-To: <1c1092e6-aa5d-4bb1-84e5-81151a02cc6f@linaro.org>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-6-7da32b076b28@arm.com>
 <65c84357-0bda-454f-88c3-623b3ff9d29d@arm.com>
 <1c1092e6-aa5d-4bb1-84e5-81151a02cc6f@linaro.org>
Message-ID: <20251209160610.GY724103@e132581.arm.com>

On Tue, Dec 09, 2025 at 01:17:50PM +0000, James Clark wrote:

[...]

> > > +??? pr_err_ratelimited("%s on CPU %d [TRBSR=0x%016llx,
> > > TRBPTR=0x%016llx, TRBLIMITR=0x%016llx]\n",
> > > +?????????????? err_str, smp_processor_id(), trbsr,
> > > +?????????????? read_sysreg_s(SYS_TRBPTR_EL1),
> > > +?????????????? read_sysreg_s(SYS_TRBLIMITR_EL1));
> 
> Don't you need to use %p to not leak pointers?

I will use "%pK" instead for debugging purpose when set
kptr_restrict=0.

> > > +??? return TRBE_FAULT_ACT_FATAL;
> > > ? }
> > > ? static unsigned long trbe_get_trace_size(struct perf_output_handle
> > > *handle,
> > > diff --git a/drivers/hwtracing/coresight/coresight-trbe.h b/drivers/
> > > hwtracing/coresight/coresight-trbe.h
> > > index 45202c48accec7c86ba56130e2737bc2d1830fae..d7f7cd763c0c7139cf322b7336ee563073e3bea0
> > > 100644
> > > --- a/drivers/hwtracing/coresight/coresight-trbe.h
> > > +++ b/drivers/hwtracing/coresight/coresight-trbe.h
> > > @@ -35,9 +35,11 @@ static inline bool is_trbe_enabled(void)
> > > ????? return trblimitr & TRBLIMITR_EL1_E;
> > > ? }
> > > -#define TRBE_EC_OTHERS??????? 0
> > > -#define TRBE_EC_STAGE1_ABORT??? 36
> > > -#define TRBE_EC_STAGE2_ABORT??? 37
> > > +#define TRBE_EC_OTHERS??????????? 0x0
> > > +#define TRBE_EC_GP_CHECK_FAULT??????? 0X1e
> > > +#define TRBE_EC_BUF_MGMT_IMPL??????? 0x1f
> > > +#define TRBE_EC_STAGE1_ABORT??????? 0x24
> > > +#define TRBE_EC_STAGE2_ABORT??????? 0x25
> 
> I know some were already defined here, but this should probably be an enum
> in sysreg.

Good point.  Will do.

Thanks,
Leo


From Frank.li at nxp.com  Tue Dec  9 08:11:31 2025
From: Frank.li at nxp.com (Frank Li)
Date: Tue, 9 Dec 2025 11:11:31 -0500
Subject: [PATCH 2/7] ASoC: dt-bindings: update tdm-slot.txt references to
 tdm-slot.yaml
In-Reply-To: <20251209-tdm-idle-slots-v1-2-38dabf6bc01e@gmail.com>
References: <20251209-tdm-idle-slots-v1-0-38dabf6bc01e@gmail.com>
 <20251209-tdm-idle-slots-v1-2-38dabf6bc01e@gmail.com>
Message-ID: <aThKMzyrr1oY35Vj@lizhi-Precision-Tower-5810>

On Tue, Dec 09, 2025 at 07:31:15PM +1000, James Calligeros wrote:
> Ensure that all references to tdm-slot.txt have been updated to
> tdm-slot.yaml.
>
> Achieved by running "sed -i 's/tdm-slot.txt/tdm-slot.yaml/g' *"
> against the bindings/sound. No other references to the file
> were found in the tree.
>
> Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
> ---
>  .../bindings/sound/imx-audio-card.yaml   | 4 ++--
>  .../bindings/sound/simple-card.yaml      | 4 ++--
>  2 files changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/sound/imx-audio-card.yaml b/Documentation/devicetree/bindings/sound/imx-audio-card.yaml
> index 3c75c8c78987..1df29a556120 100644
> --- a/Documentation/devicetree/bindings/sound/imx-audio-card.yaml
> +++ b/Documentation/devicetree/bindings/sound/imx-audio-card.yaml
> @@ -39,11 +39,11 @@ patternProperties:
>              - dsp_b
>
>        dai-tdm-slot-num:
> -        description: see tdm-slot.txt.
> +        description: see tdm-slot.yaml.
>          $ref: /schemas/types.yaml#/definitions/uint32
>
>        dai-tdm-slot-width:
> -        description: see tdm-slot.txt.
> +        description: see tdm-slot.yaml.
>          $ref: /schemas/types.yaml#/definitions/uint32

remove dai-tdm-slot-num and dai-tdm-slot-width and add

$ref: tdm-slot.yaml

Frank

>
>        playback-only:
> diff --git a/Documentation/devicetree/bindings/sound/simple-card.yaml b/Documentation/devicetree/bindings/sound/simple-card.yaml
> index 533d0a1da56e..2e1a5b3216c5 100644
> --- a/Documentation/devicetree/bindings/sound/simple-card.yaml
> +++ b/Documentation/devicetree/bindings/sound/simple-card.yaml
> @@ -28,11 +28,11 @@ definitions:
>      $ref: /schemas/types.yaml#/definitions/flag
>
>    dai-tdm-slot-num:
> -    description: see tdm-slot.txt.
> +    description: see tdm-slot.yaml.
>      $ref: /schemas/types.yaml#/definitions/uint32
>
>    dai-tdm-slot-width:
> -    description: see tdm-slot.txt.
> +    description: see tdm-slot.yaml.
>      $ref: /schemas/types.yaml#/definitions/uint32
>
>    system-clock-frequency:
>
> --
> 2.52.0
>


From ben.horgan at arm.com  Tue Dec  9 08:14:12 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Tue, 9 Dec 2025 16:14:12 +0000
Subject: [RFC PATCH 00/38] arm_mpam: Add KVM/arm64 and resctrl glue code
In-Reply-To: <CALPaoCgDuA1D+ubUv3UJ0+LyUfjCFKOcrEhg6Q80rNK5idjEmA@mail.gmail.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <41bcd0d2-d5b8-4f3d-b0b3-132387f547ed@arm.com>
 <CALPaoCgDuA1D+ubUv3UJ0+LyUfjCFKOcrEhg6Q80rNK5idjEmA@mail.gmail.com>
Message-ID: <95c9947f-574a-486f-953c-fbac6ead0853@arm.com>

Hi Peter,

On 12/9/25 15:53, Peter Newman wrote:
> Hi Ben,
> 
> On Tue, Dec 9, 2025 at 3:40?PM Ben Horgan <ben.horgan at arm.com> wrote:
>>
>> Hi James and all,
[...]
>>
>> One major departure from the previous snapshot branches referenced in
>> the base driver series is that the same MPAM setting are used for
>> kernel-space and user-space. That is, MPAM1_EL1 is set to the same value
>> as MPAM0_EL1 rather than keeping the default value. The advantages of
>> this are that it is closer to the x86 model where the closid is globally
>> applicable, all partids are usable from user-space and user-space can't
>> bypass MPAM controls by doing the work in the kernel. However, this
>> causes some priority inversion where a high priority task waits to take
>> a mutex held by another whose resources are restricted by MPAM.
>> Thanks,
> 
> In our experience, the disadvantages of the x86 model were worse
> because they triggered on hosts unintentionally, while making the
> kernel do work unrestricted on behalf of the user at least requires
> intentional abuse.
> 
> -Peter

Thanks for the quick feedback. Do you have any more data/information on
this that you can share?

Thanks,

Ben



From Frank.li at nxp.com  Tue Dec  9 08:14:20 2025
From: Frank.li at nxp.com (Frank Li)
Date: Tue, 9 Dec 2025 11:14:20 -0500
Subject: [PATCH v2] pmdomain: imx: Fix reference count leak in
 imx_gpc_probe()
In-Reply-To: <20251209081909.24982-1-vulab@iscas.ac.cn>
References: <20251209081909.24982-1-vulab@iscas.ac.cn>
Message-ID: <aThK3DwGFY1xhvyN@lizhi-Precision-Tower-5810>

On Tue, Dec 09, 2025 at 08:19:09AM +0000, Wentao Liang wrote:
> of_get_child_by_name() returns a node pointer with refcount incremented,
> we should use the __free() attribute to manage the pgc_node reference.
> This ensures automatic of_node_put() cleanup when pgc_node goes out of
> scope, eliminating the need for explicit error handling paths and
> avoiding reference count leaks.
>
> Fixes: 721cabf6c660 ("soc: imx: move PGC handling to a new GPC driver")
> Cc: stable at vger.kernel.org
> Signed-off-by: Wentao Liang <vulab at iscas.ac.cn>
>
> ---
> Change in V2:
> - Use __free() attribute instead of explicit of_node_put() calls
> ---
>  drivers/pmdomain/imx/gpc.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/pmdomain/imx/gpc.c b/drivers/pmdomain/imx/gpc.c
> index f18c7e6e75dd..89d5d68c055d 100644
> --- a/drivers/pmdomain/imx/gpc.c
> +++ b/drivers/pmdomain/imx/gpc.c
> @@ -403,7 +403,7 @@ static int imx_gpc_old_dt_init(struct device *dev, struct regmap *regmap,
>  static int imx_gpc_probe(struct platform_device *pdev)
>  {
>  	const struct imx_gpc_dt_data *of_id_data = device_get_match_data(&pdev->dev);
> -	struct device_node *pgc_node;
> +	struct device_node *pgc_node __free(pgc_node);

struct device_node *pgc_node __free(pgc_node)
	= of_get_child_by_name(pdev->dev.of_node, "pgc");

Make sure pgc_node value assigned when use cleanup. Please see cleanup.h

Frank
>  	struct regmap *regmap;
>  	void __iomem *base;
>  	int ret;
> --
> 2.34.1
>


From ben.horgan at arm.com  Tue Dec  9 08:31:00 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Tue, 9 Dec 2025 16:31:00 +0000
Subject: [RFC PATCH 27/38] arm_mpam: resctrl: Add empty definitions for
 assorted resctrl functions
In-Reply-To: <20251205215901.17772-28-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-28-james.morse@arm.com>
Message-ID: <9b452304-27ea-4c38-8bf1-820cf4d2f0a7@arm.com>

Hi James,

On 12/5/25 21:58, James Morse wrote:
> A few resctrl features and hooks need to be provided, but aren't needed
> or supported on MPAM platforms.
> 
> resctrl has individual hooks to separately enable and disable the
> closid/partid and rmid/pmg context switching code. For MPAM this is all
> the same thing, as the value in struct task_struct is used to cache the
> value that should be written to hardware. arm64's context switching code
> is enabled once MPAM is usable, but doesn't touch the hardware unless
> the value has changed.
> 
> For now event configuration is not supported, and can be turned off
> by returning 'false' from resctrl_arch_is_evt_configurable().
> 
> Add this, and empty definitions for the other hooks.
> 
> Signed-off-by: James Morse <james.morse at arm.com>

The newly added io_alloc support means we need a couple more dummy
resctrl arch functions in here, resctrl_arch_io_alloc_enable() and
resctrl_arch_io_alloc_enabled().

Thanks,

Ben



From ben.horgan at arm.com  Tue Dec  9 08:33:11 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Tue, 9 Dec 2025 16:33:11 +0000
Subject: [RFC PATCH 28/38] arm64: mpam: Select ARCH_HAS_CPU_RESCTRL
In-Reply-To: <20251205215901.17772-29-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-29-james.morse@arm.com>
Message-ID: <4e491c89-a63d-4c13-a0f4-9883a6bc6407@arm.com>

Hi James,

On 12/5/25 21:58, James Morse wrote:
> Enough MPAM support is present to enable ARCH_HAS_CPU_RESCTRL.
> Let it rip^Wlink!
> 
> ARCH_HAS_CPU_RESCTRL indicates resctrl can be enabled. It is enabled
> by the arch code sipmly because it has 'arch' in its name.
> 
> This removes ARM_CPU_RESCTRL as a mimic of X86_CPU_RESCTRL.
> While here, move the ACPI dependency to the driver's Kconfig file.

Mention we're know longer hiding behind CONFIG_EXPERT.

> 
> Signed-off-by: James Morse <james.morse at arm.com>
> ---
>  arch/arm64/Kconfig               | 4 ++--
>  arch/arm64/include/asm/resctrl.h | 2 ++
>  drivers/resctrl/Kconfig          | 9 ++++++++-
>  drivers/resctrl/Makefile         | 2 +-
>  4 files changed, 13 insertions(+), 4 deletions(-)
>  create mode 100644 arch/arm64/include/asm/resctrl.h
> 
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 558baa9e7c08..e67885ac7717 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -2025,8 +2025,8 @@ config ARM64_TLB_RANGE
>  
>  config ARM64_MPAM
>  	bool "Enable support for MPAM"
> -	select ARM64_MPAM_DRIVER if EXPERT	# does nothing yet
> -	select ACPI_MPAM if ACPI
> +	select ARM64_MPAM_DRIVER
> +	select ARCH_HAS_CPU_RESCTRL
>  	help
>  	  Memory System Resource Partitioning and Monitoring (MPAM) is an
>  	  optional extension to the Arm architecture that allows each
> diff --git a/arch/arm64/include/asm/resctrl.h b/arch/arm64/include/asm/resctrl.h
> new file mode 100644
> index 000000000000..b506e95cf6e3
> --- /dev/null
> +++ b/arch/arm64/include/asm/resctrl.h
> @@ -0,0 +1,2 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#include <linux/arm_mpam.h>
> diff --git a/drivers/resctrl/Kconfig b/drivers/resctrl/Kconfig
> index c808e0470394..672abea3b03c 100644
> --- a/drivers/resctrl/Kconfig
> +++ b/drivers/resctrl/Kconfig
> @@ -1,6 +1,7 @@
>  menuconfig ARM64_MPAM_DRIVER
>  	bool "MPAM driver"
> -	depends on ARM64 && ARM64_MPAM && EXPERT
> +	depends on ARM64 && ARM64_MPAM
> +	select ACPI_MPAM if ACPI
>  	help
>  	  Memory System Resource Partitioning and Monitoring (MPAM) driver for
>  	  System IP, e.g. caches and memory controllers.
> @@ -22,3 +23,9 @@ config MPAM_KUNIT_TEST
>  	  If unsure, say N.
>  
>  endif
> +
> +config ARM64_MPAM_RESCTRL_FS
> +	bool
> +	default y if ARM64_MPAM_DRIVER && RESCTRL_FS
> +	select RESCTRL_RMID_DEPENDS_ON_CLOSID
> +	select RESCTRL_ASSIGN_FIXED
> diff --git a/drivers/resctrl/Makefile b/drivers/resctrl/Makefile
> index 40beaf999582..4f6d0e81f9b8 100644
> --- a/drivers/resctrl/Makefile
> +++ b/drivers/resctrl/Makefile
> @@ -1,5 +1,5 @@
>  obj-$(CONFIG_ARM64_MPAM_DRIVER)			+= mpam.o
>  mpam-y						+= mpam_devices.o
> -mpam-$(CONFIG_ARM_CPU_RESCTRL)			+= mpam_resctrl.o
> +mpam-$(CONFIG_ARM64_MPAM_RESCTRL_FS)		+= mpam_resctrl.o
>  
>  ccflags-$(CONFIG_ARM64_MPAM_DRIVER_DEBUG)	+= -DDEBUG

Thanks,

Ben



From louisalexis.eyraud at collabora.com  Tue Dec  9 08:34:30 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Tue, 09 Dec 2025 17:34:30 +0100
Subject: [PATCH 00/12] Add HDMI support for Mediatek Genio 510/700/1200-EVK
 and Radxa NIO-12L boards
Message-ID: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>

This patch series adds and enables the HDMI output support for the
following boards:
- Mediatek Genio 510-EVK (MT8370)
- Mediatek Genio 700-EVK (MT8390)
- Mediatek Genio 1200-EVK (MT8395)
- Radxa NIO-12L (MT8395)

Patch 1 is a 'mediatek,hdmi-phy' dt-binding fix for MT8195 SoC and a
revised version of [1], that addresses previous feedback from mailing
list ([2]).
Patch 2 was split from [1] into a separate patch and adds a MT8188 SoC
compatible in 'mediatek,hdmi-phy' dt-binding.
Patch 3 documents in 'mediatek,hdmi-phy' dt-binding extra clocks for
MT8195 SoC.
Patch 4 adds all of the nodes that are required to enable HDMI output
for MT8195 SoC and its variant (MT8395).
Patch 5 adds the same but for MT8188 SoC and its variants (MT8370,
MT8390).
Patches 6 to 11 enable HDMI output and sound support for each board.
Patch 12 enables the Mediatek HDMIv2 driver as module in defconfig.

The series is based on linux-next (tag: next-20251209).

[1] https://lore.kernel.org/linux-mediatek/20250724083914.61351-16-angelogioacchino.delregno at collabora.com/
[2] https://lore.kernel.org/linux-mediatek/ee525312-bde1-4724-b32f-83be32c87696 at kernel.org/

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
AngeloGioacchino Del Regno (5):
      dt-bindings: phy: mediatek,hdmi-phy: Fix clock output names for MT8195
      arm64: dts: mediatek: mt8195: Add DPI1, HDMI, HDMI PHY/DDC nodes
      arm64: dts: mediatek: mt8188: Add DPI1, HDMI, HDMI PHY/DDC nodes
      arm64: dts: mediatek: mt8390-genio-common: Enable HDMI output
      arm64: dts: mediatek: mt8395-radxa-nio-12l: Enable HDMI output

Louis-Alexis Eyraud (6):
      dt-bindings: phy: mediatek,hdmi-phy: Add support for MT8188 SoC
      arm64: dts: mediatek: mt8390-genio-common: Add HDMI sound output support
      arm64: dts: mediatek: mt8395-radxa-nio-12l: Add HDMI sound output support
      arm64: dts: mediatek: mt8395-genio-common: Enable HDMI output
      arm64: dts: mediatek: mt8395-genio-common: Add HDMI sound output support
      arm64: defconfig: Enable Mediatek HDMIv2 driver

N?colas F. R. A. Prado (1):
      dt-bindings: phy: mediatek,hdmi-phy: Document extra clocks for MT8195

 .../devicetree/bindings/phy/mediatek,hdmi-phy.yaml |  43 +++++-
 arch/arm64/boot/dts/mediatek/mt8188.dtsi           |  82 +++++++++++
 arch/arm64/boot/dts/mediatek/mt8195.dtsi           |  86 ++++++++++++
 .../boot/dts/mediatek/mt8390-genio-common.dtsi     | 150 +++++++++++++++++++++
 .../boot/dts/mediatek/mt8395-genio-common.dtsi     | 150 +++++++++++++++++++++
 .../boot/dts/mediatek/mt8395-radxa-nio-12l.dts     | 150 +++++++++++++++++++++
 arch/arm64/configs/defconfig                       |   1 +
 7 files changed, 656 insertions(+), 6 deletions(-)
---
base-commit: 8ebfd5290c6162d65f83f9a8acdbbf243b49a586
change-id: 20251203-mtk-genio-evk-hdmi-support-17da5161827a

Best regards,
-- 
Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>



From louisalexis.eyraud at collabora.com  Tue Dec  9 08:34:32 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Tue, 09 Dec 2025 17:34:32 +0100
Subject: [PATCH 02/12] dt-bindings: phy: mediatek,hdmi-phy: Add support for
 MT8188 SoC
In-Reply-To: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>
References: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>
Message-ID: <20251209-mtk-genio-evk-hdmi-support-v1-2-9a6106effba6@collabora.com>

Add compatible string for the HDMI PHY IP on MT8188 SoC, that is
compatible with the one found on MT8195 SoC.

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml
index 10f1d9326f18dba85b92b4c88f4c0f6cdddc4c25..cd4ac42ee45e4648ed512f68f6f28d1f3f2e1116 100644
--- a/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml
@@ -26,6 +26,10 @@ properties:
           - enum:
               - mediatek,mt7623-hdmi-phy
           - const: mediatek,mt2701-hdmi-phy
+      - items:
+          - enum:
+              - mediatek,mt8188-hdmi-phy
+          - const: mediatek,mt8195-hdmi-phy
       - const: mediatek,mt2701-hdmi-phy
       - const: mediatek,mt8173-hdmi-phy
       - const: mediatek,mt8195-hdmi-phy

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Tue Dec  9 08:34:31 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Tue, 09 Dec 2025 17:34:31 +0100
Subject: [PATCH 01/12] dt-bindings: phy: mediatek,hdmi-phy: Fix clock
 output names for MT8195
In-Reply-To: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>
References: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>
Message-ID: <20251209-mtk-genio-evk-hdmi-support-v1-1-9a6106effba6@collabora.com>

From: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>

For all of the HDMI PHYs compatible with the one found on MT8195
the output clock has a different datasheet name and specifically
it is called "hdmi_txpll", differently from the older HDMI PHYs
which output block is called "hdmitx_dig_cts".

Replace clock output name string check by max item number one to allow
the new name on all of the HDMI PHY IPs that are perfectly compatible
with MT8195.

Fixes: c78fe548b062 ("dt-bindings: phy: mediatek: hdmi-phy: Add mt8195 compatible")
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
[Louis-Alexis Eyraud: splitted patch, addressed previous feedback from
mailing list, and reworded description]
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml
index f3a8b0b745d13ffc55d391570bff20830d925ed3..10f1d9326f18dba85b92b4c88f4c0f6cdddc4c25 100644
--- a/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml
@@ -42,8 +42,7 @@ properties:
       - const: pll_ref
 
   clock-output-names:
-    items:
-      - const: hdmitx_dig_cts
+    maxItems: 1
 
   "#phy-cells":
     const: 0

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Tue Dec  9 08:34:33 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Tue, 09 Dec 2025 17:34:33 +0100
Subject: [PATCH 03/12] dt-bindings: phy: mediatek,hdmi-phy: Document extra
 clocks for MT8195
In-Reply-To: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>
References: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>
Message-ID: <20251209-mtk-genio-evk-hdmi-support-v1-3-9a6106effba6@collabora.com>

From: "N?colas F. R. A. Prado" <nfraprado at collabora.com>

MT8195's HDMI PHY block has 4 clocks instead of just a single one.
Describe the extra clocks for it.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 .../devicetree/bindings/phy/mediatek,hdmi-phy.yaml | 36 +++++++++++++++++++---
 1 file changed, 32 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml
index cd4ac42ee45e4648ed512f68f6f28d1f3f2e1116..91f8118689d5e838c4d75264822bb09a00fea21b 100644
--- a/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml
@@ -38,12 +38,12 @@ properties:
     maxItems: 1
 
   clocks:
-    items:
-      - description: PLL reference clock
+    minItems: 1
+    maxItems: 4
 
   clock-names:
-    items:
-      - const: pll_ref
+    minItems: 1
+    maxItems: 4
 
   clock-output-names:
     maxItems: 1
@@ -79,6 +79,34 @@ required:
   - "#phy-cells"
   - "#clock-cells"
 
+allOf:
+  - if:
+      properties:
+        compatible:
+          const: mediatek,mt8195-hdmi-phy
+    then:
+      properties:
+        clocks:
+          items:
+            - description: PLL reference clock
+            - description: HDMI 26MHz clock
+            - description: HDMI PLL1 clock
+            - description: HDMI PLL2 clock
+        clock-names:
+          items:
+            - const: pll_ref
+            - const: hdmi_26m
+            - const: hdmi_pll1
+            - const: hdmi_pll2
+    else:
+      properties:
+        clocks:
+          items:
+            - description: PLL reference clock
+        clock-names:
+          items:
+            - const: pll_ref
+
 additionalProperties: false
 
 examples:

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Tue Dec  9 08:34:34 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Tue, 09 Dec 2025 17:34:34 +0100
Subject: [PATCH 04/12] arm64: dts: mediatek: mt8195: Add DPI1, HDMI, HDMI
 PHY/DDC nodes
In-Reply-To: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>
References: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>
Message-ID: <20251209-mtk-genio-evk-hdmi-support-v1-4-9a6106effba6@collabora.com>

From: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>

Add all of the nodes that are required to enable HDMI output,
including ones describing the HDMI PHY, Controller and DDC,
and the Digital Parallel Interface instance that is internally
connected to the HDMI Controller.

All of the added nodes are disabled by default as usage is
board dependent.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 arch/arm64/boot/dts/mediatek/mt8195.dtsi | 86 ++++++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8195.dtsi b/arch/arm64/boot/dts/mediatek/mt8195.dtsi
index c7adafaa83288d2d86ddf45c97cc984344e1ff77..49e52dde247f29b57d34a25b33f2d5f36f745f30 100644
--- a/arch/arm64/boot/dts/mediatek/mt8195.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8195.dtsi
@@ -26,8 +26,10 @@ / {
 	aliases {
 		dp-intf0 = &dp_intf0;
 		dp-intf1 = &dp_intf1;
+		dpi1 = &dpi1;
 		gce0 = &gce0;
 		gce1 = &gce1;
+		hdmi0 = &hdmi;
 		ethdr0 = &ethdr0;
 		mutex0 = &mutex;
 		mutex1 = &mutex1;
@@ -1857,6 +1859,24 @@ imp_iic_wrap_s: clock-controller at 11d03000 {
 			#clock-cells = <1>;
 		};
 
+		hdmi_phy: hdmi-phy at 11d5f000 {
+			compatible = "mediatek,mt8195-hdmi-phy";
+			reg = <0 0x11d5f000 0 0x100>;
+			clocks = <&topckgen CLK_TOP_HDMI_XTAL>,
+				 <&infracfg_ao CLK_INFRA_AO_HDMI_26M>,
+				 <&apmixedsys CLK_APMIXED_HDMIPLL1>,
+				 <&apmixedsys CLK_APMIXED_HDMIPLL2>;
+			clock-names = "pll_ref", "hdmi_26m",
+				      "hdmi_pll1", "hdmi_pll2";
+			clock-output-names = "hdmi_txpll";
+
+			#clock-cells = <0>;
+			#phy-cells = <0>;
+			mediatek,ibias = <0xa>;
+			mediatek,ibias_up = <0x1c>;
+			status = "disabled";
+		};
+
 		i2c0: i2c at 11e00000 {
 			compatible = "mediatek,mt8195-i2c",
 				     "mediatek,mt8192-i2c";
@@ -3670,6 +3690,34 @@ merge5: vpp-merge at 1c110000 {
 			resets = <&vdosys1 MT8195_VDOSYS1_SW0_RST_B_MERGE4_DL_ASYNC>;
 		};
 
+		dpi1: dpi at 1c112000 {
+			compatible = "mediatek,mt8195-dpi";
+			reg = <0 0x1c112000 0 0x1000>;
+			clocks = <&vdosys1 CLK_VDO1_DPI1>,
+				 <&vdosys1 CLK_VDO1_DPI1_MM>,
+				 <&vdosys1 CLK_VDO1_DPI1_HDMI>;
+			clock-names = "pixel", "engine", "pll";
+			interrupts = <GIC_SPI 512 IRQ_TYPE_LEVEL_HIGH 0>;
+			power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>;
+			resets = <&vdosys1 MT8195_VDOSYS1_SW0_RST_B_DPI1>;
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+					dpi1_in: endpoint { };
+				};
+
+				port at 1 {
+					reg = <1>;
+					dpi1_out: endpoint { };
+				};
+			};
+		};
+
 		dp_intf1: dp-intf at 1c113000 {
 			compatible = "mediatek,mt8195-dp-intf";
 			reg = <0 0x1c113000 0 0x1000>;
@@ -3730,6 +3778,44 @@ ethdr0: hdr-engine at 1c114000 {
 				      "gfx_fe1_async", "vdo_be_async";
 		};
 
+		hdmi: hdmi-tx at 1c300000 {
+			compatible = "mediatek,mt8195-hdmi-tx";
+			#sound-dai-cells = <1>;
+			reg = <0 0x1c300000 0 0x1000>;
+			clocks = <&topckgen CLK_TOP_HDMI_APB>,
+				 <&topckgen CLK_TOP_HDCP>,
+				 <&topckgen CLK_TOP_HDCP_24M>,
+				 <&vppsys1 CLK_VPP1_VPP_SPLIT_HDMI>;
+			clock-names = "bus", "hdcp", "hdcp24m", "hdmi-split";
+			assigned-clocks = <&topckgen CLK_TOP_HDCP>;
+			assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D4_D8>;
+			interrupts = <GIC_SPI 677 IRQ_TYPE_LEVEL_HIGH 0>;
+			power-domains = <&spm MT8195_POWER_DOMAIN_HDMI_TX>;
+			phys = <&hdmi_phy>;
+			phy-names = "hdmi";
+			status = "disabled";
+
+			hdmitx_ddc: i2c {
+				compatible = "mediatek,mt8195-hdmi-ddc";
+				clocks = <&clk26m>;
+			};
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+					hdmi0_in: endpoint { };
+				};
+
+				port at 1 {
+					reg = <1>;
+					hdmi0_out: endpoint { };
+				};
+			};
+		};
+
 		edp_tx: edp-tx at 1c500000 {
 			compatible = "mediatek,mt8195-edp-tx";
 			reg = <0 0x1c500000 0 0x8000>;

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Tue Dec  9 08:34:35 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Tue, 09 Dec 2025 17:34:35 +0100
Subject: [PATCH 05/12] arm64: dts: mediatek: mt8188: Add DPI1, HDMI, HDMI
 PHY/DDC nodes
In-Reply-To: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>
References: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>
Message-ID: <20251209-mtk-genio-evk-hdmi-support-v1-5-9a6106effba6@collabora.com>

From: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>

Add all of the nodes that are required to enable HDMI output,
including ones describing the HDMI PHY, Controller and DDC,
and the Digital Parallel Interface instance that is internally
connected to the HDMI Controller.

All of the added nodes are disabled by default as usage is
board dependent.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
[Louis-Alexis Eyraud: reworded subject and description]
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 arch/arm64/boot/dts/mediatek/mt8188.dtsi | 82 ++++++++++++++++++++++++++++++++
 1 file changed, 82 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8188.dtsi b/arch/arm64/boot/dts/mediatek/mt8188.dtsi
index 90c388f1890f5139be6a9513c4cd9b683a501279..e2a17359e407f0bdd3ae6ef8ade668e67a9bd493 100644
--- a/arch/arm64/boot/dts/mediatek/mt8188.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8188.dtsi
@@ -26,6 +26,7 @@ / {
 	aliases {
 		dp-intf0 = &dp_intf0;
 		dp-intf1 = &dp_intf1;
+		dpi1 = &dpi1;
 		dsc0 = &dsc0;
 		ethdr0 = &ethdr0;
 		gce0 = &gce0;
@@ -2038,6 +2039,19 @@ pcieport: pcie-phy at 0 {
 			};
 		};
 
+		hdmi_phy: hdmi-phy at 11d5f000 {
+			compatible = "mediatek,mt8188-hdmi-phy", "mediatek,mt8195-hdmi-phy";
+			reg = <0 0x11d5f000 0 0x100>;
+			clocks = <&infracfg_ao CLK_INFRA_AO_HDMI_26M>;
+			clock-names = "pll_ref";
+			clock-output-names = "hdmi_txpll";
+			#clock-cells = <0>;
+			#phy-cells = <0>;
+			mediatek,ibias = <0xa>;
+			mediatek,ibias_up = <0x1c>;
+			status = "disabled";
+		};
+
 		mipi_tx_config0: dsi-phy at 11c80000 {
 			compatible = "mediatek,mt8188-mipi-tx", "mediatek,mt8183-mipi-tx";
 			reg = <0 0x11c80000 0 0x1000>;
@@ -3406,6 +3420,34 @@ merge5: merge at 1c110000 {
 			mediatek,merge-fifo-en;
 		};
 
+		dpi1: dpi at 1c112000 {
+			compatible = "mediatek,mt8188-dpi", "mediatek,mt8195-dpi";
+			reg = <0 0x1c112000 0 0x1000>;
+			clocks = <&vdosys1 CLK_VDO1_DPI1>,
+				 <&vdosys1 CLK_VDO1_DPI1_MM>,
+				 <&vdosys1 CLK_VDO1_DPI1_HDMI>;
+			clock-names = "pixel", "engine", "pll";
+			interrupts = <GIC_SPI 524 IRQ_TYPE_LEVEL_HIGH 0>;
+			power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>;
+			resets = <&vdosys1 MT8188_VDO1_RST_DPI1_MM_CK>;
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+					dpi1_in: endpoint { };
+				};
+
+				port at 1 {
+					reg = <1>;
+					dpi1_out: endpoint { };
+				};
+			};
+		};
+
 		dp_intf1: dp-intf at 1c113000 {
 			compatible = "mediatek,mt8188-dp-intf";
 			reg = <0 0x1c113000 0 0x1000>;
@@ -3530,6 +3572,46 @@ padding7: padding at 1c124000 {
 			mediatek,gce-client-reg = <&gce0 SUBSYS_1c12XXXX 0x4000 0x1000>;
 		};
 
+		hdmi: hdmi at 1c300000 {
+			compatible = "mediatek,mt8188-hdmi-tx";
+			#sound-dai-cells = <1>;
+			reg = <0 0x1c300000 0 0x1000>;
+			clocks = <&topckgen CLK_TOP_HDMI_APB>,
+				 <&topckgen CLK_TOP_HDCP>,
+				 <&topckgen CLK_TOP_HDCP_24M>,
+				 <&vppsys1 CLK_VPP1_VPP_SPLIT_HDMI>;
+			clock-names = "bus", "hdcp", "hdcp24m", "hdmi-split";
+			assigned-clocks = <&topckgen CLK_TOP_HDCP>;
+			assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D4_D8>;
+			interrupts = <GIC_SPI 686 IRQ_TYPE_LEVEL_HIGH 0>;
+			power-domains = <&spm MT8188_POWER_DOMAIN_HDMI_TX>;
+			phys = <&hdmi_phy>;
+			phy-names = "hdmi";
+			status = "disabled";
+
+			hdmi_ddc: i2c {
+				compatible = "mediatek,mt8188-hdmi-ddc",
+					     "mediatek,mt8195-hdmi-ddc";
+				clocks = <&clk26m>;
+			};
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+					hdmi0_in: endpoint { };
+				};
+
+				port at 1 {
+					reg = <1>;
+					hdmi0_out: endpoint { };
+				};
+			};
+		};
+
+
 		edp_tx: edp-tx at 1c500000 {
 			compatible = "mediatek,mt8188-edp-tx";
 			reg = <0 0x1c500000 0 0x8000>;

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Tue Dec  9 08:34:36 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Tue, 09 Dec 2025 17:34:36 +0100
Subject: [PATCH 06/12] arm64: dts: mediatek: mt8390-genio-common: Enable
 HDMI output
In-Reply-To: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>
References: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>
Message-ID: <20251209-mtk-genio-evk-hdmi-support-v1-6-9a6106effba6@collabora.com>

From: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>

Add a node for the HDMI-A connector found on this board, then
configure the display pipeline and enable the required DPI1
interface, HDMI controller, its integrated DDC and the HDMI
PHY to enable support for the HDMI output provided by these EVKs.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
[Louis-Alexis Eyraud: reworded subject and description]
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 .../boot/dts/mediatek/mt8390-genio-common.dtsi     | 141 +++++++++++++++++++++
 1 file changed, 141 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8390-genio-common.dtsi b/arch/arm64/boot/dts/mediatek/mt8390-genio-common.dtsi
index a2cdecd2b9034e2f295d817e846d6ed1845e686a..5fa1f5fbad18f2bf9b153ae9a029829641e43023 100644
--- a/arch/arm64/boot/dts/mediatek/mt8390-genio-common.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8390-genio-common.dtsi
@@ -55,6 +55,20 @@ dmic_codec: dmic-codec {
 		wakeup-delay-ms = <30>;
 	};
 
+	connector {
+		compatible = "hdmi-connector";
+		label = "hdmi";
+		type = "a";
+		ddc-i2c-bus = <&hdmi_ddc>;
+		hdmi-pwr-supply = <&hdmi_phy>;
+
+		port {
+			hdmi_connector_in: endpoint {
+				remote-endpoint = <&hdmi0_out>;
+			};
+		};
+	};
+
 	firmware {
 		optee {
 			compatible = "linaro,optee-tz";
@@ -328,6 +342,18 @@ &dither0_out {
 	remote-endpoint = <&dsi0_in>;
 };
 
+&dpi1 {
+	status = "okay";
+};
+
+&dpi1_in {
+	remote-endpoint = <&merge5_out>;
+};
+
+&dpi1_out {
+	remote-endpoint = <&hdmi0_in>;
+};
+
 &gamma0_out {
 	remote-endpoint = <&postmask0_in>;
 };
@@ -337,6 +363,55 @@ &gpu {
 	status = "okay";
 };
 
+&ethdr0 {
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			ethdr0_in: endpoint at 1 {
+				reg = <1>;
+				remote-endpoint = <&vdosys1_ep_ext>;
+			};
+		};
+
+		port at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			ethdr0_out: endpoint at 1 {
+				reg = <1>;
+				remote-endpoint = <&merge5_in>;
+			};
+		};
+	};
+};
+
+&hdmi {
+	pinctrl-names = "default";
+	pinctrl-0 = <&hdmi_pins>;
+	status = "okay";
+};
+
+&hdmi0_in {
+	remote-endpoint = <&dpi1_out>;
+};
+
+&hdmi0_out {
+	remote-endpoint = <&hdmi_connector_in>;
+};
+
+&hdmi_phy {
+	pinctrl-names = "default";
+	pinctrl-0 = <&hdmi_vreg_pins>;
+	status = "okay";
+};
+
 &i2c0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&i2c0_pins>;
@@ -475,6 +550,35 @@ &i2c6 {
 	status = "okay";
 };
 
+&merge5 {
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			merge5_in: endpoint at 1 {
+				reg = <1>;
+				remote-endpoint = <&ethdr0_out>;
+			};
+		};
+
+		port at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			merge5_out: endpoint at 1 {
+				reg = <1>;
+				remote-endpoint = <&dpi1_in>;
+			};
+		};
+	};
+};
+
 &mfg0 {
 	domain-supply = <&mt6359_vproc2_buck_reg>;
 };
@@ -727,6 +831,31 @@ pins-txd {
 		};
 	};
 
+	hdmi_vreg_pins: hdmi-vreg-pins {
+		pins-pwr {
+			pinmux = <PINMUX_GPIO50__FUNC_O_HDMITX20_PWR5V>;
+			bias-disable;
+		};
+	};
+
+	hdmi_pins: hdmi-pins {
+		pins-hotplug {
+			pinmux = <PINMUX_GPIO51__FUNC_I0_HDMITX20_HTPLG>;
+			bias-pull-down;
+		};
+
+		pins-cec {
+			pinmux = <PINMUX_GPIO52__FUNC_B1_HDMITX20_CEC>;
+			bias-disable;
+		};
+
+		pins-ddc {
+			pinmux = <PINMUX_GPIO53__FUNC_B1_HDMITX20_SCL>,
+				 <PINMUX_GPIO54__FUNC_B1_HDMITX20_SDA>;
+			drive-strength = <10>;
+		};
+	};
+
 	i2c0_pins: i2c0-pins {
 		pins {
 			pinmux = <PINMUX_GPIO56__FUNC_B1_SDA0>,
@@ -1286,6 +1415,18 @@ connector {
 	};
 };
 
+&vdosys1 {
+	port {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		vdosys1_ep_ext: endpoint at 1 {
+			reg = <1>;
+			remote-endpoint = <&ethdr0_in>;
+		};
+	};
+};
+
 &xhci0 {
 	status = "okay";
 };

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Tue Dec  9 08:34:37 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Tue, 09 Dec 2025 17:34:37 +0100
Subject: [PATCH 07/12] arm64: dts: mediatek: mt8390-genio-common: Add HDMI
 sound output support
In-Reply-To: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>
References: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>
Message-ID: <20251209-mtk-genio-evk-hdmi-support-v1-7-9a6106effba6@collabora.com>

Add in the sound node a new dai-link for ETDM3_OUT_BE to add the sound
output support through the HDMI connector.

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 arch/arm64/boot/dts/mediatek/mt8390-genio-common.dtsi | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8390-genio-common.dtsi b/arch/arm64/boot/dts/mediatek/mt8390-genio-common.dtsi
index 5fa1f5fbad18f2bf9b153ae9a029829641e43023..2062506f6cc523d7797adc8b7e74732be9320201 100644
--- a/arch/arm64/boot/dts/mediatek/mt8390-genio-common.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8390-genio-common.dtsi
@@ -1344,6 +1344,15 @@ codec {
 			sound-dai = <&dmic_codec>;
 		};
 	};
+
+	dai-link-2 {
+		link-name = "ETDM3_OUT_BE";
+
+		codec {
+			sound-dai = <&hdmi 0>;
+		};
+	};
+
 };
 
 &spi2 {

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Tue Dec  9 08:34:38 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Tue, 09 Dec 2025 17:34:38 +0100
Subject: [PATCH 08/12] arm64: dts: mediatek: mt8395-radxa-nio-12l: Enable
 HDMI output
In-Reply-To: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>
References: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>
Message-ID: <20251209-mtk-genio-evk-hdmi-support-v1-8-9a6106effba6@collabora.com>

From: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>

Add a definition for the on-board HDMI connector, enable and add
the relevant configuration for the HDMI PHY and controller, and
define the pins used by those.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 .../boot/dts/mediatek/mt8395-radxa-nio-12l.dts     | 142 +++++++++++++++++++++
 1 file changed, 142 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8395-radxa-nio-12l.dts b/arch/arm64/boot/dts/mediatek/mt8395-radxa-nio-12l.dts
index d32f973f5e0528bc3233ff01f029006dbe6ef894..b0e18876bd5d2341c6f17f47e9f11433be807ccd 100644
--- a/arch/arm64/boot/dts/mediatek/mt8395-radxa-nio-12l.dts
+++ b/arch/arm64/boot/dts/mediatek/mt8395-radxa-nio-12l.dts
@@ -37,6 +37,20 @@ chosen {
 		stdout-path = "serial0:921600n8";
 	};
 
+	connector {
+		compatible = "hdmi-connector";
+		label = "hdmi";
+		type = "a";
+		ddc-i2c-bus = <&hdmitx_ddc>;
+		hdmi-pwr-supply = <&hdmi_phy>;
+
+		port {
+			hdmi_connector_in: endpoint {
+				remote-endpoint = <&hdmi0_out>;
+			};
+		};
+	};
+
 	firmware {
 		optee {
 			compatible = "linaro,optee-tz";
@@ -245,6 +259,18 @@ port at 1 {
 	};
 };
 
+&dpi1 {
+	status = "okay";
+};
+
+&dpi1_in {
+	remote-endpoint = <&merge5_out>;
+};
+
+&dpi1_out {
+	remote-endpoint = <&hdmi0_in>;
+};
+
 &eth {
 	phy-mode = "rgmii-rxid";
 	phy-handle = <&rgmii_phy>;
@@ -265,11 +291,61 @@ rgmii_phy: ethernet-phy at 1 {
 	};
 };
 
+&ethdr0 {
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			ethdr0_in: endpoint at 1 {
+				reg = <1>;
+				remote-endpoint = <&vdosys1_ep_ext>;
+			};
+		};
+
+		port at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			ethdr0_out: endpoint at 1 {
+				reg = <1>;
+				remote-endpoint = <&merge5_in>;
+			};
+		};
+	};
+};
+
 &gpu {
 	mali-supply = <&mt6315_7_vbuck1>;
 	status = "okay";
 };
 
+&hdmi {
+	pinctrl-names = "default";
+	pinctrl-0 = <&hdmi_pins>;
+	status = "okay";
+};
+
+&hdmi0_in {
+	remote-endpoint = <&dpi1_out>;
+};
+
+&hdmi0_out {
+	remote-endpoint = <&hdmi_connector_in>;
+};
+
+&hdmi_phy {
+	pinctrl-names = "default";
+	pinctrl-0 = <&hdmi_vreg_pins>;
+
+	status = "okay";
+};
+
 &i2c2 {
 	clock-frequency = <400000>;
 	pinctrl-0 = <&i2c2_pins>;
@@ -448,6 +524,35 @@ typec_con_mux: endpoint {
 	};
 };
 
+&merge5 {
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			merge5_in: endpoint at 1 {
+				reg = <1>;
+				remote-endpoint = <&ethdr0_out>;
+			};
+		};
+
+		port at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			merge5_out: endpoint at 1 {
+				reg = <1>;
+				remote-endpoint = <&dpi1_in>;
+			};
+		};
+	};
+};
+
 &mfg0 {
 	domain-supply = <&mt6315_7_vbuck1>;
 };
@@ -647,6 +752,31 @@ pins {
 		};
 	};
 
+	hdmi_vreg_pins: hdmi-vreg-pins {
+		pins-pwr {
+			pinmux = <PINMUX_GPIO31__FUNC_HDMITX20_PWR5V>;
+			bias-disable;
+		};
+	};
+
+	hdmi_pins: hdmi-pins {
+		pins-hotplug {
+			pinmux = <PINMUX_GPIO32__FUNC_HDMITX20_HTPLG>;
+			bias-pull-down;
+		};
+
+		pins-ddc {
+			pinmux = <PINMUX_GPIO34__FUNC_HDMITX20_SCL>,
+				 <PINMUX_GPIO35__FUNC_HDMITX20_SDA>;
+			drive-strength = <10>;
+		};
+
+		pins-cec {
+			pinmux = <PINMUX_GPIO33__FUNC_HDMITX20_CEC>;
+			bias-disable;
+		};
+	};
+
 	i2c2_pins: i2c2-pins {
 		pins-bus {
 			pinmux = <PINMUX_GPIO12__FUNC_SDA2>,
@@ -1058,6 +1188,18 @@ &ssusb2 {
 	status = "okay";
 };
 
+&vdosys1 {
+	port {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		vdosys1_ep_ext: endpoint at 1 {
+			reg = <1>;
+			remote-endpoint = <&ethdr0_in>;
+		};
+	};
+};
+
 &xhci0 {
 	vbus-supply = <&otg_vbus_regulator>;
 	status = "okay";

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Tue Dec  9 08:34:39 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Tue, 09 Dec 2025 17:34:39 +0100
Subject: [PATCH 09/12] arm64: dts: mediatek: mt8395-radxa-nio-12l: Add HDMI
 sound output support
In-Reply-To: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>
References: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>
Message-ID: <20251209-mtk-genio-evk-hdmi-support-v1-9-9a6106effba6@collabora.com>

Add in the sound node a new dai-link for ETDM3_OUT_BE to add the sound
output support through the HDMI TX connector.

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 arch/arm64/boot/dts/mediatek/mt8395-radxa-nio-12l.dts | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8395-radxa-nio-12l.dts b/arch/arm64/boot/dts/mediatek/mt8395-radxa-nio-12l.dts
index b0e18876bd5d2341c6f17f47e9f11433be807ccd..1cd4b84e98615be6c5cb13d01b7baed0e017c3be 100644
--- a/arch/arm64/boot/dts/mediatek/mt8395-radxa-nio-12l.dts
+++ b/arch/arm64/boot/dts/mediatek/mt8395-radxa-nio-12l.dts
@@ -1072,6 +1072,14 @@ codec {
 			sound-dai = <&pmic 0>;
 		};
 	};
+
+	hdmi-dai-link {
+		link-name = "ETDM3_OUT_BE";
+
+		codec {
+			sound-dai = <&hdmi 0>;
+		};
+	};
 };
 
 &spi1 {

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Tue Dec  9 08:34:40 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Tue, 09 Dec 2025 17:34:40 +0100
Subject: [PATCH 10/12] arm64: dts: mediatek: mt8395-genio-common: Enable
 HDMI output
In-Reply-To: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>
References: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>
Message-ID: <20251209-mtk-genio-evk-hdmi-support-v1-10-9a6106effba6@collabora.com>

Add a definition for the on-board HDMI connector, enable and add
the relevant configuration for the HDMI PHY and controller, and
define the pins used by those.

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 .../boot/dts/mediatek/mt8395-genio-common.dtsi     | 142 +++++++++++++++++++++
 1 file changed, 142 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8395-genio-common.dtsi b/arch/arm64/boot/dts/mediatek/mt8395-genio-common.dtsi
index 2b7167804e71d0ced33c048ecb2040667b5fece1..345fc5ac9e039de8660ae325f36ae6265ef3a7c8 100644
--- a/arch/arm64/boot/dts/mediatek/mt8395-genio-common.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8395-genio-common.dtsi
@@ -26,6 +26,20 @@ chosen {
 		stdout-path = "serial0:921600n8";
 	};
 
+	connector {
+		compatible = "hdmi-connector";
+		label = "hdmi";
+		type = "a";
+		ddc-i2c-bus = <&hdmitx_ddc>;
+		hdmi-pwr-supply = <&hdmi_phy>;
+
+		port {
+			hdmi_connector_in: endpoint {
+				remote-endpoint = <&hdmi0_out>;
+			};
+		};
+	};
+
 	firmware {
 		optee {
 			compatible = "linaro,optee-tz";
@@ -247,6 +261,18 @@ &dmic_codec {
 	wakeup-delay-ms = <200>;
 };
 
+&dpi1 {
+	status = "okay";
+};
+
+&dpi1_in {
+	remote-endpoint = <&merge5_out>;
+};
+
+&dpi1_out {
+	remote-endpoint = <&hdmi0_in>;
+};
+
 &dsi0 {
 	#address-cells = <1>;
 	#size-cells = <0>;
@@ -313,6 +339,35 @@ eth_phy0: ethernet-phy at 1 {
 	};
 };
 
+&ethdr0 {
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			ethdr0_in: endpoint at 1 {
+				reg = <1>;
+				remote-endpoint = <&vdosys1_ep_ext>;
+			};
+		};
+
+		port at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			ethdr0_out: endpoint at 1 {
+				reg = <1>;
+				remote-endpoint = <&merge5_in>;
+			};
+		};
+	};
+};
+
 &gamma0_out {
 	remote-endpoint = <&dither0_in>;
 };
@@ -329,6 +384,27 @@ &i2c0 {
 	status = "okay";
 };
 
+&hdmi {
+	pinctrl-names = "default";
+	pinctrl-0 = <&hdmi_pins>;
+	status = "okay";
+};
+
+&hdmi0_in {
+	remote-endpoint = <&dpi1_out>;
+};
+
+&hdmi0_out {
+	remote-endpoint = <&hdmi_connector_in>;
+};
+
+&hdmi_phy {
+	pinctrl-names = "default";
+	pinctrl-0 = <&hdmi_vreg_pins>;
+
+	status = "okay";
+};
+
 &i2c1 {
 	clock-frequency = <400000>;
 	pinctrl-0 = <&i2c1_pins>;
@@ -533,6 +609,35 @@ mt6360_ssusb_sbu_ep: endpoint {
 	};
 };
 
+&merge5 {
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			merge5_in: endpoint at 1 {
+				reg = <1>;
+				remote-endpoint = <&ethdr0_out>;
+			};
+		};
+
+		port at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			merge5_out: endpoint at 1 {
+				reg = <1>;
+				remote-endpoint = <&dpi1_in>;
+			};
+		};
+	};
+};
+
 &mfg0 {
 	domain-supply = <&mt6315_7_vbuck1>;
 };
@@ -762,6 +867,31 @@ pins {
 		};
 	};
 
+	hdmi_vreg_pins: hdmi-vreg-pins {
+		pins-pwr {
+			pinmux = <PINMUX_GPIO31__FUNC_HDMITX20_PWR5V>;
+			bias-disable;
+		};
+	};
+
+	hdmi_pins: hdmi-pins {
+		pins-hotplug {
+			pinmux = <PINMUX_GPIO32__FUNC_HDMITX20_HTPLG>;
+			bias-pull-down;
+		};
+
+		pins-ddc {
+			pinmux = <PINMUX_GPIO34__FUNC_HDMITX20_SCL>,
+				 <PINMUX_GPIO35__FUNC_HDMITX20_SDA>;
+			drive-strength = <10>;
+		};
+
+		pins-cec {
+			pinmux = <PINMUX_GPIO33__FUNC_HDMITX20_CEC>;
+			bias-disable;
+		};
+	};
+
 	i2c0_pins: i2c0-pins {
 		pins {
 			pinmux = <PINMUX_GPIO8__FUNC_SDA0>,
@@ -1212,6 +1342,18 @@ vdosys0_ep_main: endpoint at 0 {
 	};
 };
 
+&vdosys1 {
+	port {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		vdosys1_ep_ext: endpoint at 1 {
+			reg = <1>;
+			remote-endpoint = <&ethdr0_in>;
+		};
+	};
+};
+
 &xhci0 {
 	status = "okay";
 };

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Tue Dec  9 08:34:41 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Tue, 09 Dec 2025 17:34:41 +0100
Subject: [PATCH 11/12] arm64: dts: mediatek: mt8395-genio-common: Add HDMI
 sound output support
In-Reply-To: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>
References: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>
Message-ID: <20251209-mtk-genio-evk-hdmi-support-v1-11-9a6106effba6@collabora.com>

Add in the sound node a new dai-link for ETDM3_OUT_BE to add the sound
output support through the HDMI TX connector.

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 arch/arm64/boot/dts/mediatek/mt8395-genio-common.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8395-genio-common.dtsi b/arch/arm64/boot/dts/mediatek/mt8395-genio-common.dtsi
index 345fc5ac9e039de8660ae325f36ae6265ef3a7c8..d849af4d36134df6a7b9f7967efd0db13c372d7a 100644
--- a/arch/arm64/boot/dts/mediatek/mt8395-genio-common.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8395-genio-common.dtsi
@@ -1189,6 +1189,14 @@ codec {
 			sound-dai = <&pmic 0>;
 		};
 	};
+
+	hdmi-dai-link {
+		link-name = "ETDM3_OUT_BE";
+
+		codec {
+			sound-dai = <&hdmi 0>;
+		};
+	};
 };
 
 &spi1 {

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Tue Dec  9 08:34:42 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Tue, 09 Dec 2025 17:34:42 +0100
Subject: [PATCH 12/12] arm64: defconfig: Enable Mediatek HDMIv2 driver
In-Reply-To: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>
References: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>
Message-ID: <20251209-mtk-genio-evk-hdmi-support-v1-12-9a6106effba6@collabora.com>

In order to enable the HDMI output support on Mediatek Genio 510-EVK,
700-EVK, and 1200-EVK boards, enable the driver for it in the default
configuration.

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 arch/arm64/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index cdb7d69e3b248975557e141481a88fd86115cf40..24c1670e5bfd4ed0902d5440d43fdb4e5dd676f1 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -1015,6 +1015,7 @@ CONFIG_DRM_HISI_KIRIN=m
 CONFIG_DRM_MEDIATEK=m
 CONFIG_DRM_MEDIATEK_DP=m
 CONFIG_DRM_MEDIATEK_HDMI=m
+CONFIG_DRM_MEDIATEK_HDMI_V2=m
 CONFIG_DRM_MXSFB=m
 CONFIG_DRM_IMX_LCDIF=m
 CONFIG_DRM_MESON=m

-- 
2.52.0



From ben.horgan at arm.com  Tue Dec  9 08:36:13 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Tue, 9 Dec 2025 16:36:13 +0000
Subject: [RFC PATCH 31/38] arm_mpam: resctrl: Update the rmid reallocation
 limit
In-Reply-To: <1cc804d5-9d14-4d71-9da1-a660a2569e4e@nvidia.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-32-james.morse@arm.com>
 <1cc804d5-9d14-4d71-9da1-a660a2569e4e@nvidia.com>
Message-ID: <dc5355c6-e7a6-466e-9183-9753281961a8@arm.com>

Hi Fenghua,

On 12/6/25 00:06, Fenghua Yu wrote:
> Hi, James,
> 
> On 12/5/25 13:58, James Morse wrote:
>> resctrl's limbo code needs to be told when the data left in a cache is
>> small enough for the partid+pmg value to be re-allocated.
>>
>> x86 uses the cache size divided by the number of rmid users the cache
>> may have. Do the same, but for the smallest cache, and with the
>> number of partid-and-pmg users.
>>
>> Querying the cache size can't happen until after cacheinfo_sysfs_init()
>> has run, so mpam_resctrl_setup() must wait until then.
>>
>> Signed-off-by: James Morse <james.morse at arm.com>
>> ---
>> ? drivers/resctrl/mpam_resctrl.c | 54 ++++++++++++++++++++++++++++++++++
>> ? 1 file changed, 54 insertions(+)
>>
>> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/
>> mpam_resctrl.c
>> index 506063bd3348..ccdf8db742c9 100644
>> --- a/drivers/resctrl/mpam_resctrl.c
>> +++ b/drivers/resctrl/mpam_resctrl.c
>> @@ -16,6 +16,7 @@
>> ? #include <linux/resctrl.h>
>> ? #include <linux/slab.h>
>> ? #include <linux/types.h>
>> +#include <linux/wait.h>
>> ? ? #include <asm/mpam.h>
>> ? @@ -58,6 +59,13 @@ static bool cdp_enabled;
>> ?? */
>> ? static bool resctrl_enabled;
>> ? +/*
>> + * mpam_resctrl_pick_caches() needs to know the size of the caches.
>> cacheinfo
>> + * populates this from a device_initcall(). mpam_resctrl_setup() must
>> wait.
>> + */
>> +static bool cacheinfo_ready;
>> +static DECLARE_WAIT_QUEUE_HEAD(wait_cacheinfo_ready);
>> +
>> ? /*
>> ?? * L3 local/total may come from different classes - what is the
>> number of MBWU
>> ?? * 'on L3'?
>> @@ -584,6 +592,38 @@ void resctrl_arch_reset_cntr(struct rdt_resource
>> *r, struct rdt_mon_domain *d,
>> ????? reset_mon_cdp_safe(mon, mon_comp, USE_PRE_ALLOCATED, closid, rmid);
>> ? }
>> ? +/*
>> + * The rmid realloc threshold should be for the smallest cache
>> exposed to
>> + * resctrl.
>> + */
>> +static int update_rmid_limits(struct mpam_class *class)
>> +{
>> +??? u32 num_unique_pmg = resctrl_arch_system_num_rmid_idx();
>> +??? struct mpam_props *cprops = &class->props;
>> +??? struct cacheinfo *ci;
>> +
>> +??? lockdep_assert_cpus_held();
>> +
>> +??? /* Assume cache levels are the same size for all CPUs... */
>> +??? ci = get_cpu_cacheinfo_level(smp_processor_id(), class->level);
>> +??? if (!ci || ci->size == 0) {
>> +??????? pr_debug("Could not read cache size for class %u\n",
>> +???????????? class->level);
>> +??????? return -EINVAL;
>> +??? }
>> +
>> +??? if (!mpam_has_feature(mpam_feat_msmon_csu, cprops))
>> +??????? return 0;
>> +
>> +??? if (!resctrl_rmid_realloc_limit ||
>> +??????? ci->size < resctrl_rmid_realloc_limit) {
>> +??????? resctrl_rmid_realloc_limit = ci->size;
>> +??????? resctrl_rmid_realloc_threshold = ci->size / num_unique_pmg;
>> +??? }
>> +
>> +??? return 0;
>> +}
>> +
>> ? static bool cache_has_usable_cpor(struct mpam_class *class)
>> ? {
>> ????? struct mpam_props *cprops = &class->props;
>> @@ -1025,6 +1065,9 @@ static void mpam_resctrl_pick_counters(void)
>> ????????????? /* CSU counters only make sense on a cache. */
>> ????????????? switch (class->type) {
>> ????????????? case MPAM_CLASS_CACHE:
>> +??????????????? if (update_rmid_limits(class))
>> +??????????????????? continue;
>> +
>> ????????????????? counter_update_class(QOS_L3_OCCUP_EVENT_ID, class);
>> ????????????????? return;
>> ????????????? default:
>> @@ -1731,6 +1774,8 @@ int mpam_resctrl_setup(void)
>> ????? struct mpam_resctrl_res *res;
>> ????? struct mpam_resctrl_mon *mon;
>> ? +??? wait_event(wait_cacheinfo_ready, cacheinfo_ready);
> 
> This may cause system hang for any hw/fw issue that causes cacheinfo
> failure. Instead of hang, is it better to have a timeout wait here? Like
> ????errowait_event_timeout(wait_cache_info_read, cacheinfo_ready, 5 * HZ);
> and report failure when cacheinfo is not ready.

This is just waiting on everything in device_initcall(). I think we've
got bigger problems if that doesn't finish.

> 
> Thanks.
> 
> -Fenghua


Thanks,

Ben



From ben.horgan at arm.com  Tue Dec  9 08:45:16 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Tue, 9 Dec 2025 16:45:16 +0000
Subject: [RFC PATCH 33/38] arm_mpam: Generate a configuration for min
 controls
In-Reply-To: <20251205215901.17772-34-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-34-james.morse@arm.com>
Message-ID: <f00a0467-6f32-4105-b1b8-ca9490db57bf@arm.com>

Hi James,

On 12/5/25 21:58, James Morse wrote:
> MPAM supports a minimum and maximum control for memory bandwidth. The
> purpose of the minimum control is to give priority to tasks that are
> below their minimum value. Resctrl only provides one value for the
> bandwidth configuration, which is used for the maximum.
> 
> The minimum control is always programmed to zero on hardware that
> supports it.
> 
> Generate a minimum bandwidth value that is 5% lower than the
> value provided by resctrl. This means tasks that are not
> receiving their target bandwidth can be prioritised by the
> hardware.

To ensure that the min is always programmed we need to add a
reset_mbw_min to the reset_cfg for the ris level reset and give a value
in mpam_reset_component_cfg() for the component level reset.

> 
> CC: Zeng Heng <zengheng4 at huawei.com>
> Signed-off-by: James Morse <james.morse at arm.com>
> ---
>  drivers/resctrl/mpam_devices.c      | 68 +++++++++++++++++++++++++++--
>  drivers/resctrl/mpam_internal.h     |  2 +
>  drivers/resctrl/test_mpam_devices.c | 66 ++++++++++++++++++++++++++++
>  3 files changed, 132 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
> index 1334093fc03e..741e14e1e6cf 100644
> --- a/drivers/resctrl/mpam_devices.c
> +++ b/drivers/resctrl/mpam_devices.c
> @@ -721,6 +721,13 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris)
>  			mpam_set_feature(mpam_feat_mbw_part, props);
>  
>  		props->bwa_wd = FIELD_GET(MPAMF_MBW_IDR_BWA_WD, mbw_features);
> +
> +		/*
> +		 * The BWA_WD field can represent 0-63, but the control fields it
> +		 * describes have a maximum of 16 bits.
> +		 */
> +		props->bwa_wd = min(props->bwa_wd, 16);
> +
>  		if (props->bwa_wd && FIELD_GET(MPAMF_MBW_IDR_HAS_MAX, mbw_features))
>  			mpam_set_feature(mpam_feat_mbw_max, props);
>  
> @@ -1387,7 +1394,7 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
>  
>  	if (mpam_has_feature(mpam_feat_mbw_min, rprops) &&
>  	    mpam_has_feature(mpam_feat_mbw_min, cfg))
> -		mpam_write_partsel_reg(msc, MBW_MIN, 0);
> +		mpam_write_partsel_reg(msc, MBW_MIN, cfg->mbw_min);
>  
>  	if (mpam_has_feature(mpam_feat_mbw_max, rprops) &&
>  	    mpam_has_feature(mpam_feat_mbw_max, cfg)) {
> @@ -2693,24 +2700,77 @@ static bool mpam_update_config(struct mpam_config *cfg,
>  	maybe_update_config(cfg, mpam_feat_cpor_part, newcfg, cpbm, has_changes);
>  	maybe_update_config(cfg, mpam_feat_mbw_part, newcfg, mbw_pbm, has_changes);
>  	maybe_update_config(cfg, mpam_feat_mbw_max, newcfg, mbw_max, has_changes);
> +	maybe_update_config(cfg, mpam_feat_mbw_min, newcfg, mbw_min, has_changes);
>  
>  	return has_changes;
>  }
>  
> +static void mpam_extend_config(struct mpam_class *class, struct mpam_config *cfg)
> +{
> +	struct mpam_props *cprops = &class->props;
> +	u16 min, min_hw_granule, delta;
> +	u16 max_hw_value, res0_bits;
> +
> +	/*
> +	 * MAX and MIN should be set together. If only one is provided,
> +	 * generate a configuration for the other. If only one control
> +	 * type is supported, the other value will be ignored.
> +	 *
> +	 * Resctrl can only configure the MAX.
> +	 */
> +	if (mpam_has_feature(mpam_feat_mbw_max, cfg) &&
> +	    !mpam_has_feature(mpam_feat_mbw_min, cfg)) {
> +		/*
> +		 * Calculate the values the 'min' control can hold.
> +		 * e.g. on a platform with bwa_wd = 8, min_hw_granule is 0x00ff
> +		 * because those bits are RES0. Configurations of this value
> +		 * are effectively zero. But configurations need to saturate
> +		 * at min_hw_granule on systems with mismatched bwa_wd, where
> +		 * the 'less than 0' values are implemented on some MSC, but
> +		 * not others.
> +		 */
> +		res0_bits = 16 - cprops->bwa_wd;
> +		max_hw_value = ((1 << cprops->bwa_wd) - 1) << res0_bits;
> +		min_hw_granule = ~max_hw_value;
> +
> +		delta = ((5 * MPAMCFG_MBW_MAX_MAX) / 100) - 1;
> +		if (cfg->mbw_max > delta)
> +			min = cfg->mbw_max - delta;
> +		else
> +			min = 0;
> +
> +		cfg->mbw_min = max(min, min_hw_granule);
> +		mpam_set_feature(mpam_feat_mbw_min, cfg);
> +	}
> +}
> +
>  int mpam_apply_config(struct mpam_component *comp, u16 partid,
> -		      struct mpam_config *cfg)
> +		      struct mpam_config *user_cfg)
>  {
>  	struct mpam_write_config_arg arg;
>  	struct mpam_msc_ris *ris;
> +	struct mpam_config cfg;
>  	struct mpam_vmsc *vmsc;
>  	struct mpam_msc *msc;
>  
>  	lockdep_assert_cpus_held();
>  
> +
>  	/* Don't pass in the current config! */
> -	WARN_ON_ONCE(&comp->cfg[partid] == cfg);
> +	WARN_ON_ONCE(&comp->cfg[partid] == user_cfg);
>  
> -	if (!mpam_update_config(&comp->cfg[partid], cfg))
> +	/*
> +	 * Copy the config to avoid writing back the 'extended' version to
> +	 * the caller.
> +	 * This avoids mpam_devices.c setting a mbm_min that mpam_resctrl.c
> +	 * is unaware of ... when it then changes mbm_max to be lower than
> +	 * mbm_min.
> +	 */
> +	cfg = *user_cfg;
> +
> +	mpam_extend_config(comp->class, &cfg);
> +
> +	if (!mpam_update_config(&comp->cfg[partid], &cfg))
>  		return 0;
>  
>  	arg.comp = comp;
> diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
> index b13d5e55e701..d381906545ed 100644
> --- a/drivers/resctrl/mpam_internal.h
> +++ b/drivers/resctrl/mpam_internal.h
> @@ -277,6 +277,7 @@ struct mpam_config {
>  	u32	cpbm;
>  	u32	mbw_pbm;
>  	u16	mbw_max;
> +	u16	mbw_min;
>  
>  	bool	reset_cpbm;
>  	bool	reset_mbw_pbm;
> @@ -618,6 +619,7 @@ static inline void mpam_resctrl_teardown_class(struct mpam_class *class) { }
>   * MPAMCFG_MBW_MAX - MPAM memory maximum bandwidth partitioning configuration
>   *                   register
>   */
> +#define MPAMCFG_MBW_MAX_MAX_NR_BITS	16
>  #define MPAMCFG_MBW_MAX_MAX		GENMASK(15, 0)
>  #define MPAMCFG_MBW_MAX_HARDLIM		BIT(31)
>  
> diff --git a/drivers/resctrl/test_mpam_devices.c b/drivers/resctrl/test_mpam_devices.c
> index 3e8d564a0c64..2f802fd9f249 100644
> --- a/drivers/resctrl/test_mpam_devices.c
> +++ b/drivers/resctrl/test_mpam_devices.c
> @@ -322,6 +322,71 @@ static void test_mpam_enable_merge_features(struct kunit *test)
>  	mutex_unlock(&mpam_list_lock);
>  }
>  
> +static void test_mpam_extend_config(struct kunit *test)
> +{
> +	struct mpam_config fake_cfg = { };
> +	struct mpam_class fake_class = { };
> +
> +	/* Configurations with both are not modified */
> +	fake_class.props.bwa_wd = 16;
> +	fake_cfg.mbw_max = 0xfeef;
> +	fake_cfg.mbw_min = 0xfeef;
> +	bitmap_zero(fake_cfg.features, MPAM_FEATURE_LAST);
> +	mpam_set_feature(mpam_feat_mbw_max, &fake_cfg);
> +	mpam_set_feature(mpam_feat_mbw_min, &fake_cfg);
> +	mpam_extend_config(&fake_class, &fake_cfg);
> +	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_max, &fake_cfg));
> +	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_min, &fake_cfg));
> +	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_max, 0xfeef);
> +	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_min, 0xfeef);
> +
> +	/* When a min is missing, it is generated */
> +	fake_class.props.bwa_wd = 16;
> +	fake_cfg.mbw_max = 0xfeef;
> +	fake_cfg.mbw_min = 0;
> +	bitmap_zero(fake_cfg.features, MPAM_FEATURE_LAST);
> +	mpam_set_feature(mpam_feat_mbw_max, &fake_cfg);
> +	mpam_extend_config(&fake_class, &fake_cfg);
> +	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_max, &fake_cfg));
> +	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_min, &fake_cfg));
> +	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_max, 0xfeef);
> +	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_min, 0xf224);
> +
> +	fake_class.props.bwa_wd = 8;
> +	fake_cfg.mbw_max = 0xfeef;
> +	fake_cfg.mbw_min = 0;
> +	bitmap_zero(fake_cfg.features, MPAM_FEATURE_LAST);
> +	mpam_set_feature(mpam_feat_mbw_max, &fake_cfg);
> +	mpam_extend_config(&fake_class, &fake_cfg);
> +	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_max, &fake_cfg));
> +	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_min, &fake_cfg));
> +	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_max, 0xfeef);
> +	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_min, 0xf224);
> +
> +	/* 5% below the minimum granule, is still the minimum granule */
> +	fake_class.props.bwa_wd = 12;
> +	fake_cfg.mbw_max = 0xf;
> +	fake_cfg.mbw_min = 0;
> +	bitmap_zero(fake_cfg.features, MPAM_FEATURE_LAST);
> +	mpam_set_feature(mpam_feat_mbw_max, &fake_cfg);
> +	mpam_extend_config(&fake_class, &fake_cfg);
> +	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_max, &fake_cfg));
> +	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_min, &fake_cfg));
> +	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_max, 0xf);
> +	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_min, 0xf);
> +
> +	fake_class.props.bwa_wd = 16;
> +	fake_cfg.mbw_max = 0x4;
> +	fake_cfg.mbw_min = 0;
> +	bitmap_zero(fake_cfg.features, MPAM_FEATURE_LAST);
> +	mpam_set_feature(mpam_feat_mbw_max, &fake_cfg);
> +	mpam_extend_config(&fake_class, &fake_cfg);
> +	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_max, &fake_cfg));
> +	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_min, &fake_cfg));
> +	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_max, 0x4);
> +	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_min, 0x0);
> +}
> +
>  static void test_mpam_reset_msc_bitmap(struct kunit *test)
>  {
>  	char __iomem *buf = kunit_kzalloc(test, SZ_16K, GFP_KERNEL);
> @@ -378,6 +443,7 @@ static struct kunit_case mpam_devices_test_cases[] = {
>  	KUNIT_CASE(test_mpam_reset_msc_bitmap),
>  	KUNIT_CASE(test_mpam_enable_merge_features),
>  	KUNIT_CASE(test__props_mismatch),
> +	KUNIT_CASE(test_mpam_extend_config),
>  	{}
>  };
>  

Thanks,

Ben



From Harini.T at amd.com  Tue Dec  9 08:51:09 2025
From: Harini.T at amd.com (T, Harini)
Date: Tue, 9 Dec 2025 16:51:09 +0000
Subject: [PATCH 1/4] rtc: zynqmp: correct frequency value
In-Reply-To: <20251201-zynqmp-rtc-updates-v1-1-33875c1e385b@vaisala.com>
References: <20251201-zynqmp-rtc-updates-v1-0-33875c1e385b@vaisala.com>
 <20251201-zynqmp-rtc-updates-v1-1-33875c1e385b@vaisala.com>
Message-ID: <LV5PR12MB980479009955E816E72E6EA892A3A@LV5PR12MB9804.namprd12.prod.outlook.com>

[Public]

Hi,

> -----Original Message-----
> From: Tomas Melin <tomas.melin at vaisala.com>
> Sent: Monday, December 1, 2025 6:20 PM
> To: Alexandre Belloni <alexandre.belloni at bootlin.com>; Simek, Michal
> <michal.simek at amd.com>
> Cc: linux-rtc at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux-
> kernel at vger.kernel.org; Tomas Melin <tomas.melin at vaisala.com>
> Subject: [PATCH 1/4] rtc: zynqmp: correct frequency value
>
> Caution: This message originated from an External Source. Use proper
> caution when opening attachments, clicking links, or responding.
>
>
> Fix calibration value in case a clock reference is provided.
> The actual calibration value written into register is
> frequency - 1.
>
> Signed-off-by: Tomas Melin <tomas.melin at vaisala.com>
> ---
>  drivers/rtc/rtc-zynqmp.c | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c
> index
> 3baa2b481d9f2008750046005283b98a0d546c5c..856bc1678e7d31144f320ae
> 9f75fc58c742a2a64 100644
> --- a/drivers/rtc/rtc-zynqmp.c
> +++ b/drivers/rtc/rtc-zynqmp.c
> @@ -345,7 +345,10 @@ static int xlnx_rtc_probe(struct platform_device
> *pdev)
>                                            &xrtcdev->freq);
>                 if (ret)
>                         xrtcdev->freq = RTC_CALIB_DEF;
> +       } else {
> +               xrtcdev->freq--;
If freq > 65536, the 16-bit register silently truncates.
Please add some checks for above mentioned scenario.
>         }
> +
>         ret = readl(xrtcdev->reg_base + RTC_CALIB_RD);
>         if (!ret)
>                 writel(xrtcdev->freq, (xrtcdev->reg_base + RTC_CALIB_WR));
>
> --
> 2.47.3
>
Thanks,
Harini T

From ben.horgan at arm.com  Tue Dec  9 08:58:06 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Tue, 9 Dec 2025 16:58:06 +0000
Subject: [RFC PATCH 36/38] arm_mpam: Add workaround for T241-MPAM-4
In-Reply-To: <20251205215901.17772-37-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-37-james.morse@arm.com>
Message-ID: <1021cc11-de18-4208-8262-f9cba80e5a88@arm.com>

Hi James,

On 12/5/25 21:58, James Morse wrote:
> From: Shanker Donthineni <sdonthineni at nvidia.com>
> 
> In the T241 implementation of memory-bandwidth partitioning, in the
> absence of contention for bandwidth, the minimum bandwidth setting
> can affect the amount of achieved bandwidth. Specifically, the
> achieved bandwidth in the absence of contention can settle to any
> value between the values of MPAMCFG_MBW_MIN and MPAMCFG_MBW_MAX.
> Also, if MPAMCFG_MBW_MIN is set zero (below 0.78125%), once a core
> enters a throttled state, it will never leave that state.
> 
> The first issue is not a cocern if the MPAM software allows to
> program MPAMCFG_MBW_MIN through the sysfs interface. This patch
> ensures program MBW_MIN=1 (0.78125%) whenever MPAMCFG_MBW_MIN=0
> is programmed.
> 
> In the scenario where the resctrl doesn't support the MBW_MIN
> interface via sysfs, to achieve bandwidth closer to MW_MAX in the
> absence of contention, software should configure a relatively narrow
> gap between MBW_MIN and MBW_MAX. The recommendation is to use a 5%
> gap to mitigate the problem.
> 
> Signed-off-by: Shanker Donthineni <sdonthineni at nvidia.com>
> [ morse: Added as second quirk, adapted to use the new intermediate values
>   in mpam_extend_config() ]
> Signed-off-by: James Morse <james.morse at arm.com>
> ---
>  Documentation/arch/arm64/silicon-errata.rst |  2 +
>  drivers/resctrl/mpam_devices.c              | 60 ++++++++++++++++-----
>  drivers/resctrl/mpam_internal.h             |  1 +
>  3 files changed, 49 insertions(+), 14 deletions(-)
> 
> diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst
> index 4e86b85fe3d6..b18bc704d4a1 100644
> --- a/Documentation/arch/arm64/silicon-errata.rst
> +++ b/Documentation/arch/arm64/silicon-errata.rst
> @@ -248,6 +248,8 @@ stable kernels.
>  +----------------+-----------------+-----------------+-----------------------------+
>  | NVIDIA         | T241 MPAM       | T241-MPAM-1     | N/A                         |
>  +----------------+-----------------+-----------------+-----------------------------+
> +| NVIDIA         | T241 MPAM       | T241-MPAM-4     | N/A                         |
> ++----------------+-----------------+-----------------+-----------------------------+
>  +----------------+-----------------+-----------------+-----------------------------+
>  | Freescale/NXP  | LS2080A/LS1043A | A-008585        | FSL_ERRATUM_A008585         |
>  +----------------+-----------------+-----------------+-----------------------------+
> diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
> index f1f03ceade0a..5ba0aa703807 100644
> --- a/drivers/resctrl/mpam_devices.c
> +++ b/drivers/resctrl/mpam_devices.c
> @@ -678,6 +678,12 @@ static const struct mpam_quirk mpam_quirks[] = {
>  	.iidr_mask  = MPAM_IIDR_MATCH_ONE,
>  	.workaround = T241_SCRUB_SHADOW_REGS,
>  	},
> +	{
> +	/* NVIDIA t241 erratum T241-MPAM-4 */
> +	.iidr       = MPAM_IIDR_NVIDIA_T421,
> +	.iidr_mask  = MPAM_IIDR_MATCH_ONE,
> +	.workaround = T241_FORCE_MBW_MIN_TO_ONE,
> +	},
>  	{ NULL }, /* Sentinel */
>  };
>  
> @@ -1622,6 +1628,22 @@ static void mpam_init_reset_cfg(struct mpam_config *reset_cfg)
>  	bitmap_fill(reset_cfg->features, MPAM_FEATURE_LAST);
>  }
>  
> +/*
> + * This is not part of mpam_init_reset_cfg() as high level callers have the
> + * class, and low level callers a ris.
> + */
> +static void mpam_wa_t241_force_mbw_min_to_one(struct mpam_config *cfg,
> +					      struct mpam_props *props)
> +{
> +	u16 max_hw_value, min_hw_granule, res0_bits;
> +
> +	res0_bits = 16 - props->bwa_wd;
> +	max_hw_value = ((1 << props->bwa_wd) - 1) << res0_bits;
> +	min_hw_granule = ~max_hw_value;
> +
> +	cfg->mbw_min = min_hw_granule + 1;
> +}
> +
>  /*
>   * Called via smp_call_on_cpu() to prevent migration, while still being
>   * pre-emptible. Caller must hold mpam_srcu.
> @@ -2524,7 +2546,8 @@ static void __destroy_component_cfg(struct mpam_component *comp)
>  static void mpam_reset_component_cfg(struct mpam_component *comp)
>  {
>  	int i;
> -	struct mpam_props *cprops = &comp->class->props;
> +	struct mpam_class *class = comp->class;
> +	struct mpam_props *cprops = &class->props;
>  
>  	mpam_assert_partid_sizes_fixed();
>  
> @@ -2539,6 +2562,10 @@ static void mpam_reset_component_cfg(struct mpam_component *comp)
>  			comp->cfg[i].mbw_pbm = GENMASK(cprops->mbw_pbm_bits - 1, 0);
>  		if (cprops->bwa_wd)
>  			comp->cfg[i].mbw_max = GENMASK(15, 16 - cprops->bwa_wd);
> +
> +		if (mpam_has_quirk(T241_FORCE_MBW_MIN_TO_ONE, class))
> +			mpam_wa_t241_force_mbw_min_to_one(&comp->cfg[i],
> +							  &class->props);
>  	}
>  }

Also need to consider the mbw_min in mpam_reset_ris() reset config.

>  
> @@ -2825,6 +2852,18 @@ static void mpam_extend_config(struct mpam_class *class, struct mpam_config *cfg
>  	u16 min, min_hw_granule, delta;
>  	u16 max_hw_value, res0_bits;
>  
> +	/*
> +	 * Calculate the values the 'min' control can hold.
> +	 * e.g. on a platform with bwa_wd = 8, min_hw_granule is 0x00ff because
> +	 * those bits are RES0. Configurations of this value are effectively
> +	 * zero. But configurations need to saturate at min_hw_granule on
> +	 * systems with mismatched bwa_wd, where the 'less than 0' values are
> +	 * implemented on some MSC, but not others.
> +	 */
> +	res0_bits = 16 - cprops->bwa_wd;
> +	max_hw_value = ((1 << cprops->bwa_wd) - 1) << res0_bits;
> +	min_hw_granule = ~max_hw_value;
> +
>  	/*
>  	 * MAX and MIN should be set together. If only one is provided,
>  	 * generate a configuration for the other. If only one control
> @@ -2834,19 +2873,6 @@ static void mpam_extend_config(struct mpam_class *class, struct mpam_config *cfg
>  	 */
>  	if (mpam_has_feature(mpam_feat_mbw_max, cfg) &&
>  	    !mpam_has_feature(mpam_feat_mbw_min, cfg)) {
> -		/*
> -		 * Calculate the values the 'min' control can hold.
> -		 * e.g. on a platform with bwa_wd = 8, min_hw_granule is 0x00ff
> -		 * because those bits are RES0. Configurations of this value
> -		 * are effectively zero. But configurations need to saturate
> -		 * at min_hw_granule on systems with mismatched bwa_wd, where
> -		 * the 'less than 0' values are implemented on some MSC, but
> -		 * not others.
> -		 */
> -		res0_bits = 16 - cprops->bwa_wd;
> -		max_hw_value = ((1 << cprops->bwa_wd) - 1) << res0_bits;
> -		min_hw_granule = ~max_hw_value;
> -
>  		delta = ((5 * MPAMCFG_MBW_MAX_MAX) / 100) - 1;
>  		if (cfg->mbw_max > delta)
>  			min = cfg->mbw_max - delta;
> @@ -2856,6 +2882,12 @@ static void mpam_extend_config(struct mpam_class *class, struct mpam_config *cfg
>  		cfg->mbw_min = max(min, min_hw_granule);
>  		mpam_set_feature(mpam_feat_mbw_min, cfg);
>  	}
> +
> +	if (mpam_has_quirk(T241_FORCE_MBW_MIN_TO_ONE, class) &&
> +	    cfg->mbw_min <= min_hw_granule) {
> +		cfg->mbw_min = min_hw_granule + 1;
> +		mpam_set_feature(mpam_feat_mbw_min, cfg);
> +	}
>  }
>  
>  int mpam_apply_config(struct mpam_component *comp, u16 partid,
> diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
> index 70b78cfd1f5b..01882f0acee2 100644
> --- a/drivers/resctrl/mpam_internal.h
> +++ b/drivers/resctrl/mpam_internal.h
> @@ -223,6 +223,7 @@ struct mpam_props {
>  /* Workaround bits for msc->quirks */
>  enum mpam_device_quirks {
>  	T241_SCRUB_SHADOW_REGS,
> +	T241_FORCE_MBW_MIN_TO_ONE,
>  	MPAM_QUIRK_LAST,
>  };
>  

Thanks,

Ben



From ben.horgan at arm.com  Tue Dec  9 09:06:41 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Tue, 9 Dec 2025 17:06:41 +0000
Subject: [RFC PATCH 37/38] arm_mpam: Add workaround for T241-MPAM-6
In-Reply-To: <20251205215901.17772-38-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-38-james.morse@arm.com>
Message-ID: <1562cbdd-f50c-4890-8b41-2987490ea384@arm.com>

Hi James, Shanker,

On 12/5/25 21:59, James Morse wrote:
> From: Shanker Donthineni <sdonthineni at nvidia.com>
> 
> The registers MSMON_MBWU_L and MSMON_MBWU return the number of
> requests rather than the number of bytes transferred.
> 
> Bandwidth resource monitoring is performed at the last level cache,
> where each request arrive in 64Byte granularity. The current
> implementation returns the number of transactions received at the
> last level cache but does not provide the value in bytes. Scaling
> by 64 gives an accurate byte count to match the MPAM specification
> for the MSMON_MBWU and MSMON_MBWU_L registers. This patch fixes
> the issue by reporting the actual number of bytes instead of the
> number of transactions from __ris_msmon_read().
> 
> Signed-off-by: Shanker Donthineni <sdonthineni at nvidia.com>
> Signed-off-by: James Morse <james.morse at arm.com>
> ---
>  Documentation/arch/arm64/silicon-errata.rst |  2 ++
>  drivers/resctrl/mpam_devices.c              | 24 +++++++++++++++++++--
>  drivers/resctrl/mpam_internal.h             |  1 +
>  3 files changed, 25 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst
> index b18bc704d4a1..e810b2a8f40e 100644
> --- a/Documentation/arch/arm64/silicon-errata.rst
> +++ b/Documentation/arch/arm64/silicon-errata.rst
> @@ -250,6 +250,8 @@ stable kernels.
>  +----------------+-----------------+-----------------+-----------------------------+
>  | NVIDIA         | T241 MPAM       | T241-MPAM-4     | N/A                         |
>  +----------------+-----------------+-----------------+-----------------------------+
> +| NVIDIA         | T241 MPAM       | T241-MPAM-6     | N/A                         |
> ++----------------+-----------------+-----------------+-----------------------------+
>  +----------------+-----------------+-----------------+-----------------------------+
>  | Freescale/NXP  | LS2080A/LS1043A | A-008585        | FSL_ERRATUM_A008585         |
>  +----------------+-----------------+-----------------+-----------------------------+
> diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
> index 5ba0aa703807..c17a6fdea982 100644
> --- a/drivers/resctrl/mpam_devices.c
> +++ b/drivers/resctrl/mpam_devices.c
> @@ -684,6 +684,12 @@ static const struct mpam_quirk mpam_quirks[] = {
>  	.iidr_mask  = MPAM_IIDR_MATCH_ONE,
>  	.workaround = T241_FORCE_MBW_MIN_TO_ONE,
>  	},
> +	{
> +	/* NVIDIA t241 erratum T241-MPAM-6 */
> +	.iidr       = MPAM_IIDR_NVIDIA_T421,
> +	.iidr_mask  = MPAM_IIDR_MATCH_ONE,
> +	.workaround = T241_MBW_COUNTER_SCALE_64,
> +	},
>  	{ NULL }, /* Sentinel */
>  };
>  
> @@ -1140,7 +1146,7 @@ static void write_msmon_ctl_flt_vals(struct mon_read *m, u32 ctl_val,
>  	}
>  }
>  
> -static u64 mpam_msmon_overflow_val(enum mpam_device_features type)
> +static u64 __mpam_msmon_overflow_val(enum mpam_device_features type)
>  {
>  	/* TODO: implement scaling counters */
>  	switch (type) {
> @@ -1155,6 +1161,17 @@ static u64 mpam_msmon_overflow_val(enum mpam_device_features type)
>  	}
>  }
>  
> +static u64 mpam_msmon_overflow_val(enum mpam_device_features type,
> +				   struct mpam_msc *msc)
> +{
> +	u64 overflow_val = __mpam_msmon_overflow_val(type);
> +
> +	if (mpam_has_quirk(T241_MBW_COUNTER_SCALE_64, msc))
> +		overflow_val *= 64;
> +
> +	return overflow_val;

overflow_val wraps around for 63 bit counters. Do those need to be
considered for this errata?

> +}
> +
>  static void __ris_msmon_read(void *arg)
>  {
>  	u64 now;
> @@ -1245,13 +1262,16 @@ static void __ris_msmon_read(void *arg)
>  			now = FIELD_GET(MSMON___VALUE, now);
>  		}
>  
> +		if (mpam_has_quirk(T241_MBW_COUNTER_SCALE_64, msc))
> +			now *= 64;
> +
>  		if (nrdy)
>  			break;
>  
>  		mbwu_state = &ris->mbwu_state[ctx->mon];
>  
>  		if (overflow)
> -			mbwu_state->correction += mpam_msmon_overflow_val(m->type);
> +			mbwu_state->correction += mpam_msmon_overflow_val(m->type, msc);
>  
>  		/*
>  		 * Include bandwidth consumed before the last hardware reset and
> diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
> index 01882f0acee2..108a8373901c 100644
> --- a/drivers/resctrl/mpam_internal.h
> +++ b/drivers/resctrl/mpam_internal.h
> @@ -224,6 +224,7 @@ struct mpam_props {
>  enum mpam_device_quirks {
>  	T241_SCRUB_SHADOW_REGS,
>  	T241_FORCE_MBW_MIN_TO_ONE,
> +	T241_MBW_COUNTER_SCALE_64,
>  	MPAM_QUIRK_LAST,
>  };
>  

Thanks,

Ben



From Harini.T at amd.com  Tue Dec  9 09:28:47 2025
From: Harini.T at amd.com (T, Harini)
Date: Tue, 9 Dec 2025 17:28:47 +0000
Subject: [PATCH 2/4] rtc: zynqmp: rework read_offset
In-Reply-To: <20251201-zynqmp-rtc-updates-v1-2-33875c1e385b@vaisala.com>
References: <20251201-zynqmp-rtc-updates-v1-0-33875c1e385b@vaisala.com>
 <20251201-zynqmp-rtc-updates-v1-2-33875c1e385b@vaisala.com>
Message-ID: <LV5PR12MB98047B0A754AFFFB01163E0992A3A@LV5PR12MB9804.namprd12.prod.outlook.com>

[Public]

Hi,

> -----Original Message-----
> From: Tomas Melin <tomas.melin at vaisala.com>
> Sent: Monday, December 1, 2025 6:20 PM
> To: Alexandre Belloni <alexandre.belloni at bootlin.com>; Simek, Michal
> <michal.simek at amd.com>
> Cc: linux-rtc at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux-
> kernel at vger.kernel.org; Tomas Melin <tomas.melin at vaisala.com>
> Subject: [PATCH 2/4] rtc: zynqmp: rework read_offset
>
> Caution: This message originated from an External Source. Use proper
> caution when opening attachments, clicking links, or responding.
>
>
> read_offset() was using static frequency for determining the tick offset. It was
> also using remainder from do_div() operation as tick_mult value which
> caused the offset to be incorrect.
>
> At the same time, rework function to improve readability.
>
> Signed-off-by: Tomas Melin <tomas.melin at vaisala.com>
> ---
>  drivers/rtc/rtc-zynqmp.c | 25 ++++++++++++++++---------
>  1 file changed, 16 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c index
> 856bc1678e7d31144f320ae9f75fc58c742a2a64..7af5f6f99538f961a53ff56bfc6
> 56c907611b900 100644
> --- a/drivers/rtc/rtc-zynqmp.c
> +++ b/drivers/rtc/rtc-zynqmp.c
> @@ -178,21 +178,28 @@ static void xlnx_init_rtc(struct xlnx_rtc_dev
> *xrtcdev)  static int xlnx_rtc_read_offset(struct device *dev, long *offset)  {
>         struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
> -       unsigned long long rtc_ppb = RTC_PPB;
> -       unsigned int tick_mult = do_div(rtc_ppb, xrtcdev->freq);
> -       unsigned int calibval;
> +       unsigned int calibval, fract_data, fract_part;
Prefer one variable assignment per line for readability.
> +       int max_tick, tick_mult;
It would be better to explain why tick_mult is changed to int in the commit message.
> +       int freq = xrtcdev->freq;
Please follow reverse xmas tree variable ordering.
>         long offset_val;
>
> +       /* ticks to reach RTC_PPB */
The comment is misleading. Its tick_mult is nanoseconds per tick, not a tick count.
> +       tick_mult = DIV_ROUND_CLOSEST(RTC_PPB, freq);
> +
>         calibval = readl(xrtcdev->reg_base + RTC_CALIB_RD);
>         /* Offset with seconds ticks */
> -       offset_val = calibval & RTC_TICK_MASK;
> -       offset_val = offset_val - RTC_CALIB_DEF;
> -       offset_val = offset_val * tick_mult;
> +       max_tick = calibval & RTC_TICK_MASK;
> +       offset_val = max_tick - freq;
> +       /* Convert to ppb */
> +       offset_val *= tick_mult;
>
>         /* Offset with fractional ticks */
> -       if (calibval & RTC_FR_EN)
> -               offset_val += ((calibval & RTC_FR_MASK) >> RTC_FR_DATSHIFT)
> -                       * (tick_mult / RTC_FR_MAX_TICKS);
> +       if (calibval & RTC_FR_EN) {
> +               fract_data = (calibval & RTC_FR_MASK) >> RTC_FR_DATSHIFT;
> +               fract_part = DIV_ROUND_UP(tick_mult, RTC_FR_MAX_TICKS);
> +               offset_val += (fract_part * fract_data);
> +       }
> +
>         *offset = offset_val;
>
>         return 0;
>
> --
> 2.47.3
>
Regards,
Harini T


From seanjc at google.com  Tue Dec  9 09:37:13 2025
From: seanjc at google.com (Sean Christopherson)
Date: Tue, 9 Dec 2025 09:37:13 -0800
Subject: [PATCH v6 37/44] KVM: VMX: Dedup code for removing MSR from
 VMCS's auto-load list
In-Reply-To: <2440b9bf-a2a1-4f66-94b2-71f47d62f3db@linux.intel.com>
References: <20251206001720.468579-1-seanjc@google.com> <20251206001720.468579-38-seanjc@google.com>
 <2440b9bf-a2a1-4f66-94b2-71f47d62f3db@linux.intel.com>
Message-ID: <aTheSQb9fhXmZKw6@google.com>

On Mon, Dec 08, 2025, Dapeng Mi wrote:
> 
> On 12/6/2025 8:17 AM, Sean Christopherson wrote:
> > Add a helper to remove an MSR from an auto-{load,store} list to dedup the
> > msr_autoload code, and in anticipation of adding similar functionality for
> > msr_autostore.
> >
> > No functional change intended.
> >
> > Signed-off-by: Sean Christopherson <seanjc at google.com>
> > ---
> >  arch/x86/kvm/vmx/vmx.c | 31 ++++++++++++++++---------------
> >  1 file changed, 16 insertions(+), 15 deletions(-)
> >
> > diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> > index 52bcb817cc15..a51f66d1b201 100644
> > --- a/arch/x86/kvm/vmx/vmx.c
> > +++ b/arch/x86/kvm/vmx/vmx.c
> > @@ -1040,9 +1040,22 @@ static int vmx_find_loadstore_msr_slot(struct vmx_msrs *m, u32 msr)
> >  	return -ENOENT;
> >  }
> >  
> > +static void vmx_remove_auto_msr(struct vmx_msrs *m, u32 msr,
> > +				unsigned long vmcs_count_field)
> > +{
> > +	int i;
> > +
> > +	i = vmx_find_loadstore_msr_slot(m, msr);
> > +	if (i < 0)
> > +		return;
> > +
> > +	--m->nr;
> > +	m->val[i] = m->val[m->nr];
> 
> Sometimes the order of MSR writing does matter, e.g., PERF_GLOBAL_CTRL MSR
> should be written at last after all PMU MSR writing.

Hmm, no.  _If_ KVM were writing event selectors using the auto-load lists, then
KVM would need to bookend the event selector MSRs with PERF_GLOBAL_CTRL=0 and
PERF_GLOBAL_CTRL=<new context (guest vs. host)>.  E.g. so that guest PMC counts
aren't polluted with host events, and vice versa.

As things stand today, the only other MSRs are PEBS and the DS area configuration
stuff, and kinda to my earlier point, KVM pre-zeroes MSR_IA32_PEBS_ENABLE as part
of add_atomic_switch_msr() to ensure a quiescent period before VM-Enter.

Heh, and writing PERF_GLOBAL_CTRL last for that sequence might actually be
problematic.  E.g. load host PEBS with guest PERF_GLOBAL_CTRL active.

Anyways, I agree that this might be brittle, but this is all pre-existing behavior
so I don't want to tackle that here unless it's absolutely necessary.

Or wait, by "writing" do you mean "writing MSRs to memory", as opposed to "writing
values to MSRs"?  Regardless, I think my answer is the same: this isn't a problem
today, so I'd prefer to not shuffle the ordering unless it's absolutely necessary.

> So directly moving the last MSR entry into cleared one could break the MSR
> writing sequence and may cause issue in theory.
> 
> I know this won't really cause issue since currently vPMU won't use the MSR
> auto-load feature to save any PMU MSR, but it's still unsafe for future uses.?
> 
> I'm not sure if it's worthy to do the strict MSR entry shift right now.
>
> Perhaps we could add a message to warn users at least.

Hmm, yeah, but I'm not entirely sure where/how best to document this.  Because
it's not just that vmx_remove_auto_msr() arbitrarily maniuplates the order, e.g.
multiple calls to vmx_add_auto_msr() aren't guaranteed to provide ordering because
one or more MSRs may already be in the list.  And the "special" MSRs that can be
switched via dedicated VMCS fields further muddy the waters.

So I'm tempted to not add a comment to the helpers, or even the struct fields,
because unfortunately it's largely a "Here be dragons!" type warning. :-/


From james.clark at linaro.org  Tue Dec  9 09:55:51 2025
From: james.clark at linaro.org (James Clark)
Date: Tue, 9 Dec 2025 17:55:51 +0000
Subject: [PATCH v2 01/12] perf parse-events: Refactor get_config_terms()
 to remove macros
In-Reply-To: <CAP-5=fV_Y5W2RyJhBgnk49JuTf8EsyisY-LfL3sVhC4TVRC_gg@mail.gmail.com>
References: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
 <20251208-james-perf-config-bits-v2-1-4ac0281993b0@linaro.org>
 <6ba6bde3-f56b-4354-b336-4739cb1edb71@linaro.org>
 <CAP-5=fV_Y5W2RyJhBgnk49JuTf8EsyisY-LfL3sVhC4TVRC_gg@mail.gmail.com>
Message-ID: <d275d2fb-8670-4832-b9c4-de98376e58ad@linaro.org>



On 09/12/2025 15:58, Ian Rogers wrote:
> On Tue, Dec 9, 2025 at 4:48?AM James Clark <james.clark at linaro.org> wrote:
>>
>> On 08/12/2025 2:22 pm, James Clark wrote:
>>> The ADD_CONFIG_TERM() macros build the __type argument out of a partial
>>> EVSEL__CONFIG_TERM_x enum name. This means that they can't be called
>>> from a function where __type is a variable and it's also impossible to
>>> grep the codebase to find usages of these enums as they're never typed
>>> in full.
>>>
>>> Fix this by removing the macros and replacing them with an
>>> add_config_term() function. It seems the main reason these existed in
>>> the first place was to avoid type punning and to write to a specific
>>> field in the union, but the same thing can be achieved with a single
>>> write to a u64 'val' field.
>>>
>>> Signed-off-by: James Clark <james.clark at linaro.org>
>>> ---
>>>    tools/perf/util/evsel_config.h |   1 +
>>>    tools/perf/util/parse-events.c | 146 ++++++++++++++++++++++++-----------------
>>>    2 files changed, 86 insertions(+), 61 deletions(-)
>>>
>>> diff --git a/tools/perf/util/evsel_config.h b/tools/perf/util/evsel_config.h
>>> index bcd3a978f0c4..685fd8d5c4a8 100644
>>> --- a/tools/perf/util/evsel_config.h
>>> +++ b/tools/perf/util/evsel_config.h
>>> @@ -50,6 +50,7 @@ struct evsel_config_term {
>>>                u64           cfg_chg;
>>>                char          *str;
>>>                int           cpu;
>>> +             u64           val;
>>>        } val;
>>>        bool weak;
>>>    };
>>> diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
>>> index 17c1c36a7bf9..d5b009b4ebab 100644
>>> --- a/tools/perf/util/parse-events.c
>>> +++ b/tools/perf/util/parse-events.c
>>> @@ -1116,105 +1116,107 @@ static int config_attr(struct perf_event_attr *attr,
>>>        return 0;
>>>    }
>>>
>>> -static int get_config_terms(const struct parse_events_terms *head_config,
>>> -                         struct list_head *head_terms)
>>> +static struct evsel_config_term *add_config_term(enum evsel_term_type type,
>>> +                                              struct list_head *head_terms,
>>> +                                              bool weak)
>>>    {
>>> -#define ADD_CONFIG_TERM(__type, __weak)                              \
>>> -     struct evsel_config_term *__t;                  \
>>> -                                                             \
>>> -     __t = zalloc(sizeof(*__t));                             \
>>> -     if (!__t)                                               \
>>> -             return -ENOMEM;                                 \
>>> -                                                             \
>>> -     INIT_LIST_HEAD(&__t->list);                             \
>>> -     __t->type       = EVSEL__CONFIG_TERM_ ## __type;        \
>>> -     __t->weak       = __weak;                               \
>>> -     list_add_tail(&__t->list, head_terms)
>>> -
>>> -#define ADD_CONFIG_TERM_VAL(__type, __name, __val, __weak)   \
>>> -do {                                                         \
>>> -     ADD_CONFIG_TERM(__type, __weak);                        \
>>> -     __t->val.__name = __val;                                \
>>> -} while (0)
>>> +     struct evsel_config_term *t;
>>>
>>> -#define ADD_CONFIG_TERM_STR(__type, __val, __weak)           \
>>> -do {                                                         \
>>> -     ADD_CONFIG_TERM(__type, __weak);                        \
>>> -     __t->val.str = strdup(__val);                           \
>>> -     if (!__t->val.str) {                                    \
>>> -             zfree(&__t);                                    \
>>> -             return -ENOMEM;                                 \
>>> -     }                                                       \
>>> -     __t->free_str = true;                                   \
>>> -} while (0)
>>> +     t = zalloc(sizeof(*t));
>>> +     if (!t)
>>> +             return NULL;
>>> +
>>> +     INIT_LIST_HEAD(&t->list);
>>> +     t->type = type;
>>> +     t->weak = weak;
>>> +     list_add_tail(&t->list, head_terms);
>>>
>>> +     return t;
>>> +}
>>> +
>>> +static int get_config_terms(const struct parse_events_terms *head_config,
>>> +                         struct list_head *head_terms)
>>> +{
>>>        struct parse_events_term *term;
>>>
>>>        list_for_each_entry(term, &head_config->terms, list) {
>>> +             struct evsel_config_term *new_term;
>>> +             enum evsel_term_type new_type;
>>> +             char *str = NULL;
>>> +             u64 val;
>>> +
>>>                switch (term->type_term) {
>>>                case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
>>> -                     ADD_CONFIG_TERM_VAL(PERIOD, period, term->val.num, term->weak);
>>> +                     new_type = EVSEL__CONFIG_TERM_PERIOD;
>>> +                     val = term->val.num;
>>>                        break;
>>>                case PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ:
>>> -                     ADD_CONFIG_TERM_VAL(FREQ, freq, term->val.num, term->weak);
>>> +                     new_type = EVSEL__CONFIG_TERM_FREQ;
>>> +                     val = term->val.num;
>>>                        break;
>>>                case PARSE_EVENTS__TERM_TYPE_TIME:
>>> -                     ADD_CONFIG_TERM_VAL(TIME, time, term->val.num, term->weak);
>>> +                     new_type = EVSEL__CONFIG_TERM_TIME;
>>> +                     val = term->val.num;
>>>                        break;
>>>                case PARSE_EVENTS__TERM_TYPE_CALLGRAPH:
>>> -                     ADD_CONFIG_TERM_STR(CALLGRAPH, term->val.str, term->weak);
>>> +                     new_type = EVSEL__CONFIG_TERM_CALLGRAPH;
>>> +                     str = term->val.str;
>>>                        break;
>>>                case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
>>> -                     ADD_CONFIG_TERM_STR(BRANCH, term->val.str, term->weak);
>>> +                     new_type = EVSEL__CONFIG_TERM_BRANCH;
>>> +                     str = term->val.str;
>>>                        break;
>>>                case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
>>> -                     ADD_CONFIG_TERM_VAL(STACK_USER, stack_user,
>>> -                                         term->val.num, term->weak);
>>> +                     new_type = EVSEL__CONFIG_TERM_STACK_USER;
>>> +                     val = term->val.num;
>>>                        break;
>>>                case PARSE_EVENTS__TERM_TYPE_INHERIT:
>>> -                     ADD_CONFIG_TERM_VAL(INHERIT, inherit,
>>> -                                         term->val.num ? 1 : 0, term->weak);
>>> +                     new_type = EVSEL__CONFIG_TERM_INHERIT;
>>> +                     val = term->val.num ? 1 : 0;
>>>                        break;
>>>                case PARSE_EVENTS__TERM_TYPE_NOINHERIT:
>>> -                     ADD_CONFIG_TERM_VAL(INHERIT, inherit,
>>> -                                         term->val.num ? 0 : 1, term->weak);
>>> +                     new_type = EVSEL__CONFIG_TERM_INHERIT;
>>> +                     val = term->val.num ? 0 : 1;
>>>                        break;
>>>                case PARSE_EVENTS__TERM_TYPE_MAX_STACK:
>>> -                     ADD_CONFIG_TERM_VAL(MAX_STACK, max_stack,
>>> -                                         term->val.num, term->weak);
>>> +                     new_type = EVSEL__CONFIG_TERM_MAX_STACK;
>>> +                     val = term->val.num;
>>>                        break;
>>>                case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS:
>>> -                     ADD_CONFIG_TERM_VAL(MAX_EVENTS, max_events,
>>> -                                         term->val.num, term->weak);
>>> +                     new_type = EVSEL__CONFIG_TERM_MAX_EVENTS;
>>> +                     val = term->val.num;
>>>                        break;
>>>                case PARSE_EVENTS__TERM_TYPE_OVERWRITE:
>>> -                     ADD_CONFIG_TERM_VAL(OVERWRITE, overwrite,
>>> -                                         term->val.num ? 1 : 0, term->weak);
>>> +                     new_type = EVSEL__CONFIG_TERM_OVERWRITE;
>>> +                     val = term->val.num ? 1 : 0;
>>>                        break;
>>>                case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE:
>>> -                     ADD_CONFIG_TERM_VAL(OVERWRITE, overwrite,
>>> -                                         term->val.num ? 0 : 1, term->weak);
>>> +                     new_type = EVSEL__CONFIG_TERM_OVERWRITE;
>>> +                     val = term->val.num ? 0 : 1;
>>>                        break;
>>>                case PARSE_EVENTS__TERM_TYPE_DRV_CFG:
>>> -                     ADD_CONFIG_TERM_STR(DRV_CFG, term->val.str, term->weak);
>>> +                     new_type = EVSEL__CONFIG_TERM_DRV_CFG;
>>> +                     str = term->val.str;
>>>                        break;
>>>                case PARSE_EVENTS__TERM_TYPE_PERCORE:
>>> -                     ADD_CONFIG_TERM_VAL(PERCORE, percore,
>>> -                                         term->val.num ? true : false, term->weak);
>>> +                     new_type = EVSEL__CONFIG_TERM_PERCORE;
>>> +                     val = term->val.num ? true : false;
>>>                        break;
>>>                case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT:
>>> -                     ADD_CONFIG_TERM_VAL(AUX_OUTPUT, aux_output,
>>> -                                         term->val.num ? 1 : 0, term->weak);
>>> +                     new_type = EVSEL__CONFIG_TERM_AUX_OUTPUT;
>>> +                     val = term->val.num ? 1 : 0;
>>>                        break;
>>>                case PARSE_EVENTS__TERM_TYPE_AUX_ACTION:
>>> -                     ADD_CONFIG_TERM_STR(AUX_ACTION, term->val.str, term->weak);
>>> +                     new_type = EVSEL__CONFIG_TERM_AUX_ACTION;
>>> +                     str = term->val.str;
>>>                        break;
>>>                case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE:
>>> -                     ADD_CONFIG_TERM_VAL(AUX_SAMPLE_SIZE, aux_sample_size,
>>> -                                         term->val.num, term->weak);
>>> +                     new_type = EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE;
>>> +                     val = term->val.num;
>>>                        break;
>>>                case PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV:
>>> -                     ADD_CONFIG_TERM_STR(RATIO_TO_PREV, term->val.str, term->weak);
>>> +                     new_type = EVSEL__CONFIG_TERM_RATIO_TO_PREV;
>>> +                     str = term->val.str;
>>>                        break;
>>>                case PARSE_EVENTS__TERM_TYPE_USER:
>>>                case PARSE_EVENTS__TERM_TYPE_CONFIG:
>>> @@ -1229,7 +1231,23 @@ do {                                                           \
>>>                case PARSE_EVENTS__TERM_TYPE_RAW:
>>>                case PARSE_EVENTS__TERM_TYPE_CPU:
>>>                default:
>>> -                     break;
>>> +                     /* Don't add a new term for these ones */
>>> +                     continue;
>>> +             }
>>> +
>>> +             new_term = add_config_term(new_type, head_terms, term->weak);
>>> +             if (!new_term)
>>> +                     return -ENOMEM;
>>> +
>>> +             if (str) {
>>> +                     new_term->val.str = strdup(str);
>>> +                     if (!new_term->val.str) {
>>> +                             zfree(&new_term);
>>> +                             return -ENOMEM;
>>> +                     }
>>> +                     new_term->free_str = true;
>>> +             } else {
>>
>> This will incorrectly hit the else if term->val.str is NULL. Not sure if
>> that can happen but will fix anyway.
>>
>>> +                     new_term->val.val = val;
>>
>> There's an uninitialized variable warning for val here on release
>> builds. Will fix too
> 
> I'm not sure how I feel about the change, but did you check that it is
> ubsan clean? I worry it is introducing writes to "val" and then reads
> from say "period" in the evsel_config_term val union. I believe ubsan
> will flag this as:
> https://en.cppreference.com/w/cpp/language/union.html
> "It is undefined behavior to read from the member of the union that
> wasn't most recently written."
> 
> Thanks,
> Ian
> 

Maybe for C++, but not for C [1]:

   Accessing my_union.i after most recently writing to the other member,
   my_union.d, is an allowed form of type-punning in C, provided that the
   member read is not larger than the one whose value was set

Type punning with unions is widely used in the kernel and there are a 
couple of instances in Perf. There are tons of discussions about it on 
the mailing lists too. I can check it with ubsan though.

[1]: https://en.wikipedia.org/wiki/Type_punning#C_and_C++

>>>                }
>>>        }
>>>        return 0;
>>> @@ -1290,10 +1308,16 @@ static int get_config_chgs(struct perf_pmu *pmu, struct parse_events_terms *head
>>>                }
>>>        }
>>>
>>> -     if (bits)
>>> -             ADD_CONFIG_TERM_VAL(CFG_CHG, cfg_chg, bits, false);
>>> +     if (bits) {
>>> +             struct evsel_config_term *new_term;
>>> +
>>> +             new_term = add_config_term(EVSEL__CONFIG_TERM_CFG_CHG,
>>> +                                        head_terms, false);
>>> +             if (!new_term)
>>> +                     return -ENOMEM;
>>> +             new_term->val.cfg_chg = bits;
>>> +     }
>>>
>>> -#undef ADD_CONFIG_TERM
>>>        return 0;
>>>    }
>>>
>>>
>>



From andrea.porta at suse.com  Tue Dec  9 09:58:58 2025
From: andrea.porta at suse.com (Andrea della Porta)
Date: Tue, 9 Dec 2025 18:58:58 +0100
Subject: [PATCH] dt-bindings: pci: brcmstb: Add rp1-nexus node to fix DTC
 warning
In-Reply-To: <CAL_JsqJUzB71QdMcxJtNZ7raoPcK+SfTh7EVzGmk=syo8xLKQw@mail.gmail.com>
References: <20250812085037.13517-1-andrea.porta@suse.com>
 <4fee3870-f9d5-48e3-a5be-6df581d3e296@kernel.org>
 <aKc5nMT1xXpY03ip@apocalypse>
 <e7875f70-2b79-48e0-a63b-caf6f1fd287b@kernel.org>
 <aLVePQRfU4IB1zK8@apocalypse>
 <CAL_JsqJUzB71QdMcxJtNZ7raoPcK+SfTh7EVzGmk=syo8xLKQw@mail.gmail.com>
Message-ID: <aThjYt3ux0U-9-3A@apocalypse>

Hi Rob,

On 11:09 Thu 04 Dec     , Rob Herring wrote:
> On Mon, Sep 1, 2025 at 3:48?AM Andrea della Porta <andrea.porta at suse.com> wrote:
> >
> > Hi Krzysztof,
> >
> > On 08:50 Fri 22 Aug     , Krzysztof Kozlowski wrote:
> > > On 21/08/2025 17:22, Andrea della Porta wrote:
> > > > Hi Krzysztof,
> > > >
> > > > On 10:55 Tue 12 Aug     , Krzysztof Kozlowski wrote:
> > > >> On 12/08/2025 10:50, Andrea della Porta wrote:
> > > >>> The devicetree compiler is complaining as follows:
> > > >>>
> > > >>> arch/arm64/boot/dts/broadcom/rp1-nexus.dtsi:3.11-14.3: Warning (unit_address_vs_reg): /axi/pcie at 1000120000/rp1_nexus: node has a reg or ranges property, but no unit name
> > > >>> /home/andrea/linux-torvalds/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dtb: pcie at 1000120000: Unevaluated properties are not allowed ('rp1_nexus' was unexpected)
> > > >>
> > > >> Please trim the paths.
> > > >
> > > > Ack.
> > > >
> > > >>
> > > >>>
> > > >>> Add the optional node that fix this to the DT binding.
> > > >>>
> > > >>> Reported-by: kernel test robot <lkp at intel.com>
> > > >>> Closes: https://lore.kernel.org/oe-kbuild-all/202506041952.baJDYBT4-lkp at intel.com/
> > > >>> Signed-off-by: Andrea della Porta <andrea.porta at suse.com>
> > > >>> ---
> > > >>>  Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml | 9 +++++++++
> > > >>>  1 file changed, 9 insertions(+)
> > > >>>
> > > >>> diff --git a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
> > > >>> index 812ef5957cfc..7d8ba920b652 100644
> > > >>> --- a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
> > > >>> +++ b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
> > > >>> @@ -126,6 +126,15 @@ required:
> > > >>>  allOf:
> > > >>>    - $ref: /schemas/pci/pci-host-bridge.yaml#
> > > >>>    - $ref: /schemas/interrupt-controller/msi-controller.yaml#
> > > >>> +  - if:
> > > >>> +      properties:
> > > >>> +        compatible:
> > > >>> +          contains:
> > > >>> +            const: brcm,bcm2712-pcie
> > > >>> +    then:
> > > >>> +      properties:
> > > >>> +        rp1_nexus:
> > > >>
> > > >> No, you cannot document post-factum... This does not follow DTS coding
> > > >> style.
> > > >
> > > > I think I didn't catch what you mean here: would that mean that
> > > > we cannot resolve that warning since we cannot add anything to the
> > > > binding?
> > >
> > > I meant, you cannot use a warning from the code you recently introduced
> > > as a reason to use incorrect style.
> > >
> > > Fixing warning is of course fine and correct, but for the code recently
> > > introduced and which bypassed ABI review it is basically like new review
> > > of new ABI.
> > >
> > > This needs standard review practice, so you need to document WHY you
> > > need such node. Warning is not the reason here why you are doing. If
> > > this was part of original patchset, like it should have been, you would
> > > not use some imaginary warning as reason, right?
> > >
> > > So provide reason why you need here this dedicated child, what is that
> > > child representing.
> >
> > Ack.
> >
> > >
> > > Otherwise I can suggest: drop the child and DTSO, this also solves the
> > > warning...
> >
> > This would not fix the issue: it's the non overlay that needs the specific
> > node. But I got the point, and we have a solution for that (see below).
> >
> > >
> > > >
> > > > Regarding rp1_nexus, you're right I guess it should be
> > > > rp1-nexus as per DTS coding style.
> > > >
> > > >>
> > > >> Also:
> > > >>
> > > >> Node names should be generic. See also an explanation and list of
> > > >> examples (not exhaustive) in DT specification:
> > > >> https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation
> > > >
> > > > In this case it could be difficult: we need to search for a DT node
> > >
> > > Search like in driver? That's wrong, you should be searching by compatible.
> >
> > Thanks for the hint. Searching by compatble is the solution.
> 
> No, it is not.

This is partly true, indeed. On one side there's the need to avoid a
specific node name ('rp1_nexus'), so the only other unique identifier would
be the compatible string ('pci1de4,1' in this case, which identifies that specific
device). Unfortunately, the same compatible string is also assigned to the pci
endpoint node filled automatically by enabling CONFIG_PCI_DYNAMIC_OF_NODES.
We would end up with two nodes with the same compatible, which is not unique
anymore. 
This applies only when using 'full' dtb (bcm2712-rpi-5-b.dtb) *and* you enable
CONFIG_PCI_DYNAMIC_OF_NODES, the latter being not necessary since the overlay dtb
(...-ovl-rp1.dtb) is not in use here. To overcome this problem, the solutions
I can think of are the following:

1- Just disable CONFIG_PCI_DYNAMIC_OF_NODES should work, but only when using the
   full dtb version. However, if the user enable that option for debug or to use
   the overlay dtb version, he better be sure not to use teh full dtb or it won't
   work.
   This solution seems really weak.

2- Add another compatible string other than 'pci1de4,1', so it will be really
   unique.

> 
> > >
> > > > starting from the DT root and using generic names like pci at 0,0 or
> > > > dev at 0,0 could possibly led to conflicts with other peripherals.
> > > > That's why I chose a specific name.
> > >
> > > Dunno, depends what can be there, but you do not get a specific
> > > (non-generic) device node name for a generic PCI device or endpoint.
> >
> > I would use 'port' instead of rp1-nexus. Would it work for you?
> 
> Do you still plan to fix this? This is broken far worse than just the node name.

Yes, if we want to get rid of that nasty warning and comply with DT guidelines,
I think I really need to fix that.

> 
> The 'rp1_nexus' node is applied to the PCI host bridge. That's wrong
> unless this is PCI rather than PCIe. There's the root port device in
> between.
> 
> The clue that things are wrong are start in the driver here:
> 
> rp1_node = of_find_node_by_name(NULL, "rp1_nexus");
> if (!rp1_node) {
>   rp1_node = dev_of_node(dev);
>   skip_ovl = false;
> }
> 
> You should not need to do this nor care what the node name is. The PCI
> core should have populated pdev->dev.of_node for you. If not, your DT
> is wrong. Turn on CONFIG_PCI_DYNAMIC_OF_NODES and look at the
> resulting PCI nodes. They should also match what the hierarchy looks
> like with lspci. I don't recommend you rely on
> CONFIG_PCI_DYNAMIC_OF_NODES, but statically populate the nodes in the
> DT. First, CONFIG_PCI_DYNAMIC_OF_NODES is an under development thing
> and I hope to get rid of the config option. Second, your case is
> static (i.e. not a PCIe card in a slot) so there is no issue
> hardcoding the DT.

The 'full' dtb (bcm2712-rpi-5-b.dtb) is indeed statically populated.
CONFIG_PCI_DYNAMIC_OF_NODES is needed only if you use the overlay approach
(bcm2712-rpi-5-b-ovl-rp1.dtb) and in that case the node will be
added to the correct device node at runtime, and there won't be any node
labeled as rp1_nexus.
That conditional just check for teh presence of the rp1_nexus node to
choose if the overlay should be loaded at runtime (if rp1_nexus is present,
then we are in the static case so no overlay need to be loaded).

> 
> As far as the node name, I don't care so much as long as the driver
> doesn't care and you don't use '_' or 'pcie?' (that's for PCI
> bridges).
> 
> And why do we have drivers/misc/rp1/rp1-pci.dtso and a .dtso in
> arch/arm64? There should not be both.

drivers/misc/rp1/rp1-pci.dtso is just a wrapper over rp1-common.dtsi,
which is to be compiled in as binary blob in the driver and loaded at
runtime.
rp1.dtbo is optional, it's there just for completeness in case anyone want
to load teh overlay from the fw, as explained here:
https://lore.kernel.org/all/ab9ab3536baf5fdf6016f2a01044f00034189291.1742418429.git.andrea.porta at suse.com/
If it causes confusion, we can probably get rid of it with no penalty.

Many thanks,
Andrea

> 
> Rob


From irogers at google.com  Tue Dec  9 10:09:37 2025
From: irogers at google.com (Ian Rogers)
Date: Tue, 9 Dec 2025 10:09:37 -0800
Subject: [PATCH v2 01/12] perf parse-events: Refactor get_config_terms()
 to remove macros
In-Reply-To: <d275d2fb-8670-4832-b9c4-de98376e58ad@linaro.org>
References: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
 <20251208-james-perf-config-bits-v2-1-4ac0281993b0@linaro.org>
 <6ba6bde3-f56b-4354-b336-4739cb1edb71@linaro.org> <CAP-5=fV_Y5W2RyJhBgnk49JuTf8EsyisY-LfL3sVhC4TVRC_gg@mail.gmail.com>
 <d275d2fb-8670-4832-b9c4-de98376e58ad@linaro.org>
Message-ID: <CAP-5=fW6_MVrezxT6ssjhWnYtF_51nvuFCCSPaHzqwYw9EK4Wg@mail.gmail.com>

On Tue, Dec 9, 2025 at 9:55?AM James Clark <james.clark at linaro.org> wrote:
>
> On 09/12/2025 15:58, Ian Rogers wrote:
> > On Tue, Dec 9, 2025 at 4:48?AM James Clark <james.clark at linaro.org> wrote:
> >>
> >> On 08/12/2025 2:22 pm, James Clark wrote:
> >>> The ADD_CONFIG_TERM() macros build the __type argument out of a partial
> >>> EVSEL__CONFIG_TERM_x enum name. This means that they can't be called
> >>> from a function where __type is a variable and it's also impossible to
> >>> grep the codebase to find usages of these enums as they're never typed
> >>> in full.
> >>>
> >>> Fix this by removing the macros and replacing them with an
> >>> add_config_term() function. It seems the main reason these existed in
> >>> the first place was to avoid type punning and to write to a specific
> >>> field in the union, but the same thing can be achieved with a single
> >>> write to a u64 'val' field.
> >>>
> >>> Signed-off-by: James Clark <james.clark at linaro.org>
> >>> ---
> >>>    tools/perf/util/evsel_config.h |   1 +
> >>>    tools/perf/util/parse-events.c | 146 ++++++++++++++++++++++++-----------------
> >>>    2 files changed, 86 insertions(+), 61 deletions(-)
> >>>
> >>> diff --git a/tools/perf/util/evsel_config.h b/tools/perf/util/evsel_config.h
> >>> index bcd3a978f0c4..685fd8d5c4a8 100644
> >>> --- a/tools/perf/util/evsel_config.h
> >>> +++ b/tools/perf/util/evsel_config.h
> >>> @@ -50,6 +50,7 @@ struct evsel_config_term {
> >>>                u64           cfg_chg;
> >>>                char          *str;
> >>>                int           cpu;
> >>> +             u64           val;
> >>>        } val;
> >>>        bool weak;
> >>>    };
> >>> diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
> >>> index 17c1c36a7bf9..d5b009b4ebab 100644
> >>> --- a/tools/perf/util/parse-events.c
> >>> +++ b/tools/perf/util/parse-events.c
> >>> @@ -1116,105 +1116,107 @@ static int config_attr(struct perf_event_attr *attr,
> >>>        return 0;
> >>>    }
> >>>
> >>> -static int get_config_terms(const struct parse_events_terms *head_config,
> >>> -                         struct list_head *head_terms)
> >>> +static struct evsel_config_term *add_config_term(enum evsel_term_type type,
> >>> +                                              struct list_head *head_terms,
> >>> +                                              bool weak)
> >>>    {
> >>> -#define ADD_CONFIG_TERM(__type, __weak)                              \
> >>> -     struct evsel_config_term *__t;                  \
> >>> -                                                             \
> >>> -     __t = zalloc(sizeof(*__t));                             \
> >>> -     if (!__t)                                               \
> >>> -             return -ENOMEM;                                 \
> >>> -                                                             \
> >>> -     INIT_LIST_HEAD(&__t->list);                             \
> >>> -     __t->type       = EVSEL__CONFIG_TERM_ ## __type;        \
> >>> -     __t->weak       = __weak;                               \
> >>> -     list_add_tail(&__t->list, head_terms)
> >>> -
> >>> -#define ADD_CONFIG_TERM_VAL(__type, __name, __val, __weak)   \
> >>> -do {                                                         \
> >>> -     ADD_CONFIG_TERM(__type, __weak);                        \
> >>> -     __t->val.__name = __val;                                \
> >>> -} while (0)
> >>> +     struct evsel_config_term *t;
> >>>
> >>> -#define ADD_CONFIG_TERM_STR(__type, __val, __weak)           \
> >>> -do {                                                         \
> >>> -     ADD_CONFIG_TERM(__type, __weak);                        \
> >>> -     __t->val.str = strdup(__val);                           \
> >>> -     if (!__t->val.str) {                                    \
> >>> -             zfree(&__t);                                    \
> >>> -             return -ENOMEM;                                 \
> >>> -     }                                                       \
> >>> -     __t->free_str = true;                                   \
> >>> -} while (0)
> >>> +     t = zalloc(sizeof(*t));
> >>> +     if (!t)
> >>> +             return NULL;
> >>> +
> >>> +     INIT_LIST_HEAD(&t->list);
> >>> +     t->type = type;
> >>> +     t->weak = weak;
> >>> +     list_add_tail(&t->list, head_terms);
> >>>
> >>> +     return t;
> >>> +}
> >>> +
> >>> +static int get_config_terms(const struct parse_events_terms *head_config,
> >>> +                         struct list_head *head_terms)
> >>> +{
> >>>        struct parse_events_term *term;
> >>>
> >>>        list_for_each_entry(term, &head_config->terms, list) {
> >>> +             struct evsel_config_term *new_term;
> >>> +             enum evsel_term_type new_type;
> >>> +             char *str = NULL;
> >>> +             u64 val;
> >>> +
> >>>                switch (term->type_term) {
> >>>                case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
> >>> -                     ADD_CONFIG_TERM_VAL(PERIOD, period, term->val.num, term->weak);
> >>> +                     new_type = EVSEL__CONFIG_TERM_PERIOD;
> >>> +                     val = term->val.num;
> >>>                        break;
> >>>                case PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ:
> >>> -                     ADD_CONFIG_TERM_VAL(FREQ, freq, term->val.num, term->weak);
> >>> +                     new_type = EVSEL__CONFIG_TERM_FREQ;
> >>> +                     val = term->val.num;
> >>>                        break;
> >>>                case PARSE_EVENTS__TERM_TYPE_TIME:
> >>> -                     ADD_CONFIG_TERM_VAL(TIME, time, term->val.num, term->weak);
> >>> +                     new_type = EVSEL__CONFIG_TERM_TIME;
> >>> +                     val = term->val.num;
> >>>                        break;
> >>>                case PARSE_EVENTS__TERM_TYPE_CALLGRAPH:
> >>> -                     ADD_CONFIG_TERM_STR(CALLGRAPH, term->val.str, term->weak);
> >>> +                     new_type = EVSEL__CONFIG_TERM_CALLGRAPH;
> >>> +                     str = term->val.str;
> >>>                        break;
> >>>                case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
> >>> -                     ADD_CONFIG_TERM_STR(BRANCH, term->val.str, term->weak);
> >>> +                     new_type = EVSEL__CONFIG_TERM_BRANCH;
> >>> +                     str = term->val.str;
> >>>                        break;
> >>>                case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
> >>> -                     ADD_CONFIG_TERM_VAL(STACK_USER, stack_user,
> >>> -                                         term->val.num, term->weak);
> >>> +                     new_type = EVSEL__CONFIG_TERM_STACK_USER;
> >>> +                     val = term->val.num;
> >>>                        break;
> >>>                case PARSE_EVENTS__TERM_TYPE_INHERIT:
> >>> -                     ADD_CONFIG_TERM_VAL(INHERIT, inherit,
> >>> -                                         term->val.num ? 1 : 0, term->weak);
> >>> +                     new_type = EVSEL__CONFIG_TERM_INHERIT;
> >>> +                     val = term->val.num ? 1 : 0;
> >>>                        break;
> >>>                case PARSE_EVENTS__TERM_TYPE_NOINHERIT:
> >>> -                     ADD_CONFIG_TERM_VAL(INHERIT, inherit,
> >>> -                                         term->val.num ? 0 : 1, term->weak);
> >>> +                     new_type = EVSEL__CONFIG_TERM_INHERIT;
> >>> +                     val = term->val.num ? 0 : 1;
> >>>                        break;
> >>>                case PARSE_EVENTS__TERM_TYPE_MAX_STACK:
> >>> -                     ADD_CONFIG_TERM_VAL(MAX_STACK, max_stack,
> >>> -                                         term->val.num, term->weak);
> >>> +                     new_type = EVSEL__CONFIG_TERM_MAX_STACK;
> >>> +                     val = term->val.num;
> >>>                        break;
> >>>                case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS:
> >>> -                     ADD_CONFIG_TERM_VAL(MAX_EVENTS, max_events,
> >>> -                                         term->val.num, term->weak);
> >>> +                     new_type = EVSEL__CONFIG_TERM_MAX_EVENTS;
> >>> +                     val = term->val.num;
> >>>                        break;
> >>>                case PARSE_EVENTS__TERM_TYPE_OVERWRITE:
> >>> -                     ADD_CONFIG_TERM_VAL(OVERWRITE, overwrite,
> >>> -                                         term->val.num ? 1 : 0, term->weak);
> >>> +                     new_type = EVSEL__CONFIG_TERM_OVERWRITE;
> >>> +                     val = term->val.num ? 1 : 0;
> >>>                        break;
> >>>                case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE:
> >>> -                     ADD_CONFIG_TERM_VAL(OVERWRITE, overwrite,
> >>> -                                         term->val.num ? 0 : 1, term->weak);
> >>> +                     new_type = EVSEL__CONFIG_TERM_OVERWRITE;
> >>> +                     val = term->val.num ? 0 : 1;
> >>>                        break;
> >>>                case PARSE_EVENTS__TERM_TYPE_DRV_CFG:
> >>> -                     ADD_CONFIG_TERM_STR(DRV_CFG, term->val.str, term->weak);
> >>> +                     new_type = EVSEL__CONFIG_TERM_DRV_CFG;
> >>> +                     str = term->val.str;
> >>>                        break;
> >>>                case PARSE_EVENTS__TERM_TYPE_PERCORE:
> >>> -                     ADD_CONFIG_TERM_VAL(PERCORE, percore,
> >>> -                                         term->val.num ? true : false, term->weak);
> >>> +                     new_type = EVSEL__CONFIG_TERM_PERCORE;
> >>> +                     val = term->val.num ? true : false;
> >>>                        break;
> >>>                case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT:
> >>> -                     ADD_CONFIG_TERM_VAL(AUX_OUTPUT, aux_output,
> >>> -                                         term->val.num ? 1 : 0, term->weak);
> >>> +                     new_type = EVSEL__CONFIG_TERM_AUX_OUTPUT;
> >>> +                     val = term->val.num ? 1 : 0;
> >>>                        break;
> >>>                case PARSE_EVENTS__TERM_TYPE_AUX_ACTION:
> >>> -                     ADD_CONFIG_TERM_STR(AUX_ACTION, term->val.str, term->weak);
> >>> +                     new_type = EVSEL__CONFIG_TERM_AUX_ACTION;
> >>> +                     str = term->val.str;
> >>>                        break;
> >>>                case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE:
> >>> -                     ADD_CONFIG_TERM_VAL(AUX_SAMPLE_SIZE, aux_sample_size,
> >>> -                                         term->val.num, term->weak);
> >>> +                     new_type = EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE;
> >>> +                     val = term->val.num;
> >>>                        break;
> >>>                case PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV:
> >>> -                     ADD_CONFIG_TERM_STR(RATIO_TO_PREV, term->val.str, term->weak);
> >>> +                     new_type = EVSEL__CONFIG_TERM_RATIO_TO_PREV;
> >>> +                     str = term->val.str;
> >>>                        break;
> >>>                case PARSE_EVENTS__TERM_TYPE_USER:
> >>>                case PARSE_EVENTS__TERM_TYPE_CONFIG:
> >>> @@ -1229,7 +1231,23 @@ do {                                                           \
> >>>                case PARSE_EVENTS__TERM_TYPE_RAW:
> >>>                case PARSE_EVENTS__TERM_TYPE_CPU:
> >>>                default:
> >>> -                     break;
> >>> +                     /* Don't add a new term for these ones */
> >>> +                     continue;
> >>> +             }
> >>> +
> >>> +             new_term = add_config_term(new_type, head_terms, term->weak);
> >>> +             if (!new_term)
> >>> +                     return -ENOMEM;
> >>> +
> >>> +             if (str) {
> >>> +                     new_term->val.str = strdup(str);
> >>> +                     if (!new_term->val.str) {
> >>> +                             zfree(&new_term);
> >>> +                             return -ENOMEM;
> >>> +                     }
> >>> +                     new_term->free_str = true;
> >>> +             } else {
> >>
> >> This will incorrectly hit the else if term->val.str is NULL. Not sure if
> >> that can happen but will fix anyway.
> >>
> >>> +                     new_term->val.val = val;
> >>
> >> There's an uninitialized variable warning for val here on release
> >> builds. Will fix too
> >
> > I'm not sure how I feel about the change, but did you check that it is
> > ubsan clean? I worry it is introducing writes to "val" and then reads
> > from say "period" in the evsel_config_term val union. I believe ubsan
> > will flag this as:
> > https://en.cppreference.com/w/cpp/language/union.html
> > "It is undefined behavior to read from the member of the union that
> > wasn't most recently written."
> >
> > Thanks,
> > Ian
> >
>
> Maybe for C++, but not for C [1]:
>
>    Accessing my_union.i after most recently writing to the other member,
>    my_union.d, is an allowed form of type-punning in C, provided that the
>    member read is not larger than the one whose value was set
>
> Type punning with unions is widely used in the kernel and there are a
> couple of instances in Perf. There are tons of discussions about it on
> the mailing lists too. I can check it with ubsan though.

Thanks. I'm mostly worried about ubsan being clean. One of those
mailing list discussions, or sadly outside the usual trolls lack of
discussion, is my trying to remove a prevalent source of type punning:
https://lore.kernel.org/lkml/20251016205126.2882625-1-irogers at google.com/

Ian

> [1]: https://en.wikipedia.org/wiki/Type_punning#C_and_C++
>
> >>>                }
> >>>        }
> >>>        return 0;
> >>> @@ -1290,10 +1308,16 @@ static int get_config_chgs(struct perf_pmu *pmu, struct parse_events_terms *head
> >>>                }
> >>>        }
> >>>
> >>> -     if (bits)
> >>> -             ADD_CONFIG_TERM_VAL(CFG_CHG, cfg_chg, bits, false);
> >>> +     if (bits) {
> >>> +             struct evsel_config_term *new_term;
> >>> +
> >>> +             new_term = add_config_term(EVSEL__CONFIG_TERM_CFG_CHG,
> >>> +                                        head_terms, false);
> >>> +             if (!new_term)
> >>> +                     return -ENOMEM;
> >>> +             new_term->val.cfg_chg = bits;
> >>> +     }
> >>>
> >>> -#undef ADD_CONFIG_TERM
> >>>        return 0;
> >>>    }
> >>>
> >>>
> >>
>


From s-ramamoorthy at ti.com  Tue Dec  9 10:16:05 2025
From: s-ramamoorthy at ti.com (Shree Ramamoorthy)
Date: Tue, 9 Dec 2025 12:16:05 -0600
Subject: tps65219/am62p kernel oops
In-Reply-To: <20251209134343.GA238880@francesco-nb>
References: <aBDSTxALaOc-PD7X@gaggiata.pivistrello.it>
 <20250429185240.6a7644bf@akair> <20250430080109.GA65078@francesco-nb>
 <aBH5s7p2RxLGjTQD@gaggiata.pivistrello.it>
 <23eeda43-a938-4c15-aee3-b1b9df217ff8@ti.com>
 <20251209134343.GA238880@francesco-nb>
Message-ID: <d6de7066-a802-41fc-bb10-2f5d248743db@ti.com>

Hi Francesco,


On 12/9/25 7:43 AM, Francesco Dolcini wrote:
> Hello Shree,
>
> On Thu, May 01, 2025 at 10:32:12AM -0500, Shree Ramamoorthy wrote:
>> On 4/30/25 5:21 AM, Francesco Dolcini wrote:
>>> On Wed, Apr 30, 2025 at 10:01:14AM +0200, Francesco Dolcini wrote:
>>>> On Tue, Apr 29, 2025 at 06:52:40PM +0200, Andreas Kemnade wrote:
>>>>> Am Tue, 29 Apr 2025 15:21:19 +0200
>>>>> schrieb Francesco Dolcini <francesco at dolcini.it>:
>>>>>
>>>>>> Hello all,
>>>>>> while working on adding support in mainline for a new board based on TI
>>>>>> AM62P SoC I noticed the following Kernel Oops.
>>>>>>
>>>>>> This oops was reproduced running current Linux
>>>>>> master, 6.15.0-rc4+, ca91b9500108d4cf083a635c2e11c884d5dd20ea, but I was able
>>>>>> to reproduce the same with 6.14.4.
>>>>>>
>>>>> [...]
>>>>>> [  +0.000022] Call trace:
>>>>>> [  +0.000011]  regulator_notifier_call_chain+0x20/0xa4 (P)
>>>>>> [  +0.000018]  tps65219_regulator_irq_handler+0x34/0x80
>>>>> wild guessing: maybe because irqdata->rdev is not initalized in
>>>>> _probe()? At least I do not see where it would be initialized.
>>>> your wild guess seems correct, I'll send a proper patch with your
>>>> suggested-by after doing a couple of more tests, thanks.
>>> so, the bug is clear, however the fix is not an obvious one liner as I was
>>> wishing.
>>>
>>> we would need to add a link from each of the interrupts to the specific
>>> regulator. as of now such a connection is not existing in the code.
>> I'll try out implementing and testing the solution, but will get to it early next week. Will email with any updates!
> What's the status on this? Were you able to do any progress or work on
> it?
>
> Thanks
> Francesco

Thanks for following up on this, the task got lost on my end. My apologies!
The original line deleted `irq_data[i].rdev = rdev;` was never replaced.
The correct code should be re-implementing a version of the tps65219_get_rdev_by_name() function that was removed in commit 64a6b57
& add in irq_data.rdev = rdev;` where the other irq_data fields are being assigned within _probe.

Is there anything missing with this solution?

Thanks!

>

-- 
Best,
Shree Ramamoorthy
PMIC Software Engineer




From robh at kernel.org  Tue Dec  9 10:22:02 2025
From: robh at kernel.org (Rob Herring)
Date: Tue, 9 Dec 2025 12:22:02 -0600
Subject: [PATCH] dt-bindings: pci: brcmstb: Add rp1-nexus node to fix DTC warning
In-Reply-To: <aThjYt3ux0U-9-3A@apocalypse>
References: <20250812085037.13517-1-andrea.porta@suse.com> <4fee3870-f9d5-48e3-a5be-6df581d3e296@kernel.org>
 <aKc5nMT1xXpY03ip@apocalypse> <e7875f70-2b79-48e0-a63b-caf6f1fd287b@kernel.org>
 <aLVePQRfU4IB1zK8@apocalypse> <CAL_JsqJUzB71QdMcxJtNZ7raoPcK+SfTh7EVzGmk=syo8xLKQw@mail.gmail.com>
 <aThjYt3ux0U-9-3A@apocalypse>
Message-ID: <CAL_JsqJxseyQDDNE-p3_4qjXcDwN_XyxWCvQA3hznyASLO7Gvw@mail.gmail.com>

On Tue, Dec 9, 2025 at 11:56?AM Andrea della Porta
<andrea.porta at suse.com> wrote:
>
> Hi Rob,
>
> On 11:09 Thu 04 Dec     , Rob Herring wrote:
> > On Mon, Sep 1, 2025 at 3:48?AM Andrea della Porta <andrea.porta at suse.com> wrote:
> > >
> > > Hi Krzysztof,
> > >
> > > On 08:50 Fri 22 Aug     , Krzysztof Kozlowski wrote:
> > > > On 21/08/2025 17:22, Andrea della Porta wrote:
> > > > > Hi Krzysztof,
> > > > >
> > > > > On 10:55 Tue 12 Aug     , Krzysztof Kozlowski wrote:
> > > > >> On 12/08/2025 10:50, Andrea della Porta wrote:
> > > > >>> The devicetree compiler is complaining as follows:
> > > > >>>
> > > > >>> arch/arm64/boot/dts/broadcom/rp1-nexus.dtsi:3.11-14.3: Warning (unit_address_vs_reg): /axi/pcie at 1000120000/rp1_nexus: node has a reg or ranges property, but no unit name
> > > > >>> /home/andrea/linux-torvalds/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dtb: pcie at 1000120000: Unevaluated properties are not allowed ('rp1_nexus' was unexpected)
> > > > >>
> > > > >> Please trim the paths.
> > > > >
> > > > > Ack.
> > > > >
> > > > >>
> > > > >>>
> > > > >>> Add the optional node that fix this to the DT binding.
> > > > >>>
> > > > >>> Reported-by: kernel test robot <lkp at intel.com>
> > > > >>> Closes: https://lore.kernel.org/oe-kbuild-all/202506041952.baJDYBT4-lkp at intel.com/
> > > > >>> Signed-off-by: Andrea della Porta <andrea.porta at suse.com>
> > > > >>> ---
> > > > >>>  Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml | 9 +++++++++
> > > > >>>  1 file changed, 9 insertions(+)
> > > > >>>
> > > > >>> diff --git a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
> > > > >>> index 812ef5957cfc..7d8ba920b652 100644
> > > > >>> --- a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
> > > > >>> +++ b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
> > > > >>> @@ -126,6 +126,15 @@ required:
> > > > >>>  allOf:
> > > > >>>    - $ref: /schemas/pci/pci-host-bridge.yaml#
> > > > >>>    - $ref: /schemas/interrupt-controller/msi-controller.yaml#
> > > > >>> +  - if:
> > > > >>> +      properties:
> > > > >>> +        compatible:
> > > > >>> +          contains:
> > > > >>> +            const: brcm,bcm2712-pcie
> > > > >>> +    then:
> > > > >>> +      properties:
> > > > >>> +        rp1_nexus:
> > > > >>
> > > > >> No, you cannot document post-factum... This does not follow DTS coding
> > > > >> style.
> > > > >
> > > > > I think I didn't catch what you mean here: would that mean that
> > > > > we cannot resolve that warning since we cannot add anything to the
> > > > > binding?
> > > >
> > > > I meant, you cannot use a warning from the code you recently introduced
> > > > as a reason to use incorrect style.
> > > >
> > > > Fixing warning is of course fine and correct, but for the code recently
> > > > introduced and which bypassed ABI review it is basically like new review
> > > > of new ABI.
> > > >
> > > > This needs standard review practice, so you need to document WHY you
> > > > need such node. Warning is not the reason here why you are doing. If
> > > > this was part of original patchset, like it should have been, you would
> > > > not use some imaginary warning as reason, right?
> > > >
> > > > So provide reason why you need here this dedicated child, what is that
> > > > child representing.
> > >
> > > Ack.
> > >
> > > >
> > > > Otherwise I can suggest: drop the child and DTSO, this also solves the
> > > > warning...
> > >
> > > This would not fix the issue: it's the non overlay that needs the specific
> > > node. But I got the point, and we have a solution for that (see below).
> > >
> > > >
> > > > >
> > > > > Regarding rp1_nexus, you're right I guess it should be
> > > > > rp1-nexus as per DTS coding style.
> > > > >
> > > > >>
> > > > >> Also:
> > > > >>
> > > > >> Node names should be generic. See also an explanation and list of
> > > > >> examples (not exhaustive) in DT specification:
> > > > >> https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation
> > > > >
> > > > > In this case it could be difficult: we need to search for a DT node
> > > >
> > > > Search like in driver? That's wrong, you should be searching by compatible.
> > >
> > > Thanks for the hint. Searching by compatble is the solution.
> >
> > No, it is not.
>
> This is partly true, indeed. On one side there's the need to avoid a
> specific node name ('rp1_nexus'), so the only other unique identifier would
> be the compatible string ('pci1de4,1' in this case, which identifies that specific
> device). Unfortunately, the same compatible string is also assigned to the pci
> endpoint node filled automatically by enabling CONFIG_PCI_DYNAMIC_OF_NODES.
> We would end up with two nodes with the same compatible, which is not unique
> anymore.
> This applies only when using 'full' dtb (bcm2712-rpi-5-b.dtb) *and* you enable
> CONFIG_PCI_DYNAMIC_OF_NODES, the latter being not necessary since the overlay dtb
> (...-ovl-rp1.dtb) is not in use here. To overcome this problem, the solutions
> I can think of are the following:
>
> 1- Just disable CONFIG_PCI_DYNAMIC_OF_NODES should work, but only when using the
>    full dtb version. However, if the user enable that option for debug or to use
>    the overlay dtb version, he better be sure not to use teh full dtb or it won't
>    work.
>    This solution seems really weak.
>
> 2- Add another compatible string other than 'pci1de4,1', so it will be really
>    unique.

No! Neither one. If you end up with 2 nodes when you turn on
CONFIG_PCI_DYNAMIC_OF_NODES, then you have an error in your DT (the
node that CONFIG_PCI_DYNAMIC_OF_NODES *didn't* create is the one in
error).

You need to fix the structure.

> >
> > > >
> > > > > starting from the DT root and using generic names like pci at 0,0 or
> > > > > dev at 0,0 could possibly led to conflicts with other peripherals.
> > > > > That's why I chose a specific name.
> > > >
> > > > Dunno, depends what can be there, but you do not get a specific
> > > > (non-generic) device node name for a generic PCI device or endpoint.
> > >
> > > I would use 'port' instead of rp1-nexus. Would it work for you?
> >
> > Do you still plan to fix this? This is broken far worse than just the node name.
>
> Yes, if we want to get rid of that nasty warning and comply with DT guidelines,
> I think I really need to fix that.
>
> >
> > The 'rp1_nexus' node is applied to the PCI host bridge. That's wrong
> > unless this is PCI rather than PCIe. There's the root port device in
> > between.
> >
> > The clue that things are wrong are start in the driver here:
> >
> > rp1_node = of_find_node_by_name(NULL, "rp1_nexus");
> > if (!rp1_node) {
> >   rp1_node = dev_of_node(dev);
> >   skip_ovl = false;
> > }
> >
> > You should not need to do this nor care what the node name is. The PCI
> > core should have populated pdev->dev.of_node for you. If not, your DT
> > is wrong. Turn on CONFIG_PCI_DYNAMIC_OF_NODES and look at the
> > resulting PCI nodes. They should also match what the hierarchy looks
> > like with lspci. I don't recommend you rely on
> > CONFIG_PCI_DYNAMIC_OF_NODES, but statically populate the nodes in the
> > DT. First, CONFIG_PCI_DYNAMIC_OF_NODES is an under development thing
> > and I hope to get rid of the config option. Second, your case is
> > static (i.e. not a PCIe card in a slot) so there is no issue
> > hardcoding the DT.
>
> The 'full' dtb (bcm2712-rpi-5-b.dtb) is indeed statically populated.
> CONFIG_PCI_DYNAMIC_OF_NODES is needed only if you use the overlay approach
> (bcm2712-rpi-5-b-ovl-rp1.dtb) and in that case the node will be
> added to the correct device node at runtime, and there won't be any node
> labeled as rp1_nexus.
> That conditional just check for teh presence of the rp1_nexus node to
> choose if the overlay should be loaded at runtime (if rp1_nexus is present,
> then we are in the static case so no overlay need to be loaded).

Checking is fine, but you are checking the wrong thing.

> >
> > As far as the node name, I don't care so much as long as the driver
> > doesn't care and you don't use '_' or 'pcie?' (that's for PCI
> > bridges).
> >
> > And why do we have drivers/misc/rp1/rp1-pci.dtso and a .dtso in
> > arch/arm64? There should not be both.
>
> drivers/misc/rp1/rp1-pci.dtso is just a wrapper over rp1-common.dtsi,
> which is to be compiled in as binary blob in the driver and loaded at
> runtime.
> rp1.dtbo is optional, it's there just for completeness in case anyone want
> to load teh overlay from the fw, as explained here:
> https://lore.kernel.org/all/ab9ab3536baf5fdf6016f2a01044f00034189291.1742418429.git.andrea.porta at suse.com/
> If it causes confusion, we can probably get rid of it with no penalty.

Supporting both ways is fine, but you don't need to duplicate the
source. You can build in a .dtbo from the arch/arm64/boot/dts/...
directories.

Rob


From andrea.porta at suse.com  Tue Dec  9 10:27:03 2025
From: andrea.porta at suse.com (Andrea della Porta)
Date: Tue, 9 Dec 2025 19:27:03 +0100
Subject: [PATCH] dt-bindings: pci: brcmstb: Add rp1-nexus node to fix DTC
 warning
In-Reply-To: <aThjYt3ux0U-9-3A@apocalypse>
References: <20250812085037.13517-1-andrea.porta@suse.com>
 <4fee3870-f9d5-48e3-a5be-6df581d3e296@kernel.org>
 <aKc5nMT1xXpY03ip@apocalypse>
 <e7875f70-2b79-48e0-a63b-caf6f1fd287b@kernel.org>
 <aLVePQRfU4IB1zK8@apocalypse>
 <CAL_JsqJUzB71QdMcxJtNZ7raoPcK+SfTh7EVzGmk=syo8xLKQw@mail.gmail.com>
 <aThjYt3ux0U-9-3A@apocalypse>
Message-ID: <aThp99OfgAfNFUX-@apocalypse>

[+cc Herve]

On 18:58 Tue 09 Dec     , Andrea della Porta wrote:
> Hi Rob,
> 
> On 11:09 Thu 04 Dec     , Rob Herring wrote:
> > On Mon, Sep 1, 2025 at 3:48?AM Andrea della Porta <andrea.porta at suse.com> wrote:
> > >
> > > Hi Krzysztof,
> > >
> > > On 08:50 Fri 22 Aug     , Krzysztof Kozlowski wrote:
> > > > On 21/08/2025 17:22, Andrea della Porta wrote:
> > > > > Hi Krzysztof,
> > > > >
> > > > > On 10:55 Tue 12 Aug     , Krzysztof Kozlowski wrote:
> > > > >> On 12/08/2025 10:50, Andrea della Porta wrote:
> > > > >>> The devicetree compiler is complaining as follows:
> > > > >>>
> > > > >>> arch/arm64/boot/dts/broadcom/rp1-nexus.dtsi:3.11-14.3: Warning (unit_address_vs_reg): /axi/pcie at 1000120000/rp1_nexus: node has a reg or ranges property, but no unit name
> > > > >>> /home/andrea/linux-torvalds/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dtb: pcie at 1000120000: Unevaluated properties are not allowed ('rp1_nexus' was unexpected)
> > > > >>
> > > > >> Please trim the paths.
> > > > >
> > > > > Ack.
> > > > >
> > > > >>
> > > > >>>
> > > > >>> Add the optional node that fix this to the DT binding.
> > > > >>>
> > > > >>> Reported-by: kernel test robot <lkp at intel.com>
> > > > >>> Closes: https://lore.kernel.org/oe-kbuild-all/202506041952.baJDYBT4-lkp at intel.com/
> > > > >>> Signed-off-by: Andrea della Porta <andrea.porta at suse.com>
> > > > >>> ---
> > > > >>>  Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml | 9 +++++++++
> > > > >>>  1 file changed, 9 insertions(+)
> > > > >>>
> > > > >>> diff --git a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
> > > > >>> index 812ef5957cfc..7d8ba920b652 100644
> > > > >>> --- a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
> > > > >>> +++ b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
> > > > >>> @@ -126,6 +126,15 @@ required:
> > > > >>>  allOf:
> > > > >>>    - $ref: /schemas/pci/pci-host-bridge.yaml#
> > > > >>>    - $ref: /schemas/interrupt-controller/msi-controller.yaml#
> > > > >>> +  - if:
> > > > >>> +      properties:
> > > > >>> +        compatible:
> > > > >>> +          contains:
> > > > >>> +            const: brcm,bcm2712-pcie
> > > > >>> +    then:
> > > > >>> +      properties:
> > > > >>> +        rp1_nexus:
> > > > >>
> > > > >> No, you cannot document post-factum... This does not follow DTS coding
> > > > >> style.
> > > > >
> > > > > I think I didn't catch what you mean here: would that mean that
> > > > > we cannot resolve that warning since we cannot add anything to the
> > > > > binding?
> > > >
> > > > I meant, you cannot use a warning from the code you recently introduced
> > > > as a reason to use incorrect style.
> > > >
> > > > Fixing warning is of course fine and correct, but for the code recently
> > > > introduced and which bypassed ABI review it is basically like new review
> > > > of new ABI.
> > > >
> > > > This needs standard review practice, so you need to document WHY you
> > > > need such node. Warning is not the reason here why you are doing. If
> > > > this was part of original patchset, like it should have been, you would
> > > > not use some imaginary warning as reason, right?
> > > >
> > > > So provide reason why you need here this dedicated child, what is that
> > > > child representing.
> > >
> > > Ack.
> > >
> > > >
> > > > Otherwise I can suggest: drop the child and DTSO, this also solves the
> > > > warning...
> > >
> > > This would not fix the issue: it's the non overlay that needs the specific
> > > node. But I got the point, and we have a solution for that (see below).
> > >
> > > >
> > > > >
> > > > > Regarding rp1_nexus, you're right I guess it should be
> > > > > rp1-nexus as per DTS coding style.
> > > > >
> > > > >>
> > > > >> Also:
> > > > >>
> > > > >> Node names should be generic. See also an explanation and list of
> > > > >> examples (not exhaustive) in DT specification:
> > > > >> https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation
> > > > >
> > > > > In this case it could be difficult: we need to search for a DT node
> > > >
> > > > Search like in driver? That's wrong, you should be searching by compatible.
> > >
> > > Thanks for the hint. Searching by compatble is the solution.
> > 
> > No, it is not.
> 
> This is partly true, indeed. On one side there's the need to avoid a
> specific node name ('rp1_nexus'), so the only other unique identifier would
> be the compatible string ('pci1de4,1' in this case, which identifies that specific
> device). Unfortunately, the same compatible string is also assigned to the pci
> endpoint node filled automatically by enabling CONFIG_PCI_DYNAMIC_OF_NODES.
> We would end up with two nodes with the same compatible, which is not unique
> anymore. 
> This applies only when using 'full' dtb (bcm2712-rpi-5-b.dtb) *and* you enable
> CONFIG_PCI_DYNAMIC_OF_NODES, the latter being not necessary since the overlay dtb
> (...-ovl-rp1.dtb) is not in use here. To overcome this problem, the solutions
> I can think of are the following:
> 
> 1- Just disable CONFIG_PCI_DYNAMIC_OF_NODES should work, but only when using the
>    full dtb version. However, if the user enable that option for debug or to use
>    the overlay dtb version, he better be sure not to use teh full dtb or it won't
>    work.
>    This solution seems really weak.
> 
> 2- Add another compatible string other than 'pci1de4,1', so it will be really
>    unique.
> 
> > 
> > > >
> > > > > starting from the DT root and using generic names like pci at 0,0 or
> > > > > dev at 0,0 could possibly led to conflicts with other peripherals.
> > > > > That's why I chose a specific name.
> > > >
> > > > Dunno, depends what can be there, but you do not get a specific
> > > > (non-generic) device node name for a generic PCI device or endpoint.
> > >
> > > I would use 'port' instead of rp1-nexus. Would it work for you?
> > 
> > Do you still plan to fix this? This is broken far worse than just the node name.
> 
> Yes, if we want to get rid of that nasty warning and comply with DT guidelines,
> I think I really need to fix that.
> 
> > 
> > The 'rp1_nexus' node is applied to the PCI host bridge. That's wrong
> > unless this is PCI rather than PCIe. There's the root port device in
> > between.
> > 
> > The clue that things are wrong are start in the driver here:
> > 
> > rp1_node = of_find_node_by_name(NULL, "rp1_nexus");
> > if (!rp1_node) {
> >   rp1_node = dev_of_node(dev);
> >   skip_ovl = false;
> > }
> > 
> > You should not need to do this nor care what the node name is. The PCI
> > core should have populated pdev->dev.of_node for you. If not, your DT
> > is wrong. Turn on CONFIG_PCI_DYNAMIC_OF_NODES and look at the
> > resulting PCI nodes. They should also match what the hierarchy looks
> > like with lspci. I don't recommend you rely on
> > CONFIG_PCI_DYNAMIC_OF_NODES, but statically populate the nodes in the
> > DT. First, CONFIG_PCI_DYNAMIC_OF_NODES is an under development thing
> > and I hope to get rid of the config option. Second, your case is
> > static (i.e. not a PCIe card in a slot) so there is no issue
> > hardcoding the DT.

Are you planning to get rid of the CONFIG_PCI_DYNAMIC_OF_NODES features?
There could be other drivers relying on that besides RP1 in overlay mode,
e.g. LAN966x for instance.

Thanks,
Andrea

> 
> The 'full' dtb (bcm2712-rpi-5-b.dtb) is indeed statically populated.
> CONFIG_PCI_DYNAMIC_OF_NODES is needed only if you use the overlay approach
> (bcm2712-rpi-5-b-ovl-rp1.dtb) and in that case the node will be
> added to the correct device node at runtime, and there won't be any node
> labeled as rp1_nexus.
> That conditional just check for teh presence of the rp1_nexus node to
> choose if the overlay should be loaded at runtime (if rp1_nexus is present,
> then we are in the static case so no overlay need to be loaded).
> 
> > 
> > As far as the node name, I don't care so much as long as the driver
> > doesn't care and you don't use '_' or 'pcie?' (that's for PCI
> > bridges).
> > 
> > And why do we have drivers/misc/rp1/rp1-pci.dtso and a .dtso in
> > arch/arm64? There should not be both.
> 
> drivers/misc/rp1/rp1-pci.dtso is just a wrapper over rp1-common.dtsi,
> which is to be compiled in as binary blob in the driver and loaded at
> runtime.
> rp1.dtbo is optional, it's there just for completeness in case anyone want
> to load teh overlay from the fw, as explained here:
> https://lore.kernel.org/all/ab9ab3536baf5fdf6016f2a01044f00034189291.1742418429.git.andrea.porta at suse.com/
> If it causes confusion, we can probably get rid of it with no penalty.
> 
> Many thanks,
> Andrea
> 
> > 
> > Rob


From robh at kernel.org  Tue Dec  9 10:46:45 2025
From: robh at kernel.org (Rob Herring)
Date: Tue, 9 Dec 2025 12:46:45 -0600
Subject: [PATCH] dt-bindings: pci: brcmstb: Add rp1-nexus node to fix DTC warning
In-Reply-To: <aThp99OfgAfNFUX-@apocalypse>
References: <20250812085037.13517-1-andrea.porta@suse.com> <4fee3870-f9d5-48e3-a5be-6df581d3e296@kernel.org>
 <aKc5nMT1xXpY03ip@apocalypse> <e7875f70-2b79-48e0-a63b-caf6f1fd287b@kernel.org>
 <aLVePQRfU4IB1zK8@apocalypse> <CAL_JsqJUzB71QdMcxJtNZ7raoPcK+SfTh7EVzGmk=syo8xLKQw@mail.gmail.com>
 <aThjYt3ux0U-9-3A@apocalypse> <aThp99OfgAfNFUX-@apocalypse>
Message-ID: <CAL_Jsq+VfWJtb_VEEmHCtDdKUUFWUrxw80FocuEiVwFTAM9zyg@mail.gmail.com>

On Tue, Dec 9, 2025 at 12:24?PM Andrea della Porta
<andrea.porta at suse.com> wrote:
>
> [+cc Herve]
>
> On 18:58 Tue 09 Dec     , Andrea della Porta wrote:
> > Hi Rob,
> >
> > On 11:09 Thu 04 Dec     , Rob Herring wrote:
> > > On Mon, Sep 1, 2025 at 3:48?AM Andrea della Porta <andrea.porta at suse.com> wrote:
> > > >
> > > > Hi Krzysztof,
> > > >
> > > > On 08:50 Fri 22 Aug     , Krzysztof Kozlowski wrote:
> > > > > On 21/08/2025 17:22, Andrea della Porta wrote:
> > > > > > Hi Krzysztof,
> > > > > >
> > > > > > On 10:55 Tue 12 Aug     , Krzysztof Kozlowski wrote:
> > > > > >> On 12/08/2025 10:50, Andrea della Porta wrote:
> > > > > >>> The devicetree compiler is complaining as follows:
> > > > > >>>
> > > > > >>> arch/arm64/boot/dts/broadcom/rp1-nexus.dtsi:3.11-14.3: Warning (unit_address_vs_reg): /axi/pcie at 1000120000/rp1_nexus: node has a reg or ranges property, but no unit name
> > > > > >>> /home/andrea/linux-torvalds/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dtb: pcie at 1000120000: Unevaluated properties are not allowed ('rp1_nexus' was unexpected)
> > > > > >>
> > > > > >> Please trim the paths.
> > > > > >
> > > > > > Ack.
> > > > > >
> > > > > >>
> > > > > >>>
> > > > > >>> Add the optional node that fix this to the DT binding.
> > > > > >>>
> > > > > >>> Reported-by: kernel test robot <lkp at intel.com>
> > > > > >>> Closes: https://lore.kernel.org/oe-kbuild-all/202506041952.baJDYBT4-lkp at intel.com/
> > > > > >>> Signed-off-by: Andrea della Porta <andrea.porta at suse.com>
> > > > > >>> ---
> > > > > >>>  Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml | 9 +++++++++
> > > > > >>>  1 file changed, 9 insertions(+)
> > > > > >>>
> > > > > >>> diff --git a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
> > > > > >>> index 812ef5957cfc..7d8ba920b652 100644
> > > > > >>> --- a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
> > > > > >>> +++ b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
> > > > > >>> @@ -126,6 +126,15 @@ required:
> > > > > >>>  allOf:
> > > > > >>>    - $ref: /schemas/pci/pci-host-bridge.yaml#
> > > > > >>>    - $ref: /schemas/interrupt-controller/msi-controller.yaml#
> > > > > >>> +  - if:
> > > > > >>> +      properties:
> > > > > >>> +        compatible:
> > > > > >>> +          contains:
> > > > > >>> +            const: brcm,bcm2712-pcie
> > > > > >>> +    then:
> > > > > >>> +      properties:
> > > > > >>> +        rp1_nexus:
> > > > > >>
> > > > > >> No, you cannot document post-factum... This does not follow DTS coding
> > > > > >> style.
> > > > > >
> > > > > > I think I didn't catch what you mean here: would that mean that
> > > > > > we cannot resolve that warning since we cannot add anything to the
> > > > > > binding?
> > > > >
> > > > > I meant, you cannot use a warning from the code you recently introduced
> > > > > as a reason to use incorrect style.
> > > > >
> > > > > Fixing warning is of course fine and correct, but for the code recently
> > > > > introduced and which bypassed ABI review it is basically like new review
> > > > > of new ABI.
> > > > >
> > > > > This needs standard review practice, so you need to document WHY you
> > > > > need such node. Warning is not the reason here why you are doing. If
> > > > > this was part of original patchset, like it should have been, you would
> > > > > not use some imaginary warning as reason, right?
> > > > >
> > > > > So provide reason why you need here this dedicated child, what is that
> > > > > child representing.
> > > >
> > > > Ack.
> > > >
> > > > >
> > > > > Otherwise I can suggest: drop the child and DTSO, this also solves the
> > > > > warning...
> > > >
> > > > This would not fix the issue: it's the non overlay that needs the specific
> > > > node. But I got the point, and we have a solution for that (see below).
> > > >
> > > > >
> > > > > >
> > > > > > Regarding rp1_nexus, you're right I guess it should be
> > > > > > rp1-nexus as per DTS coding style.
> > > > > >
> > > > > >>
> > > > > >> Also:
> > > > > >>
> > > > > >> Node names should be generic. See also an explanation and list of
> > > > > >> examples (not exhaustive) in DT specification:
> > > > > >> https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation
> > > > > >
> > > > > > In this case it could be difficult: we need to search for a DT node
> > > > >
> > > > > Search like in driver? That's wrong, you should be searching by compatible.
> > > >
> > > > Thanks for the hint. Searching by compatble is the solution.
> > >
> > > No, it is not.
> >
> > This is partly true, indeed. On one side there's the need to avoid a
> > specific node name ('rp1_nexus'), so the only other unique identifier would
> > be the compatible string ('pci1de4,1' in this case, which identifies that specific
> > device). Unfortunately, the same compatible string is also assigned to the pci
> > endpoint node filled automatically by enabling CONFIG_PCI_DYNAMIC_OF_NODES.
> > We would end up with two nodes with the same compatible, which is not unique
> > anymore.
> > This applies only when using 'full' dtb (bcm2712-rpi-5-b.dtb) *and* you enable
> > CONFIG_PCI_DYNAMIC_OF_NODES, the latter being not necessary since the overlay dtb
> > (...-ovl-rp1.dtb) is not in use here. To overcome this problem, the solutions
> > I can think of are the following:
> >
> > 1- Just disable CONFIG_PCI_DYNAMIC_OF_NODES should work, but only when using the
> >    full dtb version. However, if the user enable that option for debug or to use
> >    the overlay dtb version, he better be sure not to use teh full dtb or it won't
> >    work.
> >    This solution seems really weak.
> >
> > 2- Add another compatible string other than 'pci1de4,1', so it will be really
> >    unique.
> >
> > >
> > > > >
> > > > > > starting from the DT root and using generic names like pci at 0,0 or
> > > > > > dev at 0,0 could possibly led to conflicts with other peripherals.
> > > > > > That's why I chose a specific name.
> > > > >
> > > > > Dunno, depends what can be there, but you do not get a specific
> > > > > (non-generic) device node name for a generic PCI device or endpoint.
> > > >
> > > > I would use 'port' instead of rp1-nexus. Would it work for you?
> > >
> > > Do you still plan to fix this? This is broken far worse than just the node name.
> >
> > Yes, if we want to get rid of that nasty warning and comply with DT guidelines,
> > I think I really need to fix that.
> >
> > >
> > > The 'rp1_nexus' node is applied to the PCI host bridge. That's wrong
> > > unless this is PCI rather than PCIe. There's the root port device in
> > > between.
> > >
> > > The clue that things are wrong are start in the driver here:
> > >
> > > rp1_node = of_find_node_by_name(NULL, "rp1_nexus");
> > > if (!rp1_node) {
> > >   rp1_node = dev_of_node(dev);
> > >   skip_ovl = false;
> > > }
> > >
> > > You should not need to do this nor care what the node name is. The PCI
> > > core should have populated pdev->dev.of_node for you. If not, your DT
> > > is wrong. Turn on CONFIG_PCI_DYNAMIC_OF_NODES and look at the
> > > resulting PCI nodes. They should also match what the hierarchy looks
> > > like with lspci. I don't recommend you rely on
> > > CONFIG_PCI_DYNAMIC_OF_NODES, but statically populate the nodes in the
> > > DT. First, CONFIG_PCI_DYNAMIC_OF_NODES is an under development thing
> > > and I hope to get rid of the config option. Second, your case is
> > > static (i.e. not a PCIe card in a slot) so there is no issue
> > > hardcoding the DT.
>
> Are you planning to get rid of the CONFIG_PCI_DYNAMIC_OF_NODES features?
> There could be other drivers relying on that besides RP1 in overlay mode,
> e.g. LAN966x for instance.

I only plan/want to get rid of the kconfig option, not the feature
itself! IOW, it will be enabled/disabled at runtime based on
something. I'm not sure what that something is.

Rob


From Harini.T at amd.com  Tue Dec  9 11:03:02 2025
From: Harini.T at amd.com (T, Harini)
Date: Tue, 9 Dec 2025 19:03:02 +0000
Subject: [PATCH 3/4] rtc: zynqmp: rework set_offset
In-Reply-To: <20251201-zynqmp-rtc-updates-v1-3-33875c1e385b@vaisala.com>
References: <20251201-zynqmp-rtc-updates-v1-0-33875c1e385b@vaisala.com>
 <20251201-zynqmp-rtc-updates-v1-3-33875c1e385b@vaisala.com>
Message-ID: <LV5PR12MB98045BF8A85640F924BCFD4492A3A@LV5PR12MB9804.namprd12.prod.outlook.com>

[Public]

Hi,

> -----Original Message-----
> From: Tomas Melin <tomas.melin at vaisala.com>
> Sent: Monday, December 1, 2025 6:20 PM
> To: Alexandre Belloni <alexandre.belloni at bootlin.com>; Simek, Michal
> <michal.simek at amd.com>
> Cc: linux-rtc at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux-
> kernel at vger.kernel.org; Tomas Melin <tomas.melin at vaisala.com>
> Subject: [PATCH 3/4] rtc: zynqmp: rework set_offset
>
> Caution: This message originated from an External Source. Use proper
> caution when opening attachments, clicking links, or responding.
>
>
> set_offset was using remainder of do_div as tick_mult which resulted in
> wrong offset. Calibration value also assumed builtin calibration default.
> Update fract_offset to correctly calculate the value for negative offset and
> replace the for loop with division.
>
> Signed-off-by: Tomas Melin <tomas.melin at vaisala.com>
> ---
>  drivers/rtc/rtc-zynqmp.c | 29 +++++++++++------------------
>  1 file changed, 11 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c index
> 7af5f6f99538f961a53ff56bfc656c907611b900..3bc8831ba2c4c4c701a49506b6
> 7ae6174f3ade3d 100644
> --- a/drivers/rtc/rtc-zynqmp.c
> +++ b/drivers/rtc/rtc-zynqmp.c
> @@ -208,13 +208,13 @@ static int xlnx_rtc_read_offset(struct device *dev,
> long *offset)  static int xlnx_rtc_set_offset(struct device *dev, long offset)  {
>         struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
> -       unsigned long long rtc_ppb = RTC_PPB;
> -       unsigned int tick_mult = do_div(rtc_ppb, xrtcdev->freq);
> +       unsigned int calibval, tick_mult, fract_part;
tick_mult is mentioned as int in previous patch and unsigned here. Justify the type in commit description.
>         unsigned char fract_tick = 0;
> -       unsigned int calibval;
> -       short int  max_tick;
> -       int fract_offset;
> +       int freq = xrtcdev->freq;
> +       int max_tick, fract_offset;
Please follow reverse xmas tree variable ordering.
Also keep the frac_* variables uniform in both set and read offset functions.
>
> +       /* ticks to reach RTC_PPB */
The comment is misleading. Its tick_mult is nanoseconds per tick, not a tick count.
> +       tick_mult = DIV_ROUND_CLOSEST(RTC_PPB, xrtcdev->freq);
We can first validate offset and then calculate tick_mult to reduce CPU instructions incase of invalid inputs
>         if (offset < RTC_MIN_OFFSET || offset > RTC_MAX_OFFSET)
>                 return -ERANGE;
>
> @@ -223,29 +223,22 @@ static int xlnx_rtc_set_offset(struct device *dev,
> long offset)
>
>         /* Number fractional ticks for given offset */
>         if (fract_offset) {
> +               /* round up here so we stay below a full tick */
> +               fract_part = DIV_ROUND_UP(tick_mult, RTC_FR_MAX_TICKS);
>                 if (fract_offset < 0) {
> -                       fract_offset = fract_offset + tick_mult;
> +                       fract_offset += (fract_part * RTC_FR_MAX_TICKS);
It would be better to add comment to explain on the negative offset borrowing logic
>                         max_tick--;
>                 }
> -               if (fract_offset > (tick_mult / RTC_FR_MAX_TICKS)) {
> -                       for (fract_tick = 1; fract_tick < 16; fract_tick++) {
> -                               if (fract_offset <=
> -                                   (fract_tick *
> -                                    (tick_mult / RTC_FR_MAX_TICKS)))
> -                                       break;
> -                       }
> -               }
> +               fract_tick = fract_offset / fract_part;
Its better to use DIV_ROUND_UP()
>         }
>
>         /* Zynqmp RTC uses second and fractional tick
>          * counters for compensation
>          */
> -       calibval = max_tick + RTC_CALIB_DEF;
> +       calibval = max_tick + freq;
>
>         if (fract_tick)
> -               calibval |= RTC_FR_EN;
> -
> -       calibval |= (fract_tick << RTC_FR_DATSHIFT);
> +               calibval |= (RTC_FR_EN | (fract_tick <<
> + RTC_FR_DATSHIFT));
>
>         writel(calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
>
>
> --
> 2.47.3
>

Regards,
Harini T

From robh at kernel.org  Tue Dec  9 11:07:22 2025
From: robh at kernel.org (Rob Herring)
Date: Tue, 9 Dec 2025 13:07:22 -0600
Subject: [PATCH v6 1/4] dt-bindings: backlight: Add max25014 support
In-Reply-To: <e428c3a9-49e2-4af5-b597-2cdfef7028f5@gocontroll.com>
References: <20251201-max25014-v6-0-88e3ac8112ff@gocontroll.com>
 <20251201-max25014-v6-1-88e3ac8112ff@gocontroll.com>
 <aS3H1qzSMKHamqpP@lizhi-Precision-Tower-5810>
 <b9fe6df7-fdc6-4a32-919b-8f3b44eace7d@gocontroll.com>
 <aS79eKc9Ac4np6Nf@lizhi-Precision-Tower-5810>
 <e428c3a9-49e2-4af5-b597-2cdfef7028f5@gocontroll.com>
Message-ID: <20251209190722.GA945742-robh@kernel.org>

On Mon, Dec 08, 2025 at 02:56:50PM +0100, Maud Spierings wrote:
> On 12/2/25 15:53, Frank Li wrote:
> > On Tue, Dec 02, 2025 at 08:46:21AM +0100, Maud Spierings wrote:
> > > On 12/1/25 17:52, Frank Li wrote:
> > > > On Mon, Dec 01, 2025 at 12:53:20PM +0100, Maud Spierings via B4 Relay wrote:
> > > > > From: Maud Spierings <maudspierings at gocontroll.com>
> > > > > 
> > > > > The Maxim MAX25014 is a 4-channel automotive grade backlight driver IC
> > > > > with integrated boost controller.
> > > > > 
> > > > > Signed-off-by: Maud Spierings <maudspierings at gocontroll.com>
> > > > > 
> > > > > ---
> > > > > 
> > > > > In the current implementation the control registers for channel 1,
> > > > > control all channels. So only one led subnode with led-sources is
> > > > > supported right now. If at some point the driver functionality is
> > > > > expanded the bindings can be easily extended with it.
> > > > > ---
> > > > >    .../bindings/leds/backlight/maxim,max25014.yaml    | 107 +++++++++++++++++++++
> > > > >    MAINTAINERS                                        |   5 +
> > > > >    2 files changed, 112 insertions(+)
> > > > > 
> > > > > diff --git a/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml b/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
> > > > > new file mode 100644
> > > > > index 000000000000..e83723224b07
> > > > > --- /dev/null
> > > > > +++ b/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
> > > > > @@ -0,0 +1,107 @@
> > > > > +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> > > > > +%YAML 1.2
> > > > > +---
> > > > > +$id: http://devicetree.org/schemas/leds/backlight/maxim,max25014.yaml#
> > > > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > > > +
> > > > > +title: Maxim max25014 backlight controller
> > > > > +
> > > > > +maintainers:
> > > > > +  - Maud Spierings <maudspierings at gocontroll.com>
> > > > > +
> > > > > +properties:
> > > > > +  compatible:
> > > > > +    enum:
> > > > > +      - maxim,max25014
> > > > > +
> > > > > +  reg:
> > > > > +    maxItems: 1
> > > > > +
> > > > > +  "#address-cells":
> > > > > +    const: 1
> > > > > +
> > > > > +  "#size-cells":
> > > > > +    const: 0
> > > > > +
> > > > > +  enable-gpios:
> > > > > +    maxItems: 1
> > > > > +
> > > > > +  interrupts:
> > > > > +    maxItems: 1
> > > > > +
> > > > > +  power-supply:
> > > > > +    description: Regulator which controls the boost converter input rail.
> > > > > +
> > > > > +  pwms:
> > > > > +    maxItems: 1
> > > > > +
> > > > > +  maxim,iset:
> > > > > +    $ref: /schemas/types.yaml#/definitions/uint32
> > > > > +    maximum: 15
> > > > > +    default: 11
> > > > > +    description:
> > > > > +      Value of the ISET field in the ISET register. This controls the current
> > > > > +      scale of the outputs, a higher number means more current.
> > > > > +
> > > > > +  led at 0:
> > > > 
> > > > define whole binding, allow 0-3. binding is not related with driver's
> > > > implement.
> > > > 
> > > > it'd better put unders leds.
> > > > 
> > > 
> > > so like:
> > > 
> > > backlight: backlight at 6f {
> > > 	compatible = "maxim,max25014";
> > > 	reg = <0x6f>;
> > > 	enable-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
> > > 	pinctrl-names = "default";
> > > 	pinctrl-0 = <&pinctrl_backlight>;
> > > 	maxim,iset = <7>;
> > > 
> > > 	leds {
> > > 		#address-cells = <1>;
> > > 		#size-cells = <0>;
> > > 
> > > 		led at 0 {
> > > 			reg = <0>;
> > > 			led-sources = <0 1 2>;
> > > 			default-brightness = <50>;
> > > 		};
> > > 
> > > 		optional led@#....
> > > 	};
> > > };
> > > 
> > > right?
> > 
> > yes.
> > 
> 
> I am feeling a bit weird about these led sub nodes, because it is not
> programmed as a led driver, it is programmed as a backlight. I am trying to
> figure out how this would be used later when the led strings are
> individually controllable.
> 
> it isn't possible to link the seperate strings to different displays because
> it is only one backlight device, so I don't seen any reason why it would
> ever be used in another way than what it is now, were all strings are
> programmed by one register.
> 
> The only way I can make sense of it is if instead I program this device as a
> led driver and then use the led_bl driver as the actual backlight.
> 
> Thats a pretty big step in a different direction, but then the led subnodes
> at least can be properly used I feel.

If you don't have any use for anything other than driving a single 
backlight, then I'd just drop the led nodes completely.

Rob


From robh at kernel.org  Tue Dec  9 11:13:23 2025
From: robh at kernel.org (Rob Herring)
Date: Tue, 9 Dec 2025 13:13:23 -0600
Subject: [PATCH 2/7] ASoC: dt-bindings: update tdm-slot.txt references to
 tdm-slot.yaml
In-Reply-To: <20251209-tdm-idle-slots-v1-2-38dabf6bc01e@gmail.com>
References: <20251209-tdm-idle-slots-v1-0-38dabf6bc01e@gmail.com>
 <20251209-tdm-idle-slots-v1-2-38dabf6bc01e@gmail.com>
Message-ID: <20251209191323.GA954261-robh@kernel.org>

On Tue, Dec 09, 2025 at 07:31:15PM +1000, James Calligeros wrote:
> Ensure that all references to tdm-slot.txt have been updated to
> tdm-slot.yaml.
> 
> Achieved by running "sed -i 's/tdm-slot.txt/tdm-slot.yaml/g' *"
> against the bindings/sound. No other references to the file
> were found in the tree.
> 
> Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
> ---
>  .../bindings/sound/imx-audio-card.yaml   | 4 ++--
>  .../bindings/sound/simple-card.yaml      | 4 ++--
>  2 files changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/sound/imx-audio-card.yaml b/Documentation/devicetree/bindings/sound/imx-audio-card.yaml
> index 3c75c8c78987..1df29a556120 100644
> --- a/Documentation/devicetree/bindings/sound/imx-audio-card.yaml
> +++ b/Documentation/devicetree/bindings/sound/imx-audio-card.yaml
> @@ -39,11 +39,11 @@ patternProperties:
>              - dsp_b
>  
>        dai-tdm-slot-num:
> -        description: see tdm-slot.txt.
> +        description: see tdm-slot.yaml.
>          $ref: /schemas/types.yaml#/definitions/uint32
>  
>        dai-tdm-slot-width:
> -        description: see tdm-slot.txt.
> +        description: see tdm-slot.yaml.
>          $ref: /schemas/types.yaml#/definitions/uint32

These should be removed and replaced with a '$ref: tdm-slot.yaml#' at 
the top-level. 

If you have some constraints to add here, then the property can stay.

>  
>        playback-only:
> diff --git a/Documentation/devicetree/bindings/sound/simple-card.yaml b/Documentation/devicetree/bindings/sound/simple-card.yaml
> index 533d0a1da56e..2e1a5b3216c5 100644
> --- a/Documentation/devicetree/bindings/sound/simple-card.yaml
> +++ b/Documentation/devicetree/bindings/sound/simple-card.yaml
> @@ -28,11 +28,11 @@ definitions:
>      $ref: /schemas/types.yaml#/definitions/flag
>  
>    dai-tdm-slot-num:
> -    description: see tdm-slot.txt.
> +    description: see tdm-slot.yaml.
>      $ref: /schemas/types.yaml#/definitions/uint32
>  
>    dai-tdm-slot-width:
> -    description: see tdm-slot.txt.
> +    description: see tdm-slot.yaml.
>      $ref: /schemas/types.yaml#/definitions/uint32

Same here.

>  
>    system-clock-frequency:
> 
> -- 
> 2.52.0
> 


From Harini.T at amd.com  Tue Dec  9 11:28:44 2025
From: Harini.T at amd.com (T, Harini)
Date: Tue, 9 Dec 2025 19:28:44 +0000
Subject: [PATCH 4/4] rtc: zynqmp: use dynamic max and min offset ranges
In-Reply-To: <20251201-zynqmp-rtc-updates-v1-4-33875c1e385b@vaisala.com>
References: <20251201-zynqmp-rtc-updates-v1-0-33875c1e385b@vaisala.com>
 <20251201-zynqmp-rtc-updates-v1-4-33875c1e385b@vaisala.com>
Message-ID: <LV5PR12MB98046A63E80D7A7FA299366E92A3A@LV5PR12MB9804.namprd12.prod.outlook.com>

[Public]

Hi,

> -----Original Message-----
> From: Tomas Melin <tomas.melin at vaisala.com>
> Sent: Monday, December 1, 2025 6:20 PM
> To: Alexandre Belloni <alexandre.belloni at bootlin.com>; Simek, Michal
> <michal.simek at amd.com>
> Cc: linux-rtc at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux-
> kernel at vger.kernel.org; Tomas Melin <tomas.melin at vaisala.com>
> Subject: [PATCH 4/4] rtc: zynqmp: use dynamic max and min offset ranges
>
> Caution: This message originated from an External Source. Use proper
> caution when opening attachments, clicking links, or responding.
>
>
> Maximum and minimum offsets in ppb that can be handled are dependent
> on the rtc clock frequency and what can fit in the 16-bit register field.
>
> Signed-off-by: Tomas Melin <tomas.melin at vaisala.com>
> ---
>  drivers/rtc/rtc-zynqmp.c | 8 +++-----
>  1 file changed, 3 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c index
> 3bc8831ba2c4c4c701a49506b67ae6174f3ade3d..0cebc99b15a6de2440a60afc
> 2bd1769eccfa84b3 100644
> --- a/drivers/rtc/rtc-zynqmp.c
> +++ b/drivers/rtc/rtc-zynqmp.c
> @@ -44,8 +44,6 @@
>  #define RTC_FR_MASK            0xF0000
>  #define RTC_FR_MAX_TICKS       16
>  #define RTC_PPB                        1000000000LL
> -#define RTC_MIN_OFFSET         -32768000
> -#define RTC_MAX_OFFSET         32767000
>
>  struct xlnx_rtc_dev {
>         struct rtc_device       *rtc;
> @@ -215,12 +213,12 @@ static int xlnx_rtc_set_offset(struct device *dev,
> long offset)
>
>         /* ticks to reach RTC_PPB */
>         tick_mult = DIV_ROUND_CLOSEST(RTC_PPB, xrtcdev->freq);
> -       if (offset < RTC_MIN_OFFSET || offset > RTC_MAX_OFFSET)
> -               return -ERANGE;
> -
>         /* Number ticks for given offset */
>         max_tick = div_s64_rem(offset, tick_mult, &fract_offset);
>
> +       if (freq + max_tick > RTC_TICK_MASK || (freq + max_tick < 1))
The check 'freq + max_tick < 1' should be '<2' to prevent writing 0 to the calibration register when fract_offset < 0 causes max_tick--.
Example: freq=32767, max_tick=-32766 passes (sum=1), but after decrement becomes calibval=0.
> +               return -ERANGE;
> +
>         /* Number fractional ticks for given offset */
>         if (fract_offset) {
>                 /* round up here so we stay below a full tick */
>
> --
> 2.47.3
>

Thanks,
Harini T


From robh at kernel.org  Tue Dec  9 12:41:30 2025
From: robh at kernel.org (Rob Herring)
Date: Tue, 9 Dec 2025 14:41:30 -0600
Subject: [PATCH net-next v5 1/4] dt-bindings: net: ftgmac100: Add delay
 properties for AST2600
In-Reply-To: <20251205-rgmii_delay_2600-v5-1-bd2820ad3da7@aspeedtech.com>
References: <20251205-rgmii_delay_2600-v5-0-bd2820ad3da7@aspeedtech.com>
 <20251205-rgmii_delay_2600-v5-1-bd2820ad3da7@aspeedtech.com>
Message-ID: <20251209204130.GA1056291-robh@kernel.org>

On Fri, Dec 05, 2025 at 05:53:15PM +0800, Jacky Chou wrote:
> The AST2600 contains two dies, each with its own MAC, and these MACs
> require different delay configurations.
> Previously, these delay values were configured during the bootloader
> stage rather than in the driver. This change introduces the use of the
> standard properties defined in ethernet-controller.yaml to configure
> the delay values directly in the driver.
> 
> Each Aspeed platform has its own delay step value. And for Aspeed platform,
> the total steps of RGMII delay configuraion is 32 steps, so the total delay
> is delay-step-ps * 32.
> Default delay values are declared so that tx-internal-delay-ps and
> rx-internal-delay-ps become optional. If these properties are not present,
> the driver will use the default values instead.
> Add conditional schema constraints for Aspeed AST2600 MAC controllers:
> - For MAC0/1, per delay step for rgmii is 45 ps
> - For MAC2/3, per delay step for rgmii is 250 ps
> - Both require the "aspeed,scu" and "aspeed,rgmii-delay-ps" properties.
> Other compatible values remain unrestricted.
> 
> Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
> ---
>  .../devicetree/bindings/net/faraday,ftgmac100.yaml | 27 ++++++++++++++++++++++
>  1 file changed, 27 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/net/faraday,ftgmac100.yaml b/Documentation/devicetree/bindings/net/faraday,ftgmac100.yaml
> index d14410018bcf..00f7a0e56106 100644
> --- a/Documentation/devicetree/bindings/net/faraday,ftgmac100.yaml
> +++ b/Documentation/devicetree/bindings/net/faraday,ftgmac100.yaml
> @@ -69,6 +69,30 @@ properties:
>    mdio:
>      $ref: /schemas/net/mdio.yaml#
>  
> +  aspeed,scu:
> +    $ref: /schemas/types.yaml#/definitions/phandle
> +    description:
> +      Phandle to the SCU (System Control Unit) syscon node for Aspeed platform.
> +      This reference is used by the MAC controller to configure the RGMII delays.
> +
> +  rx-internal-delay-ps:
> +    description:
> +      RGMII Receive Clock Delay defined in pico seconds. There are 32
> +      steps of RGMII delay for Aspeed platform. Each Aspeed platform has its
> +      own delay step value, it is fixed by hardware design. Total delay is
> +      calculated by delay-step * 32. A value of 0 ps will disable any
> +      delay. The Default is no delay.
> +    default: 0
> +
> +  tx-internal-delay-ps:
> +    description:
> +      RGMII Transmit Clock Delay defined in pico seconds. There are 32
> +      steps of RGMII delay for Aspeed platform. Each Aspeed platform has its
> +      own delay step value, it is fixed by hardware design. Total delay is
> +      calculated by delay-step * 32. A value of 0 ps will disable any
> +      delay. The Default is no delay.
> +    default: 0
> +
>  required:
>    - compatible
>    - reg
> @@ -85,6 +109,9 @@ allOf:
>      then:
>        properties:
>          resets: true
> +        aspeed,scu: true
> +        rx-internal-delay-ps: true
> +        tx-internal-delay-ps: true

There is no need for these (including the 'resets'). Really, the 'if' 
should be negated with a 'not' and this part dropped.

>      else:
>        properties:
>          resets: false

But you need false entries here since these 3 properties are just for 
ast2600.

Rob


From nicolas at ndufresne.ca  Tue Dec  9 12:47:10 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Tue, 09 Dec 2025 15:47:10 -0500
Subject: [PATCH 5/5] media: platform: mtk-mdp3: Change
 cmdq_pkt_jump_rel() to cmdq_pkt_jump_rel_temp()
In-Reply-To: <20251031160309.1654761-6-jason-jh.lin@mediatek.com>
References: <20251031160309.1654761-1-jason-jh.lin@mediatek.com>
	 <20251031160309.1654761-6-jason-jh.lin@mediatek.com>
Message-ID: <e0144120e0943b94454b1cddd5359c34b5a15412.camel@ndufresne.ca>

Hi,


Le samedi 01 novembre 2025 ? 00:02 +0800, Jason-JH Lin a ?crit?:
> To facilitate the removal of the shift_pa parameter from
> cmdq_pkt_jump_rel(), current users of cmdq_pkt_jump_rel() need to
> transition to using cmdq_pkt_jump_rel_temp() before the API change
> is implemented.
> 
> Signed-off-by: Jason-JH Lin <jason-jh.lin at mediatek.com>
> Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
> ---
> ?drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c | 2 +-
> ?1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c
> index d0b0b072f953..5fc9263ccb78 100644
> --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c
> +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c
> @@ -628,7 +628,7 @@ static struct mdp_cmdq_cmd *mdp_cmdq_prepare(struct mdp_dev *mdp,
> ?		goto err_free_path;
> ?	}
> ?	cmdq_pkt_eoc(&cmd->pkt);
> -	cmdq_pkt_jump_rel(&cmd->pkt, CMDQ_INST_SIZE, mdp->cmdq_shift_pa[pp_idx]);
> +	cmdq_pkt_jump_rel_temp(&cmd->pkt, CMDQ_INST_SIZE, mdp->cmdq_shift_pa[pp_idx]);

I cannot take that right now in the media tree, as it won't build. Can the SoC
maintainer help me know if I just leave that on hold, or perhaps you'd like to
take it ? (or its in next, and I just have to wait for next udpate?)

I also doubt patch 4/5 is make much of a difference without the soc changes ?

regards,
Nicolas

> ?
> ?	for (i = 0; i < num_comp; i++) {
> ?		s32 inner_id = MDP_COMP_NONE;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251209/8c61b1b9/attachment.sig>

From robh at kernel.org  Tue Dec  9 12:50:34 2025
From: robh at kernel.org (Rob Herring)
Date: Tue, 9 Dec 2025 14:50:34 -0600
Subject: [PATCH net-next v5 3/4] net: ftgmac100: Add RGMII delay support
 for AST2600
In-Reply-To: <8a991b33-f653-4f0c-bbea-b5b3404cdfe6@lunn.ch>
References: <20251205-rgmii_delay_2600-v5-0-bd2820ad3da7@aspeedtech.com>
 <20251205-rgmii_delay_2600-v5-3-bd2820ad3da7@aspeedtech.com>
 <8a991b33-f653-4f0c-bbea-b5b3404cdfe6@lunn.ch>
Message-ID: <20251209205034.GB1056291-robh@kernel.org>

On Sat, Dec 06, 2025 at 07:30:30PM +0100, Andrew Lunn wrote:
> > @@ -1907,6 +2179,10 @@ static int ftgmac100_probe(struct platform_device *pdev)
> >  		priv->rxdes0_edorr_mask = BIT(30);
> >  		priv->txdes0_edotr_mask = BIT(30);
> >  		priv->is_aspeed = true;
> > +		/* Configure RGMII delay if there are the corresponding compatibles */
> > +		err = ftgmac100_set_internal_delay(priv, &phy_intf);
> > +		if (err)
> > +			goto err_phy_connect;
> 
> Thinking forward to when you add 2700 support, i really think you need
> to break the probe up into helpers for 2500 and before, 2600 and in
> the future 2700. You currently have a couple of tests on the
> compatible which you can reduce to one.
> 
> In fact, this driver has 10 calls to of_device_is_compatible(). I
> think you should first refactor the code to list each compatible in
> ftgmac100_of_match[], and add a data structure which contains an enum
> of the MAC type. You can then transfer this to priv, and replace all
> the of_device_is_compatible() tests to just look at the enum value.

Better yet, define a structure which defines the different settings 
directly. Such as:

priv->rxdes0_edorr_mask
priv->txdes0_edotr_mask
priv->is_aspeed

And anything else needed...

Rob


From coltonlewis at google.com  Tue Dec  9 12:50:57 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Tue,  9 Dec 2025 20:50:57 +0000
Subject: [PATCH v5 00/24] ARM64 PMU Partitioning
Message-ID: <20251209205121.1871534-1-coltonlewis@google.com>

This series creates a new PMU scheme on ARM, a partitioned PMU that
allows reserving a subset of counters for more direct guest access,
significantly reducing overhead. More details, including performance
benchmarks, can be read in the v1 cover letter linked below.

An overview of what this series accomplishes was presented at KVM
Forum 2025. Slides [1] and video [2] are linked below.

The long duration between v4 and v5 is due to time spent on this
project being monopolized preparing this feature for internal
production. As a result, there are too many improvements to fully list
here, but I will cover the notable ones.

v5:

* Rebase onto v6.18-rc7. This required pulling some reorganization
  patches from Anish and Sean that were dependencies from previous
  versions based on kvm/queue but never made it to upstream.

* Ensure FGTs (fine-grained traps) are correctly programmed at vCPU
  load using kvm_vcpu_load_fgt() and helpers introduced by Oliver
  Upton.

* Cleanly separate concerns of whether the partitioned PMU is enabled
  for the guest and whether FGT should be enabled. This allows that
  the capability can be VM-scoped while the implementation detail of
  whether FGT and context switching are in effect can remain
  vCPU-scoped.

* Shrink the uAPI change. Instead of a cap and corresponding ioctl,
  the feature can be controlled by just a cap with an argument. The
  cap is now also VM-scoped and enforces ordering that it should be
  decided before vCPUs are created. Whether the cap is enabled is now
  tracked by the new flag KVM_ARCH_ARM_PARTITIONED_PMU_ENABLED.

* Improve log messages when partitioning in the PMUv3 driver.

* Introduce a global variable armv8pmu_hpmn_max in the PMUv3 driver so
  KVM code can read if a value was set before the PMU is probed. This
  is needed to properly test if we have the capability before vCPUs
  are created.

* Make it possible for a VMM to filter the HPMN0 feature bit.

* Fix event filter problems with PMEVTYPER handling in
  writethrough_pmevtyper() and kvm_pmu_apply_event_filter() by using
  kvm_pmu_event_mask() in the right spots. And if an event is
  filtered, write the physical register with the appropriate exclude
  bits set but keep the virtual register exactly what the guest wrote.

* Fix register access problems with the PMU register fast path handler
  by lifting some static PMU access checks from sys_regs.c to use them
  in the fast path too and make bit masking more strict for better ARM
  compliance.

* Fix the readability and logic of programming the MDCR_EL2 register
  when entering the guest. Make sure to set the HPME bit to allow host
  counters to count guest events. Set TPM and TPMCR by default and
  clear them if partitioning is enabled rather than the previous
  inverted logic of leaving them clear and setting them if
  partitioning is not enabled. Make the HPMN field computation more
  clear.

* As part of lazy context switching, do a load when the guest is
  switching to physical access to ensure any previous writes that only
  reached the virtual registers reach the physical ones as well and
  are not clobbered by the next vcpu_put().

* Other fixes and improvements that are too small to mention or left
  out from my personal notes.

v4:
https://lore.kernel.org/kvmarm/20250714225917.1396543-1-coltonlewis at google.com/

v3:
https://lore.kernel.org/kvm/20250626200459.1153955-1-coltonlewis at google.com/

v2:
https://lore.kernel.org/kvm/20250620221326.1261128-1-coltonlewis at google.com/

v1:
https://lore.kernel.org/kvm/20250602192702.2125115-1-coltonlewis at google.com/

[1] https://gitlab.com/qemu-project/kvm-forum/-/raw/main/_attachments/2025/Optimizing__itvHkhc.pdf
[2] https://www.youtube.com/watch?v=YRzZ8jMIA6M&list=PLW3ep1uCIRfxwmllXTOA2txfDWN6vUOHp&index=9

Anish Ghulati (1):
  KVM: arm64: Move arm_{psci,hypercalls}.h to an internal KVM path

Colton Lewis (20):
  arm64: cpufeature: Add cpucap for HPMN0
  KVM: arm64: Reorganize PMU functions
  perf: arm_pmuv3: Introduce method to partition the PMU
  perf: arm_pmuv3: Generalize counter bitmasks
  perf: arm_pmuv3: Keep out of guest counter partition
  KVM: arm64: Set up FGT for Partitioned PMU
  KVM: arm64: Writethrough trapped PMEVTYPER register
  KVM: arm64: Use physical PMSELR for PMXEVTYPER if partitioned
  KVM: arm64: Writethrough trapped PMOVS register
  KVM: arm64: Write fast path PMU register handlers
  KVM: arm64: Setup MDCR_EL2 to handle a partitioned PMU
  KVM: arm64: Account for partitioning in PMCR_EL0 access
  KVM: arm64: Context swap Partitioned PMU guest registers
  KVM: arm64: Enforce PMU event filter at vcpu_load()
  KVM: arm64: Implement lazy PMU context swaps
  perf: arm_pmuv3: Handle IRQs for Partitioned PMU guest counters
  KVM: arm64: Inject recorded guest interrupts
  KVM: arm64: Add KVM_CAP to partition the PMU
  KVM: selftests: Add find_bit to KVM library
  KVM: arm64: selftests: Add test case for partitioned PMU

Marc Zyngier (1):
  KVM: arm64: Reorganize PMU includes

Sean Christopherson (2):
  KVM: arm64: Include KVM headers to get forward declarations
  KVM: arm64: Move ARM specific headers in include/kvm to arch directory

 Documentation/virt/kvm/api.rst                |  24 +
 arch/arm/include/asm/arm_pmuv3.h              |  28 +
 arch/arm64/include/asm/arm_pmuv3.h            |  61 +-
 .../arm64/include/asm/kvm_arch_timer.h        |   2 +
 arch/arm64/include/asm/kvm_host.h             |  24 +-
 .../arm64/include/asm/kvm_pmu.h               | 142 ++++
 arch/arm64/include/asm/kvm_types.h            |   7 +-
 .../arm64/include/asm/kvm_vgic.h              |   0
 arch/arm64/kernel/cpufeature.c                |   8 +
 arch/arm64/kvm/Makefile                       |   2 +-
 arch/arm64/kvm/arch_timer.c                   |   5 +-
 arch/arm64/kvm/arm.c                          |  23 +-
 {include => arch/arm64}/kvm/arm_hypercalls.h  |   0
 {include => arch/arm64}/kvm/arm_psci.h        |   0
 arch/arm64/kvm/config.c                       |  34 +-
 arch/arm64/kvm/debug.c                        |  31 +-
 arch/arm64/kvm/guest.c                        |   2 +-
 arch/arm64/kvm/handle_exit.c                  |   2 +-
 arch/arm64/kvm/hyp/Makefile                   |   6 +-
 arch/arm64/kvm/hyp/include/hyp/switch.h       | 211 ++++-
 arch/arm64/kvm/hyp/nvhe/switch.c              |   4 +-
 arch/arm64/kvm/hyp/vhe/switch.c               |   4 +-
 arch/arm64/kvm/hypercalls.c                   |   4 +-
 arch/arm64/kvm/pmu-direct.c                   | 464 +++++++++++
 arch/arm64/kvm/pmu-emul.c                     | 678 +---------------
 arch/arm64/kvm/pmu.c                          | 726 ++++++++++++++++++
 arch/arm64/kvm/psci.c                         |   4 +-
 arch/arm64/kvm/pvtime.c                       |   2 +-
 arch/arm64/kvm/reset.c                        |   3 +-
 arch/arm64/kvm/sys_regs.c                     | 110 +--
 arch/arm64/kvm/trace_arm.h                    |   2 +-
 arch/arm64/kvm/trng.c                         |   2 +-
 arch/arm64/kvm/vgic/vgic-debug.c              |   2 +-
 arch/arm64/kvm/vgic/vgic-init.c               |   2 +-
 arch/arm64/kvm/vgic/vgic-irqfd.c              |   2 +-
 arch/arm64/kvm/vgic/vgic-kvm-device.c         |   2 +-
 arch/arm64/kvm/vgic/vgic-mmio-v2.c            |   2 +-
 arch/arm64/kvm/vgic/vgic-mmio-v3.c            |   2 +-
 arch/arm64/kvm/vgic/vgic-mmio.c               |   4 +-
 arch/arm64/kvm/vgic/vgic-v2.c                 |   2 +-
 arch/arm64/kvm/vgic/vgic-v3-nested.c          |   3 +-
 arch/arm64/kvm/vgic/vgic-v3.c                 |   2 +-
 arch/arm64/kvm/vgic/vgic-v5.c                 |   2 +-
 arch/arm64/tools/cpucaps                      |   1 +
 arch/arm64/tools/sysreg                       |   6 +-
 drivers/perf/arm_pmuv3.c                      | 137 +++-
 include/linux/perf/arm_pmu.h                  |   1 +
 include/linux/perf/arm_pmuv3.h                |  14 +-
 include/uapi/linux/kvm.h                      |   1 +
 tools/include/uapi/linux/kvm.h                |   1 +
 tools/testing/selftests/kvm/Makefile.kvm      |   1 +
 .../selftests/kvm/arm64/vpmu_counter_access.c |  77 +-
 tools/testing/selftests/kvm/lib/find_bit.c    |   1 +
 53 files changed, 2049 insertions(+), 831 deletions(-)
 rename include/kvm/arm_arch_timer.h => arch/arm64/include/asm/kvm_arch_timer.h (98%)
 rename include/kvm/arm_pmu.h => arch/arm64/include/asm/kvm_pmu.h (61%)
 rename include/kvm/arm_vgic.h => arch/arm64/include/asm/kvm_vgic.h (100%)
 rename {include => arch/arm64}/kvm/arm_hypercalls.h (100%)
 rename {include => arch/arm64}/kvm/arm_psci.h (100%)
 create mode 100644 arch/arm64/kvm/pmu-direct.c
 create mode 100644 tools/testing/selftests/kvm/lib/find_bit.c


base-commit: ac3fd01e4c1efce8f2c054cdeb2ddd2fc0fb150d
--
2.52.0.239.gd5f0c6e74e-goog


From coltonlewis at google.com  Tue Dec  9 12:50:58 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Tue,  9 Dec 2025 20:50:58 +0000
Subject: [PATCH v5 01/24] arm64: cpufeature: Add cpucap for HPMN0
In-Reply-To: <20251209205121.1871534-1-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
Message-ID: <20251209205121.1871534-2-coltonlewis@google.com>

Add a capability for FEAT_HPMN0, whether MDCR_EL2.HPMN can specify 0
counters reserved for the guest.

This required changing HPMN0 to an UnsignedEnum in tools/sysreg
because otherwise not all the appropriate macros are generated to add
it to arm64_cpu_capabilities_arm64_features.

Acked-by: Mark Rutland <mark.rutland at arm.com>
Signed-off-by: Colton Lewis <coltonlewis at google.com>
---
 arch/arm64/kernel/cpufeature.c | 8 ++++++++
 arch/arm64/kvm/sys_regs.c      | 3 ++-
 arch/arm64/tools/cpucaps       | 1 +
 arch/arm64/tools/sysreg        | 6 +++---
 4 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index e25b0f84a22da..ceddc55eb30a0 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -555,6 +555,7 @@ static const struct arm64_ftr_bits ftr_id_mmfr0[] = {
 };
 
 static const struct arm64_ftr_bits ftr_id_aa64dfr0[] = {
+	ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64DFR0_EL1_HPMN0_SHIFT, 4, 0),
 	S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_EL1_DoubleLock_SHIFT, 4, 0),
 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64DFR0_EL1_PMSVer_SHIFT, 4, 0),
 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_EL1_CTX_CMPs_SHIFT, 4, 0),
@@ -2898,6 +2899,13 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
 		.matches = has_cpuid_feature,
 		ARM64_CPUID_FIELDS(ID_AA64MMFR0_EL1, FGT, FGT2)
 	},
+	{
+		.desc = "HPMN0",
+		.type = ARM64_CPUCAP_SYSTEM_FEATURE,
+		.capability = ARM64_HAS_HPMN0,
+		.matches = has_cpuid_feature,
+		ARM64_CPUID_FIELDS(ID_AA64DFR0_EL1, HPMN0, IMP)
+	},
 #ifdef CONFIG_ARM64_SME
 	{
 		.desc = "Scalable Matrix Extension",
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index ec3fbe0b8d525..c636840b1f6f9 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -3214,7 +3214,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 		    ID_AA64DFR0_EL1_DoubleLock_MASK |
 		    ID_AA64DFR0_EL1_WRPs_MASK |
 		    ID_AA64DFR0_EL1_PMUVer_MASK |
-		    ID_AA64DFR0_EL1_DebugVer_MASK),
+		    ID_AA64DFR0_EL1_DebugVer_MASK |
+		    ID_AA64DFR0_EL1_HPMN0_MASK),
 	ID_SANITISED(ID_AA64DFR1_EL1),
 	ID_UNALLOCATED(5,2),
 	ID_UNALLOCATED(5,3),
diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps
index 1b32c1232d28d..8efa6a437515d 100644
--- a/arch/arm64/tools/cpucaps
+++ b/arch/arm64/tools/cpucaps
@@ -41,6 +41,7 @@ HAS_GICV5_LEGACY
 HAS_GIC_PRIO_MASKING
 HAS_GIC_PRIO_RELAXED_SYNC
 HAS_HCR_NV1
+HAS_HPMN0
 HAS_HCX
 HAS_LDAPR
 HAS_LPA2
diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
index 1c6cdf9d54bba..24d20138ea664 100644
--- a/arch/arm64/tools/sysreg
+++ b/arch/arm64/tools/sysreg
@@ -1666,9 +1666,9 @@ EndEnum
 EndSysreg
 
 Sysreg	ID_AA64DFR0_EL1	3	0	0	5	0
-Enum	63:60	HPMN0
-	0b0000	UNPREDICTABLE
-	0b0001	DEF
+UnsignedEnum	63:60	HPMN0
+	0b0000	NI
+	0b0001	IMP
 EndEnum
 UnsignedEnum	59:56	ExtTrcBuff
 	0b0000	NI
-- 
2.52.0.239.gd5f0c6e74e-goog



From coltonlewis at google.com  Tue Dec  9 12:50:59 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Tue,  9 Dec 2025 20:50:59 +0000
Subject: [PATCH v5 02/24] KVM: arm64: Move arm_{psci,hypercalls}.h to an
 internal KVM path
In-Reply-To: <20251209205121.1871534-1-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
Message-ID: <20251209205121.1871534-3-coltonlewis@google.com>

From: Anish Ghulati <aghulati at google.com>

Move arm_hypercalls.h and arm_psci.h into arch/arm64/kvm now that KVM
no longer supports 32-bit ARM, i.e. now that there's no reason to make
the hypercall and PSCI APIs "public".

Signed-off-by: Anish Ghulati <aghulati at google.com>
[sean: squash into one patch, write changelog]
Signed-off-by: Sean Christopherson <seanjc at google.com>
Message-ID: <20250611001042.170501-2-seanjc at google.com>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
---
 arch/arm64/kvm/arm.c                         | 5 +++--
 {include => arch/arm64}/kvm/arm_hypercalls.h | 0
 {include => arch/arm64}/kvm/arm_psci.h       | 0
 arch/arm64/kvm/guest.c                       | 2 +-
 arch/arm64/kvm/handle_exit.c                 | 2 +-
 arch/arm64/kvm/hyp/Makefile                  | 6 +++---
 arch/arm64/kvm/hyp/include/hyp/switch.h      | 4 ++--
 arch/arm64/kvm/hyp/nvhe/switch.c             | 4 ++--
 arch/arm64/kvm/hyp/vhe/switch.c              | 4 ++--
 arch/arm64/kvm/hypercalls.c                  | 4 ++--
 arch/arm64/kvm/psci.c                        | 4 ++--
 arch/arm64/kvm/pvtime.c                      | 2 +-
 arch/arm64/kvm/trng.c                        | 2 +-
 13 files changed, 20 insertions(+), 19 deletions(-)
 rename {include => arch/arm64}/kvm/arm_hypercalls.h (100%)
 rename {include => arch/arm64}/kvm/arm_psci.h (100%)

diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 052bf0d4d0b03..d1750d6058dfd 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -41,9 +41,10 @@
 #include <asm/kvm_ptrauth.h>
 #include <asm/sections.h>
 
-#include <kvm/arm_hypercalls.h>
 #include <kvm/arm_pmu.h>
-#include <kvm/arm_psci.h>
+
+#include "arm_hypercalls.h"
+#include "arm_psci.h"
 
 #include "sys_regs.h"
 
diff --git a/include/kvm/arm_hypercalls.h b/arch/arm64/kvm/arm_hypercalls.h
similarity index 100%
rename from include/kvm/arm_hypercalls.h
rename to arch/arm64/kvm/arm_hypercalls.h
diff --git a/include/kvm/arm_psci.h b/arch/arm64/kvm/arm_psci.h
similarity index 100%
rename from include/kvm/arm_psci.h
rename to arch/arm64/kvm/arm_psci.h
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 1c87699fd886e..863b351ae1221 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -18,7 +18,6 @@
 #include <linux/string.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
-#include <kvm/arm_hypercalls.h>
 #include <asm/cputype.h>
 #include <linux/uaccess.h>
 #include <asm/fpsimd.h>
@@ -27,6 +26,7 @@
 #include <asm/kvm_nested.h>
 #include <asm/sigcontext.h>
 
+#include "arm_hypercalls.h"
 #include "trace.h"
 
 const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index cc7d5d1709cb8..66740520f2166 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -22,7 +22,7 @@
 #include <asm/stacktrace/nvhe.h>
 #include <asm/traps.h>
 
-#include <kvm/arm_hypercalls.h>
+#include "arm_hypercalls.h"
 
 #define CREATE_TRACE_POINTS
 #include "trace_handle_exit.h"
diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile
index d61e44642f980..b1a4884446c69 100644
--- a/arch/arm64/kvm/hyp/Makefile
+++ b/arch/arm64/kvm/hyp/Makefile
@@ -3,8 +3,8 @@
 # Makefile for Kernel-based Virtual Machine module, HYP part
 #
 
-incdir := $(src)/include
-subdir-asflags-y := -I$(incdir)
-subdir-ccflags-y := -I$(incdir)
+hyp_includes := -I$(src)/include -I$(srctree)/arch/arm64/kvm
+subdir-asflags-y := $(hyp_includes)
+subdir-ccflags-y := $(hyp_includes)
 
 obj-$(CONFIG_KVM) += vhe/ nvhe/ pgtable.o
diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index c5d5e5b86eaf0..6e8050f260f34 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -16,8 +16,6 @@
 #include <linux/jump_label.h>
 #include <uapi/linux/psci.h>
 
-#include <kvm/arm_psci.h>
-
 #include <asm/barrier.h>
 #include <asm/cpufeature.h>
 #include <asm/extable.h>
@@ -32,6 +30,8 @@
 #include <asm/processor.h>
 #include <asm/traps.h>
 
+#include "arm_psci.h"
+
 struct kvm_exception_table_entry {
 	int insn, fixup;
 };
diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c
index d3b9ec8a7c283..5d626308952ac 100644
--- a/arch/arm64/kvm/hyp/nvhe/switch.c
+++ b/arch/arm64/kvm/hyp/nvhe/switch.c
@@ -13,8 +13,6 @@
 #include <linux/jump_label.h>
 #include <uapi/linux/psci.h>
 
-#include <kvm/arm_psci.h>
-
 #include <asm/barrier.h>
 #include <asm/cpufeature.h>
 #include <asm/kprobes.h>
@@ -28,6 +26,8 @@
 
 #include <nvhe/mem_protect.h>
 
+#include "arm_psci.h"
+
 /* Non-VHE specific context */
 DEFINE_PER_CPU(struct kvm_host_data, kvm_host_data);
 DEFINE_PER_CPU(struct kvm_cpu_context, kvm_hyp_ctxt);
diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c
index 9984c492305a8..0039e501a3cb7 100644
--- a/arch/arm64/kvm/hyp/vhe/switch.c
+++ b/arch/arm64/kvm/hyp/vhe/switch.c
@@ -13,8 +13,6 @@
 #include <linux/percpu.h>
 #include <uapi/linux/psci.h>
 
-#include <kvm/arm_psci.h>
-
 #include <asm/barrier.h>
 #include <asm/cpufeature.h>
 #include <asm/kprobes.h>
@@ -28,6 +26,8 @@
 #include <asm/thread_info.h>
 #include <asm/vectors.h>
 
+#include "arm_psci.h"
+
 /* VHE specific context */
 DEFINE_PER_CPU(struct kvm_host_data, kvm_host_data);
 DEFINE_PER_CPU(struct kvm_cpu_context, kvm_hyp_ctxt);
diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
index 58c5fe7d75727..05331389081f8 100644
--- a/arch/arm64/kvm/hypercalls.c
+++ b/arch/arm64/kvm/hypercalls.c
@@ -6,8 +6,8 @@
 
 #include <asm/kvm_emulate.h>
 
-#include <kvm/arm_hypercalls.h>
-#include <kvm/arm_psci.h>
+#include "arm_hypercalls.h"
+#include "arm_psci.h"
 
 #define KVM_ARM_SMCCC_STD_FEATURES				\
 	GENMASK(KVM_REG_ARM_STD_BMAP_BIT_COUNT - 1, 0)
diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
index 3b5dbe9a0a0ea..0566b59074978 100644
--- a/arch/arm64/kvm/psci.c
+++ b/arch/arm64/kvm/psci.c
@@ -13,8 +13,8 @@
 #include <asm/cputype.h>
 #include <asm/kvm_emulate.h>
 
-#include <kvm/arm_psci.h>
-#include <kvm/arm_hypercalls.h>
+#include "arm_hypercalls.h"
+#include "arm_psci.h"
 
 /*
  * This is an implementation of the Power State Coordination Interface
diff --git a/arch/arm64/kvm/pvtime.c b/arch/arm64/kvm/pvtime.c
index 4ceabaa4c30bd..b07d250d223c0 100644
--- a/arch/arm64/kvm/pvtime.c
+++ b/arch/arm64/kvm/pvtime.c
@@ -8,7 +8,7 @@
 #include <asm/kvm_mmu.h>
 #include <asm/pvclock-abi.h>
 
-#include <kvm/arm_hypercalls.h>
+#include "arm_hypercalls.h"
 
 void kvm_update_stolen_time(struct kvm_vcpu *vcpu)
 {
diff --git a/arch/arm64/kvm/trng.c b/arch/arm64/kvm/trng.c
index 99bdd7103c9c1..b5dc0f09797a3 100644
--- a/arch/arm64/kvm/trng.c
+++ b/arch/arm64/kvm/trng.c
@@ -6,7 +6,7 @@
 
 #include <asm/kvm_emulate.h>
 
-#include <kvm/arm_hypercalls.h>
+#include "arm_hypercalls.h"
 
 #define ARM_SMCCC_TRNG_VERSION_1_0	0x10000UL
 
-- 
2.52.0.239.gd5f0c6e74e-goog



From coltonlewis at google.com  Tue Dec  9 12:51:00 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Tue,  9 Dec 2025 20:51:00 +0000
Subject: [PATCH v5 03/24] KVM: arm64: Include KVM headers to get forward declarations
In-Reply-To: <20251209205121.1871534-1-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
Message-ID: <20251209205121.1871534-4-coltonlewis@google.com>

From: Sean Christopherson <seanjc at google.com>

Include include/uapi/linux/kvm.h and include/linux/kvm_types.h in ARM's
public arm_arch_timer.h and arm_pmu.h headers to get forward declarations
of things like "struct kvm_vcpu" and "struct kvm_device_attr", which are
referenced but never declared (neither file includes *any* KVM headers).

The missing includes don't currently cause problems because of the order
of includes in parent files, but that order is largely arbitrary and is
subject to change, e.g. a future commit will move the ARM specific headers
to arch/arm64/include/asm and reorder parent includes to maintain
alphabetic ordering.

Reported-by: kernel test robot <lkp at intel.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
Message-ID: <20250611001042.170501-3-seanjc at google.com>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
---
 include/kvm/arm_arch_timer.h | 2 ++
 include/kvm/arm_pmu.h        | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index 7310841f45121..d55359e67c22c 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -7,6 +7,8 @@
 #ifndef __ASM_ARM_KVM_ARCH_TIMER_H
 #define __ASM_ARM_KVM_ARCH_TIMER_H
 
+#include <linux/kvm.h>
+#include <linux/kvm_types.h>
 #include <linux/clocksource.h>
 #include <linux/hrtimer.h>
 
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 96754b51b4116..baf028d19dfc9 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -7,6 +7,8 @@
 #ifndef __ASM_ARM_KVM_PMU_H
 #define __ASM_ARM_KVM_PMU_H
 
+#include <linux/kvm.h>
+#include <linux/kvm_types.h>
 #include <linux/perf_event.h>
 #include <linux/perf/arm_pmuv3.h>
 
-- 
2.52.0.239.gd5f0c6e74e-goog



From coltonlewis at google.com  Tue Dec  9 12:51:01 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Tue,  9 Dec 2025 20:51:01 +0000
Subject: [PATCH v5 04/24] KVM: arm64: Move ARM specific headers in include/kvm
 to arch directory
In-Reply-To: <20251209205121.1871534-1-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
Message-ID: <20251209205121.1871534-5-coltonlewis@google.com>

From: Sean Christopherson <seanjc at google.com>

Move kvm/arm_{arch_timer,pmu,vgic}.h to arch/arm64/include/asm and drop
the "arm" prefix from all file names.  Now that KVM no longer supports
32-bit ARM, there is no reason to expose ARM specific headers to other
architectures beyond arm64.

Cc: Colton Lewis <coltonlewis at google.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
Message-ID: <20250611001042.170501-4-seanjc at google.com>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
[Colton: applied header change to vgic-v5.c]
Signed-off-by: Colton Lewis <coltonlewis at google.com>
---
 .../arm64/include/asm/kvm_arch_timer.h                     | 0
 arch/arm64/include/asm/kvm_host.h                          | 7 +++----
 include/kvm/arm_pmu.h => arch/arm64/include/asm/kvm_pmu.h  | 0
 .../kvm/arm_vgic.h => arch/arm64/include/asm/kvm_vgic.h    | 0
 arch/arm64/kvm/arch_timer.c                                | 5 ++---
 arch/arm64/kvm/arm.c                                       | 3 +--
 arch/arm64/kvm/pmu-emul.c                                  | 4 ++--
 arch/arm64/kvm/reset.c                                     | 3 +--
 arch/arm64/kvm/trace_arm.h                                 | 2 +-
 arch/arm64/kvm/vgic/vgic-debug.c                           | 2 +-
 arch/arm64/kvm/vgic/vgic-init.c                            | 2 +-
 arch/arm64/kvm/vgic/vgic-irqfd.c                           | 2 +-
 arch/arm64/kvm/vgic/vgic-kvm-device.c                      | 2 +-
 arch/arm64/kvm/vgic/vgic-mmio-v2.c                         | 2 +-
 arch/arm64/kvm/vgic/vgic-mmio-v3.c                         | 2 +-
 arch/arm64/kvm/vgic/vgic-mmio.c                            | 4 ++--
 arch/arm64/kvm/vgic/vgic-v2.c                              | 2 +-
 arch/arm64/kvm/vgic/vgic-v3-nested.c                       | 3 +--
 arch/arm64/kvm/vgic/vgic-v3.c                              | 2 +-
 arch/arm64/kvm/vgic/vgic-v5.c                              | 2 +-
 20 files changed, 22 insertions(+), 27 deletions(-)
 rename include/kvm/arm_arch_timer.h => arch/arm64/include/asm/kvm_arch_timer.h (100%)
 rename include/kvm/arm_pmu.h => arch/arm64/include/asm/kvm_pmu.h (100%)
 rename include/kvm/arm_vgic.h => arch/arm64/include/asm/kvm_vgic.h (100%)

diff --git a/include/kvm/arm_arch_timer.h b/arch/arm64/include/asm/kvm_arch_timer.h
similarity index 100%
rename from include/kvm/arm_arch_timer.h
rename to arch/arm64/include/asm/kvm_arch_timer.h
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 64302c438355c..7f19702eac2b9 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -26,17 +26,16 @@
 #include <asm/daifflags.h>
 #include <asm/fpsimd.h>
 #include <asm/kvm.h>
+#include <asm/kvm_arch_timer.h>
 #include <asm/kvm_asm.h>
+#include <asm/kvm_pmu.h>
+#include <asm/kvm_vgic.h>
 #include <asm/vncr_mapping.h>
 
 #define __KVM_HAVE_ARCH_INTC_INITIALIZED
 
 #define KVM_HALT_POLL_NS_DEFAULT 500000
 
-#include <kvm/arm_vgic.h>
-#include <kvm/arm_arch_timer.h>
-#include <kvm/arm_pmu.h>
-
 #define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
 
 #define KVM_VCPU_MAX_FEATURES 9
diff --git a/include/kvm/arm_pmu.h b/arch/arm64/include/asm/kvm_pmu.h
similarity index 100%
rename from include/kvm/arm_pmu.h
rename to arch/arm64/include/asm/kvm_pmu.h
diff --git a/include/kvm/arm_vgic.h b/arch/arm64/include/asm/kvm_vgic.h
similarity index 100%
rename from include/kvm/arm_vgic.h
rename to arch/arm64/include/asm/kvm_vgic.h
diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c
index 3f675875abea2..ce62a12cf0e5c 100644
--- a/arch/arm64/kvm/arch_timer.c
+++ b/arch/arm64/kvm/arch_timer.c
@@ -14,12 +14,11 @@
 
 #include <clocksource/arm_arch_timer.h>
 #include <asm/arch_timer.h>
+#include <asm/kvm_arch_timer.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_hyp.h>
 #include <asm/kvm_nested.h>
-
-#include <kvm/arm_vgic.h>
-#include <kvm/arm_arch_timer.h>
+#include <asm/kvm_vgic.h>
 
 #include "trace.h"
 
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index d1750d6058dfd..43e92f35f56ab 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -38,11 +38,10 @@
 #include <asm/kvm_mmu.h>
 #include <asm/kvm_nested.h>
 #include <asm/kvm_pkvm.h>
+#include <asm/kvm_pmu.h>
 #include <asm/kvm_ptrauth.h>
 #include <asm/sections.h>
 
-#include <kvm/arm_pmu.h>
-
 #include "arm_hypercalls.h"
 #include "arm_psci.h"
 
diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c
index b03dbda7f1ab9..dcdd80ffd49d5 100644
--- a/arch/arm64/kvm/pmu-emul.c
+++ b/arch/arm64/kvm/pmu-emul.c
@@ -12,8 +12,8 @@
 #include <linux/perf/arm_pmu.h>
 #include <linux/uaccess.h>
 #include <asm/kvm_emulate.h>
-#include <kvm/arm_pmu.h>
-#include <kvm/arm_vgic.h>
+#include <asm/kvm_pmu.h>
+#include <asm/kvm_vgic.h>
 
 #define PERF_ATTR_CFG1_COUNTER_64BIT	BIT(0)
 
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index 959532422d3a3..bae3676387419 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -17,12 +17,11 @@
 #include <linux/string.h>
 #include <linux/types.h>
 
-#include <kvm/arm_arch_timer.h>
-
 #include <asm/cpufeature.h>
 #include <asm/cputype.h>
 #include <asm/fpsimd.h>
 #include <asm/ptrace.h>
+#include <asm/kvm_arch_timer.h>
 #include <asm/kvm_arm.h>
 #include <asm/kvm_asm.h>
 #include <asm/kvm_emulate.h>
diff --git a/arch/arm64/kvm/trace_arm.h b/arch/arm64/kvm/trace_arm.h
index 9c60f6465c787..8fc8178e21a70 100644
--- a/arch/arm64/kvm/trace_arm.h
+++ b/arch/arm64/kvm/trace_arm.h
@@ -3,7 +3,7 @@
 #define _TRACE_ARM_ARM64_KVM_H
 
 #include <asm/kvm_emulate.h>
-#include <kvm/arm_arch_timer.h>
+#include <asm/kvm_arch_timer.h>
 #include <linux/tracepoint.h>
 
 #undef TRACE_SYSTEM
diff --git a/arch/arm64/kvm/vgic/vgic-debug.c b/arch/arm64/kvm/vgic/vgic-debug.c
index bb92853d1fd3a..a67e5e5f44871 100644
--- a/arch/arm64/kvm/vgic/vgic-debug.c
+++ b/arch/arm64/kvm/vgic/vgic-debug.c
@@ -9,7 +9,7 @@
 #include <linux/interrupt.h>
 #include <linux/kvm_host.h>
 #include <linux/seq_file.h>
-#include <kvm/arm_vgic.h>
+#include <asm/kvm_vgic.h>
 #include <asm/kvm_mmu.h>
 #include "vgic.h"
 
diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index da62edbc1205a..39ead7ec1b43a 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -7,7 +7,7 @@
 #include <linux/interrupt.h>
 #include <linux/cpu.h>
 #include <linux/kvm_host.h>
-#include <kvm/arm_vgic.h>
+#include <asm/kvm_vgic.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_mmu.h>
 #include "vgic.h"
diff --git a/arch/arm64/kvm/vgic/vgic-irqfd.c b/arch/arm64/kvm/vgic/vgic-irqfd.c
index c314c016659ab..b73401c34f298 100644
--- a/arch/arm64/kvm/vgic/vgic-irqfd.c
+++ b/arch/arm64/kvm/vgic/vgic-irqfd.c
@@ -6,7 +6,7 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <trace/events/kvm.h>
-#include <kvm/arm_vgic.h>
+#include <asm/kvm_vgic.h>
 #include "vgic.h"
 
 /*
diff --git a/arch/arm64/kvm/vgic/vgic-kvm-device.c b/arch/arm64/kvm/vgic/vgic-kvm-device.c
index 3d1a776b716d7..39d96b52f773d 100644
--- a/arch/arm64/kvm/vgic/vgic-kvm-device.c
+++ b/arch/arm64/kvm/vgic/vgic-kvm-device.c
@@ -7,7 +7,7 @@
  */
 #include <linux/irqchip/arm-gic-v3.h>
 #include <linux/kvm_host.h>
-#include <kvm/arm_vgic.h>
+#include <asm/kvm_vgic.h>
 #include <linux/uaccess.h>
 #include <asm/kvm_mmu.h>
 #include <asm/cputype.h>
diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v2.c b/arch/arm64/kvm/vgic/vgic-mmio-v2.c
index f25fccb1f8e63..d00c8a74fad63 100644
--- a/arch/arm64/kvm/vgic/vgic-mmio-v2.c
+++ b/arch/arm64/kvm/vgic/vgic-mmio-v2.c
@@ -9,7 +9,7 @@
 #include <linux/nospec.h>
 
 #include <kvm/iodev.h>
-#include <kvm/arm_vgic.h>
+#include <asm/kvm_vgic.h>
 
 #include "vgic.h"
 #include "vgic-mmio.h"
diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c
index 70d50c77e5dc7..5191ad3b74b7e 100644
--- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c
+++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c
@@ -9,11 +9,11 @@
 #include <linux/kvm_host.h>
 #include <linux/interrupt.h>
 #include <kvm/iodev.h>
-#include <kvm/arm_vgic.h>
 
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_arm.h>
 #include <asm/kvm_mmu.h>
+#include <asm/kvm_vgic.h>
 
 #include "vgic.h"
 #include "vgic-mmio.h"
diff --git a/arch/arm64/kvm/vgic/vgic-mmio.c b/arch/arm64/kvm/vgic/vgic-mmio.c
index a573b1f0c6cbe..45876b5ef9fc8 100644
--- a/arch/arm64/kvm/vgic/vgic-mmio.c
+++ b/arch/arm64/kvm/vgic/vgic-mmio.c
@@ -10,8 +10,8 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <kvm/iodev.h>
-#include <kvm/arm_arch_timer.h>
-#include <kvm/arm_vgic.h>
+#include <asm/kvm_arch_timer.h>
+#include <asm/kvm_vgic.h>
 
 #include "vgic.h"
 #include "vgic-mmio.h"
diff --git a/arch/arm64/kvm/vgic/vgic-v2.c b/arch/arm64/kvm/vgic/vgic-v2.c
index 381673f03c395..780afb7aad06e 100644
--- a/arch/arm64/kvm/vgic/vgic-v2.c
+++ b/arch/arm64/kvm/vgic/vgic-v2.c
@@ -6,7 +6,7 @@
 #include <linux/irqchip/arm-gic.h>
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
-#include <kvm/arm_vgic.h>
+#include <asm/kvm_vgic.h>
 #include <asm/kvm_mmu.h>
 
 #include "vgic.h"
diff --git a/arch/arm64/kvm/vgic/vgic-v3-nested.c b/arch/arm64/kvm/vgic/vgic-v3-nested.c
index 7f1259b49c505..f3f21d8fa8335 100644
--- a/arch/arm64/kvm/vgic/vgic-v3-nested.c
+++ b/arch/arm64/kvm/vgic/vgic-v3-nested.c
@@ -7,11 +7,10 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 
-#include <kvm/arm_vgic.h>
-
 #include <asm/kvm_arm.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_nested.h>
+#include <asm/kvm_vgic.h>
 
 #include "vgic.h"
 
diff --git a/arch/arm64/kvm/vgic/vgic-v3.c b/arch/arm64/kvm/vgic/vgic-v3.c
index 2f75ef14d3399..f345501016e2c 100644
--- a/arch/arm64/kvm/vgic/vgic-v3.c
+++ b/arch/arm64/kvm/vgic/vgic-v3.c
@@ -7,10 +7,10 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <linux/string_choices.h>
-#include <kvm/arm_vgic.h>
 #include <asm/kvm_hyp.h>
 #include <asm/kvm_mmu.h>
 #include <asm/kvm_asm.h>
+#include <asm/kvm_vgic.h>
 
 #include "vgic.h"
 
diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index 2d3811f4e1174..601d7b376deef 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 
-#include <kvm/arm_vgic.h>
+#include <asm/kvm_vgic.h>
 #include <linux/irqchip/arm-vgic-info.h>
 
 #include "vgic.h"
-- 
2.52.0.239.gd5f0c6e74e-goog



From coltonlewis at google.com  Tue Dec  9 12:51:02 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Tue,  9 Dec 2025 20:51:02 +0000
Subject: [PATCH v5 05/24] KVM: arm64: Reorganize PMU includes
In-Reply-To: <20251209205121.1871534-1-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
Message-ID: <20251209205121.1871534-6-coltonlewis@google.com>

From: Marc Zyngier <maz at kernel.org>

Including *all* of asm/kvm_host.h in asm/arm_pmuv3.h is a bad idea
because that is much more than arm_pmuv3.h logically needs and creates
a circular dependency that makes it easy to introduce compiler errors
when editing this code.

asm/kvm_host.h includes asm/kvm_pmu.h includes perf/arm_pmuv3.h
includes asm/arm_pmuv3.h includes asm/kvm_host.h

Reorganize the PMU includes to be more sane. In particular:

* Remove the circular dependency by removing the kvm_host.h include
  from asm/arm_pmuv3.h since 99% of it isn't needed.

* Move the remaining tiny bit of KVM/PMU interface from kvm_host.h
  into kvm_pmu.h

* Conditionally on ARM64, include the more targeted kvm_pmu.h directly
  in the arm_pmuv3.c driver.

Signed-off-by: Marc Zyngier <maz at kernel.org>
Signed-off-by: Colton Lewis <coltonlewis at google.com>
---
 arch/arm64/include/asm/arm_pmuv3.h |  2 --
 arch/arm64/include/asm/kvm_host.h  | 14 --------------
 arch/arm64/include/asm/kvm_pmu.h   | 15 +++++++++++++++
 drivers/perf/arm_pmuv3.c           |  5 +++++
 4 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/arch/arm64/include/asm/arm_pmuv3.h b/arch/arm64/include/asm/arm_pmuv3.h
index 8a777dec8d88a..cf2b2212e00a2 100644
--- a/arch/arm64/include/asm/arm_pmuv3.h
+++ b/arch/arm64/include/asm/arm_pmuv3.h
@@ -6,8 +6,6 @@
 #ifndef __ASM_PMUV3_H
 #define __ASM_PMUV3_H
 
-#include <asm/kvm_host.h>
-
 #include <asm/cpufeature.h>
 #include <asm/sysreg.h>
 
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 7f19702eac2b9..c7e52aaf469dc 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -1410,25 +1410,11 @@ void kvm_arch_vcpu_ctxflush_fp(struct kvm_vcpu *vcpu);
 void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu);
 void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu);
 
-static inline bool kvm_pmu_counter_deferred(struct perf_event_attr *attr)
-{
-	return (!has_vhe() && attr->exclude_host);
-}
-
 #ifdef CONFIG_KVM
-void kvm_set_pmu_events(u64 set, struct perf_event_attr *attr);
-void kvm_clr_pmu_events(u64 clr);
-bool kvm_set_pmuserenr(u64 val);
 void kvm_enable_trbe(void);
 void kvm_disable_trbe(void);
 void kvm_tracing_set_el1_configuration(u64 trfcr_while_in_guest);
 #else
-static inline void kvm_set_pmu_events(u64 set, struct perf_event_attr *attr) {}
-static inline void kvm_clr_pmu_events(u64 clr) {}
-static inline bool kvm_set_pmuserenr(u64 val)
-{
-	return false;
-}
 static inline void kvm_enable_trbe(void) {}
 static inline void kvm_disable_trbe(void) {}
 static inline void kvm_tracing_set_el1_configuration(u64 trfcr_while_in_guest) {}
diff --git a/arch/arm64/include/asm/kvm_pmu.h b/arch/arm64/include/asm/kvm_pmu.h
index baf028d19dfc9..ad3247b468388 100644
--- a/arch/arm64/include/asm/kvm_pmu.h
+++ b/arch/arm64/include/asm/kvm_pmu.h
@@ -11,9 +11,15 @@
 #include <linux/kvm_types.h>
 #include <linux/perf_event.h>
 #include <linux/perf/arm_pmuv3.h>
+#include <linux/perf/arm_pmu.h>
 
 #define KVM_ARMV8_PMU_MAX_COUNTERS	32
 
+#define kvm_pmu_counter_deferred(attr)			\
+	({						\
+		!has_vhe() && (attr)->exclude_host;	\
+	})
+
 #if IS_ENABLED(CONFIG_HW_PERF_EVENTS) && IS_ENABLED(CONFIG_KVM)
 struct kvm_pmc {
 	u8 idx;	/* index into the pmu->pmc array */
@@ -68,6 +74,9 @@ int kvm_arm_pmu_v3_has_attr(struct kvm_vcpu *vcpu,
 int kvm_arm_pmu_v3_enable(struct kvm_vcpu *vcpu);
 
 struct kvm_pmu_events *kvm_get_pmu_events(void);
+void kvm_set_pmu_events(u64 set, struct perf_event_attr *attr);
+void kvm_clr_pmu_events(u64 clr);
+bool kvm_set_pmuserenr(u64 val);
 void kvm_vcpu_pmu_restore_guest(struct kvm_vcpu *vcpu);
 void kvm_vcpu_pmu_restore_host(struct kvm_vcpu *vcpu);
 void kvm_vcpu_pmu_resync_el0(void);
@@ -161,6 +170,12 @@ static inline u64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmceid1)
 
 #define kvm_vcpu_has_pmu(vcpu)		({ false; })
 static inline void kvm_pmu_update_vcpu_events(struct kvm_vcpu *vcpu) {}
+static inline void kvm_set_pmu_events(u64 set, struct perf_event_attr *attr) {}
+static inline void kvm_clr_pmu_events(u64 clr) {}
+static inline bool kvm_set_pmuserenr(u64 val)
+{
+	return false;
+}
 static inline void kvm_vcpu_pmu_restore_guest(struct kvm_vcpu *vcpu) {}
 static inline void kvm_vcpu_pmu_restore_host(struct kvm_vcpu *vcpu) {}
 static inline void kvm_vcpu_reload_pmu(struct kvm_vcpu *vcpu) {}
diff --git a/drivers/perf/arm_pmuv3.c b/drivers/perf/arm_pmuv3.c
index 69c5cc8f56067..513122388b9da 100644
--- a/drivers/perf/arm_pmuv3.c
+++ b/drivers/perf/arm_pmuv3.c
@@ -9,6 +9,11 @@
  */
 
 #include <asm/irq_regs.h>
+
+#if defined(CONFIG_ARM64)
+#include <asm/kvm_pmu.h>
+#endif
+
 #include <asm/perf_event.h>
 #include <asm/virt.h>
 
-- 
2.52.0.239.gd5f0c6e74e-goog



From coltonlewis at google.com  Tue Dec  9 12:51:04 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Tue,  9 Dec 2025 20:51:04 +0000
Subject: [PATCH v5 07/24] perf: arm_pmuv3: Introduce method to partition the PMU
In-Reply-To: <20251209205121.1871534-1-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
Message-ID: <20251209205121.1871534-8-coltonlewis@google.com>

For PMUv3, the register field MDCR_EL2.HPMN partitiones the PMU
counters into two ranges where counters 0..HPMN-1 are accessible by
EL1 and, if allowed, EL0 while counters HPMN..N are only accessible by
EL2.

Create module parameter reserved_host_counters to reserve a number of
counters for the host. This number is set at boot because the perf
subsystem assumes the number of counters will not change after the PMU
is probed.

Introduce the function armv8pmu_partition() to modify the PMU driver's
cntr_mask of available counters to exclude the counters being reserved
for the guest and record reserved_guest_counters as the maximum
allowable value for HPMN.

Due to the difficulty this feature would create for the driver running
in nVHE mode, partitioning is only allowed in VHE mode. In order to
support a partitioning on nVHE we'd need to explicitly disable guest
counters on every exit and reset HPMN to place all counters in the
first range.

Signed-off-by: Colton Lewis <coltonlewis at google.com>
---
 arch/arm/include/asm/arm_pmuv3.h   |  4 ++
 arch/arm64/include/asm/arm_pmuv3.h |  5 ++
 arch/arm64/include/asm/kvm_pmu.h   |  8 +++
 arch/arm64/kvm/Makefile            |  2 +-
 arch/arm64/kvm/pmu-direct.c        | 22 +++++++++
 drivers/perf/arm_pmuv3.c           | 78 +++++++++++++++++++++++++++++-
 include/linux/perf/arm_pmu.h       |  1 +
 7 files changed, 117 insertions(+), 3 deletions(-)
 create mode 100644 arch/arm64/kvm/pmu-direct.c

diff --git a/arch/arm/include/asm/arm_pmuv3.h b/arch/arm/include/asm/arm_pmuv3.h
index 2ec0e5e83fc98..636b1aab9e8d2 100644
--- a/arch/arm/include/asm/arm_pmuv3.h
+++ b/arch/arm/include/asm/arm_pmuv3.h
@@ -221,6 +221,10 @@ static inline bool kvm_pmu_counter_deferred(struct perf_event_attr *attr)
 	return false;
 }
 
+static inline bool kvm_pmu_partition_supported(void)
+{
+	return false;
+}
 static inline bool kvm_set_pmuserenr(u64 val)
 {
 	return false;
diff --git a/arch/arm64/include/asm/arm_pmuv3.h b/arch/arm64/include/asm/arm_pmuv3.h
index cf2b2212e00a2..27c4d6d47da31 100644
--- a/arch/arm64/include/asm/arm_pmuv3.h
+++ b/arch/arm64/include/asm/arm_pmuv3.h
@@ -171,6 +171,11 @@ static inline bool pmuv3_implemented(int pmuver)
 		 pmuver == ID_AA64DFR0_EL1_PMUVer_NI);
 }
 
+static inline bool is_pmuv3p1(int pmuver)
+{
+	return pmuver >= ID_AA64DFR0_EL1_PMUVer_V3P1;
+}
+
 static inline bool is_pmuv3p4(int pmuver)
 {
 	return pmuver >= ID_AA64DFR0_EL1_PMUVer_V3P4;
diff --git a/arch/arm64/include/asm/kvm_pmu.h b/arch/arm64/include/asm/kvm_pmu.h
index 6c961e8778047..63bff75e4f8dd 100644
--- a/arch/arm64/include/asm/kvm_pmu.h
+++ b/arch/arm64/include/asm/kvm_pmu.h
@@ -45,7 +45,10 @@ struct arm_pmu_entry {
 	struct arm_pmu *arm_pmu;
 };
 
+extern int armv8pmu_hpmn_max;
+
 bool kvm_supports_guest_pmuv3(void);
+bool kvm_pmu_partition_supported(void);
 #define kvm_arm_pmu_irq_initialized(v)	((v)->arch.pmu.irq_num >= VGIC_NR_SGIS)
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
 void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu, u64 select_idx, u64 val);
@@ -115,6 +118,11 @@ static inline bool kvm_supports_guest_pmuv3(void)
 	return false;
 }
 
+static inline bool kvm_pmu_partition_supported(void)
+{
+	return false;
+}
+
 #define kvm_arm_pmu_irq_initialized(v)	(false)
 static inline u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu,
 					    u64 select_idx)
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index 3ebc0570345cc..baf0f296c0e53 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -26,7 +26,7 @@ kvm-y += arm.o mmu.o mmio.o psci.o hypercalls.o pvtime.o \
 	 vgic/vgic-its.o vgic/vgic-debug.o vgic/vgic-v3-nested.o \
 	 vgic/vgic-v5.o
 
-kvm-$(CONFIG_HW_PERF_EVENTS)  += pmu-emul.o pmu.o
+kvm-$(CONFIG_HW_PERF_EVENTS)  += pmu-emul.o pmu-direct.o pmu.o
 kvm-$(CONFIG_ARM64_PTR_AUTH)  += pauth.o
 kvm-$(CONFIG_PTDUMP_STAGE2_DEBUGFS) += ptdump.o
 
diff --git a/arch/arm64/kvm/pmu-direct.c b/arch/arm64/kvm/pmu-direct.c
new file mode 100644
index 0000000000000..0d38265b6f290
--- /dev/null
+++ b/arch/arm64/kvm/pmu-direct.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2025 Google LLC
+ * Author: Colton Lewis <coltonlewis at google.com>
+ */
+
+#include <linux/kvm_host.h>
+
+#include <asm/kvm_pmu.h>
+
+/**
+ * kvm_pmu_partition_supported() - Determine if partitioning is possible
+ *
+ * Partitioning is only supported in VHE mode with PMUv3
+ *
+ * Return: True if partitioning is possible, false otherwise
+ */
+bool kvm_pmu_partition_supported(void)
+{
+	return has_vhe() &&
+		system_supports_pmuv3();
+}
diff --git a/drivers/perf/arm_pmuv3.c b/drivers/perf/arm_pmuv3.c
index 513122388b9da..379d1877a61ba 100644
--- a/drivers/perf/arm_pmuv3.c
+++ b/drivers/perf/arm_pmuv3.c
@@ -42,6 +42,13 @@
 #define ARMV8_THUNDER_PERFCTR_L1I_CACHE_PREF_ACCESS		0xEC
 #define ARMV8_THUNDER_PERFCTR_L1I_CACHE_PREF_MISS		0xED
 
+static int reserved_host_counters __read_mostly = -1;
+int armv8pmu_hpmn_max = -1;
+
+module_param(reserved_host_counters, int, 0);
+MODULE_PARM_DESC(reserved_host_counters,
+		 "PMU Partition: -1 = No partition; +N = Reserve N counters for the host");
+
 /*
  * ARMv8 Architectural defined events, not all of these may
  * be supported on any given implementation. Unsupported events will
@@ -532,6 +539,11 @@ static void armv8pmu_pmcr_write(u64 val)
 	write_pmcr(val);
 }
 
+static u64 armv8pmu_pmcr_n_read(void)
+{
+	return FIELD_GET(ARMV8_PMU_PMCR_N, armv8pmu_pmcr_read());
+}
+
 static int armv8pmu_has_overflowed(u64 pmovsr)
 {
 	return !!(pmovsr & ARMV8_PMU_OVERFLOWED_MASK);
@@ -1299,6 +1311,61 @@ struct armv8pmu_probe_info {
 	bool present;
 };
 
+/**
+ * armv8pmu_reservation_is_valid() - Determine if reservation is allowed
+ * @host_counters: Number of host counters to reserve
+ *
+ * Determine if the number of host counters in the argument is an
+ * allowed reservation, 0 to NR_COUNTERS inclusive.
+ *
+ * Return: True if reservation allowed, false otherwise
+ */
+static bool armv8pmu_reservation_is_valid(int host_counters)
+{
+	return host_counters >= 0 &&
+		host_counters <= armv8pmu_pmcr_n_read();
+}
+
+/**
+ * armv8pmu_partition() - Partition the PMU
+ * @pmu: Pointer to pmu being partitioned
+ * @host_counters: Number of host counters to reserve
+ *
+ * Partition the given PMU by taking a number of host counters to
+ * reserve and, if it is a valid reservation, recording the
+ * corresponding HPMN value in the hpmn_max field of the PMU and
+ * clearing the guest-reserved counters from the counter mask.
+ *
+ * Return: 0 on success, -ERROR otherwise
+ */
+static int armv8pmu_partition(struct arm_pmu *pmu, int host_counters)
+{
+	u8 nr_counters;
+	u8 hpmn;
+
+	if (!armv8pmu_reservation_is_valid(host_counters)) {
+		pr_err("PMU partition reservation of %d host counters is not valid", host_counters);
+		return -EINVAL;
+	}
+
+	nr_counters = armv8pmu_pmcr_n_read();
+	hpmn = nr_counters - host_counters;
+
+	pmu->hpmn_max = hpmn;
+	armv8pmu_hpmn_max = hpmn;
+
+	bitmap_clear(pmu->cntr_mask, 0, hpmn);
+	bitmap_set(pmu->cntr_mask, hpmn, host_counters);
+	clear_bit(ARMV8_PMU_CYCLE_IDX, pmu->cntr_mask);
+
+	if (pmuv3_has_icntr())
+		clear_bit(ARMV8_PMU_INSTR_IDX, pmu->cntr_mask);
+
+	pr_info("Partitioned PMU with %d host counters -> %u guest counters", host_counters, hpmn);
+
+	return 0;
+}
+
 static void __armv8pmu_probe_pmu(void *info)
 {
 	struct armv8pmu_probe_info *probe = info;
@@ -1313,10 +1380,10 @@ static void __armv8pmu_probe_pmu(void *info)
 
 	cpu_pmu->pmuver = pmuver;
 	probe->present = true;
+	cpu_pmu->hpmn_max = -1;
 
 	/* Read the nb of CNTx counters supported from PMNC */
-	bitmap_set(cpu_pmu->cntr_mask,
-		   0, FIELD_GET(ARMV8_PMU_PMCR_N, armv8pmu_pmcr_read()));
+	bitmap_set(cpu_pmu->cntr_mask, 0, armv8pmu_pmcr_n_read());
 
 	/* Add the CPU cycles counter */
 	set_bit(ARMV8_PMU_CYCLE_IDX, cpu_pmu->cntr_mask);
@@ -1325,6 +1392,13 @@ static void __armv8pmu_probe_pmu(void *info)
 	if (pmuv3_has_icntr())
 		set_bit(ARMV8_PMU_INSTR_IDX, cpu_pmu->cntr_mask);
 
+	if (reserved_host_counters >= 0) {
+		if (kvm_pmu_partition_supported())
+			armv8pmu_partition(cpu_pmu, reserved_host_counters);
+		else
+			pr_err("PMU partition is not supported");
+	}
+
 	pmceid[0] = pmceid_raw[0] = read_pmceid0();
 	pmceid[1] = pmceid_raw[1] = read_pmceid1();
 
diff --git a/include/linux/perf/arm_pmu.h b/include/linux/perf/arm_pmu.h
index 93c9a26492fcf..69071e887f98f 100644
--- a/include/linux/perf/arm_pmu.h
+++ b/include/linux/perf/arm_pmu.h
@@ -128,6 +128,7 @@ struct arm_pmu {
 
 	/* Only to be used by ACPI probing code */
 	unsigned long acpi_cpuid;
+	int		hpmn_max; /* MDCR_EL2.HPMN: counter partition pivot */
 };
 
 #define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu))
-- 
2.52.0.239.gd5f0c6e74e-goog



From coltonlewis at google.com  Tue Dec  9 12:51:03 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Tue,  9 Dec 2025 20:51:03 +0000
Subject: [PATCH v5 06/24] KVM: arm64: Reorganize PMU functions
In-Reply-To: <20251209205121.1871534-1-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
Message-ID: <20251209205121.1871534-7-coltonlewis@google.com>

A lot of functions in pmu-emul.c aren't specific to the emulated PMU
implementation. Move them to the more appropriate pmu.c file where
shared PMU functions should live.

Signed-off-by: Colton Lewis <coltonlewis at google.com>
---
 arch/arm64/include/asm/kvm_pmu.h |   3 +
 arch/arm64/kvm/pmu-emul.c        | 672 +-----------------------------
 arch/arm64/kvm/pmu.c             | 675 +++++++++++++++++++++++++++++++
 3 files changed, 679 insertions(+), 671 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_pmu.h b/arch/arm64/include/asm/kvm_pmu.h
index ad3247b468388..6c961e8778047 100644
--- a/arch/arm64/include/asm/kvm_pmu.h
+++ b/arch/arm64/include/asm/kvm_pmu.h
@@ -51,13 +51,16 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
 void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu, u64 select_idx, u64 val);
 void kvm_pmu_set_counter_value_user(struct kvm_vcpu *vcpu, u64 select_idx, u64 val);
 u64 kvm_pmu_implemented_counter_mask(struct kvm_vcpu *vcpu);
+u64 kvm_pmu_hyp_counter_mask(struct kvm_vcpu *vcpu);
 u64 kvm_pmu_accessible_counter_mask(struct kvm_vcpu *vcpu);
+u32 kvm_pmu_event_mask(struct kvm *kvm);
 u64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmceid1);
 void kvm_pmu_vcpu_init(struct kvm_vcpu *vcpu);
 void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu);
 void kvm_pmu_reprogram_counter_mask(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu);
 void kvm_pmu_sync_hwstate(struct kvm_vcpu *vcpu);
+bool kvm_pmu_overflow_status(struct kvm_vcpu *vcpu);
 bool kvm_pmu_should_notify_user(struct kvm_vcpu *vcpu);
 void kvm_pmu_update_run(struct kvm_vcpu *vcpu);
 void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val);
diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c
index dcdd80ffd49d5..bcaa9f7a8ca28 100644
--- a/arch/arm64/kvm/pmu-emul.c
+++ b/arch/arm64/kvm/pmu-emul.c
@@ -17,19 +17,10 @@
 
 #define PERF_ATTR_CFG1_COUNTER_64BIT	BIT(0)
 
-static LIST_HEAD(arm_pmus);
-static DEFINE_MUTEX(arm_pmus_lock);
-
 static void kvm_pmu_create_perf_event(struct kvm_pmc *pmc);
 static void kvm_pmu_release_perf_event(struct kvm_pmc *pmc);
 static bool kvm_pmu_counter_is_enabled(struct kvm_pmc *pmc);
 
-bool kvm_supports_guest_pmuv3(void)
-{
-	guard(mutex)(&arm_pmus_lock);
-	return !list_empty(&arm_pmus);
-}
-
 static struct kvm_vcpu *kvm_pmc_to_vcpu(const struct kvm_pmc *pmc)
 {
 	return container_of(pmc, struct kvm_vcpu, arch.pmu.pmc[pmc->idx]);
@@ -40,46 +31,6 @@ static struct kvm_pmc *kvm_vcpu_idx_to_pmc(struct kvm_vcpu *vcpu, int cnt_idx)
 	return &vcpu->arch.pmu.pmc[cnt_idx];
 }
 
-static u32 __kvm_pmu_event_mask(unsigned int pmuver)
-{
-	switch (pmuver) {
-	case ID_AA64DFR0_EL1_PMUVer_IMP:
-		return GENMASK(9, 0);
-	case ID_AA64DFR0_EL1_PMUVer_V3P1:
-	case ID_AA64DFR0_EL1_PMUVer_V3P4:
-	case ID_AA64DFR0_EL1_PMUVer_V3P5:
-	case ID_AA64DFR0_EL1_PMUVer_V3P7:
-		return GENMASK(15, 0);
-	default:		/* Shouldn't be here, just for sanity */
-		WARN_ONCE(1, "Unknown PMU version %d\n", pmuver);
-		return 0;
-	}
-}
-
-static u32 kvm_pmu_event_mask(struct kvm *kvm)
-{
-	u64 dfr0 = kvm_read_vm_id_reg(kvm, SYS_ID_AA64DFR0_EL1);
-	u8 pmuver = SYS_FIELD_GET(ID_AA64DFR0_EL1, PMUVer, dfr0);
-
-	return __kvm_pmu_event_mask(pmuver);
-}
-
-u64 kvm_pmu_evtyper_mask(struct kvm *kvm)
-{
-	u64 mask = ARMV8_PMU_EXCLUDE_EL1 | ARMV8_PMU_EXCLUDE_EL0 |
-		   kvm_pmu_event_mask(kvm);
-
-	if (kvm_has_feat(kvm, ID_AA64PFR0_EL1, EL2, IMP))
-		mask |= ARMV8_PMU_INCLUDE_EL2;
-
-	if (kvm_has_feat(kvm, ID_AA64PFR0_EL1, EL3, IMP))
-		mask |= ARMV8_PMU_EXCLUDE_NS_EL0 |
-			ARMV8_PMU_EXCLUDE_NS_EL1 |
-			ARMV8_PMU_EXCLUDE_EL3;
-
-	return mask;
-}
-
 /**
  * kvm_pmc_is_64bit - determine if counter is 64bit
  * @pmc: counter context
@@ -272,59 +223,6 @@ void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu)
 	irq_work_sync(&vcpu->arch.pmu.overflow_work);
 }
 
-static u64 kvm_pmu_hyp_counter_mask(struct kvm_vcpu *vcpu)
-{
-	unsigned int hpmn, n;
-
-	if (!vcpu_has_nv(vcpu))
-		return 0;
-
-	hpmn = SYS_FIELD_GET(MDCR_EL2, HPMN, __vcpu_sys_reg(vcpu, MDCR_EL2));
-	n = vcpu->kvm->arch.nr_pmu_counters;
-
-	/*
-	 * Programming HPMN to a value greater than PMCR_EL0.N is
-	 * CONSTRAINED UNPREDICTABLE. Make the implementation choice that an
-	 * UNKNOWN number of counters (in our case, zero) are reserved for EL2.
-	 */
-	if (hpmn >= n)
-		return 0;
-
-	/*
-	 * Programming HPMN=0 is CONSTRAINED UNPREDICTABLE if FEAT_HPMN0 isn't
-	 * implemented. Since KVM's ability to emulate HPMN=0 does not directly
-	 * depend on hardware (all PMU registers are trapped), make the
-	 * implementation choice that all counters are included in the second
-	 * range reserved for EL2/EL3.
-	 */
-	return GENMASK(n - 1, hpmn);
-}
-
-bool kvm_pmu_counter_is_hyp(struct kvm_vcpu *vcpu, unsigned int idx)
-{
-	return kvm_pmu_hyp_counter_mask(vcpu) & BIT(idx);
-}
-
-u64 kvm_pmu_accessible_counter_mask(struct kvm_vcpu *vcpu)
-{
-	u64 mask = kvm_pmu_implemented_counter_mask(vcpu);
-
-	if (!vcpu_has_nv(vcpu) || vcpu_is_el2(vcpu))
-		return mask;
-
-	return mask & ~kvm_pmu_hyp_counter_mask(vcpu);
-}
-
-u64 kvm_pmu_implemented_counter_mask(struct kvm_vcpu *vcpu)
-{
-	u64 val = FIELD_GET(ARMV8_PMU_PMCR_N, kvm_vcpu_read_pmcr(vcpu));
-
-	if (val == 0)
-		return BIT(ARMV8_PMU_CYCLE_IDX);
-	else
-		return GENMASK(val - 1, 0) | BIT(ARMV8_PMU_CYCLE_IDX);
-}
-
 static void kvm_pmc_enable_perf_event(struct kvm_pmc *pmc)
 {
 	if (!pmc->perf_event) {
@@ -370,7 +268,7 @@ void kvm_pmu_reprogram_counter_mask(struct kvm_vcpu *vcpu, u64 val)
  * counter where the values of the global enable control, PMOVSSET_EL0[n], and
  * PMINTENSET_EL1[n] are all 1.
  */
-static bool kvm_pmu_overflow_status(struct kvm_vcpu *vcpu)
+bool kvm_pmu_overflow_status(struct kvm_vcpu *vcpu)
 {
 	u64 reg = __vcpu_sys_reg(vcpu, PMOVSSET_EL0);
 
@@ -393,24 +291,6 @@ static bool kvm_pmu_overflow_status(struct kvm_vcpu *vcpu)
 	return reg;
 }
 
-static void kvm_pmu_update_state(struct kvm_vcpu *vcpu)
-{
-	struct kvm_pmu *pmu = &vcpu->arch.pmu;
-	bool overflow;
-
-	overflow = kvm_pmu_overflow_status(vcpu);
-	if (pmu->irq_level == overflow)
-		return;
-
-	pmu->irq_level = overflow;
-
-	if (likely(irqchip_in_kernel(vcpu->kvm))) {
-		int ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu,
-					      pmu->irq_num, overflow, pmu);
-		WARN_ON(ret);
-	}
-}
-
 bool kvm_pmu_should_notify_user(struct kvm_vcpu *vcpu)
 {
 	struct kvm_pmu *pmu = &vcpu->arch.pmu;
@@ -436,43 +316,6 @@ void kvm_pmu_update_run(struct kvm_vcpu *vcpu)
 		regs->device_irq_level |= KVM_ARM_DEV_PMU;
 }
 
-/**
- * kvm_pmu_flush_hwstate - flush pmu state to cpu
- * @vcpu: The vcpu pointer
- *
- * Check if the PMU has overflowed while we were running in the host, and inject
- * an interrupt if that was the case.
- */
-void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu)
-{
-	kvm_pmu_update_state(vcpu);
-}
-
-/**
- * kvm_pmu_sync_hwstate - sync pmu state from cpu
- * @vcpu: The vcpu pointer
- *
- * Check if the PMU has overflowed while we were running in the guest, and
- * inject an interrupt if that was the case.
- */
-void kvm_pmu_sync_hwstate(struct kvm_vcpu *vcpu)
-{
-	kvm_pmu_update_state(vcpu);
-}
-
-/*
- * When perf interrupt is an NMI, we cannot safely notify the vcpu corresponding
- * to the event.
- * This is why we need a callback to do it once outside of the NMI context.
- */
-static void kvm_pmu_perf_overflow_notify_vcpu(struct irq_work *work)
-{
-	struct kvm_vcpu *vcpu;
-
-	vcpu = container_of(work, struct kvm_vcpu, arch.pmu.overflow_work);
-	kvm_vcpu_kick(vcpu);
-}
-
 /*
  * Perform an increment on any of the counters described in @mask,
  * generating the overflow if required, and propagate it as a chained
@@ -784,132 +627,6 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 	kvm_pmu_create_perf_event(pmc);
 }
 
-void kvm_host_pmu_init(struct arm_pmu *pmu)
-{
-	struct arm_pmu_entry *entry;
-
-	/*
-	 * Check the sanitised PMU version for the system, as KVM does not
-	 * support implementations where PMUv3 exists on a subset of CPUs.
-	 */
-	if (!pmuv3_implemented(kvm_arm_pmu_get_pmuver_limit()))
-		return;
-
-	guard(mutex)(&arm_pmus_lock);
-
-	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
-	if (!entry)
-		return;
-
-	entry->arm_pmu = pmu;
-	list_add_tail(&entry->entry, &arm_pmus);
-}
-
-static struct arm_pmu *kvm_pmu_probe_armpmu(void)
-{
-	struct arm_pmu_entry *entry;
-	struct arm_pmu *pmu;
-	int cpu;
-
-	guard(mutex)(&arm_pmus_lock);
-
-	/*
-	 * It is safe to use a stale cpu to iterate the list of PMUs so long as
-	 * the same value is used for the entirety of the loop. Given this, and
-	 * the fact that no percpu data is used for the lookup there is no need
-	 * to disable preemption.
-	 *
-	 * It is still necessary to get a valid cpu, though, to probe for the
-	 * default PMU instance as userspace is not required to specify a PMU
-	 * type. In order to uphold the preexisting behavior KVM selects the
-	 * PMU instance for the core during vcpu init. A dependent use
-	 * case would be a user with disdain of all things big.LITTLE that
-	 * affines the VMM to a particular cluster of cores.
-	 *
-	 * In any case, userspace should just do the sane thing and use the UAPI
-	 * to select a PMU type directly. But, be wary of the baggage being
-	 * carried here.
-	 */
-	cpu = raw_smp_processor_id();
-	list_for_each_entry(entry, &arm_pmus, entry) {
-		pmu = entry->arm_pmu;
-
-		if (cpumask_test_cpu(cpu, &pmu->supported_cpus))
-			return pmu;
-	}
-
-	return NULL;
-}
-
-static u64 __compute_pmceid(struct arm_pmu *pmu, bool pmceid1)
-{
-	u32 hi[2], lo[2];
-
-	bitmap_to_arr32(lo, pmu->pmceid_bitmap, ARMV8_PMUV3_MAX_COMMON_EVENTS);
-	bitmap_to_arr32(hi, pmu->pmceid_ext_bitmap, ARMV8_PMUV3_MAX_COMMON_EVENTS);
-
-	return ((u64)hi[pmceid1] << 32) | lo[pmceid1];
-}
-
-static u64 compute_pmceid0(struct arm_pmu *pmu)
-{
-	u64 val = __compute_pmceid(pmu, 0);
-
-	/* always support SW_INCR */
-	val |= BIT(ARMV8_PMUV3_PERFCTR_SW_INCR);
-	/* always support CHAIN */
-	val |= BIT(ARMV8_PMUV3_PERFCTR_CHAIN);
-	return val;
-}
-
-static u64 compute_pmceid1(struct arm_pmu *pmu)
-{
-	u64 val = __compute_pmceid(pmu, 1);
-
-	/*
-	 * Don't advertise STALL_SLOT*, as PMMIR_EL0 is handled
-	 * as RAZ
-	 */
-	val &= ~(BIT_ULL(ARMV8_PMUV3_PERFCTR_STALL_SLOT - 32) |
-		 BIT_ULL(ARMV8_PMUV3_PERFCTR_STALL_SLOT_FRONTEND - 32) |
-		 BIT_ULL(ARMV8_PMUV3_PERFCTR_STALL_SLOT_BACKEND - 32));
-	return val;
-}
-
-u64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmceid1)
-{
-	struct arm_pmu *cpu_pmu = vcpu->kvm->arch.arm_pmu;
-	unsigned long *bmap = vcpu->kvm->arch.pmu_filter;
-	u64 val, mask = 0;
-	int base, i, nr_events;
-
-	if (!pmceid1) {
-		val = compute_pmceid0(cpu_pmu);
-		base = 0;
-	} else {
-		val = compute_pmceid1(cpu_pmu);
-		base = 32;
-	}
-
-	if (!bmap)
-		return val;
-
-	nr_events = kvm_pmu_event_mask(vcpu->kvm) + 1;
-
-	for (i = 0; i < 32; i += 8) {
-		u64 byte;
-
-		byte = bitmap_get_value8(bmap, base + i);
-		mask |= byte << i;
-		if (nr_events >= (0x4000 + base + 32)) {
-			byte = bitmap_get_value8(bmap, 0x4000 + base + i);
-			mask |= byte << (32 + i);
-		}
-	}
-
-	return val & mask;
-}
-
 void kvm_vcpu_reload_pmu(struct kvm_vcpu *vcpu)
 {
 	u64 mask = kvm_pmu_implemented_counter_mask(vcpu);
@@ -921,393 +638,6 @@ void kvm_vcpu_reload_pmu(struct kvm_vcpu *vcpu)
 	kvm_pmu_reprogram_counter_mask(vcpu, mask);
 }
 
-int kvm_arm_pmu_v3_enable(struct kvm_vcpu *vcpu)
-{
-	if (!vcpu->arch.pmu.created)
-		return -EINVAL;
-
-	/*
-	 * A valid interrupt configuration for the PMU is either to have a
-	 * properly configured interrupt number and using an in-kernel
-	 * irqchip, or to not have an in-kernel GIC and not set an IRQ.
-	 */
-	if (irqchip_in_kernel(vcpu->kvm)) {
-		int irq = vcpu->arch.pmu.irq_num;
-		/*
-		 * If we are using an in-kernel vgic, at this point we know
-		 * the vgic will be initialized, so we can check the PMU irq
-		 * number against the dimensions of the vgic and make sure
-		 * it's valid.
-		 */
-		if (!irq_is_ppi(irq) && !vgic_valid_spi(vcpu->kvm, irq))
-			return -EINVAL;
-	} else if (kvm_arm_pmu_irq_initialized(vcpu)) {
-		   return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int kvm_arm_pmu_v3_init(struct kvm_vcpu *vcpu)
-{
-	if (irqchip_in_kernel(vcpu->kvm)) {
-		int ret;
-
-		/*
-		 * If using the PMU with an in-kernel virtual GIC
-		 * implementation, we require the GIC to be already
-		 * initialized when initializing the PMU.
-		 */
-		if (!vgic_initialized(vcpu->kvm))
-			return -ENODEV;
-
-		if (!kvm_arm_pmu_irq_initialized(vcpu))
-			return -ENXIO;
-
-		ret = kvm_vgic_set_owner(vcpu, vcpu->arch.pmu.irq_num,
-					 &vcpu->arch.pmu);
-		if (ret)
-			return ret;
-	}
-
-	init_irq_work(&vcpu->arch.pmu.overflow_work,
-		      kvm_pmu_perf_overflow_notify_vcpu);
-
-	vcpu->arch.pmu.created = true;
-	return 0;
-}
-
-/*
- * For one VM the interrupt type must be same for each vcpu.
- * As a PPI, the interrupt number is the same for all vcpus,
- * while as an SPI it must be a separate number per vcpu.
- */
-static bool pmu_irq_is_valid(struct kvm *kvm, int irq)
-{
-	unsigned long i;
-	struct kvm_vcpu *vcpu;
-
-	kvm_for_each_vcpu(i, vcpu, kvm) {
-		if (!kvm_arm_pmu_irq_initialized(vcpu))
-			continue;
-
-		if (irq_is_ppi(irq)) {
-			if (vcpu->arch.pmu.irq_num != irq)
-				return false;
-		} else {
-			if (vcpu->arch.pmu.irq_num == irq)
-				return false;
-		}
-	}
-
-	return true;
-}
-
-/**
- * kvm_arm_pmu_get_max_counters - Return the max number of PMU counters.
- * @kvm: The kvm pointer
- */
-u8 kvm_arm_pmu_get_max_counters(struct kvm *kvm)
-{
-	struct arm_pmu *arm_pmu = kvm->arch.arm_pmu;
-
-	/*
-	 * PMUv3 requires that all event counters are capable of counting any
-	 * event, though the same may not be true of non-PMUv3 hardware.
-	 */
-	if (cpus_have_final_cap(ARM64_WORKAROUND_PMUV3_IMPDEF_TRAPS))
-		return 1;
-
-	/*
-	 * The arm_pmu->cntr_mask considers the fixed counter(s) as well.
-	 * Ignore those and return only the general-purpose counters.
-	 */
-	return bitmap_weight(arm_pmu->cntr_mask, ARMV8_PMU_MAX_GENERAL_COUNTERS);
-}
-
-static void kvm_arm_set_nr_counters(struct kvm *kvm, unsigned int nr)
-{
-	kvm->arch.nr_pmu_counters = nr;
-
-	/* Reset MDCR_EL2.HPMN behind the vcpus' back... */
-	if (test_bit(KVM_ARM_VCPU_HAS_EL2, kvm->arch.vcpu_features)) {
-		struct kvm_vcpu *vcpu;
-		unsigned long i;
-
-		kvm_for_each_vcpu(i, vcpu, kvm) {
-			u64 val = __vcpu_sys_reg(vcpu, MDCR_EL2);
-			val &= ~MDCR_EL2_HPMN;
-			val |= FIELD_PREP(MDCR_EL2_HPMN, kvm->arch.nr_pmu_counters);
-			__vcpu_assign_sys_reg(vcpu, MDCR_EL2, val);
-		}
-	}
-}
-
-static void kvm_arm_set_pmu(struct kvm *kvm, struct arm_pmu *arm_pmu)
-{
-	lockdep_assert_held(&kvm->arch.config_lock);
-
-	kvm->arch.arm_pmu = arm_pmu;
-	kvm_arm_set_nr_counters(kvm, kvm_arm_pmu_get_max_counters(kvm));
-}
-
-/**
- * kvm_arm_set_default_pmu - No PMU set, get the default one.
- * @kvm: The kvm pointer
- *
- * The observant among you will notice that the supported_cpus
- * mask does not get updated for the default PMU even though it
- * is quite possible the selected instance supports only a
- * subset of cores in the system. This is intentional, and
- * upholds the preexisting behavior on heterogeneous systems
- * where vCPUs can be scheduled on any core but the guest
- * counters could stop working.
- */
-int kvm_arm_set_default_pmu(struct kvm *kvm)
-{
-	struct arm_pmu *arm_pmu = kvm_pmu_probe_armpmu();
-
-	if (!arm_pmu)
-		return -ENODEV;
-
-	kvm_arm_set_pmu(kvm, arm_pmu);
-	return 0;
-}
-
-static int kvm_arm_pmu_v3_set_pmu(struct kvm_vcpu *vcpu, int pmu_id)
-{
-	struct kvm *kvm = vcpu->kvm;
-	struct arm_pmu_entry *entry;
-	struct arm_pmu *arm_pmu;
-	int ret = -ENXIO;
-
-	lockdep_assert_held(&kvm->arch.config_lock);
-	mutex_lock(&arm_pmus_lock);
-
-	list_for_each_entry(entry, &arm_pmus, entry) {
-		arm_pmu = entry->arm_pmu;
-		if (arm_pmu->pmu.type == pmu_id) {
-			if (kvm_vm_has_ran_once(kvm) ||
-			    (kvm->arch.pmu_filter && kvm->arch.arm_pmu != arm_pmu)) {
-				ret = -EBUSY;
-				break;
-			}
-
-			kvm_arm_set_pmu(kvm, arm_pmu);
-			cpumask_copy(kvm->arch.supported_cpus, &arm_pmu->supported_cpus);
-			ret = 0;
-			break;
-		}
-	}
-
-	mutex_unlock(&arm_pmus_lock);
-	return ret;
-}
-
-static int kvm_arm_pmu_v3_set_nr_counters(struct kvm_vcpu *vcpu, unsigned int n)
-{
-	struct kvm *kvm = vcpu->kvm;
-
-	if (!kvm->arch.arm_pmu)
-		return -EINVAL;
-
-	if (n > kvm_arm_pmu_get_max_counters(kvm))
-		return -EINVAL;
-
-	kvm_arm_set_nr_counters(kvm, n);
-	return 0;
-}
-
-int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
-{
-	struct kvm *kvm = vcpu->kvm;
-
-	lockdep_assert_held(&kvm->arch.config_lock);
-
-	if (!kvm_vcpu_has_pmu(vcpu))
-		return -ENODEV;
-
-	if (vcpu->arch.pmu.created)
-		return -EBUSY;
-
-	switch (attr->attr) {
-	case KVM_ARM_VCPU_PMU_V3_IRQ: {
-		int __user *uaddr = (int __user *)(long)attr->addr;
-		int irq;
-
-		if (!irqchip_in_kernel(kvm))
-			return -EINVAL;
-
-		if (get_user(irq, uaddr))
-			return -EFAULT;
-
-		/* The PMU overflow interrupt can be a PPI or a valid SPI. */
-		if (!(irq_is_ppi(irq) || irq_is_spi(irq)))
-			return -EINVAL;
-
-		if (!pmu_irq_is_valid(kvm, irq))
-			return -EINVAL;
-
-		if (kvm_arm_pmu_irq_initialized(vcpu))
-			return -EBUSY;
-
-		kvm_debug("Set kvm ARM PMU irq: %d\n", irq);
-		vcpu->arch.pmu.irq_num = irq;
-		return 0;
-	}
-	case KVM_ARM_VCPU_PMU_V3_FILTER: {
-		u8 pmuver = kvm_arm_pmu_get_pmuver_limit();
-		struct kvm_pmu_event_filter __user *uaddr;
-		struct kvm_pmu_event_filter filter;
-		int nr_events;
-
-		/*
-		 * Allow userspace to specify an event filter for the entire
-		 * event range supported by PMUVer of the hardware, rather
-		 * than the guest's PMUVer for KVM backward compatibility.
-		 */
-		nr_events = __kvm_pmu_event_mask(pmuver) + 1;
-
-		uaddr = (struct kvm_pmu_event_filter __user *)(long)attr->addr;
-
-		if (copy_from_user(&filter, uaddr, sizeof(filter)))
-			return -EFAULT;
-
-		if (((u32)filter.base_event + filter.nevents) > nr_events ||
-		    (filter.action != KVM_PMU_EVENT_ALLOW &&
-		     filter.action != KVM_PMU_EVENT_DENY))
-			return -EINVAL;
-
-		if (kvm_vm_has_ran_once(kvm))
-			return -EBUSY;
-
-		if (!kvm->arch.pmu_filter) {
-			kvm->arch.pmu_filter = bitmap_alloc(nr_events, GFP_KERNEL_ACCOUNT);
-			if (!kvm->arch.pmu_filter)
-				return -ENOMEM;
-
-			/*
-			 * The default depends on the first applied filter.
-			 * If it allows events, the default is to deny.
-			 * Conversely, if the first filter denies a set of
-			 * events, the default is to allow.
-			 */
-			if (filter.action == KVM_PMU_EVENT_ALLOW)
-				bitmap_zero(kvm->arch.pmu_filter, nr_events);
-			else
-				bitmap_fill(kvm->arch.pmu_filter, nr_events);
-		}
-
-		if (filter.action == KVM_PMU_EVENT_ALLOW)
-			bitmap_set(kvm->arch.pmu_filter, filter.base_event, filter.nevents);
-		else
-			bitmap_clear(kvm->arch.pmu_filter, filter.base_event, filter.nevents);
-
-		return 0;
-	}
-	case KVM_ARM_VCPU_PMU_V3_SET_PMU: {
-		int __user *uaddr = (int __user *)(long)attr->addr;
-		int pmu_id;
-
-		if (get_user(pmu_id, uaddr))
-			return -EFAULT;
-
-		return kvm_arm_pmu_v3_set_pmu(vcpu, pmu_id);
-	}
-	case KVM_ARM_VCPU_PMU_V3_SET_NR_COUNTERS: {
-		unsigned int __user *uaddr = (unsigned int __user *)(long)attr->addr;
-		unsigned int n;
-
-		if (get_user(n, uaddr))
-			return -EFAULT;
-
-		return kvm_arm_pmu_v3_set_nr_counters(vcpu, n);
-	}
-	case KVM_ARM_VCPU_PMU_V3_INIT:
-		return kvm_arm_pmu_v3_init(vcpu);
-	}
-
-	return -ENXIO;
-}
-
-int kvm_arm_pmu_v3_get_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
-{
-	switch (attr->attr) {
-	case KVM_ARM_VCPU_PMU_V3_IRQ: {
-		int __user *uaddr = (int __user *)(long)attr->addr;
-		int irq;
-
-		if (!irqchip_in_kernel(vcpu->kvm))
-			return -EINVAL;
-
-		if (!kvm_vcpu_has_pmu(vcpu))
-			return -ENODEV;
-
-		if (!kvm_arm_pmu_irq_initialized(vcpu))
-			return -ENXIO;
-
-		irq = vcpu->arch.pmu.irq_num;
-		return put_user(irq, uaddr);
-	}
-	}
-
-	return -ENXIO;
-}
-
-int kvm_arm_pmu_v3_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
-{
-	switch (attr->attr) {
-	case KVM_ARM_VCPU_PMU_V3_IRQ:
-	case KVM_ARM_VCPU_PMU_V3_INIT:
-	case KVM_ARM_VCPU_PMU_V3_FILTER:
-	case KVM_ARM_VCPU_PMU_V3_SET_PMU:
-	case KVM_ARM_VCPU_PMU_V3_SET_NR_COUNTERS:
-		if (kvm_vcpu_has_pmu(vcpu))
-			return 0;
-	}
-
-	return -ENXIO;
-}
-
-u8 kvm_arm_pmu_get_pmuver_limit(void)
-{
-	unsigned int pmuver;
-
-	pmuver = SYS_FIELD_GET(ID_AA64DFR0_EL1, PMUVer,
-			       read_sanitised_ftr_reg(SYS_ID_AA64DFR0_EL1));
-
-	/*
-	 * Spoof a barebones PMUv3 implementation if the system supports IMPDEF
-	 * traps of the PMUv3 sysregs
-	 */
-	if (cpus_have_final_cap(ARM64_WORKAROUND_PMUV3_IMPDEF_TRAPS))
-		return ID_AA64DFR0_EL1_PMUVer_IMP;
-
-	/*
-	 * Otherwise, treat IMPLEMENTATION DEFINED functionality as
-	 * unimplemented
-	 */
-	if (pmuver == ID_AA64DFR0_EL1_PMUVer_IMP_DEF)
-		return 0;
-
-	return min(pmuver, ID_AA64DFR0_EL1_PMUVer_V3P5);
-}
-
-/**
- * kvm_vcpu_read_pmcr - Read PMCR_EL0 register for the vCPU
- * @vcpu: The vcpu pointer
- */
-u64 kvm_vcpu_read_pmcr(struct kvm_vcpu *vcpu)
-{
-	u64 pmcr = __vcpu_sys_reg(vcpu, PMCR_EL0);
-	u64 n = vcpu->kvm->arch.nr_pmu_counters;
-
-	if (vcpu_has_nv(vcpu) && !vcpu_is_el2(vcpu))
-		n = FIELD_GET(MDCR_EL2_HPMN, __vcpu_sys_reg(vcpu, MDCR_EL2));
-
-	return u64_replace_bits(pmcr, n, ARMV8_PMU_PMCR_N);
-}
-
 void kvm_pmu_nested_transition(struct kvm_vcpu *vcpu)
 {
 	bool reprogrammed = false;
diff --git a/arch/arm64/kvm/pmu.c b/arch/arm64/kvm/pmu.c
index 6b48a3d16d0d5..79b7ea037153a 100644
--- a/arch/arm64/kvm/pmu.c
+++ b/arch/arm64/kvm/pmu.c
@@ -8,8 +8,21 @@
 #include <linux/perf/arm_pmu.h>
 #include <linux/perf/arm_pmuv3.h>
 
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_pmu.h>
+
+static LIST_HEAD(arm_pmus);
+static DEFINE_MUTEX(arm_pmus_lock);
 static DEFINE_PER_CPU(struct kvm_pmu_events, kvm_pmu_events);
 
+#define kvm_arm_pmu_irq_initialized(v)	((v)->arch.pmu.irq_num >= VGIC_NR_SGIS)
+
+bool kvm_supports_guest_pmuv3(void)
+{
+	guard(mutex)(&arm_pmus_lock);
+	return !list_empty(&arm_pmus);
+}
+
 /*
  * Given the perf event attributes and system type, determine
  * if we are going to need to switch counters at guest entry/exit.
@@ -209,3 +222,665 @@ void kvm_vcpu_pmu_resync_el0(void)
 
 	kvm_make_request(KVM_REQ_RESYNC_PMU_EL0, vcpu);
 }
+
+void kvm_host_pmu_init(struct arm_pmu *pmu)
+{
+	struct arm_pmu_entry *entry;
+
+	/*
+	 * Check the sanitised PMU version for the system, as KVM does not
+	 * support implementations where PMUv3 exists on a subset of CPUs.
+	 */
+	if (!pmuv3_implemented(kvm_arm_pmu_get_pmuver_limit()))
+		return;
+
+	guard(mutex)(&arm_pmus_lock);
+
+	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry)
+		return;
+
+	entry->arm_pmu = pmu;
+	list_add_tail(&entry->entry, &arm_pmus);
+}
+
+static struct arm_pmu *kvm_pmu_probe_armpmu(void)
+{
+	struct arm_pmu_entry *entry;
+	struct arm_pmu *pmu;
+	int cpu;
+
+	guard(mutex)(&arm_pmus_lock);
+
+	/*
+	 * It is safe to use a stale cpu to iterate the list of PMUs so long as
+	 * the same value is used for the entirety of the loop. Given this, and
+	 * the fact that no percpu data is used for the lookup there is no need
+	 * to disable preemption.
+	 *
+	 * It is still necessary to get a valid cpu, though, to probe for the
+	 * default PMU instance as userspace is not required to specify a PMU
+	 * type. In order to uphold the preexisting behavior KVM selects the
+	 * PMU instance for the core during vcpu init. A dependent use
+	 * case would be a user with disdain of all things big.LITTLE that
+	 * affines the VMM to a particular cluster of cores.
+	 *
+	 * In any case, userspace should just do the sane thing and use the UAPI
+	 * to select a PMU type directly. But, be wary of the baggage being
+	 * carried here.
+	 */
+	cpu = raw_smp_processor_id();
+	list_for_each_entry(entry, &arm_pmus, entry) {
+		pmu = entry->arm_pmu;
+
+		if (cpumask_test_cpu(cpu, &pmu->supported_cpus))
+			return pmu;
+	}
+
+	return NULL;
+}
+
+static u64 __compute_pmceid(struct arm_pmu *pmu, bool pmceid1)
+{
+	u32 hi[2], lo[2];
+
+	bitmap_to_arr32(lo, pmu->pmceid_bitmap, ARMV8_PMUV3_MAX_COMMON_EVENTS);
+	bitmap_to_arr32(hi, pmu->pmceid_ext_bitmap, ARMV8_PMUV3_MAX_COMMON_EVENTS);
+
+	return ((u64)hi[pmceid1] << 32) | lo[pmceid1];
+}
+
+static u64 compute_pmceid0(struct arm_pmu *pmu)
+{
+	u64 val = __compute_pmceid(pmu, 0);
+
+	/* always support SW_INCR */
+	val |= BIT(ARMV8_PMUV3_PERFCTR_SW_INCR);
+	/* always support CHAIN */
+	val |= BIT(ARMV8_PMUV3_PERFCTR_CHAIN);
+	return val;
+}
+
+static u64 compute_pmceid1(struct arm_pmu *pmu)
+{
+	u64 val = __compute_pmceid(pmu, 1);
+
+	/*
+	 * Don't advertise STALL_SLOT*, as PMMIR_EL0 is handled
+	 * as RAZ
+	 */
+	val &= ~(BIT_ULL(ARMV8_PMUV3_PERFCTR_STALL_SLOT - 32) |
+		 BIT_ULL(ARMV8_PMUV3_PERFCTR_STALL_SLOT_FRONTEND - 32) |
+		 BIT_ULL(ARMV8_PMUV3_PERFCTR_STALL_SLOT_BACKEND - 32));
+	return val;
+}
+
+u64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmceid1)
+{
+	struct arm_pmu *cpu_pmu = vcpu->kvm->arch.arm_pmu;
+	unsigned long *bmap = vcpu->kvm->arch.pmu_filter;
+	u64 val, mask = 0;
+	int base, i, nr_events;
+
+	if (!pmceid1) {
+		val = compute_pmceid0(cpu_pmu);
+		base = 0;
+	} else {
+		val = compute_pmceid1(cpu_pmu);
+		base = 32;
+	}
+
+	if (!bmap)
+		return val;
+
+	nr_events = kvm_pmu_event_mask(vcpu->kvm) + 1;
+
+	for (i = 0; i < 32; i += 8) {
+		u64 byte;
+
+		byte = bitmap_get_value8(bmap, base + i);
+		mask |= byte << i;
+		if (nr_events >= (0x4000 + base + 32)) {
+			byte = bitmap_get_value8(bmap, 0x4000 + base + i);
+			mask |= byte << (32 + i);
+		}
+	}
+
+	return val & mask;
+}
+
+/*
+ * When perf interrupt is an NMI, we cannot safely notify the vcpu corresponding
+ * to the event.
+ * This is why we need a callback to do it once outside of the NMI context.
+ */
+static void kvm_pmu_perf_overflow_notify_vcpu(struct irq_work *work)
+{
+	struct kvm_vcpu *vcpu;
+
+	vcpu = container_of(work, struct kvm_vcpu, arch.pmu.overflow_work);
+	kvm_vcpu_kick(vcpu);
+}
+
+static u32 __kvm_pmu_event_mask(unsigned int pmuver)
+{
+	switch (pmuver) {
+	case ID_AA64DFR0_EL1_PMUVer_IMP:
+		return GENMASK(9, 0);
+	case ID_AA64DFR0_EL1_PMUVer_V3P1:
+	case ID_AA64DFR0_EL1_PMUVer_V3P4:
+	case ID_AA64DFR0_EL1_PMUVer_V3P5:
+	case ID_AA64DFR0_EL1_PMUVer_V3P7:
+		return GENMASK(15, 0);
+	default:		/* Shouldn't be here, just for sanity */
+		WARN_ONCE(1, "Unknown PMU version %d\n", pmuver);
+		return 0;
+	}
+}
+
+u32 kvm_pmu_event_mask(struct kvm *kvm)
+{
+	u64 dfr0 = kvm_read_vm_id_reg(kvm, SYS_ID_AA64DFR0_EL1);
+	u8 pmuver = SYS_FIELD_GET(ID_AA64DFR0_EL1, PMUVer, dfr0);
+
+	return __kvm_pmu_event_mask(pmuver);
+}
+
+u64 kvm_pmu_evtyper_mask(struct kvm *kvm)
+{
+	u64 mask = ARMV8_PMU_EXCLUDE_EL1 | ARMV8_PMU_EXCLUDE_EL0 |
+		   kvm_pmu_event_mask(kvm);
+
+	if (kvm_has_feat(kvm, ID_AA64PFR0_EL1, EL2, IMP))
+		mask |= ARMV8_PMU_INCLUDE_EL2;
+
+	if (kvm_has_feat(kvm, ID_AA64PFR0_EL1, EL3, IMP))
+		mask |= ARMV8_PMU_EXCLUDE_NS_EL0 |
+			ARMV8_PMU_EXCLUDE_NS_EL1 |
+			ARMV8_PMU_EXCLUDE_EL3;
+
+	return mask;
+}
+
+static void kvm_pmu_update_state(struct kvm_vcpu *vcpu)
+{
+	struct kvm_pmu *pmu = &vcpu->arch.pmu;
+	bool overflow;
+
+	overflow = kvm_pmu_overflow_status(vcpu);
+	if (pmu->irq_level == overflow)
+		return;
+
+	pmu->irq_level = overflow;
+
+	if (likely(irqchip_in_kernel(vcpu->kvm))) {
+		int ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu,
+					      pmu->irq_num, overflow, pmu);
+		WARN_ON(ret);
+	}
+}
+
+/**
+ * kvm_pmu_flush_hwstate - flush pmu state to cpu
+ * @vcpu: The vcpu pointer
+ *
+ * Check if the PMU has overflowed while we were running in the host, and inject
+ * an interrupt if that was the case.
+ */
+void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu)
+{
+	kvm_pmu_update_state(vcpu);
+}
+
+/**
+ * kvm_pmu_sync_hwstate - sync pmu state from cpu
+ * @vcpu: The vcpu pointer
+ *
+ * Check if the PMU has overflowed while we were running in the guest, and
+ * inject an interrupt if that was the case.
+ */
+void kvm_pmu_sync_hwstate(struct kvm_vcpu *vcpu)
+{
+	kvm_pmu_update_state(vcpu);
+}
+
+int kvm_arm_pmu_v3_enable(struct kvm_vcpu *vcpu)
+{
+	if (!vcpu->arch.pmu.created)
+		return -EINVAL;
+
+	/*
+	 * A valid interrupt configuration for the PMU is either to have a
+	 * properly configured interrupt number and using an in-kernel
+	 * irqchip, or to not have an in-kernel GIC and not set an IRQ.
+	 */
+	if (irqchip_in_kernel(vcpu->kvm)) {
+		int irq = vcpu->arch.pmu.irq_num;
+		/*
+		 * If we are using an in-kernel vgic, at this point we know
+		 * the vgic will be initialized, so we can check the PMU irq
+		 * number against the dimensions of the vgic and make sure
+		 * it's valid.
+		 */
+		if (!irq_is_ppi(irq) && !vgic_valid_spi(vcpu->kvm, irq))
+			return -EINVAL;
+	} else if (kvm_arm_pmu_irq_initialized(vcpu)) {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int kvm_arm_pmu_v3_init(struct kvm_vcpu *vcpu)
+{
+	if (irqchip_in_kernel(vcpu->kvm)) {
+		int ret;
+
+		/*
+		 * If using the PMU with an in-kernel virtual GIC
+		 * implementation, we require the GIC to be already
+		 * initialized when initializing the PMU.
+		 */
+		if (!vgic_initialized(vcpu->kvm))
+			return -ENODEV;
+
+		if (!kvm_arm_pmu_irq_initialized(vcpu))
+			return -ENXIO;
+
+		ret = kvm_vgic_set_owner(vcpu, vcpu->arch.pmu.irq_num,
+					 &vcpu->arch.pmu);
+		if (ret)
+			return ret;
+	}
+
+	init_irq_work(&vcpu->arch.pmu.overflow_work,
+		      kvm_pmu_perf_overflow_notify_vcpu);
+
+	vcpu->arch.pmu.created = true;
+	return 0;
+}
+
+/*
+ * For one VM the interrupt type must be same for each vcpu.
+ * As a PPI, the interrupt number is the same for all vcpus,
+ * while as an SPI it must be a separate number per vcpu.
+ */
+static bool pmu_irq_is_valid(struct kvm *kvm, int irq)
+{
+	unsigned long i;
+	struct kvm_vcpu *vcpu;
+
+	kvm_for_each_vcpu(i, vcpu, kvm) {
+		if (!kvm_arm_pmu_irq_initialized(vcpu))
+			continue;
+
+		if (irq_is_ppi(irq)) {
+			if (vcpu->arch.pmu.irq_num != irq)
+				return false;
+		} else {
+			if (vcpu->arch.pmu.irq_num == irq)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/**
+ * kvm_arm_pmu_get_max_counters - Return the max number of PMU counters.
+ * @kvm: The kvm pointer
+ */
+u8 kvm_arm_pmu_get_max_counters(struct kvm *kvm)
+{
+	struct arm_pmu *arm_pmu = kvm->arch.arm_pmu;
+
+	/*
+	 * PMUv3 requires that all event counters are capable of counting any
+	 * event, though the same may not be true of non-PMUv3 hardware.
+	 */
+	if (cpus_have_final_cap(ARM64_WORKAROUND_PMUV3_IMPDEF_TRAPS))
+		return 1;
+
+	/*
+	 * The arm_pmu->cntr_mask considers the fixed counter(s) as well.
+	 * Ignore those and return only the general-purpose counters.
+	 */
+	return bitmap_weight(arm_pmu->cntr_mask, ARMV8_PMU_MAX_GENERAL_COUNTERS);
+}
+
+static void kvm_arm_set_nr_counters(struct kvm *kvm, unsigned int nr)
+{
+	kvm->arch.nr_pmu_counters = nr;
+
+	/* Reset MDCR_EL2.HPMN behind the vcpus' back... */
+	if (test_bit(KVM_ARM_VCPU_HAS_EL2, kvm->arch.vcpu_features)) {
+		struct kvm_vcpu *vcpu;
+		unsigned long i;
+
+		kvm_for_each_vcpu(i, vcpu, kvm) {
+			u64 val = __vcpu_sys_reg(vcpu, MDCR_EL2);
+
+			val &= ~MDCR_EL2_HPMN;
+			val |= FIELD_PREP(MDCR_EL2_HPMN, kvm->arch.nr_pmu_counters);
+			__vcpu_assign_sys_reg(vcpu, MDCR_EL2, val);
+		}
+	}
+}
+
+static void kvm_arm_set_pmu(struct kvm *kvm, struct arm_pmu *arm_pmu)
+{
+	lockdep_assert_held(&kvm->arch.config_lock);
+
+	kvm->arch.arm_pmu = arm_pmu;
+	kvm_arm_set_nr_counters(kvm, kvm_arm_pmu_get_max_counters(kvm));
+}
+
+/**
+ * kvm_arm_set_default_pmu - No PMU set, get the default one.
+ * @kvm: The kvm pointer
+ *
+ * The observant among you will notice that the supported_cpus
+ * mask does not get updated for the default PMU even though it
+ * is quite possible the selected instance supports only a
+ * subset of cores in the system. This is intentional, and
+ * upholds the preexisting behavior on heterogeneous systems
+ * where vCPUs can be scheduled on any core but the guest
+ * counters could stop working.
+ */
+int kvm_arm_set_default_pmu(struct kvm *kvm)
+{
+	struct arm_pmu *arm_pmu = kvm_pmu_probe_armpmu();
+
+	if (!arm_pmu)
+		return -ENODEV;
+
+	kvm_arm_set_pmu(kvm, arm_pmu);
+	return 0;
+}
+
+static int kvm_arm_pmu_v3_set_pmu(struct kvm_vcpu *vcpu, int pmu_id)
+{
+	struct kvm *kvm = vcpu->kvm;
+	struct arm_pmu_entry *entry;
+	struct arm_pmu *arm_pmu;
+	int ret = -ENXIO;
+
+	lockdep_assert_held(&kvm->arch.config_lock);
+	mutex_lock(&arm_pmus_lock);
+
+	list_for_each_entry(entry, &arm_pmus, entry) {
+		arm_pmu = entry->arm_pmu;
+		if (arm_pmu->pmu.type == pmu_id) {
+			if (kvm_vm_has_ran_once(kvm) ||
+			    (kvm->arch.pmu_filter && kvm->arch.arm_pmu != arm_pmu)) {
+				ret = -EBUSY;
+				break;
+			}
+
+			kvm_arm_set_pmu(kvm, arm_pmu);
+			cpumask_copy(kvm->arch.supported_cpus, &arm_pmu->supported_cpus);
+			ret = 0;
+			break;
+		}
+	}
+
+	mutex_unlock(&arm_pmus_lock);
+	return ret;
+}
+
+static int kvm_arm_pmu_v3_set_nr_counters(struct kvm_vcpu *vcpu, unsigned int n)
+{
+	struct kvm *kvm = vcpu->kvm;
+
+	if (!kvm->arch.arm_pmu)
+		return -EINVAL;
+
+	if (n > kvm_arm_pmu_get_max_counters(kvm))
+		return -EINVAL;
+
+	kvm_arm_set_nr_counters(kvm, n);
+	return 0;
+}
+
+int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
+{
+	struct kvm *kvm = vcpu->kvm;
+
+	lockdep_assert_held(&kvm->arch.config_lock);
+
+	if (!kvm_vcpu_has_pmu(vcpu))
+		return -ENODEV;
+
+	if (vcpu->arch.pmu.created)
+		return -EBUSY;
+
+	switch (attr->attr) {
+	case KVM_ARM_VCPU_PMU_V3_IRQ: {
+		int __user *uaddr = (int __user *)(long)attr->addr;
+		int irq;
+
+		if (!irqchip_in_kernel(kvm))
+			return -EINVAL;
+
+		if (get_user(irq, uaddr))
+			return -EFAULT;
+
+		/* The PMU overflow interrupt can be a PPI or a valid SPI. */
+		if (!(irq_is_ppi(irq) || irq_is_spi(irq)))
+			return -EINVAL;
+
+		if (!pmu_irq_is_valid(kvm, irq))
+			return -EINVAL;
+
+		if (kvm_arm_pmu_irq_initialized(vcpu))
+			return -EBUSY;
+
+		kvm_debug("Set kvm ARM PMU irq: %d\n", irq);
+		vcpu->arch.pmu.irq_num = irq;
+		return 0;
+	}
+	case KVM_ARM_VCPU_PMU_V3_FILTER: {
+		u8 pmuver = kvm_arm_pmu_get_pmuver_limit();
+		struct kvm_pmu_event_filter __user *uaddr;
+		struct kvm_pmu_event_filter filter;
+		int nr_events;
+
+		/*
+		 * Allow userspace to specify an event filter for the entire
+		 * event range supported by PMUVer of the hardware, rather
+		 * than the guest's PMUVer for KVM backward compatibility.
+		 */
+		nr_events = __kvm_pmu_event_mask(pmuver) + 1;
+
+		uaddr = (struct kvm_pmu_event_filter __user *)(long)attr->addr;
+
+		if (copy_from_user(&filter, uaddr, sizeof(filter)))
+			return -EFAULT;
+
+		if (((u32)filter.base_event + filter.nevents) > nr_events ||
+		    (filter.action != KVM_PMU_EVENT_ALLOW &&
+		     filter.action != KVM_PMU_EVENT_DENY))
+			return -EINVAL;
+
+		if (kvm_vm_has_ran_once(kvm))
+			return -EBUSY;
+
+		if (!kvm->arch.pmu_filter) {
+			kvm->arch.pmu_filter = bitmap_alloc(nr_events, GFP_KERNEL_ACCOUNT);
+			if (!kvm->arch.pmu_filter)
+				return -ENOMEM;
+
+			/*
+			 * The default depends on the first applied filter.
+			 * If it allows events, the default is to deny.
+			 * Conversely, if the first filter denies a set of
+			 * events, the default is to allow.
+			 */
+			if (filter.action == KVM_PMU_EVENT_ALLOW)
+				bitmap_zero(kvm->arch.pmu_filter, nr_events);
+			else
+				bitmap_fill(kvm->arch.pmu_filter, nr_events);
+		}
+
+		if (filter.action == KVM_PMU_EVENT_ALLOW)
+			bitmap_set(kvm->arch.pmu_filter, filter.base_event, filter.nevents);
+		else
+			bitmap_clear(kvm->arch.pmu_filter, filter.base_event, filter.nevents);
+
+		return 0;
+	}
+	case KVM_ARM_VCPU_PMU_V3_SET_PMU: {
+		int __user *uaddr = (int __user *)(long)attr->addr;
+		int pmu_id;
+
+		if (get_user(pmu_id, uaddr))
+			return -EFAULT;
+
+		return kvm_arm_pmu_v3_set_pmu(vcpu, pmu_id);
+	}
+	case KVM_ARM_VCPU_PMU_V3_SET_NR_COUNTERS: {
+		unsigned int __user *uaddr = (unsigned int __user *)(long)attr->addr;
+		unsigned int n;
+
+		if (get_user(n, uaddr))
+			return -EFAULT;
+
+		return kvm_arm_pmu_v3_set_nr_counters(vcpu, n);
+	}
+	case KVM_ARM_VCPU_PMU_V3_INIT:
+		return kvm_arm_pmu_v3_init(vcpu);
+	}
+
+	return -ENXIO;
+}
+
+int kvm_arm_pmu_v3_get_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
+{
+	switch (attr->attr) {
+	case KVM_ARM_VCPU_PMU_V3_IRQ: {
+		int __user *uaddr = (int __user *)(long)attr->addr;
+		int irq;
+
+		if (!irqchip_in_kernel(vcpu->kvm))
+			return -EINVAL;
+
+		if (!kvm_vcpu_has_pmu(vcpu))
+			return -ENODEV;
+
+		if (!kvm_arm_pmu_irq_initialized(vcpu))
+			return -ENXIO;
+
+		irq = vcpu->arch.pmu.irq_num;
+		return put_user(irq, uaddr);
+	}
+	}
+
+	return -ENXIO;
+}
+
+int kvm_arm_pmu_v3_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
+{
+	switch (attr->attr) {
+	case KVM_ARM_VCPU_PMU_V3_IRQ:
+	case KVM_ARM_VCPU_PMU_V3_INIT:
+	case KVM_ARM_VCPU_PMU_V3_FILTER:
+	case KVM_ARM_VCPU_PMU_V3_SET_PMU:
+	case KVM_ARM_VCPU_PMU_V3_SET_NR_COUNTERS:
+		if (kvm_vcpu_has_pmu(vcpu))
+			return 0;
+	}
+
+	return -ENXIO;
+}
+
+u8 kvm_arm_pmu_get_pmuver_limit(void)
+{
+	unsigned int pmuver;
+
+	pmuver = SYS_FIELD_GET(ID_AA64DFR0_EL1, PMUVer,
+			       read_sanitised_ftr_reg(SYS_ID_AA64DFR0_EL1));
+
+	/*
+	 * Spoof a barebones PMUv3 implementation if the system supports IMPDEF
+	 * traps of the PMUv3 sysregs
+	 */
+	if (cpus_have_final_cap(ARM64_WORKAROUND_PMUV3_IMPDEF_TRAPS))
+		return ID_AA64DFR0_EL1_PMUVer_IMP;
+
+	/*
+	 * Otherwise, treat IMPLEMENTATION DEFINED functionality as
+	 * unimplemented
+	 */
+	if (pmuver == ID_AA64DFR0_EL1_PMUVer_IMP_DEF)
+		return 0;
+
+	return min(pmuver, ID_AA64DFR0_EL1_PMUVer_V3P5);
+}
+
+u64 kvm_pmu_implemented_counter_mask(struct kvm_vcpu *vcpu)
+{
+	u64 val = FIELD_GET(ARMV8_PMU_PMCR_N, kvm_vcpu_read_pmcr(vcpu));
+
+	if (val == 0)
+		return BIT(ARMV8_PMU_CYCLE_IDX);
+	else
+		return GENMASK(val - 1, 0) | BIT(ARMV8_PMU_CYCLE_IDX);
+}
+
+u64 kvm_pmu_hyp_counter_mask(struct kvm_vcpu *vcpu)
+{
+	unsigned int hpmn, n;
+
+	if (!vcpu_has_nv(vcpu))
+		return 0;
+
+	hpmn = SYS_FIELD_GET(MDCR_EL2, HPMN, __vcpu_sys_reg(vcpu, MDCR_EL2));
+	n = vcpu->kvm->arch.nr_pmu_counters;
+
+	/*
+	 * Programming HPMN to a value greater than PMCR_EL0.N is
+	 * CONSTRAINED UNPREDICTABLE. Make the implementation choice that an
+	 * UNKNOWN number of counters (in our case, zero) are reserved for EL2.
+	 */
+	if (hpmn >= n)
+		return 0;
+
+	/*
+	 * Programming HPMN=0 is CONSTRAINED UNPREDICTABLE if FEAT_HPMN0 isn't
+	 * implemented. Since KVM's ability to emulate HPMN=0 does not directly
+	 * depend on hardware (all PMU registers are trapped), make the
+	 * implementation choice that all counters are included in the second
+	 * range reserved for EL2/EL3.
+	 */
+	return GENMASK(n - 1, hpmn);
+}
+
+bool kvm_pmu_counter_is_hyp(struct kvm_vcpu *vcpu, unsigned int idx)
+{
+	return kvm_pmu_hyp_counter_mask(vcpu) & BIT(idx);
+}
+
+u64 kvm_pmu_accessible_counter_mask(struct kvm_vcpu *vcpu)
+{
+	u64 mask = kvm_pmu_implemented_counter_mask(vcpu);
+
+	if (!vcpu_has_nv(vcpu) || vcpu_is_el2(vcpu))
+		return mask;
+
+	return mask & ~kvm_pmu_hyp_counter_mask(vcpu);
+}
+
+/**
+ * kvm_vcpu_read_pmcr - Read PMCR_EL0 register for the vCPU
+ * @vcpu: The vcpu pointer
+ */
+u64 kvm_vcpu_read_pmcr(struct kvm_vcpu *vcpu)
+{
+	u64 pmcr = __vcpu_sys_reg(vcpu, PMCR_EL0);
+	u64 n = vcpu->kvm->arch.nr_pmu_counters;
+
+	if (vcpu_has_nv(vcpu) && !vcpu_is_el2(vcpu))
+		n = FIELD_GET(MDCR_EL2_HPMN, __vcpu_sys_reg(vcpu, MDCR_EL2));
+
+	return u64_replace_bits(pmcr, n, ARMV8_PMU_PMCR_N);
+}
-- 
2.52.0.239.gd5f0c6e74e-goog



From coltonlewis at google.com  Tue Dec  9 12:51:05 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Tue,  9 Dec 2025 20:51:05 +0000
Subject: [PATCH v5 08/24] perf: arm_pmuv3: Generalize counter bitmasks
In-Reply-To: <20251209205121.1871534-1-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
Message-ID: <20251209205121.1871534-9-coltonlewis@google.com>

The OVSR bitmasks are valid for enable and interrupt registers as well as
overflow registers. Generalize the names.

Acked-by: Mark Rutland <mark.rutland at arm.com>
Signed-off-by: Colton Lewis <coltonlewis at google.com>
---
 drivers/perf/arm_pmuv3.c       |  4 ++--
 include/linux/perf/arm_pmuv3.h | 14 +++++++-------
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/perf/arm_pmuv3.c b/drivers/perf/arm_pmuv3.c
index 379d1877a61ba..3e6eb4be4ac43 100644
--- a/drivers/perf/arm_pmuv3.c
+++ b/drivers/perf/arm_pmuv3.c
@@ -546,7 +546,7 @@ static u64 armv8pmu_pmcr_n_read(void)
 
 static int armv8pmu_has_overflowed(u64 pmovsr)
 {
-	return !!(pmovsr & ARMV8_PMU_OVERFLOWED_MASK);
+	return !!(pmovsr & ARMV8_PMU_CNT_MASK_ALL);
 }
 
 static int armv8pmu_counter_has_overflowed(u64 pmnc, int idx)
@@ -782,7 +782,7 @@ static u64 armv8pmu_getreset_flags(void)
 	value = read_pmovsclr();
 
 	/* Write to clear flags */
-	value &= ARMV8_PMU_OVERFLOWED_MASK;
+	value &= ARMV8_PMU_CNT_MASK_ALL;
 	write_pmovsclr(value);
 
 	return value;
diff --git a/include/linux/perf/arm_pmuv3.h b/include/linux/perf/arm_pmuv3.h
index d698efba28a27..fd2a34b4a64d1 100644
--- a/include/linux/perf/arm_pmuv3.h
+++ b/include/linux/perf/arm_pmuv3.h
@@ -224,14 +224,14 @@
 				 ARMV8_PMU_PMCR_LC | ARMV8_PMU_PMCR_LP)
 
 /*
- * PMOVSR: counters overflow flag status reg
+ * Counter bitmask layouts for overflow, enable, and interrupts
  */
-#define ARMV8_PMU_OVSR_P		GENMASK(30, 0)
-#define ARMV8_PMU_OVSR_C		BIT(31)
-#define ARMV8_PMU_OVSR_F		BIT_ULL(32) /* arm64 only */
-/* Mask for writable bits is both P and C fields */
-#define ARMV8_PMU_OVERFLOWED_MASK	(ARMV8_PMU_OVSR_P | ARMV8_PMU_OVSR_C | \
-					ARMV8_PMU_OVSR_F)
+#define ARMV8_PMU_CNT_MASK_P		GENMASK(30, 0)
+#define ARMV8_PMU_CNT_MASK_C		BIT(31)
+#define ARMV8_PMU_CNT_MASK_F		BIT_ULL(32) /* arm64 only */
+#define ARMV8_PMU_CNT_MASK_ALL		(ARMV8_PMU_CNT_MASK_P | \
+					 ARMV8_PMU_CNT_MASK_C | \
+					 ARMV8_PMU_CNT_MASK_F)
 
 /*
  * PMXEVTYPER: Event selection reg
-- 
2.52.0.239.gd5f0c6e74e-goog



From coltonlewis at google.com  Tue Dec  9 12:51:06 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Tue,  9 Dec 2025 20:51:06 +0000
Subject: [PATCH v5 09/24] perf: arm_pmuv3: Keep out of guest counter partition
In-Reply-To: <20251209205121.1871534-1-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
Message-ID: <20251209205121.1871534-10-coltonlewis@google.com>

If the PMU is partitioned, keep the driver out of the guest counter
partition and only use the host counter partition.

Define some functions that determine whether the PMU is partitioned
and construct mutually exclusive bitmaps for testing which partition a
particular counter is in. Note that despite their separate position in
the bitmap, the cycle and instruction counters are always in the guest
partition.

Signed-off-by: Colton Lewis <coltonlewis at google.com>
---
 arch/arm/include/asm/arm_pmuv3.h | 18 +++++++
 arch/arm64/include/asm/kvm_pmu.h | 24 +++++++++
 arch/arm64/kvm/pmu-direct.c      | 86 ++++++++++++++++++++++++++++++++
 drivers/perf/arm_pmuv3.c         | 41 +++++++++++++--
 4 files changed, 165 insertions(+), 4 deletions(-)

diff --git a/arch/arm/include/asm/arm_pmuv3.h b/arch/arm/include/asm/arm_pmuv3.h
index 636b1aab9e8d2..3ea5741d213d8 100644
--- a/arch/arm/include/asm/arm_pmuv3.h
+++ b/arch/arm/include/asm/arm_pmuv3.h
@@ -231,6 +231,24 @@ static inline bool kvm_set_pmuserenr(u64 val)
 }
 
 static inline void kvm_vcpu_pmu_resync_el0(void) {}
+static inline void kvm_pmu_host_counters_enable(void) {}
+static inline void kvm_pmu_host_counters_disable(void) {}
+
+static inline bool kvm_pmu_is_partitioned(struct arm_pmu *pmu)
+{
+	return false;
+}
+
+static inline u64 kvm_pmu_host_counter_mask(struct arm_pmu *pmu)
+{
+	return ~0;
+}
+
+static inline u64 kvm_pmu_guest_counter_mask(struct arm_pmu *pmu)
+{
+	return ~0;
+}
+
 
 /* PMU Version in DFR Register */
 #define ARMV8_PMU_DFR_VER_NI        0
diff --git a/arch/arm64/include/asm/kvm_pmu.h b/arch/arm64/include/asm/kvm_pmu.h
index 63bff75e4f8dd..8887f39c25e60 100644
--- a/arch/arm64/include/asm/kvm_pmu.h
+++ b/arch/arm64/include/asm/kvm_pmu.h
@@ -90,6 +90,12 @@ void kvm_vcpu_pmu_resync_el0(void);
 #define kvm_vcpu_has_pmu(vcpu)					\
 	(vcpu_has_feature(vcpu, KVM_ARM_VCPU_PMU_V3))
 
+bool kvm_pmu_is_partitioned(struct arm_pmu *pmu);
+u64 kvm_pmu_host_counter_mask(struct arm_pmu *pmu);
+u64 kvm_pmu_guest_counter_mask(struct arm_pmu *pmu);
+void kvm_pmu_host_counters_enable(void);
+void kvm_pmu_host_counters_disable(void);
+
 /*
  * Updates the vcpu's view of the pmu events for this cpu.
  * Must be called before every vcpu run after disabling interrupts, to ensure
@@ -222,6 +228,24 @@ static inline bool kvm_pmu_counter_is_hyp(struct kvm_vcpu *vcpu, unsigned int id
 
 static inline void kvm_pmu_nested_transition(struct kvm_vcpu *vcpu) {}
 
+static inline bool kvm_pmu_is_partitioned(void *pmu)
+{
+	return false;
+}
+
+static inline u64 kvm_pmu_host_counter_mask(void *pmu)
+{
+	return ~0;
+}
+
+static inline u64 kvm_pmu_guest_counter_mask(void *pmu)
+{
+	return ~0;
+}
+
+static inline void kvm_pmu_host_counters_enable(void) {}
+static inline void kvm_pmu_host_counters_disable(void) {}
+
 #endif
 
 #endif
diff --git a/arch/arm64/kvm/pmu-direct.c b/arch/arm64/kvm/pmu-direct.c
index 0d38265b6f290..d5de7fdd059f4 100644
--- a/arch/arm64/kvm/pmu-direct.c
+++ b/arch/arm64/kvm/pmu-direct.c
@@ -5,7 +5,10 @@
  */
 
 #include <linux/kvm_host.h>
+#include <linux/perf/arm_pmu.h>
+#include <linux/perf/arm_pmuv3.h>
 
+#include <asm/arm_pmuv3.h>
 #include <asm/kvm_pmu.h>
 
 /**
@@ -20,3 +23,86 @@ bool kvm_pmu_partition_supported(void)
 	return has_vhe() &&
 		system_supports_pmuv3();
 }
+
+/**
+ * kvm_pmu_is_partitioned() - Determine if given PMU is partitioned
+ * @pmu: Pointer to arm_pmu struct
+ *
+ * Determine if given PMU is partitioned by looking at hpmn field. The
+ * PMU is partitioned if this field is less than the number of
+ * counters in the system.
+ *
+ * Return: True if the PMU is partitioned, false otherwise
+ */
+bool kvm_pmu_is_partitioned(struct arm_pmu *pmu)
+{
+	if (!pmu)
+		return false;
+
+	return pmu->hpmn_max >= 0 &&
+		pmu->hpmn_max <= *host_data_ptr(nr_event_counters);
+}
+
+/**
+ * kvm_pmu_host_counter_mask() - Compute bitmask of host-reserved counters
+ * @pmu: Pointer to arm_pmu struct
+ *
+ * Compute the bitmask that selects the host-reserved counters in the
+ * {PMCNTEN,PMINTEN,PMOVS}{SET,CLR} registers. These are the counters
+ * in HPMN..N
+ *
+ * Return: Bitmask
+ */
+u64 kvm_pmu_host_counter_mask(struct arm_pmu *pmu)
+{
+	u8 nr_counters = *host_data_ptr(nr_event_counters);
+
+	if (!kvm_pmu_is_partitioned(pmu))
+		return ARMV8_PMU_CNT_MASK_ALL;
+
+	return GENMASK(nr_counters - 1, pmu->hpmn_max);
+}
+
+/**
+ * kvm_pmu_guest_counter_mask() - Compute bitmask of guest-reserved counters
+ *
+ * Compute the bitmask that selects the guest-reserved counters in the
+ * {PMCNTEN,PMINTEN,PMOVS}{SET,CLR} registers. These are the counters
+ * in 0..HPMN and the cycle and instruction counters.
+ *
+ * Return: Bitmask
+ */
+u64 kvm_pmu_guest_counter_mask(struct arm_pmu *pmu)
+{
+	return ARMV8_PMU_CNT_MASK_ALL & ~kvm_pmu_host_counter_mask(pmu);
+}
+
+/**
+ * kvm_pmu_host_counters_enable() - Enable host-reserved counters
+ *
+ * When partitioned the enable bit for host-reserved counters is
+ * MDCR_EL2.HPME instead of the typical PMCR_EL0.E, which now
+ * exclusively controls the guest-reserved counters. Enable that bit.
+ */
+void kvm_pmu_host_counters_enable(void)
+{
+	u64 mdcr = read_sysreg(mdcr_el2);
+
+	mdcr |= MDCR_EL2_HPME;
+	write_sysreg(mdcr, mdcr_el2);
+}
+
+/**
+ * kvm_pmu_host_counters_disable() - Disable host-reserved counters
+ *
+ * When partitioned the disable bit for host-reserved counters is
+ * MDCR_EL2.HPME instead of the typical PMCR_EL0.E, which now
+ * exclusively controls the guest-reserved counters. Disable that bit.
+ */
+void kvm_pmu_host_counters_disable(void)
+{
+	u64 mdcr = read_sysreg(mdcr_el2);
+
+	mdcr &= ~MDCR_EL2_HPME;
+	write_sysreg(mdcr, mdcr_el2);
+}
diff --git a/drivers/perf/arm_pmuv3.c b/drivers/perf/arm_pmuv3.c
index 3e6eb4be4ac43..2bed99ba992d7 100644
--- a/drivers/perf/arm_pmuv3.c
+++ b/drivers/perf/arm_pmuv3.c
@@ -871,6 +871,9 @@ static void armv8pmu_start(struct arm_pmu *cpu_pmu)
 		brbe_enable(cpu_pmu);
 
 	/* Enable all counters */
+	if (kvm_pmu_is_partitioned(cpu_pmu))
+		kvm_pmu_host_counters_enable();
+
 	armv8pmu_pmcr_write(armv8pmu_pmcr_read() | ARMV8_PMU_PMCR_E);
 }
 
@@ -882,6 +885,9 @@ static void armv8pmu_stop(struct arm_pmu *cpu_pmu)
 		brbe_disable();
 
 	/* Disable all counters */
+	if (kvm_pmu_is_partitioned(cpu_pmu))
+		kvm_pmu_host_counters_disable();
+
 	armv8pmu_pmcr_write(armv8pmu_pmcr_read() & ~ARMV8_PMU_PMCR_E);
 }
 
@@ -998,6 +1004,7 @@ static int armv8pmu_get_chain_idx(struct pmu_hw_events *cpuc,
 static bool armv8pmu_can_use_pmccntr(struct pmu_hw_events *cpuc,
 				     struct perf_event *event)
 {
+	struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
 	struct hw_perf_event *hwc = &event->hw;
 	unsigned long evtype = hwc->config_base & ARMV8_PMU_EVTYPE_EVENT;
 
@@ -1018,6 +1025,12 @@ static bool armv8pmu_can_use_pmccntr(struct pmu_hw_events *cpuc,
 	if (has_branch_stack(event))
 		return false;
 
+	/*
+	 * If partitioned at all, pmccntr belongs to the guest.
+	 */
+	if (kvm_pmu_is_partitioned(cpu_pmu))
+		return false;
+
 	return true;
 }
 
@@ -1044,6 +1057,7 @@ static int armv8pmu_get_event_idx(struct pmu_hw_events *cpuc,
 	 * may not know how to handle it.
 	 */
 	if ((evtype == ARMV8_PMUV3_PERFCTR_INST_RETIRED) &&
+	    !kvm_pmu_is_partitioned(cpu_pmu) &&
 	    !armv8pmu_event_get_threshold(&event->attr) &&
 	    test_bit(ARMV8_PMU_INSTR_IDX, cpu_pmu->cntr_mask) &&
 	    !armv8pmu_event_want_user_access(event)) {
@@ -1055,7 +1069,7 @@ static int armv8pmu_get_event_idx(struct pmu_hw_events *cpuc,
 	 * Otherwise use events counters
 	 */
 	if (armv8pmu_event_is_chained(event))
-		return	armv8pmu_get_chain_idx(cpuc, cpu_pmu);
+		return armv8pmu_get_chain_idx(cpuc, cpu_pmu);
 	else
 		return armv8pmu_get_single_idx(cpuc, cpu_pmu);
 }
@@ -1167,6 +1181,14 @@ static int armv8pmu_set_event_filter(struct hw_perf_event *event,
 	return 0;
 }
 
+static void armv8pmu_reset_host_counters(struct arm_pmu *cpu_pmu)
+{
+	int idx;
+
+	for_each_set_bit(idx, cpu_pmu->cntr_mask, ARMV8_PMU_MAX_GENERAL_COUNTERS)
+		armv8pmu_write_evcntr(idx, 0);
+}
+
 static void armv8pmu_reset(void *info)
 {
 	struct arm_pmu *cpu_pmu = (struct arm_pmu *)info;
@@ -1174,6 +1196,9 @@ static void armv8pmu_reset(void *info)
 
 	bitmap_to_arr64(&mask, cpu_pmu->cntr_mask, ARMPMU_MAX_HWEVENTS);
 
+	if (kvm_pmu_is_partitioned(cpu_pmu))
+		mask &= kvm_pmu_host_counter_mask(cpu_pmu);
+
 	/* The counter and interrupt enable registers are unknown at reset. */
 	armv8pmu_disable_counter(mask);
 	armv8pmu_disable_intens(mask);
@@ -1186,11 +1211,19 @@ static void armv8pmu_reset(void *info)
 		brbe_invalidate();
 	}
 
+	pmcr = ARMV8_PMU_PMCR_LC;
+
 	/*
-	 * Initialize & Reset PMNC. Request overflow interrupt for
-	 * 64 bit cycle counter but cheat in armv8pmu_write_counter().
+	 * Initialize & Reset PMNC. Request overflow interrupt for 64
+	 * bit cycle counter but cheat in armv8pmu_write_counter().
+	 *
+	 * When partitioned, there is no single bit to reset only the
+	 * host counters. so reset them individually.
 	 */
-	pmcr = ARMV8_PMU_PMCR_P | ARMV8_PMU_PMCR_C | ARMV8_PMU_PMCR_LC;
+	if (kvm_pmu_is_partitioned(cpu_pmu))
+		armv8pmu_reset_host_counters(cpu_pmu);
+	else
+		pmcr = ARMV8_PMU_PMCR_P | ARMV8_PMU_PMCR_C;
 
 	/* Enable long event counter support where available */
 	if (armv8pmu_has_long_event(cpu_pmu))
-- 
2.52.0.239.gd5f0c6e74e-goog



From coltonlewis at google.com  Tue Dec  9 12:51:08 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Tue,  9 Dec 2025 20:51:08 +0000
Subject: [PATCH v5 11/24] KVM: arm64: Writethrough trapped PMEVTYPER register
In-Reply-To: <20251209205121.1871534-1-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
Message-ID: <20251209205121.1871534-12-coltonlewis@google.com>

With FGT in place, the remaining trapped registers need to be written
through to the underlying physical registers as well as the virtual
ones. Failing to do this means guest writes will not take effect when
expected.

For the PMEVTYPER register, take care to enforce KVM's PMU event
filter. Do that by setting the bits to exclude EL1 and EL0 when an
event is not present in the filter and clearing the bit to include EL2
always.

Note the virtual register is always assigned the value specified by
the guest to hide the setting of those bits.

Signed-off-by: Colton Lewis <coltonlewis at google.com>
---
 arch/arm64/kvm/sys_regs.c | 34 +++++++++++++++++++++++++++++++++-
 1 file changed, 33 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index c636840b1f6f9..0c9596325519b 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1166,6 +1166,36 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
 	return true;
 }
 
+static bool writethrough_pmevtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+				   u64 reg, u64 idx)
+{
+	u64 eventsel;
+	u64 val = p->regval;
+	u64 evtyper_set = ARMV8_PMU_EXCLUDE_EL0 |
+		ARMV8_PMU_EXCLUDE_EL1;
+	u64 evtyper_clr = ARMV8_PMU_INCLUDE_EL2;
+
+	__vcpu_assign_sys_reg(vcpu, reg, val);
+
+	if (idx == ARMV8_PMU_CYCLE_IDX)
+		eventsel = ARMV8_PMUV3_PERFCTR_CPU_CYCLES;
+	else
+		eventsel = val & kvm_pmu_event_mask(vcpu->kvm);
+
+	if (vcpu->kvm->arch.pmu_filter &&
+	    !test_bit(eventsel, vcpu->kvm->arch.pmu_filter))
+		val |= evtyper_set;
+
+	val &= ~evtyper_clr;
+
+	if (idx == ARMV8_PMU_CYCLE_IDX)
+		write_pmccfiltr(val);
+	else
+		write_pmevtypern(idx, val);
+
+	return true;
+}
+
 static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			       const struct sys_reg_desc *r)
 {
@@ -1192,7 +1222,9 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	if (!pmu_counter_idx_valid(vcpu, idx))
 		return false;
 
-	if (p->is_write) {
+	if (kvm_vcpu_pmu_is_partitioned(vcpu) && p->is_write) {
+		writethrough_pmevtyper(vcpu, p, reg, idx);
+	} else if (p->is_write) {
 		kvm_pmu_set_counter_event_type(vcpu, p->regval, idx);
 		kvm_vcpu_pmu_restore_guest(vcpu);
 	} else {
-- 
2.52.0.239.gd5f0c6e74e-goog



From coltonlewis at google.com  Tue Dec  9 12:51:07 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Tue,  9 Dec 2025 20:51:07 +0000
Subject: [PATCH v5 10/24] KVM: arm64: Set up FGT for Partitioned PMU
In-Reply-To: <20251209205121.1871534-1-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
Message-ID: <20251209205121.1871534-11-coltonlewis@google.com>

In order to gain the best performance benefit from partitioning the
PMU, utilize fine grain traps (FEAT_FGT and FEAT_FGT2) to avoid
trapping common PMU register accesses by the guest to remove that
overhead.

Untrapped:
* PMCR_EL0
* PMUSERENR_EL0
* PMSELR_EL0
* PMCCNTR_EL0
* PMCNTEN_EL0
* PMINTEN_EL1
* PMEVCNTRn_EL0

These are safe to untrap because writing MDCR_EL2.HPMN as this series
will do limits the effect of writes to any of these registers to the
partition of counters 0..HPMN-1. Reads from these registers will not
leak information from between guests as all these registers are
context swapped by a later patch in this series. Reads from these
registers also do not leak any information about the host's hardware
beyond what is promised by PMUv3.

Trapped:
* PMOVS_EL0
* PMEVTYPERn_EL0
* PMCCFILTR_EL0
* PMICNTR_EL0
* PMICFILTR_EL0
* PMCEIDn_EL0
* PMMIR_EL1

PMOVS remains trapped so KVM can track overflow IRQs that will need to
be injected into the guest.

PMICNTR and PMIFILTR remain trapped because KVM is not handling them
yet.

PMEVTYPERn remains trapped so KVM can limit which events guests can
count, such as disallowing counting at EL2. PMCCFILTR and PMCIFILTR
are special cases of the same.

PMCEIDn and PMMIR remain trapped because they can leak information
specific to the host hardware implementation.

NOTE: This patch temporarily forces kvm_vcpu_pmu_is_partitioned() to
be false to prevent partial feature activation for easier debugging.

Signed-off-by: Colton Lewis <coltonlewis at google.com>
---
 arch/arm64/include/asm/kvm_pmu.h | 33 ++++++++++++++++++++++
 arch/arm64/kvm/config.c          | 34 ++++++++++++++++++++--
 arch/arm64/kvm/pmu-direct.c      | 48 ++++++++++++++++++++++++++++++++
 3 files changed, 112 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_pmu.h b/arch/arm64/include/asm/kvm_pmu.h
index 8887f39c25e60..7297a697a4a62 100644
--- a/arch/arm64/include/asm/kvm_pmu.h
+++ b/arch/arm64/include/asm/kvm_pmu.h
@@ -96,6 +96,23 @@ u64 kvm_pmu_guest_counter_mask(struct arm_pmu *pmu);
 void kvm_pmu_host_counters_enable(void);
 void kvm_pmu_host_counters_disable(void);
 
+#if !defined(__KVM_NVHE_HYPERVISOR__)
+bool kvm_vcpu_pmu_is_partitioned(struct kvm_vcpu *vcpu);
+bool kvm_vcpu_pmu_use_fgt(struct kvm_vcpu *vcpu);
+#else
+static inline bool kvm_vcpu_pmu_is_partitioned(struct kvm_vcpu *vcpu)
+{
+	return false;
+}
+
+static inline bool kvm_vcpu_pmu_use_fgt(struct kvm_vcpu *vcpu)
+{
+	return false;
+}
+#endif
+u64 kvm_pmu_fgt_bits(void);
+u64 kvm_pmu_fgt2_bits(void);
+
 /*
  * Updates the vcpu's view of the pmu events for this cpu.
  * Must be called before every vcpu run after disabling interrupts, to ensure
@@ -135,6 +152,22 @@ static inline u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu,
 {
 	return 0;
 }
+static inline bool kvm_vcpu_pmu_is_partitioned(struct kvm_vcpu *vcpu)
+{
+	return false;
+}
+static inline bool kvm_vcpu_pmu_use_fgt(struct kvm_vcpu *vcpu)
+{
+	return false;
+}
+static inline u64 kvm_pmu_fgt_bits(void)
+{
+	return 0;
+}
+static inline u64 kvm_pmu_fgt2_bits(void)
+{
+	return 0;
+}
 static inline void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu,
 					     u64 select_idx, u64 val) {}
 static inline void kvm_pmu_set_counter_value_user(struct kvm_vcpu *vcpu,
diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index 24bb3f36e9d59..064dc6aa06f76 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -6,6 +6,7 @@
 
 #include <linux/kvm_host.h>
 #include <asm/kvm_emulate.h>
+#include <asm/kvm_pmu.h>
 #include <asm/kvm_nested.h>
 #include <asm/sysreg.h>
 
@@ -1489,12 +1490,39 @@ static void __compute_hfgwtr(struct kvm_vcpu *vcpu)
 		*vcpu_fgt(vcpu, HFGWTR_EL2) |= HFGWTR_EL2_TCR_EL1;
 }
 
+static void __compute_hdfgrtr(struct kvm_vcpu *vcpu)
+{
+	__compute_fgt(vcpu, HDFGRTR_EL2);
+
+	if (kvm_vcpu_pmu_use_fgt(vcpu))
+		*vcpu_fgt(vcpu, HDFGRTR_EL2) |= kvm_pmu_fgt_bits();
+}
+
 static void __compute_hdfgwtr(struct kvm_vcpu *vcpu)
 {
 	__compute_fgt(vcpu, HDFGWTR_EL2);
 
 	if (is_hyp_ctxt(vcpu))
 		*vcpu_fgt(vcpu, HDFGWTR_EL2) |= HDFGWTR_EL2_MDSCR_EL1;
+
+	if (kvm_vcpu_pmu_use_fgt(vcpu))
+		*vcpu_fgt(vcpu, HDFGWTR_EL2) |= kvm_pmu_fgt_bits();
+}
+
+static void __compute_hdfgrtr2(struct kvm_vcpu *vcpu)
+{
+	__compute_fgt(vcpu, HDFGRTR2_EL2);
+
+	if (kvm_vcpu_pmu_use_fgt(vcpu))
+		*vcpu_fgt(vcpu, HDFGRTR2_EL2) |= kvm_pmu_fgt2_bits();
+}
+
+static void __compute_hdfgwtr2(struct kvm_vcpu *vcpu)
+{
+	__compute_fgt(vcpu, HDFGWTR2_EL2);
+
+	if (kvm_vcpu_pmu_use_fgt(vcpu))
+		*vcpu_fgt(vcpu, HDFGWTR2_EL2) |= kvm_pmu_fgt2_bits();
 }
 
 void kvm_vcpu_load_fgt(struct kvm_vcpu *vcpu)
@@ -1505,7 +1533,7 @@ void kvm_vcpu_load_fgt(struct kvm_vcpu *vcpu)
 	__compute_fgt(vcpu, HFGRTR_EL2);
 	__compute_hfgwtr(vcpu);
 	__compute_fgt(vcpu, HFGITR_EL2);
-	__compute_fgt(vcpu, HDFGRTR_EL2);
+	__compute_hdfgrtr(vcpu);
 	__compute_hdfgwtr(vcpu);
 	__compute_fgt(vcpu, HAFGRTR_EL2);
 
@@ -1515,6 +1543,6 @@ void kvm_vcpu_load_fgt(struct kvm_vcpu *vcpu)
 	__compute_fgt(vcpu, HFGRTR2_EL2);
 	__compute_fgt(vcpu, HFGWTR2_EL2);
 	__compute_fgt(vcpu, HFGITR2_EL2);
-	__compute_fgt(vcpu, HDFGRTR2_EL2);
-	__compute_fgt(vcpu, HDFGWTR2_EL2);
+	__compute_hdfgrtr2(vcpu);
+	__compute_hdfgwtr2(vcpu);
 }
diff --git a/arch/arm64/kvm/pmu-direct.c b/arch/arm64/kvm/pmu-direct.c
index d5de7fdd059f4..4dd160c878862 100644
--- a/arch/arm64/kvm/pmu-direct.c
+++ b/arch/arm64/kvm/pmu-direct.c
@@ -43,6 +43,54 @@ bool kvm_pmu_is_partitioned(struct arm_pmu *pmu)
 		pmu->hpmn_max <= *host_data_ptr(nr_event_counters);
 }
 
+/**
+ * kvm_vcpu_pmu_is_partitioned() - Determine if given VCPU has a partitioned PMU
+ * @vcpu: Pointer to kvm_vcpu struct
+ *
+ * Determine if given VCPU has a partitioned PMU by extracting that
+ * field and passing it to :c:func:`kvm_pmu_is_partitioned`
+ *
+ * Return: True if the VCPU PMU is partitioned, false otherwise
+ */
+bool kvm_vcpu_pmu_is_partitioned(struct kvm_vcpu *vcpu)
+{
+	return kvm_pmu_is_partitioned(vcpu->kvm->arch.arm_pmu) &&
+		false;
+}
+
+/**
+ * kvm_vcpu_pmu_use_fgt() - Determine if we can use FGT
+ * @vcpu: Pointer to struct kvm_vcpu
+ *
+ * Determine if we can use FGT for direct access to registers. We can
+ * if capabilities permit the number of guest counters requested.
+ *
+ * Return: True if we can use FGT, false otherwise
+ */
+bool kvm_vcpu_pmu_use_fgt(struct kvm_vcpu *vcpu)
+{
+	u8 hpmn = vcpu->kvm->arch.nr_pmu_counters;
+
+	return kvm_vcpu_pmu_is_partitioned(vcpu) &&
+		cpus_have_final_cap(ARM64_HAS_FGT) &&
+		(hpmn != 0 || cpus_have_final_cap(ARM64_HAS_HPMN0));
+}
+
+u64 kvm_pmu_fgt_bits(void)
+{
+	return HDFGRTR_EL2_PMOVS
+		| HDFGRTR_EL2_PMCCFILTR_EL0
+		| HDFGRTR_EL2_PMEVTYPERn_EL0
+		| HDFGRTR_EL2_PMCEIDn_EL0
+		| HDFGRTR_EL2_PMMIR_EL1;
+}
+
+u64 kvm_pmu_fgt2_bits(void)
+{
+	return HDFGRTR2_EL2_nPMICFILTR_EL0
+		| HDFGRTR2_EL2_nPMICNTR_EL0;
+}
+
 /**
  * kvm_pmu_host_counter_mask() - Compute bitmask of host-reserved counters
  * @pmu: Pointer to arm_pmu struct
-- 
2.52.0.239.gd5f0c6e74e-goog



From coltonlewis at google.com  Tue Dec  9 12:51:09 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Tue,  9 Dec 2025 20:51:09 +0000
Subject: [PATCH v5 12/24] KVM: arm64: Use physical PMSELR for PMXEVTYPER if partitioned
In-Reply-To: <20251209205121.1871534-1-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
Message-ID: <20251209205121.1871534-13-coltonlewis@google.com>

Because PMXEVTYPER is trapped and PMSELR is not, it is not appropriate
to use the virtual PMSELR register when it could be outdated and lead
to an invalid write. Use the physical register when partitioned.

Signed-off-by: Colton Lewis <coltonlewis at google.com>
---
 arch/arm64/include/asm/arm_pmuv3.h | 7 ++++++-
 arch/arm64/kvm/sys_regs.c          | 9 +++++++--
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/arm_pmuv3.h b/arch/arm64/include/asm/arm_pmuv3.h
index 27c4d6d47da31..60600f04b5902 100644
--- a/arch/arm64/include/asm/arm_pmuv3.h
+++ b/arch/arm64/include/asm/arm_pmuv3.h
@@ -70,11 +70,16 @@ static inline u64 read_pmcr(void)
 	return read_sysreg(pmcr_el0);
 }
 
-static inline void write_pmselr(u32 val)
+static inline void write_pmselr(u64 val)
 {
 	write_sysreg(val, pmselr_el0);
 }
 
+static inline u64 read_pmselr(void)
+{
+	return read_sysreg(pmselr_el0);
+}
+
 static inline void write_pmccntr(u64 val)
 {
 	write_sysreg(val, pmccntr_el0);
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 0c9596325519b..2e6d907fa8af2 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1199,14 +1199,19 @@ static bool writethrough_pmevtyper(struct kvm_vcpu *vcpu, struct sys_reg_params
 static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			       const struct sys_reg_desc *r)
 {
-	u64 idx, reg;
+	u64 idx, reg, pmselr;
 
 	if (pmu_access_el0_disabled(vcpu))
 		return false;
 
 	if (r->CRn == 9 && r->CRm == 13 && r->Op2 == 1) {
 		/* PMXEVTYPER_EL0 */
-		idx = SYS_FIELD_GET(PMSELR_EL0, SEL, __vcpu_sys_reg(vcpu, PMSELR_EL0));
+		if (kvm_vcpu_pmu_is_partitioned(vcpu))
+			pmselr = read_pmselr();
+		else
+			pmselr = __vcpu_sys_reg(vcpu, PMSELR_EL0);
+
+		idx = SYS_FIELD_GET(PMSELR_EL0, SEL, pmselr);
 		reg = PMEVTYPER0_EL0 + idx;
 	} else if (r->CRn == 14 && (r->CRm & 12) == 12) {
 		idx = ((r->CRm & 3) << 3) | (r->Op2 & 7);
-- 
2.52.0.239.gd5f0c6e74e-goog



From coltonlewis at google.com  Tue Dec  9 12:51:10 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Tue,  9 Dec 2025 20:51:10 +0000
Subject: [PATCH v5 13/24] KVM: arm64: Writethrough trapped PMOVS register
In-Reply-To: <20251209205121.1871534-1-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
Message-ID: <20251209205121.1871534-14-coltonlewis@google.com>

Because PMOVS remains trapped, it needs to be written through when
partitioned to affect PMU hardware when expected.

Signed-off-by: Colton Lewis <coltonlewis at google.com>
---
 arch/arm64/include/asm/arm_pmuv3.h | 10 ++++++++++
 arch/arm64/kvm/sys_regs.c          | 17 ++++++++++++++++-
 2 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/arm_pmuv3.h b/arch/arm64/include/asm/arm_pmuv3.h
index 60600f04b5902..3e25c0313263c 100644
--- a/arch/arm64/include/asm/arm_pmuv3.h
+++ b/arch/arm64/include/asm/arm_pmuv3.h
@@ -140,6 +140,16 @@ static inline u64 read_pmicfiltr(void)
 	return read_sysreg_s(SYS_PMICFILTR_EL0);
 }
 
+static inline void write_pmovsset(u64 val)
+{
+	write_sysreg(val, pmovsset_el0);
+}
+
+static inline u64 read_pmovsset(void)
+{
+	return read_sysreg(pmovsset_el0);
+}
+
 static inline void write_pmovsclr(u64 val)
 {
 	write_sysreg(val, pmovsclr_el0);
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 2e6d907fa8af2..bee892db9ca8b 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1307,6 +1307,19 @@ static bool access_pminten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
+static void writethrough_pmovs(struct kvm_vcpu *vcpu, struct sys_reg_params *p, bool set)
+{
+	u64 mask = kvm_pmu_accessible_counter_mask(vcpu);
+
+	if (set) {
+		__vcpu_rmw_sys_reg(vcpu, PMOVSSET_EL0, |=, (p->regval & mask));
+		write_pmovsset(p->regval & mask);
+	} else {
+		__vcpu_rmw_sys_reg(vcpu, PMOVSSET_EL0, &=, ~(p->regval & mask));
+		write_pmovsclr(p->regval & mask);
+	}
+}
+
 static bool access_pmovs(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			 const struct sys_reg_desc *r)
 {
@@ -1315,7 +1328,9 @@ static bool access_pmovs(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	if (pmu_access_el0_disabled(vcpu))
 		return false;
 
-	if (p->is_write) {
+	if (kvm_vcpu_pmu_is_partitioned(vcpu) && p->is_write) {
+		writethrough_pmovs(vcpu, p, r->CRm & 0x2);
+	} else if (p->is_write) {
 		if (r->CRm & 0x2)
 			/* accessing PMOVSSET_EL0 */
 			__vcpu_rmw_sys_reg(vcpu, PMOVSSET_EL0, |=, (p->regval & mask));
-- 
2.52.0.239.gd5f0c6e74e-goog



From coltonlewis at google.com  Tue Dec  9 12:51:13 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Tue,  9 Dec 2025 20:51:13 +0000
Subject: [PATCH v5 16/24] KVM: arm64: Account for partitioning in PMCR_EL0 access
In-Reply-To: <20251209205121.1871534-1-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
Message-ID: <20251209205121.1871534-17-coltonlewis@google.com>

Make sure reads and writes to PMCR_EL0 conform to additional
constraints imposed when the PMU is partitioned.

Signed-off-by: Colton Lewis <coltonlewis at google.com>
---
 arch/arm64/kvm/pmu.c      | 2 +-
 arch/arm64/kvm/sys_regs.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/pmu.c b/arch/arm64/kvm/pmu.c
index 1fd012f8ff4a9..48b39f096fa12 100644
--- a/arch/arm64/kvm/pmu.c
+++ b/arch/arm64/kvm/pmu.c
@@ -877,7 +877,7 @@ u64 kvm_pmu_accessible_counter_mask(struct kvm_vcpu *vcpu)
 u64 kvm_vcpu_read_pmcr(struct kvm_vcpu *vcpu)
 {
 	u64 pmcr = __vcpu_sys_reg(vcpu, PMCR_EL0);
-	u64 n = vcpu->kvm->arch.nr_pmu_counters;
+	u64 n = kvm_pmu_guest_num_counters(vcpu);
 
 	if (vcpu_has_nv(vcpu) && !vcpu_is_el2(vcpu))
 		n = FIELD_GET(MDCR_EL2_HPMN, __vcpu_sys_reg(vcpu, MDCR_EL2));
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 70104087b6c7b..f2ae761625a66 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1360,7 +1360,7 @@ static int set_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
 	 */
 	if (!kvm_vm_has_ran_once(kvm) &&
 	    !vcpu_has_nv(vcpu)	      &&
-	    new_n <= kvm_arm_pmu_get_max_counters(kvm))
+	    new_n <= kvm_pmu_hpmn(vcpu))
 		kvm->arch.nr_pmu_counters = new_n;
 
 	mutex_unlock(&kvm->arch.config_lock);
-- 
2.52.0.239.gd5f0c6e74e-goog



From coltonlewis at google.com  Tue Dec  9 12:51:12 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Tue,  9 Dec 2025 20:51:12 +0000
Subject: [PATCH v5 15/24] KVM: arm64: Setup MDCR_EL2 to handle a partitioned PMU
In-Reply-To: <20251209205121.1871534-1-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
Message-ID: <20251209205121.1871534-16-coltonlewis@google.com>

Setup MDCR_EL2 to handle a partitioned PMU. That means calculate an
appropriate value for HPMN instead of the default maximum setting the
host allows (which implies no partition) so hardware enforces that a
guest will only see the counters in the guest partition.

Setting HPMN to a non default value means the global enable bit for
the host counters is now MDCR_EL2.HPME instead of the usual
PMCR_EL0.E. Enable the HPME bit to allow the host to count guest
events. Since HPME only has an effect when HPMN is set which we only
do for the guest, it is correct to enable it unconditionally here.

Unset the TPM and TPMCR bits, which trap all PMU accesses, if
FGT (fine grain trapping) is being used.

If available, set the filtering bits HPMD and HCCD to be extra sure
nothing in the guest counts at EL2.

Signed-off-by: Colton Lewis <coltonlewis at google.com>
---
 arch/arm64/include/asm/kvm_pmu.h | 11 ++++++
 arch/arm64/kvm/debug.c           | 29 ++++++++++++--
 arch/arm64/kvm/pmu-direct.c      | 65 ++++++++++++++++++++++++++++++++
 3 files changed, 102 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_pmu.h b/arch/arm64/include/asm/kvm_pmu.h
index 60b8a48cad456..8b634112eded2 100644
--- a/arch/arm64/include/asm/kvm_pmu.h
+++ b/arch/arm64/include/asm/kvm_pmu.h
@@ -101,6 +101,9 @@ u64 kvm_pmu_guest_counter_mask(struct arm_pmu *pmu);
 void kvm_pmu_host_counters_enable(void);
 void kvm_pmu_host_counters_disable(void);
 
+u8 kvm_pmu_guest_num_counters(struct kvm_vcpu *vcpu);
+u8 kvm_pmu_hpmn(struct kvm_vcpu *vcpu);
+
 #if !defined(__KVM_NVHE_HYPERVISOR__)
 bool kvm_vcpu_pmu_is_partitioned(struct kvm_vcpu *vcpu);
 bool kvm_vcpu_pmu_use_fgt(struct kvm_vcpu *vcpu);
@@ -173,6 +176,14 @@ static inline u64 kvm_pmu_fgt2_bits(void)
 {
 	return 0;
 }
+static inline u8 kvm_pmu_guest_num_counters(struct kvm_vcpu *vcpu)
+{
+	return 0;
+}
+static inline u8 kvm_pmu_hpmn(struct kvm_vcpu *vcpu)
+{
+	return 0;
+}
 static inline void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu,
 					     u64 select_idx, u64 val) {}
 static inline void kvm_pmu_set_counter_value_user(struct kvm_vcpu *vcpu,
diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
index 3ad6b7c6e4ba7..0ab89c91e19cb 100644
--- a/arch/arm64/kvm/debug.c
+++ b/arch/arm64/kvm/debug.c
@@ -36,20 +36,43 @@ static int cpu_has_spe(u64 dfr0)
  */
 static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu)
 {
+	int hpmn = kvm_pmu_hpmn(vcpu);
+
 	preempt_disable();
 
 	/*
 	 * This also clears MDCR_EL2_E2PB_MASK and MDCR_EL2_E2TB_MASK
 	 * to disable guest access to the profiling and trace buffers
 	 */
-	vcpu->arch.mdcr_el2 = FIELD_PREP(MDCR_EL2_HPMN,
-					 *host_data_ptr(nr_event_counters));
+
+	vcpu->arch.mdcr_el2 = FIELD_PREP(MDCR_EL2_HPMN, hpmn);
 	vcpu->arch.mdcr_el2 |= (MDCR_EL2_TPM |
 				MDCR_EL2_TPMS |
 				MDCR_EL2_TTRF |
 				MDCR_EL2_TPMCR |
 				MDCR_EL2_TDRA |
-				MDCR_EL2_TDOSA);
+				MDCR_EL2_TDOSA |
+				MDCR_EL2_HPME);
+
+	if (kvm_vcpu_pmu_is_partitioned(vcpu)) {
+		/*
+		 * Filtering these should be redundant because we trap
+		 * all the TYPER and FILTR registers anyway and ensure
+		 * they filter EL2, but set the bits if they are here.
+		 */
+		if (is_pmuv3p1(read_pmuver()))
+			vcpu->arch.mdcr_el2 |= MDCR_EL2_HPMD;
+		if (is_pmuv3p5(read_pmuver()))
+			vcpu->arch.mdcr_el2 |= MDCR_EL2_HCCD;
+
+		/*
+		 * Take out the coarse grain traps if we are using
+		 * fine grain traps.
+		 */
+		if (kvm_vcpu_pmu_use_fgt(vcpu))
+			vcpu->arch.mdcr_el2 &= ~(MDCR_EL2_TPM | MDCR_EL2_TPMCR);
+
+	}
 
 	/* Is the VM being debugged by userspace? */
 	if (vcpu->guest_debug)
diff --git a/arch/arm64/kvm/pmu-direct.c b/arch/arm64/kvm/pmu-direct.c
index 4dd160c878862..7fb4fb5c22e2a 100644
--- a/arch/arm64/kvm/pmu-direct.c
+++ b/arch/arm64/kvm/pmu-direct.c
@@ -154,3 +154,68 @@ void kvm_pmu_host_counters_disable(void)
 	mdcr &= ~MDCR_EL2_HPME;
 	write_sysreg(mdcr, mdcr_el2);
 }
+
+/**
+ * kvm_pmu_guest_num_counters() - Number of counters to show to guest
+ * @vcpu: Pointer to struct kvm_vcpu
+ *
+ * Calculate the number of counters to show to the guest via
+ * PMCR_EL0.N, making sure to respect the maximum the host allows,
+ * which is hpmn_max if partitioned and host_max otherwise.
+ *
+ * Return: Valid value for PMCR_EL0.N
+ */
+u8 kvm_pmu_guest_num_counters(struct kvm_vcpu *vcpu)
+{
+	u8 nr_cnt = vcpu->kvm->arch.nr_pmu_counters;
+	int hpmn_max = armv8pmu_hpmn_max;
+	u8 host_max = *host_data_ptr(nr_event_counters);
+
+	if (vcpu->kvm->arch.arm_pmu)
+		hpmn_max = vcpu->kvm->arch.arm_pmu->hpmn_max;
+
+	if (kvm_vcpu_pmu_is_partitioned(vcpu)) {
+		if (nr_cnt <= hpmn_max && nr_cnt <= host_max)
+			return nr_cnt;
+		if (hpmn_max <= host_max)
+			return hpmn_max;
+	}
+
+	if (nr_cnt <= host_max)
+		return nr_cnt;
+
+	return host_max;
+}
+
+/**
+ * kvm_pmu_hpmn() - Calculate HPMN field value
+ * @vcpu: Pointer to struct kvm_vcpu
+ *
+ * Calculate the appropriate value to set for MDCR_EL2.HPMN. If
+ * partitioned, this is the number of counters set for the guest if
+ * supported, falling back to hpmn_max if needed. If we are not
+ * partitioned or can't set the implied HPMN value, fall back to the
+ * host value.
+ *
+ * Return: A valid HPMN value
+ */
+u8 kvm_pmu_hpmn(struct kvm_vcpu *vcpu)
+{
+	u8 nr_guest_cnt = kvm_pmu_guest_num_counters(vcpu);
+	int nr_guest_cnt_max = armv8pmu_hpmn_max;
+	u8 nr_host_cnt_max = *host_data_ptr(nr_event_counters);
+
+	if (vcpu->kvm->arch.arm_pmu)
+		nr_guest_cnt_max = vcpu->kvm->arch.arm_pmu->hpmn_max;
+
+	if (kvm_vcpu_pmu_is_partitioned(vcpu)) {
+		if (cpus_have_final_cap(ARM64_HAS_HPMN0))
+			return nr_guest_cnt;
+		else if (nr_guest_cnt > 0)
+			return nr_guest_cnt;
+		else if (nr_guest_cnt_max > 0)
+			return nr_guest_cnt_max;
+	}
+
+	return nr_host_cnt_max;
+}
-- 
2.52.0.239.gd5f0c6e74e-goog



From coltonlewis at google.com  Tue Dec  9 12:51:15 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Tue,  9 Dec 2025 20:51:15 +0000
Subject: [PATCH v5 18/24] KVM: arm64: Enforce PMU event filter at vcpu_load()
In-Reply-To: <20251209205121.1871534-1-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
Message-ID: <20251209205121.1871534-19-coltonlewis@google.com>

The KVM API for event filtering says that counters do not count when
blocked by the event filter. To enforce that, the event filter must be
rechecked on every load since it might have changed since the last
time the guest wrote a value. If the event is filtered, exclude
counting at all exception levels before writing the hardware.

Signed-off-by: Colton Lewis <coltonlewis at google.com>
---
 arch/arm64/kvm/pmu-direct.c | 44 +++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/arch/arm64/kvm/pmu-direct.c b/arch/arm64/kvm/pmu-direct.c
index 71977d24f489a..8d0d6d1a0d851 100644
--- a/arch/arm64/kvm/pmu-direct.c
+++ b/arch/arm64/kvm/pmu-direct.c
@@ -221,6 +221,49 @@ u8 kvm_pmu_hpmn(struct kvm_vcpu *vcpu)
 	return nr_host_cnt_max;
 }
 
+/**
+ * kvm_pmu_apply_event_filter()
+ * @vcpu: Pointer to vcpu struct
+ *
+ * To uphold the guarantee of the KVM PMU event filter, we must ensure
+ * no counter counts if the event is filtered. Accomplish this by
+ * filtering all exception levels if the event is filtered.
+ */
+static void kvm_pmu_apply_event_filter(struct kvm_vcpu *vcpu)
+{
+	struct arm_pmu *pmu = vcpu->kvm->arch.arm_pmu;
+	u64 evtyper_set = ARMV8_PMU_EXCLUDE_EL0 |
+		ARMV8_PMU_EXCLUDE_EL1;
+	u64 evtyper_clr = ARMV8_PMU_INCLUDE_EL2;
+	u8 i;
+	u64 val;
+	u64 evsel;
+
+	if (!pmu)
+		return;
+
+	for (i = 0; i < pmu->hpmn_max; i++) {
+		val = __vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i);
+		evsel = val & kvm_pmu_event_mask(vcpu->kvm);
+
+		if (vcpu->kvm->arch.pmu_filter &&
+		    !test_bit(evsel, vcpu->kvm->arch.pmu_filter))
+			val |= evtyper_set;
+
+		val &= ~evtyper_clr;
+		write_pmevtypern(i, val);
+	}
+
+	val = __vcpu_sys_reg(vcpu, PMCCFILTR_EL0);
+
+	if (vcpu->kvm->arch.pmu_filter &&
+	    !test_bit(ARMV8_PMUV3_PERFCTR_CPU_CYCLES, vcpu->kvm->arch.pmu_filter))
+		val |= evtyper_set;
+
+	val &= ~evtyper_clr;
+	write_pmccfiltr(val);
+}
+
 /**
  * kvm_pmu_load() - Load untrapped PMU registers
  * @vcpu: Pointer to struct kvm_vcpu
@@ -244,6 +287,7 @@ void kvm_pmu_load(struct kvm_vcpu *vcpu)
 		return;
 
 	pmu = vcpu->kvm->arch.arm_pmu;
+	kvm_pmu_apply_event_filter(vcpu);
 
 	for (i = 0; i < pmu->hpmn_max; i++) {
 		val = __vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i);
-- 
2.52.0.239.gd5f0c6e74e-goog



From coltonlewis at google.com  Tue Dec  9 12:51:14 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Tue,  9 Dec 2025 20:51:14 +0000
Subject: [PATCH v5 17/24] KVM: arm64: Context swap Partitioned PMU guest registers
In-Reply-To: <20251209205121.1871534-1-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
Message-ID: <20251209205121.1871534-18-coltonlewis@google.com>

Save and restore newly untrapped registers that can be directly
accessed by the guest when the PMU is partitioned.

* PMEVCNTRn_EL0
* PMCCNTR_EL0
* PMICNTR_EL0
* PMUSERENR_EL0
* PMSELR_EL0
* PMCR_EL0
* PMCNTEN_EL0
* PMINTEN_EL1

If we know we are not using FGT (that is, trapping everything), then
return immediately. Either the PMU is not partitioned, or it is but
all register writes are being written through the VCPU fields to
hardware, so all values are fresh.

Since we are taking over context switching, avoid the writes to
PMSELR_EL0 and PMUSERENR_EL0 that would normally occur in
__{,de}activate_traps_common()

Signed-off-by: Colton Lewis <coltonlewis at google.com>
---
 arch/arm64/include/asm/kvm_pmu.h        |   4 +
 arch/arm64/kvm/arm.c                    |   2 +
 arch/arm64/kvm/hyp/include/hyp/switch.h |   4 +-
 arch/arm64/kvm/pmu-direct.c             | 112 ++++++++++++++++++++++++
 4 files changed, 120 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_pmu.h b/arch/arm64/include/asm/kvm_pmu.h
index 8b634112eded2..25a5eb8c623da 100644
--- a/arch/arm64/include/asm/kvm_pmu.h
+++ b/arch/arm64/include/asm/kvm_pmu.h
@@ -103,6 +103,8 @@ void kvm_pmu_host_counters_disable(void);
 
 u8 kvm_pmu_guest_num_counters(struct kvm_vcpu *vcpu);
 u8 kvm_pmu_hpmn(struct kvm_vcpu *vcpu);
+void kvm_pmu_load(struct kvm_vcpu *vcpu);
+void kvm_pmu_put(struct kvm_vcpu *vcpu);
 
 #if !defined(__KVM_NVHE_HYPERVISOR__)
 bool kvm_vcpu_pmu_is_partitioned(struct kvm_vcpu *vcpu);
@@ -184,6 +186,8 @@ static inline u8 kvm_pmu_hpmn(struct kvm_vcpu *vcpu)
 {
 	return 0;
 }
+static inline void kvm_pmu_load(struct kvm_vcpu *vcpu) {}
+static inline void kvm_pmu_put(struct kvm_vcpu *vcpu) {}
 static inline void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu,
 					     u64 select_idx, u64 val) {}
 static inline void kvm_pmu_set_counter_value_user(struct kvm_vcpu *vcpu,
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 43e92f35f56ab..1750df5944f6d 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -629,6 +629,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 		kvm_vcpu_load_vhe(vcpu);
 	kvm_arch_vcpu_load_fp(vcpu);
 	kvm_vcpu_pmu_restore_guest(vcpu);
+	kvm_pmu_load(vcpu);
 	if (kvm_arm_is_pvtime_enabled(&vcpu->arch))
 		kvm_make_request(KVM_REQ_RECORD_STEAL, vcpu);
 
@@ -671,6 +672,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
 	kvm_timer_vcpu_put(vcpu);
 	kvm_vgic_put(vcpu);
 	kvm_vcpu_pmu_restore_host(vcpu);
+	kvm_pmu_put(vcpu);
 	if (vcpu_has_nv(vcpu))
 		kvm_vcpu_put_hw_mmu(vcpu);
 	kvm_arm_vmid_clear_active();
diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index 40bd00df6c58f..bde79ec1a1836 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -311,7 +311,7 @@ static inline void __activate_traps_common(struct kvm_vcpu *vcpu)
 	 * counter, which could make a PMXEVCNTR_EL0 access UNDEF at
 	 * EL1 instead of being trapped to EL2.
 	 */
-	if (system_supports_pmuv3()) {
+	if (system_supports_pmuv3() && !kvm_vcpu_pmu_is_partitioned(vcpu)) {
 		write_sysreg(0, pmselr_el0);
 
 		ctxt_sys_reg(hctxt, PMUSERENR_EL0) = read_sysreg(pmuserenr_el0);
@@ -340,7 +340,7 @@ static inline void __deactivate_traps_common(struct kvm_vcpu *vcpu)
 	struct kvm_cpu_context *hctxt = host_data_ptr(host_ctxt);
 
 	write_sysreg(0, hstr_el2);
-	if (system_supports_pmuv3()) {
+	if (system_supports_pmuv3() && !kvm_vcpu_pmu_is_partitioned(vcpu)) {
 		write_sysreg(ctxt_sys_reg(hctxt, PMUSERENR_EL0), pmuserenr_el0);
 		vcpu_clear_flag(vcpu, PMUSERENR_ON_CPU);
 	}
diff --git a/arch/arm64/kvm/pmu-direct.c b/arch/arm64/kvm/pmu-direct.c
index 7fb4fb5c22e2a..71977d24f489a 100644
--- a/arch/arm64/kvm/pmu-direct.c
+++ b/arch/arm64/kvm/pmu-direct.c
@@ -9,6 +9,7 @@
 #include <linux/perf/arm_pmuv3.h>
 
 #include <asm/arm_pmuv3.h>
+#include <asm/kvm_emulate.h>
 #include <asm/kvm_pmu.h>
 
 /**
@@ -219,3 +220,114 @@ u8 kvm_pmu_hpmn(struct kvm_vcpu *vcpu)
 
 	return nr_host_cnt_max;
 }
+
+/**
+ * kvm_pmu_load() - Load untrapped PMU registers
+ * @vcpu: Pointer to struct kvm_vcpu
+ *
+ * Load all untrapped PMU registers from the VCPU into the PCPU. Mask
+ * to only bits belonging to guest-reserved counters and leave
+ * host-reserved counters alone in bitmask registers.
+ */
+void kvm_pmu_load(struct kvm_vcpu *vcpu)
+{
+	struct arm_pmu *pmu;
+	u64 mask;
+	u8 i;
+	u64 val;
+
+	/*
+	 * If we aren't using FGT then we are trapping everything
+	 * anyway, so no need to bother with the swap.
+	 */
+	if (!kvm_vcpu_pmu_use_fgt(vcpu))
+		return;
+
+	pmu = vcpu->kvm->arch.arm_pmu;
+
+	for (i = 0; i < pmu->hpmn_max; i++) {
+		val = __vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i);
+		write_pmevcntrn(i, val);
+	}
+
+	val = __vcpu_sys_reg(vcpu, PMCCNTR_EL0);
+	write_pmccntr(val);
+
+	val = __vcpu_sys_reg(vcpu, PMUSERENR_EL0);
+	write_pmuserenr(val);
+
+	val = __vcpu_sys_reg(vcpu, PMSELR_EL0);
+	write_pmselr(val);
+
+	/* Save only the stateful writable bits. */
+	val = __vcpu_sys_reg(vcpu, PMCR_EL0);
+	mask = ARMV8_PMU_PMCR_MASK &
+		~(ARMV8_PMU_PMCR_P | ARMV8_PMU_PMCR_C);
+	write_pmcr(val & mask);
+
+	/*
+	 * When handling these:
+	 * 1. Apply only the bits for guest counters (indicated by mask)
+	 * 2. Use the different registers for set and clear
+	 */
+	mask = kvm_pmu_guest_counter_mask(pmu);
+
+	val = __vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
+	write_pmcntenset(val & mask);
+	write_pmcntenclr(~val & mask);
+
+	val = __vcpu_sys_reg(vcpu, PMINTENSET_EL1);
+	write_pmintenset(val & mask);
+	write_pmintenclr(~val & mask);
+}
+
+/**
+ * kvm_pmu_put() - Put untrapped PMU registers
+ * @vcpu: Pointer to struct kvm_vcpu
+ *
+ * Put all untrapped PMU registers from the VCPU into the PCPU. Mask
+ * to only bits belonging to guest-reserved counters and leave
+ * host-reserved counters alone in bitmask registers.
+ */
+void kvm_pmu_put(struct kvm_vcpu *vcpu)
+{
+	struct arm_pmu *pmu;
+	u64 mask;
+	u8 i;
+	u64 val;
+
+	/*
+	 * If we aren't using FGT then we are trapping everything
+	 * anyway, so no need to bother with the swap.
+	 */
+	if (!kvm_vcpu_pmu_use_fgt(vcpu))
+		return;
+
+	pmu = vcpu->kvm->arch.arm_pmu;
+
+	for (i = 0; i < pmu->hpmn_max; i++) {
+		val = read_pmevcntrn(i);
+		__vcpu_assign_sys_reg(vcpu, PMEVCNTR0_EL0 + i, val);
+	}
+
+	val = read_pmccntr();
+	__vcpu_assign_sys_reg(vcpu, PMCCNTR_EL0, val);
+
+	val = read_pmuserenr();
+	__vcpu_assign_sys_reg(vcpu, PMUSERENR_EL0, val);
+
+	val = read_pmselr();
+	__vcpu_assign_sys_reg(vcpu, PMSELR_EL0, val);
+
+	val = read_pmcr();
+	__vcpu_assign_sys_reg(vcpu, PMCR_EL0, val);
+
+	/* Mask these to only save the guest relevant bits. */
+	mask = kvm_pmu_guest_counter_mask(pmu);
+
+	val = read_pmcntenset();
+	__vcpu_assign_sys_reg(vcpu, PMCNTENSET_EL0, val & mask);
+
+	val = read_pmintenset();
+	__vcpu_assign_sys_reg(vcpu, PMINTENSET_EL1, val & mask);
+}
-- 
2.52.0.239.gd5f0c6e74e-goog



From coltonlewis at google.com  Tue Dec  9 12:51:11 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Tue,  9 Dec 2025 20:51:11 +0000
Subject: [PATCH v5 14/24] KVM: arm64: Write fast path PMU register handlers
In-Reply-To: <20251209205121.1871534-1-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
Message-ID: <20251209205121.1871534-15-coltonlewis@google.com>

We may want a partitioned PMU but not have FEAT_FGT to untrap the
specific registers that would normally be untrapped. Add a handler for
those registers in the fast path so we can still get a performance
boost from partitioning.

The idea is to handle traps for all the PMU registers quickly by
writing through to the hardware as possible instead of hooking into
the emulated vPMU as the standard handlers in sys_regs.c do. Since
context switching will not happen without FGT, make sure to write both
physical and virtual registers so they stay in sync.

To assist with that, fill of the gaps in arm_pmuv3.h for helper
functions to read and write PMU registers and lift some of the access
checking functions from sys_regs.c to pmu.c

Signed-off-by: Colton Lewis <coltonlewis at google.com>
---
 arch/arm64/include/asm/arm_pmuv3.h      |  37 ++++-
 arch/arm64/include/asm/kvm_pmu.h        |  25 +++
 arch/arm64/kvm/hyp/include/hyp/switch.h | 201 ++++++++++++++++++++++++
 arch/arm64/kvm/pmu.c                    |  40 +++++
 arch/arm64/kvm/sys_regs.c               |  41 +----
 5 files changed, 303 insertions(+), 41 deletions(-)

diff --git a/arch/arm64/include/asm/arm_pmuv3.h b/arch/arm64/include/asm/arm_pmuv3.h
index 3e25c0313263c..41ec6730ebc62 100644
--- a/arch/arm64/include/asm/arm_pmuv3.h
+++ b/arch/arm64/include/asm/arm_pmuv3.h
@@ -39,6 +39,16 @@ static inline unsigned long read_pmevtypern(int n)
 	return 0;
 }
 
+static inline void write_pmxevcntr(u64 val)
+{
+	write_sysreg(val, pmxevcntr_el0);
+}
+
+static inline u64 read_pmxevcntr(void)
+{
+	return read_sysreg(pmxevcntr_el0);
+}
+
 static inline unsigned long read_pmmir(void)
 {
 	return read_cpuid(PMMIR_EL1);
@@ -105,21 +115,41 @@ static inline void write_pmcntenset(u64 val)
 	write_sysreg(val, pmcntenset_el0);
 }
 
+static inline u64 read_pmcntenset(void)
+{
+	return read_sysreg(pmcntenset_el0);
+}
+
 static inline void write_pmcntenclr(u64 val)
 {
 	write_sysreg(val, pmcntenclr_el0);
 }
 
+static inline u64 read_pmcntenclr(void)
+{
+	return read_sysreg(pmcntenclr_el0);
+}
+
 static inline void write_pmintenset(u64 val)
 {
 	write_sysreg(val, pmintenset_el1);
 }
 
+static inline u64 read_pmintenset(void)
+{
+	return read_sysreg(pmintenset_el1);
+}
+
 static inline void write_pmintenclr(u64 val)
 {
 	write_sysreg(val, pmintenclr_el1);
 }
 
+static inline u64 read_pmintenclr(void)
+{
+	return read_sysreg(pmintenclr_el1);
+}
+
 static inline void write_pmccfiltr(u64 val)
 {
 	write_sysreg(val, pmccfiltr_el0);
@@ -160,11 +190,16 @@ static inline u64 read_pmovsclr(void)
 	return read_sysreg(pmovsclr_el0);
 }
 
-static inline void write_pmuserenr(u32 val)
+static inline void write_pmuserenr(u64 val)
 {
 	write_sysreg(val, pmuserenr_el0);
 }
 
+static inline u64 read_pmuserenr(void)
+{
+	return read_sysreg(pmuserenr_el0);
+}
+
 static inline void write_pmuacr(u64 val)
 {
 	write_sysreg_s(val, SYS_PMUACR_EL1);
diff --git a/arch/arm64/include/asm/kvm_pmu.h b/arch/arm64/include/asm/kvm_pmu.h
index 7297a697a4a62..60b8a48cad456 100644
--- a/arch/arm64/include/asm/kvm_pmu.h
+++ b/arch/arm64/include/asm/kvm_pmu.h
@@ -83,6 +83,11 @@ struct kvm_pmu_events *kvm_get_pmu_events(void);
 void kvm_set_pmu_events(u64 set, struct perf_event_attr *attr);
 void kvm_clr_pmu_events(u64 clr);
 bool kvm_set_pmuserenr(u64 val);
+bool check_pmu_access_disabled(struct kvm_vcpu *vcpu, u64 flags);
+bool pmu_access_el0_disabled(struct kvm_vcpu *vcpu);
+bool pmu_access_event_counter_el0_disabled(struct kvm_vcpu *vcpu);
+bool pmu_access_cycle_counter_el0_disabled(struct kvm_vcpu *vcpu);
+bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx);
 void kvm_vcpu_pmu_restore_guest(struct kvm_vcpu *vcpu);
 void kvm_vcpu_pmu_restore_host(struct kvm_vcpu *vcpu);
 void kvm_vcpu_pmu_resync_el0(void);
@@ -226,6 +231,26 @@ static inline bool kvm_set_pmuserenr(u64 val)
 {
 	return false;
 }
+static inline bool check_pmu_access_disabled(struct kvm_vcpu *vcpu, u64 flags)
+{
+	return false;
+}
+static inline bool pmu_access_el0_disabled(struct kvm_vcpu *vcpu)
+{
+	return false;
+}
+static inline bool pmu_access_event_counter_el0_disabled(struct kvm_vcpu *vcpu)
+{
+	return false;
+}
+static inline bool pmu_access_cycle_counter_el0_disabled(struct kvm_vcpu *vcpu)
+{
+	return false;
+}
+static inline bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx)
+{
+	return false;
+}
 static inline void kvm_vcpu_pmu_restore_guest(struct kvm_vcpu *vcpu) {}
 static inline void kvm_vcpu_pmu_restore_host(struct kvm_vcpu *vcpu) {}
 static inline void kvm_vcpu_reload_pmu(struct kvm_vcpu *vcpu) {}
diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index 6e8050f260f34..40bd00df6c58f 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -24,12 +24,14 @@
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_hyp.h>
 #include <asm/kvm_mmu.h>
+#include <asm/kvm_pmu.h>
 #include <asm/kvm_nested.h>
 #include <asm/fpsimd.h>
 #include <asm/debug-monitors.h>
 #include <asm/processor.h>
 #include <asm/traps.h>
 
+#include <../../sys_regs.h>
 #include "arm_psci.h"
 
 struct kvm_exception_table_entry {
@@ -768,6 +770,202 @@ static bool handle_ampere1_tcr(struct kvm_vcpu *vcpu)
 	return true;
 }
 
+/**
+ * handle_pmu_reg() - Handle fast access to most PMU regs
+ * @vcpu: Ponter to kvm_vcpu struct
+ * @p: System register parameters (read/write, Op0, Op1, CRm, CRn, Op2)
+ * @reg: VCPU register identifier
+ * @rt: Target general register
+ * @val: Value to write
+ * @readfn: Sysreg read function
+ * @writefn: Sysreg write function
+ *
+ * Handle fast access to most PMU regs. Writethrough to the physical
+ * register. This function is a wrapper for the simplest case, but
+ * sadly there aren't many of those.
+ *
+ * Always return true. The boolean makes usage more consistent with
+ * similar functions.
+ *
+ * Return: True
+ */
+static bool handle_pmu_reg(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			   enum vcpu_sysreg reg, u8 rt, u64 val,
+			   u64 (*readfn)(void), void (*writefn)(u64))
+{
+	if (p->is_write) {
+		__vcpu_assign_sys_reg(vcpu, reg, val);
+		writefn(val);
+	} else {
+		vcpu_set_reg(vcpu, rt, readfn());
+	}
+
+	return true;
+}
+
+/**
+ * kvm_hyp_handle_pmu_regs() - Fast handler for PMU registers
+ * @vcpu: Pointer to vcpu struct
+ *
+ * This handler immediately writes through certain PMU registers when
+ * we have a partitioned PMU (that is, MDCR_EL2.HPMN is set to reserve
+ * a range of counters for the guest) but the machine does not have
+ * FEAT_FGT to selectively untrap the registers we want.
+ *
+ * Return: True if the exception was successfully handled, false otherwise
+ */
+static bool kvm_hyp_handle_pmu_regs(struct kvm_vcpu *vcpu)
+{
+	struct sys_reg_params p;
+	u64 esr;
+	u32 sysreg;
+	u8 rt;
+	u64 val;
+	u64 mask;
+	u8 idx;
+	bool ret;
+
+	if (!kvm_vcpu_pmu_is_partitioned(vcpu)
+	    || pmu_access_el0_disabled(vcpu))
+		return false;
+
+	esr = kvm_vcpu_get_esr(vcpu);
+	p = esr_sys64_to_params(esr);
+	sysreg = esr_sys64_to_sysreg(esr);
+	rt = kvm_vcpu_sys_get_rt(vcpu);
+	val = vcpu_get_reg(vcpu, rt);
+
+	switch (sysreg) {
+	case SYS_PMCR_EL0:
+		mask = ARMV8_PMU_PMCR_MASK;
+
+		if (p.is_write) {
+			write_pmcr(val);
+			mask &= ~(ARMV8_PMU_PMCR_P | ARMV8_PMU_PMCR_C);
+			__vcpu_assign_sys_reg(vcpu, PMCR_EL0, val & mask);
+		} else {
+			val = u64_replace_bits(
+				read_pmcr(),
+				vcpu->kvm->arch.nr_pmu_counters,
+				ARMV8_PMU_PMCR_N);
+			vcpu_set_reg(vcpu, rt, val);
+		}
+
+		ret = true;
+		break;
+	case SYS_PMUSERENR_EL0:
+		mask = ARMV8_PMU_USERENR_MASK;
+		ret = handle_pmu_reg(vcpu, &p, PMUSERENR_EL0, rt, val & mask,
+				     &read_pmuserenr, &write_pmuserenr);
+		break;
+	case SYS_PMSELR_EL0:
+		mask = PMSELR_EL0_SEL_MASK;
+
+		if (pmu_access_event_counter_el0_disabled(vcpu))
+			return false;
+
+		ret = handle_pmu_reg(vcpu, &p, PMSELR_EL0, rt, val & mask,
+				     &read_pmselr, &write_pmselr);
+		break;
+	case SYS_PMINTENCLR_EL1:
+		mask = kvm_pmu_accessible_counter_mask(vcpu);
+
+		if (p.is_write) {
+			__vcpu_rmw_sys_reg(vcpu, PMINTENSET_EL1, &=, ~(val & mask));
+			write_pmintenclr(val);
+		} else {
+			val = read_pmintenclr();
+			vcpu_set_reg(vcpu, rt, val & mask);
+		}
+		ret = true;
+
+		break;
+	case SYS_PMINTENSET_EL1:
+		mask = kvm_pmu_accessible_counter_mask(vcpu);
+
+		if (p.is_write) {
+			__vcpu_rmw_sys_reg(vcpu, PMINTENSET_EL1, |=, val & mask);
+			write_pmintenset(val);
+		} else {
+			val = read_pmintenset();
+			vcpu_set_reg(vcpu, rt, val & mask);
+		}
+
+		ret = true;
+		break;
+	case SYS_PMCNTENCLR_EL0:
+		mask = kvm_pmu_accessible_counter_mask(vcpu);
+
+		if (p.is_write) {
+			__vcpu_rmw_sys_reg(vcpu, PMCNTENSET_EL0, &=, ~(val & mask));
+			write_pmcntenclr(val);
+		} else {
+			val = read_pmcntenclr();
+			vcpu_set_reg(vcpu, rt, val & mask);
+		}
+
+		ret = true;
+		break;
+	case SYS_PMCNTENSET_EL0:
+		mask = kvm_pmu_accessible_counter_mask(vcpu);
+
+		if (p.is_write) {
+			__vcpu_rmw_sys_reg(vcpu, PMCNTENSET_EL0, |=, val & mask);
+			write_pmcntenset(val);
+		} else {
+			val = read_pmcntenset();
+			vcpu_set_reg(vcpu, rt, val & mask);
+		}
+
+		ret = true;
+		break;
+	case SYS_PMCCNTR_EL0:
+		if (pmu_access_cycle_counter_el0_disabled(vcpu))
+			return false;
+
+		ret = handle_pmu_reg(vcpu, &p, PMCCNTR_EL0, rt, val,
+				     &read_pmccntr, &write_pmccntr);
+		break;
+	case SYS_PMXEVCNTR_EL0:
+		idx = FIELD_GET(PMSELR_EL0_SEL, read_pmselr());
+
+		if (pmu_access_event_counter_el0_disabled(vcpu))
+			return false;
+
+		if (!pmu_counter_idx_valid(vcpu, idx))
+			return false;
+
+		ret = handle_pmu_reg(vcpu, &p, PMEVCNTR0_EL0 + idx, rt, val,
+				     &read_pmxevcntr, &write_pmxevcntr);
+		break;
+	case SYS_PMEVCNTRn_EL0(0) ... SYS_PMEVCNTRn_EL0(30):
+		idx = ((p.CRm & 3) << 3) | (p.Op2 & 7);
+
+		if (pmu_access_event_counter_el0_disabled(vcpu))
+			return false;
+
+		if (!pmu_counter_idx_valid(vcpu, idx))
+			return false;
+
+		if (p.is_write) {
+			write_pmevcntrn(idx, val);
+			__vcpu_assign_sys_reg(vcpu, PMEVCNTR0_EL0 + idx, val);
+		} else {
+			vcpu_set_reg(vcpu, rt, read_pmevcntrn(idx));
+		}
+
+		ret = true;
+		break;
+	default:
+		ret = false;
+	}
+
+	if (ret)
+		__kvm_skip_instr(vcpu);
+
+	return ret;
+}
+
 static inline bool kvm_hyp_handle_sysreg(struct kvm_vcpu *vcpu, u64 *exit_code)
 {
 	if (cpus_have_final_cap(ARM64_WORKAROUND_CAVIUM_TX2_219_TVM) &&
@@ -785,6 +983,9 @@ static inline bool kvm_hyp_handle_sysreg(struct kvm_vcpu *vcpu, u64 *exit_code)
 	if (kvm_handle_cntxct(vcpu))
 		return true;
 
+	if (kvm_hyp_handle_pmu_regs(vcpu))
+		return true;
+
 	return false;
 }
 
diff --git a/arch/arm64/kvm/pmu.c b/arch/arm64/kvm/pmu.c
index 79b7ea037153a..1fd012f8ff4a9 100644
--- a/arch/arm64/kvm/pmu.c
+++ b/arch/arm64/kvm/pmu.c
@@ -884,3 +884,43 @@ u64 kvm_vcpu_read_pmcr(struct kvm_vcpu *vcpu)
 
 	return u64_replace_bits(pmcr, n, ARMV8_PMU_PMCR_N);
 }
+
+bool check_pmu_access_disabled(struct kvm_vcpu *vcpu, u64 flags)
+{
+	u64 reg = __vcpu_sys_reg(vcpu, PMUSERENR_EL0);
+	bool enabled = (reg & flags) || vcpu_mode_priv(vcpu);
+
+	if (!enabled)
+		kvm_inject_undefined(vcpu);
+
+	return !enabled;
+}
+
+bool pmu_access_el0_disabled(struct kvm_vcpu *vcpu)
+{
+	return check_pmu_access_disabled(vcpu, ARMV8_PMU_USERENR_EN);
+}
+
+bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx)
+{
+	u64 pmcr, val;
+
+	pmcr = kvm_vcpu_read_pmcr(vcpu);
+	val = FIELD_GET(ARMV8_PMU_PMCR_N, pmcr);
+	if (idx >= val && idx != ARMV8_PMU_CYCLE_IDX) {
+		kvm_inject_undefined(vcpu);
+		return false;
+	}
+
+	return true;
+}
+
+bool pmu_access_cycle_counter_el0_disabled(struct kvm_vcpu *vcpu)
+{
+	return check_pmu_access_disabled(vcpu, ARMV8_PMU_USERENR_CR | ARMV8_PMU_USERENR_EN);
+}
+
+bool pmu_access_event_counter_el0_disabled(struct kvm_vcpu *vcpu)
+{
+	return check_pmu_access_disabled(vcpu, ARMV8_PMU_USERENR_ER | ARMV8_PMU_USERENR_EN);
+}
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index bee892db9ca8b..70104087b6c7b 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -29,6 +29,7 @@
 #include <asm/kvm_hyp.h>
 #include <asm/kvm_mmu.h>
 #include <asm/kvm_nested.h>
+#include <asm/kvm_pmu.h>
 #include <asm/perf_event.h>
 #include <asm/sysreg.h>
 
@@ -970,37 +971,11 @@ static u64 reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 	return __vcpu_sys_reg(vcpu, r->reg);
 }
 
-static bool check_pmu_access_disabled(struct kvm_vcpu *vcpu, u64 flags)
-{
-	u64 reg = __vcpu_sys_reg(vcpu, PMUSERENR_EL0);
-	bool enabled = (reg & flags) || vcpu_mode_priv(vcpu);
-
-	if (!enabled)
-		kvm_inject_undefined(vcpu);
-
-	return !enabled;
-}
-
-static bool pmu_access_el0_disabled(struct kvm_vcpu *vcpu)
-{
-	return check_pmu_access_disabled(vcpu, ARMV8_PMU_USERENR_EN);
-}
-
 static bool pmu_write_swinc_el0_disabled(struct kvm_vcpu *vcpu)
 {
 	return check_pmu_access_disabled(vcpu, ARMV8_PMU_USERENR_SW | ARMV8_PMU_USERENR_EN);
 }
 
-static bool pmu_access_cycle_counter_el0_disabled(struct kvm_vcpu *vcpu)
-{
-	return check_pmu_access_disabled(vcpu, ARMV8_PMU_USERENR_CR | ARMV8_PMU_USERENR_EN);
-}
-
-static bool pmu_access_event_counter_el0_disabled(struct kvm_vcpu *vcpu)
-{
-	return check_pmu_access_disabled(vcpu, ARMV8_PMU_USERENR_ER | ARMV8_PMU_USERENR_EN);
-}
-
 static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			const struct sys_reg_desc *r)
 {
@@ -1067,20 +1042,6 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
-static bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx)
-{
-	u64 pmcr, val;
-
-	pmcr = kvm_vcpu_read_pmcr(vcpu);
-	val = FIELD_GET(ARMV8_PMU_PMCR_N, pmcr);
-	if (idx >= val && idx != ARMV8_PMU_CYCLE_IDX) {
-		kvm_inject_undefined(vcpu);
-		return false;
-	}
-
-	return true;
-}
-
 static int get_pmu_evcntr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
 			  u64 *val)
 {
-- 
2.52.0.239.gd5f0c6e74e-goog



From coltonlewis at google.com  Tue Dec  9 12:51:17 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Tue,  9 Dec 2025 20:51:17 +0000
Subject: [PATCH v5 20/24] perf: arm_pmuv3: Handle IRQs for Partitioned PMU
 guest counters
In-Reply-To: <20251209205121.1871534-1-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
Message-ID: <20251209205121.1871534-21-coltonlewis@google.com>

Because ARM hardware is not yet capable of direct interrupt injection
into guests, guest counters will still trigger interrupts that need to
be handled by the host PMU interrupt handler. Clear the overflow flags
in hardware to handle the interrupt as normal, but record which guest
overflow flags were set in the virtual overflow register for later
injecting the interrupt into the guest.

Signed-off-by: Colton Lewis <coltonlewis at google.com>
---
 arch/arm/include/asm/arm_pmuv3.h |  6 ++++++
 arch/arm64/include/asm/kvm_pmu.h |  2 ++
 arch/arm64/kvm/pmu-direct.c      | 17 +++++++++++++++++
 drivers/perf/arm_pmuv3.c         |  9 +++++++++
 4 files changed, 34 insertions(+)

diff --git a/arch/arm/include/asm/arm_pmuv3.h b/arch/arm/include/asm/arm_pmuv3.h
index 3ea5741d213d8..485d2f08ac113 100644
--- a/arch/arm/include/asm/arm_pmuv3.h
+++ b/arch/arm/include/asm/arm_pmuv3.h
@@ -180,6 +180,11 @@ static inline void write_pmintenset(u32 val)
 	write_sysreg(val, PMINTENSET);
 }
 
+static inline u32 read_pmintenset(void)
+{
+	return read_sysreg(PMINTENSET);
+}
+
 static inline void write_pmintenclr(u32 val)
 {
 	write_sysreg(val, PMINTENCLR);
@@ -249,6 +254,7 @@ static inline u64 kvm_pmu_guest_counter_mask(struct arm_pmu *pmu)
 	return ~0;
 }
 
+static inline void kvm_pmu_handle_guest_irq(u64 govf) {}
 
 /* PMU Version in DFR Register */
 #define ARMV8_PMU_DFR_VER_NI        0
diff --git a/arch/arm64/include/asm/kvm_pmu.h b/arch/arm64/include/asm/kvm_pmu.h
index 43aa334dce517..e4cbab0fd09cf 100644
--- a/arch/arm64/include/asm/kvm_pmu.h
+++ b/arch/arm64/include/asm/kvm_pmu.h
@@ -101,6 +101,7 @@ u64 kvm_pmu_host_counter_mask(struct arm_pmu *pmu);
 u64 kvm_pmu_guest_counter_mask(struct arm_pmu *pmu);
 void kvm_pmu_host_counters_enable(void);
 void kvm_pmu_host_counters_disable(void);
+void kvm_pmu_handle_guest_irq(u64 govf);
 
 u8 kvm_pmu_guest_num_counters(struct kvm_vcpu *vcpu);
 u8 kvm_pmu_hpmn(struct kvm_vcpu *vcpu);
@@ -322,6 +323,7 @@ static inline u64 kvm_pmu_guest_counter_mask(void *pmu)
 
 static inline void kvm_pmu_host_counters_enable(void) {}
 static inline void kvm_pmu_host_counters_disable(void) {}
+static inline void kvm_pmu_handle_guest_irq(u64 govf) {}
 
 #endif
 
diff --git a/arch/arm64/kvm/pmu-direct.c b/arch/arm64/kvm/pmu-direct.c
index c5767e2ebc651..76d8ed24c8646 100644
--- a/arch/arm64/kvm/pmu-direct.c
+++ b/arch/arm64/kvm/pmu-direct.c
@@ -396,3 +396,20 @@ void kvm_pmu_put(struct kvm_vcpu *vcpu)
 	val = read_pmintenset();
 	__vcpu_assign_sys_reg(vcpu, PMINTENSET_EL1, val & mask);
 }
+
+/**
+ * kvm_pmu_handle_guest_irq() - Record IRQs in guest counters
+ * @govf: Bitmask of guest overflowed counters
+ *
+ * Record IRQs from overflows in guest-reserved counters in the VCPU
+ * register for the guest to clear later.
+ */
+void kvm_pmu_handle_guest_irq(u64 govf)
+{
+	struct kvm_vcpu *vcpu = kvm_get_running_vcpu();
+
+	if (!vcpu)
+		return;
+
+	__vcpu_rmw_sys_reg(vcpu, PMOVSSET_EL0, |=, govf);
+}
diff --git a/drivers/perf/arm_pmuv3.c b/drivers/perf/arm_pmuv3.c
index 2bed99ba992d7..3c1a69f88b284 100644
--- a/drivers/perf/arm_pmuv3.c
+++ b/drivers/perf/arm_pmuv3.c
@@ -783,6 +783,8 @@ static u64 armv8pmu_getreset_flags(void)
 
 	/* Write to clear flags */
 	value &= ARMV8_PMU_CNT_MASK_ALL;
+	/* Only reset interrupt enabled counters. */
+	value &= read_pmintenset();
 	write_pmovsclr(value);
 
 	return value;
@@ -904,6 +906,7 @@ static void read_branch_records(struct pmu_hw_events *cpuc,
 static irqreturn_t armv8pmu_handle_irq(struct arm_pmu *cpu_pmu)
 {
 	u64 pmovsr;
+	u64 govf;
 	struct perf_sample_data data;
 	struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events);
 	struct pt_regs *regs;
@@ -961,6 +964,12 @@ static irqreturn_t armv8pmu_handle_irq(struct arm_pmu *cpu_pmu)
 		 */
 		perf_event_overflow(event, &data, regs);
 	}
+
+	govf = pmovsr & kvm_pmu_guest_counter_mask(cpu_pmu);
+
+	if (kvm_pmu_is_partitioned(cpu_pmu) && govf)
+		kvm_pmu_handle_guest_irq(govf);
+
 	armv8pmu_start(cpu_pmu);
 
 	return IRQ_HANDLED;
-- 
2.52.0.239.gd5f0c6e74e-goog



From coltonlewis at google.com  Tue Dec  9 12:51:16 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Tue,  9 Dec 2025 20:51:16 +0000
Subject: [PATCH v5 19/24] KVM: arm64: Implement lazy PMU context swaps
In-Reply-To: <20251209205121.1871534-1-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
Message-ID: <20251209205121.1871534-20-coltonlewis@google.com>

Since many guests will never touch the PMU, they need not pay the cost
of context swapping those registers.

Use an enum to implement a simple state machine for PMU register
access. The PMU either accesses registers virtually or physically.

Virtual access implies all PMU registers are trapped coarsely by
MDCR_EL2.TPM and therefore do not need to be context swapped. Physical
access implies some registers are untrapped through FGT and do need to
be context swapped. All vCPUs do virtual access by default and
transition to physical if the PMU is partitioned and the guest
actually tries a PMU access.

Signed-off-by: Colton Lewis <coltonlewis at google.com>
---
 arch/arm64/include/asm/kvm_host.h       |  1 +
 arch/arm64/include/asm/kvm_pmu.h        |  4 ++++
 arch/arm64/include/asm/kvm_types.h      |  7 ++++++-
 arch/arm64/kvm/debug.c                  |  2 +-
 arch/arm64/kvm/hyp/include/hyp/switch.h |  2 ++
 arch/arm64/kvm/pmu-direct.c             | 21 +++++++++++++++++++++
 arch/arm64/kvm/pmu.c                    |  7 +++++++
 arch/arm64/kvm/sys_regs.c               |  4 ++++
 8 files changed, 46 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index c7e52aaf469dc..f92027d8fdfd0 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -1373,6 +1373,7 @@ static inline bool kvm_system_needs_idmapped_vectors(void)
 	return cpus_have_final_cap(ARM64_SPECTRE_V3A);
 }
 
+void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu);
 void kvm_init_host_debug_data(void);
 void kvm_debug_init_vhe(void);
 void kvm_vcpu_load_debug(struct kvm_vcpu *vcpu);
diff --git a/arch/arm64/include/asm/kvm_pmu.h b/arch/arm64/include/asm/kvm_pmu.h
index 25a5eb8c623da..43aa334dce517 100644
--- a/arch/arm64/include/asm/kvm_pmu.h
+++ b/arch/arm64/include/asm/kvm_pmu.h
@@ -38,6 +38,7 @@ struct kvm_pmu {
 	int irq_num;
 	bool created;
 	bool irq_level;
+	enum vcpu_pmu_register_access access;
 };
 
 struct arm_pmu_entry {
@@ -106,6 +107,8 @@ u8 kvm_pmu_hpmn(struct kvm_vcpu *vcpu);
 void kvm_pmu_load(struct kvm_vcpu *vcpu);
 void kvm_pmu_put(struct kvm_vcpu *vcpu);
 
+void kvm_pmu_set_physical_access(struct kvm_vcpu *vcpu);
+
 #if !defined(__KVM_NVHE_HYPERVISOR__)
 bool kvm_vcpu_pmu_is_partitioned(struct kvm_vcpu *vcpu);
 bool kvm_vcpu_pmu_use_fgt(struct kvm_vcpu *vcpu);
@@ -188,6 +191,7 @@ static inline u8 kvm_pmu_hpmn(struct kvm_vcpu *vcpu)
 }
 static inline void kvm_pmu_load(struct kvm_vcpu *vcpu) {}
 static inline void kvm_pmu_put(struct kvm_vcpu *vcpu) {}
+static inline void kvm_pmu_set_physical_access(struct kvm_vcpu *vcpu) {}
 static inline void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu,
 					     u64 select_idx, u64 val) {}
 static inline void kvm_pmu_set_counter_value_user(struct kvm_vcpu *vcpu,
diff --git a/arch/arm64/include/asm/kvm_types.h b/arch/arm64/include/asm/kvm_types.h
index 9a126b9e2d7c9..9f67165359f5c 100644
--- a/arch/arm64/include/asm/kvm_types.h
+++ b/arch/arm64/include/asm/kvm_types.h
@@ -4,5 +4,10 @@
 
 #define KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE 40
 
-#endif /* _ASM_ARM64_KVM_TYPES_H */
+enum vcpu_pmu_register_access {
+	VCPU_PMU_ACCESS_UNSET,
+	VCPU_PMU_ACCESS_VIRTUAL,
+	VCPU_PMU_ACCESS_PHYSICAL,
+};
 
+#endif /* _ASM_ARM64_KVM_TYPES_H */
diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
index 0ab89c91e19cb..c2cf6b308ec60 100644
--- a/arch/arm64/kvm/debug.c
+++ b/arch/arm64/kvm/debug.c
@@ -34,7 +34,7 @@ static int cpu_has_spe(u64 dfr0)
  *  - Self-hosted Trace Filter controls (MDCR_EL2_TTRF)
  *  - Self-hosted Trace (MDCR_EL2_TTRF/MDCR_EL2_E2TB)
  */
-static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu)
+void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu)
 {
 	int hpmn = kvm_pmu_hpmn(vcpu);
 
diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index bde79ec1a1836..ea288a712bb5d 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -963,6 +963,8 @@ static bool kvm_hyp_handle_pmu_regs(struct kvm_vcpu *vcpu)
 	if (ret)
 		__kvm_skip_instr(vcpu);
 
+	kvm_pmu_set_physical_access(vcpu);
+
 	return ret;
 }
 
diff --git a/arch/arm64/kvm/pmu-direct.c b/arch/arm64/kvm/pmu-direct.c
index 8d0d6d1a0d851..c5767e2ebc651 100644
--- a/arch/arm64/kvm/pmu-direct.c
+++ b/arch/arm64/kvm/pmu-direct.c
@@ -73,6 +73,7 @@ bool kvm_vcpu_pmu_use_fgt(struct kvm_vcpu *vcpu)
 	u8 hpmn = vcpu->kvm->arch.nr_pmu_counters;
 
 	return kvm_vcpu_pmu_is_partitioned(vcpu) &&
+		vcpu->arch.pmu.access == VCPU_PMU_ACCESS_PHYSICAL &&
 		cpus_have_final_cap(ARM64_HAS_FGT) &&
 		(hpmn != 0 || cpus_have_final_cap(ARM64_HAS_HPMN0));
 }
@@ -92,6 +93,26 @@ u64 kvm_pmu_fgt2_bits(void)
 		| HDFGRTR2_EL2_nPMICNTR_EL0;
 }
 
+/**
+ * kvm_pmu_set_physical_access()
+ * @vcpu: Pointer to vcpu struct
+ *
+ * Reconfigure the guest for physical access of PMU hardware if
+ * allowed. This means reconfiguring mdcr_el2 and loading the vCPU
+ * state onto hardware.
+ *
+ */
+
+void kvm_pmu_set_physical_access(struct kvm_vcpu *vcpu)
+{
+	if (kvm_vcpu_pmu_is_partitioned(vcpu)
+	    && vcpu->arch.pmu.access == VCPU_PMU_ACCESS_VIRTUAL) {
+		vcpu->arch.pmu.access = VCPU_PMU_ACCESS_PHYSICAL;
+		kvm_arm_setup_mdcr_el2(vcpu);
+		kvm_pmu_load(vcpu);
+	}
+}
+
 /**
  * kvm_pmu_host_counter_mask() - Compute bitmask of host-reserved counters
  * @pmu: Pointer to arm_pmu struct
diff --git a/arch/arm64/kvm/pmu.c b/arch/arm64/kvm/pmu.c
index 48b39f096fa12..c9862e55a4049 100644
--- a/arch/arm64/kvm/pmu.c
+++ b/arch/arm64/kvm/pmu.c
@@ -471,6 +471,12 @@ int kvm_arm_pmu_v3_enable(struct kvm_vcpu *vcpu)
 	return 0;
 }
 
+static void kvm_pmu_register_init(struct kvm_vcpu *vcpu)
+{
+	if (vcpu->arch.pmu.access == VCPU_PMU_ACCESS_UNSET)
+		vcpu->arch.pmu.access = VCPU_PMU_ACCESS_VIRTUAL;
+}
+
 static int kvm_arm_pmu_v3_init(struct kvm_vcpu *vcpu)
 {
 	if (irqchip_in_kernel(vcpu->kvm)) {
@@ -496,6 +502,7 @@ static int kvm_arm_pmu_v3_init(struct kvm_vcpu *vcpu)
 	init_irq_work(&vcpu->arch.pmu.overflow_work,
 		      kvm_pmu_perf_overflow_notify_vcpu);
 
+	kvm_pmu_register_init(vcpu);
 	vcpu->arch.pmu.created = true;
 	return 0;
 }
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index f2ae761625a66..d73218706b834 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1197,6 +1197,8 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 		p->regval = __vcpu_sys_reg(vcpu, reg);
 	}
 
+	kvm_pmu_set_physical_access(vcpu);
+
 	return true;
 }
 
@@ -1302,6 +1304,8 @@ static bool access_pmovs(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 		p->regval = __vcpu_sys_reg(vcpu, PMOVSSET_EL0);
 	}
 
+	kvm_pmu_set_physical_access(vcpu);
+
 	return true;
 }
 
-- 
2.52.0.239.gd5f0c6e74e-goog



From coltonlewis at google.com  Tue Dec  9 12:51:18 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Tue,  9 Dec 2025 20:51:18 +0000
Subject: [PATCH v5 21/24] KVM: arm64: Inject recorded guest interrupts
In-Reply-To: <20251209205121.1871534-1-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
Message-ID: <20251209205121.1871534-22-coltonlewis@google.com>

When we re-enter the VM after handling a PMU interrupt, calculate
whether it was any of the guest counters that overflowed and inject an
interrupt into the guest if so.

Signed-off-by: Colton Lewis <coltonlewis at google.com>
---
 arch/arm64/include/asm/kvm_pmu.h |  2 ++
 arch/arm64/kvm/pmu-direct.c      | 20 ++++++++++++++++++++
 arch/arm64/kvm/pmu-emul.c        |  4 ++--
 arch/arm64/kvm/pmu.c             |  6 +++++-
 4 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_pmu.h b/arch/arm64/include/asm/kvm_pmu.h
index e4cbab0fd09cf..47e6f2a14e381 100644
--- a/arch/arm64/include/asm/kvm_pmu.h
+++ b/arch/arm64/include/asm/kvm_pmu.h
@@ -92,6 +92,8 @@ bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx);
 void kvm_vcpu_pmu_restore_guest(struct kvm_vcpu *vcpu);
 void kvm_vcpu_pmu_restore_host(struct kvm_vcpu *vcpu);
 void kvm_vcpu_pmu_resync_el0(void);
+bool kvm_pmu_emul_overflow_status(struct kvm_vcpu *vcpu);
+bool kvm_pmu_part_overflow_status(struct kvm_vcpu *vcpu);
 
 #define kvm_vcpu_has_pmu(vcpu)					\
 	(vcpu_has_feature(vcpu, KVM_ARM_VCPU_PMU_V3))
diff --git a/arch/arm64/kvm/pmu-direct.c b/arch/arm64/kvm/pmu-direct.c
index 76d8ed24c8646..2ee99d6d2b6c1 100644
--- a/arch/arm64/kvm/pmu-direct.c
+++ b/arch/arm64/kvm/pmu-direct.c
@@ -413,3 +413,23 @@ void kvm_pmu_handle_guest_irq(u64 govf)
 
 	__vcpu_rmw_sys_reg(vcpu, PMOVSSET_EL0, |=, govf);
 }
+
+/**
+ * kvm_pmu_part_overflow_status() - Determine if any guest counters have overflowed
+ * @vcpu: Ponter to struct kvm_vcpu
+ *
+ * Determine if any guest counters have overflowed and therefore an
+ * IRQ needs to be injected into the guest.
+ *
+ * Return: True if there was an overflow, false otherwise
+ */
+bool kvm_pmu_part_overflow_status(struct kvm_vcpu *vcpu)
+{
+	struct arm_pmu *pmu = vcpu->kvm->arch.arm_pmu;
+	u64 mask = kvm_pmu_guest_counter_mask(pmu);
+	u64 pmovs = __vcpu_sys_reg(vcpu, PMOVSSET_EL0);
+	u64 pmint = read_pmintenset();
+	u64 pmcr = read_pmcr();
+
+	return (pmcr & ARMV8_PMU_PMCR_E) && (mask & pmovs & pmint);
+}
diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c
index bcaa9f7a8ca28..6f41fc3e3f74b 100644
--- a/arch/arm64/kvm/pmu-emul.c
+++ b/arch/arm64/kvm/pmu-emul.c
@@ -268,7 +268,7 @@ void kvm_pmu_reprogram_counter_mask(struct kvm_vcpu *vcpu, u64 val)
  * counter where the values of the global enable control, PMOVSSET_EL0[n], and
  * PMINTENSET_EL1[n] are all 1.
  */
-bool kvm_pmu_overflow_status(struct kvm_vcpu *vcpu)
+bool kvm_pmu_emul_overflow_status(struct kvm_vcpu *vcpu)
 {
 	u64 reg = __vcpu_sys_reg(vcpu, PMOVSSET_EL0);
 
@@ -405,7 +405,7 @@ static void kvm_pmu_perf_overflow(struct perf_event *perf_event,
 		kvm_pmu_counter_increment(vcpu, BIT(idx + 1),
 					  ARMV8_PMUV3_PERFCTR_CHAIN);
 
-	if (kvm_pmu_overflow_status(vcpu)) {
+	if (kvm_pmu_emul_overflow_status(vcpu)) {
 		kvm_make_request(KVM_REQ_IRQ_PENDING, vcpu);
 
 		if (!in_nmi())
diff --git a/arch/arm64/kvm/pmu.c b/arch/arm64/kvm/pmu.c
index c9862e55a4049..e1332a158dfc8 100644
--- a/arch/arm64/kvm/pmu.c
+++ b/arch/arm64/kvm/pmu.c
@@ -407,7 +407,11 @@ static void kvm_pmu_update_state(struct kvm_vcpu *vcpu)
 	struct kvm_pmu *pmu = &vcpu->arch.pmu;
 	bool overflow;
 
-	overflow = kvm_pmu_overflow_status(vcpu);
+	if (kvm_vcpu_pmu_is_partitioned(vcpu))
+		overflow = kvm_pmu_part_overflow_status(vcpu);
+	else
+		overflow = kvm_pmu_emul_overflow_status(vcpu);
+
 	if (pmu->irq_level == overflow)
 		return;
 
-- 
2.52.0.239.gd5f0c6e74e-goog



From coltonlewis at google.com  Tue Dec  9 12:51:19 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Tue,  9 Dec 2025 20:51:19 +0000
Subject: [PATCH v5 22/24] KVM: arm64: Add KVM_CAP to partition the PMU
In-Reply-To: <20251209205121.1871534-1-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
Message-ID: <20251209205121.1871534-23-coltonlewis@google.com>

Add KVM_CAP_ARM_PARTITION_PMU to enable the partitioned PMU for a
given VM. This capability is allowed where PMUv3 and VHE are supported
and the host driver was configured with
arm_pmuv3.reserved_host_counters.

Ordering is enforced such that this must be called before the vCPUs
are created to avoid the possibility the guest is already using one
PMU configuration that gets switched out from under it.

The enabled capability is tracked by the new flag
KVM_ARCH_FLAG_PARTITIONED_PMU_ENABLED.

Signed-off-by: Colton Lewis <coltonlewis at google.com>
---
 Documentation/virt/kvm/api.rst    | 24 +++++++++++++++++++++
 arch/arm64/include/asm/kvm_host.h |  2 ++
 arch/arm64/include/asm/kvm_pmu.h  |  9 ++++++++
 arch/arm64/kvm/arm.c              | 15 +++++++++++++
 arch/arm64/kvm/pmu-direct.c       | 35 ++++++++++++++++++++++++++++---
 include/uapi/linux/kvm.h          |  1 +
 6 files changed, 83 insertions(+), 3 deletions(-)

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 57061fa29e6a0..ef1b22f20ee71 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -8703,6 +8703,30 @@ This capability indicate to the userspace whether a PFNMAP memory region
 can be safely mapped as cacheable. This relies on the presence of
 force write back (FWB) feature support on the hardware.
 
+
+7.245 KVM_CAP_ARM_PARTITION_PMU
+-------------------------------------
+
+:Architectures: arm64
+:Target: VM
+:Parameters: arg[0] is a boolean that enables or disables the capability
+:Returns: 0 on success
+	  -EPERM if host doesn't support
+	  -EBUSY if vPMU was already created
+
+This API controls the PMU implementation used for VMs. The capability
+is only available if the host PMUv3 driver was configured for
+partitioning via the module parameter
+``arm-pmuv3.reserved_guest_counters=[0-$NR_COUNTERS]``. When enabled,
+VMs are configured to have direct hardware access to the most
+frequently used registers for the counters configured by the
+aforementioned module parameters, bypassing the KVM traps in the
+standard emulated PMU implementation and reducing overhead of any
+guest software that uses PMU capabilities such as ``perf``.
+
+If the host driver was configured for partitioning but the partitioned
+PMU is disabled through this interface, the VM will use the legacy PMU
+
 8. Other capabilities.
 ======================
 
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index f92027d8fdfd0..8431fdebcac43 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -349,6 +349,8 @@ struct kvm_arch {
 #define KVM_ARCH_FLAG_GUEST_HAS_SVE			9
 	/* MIDR_EL1, REVIDR_EL1, and AIDR_EL1 are writable from userspace */
 #define KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS		10
+	/* Partitioned PMU Enabled */
+#define KVM_ARCH_FLAG_PARTITION_PMU_ENABLED		11
 	unsigned long flags;
 
 	/* VM-wide vCPU feature set */
diff --git a/arch/arm64/include/asm/kvm_pmu.h b/arch/arm64/include/asm/kvm_pmu.h
index 47e6f2a14e381..6146120208e39 100644
--- a/arch/arm64/include/asm/kvm_pmu.h
+++ b/arch/arm64/include/asm/kvm_pmu.h
@@ -111,6 +111,8 @@ void kvm_pmu_load(struct kvm_vcpu *vcpu);
 void kvm_pmu_put(struct kvm_vcpu *vcpu);
 
 void kvm_pmu_set_physical_access(struct kvm_vcpu *vcpu);
+bool kvm_pmu_partition_ready(void);
+void kvm_pmu_partition_enable(struct kvm *kvm, bool enable);
 
 #if !defined(__KVM_NVHE_HYPERVISOR__)
 bool kvm_vcpu_pmu_is_partitioned(struct kvm_vcpu *vcpu);
@@ -327,6 +329,13 @@ static inline void kvm_pmu_host_counters_enable(void) {}
 static inline void kvm_pmu_host_counters_disable(void) {}
 static inline void kvm_pmu_handle_guest_irq(u64 govf) {}
 
+static inline bool kvm_pmu_partition_ready(void)
+{
+	return false;
+}
+
+static inline void kvm_pmu_partition_enable(struct kvm *kvm, bool enable) {}
+
 #endif
 
 #endif
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 1750df5944f6d..d09f272577277 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -20,6 +20,7 @@
 #include <linux/irqbypass.h>
 #include <linux/sched/stat.h>
 #include <linux/psci.h>
+#include <linux/perf/arm_pmu.h>
 #include <trace/events/kvm.h>
 
 #define CREATE_TRACE_POINTS
@@ -37,6 +38,7 @@
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_mmu.h>
 #include <asm/kvm_nested.h>
+#include <asm/kvm_pmu.h>
 #include <asm/kvm_pkvm.h>
 #include <asm/kvm_pmu.h>
 #include <asm/kvm_ptrauth.h>
@@ -132,6 +134,16 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
 		}
 		mutex_unlock(&kvm->lock);
 		break;
+	case KVM_CAP_ARM_PARTITION_PMU:
+		if (kvm->created_vcpus) {
+			r = -EBUSY;
+		} else if (!kvm_pmu_partition_ready()) {
+			r = -EPERM;
+		} else {
+			r = 0;
+			kvm_pmu_partition_enable(kvm, cap->args[0]);
+		}
+		break;
 	default:
 		break;
 	}
@@ -388,6 +400,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 	case KVM_CAP_ARM_PMU_V3:
 		r = kvm_supports_guest_pmuv3();
 		break;
+	case KVM_CAP_ARM_PARTITION_PMU:
+		r = kvm_pmu_partition_ready();
+		break;
 	case KVM_CAP_ARM_INJECT_SERROR_ESR:
 		r = cpus_have_final_cap(ARM64_HAS_RAS_EXTN);
 		break;
diff --git a/arch/arm64/kvm/pmu-direct.c b/arch/arm64/kvm/pmu-direct.c
index 2ee99d6d2b6c1..6cfba9caeea0e 100644
--- a/arch/arm64/kvm/pmu-direct.c
+++ b/arch/arm64/kvm/pmu-direct.c
@@ -45,8 +45,8 @@ bool kvm_pmu_is_partitioned(struct arm_pmu *pmu)
 }
 
 /**
- * kvm_vcpu_pmu_is_partitioned() - Determine if given VCPU has a partitioned PMU
- * @vcpu: Pointer to kvm_vcpu struct
+ * kvm_pmu_is_partitioned() - Determine if given VCPU has a partitioned PMU
+ * @kvm: Pointer to kvm_vcpu struct
  *
  * Determine if given VCPU has a partitioned PMU by extracting that
  * field and passing it to :c:func:`kvm_pmu_is_partitioned`
@@ -56,7 +56,36 @@ bool kvm_pmu_is_partitioned(struct arm_pmu *pmu)
 bool kvm_vcpu_pmu_is_partitioned(struct kvm_vcpu *vcpu)
 {
 	return kvm_pmu_is_partitioned(vcpu->kvm->arch.arm_pmu) &&
-		false;
+		test_bit(KVM_ARCH_FLAG_PARTITION_PMU_ENABLED, &vcpu->kvm->arch.flags);
+}
+
+/**
+ * kvm_pmu_partition_ready() - If we can enable/disable partition
+ *
+ * Return: true if allowed, false otherwise.
+ */
+bool kvm_pmu_partition_ready(void)
+{
+	return kvm_pmu_partition_supported() &&
+		kvm_supports_guest_pmuv3() &&
+		armv8pmu_hpmn_max > -1;
+}
+
+/**
+ * kvm_pmu_partition_enable() - Enable/disable partition flag
+ * @kvm: Pointer to vcpu
+ * @enable: Whether to enable or disable
+ *
+ * If we want to enable the partition, the guest is free to grab
+ * hardware by accessing PMU registers. Otherwise, the host maintains
+ * control.
+ */
+void kvm_pmu_partition_enable(struct kvm *kvm, bool enable)
+{
+	if (enable)
+		set_bit(KVM_ARCH_FLAG_PARTITION_PMU_ENABLED, &kvm->arch.flags);
+	else
+		clear_bit(KVM_ARCH_FLAG_PARTITION_PMU_ENABLED, &kvm->arch.flags);
 }
 
 /**
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 52f6000ab0208..2bb2f234df0e6 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -963,6 +963,7 @@ struct kvm_enable_cap {
 #define KVM_CAP_RISCV_MP_STATE_RESET 242
 #define KVM_CAP_ARM_CACHEABLE_PFNMAP_SUPPORTED 243
 #define KVM_CAP_GUEST_MEMFD_FLAGS 244
+#define KVM_CAP_ARM_PARTITION_PMU 245
 
 struct kvm_irq_routing_irqchip {
 	__u32 irqchip;
-- 
2.52.0.239.gd5f0c6e74e-goog



From coltonlewis at google.com  Tue Dec  9 12:51:20 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Tue,  9 Dec 2025 20:51:20 +0000
Subject: [PATCH v5 23/24] KVM: selftests: Add find_bit to KVM library
In-Reply-To: <20251209205121.1871534-1-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
Message-ID: <20251209205121.1871534-24-coltonlewis@google.com>

Some selftests have a dependency on find_bit and weren't compiling
separately without it, so I've added it to the KVM library here using
the same method as files like rbtree.c.

Signed-off-by: Colton Lewis <coltonlewis at google.com>
---
 tools/testing/selftests/kvm/Makefile.kvm   | 1 +
 tools/testing/selftests/kvm/lib/find_bit.c | 1 +
 2 files changed, 2 insertions(+)
 create mode 100644 tools/testing/selftests/kvm/lib/find_bit.c

diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 148d427ff24be..f44822b7d0e20 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -5,6 +5,7 @@ all:
 
 LIBKVM += lib/assert.c
 LIBKVM += lib/elf.c
+LIBKVM += lib/find_bit.c
 LIBKVM += lib/guest_modes.c
 LIBKVM += lib/io.c
 LIBKVM += lib/kvm_util.c
diff --git a/tools/testing/selftests/kvm/lib/find_bit.c b/tools/testing/selftests/kvm/lib/find_bit.c
new file mode 100644
index 0000000000000..67d9d9cbca85c
--- /dev/null
+++ b/tools/testing/selftests/kvm/lib/find_bit.c
@@ -0,0 +1 @@
+#include "../../../../lib/find_bit.c"
-- 
2.52.0.239.gd5f0c6e74e-goog



From coltonlewis at google.com  Tue Dec  9 12:51:21 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Tue,  9 Dec 2025 20:51:21 +0000
Subject: [PATCH v5 24/24] KVM: arm64: selftests: Add test case for partitioned PMU
In-Reply-To: <20251209205121.1871534-1-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
Message-ID: <20251209205121.1871534-25-coltonlewis@google.com>

Rerun all tests for a partitioned PMU in vpmu_counter_access.

Create an enum specifying whether we are testing the emulated or
partitioned PMU and all the test functions are modified to take the
implementation as an argument and make the difference in setup
appropriately.

Signed-off-by: Colton Lewis <coltonlewis at google.com>
---
 tools/include/uapi/linux/kvm.h                |  1 +
 .../selftests/kvm/arm64/vpmu_counter_access.c | 77 ++++++++++++++-----
 2 files changed, 57 insertions(+), 21 deletions(-)

diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h
index 52f6000ab0208..2bb2f234df0e6 100644
--- a/tools/include/uapi/linux/kvm.h
+++ b/tools/include/uapi/linux/kvm.h
@@ -963,6 +963,7 @@ struct kvm_enable_cap {
 #define KVM_CAP_RISCV_MP_STATE_RESET 242
 #define KVM_CAP_ARM_CACHEABLE_PFNMAP_SUPPORTED 243
 #define KVM_CAP_GUEST_MEMFD_FLAGS 244
+#define KVM_CAP_ARM_PARTITION_PMU 245
 
 struct kvm_irq_routing_irqchip {
 	__u32 irqchip;
diff --git a/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c b/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c
index ae36325c022fb..e68072e3e1326 100644
--- a/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c
+++ b/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c
@@ -25,9 +25,20 @@
 /* The cycle counter bit position that's common among the PMU registers */
 #define ARMV8_PMU_CYCLE_IDX		31
 
+enum pmu_impl {
+	EMULATED,
+	PARTITIONED
+};
+
+const char *pmu_impl_str[] = {
+	"Emulated",
+	"Partitioned"
+};
+
 struct vpmu_vm {
 	struct kvm_vm *vm;
 	struct kvm_vcpu *vcpu;
+	bool pmu_partitioned;
 };
 
 static struct vpmu_vm vpmu_vm;
@@ -399,7 +410,7 @@ static void guest_code(uint64_t expected_pmcr_n)
 }
 
 /* Create a VM that has one vCPU with PMUv3 configured. */
-static void create_vpmu_vm(void *guest_code)
+static void create_vpmu_vm(void *guest_code, enum pmu_impl impl)
 {
 	struct kvm_vcpu_init init;
 	uint8_t pmuver, ec;
@@ -409,6 +420,11 @@ static void create_vpmu_vm(void *guest_code)
 		.attr = KVM_ARM_VCPU_PMU_V3_IRQ,
 		.addr = (uint64_t)&irq,
 	};
+	bool partition = (impl == PARTITIONED);
+	struct kvm_enable_cap partition_cap = {
+		.cap = KVM_CAP_ARM_PARTITION_PMU,
+		.args[0] = partition,
+	};
 
 	/* The test creates the vpmu_vm multiple times. Ensure a clean state */
 	memset(&vpmu_vm, 0, sizeof(vpmu_vm));
@@ -420,6 +436,12 @@ static void create_vpmu_vm(void *guest_code)
 					guest_sync_handler);
 	}
 
+	if (kvm_has_cap(KVM_CAP_ARM_PARTITION_PMU)) {
+		vm_ioctl(vpmu_vm.vm, KVM_ENABLE_CAP, &partition_cap);
+		vpmu_vm.pmu_partitioned = partition;
+		pr_debug("Set PMU partitioning: %d\n", partition);
+	}
+
 	/* Create vCPU with PMUv3 */
 	kvm_get_default_vcpu_target(vpmu_vm.vm, &init);
 	init.features[0] |= (1 << KVM_ARM_VCPU_PMU_V3);
@@ -461,13 +483,14 @@ static void run_vcpu(struct kvm_vcpu *vcpu, uint64_t pmcr_n)
 	}
 }
 
-static void test_create_vpmu_vm_with_nr_counters(unsigned int nr_counters, bool expect_fail)
+static void test_create_vpmu_vm_with_nr_counters(
+	unsigned int nr_counters, enum pmu_impl impl, bool expect_fail)
 {
 	struct kvm_vcpu *vcpu;
 	unsigned int prev;
 	int ret;
 
-	create_vpmu_vm(guest_code);
+	create_vpmu_vm(guest_code, impl);
 	vcpu = vpmu_vm.vcpu;
 
 	prev = get_pmcr_n(vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_PMCR_EL0)));
@@ -489,7 +512,7 @@ static void test_create_vpmu_vm_with_nr_counters(unsigned int nr_counters, bool
  * Create a guest with one vCPU, set the PMCR_EL0.N for the vCPU to @pmcr_n,
  * and run the test.
  */
-static void run_access_test(uint64_t pmcr_n)
+static void run_access_test(uint64_t pmcr_n, enum pmu_impl impl)
 {
 	uint64_t sp;
 	struct kvm_vcpu *vcpu;
@@ -497,7 +520,7 @@ static void run_access_test(uint64_t pmcr_n)
 
 	pr_debug("Test with pmcr_n %lu\n", pmcr_n);
 
-	test_create_vpmu_vm_with_nr_counters(pmcr_n, false);
+	test_create_vpmu_vm_with_nr_counters(pmcr_n, impl, false);
 	vcpu = vpmu_vm.vcpu;
 
 	/* Save the initial sp to restore them later to run the guest again */
@@ -531,14 +554,14 @@ static struct pmreg_sets validity_check_reg_sets[] = {
  * Create a VM, and check if KVM handles the userspace accesses of
  * the PMU register sets in @validity_check_reg_sets[] correctly.
  */
-static void run_pmregs_validity_test(uint64_t pmcr_n)
+static void run_pmregs_validity_test(uint64_t pmcr_n, enum pmu_impl impl)
 {
 	int i;
 	struct kvm_vcpu *vcpu;
 	uint64_t set_reg_id, clr_reg_id, reg_val;
 	uint64_t valid_counters_mask, max_counters_mask;
 
-	test_create_vpmu_vm_with_nr_counters(pmcr_n, false);
+	test_create_vpmu_vm_with_nr_counters(pmcr_n, impl, false);
 	vcpu = vpmu_vm.vcpu;
 
 	valid_counters_mask = get_counters_mask(pmcr_n);
@@ -588,11 +611,11 @@ static void run_pmregs_validity_test(uint64_t pmcr_n)
  * the vCPU to @pmcr_n, which is larger than the host value.
  * The attempt should fail as @pmcr_n is too big to set for the vCPU.
  */
-static void run_error_test(uint64_t pmcr_n)
+static void run_error_test(uint64_t pmcr_n, enum pmu_impl impl)
 {
-	pr_debug("Error test with pmcr_n %lu (larger than the host)\n", pmcr_n);
+	pr_debug("Error test with pmcr_n %lu (larger than the host allows)\n", pmcr_n);
 
-	test_create_vpmu_vm_with_nr_counters(pmcr_n, true);
+	test_create_vpmu_vm_with_nr_counters(pmcr_n, impl, true);
 	destroy_vpmu_vm();
 }
 
@@ -600,11 +623,11 @@ static void run_error_test(uint64_t pmcr_n)
  * Return the default number of implemented PMU event counters excluding
  * the cycle counter (i.e. PMCR_EL0.N value) for the guest.
  */
-static uint64_t get_pmcr_n_limit(void)
+static uint64_t get_pmcr_n_limit(enum pmu_impl impl)
 {
 	uint64_t pmcr;
 
-	create_vpmu_vm(guest_code);
+	create_vpmu_vm(guest_code, impl);
 	pmcr = vcpu_get_reg(vpmu_vm.vcpu, KVM_ARM64_SYS_REG(SYS_PMCR_EL0));
 	destroy_vpmu_vm();
 	return get_pmcr_n(pmcr);
@@ -614,7 +637,7 @@ static bool kvm_supports_nr_counters_attr(void)
 {
 	bool supported;
 
-	create_vpmu_vm(NULL);
+	create_vpmu_vm(NULL, EMULATED);
 	supported = !__vcpu_has_device_attr(vpmu_vm.vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
 					    KVM_ARM_VCPU_PMU_V3_SET_NR_COUNTERS);
 	destroy_vpmu_vm();
@@ -622,22 +645,34 @@ static bool kvm_supports_nr_counters_attr(void)
 	return supported;
 }
 
-int main(void)
+void test_pmu(enum pmu_impl impl)
 {
 	uint64_t i, pmcr_n;
 
-	TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_PMU_V3));
-	TEST_REQUIRE(kvm_supports_vgic_v3());
-	TEST_REQUIRE(kvm_supports_nr_counters_attr());
+	pr_info("Testing PMU: Implementation = %s\n", pmu_impl_str[impl]);
+
+	pmcr_n = get_pmcr_n_limit(impl);
+	pr_debug("PMCR_EL0.N: Limit = %lu\n", pmcr_n);
 
-	pmcr_n = get_pmcr_n_limit();
 	for (i = 0; i <= pmcr_n; i++) {
-		run_access_test(i);
-		run_pmregs_validity_test(i);
+		run_access_test(i, impl);
+		run_pmregs_validity_test(i, impl);
 	}
 
 	for (i = pmcr_n + 1; i < ARMV8_PMU_MAX_COUNTERS; i++)
-		run_error_test(i);
+		run_error_test(i, impl);
+}
+
+int main(void)
+{
+	TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_PMU_V3));
+	TEST_REQUIRE(kvm_supports_vgic_v3());
+	TEST_REQUIRE(kvm_supports_nr_counters_attr());
+
+	test_pmu(EMULATED);
+
+	if (kvm_has_cap(KVM_CAP_ARM_PARTITION_PMU))
+		test_pmu(PARTITIONED);
 
 	return 0;
 }
-- 
2.52.0.239.gd5f0c6e74e-goog



From nicolas at ndufresne.ca  Tue Dec  9 12:57:32 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Tue, 09 Dec 2025 15:57:32 -0500
Subject: [PATCH] media: platform: mtk-mdp3: add WQ_PERCPU to
 alloc_workqueue users
In-Reply-To: <20251107141303.223254-1-marco.crivellari@suse.com>
References: <20251107141303.223254-1-marco.crivellari@suse.com>
Message-ID: <7e24110636db36e8c0a877d90d2ed9570c4aecf5.camel@ndufresne.ca>

Hi,

Le vendredi 07 novembre 2025 ? 15:13 +0100, Marco Crivellari a ?crit?:
> Currently if a user enqueues a work item using schedule_delayed_work() the
> used wq is "system_wq" (per-cpu wq) while queue_delayed_work() use
> WORK_CPU_UNBOUND (used when a cpu is not specified). The same applies to
> schedule_work() that is using system_wq and queue_work(), that makes use
> again of WORK_CPU_UNBOUND.
> This lack of consistency cannot be addressed without refactoring the API.
> 
> alloc_workqueue() treats all queues as per-CPU by default, while unbound
> workqueues must opt-in via WQ_UNBOUND.
> 
> This default is suboptimal: most workloads benefit from unbound queues,
> allowing the scheduler to place worker threads where they?re needed and
> reducing noise when CPUs are isolated.
> 
> This continues the effort to refactor workqueue APIs, which began with
> the introduction of new workqueues and a new alloc_workqueue flag in:
> 
> commit 128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq")
> commit 930c2ea566af ("workqueue: Add new WQ_PERCPU flag")
> 
> This change adds a new WQ_PERCPU flag to explicitly request
> alloc_workqueue() to be per-cpu when WQ_UNBOUND has not been specified.
> 
> With the introduction of the WQ_PERCPU flag (equivalent to !WQ_UNBOUND),
> any alloc_workqueue() caller that doesn?t explicitly specify WQ_UNBOUND
> must now use WQ_PERCPU.
> 
> Once migration is complete, WQ_UNBOUND can be removed and unbound will
> become the implicit default.

I have to admit, there is likely no review here due to the lack of knowledge, so
in order to help educate myself (hopefully its not just me), can you explain why
the new default of WQ_UNBOUND would not be a fit for this driver ? After all,
the author didn't care and didn't make a choice, so I feel like its worth
asking.

cheers,
Nicolas

> 
> Suggested-by: Tejun Heo <tj at kernel.org>
> Signed-off-by: Marco Crivellari <marco.crivellari at suse.com>
> ---
> ?drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c | 6 ++++--
> ?1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
> b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
> index 6559d72d5d42..9083367ae2e4 100644
> --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
> +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
> @@ -255,14 +255,16 @@ static int mdp_probe(struct platform_device *pdev)
> ?		goto err_free_mutex;
> ?	}
> ?
> -	mdp->job_wq = alloc_workqueue(MDP_MODULE_NAME, WQ_FREEZABLE, 0);
> +	mdp->job_wq = alloc_workqueue(MDP_MODULE_NAME,
> +				????? WQ_FREEZABLE | WQ_PERCPU, 0);
> ?	if (!mdp->job_wq) {
> ?		dev_err(dev, "Unable to create job workqueue\n");
> ?		ret = -ENOMEM;
> ?		goto err_deinit_comp;
> ?	}
> ?
> -	mdp->clock_wq = alloc_workqueue(MDP_MODULE_NAME "-clock",
> WQ_FREEZABLE,
> +	mdp->clock_wq = alloc_workqueue(MDP_MODULE_NAME "-clock",
> +					WQ_FREEZABLE | WQ_PERCPU,
> ?					0);
> ?	if (!mdp->clock_wq) {
> ?		dev_err(dev, "Unable to create clock workqueue\n");
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251209/1ad863dd/attachment-0001.sig>

From tharvey at gateworks.com  Tue Dec  9 12:58:28 2025
From: tharvey at gateworks.com (Tim Harvey)
Date: Tue,  9 Dec 2025 12:58:28 -0800
Subject: [PATCH] arm64: dts: imx8m{m,p}-venice-gw71xx: Add Magetometer
Message-ID: <20251209205828.689999-1-tharvey@gateworks.com>

Add support for the optional LIS2MDL magnetometer on GW71xx baseboards.

Signed-off-by: Tim Harvey <tharvey at gateworks.com>
---
 .../boot/dts/freescale/imx8mm-venice-gw71xx.dtsi  | 15 +++++++++++++++
 .../boot/dts/freescale/imx8mp-venice-gw71xx.dtsi  | 15 +++++++++++++++
 2 files changed, 30 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw71xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw71xx.dtsi
index 429be2bab8a2..320806d3d073 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw71xx.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw71xx.dtsi
@@ -92,6 +92,15 @@ accelerometer at 19 {
 		interrupt-parent = <&gpio4>;
 		interrupts = <5 IRQ_TYPE_LEVEL_LOW>;
 	};
+
+	magnetometer at 1e {
+		compatible = "st,lis2mdl";
+		reg = <0x1e>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_mag>;
+		interrupt-parent = <&gpio4>;
+		interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
+	};
 };
 
 /* off-board header */
@@ -174,6 +183,12 @@ MX8MM_IOMUXC_SAI1_RXD3_GPIO4_IO5	0x159
 		>;
 	};
 
+	pinctrl_mag: maggrp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SAI1_RXC_GPIO4_IO1		0x159
+		>;
+	};
+
 	pinctrl_gpio_leds: gpioledgrp {
 		fsl,pins = <
 			MX8MM_IOMUXC_SPDIF_EXT_CLK_GPIO5_IO5	0x19
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw71xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw71xx.dtsi
index 4bf818873fe3..9317e62304e3 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw71xx.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw71xx.dtsi
@@ -101,6 +101,15 @@ accelerometer at 19 {
 		interrupt-parent = <&gpio4>;
 		interrupts = <21 IRQ_TYPE_LEVEL_LOW>;
 	};
+
+	magnetometer at 1e {
+		compatible = "st,lis2mdl";
+		reg = <0x1e>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_mag>;
+		interrupt-parent = <&gpio4>;
+		interrupts = <25 IRQ_TYPE_LEVEL_LOW>;
+	};
 };
 
 &pcie_phy {
@@ -198,6 +207,12 @@ MX8MP_IOMUXC_SAI2_RXFS__GPIO4_IO21	0x150	/* IRQ */
 		>;
 	};
 
+	pinctrl_mag: maggrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI2_TXC__GPIO4_IO25	0x150	/* IRQ */
+		>;
+	};
+
 	pinctrl_gpio_leds: gpioledgrp {
 		fsl,pins = <
 			MX8MP_IOMUXC_SAI1_RXC__GPIO4_IO01	0x6	/* LEDG */
-- 
2.25.1



From nicolas at ndufresne.ca  Tue Dec  9 13:01:44 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Tue, 09 Dec 2025 16:01:44 -0500
Subject: [PATCH v7 17/20] media: platform: mtk-mdp3: Use
 cmdq_pkt_jump_rel() without shift_pa
In-Reply-To: <20250827114006.3310175-18-jason-jh.lin@mediatek.com>
References: <20250827114006.3310175-1-jason-jh.lin@mediatek.com>
	 <20250827114006.3310175-18-jason-jh.lin@mediatek.com>
Message-ID: <ae08e53e055a238cde639dc9d9c7263fa296af5f.camel@ndufresne.ca>

Hi,

Le mercredi 27 ao?t 2025 ? 19:37 +0800, Jason-JH Lin a ?crit?:
> With the removal of the shift_pa parameter, cmdq_pkt_jump_rel_temp()
> can be replaced by the new cmdq_pkt_jump_rel() without shift_pa.
> 
> Then, remove the cmdq_shift_pa variable in the mdp_dev structure for
> each mbox client.
> 
> Fixes: ade176534112 ("soc: mediatek: cmdq: Add parameter shift_pa to cmdq_pkt_jump()")
> Signed-off-by: Jason-JH Lin <jason-jh.lin at mediatek.com>
> ---
> ?drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c | 2 +-
> ?drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c | 2 --
> ?drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.h | 1 -
> ?3 files changed, 1 insertion(+), 4 deletions(-)
> 
> diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c
> index 7575ec376367..c35fe0e3a4d5 100644
> --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c
> +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c
> @@ -638,7 +638,7 @@ static struct mdp_cmdq_cmd *mdp_cmdq_prepare(struct mdp_dev *mdp,
> ?		goto err_free_path;
> ?	}
> ?	cmdq_pkt_eoc(&cmd->pkt);
> -	cmdq_pkt_jump_rel_temp(&cmd->pkt, CMDQ_INST_SIZE, mdp->cmdq_shift_pa[pp_idx]);
> +	cmdq_pkt_jump_rel(&cmd->pkt, CMDQ_INST_SIZE);

That effectively revert another patch that is pending, and remove the use of the
new cmdq_pkt_jump_rel_temp(). I don't follow what is doing on here, I think some
context must be lost.

Nicolas

> ?
> ?	for (i = 0; i < num_comp; i++) {
> ?		s32 inner_id = MDP_COMP_NONE;
> diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
> index 8de2c8e4d333..2f8147481bd6 100644
> --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
> +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
> @@ -293,8 +293,6 @@ static int mdp_probe(struct platform_device *pdev)
> ?			ret = PTR_ERR(mdp->cmdq_clt[i]);
> ?			goto err_mbox_destroy;
> ?		}
> -
> -		mdp->cmdq_shift_pa[i] = cmdq_get_shift_pa(mdp->cmdq_clt[i]->chan);
> ?	}
> ?
> ?	init_waitqueue_head(&mdp->callback_wq);
> diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.h b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.h
> index 05cade1d098e..430251f63754 100644
> --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.h
> +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.h
> @@ -126,7 +126,6 @@ struct mdp_dev {
> ?	u32					id_count;
> ?	struct ida				mdp_ida;
> ?	struct cmdq_client			*cmdq_clt[MDP_PP_MAX];
> -	u8					cmdq_shift_pa[MDP_PP_MAX];
> ?	wait_queue_head_t			callback_wq;
> ?
> ?	struct v4l2_device			v4l2_dev;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251209/ccf40a76/attachment.sig>

From nicolinc at nvidia.com  Tue Dec  9 13:04:43 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Tue, 9 Dec 2025 13:04:43 -0800
Subject: [PATCH rc v2 4/4] iommu/arm-smmu-v3-test: Add nested
 s1bypass/s1dssbypass coverage
In-Reply-To: <f52c705d-6032-4d85-b902-dd6d0a40b9ec@linux.alibaba.com>
References: <cover.1765140287.git.nicolinc@nvidia.com>
 <b6d87901f89c05dd9e1d0c1e819040d205f569a7.1765140287.git.nicolinc@nvidia.com>
 <f52c705d-6032-4d85-b902-dd6d0a40b9ec@linux.alibaba.com>
Message-ID: <aTiO69YZ9WA8dFe0@nvidia.com>

On Mon, Dec 08, 2025 at 11:43:41AM +0800, Shuai Xue wrote:
> Hi, Nicolin,
> 
> Nit. Instead of duplicating this code, we can leverage the existing
> arm_smmu_test_make_cdtable_ste() helper here.

Thanks for the review. I squashed the following changes:

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
index 1672e75ebffc2..197b8b55fe7a2 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
@@ -33,8 +33,12 @@ static struct mm_struct sva_mm = {
 enum arm_smmu_test_master_feat {
 	ARM_SMMU_MASTER_TEST_ATS = BIT(0),
 	ARM_SMMU_MASTER_TEST_STALL = BIT(1),
+	ARM_SMMU_MASTER_TEST_NESTED = BIT(2),
 };
 
+static void arm_smmu_test_make_s2_ste(struct arm_smmu_ste *ste,
+				      enum arm_smmu_test_master_feat feat);
+
 static bool arm_smmu_entry_differs_in_used_bits(const __le64 *entry,
 						const __le64 *used_bits,
 						const __le64 *target,
@@ -198,6 +202,17 @@ static void arm_smmu_test_make_cdtable_ste(struct arm_smmu_ste *ste,
 	};
 
 	arm_smmu_make_cdtable_ste(ste, &master, ats_enabled, s1dss);
+	if (feat & ARM_SMMU_MASTER_TEST_NESTED) {
+		struct arm_smmu_ste s2ste;
+		int i;
+
+		arm_smmu_test_make_s2_ste(&s2ste, ARM_SMMU_MASTER_TEST_ATS);
+		ste->data[0] |= cpu_to_le64(
+			FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_NESTED));
+		ste->data[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
+		for (i = 2; i < NUM_ENTRY_QWORDS; i++)
+			ste->data[i] = s2ste.data[i];
+	}
 }
 
 static void arm_smmu_v3_write_ste_test_bypass_to_abort(struct kunit *test)
@@ -555,46 +570,17 @@ static void arm_smmu_v3_write_ste_test_s2_to_s1_stall(struct kunit *test)
 						       NUM_EXPECTED_SYNCS(3));
 }
 
-static void arm_smmu_test_make_nested_cdtable_ste(
-	struct arm_smmu_ste *ste, unsigned int s1dss, const dma_addr_t dma_addr,
-	enum arm_smmu_test_master_feat feat)
-{
-	bool stall_enabled = feat & ARM_SMMU_MASTER_TEST_STALL;
-	bool ats_enabled = feat & ARM_SMMU_MASTER_TEST_ATS;
-	struct arm_smmu_ste s1ste;
-
-	struct arm_smmu_master master = {
-		.ats_enabled = ats_enabled,
-		.cd_table.cdtab_dma = dma_addr,
-		.cd_table.s1cdmax = 0xFF,
-		.cd_table.s1fmt = STRTAB_STE_0_S1FMT_64K_L2,
-		.smmu = &smmu,
-		.stall_enabled = stall_enabled,
-	};
-
-	arm_smmu_test_make_s2_ste(ste, ARM_SMMU_MASTER_TEST_ATS);
-	arm_smmu_make_cdtable_ste(&s1ste, &master, ats_enabled, s1dss);
-
-	ste->data[0] = cpu_to_le64(
-		STRTAB_STE_0_V |
-		FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_NESTED));
-	ste->data[0] |= s1ste.data[0] & ~cpu_to_le64(STRTAB_STE_0_CFG);
-	ste->data[1] |= s1ste.data[1];
-	/* Merge events for DoS mitigations on eventq */
-	ste->data[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
-}
-
 static void
 arm_smmu_v3_write_ste_test_nested_s1dssbypass_to_s1bypass(struct kunit *test)
 {
 	struct arm_smmu_ste s1_ste;
 	struct arm_smmu_ste s2_ste;
 
-	arm_smmu_test_make_nested_cdtable_ste(&s1_ste,
-					      STRTAB_STE_1_S1DSS_BYPASS,
-					      fake_cdtab_dma_addr,
-					      ARM_SMMU_MASTER_TEST_ATS);
+	arm_smmu_test_make_cdtable_ste(
+		&s1_ste, STRTAB_STE_1_S1DSS_BYPASS, fake_cdtab_dma_addr,
+		ARM_SMMU_MASTER_TEST_ATS | ARM_SMMU_MASTER_TEST_NESTED);
 	arm_smmu_test_make_s2_ste(&s2_ste, 0);
+	/* Expect an additional sync to unset ignored bits: EATS and MEV */
 	arm_smmu_v3_test_ste_expect_hitless_transition(test, &s1_ste, &s2_ste,
 						       NUM_EXPECTED_SYNCS(3));
 }
@@ -605,10 +591,9 @@ arm_smmu_v3_write_ste_test_nested_s1bypass_to_s1dssbypass(struct kunit *test)
 	struct arm_smmu_ste s1_ste;
 	struct arm_smmu_ste s2_ste;
 
-	arm_smmu_test_make_nested_cdtable_ste(&s1_ste,
-					      STRTAB_STE_1_S1DSS_BYPASS,
-					      fake_cdtab_dma_addr,
-					      ARM_SMMU_MASTER_TEST_ATS);
+	arm_smmu_test_make_cdtable_ste(
+		&s1_ste, STRTAB_STE_1_S1DSS_BYPASS, fake_cdtab_dma_addr,
+		ARM_SMMU_MASTER_TEST_ATS | ARM_SMMU_MASTER_TEST_NESTED);
 	arm_smmu_test_make_s2_ste(&s2_ste, 0);
 	arm_smmu_v3_test_ste_expect_hitless_transition(test, &s2_ste, &s1_ste,
 						       NUM_EXPECTED_SYNCS(2));


From oupton at kernel.org  Tue Dec  9 13:08:13 2025
From: oupton at kernel.org (Oliver Upton)
Date: Tue, 9 Dec 2025 13:08:13 -0800
Subject: [PATCH v5 10/24] KVM: arm64: Set up FGT for Partitioned PMU
In-Reply-To: <20251209205121.1871534-11-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
 <20251209205121.1871534-11-coltonlewis@google.com>
Message-ID: <aTiPvS49uMOJEBrf@kernel.org>

Hi Colton,

On Tue, Dec 09, 2025 at 08:51:07PM +0000, Colton Lewis wrote:
> In order to gain the best performance benefit from partitioning the
> PMU, utilize fine grain traps (FEAT_FGT and FEAT_FGT2) to avoid
> trapping common PMU register accesses by the guest to remove that
> overhead.
> 
> Untrapped:
> * PMCR_EL0
> * PMUSERENR_EL0
> * PMSELR_EL0
> * PMCCNTR_EL0
> * PMCNTEN_EL0
> * PMINTEN_EL1
> * PMEVCNTRn_EL0
> 
> These are safe to untrap because writing MDCR_EL2.HPMN as this series
> will do limits the effect of writes to any of these registers to the
> partition of counters 0..HPMN-1. Reads from these registers will not
> leak information from between guests as all these registers are
> context swapped by a later patch in this series. Reads from these
> registers also do not leak any information about the host's hardware
> beyond what is promised by PMUv3.
> 
> Trapped:
> * PMOVS_EL0
> * PMEVTYPERn_EL0
> * PMCCFILTR_EL0
> * PMICNTR_EL0
> * PMICFILTR_EL0
> * PMCEIDn_EL0
> * PMMIR_EL1
> 
> PMOVS remains trapped so KVM can track overflow IRQs that will need to
> be injected into the guest.
> 
> PMICNTR and PMIFILTR remain trapped because KVM is not handling them
> yet.
> 
> PMEVTYPERn remains trapped so KVM can limit which events guests can
> count, such as disallowing counting at EL2. PMCCFILTR and PMCIFILTR
> are special cases of the same.
> 
> PMCEIDn and PMMIR remain trapped because they can leak information
> specific to the host hardware implementation.
> 
> NOTE: This patch temporarily forces kvm_vcpu_pmu_is_partitioned() to
> be false to prevent partial feature activation for easier debugging.
> 
> Signed-off-by: Colton Lewis <coltonlewis at google.com>
> ---
>  arch/arm64/include/asm/kvm_pmu.h | 33 ++++++++++++++++++++++
>  arch/arm64/kvm/config.c          | 34 ++++++++++++++++++++--
>  arch/arm64/kvm/pmu-direct.c      | 48 ++++++++++++++++++++++++++++++++
>  3 files changed, 112 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_pmu.h b/arch/arm64/include/asm/kvm_pmu.h
> index 8887f39c25e60..7297a697a4a62 100644
> --- a/arch/arm64/include/asm/kvm_pmu.h
> +++ b/arch/arm64/include/asm/kvm_pmu.h
> @@ -96,6 +96,23 @@ u64 kvm_pmu_guest_counter_mask(struct arm_pmu *pmu);
>  void kvm_pmu_host_counters_enable(void);
>  void kvm_pmu_host_counters_disable(void);
>  
> +#if !defined(__KVM_NVHE_HYPERVISOR__)
> +bool kvm_vcpu_pmu_is_partitioned(struct kvm_vcpu *vcpu);
> +bool kvm_vcpu_pmu_use_fgt(struct kvm_vcpu *vcpu);
> +#else
> +static inline bool kvm_vcpu_pmu_is_partitioned(struct kvm_vcpu *vcpu)
> +{
> +	return false;
> +}
> +
> +static inline bool kvm_vcpu_pmu_use_fgt(struct kvm_vcpu *vcpu)
> +{
> +	return false;
> +}
> +#endif
> +u64 kvm_pmu_fgt_bits(void);
> +u64 kvm_pmu_fgt2_bits(void);
> +
>  /*
>   * Updates the vcpu's view of the pmu events for this cpu.
>   * Must be called before every vcpu run after disabling interrupts, to ensure
> @@ -135,6 +152,22 @@ static inline u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu,
>  {
>  	return 0;
>  }
> +static inline bool kvm_vcpu_pmu_is_partitioned(struct kvm_vcpu *vcpu)
> +{
> +	return false;
> +}
> +static inline bool kvm_vcpu_pmu_use_fgt(struct kvm_vcpu *vcpu)
> +{
> +	return false;
> +}
> +static inline u64 kvm_pmu_fgt_bits(void)
> +{
> +	return 0;
> +}
> +static inline u64 kvm_pmu_fgt2_bits(void)
> +{
> +	return 0;
> +}
>  static inline void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu,
>  					     u64 select_idx, u64 val) {}
>  static inline void kvm_pmu_set_counter_value_user(struct kvm_vcpu *vcpu,
> diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
> index 24bb3f36e9d59..064dc6aa06f76 100644
> --- a/arch/arm64/kvm/config.c
> +++ b/arch/arm64/kvm/config.c
> @@ -6,6 +6,7 @@
>  
>  #include <linux/kvm_host.h>
>  #include <asm/kvm_emulate.h>
> +#include <asm/kvm_pmu.h>
>  #include <asm/kvm_nested.h>
>  #include <asm/sysreg.h>
>  
> @@ -1489,12 +1490,39 @@ static void __compute_hfgwtr(struct kvm_vcpu *vcpu)
>  		*vcpu_fgt(vcpu, HFGWTR_EL2) |= HFGWTR_EL2_TCR_EL1;
>  }
>  
> +static void __compute_hdfgrtr(struct kvm_vcpu *vcpu)
> +{
> +	__compute_fgt(vcpu, HDFGRTR_EL2);
> +
> +	if (kvm_vcpu_pmu_use_fgt(vcpu))
> +		*vcpu_fgt(vcpu, HDFGRTR_EL2) |= kvm_pmu_fgt_bits();

Couple of suggestions. I'd rather see this conditioned on
kvm_vcpu_pmu_is_partitioned() and get rid of the FGT predicate. After
all, kvm_vcpu_load_fgt() already checks for the presence of FEAT_FGT
first.

Additionally, I'd prefer that the trap configuration is inline instead
of done in a helper in some other file. Centralizing the FGT
configuration here was very much intentional.

The other reason for doing this is kvm_pmu_fgt_bits() assumes a
'positive' trap polarity, even though there are several cases where FGTs
have a 'negative' priority (i.e. 0 => trap).

Thanks,
Oliver


From adrian.kossmann at posteo.de  Tue Dec  9 13:09:33 2025
From: adrian.kossmann at posteo.de (Adrian Kossmann)
Date: Tue, 09 Dec 2025 21:09:33 +0000
Subject: [PATCH] arm64: dts: rockchip: Add compatible for Ethernet PHY
Message-ID: <20251209210658.458506-2-adrian.kossmann@posteo.de>

Without the compatible string the Ethernet PHY is not bound to the
correct driver. This causes link instability under load, with throughput
eventually dropping to zero.
Add the explicit PHY ID compatible to ensure the proper driver is selected.

Signed-off-by: Adrian Kossmann <adrian.kossmann at posteo.de>
---
 arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts b/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts
index a4bdd87d0729..4da5ff6f2572 100644
--- a/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts
@@ -163,6 +163,7 @@ mdio {
 		#size-cells = <0>;
 
 		rtl8211: ethernet-phy at 1 {
+			compatible = "ethernet-phy-id001c.c916";
 			reg = <1>;
 			pinctrl-0 = <&eth_phy_int_pin>, <&eth_phy_reset_pin>;
 			pinctrl-names = "default";
-- 
2.52.0



From oupton at kernel.org  Tue Dec  9 13:14:03 2025
From: oupton at kernel.org (Oliver Upton)
Date: Tue, 9 Dec 2025 13:14:03 -0800
Subject: [PATCH v5 12/24] KVM: arm64: Use physical PMSELR for PMXEVTYPER
 if partitioned
In-Reply-To: <20251209205121.1871534-13-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
 <20251209205121.1871534-13-coltonlewis@google.com>
Message-ID: <aTiRG0I1FZzntHtH@kernel.org>

On Tue, Dec 09, 2025 at 08:51:09PM +0000, Colton Lewis wrote:
> Because PMXEVTYPER is trapped and PMSELR is not, it is not appropriate
> to use the virtual PMSELR register when it could be outdated and lead
> to an invalid write. Use the physical register when partitioned.
> 
> Signed-off-by: Colton Lewis <coltonlewis at google.com>
> ---
>  arch/arm64/include/asm/arm_pmuv3.h | 7 ++++++-
>  arch/arm64/kvm/sys_regs.c          | 9 +++++++--
>  2 files changed, 13 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/arm_pmuv3.h b/arch/arm64/include/asm/arm_pmuv3.h
> index 27c4d6d47da31..60600f04b5902 100644
> --- a/arch/arm64/include/asm/arm_pmuv3.h
> +++ b/arch/arm64/include/asm/arm_pmuv3.h
> @@ -70,11 +70,16 @@ static inline u64 read_pmcr(void)
>  	return read_sysreg(pmcr_el0);
>  }
>  
> -static inline void write_pmselr(u32 val)
> +static inline void write_pmselr(u64 val)
>  {
>  	write_sysreg(val, pmselr_el0);
>  }
>  
> +static inline u64 read_pmselr(void)
> +{
> +	return read_sysreg(pmselr_el0);
> +}
> +
>  static inline void write_pmccntr(u64 val)
>  {
>  	write_sysreg(val, pmccntr_el0);
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index 0c9596325519b..2e6d907fa8af2 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -1199,14 +1199,19 @@ static bool writethrough_pmevtyper(struct kvm_vcpu *vcpu, struct sys_reg_params
>  static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  			       const struct sys_reg_desc *r)
>  {
> -	u64 idx, reg;
> +	u64 idx, reg, pmselr;
>  
>  	if (pmu_access_el0_disabled(vcpu))
>  		return false;
>  
>  	if (r->CRn == 9 && r->CRm == 13 && r->Op2 == 1) {
>  		/* PMXEVTYPER_EL0 */
> -		idx = SYS_FIELD_GET(PMSELR_EL0, SEL, __vcpu_sys_reg(vcpu, PMSELR_EL0));
> +		if (kvm_vcpu_pmu_is_partitioned(vcpu))
> +			pmselr = read_pmselr();
> +		else
> +			pmselr = __vcpu_sys_reg(vcpu, PMSELR_EL0);

This isn't preemption safe. Nor should the "if (partitioned) do X else do Y" get
open-coded throughout the shop.

I would rather this be handled with a prepatory patch that provides
generic PMU register accessors to the rest of KVM (e.g.
vcpu_read_pmu_reg() / vcpu_write_pmu_reg()). Internally those helpers
can locate the vCPU's PMU registers (emulated, partitioned in-memory,
partitioned in-CPU).

Thanks,
Oliver


From robh at kernel.org  Tue Dec  9 13:15:21 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Tue, 9 Dec 2025 15:15:21 -0600
Subject: [PATCH 2/4] media: dt-bindings: rockchip: Add RK3568 Video
 Decoder bindings
In-Reply-To: <20251206082809.2040679-3-christianshewitt@gmail.com>
References: <20251206082809.2040679-1-christianshewitt@gmail.com>
 <20251206082809.2040679-3-christianshewitt@gmail.com>
Message-ID: <176531492074.1107900.2748821252600292565.robh@kernel.org>


On Sat, 06 Dec 2025 08:28:07 +0000, Christian Hewitt wrote:
> The video decoder in RK356X (vdpu346) is described in the same way as
> the one in RK3588 (vdpu381). A new compatible is added as the decoder
> capabilities are a subset of the vdpu381 capabilities.
> 
> Signed-off-by: Christian Hewitt <christianshewitt at gmail.com>
> ---
> nb: I've chosen to us rk3568-vdec not rk356x-vdec as other compatibles
> for these chips are using rk3568.
> 
>  Documentation/devicetree/bindings/media/rockchip,vdec.yaml | 2 ++
>  1 file changed, 2 insertions(+)
> 

Acked-by: Rob Herring (Arm) <robh at kernel.org>



From oupton at kernel.org  Tue Dec  9 13:19:08 2025
From: oupton at kernel.org (Oliver Upton)
Date: Tue, 9 Dec 2025 13:19:08 -0800
Subject: [PATCH v5 13/24] KVM: arm64: Writethrough trapped PMOVS register
In-Reply-To: <20251209205121.1871534-14-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
 <20251209205121.1871534-14-coltonlewis@google.com>
Message-ID: <aTiSTODjzaLzwAPN@kernel.org>

On Tue, Dec 09, 2025 at 08:51:10PM +0000, Colton Lewis wrote:
> Because PMOVS remains trapped, it needs to be written through when
> partitioned to affect PMU hardware when expected.
> 
> Signed-off-by: Colton Lewis <coltonlewis at google.com>
> ---
>  arch/arm64/include/asm/arm_pmuv3.h | 10 ++++++++++
>  arch/arm64/kvm/sys_regs.c          | 17 ++++++++++++++++-
>  2 files changed, 26 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/include/asm/arm_pmuv3.h b/arch/arm64/include/asm/arm_pmuv3.h
> index 60600f04b5902..3e25c0313263c 100644
> --- a/arch/arm64/include/asm/arm_pmuv3.h
> +++ b/arch/arm64/include/asm/arm_pmuv3.h
> @@ -140,6 +140,16 @@ static inline u64 read_pmicfiltr(void)
>  	return read_sysreg_s(SYS_PMICFILTR_EL0);
>  }
>  
> +static inline void write_pmovsset(u64 val)
> +{
> +	write_sysreg(val, pmovsset_el0);
> +}
> +
> +static inline u64 read_pmovsset(void)
> +{
> +	return read_sysreg(pmovsset_el0);
> +}
> +
>  static inline void write_pmovsclr(u64 val)
>  {
>  	write_sysreg(val, pmovsclr_el0);
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index 2e6d907fa8af2..bee892db9ca8b 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -1307,6 +1307,19 @@ static bool access_pminten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  	return true;
>  }
>  
> +static void writethrough_pmovs(struct kvm_vcpu *vcpu, struct sys_reg_params *p, bool set)
> +{
> +	u64 mask = kvm_pmu_accessible_counter_mask(vcpu);
> +
> +	if (set) {
> +		__vcpu_rmw_sys_reg(vcpu, PMOVSSET_EL0, |=, (p->regval & mask));
> +		write_pmovsset(p->regval & mask);
> +	} else {
> +		__vcpu_rmw_sys_reg(vcpu, PMOVSSET_EL0, &=, ~(p->regval & mask));
> +		write_pmovsclr(p->regval & mask);
> +	}

There's only ever a single canonical guest view of a register. Either it has
been loaded onto the CPU or it is in memory, writing the value to two
different locations is odd. What guarantees the guest context is on the
CPU currently? And what about preemption?

Thanks,
Oliver


From oupton at kernel.org  Tue Dec  9 13:33:16 2025
From: oupton at kernel.org (Oliver Upton)
Date: Tue, 9 Dec 2025 13:33:16 -0800
Subject: [PATCH v5 15/24] KVM: arm64: Setup MDCR_EL2 to handle a
 partitioned PMU
In-Reply-To: <20251209205121.1871534-16-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
 <20251209205121.1871534-16-coltonlewis@google.com>
Message-ID: <aTiVnI5ewoEVRztD@kernel.org>

On Tue, Dec 09, 2025 at 08:51:12PM +0000, Colton Lewis wrote:
> Setup MDCR_EL2 to handle a partitioned PMU. That means calculate an
> appropriate value for HPMN instead of the default maximum setting the
> host allows (which implies no partition) so hardware enforces that a
> guest will only see the counters in the guest partition.
> 
> Setting HPMN to a non default value means the global enable bit for
> the host counters is now MDCR_EL2.HPME instead of the usual
> PMCR_EL0.E. Enable the HPME bit to allow the host to count guest
> events. Since HPME only has an effect when HPMN is set which we only
> do for the guest, it is correct to enable it unconditionally here.
> 
> Unset the TPM and TPMCR bits, which trap all PMU accesses, if
> FGT (fine grain trapping) is being used.
> 
> If available, set the filtering bits HPMD and HCCD to be extra sure
> nothing in the guest counts at EL2.
> 
> Signed-off-by: Colton Lewis <coltonlewis at google.com>
> ---
>  arch/arm64/include/asm/kvm_pmu.h | 11 ++++++
>  arch/arm64/kvm/debug.c           | 29 ++++++++++++--
>  arch/arm64/kvm/pmu-direct.c      | 65 ++++++++++++++++++++++++++++++++
>  3 files changed, 102 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_pmu.h b/arch/arm64/include/asm/kvm_pmu.h
> index 60b8a48cad456..8b634112eded2 100644
> --- a/arch/arm64/include/asm/kvm_pmu.h
> +++ b/arch/arm64/include/asm/kvm_pmu.h
> @@ -101,6 +101,9 @@ u64 kvm_pmu_guest_counter_mask(struct arm_pmu *pmu);
>  void kvm_pmu_host_counters_enable(void);
>  void kvm_pmu_host_counters_disable(void);
>  
> +u8 kvm_pmu_guest_num_counters(struct kvm_vcpu *vcpu);
> +u8 kvm_pmu_hpmn(struct kvm_vcpu *vcpu);
> +
>  #if !defined(__KVM_NVHE_HYPERVISOR__)
>  bool kvm_vcpu_pmu_is_partitioned(struct kvm_vcpu *vcpu);
>  bool kvm_vcpu_pmu_use_fgt(struct kvm_vcpu *vcpu);
> @@ -173,6 +176,14 @@ static inline u64 kvm_pmu_fgt2_bits(void)
>  {
>  	return 0;
>  }
> +static inline u8 kvm_pmu_guest_num_counters(struct kvm_vcpu *vcpu)
> +{
> +	return 0;
> +}
> +static inline u8 kvm_pmu_hpmn(struct kvm_vcpu *vcpu)
> +{
> +	return 0;
> +}
>  static inline void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu,
>  					     u64 select_idx, u64 val) {}
>  static inline void kvm_pmu_set_counter_value_user(struct kvm_vcpu *vcpu,
> diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
> index 3ad6b7c6e4ba7..0ab89c91e19cb 100644
> --- a/arch/arm64/kvm/debug.c
> +++ b/arch/arm64/kvm/debug.c
> @@ -36,20 +36,43 @@ static int cpu_has_spe(u64 dfr0)
>   */
>  static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu)
>  {
> +	int hpmn = kvm_pmu_hpmn(vcpu);
> +
>  	preempt_disable();
>  
>  	/*
>  	 * This also clears MDCR_EL2_E2PB_MASK and MDCR_EL2_E2TB_MASK
>  	 * to disable guest access to the profiling and trace buffers
>  	 */
> -	vcpu->arch.mdcr_el2 = FIELD_PREP(MDCR_EL2_HPMN,
> -					 *host_data_ptr(nr_event_counters));
> +
> +	vcpu->arch.mdcr_el2 = FIELD_PREP(MDCR_EL2_HPMN, hpmn);
>  	vcpu->arch.mdcr_el2 |= (MDCR_EL2_TPM |
>  				MDCR_EL2_TPMS |
>  				MDCR_EL2_TTRF |
>  				MDCR_EL2_TPMCR |
>  				MDCR_EL2_TDRA |
> -				MDCR_EL2_TDOSA);
> +				MDCR_EL2_TDOSA |
> +				MDCR_EL2_HPME);
> +
> +	if (kvm_vcpu_pmu_is_partitioned(vcpu)) {
> +		/*
> +		 * Filtering these should be redundant because we trap
> +		 * all the TYPER and FILTR registers anyway and ensure
> +		 * they filter EL2, but set the bits if they are here.
> +		 */
> +		if (is_pmuv3p1(read_pmuver()))
> +			vcpu->arch.mdcr_el2 |= MDCR_EL2_HPMD;
> +		if (is_pmuv3p5(read_pmuver()))
> +			vcpu->arch.mdcr_el2 |= MDCR_EL2_HCCD;
> +
> +		/*
> +		 * Take out the coarse grain traps if we are using
> +		 * fine grain traps.
> +		 */
> +		if (kvm_vcpu_pmu_use_fgt(vcpu))
> +			vcpu->arch.mdcr_el2 &= ~(MDCR_EL2_TPM | MDCR_EL2_TPMCR);
> +
> +	}
>  
>  	/* Is the VM being debugged by userspace? */
>  	if (vcpu->guest_debug)
> diff --git a/arch/arm64/kvm/pmu-direct.c b/arch/arm64/kvm/pmu-direct.c
> index 4dd160c878862..7fb4fb5c22e2a 100644
> --- a/arch/arm64/kvm/pmu-direct.c
> +++ b/arch/arm64/kvm/pmu-direct.c
> @@ -154,3 +154,68 @@ void kvm_pmu_host_counters_disable(void)
>  	mdcr &= ~MDCR_EL2_HPME;
>  	write_sysreg(mdcr, mdcr_el2);
>  }

<snip>

> +/**
> + * kvm_pmu_guest_num_counters() - Number of counters to show to guest
> + * @vcpu: Pointer to struct kvm_vcpu
> + *
> + * Calculate the number of counters to show to the guest via
> + * PMCR_EL0.N, making sure to respect the maximum the host allows,
> + * which is hpmn_max if partitioned and host_max otherwise.
> + *
> + * Return: Valid value for PMCR_EL0.N
> + */
> +u8 kvm_pmu_guest_num_counters(struct kvm_vcpu *vcpu)
> +{
> +	u8 nr_cnt = vcpu->kvm->arch.nr_pmu_counters;
> +	int hpmn_max = armv8pmu_hpmn_max;
> +	u8 host_max = *host_data_ptr(nr_event_counters);
> +
> +	if (vcpu->kvm->arch.arm_pmu)
> +		hpmn_max = vcpu->kvm->arch.arm_pmu->hpmn_max;
> +
> +	if (kvm_vcpu_pmu_is_partitioned(vcpu)) {
> +		if (nr_cnt <= hpmn_max && nr_cnt <= host_max)
> +			return nr_cnt;
> +		if (hpmn_max <= host_max)
> +			return hpmn_max;
> +	}
> +
> +	if (nr_cnt <= host_max)
> +		return nr_cnt;
> +
> +	return host_max;
> +}
> +
> +/**
> + * kvm_pmu_hpmn() - Calculate HPMN field value
> + * @vcpu: Pointer to struct kvm_vcpu
> + *
> + * Calculate the appropriate value to set for MDCR_EL2.HPMN. If
> + * partitioned, this is the number of counters set for the guest if
> + * supported, falling back to hpmn_max if needed. If we are not
> + * partitioned or can't set the implied HPMN value, fall back to the
> + * host value.
> + *
> + * Return: A valid HPMN value
> + */
> +u8 kvm_pmu_hpmn(struct kvm_vcpu *vcpu)
> +{
> +	u8 nr_guest_cnt = kvm_pmu_guest_num_counters(vcpu);
> +	int nr_guest_cnt_max = armv8pmu_hpmn_max;
> +	u8 nr_host_cnt_max = *host_data_ptr(nr_event_counters);
> +
> +	if (vcpu->kvm->arch.arm_pmu)
> +		nr_guest_cnt_max = vcpu->kvm->arch.arm_pmu->hpmn_max;
> +
> +	if (kvm_vcpu_pmu_is_partitioned(vcpu)) {
> +		if (cpus_have_final_cap(ARM64_HAS_HPMN0))
> +			return nr_guest_cnt;
> +		else if (nr_guest_cnt > 0)
> +			return nr_guest_cnt;
> +		else if (nr_guest_cnt_max > 0)
> +			return nr_guest_cnt_max;
> +	}
> +
> +	return nr_host_cnt_max;
> +}

</snip>

I find all of this rather confusing. It seems like you're dealing with
sanitizing kvm->arch.nr_pmu_counters vs. the underlying implementation.
I'm not sure why you need to do that, I would expect that we reject
unsupported values at the time of the ioctl.

The only thing you do need to handle is if the vCPU has migrated to an
"unsupported" CPU, for which we already have supporting helpers. I'm too
lazy to fetch the Arm ARM and cite architecture but I'm pretty sure an
out-of-range HPMN has UNPREDICTABLE behavior.

I think you just need to move the vcpu_set_unsupported_cpu() call earlier in
kvm_arch_vcpu_load().

Taking all that into consideration:

u8 kvm_mdcr_hpmn(struct kvm_vcpu *vcpu)
{
	u8 nr_counters = *host_data_ptr(nr_event_counters);

	if (!kvm_vcpu_pmu_is_partitioned(vcpu) || vcpu_on_unsupported_cpu(vcpu))
		return nr_counters;

	return vcpu->kvm->arch.nr_pmu_counters;
}

Thanks,
Oliver


From oupton at kernel.org  Tue Dec  9 13:37:52 2025
From: oupton at kernel.org (Oliver Upton)
Date: Tue, 9 Dec 2025 13:37:52 -0800
Subject: [PATCH v5 16/24] KVM: arm64: Account for partitioning in
 PMCR_EL0 access
In-Reply-To: <20251209205121.1871534-17-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
 <20251209205121.1871534-17-coltonlewis@google.com>
Message-ID: <aTiWsAvK9krnEw7V@kernel.org>

On Tue, Dec 09, 2025 at 08:51:13PM +0000, Colton Lewis wrote:
> Make sure reads and writes to PMCR_EL0 conform to additional
> constraints imposed when the PMU is partitioned.
> 
> Signed-off-by: Colton Lewis <coltonlewis at google.com>
> ---
>  arch/arm64/kvm/pmu.c      | 2 +-
>  arch/arm64/kvm/sys_regs.c | 2 +-
>  2 files changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/kvm/pmu.c b/arch/arm64/kvm/pmu.c
> index 1fd012f8ff4a9..48b39f096fa12 100644
> --- a/arch/arm64/kvm/pmu.c
> +++ b/arch/arm64/kvm/pmu.c
> @@ -877,7 +877,7 @@ u64 kvm_pmu_accessible_counter_mask(struct kvm_vcpu *vcpu)
>  u64 kvm_vcpu_read_pmcr(struct kvm_vcpu *vcpu)
>  {
>  	u64 pmcr = __vcpu_sys_reg(vcpu, PMCR_EL0);
> -	u64 n = vcpu->kvm->arch.nr_pmu_counters;
> +	u64 n = kvm_pmu_guest_num_counters(vcpu);

Why can't the value of vcpu->kvm->arch.nr_pmu_counters be trusted?

> @@ -1360,7 +1360,7 @@ static int set_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
>  	 */
>  	if (!kvm_vm_has_ran_once(kvm) &&
>  	    !vcpu_has_nv(vcpu)	      &&
> -	    new_n <= kvm_arm_pmu_get_max_counters(kvm))
> +	    new_n <= kvm_pmu_hpmn(vcpu))
>  		kvm->arch.nr_pmu_counters = new_n;

This is the legacy UAPI for setting the number of PMU counters by
writing to PMCR_EL0.N.

The 'partitioned' implementation should take a dependency on the
SET_NR_COUNTERS attribute and reject attempts to change the value of
PMCR_EL0.N. Just like nested.

Thanks,
Oliver


From oupton at kernel.org  Tue Dec  9 13:55:59 2025
From: oupton at kernel.org (Oliver Upton)
Date: Tue, 9 Dec 2025 13:55:59 -0800
Subject: [PATCH v5 17/24] KVM: arm64: Context swap Partitioned PMU guest
 registers
In-Reply-To: <20251209205121.1871534-18-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
 <20251209205121.1871534-18-coltonlewis@google.com>
Message-ID: <aTia74R74upcsMEA@kernel.org>

On Tue, Dec 09, 2025 at 08:51:14PM +0000, Colton Lewis wrote:
> +/**
> + * kvm_pmu_load() - Load untrapped PMU registers
> + * @vcpu: Pointer to struct kvm_vcpu
> + *
> + * Load all untrapped PMU registers from the VCPU into the PCPU. Mask
> + * to only bits belonging to guest-reserved counters and leave
> + * host-reserved counters alone in bitmask registers.
> + */
> +void kvm_pmu_load(struct kvm_vcpu *vcpu)
> +{
> +	struct arm_pmu *pmu;
> +	u64 mask;
> +	u8 i;
> +	u64 val;
> +

Assert that preemption is disabled.

> +	/*
> +	 * If we aren't using FGT then we are trapping everything
> +	 * anyway, so no need to bother with the swap.
> +	 */
> +	if (!kvm_vcpu_pmu_use_fgt(vcpu))
> +		return;

Uhh... Then how do events count in this case?

The absence of FEAT_FGT shouldn't affect the residence of the guest PMU
context. We just need to handle the extra traps, ideally by reading the
PMU registers directly as a fast path exit handler.

> +	pmu = vcpu->kvm->arch.arm_pmu;
> +
> +	for (i = 0; i < pmu->hpmn_max; i++) {
> +		val = __vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i);
> +		write_pmevcntrn(i, val);
> +	}
> +
> +	val = __vcpu_sys_reg(vcpu, PMCCNTR_EL0);
> +	write_pmccntr(val);
> +
> +	val = __vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> +	write_pmuserenr(val);

What about the host's value for PMUSERENR?

> +	val = __vcpu_sys_reg(vcpu, PMSELR_EL0);
> +	write_pmselr(val);

PMSELR_EL0 needs to be switched late, e.g. at sysreg_restore_guest_state_vhe().
Even though the host doesn't currently use the selector-based accessor,
I'd prefer we not load things that'd affect the host context until we're
about to enter the guest.

> +	/* Save only the stateful writable bits. */
> +	val = __vcpu_sys_reg(vcpu, PMCR_EL0);
> +	mask = ARMV8_PMU_PMCR_MASK &
> +		~(ARMV8_PMU_PMCR_P | ARMV8_PMU_PMCR_C);
> +	write_pmcr(val & mask);
> +
> +	/*
> +	 * When handling these:
> +	 * 1. Apply only the bits for guest counters (indicated by mask)
> +	 * 2. Use the different registers for set and clear
> +	 */
> +	mask = kvm_pmu_guest_counter_mask(pmu);
> +
> +	val = __vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
> +	write_pmcntenset(val & mask);
> +	write_pmcntenclr(~val & mask);
> +
> +	val = __vcpu_sys_reg(vcpu, PMINTENSET_EL1);
> +	write_pmintenset(val & mask);
> +	write_pmintenclr(~val & mask);

Is this safe? What happens if we put the PMU into an overflow condition?

> +}
> +
> +/**
> + * kvm_pmu_put() - Put untrapped PMU registers
> + * @vcpu: Pointer to struct kvm_vcpu
> + *
> + * Put all untrapped PMU registers from the VCPU into the PCPU. Mask
> + * to only bits belonging to guest-reserved counters and leave
> + * host-reserved counters alone in bitmask registers.
> + */
> +void kvm_pmu_put(struct kvm_vcpu *vcpu)
> +{
> +	struct arm_pmu *pmu;
> +	u64 mask;
> +	u8 i;
> +	u64 val;
> +
> +	/*
> +	 * If we aren't using FGT then we are trapping everything
> +	 * anyway, so no need to bother with the swap.
> +	 */
> +	if (!kvm_vcpu_pmu_use_fgt(vcpu))
> +		return;
> +
> +	pmu = vcpu->kvm->arch.arm_pmu;
> +
> +	for (i = 0; i < pmu->hpmn_max; i++) {
> +		val = read_pmevcntrn(i);
> +		__vcpu_assign_sys_reg(vcpu, PMEVCNTR0_EL0 + i, val);
> +	}
> +
> +	val = read_pmccntr();
> +	__vcpu_assign_sys_reg(vcpu, PMCCNTR_EL0, val);
> +
> +	val = read_pmuserenr();
> +	__vcpu_assign_sys_reg(vcpu, PMUSERENR_EL0, val);
> +
> +	val = read_pmselr();
> +	__vcpu_assign_sys_reg(vcpu, PMSELR_EL0, val);
> +
> +	val = read_pmcr();
> +	__vcpu_assign_sys_reg(vcpu, PMCR_EL0, val);
> +
> +	/* Mask these to only save the guest relevant bits. */
> +	mask = kvm_pmu_guest_counter_mask(pmu);
> +
> +	val = read_pmcntenset();
> +	__vcpu_assign_sys_reg(vcpu, PMCNTENSET_EL0, val & mask);
> +
> +	val = read_pmintenset();
> +	__vcpu_assign_sys_reg(vcpu, PMINTENSET_EL1, val & mask);

What if the PMU is in an overflow state at this point?

Thanks,
Oliver


From andrew at lunn.ch  Tue Dec  9 13:57:03 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Tue, 9 Dec 2025 22:57:03 +0100
Subject: [PATCH] arm64: dts: rockchip: Add compatible for Ethernet PHY
In-Reply-To: <20251209210658.458506-2-adrian.kossmann@posteo.de>
References: <20251209210658.458506-2-adrian.kossmann@posteo.de>
Message-ID: <8e4607b7-8045-413d-aa3e-c2c1a74f52a6@lunn.ch>

On Tue, Dec 09, 2025 at 09:09:33PM +0000, Adrian Kossmann wrote:
> Without the compatible string the Ethernet PHY is not bound to the
> correct driver. 

Which driver is being bound if you don't have a compatible? genphy?

It is a bit unusual for phylib to get the wrong driver, so i would
like to understand this a bit more.

	Andrew


From oupton at kernel.org  Tue Dec  9 14:00:47 2025
From: oupton at kernel.org (Oliver Upton)
Date: Tue, 9 Dec 2025 14:00:47 -0800
Subject: [PATCH v5 18/24] KVM: arm64: Enforce PMU event filter at
 vcpu_load()
In-Reply-To: <20251209205121.1871534-19-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
 <20251209205121.1871534-19-coltonlewis@google.com>
Message-ID: <aTicD5hlKhZ3rkIn@kernel.org>

On Tue, Dec 09, 2025 at 08:51:15PM +0000, Colton Lewis wrote:
> The KVM API for event filtering says that counters do not count when
> blocked by the event filter. To enforce that, the event filter must be
> rechecked on every load since it might have changed since the last
> time the guest wrote a value. If the event is filtered, exclude
> counting at all exception levels before writing the hardware.
> 
> Signed-off-by: Colton Lewis <coltonlewis at google.com>
> ---
>  arch/arm64/kvm/pmu-direct.c | 44 +++++++++++++++++++++++++++++++++++++
>  1 file changed, 44 insertions(+)
> 
> diff --git a/arch/arm64/kvm/pmu-direct.c b/arch/arm64/kvm/pmu-direct.c
> index 71977d24f489a..8d0d6d1a0d851 100644
> --- a/arch/arm64/kvm/pmu-direct.c
> +++ b/arch/arm64/kvm/pmu-direct.c
> @@ -221,6 +221,49 @@ u8 kvm_pmu_hpmn(struct kvm_vcpu *vcpu)
>  	return nr_host_cnt_max;
>  }
>  
> +/**
> + * kvm_pmu_apply_event_filter()
> + * @vcpu: Pointer to vcpu struct
> + *
> + * To uphold the guarantee of the KVM PMU event filter, we must ensure
> + * no counter counts if the event is filtered. Accomplish this by
> + * filtering all exception levels if the event is filtered.
> + */
> +static void kvm_pmu_apply_event_filter(struct kvm_vcpu *vcpu)
> +{
> +	struct arm_pmu *pmu = vcpu->kvm->arch.arm_pmu;
> +	u64 evtyper_set = ARMV8_PMU_EXCLUDE_EL0 |
> +		ARMV8_PMU_EXCLUDE_EL1;
> +	u64 evtyper_clr = ARMV8_PMU_INCLUDE_EL2;
> +	u8 i;
> +	u64 val;
> +	u64 evsel;
> +
> +	if (!pmu)
> +		return;
> +
> +	for (i = 0; i < pmu->hpmn_max; i++) {
> +		val = __vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i);
> +		evsel = val & kvm_pmu_event_mask(vcpu->kvm);
> +
> +		if (vcpu->kvm->arch.pmu_filter &&
> +		    !test_bit(evsel, vcpu->kvm->arch.pmu_filter))
> +			val |= evtyper_set;
> +
> +		val &= ~evtyper_clr;
> +		write_pmevtypern(i, val);
> +	}
> +
> +	val = __vcpu_sys_reg(vcpu, PMCCFILTR_EL0);
> +
> +	if (vcpu->kvm->arch.pmu_filter &&
> +	    !test_bit(ARMV8_PMUV3_PERFCTR_CPU_CYCLES, vcpu->kvm->arch.pmu_filter))
> +		val |= evtyper_set;
> +
> +	val &= ~evtyper_clr;
> +	write_pmccfiltr(val);
> +}

This doesn't work for nested. I agree that the hardware value of
PMEVTYPERn_EL0 needs to be under KVM control, but depending on whether
or not we're in a hyp context the meaning of the EL1 filtering bit
changes. Have a look at kvm_pmu_create_perf_event().

Thanks,
Oliver


From oupton at kernel.org  Tue Dec  9 14:06:53 2025
From: oupton at kernel.org (Oliver Upton)
Date: Tue, 9 Dec 2025 14:06:53 -0800
Subject: [PATCH v5 19/24] KVM: arm64: Implement lazy PMU context swaps
In-Reply-To: <20251209205121.1871534-20-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
 <20251209205121.1871534-20-coltonlewis@google.com>
Message-ID: <aTidfRwYLYwTfmK_@kernel.org>

On Tue, Dec 09, 2025 at 08:51:16PM +0000, Colton Lewis wrote:
> +enum vcpu_pmu_register_access {
> +	VCPU_PMU_ACCESS_UNSET,
> +	VCPU_PMU_ACCESS_VIRTUAL,
> +	VCPU_PMU_ACCESS_PHYSICAL,
> +};

This is confusing. Even when the guest is accessing registers directly
on the CPU I'd still call that "hardware assisted virtualization" and
not "physical".

> +#endif /* _ASM_ARM64_KVM_TYPES_H */
> diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
> index 0ab89c91e19cb..c2cf6b308ec60 100644
> --- a/arch/arm64/kvm/debug.c
> +++ b/arch/arm64/kvm/debug.c
> @@ -34,7 +34,7 @@ static int cpu_has_spe(u64 dfr0)
>   *  - Self-hosted Trace Filter controls (MDCR_EL2_TTRF)
>   *  - Self-hosted Trace (MDCR_EL2_TTRF/MDCR_EL2_E2TB)
>   */
> -static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu)
> +void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu)
>  {
>  	int hpmn = kvm_pmu_hpmn(vcpu);
>  
> diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
> index bde79ec1a1836..ea288a712bb5d 100644
> --- a/arch/arm64/kvm/hyp/include/hyp/switch.h
> +++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
> @@ -963,6 +963,8 @@ static bool kvm_hyp_handle_pmu_regs(struct kvm_vcpu *vcpu)
>  	if (ret)
>  		__kvm_skip_instr(vcpu);
>  
> +	kvm_pmu_set_physical_access(vcpu);
> +
>  	return ret;
>  }
>  
> diff --git a/arch/arm64/kvm/pmu-direct.c b/arch/arm64/kvm/pmu-direct.c
> index 8d0d6d1a0d851..c5767e2ebc651 100644
> --- a/arch/arm64/kvm/pmu-direct.c
> +++ b/arch/arm64/kvm/pmu-direct.c
> @@ -73,6 +73,7 @@ bool kvm_vcpu_pmu_use_fgt(struct kvm_vcpu *vcpu)
>  	u8 hpmn = vcpu->kvm->arch.nr_pmu_counters;
>  
>  	return kvm_vcpu_pmu_is_partitioned(vcpu) &&
> +		vcpu->arch.pmu.access == VCPU_PMU_ACCESS_PHYSICAL &&
>  		cpus_have_final_cap(ARM64_HAS_FGT) &&
>  		(hpmn != 0 || cpus_have_final_cap(ARM64_HAS_HPMN0));
>  }
> @@ -92,6 +93,26 @@ u64 kvm_pmu_fgt2_bits(void)
>  		| HDFGRTR2_EL2_nPMICNTR_EL0;
>  }
>  
> +/**
> + * kvm_pmu_set_physical_access()
> + * @vcpu: Pointer to vcpu struct
> + *
> + * Reconfigure the guest for physical access of PMU hardware if
> + * allowed. This means reconfiguring mdcr_el2 and loading the vCPU
> + * state onto hardware.
> + *
> + */
> +
> +void kvm_pmu_set_physical_access(struct kvm_vcpu *vcpu)
> +{
> +	if (kvm_vcpu_pmu_is_partitioned(vcpu)
> +	    && vcpu->arch.pmu.access == VCPU_PMU_ACCESS_VIRTUAL) {
> +		vcpu->arch.pmu.access = VCPU_PMU_ACCESS_PHYSICAL;
> +		kvm_arm_setup_mdcr_el2(vcpu);
> +		kvm_pmu_load(vcpu);
> +	}

It isn't immediately obvious how this guards against preemption.

Also, the general approach for these context-loading situations is to do
a full load/put on the vCPU rather than a directed load.

> +static void kvm_pmu_register_init(struct kvm_vcpu *vcpu)
> +{
> +	if (vcpu->arch.pmu.access == VCPU_PMU_ACCESS_UNSET)
> +		vcpu->arch.pmu.access = VCPU_PMU_ACCESS_VIRTUAL;

This is confusing. The zero value of the enum should be consistent with
the "unloaded" state.

> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index f2ae761625a66..d73218706b834 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -1197,6 +1197,8 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  		p->regval = __vcpu_sys_reg(vcpu, reg);
>  	}
>  
> +	kvm_pmu_set_physical_access(vcpu);
> +
>  	return true;
>  }
>  
> @@ -1302,6 +1304,8 @@ static bool access_pmovs(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  		p->regval = __vcpu_sys_reg(vcpu, PMOVSSET_EL0);
>  	}
>  
> +	kvm_pmu_set_physical_access(vcpu);
> +
>  	return true;
>  }

Aren't there a ton of other registers the guest may access before
these two? Having generic PMU register accessors would allow you to
manage residence of PMU registers from a single spot.

Thanks,
Oliver


From ebiggers at kernel.org  Tue Dec  9 14:34:17 2025
From: ebiggers at kernel.org (Eric Biggers)
Date: Tue,  9 Dec 2025 14:34:17 -0800
Subject: [PATCH] crypto: arm64/ghash - Fix incorrect output from ghash-neon
In-Reply-To: <DETXT7QI62KE.F3CGH2VWX1SC@cknow-tech.com>
References: <DETXT7QI62KE.F3CGH2VWX1SC@cknow-tech.com>
Message-ID: <20251209223417.112294-1-ebiggers@kernel.org>

Commit 9a7c987fb92b ("crypto: arm64/ghash - Use API partial block
handling") made ghash_finup() pass the wrong buffer to
ghash_do_simd_update().  As a result, ghash-neon now produces incorrect
outputs when the message length isn't divisible by 16 bytes.  Fix this.

(I didn't notice this earlier because this code is reached only on CPUs
that support NEON but not PMULL.  I haven't yet found a way to get
qemu-system-aarch64 to emulate that configuration.)

Fixes: 9a7c987fb92b ("crypto: arm64/ghash - Use API partial block handling")
Cc: stable at vger.kernel.org
Reported-by: Diederik de Haas <diederik at cknow-tech.com>
Closes: https://lore.kernel.org/linux-crypto/DETXT7QI62KE.F3CGH2VWX1SC at cknow-tech.com/
Signed-off-by: Eric Biggers <ebiggers at kernel.org>
---

If it's okay, I'd like to just take this via libcrypto-fixes.

 arch/arm64/crypto/ghash-ce-glue.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/crypto/ghash-ce-glue.c b/arch/arm64/crypto/ghash-ce-glue.c
index 7951557a285a..ef249d06c92c 100644
--- a/arch/arm64/crypto/ghash-ce-glue.c
+++ b/arch/arm64/crypto/ghash-ce-glue.c
@@ -131,11 +131,11 @@ static int ghash_finup(struct shash_desc *desc, const u8 *src,
 
 	if (len) {
 		u8 buf[GHASH_BLOCK_SIZE] = {};
 
 		memcpy(buf, src, len);
-		ghash_do_simd_update(1, ctx->digest, src, key, NULL,
+		ghash_do_simd_update(1, ctx->digest, buf, key, NULL,
 				     pmull_ghash_update_p8);
 		memzero_explicit(buf, sizeof(buf));
 	}
 	return ghash_export(desc, dst);
 }

base-commit: 7a3984bbd69055898add0fe22445f99435f33450
-- 
2.52.0



From robh at kernel.org  Tue Dec  9 14:39:12 2025
From: robh at kernel.org (Rob Herring)
Date: Tue, 9 Dec 2025 16:39:12 -0600
Subject: [PATCH v2 2/3] ARM: at91: Move PM init functions to .init_late hook
In-Reply-To: <ece2d53c-3e16-4e5e-9bb9-3ed7bb362b7b@tuxon.dev>
References: <20251120-at91-probe-v2-0-8c8592f02e8e@kernel.org>
 <20251120-at91-probe-v2-2-8c8592f02e8e@kernel.org> <ece2d53c-3e16-4e5e-9bb9-3ed7bb362b7b@tuxon.dev>
Message-ID: <CAL_JsqJ2ghfNKQPhs19F1oxJxyTsrQ47hgPwsa3hUmgbGjpi-A@mail.gmail.com>

On Sat, Nov 22, 2025 at 9:37?AM Claudiu Beznea <claudiu.beznea at tuxon.dev> wrote:
>
> Hi, Rob,
>
> On 11/20/25 23:37, Rob Herring wrote:
> > Move the AT91 PM init functions to .init_late hook to ensure driver
> > dependencies have probed.
> >
> > Cc: Nicolas Ferre <nicolas.ferre at microchip.com>
> > Cc: Alexandre Belloni <alexandre.belloni at bootlin.com>
> > Cc: linux-arm-kernel at lists.infradead.org
> > Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
>
> 'From: Rob Herring <robh at kernel.org>' != 'Signed-off-by: Rob Herring (Arm)
> <robh at kernel.org>

Before I respin, any feedback on whether this series actually works or not?

Rob


From oupton at kernel.org  Tue Dec  9 14:45:57 2025
From: oupton at kernel.org (Oliver Upton)
Date: Tue, 9 Dec 2025 14:45:57 -0800
Subject: [PATCH v5 20/24] perf: arm_pmuv3: Handle IRQs for Partitioned
 PMU guest counters
In-Reply-To: <20251209205121.1871534-21-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
 <20251209205121.1871534-21-coltonlewis@google.com>
Message-ID: <aTimpRFfr9wI9Hw5@kernel.org>

On Tue, Dec 09, 2025 at 08:51:17PM +0000, Colton Lewis wrote:
> Because ARM hardware is not yet capable of direct interrupt injection

PPI injection, it can do LPIs just fine.

> @@ -961,6 +964,12 @@ static irqreturn_t armv8pmu_handle_irq(struct arm_pmu *cpu_pmu)
>  		 */
>  		perf_event_overflow(event, &data, regs);
>  	}
> +
> +	govf = pmovsr & kvm_pmu_guest_counter_mask(cpu_pmu);
> +
> +	if (kvm_pmu_is_partitioned(cpu_pmu) && govf)
> +		kvm_pmu_handle_guest_irq(govf);
> +

The state ownership of this whole interaction is very odd. I would much
rather that KVM have full ownership of the range of counters while the
guest is loaded. By that I mean the PMUv3 driver only clears overflows
on PMCs that it owns and KVM will do the same on the back of the IRQ.

Similarly, KVM should be leaving the "guest" range of counters in a
non-overflow condition at vcpu_put().

Thanks,
Oliver


From oupton at kernel.org  Tue Dec  9 14:52:01 2025
From: oupton at kernel.org (Oliver Upton)
Date: Tue, 9 Dec 2025 14:52:01 -0800
Subject: [PATCH v5 21/24] KVM: arm64: Inject recorded guest interrupts
In-Reply-To: <20251209205121.1871534-22-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
 <20251209205121.1871534-22-coltonlewis@google.com>
Message-ID: <aTioEWHu0ZbFCjR6@kernel.org>

In no situation should KVM be injecting a "recorded" IRQ. The overflow
condition of the PMU is well defined in the architecture and we should
implement *exactly* that.

On Tue, Dec 09, 2025 at 08:51:18PM +0000, Colton Lewis wrote:
> +/**
> + * kvm_pmu_part_overflow_status() - Determine if any guest counters have overflowed
> + * @vcpu: Ponter to struct kvm_vcpu
> + *
> + * Determine if any guest counters have overflowed and therefore an
> + * IRQ needs to be injected into the guest.
> + *
> + * Return: True if there was an overflow, false otherwise
> + */
> +bool kvm_pmu_part_overflow_status(struct kvm_vcpu *vcpu)
> +{
> +	struct arm_pmu *pmu = vcpu->kvm->arch.arm_pmu;
> +	u64 mask = kvm_pmu_guest_counter_mask(pmu);
> +	u64 pmovs = __vcpu_sys_reg(vcpu, PMOVSSET_EL0);
> +	u64 pmint = read_pmintenset();
> +	u64 pmcr = read_pmcr();

How do we know that the vPMU has been loaded on the CPU at this point?

> +
> +	return (pmcr & ARMV8_PMU_PMCR_E) && (mask & pmovs & pmint);
> +}

I'd rather reuse kvm_pmu_overflow_status(), relying on the accessors to
abstract away the implementation / location of the guest PMU context.

Thanks,
Oliver


From oupton at kernel.org  Tue Dec  9 14:58:01 2025
From: oupton at kernel.org (Oliver Upton)
Date: Tue, 9 Dec 2025 14:58:01 -0800
Subject: [PATCH v5 22/24] KVM: arm64: Add KVM_CAP to partition the PMU
In-Reply-To: <20251209205121.1871534-23-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
 <20251209205121.1871534-23-coltonlewis@google.com>
Message-ID: <aTipeb2fAmUtSzzX@kernel.org>

On Tue, Dec 09, 2025 at 08:51:19PM +0000, Colton Lewis wrote:
> +
> +7.245 KVM_CAP_ARM_PARTITION_PMU
> +-------------------------------------
> +

Why can't this be a vCPU attribute similar to the other vPMU controls?
Making the UAPI consistent will make it easier for userspace to reason
about it.

Better yet, we could make the UAPI such that userspace selects a PMU
implementation and the partitioned-ness of the PMU at the same time.

> @@ -132,6 +134,16 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
>  		}
>  		mutex_unlock(&kvm->lock);
>  		break;
> +	case KVM_CAP_ARM_PARTITION_PMU:
> +		if (kvm->created_vcpus) {
> +			r = -EBUSY;
> +		} else if (!kvm_pmu_partition_ready()) {
> +			r = -EPERM;
> +		} else {
> +			r = 0;
> +			kvm_pmu_partition_enable(kvm, cap->args[0]);
> +		}
> +		break;
>  	default:
>  		break;
>  	}
> @@ -388,6 +400,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
>  	case KVM_CAP_ARM_PMU_V3:
>  		r = kvm_supports_guest_pmuv3();
>  		break;
> +	case KVM_CAP_ARM_PARTITION_PMU:
> +		r = kvm_pmu_partition_ready();

"ready" is very confusing in this context, as KVM will never be ready to
support the feature on a system w/o the prerequisites.

Thanks,
Oliver


From oupton at kernel.org  Tue Dec  9 15:00:59 2025
From: oupton at kernel.org (Oliver Upton)
Date: Tue, 9 Dec 2025 15:00:59 -0800
Subject: [PATCH v5 00/24] ARM64 PMU Partitioning
In-Reply-To: <20251209205121.1871534-1-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
Message-ID: <aTiqK7gKKKzGGwgW@kernel.org>

On Tue, Dec 09, 2025 at 08:50:57PM +0000, Colton Lewis wrote:
> This series creates a new PMU scheme on ARM, a partitioned PMU that
> allows reserving a subset of counters for more direct guest access,
> significantly reducing overhead. More details, including performance
> benchmarks, can be read in the v1 cover letter linked below.
> 
> An overview of what this series accomplishes was presented at KVM
> Forum 2025. Slides [1] and video [2] are linked below.
> 
> The long duration between v4 and v5 is due to time spent on this
> project being monopolized preparing this feature for internal
> production. As a result, there are too many improvements to fully list
> here, but I will cover the notable ones.

Thanks for reposting. I think there's still quite a bit of ground to
cover on the KVM side of this, but I would definitely appreciate it if
someone with more context on the perf side of things could chime in.

Will, IIRC you had some thoughts around counter allocation, right?

Best,
Oliver


From herbert at gondor.apana.org.au  Tue Dec  9 15:24:31 2025
From: herbert at gondor.apana.org.au (Herbert Xu)
Date: Wed, 10 Dec 2025 07:24:31 +0800
Subject: [PATCH] crypto: arm64/ghash - Fix incorrect output from
 ghash-neon
In-Reply-To: <20251209223417.112294-1-ebiggers@kernel.org>
References: <DETXT7QI62KE.F3CGH2VWX1SC@cknow-tech.com>
 <20251209223417.112294-1-ebiggers@kernel.org>
Message-ID: <aTivr6JtPIxFmKLS@gondor.apana.org.au>

On Tue, Dec 09, 2025 at 02:34:17PM -0800, Eric Biggers wrote:
> Commit 9a7c987fb92b ("crypto: arm64/ghash - Use API partial block
> handling") made ghash_finup() pass the wrong buffer to
> ghash_do_simd_update().  As a result, ghash-neon now produces incorrect
> outputs when the message length isn't divisible by 16 bytes.  Fix this.
> 
> (I didn't notice this earlier because this code is reached only on CPUs
> that support NEON but not PMULL.  I haven't yet found a way to get
> qemu-system-aarch64 to emulate that configuration.)
> 
> Fixes: 9a7c987fb92b ("crypto: arm64/ghash - Use API partial block handling")
> Cc: stable at vger.kernel.org
> Reported-by: Diederik de Haas <diederik at cknow-tech.com>
> Closes: https://lore.kernel.org/linux-crypto/DETXT7QI62KE.F3CGH2VWX1SC at cknow-tech.com/
> Signed-off-by: Eric Biggers <ebiggers at kernel.org>
> ---
> 
> If it's okay, I'd like to just take this via libcrypto-fixes.
> 
>  arch/arm64/crypto/ghash-ce-glue.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)

Thanks for catching this!

Acked-by: Herbert Xu <herbert at gondor.apana.org.au>
-- 
Email: Herbert Xu <herbert at gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt


From iuliana.prodan at nxp.com  Tue Dec  9 16:24:37 2025
From: iuliana.prodan at nxp.com (Iuliana Prodan)
Date: Wed, 10 Dec 2025 02:24:37 +0200
Subject: [RFC PATCH] remoteproc: imx_dsp_rproc: Fix multiple start/stop
 commands
In-Reply-To: <20251209140425.766742-1-daniel.baluta@nxp.com>
References: <20251209140425.766742-1-daniel.baluta@nxp.com>
Message-ID: <091a4f29-5435-428a-9a1c-ef82465211cb@nxp.com>

On 12/9/2025 4:04 PM, Daniel Baluta wrote:
> After commit 67a7bc7f0358 ("remoteproc: Use of reserved_mem_region_*
> functions for "memory-region"") following commands with
> imx-dsp-rproc started to fail:
> 
> $ echo zephyr.elf > /sys/class/remoteproc/remoteproc0/firmware
> $ echo start > /sys/class/remoteproc/remoteproc0/state
> $ echo stop > /sys/class/remoteproc/remoteproc0/state
> $ echo start > /sys/class/remoteproc/remoteproc0/state #! This fails
> -sh: echo: write error: Device or resource busy
> 
> This happens because aforementioned commit replaced devm_ioremap_wc with
> devm_ioremap_resource_wc which will "reserve" the memory region with the
> first start and then will fail at the second start if the memory
> region is already reserved.
> 
> So prefer using devm_ioremap_wc as there is no easy way to undo
> devm_iormep_resource_wc manually.
> 
> Fixes: 67a7bc7f0358 ("remoteproc: Use of_reserved_mem_region_* functions for "memory-region"")
> Signed-off-by: Daniel Baluta <daniel.baluta at nxp.com>
> ---
>   drivers/remoteproc/imx_dsp_rproc.c | 6 +++---
>   1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c
> index 5130a35214c9..79d5c15319f3 100644
> --- a/drivers/remoteproc/imx_dsp_rproc.c
> +++ b/drivers/remoteproc/imx_dsp_rproc.c
> @@ -709,10 +709,10 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv)
>   		if (imx_dsp_rproc_sys_to_da(priv, res.start, resource_size(&res), &da))
>   			return -EINVAL;
>   
> -		cpu_addr = devm_ioremap_resource_wc(dev, &res);
> -		if (IS_ERR(cpu_addr)) {
> +		cpu_addr = devm_ioremap_wc(dev, res.start, resource_size(&res));

While this patch technically "works", it?s more of a workaround because:
- it removes important resource protection;
- it doesn?t address the root cause.

The real issue is likely that:
- resources should be released on stop but aren?t;
- or the mapping should happen once during probe, not on every start.

Better alterntives:
1. move the devm_ioremap_resource_wc() to probe() and keep it mapped for 
the device lifetime. This is the typical pattern for remoteproc drivers.
2. use non-devm versions in start/stop callbacks:
/* In start callback */
cpu_addr = ioremap_wc(res.start, resource_size(&res));
/* In stop callback */
iounmap(cpu_addr);

My vote goes for option 1.

> +		if (!cpu_addr) {
>   			dev_err(dev, "failed to map memory %pR\n", &res);
> -			return PTR_ERR(cpu_addr);
> +			return -ENOMEM;
>   		}
>   
>   		/* Register memory region */



From ebiggers at kernel.org  Tue Dec  9 16:30:28 2025
From: ebiggers at kernel.org (Eric Biggers)
Date: Wed, 10 Dec 2025 00:30:28 +0000
Subject: [PATCH] crypto: arm64/ghash - Fix incorrect output from
 ghash-neon
In-Reply-To: <20251209223417.112294-1-ebiggers@kernel.org>
References: <DETXT7QI62KE.F3CGH2VWX1SC@cknow-tech.com>
 <20251209223417.112294-1-ebiggers@kernel.org>
Message-ID: <20251210003028.GA1783653@google.com>

On Tue, Dec 09, 2025 at 02:34:17PM -0800, Eric Biggers wrote:
> Commit 9a7c987fb92b ("crypto: arm64/ghash - Use API partial block
> handling") made ghash_finup() pass the wrong buffer to
> ghash_do_simd_update().  As a result, ghash-neon now produces incorrect
> outputs when the message length isn't divisible by 16 bytes.  Fix this.
> 
> (I didn't notice this earlier because this code is reached only on CPUs
> that support NEON but not PMULL.  I haven't yet found a way to get
> qemu-system-aarch64 to emulate that configuration.)
> 
> Fixes: 9a7c987fb92b ("crypto: arm64/ghash - Use API partial block handling")
> Cc: stable at vger.kernel.org
> Reported-by: Diederik de Haas <diederik at cknow-tech.com>
> Closes: https://lore.kernel.org/linux-crypto/DETXT7QI62KE.F3CGH2VWX1SC at cknow-tech.com/
> Signed-off-by: Eric Biggers <ebiggers at kernel.org>
> ---
> 
> If it's okay, I'd like to just take this via libcrypto-fixes.
> 
>  arch/arm64/crypto/ghash-ce-glue.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)

Applied to https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git/log/?h=libcrypto-fixes

(As always, additional reviews/acks still appreciated!)

- Eric


From will at kernel.org  Tue Dec  9 16:42:54 2025
From: will at kernel.org (Will Deacon)
Date: Wed, 10 Dec 2025 09:42:54 +0900
Subject: [PATCH] iommu/io-pgtable-arm: Add misisng concatenated PGD cases
In-Reply-To: <498bbad4-ea64-4a24-a63f-e131d271990a@arm.com>
References: <20251130194506.593700-1-smostafa@google.com>
 <18a39079-2285-47fb-b306-040f2bc1bbaa@arm.com>
 <aTgX9qhaLyrQ5iye@google.com>
 <498bbad4-ea64-4a24-a63f-e131d271990a@arm.com>
Message-ID: <aTjCDvtANr2WIv3L@google.com>

On Tue, Dec 09, 2025 at 01:33:36PM +0000, Robin Murphy wrote:
> On 2025-12-09 12:37 pm, Mostafa Saleh wrote:
> > On Tue, Dec 09, 2025 at 11:34:34AM +0000, Robin Murphy wrote:
> > > On 2025-11-30 7:45 pm, Mostafa Saleh wrote:
> > > > arm_lpae_concat_mandatory() assumes that OAS >= IAS which is not
> > > > correct for SMMUs supporting AArch32, and have OAS = 32/36 bits,
> > > > as IAS would be 40 bits.
> > > 
> > > But that is only when *using* AArch32 format. The bit in chapter 3.4 of the
> > > SMMU architecture is talking about the maximum IAS that an SMMU
> > > implementation needs to be able to accommodate based on its configuration,
> > > but it does then attempt to clarify that the actual IPA size in use by any
> > > given context should depend on the VMSA format in use:
> > > 
> > > "VMSAv8-32 LPAE always supports an IPA size of 40 bits, whereas VMSAv8-64
> > > and VMSAv9-128 limits the maximum IPA size to the maximum PA size."
> > > 
> > > Rule R_SRKBC in the Arm ARM lays out the exact T0SZ constraints with this
> > > AArch32/AArch64 detail.
> > 
> > I see, thanks a lot for the explanation, I got confused by the this
> > statement:
> > Note: If AArch32 is implemented, IAS == MAX(40, OAS), otherwise IAS == OAS.
> 
> Indeed, that appears confusingly contradictory; I've filed a bug.

I think the spec has always been worded like this. My reading is that, in
isolation:

  - VMSAv8-32 LPAE always uses a 40-bit IAS
  - VMSAv8-64 has IAS == OAS and this can be smaller than 40 bits

so if AArch32 is implemented, we know that the hardware supports at
least a 40-bit IAS and in that case the VMSAv8-64 IAS can be bigger
than the OAS.

That seems consistent to me; where is the contradiction?

Will (jet-lagged so may well be talking rubbish!)


From dapeng1.mi at linux.intel.com  Tue Dec  9 17:08:52 2025
From: dapeng1.mi at linux.intel.com (Mi, Dapeng)
Date: Wed, 10 Dec 2025 09:08:52 +0800
Subject: [PATCH v6 37/44] KVM: VMX: Dedup code for removing MSR from
 VMCS's auto-load list
In-Reply-To: <aTheSQb9fhXmZKw6@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
 <20251206001720.468579-38-seanjc@google.com>
 <2440b9bf-a2a1-4f66-94b2-71f47d62f3db@linux.intel.com>
 <aTheSQb9fhXmZKw6@google.com>
Message-ID: <fad66209-6dc1-4067-87df-9aa1105e3017@linux.intel.com>


On 12/10/2025 1:37 AM, Sean Christopherson wrote:
> On Mon, Dec 08, 2025, Dapeng Mi wrote:
>> On 12/6/2025 8:17 AM, Sean Christopherson wrote:
>>> Add a helper to remove an MSR from an auto-{load,store} list to dedup the
>>> msr_autoload code, and in anticipation of adding similar functionality for
>>> msr_autostore.
>>>
>>> No functional change intended.
>>>
>>> Signed-off-by: Sean Christopherson <seanjc at google.com>
>>> ---
>>>  arch/x86/kvm/vmx/vmx.c | 31 ++++++++++++++++---------------
>>>  1 file changed, 16 insertions(+), 15 deletions(-)
>>>
>>> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
>>> index 52bcb817cc15..a51f66d1b201 100644
>>> --- a/arch/x86/kvm/vmx/vmx.c
>>> +++ b/arch/x86/kvm/vmx/vmx.c
>>> @@ -1040,9 +1040,22 @@ static int vmx_find_loadstore_msr_slot(struct vmx_msrs *m, u32 msr)
>>>  	return -ENOENT;
>>>  }
>>>  
>>> +static void vmx_remove_auto_msr(struct vmx_msrs *m, u32 msr,
>>> +				unsigned long vmcs_count_field)
>>> +{
>>> +	int i;
>>> +
>>> +	i = vmx_find_loadstore_msr_slot(m, msr);
>>> +	if (i < 0)
>>> +		return;
>>> +
>>> +	--m->nr;
>>> +	m->val[i] = m->val[m->nr];
>> Sometimes the order of MSR writing does matter, e.g., PERF_GLOBAL_CTRL MSR
>> should be written at last after all PMU MSR writing.
> Hmm, no.  _If_ KVM were writing event selectors using the auto-load lists, then
> KVM would need to bookend the event selector MSRs with PERF_GLOBAL_CTRL=0 and
> PERF_GLOBAL_CTRL=<new context (guest vs. host)>.  E.g. so that guest PMC counts
> aren't polluted with host events, and vice versa.
>
> As things stand today, the only other MSRs are PEBS and the DS area configuration
> stuff, and kinda to my earlier point, KVM pre-zeroes MSR_IA32_PEBS_ENABLE as part
> of add_atomic_switch_msr() to ensure a quiescent period before VM-Enter.
>
> Heh, and writing PERF_GLOBAL_CTRL last for that sequence might actually be
> problematic.  E.g. load host PEBS with guest PERF_GLOBAL_CTRL active.
>
> Anyways, I agree that this might be brittle, but this is all pre-existing behavior
> so I don't want to tackle that here unless it's absolutely necessary.

Yeah, this won't cause any real issue for current code.?


>
> Or wait, by "writing" do you mean "writing MSRs to memory", as opposed to "writing
> values to MSRs"?  Regardless, I think my answer is the same: this isn't a problem
> today, so I'd prefer to not shuffle the ordering unless it's absolutely necessary.

Actually both. As SDM suggests, current any manipulation for PMU MSRs, the
below order should be followed.

- disable all PMU counters by writing PERF_GLOBAL_CTRL to 0.

- manipulate PMU MSRs.

- Enable the needed PMU counters by writing PERF_GLOBAL_CTRL.

So there is a implicit order on the MSR writing in fact.?

For KVM, if MSR auto-load list feature is used to automatically restore the
host/guest MSRs, KVM needs to follow the above order to fill the MSR
auto-load list and then expect these MSRs are written by VMX in the
designed order.

But since it won't cause any real issue now, it's fine for me to handle it
until there is a real necessity.


>
>> So directly moving the last MSR entry into cleared one could break the MSR
>> writing sequence and may cause issue in theory.
>>
>> I know this won't really cause issue since currently vPMU won't use the MSR
>> auto-load feature to save any PMU MSR, but it's still unsafe for future uses.?
>>
>> I'm not sure if it's worthy to do the strict MSR entry shift right now.
>>
>> Perhaps we could add a message to warn users at least.
> Hmm, yeah, but I'm not entirely sure where/how best to document this.  Because
> it's not just that vmx_remove_auto_msr() arbitrarily maniuplates the order, e.g.
> multiple calls to vmx_add_auto_msr() aren't guaranteed to provide ordering because
> one or more MSRs may already be in the list.  And the "special" MSRs that can be
> switched via dedicated VMCS fields further muddy the waters.
>
> So I'm tempted to not add a comment to the helpers, or even the struct fields,
> because unfortunately it's largely a "Here be dragons!" type warning. :-/

I see. Thanks.




From xueshuai at linux.alibaba.com  Tue Dec  9 17:53:57 2025
From: xueshuai at linux.alibaba.com (Shuai Xue)
Date: Wed, 10 Dec 2025 09:53:57 +0800
Subject: [PATCH rc v2 4/4] iommu/arm-smmu-v3-test: Add nested
 s1bypass/s1dssbypass coverage
In-Reply-To: <aTiO69YZ9WA8dFe0@nvidia.com>
References: <cover.1765140287.git.nicolinc@nvidia.com>
 <b6d87901f89c05dd9e1d0c1e819040d205f569a7.1765140287.git.nicolinc@nvidia.com>
 <f52c705d-6032-4d85-b902-dd6d0a40b9ec@linux.alibaba.com>
 <aTiO69YZ9WA8dFe0@nvidia.com>
Message-ID: <04fc0c2e-9649-4cde-9415-e7e0e7145776@linux.alibaba.com>



? 2025/12/10 05:04, Nicolin Chen ??:
> On Mon, Dec 08, 2025 at 11:43:41AM +0800, Shuai Xue wrote:
>> Hi, Nicolin,
>>
>> Nit. Instead of duplicating this code, we can leverage the existing
>> arm_smmu_test_make_cdtable_ste() helper here.
> 
> Thanks for the review. I squashed the following changes:
> 
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> index 1672e75ebffc2..197b8b55fe7a2 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> @@ -33,8 +33,12 @@ static struct mm_struct sva_mm = {
>   enum arm_smmu_test_master_feat {
>   	ARM_SMMU_MASTER_TEST_ATS = BIT(0),
>   	ARM_SMMU_MASTER_TEST_STALL = BIT(1),
> +	ARM_SMMU_MASTER_TEST_NESTED = BIT(2),
>   };
>   
> +static void arm_smmu_test_make_s2_ste(struct arm_smmu_ste *ste,
> +				      enum arm_smmu_test_master_feat feat);
> +
>   static bool arm_smmu_entry_differs_in_used_bits(const __le64 *entry,
>   						const __le64 *used_bits,
>   						const __le64 *target,
> @@ -198,6 +202,17 @@ static void arm_smmu_test_make_cdtable_ste(struct arm_smmu_ste *ste,
>   	};
>   
>   	arm_smmu_make_cdtable_ste(ste, &master, ats_enabled, s1dss);
> +	if (feat & ARM_SMMU_MASTER_TEST_NESTED) {
> +		struct arm_smmu_ste s2ste;
> +		int i;
> +
> +		arm_smmu_test_make_s2_ste(&s2ste, ARM_SMMU_MASTER_TEST_ATS);
> +		ste->data[0] |= cpu_to_le64(
> +			FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_NESTED));
> +		ste->data[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
> +		for (i = 2; i < NUM_ENTRY_QWORDS; i++)
> +			ste->data[i] = s2ste.data[i];
> +	}
>   }
>   
>   static void arm_smmu_v3_write_ste_test_bypass_to_abort(struct kunit *test)
> @@ -555,46 +570,17 @@ static void arm_smmu_v3_write_ste_test_s2_to_s1_stall(struct kunit *test)
>   						       NUM_EXPECTED_SYNCS(3));
>   }
>   
> -static void arm_smmu_test_make_nested_cdtable_ste(
> -	struct arm_smmu_ste *ste, unsigned int s1dss, const dma_addr_t dma_addr,
> -	enum arm_smmu_test_master_feat feat)
> -{
> -	bool stall_enabled = feat & ARM_SMMU_MASTER_TEST_STALL;
> -	bool ats_enabled = feat & ARM_SMMU_MASTER_TEST_ATS;
> -	struct arm_smmu_ste s1ste;
> -
> -	struct arm_smmu_master master = {
> -		.ats_enabled = ats_enabled,
> -		.cd_table.cdtab_dma = dma_addr,
> -		.cd_table.s1cdmax = 0xFF,
> -		.cd_table.s1fmt = STRTAB_STE_0_S1FMT_64K_L2,
> -		.smmu = &smmu,
> -		.stall_enabled = stall_enabled,
> -	};
> -
> -	arm_smmu_test_make_s2_ste(ste, ARM_SMMU_MASTER_TEST_ATS);
> -	arm_smmu_make_cdtable_ste(&s1ste, &master, ats_enabled, s1dss);
> -
> -	ste->data[0] = cpu_to_le64(
> -		STRTAB_STE_0_V |
> -		FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_NESTED));
> -	ste->data[0] |= s1ste.data[0] & ~cpu_to_le64(STRTAB_STE_0_CFG);
> -	ste->data[1] |= s1ste.data[1];
> -	/* Merge events for DoS mitigations on eventq */
> -	ste->data[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
> -}
> -
>   static void
>   arm_smmu_v3_write_ste_test_nested_s1dssbypass_to_s1bypass(struct kunit *test)
>   {
>   	struct arm_smmu_ste s1_ste;
>   	struct arm_smmu_ste s2_ste;
>   
> -	arm_smmu_test_make_nested_cdtable_ste(&s1_ste,
> -					      STRTAB_STE_1_S1DSS_BYPASS,
> -					      fake_cdtab_dma_addr,
> -					      ARM_SMMU_MASTER_TEST_ATS);
> +	arm_smmu_test_make_cdtable_ste(
> +		&s1_ste, STRTAB_STE_1_S1DSS_BYPASS, fake_cdtab_dma_addr,
> +		ARM_SMMU_MASTER_TEST_ATS | ARM_SMMU_MASTER_TEST_NESTED);
>   	arm_smmu_test_make_s2_ste(&s2_ste, 0);
> +	/* Expect an additional sync to unset ignored bits: EATS and MEV */
>   	arm_smmu_v3_test_ste_expect_hitless_transition(test, &s1_ste, &s2_ste,
>   						       NUM_EXPECTED_SYNCS(3));
>   }
> @@ -605,10 +591,9 @@ arm_smmu_v3_write_ste_test_nested_s1bypass_to_s1dssbypass(struct kunit *test)
>   	struct arm_smmu_ste s1_ste;
>   	struct arm_smmu_ste s2_ste;
>   
> -	arm_smmu_test_make_nested_cdtable_ste(&s1_ste,
> -					      STRTAB_STE_1_S1DSS_BYPASS,
> -					      fake_cdtab_dma_addr,
> -					      ARM_SMMU_MASTER_TEST_ATS);
> +	arm_smmu_test_make_cdtable_ste(
> +		&s1_ste, STRTAB_STE_1_S1DSS_BYPASS, fake_cdtab_dma_addr,
> +		ARM_SMMU_MASTER_TEST_ATS | ARM_SMMU_MASTER_TEST_NESTED);
>   	arm_smmu_test_make_s2_ste(&s2_ste, 0);
>   	arm_smmu_v3_test_ste_expect_hitless_transition(test, &s2_ste, &s1_ste,
>   						       NUM_EXPECTED_SYNCS(2));


Nice work. LGTM.

Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>

Thanks.
Shuai



From jacky_chou at aspeedtech.com  Tue Dec  9 18:17:31 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Wed, 10 Dec 2025 02:17:31 +0000
Subject: [PATCH v6 6/7] PCI: aspeed: Add ASPEED PCIe RC driver
In-Reply-To: <20251209001107.GA3430423@bhelgaas>
References: <20251201-upstream_pcie_rc-v6-6-8c8800c56b16@aspeedtech.com>
 <20251209001107.GA3430423@bhelgaas>
Message-ID: <SEYPR06MB513497D82F1FBBFAC6B9EE309DA0A@SEYPR06MB5134.apcprd06.prod.outlook.com>

Hi Bjorn,

Thank you for your reply.

> > +	u8 tx_tag;
> > +	int host_bus_num;
> 
> Only needs a u8.
> 

Agreed.

> > +static int aspeed_pcie_port_init(struct aspeed_pcie_port *port) {
> > +	struct aspeed_pcie *pcie = port->pcie;
> > +	struct device *dev = pcie->dev;
> > +	int ret;
> > +
> > +	ret = clk_prepare_enable(port->clk);
> > +	if (ret)
> > +		return dev_err_probe(dev, ret,
> > +				     "failed to set clock for slot (%d)\n",
> > +				     port->slot);
> > +
> > +	ret = phy_init(port->phy);
> > +	if (ret)
> > +		return dev_err_probe(dev, ret,
> > +				     "failed to init phy pcie for slot (%d)\n",
> > +				     port->slot);
> > +
> > +	ret = phy_set_mode_ext(port->phy, PHY_MODE_PCIE,
> PHY_MODE_PCIE_RC);
> > +	if (ret)
> > +		return dev_err_probe(dev, ret,
> > +				     "failed to set phy mode for slot (%d)\n",
> > +				     port->slot);
> > +
> > +	reset_control_deassert(port->perst);
> > +	mdelay(PCIE_RESET_CONFIG_WAIT_MS);
> 
> I think this should use msleep().
> 

Agreed.

> > +static int aspeed_ast2600_setup(struct platform_device *pdev) {
> > +	struct aspeed_pcie *pcie = platform_get_drvdata(pdev);
> > +	struct device *dev = pcie->dev;
> > +
> > +	pcie->ahbc = syscon_regmap_lookup_by_phandle(dev->of_node,
> > +						     "aspeed,ahbc");
> > +	if (IS_ERR(pcie->ahbc))
> > +		return dev_err_probe(dev, PTR_ERR(pcie->ahbc),
> > +				     "failed to map ahbc base\n");
> > +
> > +	aspeed_host_reset(pcie);
> > +
> > +	regmap_write(pcie->ahbc, ASPEED_AHBC_KEY,
> ASPEED_AHBC_UNLOCK_KEY);
> > +	regmap_update_bits(pcie->ahbc, ASPEED_AHBC_ADDR_MAPPING,
> > +			   ASPEED_PCIE_RC_MEMORY_EN,
> ASPEED_PCIE_RC_MEMORY_EN);
> > +	regmap_write(pcie->ahbc, ASPEED_AHBC_KEY, ASPEED_AHBC_UNLOCK);
> > +
> > +	/* Due to the BAR assignment is fixed mapping on 0x6000_0000.*/
> > +	writel(ASPEED_AHB_REMAP_LO_ADDR(0x600) |
> ASPEED_AHB_MASK_LO_ADDR(0xe00),
> > +	       pcie->reg + ASPEED_H2X_AHB_ADDR_CONFIG0);
> > +	writel(ASPEED_AHB_REMAP_HI_ADDR(0),
> > +	       pcie->reg + ASPEED_H2X_AHB_ADDR_CONFIG1);
> 
> I assume this ASPEED_H2X_AHB_ADDR_CONFIG is doing basically the same
> thing as aspeed_ast2700_remap_pci_addr() below, so see the comments
> there.
> 

Yes.

> > +	writel(ASPEED_AHB_MASK_HI_ADDR(~0),
> > +	       pcie->reg + ASPEED_H2X_AHB_ADDR_CONFIG2);
> > +	writel(ASPEED_H2X_BRIDGE_EN, pcie->reg + ASPEED_H2X_CTRL);
> > +
> > +	writel(ASPEED_PCIE_RX_DMA_EN | ASPEED_PCIE_RX_LINEAR |
> > +	       ASPEED_PCIE_RX_MSI_SEL | ASPEED_PCIE_RX_MSI_EN |
> > +	       ASPEED_PCIE_WAIT_RX_TLP_CLR |
> ASPEED_PCIE_RC_RX_ENABLE |
> > +	       ASPEED_PCIE_RC_ENABLE,
> > +	       pcie->reg + ASPEED_H2X_DEV_CTRL);
> > +
> > +	writel(ASPEED_RC_TLP_TX_TAG_NUM, pcie->reg +
> ASPEED_H2X_DEV_TX_TAG);
> > +
> > +	pcie->host->ops = &aspeed_ast2600_pcie_ops;
> > +	pcie->host->child_ops = &aspeed_ast2600_pcie_child_ops;
> > +
> > +	return 0;
> > +}
> > +
> > +static int aspeed_ast2700_remap_pci_addr(struct aspeed_pcie *pcie) {
> > +	struct device_node *dev_node = pcie->dev->of_node;
> > +	struct of_pci_range range;
> > +	struct of_pci_range_parser parser;
> > +	int ret;
> > +
> > +	ret = of_pci_range_parser_init(&parser, dev_node);
> > +	if (ret)
> > +		return ret;
> > +
> > +	for_each_of_pci_range(&parser, &range) {
> > +		if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM) {
> > +			writel(ASPEED_REMAP_PCI_ADDR_31_12(range.pci_addr),
> > +			       pcie->reg + ASPEED_H2X_REMAP_PCI_ADDR_LO);
> > +			writel(ASPEED_REMAP_PCI_ADDR_63_32(range.pci_addr),
> > +			       pcie->reg + ASPEED_H2X_REMAP_PCI_ADDR_HI);
> > +			return 0;
> 
> It looks like this is essentially hardcoding the offset between the
> parent-bus-address and the child-bus-address in the DT 'ranges'
> property.  Since ASPEED_REMAP_PCI_ADDR_31_12() and
> ASPEED_REMAP_PCI_ADDR_63_32() do nothing except mask out the low 12
> bits, I assume that offset is zero.
> 
> But this should not be hard-coded at all; it should be extracted from 'ranges'.
> I don't think we really have a consistent way of doing this, but you can take a
> look at how these other drivers program "outbound" mappings like this using
> bridge->windows:
> 
>   cdns_pcie_hpa_host_init_address_translation()
>   dw_pcie_iatu_setup()
>   mobiveil_host_init()
>   xgene_pcie_map_ranges()
>   iproc_pcie_map_ranges()
>   rzg3s_pcie_parse_map_ranges()
> 

Thank you for providing the information.
We will refer to this information to integrate the PCIe mapping range.

> > +static int aspeed_pcie_parse_dt(struct aspeed_pcie *pcie) {
> > +	struct device *dev = pcie->dev;
> > +	struct device_node *node = dev->of_node;
> > +	int ret;
> > +
> > +	for_each_available_child_of_node_scoped(node, child) {
> > +		int slot;
> > +		const char *type;
> > +
> > +		ret = of_property_read_string(child, "device_type", &type);
> > +		if (ret || strcmp(type, "pci"))
> > +			continue;
> > +
> > +		ret = of_pci_get_devfn(child);
> > +		if (ret < 0)
> > +			return dev_err_probe(dev, ret,
> > +					     "failed to parse devfn\n");
> > +
> > +		slot = PCI_SLOT(ret);
> > +
> > +		ret = aspeed_pcie_parse_port(pcie, child, slot);
> > +		if (ret)
> > +			return ret;
> 
> It looks unnecessarily complicated to put each port on a list in
> aspeed_pcie_parse_port() and then iterate over that list in
> aspeed_pcie_init_ports().
> 
> I think you could just do something like:
> 
>   aspeed_pcie_parse_port();
>   aspeed_pcie_port_init();
> 
> and get rid of the list completely.
> 

Agreed.
We will remove the list and initialize the port directly.

> > +	}
> > +
> > +	if (list_empty(&pcie->ports))
> > +		return dev_err_probe(dev, -ENODEV,
> > +				     "No PCIe port found in DT\n");
> > +
> > +	return 0;
> > +}
> > +
> > +static int aspeed_pcie_probe(struct platform_device *pdev) {
> > +	struct device *dev = &pdev->dev;
> > +	struct pci_host_bridge *host;
> > +	struct aspeed_pcie *pcie;
> > +	struct resource_entry *entry;
> > +	const struct aspeed_pcie_rc_platform *md;
> > +	int irq, ret;
> > +
> > +	md = of_device_get_match_data(dev);
> > +	if (!md)
> > +		return -ENODEV;
> > +
> > +	host = devm_pci_alloc_host_bridge(dev, sizeof(*pcie));
> > +	if (!host)
> > +		return -ENOMEM;
> > +
> > +	pcie = pci_host_bridge_priv(host);
> > +	pcie->dev = dev;
> > +	pcie->tx_tag = 0;
> > +	platform_set_drvdata(pdev, pcie);
> > +
> > +	pcie->platform = md;
> > +	pcie->host = host;
> > +	INIT_LIST_HEAD(&pcie->ports);
> > +
> > +	/* Get root bus num for cfg command to decide tlp type 0 or type 1 */
> > +	entry = resource_list_first_type(&host->windows, IORESOURCE_BUS);
> > +	if (entry)
> > +		pcie->host_bus_num = entry->res->start;
> 
> s/host_bus_num/root_bus_nr/   to match struct altera_pcie

Agreed.

Thanks,
Jacky



From broonie at kernel.org  Tue Dec  9 18:22:43 2025
From: broonie at kernel.org (Mark Brown)
Date: Wed, 10 Dec 2025 11:22:43 +0900
Subject: [PATCH 4/7] ASoC: soc-dai: define TDM idle behaviour modes
In-Reply-To: <20251209-tdm-idle-slots-v1-4-38dabf6bc01e@gmail.com>
References: <20251209-tdm-idle-slots-v1-0-38dabf6bc01e@gmail.com>
 <20251209-tdm-idle-slots-v1-4-38dabf6bc01e@gmail.com>
Message-ID: <aTjZc3mgu7CQOkDU@sirena.co.uk>

On Tue, Dec 09, 2025 at 07:31:17PM +1000, James Calligeros wrote:

> Imagine for example two codecs sharing a bus. When one codec is
> transmitting, the other must ensure that it is holding its side
> to 0, or data from the transmitting codec will be corrupted. We
> can trust the "idle" codec to simply do this itself, however
> this is undefined behaviour. Some devices may leave the line
> floating, others still may pull the line high. We need a way to
> control this behaviour.

I'm finding this explanation quite confusing - you appear to be
describing the situation where two devices simultaneously drive the same
signal which would be extremely unusual and I can't see how it would
work electrically.

> Thus, we define five possible bus-keeping modes that a device can
> be in: NONE (UB/as initialised), OFF (explicitly disabled), ZERO
> (actively transmit a 0), PULLDOWN, and HIZ (floating).

What is "explicitly disabled" in ths context?  Why aren't pull up or
drive high options?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251210/86a804f4/attachment.sig>

From anshuman.khandual at arm.com  Tue Dec  9 18:22:51 2025
From: anshuman.khandual at arm.com (Anshuman Khandual)
Date: Wed, 10 Dec 2025 07:52:51 +0530
Subject: [PATCH 19/19] perf: cs-etm: Set watermark for AUX trace
In-Reply-To: <5ebf1743-b01c-4664-961c-9e1e2aa7ffce@linaro.org>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-19-7da32b076b28@arm.com>
 <c22b084b-3853-405d-8b43-397786af7be9@arm.com>
 <5ebf1743-b01c-4664-961c-9e1e2aa7ffce@linaro.org>
Message-ID: <d39d633c-a009-41ba-8546-1137509cf678@arm.com>



On 09/12/25 8:24 PM, James Clark wrote:
> 
> 
> On 05/12/2025 4:48 am, Anshuman Khandual wrote:
>> On 01/12/25 4:52 PM, Leo Yan wrote:
>>> The default watermark is half of the total buffer size. In many cases,
>>> the tool can not be notified with sufficient free space, especially when
>>> profiling with small AUX buffer (e.g., 64KiB).
>>
>> Could not smaller AUX buffer be prevented for TRBE instead ?
>>
> 
> It's not really about the size of the buffer but where the wakeup points are. With only two wakeup points (middle and end) once you pass the first one you are immediately into the last chance end section.
> 
> Now the driver is writing into the end section, but Perf is still reading from the first one. Once the end one fills up, you end up with no space left without Perf having a chance to say it's finished reading.

Understood.

> 
> To guarantee free space, there needs to be at least one additional section as a buffer zone. Ideally we'd set the wakeup point at thirds so there were fewer wakeups and still have one free section, but it might not always divide by 3, so 4 is also fine.
> 
> The commit message could probably explain it a bit better though.

Agreed, the commit message should explain this problem in detail. Otherwise it appeared
as if the buffer sizing alone is impacting the perf records collection.

> 
> The reason this is different now is because we want to be able to enable wrap mode as much as possible. If you imagine the scenario where a half way watermark is hit, you can't enable wrap mode without wrapping into Perf's part of the buffer (the beginning) as it's all that's left after the second half.

Got it.

> 
>>>> Setting watermark to quarter of the buffer to notifies the tool to read
>>> data earlier and prevents the data loss.
>>>
>>> Signed-off-by: Leo Yan <leo.yan at arm.com>
>>> ---
>>> ? tools/perf/arch/arm/util/cs-etm.c | 7 +++++++
>>> ? 1 file changed, 7 insertions(+)
>>>
>>> diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
>>> index ea891d12f8f40beebf8dee1d3db71cad701f5666..649b8b0d0f92b4af45fb97db9da3c5ccf24a978b 100644
>>> --- a/tools/perf/arch/arm/util/cs-etm.c
>>> +++ b/tools/perf/arch/arm/util/cs-etm.c
>>> @@ -424,6 +424,13 @@ static int cs_etm_recording_options(struct auxtrace_record *itr,
>>> ????????? pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME,
>>> ??????????????? opts->auxtrace_snapshot_size);
>>> ? +??? if (!opts->auxtrace_snapshot_mode && !opts->auxtrace_sample_mode) {
>>> +??????? size_t aw = opts->auxtrace_mmap_pages * (size_t)page_size / 4;
>>> +??????? u32 aux_watermark = aw > UINT_MAX ? UINT_MAX : aw;
>>> +
>>> +??????? cs_etm_evsel->core.attr.aux_watermark = aux_watermark;
>>> +??? }
>>> +
>>> ????? /*
>>> ?????? * To obtain the auxtrace buffer file descriptor, the auxtrace
>>> ?????? * event must come first.
>>>
>>
> 



From broonie at kernel.org  Tue Dec  9 18:43:08 2025
From: broonie at kernel.org (Mark Brown)
Date: Wed, 10 Dec 2025 11:43:08 +0900
Subject: [PATCH 0/7] ASoC: basic support for configuring bus keepers
In-Reply-To: <20251209-tdm-idle-slots-v1-0-38dabf6bc01e@gmail.com>
References: <20251209-tdm-idle-slots-v1-0-38dabf6bc01e@gmail.com>
Message-ID: <aTjePJuPNegXc9cl@sirena.co.uk>

On Tue, Dec 09, 2025 at 07:31:13PM +1000, James Calligeros wrote:

> Consider a device with two codecs that report voice coil voltage and
> current data back to the host via I2S. Codec A is configured to transmit
> its V/ISENSE data on TDM slots 1 and 3, while Codec B is configured to
> do so on slots 2 and 4. The receiving end sums the two together.
> If Codec A transmits anything on slots 2 or 4 (and vice versa), the
> result is a bus conflict.

> Some codecs include configurable bus keepers to ameliorate this issue.

You've not really mentioned an issue here?  The expected behaviour for
TDM is that devices should only drive the the slots they are configured
to drive and should let the bus float otherwise, otherwise no other
device could transmit.

> Notable examples are the TI TAS2764 and TAS2770. By default, these
> codecs keep their SDOUT pin floating during unconfigured TDM slots,
> however this can result in garbage data on the bus. TAS2764 can be
> set up to fill specific TDM slots with zeroes, TAS2770 can hold its
> SDOUT pin to ground.

Right, so AIUI this is the actual thing you're trying to do - you want
to additionally configure a CODEC to drive slots it's not putting data
on to ensure there are no dead slots on the bus?  I guess you might have
some restrictions on clocking which mean you need extra BCLKs (eg,
needing power of 2 clocks).  But I'm having a hard time connecting this
to your description below so I don't think I've followed what you're
saying here.

> This feature is necessary to properly drive the speaker systems found
> on most Apple Silicon laptops. All but three models include six codecs
> in two groups of three driving two woofers and a tweeter on both the left
> and right channels. Each codec group has a single line for SDOUT, to
> which all codecs are connected. The two groups are then summed on to
> one I2S port. Each group must ensure that it is silent on the bus while
> the other is supposed to be active.

So is there one SDOUT or two which are connected... somehow?  I'm
confused.

> In the downstream Asahi Linux kernel[1], we set up one codec in each
> group to zero-fill or pull down its group's side of the bus for the
> opposite group's transmit slots. This is done entirely in the codec
> driver, however this approach is perhaps over-fit for our use case.
> Following previous mailing list discussions[2], I have tried to
> expose the functionality in a more configurable and generic way.

I can't parse what this is describing at all, sorry.  What is a "side"
of a bus, and how is all this different to idle TDM slots?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251210/f6de9498/attachment.sig>

From nicolinc at nvidia.com  Tue Dec  9 18:45:17 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Tue, 9 Dec 2025 18:45:17 -0800
Subject: [PATCH rc v3 2/4] iommu/arm-smmu-v3: Ignore STE MEV when computing the update sequence
In-Reply-To: <cover.1765334526.git.nicolinc@nvidia.com>
References: <cover.1765334526.git.nicolinc@nvidia.com>
Message-ID: <0066c711b12af33b39a078ce0d0367e2b692f590.1765334526.git.nicolinc@nvidia.com>

From: Jason Gunthorpe <jgg at nvidia.com>

Nested CD tables set the MEV bit to try to reduce multi-fault spamming on
the hypervisor. Since MEV is in STE word 1 this causes a breaking update
sequence that is not required and impacts real workloads.

For the purposes of STE updates the value of MEV doesn't matter, if it is
set/cleared early or late it just results in a change to the fault reports
that must be supported by the kernel anyhow. The spec says:

 Note: Software must expect, and be able to deal with, coalesced fault
 records even when MEV == 0.

So ignore MEV when computing the update sequence to avoid creating a
breaking update.

Fixes: da0c56520e88 ("iommu/arm-smmu-v3: Set MEV bit in nested STE for DoS mitigations")
Cc: stable at vger.kernel.org
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index e22c0890041b..3e161d8298d9 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1085,6 +1085,16 @@ EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_used);
 VISIBLE_IF_KUNIT
 void arm_smmu_get_ste_ignored(__le64 *ignored_bits)
 {
+	/*
+	 * MEV does not meaningfully impact the operation of the HW, it only
+	 * changes how many fault events are generated, thus we can ignore it
+	 * when computing the ordering. The spec notes the device can act like
+	 * MEV=1 anyhow:
+	 *
+	 *  Note: Software must expect, and be able to deal with, coalesced
+	 *  fault records even when MEV == 0.
+	 */
+	ignored_bits[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
 }
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_ignored);
 
-- 
2.43.0



From nicolinc at nvidia.com  Tue Dec  9 18:45:18 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Tue, 9 Dec 2025 18:45:18 -0800
Subject: [PATCH rc v3 3/4] iommu/arm-smmu-v3: Ignore STE EATS when computing the update sequence
In-Reply-To: <cover.1765334526.git.nicolinc@nvidia.com>
References: <cover.1765334526.git.nicolinc@nvidia.com>
Message-ID: <7c0b9c00d50ca22b078117f7f1b9a49cc41eec2e.1765334527.git.nicolinc@nvidia.com>

From: Jason Gunthorpe <jgg at nvidia.com>

If a VM wants to toggle EATS off at the same time as changing the CFG, the
hypervisor will see EATS change to 0 and insert a V=0 breaking update into
the STE even though the VM did not ask for that.

In bare metal, EATS is ignored by CFG=ABORT/BYPASS, which is why this does
not cause a problem until we have nested where CFG is always a variation of
S2 trans that does use EATS.

Relax the rules for EATS sequencing, we don't need it to be exact because
the enclosing code will always disable ATS at the PCI device if we are
changing EATS. This ensures there are no ATS transactions that can race
with an EATS change so we don't need to carefully sequence these bits.

Fixes: 1e8be08d1c91 ("iommu/arm-smmu-v3: Support IOMMU_DOMAIN_NESTED")
Cc: stable at vger.kernel.org
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 3e161d8298d9..72ba41591fdb 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1095,6 +1095,15 @@ void arm_smmu_get_ste_ignored(__le64 *ignored_bits)
 	 *  fault records even when MEV == 0.
 	 */
 	ignored_bits[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
+
+	/*
+	 * EATS is used to reject and control the ATS behavior of the device. If
+	 * we are changing it away from 0 then we already trust the device to
+	 * use ATS properly and we have sequenced the device's ATS enable in PCI
+	 * config space to prevent it from issuing ATS while we are changing
+	 * EATS.
+	 */
+	ignored_bits[1] |= cpu_to_le64(STRTAB_STE_1_EATS);
 }
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_ignored);
 
-- 
2.43.0



From nicolinc at nvidia.com  Tue Dec  9 18:45:15 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Tue, 9 Dec 2025 18:45:15 -0800
Subject: [PATCH rc v3 0/4] : iommu/arm-smmu-v3: Fix hitless STE update in nesting cases
Message-ID: <cover.1765334526.git.nicolinc@nvidia.com>

Occasional C_BAD_STE errors were observed in nesting setups where a device
attached to a nested bypass/identity domain enables PASID.

This occurred when the physical STE was updated from S2-only mode to S1+S2
nesting mode, but the update failed to use the hitless routine that it was
supposed to use. Instead, it cleared STE.V bit to load the CD table, while
the default substream was still actively performing DMA.

It was later found that the diff algorithm in arm_smmu_entry_qword_diff()
enforced an additional critical word due to misaligned MEV and EATS fields
between S2-only and S1+S2 modes.

Both fields are either well-managed or non-critical, so move them to the
"ignored" list to relax the qword diff algorithm.

Additionally, add KUnit test coverage for these nesting STE cases.

This is on Github:
https://github.com/nicolinc/iommufd/commits/smmuv3_ste_fixes/

A host kernel must apply this to fix the bug.

Changelog
v3:
 * Add Reviewed-by from Shuai
 * Add an inline comments in nested test cases
 * Reuse arm_smmu_test_make_cdtable_ste() for nested test cases
v2:
 https://lore.kernel.org/all/cover.1765140287.git.nicolinc at nvidia.com/
 * Fix kunit tests
 * Update commit message and inline comments
 * Keep MEV/EATS in used list by masking them away using ignored_bits
v1:
 https://lore.kernel.org/all/cover.1764982046.git.nicolinc at nvidia.com/

Jason Gunthorpe (3):
  iommu/arm-smmu-v3: Add ignored bits to fix STE update sequence
  iommu/arm-smmu-v3: Ignore STE MEV when computing the update sequence
  iommu/arm-smmu-v3: Ignore STE EATS when computing the update sequence

Nicolin Chen (1):
  iommu/arm-smmu-v3-test: Add nested s1bypass/s1dssbypass coverage

 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  2 +
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  | 65 ++++++++++++++++++-
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 43 ++++++++++--
 3 files changed, 102 insertions(+), 8 deletions(-)

-- 
2.43.0



From nicolinc at nvidia.com  Tue Dec  9 18:45:19 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Tue, 9 Dec 2025 18:45:19 -0800
Subject: [PATCH rc v3 4/4] iommu/arm-smmu-v3-test: Add nested s1bypass/s1dssbypass coverage
In-Reply-To: <cover.1765334526.git.nicolinc@nvidia.com>
References: <cover.1765334526.git.nicolinc@nvidia.com>
Message-ID: <229cbb478c40a031a0399d1037e07195139cdeba.1765334527.git.nicolinc@nvidia.com>

STE in a nested case requires both S1 and S2 fields. And this makes the use
case different from the existing one.

Add coverage for previously failed cases shifting between S2-only and S1+S2
STEs.

Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  | 46 +++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
index 3556e65cf9ac..ffa43e103692 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
@@ -33,8 +33,12 @@ static struct mm_struct sva_mm = {
 enum arm_smmu_test_master_feat {
 	ARM_SMMU_MASTER_TEST_ATS = BIT(0),
 	ARM_SMMU_MASTER_TEST_STALL = BIT(1),
+	ARM_SMMU_MASTER_TEST_NESTED = BIT(2),
 };
 
+static void arm_smmu_test_make_s2_ste(struct arm_smmu_ste *ste,
+				      enum arm_smmu_test_master_feat feat);
+
 static bool arm_smmu_entry_differs_in_used_bits(const __le64 *entry,
 						const __le64 *used_bits,
 						const __le64 *target,
@@ -198,6 +202,17 @@ static void arm_smmu_test_make_cdtable_ste(struct arm_smmu_ste *ste,
 	};
 
 	arm_smmu_make_cdtable_ste(ste, &master, ats_enabled, s1dss);
+	if (feat & ARM_SMMU_MASTER_TEST_NESTED) {
+		struct arm_smmu_ste s2ste;
+		int i;
+
+		arm_smmu_test_make_s2_ste(&s2ste, ARM_SMMU_MASTER_TEST_ATS);
+		ste->data[0] |= cpu_to_le64(
+			FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_NESTED));
+		ste->data[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
+		for (i = 2; i < NUM_ENTRY_QWORDS; i++)
+			ste->data[i] = s2ste.data[i];
+	}
 }
 
 static void arm_smmu_v3_write_ste_test_bypass_to_abort(struct kunit *test)
@@ -555,6 +570,35 @@ static void arm_smmu_v3_write_ste_test_s2_to_s1_stall(struct kunit *test)
 						       NUM_EXPECTED_SYNCS(3));
 }
 
+static void
+arm_smmu_v3_write_ste_test_nested_s1dssbypass_to_s1bypass(struct kunit *test)
+{
+	struct arm_smmu_ste s1_ste;
+	struct arm_smmu_ste s2_ste;
+
+	arm_smmu_test_make_cdtable_ste(
+		&s1_ste, STRTAB_STE_1_S1DSS_BYPASS, fake_cdtab_dma_addr,
+		ARM_SMMU_MASTER_TEST_ATS | ARM_SMMU_MASTER_TEST_NESTED);
+	arm_smmu_test_make_s2_ste(&s2_ste, 0);
+	/* Expect an additional sync to unset ignored bits: EATS and MEV */
+	arm_smmu_v3_test_ste_expect_hitless_transition(test, &s1_ste, &s2_ste,
+						       NUM_EXPECTED_SYNCS(3));
+}
+
+static void
+arm_smmu_v3_write_ste_test_nested_s1bypass_to_s1dssbypass(struct kunit *test)
+{
+	struct arm_smmu_ste s1_ste;
+	struct arm_smmu_ste s2_ste;
+
+	arm_smmu_test_make_cdtable_ste(
+		&s1_ste, STRTAB_STE_1_S1DSS_BYPASS, fake_cdtab_dma_addr,
+		ARM_SMMU_MASTER_TEST_ATS | ARM_SMMU_MASTER_TEST_NESTED);
+	arm_smmu_test_make_s2_ste(&s2_ste, 0);
+	arm_smmu_v3_test_ste_expect_hitless_transition(test, &s2_ste, &s1_ste,
+						       NUM_EXPECTED_SYNCS(2));
+}
+
 static void arm_smmu_v3_write_cd_test_sva_clear(struct kunit *test)
 {
 	struct arm_smmu_cd cd = {};
@@ -601,6 +645,8 @@ static struct kunit_case arm_smmu_v3_test_cases[] = {
 	KUNIT_CASE(arm_smmu_v3_write_cd_test_s1_change_asid),
 	KUNIT_CASE(arm_smmu_v3_write_ste_test_s1_to_s2_stall),
 	KUNIT_CASE(arm_smmu_v3_write_ste_test_s2_to_s1_stall),
+	KUNIT_CASE(arm_smmu_v3_write_ste_test_nested_s1dssbypass_to_s1bypass),
+	KUNIT_CASE(arm_smmu_v3_write_ste_test_nested_s1bypass_to_s1dssbypass),
 	KUNIT_CASE(arm_smmu_v3_write_cd_test_sva_clear),
 	KUNIT_CASE(arm_smmu_v3_write_cd_test_sva_release),
 	{},
-- 
2.43.0



From nicolinc at nvidia.com  Tue Dec  9 18:45:16 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Tue, 9 Dec 2025 18:45:16 -0800
Subject: [PATCH rc v3 1/4] iommu/arm-smmu-v3: Add ignored bits to fix STE update sequence
In-Reply-To: <cover.1765334526.git.nicolinc@nvidia.com>
References: <cover.1765334526.git.nicolinc@nvidia.com>
Message-ID: <cc0d4ab571e2e789ee1cddfa035379dc54f0601b.1765334526.git.nicolinc@nvidia.com>

From: Jason Gunthorpe <jgg at nvidia.com>

C_BAD_STE was observed when updating nested STE from an S1-bypass mode to
an S1DSS-bypass mode. As both modes enabled S2, the used bit is slightly
different than the normal S1-bypass and S1DSS-bypass modes. As a result,
fields like MEV and EATS in S2's used list marked the word1 as a critical
word that requested a STE.V=0. This breaks a hitless update.

However, both MEV and EATS aren't critical in terms of STE update. One
controls the merge of the events and the other controls the ATS that is
managed by the driver at the same time via pci_enable_ats().

Add an arm_smmu_get_ste_ignored() to allow STE update algorithm to ignore
those fields, avoiding the STE update breakages.

Note that this change is required by both MEV and EATS fields, which were
introduced in different kernel versions. So add this get_ignored() first.
The MEV and EATS will be added in arm_smmu_get_ste_ignored() separately.

Fixes: 1e8be08d1c91 ("iommu/arm-smmu-v3: Support IOMMU_DOMAIN_NESTED")
Cc: stable at vger.kernel.org
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  2 ++
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  | 19 ++++++++++++---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 24 +++++++++++++++----
 3 files changed, 37 insertions(+), 8 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index ae23aacc3840..d5f0e5407b9f 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -900,6 +900,7 @@ struct arm_smmu_entry_writer {
 
 struct arm_smmu_entry_writer_ops {
 	void (*get_used)(const __le64 *entry, __le64 *used);
+	void (*get_ignored)(__le64 *ignored_bits);
 	void (*sync)(struct arm_smmu_entry_writer *writer);
 };
 
@@ -911,6 +912,7 @@ void arm_smmu_make_s2_domain_ste(struct arm_smmu_ste *target,
 
 #if IS_ENABLED(CONFIG_KUNIT)
 void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits);
+void arm_smmu_get_ste_ignored(__le64 *ignored_bits);
 void arm_smmu_write_entry(struct arm_smmu_entry_writer *writer, __le64 *cur,
 			  const __le64 *target);
 void arm_smmu_get_cd_used(const __le64 *ent, __le64 *used_bits);
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
index d2671bfd3798..3556e65cf9ac 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
@@ -38,13 +38,16 @@ enum arm_smmu_test_master_feat {
 static bool arm_smmu_entry_differs_in_used_bits(const __le64 *entry,
 						const __le64 *used_bits,
 						const __le64 *target,
+						const __le64 *ignored,
 						unsigned int length)
 {
 	bool differs = false;
 	unsigned int i;
 
 	for (i = 0; i < length; i++) {
-		if ((entry[i] & used_bits[i]) != target[i])
+		__le64 used = used_bits[i] & ~ignored[i];
+
+		if ((entry[i] & used) != (target[i] & used))
 			differs = true;
 	}
 	return differs;
@@ -56,12 +59,18 @@ arm_smmu_test_writer_record_syncs(struct arm_smmu_entry_writer *writer)
 	struct arm_smmu_test_writer *test_writer =
 		container_of(writer, struct arm_smmu_test_writer, writer);
 	__le64 *entry_used_bits;
+	__le64 *ignored;
 
 	entry_used_bits = kunit_kzalloc(
 		test_writer->test, sizeof(*entry_used_bits) * NUM_ENTRY_QWORDS,
 		GFP_KERNEL);
 	KUNIT_ASSERT_NOT_NULL(test_writer->test, entry_used_bits);
 
+	ignored = kunit_kzalloc(test_writer->test,
+				sizeof(*ignored) * NUM_ENTRY_QWORDS,
+				GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test_writer->test, ignored);
+
 	pr_debug("STE value is now set to: ");
 	print_hex_dump_debug("    ", DUMP_PREFIX_NONE, 16, 8,
 			     test_writer->entry,
@@ -79,14 +88,17 @@ arm_smmu_test_writer_record_syncs(struct arm_smmu_entry_writer *writer)
 		 * configuration.
 		 */
 		writer->ops->get_used(test_writer->entry, entry_used_bits);
+		if (writer->ops->get_ignored)
+			writer->ops->get_ignored(ignored);
 		KUNIT_EXPECT_FALSE(
 			test_writer->test,
 			arm_smmu_entry_differs_in_used_bits(
 				test_writer->entry, entry_used_bits,
-				test_writer->init_entry, NUM_ENTRY_QWORDS) &&
+				test_writer->init_entry, ignored,
+				NUM_ENTRY_QWORDS) &&
 				arm_smmu_entry_differs_in_used_bits(
 					test_writer->entry, entry_used_bits,
-					test_writer->target_entry,
+					test_writer->target_entry, ignored,
 					NUM_ENTRY_QWORDS));
 	}
 }
@@ -106,6 +118,7 @@ arm_smmu_v3_test_debug_print_used_bits(struct arm_smmu_entry_writer *writer,
 static const struct arm_smmu_entry_writer_ops test_ste_ops = {
 	.sync = arm_smmu_test_writer_record_syncs,
 	.get_used = arm_smmu_get_ste_used,
+	.get_ignored = arm_smmu_get_ste_ignored,
 };
 
 static const struct arm_smmu_entry_writer_ops test_cd_ops = {
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index d16d35c78c06..e22c0890041b 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1082,6 +1082,12 @@ void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits)
 }
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_used);
 
+VISIBLE_IF_KUNIT
+void arm_smmu_get_ste_ignored(__le64 *ignored_bits)
+{
+}
+EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_ignored);
+
 /*
  * Figure out if we can do a hitless update of entry to become target. Returns a
  * bit mask where 1 indicates that qword needs to be set disruptively.
@@ -1094,13 +1100,22 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
 {
 	__le64 target_used[NUM_ENTRY_QWORDS] = {};
 	__le64 cur_used[NUM_ENTRY_QWORDS] = {};
+	__le64 ignored[NUM_ENTRY_QWORDS] = {};
 	u8 used_qword_diff = 0;
 	unsigned int i;
 
 	writer->ops->get_used(entry, cur_used);
 	writer->ops->get_used(target, target_used);
+	if (writer->ops->get_ignored)
+		writer->ops->get_ignored(ignored);
 
 	for (i = 0; i != NUM_ENTRY_QWORDS; i++) {
+		/*
+		 * Ignored is only used for bits that are used by both entries,
+		 * otherwise it is sequenced according to the unused entry.
+		 */
+		ignored[i] &= target_used[i] & cur_used[i];
+
 		/*
 		 * Check that masks are up to date, the make functions are not
 		 * allowed to set a bit to 1 if the used function doesn't say it
@@ -1109,6 +1124,7 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
 		WARN_ON_ONCE(target[i] & ~target_used[i]);
 
 		/* Bits can change because they are not currently being used */
+		cur_used[i] &= ~ignored[i];
 		unused_update[i] = (entry[i] & cur_used[i]) |
 				   (target[i] & ~cur_used[i]);
 		/*
@@ -1207,12 +1223,9 @@ void arm_smmu_write_entry(struct arm_smmu_entry_writer *writer, __le64 *entry,
 		entry_set(writer, entry, target, 0, 1);
 	} else {
 		/*
-		 * No inuse bit changed. Sanity check that all unused bits are 0
-		 * in the entry. The target was already sanity checked by
-		 * compute_qword_diff().
+		 * No inuse bit changed, though ignored bits may have changed.
 		 */
-		WARN_ON_ONCE(
-			entry_set(writer, entry, target, 0, NUM_ENTRY_QWORDS));
+		entry_set(writer, entry, target, 0, NUM_ENTRY_QWORDS);
 	}
 }
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_write_entry);
@@ -1543,6 +1556,7 @@ static void arm_smmu_ste_writer_sync_entry(struct arm_smmu_entry_writer *writer)
 static const struct arm_smmu_entry_writer_ops arm_smmu_ste_writer_ops = {
 	.sync = arm_smmu_ste_writer_sync_entry,
 	.get_used = arm_smmu_get_ste_used,
+	.get_ignored = arm_smmu_get_ste_ignored,
 };
 
 static void arm_smmu_write_ste(struct arm_smmu_master *master, u32 sid,
-- 
2.43.0



From jacky_chou at aspeedtech.com  Tue Dec  9 18:51:11 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Wed, 10 Dec 2025 02:51:11 +0000
Subject: [PATCH net v2] net: mdio: aspeed: add dummy read to avoid
 read-after-write issue
In-Reply-To: <aTgHva-UVEPl9EAR@shell.armlinux.org.uk>
References: <20251209-aspeed_mdio_add_dummy_read-v2-1-5f6061641989@aspeedtech.com>
 <aTgHva-UVEPl9EAR@shell.armlinux.org.uk>
Message-ID: <SEYPR06MB5134FEDC81B12477031E2C179DA0A@SEYPR06MB5134.apcprd06.prod.outlook.com>

Hi Russell King,

> > +	(void)ioread32(ctx->base + ASPEED_MDIO_CTRL);
> 
> What purpose does this cast to void achieve in an already void context?
> 
> We have plenty of functions that get called in the kernel that return a value
> which the caller ignores, never assigning to a variable, none of these warn.
> 

Thanks for pointing this out.

On some older compilers I used to encounter warnings when ignoring a 
function's return value, so adding (void) became a habitual practice.
You're right that it is unnecessary in the kernel context today.
I'll remove it in the next revision.

Thanks,
Jacky



From ruanjinjie at huawei.com  Tue Dec  9 18:56:56 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Wed, 10 Dec 2025 10:56:56 +0800
Subject: [PATCH v9 14/16] arm64: Inline el0_svc_common()
In-Reply-To: <746211f0-74b7-4935-a036-48a00bb5701b@arm.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
 <20251204082123.2792067-15-ruanjinjie@huawei.com>
 <746211f0-74b7-4935-a036-48a00bb5701b@arm.com>
Message-ID: <132ceb8f-e82d-bed7-7b93-41f5dd505a03@huawei.com>



On 2025/12/9 21:48, Kevin Brodsky wrote:
> On 04/12/2025 09:21, Jinjie Ruan wrote:
>> After switch arm64 to Generic Entry, the compiler no longer inlines
> 
> Did it inline it before this series?

Yes, as below

<do_el0_svc>:
       d503201f        nop
       d503201f        nop
       d503233f        paciasp
       a9be7bfd        stp     x29, x30, [sp, #-32]!
       910003fd        mov     x29, sp
       a90153f3        stp     x19, x20, [sp, #16]
       aa0003f3        mov     x19, x0
       d5384114        mrs     x20, sp_el0
       f9400001        ldr     x1, [x0]
       f9400282        ldr     x2, [x20]
       f9008801        str     x1, [x0, #272]
       f9402001        ldr     x1, [x0, #64]
       b9011801        str     w1, [x0, #280]
       373001e2        tbnz    w2, #6, ffff80008002c0f0 <do_el0_svc+0x70>
       f278105f        tst     x2, #0x1f00
       54000261        b.ne    ffff80008002c108 <do_el0_svc+0x88>  // b.any
       52803ac2        mov     w2, #0x1d6                      // #470
       97ffffb1        bl      ffff80008002bf88 <invoke_syscall.constprop.0>
       f9400280        ldr     x0, [x20]
       92783400        and     x0, x0, #0x3fff00
       926bdc00        and     x0, x0, #0xffffffffffe01fff
       b4000060        cbz     x0, ffff80008002c0e0 <do_el0_svc+0x60>
       aa1303e0        mov     x0, x19
       97ffc835        bl      ffff80008001e1b0 <syscall_trace_exit>
       a94153f3        ldp     x19, x20, [sp, #16]
       a8c27bfd        ldp     x29, x30, [sp], #32
       d50323bf        autiasp
       d65f03c0        ret
       92804000        mov     x0, #0xfffffffffffffdff         // #-513
       f9000260        str     x0, [x19]
       a94153f3        ldp     x19, x20, [sp, #16]
       a8c27bfd        ldp     x29, x30, [sp], #32
       d50323bf        autiasp
       d65f03c0        ret
       3100043f        cmn     w1, #0x1
       54000140        b.eq    ffff80008002c134 <do_el0_svc+0xb4>  // b.none
       aa1303e0        mov     x0, x19
       97ffc7c1        bl      ffff80008001e018 <syscall_trace_enter>
       2a0003e1        mov     w1, w0
       3100041f        cmn     w0, #0x1
       54fffdc0        b.eq    ffff80008002c0d8 <do_el0_svc+0x58>  // b.none
       aa1303e0        mov     x0, x19
       52803ac2        mov     w2, #0x1d6                      // #470
       97ffff97        bl      ffff80008002bf88 <invoke_syscall.constprop.0>
       17ffffea        b       ffff80008002c0d8 <do_el0_svc+0x58>
       928004a0        mov     x0, #0xffffffffffffffda         // #-38
       f9000260        str     x0, [x19]
       17fffff5        b       ffff80008002c110 <do_el0_svc+0x90>
       d53cd044        mrs     x4, tpidr_el2
       d53cd040        mrs     x0, tpidr_el2
       d53cd041        mrs     x1, tpidr_el2
       00000000        udf     #0
       d503201f        nop
       d503201f        nop

> 
>> el0_svc_common() into do_el0_svc(). So inline el0_svc_common() and it
>> has 1% performance uplift on perf bench basic syscall on kunpeng920
>> as below.
>>
>> | Metric     | W/O this patch | With this patch | Change    |
>> | ---------- | -------------- | --------------- | --------- |
>> | Total time | 2.195 [sec]    | 2.171 [sec]     |  ?1.1%   |
>> | usecs/op   | 0.219575       | 0.217192        |  ?1.1%   |
>> | ops/sec    | 4,554,260      | 4,604,225       |  ?1.1%    |
>>
>> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
> 
> I think this is sensible - do_el0_svc() is clearly hot and the small
> increase in code size is completely justified. It also removes a
> performance regression when enabling CONFIG_COMPAT (without it
> el0_svc_common() has only one caller so it should be inlined regardless).
> 
> Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
> 
>> ---
>>  arch/arm64/kernel/syscall.c | 4 ++--
>>  1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
>> index 47e193a1cfff..5aa51da9ec25 100644
>> --- a/arch/arm64/kernel/syscall.c
>> +++ b/arch/arm64/kernel/syscall.c
>> @@ -66,8 +66,8 @@ static void invoke_syscall(struct pt_regs *regs, unsigned int scno,
>>  	choose_random_kstack_offset(get_random_u16());
>>  }
>>  
>> -static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
>> -			   const syscall_fn_t syscall_table[])
>> +static __always_inline void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
>> +					   const syscall_fn_t syscall_table[])
>>  {
>>  	unsigned long work = READ_ONCE(current_thread_info()->syscall_work);
>>  	unsigned long flags = read_thread_flags();
> 


From vulab at iscas.ac.cn  Tue Dec  9 19:00:13 2025
From: vulab at iscas.ac.cn (Haotian Zhang)
Date: Wed, 10 Dec 2025 11:00:13 +0800
Subject: [PATCH] input: mtk-pmic-keys: Fix potential NULL pointer dereference in probe()
Message-ID: <20251210030013.913-1-vulab@iscas.ac.cn>

of_match_device() may return NULL when the device node
does not match any entry in the driver's match table.
The current code dereferences of_id->data unconditionally,
which can lead to a NULL pointer dereference.

Add a NULL check for the return value of of_match_device()
and return -ENODEV upon failure.

Fixes: 3e9f0b3e2b27 ("input: Add MediaTek PMIC keys support")
Signed-off-by: Haotian Zhang <vulab at iscas.ac.cn>
---
 drivers/input/keyboard/mtk-pmic-keys.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/input/keyboard/mtk-pmic-keys.c b/drivers/input/keyboard/mtk-pmic-keys.c
index c78d9f6d97c4..474ef36605dc 100644
--- a/drivers/input/keyboard/mtk-pmic-keys.c
+++ b/drivers/input/keyboard/mtk-pmic-keys.c
@@ -335,6 +335,8 @@ static int mtk_pmic_keys_probe(struct platform_device *pdev)
 	struct input_dev *input_dev;
 	const struct of_device_id *of_id =
 		of_match_device(of_mtk_pmic_keys_match_tbl, &pdev->dev);
+	if (!of_id)
+		return -ENODEV;
 
 	keys = devm_kzalloc(&pdev->dev, sizeof(*keys), GFP_KERNEL);
 	if (!keys)
-- 
2.50.1.windows.1



From lihaoxiang at isrc.iscas.ac.cn  Tue Dec  9 19:16:56 2025
From: lihaoxiang at isrc.iscas.ac.cn (Haoxiang Li)
Date: Wed, 10 Dec 2025 11:16:56 +0800
Subject: [PATCH] firmware: arm_ffa: Add missing umap in ffa_init()
Message-ID: <20251210031656.56194-1-lihaoxiang@isrc.iscas.ac.cn>

In error path, add ffa_rxtx_unmap() to release the resource
acquired by ffa_rxtx_map().

Signed-off-by: Haoxiang Li <lihaoxiang at isrc.iscas.ac.cn>
---
 drivers/firmware/arm_ffa/driver.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
index c72ee4756585..7209a630f6d1 100644
--- a/drivers/firmware/arm_ffa/driver.c
+++ b/drivers/firmware/arm_ffa/driver.c
@@ -2068,6 +2068,7 @@ static int __init ffa_init(void)
 
 	pr_err("failed to setup partitions\n");
 	ffa_notifications_cleanup();
+	ffa_rxtx_unmap(drv_info->vm_id);
 free_pages:
 	if (drv_info->tx_buffer)
 		free_pages_exact(drv_info->tx_buffer, rxtx_bufsz);
-- 
2.25.1



From lkp at intel.com  Tue Dec  9 19:21:47 2025
From: lkp at intel.com (kernel test robot)
Date: Wed, 10 Dec 2025 11:21:47 +0800
Subject: [PATCH v2] pmdomain: imx: Fix reference count leak in
 imx_gpc_probe()
In-Reply-To: <20251209081909.24982-1-vulab@iscas.ac.cn>
References: <20251209081909.24982-1-vulab@iscas.ac.cn>
Message-ID: <202512101101.zAlerEtu-lkp@intel.com>

Hi Wentao,

kernel test robot noticed the following build errors:

[auto build test ERROR on shawnguo/for-next]
[also build test ERROR on linus/master v6.18 next-20251209]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Wentao-Liang/pmdomain-imx-Fix-reference-count-leak-in-imx_gpc_probe/20251209-162152
base:   https://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git for-next
patch link:    https://lore.kernel.org/r/20251209081909.24982-1-vulab%40iscas.ac.cn
patch subject: [PATCH v2] pmdomain: imx: Fix reference count leak in imx_gpc_probe()
config: arm-randconfig-003-20251210 (https://download.01.org/0day-ci/archive/20251210/202512101101.zAlerEtu-lkp at intel.com/config)
compiler: arm-linux-gnueabi-gcc (GCC) 8.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251210/202512101101.zAlerEtu-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512101101.zAlerEtu-lkp at intel.com/

All errors (new ones prefixed by >>):

   drivers/pmdomain/imx/gpc.c: In function 'imx_gpc_probe':
>> drivers/pmdomain/imx/gpc.c:405:9: error: cleanup argument not a function
     struct device_node *pgc_node __free(pgc_node);
            ^~~~~~~~~~~


vim +405 drivers/pmdomain/imx/gpc.c

   401	
   402	static int imx_gpc_probe(struct platform_device *pdev)
   403	{
   404		const struct imx_gpc_dt_data *of_id_data = device_get_match_data(&pdev->dev);
 > 405		struct device_node *pgc_node __free(pgc_node);
   406		struct regmap *regmap;
   407		void __iomem *base;
   408		int ret;
   409	
   410		pgc_node = of_get_child_by_name(pdev->dev.of_node, "pgc");
   411	
   412		/* bail out if DT too old and doesn't provide the necessary info */
   413		if (!of_property_present(pdev->dev.of_node, "#power-domain-cells") &&
   414		    !pgc_node)
   415			return 0;
   416	
   417		base = devm_platform_ioremap_resource(pdev, 0);
   418		if (IS_ERR(base))
   419			return PTR_ERR(base);
   420	
   421		regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL, base,
   422						   &imx_gpc_regmap_config);
   423		if (IS_ERR(regmap)) {
   424			ret = PTR_ERR(regmap);
   425			dev_err(&pdev->dev, "failed to init regmap: %d\n",
   426				ret);
   427			return ret;
   428		}
   429	
   430		/*
   431		 * Disable PU power down by runtime PM if ERR009619 is present.
   432		 *
   433		 * The PRE clock will be paused for several cycles when turning on the
   434		 * PU domain LDO from power down state. If PRE is in use at that time,
   435		 * the IPU/PRG cannot get the correct display data from the PRE.
   436		 *
   437		 * This is not a concern when the whole system enters suspend state, so
   438		 * it's safe to power down PU in this case.
   439		 */
   440		if (of_id_data->err009619_present)
   441			imx_gpc_domains[GPC_PGC_DOMAIN_PU].base.flags |=
   442					GENPD_FLAG_RPM_ALWAYS_ON;
   443	
   444		/* Keep DISP always on if ERR006287 is present */
   445		if (of_id_data->err006287_present)
   446			imx_gpc_domains[GPC_PGC_DOMAIN_DISPLAY].base.flags |=
   447					GENPD_FLAG_ALWAYS_ON;
   448	
   449		if (!pgc_node) {
   450			ret = imx_gpc_old_dt_init(&pdev->dev, regmap,
   451						  of_id_data->num_domains);
   452			if (ret)
   453				return ret;
   454		} else {
   455			struct imx_pm_domain *domain;
   456			struct platform_device *pd_pdev;
   457			struct clk *ipg_clk;
   458			unsigned int ipg_rate_mhz;
   459			int domain_index;
   460	
   461			ipg_clk = devm_clk_get(&pdev->dev, "ipg");
   462			if (IS_ERR(ipg_clk))
   463				return PTR_ERR(ipg_clk);
   464			ipg_rate_mhz = clk_get_rate(ipg_clk) / 1000000;
   465	
   466			for_each_child_of_node_scoped(pgc_node, np) {
   467				ret = of_property_read_u32(np, "reg", &domain_index);
   468				if (ret)
   469					return ret;
   470	
   471				if (domain_index >= of_id_data->num_domains)
   472					continue;
   473	
   474				pd_pdev = platform_device_alloc("imx-pgc-power-domain",
   475								domain_index);
   476				if (!pd_pdev)
   477					return -ENOMEM;
   478	
   479				ret = platform_device_add_data(pd_pdev,
   480							       &imx_gpc_domains[domain_index],
   481							       sizeof(imx_gpc_domains[domain_index]));
   482				if (ret) {
   483					platform_device_put(pd_pdev);
   484					return ret;
   485				}
   486				domain = pd_pdev->dev.platform_data;
   487				domain->regmap = regmap;
   488				domain->ipg_rate_mhz = ipg_rate_mhz;
   489	
   490				pd_pdev->dev.parent = &pdev->dev;
   491				pd_pdev->dev.of_node = np;
   492				pd_pdev->dev.fwnode = of_fwnode_handle(np);
   493	
   494				ret = platform_device_add(pd_pdev);
   495				if (ret) {
   496					platform_device_put(pd_pdev);
   497					return ret;
   498				}
   499			}
   500		}
   501	
   502		return 0;
   503	}
   504	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From BenNiu at meta.com  Tue Dec  9 19:32:29 2025
From: BenNiu at meta.com (Ben Niu)
Date: Tue, 9 Dec 2025 19:32:29 -0800
Subject: Withdraw [PATCH v2] tracing: Enable kprobe for selected Arm64
 assembly
In-Reply-To: <aRr1gXk1giE8TXvY@J2N7QTR9R3>
References: <20251103185237.2284456-1-benniu@meta.com>
 <aRr1gXk1giE8TXvY@J2N7QTR9R3>
Message-ID: <aTjpzfqTEGPcird5@meta.com>

On Mon, Nov 17, 2025 at 10:14:25AM +0000, Mark Rutland wrote:
> On Mon, Nov 03, 2025 at 10:52:35AM -0800, Ben Niu wrote:
> > When ftrace is enabled, a function can only be kprobe'd if
> >   (1) the function has proper nops inserted at the beginning
> >   (2) the first inserted nop's address is added in section
> >       __patchable_function_entries.
> >
> > See function within_notrace_func in kernel/trace/trace_kprobe.c
> > for more details.
> 
> As mentioned last time, this isn't accurate, and this is at the wrong
> level of abstraction. You're conflating kprobes with kprobes-based trace
> evnts, and you're describing the implementation details of ftrace rather
> than the logical situation that the function needs to be traceable via
> ftrace
> 
> This would be better summarized as:
> 
>   While kprobes can be placed on most kernel functions, kprobes-based
>   trace events can only be placed on functions which are traceable via
>   ftrace (unless CONFIG_KPROBE_EVENTS_ON_NOTRACE=y).

Thanks. I'm withdrawing this patch because my colleague suggested
a workaround that could trace __arch_copy_to_user/__arch_copy_from_user
without any changes for the kernel:

bpftrace -q -e '
BEGIN {
    printf("Attaching to __arch_copy_to_user...\n");
}

watchpoint:'"0x$(grep ' __arch_copy_to_user$' /proc/kallsyms | awk '{print $1}')"':4:x
{
    $n = reg("r2");
    @__arch_copy_to_user_sizes = hist($n);
}'

> IIUC from last time you only want this so that you can introspect
> __arch_copy_to_user() and __arch_copy_from_user(), so why can't you
> select CONFIG_KPROBE_EVENTS_ON_NOTRACE in your test kernel? That would
> require zero kernel changes AFAICT.

CONFIG_KPROBE_EVENTS_ON_NOTRACE has this help message, see
https://github.com/torvalds/linux/blob/c9b47175e9131118e6f221cc8fb81397d62e7c91/kernel/trace/Kconfig#L798,
that discourages production enablement, so we didn't turn it on.
 
> I'm not keen on doing this unless absolutely necessary, and as above it
> looks like we already have suitable options to make this possible for
> your use-case.

This patch is no longer needed.
 
> > This patch adds a new asm function macro SYM_FUNC_START_TRACE
> > that makes an asm funtion satisfy the above two conditions so that
> > it can be kprobe'd. In addition, the macro is applied to
> > __arch_copy_to_user and __arch_copy_from_user, which were found
> > to be hot in certain workloads.
> > 
> > Note: although this patch unblocks kprobe tracing, fentry is still
> > broken because no BTF info gets generated from assembly files. A
> > separate patch is needed to fix that.
> 
> As above, I'm not keen on doing this, and if it's largely incomplete, I
> think that's another nail in the coffin.
> 
> [...]
> 
> > +#ifdef CONFIG_ARM64_BTI_KERNEL
> > +#define BTI_C bti c;
> > +#else
> > +#define BTI_C
> > +#endif
> 
> Please note that we deliberately chose to always output BTI for asm
> functions to avoid a performance vaiability depending on whether BTI was
> enabled, so if we're going to change that, we must do that as a
> preparatory step with a clear rationale.

Ok, thanks for clarifying that.

> Mark.


From vulab at iscas.ac.cn  Tue Dec  9 19:35:24 2025
From: vulab at iscas.ac.cn (Wentao Liang)
Date: Wed, 10 Dec 2025 03:35:24 +0000
Subject: [PATCH v3] pmdomain: imx: Fix reference count leak in imx_gpc_probe()
Message-ID: <20251210033524.34600-1-vulab@iscas.ac.cn>

of_get_child_by_name() returns a node pointer with refcount incremented.
Use the __free() attribute to manage the pgc_node reference, ensuring
automatic of_node_put() cleanup when pgc_node goes out of scope.

This eliminates the need for explicit error handling paths and avoids
reference count leaks.

Fixes: 721cabf6c660 ("soc: imx: move PGC handling to a new GPC driver")
Cc: stable at vger.kernel.org
Signed-off-by: Wentao Liang <vulab at iscas.ac.cn>

---
Change in V3:
- Ensure variable is assigned when using cleanup attribute

Change in V2:
- Use __free() attribute instead of explicit of_node_put() calls
---
 drivers/pmdomain/imx/gpc.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/pmdomain/imx/gpc.c b/drivers/pmdomain/imx/gpc.c
index f18c7e6e75dd..0fb3250dbf5f 100644
--- a/drivers/pmdomain/imx/gpc.c
+++ b/drivers/pmdomain/imx/gpc.c
@@ -403,13 +403,12 @@ static int imx_gpc_old_dt_init(struct device *dev, struct regmap *regmap,
 static int imx_gpc_probe(struct platform_device *pdev)
 {
 	const struct imx_gpc_dt_data *of_id_data = device_get_match_data(&pdev->dev);
-	struct device_node *pgc_node;
+	struct device_node *pgc_node __free(pgc_node)
+		= of_get_child_by_name(pdev->dev.of_node, "pgc");
 	struct regmap *regmap;
 	void __iomem *base;
 	int ret;
 
-	pgc_node = of_get_child_by_name(pdev->dev.of_node, "pgc");
-
 	/* bail out if DT too old and doesn't provide the necessary info */
 	if (!of_property_present(pdev->dev.of_node, "#power-domain-cells") &&
 	    !pgc_node)
-- 
2.34.1



From sashal at kernel.org  Tue Dec  9 19:48:49 2025
From: sashal at kernel.org (Sasha Levin)
Date: Tue,  9 Dec 2025 22:48:49 -0500
Subject: [PATCH AUTOSEL 6.18-6.12] scsi: ufs: host: mediatek: Fix shutdown/suspend race condition
In-Reply-To: <20251210034915.2268617-1-sashal@kernel.org>
References: <20251210034915.2268617-1-sashal@kernel.org>
Message-ID: <20251210034915.2268617-8-sashal@kernel.org>

From: Peter Wang <peter.wang at mediatek.com>

[ Upstream commit 014de20bb36ba03e0e0b0a7e0a1406ab900c9fda ]

Address a race condition between shutdown and suspend operations in the
UFS Mediatek driver. Before entering suspend, check if a shutdown is in
progress to prevent conflicts and ensure system stability.

Signed-off-by: Peter Wang <peter.wang at mediatek.com>
Acked-by: Chun-Hung Wu <chun-hung.wu at mediatek.com>
Link: https://patch.msgid.link/20250924094527.2992256-6-peter.wang at mediatek.com
Signed-off-by: Martin K. Petersen <martin.petersen at oracle.com>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---

LLM Generated explanations, may be completely bogus:

## Analysis Summary

### 1. Commit Message Analysis
- **Subject**: "Fix shutdown/suspend race condition" - clearly indicates
  a bug fix
- **No Cc: stable tag** or **Fixes: tag** present
- The message describes preventing conflicts between shutdown and
  suspend operations "to ensure system stability"

### 2. Code Change Analysis
The fix is extremely small (4 lines):
```c
if (hba->shutting_down) {
    ret = -EBUSY;
    goto out;
}
```

**What it does**: At the start of `ufs_mtk_system_suspend()`, before
calling `ufshcd_system_suspend()` and performing Mediatek-specific
operations (voltage regulator LPM, MTCMOS control), it checks if
`hba->shutting_down` is true.

**Why the race is problematic**: The Mediatek driver performs hardware-
specific operations after calling the core suspend:
- `ufs_mtk_dev_vreg_set_lpm()` - controls voltage regulators
- `ufs_mtk_mtcmos_ctrl()` - controls power domains

If shutdown is in progress (`ufshcd_wl_shutdown()` sets
`hba->shutting_down = true`), these operations could conflict with the
shutdown sequence that also manipulates hardware state, causing
instability.

### 3. Classification
- **Bug fix**: Yes - fixes a real race condition
- **Not a feature**: No new functionality, APIs, or capabilities added
- Uses existing infrastructure (`shutting_down` flag already exists in
  `struct ufs_hba`)

### 4. Scope and Risk Assessment
- **Lines changed**: 4 lines (minimal)
- **Files touched**: 1 (driver-specific)
- **Risk**: Very low - adds a defensive early return that makes the
  driver more conservative
- **Regression potential**: Minimal - worst case is a suspend returning
  `-EBUSY` when it shouldn't, but this is very unlikely given the
  shutdown context

### 5. User Impact
- **Affected hardware**: Mediatek UFS storage (common in Android devices
  and embedded systems)
- **Severity**: Race conditions between suspend/shutdown can cause
  system hangs, crashes, or data corruption
- **Real-world scenario**: User initiates shutdown while system is
  suspending (e.g., closing laptop lid during shutdown)

### 6. Stability Indicators
- Signed-off-by Mediatek developer (Peter Wang)
- Acked-by another Mediatek engineer
- Merged by SCSI maintainer Martin K. Petersen

### 7. Concerns
- No explicit `Cc: stable` tag
- No `Fixes:` tag indicating when the bug was introduced
- No bug report or `Reported-by` tag showing users encountered this
  issue

### Decision Rationale

**In favor of backporting:**
- Fixes a real race condition that can cause system instability
- The fix is trivially correct and uses existing infrastructure
- Very small change with minimal regression risk
- Mediatek UFS is widely deployed in consumer devices
- Race conditions between power management paths (suspend/shutdown) are
  serious issues

**Against backporting:**
- No explicit stable tag from the maintainer
- No evidence of users hitting this bug in practice
- Other UFS drivers don't have similar protection (though they may not
  have the same post-suspend hardware operations)

The fix is clearly correct, surgical, and addresses a real class of bug
(PM race conditions). While lacking explicit stable markers, the fix
meets the stable kernel criteria: it's obviously correct, fixes a real
bug affecting system stability, and is small and contained.

**YES**

 drivers/ufs/host/ufs-mediatek.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index 758a393a9de1a..d0cbd96ad29dc 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -2373,6 +2373,11 @@ static int ufs_mtk_system_suspend(struct device *dev)
 	struct arm_smccc_res res;
 	int ret;
 
+	if (hba->shutting_down) {
+		ret = -EBUSY;
+		goto out;
+	}
+
 	ret = ufshcd_system_suspend(dev);
 	if (ret)
 		goto out;
-- 
2.51.0



From sashal at kernel.org  Tue Dec  9 19:48:56 2025
From: sashal at kernel.org (Sasha Levin)
Date: Tue,  9 Dec 2025 22:48:56 -0500
Subject: [PATCH AUTOSEL 6.18-5.10] clk: mvebu: cp110 add CLK_IGNORE_UNUSED to pcie_x10, pcie_x11 & pcie_x4
In-Reply-To: <20251210034915.2268617-1-sashal@kernel.org>
References: <20251210034915.2268617-1-sashal@kernel.org>
Message-ID: <20251210034915.2268617-15-sashal@kernel.org>

From: Josua Mayer <josua at solid-run.com>

[ Upstream commit f0e6bc0c3ef4b4afb299bd6912586cafd5d864e9 ]

CP110 based platforms rely on the bootloader for pci port
initialization.
TF-A actively prevents non-uboot re-configuration of pci lanes, and many
boards do not have software control over the pci card reset.

If a pci port had link at boot-time and the clock is stopped at a later
point, the link fails and can not be recovered.

PCI controller driver probe - and by extension ownership of a driver for
the pci clocks - may be delayed especially on large modular kernels,
causing the clock core to start disabling unused clocks.

Add the CLK_IGNORE_UNUSED flag to the three pci port's clocks to ensure
they are not stopped before the pci controller driver has taken
ownership and tested for an existing link.

This fixes failed pci link detection when controller driver probes late,
e.g. with arm64 defconfig and CONFIG_PHY_MVEBU_CP110_COMPHY=m.

Closes: https://lore.kernel.org/r/b71596c7-461b-44b6-89ab-3cfbd492639f at solid-run.com
Signed-off-by: Josua Mayer <josua at solid-run.com>
Reviewed-by: Andrew Lunn <andrew at lunn.ch>
Signed-off-by: Gregory CLEMENT <gregory.clement at bootlin.com>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---

LLM Generated explanations, may be completely bogus:

## Commit Analysis: clk: mvebu: cp110 add CLK_IGNORE_UNUSED to pcie_x10,
pcie_x11 & pcie_x4

### 1. COMMIT MESSAGE ANALYSIS

**Subject:** Adding CLK_IGNORE_UNUSED flag to three PCIe clock gates on
Marvell CP110 platforms.

**Key problem described:**
- CP110 platforms rely on bootloader for PCIe port initialization
- TF-A (Trusted Firmware-A) prevents non-U-Boot reconfiguration of PCIe
  lanes
- Many boards lack software control over PCIe card reset
- If a PCIe port had an active link at boot and the clock is stopped
  later, the link fails permanently and cannot be recovered
- PCIe controller driver probe may be delayed on large modular kernels,
  causing the clock framework to disable "unused" clocks before the
  driver takes ownership

**Important tags:**
- **No "Cc: stable at vger.kernel.org"** - maintainer didn't explicitly
  request backport
- **No "Fixes:" tag** - unclear when the issue was introduced
- **Reviewed-by: Andrew Lunn** - reputable ARM/networking kernel
  developer
- **Closes:** link to lore.kernel.org bug report - confirms real users
  hit this

### 2. CODE CHANGE ANALYSIS

The change adds a new `gate_flags()` helper function that returns
`CLK_IGNORE_UNUSED` for three specific clock gates:
- `CP110_GATE_PCIE_X1_0` (pcie_x10)
- `CP110_GATE_PCIE_X1_1` (pcie_x11)
- `CP110_GATE_PCIE_X4` (pcie_x4)

This flag is then passed to `init.flags` when registering gate clocks.

**Technical mechanism of the bug:**
1. Boot proceeds with PCIe link established by bootloader
2. Clock framework marks these PCIe clocks as "unused" (no driver
   claimed them yet)
3. Late in boot, clock framework garbage-collects unused clocks
4. PCIe clocks are disabled, breaking the active link
5. When PCIe driver finally probes (especially in modular configs), link
   is irrecoverably failed

**What CLK_IGNORE_UNUSED does:**
Tells the clock framework to never disable these clocks just because
they appear unclaimed. This is the standard mechanism for clocks that
must remain active until a driver explicitly takes ownership.

### 3. CLASSIFICATION

**Type:** Hardware workaround / quirk for platform-specific behavior

This falls into the "quirks and workarounds" exception category for
stable kernels. It's a workaround for the specific constraints of the
Marvell CP110 platform where:
- TF-A manages PCIe lane configuration
- Clock disable breaks PCIe links irreversibly
- Driver load timing varies across kernel configurations

### 4. SCOPE AND RISK ASSESSMENT

**Size:** ~21 lines added, 1 file changed, self-contained

**Risk level:** LOW
- Only affects Marvell CP110 platforms
- No changes to core clock framework
- Worst case: slightly higher power consumption (clocks stay on when
  could be off)
- No chance of breaking other subsystems

**Subsystem:** mvebu clock driver - mature platform-specific driver

### 5. USER IMPACT

**Affected users:** Marvell CP110-based platforms (Armada 7K/8K,
SolidRun products, etc.)

**Severity:** HIGH for affected users - PCIe devices completely fail to
be detected

**Real-world evidence:**
- Bug report on lore.kernel.org linked in commit
- Reproducible with "arm64 defconfig and
  CONFIG_PHY_MVEBU_CP110_COMPHY=m"

### 6. STABILITY INDICATORS

- **Reviewed-by:** Andrew Lunn (highly respected maintainer for this
  subsystem)
- The CP110 clock driver has existed for years - this isn't new code
- Change is isolated and uses standard clock framework mechanisms

### 7. DEPENDENCY CHECK

- Self-contained change, no dependencies on other commits
- The CP110 clock driver exists in stable trees
- No required prerequisite patches

### CONCERNS

1. **No explicit stable tag** - maintainer didn't mark for backport
2. **No Fixes: tag** - we don't know how far back this issue goes
3. **Workaround approach** - CLK_IGNORE_UNUSED is somewhat heavy-handed
   but appropriate here

### DECISION ANALYSIS

**For backporting:**
- Fixes real hardware failure (PCIe not working) on production hardware
- Small, surgical, self-contained fix
- Very low regression risk (only affects specific ARM platform)
- Follows the "hardware quirk" exception pattern for stable
- Uses standard clock framework mechanisms
- Has review from reputable subsystem maintainer

**Against backporting:**
- No Cc: stable from maintainer
- Affects relatively niche ARM SoC platform
- No indication of when bug was introduced

### Conclusion

This commit fixes a real, user-impacting bug where PCIe devices fail to
be detected on Marvell CP110-based platforms. The fix is a standard
hardware quirk/workaround pattern - adding CLK_IGNORE_UNUSED to prevent
premature clock disabling that breaks active PCIe links. The change is
small (~21 lines), isolated to a single platform-specific driver,
carries minimal regression risk, and has been reviewed by a reputable
kernel maintainer.

While there's no explicit stable tag, this fits the stable criteria for
hardware workarounds that fix real user-facing bugs. The worst case
(clocks stay on unnecessarily) is far preferable to the current bug
(PCIe completely broken).

**YES**

 drivers/clk/mvebu/cp110-system-controller.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/drivers/clk/mvebu/cp110-system-controller.c b/drivers/clk/mvebu/cp110-system-controller.c
index 03c59bf221060..b47c869060466 100644
--- a/drivers/clk/mvebu/cp110-system-controller.c
+++ b/drivers/clk/mvebu/cp110-system-controller.c
@@ -110,6 +110,25 @@ static const char * const gate_base_names[] = {
 	[CP110_GATE_EIP197]	= "eip197"
 };
 
+static unsigned long gate_flags(const u8 bit_idx)
+{
+	switch (bit_idx) {
+	case CP110_GATE_PCIE_X1_0:
+	case CP110_GATE_PCIE_X1_1:
+	case CP110_GATE_PCIE_X4:
+		/*
+		 * If a port had an active link at boot time, stopping
+		 * the clock creates a failed state from which controller
+		 * driver can not recover.
+		 * Prevent stopping this clock till after a driver has taken
+		 * ownership.
+		 */
+		return CLK_IGNORE_UNUSED;
+	default:
+		return 0;
+	}
+};
+
 struct cp110_gate_clk {
 	struct clk_hw hw;
 	struct regmap *regmap;
@@ -171,6 +190,7 @@ static struct clk_hw *cp110_register_gate(const char *name,
 	init.ops = &cp110_gate_ops;
 	init.parent_names = &parent_name;
 	init.num_parents = 1;
+	init.flags = gate_flags(bit_idx);
 
 	gate->regmap = regmap;
 	gate->bit_idx = bit_idx;
-- 
2.51.0



From sashal at kernel.org  Tue Dec  9 19:48:58 2025
From: sashal at kernel.org (Sasha Levin)
Date: Tue,  9 Dec 2025 22:48:58 -0500
Subject: [PATCH AUTOSEL 6.18-5.10] firmware: imx: scu-irq: Init workqueue before request mbox channel
In-Reply-To: <20251210034915.2268617-1-sashal@kernel.org>
References: <20251210034915.2268617-1-sashal@kernel.org>
Message-ID: <20251210034915.2268617-17-sashal@kernel.org>

From: Peng Fan <peng.fan at nxp.com>

[ Upstream commit 81fb53feb66a3aefbf6fcab73bb8d06f5b0c54ad ]

With mailbox channel requested, there is possibility that interrupts may
come in, so need to make sure the workqueue is initialized before
the queue is scheduled by mailbox rx callback.

Reviewed-by: Frank Li <Frank.Li at nxp.com>
Signed-off-by: Peng Fan <peng.fan at nxp.com>
Signed-off-by: Shawn Guo <shawnguo at kernel.org>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---

LLM Generated explanations, may be completely bogus:

## Analysis Summary

### What the Bug Is

This commit fixes a classic **initialization race condition** in the
i.MX SCU IRQ driver. The problem is:

1. `mbox_request_channel_byname(cl, "gip3")` is called, which sets up a
   mailbox channel with `imx_scu_irq_callback` as the receive callback
2. Once the channel is established, interrupts from the System
   Controller Unit (SCU) can trigger the callback **at any time**
3. The callback (`imx_scu_irq_callback` at line 175-178) calls
   `schedule_work(&imx_sc_irq_work)`
4. **But** `INIT_WORK(&imx_sc_irq_work, ...)` was being called **after**
   the mailbox channel was requested

If an interrupt arrives in the window between
`mbox_request_channel_byname()` and `INIT_WORK()`, it would schedule an
uninitialized work struct, leading to undefined behavior, crashes, or
memory corruption in the workqueue subsystem.

### The Fix

The fix is trivially correct: move `INIT_WORK()` to **before**
`mbox_request_channel_byname()`. This ensures the work struct is
properly initialized before any callback can possibly use it.

### Bug Origin

The bug was introduced in commit `851826c7566e9` ("firmware: imx: enable
imx scu general irq function") in kernel v5.2-rc1 when this driver was
first created. The initialization order was wrong from the very
beginning.

### Stable Kernel Criteria Assessment

| Criterion | Assessment |
|-----------|------------|
| Obviously correct | ? Yes - classic "initialize before use" pattern |
| Fixes real bug | ? Yes - race condition causing potential crashes |
| Small and contained | ? Yes - moves one line of code |
| No new features | ? Correct - purely a fix |
| Tested | ? Has Reviewed-by from NXP engineer |
| Low risk | ? Cannot introduce regressions |

### Risk vs. Benefit

- **Risk**: Extremely low - the work struct must be initialized before
  use regardless of when the first interrupt arrives; moving
  initialization earlier cannot break anything
- **Benefit**: Prevents crashes on i.MX SoC platforms (used in embedded
  systems, automotive, IoT devices) where early interrupts could trigger
  the race

### Dependencies

None - this is a self-contained single-line reordering fix that should
apply cleanly to any kernel with this driver (5.2+).

### Conclusion

This is an ideal stable backport candidate. It fixes a real
initialization race condition that can cause crashes, the fix is
obviously correct (a single line moved earlier in the initialization
sequence), it's minimal and surgical, and it affects real users of i.MX
SoC platforms. The only missing element is an explicit `Cc:
stable at vger.kernel.org` tag, but the fix clearly meets all stable kernel
rules.

**YES**

 drivers/firmware/imx/imx-scu-irq.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/firmware/imx/imx-scu-irq.c b/drivers/firmware/imx/imx-scu-irq.c
index 6125cccc9ba79..53bde775a1bf6 100644
--- a/drivers/firmware/imx/imx-scu-irq.c
+++ b/drivers/firmware/imx/imx-scu-irq.c
@@ -214,6 +214,8 @@ int imx_scu_enable_general_irq_channel(struct device *dev)
 	cl->dev = dev;
 	cl->rx_callback = imx_scu_irq_callback;
 
+	INIT_WORK(&imx_sc_irq_work, imx_scu_irq_work_handler);
+
 	/* SCU general IRQ uses general interrupt channel 3 */
 	ch = mbox_request_channel_byname(cl, "gip3");
 	if (IS_ERR(ch)) {
@@ -223,8 +225,6 @@ int imx_scu_enable_general_irq_channel(struct device *dev)
 		return ret;
 	}
 
-	INIT_WORK(&imx_sc_irq_work, imx_scu_irq_work_handler);
-
 	if (!of_parse_phandle_with_args(dev->of_node, "mboxes",
 				       "#mbox-cells", 0, &spec))
 		i = of_alias_get_id(spec.np, "mu");
-- 
2.51.0



From jcalligeros99 at gmail.com  Tue Dec  9 19:57:50 2025
From: jcalligeros99 at gmail.com (James Calligeros)
Date: Wed, 10 Dec 2025 13:57:50 +1000
Subject: [PATCH 4/7] ASoC: soc-dai: define TDM idle behaviour modes
In-Reply-To: <aTjZc3mgu7CQOkDU@sirena.co.uk>
References: <20251209-tdm-idle-slots-v1-0-38dabf6bc01e@gmail.com>
 <20251209-tdm-idle-slots-v1-4-38dabf6bc01e@gmail.com> <aTjZc3mgu7CQOkDU@sirena.co.uk>
Message-ID: <CAHgNfTxmYxNaYOdGK4Eb4ouCqmUCjVuhzGdgTAL=+ybObqrCmw@mail.gmail.com>

Hi Mark,

On Wed, Dec 10, 2025 at 12:22?PM Mark Brown <broonie at kernel.org> wrote:
>
> On Tue, Dec 09, 2025 at 07:31:17PM +1000, James Calligeros wrote:
>
> > Imagine for example two codecs sharing a bus. When one codec is
> > transmitting, the other must ensure that it is holding its side
> > to 0, or data from the transmitting codec will be corrupted. We
> > can trust the "idle" codec to simply do this itself, however
> > this is undefined behaviour. Some devices may leave the line
> > floating, others still may pull the line high. We need a way to
> > control this behaviour.
>
> I'm finding this explanation quite confusing - you appear to be
> describing the situation where two devices simultaneously drive the same
> signal which would be extremely unusual and I can't see how it would
> work electrically.

We are trying to solve a few of problems here, and one of them is
a bit odd. I've probably jumbled up a bunch of different things here.

We have the use case where a codec enjoys exclusive use of a bus. For
these, the codec can transmit 0 on any unused slots to hold the bus.

We also have the case where multiple codecs share a single bus. One
codec can weakly pull the bus low when it's not being actively driven by
any of the attached codecs.

However, a number of machines split six codecs into groups of three
across two electrical lines and then OR them at the receiving
port such that they appear on a single bus at the SoC. Because the two
data lines are ORed at the receiver, we have to guarantee that line B is
zero while line A is active, and vice versa. To do this, we set a single codec
from each group to zero-fill during the active slots of the other group.

> > Thus, we define five possible bus-keeping modes that a device can
> > be in: NONE (UB/as initialised), OFF (explicitly disabled), ZERO
> > (actively transmit a 0), PULLDOWN, and HIZ (floating).
>
> What is "explicitly disabled" in ths context?  Why aren't pull up or
> drive high options?

The OFF state was added so that consumers can explicitly disable
any and all bus keeping if necessary and supported by the component.
TAS2764 and 2770 both initialise with some bus keeping features enabled,
hence for this hardware NONE != OFF. I suspect this is the case for other
hardware too.

I neglected to add pull up and drive high simply because none of the
initially implemented hardware uses either. I can them for completeness's
sake, however.

Regards,
James


From dmitry.torokhov at gmail.com  Tue Dec  9 20:48:13 2025
From: dmitry.torokhov at gmail.com (Dmitry Torokhov)
Date: Tue, 9 Dec 2025 20:48:13 -0800
Subject: [PATCH] input: mtk-pmic-keys: Fix potential NULL pointer
 dereference in probe()
In-Reply-To: <20251210030013.913-1-vulab@iscas.ac.cn>
References: <20251210030013.913-1-vulab@iscas.ac.cn>
Message-ID: <inmlorhcpi5g7kfs45rhtpwq7aatmzxemgnulamvjqxmmmtl2j@vfcd5kndbhep>

Hi Haotian,

On Wed, Dec 10, 2025 at 11:00:13AM +0800, Haotian Zhang wrote:
> of_match_device() may return NULL when the device node
> does not match any entry in the driver's match table.
> The current code dereferences of_id->data unconditionally,
> which can lead to a NULL pointer dereference.

How are we getting into probe() without matching compatible?

We already had a discussion about this in [1] and patched the MFD
portion to not use generic driver name when instantiating the keypad
sub-device.

[1] http://lore.kernel.org/r/20250630-mtk-pmic-keys-fix-crash-v1-1-e47351fa9d1f at collabora.com

Thanks.

-- 
Dmitry


From amhetre at nvidia.com  Tue Dec  9 21:19:12 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Wed, 10 Dec 2025 10:49:12 +0530
Subject: [PATCH V4 1/3] iommu/arm-smmu-v3: Add device-tree support for
 CMDQV driver
In-Reply-To: <202512090331.QAFgb6vQ-lkp@intel.com>
References: <20251205065850.3841834-2-amhetre@nvidia.com>
 <202512090331.QAFgb6vQ-lkp@intel.com>
Message-ID: <2bf7bb25-9a6b-42d5-b095-978f7bb81f35@nvidia.com>


On 12/9/2025 1:13 AM, kernel test robot wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Ashish,
>
> kernel test robot noticed the following build warnings:
>
> [auto build test WARNING on next-20251204]
> [also build test WARNING on v6.18]
> [cannot apply to robh/for-next linus/master v6.18 v6.18-rc7 v6.18-rc6]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
>
> url:    https://github.com/intel-lab-lkp/linux/commits/Ashish-Mhetre/iommu-arm-smmu-v3-Add-device-tree-support-for-CMDQV-driver/20251205-151258
> base:   next-20251204
> patch link:    https://lore.kernel.org/r/20251205065850.3841834-2-amhetre%40nvidia.com
> patch subject: [PATCH V4 1/3] iommu/arm-smmu-v3: Add device-tree support for CMDQV driver
> config: arm64-randconfig-004-20251209 (https://download.01.org/0day-ci/archive/20251209/202512090331.QAFgb6vQ-lkp at intel.com/config)
> compiler: aarch64-linux-gcc (GCC) 11.5.0
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251209/202512090331.QAFgb6vQ-lkp at intel.com/reproduce)
>
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp at intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202512090331.QAFgb6vQ-lkp at intel.com/
>
> All warnings (new ones prefixed by >>):
>
>     drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c: In function 'tegra241_cmdqv_acpi_is_memory':
>     drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c:863:17: error: implicit declaration of function 'acpi_dev_resource_address_space' [-Werror=implicit-function-declaration]
>       863 |         return !acpi_dev_resource_address_space(res, &win);
>           |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>     drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c: In function 'tegra241_cmdqv_acpi_get_irqs':
>     drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c:871:26: error: implicit declaration of function 'acpi_dev_resource_interrupt' [-Werror=implicit-function-declaration]
>       871 |         if (*irq <= 0 && acpi_dev_resource_interrupt(ares, 0, &r))
>           |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~
>     drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c: In function 'tegra241_cmdqv_find_acpi_resource':
>     drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c:879:36: error: implicit declaration of function 'to_acpi_device'; did you mean 'to_acpi_device_node'? [-Werror=implicit-function-declaration]
>       879 |         struct acpi_device *adev = to_acpi_device(dev);
>           |                                    ^~~~~~~~~~~~~~
>           |                                    to_acpi_device_node
>>> drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c:879:36: warning: initialization of 'struct acpi_device *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
>     drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c:886:15: error: implicit declaration of function 'acpi_dev_get_resources'; did you mean 'acpi_get_event_resources'? [-Werror=implicit-function-declaration]
>       886 |         ret = acpi_dev_get_resources(adev, &resource_list,
>           |               ^~~~~~~~~~~~~~~~~~~~~~
>           |               acpi_get_event_resources
>     drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c:907:9: error: implicit declaration of function 'acpi_dev_free_resource_list' [-Werror=implicit-function-declaration]
>       907 |         acpi_dev_free_resource_list(&resource_list);
>           |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~
>     cc1: some warnings being treated as errors

Hi Robin, Nic,
We removed ACPI dependency in Kconfig but driver still depends
on ACPI for these functions. I will be protecting ACPIspecific
tegra241-cmdqv code under CONFIG_ACPI similar to what is done
in arm-smmu-v3 driver. Is this the correct thing to do or do you
have any other suggestions?

> vim +879 drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
>
> 918eb5c856f6ce Nate Watterson 2024-08-29  875
> 918eb5c856f6ce Nate Watterson 2024-08-29  876  static struct resource *
> 918eb5c856f6ce Nate Watterson 2024-08-29  877  tegra241_cmdqv_find_acpi_resource(struct device *dev, int *irq)
> 918eb5c856f6ce Nate Watterson 2024-08-29  878  {
> 918eb5c856f6ce Nate Watterson 2024-08-29 @879   struct acpi_device *adev = to_acpi_device(dev);
> 918eb5c856f6ce Nate Watterson 2024-08-29  880   struct list_head resource_list;
> 918eb5c856f6ce Nate Watterson 2024-08-29  881   struct resource_entry *rentry;
> 918eb5c856f6ce Nate Watterson 2024-08-29  882   struct resource *res = NULL;
> 918eb5c856f6ce Nate Watterson 2024-08-29  883   int ret;
> 918eb5c856f6ce Nate Watterson 2024-08-29  884
> 918eb5c856f6ce Nate Watterson 2024-08-29  885   INIT_LIST_HEAD(&resource_list);
> 918eb5c856f6ce Nate Watterson 2024-08-29  886   ret = acpi_dev_get_resources(adev, &resource_list,
> 918eb5c856f6ce Nate Watterson 2024-08-29  887                                tegra241_cmdqv_acpi_is_memory, NULL);
> 918eb5c856f6ce Nate Watterson 2024-08-29  888   if (ret < 0) {
> 918eb5c856f6ce Nate Watterson 2024-08-29  889           dev_err(dev, "failed to get memory resource: %d\n", ret);
> 918eb5c856f6ce Nate Watterson 2024-08-29  890           return NULL;
> 918eb5c856f6ce Nate Watterson 2024-08-29  891   }
> 918eb5c856f6ce Nate Watterson 2024-08-29  892
> 918eb5c856f6ce Nate Watterson 2024-08-29  893   rentry = list_first_entry_or_null(&resource_list,
> 918eb5c856f6ce Nate Watterson 2024-08-29  894                                     struct resource_entry, node);
> 918eb5c856f6ce Nate Watterson 2024-08-29  895   if (!rentry) {
> 918eb5c856f6ce Nate Watterson 2024-08-29  896           dev_err(dev, "failed to get memory resource entry\n");
> 918eb5c856f6ce Nate Watterson 2024-08-29  897           goto free_list;
> 918eb5c856f6ce Nate Watterson 2024-08-29  898   }
> 918eb5c856f6ce Nate Watterson 2024-08-29  899
> 918eb5c856f6ce Nate Watterson 2024-08-29  900   /* Caller must free the res */
> 918eb5c856f6ce Nate Watterson 2024-08-29  901   res = kzalloc(sizeof(*res), GFP_KERNEL);
> 918eb5c856f6ce Nate Watterson 2024-08-29  902   if (!res)
> 918eb5c856f6ce Nate Watterson 2024-08-29  903           goto free_list;
> 918eb5c856f6ce Nate Watterson 2024-08-29  904
> 918eb5c856f6ce Nate Watterson 2024-08-29  905   *res = *rentry->res;
> 918eb5c856f6ce Nate Watterson 2024-08-29  906
> 918eb5c856f6ce Nate Watterson 2024-08-29  907   acpi_dev_free_resource_list(&resource_list);
> 918eb5c856f6ce Nate Watterson 2024-08-29  908
> 918eb5c856f6ce Nate Watterson 2024-08-29  909   INIT_LIST_HEAD(&resource_list);
> 918eb5c856f6ce Nate Watterson 2024-08-29  910
> 918eb5c856f6ce Nate Watterson 2024-08-29  911   if (irq)
> 918eb5c856f6ce Nate Watterson 2024-08-29  912           ret = acpi_dev_get_resources(adev, &resource_list,
> 918eb5c856f6ce Nate Watterson 2024-08-29  913                                        tegra241_cmdqv_acpi_get_irqs, irq);
> 918eb5c856f6ce Nate Watterson 2024-08-29  914   if (ret < 0 || !irq || *irq <= 0)
> 918eb5c856f6ce Nate Watterson 2024-08-29  915           dev_warn(dev, "no interrupt. errors will not be reported\n");
> 918eb5c856f6ce Nate Watterson 2024-08-29  916
> 918eb5c856f6ce Nate Watterson 2024-08-29  917  free_list:
> 918eb5c856f6ce Nate Watterson 2024-08-29  918   acpi_dev_free_resource_list(&resource_list);
> 918eb5c856f6ce Nate Watterson 2024-08-29  919   return res;
> 918eb5c856f6ce Nate Watterson 2024-08-29  920  }
> 918eb5c856f6ce Nate Watterson 2024-08-29  921
>
> --
> 0-DAY CI Kernel Test Service
> https://github.com/intel/lkp-tests/wiki


From daniel.lezcano at linaro.org  Tue Dec  9 21:24:46 2025
From: daniel.lezcano at linaro.org (Daniel Lezcano)
Date: Wed, 10 Dec 2025 06:24:46 +0100
Subject: [PATCH v2 2/3] dt-bindings: counter: Add NXP System Timer Module Counter
In-Reply-To: <20251210052449.4154283-1-daniel.lezcano@linaro.org>
References: <20251210052449.4154283-1-daniel.lezcano@linaro.org>
Message-ID: <20251210052449.4154283-3-daniel.lezcano@linaro.org>

Add the System Timer Module description found on the NXP s32 platform
when it is used as a counter and the compatible for the s32g2 variant.

Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Daniel Lezcano <daniel.lezcano at linaro.org>
---
 .../bindings/counter/nxp,s32g2-stm-cnt.yaml   | 64 +++++++++++++++++++
 1 file changed, 64 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/counter/nxp,s32g2-stm-cnt.yaml

diff --git a/Documentation/devicetree/bindings/counter/nxp,s32g2-stm-cnt.yaml b/Documentation/devicetree/bindings/counter/nxp,s32g2-stm-cnt.yaml
new file mode 100644
index 000000000000..4d42996f5ad3
--- /dev/null
+++ b/Documentation/devicetree/bindings/counter/nxp,s32g2-stm-cnt.yaml
@@ -0,0 +1,64 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/counter/nxp,s32g2-stm-cnt.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP System Timer Module (STM)
+
+maintainers:
+  - Daniel Lezcano <daniel.lezcano at kernel.org>
+
+description:
+  The System Timer Module supports commonly required system and application
+  software timing functions. STM includes a 32-bit count-up timer and four
+  32-bit compare channels with a separate interrupt source for each channel.
+  The counter is driven by the STM module clock divided by an 8-bit prescale
+  value.
+
+properties:
+  compatible:
+    oneOf:
+      - const: nxp,s32g2-stm-cnt
+      - items:
+          - const: nxp,s32g3-stm-cnt
+          - const: nxp,s32g2-stm-cnt
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: Counter clock
+      - description: Module clock
+      - description: Register clock
+
+  clock-names:
+    items:
+      - const: counter
+      - const: module
+      - const: register
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    timer at 4011c000 {
+        compatible = "nxp,s32g2-stm-cnt";
+        reg = <0x4011c000 0x3000>;
+        interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&clks 0x3b>, <&clks 0x3c>, <&clks 0x3c>;
+        clock-names = "counter", "module", "register";
+    };
-- 
2.43.0



From daniel.lezcano at linaro.org  Tue Dec  9 21:24:47 2025
From: daniel.lezcano at linaro.org (Daniel Lezcano)
Date: Wed, 10 Dec 2025 06:24:47 +0100
Subject: [PATCH v2 3/3] counter: Add STM based counter
In-Reply-To: <20251210052449.4154283-1-daniel.lezcano@linaro.org>
References: <20251210052449.4154283-1-daniel.lezcano@linaro.org>
Message-ID: <20251210052449.4154283-4-daniel.lezcano@linaro.org>

The NXP S32G2 automotive platform integrates four Cortex-A53 cores and
three Cortex-M7 cores, along with a large number of timers and
counters. These hardware blocks can be used as clocksources or
clockevents, or as timestamp counters shared across the various
subsystems running alongside the Linux kernel, such as firmware
components. Their actual usage depends on the overall platform
software design.

In a Linux-based system, the kernel controls the counter, which is a
read-only shared resource for the other subsystems. One of its primary
purposes is to act as a common timestamp source for messages or
traces, allowing correlation of events occurring in different
operating system contexts.

These changes introduce a basic counter driver that can start, stop,
and reset the counter. It also handles overflow accounting and
configures the prescaler value.

Signed-off-by: Daniel Lezcano <daniel.lezcano at linaro.org>
---
 drivers/counter/Kconfig       |  10 +
 drivers/counter/Makefile      |   1 +
 drivers/counter/nxp-stm-cnt.c | 386 ++++++++++++++++++++++++++++++++++
 3 files changed, 397 insertions(+)
 create mode 100644 drivers/counter/nxp-stm-cnt.c

diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig
index d30d22dfe577..bf5b281f194c 100644
--- a/drivers/counter/Kconfig
+++ b/drivers/counter/Kconfig
@@ -90,6 +90,16 @@ config MICROCHIP_TCB_CAPTURE
 	  To compile this driver as a module, choose M here: the
 	  module will be called microchip-tcb-capture.
 
+config NXP_STM_CNT
+	tristate "NXP System Timer Module Counter driver"
+	depends on ARCH_S32 || COMPILE_TEST
+	help
+	  Select this option to enable the NXP System Timer Module
+	  Counter driver.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called nxp_stm_cnt.
+
 config RZ_MTU3_CNT
 	tristate "Renesas RZ/G2L MTU3a counter driver"
 	depends on RZ_MTU3
diff --git a/drivers/counter/Makefile b/drivers/counter/Makefile
index 40e644948e7a..196b3c216875 100644
--- a/drivers/counter/Makefile
+++ b/drivers/counter/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_I8254)			+= i8254.o
 obj-$(CONFIG_INTEL_QEP)			+= intel-qep.o
 obj-$(CONFIG_INTERRUPT_CNT)		+= interrupt-cnt.o
 obj-$(CONFIG_MICROCHIP_TCB_CAPTURE)	+= microchip-tcb-capture.o
+obj-$(CONFIG_NXP_STM_CNT)		+= nxp-stm-cnt.o
 obj-$(CONFIG_RZ_MTU3_CNT)		+= rz-mtu3-cnt.o
 obj-$(CONFIG_STM32_TIMER_CNT)		+= stm32-timer-cnt.o
 obj-$(CONFIG_STM32_LPTIMER_CNT)		+= stm32-lptimer-cnt.o
diff --git a/drivers/counter/nxp-stm-cnt.c b/drivers/counter/nxp-stm-cnt.c
new file mode 100644
index 000000000000..4b310dbbc76f
--- /dev/null
+++ b/drivers/counter/nxp-stm-cnt.c
@@ -0,0 +1,386 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2018,2021-2025 NXP
+ * Copyright 2025 Linaro Limited
+ *
+ * Author: Daniel Lezcano <daniel.lezcano at linaro.org>
+ *
+ * NXP S32G System Timer Module counters:
+ *
+ *  STM supports commonly required system and application software
+ *  timing functions. STM includes a 32-bit count-up timer and four
+ *  32-bit compare channels with a separate interrupt source for each
+ *  channel. The timer is driven by the STM module clock divided by an
+ *  8-bit prescale value (1 to 256). It has ability to stop the timer
+ *  in Debug mode
+ *
+ */
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/counter.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#define STM_CR(__base)		(__base)
+#define STM_CR_TEN		BIT(0)
+#define STM_CR_FRZ		BIT(1)
+#define STM_CR_CPS_MASK         GENMASK(15, 8)
+
+#define STM_CCR0(__base)	((__base) + 0x10)
+#define STM_CCR_CEN		BIT(0)
+
+#define STM_CIR0(__base)	((__base) + 0x14)
+#define STM_CIR_CIF		BIT(0)
+
+#define STM_CMP0(__base)	((__base) + 0x18)
+
+#define STM_CNT(__base)		((__base) + 0x04)
+
+#define STM_ENABLE_MASK	(STM_CR_FRZ | STM_CR_TEN)
+
+struct nxp_stm_cnt {
+	spinlock_t lock;
+	void __iomem *base;
+	u64 overflow;
+	u32 counter;
+	u8 prescaler;
+	bool is_started;
+};
+
+static void nxp_stm_cnt_enable(struct nxp_stm_cnt *stm_cnt)
+{
+	u32 reg;
+
+	reg = readl(STM_CR(stm_cnt->base));
+
+	reg |= STM_ENABLE_MASK;
+
+	writel(reg, STM_CR(stm_cnt->base));
+}
+
+static void nxp_stm_cnt_disable(struct nxp_stm_cnt *stm_cnt)
+{
+	u32 reg;
+
+	reg = readl(STM_CR(stm_cnt->base));
+
+	reg &= ~STM_ENABLE_MASK;
+
+	writel(reg, STM_CR(stm_cnt->base));
+}
+
+static void nxp_stm_cnt_ccr_disable(struct nxp_stm_cnt *stm_cnt)
+{
+	writel(0, STM_CCR0(stm_cnt->base));
+}
+
+static void nxp_stm_cnt_ccr_enable(struct nxp_stm_cnt *stm_cnt)
+{
+	writel(STM_CCR_CEN, STM_CCR0(stm_cnt->base));
+}
+
+static void nxp_stm_cnt_set_overflow(struct nxp_stm_cnt *stm_cnt)
+{
+	writel(UINT_MAX, STM_CMP0(stm_cnt->base));
+}
+
+static u32 nxp_stm_cnt_get_counter(struct nxp_stm_cnt *stm_cnt)
+{
+	return readl(STM_CNT(stm_cnt->base));
+}
+
+static void nxp_stm_cnt_set_counter(struct nxp_stm_cnt *stm_cnt, u32 counter)
+{
+	writel(counter, STM_CNT(stm_cnt->base));
+}
+
+static void nxp_stm_cnt_set_prescaler(struct nxp_stm_cnt *stm_cnt, u8 prescaler)
+{
+	u32 reg;
+
+	reg = readl(STM_CR(stm_cnt->base));
+
+	FIELD_MODIFY(STM_CR_CPS_MASK, &reg, prescaler);
+
+	writel(reg, STM_CR(stm_cnt->base));
+}
+
+static u8 nxp_stm_cnt_get_prescaler(struct nxp_stm_cnt *stm_cnt)
+{
+	u32 reg = readl(STM_CR(stm_cnt->base));
+
+	return FIELD_GET(STM_CR_CPS_MASK, reg);
+}
+
+static bool nxp_stm_cnt_is_started(struct nxp_stm_cnt *stm_cnt)
+{
+	u32 reg;
+
+	reg = readl(STM_CR(stm_cnt->base));
+
+	return !!FIELD_GET(STM_CR_TEN, reg);
+}
+
+static void nxp_stm_cnt_irq_ack(struct nxp_stm_cnt *stm_cnt)
+{
+	writel(STM_CIR_CIF, STM_CIR0(stm_cnt->base));
+}
+
+static irqreturn_t nxp_stm_cnt_irq(int irq, void *dev_id)
+{
+	struct nxp_stm_cnt *stm_cnt = dev_id;
+
+	nxp_stm_cnt_irq_ack(stm_cnt);
+
+	spin_lock(&stm_cnt->lock);
+	stm_cnt->overflow++;
+	spin_unlock(&stm_cnt->lock);
+
+	return IRQ_HANDLED;
+}
+
+static void nxp_stm_cnt_start(struct nxp_stm_cnt *stm_cnt)
+{
+	nxp_stm_cnt_ccr_enable(stm_cnt);
+	nxp_stm_cnt_set_overflow(stm_cnt);
+	nxp_stm_cnt_enable(stm_cnt);
+}
+
+static void nxp_stm_cnt_stop(struct nxp_stm_cnt *stm_cnt)
+{
+	nxp_stm_cnt_disable(stm_cnt);
+	nxp_stm_cnt_irq_ack(stm_cnt);
+	nxp_stm_cnt_ccr_disable(stm_cnt);
+}
+
+static int nxp_stm_cnt_overflow_read(struct counter_device *counter,
+				     struct counter_count *count, u64 *val)
+{
+	struct nxp_stm_cnt *stm_cnt = counter_priv(counter);
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&stm_cnt->lock, irqflags);
+	*val = stm_cnt->overflow;
+	spin_unlock_irqrestore(&stm_cnt->lock, irqflags);
+
+	return 0;
+}
+
+static int nxp_stm_cnt_overflow_write(struct counter_device *counter,
+				      struct counter_count *count, u64 val)
+{
+	struct nxp_stm_cnt *stm_cnt = counter_priv(counter);
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&stm_cnt->lock, irqflags);
+	stm_cnt->overflow = val;
+	spin_unlock_irqrestore(&stm_cnt->lock, irqflags);
+
+	return 0;
+}
+
+static int nxp_stm_cnt_reset_write(struct counter_device *counter,
+				   struct counter_count *count, u8 val)
+{
+	struct nxp_stm_cnt *stm_cnt = counter_priv(counter);
+
+	nxp_stm_cnt_set_counter(stm_cnt, 0);
+	spin_lock(&stm_cnt->lock);
+	stm_cnt->overflow = 0;
+	spin_unlock(&stm_cnt->lock);
+
+	return 0;
+}
+
+static int nxp_stm_cnt_prescaler_read(struct counter_device *counter,
+				      struct counter_count *count, u8 *val)
+{
+	struct nxp_stm_cnt *stm_cnt = counter_priv(counter);
+
+	*val = nxp_stm_cnt_get_prescaler(stm_cnt);
+
+	return 0;
+}
+
+static int nxp_stm_cnt_prescaler_write(struct counter_device *counter,
+				       struct counter_count *count, u8 val)
+{
+	struct nxp_stm_cnt *stm_cnt = counter_priv(counter);
+
+	nxp_stm_cnt_set_prescaler(stm_cnt, val);
+
+	return 0;
+}
+
+static int nxp_stm_cnt_count_enable_write(struct counter_device *counter,
+					  struct counter_count *count, u8 enable)
+{
+	struct nxp_stm_cnt *stm_cnt = counter_priv(counter);
+
+	if (enable)
+		nxp_stm_cnt_start(stm_cnt);
+	else
+		nxp_stm_cnt_stop(stm_cnt);
+
+	return 0;
+}
+
+static int nxp_stm_cnt_count_enable_read(struct counter_device *counter,
+					 struct counter_count *count, u8 *enable)
+{
+	struct nxp_stm_cnt *stm_cnt = counter_priv(counter);
+
+	*enable = nxp_stm_cnt_is_started(stm_cnt);
+
+	return 0;
+}
+
+static struct counter_comp stm_cnt_count_ext[] = {
+	COUNTER_COMP_COUNT_BOOL("reset",  NULL, nxp_stm_cnt_reset_write),
+	COUNTER_COMP_COUNT_U8("prescaler", nxp_stm_cnt_prescaler_read, nxp_stm_cnt_prescaler_write),
+	COUNTER_COMP_COUNT_U64("overflows", nxp_stm_cnt_overflow_read, nxp_stm_cnt_overflow_write),
+	COUNTER_COMP_ENABLE(nxp_stm_cnt_count_enable_read, nxp_stm_cnt_count_enable_write),
+};
+
+static int nxp_stm_cnt_count_read(struct counter_device *dev,
+				  struct counter_count *count, u64 *val)
+{
+	struct nxp_stm_cnt *stm_cnt = counter_priv(dev);
+
+	*val = nxp_stm_cnt_get_counter(stm_cnt);
+
+	return 0;
+}
+
+static const struct counter_ops nxp_stm_cnt_counter_ops = {
+	.count_read  = nxp_stm_cnt_count_read,
+};
+
+static struct counter_count nxp_stm_cnt_counts[] = {
+	{
+		.id = 0,
+		.name = "stm_cnt",
+		.ext = stm_cnt_count_ext,
+		.num_ext = ARRAY_SIZE(stm_cnt_count_ext),
+	},
+};
+
+static int nxp_stm_cnt_suspend(struct device *dev)
+{
+	struct nxp_stm_cnt *stm_cnt = dev_get_drvdata(dev);
+
+	stm_cnt->is_started = nxp_stm_cnt_is_started(stm_cnt);
+
+	if (stm_cnt->is_started) {
+		nxp_stm_cnt_stop(stm_cnt);
+		stm_cnt->prescaler = nxp_stm_cnt_get_prescaler(stm_cnt);
+		stm_cnt->counter = nxp_stm_cnt_get_counter(stm_cnt);
+	}
+
+	return 0;
+}
+
+static int nxp_stm_cnt_resume(struct device *dev)
+{
+	struct nxp_stm_cnt *stm_cnt = dev_get_drvdata(dev);
+
+	if (stm_cnt->is_started) {
+		nxp_stm_cnt_set_counter(stm_cnt, stm_cnt->counter);
+		nxp_stm_cnt_set_prescaler(stm_cnt, stm_cnt->prescaler);
+		nxp_stm_cnt_start(stm_cnt);
+	}
+
+	return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(nxp_stm_cnt_pm_ops, nxp_stm_cnt_suspend,
+				nxp_stm_cnt_resume);
+
+static int nxp_stm_cnt_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct counter_device *counter;
+	struct nxp_stm_cnt *stm_cnt;
+	struct clk *clk;
+	void __iomem *base;
+	int irq, ret;
+
+	base = devm_of_iomap(dev, np, 0, NULL);
+	if (IS_ERR(base))
+		return dev_err_probe(dev, PTR_ERR(base), "Failed to iomap %pOFn\n", np);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return dev_err_probe(dev, irq, "Failed to get IRQ\n");
+
+	clk = devm_clk_get_enabled(dev, NULL);
+	if (IS_ERR(clk))
+		return dev_err_probe(dev, PTR_ERR(clk), "Clock not found\n");
+
+	counter = devm_counter_alloc(dev, sizeof(*stm_cnt));
+	if (!counter)
+		return -ENOMEM;
+
+	stm_cnt = counter_priv(counter);
+
+	stm_cnt->base = base;
+	stm_cnt->overflow = 0;
+	spin_lock_init(&stm_cnt->lock);
+
+	counter->name       = "stm_counter";
+	counter->parent     = &pdev->dev;
+	counter->ops        = &nxp_stm_cnt_counter_ops;
+	counter->counts     = nxp_stm_cnt_counts;
+	counter->num_counts = ARRAY_SIZE(nxp_stm_cnt_counts);
+
+	ret = devm_request_irq(dev, irq, nxp_stm_cnt_irq, IRQF_TIMER | IRQF_NOBALANCING,
+			       dev_name(&counter->dev), stm_cnt);
+	if (ret)
+		return dev_err_probe(dev, ret, "Unable to allocate interrupt line\n");
+
+	ret = devm_counter_add(dev, counter);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to register counter\n");
+
+	platform_set_drvdata(pdev, stm_cnt);
+
+	return 0;
+}
+
+static void nxp_stm_cnt_remove(struct platform_device *pdev)
+{
+	struct nxp_stm_cnt *stm_cnt = platform_get_drvdata(pdev);
+
+	if (nxp_stm_cnt_is_started(stm_cnt))
+		nxp_stm_cnt_stop(stm_cnt);
+}
+
+static const struct of_device_id nxp_stm_cnt_of_match[] = {
+	{ .compatible = "nxp,s32g2-stm", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, nxp_stm_cnt_of_match);
+
+static struct platform_driver nxp_stm_cnt_driver = {
+	.probe  = nxp_stm_cnt_probe,
+	.remove = nxp_stm_cnt_remove,
+	.driver = {
+		.name           = "nxp-stm-cnt",
+		.pm		= pm_sleep_ptr(&nxp_stm_cnt_pm_ops),
+		.of_match_table = nxp_stm_cnt_of_match,
+	},
+};
+module_platform_driver(nxp_stm_cnt_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Daniel Lezcano");
+MODULE_DESCRIPTION("NXP System Timer Module counter driver");
+MODULE_IMPORT_NS("COUNTER");
-- 
2.43.0



From yanan.yang at nxp.com  Tue Dec  9 22:31:43 2025
From: yanan.yang at nxp.com (Yanan Yang)
Date: Wed, 10 Dec 2025 15:31:43 +0900
Subject: [PATCH 1/2] dt-bindings: arm: fsl: Add FRDM-IMX91S board
In-Reply-To: <4b29cc46-28a1-45f1-b24e-548513178884@kernel.org>
References: <20251205-imx91s-frdm-v1-0-afd6cd01c299@nxp.com>
 <20251205-imx91s-frdm-v1-1-afd6cd01c299@nxp.com>
 <4b29cc46-28a1-45f1-b24e-548513178884@kernel.org>
Message-ID: <aTkTz-5QoB8BuLs7@lsvm11u0000554.swis.ap-northeast-2.aws.nxp.com>

On Fri, Dec 05, 2025 at 09:21:55AM +0100, Krzysztof Kozlowski wrote:
> On 05/12/2025 09:03, Yanan.Yang wrote:
> > Add DT compatible string for NXP FRDM-IMX91S board
> > 
> > The FRDM i.MX 91S development board is an low-cost and compact
> > development board featuring the i.MX 91 applications processor.
> > 
> > Signed-off-by: Yanan.Yang <yanan.yang at nxp.com>
> 
> Are you sure your Latin name contains '.' character? Or you just copied
> login?
> 
> > ---
> >  Documentation/devicetree/bindings/arm/fsl.yaml | 1 +
> >  1 file changed, 1 insertion(+)
> > 
> > diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
> > index 68a2d5fecc43..82f28be401b8 100644
> > --- a/Documentation/devicetree/bindings/arm/fsl.yaml
> > +++ b/Documentation/devicetree/bindings/arm/fsl.yaml
> > @@ -1412,6 +1412,7 @@ properties:
> >          items:
> >            - enum:
> >                - fsl,imx91-11x11-evk       # i.MX91 11x11 EVK Board
> > +              - fsl,imx91-11x11-frdm-s    # FRDM-IMX91S Board
> 
> Anyway, this was sent, or something almost the same.
> 
> Align internally before posting duplicates or at least explain why this
> is not a duplicate It is not the job of the community to coordinate how
> NXP employees should work. Srsly, it's NXP's job.
>
Hi Krzysztof,
Thank you for your review and for pointing this out.

This patch set is not a duplicate of the FRDM-IMX91 series. It introduces
support for a new board: FRDM-IMX91S. While FRDM-IMX91S is similar to
FRDM-IMX91, there are hardware differences that require a separate DTS:

- 512MB LPDDR4 (FRDM-IMX91 uses 1GB)
- 256MB FlexSPI-NAND (FRDM-IMX91 uses 8GB eMMC)
- Single GbE port (FRDM-IMX91 has dual GbE)
- PMIC PF9453 (FRDM-IMX91 uses PCA9451A)

These differences were described in the cover letter and commit message,
but I can make them more explicit if needed.

Regards,
Yanan

> 
> 
> Best regards,
> Krzysztof


From tomeu at tomeuvizoso.net  Tue Dec  9 22:50:36 2025
From: tomeu at tomeuvizoso.net (Tomeu Vizoso)
Date: Wed, 10 Dec 2025 07:50:36 +0100
Subject: Issues with DRM_ACCEL_ROCKET (Oops, power-domain, probe-ordering)
In-Reply-To: <75166475-d6a8-45b8-8092-f31d292d4206@rock-chips.com>
References: <0b20d760-ad4f-41c0-b733-39db10d6cc41@cherry.de>
 <77685900-2c34-49b8-8c7e-14718841ef17@rock-chips.com> <fa82d11f-ce11-4feb-bdb4-c31d360a2a62@rock-chips.com>
 <CAAObsKDYLXVf1GdYUNeaOya+pWD4jTOEf55ouXAL9iM_kWCcMw@mail.gmail.com> <75166475-d6a8-45b8-8092-f31d292d4206@rock-chips.com>
Message-ID: <CAAObsKABYQnw9rUfxwTS-yiQSoH9rdxZ_ffUBtp2H3tMJqMb7w@mail.gmail.com>

On Tue, Dec 9, 2025 at 10:31?AM Chaoyi Chen <chaoyi.chen at rock-chips.com> wrote:
>
> Hello Tomeu,
>
> On 12/9/2025 2:55 PM, Tomeu Vizoso wrote:
> > On Tue, Dec 2, 2025 at 8:00?AM Chaoyi Chen <chaoyi.chen at rock-chips.com> wrote:
>
> [...]
>
> >
> > This need was questioned during the review process, and during my
> > stress testing I didn't find a need for core 0 to be treated
> > specially. So it was considered unneeded complexity and the code was
> > dropped.
> >
>
> Oh, I just noticed that the commit comment in the devicetree still
> contains a relevant description.
>
> > My testing involves running the supported models as a whole, and also
> > their individual operations as individual tests. I run them in 8
> > parallel processes, in batches so we have continuous bring up and down
> > of clients.
> >
> > I'm a bit surprised that that testing worked stably but we have still
> > failures in some setups.
>
> Could you please describe the failures that still exist? Thank you.

I was referring to the ones that Quentin reported when starting this thread.

Regards,

Tomeu


From lei.xu at nxp.com  Tue Dec  9 23:05:44 2025
From: lei.xu at nxp.com (Lei Xu)
Date: Tue, 9 Dec 2025 23:05:44 -0800
Subject: [PATCH 2/2] arm64: dts: freescale: imx95: Add support for i.MX95
 15x15 FRDM board
In-Reply-To: <20251208065707.GA15128@francesco-nb>
References: <20251207-127-v1-0-5a2eeb69f150@nxp.com>
 <20251207-127-v1-2-5a2eeb69f150@nxp.com>
 <20251208065707.GA15128@francesco-nb>
Message-ID: <aTkbyAHjrwzTsfO8@lsvm07u0000156.swis.us-west-2.aws.nxp.com>

On Mon, Dec 08, 2025 at 07:57:07AM +0100, Francesco Dolcini wrote:
> Hello Lei,
> 
> On Sun, Dec 07, 2025 at 05:26:06AM -0800, Lei Xu wrote:
> > The i.MX95 15x15 FRDM board is a compact and cost-effective development
> > platform based on the i.MX95 applications processor.
> 
> ...
> 
> > diff --git a/arch/arm64/boot/dts/freescale/imx95-15x15-frdm.dts b/arch/arm64/boot/dts/freescale/imx95-15x15-frdm.dts
> > new file mode 100644
> > index 000000000000..61e815c858b8
> > --- /dev/null
> > +++ b/arch/arm64/boot/dts/freescale/imx95-15x15-frdm.dts
> 
> ...
> 
> > +
> > +/* Default settings in i.mx95.dtsi are for i.MX95 19x19 package.
> > + * Override here for the i.MX95 15x15 package.
> > + */
> > +&netc_bus0 {
> > +	msi-map = <0x0 &its 0x60 0x1>,	//ENETC0 PF
> > +		  <0x10 &its 0x61 0x1>, //ENETC0 VF0
> > +		  <0x20 &its 0x62 0x1>, //ENETC0 VF1
> > +		  <0x40 &its 0x63 0x1>, //ENETC1 PF
> > +		  <0x50 &its 0x65 0x1>, //ENETC1 VF0
> > +		  <0x60 &its 0x66 0x1>, //ENETC1 VF1
> > +		  <0x80 &its 0x64 0x1>, //ENETC2 PF
> > +		  <0xc0 &its 0x67 0x1>; //NETC Timer
> > +	iommu-map = <0x0 &smmu 0x20 0x1>,
> > +		    <0x10 &smmu 0x21 0x1>,
> > +		    <0x20 &smmu 0x22 0x1>,
> > +		    <0x40 &smmu 0x23 0x1>,
> > +		    <0x50 &smmu 0x25 0x1>,
> > +		    <0x60 &smmu 0x26 0x1>,
> > +		    <0x80 &smmu 0x24 0x1>,
> > +		    <0xc0 &smmu 0x27 0x1>;
> > +};
> 
> If the 19x19 and 15x15 i.MX95 requires something different you should
> have a different soc dtsi. Probably creating a new imx95-$something
> dtsi, that includes the existing imx95.dtsi and override this property.
> 
> This solution does not scale, please fix it.
> 
> Francesco
>

Hello, Francesco

The original comment is misleading because this configuration applies to the board rather than the SoC.
Therefore, update the comment as follows:
/*
 * Configure PCIe MSI and IOMMU mappings specific
 * to the i.MX95 15x15 FRDM board.
 */

Does this look acceptable to you? Thank you.

Lei


From jianpeng.chang.cn at windriver.com  Tue Dec  9 23:31:24 2025
From: jianpeng.chang.cn at windriver.com (Jianpeng Chang)
Date: Wed, 10 Dec 2025 15:31:24 +0800
Subject: [v3 PATCH] arm64: mm: Fix kexec failure after pte_mkwrite_novma()
 change
In-Reply-To: <4050b918-2ff8-4625-b1b6-8bb43e82c906@windriver.com>
References: <20251204062722.3367201-1-jianpeng.chang.cn@windriver.com>
 <8248c3fa-5c17-419c-ad8d-7abda988f0aa@arm.com>
 <4050b918-2ff8-4625-b1b6-8bb43e82c906@windriver.com>
Message-ID: <fee21b3f-fe4d-480e-9ad6-cac8ba46055f@windriver.com>



On 12/4/25 4:16 PM, Chang, Jianpeng (CN) wrote:
> 
> 
> On 12/4/2025 4:07 PM, Anshuman Khandual wrote:
>> CAUTION: This email comes from a non Wind River email account!
>> Do not click links or open attachments unless you recognize the sender
>> and know the content is safe.
>>
>> On 04/12/25 11:57 AM, Jianpeng Chang wrote:
>>> Commit 143937ca51cc ("arm64, mm: avoid always making PTE dirty in
>>> pte_mkwrite()") modified pte_mkwrite_novma() to only clear PTE_RDONLY
>>> when the page is already dirty (PTE_DIRTY is set). While this
>>> optimization
>>> prevents unnecessary dirty page marking in normal memory management
>>> paths,
>>> it breaks kexec on some platforms like NXP LS1043.
>>
>> Why is this problem only applicable for NXP LS1043 ? OR is that the only
>> platform you have observed the issue ? although that is problematic else
>> where as well.
> 
> Not only 1043. I found it on the NXP LS1043, and I have both NXP LS1043
> and LS1046 boards available. They both have this issue.
Hi Anshuman,

Just following up on my previous response from a week ago, any updates?

I borrowed an IMX8 board, which differs from the LS1043 as it's based on
Cortex-A72 + Cortex-A53, and conducted the same test. When reproducing
the issue on LS1043, I used the same Image as the first kernel with:
kexec -l /boot/Image --reuse-cmdline.

However, I couldn't reproduce it on IMX8 initially - the second kernel
booted normally. Here are the differences between IMX8 and LS1043:

root at nxp-ls1043:~# cat /proc/iomem | grep Kernel
  81000000-824effff : Kernel code
  82700000-82a8ffff : Kernel data
root at nxp-ls1043:~# kexec -l /boot/Image --reuse-cmdline -d 2>&1 | grep
segment
image_arm64_load: kernel_segment: 0000000080000000
arm64_load_other_segments:730: purgatory sink: 0x0
nr_segments = 3
segment[0].buf   = 0xffff9c5a2010
segment[0].bufsz = 0x194e200
segment[0].mem   = 0x80000000
segment[0].memsz = 0x1a90000
segment[1].buf   = 0xaaaad60cc180
segment[1].bufsz = 0xfa81
segment[1].mem   = 0x81a90000
segment[1].memsz = 0x10000
segment[2].buf   = 0xaaaad60dc1c0
segment[2].bufsz = 0x3660
segment[2].mem   = 0x81aa0000
segment[2].memsz = 0x4000

root at nxp-imx8:~# cat /proc/iomem | grep Kernel
  8a0000000-8a19bffff : Kernel code
  8a1c20000-8a1f7ffff : Kernel data
root at nxp-imx8:~# kexec -l /boot/Image --reuse-cmdline -d 2>&1 | grep segment
image_arm64_load: kernel_segment: 0000000080200000
arm64_load_other_segments:730: purgatory sink: 0x0
nr_segments = 3
segment[0].buf   = 0xffff990da010
segment[0].bufsz = 0x1ea2200
segment[0].mem   = 0x80200000
segment[0].memsz = 0x1f80000
segment[1].buf   = 0xffff99084010
segment[1].bufsz = 0x29839
segment[1].mem   = 0x82180000
segment[1].memsz = 0x2a000
segment[2].buf   = 0xaaaab0cdbc10
segment[2].bufsz = 0x3680
segment[2].mem   = 0x821aa000
segment[2].memsz = 0x4000

>From the logs, on LS1043, the second kernel segments happen to overlap
with the kernel code pages, which are read-only. I was able to reproduce
the same issue on IMX8 by forcing the overlap:
kexec -l /boot/Image --reuse-cmdline --mem-min=0x898000000
--mem-max=0x8a1000000

root at nxp-imx8:~# kexec -l /boot/Image --reuse-cmdline
--mem-min=0x898000000 --mem-max=0x8a1000000 -d 2>&1 | grep segment
image_arm64_load: kernel_segment: 0000000898000000
arm64_load_other_segments:730: purgatory sink: 0x0
nr_segments = 3
segment[0].buf   = 0xffff95e0a010
segment[0].bufsz = 0x1ea2200
segment[0].mem   = 0x898000000  overlap
segment[0].memsz = 0x1f80000
segment[1].buf   = 0xffff95db4010
segment[1].bufsz = 0x29839
segment[1].mem   = 0x899f80000
segment[1].memsz = 0x2a000
segment[2].buf   = 0xaaaac05fbc10
segment[2].bufsz = 0x3680
segment[2].mem   = 0x899faa000
segment[2].memsz = 0x4000

This explains why we haven't seen similar reports - the issue is memory
layout dependent. However, I still prefer this fix because it's
universal and works regardless of memory layout or kexec-tools address
selection. We cannot expect kexec-tools to always find the "right"
memory location, and fundamentally, we expect this temporary page table
to be writable.

I'm happy to know if you need any additional information or clarification.

Thanks,
Jianpeng
> 
>>
>>>
>>> The issue occurs in the kexec code path:
>>> 1. machine_kexec_post_load() calls trans_pgd_create_copy() to create a
>>> ??? writable copy of the linear mapping
>>> 2. _copy_pte() calls pte_mkwrite_novma() to ensure all pages in the copy
>>> ??? are writable for the new kernel image copying
>>> 3. With the new logic, clean pages (without PTE_DIRTY) remain read-only
>>> 4. When kexec tries to copy the new kernel image through the linear
>>> ??? mapping, it fails on read-only pages, causing the system to hang
>>> ??? after "Bye!"
>>>
>>> The same issue affects hibernation which uses the same trans_pgd code
>>> path.
>>>
>>> Fix this by marking pages dirty with pte_mkdirty() in _copy_pte(), which
>>> ensures pte_mkwrite_novma() clears PTE_RDONLY for both kexec and
>>> hibernation, making all pages in the temporary mapping writable
>>> regardless
>>> of their dirty state. This preserves the original commit's optimization
>>> for normal memory management while fixing the kexec/hibernation
>>> regression.
>>>
>>> Using pte_mkdirty() causes redundant bit operations when the page is
>>> already writable (redundant PTE_RDONLY clearing), but this is acceptable
>>> since it's not a hot path and only affects kexec/hibernation scenarios.
>>>
>>> Fixes: 143937ca51cc ("arm64, mm: avoid always making PTE dirty in
>>> pte_mkwrite()")
>>> Signed-off-by: Jianpeng Chang <jianpeng.chang.cn at windriver.com>
>>> Reviewed-by: Huang Ying <ying.huang at linux.alibaba.com>
>>> ---
>>> v3:
>>> ?? - Add the description about pte_mkdirty in commit message
>>> ?? - Note that the redundant bit operations in commit message
>>> ?? - Fix the comments following the suggestions
>>> v2: https://lore.kernel.org/all/20251202022707.2720933-1-
>>> jianpeng.chang.cn at windriver.com/
>>> ?? - Use pte_mkwrite_novma(pte_mkdirty(pte)) instead of manual bit
>>> manipulation
>>> ?? - Updated comments to clarify pte_mkwrite_novma() alone cannot be
>>> used
>>> v1: https://lore.kernel.org/all/20251127034350.3600454-1-
>>> jianpeng.chang.cn at windriver.com/
>>>
>>> ? arch/arm64/mm/trans_pgd.c | 17 +++++++++++++++--
>>> ? 1 file changed, 15 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/arch/arm64/mm/trans_pgd.c b/arch/arm64/mm/trans_pgd.c
>>> index 18543b603c77..766883780d2a 100644
>>> --- a/arch/arm64/mm/trans_pgd.c
>>> +++ b/arch/arm64/mm/trans_pgd.c
>>> @@ -40,8 +40,14 @@ static void _copy_pte(pte_t *dst_ptep, pte_t
>>> *src_ptep, unsigned long addr)
>>> ??????????????? * Resume will overwrite areas that may be marked
>>> ??????????????? * read only (code, rodata). Clear the RDONLY bit from
>>> ??????????????? * the temporary mappings we use during restore.
>>> +????????????? *
>>> +????????????? * For both kexec and hibernation, writable accesses
>>> are required
>>> +????????????? * for all pages in the linear map to copy over new
>>> kernel image.
>>> +????????????? * Hence mark these pages dirty first via pte_mkdirty()
>>> to ensure
>>> +????????????? * pte_mkwrite_novma() subsequently clears PTE_RDONLY -
>>> providing
>>> +????????????? * required write access for the pages.
>>> ??????????????? */
>>> -???????????? __set_pte(dst_ptep, pte_mkwrite_novma(pte));
>>> +???????????? __set_pte(dst_ptep, pte_mkwrite_novma(pte_mkdirty(pte)));
>>> ?????? } else if (!pte_none(pte)) {
>>> ?????????????? /*
>>> ??????????????? * debug_pagealloc will removed the PTE_VALID bit if
>>> @@ -57,7 +63,14 @@ static void _copy_pte(pte_t *dst_ptep, pte_t
>>> *src_ptep, unsigned long addr)
>>> ??????????????? */
>>> ?????????????? BUG_ON(!pfn_valid(pte_pfn(pte)));
>>>
>>> -???????????? __set_pte(dst_ptep, pte_mkvalid(pte_mkwrite_novma(pte)));
>>> +???????????? /*
>>> +????????????? * For both kexec and hibernation, writable accesses
>>> are required
>>> +????????????? * for all pages in the linear map to copy over new
>>> kernel image.
>>> +????????????? * Hence mark these pages dirty first via pte_mkdirty()
>>> to ensure
>>> +????????????? * pte_mkwrite_novma() subsequently clears PTE_RDONLY -
>>> providing
>>> +????????????? * required write access for the pages.
>>> +????????????? */
>>> +???????????? __set_pte(dst_ptep,
>>> pte_mkvalid(pte_mkwrite_novma(pte_mkdirty(pte))));
>>> ?????? }
>>> ? }
>>>
>>
> 



From francesco at dolcini.it  Tue Dec  9 23:45:50 2025
From: francesco at dolcini.it (Francesco Dolcini)
Date: Wed, 10 Dec 2025 08:45:50 +0100
Subject: [PATCH v2] arm64: errata: Add NXP iMX8QM workaround for A53
 Cache coherency issue
In-Reply-To: <20230420112952.28340-1-iivanov@suse.de>
References: <20230420112952.28340-1-iivanov@suse.de>
Message-ID: <20251210074550.GA10733@francesco-nb>

Hello Ivan,

On Thu, Apr 20, 2023 at 02:29:52PM +0300, Ivan T. Ivanov wrote:
> According to NXP errata document[1] i.MX8QuadMax SoC suffers from
> serious cache coherence issue. It was also mentioned in initial
> support[2] for imx8qm mek machine.

Ivan, from what I can see this patch was never merged and there was not any
follow-up on this. What's the status? Are you planning to work on it?

Frank, it would be nice to have this issue sorted out in mainline, any
chance that NXP can help move this forward?

Francesco



From francesco at dolcini.it  Tue Dec  9 23:59:27 2025
From: francesco at dolcini.it (Francesco Dolcini)
Date: Wed, 10 Dec 2025 08:59:27 +0100
Subject: [PATCH 2/2] arm64: dts: freescale: imx95: Add support for i.MX95
 15x15 FRDM board
In-Reply-To: <aTkbyAHjrwzTsfO8@lsvm07u0000156.swis.us-west-2.aws.nxp.com>
References: <20251207-127-v1-0-5a2eeb69f150@nxp.com>
 <20251207-127-v1-2-5a2eeb69f150@nxp.com>
 <20251208065707.GA15128@francesco-nb>
 <aTkbyAHjrwzTsfO8@lsvm07u0000156.swis.us-west-2.aws.nxp.com>
Message-ID: <20251210075927.GA13526@francesco-nb>

On Tue, Dec 09, 2025 at 11:05:44PM -0800, Lei Xu wrote:
> On Mon, Dec 08, 2025 at 07:57:07AM +0100, Francesco Dolcini wrote:
> > On Sun, Dec 07, 2025 at 05:26:06AM -0800, Lei Xu wrote:
> > > The i.MX95 15x15 FRDM board is a compact and cost-effective development
> > > platform based on the i.MX95 applications processor.
> > 
> > ...
> > 
> > > diff --git a/arch/arm64/boot/dts/freescale/imx95-15x15-frdm.dts b/arch/arm64/boot/dts/freescale/imx95-15x15-frdm.dts
> > > new file mode 100644
> > > index 000000000000..61e815c858b8
> > > --- /dev/null
> > > +++ b/arch/arm64/boot/dts/freescale/imx95-15x15-frdm.dts
> > 
> > ...
> > 
> > > +
> > > +/* Default settings in i.mx95.dtsi are for i.MX95 19x19 package.
> > > + * Override here for the i.MX95 15x15 package.
> > > + */
> > > +&netc_bus0 {
> > > +	msi-map = <0x0 &its 0x60 0x1>,	//ENETC0 PF
> > > +		  <0x10 &its 0x61 0x1>, //ENETC0 VF0
> > > +		  <0x20 &its 0x62 0x1>, //ENETC0 VF1
> > > +		  <0x40 &its 0x63 0x1>, //ENETC1 PF
> > > +		  <0x50 &its 0x65 0x1>, //ENETC1 VF0
> > > +		  <0x60 &its 0x66 0x1>, //ENETC1 VF1
> > > +		  <0x80 &its 0x64 0x1>, //ENETC2 PF
> > > +		  <0xc0 &its 0x67 0x1>; //NETC Timer
> > > +	iommu-map = <0x0 &smmu 0x20 0x1>,
> > > +		    <0x10 &smmu 0x21 0x1>,
> > > +		    <0x20 &smmu 0x22 0x1>,
> > > +		    <0x40 &smmu 0x23 0x1>,
> > > +		    <0x50 &smmu 0x25 0x1>,
> > > +		    <0x60 &smmu 0x26 0x1>,
> > > +		    <0x80 &smmu 0x24 0x1>,
> > > +		    <0xc0 &smmu 0x27 0x1>;
> > > +};
> > 
> > If the 19x19 and 15x15 i.MX95 requires something different you should
> > have a different soc dtsi. Probably creating a new imx95-$something
> > dtsi, that includes the existing imx95.dtsi and override this property.
> > 
> > This solution does not scale, please fix it.
> > 
> > Francesco
> >
> 
> Hello, Francesco
> 
> The original comment is misleading because this configuration applies
> to the board rather than the SoC.

If this is a board configuration, why it is in imx95.dtsi in the first
place?

In addition, I am interested in the topic, can you explain in more
detail why this is needed and what is this achieving?

Francesco



From claudiu.beznea at tuxon.dev  Wed Dec 10 00:04:55 2025
From: claudiu.beznea at tuxon.dev (Claudiu Beznea)
Date: Wed, 10 Dec 2025 10:04:55 +0200
Subject: [PATCH v2 2/3] ARM: at91: Move PM init functions to .init_late
 hook
In-Reply-To: <CAL_JsqJ2ghfNKQPhs19F1oxJxyTsrQ47hgPwsa3hUmgbGjpi-A@mail.gmail.com>
References: <20251120-at91-probe-v2-0-8c8592f02e8e@kernel.org>
 <20251120-at91-probe-v2-2-8c8592f02e8e@kernel.org>
 <ece2d53c-3e16-4e5e-9bb9-3ed7bb362b7b@tuxon.dev>
 <CAL_JsqJ2ghfNKQPhs19F1oxJxyTsrQ47hgPwsa3hUmgbGjpi-A@mail.gmail.com>
Message-ID: <985eb494-7bf3-4da6-9a54-aac3ba559cca@tuxon.dev>

Hi, Rob,

On 12/10/25 00:39, Rob Herring wrote:
> On Sat, Nov 22, 2025 at 9:37?AM Claudiu Beznea <claudiu.beznea at tuxon.dev> wrote:
>>
>> Hi, Rob,
>>
>> On 11/20/25 23:37, Rob Herring wrote:
>>> Move the AT91 PM init functions to .init_late hook to ensure driver
>>> dependencies have probed.
>>>
>>> Cc: Nicolas Ferre <nicolas.ferre at microchip.com>
>>> Cc: Alexandre Belloni <alexandre.belloni at bootlin.com>
>>> Cc: linux-arm-kernel at lists.infradead.org
>>> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
>>
>> 'From: Rob Herring <robh at kernel.org>' != 'Signed-off-by: Rob Herring (Arm)
>> <robh at kernel.org>
> 
> Before I respin, any feedback on whether this series actually works or not?

I've tested it on SAMA7G5-EK and SAM9X60-EK boards and it works.

Thank you,
Claudiu


From francesco at dolcini.it  Wed Dec 10 00:10:14 2025
From: francesco at dolcini.it (Francesco Dolcini)
Date: Wed, 10 Dec 2025 09:10:14 +0100
Subject: tps65219/am62p kernel oops
In-Reply-To: <d6de7066-a802-41fc-bb10-2f5d248743db@ti.com>
References: <aBDSTxALaOc-PD7X@gaggiata.pivistrello.it>
 <20250429185240.6a7644bf@akair>
 <20250430080109.GA65078@francesco-nb>
 <aBH5s7p2RxLGjTQD@gaggiata.pivistrello.it>
 <23eeda43-a938-4c15-aee3-b1b9df217ff8@ti.com>
 <20251209134343.GA238880@francesco-nb>
 <d6de7066-a802-41fc-bb10-2f5d248743db@ti.com>
Message-ID: <20251210080955.GA14989@francesco-nb>

Hello Shree,

On Tue, Dec 09, 2025 at 12:16:05PM -0600, Shree Ramamoorthy wrote:
> On 12/9/25 7:43 AM, Francesco Dolcini wrote:
> > On Thu, May 01, 2025 at 10:32:12AM -0500, Shree Ramamoorthy wrote:
> > > On 4/30/25 5:21 AM, Francesco Dolcini wrote:
> > > > On Wed, Apr 30, 2025 at 10:01:14AM +0200, Francesco Dolcini wrote:
> > > > > On Tue, Apr 29, 2025 at 06:52:40PM +0200, Andreas Kemnade wrote:
> > > > > > Am Tue, 29 Apr 2025 15:21:19 +0200
> > > > > > schrieb Francesco Dolcini <francesco at dolcini.it>:
> > > > > > > This oops was reproduced running current Linux
> > > > > > > master, 6.15.0-rc4+, ca91b9500108d4cf083a635c2e11c884d5dd20ea, but I was able
> > > > > > > to reproduce the same with 6.14.4.
> > > > > > > 
> > > > > > [...]
> > > > > > > [  +0.000022] Call trace:
> > > > > > > [  +0.000011]  regulator_notifier_call_chain+0x20/0xa4 (P)
> > > > > > > [  +0.000018]  tps65219_regulator_irq_handler+0x34/0x80
> > > > > > wild guessing: maybe because irqdata->rdev is not initalized in
> > > > > > _probe()? At least I do not see where it would be initialized.
> > > > > your wild guess seems correct, I'll send a proper patch with your
> > > > > suggested-by after doing a couple of more tests, thanks.
> > > > so, the bug is clear, however the fix is not an obvious one liner as I was
> > > > wishing.
> > > > 
> > > > we would need to add a link from each of the interrupts to the specific
> > > > regulator. as of now such a connection is not existing in the code.
> > > I'll try out implementing and testing the solution, but will get
> > > to it early next week. Will email with any updates!
> > What's the status on this? Were you able to do any progress or work on
> > it?
> 
> Thanks for following up on this, the task got lost on my end. My
> apologies!  The original line deleted `irq_data[i].rdev = rdev;` was
> never replaced.  The correct code should be re-implementing a version
> of the tps65219_get_rdev_by_name() function that was removed in commit
> 64a6b57 & add in irq_data.rdev = rdev;` where the other irq_data
> fields are being assigned within _probe.
> 
> Is there anything missing with this solution?

I am not really familiar with the code, I just looked at it once when
I did hit this bug. I would say to just send such a patch.

Francesco



From angelogioacchino.delregno at collabora.com  Wed Dec 10 00:10:20 2025
From: angelogioacchino.delregno at collabora.com (AngeloGioacchino Del Regno)
Date: Wed, 10 Dec 2025 09:10:20 +0100
Subject: [PATCH] media: platform: mtk-mdp3: add WQ_PERCPU to
 alloc_workqueue users
In-Reply-To: <20251107141303.223254-1-marco.crivellari@suse.com>
References: <20251107141303.223254-1-marco.crivellari@suse.com>
Message-ID: <17d99a64-8648-4fbc-9b7c-581f882d02a1@collabora.com>

Il 07/11/25 15:13, Marco Crivellari ha scritto:
> Currently if a user enqueues a work item using schedule_delayed_work() the
> used wq is "system_wq" (per-cpu wq) while queue_delayed_work() use
> WORK_CPU_UNBOUND (used when a cpu is not specified). The same applies to
> schedule_work() that is using system_wq and queue_work(), that makes use
> again of WORK_CPU_UNBOUND.
> This lack of consistency cannot be addressed without refactoring the API.
> 
> alloc_workqueue() treats all queues as per-CPU by default, while unbound
> workqueues must opt-in via WQ_UNBOUND.
> 
> This default is suboptimal: most workloads benefit from unbound queues,
> allowing the scheduler to place worker threads where they?re needed and
> reducing noise when CPUs are isolated.
> 
> This continues the effort to refactor workqueue APIs, which began with
> the introduction of new workqueues and a new alloc_workqueue flag in:
> 
> commit 128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq")
> commit 930c2ea566af ("workqueue: Add new WQ_PERCPU flag")
> 
> This change adds a new WQ_PERCPU flag to explicitly request
> alloc_workqueue() to be per-cpu when WQ_UNBOUND has not been specified.
> 
> With the introduction of the WQ_PERCPU flag (equivalent to !WQ_UNBOUND),
> any alloc_workqueue() caller that doesn?t explicitly specify WQ_UNBOUND
> must now use WQ_PERCPU.
> 
> Once migration is complete, WQ_UNBOUND can be removed and unbound will
> become the implicit default.
> 
> Suggested-by: Tejun Heo <tj at kernel.org>
> Signed-off-by: Marco Crivellari <marco.crivellari at suse.com>

Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>

> ---
>   drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c | 6 ++++--
>   1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
> index 6559d72d5d42..9083367ae2e4 100644
> --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
> +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
> @@ -255,14 +255,16 @@ static int mdp_probe(struct platform_device *pdev)
>   		goto err_free_mutex;
>   	}
>   
> -	mdp->job_wq = alloc_workqueue(MDP_MODULE_NAME, WQ_FREEZABLE, 0);
> +	mdp->job_wq = alloc_workqueue(MDP_MODULE_NAME,
> +				      WQ_FREEZABLE | WQ_PERCPU, 0);
>   	if (!mdp->job_wq) {
>   		dev_err(dev, "Unable to create job workqueue\n");
>   		ret = -ENOMEM;
>   		goto err_deinit_comp;
>   	}
>   
> -	mdp->clock_wq = alloc_workqueue(MDP_MODULE_NAME "-clock", WQ_FREEZABLE,
> +	mdp->clock_wq = alloc_workqueue(MDP_MODULE_NAME "-clock",
> +					WQ_FREEZABLE | WQ_PERCPU,
>   					0);
>   	if (!mdp->clock_wq) {
>   		dev_err(dev, "Unable to create clock workqueue\n");




From dmitry.baryshkov at oss.qualcomm.com  Wed Dec 10 00:21:37 2025
From: dmitry.baryshkov at oss.qualcomm.com (Dmitry Baryshkov)
Date: Wed, 10 Dec 2025 10:21:37 +0200
Subject: [PATCH v2 2/3] arm64: dts: qcom: lemans: add mdss1 display
 device nodes
In-Reply-To: <32f013e7-ce2a-484b-8575-e98f2d23f59b@oss.qualcomm.com>
References: <20251125105622.1755651-1-quic_mkuntuma@quicinc.com>
 <20251125105622.1755651-3-quic_mkuntuma@quicinc.com>
 <32f013e7-ce2a-484b-8575-e98f2d23f59b@oss.qualcomm.com>
Message-ID: <faau2h5z53frwfply57oh75zr5gcz4gf3za4vflbyht3ok4zgz@2ylcwcqcl4rt>

On Mon, Dec 01, 2025 at 02:35:44PM +0100, Konrad Dybcio wrote:
> On 11/25/25 11:56 AM, Mani Chandana Ballary Kuntumalla wrote:
> > Add devicetree changes to enable second Mobile Display Subsystem (mdss1),
> > Display Processing Unit(DPU), Display Port(DP) controllers and eDP PHYs
> > on the Qualcomm Lemans platform.
> > 
> > Signed-off-by: Mahadevan P <mahadevan.p at oss.qualcomm.com>
> > Signed-off-by: Mani Chandana Ballary Kuntumalla <quic_mkuntuma at quicinc.com>
> > ---
> 
> [...]
> 
> > +			mdss1_dp1: displayport-controller at 2215c000 {
> > +				compatible = "qcom,sa8775p-dp";
> > +
> > +				reg = <0x0 0x2215c000 0x0 0x104>,
> > +				      <0x0 0x2215c200 0x0 0x0c0>,
> > +				      <0x0 0x2215d000 0x0 0x770>,
> > +				      <0x0 0x2215e000 0x0 0x09c>,
> > +				      <0x0 0x2215f000 0x0 0x09c>,
> > +				      <0x0 0x22160000 0x0 0x09c>,
> > +				      <0x0 0x22161000 0x0 0x09c>,
> > +				      <0x0 0x22162000 0x0 0x23c>,
> > +				      <0x0 0x22163000 0x0 0x23c>;
> 
> The last two regions still happen not to exist

According to the memory map I observe, they do exist.

> https://lore.kernel.org/all/vc2hen5r7xdaj4nepkoy7pk2jmj4y4hgog5o2nfndrff4yti2m at g46svhsdyy7m/

-- 
With best wishes
Dmitry


From dmitry.baryshkov at oss.qualcomm.com  Wed Dec 10 00:29:03 2025
From: dmitry.baryshkov at oss.qualcomm.com (Dmitry Baryshkov)
Date: Wed, 10 Dec 2025 10:29:03 +0200
Subject: [PATCH v2 1/3] drm/msm/dp: Update msm_dp_controller IDs for
 sa8775p
In-Reply-To: <20251125105622.1755651-2-quic_mkuntuma@quicinc.com>
References: <20251125105622.1755651-1-quic_mkuntuma@quicinc.com>
 <20251125105622.1755651-2-quic_mkuntuma@quicinc.com>
Message-ID: <sfnfn3vctmhuks3wjco2f4y5vcfon3fn3pprcwgz7umpx6jt3t@dlps76vcmybc>

On Tue, Nov 25, 2025 at 04:26:20PM +0530, Mani Chandana Ballary Kuntumalla wrote:
> The Qualcomm SA8775P platform comes with 2 DisplayPort controllers
> for each mdss. Update controller id for DPTX0 and DPTX1 of mdss1.
> 
> Fixes: dcb380d19e58 ("drm/msm/dp: Add DisplayPort controller for SA8775P")
> Signed-off-by: Mani Chandana Ballary Kuntumalla <quic_mkuntuma at quicinc.com>
> ---
>  drivers/gpu/drm/msm/dp/dp_display.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>


-- 
With best wishes
Dmitry


From dmitry.baryshkov at oss.qualcomm.com  Wed Dec 10 00:30:39 2025
From: dmitry.baryshkov at oss.qualcomm.com (Dmitry Baryshkov)
Date: Wed, 10 Dec 2025 10:30:39 +0200
Subject: [PATCH v2 2/3] arm64: dts: qcom: lemans: add mdss1 display
 device nodes
In-Reply-To: <20251125105622.1755651-3-quic_mkuntuma@quicinc.com>
References: <20251125105622.1755651-1-quic_mkuntuma@quicinc.com>
 <20251125105622.1755651-3-quic_mkuntuma@quicinc.com>
Message-ID: <cndguco6ijb666ugbqpbffyhbbgs2nyno3qujuevz5dnpegir3@ygkh7vctnzuj>

On Tue, Nov 25, 2025 at 04:26:21PM +0530, Mani Chandana Ballary Kuntumalla wrote:
> Add devicetree changes to enable second Mobile Display Subsystem (mdss1),
> Display Processing Unit(DPU), Display Port(DP) controllers and eDP PHYs
> on the Qualcomm Lemans platform.
> 
> Signed-off-by: Mahadevan P <mahadevan.p at oss.qualcomm.com>
> Signed-off-by: Mani Chandana Ballary Kuntumalla <quic_mkuntuma at quicinc.com>
> ---
>  arch/arm64/boot/dts/qcom/lemans.dtsi | 338 ++++++++++++++++++++++++++-
>  1 file changed, 336 insertions(+), 2 deletions(-)
> 
> +
> +				mdss1_dp_opp_table: opp-table {

Why do we need two instances of the table?

> +					compatible = "operating-points-v2";
> +
> +					opp-160000000 {
> +						opp-hz = /bits/ 64 <160000000>;
> +						required-opps = <&rpmhpd_opp_low_svs>;
> +					};
> +
> +					opp-270000000 {
> +						opp-hz = /bits/ 64 <270000000>;
> +						required-opps = <&rpmhpd_opp_svs>;
> +					};
> +
> +					opp-540000000 {
> +						opp-hz = /bits/ 64 <540000000>;
> +						required-opps = <&rpmhpd_opp_svs_l1>;
> +					};
> +
> +					opp-810000000 {
> +						opp-hz = /bits/ 64 <810000000>;
> +						required-opps = <&rpmhpd_opp_nom>;
> +					};
> +				};
> +			};
> +
> +				mdss1_dp1_opp_table: opp-table {
> +					compatible = "operating-points-v2";
> +
> +					opp-160000000 {
> +						opp-hz = /bits/ 64 <160000000>;
> +						required-opps = <&rpmhpd_opp_low_svs>;
> +					};
> +
> +					opp-270000000 {
> +						opp-hz = /bits/ 64 <270000000>;
> +						required-opps = <&rpmhpd_opp_svs>;
> +					};
> +
> +					opp-540000000 {
> +						opp-hz = /bits/ 64 <540000000>;
> +						required-opps = <&rpmhpd_opp_svs_l1>;
> +					};
> +
> +					opp-810000000 {
> +						opp-hz = /bits/ 64 <810000000>;
> +						required-opps = <&rpmhpd_opp_nom>;
> +					};
> +				};
> +			};
> +		};
> +

-- 
With best wishes
Dmitry


From lei.xu at nxp.com  Wed Dec 10 01:07:25 2025
From: lei.xu at nxp.com (Lei Xu)
Date: Wed, 10 Dec 2025 01:07:25 -0800
Subject: [PATCH 2/2] arm64: dts: freescale: imx95: Add support for i.MX95
 15x15 FRDM board
In-Reply-To: <20251210075927.GA13526@francesco-nb>
References: <20251207-127-v1-0-5a2eeb69f150@nxp.com>
 <20251207-127-v1-2-5a2eeb69f150@nxp.com>
 <20251208065707.GA15128@francesco-nb>
 <aTkbyAHjrwzTsfO8@lsvm07u0000156.swis.us-west-2.aws.nxp.com>
 <20251210075927.GA13526@francesco-nb>
Message-ID: <aTk4TY8WYSILvFjY@lsvm07u0000156.swis.us-west-2.aws.nxp.com>

On Wed, Dec 10, 2025 at 08:59:27AM +0100, Francesco Dolcini wrote:
> On Tue, Dec 09, 2025 at 11:05:44PM -0800, Lei Xu wrote:
> > On Mon, Dec 08, 2025 at 07:57:07AM +0100, Francesco Dolcini wrote:
> > > On Sun, Dec 07, 2025 at 05:26:06AM -0800, Lei Xu wrote:
> > > > The i.MX95 15x15 FRDM board is a compact and cost-effective development
> > > > platform based on the i.MX95 applications processor.
> > > 
> > > ...
> > > 
> > > > diff --git a/arch/arm64/boot/dts/freescale/imx95-15x15-frdm.dts b/arch/arm64/boot/dts/freescale/imx95-15x15-frdm.dts
> > > > new file mode 100644
> > > > index 000000000000..61e815c858b8
> > > > --- /dev/null
> > > > +++ b/arch/arm64/boot/dts/freescale/imx95-15x15-frdm.dts
> > > 
> > > ...
> > > 
> > > > +
> > > > +/* Default settings in i.mx95.dtsi are for i.MX95 19x19 package.
> > > > + * Override here for the i.MX95 15x15 package.
> > > > + */
> > > > +&netc_bus0 {
> > > > +	msi-map = <0x0 &its 0x60 0x1>,	//ENETC0 PF
> > > > +		  <0x10 &its 0x61 0x1>, //ENETC0 VF0
> > > > +		  <0x20 &its 0x62 0x1>, //ENETC0 VF1
> > > > +		  <0x40 &its 0x63 0x1>, //ENETC1 PF
> > > > +		  <0x50 &its 0x65 0x1>, //ENETC1 VF0
> > > > +		  <0x60 &its 0x66 0x1>, //ENETC1 VF1
> > > > +		  <0x80 &its 0x64 0x1>, //ENETC2 PF
> > > > +		  <0xc0 &its 0x67 0x1>; //NETC Timer
> > > > +	iommu-map = <0x0 &smmu 0x20 0x1>,
> > > > +		    <0x10 &smmu 0x21 0x1>,
> > > > +		    <0x20 &smmu 0x22 0x1>,
> > > > +		    <0x40 &smmu 0x23 0x1>,
> > > > +		    <0x50 &smmu 0x25 0x1>,
> > > > +		    <0x60 &smmu 0x26 0x1>,
> > > > +		    <0x80 &smmu 0x24 0x1>,
> > > > +		    <0xc0 &smmu 0x27 0x1>;
> > > > +};
> > > 
> > > If the 19x19 and 15x15 i.MX95 requires something different you should
> > > have a different soc dtsi. Probably creating a new imx95-$something
> > > dtsi, that includes the existing imx95.dtsi and override this property.
> > > 
> > > This solution does not scale, please fix it.
> > > 
> > > Francesco
> > >
> > 
> > Hello, Francesco
> > 
> > The original comment is misleading because this configuration applies
> > to the board rather than the SoC.
> 
> If this is a board configuration, why it is in imx95.dtsi in the first
> place?
> 
> In addition, I am interested in the topic, can you explain in more
> detail why this is needed and what is this achieving?
> 
> Francesco
>

These entries define MSI and IOMMU mappings for ENETC interfaces.
The i.MX95 SoC integrates three ENETC instances.
On the i.MX95 15x15 FRDM board, instances 0 and 1 are used,
while on the i.MX95 19x19 EVK board, instances 0 and 2 are utilized by
default. Therefore, the mapping configuration must be customized for each board.

Lei


From xieyuanbin1 at huawei.com  Wed Dec 10 01:08:36 2025
From: xieyuanbin1 at huawei.com (Xie Yuanbin)
Date: Wed, 10 Dec 2025 17:08:36 +0800
Subject: [PATCH 0/3] ARM: fix hash_name() and branch predictor issues
In-Reply-To: <20251209085627.64057-1-xieyuanbin1@huawei.com>
References: <20251209085627.64057-1-xieyuanbin1@huawei.com>
Message-ID: <20251210090836.60465-1-xieyuanbin1@huawei.com>

Hi, Russell!

The syzkaller test has been running for 19+ hours now, and no issues
have been found so far. So to patch3:

Tested-by: Xie Yuanbin <xieyuanbin1 at huawei.com>

This test will continue to run. If any issues are found, I will email
you. If I don't send any emails, then there are no issues. :)

On Tue, 9 Dec 2025 16:56:27 +0800, Xie Yuanbin wrote:
> patch1 and patch2 with compilation error fixed:
>
> Tested-by: Xie Yuanbin <xieyuanbin1 at huawei.com>
>
> patch3:
> The simple test case passed, but the syzkaller test (the original
> scenario that triggered the branch predictor issue) is still running.
> The syzkaller test is better to run for a day.
>
> ...
>
> 2. About the branch predictor issue:
> Simple test cases (Link same as above) that can trigger this issue, has
> passed the tests. However, the original scenario which trigger the issue
> is the syzkaller test, which might take some time, possibly around a day.


From diederik at cknow-tech.com  Wed Dec 10 01:22:19 2025
From: diederik at cknow-tech.com (Diederik de Haas)
Date: Wed, 10 Dec 2025 10:22:19 +0100
Subject: [PATCH] crypto: arm64/ghash - Fix incorrect output from
 ghash-neon
In-Reply-To: <20251209223417.112294-1-ebiggers@kernel.org>
References: <DETXT7QI62KE.F3CGH2VWX1SC@cknow-tech.com>
 <20251209223417.112294-1-ebiggers@kernel.org>
Message-ID: <DEUFDH7FJURL.3J0FN5I19VV8F@cknow-tech.com>

On Tue Dec 9, 2025 at 11:34 PM CET, Eric Biggers wrote:
> Commit 9a7c987fb92b ("crypto: arm64/ghash - Use API partial block
> handling") made ghash_finup() pass the wrong buffer to
> ghash_do_simd_update().  As a result, ghash-neon now produces incorrect
> outputs when the message length isn't divisible by 16 bytes.  Fix this.

I was hoping to not have to do a 'git bisect', but this is much better
:-D I can confirm that this patch fixes the error I was seeing, so

Tested-by: Diederik de Haas <diederik at cknow-tech.com>

> (I didn't notice this earlier because this code is reached only on CPUs
> that support NEON but not PMULL.  I haven't yet found a way to get
> qemu-system-aarch64 to emulate that configuration.)

https://www.qemu.org/docs/master/system/arm/raspi.html indicates it can
emulate various Raspberry Pi models. I've only tested it with RPi 3B+
(bc of its wifi+bt chip), but I wouldn't be surprised if all RPi models
would have this problem? Dunno if QEMU emulates that though.

Thanks for the quick fix!

Cheers,
  Diederik

> Fixes: 9a7c987fb92b ("crypto: arm64/ghash - Use API partial block handling")
> Cc: stable at vger.kernel.org
> Reported-by: Diederik de Haas <diederik at cknow-tech.com>
> Closes: https://lore.kernel.org/linux-crypto/DETXT7QI62KE.F3CGH2VWX1SC at cknow-tech.com/
> Signed-off-by: Eric Biggers <ebiggers at kernel.org>
> ---
>
> If it's okay, I'd like to just take this via libcrypto-fixes.
>
>  arch/arm64/crypto/ghash-ce-glue.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/arm64/crypto/ghash-ce-glue.c b/arch/arm64/crypto/ghash-ce-glue.c
> index 7951557a285a..ef249d06c92c 100644
> --- a/arch/arm64/crypto/ghash-ce-glue.c
> +++ b/arch/arm64/crypto/ghash-ce-glue.c
> @@ -131,11 +131,11 @@ static int ghash_finup(struct shash_desc *desc, const u8 *src,
>  
>  	if (len) {
>  		u8 buf[GHASH_BLOCK_SIZE] = {};
>  
>  		memcpy(buf, src, len);
> -		ghash_do_simd_update(1, ctx->digest, src, key, NULL,
> +		ghash_do_simd_update(1, ctx->digest, buf, key, NULL,
>  				     pmull_ghash_update_p8);
>  		memzero_explicit(buf, sizeof(buf));
>  	}
>  	return ghash_export(desc, dst);
>  }
>
> base-commit: 7a3984bbd69055898add0fe22445f99435f33450



From ardb at kernel.org  Wed Dec 10 01:31:44 2025
From: ardb at kernel.org (Ard Biesheuvel)
Date: Wed, 10 Dec 2025 18:31:44 +0900
Subject: [PATCH] crypto: arm64/ghash - Fix incorrect output from ghash-neon
In-Reply-To: <DEUFDH7FJURL.3J0FN5I19VV8F@cknow-tech.com>
References: <DETXT7QI62KE.F3CGH2VWX1SC@cknow-tech.com> <20251209223417.112294-1-ebiggers@kernel.org>
 <DEUFDH7FJURL.3J0FN5I19VV8F@cknow-tech.com>
Message-ID: <CAMj1kXEQkB9MWB+PAi4XE_MuBt0ScitxTsKMDo1-7Cp-=xXOpw@mail.gmail.com>

On Wed, 10 Dec 2025 at 18:22, Diederik de Haas <diederik at cknow-tech.com> wrote:
>
> On Tue Dec 9, 2025 at 11:34 PM CET, Eric Biggers wrote:
> > Commit 9a7c987fb92b ("crypto: arm64/ghash - Use API partial block
> > handling") made ghash_finup() pass the wrong buffer to
> > ghash_do_simd_update().  As a result, ghash-neon now produces incorrect
> > outputs when the message length isn't divisible by 16 bytes.  Fix this.
>
> I was hoping to not have to do a 'git bisect', but this is much better
> :-D I can confirm that this patch fixes the error I was seeing, so
>
> Tested-by: Diederik de Haas <diederik at cknow-tech.com>
>
> > (I didn't notice this earlier because this code is reached only on CPUs
> > that support NEON but not PMULL.  I haven't yet found a way to get
> > qemu-system-aarch64 to emulate that configuration.)
>
> https://www.qemu.org/docs/master/system/arm/raspi.html indicates it can
> emulate various Raspberry Pi models. I've only tested it with RPi 3B+
> (bc of its wifi+bt chip), but I wouldn't be surprised if all RPi models
> would have this problem? Dunno if QEMU emulates that though.
>

All 64-bit RPi models except the RPi5 are affected by this, as those
do not implement the crypto extensions. So I would expect QEMU to do
the same.

It would be nice, though, if we could emulate this on the mach-virt
machine model too. It should be fairly trivial to do, so if there is
demand for this I can look into it.


From Irving-CH.Lin at mediatek.com  Wed Dec 10 02:01:24 2025
From: Irving-CH.Lin at mediatek.com (=?utf-8?B?SXJ2aW5nLUNIIExpbiAo5p6X5bu65byYKQ==?=)
Date: Wed, 10 Dec 2025 10:01:24 +0000
Subject: [PATCH v3 01/21] dt-bindings: clock: mediatek: Add MT8189 clock
 definitions
In-Reply-To: <20251106-hug-stingray-2d3ff42fd365@spud>
References: <20251106124330.1145600-1-irving-ch.lin@mediatek.com>
	 <20251106124330.1145600-2-irving-ch.lin@mediatek.com>
	 <20251106-hug-stingray-2d3ff42fd365@spud>
Message-ID: <626b5c4b810678a7f0de1f109371a6d6694bd2a8.camel@mediatek.com>

Hi Conor,

On Thu, 2025-11-06 at 17:19 +0000, Conor Dooley wrote:
> On Thu, Nov 06, 2025 at 08:41:46PM +0800, irving.ch.lin wrote:
> > From: Irving-CH Lin <irving-ch.lin at mediatek.com>
> > 
> > Add device tree bindings for the clock of MediaTek MT8189 SoC.
> > 
> > Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
> 
> Before I approve this, can you share the dts that actually uses it?
> This many different syscons really does look suspect, and that not
> all
> of these should be nodes of their own. They may very well be, I would
> just like to see what the dts looks like. Doesn't need to be a patch,
> a
> link to your tree will suffice.
> 
> Cheers,
> Conor.
> 
https://patchwork.kernel.org/project/linux-mediatek/patch/20251111070031.305281-10-jh.hsu at mediatek.com/
Please refer to link for mt8189 dts.

thanks

BR,
irving

> > ---
> > ?.../bindings/clock/mediatek,mt8189-clock.yaml |? 90 +++
> > ?.../clock/mediatek,mt8189-sys-clock.yaml????? |? 58 ++
> > ?.../dt-bindings/clock/mediatek,mt8189-clk.h?? | 580
> > ++++++++++++++++++
> > ?3 files changed, 728 insertions(+)
> > ?create mode 100644
> > Documentation/devicetree/bindings/clock/mediatek,mt8189-clock.yaml
> > ?create mode 100644
> > Documentation/devicetree/bindings/clock/mediatek,mt8189-sys-
> > clock.yaml
> > ?create mode 100644 include/dt-bindings/clock/mediatek,mt8189-clk.h
> > 
> > diff --git
> > a/Documentation/devicetree/bindings/clock/mediatek,mt8189-
> > clock.yaml
> > b/Documentation/devicetree/bindings/clock/mediatek,mt8189-
> > clock.yaml
> > new file mode 100644
> > index 000000000000..25f7c9fb99fe
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/clock/mediatek,mt8189-
> > clock.yaml
> > @@ -0,0 +1,90 @@
> > +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id:
> > http://devicetree.org/schemas/clock/mediatek,mt8189-clock.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: MediaTek Functional Clock Controller for MT8189
> > +
> > +maintainers:
> > +? - Qiqi Wang <qiqi.wang at mediatek.com>
> > +
> > +description: |
> > +? The clock architecture in MediaTek like below
> > +? PLLs -->
> > +????????? dividers -->
> > +????????????????????? muxes -->
> > +?????????????????????????????? clock gate
> > +
> > +? The devices provide clock gate control in different IP blocks.
> > +
> > +properties:
> > +? compatible:
> > +??? items:
> > +????? - enum:
> > +??????? - mediatek,mt8189-camsys-main
> > +??????? - mediatek,mt8189-camsys-rawa
> > +??????? - mediatek,mt8189-camsys-rawb
> > +??????? - mediatek,mt8189-dbg-ao
> > +??????? - mediatek,mt8189-dem
> > +??????? - mediatek,mt8189-dispsys
> > +??????? - mediatek,mt8189-dvfsrc-top
> > +??????? - mediatek,mt8189-gce-d
> > +??????? - mediatek,mt8189-gce-m
> > +??????? - mediatek,mt8189-iic-wrap-e
> > +??????? - mediatek,mt8189-iic-wrap-en
> > +??????? - mediatek,mt8189-iic-wrap-s
> > +??????? - mediatek,mt8189-iic-wrap-ws
> > +??????? - mediatek,mt8189-imgsys1
> > +??????? - mediatek,mt8189-imgsys2
> > +??????? - mediatek,mt8189-infra-ao
> > +??????? - mediatek,mt8189-ipesys
> > +??????? - mediatek,mt8189-mdpsys
> > +??????? - mediatek,mt8189-mfgcfg
> > +??????? - mediatek,mt8189-mm-infra
> > +??????? - mediatek,mt8189-peri-ao
> > +??????? - mediatek,mt8189-scp-clk
> > +??????? - mediatek,mt8189-scp-i2c-clk
> > +??????? - mediatek,mt8189-ufscfg-ao
> > +??????? - mediatek,mt8189-ufscfg-pdn
> > +??????? - mediatek,mt8189-vdec-core
> > +??????? - mediatek,mt8189-venc
> > +????? - const: syscon
> > +
> > +? reg:
> > +??? maxItems: 1
> > +
> > +? '#clock-cells':
> > +??? const: 1
> > +
> > +? '#reset-cells':
> > +??? const: 1
> > +
> > +required:
> > +? - compatible
> > +? - reg
> > +? - '#clock-cells'
> > +
> > +allOf:
> > +? - if:
> > +????? properties:
> > +??????? compatible:
> > +????????? contains:
> > +??????????? enum:
> > +????????????? - mediatek,mt8189-peri-ao
> > +????????????? - mediatek,mt8189-ufscfg-ao
> > +????????????? - mediatek,mt8189-ufscfg-pdn
> > +
> > +??? then:
> > +????? required:
> > +??????? - '#reset-cells'
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > +? - |
> > +??? clock-controller at 11b21000 {
> > +??????? compatible = "mediatek,mt8189-iic-wrap-ws", "syscon";
> > +??????? reg = <0x11b21000 0x1000>;
> > +??????? #clock-cells = <1>;
> > +??? };
> > diff --git
> > a/Documentation/devicetree/bindings/clock/mediatek,mt8189-sys-
> > clock.yaml
> > b/Documentation/devicetree/bindings/clock/mediatek,mt8189-sys-
> > clock.yaml
> > new file mode 100644
> > index 000000000000..ba36c303617e
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/clock/mediatek,mt8189-sys-
> > clock.yaml
> > @@ -0,0 +1,58 @@
> > +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id:
> > http://devicetree.org/schemas/clock/mediatek,mt8189-sys-clock.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: MediaTek System Clock Controller for MT8189
> > +
> > +maintainers:
> > +? - Qiqi Wang <qiqi.wang at mediatek.com>
> > +
> > +description: |
> > +? The clock architecture in MediaTek like below
> > +? PLLs -->
> > +????????? dividers -->
> > +????????????????????? muxes -->
> > +?????????????????????????????? clock gate
> > +
> > +? The apmixedsys provides most of PLLs which generated from SoC
> > 26m.
> > +? The topckgen provides dividers and muxes which provide the clock
> > source to other IP blocks.
> > +? The infracfg_ao provides clock gate in peripheral and
> > infrastructure IP blocks.
> > +? The mcusys provides mux control to select the clock source in AP
> > MCU.
> > +? The device nodes also provide the system control capacity for
> > configuration.
> > +
> > +properties:
> > +? compatible:
> > +??? items:
> > +????? - enum:
> > +????????? - mediatek,mt8189-apmixedsys
> > +????????? - mediatek,mt8189-topckgen
> > +????????? - mediatek,mt8189-vlpckgen
> > +????????? - mediatek,mt8189-vlp-ao-ckgen
> > +????????? - mediatek,mt8189-vlpcfg-ao
> > +????? - const: syscon
> > +
> > +? reg:
> > +??? maxItems: 1
> > +
> > +? '#clock-cells':
> > +??? const: 1
> > +
> > +? '#reset-cells':
> > +??? const: 1
> > +
> > +required:
> > +? - compatible
> > +? - reg
> > +? - '#clock-cells'
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > +? - |
> > +??? clock-controller at 10000000 {
> > +??????? compatible = "mediatek,mt8189-topckgen", "syscon";
> > +??????? reg = <0x10000000 0x1000>;
> > +??????? #clock-cells = <1>;
> > +??? };
> > diff --git a/include/dt-bindings/clock/mediatek,mt8189-clk.h
> > b/include/dt-bindings/clock/mediatek,mt8189-clk.h
> > new file mode 100644
> > index 000000000000..139db869a3ec
> > --- /dev/null
> > +++ b/include/dt-bindings/clock/mediatek,mt8189-clk.h
> > @@ -0,0 +1,580 @@
> > +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)? */
> > +/*
> > + * Copyright (c) 2025 MediaTek Inc.
> > + * Author: Qiqi Wang <qiqi.wang at mediatek.com>
> > + */
> > +
> > +#ifndef _DT_BINDINGS_CLK_MT8189_H
> > +#define _DT_BINDINGS_CLK_MT8189_H
> > +
> > +/* TOPCKGEN */
> > +#define CLK_TOP_AXI_SEL					0
> > +#define CLK_TOP_AXI_PERI_SEL				1
> > +#define CLK_TOP_AXI_U_SEL				2
> > +#define CLK_TOP_BUS_AXIMEM_SEL				3
> > +#define CLK_TOP_DISP0_SEL				4
> > +#define CLK_TOP_MMINFRA_SEL				5
> > +#define CLK_TOP_UART_SEL				6
> > +#define CLK_TOP_SPI0_SEL				7
> > +#define CLK_TOP_SPI1_SEL				8
> > +#define CLK_TOP_SPI2_SEL				9
> > +#define CLK_TOP_SPI3_SEL				10
> > +#define CLK_TOP_SPI4_SEL				11
> > +#define CLK_TOP_SPI5_SEL				12
> > +#define CLK_TOP_MSDC_MACRO_0P_SEL			13
> > +#define CLK_TOP_MSDC50_0_HCLK_SEL			14
> > +#define CLK_TOP_MSDC50_0_SEL				15
> > +#define CLK_TOP_AES_MSDCFDE_SEL				16
> > +#define CLK_TOP_MSDC_MACRO_1P_SEL			17
> > +#define CLK_TOP_MSDC30_1_SEL				18
> > +#define CLK_TOP_MSDC30_1_HCLK_SEL			19
> > +#define CLK_TOP_MSDC_MACRO_2P_SEL			20
> > +#define CLK_TOP_MSDC30_2_SEL				21
> > +#define CLK_TOP_MSDC30_2_HCLK_SEL			22
> > +#define CLK_TOP_AUD_INTBUS_SEL				23
> > +#define CLK_TOP_ATB_SEL					24
> > +#define CLK_TOP_DISP_PWM_SEL				25
> > +#define CLK_TOP_USB_TOP_P0_SEL				26
> > +#define CLK_TOP_USB_XHCI_P0_SEL				27
> > +#define CLK_TOP_USB_TOP_P1_SEL				28
> > +#define CLK_TOP_USB_XHCI_P1_SEL				29
> > +#define CLK_TOP_USB_TOP_P2_SEL				30
> > +#define CLK_TOP_USB_XHCI_P2_SEL				31
> > +#define CLK_TOP_USB_TOP_P3_SEL				32
> > +#define CLK_TOP_USB_XHCI_P3_SEL				33
> > +#define CLK_TOP_USB_TOP_P4_SEL				34
> > +#define CLK_TOP_USB_XHCI_P4_SEL				35
> > +#define CLK_TOP_I2C_SEL					36
> > +#define CLK_TOP_SENINF_SEL				37
> > +#define CLK_TOP_SENINF1_SEL				38
> > +#define CLK_TOP_AUD_ENGEN1_SEL				39
> > +#define CLK_TOP_AUD_ENGEN2_SEL				40
> > +#define CLK_TOP_AES_UFSFDE_SEL				41
> > +#define CLK_TOP_U_SEL					42
> > +#define CLK_TOP_U_MBIST_SEL				43
> > +#define CLK_TOP_AUD_1_SEL				44
> > +#define CLK_TOP_AUD_2_SEL				45
> > +#define CLK_TOP_VENC_SEL				46
> > +#define CLK_TOP_VDEC_SEL				47
> > +#define CLK_TOP_PWM_SEL					48
> > +#define CLK_TOP_AUDIO_H_SEL				49
> > +#define CLK_TOP_MCUPM_SEL				50
> > +#define CLK_TOP_MEM_SUB_SEL				51
> > +#define CLK_TOP_MEM_SUB_PERI_SEL			52
> > +#define CLK_TOP_MEM_SUB_U_SEL				53
> > +#define CLK_TOP_EMI_N_SEL				54
> > +#define CLK_TOP_DSI_OCC_SEL				55
> > +#define CLK_TOP_AP2CONN_HOST_SEL			56
> > +#define CLK_TOP_IMG1_SEL				57
> > +#define CLK_TOP_IPE_SEL					58
> > +#define CLK_TOP_CAM_SEL					59
> > +#define CLK_TOP_CAMTM_SEL				60
> > +#define CLK_TOP_DSP_SEL					61
> > +#define CLK_TOP_SR_PKA_SEL				62
> > +#define CLK_TOP_DXCC_SEL				63
> > +#define CLK_TOP_MFG_REF_SEL				64
> > +#define CLK_TOP_MDP0_SEL				65
> > +#define CLK_TOP_DP_SEL					66
> > +#define CLK_TOP_EDP_SEL					67
> > +#define CLK_TOP_EDP_FAVT_SEL				68
> > +#define CLK_TOP_ETH_250M_SEL				69
> > +#define CLK_TOP_ETH_62P4M_PTP_SEL			70
> > +#define CLK_TOP_ETH_50M_RMII_SEL			71
> > +#define CLK_TOP_SFLASH_SEL				72
> > +#define CLK_TOP_GCPU_SEL				73
> > +#define CLK_TOP_MAC_TL_SEL				74
> > +#define CLK_TOP_VDSTX_DG_CTS_SEL			75
> > +#define CLK_TOP_PLL_DPIX_SEL				76
> > +#define CLK_TOP_ECC_SEL					77
> > +#define CLK_TOP_APLL_I2SIN0_MCK_SEL			78
> > +#define CLK_TOP_APLL_I2SIN1_MCK_SEL			79
> > +#define CLK_TOP_APLL_I2SIN2_MCK_SEL			80
> > +#define CLK_TOP_APLL_I2SIN3_MCK_SEL			81
> > +#define CLK_TOP_APLL_I2SIN4_MCK_SEL			82
> > +#define CLK_TOP_APLL_I2SIN6_MCK_SEL			83
> > +#define CLK_TOP_APLL_I2SOUT0_MCK_SEL			84
> > +#define CLK_TOP_APLL_I2SOUT1_MCK_SEL			85
> > +#define CLK_TOP_APLL_I2SOUT2_MCK_SEL			86
> > +#define CLK_TOP_APLL_I2SOUT3_MCK_SEL			87
> > +#define CLK_TOP_APLL_I2SOUT4_MCK_SEL			88
> > +#define CLK_TOP_APLL_I2SOUT6_MCK_SEL			89
> > +#define CLK_TOP_APLL_FMI2S_MCK_SEL			90
> > +#define CLK_TOP_APLL_TDMOUT_MCK_SEL			91
> > +#define CLK_TOP_MFG_SEL_MFGPLL				92
> > +#define CLK_TOP_APLL12_CK_DIV_I2SIN0			93
> > +#define CLK_TOP_APLL12_CK_DIV_I2SIN1			94
> > +#define CLK_TOP_APLL12_CK_DIV_I2SOUT0			95
> > +#define CLK_TOP_APLL12_CK_DIV_I2SOUT1			96
> > +#define CLK_TOP_APLL12_CK_DIV_FMI2S			97
> > +#define CLK_TOP_APLL12_CK_DIV_TDMOUT_M			98
> > +#define CLK_TOP_APLL12_CK_DIV_TDMOUT_B			99
> > +#define CLK_TOP_MAINPLL_D3				100
> > +#define CLK_TOP_MAINPLL_D4				101
> > +#define CLK_TOP_MAINPLL_D4_D2				102
> > +#define CLK_TOP_MAINPLL_D4_D4				103
> > +#define CLK_TOP_MAINPLL_D4_D8				104
> > +#define CLK_TOP_MAINPLL_D5				105
> > +#define CLK_TOP_MAINPLL_D5_D2				106
> > +#define CLK_TOP_MAINPLL_D5_D4				107
> > +#define CLK_TOP_MAINPLL_D5_D8				108
> > +#define CLK_TOP_MAINPLL_D6				109
> > +#define CLK_TOP_MAINPLL_D6_D2				110
> > +#define CLK_TOP_MAINPLL_D6_D4				111
> > +#define CLK_TOP_MAINPLL_D6_D8				112
> > +#define CLK_TOP_MAINPLL_D7				113
> > +#define CLK_TOP_MAINPLL_D7_D2				114
> > +#define CLK_TOP_MAINPLL_D7_D4				115
> > +#define CLK_TOP_MAINPLL_D7_D8				116
> > +#define CLK_TOP_MAINPLL_D9				117
> > +#define CLK_TOP_UNIVPLL_D2				118
> > +#define CLK_TOP_UNIVPLL_D3				119
> > +#define CLK_TOP_UNIVPLL_D4				120
> > +#define CLK_TOP_UNIVPLL_D4_D2				121
> > +#define CLK_TOP_UNIVPLL_D4_D4				122
> > +#define CLK_TOP_UNIVPLL_D4_D8				123
> > +#define CLK_TOP_UNIVPLL_D5				124
> > +#define CLK_TOP_UNIVPLL_D5_D2				125
> > +#define CLK_TOP_UNIVPLL_D5_D4				126
> > +#define CLK_TOP_UNIVPLL_D6				127
> > +#define CLK_TOP_UNIVPLL_D6_D2				128
> > +#define CLK_TOP_UNIVPLL_D6_D4				129
> > +#define CLK_TOP_UNIVPLL_D6_D8				130
> > +#define CLK_TOP_UNIVPLL_D6_D16				131
> > +#define CLK_TOP_UNIVPLL_D7				132
> > +#define CLK_TOP_UNIVPLL_D7_D2				133
> > +#define CLK_TOP_UNIVPLL_D7_D3				134
> > +#define CLK_TOP_LVDSTX_DG_CTS				135
> > +#define CLK_TOP_UNIVPLL_192M				136
> > +#define
> > CLK_TOP_UNIVPLL_192M_D2				137
> > +#define
> > CLK_TOP_UNIVPLL_192M_D4				138
> > +#define
> > CLK_TOP_UNIVPLL_192M_D8				139
> > +#define CLK_TOP_UNIVPLL_192M_D10			140
> > +#define CLK_TOP_UNIVPLL_192M_D16			141
> > +#define CLK_TOP_UNIVPLL_192M_D32			142
> > +#define CLK_TOP_APLL1_D2				143
> > +#define CLK_TOP_APLL1_D4				144
> > +#define CLK_TOP_APLL1_D8				145
> > +#define CLK_TOP_APLL1_D3				146
> > +#define CLK_TOP_APLL2_D2				147
> > +#define CLK_TOP_APLL2_D4				148
> > +#define CLK_TOP_APLL2_D8				149
> > +#define CLK_TOP_APLL2_D3				150
> > +#define CLK_TOP_MMPLL_D4				151
> > +#define CLK_TOP_MMPLL_D4_D2				152
> > +#define CLK_TOP_MMPLL_D4_D4				153
> > +#define CLK_TOP_VPLL_DPIX				154
> > +#define CLK_TOP_MMPLL_D5				155
> > +#define CLK_TOP_MMPLL_D5_D2				156
> > +#define CLK_TOP_MMPLL_D5_D4				157
> > +#define CLK_TOP_MMPLL_D6				158
> > +#define CLK_TOP_MMPLL_D6_D2				159
> > +#define CLK_TOP_MMPLL_D7				160
> > +#define CLK_TOP_MMPLL_D9				161
> > +#define CLK_TOP_TVDPLL1_D2				162
> > +#define CLK_TOP_TVDPLL1_D4				163
> > +#define CLK_TOP_TVDPLL1_D8				164
> > +#define CLK_TOP_TVDPLL1_D16				165
> > +#define CLK_TOP_TVDPLL2_D2				166
> > +#define CLK_TOP_TVDPLL2_D4				167
> > +#define CLK_TOP_TVDPLL2_D8				168
> > +#define CLK_TOP_TVDPLL2_D16				169
> > +#define CLK_TOP_ETHPLL_D2				170
> > +#define CLK_TOP_ETHPLL_D8				171
> > +#define CLK_TOP_ETHPLL_D10				172
> > +#define CLK_TOP_MSDCPLL_D2				173
> > +#define CLK_TOP_VOWPLL????????????????????????????????? 174
> > +#define CLK_TOP_UFSPLL_D2				175
> > +#define CLK_TOP_F26M_CK_D2				176
> > +#define CLK_TOP_OSC_D2					177
> > +#define CLK_TOP_OSC_D4					178
> > +#define CLK_TOP_OSC_D8					179
> > +#define
> > CLK_TOP_OSC_D16					180
> > +#define CLK_TOP_OSC_D3					181
> > +#define CLK_TOP_OSC_D7					182
> > +#define
> > CLK_TOP_OSC_D10					183
> > +#define
> > CLK_TOP_OSC_D20					184
> > +#define CLK_TOP_FMCNT_P0_EN				185
> > +#define CLK_TOP_FMCNT_P1_EN				186
> > +#define CLK_TOP_FMCNT_P2_EN				187
> > +#define CLK_TOP_FMCNT_P3_EN				188
> > +#define CLK_TOP_FMCNT_P4_EN				189
> > +#define CLK_TOP_USB_F26M_CK_EN				190
> > +#define CLK_TOP_SSPXTP_F26M_CK_EN			191
> > +#define CLK_TOP_USB2_PHY_RF_P0_EN			192
> > +#define CLK_TOP_USB2_PHY_RF_P1_EN			193
> > +#define CLK_TOP_USB2_PHY_RF_P2_EN			194
> > +#define CLK_TOP_USB2_PHY_RF_P3_EN			195
> > +#define CLK_TOP_USB2_PHY_RF_P4_EN			196
> > +#define CLK_TOP_USB2_26M_CK_P0_EN			197
> > +#define CLK_TOP_USB2_26M_CK_P1_EN			198
> > +#define CLK_TOP_USB2_26M_CK_P2_EN			199
> > +#define CLK_TOP_USB2_26M_CK_P3_EN			200
> > +#define CLK_TOP_USB2_26M_CK_P4_EN			201
> > +#define CLK_TOP_F26M_CK_EN				202
> > +#define CLK_TOP_AP2CON_EN				203
> > +#define CLK_TOP_EINT_N_EN				204
> > +#define CLK_TOP_TOPCKGEN_FMIPI_CSI_UP26M_CK_EN		205
> > +#define CLK_TOP_DRAMULP_CK_EN				206
> > +#define CLK_TOP_EINT_E_EN				207
> > +#define CLK_TOP_EINT_W_EN				208
> > +#define CLK_TOP_EINT_S_EN				209
> > +
> > +/* INFRACFG_AO */
> > +#define CLK_IFRAO_CQ_DMA_FPC				0
> > +#define CLK_IFRAO_DEBUGSYS				1
> > +#define CLK_IFRAO_DBG_TRACE				2
> > +#define CLK_IFRAO_CQ_DMA				3
> > +
> > +/* APMIXEDSYS */
> > +#define CLK_APMIXED_ARMPLL_LL				0
> > +#define CLK_APMIXED_ARMPLL_BL				1
> > +#define CLK_APMIXED_CCIPLL				2
> > +#define CLK_APMIXED_MAINPLL				3
> > +#define CLK_APMIXED_UNIVPLL				4
> > +#define CLK_APMIXED_MMPLL				5
> > +#define CLK_APMIXED_MFGPLL				6
> > +#define CLK_APMIXED_APLL1				7
> > +#define CLK_APMIXED_APLL2				8
> > +#define CLK_APMIXED_EMIPLL				9
> > +#define CLK_APMIXED_APUPLL2				10
> > +#define CLK_APMIXED_APUPLL				11
> > +#define CLK_APMIXED_TVDPLL1				12
> > +#define CLK_APMIXED_TVDPLL2				13
> > +#define CLK_APMIXED_ETHPLL				14
> > +#define CLK_APMIXED_MSDCPLL				15
> > +#define CLK_APMIXED_UFSPLL				16
> > +
> > +/* PERICFG_AO */
> > +#define CLK_PERAO_UART0					0
> > +#define CLK_PERAO_UART1					1
> > +#define CLK_PERAO_UART2					2
> > +#define CLK_PERAO_UART3					3
> > +#define CLK_PERAO_PWM_H					4
> > +#define CLK_PERAO_PWM_B					5
> > +#define CLK_PERAO_PWM_FB1				6
> > +#define CLK_PERAO_PWM_FB2				7
> > +#define CLK_PERAO_PWM_FB3				8
> > +#define CLK_PERAO_PWM_FB4				9
> > +#define CLK_PERAO_DISP_PWM0				10
> > +#define CLK_PERAO_DISP_PWM1				11
> > +#define CLK_PERAO_SPI0_B				12
> > +#define CLK_PERAO_SPI1_B				13
> > +#define CLK_PERAO_SPI2_B				14
> > +#define CLK_PERAO_SPI3_B				15
> > +#define CLK_PERAO_SPI4_B				16
> > +#define CLK_PERAO_SPI5_B				17
> > +#define CLK_PERAO_SPI0_H				18
> > +#define CLK_PERAO_SPI1_H				19
> > +#define CLK_PERAO_SPI2_H				20
> > +#define CLK_PERAO_SPI3_H				21
> > +#define CLK_PERAO_SPI4_H				22
> > +#define CLK_PERAO_SPI5_H				23
> > +#define CLK_PERAO_AXI					24
> > +#define CLK_PERAO_AHB_APB				25
> > +#define CLK_PERAO_TL					26
> > +#define CLK_PERAO_REF					27
> > +#define CLK_PERAO_I2C					28
> > +#define CLK_PERAO_DMA_B					29
> > +#define CLK_PERAO_SSUSB0_REF				30
> > +#define CLK_PERAO_SSUSB0_FRMCNT				31
> > +#define CLK_PERAO_SSUSB0_SYS				32
> > +#define CLK_PERAO_SSUSB0_XHCI				33
> > +#define CLK_PERAO_SSUSB0_F				34
> > +#define CLK_PERAO_SSUSB0_H				35
> > +#define CLK_PERAO_SSUSB1_REF				36
> > +#define CLK_PERAO_SSUSB1_FRMCNT				37
> > +#define CLK_PERAO_SSUSB1_SYS				38
> > +#define CLK_PERAO_SSUSB1_XHCI				39
> > +#define CLK_PERAO_SSUSB1_F				40
> > +#define CLK_PERAO_SSUSB1_H				41
> > +#define CLK_PERAO_SSUSB2_REF				42
> > +#define CLK_PERAO_SSUSB2_FRMCNT				43
> > +#define CLK_PERAO_SSUSB2_SYS				44
> > +#define CLK_PERAO_SSUSB2_XHCI				45
> > +#define CLK_PERAO_SSUSB2_F				46
> > +#define CLK_PERAO_SSUSB2_H				47
> > +#define CLK_PERAO_SSUSB3_REF				48
> > +#define CLK_PERAO_SSUSB3_FRMCNT				49
> > +#define CLK_PERAO_SSUSB3_SYS				50
> > +#define CLK_PERAO_SSUSB3_XHCI				51
> > +#define CLK_PERAO_SSUSB3_F				52
> > +#define CLK_PERAO_SSUSB3_H				53
> > +#define CLK_PERAO_SSUSB4_REF				54
> > +#define CLK_PERAO_SSUSB4_FRMCNT				55
> > +#define CLK_PERAO_SSUSB4_SYS				56
> > +#define CLK_PERAO_SSUSB4_XHCI				57
> > +#define CLK_PERAO_SSUSB4_F				58
> > +#define CLK_PERAO_SSUSB4_H				59
> > +#define CLK_PERAO_MSDC0					60
> > +#define CLK_PERAO_MSDC0_H				61
> > +#define CLK_PERAO_MSDC0_FAES				62
> > +#define CLK_PERAO_MSDC0_MST_F				63
> > +#define CLK_PERAO_MSDC0_SLV_H				64
> > +#define CLK_PERAO_MSDC1					65
> > +#define CLK_PERAO_MSDC1_H				66
> > +#define CLK_PERAO_MSDC1_MST_F				67
> > +#define CLK_PERAO_MSDC1_SLV_H				68
> > +#define CLK_PERAO_MSDC2					69
> > +#define CLK_PERAO_MSDC2_H				70
> > +#define CLK_PERAO_MSDC2_MST_F				71
> > +#define CLK_PERAO_MSDC2_SLV_H				72
> > +#define CLK_PERAO_SFLASH				73
> > +#define CLK_PERAO_SFLASH_F				74
> > +#define CLK_PERAO_SFLASH_H				75
> > +#define CLK_PERAO_SFLASH_P				76
> > +#define CLK_PERAO_AUDIO0				77
> > +#define CLK_PERAO_AUDIO1				78
> > +#define CLK_PERAO_AUDIO2				79
> > +#define CLK_PERAO_AUXADC_26M				80
> > +
> > +/* UFSCFG_AO_REG */
> > +#define CLK_UFSCFG_AO_REG_UNIPRO_TX_SYM			0
> > +#define CLK_UFSCFG_AO_REG_UNIPRO_RX_SYM0		1
> > +#define CLK_UFSCFG_AO_REG_UNIPRO_RX_SYM1		2
> > +#define CLK_UFSCFG_AO_REG_UNIPRO_SYS			3
> > +#define CLK_UFSCFG_AO_REG_U_SAP_CFG			4
> > +#define CLK_UFSCFG_AO_REG_U_PHY_TOP_AHB_S_BUS		5
> > +
> > +/* UFSCFG_PDN_REG */
> > +#define CLK_UFSCFG_REG_UFSHCI_UFS			0
> > +#define CLK_UFSCFG_REG_UFSHCI_AES			1
> > +#define CLK_UFSCFG_REG_UFSHCI_U_AHB			2
> > +#define CLK_UFSCFG_REG_UFSHCI_U_AXI			3
> > +
> > +/* IMP_IIC_WRAP_WS */
> > +#define CLK_IMPWS_I2C2					0
> > +
> > +/* IMP_IIC_WRAP_E */
> > +#define CLK_IMPE_I2C0					0
> > +#define CLK_IMPE_I2C1					1
> > +
> > +/* IMP_IIC_WRAP_S */
> > +#define CLK_IMPS_I2C3					0
> > +#define CLK_IMPS_I2C4					1
> > +#define CLK_IMPS_I2C5					2
> > +#define CLK_IMPS_I2C6					3
> > +
> > +/* IMP_IIC_WRAP_EN */
> > +#define CLK_IMPEN_I2C7					0
> > +#define CLK_IMPEN_I2C8					1
> > +
> > +/* MFG */
> > +#define CLK_MFG_BG3D					0
> > +
> > +/* DISPSYS_CONFIG */
> > +#define CLK_MM_DISP_OVL0_4L				0
> > +#define CLK_MM_DISP_OVL1_4L				1
> > +#define CLK_MM_VPP_RSZ0					2
> > +#define CLK_MM_VPP_RSZ1					3
> > +#define CLK_MM_DISP_RDMA0				4
> > +#define CLK_MM_DISP_RDMA1				5
> > +#define CLK_MM_DISP_COLOR0				6
> > +#define CLK_MM_DISP_COLOR1				7
> > +#define CLK_MM_DISP_CCORR0				8
> > +#define CLK_MM_DISP_CCORR1				9
> > +#define CLK_MM_DISP_CCORR2				10
> > +#define CLK_MM_DISP_CCORR3				11
> > +#define CLK_MM_DISP_AAL0				12
> > +#define CLK_MM_DISP_AAL1				13
> > +#define CLK_MM_DISP_GAMMA0				14
> > +#define CLK_MM_DISP_GAMMA1				15
> > +#define CLK_MM_DISP_DITHER0				16
> > +#define CLK_MM_DISP_DITHER1				17
> > +#define CLK_MM_DISP_DSC_WRAP0				18
> > +#define CLK_MM_VPP_MERGE0				19
> > +#define CLK_MMSYS_0_DISP_DVO				20
> > +#define CLK_MMSYS_0_DISP_DSI0				21
> > +#define CLK_MM_DP_INTF0					22
> > +#define CLK_MM_DPI0					23
> > +#define CLK_MM_DISP_WDMA0				24
> > +#define CLK_MM_DISP_WDMA1				25
> > +#define CLK_MM_DISP_FAKE_ENG0				26
> > +#define CLK_MM_DISP_FAKE_ENG1				27
> > +#define CLK_MM_SMI_LARB					28
> > +#define CLK_MM_DISP_MUTEX0				29
> > +#define CLK_MM_DIPSYS_CONFIG				30
> > +#define CLK_MM_DUMMY					31
> > +#define CLK_MMSYS_1_DISP_DSI0				32
> > +#define CLK_MMSYS_1_LVDS_ENCODER			33
> > +#define CLK_MMSYS_1_DPI0				34
> > +#define CLK_MMSYS_1_DISP_DVO				35
> > +#define CLK_MM_DP_INTF					36
> > +#define CLK_MMSYS_1_LVDS_ENCODER_CTS			37
> > +#define CLK_MMSYS_1_DISP_DVO_AVT			38
> > +
> > +/* IMGSYS1 */
> > +#define CLK_IMGSYS1_LARB9				0
> > +#define CLK_IMGSYS1_LARB11				1
> > +#define CLK_IMGSYS1_DIP					2
> > +#define CLK_IMGSYS1_GALS				3
> > +
> > +/* IMGSYS2 */
> > +#define CLK_IMGSYS2_LARB9				0
> > +#define CLK_IMGSYS2_LARB11				1
> > +#define CLK_IMGSYS2_MFB					2
> > +#define CLK_IMGSYS2_WPE					3
> > +#define CLK_IMGSYS2_MSS					4
> > +#define CLK_IMGSYS2_GALS				5
> > +
> > +/* VDEC_CORE */
> > +#define CLK_VDEC_CORE_LARB_CKEN				0
> > +#define CLK_VDEC_CORE_VDEC_CKEN				1
> > +#define CLK_VDEC_CORE_VDEC_ACTIVE			2
> > +
> > +/* VENC_GCON */
> > +#define CLK_VEN1_CKE0_LARB				0
> > +#define CLK_VEN1_CKE1_VENC				1
> > +#define CLK_VEN1_CKE2_JPGENC				2
> > +#define CLK_VEN1_CKE3_JPGDEC				3
> > +#define CLK_VEN1_CKE4_JPGDEC_C1				4
> > +#define CLK_VEN1_CKE5_GALS				5
> > +#define CLK_VEN1_CKE6_GALS_SRAM				6
> > +
> > +/* VLPCFG_REG */
> > +#define CLK_VLPCFG_REG_SCP				0
> > +#define CLK_VLPCFG_REG_RG_R_APXGPT_26M			1
> > +#define CLK_VLPCFG_REG_DPMSRCK_TEST			2
> > +#define CLK_VLPCFG_REG_RG_DPMSRRTC_TEST			3
> > +#define CLK_VLPCFG_REG_DPMSRULP_TEST			4
> > +#define CLK_VLPCFG_REG_SPMI_P_MST			5
> > +#define CLK_VLPCFG_REG_SPMI_P_MST_32K			6
> > +#define CLK_VLPCFG_REG_PMIF_SPMI_P_SYS			7
> > +#define CLK_VLPCFG_REG_PMIF_SPMI_P_TMR			8
> > +#define CLK_VLPCFG_REG_PMIF_SPMI_M_SYS			9
> > +#define CLK_VLPCFG_REG_PMIF_SPMI_M_TMR			10
> > +#define CLK_VLPCFG_REG_DVFSRC				11
> > +#define CLK_VLPCFG_REG_PWM_VLP				12
> > +#define CLK_VLPCFG_REG_SRCK				13
> > +#define CLK_VLPCFG_REG_SSPM_F26M			14
> > +#define CLK_VLPCFG_REG_SSPM_F32K			15
> > +#define CLK_VLPCFG_REG_SSPM_ULPOSC			16
> > +#define CLK_VLPCFG_REG_VLP_32K_COM			17
> > +#define CLK_VLPCFG_REG_VLP_26M_COM			18
> > +
> > +/* VLP_CKSYS */
> > +#define CLK_VLP_CK_SCP_SEL				0
> > +#define CLK_VLP_CK_PWRAP_ULPOSC_SEL			1
> > +#define CLK_VLP_CK_SPMI_P_MST_SEL			2
> > +#define CLK_VLP_CK_DVFSRC_SEL				3
> > +#define CLK_VLP_CK_PWM_VLP_SEL				4
> > +#define CLK_VLP_CK_AXI_VLP_SEL				5
> > +#define CLK_VLP_CK_SYSTIMER_26M_SEL			6
> > +#define CLK_VLP_CK_SSPM_SEL				7
> > +#define CLK_VLP_CK_SSPM_F26M_SEL			8
> > +#define CLK_VLP_CK_SRCK_SEL				9
> > +#define CLK_VLP_CK_SCP_SPI_SEL				10
> > +#define CLK_VLP_CK_SCP_IIC_SEL				11
> > +#define CLK_VLP_CK_SCP_SPI_HIGH_SPD_SEL			12
> > +#define CLK_VLP_CK_SCP_IIC_HIGH_SPD_SEL			13
> > +#define CLK_VLP_CK_SSPM_ULPOSC_SEL			14
> > +#define CLK_VLP_CK_APXGPT_26M_SEL			15
> > +#define CLK_VLP_CK_VADSP_SEL				16
> > +#define CLK_VLP_CK_VADSP_VOWPLL_SEL			17
> > +#define CLK_VLP_CK_VADSP_UARTHUB_BCLK_SEL		18
> > +#define CLK_VLP_CK_CAMTG0_SEL				19
> > +#define CLK_VLP_CK_CAMTG1_SEL				20
> > +#define CLK_VLP_CK_CAMTG2_SEL				21
> > +#define CLK_VLP_CK_AUD_ADC_SEL				22
> > +#define CLK_VLP_CK_KP_IRQ_GEN_SEL			23
> > +#define CLK_VLP_CK_VADSYS_VLP_26M_EN			24
> > +#define CLK_VLP_CK_SEJ_13M_EN				25
> > +#define CLK_VLP_CK_SEJ_26M_EN				26
> > +#define CLK_VLP_CK_FMIPI_CSI_UP26M_CK_EN		27
> > +
> > +/* SCP_IIC */
> > +#define CLK_SCP_IIC_I2C0_W1S				0
> > +#define CLK_SCP_IIC_I2C1_W1S				1
> > +
> > +/* SCP */
> > +#define CLK_SCP_SET_SPI0				0
> > +#define CLK_SCP_SET_SPI1				1
> > +
> > +/* CAMSYS_MAIN */
> > +#define CLK_CAM_M_LARB13				0
> > +#define CLK_CAM_M_LARB14				1
> > +#define CLK_CAM_M_CAMSYS_MAIN_CAM			2
> > +#define CLK_CAM_M_CAMSYS_MAIN_CAMTG			3
> > +#define CLK_CAM_M_SENINF				4
> > +#define CLK_CAM_M_CAMSV1				5
> > +#define CLK_CAM_M_CAMSV2				6
> > +#define CLK_CAM_M_CAMSV3				7
> > +#define CLK_CAM_M_FAKE_ENG				8
> > +#define CLK_CAM_M_CAM2MM_GALS				9
> > +#define CLK_CAM_M_CAMSV4				10
> > +#define CLK_CAM_M_PDA					11
> > +
> > +/* CAMSYS_RAWA */
> > +#define CLK_CAM_RA_CAMSYS_RAWA_LARBX			0
> > +#define CLK_CAM_RA_CAMSYS_RAWA_CAM			1
> > +#define CLK_CAM_RA_CAMSYS_RAWA_CAMTG			2
> > +
> > +/* CAMSYS_RAWB */
> > +#define CLK_CAM_RB_CAMSYS_RAWB_LARBX			0
> > +#define CLK_CAM_RB_CAMSYS_RAWB_CAM			1
> > +#define CLK_CAM_RB_CAMSYS_RAWB_CAMTG			2
> > +
> > +/* IPESYS */
> > +#define CLK_IPE_LARB19					0
> > +#define CLK_IPE_LARB20					1
> > +#define CLK_IPE_SMI_SUBCOM				2
> > +#define CLK_IPE_FD					3
> > +#define CLK_IPE_FE					4
> > +#define CLK_IPE_RSC					5
> > +#define CLK_IPESYS_GALS					6
> > +
> > +/* VLPCFG_AO_REG */
> > +#define CLK_VLPCFG_AO_APEINT_RX				0
> > +
> > +/* DVFSRC_TOP */
> > +#define CLK_DVFSRC_TOP_DVFSRC_EN			0
> > +
> > +/* MMINFRA_CONFIG */
> > +#define CLK_MMINFRA_GCE_D				0
> > +#define CLK_MMINFRA_GCE_M				1
> > +#define CLK_MMINFRA_SMI					2
> > +#define CLK_MMINFRA_GCE_26M				3
> > +
> > +/* GCE_D */
> > +#define CLK_GCE_D_TOP					0
> > +
> > +/* GCE_M */
> > +#define CLK_GCE_M_TOP					0
> > +
> > +/* MDPSYS_CONFIG */
> > +#define CLK_MDP_MUTEX0					0
> > +#define CLK_MDP_APB_BUS					1
> > +#define CLK_MDP_SMI0					2
> > +#define CLK_MDP_RDMA0					3
> > +#define CLK_MDP_RDMA2					4
> > +#define CLK_MDP_HDR0					5
> > +#define CLK_MDP_AAL0					6
> > +#define CLK_MDP_RSZ0					7
> > +#define CLK_MDP_TDSHP0					8
> > +#define CLK_MDP_COLOR0					9
> > +#define CLK_MDP_WROT0					10
> > +#define CLK_MDP_FAKE_ENG0				11
> > +#define CLK_MDPSYS_CONFIG				12
> > +#define CLK_MDP_RDMA1					13
> > +#define CLK_MDP_RDMA3					14
> > +#define CLK_MDP_HDR1					15
> > +#define CLK_MDP_AAL1					16
> > +#define CLK_MDP_RSZ1					17
> > +#define CLK_MDP_TDSHP1					18
> > +#define CLK_MDP_COLOR1					19
> > +#define CLK_MDP_WROT1					20
> > +#define CLK_MDP_RSZ2					21
> > +#define CLK_MDP_WROT2					22
> > +#define CLK_MDP_RSZ3					23
> > +#define CLK_MDP_WROT3					24
> > +#define CLK_MDP_BIRSZ0					25
> > +#define CLK_MDP_BIRSZ1					26
> > +
> > +/* DBGAO */
> > +#define CLK_DBGAO_ATB_EN				0
> > +
> > +/* DEM */
> > +#define CLK_DEM_ATB_EN					0
> > +#define CLK_DEM_BUSCLK_EN				1
> > +#define CLK_DEM_SYSCLK_EN				2
> > +
> > +#endif /* _DT_BINDINGS_CLK_MT8189_H */
> > -- 
> > 2.45.2
> > 


From c.parant at phytec.fr  Wed Dec 10 02:16:01 2025
From: c.parant at phytec.fr (Christophe Parant)
Date: Wed, 10 Dec 2025 11:16:01 +0100
Subject: [PATCH RESEND v2 01/11] ARM: dts: stm32: phycore-stm32mp15: Rename device tree files
In-Reply-To: <20251210101611.27008-1-c.parant@phytec.fr>
References: <20251210101611.27008-1-c.parant@phytec.fr>
Message-ID: <20251210101611.27008-2-c.parant@phytec.fr>

Rename "stm32mp157c-phycore-*" device tree for the following reasons:

- The name of the dts should match to the phyBOARD name and not the name
of the SoM ("phycore-stm32mp1-3" was initialy coming from the name of
the yocto machine from meta-phytec).
- PHYTEC manages different SoM configurations with different STM32MP15x
SoC versions, so common dtsi files starting with "stm32mp15xx-*" should
be used (as it is done for ST boards for example).
- Add "-rdk" as suffix (for "Rapid Development Kit") to match our others
phytec boards dts names (imx6, imx6ul,..).
- "model" property is updated to introduce the name "phyBOARD-Sargas".

Signed-off-by: Christophe Parant <c.parant at phytec.fr>
---
 arch/arm/boot/dts/st/Makefile                                 | 2 +-
 ...ore-stm32mp1-3.dts => stm32mp157c-phyboard-sargas-rdk.dts} | 4 ++--
 ...re-stm32mp15-som.dtsi => stm32mp15xx-phyboard-sargas.dtsi} | 3 ---
 3 files changed, 3 insertions(+), 6 deletions(-)
 rename arch/arm/boot/dts/st/{stm32mp157c-phycore-stm32mp1-3.dts => stm32mp157c-phyboard-sargas-rdk.dts} (89%)
 rename arch/arm/boot/dts/st/{stm32mp157c-phycore-stm32mp15-som.dtsi => stm32mp15xx-phyboard-sargas.dtsi} (99%)

diff --git a/arch/arm/boot/dts/st/Makefile b/arch/arm/boot/dts/st/Makefile
index cc9948b9870f..099199f3e5f3 100644
--- a/arch/arm/boot/dts/st/Makefile
+++ b/arch/arm/boot/dts/st/Makefile
@@ -71,7 +71,7 @@ dtb-$(CONFIG_ARCH_STM32) += \
 	stm32mp157c-lxa-tac-gen2.dtb \
 	stm32mp157c-odyssey.dtb \
 	stm32mp157c-osd32mp1-red.dtb \
-	stm32mp157c-phycore-stm32mp1-3.dtb \
+	stm32mp157c-phyboard-sargas-rdk.dtb \
 	stm32mp157c-ultra-fly-sbc.dtb
 dtb-$(CONFIG_ARCH_U8500) += \
 	ste-snowball.dtb \
diff --git a/arch/arm/boot/dts/st/stm32mp157c-phycore-stm32mp1-3.dts b/arch/arm/boot/dts/st/stm32mp157c-phyboard-sargas-rdk.dts
similarity index 89%
rename from arch/arm/boot/dts/st/stm32mp157c-phycore-stm32mp1-3.dts
rename to arch/arm/boot/dts/st/stm32mp157c-phyboard-sargas-rdk.dts
index 28d7203264ce..26995eb2a619 100644
--- a/arch/arm/boot/dts/st/stm32mp157c-phycore-stm32mp1-3.dts
+++ b/arch/arm/boot/dts/st/stm32mp157c-phyboard-sargas-rdk.dts
@@ -10,10 +10,10 @@
 #include "stm32mp157.dtsi"
 #include "stm32mp15xc.dtsi"
 #include "stm32mp15xxac-pinctrl.dtsi"
-#include "stm32mp157c-phycore-stm32mp15-som.dtsi"
+#include "stm32mp15xx-phyboard-sargas.dtsi"
 
 / {
-	model = "PHYTEC phyCORE-STM32MP1-3 Dev Board";
+	model = "PHYTEC phyBOARD-Sargas STM32MP157C";
 	compatible = "phytec,phycore-stm32mp1-3",
 		     "phytec,phycore-stm32mp157c-som", "st,stm32mp157";
 
diff --git a/arch/arm/boot/dts/st/stm32mp157c-phycore-stm32mp15-som.dtsi b/arch/arm/boot/dts/st/stm32mp15xx-phyboard-sargas.dtsi
similarity index 99%
rename from arch/arm/boot/dts/st/stm32mp157c-phycore-stm32mp15-som.dtsi
rename to arch/arm/boot/dts/st/stm32mp15xx-phyboard-sargas.dtsi
index bf0c32027baf..ebbb82c09a1e 100644
--- a/arch/arm/boot/dts/st/stm32mp157c-phycore-stm32mp15-som.dtsi
+++ b/arch/arm/boot/dts/st/stm32mp15xx-phyboard-sargas.dtsi
@@ -16,9 +16,6 @@
 #include "stm32mp15-pinctrl.dtsi"
 
 / {
-	model = "PHYTEC phyCORE-STM32MP15 SOM";
-	compatible = "phytec,phycore-stm32mp157c-som", "st,stm32mp157";
-
 	aliases {
 		ethernet0 = &ethernet0;
 		rtc0 = &i2c4_rtc;
-- 
2.34.1



From c.parant at phytec.fr  Wed Dec 10 02:16:00 2025
From: c.parant at phytec.fr (Christophe Parant)
Date: Wed, 10 Dec 2025 11:16:00 +0100
Subject: [PATCH RESEND v2 00/11] Rework and fix STM32MP15x PHYTEC dts
Message-ID: <20251210101611.27008-1-c.parant@phytec.fr>

This patch series rename and reorganize the STM32MP15x PHYTEC
baseboard (phyBOARD-Sargas) and SoM (phyCORE-STM32MP15x) device tree
files.
Indeed, the current device tree naming and organization is not really
consistent as it does not align with others STM32MP boards (use common
dtsi file as much as possible, use one dtsi for SoM and one dtsi for
baseboard).

The series also fixes some important pinctrl issues and minor one (coding
style). Additional pinctrl is also added for the optionnal interfaces
that are not enabled by default (FMC, LTDC, DCMI, PWM).

Changes in v2:
- Rebase on v6.16-rc5
- Rework Patch 3 (stm32.yaml): for board description, keep "compatible"
string identifiers as before to not break ABI. But use "enum" type
instead of "const" for the SoM and phyBOARD indentifiers.

Christophe Parant (11):
  ARM: dts: stm32: phycore-stm32mp15: Rename device tree files
  ARM: dts: stm32: phyboard-sargas: Introduce SoM device tree
  dt-bindings: arm: stm32: Modify STM32MP15x Phytec board items types
  ARM: dts: stm32: Add new pinmux groups for phyboard-sargas and phycore
  ARM: dts: stm32: phyboard-sargas: Fix uart4 and sai2 pinctrl
  ARM: dts: stm32: phycore-stm32mp15: qspi: Fix memory map and pinctrl
  ARM: dts: stm32: phycore-stm32mp15: Add dummy memory-node
  ARM: dts: stm32: phyboard-sargas: Move aliases from dts to dtsi
  ARM: dts: stm32: phycore-stm32mp15: Disable optional SoM peripherals
  ARM: dts: stm32: phyboard-sargas and phycore: Fix coding style issues
  ARM: dts: stm32: phyboard-sargas and phycore: Add optional interfaces

 .../devicetree/bindings/arm/stm32/stm32.yaml  |   8 +-
 arch/arm/boot/dts/st/Makefile                 |   2 +-
 arch/arm/boot/dts/st/stm32mp15-pinctrl.dtsi   | 164 +++++++++
 ...ts => stm32mp157c-phyboard-sargas-rdk.dts} |  24 +-
 .../dts/st/stm32mp15xx-phyboard-sargas.dtsi   | 285 +++++++++++++++
 ...-som.dtsi => stm32mp15xx-phycore-som.dtsi} | 344 ++++--------------
 6 files changed, 525 insertions(+), 302 deletions(-)
 rename arch/arm/boot/dts/st/{stm32mp157c-phycore-stm32mp1-3.dts => stm32mp157c-phyboard-sargas-rdk.dts} (58%)
 create mode 100644 arch/arm/boot/dts/st/stm32mp15xx-phyboard-sargas.dtsi
 rename arch/arm/boot/dts/st/{stm32mp157c-phycore-stm32mp15-som.dtsi => stm32mp15xx-phycore-som.dtsi} (53%)

-- 
2.34.1



From c.parant at phytec.fr  Wed Dec 10 02:16:04 2025
From: c.parant at phytec.fr (Christophe Parant)
Date: Wed, 10 Dec 2025 11:16:04 +0100
Subject: [PATCH RESEND v2 04/11] ARM: dts: stm32: Add new pinmux groups for phyboard-sargas and phycore
In-Reply-To: <20251210101611.27008-1-c.parant@phytec.fr>
References: <20251210101611.27008-1-c.parant@phytec.fr>
Message-ID: <20251210101611.27008-5-c.parant@phytec.fr>

Add add alternate pinmux for following interfaces used on
phyBOARD-Sargas:
- UART4
- LTDC
- DCMI
- TIM5
- SAI2

Fix "ethernet0_rgmii_pins_d" pinmux used on phyCORE-STM32MP15x:
ETH_RGMII_GTX_CLK pin was missing.

Signed-off-by: Christophe Parant <c.parant at phytec.fr>
---
 arch/arm/boot/dts/st/stm32mp15-pinctrl.dtsi | 164 ++++++++++++++++++++
 1 file changed, 164 insertions(+)

diff --git a/arch/arm/boot/dts/st/stm32mp15-pinctrl.dtsi b/arch/arm/boot/dts/st/stm32mp15-pinctrl.dtsi
index 40605ea85ee1..f242959e8716 100644
--- a/arch/arm/boot/dts/st/stm32mp15-pinctrl.dtsi
+++ b/arch/arm/boot/dts/st/stm32mp15-pinctrl.dtsi
@@ -223,6 +223,45 @@ pins {
 		};
 	};
 
+	/omit-if-no-ref/
+	dcmi_pins_d: dcmi-3 {
+		pins {
+			pinmux = <STM32_PINMUX('H', 8,  AF13)>,/* DCMI_HSYNC */
+				 <STM32_PINMUX('B', 7,  AF13)>,/* DCMI_VSYNC */
+				 <STM32_PINMUX('A', 6,  AF13)>,/* DCMI_PIXCLK */
+				 <STM32_PINMUX('H', 9,  AF13)>,/* DCMI_D0 */
+				 <STM32_PINMUX('C', 7,  AF13)>,/* DCMI_D1 */
+				 <STM32_PINMUX('E', 0,  AF13)>,/* DCMI_D2 */
+				 <STM32_PINMUX('E', 1,  AF13)>,/* DCMI_D3 */
+				 <STM32_PINMUX('H', 14, AF13)>,/* DCMI_D4 */
+				 <STM32_PINMUX('I', 4,  AF13)>,/* DCMI_D5 */
+				 <STM32_PINMUX('E', 5,  AF13)>,/* DCMI_D6 */
+				 <STM32_PINMUX('I', 7,  AF13)>,/* DCMI_D7 */
+				 <STM32_PINMUX('I', 1,  AF13)>,/* DCMI_D8 */
+				 <STM32_PINMUX('H', 7,  AF13)>;/* DCMI_D9 */
+			bias-disable;
+		};
+	};
+
+	/omit-if-no-ref/
+	dcmi_sleep_pins_d: dcmi-sleep-3 {
+		pins {
+			pinmux = <STM32_PINMUX('H', 8,  ANALOG)>,/* DCMI_HSYNC */
+				 <STM32_PINMUX('B', 7,  ANALOG)>,/* DCMI_VSYNC */
+				 <STM32_PINMUX('A', 6,  ANALOG)>,/* DCMI_PIXCLK */
+				 <STM32_PINMUX('H', 9,  ANALOG)>,/* DCMI_D0 */
+				 <STM32_PINMUX('C', 7,  ANALOG)>,/* DCMI_D1 */
+				 <STM32_PINMUX('E', 0,  ANALOG)>,/* DCMI_D2 */
+				 <STM32_PINMUX('E', 1,  ANALOG)>,/* DCMI_D3 */
+				 <STM32_PINMUX('H', 14, ANALOG)>,/* DCMI_D4 */
+				 <STM32_PINMUX('I', 4,  ANALOG)>,/* DCMI_D5 */
+				 <STM32_PINMUX('E', 5,  ANALOG)>,/* DCMI_D6 */
+				 <STM32_PINMUX('I', 7,  ANALOG)>,/* DCMI_D7 */
+				 <STM32_PINMUX('I', 1,  ANALOG)>,/* DCMI_D8 */
+				 <STM32_PINMUX('H', 7,  ANALOG)>;/* DCMI_D9 */
+		};
+	};
+
 	/omit-if-no-ref/
 	ethernet0_rgmii_pins_a: rgmii-0 {
 		pins1 {
@@ -386,6 +425,7 @@ pins1 {
 	ethernet0_rgmii_pins_d: rgmii-3 {
 		pins1 {
 			pinmux = <STM32_PINMUX('G', 5, AF11)>, /* ETH_RGMII_CLK125 */
+				 <STM32_PINMUX('G', 4, AF11)>, /* ETH_RGMII_GTX_CLK */
 				 <STM32_PINMUX('G', 13, AF11)>,	/* ETH_RGMII_TXD0 */
 				 <STM32_PINMUX('G', 14, AF11)>,	/* ETH_RGMII_TXD1 */
 				 <STM32_PINMUX('C', 2, AF11)>, /* ETH_RGMII_TXD2 */
@@ -1304,6 +1344,65 @@ pins {
 		};
 	};
 
+	/omit-if-no-ref/
+	ltdc_pins_f: ltdc-5 {
+		pins {
+			pinmux = <STM32_PINMUX('G', 7,  AF14)>, /* LCD_CLK */
+				 <STM32_PINMUX('I', 10, AF14)>, /* LCD_HSYNC */
+				 <STM32_PINMUX('I', 9,  AF14)>, /* LCD_VSYNC */
+				 <STM32_PINMUX('E', 13, AF14)>, /* LCD_DE */
+				 <STM32_PINMUX('C', 10, AF14)>, /* LCD_R2 */
+				 <STM32_PINMUX('B', 0,   AF9)>, /* LCD_R3 */
+				 <STM32_PINMUX('H', 10, AF14)>, /* LCD_R4 */
+				 <STM32_PINMUX('H', 11, AF14)>, /* LCD_R5 */
+				 <STM32_PINMUX('H', 12, AF14)>, /* LCD_R6 */
+				 <STM32_PINMUX('E', 15, AF14)>, /* LCD_R7 */
+				 <STM32_PINMUX('H', 13, AF14)>, /* LCD_G2 */
+				 <STM32_PINMUX('E', 11, AF14)>, /* LCD_G3 */
+				 <STM32_PINMUX('H', 15, AF14)>, /* LCD_G4 */
+				 <STM32_PINMUX('H', 4,   AF9)>, /* LCD_G5 */
+				 <STM32_PINMUX('I', 11,  AF9)>, /* LCD_G6 */
+				 <STM32_PINMUX('I', 2,  AF14)>, /* LCD_G7 */
+				 <STM32_PINMUX('G', 10, AF14)>, /* LCD_B2 */
+				 <STM32_PINMUX('G', 11, AF14)>, /* LCD_B3 */
+				 <STM32_PINMUX('E', 12, AF14)>, /* LCD_B4 */
+				 <STM32_PINMUX('I', 5,  AF14)>, /* LCD_B5 */
+				 <STM32_PINMUX('B', 8,  AF14)>, /* LCD_B6 */
+				 <STM32_PINMUX('D', 8,  AF14)>; /* LCD_B7 */
+			bias-disable;
+			drive-push-pull;
+			slew-rate = <1>;
+		};
+	};
+
+	/omit-if-no-ref/
+	ltdc_sleep_pins_f: ltdc-sleep-5 {
+		pins {
+			pinmux = <STM32_PINMUX('G', 7,  ANALOG)>, /* LCD_CLK */
+				 <STM32_PINMUX('I', 10, ANALOG)>, /* LCD_HSYNC */
+				 <STM32_PINMUX('I', 9,  ANALOG)>, /* LCD_VSYNC */
+				 <STM32_PINMUX('E', 13, ANALOG)>, /* LCD_DE */
+				 <STM32_PINMUX('C', 10, ANALOG)>, /* LCD_R2 */
+				 <STM32_PINMUX('B', 0,  ANALOG)>, /* LCD_R3 */
+				 <STM32_PINMUX('H', 10, ANALOG)>, /* LCD_R4 */
+				 <STM32_PINMUX('H', 11, ANALOG)>, /* LCD_R5 */
+				 <STM32_PINMUX('H', 12, ANALOG)>, /* LCD_R6 */
+				 <STM32_PINMUX('E', 15, ANALOG)>, /* LCD_R7 */
+				 <STM32_PINMUX('H', 13, ANALOG)>, /* LCD_G2 */
+				 <STM32_PINMUX('E', 11, ANALOG)>, /* LCD_G3 */
+				 <STM32_PINMUX('H', 15, ANALOG)>, /* LCD_G4 */
+				 <STM32_PINMUX('H', 4,  ANALOG)>, /* LCD_G5 */
+				 <STM32_PINMUX('I', 11, ANALOG)>, /* LCD_G6 */
+				 <STM32_PINMUX('I', 2,  ANALOG)>, /* LCD_G7 */
+				 <STM32_PINMUX('G', 10, ANALOG)>, /* LCD_B2 */
+				 <STM32_PINMUX('G', 11, ANALOG)>, /* LCD_B3 */
+				 <STM32_PINMUX('E', 12, ANALOG)>, /* LCD_B4 */
+				 <STM32_PINMUX('I', 5,  ANALOG)>, /* LCD_B5 */
+				 <STM32_PINMUX('B', 8,  ANALOG)>, /* LCD_B6 */
+				 <STM32_PINMUX('D', 8,  ANALOG)>; /* LCD_B7 */
+		};
+	};
+
 	/omit-if-no-ref/
 	mco1_pins_a: mco1-0 {
 		pins {
@@ -1644,6 +1743,23 @@ pins {
 		};
 	};
 
+	/omit-if-no-ref/
+	pwm5_pins_c: pwm5-2 {
+		pins {
+			pinmux = <STM32_PINMUX('I', 0, AF2)>; /* TIM5_CH4 */
+			bias-pull-down;
+			drive-push-pull;
+			slew-rate = <0>;
+		};
+	};
+
+	/omit-if-no-ref/
+	pwm5_sleep_pins_c: pwm5-sleep-2 {
+		pins {
+			pinmux = <STM32_PINMUX('I', 0, ANALOG)>; /* TIM5_CH4 */
+		};
+	};
+
 	/omit-if-no-ref/
 	pwm8_pins_a: pwm8-0 {
 		pins {
@@ -1869,6 +1985,21 @@ pins {
 		};
 	};
 
+	/omit-if-no-ref/
+	sai2a_pins_d: sai2a-3 {
+		pins {
+			pinmux = <STM32_PINMUX('I', 6, AF10)>; /* SAI2_SD_A */
+			bias-disable;
+		};
+	};
+
+	/omit-if-no-ref/
+	sai2a_sleep_pins_d: sai2a-3 {
+		pins {
+			pinmux = <STM32_PINMUX('I', 6, ANALOG)>; /* SAI2_SD_A */
+		};
+	};
+
 	/omit-if-no-ref/
 	sai2b_pins_a: sai2b-0 {
 		pins1 {
@@ -2856,6 +2987,39 @@ pins {
 		};
 	};
 
+	/omit-if-no-ref/
+	uart4_pins_f: uart4-5 {
+		pins1 {
+			pinmux = <STM32_PINMUX('B', 9, AF8)>; /* UART4_TX */
+			bias-disable;
+			drive-push-pull;
+			slew-rate = <0>;
+		};
+		pins2 {
+			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+			bias-disable;
+		};
+	};
+
+	/omit-if-no-ref/
+	uart4_idle_pins_f: uart4-idle-5 {
+		pins1 {
+			pinmux = <STM32_PINMUX('B', 9, ANALOG)>; /* UART4_TX */
+		};
+		pins2 {
+			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+			bias-disable;
+		};
+	};
+
+	/omit-if-no-ref/
+	uart4_sleep_pins_f: uart4-sleep-5 {
+		pins {
+			pinmux = <STM32_PINMUX('B', 9, ANALOG)>, /* UART4_TX */
+				 <STM32_PINMUX('B', 2, ANALOG)>; /* UART4_RX */
+		};
+	};
+
 	/omit-if-no-ref/
 	uart5_pins_a: uart5-0 {
 		pins1 {
-- 
2.34.1



From c.parant at phytec.fr  Wed Dec 10 02:16:05 2025
From: c.parant at phytec.fr (Christophe Parant)
Date: Wed, 10 Dec 2025 11:16:05 +0100
Subject: [PATCH RESEND v2 05/11] ARM: dts: stm32: phyboard-sargas: Fix uart4 and sai2 pinctrl
In-Reply-To: <20251210101611.27008-1-c.parant@phytec.fr>
References: <20251210101611.27008-1-c.parant@phytec.fr>
Message-ID: <20251210101611.27008-6-c.parant@phytec.fr>

- UART4:
  "uart4_pins_a" pinmux option does not apply here, as PB9 should be
  used for UART4_TX instead of PG11 (PG11 is LCD_B3 on Sargas).
  Use "uart4_pins_f" instead.
  Also remove "pinctrl-3" which is useless (identical to "pinctrl-1").

- SAI2 A:
  "sai2a_pins_b" pinmux option does not apply here, as only PI6 is used
  for SAI2 A ("SAI2_SD_A"). Other pins of this group (PI7 and PD13) are
  not used for audio.
  Use "sai2a_sleep_pins_d" instead.

Signed-off-by: Christophe Parant <c.parant at phytec.fr>
---
 arch/arm/boot/dts/st/stm32mp15xx-phyboard-sargas.dtsi | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/arch/arm/boot/dts/st/stm32mp15xx-phyboard-sargas.dtsi b/arch/arm/boot/dts/st/stm32mp15xx-phyboard-sargas.dtsi
index 2fdab99fc562..44f3aa1ddebf 100644
--- a/arch/arm/boot/dts/st/stm32mp15xx-phyboard-sargas.dtsi
+++ b/arch/arm/boot/dts/st/stm32mp15xx-phyboard-sargas.dtsi
@@ -143,8 +143,8 @@ &sai2 {
 	clocks = <&rcc SAI2>, <&rcc PLL3_Q>, <&rcc PLL3_R>;
 	clock-names = "pclk", "x8k", "x11k";
 	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&sai2a_pins_b>, <&sai2b_pins_d>;
-	pinctrl-1 = <&sai2a_sleep_pins_b>, <&sai2b_sleep_pins_d>;
+	pinctrl-0 = <&sai2a_pins_d>, <&sai2b_pins_d>;
+	pinctrl-1 = <&sai2a_sleep_pins_d>, <&sai2b_sleep_pins_d>;
 	status = "okay";
 };
 
@@ -202,10 +202,9 @@ &spi1 {
 
 &uart4 {
 	pinctrl-names = "default", "sleep", "idle";
-	pinctrl-0 = <&uart4_pins_a>;
-	pinctrl-1 = <&uart4_sleep_pins_a>;
-	pinctrl-2 = <&uart4_idle_pins_a>;
-	pinctrl-3 = <&uart4_pins_a>;
+	pinctrl-0 = <&uart4_pins_f>;
+	pinctrl-1 = <&uart4_sleep_pins_f>;
+	pinctrl-2 = <&uart4_idle_pins_f>;
 	/delete-property/dmas;
 	/delete-property/dma-names;
 	status = "okay";
-- 
2.34.1



From c.parant at phytec.fr  Wed Dec 10 02:16:03 2025
From: c.parant at phytec.fr (Christophe Parant)
Date: Wed, 10 Dec 2025 11:16:03 +0100
Subject: [PATCH RESEND v2 03/11] dt-bindings: arm: stm32: Modify STM32MP15x Phytec board items types
In-Reply-To: <20251210101611.27008-1-c.parant@phytec.fr>
References: <20251210101611.27008-1-c.parant@phytec.fr>
Message-ID: <20251210101611.27008-4-c.parant@phytec.fr>

As Phytec manages different SoM configurations with different STM32MP15
SoC versions, modify the phyBOARD and SoM compatible items to "enum"
instead of "const".
The description concerns PHYTEC SoM equipped with STM32MP157
("st,stm32mp157" is "const").
Also add comments in front of the enum items to be able to identify the
compatible string with the phyBOARD/phyCORE names.

Signed-off-by: Christophe Parant <c.parant at phytec.fr>
---
 Documentation/devicetree/bindings/arm/stm32/stm32.yaml | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/stm32/stm32.yaml b/Documentation/devicetree/bindings/arm/stm32/stm32.yaml
index 408532504a24..fbd3d364c1f7 100644
--- a/Documentation/devicetree/bindings/arm/stm32/stm32.yaml
+++ b/Documentation/devicetree/bindings/arm/stm32/stm32.yaml
@@ -182,10 +182,12 @@ properties:
           - const: seeed,stm32mp157c-odyssey-som
           - const: st,stm32mp157
 
-      - description: Phytec STM32MP1 SoM based Boards
+      - description: Phytec STM32MP157 SoM based Boards
         items:
-          - const: phytec,phycore-stm32mp1-3
-          - const: phytec,phycore-stm32mp157c-som
+          - enum:
+              - phytec,phycore-stm32mp1-3 # phyBOARD-Sargas with phyCORE-STM32MP157C SoM
+          - enum:
+              - phytec,phycore-stm32mp157c-som # phyCORE-STM32MP157C SoM
           - const: st,stm32mp157
 
       - description: Ultratronik STM32MP1 SBC based Boards
-- 
2.34.1



From c.parant at phytec.fr  Wed Dec 10 02:16:06 2025
From: c.parant at phytec.fr (Christophe Parant)
Date: Wed, 10 Dec 2025 11:16:06 +0100
Subject: [PATCH RESEND v2 06/11] ARM: dts: stm32: phycore-stm32mp15: qspi: Fix memory map and pinctrl
In-Reply-To: <20251210101611.27008-1-c.parant@phytec.fr>
References: <20251210101611.27008-1-c.parant@phytec.fr>
Message-ID: <20251210101611.27008-7-c.parant@phytec.fr>

- Add missing chip select pin group in pinctrl.
- Overwrite the memory map to the Flash device size (16MB) is necessary
to avoid waste of virtual memory that will not be used.
Without this modification, qspi probe fails because of ioremap error.

Signed-off-by: Christophe Parant <c.parant at phytec.fr>
---
 arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi b/arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi
index 660cdc260963..72926c3de52c 100644
--- a/arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi
+++ b/arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi
@@ -290,8 +290,14 @@ &pwr_regulators {
 
 &qspi {
 	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&qspi_clk_pins_a &qspi_bk1_pins_a>;
-	pinctrl-1 = <&qspi_clk_sleep_pins_a &qspi_bk1_sleep_pins_a>;
+	pinctrl-0 = <&qspi_clk_pins_a
+		     &qspi_bk1_pins_a
+		     &qspi_cs1_pins_a>;
+	pinctrl-1 = <&qspi_clk_sleep_pins_a
+		     &qspi_bk1_sleep_pins_a
+		     &qspi_cs1_sleep_pins_a>;
+	reg = <0x58003000 0x1000>,
+	      <0x70000000 0x1000000>;
 	status = "okay";
 
 	flash0: flash at 0 {
-- 
2.34.1



From c.parant at phytec.fr  Wed Dec 10 02:16:07 2025
From: c.parant at phytec.fr (Christophe Parant)
Date: Wed, 10 Dec 2025 11:16:07 +0100
Subject: [PATCH RESEND v2 07/11] ARM: dts: stm32: phycore-stm32mp15: Add dummy memory-node
In-Reply-To: <20251210101611.27008-1-c.parant@phytec.fr>
References: <20251210101611.27008-1-c.parant@phytec.fr>
Message-ID: <20251210101611.27008-8-c.parant@phytec.fr>

"memory" node is not necessary as the bootloader is taking care of
passing the correct DDR size.
However keep a dummy memory node with the minimum DDR size (512MB) with
comment explaining that.

Signed-off-by: Christophe Parant <c.parant at phytec.fr>
---
 arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi b/arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi
index 72926c3de52c..ce859b94ae26 100644
--- a/arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi
+++ b/arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi
@@ -22,6 +22,15 @@ aliases {
 		rtc1 = &rtc;
 	};
 
+	/*
+	 * Set the minimum memory size here and
+	 * let the bootloader set the real size.
+	 */
+	memory at c0000000 {
+		device_type = "memory";
+		reg = <0xc0000000 0x20000000>;
+	};
+
 	reserved-memory {
 		#address-cells = <1>;
 		#size-cells = <1>;
-- 
2.34.1



From c.parant at phytec.fr  Wed Dec 10 02:16:09 2025
From: c.parant at phytec.fr (Christophe Parant)
Date: Wed, 10 Dec 2025 11:16:09 +0100
Subject: [PATCH RESEND v2 09/11] ARM: dts: stm32: phycore-stm32mp15: Disable optional SoM peripherals
In-Reply-To: <20251210101611.27008-1-c.parant@phytec.fr>
References: <20251210101611.27008-1-c.parant@phytec.fr>
Message-ID: <20251210101611.27008-10-c.parant@phytec.fr>

Following peripherals are optional on phyCORE-STM32MP15x following
PHYTEC standard SoM variants: external RTC, EEPROM, SPI NOR.
Also NAND (fmc) can be populated instead of eMMC (sdmmc2).

So disable those peripherals on SoM dtsi file and enable them on board
dts file.
Additionally, enable by default the "DTS" SoC IP on common SoM dtsi file
as it is not an optional IP in STM32MP15x SoC.

Signed-off-by: Christophe Parant <c.parant at phytec.fr>
---
 arch/arm/boot/dts/st/stm32mp157c-phyboard-sargas-rdk.dts | 8 --------
 arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi        | 9 ++++++++-
 2 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/arch/arm/boot/dts/st/stm32mp157c-phyboard-sargas-rdk.dts b/arch/arm/boot/dts/st/stm32mp157c-phyboard-sargas-rdk.dts
index f7c02a381304..c90b12a479c9 100644
--- a/arch/arm/boot/dts/st/stm32mp157c-phyboard-sargas-rdk.dts
+++ b/arch/arm/boot/dts/st/stm32mp157c-phyboard-sargas-rdk.dts
@@ -22,14 +22,6 @@ &cryp1 {
 	status = "okay";
 };
 
-&dts {
-	status = "okay";
-};
-
-&fmc {
-	status = "disabled";
-};
-
 &gpu {
 	status = "okay";
 };
diff --git a/arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi b/arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi
index ce859b94ae26..3f60f184978c 100644
--- a/arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi
+++ b/arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi
@@ -265,11 +265,13 @@ i2c4_eeprom: eeprom at 50 {
 		compatible = "microchip,24c32",
 			     "atmel,24c32";
 		reg = <0x50>;
+		status = "disabled";
 	};
 
 	i2c4_rtc: rtc at 52 {
 		compatible = "microcrystal,rv3028";
 		reg = <0x52>;
+		status = "disabled";
 	};
 };
 
@@ -307,7 +309,7 @@ &qspi_bk1_sleep_pins_a
 		     &qspi_cs1_sleep_pins_a>;
 	reg = <0x58003000 0x1000>,
 	      <0x70000000 0x1000000>;
-	status = "okay";
+	status = "disabled";
 
 	flash0: flash at 0 {
 		compatible = "winbond,w25q128", "jedec,spi-nor";
@@ -328,6 +330,10 @@ &rtc {
 	status = "okay";
 };
 
+&dts {
+	status = "okay";
+};
+
 &sdmmc2 {
 	pinctrl-names = "default", "opendrain", "sleep";
 	pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_e>;
@@ -341,4 +347,5 @@ &sdmmc2 {
 	vmmc-supply = <&v3v3>;
 	vqmmc-supply = <&v3v3>;
 	mmc-ddr-3_3v;
+	status = "disabled";
 };
-- 
2.34.1



From c.parant at phytec.fr  Wed Dec 10 02:16:02 2025
From: c.parant at phytec.fr (Christophe Parant)
Date: Wed, 10 Dec 2025 11:16:02 +0100
Subject: [PATCH RESEND v2 02/11] ARM: dts: stm32: phyboard-sargas: Introduce SoM device tree
In-Reply-To: <20251210101611.27008-1-c.parant@phytec.fr>
References: <20251210101611.27008-1-c.parant@phytec.fr>
Message-ID: <20251210101611.27008-3-c.parant@phytec.fr>

Add stm32mp15xx-phycore-som.dtsi device tree file to split hardware
features between the phyBOARD (baseboard) and the phyCORE (SoM).

Signed-off-by: Christophe Parant <c.parant at phytec.fr>
---
 .../st/stm32mp157c-phyboard-sargas-rdk.dts    |   2 +-
 .../dts/st/stm32mp15xx-phyboard-sargas.dtsi   | 317 +----------------
 .../boot/dts/st/stm32mp15xx-phycore-som.dtsi  | 329 ++++++++++++++++++
 3 files changed, 331 insertions(+), 317 deletions(-)
 create mode 100644 arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi

diff --git a/arch/arm/boot/dts/st/stm32mp157c-phyboard-sargas-rdk.dts b/arch/arm/boot/dts/st/stm32mp157c-phyboard-sargas-rdk.dts
index 26995eb2a619..48adc3462958 100644
--- a/arch/arm/boot/dts/st/stm32mp157c-phyboard-sargas-rdk.dts
+++ b/arch/arm/boot/dts/st/stm32mp157c-phyboard-sargas-rdk.dts
@@ -9,7 +9,7 @@
 #include <dt-bindings/pinctrl/stm32-pinfunc.h>
 #include "stm32mp157.dtsi"
 #include "stm32mp15xc.dtsi"
-#include "stm32mp15xxac-pinctrl.dtsi"
+#include "stm32mp15xx-phycore-som.dtsi"
 #include "stm32mp15xx-phyboard-sargas.dtsi"
 
 / {
diff --git a/arch/arm/boot/dts/st/stm32mp15xx-phyboard-sargas.dtsi b/arch/arm/boot/dts/st/stm32mp15xx-phyboard-sargas.dtsi
index ebbb82c09a1e..2fdab99fc562 100644
--- a/arch/arm/boot/dts/st/stm32mp15xx-phyboard-sargas.dtsi
+++ b/arch/arm/boot/dts/st/stm32mp15xx-phyboard-sargas.dtsi
@@ -5,23 +5,13 @@
  * Author: Dom VOVARD <dom.vovard at linrt.com>.
  */
 
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/input/input.h>
+
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/leds/common.h>
 #include <dt-bindings/leds/leds-pca9532.h>
-#include <dt-bindings/mfd/st,stpmic1.h>
-#include <dt-bindings/net/ti-dp83867.h>
-#include "stm32mp15-pinctrl.dtsi"
 
 / {
-	aliases {
-		ethernet0 = &ethernet0;
-		rtc0 = &i2c4_rtc;
-		rtc1 = &rtc;
-	};
-
 	chosen {
 		stdout-path = "serial0:115200n8";
 	};
@@ -42,48 +32,6 @@ key-enter {
 		};
 	};
 
-	reserved-memory {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		retram: retram at 38000000 {
-			compatible = "shared-dma-pool";
-			reg = <0x38000000 0x10000>;
-			no-map;
-		};
-
-		mcuram: mcuram at 30000000 {
-			compatible = "shared-dma-pool";
-			reg = <0x30000000 0x40000>;
-			no-map;
-		};
-
-		mcuram2: mcuram2 at 10000000 {
-			compatible = "shared-dma-pool";
-			reg = <0x10000000 0x40000>;
-			no-map;
-		};
-
-		vdev0vring0: vdev0vring0 at 10040000 {
-			compatible = "shared-dma-pool";
-			reg = <0x10040000 0x1000>;
-			no-map;
-		};
-
-		vdev0vring1: vdev0vring1 at 10041000 {
-			compatible = "shared-dma-pool";
-			reg = <0x10041000 0x1000>;
-			no-map;
-		};
-
-		vdev0buffer: vdev0buffer at 10042000 {
-			compatible = "shared-dma-pool";
-			reg = <0x10042000 0x4000>;
-			no-map;
-		};
-	};
-
 	sound {
 		compatible = "audio-graph-card";
 		label = "STM32MP1-PHYCORE";
@@ -93,44 +41,6 @@ sound {
 		dais = <&sai2b_port>,
 		       <&sai2a_port>;
 	};
-
-	regulator_vin: regulator {
-		compatible = "regulator-fixed";
-		regulator-name = "vin";
-		regulator-min-microvolt = <5000000>;
-		regulator-max-microvolt = <5000000>;
-		regulator-always-on;
-	};
-};
-
-&ethernet0 {
-	pinctrl-0 = <&ethernet0_rgmii_pins_d>;
-	pinctrl-1 = <&ethernet0_rgmii_sleep_pins_d>;
-	pinctrl-names = "default", "sleep";
-	phy-mode = "rgmii-id";
-	max-speed = <1000>;
-	phy-handle = <&phy0>;
-	st,eth-clk-sel;
-	status = "okay";
-
-	mdio {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "snps,dwmac-mdio";
-
-		phy0: ethernet-phy at 1 {
-			compatible = "ethernet-phy-ieee802.3-c22";
-			reg = <1>;
-			interrupt-parent = <&gpiog>;
-			interrupts = <12 IRQ_TYPE_EDGE_FALLING>;
-			ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
-			ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
-			ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
-			ti,min-output-impedance;
-			enet-phy-lane-no-swap;
-			ti,clk-output-sel = <DP83867_CLK_O_SEL_OFF>;
-		};
-	};
 };
 
 &i2c1 {
@@ -222,176 +132,6 @@ led-2 {
 	};
 };
 
-&i2c4 {
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&i2c4_pins_a>;
-	pinctrl-1 = <&i2c4_sleep_pins_a>;
-	i2c-scl-rising-time-ns = <185>;
-	i2c-scl-falling-time-ns = <20>;
-	status = "okay";
-
-	pmic at 33 {
-		compatible = "st,stpmic1";
-		reg = <0x33>;
-		interrupts-extended = <&gpioa 0 IRQ_TYPE_EDGE_FALLING>;
-		interrupt-controller;
-		#interrupt-cells = <2>;
-
-		regulators {
-			compatible = "st,stpmic1-regulators";
-			buck1-supply = <&regulator_vin>;
-			buck2-supply = <&regulator_vin>;
-			buck3-supply = <&regulator_vin>;
-			buck4-supply = <&regulator_vin>;
-			ldo1-supply = <&v3v3>;
-			ldo2-supply = <&v3v3>;
-			ldo3-supply = <&vdd_ddr>;
-			ldo4-supply = <&regulator_vin>;
-			ldo5-supply = <&v3v3>;
-			ldo6-supply = <&v3v3>;
-			boost-supply = <&regulator_vin>;
-			pwr_sw1-supply = <&bst_out>;
-			pwr_sw2-supply = <&bst_out>;
-
-			vddcore: buck1 {
-				regulator-name = "vddcore";
-				regulator-min-microvolt = <1200000>;
-				regulator-max-microvolt = <1350000>;
-				regulator-always-on;
-				regulator-initial-mode = <0>;
-			};
-
-			vdd_ddr: buck2 {
-				regulator-name = "vdd_ddr";
-				regulator-min-microvolt = <1350000>;
-				regulator-max-microvolt = <1350000>;
-				regulator-always-on;
-				regulator-initial-mode = <0>;
-			};
-
-			vdd: buck3 {
-				regulator-name = "vdd";
-				regulator-min-microvolt = <3300000>;
-				regulator-max-microvolt = <3300000>;
-				regulator-always-on;
-				st,mask-reset;
-				regulator-initial-mode = <0>;
-			};
-
-			v3v3: buck4 {
-				regulator-name = "v3v3";
-				regulator-min-microvolt = <3300000>;
-				regulator-max-microvolt = <3300000>;
-				regulator-always-on;
-				regulator-initial-mode = <0>;
-			};
-
-			v1v8_audio: ldo1 {
-				regulator-name = "v1v8_audio";
-				regulator-min-microvolt = <1800000>;
-				regulator-max-microvolt = <1800000>;
-				regulator-always-on;
-				interrupts = <IT_CURLIM_LDO1 0>;
-
-			};
-
-			vdd_eth_2v5: ldo2 {
-				regulator-name = "dd_eth_2v5";
-				regulator-min-microvolt = <2500000>;
-				regulator-max-microvolt = <2500000>;
-				regulator-always-on;
-				interrupts = <IT_CURLIM_LDO2 0>;
-
-			};
-
-			vtt_ddr: ldo3 {
-				regulator-name = "vtt_ddr";
-				regulator-min-microvolt = <500000>;
-				regulator-max-microvolt = <750000>;
-				regulator-always-on;
-				regulator-over-current-protection;
-			};
-
-			vdd_usb: ldo4 {
-				regulator-name = "vdd_usb";
-				interrupts = <IT_CURLIM_LDO4 0>;
-			};
-
-			vdda: ldo5 {
-				regulator-name = "vdda";
-				regulator-min-microvolt = <2900000>;
-				regulator-max-microvolt = <2900000>;
-				interrupts = <IT_CURLIM_LDO5 0>;
-				regulator-boot-on;
-			};
-
-			vdd_eth_1v0: ldo6 {
-				regulator-name = "vdd_eth_1v0";
-				regulator-min-microvolt = <1000000>;
-				regulator-max-microvolt = <1000000>;
-				regulator-always-on;
-				interrupts = <IT_CURLIM_LDO6 0>;
-
-			};
-
-			vref_ddr: vref_ddr {
-				regulator-name = "vref_ddr";
-				regulator-always-on;
-			};
-
-			bst_out: boost {
-				regulator-name = "bst_out";
-				interrupts = <IT_OCP_BOOST 0>;
-			};
-
-			vbus_otg: pwr_sw1 {
-				regulator-name = "vbus_otg";
-				interrupts = <IT_OCP_OTG 0>;
-				regulator-active-discharge = <1>;
-			};
-
-			vbus_sw: pwr_sw2 {
-				regulator-name = "vbus_sw";
-				interrupts = <IT_OCP_SWOUT 0>;
-				regulator-active-discharge = <1>;
-			};
-		};
-
-		onkey {
-			compatible = "st,stpmic1-onkey";
-			interrupts = <IT_PONKEY_F 0>,
-				     <IT_PONKEY_R 0>;
-			interrupt-names = "onkey-falling",
-					  "onkey-rising";
-			power-off-time-sec = <10>;
-		};
-
-		watchdog {
-			compatible = "st,stpmic1-wdt";
-		};
-	};
-
-	i2c4_eeprom: eeprom at 50 {
-		compatible = "microchip,24c32",
-			     "atmel,24c32";
-		reg = <0x50>;
-	};
-
-	i2c4_rtc: rtc at 52 {
-		compatible = "microcrystal,rv3028";
-		reg = <0x52>;
-	};
-};
-
-&ipcc {
-	status = "okay";
-};
-
-&iwdg2 {
-	timeout-sec = <32>;
-	status = "okay";
-};
-
 &m_can2 {
 	pinctrl-names = "default", "sleep";
 	pinctrl-0 = <&m_can2_pins_a>;
@@ -399,46 +139,6 @@ &m_can2 {
 	status = "okay";
 };
 
-&m4_rproc {
-	memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>,
-			<&vdev0vring1>, <&vdev0buffer>;
-	mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>, <&ipcc 3>;
-	mbox-names = "vq0", "vq1", "shutdown", "detach";
-	interrupt-parent = <&exti>;
-	interrupts = <68 1>;
-	status = "okay";
-};
-
-&pwr_regulators {
-	vdd-supply = <&vdd>;
-	vdd_3v3_usbfs-supply = <&vdd_usb>;
-};
-
-&qspi {
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&qspi_clk_pins_a &qspi_bk1_pins_a>;
-	pinctrl-1 = <&qspi_clk_sleep_pins_a &qspi_bk1_sleep_pins_a>;
-	status = "okay";
-
-	flash0: flash at 0 {
-		compatible = "winbond,w25q128", "jedec,spi-nor";
-		reg = <0>;
-		spi-rx-bus-width = <4>;
-		spi-max-frequency = <50000000>;
-		m25p,fast-read;
-		#address-cells = <1>;
-		#size-cells = <1>;
-	};
-};
-
-&rng1 {
-	status = "okay";
-};
-
-&rtc {
-	status = "okay";
-};
-
 &sai2 {
 	clocks = <&rcc SAI2>, <&rcc PLL3_Q>, <&rcc PLL3_R>;
 	clock-names = "pclk", "x8k", "x11k";
@@ -492,21 +192,6 @@ &sdmmc1 {
 	status = "okay";
 };
 
-&sdmmc2 {
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_e>;
-	pinctrl-1 = <&sdmmc2_b4_od_pins_a &sdmmc2_d47_pins_e>;
-	pinctrl-2 = <&sdmmc2_b4_sleep_pins_a &sdmmc2_d47_sleep_pins_e>;
-	non-removable;
-	no-sd;
-	no-sdio;
-	st,neg-edge;
-	bus-width = <8>;
-	vmmc-supply = <&v3v3>;
-	vqmmc-supply = <&v3v3>;
-	mmc-ddr-3_3v;
-};
-
 &spi1 {
 	pinctrl-names = "default", "sleep";
 	pinctrl-0 = <&spi1_pins_a>;
diff --git a/arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi b/arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi
new file mode 100644
index 000000000000..660cdc260963
--- /dev/null
+++ b/arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi
@@ -0,0 +1,329 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) Phytec GmbH 2019-2020 - All Rights Reserved
+ * Author: Dom VOVARD <dom.vovard at linrt.com>
+ * Copyright (C) 2022-2023 Steffen Trumtrar <kernel at pengutronix.de>
+ * Copyright (C) 2024 PHYTEC Messtechnik GmbH
+ * Author: Christophe Parant <c.parant at phytec.fr>
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/mfd/st,stpmic1.h>
+#include <dt-bindings/net/ti-dp83867.h>
+#include "stm32mp15-pinctrl.dtsi"
+#include "stm32mp15xxac-pinctrl.dtsi"
+
+/ {
+
+	aliases {
+		ethernet0 = &ethernet0;
+		rtc0 = &i2c4_rtc;
+		rtc1 = &rtc;
+	};
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		retram: retram at 38000000 {
+			compatible = "shared-dma-pool";
+			reg = <0x38000000 0x10000>;
+			no-map;
+		};
+
+		mcuram: mcuram at 30000000 {
+			compatible = "shared-dma-pool";
+			reg = <0x30000000 0x40000>;
+			no-map;
+		};
+
+		mcuram2: mcuram2 at 10000000 {
+			compatible = "shared-dma-pool";
+			reg = <0x10000000 0x40000>;
+			no-map;
+		};
+
+		vdev0vring0: vdev0vring0 at 10040000 {
+			compatible = "shared-dma-pool";
+			reg = <0x10040000 0x1000>;
+			no-map;
+		};
+
+		vdev0vring1: vdev0vring1 at 10041000 {
+			compatible = "shared-dma-pool";
+			reg = <0x10041000 0x1000>;
+			no-map;
+		};
+
+		vdev0buffer: vdev0buffer at 10042000 {
+			compatible = "shared-dma-pool";
+			reg = <0x10042000 0x4000>;
+			no-map;
+		};
+	};
+
+	regulator_vin: regulator {
+		compatible = "regulator-fixed";
+		regulator-name = "vin";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+	};
+};
+
+&ethernet0 {
+	pinctrl-0 = <&ethernet0_rgmii_pins_d>;
+	pinctrl-1 = <&ethernet0_rgmii_sleep_pins_d>;
+	pinctrl-names = "default", "sleep";
+	phy-mode = "rgmii-id";
+	max-speed = <1000>;
+	phy-handle = <&phy0>;
+	st,eth-clk-sel;
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "snps,dwmac-mdio";
+
+		phy0: ethernet-phy at 1 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <1>;
+			interrupt-parent = <&gpiog>;
+			interrupts = <12 IRQ_TYPE_EDGE_FALLING>;
+			ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
+			ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
+			ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
+			ti,min-output-impedance;
+			enet-phy-lane-no-swap;
+			ti,clk-output-sel = <DP83867_CLK_O_SEL_OFF>;
+		};
+	};
+};
+
+&i2c4 {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&i2c4_pins_a>;
+	pinctrl-1 = <&i2c4_sleep_pins_a>;
+	i2c-scl-rising-time-ns = <185>;
+	i2c-scl-falling-time-ns = <20>;
+	status = "okay";
+
+	pmic at 33 {
+		compatible = "st,stpmic1";
+		reg = <0x33>;
+		interrupts-extended = <&gpioa 0 IRQ_TYPE_EDGE_FALLING>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		regulators {
+			compatible = "st,stpmic1-regulators";
+			buck1-supply = <&regulator_vin>;
+			buck2-supply = <&regulator_vin>;
+			buck3-supply = <&regulator_vin>;
+			buck4-supply = <&regulator_vin>;
+			ldo1-supply = <&v3v3>;
+			ldo2-supply = <&v3v3>;
+			ldo3-supply = <&vdd_ddr>;
+			ldo4-supply = <&regulator_vin>;
+			ldo5-supply = <&v3v3>;
+			ldo6-supply = <&v3v3>;
+			boost-supply = <&regulator_vin>;
+			pwr_sw1-supply = <&bst_out>;
+			pwr_sw2-supply = <&bst_out>;
+
+			vddcore: buck1 {
+				regulator-name = "vddcore";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-always-on;
+				regulator-initial-mode = <0>;
+			};
+
+			vdd_ddr: buck2 {
+				regulator-name = "vdd_ddr";
+				regulator-min-microvolt = <1350000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-always-on;
+				regulator-initial-mode = <0>;
+			};
+
+			vdd: buck3 {
+				regulator-name = "vdd";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+				st,mask-reset;
+				regulator-initial-mode = <0>;
+			};
+
+			v3v3: buck4 {
+				regulator-name = "v3v3";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+				regulator-initial-mode = <0>;
+			};
+
+			v1v8_audio: ldo1 {
+				regulator-name = "v1v8_audio";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+				interrupts = <IT_CURLIM_LDO1 0>;
+
+			};
+
+			vdd_eth_2v5: ldo2 {
+				regulator-name = "dd_eth_2v5";
+				regulator-min-microvolt = <2500000>;
+				regulator-max-microvolt = <2500000>;
+				regulator-always-on;
+				interrupts = <IT_CURLIM_LDO2 0>;
+
+			};
+
+			vtt_ddr: ldo3 {
+				regulator-name = "vtt_ddr";
+				regulator-min-microvolt = <500000>;
+				regulator-max-microvolt = <750000>;
+				regulator-always-on;
+				regulator-over-current-protection;
+			};
+
+			vdd_usb: ldo4 {
+				regulator-name = "vdd_usb";
+				interrupts = <IT_CURLIM_LDO4 0>;
+			};
+
+			vdda: ldo5 {
+				regulator-name = "vdda";
+				regulator-min-microvolt = <2900000>;
+				regulator-max-microvolt = <2900000>;
+				interrupts = <IT_CURLIM_LDO5 0>;
+				regulator-boot-on;
+			};
+
+			vdd_eth_1v0: ldo6 {
+				regulator-name = "vdd_eth_1v0";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+				interrupts = <IT_CURLIM_LDO6 0>;
+
+			};
+
+			vref_ddr: vref_ddr {
+				regulator-name = "vref_ddr";
+				regulator-always-on;
+			};
+
+			bst_out: boost {
+				regulator-name = "bst_out";
+				interrupts = <IT_OCP_BOOST 0>;
+			};
+
+			vbus_otg: pwr_sw1 {
+				regulator-name = "vbus_otg";
+				interrupts = <IT_OCP_OTG 0>;
+				regulator-active-discharge = <1>;
+			};
+
+			vbus_sw: pwr_sw2 {
+				regulator-name = "vbus_sw";
+				interrupts = <IT_OCP_SWOUT 0>;
+				regulator-active-discharge = <1>;
+			};
+		};
+
+		onkey {
+			compatible = "st,stpmic1-onkey";
+			interrupts = <IT_PONKEY_F 0>,
+				     <IT_PONKEY_R 0>;
+			interrupt-names = "onkey-falling",
+					  "onkey-rising";
+			power-off-time-sec = <10>;
+		};
+
+		watchdog {
+			compatible = "st,stpmic1-wdt";
+		};
+	};
+
+	i2c4_eeprom: eeprom at 50 {
+		compatible = "microchip,24c32",
+			     "atmel,24c32";
+		reg = <0x50>;
+	};
+
+	i2c4_rtc: rtc at 52 {
+		compatible = "microcrystal,rv3028";
+		reg = <0x52>;
+	};
+};
+
+&ipcc {
+	status = "okay";
+};
+
+&iwdg2 {
+	timeout-sec = <32>;
+	status = "okay";
+};
+
+&m4_rproc {
+	memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>,
+			<&vdev0vring1>, <&vdev0buffer>;
+	mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>, <&ipcc 3>;
+	mbox-names = "vq0", "vq1", "shutdown", "detach";
+	interrupt-parent = <&exti>;
+	interrupts = <68 1>;
+	status = "okay";
+};
+
+&pwr_regulators {
+	vdd-supply = <&vdd>;
+	vdd_3v3_usbfs-supply = <&vdd_usb>;
+};
+
+&qspi {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&qspi_clk_pins_a &qspi_bk1_pins_a>;
+	pinctrl-1 = <&qspi_clk_sleep_pins_a &qspi_bk1_sleep_pins_a>;
+	status = "okay";
+
+	flash0: flash at 0 {
+		compatible = "winbond,w25q128", "jedec,spi-nor";
+		reg = <0>;
+		spi-rx-bus-width = <4>;
+		spi-max-frequency = <50000000>;
+		m25p,fast-read;
+		#address-cells = <1>;
+		#size-cells = <1>;
+	};
+};
+
+&rng1 {
+	status = "okay";
+};
+
+&rtc {
+	status = "okay";
+};
+
+&sdmmc2 {
+	pinctrl-names = "default", "opendrain", "sleep";
+	pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_e>;
+	pinctrl-1 = <&sdmmc2_b4_od_pins_a &sdmmc2_d47_pins_e>;
+	pinctrl-2 = <&sdmmc2_b4_sleep_pins_a &sdmmc2_d47_sleep_pins_e>;
+	non-removable;
+	no-sd;
+	no-sdio;
+	st,neg-edge;
+	bus-width = <8>;
+	vmmc-supply = <&v3v3>;
+	vqmmc-supply = <&v3v3>;
+	mmc-ddr-3_3v;
+};
-- 
2.34.1



From c.parant at phytec.fr  Wed Dec 10 02:16:08 2025
From: c.parant at phytec.fr (Christophe Parant)
Date: Wed, 10 Dec 2025 11:16:08 +0100
Subject: [PATCH RESEND v2 08/11] ARM: dts: stm32: phyboard-sargas: Move aliases from dts to dtsi
In-Reply-To: <20251210101611.27008-1-c.parant@phytec.fr>
References: <20251210101611.27008-1-c.parant@phytec.fr>
Message-ID: <20251210101611.27008-9-c.parant@phytec.fr>

aliases are common to every phyboard-sargas version. So move it to
the common phyboard dtsi file.

Signed-off-by: Christophe Parant <c.parant at phytec.fr>
---
 arch/arm/boot/dts/st/stm32mp157c-phyboard-sargas-rdk.dts | 9 ---------
 arch/arm/boot/dts/st/stm32mp15xx-phyboard-sargas.dtsi    | 9 +++++++++
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/arch/arm/boot/dts/st/stm32mp157c-phyboard-sargas-rdk.dts b/arch/arm/boot/dts/st/stm32mp157c-phyboard-sargas-rdk.dts
index 48adc3462958..f7c02a381304 100644
--- a/arch/arm/boot/dts/st/stm32mp157c-phyboard-sargas-rdk.dts
+++ b/arch/arm/boot/dts/st/stm32mp157c-phyboard-sargas-rdk.dts
@@ -16,15 +16,6 @@ / {
 	model = "PHYTEC phyBOARD-Sargas STM32MP157C";
 	compatible = "phytec,phycore-stm32mp1-3",
 		     "phytec,phycore-stm32mp157c-som", "st,stm32mp157";
-
-	aliases {
-		mmc0 = &sdmmc1;
-		mmc1 = &sdmmc2;
-		mmc2 = &sdmmc3;
-		serial0 = &uart4;
-		serial1 = &usart3;
-		serial2 = &usart1;
-	};
 };
 
 &cryp1 {
diff --git a/arch/arm/boot/dts/st/stm32mp15xx-phyboard-sargas.dtsi b/arch/arm/boot/dts/st/stm32mp15xx-phyboard-sargas.dtsi
index 44f3aa1ddebf..9578e78bcc1d 100644
--- a/arch/arm/boot/dts/st/stm32mp15xx-phyboard-sargas.dtsi
+++ b/arch/arm/boot/dts/st/stm32mp15xx-phyboard-sargas.dtsi
@@ -12,6 +12,15 @@
 #include <dt-bindings/leds/leds-pca9532.h>
 
 / {
+	aliases {
+		mmc0 = &sdmmc1;
+		mmc1 = &sdmmc2;
+		mmc2 = &sdmmc3;
+		serial0 = &uart4;
+		serial1 = &usart3;
+		serial2 = &usart1;
+	};
+
 	chosen {
 		stdout-path = "serial0:115200n8";
 	};
-- 
2.34.1



From c.parant at phytec.fr  Wed Dec 10 02:16:11 2025
From: c.parant at phytec.fr (Christophe Parant)
Date: Wed, 10 Dec 2025 11:16:11 +0100
Subject: [PATCH RESEND v2 11/11] ARM: dts: stm32: phyboard-sargas and phycore: Add optional interfaces
In-Reply-To: <20251210101611.27008-1-c.parant@phytec.fr>
References: <20251210101611.27008-1-c.parant@phytec.fr>
Message-ID: <20251210101611.27008-12-c.parant@phytec.fr>

- stm32mp15xx-phycore-som: add NAND device on FMC interface to support
the SoM version equipped with NAND flash instead of eMMC.

- stm32mp15xx-phyboard-sargas: define pinctrl for PWM5, LTDC and DCMI
interfaces used on phyBOARD-Sargas. Those interfaces are not enabled by
default as PHYTEC displays and PHYTEC cameras are enabled and configured
throught device tree overlays.
PWM5 is used for LCD backlight command.

Signed-off-by: Christophe Parant <c.parant at phytec.fr>
---
 .../dts/st/stm32mp15xx-phyboard-sargas.dtsi   | 23 +++++++++++++++++++
 .../boot/dts/st/stm32mp15xx-phycore-som.dtsi  | 16 +++++++++++++
 2 files changed, 39 insertions(+)

diff --git a/arch/arm/boot/dts/st/stm32mp15xx-phyboard-sargas.dtsi b/arch/arm/boot/dts/st/stm32mp15xx-phyboard-sargas.dtsi
index 20684b497c99..28a21dec9cd7 100644
--- a/arch/arm/boot/dts/st/stm32mp15xx-phyboard-sargas.dtsi
+++ b/arch/arm/boot/dts/st/stm32mp15xx-phyboard-sargas.dtsi
@@ -260,3 +260,26 @@ &usbphyc_port0 {
 &usbphyc_port1 {
 	phy-supply = <&vdd_usb>;
 };
+
+&timers5 {
+	/* spare dmas for other usage */
+	/delete-property/dmas;
+	/delete-property/dma-names;
+	pwm5: pwm {
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&pwm5_pins_c>;
+		pinctrl-1 = <&pwm5_sleep_pins_c>;
+	};
+};
+
+&ltdc {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&ltdc_pins_f>;
+	pinctrl-1 = <&ltdc_sleep_pins_f>;
+};
+
+&dcmi {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&dcmi_pins_d>;
+	pinctrl-1 = <&dcmi_sleep_pins_d>;
+};
diff --git a/arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi b/arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi
index 0689967b8c56..23db635c39a1 100644
--- a/arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi
+++ b/arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi
@@ -345,3 +345,19 @@ &sdmmc2 {
 	st,neg-edge;
 	status = "disabled";
 };
+
+&fmc {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&fmc_pins_a>;
+	pinctrl-1 = <&fmc_sleep_pins_a>;
+	status = "disabled";
+
+	nand-controller at 4,0 {
+		nand0: nand at 0 {
+			reg = <0>;
+			nand-on-flash-bbt;
+			nand-ecc-strength = <4>;
+			nand-ecc-step-size = <512>;
+		};
+	};
+};
-- 
2.34.1



From c.parant at phytec.fr  Wed Dec 10 02:16:10 2025
From: c.parant at phytec.fr (Christophe Parant)
Date: Wed, 10 Dec 2025 11:16:10 +0100
Subject: [PATCH RESEND v2 10/11] ARM: dts: stm32: phyboard-sargas and phycore: Fix coding style issues
In-Reply-To: <20251210101611.27008-1-c.parant@phytec.fr>
References: <20251210101611.27008-1-c.parant@phytec.fr>
Message-ID: <20251210101611.27008-11-c.parant@phytec.fr>

- Remove "stm32-pinfunc.h" include as it is already include in
"stm32mp15-pinctrl.dtsi" file.
- reserved-memory: reorder the memory sections (lower to higher
  addresses).
- Move vendor properties (go last).
- Remove useless compatible values:
  - QSPI flash: remove the winbond compatible. jedec is enought as the
    NOR flahses are detectable.
  - EEPROM: "atmel,24c32" is enought.
- Use uppercase for regulator-name properties.
- In pmic node: use the names from the PHYTEC SoM schematics.
- stmpe811 touch: fix dts schema to comply with st,stmpe.yaml.
- Fix one "multiple blank lines" detected by checkpatch.

Signed-off-by: Christophe Parant <c.parant at phytec.fr>
---
 .../st/stm32mp157c-phyboard-sargas-rdk.dts    |  1 -
 .../dts/st/stm32mp15xx-phyboard-sargas.dtsi   | 13 ++--
 .../boot/dts/st/stm32mp15xx-phycore-som.dtsi  | 64 +++++++++----------
 3 files changed, 36 insertions(+), 42 deletions(-)

diff --git a/arch/arm/boot/dts/st/stm32mp157c-phyboard-sargas-rdk.dts b/arch/arm/boot/dts/st/stm32mp157c-phyboard-sargas-rdk.dts
index c90b12a479c9..c18a37266083 100644
--- a/arch/arm/boot/dts/st/stm32mp157c-phyboard-sargas-rdk.dts
+++ b/arch/arm/boot/dts/st/stm32mp157c-phyboard-sargas-rdk.dts
@@ -6,7 +6,6 @@
 
 /dts-v1/;
 
-#include <dt-bindings/pinctrl/stm32-pinfunc.h>
 #include "stm32mp157.dtsi"
 #include "stm32mp15xc.dtsi"
 #include "stm32mp15xx-phycore-som.dtsi"
diff --git a/arch/arm/boot/dts/st/stm32mp15xx-phyboard-sargas.dtsi b/arch/arm/boot/dts/st/stm32mp15xx-phyboard-sargas.dtsi
index 9578e78bcc1d..20684b497c99 100644
--- a/arch/arm/boot/dts/st/stm32mp15xx-phyboard-sargas.dtsi
+++ b/arch/arm/boot/dts/st/stm32mp15xx-phyboard-sargas.dtsi
@@ -5,7 +5,6 @@
  * Author: Dom VOVARD <dom.vovard at linrt.com>.
  */
 
-
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/leds/common.h>
@@ -101,13 +100,13 @@ touch at 44 {
 		interrupt-parent = <&gpioi>;
 		vio-supply = <&v3v3>;
 		vcc-supply = <&v3v3>;
+		st,sample-time = <4>;
+		st,mod-12b = <1>;
+		st,ref-sel = <0>;
+		st,adc-freq = <1>;
 
 		touchscreen {
 			compatible = "st,stmpe-ts";
-			st,sample-time = <4>;
-			st,mod-12b = <1>;
-			st,ref-sel = <0>;
-			st,adc-freq = <1>;
 			st,ave-ctrl = <1>;
 			st,touch-det-delay = <2>;
 			st,settling = <2>;
@@ -159,10 +158,10 @@ &sai2 {
 
 &sai2a {
 	dma-names = "rx";
-	st,sync = <&sai2b 2>;
 	clocks = <&rcc SAI2_K>, <&sai2b>;
 	clock-names = "sai_ck", "MCLK";
 	#clock-cells = <0>;
+	st,sync = <&sai2b 2>;
 
 	sai2a_port: port {
 		sai2a_endpoint: endpoint {
@@ -195,9 +194,9 @@ &sdmmc1 {
 	pinctrl-2 = <&sdmmc1_b4_sleep_pins_b>;
 	cd-gpios = <&gpiof 3 GPIO_ACTIVE_LOW>;
 	disable-wp;
-	st,neg-edge;
 	bus-width = <4>;
 	vmmc-supply = <&v3v3>;
+	st,neg-edge;
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi b/arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi
index 3f60f184978c..0689967b8c56 100644
--- a/arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi
+++ b/arch/arm/boot/dts/st/stm32mp15xx-phycore-som.dtsi
@@ -36,18 +36,6 @@ reserved-memory {
 		#size-cells = <1>;
 		ranges;
 
-		retram: retram at 38000000 {
-			compatible = "shared-dma-pool";
-			reg = <0x38000000 0x10000>;
-			no-map;
-		};
-
-		mcuram: mcuram at 30000000 {
-			compatible = "shared-dma-pool";
-			reg = <0x30000000 0x40000>;
-			no-map;
-		};
-
 		mcuram2: mcuram2 at 10000000 {
 			compatible = "shared-dma-pool";
 			reg = <0x10000000 0x40000>;
@@ -71,11 +59,22 @@ vdev0buffer: vdev0buffer at 10042000 {
 			reg = <0x10042000 0x4000>;
 			no-map;
 		};
+		mcuram: mcuram at 30000000 {
+			compatible = "shared-dma-pool";
+			reg = <0x30000000 0x40000>;
+			no-map;
+		};
+
+		retram: retram at 38000000 {
+			compatible = "shared-dma-pool";
+			reg = <0x38000000 0x10000>;
+			no-map;
+		};
 	};
 
 	regulator_vin: regulator {
 		compatible = "regulator-fixed";
-		regulator-name = "vin";
+		regulator-name = "VIN";
 		regulator-min-microvolt = <5000000>;
 		regulator-max-microvolt = <5000000>;
 		regulator-always-on;
@@ -102,11 +101,11 @@ phy0: ethernet-phy at 1 {
 			reg = <1>;
 			interrupt-parent = <&gpiog>;
 			interrupts = <12 IRQ_TYPE_EDGE_FALLING>;
+			enet-phy-lane-no-swap;
 			ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
 			ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
 			ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
 			ti,min-output-impedance;
-			enet-phy-lane-no-swap;
 			ti,clk-output-sel = <DP83867_CLK_O_SEL_OFF>;
 		};
 	};
@@ -144,7 +143,7 @@ regulators {
 			pwr_sw2-supply = <&bst_out>;
 
 			vddcore: buck1 {
-				regulator-name = "vddcore";
+				regulator-name = "VDD_CORE";
 				regulator-min-microvolt = <1200000>;
 				regulator-max-microvolt = <1350000>;
 				regulator-always-on;
@@ -152,7 +151,7 @@ vddcore: buck1 {
 			};
 
 			vdd_ddr: buck2 {
-				regulator-name = "vdd_ddr";
+				regulator-name = "VDD_DDR";
 				regulator-min-microvolt = <1350000>;
 				regulator-max-microvolt = <1350000>;
 				regulator-always-on;
@@ -160,7 +159,7 @@ vdd_ddr: buck2 {
 			};
 
 			vdd: buck3 {
-				regulator-name = "vdd";
+				regulator-name = "VDD";
 				regulator-min-microvolt = <3300000>;
 				regulator-max-microvolt = <3300000>;
 				regulator-always-on;
@@ -169,7 +168,7 @@ vdd: buck3 {
 			};
 
 			v3v3: buck4 {
-				regulator-name = "v3v3";
+				regulator-name = "VDD_BUCK4";
 				regulator-min-microvolt = <3300000>;
 				regulator-max-microvolt = <3300000>;
 				regulator-always-on;
@@ -177,7 +176,7 @@ v3v3: buck4 {
 			};
 
 			v1v8_audio: ldo1 {
-				regulator-name = "v1v8_audio";
+				regulator-name = "VDD_LDO1";
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <1800000>;
 				regulator-always-on;
@@ -186,7 +185,7 @@ v1v8_audio: ldo1 {
 			};
 
 			vdd_eth_2v5: ldo2 {
-				regulator-name = "dd_eth_2v5";
+				regulator-name = "VDD_ETH_2V5";
 				regulator-min-microvolt = <2500000>;
 				regulator-max-microvolt = <2500000>;
 				regulator-always-on;
@@ -195,7 +194,7 @@ vdd_eth_2v5: ldo2 {
 			};
 
 			vtt_ddr: ldo3 {
-				regulator-name = "vtt_ddr";
+				regulator-name = "VTT_DDR";
 				regulator-min-microvolt = <500000>;
 				regulator-max-microvolt = <750000>;
 				regulator-always-on;
@@ -203,12 +202,12 @@ vtt_ddr: ldo3 {
 			};
 
 			vdd_usb: ldo4 {
-				regulator-name = "vdd_usb";
+				regulator-name = "VDD_USB";
 				interrupts = <IT_CURLIM_LDO4 0>;
 			};
 
 			vdda: ldo5 {
-				regulator-name = "vdda";
+				regulator-name = "VDDA";
 				regulator-min-microvolt = <2900000>;
 				regulator-max-microvolt = <2900000>;
 				interrupts = <IT_CURLIM_LDO5 0>;
@@ -216,7 +215,7 @@ vdda: ldo5 {
 			};
 
 			vdd_eth_1v0: ldo6 {
-				regulator-name = "vdd_eth_1v0";
+				regulator-name = "VDD_ETH_1V0";
 				regulator-min-microvolt = <1000000>;
 				regulator-max-microvolt = <1000000>;
 				regulator-always-on;
@@ -225,23 +224,23 @@ vdd_eth_1v0: ldo6 {
 			};
 
 			vref_ddr: vref_ddr {
-				regulator-name = "vref_ddr";
+				regulator-name = "VDD_REFDDR";
 				regulator-always-on;
 			};
 
 			bst_out: boost {
-				regulator-name = "bst_out";
+				regulator-name = "BST_OUT";
 				interrupts = <IT_OCP_BOOST 0>;
 			};
 
 			vbus_otg: pwr_sw1 {
-				regulator-name = "vbus_otg";
+				regulator-name = "VBUS_OTG";
 				interrupts = <IT_OCP_OTG 0>;
 				regulator-active-discharge = <1>;
 			};
 
 			vbus_sw: pwr_sw2 {
-				regulator-name = "vbus_sw";
+				regulator-name = "VBUS_SW";
 				interrupts = <IT_OCP_SWOUT 0>;
 				regulator-active-discharge = <1>;
 			};
@@ -262,8 +261,7 @@ watchdog {
 	};
 
 	i2c4_eeprom: eeprom at 50 {
-		compatible = "microchip,24c32",
-			     "atmel,24c32";
+		compatible = "atmel,24c32";
 		reg = <0x50>;
 		status = "disabled";
 	};
@@ -312,13 +310,11 @@ &qspi_bk1_sleep_pins_a
 	status = "disabled";
 
 	flash0: flash at 0 {
-		compatible = "winbond,w25q128", "jedec,spi-nor";
+		compatible = "jedec,spi-nor";
 		reg = <0>;
 		spi-rx-bus-width = <4>;
 		spi-max-frequency = <50000000>;
 		m25p,fast-read;
-		#address-cells = <1>;
-		#size-cells = <1>;
 	};
 };
 
@@ -342,10 +338,10 @@ &sdmmc2 {
 	non-removable;
 	no-sd;
 	no-sdio;
-	st,neg-edge;
 	bus-width = <8>;
 	vmmc-supply = <&v3v3>;
 	vqmmc-supply = <&v3v3>;
 	mmc-ddr-3_3v;
+	st,neg-edge;
 	status = "disabled";
 };
-- 
2.34.1



From Irving-CH.Lin at mediatek.com  Wed Dec 10 02:30:23 2025
From: Irving-CH.Lin at mediatek.com (=?utf-8?B?SXJ2aW5nLUNIIExpbiAo5p6X5bu65byYKQ==?=)
Date: Wed, 10 Dec 2025 10:30:23 +0000
Subject: [PATCH v3 20/21] pmdomain: mediatek: Add bus protect control flow
 for MT8189
In-Reply-To: <6f1bbbc7-ca54-43f9-953d-725902af7b10@collabora.com>
References: <20251106124330.1145600-1-irving-ch.lin@mediatek.com>
	 <20251106124330.1145600-21-irving-ch.lin@mediatek.com>
	 <6f1bbbc7-ca54-43f9-953d-725902af7b10@collabora.com>
Message-ID: <174a8f4ec6e04ec06f4ec77345615bd3e0f7671c.camel@mediatek.com>

Hi Angelo,

On Fri, 2025-11-07 at 11:36 +0100, AngeloGioacchino Del Regno wrote:
> 
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
> 
> 
> Il 06/11/25 13:42, irving.ch.lin ha scritto:
> > From: Irving-CH Lin <irving-ch.lin at mediatek.com>
> > 
> > In MT8189 mminfra power domain, the bus protect policy separates
> > into two parts, one is set before subsys clocks enabled, and
> > another
> > need to enable after subsys clocks enable.
> > 
> > Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
> > ---
> > ? drivers/pmdomain/mediatek/mtk-pm-domains.c | 31
> > ++++++++++++++++++----
> > ? drivers/pmdomain/mediatek/mtk-pm-domains.h |? 5 ++++
> > ? 2 files changed, 31 insertions(+), 5 deletions(-)
> > 
> > diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c
> > b/drivers/pmdomain/mediatek/mtk-pm-domains.c
> > index 164c6b519af3..222846e52daf 100644
> > --- a/drivers/pmdomain/mediatek/mtk-pm-domains.c
> > +++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c
> > @@ -250,7 +250,7 @@ static int scpsys_bus_protect_set(struct
> > scpsys_domain *pd,
> > ????????????????????????????????????? MTK_POLL_DELAY_US,
> > MTK_POLL_TIMEOUT);
> > ? }
> > 
> > -static int scpsys_bus_protect_enable(struct scpsys_domain *pd)
> > +static int scpsys_bus_protect_enable(struct scpsys_domain *pd, u8
> > flags)
> > ? {
> > ????? for (int i = 0; i < SPM_MAX_BUS_PROT_DATA; i++) {
> > ????????????? const struct scpsys_bus_prot_data *bpd = &pd->data-
> > >bp_cfg[i];
> > @@ -259,6 +259,10 @@ static int scpsys_bus_protect_enable(struct
> > scpsys_domain *pd)
> > ????????????? if (!bpd->bus_prot_set_clr_mask)
> > ????????????????????? break;
> > 
> > +???????????? if ((bpd->flags & BUS_PROT_IGNORE_SUBCLK) !=
> > +???????????????? (flags & BUS_PROT_IGNORE_SUBCLK))
> > +???????????????????? continue;
> > +
> > ????????????? if (bpd->flags & BUS_PROT_INVERTED)
> > ????????????????????? ret = scpsys_bus_protect_clear(pd, bpd);
> > ????????????? else
> > @@ -270,7 +274,7 @@ static int scpsys_bus_protect_enable(struct
> > scpsys_domain *pd)
> > ????? return 0;
> > ? }
> > 
> > -static int scpsys_bus_protect_disable(struct scpsys_domain *pd)
> > +static int scpsys_bus_protect_disable(struct scpsys_domain *pd, u8
> > flags)
> > ? {
> > ????? for (int i = SPM_MAX_BUS_PROT_DATA - 1; i >= 0; i--) {
> > ????????????? const struct scpsys_bus_prot_data *bpd = &pd->data-
> > >bp_cfg[i];
> > @@ -279,6 +283,10 @@ static int scpsys_bus_protect_disable(struct
> > scpsys_domain *pd)
> > ????????????? if (!bpd->bus_prot_set_clr_mask)
> > ????????????????????? continue;
> > 
> > +???????????? if ((bpd->flags & BUS_PROT_IGNORE_SUBCLK) !=
> 
> Is that the right name for this flag?
> 
> As far as I understand, you have to set bus protection in two steps,
> right?
> So in the first step you're setting bus protection for the MM_INFRA
> and for
> MM_INFRA_2ND - and in the second step you're setting MM_INFRA_IGN and
> 2_IGN.
> 
> So the first step (the prots with BUS_PROT_IGNORE_SUBCLK) unlocks
> SUBSYS clks
> and SRAM ISO access, the second one does the rest.
> 
> I think that a better name for this, at this point would be...
> 
> if ((bpd->flags & local_flags) & BUS_PROT_SRAM_PROTECTION)
> ??????? continue;
> 
> What do you think?
> 
> Regards,
> Angelo
> 
Yes, the purpose is to set bus with two steps:
In general case, bus protection needs to control after subsys clock
enabled. But on MT8189 MM_INFRA subsys, some bus protection set before
subsys clock enabled.

So here i name bus protection setting w/o subsys clock as
IGNORE_SUBCLK.

thanks

BR,
irving

> > +???????????????? (flags & BUS_PROT_IGNORE_SUBCLK))
> > +???????????????????? continue;
> > +
> > ????????????? if (bpd->flags & BUS_PROT_INVERTED)
> > ????????????????????? ret = scpsys_bus_protect_set(pd, bpd);
> > ????????????? else
> > @@ -632,6 +640,15 @@ static int scpsys_power_on(struct
> > generic_pm_domain *genpd)
> > ????? if (ret)
> > ????????????? goto err_pwr_ack;
> > 
> > +???? /*
> > +????? * In MT8189 mminfra power domain, the bus protect policy
> > separates
> > +????? * into two parts, one is set before subsys clocks enabled,
> > and another
> > +????? * need to enable after subsys clocks enable.
> > +????? */
> > +???? ret = scpsys_bus_protect_disable(pd, BUS_PROT_IGNORE_SUBCLK);
> > +???? if (ret < 0)
> > +???????????? goto err_pwr_ack;
> > +
> > ????? /*
> > ?????? * In few Mediatek platforms(e.g. MT6779), the bus protect
> > policy is
> > ?????? * stricter, which leads to bus protect release must be prior
> > to bus
> > @@ -648,7 +665,7 @@ static int scpsys_power_on(struct
> > generic_pm_domain *genpd)
> > ????? if (ret < 0)
> > ????????????? goto err_disable_subsys_clks;
> > 
> > -???? ret = scpsys_bus_protect_disable(pd);
> > +???? ret = scpsys_bus_protect_disable(pd, 0);
> > ????? if (ret < 0)
> > ????????????? goto err_disable_sram;
> > 
> > @@ -662,7 +679,7 @@ static int scpsys_power_on(struct
> > generic_pm_domain *genpd)
> > ????? return 0;
> > 
> > ? err_enable_bus_protect:
> > -???? scpsys_bus_protect_enable(pd);
> > +???? scpsys_bus_protect_enable(pd, 0);
> > ? err_disable_sram:
> > ????? scpsys_sram_disable(pd);
> > ? err_disable_subsys_clks:
> > @@ -683,7 +700,7 @@ static int scpsys_power_off(struct
> > generic_pm_domain *genpd)
> > ????? bool tmp;
> > ????? int ret;
> > 
> > -???? ret = scpsys_bus_protect_enable(pd);
> > +???? ret = scpsys_bus_protect_enable(pd, 0);
> > ????? if (ret < 0)
> > ????????????? return ret;
> > 
> > @@ -697,6 +714,10 @@ static int scpsys_power_off(struct
> > generic_pm_domain *genpd)
> > 
> > ????? clk_bulk_disable_unprepare(pd->num_subsys_clks, pd-
> > >subsys_clks);
> > 
> > +???? ret = scpsys_bus_protect_enable(pd, BUS_PROT_IGNORE_SUBCLK);
> > +???? if (ret < 0)
> > +???????????? return ret;
> > +
> > ????? if (MTK_SCPD_CAPS(pd, MTK_SCPD_MODEM_PWRSEQ))
> > ????????????? scpsys_modem_pwrseq_off(pd);
> > ????? else
> > diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.h
> > b/drivers/pmdomain/mediatek/mtk-pm-domains.h
> > index f608e6ec4744..a5dca24cbc2f 100644
> > --- a/drivers/pmdomain/mediatek/mtk-pm-domains.h
> > +++ b/drivers/pmdomain/mediatek/mtk-pm-domains.h
> > @@ -56,6 +56,7 @@ enum scpsys_bus_prot_flags {
> > ????? BUS_PROT_REG_UPDATE = BIT(1),
> > ????? BUS_PROT_IGNORE_CLR_ACK = BIT(2),
> > ????? BUS_PROT_INVERTED = BIT(3),
> > +???? BUS_PROT_IGNORE_SUBCLK = BIT(4),
> > ? };
> > 
> > ? enum scpsys_bus_prot_block {
> > @@ -95,6 +96,10 @@ enum scpsys_bus_prot_block {
> > ????????????? _BUS_PROT(_hwip, _mask, _set, _clr, _mask,
> > _sta,??????? \
> > ??????????????????????? BUS_PROT_REG_UPDATE)
> > 
> > +#define BUS_PROT_WR_IGN_SUBCLK(_hwip, _mask, _set, _clr,
> > _sta)?????????????? \
> > +???????????? _BUS_PROT(_hwip, _mask, _set, _clr, _mask,
> > _sta,??????? \
> > +?????????????????????? BUS_PROT_IGNORE_CLR_ACK |
> > BUS_PROT_IGNORE_SUBCLK)
> > +
> > ? #define BUS_PROT_INFRA_UPDATE_TOPAXI(_mask)???????????????? \
> > ????????????? BUS_PROT_UPDATE(INFRA, _mask,?????????????????? \
> > ????????????????????????????? INFRA_TOPAXI_PROTECTEN,???????? \
> 
> 


From Irving-CH.Lin at mediatek.com  Wed Dec 10 02:41:15 2025
From: Irving-CH.Lin at mediatek.com (=?utf-8?B?SXJ2aW5nLUNIIExpbiAo5p6X5bu65byYKQ==?=)
Date: Wed, 10 Dec 2025 10:41:15 +0000
Subject: [PATCH v3 05/21] clk: mediatek: Add MT8189 topckgen clock support
In-Reply-To: <bcd9e90530a963c4331c6df13827fb1d9c6b794b.camel@collabora.com>
References: <20251106124330.1145600-1-irving-ch.lin@mediatek.com>
	 <20251106124330.1145600-6-irving-ch.lin@mediatek.com>
	 <bcd9e90530a963c4331c6df13827fb1d9c6b794b.camel@collabora.com>
Message-ID: <85bd813b5e20696d839ada2e71d4e49a7c897187.camel@mediatek.com>

Hi Louis,

On Thu, 2025-11-27 at 14:46 +0100, Louis-Alexis Eyraud wrote:
> 
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
> 
> 
> Hi Irving-CH,
> 
> On Thu, 2025-11-06 at 20:41 +0800, irving.ch.lin wrote:
> > From: Irving-CH Lin <irving-ch.lin at mediatek.com>
> > 
> > Add support for the MT8189 topckgen clock controller, which
> > provides
> > muxes and dividers for clock selection in other IP blocks.
> > 
> > Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
> > ---
> > ?drivers/clk/mediatek/Makefile????????????? |??? 2 +-
> > ?drivers/clk/mediatek/clk-mt8189-topckgen.c | 1018
> > ++++++++++++++++++++
> > ?2 files changed, 1019 insertions(+), 1 deletion(-)
> > ?create mode 100644 drivers/clk/mediatek/clk-mt8189-topckgen.c
> > 
> > diff --git a/drivers/clk/mediatek/Makefile
> > b/drivers/clk/mediatek/Makefile
> > index 66577ccb9b93..9d3d2983bfb2 100644
> > --- a/drivers/clk/mediatek/Makefile
> > +++ b/drivers/clk/mediatek/Makefile
> > @@ -123,7 +123,7 @@ obj-$(CONFIG_COMMON_CLK_MT8188_VDOSYS) += clk-
> > mt8188-vdo0.o clk-mt8188-vdo1.o
> > ?obj-$(CONFIG_COMMON_CLK_MT8188_VENCSYS) += clk-mt8188-venc.o
> > ?obj-$(CONFIG_COMMON_CLK_MT8188_VPPSYS) += clk-mt8188-vpp0.o clk-
> > mt8188-vpp1.o
> > ?obj-$(CONFIG_COMMON_CLK_MT8188_WPESYS) += clk-mt8188-wpe.o
> > -obj-$(CONFIG_COMMON_CLK_MT8189) += clk-mt8189-apmixedsys.o
> > +obj-$(CONFIG_COMMON_CLK_MT8189) += clk-mt8189-apmixedsys.o clk-
> > mt8189-topckgen.o
> > ?obj-$(CONFIG_COMMON_CLK_MT8192) += clk-mt8192-apmixedsys.o clk-
> > mt8192.o
> > ?obj-$(CONFIG_COMMON_CLK_MT8192_AUDSYS) += clk-mt8192-aud.o
> > ?obj-$(CONFIG_COMMON_CLK_MT8192_CAMSYS) += clk-mt8192-cam.o
> > diff --git a/drivers/clk/mediatek/clk-mt8189-topckgen.c
> > b/drivers/clk/mediatek/clk-mt8189-topckgen.c
> > new file mode 100644
> > index 000000000000..a849b92bf7de
> > --- /dev/null
> > +++ b/drivers/clk/mediatek/clk-mt8189-topckgen.c
> > @@ -0,0 +1,1018 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (c) 2025 MediaTek Inc.
> > + * Author: Qiqi Wang <qiqi.wang at mediatek.com>
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/delay.h>
> > +#include <linux/mfd/syscon.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +#include <linux/of_device.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/slab.h>
> > +
> > +#include "clk-mtk.h"
> > +#include "clk-mux.h"
> > +#include "clk-gate.h"
> > +
> > +#include <dt-bindings/clock/mediatek,mt8189-clk.h>
> > +
> > +static DEFINE_SPINLOCK(mt8189_clk_lock);
> > +
> > +static const struct mtk_fixed_factor top_divs[] = {
> > +???? FACTOR(CLK_TOP_MAINPLL_D3, "mainpll_d3", "mainpll", 1, 3),
> > +???? FACTOR(CLK_TOP_MAINPLL_D4, "mainpll_d4", "mainpll", 1, 4),
> > +???? FACTOR(CLK_TOP_MAINPLL_D4_D2, "mainpll_d4_d2", "mainpll", 1,
> > 8),
> > +???? FACTOR(CLK_TOP_MAINPLL_D4_D4, "mainpll_d4_d4", "mainpll", 1,
> > 16),
> > +???? FACTOR(CLK_TOP_MAINPLL_D4_D8, "mainpll_d4_d8", "mainpll",
> > 43, 1375),
> > +???? FACTOR(CLK_TOP_MAINPLL_D5, "mainpll_d5", "mainpll", 1, 5),
> > +???? FACTOR(CLK_TOP_MAINPLL_D5_D2, "mainpll_d5_d2", "mainpll", 1,
> > 10),
> > +???? FACTOR(CLK_TOP_MAINPLL_D5_D4, "mainpll_d5_d4", "mainpll", 1,
> > 20),
> > +???? FACTOR(CLK_TOP_MAINPLL_D5_D8, "mainpll_d5_d8", "mainpll", 1,
> > 40),
> > +???? FACTOR(CLK_TOP_MAINPLL_D6, "mainpll_d6", "mainpll", 1, 6),
> > +???? FACTOR(CLK_TOP_MAINPLL_D6_D2, "mainpll_d6_d2", "mainpll", 1,
> > 12),
> > +???? FACTOR(CLK_TOP_MAINPLL_D6_D4, "mainpll_d6_d4", "mainpll", 1,
> > 24),
> > +???? FACTOR(CLK_TOP_MAINPLL_D6_D8, "mainpll_d6_d8", "mainpll", 1,
> > 48),
> > +???? FACTOR(CLK_TOP_MAINPLL_D7, "mainpll_d7", "mainpll", 1, 7),
> > +???? FACTOR(CLK_TOP_MAINPLL_D7_D2, "mainpll_d7_d2", "mainpll", 1,
> > 14),
> > +???? FACTOR(CLK_TOP_MAINPLL_D7_D4, "mainpll_d7_d4", "mainpll", 1,
> > 28),
> > +???? FACTOR(CLK_TOP_MAINPLL_D7_D8, "mainpll_d7_d8", "mainpll", 1,
> > 56),
> > +???? FACTOR(CLK_TOP_MAINPLL_D9, "mainpll_d9", "mainpll", 1, 9),
> > +???? FACTOR(CLK_TOP_UNIVPLL_D2, "univpll_d2", "univpll", 1, 2),
> > +???? FACTOR(CLK_TOP_UNIVPLL_D3, "univpll_d3", "univpll", 1, 3),
> > +???? FACTOR(CLK_TOP_UNIVPLL_D4, "univpll_d4", "univpll", 1, 4),
> > +???? FACTOR(CLK_TOP_UNIVPLL_D4_D2, "univpll_d4_d2", "univpll", 1,
> > 8),
> > +???? FACTOR(CLK_TOP_UNIVPLL_D4_D4, "univpll_d4_d4", "univpll", 1,
> > 16),
> > +???? FACTOR(CLK_TOP_UNIVPLL_D4_D8, "univpll_d4_d8", "univpll", 1,
> > 32),
> > +???? FACTOR(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univpll", 1, 5),
> > +???? FACTOR(CLK_TOP_UNIVPLL_D5_D2, "univpll_d5_d2", "univpll", 1,
> > 10),
> > +???? FACTOR(CLK_TOP_UNIVPLL_D5_D4, "univpll_d5_d4", "univpll", 1,
> > 20),
> > +???? FACTOR(CLK_TOP_UNIVPLL_D6, "univpll_d6", "univpll", 1, 6),
> > +???? FACTOR(CLK_TOP_UNIVPLL_D6_D2, "univpll_d6_d2", "univpll", 1,
> > 12),
> > +???? FACTOR(CLK_TOP_UNIVPLL_D6_D4, "univpll_d6_d4", "univpll", 1,
> > 24),
> > +???? FACTOR(CLK_TOP_UNIVPLL_D6_D8, "univpll_d6_d8", "univpll", 1,
> > 48),
> > +???? FACTOR(CLK_TOP_UNIVPLL_D6_D16, "univpll_d6_d16", "univpll",
> > 1, 96),
> > +???? FACTOR(CLK_TOP_UNIVPLL_D7, "univpll_d7", "univpll", 1, 7),
> > +???? FACTOR(CLK_TOP_UNIVPLL_D7_D2, "univpll_d7_d2", "univpll", 1,
> > 14),
> > +???? FACTOR(CLK_TOP_UNIVPLL_D7_D3, "univpll_d7_d3", "univpll", 1,
> > 21),
> > +???? FACTOR(CLK_TOP_LVDSTX_DG_CTS, "lvdstx_dg_cts", "univpll", 1,
> > 21),
> > +???? FACTOR(CLK_TOP_UNIVPLL_192M, "univpll_192m", "univpll", 1,
> > 13),
> > +???? FACTOR(CLK_TOP_UNIVPLL_192M_D2, "univpll_192m_d2",
> > "univpll", 1, 26),
> > +???? FACTOR(CLK_TOP_UNIVPLL_192M_D4, "univpll_192m_d4",
> > "univpll", 1, 52),
> > +???? FACTOR(CLK_TOP_UNIVPLL_192M_D8, "univpll_192m_d8",
> > "univpll", 1, 104),
> > +???? FACTOR(CLK_TOP_UNIVPLL_192M_D10, "univpll_192m_d10",
> > "univpll", 1, 130),
> > +???? FACTOR(CLK_TOP_UNIVPLL_192M_D16, "univpll_192m_d16",
> > "univpll", 1, 208),
> > +???? FACTOR(CLK_TOP_UNIVPLL_192M_D32, "univpll_192m_d32",
> > "univpll", 1, 416),
> > +???? FACTOR(CLK_TOP_APLL1_D2, "apll1_d2", "apll1", 1, 2),
> > +???? FACTOR(CLK_TOP_APLL1_D4, "apll1_d4", "apll1", 1, 4),
> > +???? FACTOR(CLK_TOP_APLL1_D8, "apll1_d8", "apll1", 1, 8),
> > +???? FACTOR(CLK_TOP_APLL1_D3, "apll1_d3", "apll1", 1, 3),
> > +???? FACTOR(CLK_TOP_APLL2_D2, "apll2_d2", "apll2", 1, 2),
> > +???? FACTOR(CLK_TOP_APLL2_D4, "apll2_d4", "apll2", 1, 4),
> > +???? FACTOR(CLK_TOP_APLL2_D8, "apll2_d8", "apll2", 1, 8),
> > +???? FACTOR(CLK_TOP_APLL2_D3, "apll2_d3", "apll2", 1, 3),
> > +???? FACTOR(CLK_TOP_MMPLL_D4, "mmpll_d4", "mmpll", 1, 4),
> > +???? FACTOR(CLK_TOP_MMPLL_D4_D2, "mmpll_d4_d2", "mmpll", 1, 8),
> > +???? FACTOR(CLK_TOP_MMPLL_D4_D4, "mmpll_d4_d4", "mmpll", 1, 16),
> > +???? FACTOR(CLK_TOP_VPLL_DPIX, "vpll_dpix", "mmpll", 1, 16),
> > +???? FACTOR(CLK_TOP_MMPLL_D5, "mmpll_d5", "mmpll", 1, 5),
> > +???? FACTOR(CLK_TOP_MMPLL_D5_D2, "mmpll_d5_d2", "mmpll", 1, 10),
> > +???? FACTOR(CLK_TOP_MMPLL_D5_D4, "mmpll_d5_d4", "mmpll", 1, 20),
> > +???? FACTOR(CLK_TOP_MMPLL_D6, "mmpll_d6", "mmpll", 1, 6),
> > +???? FACTOR(CLK_TOP_MMPLL_D6_D2, "mmpll_d6_d2", "mmpll", 1, 12),
> > +???? FACTOR(CLK_TOP_MMPLL_D7, "mmpll_d7", "mmpll", 1, 7),
> > +???? FACTOR(CLK_TOP_MMPLL_D9, "mmpll_d9", "mmpll", 1, 9),
> > +???? FACTOR(CLK_TOP_TVDPLL1_D2, "tvdpll1_d2", "tvdpll1", 1, 2),
> > +???? FACTOR(CLK_TOP_TVDPLL1_D4, "tvdpll1_d4", "tvdpll1", 1, 4),
> > +???? FACTOR(CLK_TOP_TVDPLL1_D8, "tvdpll1_d8", "tvdpll1", 1, 8),
> > +???? FACTOR(CLK_TOP_TVDPLL1_D16, "tvdpll1_d16", "tvdpll1", 92,
> > 1473),
> > +???? FACTOR(CLK_TOP_TVDPLL2_D2, "tvdpll2_d2", "tvdpll2", 1, 2),
> > +???? FACTOR(CLK_TOP_TVDPLL2_D4, "tvdpll2_d4", "tvdpll2", 1, 4),
> > +???? FACTOR(CLK_TOP_TVDPLL2_D8, "tvdpll2_d8", "tvdpll2", 1, 8),
> > +???? FACTOR(CLK_TOP_TVDPLL2_D16, "tvdpll2_d16", "tvdpll2", 92,
> > 1473),
> > +???? FACTOR(CLK_TOP_ETHPLL_D2, "ethpll_d2", "ethpll", 1, 2),
> > +???? FACTOR(CLK_TOP_ETHPLL_D8, "ethpll_d8", "ethpll", 1, 8),
> > +???? FACTOR(CLK_TOP_ETHPLL_D10, "ethpll_d10", "ethpll", 1, 10),
> > +???? FACTOR(CLK_TOP_MSDCPLL_D2, "msdcpll_d2", "msdcpll", 1, 2),
> > +???? FACTOR(CLK_TOP_UFSPLL_D2, "ufspll_d2", "ufspll", 1, 2),
> > +???? FACTOR(CLK_TOP_F26M_CK_D2, "f26m_d2", "clk26m", 1, 2),
> > +???? FACTOR(CLK_TOP_OSC_D2, "osc_d2", "ulposc", 1, 2),
> > +???? FACTOR(CLK_TOP_OSC_D4, "osc_d4", "ulposc", 1, 4),
> > +???? FACTOR(CLK_TOP_OSC_D8, "osc_d8", "ulposc", 1, 8),
> > +???? FACTOR(CLK_TOP_OSC_D16, "osc_d16", "ulposc", 61, 973),
> > +???? FACTOR(CLK_TOP_OSC_D3, "osc_d3", "ulposc", 1, 3),
> > +???? FACTOR(CLK_TOP_OSC_D7, "osc_d7", "ulposc", 1, 7),
> > +???? FACTOR(CLK_TOP_OSC_D10, "osc_d10", "ulposc", 1, 10),
> > +???? FACTOR(CLK_TOP_OSC_D20, "osc_d20", "ulposc", 1, 20),
> > +};
> > +
> > +static const char * const ap2conn_host_parents[] = {
> > +???? "clk26m",
> > +???? "mainpll_d7_d4"
> > +};
> > +
> > +static const char * const apll_m_parents[] = {
> > +???? "aud_1_sel",
> > +???? "aud_2_sel"
> > +};
> > +
> > +static const char * const aud_1_parents[] = {
> > +???? "clk26m",
> > +???? "apll1"
> > +};
> > +
> > +static const char * const aud_2_parents[] = {
> > +???? "clk26m",
> > +???? "apll2"
> > +};
> > +
> > +static const char * const mfg_sel_mfgpll_parents[] = {
> > +???? "mfg_ref_sel",
> > +???? "mfgpll"
> > +};
> > +
> > +static const char * const pwm_parents[] = {
> > +???? "clk26m",
> > +???? "univpll_d4_d8"
> > +};
> > +
> > +static const char * const snps_eth_250m_parents[] = {
> > +???? "clk26m",
> > +???? "ethpll_d2"
> > +};
> > +
> > +static const char * const snps_eth_50m_rmii_parents[] = {
> > +???? "clk26m",
> > +???? "ethpll_d10"
> > +};
> > +
> > +static const char * const uart_parents[] = {
> > +???? "clk26m",
> > +???? "univpll_d6_d8"
> > +};
> > +
> > +static const char * const atb_parents[] = {
> > +???? "clk26m",
> > +???? "mainpll_d4_d2",
> > +???? "mainpll_d5_d2"
> > +};
> > +
> > +static const char * const aud_intbus_parents[] = {
> > +???? "clk26m",
> > +???? "mainpll_d4_d4",
> > +???? "mainpll_d7_d4"
> > +};
> > +
> > +static const char * const msdc5hclk_parents[] = {
> > +???? "clk26m",
> > +???? "mainpll_d4_d2",
> > +???? "mainpll_d6_d2"
> > +};
> > +
> > +static const char * const pcie_mac_tl_parents[] = {
> > +???? "clk26m",
> > +???? "mainpll_d4_d4",
> > +???? "univpll_d5_d4"
> > +};
> > +
> > +static const char * const pll_dpix_parents[] = {
> > +???? "clk26m",
> > +???? "vpll_dpix",
> > +???? "mmpll_d4_d4"
> > +};
> > +
> > +static const char * const usb_parents[] = {
> > +???? "clk26m",
> > +???? "univpll_d5_d4",
> > +???? "univpll_d6_d4"
> > +};
> > +
> > +static const char * const vdstx_dg_cts_parents[] = {
> > +???? "clk26m",
> > +???? "lvdstx_dg_cts",
> > +???? "univpll_d7_d3"
> > +};
> > +
> > +static const char * const audio_h_parents[] = {
> > +???? "clk26m",
> > +???? "univpll_d7_d2",
> > +???? "apll1",
> > +???? "apll2"
> > +};
> > +
> > +static const char * const aud_engen1_parents[] = {
> > +???? "clk26m",
> > +???? "apll1_d2",
> > +???? "apll1_d4",
> > +???? "apll1_d8"
> > +};
> > +
> > +static const char * const aud_engen2_parents[] = {
> > +???? "clk26m",
> > +???? "apll2_d2",
> > +???? "apll2_d4",
> > +???? "apll2_d8"
> > +};
> > +
> > +static const char * const axi_peri_parents[] = {
> > +???? "clk26m",
> > +???? "mainpll_d4_d4",
> > +???? "mainpll_d7_d2",
> > +???? "osc_d4"
> > +};
> > +
> > +static const char * const axi_u_parents[] = {
> > +???? "clk26m",
> > +???? "mainpll_d4_d8",
> > +???? "mainpll_d7_d4",
> > +???? "osc_d8"
> > +};
> > +
> > +static const char * const camtm_parents[] = {
> > +???? "clk26m",
> > +???? "osc_d2",
> > +???? "univpll_d6_d2",
> > +???? "univpll_d6_d4"
> > +};
> > +
> > +static const char * const dsi_occ_parents[] = {
> > +???? "clk26m",
> > +???? "univpll_d6_d2",
> > +???? "univpll_d5_d2",
> > +???? "univpll_d4_d2"
> > +};
> > +
> > +static const char * const dxcc_parents[] = {
> > +???? "clk26m",
> > +???? "mainpll_d4_d8",
> > +???? "mainpll_d4_d4",
> > +???? "mainpll_d4_d2"
> > +};
> > +
> > +static const char * const i2c_parents[] = {
> > +???? "clk26m",
> > +???? "mainpll_d4_d8",
> > +???? "univpll_d5_d4",
> > +???? "mainpll_d4_d4"
> > +};
> > +
> > +static const char * const mcupm_parents[] = {
> > +???? "clk26m",
> > +???? "univpll_d6_d2",
> > +???? "mainpll_d5_d2",
> > +???? "mainpll_d6_d2"
> > +};
> > +
> > +static const char * const mfg_ref_parents[] = {
> > +???? "clk26m",
> > +???? "mainpll_d6_d2",
> > +???? "mainpll_d6",
> > +???? "mainpll_d5_d2"
> > +};
> > +
> > +static const char * const msdc30_h_parents[] = {
> > +???? "clk26m",
> > +???? "msdcpll_d2",
> > +???? "mainpll_d4_d4",
> > +???? "mainpll_d6_d4"
> > +};
> > +
> > +static const char * const msdc_macro_p_parents[] = {
> > +???? "clk26m",
> > +???? "msdcpll",
> > +???? "mmpll_d5_d4",
> > +???? "univpll_d4_d2"
> > +};
> > +
> > +static const char * const snps_eth_62p4m_ptp_parents[] = {
> > +???? "clk26m",
> > +???? "ethpll_d8",
> > +???? "apll1_d3",
> > +???? "apll2_d3"
> > +};
> > +
> > +static const char * const ufs_mbist_parents[] = {
> > +???? "clk26m",
> > +???? "mainpll_d4_d2",
> > +???? "univpll_d4_d2",
> > +???? "ufspll_d2"
> > +};
> > +
> > +static const char * const aes_msdcfde_parents[] = {
> > +???? "clk26m",
> > +???? "mainpll_d4_d2",
> > +???? "mainpll_d6",
> > +???? "mainpll_d4_d4",
> > +???? "msdcpll"
> > +};
> > +
> > +static const char * const bus_aximem_parents[] = {
> > +???? "clk26m",
> > +???? "mainpll_d7_d2",
> > +???? "mainpll_d5_d2",
> > +???? "mainpll_d4_d2",
> > +???? "mainpll_d6"
> > +};
> > +
> > +static const char * const dp_parents[] = {
> > +???? "clk26m",
> > +???? "tvdpll1_d16",
> > +???? "tvdpll1_d8",
> > +???? "tvdpll1_d4",
> > +???? "tvdpll1_d2"
> > +};
> > +
> > +static const char * const msdc30_parents[] = {
> > +???? "clk26m",
> > +???? "univpll_d6_d2",
> > +???? "mainpll_d6_d2",
> > +???? "mainpll_d7_d2",
> > +???? "msdcpll_d2"
> > +};
> > +
> > +static const char * const ecc_parents[] = {
> > +???? "clk26m",
> > +???? "univpll_d6_d2",
> > +???? "univpll_d4_d2",
> > +???? "univpll_d6",
> > +???? "mainpll_d4",
> > +???? "univpll_d4"
> > +};
> > +
> > +static const char * const emi_n_parents[] = {
> > +???? "clk26m",
> > +???? "osc_d2",
> > +???? "mainpll_d9",
> > +???? "mainpll_d6",
> > +???? "mainpll_d5",
> > +???? "emipll"
> > +};
> > +
> > +static const char * const sr_pka_parents[] = {
> > +???? "clk26m",
> > +???? "mainpll_d4_d4",
> > +???? "mainpll_d4_d2",
> > +???? "mainpll_d7",
> > +???? "mainpll_d6",
> > +???? "mainpll_d5"
> > +};
> > +
> > +static const char * const aes_ufsfde_parents[] = {
> > +???? "clk26m",
> > +???? "mainpll_d4",
> > +???? "mainpll_d4_d2",
> > +???? "mainpll_d6",
> > +???? "mainpll_d4_d4",
> > +???? "univpll_d4_d2",
> > +???? "univpll_d6"
> > +};
> > +
> > +static const char * const axi_parents[] = {
> > +???? "clk26m",
> > +???? "mainpll_d4_d4",
> > +???? "mainpll_d7_d2",
> > +???? "mainpll_d4_d2",
> > +???? "mainpll_d5_d2",
> > +???? "mainpll_d6_d2",
> > +???? "osc_d4"
> > +};
> > +
> > +static const char * const disp_pwm_parents[] = {
> > +???? "clk26m",
> > +???? "univpll_d6_d4",
> > +???? "osc_d2",
> > +???? "osc_d4",
> > +???? "osc_d16",
> > +???? "univpll_d5_d4",
> > +???? "mainpll_d4_d4"
> > +};
> > +
> > +static const char * const edp_parents[] = {
> > +???? "clk26m",
> > +???? "tvdpll2_d16",
> > +???? "tvdpll2_d8",
> > +???? "tvdpll2_d4",
> > +???? "tvdpll2_d2"
> > +};
> > +
> > +static const char * const gcpu_parents[] = {
> > +???? "clk26m",
> > +???? "mainpll_d6",
> > +???? "mainpll_d4_d2",
> > +???? "univpll_d4_d2",
> > +???? "univpll_d5_d2",
> > +???? "univpll_d5_d4",
> > +???? "univpll_d6"
> > +};
> > +
> > +static const char * const msdc50_0_parents[] = {
> > +???? "clk26m",
> > +???? "msdcpll",
> > +???? "msdcpll_d2",
> > +???? "mainpll_d6_d2",
> > +???? "mainpll_d4_d4",
> > +???? "mainpll_d6",
> > +???? "univpll_d4_d4"
> > +};
> > +
> > +static const char * const ufs_parents[] = {
> > +???? "clk26m",
> > +???? "mainpll_d4_d8",
> > +???? "mainpll_d4_d4",
> > +???? "mainpll_d5_d2",
> > +???? "mainpll_d6_d2",
> > +???? "univpll_d6_d2",
> > +???? "msdcpll_d2"
> > +};
> > +
> > +static const char * const dsp_parents[] = {
> > +???? "clk26m",
> > +???? "osc_d4",
> > +???? "osc_d3",
> > +???? "osc_d2",
> > +???? "univpll_d7_d2",
> > +???? "univpll_d6_d2",
> > +???? "mainpll_d6",
> > +???? "univpll_d5"
> > +};
> > +
> > +static const char * const mem_sub_peri_u_parents[] = {
> > +???? "clk26m",
> > +???? "univpll_d4_d4",
> > +???? "mainpll_d5_d2",
> > +???? "mainpll_d4_d2",
> > +???? "mainpll_d6",
> > +???? "mainpll_d5",
> > +???? "univpll_d5",
> > +???? "mainpll_d4"
> > +};
> > +
> > +static const char * const seninf_parents[] = {
> > +???? "clk26m",
> > +???? "osc_d2",
> > +???? "univpll_d6_d2",
> > +???? "mainpll_d4_d2",
> > +???? "univpll_d4_d2",
> > +???? "mmpll_d7",
> > +???? "univpll_d6",
> > +???? "univpll_d5"
> > +};
> > +
> > +static const char * const sflash_parents[] = {
> > +???? "clk26m",
> > +???? "mainpll_d7_d8",
> > +???? "univpll_d6_d8",
> > +???? "mainpll_d7_d4",
> > +???? "mainpll_d6_d4",
> > +???? "univpll_d6_d4",
> > +???? "univpll_d7_d3",
> > +???? "univpll_d5_d4"
> > +};
> > +
> > +static const char * const spi_parents[] = {
> > +???? "clk26m",
> > +???? "univpll_d6_d2",
> > +???? "univpll_192m",
> > +???? "mainpll_d6_d2",
> > +???? "univpll_d4_d4",
> > +???? "mainpll_d4_d4",
> > +???? "univpll_d5_d4",
> > +???? "univpll_d6_d4"
> > +};
> > +
> > +static const char * const img1_parents[] = {
> > +???? "clk26m",
> > +???? "univpll_d4",
> > +???? "mmpll_d5",
> > +???? "mmpll_d6",
> > +???? "univpll_d6",
> > +???? "mmpll_d7",
> > +???? "mmpll_d4_d2",
> > +???? "univpll_d4_d2",
> > +???? "mainpll_d4_d2",
> > +???? "mmpll_d6_d2",
> > +???? "mmpll_d5_d2"
> > +};
> > +
> > +static const char * const ipe_parents[] = {
> > +???? "clk26m",
> > +???? "univpll_d4",
> > +???? "mainpll_d4",
> > +???? "mmpll_d6",
> > +???? "univpll_d6",
> > +???? "mainpll_d6",
> > +???? "mmpll_d4_d2",
> > +???? "univpll_d4_d2",
> > +???? "mainpll_d4_d2",
> > +???? "mmpll_d6_d2",
> > +???? "mmpll_d5_d2"
> > +};
> > +
> > +static const char * const mem_sub_parents[] = {
> > +???? "clk26m",
> > +???? "univpll_d4_d4",
> > +???? "mainpll_d6_d2",
> > +???? "mainpll_d5_d2",
> > +???? "mainpll_d4_d2",
> > +???? "mainpll_d6",
> > +???? "mmpll_d7",
> > +???? "mainpll_d5",
> > +???? "univpll_d5",
> > +???? "mainpll_d4",
> > +???? "univpll_d4"
> > +};
> > +
> > +static const char * const cam_parents[] = {
> > +???? "clk26m",
> > +???? "mainpll_d4",
> > +???? "mmpll_d4",
> > +???? "univpll_d4",
> > +???? "univpll_d5",
> > +???? "mmpll_d7",
> > +???? "mmpll_d6",
> > +???? "univpll_d6",
> > +???? "univpll_d4_d2",
> > +???? "mmpll_d9",
> > +???? "mainpll_d4_d2",
> > +???? "osc_d2"
> > +};
> > +
> > +static const char * const mmsys_parents[] = {
> > +???? "clk26m",
> > +???? "mainpll_d5_d2",
> > +???? "univpll_d5_d2",
> > +???? "mainpll_d4_d2",
> > +???? "univpll_d4_d2",
> > +???? "mainpll_d6",
> > +???? "univpll_d6",
> > +???? "mmpll_d6",
> > +???? "tvdpll1",
> > +???? "tvdpll2",
> > +???? "univpll_d4",
> > +???? "mmpll_d4"
> > +};
> > +
> > +static const char * const mminfra_parents[] = {
> > +???? "clk26m",
> > +???? "osc_d2",
> > +???? "mainpll_d5_d2",
> > +???? "mmpll_d6_d2",
> > +???? "mainpll_d4_d2",
> > +???? "mmpll_d4_d2",
> > +???? "mainpll_d6",
> > +???? "mmpll_d7",
> > +???? "univpll_d6",
> > +???? "mainpll_d5",
> > +???? "mmpll_d6",
> > +???? "univpll_d5",
> > +???? "mainpll_d4",
> > +???? "univpll_d4",
> > +???? "mmpll_d4",
> > +???? "emipll"
> > +};
> > +
> > +static const char * const vdec_parents[] = {
> > +???? "clk26m",
> > +???? "univpll_192m_d2",
> > +???? "univpll_d5_d4",
> > +???? "mainpll_d5",
> > +???? "mainpll_d5_d2",
> > +???? "mmpll_d6_d2",
> > +???? "univpll_d5_d2",
> > +???? "mainpll_d4_d2",
> > +???? "univpll_d4_d2",
> > +???? "univpll_d7",
> > +???? "mmpll_d7",
> > +???? "mmpll_d6",
> > +???? "univpll_d6",
> > +???? "mainpll_d4",
> > +???? "univpll_d4",
> > +???? "mmpll_d5_d2"
> > +};
> > +
> > +static const char * const venc_parents[] = {
> > +???? "clk26m",
> > +???? "mmpll_d4_d2",
> > +???? "mainpll_d6",
> > +???? "univpll_d4_d2",
> > +???? "mainpll_d4_d2",
> > +???? "univpll_d6",
> > +???? "mmpll_d6",
> > +???? "mainpll_d5_d2",
> > +???? "mainpll_d6_d2",
> > +???? "mmpll_d9",
> > +???? "mmpll_d4",
> > +???? "mainpll_d4",
> > +???? "univpll_d4",
> > +???? "univpll_d5",
> > +???? "univpll_d5_d2",
> > +???? "mainpll_d5"
> > +};
> > +
> > +static const struct mtk_mux top_muxes[] = {
> > +???? /* CLK_CFG_0 */
> > +???? MUX_CLR_SET_UPD(CLK_TOP_AXI_SEL, "axi_sel",
> > +???????????????????? axi_parents, 0x010, 0x014, 0x018, 0, 3,
> > 0x04, 0),
> > +???? MUX_CLR_SET_UPD(CLK_TOP_AXI_PERI_SEL, "axi_peri_sel",
> > +???????????????????? axi_peri_parents, 0x010, 0x014, 0x018,
> > +???????????????????? 8, 2, 0x04, 1),
> > +???? MUX_CLR_SET_UPD(CLK_TOP_AXI_U_SEL, "axi_u_sel",
> > +???????????????????? axi_u_parents, 0x010, 0x014, 0x018,
> > +???????????????????? 16, 2, 0x04, 2),
> > +???? MUX_CLR_SET_UPD(CLK_TOP_BUS_AXIMEM_SEL, "bus_aximem_sel",
> > +???????????????????? bus_aximem_parents, 0x010, 0x014, 0x018,
> > +???????????????????? 24, 3, 0x04, 3),
> > +???? /* CLK_CFG_1 */
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_DISP0_SEL, "disp0_sel",
> > +????????????????????????? mmsys_parents, 0x020, 0x024, 0x028,
> > +????????????????????????? 0, 4, 7, 0x04, 4),
> > +???? MUX_CLR_SET_UPD(CLK_TOP_MMINFRA_SEL, "mminfra_sel",
> > +???????????????????? mminfra_parents, 0x020, 0x024, 0x028,
> > +???????????????????? 8, 4, 0x04, 5),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_UART_SEL, "uart_sel",
> > +????????????????????????? uart_parents, 0x020, 0x024, 0x028,
> > +????????????????????????? 16, 1, 23, 0x04, 6),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_SPI0_SEL, "spi0_sel",
> > +????????????????????????? spi_parents, 0x020, 0x024, 0x028,
> > +????????????????????????? 24, 3, 31, 0x04, 7),
> > +???? /* CLK_CFG_2 */
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_SPI1_SEL, "spi1_sel",
> > +????????????????????????? spi_parents, 0x030, 0x034, 0x038,
> > +????????????????????????? 0, 3, 7, 0x04, 8),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_SPI2_SEL, "spi2_sel",
> > +????????????????????????? spi_parents, 0x030, 0x034, 0x038,
> > +????????????????????????? 8, 3, 15, 0x04, 9),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_SPI3_SEL, "spi3_sel",
> > +????????????????????????? spi_parents, 0x030, 0x034, 0x038,
> > +????????????????????????? 16, 3, 23, 0x04, 10),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_SPI4_SEL, "spi4_sel",
> > +????????????????????????? spi_parents, 0x030, 0x034, 0x038,
> > +????????????????????????? 24, 3, 31, 0x04, 11),
> > +???? /* CLK_CFG_3 */
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_SPI5_SEL, "spi5_sel",
> > +????????????????????????? spi_parents, 0x040, 0x044, 0x048,
> > +????????????????????????? 0, 3, 7, 0x04, 12),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC_MACRO_0P_SEL,
> > "msdc_macro_0p_sel",
> > +????????????????????????? msdc_macro_p_parents, 0x040, 0x044,
> > 0x048,
> > +????????????????????????? 8, 2, 15, 0x04, 13),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC50_0_HCLK_SEL,
> > "msdc5hclk_sel",
> > +????????????????????????? msdc5hclk_parents, 0x040, 0x044, 0x048,
> > +????????????????????????? 16, 2, 23, 0x04, 14),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC50_0_SEL, "msdc50_0_sel",
> > +????????????????????????? msdc50_0_parents, 0x040, 0x044, 0x048,
> > +????????????????????????? 24, 3, 31, 0x04, 15),
> > +???? /* CLK_CFG_4 */
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_AES_MSDCFDE_SEL,
> > "aes_msdcfde_sel",
> > +????????????????????????? aes_msdcfde_parents, 0x050, 0x054,
> > 0x058,
> > +????????????????????????? 0, 3, 7, 0x04, 16),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC_MACRO_1P_SEL,
> > "msdc_macro_1p_sel",
> > +????????????????????????? msdc_macro_p_parents, 0x050, 0x054,
> > 0x058,
> > +????????????????????????? 8, 2, 15, 0x04, 17),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC30_1_SEL, "msdc30_1_sel",
> > +????????????????????????? msdc30_parents, 0x050, 0x054, 0x058,
> > +????????????????????????? 16, 3, 23, 0x04, 18),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC30_1_HCLK_SEL,
> > "msdc30_1_h_sel",
> > +????????????????????????? msdc30_h_parents, 0x050, 0x054, 0x058,
> > +????????????????????????? 24, 2, 31, 0x04, 19),
> > +???? /* CLK_CFG_5 */
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC_MACRO_2P_SEL,
> > "msdc_macro_2p_sel",
> > +????????????????????????? msdc_macro_p_parents, 0x060, 0x064,
> > 0x068,
> > +????????????????????????? 0, 2, 7, 0x04, 20),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC30_2_SEL, "msdc30_2_sel",
> > +????????????????????????? msdc30_parents, 0x060, 0x064, 0x068,
> > +????????????????????????? 8, 3, 15, 0x04, 21),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC30_2_HCLK_SEL,
> > "msdc30_2_h_sel",
> > +????????????????????????? msdc30_h_parents, 0x060, 0x064, 0x068,
> > +????????????????????????? 16, 2, 23, 0x04, 22),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_INTBUS_SEL,
> > "aud_intbus_sel",
> > +????????????????????????? aud_intbus_parents, 0x060, 0x064,
> > 0x068,
> > +????????????????????????? 24, 2, 31, 0x04, 23),
> > +???? /* CLK_CFG_6 */
> > +???? MUX_CLR_SET_UPD(CLK_TOP_ATB_SEL, "atb_sel",
> > +???????????????????? atb_parents, 0x070, 0x074, 0x078, 0, 2,
> > 0x04, 24),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_DISP_PWM_SEL, "disp_pwm_sel",
> > +????????????????????????? disp_pwm_parents, 0x070, 0x074, 0x078,
> > +????????????????????????? 8, 3, 15, 0x04, 25),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_TOP_P0_SEL, "usb_p0_sel",
> > +????????????????????????? usb_parents, 0x070, 0x074, 0x078,
> > +????????????????????????? 16, 2, 23, 0x04, 26),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_XHCI_P0_SEL,
> > "ssusb_xhci_p0_sel",
> > +????????????????????????? usb_parents, 0x070, 0x074, 0x078,
> > +????????????????????????? 24, 2, 31, 0x04, 27),
> > +???? /* CLK_CFG_7 */
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_TOP_P1_SEL, "usb_p1_sel",
> > +????????????????????????? usb_parents, 0x080, 0x084, 0x088,
> > +????????????????????????? 0, 2, 7, 0x04, 28),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_XHCI_P1_SEL,
> > "ssusb_xhci_p1_sel",
> > +????????????????????????? usb_parents, 0x080, 0x084, 0x088,
> > +????????????????????????? 8, 2, 15, 0x04, 29),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_TOP_P2_SEL, "usb_p2_sel",
> > +????????????????????????? usb_parents, 0x080, 0x084, 0x088,
> > +????????????????????????? 16, 2, 23, 0x04, 30),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_XHCI_P2_SEL,
> > "ssusb_xhci_p2_sel",
> > +????????????????????????? usb_parents, 0x080, 0x084, 0x088,
> > +????????????????????????? 24, 2, 31, 0x08, 0),
> > +???? /* CLK_CFG_8 */
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_TOP_P3_SEL, "usb_p3_sel",
> > +????????????????????????? usb_parents, 0x090, 0x094, 0x098,
> > +????????????????????????? 0, 2, 7, 0x08, 1),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_XHCI_P3_SEL,
> > "ssusb_xhci_p3_sel",
> > +????????????????????????? usb_parents, 0x090, 0x094, 0x098,
> > +????????????????????????? 8, 2, 15, 0x08, 2),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_TOP_P4_SEL, "usb_p4_sel",
> > +????????????????????????? usb_parents, 0x090, 0x094, 0x098,
> > +????????????????????????? 16, 2, 23, 0x08, 3),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_XHCI_P4_SEL,
> > "ssusb_xhci_p4_sel",
> > +????????????????????????? usb_parents, 0x090, 0x094, 0x098,
> > +????????????????????????? 24, 2, 31, 0x08, 4),
> > +???? /* CLK_CFG_9 */
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_I2C_SEL, "i2c_sel",
> > +????????????????????????? i2c_parents, 0x0a0, 0x0a4, 0x0a8,
> > +????????????????????????? 0, 2, 7, 0x08, 5),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_SENINF_SEL, "seninf_sel",
> > +????????????????????????? seninf_parents, 0x0a0, 0x0a4, 0x0a8,
> > +????????????????????????? 8, 3, 15, 0x08, 6),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_SENINF1_SEL, "seninf1_sel",
> > +????????????????????????? seninf_parents, 0x0a0, 0x0a4, 0x0a8,
> > +????????????????????????? 16, 3, 23, 0x08, 7),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_ENGEN1_SEL,
> > "aud_engen1_sel",
> > +????????????????????????? aud_engen1_parents, 0x0a0, 0x0a4,
> > 0x0a8,
> > +????????????????????????? 24, 2, 31, 0x08, 8),
> > +???? /* CLK_CFG_10 */
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_ENGEN2_SEL,
> > "aud_engen2_sel",
> > +????????????????????????? aud_engen2_parents, 0x0b0, 0x0b4,
> > 0x0b8,
> > +????????????????????????? 0, 2, 7, 0x08, 9),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_AES_UFSFDE_SEL,
> > "aes_ufsfde_sel",
> > +????????????????????????? aes_ufsfde_parents, 0x0b0, 0x0b4,
> > 0x0b8,
> > +????????????????????????? 8, 3, 15, 0x08, 10),
> > +???? MUX_CLR_SET_UPD(CLK_TOP_U_SEL, "ufs_sel",
> > +???????????????????? ufs_parents, 0x0b0, 0x0b4, 0x0b8,
> > +???????????????????? 16, 3, 0x08, 11),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_U_MBIST_SEL, "ufs_mbist_sel",
> > +????????????????????????? ufs_mbist_parents, 0x0b0, 0x0b4, 0x0b8,
> > +????????????????????????? 24, 2, 31, 0x08, 12),
> > +???? /* CLK_CFG_11 */
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_1_SEL, "aud_1_sel",
> > +????????????????????????? aud_1_parents, 0x0c0, 0x0c4, 0x0c8,
> > +????????????????????????? 0, 1, 7, 0x08, 13),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_2_SEL, "aud_2_sel",
> > +????????????????????????? aud_2_parents, 0x0c0, 0x0c4, 0x0c8,
> > +????????????????????????? 8, 1, 15, 0x08, 14),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_VENC_SEL, "venc_sel",
> > +????????????????????????? venc_parents, 0x0c0, 0x0c4, 0x0c8,
> > +????????????????????????? 16, 4, 23, 0x08, 15),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_VDEC_SEL, "vdec_sel",
> > +????????????????????????? vdec_parents, 0x0c0, 0x0c4, 0x0c8,
> > +????????????????????????? 24, 4, 31, 0x08, 16),
> > +???? /* CLK_CFG_12 */
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_PWM_SEL, "pwm_sel",
> > +????????????????????????? pwm_parents, 0x0d0, 0x0d4, 0x0d8,
> > +????????????????????????? 0, 1, 7, 0x08, 17),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_AUDIO_H_SEL, "audio_h_sel",
> > +????????????????????????? audio_h_parents, 0x0d0, 0x0d4, 0x0d8,
> > +????????????????????????? 8, 2, 15, 0x08, 18),
> > +???? MUX_CLR_SET_UPD(CLK_TOP_MCUPM_SEL, "mcupm_sel",
> > +???????????????????? mcupm_parents, 0x0d0, 0x0d4, 0x0d8,
> > +???????????????????? 16, 2, 0x08, 19),
> > +???? MUX_CLR_SET_UPD(CLK_TOP_MEM_SUB_SEL, "mem_sub_sel",
> > +???????????????????? mem_sub_parents, 0x0d0, 0x0d4, 0x0d8,
> > +???????????????????? 24, 4, 0x08, 20),
> > +???? /* CLK_CFG_13 */
> > +???? MUX_CLR_SET_UPD(CLK_TOP_MEM_SUB_PERI_SEL,
> > "mem_sub_peri_sel",
> > +???????????????????? mem_sub_peri_u_parents, 0x0e0, 0x0e4, 0x0e8,
> > +???????????????????? 0, 3, 0x08, 21),
> > +???? MUX_CLR_SET_UPD(CLK_TOP_MEM_SUB_U_SEL, "mem_sub_u_sel",
> > +???????????????????? mem_sub_peri_u_parents, 0x0e0, 0x0e4, 0x0e8,
> > +???????????????????? 8, 3, 0x08, 22),
> > +???? MUX_CLR_SET_UPD(CLK_TOP_EMI_N_SEL, "emi_n_sel",
> > +???????????????????? emi_n_parents, 0x0e0, 0x0e4, 0x0e8,
> > +???????????????????? 16, 3, 0x08, 23),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_DSI_OCC_SEL, "dsi_occ_sel",
> > +????????????????????????? dsi_occ_parents, 0x0e0, 0x0e4, 0x0e8,
> > +????????????????????????? 24, 2, 31, 0x08, 24),
> > +???? /* CLK_CFG_14 */
> > +???? MUX_CLR_SET_UPD(CLK_TOP_AP2CONN_HOST_SEL,
> > "ap2conn_host_sel",
> > +???????????????????? ap2conn_host_parents, 0x0f0, 0x0f4, 0x0f8,
> > +???????????????????? 0, 1, 0x08, 25),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_IMG1_SEL, "img1_sel",
> > +????????????????????????? img1_parents, 0x0f0, 0x0f4, 0x0f8,
> > +????????????????????????? 8, 4, 15, 0x08, 26),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_IPE_SEL, "ipe_sel",
> > +????????????????????????? ipe_parents, 0x0f0, 0x0f4, 0x0f8,
> > +????????????????????????? 16, 4, 23, 0x08, 27),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_CAM_SEL, "cam_sel",
> > +????????????????????????? cam_parents, 0x0f0, 0x0f4, 0x0f8,
> > +????????????????????????? 24, 4, 31, 0x08, 28),
> > +???? /* CLK_CFG_15 */
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_CAMTM_SEL, "camtm_sel",
> > +????????????????????????? camtm_parents, 0x100, 0x104, 0x108,
> > +????????????????????????? 0, 2, 7, 0x08, 29),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_DSP_SEL, "dsp_sel",
> > +????????????????????????? dsp_parents, 0x100, 0x104, 0x108,
> > +????????????????????????? 8, 3, 15, 0x08, 30),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_SR_PKA_SEL, "sr_pka_sel",
> > +????????????????????????? sr_pka_parents, 0x100, 0x104, 0x108,
> > +????????????????????????? 16, 3, 23, 0x0c, 0),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_DXCC_SEL, "dxcc_sel",
> > +????????????????????????? dxcc_parents, 0x100, 0x104, 0x108,
> > +????????????????????????? 24, 2, 31, 0x0c, 1),
> > +???? /* CLK_CFG_16 */
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_MFG_REF_SEL, "mfg_ref_sel",
> > +????????????????????????? mfg_ref_parents, 0x110, 0x114, 0x118,
> > +????????????????????????? 0, 2, 7, 0x0c, 2),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_MDP0_SEL, "mdp0_sel",
> > +????????????????????????? mmsys_parents, 0x110, 0x114, 0x118,
> > +????????????????????????? 8, 4, 15, 0x0c, 3),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_DP_SEL, "dp_sel",
> > +????????????????????????? dp_parents, 0x110, 0x114, 0x118,
> > +????????????????????????? 16, 3, 23, 0x0c, 4),
> > +???? MUX_CLR_SET_UPD(CLK_TOP_EDP_SEL, "edp_sel",
> > +???????????????????? edp_parents, 0x110, 0x114, 0x118,
> > +???????????????????? 24, 3, 0x0c, 5),
> > +???? /* CLK_CFG_17 */
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_EDP_FAVT_SEL, "edp_favt_sel",
> > +????????????????????????? edp_parents, 0x180, 0x184, 0x188,
> > +????????????????????????? 0, 3, 7, 0x0c, 6),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_250M_SEL,
> > "snps_eth_250m_sel",
> > +????????????????????????? snps_eth_250m_parents, 0x180, 0x184,
> > 0x188,
> > +????????????????????????? 8, 1, 15, 0x0c, 7),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_62P4M_PTP_SEL,
> > +????????????????????????? "snps_eth_62p4m_ptp_sel",
> > +????????????????????????? snps_eth_62p4m_ptp_parents,
> > +????????????????????????? 0x180, 0x184, 0x188, 16, 2, 23, 0x0c,
> > 8),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_50M_RMII_SEL,
> > +????????????????????????? "snps_eth_50m_rmii_sel",
> > +????????????????????????? snps_eth_50m_rmii_parents,
> > +????????????????????????? 0x180, 0x184, 0x188, 24, 1, 31, 0x0c,
> > 9),
> > +???? /* CLK_CFG_18 */
> > +???? MUX_CLR_SET_UPD(CLK_TOP_SFLASH_SEL, "sflash_sel",
> > +???????????????????? sflash_parents, 0x190, 0x194, 0x198,
> > +???????????????????? 0, 3, 0x0c, 10),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_GCPU_SEL, "gcpu_sel",
> > +????????????????????????? gcpu_parents, 0x190, 0x194, 0x198,
> > +????????????????????????? 8, 3, 15, 0x0c, 11),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_MAC_TL_SEL, "pcie_mac_tl_sel",
> > +????????????????????????? pcie_mac_tl_parents, 0x190, 0x194,
> > 0x198,
> > +????????????????????????? 16, 2, 23, 0x0c, 12),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_VDSTX_DG_CTS_SEL,
> > "vdstx_dg_cts_sel",
> > +????????????????????????? vdstx_dg_cts_parents, 0x190, 0x194,
> > 0x198,
> > +????????????????????????? 24, 2, 31, 0x0c, 13),
> > +???? /* CLK_CFG_19 */
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_PLL_DPIX_SEL, "pll_dpix_sel",
> > +????????????????????????? pll_dpix_parents, 0x240, 0x244, 0x248,
> > +????????????????????????? 0, 2, 7, 0x0c, 14),
> > +???? MUX_GATE_CLR_SET_UPD(CLK_TOP_ECC_SEL, "ecc_sel",
> > +????????????????????????? ecc_parents, 0x240, 0x244, 0x248,
> > +????????????????????????? 8, 3, 15, 0x0c, 15),
> > +???? /* CLK_MISC_CFG_3 */
> > +???? GATE_CLR_SET_UPD_FLAGS(CLK_TOP_MFG_SEL_MFGPLL,
> > "mfg_sel_mfgpll",
> > +??????????????????????????? mfg_sel_mfgpll_parents,
> > +??????????????????????????? 0x510, 0x514, 0x0518, 16, 1, 0, -1, -
> > 1,
> > +??????????????????????????? CLK_SET_RATE_PARENT |
> > CLK_SET_RATE_NO_REPARENT,
> > +??????????????????????????? mtk_mux_clr_set_upd_ops)
> > +};
> > +
> > +static const struct mtk_composite top_composites[] = {
> > +???? /* CLK_AUDDIV_0 */
> > +???? MUX(CLK_TOP_APLL_I2SIN0_MCK_SEL, "apll_i2sin0_m_sel",
> > +???????? apll_m_parents, 0x0320, 16, 1),
> > +???? MUX(CLK_TOP_APLL_I2SIN1_MCK_SEL, "apll_i2sin1_m_sel",
> > +???????? apll_m_parents, 0x0320, 17, 1),
> > +???? MUX(CLK_TOP_APLL_I2SIN2_MCK_SEL, "apll_i2sin2_m_sel",
> > +???????? apll_m_parents, 0x0320, 18, 1),
> > +???? MUX(CLK_TOP_APLL_I2SIN3_MCK_SEL, "apll_i2sin3_m_sel",
> > +???????? apll_m_parents, 0x0320, 19, 1),
> > +???? MUX(CLK_TOP_APLL_I2SIN4_MCK_SEL, "apll_i2sin4_m_sel",
> > +???????? apll_m_parents, 0x0320, 20, 1),
> > +???? MUX(CLK_TOP_APLL_I2SIN6_MCK_SEL, "apll_i2sin6_m_sel",
> > +???????? apll_m_parents, 0x0320, 21, 1),
> > +???? MUX(CLK_TOP_APLL_I2SOUT0_MCK_SEL, "apll_i2sout0_m_sel",
> > +???????? apll_m_parents, 0x0320, 22, 1),
> > +???? MUX(CLK_TOP_APLL_I2SOUT1_MCK_SEL, "apll_i2sout1_m_sel",
> > +???????? apll_m_parents, 0x0320, 23, 1),
> > +???? MUX(CLK_TOP_APLL_I2SOUT2_MCK_SEL, "apll_i2sout2_m_sel",
> > +???????? apll_m_parents, 0x0320, 24, 1),
> > +???? MUX(CLK_TOP_APLL_I2SOUT3_MCK_SEL, "apll_i2sout3_m_sel",
> > +???????? apll_m_parents, 0x0320, 25, 1),
> > +???? MUX(CLK_TOP_APLL_I2SOUT4_MCK_SEL, "apll_i2sout4_m_sel",
> > +???????? apll_m_parents, 0x0320, 26, 1),
> > +???? MUX(CLK_TOP_APLL_I2SOUT6_MCK_SEL, "apll_i2sout6_m_sel",
> > +???????? apll_m_parents, 0x0320, 27, 1),
> > +???? MUX(CLK_TOP_APLL_FMI2S_MCK_SEL, "apll_fmi2s_m_sel",
> > +???????? apll_m_parents, 0x0320, 28, 1),
> > +???? MUX(CLK_TOP_APLL_TDMOUT_MCK_SEL, "apll_tdmout_m_sel",
> > +???????? apll_m_parents, 0x0320, 29, 1),
> > +???? /* CLK_AUDDIV_2 */
> > +???? DIV_GATE(CLK_TOP_APLL12_CK_DIV_I2SIN0, "apll12_div_i2sin0",
> > +????????????? "apll_i2sin0_m_sel", 0x0320, 0, 0x0328, 8, 0),
> > +???? DIV_GATE(CLK_TOP_APLL12_CK_DIV_I2SIN1, "apll12_div_i2sin1",
> > +????????????? "apll_i2sin1_m_sel", 0x0320, 1, 0x0328, 8, 8),
> > +???? /* CLK_AUDDIV_3 */
> > +???? DIV_GATE(CLK_TOP_APLL12_CK_DIV_I2SOUT0,
> > "apll12_div_i2sout0",
> > +????????????? "apll_i2sout0_m_sel", 0x0320, 6, 0x0334, 8, 16),
> > +???? DIV_GATE(CLK_TOP_APLL12_CK_DIV_I2SOUT1,
> > "apll12_div_i2sout1",
> > +????????????? "apll_i2sout1_m_sel", 0x0320, 7, 0x0334, 8, 24),
> > +???? /* CLK_AUDDIV_5 */
> > +???? DIV_GATE(CLK_TOP_APLL12_CK_DIV_FMI2S, "apll12_div_fmi2s",
> > +????????????? "apll_fmi2s_m_sel", 0x0320, 12, 0x033c, 8, 0),
> > +???? DIV_GATE(CLK_TOP_APLL12_CK_DIV_TDMOUT_M,
> > "apll12_div_tdmout_m",
> > +????????????? "apll_tdmout_m_sel", 0x0320, 13, 0x033c, 8, 8),
> > +???? DIV_GATE(CLK_TOP_APLL12_CK_DIV_TDMOUT_B,
> > "apll12_div_tdmout_b",
> > +????????????? "apll12_div_tdmout_m", 0x0320, 14, 0x033c, 8, 16),
> > +};
> > +
> > +static const struct mtk_gate_regs top_cg_regs = {
> > +???? .set_ofs = 0x514,
> > +???? .clr_ofs = 0x518,
> > +???? .sta_ofs = 0x510,
> > +};
> > +
> > +#define GATE_TOP_FLAGS(_id, _name, _parent, _shift, _flag) { \
> > +???????????? .id = _id,????????????????????????????? \
> > +???????????? .name = _name,????????????????????????? \
> > +???????????? .parent_name = _parent,???????????????? \
> > +???????????? .regs = &top_cg_regs,?????????????????? \
> > +???????????? .shift = _shift,??????????????????????? \
> > +???????????? .flags = _flag,???????????????????????? \
> > +???????????? .ops = &mtk_clk_gate_ops_setclr_inv,??? \
> > +???? }
> > +
> > +#define GATE_TOP(_id, _name, _parent, _shift)??????????????? \
> > +???? GATE_TOP_FLAGS(_id, _name, _parent, _shift, 0)
> > +
> > +static const struct mtk_gate top_clks[] = {
> > +???? GATE_TOP_FLAGS(CLK_TOP_FMCNT_P0_EN, "fmcnt_p0_en",
> > "univpll_192m_d4", 0, CLK_IS_CRITICAL),
> > +???? GATE_TOP_FLAGS(CLK_TOP_FMCNT_P1_EN, "fmcnt_p1_en",
> > "univpll_192m_d4", 1, CLK_IS_CRITICAL),
> > +???? GATE_TOP_FLAGS(CLK_TOP_FMCNT_P2_EN, "fmcnt_p2_en",
> > "univpll_192m_d4", 2, CLK_IS_CRITICAL),
> > +???? GATE_TOP_FLAGS(CLK_TOP_FMCNT_P3_EN, "fmcnt_p3_en",
> > "univpll_192m_d4", 3, CLK_IS_CRITICAL),
> > +???? GATE_TOP_FLAGS(CLK_TOP_FMCNT_P4_EN, "fmcnt_p4_en",
> > "univpll_192m_d4", 4, CLK_IS_CRITICAL),
> > +???? GATE_TOP_FLAGS(CLK_TOP_USB_F26M_CK_EN, "ssusb_f26m",
> > "clk26m", 5, CLK_IS_CRITICAL),
> > +???? GATE_TOP_FLAGS(CLK_TOP_SSPXTP_F26M_CK_EN, "sspxtp_f26m",
> > "clk26m", 6, CLK_IS_CRITICAL),
> > +???? GATE_TOP(CLK_TOP_USB2_PHY_RF_P0_EN, "usb2_phy_rf_p0_en",
> > "clk26m", 7),
> > +???? GATE_TOP(CLK_TOP_USB2_PHY_RF_P1_EN, "usb2_phy_rf_p1_en",
> > "clk26m", 10),
> > +???? GATE_TOP(CLK_TOP_USB2_PHY_RF_P2_EN, "usb2_phy_rf_p2_en",
> > "clk26m", 11),
> > +???? GATE_TOP(CLK_TOP_USB2_PHY_RF_P3_EN, "usb2_phy_rf_p3_en",
> > "clk26m", 12),
> > +???? GATE_TOP(CLK_TOP_USB2_PHY_RF_P4_EN, "usb2_phy_rf_p4_en",
> > "clk26m", 13),
> > +???? GATE_TOP_FLAGS(CLK_TOP_USB2_26M_CK_P0_EN, "usb2_26m_p0_en",
> > "clk26m", 14, CLK_IS_CRITICAL),
> > +???? GATE_TOP_FLAGS(CLK_TOP_USB2_26M_CK_P1_EN, "usb2_26m_p1_en",
> > "clk26m", 15, CLK_IS_CRITICAL),
> > +???? GATE_TOP_FLAGS(CLK_TOP_USB2_26M_CK_P2_EN, "usb2_26m_p2_en",
> > "clk26m", 18, CLK_IS_CRITICAL),
> > +???? GATE_TOP_FLAGS(CLK_TOP_USB2_26M_CK_P3_EN, "usb2_26m_p3_en",
> > "clk26m", 19, CLK_IS_CRITICAL),
> > +???? GATE_TOP_FLAGS(CLK_TOP_USB2_26M_CK_P4_EN, "usb2_26m_p4_en",
> > "clk26m", 20, CLK_IS_CRITICAL),
> 
> In the v1 patch review, Angelo raised a concern about all those USB
> clocks being always-on and got no answer on this matter.
> Could you please explain why they are configured as critical ?
> 
Discuss with USB owner, for MTK platforms, USB driver control some
clocks, so these clocks only on MT8189 and need to set as always-on.

> > +???? GATE_TOP(CLK_TOP_F26M_CK_EN, "pcie_f26m", "clk26m", 21),
> > +???? GATE_TOP_FLAGS(CLK_TOP_AP2CON_EN, "ap2con", "clk26m", 24,
> > CLK_IS_CRITICAL),
> > +???? GATE_TOP_FLAGS(CLK_TOP_EINT_N_EN, "eint_n", "clk26m", 25,
> > CLK_IS_CRITICAL),
> > +???? GATE_TOP_FLAGS(CLK_TOP_TOPCKGEN_FMIPI_CSI_UP26M_CK_EN,
> > +??????????????????? "TOPCKGEN_fmipi_csi_up26m", "osc_d10", 26,
> > CLK_IS_CRITICAL),
> > +???? GATE_TOP_FLAGS(CLK_TOP_EINT_E_EN, "eint_e", "clk26m", 28,
> > CLK_IS_CRITICAL),
> > +???? GATE_TOP_FLAGS(CLK_TOP_EINT_W_EN, "eint_w", "clk26m", 30,
> > CLK_IS_CRITICAL),
> > +???? GATE_TOP_FLAGS(CLK_TOP_EINT_S_EN, "eint_s", "clk26m", 31,
> > CLK_IS_CRITICAL),
> > +};
> > +
> > +/* Register mux notifier for MFG mux */
> > +static int clk_mt8189_reg_mfg_mux_notifier(struct device *dev,
> > +??????????????????????????????????????? struct clk *clk)
> > +{
> > +???? struct mtk_mux_nb *mfg_mux_nb;
> > +
> > +???? mfg_mux_nb = devm_kzalloc(dev, sizeof(*mfg_mux_nb),
> > GFP_KERNEL);
> > +???? if (!mfg_mux_nb)
> > +???????????? return -ENOMEM;
> > +
> > +???? mfg_mux_nb->ops = &mtk_mux_clr_set_upd_ops;
> > +???? mfg_mux_nb->bypass_index = 0; /* Bypass to
> > CLK_TOP_MFG_REF_SEL */
> > +
> > +???? return devm_mtk_clk_mux_notifier_register(dev, clk,
> > mfg_mux_nb);
> > +}
> > +
> > +static const struct mtk_clk_desc topck_desc = {
> > +???? .factor_clks = top_divs,
> > +???? .num_factor_clks = ARRAY_SIZE(top_divs),
> > +???? .mux_clks = top_muxes,
> > +???? .num_mux_clks = ARRAY_SIZE(top_muxes),
> > +???? .composite_clks = top_composites,
> > +???? .num_composite_clks = ARRAY_SIZE(top_composites),
> > +???? .clks = top_clks,
> > +???? .num_clks = ARRAY_SIZE(top_clks),
> > +???? .clk_notifier_func = clk_mt8189_reg_mfg_mux_notifier,
> > +???? .mfg_clk_idx = CLK_TOP_MFG_SEL_MFGPLL,
> > +???? .clk_lock = &mt8189_clk_lock,
> > +};
> > +
> > +static const struct of_device_id of_match_clk_mt8189_topck[] = {
> > +???? { .compatible = "mediatek,mt8189-topckgen", .data =
> > &topck_desc },
> > +???? { /* sentinel */ }
> > +};
> > +
> > +static struct platform_driver clk_mt8189_topck_drv = {
> > +???? .probe = mtk_clk_simple_probe,
> It misses a remove callback implementation for the driver, so use
> mtk_clk_simple_remove function then:
> ```
> ??????? .remove = mtk_clk_simple_remove,
> ```
> Same remarks for the other drivers in the patch series that use
> mtk_clk_simple_probe as probe callback.
> 
> Regards,
> Louis-Alexis
> 
> > +???? .driver = {
> > +???????????? .name = "clk-mt8189-topck",
> > +???????????? .of_match_table = of_match_clk_mt8189_topck,
> > +???? },
> > +};
> > +
> > +module_platform_driver(clk_mt8189_topck_drv);
> > +MODULE_LICENSE("GPL");


From chaoyi.chen at rock-chips.com  Wed Dec 10 02:47:42 2025
From: chaoyi.chen at rock-chips.com (Chaoyi Chen)
Date: Wed, 10 Dec 2025 18:47:42 +0800
Subject: Issues with DRM_ACCEL_ROCKET (Oops, power-domain, probe-ordering)
In-Reply-To: <CAAObsKABYQnw9rUfxwTS-yiQSoH9rdxZ_ffUBtp2H3tMJqMb7w@mail.gmail.com>
References: <0b20d760-ad4f-41c0-b733-39db10d6cc41@cherry.de>
 <77685900-2c34-49b8-8c7e-14718841ef17@rock-chips.com>
 <fa82d11f-ce11-4feb-bdb4-c31d360a2a62@rock-chips.com>
 <CAAObsKDYLXVf1GdYUNeaOya+pWD4jTOEf55ouXAL9iM_kWCcMw@mail.gmail.com>
 <75166475-d6a8-45b8-8092-f31d292d4206@rock-chips.com>
 <CAAObsKABYQnw9rUfxwTS-yiQSoH9rdxZ_ffUBtp2H3tMJqMb7w@mail.gmail.com>
Message-ID: <e7b2ceaf-1fbd-4f02-9d75-be4feab724e3@rock-chips.com>

Hello Tomeu,

On 12/10/2025 2:50 PM, Tomeu Vizoso wrote:
> On Tue, Dec 9, 2025 at 10:31?AM Chaoyi Chen <chaoyi.chen at rock-chips.com> wrote:
>>
>> Hello Tomeu,
>>
>> On 12/9/2025 2:55 PM, Tomeu Vizoso wrote:
>>> On Tue, Dec 2, 2025 at 8:00?AM Chaoyi Chen <chaoyi.chen at rock-chips.com> wrote:
>>
>> [...]
>>
>>>
>>> This need was questioned during the review process, and during my
>>> stress testing I didn't find a need for core 0 to be treated
>>> specially. So it was considered unneeded complexity and the code was
>>> dropped.
>>>
>>
>> Oh, I just noticed that the commit comment in the devicetree still
>> contains a relevant description.
>>
>>> My testing involves running the supported models as a whole, and also
>>> their individual operations as individual tests. I run them in 8
>>> parallel processes, in batches so we have continuous bring up and down
>>> of clients.
>>>
>>> I'm a bit surprised that that testing worked stably but we have still
>>> failures in some setups.
>>
>> Could you please describe the failures that still exist? Thank you.
> 
> I was referring to the ones that Quentin reported when starting this thread.
> 

I believe this pmdomain patch can alleviate some of the problems [0]. 

However, the problem Quentin mentioned still exists. For example, if
there is an invalid device on core0, while core1 and core2 are valid, 
accessing the relevant data on core0 will cause problems. Quentin's
patch can fix this, but he doesn't seem to have time for it lately...

[0] https://lore.kernel.org/all/20251205064739.20270-1-rmxpzlb at gmail.com/

> Regards,
> 
> Tomeu
> 
> 

-- 
Best, 
Chaoyi


From suzuki.poulose at arm.com  Wed Dec 10 02:54:10 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Wed, 10 Dec 2025 10:54:10 +0000
Subject: [PATCH v5 01/24] arm64: cpufeature: Add cpucap for HPMN0
In-Reply-To: <20251209205121.1871534-2-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
 <20251209205121.1871534-2-coltonlewis@google.com>
Message-ID: <d3e946ec-787a-424a-9a7a-f04aeb490ba6@arm.com>

On 09/12/2025 20:50, Colton Lewis wrote:
> Add a capability for FEAT_HPMN0, whether MDCR_EL2.HPMN can specify 0
> counters reserved for the guest.
> 
> This required changing HPMN0 to an UnsignedEnum in tools/sysreg
> because otherwise not all the appropriate macros are generated to add
> it to arm64_cpu_capabilities_arm64_features.
> 
> Acked-by: Mark Rutland <mark.rutland at arm.com>
> Signed-off-by: Colton Lewis <coltonlewis at google.com>

Reviewed-by: Suzuki K Poulose <suzuki.poulose at arm.com>



From ziniu.wang_1 at nxp.com  Wed Dec 10 03:18:06 2025
From: ziniu.wang_1 at nxp.com (Luke Wang)
Date: Wed, 10 Dec 2025 11:18:06 +0000
Subject: [EXT] Re: [PATCH v2] mmc: sdhci-esdhc-imx: wait for data transfer
 completion before reset
In-Reply-To: <CAPDyKFpYU3PZs-dSREyGyyyoptY0zCQmHP+mxMMgvYQL-xXQZA@mail.gmail.com>
References: <20251205071729.83857-1-ziniu.wang_1@nxp.com>
 <DU0PR04MB94962D103B1A92354CDD1FE690A7A@DU0PR04MB9496.eurprd04.prod.outlook.com>
 <CAPDyKFpYU3PZs-dSREyGyyyoptY0zCQmHP+mxMMgvYQL-xXQZA@mail.gmail.com>
Message-ID: <DU2PR04MB8567DB3B818280EED81A36B2EDA0A@DU2PR04MB8567.eurprd04.prod.outlook.com>



> -----Original Message-----
> From: Ulf Hansson <ulf.hansson at linaro.org>
> Sent: Tuesday, December 9, 2025 9:48 PM
> To: Bough Chen <haibo.chen at nxp.com>; Luke Wang
> <ziniu.wang_1 at nxp.com>
> Cc: adrian.hunter at intel.com; shawnguo at kernel.org;
> s.hauer at pengutronix.de; kernel at pengutronix.de; festevam at gmail.com;
> linux-mmc at vger.kernel.org; imx at lists.linux.dev; dl-S32 <S32 at nxp.com>;
> linux-arm-kernel at lists.infradead.org; linux-kernel at vger.kernel.org
> Subject: [EXT] Re: [PATCH v2] mmc: sdhci-esdhc-imx: wait for data transfer
> completion before reset
> 
> Caution: This is an external email. Please take care when clicking links or
> opening attachments. When in doubt, report the message using the 'Report
> this email' button
> 
> 
> On Fri, 5 Dec 2025 at 09:12, Bough Chen <haibo.chen at nxp.com> wrote:
> >
> > > -----Original Message-----
> > > From: Luke Wang <ziniu.wang_1 at nxp.com>
> > > Sent: 2025?12?5? 15:17
> > > To: adrian.hunter at intel.com; Bough Chen <haibo.chen at nxp.com>;
> > > ulf.hansson at linaro.org
> > > Cc: shawnguo at kernel.org; s.hauer at pengutronix.de;
> kernel at pengutronix.de;
> > > festevam at gmail.com; linux-mmc at vger.kernel.org; imx at lists.linux.dev;
> dl-S32
> > > <S32 at nxp.com>; linux-arm-kernel at lists.infradead.org;
> > > linux-kernel at vger.kernel.org
> > > Subject: [PATCH v2] mmc: sdhci-esdhc-imx: wait for data transfer
> completion
> > > before reset
> > >
> > > From: Luke Wang <ziniu.wang_1 at nxp.com>
> > >
> > > On IMX7ULP platforms, certain SD cards (e.g. Kingston Canvas Go! Plus)
> cause
> > > system hangs and reboots during manual tuning. These cards exhibit large
> gaps
> > > (~16us) between tuning command response and data transmission.
> > > When cmd CRC errors occur during tuning, the code assumes data errors
> even
> > > tuning data hasn't been fully received and then reset host data circuit.
> > >
> > > Per IMX7ULP reference manual, reset operations (RESET_DATA/ALL) need
> to
> > > make sure no active data transfers. Previously, resetting while data was in-
> flight
> > > would clear data circuit, including ADMA/SDMA address, causing data to
> be
> > > transmitted to incorrect memory address. This patch adds polling for data
> > > transfer completion before executing resets.
> > >
> > > Signed-off-by: Luke Wang <ziniu.wang_1 at nxp.com>
> > > ---
> > > v2: amend commit message
> > > ---
> > >  drivers/mmc/host/sdhci-esdhc-imx.c | 15 +++++++++++++++
> > >  1 file changed, 15 insertions(+)
> > >
> > > diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c
> > > b/drivers/mmc/host/sdhci-esdhc-imx.c
> > > index a7a5df673b0f..affde1936510 100644
> > > --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> > > +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> > > @@ -1453,6 +1453,21 @@ static void esdhc_set_uhs_signaling(struct
> > > sdhci_host *host, unsigned timing)
> > >
> > >  static void esdhc_reset(struct sdhci_host *host, u8 mask)  {
> > > +     u32 present_state;
> > > +     int ret;
> > > +
> > > +     /*
> > > +      * For data or full reset, ensure any active data transfer completes
> > > +      * before resetting to avoid system hang.
> > > +      */
> > > +     if (mask & (SDHCI_RESET_DATA | SDHCI_RESET_ALL)) {
> > > +             ret = readl_poll_timeout_atomic(host->ioaddr + ESDHC_PRSSTAT,
> > > present_state,
> >
> > I'm okay with the patch, but I find one thing here:
> >
> > I notice you use _atomic here, I guess you want to cover the case when the
> reset function is called in hardware irq handler sdhci_irq().
> > I'm not sure whether it is suitable to add delay in hardware iqr handler, I
> find there is also udelay in sdhci_reset(), sdhci_reset can also be called in
> hardware irq handler when there is cmd_crc/data_crc error.
> > Adrian/Ulf, do you notice this issue before? Any comments?
> 
> You are right. In general it's certainly not preferred to poll/delay
> in an atomic context. But if I understand correctly here, polling in
> atomic context should not happen that frequently, right?
> 
> Moreover, I wonder if we really need to have a polling-timeout of
> 100ms? Where did that value come from?

I referred to the 100ms timeout setting of sdhci_reset. 

Actual measurements show that during tuning, waiting for data transfer
completion typically only requires tens of microseconds. However, considering
that the tuning block size is very small, when transferring larger blocks, it
may require a longer waiting time. 

The probability of encountering CRC errors that require a reset when not in tuning
is quite low, so waiting for some additional time may not cause significant impact.

> 
> In any case, please add a define to specify the timeout and make sure
> the define-name has the suffix corresponding to the unit (_US,
> _MS,...)
> 

Sure, will do in next version

Thanks,
Luke Wang

> >
> > Regards
> > Haibo Chen
> >
> >
> > > +                                             !(present_state & SDHCI_DATA_INHIBIT), 2,
> > > 100000);
> > > +             if (ret == -ETIMEDOUT)
> > > +                     dev_warn(mmc_dev(host->mmc),
> > > +                              "timeout waiting for data transfer completion\n");
> > > +     }
> > > +
> > >       sdhci_and_cqhci_reset(host, mask);
> > >
> > >       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
> > > --
> > > 2.34.1
> >
> 
> Kind regards
> Uffe

From iivanov at suse.de  Wed Dec 10 03:39:43 2025
From: iivanov at suse.de (Ivan T. Ivanov)
Date: Wed, 10 Dec 2025 13:39:43 +0200
Subject: [PATCH v2] arm64: errata: Add NXP iMX8QM workaround for A53 Cache
 coherency issue
In-Reply-To: <20251210074550.GA10733@francesco-nb>
References: <20230420112952.28340-1-iivanov@suse.de>
 <20251210074550.GA10733@francesco-nb>
Message-ID: <3EB1BF9A-9D76-48BD-B134-D1D7DF8AD2CB@suse.de>

Hi,

> On 10 Dec 2025, at 9:45, Francesco Dolcini <francesco at dolcini.it> wrote:
> 
> Hello Ivan,
> 
> On Thu, Apr 20, 2023 at 02:29:52PM +0300, Ivan T. Ivanov wrote:
>> According to NXP errata document[1] i.MX8QuadMax SoC suffers from
>> serious cache coherence issue. It was also mentioned in initial
>> support[2] for imx8qm mek machine.
> 
> Ivan, from what I can see this patch was never merged and there was not any
> follow-up on this. What's the status? Are you planning to work on it?

Yep, it was put in low priority list and it was forgotten successfully.

I don't have plans to work on this in foreseeable future.

Regards,
Ivan




From robin.murphy at arm.com  Wed Dec 10 04:06:10 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Wed, 10 Dec 2025 12:06:10 +0000
Subject: [PATCH] iommu/io-pgtable-arm: Add misisng concatenated PGD cases
In-Reply-To: <aTjCDvtANr2WIv3L@google.com>
References: <20251130194506.593700-1-smostafa@google.com>
 <18a39079-2285-47fb-b306-040f2bc1bbaa@arm.com> <aTgX9qhaLyrQ5iye@google.com>
 <498bbad4-ea64-4a24-a63f-e131d271990a@arm.com> <aTjCDvtANr2WIv3L@google.com>
Message-ID: <8e058f60-60da-47c2-9947-2ea26cca1639@arm.com>

On 2025-12-10 12:42 am, Will Deacon wrote:
> On Tue, Dec 09, 2025 at 01:33:36PM +0000, Robin Murphy wrote:
>> On 2025-12-09 12:37 pm, Mostafa Saleh wrote:
>>> On Tue, Dec 09, 2025 at 11:34:34AM +0000, Robin Murphy wrote:
>>>> On 2025-11-30 7:45 pm, Mostafa Saleh wrote:
>>>>> arm_lpae_concat_mandatory() assumes that OAS >= IAS which is not
>>>>> correct for SMMUs supporting AArch32, and have OAS = 32/36 bits,
>>>>> as IAS would be 40 bits.
>>>>
>>>> But that is only when *using* AArch32 format. The bit in chapter 3.4 of the
>>>> SMMU architecture is talking about the maximum IAS that an SMMU
>>>> implementation needs to be able to accommodate based on its configuration,
>>>> but it does then attempt to clarify that the actual IPA size in use by any
>>>> given context should depend on the VMSA format in use:
>>>>
>>>> "VMSAv8-32 LPAE always supports an IPA size of 40 bits, whereas VMSAv8-64
>>>> and VMSAv9-128 limits the maximum IPA size to the maximum PA size."
>>>>
>>>> Rule R_SRKBC in the Arm ARM lays out the exact T0SZ constraints with this
>>>> AArch32/AArch64 detail.
>>>
>>> I see, thanks a lot for the explanation, I got confused by the this
>>> statement:
>>> Note: If AArch32 is implemented, IAS == MAX(40, OAS), otherwise IAS == OAS.
>>
>> Indeed, that appears confusingly contradictory; I've filed a bug.
> 
> I think the spec has always been worded like this. My reading is that, in
> isolation:
> 
>    - VMSAv8-32 LPAE always uses a 40-bit IAS
>    - VMSAv8-64 has IAS == OAS and this can be smaller than 40 bits
> 
> so if AArch32 is implemented, we know that the hardware supports at
> least a 40-bit IAS and in that case the VMSAv8-64 IAS can be bigger
> than the OAS.

No, the VMSAv8-64 IAS can never be bigger than OAS, as that would 
violate VMSA (see rules R_DTLMN and R_SRKBC). The SMMU spec seems mostly 
fixated on the notional maximum IAS that an SMMU must accommodate in 
general across all supported formats; the limitations of using any 
particular format must still apply though (similarly, the fact that 
AArch32 has a fixed 40-bit output doesn't mean that OAS and S2PS don't 
still matter for AArch64 format.)

Note that AArch32 is still free to use less than 40 bits of IAS if it 
wants to, by setting S2T0SZ appropriately, it's just guaranteed to 
support a *minimum* S2T0SZ of 24 regardless of OAS, unlike AArch64.

Cheers,
Robin.

> That seems consistent to me; where is the contradiction?
> 
> Will (jet-lagged so may well be talking rubbish!)



From tomas.melin at vaisala.com  Wed Dec 10 04:04:38 2025
From: tomas.melin at vaisala.com (Tomas Melin)
Date: Wed, 10 Dec 2025 14:04:38 +0200
Subject: [PATCH 2/4] rtc: zynqmp: rework read_offset
In-Reply-To: <LV5PR12MB98047B0A754AFFFB01163E0992A3A@LV5PR12MB9804.namprd12.prod.outlook.com>
References: <20251201-zynqmp-rtc-updates-v1-0-33875c1e385b@vaisala.com>
 <20251201-zynqmp-rtc-updates-v1-2-33875c1e385b@vaisala.com>
 <LV5PR12MB98047B0A754AFFFB01163E0992A3A@LV5PR12MB9804.namprd12.prod.outlook.com>
Message-ID: <353422a2-ba6e-4600-9326-e0cee2098062@vaisala.com>

Hi,

On 09/12/2025 19:28, T, Harini wrote:
> [Public]
> 
> Hi,
> 
>> -----Original Message-----
>> From: Tomas Melin <tomas.melin at vaisala.com>
>> Sent: Monday, December 1, 2025 6:20 PM
>> To: Alexandre Belloni <alexandre.belloni at bootlin.com>; Simek, Michal
>> <michal.simek at amd.com>
>> Cc: linux-rtc at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux-
>> kernel at vger.kernel.org; Tomas Melin <tomas.melin at vaisala.com>
>> Subject: [PATCH 2/4] rtc: zynqmp: rework read_offset
>>
>> Caution: This message originated from an External Source. Use proper
>> caution when opening attachments, clicking links, or responding.
>>
>>
>> read_offset() was using static frequency for determining the tick offset. It was
>> also using remainder from do_div() operation as tick_mult value which
>> caused the offset to be incorrect.
>>
>> At the same time, rework function to improve readability.
>>
>> Signed-off-by: Tomas Melin <tomas.melin at vaisala.com>
>> ---
>>  drivers/rtc/rtc-zynqmp.c | 25 ++++++++++++++++---------
>>  1 file changed, 16 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c index
>> 856bc1678e7d31144f320ae9f75fc58c742a2a64..7af5f6f99538f961a53ff56bfc6
>> 56c907611b900 100644
>> --- a/drivers/rtc/rtc-zynqmp.c
>> +++ b/drivers/rtc/rtc-zynqmp.c
>> @@ -178,21 +178,28 @@ static void xlnx_init_rtc(struct xlnx_rtc_dev
>> *xrtcdev)  static int xlnx_rtc_read_offset(struct device *dev, long *offset)  {
>>         struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
>> -       unsigned long long rtc_ppb = RTC_PPB;
>> -       unsigned int tick_mult = do_div(rtc_ppb, xrtcdev->freq);
>> -       unsigned int calibval;
>> +       unsigned int calibval, fract_data, fract_part;
> Prefer one variable assignment per line for readability.
This is after all quite common practice, and in a function like this
where several variables are needed, I would argue that this is more
readable than the alternative. Is there some convention I'm not aware of?

>> +       int max_tick, tick_mult;
> It would be better to explain why tick_mult is changed to int in the commit message.
This is part of the refactoring, mixing signed and unsigned variables in
operations is more risky than having same type.

>> +       int freq = xrtcdev->freq;
> Please follow reverse xmas tree variable ordering.
Ok fixing this and other occurances.

>>         long offset_val;
>>
>> +       /* ticks to reach RTC_PPB */
> The comment is misleading. Its tick_mult is nanoseconds per tick, not a tick count.
Perhaps the comment was not well formulated. I suggest changing to
/* Tick to offset multiplier */
 as that it what it is primarily used for. Would that be okay for You?

Thanks,
Tomas

>> +       tick_mult = DIV_ROUND_CLOSEST(RTC_PPB, freq);
>> +
>>         calibval = readl(xrtcdev->reg_base + RTC_CALIB_RD);
>>         /* Offset with seconds ticks */
>> -       offset_val = calibval & RTC_TICK_MASK;
>> -       offset_val = offset_val - RTC_CALIB_DEF;
>> -       offset_val = offset_val * tick_mult;
>> +       max_tick = calibval & RTC_TICK_MASK;
>> +       offset_val = max_tick - freq;
>> +       /* Convert to ppb */
>> +       offset_val *= tick_mult;
>>
>>         /* Offset with fractional ticks */
>> -       if (calibval & RTC_FR_EN)
>> -               offset_val += ((calibval & RTC_FR_MASK) >> RTC_FR_DATSHIFT)
>> -                       * (tick_mult / RTC_FR_MAX_TICKS);
>> +       if (calibval & RTC_FR_EN) {
>> +               fract_data = (calibval & RTC_FR_MASK) >> RTC_FR_DATSHIFT;
>> +               fract_part = DIV_ROUND_UP(tick_mult, RTC_FR_MAX_TICKS);
>> +               offset_val += (fract_part * fract_data);
>> +       }
>> +
>>         *offset = offset_val;
>>
>>         return 0;
>>
>> --
>> 2.47.3
>>
> Regards,
> Harini T
> 



From tomas.melin at vaisala.com  Wed Dec 10 04:18:03 2025
From: tomas.melin at vaisala.com (Tomas Melin)
Date: Wed, 10 Dec 2025 14:18:03 +0200
Subject: [PATCH 3/4] rtc: zynqmp: rework set_offset
In-Reply-To: <LV5PR12MB98045BF8A85640F924BCFD4492A3A@LV5PR12MB9804.namprd12.prod.outlook.com>
References: <20251201-zynqmp-rtc-updates-v1-0-33875c1e385b@vaisala.com>
 <20251201-zynqmp-rtc-updates-v1-3-33875c1e385b@vaisala.com>
 <LV5PR12MB98045BF8A85640F924BCFD4492A3A@LV5PR12MB9804.namprd12.prod.outlook.com>
Message-ID: <d02fda5e-47d4-4613-9a21-ed81bc957146@vaisala.com>

Hi,

On 09/12/2025 21:03, T, Harini wrote:
> [Public]
> 
> Hi,
> 
>> -----Original Message-----
>> From: Tomas Melin <tomas.melin at vaisala.com>
>> Sent: Monday, December 1, 2025 6:20 PM
>> To: Alexandre Belloni <alexandre.belloni at bootlin.com>; Simek, Michal
>> <michal.simek at amd.com>
>> Cc: linux-rtc at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux-
>> kernel at vger.kernel.org; Tomas Melin <tomas.melin at vaisala.com>
>> Subject: [PATCH 3/4] rtc: zynqmp: rework set_offset
>>
>> Caution: This message originated from an External Source. Use proper
>> caution when opening attachments, clicking links, or responding.
>>
>>
>> set_offset was using remainder of do_div as tick_mult which resulted in
>> wrong offset. Calibration value also assumed builtin calibration default.
>> Update fract_offset to correctly calculate the value for negative offset and
>> replace the for loop with division.
>>
>> Signed-off-by: Tomas Melin <tomas.melin at vaisala.com>
>> ---
>>  drivers/rtc/rtc-zynqmp.c | 29 +++++++++++------------------
>>  1 file changed, 11 insertions(+), 18 deletions(-)
>>
>> diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c index
>> 7af5f6f99538f961a53ff56bfc656c907611b900..3bc8831ba2c4c4c701a49506b6
>> 7ae6174f3ade3d 100644
>> --- a/drivers/rtc/rtc-zynqmp.c
>> +++ b/drivers/rtc/rtc-zynqmp.c
>> @@ -208,13 +208,13 @@ static int xlnx_rtc_read_offset(struct device *dev,
>> long *offset)  static int xlnx_rtc_set_offset(struct device *dev, long offset)  {
>>         struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
>> -       unsigned long long rtc_ppb = RTC_PPB;
>> -       unsigned int tick_mult = do_div(rtc_ppb, xrtcdev->freq);
>> +       unsigned int calibval, tick_mult, fract_part;
> tick_mult is mentioned as int in previous patch and unsigned here. Justify the type in commit description.
>>         unsigned char fract_tick = 0;
>> -       unsigned int calibval;
>> -       short int  max_tick;
>> -       int fract_offset;
>> +       int freq = xrtcdev->freq;
>> +       int max_tick, fract_offset;
> Please follow reverse xmas tree variable ordering.
> Also keep the frac_* variables uniform in both set and read offset functions.
Agreed, I will use same name of variables and types in next version.

>>
>> +       /* ticks to reach RTC_PPB */
> The comment is misleading. Its tick_mult is nanoseconds per tick, not a tick count.
Answered in patch 2/4.
>> +       tick_mult = DIV_ROUND_CLOSEST(RTC_PPB, xrtcdev->freq);
> We can first validate offset and then calculate tick_mult to reduce CPU instructions incase of invalid inputs
In this patch it would in theory apply, but when looking at patch 4/4
You will notice that we need to first calculate the helpers so offset is
then performed as soon as possible.

>>         if (offset < RTC_MIN_OFFSET || offset > RTC_MAX_OFFSET)
>>                 return -ERANGE;
>>
>> @@ -223,29 +223,22 @@ static int xlnx_rtc_set_offset(struct device *dev,
>> long offset)
>>
>>         /* Number fractional ticks for given offset */
>>         if (fract_offset) {
>> +               /* round up here so we stay below a full tick */
>> +               fract_part = DIV_ROUND_UP(tick_mult, RTC_FR_MAX_TICKS);
>>                 if (fract_offset < 0) {
>> -                       fract_offset = fract_offset + tick_mult;
>> +                       fract_offset += (fract_part * RTC_FR_MAX_TICKS);
> It would be better to add comment to explain on the negative offset borrowing logic
I will add comment about this.


>>                         max_tick--;
>>                 }
>> -               if (fract_offset > (tick_mult / RTC_FR_MAX_TICKS)) {
>> -                       for (fract_tick = 1; fract_tick < 16; fract_tick++) {
>> -                               if (fract_offset <=
>> -                                   (fract_tick *
>> -                                    (tick_mult / RTC_FR_MAX_TICKS)))
>> -                                       break;
>> -                       }
>> -               }
>> +               fract_tick = fract_offset / fract_part;
> Its better to use DIV_ROUND_UP()
Please explain why, that would change the end result from what is is now.

Thanks,
Tomas

>>         }
>>
>>         /* Zynqmp RTC uses second and fractional tick
>>          * counters for compensation
>>          */
>> -       calibval = max_tick + RTC_CALIB_DEF;
>> +       calibval = max_tick + freq;
>>
>>         if (fract_tick)
>> -               calibval |= RTC_FR_EN;
>> -
>> -       calibval |= (fract_tick << RTC_FR_DATSHIFT);
>> +               calibval |= (RTC_FR_EN | (fract_tick <<
>> + RTC_FR_DATSHIFT));
>>
>>         writel(calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
>>
>>
>> --
>> 2.47.3
>>
> 
> Regards,
> Harini T



From ben.horgan at arm.com  Wed Dec 10 04:20:19 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Wed, 10 Dec 2025 12:20:19 +0000
Subject: [RFC PATCH 35/38] arm_mpam: Add workaround for T241-MPAM-1
In-Reply-To: <20251205215901.17772-36-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-36-james.morse@arm.com>
Message-ID: <7b3fca1d-8f1d-481f-8635-ac973baec1c2@arm.com>

Hi James,

On 12/5/25 21:58, James Morse wrote:
> From: Shanker Donthineni <sdonthineni at nvidia.com>
> 
> The MPAM bandwidth partitioning controls will not be correctly configured,
> and hardware will retain default configuration register values, meaning
> generally that bandwidth will remain unprovisioned.
> 
> To address the issue, follow the below steps after updating the MBW_MIN
> and/or MBW_MAX registers.
> 
>  - Perform 64b reads from all 12 bridge MPAM shadow registers at offsets
>    (0x360048 + slice*0x10000 + partid*8). These registers are read-only.
>  - Continue iterating until all 12 shadow register values match in a loop.
>    pr_warn_once if the values fail to match within the loop count 1000.
>  - Perform 64b writes with the value 0x0 to the two spare registers at
>    offsets 0x1b0000 and 0x1c0000.
> 
> In the hardware, writes to the MPAMCFG_MBW_MAX MPAMCFG_MBW_MIN registers
> are transformed into broadcast writes to the 12 shadow registers. The
> final two writes to the spare registers cause a final rank of downstream
> micro-architectural MPAM registers to be updated from the shadow copies.
> The intervening loop to read the 12 shadow registers helps avoid a race
> condition where writes to the spare registers occur before all shadow
> registers have been updated.
> 
> Signed-off-by: Shanker Donthineni <sdonthineni at nvidia.com>
> [ morse: Merged the min/max update into a single
>   mpam_quirk_post_config_change() helper. Stashed the t241_id in the msc
>   instead of carrying the physical address around. Test the msc quirk bit
>   instead of a static key. ]
> Signed-off-by: James Morse <james.morse at arm.com>
> ---
>  Documentation/arch/arm64/silicon-errata.rst |  2 +
>  drivers/resctrl/mpam_devices.c              | 87 +++++++++++++++++++++
>  drivers/resctrl/mpam_internal.h             |  9 +++
>  3 files changed, 98 insertions(+)
> 
> diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst
> index a7ec57060f64..4e86b85fe3d6 100644
> --- a/Documentation/arch/arm64/silicon-errata.rst
> +++ b/Documentation/arch/arm64/silicon-errata.rst
> @@ -246,6 +246,8 @@ stable kernels.
>  +----------------+-----------------+-----------------+-----------------------------+
>  | NVIDIA         | T241 GICv3/4.x  | T241-FABRIC-4   | N/A                         |
>  +----------------+-----------------+-----------------+-----------------------------+
> +| NVIDIA         | T241 MPAM       | T241-MPAM-1     | N/A                         |
> ++----------------+-----------------+-----------------+-----------------------------+
>  +----------------+-----------------+-----------------+-----------------------------+
>  | Freescale/NXP  | LS2080A/LS1043A | A-008585        | FSL_ERRATUM_A008585         |
>  +----------------+-----------------+-----------------+-----------------------------+
> diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
> index f0f6f9b55ad4..f1f03ceade0a 100644
> --- a/drivers/resctrl/mpam_devices.c
> +++ b/drivers/resctrl/mpam_devices.c
> @@ -29,6 +29,16 @@
>  
>  #include "mpam_internal.h"
>  
> +/* Values for the T241 errata workaround */
> +#define T241_CHIPS_MAX			4
> +#define T241_CHIP_NSLICES		12
> +#define T241_SPARE_REG0_OFF		0x1b0000
> +#define T241_SPARE_REG1_OFF		0x1c0000
> +#define T241_CHIP_ID(phys)		FIELD_GET(GENMASK_ULL(44, 43), phys)
> +#define T241_SHADOW_REG_OFF(sidx, pid)	(0x360048 + (sidx) * 0x10000 + (pid) * 8)
> +#define SMCCC_SOC_ID_T241		0x036b0241
> +static void __iomem *t241_scratch_regs[T241_CHIPS_MAX];
> +
>  /*
>   * mpam_list_lock protects the SRCU lists when writing. Once the
>   * mpam_enabled key is enabled these lists are read-only,
> @@ -630,7 +640,44 @@ static struct mpam_msc_ris *mpam_get_or_create_ris(struct mpam_msc *msc,
>  	return ERR_PTR(-ENOENT);
>  }
>  
> +static void mpam_enable_quirk_nvidia_t241(struct mpam_msc *msc,
> +					  const struct mpam_quirk *quirk)
> +{
> +	s32 soc_id = arm_smccc_get_soc_id_version();
> +	struct resource *r;
> +	phys_addr_t phys;
> +
> +	/*
> +	 * A mapping to a device other than the MSC is needed, check
> +	 * SOC_ID is  NVIDIA T241 chip (036b:0241)
> +	 */
> +	if (soc_id < 0 || soc_id != SMCCC_SOC_ID_T241)
> +		return;
> +
> +	r = platform_get_resource(msc->pdev, IORESOURCE_MEM, 0);
> +	if (!r)
> +		return;
> +
> +	/* Find the internal registers base addr from the CHIP ID */
> +	msc->t241_id = T241_CHIP_ID(r->start);
> +	phys = FIELD_PREP(GENMASK_ULL(45, 44), msc->t241_id) | 0x19000000ULL;
> +
> +	t241_scratch_regs[msc->t241_id] = ioremap(phys, SZ_8M);
> +	if (WARN_ON_ONCE(!t241_scratch_regs[msc->t241_id]))
> +		return;
> +
> +	mpam_set_quirk(quirk->workaround, msc);
> +	pr_info_once("Enabled workaround for NVIDIA T241 erratum T241-MPAM-1\n");
> +}
> +
>  static const struct mpam_quirk mpam_quirks[] = {
> +	{
> +	/* NVIDIA t241 erratum T241-MPAM-1 */
> +	.init       = mpam_enable_quirk_nvidia_t241,
> +	.iidr       = MPAM_IIDR_NVIDIA_T421,

MPAM_IIDR_NVIDIA_T421 -> MPAM_IIDR_NVIDIA_T241

> +	.iidr_mask  = MPAM_IIDR_MATCH_ONE,
> +	.workaround = T241_SCRUB_SHADOW_REGS,
> +	},
>  	{ NULL }, /* Sentinel */
>  };
>  
> @@ -1372,6 +1419,44 @@ static void mpam_reset_msc_bitmap(struct mpam_msc *msc, u16 reg, u16 wd)
>  	__mpam_write_reg(msc, reg, bm);
>  }
>  
> +static void mpam_apply_t241_erratum(struct mpam_msc_ris *ris, u16 partid)
> +{
> +	int sidx, i, lcount = 1000;
> +	void __iomem *regs;
> +	u64 val0, val;
> +
> +	regs = t241_scratch_regs[ris->vmsc->msc->t241_id];
> +
> +	for (i = 0; i < lcount; i++) {
> +		/* Read the shadow register at index 0 */
> +		val0 = readq_relaxed(regs + T241_SHADOW_REG_OFF(0, partid));
> +
> +		/* Check if all the shadow registers have the same value */
> +		for (sidx = 1; sidx < T241_CHIP_NSLICES; sidx++) {
> +			val = readq_relaxed(regs +
> +					    T241_SHADOW_REG_OFF(sidx, partid));
> +			if (val != val0)
> +				break;
> +		}
> +		if (sidx == T241_CHIP_NSLICES)
> +			break;
> +	}
> +
> +	if (i == lcount)
> +		pr_warn_once("t241: inconsistent values in shadow regs");
> +
> +	/* Write a value zero to spare registers to take effect of MBW conf */
> +	writeq_relaxed(0, regs + T241_SPARE_REG0_OFF);
> +	writeq_relaxed(0, regs + T241_SPARE_REG1_OFF);
> +}
> +
> +static void mpam_quirk_post_config_change(struct mpam_msc_ris *ris, u16 partid,
> +					  struct mpam_config *cfg)
> +{
> +	if (mpam_has_quirk(T241_SCRUB_SHADOW_REGS, ris->vmsc->msc))
> +		mpam_apply_t241_erratum(ris, partid);
> +}
> +
>  /* Called via IPI. Call while holding an SRCU reference */
>  static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
>  				      struct mpam_config *cfg)
> @@ -1455,6 +1540,8 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
>  		mpam_write_partsel_reg(msc, PRI, pri_val);
>  	}
>  
> +	mpam_quirk_post_config_change(ris, partid, cfg);
> +
>  	mutex_unlock(&msc->part_sel_lock);
>  }
>  
> diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
> index de3e5faa12b2..70b78cfd1f5b 100644
> --- a/drivers/resctrl/mpam_internal.h
> +++ b/drivers/resctrl/mpam_internal.h
> @@ -133,6 +133,9 @@ struct mpam_msc {
>  	void __iomem		*mapped_hwpage;
>  	size_t			mapped_hwpage_sz;
>  
> +	/* Values only used on some platforms for quirks */
> +	u32			t241_id;
> +
>  	struct mpam_garbage	garbage;
>  };
>  
> @@ -219,6 +222,7 @@ struct mpam_props {
>  
>  /* Workaround bits for msc->quirks */
>  enum mpam_device_quirks {
> +	T241_SCRUB_SHADOW_REGS,
>  	MPAM_QUIRK_LAST,
>  };
>  
> @@ -239,6 +243,11 @@ struct mpam_quirk {
>  				FIELD_PREP_CONST(MPAMF_IIDR_REVISION,    0xf  ) | \
>  				FIELD_PREP_CONST(MPAMF_IIDR_IMPLEMENTER, 0xfff)
>  
> +#define MPAM_IIDR_NVIDIA_T421   FIELD_PREP_CONST(MPAMF_IIDR_PRODUCTID,   0x241) | \

MPAM_IIDR_NVIDIA_T421 -> MPAM_IIDR_NVIDIA_T241

> +				FIELD_PREP_CONST(MPAMF_IIDR_VARIANT,     0    ) | \
> +				FIELD_PREP_CONST(MPAMF_IIDR_REVISION,    0    ) | \
> +				FIELD_PREP_CONST(MPAMF_IIDR_IMPLEMENTER, 0x36b)
> +
>  
>  /* The values for MSMON_CFG_MBWU_FLT.RWBW */
>  enum mon_filter_options {

Thanks,

Ben



From tomas.melin at vaisala.com  Wed Dec 10 04:25:27 2025
From: tomas.melin at vaisala.com (Tomas Melin)
Date: Wed, 10 Dec 2025 14:25:27 +0200
Subject: [PATCH 4/4] rtc: zynqmp: use dynamic max and min offset ranges
In-Reply-To: <LV5PR12MB98046A63E80D7A7FA299366E92A3A@LV5PR12MB9804.namprd12.prod.outlook.com>
References: <20251201-zynqmp-rtc-updates-v1-0-33875c1e385b@vaisala.com>
 <20251201-zynqmp-rtc-updates-v1-4-33875c1e385b@vaisala.com>
 <LV5PR12MB98046A63E80D7A7FA299366E92A3A@LV5PR12MB9804.namprd12.prod.outlook.com>
Message-ID: <ea85c8d6-ead8-4fda-905d-909968de5056@vaisala.com>

Hi,

On 09/12/2025 21:28, T, Harini wrote:
> [Public]
> 
> Hi,
> 
>> -----Original Message-----
>> From: Tomas Melin <tomas.melin at vaisala.com>
>> Sent: Monday, December 1, 2025 6:20 PM
>> To: Alexandre Belloni <alexandre.belloni at bootlin.com>; Simek, Michal
>> <michal.simek at amd.com>
>> Cc: linux-rtc at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux-
>> kernel at vger.kernel.org; Tomas Melin <tomas.melin at vaisala.com>
>> Subject: [PATCH 4/4] rtc: zynqmp: use dynamic max and min offset ranges
>>
>> Caution: This message originated from an External Source. Use proper
>> caution when opening attachments, clicking links, or responding.
>>
>>
>> Maximum and minimum offsets in ppb that can be handled are dependent
>> on the rtc clock frequency and what can fit in the 16-bit register field.
>>
>> Signed-off-by: Tomas Melin <tomas.melin at vaisala.com>
>> ---
>>  drivers/rtc/rtc-zynqmp.c | 8 +++-----
>>  1 file changed, 3 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c index
>> 3bc8831ba2c4c4c701a49506b67ae6174f3ade3d..0cebc99b15a6de2440a60afc
>> 2bd1769eccfa84b3 100644
>> --- a/drivers/rtc/rtc-zynqmp.c
>> +++ b/drivers/rtc/rtc-zynqmp.c
>> @@ -44,8 +44,6 @@
>>  #define RTC_FR_MASK            0xF0000
>>  #define RTC_FR_MAX_TICKS       16
>>  #define RTC_PPB                        1000000000LL
>> -#define RTC_MIN_OFFSET         -32768000
>> -#define RTC_MAX_OFFSET         32767000
>>
>>  struct xlnx_rtc_dev {
>>         struct rtc_device       *rtc;
>> @@ -215,12 +213,12 @@ static int xlnx_rtc_set_offset(struct device *dev,
>> long offset)
>>
>>         /* ticks to reach RTC_PPB */
>>         tick_mult = DIV_ROUND_CLOSEST(RTC_PPB, xrtcdev->freq);
>> -       if (offset < RTC_MIN_OFFSET || offset > RTC_MAX_OFFSET)
>> -               return -ERANGE;
>> -
>>         /* Number ticks for given offset */
>>         max_tick = div_s64_rem(offset, tick_mult, &fract_offset);
>>
>> +       if (freq + max_tick > RTC_TICK_MASK || (freq + max_tick < 1))
> The check 'freq + max_tick < 1' should be '<2' to prevent writing 0 to the calibration register when fract_offset < 0 causes max_tick--.
> Example: freq=32767, max_tick=-32766 passes (sum=1), but after decrement becomes calibval=0.
calibval=0 is not documented as invalid calibration value. AFAIS it
would mean a frequency of 1Hz. Can You provide more info on this?

Thanks,
Tomas


>> +               return -ERANGE;
>> +
>>         /* Number fractional ticks for given offset */
>>         if (fract_offset) {
>>                 /* round up here so we stay below a full tick */
>>
>> --
>> 2.47.3
>>
> 
> Thanks,
> Harini T
> 



From ryan.roberts at arm.com  Wed Dec 10 04:29:33 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Wed, 10 Dec 2025 12:29:33 +0000
Subject: [PATCH 00/10] arm64: Replace TLB invalidation preprocessor macros
 with C functions
In-Reply-To: <20250711161732.384-1-will@kernel.org>
References: <20250711161732.384-1-will@kernel.org>
Message-ID: <eb583fda-cbd1-4ef2-900a-a86e08a0b5d3@arm.com>

On 11/07/2025 17:17, Will Deacon wrote:
> Hi all,
> 
> I cooked this series following a complaint from Linus back in March
> about our range-based TLB invalidation macro after we fixed an
> over-invalidation bug thanks to incorrect handling of its arguments:
> 
>   https://lore.kernel.org/all/CAHk-=wgiX0q0WCL+SFwVCYtG7JR3=2Rshse-5J3AO2Y4AgT7Jw at mail.gmail.com/
> 
> Once I started trying to rework the range macro into a C function, I
> spotted a few other opportunities for cleanup and so I've ended up with
> this series.
> 
> Testing and feedback welcome.

Hi Will,

Did this go anywhere/are you planning to post a new version? There are a couple
of other cleanups I'd like to do in this area, and also I'd like to add tlbip
support. But I don't want to spend time on it if the baseline is going to
drastically change.

If you're not planning a v2, perhaps I could have a go then extend for the
extras I want to do?

Thanks,
Ryan


> 
> Cheers,
> 
> Will
> 
> Cc: Ard Biesheuvel <ardb at kernel.org>
> Cc: Catalin Marinas <catalin.marinas at arm.com>
> Cc: Ryan Roberts <ryan.roberts at arm.com>
> Cc: Mark Rutland <mark.rutland at arm.com>
> Cc: Linus Torvalds <torvalds at linux-foundation.org>
> Cc: Oliver Upton <oliver.upton at linux.dev>
> Cc: Marc Zyngier <maz at kernel.org>
> 
> --->8
> 
> Will Deacon (10):
>   arm64: mm: Introduce a C wrapper for by-level TLB invalidation helpers
>   arm64: mm: Introduce a C wrapper for by-range TLB invalidation helpers
>   arm64: mm: Implicitly invalidate user ASID based on TLBI operation
>   arm64: mm: Remove unused 'tlbi_user' argument from
>     __flush_tlb_range_op()
>   arm64: mm: Re-implement the __tlbi_level macro in C
>   arm64: mm: Simplify __TLBI_RANGE_NUM() macro
>   arm64: mm: Push __TLBI_VADDR() into __tlbi_level()
>   arm64: mm: Inline __TLBI_VADDR_RANGE() into __tlbi_range()
>   arm64: mm: Simplify __flush_tlb_range_limit_excess()
>   arm64: mm: Re-implement the __flush_tlb_range_op macro in C
> 
>  arch/arm64/include/asm/tlbflush.h | 230 ++++++++++++++++++------------
>  arch/arm64/kernel/sys_compat.c    |   2 +-
>  arch/arm64/kvm/hyp/nvhe/mm.c      |   2 +-
>  arch/arm64/kvm/hyp/pgtable.c      |   4 +-
>  4 files changed, 140 insertions(+), 98 deletions(-)
> 



From tomas.melin at vaisala.com  Wed Dec 10 04:29:42 2025
From: tomas.melin at vaisala.com (Tomas Melin)
Date: Wed, 10 Dec 2025 14:29:42 +0200
Subject: [PATCH 1/4] rtc: zynqmp: correct frequency value
In-Reply-To: <LV5PR12MB980479009955E816E72E6EA892A3A@LV5PR12MB9804.namprd12.prod.outlook.com>
References: <20251201-zynqmp-rtc-updates-v1-0-33875c1e385b@vaisala.com>
 <20251201-zynqmp-rtc-updates-v1-1-33875c1e385b@vaisala.com>
 <LV5PR12MB980479009955E816E72E6EA892A3A@LV5PR12MB9804.namprd12.prod.outlook.com>
Message-ID: <d3087d78-31e6-4a29-8939-d6adae8a4307@vaisala.com>

Hi,

On 09/12/2025 18:51, T, Harini wrote:
> [Public]
> 
> Hi,
> 
>> -----Original Message-----
>> From: Tomas Melin <tomas.melin at vaisala.com>
>> Sent: Monday, December 1, 2025 6:20 PM
>> To: Alexandre Belloni <alexandre.belloni at bootlin.com>; Simek, Michal
>> <michal.simek at amd.com>
>> Cc: linux-rtc at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux-
>> kernel at vger.kernel.org; Tomas Melin <tomas.melin at vaisala.com>
>> Subject: [PATCH 1/4] rtc: zynqmp: correct frequency value
>>
>> Caution: This message originated from an External Source. Use proper
>> caution when opening attachments, clicking links, or responding.
>>
>>
>> Fix calibration value in case a clock reference is provided.
>> The actual calibration value written into register is
>> frequency - 1.
>>
>> Signed-off-by: Tomas Melin <tomas.melin at vaisala.com>
>> ---
>>  drivers/rtc/rtc-zynqmp.c | 3 +++
>>  1 file changed, 3 insertions(+)
>>
>> diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c
>> index
>> 3baa2b481d9f2008750046005283b98a0d546c5c..856bc1678e7d31144f320ae
>> 9f75fc58c742a2a64 100644
>> --- a/drivers/rtc/rtc-zynqmp.c
>> +++ b/drivers/rtc/rtc-zynqmp.c
>> @@ -345,7 +345,10 @@ static int xlnx_rtc_probe(struct platform_device
>> *pdev)
>>                                            &xrtcdev->freq);
>>                 if (ret)
>>                         xrtcdev->freq = RTC_CALIB_DEF;
>> +       } else {
>> +               xrtcdev->freq--;
> If freq > 65536, the 16-bit register silently truncates.
> Please add some checks for above mentioned scenario.
That is indeed a scenario that is not accounted for in the current
driver. I can add a separate patch for that as part of this series.

Thanks,
Tomas


>>         }
>> +
>>         ret = readl(xrtcdev->reg_base + RTC_CALIB_RD);
>>         if (!ret)
>>                 writel(xrtcdev->freq, (xrtcdev->reg_base + RTC_CALIB_WR));
>>
>> --
>> 2.47.3
>>
> Thanks,
> Harini T



From robin.murphy at arm.com  Wed Dec 10 04:39:49 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Wed, 10 Dec 2025 12:39:49 +0000
Subject: [PATCH V4 1/3] iommu/arm-smmu-v3: Add device-tree support for
 CMDQV driver
In-Reply-To: <2bf7bb25-9a6b-42d5-b095-978f7bb81f35@nvidia.com>
References: <20251205065850.3841834-2-amhetre@nvidia.com>
 <202512090331.QAFgb6vQ-lkp@intel.com>
 <2bf7bb25-9a6b-42d5-b095-978f7bb81f35@nvidia.com>
Message-ID: <e7c69e9c-6af4-468a-88ed-fb8829afb92e@arm.com>

On 2025-12-10 5:19 am, Ashish Mhetre wrote:
[...]
> Hi Robin, Nic,
> We removed ACPI dependency in Kconfig but driver still depends
> on ACPI for these functions. I will be protecting ACPIspecific
> tegra241-cmdqv code under CONFIG_ACPI similar to what is done
> in arm-smmu-v3 driver. Is this the correct thing to do or do you
> have any other suggestions?

Yes, when I commented that "depends on ACPI || OF" was functionally the 
same as just removing "depends on ACPI", I didn't mean to suggest that 
wasn't necessarily a genuine dependency still.

I guess if you can wrap the ACPI-specific functions in a single #ifdef 
block that's reasonable, however I do now wonder whether things couldn't 
be factored out a bit more - if it's a standard DSDT/SSDT namespace 
device, shouldn't there also be a corresponding platform device created 
for it, which we could look up instead of delving directly into the _CRS 
of the ACPI node itself? (not sure off-hand if there's a straightforward 
inverse of ACPI_COMPANION()...)

Thanks,
Robin.


From daniel.baluta at gmail.com  Wed Dec 10 04:56:13 2025
From: daniel.baluta at gmail.com (Daniel Baluta)
Date: Wed, 10 Dec 2025 14:56:13 +0200
Subject: [RFC PATCH] remoteproc: imx_dsp_rproc: Fix multiple start/stop commands
In-Reply-To: <20251209152720.GA189083-robh@kernel.org>
References: <20251209140425.766742-1-daniel.baluta@nxp.com> <20251209152720.GA189083-robh@kernel.org>
Message-ID: <CAEnQRZBV5ECT+P0FYPuS0Yt3C0xdpSmBpxjknhX0wa-c-LBXMg@mail.gmail.com>

On Tue, Dec 9, 2025 at 5:27?PM Rob Herring <robh at kernel.org> wrote:
>
> On Tue, Dec 09, 2025 at 04:04:25PM +0200, Daniel Baluta wrote:
> > After commit 67a7bc7f0358 ("remoteproc: Use of reserved_mem_region_*
> > functions for "memory-region"") following commands with
> > imx-dsp-rproc started to fail:
> >
> > $ echo zephyr.elf > /sys/class/remoteproc/remoteproc0/firmware
> > $ echo start > /sys/class/remoteproc/remoteproc0/state
> > $ echo stop > /sys/class/remoteproc/remoteproc0/state
> > $ echo start > /sys/class/remoteproc/remoteproc0/state #! This fails
> > -sh: echo: write error: Device or resource busy
>
> So unlike Marek's case, the first time works. Can you confirm your
> region is fixed address?

Yes, all regions are fixed addresses.

> > +             cpu_addr = devm_ioremap_wc(dev, res.start, resource_size(&res));
>
> Best case this is reusing the same mapping and we just have unnecessary
> ioremap and iounmap calls and devm entries. Worst case, we get a new
> virtual mapping every time. IIRC, arm32 will reuse existing mapping, but
> arm64 does not. But that's 10+ years ago I looked into it.
>
> Seems like devres is not the right lifetime. This should be just
> ioremap_wc() instead.

Yes, looks like for arm64 (imx8mp-evk) will not reuse existing mapping
but creates a new one.

Best course of action would be as Iulia suggested to move the operation
at probe instead of prepare.


From paul at crapouillou.net  Wed Dec 10 05:06:41 2025
From: paul at crapouillou.net (Paul Cercueil)
Date: Wed, 10 Dec 2025 14:06:41 +0100
Subject: Kconfig dangling references (BZ 216748)
In-Reply-To: <22b92ddf-6321-41b5-8073-f9c7064d3432@infradead.org>
References: <22b92ddf-6321-41b5-8073-f9c7064d3432@infradead.org>
Message-ID: <4b6db1eb455fff8e3c7372943faa5ef179c1d19f.camel@crapouillou.net>

Hi Randy,

Le dimanche 07 d?cembre 2025 ? 18:04 -0800, Randy Dunlap a ?crit?:
> from? https://bugzilla.kernel.org/show_bug.cgi?id=216748
> 
> The bugzilla entry includes a Perl script and a shell script.
> This is the edited result of running them (I removed some entries
> that were noise).
> 
> I'll try to Cc: all of the relevant mailing lists or individuals.
> 
> 
> ARCH_HAS_HOLES_MEMORYMODEL ---
> arch/arm/mach-omap1/Kconfig:7:	select ARCH_HAS_HOLES_MEMORYMODEL
> 
> ARM_ERRATA_794072 ---
> arch/arm/mach-npcm/Kconfig:33:	select ARM_ERRATA_794072
> 
> ARM_SMC_MBOX ---
> arch/arm64/Kconfig.platforms:375:	select ARM_SMC_MBOX
> 
> CLK_FIXED_FCH ---
> sound/soc/amd/Kconfig:11:	select CLK_FIXED_FCH
> sound/soc/amd/Kconfig:48:	select CLK_FIXED_FCH
> sound/soc/amd/acp/Kconfig:107:	select CLK_FIXED_FCH
> 
> CONFIG_STM ---
> drivers/hwtracing/stm/Kconfig:16:	default CONFIG_STM? # should
> be STM
> drivers/hwtracing/stm/Kconfig:31:	default CONFIG_STM
> 
> CPU_HAS_LOAD_STORE_LR ---
> arch/mips/Kconfig:1411:	select CPU_HAS_LOAD_STORE_LR
> 
> DRM_KMS_DMA_HELPER ---
> drivers/gpu/drm/adp/Kconfig:9:	select DRM_KMS_DMA_HELPER
> drivers/gpu/drm/logicvc/Kconfig:7:	select DRM_KMS_DMA_HELPER
> 
> EXTCON_TCSS_CROS_EC ---
> drivers/usb/typec/ucsi/Kconfig:76:	depends on
> !EXTCON_TCSS_CROS_EC
> 
> MACH_JZ4755 ---
> drivers/clk/ingenic/Kconfig:20:	default MACH_JZ4755
> drivers/pinctrl/pinctrl-
> ingenic.c:158:	IS_ENABLED(CONFIG_MACH_JZ4755) << ID_JZ4755 |
> drivers/pinctrl/pinctrl-ingenic.c:4616:		.data =
> IF_ENABLED(CONFIG_MACH_JZ4755, &jz4755_chip_info)
> 
> MACH_JZ4760 ---
> drivers/clk/ingenic/Kconfig:40:	default MACH_JZ4760
> drivers/pinctrl/pinctrl-
> ingenic.c:159:	IS_ENABLED(CONFIG_MACH_JZ4760) << ID_JZ4760 |
> drivers/pinctrl/pinctrl-ingenic.c:4620:		.data =
> IF_ENABLED(CONFIG_MACH_JZ4760, &jz4760_chip_info)
> drivers/pinctrl/pinctrl-ingenic.c:4624:		.data =
> IF_ENABLED(CONFIG_MACH_JZ4760, &jz4760_chip_info)

Those were added when upstreaming support for the JZ4755/JZ4760, but
the DTS files and actual support in arch/mips/ was never sent.

Instead of dropping those, I'll try to upstream the basic support for
those SoCs in the coming days.

Cheers,
-Paul

> 
> MACH_STM32MP25 ---
> drivers/pinctrl/stm32/Kconfig:58:	default MACH_STM32MP25 ||
> (ARCH_STM32 && ARM64)
> 
> MFD_AIROHA_AN8855 ---
> drivers/nvmem/Kconfig:33:	depends on MFD_AIROHA_AN8855 ||
> COMPILE_TEST
> 
> MFD_TN48M_CPLD ---
> drivers/gpio/Kconfig:1624:	depends on MFD_TN48M_CPLD ||
> COMPILE_TEST
> drivers/reset/Kconfig:365:	depends on MFD_TN48M_CPLD ||
> COMPILE_TEST
> drivers/reset/Kconfig:366:	default MFD_TN48M_CPLD
> 
> MIPS_BAIKAL_T1 ---
> drivers/ata/Kconfig:197:	select MFD_SYSCON if (MIPS_BAIKAL_T1
> || COMPILE_TEST)
> drivers/bus/Kconfig:43:	depends on MIPS_BAIKAL_T1 || COMPILE_TEST
> drivers/bus/Kconfig:58:	depends on MIPS_BAIKAL_T1 || COMPILE_TEST
> drivers/clk/baikal-t1/Kconfig:4:	depends on (MIPS_BAIKAL_T1
> && OF) || COMPILE_TEST
> drivers/clk/baikal-t1/Kconfig:5:	default MIPS_BAIKAL_T1
> drivers/clk/baikal-t1/Kconfig:20:	default MIPS_BAIKAL_T1
> drivers/clk/baikal-t1/Kconfig:33:	default MIPS_BAIKAL_T1
> drivers/clk/baikal-t1/Kconfig:45:	default MIPS_BAIKAL_T1
> drivers/hwmon/Kconfig:462:	depends on MIPS_BAIKAL_T1 ||
> COMPILE_TEST
> drivers/i2c/busses/Kconfig:589:	select MFD_SYSCON if MIPS_BAIKAL_T1
> drivers/memory/Kconfig:69:	depends on MIPS_BAIKAL_T1 ||
> COMPILE_TEST
> drivers/mtd/maps/Kconfig:81:	depends on MIPS_BAIKAL_T1 ||
> COMPILE_TEST
> drivers/pci/controller/dwc/Kconfig:89:	depends on MIPS_BAIKAL_T1 ||
> COMPILE_TEST
> drivers/spi/Kconfig:370:	depends on MIPS_BAIKAL_T1 ||
> COMPILE_TEST
> 
> PINCTRL_MILBEAUT ---
> arch/arm/mach-milbeaut/Kconfig:16:	select PINCTRL_MILBEAUT
> 
> SND_SOC_AC97_BUS_NEW ---
> sound/soc/pxa/Kconfig:21:	select SND_SOC_AC97_BUS_NEW
> 
> SND_SOC_CS35L56_CAL_SYSFS_COMMON ---
> sound/soc/codecs/Kconfig:920:	select
> SND_SOC_CS35L56_CAL_SYSFS_COMMON
> 
> TEST_KUNIT_DEVICE_HELPERS ---
> drivers/iio/test/Kconfig:11:	select TEST_KUNIT_DEVICE_HELPERS
> 
> USB_HSIC_USB3613 ---
> drivers/staging/greybus/Kconfig:209:	depends on USB_HSIC_USB3613
> || COMPILE_TEST
> drivers/staging/greybus/arche-platform.c:26:#if
> IS_ENABLED(CONFIG_USB_HSIC_USB3613)
> 
> USB_OHCI_SH ---
> arch/sh/Kconfig:334:	select USB_OHCI_SH if USB_OHCI_HCD
> arch/sh/Kconfig:344:	select USB_OHCI_SH if USB_OHCI_HCD
> arch/sh/Kconfig:429:	select USB_OHCI_SH if USB_OHCI_HCD
> arch/sh/Kconfig:455:	select USB_OHCI_SH if USB_OHCI_HCD
> arch/sh/configs/sh7757lcr_defconfig:61:CONFIG_USB_OHCI_SH=y
> 
> X86_P6_NOP ---
> arch/x86/Kconfig.cpufeatures:41:	depends on X86_64 ||
> X86_P6_NOP
> arch/x86/Makefile_32.cpu:48:ifneq ($(CONFIG_X86_P6_NOP),y)
> 
> XTENSA_PLATFORM_ESP32 ---
> drivers/tty/serial/Kconfig:1598:	depends on
> XTENSA_PLATFORM_ESP32 || (COMPILE_TEST && OF)
> drivers/tty/serial/Kconfig:1611:	depends on
> XTENSA_PLATFORM_ESP32 || (COMPILE_TEST && OF)
> 


From alexandru.elisei at arm.com  Wed Dec 10 05:21:00 2025
From: alexandru.elisei at arm.com (Alexandru Elisei)
Date: Wed, 10 Dec 2025 13:21:00 +0000
Subject: [PATCH 0/2] KVM: arm64: pKVM fixes
Message-ID: <20251210132102.137631-1-alexandru.elisei@arm.com>

Similar to [1], when trying to run an unprotected VM on FVP with S1PIE enabled
and kvm-arm.mode=protected, writes to PIRE0_EL1 made by the guest in
__cpu_setup() are trapped by KVM and the BUG_ON(!r->access) is hit. That's
because HFGWTR_EL2.nPIRE0_EL1 is an inverse polarity trap and the FGT values for
the unprotected pKVM VCPU weren't being propagated from kvm_arch_vcpu_load().

Couldn't figure out how to run a protected pKVM VM, so that's untested.

Patch #2 is just a minor fixup for something I found by code inspection when I
trying to figure out how unprotected pKVM works.

[1] https://lore.kernel.org/all/20251112102853.47759-1-alexandru.elisei at arm.com/

Alexandru Elisei (2):
  KVM: arm64: Copy FGT traps to unprotected pKVM VCPU on VCPU load
  KVM: arm64: Remove extra argument for
    __pvkm_host_{share,unshare}_hyp()

 arch/arm64/kvm/hyp/nvhe/hyp-main.c | 12 ++++++++++--
 arch/arm64/kvm/hyp/nvhe/pkvm.c     |  1 -
 arch/arm64/kvm/mmu.c               |  2 +-
 3 files changed, 11 insertions(+), 4 deletions(-)


base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
-- 
2.52.0



From alexandru.elisei at arm.com  Wed Dec 10 05:21:01 2025
From: alexandru.elisei at arm.com (Alexandru Elisei)
Date: Wed, 10 Dec 2025 13:21:01 +0000
Subject: [PATCH 1/2] KVM: arm64: Copy FGT traps to unprotected pKVM VCPU on VCPU load
In-Reply-To: <20251210132102.137631-1-alexandru.elisei@arm.com>
References: <20251210132102.137631-1-alexandru.elisei@arm.com>
Message-ID: <20251210132102.137631-2-alexandru.elisei@arm.com>

Commit fb10ddf35c1c ("KVM: arm64: Compute per-vCPU FGTs at vcpu_load()")
introduced per-VCPU FGT traps. For an unprotected pKVM VCPU, the untrusted
host FGT configuration is copied in pkvm_vcpu_init_traps(), which is called
from __pkvm_init_vcpu(). __pkvm_init_vcpu() is called once per VCPU (when
the VCPU is first run) which means that the uninitialized, zero, values for
the FGT registers end up being used for the entire lifetime of the VCPU.
This causes both unwanted traps (for the inverse polarity trap bits) and
the guest being allowed to access registers it shouldn't.

Fix it by copying the FGT traps for unprotected pKVM VCPUs when the
untrusted host loads the VCPU.

Fixes: fb10ddf35c1c ("KVM: arm64: Compute per-vCPU FGTs at vcpu_load()")
Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
---
 arch/arm64/kvm/hyp/nvhe/hyp-main.c | 12 ++++++++++--
 arch/arm64/kvm/hyp/nvhe/pkvm.c     |  1 -
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 29430c031095..ee0f1343100c 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -167,6 +167,7 @@ static void handle___pkvm_vcpu_load(struct kvm_cpu_context *host_ctxt)
 	DECLARE_REG(unsigned int, vcpu_idx, host_ctxt, 2);
 	DECLARE_REG(u64, hcr_el2, host_ctxt, 3);
 	struct pkvm_hyp_vcpu *hyp_vcpu;
+	struct kvm_vcpu *hyp_kvm_vcpu;
 
 	if (!is_protected_kvm_enabled())
 		return;
@@ -175,10 +176,17 @@ static void handle___pkvm_vcpu_load(struct kvm_cpu_context *host_ctxt)
 	if (!hyp_vcpu)
 		return;
 
+	hyp_kvm_vcpu = &hyp_vcpu->vcpu;
+
 	if (pkvm_hyp_vcpu_is_protected(hyp_vcpu)) {
 		/* Propagate WFx trapping flags */
-		hyp_vcpu->vcpu.arch.hcr_el2 &= ~(HCR_TWE | HCR_TWI);
-		hyp_vcpu->vcpu.arch.hcr_el2 |= hcr_el2 & (HCR_TWE | HCR_TWI);
+		hyp_kvm_vcpu->arch.hcr_el2 &= ~(HCR_TWE | HCR_TWI);
+		hyp_kvm_vcpu->arch.hcr_el2 |= hcr_el2 & (HCR_TWE | HCR_TWI);
+	} else {
+		struct kvm_vcpu *host_vcpu = hyp_vcpu->host_vcpu;
+
+		memcpy(&hyp_kvm_vcpu->arch.fgt, host_vcpu->arch.fgt,
+		       sizeof(hyp_kvm_vcpu->arch.fgt));
 	}
 }
 
diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index 43bde061b65d..05774aed09cb 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -172,7 +172,6 @@ static int pkvm_vcpu_init_traps(struct pkvm_hyp_vcpu *hyp_vcpu)
 
 		/* Trust the host for non-protected vcpu features. */
 		vcpu->arch.hcrx_el2 = host_vcpu->arch.hcrx_el2;
-		memcpy(vcpu->arch.fgt, host_vcpu->arch.fgt, sizeof(vcpu->arch.fgt));
 		return 0;
 	}
 
-- 
2.52.0



From alexandru.elisei at arm.com  Wed Dec 10 05:21:02 2025
From: alexandru.elisei at arm.com (Alexandru Elisei)
Date: Wed, 10 Dec 2025 13:21:02 +0000
Subject: [PATCH 2/2] KVM: arm64: Remove extra argument for __pvkm_host_{share,unshare}_hyp()
In-Reply-To: <20251210132102.137631-1-alexandru.elisei@arm.com>
References: <20251210132102.137631-1-alexandru.elisei@arm.com>
Message-ID: <20251210132102.137631-3-alexandru.elisei@arm.com>

__pvkm_host_share_hyp() and __pkvm_host_unshare_hyp() both have one
parameter, the pfn, not two. Even though correctness isn't impacted because
the SMCCC handlers pass the first argument and ignore the second one, let's
call the functions with the proper number of arguments.

Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
---
 arch/arm64/kvm/mmu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index 7cc964af8d30..6c6abcd8e89e 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -497,7 +497,7 @@ static int share_pfn_hyp(u64 pfn)
 	this->count = 1;
 	rb_link_node(&this->node, parent, node);
 	rb_insert_color(&this->node, &hyp_shared_pfns);
-	ret = kvm_call_hyp_nvhe(__pkvm_host_share_hyp, pfn, 1);
+	ret = kvm_call_hyp_nvhe(__pkvm_host_share_hyp, pfn);
 unlock:
 	mutex_unlock(&hyp_shared_pfns_lock);
 
-- 
2.52.0



From herve.codina at bootlin.com  Wed Dec 10 06:00:08 2025
From: herve.codina at bootlin.com (Herve Codina)
Date: Wed, 10 Dec 2025 15:00:08 +0100
Subject: [PATCH] dt-bindings: pci: brcmstb: Add rp1-nexus node to fix
 DTC warning
In-Reply-To: <aThp99OfgAfNFUX-@apocalypse>
References: <20250812085037.13517-1-andrea.porta@suse.com>
	<4fee3870-f9d5-48e3-a5be-6df581d3e296@kernel.org>
	<aKc5nMT1xXpY03ip@apocalypse>
	<e7875f70-2b79-48e0-a63b-caf6f1fd287b@kernel.org>
	<aLVePQRfU4IB1zK8@apocalypse>
	<CAL_JsqJUzB71QdMcxJtNZ7raoPcK+SfTh7EVzGmk=syo8xLKQw@mail.gmail.com>
	<aThjYt3ux0U-9-3A@apocalypse>
	<aThp99OfgAfNFUX-@apocalypse>
Message-ID: <20251210150008.2ef2f8c4@bootlin.com>

Hi Andrea,

On Tue, 9 Dec 2025 19:27:03 +0100
Andrea della Porta <andrea.porta at suse.com> wrote:

> [+cc Herve]
> 
> On 18:58 Tue 09 Dec     , Andrea della Porta wrote:
> > Hi Rob,
> > 
> > On 11:09 Thu 04 Dec     , Rob Herring wrote:  
> > > On Mon, Sep 1, 2025 at 3:48?AM Andrea della Porta <andrea.porta at suse.com> wrote:  
> > > >
> > > > Hi Krzysztof,
> > > >
> > > > On 08:50 Fri 22 Aug     , Krzysztof Kozlowski wrote:  
> > > > > On 21/08/2025 17:22, Andrea della Porta wrote:  
> > > > > > Hi Krzysztof,
> > > > > >
> > > > > > On 10:55 Tue 12 Aug     , Krzysztof Kozlowski wrote:  
> > > > > >> On 12/08/2025 10:50, Andrea della Porta wrote:  
> > > > > >>> The devicetree compiler is complaining as follows:
> > > > > >>>
> > > > > >>> arch/arm64/boot/dts/broadcom/rp1-nexus.dtsi:3.11-14.3: Warning (unit_address_vs_reg): /axi/pcie at 1000120000/rp1_nexus: node has a reg or ranges property, but no unit name
> > > > > >>> /home/andrea/linux-torvalds/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dtb: pcie at 1000120000: Unevaluated properties are not allowed ('rp1_nexus' was unexpected)  
> > > > > >>
> > > > > >> Please trim the paths.  
> > > > > >
> > > > > > Ack.
> > > > > >  
> > > > > >>  
> > > > > >>>
> > > > > >>> Add the optional node that fix this to the DT binding.
> > > > > >>>
> > > > > >>> Reported-by: kernel test robot <lkp at intel.com>
> > > > > >>> Closes: https://lore.kernel.org/oe-kbuild-all/202506041952.baJDYBT4-lkp at intel.com/
> > > > > >>> Signed-off-by: Andrea della Porta <andrea.porta at suse.com>
> > > > > >>> ---
> > > > > >>>  Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml | 9 +++++++++
> > > > > >>>  1 file changed, 9 insertions(+)
> > > > > >>>
> > > > > >>> diff --git a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
> > > > > >>> index 812ef5957cfc..7d8ba920b652 100644
> > > > > >>> --- a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
> > > > > >>> +++ b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
> > > > > >>> @@ -126,6 +126,15 @@ required:
> > > > > >>>  allOf:
> > > > > >>>    - $ref: /schemas/pci/pci-host-bridge.yaml#
> > > > > >>>    - $ref: /schemas/interrupt-controller/msi-controller.yaml#
> > > > > >>> +  - if:
> > > > > >>> +      properties:
> > > > > >>> +        compatible:
> > > > > >>> +          contains:
> > > > > >>> +            const: brcm,bcm2712-pcie
> > > > > >>> +    then:
> > > > > >>> +      properties:
> > > > > >>> +        rp1_nexus:  
> > > > > >>
> > > > > >> No, you cannot document post-factum... This does not follow DTS coding
> > > > > >> style.  
> > > > > >
> > > > > > I think I didn't catch what you mean here: would that mean that
> > > > > > we cannot resolve that warning since we cannot add anything to the
> > > > > > binding?  
> > > > >
> > > > > I meant, you cannot use a warning from the code you recently introduced
> > > > > as a reason to use incorrect style.
> > > > >
> > > > > Fixing warning is of course fine and correct, but for the code recently
> > > > > introduced and which bypassed ABI review it is basically like new review
> > > > > of new ABI.
> > > > >
> > > > > This needs standard review practice, so you need to document WHY you
> > > > > need such node. Warning is not the reason here why you are doing. If
> > > > > this was part of original patchset, like it should have been, you would
> > > > > not use some imaginary warning as reason, right?
> > > > >
> > > > > So provide reason why you need here this dedicated child, what is that
> > > > > child representing.  
> > > >
> > > > Ack.
> > > >  
> > > > >
> > > > > Otherwise I can suggest: drop the child and DTSO, this also solves the
> > > > > warning...  
> > > >
> > > > This would not fix the issue: it's the non overlay that needs the specific
> > > > node. But I got the point, and we have a solution for that (see below).
> > > >  
> > > > >  
> > > > > >
> > > > > > Regarding rp1_nexus, you're right I guess it should be
> > > > > > rp1-nexus as per DTS coding style.
> > > > > >  
> > > > > >>
> > > > > >> Also:
> > > > > >>
> > > > > >> Node names should be generic. See also an explanation and list of
> > > > > >> examples (not exhaustive) in DT specification:
> > > > > >> https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation  
> > > > > >
> > > > > > In this case it could be difficult: we need to search for a DT node  
> > > > >
> > > > > Search like in driver? That's wrong, you should be searching by compatible.  
> > > >
> > > > Thanks for the hint. Searching by compatble is the solution.  
> > > 
> > > No, it is not.  
> > 
> > This is partly true, indeed. On one side there's the need to avoid a
> > specific node name ('rp1_nexus'), so the only other unique identifier would
> > be the compatible string ('pci1de4,1' in this case, which identifies that specific
> > device). Unfortunately, the same compatible string is also assigned to the pci
> > endpoint node filled automatically by enabling CONFIG_PCI_DYNAMIC_OF_NODES.
> > We would end up with two nodes with the same compatible, which is not unique
> > anymore. 
> > This applies only when using 'full' dtb (bcm2712-rpi-5-b.dtb) *and* you enable
> > CONFIG_PCI_DYNAMIC_OF_NODES, the latter being not necessary since the overlay dtb
> > (...-ovl-rp1.dtb) is not in use here. To overcome this problem, the solutions
> > I can think of are the following:
> > 
> > 1- Just disable CONFIG_PCI_DYNAMIC_OF_NODES should work, but only when using the
> >    full dtb version. However, if the user enable that option for debug or to use
> >    the overlay dtb version, he better be sure not to use teh full dtb or it won't
> >    work.
> >    This solution seems really weak.
> > 
> > 2- Add another compatible string other than 'pci1de4,1', so it will be really
> >    unique.
> >   
> > >   
> > > > >  
> > > > > > starting from the DT root and using generic names like pci at 0,0 or
> > > > > > dev at 0,0 could possibly led to conflicts with other peripherals.
> > > > > > That's why I chose a specific name.  
> > > > >
> > > > > Dunno, depends what can be there, but you do not get a specific
> > > > > (non-generic) device node name for a generic PCI device or endpoint.  
> > > >
> > > > I would use 'port' instead of rp1-nexus. Would it work for you?  
> > > 
> > > Do you still plan to fix this? This is broken far worse than just the node name.  
> > 
> > Yes, if we want to get rid of that nasty warning and comply with DT guidelines,
> > I think I really need to fix that.
> >   
> > > 
> > > The 'rp1_nexus' node is applied to the PCI host bridge. That's wrong
> > > unless this is PCI rather than PCIe. There's the root port device in
> > > between.
> > > 
> > > The clue that things are wrong are start in the driver here:
> > > 
> > > rp1_node = of_find_node_by_name(NULL, "rp1_nexus");
> > > if (!rp1_node) {
> > >   rp1_node = dev_of_node(dev);
> > >   skip_ovl = false;
> > > }

I don't fully understand what you want to do.

This piece of code is present in the drivers/misc/rp1/rp1_pci.c driver.
This driver is used when a specific PCI device is available on the system.
This device is PCI_DEVICE(PCI_VENDOR_ID_RPI, PCI_DEVICE_ID_RPI_RP1_C0)

In order to work, the driver needs either CONFIG_PCI_DYNAMIC_OF_NODES or
having the full PCI hierarchy described in the DT leading to this device.
Indeed, it needs a DT node related to the PCI device.

I don't understand why rp1_nexus should be described at the PCI controller
root level.

Only PCI devices (or bridges as they are particular devices) at this level
as decribed in the pci-bus-common.yaml binding [1].

If the purpose of this 'rp1_nexus' node is to only avoid the application of
the overlay, even if I don't understand why, you should search for something
added by the overlay and not for the 'rp1_nexus' node in the whole DT.

Instead of:
  rp1_node = of_find_node_by_name(NULL, "rp1_nexus");

You should search for a sub-node added by the overlay. Something like the
following for instance:
--- 8< ---
int rp1_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
	struct device_node *np;

	np = dev_of_node(&pdev->dev);

	...
	if ( np && of_find_node_by_name(np, "pci-ep-bus at 1");
        ...
}
--- 8< ---

If you really want to be sure that the "pci-ep-bus at 1" comes from an overlay
you can check for the OF_OVERLAY flag.
--- 8< ---
  node = of_find_node_by_name(np, "pci-ep-bus at 1");
  if (node && of_node_check_flag(node, OF_OVERLAY))
--- 8< ---

Also your overlay has to be applied on the DT node related to your PCI
device and not the rp1_nexus you search for in the whole DT. In other
word, in your driver, the following is not correct:

   err = of_overlay_fdt_apply(dtbo_start, dtbo_size, &rp1->ovcs_id,
                                           rp1_node);

It should be:

   err = of_overlay_fdt_apply(dtbo_start, dtbo_size, &rp1->ovcs_id,
                                           dev_of_node(&pdev->dev));
 
In your overlay, your have
	__overlay__ {
		compatible = "pci1de4,1";
		#address-cells = <3>;
		#size-cells = <2>;
		interrupt-controller;
		#interrupt-cells = <2>;

		#include "arm64/broadcom/rp1-common.dtsi"
       };

Only sub-nodes should be present (#address-cells = <3> and #size-cells = <2>)
can be there just to make DTC happy.

It is worth noting that any properties other than #address-cells and
#size-cells lead to memleaks. And so avoid them.

Memleaks are reported at runtime when the overlay is applied with this
kind of logs:
 OF: overlay: WARNING: memory leak will occur if overlay removed, property: ...

I am pretty sure that you have those kind of traces when you apply your
overlay.

compatible, interrupt-controller and #interrupt-cells should not be added by
the overlay. Either they are added by when PCI nodes are created by 
CONFIG_PCI_DYNAMIC_OF_NODES either they are already available in the base
DT if the PCI device is described in the base DT.

[1] https://github.com/devicetree-org/dt-schema/blob/aa859412ce8e38c63bb13fa55c5e1c6ba66a8e3b/dtschema/schemas/pci/pci-bus-common.yaml#L226

Best regards,
Herv?


From Markus.Elfring at web.de  Wed Dec 10 06:11:03 2025
From: Markus.Elfring at web.de (Markus Elfring)
Date: Wed, 10 Dec 2025 15:11:03 +0100
Subject: [PATCH] input: mtk-pmic-keys: Fix potential NULL pointer
 dereference in probe()
In-Reply-To: <20251210030013.913-1-vulab@iscas.ac.cn>
References: <20251210030013.913-1-vulab@iscas.ac.cn>
Message-ID: <316d6242-fbfa-4c9e-addd-e9f76facf9d7@web.de>

> of_match_device() may return NULL when the device node
> does not match any entry in the driver's match table.
> The current code dereferences of_id->data unconditionally,
> which can lead to a NULL pointer dereference.
?

Under which circumstances would you get into the mood to take more desirable
word wrap preferences better into account?
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/submitting-patches.rst?h=v6.18#n658

Regards,
Markus


From josua at solid-run.com  Wed Dec 10 06:21:56 2025
From: josua at solid-run.com (Josua Mayer)
Date: Wed, 10 Dec 2025 14:21:56 +0000
Subject: [PATCH v4 7/8] arm64: dts: add description for solidrun
 solidsense-n8 board
In-Reply-To: <c06e5a6b-6150-4771-8ff6-b2cda0863a21@lunn.ch>
References: <20251201-imx8mp-hb-iiot-v4-0-53a4cd6c21bf@solid-run.com>
 <20251201-imx8mp-hb-iiot-v4-7-53a4cd6c21bf@solid-run.com>
 <c06e5a6b-6150-4771-8ff6-b2cda0863a21@lunn.ch>
Message-ID: <eb258010-3778-4852-833d-a51a6b3ca36c@solid-run.com>

Hi Andrew,

Am 01.12.25 um 14:49 schrieb Andrew Lunn:
>> +&fec1 {
>> +	pinctrl-names = "default";
>> +	pinctrl-0 = <&fec1_pins>;
>> +	phy-mode = "rgmii-id";
>> +	phy-handle = <&phy4>;
>> +	local-mac-address = [00 00 00 00 00 00];
>> +	fsl,magic-packet;
> Has WoL been tested, or is this copy/paste from the binding
> documentation?

This is copy-paste by previous developers which I did not validate.

So I may wish to drop both local-mac-address property
(should be automatic by u-boot),

and drop the magic-packet here.

>
>> +	status = "okay";
>> +
>> +	mdio {
>> +		#address-cells = <1>;
>> +		#size-cells = <0>;
>> +
>> +		/*
>> +		 * Depending on board revision two different phys are used:
>> +		 * - v1.1: atheros phy at address 4
>> +		 * - v1.2+: analog devices phy at address 0
>> +		 * Configure first version by default.
>> +		 * On v1.2 and later, U-Boot will enable the correct phy
>> +		 * based on runtime detection and patch dtb accordingly.
>> +		 */
>> +
>> +		/* ADIN1300 */
>> +		phy0: ethernet-phy at 0 {
>> +			reg = <0>;
>> +			reset-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>;
>> +			reset-assert-us = <10>;
>> +			reset-deassert-us = <5000>;
>> +			interrupt-parent = <&gpio1>;
>> +			interrupts = <10 IRQ_TYPE_LEVEL_LOW>;
> The analog devices PHY has interrupts, so can it implement WoL? Has
> this been tested?
Interrupts were tested, WoL was not.
>
>> +		/* AR8035 */
>> +		phy4: ethernet-phy at 4 {
>> +			reg = <4>;
>> +			reset-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>;
>> +			reset-assert-us = <10000>;
>> +			status = "okay";
> The Atheros PHY does not interrupts, so i assume it cannot support
> WoL? You only have MAC WoL?
We have never tested any off states where the phy was still on.
Instead the board is designed to be always-in with supercap to cover
glitches and/or ensure graceful shutdown.

So I suggest dropping any traces of WoL.

regards
Josua Mayer

From rkrcmar at ventanamicro.com  Wed Dec 10 06:22:29 2025
From: rkrcmar at ventanamicro.com (=?utf-8?q?Radim_Kr=C4=8Dm=C3=A1=C5=99?=)
Date: Wed, 10 Dec 2025 23:22:29 +0900
Subject: [External] Re: [PATCH v3 5/8] riscv: smp: use NMI for CPU stop
In-Reply-To: <CAEEQ3wngwxjiytt7g6XY0bC1PL4A1NEmirML7FiqXMA4_K0irw@mail.gmail.com>
References: <20251127125305.89961-1-cuiyunhui@bytedance.com>
 <20251127125305.89961-6-cuiyunhui@bytedance.com>
 <DEP4X1DAIOU5.2WLIV4BMWLMRR@ventanamicro.com>
 <CAEEQ3wmAn=9w=fR=OMTMF17_tAcEnsdJWL_w8fw-3wA-Bfi6xw@mail.gmail.com>
 <DEPGLFUVHA0O.XSZVD2T1ENLD@ventanamicro.com>
 <CAEEQ3wngwxjiytt7g6XY0bC1PL4A1NEmirML7FiqXMA4_K0irw@mail.gmail.com>
Message-ID: <DEULRAM55E2G.1464D4JSWL3SZ@ventanamicro.com>

2025-12-08T19:40:39+08:00, yunhui cui <cuiyunhui at bytedance.com>:
> Hi Radim,
>
> On Thu, Dec 4, 2025 at 9:16?PM Radim Kr?m?? <rkrcmar at ventanamicro.com> wrote:
>>
>> 2025-12-04T13:28:45+08:00, yunhui cui <cuiyunhui at bytedance.com>:
>> > Hi Radim,
>> >
>> > On Thu, Dec 4, 2025 at 12:07?PM Radim Kr?m?? <rkrcmar at ventanamicro.com> wrote:
>> >>
>> >> 2025-11-27T20:53:02+08:00, Yunhui Cui <cuiyunhui at bytedance.com>:
>> >> > Use NMI instead of IPI for CPU stop if RISC-V SSE NMI is supported.
>> >> >
>> >> > Signed-off-by: Yunhui Cui <cuiyunhui at bytedance.com>
>> >> > ---
>> >> > diff --git a/drivers/firmware/riscv/riscv_sse_nmi.c b/drivers/firmware/riscv/riscv_sse_nmi.c
>> >> > @@ -58,6 +58,7 @@ static int local_nmi_handler(u32 evt, void *arg, struct pt_regs *regs)
>> >> >       type = atomic_read(this_cpu_ptr(&local_nmi));
>> >> >
>> >> >       NMI_HANDLE(LOCAL_NMI_CRASH, cpu_crash_stop, cpu, regs);
>> >> > +     NMI_HANDLE(LOCAL_NMI_STOP, cpu_stop);
>> >>
>> >> Please document the intended preemption design for all SSE events,
>> >> because it will be a nightmare if we forget some assumptions in the
>> >> coming years.  (That includes the relative priorities of RAS/PMU/...)
>> >
>> > Actually, LOCAL_NMI_CRASH, LOCAL_NMI_STOP, LOCAL_NMI_BACKTRACE,
>> > LOCAL_NMI_KGDB, ... are all implemented via the single SSE event
>> > SBI_SSE_EVENT_LOCAL_SOFTWARE_INJECTED. Per the SSE design, no
>> > preemption will occur among CRASH, STOP, BACKTRACE, and KGDB events.
>>
>> That is how it is.  I don't understand why it must be like that.
>>
>> For example: PMU_OVERFLOW has lower event_id than SOFTWARE_INJECTED, so
>> it will currently interrupt NMI_CRASH as they both have priority 0,
>> although NMI_CRASH probably shouldn't be masked by anything, and should
>> preempt everything.
>> NMI_BACKTRACE, on the other hand, probably shouldn't have that high
>> priority as there seem more important events (e.g. RAS and NMI_CRASH).
>>
>> The issues can be avoided by event priorities, masking, or deemed as
>> non-issue, but I think it would be beneficial to provide some reasoning
>> behind the design, as the choices don't seem obvious to me.
>
> Indeed, it is necessary to consider the priority among different
> events. Should different priorities also be assigned to NMI_CRASH,
> NMI_BACKTRACE, NMI_STOP, and NMI_KGDB?

I think it would be beneficial to document the desired behavior even if
we can't (currently?) implement it, because like you said, SSE can't
directly express the priority when multiplexing SOFTWARE_INJECTED.

>                                        Do these operations need to be
> visible to the BIOS?

BIOS shouldn't care what lower privilege wants to do.
SBI could define more events for software use, though.

>                      Could you kindly provide some good suggestions?

I think it would be good practice to explicitly set a unique priority
when registering SSE events.  Maybe through a global priority enum, and
make sure that all event registrations are passing a value from that
enum.

That would make sure that different events interact like we expect them
to, but it doesn't solve the multiplexing issue of SOFTWARE_INJECTED.

If we're fine with all SOFTWARE_INJECTED sub-handlers having the maximal
priority (higher than RAS/PMU/UNKNOWN_NMI/...), then we could hope that
lower imporance handlers (e.g. BACKTRACE) won't hang, so the higher
importance handlers (e.g. CRASH) would eventually run.
We're dealing with low-occurrence scenarios, so this might be "good
enough for now"...

Situation would get simpler if we could avoid some sub-handlers;
alternatively, it would get more complicated if SOFTWARE_INJECTED had
lower priority than some other event -- we'd make CRASH partially
recover its high priority image by masking other SSE events during its
execution (and we'd need warding amulets against hangs and starvation).

Thanks.


From frank.li at nxp.com  Wed Dec 10 06:55:12 2025
From: frank.li at nxp.com (Frank Li)
Date: Wed, 10 Dec 2025 14:55:12 +0000
Subject: [EXT] Re: [PATCH v2] arm64: errata: Add NXP iMX8QM workaround for
 A53 Cache coherency issue
In-Reply-To: <20251210074550.GA10733@francesco-nb>
References: <20230420112952.28340-1-iivanov@suse.de>
 <20251210074550.GA10733@francesco-nb>
Message-ID: <DU2PR04MB8951DEE7CB2D29D7E83CE03388A0A@DU2PR04MB8951.eurprd04.prod.outlook.com>



> -----Original Message-----
> From: Francesco Dolcini <francesco at dolcini.it>
> Sent: Wednesday, December 10, 2025 1:46 AM
> To: Ivan T. Ivanov <iivanov at suse.de>; Frank Li <frank.li at nxp.com>; Jason Liu
> <jason.hui.liu at nxp.com>
> Cc: Catalin Marinas <catalin.marinas at arm.com>; Will Deacon
> <will at kernel.org>; Mark Brown <broonie at kernel.org>; Mark Rutland
> <mark.rutland at arm.com>; Shawn Guo <shawnguo at kernel.org>; Aisheng
> Dong <aisheng.dong at nxp.com>; linux-arm-kernel at lists.infradead.org; dl-
> linux-imx <linux-imx at nxp.com>
> Subject: [EXT] Re: [PATCH v2] arm64: errata: Add NXP iMX8QM workaround
> for A53 Cache coherency issue
> 
> Caution: This is an external email. Please take care when clicking links or
> opening attachments. When in doubt, report the message using the 'Report
> this email' button
> 
> 
> Hello Ivan,
> 
> On Thu, Apr 20, 2023 at 02:29:52PM +0300, Ivan T. Ivanov wrote:
> > According to NXP errata document[1] i.MX8QuadMax SoC suffers from
> > serious cache coherence issue. It was also mentioned in initial
> > support[2] for imx8qm mek machine.
> 
> Ivan, from what I can see this patch was never merged and there was not any
> follow-up on this. What's the status? Are you planning to work on it?
> 
> Frank, it would be nice to have this issue sorted out in mainline, any
> chance that NXP can help move this forward?

Jason worked the original solution, what's difficult of upstream accept the
Solution?

Frank 

> 
> Francesco



From linux at armlinux.org.uk  Wed Dec 10 07:11:40 2025
From: linux at armlinux.org.uk (Russell King (Oracle))
Date: Wed, 10 Dec 2025 15:11:40 +0000
Subject: [PATCH 0/3] ARM: fix hash_name() and branch predictor issues
In-Reply-To: <20251210090836.60465-1-xieyuanbin1@huawei.com>
References: <20251209085627.64057-1-xieyuanbin1@huawei.com>
 <20251210090836.60465-1-xieyuanbin1@huawei.com>
Message-ID: <aTmNrPVmd7sG7J8s@shell.armlinux.org.uk>

On Wed, Dec 10, 2025 at 05:08:36PM +0800, Xie Yuanbin wrote:
> Hi, Russell!
> 
> The syzkaller test has been running for 19+ hours now, and no issues
> have been found so far. So to patch3:
> 
> Tested-by: Xie Yuanbin <xieyuanbin1 at huawei.com>
> 
> This test will continue to run. If any issues are found, I will email
> you. If I don't send any emails, then there are no issues. :)

Thanks. I've updated the three patches, and pushed out the updated
tree. See the top four commits:

https://git.kernel.org/pub/scm/linux/kernel/git/rmk/linux.git/log/?h=fixes

Given the timings, I doubt that linux-next will pick this up before
I need to send Linus a pull request before going on vacation for the
remainder of this year:

https://git.kernel.org/pub/scm/linux/kernel/git/rmk/linux.git/log/?h=for-linus

However, I also can't guarantee that I'll be able to look at mainline
at the start of next year due to other pressures - and I don't yet
know for how long that's likely to be at the moment.

So, it's either a pull request for the for-linus tag later today,
at some point next year likely not before mid-January and splitting
it up into fixes (for -rc) and the two PREEMPT_RT non-fix patches (for
the next merge window.)

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


From stefano.r at variscite.com  Wed Dec 10 07:19:52 2025
From: stefano.r at variscite.com (Stefano Radaelli)
Date: Wed, 10 Dec 2025 16:19:52 +0100
Subject: [PATCH v1 0/6] arm64: dts: imx8mp-var-som: align DTS with hardware revision
Message-ID: <20251210152000.42265-1-stefano.r@variscite.com>

This patchset updates the device tree support for the VAR-SOM-MX8MP
module by removing nodes for hardware that is not populated on the SOM
and by introducing support for several on-module peripherals.

The first three patches drop USDHC2, the PCA9534 GPIO expander and
UART2, all of which are only present on the Symphony carrier board or
other custom carrier designs, and thus should not appear in the SOM
device tree.

The remaining patches add support for WiFi+Bluetooth connectivity, the
WM8904 audio codec, and the ADS7846 touchscreen controller.

This series ensures that the SOM device tree only describes hardware
that is actually present on the module, while enabling key on-module
features used across multiple designs.

Stefano Radaelli (6):
  arm64: dts: imx8mp-var-som: Remove USDHC2 controller and related
    signals
  arm64: dts: imx8mp-var-som: Remove PCA9534 GPIO expander
  arm64: dts: imx8mp-var-som: Remove UART2 console
  arm64: dts: imx8mp-var-som: Add WiFi and Bluetooth support
  arm64: dts: imx8mp-var-som: Add support for WM8904 audio codec
  arm64: dts: imx8mp-var-som: Add support for ADS7846 touchscreen

 .../boot/dts/freescale/imx8mp-var-som.dtsi    | 332 +++++++++++-------
 1 file changed, 211 insertions(+), 121 deletions(-)


base-commit: cb015814f8b6eebcbb8e46e111d108892c5e6821
-- 
2.47.3



From stefano.r at variscite.com  Wed Dec 10 07:19:53 2025
From: stefano.r at variscite.com (Stefano Radaelli)
Date: Wed, 10 Dec 2025 16:19:53 +0100
Subject: [PATCH v1 1/6] arm64: dts: imx8mp-var-som: Remove USDHC2 controller and related signals
In-Reply-To: <20251210152000.42265-1-stefano.r@variscite.com>
References: <20251210152000.42265-1-stefano.r@variscite.com>
Message-ID: <20251210152000.42265-2-stefano.r@variscite.com>

The VAR-SOM-MX8MP does not include any microSD slot connected to USDHC2.
The USDHC2 interface is instead available only on the Symphony carrier
board, and customers may optionally route it on their custom carrier
boards.

Since USDHC2 is not populated on the SOM, drop the USDHC2 node together
with its regulators, pinctrl groups and GPIOs from the SOM device tree.

This avoids exposing non-existing hardware and prevents misleading DT
descriptions for boards that do not implement USDHC2.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../boot/dts/freescale/imx8mp-var-som.dtsi    | 75 -------------------
 1 file changed, 75 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
index 29f080904482..949d9878f395 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
@@ -35,27 +35,6 @@ memory at 40000000 {
 		      <0x1 0x00000000 0 0xc0000000>;
 	};
 
-	reg_usdhc2_vmmc: regulator-usdhc2-vmmc {
-	        compatible = "regulator-fixed";
-	        regulator-name = "VSD_3V3";
-	        regulator-min-microvolt = <3300000>;
-	        regulator-max-microvolt = <3300000>;
-	        gpios = <&gpio4 22 GPIO_ACTIVE_HIGH>;
-	        enable-active-high;
-	        startup-delay-us = <100>;
-	        off-on-delay-us = <12000>;
-	};
-
-	reg_usdhc2_vqmmc: regulator-usdhc2-vqmmc {
-		compatible = "regulator-gpio";
-		regulator-name = "VSD_VSEL";
-		regulator-min-microvolt = <1800000>;
-		regulator-max-microvolt = <3300000>;
-		gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>;
-		states = <3300000 0x0 1800000 0x1>;
-		vin-supply = <&ldo5>;
-	};
-
 	reg_phy_supply: regulator-phy-supply {
 		compatible = "regulator-fixed";
 		regulator-name = "phy-supply";
@@ -271,19 +250,6 @@ &uart2 {
         status = "okay";
 };
 
-/* SD-card */
-&usdhc2 {
-        pinctrl-names = "default", "state_100mhz", "state_200mhz";
-        pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
-        pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
-        pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
-        cd-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;
-        vmmc-supply = <&reg_usdhc2_vmmc>;
-	vqmmc-supply = <&reg_usdhc2_vqmmc>;
-        bus-width = <4>;
-        status = "okay";
-};
-
 /* eMMC */
 &usdhc3 {
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
@@ -358,47 +324,6 @@ MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX                            0x40
 		>;
 	};
 
-	pinctrl_usdhc2_gpio: usdhc2-gpiogrp {
-	        fsl,pins = <
-	                MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14                             0x1c4
-	                MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22                               0x10
-	                MX8MP_IOMUXC_SD2_CD_B__GPIO2_IO12                               0xc0
-	        >;
-	};
-
-	pinctrl_usdhc2: usdhc2grp {
-	        fsl,pins = <
-	                MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK                                0x190
-	                MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD                                0x1d0
-	                MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0                            0x1d0
-	                MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1                            0x1d0
-	                MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2                            0x1d0
-	                MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3                            0x1d0
-	        >;
-	};
-
-	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
-	        fsl,pins = <
-	                MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK                                0x194
-	                MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD                                0x1d4
-	                MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0                            0x1d4
-	                MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1                            0x1d4
-	                MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2                            0x1d4
-	                MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3                            0x1d4
-	        >;
-	};
-
-	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
-	        fsl,pins = <
-	                MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK                                0x196
-	                MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD                                0x1d6
-	                MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0                            0x1d6
-	                MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1                            0x1d6
-	                MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2                            0x1d6
-	                MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3                            0x1d6
-	        >;
-	};
-
 	pinctrl_usdhc3: usdhc3grp {
 		fsl,pins = <
 			MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK				0x190
-- 
2.47.3



From stefano.r at variscite.com  Wed Dec 10 07:19:55 2025
From: stefano.r at variscite.com (Stefano Radaelli)
Date: Wed, 10 Dec 2025 16:19:55 +0100
Subject: [PATCH v1 3/6] arm64: dts: imx8mp-var-som: Remove UART2 console
In-Reply-To: <20251210152000.42265-1-stefano.r@variscite.com>
References: <20251210152000.42265-1-stefano.r@variscite.com>
Message-ID: <20251210152000.42265-4-stefano.r@variscite.com>

The VAR-SOM-MX8MP does not include an onboard console connector. The
debug UART is provided on the Symphony carrier board, and customers may
choose to expose any UART controller on their own carrier designs.

Since UART2 is not populated on the SOM, drop the UART2 node from the
SOM device tree.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../boot/dts/freescale/imx8mp-var-som.dtsi     | 18 ------------------
 1 file changed, 18 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
index 158a78ec9656..5bba91dcef17 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
@@ -15,10 +15,6 @@
 / {
 	model = "Variscite VAR-SOM-MX8M Plus module";
 
-	chosen {
-		stdout-path = &uart2;
-	};
-
 	memory at 40000000 {
 		device_type = "memory";
 		reg = <0x0 0x40000000 0 0xc0000000>,
@@ -206,13 +202,6 @@ ldo5: LDO5 {
 	};
 };
 
-/* Console */
-&uart2 {
-        pinctrl-names = "default";
-        pinctrl-0 = <&pinctrl_uart2>;
-        status = "okay";
-};
-
 /* eMMC */
 &usdhc3 {
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
@@ -267,13 +256,6 @@ MX8MP_IOMUXC_SPDIF_RX__GPIO5_IO04				0x1c0
 		>;
 	};
 
-	pinctrl_uart2: uart2grp {
-	        fsl,pins = <
-		        MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX                            0x40
-			MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX                            0x40
-		>;
-	};
-
 	pinctrl_usdhc3: usdhc3grp {
 		fsl,pins = <
 			MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK				0x190
-- 
2.47.3



From stefano.r at variscite.com  Wed Dec 10 07:19:56 2025
From: stefano.r at variscite.com (Stefano Radaelli)
Date: Wed, 10 Dec 2025 16:19:56 +0100
Subject: [PATCH v1 4/6] arm64: dts: imx8mp-var-som: Add WiFi and Bluetooth support
In-Reply-To: <20251210152000.42265-1-stefano.r@variscite.com>
References: <20251210152000.42265-1-stefano.r@variscite.com>
Message-ID: <20251210152000.42265-5-stefano.r@variscite.com>

Add device tree nodes for the WiFi and Bluetooth module mounted on the
VAR-SOM-MX8MP. The module can be based on either the NXP IW612 or IW611
chipset, depending on the configuration chosen by the customer.

Regardless of the chipset used, WiFi communicates over SDIO and Bluetooth
over UART.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../boot/dts/freescale/imx8mp-var-som.dtsi    | 93 +++++++++++++++++++
 1 file changed, 93 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
index 5bba91dcef17..e7f5ec10cbac 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
@@ -21,6 +21,15 @@ memory at 40000000 {
 		      <0x1 0x00000000 0 0xc0000000>;
 	};
 
+	iw61x_pwrseq: wifi-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		post-power-on-delay-ms = <100>;
+		power-off-delay-us = <10000>;
+		reset-gpios = <&gpio2 8 GPIO_ACTIVE_LOW>, /* WIFI_RESET */
+			      <&gpio2 19 GPIO_ACTIVE_LOW>; /* WIFI_PWR_EN */
+		status = "okay";
+	};
+
 	reg_phy_supply: regulator-phy-supply {
 		compatible = "regulator-fixed";
 		regulator-name = "phy-supply";
@@ -202,6 +211,33 @@ ldo5: LDO5 {
 	};
 };
 
+/* BT */
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart3>, <&pinctrl_bluetooth>;
+	assigned-clocks = <&clk IMX8MP_CLK_UART3>;
+	assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_80M>;
+	uart-has-rtscts;
+	status = "okay";
+
+	bluetooth {
+		compatible = "nxp,88w8987-bt";
+	};
+};
+
+/* WIFI */
+&usdhc1 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc1>, <&pinctrl_wifi>;
+	pinctrl-1 = <&pinctrl_usdhc1_100mhz>, <&pinctrl_wifi>;
+	pinctrl-2 = <&pinctrl_usdhc1_200mhz>, <&pinctrl_wifi>;
+	bus-width = <4>;
+	non-removable;
+	keep-power-in-suspend;
+	mmc-pwrseq = <&iw61x_pwrseq>;
+	status = "okay";
+};
+
 /* eMMC */
 &usdhc3 {
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
@@ -222,6 +258,14 @@ &wdog1 {
 
 &iomuxc {
 
+	pinctrl_bluetooth: bluetoothgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_DATA7__GPIO2_IO09                              0xc0
+			MX8MP_IOMUXC_GPIO1_IO04__GPIO1_IO04                             0xc0
+			MX8MP_IOMUXC_SD1_RESET_B__GPIO2_IO10                            0xc0
+		>;
+	};
+
 	pinctrl_eqos: eqosgrp {
 		fsl,pins = <
 			MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC				0x2
@@ -256,6 +300,48 @@ MX8MP_IOMUXC_SPDIF_RX__GPIO5_IO04				0x1c0
 		>;
 	};
 
+	pinctrl_uart3: uart3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_ECSPI1_SCLK__UART3_DCE_RX                          0x140
+			MX8MP_IOMUXC_ECSPI1_MOSI__UART3_DCE_TX                          0x140
+			MX8MP_IOMUXC_ECSPI1_MISO__UART3_DCE_CTS                         0x140
+			MX8MP_IOMUXC_ECSPI1_SS0__UART3_DCE_RTS                          0x140
+		>;
+	};
+
+	pinctrl_usdhc1: usdhc1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK                                0x190
+			MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD                                0x1d0
+			MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0                            0x1d0
+			MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1                            0x1d0
+			MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2                            0x1d0
+			MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3                            0x1d0
+		>;
+	};
+
+	pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK                                0x194
+			MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD                                0x1d4
+			MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0                            0x1d4
+			MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1                            0x1d4
+			MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2                            0x1d4
+			MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3                            0x1d4
+		>;
+	};
+
+	pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK                                0x196
+			MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD                                0x1d6
+			MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0                            0x1d6
+			MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1                            0x1d6
+			MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2                            0x1d6
+			MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3                            0x1d6
+		>;
+	};
+
 	pinctrl_usdhc3: usdhc3grp {
 		fsl,pins = <
 			MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK				0x190
@@ -309,4 +395,11 @@ pinctrl_wdog: wdoggrp {
 			MX8MP_IOMUXC_GPIO1_IO02__WDOG1_WDOG_B				0xc6
 		>;
 	};
+
+	pinctrl_wifi: wifigrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_DATA6__GPIO2_IO08                              0xc0
+			MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19                            0xc0
+		>;
+	};
 };
-- 
2.47.3



From stefano.r at variscite.com  Wed Dec 10 07:19:57 2025
From: stefano.r at variscite.com (Stefano Radaelli)
Date: Wed, 10 Dec 2025 16:19:57 +0100
Subject: [PATCH v1 5/6] arm64: dts: imx8mp-var-som: Add support for WM8904 audio codec
In-Reply-To: <20251210152000.42265-1-stefano.r@variscite.com>
References: <20251210152000.42265-1-stefano.r@variscite.com>
Message-ID: <20251210152000.42265-6-stefano.r@variscite.com>

The VAR-SOM-MX8MP can integrate the WM8904, a high-performance
ultra-low-power stereo codec optimized for portable audio applications.

This patch adds the WM8904 device to the appropriate I2C bus, enables
the SAI peripheral, and introduces the sound node to expose the
sound card to the system.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../boot/dts/freescale/imx8mp-var-som.dtsi    | 94 +++++++++++++++++++
 1 file changed, 94 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
index e7f5ec10cbac..169fc6a9c8cb 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
@@ -30,6 +30,14 @@ iw61x_pwrseq: wifi-pwrseq {
 		status = "okay";
 	};
 
+	reg_audio_supply: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "wm8904-supply";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
 	reg_phy_supply: regulator-phy-supply {
 		compatible = "regulator-fixed";
 		regulator-name = "phy-supply";
@@ -47,6 +55,34 @@ reg_phy_vddio: regulator-phy-vddio {
 		regulator-min-microvolt = <1800000>;
 		regulator-max-microvolt = <1800000>;
 	};
+
+	sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,bitclock-master = <&codec_dai>;
+		simple-audio-card,format = "i2s";
+		simple-audio-card,frame-master = <&codec_dai>;
+		simple-audio-card,mclk-fs = <256>;
+		simple-audio-card,name = "wm8904-audio";
+		simple-audio-card,routing =
+			"Headphone Jack", "HPOUTL",
+			"Headphone Jack", "HPOUTR",
+			"IN2L", "Line In Jack",
+			"IN2R", "Line In Jack",
+			"IN1L", "Microphone Jack",
+			"IN1R", "Microphone Jack";
+		simple-audio-card,widgets =
+			"Microphone", "Microphone Jack",
+			"Headphone", "Headphone Jack",
+			"Line", "Line In Jack";
+
+		codec_dai: simple-audio-card,codec {
+			sound-dai = <&wm8904>;
+		};
+
+		simple-audio-card,cpu {
+			sound-dai = <&sai3>;
+		};
+	};
 };
 
 &A53_0 {
@@ -209,6 +245,52 @@ ldo5: LDO5 {
 			};
 		};
 	};
+
+	wm8904: audio-codec at 1a {
+		compatible = "wlf,wm8904";
+		reg = <0x1a>;
+		#sound-dai-cells = <0>;
+		clocks = <&audio_blk_ctrl IMX8MP_CLK_AUDIOMIX_SAI3_MCLK1>;
+		clock-names = "mclk";
+		AVDD-supply = <&reg_audio_supply>;
+		CPVDD-supply = <&reg_audio_supply>;
+		DBVDD-supply = <&reg_audio_supply>;
+		DCVDD-supply = <&reg_audio_supply>;
+		MICVDD-supply = <&reg_audio_supply>;
+		wlf,drc-cfg-names = "default", "peaklimiter", "tradition",
+				    "soft", "music";
+		/*
+		 * Config registers per name, respectively:
+		 * KNEE_IP = 0,   KNEE_OP = 0,     HI_COMP = 1,   LO_COMP = 1
+		 * KNEE_IP = -24, KNEE_OP = -6,    HI_COMP = 1/4, LO_COMP = 1
+		 * KNEE_IP = -42, KNEE_OP = -3,    HI_COMP = 0,   LO_COMP = 1
+		 * KNEE_IP = -45, KNEE_OP = -9,    HI_COMP = 1/8, LO_COMP = 1
+		 * KNEE_IP = -30, KNEE_OP = -10.5, HI_COMP = 1/4, LO_COMP = 1
+		 */
+		wlf,drc-cfg-regs = /bits/ 16 <0x01af 0x3248 0x0000 0x0000>,
+				   /bits/ 16 <0x04af 0x324b 0x0010 0x0408>,
+				   /bits/ 16 <0x04af 0x324b 0x0028 0x0704>,
+				   /bits/ 16 <0x04af 0x324b 0x0018 0x078c>,
+				   /bits/ 16 <0x04af 0x324b 0x0010 0x050e>;
+		/* GPIO1 = DMIC_CLK, don't touch others */
+		wlf,gpio-cfg = <0x0018>, <0xffff>, <0xffff>, <0xffff>;
+	};
+};
+
+&sai3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_sai3>;
+	assigned-clocks = <&clk IMX8MP_CLK_SAI3>;
+	assigned-clock-parents = <&clk IMX8MP_AUDIO_PLL1_OUT>;
+	assigned-clock-rates = <11536000>;
+	clocks = <&audio_blk_ctrl IMX8MP_CLK_AUDIOMIX_SAI3_IPG>,
+		 <&clk IMX8MP_CLK_DUMMY>,
+		 <&audio_blk_ctrl IMX8MP_CLK_AUDIOMIX_SAI3_MCLK1>,
+		 <&clk IMX8MP_CLK_DUMMY>,
+		 <&clk IMX8MP_CLK_DUMMY>;
+	clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
+	fsl,sai-mclk-direction-output;
+	status = "okay";
 };
 
 /* BT */
@@ -300,6 +382,18 @@ MX8MP_IOMUXC_SPDIF_RX__GPIO5_IO04				0x1c0
 		>;
 	};
 
+	pinctrl_sai3: sai3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI3_TXFS__AUDIOMIX_SAI3_TX_SYNC                   0xd6
+			MX8MP_IOMUXC_SAI3_TXC__AUDIOMIX_SAI3_TX_BCLK                    0xd6
+			MX8MP_IOMUXC_SAI3_RXD__AUDIOMIX_SAI3_RX_DATA00                  0xd6
+			MX8MP_IOMUXC_SAI3_TXD__AUDIOMIX_SAI3_TX_DATA00                  0xd6
+			MX8MP_IOMUXC_SAI3_MCLK__AUDIOMIX_SAI3_MCLK                      0xd6
+			MX8MP_IOMUXC_SAI3_RXFS__AUDIOMIX_SAI3_RX_SYNC                   0xd6
+			MX8MP_IOMUXC_SAI3_RXC__AUDIOMIX_SAI3_RX_BCLK                    0xd6
+		>;
+	};
+
 	pinctrl_uart3: uart3grp {
 		fsl,pins = <
 			MX8MP_IOMUXC_ECSPI1_SCLK__UART3_DCE_RX                          0x140
-- 
2.47.3



From stefano.r at variscite.com  Wed Dec 10 07:19:54 2025
From: stefano.r at variscite.com (Stefano Radaelli)
Date: Wed, 10 Dec 2025 16:19:54 +0100
Subject: [PATCH v1 2/6] arm64: dts: imx8mp-var-som: Remove PCA9534 GPIO expander
In-Reply-To: <20251210152000.42265-1-stefano.r@variscite.com>
References: <20251210152000.42265-1-stefano.r@variscite.com>
Message-ID: <20251210152000.42265-3-stefano.r@variscite.com>

The VAR-SOM-MX8MP module does not include the PCA9534 GPIO expander nor
the LED connected to it. These components are present only on the
Symphony carrier board and may vary depending on the final carrier
design.

Since the PCA9534 is not part of the SOM hardware, its node and related
LED definition do not belong in the SOM dtsi and are removed.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../boot/dts/freescale/imx8mp-var-som.dtsi    | 50 -------------------
 1 file changed, 50 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
index 949d9878f395..158a78ec9656 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
@@ -19,16 +19,6 @@ chosen {
 		stdout-path = &uart2;
 	};
 
-	gpio-leds {
-	        compatible = "gpio-leds";
-
-	        led-0 {
-	                function = LED_FUNCTION_POWER;
-	                gpios = <&pca9534 0 GPIO_ACTIVE_HIGH>;
-	                linux,default-trigger = "heartbeat";
-	        };
-	};
-
 	memory at 40000000 {
 		device_type = "memory";
 		reg = <0x0 0x40000000 0 0xc0000000>,
@@ -216,33 +206,6 @@ ldo5: LDO5 {
 	};
 };
 
-&i2c3 {
-        clock-frequency = <400000>;
-        pinctrl-names = "default";
-        pinctrl-0 = <&pinctrl_i2c3>;
-        status = "okay";
-
-	/* GPIO expander */
-	pca9534: gpio at 20 {
-	        compatible = "nxp,pca9534";
-	        reg = <0x20>;
-	        pinctrl-names = "default";
-	        pinctrl-0 = <&pinctrl_pca9534>;
-	        gpio-controller;
-	        #gpio-cells = <2>;
-	        interrupt-parent = <&gpio1>;
-	        interrupts = <15 IRQ_TYPE_EDGE_FALLING>;
-	        wakeup-source;
-
-	        usb3-sata-sel-hog {
-	                gpio-hog;
-	                gpios = <4 0>;
-	                output-low;
-	                line-name = "usb3_sata_sel";
-	        };
-	};
-};
-
 /* Console */
 &uart2 {
         pinctrl-names = "default";
@@ -298,19 +261,6 @@ MX8MP_IOMUXC_SD1_DATA5__I2C1_SDA				0x400001c2
 		>;
 	};
 
-	pinctrl_i2c3: i2c3grp {
-	        fsl,pins = <
-	                MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL                                 0x400001c2
-	                MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA                                 0x400001c2
-	        >;
-	};
-
-	pinctrl_pca9534: pca9534grp {
-	        fsl,pins = <
-	                MX8MP_IOMUXC_GPIO1_IO15__GPIO1_IO15                             0xc0
-	        >;
-	};
-
 	pinctrl_pmic: pmicgrp {
 		fsl,pins = <
 			MX8MP_IOMUXC_SPDIF_RX__GPIO5_IO04				0x1c0
-- 
2.47.3



From stefano.r at variscite.com  Wed Dec 10 07:19:58 2025
From: stefano.r at variscite.com (Stefano Radaelli)
Date: Wed, 10 Dec 2025 16:19:58 +0100
Subject: [PATCH v1 6/6] arm64: dts: imx8mp-var-som: Add support for ADS7846 touchscreen
In-Reply-To: <20251210152000.42265-1-stefano.r@variscite.com>
References: <20251210152000.42265-1-stefano.r@variscite.com>
Message-ID: <20251210152000.42265-7-stefano.r@variscite.com>

The VAR-SOM-MX8MP integrates an ADS7846 resistive touchscreen controller.
The controller is physically located on the SOM, and its signals are
routed to the SOM pins, allowing carrier boards to make use of it.

This patch adds the ADS7846 node and the appropriate SPI controller.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../boot/dts/freescale/imx8mp-var-som.dtsi    | 46 +++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
index 169fc6a9c8cb..ebe615a84150 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
@@ -101,6 +101,37 @@ &A53_3 {
 	cpu-supply = <&buck2>;
 };
 
+&ecspi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi1>;
+	cs-gpios = <&gpio5 17 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	/* Resistive touch controller */
+	ads7846: touchscreen at 0 {
+		compatible = "ti,ads7846";
+		reg = <0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_restouch>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <12 IRQ_TYPE_EDGE_FALLING>;
+		spi-max-frequency = <1500000>;
+		pendown-gpio = <&gpio1 12 GPIO_ACTIVE_LOW>;
+		ti,x-min = /bits/ 16 <125>;
+		ti,x-max = /bits/ 16 <4008>;
+		ti,y-min = /bits/ 16 <282>;
+		ti,y-max = /bits/ 16 <3864>;
+		ti,x-plate-ohms = /bits/ 16 <180>;
+		ti,pressure-max = /bits/ 16 <255>;
+		ti,debounce-max = /bits/ 16 <10>;
+		ti,debounce-tol = /bits/ 16 <3>;
+		ti,debounce-rep = /bits/ 16 <1>;
+		ti,settle-delay-usec = /bits/ 16 <150>;
+		ti,keep-vref-on;
+		wakeup-source;
+	};
+};
+
 &eqos {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_eqos>;
@@ -348,6 +379,15 @@ MX8MP_IOMUXC_SD1_RESET_B__GPIO2_IO10                            0xc0
 		>;
 	};
 
+	pinctrl_ecspi1: ecspi1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C1_SCL__ECSPI1_SCLK                              0x12
+			MX8MP_IOMUXC_I2C1_SDA__ECSPI1_MOSI                              0x12
+			MX8MP_IOMUXC_I2C2_SCL__ECSPI1_MISO                              0x12
+			MX8MP_IOMUXC_I2C2_SDA__GPIO5_IO17                               0x12
+		>;
+	};
+
 	pinctrl_eqos: eqosgrp {
 		fsl,pins = <
 			MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC				0x2
@@ -382,6 +422,12 @@ MX8MP_IOMUXC_SPDIF_RX__GPIO5_IO04				0x1c0
 		>;
 	};
 
+	pinctrl_restouch: restouchgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO12__GPIO1_IO12                             0xc0
+		>;
+	};
+
 	pinctrl_sai3: sai3grp {
 		fsl,pins = <
 			MX8MP_IOMUXC_SAI3_TXFS__AUDIOMIX_SAI3_TX_SYNC                   0xd6
-- 
2.47.3



From Frank.li at nxp.com  Wed Dec 10 07:24:19 2025
From: Frank.li at nxp.com (Frank Li)
Date: Wed, 10 Dec 2025 10:24:19 -0500
Subject: [PATCH v3] pmdomain: imx: Fix reference count leak in
 imx_gpc_probe()
In-Reply-To: <20251210033524.34600-1-vulab@iscas.ac.cn>
References: <20251210033524.34600-1-vulab@iscas.ac.cn>
Message-ID: <aTmQo6L96/PcpVq0@lizhi-Precision-Tower-5810>

On Wed, Dec 10, 2025 at 03:35:24AM +0000, Wentao Liang wrote:
> of_get_child_by_name() returns a node pointer with refcount incremented.
> Use the __free() attribute to manage the pgc_node reference, ensuring
> automatic of_node_put() cleanup when pgc_node goes out of scope.
>
> This eliminates the need for explicit error handling paths and avoids
> reference count leaks.
>
> Fixes: 721cabf6c660 ("soc: imx: move PGC handling to a new GPC driver")
> Cc: stable at vger.kernel.org
> Signed-off-by: Wentao Liang <vulab at iscas.ac.cn>
>
> ---
> Change in V3:
> - Ensure variable is assigned when using cleanup attribute
>
> Change in V2:
> - Use __free() attribute instead of explicit of_node_put() calls
> ---
>  drivers/pmdomain/imx/gpc.c | 5 ++---
>  1 file changed, 2 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/pmdomain/imx/gpc.c b/drivers/pmdomain/imx/gpc.c
> index f18c7e6e75dd..0fb3250dbf5f 100644
> --- a/drivers/pmdomain/imx/gpc.c
> +++ b/drivers/pmdomain/imx/gpc.c
> @@ -403,13 +403,12 @@ static int imx_gpc_old_dt_init(struct device *dev, struct regmap *regmap,
>  static int imx_gpc_probe(struct platform_device *pdev)
>  {
>  	const struct imx_gpc_dt_data *of_id_data = device_get_match_data(&pdev->dev);
> -	struct device_node *pgc_node;
> +	struct device_node *pgc_node __free(pgc_node)
> +		= of_get_child_by_name(pdev->dev.of_node, "pgc");

Does it pass build? Sorry I have typo at previous comments.

struct device_node *pgc_node __free(device_node) = of_get_child_by_name(pdev->dev.of_node, "pgc");
                                    ^^^^^^^^^^^

Frank


>  	struct regmap *regmap;
>  	void __iomem *base;
>  	int ret;
>
> -	pgc_node = of_get_child_by_name(pdev->dev.of_node, "pgc");
> -
>  	/* bail out if DT too old and doesn't provide the necessary info */
>  	if (!of_property_present(pdev->dev.of_node, "#power-domain-cells") &&
>  	    !pgc_node)
> --
> 2.34.1
>


From marco.crivellari at suse.com  Wed Dec 10 07:30:15 2025
From: marco.crivellari at suse.com (Marco Crivellari)
Date: Wed, 10 Dec 2025 16:30:15 +0100
Subject: [PATCH] media: platform: mtk-mdp3: add WQ_PERCPU to
 alloc_workqueue users
In-Reply-To: <7e24110636db36e8c0a877d90d2ed9570c4aecf5.camel@ndufresne.ca>
References: <20251107141303.223254-1-marco.crivellari@suse.com> <7e24110636db36e8c0a877d90d2ed9570c4aecf5.camel@ndufresne.ca>
Message-ID: <CAAofZF44pUoyDPnnv9UUuMkYvqiSWP4gELg4rutgo=3tNpBZsw@mail.gmail.com>

On Tue, Dec 9, 2025 at 9:57?PM Nicolas Dufresne <nicolas at ndufresne.ca> wrote:
>
> Hi,
> I have to admit, there is likely no review here due to the lack of knowledge, so
> in order to help educate myself (hopefully its not just me), can you explain why
> the new default of WQ_UNBOUND would not be a fit for this driver ? After all,
> the author didn't care and didn't make a choice, so I feel like its worth
> asking.

Hi Nicolas,

The fact is that "alloc_workqueue()" without WQ_UNBOUND it means per-cpu.
So what we are doing here is just make explicit that the workqueue is per-cpu.

Currently there are no behavioral changes in alloc_workqueue(); in a
future release
WQ_UNBOUND will be removed and unbound will be the default. But as for now,
it is still per-cpu.

We can of course change the current behavior and I can send the v2 with
WQ_UNBOUND instead. Looking at the code there are not per-cpu variable and
the workqueue does not have the WQ_BH flag, so we can convert it if it
is better.

Thanks!

--

Marco Crivellari

L3 Support Engineer


From leo.yan at arm.com  Wed Dec 10 07:43:08 2025
From: leo.yan at arm.com (Leo Yan)
Date: Wed, 10 Dec 2025 15:43:08 +0000
Subject: [PATCH 07/19] coresight: trbe: Refactor AUX flag setting
In-Reply-To: <a638f74f-94bc-4052-b8e1-e940aca2d4ce@linaro.org>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-7-7da32b076b28@arm.com>
 <a638f74f-94bc-4052-b8e1-e940aca2d4ce@linaro.org>
Message-ID: <20251210154308.GZ724103@e132581.arm.com>

On Tue, Dec 09, 2025 at 01:37:39PM +0000, James Clark wrote:

[...]

> > +	if (!is_trbe_running(trbsr))
> > +		perf_aux_output_flag(handle, PERF_AUX_FLAG_COLLISION);
> > +
> 
> Do we need the complexity of COLLISION (changed to PARTIAL in a later
> commit) and TRUNCATED at the same time?

> From my understanding, TRUNCATED would be when Perf is too slow and we want
> to disable the event for it to catch up, and PARTIAL is when there was some
> buffer error so technically we don't need the event to be disabled, but Perf
> still needs to be notified if we want to start only resetting the decoder
> when a flag is set rather than on all aux records?

The main difference between the TRUNCATED flag and the COLLISION/PARTIAL
flags is that the TRUNCATED flag implicitly asks the event core layer to
disable the PMU event.  In contrast, the COLLISION and PARTIAL flags are
only stored in AUX record and no additional action in the event core
layer.

Setting the TRUNCATED flag would be a over-killer if the buffer has
free space, as it would run the expensive sequence of disabling both ETE
and TRBE and then requiring userspace to re-enable them.

> There is no happy path where there is a buffer error, so I'm not sure why we
> need the complexity of an extra case? There's no harm in disabling the event
> on a buffer error. Also it's hard to see what the exact scenario for PARTIAL
> is, because we set truncated anyway for fatal statuses. The comment in the
> later commit for the PARTIAL change just says "trace was stopped", but not
> why.

The trace can be stopped on Fill mode (stop on wrap) or Stop on trigger, so
it is not (only) about buffer error.  In these cases, even though the trace
unit is stopped, the buffer may still have space available, tracing can be
directly re-enabled in interrupt handler, thus the COLLISION/PARTIAL flags
are better choices.

Only when the buffer is actually used out (i.e., handle->size == 0), it is
appropriate to set TRUNCATED flag, since at that point we must wait for
userspace to read out the data.

Thanks,
Leo


From daniel.baluta at nxp.com  Wed Dec 10 07:49:06 2025
From: daniel.baluta at nxp.com (Daniel Baluta)
Date: Wed, 10 Dec 2025 17:49:06 +0200
Subject: [PATCH v2] remoteproc: imx_dsp_rproc: Fix multiple start/stop operations
Message-ID: <20251210154906.99210-1-daniel.baluta@nxp.com>

After commit 67a7bc7f0358 ("remoteproc: Use of reserved_mem_region_*
functions for "memory-region"") following commands with
imx-dsp-rproc started to fail:

$ echo zephyr.elf > /sys/class/remoteproc/remoteproc0/firmware
$ echo start > /sys/class/remoteproc/remoteproc0/state
$ echo stop > /sys/class/remoteproc/remoteproc0/state
$ echo start > /sys/class/remoteproc/remoteproc0/state #! This fails
-sh: echo: write error: Device or resource busy

This happens because aforementioned commit replaced devm_ioremap_wc with
devm_ioremap_resource_wc which will "reserve" the memory region with the
first start and then will fail at the second start if the memory
region is already reserved.

Even partially reverting the faulty commit won't fix the
underlying issue because we map the address in prepare() but we never
unmap it at unprepare(), so we will keep leaking memory regions.

So, lets use alloc() and release() callbacks for memory carveout
handling. This will nicely map() the memory region at prepare() time
and unmap() it at unprepare().

Fixes: 67a7bc7f0358 ("remoteproc: Use of_reserved_mem_region_* functions for "memory-region"")
Signed-off-by: Daniel Baluta <daniel.baluta at nxp.com>
---
Changes since v1:
 * https://lore.kernel.org/imx/091a4f29-5435-428a-9a1c-ef82465211cb at nxp.com/T/#t 
 * took a different approach and instead of partially reverting the
  faulty patch, used alloc() and release() callbacks to handle memory
  region mapping.
 drivers/remoteproc/imx_dsp_rproc.c | 50 ++++++++++++++++++++----------
 1 file changed, 33 insertions(+), 17 deletions(-)

diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c
index 5130a35214c9..83468558e634 100644
--- a/drivers/remoteproc/imx_dsp_rproc.c
+++ b/drivers/remoteproc/imx_dsp_rproc.c
@@ -644,6 +644,32 @@ static void imx_dsp_rproc_free_mbox(struct imx_dsp_rproc *priv)
 	mbox_free_channel(priv->rxdb_ch);
 }
 
+static int imx_dsp_rproc_mem_alloc(struct rproc *rproc,
+				   struct rproc_mem_entry *mem)
+{
+	struct device *dev = rproc->dev.parent;
+	void *va;
+
+	va = ioremap_wc(mem->dma, mem->len);
+	if (!va) {
+		dev_err(dev, "Unable to map memory region: %pa+%zx\n",
+			&mem->dma, mem->len);
+		return -ENOMEM;
+	}
+
+	mem->va = va;
+
+	return 0;
+}
+
+static int imx_dsp_rproc_mem_release(struct rproc *rproc,
+				     struct rproc_mem_entry *mem)
+{
+	iounmap(mem->va);
+
+	return 0;
+}
+
 /**
  * imx_dsp_rproc_add_carveout() - request mailbox channels
  * @priv: private data pointer
@@ -659,7 +685,6 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv)
 	struct device *dev = rproc->dev.parent;
 	struct device_node *np = dev->of_node;
 	struct rproc_mem_entry *mem;
-	void __iomem *cpu_addr;
 	int a, i = 0;
 	u64 da;
 
@@ -673,15 +698,10 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv)
 		if (imx_dsp_rproc_sys_to_da(priv, att->sa, att->size, &da))
 			return -EINVAL;
 
-		cpu_addr = devm_ioremap_wc(dev, att->sa, att->size);
-		if (!cpu_addr) {
-			dev_err(dev, "failed to map memory %p\n", &att->sa);
-			return -ENOMEM;
-		}
-
 		/* Register memory region */
-		mem = rproc_mem_entry_init(dev, (void __force *)cpu_addr, (dma_addr_t)att->sa,
-					   att->size, da, NULL, NULL, "dsp_mem");
+		mem = rproc_mem_entry_init(dev, NULL, (dma_addr_t)att->sa,
+					   att->size, da, imx_dsp_rproc_mem_alloc,
+					   imx_dsp_rproc_mem_release, "dsp_mem");
 
 		if (mem)
 			rproc_coredump_add_segment(rproc, da, att->size);
@@ -709,15 +729,11 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv)
 		if (imx_dsp_rproc_sys_to_da(priv, res.start, resource_size(&res), &da))
 			return -EINVAL;
 
-		cpu_addr = devm_ioremap_resource_wc(dev, &res);
-		if (IS_ERR(cpu_addr)) {
-			dev_err(dev, "failed to map memory %pR\n", &res);
-			return PTR_ERR(cpu_addr);
-		}
-
 		/* Register memory region */
-		mem = rproc_mem_entry_init(dev, (void __force *)cpu_addr, (dma_addr_t)res.start,
-					   resource_size(&res), da, NULL, NULL,
+		mem = rproc_mem_entry_init(dev, NULL, (dma_addr_t)res.start,
+					   resource_size(&res), da,
+					    imx_dsp_rproc_mem_alloc,
+					    imx_dsp_rproc_mem_release,
 					   "%.*s", strchrnul(res.name, '@') - res.name, res.name);
 		if (!mem)
 			return -ENOMEM;
-- 
2.45.2



From nicolas at ndufresne.ca  Wed Dec 10 08:04:32 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 10 Dec 2025 11:04:32 -0500
Subject: [PATCH] media: platform: mtk-mdp3: add WQ_PERCPU to
 alloc_workqueue users
In-Reply-To: <CAAofZF44pUoyDPnnv9UUuMkYvqiSWP4gELg4rutgo=3tNpBZsw@mail.gmail.com>
References: <20251107141303.223254-1-marco.crivellari@suse.com>
	 <7e24110636db36e8c0a877d90d2ed9570c4aecf5.camel@ndufresne.ca>
	 <CAAofZF44pUoyDPnnv9UUuMkYvqiSWP4gELg4rutgo=3tNpBZsw@mail.gmail.com>
Message-ID: <fd401d1b4f1e7b7178699227d31976453de5891e.camel@ndufresne.ca>

Hi,

Le mercredi 10 d?cembre 2025 ? 16:30 +0100, Marco Crivellari a ?crit?:
> On Tue, Dec 9, 2025 at 9:57?PM Nicolas Dufresne <nicolas at ndufresne.ca> wrote:
> > 
> > Hi,
> > I have to admit, there is likely no review here due to the lack of knowledge, so
> > in order to help educate myself (hopefully its not just me), can you explain why
> > the new default of WQ_UNBOUND would not be a fit for this driver ? After all,
> > the author didn't care and didn't make a choice, so I feel like its worth
> > asking.
> 
> Hi Nicolas,
> 
> The fact is that "alloc_workqueue()" without WQ_UNBOUND it means per-cpu.
> So what we are doing here is just make explicit that the workqueue is per-cpu.
> 
> Currently there are no behavioral changes in alloc_workqueue(); in a
> future release
> WQ_UNBOUND will be removed and unbound will be the default. But as for now,
> it is still per-cpu.
> 
> We can of course change the current behavior and I can send the v2 with
> WQ_UNBOUND instead. Looking at the code there are not per-cpu variable and
> the workqueue does not have the WQ_BH flag, so we can convert it if it
> is better.

thanks for clarifying. This driver having no clear maintainer, it is hard to
delegate the checks needed, but from the description, it pretty much sounded as
if most driver are picking up the wrong thing, because that is what the default
do.

I don't have strong opinion, if you think this driver can be ported in one step,
that is always my preference, and making things explicit is also nice. But I'm
also fine picking this as-is for now. Let me know, your preference, available
time and safety of not breaking anything is valid argument to me.

Nicolas
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251210/559f4698/attachment.sig>

From Macpaul.Lin at mediatek.com  Wed Dec 10 08:17:29 2025
From: Macpaul.Lin at mediatek.com (=?utf-8?B?TWFjcGF1bCBMaW4gKOael+aZuuaWjCk=?=)
Date: Wed, 10 Dec 2025 16:17:29 +0000
Subject: [PATCH] soc: mediatek: mtk-socinfo: Add entry for MT8391AV/AZA
 Genio 720
In-Reply-To: <20251029-mtk-socinfo-mt8391-v1-1-61412dcd9938@collabora.com>
References: <20251029-mtk-socinfo-mt8391-v1-1-61412dcd9938@collabora.com>
Message-ID: <d631c04f62edac5d5ee131160c3b287534d6b2c6.camel@mediatek.com>

On Wed, 2025-10-29 at 14:46 +0100, Louis-Alexis Eyraud wrote:
> 
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
> 
> 
> Add an entry for the MT8391 SoC with commercial name Genio 720.
> 
> Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
> ---
> ?drivers/soc/mediatek/mtk-socinfo.c | 1 +
> ?1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/soc/mediatek/mtk-socinfo.c
> b/drivers/soc/mediatek/mtk-socinfo.c
> index
> c697a0398d917c0944661a75667824369373ba2c..44a21e91d159b93ed1540b5754f
> 5512d2d9c3fc0 100644
> --- a/drivers/soc/mediatek/mtk-socinfo.c
> +++ b/drivers/soc/mediatek/mtk-socinfo.c
> @@ -58,6 +58,7 @@ static struct socinfo_data socinfo_data_table[] = {
> ??????? MTK_SOCINFO_ENTRY("MT8195", "MT8195TV/EHZA", "Kompanio 1380",
> 0x81950404, CELL_NOT_USED),
> ??????? MTK_SOCINFO_ENTRY("MT8370", "MT8370AV/AZA", "Genio 510",
> 0x83700000, 0x00000081),
> ??????? MTK_SOCINFO_ENTRY("MT8390", "MT8390AV/AZA", "Genio 700",
> 0x83900000, 0x00000080),
> +?????? MTK_SOCINFO_ENTRY("MT8391", "MT8391AV/AZA", "Genio 720",
> 0x83910000, 0x00000080),
> ??????? MTK_SOCINFO_ENTRY("MT8395", "MT8395AV/ZA", "Genio 1200",
> 0x83950100, CELL_NOT_USED),
> ??????? MTK_SOCINFO_ENTRY("MT8395", "MT8395AV/ZA", "Genio 1200",
> 0x83950800, CELL_NOT_USED),
> ?};
> 
> ---
> base-commit: c9a389ffad27e7847c69f4d2b67ba56b77190209
> change-id: 20251029-mtk-socinfo-mt8391-260ae9cc6f61
> 
> Best regards,
> --
> Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
> 
> 

Reviewed-by Macpaul Lin <macpaul.lin at mediatek.com>

Best regards,
Macpaul Lin

From Macpaul.Lin at mediatek.com  Wed Dec 10 08:19:37 2025
From: Macpaul.Lin at mediatek.com (=?utf-8?B?TWFjcGF1bCBMaW4gKOael+aZuuaWjCk=?=)
Date: Wed, 10 Dec 2025 16:19:37 +0000
Subject: [PATCH 1/4] dt-bindings: serial: mediatek,uart: Add compatible
 for MT8189 SoC
In-Reply-To: <20251203-add-mediatek-genio-520-720-evk-v1-1-df794b2a30ae@collabora.com>
References: <20251203-add-mediatek-genio-520-720-evk-v1-0-df794b2a30ae@collabora.com>
	 <20251203-add-mediatek-genio-520-720-evk-v1-1-df794b2a30ae@collabora.com>
Message-ID: <b5cbb1fa0e56d926b4e9c0938d1364533d265c90.camel@mediatek.com>

On Wed, 2025-12-03 at 14:59 +0100, Louis-Alexis Eyraud wrote:
> 
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
> 
> 
> Add a compatible string for the MT8189 SoC.
> The UART IPs in this chip are fully compatible with the one found in
> MT6577 SoC.
> 
> Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
> ---
> ?Documentation/devicetree/bindings/serial/mediatek,uart.yaml | 1 +
> ?1 file changed, 1 insertion(+)
> 
> diff --git
> a/Documentation/devicetree/bindings/serial/mediatek,uart.yaml
> b/Documentation/devicetree/bindings/serial/mediatek,uart.yaml
> index
> 5bd8a8853ae0d4ae309d28350fd54b6f9b4e731e..3f0f4aea0a4c0ef11055ddd08ba
> 71d045e7fa519 100644
> --- a/Documentation/devicetree/bindings/serial/mediatek,uart.yaml
> +++ b/Documentation/devicetree/bindings/serial/mediatek,uart.yaml
> @@ -47,6 +47,7 @@ properties:
> ?????????????? - mediatek,mt8183-uart
> ?????????????? - mediatek,mt8186-uart
> ?????????????? - mediatek,mt8188-uart
> +????????????? - mediatek,mt8189-uart
> ?????????????? - mediatek,mt8192-uart
> ?????????????? - mediatek,mt8195-uart
> ?????????????? - mediatek,mt8365-uart
> 
> --
> 2.52.0
> 
> 

Reviewed-by Macpaul Lin <macpaul.lin at mediatek.com>

Best regards,
Macpaul Lin

From leo.yan at arm.com  Wed Dec 10 08:19:58 2025
From: leo.yan at arm.com (Leo Yan)
Date: Wed, 10 Dec 2025 16:19:58 +0000
Subject: [PATCH 08/19] coresight: trbe: Use PERF_AUX_FLAG_PARTIAL instead
 of PERF_AUX_FLAG_COLLISION
In-Reply-To: <f1ac7190-bdd9-4725-8955-d82d6f1912fb@linaro.org>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-8-7da32b076b28@arm.com>
 <5f6bcd93-b565-4b10-9a2d-6851141e5dbe@arm.com>
 <f1ac7190-bdd9-4725-8955-d82d6f1912fb@linaro.org>
Message-ID: <20251210161958.GA724103@e132581.arm.com>

On Tue, Dec 09, 2025 at 01:40:35PM +0000, James Clark wrote:

[...]

> > >   	if (!is_trbe_running(trbsr))
> > > -		perf_aux_output_flag(handle, PERF_AUX_FLAG_COLLISION);
> > > +		perf_aux_output_flag(handle, PERF_AUX_FLAG_PARTIAL);
> > 
> > This is interesting. So there is a no possibility for the records to be
> > overridden in the perf ring buffer and incomplete record is all that can
> > happen when TRBE is stopped, without stopping the ETE first ? Could both
> > of these scenarios might be possible as well ?
> > 
> 
> There's no chance of overwriting because that would be the TRUNCATED case
> and the event would get disabled. PARTIAL seems to be when there was an
> error that's recoverable in the driver only, but as in my other comment I
> don't think the extra complexity is necessary and always using TRUNCATED
> would be enough.

If I extend a bit, I would say that the TRUNCATED flag is used to prevent
buffer overwrites, while the other flags indicate why a record is
incomplete.

Thanks,
Leo


From Macpaul.Lin at mediatek.com  Wed Dec 10 08:27:07 2025
From: Macpaul.Lin at mediatek.com (=?utf-8?B?TWFjcGF1bCBMaW4gKOael+aZuuaWjCk=?=)
Date: Wed, 10 Dec 2025 16:27:07 +0000
Subject: [PATCH] soc: mediatek: mtk-socinfo: Add entry for MT8371AV/AZA
 Genio 520
In-Reply-To: <20251209-mtk-socinfo-mt8371-v1-1-155a9df851d0@collabora.com>
References: <20251209-mtk-socinfo-mt8371-v1-1-155a9df851d0@collabora.com>
Message-ID: <7cff00aab8c4c9b3cc5f5cebf54eca793fb26bd1.camel@mediatek.com>

On Tue, 2025-12-09 at 10:33 +0100, Louis-Alexis Eyraud wrote:
> 
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
> 
> 
> Add an entry for the MT8371 SoC with commercial name Genio 520.
> 
> Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
> ---
> ?drivers/soc/mediatek/mtk-socinfo.c | 1 +
> ?1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/soc/mediatek/mtk-socinfo.c
> b/drivers/soc/mediatek/mtk-socinfo.c
> index
> 978c43e9115ab29b20703621c60f1b8ef4d6f851..424a1eb82c20fa5226bd70ec014
> 5f437560b40cf 100644
> --- a/drivers/soc/mediatek/mtk-socinfo.c
> +++ b/drivers/soc/mediatek/mtk-socinfo.c
> @@ -59,6 +59,7 @@ static struct socinfo_data socinfo_data_table[] = {
> ??????? MTK_SOCINFO_ENTRY("MT8195", "MT8195TV/EZA", "Kompanio 1380",
> 0x81950400, CELL_NOT_USED),
> ??????? MTK_SOCINFO_ENTRY("MT8195", "MT8195TV/EHZA", "Kompanio 1380",
> 0x81950404, CELL_NOT_USED),
> ??????? MTK_SOCINFO_ENTRY("MT8370", "MT8370AV/AZA", "Genio 510",
> 0x83700000, 0x00000081),
> +?????? MTK_SOCINFO_ENTRY("MT8371", "MT8371AV/AZA", "Genio 520",
> 0x83710000, 0x00000081),
> ??????? MTK_SOCINFO_ENTRY("MT8390", "MT8390AV/AZA", "Genio 700",
> 0x83900000, 0x00000080),
> ??????? MTK_SOCINFO_ENTRY("MT8391", "MT8391AV/AZA", "Genio 720",
> 0x83910000, 0x00000080),
> ??????? MTK_SOCINFO_ENTRY("MT8395", "MT8395AV/ZA", "Genio 1200",
> 0x83950100, CELL_NOT_USED),
> 
> ---
> base-commit: 8ebfd5290c6162d65f83f9a8acdbbf243b49a586
> change-id: 20251209-mtk-socinfo-mt8371-ef9ef20e66e5
> 
> Best regards,
> --
> Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
> 
> 

Reviewed-by: Macpaul Lin <macpaul.lin at mediatek.com>

Best regards,
Macpaul Lin

From Macpaul.Lin at mediatek.com  Wed Dec 10 08:29:29 2025
From: Macpaul.Lin at mediatek.com (=?utf-8?B?TWFjcGF1bCBMaW4gKOael+aZuuaWjCk=?=)
Date: Wed, 10 Dec 2025 16:29:29 +0000
Subject: [PATCH] soc: mediatek: mtk-socinfo: Add entry for MT8391AV/AZA
 Genio 720
In-Reply-To: <d631c04f62edac5d5ee131160c3b287534d6b2c6.camel@mediatek.com>
References: <20251029-mtk-socinfo-mt8391-v1-1-61412dcd9938@collabora.com>
	 <d631c04f62edac5d5ee131160c3b287534d6b2c6.camel@mediatek.com>
Message-ID: <136d43b6382d09a1e60a24ae72a5c05be6218dc1.camel@mediatek.com>

On Thu, 2025-12-11 at 00:17 +0800, Macpaul Lin wrote:
> On Wed, 2025-10-29 at 14:46 +0100, Louis-Alexis Eyraud wrote:
> > 
> > External email : Please do not click links or open attachments
> > until
> > you have verified the sender or the content.
> > 
> > 
> > Add an entry for the MT8391 SoC with commercial name Genio 720.
> > 
> > Signed-off-by: Louis-Alexis Eyraud
> > <louisalexis.eyraud at collabora.com>
> > ---
> > ?drivers/soc/mediatek/mtk-socinfo.c | 1 +
> > ?1 file changed, 1 insertion(+)
> > 
> > diff --git a/drivers/soc/mediatek/mtk-socinfo.c
> > b/drivers/soc/mediatek/mtk-socinfo.c
> > index
> > c697a0398d917c0944661a75667824369373ba2c..44a21e91d159b93ed1540b575
> > 4f
> > 5512d2d9c3fc0 100644
> > --- a/drivers/soc/mediatek/mtk-socinfo.c
> > +++ b/drivers/soc/mediatek/mtk-socinfo.c
> > @@ -58,6 +58,7 @@ static struct socinfo_data socinfo_data_table[] =
> > {
> > ??????? MTK_SOCINFO_ENTRY("MT8195", "MT8195TV/EHZA", "Kompanio
> > 1380",
> > 0x81950404, CELL_NOT_USED),
> > ??????? MTK_SOCINFO_ENTRY("MT8370", "MT8370AV/AZA", "Genio 510",
> > 0x83700000, 0x00000081),
> > ??????? MTK_SOCINFO_ENTRY("MT8390", "MT8390AV/AZA", "Genio 700",
> > 0x83900000, 0x00000080),
> > +?????? MTK_SOCINFO_ENTRY("MT8391", "MT8391AV/AZA", "Genio 720",
> > 0x83910000, 0x00000080),
> > ??????? MTK_SOCINFO_ENTRY("MT8395", "MT8395AV/ZA", "Genio 1200",
> > 0x83950100, CELL_NOT_USED),
> > ??????? MTK_SOCINFO_ENTRY("MT8395", "MT8395AV/ZA", "Genio 1200",
> > 0x83950800, CELL_NOT_USED),
> > ?};
> > 
> > ---
> > base-commit: c9a389ffad27e7847c69f4d2b67ba56b77190209
> > change-id: 20251029-mtk-socinfo-mt8391-260ae9cc6f61
> > 
> > Best regards,
> > --
> > Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
> > 
> > 
> 
> Reviewed-by Macpaul Lin <macpaul.lin at mediatek.com>
> 
> Best regards,
> Macpaul Lin

Sorry for missing a colon in the tag. Resend the reply again.

Reviewed-by: Macpaul Lin <macpaul.lin at mediatek.com>

Best regards,
Macpaul Lin

From conor at kernel.org  Wed Dec 10 08:33:43 2025
From: conor at kernel.org (Conor Dooley)
Date: Wed, 10 Dec 2025 16:33:43 +0000
Subject: [PATCH v3 01/21] dt-bindings: clock: mediatek: Add MT8189 clock
 definitions
In-Reply-To: <626b5c4b810678a7f0de1f109371a6d6694bd2a8.camel@mediatek.com>
References: <20251106124330.1145600-1-irving-ch.lin@mediatek.com>
 <20251106124330.1145600-2-irving-ch.lin@mediatek.com>
 <20251106-hug-stingray-2d3ff42fd365@spud>
 <626b5c4b810678a7f0de1f109371a6d6694bd2a8.camel@mediatek.com>
Message-ID: <20251210-progress-overdue-bded69c47048@spud>

On Wed, Dec 10, 2025 at 10:01:24AM +0000, Irving-CH Lin (???) wrote:
> Hi Conor,
> 
> On Thu, 2025-11-06 at 17:19 +0000, Conor Dooley wrote:
> > On Thu, Nov 06, 2025 at 08:41:46PM +0800, irving.ch.lin wrote:
> > > From: Irving-CH Lin <irving-ch.lin at mediatek.com>
> > > 
> > > Add device tree bindings for the clock of MediaTek MT8189 SoC.
> > > 
> > > Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
> > 
> > Before I approve this, can you share the dts that actually uses it?
> > This many different syscons really does look suspect, and that not
> > all
> > of these should be nodes of their own. They may very well be, I would
> > just like to see what the dts looks like. Doesn't need to be a patch,
> > a
> > link to your tree will suffice.
> > 
> > Cheers,
> > Conor.
> > 
> https://patchwork.kernel.org/project/linux-mediatek/patch/20251111070031.305281-10-jh.hsu at mediatek.com/
> Please refer to link for mt8189 dts.

Acked-by: Conor Dooley <conor.dooley at microchip.com>
pw-bot: not-applicable
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251210/0b4a67d5/attachment.sig>

From tomeu at tomeuvizoso.net  Wed Dec 10 08:39:29 2025
From: tomeu at tomeuvizoso.net (Tomeu Vizoso)
Date: Wed, 10 Dec 2025 17:39:29 +0100
Subject: Issues with DRM_ACCEL_ROCKET (Oops, power-domain, probe-ordering)
In-Reply-To: <e7b2ceaf-1fbd-4f02-9d75-be4feab724e3@rock-chips.com>
References: <0b20d760-ad4f-41c0-b733-39db10d6cc41@cherry.de>
 <77685900-2c34-49b8-8c7e-14718841ef17@rock-chips.com> <fa82d11f-ce11-4feb-bdb4-c31d360a2a62@rock-chips.com>
 <CAAObsKDYLXVf1GdYUNeaOya+pWD4jTOEf55ouXAL9iM_kWCcMw@mail.gmail.com>
 <75166475-d6a8-45b8-8092-f31d292d4206@rock-chips.com> <CAAObsKABYQnw9rUfxwTS-yiQSoH9rdxZ_ffUBtp2H3tMJqMb7w@mail.gmail.com>
 <e7b2ceaf-1fbd-4f02-9d75-be4feab724e3@rock-chips.com>
Message-ID: <CAAObsKBneQrciukH-eZ8qY92n1YxRFChpXV9s6G8oQP5jSMwRA@mail.gmail.com>

On Wed, Dec 10, 2025 at 11:47?AM Chaoyi Chen <chaoyi.chen at rock-chips.com> wrote:
>
> Hello Tomeu,
>
> On 12/10/2025 2:50 PM, Tomeu Vizoso wrote:
> > On Tue, Dec 9, 2025 at 10:31?AM Chaoyi Chen <chaoyi.chen at rock-chips.com> wrote:
> >>
> >> Hello Tomeu,
> >>
> >> On 12/9/2025 2:55 PM, Tomeu Vizoso wrote:
> >>> On Tue, Dec 2, 2025 at 8:00?AM Chaoyi Chen <chaoyi.chen at rock-chips.com> wrote:
> >>
> >> [...]
> >>
> >>>
> >>> This need was questioned during the review process, and during my
> >>> stress testing I didn't find a need for core 0 to be treated
> >>> specially. So it was considered unneeded complexity and the code was
> >>> dropped.
> >>>
> >>
> >> Oh, I just noticed that the commit comment in the devicetree still
> >> contains a relevant description.
> >>
> >>> My testing involves running the supported models as a whole, and also
> >>> their individual operations as individual tests. I run them in 8
> >>> parallel processes, in batches so we have continuous bring up and down
> >>> of clients.
> >>>
> >>> I'm a bit surprised that that testing worked stably but we have still
> >>> failures in some setups.
> >>
> >> Could you please describe the failures that still exist? Thank you.
> >
> > I was referring to the ones that Quentin reported when starting this thread.
> >
>
> I believe this pmdomain patch can alleviate some of the problems [0].
>
> However, the problem Quentin mentioned still exists. For example, if
> there is an invalid device on core0, while core1 and core2 are valid,
> accessing the relevant data on core0 will cause problems. Quentin's
> patch can fix this, but he doesn't seem to have time for it lately...

Has anybody reproduced this problem with the pmdomain fix applied?

Thanks,

Tomeu

> [0] https://lore.kernel.org/all/20251205064739.20270-1-rmxpzlb at gmail.com/
>
> > Regards,
> >
> > Tomeu
> >
> >
>
> --
> Best,
> Chaoyi


From m.wieczorretman at pm.me  Wed Dec 10 09:28:29 2025
From: m.wieczorretman at pm.me (Maciej Wieczor-Retman)
Date: Wed, 10 Dec 2025 17:28:29 +0000
Subject: [PATCH v7 01/15] kasan: sw_tags: Use arithmetic shift for shadow computation
In-Reply-To: <cover.1765386422.git.m.wieczorretman@pm.me>
References: <cover.1765386422.git.m.wieczorretman@pm.me>
Message-ID: <138681b036a91587e62fd62548502bc3205c93af.1765386422.git.m.wieczorretman@pm.me>

From: Samuel Holland <samuel.holland at sifive.com>

Currently, kasan_mem_to_shadow() uses a logical right shift, which turns
canonical kernel addresses into non-canonical addresses by clearing the
high KASAN_SHADOW_SCALE_SHIFT bits. The value of KASAN_SHADOW_OFFSET is
then chosen so that the addition results in a canonical address for the
shadow memory.

For KASAN_GENERIC, this shift/add combination is ABI with the compiler,
because KASAN_SHADOW_OFFSET is used in compiler-generated inline tag
checks[1], which must only attempt to dereference canonical addresses.

However, for KASAN_SW_TAGS there is some freedom to change the algorithm
without breaking the ABI. Because TBI is enabled for kernel addresses,
the top bits of shadow memory addresses computed during tag checks are
irrelevant, and so likewise are the top bits of KASAN_SHADOW_OFFSET.
This is demonstrated by the fact that LLVM uses a logical right shift in
the tag check fast path[2] but a sbfx (signed bitfield extract)
instruction in the slow path[3] without causing any issues.

Using an arithmetic shift in kasan_mem_to_shadow() provides a number of
benefits:

1) The memory layout doesn't change but is easier to understand.
KASAN_SHADOW_OFFSET becomes a canonical memory address, and the shifted
pointer becomes a negative offset, so KASAN_SHADOW_OFFSET ==
KASAN_SHADOW_END regardless of the shift amount or the size of the
virtual address space.

2) KASAN_SHADOW_OFFSET becomes a simpler constant, requiring only one
instruction to load instead of two. Since it must be loaded in each
function with a tag check, this decreases kernel text size by 0.5%.

3) This shift and the sign extension from kasan_reset_tag() can be
combined into a single sbfx instruction. When this same algorithm change
is applied to the compiler, it removes an instruction from each inline
tag check, further reducing kernel text size by an additional 4.6%.

These benefits extend to other architectures as well. On RISC-V, where
the baseline ISA does not shifted addition or have an equivalent to the
sbfx instruction, loading KASAN_SHADOW_OFFSET is reduced from 3 to 2
instructions, and kasan_mem_to_shadow(kasan_reset_tag(addr)) similarly
combines two consecutive right shifts.

Link: https://github.com/llvm/llvm-project/blob/llvmorg-20-init/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp#L1316 [1]
Link: https://github.com/llvm/llvm-project/blob/llvmorg-20-init/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp#L895 [2]
Link: https://github.com/llvm/llvm-project/blob/llvmorg-20-init/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp#L669 [3]
Signed-off-by: Samuel Holland <samuel.holland at sifive.com>
Co-developed-by: Maciej Wieczor-Retman <maciej.wieczor-retman at intel.com>
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman at intel.com>
Acked-by: Catalin Marinas <catalin.marinas at arm.com>
---
Changelog v7: (Maciej)
- Change UL to ULL in report.c to fix some compilation warnings.

Changelog v6: (Maciej)
- Add Catalin's acked-by.
- Move x86 gdb snippet here from the last patch.

Changelog v5: (Maciej)
- (u64) -> (unsigned long) in report.c

Changelog v4: (Maciej)
- Revert x86 to signed mem_to_shadow mapping.
- Remove last two paragraphs since they were just poorer duplication of
  the comments in kasan_non_canonical_hook().

Changelog v3: (Maciej)
- Fix scripts/gdb/linux/kasan.py so the new signed mem_to_shadow() is
  reflected there.
- Fix Documentation/arch/arm64/kasan-offsets.sh to take new offsets into
  account.
- Made changes to the kasan_non_canonical_hook() according to upstream
  discussion. Settled on overflow on both ranges and separate checks for
  x86 and arm.

Changelog v2: (Maciej)
- Correct address range that's checked in kasan_non_canonical_hook().
  Adjust the comment inside.
- Remove part of comment from arch/arm64/include/asm/memory.h.
- Append patch message paragraph about the overflow in
  kasan_non_canonical_hook().

 Documentation/arch/arm64/kasan-offsets.sh |  8 +++--
 arch/arm64/Kconfig                        | 10 +++----
 arch/arm64/include/asm/memory.h           | 14 ++++++++-
 arch/arm64/mm/kasan_init.c                |  7 +++--
 include/linux/kasan.h                     | 10 +++++--
 mm/kasan/report.c                         | 36 ++++++++++++++++++++---
 scripts/gdb/linux/kasan.py                |  5 +++-
 scripts/gdb/linux/mm.py                   |  5 ++--
 8 files changed, 76 insertions(+), 19 deletions(-)

diff --git a/Documentation/arch/arm64/kasan-offsets.sh b/Documentation/arch/arm64/kasan-offsets.sh
index 2dc5f9e18039..ce777c7c7804 100644
--- a/Documentation/arch/arm64/kasan-offsets.sh
+++ b/Documentation/arch/arm64/kasan-offsets.sh
@@ -5,8 +5,12 @@
 
 print_kasan_offset () {
 	printf "%02d\t" $1
-	printf "0x%08x00000000\n" $(( (0xffffffff & (-1 << ($1 - 1 - 32))) \
-			- (1 << (64 - 32 - $2)) ))
+	if [[ $2 -ne 4 ]] then
+		printf "0x%08x00000000\n" $(( (0xffffffff & (-1 << ($1 - 1 - 32))) \
+				- (1 << (64 - 32 - $2)) ))
+	else
+		printf "0x%08x00000000\n" $(( (0xffffffff & (-1 << ($1 - 1 - 32))) ))
+	fi
 }
 
 echo KASAN_SHADOW_SCALE_SHIFT = 3
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 6663ffd23f25..ac50ba2d760b 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -433,11 +433,11 @@ config KASAN_SHADOW_OFFSET
 	default 0xdffffe0000000000 if ARM64_VA_BITS_42 && !KASAN_SW_TAGS
 	default 0xdfffffc000000000 if ARM64_VA_BITS_39 && !KASAN_SW_TAGS
 	default 0xdffffff800000000 if ARM64_VA_BITS_36 && !KASAN_SW_TAGS
-	default 0xefff800000000000 if (ARM64_VA_BITS_48 || (ARM64_VA_BITS_52 && !ARM64_16K_PAGES)) && KASAN_SW_TAGS
-	default 0xefffc00000000000 if (ARM64_VA_BITS_47 || ARM64_VA_BITS_52) && ARM64_16K_PAGES && KASAN_SW_TAGS
-	default 0xeffffe0000000000 if ARM64_VA_BITS_42 && KASAN_SW_TAGS
-	default 0xefffffc000000000 if ARM64_VA_BITS_39 && KASAN_SW_TAGS
-	default 0xeffffff800000000 if ARM64_VA_BITS_36 && KASAN_SW_TAGS
+	default 0xffff800000000000 if (ARM64_VA_BITS_48 || (ARM64_VA_BITS_52 && !ARM64_16K_PAGES)) && KASAN_SW_TAGS
+	default 0xffffc00000000000 if (ARM64_VA_BITS_47 || ARM64_VA_BITS_52) && ARM64_16K_PAGES && KASAN_SW_TAGS
+	default 0xfffffe0000000000 if ARM64_VA_BITS_42 && KASAN_SW_TAGS
+	default 0xffffffc000000000 if ARM64_VA_BITS_39 && KASAN_SW_TAGS
+	default 0xfffffff800000000 if ARM64_VA_BITS_36 && KASAN_SW_TAGS
 	default 0xffffffffffffffff
 
 config UNWIND_TABLES
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index f1505c4acb38..7bbebde59a75 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -89,7 +89,15 @@
  *
  * KASAN_SHADOW_END is defined first as the shadow address that corresponds to
  * the upper bound of possible virtual kernel memory addresses UL(1) << 64
- * according to the mapping formula.
+ * according to the mapping formula. For Generic KASAN, the address in the
+ * mapping formula is treated as unsigned (part of the compiler's ABI), so the
+ * end of the shadow memory region is at a large positive offset from
+ * KASAN_SHADOW_OFFSET. For Software Tag-Based KASAN, the address in the
+ * formula is treated as signed. Since all kernel addresses are negative, they
+ * map to shadow memory below KASAN_SHADOW_OFFSET, making KASAN_SHADOW_OFFSET
+ * itself the end of the shadow memory region. (User pointers are positive and
+ * would map to shadow memory above KASAN_SHADOW_OFFSET, but shadow memory is
+ * not allocated for them.)
  *
  * KASAN_SHADOW_START is defined second based on KASAN_SHADOW_END. The shadow
  * memory start must map to the lowest possible kernel virtual memory address
@@ -100,7 +108,11 @@
  */
 #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
 #define KASAN_SHADOW_OFFSET	_AC(CONFIG_KASAN_SHADOW_OFFSET, UL)
+#ifdef CONFIG_KASAN_GENERIC
 #define KASAN_SHADOW_END	((UL(1) << (64 - KASAN_SHADOW_SCALE_SHIFT)) + KASAN_SHADOW_OFFSET)
+#else
+#define KASAN_SHADOW_END	KASAN_SHADOW_OFFSET
+#endif
 #define _KASAN_SHADOW_START(va)	(KASAN_SHADOW_END - (UL(1) << ((va) - KASAN_SHADOW_SCALE_SHIFT)))
 #define KASAN_SHADOW_START	_KASAN_SHADOW_START(vabits_actual)
 #define PAGE_END		KASAN_SHADOW_START
diff --git a/arch/arm64/mm/kasan_init.c b/arch/arm64/mm/kasan_init.c
index abeb81bf6ebd..937f6eb8115b 100644
--- a/arch/arm64/mm/kasan_init.c
+++ b/arch/arm64/mm/kasan_init.c
@@ -198,8 +198,11 @@ static bool __init root_level_aligned(u64 addr)
 /* The early shadow maps everything to a single page of zeroes */
 asmlinkage void __init kasan_early_init(void)
 {
-	BUILD_BUG_ON(KASAN_SHADOW_OFFSET !=
-		KASAN_SHADOW_END - (1UL << (64 - KASAN_SHADOW_SCALE_SHIFT)));
+	if (IS_ENABLED(CONFIG_KASAN_GENERIC))
+		BUILD_BUG_ON(KASAN_SHADOW_OFFSET !=
+			KASAN_SHADOW_END - (1UL << (64 - KASAN_SHADOW_SCALE_SHIFT)));
+	else
+		BUILD_BUG_ON(KASAN_SHADOW_OFFSET != KASAN_SHADOW_END);
 	BUILD_BUG_ON(!IS_ALIGNED(_KASAN_SHADOW_START(VA_BITS), SHADOW_ALIGN));
 	BUILD_BUG_ON(!IS_ALIGNED(_KASAN_SHADOW_START(VA_BITS_MIN), SHADOW_ALIGN));
 	BUILD_BUG_ON(!IS_ALIGNED(KASAN_SHADOW_END, SHADOW_ALIGN));
diff --git a/include/linux/kasan.h b/include/linux/kasan.h
index d12e1a5f5a9a..670de5427c32 100644
--- a/include/linux/kasan.h
+++ b/include/linux/kasan.h
@@ -61,8 +61,14 @@ int kasan_populate_early_shadow(const void *shadow_start,
 #ifndef kasan_mem_to_shadow
 static inline void *kasan_mem_to_shadow(const void *addr)
 {
-	return (void *)((unsigned long)addr >> KASAN_SHADOW_SCALE_SHIFT)
-		+ KASAN_SHADOW_OFFSET;
+	void *scaled;
+
+	if (IS_ENABLED(CONFIG_KASAN_GENERIC))
+		scaled = (void *)((unsigned long)addr >> KASAN_SHADOW_SCALE_SHIFT);
+	else
+		scaled = (void *)((long)addr >> KASAN_SHADOW_SCALE_SHIFT);
+
+	return KASAN_SHADOW_OFFSET + scaled;
 }
 #endif
 
diff --git a/mm/kasan/report.c b/mm/kasan/report.c
index 62c01b4527eb..b5beb1b10bd2 100644
--- a/mm/kasan/report.c
+++ b/mm/kasan/report.c
@@ -642,11 +642,39 @@ void kasan_non_canonical_hook(unsigned long addr)
 	const char *bug_type;
 
 	/*
-	 * All addresses that came as a result of the memory-to-shadow mapping
-	 * (even for bogus pointers) must be >= KASAN_SHADOW_OFFSET.
+	 * For Generic KASAN, kasan_mem_to_shadow() uses the logical right shift
+	 * and never overflows with the chosen KASAN_SHADOW_OFFSET values (on
+	 * both x86 and arm64). Thus, the possible shadow addresses (even for
+	 * bogus pointers) belong to a single contiguous region that is the
+	 * result of kasan_mem_to_shadow() applied to the whole address space.
 	 */
-	if (addr < KASAN_SHADOW_OFFSET)
-		return;
+	if (IS_ENABLED(CONFIG_KASAN_GENERIC)) {
+		if (addr < (unsigned long)kasan_mem_to_shadow((void *)(0ULL)) ||
+		    addr > (unsigned long)kasan_mem_to_shadow((void *)(~0ULL)))
+			return;
+	}
+
+	/*
+	 * For Software Tag-Based KASAN, kasan_mem_to_shadow() uses the
+	 * arithmetic shift. Normally, this would make checking for a possible
+	 * shadow address complicated, as the shadow address computation
+	 * operation would overflow only for some memory addresses. However, due
+	 * to the chosen KASAN_SHADOW_OFFSET values and the fact the
+	 * kasan_mem_to_shadow() only operates on pointers with the tag reset,
+	 * the overflow always happens.
+	 *
+	 * For arm64, the top byte of the pointer gets reset to 0xFF. Thus, the
+	 * possible shadow addresses belong to a region that is the result of
+	 * kasan_mem_to_shadow() applied to the memory range
+	 * [0xFF000000000000, 0xFFFFFFFFFFFFFFFF]. Despite the overflow, the
+	 * resulting possible shadow region is contiguous, as the overflow
+	 * happens for both 0xFF000000000000 and 0xFFFFFFFFFFFFFFFF.
+	 */
+	if (IS_ENABLED(CONFIG_KASAN_SW_TAGS) && IS_ENABLED(CONFIG_ARM64)) {
+		if (addr < (unsigned long)kasan_mem_to_shadow((void *)(0xFFULL << 56)) ||
+		    addr > (unsigned long)kasan_mem_to_shadow((void *)(~0ULL)))
+			return;
+	}
 
 	orig_addr = (unsigned long)kasan_shadow_to_mem((void *)addr);
 
diff --git a/scripts/gdb/linux/kasan.py b/scripts/gdb/linux/kasan.py
index 56730b3fde0b..4b86202b155f 100644
--- a/scripts/gdb/linux/kasan.py
+++ b/scripts/gdb/linux/kasan.py
@@ -7,7 +7,8 @@
 #
 
 import gdb
-from linux import constants, mm
+from linux import constants, utils, mm
+from ctypes import c_int64 as s64
 
 def help():
     t = """Usage: lx-kasan_mem_to_shadow [Hex memory addr]
@@ -39,6 +40,8 @@ class KasanMemToShadow(gdb.Command):
         else:
             help()
     def kasan_mem_to_shadow(self, addr):
+        if constants.CONFIG_KASAN_SW_TAGS and not utils.is_target_arch('x86'):
+            addr = s64(addr)
         return (addr >> self.p_ops.KASAN_SHADOW_SCALE_SHIFT) + self.p_ops.KASAN_SHADOW_OFFSET
 
 KasanMemToShadow()
diff --git a/scripts/gdb/linux/mm.py b/scripts/gdb/linux/mm.py
index 7571aebbe650..2e63f3dedd53 100644
--- a/scripts/gdb/linux/mm.py
+++ b/scripts/gdb/linux/mm.py
@@ -110,12 +110,13 @@ class aarch64_page_ops():
         self.KERNEL_END = gdb.parse_and_eval("_end")
 
         if constants.LX_CONFIG_KASAN_GENERIC or constants.LX_CONFIG_KASAN_SW_TAGS:
+            self.KASAN_SHADOW_OFFSET = constants.LX_CONFIG_KASAN_SHADOW_OFFSET
             if constants.LX_CONFIG_KASAN_GENERIC:
                 self.KASAN_SHADOW_SCALE_SHIFT = 3
+                self.KASAN_SHADOW_END = (1 << (64 - self.KASAN_SHADOW_SCALE_SHIFT)) + self.KASAN_SHADOW_OFFSET
             else:
                 self.KASAN_SHADOW_SCALE_SHIFT = 4
-            self.KASAN_SHADOW_OFFSET = constants.LX_CONFIG_KASAN_SHADOW_OFFSET
-            self.KASAN_SHADOW_END = (1 << (64 - self.KASAN_SHADOW_SCALE_SHIFT)) + self.KASAN_SHADOW_OFFSET
+                self.KASAN_SHADOW_END = self.KASAN_SHADOW_OFFSET
             self.PAGE_END = self.KASAN_SHADOW_END - (1 << (self.vabits_actual - self.KASAN_SHADOW_SCALE_SHIFT))
         else:
             self.PAGE_END = self._PAGE_END(self.VA_BITS_MIN)
-- 
2.52.0




From m.wieczorretman at pm.me  Wed Dec 10 09:28:43 2025
From: m.wieczorretman at pm.me (Maciej Wieczor-Retman)
Date: Wed, 10 Dec 2025 17:28:43 +0000
Subject: [PATCH v7 02/15] kasan: arm64: x86: Make special tags arch specific
In-Reply-To: <cover.1765386422.git.m.wieczorretman@pm.me>
References: <cover.1765386422.git.m.wieczorretman@pm.me>
Message-ID: <0db7ec3b1a813b4d9e3aa8648b3c212166a248b7.1765386422.git.m.wieczorretman@pm.me>

From: Samuel Holland <samuel.holland at sifive.com>

KASAN's tag-based mode defines multiple special tag values. They're
reserved for:
- Native kernel value. On arm64 it's 0xFF and it causes an early return
  in the tag checking function.
- Invalid value. 0xFE marks an area as freed / unallocated. It's also
  the value that is used to initialize regions of shadow memory.
- Min and max values. 0xFD is the highest value that can be randomly
  generated for a new tag. 0 is the minimal value with the exception of
  arm64's hardware mode where it is equal to 0xF0.

Metadata macro is also defined:
- Tag width equal to 8.

Tag-based mode on x86 is going to use 4 bit wide tags so all the above
values need to be changed accordingly.

Make tag width and native kernel tag arch specific for x86 and arm64.

Base the invalid tag value and the max value on the native kernel tag
since they follow the same pattern on both mentioned architectures.

Also generalize KASAN_SHADOW_INIT and 0xff used in various
page_kasan_tag* helpers.

Give KASAN_TAG_MIN the default value of zero, and move the special value
for hw_tags arm64 to its arch specific kasan-tags.h.

Signed-off-by: Samuel Holland <samuel.holland at sifive.com>
Co-developed-by: Maciej Wieczor-Retman <maciej.wieczor-retman at intel.com>
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman at intel.com>
---
Changelog v7:
- Reorder defines of arm64 tag width to prevent redefinition warnings.
- Remove KASAN_TAG_MASK so it's only defined in mmzone.h (Andrey
  Konovalov)
- Merge the 'support tag widths less than 8 bits' with this patch since
  they do similar things and overwrite each other. (Alexander)

Changelog v6:
- Add hardware tags KASAN_TAG_WIDTH value to the arm64 arch file.
- Keep KASAN_TAG_MASK in the mmzone.h.
- Remove ifndef from KASAN_SHADOW_INIT.

Changelog v5:
- Move KASAN_TAG_MIN to the arm64 kasan-tags.h for the hardware KASAN
  mode case.

Changelog v4:
- Move KASAN_TAG_MASK to kasan-tags.h.

Changelog v2:
- Remove risc-v from the patch.

 MAINTAINERS                         |  2 +-
 arch/arm64/include/asm/kasan-tags.h | 14 ++++++++++++++
 arch/arm64/include/asm/kasan.h      |  2 --
 arch/arm64/include/asm/uaccess.h    |  1 +
 arch/x86/include/asm/kasan-tags.h   |  9 +++++++++
 include/linux/kasan-tags.h          | 19 ++++++++++++++-----
 include/linux/kasan.h               |  3 +--
 include/linux/mm.h                  |  6 +++---
 include/linux/page-flags-layout.h   |  9 +--------
 9 files changed, 44 insertions(+), 21 deletions(-)
 create mode 100644 arch/arm64/include/asm/kasan-tags.h
 create mode 100644 arch/x86/include/asm/kasan-tags.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 7bf6385efe04..a591598cc4b5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13420,7 +13420,7 @@ L:	kasan-dev at googlegroups.com
 S:	Maintained
 B:	https://bugzilla.kernel.org/buglist.cgi?component=Sanitizers&product=Memory%20Management
 F:	Documentation/dev-tools/kasan.rst
-F:	arch/*/include/asm/*kasan.h
+F:	arch/*/include/asm/*kasan*.h
 F:	arch/*/mm/kasan_init*
 F:	include/linux/kasan*.h
 F:	lib/Kconfig.kasan
diff --git a/arch/arm64/include/asm/kasan-tags.h b/arch/arm64/include/asm/kasan-tags.h
new file mode 100644
index 000000000000..259952677443
--- /dev/null
+++ b/arch/arm64/include/asm/kasan-tags.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_KASAN_TAGS_H
+#define __ASM_KASAN_TAGS_H
+
+#define KASAN_TAG_KERNEL	0xFF /* native kernel pointers tag */
+
+#ifdef CONFIG_KASAN_HW_TAGS
+#define KASAN_TAG_MIN		0xF0 /* minimum value for random tags */
+#define KASAN_TAG_WIDTH		4
+#else
+#define KASAN_TAG_WIDTH		8
+#endif
+
+#endif /* ASM_KASAN_TAGS_H */
diff --git a/arch/arm64/include/asm/kasan.h b/arch/arm64/include/asm/kasan.h
index e1b57c13f8a4..d2841e0fb908 100644
--- a/arch/arm64/include/asm/kasan.h
+++ b/arch/arm64/include/asm/kasan.h
@@ -6,8 +6,6 @@
 
 #include <linux/linkage.h>
 #include <asm/memory.h>
-#include <asm/mte-kasan.h>
-#include <asm/pgtable-types.h>
 
 #define arch_kasan_set_tag(addr, tag)	__tag_set(addr, tag)
 #define arch_kasan_reset_tag(addr)	__tag_reset(addr)
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
index 6490930deef8..ccd41a39e3a1 100644
--- a/arch/arm64/include/asm/uaccess.h
+++ b/arch/arm64/include/asm/uaccess.h
@@ -22,6 +22,7 @@
 #include <asm/cpufeature.h>
 #include <asm/mmu.h>
 #include <asm/mte.h>
+#include <asm/mte-kasan.h>
 #include <asm/ptrace.h>
 #include <asm/memory.h>
 #include <asm/extable.h>
diff --git a/arch/x86/include/asm/kasan-tags.h b/arch/x86/include/asm/kasan-tags.h
new file mode 100644
index 000000000000..68ba385bc75c
--- /dev/null
+++ b/arch/x86/include/asm/kasan-tags.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_KASAN_TAGS_H
+#define __ASM_KASAN_TAGS_H
+
+#define KASAN_TAG_KERNEL	0xF /* native kernel pointers tag */
+
+#define KASAN_TAG_WIDTH		4
+
+#endif /* ASM_KASAN_TAGS_H */
diff --git a/include/linux/kasan-tags.h b/include/linux/kasan-tags.h
index 4f85f562512c..ad5c11950233 100644
--- a/include/linux/kasan-tags.h
+++ b/include/linux/kasan-tags.h
@@ -2,13 +2,22 @@
 #ifndef _LINUX_KASAN_TAGS_H
 #define _LINUX_KASAN_TAGS_H
 
+#if defined(CONFIG_KASAN_SW_TAGS) || defined(CONFIG_KASAN_HW_TAGS)
+#include <asm/kasan-tags.h>
+#endif
+
+#ifndef KASAN_TAG_WIDTH
+#define KASAN_TAG_WIDTH		0
+#endif
+
+#ifndef KASAN_TAG_KERNEL
 #define KASAN_TAG_KERNEL	0xFF /* native kernel pointers tag */
-#define KASAN_TAG_INVALID	0xFE /* inaccessible memory tag */
-#define KASAN_TAG_MAX		0xFD /* maximum value for random tags */
+#endif
+
+#define KASAN_TAG_INVALID	(KASAN_TAG_KERNEL - 1) /* inaccessible memory tag */
+#define KASAN_TAG_MAX		(KASAN_TAG_KERNEL - 2) /* maximum value for random tags */
 
-#ifdef CONFIG_KASAN_HW_TAGS
-#define KASAN_TAG_MIN		0xF0 /* minimum value for random tags */
-#else
+#ifndef KASAN_TAG_MIN
 #define KASAN_TAG_MIN		0x00 /* minimum value for random tags */
 #endif
 
diff --git a/include/linux/kasan.h b/include/linux/kasan.h
index 670de5427c32..5cb21b90a2ec 100644
--- a/include/linux/kasan.h
+++ b/include/linux/kasan.h
@@ -39,8 +39,7 @@ typedef unsigned int __bitwise kasan_vmalloc_flags_t;
 /* Software KASAN implementations use shadow memory. */
 
 #ifdef CONFIG_KASAN_SW_TAGS
-/* This matches KASAN_TAG_INVALID. */
-#define KASAN_SHADOW_INIT 0xFE
+#define KASAN_SHADOW_INIT KASAN_TAG_INVALID
 #else
 #define KASAN_SHADOW_INIT 0
 #endif
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 8e9268cf929e..b61090a80e3f 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1762,7 +1762,7 @@ static inline u8 page_kasan_tag(const struct page *page)
 
 	if (kasan_enabled()) {
 		tag = (page->flags.f >> KASAN_TAG_PGSHIFT) & KASAN_TAG_MASK;
-		tag ^= 0xff;
+		tag ^= KASAN_TAG_KERNEL;
 	}
 
 	return tag;
@@ -1775,7 +1775,7 @@ static inline void page_kasan_tag_set(struct page *page, u8 tag)
 	if (!kasan_enabled())
 		return;
 
-	tag ^= 0xff;
+	tag ^= KASAN_TAG_KERNEL;
 	old_flags = READ_ONCE(page->flags.f);
 	do {
 		flags = old_flags;
@@ -1794,7 +1794,7 @@ static inline void page_kasan_tag_reset(struct page *page)
 
 static inline u8 page_kasan_tag(const struct page *page)
 {
-	return 0xff;
+	return KASAN_TAG_KERNEL;
 }
 
 static inline void page_kasan_tag_set(struct page *page, u8 tag) { }
diff --git a/include/linux/page-flags-layout.h b/include/linux/page-flags-layout.h
index 760006b1c480..b2cc4cb870e0 100644
--- a/include/linux/page-flags-layout.h
+++ b/include/linux/page-flags-layout.h
@@ -3,6 +3,7 @@
 #define PAGE_FLAGS_LAYOUT_H
 
 #include <linux/numa.h>
+#include <linux/kasan-tags.h>
 #include <generated/bounds.h>
 
 /*
@@ -72,14 +73,6 @@
 #define NODE_NOT_IN_PAGE_FLAGS	1
 #endif
 
-#if defined(CONFIG_KASAN_SW_TAGS)
-#define KASAN_TAG_WIDTH 8
-#elif defined(CONFIG_KASAN_HW_TAGS)
-#define KASAN_TAG_WIDTH 4
-#else
-#define KASAN_TAG_WIDTH 0
-#endif
-
 #ifdef CONFIG_NUMA_BALANCING
 #define LAST__PID_SHIFT 8
 #define LAST__PID_MASK  ((1 << LAST__PID_SHIFT)-1)
-- 
2.52.0




From m.wieczorretman at pm.me  Wed Dec 10 09:30:10 2025
From: m.wieczorretman at pm.me (Maciej Wieczor-Retman)
Date: Wed, 10 Dec 2025 17:30:10 +0000
Subject: [PATCH v7 13/15] arm64: Unify software tag-based KASAN inline recovery path
In-Reply-To: <cover.1765386422.git.m.wieczorretman@pm.me>
References: <cover.1765386422.git.m.wieczorretman@pm.me>
Message-ID: <3cb831d9ec43485b42b2c6ff765367c4a92c5d5f.1765386422.git.m.wieczorretman@pm.me>

From: Maciej Wieczor-Retman <maciej.wieczor-retman at intel.com>

To avoid having a copy of a long comment explaining the intricacies of
the inline KASAN recovery system and issues for every architecture that
uses the software tag-based mode, a unified kasan_die_unless_recover()
function was added.

Use kasan_die_unless_recover() in the kasan brk handler to cleanup the
long comment, that's kept in the non-arch KASAN code.

Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman at intel.com>
Acked-by: Catalin Marinas <catalin.marinas at arm.com>
Acked-by: Alexander Potapenko <glider at google.com>
---
Changelog v7:
- Add Alexander's Acked-by tag.

Changelog v6:
- Add Catalin's Acked-by tag.

Changelog v5:
- Split arm64 portion of patch 13/18 into this one. (Peter Zijlstra)

 arch/arm64/kernel/traps.c | 17 +----------------
 1 file changed, 1 insertion(+), 16 deletions(-)

diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index 681939ef5d16..b1efc11c3b5a 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -1071,22 +1071,7 @@ int kasan_brk_handler(struct pt_regs *regs, unsigned long esr)
 
 	kasan_report(addr, size, write, pc);
 
-	/*
-	 * The instrumentation allows to control whether we can proceed after
-	 * a crash was detected. This is done by passing the -recover flag to
-	 * the compiler. Disabling recovery allows to generate more compact
-	 * code.
-	 *
-	 * Unfortunately disabling recovery doesn't work for the kernel right
-	 * now. KASAN reporting is disabled in some contexts (for example when
-	 * the allocator accesses slab object metadata; this is controlled by
-	 * current->kasan_depth). All these accesses are detected by the tool,
-	 * even though the reports for them are not printed.
-	 *
-	 * This is something that might be fixed at some point in the future.
-	 */
-	if (!recover)
-		die("Oops - KASAN", regs, esr);
+	kasan_die_unless_recover(recover, "Oops - KASAN", regs, esr, die);
 
 	/* If thread survives, skip over the brk instruction and continue: */
 	arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);
-- 
2.52.0




From maz at kernel.org  Wed Dec 10 09:30:19 2025
From: maz at kernel.org (Marc Zyngier)
Date: Wed, 10 Dec 2025 17:30:19 +0000
Subject: [PATCH v2 1/6] KVM: arm64: Fix EL2 S1 XN handling for hVHE setups
In-Reply-To: <20251210173024.561160-1-maz@kernel.org>
References: <20251210173024.561160-1-maz@kernel.org>
Message-ID: <20251210173024.561160-2-maz@kernel.org>

The current XN implementation is tied to the EL2 translation regime,
and fall flat on its face with the EL2&0 one that is used for hVHE,
as the permission bit for privileged execution is a different one.

Fixes: 6537565fd9b7f ("KVM: arm64: Adjust EL2 stage-1 leaf AP bits when ARM64_KVM_HVHE is set")
Signed-off-by: Marc Zyngier <maz at kernel.org>
---
 arch/arm64/include/asm/kvm_pgtable.h | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h
index fc02de43c68dd..be68b89692065 100644
--- a/arch/arm64/include/asm/kvm_pgtable.h
+++ b/arch/arm64/include/asm/kvm_pgtable.h
@@ -87,7 +87,15 @@ typedef u64 kvm_pte_t;
 
 #define KVM_PTE_LEAF_ATTR_HI_SW		GENMASK(58, 55)
 
-#define KVM_PTE_LEAF_ATTR_HI_S1_XN	BIT(54)
+#define __KVM_PTE_LEAF_ATTR_HI_S1_XN	BIT(54)
+#define __KVM_PTE_LEAF_ATTR_HI_S1_UXN	BIT(54)
+#define __KVM_PTE_LEAF_ATTR_HI_S1_PXN	BIT(53)
+
+#define KVM_PTE_LEAF_ATTR_HI_S1_XN					\
+	({ cpus_have_final_cap(ARM64_KVM_HVHE) ?			\
+			(__KVM_PTE_LEAF_ATTR_HI_S1_UXN |		\
+			 __KVM_PTE_LEAF_ATTR_HI_S1_PXN) :		\
+			__KVM_PTE_LEAF_ATTR_HI_S1_XN; })
 
 #define KVM_PTE_LEAF_ATTR_HI_S2_XN	GENMASK(54, 53)
 
-- 
2.47.3



From maz at kernel.org  Wed Dec 10 09:30:18 2025
From: maz at kernel.org (Marc Zyngier)
Date: Wed, 10 Dec 2025 17:30:18 +0000
Subject: [PATCH v2 0/6] KVM: arm64: VTCR_EL2 conversion to feature dependency framework
Message-ID: <20251210173024.561160-1-maz@kernel.org>

This is a follow-up on my VTCR_EL2 sanitisation series, with extra
goodies, mostly as a consequence of Alexandru's patches and review.

* From [1]:

  - Added two patches fixing some FEAT_XNX issues: one dating back
    from the hVHE introduction, and the other related to the newer
    stuff in 6.19.

  - Expanded the scope of the RES1 handling in DECLARE_FEAT_MAP() to
    deal with FGTs, as we're about to get quality stuff thanks to
    GICv5.

  - Simplified the S2TGRANx detection slightly.

  - Collected RBs, with thanks

[1] https://lore.kernel.org/r/20251129144525.2609207-1-maz at kernel.org

Marc Zyngier (6):
  KVM: arm64: Fix EL2 S1 XN handling for hVHE setups
  arm64: Convert ID_AA64MMFR0_EL1.TGRAN{4,16,64}_2 to UnsignedEnum
  arm64: Convert VTCR_EL2 to sysreg infratructure
  KVM: arm64: Account for RES1 bits in DECLARE_FEAT_MAP() and co
  KVM: arm64: Convert VTCR_EL2 to config-driven sanitisation
  KVM: arm64: Honor UX/PX attributes for EL2 S1 mappings

 arch/arm64/include/asm/kvm_arm.h     | 52 ++++-----------
 arch/arm64/include/asm/kvm_host.h    |  1 +
 arch/arm64/include/asm/kvm_pgtable.h |  2 +
 arch/arm64/include/asm/sysreg.h      |  1 -
 arch/arm64/kvm/config.c              | 94 ++++++++++++++++++++++++----
 arch/arm64/kvm/emulate-nested.c      | 55 +++++++++-------
 arch/arm64/kvm/hyp/pgtable.c         | 32 +++++++---
 arch/arm64/kvm/nested.c              | 11 ++--
 arch/arm64/tools/sysreg              | 63 ++++++++++++++++++-
 9 files changed, 217 insertions(+), 94 deletions(-)

-- 
2.47.3



From maz at kernel.org  Wed Dec 10 09:30:20 2025
From: maz at kernel.org (Marc Zyngier)
Date: Wed, 10 Dec 2025 17:30:20 +0000
Subject: [PATCH v2 2/6] arm64: Convert ID_AA64MMFR0_EL1.TGRAN{4,16,64}_2 to UnsignedEnum
In-Reply-To: <20251210173024.561160-1-maz@kernel.org>
References: <20251210173024.561160-1-maz@kernel.org>
Message-ID: <20251210173024.561160-3-maz@kernel.org>

ID_AA64MMFR0_EL1.TGRAN{4,16,64}_2 are currently represented as unordered
enumerations. However, the architecture treats them as Unsigned,
as hinted to by the MRS data:

(FEAT_S2TGran4K <=> (((UInt(ID_AA64MMFR0_EL1.TGran4_2) == 0) &&
		       FEAT_TGran4K) ||
		     (UInt(ID_AA64MMFR0_EL1.TGran4_2) >= 2))))

and similar descriptions exist for 16 and 64k.

This is also confirmed by D24.1.3.3 ("Alternative ID scheme used for
ID_AA64MMFR0_EL1 stage 2 granule sizes") in the L.b revision of
the ARM ARM.

Turn these fields into UnsignedEnum so that we can use the above
description more or less literally.

Signed-off-by: Marc Zyngier <maz at kernel.org>
---
 arch/arm64/tools/sysreg | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
index 1c6cdf9d54bba..9d388f87d9a13 100644
--- a/arch/arm64/tools/sysreg
+++ b/arch/arm64/tools/sysreg
@@ -2098,18 +2098,18 @@ UnsignedEnum	47:44	EXS
 	0b0000	NI
 	0b0001	IMP
 EndEnum
-Enum	43:40	TGRAN4_2
+UnsignedEnum	43:40	TGRAN4_2
 	0b0000	TGRAN4
 	0b0001	NI
 	0b0010	IMP
 	0b0011	52_BIT
 EndEnum
-Enum	39:36	TGRAN64_2
+UnsignedEnum	39:36	TGRAN64_2
 	0b0000	TGRAN64
 	0b0001	NI
 	0b0010	IMP
 EndEnum
-Enum	35:32	TGRAN16_2
+UnsignedEnum	35:32	TGRAN16_2
 	0b0000	TGRAN16
 	0b0001	NI
 	0b0010	IMP
-- 
2.47.3



From maz at kernel.org  Wed Dec 10 09:30:22 2025
From: maz at kernel.org (Marc Zyngier)
Date: Wed, 10 Dec 2025 17:30:22 +0000
Subject: [PATCH v2 4/6] KVM: arm64: Account for RES1 bits in DECLARE_FEAT_MAP() and co
In-Reply-To: <20251210173024.561160-1-maz@kernel.org>
References: <20251210173024.561160-1-maz@kernel.org>
Message-ID: <20251210173024.561160-5-maz@kernel.org>

None of the registers we manage in the feature dependency infrastructure
so far has any RES1 bit. This is about to change, as VTCR_EL2 has
its bit 31 being RES1.

In order to not fail the consistency checks by not describing a bit,
add RES1 bits to the set of immutable bits. This requires some extra
surgery for the FGT handling, as we now need to track RES1 bits there
as well.

There are no RES1 FGT bits *yet*. Watch this space.

Signed-off-by: Marc Zyngier <maz at kernel.org>
---
 arch/arm64/include/asm/kvm_host.h |  1 +
 arch/arm64/kvm/config.c           | 25 +++++++-------
 arch/arm64/kvm/emulate-nested.c   | 55 +++++++++++++++++--------------
 3 files changed, 45 insertions(+), 36 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index ac7f970c78830..b552a1e03848c 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -638,6 +638,7 @@ struct fgt_masks {
 	u64		mask;
 	u64		nmask;
 	u64		res0;
+	u64		res1;
 };
 
 extern struct fgt_masks hfgrtr_masks;
diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index 24bb3f36e9d59..3845b188551b6 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -16,14 +16,14 @@
  */
 struct reg_bits_to_feat_map {
 	union {
-		u64	bits;
-		u64	*res0p;
+		u64		 bits;
+		struct fgt_masks *masks;
 	};
 
 #define	NEVER_FGU	BIT(0)	/* Can trap, but never UNDEF */
 #define	CALL_FUNC	BIT(1)	/* Needs to evaluate tons of crap */
 #define	FIXED_VALUE	BIT(2)	/* RAZ/WI or RAO/WI in KVM */
-#define	RES0_POINTER	BIT(3)	/* Pointer to RES0 value instead of bits */
+#define	MASKS_POINTER	BIT(3)	/* Pointer to fgt_masks struct instead of bits */
 
 	unsigned long	flags;
 
@@ -92,8 +92,8 @@ struct reg_feat_map_desc {
 #define NEEDS_FEAT_FIXED(m, ...)			\
 	__NEEDS_FEAT_FLAG(m, FIXED_VALUE, bits, __VA_ARGS__, 0)
 
-#define NEEDS_FEAT_RES0(p, ...)				\
-	__NEEDS_FEAT_FLAG(p, RES0_POINTER, res0p, __VA_ARGS__)
+#define NEEDS_FEAT_MASKS(p, ...)				\
+	__NEEDS_FEAT_FLAG(p, MASKS_POINTER, masks, __VA_ARGS__)
 
 /*
  * Declare the dependency between a set of bits and a set of features,
@@ -109,19 +109,20 @@ struct reg_feat_map_desc {
 #define DECLARE_FEAT_MAP(n, r, m, f)					\
 	struct reg_feat_map_desc n = {					\
 		.name			= #r,				\
-		.feat_map		= NEEDS_FEAT(~r##_RES0, f), 	\
+		.feat_map		= NEEDS_FEAT(~(r##_RES0 |	\
+						       r##_RES1), f),	\
 		.bit_feat_map		= m,				\
 		.bit_feat_map_sz	= ARRAY_SIZE(m),		\
 	}
 
 /*
  * Specialised version of the above for FGT registers that have their
- * RES0 masks described as struct fgt_masks.
+ * RESx masks described as struct fgt_masks.
  */
 #define DECLARE_FEAT_MAP_FGT(n, msk, m, f)				\
 	struct reg_feat_map_desc n = {					\
 		.name			= #msk,				\
-		.feat_map		= NEEDS_FEAT_RES0(&msk.res0, f),\
+		.feat_map		= NEEDS_FEAT_MASKS(&msk, f),	\
 		.bit_feat_map		= m,				\
 		.bit_feat_map_sz	= ARRAY_SIZE(m),		\
 	}
@@ -1168,21 +1169,21 @@ static const DECLARE_FEAT_MAP(mdcr_el2_desc, MDCR_EL2,
 			      mdcr_el2_feat_map, FEAT_AA64EL2);
 
 static void __init check_feat_map(const struct reg_bits_to_feat_map *map,
-				  int map_size, u64 res0, const char *str)
+				  int map_size, u64 resx, const char *str)
 {
 	u64 mask = 0;
 
 	for (int i = 0; i < map_size; i++)
 		mask |= map[i].bits;
 
-	if (mask != ~res0)
+	if (mask != ~resx)
 		kvm_err("Undefined %s behaviour, bits %016llx\n",
-			str, mask ^ ~res0);
+			str, mask ^ ~resx);
 }
 
 static u64 reg_feat_map_bits(const struct reg_bits_to_feat_map *map)
 {
-	return map->flags & RES0_POINTER ? ~(*map->res0p) : map->bits;
+	return map->flags & MASKS_POINTER ? (map->masks->mask | map->masks->nmask) : map->bits;
 }
 
 static void __init check_reg_desc(const struct reg_feat_map_desc *r)
diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c
index 834f13fb1fb7d..75d49f83342a5 100644
--- a/arch/arm64/kvm/emulate-nested.c
+++ b/arch/arm64/kvm/emulate-nested.c
@@ -2105,23 +2105,24 @@ static u32 encoding_next(u32 encoding)
 }
 
 #define FGT_MASKS(__n, __m)						\
-	struct fgt_masks __n = { .str = #__m, .res0 = __m, }
-
-FGT_MASKS(hfgrtr_masks, HFGRTR_EL2_RES0);
-FGT_MASKS(hfgwtr_masks, HFGWTR_EL2_RES0);
-FGT_MASKS(hfgitr_masks, HFGITR_EL2_RES0);
-FGT_MASKS(hdfgrtr_masks, HDFGRTR_EL2_RES0);
-FGT_MASKS(hdfgwtr_masks, HDFGWTR_EL2_RES0);
-FGT_MASKS(hafgrtr_masks, HAFGRTR_EL2_RES0);
-FGT_MASKS(hfgrtr2_masks, HFGRTR2_EL2_RES0);
-FGT_MASKS(hfgwtr2_masks, HFGWTR2_EL2_RES0);
-FGT_MASKS(hfgitr2_masks, HFGITR2_EL2_RES0);
-FGT_MASKS(hdfgrtr2_masks, HDFGRTR2_EL2_RES0);
-FGT_MASKS(hdfgwtr2_masks, HDFGWTR2_EL2_RES0);
+	struct fgt_masks __n = { .str = #__m, .res0 = __m ## _RES0, .res1 = __m ## _RES1 }
+
+FGT_MASKS(hfgrtr_masks, HFGRTR_EL2);
+FGT_MASKS(hfgwtr_masks, HFGWTR_EL2);
+FGT_MASKS(hfgitr_masks, HFGITR_EL2);
+FGT_MASKS(hdfgrtr_masks, HDFGRTR_EL2);
+FGT_MASKS(hdfgwtr_masks, HDFGWTR_EL2);
+FGT_MASKS(hafgrtr_masks, HAFGRTR_EL2);
+FGT_MASKS(hfgrtr2_masks, HFGRTR2_EL2);
+FGT_MASKS(hfgwtr2_masks, HFGWTR2_EL2);
+FGT_MASKS(hfgitr2_masks, HFGITR2_EL2);
+FGT_MASKS(hdfgrtr2_masks, HDFGRTR2_EL2);
+FGT_MASKS(hdfgwtr2_masks, HDFGWTR2_EL2);
 
 static __init bool aggregate_fgt(union trap_config tc)
 {
 	struct fgt_masks *rmasks, *wmasks;
+	u64 rresx, wresx;
 
 	switch (tc.fgt) {
 	case HFGRTR_GROUP:
@@ -2154,24 +2155,27 @@ static __init bool aggregate_fgt(union trap_config tc)
 		break;
 	}
 
+	rresx = rmasks->res0 | rmasks->res1;
+	if (wmasks)
+		wresx = wmasks->res0 | wmasks->res1;
+
 	/*
 	 * A bit can be reserved in either the R or W register, but
 	 * not both.
 	 */
-	if ((BIT(tc.bit) & rmasks->res0) &&
-	    (!wmasks || (BIT(tc.bit) & wmasks->res0)))
+	if ((BIT(tc.bit) & rresx) && (!wmasks || (BIT(tc.bit) & wresx)))
 		return false;
 
 	if (tc.pol)
-		rmasks->mask |= BIT(tc.bit) & ~rmasks->res0;
+		rmasks->mask |= BIT(tc.bit) & ~rresx;
 	else
-		rmasks->nmask |= BIT(tc.bit) & ~rmasks->res0;
+		rmasks->nmask |= BIT(tc.bit) & ~rresx;
 
 	if (wmasks) {
 		if (tc.pol)
-			wmasks->mask |= BIT(tc.bit) & ~wmasks->res0;
+			wmasks->mask |= BIT(tc.bit) & ~wresx;
 		else
-			wmasks->nmask |= BIT(tc.bit) & ~wmasks->res0;
+			wmasks->nmask |= BIT(tc.bit) & ~wresx;
 	}
 
 	return true;
@@ -2180,7 +2184,6 @@ static __init bool aggregate_fgt(union trap_config tc)
 static __init int check_fgt_masks(struct fgt_masks *masks)
 {
 	unsigned long duplicate = masks->mask & masks->nmask;
-	u64 res0 = masks->res0;
 	int ret = 0;
 
 	if (duplicate) {
@@ -2194,10 +2197,14 @@ static __init int check_fgt_masks(struct fgt_masks *masks)
 		ret = -EINVAL;
 	}
 
-	masks->res0 = ~(masks->mask | masks->nmask);
-	if (masks->res0 != res0)
-		kvm_info("Implicit %s = %016llx, expecting %016llx\n",
-			 masks->str, masks->res0, res0);
+	if ((masks->res0 | masks->res1 | masks->mask | masks->nmask) != GENMASK(63, 0) ||
+	    (masks->res0 & masks->res1)  || (masks->res0 & masks->mask) ||
+	    (masks->res0 & masks->nmask) || (masks->res1 & masks->mask)  ||
+	    (masks->res1 & masks->nmask) || (masks->mask & masks->nmask)) {
+		kvm_info("Inconsistent masks for %s (%016llx, %016llx, %016llx, %016llx)\n",
+			 masks->str, masks->res0, masks->res1, masks->mask, masks->nmask);
+		masks->res0 = ~(masks->res1 | masks->mask | masks->nmask);
+	}
 
 	return ret;
 }
-- 
2.47.3



From maz at kernel.org  Wed Dec 10 09:30:21 2025
From: maz at kernel.org (Marc Zyngier)
Date: Wed, 10 Dec 2025 17:30:21 +0000
Subject: [PATCH v2 3/6] arm64: Convert VTCR_EL2 to sysreg infratructure
In-Reply-To: <20251210173024.561160-1-maz@kernel.org>
References: <20251210173024.561160-1-maz@kernel.org>
Message-ID: <20251210173024.561160-4-maz@kernel.org>

Our definition of VTCR_EL2 is both partial (tons of fields are
missing) and totally inconsistent (some constants are shifted,
some are not). They are also expressed in terms of TCR, which is
rather inconvenient.

Replace the ad-hoc definitions with the the generated version.
This results in a bunch of additional changes to make the code
with the unshifted nature of generated enumerations.

The register data was extracted from the BSD licenced AARCHMRS
(AARCHMRS_OPENSOURCE_A_profile_FAT-2025-09_ASL0).

Reviewed-by: Alexandru Elisei <alexandru.elisei at arm.com>
Signed-off-by: Marc Zyngier <maz at kernel.org>
---
 arch/arm64/include/asm/kvm_arm.h | 52 +++++++----------------------
 arch/arm64/include/asm/sysreg.h  |  1 -
 arch/arm64/kvm/hyp/pgtable.c     |  8 ++---
 arch/arm64/kvm/nested.c          |  8 ++---
 arch/arm64/tools/sysreg          | 57 ++++++++++++++++++++++++++++++++
 5 files changed, 76 insertions(+), 50 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index e500600e4b9b8..dfdbd2b65db9e 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -124,37 +124,7 @@
 #define TCR_EL2_MASK	(TCR_EL2_TG0_MASK | TCR_EL2_SH0_MASK | \
 			 TCR_EL2_ORGN0_MASK | TCR_EL2_IRGN0_MASK)
 
-/* VTCR_EL2 Registers bits */
-#define VTCR_EL2_DS		TCR_EL2_DS
-#define VTCR_EL2_RES1		(1U << 31)
-#define VTCR_EL2_HD		(1 << 22)
-#define VTCR_EL2_HA		(1 << 21)
-#define VTCR_EL2_PS_SHIFT	TCR_EL2_PS_SHIFT
-#define VTCR_EL2_PS_MASK	TCR_EL2_PS_MASK
-#define VTCR_EL2_TG0_MASK	TCR_TG0_MASK
-#define VTCR_EL2_TG0_4K		TCR_TG0_4K
-#define VTCR_EL2_TG0_16K	TCR_TG0_16K
-#define VTCR_EL2_TG0_64K	TCR_TG0_64K
-#define VTCR_EL2_SH0_MASK	TCR_SH0_MASK
-#define VTCR_EL2_SH0_INNER	TCR_SH0_INNER
-#define VTCR_EL2_ORGN0_MASK	TCR_ORGN0_MASK
-#define VTCR_EL2_ORGN0_WBWA	TCR_ORGN0_WBWA
-#define VTCR_EL2_IRGN0_MASK	TCR_IRGN0_MASK
-#define VTCR_EL2_IRGN0_WBWA	TCR_IRGN0_WBWA
-#define VTCR_EL2_SL0_SHIFT	6
-#define VTCR_EL2_SL0_MASK	(3 << VTCR_EL2_SL0_SHIFT)
-#define VTCR_EL2_T0SZ_MASK	0x3f
-#define VTCR_EL2_VS_SHIFT	19
-#define VTCR_EL2_VS_8BIT	(0 << VTCR_EL2_VS_SHIFT)
-#define VTCR_EL2_VS_16BIT	(1 << VTCR_EL2_VS_SHIFT)
-
-#define VTCR_EL2_T0SZ(x)	TCR_T0SZ(x)
-
 /*
- * We configure the Stage-2 page tables to always restrict the IPA space to be
- * 40 bits wide (T0SZ = 24).  Systems with a PARange smaller than 40 bits are
- * not known to exist and will break with this configuration.
- *
  * The VTCR_EL2 is configured per VM and is initialised in kvm_init_stage2_mmu.
  *
  * Note that when using 4K pages, we concatenate two first level page tables
@@ -162,9 +132,6 @@
  *
  */
 
-#define VTCR_EL2_COMMON_BITS	(VTCR_EL2_SH0_INNER | VTCR_EL2_ORGN0_WBWA | \
-				 VTCR_EL2_IRGN0_WBWA | VTCR_EL2_RES1)
-
 /*
  * VTCR_EL2:SL0 indicates the entry level for Stage2 translation.
  * Interestingly, it depends on the page size.
@@ -196,30 +163,35 @@
  */
 #ifdef CONFIG_ARM64_64K_PAGES
 
-#define VTCR_EL2_TGRAN			VTCR_EL2_TG0_64K
+#define VTCR_EL2_TGRAN			64K
 #define VTCR_EL2_TGRAN_SL0_BASE		3UL
 
 #elif defined(CONFIG_ARM64_16K_PAGES)
 
-#define VTCR_EL2_TGRAN			VTCR_EL2_TG0_16K
+#define VTCR_EL2_TGRAN			16K
 #define VTCR_EL2_TGRAN_SL0_BASE		3UL
 
 #else	/* 4K */
 
-#define VTCR_EL2_TGRAN			VTCR_EL2_TG0_4K
+#define VTCR_EL2_TGRAN			4K
 #define VTCR_EL2_TGRAN_SL0_BASE		2UL
 
 #endif
 
 #define VTCR_EL2_LVLS_TO_SL0(levels)	\
-	((VTCR_EL2_TGRAN_SL0_BASE - (4 - (levels))) << VTCR_EL2_SL0_SHIFT)
+	FIELD_PREP(VTCR_EL2_SL0, (VTCR_EL2_TGRAN_SL0_BASE - (4 - (levels))))
 #define VTCR_EL2_SL0_TO_LVLS(sl0)	\
 	((sl0) + 4 - VTCR_EL2_TGRAN_SL0_BASE)
 #define VTCR_EL2_LVLS(vtcr)		\
-	VTCR_EL2_SL0_TO_LVLS(((vtcr) & VTCR_EL2_SL0_MASK) >> VTCR_EL2_SL0_SHIFT)
+	VTCR_EL2_SL0_TO_LVLS(FIELD_GET(VTCR_EL2_SL0, (vtcr)))
+
+#define VTCR_EL2_FLAGS	(SYS_FIELD_PREP_ENUM(VTCR_EL2, SH0, INNER)	    | \
+			 SYS_FIELD_PREP_ENUM(VTCR_EL2, ORGN0, WBWA)	    | \
+			 SYS_FIELD_PREP_ENUM(VTCR_EL2, IRGN0, WBWA)	    | \
+			 SYS_FIELD_PREP_ENUM(VTCR_EL2, TG0, VTCR_EL2_TGRAN) | \
+			 VTCR_EL2_RES1)
 
-#define VTCR_EL2_FLAGS			(VTCR_EL2_COMMON_BITS | VTCR_EL2_TGRAN)
-#define VTCR_EL2_IPA(vtcr)		(64 - ((vtcr) & VTCR_EL2_T0SZ_MASK))
+#define VTCR_EL2_IPA(vtcr)		(64 - FIELD_GET(VTCR_EL2_T0SZ, (vtcr)))
 
 /*
  * ARM VMSAv8-64 defines an algorithm for finding the translation table
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index c231d2a3e5159..acad7a7621b9e 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -516,7 +516,6 @@
 #define SYS_TTBR1_EL2			sys_reg(3, 4, 2, 0, 1)
 #define SYS_TCR_EL2			sys_reg(3, 4, 2, 0, 2)
 #define SYS_VTTBR_EL2			sys_reg(3, 4, 2, 1, 0)
-#define SYS_VTCR_EL2			sys_reg(3, 4, 2, 1, 2)
 
 #define SYS_HAFGRTR_EL2			sys_reg(3, 4, 3, 1, 6)
 #define SYS_SPSR_EL2			sys_reg(3, 4, 4, 0, 0)
diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
index 947ac1a951a5b..e0bd6a0172729 100644
--- a/arch/arm64/kvm/hyp/pgtable.c
+++ b/arch/arm64/kvm/hyp/pgtable.c
@@ -583,8 +583,8 @@ u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
 	u64 vtcr = VTCR_EL2_FLAGS;
 	s8 lvls;
 
-	vtcr |= kvm_get_parange(mmfr0) << VTCR_EL2_PS_SHIFT;
-	vtcr |= VTCR_EL2_T0SZ(phys_shift);
+	vtcr |= FIELD_PREP(VTCR_EL2_PS, kvm_get_parange(mmfr0));
+	vtcr |= FIELD_PREP(VTCR_EL2_T0SZ, (UL(64) - phys_shift));
 	/*
 	 * Use a minimum 2 level page table to prevent splitting
 	 * host PMD huge pages at stage2.
@@ -624,9 +624,7 @@ u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
 		vtcr |= VTCR_EL2_DS;
 
 	/* Set the vmid bits */
-	vtcr |= (get_vmid_bits(mmfr1) == 16) ?
-		VTCR_EL2_VS_16BIT :
-		VTCR_EL2_VS_8BIT;
+	vtcr |= (get_vmid_bits(mmfr1) == 16) ? VTCR_EL2_VS : 0;
 
 	return vtcr;
 }
diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
index 911fc99ed99d9..e1ef8930c97b3 100644
--- a/arch/arm64/kvm/nested.c
+++ b/arch/arm64/kvm/nested.c
@@ -377,7 +377,7 @@ static void vtcr_to_walk_info(u64 vtcr, struct s2_walk_info *wi)
 {
 	wi->t0sz = vtcr & TCR_EL2_T0SZ_MASK;
 
-	switch (vtcr & VTCR_EL2_TG0_MASK) {
+	switch (FIELD_GET(VTCR_EL2_TG0_MASK, vtcr)) {
 	case VTCR_EL2_TG0_4K:
 		wi->pgshift = 12;	 break;
 	case VTCR_EL2_TG0_16K:
@@ -513,7 +513,7 @@ static u8 get_guest_mapping_ttl(struct kvm_s2_mmu *mmu, u64 addr)
 
 	lockdep_assert_held_write(&kvm_s2_mmu_to_kvm(mmu)->mmu_lock);
 
-	switch (vtcr & VTCR_EL2_TG0_MASK) {
+	switch (FIELD_GET(VTCR_EL2_TG0_MASK, vtcr)) {
 	case VTCR_EL2_TG0_4K:
 		ttl = (TLBI_TTL_TG_4K << 2);
 		break;
@@ -530,7 +530,7 @@ static u8 get_guest_mapping_ttl(struct kvm_s2_mmu *mmu, u64 addr)
 
 again:
 	/* Iteratively compute the block sizes for a particular granule size */
-	switch (vtcr & VTCR_EL2_TG0_MASK) {
+	switch (FIELD_GET(VTCR_EL2_TG0_MASK, vtcr)) {
 	case VTCR_EL2_TG0_4K:
 		if	(sz < SZ_4K)	sz = SZ_4K;
 		else if (sz < SZ_2M)	sz = SZ_2M;
@@ -593,7 +593,7 @@ unsigned long compute_tlb_inval_range(struct kvm_s2_mmu *mmu, u64 val)
 
 	if (!max_size) {
 		/* Compute the maximum extent of the invalidation */
-		switch (mmu->tlb_vtcr & VTCR_EL2_TG0_MASK) {
+		switch (FIELD_GET(VTCR_EL2_TG0_MASK, mmu->tlb_vtcr)) {
 		case VTCR_EL2_TG0_4K:
 			max_size = SZ_1G;
 			break;
diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
index 9d388f87d9a13..6f43b2ae5993b 100644
--- a/arch/arm64/tools/sysreg
+++ b/arch/arm64/tools/sysreg
@@ -4400,6 +4400,63 @@ Field	56:12	BADDR
 Res0	11:0
 EndSysreg
 
+Sysreg	VTCR_EL2	3	4	2	1	2
+Res0	63:46	
+Field	45	HDBSS
+Field	44	HAFT
+Res0	43:42	
+Field	41	TL0
+Field	40	GCSH
+Res0	39
+Field	38	D128
+Field	37	S2POE
+Field	36	S2PIE
+Field	35	TL1
+Field	34	AssuredOnly
+Field	33	SL2
+Field	32	DS
+Res1	31
+Field	30	NSA
+Field	29	NSW
+Field	28	HWU62
+Field	27	HWU61
+Field	26	HWU60
+Field	25	HWU59
+Res0	24:23
+Field	22	HD
+Field	21	HA
+Res0	20
+Enum	19	VS
+	0b0	8BIT
+	0b1	16BIT
+EndEnum
+Field	18:16	PS
+Enum	15:14	TG0
+	0b00	4K
+	0b01	64K
+	0b10	16K
+EndEnum
+Enum	13:12	SH0
+	0b00	NONE
+	0b01	OUTER
+	0b11	INNER
+EndEnum
+Enum	11:10	ORGN0
+	0b00	NC
+	0b01	WBWA
+	0b10	WT
+	0b11	WBnWA
+EndEnum
+Enum	9:8	IRGN0
+	0b00	NC
+	0b01	WBWA
+	0b10	WT
+	0b11	WBnWA
+EndEnum
+Field	7:6	SL0
+Field	5:0	T0SZ
+EndSysreg
+
 Sysreg	GCSCR_EL2	3	4	2	5	0
 Fields	GCSCR_ELx
 EndSysreg
-- 
2.47.3



From maz at kernel.org  Wed Dec 10 09:30:23 2025
From: maz at kernel.org (Marc Zyngier)
Date: Wed, 10 Dec 2025 17:30:23 +0000
Subject: [PATCH v2 5/6] KVM: arm64: Convert VTCR_EL2 to config-driven sanitisation
In-Reply-To: <20251210173024.561160-1-maz@kernel.org>
References: <20251210173024.561160-1-maz@kernel.org>
Message-ID: <20251210173024.561160-6-maz@kernel.org>

Describe all the VTCR_EL2 fields and their respective configurations,
making sure that we correctly ignore the bits that are not defined
for a given guest configuration.

Reviewed-by: Alexandru Elisei <alexandru.elisei at arm.com>
Signed-off-by: Marc Zyngier <maz at kernel.org>
---
 arch/arm64/kvm/config.c | 69 +++++++++++++++++++++++++++++++++++++++++
 arch/arm64/kvm/nested.c |  3 +-
 2 files changed, 70 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index 3845b188551b6..9c04f895d3769 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -141,6 +141,7 @@ struct reg_feat_map_desc {
 #define FEAT_AA64EL1		ID_AA64PFR0_EL1, EL1, IMP
 #define FEAT_AA64EL2		ID_AA64PFR0_EL1, EL2, IMP
 #define FEAT_AA64EL3		ID_AA64PFR0_EL1, EL3, IMP
+#define FEAT_SEL2		ID_AA64PFR0_EL1, SEL2, IMP
 #define FEAT_AIE		ID_AA64MMFR3_EL1, AIE, IMP
 #define FEAT_S2POE		ID_AA64MMFR3_EL1, S2POE, IMP
 #define FEAT_S1POE		ID_AA64MMFR3_EL1, S1POE, IMP
@@ -202,6 +203,8 @@ struct reg_feat_map_desc {
 #define FEAT_ASID2		ID_AA64MMFR4_EL1, ASID2, IMP
 #define FEAT_MEC		ID_AA64MMFR3_EL1, MEC, IMP
 #define FEAT_HAFT		ID_AA64MMFR1_EL1, HAFDBS, HAFT
+#define FEAT_HDBSS		ID_AA64MMFR1_EL1, HAFDBS, HDBSS
+#define FEAT_HPDS2		ID_AA64MMFR1_EL1, HPDS, HPDS2
 #define FEAT_BTI		ID_AA64PFR1_EL1, BT, IMP
 #define FEAT_ExS		ID_AA64MMFR0_EL1, EXS, IMP
 #define FEAT_IESB		ID_AA64MMFR2_EL1, IESB, IMP
@@ -219,6 +222,7 @@ struct reg_feat_map_desc {
 #define FEAT_FGT2		ID_AA64MMFR0_EL1, FGT, FGT2
 #define FEAT_MTPMU		ID_AA64DFR0_EL1, MTPMU, IMP
 #define FEAT_HCX		ID_AA64MMFR1_EL1, HCX, IMP
+#define FEAT_S2PIE		ID_AA64MMFR3_EL1, S2PIE, IMP
 
 static bool not_feat_aa64el3(struct kvm *kvm)
 {
@@ -362,6 +366,28 @@ static bool feat_pmuv3p9(struct kvm *kvm)
 	return check_pmu_revision(kvm, V3P9);
 }
 
+#define has_feat_s2tgran(k, s)						\
+  ((kvm_has_feat_enum(kvm, ID_AA64MMFR0_EL1, TGRAN##s##_2, TGRAN##s) && \
+    kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN##s, IMP))		     ||	\
+   kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN##s##_2, IMP))
+
+static bool feat_lpa2(struct kvm *kvm)
+{
+	return ((kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4, 52_BIT)    ||
+		 !kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4, IMP))	&&
+		(kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16, 52_BIT)   ||
+		 !kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16, IMP))	&&
+		(kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4_2, 52_BIT)  ||
+		 !has_feat_s2tgran(kvm, 4))				&&
+		(kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16_2, 52_BIT) ||
+		 !has_feat_s2tgran(kvm, 16)));
+}
+
+static bool feat_vmid16(struct kvm *kvm)
+{
+	return kvm_has_feat_enum(kvm, ID_AA64MMFR1_EL1, VMIDBits, 16);
+}
+
 static bool compute_hcr_rw(struct kvm *kvm, u64 *bits)
 {
 	/* This is purely academic: AArch32 and NV are mutually exclusive */
@@ -1168,6 +1194,44 @@ static const struct reg_bits_to_feat_map mdcr_el2_feat_map[] = {
 static const DECLARE_FEAT_MAP(mdcr_el2_desc, MDCR_EL2,
 			      mdcr_el2_feat_map, FEAT_AA64EL2);
 
+static const struct reg_bits_to_feat_map vtcr_el2_feat_map[] = {
+	NEEDS_FEAT(VTCR_EL2_HDBSS, FEAT_HDBSS),
+	NEEDS_FEAT(VTCR_EL2_HAFT, FEAT_HAFT),
+	NEEDS_FEAT(VTCR_EL2_TL0		|
+		   VTCR_EL2_TL1		|
+		   VTCR_EL2_AssuredOnly	|
+		   VTCR_EL2_GCSH,
+		   FEAT_THE),
+	NEEDS_FEAT(VTCR_EL2_D128, FEAT_D128),
+	NEEDS_FEAT(VTCR_EL2_S2POE, FEAT_S2POE),
+	NEEDS_FEAT(VTCR_EL2_S2PIE, FEAT_S2PIE),
+	NEEDS_FEAT(VTCR_EL2_SL2		|
+		   VTCR_EL2_DS,
+		   feat_lpa2),
+	NEEDS_FEAT(VTCR_EL2_NSA		|
+		   VTCR_EL2_NSW,
+		   FEAT_SEL2),
+	NEEDS_FEAT(VTCR_EL2_HWU62	|
+		   VTCR_EL2_HWU61	|
+		   VTCR_EL2_HWU60	|
+		   VTCR_EL2_HWU59,
+		   FEAT_HPDS2),
+	NEEDS_FEAT(VTCR_EL2_HD, ID_AA64MMFR1_EL1, HAFDBS, DBM),
+	NEEDS_FEAT(VTCR_EL2_HA, ID_AA64MMFR1_EL1, HAFDBS, AF),
+	NEEDS_FEAT(VTCR_EL2_VS, feat_vmid16),
+	NEEDS_FEAT(VTCR_EL2_PS		|
+		   VTCR_EL2_TG0		|
+		   VTCR_EL2_SH0		|
+		   VTCR_EL2_ORGN0	|
+		   VTCR_EL2_IRGN0	|
+		   VTCR_EL2_SL0		|
+		   VTCR_EL2_T0SZ,
+		   FEAT_AA64EL1),
+};
+
+static const DECLARE_FEAT_MAP(vtcr_el2_desc, VTCR_EL2,
+			      vtcr_el2_feat_map, FEAT_AA64EL2);
+
 static void __init check_feat_map(const struct reg_bits_to_feat_map *map,
 				  int map_size, u64 resx, const char *str)
 {
@@ -1211,6 +1275,7 @@ void __init check_feature_map(void)
 	check_reg_desc(&tcr2_el2_desc);
 	check_reg_desc(&sctlr_el1_desc);
 	check_reg_desc(&mdcr_el2_desc);
+	check_reg_desc(&vtcr_el2_desc);
 }
 
 static bool idreg_feat_match(struct kvm *kvm, const struct reg_bits_to_feat_map *map)
@@ -1425,6 +1490,10 @@ void get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg, u64 *res0, u64 *r
 		*res0 = compute_reg_res0_bits(kvm, &mdcr_el2_desc, 0, 0);
 		*res1 = MDCR_EL2_RES1;
 		break;
+	case VTCR_EL2:
+		*res0 = compute_reg_res0_bits(kvm, &vtcr_el2_desc, 0, 0);
+		*res1 = VTCR_EL2_RES1;
+		break;
 	default:
 		WARN_ON_ONCE(1);
 		*res0 = *res1 = 0;
diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
index e1ef8930c97b3..606cebcaa7c09 100644
--- a/arch/arm64/kvm/nested.c
+++ b/arch/arm64/kvm/nested.c
@@ -1719,8 +1719,7 @@ int kvm_init_nv_sysregs(struct kvm_vcpu *vcpu)
 	set_sysreg_masks(kvm, VTTBR_EL2, res0, res1);
 
 	/* VTCR_EL2 */
-	res0 = GENMASK(63, 32) | GENMASK(30, 20);
-	res1 = BIT(31);
+	get_reg_fixed_bits(kvm, VTCR_EL2, &res0, &res1);
 	set_sysreg_masks(kvm, VTCR_EL2, res0, res1);
 
 	/* VMPIDR_EL2 */
-- 
2.47.3



From maz at kernel.org  Wed Dec 10 09:30:24 2025
From: maz at kernel.org (Marc Zyngier)
Date: Wed, 10 Dec 2025 17:30:24 +0000
Subject: [PATCH v2 6/6] KVM: arm64: Honor UX/PX attributes for EL2 S1 mappings
In-Reply-To: <20251210173024.561160-1-maz@kernel.org>
References: <20251210173024.561160-1-maz@kernel.org>
Message-ID: <20251210173024.561160-7-maz@kernel.org>

Now that we potentially have two bits to deal with when setting
execution permissions, make sure we correctly handle them when both
when building the page tables and when reading back from them.

Reported-by: Alexandru Elisei <alexandru.elisei at arm.com>
Signed-off-by: Marc Zyngier <maz at kernel.org>
---
 arch/arm64/include/asm/kvm_pgtable.h | 12 +++---------
 arch/arm64/kvm/hyp/pgtable.c         | 24 +++++++++++++++++++++---
 2 files changed, 24 insertions(+), 12 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h
index be68b89692065..095e6b73740a6 100644
--- a/arch/arm64/include/asm/kvm_pgtable.h
+++ b/arch/arm64/include/asm/kvm_pgtable.h
@@ -87,15 +87,9 @@ typedef u64 kvm_pte_t;
 
 #define KVM_PTE_LEAF_ATTR_HI_SW		GENMASK(58, 55)
 
-#define __KVM_PTE_LEAF_ATTR_HI_S1_XN	BIT(54)
-#define __KVM_PTE_LEAF_ATTR_HI_S1_UXN	BIT(54)
-#define __KVM_PTE_LEAF_ATTR_HI_S1_PXN	BIT(53)
-
-#define KVM_PTE_LEAF_ATTR_HI_S1_XN					\
-	({ cpus_have_final_cap(ARM64_KVM_HVHE) ?			\
-			(__KVM_PTE_LEAF_ATTR_HI_S1_UXN |		\
-			 __KVM_PTE_LEAF_ATTR_HI_S1_PXN) :		\
-			__KVM_PTE_LEAF_ATTR_HI_S1_XN; })
+#define KVM_PTE_LEAF_ATTR_HI_S1_XN	BIT(54)
+#define KVM_PTE_LEAF_ATTR_HI_S1_UXN	BIT(54)
+#define KVM_PTE_LEAF_ATTR_HI_S1_PXN	BIT(53)
 
 #define KVM_PTE_LEAF_ATTR_HI_S2_XN	GENMASK(54, 53)
 
diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
index e0bd6a0172729..97c0835d25590 100644
--- a/arch/arm64/kvm/hyp/pgtable.c
+++ b/arch/arm64/kvm/hyp/pgtable.c
@@ -342,6 +342,9 @@ static int hyp_set_prot_attr(enum kvm_pgtable_prot prot, kvm_pte_t *ptep)
 	if (!(prot & KVM_PGTABLE_PROT_R))
 		return -EINVAL;
 
+	if (!cpus_have_final_cap(ARM64_KVM_HVHE))
+		prot &= ~KVM_PGTABLE_PROT_UX;
+
 	if (prot & KVM_PGTABLE_PROT_X) {
 		if (prot & KVM_PGTABLE_PROT_W)
 			return -EINVAL;
@@ -351,8 +354,16 @@ static int hyp_set_prot_attr(enum kvm_pgtable_prot prot, kvm_pte_t *ptep)
 
 		if (system_supports_bti_kernel())
 			attr |= KVM_PTE_LEAF_ATTR_HI_S1_GP;
+	}
+
+	if (cpus_have_final_cap(ARM64_KVM_HVHE)) {
+		if (!(prot & KVM_PGTABLE_PROT_PX))
+			attr |= KVM_PTE_LEAF_ATTR_HI_S1_PXN;
+		if (!(prot & KVM_PGTABLE_PROT_UX))
+			attr |= KVM_PTE_LEAF_ATTR_HI_S1_UXN;
 	} else {
-		attr |= KVM_PTE_LEAF_ATTR_HI_S1_XN;
+		if (!(prot & KVM_PGTABLE_PROT_PX))
+			attr |= KVM_PTE_LEAF_ATTR_HI_S1_XN;
 	}
 
 	attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_AP, ap);
@@ -373,8 +384,15 @@ enum kvm_pgtable_prot kvm_pgtable_hyp_pte_prot(kvm_pte_t pte)
 	if (!kvm_pte_valid(pte))
 		return prot;
 
-	if (!(pte & KVM_PTE_LEAF_ATTR_HI_S1_XN))
-		prot |= KVM_PGTABLE_PROT_X;
+	if (cpus_have_final_cap(ARM64_KVM_HVHE)) {
+		if (!(pte & KVM_PTE_LEAF_ATTR_HI_S1_PXN))
+			prot |= KVM_PGTABLE_PROT_PX;
+		if (!(pte & KVM_PTE_LEAF_ATTR_HI_S1_UXN))
+			prot |= KVM_PGTABLE_PROT_UX;
+	} else {
+		if (!(pte & KVM_PTE_LEAF_ATTR_HI_S1_XN))
+			prot |= KVM_PGTABLE_PROT_PX;
+	}
 
 	ap = FIELD_GET(KVM_PTE_LEAF_ATTR_LO_S1_AP, pte);
 	if (ap == KVM_PTE_LEAF_ATTR_LO_S1_AP_RO)
-- 
2.47.3



From luca.ceresoli at bootlin.com  Wed Dec 10 10:10:45 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Wed, 10 Dec 2025 19:10:45 +0100
Subject: [PATCH 03/21] drm/tilcdc: Remove simulate_vesa_sync flag
In-Reply-To: <20251126-feature_tilcdc-v1-3-49b9ef2e3aa0@bootlin.com>
References: <20251126-feature_tilcdc-v1-0-49b9ef2e3aa0@bootlin.com>
 <20251126-feature_tilcdc-v1-3-49b9ef2e3aa0@bootlin.com>
Message-ID: <DEUQM2HNEOQU.3K4ZPL44GVZAJ@bootlin.com>

Hi K?ry,

On Wed Nov 26, 2025 at 6:35 PM CET, Kory Maincent (TI.com) wrote:
> The tilcdc hardware does not generate VESA-compliant sync signals. It
> aligns the vertical sync (VS) on the second edge of the horizontal sync
> (HS) instead of the first edge. To compensate for this hardware
> behavior, the driver applies a timing adjustment in mode_fixup().
>
> Previously, this adjustment was conditional based on the simulate_vesa_sync
> flag, which was only set when using external encoders. This appears
> problematic because:
>
> 1. The timing adjustment seems needed for the hardware behavior regardless
>    of whether an external encoder is used
> 2. The external encoder infrastructure is driver-specific and being
>    removed due to design issues
> 3. Boards using tilcdc without bridges (e.g., am335x-evm, am335x-evmsk)
>    may not be getting the necessary timing adjustments
>
> Remove the simulate_vesa_sync flag and apply the VESA sync timing
> adjustment unconditionally, ensuring consistent behavior across all
> configurations. While it's unclear if the previous conditional behavior
> was causing actual issues, the unconditional adjustment better reflects
> the hardware's characteristics.
>
> Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
> ---
>
> Only few board currently use tilcdc not associated to a bridge like the
> am335x_evm or the am335x-evmsk.

Have you tested this change on any affected board?

The change looks good to me but without some testing it would be risky.

Luca

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From luca.ceresoli at bootlin.com  Wed Dec 10 10:13:53 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Wed, 10 Dec 2025 19:13:53 +0100
Subject: [PATCH 04/21] drm/tilcdc: Add support for DRM bus flags and
 simplify panel config
In-Reply-To: <20251126-feature_tilcdc-v1-4-49b9ef2e3aa0@bootlin.com>
References: <20251126-feature_tilcdc-v1-0-49b9ef2e3aa0@bootlin.com>
 <20251126-feature_tilcdc-v1-4-49b9ef2e3aa0@bootlin.com>
Message-ID: <DEUQOGYVBYFL.39NLEZ2GBI2WT@bootlin.com>

On Wed Nov 26, 2025 at 6:35 PM CET, Kory Maincent (TI.com) wrote:
> Migrate CRTC mode configuration to use standard DRM bus flags in
> preparation for removing the tilcdc_panel driver and its custom
> tilcdc_panel_info structure.
>
> Add support for DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE and
> DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE flags to control pixel clock and sync
> signal edge polarity, while maintaining backward compatibility with the
> existing tilcdc panel info structure.
>
> Simplify several hardware parameters by setting them to fixed defaults
> based on common usage across existing device trees:
> - DMA burst size: 16 (previously configurable via switch statement)
> - AC bias frequency: 255 (previously panel-specific)
> - FIFO DMA request delay: 128 (previously panel-specific)
>
> These parameters show no variation in real-world usage, so hardcoding
> them simplifies the driver without losing functionality.
>
> Preserve FIFO threshold configurability by adding a new "fifo-threshold"
> device tree property at the display controller level, as this parameter
> varies across different display configurations in existing device trees.
>
> Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>

Apart from the "fifo-threshold" property, which as discussed should instead
be inferred from the compatible, the patch looks good. I checked the values
which are being removed and they have all the same value in the code
defaults and all in-tree dts files.

Luca

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From luca.ceresoli at bootlin.com  Wed Dec 10 10:22:04 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Wed, 10 Dec 2025 19:22:04 +0100
Subject: [PATCH 10/21] drm/tilcdc: Remove redundant #endif/#ifdef in
 debugfs code
In-Reply-To: <20251126-feature_tilcdc-v1-10-49b9ef2e3aa0@bootlin.com>
References: <20251126-feature_tilcdc-v1-0-49b9ef2e3aa0@bootlin.com>
 <20251126-feature_tilcdc-v1-10-49b9ef2e3aa0@bootlin.com>
Message-ID: <DEUQUQS51C7K.FJD7W3YFJJU5@bootlin.com>

On Wed Nov 26, 2025 at 6:35 PM CET, Kory Maincent (TI.com) wrote:
> Remove the unnecessary #endif/#ifdef CONFIG_DEBUG_FS pair that splits
> the debugfs code section. This keeps all debugfs-related code within a
> single preprocessor conditional block, improving code readability.
>
> Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>

Reviewed-by: Luca Ceresoli <luca.ceresoli at bootlin.com>

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From lkp at intel.com  Wed Dec 10 10:31:00 2025
From: lkp at intel.com (kernel test robot)
Date: Thu, 11 Dec 2025 02:31:00 +0800
Subject: [PATCH v5 11/24] KVM: arm64: Writethrough trapped PMEVTYPER
 register
In-Reply-To: <20251209205121.1871534-12-coltonlewis@google.com>
References: <20251209205121.1871534-12-coltonlewis@google.com>
Message-ID: <202512110209.GjVZa9ti-lkp@intel.com>

Hi Colton,

kernel test robot noticed the following build errors:

[auto build test ERROR on ac3fd01e4c1efce8f2c054cdeb2ddd2fc0fb150d]

url:    https://github.com/intel-lab-lkp/linux/commits/Colton-Lewis/arm64-cpufeature-Add-cpucap-for-HPMN0/20251210-055309
base:   ac3fd01e4c1efce8f2c054cdeb2ddd2fc0fb150d
patch link:    https://lore.kernel.org/r/20251209205121.1871534-12-coltonlewis%40google.com
patch subject: [PATCH v5 11/24] KVM: arm64: Writethrough trapped PMEVTYPER register
config: arm64-randconfig-001-20251210 (https://download.01.org/0day-ci/archive/20251211/202512110209.GjVZa9ti-lkp at intel.com/config)
compiler: aarch64-linux-gcc (GCC) 14.3.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251211/202512110209.GjVZa9ti-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512110209.GjVZa9ti-lkp at intel.com/

All errors (new ones prefixed by >>):

   arch/arm64/kvm/sys_regs.c: In function 'writethrough_pmevtyper':
>> arch/arm64/kvm/sys_regs.c:1183:34: error: implicit declaration of function 'kvm_pmu_event_mask'; did you mean 'kvm_pmu_evtyper_mask'? [-Wimplicit-function-declaration]
    1183 |                 eventsel = val & kvm_pmu_event_mask(vcpu->kvm);
         |                                  ^~~~~~~~~~~~~~~~~~
         |                                  kvm_pmu_evtyper_mask


vim +1183 arch/arm64/kvm/sys_regs.c

  1168	
  1169	static bool writethrough_pmevtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
  1170					   u64 reg, u64 idx)
  1171	{
  1172		u64 eventsel;
  1173		u64 val = p->regval;
  1174		u64 evtyper_set = ARMV8_PMU_EXCLUDE_EL0 |
  1175			ARMV8_PMU_EXCLUDE_EL1;
  1176		u64 evtyper_clr = ARMV8_PMU_INCLUDE_EL2;
  1177	
  1178		__vcpu_assign_sys_reg(vcpu, reg, val);
  1179	
  1180		if (idx == ARMV8_PMU_CYCLE_IDX)
  1181			eventsel = ARMV8_PMUV3_PERFCTR_CPU_CYCLES;
  1182		else
> 1183			eventsel = val & kvm_pmu_event_mask(vcpu->kvm);
  1184	
  1185		if (vcpu->kvm->arch.pmu_filter &&
  1186		    !test_bit(eventsel, vcpu->kvm->arch.pmu_filter))
  1187			val |= evtyper_set;
  1188	
  1189		val &= ~evtyper_clr;
  1190	
  1191		if (idx == ARMV8_PMU_CYCLE_IDX)
  1192			write_pmccfiltr(val);
  1193		else
  1194			write_pmevtypern(idx, val);
  1195	
  1196		return true;
  1197	}
  1198	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From leo.yan at arm.com  Wed Dec 10 10:38:27 2025
From: leo.yan at arm.com (Leo Yan)
Date: Wed, 10 Dec 2025 18:38:27 +0000
Subject: [RFC PATCH v6 01/35] arm64/sysreg: Add new SPE fields
In-Reply-To: <20251114160717.163230-2-alexandru.elisei@arm.com>
References: <20251114160717.163230-1-alexandru.elisei@arm.com>
 <20251114160717.163230-2-alexandru.elisei@arm.com>
Message-ID: <20251210183827.GA3920451@e132581.arm.com>

On Fri, Nov 14, 2025 at 04:06:42PM +0000, Alexandru Elisei wrote:

[...]

>  Sysreg	PMBIDR_EL1	3	0	9	10	7
> -Res0	63:12
> +Res0	63:48
> +Field	47:32	MaxBuffSize
> +Res0	31:12
>  Enum	11:8	EA
>  	0b0000	NotDescribed
>  	0b0001	Ignored
>  	0b0010	SError
>  EndEnum
> -Res0	7:6
> +Enum	7:6	AddrMode
> +	0b00	VM_ONLY
> +	0b01	BOTH
> +	0b10	RESERVED
> +	0b11	nVM_ONLY
> +EndEnum

Not sure how to select the enum names, but seems names above don't match
well to the definitions.  How about:

  Enum  7:6     AddrMode
        0b00    VA_ONLY         // Virtual address only
        0b01    VA_PA           // Virtual and physical address supported
        0b10    RESERVED
        0b11    VM_PA_ONLY      // Physical address only in VM

Thanks,
Leo


From lkp at intel.com  Wed Dec 10 11:05:08 2025
From: lkp at intel.com (kernel test robot)
Date: Thu, 11 Dec 2025 03:05:08 +0800
Subject: [PATCH 6/8] nvmet: pci-epf: Use
 dmaengine_prep_slave_single_config() API
In-Reply-To: <20251208-dma_prep_config-v1-6-53490c5e1e2a@nxp.com>
References: <20251208-dma_prep_config-v1-6-53490c5e1e2a@nxp.com>
Message-ID: <202512110249.kCiMC4sb-lkp@intel.com>

Hi Frank,

kernel test robot noticed the following build warnings:

[auto build test WARNING on bc04acf4aeca588496124a6cf54bfce3db327039]

url:    https://github.com/intel-lab-lkp/linux/commits/Frank-Li/dmaengine-Add-API-to-combine-configuration-and-preparation-sg-and-single/20251209-011820
base:   bc04acf4aeca588496124a6cf54bfce3db327039
patch link:    https://lore.kernel.org/r/20251208-dma_prep_config-v1-6-53490c5e1e2a%40nxp.com
patch subject: [PATCH 6/8] nvmet: pci-epf: Use dmaengine_prep_slave_single_config() API
config: i386-allmodconfig (https://download.01.org/0day-ci/archive/20251211/202512110249.kCiMC4sb-lkp at intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251211/202512110249.kCiMC4sb-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512110249.kCiMC4sb-lkp at intel.com/

All warnings (new ones prefixed by >>):

   drivers/nvme/target/pci-epf.c: In function 'nvmet_pci_epf_dma_transfer':
>> drivers/nvme/target/pci-epf.c:369:23: warning: variable 'lock' set but not used [-Wunused-but-set-variable]
     369 |         struct mutex *lock;
         |                       ^~~~


vim +/lock +369 drivers/nvme/target/pci-epf.c

0faa0fe6f90ea5 Damien Le Moal 2025-01-04  357  
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  358  static int nvmet_pci_epf_dma_transfer(struct nvmet_pci_epf *nvme_epf,
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  359  		struct nvmet_pci_epf_segment *seg, enum dma_data_direction dir)
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  360  {
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  361  	struct pci_epf *epf = nvme_epf->epf;
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  362  	struct dma_async_tx_descriptor *desc;
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  363  	struct dma_slave_config sconf = {};
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  364  	struct device *dev = &epf->dev;
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  365  	struct device *dma_dev;
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  366  	struct dma_chan *chan;
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  367  	dma_cookie_t cookie;
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  368  	dma_addr_t dma_addr;
0faa0fe6f90ea5 Damien Le Moal 2025-01-04 @369  	struct mutex *lock;
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  370  	int ret;
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  371  
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  372  	switch (dir) {
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  373  	case DMA_FROM_DEVICE:
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  374  		lock = &nvme_epf->dma_rx_lock;
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  375  		chan = nvme_epf->dma_rx_chan;
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  376  		sconf.direction = DMA_DEV_TO_MEM;
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  377  		sconf.src_addr = seg->pci_addr;
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  378  		break;
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  379  	case DMA_TO_DEVICE:
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  380  		lock = &nvme_epf->dma_tx_lock;
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  381  		chan = nvme_epf->dma_tx_chan;
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  382  		sconf.direction = DMA_MEM_TO_DEV;
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  383  		sconf.dst_addr = seg->pci_addr;
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  384  		break;
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  385  	default:
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  386  		return -EINVAL;
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  387  	}
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  388  
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  389  	dma_dev = dmaengine_get_dma_device(chan);
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  390  	dma_addr = dma_map_single(dma_dev, seg->buf, seg->length, dir);
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  391  	ret = dma_mapping_error(dma_dev, dma_addr);
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  392  	if (ret)
f9f42a84df49d9 Frank Li       2025-12-08  393  		return ret;
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  394  
f9f42a84df49d9 Frank Li       2025-12-08  395  	desc = dmaengine_prep_slave_single_config(chan, dma_addr, seg->length,
f9f42a84df49d9 Frank Li       2025-12-08  396  						  sconf.direction,
f9f42a84df49d9 Frank Li       2025-12-08  397  						  DMA_CTRL_ACK,
f9f42a84df49d9 Frank Li       2025-12-08  398  						  &sconf);
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  399  	if (!desc) {
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  400  		dev_err(dev, "Failed to prepare DMA\n");
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  401  		ret = -EIO;
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  402  		goto unmap;
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  403  	}
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  404  
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  405  	cookie = dmaengine_submit(desc);
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  406  	ret = dma_submit_error(cookie);
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  407  	if (ret) {
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  408  		dev_err(dev, "Failed to do DMA submit (err=%d)\n", ret);
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  409  		goto unmap;
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  410  	}
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  411  
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  412  	if (dma_sync_wait(chan, cookie) != DMA_COMPLETE) {
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  413  		dev_err(dev, "DMA transfer failed\n");
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  414  		ret = -EIO;
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  415  	}
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  416  
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  417  unmap:
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  418  	dma_unmap_single(dma_dev, dma_addr, seg->length, dir);
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  419  
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  420  	return ret;
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  421  }
0faa0fe6f90ea5 Damien Le Moal 2025-01-04  422  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From nicolas.dufresne at collabora.com  Wed Dec 10 12:03:06 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Wed, 10 Dec 2025 15:03:06 -0500
Subject: [PATCH v3 01/15] media: uapi: HEVC: Add
 v4l2_ctrl_hevc_ext_sps_[ls]t_rps controls
In-Reply-To: <20251022162459.271603-2-detlev.casanova@collabora.com>
References: <20251022162459.271603-1-detlev.casanova@collabora.com>
	 <20251022162459.271603-2-detlev.casanova@collabora.com>
Message-ID: <a46d28aab764afcf3feab29df0fd1793bfe27c52.camel@collabora.com>

Hi,

Le mercredi 22 octobre 2025 ? 12:22 -0400, Detlev Casanova a ?crit?:
> Some hardware (e.g.: Rockchip's rk3588 hevc decoder) need the
> long and short term reference information for HEVC decoding.

That's seems a bit short and incomplete. My understanding is that the decoder on
this hardware needs to full parse the slice headers, and cannot be passed with
the slice information. It also does not implement a a skip method similar to
Hantro.

So in short, I think the justification for this API is that these parameters are
needed to fully parse HEVC slice headers. You should perhaps say that similar
paramters ares passed in Vulkan Video API ?

> 
> Add controls to provide it as the raw data form the stream.
> 
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
> ---
> ?.../media/v4l/ext-ctrls-codec-stateless.rst?? | 114 ++++++++++++++++++
> ?.../media/v4l/videodev2.h.rst.exceptions????? |?? 2 +
> ?.../media/v4l/vidioc-queryctrl.rst??????????? |? 12 ++
> ?3 files changed, 128 insertions(+)
> 
> diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst
> index 0da635691fdc..bb6772cf3cee 100644
> --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst
> +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst
> @@ -2958,6 +2958,120 @@ This structure contains all loop filter related parameters. See sections
> ?????? - 0x00000004
> ?????? -
> ?
> +``V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS (struct)``
> +??? Specifies the list of Long-Term reference sets parameters from the SPS.
> +??? These parameters are defined according to :ref:`hevc`.
> +??? They are described in section 7.4.3.2.1 "General sequence parameter set
> +??? RBSP semantics" of the specification.
> +??? This control is a dynamically sized 1-dimensional array,
> +??? V4L2_CTRL_FLAG_DYNAMIC_ARRAY flag must be set when using it.

Can we making a bit clearer that this is a subset of the SPS (perhaps use the
term subset). And this is user to extend another control (mention this other
control) ?

> +
> +.. c:type:: v4l2_ctrl_hevc_ext_sps_lt_rps
> +
> +.. cssclass:: longtable
> +
> +.. flat-table:: struct v4l2_ctrl_hevc_ext_sps_lt_rps
> +??? :header-rows:? 0
> +??? :stub-columns: 0
> +??? :widths:?????? 1 1 2
> +
> +??? * - __u16
> +????? - ``lt_ref_pic_poc_lsb_sps``
> +????? - Long term reference picture order count as described in section 7.4.3.2.1
> +??????? "General sequence parameter set RBSP semantics" of the specification.
> +??? * - __u8
> +????? - ``flags``
> +????? - See :ref:`Extended Long-Term RPS Flags <hevc_ext_sps_lt_rps_flags>`
> +
> +.. _hevc_ext_sps_lt_rps_flags:
> +
> +``Extended SPS Long-Term RPS Flags``
> +
> +.. cssclass:: longtable
> +
> +.. flat-table::
> +??? :header-rows:? 0
> +??? :stub-columns: 0
> +??? :widths:?????? 1 1 2
> +
> +??? * - ``V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_USED_LT``
> +????? - 0x00000001
> +????? - Specifies if the long-term reference picture is used 7.4.3.2.1 "General sequence parameter
> +??????? set RBSP semantics" of the specification.
> +
> +``V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS (struct)``
> +??? Specifies the list of Short-Term reference sets parameters from the SPS.
> +??? These parameters are defined according to :ref:`hevc`.
> +??? They are described in section 7.4.8 "Short-term reference picture set
> +??? semantics" of the specification.
> +??? This control is a dynamically sized 1-dimensional array,
> +??? V4L2_CTRL_FLAG_DYNAMIC_ARRAY flag must be set when using it.

D?j? vue, this is a duplicate right ?

> +
> +.. c:type:: v4l2_ctrl_hevc_ext_sps_st_rps
> +
> +.. cssclass:: longtable
> +
> +.. flat-table:: struct v4l2_ctrl_hevc_ext_sps_st_rps
> +??? :header-rows:? 0
> +??? :stub-columns: 0
> +??? :widths:?????? 1 1 2
> +
> +??? * - __u8
> +????? - ``delta_idx_minus1``
> +????? - Specifies the delta compare to the index. See details in section 7.4.8 "Short-term
> +??????? reference picture set semantics" of the specification.
> +??? * - __u8
> +????? - ``delta_rps_sign``
> +????? - Sign of the delta as specified in section 7.4.8 "Short-term reference picture set
> +??????? semantics" of the specification.
> +??? * - __u16
> +????? - ``abs_delta_rps_minus1``
> +????? - Absolute delta RPS as specified in section 7.4.8 "Short-term reference picture set
> +??????? semantics" of the specification.
> +??? * - __u8
> +????? - ``num_negative_pics``
> +????? - Number of short-term RPS entries that have picture order count values less than the
> +??????? picture order count value of the current picture.
> +??? * - __u8
> +????? - ``num_positive_pics``
> +????? - Number of short-term RPS entries that have picture order count values greater than the
> +??????? picture order count value of the current picture.
> +??? * - __u32
> +????? - ``used_by_curr_pic``
> +????? - Bit i specifies if short-term RPS i is used by the current picture.
> +??? * - __u32
> +????? - ``use_delta_flag``
> +????? - Bit i specifies if short-term RPS i is included in the short-term RPS entries.
> +??? * - __u16
> +????? - ``delta_poc_s0_minus1[16]``
> +????? - Specifies the negative picture order count delta for the i-th entry in the short-term RPS.
> +??????? See details in section 7.4.8 "Short-term reference picture set semantics" of the
> +??????? specification.
> +??? * - __u16
> +????? - ``delta_poc_s1_minus1[16]``
> +????? - Specifies the positive picture order count delta for the i-th entry in the short-term RPS.
> +??????? See details in section 7.4.8 "Short-term reference picture set semantics" of the
> +??????? specification.
> +??? * - __u8
> +????? - ``flags``
> +????? - See :ref:`Extended Short-Term RPS Flags <hevc_ext_sps_st_rps_flags>`
> +
> +.. _hevc_ext_sps_st_rps_flags:
> +
> +``Extended SPS Short-Term RPS Flags``
> +
> +.. cssclass:: longtable
> +
> +.. flat-table::
> +??? :header-rows:? 0
> +??? :stub-columns: 0
> +??? :widths:?????? 1 1 2
> +
> +??? * - ``V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED``
> +????? - 0x00000001
> +????? - Specifies if the short-term RPS is predicted from another short term RPS. See details in
> +??????? section 7.4.8 "Short-term reference picture set semantics" of the specification.
> +
> ?.. _v4l2-codec-stateless-av1:
> ?
> ?``V4L2_CID_STATELESS_AV1_SEQUENCE (struct)``
> diff --git a/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions b/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions
> index 35d3456cc812..1663fdf8444c 100644
> --- a/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions
> +++ b/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions
> @@ -149,6 +149,8 @@ replace symbol V4L2_CTRL_TYPE_H264_DECODE_PARAMS :c:type:`v4l2_ctrl_type`
> ?replace symbol V4L2_CTRL_TYPE_HEVC_SPS :c:type:`v4l2_ctrl_type`
> ?replace symbol V4L2_CTRL_TYPE_HEVC_PPS :c:type:`v4l2_ctrl_type`
> ?replace symbol V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS :c:type:`v4l2_ctrl_type`
> +replace symbol V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS :c:type:`v4l2_ctrl_type`
> +replace symbol V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS :c:type:`v4l2_ctrl_type`
> ?replace symbol V4L2_CTRL_TYPE_AREA :c:type:`v4l2_ctrl_type`
> ?replace symbol V4L2_CTRL_TYPE_RECT :c:type:`v4l2_ctrl_type`
> ?replace symbol V4L2_CTRL_TYPE_FWHT_PARAMS :c:type:`v4l2_ctrl_type`
> diff --git a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
> index 3549417c7feb..128c044d2e3c 100644
> --- a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
> +++ b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
> @@ -523,6 +523,18 @@ See also the examples in :ref:`control`.
> ?????? - n/a
> ?????? - A struct :c:type:`v4l2_ctrl_hevc_decode_params`, containing HEVC
> ?	decoding parameters for stateless video decoders.
> +??? * - ``V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS``
> +????? - n/a
> +????? - n/a
> +????? - n/a
> +????? - A struct :c:type:`v4l2_ctrl_hevc_ext_sps_lt_rps`, containing HEVC
> +	extended Long-Term RPS for stateless video decoders.
> +??? * - ``V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS``
> +????? - n/a
> +????? - n/a
> +????? - n/a
> +????? - A struct :c:type:`v4l2_ctrl_hevc_ext_sps_st_rps`, containing HEVC
> +	extended Short-Term RPS for stateless video decoders.
> ???? * - ``V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR``
> ?????? - n/a
> ?????? - n/a

cheers,
Nicolas
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251210/34d627eb/attachment.sig>

From nicolas.dufresne at collabora.com  Wed Dec 10 12:07:03 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Wed, 10 Dec 2025 15:07:03 -0500
Subject: [PATCH v3 02/15] media: v4l2-ctrls: Add hevc_ext_sps_[ls]t_rps
 controls
In-Reply-To: <20251022162459.271603-3-detlev.casanova@collabora.com>
References: <20251022162459.271603-1-detlev.casanova@collabora.com>
	 <20251022162459.271603-3-detlev.casanova@collabora.com>
Message-ID: <3ff3c7f76e24fdc92d86be3f92b6947ef86abc25.camel@collabora.com>

Hi,

Le mercredi 22 octobre 2025 ? 12:22 -0400, Detlev Casanova a ?crit?:
> The vdpu381 decoder found on newer Rockchip SoC need the information
> from the long term and short term ref pic sets from the SPS.
> 
> So far, it wasn't included in the v4l2 API, so add it with new dynamic
> sized controls.
> 
> Each element of the hevc_ext_sps_lt_rps array contains the long term ref
> pic set at that index.
> Each element of the hevc_ext_sps_st_rps contains the short term ref pic
> set at that index, as the raw data.
> It is the role of the drivers to calculate the reference sets values.
> 
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
> ---
> ?drivers/media/v4l2-core/v4l2-ctrls-core.c | 18 +++++++
> ?drivers/media/v4l2-core/v4l2-ctrls-defs.c | 10 ++++
> ?include/uapi/linux/v4l2-controls.h??????? | 61 +++++++++++++++++++++++
> ?include/uapi/linux/videodev2.h??????????? |? 2 +
> ?4 files changed, 91 insertions(+)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c
> index 85d07ef44f62..779936727505 100644
> --- a/drivers/media/v4l2-core/v4l2-ctrls-core.c
> +++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c
> @@ -418,6 +418,12 @@ void v4l2_ctrl_type_op_log(const struct v4l2_ctrl *ctrl)
> ?	case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
> ?		pr_cont("HEVC_SLICE_PARAMS");
> ?		break;
> +	case V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS:
> +		pr_cont("HEVC_EXT_SPS_ST_RPS");
> +		break;
> +	case V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS:
> +		pr_cont("HEVC_EXT_SPS_LT_RPS");
> +		break;
> ?	case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX:
> ?		pr_cont("HEVC_SCALING_MATRIX");
> ?		break;
> @@ -1173,6 +1179,12 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
> ?	case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
> ?		break;
> ?
> +	case V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS:
> +		break;
> +
> +	case V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS:
> +		break;
> +
> ?	case V4L2_CTRL_TYPE_HDR10_CLL_INFO:
> ?		break;
> ?
> @@ -1925,6 +1937,12 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
> ?	case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
> ?		elem_size = sizeof(struct v4l2_ctrl_hevc_slice_params);
> ?		break;
> +	case V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS:
> +		elem_size = sizeof(struct v4l2_ctrl_hevc_ext_sps_st_rps);
> +		break;
> +	case V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS:
> +		elem_size = sizeof(struct v4l2_ctrl_hevc_ext_sps_lt_rps);
> +		break;
> ?	case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX:
> ?		elem_size = sizeof(struct v4l2_ctrl_hevc_scaling_matrix);
> ?		break;
> diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
> index ad41f65374e2..167286c9e424 100644
> --- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c
> +++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
> @@ -1233,6 +1233,8 @@ const char *v4l2_ctrl_get_name(u32 id)
> ?	case V4L2_CID_STATELESS_HEVC_DECODE_MODE:		return "HEVC Decode Mode";
> ?	case V4L2_CID_STATELESS_HEVC_START_CODE:		return "HEVC Start Code";
> ?	case V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS:	return "HEVC Entry Point Offsets";
> +	case V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS:		return "HEVC Short Term Ref Sets";
> +	case V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS:		return "HEVC Long Term Ref Sets";
> ?	case V4L2_CID_STATELESS_AV1_SEQUENCE:			return "AV1 Sequence Parameters";
> ?	case V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY:		return "AV1 Tile Group Entry";
> ?	case V4L2_CID_STATELESS_AV1_FRAME:			return "AV1 Frame Parameters";
> @@ -1578,6 +1580,14 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
> ?		*type = V4L2_CTRL_TYPE_U32;
> ?		*flags |= V4L2_CTRL_FLAG_DYNAMIC_ARRAY;
> ?		break;
> +	case V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS:
> +		*type = V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS;
> +		*flags |= V4L2_CTRL_FLAG_DYNAMIC_ARRAY;
> +		break;
> +	case V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS:
> +		*type = V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS;
> +		*flags |= V4L2_CTRL_FLAG_DYNAMIC_ARRAY;
> +		break;
> ?	case V4L2_CID_STATELESS_VP9_COMPRESSED_HDR:
> ?		*type = V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR;
> ?		break;
> diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
> index 2d30107e047e..dd9e29afa155 100644
> --- a/include/uapi/linux/v4l2-controls.h
> +++ b/include/uapi/linux/v4l2-controls.h
> @@ -2093,6 +2093,8 @@ struct v4l2_ctrl_mpeg2_quantisation {
> ?#define V4L2_CID_STATELESS_HEVC_DECODE_MODE	(V4L2_CID_CODEC_STATELESS_BASE + 405)
> ?#define V4L2_CID_STATELESS_HEVC_START_CODE	(V4L2_CID_CODEC_STATELESS_BASE + 406)
> ?#define V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS (V4L2_CID_CODEC_STATELESS_BASE + 407)
> +#define V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS? (V4L2_CID_CODEC_STATELESS_BASE + 408)
> +#define V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS? (V4L2_CID_CODEC_STATELESS_BASE + 409)
> ?
> ?enum v4l2_stateless_hevc_decode_mode {
> ?	V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED,
> @@ -2548,6 +2550,65 @@ struct v4l2_ctrl_hevc_scaling_matrix {
> ?	__u8	scaling_list_dc_coef_32x32[2];
> ?};
> ?
> +#define V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED	0x1
> +
> +/*
> + * struct v4l2_ctrl_hevc_ext_sps_st_rps - HEVC short term RPS parameters
> + *
> + * Dynamic size 1-dimension array for short term RPS. The number of elements
> + * is v4l2_ctrl_hevc_sps::num_short_term_ref_pic_sets. It can contain up to 65 elements.
> + *
> + * @delta_idx_minus1: Specifies the delta compare to the index. See details in section 7.4.8
> + *??????????????????? "Short-term reference picture set semantics" of the specification.
> + * @delta_rps_sign: Sign of the delta as specified in section 7.4.8 "Short-term reference picture
> + *????????????????? set semantics" of the specification.
> + * @abs_delta_rps_minus1: Absolute delta RPS as specified in section 7.4.8 "Short-term reference
> + *??????????????????????? picture set semantics" of the specification.
> + * @num_negative_pics: Number of short-term RPS entries that have picture order count values less
> + *???????????????????? than the picture order count value of the current picture.
> + * @num_positive_pics: Number of short-term RPS entries that have picture order count values
> + *???????????????????? greater than the picture order count value of the current picture.
> + * @used_by_curr_pic: Bit j specifies if short-term RPS j is used by the current picture.
> + * @use_delta_flag: Bit j equals to 1 specifies that the j-th entry in the source candidate
> + *????????????????? short-term RPS is included in this candidate short-term RPS.
> + * @delta_poc_s0_minus1: Specifies the negative picture order count delta for the i-th entry in
> + *?????????????????????? the short-term RPS. See details in section 7.4.8 "Short-term reference
> + *?????????????????????? picture set semantics" of the specification.
> + * @delta_poc_s1_minus1: Specifies the positive picture order count delta for the i-th entry in
> + *?????????????????????? the short-term RPS. See details in section 7.4.8 "Short-term reference
> + *?????????????????????? picture set semantics" of the specification.
> + * @flags: See V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_{}
> + */
> +struct v4l2_ctrl_hevc_ext_sps_st_rps {
> +	__u8	delta_idx_minus1;
> +	__u8	delta_rps_sign;
> +	__u16	abs_delta_rps_minus1;
> +	__u8	num_negative_pics;
> +	__u8	num_positive_pics;
> +	__u32	used_by_curr_pic;

Did you run pahole ? This one does not seem to align, it starts with 16bit
offset. The remark is because 32bit and 64bit platform, and all compiler should
have the same binary representation, otherwise it will break in some ways.

regards,
Nicolas

> +	__u32	use_delta_flag;
> +	__u16	delta_poc_s0_minus1[16];
> +	__u16	delta_poc_s1_minus1[16];
> +	__u8	flags;
> +};
> +
> +#define V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_USED_LT		0x1
> +
> +/*
> + * struct v4l2_ctrl_hevc_ext_sps_lt_rps - HEVC long term RPS parameters
> + *
> + * Dynamic size 1-dimension array for long term RPS. The number of elements
> + * is v4l2_ctrl_hevc_sps::num_long_term_ref_pics_sps. It can contain up to 65 elements.
> + *
> + * @lt_ref_pic_poc_lsb_sps: picture order count modulo MaxPicOrderCntLsb of the i-th candidate
> + *????????????????????????? long-term reference picture.
> + * @flags: See V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_{}
> + */
> +struct v4l2_ctrl_hevc_ext_sps_lt_rps {
> +	__u16	lt_ref_pic_poc_lsb_sps;
> +	__u8	flags;
> +};
> +
> ?/* Stateless VP9 controls */
> ?
> ?#define V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED	0x1
> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
> index becd08fdbddb..ae1d33fd37b7 100644
> --- a/include/uapi/linux/videodev2.h
> +++ b/include/uapi/linux/videodev2.h
> @@ -1981,6 +1981,8 @@ enum v4l2_ctrl_type {
> ?	V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS	= 0x0272,
> ?	V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX	= 0x0273,
> ?	V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS	= 0x0274,
> +	V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS	= 0x0275,
> +	V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS	= 0x0276,
> ?
> ?	V4L2_CTRL_TYPE_AV1_SEQUENCE	??? = 0x280,
> ?	V4L2_CTRL_TYPE_AV1_TILE_GROUP_ENTRY = 0x281,
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251210/f0d00d0a/attachment-0001.sig>

From nicolas.dufresne at collabora.com  Wed Dec 10 12:11:47 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Wed, 10 Dec 2025 15:11:47 -0500
Subject: [PATCH v3 03/15] media: rkvdec: Switch to using structs instead
 of writel
In-Reply-To: <20251022162459.271603-4-detlev.casanova@collabora.com>
References: <20251022162459.271603-1-detlev.casanova@collabora.com>
	 <20251022162459.271603-4-detlev.casanova@collabora.com>
Message-ID: <0f155ec75f54dfc5a129ce31cd72ee8c16b301fa.camel@collabora.com>

Hi,

Le mercredi 22 octobre 2025 ? 12:22 -0400, Detlev Casanova a ?crit?:
> In an effort to merge the rkvdec2 driver [1] with this one, switch from
> writel() calls to using structs to represent the register mappings.
> 
> This is done in order to have all supported decoders use the same format
> in the future and ease reading of the code.
> 
> Using structs also improves stability as the hardware is tested and
> validated downstream using a similar method.
> It was noticed, on decoders, that:
> ?- Some registers require to be writen in increasing order [2]
> ?- Some registers, even if unrelated, need to be written to their reset
> ?? values (it was the case here for axi_ddr_[rw]data).
> 
> Using structs can also help improving performance later when, e.g.
> multicore support is added on RK3588.
> 
> Performance seems to be slightly improved, but at least, not made worse.
> Running fluster's JVT-AVC_V1 test suite with GStreamer on the Radxa ROCK
> PI 4 SE gives the following times:
> 
> Before this patch:
> 
> - --jobs 1: Ran 129/135 tests successfully?????????????? in 77.167 secs
> - --jobs 6: Ran 129/135 tests successfully?????????????? in 23.046 secs
> 
> With this patch:
> - --jobs 1: Ran 129/135 tests successfully?????????????? in 70.698 secs
> - --jobs 6: Ran 129/135 tests successfully?????????????? in 22.917 secs
> 
> This also shows that the fluster score hasn't changed.
> 
> [1]: https://lore.kernel.org/all/20250325213303.826925-1-detlev.casanova at collabora.com/
> [2]: https://lore.kernel.org/all/20200127143009.15677-5-andrzej.p at collabora.com/
> 
> Tested-by: Diederik de Haas <didi.debian at cknow.org>? # Rock 5B
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?.../platform/rockchip/rkvdec/rkvdec-h264.c??? | 165 +++--
> ?.../platform/rockchip/rkvdec/rkvdec-hevc.c??? |? 63 +-
> ?.../platform/rockchip/rkvdec/rkvdec-regs.h??? | 571 ++++++++++++------
> ?.../platform/rockchip/rkvdec/rkvdec-vp9.c???? | 231 +++----
> ?.../media/platform/rockchip/rkvdec/rkvdec.c?? |? 10 +-
> ?.../media/platform/rockchip/rkvdec/rkvdec.h?? |?? 1 +
> ?6 files changed, 587 insertions(+), 454 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
> index d14b4d173448..116e7b1076b7 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
> @@ -115,6 +115,7 @@ struct rkvdec_h264_run {
> ?struct rkvdec_h264_ctx {
> ?	struct rkvdec_aux_buf priv_tbl;
> ?	struct rkvdec_h264_reflists reflists;
> +	struct rkvdec_regs regs;
> ?};
> ?
> ?#define CABAC_ENTRY(ctxidx, idc0_m, idc0_n, idc1_m, idc1_n,		\
> @@ -841,45 +842,41 @@ static void assemble_hw_scaling_list(struct rkvdec_ctx *ctx,
> ?}
> ?
> ?/*
> - * dpb poc related registers table
> + * Set the ref POC in the correct register.
> + *
> + * The 32 registers are spread across 3 regions, each alternating top and bottom ref POCs:
> + *? - 1: ref 0 to 14 contain top 0 to 7 and bottoms 0 to 6
> + *? - 2: ref 15 to 29 contain top 8 to 14 and bottoms 7 to 14
> + *? - 3: ref 30 and 31 which correspond to top 15 and bottom 15 respectively.
> ? */
> -static const u32 poc_reg_tbl_top_field[16] = {
> -	RKVDEC_REG_H264_POC_REFER0(0),
> -	RKVDEC_REG_H264_POC_REFER0(2),
> -	RKVDEC_REG_H264_POC_REFER0(4),
> -	RKVDEC_REG_H264_POC_REFER0(6),
> -	RKVDEC_REG_H264_POC_REFER0(8),
> -	RKVDEC_REG_H264_POC_REFER0(10),
> -	RKVDEC_REG_H264_POC_REFER0(12),
> -	RKVDEC_REG_H264_POC_REFER0(14),
> -	RKVDEC_REG_H264_POC_REFER1(1),
> -	RKVDEC_REG_H264_POC_REFER1(3),
> -	RKVDEC_REG_H264_POC_REFER1(5),
> -	RKVDEC_REG_H264_POC_REFER1(7),
> -	RKVDEC_REG_H264_POC_REFER1(9),
> -	RKVDEC_REG_H264_POC_REFER1(11),
> -	RKVDEC_REG_H264_POC_REFER1(13),
> -	RKVDEC_REG_H264_POC_REFER2(0)
> -};
> -
> -static const u32 poc_reg_tbl_bottom_field[16] = {
> -	RKVDEC_REG_H264_POC_REFER0(1),
> -	RKVDEC_REG_H264_POC_REFER0(3),
> -	RKVDEC_REG_H264_POC_REFER0(5),
> -	RKVDEC_REG_H264_POC_REFER0(7),
> -	RKVDEC_REG_H264_POC_REFER0(9),
> -	RKVDEC_REG_H264_POC_REFER0(11),
> -	RKVDEC_REG_H264_POC_REFER0(13),
> -	RKVDEC_REG_H264_POC_REFER1(0),
> -	RKVDEC_REG_H264_POC_REFER1(2),
> -	RKVDEC_REG_H264_POC_REFER1(4),
> -	RKVDEC_REG_H264_POC_REFER1(6),
> -	RKVDEC_REG_H264_POC_REFER1(8),
> -	RKVDEC_REG_H264_POC_REFER1(10),
> -	RKVDEC_REG_H264_POC_REFER1(12),
> -	RKVDEC_REG_H264_POC_REFER1(14),
> -	RKVDEC_REG_H264_POC_REFER2(1)
> -};
> +static void set_poc_reg(struct rkvdec_regs *regs, uint32_t poc, int id, bool bottom)
> +{
> +	if (!bottom) {
> +		switch (id) {
> +		case 0 ... 7:
> +			regs->h26x.ref0_14_poc[id * 2] = poc;
> +			break;
> +		case 8 ... 14:
> +			regs->h26x.ref15_29_poc[(id - 8) * 2 + 1] = poc;
> +			break;
> +		case 15:
> +			regs->h26x.ref30_poc = poc;
> +			break;
> +		}
> +	} else {
> +		switch (id) {
> +		case 0 ... 6:
> +			regs->h26x.ref0_14_poc[id * 2 + 1] = poc;
> +			break;
> +		case 7 ... 14:
> +			regs->h26x.ref15_29_poc[(id - 7) * 2] = poc;
> +			break;
> +		case 15:
> +			regs->h26x.ref31_poc = poc;
> +			break;
> +		}
> +	}
> +}
> ?
> ?static void config_registers(struct rkvdec_ctx *ctx,
> ?			???? struct rkvdec_h264_run *run)
> @@ -894,6 +891,7 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?	struct vb2_v4l2_buffer *src_buf = run->base.bufs.src;
> ?	struct vb2_v4l2_buffer *dst_buf = run->base.bufs.dst;
> ?	const struct v4l2_format *f;
> +	struct rkvdec_regs *regs = &h264_ctx->regs;
> ?	dma_addr_t rlc_addr;
> ?	dma_addr_t refer_addr;
> ?	u32 rlc_len;
> @@ -903,10 +901,11 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?	u32 yuv_virstride = 0;
> ?	u32 offset;
> ?	dma_addr_t dst_addr;
> -	u32 reg, i;
> +	u32 i;
> ?
> -	reg = RKVDEC_MODE(RKVDEC_MODE_H264);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_SYSCTRL);
> +	memset(regs, 0, sizeof(*regs));
> +
> +	regs->common.reg02.dec_mode = RKVDEC_MODE_H264;
> ?
> ?	f = &ctx->decoded_fmt;
> ?	dst_fmt = &f->fmt.pix_mp;
> @@ -921,39 +920,35 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?	else if (sps->chroma_format_idc == 2)
> ?		yuv_virstride = 2 * y_virstride;
> ?
> -	reg = RKVDEC_Y_HOR_VIRSTRIDE(hor_virstride / 16) |
> -	????? RKVDEC_UV_HOR_VIRSTRIDE(hor_virstride / 16) |
> -	????? RKVDEC_SLICE_NUM_HIGHBIT |
> -	????? RKVDEC_SLICE_NUM_LOWBITS(0x7ff);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_PICPAR);
> +	regs->common.reg03.uv_hor_virstride = hor_virstride / 16;
> +	regs->common.reg03.y_hor_virstride = hor_virstride / 16;
> +	regs->common.reg03.slice_num_highbit = 1;
> +	regs->common.reg03.slice_num_lowbits = 0x7ff;
> ?
> ?	/* config rlc base address */
> ?	rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
> -	writel_relaxed(rlc_addr, rkvdec->regs + RKVDEC_REG_STRM_RLC_BASE);
> -	writel_relaxed(rlc_addr, rkvdec->regs + RKVDEC_REG_RLCWRITE_BASE);
> +	regs->common.strm_rlc_base = rlc_addr;
> +	regs->h26x.rlcwrite_base = rlc_addr;
> ?
> ?	rlc_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
> -	reg = RKVDEC_STRM_LEN(rlc_len);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_STRM_LEN);
> +	regs->common.stream_len = rlc_len;
> ?
> ?	/* config cabac table */
> ?	offset = offsetof(struct rkvdec_h264_priv_tbl, cabac_table);
> -	writel_relaxed(priv_start_addr + offset,
> -		?????? rkvdec->regs + RKVDEC_REG_CABACTBL_PROB_BASE);
> +	regs->common.cabactbl_base = priv_start_addr + offset;
> ?
> ?	/* config output base address */
> ?	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
> -	writel_relaxed(dst_addr, rkvdec->regs + RKVDEC_REG_DECOUT_BASE);
> +	regs->common.decout_base = dst_addr;
> ?
> -	reg = RKVDEC_Y_VIRSTRIDE(y_virstride / 16);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_Y_VIRSTRIDE);
> +	regs->common.reg08.y_virstride = y_virstride / 16;
> ?
> -	reg = RKVDEC_YUV_VIRSTRIDE(yuv_virstride / 16);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_YUV_VIRSTRIDE);
> +	regs->common.reg09.yuv_virstride = yuv_virstride / 16;
> ?
> ?	/* config ref pic address & poc */
> ?	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
> ?		struct vb2_buffer *vb_buf = run->ref_buf[i];
> +		struct ref_base *base;
> ?
> ?		/*
> ?		 * If a DPB entry is unused or invalid, address of current destination
> @@ -963,54 +958,36 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?			vb_buf = &dst_buf->vb2_buf;
> ?		refer_addr = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
> ?
> -		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)
> -			refer_addr |= RKVDEC_COLMV_USED_FLAG_REF;
> -		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD)
> -			refer_addr |= RKVDEC_FIELD_REF;
> -
> -		if (dpb[i].fields & V4L2_H264_TOP_FIELD_REF)
> -			refer_addr |= RKVDEC_TOPFIELD_USED_REF;
> -		if (dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF)
> -			refer_addr |= RKVDEC_BOTFIELD_USED_REF;
> -
> -		writel_relaxed(dpb[i].top_field_order_cnt,
> -			?????? rkvdec->regs +? poc_reg_tbl_top_field[i]);
> -		writel_relaxed(dpb[i].bottom_field_order_cnt,
> -			?????? rkvdec->regs + poc_reg_tbl_bottom_field[i]);
> -
> ?		if (i < V4L2_H264_NUM_DPB_ENTRIES - 1)
> -			writel_relaxed(refer_addr,
> -				?????? rkvdec->regs + RKVDEC_REG_H264_BASE_REFER(i));
> +			base = &regs->h26x.ref0_14_base[i];
> ?		else
> -			writel_relaxed(refer_addr,
> -				?????? rkvdec->regs + RKVDEC_REG_H264_BASE_REFER15);
> -	}
> +			base = &regs->h26x.ref15_base;
> ?
> -	reg = RKVDEC_CUR_POC(dec_params->top_field_order_cnt);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC0);
> +		base->field_ref = !!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD);
> +		base->colmv_used_flag_ref = !!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE);
> +		base->topfield_used_ref = !!(dpb[i].fields & V4L2_H264_TOP_FIELD_REF);
> +		base->botfield_used_ref = !!(dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF);
> +		base->base_addr = refer_addr >> 4;
> ?
> -	reg = RKVDEC_CUR_POC(dec_params->bottom_field_order_cnt);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC1);
> +		set_poc_reg(regs, dpb[i].top_field_order_cnt, i, false);
> +		set_poc_reg(regs, dpb[i].bottom_field_order_cnt, i, true);
> +	}
> +
> +	regs->h26x.cur_poc = dec_params->top_field_order_cnt;
> +	regs->h26x.cur_poc1 = dec_params->bottom_field_order_cnt;
> ?
> ?	/* config hw pps address */
> ?	offset = offsetof(struct rkvdec_h264_priv_tbl, param_set);
> -	writel_relaxed(priv_start_addr + offset,
> -		?????? rkvdec->regs + RKVDEC_REG_PPS_BASE);
> +	regs->h26x.pps_base = priv_start_addr + offset;
> ?
> ?	/* config hw rps address */
> ?	offset = offsetof(struct rkvdec_h264_priv_tbl, rps);
> -	writel_relaxed(priv_start_addr + offset,
> -		?????? rkvdec->regs + RKVDEC_REG_RPS_BASE);
> -
> -	reg = RKVDEC_AXI_DDR_RDATA(0);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_RDATA);
> -
> -	reg = RKVDEC_AXI_DDR_WDATA(0);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_WDATA);
> +	regs->h26x.rps_base = priv_start_addr + offset;
> ?
> ?	offset = offsetof(struct rkvdec_h264_priv_tbl, err_info);
> -	writel_relaxed(priv_start_addr + offset,
> -		?????? rkvdec->regs + RKVDEC_REG_H264_ERRINFO_BASE);
> +	regs->h26x.errorinfo_base = priv_start_addr + offset;
> +
> +	rkvdec_memcpy_toio(rkvdec->regs, regs, MIN(sizeof(*regs), 4 * rkvdec->variant->num_regs));
> ?}
> ?
> ?#define RKVDEC_H264_MAX_DEPTH_IN_BYTES		2
> @@ -1181,8 +1158,6 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
> ?
> ?	schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000));
> ?
> -	writel(0, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN);
> -	writel(0, rkvdec->regs + RKVDEC_REG_H264_ERR_E);
> ?	writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND);
> ?	writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);
> ?
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
> index fc7e6a260b0a..01f92fa27356 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
> @@ -129,6 +129,7 @@ struct rkvdec_hevc_run {
> ?struct rkvdec_hevc_ctx {
> ?	struct rkvdec_aux_buf priv_tbl;
> ?	struct v4l2_ctrl_hevc_scaling_matrix scaling_matrix_cache;
> +	struct rkvdec_regs regs;
> ?};
> ?
> ?struct scaling_factor {
> @@ -548,6 +549,7 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?	const struct v4l2_ctrl_hevc_slice_params *sl_params = &run->slices_params[0];
> ?	const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb;
> ?	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
> +	struct rkvdec_regs *regs = &hevc_ctx->regs;
> ?	dma_addr_t priv_start_addr = hevc_ctx->priv_tbl.dma;
> ?	const struct v4l2_pix_format_mplane *dst_fmt;
> ?	struct vb2_v4l2_buffer *src_buf = run->base.bufs.src;
> @@ -564,8 +566,9 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?	dma_addr_t dst_addr;
> ?	u32 reg, i;
> ?
> -	reg = RKVDEC_MODE(RKVDEC_MODE_HEVC);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_SYSCTRL);
> +	memset(regs, 0, sizeof(*regs));
> +
> +	regs->common.reg02.dec_mode = RKVDEC_MODE_HEVC;
> ?
> ?	f = &ctx->decoded_fmt;
> ?	dst_fmt = &f->fmt.pix_mp;
> @@ -580,33 +583,27 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?	else if (sps->chroma_format_idc == 2)
> ?		yuv_virstride = 2 * y_virstride;
> ?
> -	reg = RKVDEC_Y_HOR_VIRSTRIDE(hor_virstride / 16) |
> -	????? RKVDEC_UV_HOR_VIRSTRIDE(hor_virstride / 16) |
> -	????? RKVDEC_SLICE_NUM_LOWBITS(run->num_slices);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_PICPAR);
> +	regs->common.reg03.slice_num_lowbits = run->num_slices;
> +	regs->common.reg03.uv_hor_virstride = hor_virstride / 16;
> +	regs->common.reg03.y_hor_virstride = hor_virstride / 16;
> ?
> ?	/* config rlc base address */
> ?	rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
> -	writel_relaxed(rlc_addr, rkvdec->regs + RKVDEC_REG_STRM_RLC_BASE);
> +	regs->common.strm_rlc_base = rlc_addr;
> ?
> ?	rlc_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
> -	reg = RKVDEC_STRM_LEN(round_up(rlc_len, 16) + 64);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_STRM_LEN);
> +	regs->common.stream_len = round_up(rlc_len, 16) + 64;
> ?
> ?	/* config cabac table */
> ?	offset = offsetof(struct rkvdec_hevc_priv_tbl, cabac_table);
> -	writel_relaxed(priv_start_addr + offset,
> -		?????? rkvdec->regs + RKVDEC_REG_CABACTBL_PROB_BASE);
> +	regs->common.cabactbl_base = priv_start_addr + offset;
> ?
> ?	/* config output base address */
> ?	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
> -	writel_relaxed(dst_addr, rkvdec->regs + RKVDEC_REG_DECOUT_BASE);
> -
> -	reg = RKVDEC_Y_VIRSTRIDE(y_virstride / 16);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_Y_VIRSTRIDE);
> +	regs->common.decout_base = dst_addr;
> ?
> -	reg = RKVDEC_YUV_VIRSTRIDE(yuv_virstride / 16);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_YUV_VIRSTRIDE);
> +	regs->common.reg08.y_virstride = y_virstride / 16;
> +	regs->common.reg09.yuv_virstride = yuv_virstride / 16;
> ?
> ?	/* config ref pic address */
> ?	for (i = 0; i < 15; i++) {
> @@ -620,33 +617,29 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?		}
> ?
> ?		refer_addr = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
> -		writel_relaxed(refer_addr | reg,
> -			?????? rkvdec->regs + RKVDEC_REG_H264_BASE_REFER(i));
> ?
> -		reg = RKVDEC_POC_REFER(i < decode_params->num_active_dpb_entries ?
> -			dpb[i].pic_order_cnt_val : 0);
> -		writel_relaxed(reg,
> -			?????? rkvdec->regs + RKVDEC_REG_H264_POC_REFER0(i));
> +		regs->h26x.ref0_14_base[i].base_addr = refer_addr >> 4;
> +		regs->h26x.ref0_14_base[i].field_ref = !!(reg & 1);
> +		regs->h26x.ref0_14_base[i].topfield_used_ref = !!(reg & 2);
> +		regs->h26x.ref0_14_base[i].botfield_used_ref = !!(reg & 4);
> +		regs->h26x.ref0_14_base[i].colmv_used_flag_ref = !!(reg & 8);
> +
> +		regs->h26x.ref0_14_poc[i] = i < decode_params->num_active_dpb_entries
> +					??? ? dpb[i].pic_order_cnt_val
> +					??? : 0;
> ?	}
> ?
> -	reg = RKVDEC_CUR_POC(sl_params->slice_pic_order_cnt);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC0);
> +	regs->h26x.cur_poc = sl_params->slice_pic_order_cnt;
> ?
> ?	/* config hw pps address */
> ?	offset = offsetof(struct rkvdec_hevc_priv_tbl, param_set);
> -	writel_relaxed(priv_start_addr + offset,
> -		?????? rkvdec->regs + RKVDEC_REG_PPS_BASE);
> +	regs->h26x.pps_base = priv_start_addr + offset;
> ?
> ?	/* config hw rps address */
> ?	offset = offsetof(struct rkvdec_hevc_priv_tbl, rps);
> -	writel_relaxed(priv_start_addr + offset,
> -		?????? rkvdec->regs + RKVDEC_REG_RPS_BASE);
> -
> -	reg = RKVDEC_AXI_DDR_RDATA(0);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_RDATA);
> +	regs->h26x.rps_base = priv_start_addr + offset;
> ?
> -	reg = RKVDEC_AXI_DDR_WDATA(0);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_WDATA);
> +	rkvdec_memcpy_toio(rkvdec->regs, regs, MIN(sizeof(*regs), 4 * rkvdec->variant->num_regs));
> ?}
> ?
> ?#define RKVDEC_HEVC_MAX_DEPTH_IN_BYTES		2
> @@ -784,8 +777,6 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
> ?
> ?	schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000));
> ?
> -	writel(0, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN);
> -	writel(0, rkvdec->regs + RKVDEC_REG_H264_ERR_E);
> ?	writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND);
> ?	writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);
> ?
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h
> index c627b6b6f53a..7745ea257148 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h
> @@ -3,7 +3,12 @@
> ?#ifndef RKVDEC_REGS_H_
> ?#define RKVDEC_REGS_H_
> ?
> -/* rkvcodec registers */
> +#include <linux/types.h>
> +
> +/*
> + * REG_INTERRUPT is accessed via writel to enable the decoder after
> + * configuring it and clear interrupt strmd_error_status
> + */
> ?#define RKVDEC_REG_INTERRUPT				0x004
> ?#define RKVDEC_INTERRUPT_DEC_E				BIT(0)
> ?#define RKVDEC_CONFIG_DEC_CLK_GATE_E			BIT(1)
> @@ -30,198 +35,384 @@
> ?#define RKVDEC_SOFTRESET_RDY				BIT(22)
> ?#define RKVDEC_WR_DDR_ALIGN_EN				BIT(23)
> ?
> -#define RKVDEC_REG_SYSCTRL				0x008
> -#define RKVDEC_IN_ENDIAN				BIT(0)
> -#define RKVDEC_IN_SWAP32_E				BIT(1)
> -#define RKVDEC_IN_SWAP64_E				BIT(2)
> -#define RKVDEC_STR_ENDIAN				BIT(3)
> -#define RKVDEC_STR_SWAP32_E				BIT(4)
> -#define RKVDEC_STR_SWAP64_E				BIT(5)
> -#define RKVDEC_OUT_ENDIAN				BIT(6)
> -#define RKVDEC_OUT_SWAP32_E				BIT(7)
> -#define RKVDEC_OUT_CBCR_SWAP				BIT(8)
> -#define RKVDEC_RLC_MODE_DIRECT_WRITE			BIT(10)
> -#define RKVDEC_RLC_MODE					BIT(11)
> -#define RKVDEC_STRM_START_BIT(x)			(((x) & 0x7f) << 12)
> -#define RKVDEC_MODE(x)					(((x) & 0x03) << 20)
> -#define RKVDEC_MODE_HEVC				0
> -#define RKVDEC_MODE_H264				1
> -#define RKVDEC_MODE_VP9					2
> -#define RKVDEC_RPS_MODE					BIT(24)
> -#define RKVDEC_STRM_MODE				BIT(25)
> -#define RKVDEC_H264_STRM_LASTPKT			BIT(26)
> -#define RKVDEC_H264_FIRSTSLICE_FLAG			BIT(27)
> -#define RKVDEC_H264_FRAME_ORSLICE			BIT(28)
> -#define RKVDEC_BUSPR_SLOT_DIS				BIT(29)
> -
> -#define RKVDEC_REG_PICPAR				0x00C
> -#define RKVDEC_Y_HOR_VIRSTRIDE(x)			((x) & 0x1ff)
> -#define RKVDEC_SLICE_NUM_HIGHBIT			BIT(11)
> -#define RKVDEC_UV_HOR_VIRSTRIDE(x)			(((x) & 0x1ff) << 12)
> -#define RKVDEC_SLICE_NUM_LOWBITS(x)			(((x) & 0x7ff) << 21)
> -
> -#define RKVDEC_REG_STRM_RLC_BASE			0x010
> -
> -#define RKVDEC_REG_STRM_LEN				0x014
> -#define RKVDEC_STRM_LEN(x)				((x) & 0x7ffffff)
> -
> -#define RKVDEC_REG_CABACTBL_PROB_BASE			0x018
> -#define RKVDEC_REG_DECOUT_BASE				0x01C
> -
> -#define RKVDEC_REG_Y_VIRSTRIDE				0x020
> -#define RKVDEC_Y_VIRSTRIDE(x)				((x) & 0xfffff)
> -
> -#define RKVDEC_REG_YUV_VIRSTRIDE			0x024
> -#define RKVDEC_YUV_VIRSTRIDE(x)				((x) & 0x1fffff)
> -#define RKVDEC_REG_H264_BASE_REFER(i)			(((i) * 0x04) + 0x028)
> -
> -#define RKVDEC_REG_H264_BASE_REFER15			0x0C0
> -#define RKVDEC_FIELD_REF				BIT(0)
> -#define RKVDEC_TOPFIELD_USED_REF			BIT(1)
> -#define RKVDEC_BOTFIELD_USED_REF			BIT(2)
> -#define RKVDEC_COLMV_USED_FLAG_REF			BIT(3)
> -
> -#define RKVDEC_REG_VP9_LAST_FRAME_BASE			0x02c
> -#define RKVDEC_REG_VP9_GOLDEN_FRAME_BASE		0x030
> -#define RKVDEC_REG_VP9_ALTREF_FRAME_BASE		0x034
> -
> -#define RKVDEC_REG_VP9_CPRHEADER_OFFSET			0x028
> -#define RKVDEC_VP9_CPRHEADER_OFFSET(x)			((x) & 0xffff)
> -
> -#define RKVDEC_REG_VP9_REFERLAST_BASE			0x02C
> -#define RKVDEC_REG_VP9_REFERGOLDEN_BASE			0x030
> -#define RKVDEC_REG_VP9_REFERALFTER_BASE			0x034
> -
> -#define RKVDEC_REG_VP9COUNT_BASE			0x038
> -#define RKVDEC_VP9COUNT_UPDATE_EN			BIT(0)
> -
> -#define RKVDEC_REG_VP9_SEGIDLAST_BASE			0x03C
> -#define RKVDEC_REG_VP9_SEGIDCUR_BASE			0x040
> -#define RKVDEC_REG_VP9_FRAME_SIZE(i)			((i) * 0x04 + 0x044)
> -#define RKVDEC_VP9_FRAMEWIDTH(x)			(((x) & 0xffff) << 0)
> -#define RKVDEC_VP9_FRAMEHEIGHT(x)			(((x) & 0xffff) << 16)
> -
> -#define RKVDEC_VP9_SEGID_GRP(i)				((i) * 0x04 + 0x050)
> -#define RKVDEC_SEGID_ABS_DELTA(x)			((x) & 0x1)
> -#define RKVDEC_SEGID_FRAME_QP_DELTA_EN(x)		(((x) & 0x1) << 1)
> -#define RKVDEC_SEGID_FRAME_QP_DELTA(x)			(((x) & 0x1ff) << 2)
> -#define RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE_EN(x)	(((x) & 0x1) << 11)
> -#define RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE(x)		(((x) & 0x7f) << 12)
> -#define RKVDEC_SEGID_REFERINFO_EN(x)			(((x) & 0x1) << 19)
> -#define RKVDEC_SEGID_REFERINFO(x)			(((x) & 0x03) << 20)
> -#define RKVDEC_SEGID_FRAME_SKIP_EN(x)			(((x) & 0x1) << 22)
> -
> -#define RKVDEC_VP9_CPRHEADER_CONFIG			0x070
> -#define RKVDEC_VP9_TX_MODE(x)				((x) & 0x07)
> -#define RKVDEC_VP9_FRAME_REF_MODE(x)			(((x) & 0x03) << 3)
> -
> -#define RKVDEC_VP9_REF_SCALE(i)				((i) * 0x04 + 0x074)
> -#define RKVDEC_VP9_REF_HOR_SCALE(x)			((x) & 0xffff)
> -#define RKVDEC_VP9_REF_VER_SCALE(x)			(((x) & 0xffff) << 16)
> -
> -#define RKVDEC_VP9_REF_DELTAS_LASTFRAME			0x080
> -#define RKVDEC_REF_DELTAS_LASTFRAME(pos, val)		(((val) & 0x7f) << ((pos) * 7))
> -
> -#define RKVDEC_VP9_INFO_LASTFRAME			0x084
> -#define RKVDEC_MODE_DELTAS_LASTFRAME(pos, val)		(((val) & 0x7f) << ((pos) * 7))
> -#define RKVDEC_SEG_EN_LASTFRAME				BIT(16)
> -#define RKVDEC_LAST_SHOW_FRAME				BIT(17)
> -#define RKVDEC_LAST_INTRA_ONLY				BIT(18)
> -#define RKVDEC_LAST_WIDHHEIGHT_EQCUR			BIT(19)
> -#define RKVDEC_COLOR_SPACE_LASTKEYFRAME(x)		(((x) & 0x07) << 20)
> -
> -#define RKVDEC_VP9_INTERCMD_BASE			0x088
> -
> -#define RKVDEC_VP9_INTERCMD_NUM				0x08C
> -#define RKVDEC_INTERCMD_NUM(x)				((x) & 0xffffff)
> -
> -#define RKVDEC_VP9_LASTTILE_SIZE			0x090
> -#define RKVDEC_LASTTILE_SIZE(x)				((x) & 0xffffff)
> -
> -#define RKVDEC_VP9_HOR_VIRSTRIDE(i)			((i) * 0x04 + 0x094)
> -#define RKVDEC_HOR_Y_VIRSTRIDE(x)			((x) & 0x1ff)
> -#define RKVDEC_HOR_UV_VIRSTRIDE(x)			(((x) & 0x1ff) << 16)
> -
> -#define RKVDEC_REG_H264_POC_REFER0(i)			(((i) * 0x04) + 0x064)
> -#define RKVDEC_REG_H264_POC_REFER1(i)			(((i) * 0x04) + 0x0C4)
> -#define RKVDEC_REG_H264_POC_REFER2(i)			(((i) * 0x04) + 0x120)
> -#define RKVDEC_POC_REFER(x)				((x) & 0xffffffff)
> -
> -#define RKVDEC_REG_CUR_POC0				0x0A0
> -#define RKVDEC_REG_CUR_POC1				0x128
> -#define RKVDEC_CUR_POC(x)				((x) & 0xffffffff)
> -
> -#define RKVDEC_REG_RLCWRITE_BASE			0x0A4
> -#define RKVDEC_REG_PPS_BASE				0x0A8
> -#define RKVDEC_REG_RPS_BASE				0x0AC
> -
> -#define RKVDEC_REG_STRMD_ERR_EN				0x0B0
> -#define RKVDEC_STRMD_ERR_EN(x)				((x) & 0xffffffff)
> -
> -#define RKVDEC_REG_STRMD_ERR_STA			0x0B4
> -#define RKVDEC_STRMD_ERR_STA(x)				((x) & 0xfffffff)
> -#define RKVDEC_COLMV_ERR_REF_PICIDX(x)			(((x) & 0x0f) << 28)
> -
> -#define RKVDEC_REG_STRMD_ERR_CTU			0x0B8
> -#define RKVDEC_STRMD_ERR_CTU(x)				((x) & 0xff)
> -#define RKVDEC_STRMD_ERR_CTU_YOFFSET(x)			(((x) & 0xff) << 8)
> -#define RKVDEC_STRMFIFO_SPACE2FULL(x)			(((x) & 0x7f) << 16)
> -#define RKVDEC_VP9_ERR_EN_CTU0				BIT(24)
> -
> -#define RKVDEC_REG_SAO_CTU_POS				0x0BC
> -#define RKVDEC_SAOWR_XOFFSET(x)				((x) & 0x1ff)
> -#define RKVDEC_SAOWR_YOFFSET(x)				(((x) & 0x3ff) << 16)
> -
> -#define RKVDEC_VP9_LAST_FRAME_YSTRIDE			0x0C0
> -#define RKVDEC_VP9_GOLDEN_FRAME_YSTRIDE			0x0C4
> -#define RKVDEC_VP9_ALTREF_FRAME_YSTRIDE			0x0C8
> -#define RKVDEC_VP9_REF_YSTRIDE(x)			(((x) & 0xfffff) << 0)
> -
> -#define RKVDEC_VP9_LAST_FRAME_YUVSTRIDE			0x0CC
> -#define RKVDEC_VP9_REF_YUVSTRIDE(x)			(((x) & 0x1fffff) << 0)
> -
> -#define RKVDEC_VP9_REF_COLMV_BASE			0x0D0
> -
> -#define RKVDEC_REG_PERFORMANCE_CYCLE			0x100
> -#define RKVDEC_PERFORMANCE_CYCLE(x)			((x) & 0xffffffff)
> -
> -#define RKVDEC_REG_AXI_DDR_RDATA			0x104
> -#define RKVDEC_AXI_DDR_RDATA(x)				((x) & 0xffffffff)
> -
> -#define RKVDEC_REG_AXI_DDR_WDATA			0x108
> -#define RKVDEC_AXI_DDR_WDATA(x)				((x) & 0xffffffff)
> -
> -#define RKVDEC_REG_FPGADEBUG_RESET			0x10C
> -#define RKVDEC_BUSIFD_RESETN				BIT(0)
> -#define RKVDEC_CABAC_RESETN				BIT(1)
> -#define RKVDEC_DEC_CTRL_RESETN				BIT(2)
> -#define RKVDEC_TRANSD_RESETN				BIT(3)
> -#define RKVDEC_INTRA_RESETN				BIT(4)
> -#define RKVDEC_INTER_RESETN				BIT(5)
> -#define RKVDEC_RECON_RESETN				BIT(6)
> -#define RKVDEC_FILER_RESETN				BIT(7)
> -
> -#define RKVDEC_REG_PERFORMANCE_SEL			0x110
> -#define RKVDEC_PERF_SEL_CNT0(x)				((x) & 0x3f)
> -#define RKVDEC_PERF_SEL_CNT1(x)				(((x) & 0x3f) << 8)
> -#define RKVDEC_PERF_SEL_CNT2(x)				(((x) & 0x3f) << 16)
> -
> -#define RKVDEC_REG_PERFORMANCE_CNT(i)			((i) * 0x04 + 0x114)
> -#define RKVDEC_PERF_CNT(x)				((x) & 0xffffffff)
> -
> -#define RKVDEC_REG_H264_ERRINFO_BASE			0x12C
> -
> -#define RKVDEC_REG_H264_ERRINFO_NUM			0x130
> -#define RKVDEC_SLICEDEC_NUM(x)				((x) & 0x3fff)
> -#define RKVDEC_STRMD_DECT_ERR_FLAG			BIT(15)
> -#define RKVDEC_ERR_PKT_NUM(x)				(((x) & 0x3fff) << 16)
> -
> -#define RKVDEC_REG_H264_ERR_E				0x134
> -#define RKVDEC_H264_ERR_EN_HIGHBITS(x)			((x) & 0x3fffffff)
> -
> ?#define RKVDEC_REG_QOS_CTRL				0x18C
> ?
> +/*
> + * Cache configuration is not covered in the range of the register struct
> + */
> ?#define RKVDEC_REG_PREF_LUMA_CACHE_COMMAND		0x410
> ?#define RKVDEC_REG_PREF_CHR_CACHE_COMMAND		0x450
> ?
> +/*
> + * Define the mode values
> + */
> +#define RKVDEC_MODE_HEVC				0
> +#define RKVDEC_MODE_H264				1
> +#define RKVDEC_MODE_VP9					2
> +
> +/* rkvcodec registers */
> +struct rkvdec_common_regs {
> +	struct rkvdec_id {
> +		u32 minor_ver	: 8;
> +		u32 level	: 1;
> +		u32 dec_support	: 3;
> +		u32 profile	: 1;
> +		u32 reserved0	: 1;
> +		u32 codec_flag	: 1;
> +		u32 reserved1	: 1;
> +		u32 prod_num	: 16;
> +	} reg00;
> +
> +	struct rkvdec_int {
> +		u32 dec_e			: 1;
> +		u32 dec_clkgate_e		: 1;
> +		u32 reserved0			: 1;
> +		u32 timeout_mode		: 1;
> +		u32 dec_irq_dis			: 1;
> +		u32 dec_timeout_e		: 1;
> +		u32 buf_empty_en		: 1;
> +		u32 stmerror_waitdecfifo_empty	: 1;
> +		u32 dec_irq			: 1;
> +		u32 dec_irq_raw			: 1;
> +		u32 reserved2			: 2;
> +		u32 dec_rdy_sta			: 1;
> +		u32 dec_bus_sta			: 1;
> +		u32 dec_error_sta		: 1;
> +		u32 dec_timeout_sta		: 1;
> +		u32 dec_empty_sta		: 1;
> +		u32 colmv_ref_error_sta		: 1;
> +		u32 cabu_end_sta		: 1;
> +		u32 h264orvp9_error_mode	: 1;
> +		u32 softrst_en_p		: 1;
> +		u32 force_softreset_valid	: 1;
> +		u32 softreset_rdy		: 1;
> +		u32 reserved1			: 9;
> +	} reg01;
> +
> +	struct rkvdec_sysctrl {
> +		u32 in_endian			: 1;
> +		u32 in_swap32_e			: 1;
> +		u32 in_swap64_e			: 1;
> +		u32 str_endian			: 1;
> +		u32 str_swap32_e		: 1;
> +		u32 str_swap64_e		: 1;
> +		u32 out_endian			: 1;
> +		u32 out_swap32_e		: 1;
> +		u32 out_cbcr_swap		: 1;
> +		u32 reserved0			: 1;
> +		u32 rlc_mode_direct_write	: 1;
> +		u32 rlc_mode			: 1;
> +		u32 strm_start_bit		: 7;
> +		u32 reserved1			: 1;
> +		u32 dec_mode			: 2;
> +		u32 reserved2			: 2;
> +		u32 rps_mode			: 1;
> +		u32 stream_mode			: 1;
> +		u32 stream_lastpacket		: 1;
> +		u32 firstslice_flag		: 1;
> +		u32 frame_orslice		: 1;
> +		u32 buspr_slot_disable		: 1;
> +		u32 reserved3			: 2;
> +	} reg02;
> +
> +	struct rkvdec_picpar {
> +		u32 y_hor_virstride	: 9;
> +		u32 reserved		: 2;
> +		u32 slice_num_highbit	: 1;
> +		u32 uv_hor_virstride	: 9;
> +		u32 slice_num_lowbits	: 11;
> +	} reg03;
> +
> +	u32 strm_rlc_base;
> +	u32 stream_len;
> +	u32 cabactbl_base;
> +	u32 decout_base;
> +
> +	struct rkvdec_y_virstride {
> +		u32 y_virstride	: 20;
> +		u32 reserved0	: 12;
> +	} reg08;
> +
> +	struct rkvdec_yuv_virstride {
> +		u32 yuv_virstride	: 21;
> +		u32 reserved0		: 11;
> +	} reg09;
> +} __packed;
> +
> +struct ref_base {
> +	u32 field_ref		: 1;
> +	u32 topfield_used_ref	: 1;
> +	u32 botfield_used_ref	: 1;
> +	u32 colmv_used_flag_ref	: 1;
> +	u32 base_addr		: 28;
> +};
> +
> +struct rkvdec_h26x_regs {
> +	struct ref_base ref0_14_base[15];
> +	u32 ref0_14_poc[15];
> +
> +	u32 cur_poc;
> +	u32 rlcwrite_base;
> +	u32 pps_base;
> +	u32 rps_base;
> +
> +	u32 strmd_error_e;
> +
> +	struct {
> +		u32 strmd_error_status		: 28;
> +		u32 colmv_error_ref_picidx	: 4;
> +	} reg45;
> +
> +	struct {
> +		u32 strmd_error_ctu_xoffset	: 8;
> +		u32 strmd_error_ctu_yoffset	: 8;
> +		u32 streamfifo_space2full	: 7;
> +		u32 reserved0			: 1;
> +		u32 vp9_error_ctu0_en		: 1;
> +		u32 reserved1			: 7;
> +	} reg46;
> +
> +	struct {
> +		u32 saowr_xoffet	: 9;
> +		u32 reserved0		: 7;
> +		u32 saowr_yoffset	: 10;
> +		u32 reserved1		: 6;
> +	} reg47;
> +
> +	struct ref_base ref15_base;
> +
> +	u32 ref15_29_poc[15];
> +
> +	u32 performance_cycle;
> +	u32 axi_ddr_rdata;
> +	u32 axi_ddr_wdata;
> +
> +	struct {
> +		u32 busifd_resetn	: 1;
> +		u32 cabac_resetn	: 1;
> +		u32 dec_ctrl_resetn	: 1;
> +		u32 transd_resetn	: 1;
> +		u32 intra_resetn	: 1;
> +		u32 inter_resetn	: 1;
> +		u32 recon_resetn	: 1;
> +		u32 filer_resetn	: 1;
> +		u32 reserved0		: 24;
> +	} reg67;
> +
> +	struct {
> +		u32 perf_cnt0_sel	: 6;
> +		u32 reserved0		: 2;
> +		u32 perf_cnt1_sel	: 6;
> +		u32 reserved1		: 2;
> +		u32 perf_cnt2_sel	: 6;
> +		u32 reserved2		: 10;
> +	} reg68;
> +
> +	u32 perf_cnt0;
> +	u32 perf_cnt1;
> +	u32 perf_cnt2;
> +	u32 ref30_poc;
> +	u32 ref31_poc;
> +	u32 cur_poc1;
> +	u32 errorinfo_base;
> +
> +	struct {
> +		u32 slicedec_num		: 14;
> +		u32 reserved0			: 1;
> +		u32 strmd_detect_error_flag	: 1;
> +		u32 error_packet_num		: 14;
> +		u32 reserved1			: 2;
> +	} reg76;
> +
> +	struct {
> +		u32 error_en_highbits	: 30;
> +		u32 reserved		: 2;
> +	} reg77;
> +} __packed;
> +
> +struct rkvdec_vp9_regs {
> +	struct cprheader_offset {
> +		u32 cprheader_offset	: 16;
> +		u32 reserved		: 16;
> +	} reg10;
> +
> +	u32 refer_bases[3];
> +	u32 count_base;
> +	u32 segidlast_base;
> +	u32 segidcur_base;
> +
> +	struct frame_sizes {
> +		u32 framewidth		: 16;
> +		u32 frameheight		: 16;
> +	} reg17_19[3];
> +
> +	struct segid_grp {
> +		u32 segid_abs_delta			: 1;
> +		u32 segid_frame_qp_delta_en		: 1;
> +		u32 segid_frame_qp_delta		: 9;
> +		u32 segid_frame_loopfilter_value_en	: 1;
> +		u32 segid_frame_loopfilter_value	: 7;
> +		u32 segid_referinfo_en			: 1;
> +		u32 segid_referinfo			: 2;
> +		u32 segid_frame_skip_en			: 1;
> +		u32 reserved				: 9;
> +	} reg20_27[8];
> +
> +	struct cprheader_config {
> +		u32 tx_mode			: 3;
> +		u32 frame_reference_mode	: 2;
> +		u32 reserved			: 27;
> +	} reg28;
> +
> +	struct ref_scale {
> +		u32 ref_hor_scale		: 16;
> +		u32 ref_ver_scale		: 16;
> +	} reg29_31[3];
> +
> +	struct ref_deltas_lastframe {
> +		u32 ref_deltas_lastframe0	: 7;
> +		u32 ref_deltas_lastframe1	: 7;
> +		u32 ref_deltas_lastframe2	: 7;
> +		u32 ref_deltas_lastframe3	: 7;
> +		u32 reserved			: 4;
> +	} reg32;
> +
> +	struct info_lastframe {
> +		u32 mode_deltas_lastframe0		: 7;
> +		u32 mode_deltas_lastframe1		: 7;
> +		u32 reserved0				: 2;
> +		u32 segmentation_enable_lstframe	: 1;
> +		u32 last_show_frame			: 1;
> +		u32 last_intra_only			: 1;
> +		u32 last_widthheight_eqcur		: 1;
> +		u32 color_space_lastkeyframe		: 3;
> +		u32 reserved1				: 9;
> +	} reg33;
> +
> +	u32 intercmd_base;
> +
> +	struct intercmd_num {
> +		u32 intercmd_num	: 24;
> +		u32 reserved		: 8;
> +	} reg35;
> +
> +	struct lasttile_size {
> +		u32 lasttile_size	: 24;
> +		u32 reserved		: 8;
> +	} reg36;
> +
> +	struct hor_virstride {
> +		u32 y_hor_virstride	: 9;
> +		u32 reserved0		: 7;
> +		u32 uv_hor_virstride	: 9;
> +		u32 reserved1		: 7;
> +	} reg37_39[3];
> +
> +	u32 cur_poc;
> +
> +	struct rlcwrite_base {
> +		u32 reserved		: 3;
> +		u32 rlcwrite_base	: 29;
> +	} reg41;
> +
> +	struct pps_base {
> +		u32 reserved	: 4;
> +		u32 pps_base	: 28;
> +	} reg42;
> +
> +	struct rps_base {
> +		u32 reserved	: 4;
> +		u32 rps_base	: 28;
> +	} reg43;
> +
> +	struct strmd_error_en {
> +		u32 strmd_error_e	: 28;
> +		u32 reserved		: 4;
> +	} reg44;
> +
> +	u32 vp9_error_info0;
> +
> +	struct strmd_error_ctu {
> +		u32 strmd_error_ctu_xoffset	: 8;
> +		u32 strmd_error_ctu_yoffset	: 8;
> +		u32 streamfifo_space2full	: 7;
> +		u32 reserved0			: 1;
> +		u32 error_ctu0_en		: 1;
> +		u32 reserved1			: 7;
> +	} reg46;
> +
> +	struct sao_ctu_position {
> +		u32 saowr_xoffet	: 9;
> +		u32 reserved0		: 7;
> +		u32 saowr_yoffset	: 10;
> +		u32 reserved1		: 6;
> +	} reg47;
> +
> +	struct ystride {
> +		u32 virstride	: 20;
> +		u32 reserved	: 12;
> +	} reg48_50[3];
> +
> +	struct lastref_yuvstride {
> +		u32 lastref_yuv_virstride	: 21;
> +		u32 reserved			: 11;
> +	} reg51;
> +
> +	u32 refcolmv_base;
> +
> +	u32 reserved0[11];
> +
> +	u32 performance_cycle;
> +	u32 axi_ddr_rdata;
> +	u32 axi_ddr_wdata;
> +
> +	struct fpgadebug_reset {
> +		u32 busifd_resetn	: 1;
> +		u32 cabac_resetn	: 1;
> +		u32 dec_ctrl_resetn	: 1;
> +		u32 transd_resetn	: 1;
> +		u32 intra_resetn	: 1;
> +		u32 inter_resetn	: 1;
> +		u32 recon_resetn	: 1;
> +		u32 filer_resetn	: 1;
> +		u32 reserved		: 24;
> +	} reg67;
> +
> +	struct performance_sel {
> +		u32 perf_cnt0_sel	: 6;
> +		u32 reserved0		: 2;
> +		u32 perf_cnt1_sel	: 6;
> +		u32 reserved1		: 2;
> +		u32 perf_cnt2_sel	: 6;
> +		u32 reserved		: 10;
> +	} reg68;
> +
> +	u32 perf_cnt0;
> +	u32 perf_cnt1;
> +	u32 perf_cnt2;
> +
> +	u32 reserved1[3];
> +
> +	u32 vp9_error_info1;
> +
> +	struct error_ctu1 {
> +		u32 vp9_error_ctu1_x	: 6;
> +		u32 reserved0		: 2;
> +		u32 vp9_error_ctu1_y	: 6;
> +		u32 reserved1		: 1;
> +		u32 vp9_error_ctu1_en	: 1;
> +		u32 reserved2		: 16;
> +	} reg76;
> +
> +	u32 reserved2;
> +} __packed;
> +
> +struct rkvdec_regs {
> +	struct rkvdec_common_regs common;
> +	union {
> +		struct rkvdec_h26x_regs h26x;
> +		struct rkvdec_vp9_regs? vp9;
> +	};
> +} __packed;
> +
> ?#endif /* RKVDEC_REGS_H_ */
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
> index b4bf01e839ef..0cf5a559701c 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
> @@ -163,6 +163,7 @@ struct rkvdec_vp9_ctx {
> ?	struct v4l2_vp9_frame_context frame_context[4];
> ?	struct rkvdec_vp9_frame_info cur;
> ?	struct rkvdec_vp9_frame_info last;
> +	struct rkvdec_regs regs;
> ?};
> ?
> ?static void write_coeff_plane(const u8 coef[6][6][3], u8 *coeff_plane)
> @@ -347,38 +348,6 @@ static void init_probs(struct rkvdec_ctx *ctx,
> ?		init_inter_probs(ctx, run);
> ?}
> ?
> -struct rkvdec_vp9_ref_reg {
> -	u32 reg_frm_size;
> -	u32 reg_hor_stride;
> -	u32 reg_y_stride;
> -	u32 reg_yuv_stride;
> -	u32 reg_ref_base;
> -};
> -
> -static struct rkvdec_vp9_ref_reg ref_regs[] = {
> -	{
> -		.reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(0),
> -		.reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(0),
> -		.reg_y_stride = RKVDEC_VP9_LAST_FRAME_YSTRIDE,
> -		.reg_yuv_stride = RKVDEC_VP9_LAST_FRAME_YUVSTRIDE,
> -		.reg_ref_base = RKVDEC_REG_VP9_LAST_FRAME_BASE,
> -	},
> -	{
> -		.reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(1),
> -		.reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(1),
> -		.reg_y_stride = RKVDEC_VP9_GOLDEN_FRAME_YSTRIDE,
> -		.reg_yuv_stride = 0,
> -		.reg_ref_base = RKVDEC_REG_VP9_GOLDEN_FRAME_BASE,
> -	},
> -	{
> -		.reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(2),
> -		.reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(2),
> -		.reg_y_stride = RKVDEC_VP9_ALTREF_FRAME_YSTRIDE,
> -		.reg_yuv_stride = 0,
> -		.reg_ref_base = RKVDEC_REG_VP9_ALTREF_FRAME_BASE,
> -	}
> -};
> -
> ?static struct rkvdec_decoded_buffer *
> ?get_ref_buf(struct rkvdec_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp)
> ?{
> @@ -412,18 +381,17 @@ static dma_addr_t get_mv_base_addr(struct rkvdec_decoded_buffer *buf)
> ?static void config_ref_registers(struct rkvdec_ctx *ctx,
> ?				 const struct rkvdec_vp9_run *run,
> ?				 struct rkvdec_decoded_buffer *ref_buf,
> -				 struct rkvdec_vp9_ref_reg *ref_reg)
> +				 int i)
> ?{
> ?	unsigned int aligned_pitch, aligned_height, y_len, yuv_len;
> -	struct rkvdec_dev *rkvdec = ctx->dev;
> +	struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
> +	struct rkvdec_regs *regs = &vp9_ctx->regs;
> ?
> ?	aligned_height = round_up(ref_buf->vp9.height, 64);
> -	writel_relaxed(RKVDEC_VP9_FRAMEWIDTH(ref_buf->vp9.width) |
> -		?????? RKVDEC_VP9_FRAMEHEIGHT(ref_buf->vp9.height),
> -		?????? rkvdec->regs + ref_reg->reg_frm_size);
> +	regs->vp9.reg17_19[i].frameheight = ref_buf->vp9.height;
> +	regs->vp9.reg17_19[i].framewidth = ref_buf->vp9.width;
> ?
> -	writel_relaxed(vb2_dma_contig_plane_dma_addr(&ref_buf->base.vb.vb2_buf, 0),
> -		?????? rkvdec->regs + ref_reg->reg_ref_base);
> +	regs->vp9.refer_bases[i] = vb2_dma_contig_plane_dma_addr(&ref_buf->base.vb.vb2_buf, 0);
> ?
> ?	if (&ref_buf->base.vb == run->base.bufs.dst)
> ?		return;
> @@ -432,59 +400,50 @@ static void config_ref_registers(struct rkvdec_ctx *ctx,
> ?	y_len = aligned_height * aligned_pitch;
> ?	yuv_len = (y_len * 3) / 2;
> ?
> -	writel_relaxed(RKVDEC_HOR_Y_VIRSTRIDE(aligned_pitch / 16) |
> -		?????? RKVDEC_HOR_UV_VIRSTRIDE(aligned_pitch / 16),
> -		?????? rkvdec->regs + ref_reg->reg_hor_stride);
> -	writel_relaxed(RKVDEC_VP9_REF_YSTRIDE(y_len / 16),
> -		?????? rkvdec->regs + ref_reg->reg_y_stride);
> -
> -	if (!ref_reg->reg_yuv_stride)
> -		return;
> +	regs->vp9.reg37_39[i].y_hor_virstride = aligned_pitch / 16;
> +	regs->vp9.reg37_39[i].uv_hor_virstride = aligned_pitch / 16;
> +	regs->vp9.reg48_50[i].virstride = y_len / 16;
> ?
> -	writel_relaxed(RKVDEC_VP9_REF_YUVSTRIDE(yuv_len / 16),
> -		?????? rkvdec->regs + ref_reg->reg_yuv_stride);
> +	if (!i)
> +		regs->vp9.reg51.lastref_yuv_virstride = yuv_len / 16;
> ?}
> ?
> ?static void config_seg_registers(struct rkvdec_ctx *ctx, unsigned int segid)
> ?{
> ?	struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
> +	struct rkvdec_regs *regs = &vp9_ctx->regs;
> ?	const struct v4l2_vp9_segmentation *seg;
> -	struct rkvdec_dev *rkvdec = ctx->dev;
> ?	s16 feature_val;
> ?	int feature_id;
> -	u32 val = 0;
> ?
> ?	seg = vp9_ctx->last.valid ? &vp9_ctx->last.seg : &vp9_ctx->cur.seg;
> ?	feature_id = V4L2_VP9_SEG_LVL_ALT_Q;
> ?	if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid)) {
> ?		feature_val = seg->feature_data[segid][feature_id];
> -		val |= RKVDEC_SEGID_FRAME_QP_DELTA_EN(1) |
> -		?????? RKVDEC_SEGID_FRAME_QP_DELTA(feature_val);
> +		regs->vp9.reg20_27[segid].segid_frame_qp_delta_en = 1;
> +		regs->vp9.reg20_27[segid].segid_frame_qp_delta = feature_val;
> ?	}
> ?
> ?	feature_id = V4L2_VP9_SEG_LVL_ALT_L;
> ?	if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid)) {
> ?		feature_val = seg->feature_data[segid][feature_id];
> -		val |= RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE_EN(1) |
> -		?????? RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE(feature_val);
> +		regs->vp9.reg20_27[segid].segid_frame_loopfilter_value_en = 1;
> +		regs->vp9.reg20_27[segid].segid_frame_loopfilter_value = feature_val;
> ?	}
> ?
> ?	feature_id = V4L2_VP9_SEG_LVL_REF_FRAME;
> ?	if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid)) {
> ?		feature_val = seg->feature_data[segid][feature_id];
> -		val |= RKVDEC_SEGID_REFERINFO_EN(1) |
> -		?????? RKVDEC_SEGID_REFERINFO(feature_val);
> +		regs->vp9.reg20_27[segid].segid_referinfo_en = 1;
> +		regs->vp9.reg20_27[segid].segid_referinfo = feature_val;
> ?	}
> ?
> ?	feature_id = V4L2_VP9_SEG_LVL_SKIP;
> -	if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid))
> -		val |= RKVDEC_SEGID_FRAME_SKIP_EN(1);
> -
> -	if (!segid &&
> -	??? (seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE))
> -		val |= RKVDEC_SEGID_ABS_DELTA(1);
> +	regs->vp9.reg20_27[segid].segid_frame_skip_en =
> +		v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid);
> ?
> -	writel_relaxed(val, rkvdec->regs + RKVDEC_VP9_SEGID_GRP(segid));
> +	regs->vp9.reg20_27[segid].segid_abs_delta = !segid &&
> +		(seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE);
> ?}
> ?
> ?static void update_dec_buf_info(struct rkvdec_decoded_buffer *buf,
> @@ -521,7 +480,8 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?	struct rkvdec_decoded_buffer *ref_bufs[3];
> ?	struct rkvdec_decoded_buffer *dst, *last, *mv_ref;
> ?	struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
> -	u32 val, last_frame_info = 0;
> +	struct rkvdec_regs *regs = &vp9_ctx->regs;
> +	u32 val;
> ?	const struct v4l2_vp9_segmentation *seg;
> ?	struct rkvdec_dev *rkvdec = ctx->dev;
> ?	dma_addr_t addr;
> @@ -547,8 +507,7 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?			(V4L2_VP9_FRAME_FLAG_KEY_FRAME |
> ?			 V4L2_VP9_FRAME_FLAG_INTRA_ONLY));
> ?
> -	writel_relaxed(RKVDEC_MODE(RKVDEC_MODE_VP9),
> -		?????? rkvdec->regs + RKVDEC_REG_SYSCTRL);
> +	regs->common.reg02.dec_mode = RKVDEC_MODE_VP9;
> ?
> ?	bit_depth = dec_params->bit_depth;
> ?	aligned_height = round_up(ctx->decoded_fmt.fmt.pix_mp.height, 64);
> @@ -560,17 +519,14 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?	uv_len = y_len / 2;
> ?	yuv_len = y_len + uv_len;
> ?
> -	writel_relaxed(RKVDEC_Y_HOR_VIRSTRIDE(aligned_pitch / 16) |
> -		?????? RKVDEC_UV_HOR_VIRSTRIDE(aligned_pitch / 16),
> -		?????? rkvdec->regs + RKVDEC_REG_PICPAR);
> -	writel_relaxed(RKVDEC_Y_VIRSTRIDE(y_len / 16),
> -		?????? rkvdec->regs + RKVDEC_REG_Y_VIRSTRIDE);
> -	writel_relaxed(RKVDEC_YUV_VIRSTRIDE(yuv_len / 16),
> -		?????? rkvdec->regs + RKVDEC_REG_YUV_VIRSTRIDE);
> +	regs->common.reg03.y_hor_virstride = aligned_pitch / 16;
> +	regs->common.reg03.uv_hor_virstride = aligned_pitch / 16;
> +	regs->common.reg08.y_virstride = y_len / 16;
> +	regs->common.reg09.yuv_virstride = yuv_len / 16;
> ?
> ?	stream_len = vb2_get_plane_payload(&run->base.bufs.src->vb2_buf, 0);
> -	writel_relaxed(RKVDEC_STRM_LEN(stream_len),
> -		?????? rkvdec->regs + RKVDEC_REG_STRM_LEN);
> +
> +	regs->common.stream_len = stream_len;
> ?
> ?	/*
> ?	 * Reset count buffer, because decoder only output intra related syntax
> @@ -588,14 +544,13 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?		vp9_ctx->cur.segmapid++;
> ?
> ?	for (i = 0; i < ARRAY_SIZE(ref_bufs); i++)
> -		config_ref_registers(ctx, run, ref_bufs[i], &ref_regs[i]);
> +		config_ref_registers(ctx, run, ref_bufs[i], i);
> ?
> ?	for (i = 0; i < 8; i++)
> ?		config_seg_registers(ctx, i);
> ?
> -	writel_relaxed(RKVDEC_VP9_TX_MODE(vp9_ctx->cur.tx_mode) |
> -		?????? RKVDEC_VP9_FRAME_REF_MODE(dec_params->reference_mode),
> -		?????? rkvdec->regs + RKVDEC_VP9_CPRHEADER_CONFIG);
> +	regs->vp9.reg28.tx_mode = vp9_ctx->cur.tx_mode;
> +	regs->vp9.reg28.frame_reference_mode = dec_params->reference_mode;
> ?
> ?	if (!intra_only) {
> ?		const struct v4l2_vp9_loop_filter *lf;
> @@ -609,43 +564,56 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?		val = 0;
> ?		for (i = 0; i < ARRAY_SIZE(lf->ref_deltas); i++) {
> ?			delta = lf->ref_deltas[i];
> -			val |= RKVDEC_REF_DELTAS_LASTFRAME(i, delta);
> +			switch (i) {
> +			case 0:
> +				regs->vp9.reg32.ref_deltas_lastframe0 = delta;
> +				break;
> +			case 1:
> +				regs->vp9.reg32.ref_deltas_lastframe1 = delta;
> +				break;
> +			case 2:
> +				regs->vp9.reg32.ref_deltas_lastframe2 = delta;
> +				break;
> +			case 3:
> +				regs->vp9.reg32.ref_deltas_lastframe3 = delta;
> +				break;
> +			}
> ?		}
> ?
> -		writel_relaxed(val,
> -			?????? rkvdec->regs + RKVDEC_VP9_REF_DELTAS_LASTFRAME);
> -
> ?		for (i = 0; i < ARRAY_SIZE(lf->mode_deltas); i++) {
> ?			delta = lf->mode_deltas[i];
> -			last_frame_info |= RKVDEC_MODE_DELTAS_LASTFRAME(i,
> -									delta);
> +			switch (i) {
> +			case 0:
> +				regs->vp9.reg33.mode_deltas_lastframe0 = delta;
> +				break;
> +			case 1:
> +				regs->vp9.reg33.mode_deltas_lastframe1 = delta;
> +				break;
> +			}
> ?		}
> ?	}
> ?
> -	if (vp9_ctx->last.valid && !intra_only &&
> -	??? vp9_ctx->last.seg.flags & V4L2_VP9_SEGMENTATION_FLAG_ENABLED)
> -		last_frame_info |= RKVDEC_SEG_EN_LASTFRAME;
> +	regs->vp9.reg33.segmentation_enable_lstframe =
> +		vp9_ctx->last.valid && !intra_only &&
> +		vp9_ctx->last.seg.flags & V4L2_VP9_SEGMENTATION_FLAG_ENABLED;
> ?
> -	if (vp9_ctx->last.valid &&
> -	??? vp9_ctx->last.flags & V4L2_VP9_FRAME_FLAG_SHOW_FRAME)
> -		last_frame_info |= RKVDEC_LAST_SHOW_FRAME;
> +	regs->vp9.reg33.last_show_frame =
> +		vp9_ctx->last.valid &&
> +		vp9_ctx->last.flags & V4L2_VP9_FRAME_FLAG_SHOW_FRAME;
> ?
> -	if (vp9_ctx->last.valid &&
> -	??? vp9_ctx->last.flags &
> -	??? (V4L2_VP9_FRAME_FLAG_KEY_FRAME | V4L2_VP9_FRAME_FLAG_INTRA_ONLY))
> -		last_frame_info |= RKVDEC_LAST_INTRA_ONLY;
> +	regs->vp9.reg33.last_intra_only =
> +		vp9_ctx->last.valid &&
> +		vp9_ctx->last.flags &
> +		(V4L2_VP9_FRAME_FLAG_KEY_FRAME | V4L2_VP9_FRAME_FLAG_INTRA_ONLY);
> ?
> -	if (vp9_ctx->last.valid &&
> -	??? last->vp9.width == dst->vp9.width &&
> -	??? last->vp9.height == dst->vp9.height)
> -		last_frame_info |= RKVDEC_LAST_WIDHHEIGHT_EQCUR;
> +	regs->vp9.reg33.last_widthheight_eqcur =
> +		vp9_ctx->last.valid &&
> +		last->vp9.width == dst->vp9.width &&
> +		last->vp9.height == dst->vp9.height;
> ?
> -	writel_relaxed(last_frame_info,
> -		?????? rkvdec->regs + RKVDEC_VP9_INFO_LASTFRAME);
> -
> -	writel_relaxed(stream_len - dec_params->compressed_header_size -
> -		?????? dec_params->uncompressed_header_size,
> -		?????? rkvdec->regs + RKVDEC_VP9_LASTTILE_SIZE);
> +	regs->vp9.reg36.lasttile_size =
> +		stream_len - dec_params->compressed_header_size -
> +		dec_params->uncompressed_header_size;
> ?
> ?	for (i = 0; !intra_only && i < ARRAY_SIZE(ref_bufs); i++) {
> ?		unsigned int refw = ref_bufs[i]->vp9.width;
> @@ -654,29 +622,28 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?
> ?		hscale = (refw << 14) /	dst->vp9.width;
> ?		vscale = (refh << 14) / dst->vp9.height;
> -		writel_relaxed(RKVDEC_VP9_REF_HOR_SCALE(hscale) |
> -			?????? RKVDEC_VP9_REF_VER_SCALE(vscale),
> -			?????? rkvdec->regs + RKVDEC_VP9_REF_SCALE(i));
> +
> +		regs->vp9.reg29_31[i].ref_hor_scale = hscale;
> +		regs->vp9.reg29_31[i].ref_ver_scale = vscale;
> ?	}
> ?
> ?	addr = vb2_dma_contig_plane_dma_addr(&dst->base.vb.vb2_buf, 0);
> -	writel_relaxed(addr, rkvdec->regs + RKVDEC_REG_DECOUT_BASE);
> +	regs->common.decout_base = addr;
> ?	addr = vb2_dma_contig_plane_dma_addr(&run->base.bufs.src->vb2_buf, 0);
> -	writel_relaxed(addr, rkvdec->regs + RKVDEC_REG_STRM_RLC_BASE);
> -	writel_relaxed(vp9_ctx->priv_tbl.dma +
> -		?????? offsetof(struct rkvdec_vp9_priv_tbl, probs),
> -		?????? rkvdec->regs + RKVDEC_REG_CABACTBL_PROB_BASE);
> -	writel_relaxed(vp9_ctx->count_tbl.dma,
> -		?????? rkvdec->regs + RKVDEC_REG_VP9COUNT_BASE);
> -
> -	writel_relaxed(vp9_ctx->priv_tbl.dma +
> -		?????? offsetof(struct rkvdec_vp9_priv_tbl, segmap) +
> -		?????? (RKVDEC_VP9_MAX_SEGMAP_SIZE * vp9_ctx->cur.segmapid),
> -		?????? rkvdec->regs + RKVDEC_REG_VP9_SEGIDCUR_BASE);
> -	writel_relaxed(vp9_ctx->priv_tbl.dma +
> -		?????? offsetof(struct rkvdec_vp9_priv_tbl, segmap) +
> -		?????? (RKVDEC_VP9_MAX_SEGMAP_SIZE * (!vp9_ctx->cur.segmapid)),
> -		?????? rkvdec->regs + RKVDEC_REG_VP9_SEGIDLAST_BASE);
> +	regs->common.strm_rlc_base = addr;
> +
> +	regs->common.cabactbl_base = vp9_ctx->priv_tbl.dma +
> +		offsetof(struct rkvdec_vp9_priv_tbl, probs);
> +
> +	regs->vp9.count_base = vp9_ctx->count_tbl.dma;
> +
> +	regs->vp9.segidlast_base = vp9_ctx->priv_tbl.dma +
> +		offsetof(struct rkvdec_vp9_priv_tbl, segmap) +
> +		(RKVDEC_VP9_MAX_SEGMAP_SIZE * (!vp9_ctx->cur.segmapid));
> +
> +	regs->vp9.segidcur_base = vp9_ctx->priv_tbl.dma +
> +		offsetof(struct rkvdec_vp9_priv_tbl, segmap) +
> +		(RKVDEC_VP9_MAX_SEGMAP_SIZE * vp9_ctx->cur.segmapid);
> ?
> ?	if (!intra_only &&
> ?	??? !(dec_params->flags & V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT) &&
> @@ -685,12 +652,14 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?	else
> ?		mv_ref = dst;
> ?
> -	writel_relaxed(get_mv_base_addr(mv_ref),
> -		?????? rkvdec->regs + RKVDEC_VP9_REF_COLMV_BASE);
> +	regs->vp9.refcolmv_base = get_mv_base_addr(mv_ref);
> ?
> -	writel_relaxed(ctx->decoded_fmt.fmt.pix_mp.width |
> -		?????? (ctx->decoded_fmt.fmt.pix_mp.height << 16),
> -		?????? rkvdec->regs + RKVDEC_REG_PERFORMANCE_CYCLE);
> +	regs->vp9.performance_cycle = ctx->decoded_fmt.fmt.pix_mp.width |
> +		?????? (ctx->decoded_fmt.fmt.pix_mp.height << 16);
> +
> +	regs->vp9.reg44.strmd_error_e = 0xe;
> +
> +	rkvdec_memcpy_toio(rkvdec->regs, regs, MIN(sizeof(*regs), rkvdec->variant->num_regs));
> ?}
> ?
> ?static int validate_dec_params(struct rkvdec_ctx *ctx,
> @@ -823,8 +792,6 @@ static int rkvdec_vp9_run(struct rkvdec_ctx *ctx)
> ?	writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND);
> ?	writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);
> ?
> -	writel(0xe, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN);
> -
> ?	if (rkvdec->variant->quirks & RKVDEC_QUIRK_DISABLE_QOS)
> ?		rkvdec_quirks_disable_qos(ctx);
> ?
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> index 5af9aa5ab353..776149f871b0 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> @@ -914,6 +914,15 @@ void rkvdec_quirks_disable_qos(struct rkvdec_ctx *ctx)
> ?	writel(reg, rkvdec->regs + RKVDEC_REG_QOS_CTRL);
> ?}
> ?
> +void rkvdec_memcpy_toio(void __iomem *dst, void *src, size_t len)
> +{
> +#ifdef CONFIG_ARM64
> +	__iowrite32_copy(dst, src, len / 4);
> +#else
> +	memcpy_toio(dst, src, len);
> +#endif
> +}
> +
> ?static void rkvdec_device_run(void *priv)
> ?{
> ?	struct rkvdec_ctx *ctx = priv;
> @@ -1227,7 +1236,6 @@ static void rkvdec_watchdog_func(struct work_struct *work)
> ?	if (ctx) {
> ?		dev_err(rkvdec->dev, "Frame processing timed out!\n");
> ?		writel(RKVDEC_IRQ_DIS, rkvdec->regs + RKVDEC_REG_INTERRUPT);
> -		writel(0, rkvdec->regs + RKVDEC_REG_SYSCTRL);
> ?		rkvdec_job_finish(ctx, VB2_BUF_STATE_ERROR);
> ?	}
> ?}
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> index 566e06fa2b1e..f35f6e80ea2e 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> @@ -151,6 +151,7 @@ struct rkvdec_aux_buf {
> ?
> ?void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run);
> ?void rkvdec_run_postamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run);
> +void rkvdec_memcpy_toio(void __iomem *dst, void *src, size_t len);
> ?
> ?void rkvdec_quirks_disable_qos(struct rkvdec_ctx *ctx);
> ?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251210/5e8798d3/attachment-0001.sig>

From nicolas.dufresne at collabora.com  Wed Dec 10 12:13:23 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Wed, 10 Dec 2025 15:13:23 -0500
Subject: [PATCH v3 04/15] media: rkvdec: Move cabac tables to their own
 source file
In-Reply-To: <20251022162459.271603-5-detlev.casanova@collabora.com>
References: <20251022162459.271603-1-detlev.casanova@collabora.com>
	 <20251022162459.271603-5-detlev.casanova@collabora.com>
Message-ID: <a806b28faeccb761cf0dee917566811012429dc7.camel@collabora.com>

Le mercredi 22 octobre 2025 ? 12:22 -0400, Detlev Casanova a ?crit?:
> This is in preparation to add support for new variants that will use the
> same tables.
> 
> Tested-by: Diederik de Haas <didi.debian at cknow.org>? # Rock 5B
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?.../media/platform/rockchip/rkvdec/Makefile?? |?? 7 +-
> ?.../{rkvdec-hevc-data.c => rkvdec-cabac.c}??? | 506 +++++++++++++++++-
> ?.../platform/rockchip/rkvdec/rkvdec-h264.c??? | 501 +----------------
> ?.../platform/rockchip/rkvdec/rkvdec-hevc.c??? |?? 6 +-
> ?4 files changed, 514 insertions(+), 506 deletions(-)
> ?rename drivers/media/platform/rockchip/rkvdec/{rkvdec-hevc-data.c => rkvdec-cabac.c} (86%)
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
> index a77122641d14..a8ff5e3d7bec 100644
> --- a/drivers/media/platform/rockchip/rkvdec/Makefile
> +++ b/drivers/media/platform/rockchip/rkvdec/Makefile
> @@ -1,3 +1,8 @@
> ?obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC) += rockchip-vdec.o
> ?
> -rockchip-vdec-y += rkvdec.o rkvdec-h264.o rkvdec-hevc.o rkvdec-vp9.o
> +rockchip-vdec-y += \
> +		?? rkvdec.o \
> +		?? rkvdec-cabac.o \
> +		?? rkvdec-h264.o \
> +		?? rkvdec-hevc.o \
> +		?? rkvdec-vp9.o
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-data.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-cabac.c
> similarity index 86%
> rename from drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-data.c
> rename to drivers/media/platform/rockchip/rkvdec/rkvdec-cabac.c
> index eac4ea604949..bc87f59636ea 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-data.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-cabac.c
> @@ -1,19 +1,517 @@
> ?// SPDX-License-Identifier: GPL-2.0
> ?/*
> - * Rockchip Video Decoder driver
> + * Rockchip Video Decoder CABAC tables
> ? *
> ? * Copyright (C) 2023 Collabora, Ltd.
> ? *	Sebastian Fricke <sebastian.fricke at collabora.com>
> + * Copyright (C) 2019 Collabora, Ltd.
> + *	Boris Brezillon <boris.brezillon at collabora.com>
> ? */
> ?
> ?#include <linux/types.h>
> ?
> -#define RKV_CABAC_TABLE_SIZE		27456
> +#define CABAC_ENTRY(ctxidx, idc0_m, idc0_n, idc1_m, idc1_n,		\
> +	??? idc2_m, idc2_n, intra_m, intra_n)			\
> +	[0][(ctxidx)] = {idc0_m, idc0_n},			\
> +	[1][(ctxidx)] = {idc1_m, idc1_n},			\
> +	[2][(ctxidx)] = {idc2_m, idc2_n},			\
> +	[3][(ctxidx)] = {intra_m, intra_n}
> ?
> ?/*
> - * This file is #include from rkvdec-hevc.c and not compiled.
> + * Constant CABAC table.
> + * Built from the tables described in section '9.3.1.1 Initialisation process
> + * for context variables' of the H264 spec.
> ? */
> -static const u8 rkvdec_hevc_cabac_table[RKV_CABAC_TABLE_SIZE] = {
> +const s8 rkvdec_h264_cabac_table[4][464][2] = {
> +	/* Table 9-12 ? Values of variables m and n for ctxIdx from 0 to 10 */
> +	CABAC_ENTRY(0, 20, -15, 20, -15, 20, -15, 20, -15),
> +	CABAC_ENTRY(1, 2, 54, 2, 54, 2, 54, 2, 54),
> +	CABAC_ENTRY(2, 3, 74, 3, 74, 3, 74, 3, 74),
> +	CABAC_ENTRY(3, 20, -15, 20, -15, 20, -15, 20, -15),
> +	CABAC_ENTRY(4, 2, 54, 2, 54, 2, 54, 2, 54),
> +	CABAC_ENTRY(5, 3, 74, 3, 74, 3, 74, 3, 74),
> +	CABAC_ENTRY(6, -28, 127, -28, 127, -28, 127, -28, 127),
> +	CABAC_ENTRY(7, -23, 104, -23, 104, -23, 104, -23, 104),
> +	CABAC_ENTRY(8, -6, 53, -6, 53, -6, 53, -6, 53),
> +	CABAC_ENTRY(9, -1, 54, -1, 54, -1, 54, -1, 54),
> +	CABAC_ENTRY(10, 7, 51, 7, 51, 7, 51, 7, 51),
> +
> +	/* Table 9-13 ? Values of variables m and n for ctxIdx from 11 to 23 */
> +	CABAC_ENTRY(11, 23, 33, 22, 25, 29, 16, 0, 0),
> +	CABAC_ENTRY(12, 23, 2, 34, 0, 25, 0, 0, 0),
> +	CABAC_ENTRY(13, 21, 0, 16, 0, 14, 0, 0, 0),
> +	CABAC_ENTRY(14, 1, 9, -2, 9, -10, 51, 0, 0),
> +	CABAC_ENTRY(15, 0, 49, 4, 41, -3, 62, 0, 0),
> +	CABAC_ENTRY(16, -37, 118, -29, 118, -27, 99, 0, 0),
> +	CABAC_ENTRY(17, 5, 57, 2, 65, 26, 16, 0, 0),
> +	CABAC_ENTRY(18, -13, 78, -6, 71, -4, 85, 0, 0),
> +	CABAC_ENTRY(19, -11, 65, -13, 79, -24, 102, 0, 0),
> +	CABAC_ENTRY(20, 1, 62, 5, 52, 5, 57, 0, 0),
> +	CABAC_ENTRY(21, 12, 49, 9, 50, 6, 57, 0, 0),
> +	CABAC_ENTRY(22, -4, 73, -3, 70, -17, 73, 0, 0),
> +	CABAC_ENTRY(23, 17, 50, 10, 54, 14, 57, 0, 0),
> +
> +	/* Table 9-14 ? Values of variables m and n for ctxIdx from 24 to 39 */
> +	CABAC_ENTRY(24, 18, 64, 26, 34, 20, 40, 0, 0),
> +	CABAC_ENTRY(25, 9, 43, 19, 22, 20, 10, 0, 0),
> +	CABAC_ENTRY(26, 29, 0, 40, 0, 29, 0, 0, 0),
> +	CABAC_ENTRY(27, 26, 67, 57, 2, 54, 0, 0, 0),
> +	CABAC_ENTRY(28, 16, 90, 41, 36, 37, 42, 0, 0),
> +	CABAC_ENTRY(29, 9, 104, 26, 69, 12, 97, 0, 0),
> +	CABAC_ENTRY(30, -46, 127, -45, 127, -32, 127, 0, 0),
> +	CABAC_ENTRY(31, -20, 104, -15, 101, -22, 117, 0, 0),
> +	CABAC_ENTRY(32, 1, 67, -4, 76, -2, 74, 0, 0),
> +	CABAC_ENTRY(33, -13, 78, -6, 71, -4, 85, 0, 0),
> +	CABAC_ENTRY(34, -11, 65, -13, 79, -24, 102, 0, 0),
> +	CABAC_ENTRY(35, 1, 62, 5, 52, 5, 57, 0, 0),
> +	CABAC_ENTRY(36, -6, 86, 6, 69, -6, 93, 0, 0),
> +	CABAC_ENTRY(37, -17, 95, -13, 90, -14, 88, 0, 0),
> +	CABAC_ENTRY(38, -6, 61, 0, 52, -6, 44, 0, 0),
> +	CABAC_ENTRY(39, 9, 45, 8, 43, 4, 55, 0, 0),
> +
> +	/* Table 9-15 ? Values of variables m and n for ctxIdx from 40 to 53 */
> +	CABAC_ENTRY(40, -3, 69, -2, 69, -11, 89, 0, 0),
> +	CABAC_ENTRY(41, -6, 81, -5, 82, -15, 103, 0, 0),
> +	CABAC_ENTRY(42, -11, 96, -10, 96, -21, 116, 0, 0),
> +	CABAC_ENTRY(43, 6, 55, 2, 59, 19, 57, 0, 0),
> +	CABAC_ENTRY(44, 7, 67, 2, 75, 20, 58, 0, 0),
> +	CABAC_ENTRY(45, -5, 86, -3, 87, 4, 84, 0, 0),
> +	CABAC_ENTRY(46, 2, 88, -3, 100, 6, 96, 0, 0),
> +	CABAC_ENTRY(47, 0, 58, 1, 56, 1, 63, 0, 0),
> +	CABAC_ENTRY(48, -3, 76, -3, 74, -5, 85, 0, 0),
> +	CABAC_ENTRY(49, -10, 94, -6, 85, -13, 106, 0, 0),
> +	CABAC_ENTRY(50, 5, 54, 0, 59, 5, 63, 0, 0),
> +	CABAC_ENTRY(51, 4, 69, -3, 81, 6, 75, 0, 0),
> +	CABAC_ENTRY(52, -3, 81, -7, 86, -3, 90, 0, 0),
> +	CABAC_ENTRY(53, 0, 88, -5, 95, -1, 101, 0, 0),
> +
> +	/* Table 9-16 ? Values of variables m and n for ctxIdx from 54 to 59 */
> +	CABAC_ENTRY(54, -7, 67, -1, 66, 3, 55, 0, 0),
> +	CABAC_ENTRY(55, -5, 74, -1, 77, -4, 79, 0, 0),
> +	CABAC_ENTRY(56, -4, 74, 1, 70, -2, 75, 0, 0),
> +	CABAC_ENTRY(57, -5, 80, -2, 86, -12, 97, 0, 0),
> +	CABAC_ENTRY(58, -7, 72, -5, 72, -7, 50, 0, 0),
> +	CABAC_ENTRY(59, 1, 58, 0, 61, 1, 60, 0, 0),
> +
> +	/* Table 9-17 ? Values of variables m and n for ctxIdx from 60 to 69 */
> +	CABAC_ENTRY(60, 0, 41, 0, 41, 0, 41, 0, 41),
> +	CABAC_ENTRY(61, 0, 63, 0, 63, 0, 63, 0, 63),
> +	CABAC_ENTRY(62, 0, 63, 0, 63, 0, 63, 0, 63),
> +	CABAC_ENTRY(63, 0, 63, 0, 63, 0, 63, 0, 63),
> +	CABAC_ENTRY(64, -9, 83, -9, 83, -9, 83, -9, 83),
> +	CABAC_ENTRY(65, 4, 86, 4, 86, 4, 86, 4, 86),
> +	CABAC_ENTRY(66, 0, 97, 0, 97, 0, 97, 0, 97),
> +	CABAC_ENTRY(67, -7, 72, -7, 72, -7, 72, -7, 72),
> +	CABAC_ENTRY(68, 13, 41, 13, 41, 13, 41, 13, 41),
> +	CABAC_ENTRY(69, 3, 62, 3, 62, 3, 62, 3, 62),
> +
> +	/* Table 9-18 ? Values of variables m and n for ctxIdx from 70 to 104 */
> +	CABAC_ENTRY(70, 0, 45, 13, 15, 7, 34, 0, 11),
> +	CABAC_ENTRY(71, -4, 78, 7, 51, -9, 88, 1, 55),
> +	CABAC_ENTRY(72, -3, 96, 2, 80, -20, 127, 0, 69),
> +	CABAC_ENTRY(73, -27, 126, -39, 127, -36, 127, -17, 127),
> +	CABAC_ENTRY(74, -28, 98, -18, 91, -17, 91, -13, 102),
> +	CABAC_ENTRY(75, -25, 101, -17, 96, -14, 95, 0, 82),
> +	CABAC_ENTRY(76, -23, 67, -26, 81, -25, 84, -7, 74),
> +	CABAC_ENTRY(77, -28, 82, -35, 98, -25, 86, -21, 107),
> +	CABAC_ENTRY(78, -20, 94, -24, 102, -12, 89, -27, 127),
> +	CABAC_ENTRY(79, -16, 83, -23, 97, -17, 91, -31, 127),
> +	CABAC_ENTRY(80, -22, 110, -27, 119, -31, 127, -24, 127),
> +	CABAC_ENTRY(81, -21, 91, -24, 99, -14, 76, -18, 95),
> +	CABAC_ENTRY(82, -18, 102, -21, 110, -18, 103, -27, 127),
> +	CABAC_ENTRY(83, -13, 93, -18, 102, -13, 90, -21, 114),
> +	CABAC_ENTRY(84, -29, 127, -36, 127, -37, 127, -30, 127),
> +	CABAC_ENTRY(85, -7, 92, 0, 80, 11, 80, -17, 123),
> +	CABAC_ENTRY(86, -5, 89, -5, 89, 5, 76, -12, 115),
> +	CABAC_ENTRY(87, -7, 96, -7, 94, 2, 84, -16, 122),
> +	CABAC_ENTRY(88, -13, 108, -4, 92, 5, 78, -11, 115),
> +	CABAC_ENTRY(89, -3, 46, 0, 39, -6, 55, -12, 63),
> +	CABAC_ENTRY(90, -1, 65, 0, 65, 4, 61, -2, 68),
> +	CABAC_ENTRY(91, -1, 57, -15, 84, -14, 83, -15, 84),
> +	CABAC_ENTRY(92, -9, 93, -35, 127, -37, 127, -13, 104),
> +	CABAC_ENTRY(93, -3, 74, -2, 73, -5, 79, -3, 70),
> +	CABAC_ENTRY(94, -9, 92, -12, 104, -11, 104, -8, 93),
> +	CABAC_ENTRY(95, -8, 87, -9, 91, -11, 91, -10, 90),
> +	CABAC_ENTRY(96, -23, 126, -31, 127, -30, 127, -30, 127),
> +	CABAC_ENTRY(97, 5, 54, 3, 55, 0, 65, -1, 74),
> +	CABAC_ENTRY(98, 6, 60, 7, 56, -2, 79, -6, 97),
> +	CABAC_ENTRY(99, 6, 59, 7, 55, 0, 72, -7, 91),
> +	CABAC_ENTRY(100, 6, 69, 8, 61, -4, 92, -20, 127),
> +	CABAC_ENTRY(101, -1, 48, -3, 53, -6, 56, -4, 56),
> +	CABAC_ENTRY(102, 0, 68, 0, 68, 3, 68, -5, 82),
> +	CABAC_ENTRY(103, -4, 69, -7, 74, -8, 71, -7, 76),
> +	CABAC_ENTRY(104, -8, 88, -9, 88, -13, 98, -22, 125),
> +
> +	/* Table 9-19 ? Values of variables m and n for ctxIdx from 105 to 165 */
> +	CABAC_ENTRY(105, -2, 85, -13, 103, -4, 86, -7, 93),
> +	CABAC_ENTRY(106, -6, 78, -13, 91, -12, 88, -11, 87),
> +	CABAC_ENTRY(107, -1, 75, -9, 89, -5, 82, -3, 77),
> +	CABAC_ENTRY(108, -7, 77, -14, 92, -3, 72, -5, 71),
> +	CABAC_ENTRY(109, 2, 54, -8, 76, -4, 67, -4, 63),
> +	CABAC_ENTRY(110, 5, 50, -12, 87, -8, 72, -4, 68),
> +	CABAC_ENTRY(111, -3, 68, -23, 110, -16, 89, -12, 84),
> +	CABAC_ENTRY(112, 1, 50, -24, 105, -9, 69, -7, 62),
> +	CABAC_ENTRY(113, 6, 42, -10, 78, -1, 59, -7, 65),
> +	CABAC_ENTRY(114, -4, 81, -20, 112, 5, 66, 8, 61),
> +	CABAC_ENTRY(115, 1, 63, -17, 99, 4, 57, 5, 56),
> +	CABAC_ENTRY(116, -4, 70, -78, 127, -4, 71, -2, 66),
> +	CABAC_ENTRY(117, 0, 67, -70, 127, -2, 71, 1, 64),
> +	CABAC_ENTRY(118, 2, 57, -50, 127, 2, 58, 0, 61),
> +	CABAC_ENTRY(119, -2, 76, -46, 127, -1, 74, -2, 78),
> +	CABAC_ENTRY(120, 11, 35, -4, 66, -4, 44, 1, 50),
> +	CABAC_ENTRY(121, 4, 64, -5, 78, -1, 69, 7, 52),
> +	CABAC_ENTRY(122, 1, 61, -4, 71, 0, 62, 10, 35),
> +	CABAC_ENTRY(123, 11, 35, -8, 72, -7, 51, 0, 44),
> +	CABAC_ENTRY(124, 18, 25, 2, 59, -4, 47, 11, 38),
> +	CABAC_ENTRY(125, 12, 24, -1, 55, -6, 42, 1, 45),
> +	CABAC_ENTRY(126, 13, 29, -7, 70, -3, 41, 0, 46),
> +	CABAC_ENTRY(127, 13, 36, -6, 75, -6, 53, 5, 44),
> +	CABAC_ENTRY(128, -10, 93, -8, 89, 8, 76, 31, 17),
> +	CABAC_ENTRY(129, -7, 73, -34, 119, -9, 78, 1, 51),
> +	CABAC_ENTRY(130, -2, 73, -3, 75, -11, 83, 7, 50),
> +	CABAC_ENTRY(131, 13, 46, 32, 20, 9, 52, 28, 19),
> +	CABAC_ENTRY(132, 9, 49, 30, 22, 0, 67, 16, 33),
> +	CABAC_ENTRY(133, -7, 100, -44, 127, -5, 90, 14, 62),
> +	CABAC_ENTRY(134, 9, 53, 0, 54, 1, 67, -13, 108),
> +	CABAC_ENTRY(135, 2, 53, -5, 61, -15, 72, -15, 100),
> +	CABAC_ENTRY(136, 5, 53, 0, 58, -5, 75, -13, 101),
> +	CABAC_ENTRY(137, -2, 61, -1, 60, -8, 80, -13, 91),
> +	CABAC_ENTRY(138, 0, 56, -3, 61, -21, 83, -12, 94),
> +	CABAC_ENTRY(139, 0, 56, -8, 67, -21, 64, -10, 88),
> +	CABAC_ENTRY(140, -13, 63, -25, 84, -13, 31, -16, 84),
> +	CABAC_ENTRY(141, -5, 60, -14, 74, -25, 64, -10, 86),
> +	CABAC_ENTRY(142, -1, 62, -5, 65, -29, 94, -7, 83),
> +	CABAC_ENTRY(143, 4, 57, 5, 52, 9, 75, -13, 87),
> +	CABAC_ENTRY(144, -6, 69, 2, 57, 17, 63, -19, 94),
> +	CABAC_ENTRY(145, 4, 57, 0, 61, -8, 74, 1, 70),
> +	CABAC_ENTRY(146, 14, 39, -9, 69, -5, 35, 0, 72),
> +	CABAC_ENTRY(147, 4, 51, -11, 70, -2, 27, -5, 74),
> +	CABAC_ENTRY(148, 13, 68, 18, 55, 13, 91, 18, 59),
> +	CABAC_ENTRY(149, 3, 64, -4, 71, 3, 65, -8, 102),
> +	CABAC_ENTRY(150, 1, 61, 0, 58, -7, 69, -15, 100),
> +	CABAC_ENTRY(151, 9, 63, 7, 61, 8, 77, 0, 95),
> +	CABAC_ENTRY(152, 7, 50, 9, 41, -10, 66, -4, 75),
> +	CABAC_ENTRY(153, 16, 39, 18, 25, 3, 62, 2, 72),
> +	CABAC_ENTRY(154, 5, 44, 9, 32, -3, 68, -11, 75),
> +	CABAC_ENTRY(155, 4, 52, 5, 43, -20, 81, -3, 71),
> +	CABAC_ENTRY(156, 11, 48, 9, 47, 0, 30, 15, 46),
> +	CABAC_ENTRY(157, -5, 60, 0, 44, 1, 7, -13, 69),
> +	CABAC_ENTRY(158, -1, 59, 0, 51, -3, 23, 0, 62),
> +	CABAC_ENTRY(159, 0, 59, 2, 46, -21, 74, 0, 65),
> +	CABAC_ENTRY(160, 22, 33, 19, 38, 16, 66, 21, 37),
> +	CABAC_ENTRY(161, 5, 44, -4, 66, -23, 124, -15, 72),
> +	CABAC_ENTRY(162, 14, 43, 15, 38, 17, 37, 9, 57),
> +	CABAC_ENTRY(163, -1, 78, 12, 42, 44, -18, 16, 54),
> +	CABAC_ENTRY(164, 0, 60, 9, 34, 50, -34, 0, 62),
> +	CABAC_ENTRY(165, 9, 69, 0, 89, -22, 127, 12, 72),
> +
> +	/* Table 9-20 ? Values of variables m and n for ctxIdx from 166 to 226 */
> +	CABAC_ENTRY(166, 11, 28, 4, 45, 4, 39, 24, 0),
> +	CABAC_ENTRY(167, 2, 40, 10, 28, 0, 42, 15, 9),
> +	CABAC_ENTRY(168, 3, 44, 10, 31, 7, 34, 8, 25),
> +	CABAC_ENTRY(169, 0, 49, 33, -11, 11, 29, 13, 18),
> +	CABAC_ENTRY(170, 0, 46, 52, -43, 8, 31, 15, 9),
> +	CABAC_ENTRY(171, 2, 44, 18, 15, 6, 37, 13, 19),
> +	CABAC_ENTRY(172, 2, 51, 28, 0, 7, 42, 10, 37),
> +	CABAC_ENTRY(173, 0, 47, 35, -22, 3, 40, 12, 18),
> +	CABAC_ENTRY(174, 4, 39, 38, -25, 8, 33, 6, 29),
> +	CABAC_ENTRY(175, 2, 62, 34, 0, 13, 43, 20, 33),
> +	CABAC_ENTRY(176, 6, 46, 39, -18, 13, 36, 15, 30),
> +	CABAC_ENTRY(177, 0, 54, 32, -12, 4, 47, 4, 45),
> +	CABAC_ENTRY(178, 3, 54, 102, -94, 3, 55, 1, 58),
> +	CABAC_ENTRY(179, 2, 58, 0, 0, 2, 58, 0, 62),
> +	CABAC_ENTRY(180, 4, 63, 56, -15, 6, 60, 7, 61),
> +	CABAC_ENTRY(181, 6, 51, 33, -4, 8, 44, 12, 38),
> +	CABAC_ENTRY(182, 6, 57, 29, 10, 11, 44, 11, 45),
> +	CABAC_ENTRY(183, 7, 53, 37, -5, 14, 42, 15, 39),
> +	CABAC_ENTRY(184, 6, 52, 51, -29, 7, 48, 11, 42),
> +	CABAC_ENTRY(185, 6, 55, 39, -9, 4, 56, 13, 44),
> +	CABAC_ENTRY(186, 11, 45, 52, -34, 4, 52, 16, 45),
> +	CABAC_ENTRY(187, 14, 36, 69, -58, 13, 37, 12, 41),
> +	CABAC_ENTRY(188, 8, 53, 67, -63, 9, 49, 10, 49),
> +	CABAC_ENTRY(189, -1, 82, 44, -5, 19, 58, 30, 34),
> +	CABAC_ENTRY(190, 7, 55, 32, 7, 10, 48, 18, 42),
> +	CABAC_ENTRY(191, -3, 78, 55, -29, 12, 45, 10, 55),
> +	CABAC_ENTRY(192, 15, 46, 32, 1, 0, 69, 17, 51),
> +	CABAC_ENTRY(193, 22, 31, 0, 0, 20, 33, 17, 46),
> +	CABAC_ENTRY(194, -1, 84, 27, 36, 8, 63, 0, 89),
> +	CABAC_ENTRY(195, 25, 7, 33, -25, 35, -18, 26, -19),
> +	CABAC_ENTRY(196, 30, -7, 34, -30, 33, -25, 22, -17),
> +	CABAC_ENTRY(197, 28, 3, 36, -28, 28, -3, 26, -17),
> +	CABAC_ENTRY(198, 28, 4, 38, -28, 24, 10, 30, -25),
> +	CABAC_ENTRY(199, 32, 0, 38, -27, 27, 0, 28, -20),
> +	CABAC_ENTRY(200, 34, -1, 34, -18, 34, -14, 33, -23),
> +	CABAC_ENTRY(201, 30, 6, 35, -16, 52, -44, 37, -27),
> +	CABAC_ENTRY(202, 30, 6, 34, -14, 39, -24, 33, -23),
> +	CABAC_ENTRY(203, 32, 9, 32, -8, 19, 17, 40, -28),
> +	CABAC_ENTRY(204, 31, 19, 37, -6, 31, 25, 38, -17),
> +	CABAC_ENTRY(205, 26, 27, 35, 0, 36, 29, 33, -11),
> +	CABAC_ENTRY(206, 26, 30, 30, 10, 24, 33, 40, -15),
> +	CABAC_ENTRY(207, 37, 20, 28, 18, 34, 15, 41, -6),
> +	CABAC_ENTRY(208, 28, 34, 26, 25, 30, 20, 38, 1),
> +	CABAC_ENTRY(209, 17, 70, 29, 41, 22, 73, 41, 17),
> +	CABAC_ENTRY(210, 1, 67, 0, 75, 20, 34, 30, -6),
> +	CABAC_ENTRY(211, 5, 59, 2, 72, 19, 31, 27, 3),
> +	CABAC_ENTRY(212, 9, 67, 8, 77, 27, 44, 26, 22),
> +	CABAC_ENTRY(213, 16, 30, 14, 35, 19, 16, 37, -16),
> +	CABAC_ENTRY(214, 18, 32, 18, 31, 15, 36, 35, -4),
> +	CABAC_ENTRY(215, 18, 35, 17, 35, 15, 36, 38, -8),
> +	CABAC_ENTRY(216, 22, 29, 21, 30, 21, 28, 38, -3),
> +	CABAC_ENTRY(217, 24, 31, 17, 45, 25, 21, 37, 3),
> +	CABAC_ENTRY(218, 23, 38, 20, 42, 30, 20, 38, 5),
> +	CABAC_ENTRY(219, 18, 43, 18, 45, 31, 12, 42, 0),
> +	CABAC_ENTRY(220, 20, 41, 27, 26, 27, 16, 35, 16),
> +	CABAC_ENTRY(221, 11, 63, 16, 54, 24, 42, 39, 22),
> +	CABAC_ENTRY(222, 9, 59, 7, 66, 0, 93, 14, 48),
> +	CABAC_ENTRY(223, 9, 64, 16, 56, 14, 56, 27, 37),
> +	CABAC_ENTRY(224, -1, 94, 11, 73, 15, 57, 21, 60),
> +	CABAC_ENTRY(225, -2, 89, 10, 67, 26, 38, 12, 68),
> +	CABAC_ENTRY(226, -9, 108, -10, 116, -24, 127, 2, 97),
> +
> +	/* Table 9-21 ? Values of variables m and n for ctxIdx from 227 to 275 */
> +	CABAC_ENTRY(227, -6, 76, -23, 112, -24, 115, -3, 71),
> +	CABAC_ENTRY(228, -2, 44, -15, 71, -22, 82, -6, 42),
> +	CABAC_ENTRY(229, 0, 45, -7, 61, -9, 62, -5, 50),
> +	CABAC_ENTRY(230, 0, 52, 0, 53, 0, 53, -3, 54),
> +	CABAC_ENTRY(231, -3, 64, -5, 66, 0, 59, -2, 62),
> +	CABAC_ENTRY(232, -2, 59, -11, 77, -14, 85, 0, 58),
> +	CABAC_ENTRY(233, -4, 70, -9, 80, -13, 89, 1, 63),
> +	CABAC_ENTRY(234, -4, 75, -9, 84, -13, 94, -2, 72),
> +	CABAC_ENTRY(235, -8, 82, -10, 87, -11, 92, -1, 74),
> +	CABAC_ENTRY(236, -17, 102, -34, 127, -29, 127, -9, 91),
> +	CABAC_ENTRY(237, -9, 77, -21, 101, -21, 100, -5, 67),
> +	CABAC_ENTRY(238, 3, 24, -3, 39, -14, 57, -5, 27),
> +	CABAC_ENTRY(239, 0, 42, -5, 53, -12, 67, -3, 39),
> +	CABAC_ENTRY(240, 0, 48, -7, 61, -11, 71, -2, 44),
> +	CABAC_ENTRY(241, 0, 55, -11, 75, -10, 77, 0, 46),
> +	CABAC_ENTRY(242, -6, 59, -15, 77, -21, 85, -16, 64),
> +	CABAC_ENTRY(243, -7, 71, -17, 91, -16, 88, -8, 68),
> +	CABAC_ENTRY(244, -12, 83, -25, 107, -23, 104, -10, 78),
> +	CABAC_ENTRY(245, -11, 87, -25, 111, -15, 98, -6, 77),
> +	CABAC_ENTRY(246, -30, 119, -28, 122, -37, 127, -10, 86),
> +	CABAC_ENTRY(247, 1, 58, -11, 76, -10, 82, -12, 92),
> +	CABAC_ENTRY(248, -3, 29, -10, 44, -8, 48, -15, 55),
> +	CABAC_ENTRY(249, -1, 36, -10, 52, -8, 61, -10, 60),
> +	CABAC_ENTRY(250, 1, 38, -10, 57, -8, 66, -6, 62),
> +	CABAC_ENTRY(251, 2, 43, -9, 58, -7, 70, -4, 65),
> +	CABAC_ENTRY(252, -6, 55, -16, 72, -14, 75, -12, 73),
> +	CABAC_ENTRY(253, 0, 58, -7, 69, -10, 79, -8, 76),
> +	CABAC_ENTRY(254, 0, 64, -4, 69, -9, 83, -7, 80),
> +	CABAC_ENTRY(255, -3, 74, -5, 74, -12, 92, -9, 88),
> +	CABAC_ENTRY(256, -10, 90, -9, 86, -18, 108, -17, 110),
> +	CABAC_ENTRY(257, 0, 70, 2, 66, -4, 79, -11, 97),
> +	CABAC_ENTRY(258, -4, 29, -9, 34, -22, 69, -20, 84),
> +	CABAC_ENTRY(259, 5, 31, 1, 32, -16, 75, -11, 79),
> +	CABAC_ENTRY(260, 7, 42, 11, 31, -2, 58, -6, 73),
> +	CABAC_ENTRY(261, 1, 59, 5, 52, 1, 58, -4, 74),
> +	CABAC_ENTRY(262, -2, 58, -2, 55, -13, 78, -13, 86),
> +	CABAC_ENTRY(263, -3, 72, -2, 67, -9, 83, -13, 96),
> +	CABAC_ENTRY(264, -3, 81, 0, 73, -4, 81, -11, 97),
> +	CABAC_ENTRY(265, -11, 97, -8, 89, -13, 99, -19, 117),
> +	CABAC_ENTRY(266, 0, 58, 3, 52, -13, 81, -8, 78),
> +	CABAC_ENTRY(267, 8, 5, 7, 4, -6, 38, -5, 33),
> +	CABAC_ENTRY(268, 10, 14, 10, 8, -13, 62, -4, 48),
> +	CABAC_ENTRY(269, 14, 18, 17, 8, -6, 58, -2, 53),
> +	CABAC_ENTRY(270, 13, 27, 16, 19, -2, 59, -3, 62),
> +	CABAC_ENTRY(271, 2, 40, 3, 37, -16, 73, -13, 71),
> +	CABAC_ENTRY(272, 0, 58, -1, 61, -10, 76, -10, 79),
> +	CABAC_ENTRY(273, -3, 70, -5, 73, -13, 86, -12, 86),
> +	CABAC_ENTRY(274, -6, 79, -1, 70, -9, 83, -13, 90),
> +	CABAC_ENTRY(275, -8, 85, -4, 78, -10, 87, -14, 97),
> +
> +	/* Table 9-22 ? Values of variables m and n for ctxIdx from 277 to 337 */
> +	CABAC_ENTRY(277, -13, 106, -21, 126, -22, 127, -6, 93),
> +	CABAC_ENTRY(278, -16, 106, -23, 124, -25, 127, -6, 84),
> +	CABAC_ENTRY(279, -10, 87, -20, 110, -25, 120, -8, 79),
> +	CABAC_ENTRY(280, -21, 114, -26, 126, -27, 127, 0, 66),
> +	CABAC_ENTRY(281, -18, 110, -25, 124, -19, 114, -1, 71),
> +	CABAC_ENTRY(282, -14, 98, -17, 105, -23, 117, 0, 62),
> +	CABAC_ENTRY(283, -22, 110, -27, 121, -25, 118, -2, 60),
> +	CABAC_ENTRY(284, -21, 106, -27, 117, -26, 117, -2, 59),
> +	CABAC_ENTRY(285, -18, 103, -17, 102, -24, 113, -5, 75),
> +	CABAC_ENTRY(286, -21, 107, -26, 117, -28, 118, -3, 62),
> +	CABAC_ENTRY(287, -23, 108, -27, 116, -31, 120, -4, 58),
> +	CABAC_ENTRY(288, -26, 112, -33, 122, -37, 124, -9, 66),
> +	CABAC_ENTRY(289, -10, 96, -10, 95, -10, 94, -1, 79),
> +	CABAC_ENTRY(290, -12, 95, -14, 100, -15, 102, 0, 71),
> +	CABAC_ENTRY(291, -5, 91, -8, 95, -10, 99, 3, 68),
> +	CABAC_ENTRY(292, -9, 93, -17, 111, -13, 106, 10, 44),
> +	CABAC_ENTRY(293, -22, 94, -28, 114, -50, 127, -7, 62),
> +	CABAC_ENTRY(294, -5, 86, -6, 89, -5, 92, 15, 36),
> +	CABAC_ENTRY(295, 9, 67, -2, 80, 17, 57, 14, 40),
> +	CABAC_ENTRY(296, -4, 80, -4, 82, -5, 86, 16, 27),
> +	CABAC_ENTRY(297, -10, 85, -9, 85, -13, 94, 12, 29),
> +	CABAC_ENTRY(298, -1, 70, -8, 81, -12, 91, 1, 44),
> +	CABAC_ENTRY(299, 7, 60, -1, 72, -2, 77, 20, 36),
> +	CABAC_ENTRY(300, 9, 58, 5, 64, 0, 71, 18, 32),
> +	CABAC_ENTRY(301, 5, 61, 1, 67, -1, 73, 5, 42),
> +	CABAC_ENTRY(302, 12, 50, 9, 56, 4, 64, 1, 48),
> +	CABAC_ENTRY(303, 15, 50, 0, 69, -7, 81, 10, 62),
> +	CABAC_ENTRY(304, 18, 49, 1, 69, 5, 64, 17, 46),
> +	CABAC_ENTRY(305, 17, 54, 7, 69, 15, 57, 9, 64),
> +	CABAC_ENTRY(306, 10, 41, -7, 69, 1, 67, -12, 104),
> +	CABAC_ENTRY(307, 7, 46, -6, 67, 0, 68, -11, 97),
> +	CABAC_ENTRY(308, -1, 51, -16, 77, -10, 67, -16, 96),
> +	CABAC_ENTRY(309, 7, 49, -2, 64, 1, 68, -7, 88),
> +	CABAC_ENTRY(310, 8, 52, 2, 61, 0, 77, -8, 85),
> +	CABAC_ENTRY(311, 9, 41, -6, 67, 2, 64, -7, 85),
> +	CABAC_ENTRY(312, 6, 47, -3, 64, 0, 68, -9, 85),
> +	CABAC_ENTRY(313, 2, 55, 2, 57, -5, 78, -13, 88),
> +	CABAC_ENTRY(314, 13, 41, -3, 65, 7, 55, 4, 66),
> +	CABAC_ENTRY(315, 10, 44, -3, 66, 5, 59, -3, 77),
> +	CABAC_ENTRY(316, 6, 50, 0, 62, 2, 65, -3, 76),
> +	CABAC_ENTRY(317, 5, 53, 9, 51, 14, 54, -6, 76),
> +	CABAC_ENTRY(318, 13, 49, -1, 66, 15, 44, 10, 58),
> +	CABAC_ENTRY(319, 4, 63, -2, 71, 5, 60, -1, 76),
> +	CABAC_ENTRY(320, 6, 64, -2, 75, 2, 70, -1, 83),
> +	CABAC_ENTRY(321, -2, 69, -1, 70, -2, 76, -7, 99),
> +	CABAC_ENTRY(322, -2, 59, -9, 72, -18, 86, -14, 95),
> +	CABAC_ENTRY(323, 6, 70, 14, 60, 12, 70, 2, 95),
> +	CABAC_ENTRY(324, 10, 44, 16, 37, 5, 64, 0, 76),
> +	CABAC_ENTRY(325, 9, 31, 0, 47, -12, 70, -5, 74),
> +	CABAC_ENTRY(326, 12, 43, 18, 35, 11, 55, 0, 70),
> +	CABAC_ENTRY(327, 3, 53, 11, 37, 5, 56, -11, 75),
> +	CABAC_ENTRY(328, 14, 34, 12, 41, 0, 69, 1, 68),
> +	CABAC_ENTRY(329, 10, 38, 10, 41, 2, 65, 0, 65),
> +	CABAC_ENTRY(330, -3, 52, 2, 48, -6, 74, -14, 73),
> +	CABAC_ENTRY(331, 13, 40, 12, 41, 5, 54, 3, 62),
> +	CABAC_ENTRY(332, 17, 32, 13, 41, 7, 54, 4, 62),
> +	CABAC_ENTRY(333, 7, 44, 0, 59, -6, 76, -1, 68),
> +	CABAC_ENTRY(334, 7, 38, 3, 50, -11, 82, -13, 75),
> +	CABAC_ENTRY(335, 13, 50, 19, 40, -2, 77, 11, 55),
> +	CABAC_ENTRY(336, 10, 57, 3, 66, -2, 77, 5, 64),
> +	CABAC_ENTRY(337, 26, 43, 18, 50, 25, 42, 12, 70),
> +
> +	/* Table 9-23 ? Values of variables m and n for ctxIdx from 338 to 398 */
> +	CABAC_ENTRY(338, 14, 11, 19, -6, 17, -13, 15, 6),
> +	CABAC_ENTRY(339, 11, 14, 18, -6, 16, -9, 6, 19),
> +	CABAC_ENTRY(340, 9, 11, 14, 0, 17, -12, 7, 16),
> +	CABAC_ENTRY(341, 18, 11, 26, -12, 27, -21, 12, 14),
> +	CABAC_ENTRY(342, 21, 9, 31, -16, 37, -30, 18, 13),
> +	CABAC_ENTRY(343, 23, -2, 33, -25, 41, -40, 13, 11),
> +	CABAC_ENTRY(344, 32, -15, 33, -22, 42, -41, 13, 15),
> +	CABAC_ENTRY(345, 32, -15, 37, -28, 48, -47, 15, 16),
> +	CABAC_ENTRY(346, 34, -21, 39, -30, 39, -32, 12, 23),
> +	CABAC_ENTRY(347, 39, -23, 42, -30, 46, -40, 13, 23),
> +	CABAC_ENTRY(348, 42, -33, 47, -42, 52, -51, 15, 20),
> +	CABAC_ENTRY(349, 41, -31, 45, -36, 46, -41, 14, 26),
> +	CABAC_ENTRY(350, 46, -28, 49, -34, 52, -39, 14, 44),
> +	CABAC_ENTRY(351, 38, -12, 41, -17, 43, -19, 17, 40),
> +	CABAC_ENTRY(352, 21, 29, 32, 9, 32, 11, 17, 47),
> +	CABAC_ENTRY(353, 45, -24, 69, -71, 61, -55, 24, 17),
> +	CABAC_ENTRY(354, 53, -45, 63, -63, 56, -46, 21, 21),
> +	CABAC_ENTRY(355, 48, -26, 66, -64, 62, -50, 25, 22),
> +	CABAC_ENTRY(356, 65, -43, 77, -74, 81, -67, 31, 27),
> +	CABAC_ENTRY(357, 43, -19, 54, -39, 45, -20, 22, 29),
> +	CABAC_ENTRY(358, 39, -10, 52, -35, 35, -2, 19, 35),
> +	CABAC_ENTRY(359, 30, 9, 41, -10, 28, 15, 14, 50),
> +	CABAC_ENTRY(360, 18, 26, 36, 0, 34, 1, 10, 57),
> +	CABAC_ENTRY(361, 20, 27, 40, -1, 39, 1, 7, 63),
> +	CABAC_ENTRY(362, 0, 57, 30, 14, 30, 17, -2, 77),
> +	CABAC_ENTRY(363, -14, 82, 28, 26, 20, 38, -4, 82),
> +	CABAC_ENTRY(364, -5, 75, 23, 37, 18, 45, -3, 94),
> +	CABAC_ENTRY(365, -19, 97, 12, 55, 15, 54, 9, 69),
> +	CABAC_ENTRY(366, -35, 125, 11, 65, 0, 79, -12, 109),
> +	CABAC_ENTRY(367, 27, 0, 37, -33, 36, -16, 36, -35),
> +	CABAC_ENTRY(368, 28, 0, 39, -36, 37, -14, 36, -34),
> +	CABAC_ENTRY(369, 31, -4, 40, -37, 37, -17, 32, -26),
> +	CABAC_ENTRY(370, 27, 6, 38, -30, 32, 1, 37, -30),
> +	CABAC_ENTRY(371, 34, 8, 46, -33, 34, 15, 44, -32),
> +	CABAC_ENTRY(372, 30, 10, 42, -30, 29, 15, 34, -18),
> +	CABAC_ENTRY(373, 24, 22, 40, -24, 24, 25, 34, -15),
> +	CABAC_ENTRY(374, 33, 19, 49, -29, 34, 22, 40, -15),
> +	CABAC_ENTRY(375, 22, 32, 38, -12, 31, 16, 33, -7),
> +	CABAC_ENTRY(376, 26, 31, 40, -10, 35, 18, 35, -5),
> +	CABAC_ENTRY(377, 21, 41, 38, -3, 31, 28, 33, 0),
> +	CABAC_ENTRY(378, 26, 44, 46, -5, 33, 41, 38, 2),
> +	CABAC_ENTRY(379, 23, 47, 31, 20, 36, 28, 33, 13),
> +	CABAC_ENTRY(380, 16, 65, 29, 30, 27, 47, 23, 35),
> +	CABAC_ENTRY(381, 14, 71, 25, 44, 21, 62, 13, 58),
> +	CABAC_ENTRY(382, 8, 60, 12, 48, 18, 31, 29, -3),
> +	CABAC_ENTRY(383, 6, 63, 11, 49, 19, 26, 26, 0),
> +	CABAC_ENTRY(384, 17, 65, 26, 45, 36, 24, 22, 30),
> +	CABAC_ENTRY(385, 21, 24, 22, 22, 24, 23, 31, -7),
> +	CABAC_ENTRY(386, 23, 20, 23, 22, 27, 16, 35, -15),
> +	CABAC_ENTRY(387, 26, 23, 27, 21, 24, 30, 34, -3),
> +	CABAC_ENTRY(388, 27, 32, 33, 20, 31, 29, 34, 3),
> +	CABAC_ENTRY(389, 28, 23, 26, 28, 22, 41, 36, -1),
> +	CABAC_ENTRY(390, 28, 24, 30, 24, 22, 42, 34, 5),
> +	CABAC_ENTRY(391, 23, 40, 27, 34, 16, 60, 32, 11),
> +	CABAC_ENTRY(392, 24, 32, 18, 42, 15, 52, 35, 5),
> +	CABAC_ENTRY(393, 28, 29, 25, 39, 14, 60, 34, 12),
> +	CABAC_ENTRY(394, 23, 42, 18, 50, 3, 78, 39, 11),
> +	CABAC_ENTRY(395, 19, 57, 12, 70, -16, 123, 30, 29),
> +	CABAC_ENTRY(396, 22, 53, 21, 54, 21, 53, 34, 26),
> +	CABAC_ENTRY(397, 22, 61, 14, 71, 22, 56, 29, 39),
> +	CABAC_ENTRY(398, 11, 86, 11, 83, 25, 61, 19, 66),
> +
> +	/* Values of variables m and n for ctxIdx from 399 to 463 (not documented) */
> +	CABAC_ENTRY(399, 12, 40, 25, 32, 21, 33, 31, 21),
> +	CABAC_ENTRY(400, 11, 51, 21, 49, 19, 50, 31, 31),
> +	CABAC_ENTRY(401, 14, 59, 21, 54, 17, 61, 25, 50),
> +	CABAC_ENTRY(402, -4, 79, -5, 85, -3, 78, -17, 120),
> +	CABAC_ENTRY(403, -7, 71, -6, 81, -8, 74, -20, 112),
> +	CABAC_ENTRY(404, -5, 69, -10, 77, -9, 72, -18, 114),
> +	CABAC_ENTRY(405, -9, 70, -7, 81, -10, 72, -11, 85),
> +	CABAC_ENTRY(406, -8, 66, -17, 80, -18, 75, -15, 92),
> +	CABAC_ENTRY(407, -10, 68, -18, 73, -12, 71, -14, 89),
> +	CABAC_ENTRY(408, -19, 73, -4, 74, -11, 63, -26, 71),
> +	CABAC_ENTRY(409, -12, 69, -10, 83, -5, 70, -15, 81),
> +	CABAC_ENTRY(410, -16, 70, -9, 71, -17, 75, -14, 80),
> +	CABAC_ENTRY(411, -15, 67, -9, 67, -14, 72, 0, 68),
> +	CABAC_ENTRY(412, -20, 62, -1, 61, -16, 67, -14, 70),
> +	CABAC_ENTRY(413, -19, 70, -8, 66, -8, 53, -24, 56),
> +	CABAC_ENTRY(414, -16, 66, -14, 66, -14, 59, -23, 68),
> +	CABAC_ENTRY(415, -22, 65, 0, 59, -9, 52, -24, 50),
> +	CABAC_ENTRY(416, -20, 63, 2, 59, -11, 68, -11, 74),
> +	CABAC_ENTRY(417, 9, -2, 17, -10, 9, -2, 23, -13),
> +	CABAC_ENTRY(418, 26, -9, 32, -13, 30, -10, 26, -13),
> +	CABAC_ENTRY(419, 33, -9, 42, -9, 31, -4, 40, -15),
> +	CABAC_ENTRY(420, 39, -7, 49, -5, 33, -1, 49, -14),
> +	CABAC_ENTRY(421, 41, -2, 53, 0, 33, 7, 44, 3),
> +	CABAC_ENTRY(422, 45, 3, 64, 3, 31, 12, 45, 6),
> +	CABAC_ENTRY(423, 49, 9, 68, 10, 37, 23, 44, 34),
> +	CABAC_ENTRY(424, 45, 27, 66, 27, 31, 38, 33, 54),
> +	CABAC_ENTRY(425, 36, 59, 47, 57, 20, 64, 19, 82),
> +	CABAC_ENTRY(426, -6, 66, -5, 71, -9, 71, -3, 75),
> +	CABAC_ENTRY(427, -7, 35, 0, 24, -7, 37, -1, 23),
> +	CABAC_ENTRY(428, -7, 42, -1, 36, -8, 44, 1, 34),
> +	CABAC_ENTRY(429, -8, 45, -2, 42, -11, 49, 1, 43),
> +	CABAC_ENTRY(430, -5, 48, -2, 52, -10, 56, 0, 54),
> +	CABAC_ENTRY(431, -12, 56, -9, 57, -12, 59, -2, 55),
> +	CABAC_ENTRY(432, -6, 60, -6, 63, -8, 63, 0, 61),
> +	CABAC_ENTRY(433, -5, 62, -4, 65, -9, 67, 1, 64),
> +	CABAC_ENTRY(434, -8, 66, -4, 67, -6, 68, 0, 68),
> +	CABAC_ENTRY(435, -8, 76, -7, 82, -10, 79, -9, 92),
> +	CABAC_ENTRY(436, -5, 85, -3, 81, -3, 78, -14, 106),
> +	CABAC_ENTRY(437, -6, 81, -3, 76, -8, 74, -13, 97),
> +	CABAC_ENTRY(438, -10, 77, -7, 72, -9, 72, -15, 90),
> +	CABAC_ENTRY(439, -7, 81, -6, 78, -10, 72, -12, 90),
> +	CABAC_ENTRY(440, -17, 80, -12, 72, -18, 75, -18, 88),
> +	CABAC_ENTRY(441, -18, 73, -14, 68, -12, 71, -10, 73),
> +	CABAC_ENTRY(442, -4, 74, -3, 70, -11, 63, -9, 79),
> +	CABAC_ENTRY(443, -10, 83, -6, 76, -5, 70, -14, 86),
> +	CABAC_ENTRY(444, -9, 71, -5, 66, -17, 75, -10, 73),
> +	CABAC_ENTRY(445, -9, 67, -5, 62, -14, 72, -10, 70),
> +	CABAC_ENTRY(446, -1, 61, 0, 57, -16, 67, -10, 69),
> +	CABAC_ENTRY(447, -8, 66, -4, 61, -8, 53, -5, 66),
> +	CABAC_ENTRY(448, -14, 66, -9, 60, -14, 59, -9, 64),
> +	CABAC_ENTRY(449, 0, 59, 1, 54, -9, 52, -5, 58),
> +	CABAC_ENTRY(450, 2, 59, 2, 58, -11, 68, 2, 59),
> +	CABAC_ENTRY(451, 21, -13, 17, -10, 9, -2, 21, -10),
> +	CABAC_ENTRY(452, 33, -14, 32, -13, 30, -10, 24, -11),
> +	CABAC_ENTRY(453, 39, -7, 42, -9, 31, -4, 28, -8),
> +	CABAC_ENTRY(454, 46, -2, 49, -5, 33, -1, 28, -1),
> +	CABAC_ENTRY(455, 51, 2, 53, 0, 33, 7, 29, 3),
> +	CABAC_ENTRY(456, 60, 6, 64, 3, 31, 12, 29, 9),
> +	CABAC_ENTRY(457, 61, 17, 68, 10, 37, 23, 35, 20),
> +	CABAC_ENTRY(458, 55, 34, 66, 27, 31, 38, 29, 36),
> +	CABAC_ENTRY(459, 42, 62, 47, 57, 20, 64, 14, 67),
> +};
> +
> +#define RKV_HEVC_CABAC_TABLE_SIZE		27456
> +
> +const u8 rkvdec_hevc_cabac_table[RKV_HEVC_CABAC_TABLE_SIZE] = {
> ?	0x07, 0x0f, 0x48, 0x58, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0f, 0x40, 0x40, 0x40, 0x0f,
> ?	0x68, 0x48, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x40,
> ?	0x40, 0x68, 0x58, 0x60, 0x40, 0x1f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x48, 0x48, 0x60,
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
> index 116e7b1076b7..989379ae3a73 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
> @@ -15,6 +15,8 @@
> ?#include "rkvdec.h"
> ?#include "rkvdec-regs.h"
> ?
> +extern const s8 rkvdec_h264_cabac_table[4][464][2];
> +
> ?/* Size with u32 units. */
> ?#define RKV_CABAC_INIT_BUFFER_SIZE	(3680 + 128)
> ?#define RKV_RPS_SIZE			((128 + 128) / 4)
> @@ -118,505 +120,6 @@ struct rkvdec_h264_ctx {
> ?	struct rkvdec_regs regs;
> ?};
> ?
> -#define CABAC_ENTRY(ctxidx, idc0_m, idc0_n, idc1_m, idc1_n,		\
> -	??? idc2_m, idc2_n, intra_m, intra_n)			\
> -	[0][(ctxidx)] = {idc0_m, idc0_n},			\
> -	[1][(ctxidx)] = {idc1_m, idc1_n},			\
> -	[2][(ctxidx)] = {idc2_m, idc2_n},			\
> -	[3][(ctxidx)] = {intra_m, intra_n}
> -
> -/*
> - * Constant CABAC table.
> - * Built from the tables described in section '9.3.1.1 Initialisation process
> - * for context variables' of the H264 spec.
> - */
> -static const s8 rkvdec_h264_cabac_table[4][464][2] = {
> -	/* Table 9-12 ? Values of variables m and n for ctxIdx from 0 to 10 */
> -	CABAC_ENTRY(0, 20, -15, 20, -15, 20, -15, 20, -15),
> -	CABAC_ENTRY(1, 2, 54, 2, 54, 2, 54, 2, 54),
> -	CABAC_ENTRY(2, 3, 74, 3, 74, 3, 74, 3, 74),
> -	CABAC_ENTRY(3, 20, -15, 20, -15, 20, -15, 20, -15),
> -	CABAC_ENTRY(4, 2, 54, 2, 54, 2, 54, 2, 54),
> -	CABAC_ENTRY(5, 3, 74, 3, 74, 3, 74, 3, 74),
> -	CABAC_ENTRY(6, -28, 127, -28, 127, -28, 127, -28, 127),
> -	CABAC_ENTRY(7, -23, 104, -23, 104, -23, 104, -23, 104),
> -	CABAC_ENTRY(8, -6, 53, -6, 53, -6, 53, -6, 53),
> -	CABAC_ENTRY(9, -1, 54, -1, 54, -1, 54, -1, 54),
> -	CABAC_ENTRY(10, 7, 51, 7, 51, 7, 51, 7, 51),
> -
> -	/* Table 9-13 ? Values of variables m and n for ctxIdx from 11 to 23 */
> -	CABAC_ENTRY(11, 23, 33, 22, 25, 29, 16, 0, 0),
> -	CABAC_ENTRY(12, 23, 2, 34, 0, 25, 0, 0, 0),
> -	CABAC_ENTRY(13, 21, 0, 16, 0, 14, 0, 0, 0),
> -	CABAC_ENTRY(14, 1, 9, -2, 9, -10, 51, 0, 0),
> -	CABAC_ENTRY(15, 0, 49, 4, 41, -3, 62, 0, 0),
> -	CABAC_ENTRY(16, -37, 118, -29, 118, -27, 99, 0, 0),
> -	CABAC_ENTRY(17, 5, 57, 2, 65, 26, 16, 0, 0),
> -	CABAC_ENTRY(18, -13, 78, -6, 71, -4, 85, 0, 0),
> -	CABAC_ENTRY(19, -11, 65, -13, 79, -24, 102, 0, 0),
> -	CABAC_ENTRY(20, 1, 62, 5, 52, 5, 57, 0, 0),
> -	CABAC_ENTRY(21, 12, 49, 9, 50, 6, 57, 0, 0),
> -	CABAC_ENTRY(22, -4, 73, -3, 70, -17, 73, 0, 0),
> -	CABAC_ENTRY(23, 17, 50, 10, 54, 14, 57, 0, 0),
> -
> -	/* Table 9-14 ? Values of variables m and n for ctxIdx from 24 to 39 */
> -	CABAC_ENTRY(24, 18, 64, 26, 34, 20, 40, 0, 0),
> -	CABAC_ENTRY(25, 9, 43, 19, 22, 20, 10, 0, 0),
> -	CABAC_ENTRY(26, 29, 0, 40, 0, 29, 0, 0, 0),
> -	CABAC_ENTRY(27, 26, 67, 57, 2, 54, 0, 0, 0),
> -	CABAC_ENTRY(28, 16, 90, 41, 36, 37, 42, 0, 0),
> -	CABAC_ENTRY(29, 9, 104, 26, 69, 12, 97, 0, 0),
> -	CABAC_ENTRY(30, -46, 127, -45, 127, -32, 127, 0, 0),
> -	CABAC_ENTRY(31, -20, 104, -15, 101, -22, 117, 0, 0),
> -	CABAC_ENTRY(32, 1, 67, -4, 76, -2, 74, 0, 0),
> -	CABAC_ENTRY(33, -13, 78, -6, 71, -4, 85, 0, 0),
> -	CABAC_ENTRY(34, -11, 65, -13, 79, -24, 102, 0, 0),
> -	CABAC_ENTRY(35, 1, 62, 5, 52, 5, 57, 0, 0),
> -	CABAC_ENTRY(36, -6, 86, 6, 69, -6, 93, 0, 0),
> -	CABAC_ENTRY(37, -17, 95, -13, 90, -14, 88, 0, 0),
> -	CABAC_ENTRY(38, -6, 61, 0, 52, -6, 44, 0, 0),
> -	CABAC_ENTRY(39, 9, 45, 8, 43, 4, 55, 0, 0),
> -
> -	/* Table 9-15 ? Values of variables m and n for ctxIdx from 40 to 53 */
> -	CABAC_ENTRY(40, -3, 69, -2, 69, -11, 89, 0, 0),
> -	CABAC_ENTRY(41, -6, 81, -5, 82, -15, 103, 0, 0),
> -	CABAC_ENTRY(42, -11, 96, -10, 96, -21, 116, 0, 0),
> -	CABAC_ENTRY(43, 6, 55, 2, 59, 19, 57, 0, 0),
> -	CABAC_ENTRY(44, 7, 67, 2, 75, 20, 58, 0, 0),
> -	CABAC_ENTRY(45, -5, 86, -3, 87, 4, 84, 0, 0),
> -	CABAC_ENTRY(46, 2, 88, -3, 100, 6, 96, 0, 0),
> -	CABAC_ENTRY(47, 0, 58, 1, 56, 1, 63, 0, 0),
> -	CABAC_ENTRY(48, -3, 76, -3, 74, -5, 85, 0, 0),
> -	CABAC_ENTRY(49, -10, 94, -6, 85, -13, 106, 0, 0),
> -	CABAC_ENTRY(50, 5, 54, 0, 59, 5, 63, 0, 0),
> -	CABAC_ENTRY(51, 4, 69, -3, 81, 6, 75, 0, 0),
> -	CABAC_ENTRY(52, -3, 81, -7, 86, -3, 90, 0, 0),
> -	CABAC_ENTRY(53, 0, 88, -5, 95, -1, 101, 0, 0),
> -
> -	/* Table 9-16 ? Values of variables m and n for ctxIdx from 54 to 59 */
> -	CABAC_ENTRY(54, -7, 67, -1, 66, 3, 55, 0, 0),
> -	CABAC_ENTRY(55, -5, 74, -1, 77, -4, 79, 0, 0),
> -	CABAC_ENTRY(56, -4, 74, 1, 70, -2, 75, 0, 0),
> -	CABAC_ENTRY(57, -5, 80, -2, 86, -12, 97, 0, 0),
> -	CABAC_ENTRY(58, -7, 72, -5, 72, -7, 50, 0, 0),
> -	CABAC_ENTRY(59, 1, 58, 0, 61, 1, 60, 0, 0),
> -
> -	/* Table 9-17 ? Values of variables m and n for ctxIdx from 60 to 69 */
> -	CABAC_ENTRY(60, 0, 41, 0, 41, 0, 41, 0, 41),
> -	CABAC_ENTRY(61, 0, 63, 0, 63, 0, 63, 0, 63),
> -	CABAC_ENTRY(62, 0, 63, 0, 63, 0, 63, 0, 63),
> -	CABAC_ENTRY(63, 0, 63, 0, 63, 0, 63, 0, 63),
> -	CABAC_ENTRY(64, -9, 83, -9, 83, -9, 83, -9, 83),
> -	CABAC_ENTRY(65, 4, 86, 4, 86, 4, 86, 4, 86),
> -	CABAC_ENTRY(66, 0, 97, 0, 97, 0, 97, 0, 97),
> -	CABAC_ENTRY(67, -7, 72, -7, 72, -7, 72, -7, 72),
> -	CABAC_ENTRY(68, 13, 41, 13, 41, 13, 41, 13, 41),
> -	CABAC_ENTRY(69, 3, 62, 3, 62, 3, 62, 3, 62),
> -
> -	/* Table 9-18 ? Values of variables m and n for ctxIdx from 70 to 104 */
> -	CABAC_ENTRY(70, 0, 45, 13, 15, 7, 34, 0, 11),
> -	CABAC_ENTRY(71, -4, 78, 7, 51, -9, 88, 1, 55),
> -	CABAC_ENTRY(72, -3, 96, 2, 80, -20, 127, 0, 69),
> -	CABAC_ENTRY(73, -27, 126, -39, 127, -36, 127, -17, 127),
> -	CABAC_ENTRY(74, -28, 98, -18, 91, -17, 91, -13, 102),
> -	CABAC_ENTRY(75, -25, 101, -17, 96, -14, 95, 0, 82),
> -	CABAC_ENTRY(76, -23, 67, -26, 81, -25, 84, -7, 74),
> -	CABAC_ENTRY(77, -28, 82, -35, 98, -25, 86, -21, 107),
> -	CABAC_ENTRY(78, -20, 94, -24, 102, -12, 89, -27, 127),
> -	CABAC_ENTRY(79, -16, 83, -23, 97, -17, 91, -31, 127),
> -	CABAC_ENTRY(80, -22, 110, -27, 119, -31, 127, -24, 127),
> -	CABAC_ENTRY(81, -21, 91, -24, 99, -14, 76, -18, 95),
> -	CABAC_ENTRY(82, -18, 102, -21, 110, -18, 103, -27, 127),
> -	CABAC_ENTRY(83, -13, 93, -18, 102, -13, 90, -21, 114),
> -	CABAC_ENTRY(84, -29, 127, -36, 127, -37, 127, -30, 127),
> -	CABAC_ENTRY(85, -7, 92, 0, 80, 11, 80, -17, 123),
> -	CABAC_ENTRY(86, -5, 89, -5, 89, 5, 76, -12, 115),
> -	CABAC_ENTRY(87, -7, 96, -7, 94, 2, 84, -16, 122),
> -	CABAC_ENTRY(88, -13, 108, -4, 92, 5, 78, -11, 115),
> -	CABAC_ENTRY(89, -3, 46, 0, 39, -6, 55, -12, 63),
> -	CABAC_ENTRY(90, -1, 65, 0, 65, 4, 61, -2, 68),
> -	CABAC_ENTRY(91, -1, 57, -15, 84, -14, 83, -15, 84),
> -	CABAC_ENTRY(92, -9, 93, -35, 127, -37, 127, -13, 104),
> -	CABAC_ENTRY(93, -3, 74, -2, 73, -5, 79, -3, 70),
> -	CABAC_ENTRY(94, -9, 92, -12, 104, -11, 104, -8, 93),
> -	CABAC_ENTRY(95, -8, 87, -9, 91, -11, 91, -10, 90),
> -	CABAC_ENTRY(96, -23, 126, -31, 127, -30, 127, -30, 127),
> -	CABAC_ENTRY(97, 5, 54, 3, 55, 0, 65, -1, 74),
> -	CABAC_ENTRY(98, 6, 60, 7, 56, -2, 79, -6, 97),
> -	CABAC_ENTRY(99, 6, 59, 7, 55, 0, 72, -7, 91),
> -	CABAC_ENTRY(100, 6, 69, 8, 61, -4, 92, -20, 127),
> -	CABAC_ENTRY(101, -1, 48, -3, 53, -6, 56, -4, 56),
> -	CABAC_ENTRY(102, 0, 68, 0, 68, 3, 68, -5, 82),
> -	CABAC_ENTRY(103, -4, 69, -7, 74, -8, 71, -7, 76),
> -	CABAC_ENTRY(104, -8, 88, -9, 88, -13, 98, -22, 125),
> -
> -	/* Table 9-19 ? Values of variables m and n for ctxIdx from 105 to 165 */
> -	CABAC_ENTRY(105, -2, 85, -13, 103, -4, 86, -7, 93),
> -	CABAC_ENTRY(106, -6, 78, -13, 91, -12, 88, -11, 87),
> -	CABAC_ENTRY(107, -1, 75, -9, 89, -5, 82, -3, 77),
> -	CABAC_ENTRY(108, -7, 77, -14, 92, -3, 72, -5, 71),
> -	CABAC_ENTRY(109, 2, 54, -8, 76, -4, 67, -4, 63),
> -	CABAC_ENTRY(110, 5, 50, -12, 87, -8, 72, -4, 68),
> -	CABAC_ENTRY(111, -3, 68, -23, 110, -16, 89, -12, 84),
> -	CABAC_ENTRY(112, 1, 50, -24, 105, -9, 69, -7, 62),
> -	CABAC_ENTRY(113, 6, 42, -10, 78, -1, 59, -7, 65),
> -	CABAC_ENTRY(114, -4, 81, -20, 112, 5, 66, 8, 61),
> -	CABAC_ENTRY(115, 1, 63, -17, 99, 4, 57, 5, 56),
> -	CABAC_ENTRY(116, -4, 70, -78, 127, -4, 71, -2, 66),
> -	CABAC_ENTRY(117, 0, 67, -70, 127, -2, 71, 1, 64),
> -	CABAC_ENTRY(118, 2, 57, -50, 127, 2, 58, 0, 61),
> -	CABAC_ENTRY(119, -2, 76, -46, 127, -1, 74, -2, 78),
> -	CABAC_ENTRY(120, 11, 35, -4, 66, -4, 44, 1, 50),
> -	CABAC_ENTRY(121, 4, 64, -5, 78, -1, 69, 7, 52),
> -	CABAC_ENTRY(122, 1, 61, -4, 71, 0, 62, 10, 35),
> -	CABAC_ENTRY(123, 11, 35, -8, 72, -7, 51, 0, 44),
> -	CABAC_ENTRY(124, 18, 25, 2, 59, -4, 47, 11, 38),
> -	CABAC_ENTRY(125, 12, 24, -1, 55, -6, 42, 1, 45),
> -	CABAC_ENTRY(126, 13, 29, -7, 70, -3, 41, 0, 46),
> -	CABAC_ENTRY(127, 13, 36, -6, 75, -6, 53, 5, 44),
> -	CABAC_ENTRY(128, -10, 93, -8, 89, 8, 76, 31, 17),
> -	CABAC_ENTRY(129, -7, 73, -34, 119, -9, 78, 1, 51),
> -	CABAC_ENTRY(130, -2, 73, -3, 75, -11, 83, 7, 50),
> -	CABAC_ENTRY(131, 13, 46, 32, 20, 9, 52, 28, 19),
> -	CABAC_ENTRY(132, 9, 49, 30, 22, 0, 67, 16, 33),
> -	CABAC_ENTRY(133, -7, 100, -44, 127, -5, 90, 14, 62),
> -	CABAC_ENTRY(134, 9, 53, 0, 54, 1, 67, -13, 108),
> -	CABAC_ENTRY(135, 2, 53, -5, 61, -15, 72, -15, 100),
> -	CABAC_ENTRY(136, 5, 53, 0, 58, -5, 75, -13, 101),
> -	CABAC_ENTRY(137, -2, 61, -1, 60, -8, 80, -13, 91),
> -	CABAC_ENTRY(138, 0, 56, -3, 61, -21, 83, -12, 94),
> -	CABAC_ENTRY(139, 0, 56, -8, 67, -21, 64, -10, 88),
> -	CABAC_ENTRY(140, -13, 63, -25, 84, -13, 31, -16, 84),
> -	CABAC_ENTRY(141, -5, 60, -14, 74, -25, 64, -10, 86),
> -	CABAC_ENTRY(142, -1, 62, -5, 65, -29, 94, -7, 83),
> -	CABAC_ENTRY(143, 4, 57, 5, 52, 9, 75, -13, 87),
> -	CABAC_ENTRY(144, -6, 69, 2, 57, 17, 63, -19, 94),
> -	CABAC_ENTRY(145, 4, 57, 0, 61, -8, 74, 1, 70),
> -	CABAC_ENTRY(146, 14, 39, -9, 69, -5, 35, 0, 72),
> -	CABAC_ENTRY(147, 4, 51, -11, 70, -2, 27, -5, 74),
> -	CABAC_ENTRY(148, 13, 68, 18, 55, 13, 91, 18, 59),
> -	CABAC_ENTRY(149, 3, 64, -4, 71, 3, 65, -8, 102),
> -	CABAC_ENTRY(150, 1, 61, 0, 58, -7, 69, -15, 100),
> -	CABAC_ENTRY(151, 9, 63, 7, 61, 8, 77, 0, 95),
> -	CABAC_ENTRY(152, 7, 50, 9, 41, -10, 66, -4, 75),
> -	CABAC_ENTRY(153, 16, 39, 18, 25, 3, 62, 2, 72),
> -	CABAC_ENTRY(154, 5, 44, 9, 32, -3, 68, -11, 75),
> -	CABAC_ENTRY(155, 4, 52, 5, 43, -20, 81, -3, 71),
> -	CABAC_ENTRY(156, 11, 48, 9, 47, 0, 30, 15, 46),
> -	CABAC_ENTRY(157, -5, 60, 0, 44, 1, 7, -13, 69),
> -	CABAC_ENTRY(158, -1, 59, 0, 51, -3, 23, 0, 62),
> -	CABAC_ENTRY(159, 0, 59, 2, 46, -21, 74, 0, 65),
> -	CABAC_ENTRY(160, 22, 33, 19, 38, 16, 66, 21, 37),
> -	CABAC_ENTRY(161, 5, 44, -4, 66, -23, 124, -15, 72),
> -	CABAC_ENTRY(162, 14, 43, 15, 38, 17, 37, 9, 57),
> -	CABAC_ENTRY(163, -1, 78, 12, 42, 44, -18, 16, 54),
> -	CABAC_ENTRY(164, 0, 60, 9, 34, 50, -34, 0, 62),
> -	CABAC_ENTRY(165, 9, 69, 0, 89, -22, 127, 12, 72),
> -
> -	/* Table 9-20 ? Values of variables m and n for ctxIdx from 166 to 226 */
> -	CABAC_ENTRY(166, 11, 28, 4, 45, 4, 39, 24, 0),
> -	CABAC_ENTRY(167, 2, 40, 10, 28, 0, 42, 15, 9),
> -	CABAC_ENTRY(168, 3, 44, 10, 31, 7, 34, 8, 25),
> -	CABAC_ENTRY(169, 0, 49, 33, -11, 11, 29, 13, 18),
> -	CABAC_ENTRY(170, 0, 46, 52, -43, 8, 31, 15, 9),
> -	CABAC_ENTRY(171, 2, 44, 18, 15, 6, 37, 13, 19),
> -	CABAC_ENTRY(172, 2, 51, 28, 0, 7, 42, 10, 37),
> -	CABAC_ENTRY(173, 0, 47, 35, -22, 3, 40, 12, 18),
> -	CABAC_ENTRY(174, 4, 39, 38, -25, 8, 33, 6, 29),
> -	CABAC_ENTRY(175, 2, 62, 34, 0, 13, 43, 20, 33),
> -	CABAC_ENTRY(176, 6, 46, 39, -18, 13, 36, 15, 30),
> -	CABAC_ENTRY(177, 0, 54, 32, -12, 4, 47, 4, 45),
> -	CABAC_ENTRY(178, 3, 54, 102, -94, 3, 55, 1, 58),
> -	CABAC_ENTRY(179, 2, 58, 0, 0, 2, 58, 0, 62),
> -	CABAC_ENTRY(180, 4, 63, 56, -15, 6, 60, 7, 61),
> -	CABAC_ENTRY(181, 6, 51, 33, -4, 8, 44, 12, 38),
> -	CABAC_ENTRY(182, 6, 57, 29, 10, 11, 44, 11, 45),
> -	CABAC_ENTRY(183, 7, 53, 37, -5, 14, 42, 15, 39),
> -	CABAC_ENTRY(184, 6, 52, 51, -29, 7, 48, 11, 42),
> -	CABAC_ENTRY(185, 6, 55, 39, -9, 4, 56, 13, 44),
> -	CABAC_ENTRY(186, 11, 45, 52, -34, 4, 52, 16, 45),
> -	CABAC_ENTRY(187, 14, 36, 69, -58, 13, 37, 12, 41),
> -	CABAC_ENTRY(188, 8, 53, 67, -63, 9, 49, 10, 49),
> -	CABAC_ENTRY(189, -1, 82, 44, -5, 19, 58, 30, 34),
> -	CABAC_ENTRY(190, 7, 55, 32, 7, 10, 48, 18, 42),
> -	CABAC_ENTRY(191, -3, 78, 55, -29, 12, 45, 10, 55),
> -	CABAC_ENTRY(192, 15, 46, 32, 1, 0, 69, 17, 51),
> -	CABAC_ENTRY(193, 22, 31, 0, 0, 20, 33, 17, 46),
> -	CABAC_ENTRY(194, -1, 84, 27, 36, 8, 63, 0, 89),
> -	CABAC_ENTRY(195, 25, 7, 33, -25, 35, -18, 26, -19),
> -	CABAC_ENTRY(196, 30, -7, 34, -30, 33, -25, 22, -17),
> -	CABAC_ENTRY(197, 28, 3, 36, -28, 28, -3, 26, -17),
> -	CABAC_ENTRY(198, 28, 4, 38, -28, 24, 10, 30, -25),
> -	CABAC_ENTRY(199, 32, 0, 38, -27, 27, 0, 28, -20),
> -	CABAC_ENTRY(200, 34, -1, 34, -18, 34, -14, 33, -23),
> -	CABAC_ENTRY(201, 30, 6, 35, -16, 52, -44, 37, -27),
> -	CABAC_ENTRY(202, 30, 6, 34, -14, 39, -24, 33, -23),
> -	CABAC_ENTRY(203, 32, 9, 32, -8, 19, 17, 40, -28),
> -	CABAC_ENTRY(204, 31, 19, 37, -6, 31, 25, 38, -17),
> -	CABAC_ENTRY(205, 26, 27, 35, 0, 36, 29, 33, -11),
> -	CABAC_ENTRY(206, 26, 30, 30, 10, 24, 33, 40, -15),
> -	CABAC_ENTRY(207, 37, 20, 28, 18, 34, 15, 41, -6),
> -	CABAC_ENTRY(208, 28, 34, 26, 25, 30, 20, 38, 1),
> -	CABAC_ENTRY(209, 17, 70, 29, 41, 22, 73, 41, 17),
> -	CABAC_ENTRY(210, 1, 67, 0, 75, 20, 34, 30, -6),
> -	CABAC_ENTRY(211, 5, 59, 2, 72, 19, 31, 27, 3),
> -	CABAC_ENTRY(212, 9, 67, 8, 77, 27, 44, 26, 22),
> -	CABAC_ENTRY(213, 16, 30, 14, 35, 19, 16, 37, -16),
> -	CABAC_ENTRY(214, 18, 32, 18, 31, 15, 36, 35, -4),
> -	CABAC_ENTRY(215, 18, 35, 17, 35, 15, 36, 38, -8),
> -	CABAC_ENTRY(216, 22, 29, 21, 30, 21, 28, 38, -3),
> -	CABAC_ENTRY(217, 24, 31, 17, 45, 25, 21, 37, 3),
> -	CABAC_ENTRY(218, 23, 38, 20, 42, 30, 20, 38, 5),
> -	CABAC_ENTRY(219, 18, 43, 18, 45, 31, 12, 42, 0),
> -	CABAC_ENTRY(220, 20, 41, 27, 26, 27, 16, 35, 16),
> -	CABAC_ENTRY(221, 11, 63, 16, 54, 24, 42, 39, 22),
> -	CABAC_ENTRY(222, 9, 59, 7, 66, 0, 93, 14, 48),
> -	CABAC_ENTRY(223, 9, 64, 16, 56, 14, 56, 27, 37),
> -	CABAC_ENTRY(224, -1, 94, 11, 73, 15, 57, 21, 60),
> -	CABAC_ENTRY(225, -2, 89, 10, 67, 26, 38, 12, 68),
> -	CABAC_ENTRY(226, -9, 108, -10, 116, -24, 127, 2, 97),
> -
> -	/* Table 9-21 ? Values of variables m and n for ctxIdx from 227 to 275 */
> -	CABAC_ENTRY(227, -6, 76, -23, 112, -24, 115, -3, 71),
> -	CABAC_ENTRY(228, -2, 44, -15, 71, -22, 82, -6, 42),
> -	CABAC_ENTRY(229, 0, 45, -7, 61, -9, 62, -5, 50),
> -	CABAC_ENTRY(230, 0, 52, 0, 53, 0, 53, -3, 54),
> -	CABAC_ENTRY(231, -3, 64, -5, 66, 0, 59, -2, 62),
> -	CABAC_ENTRY(232, -2, 59, -11, 77, -14, 85, 0, 58),
> -	CABAC_ENTRY(233, -4, 70, -9, 80, -13, 89, 1, 63),
> -	CABAC_ENTRY(234, -4, 75, -9, 84, -13, 94, -2, 72),
> -	CABAC_ENTRY(235, -8, 82, -10, 87, -11, 92, -1, 74),
> -	CABAC_ENTRY(236, -17, 102, -34, 127, -29, 127, -9, 91),
> -	CABAC_ENTRY(237, -9, 77, -21, 101, -21, 100, -5, 67),
> -	CABAC_ENTRY(238, 3, 24, -3, 39, -14, 57, -5, 27),
> -	CABAC_ENTRY(239, 0, 42, -5, 53, -12, 67, -3, 39),
> -	CABAC_ENTRY(240, 0, 48, -7, 61, -11, 71, -2, 44),
> -	CABAC_ENTRY(241, 0, 55, -11, 75, -10, 77, 0, 46),
> -	CABAC_ENTRY(242, -6, 59, -15, 77, -21, 85, -16, 64),
> -	CABAC_ENTRY(243, -7, 71, -17, 91, -16, 88, -8, 68),
> -	CABAC_ENTRY(244, -12, 83, -25, 107, -23, 104, -10, 78),
> -	CABAC_ENTRY(245, -11, 87, -25, 111, -15, 98, -6, 77),
> -	CABAC_ENTRY(246, -30, 119, -28, 122, -37, 127, -10, 86),
> -	CABAC_ENTRY(247, 1, 58, -11, 76, -10, 82, -12, 92),
> -	CABAC_ENTRY(248, -3, 29, -10, 44, -8, 48, -15, 55),
> -	CABAC_ENTRY(249, -1, 36, -10, 52, -8, 61, -10, 60),
> -	CABAC_ENTRY(250, 1, 38, -10, 57, -8, 66, -6, 62),
> -	CABAC_ENTRY(251, 2, 43, -9, 58, -7, 70, -4, 65),
> -	CABAC_ENTRY(252, -6, 55, -16, 72, -14, 75, -12, 73),
> -	CABAC_ENTRY(253, 0, 58, -7, 69, -10, 79, -8, 76),
> -	CABAC_ENTRY(254, 0, 64, -4, 69, -9, 83, -7, 80),
> -	CABAC_ENTRY(255, -3, 74, -5, 74, -12, 92, -9, 88),
> -	CABAC_ENTRY(256, -10, 90, -9, 86, -18, 108, -17, 110),
> -	CABAC_ENTRY(257, 0, 70, 2, 66, -4, 79, -11, 97),
> -	CABAC_ENTRY(258, -4, 29, -9, 34, -22, 69, -20, 84),
> -	CABAC_ENTRY(259, 5, 31, 1, 32, -16, 75, -11, 79),
> -	CABAC_ENTRY(260, 7, 42, 11, 31, -2, 58, -6, 73),
> -	CABAC_ENTRY(261, 1, 59, 5, 52, 1, 58, -4, 74),
> -	CABAC_ENTRY(262, -2, 58, -2, 55, -13, 78, -13, 86),
> -	CABAC_ENTRY(263, -3, 72, -2, 67, -9, 83, -13, 96),
> -	CABAC_ENTRY(264, -3, 81, 0, 73, -4, 81, -11, 97),
> -	CABAC_ENTRY(265, -11, 97, -8, 89, -13, 99, -19, 117),
> -	CABAC_ENTRY(266, 0, 58, 3, 52, -13, 81, -8, 78),
> -	CABAC_ENTRY(267, 8, 5, 7, 4, -6, 38, -5, 33),
> -	CABAC_ENTRY(268, 10, 14, 10, 8, -13, 62, -4, 48),
> -	CABAC_ENTRY(269, 14, 18, 17, 8, -6, 58, -2, 53),
> -	CABAC_ENTRY(270, 13, 27, 16, 19, -2, 59, -3, 62),
> -	CABAC_ENTRY(271, 2, 40, 3, 37, -16, 73, -13, 71),
> -	CABAC_ENTRY(272, 0, 58, -1, 61, -10, 76, -10, 79),
> -	CABAC_ENTRY(273, -3, 70, -5, 73, -13, 86, -12, 86),
> -	CABAC_ENTRY(274, -6, 79, -1, 70, -9, 83, -13, 90),
> -	CABAC_ENTRY(275, -8, 85, -4, 78, -10, 87, -14, 97),
> -
> -	/* Table 9-22 ? Values of variables m and n for ctxIdx from 277 to 337 */
> -	CABAC_ENTRY(277, -13, 106, -21, 126, -22, 127, -6, 93),
> -	CABAC_ENTRY(278, -16, 106, -23, 124, -25, 127, -6, 84),
> -	CABAC_ENTRY(279, -10, 87, -20, 110, -25, 120, -8, 79),
> -	CABAC_ENTRY(280, -21, 114, -26, 126, -27, 127, 0, 66),
> -	CABAC_ENTRY(281, -18, 110, -25, 124, -19, 114, -1, 71),
> -	CABAC_ENTRY(282, -14, 98, -17, 105, -23, 117, 0, 62),
> -	CABAC_ENTRY(283, -22, 110, -27, 121, -25, 118, -2, 60),
> -	CABAC_ENTRY(284, -21, 106, -27, 117, -26, 117, -2, 59),
> -	CABAC_ENTRY(285, -18, 103, -17, 102, -24, 113, -5, 75),
> -	CABAC_ENTRY(286, -21, 107, -26, 117, -28, 118, -3, 62),
> -	CABAC_ENTRY(287, -23, 108, -27, 116, -31, 120, -4, 58),
> -	CABAC_ENTRY(288, -26, 112, -33, 122, -37, 124, -9, 66),
> -	CABAC_ENTRY(289, -10, 96, -10, 95, -10, 94, -1, 79),
> -	CABAC_ENTRY(290, -12, 95, -14, 100, -15, 102, 0, 71),
> -	CABAC_ENTRY(291, -5, 91, -8, 95, -10, 99, 3, 68),
> -	CABAC_ENTRY(292, -9, 93, -17, 111, -13, 106, 10, 44),
> -	CABAC_ENTRY(293, -22, 94, -28, 114, -50, 127, -7, 62),
> -	CABAC_ENTRY(294, -5, 86, -6, 89, -5, 92, 15, 36),
> -	CABAC_ENTRY(295, 9, 67, -2, 80, 17, 57, 14, 40),
> -	CABAC_ENTRY(296, -4, 80, -4, 82, -5, 86, 16, 27),
> -	CABAC_ENTRY(297, -10, 85, -9, 85, -13, 94, 12, 29),
> -	CABAC_ENTRY(298, -1, 70, -8, 81, -12, 91, 1, 44),
> -	CABAC_ENTRY(299, 7, 60, -1, 72, -2, 77, 20, 36),
> -	CABAC_ENTRY(300, 9, 58, 5, 64, 0, 71, 18, 32),
> -	CABAC_ENTRY(301, 5, 61, 1, 67, -1, 73, 5, 42),
> -	CABAC_ENTRY(302, 12, 50, 9, 56, 4, 64, 1, 48),
> -	CABAC_ENTRY(303, 15, 50, 0, 69, -7, 81, 10, 62),
> -	CABAC_ENTRY(304, 18, 49, 1, 69, 5, 64, 17, 46),
> -	CABAC_ENTRY(305, 17, 54, 7, 69, 15, 57, 9, 64),
> -	CABAC_ENTRY(306, 10, 41, -7, 69, 1, 67, -12, 104),
> -	CABAC_ENTRY(307, 7, 46, -6, 67, 0, 68, -11, 97),
> -	CABAC_ENTRY(308, -1, 51, -16, 77, -10, 67, -16, 96),
> -	CABAC_ENTRY(309, 7, 49, -2, 64, 1, 68, -7, 88),
> -	CABAC_ENTRY(310, 8, 52, 2, 61, 0, 77, -8, 85),
> -	CABAC_ENTRY(311, 9, 41, -6, 67, 2, 64, -7, 85),
> -	CABAC_ENTRY(312, 6, 47, -3, 64, 0, 68, -9, 85),
> -	CABAC_ENTRY(313, 2, 55, 2, 57, -5, 78, -13, 88),
> -	CABAC_ENTRY(314, 13, 41, -3, 65, 7, 55, 4, 66),
> -	CABAC_ENTRY(315, 10, 44, -3, 66, 5, 59, -3, 77),
> -	CABAC_ENTRY(316, 6, 50, 0, 62, 2, 65, -3, 76),
> -	CABAC_ENTRY(317, 5, 53, 9, 51, 14, 54, -6, 76),
> -	CABAC_ENTRY(318, 13, 49, -1, 66, 15, 44, 10, 58),
> -	CABAC_ENTRY(319, 4, 63, -2, 71, 5, 60, -1, 76),
> -	CABAC_ENTRY(320, 6, 64, -2, 75, 2, 70, -1, 83),
> -	CABAC_ENTRY(321, -2, 69, -1, 70, -2, 76, -7, 99),
> -	CABAC_ENTRY(322, -2, 59, -9, 72, -18, 86, -14, 95),
> -	CABAC_ENTRY(323, 6, 70, 14, 60, 12, 70, 2, 95),
> -	CABAC_ENTRY(324, 10, 44, 16, 37, 5, 64, 0, 76),
> -	CABAC_ENTRY(325, 9, 31, 0, 47, -12, 70, -5, 74),
> -	CABAC_ENTRY(326, 12, 43, 18, 35, 11, 55, 0, 70),
> -	CABAC_ENTRY(327, 3, 53, 11, 37, 5, 56, -11, 75),
> -	CABAC_ENTRY(328, 14, 34, 12, 41, 0, 69, 1, 68),
> -	CABAC_ENTRY(329, 10, 38, 10, 41, 2, 65, 0, 65),
> -	CABAC_ENTRY(330, -3, 52, 2, 48, -6, 74, -14, 73),
> -	CABAC_ENTRY(331, 13, 40, 12, 41, 5, 54, 3, 62),
> -	CABAC_ENTRY(332, 17, 32, 13, 41, 7, 54, 4, 62),
> -	CABAC_ENTRY(333, 7, 44, 0, 59, -6, 76, -1, 68),
> -	CABAC_ENTRY(334, 7, 38, 3, 50, -11, 82, -13, 75),
> -	CABAC_ENTRY(335, 13, 50, 19, 40, -2, 77, 11, 55),
> -	CABAC_ENTRY(336, 10, 57, 3, 66, -2, 77, 5, 64),
> -	CABAC_ENTRY(337, 26, 43, 18, 50, 25, 42, 12, 70),
> -
> -	/* Table 9-23 ? Values of variables m and n for ctxIdx from 338 to 398 */
> -	CABAC_ENTRY(338, 14, 11, 19, -6, 17, -13, 15, 6),
> -	CABAC_ENTRY(339, 11, 14, 18, -6, 16, -9, 6, 19),
> -	CABAC_ENTRY(340, 9, 11, 14, 0, 17, -12, 7, 16),
> -	CABAC_ENTRY(341, 18, 11, 26, -12, 27, -21, 12, 14),
> -	CABAC_ENTRY(342, 21, 9, 31, -16, 37, -30, 18, 13),
> -	CABAC_ENTRY(343, 23, -2, 33, -25, 41, -40, 13, 11),
> -	CABAC_ENTRY(344, 32, -15, 33, -22, 42, -41, 13, 15),
> -	CABAC_ENTRY(345, 32, -15, 37, -28, 48, -47, 15, 16),
> -	CABAC_ENTRY(346, 34, -21, 39, -30, 39, -32, 12, 23),
> -	CABAC_ENTRY(347, 39, -23, 42, -30, 46, -40, 13, 23),
> -	CABAC_ENTRY(348, 42, -33, 47, -42, 52, -51, 15, 20),
> -	CABAC_ENTRY(349, 41, -31, 45, -36, 46, -41, 14, 26),
> -	CABAC_ENTRY(350, 46, -28, 49, -34, 52, -39, 14, 44),
> -	CABAC_ENTRY(351, 38, -12, 41, -17, 43, -19, 17, 40),
> -	CABAC_ENTRY(352, 21, 29, 32, 9, 32, 11, 17, 47),
> -	CABAC_ENTRY(353, 45, -24, 69, -71, 61, -55, 24, 17),
> -	CABAC_ENTRY(354, 53, -45, 63, -63, 56, -46, 21, 21),
> -	CABAC_ENTRY(355, 48, -26, 66, -64, 62, -50, 25, 22),
> -	CABAC_ENTRY(356, 65, -43, 77, -74, 81, -67, 31, 27),
> -	CABAC_ENTRY(357, 43, -19, 54, -39, 45, -20, 22, 29),
> -	CABAC_ENTRY(358, 39, -10, 52, -35, 35, -2, 19, 35),
> -	CABAC_ENTRY(359, 30, 9, 41, -10, 28, 15, 14, 50),
> -	CABAC_ENTRY(360, 18, 26, 36, 0, 34, 1, 10, 57),
> -	CABAC_ENTRY(361, 20, 27, 40, -1, 39, 1, 7, 63),
> -	CABAC_ENTRY(362, 0, 57, 30, 14, 30, 17, -2, 77),
> -	CABAC_ENTRY(363, -14, 82, 28, 26, 20, 38, -4, 82),
> -	CABAC_ENTRY(364, -5, 75, 23, 37, 18, 45, -3, 94),
> -	CABAC_ENTRY(365, -19, 97, 12, 55, 15, 54, 9, 69),
> -	CABAC_ENTRY(366, -35, 125, 11, 65, 0, 79, -12, 109),
> -	CABAC_ENTRY(367, 27, 0, 37, -33, 36, -16, 36, -35),
> -	CABAC_ENTRY(368, 28, 0, 39, -36, 37, -14, 36, -34),
> -	CABAC_ENTRY(369, 31, -4, 40, -37, 37, -17, 32, -26),
> -	CABAC_ENTRY(370, 27, 6, 38, -30, 32, 1, 37, -30),
> -	CABAC_ENTRY(371, 34, 8, 46, -33, 34, 15, 44, -32),
> -	CABAC_ENTRY(372, 30, 10, 42, -30, 29, 15, 34, -18),
> -	CABAC_ENTRY(373, 24, 22, 40, -24, 24, 25, 34, -15),
> -	CABAC_ENTRY(374, 33, 19, 49, -29, 34, 22, 40, -15),
> -	CABAC_ENTRY(375, 22, 32, 38, -12, 31, 16, 33, -7),
> -	CABAC_ENTRY(376, 26, 31, 40, -10, 35, 18, 35, -5),
> -	CABAC_ENTRY(377, 21, 41, 38, -3, 31, 28, 33, 0),
> -	CABAC_ENTRY(378, 26, 44, 46, -5, 33, 41, 38, 2),
> -	CABAC_ENTRY(379, 23, 47, 31, 20, 36, 28, 33, 13),
> -	CABAC_ENTRY(380, 16, 65, 29, 30, 27, 47, 23, 35),
> -	CABAC_ENTRY(381, 14, 71, 25, 44, 21, 62, 13, 58),
> -	CABAC_ENTRY(382, 8, 60, 12, 48, 18, 31, 29, -3),
> -	CABAC_ENTRY(383, 6, 63, 11, 49, 19, 26, 26, 0),
> -	CABAC_ENTRY(384, 17, 65, 26, 45, 36, 24, 22, 30),
> -	CABAC_ENTRY(385, 21, 24, 22, 22, 24, 23, 31, -7),
> -	CABAC_ENTRY(386, 23, 20, 23, 22, 27, 16, 35, -15),
> -	CABAC_ENTRY(387, 26, 23, 27, 21, 24, 30, 34, -3),
> -	CABAC_ENTRY(388, 27, 32, 33, 20, 31, 29, 34, 3),
> -	CABAC_ENTRY(389, 28, 23, 26, 28, 22, 41, 36, -1),
> -	CABAC_ENTRY(390, 28, 24, 30, 24, 22, 42, 34, 5),
> -	CABAC_ENTRY(391, 23, 40, 27, 34, 16, 60, 32, 11),
> -	CABAC_ENTRY(392, 24, 32, 18, 42, 15, 52, 35, 5),
> -	CABAC_ENTRY(393, 28, 29, 25, 39, 14, 60, 34, 12),
> -	CABAC_ENTRY(394, 23, 42, 18, 50, 3, 78, 39, 11),
> -	CABAC_ENTRY(395, 19, 57, 12, 70, -16, 123, 30, 29),
> -	CABAC_ENTRY(396, 22, 53, 21, 54, 21, 53, 34, 26),
> -	CABAC_ENTRY(397, 22, 61, 14, 71, 22, 56, 29, 39),
> -	CABAC_ENTRY(398, 11, 86, 11, 83, 25, 61, 19, 66),
> -
> -	/* Values of variables m and n for ctxIdx from 399 to 463 (not documented) */
> -	CABAC_ENTRY(399, 12, 40, 25, 32, 21, 33, 31, 21),
> -	CABAC_ENTRY(400, 11, 51, 21, 49, 19, 50, 31, 31),
> -	CABAC_ENTRY(401, 14, 59, 21, 54, 17, 61, 25, 50),
> -	CABAC_ENTRY(402, -4, 79, -5, 85, -3, 78, -17, 120),
> -	CABAC_ENTRY(403, -7, 71, -6, 81, -8, 74, -20, 112),
> -	CABAC_ENTRY(404, -5, 69, -10, 77, -9, 72, -18, 114),
> -	CABAC_ENTRY(405, -9, 70, -7, 81, -10, 72, -11, 85),
> -	CABAC_ENTRY(406, -8, 66, -17, 80, -18, 75, -15, 92),
> -	CABAC_ENTRY(407, -10, 68, -18, 73, -12, 71, -14, 89),
> -	CABAC_ENTRY(408, -19, 73, -4, 74, -11, 63, -26, 71),
> -	CABAC_ENTRY(409, -12, 69, -10, 83, -5, 70, -15, 81),
> -	CABAC_ENTRY(410, -16, 70, -9, 71, -17, 75, -14, 80),
> -	CABAC_ENTRY(411, -15, 67, -9, 67, -14, 72, 0, 68),
> -	CABAC_ENTRY(412, -20, 62, -1, 61, -16, 67, -14, 70),
> -	CABAC_ENTRY(413, -19, 70, -8, 66, -8, 53, -24, 56),
> -	CABAC_ENTRY(414, -16, 66, -14, 66, -14, 59, -23, 68),
> -	CABAC_ENTRY(415, -22, 65, 0, 59, -9, 52, -24, 50),
> -	CABAC_ENTRY(416, -20, 63, 2, 59, -11, 68, -11, 74),
> -	CABAC_ENTRY(417, 9, -2, 17, -10, 9, -2, 23, -13),
> -	CABAC_ENTRY(418, 26, -9, 32, -13, 30, -10, 26, -13),
> -	CABAC_ENTRY(419, 33, -9, 42, -9, 31, -4, 40, -15),
> -	CABAC_ENTRY(420, 39, -7, 49, -5, 33, -1, 49, -14),
> -	CABAC_ENTRY(421, 41, -2, 53, 0, 33, 7, 44, 3),
> -	CABAC_ENTRY(422, 45, 3, 64, 3, 31, 12, 45, 6),
> -	CABAC_ENTRY(423, 49, 9, 68, 10, 37, 23, 44, 34),
> -	CABAC_ENTRY(424, 45, 27, 66, 27, 31, 38, 33, 54),
> -	CABAC_ENTRY(425, 36, 59, 47, 57, 20, 64, 19, 82),
> -	CABAC_ENTRY(426, -6, 66, -5, 71, -9, 71, -3, 75),
> -	CABAC_ENTRY(427, -7, 35, 0, 24, -7, 37, -1, 23),
> -	CABAC_ENTRY(428, -7, 42, -1, 36, -8, 44, 1, 34),
> -	CABAC_ENTRY(429, -8, 45, -2, 42, -11, 49, 1, 43),
> -	CABAC_ENTRY(430, -5, 48, -2, 52, -10, 56, 0, 54),
> -	CABAC_ENTRY(431, -12, 56, -9, 57, -12, 59, -2, 55),
> -	CABAC_ENTRY(432, -6, 60, -6, 63, -8, 63, 0, 61),
> -	CABAC_ENTRY(433, -5, 62, -4, 65, -9, 67, 1, 64),
> -	CABAC_ENTRY(434, -8, 66, -4, 67, -6, 68, 0, 68),
> -	CABAC_ENTRY(435, -8, 76, -7, 82, -10, 79, -9, 92),
> -	CABAC_ENTRY(436, -5, 85, -3, 81, -3, 78, -14, 106),
> -	CABAC_ENTRY(437, -6, 81, -3, 76, -8, 74, -13, 97),
> -	CABAC_ENTRY(438, -10, 77, -7, 72, -9, 72, -15, 90),
> -	CABAC_ENTRY(439, -7, 81, -6, 78, -10, 72, -12, 90),
> -	CABAC_ENTRY(440, -17, 80, -12, 72, -18, 75, -18, 88),
> -	CABAC_ENTRY(441, -18, 73, -14, 68, -12, 71, -10, 73),
> -	CABAC_ENTRY(442, -4, 74, -3, 70, -11, 63, -9, 79),
> -	CABAC_ENTRY(443, -10, 83, -6, 76, -5, 70, -14, 86),
> -	CABAC_ENTRY(444, -9, 71, -5, 66, -17, 75, -10, 73),
> -	CABAC_ENTRY(445, -9, 67, -5, 62, -14, 72, -10, 70),
> -	CABAC_ENTRY(446, -1, 61, 0, 57, -16, 67, -10, 69),
> -	CABAC_ENTRY(447, -8, 66, -4, 61, -8, 53, -5, 66),
> -	CABAC_ENTRY(448, -14, 66, -9, 60, -14, 59, -9, 64),
> -	CABAC_ENTRY(449, 0, 59, 1, 54, -9, 52, -5, 58),
> -	CABAC_ENTRY(450, 2, 59, 2, 58, -11, 68, 2, 59),
> -	CABAC_ENTRY(451, 21, -13, 17, -10, 9, -2, 21, -10),
> -	CABAC_ENTRY(452, 33, -14, 32, -13, 30, -10, 24, -11),
> -	CABAC_ENTRY(453, 39, -7, 42, -9, 31, -4, 28, -8),
> -	CABAC_ENTRY(454, 46, -2, 49, -5, 33, -1, 28, -1),
> -	CABAC_ENTRY(455, 51, 2, 53, 0, 33, 7, 29, 3),
> -	CABAC_ENTRY(456, 60, 6, 64, 3, 31, 12, 29, 9),
> -	CABAC_ENTRY(457, 61, 17, 68, 10, 37, 23, 35, 20),
> -	CABAC_ENTRY(458, 55, 34, 66, 27, 31, 38, 29, 36),
> -	CABAC_ENTRY(459, 42, 62, 47, 57, 20, 64, 14, 67),
> -};
> -
> ?static void set_ps_field(u32 *buf, struct rkvdec_ps_field field, u32 value)
> ?{
> ?	u8 bit = field.offset % 32, word = field.offset / 32;
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
> index 01f92fa27356..b01c1bb52a04 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
> @@ -16,7 +16,6 @@
> ?
> ?#include "rkvdec.h"
> ?#include "rkvdec-regs.h"
> -#include "rkvdec-hevc-data.c"
> ?
> ?/* Size in u8/u32 units. */
> ?#define RKV_SCALING_LIST_SIZE		1360
> @@ -25,6 +24,9 @@
> ?#define RKV_RPS_SIZE			(32 / 4)
> ?#define RKV_RPS_LEN			600
> ?
> +#define RKV_HEVC_CABAC_TABLE_SIZE		27456
> +extern const u8 rkvdec_hevc_cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
> +
> ?struct rkvdec_sps_pps_packet {
> ?	u32 info[RKV_PPS_SIZE];
> ?};
> @@ -110,7 +112,7 @@ struct rkvdec_ps_field {
> ?
> ?/* Data structure describing auxiliary buffer format. */
> ?struct rkvdec_hevc_priv_tbl {
> -	u8 cabac_table[RKV_CABAC_TABLE_SIZE];
> +	u8 cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
> ?	u8 scaling_list[RKV_SCALING_LIST_SIZE];
> ?	struct rkvdec_sps_pps_packet param_set[RKV_PPS_LEN];
> ?	struct rkvdec_rps_packet rps[RKV_RPS_LEN];
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251210/23918aef/attachment-0001.sig>

From BenNiu at meta.com  Wed Dec 10 12:16:17 2025
From: BenNiu at meta.com (Ben Niu)
Date: Wed, 10 Dec 2025 12:16:17 -0800
Subject: Withdraw [PATCH] tracing: Enable kprobe tracing for Arm64 asm
 functions
In-Reply-To: <aRr6Ll7h29dpt7zz@J2N7QTR9R3>
References: <20251027181749.240466-1-benniu@meta.com>
 <aQIltqoIVDwh4A6p@J2N7QTR9R3>
 <aQKpDIYwO9VTP7qM@meta.com>
 <aQNbjap69C6inZwb@J2N7QTR9R3>
 <aQOpd14RXnyQLOWR@meta.com>
 <aRr6Ll7h29dpt7zz@J2N7QTR9R3>
Message-ID: <aTnVEdv2j5ur48aF@meta.com>

On Mon, Nov 17, 2025 at 10:34:22AM +0000, Mark Rutland wrote:
> On Thu, Oct 30, 2025 at 11:07:51AM -0700, Ben Niu wrote:
> > On Thu, Oct 30, 2025 at 12:35:25PM +0000, Mark Rutland wrote:
> > > Is there something specific you want to trace, but cannot currently
> > > trace (on arm64)?
> > 
> > For some reason, we only saw Arm64 Linux asm functions __arch_copy_to_user and
> > __arch_copy_from_user being hot in our workloads, not those counterpart asm
> > functions on x86, so we are trying to understand and improve performance of
> > those Arm64 asm functions.
> 
> Are you sure that's not an artifact of those being out-of-line on arm64,
> but inline on x86? On x86, the out-of-line forms are only used when the
> CPU doesn't have FSRM, and when the CPU *does* have FSRM, the logic gets
> inlined. See raw_copy_from_user(), raw_copy_to_user(), and
> copy_user_generic() in arch/x86/include/asm/uaccess_64.h.

On x86, INLINE_COPY_TO_USER is not defined in the latest linux kernel and our
internal branch, so _copy_to_user is always defined as an extern function
(no-inline), which ends up inlining copy_user_generic. copy_user_generic
executes FSRM rep movs if CPU supports it (our case), otherwise, it calls
rep_movs_alternative, which issues plain movs to copy memory.

FSRM is vectorized internally by the CPU and Arm FEAT_MOPS seems similar to
what FSRM does, but Neoverse V2 does not support FEAT_MOPS so the kernel
resorts to sttr to copy memory.

> Have you checked that inlining is not skewing your results, and
> artificially making those look hotter on am64 by virtue of centralizing
> samples to the same IP/PC range?

As mentioned above, _copy_to_user is not inlined on x86.

> Can you share any information on those workloads? e.g. which callchains
> were hot?

Please reach out to James Greenhalgh and Chris Goodyer at Arm for more details
about those workloads, which I can't share in a public channel.

By bpftracing, we found that most of __arch_copy_to_user calls are against size
2k-4k. I wrote a simple microbenchmark to test and compare the performance of
copy_to_user on both x64 and arm64, see
https://github.com/mcfi/benchmark/tree/main/ku_copy
Below were data collected. You could see that Arm64 ku copy speed had a dip
when the size hits 2K-16K.

Routine	        Size	Arm64 bytes/s / x64 bytes /s
copy_to_user	8	203.4%
copy_from_user	8	248.5%
copy_to_user	16	194.6%
copy_from_user	16	240.6%
copy_to_user	32	195.0%
copy_from_user	32	236.5%
copy_to_user	64	193.2%
copy_from_user	64	240.4%
copy_to_user	128	211.0%
copy_from_user	128	273.0%
copy_to_user	256	185.3%
copy_from_user	256	229.3%
copy_to_user	512	152.9%
copy_from_user	512	182.4%
copy_to_user	1024	121.0%
copy_from_user	1024	141.9%
copy_to_user	2048	95.1%
copy_from_user	2048	108.7%
copy_to_user	4096	78.9%
copy_from_user	4096	85.7%
copy_to_user	8192	69.7%
copy_from_user	8192	73.5%
copy_to_user	16384	65.9%
copy_from_user	16384	68.8%
copy_to_user	32768	117.3%
copy_from_user	32768	118.6%
copy_to_user	65536	115.5%
copy_from_user	65536	117.4%
copy_to_user	131072	114.6%
copy_from_user	131072	113.3%
copy_to_user	262144	114.4%
copy_from_user	262144	109.3%

I sent out a patch for faster __arch_copy_from_user/__arch_copy_to_user. Please
see this message ID 20251018052237.1368504-2-benniu at meta.com for more details.

> Mark.

In addition, I'm withdrawing this patch because we found a workaround to trace
__arch_copy_to_user/__arch_copy_from_user through watchpoints. This message ID
aTjpzfqTEGPcird5 at meta.com should have all the details. Thank you for reviewing
this patch and all your helpful comments.

Ben


From nicolas.dufresne at collabora.com  Wed Dec 10 12:17:45 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Wed, 10 Dec 2025 15:17:45 -0500
Subject: [PATCH v4 03/15] media: rkvdec: Switch to using structs instead
 of writel
In-Reply-To: <20251022174508.284929-4-detlev.casanova@collabora.com>
References: <20251022174508.284929-1-detlev.casanova@collabora.com>
	 <20251022174508.284929-4-detlev.casanova@collabora.com>
Message-ID: <e750c4b9c461bde6aab0bf8e5fc13d1fd69cd989.camel@collabora.com>

Hi,

was commenting against the wrong version, to help with b4 flow.

Le mercredi 22 octobre 2025 ? 13:44 -0400, Detlev Casanova a ?crit?:
> In an effort to merge the rkvdec2 driver [1] with this one, switch from
> writel() calls to using structs to represent the register mappings.
> 
> This is done in order to have all supported decoders use the same format
> in the future and ease reading of the code.
> 
> Using structs also improves stability as the hardware is tested and
> validated downstream using a similar method.
> It was noticed, on decoders, that:
> ?- Some registers require to be writen in increasing order [2]
> ?- Some registers, even if unrelated, need to be written to their reset
> ?? values (it was the case here for axi_ddr_[rw]data).
> 
> Using structs can also help improving performance later when, e.g.
> multicore support is added on RK3588.
> 
> Performance seems to be slightly improved, but at least, not made worse.
> Running fluster's JVT-AVC_V1 test suite with GStreamer on the Radxa ROCK
> PI 4 SE gives the following times:
> 
> Before this patch:
> 
> - --jobs 1: Ran 129/135 tests successfully?????????????? in 77.167 secs
> - --jobs 6: Ran 129/135 tests successfully?????????????? in 23.046 secs
> 
> With this patch:
> - --jobs 1: Ran 129/135 tests successfully?????????????? in 70.698 secs
> - --jobs 6: Ran 129/135 tests successfully?????????????? in 22.917 secs
> 
> This also shows that the fluster score hasn't changed.
> 
> [1]: https://lore.kernel.org/all/20250325213303.826925-1-detlev.casanova at collabora.com/
> [2]: https://lore.kernel.org/all/20200127143009.15677-5-andrzej.p at collabora.com/
> 
> Tested-by: Diederik de Haas <didi.debian at cknow.org>? # Rock 5B
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?.../platform/rockchip/rkvdec/rkvdec-h264.c??? | 165 +++--
> ?.../platform/rockchip/rkvdec/rkvdec-hevc.c??? |? 63 +-
> ?.../platform/rockchip/rkvdec/rkvdec-regs.h??? | 571 ++++++++++++------
> ?.../platform/rockchip/rkvdec/rkvdec-vp9.c???? | 231 +++----
> ?.../media/platform/rockchip/rkvdec/rkvdec.c?? |? 10 +-
> ?.../media/platform/rockchip/rkvdec/rkvdec.h?? |?? 1 +
> ?6 files changed, 587 insertions(+), 454 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
> index d14b4d173448..116e7b1076b7 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
> @@ -115,6 +115,7 @@ struct rkvdec_h264_run {
> ?struct rkvdec_h264_ctx {
> ?	struct rkvdec_aux_buf priv_tbl;
> ?	struct rkvdec_h264_reflists reflists;
> +	struct rkvdec_regs regs;
> ?};
> ?
> ?#define CABAC_ENTRY(ctxidx, idc0_m, idc0_n, idc1_m, idc1_n,		\
> @@ -841,45 +842,41 @@ static void assemble_hw_scaling_list(struct rkvdec_ctx *ctx,
> ?}
> ?
> ?/*
> - * dpb poc related registers table
> + * Set the ref POC in the correct register.
> + *
> + * The 32 registers are spread across 3 regions, each alternating top and bottom ref POCs:
> + *? - 1: ref 0 to 14 contain top 0 to 7 and bottoms 0 to 6
> + *? - 2: ref 15 to 29 contain top 8 to 14 and bottoms 7 to 14
> + *? - 3: ref 30 and 31 which correspond to top 15 and bottom 15 respectively.
> ? */
> -static const u32 poc_reg_tbl_top_field[16] = {
> -	RKVDEC_REG_H264_POC_REFER0(0),
> -	RKVDEC_REG_H264_POC_REFER0(2),
> -	RKVDEC_REG_H264_POC_REFER0(4),
> -	RKVDEC_REG_H264_POC_REFER0(6),
> -	RKVDEC_REG_H264_POC_REFER0(8),
> -	RKVDEC_REG_H264_POC_REFER0(10),
> -	RKVDEC_REG_H264_POC_REFER0(12),
> -	RKVDEC_REG_H264_POC_REFER0(14),
> -	RKVDEC_REG_H264_POC_REFER1(1),
> -	RKVDEC_REG_H264_POC_REFER1(3),
> -	RKVDEC_REG_H264_POC_REFER1(5),
> -	RKVDEC_REG_H264_POC_REFER1(7),
> -	RKVDEC_REG_H264_POC_REFER1(9),
> -	RKVDEC_REG_H264_POC_REFER1(11),
> -	RKVDEC_REG_H264_POC_REFER1(13),
> -	RKVDEC_REG_H264_POC_REFER2(0)
> -};
> -
> -static const u32 poc_reg_tbl_bottom_field[16] = {
> -	RKVDEC_REG_H264_POC_REFER0(1),
> -	RKVDEC_REG_H264_POC_REFER0(3),
> -	RKVDEC_REG_H264_POC_REFER0(5),
> -	RKVDEC_REG_H264_POC_REFER0(7),
> -	RKVDEC_REG_H264_POC_REFER0(9),
> -	RKVDEC_REG_H264_POC_REFER0(11),
> -	RKVDEC_REG_H264_POC_REFER0(13),
> -	RKVDEC_REG_H264_POC_REFER1(0),
> -	RKVDEC_REG_H264_POC_REFER1(2),
> -	RKVDEC_REG_H264_POC_REFER1(4),
> -	RKVDEC_REG_H264_POC_REFER1(6),
> -	RKVDEC_REG_H264_POC_REFER1(8),
> -	RKVDEC_REG_H264_POC_REFER1(10),
> -	RKVDEC_REG_H264_POC_REFER1(12),
> -	RKVDEC_REG_H264_POC_REFER1(14),
> -	RKVDEC_REG_H264_POC_REFER2(1)
> -};
> +static void set_poc_reg(struct rkvdec_regs *regs, uint32_t poc, int id, bool bottom)
> +{
> +	if (!bottom) {
> +		switch (id) {
> +		case 0 ... 7:
> +			regs->h26x.ref0_14_poc[id * 2] = poc;
> +			break;
> +		case 8 ... 14:
> +			regs->h26x.ref15_29_poc[(id - 8) * 2 + 1] = poc;
> +			break;
> +		case 15:
> +			regs->h26x.ref30_poc = poc;
> +			break;
> +		}
> +	} else {
> +		switch (id) {
> +		case 0 ... 6:
> +			regs->h26x.ref0_14_poc[id * 2 + 1] = poc;
> +			break;
> +		case 7 ... 14:
> +			regs->h26x.ref15_29_poc[(id - 7) * 2] = poc;
> +			break;
> +		case 15:
> +			regs->h26x.ref31_poc = poc;
> +			break;
> +		}
> +	}
> +}
> ?
> ?static void config_registers(struct rkvdec_ctx *ctx,
> ?			???? struct rkvdec_h264_run *run)
> @@ -894,6 +891,7 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?	struct vb2_v4l2_buffer *src_buf = run->base.bufs.src;
> ?	struct vb2_v4l2_buffer *dst_buf = run->base.bufs.dst;
> ?	const struct v4l2_format *f;
> +	struct rkvdec_regs *regs = &h264_ctx->regs;
> ?	dma_addr_t rlc_addr;
> ?	dma_addr_t refer_addr;
> ?	u32 rlc_len;
> @@ -903,10 +901,11 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?	u32 yuv_virstride = 0;
> ?	u32 offset;
> ?	dma_addr_t dst_addr;
> -	u32 reg, i;
> +	u32 i;
> ?
> -	reg = RKVDEC_MODE(RKVDEC_MODE_H264);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_SYSCTRL);
> +	memset(regs, 0, sizeof(*regs));
> +
> +	regs->common.reg02.dec_mode = RKVDEC_MODE_H264;
> ?
> ?	f = &ctx->decoded_fmt;
> ?	dst_fmt = &f->fmt.pix_mp;
> @@ -921,39 +920,35 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?	else if (sps->chroma_format_idc == 2)
> ?		yuv_virstride = 2 * y_virstride;
> ?
> -	reg = RKVDEC_Y_HOR_VIRSTRIDE(hor_virstride / 16) |
> -	????? RKVDEC_UV_HOR_VIRSTRIDE(hor_virstride / 16) |
> -	????? RKVDEC_SLICE_NUM_HIGHBIT |
> -	????? RKVDEC_SLICE_NUM_LOWBITS(0x7ff);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_PICPAR);
> +	regs->common.reg03.uv_hor_virstride = hor_virstride / 16;
> +	regs->common.reg03.y_hor_virstride = hor_virstride / 16;
> +	regs->common.reg03.slice_num_highbit = 1;
> +	regs->common.reg03.slice_num_lowbits = 0x7ff;
> ?
> ?	/* config rlc base address */
> ?	rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
> -	writel_relaxed(rlc_addr, rkvdec->regs + RKVDEC_REG_STRM_RLC_BASE);
> -	writel_relaxed(rlc_addr, rkvdec->regs + RKVDEC_REG_RLCWRITE_BASE);
> +	regs->common.strm_rlc_base = rlc_addr;
> +	regs->h26x.rlcwrite_base = rlc_addr;
> ?
> ?	rlc_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
> -	reg = RKVDEC_STRM_LEN(rlc_len);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_STRM_LEN);
> +	regs->common.stream_len = rlc_len;
> ?
> ?	/* config cabac table */
> ?	offset = offsetof(struct rkvdec_h264_priv_tbl, cabac_table);
> -	writel_relaxed(priv_start_addr + offset,
> -		?????? rkvdec->regs + RKVDEC_REG_CABACTBL_PROB_BASE);
> +	regs->common.cabactbl_base = priv_start_addr + offset;
> ?
> ?	/* config output base address */
> ?	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
> -	writel_relaxed(dst_addr, rkvdec->regs + RKVDEC_REG_DECOUT_BASE);
> +	regs->common.decout_base = dst_addr;
> ?
> -	reg = RKVDEC_Y_VIRSTRIDE(y_virstride / 16);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_Y_VIRSTRIDE);
> +	regs->common.reg08.y_virstride = y_virstride / 16;
> ?
> -	reg = RKVDEC_YUV_VIRSTRIDE(yuv_virstride / 16);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_YUV_VIRSTRIDE);
> +	regs->common.reg09.yuv_virstride = yuv_virstride / 16;
> ?
> ?	/* config ref pic address & poc */
> ?	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
> ?		struct vb2_buffer *vb_buf = run->ref_buf[i];
> +		struct ref_base *base;
> ?
> ?		/*
> ?		 * If a DPB entry is unused or invalid, address of current destination
> @@ -963,54 +958,36 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?			vb_buf = &dst_buf->vb2_buf;
> ?		refer_addr = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
> ?
> -		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)
> -			refer_addr |= RKVDEC_COLMV_USED_FLAG_REF;
> -		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD)
> -			refer_addr |= RKVDEC_FIELD_REF;
> -
> -		if (dpb[i].fields & V4L2_H264_TOP_FIELD_REF)
> -			refer_addr |= RKVDEC_TOPFIELD_USED_REF;
> -		if (dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF)
> -			refer_addr |= RKVDEC_BOTFIELD_USED_REF;
> -
> -		writel_relaxed(dpb[i].top_field_order_cnt,
> -			?????? rkvdec->regs +? poc_reg_tbl_top_field[i]);
> -		writel_relaxed(dpb[i].bottom_field_order_cnt,
> -			?????? rkvdec->regs + poc_reg_tbl_bottom_field[i]);
> -
> ?		if (i < V4L2_H264_NUM_DPB_ENTRIES - 1)
> -			writel_relaxed(refer_addr,
> -				?????? rkvdec->regs + RKVDEC_REG_H264_BASE_REFER(i));
> +			base = &regs->h26x.ref0_14_base[i];
> ?		else
> -			writel_relaxed(refer_addr,
> -				?????? rkvdec->regs + RKVDEC_REG_H264_BASE_REFER15);
> -	}
> +			base = &regs->h26x.ref15_base;
> ?
> -	reg = RKVDEC_CUR_POC(dec_params->top_field_order_cnt);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC0);
> +		base->field_ref = !!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD);
> +		base->colmv_used_flag_ref = !!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE);
> +		base->topfield_used_ref = !!(dpb[i].fields & V4L2_H264_TOP_FIELD_REF);
> +		base->botfield_used_ref = !!(dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF);
> +		base->base_addr = refer_addr >> 4;
> ?
> -	reg = RKVDEC_CUR_POC(dec_params->bottom_field_order_cnt);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC1);
> +		set_poc_reg(regs, dpb[i].top_field_order_cnt, i, false);
> +		set_poc_reg(regs, dpb[i].bottom_field_order_cnt, i, true);
> +	}
> +
> +	regs->h26x.cur_poc = dec_params->top_field_order_cnt;
> +	regs->h26x.cur_poc1 = dec_params->bottom_field_order_cnt;
> ?
> ?	/* config hw pps address */
> ?	offset = offsetof(struct rkvdec_h264_priv_tbl, param_set);
> -	writel_relaxed(priv_start_addr + offset,
> -		?????? rkvdec->regs + RKVDEC_REG_PPS_BASE);
> +	regs->h26x.pps_base = priv_start_addr + offset;
> ?
> ?	/* config hw rps address */
> ?	offset = offsetof(struct rkvdec_h264_priv_tbl, rps);
> -	writel_relaxed(priv_start_addr + offset,
> -		?????? rkvdec->regs + RKVDEC_REG_RPS_BASE);
> -
> -	reg = RKVDEC_AXI_DDR_RDATA(0);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_RDATA);
> -
> -	reg = RKVDEC_AXI_DDR_WDATA(0);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_WDATA);
> +	regs->h26x.rps_base = priv_start_addr + offset;
> ?
> ?	offset = offsetof(struct rkvdec_h264_priv_tbl, err_info);
> -	writel_relaxed(priv_start_addr + offset,
> -		?????? rkvdec->regs + RKVDEC_REG_H264_ERRINFO_BASE);
> +	regs->h26x.errorinfo_base = priv_start_addr + offset;
> +
> +	rkvdec_memcpy_toio(rkvdec->regs, regs, MIN(sizeof(*regs), 4 * rkvdec->variant->num_regs));
> ?}
> ?
> ?#define RKVDEC_H264_MAX_DEPTH_IN_BYTES		2
> @@ -1181,8 +1158,6 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
> ?
> ?	schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000));
> ?
> -	writel(0, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN);
> -	writel(0, rkvdec->regs + RKVDEC_REG_H264_ERR_E);
> ?	writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND);
> ?	writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);
> ?
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
> index fc7e6a260b0a..01f92fa27356 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
> @@ -129,6 +129,7 @@ struct rkvdec_hevc_run {
> ?struct rkvdec_hevc_ctx {
> ?	struct rkvdec_aux_buf priv_tbl;
> ?	struct v4l2_ctrl_hevc_scaling_matrix scaling_matrix_cache;
> +	struct rkvdec_regs regs;
> ?};
> ?
> ?struct scaling_factor {
> @@ -548,6 +549,7 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?	const struct v4l2_ctrl_hevc_slice_params *sl_params = &run->slices_params[0];
> ?	const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb;
> ?	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
> +	struct rkvdec_regs *regs = &hevc_ctx->regs;
> ?	dma_addr_t priv_start_addr = hevc_ctx->priv_tbl.dma;
> ?	const struct v4l2_pix_format_mplane *dst_fmt;
> ?	struct vb2_v4l2_buffer *src_buf = run->base.bufs.src;
> @@ -564,8 +566,9 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?	dma_addr_t dst_addr;
> ?	u32 reg, i;
> ?
> -	reg = RKVDEC_MODE(RKVDEC_MODE_HEVC);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_SYSCTRL);
> +	memset(regs, 0, sizeof(*regs));
> +
> +	regs->common.reg02.dec_mode = RKVDEC_MODE_HEVC;
> ?
> ?	f = &ctx->decoded_fmt;
> ?	dst_fmt = &f->fmt.pix_mp;
> @@ -580,33 +583,27 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?	else if (sps->chroma_format_idc == 2)
> ?		yuv_virstride = 2 * y_virstride;
> ?
> -	reg = RKVDEC_Y_HOR_VIRSTRIDE(hor_virstride / 16) |
> -	????? RKVDEC_UV_HOR_VIRSTRIDE(hor_virstride / 16) |
> -	????? RKVDEC_SLICE_NUM_LOWBITS(run->num_slices);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_PICPAR);
> +	regs->common.reg03.slice_num_lowbits = run->num_slices;
> +	regs->common.reg03.uv_hor_virstride = hor_virstride / 16;
> +	regs->common.reg03.y_hor_virstride = hor_virstride / 16;
> ?
> ?	/* config rlc base address */
> ?	rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
> -	writel_relaxed(rlc_addr, rkvdec->regs + RKVDEC_REG_STRM_RLC_BASE);
> +	regs->common.strm_rlc_base = rlc_addr;
> ?
> ?	rlc_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
> -	reg = RKVDEC_STRM_LEN(round_up(rlc_len, 16) + 64);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_STRM_LEN);
> +	regs->common.stream_len = round_up(rlc_len, 16) + 64;
> ?
> ?	/* config cabac table */
> ?	offset = offsetof(struct rkvdec_hevc_priv_tbl, cabac_table);
> -	writel_relaxed(priv_start_addr + offset,
> -		?????? rkvdec->regs + RKVDEC_REG_CABACTBL_PROB_BASE);
> +	regs->common.cabactbl_base = priv_start_addr + offset;
> ?
> ?	/* config output base address */
> ?	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
> -	writel_relaxed(dst_addr, rkvdec->regs + RKVDEC_REG_DECOUT_BASE);
> -
> -	reg = RKVDEC_Y_VIRSTRIDE(y_virstride / 16);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_Y_VIRSTRIDE);
> +	regs->common.decout_base = dst_addr;
> ?
> -	reg = RKVDEC_YUV_VIRSTRIDE(yuv_virstride / 16);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_YUV_VIRSTRIDE);
> +	regs->common.reg08.y_virstride = y_virstride / 16;
> +	regs->common.reg09.yuv_virstride = yuv_virstride / 16;
> ?
> ?	/* config ref pic address */
> ?	for (i = 0; i < 15; i++) {
> @@ -620,33 +617,29 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?		}
> ?
> ?		refer_addr = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
> -		writel_relaxed(refer_addr | reg,
> -			?????? rkvdec->regs + RKVDEC_REG_H264_BASE_REFER(i));
> ?
> -		reg = RKVDEC_POC_REFER(i < decode_params->num_active_dpb_entries ?
> -			dpb[i].pic_order_cnt_val : 0);
> -		writel_relaxed(reg,
> -			?????? rkvdec->regs + RKVDEC_REG_H264_POC_REFER0(i));
> +		regs->h26x.ref0_14_base[i].base_addr = refer_addr >> 4;
> +		regs->h26x.ref0_14_base[i].field_ref = !!(reg & 1);
> +		regs->h26x.ref0_14_base[i].topfield_used_ref = !!(reg & 2);
> +		regs->h26x.ref0_14_base[i].botfield_used_ref = !!(reg & 4);
> +		regs->h26x.ref0_14_base[i].colmv_used_flag_ref = !!(reg & 8);
> +
> +		regs->h26x.ref0_14_poc[i] = i < decode_params->num_active_dpb_entries
> +					??? ? dpb[i].pic_order_cnt_val
> +					??? : 0;
> ?	}
> ?
> -	reg = RKVDEC_CUR_POC(sl_params->slice_pic_order_cnt);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC0);
> +	regs->h26x.cur_poc = sl_params->slice_pic_order_cnt;
> ?
> ?	/* config hw pps address */
> ?	offset = offsetof(struct rkvdec_hevc_priv_tbl, param_set);
> -	writel_relaxed(priv_start_addr + offset,
> -		?????? rkvdec->regs + RKVDEC_REG_PPS_BASE);
> +	regs->h26x.pps_base = priv_start_addr + offset;
> ?
> ?	/* config hw rps address */
> ?	offset = offsetof(struct rkvdec_hevc_priv_tbl, rps);
> -	writel_relaxed(priv_start_addr + offset,
> -		?????? rkvdec->regs + RKVDEC_REG_RPS_BASE);
> -
> -	reg = RKVDEC_AXI_DDR_RDATA(0);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_RDATA);
> +	regs->h26x.rps_base = priv_start_addr + offset;
> ?
> -	reg = RKVDEC_AXI_DDR_WDATA(0);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_WDATA);
> +	rkvdec_memcpy_toio(rkvdec->regs, regs, MIN(sizeof(*regs), 4 * rkvdec->variant->num_regs));
> ?}
> ?
> ?#define RKVDEC_HEVC_MAX_DEPTH_IN_BYTES		2
> @@ -784,8 +777,6 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
> ?
> ?	schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000));
> ?
> -	writel(0, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN);
> -	writel(0, rkvdec->regs + RKVDEC_REG_H264_ERR_E);
> ?	writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND);
> ?	writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);
> ?
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h
> index c627b6b6f53a..7745ea257148 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h
> @@ -3,7 +3,12 @@
> ?#ifndef RKVDEC_REGS_H_
> ?#define RKVDEC_REGS_H_
> ?
> -/* rkvcodec registers */
> +#include <linux/types.h>
> +
> +/*
> + * REG_INTERRUPT is accessed via writel to enable the decoder after
> + * configuring it and clear interrupt strmd_error_status
> + */
> ?#define RKVDEC_REG_INTERRUPT				0x004
> ?#define RKVDEC_INTERRUPT_DEC_E				BIT(0)
> ?#define RKVDEC_CONFIG_DEC_CLK_GATE_E			BIT(1)
> @@ -30,198 +35,384 @@
> ?#define RKVDEC_SOFTRESET_RDY				BIT(22)
> ?#define RKVDEC_WR_DDR_ALIGN_EN				BIT(23)
> ?
> -#define RKVDEC_REG_SYSCTRL				0x008
> -#define RKVDEC_IN_ENDIAN				BIT(0)
> -#define RKVDEC_IN_SWAP32_E				BIT(1)
> -#define RKVDEC_IN_SWAP64_E				BIT(2)
> -#define RKVDEC_STR_ENDIAN				BIT(3)
> -#define RKVDEC_STR_SWAP32_E				BIT(4)
> -#define RKVDEC_STR_SWAP64_E				BIT(5)
> -#define RKVDEC_OUT_ENDIAN				BIT(6)
> -#define RKVDEC_OUT_SWAP32_E				BIT(7)
> -#define RKVDEC_OUT_CBCR_SWAP				BIT(8)
> -#define RKVDEC_RLC_MODE_DIRECT_WRITE			BIT(10)
> -#define RKVDEC_RLC_MODE					BIT(11)
> -#define RKVDEC_STRM_START_BIT(x)			(((x) & 0x7f) << 12)
> -#define RKVDEC_MODE(x)					(((x) & 0x03) << 20)
> -#define RKVDEC_MODE_HEVC				0
> -#define RKVDEC_MODE_H264				1
> -#define RKVDEC_MODE_VP9					2
> -#define RKVDEC_RPS_MODE					BIT(24)
> -#define RKVDEC_STRM_MODE				BIT(25)
> -#define RKVDEC_H264_STRM_LASTPKT			BIT(26)
> -#define RKVDEC_H264_FIRSTSLICE_FLAG			BIT(27)
> -#define RKVDEC_H264_FRAME_ORSLICE			BIT(28)
> -#define RKVDEC_BUSPR_SLOT_DIS				BIT(29)
> -
> -#define RKVDEC_REG_PICPAR				0x00C
> -#define RKVDEC_Y_HOR_VIRSTRIDE(x)			((x) & 0x1ff)
> -#define RKVDEC_SLICE_NUM_HIGHBIT			BIT(11)
> -#define RKVDEC_UV_HOR_VIRSTRIDE(x)			(((x) & 0x1ff) << 12)
> -#define RKVDEC_SLICE_NUM_LOWBITS(x)			(((x) & 0x7ff) << 21)
> -
> -#define RKVDEC_REG_STRM_RLC_BASE			0x010
> -
> -#define RKVDEC_REG_STRM_LEN				0x014
> -#define RKVDEC_STRM_LEN(x)				((x) & 0x7ffffff)
> -
> -#define RKVDEC_REG_CABACTBL_PROB_BASE			0x018
> -#define RKVDEC_REG_DECOUT_BASE				0x01C
> -
> -#define RKVDEC_REG_Y_VIRSTRIDE				0x020
> -#define RKVDEC_Y_VIRSTRIDE(x)				((x) & 0xfffff)
> -
> -#define RKVDEC_REG_YUV_VIRSTRIDE			0x024
> -#define RKVDEC_YUV_VIRSTRIDE(x)				((x) & 0x1fffff)
> -#define RKVDEC_REG_H264_BASE_REFER(i)			(((i) * 0x04) + 0x028)
> -
> -#define RKVDEC_REG_H264_BASE_REFER15			0x0C0
> -#define RKVDEC_FIELD_REF				BIT(0)
> -#define RKVDEC_TOPFIELD_USED_REF			BIT(1)
> -#define RKVDEC_BOTFIELD_USED_REF			BIT(2)
> -#define RKVDEC_COLMV_USED_FLAG_REF			BIT(3)
> -
> -#define RKVDEC_REG_VP9_LAST_FRAME_BASE			0x02c
> -#define RKVDEC_REG_VP9_GOLDEN_FRAME_BASE		0x030
> -#define RKVDEC_REG_VP9_ALTREF_FRAME_BASE		0x034
> -
> -#define RKVDEC_REG_VP9_CPRHEADER_OFFSET			0x028
> -#define RKVDEC_VP9_CPRHEADER_OFFSET(x)			((x) & 0xffff)
> -
> -#define RKVDEC_REG_VP9_REFERLAST_BASE			0x02C
> -#define RKVDEC_REG_VP9_REFERGOLDEN_BASE			0x030
> -#define RKVDEC_REG_VP9_REFERALFTER_BASE			0x034
> -
> -#define RKVDEC_REG_VP9COUNT_BASE			0x038
> -#define RKVDEC_VP9COUNT_UPDATE_EN			BIT(0)
> -
> -#define RKVDEC_REG_VP9_SEGIDLAST_BASE			0x03C
> -#define RKVDEC_REG_VP9_SEGIDCUR_BASE			0x040
> -#define RKVDEC_REG_VP9_FRAME_SIZE(i)			((i) * 0x04 + 0x044)
> -#define RKVDEC_VP9_FRAMEWIDTH(x)			(((x) & 0xffff) << 0)
> -#define RKVDEC_VP9_FRAMEHEIGHT(x)			(((x) & 0xffff) << 16)
> -
> -#define RKVDEC_VP9_SEGID_GRP(i)				((i) * 0x04 + 0x050)
> -#define RKVDEC_SEGID_ABS_DELTA(x)			((x) & 0x1)
> -#define RKVDEC_SEGID_FRAME_QP_DELTA_EN(x)		(((x) & 0x1) << 1)
> -#define RKVDEC_SEGID_FRAME_QP_DELTA(x)			(((x) & 0x1ff) << 2)
> -#define RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE_EN(x)	(((x) & 0x1) << 11)
> -#define RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE(x)		(((x) & 0x7f) << 12)
> -#define RKVDEC_SEGID_REFERINFO_EN(x)			(((x) & 0x1) << 19)
> -#define RKVDEC_SEGID_REFERINFO(x)			(((x) & 0x03) << 20)
> -#define RKVDEC_SEGID_FRAME_SKIP_EN(x)			(((x) & 0x1) << 22)
> -
> -#define RKVDEC_VP9_CPRHEADER_CONFIG			0x070
> -#define RKVDEC_VP9_TX_MODE(x)				((x) & 0x07)
> -#define RKVDEC_VP9_FRAME_REF_MODE(x)			(((x) & 0x03) << 3)
> -
> -#define RKVDEC_VP9_REF_SCALE(i)				((i) * 0x04 + 0x074)
> -#define RKVDEC_VP9_REF_HOR_SCALE(x)			((x) & 0xffff)
> -#define RKVDEC_VP9_REF_VER_SCALE(x)			(((x) & 0xffff) << 16)
> -
> -#define RKVDEC_VP9_REF_DELTAS_LASTFRAME			0x080
> -#define RKVDEC_REF_DELTAS_LASTFRAME(pos, val)		(((val) & 0x7f) << ((pos) * 7))
> -
> -#define RKVDEC_VP9_INFO_LASTFRAME			0x084
> -#define RKVDEC_MODE_DELTAS_LASTFRAME(pos, val)		(((val) & 0x7f) << ((pos) * 7))
> -#define RKVDEC_SEG_EN_LASTFRAME				BIT(16)
> -#define RKVDEC_LAST_SHOW_FRAME				BIT(17)
> -#define RKVDEC_LAST_INTRA_ONLY				BIT(18)
> -#define RKVDEC_LAST_WIDHHEIGHT_EQCUR			BIT(19)
> -#define RKVDEC_COLOR_SPACE_LASTKEYFRAME(x)		(((x) & 0x07) << 20)
> -
> -#define RKVDEC_VP9_INTERCMD_BASE			0x088
> -
> -#define RKVDEC_VP9_INTERCMD_NUM				0x08C
> -#define RKVDEC_INTERCMD_NUM(x)				((x) & 0xffffff)
> -
> -#define RKVDEC_VP9_LASTTILE_SIZE			0x090
> -#define RKVDEC_LASTTILE_SIZE(x)				((x) & 0xffffff)
> -
> -#define RKVDEC_VP9_HOR_VIRSTRIDE(i)			((i) * 0x04 + 0x094)
> -#define RKVDEC_HOR_Y_VIRSTRIDE(x)			((x) & 0x1ff)
> -#define RKVDEC_HOR_UV_VIRSTRIDE(x)			(((x) & 0x1ff) << 16)
> -
> -#define RKVDEC_REG_H264_POC_REFER0(i)			(((i) * 0x04) + 0x064)
> -#define RKVDEC_REG_H264_POC_REFER1(i)			(((i) * 0x04) + 0x0C4)
> -#define RKVDEC_REG_H264_POC_REFER2(i)			(((i) * 0x04) + 0x120)
> -#define RKVDEC_POC_REFER(x)				((x) & 0xffffffff)
> -
> -#define RKVDEC_REG_CUR_POC0				0x0A0
> -#define RKVDEC_REG_CUR_POC1				0x128
> -#define RKVDEC_CUR_POC(x)				((x) & 0xffffffff)
> -
> -#define RKVDEC_REG_RLCWRITE_BASE			0x0A4
> -#define RKVDEC_REG_PPS_BASE				0x0A8
> -#define RKVDEC_REG_RPS_BASE				0x0AC
> -
> -#define RKVDEC_REG_STRMD_ERR_EN				0x0B0
> -#define RKVDEC_STRMD_ERR_EN(x)				((x) & 0xffffffff)
> -
> -#define RKVDEC_REG_STRMD_ERR_STA			0x0B4
> -#define RKVDEC_STRMD_ERR_STA(x)				((x) & 0xfffffff)
> -#define RKVDEC_COLMV_ERR_REF_PICIDX(x)			(((x) & 0x0f) << 28)
> -
> -#define RKVDEC_REG_STRMD_ERR_CTU			0x0B8
> -#define RKVDEC_STRMD_ERR_CTU(x)				((x) & 0xff)
> -#define RKVDEC_STRMD_ERR_CTU_YOFFSET(x)			(((x) & 0xff) << 8)
> -#define RKVDEC_STRMFIFO_SPACE2FULL(x)			(((x) & 0x7f) << 16)
> -#define RKVDEC_VP9_ERR_EN_CTU0				BIT(24)
> -
> -#define RKVDEC_REG_SAO_CTU_POS				0x0BC
> -#define RKVDEC_SAOWR_XOFFSET(x)				((x) & 0x1ff)
> -#define RKVDEC_SAOWR_YOFFSET(x)				(((x) & 0x3ff) << 16)
> -
> -#define RKVDEC_VP9_LAST_FRAME_YSTRIDE			0x0C0
> -#define RKVDEC_VP9_GOLDEN_FRAME_YSTRIDE			0x0C4
> -#define RKVDEC_VP9_ALTREF_FRAME_YSTRIDE			0x0C8
> -#define RKVDEC_VP9_REF_YSTRIDE(x)			(((x) & 0xfffff) << 0)
> -
> -#define RKVDEC_VP9_LAST_FRAME_YUVSTRIDE			0x0CC
> -#define RKVDEC_VP9_REF_YUVSTRIDE(x)			(((x) & 0x1fffff) << 0)
> -
> -#define RKVDEC_VP9_REF_COLMV_BASE			0x0D0
> -
> -#define RKVDEC_REG_PERFORMANCE_CYCLE			0x100
> -#define RKVDEC_PERFORMANCE_CYCLE(x)			((x) & 0xffffffff)
> -
> -#define RKVDEC_REG_AXI_DDR_RDATA			0x104
> -#define RKVDEC_AXI_DDR_RDATA(x)				((x) & 0xffffffff)
> -
> -#define RKVDEC_REG_AXI_DDR_WDATA			0x108
> -#define RKVDEC_AXI_DDR_WDATA(x)				((x) & 0xffffffff)
> -
> -#define RKVDEC_REG_FPGADEBUG_RESET			0x10C
> -#define RKVDEC_BUSIFD_RESETN				BIT(0)
> -#define RKVDEC_CABAC_RESETN				BIT(1)
> -#define RKVDEC_DEC_CTRL_RESETN				BIT(2)
> -#define RKVDEC_TRANSD_RESETN				BIT(3)
> -#define RKVDEC_INTRA_RESETN				BIT(4)
> -#define RKVDEC_INTER_RESETN				BIT(5)
> -#define RKVDEC_RECON_RESETN				BIT(6)
> -#define RKVDEC_FILER_RESETN				BIT(7)
> -
> -#define RKVDEC_REG_PERFORMANCE_SEL			0x110
> -#define RKVDEC_PERF_SEL_CNT0(x)				((x) & 0x3f)
> -#define RKVDEC_PERF_SEL_CNT1(x)				(((x) & 0x3f) << 8)
> -#define RKVDEC_PERF_SEL_CNT2(x)				(((x) & 0x3f) << 16)
> -
> -#define RKVDEC_REG_PERFORMANCE_CNT(i)			((i) * 0x04 + 0x114)
> -#define RKVDEC_PERF_CNT(x)				((x) & 0xffffffff)
> -
> -#define RKVDEC_REG_H264_ERRINFO_BASE			0x12C
> -
> -#define RKVDEC_REG_H264_ERRINFO_NUM			0x130
> -#define RKVDEC_SLICEDEC_NUM(x)				((x) & 0x3fff)
> -#define RKVDEC_STRMD_DECT_ERR_FLAG			BIT(15)
> -#define RKVDEC_ERR_PKT_NUM(x)				(((x) & 0x3fff) << 16)
> -
> -#define RKVDEC_REG_H264_ERR_E				0x134
> -#define RKVDEC_H264_ERR_EN_HIGHBITS(x)			((x) & 0x3fffffff)
> -
> ?#define RKVDEC_REG_QOS_CTRL				0x18C
> ?
> +/*
> + * Cache configuration is not covered in the range of the register struct
> + */
> ?#define RKVDEC_REG_PREF_LUMA_CACHE_COMMAND		0x410
> ?#define RKVDEC_REG_PREF_CHR_CACHE_COMMAND		0x450
> ?
> +/*
> + * Define the mode values
> + */
> +#define RKVDEC_MODE_HEVC				0
> +#define RKVDEC_MODE_H264				1
> +#define RKVDEC_MODE_VP9					2
> +
> +/* rkvcodec registers */
> +struct rkvdec_common_regs {
> +	struct rkvdec_id {
> +		u32 minor_ver	: 8;
> +		u32 level	: 1;
> +		u32 dec_support	: 3;
> +		u32 profile	: 1;
> +		u32 reserved0	: 1;
> +		u32 codec_flag	: 1;
> +		u32 reserved1	: 1;
> +		u32 prod_num	: 16;
> +	} reg00;
> +
> +	struct rkvdec_int {
> +		u32 dec_e			: 1;
> +		u32 dec_clkgate_e		: 1;
> +		u32 reserved0			: 1;
> +		u32 timeout_mode		: 1;
> +		u32 dec_irq_dis			: 1;
> +		u32 dec_timeout_e		: 1;
> +		u32 buf_empty_en		: 1;
> +		u32 stmerror_waitdecfifo_empty	: 1;
> +		u32 dec_irq			: 1;
> +		u32 dec_irq_raw			: 1;
> +		u32 reserved2			: 2;
> +		u32 dec_rdy_sta			: 1;
> +		u32 dec_bus_sta			: 1;
> +		u32 dec_error_sta		: 1;
> +		u32 dec_timeout_sta		: 1;
> +		u32 dec_empty_sta		: 1;
> +		u32 colmv_ref_error_sta		: 1;
> +		u32 cabu_end_sta		: 1;
> +		u32 h264orvp9_error_mode	: 1;
> +		u32 softrst_en_p		: 1;
> +		u32 force_softreset_valid	: 1;
> +		u32 softreset_rdy		: 1;
> +		u32 reserved1			: 9;
> +	} reg01;
> +
> +	struct rkvdec_sysctrl {
> +		u32 in_endian			: 1;
> +		u32 in_swap32_e			: 1;
> +		u32 in_swap64_e			: 1;
> +		u32 str_endian			: 1;
> +		u32 str_swap32_e		: 1;
> +		u32 str_swap64_e		: 1;
> +		u32 out_endian			: 1;
> +		u32 out_swap32_e		: 1;
> +		u32 out_cbcr_swap		: 1;
> +		u32 reserved0			: 1;
> +		u32 rlc_mode_direct_write	: 1;
> +		u32 rlc_mode			: 1;
> +		u32 strm_start_bit		: 7;
> +		u32 reserved1			: 1;
> +		u32 dec_mode			: 2;
> +		u32 reserved2			: 2;
> +		u32 rps_mode			: 1;
> +		u32 stream_mode			: 1;
> +		u32 stream_lastpacket		: 1;
> +		u32 firstslice_flag		: 1;
> +		u32 frame_orslice		: 1;
> +		u32 buspr_slot_disable		: 1;
> +		u32 reserved3			: 2;
> +	} reg02;
> +
> +	struct rkvdec_picpar {
> +		u32 y_hor_virstride	: 9;
> +		u32 reserved		: 2;
> +		u32 slice_num_highbit	: 1;
> +		u32 uv_hor_virstride	: 9;
> +		u32 slice_num_lowbits	: 11;
> +	} reg03;
> +
> +	u32 strm_rlc_base;
> +	u32 stream_len;
> +	u32 cabactbl_base;
> +	u32 decout_base;
> +
> +	struct rkvdec_y_virstride {
> +		u32 y_virstride	: 20;
> +		u32 reserved0	: 12;
> +	} reg08;
> +
> +	struct rkvdec_yuv_virstride {
> +		u32 yuv_virstride	: 21;
> +		u32 reserved0		: 11;
> +	} reg09;
> +} __packed;
> +
> +struct ref_base {
> +	u32 field_ref		: 1;
> +	u32 topfield_used_ref	: 1;
> +	u32 botfield_used_ref	: 1;
> +	u32 colmv_used_flag_ref	: 1;
> +	u32 base_addr		: 28;
> +};
> +
> +struct rkvdec_h26x_regs {
> +	struct ref_base ref0_14_base[15];
> +	u32 ref0_14_poc[15];
> +
> +	u32 cur_poc;
> +	u32 rlcwrite_base;
> +	u32 pps_base;
> +	u32 rps_base;
> +
> +	u32 strmd_error_e;
> +
> +	struct {
> +		u32 strmd_error_status		: 28;
> +		u32 colmv_error_ref_picidx	: 4;
> +	} reg45;
> +
> +	struct {
> +		u32 strmd_error_ctu_xoffset	: 8;
> +		u32 strmd_error_ctu_yoffset	: 8;
> +		u32 streamfifo_space2full	: 7;
> +		u32 reserved0			: 1;
> +		u32 vp9_error_ctu0_en		: 1;
> +		u32 reserved1			: 7;
> +	} reg46;
> +
> +	struct {
> +		u32 saowr_xoffet	: 9;
> +		u32 reserved0		: 7;
> +		u32 saowr_yoffset	: 10;
> +		u32 reserved1		: 6;
> +	} reg47;
> +
> +	struct ref_base ref15_base;
> +
> +	u32 ref15_29_poc[15];
> +
> +	u32 performance_cycle;
> +	u32 axi_ddr_rdata;
> +	u32 axi_ddr_wdata;
> +
> +	struct {
> +		u32 busifd_resetn	: 1;
> +		u32 cabac_resetn	: 1;
> +		u32 dec_ctrl_resetn	: 1;
> +		u32 transd_resetn	: 1;
> +		u32 intra_resetn	: 1;
> +		u32 inter_resetn	: 1;
> +		u32 recon_resetn	: 1;
> +		u32 filer_resetn	: 1;
> +		u32 reserved0		: 24;
> +	} reg67;
> +
> +	struct {
> +		u32 perf_cnt0_sel	: 6;
> +		u32 reserved0		: 2;
> +		u32 perf_cnt1_sel	: 6;
> +		u32 reserved1		: 2;
> +		u32 perf_cnt2_sel	: 6;
> +		u32 reserved2		: 10;
> +	} reg68;
> +
> +	u32 perf_cnt0;
> +	u32 perf_cnt1;
> +	u32 perf_cnt2;
> +	u32 ref30_poc;
> +	u32 ref31_poc;
> +	u32 cur_poc1;
> +	u32 errorinfo_base;
> +
> +	struct {
> +		u32 slicedec_num		: 14;
> +		u32 reserved0			: 1;
> +		u32 strmd_detect_error_flag	: 1;
> +		u32 error_packet_num		: 14;
> +		u32 reserved1			: 2;
> +	} reg76;
> +
> +	struct {
> +		u32 error_en_highbits	: 30;
> +		u32 reserved		: 2;
> +	} reg77;
> +} __packed;
> +
> +struct rkvdec_vp9_regs {
> +	struct cprheader_offset {
> +		u32 cprheader_offset	: 16;
> +		u32 reserved		: 16;
> +	} reg10;
> +
> +	u32 refer_bases[3];
> +	u32 count_base;
> +	u32 segidlast_base;
> +	u32 segidcur_base;
> +
> +	struct frame_sizes {
> +		u32 framewidth		: 16;
> +		u32 frameheight		: 16;
> +	} reg17_19[3];
> +
> +	struct segid_grp {
> +		u32 segid_abs_delta			: 1;
> +		u32 segid_frame_qp_delta_en		: 1;
> +		u32 segid_frame_qp_delta		: 9;
> +		u32 segid_frame_loopfilter_value_en	: 1;
> +		u32 segid_frame_loopfilter_value	: 7;
> +		u32 segid_referinfo_en			: 1;
> +		u32 segid_referinfo			: 2;
> +		u32 segid_frame_skip_en			: 1;
> +		u32 reserved				: 9;
> +	} reg20_27[8];
> +
> +	struct cprheader_config {
> +		u32 tx_mode			: 3;
> +		u32 frame_reference_mode	: 2;
> +		u32 reserved			: 27;
> +	} reg28;
> +
> +	struct ref_scale {
> +		u32 ref_hor_scale		: 16;
> +		u32 ref_ver_scale		: 16;
> +	} reg29_31[3];
> +
> +	struct ref_deltas_lastframe {
> +		u32 ref_deltas_lastframe0	: 7;
> +		u32 ref_deltas_lastframe1	: 7;
> +		u32 ref_deltas_lastframe2	: 7;
> +		u32 ref_deltas_lastframe3	: 7;
> +		u32 reserved			: 4;
> +	} reg32;
> +
> +	struct info_lastframe {
> +		u32 mode_deltas_lastframe0		: 7;
> +		u32 mode_deltas_lastframe1		: 7;
> +		u32 reserved0				: 2;
> +		u32 segmentation_enable_lstframe	: 1;
> +		u32 last_show_frame			: 1;
> +		u32 last_intra_only			: 1;
> +		u32 last_widthheight_eqcur		: 1;
> +		u32 color_space_lastkeyframe		: 3;
> +		u32 reserved1				: 9;
> +	} reg33;
> +
> +	u32 intercmd_base;
> +
> +	struct intercmd_num {
> +		u32 intercmd_num	: 24;
> +		u32 reserved		: 8;
> +	} reg35;
> +
> +	struct lasttile_size {
> +		u32 lasttile_size	: 24;
> +		u32 reserved		: 8;
> +	} reg36;
> +
> +	struct hor_virstride {
> +		u32 y_hor_virstride	: 9;
> +		u32 reserved0		: 7;
> +		u32 uv_hor_virstride	: 9;
> +		u32 reserved1		: 7;
> +	} reg37_39[3];
> +
> +	u32 cur_poc;
> +
> +	struct rlcwrite_base {
> +		u32 reserved		: 3;
> +		u32 rlcwrite_base	: 29;
> +	} reg41;
> +
> +	struct pps_base {
> +		u32 reserved	: 4;
> +		u32 pps_base	: 28;
> +	} reg42;
> +
> +	struct rps_base {
> +		u32 reserved	: 4;
> +		u32 rps_base	: 28;
> +	} reg43;
> +
> +	struct strmd_error_en {
> +		u32 strmd_error_e	: 28;
> +		u32 reserved		: 4;
> +	} reg44;
> +
> +	u32 vp9_error_info0;
> +
> +	struct strmd_error_ctu {
> +		u32 strmd_error_ctu_xoffset	: 8;
> +		u32 strmd_error_ctu_yoffset	: 8;
> +		u32 streamfifo_space2full	: 7;
> +		u32 reserved0			: 1;
> +		u32 error_ctu0_en		: 1;
> +		u32 reserved1			: 7;
> +	} reg46;
> +
> +	struct sao_ctu_position {
> +		u32 saowr_xoffet	: 9;
> +		u32 reserved0		: 7;
> +		u32 saowr_yoffset	: 10;
> +		u32 reserved1		: 6;
> +	} reg47;
> +
> +	struct ystride {
> +		u32 virstride	: 20;
> +		u32 reserved	: 12;
> +	} reg48_50[3];
> +
> +	struct lastref_yuvstride {
> +		u32 lastref_yuv_virstride	: 21;
> +		u32 reserved			: 11;
> +	} reg51;
> +
> +	u32 refcolmv_base;
> +
> +	u32 reserved0[11];
> +
> +	u32 performance_cycle;
> +	u32 axi_ddr_rdata;
> +	u32 axi_ddr_wdata;
> +
> +	struct fpgadebug_reset {
> +		u32 busifd_resetn	: 1;
> +		u32 cabac_resetn	: 1;
> +		u32 dec_ctrl_resetn	: 1;
> +		u32 transd_resetn	: 1;
> +		u32 intra_resetn	: 1;
> +		u32 inter_resetn	: 1;
> +		u32 recon_resetn	: 1;
> +		u32 filer_resetn	: 1;
> +		u32 reserved		: 24;
> +	} reg67;
> +
> +	struct performance_sel {
> +		u32 perf_cnt0_sel	: 6;
> +		u32 reserved0		: 2;
> +		u32 perf_cnt1_sel	: 6;
> +		u32 reserved1		: 2;
> +		u32 perf_cnt2_sel	: 6;
> +		u32 reserved		: 10;
> +	} reg68;
> +
> +	u32 perf_cnt0;
> +	u32 perf_cnt1;
> +	u32 perf_cnt2;
> +
> +	u32 reserved1[3];
> +
> +	u32 vp9_error_info1;
> +
> +	struct error_ctu1 {
> +		u32 vp9_error_ctu1_x	: 6;
> +		u32 reserved0		: 2;
> +		u32 vp9_error_ctu1_y	: 6;
> +		u32 reserved1		: 1;
> +		u32 vp9_error_ctu1_en	: 1;
> +		u32 reserved2		: 16;
> +	} reg76;
> +
> +	u32 reserved2;
> +} __packed;
> +
> +struct rkvdec_regs {
> +	struct rkvdec_common_regs common;
> +	union {
> +		struct rkvdec_h26x_regs h26x;
> +		struct rkvdec_vp9_regs? vp9;
> +	};
> +} __packed;
> +
> ?#endif /* RKVDEC_REGS_H_ */
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
> index b4bf01e839ef..0cf5a559701c 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
> @@ -163,6 +163,7 @@ struct rkvdec_vp9_ctx {
> ?	struct v4l2_vp9_frame_context frame_context[4];
> ?	struct rkvdec_vp9_frame_info cur;
> ?	struct rkvdec_vp9_frame_info last;
> +	struct rkvdec_regs regs;
> ?};
> ?
> ?static void write_coeff_plane(const u8 coef[6][6][3], u8 *coeff_plane)
> @@ -347,38 +348,6 @@ static void init_probs(struct rkvdec_ctx *ctx,
> ?		init_inter_probs(ctx, run);
> ?}
> ?
> -struct rkvdec_vp9_ref_reg {
> -	u32 reg_frm_size;
> -	u32 reg_hor_stride;
> -	u32 reg_y_stride;
> -	u32 reg_yuv_stride;
> -	u32 reg_ref_base;
> -};
> -
> -static struct rkvdec_vp9_ref_reg ref_regs[] = {
> -	{
> -		.reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(0),
> -		.reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(0),
> -		.reg_y_stride = RKVDEC_VP9_LAST_FRAME_YSTRIDE,
> -		.reg_yuv_stride = RKVDEC_VP9_LAST_FRAME_YUVSTRIDE,
> -		.reg_ref_base = RKVDEC_REG_VP9_LAST_FRAME_BASE,
> -	},
> -	{
> -		.reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(1),
> -		.reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(1),
> -		.reg_y_stride = RKVDEC_VP9_GOLDEN_FRAME_YSTRIDE,
> -		.reg_yuv_stride = 0,
> -		.reg_ref_base = RKVDEC_REG_VP9_GOLDEN_FRAME_BASE,
> -	},
> -	{
> -		.reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(2),
> -		.reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(2),
> -		.reg_y_stride = RKVDEC_VP9_ALTREF_FRAME_YSTRIDE,
> -		.reg_yuv_stride = 0,
> -		.reg_ref_base = RKVDEC_REG_VP9_ALTREF_FRAME_BASE,
> -	}
> -};
> -
> ?static struct rkvdec_decoded_buffer *
> ?get_ref_buf(struct rkvdec_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp)
> ?{
> @@ -412,18 +381,17 @@ static dma_addr_t get_mv_base_addr(struct rkvdec_decoded_buffer *buf)
> ?static void config_ref_registers(struct rkvdec_ctx *ctx,
> ?				 const struct rkvdec_vp9_run *run,
> ?				 struct rkvdec_decoded_buffer *ref_buf,
> -				 struct rkvdec_vp9_ref_reg *ref_reg)
> +				 int i)
> ?{
> ?	unsigned int aligned_pitch, aligned_height, y_len, yuv_len;
> -	struct rkvdec_dev *rkvdec = ctx->dev;
> +	struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
> +	struct rkvdec_regs *regs = &vp9_ctx->regs;
> ?
> ?	aligned_height = round_up(ref_buf->vp9.height, 64);
> -	writel_relaxed(RKVDEC_VP9_FRAMEWIDTH(ref_buf->vp9.width) |
> -		?????? RKVDEC_VP9_FRAMEHEIGHT(ref_buf->vp9.height),
> -		?????? rkvdec->regs + ref_reg->reg_frm_size);
> +	regs->vp9.reg17_19[i].frameheight = ref_buf->vp9.height;
> +	regs->vp9.reg17_19[i].framewidth = ref_buf->vp9.width;
> ?
> -	writel_relaxed(vb2_dma_contig_plane_dma_addr(&ref_buf->base.vb.vb2_buf, 0),
> -		?????? rkvdec->regs + ref_reg->reg_ref_base);
> +	regs->vp9.refer_bases[i] = vb2_dma_contig_plane_dma_addr(&ref_buf->base.vb.vb2_buf, 0);
> ?
> ?	if (&ref_buf->base.vb == run->base.bufs.dst)
> ?		return;
> @@ -432,59 +400,50 @@ static void config_ref_registers(struct rkvdec_ctx *ctx,
> ?	y_len = aligned_height * aligned_pitch;
> ?	yuv_len = (y_len * 3) / 2;
> ?
> -	writel_relaxed(RKVDEC_HOR_Y_VIRSTRIDE(aligned_pitch / 16) |
> -		?????? RKVDEC_HOR_UV_VIRSTRIDE(aligned_pitch / 16),
> -		?????? rkvdec->regs + ref_reg->reg_hor_stride);
> -	writel_relaxed(RKVDEC_VP9_REF_YSTRIDE(y_len / 16),
> -		?????? rkvdec->regs + ref_reg->reg_y_stride);
> -
> -	if (!ref_reg->reg_yuv_stride)
> -		return;
> +	regs->vp9.reg37_39[i].y_hor_virstride = aligned_pitch / 16;
> +	regs->vp9.reg37_39[i].uv_hor_virstride = aligned_pitch / 16;
> +	regs->vp9.reg48_50[i].virstride = y_len / 16;
> ?
> -	writel_relaxed(RKVDEC_VP9_REF_YUVSTRIDE(yuv_len / 16),
> -		?????? rkvdec->regs + ref_reg->reg_yuv_stride);
> +	if (!i)
> +		regs->vp9.reg51.lastref_yuv_virstride = yuv_len / 16;
> ?}
> ?
> ?static void config_seg_registers(struct rkvdec_ctx *ctx, unsigned int segid)
> ?{
> ?	struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
> +	struct rkvdec_regs *regs = &vp9_ctx->regs;
> ?	const struct v4l2_vp9_segmentation *seg;
> -	struct rkvdec_dev *rkvdec = ctx->dev;
> ?	s16 feature_val;
> ?	int feature_id;
> -	u32 val = 0;
> ?
> ?	seg = vp9_ctx->last.valid ? &vp9_ctx->last.seg : &vp9_ctx->cur.seg;
> ?	feature_id = V4L2_VP9_SEG_LVL_ALT_Q;
> ?	if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid)) {
> ?		feature_val = seg->feature_data[segid][feature_id];
> -		val |= RKVDEC_SEGID_FRAME_QP_DELTA_EN(1) |
> -		?????? RKVDEC_SEGID_FRAME_QP_DELTA(feature_val);
> +		regs->vp9.reg20_27[segid].segid_frame_qp_delta_en = 1;
> +		regs->vp9.reg20_27[segid].segid_frame_qp_delta = feature_val;
> ?	}
> ?
> ?	feature_id = V4L2_VP9_SEG_LVL_ALT_L;
> ?	if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid)) {
> ?		feature_val = seg->feature_data[segid][feature_id];
> -		val |= RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE_EN(1) |
> -		?????? RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE(feature_val);
> +		regs->vp9.reg20_27[segid].segid_frame_loopfilter_value_en = 1;
> +		regs->vp9.reg20_27[segid].segid_frame_loopfilter_value = feature_val;
> ?	}
> ?
> ?	feature_id = V4L2_VP9_SEG_LVL_REF_FRAME;
> ?	if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid)) {
> ?		feature_val = seg->feature_data[segid][feature_id];
> -		val |= RKVDEC_SEGID_REFERINFO_EN(1) |
> -		?????? RKVDEC_SEGID_REFERINFO(feature_val);
> +		regs->vp9.reg20_27[segid].segid_referinfo_en = 1;
> +		regs->vp9.reg20_27[segid].segid_referinfo = feature_val;
> ?	}
> ?
> ?	feature_id = V4L2_VP9_SEG_LVL_SKIP;
> -	if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid))
> -		val |= RKVDEC_SEGID_FRAME_SKIP_EN(1);
> -
> -	if (!segid &&
> -	??? (seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE))
> -		val |= RKVDEC_SEGID_ABS_DELTA(1);
> +	regs->vp9.reg20_27[segid].segid_frame_skip_en =
> +		v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid);
> ?
> -	writel_relaxed(val, rkvdec->regs + RKVDEC_VP9_SEGID_GRP(segid));
> +	regs->vp9.reg20_27[segid].segid_abs_delta = !segid &&
> +		(seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE);
> ?}
> ?
> ?static void update_dec_buf_info(struct rkvdec_decoded_buffer *buf,
> @@ -521,7 +480,8 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?	struct rkvdec_decoded_buffer *ref_bufs[3];
> ?	struct rkvdec_decoded_buffer *dst, *last, *mv_ref;
> ?	struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
> -	u32 val, last_frame_info = 0;
> +	struct rkvdec_regs *regs = &vp9_ctx->regs;
> +	u32 val;
> ?	const struct v4l2_vp9_segmentation *seg;
> ?	struct rkvdec_dev *rkvdec = ctx->dev;
> ?	dma_addr_t addr;
> @@ -547,8 +507,7 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?			(V4L2_VP9_FRAME_FLAG_KEY_FRAME |
> ?			 V4L2_VP9_FRAME_FLAG_INTRA_ONLY));
> ?
> -	writel_relaxed(RKVDEC_MODE(RKVDEC_MODE_VP9),
> -		?????? rkvdec->regs + RKVDEC_REG_SYSCTRL);
> +	regs->common.reg02.dec_mode = RKVDEC_MODE_VP9;
> ?
> ?	bit_depth = dec_params->bit_depth;
> ?	aligned_height = round_up(ctx->decoded_fmt.fmt.pix_mp.height, 64);
> @@ -560,17 +519,14 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?	uv_len = y_len / 2;
> ?	yuv_len = y_len + uv_len;
> ?
> -	writel_relaxed(RKVDEC_Y_HOR_VIRSTRIDE(aligned_pitch / 16) |
> -		?????? RKVDEC_UV_HOR_VIRSTRIDE(aligned_pitch / 16),
> -		?????? rkvdec->regs + RKVDEC_REG_PICPAR);
> -	writel_relaxed(RKVDEC_Y_VIRSTRIDE(y_len / 16),
> -		?????? rkvdec->regs + RKVDEC_REG_Y_VIRSTRIDE);
> -	writel_relaxed(RKVDEC_YUV_VIRSTRIDE(yuv_len / 16),
> -		?????? rkvdec->regs + RKVDEC_REG_YUV_VIRSTRIDE);
> +	regs->common.reg03.y_hor_virstride = aligned_pitch / 16;
> +	regs->common.reg03.uv_hor_virstride = aligned_pitch / 16;
> +	regs->common.reg08.y_virstride = y_len / 16;
> +	regs->common.reg09.yuv_virstride = yuv_len / 16;
> ?
> ?	stream_len = vb2_get_plane_payload(&run->base.bufs.src->vb2_buf, 0);
> -	writel_relaxed(RKVDEC_STRM_LEN(stream_len),
> -		?????? rkvdec->regs + RKVDEC_REG_STRM_LEN);
> +
> +	regs->common.stream_len = stream_len;
> ?
> ?	/*
> ?	 * Reset count buffer, because decoder only output intra related syntax
> @@ -588,14 +544,13 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?		vp9_ctx->cur.segmapid++;
> ?
> ?	for (i = 0; i < ARRAY_SIZE(ref_bufs); i++)
> -		config_ref_registers(ctx, run, ref_bufs[i], &ref_regs[i]);
> +		config_ref_registers(ctx, run, ref_bufs[i], i);
> ?
> ?	for (i = 0; i < 8; i++)
> ?		config_seg_registers(ctx, i);
> ?
> -	writel_relaxed(RKVDEC_VP9_TX_MODE(vp9_ctx->cur.tx_mode) |
> -		?????? RKVDEC_VP9_FRAME_REF_MODE(dec_params->reference_mode),
> -		?????? rkvdec->regs + RKVDEC_VP9_CPRHEADER_CONFIG);
> +	regs->vp9.reg28.tx_mode = vp9_ctx->cur.tx_mode;
> +	regs->vp9.reg28.frame_reference_mode = dec_params->reference_mode;
> ?
> ?	if (!intra_only) {
> ?		const struct v4l2_vp9_loop_filter *lf;
> @@ -609,43 +564,56 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?		val = 0;
> ?		for (i = 0; i < ARRAY_SIZE(lf->ref_deltas); i++) {
> ?			delta = lf->ref_deltas[i];
> -			val |= RKVDEC_REF_DELTAS_LASTFRAME(i, delta);
> +			switch (i) {
> +			case 0:
> +				regs->vp9.reg32.ref_deltas_lastframe0 = delta;
> +				break;
> +			case 1:
> +				regs->vp9.reg32.ref_deltas_lastframe1 = delta;
> +				break;
> +			case 2:
> +				regs->vp9.reg32.ref_deltas_lastframe2 = delta;
> +				break;
> +			case 3:
> +				regs->vp9.reg32.ref_deltas_lastframe3 = delta;
> +				break;
> +			}
> ?		}
> ?
> -		writel_relaxed(val,
> -			?????? rkvdec->regs + RKVDEC_VP9_REF_DELTAS_LASTFRAME);
> -
> ?		for (i = 0; i < ARRAY_SIZE(lf->mode_deltas); i++) {
> ?			delta = lf->mode_deltas[i];
> -			last_frame_info |= RKVDEC_MODE_DELTAS_LASTFRAME(i,
> -									delta);
> +			switch (i) {
> +			case 0:
> +				regs->vp9.reg33.mode_deltas_lastframe0 = delta;
> +				break;
> +			case 1:
> +				regs->vp9.reg33.mode_deltas_lastframe1 = delta;
> +				break;
> +			}
> ?		}
> ?	}
> ?
> -	if (vp9_ctx->last.valid && !intra_only &&
> -	??? vp9_ctx->last.seg.flags & V4L2_VP9_SEGMENTATION_FLAG_ENABLED)
> -		last_frame_info |= RKVDEC_SEG_EN_LASTFRAME;
> +	regs->vp9.reg33.segmentation_enable_lstframe =
> +		vp9_ctx->last.valid && !intra_only &&
> +		vp9_ctx->last.seg.flags & V4L2_VP9_SEGMENTATION_FLAG_ENABLED;
> ?
> -	if (vp9_ctx->last.valid &&
> -	??? vp9_ctx->last.flags & V4L2_VP9_FRAME_FLAG_SHOW_FRAME)
> -		last_frame_info |= RKVDEC_LAST_SHOW_FRAME;
> +	regs->vp9.reg33.last_show_frame =
> +		vp9_ctx->last.valid &&
> +		vp9_ctx->last.flags & V4L2_VP9_FRAME_FLAG_SHOW_FRAME;
> ?
> -	if (vp9_ctx->last.valid &&
> -	??? vp9_ctx->last.flags &
> -	??? (V4L2_VP9_FRAME_FLAG_KEY_FRAME | V4L2_VP9_FRAME_FLAG_INTRA_ONLY))
> -		last_frame_info |= RKVDEC_LAST_INTRA_ONLY;
> +	regs->vp9.reg33.last_intra_only =
> +		vp9_ctx->last.valid &&
> +		vp9_ctx->last.flags &
> +		(V4L2_VP9_FRAME_FLAG_KEY_FRAME | V4L2_VP9_FRAME_FLAG_INTRA_ONLY);
> ?
> -	if (vp9_ctx->last.valid &&
> -	??? last->vp9.width == dst->vp9.width &&
> -	??? last->vp9.height == dst->vp9.height)
> -		last_frame_info |= RKVDEC_LAST_WIDHHEIGHT_EQCUR;
> +	regs->vp9.reg33.last_widthheight_eqcur =
> +		vp9_ctx->last.valid &&
> +		last->vp9.width == dst->vp9.width &&
> +		last->vp9.height == dst->vp9.height;
> ?
> -	writel_relaxed(last_frame_info,
> -		?????? rkvdec->regs + RKVDEC_VP9_INFO_LASTFRAME);
> -
> -	writel_relaxed(stream_len - dec_params->compressed_header_size -
> -		?????? dec_params->uncompressed_header_size,
> -		?????? rkvdec->regs + RKVDEC_VP9_LASTTILE_SIZE);
> +	regs->vp9.reg36.lasttile_size =
> +		stream_len - dec_params->compressed_header_size -
> +		dec_params->uncompressed_header_size;
> ?
> ?	for (i = 0; !intra_only && i < ARRAY_SIZE(ref_bufs); i++) {
> ?		unsigned int refw = ref_bufs[i]->vp9.width;
> @@ -654,29 +622,28 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?
> ?		hscale = (refw << 14) /	dst->vp9.width;
> ?		vscale = (refh << 14) / dst->vp9.height;
> -		writel_relaxed(RKVDEC_VP9_REF_HOR_SCALE(hscale) |
> -			?????? RKVDEC_VP9_REF_VER_SCALE(vscale),
> -			?????? rkvdec->regs + RKVDEC_VP9_REF_SCALE(i));
> +
> +		regs->vp9.reg29_31[i].ref_hor_scale = hscale;
> +		regs->vp9.reg29_31[i].ref_ver_scale = vscale;
> ?	}
> ?
> ?	addr = vb2_dma_contig_plane_dma_addr(&dst->base.vb.vb2_buf, 0);
> -	writel_relaxed(addr, rkvdec->regs + RKVDEC_REG_DECOUT_BASE);
> +	regs->common.decout_base = addr;
> ?	addr = vb2_dma_contig_plane_dma_addr(&run->base.bufs.src->vb2_buf, 0);
> -	writel_relaxed(addr, rkvdec->regs + RKVDEC_REG_STRM_RLC_BASE);
> -	writel_relaxed(vp9_ctx->priv_tbl.dma +
> -		?????? offsetof(struct rkvdec_vp9_priv_tbl, probs),
> -		?????? rkvdec->regs + RKVDEC_REG_CABACTBL_PROB_BASE);
> -	writel_relaxed(vp9_ctx->count_tbl.dma,
> -		?????? rkvdec->regs + RKVDEC_REG_VP9COUNT_BASE);
> -
> -	writel_relaxed(vp9_ctx->priv_tbl.dma +
> -		?????? offsetof(struct rkvdec_vp9_priv_tbl, segmap) +
> -		?????? (RKVDEC_VP9_MAX_SEGMAP_SIZE * vp9_ctx->cur.segmapid),
> -		?????? rkvdec->regs + RKVDEC_REG_VP9_SEGIDCUR_BASE);
> -	writel_relaxed(vp9_ctx->priv_tbl.dma +
> -		?????? offsetof(struct rkvdec_vp9_priv_tbl, segmap) +
> -		?????? (RKVDEC_VP9_MAX_SEGMAP_SIZE * (!vp9_ctx->cur.segmapid)),
> -		?????? rkvdec->regs + RKVDEC_REG_VP9_SEGIDLAST_BASE);
> +	regs->common.strm_rlc_base = addr;
> +
> +	regs->common.cabactbl_base = vp9_ctx->priv_tbl.dma +
> +		offsetof(struct rkvdec_vp9_priv_tbl, probs);
> +
> +	regs->vp9.count_base = vp9_ctx->count_tbl.dma;
> +
> +	regs->vp9.segidlast_base = vp9_ctx->priv_tbl.dma +
> +		offsetof(struct rkvdec_vp9_priv_tbl, segmap) +
> +		(RKVDEC_VP9_MAX_SEGMAP_SIZE * (!vp9_ctx->cur.segmapid));
> +
> +	regs->vp9.segidcur_base = vp9_ctx->priv_tbl.dma +
> +		offsetof(struct rkvdec_vp9_priv_tbl, segmap) +
> +		(RKVDEC_VP9_MAX_SEGMAP_SIZE * vp9_ctx->cur.segmapid);
> ?
> ?	if (!intra_only &&
> ?	??? !(dec_params->flags & V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT) &&
> @@ -685,12 +652,14 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?	else
> ?		mv_ref = dst;
> ?
> -	writel_relaxed(get_mv_base_addr(mv_ref),
> -		?????? rkvdec->regs + RKVDEC_VP9_REF_COLMV_BASE);
> +	regs->vp9.refcolmv_base = get_mv_base_addr(mv_ref);
> ?
> -	writel_relaxed(ctx->decoded_fmt.fmt.pix_mp.width |
> -		?????? (ctx->decoded_fmt.fmt.pix_mp.height << 16),
> -		?????? rkvdec->regs + RKVDEC_REG_PERFORMANCE_CYCLE);
> +	regs->vp9.performance_cycle = ctx->decoded_fmt.fmt.pix_mp.width |
> +		?????? (ctx->decoded_fmt.fmt.pix_mp.height << 16);
> +
> +	regs->vp9.reg44.strmd_error_e = 0xe;
> +
> +	rkvdec_memcpy_toio(rkvdec->regs, regs, MIN(sizeof(*regs), rkvdec->variant->num_regs));
> ?}
> ?
> ?static int validate_dec_params(struct rkvdec_ctx *ctx,
> @@ -823,8 +792,6 @@ static int rkvdec_vp9_run(struct rkvdec_ctx *ctx)
> ?	writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND);
> ?	writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);
> ?
> -	writel(0xe, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN);
> -
> ?	if (rkvdec->variant->quirks & RKVDEC_QUIRK_DISABLE_QOS)
> ?		rkvdec_quirks_disable_qos(ctx);
> ?
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> index 5af9aa5ab353..776149f871b0 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> @@ -914,6 +914,15 @@ void rkvdec_quirks_disable_qos(struct rkvdec_ctx *ctx)
> ?	writel(reg, rkvdec->regs + RKVDEC_REG_QOS_CTRL);
> ?}
> ?
> +void rkvdec_memcpy_toio(void __iomem *dst, void *src, size_t len)
> +{
> +#ifdef CONFIG_ARM64
> +	__iowrite32_copy(dst, src, len / 4);
> +#else
> +	memcpy_toio(dst, src, len);
> +#endif
> +}
> +
> ?static void rkvdec_device_run(void *priv)
> ?{
> ?	struct rkvdec_ctx *ctx = priv;
> @@ -1227,7 +1236,6 @@ static void rkvdec_watchdog_func(struct work_struct *work)
> ?	if (ctx) {
> ?		dev_err(rkvdec->dev, "Frame processing timed out!\n");
> ?		writel(RKVDEC_IRQ_DIS, rkvdec->regs + RKVDEC_REG_INTERRUPT);
> -		writel(0, rkvdec->regs + RKVDEC_REG_SYSCTRL);
> ?		rkvdec_job_finish(ctx, VB2_BUF_STATE_ERROR);
> ?	}
> ?}
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> index 566e06fa2b1e..f35f6e80ea2e 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> @@ -151,6 +151,7 @@ struct rkvdec_aux_buf {
> ?
> ?void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run);
> ?void rkvdec_run_postamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run);
> +void rkvdec_memcpy_toio(void __iomem *dst, void *src, size_t len);
> ?
> ?void rkvdec_quirks_disable_qos(struct rkvdec_ctx *ctx);
> ?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251210/40b2a140/attachment-0001.sig>

From nicolas.dufresne at collabora.com  Wed Dec 10 12:18:03 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Wed, 10 Dec 2025 15:18:03 -0500
Subject: [PATCH v4 04/15] media: rkvdec: Move cabac tables to their own
 source file
In-Reply-To: <20251022174508.284929-5-detlev.casanova@collabora.com>
References: <20251022174508.284929-1-detlev.casanova@collabora.com>
	 <20251022174508.284929-5-detlev.casanova@collabora.com>
Message-ID: <1d129311cd328cd6848a099a71566d743a7d3128.camel@collabora.com>

Le mercredi 22 octobre 2025 ? 13:44 -0400, Detlev Casanova a ?crit?:
> This is in preparation to add support for new variants that will use the
> same tables.
> 
> Tested-by: Diederik de Haas <didi.debian at cknow.org>? # Rock 5B
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?.../media/platform/rockchip/rkvdec/Makefile?? |?? 7 +-
> ?.../{rkvdec-hevc-data.c => rkvdec-cabac.c}??? | 506 +++++++++++++++++-
> ?.../platform/rockchip/rkvdec/rkvdec-h264.c??? | 501 +----------------
> ?.../platform/rockchip/rkvdec/rkvdec-hevc.c??? |?? 6 +-
> ?4 files changed, 514 insertions(+), 506 deletions(-)
> ?rename drivers/media/platform/rockchip/rkvdec/{rkvdec-hevc-data.c => rkvdec-cabac.c} (86%)
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
> index a77122641d14..a8ff5e3d7bec 100644
> --- a/drivers/media/platform/rockchip/rkvdec/Makefile
> +++ b/drivers/media/platform/rockchip/rkvdec/Makefile
> @@ -1,3 +1,8 @@
> ?obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC) += rockchip-vdec.o
> ?
> -rockchip-vdec-y += rkvdec.o rkvdec-h264.o rkvdec-hevc.o rkvdec-vp9.o
> +rockchip-vdec-y += \
> +		?? rkvdec.o \
> +		?? rkvdec-cabac.o \
> +		?? rkvdec-h264.o \
> +		?? rkvdec-hevc.o \
> +		?? rkvdec-vp9.o
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-data.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-cabac.c
> similarity index 86%
> rename from drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-data.c
> rename to drivers/media/platform/rockchip/rkvdec/rkvdec-cabac.c
> index eac4ea604949..bc87f59636ea 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-data.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-cabac.c
> @@ -1,19 +1,517 @@
> ?// SPDX-License-Identifier: GPL-2.0
> ?/*
> - * Rockchip Video Decoder driver
> + * Rockchip Video Decoder CABAC tables
> ? *
> ? * Copyright (C) 2023 Collabora, Ltd.
> ? *	Sebastian Fricke <sebastian.fricke at collabora.com>
> + * Copyright (C) 2019 Collabora, Ltd.
> + *	Boris Brezillon <boris.brezillon at collabora.com>
> ? */
> ?
> ?#include <linux/types.h>
> ?
> -#define RKV_CABAC_TABLE_SIZE		27456
> +#define CABAC_ENTRY(ctxidx, idc0_m, idc0_n, idc1_m, idc1_n,		\
> +	??? idc2_m, idc2_n, intra_m, intra_n)			\
> +	[0][(ctxidx)] = {idc0_m, idc0_n},			\
> +	[1][(ctxidx)] = {idc1_m, idc1_n},			\
> +	[2][(ctxidx)] = {idc2_m, idc2_n},			\
> +	[3][(ctxidx)] = {intra_m, intra_n}
> ?
> ?/*
> - * This file is #include from rkvdec-hevc.c and not compiled.
> + * Constant CABAC table.
> + * Built from the tables described in section '9.3.1.1 Initialisation process
> + * for context variables' of the H264 spec.
> ? */
> -static const u8 rkvdec_hevc_cabac_table[RKV_CABAC_TABLE_SIZE] = {
> +const s8 rkvdec_h264_cabac_table[4][464][2] = {
> +	/* Table 9-12 ? Values of variables m and n for ctxIdx from 0 to 10 */
> +	CABAC_ENTRY(0, 20, -15, 20, -15, 20, -15, 20, -15),
> +	CABAC_ENTRY(1, 2, 54, 2, 54, 2, 54, 2, 54),
> +	CABAC_ENTRY(2, 3, 74, 3, 74, 3, 74, 3, 74),
> +	CABAC_ENTRY(3, 20, -15, 20, -15, 20, -15, 20, -15),
> +	CABAC_ENTRY(4, 2, 54, 2, 54, 2, 54, 2, 54),
> +	CABAC_ENTRY(5, 3, 74, 3, 74, 3, 74, 3, 74),
> +	CABAC_ENTRY(6, -28, 127, -28, 127, -28, 127, -28, 127),
> +	CABAC_ENTRY(7, -23, 104, -23, 104, -23, 104, -23, 104),
> +	CABAC_ENTRY(8, -6, 53, -6, 53, -6, 53, -6, 53),
> +	CABAC_ENTRY(9, -1, 54, -1, 54, -1, 54, -1, 54),
> +	CABAC_ENTRY(10, 7, 51, 7, 51, 7, 51, 7, 51),
> +
> +	/* Table 9-13 ? Values of variables m and n for ctxIdx from 11 to 23 */
> +	CABAC_ENTRY(11, 23, 33, 22, 25, 29, 16, 0, 0),
> +	CABAC_ENTRY(12, 23, 2, 34, 0, 25, 0, 0, 0),
> +	CABAC_ENTRY(13, 21, 0, 16, 0, 14, 0, 0, 0),
> +	CABAC_ENTRY(14, 1, 9, -2, 9, -10, 51, 0, 0),
> +	CABAC_ENTRY(15, 0, 49, 4, 41, -3, 62, 0, 0),
> +	CABAC_ENTRY(16, -37, 118, -29, 118, -27, 99, 0, 0),
> +	CABAC_ENTRY(17, 5, 57, 2, 65, 26, 16, 0, 0),
> +	CABAC_ENTRY(18, -13, 78, -6, 71, -4, 85, 0, 0),
> +	CABAC_ENTRY(19, -11, 65, -13, 79, -24, 102, 0, 0),
> +	CABAC_ENTRY(20, 1, 62, 5, 52, 5, 57, 0, 0),
> +	CABAC_ENTRY(21, 12, 49, 9, 50, 6, 57, 0, 0),
> +	CABAC_ENTRY(22, -4, 73, -3, 70, -17, 73, 0, 0),
> +	CABAC_ENTRY(23, 17, 50, 10, 54, 14, 57, 0, 0),
> +
> +	/* Table 9-14 ? Values of variables m and n for ctxIdx from 24 to 39 */
> +	CABAC_ENTRY(24, 18, 64, 26, 34, 20, 40, 0, 0),
> +	CABAC_ENTRY(25, 9, 43, 19, 22, 20, 10, 0, 0),
> +	CABAC_ENTRY(26, 29, 0, 40, 0, 29, 0, 0, 0),
> +	CABAC_ENTRY(27, 26, 67, 57, 2, 54, 0, 0, 0),
> +	CABAC_ENTRY(28, 16, 90, 41, 36, 37, 42, 0, 0),
> +	CABAC_ENTRY(29, 9, 104, 26, 69, 12, 97, 0, 0),
> +	CABAC_ENTRY(30, -46, 127, -45, 127, -32, 127, 0, 0),
> +	CABAC_ENTRY(31, -20, 104, -15, 101, -22, 117, 0, 0),
> +	CABAC_ENTRY(32, 1, 67, -4, 76, -2, 74, 0, 0),
> +	CABAC_ENTRY(33, -13, 78, -6, 71, -4, 85, 0, 0),
> +	CABAC_ENTRY(34, -11, 65, -13, 79, -24, 102, 0, 0),
> +	CABAC_ENTRY(35, 1, 62, 5, 52, 5, 57, 0, 0),
> +	CABAC_ENTRY(36, -6, 86, 6, 69, -6, 93, 0, 0),
> +	CABAC_ENTRY(37, -17, 95, -13, 90, -14, 88, 0, 0),
> +	CABAC_ENTRY(38, -6, 61, 0, 52, -6, 44, 0, 0),
> +	CABAC_ENTRY(39, 9, 45, 8, 43, 4, 55, 0, 0),
> +
> +	/* Table 9-15 ? Values of variables m and n for ctxIdx from 40 to 53 */
> +	CABAC_ENTRY(40, -3, 69, -2, 69, -11, 89, 0, 0),
> +	CABAC_ENTRY(41, -6, 81, -5, 82, -15, 103, 0, 0),
> +	CABAC_ENTRY(42, -11, 96, -10, 96, -21, 116, 0, 0),
> +	CABAC_ENTRY(43, 6, 55, 2, 59, 19, 57, 0, 0),
> +	CABAC_ENTRY(44, 7, 67, 2, 75, 20, 58, 0, 0),
> +	CABAC_ENTRY(45, -5, 86, -3, 87, 4, 84, 0, 0),
> +	CABAC_ENTRY(46, 2, 88, -3, 100, 6, 96, 0, 0),
> +	CABAC_ENTRY(47, 0, 58, 1, 56, 1, 63, 0, 0),
> +	CABAC_ENTRY(48, -3, 76, -3, 74, -5, 85, 0, 0),
> +	CABAC_ENTRY(49, -10, 94, -6, 85, -13, 106, 0, 0),
> +	CABAC_ENTRY(50, 5, 54, 0, 59, 5, 63, 0, 0),
> +	CABAC_ENTRY(51, 4, 69, -3, 81, 6, 75, 0, 0),
> +	CABAC_ENTRY(52, -3, 81, -7, 86, -3, 90, 0, 0),
> +	CABAC_ENTRY(53, 0, 88, -5, 95, -1, 101, 0, 0),
> +
> +	/* Table 9-16 ? Values of variables m and n for ctxIdx from 54 to 59 */
> +	CABAC_ENTRY(54, -7, 67, -1, 66, 3, 55, 0, 0),
> +	CABAC_ENTRY(55, -5, 74, -1, 77, -4, 79, 0, 0),
> +	CABAC_ENTRY(56, -4, 74, 1, 70, -2, 75, 0, 0),
> +	CABAC_ENTRY(57, -5, 80, -2, 86, -12, 97, 0, 0),
> +	CABAC_ENTRY(58, -7, 72, -5, 72, -7, 50, 0, 0),
> +	CABAC_ENTRY(59, 1, 58, 0, 61, 1, 60, 0, 0),
> +
> +	/* Table 9-17 ? Values of variables m and n for ctxIdx from 60 to 69 */
> +	CABAC_ENTRY(60, 0, 41, 0, 41, 0, 41, 0, 41),
> +	CABAC_ENTRY(61, 0, 63, 0, 63, 0, 63, 0, 63),
> +	CABAC_ENTRY(62, 0, 63, 0, 63, 0, 63, 0, 63),
> +	CABAC_ENTRY(63, 0, 63, 0, 63, 0, 63, 0, 63),
> +	CABAC_ENTRY(64, -9, 83, -9, 83, -9, 83, -9, 83),
> +	CABAC_ENTRY(65, 4, 86, 4, 86, 4, 86, 4, 86),
> +	CABAC_ENTRY(66, 0, 97, 0, 97, 0, 97, 0, 97),
> +	CABAC_ENTRY(67, -7, 72, -7, 72, -7, 72, -7, 72),
> +	CABAC_ENTRY(68, 13, 41, 13, 41, 13, 41, 13, 41),
> +	CABAC_ENTRY(69, 3, 62, 3, 62, 3, 62, 3, 62),
> +
> +	/* Table 9-18 ? Values of variables m and n for ctxIdx from 70 to 104 */
> +	CABAC_ENTRY(70, 0, 45, 13, 15, 7, 34, 0, 11),
> +	CABAC_ENTRY(71, -4, 78, 7, 51, -9, 88, 1, 55),
> +	CABAC_ENTRY(72, -3, 96, 2, 80, -20, 127, 0, 69),
> +	CABAC_ENTRY(73, -27, 126, -39, 127, -36, 127, -17, 127),
> +	CABAC_ENTRY(74, -28, 98, -18, 91, -17, 91, -13, 102),
> +	CABAC_ENTRY(75, -25, 101, -17, 96, -14, 95, 0, 82),
> +	CABAC_ENTRY(76, -23, 67, -26, 81, -25, 84, -7, 74),
> +	CABAC_ENTRY(77, -28, 82, -35, 98, -25, 86, -21, 107),
> +	CABAC_ENTRY(78, -20, 94, -24, 102, -12, 89, -27, 127),
> +	CABAC_ENTRY(79, -16, 83, -23, 97, -17, 91, -31, 127),
> +	CABAC_ENTRY(80, -22, 110, -27, 119, -31, 127, -24, 127),
> +	CABAC_ENTRY(81, -21, 91, -24, 99, -14, 76, -18, 95),
> +	CABAC_ENTRY(82, -18, 102, -21, 110, -18, 103, -27, 127),
> +	CABAC_ENTRY(83, -13, 93, -18, 102, -13, 90, -21, 114),
> +	CABAC_ENTRY(84, -29, 127, -36, 127, -37, 127, -30, 127),
> +	CABAC_ENTRY(85, -7, 92, 0, 80, 11, 80, -17, 123),
> +	CABAC_ENTRY(86, -5, 89, -5, 89, 5, 76, -12, 115),
> +	CABAC_ENTRY(87, -7, 96, -7, 94, 2, 84, -16, 122),
> +	CABAC_ENTRY(88, -13, 108, -4, 92, 5, 78, -11, 115),
> +	CABAC_ENTRY(89, -3, 46, 0, 39, -6, 55, -12, 63),
> +	CABAC_ENTRY(90, -1, 65, 0, 65, 4, 61, -2, 68),
> +	CABAC_ENTRY(91, -1, 57, -15, 84, -14, 83, -15, 84),
> +	CABAC_ENTRY(92, -9, 93, -35, 127, -37, 127, -13, 104),
> +	CABAC_ENTRY(93, -3, 74, -2, 73, -5, 79, -3, 70),
> +	CABAC_ENTRY(94, -9, 92, -12, 104, -11, 104, -8, 93),
> +	CABAC_ENTRY(95, -8, 87, -9, 91, -11, 91, -10, 90),
> +	CABAC_ENTRY(96, -23, 126, -31, 127, -30, 127, -30, 127),
> +	CABAC_ENTRY(97, 5, 54, 3, 55, 0, 65, -1, 74),
> +	CABAC_ENTRY(98, 6, 60, 7, 56, -2, 79, -6, 97),
> +	CABAC_ENTRY(99, 6, 59, 7, 55, 0, 72, -7, 91),
> +	CABAC_ENTRY(100, 6, 69, 8, 61, -4, 92, -20, 127),
> +	CABAC_ENTRY(101, -1, 48, -3, 53, -6, 56, -4, 56),
> +	CABAC_ENTRY(102, 0, 68, 0, 68, 3, 68, -5, 82),
> +	CABAC_ENTRY(103, -4, 69, -7, 74, -8, 71, -7, 76),
> +	CABAC_ENTRY(104, -8, 88, -9, 88, -13, 98, -22, 125),
> +
> +	/* Table 9-19 ? Values of variables m and n for ctxIdx from 105 to 165 */
> +	CABAC_ENTRY(105, -2, 85, -13, 103, -4, 86, -7, 93),
> +	CABAC_ENTRY(106, -6, 78, -13, 91, -12, 88, -11, 87),
> +	CABAC_ENTRY(107, -1, 75, -9, 89, -5, 82, -3, 77),
> +	CABAC_ENTRY(108, -7, 77, -14, 92, -3, 72, -5, 71),
> +	CABAC_ENTRY(109, 2, 54, -8, 76, -4, 67, -4, 63),
> +	CABAC_ENTRY(110, 5, 50, -12, 87, -8, 72, -4, 68),
> +	CABAC_ENTRY(111, -3, 68, -23, 110, -16, 89, -12, 84),
> +	CABAC_ENTRY(112, 1, 50, -24, 105, -9, 69, -7, 62),
> +	CABAC_ENTRY(113, 6, 42, -10, 78, -1, 59, -7, 65),
> +	CABAC_ENTRY(114, -4, 81, -20, 112, 5, 66, 8, 61),
> +	CABAC_ENTRY(115, 1, 63, -17, 99, 4, 57, 5, 56),
> +	CABAC_ENTRY(116, -4, 70, -78, 127, -4, 71, -2, 66),
> +	CABAC_ENTRY(117, 0, 67, -70, 127, -2, 71, 1, 64),
> +	CABAC_ENTRY(118, 2, 57, -50, 127, 2, 58, 0, 61),
> +	CABAC_ENTRY(119, -2, 76, -46, 127, -1, 74, -2, 78),
> +	CABAC_ENTRY(120, 11, 35, -4, 66, -4, 44, 1, 50),
> +	CABAC_ENTRY(121, 4, 64, -5, 78, -1, 69, 7, 52),
> +	CABAC_ENTRY(122, 1, 61, -4, 71, 0, 62, 10, 35),
> +	CABAC_ENTRY(123, 11, 35, -8, 72, -7, 51, 0, 44),
> +	CABAC_ENTRY(124, 18, 25, 2, 59, -4, 47, 11, 38),
> +	CABAC_ENTRY(125, 12, 24, -1, 55, -6, 42, 1, 45),
> +	CABAC_ENTRY(126, 13, 29, -7, 70, -3, 41, 0, 46),
> +	CABAC_ENTRY(127, 13, 36, -6, 75, -6, 53, 5, 44),
> +	CABAC_ENTRY(128, -10, 93, -8, 89, 8, 76, 31, 17),
> +	CABAC_ENTRY(129, -7, 73, -34, 119, -9, 78, 1, 51),
> +	CABAC_ENTRY(130, -2, 73, -3, 75, -11, 83, 7, 50),
> +	CABAC_ENTRY(131, 13, 46, 32, 20, 9, 52, 28, 19),
> +	CABAC_ENTRY(132, 9, 49, 30, 22, 0, 67, 16, 33),
> +	CABAC_ENTRY(133, -7, 100, -44, 127, -5, 90, 14, 62),
> +	CABAC_ENTRY(134, 9, 53, 0, 54, 1, 67, -13, 108),
> +	CABAC_ENTRY(135, 2, 53, -5, 61, -15, 72, -15, 100),
> +	CABAC_ENTRY(136, 5, 53, 0, 58, -5, 75, -13, 101),
> +	CABAC_ENTRY(137, -2, 61, -1, 60, -8, 80, -13, 91),
> +	CABAC_ENTRY(138, 0, 56, -3, 61, -21, 83, -12, 94),
> +	CABAC_ENTRY(139, 0, 56, -8, 67, -21, 64, -10, 88),
> +	CABAC_ENTRY(140, -13, 63, -25, 84, -13, 31, -16, 84),
> +	CABAC_ENTRY(141, -5, 60, -14, 74, -25, 64, -10, 86),
> +	CABAC_ENTRY(142, -1, 62, -5, 65, -29, 94, -7, 83),
> +	CABAC_ENTRY(143, 4, 57, 5, 52, 9, 75, -13, 87),
> +	CABAC_ENTRY(144, -6, 69, 2, 57, 17, 63, -19, 94),
> +	CABAC_ENTRY(145, 4, 57, 0, 61, -8, 74, 1, 70),
> +	CABAC_ENTRY(146, 14, 39, -9, 69, -5, 35, 0, 72),
> +	CABAC_ENTRY(147, 4, 51, -11, 70, -2, 27, -5, 74),
> +	CABAC_ENTRY(148, 13, 68, 18, 55, 13, 91, 18, 59),
> +	CABAC_ENTRY(149, 3, 64, -4, 71, 3, 65, -8, 102),
> +	CABAC_ENTRY(150, 1, 61, 0, 58, -7, 69, -15, 100),
> +	CABAC_ENTRY(151, 9, 63, 7, 61, 8, 77, 0, 95),
> +	CABAC_ENTRY(152, 7, 50, 9, 41, -10, 66, -4, 75),
> +	CABAC_ENTRY(153, 16, 39, 18, 25, 3, 62, 2, 72),
> +	CABAC_ENTRY(154, 5, 44, 9, 32, -3, 68, -11, 75),
> +	CABAC_ENTRY(155, 4, 52, 5, 43, -20, 81, -3, 71),
> +	CABAC_ENTRY(156, 11, 48, 9, 47, 0, 30, 15, 46),
> +	CABAC_ENTRY(157, -5, 60, 0, 44, 1, 7, -13, 69),
> +	CABAC_ENTRY(158, -1, 59, 0, 51, -3, 23, 0, 62),
> +	CABAC_ENTRY(159, 0, 59, 2, 46, -21, 74, 0, 65),
> +	CABAC_ENTRY(160, 22, 33, 19, 38, 16, 66, 21, 37),
> +	CABAC_ENTRY(161, 5, 44, -4, 66, -23, 124, -15, 72),
> +	CABAC_ENTRY(162, 14, 43, 15, 38, 17, 37, 9, 57),
> +	CABAC_ENTRY(163, -1, 78, 12, 42, 44, -18, 16, 54),
> +	CABAC_ENTRY(164, 0, 60, 9, 34, 50, -34, 0, 62),
> +	CABAC_ENTRY(165, 9, 69, 0, 89, -22, 127, 12, 72),
> +
> +	/* Table 9-20 ? Values of variables m and n for ctxIdx from 166 to 226 */
> +	CABAC_ENTRY(166, 11, 28, 4, 45, 4, 39, 24, 0),
> +	CABAC_ENTRY(167, 2, 40, 10, 28, 0, 42, 15, 9),
> +	CABAC_ENTRY(168, 3, 44, 10, 31, 7, 34, 8, 25),
> +	CABAC_ENTRY(169, 0, 49, 33, -11, 11, 29, 13, 18),
> +	CABAC_ENTRY(170, 0, 46, 52, -43, 8, 31, 15, 9),
> +	CABAC_ENTRY(171, 2, 44, 18, 15, 6, 37, 13, 19),
> +	CABAC_ENTRY(172, 2, 51, 28, 0, 7, 42, 10, 37),
> +	CABAC_ENTRY(173, 0, 47, 35, -22, 3, 40, 12, 18),
> +	CABAC_ENTRY(174, 4, 39, 38, -25, 8, 33, 6, 29),
> +	CABAC_ENTRY(175, 2, 62, 34, 0, 13, 43, 20, 33),
> +	CABAC_ENTRY(176, 6, 46, 39, -18, 13, 36, 15, 30),
> +	CABAC_ENTRY(177, 0, 54, 32, -12, 4, 47, 4, 45),
> +	CABAC_ENTRY(178, 3, 54, 102, -94, 3, 55, 1, 58),
> +	CABAC_ENTRY(179, 2, 58, 0, 0, 2, 58, 0, 62),
> +	CABAC_ENTRY(180, 4, 63, 56, -15, 6, 60, 7, 61),
> +	CABAC_ENTRY(181, 6, 51, 33, -4, 8, 44, 12, 38),
> +	CABAC_ENTRY(182, 6, 57, 29, 10, 11, 44, 11, 45),
> +	CABAC_ENTRY(183, 7, 53, 37, -5, 14, 42, 15, 39),
> +	CABAC_ENTRY(184, 6, 52, 51, -29, 7, 48, 11, 42),
> +	CABAC_ENTRY(185, 6, 55, 39, -9, 4, 56, 13, 44),
> +	CABAC_ENTRY(186, 11, 45, 52, -34, 4, 52, 16, 45),
> +	CABAC_ENTRY(187, 14, 36, 69, -58, 13, 37, 12, 41),
> +	CABAC_ENTRY(188, 8, 53, 67, -63, 9, 49, 10, 49),
> +	CABAC_ENTRY(189, -1, 82, 44, -5, 19, 58, 30, 34),
> +	CABAC_ENTRY(190, 7, 55, 32, 7, 10, 48, 18, 42),
> +	CABAC_ENTRY(191, -3, 78, 55, -29, 12, 45, 10, 55),
> +	CABAC_ENTRY(192, 15, 46, 32, 1, 0, 69, 17, 51),
> +	CABAC_ENTRY(193, 22, 31, 0, 0, 20, 33, 17, 46),
> +	CABAC_ENTRY(194, -1, 84, 27, 36, 8, 63, 0, 89),
> +	CABAC_ENTRY(195, 25, 7, 33, -25, 35, -18, 26, -19),
> +	CABAC_ENTRY(196, 30, -7, 34, -30, 33, -25, 22, -17),
> +	CABAC_ENTRY(197, 28, 3, 36, -28, 28, -3, 26, -17),
> +	CABAC_ENTRY(198, 28, 4, 38, -28, 24, 10, 30, -25),
> +	CABAC_ENTRY(199, 32, 0, 38, -27, 27, 0, 28, -20),
> +	CABAC_ENTRY(200, 34, -1, 34, -18, 34, -14, 33, -23),
> +	CABAC_ENTRY(201, 30, 6, 35, -16, 52, -44, 37, -27),
> +	CABAC_ENTRY(202, 30, 6, 34, -14, 39, -24, 33, -23),
> +	CABAC_ENTRY(203, 32, 9, 32, -8, 19, 17, 40, -28),
> +	CABAC_ENTRY(204, 31, 19, 37, -6, 31, 25, 38, -17),
> +	CABAC_ENTRY(205, 26, 27, 35, 0, 36, 29, 33, -11),
> +	CABAC_ENTRY(206, 26, 30, 30, 10, 24, 33, 40, -15),
> +	CABAC_ENTRY(207, 37, 20, 28, 18, 34, 15, 41, -6),
> +	CABAC_ENTRY(208, 28, 34, 26, 25, 30, 20, 38, 1),
> +	CABAC_ENTRY(209, 17, 70, 29, 41, 22, 73, 41, 17),
> +	CABAC_ENTRY(210, 1, 67, 0, 75, 20, 34, 30, -6),
> +	CABAC_ENTRY(211, 5, 59, 2, 72, 19, 31, 27, 3),
> +	CABAC_ENTRY(212, 9, 67, 8, 77, 27, 44, 26, 22),
> +	CABAC_ENTRY(213, 16, 30, 14, 35, 19, 16, 37, -16),
> +	CABAC_ENTRY(214, 18, 32, 18, 31, 15, 36, 35, -4),
> +	CABAC_ENTRY(215, 18, 35, 17, 35, 15, 36, 38, -8),
> +	CABAC_ENTRY(216, 22, 29, 21, 30, 21, 28, 38, -3),
> +	CABAC_ENTRY(217, 24, 31, 17, 45, 25, 21, 37, 3),
> +	CABAC_ENTRY(218, 23, 38, 20, 42, 30, 20, 38, 5),
> +	CABAC_ENTRY(219, 18, 43, 18, 45, 31, 12, 42, 0),
> +	CABAC_ENTRY(220, 20, 41, 27, 26, 27, 16, 35, 16),
> +	CABAC_ENTRY(221, 11, 63, 16, 54, 24, 42, 39, 22),
> +	CABAC_ENTRY(222, 9, 59, 7, 66, 0, 93, 14, 48),
> +	CABAC_ENTRY(223, 9, 64, 16, 56, 14, 56, 27, 37),
> +	CABAC_ENTRY(224, -1, 94, 11, 73, 15, 57, 21, 60),
> +	CABAC_ENTRY(225, -2, 89, 10, 67, 26, 38, 12, 68),
> +	CABAC_ENTRY(226, -9, 108, -10, 116, -24, 127, 2, 97),
> +
> +	/* Table 9-21 ? Values of variables m and n for ctxIdx from 227 to 275 */
> +	CABAC_ENTRY(227, -6, 76, -23, 112, -24, 115, -3, 71),
> +	CABAC_ENTRY(228, -2, 44, -15, 71, -22, 82, -6, 42),
> +	CABAC_ENTRY(229, 0, 45, -7, 61, -9, 62, -5, 50),
> +	CABAC_ENTRY(230, 0, 52, 0, 53, 0, 53, -3, 54),
> +	CABAC_ENTRY(231, -3, 64, -5, 66, 0, 59, -2, 62),
> +	CABAC_ENTRY(232, -2, 59, -11, 77, -14, 85, 0, 58),
> +	CABAC_ENTRY(233, -4, 70, -9, 80, -13, 89, 1, 63),
> +	CABAC_ENTRY(234, -4, 75, -9, 84, -13, 94, -2, 72),
> +	CABAC_ENTRY(235, -8, 82, -10, 87, -11, 92, -1, 74),
> +	CABAC_ENTRY(236, -17, 102, -34, 127, -29, 127, -9, 91),
> +	CABAC_ENTRY(237, -9, 77, -21, 101, -21, 100, -5, 67),
> +	CABAC_ENTRY(238, 3, 24, -3, 39, -14, 57, -5, 27),
> +	CABAC_ENTRY(239, 0, 42, -5, 53, -12, 67, -3, 39),
> +	CABAC_ENTRY(240, 0, 48, -7, 61, -11, 71, -2, 44),
> +	CABAC_ENTRY(241, 0, 55, -11, 75, -10, 77, 0, 46),
> +	CABAC_ENTRY(242, -6, 59, -15, 77, -21, 85, -16, 64),
> +	CABAC_ENTRY(243, -7, 71, -17, 91, -16, 88, -8, 68),
> +	CABAC_ENTRY(244, -12, 83, -25, 107, -23, 104, -10, 78),
> +	CABAC_ENTRY(245, -11, 87, -25, 111, -15, 98, -6, 77),
> +	CABAC_ENTRY(246, -30, 119, -28, 122, -37, 127, -10, 86),
> +	CABAC_ENTRY(247, 1, 58, -11, 76, -10, 82, -12, 92),
> +	CABAC_ENTRY(248, -3, 29, -10, 44, -8, 48, -15, 55),
> +	CABAC_ENTRY(249, -1, 36, -10, 52, -8, 61, -10, 60),
> +	CABAC_ENTRY(250, 1, 38, -10, 57, -8, 66, -6, 62),
> +	CABAC_ENTRY(251, 2, 43, -9, 58, -7, 70, -4, 65),
> +	CABAC_ENTRY(252, -6, 55, -16, 72, -14, 75, -12, 73),
> +	CABAC_ENTRY(253, 0, 58, -7, 69, -10, 79, -8, 76),
> +	CABAC_ENTRY(254, 0, 64, -4, 69, -9, 83, -7, 80),
> +	CABAC_ENTRY(255, -3, 74, -5, 74, -12, 92, -9, 88),
> +	CABAC_ENTRY(256, -10, 90, -9, 86, -18, 108, -17, 110),
> +	CABAC_ENTRY(257, 0, 70, 2, 66, -4, 79, -11, 97),
> +	CABAC_ENTRY(258, -4, 29, -9, 34, -22, 69, -20, 84),
> +	CABAC_ENTRY(259, 5, 31, 1, 32, -16, 75, -11, 79),
> +	CABAC_ENTRY(260, 7, 42, 11, 31, -2, 58, -6, 73),
> +	CABAC_ENTRY(261, 1, 59, 5, 52, 1, 58, -4, 74),
> +	CABAC_ENTRY(262, -2, 58, -2, 55, -13, 78, -13, 86),
> +	CABAC_ENTRY(263, -3, 72, -2, 67, -9, 83, -13, 96),
> +	CABAC_ENTRY(264, -3, 81, 0, 73, -4, 81, -11, 97),
> +	CABAC_ENTRY(265, -11, 97, -8, 89, -13, 99, -19, 117),
> +	CABAC_ENTRY(266, 0, 58, 3, 52, -13, 81, -8, 78),
> +	CABAC_ENTRY(267, 8, 5, 7, 4, -6, 38, -5, 33),
> +	CABAC_ENTRY(268, 10, 14, 10, 8, -13, 62, -4, 48),
> +	CABAC_ENTRY(269, 14, 18, 17, 8, -6, 58, -2, 53),
> +	CABAC_ENTRY(270, 13, 27, 16, 19, -2, 59, -3, 62),
> +	CABAC_ENTRY(271, 2, 40, 3, 37, -16, 73, -13, 71),
> +	CABAC_ENTRY(272, 0, 58, -1, 61, -10, 76, -10, 79),
> +	CABAC_ENTRY(273, -3, 70, -5, 73, -13, 86, -12, 86),
> +	CABAC_ENTRY(274, -6, 79, -1, 70, -9, 83, -13, 90),
> +	CABAC_ENTRY(275, -8, 85, -4, 78, -10, 87, -14, 97),
> +
> +	/* Table 9-22 ? Values of variables m and n for ctxIdx from 277 to 337 */
> +	CABAC_ENTRY(277, -13, 106, -21, 126, -22, 127, -6, 93),
> +	CABAC_ENTRY(278, -16, 106, -23, 124, -25, 127, -6, 84),
> +	CABAC_ENTRY(279, -10, 87, -20, 110, -25, 120, -8, 79),
> +	CABAC_ENTRY(280, -21, 114, -26, 126, -27, 127, 0, 66),
> +	CABAC_ENTRY(281, -18, 110, -25, 124, -19, 114, -1, 71),
> +	CABAC_ENTRY(282, -14, 98, -17, 105, -23, 117, 0, 62),
> +	CABAC_ENTRY(283, -22, 110, -27, 121, -25, 118, -2, 60),
> +	CABAC_ENTRY(284, -21, 106, -27, 117, -26, 117, -2, 59),
> +	CABAC_ENTRY(285, -18, 103, -17, 102, -24, 113, -5, 75),
> +	CABAC_ENTRY(286, -21, 107, -26, 117, -28, 118, -3, 62),
> +	CABAC_ENTRY(287, -23, 108, -27, 116, -31, 120, -4, 58),
> +	CABAC_ENTRY(288, -26, 112, -33, 122, -37, 124, -9, 66),
> +	CABAC_ENTRY(289, -10, 96, -10, 95, -10, 94, -1, 79),
> +	CABAC_ENTRY(290, -12, 95, -14, 100, -15, 102, 0, 71),
> +	CABAC_ENTRY(291, -5, 91, -8, 95, -10, 99, 3, 68),
> +	CABAC_ENTRY(292, -9, 93, -17, 111, -13, 106, 10, 44),
> +	CABAC_ENTRY(293, -22, 94, -28, 114, -50, 127, -7, 62),
> +	CABAC_ENTRY(294, -5, 86, -6, 89, -5, 92, 15, 36),
> +	CABAC_ENTRY(295, 9, 67, -2, 80, 17, 57, 14, 40),
> +	CABAC_ENTRY(296, -4, 80, -4, 82, -5, 86, 16, 27),
> +	CABAC_ENTRY(297, -10, 85, -9, 85, -13, 94, 12, 29),
> +	CABAC_ENTRY(298, -1, 70, -8, 81, -12, 91, 1, 44),
> +	CABAC_ENTRY(299, 7, 60, -1, 72, -2, 77, 20, 36),
> +	CABAC_ENTRY(300, 9, 58, 5, 64, 0, 71, 18, 32),
> +	CABAC_ENTRY(301, 5, 61, 1, 67, -1, 73, 5, 42),
> +	CABAC_ENTRY(302, 12, 50, 9, 56, 4, 64, 1, 48),
> +	CABAC_ENTRY(303, 15, 50, 0, 69, -7, 81, 10, 62),
> +	CABAC_ENTRY(304, 18, 49, 1, 69, 5, 64, 17, 46),
> +	CABAC_ENTRY(305, 17, 54, 7, 69, 15, 57, 9, 64),
> +	CABAC_ENTRY(306, 10, 41, -7, 69, 1, 67, -12, 104),
> +	CABAC_ENTRY(307, 7, 46, -6, 67, 0, 68, -11, 97),
> +	CABAC_ENTRY(308, -1, 51, -16, 77, -10, 67, -16, 96),
> +	CABAC_ENTRY(309, 7, 49, -2, 64, 1, 68, -7, 88),
> +	CABAC_ENTRY(310, 8, 52, 2, 61, 0, 77, -8, 85),
> +	CABAC_ENTRY(311, 9, 41, -6, 67, 2, 64, -7, 85),
> +	CABAC_ENTRY(312, 6, 47, -3, 64, 0, 68, -9, 85),
> +	CABAC_ENTRY(313, 2, 55, 2, 57, -5, 78, -13, 88),
> +	CABAC_ENTRY(314, 13, 41, -3, 65, 7, 55, 4, 66),
> +	CABAC_ENTRY(315, 10, 44, -3, 66, 5, 59, -3, 77),
> +	CABAC_ENTRY(316, 6, 50, 0, 62, 2, 65, -3, 76),
> +	CABAC_ENTRY(317, 5, 53, 9, 51, 14, 54, -6, 76),
> +	CABAC_ENTRY(318, 13, 49, -1, 66, 15, 44, 10, 58),
> +	CABAC_ENTRY(319, 4, 63, -2, 71, 5, 60, -1, 76),
> +	CABAC_ENTRY(320, 6, 64, -2, 75, 2, 70, -1, 83),
> +	CABAC_ENTRY(321, -2, 69, -1, 70, -2, 76, -7, 99),
> +	CABAC_ENTRY(322, -2, 59, -9, 72, -18, 86, -14, 95),
> +	CABAC_ENTRY(323, 6, 70, 14, 60, 12, 70, 2, 95),
> +	CABAC_ENTRY(324, 10, 44, 16, 37, 5, 64, 0, 76),
> +	CABAC_ENTRY(325, 9, 31, 0, 47, -12, 70, -5, 74),
> +	CABAC_ENTRY(326, 12, 43, 18, 35, 11, 55, 0, 70),
> +	CABAC_ENTRY(327, 3, 53, 11, 37, 5, 56, -11, 75),
> +	CABAC_ENTRY(328, 14, 34, 12, 41, 0, 69, 1, 68),
> +	CABAC_ENTRY(329, 10, 38, 10, 41, 2, 65, 0, 65),
> +	CABAC_ENTRY(330, -3, 52, 2, 48, -6, 74, -14, 73),
> +	CABAC_ENTRY(331, 13, 40, 12, 41, 5, 54, 3, 62),
> +	CABAC_ENTRY(332, 17, 32, 13, 41, 7, 54, 4, 62),
> +	CABAC_ENTRY(333, 7, 44, 0, 59, -6, 76, -1, 68),
> +	CABAC_ENTRY(334, 7, 38, 3, 50, -11, 82, -13, 75),
> +	CABAC_ENTRY(335, 13, 50, 19, 40, -2, 77, 11, 55),
> +	CABAC_ENTRY(336, 10, 57, 3, 66, -2, 77, 5, 64),
> +	CABAC_ENTRY(337, 26, 43, 18, 50, 25, 42, 12, 70),
> +
> +	/* Table 9-23 ? Values of variables m and n for ctxIdx from 338 to 398 */
> +	CABAC_ENTRY(338, 14, 11, 19, -6, 17, -13, 15, 6),
> +	CABAC_ENTRY(339, 11, 14, 18, -6, 16, -9, 6, 19),
> +	CABAC_ENTRY(340, 9, 11, 14, 0, 17, -12, 7, 16),
> +	CABAC_ENTRY(341, 18, 11, 26, -12, 27, -21, 12, 14),
> +	CABAC_ENTRY(342, 21, 9, 31, -16, 37, -30, 18, 13),
> +	CABAC_ENTRY(343, 23, -2, 33, -25, 41, -40, 13, 11),
> +	CABAC_ENTRY(344, 32, -15, 33, -22, 42, -41, 13, 15),
> +	CABAC_ENTRY(345, 32, -15, 37, -28, 48, -47, 15, 16),
> +	CABAC_ENTRY(346, 34, -21, 39, -30, 39, -32, 12, 23),
> +	CABAC_ENTRY(347, 39, -23, 42, -30, 46, -40, 13, 23),
> +	CABAC_ENTRY(348, 42, -33, 47, -42, 52, -51, 15, 20),
> +	CABAC_ENTRY(349, 41, -31, 45, -36, 46, -41, 14, 26),
> +	CABAC_ENTRY(350, 46, -28, 49, -34, 52, -39, 14, 44),
> +	CABAC_ENTRY(351, 38, -12, 41, -17, 43, -19, 17, 40),
> +	CABAC_ENTRY(352, 21, 29, 32, 9, 32, 11, 17, 47),
> +	CABAC_ENTRY(353, 45, -24, 69, -71, 61, -55, 24, 17),
> +	CABAC_ENTRY(354, 53, -45, 63, -63, 56, -46, 21, 21),
> +	CABAC_ENTRY(355, 48, -26, 66, -64, 62, -50, 25, 22),
> +	CABAC_ENTRY(356, 65, -43, 77, -74, 81, -67, 31, 27),
> +	CABAC_ENTRY(357, 43, -19, 54, -39, 45, -20, 22, 29),
> +	CABAC_ENTRY(358, 39, -10, 52, -35, 35, -2, 19, 35),
> +	CABAC_ENTRY(359, 30, 9, 41, -10, 28, 15, 14, 50),
> +	CABAC_ENTRY(360, 18, 26, 36, 0, 34, 1, 10, 57),
> +	CABAC_ENTRY(361, 20, 27, 40, -1, 39, 1, 7, 63),
> +	CABAC_ENTRY(362, 0, 57, 30, 14, 30, 17, -2, 77),
> +	CABAC_ENTRY(363, -14, 82, 28, 26, 20, 38, -4, 82),
> +	CABAC_ENTRY(364, -5, 75, 23, 37, 18, 45, -3, 94),
> +	CABAC_ENTRY(365, -19, 97, 12, 55, 15, 54, 9, 69),
> +	CABAC_ENTRY(366, -35, 125, 11, 65, 0, 79, -12, 109),
> +	CABAC_ENTRY(367, 27, 0, 37, -33, 36, -16, 36, -35),
> +	CABAC_ENTRY(368, 28, 0, 39, -36, 37, -14, 36, -34),
> +	CABAC_ENTRY(369, 31, -4, 40, -37, 37, -17, 32, -26),
> +	CABAC_ENTRY(370, 27, 6, 38, -30, 32, 1, 37, -30),
> +	CABAC_ENTRY(371, 34, 8, 46, -33, 34, 15, 44, -32),
> +	CABAC_ENTRY(372, 30, 10, 42, -30, 29, 15, 34, -18),
> +	CABAC_ENTRY(373, 24, 22, 40, -24, 24, 25, 34, -15),
> +	CABAC_ENTRY(374, 33, 19, 49, -29, 34, 22, 40, -15),
> +	CABAC_ENTRY(375, 22, 32, 38, -12, 31, 16, 33, -7),
> +	CABAC_ENTRY(376, 26, 31, 40, -10, 35, 18, 35, -5),
> +	CABAC_ENTRY(377, 21, 41, 38, -3, 31, 28, 33, 0),
> +	CABAC_ENTRY(378, 26, 44, 46, -5, 33, 41, 38, 2),
> +	CABAC_ENTRY(379, 23, 47, 31, 20, 36, 28, 33, 13),
> +	CABAC_ENTRY(380, 16, 65, 29, 30, 27, 47, 23, 35),
> +	CABAC_ENTRY(381, 14, 71, 25, 44, 21, 62, 13, 58),
> +	CABAC_ENTRY(382, 8, 60, 12, 48, 18, 31, 29, -3),
> +	CABAC_ENTRY(383, 6, 63, 11, 49, 19, 26, 26, 0),
> +	CABAC_ENTRY(384, 17, 65, 26, 45, 36, 24, 22, 30),
> +	CABAC_ENTRY(385, 21, 24, 22, 22, 24, 23, 31, -7),
> +	CABAC_ENTRY(386, 23, 20, 23, 22, 27, 16, 35, -15),
> +	CABAC_ENTRY(387, 26, 23, 27, 21, 24, 30, 34, -3),
> +	CABAC_ENTRY(388, 27, 32, 33, 20, 31, 29, 34, 3),
> +	CABAC_ENTRY(389, 28, 23, 26, 28, 22, 41, 36, -1),
> +	CABAC_ENTRY(390, 28, 24, 30, 24, 22, 42, 34, 5),
> +	CABAC_ENTRY(391, 23, 40, 27, 34, 16, 60, 32, 11),
> +	CABAC_ENTRY(392, 24, 32, 18, 42, 15, 52, 35, 5),
> +	CABAC_ENTRY(393, 28, 29, 25, 39, 14, 60, 34, 12),
> +	CABAC_ENTRY(394, 23, 42, 18, 50, 3, 78, 39, 11),
> +	CABAC_ENTRY(395, 19, 57, 12, 70, -16, 123, 30, 29),
> +	CABAC_ENTRY(396, 22, 53, 21, 54, 21, 53, 34, 26),
> +	CABAC_ENTRY(397, 22, 61, 14, 71, 22, 56, 29, 39),
> +	CABAC_ENTRY(398, 11, 86, 11, 83, 25, 61, 19, 66),
> +
> +	/* Values of variables m and n for ctxIdx from 399 to 463 (not documented) */
> +	CABAC_ENTRY(399, 12, 40, 25, 32, 21, 33, 31, 21),
> +	CABAC_ENTRY(400, 11, 51, 21, 49, 19, 50, 31, 31),
> +	CABAC_ENTRY(401, 14, 59, 21, 54, 17, 61, 25, 50),
> +	CABAC_ENTRY(402, -4, 79, -5, 85, -3, 78, -17, 120),
> +	CABAC_ENTRY(403, -7, 71, -6, 81, -8, 74, -20, 112),
> +	CABAC_ENTRY(404, -5, 69, -10, 77, -9, 72, -18, 114),
> +	CABAC_ENTRY(405, -9, 70, -7, 81, -10, 72, -11, 85),
> +	CABAC_ENTRY(406, -8, 66, -17, 80, -18, 75, -15, 92),
> +	CABAC_ENTRY(407, -10, 68, -18, 73, -12, 71, -14, 89),
> +	CABAC_ENTRY(408, -19, 73, -4, 74, -11, 63, -26, 71),
> +	CABAC_ENTRY(409, -12, 69, -10, 83, -5, 70, -15, 81),
> +	CABAC_ENTRY(410, -16, 70, -9, 71, -17, 75, -14, 80),
> +	CABAC_ENTRY(411, -15, 67, -9, 67, -14, 72, 0, 68),
> +	CABAC_ENTRY(412, -20, 62, -1, 61, -16, 67, -14, 70),
> +	CABAC_ENTRY(413, -19, 70, -8, 66, -8, 53, -24, 56),
> +	CABAC_ENTRY(414, -16, 66, -14, 66, -14, 59, -23, 68),
> +	CABAC_ENTRY(415, -22, 65, 0, 59, -9, 52, -24, 50),
> +	CABAC_ENTRY(416, -20, 63, 2, 59, -11, 68, -11, 74),
> +	CABAC_ENTRY(417, 9, -2, 17, -10, 9, -2, 23, -13),
> +	CABAC_ENTRY(418, 26, -9, 32, -13, 30, -10, 26, -13),
> +	CABAC_ENTRY(419, 33, -9, 42, -9, 31, -4, 40, -15),
> +	CABAC_ENTRY(420, 39, -7, 49, -5, 33, -1, 49, -14),
> +	CABAC_ENTRY(421, 41, -2, 53, 0, 33, 7, 44, 3),
> +	CABAC_ENTRY(422, 45, 3, 64, 3, 31, 12, 45, 6),
> +	CABAC_ENTRY(423, 49, 9, 68, 10, 37, 23, 44, 34),
> +	CABAC_ENTRY(424, 45, 27, 66, 27, 31, 38, 33, 54),
> +	CABAC_ENTRY(425, 36, 59, 47, 57, 20, 64, 19, 82),
> +	CABAC_ENTRY(426, -6, 66, -5, 71, -9, 71, -3, 75),
> +	CABAC_ENTRY(427, -7, 35, 0, 24, -7, 37, -1, 23),
> +	CABAC_ENTRY(428, -7, 42, -1, 36, -8, 44, 1, 34),
> +	CABAC_ENTRY(429, -8, 45, -2, 42, -11, 49, 1, 43),
> +	CABAC_ENTRY(430, -5, 48, -2, 52, -10, 56, 0, 54),
> +	CABAC_ENTRY(431, -12, 56, -9, 57, -12, 59, -2, 55),
> +	CABAC_ENTRY(432, -6, 60, -6, 63, -8, 63, 0, 61),
> +	CABAC_ENTRY(433, -5, 62, -4, 65, -9, 67, 1, 64),
> +	CABAC_ENTRY(434, -8, 66, -4, 67, -6, 68, 0, 68),
> +	CABAC_ENTRY(435, -8, 76, -7, 82, -10, 79, -9, 92),
> +	CABAC_ENTRY(436, -5, 85, -3, 81, -3, 78, -14, 106),
> +	CABAC_ENTRY(437, -6, 81, -3, 76, -8, 74, -13, 97),
> +	CABAC_ENTRY(438, -10, 77, -7, 72, -9, 72, -15, 90),
> +	CABAC_ENTRY(439, -7, 81, -6, 78, -10, 72, -12, 90),
> +	CABAC_ENTRY(440, -17, 80, -12, 72, -18, 75, -18, 88),
> +	CABAC_ENTRY(441, -18, 73, -14, 68, -12, 71, -10, 73),
> +	CABAC_ENTRY(442, -4, 74, -3, 70, -11, 63, -9, 79),
> +	CABAC_ENTRY(443, -10, 83, -6, 76, -5, 70, -14, 86),
> +	CABAC_ENTRY(444, -9, 71, -5, 66, -17, 75, -10, 73),
> +	CABAC_ENTRY(445, -9, 67, -5, 62, -14, 72, -10, 70),
> +	CABAC_ENTRY(446, -1, 61, 0, 57, -16, 67, -10, 69),
> +	CABAC_ENTRY(447, -8, 66, -4, 61, -8, 53, -5, 66),
> +	CABAC_ENTRY(448, -14, 66, -9, 60, -14, 59, -9, 64),
> +	CABAC_ENTRY(449, 0, 59, 1, 54, -9, 52, -5, 58),
> +	CABAC_ENTRY(450, 2, 59, 2, 58, -11, 68, 2, 59),
> +	CABAC_ENTRY(451, 21, -13, 17, -10, 9, -2, 21, -10),
> +	CABAC_ENTRY(452, 33, -14, 32, -13, 30, -10, 24, -11),
> +	CABAC_ENTRY(453, 39, -7, 42, -9, 31, -4, 28, -8),
> +	CABAC_ENTRY(454, 46, -2, 49, -5, 33, -1, 28, -1),
> +	CABAC_ENTRY(455, 51, 2, 53, 0, 33, 7, 29, 3),
> +	CABAC_ENTRY(456, 60, 6, 64, 3, 31, 12, 29, 9),
> +	CABAC_ENTRY(457, 61, 17, 68, 10, 37, 23, 35, 20),
> +	CABAC_ENTRY(458, 55, 34, 66, 27, 31, 38, 29, 36),
> +	CABAC_ENTRY(459, 42, 62, 47, 57, 20, 64, 14, 67),
> +};
> +
> +#define RKV_HEVC_CABAC_TABLE_SIZE		27456
> +
> +const u8 rkvdec_hevc_cabac_table[RKV_HEVC_CABAC_TABLE_SIZE] = {
> ?	0x07, 0x0f, 0x48, 0x58, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0f, 0x40, 0x40, 0x40, 0x0f,
> ?	0x68, 0x48, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x40,
> ?	0x40, 0x68, 0x58, 0x60, 0x40, 0x1f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x48, 0x48, 0x60,
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
> index 116e7b1076b7..989379ae3a73 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
> @@ -15,6 +15,8 @@
> ?#include "rkvdec.h"
> ?#include "rkvdec-regs.h"
> ?
> +extern const s8 rkvdec_h264_cabac_table[4][464][2];
> +
> ?/* Size with u32 units. */
> ?#define RKV_CABAC_INIT_BUFFER_SIZE	(3680 + 128)
> ?#define RKV_RPS_SIZE			((128 + 128) / 4)
> @@ -118,505 +120,6 @@ struct rkvdec_h264_ctx {
> ?	struct rkvdec_regs regs;
> ?};
> ?
> -#define CABAC_ENTRY(ctxidx, idc0_m, idc0_n, idc1_m, idc1_n,		\
> -	??? idc2_m, idc2_n, intra_m, intra_n)			\
> -	[0][(ctxidx)] = {idc0_m, idc0_n},			\
> -	[1][(ctxidx)] = {idc1_m, idc1_n},			\
> -	[2][(ctxidx)] = {idc2_m, idc2_n},			\
> -	[3][(ctxidx)] = {intra_m, intra_n}
> -
> -/*
> - * Constant CABAC table.
> - * Built from the tables described in section '9.3.1.1 Initialisation process
> - * for context variables' of the H264 spec.
> - */
> -static const s8 rkvdec_h264_cabac_table[4][464][2] = {
> -	/* Table 9-12 ? Values of variables m and n for ctxIdx from 0 to 10 */
> -	CABAC_ENTRY(0, 20, -15, 20, -15, 20, -15, 20, -15),
> -	CABAC_ENTRY(1, 2, 54, 2, 54, 2, 54, 2, 54),
> -	CABAC_ENTRY(2, 3, 74, 3, 74, 3, 74, 3, 74),
> -	CABAC_ENTRY(3, 20, -15, 20, -15, 20, -15, 20, -15),
> -	CABAC_ENTRY(4, 2, 54, 2, 54, 2, 54, 2, 54),
> -	CABAC_ENTRY(5, 3, 74, 3, 74, 3, 74, 3, 74),
> -	CABAC_ENTRY(6, -28, 127, -28, 127, -28, 127, -28, 127),
> -	CABAC_ENTRY(7, -23, 104, -23, 104, -23, 104, -23, 104),
> -	CABAC_ENTRY(8, -6, 53, -6, 53, -6, 53, -6, 53),
> -	CABAC_ENTRY(9, -1, 54, -1, 54, -1, 54, -1, 54),
> -	CABAC_ENTRY(10, 7, 51, 7, 51, 7, 51, 7, 51),
> -
> -	/* Table 9-13 ? Values of variables m and n for ctxIdx from 11 to 23 */
> -	CABAC_ENTRY(11, 23, 33, 22, 25, 29, 16, 0, 0),
> -	CABAC_ENTRY(12, 23, 2, 34, 0, 25, 0, 0, 0),
> -	CABAC_ENTRY(13, 21, 0, 16, 0, 14, 0, 0, 0),
> -	CABAC_ENTRY(14, 1, 9, -2, 9, -10, 51, 0, 0),
> -	CABAC_ENTRY(15, 0, 49, 4, 41, -3, 62, 0, 0),
> -	CABAC_ENTRY(16, -37, 118, -29, 118, -27, 99, 0, 0),
> -	CABAC_ENTRY(17, 5, 57, 2, 65, 26, 16, 0, 0),
> -	CABAC_ENTRY(18, -13, 78, -6, 71, -4, 85, 0, 0),
> -	CABAC_ENTRY(19, -11, 65, -13, 79, -24, 102, 0, 0),
> -	CABAC_ENTRY(20, 1, 62, 5, 52, 5, 57, 0, 0),
> -	CABAC_ENTRY(21, 12, 49, 9, 50, 6, 57, 0, 0),
> -	CABAC_ENTRY(22, -4, 73, -3, 70, -17, 73, 0, 0),
> -	CABAC_ENTRY(23, 17, 50, 10, 54, 14, 57, 0, 0),
> -
> -	/* Table 9-14 ? Values of variables m and n for ctxIdx from 24 to 39 */
> -	CABAC_ENTRY(24, 18, 64, 26, 34, 20, 40, 0, 0),
> -	CABAC_ENTRY(25, 9, 43, 19, 22, 20, 10, 0, 0),
> -	CABAC_ENTRY(26, 29, 0, 40, 0, 29, 0, 0, 0),
> -	CABAC_ENTRY(27, 26, 67, 57, 2, 54, 0, 0, 0),
> -	CABAC_ENTRY(28, 16, 90, 41, 36, 37, 42, 0, 0),
> -	CABAC_ENTRY(29, 9, 104, 26, 69, 12, 97, 0, 0),
> -	CABAC_ENTRY(30, -46, 127, -45, 127, -32, 127, 0, 0),
> -	CABAC_ENTRY(31, -20, 104, -15, 101, -22, 117, 0, 0),
> -	CABAC_ENTRY(32, 1, 67, -4, 76, -2, 74, 0, 0),
> -	CABAC_ENTRY(33, -13, 78, -6, 71, -4, 85, 0, 0),
> -	CABAC_ENTRY(34, -11, 65, -13, 79, -24, 102, 0, 0),
> -	CABAC_ENTRY(35, 1, 62, 5, 52, 5, 57, 0, 0),
> -	CABAC_ENTRY(36, -6, 86, 6, 69, -6, 93, 0, 0),
> -	CABAC_ENTRY(37, -17, 95, -13, 90, -14, 88, 0, 0),
> -	CABAC_ENTRY(38, -6, 61, 0, 52, -6, 44, 0, 0),
> -	CABAC_ENTRY(39, 9, 45, 8, 43, 4, 55, 0, 0),
> -
> -	/* Table 9-15 ? Values of variables m and n for ctxIdx from 40 to 53 */
> -	CABAC_ENTRY(40, -3, 69, -2, 69, -11, 89, 0, 0),
> -	CABAC_ENTRY(41, -6, 81, -5, 82, -15, 103, 0, 0),
> -	CABAC_ENTRY(42, -11, 96, -10, 96, -21, 116, 0, 0),
> -	CABAC_ENTRY(43, 6, 55, 2, 59, 19, 57, 0, 0),
> -	CABAC_ENTRY(44, 7, 67, 2, 75, 20, 58, 0, 0),
> -	CABAC_ENTRY(45, -5, 86, -3, 87, 4, 84, 0, 0),
> -	CABAC_ENTRY(46, 2, 88, -3, 100, 6, 96, 0, 0),
> -	CABAC_ENTRY(47, 0, 58, 1, 56, 1, 63, 0, 0),
> -	CABAC_ENTRY(48, -3, 76, -3, 74, -5, 85, 0, 0),
> -	CABAC_ENTRY(49, -10, 94, -6, 85, -13, 106, 0, 0),
> -	CABAC_ENTRY(50, 5, 54, 0, 59, 5, 63, 0, 0),
> -	CABAC_ENTRY(51, 4, 69, -3, 81, 6, 75, 0, 0),
> -	CABAC_ENTRY(52, -3, 81, -7, 86, -3, 90, 0, 0),
> -	CABAC_ENTRY(53, 0, 88, -5, 95, -1, 101, 0, 0),
> -
> -	/* Table 9-16 ? Values of variables m and n for ctxIdx from 54 to 59 */
> -	CABAC_ENTRY(54, -7, 67, -1, 66, 3, 55, 0, 0),
> -	CABAC_ENTRY(55, -5, 74, -1, 77, -4, 79, 0, 0),
> -	CABAC_ENTRY(56, -4, 74, 1, 70, -2, 75, 0, 0),
> -	CABAC_ENTRY(57, -5, 80, -2, 86, -12, 97, 0, 0),
> -	CABAC_ENTRY(58, -7, 72, -5, 72, -7, 50, 0, 0),
> -	CABAC_ENTRY(59, 1, 58, 0, 61, 1, 60, 0, 0),
> -
> -	/* Table 9-17 ? Values of variables m and n for ctxIdx from 60 to 69 */
> -	CABAC_ENTRY(60, 0, 41, 0, 41, 0, 41, 0, 41),
> -	CABAC_ENTRY(61, 0, 63, 0, 63, 0, 63, 0, 63),
> -	CABAC_ENTRY(62, 0, 63, 0, 63, 0, 63, 0, 63),
> -	CABAC_ENTRY(63, 0, 63, 0, 63, 0, 63, 0, 63),
> -	CABAC_ENTRY(64, -9, 83, -9, 83, -9, 83, -9, 83),
> -	CABAC_ENTRY(65, 4, 86, 4, 86, 4, 86, 4, 86),
> -	CABAC_ENTRY(66, 0, 97, 0, 97, 0, 97, 0, 97),
> -	CABAC_ENTRY(67, -7, 72, -7, 72, -7, 72, -7, 72),
> -	CABAC_ENTRY(68, 13, 41, 13, 41, 13, 41, 13, 41),
> -	CABAC_ENTRY(69, 3, 62, 3, 62, 3, 62, 3, 62),
> -
> -	/* Table 9-18 ? Values of variables m and n for ctxIdx from 70 to 104 */
> -	CABAC_ENTRY(70, 0, 45, 13, 15, 7, 34, 0, 11),
> -	CABAC_ENTRY(71, -4, 78, 7, 51, -9, 88, 1, 55),
> -	CABAC_ENTRY(72, -3, 96, 2, 80, -20, 127, 0, 69),
> -	CABAC_ENTRY(73, -27, 126, -39, 127, -36, 127, -17, 127),
> -	CABAC_ENTRY(74, -28, 98, -18, 91, -17, 91, -13, 102),
> -	CABAC_ENTRY(75, -25, 101, -17, 96, -14, 95, 0, 82),
> -	CABAC_ENTRY(76, -23, 67, -26, 81, -25, 84, -7, 74),
> -	CABAC_ENTRY(77, -28, 82, -35, 98, -25, 86, -21, 107),
> -	CABAC_ENTRY(78, -20, 94, -24, 102, -12, 89, -27, 127),
> -	CABAC_ENTRY(79, -16, 83, -23, 97, -17, 91, -31, 127),
> -	CABAC_ENTRY(80, -22, 110, -27, 119, -31, 127, -24, 127),
> -	CABAC_ENTRY(81, -21, 91, -24, 99, -14, 76, -18, 95),
> -	CABAC_ENTRY(82, -18, 102, -21, 110, -18, 103, -27, 127),
> -	CABAC_ENTRY(83, -13, 93, -18, 102, -13, 90, -21, 114),
> -	CABAC_ENTRY(84, -29, 127, -36, 127, -37, 127, -30, 127),
> -	CABAC_ENTRY(85, -7, 92, 0, 80, 11, 80, -17, 123),
> -	CABAC_ENTRY(86, -5, 89, -5, 89, 5, 76, -12, 115),
> -	CABAC_ENTRY(87, -7, 96, -7, 94, 2, 84, -16, 122),
> -	CABAC_ENTRY(88, -13, 108, -4, 92, 5, 78, -11, 115),
> -	CABAC_ENTRY(89, -3, 46, 0, 39, -6, 55, -12, 63),
> -	CABAC_ENTRY(90, -1, 65, 0, 65, 4, 61, -2, 68),
> -	CABAC_ENTRY(91, -1, 57, -15, 84, -14, 83, -15, 84),
> -	CABAC_ENTRY(92, -9, 93, -35, 127, -37, 127, -13, 104),
> -	CABAC_ENTRY(93, -3, 74, -2, 73, -5, 79, -3, 70),
> -	CABAC_ENTRY(94, -9, 92, -12, 104, -11, 104, -8, 93),
> -	CABAC_ENTRY(95, -8, 87, -9, 91, -11, 91, -10, 90),
> -	CABAC_ENTRY(96, -23, 126, -31, 127, -30, 127, -30, 127),
> -	CABAC_ENTRY(97, 5, 54, 3, 55, 0, 65, -1, 74),
> -	CABAC_ENTRY(98, 6, 60, 7, 56, -2, 79, -6, 97),
> -	CABAC_ENTRY(99, 6, 59, 7, 55, 0, 72, -7, 91),
> -	CABAC_ENTRY(100, 6, 69, 8, 61, -4, 92, -20, 127),
> -	CABAC_ENTRY(101, -1, 48, -3, 53, -6, 56, -4, 56),
> -	CABAC_ENTRY(102, 0, 68, 0, 68, 3, 68, -5, 82),
> -	CABAC_ENTRY(103, -4, 69, -7, 74, -8, 71, -7, 76),
> -	CABAC_ENTRY(104, -8, 88, -9, 88, -13, 98, -22, 125),
> -
> -	/* Table 9-19 ? Values of variables m and n for ctxIdx from 105 to 165 */
> -	CABAC_ENTRY(105, -2, 85, -13, 103, -4, 86, -7, 93),
> -	CABAC_ENTRY(106, -6, 78, -13, 91, -12, 88, -11, 87),
> -	CABAC_ENTRY(107, -1, 75, -9, 89, -5, 82, -3, 77),
> -	CABAC_ENTRY(108, -7, 77, -14, 92, -3, 72, -5, 71),
> -	CABAC_ENTRY(109, 2, 54, -8, 76, -4, 67, -4, 63),
> -	CABAC_ENTRY(110, 5, 50, -12, 87, -8, 72, -4, 68),
> -	CABAC_ENTRY(111, -3, 68, -23, 110, -16, 89, -12, 84),
> -	CABAC_ENTRY(112, 1, 50, -24, 105, -9, 69, -7, 62),
> -	CABAC_ENTRY(113, 6, 42, -10, 78, -1, 59, -7, 65),
> -	CABAC_ENTRY(114, -4, 81, -20, 112, 5, 66, 8, 61),
> -	CABAC_ENTRY(115, 1, 63, -17, 99, 4, 57, 5, 56),
> -	CABAC_ENTRY(116, -4, 70, -78, 127, -4, 71, -2, 66),
> -	CABAC_ENTRY(117, 0, 67, -70, 127, -2, 71, 1, 64),
> -	CABAC_ENTRY(118, 2, 57, -50, 127, 2, 58, 0, 61),
> -	CABAC_ENTRY(119, -2, 76, -46, 127, -1, 74, -2, 78),
> -	CABAC_ENTRY(120, 11, 35, -4, 66, -4, 44, 1, 50),
> -	CABAC_ENTRY(121, 4, 64, -5, 78, -1, 69, 7, 52),
> -	CABAC_ENTRY(122, 1, 61, -4, 71, 0, 62, 10, 35),
> -	CABAC_ENTRY(123, 11, 35, -8, 72, -7, 51, 0, 44),
> -	CABAC_ENTRY(124, 18, 25, 2, 59, -4, 47, 11, 38),
> -	CABAC_ENTRY(125, 12, 24, -1, 55, -6, 42, 1, 45),
> -	CABAC_ENTRY(126, 13, 29, -7, 70, -3, 41, 0, 46),
> -	CABAC_ENTRY(127, 13, 36, -6, 75, -6, 53, 5, 44),
> -	CABAC_ENTRY(128, -10, 93, -8, 89, 8, 76, 31, 17),
> -	CABAC_ENTRY(129, -7, 73, -34, 119, -9, 78, 1, 51),
> -	CABAC_ENTRY(130, -2, 73, -3, 75, -11, 83, 7, 50),
> -	CABAC_ENTRY(131, 13, 46, 32, 20, 9, 52, 28, 19),
> -	CABAC_ENTRY(132, 9, 49, 30, 22, 0, 67, 16, 33),
> -	CABAC_ENTRY(133, -7, 100, -44, 127, -5, 90, 14, 62),
> -	CABAC_ENTRY(134, 9, 53, 0, 54, 1, 67, -13, 108),
> -	CABAC_ENTRY(135, 2, 53, -5, 61, -15, 72, -15, 100),
> -	CABAC_ENTRY(136, 5, 53, 0, 58, -5, 75, -13, 101),
> -	CABAC_ENTRY(137, -2, 61, -1, 60, -8, 80, -13, 91),
> -	CABAC_ENTRY(138, 0, 56, -3, 61, -21, 83, -12, 94),
> -	CABAC_ENTRY(139, 0, 56, -8, 67, -21, 64, -10, 88),
> -	CABAC_ENTRY(140, -13, 63, -25, 84, -13, 31, -16, 84),
> -	CABAC_ENTRY(141, -5, 60, -14, 74, -25, 64, -10, 86),
> -	CABAC_ENTRY(142, -1, 62, -5, 65, -29, 94, -7, 83),
> -	CABAC_ENTRY(143, 4, 57, 5, 52, 9, 75, -13, 87),
> -	CABAC_ENTRY(144, -6, 69, 2, 57, 17, 63, -19, 94),
> -	CABAC_ENTRY(145, 4, 57, 0, 61, -8, 74, 1, 70),
> -	CABAC_ENTRY(146, 14, 39, -9, 69, -5, 35, 0, 72),
> -	CABAC_ENTRY(147, 4, 51, -11, 70, -2, 27, -5, 74),
> -	CABAC_ENTRY(148, 13, 68, 18, 55, 13, 91, 18, 59),
> -	CABAC_ENTRY(149, 3, 64, -4, 71, 3, 65, -8, 102),
> -	CABAC_ENTRY(150, 1, 61, 0, 58, -7, 69, -15, 100),
> -	CABAC_ENTRY(151, 9, 63, 7, 61, 8, 77, 0, 95),
> -	CABAC_ENTRY(152, 7, 50, 9, 41, -10, 66, -4, 75),
> -	CABAC_ENTRY(153, 16, 39, 18, 25, 3, 62, 2, 72),
> -	CABAC_ENTRY(154, 5, 44, 9, 32, -3, 68, -11, 75),
> -	CABAC_ENTRY(155, 4, 52, 5, 43, -20, 81, -3, 71),
> -	CABAC_ENTRY(156, 11, 48, 9, 47, 0, 30, 15, 46),
> -	CABAC_ENTRY(157, -5, 60, 0, 44, 1, 7, -13, 69),
> -	CABAC_ENTRY(158, -1, 59, 0, 51, -3, 23, 0, 62),
> -	CABAC_ENTRY(159, 0, 59, 2, 46, -21, 74, 0, 65),
> -	CABAC_ENTRY(160, 22, 33, 19, 38, 16, 66, 21, 37),
> -	CABAC_ENTRY(161, 5, 44, -4, 66, -23, 124, -15, 72),
> -	CABAC_ENTRY(162, 14, 43, 15, 38, 17, 37, 9, 57),
> -	CABAC_ENTRY(163, -1, 78, 12, 42, 44, -18, 16, 54),
> -	CABAC_ENTRY(164, 0, 60, 9, 34, 50, -34, 0, 62),
> -	CABAC_ENTRY(165, 9, 69, 0, 89, -22, 127, 12, 72),
> -
> -	/* Table 9-20 ? Values of variables m and n for ctxIdx from 166 to 226 */
> -	CABAC_ENTRY(166, 11, 28, 4, 45, 4, 39, 24, 0),
> -	CABAC_ENTRY(167, 2, 40, 10, 28, 0, 42, 15, 9),
> -	CABAC_ENTRY(168, 3, 44, 10, 31, 7, 34, 8, 25),
> -	CABAC_ENTRY(169, 0, 49, 33, -11, 11, 29, 13, 18),
> -	CABAC_ENTRY(170, 0, 46, 52, -43, 8, 31, 15, 9),
> -	CABAC_ENTRY(171, 2, 44, 18, 15, 6, 37, 13, 19),
> -	CABAC_ENTRY(172, 2, 51, 28, 0, 7, 42, 10, 37),
> -	CABAC_ENTRY(173, 0, 47, 35, -22, 3, 40, 12, 18),
> -	CABAC_ENTRY(174, 4, 39, 38, -25, 8, 33, 6, 29),
> -	CABAC_ENTRY(175, 2, 62, 34, 0, 13, 43, 20, 33),
> -	CABAC_ENTRY(176, 6, 46, 39, -18, 13, 36, 15, 30),
> -	CABAC_ENTRY(177, 0, 54, 32, -12, 4, 47, 4, 45),
> -	CABAC_ENTRY(178, 3, 54, 102, -94, 3, 55, 1, 58),
> -	CABAC_ENTRY(179, 2, 58, 0, 0, 2, 58, 0, 62),
> -	CABAC_ENTRY(180, 4, 63, 56, -15, 6, 60, 7, 61),
> -	CABAC_ENTRY(181, 6, 51, 33, -4, 8, 44, 12, 38),
> -	CABAC_ENTRY(182, 6, 57, 29, 10, 11, 44, 11, 45),
> -	CABAC_ENTRY(183, 7, 53, 37, -5, 14, 42, 15, 39),
> -	CABAC_ENTRY(184, 6, 52, 51, -29, 7, 48, 11, 42),
> -	CABAC_ENTRY(185, 6, 55, 39, -9, 4, 56, 13, 44),
> -	CABAC_ENTRY(186, 11, 45, 52, -34, 4, 52, 16, 45),
> -	CABAC_ENTRY(187, 14, 36, 69, -58, 13, 37, 12, 41),
> -	CABAC_ENTRY(188, 8, 53, 67, -63, 9, 49, 10, 49),
> -	CABAC_ENTRY(189, -1, 82, 44, -5, 19, 58, 30, 34),
> -	CABAC_ENTRY(190, 7, 55, 32, 7, 10, 48, 18, 42),
> -	CABAC_ENTRY(191, -3, 78, 55, -29, 12, 45, 10, 55),
> -	CABAC_ENTRY(192, 15, 46, 32, 1, 0, 69, 17, 51),
> -	CABAC_ENTRY(193, 22, 31, 0, 0, 20, 33, 17, 46),
> -	CABAC_ENTRY(194, -1, 84, 27, 36, 8, 63, 0, 89),
> -	CABAC_ENTRY(195, 25, 7, 33, -25, 35, -18, 26, -19),
> -	CABAC_ENTRY(196, 30, -7, 34, -30, 33, -25, 22, -17),
> -	CABAC_ENTRY(197, 28, 3, 36, -28, 28, -3, 26, -17),
> -	CABAC_ENTRY(198, 28, 4, 38, -28, 24, 10, 30, -25),
> -	CABAC_ENTRY(199, 32, 0, 38, -27, 27, 0, 28, -20),
> -	CABAC_ENTRY(200, 34, -1, 34, -18, 34, -14, 33, -23),
> -	CABAC_ENTRY(201, 30, 6, 35, -16, 52, -44, 37, -27),
> -	CABAC_ENTRY(202, 30, 6, 34, -14, 39, -24, 33, -23),
> -	CABAC_ENTRY(203, 32, 9, 32, -8, 19, 17, 40, -28),
> -	CABAC_ENTRY(204, 31, 19, 37, -6, 31, 25, 38, -17),
> -	CABAC_ENTRY(205, 26, 27, 35, 0, 36, 29, 33, -11),
> -	CABAC_ENTRY(206, 26, 30, 30, 10, 24, 33, 40, -15),
> -	CABAC_ENTRY(207, 37, 20, 28, 18, 34, 15, 41, -6),
> -	CABAC_ENTRY(208, 28, 34, 26, 25, 30, 20, 38, 1),
> -	CABAC_ENTRY(209, 17, 70, 29, 41, 22, 73, 41, 17),
> -	CABAC_ENTRY(210, 1, 67, 0, 75, 20, 34, 30, -6),
> -	CABAC_ENTRY(211, 5, 59, 2, 72, 19, 31, 27, 3),
> -	CABAC_ENTRY(212, 9, 67, 8, 77, 27, 44, 26, 22),
> -	CABAC_ENTRY(213, 16, 30, 14, 35, 19, 16, 37, -16),
> -	CABAC_ENTRY(214, 18, 32, 18, 31, 15, 36, 35, -4),
> -	CABAC_ENTRY(215, 18, 35, 17, 35, 15, 36, 38, -8),
> -	CABAC_ENTRY(216, 22, 29, 21, 30, 21, 28, 38, -3),
> -	CABAC_ENTRY(217, 24, 31, 17, 45, 25, 21, 37, 3),
> -	CABAC_ENTRY(218, 23, 38, 20, 42, 30, 20, 38, 5),
> -	CABAC_ENTRY(219, 18, 43, 18, 45, 31, 12, 42, 0),
> -	CABAC_ENTRY(220, 20, 41, 27, 26, 27, 16, 35, 16),
> -	CABAC_ENTRY(221, 11, 63, 16, 54, 24, 42, 39, 22),
> -	CABAC_ENTRY(222, 9, 59, 7, 66, 0, 93, 14, 48),
> -	CABAC_ENTRY(223, 9, 64, 16, 56, 14, 56, 27, 37),
> -	CABAC_ENTRY(224, -1, 94, 11, 73, 15, 57, 21, 60),
> -	CABAC_ENTRY(225, -2, 89, 10, 67, 26, 38, 12, 68),
> -	CABAC_ENTRY(226, -9, 108, -10, 116, -24, 127, 2, 97),
> -
> -	/* Table 9-21 ? Values of variables m and n for ctxIdx from 227 to 275 */
> -	CABAC_ENTRY(227, -6, 76, -23, 112, -24, 115, -3, 71),
> -	CABAC_ENTRY(228, -2, 44, -15, 71, -22, 82, -6, 42),
> -	CABAC_ENTRY(229, 0, 45, -7, 61, -9, 62, -5, 50),
> -	CABAC_ENTRY(230, 0, 52, 0, 53, 0, 53, -3, 54),
> -	CABAC_ENTRY(231, -3, 64, -5, 66, 0, 59, -2, 62),
> -	CABAC_ENTRY(232, -2, 59, -11, 77, -14, 85, 0, 58),
> -	CABAC_ENTRY(233, -4, 70, -9, 80, -13, 89, 1, 63),
> -	CABAC_ENTRY(234, -4, 75, -9, 84, -13, 94, -2, 72),
> -	CABAC_ENTRY(235, -8, 82, -10, 87, -11, 92, -1, 74),
> -	CABAC_ENTRY(236, -17, 102, -34, 127, -29, 127, -9, 91),
> -	CABAC_ENTRY(237, -9, 77, -21, 101, -21, 100, -5, 67),
> -	CABAC_ENTRY(238, 3, 24, -3, 39, -14, 57, -5, 27),
> -	CABAC_ENTRY(239, 0, 42, -5, 53, -12, 67, -3, 39),
> -	CABAC_ENTRY(240, 0, 48, -7, 61, -11, 71, -2, 44),
> -	CABAC_ENTRY(241, 0, 55, -11, 75, -10, 77, 0, 46),
> -	CABAC_ENTRY(242, -6, 59, -15, 77, -21, 85, -16, 64),
> -	CABAC_ENTRY(243, -7, 71, -17, 91, -16, 88, -8, 68),
> -	CABAC_ENTRY(244, -12, 83, -25, 107, -23, 104, -10, 78),
> -	CABAC_ENTRY(245, -11, 87, -25, 111, -15, 98, -6, 77),
> -	CABAC_ENTRY(246, -30, 119, -28, 122, -37, 127, -10, 86),
> -	CABAC_ENTRY(247, 1, 58, -11, 76, -10, 82, -12, 92),
> -	CABAC_ENTRY(248, -3, 29, -10, 44, -8, 48, -15, 55),
> -	CABAC_ENTRY(249, -1, 36, -10, 52, -8, 61, -10, 60),
> -	CABAC_ENTRY(250, 1, 38, -10, 57, -8, 66, -6, 62),
> -	CABAC_ENTRY(251, 2, 43, -9, 58, -7, 70, -4, 65),
> -	CABAC_ENTRY(252, -6, 55, -16, 72, -14, 75, -12, 73),
> -	CABAC_ENTRY(253, 0, 58, -7, 69, -10, 79, -8, 76),
> -	CABAC_ENTRY(254, 0, 64, -4, 69, -9, 83, -7, 80),
> -	CABAC_ENTRY(255, -3, 74, -5, 74, -12, 92, -9, 88),
> -	CABAC_ENTRY(256, -10, 90, -9, 86, -18, 108, -17, 110),
> -	CABAC_ENTRY(257, 0, 70, 2, 66, -4, 79, -11, 97),
> -	CABAC_ENTRY(258, -4, 29, -9, 34, -22, 69, -20, 84),
> -	CABAC_ENTRY(259, 5, 31, 1, 32, -16, 75, -11, 79),
> -	CABAC_ENTRY(260, 7, 42, 11, 31, -2, 58, -6, 73),
> -	CABAC_ENTRY(261, 1, 59, 5, 52, 1, 58, -4, 74),
> -	CABAC_ENTRY(262, -2, 58, -2, 55, -13, 78, -13, 86),
> -	CABAC_ENTRY(263, -3, 72, -2, 67, -9, 83, -13, 96),
> -	CABAC_ENTRY(264, -3, 81, 0, 73, -4, 81, -11, 97),
> -	CABAC_ENTRY(265, -11, 97, -8, 89, -13, 99, -19, 117),
> -	CABAC_ENTRY(266, 0, 58, 3, 52, -13, 81, -8, 78),
> -	CABAC_ENTRY(267, 8, 5, 7, 4, -6, 38, -5, 33),
> -	CABAC_ENTRY(268, 10, 14, 10, 8, -13, 62, -4, 48),
> -	CABAC_ENTRY(269, 14, 18, 17, 8, -6, 58, -2, 53),
> -	CABAC_ENTRY(270, 13, 27, 16, 19, -2, 59, -3, 62),
> -	CABAC_ENTRY(271, 2, 40, 3, 37, -16, 73, -13, 71),
> -	CABAC_ENTRY(272, 0, 58, -1, 61, -10, 76, -10, 79),
> -	CABAC_ENTRY(273, -3, 70, -5, 73, -13, 86, -12, 86),
> -	CABAC_ENTRY(274, -6, 79, -1, 70, -9, 83, -13, 90),
> -	CABAC_ENTRY(275, -8, 85, -4, 78, -10, 87, -14, 97),
> -
> -	/* Table 9-22 ? Values of variables m and n for ctxIdx from 277 to 337 */
> -	CABAC_ENTRY(277, -13, 106, -21, 126, -22, 127, -6, 93),
> -	CABAC_ENTRY(278, -16, 106, -23, 124, -25, 127, -6, 84),
> -	CABAC_ENTRY(279, -10, 87, -20, 110, -25, 120, -8, 79),
> -	CABAC_ENTRY(280, -21, 114, -26, 126, -27, 127, 0, 66),
> -	CABAC_ENTRY(281, -18, 110, -25, 124, -19, 114, -1, 71),
> -	CABAC_ENTRY(282, -14, 98, -17, 105, -23, 117, 0, 62),
> -	CABAC_ENTRY(283, -22, 110, -27, 121, -25, 118, -2, 60),
> -	CABAC_ENTRY(284, -21, 106, -27, 117, -26, 117, -2, 59),
> -	CABAC_ENTRY(285, -18, 103, -17, 102, -24, 113, -5, 75),
> -	CABAC_ENTRY(286, -21, 107, -26, 117, -28, 118, -3, 62),
> -	CABAC_ENTRY(287, -23, 108, -27, 116, -31, 120, -4, 58),
> -	CABAC_ENTRY(288, -26, 112, -33, 122, -37, 124, -9, 66),
> -	CABAC_ENTRY(289, -10, 96, -10, 95, -10, 94, -1, 79),
> -	CABAC_ENTRY(290, -12, 95, -14, 100, -15, 102, 0, 71),
> -	CABAC_ENTRY(291, -5, 91, -8, 95, -10, 99, 3, 68),
> -	CABAC_ENTRY(292, -9, 93, -17, 111, -13, 106, 10, 44),
> -	CABAC_ENTRY(293, -22, 94, -28, 114, -50, 127, -7, 62),
> -	CABAC_ENTRY(294, -5, 86, -6, 89, -5, 92, 15, 36),
> -	CABAC_ENTRY(295, 9, 67, -2, 80, 17, 57, 14, 40),
> -	CABAC_ENTRY(296, -4, 80, -4, 82, -5, 86, 16, 27),
> -	CABAC_ENTRY(297, -10, 85, -9, 85, -13, 94, 12, 29),
> -	CABAC_ENTRY(298, -1, 70, -8, 81, -12, 91, 1, 44),
> -	CABAC_ENTRY(299, 7, 60, -1, 72, -2, 77, 20, 36),
> -	CABAC_ENTRY(300, 9, 58, 5, 64, 0, 71, 18, 32),
> -	CABAC_ENTRY(301, 5, 61, 1, 67, -1, 73, 5, 42),
> -	CABAC_ENTRY(302, 12, 50, 9, 56, 4, 64, 1, 48),
> -	CABAC_ENTRY(303, 15, 50, 0, 69, -7, 81, 10, 62),
> -	CABAC_ENTRY(304, 18, 49, 1, 69, 5, 64, 17, 46),
> -	CABAC_ENTRY(305, 17, 54, 7, 69, 15, 57, 9, 64),
> -	CABAC_ENTRY(306, 10, 41, -7, 69, 1, 67, -12, 104),
> -	CABAC_ENTRY(307, 7, 46, -6, 67, 0, 68, -11, 97),
> -	CABAC_ENTRY(308, -1, 51, -16, 77, -10, 67, -16, 96),
> -	CABAC_ENTRY(309, 7, 49, -2, 64, 1, 68, -7, 88),
> -	CABAC_ENTRY(310, 8, 52, 2, 61, 0, 77, -8, 85),
> -	CABAC_ENTRY(311, 9, 41, -6, 67, 2, 64, -7, 85),
> -	CABAC_ENTRY(312, 6, 47, -3, 64, 0, 68, -9, 85),
> -	CABAC_ENTRY(313, 2, 55, 2, 57, -5, 78, -13, 88),
> -	CABAC_ENTRY(314, 13, 41, -3, 65, 7, 55, 4, 66),
> -	CABAC_ENTRY(315, 10, 44, -3, 66, 5, 59, -3, 77),
> -	CABAC_ENTRY(316, 6, 50, 0, 62, 2, 65, -3, 76),
> -	CABAC_ENTRY(317, 5, 53, 9, 51, 14, 54, -6, 76),
> -	CABAC_ENTRY(318, 13, 49, -1, 66, 15, 44, 10, 58),
> -	CABAC_ENTRY(319, 4, 63, -2, 71, 5, 60, -1, 76),
> -	CABAC_ENTRY(320, 6, 64, -2, 75, 2, 70, -1, 83),
> -	CABAC_ENTRY(321, -2, 69, -1, 70, -2, 76, -7, 99),
> -	CABAC_ENTRY(322, -2, 59, -9, 72, -18, 86, -14, 95),
> -	CABAC_ENTRY(323, 6, 70, 14, 60, 12, 70, 2, 95),
> -	CABAC_ENTRY(324, 10, 44, 16, 37, 5, 64, 0, 76),
> -	CABAC_ENTRY(325, 9, 31, 0, 47, -12, 70, -5, 74),
> -	CABAC_ENTRY(326, 12, 43, 18, 35, 11, 55, 0, 70),
> -	CABAC_ENTRY(327, 3, 53, 11, 37, 5, 56, -11, 75),
> -	CABAC_ENTRY(328, 14, 34, 12, 41, 0, 69, 1, 68),
> -	CABAC_ENTRY(329, 10, 38, 10, 41, 2, 65, 0, 65),
> -	CABAC_ENTRY(330, -3, 52, 2, 48, -6, 74, -14, 73),
> -	CABAC_ENTRY(331, 13, 40, 12, 41, 5, 54, 3, 62),
> -	CABAC_ENTRY(332, 17, 32, 13, 41, 7, 54, 4, 62),
> -	CABAC_ENTRY(333, 7, 44, 0, 59, -6, 76, -1, 68),
> -	CABAC_ENTRY(334, 7, 38, 3, 50, -11, 82, -13, 75),
> -	CABAC_ENTRY(335, 13, 50, 19, 40, -2, 77, 11, 55),
> -	CABAC_ENTRY(336, 10, 57, 3, 66, -2, 77, 5, 64),
> -	CABAC_ENTRY(337, 26, 43, 18, 50, 25, 42, 12, 70),
> -
> -	/* Table 9-23 ? Values of variables m and n for ctxIdx from 338 to 398 */
> -	CABAC_ENTRY(338, 14, 11, 19, -6, 17, -13, 15, 6),
> -	CABAC_ENTRY(339, 11, 14, 18, -6, 16, -9, 6, 19),
> -	CABAC_ENTRY(340, 9, 11, 14, 0, 17, -12, 7, 16),
> -	CABAC_ENTRY(341, 18, 11, 26, -12, 27, -21, 12, 14),
> -	CABAC_ENTRY(342, 21, 9, 31, -16, 37, -30, 18, 13),
> -	CABAC_ENTRY(343, 23, -2, 33, -25, 41, -40, 13, 11),
> -	CABAC_ENTRY(344, 32, -15, 33, -22, 42, -41, 13, 15),
> -	CABAC_ENTRY(345, 32, -15, 37, -28, 48, -47, 15, 16),
> -	CABAC_ENTRY(346, 34, -21, 39, -30, 39, -32, 12, 23),
> -	CABAC_ENTRY(347, 39, -23, 42, -30, 46, -40, 13, 23),
> -	CABAC_ENTRY(348, 42, -33, 47, -42, 52, -51, 15, 20),
> -	CABAC_ENTRY(349, 41, -31, 45, -36, 46, -41, 14, 26),
> -	CABAC_ENTRY(350, 46, -28, 49, -34, 52, -39, 14, 44),
> -	CABAC_ENTRY(351, 38, -12, 41, -17, 43, -19, 17, 40),
> -	CABAC_ENTRY(352, 21, 29, 32, 9, 32, 11, 17, 47),
> -	CABAC_ENTRY(353, 45, -24, 69, -71, 61, -55, 24, 17),
> -	CABAC_ENTRY(354, 53, -45, 63, -63, 56, -46, 21, 21),
> -	CABAC_ENTRY(355, 48, -26, 66, -64, 62, -50, 25, 22),
> -	CABAC_ENTRY(356, 65, -43, 77, -74, 81, -67, 31, 27),
> -	CABAC_ENTRY(357, 43, -19, 54, -39, 45, -20, 22, 29),
> -	CABAC_ENTRY(358, 39, -10, 52, -35, 35, -2, 19, 35),
> -	CABAC_ENTRY(359, 30, 9, 41, -10, 28, 15, 14, 50),
> -	CABAC_ENTRY(360, 18, 26, 36, 0, 34, 1, 10, 57),
> -	CABAC_ENTRY(361, 20, 27, 40, -1, 39, 1, 7, 63),
> -	CABAC_ENTRY(362, 0, 57, 30, 14, 30, 17, -2, 77),
> -	CABAC_ENTRY(363, -14, 82, 28, 26, 20, 38, -4, 82),
> -	CABAC_ENTRY(364, -5, 75, 23, 37, 18, 45, -3, 94),
> -	CABAC_ENTRY(365, -19, 97, 12, 55, 15, 54, 9, 69),
> -	CABAC_ENTRY(366, -35, 125, 11, 65, 0, 79, -12, 109),
> -	CABAC_ENTRY(367, 27, 0, 37, -33, 36, -16, 36, -35),
> -	CABAC_ENTRY(368, 28, 0, 39, -36, 37, -14, 36, -34),
> -	CABAC_ENTRY(369, 31, -4, 40, -37, 37, -17, 32, -26),
> -	CABAC_ENTRY(370, 27, 6, 38, -30, 32, 1, 37, -30),
> -	CABAC_ENTRY(371, 34, 8, 46, -33, 34, 15, 44, -32),
> -	CABAC_ENTRY(372, 30, 10, 42, -30, 29, 15, 34, -18),
> -	CABAC_ENTRY(373, 24, 22, 40, -24, 24, 25, 34, -15),
> -	CABAC_ENTRY(374, 33, 19, 49, -29, 34, 22, 40, -15),
> -	CABAC_ENTRY(375, 22, 32, 38, -12, 31, 16, 33, -7),
> -	CABAC_ENTRY(376, 26, 31, 40, -10, 35, 18, 35, -5),
> -	CABAC_ENTRY(377, 21, 41, 38, -3, 31, 28, 33, 0),
> -	CABAC_ENTRY(378, 26, 44, 46, -5, 33, 41, 38, 2),
> -	CABAC_ENTRY(379, 23, 47, 31, 20, 36, 28, 33, 13),
> -	CABAC_ENTRY(380, 16, 65, 29, 30, 27, 47, 23, 35),
> -	CABAC_ENTRY(381, 14, 71, 25, 44, 21, 62, 13, 58),
> -	CABAC_ENTRY(382, 8, 60, 12, 48, 18, 31, 29, -3),
> -	CABAC_ENTRY(383, 6, 63, 11, 49, 19, 26, 26, 0),
> -	CABAC_ENTRY(384, 17, 65, 26, 45, 36, 24, 22, 30),
> -	CABAC_ENTRY(385, 21, 24, 22, 22, 24, 23, 31, -7),
> -	CABAC_ENTRY(386, 23, 20, 23, 22, 27, 16, 35, -15),
> -	CABAC_ENTRY(387, 26, 23, 27, 21, 24, 30, 34, -3),
> -	CABAC_ENTRY(388, 27, 32, 33, 20, 31, 29, 34, 3),
> -	CABAC_ENTRY(389, 28, 23, 26, 28, 22, 41, 36, -1),
> -	CABAC_ENTRY(390, 28, 24, 30, 24, 22, 42, 34, 5),
> -	CABAC_ENTRY(391, 23, 40, 27, 34, 16, 60, 32, 11),
> -	CABAC_ENTRY(392, 24, 32, 18, 42, 15, 52, 35, 5),
> -	CABAC_ENTRY(393, 28, 29, 25, 39, 14, 60, 34, 12),
> -	CABAC_ENTRY(394, 23, 42, 18, 50, 3, 78, 39, 11),
> -	CABAC_ENTRY(395, 19, 57, 12, 70, -16, 123, 30, 29),
> -	CABAC_ENTRY(396, 22, 53, 21, 54, 21, 53, 34, 26),
> -	CABAC_ENTRY(397, 22, 61, 14, 71, 22, 56, 29, 39),
> -	CABAC_ENTRY(398, 11, 86, 11, 83, 25, 61, 19, 66),
> -
> -	/* Values of variables m and n for ctxIdx from 399 to 463 (not documented) */
> -	CABAC_ENTRY(399, 12, 40, 25, 32, 21, 33, 31, 21),
> -	CABAC_ENTRY(400, 11, 51, 21, 49, 19, 50, 31, 31),
> -	CABAC_ENTRY(401, 14, 59, 21, 54, 17, 61, 25, 50),
> -	CABAC_ENTRY(402, -4, 79, -5, 85, -3, 78, -17, 120),
> -	CABAC_ENTRY(403, -7, 71, -6, 81, -8, 74, -20, 112),
> -	CABAC_ENTRY(404, -5, 69, -10, 77, -9, 72, -18, 114),
> -	CABAC_ENTRY(405, -9, 70, -7, 81, -10, 72, -11, 85),
> -	CABAC_ENTRY(406, -8, 66, -17, 80, -18, 75, -15, 92),
> -	CABAC_ENTRY(407, -10, 68, -18, 73, -12, 71, -14, 89),
> -	CABAC_ENTRY(408, -19, 73, -4, 74, -11, 63, -26, 71),
> -	CABAC_ENTRY(409, -12, 69, -10, 83, -5, 70, -15, 81),
> -	CABAC_ENTRY(410, -16, 70, -9, 71, -17, 75, -14, 80),
> -	CABAC_ENTRY(411, -15, 67, -9, 67, -14, 72, 0, 68),
> -	CABAC_ENTRY(412, -20, 62, -1, 61, -16, 67, -14, 70),
> -	CABAC_ENTRY(413, -19, 70, -8, 66, -8, 53, -24, 56),
> -	CABAC_ENTRY(414, -16, 66, -14, 66, -14, 59, -23, 68),
> -	CABAC_ENTRY(415, -22, 65, 0, 59, -9, 52, -24, 50),
> -	CABAC_ENTRY(416, -20, 63, 2, 59, -11, 68, -11, 74),
> -	CABAC_ENTRY(417, 9, -2, 17, -10, 9, -2, 23, -13),
> -	CABAC_ENTRY(418, 26, -9, 32, -13, 30, -10, 26, -13),
> -	CABAC_ENTRY(419, 33, -9, 42, -9, 31, -4, 40, -15),
> -	CABAC_ENTRY(420, 39, -7, 49, -5, 33, -1, 49, -14),
> -	CABAC_ENTRY(421, 41, -2, 53, 0, 33, 7, 44, 3),
> -	CABAC_ENTRY(422, 45, 3, 64, 3, 31, 12, 45, 6),
> -	CABAC_ENTRY(423, 49, 9, 68, 10, 37, 23, 44, 34),
> -	CABAC_ENTRY(424, 45, 27, 66, 27, 31, 38, 33, 54),
> -	CABAC_ENTRY(425, 36, 59, 47, 57, 20, 64, 19, 82),
> -	CABAC_ENTRY(426, -6, 66, -5, 71, -9, 71, -3, 75),
> -	CABAC_ENTRY(427, -7, 35, 0, 24, -7, 37, -1, 23),
> -	CABAC_ENTRY(428, -7, 42, -1, 36, -8, 44, 1, 34),
> -	CABAC_ENTRY(429, -8, 45, -2, 42, -11, 49, 1, 43),
> -	CABAC_ENTRY(430, -5, 48, -2, 52, -10, 56, 0, 54),
> -	CABAC_ENTRY(431, -12, 56, -9, 57, -12, 59, -2, 55),
> -	CABAC_ENTRY(432, -6, 60, -6, 63, -8, 63, 0, 61),
> -	CABAC_ENTRY(433, -5, 62, -4, 65, -9, 67, 1, 64),
> -	CABAC_ENTRY(434, -8, 66, -4, 67, -6, 68, 0, 68),
> -	CABAC_ENTRY(435, -8, 76, -7, 82, -10, 79, -9, 92),
> -	CABAC_ENTRY(436, -5, 85, -3, 81, -3, 78, -14, 106),
> -	CABAC_ENTRY(437, -6, 81, -3, 76, -8, 74, -13, 97),
> -	CABAC_ENTRY(438, -10, 77, -7, 72, -9, 72, -15, 90),
> -	CABAC_ENTRY(439, -7, 81, -6, 78, -10, 72, -12, 90),
> -	CABAC_ENTRY(440, -17, 80, -12, 72, -18, 75, -18, 88),
> -	CABAC_ENTRY(441, -18, 73, -14, 68, -12, 71, -10, 73),
> -	CABAC_ENTRY(442, -4, 74, -3, 70, -11, 63, -9, 79),
> -	CABAC_ENTRY(443, -10, 83, -6, 76, -5, 70, -14, 86),
> -	CABAC_ENTRY(444, -9, 71, -5, 66, -17, 75, -10, 73),
> -	CABAC_ENTRY(445, -9, 67, -5, 62, -14, 72, -10, 70),
> -	CABAC_ENTRY(446, -1, 61, 0, 57, -16, 67, -10, 69),
> -	CABAC_ENTRY(447, -8, 66, -4, 61, -8, 53, -5, 66),
> -	CABAC_ENTRY(448, -14, 66, -9, 60, -14, 59, -9, 64),
> -	CABAC_ENTRY(449, 0, 59, 1, 54, -9, 52, -5, 58),
> -	CABAC_ENTRY(450, 2, 59, 2, 58, -11, 68, 2, 59),
> -	CABAC_ENTRY(451, 21, -13, 17, -10, 9, -2, 21, -10),
> -	CABAC_ENTRY(452, 33, -14, 32, -13, 30, -10, 24, -11),
> -	CABAC_ENTRY(453, 39, -7, 42, -9, 31, -4, 28, -8),
> -	CABAC_ENTRY(454, 46, -2, 49, -5, 33, -1, 28, -1),
> -	CABAC_ENTRY(455, 51, 2, 53, 0, 33, 7, 29, 3),
> -	CABAC_ENTRY(456, 60, 6, 64, 3, 31, 12, 29, 9),
> -	CABAC_ENTRY(457, 61, 17, 68, 10, 37, 23, 35, 20),
> -	CABAC_ENTRY(458, 55, 34, 66, 27, 31, 38, 29, 36),
> -	CABAC_ENTRY(459, 42, 62, 47, 57, 20, 64, 14, 67),
> -};
> -
> ?static void set_ps_field(u32 *buf, struct rkvdec_ps_field field, u32 value)
> ?{
> ?	u8 bit = field.offset % 32, word = field.offset / 32;
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
> index 01f92fa27356..b01c1bb52a04 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
> @@ -16,7 +16,6 @@
> ?
> ?#include "rkvdec.h"
> ?#include "rkvdec-regs.h"
> -#include "rkvdec-hevc-data.c"
> ?
> ?/* Size in u8/u32 units. */
> ?#define RKV_SCALING_LIST_SIZE		1360
> @@ -25,6 +24,9 @@
> ?#define RKV_RPS_SIZE			(32 / 4)
> ?#define RKV_RPS_LEN			600
> ?
> +#define RKV_HEVC_CABAC_TABLE_SIZE		27456
> +extern const u8 rkvdec_hevc_cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
> +
> ?struct rkvdec_sps_pps_packet {
> ?	u32 info[RKV_PPS_SIZE];
> ?};
> @@ -110,7 +112,7 @@ struct rkvdec_ps_field {
> ?
> ?/* Data structure describing auxiliary buffer format. */
> ?struct rkvdec_hevc_priv_tbl {
> -	u8 cabac_table[RKV_CABAC_TABLE_SIZE];
> +	u8 cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
> ?	u8 scaling_list[RKV_SCALING_LIST_SIZE];
> ?	struct rkvdec_sps_pps_packet param_set[RKV_PPS_LEN];
> ?	struct rkvdec_rps_packet rps[RKV_RPS_LEN];
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251210/e8e25132/attachment-0001.sig>

From nicolas.dufresne at collabora.com  Wed Dec 10 12:19:50 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Wed, 10 Dec 2025 15:19:50 -0500
Subject: [PATCH v4 05/15] media: rkvdec: Use structs to represent the HW
 RPS
In-Reply-To: <20251022174508.284929-6-detlev.casanova@collabora.com>
References: <20251022174508.284929-1-detlev.casanova@collabora.com>
	 <20251022174508.284929-6-detlev.casanova@collabora.com>
Message-ID: <1e1eeec3f121697f914abee362ee657093fcf42b.camel@collabora.com>

Hi,

Le mercredi 22 octobre 2025 ? 13:44 -0400, Detlev Casanova a ?crit?:
> This is in preparation to add support for other variants of the decoder.
> 
> Moving to struct representation is mainly to prepare for multicore
> support that is present in e.g. rk3588.
> 
> Tested-by: Diederik de Haas <didi.debian at cknow.org>? # Rock 5B
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?.../platform/rockchip/rkvdec/rkvdec-h264.c??? | 93 +++++++++++++++++--
> ?1 file changed, 84 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
> index 989379ae3a73..cb17dfcae5ca 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
> @@ -19,7 +19,6 @@ extern const s8 rkvdec_h264_cabac_table[4][464][2];
> ?
> ?/* Size with u32 units. */
> ?#define RKV_CABAC_INIT_BUFFER_SIZE	(3680 + 128)
> -#define RKV_RPS_SIZE			((128 + 128) / 4)
> ?#define RKV_ERROR_INFO_SIZE		(256 * 144 * 4)
> ?
> ?#define RKVDEC_NUM_REFLIST		3
> @@ -34,6 +33,40 @@ struct rkvdec_sps_pps_packet {
> ?	u32 info[8];
> ?};
> ?
> +struct rkvdec_rps_entry {
> +	u32 dpb_info0:????????? 5;
> +	u32 bottom_flag0:?????? 1;
> +	u32 view_index_off0:??? 1;
> +	u32 dpb_info1:????????? 5;
> +	u32 bottom_flag1:?????? 1;
> +	u32 view_index_off1:??? 1;
> +	u32 dpb_info2:????????? 5;
> +	u32 bottom_flag2:?????? 1;
> +	u32 view_index_off2:??? 1;
> +	u32 dpb_info3:????????? 5;
> +	u32 bottom_flag3:?????? 1;
> +	u32 view_index_off3:??? 1;
> +	u32 dpb_info4:????????? 5;
> +	u32 bottom_flag4:?????? 1;
> +	u32 view_index_off4:??? 1;
> +	u32 dpb_info5:????????? 5;
> +	u32 bottom_flag5:?????? 1;
> +	u32 view_index_off5:??? 1;
> +	u32 dpb_info6:????????? 5;
> +	u32 bottom_flag6:?????? 1;
> +	u32 view_index_off6:??? 1;
> +	u32 dpb_info7:????????? 5;
> +	u32 bottom_flag7:?????? 1;
> +	u32 view_index_off7:??? 1;
> +} __packed;
> +
> +struct rkvdec_rps {
> +	u16 frame_num[16];
> +	u32 reserved0;
> +	struct rkvdec_rps_entry entries[12];
> +	u32 reserved1[66];
> +} __packed;
> +
> ?struct rkvdec_ps_field {
> ?	u16 offset;
> ?	u8 len;
> @@ -94,7 +127,7 @@ struct rkvdec_ps_field {
> ?struct rkvdec_h264_priv_tbl {
> ?	s8 cabac_table[4][464][2];
> ?	struct rkvdec_h264_scaling_list scaling_list;
> -	u32 rps[RKV_RPS_SIZE];
> +	struct rkvdec_rps rps;
> ?	struct rkvdec_sps_pps_packet param_set[256];
> ?	u8 err_info[RKV_ERROR_INFO_SIZE];
> ?};
> @@ -260,6 +293,51 @@ static void lookup_ref_buf_idx(struct rkvdec_ctx *ctx,
> ?	}
> ?}
> ?
> +static void set_dpb_info(struct rkvdec_rps_entry *entries,
> +			 u8 reflist,
> +			 u8 refnum,
> +			 u8 info,
> +			 bool bottom)
> +{
> +	struct rkvdec_rps_entry *entry = &entries[(reflist * 4) + refnum / 8];
> +	u8 idx = refnum % 8;
> +
> +	switch (idx) {
> +	case 0:
> +		entry->dpb_info0 = info;
> +		entry->bottom_flag0 = bottom;
> +		break;
> +	case 1:
> +		entry->dpb_info1 = info;
> +		entry->bottom_flag1 = bottom;
> +		break;
> +	case 2:
> +		entry->dpb_info2 = info;
> +		entry->bottom_flag2 = bottom;
> +		break;
> +	case 3:
> +		entry->dpb_info3 = info;
> +		entry->bottom_flag3 = bottom;
> +		break;
> +	case 4:
> +		entry->dpb_info4 = info;
> +		entry->bottom_flag4 = bottom;
> +		break;
> +	case 5:
> +		entry->dpb_info5 = info;
> +		entry->bottom_flag5 = bottom;
> +		break;
> +	case 6:
> +		entry->dpb_info6 = info;
> +		entry->bottom_flag6 = bottom;
> +		break;
> +	case 7:
> +		entry->dpb_info7 = info;
> +		entry->bottom_flag7 = bottom;
> +		break;
> +	}
> +}
> +
> ?static void assemble_hw_rps(struct rkvdec_ctx *ctx,
> ?			??? struct v4l2_h264_reflist_builder *builder,
> ?			??? struct rkvdec_h264_run *run)
> @@ -269,11 +347,10 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx,
> ?	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
> ?	struct rkvdec_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu;
> ?
> -	u32 *hw_rps = priv_tbl->rps;
> +	struct rkvdec_rps *hw_rps = &priv_tbl->rps;
> ?	u32 i, j;
> -	u16 *p = (u16 *)hw_rps;
> ?
> -	memset(hw_rps, 0, sizeof(priv_tbl->rps));
> +	memset(hw_rps, 0, sizeof(*hw_rps));
> ?
> ?	/*
> ?	 * Assign an invalid pic_num if DPB entry at that position is inactive.
> @@ -285,7 +362,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx,
> ?		if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
> ?			continue;
> ?
> -		p[i] = builder->refs[i].frame_num;
> +		hw_rps->frame_num[i] = builder->refs[i].frame_num;
> ?	}
> ?
> ?	for (j = 0; j < RKVDEC_NUM_REFLIST; j++) {
> @@ -312,9 +389,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx,
> ?			dpb_valid = run->ref_buf[ref->index] != NULL;
> ?			bottom = ref->fields == V4L2_H264_BOTTOM_FIELD_REF;
> ?
> -			set_ps_field(hw_rps, DPB_INFO(i, j),
> -				???? ref->index | dpb_valid << 4);
> -			set_ps_field(hw_rps, BOTTOM_FLAG(i, j), bottom);
> +			set_dpb_info(hw_rps->entries, j, i, ref->index | (dpb_valid << 4), bottom);
> ?		}
> ?	}
> ?}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251210/9c2a0e67/attachment.sig>

From nicolas.dufresne at collabora.com  Wed Dec 10 12:20:35 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Wed, 10 Dec 2025 15:20:35 -0500
Subject: [PATCH v4 06/15] media: rkvdec: Move h264 functions to common
 file
In-Reply-To: <20251022174508.284929-7-detlev.casanova@collabora.com>
References: <20251022174508.284929-1-detlev.casanova@collabora.com>
	 <20251022174508.284929-7-detlev.casanova@collabora.com>
Message-ID: <f5167f640540007ceb4dc6adef851d05bb0190cd.camel@collabora.com>

Le mercredi 22 octobre 2025 ? 13:44 -0400, Detlev Casanova a ?crit?:
> This is a preparation commit to add support for new variants of the
> decoder.
> 
> The functions will later be shared with vdpu381 (rk3588) and vdpu383
> (rk3576).
> 
> Tested-by: Diederik de Haas <didi.debian at cknow.org>? # Rock 5B
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?.../media/platform/rockchip/rkvdec/Makefile?? |?? 1 +
> ?.../rockchip/rkvdec/rkvdec-h264-common.c????? | 252 ++++++++++++++
> ?.../rockchip/rkvdec/rkvdec-h264-common.h????? |? 81 +++++
> ?.../platform/rockchip/rkvdec/rkvdec-h264.c??? | 310 +-----------------
> ?4 files changed, 338 insertions(+), 306 deletions(-)
> ?create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.c
> ?create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
> index a8ff5e3d7bec..d2ba7a7c15e5 100644
> --- a/drivers/media/platform/rockchip/rkvdec/Makefile
> +++ b/drivers/media/platform/rockchip/rkvdec/Makefile
> @@ -4,5 +4,6 @@ rockchip-vdec-y += \
> ?		?? rkvdec.o \
> ?		?? rkvdec-cabac.o \
> ?		?? rkvdec-h264.o \
> +		?? rkvdec-h264-common.o \
> ?		?? rkvdec-hevc.o \
> ?		?? rkvdec-vp9.o
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.c
> new file mode 100644
> index 000000000000..d660dd81ca6e
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.c
> @@ -0,0 +1,252 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Rockchip video decoder h264 common functions
> + *
> + * Copyright (C) 2025 Collabora, Ltd.
> + *? Detlev Casanova <detlev.casanova at collabora.com>
> + */
> +
> +#include <linux/v4l2-common.h>
> +#include <media/v4l2-h264.h>
> +#include <media/v4l2-mem2mem.h>
> +
> +#include "rkvdec.h"
> +#include "rkvdec-h264-common.h"
> +
> +#define RKVDEC_NUM_REFLIST		3
> +
> +static void set_dpb_info(struct rkvdec_rps_entry *entries,
> +			 u8 reflist,
> +			 u8 refnum,
> +			 u8 info,
> +			 bool bottom)
> +{
> +	struct rkvdec_rps_entry *entry = &entries[(reflist * 4) + refnum / 8];
> +	u8 idx = refnum % 8;
> +
> +	switch (idx) {
> +	case 0:
> +		entry->dpb_info0 = info;
> +		entry->bottom_flag0 = bottom;
> +		break;
> +	case 1:
> +		entry->dpb_info1 = info;
> +		entry->bottom_flag1 = bottom;
> +		break;
> +	case 2:
> +		entry->dpb_info2 = info;
> +		entry->bottom_flag2 = bottom;
> +		break;
> +	case 3:
> +		entry->dpb_info3 = info;
> +		entry->bottom_flag3 = bottom;
> +		break;
> +	case 4:
> +		entry->dpb_info4 = info;
> +		entry->bottom_flag4 = bottom;
> +		break;
> +	case 5:
> +		entry->dpb_info5 = info;
> +		entry->bottom_flag5 = bottom;
> +		break;
> +	case 6:
> +		entry->dpb_info6 = info;
> +		entry->bottom_flag6 = bottom;
> +		break;
> +	case 7:
> +		entry->dpb_info7 = info;
> +		entry->bottom_flag7 = bottom;
> +		break;
> +	}
> +}
> +
> +void lookup_ref_buf_idx(struct rkvdec_ctx *ctx,
> +			struct rkvdec_h264_run *run)
> +{
> +	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
> +	u32 i;
> +
> +	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
> +		struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
> +		const struct v4l2_h264_dpb_entry *dpb = run->decode_params->dpb;
> +		struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q;
> +		struct vb2_buffer *buf = NULL;
> +
> +		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) {
> +			buf = vb2_find_buffer(cap_q, dpb[i].reference_ts);
> +			if (!buf)
> +				pr_debug("No buffer for reference_ts %llu",
> +					 dpb[i].reference_ts);
> +		}
> +
> +		run->ref_buf[i] = buf;
> +	}
> +}
> +
> +void assemble_hw_rps(struct v4l2_h264_reflist_builder *builder,
> +		???? struct rkvdec_h264_run *run,
> +		???? struct rkvdec_h264_reflists *reflists,
> +		???? struct rkvdec_rps *hw_rps)
> +{
> +	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
> +	const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb;
> +
> +	u32 i, j;
> +
> +	memset(hw_rps, 0, sizeof(*hw_rps));
> +
> +	/*
> +	 * Assign an invalid pic_num if DPB entry at that position is inactive.
> +	 * If we assign 0 in that position hardware will treat that as a real
> +	 * reference picture with pic_num 0, triggering output picture
> +	 * corruption.
> +	 */
> +	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
> +		if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
> +			continue;
> +
> +		hw_rps->frame_num[i] = builder->refs[i].frame_num;
> +	}
> +
> +	for (j = 0; j < RKVDEC_NUM_REFLIST; j++) {
> +		for (i = 0; i < builder->num_valid; i++) {
> +			struct v4l2_h264_reference *ref;
> +			bool dpb_valid;
> +			bool bottom;
> +
> +			switch (j) {
> +			case 0:
> +				ref = &reflists->p[i];
> +				break;
> +			case 1:
> +				ref = &reflists->b0[i];
> +				break;
> +			case 2:
> +				ref = &reflists->b1[i];
> +				break;
> +			}
> +
> +			if (WARN_ON(ref->index >= ARRAY_SIZE(dec_params->dpb)))
> +				continue;
> +
> +			dpb_valid = !!(run->ref_buf[ref->index]);
> +			bottom = ref->fields == V4L2_H264_BOTTOM_FIELD_REF;
> +
> +			set_dpb_info(hw_rps->entries, j, i, ref->index | (dpb_valid << 4), bottom);
> +		}
> +	}
> +}
> +
> +void assemble_hw_scaling_list(struct rkvdec_h264_run *run,
> +			????? struct rkvdec_h264_scaling_list *scaling_list)
> +{
> +	const struct v4l2_ctrl_h264_scaling_matrix *scaling = run->scaling_matrix;
> +	const struct v4l2_ctrl_h264_pps *pps = run->pps;
> +
> +	if (!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT))
> +		return;
> +
> +	BUILD_BUG_ON(sizeof(scaling_list->scaling_list_4x4) !=
> +		???? sizeof(scaling->scaling_list_4x4));
> +	BUILD_BUG_ON(sizeof(scaling_list->scaling_list_8x8) !=
> +		???? sizeof(scaling->scaling_list_8x8));
> +
> +	memcpy(scaling_list->scaling_list_4x4,
> +	?????? scaling->scaling_list_4x4,
> +	?????? sizeof(scaling->scaling_list_4x4));
> +
> +	memcpy(scaling_list->scaling_list_8x8,
> +	?????? scaling->scaling_list_8x8,
> +	?????? sizeof(scaling->scaling_list_8x8));
> +}
> +
> +#define RKVDEC_H264_MAX_DEPTH_IN_BYTES		2
> +
> +int rkvdec_h264_adjust_fmt(struct rkvdec_ctx *ctx,
> +			?? struct v4l2_format *f)
> +{
> +	struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp;
> +
> +	fmt->num_planes = 1;
> +	if (!fmt->plane_fmt[0].sizeimage)
> +		fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height *
> +					????? RKVDEC_H264_MAX_DEPTH_IN_BYTES;
> +	return 0;
> +}
> +
> +enum rkvdec_image_fmt rkvdec_h264_get_image_fmt(struct rkvdec_ctx *ctx,
> +						struct v4l2_ctrl *ctrl)
> +{
> +	const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps;
> +
> +	if (ctrl->id != V4L2_CID_STATELESS_H264_SPS)
> +		return RKVDEC_IMG_FMT_ANY;
> +
> +	if (sps->bit_depth_luma_minus8 == 0) {
> +		if (sps->chroma_format_idc == 2)
> +			return RKVDEC_IMG_FMT_422_8BIT;
> +		else
> +			return RKVDEC_IMG_FMT_420_8BIT;
> +	} else if (sps->bit_depth_luma_minus8 == 2) {
> +		if (sps->chroma_format_idc == 2)
> +			return RKVDEC_IMG_FMT_422_10BIT;
> +		else
> +			return RKVDEC_IMG_FMT_420_10BIT;
> +	}
> +
> +	return RKVDEC_IMG_FMT_ANY;
> +}
> +
> +int rkvdec_h264_validate_sps(struct rkvdec_ctx *ctx,
> +			???? const struct v4l2_ctrl_h264_sps *sps)
> +{
> +	unsigned int width, height;
> +
> +	if (sps->chroma_format_idc > 2)
> +		/* Only 4:0:0, 4:2:0 and 4:2:2 are supported */
> +		return -EINVAL;
> +	if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
> +		/* Luma and chroma bit depth mismatch */
> +		return -EINVAL;
> +	if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2)
> +		/* Only 8-bit and 10-bit is supported */
> +		return -EINVAL;
> +
> +	width = (sps->pic_width_in_mbs_minus1 + 1) * 16;
> +	height = (sps->pic_height_in_map_units_minus1 + 1) * 16;
> +
> +	/*
> +	 * When frame_mbs_only_flag is not set, this is field height,
> +	 * which is half the final height (see (7-18) in the
> +	 * specification)
> +	 */
> +	if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY))
> +		height *= 2;
> +
> +	if (width > ctx->coded_fmt.fmt.pix_mp.width ||
> +	??? height > ctx->coded_fmt.fmt.pix_mp.height)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +void rkvdec_h264_run_preamble(struct rkvdec_ctx *ctx,
> +			????? struct rkvdec_h264_run *run)
> +{
> +	struct v4l2_ctrl *ctrl;
> +
> +	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> +			????? V4L2_CID_STATELESS_H264_DECODE_PARAMS);
> +	run->decode_params = ctrl ? ctrl->p_cur.p : NULL;
> +	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> +			????? V4L2_CID_STATELESS_H264_SPS);
> +	run->sps = ctrl ? ctrl->p_cur.p : NULL;
> +	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> +			????? V4L2_CID_STATELESS_H264_PPS);
> +	run->pps = ctrl ? ctrl->p_cur.p : NULL;
> +	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> +			????? V4L2_CID_STATELESS_H264_SCALING_MATRIX);
> +	run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL;
> +
> +	rkvdec_run_preamble(ctx, &run->base);
> +}
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h
> new file mode 100644
> index 000000000000..aea346744e4c
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h
> @@ -0,0 +1,81 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Rockchip video decoder h264 common functions
> + *
> + * Copyright (C) 2025 Collabora, Ltd.
> + *? Detlev Casanova <detlev.casanova at collabora.com>
> + */
> +
> +#include <media/v4l2-h264.h>
> +#include <media/v4l2-mem2mem.h>
> +
> +#include "rkvdec.h"
> +
> +extern const s8 rkvdec_h264_cabac_table[4][464][2];
> +
> +struct rkvdec_h264_scaling_list {
> +	u8 scaling_list_4x4[6][16];
> +	u8 scaling_list_8x8[6][64];
> +	u8 padding[128];
> +};
> +
> +struct rkvdec_h264_reflists {
> +	struct v4l2_h264_reference p[V4L2_H264_REF_LIST_LEN];
> +	struct v4l2_h264_reference b0[V4L2_H264_REF_LIST_LEN];
> +	struct v4l2_h264_reference b1[V4L2_H264_REF_LIST_LEN];
> +};
> +
> +struct rkvdec_h264_run {
> +	struct rkvdec_run base;
> +	const struct v4l2_ctrl_h264_decode_params *decode_params;
> +	const struct v4l2_ctrl_h264_sps *sps;
> +	const struct v4l2_ctrl_h264_pps *pps;
> +	const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix;
> +	struct vb2_buffer *ref_buf[V4L2_H264_NUM_DPB_ENTRIES];
> +};
> +
> +struct rkvdec_rps_entry {
> +	u32 dpb_info0:????????? 5;
> +	u32 bottom_flag0:?????? 1;
> +	u32 view_index_off0:??? 1;
> +	u32 dpb_info1:????????? 5;
> +	u32 bottom_flag1:?????? 1;
> +	u32 view_index_off1:??? 1;
> +	u32 dpb_info2:????????? 5;
> +	u32 bottom_flag2:?????? 1;
> +	u32 view_index_off2:??? 1;
> +	u32 dpb_info3:????????? 5;
> +	u32 bottom_flag3:?????? 1;
> +	u32 view_index_off3:??? 1;
> +	u32 dpb_info4:????????? 5;
> +	u32 bottom_flag4:?????? 1;
> +	u32 view_index_off4:??? 1;
> +	u32 dpb_info5:????????? 5;
> +	u32 bottom_flag5:?????? 1;
> +	u32 view_index_off5:??? 1;
> +	u32 dpb_info6:????????? 5;
> +	u32 bottom_flag6:?????? 1;
> +	u32 view_index_off6:??? 1;
> +	u32 dpb_info7:????????? 5;
> +	u32 bottom_flag7:?????? 1;
> +	u32 view_index_off7:??? 1;
> +} __packed;
> +
> +struct rkvdec_rps {
> +	u16 frame_num[16];
> +	u32 reserved0;
> +	struct rkvdec_rps_entry entries[12];
> +	u32 reserved1[66];
> +} __packed;
> +
> +void lookup_ref_buf_idx(struct rkvdec_ctx *ctx, struct rkvdec_h264_run *run);
> +void assemble_hw_rps(struct v4l2_h264_reflist_builder *builder,
> +		???? struct rkvdec_h264_run *run,
> +		???? struct rkvdec_h264_reflists *reflists,
> +		???? struct rkvdec_rps *hw_rps);
> +void assemble_hw_scaling_list(struct rkvdec_h264_run *run,
> +			????? struct rkvdec_h264_scaling_list *scaling_list);
> +int rkvdec_h264_adjust_fmt(struct rkvdec_ctx *ctx, struct v4l2_format *f);
> +enum rkvdec_image_fmt rkvdec_h264_get_image_fmt(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl);
> +int rkvdec_h264_validate_sps(struct rkvdec_ctx *ctx, const struct v4l2_ctrl_h264_sps *sps);
> +void rkvdec_h264_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_h264_run *run);
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
> index cb17dfcae5ca..e98bb69ff7f9 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
> @@ -14,59 +14,16 @@
> ?
> ?#include "rkvdec.h"
> ?#include "rkvdec-regs.h"
> -
> -extern const s8 rkvdec_h264_cabac_table[4][464][2];
> +#include "rkvdec-h264-common.h"
> ?
> ?/* Size with u32 units. */
> ?#define RKV_CABAC_INIT_BUFFER_SIZE	(3680 + 128)
> ?#define RKV_ERROR_INFO_SIZE		(256 * 144 * 4)
> ?
> -#define RKVDEC_NUM_REFLIST		3
> -
> -struct rkvdec_h264_scaling_list {
> -	u8 scaling_list_4x4[6][16];
> -	u8 scaling_list_8x8[6][64];
> -	u8 padding[128];
> -};
> -
> ?struct rkvdec_sps_pps_packet {
> ?	u32 info[8];
> ?};
> ?
> -struct rkvdec_rps_entry {
> -	u32 dpb_info0:????????? 5;
> -	u32 bottom_flag0:?????? 1;
> -	u32 view_index_off0:??? 1;
> -	u32 dpb_info1:????????? 5;
> -	u32 bottom_flag1:?????? 1;
> -	u32 view_index_off1:??? 1;
> -	u32 dpb_info2:????????? 5;
> -	u32 bottom_flag2:?????? 1;
> -	u32 view_index_off2:??? 1;
> -	u32 dpb_info3:????????? 5;
> -	u32 bottom_flag3:?????? 1;
> -	u32 view_index_off3:??? 1;
> -	u32 dpb_info4:????????? 5;
> -	u32 bottom_flag4:?????? 1;
> -	u32 view_index_off4:??? 1;
> -	u32 dpb_info5:????????? 5;
> -	u32 bottom_flag5:?????? 1;
> -	u32 view_index_off5:??? 1;
> -	u32 dpb_info6:????????? 5;
> -	u32 bottom_flag6:?????? 1;
> -	u32 view_index_off6:??? 1;
> -	u32 dpb_info7:????????? 5;
> -	u32 bottom_flag7:?????? 1;
> -	u32 view_index_off7:??? 1;
> -} __packed;
> -
> -struct rkvdec_rps {
> -	u16 frame_num[16];
> -	u32 reserved0;
> -	struct rkvdec_rps_entry entries[12];
> -	u32 reserved1[66];
> -} __packed;
> -
> ?struct rkvdec_ps_field {
> ?	u16 offset;
> ?	u8 len;
> @@ -118,11 +75,6 @@ struct rkvdec_ps_field {
> ?#define SCALING_LIST_ADDRESS				PS_FIELD(184, 32)
> ?#define IS_LONG_TERM(i)				PS_FIELD(216 + (i), 1)
> ?
> -#define DPB_OFFS(i, j)					(288 + ((j) * 32 * 7) + ((i) * 7))
> -#define DPB_INFO(i, j)					PS_FIELD(DPB_OFFS(i, j), 5)
> -#define BOTTOM_FLAG(i, j)				PS_FIELD(DPB_OFFS(i, j) + 5, 1)
> -#define VIEW_INDEX_OFF(i, j)				PS_FIELD(DPB_OFFS(i, j) + 6, 1)
> -
> ?/* Data structure describing auxiliary buffer format. */
> ?struct rkvdec_h264_priv_tbl {
> ?	s8 cabac_table[4][464][2];
> @@ -132,21 +84,6 @@ struct rkvdec_h264_priv_tbl {
> ?	u8 err_info[RKV_ERROR_INFO_SIZE];
> ?};
> ?
> -struct rkvdec_h264_reflists {
> -	struct v4l2_h264_reference p[V4L2_H264_REF_LIST_LEN];
> -	struct v4l2_h264_reference b0[V4L2_H264_REF_LIST_LEN];
> -	struct v4l2_h264_reference b1[V4L2_H264_REF_LIST_LEN];
> -};
> -
> -struct rkvdec_h264_run {
> -	struct rkvdec_run base;
> -	const struct v4l2_ctrl_h264_decode_params *decode_params;
> -	const struct v4l2_ctrl_h264_sps *sps;
> -	const struct v4l2_ctrl_h264_pps *pps;
> -	const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix;
> -	struct vb2_buffer *ref_buf[V4L2_H264_NUM_DPB_ENTRIES];
> -};
> -
> ?struct rkvdec_h264_ctx {
> ?	struct rkvdec_aux_buf priv_tbl;
> ?	struct rkvdec_h264_reflists reflists;
> @@ -270,155 +207,6 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
> ?	}
> ?}
> ?
> -static void lookup_ref_buf_idx(struct rkvdec_ctx *ctx,
> -			?????? struct rkvdec_h264_run *run)
> -{
> -	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
> -	u32 i;
> -
> -	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
> -		struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
> -		const struct v4l2_h264_dpb_entry *dpb = run->decode_params->dpb;
> -		struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q;
> -		struct vb2_buffer *buf = NULL;
> -
> -		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) {
> -			buf = vb2_find_buffer(cap_q, dpb[i].reference_ts);
> -			if (!buf)
> -				pr_debug("No buffer for reference_ts %llu",
> -					 dpb[i].reference_ts);
> -		}
> -
> -		run->ref_buf[i] = buf;
> -	}
> -}
> -
> -static void set_dpb_info(struct rkvdec_rps_entry *entries,
> -			 u8 reflist,
> -			 u8 refnum,
> -			 u8 info,
> -			 bool bottom)
> -{
> -	struct rkvdec_rps_entry *entry = &entries[(reflist * 4) + refnum / 8];
> -	u8 idx = refnum % 8;
> -
> -	switch (idx) {
> -	case 0:
> -		entry->dpb_info0 = info;
> -		entry->bottom_flag0 = bottom;
> -		break;
> -	case 1:
> -		entry->dpb_info1 = info;
> -		entry->bottom_flag1 = bottom;
> -		break;
> -	case 2:
> -		entry->dpb_info2 = info;
> -		entry->bottom_flag2 = bottom;
> -		break;
> -	case 3:
> -		entry->dpb_info3 = info;
> -		entry->bottom_flag3 = bottom;
> -		break;
> -	case 4:
> -		entry->dpb_info4 = info;
> -		entry->bottom_flag4 = bottom;
> -		break;
> -	case 5:
> -		entry->dpb_info5 = info;
> -		entry->bottom_flag5 = bottom;
> -		break;
> -	case 6:
> -		entry->dpb_info6 = info;
> -		entry->bottom_flag6 = bottom;
> -		break;
> -	case 7:
> -		entry->dpb_info7 = info;
> -		entry->bottom_flag7 = bottom;
> -		break;
> -	}
> -}
> -
> -static void assemble_hw_rps(struct rkvdec_ctx *ctx,
> -			??? struct v4l2_h264_reflist_builder *builder,
> -			??? struct rkvdec_h264_run *run)
> -{
> -	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
> -	const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb;
> -	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
> -	struct rkvdec_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu;
> -
> -	struct rkvdec_rps *hw_rps = &priv_tbl->rps;
> -	u32 i, j;
> -
> -	memset(hw_rps, 0, sizeof(*hw_rps));
> -
> -	/*
> -	 * Assign an invalid pic_num if DPB entry at that position is inactive.
> -	 * If we assign 0 in that position hardware will treat that as a real
> -	 * reference picture with pic_num 0, triggering output picture
> -	 * corruption.
> -	 */
> -	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
> -		if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
> -			continue;
> -
> -		hw_rps->frame_num[i] = builder->refs[i].frame_num;
> -	}
> -
> -	for (j = 0; j < RKVDEC_NUM_REFLIST; j++) {
> -		for (i = 0; i < builder->num_valid; i++) {
> -			struct v4l2_h264_reference *ref;
> -			bool dpb_valid;
> -			bool bottom;
> -
> -			switch (j) {
> -			case 0:
> -				ref = &h264_ctx->reflists.p[i];
> -				break;
> -			case 1:
> -				ref = &h264_ctx->reflists.b0[i];
> -				break;
> -			case 2:
> -				ref = &h264_ctx->reflists.b1[i];
> -				break;
> -			}
> -
> -			if (WARN_ON(ref->index >= ARRAY_SIZE(dec_params->dpb)))
> -				continue;
> -
> -			dpb_valid = run->ref_buf[ref->index] != NULL;
> -			bottom = ref->fields == V4L2_H264_BOTTOM_FIELD_REF;
> -
> -			set_dpb_info(hw_rps->entries, j, i, ref->index | (dpb_valid << 4), bottom);
> -		}
> -	}
> -}
> -
> -static void assemble_hw_scaling_list(struct rkvdec_ctx *ctx,
> -				???? struct rkvdec_h264_run *run)
> -{
> -	const struct v4l2_ctrl_h264_scaling_matrix *scaling = run->scaling_matrix;
> -	const struct v4l2_ctrl_h264_pps *pps = run->pps;
> -	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
> -	struct rkvdec_h264_priv_tbl *tbl = h264_ctx->priv_tbl.cpu;
> -
> -	if (!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT))
> -		return;
> -
> -	BUILD_BUG_ON(sizeof(tbl->scaling_list.scaling_list_4x4) !=
> -		???? sizeof(scaling->scaling_list_4x4));
> -	BUILD_BUG_ON(sizeof(tbl->scaling_list.scaling_list_8x8) !=
> -		???? sizeof(scaling->scaling_list_8x8));
> -
> -	memcpy(tbl->scaling_list.scaling_list_4x4,
> -	?????? scaling->scaling_list_4x4,
> -	?????? sizeof(scaling->scaling_list_4x4));
> -
> -	memcpy(tbl->scaling_list.scaling_list_8x8,
> -	?????? scaling->scaling_list_8x8,
> -	?????? sizeof(scaling->scaling_list_8x8));
> -}
> -
> ?/*
> ? * Set the ref POC in the correct register.
> ? *
> @@ -568,76 +356,6 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?	rkvdec_memcpy_toio(rkvdec->regs, regs, MIN(sizeof(*regs), 4 * rkvdec->variant->num_regs));
> ?}
> ?
> -#define RKVDEC_H264_MAX_DEPTH_IN_BYTES		2
> -
> -static int rkvdec_h264_adjust_fmt(struct rkvdec_ctx *ctx,
> -				? struct v4l2_format *f)
> -{
> -	struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp;
> -
> -	fmt->num_planes = 1;
> -	if (!fmt->plane_fmt[0].sizeimage)
> -		fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height *
> -					????? RKVDEC_H264_MAX_DEPTH_IN_BYTES;
> -	return 0;
> -}
> -
> -static enum rkvdec_image_fmt rkvdec_h264_get_image_fmt(struct rkvdec_ctx *ctx,
> -						?????? struct v4l2_ctrl *ctrl)
> -{
> -	const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps;
> -
> -	if (ctrl->id != V4L2_CID_STATELESS_H264_SPS)
> -		return RKVDEC_IMG_FMT_ANY;
> -
> -	if (sps->bit_depth_luma_minus8 == 0) {
> -		if (sps->chroma_format_idc == 2)
> -			return RKVDEC_IMG_FMT_422_8BIT;
> -		else
> -			return RKVDEC_IMG_FMT_420_8BIT;
> -	} else if (sps->bit_depth_luma_minus8 == 2) {
> -		if (sps->chroma_format_idc == 2)
> -			return RKVDEC_IMG_FMT_422_10BIT;
> -		else
> -			return RKVDEC_IMG_FMT_420_10BIT;
> -	}
> -
> -	return RKVDEC_IMG_FMT_ANY;
> -}
> -
> -static int rkvdec_h264_validate_sps(struct rkvdec_ctx *ctx,
> -				??? const struct v4l2_ctrl_h264_sps *sps)
> -{
> -	unsigned int width, height;
> -
> -	if (sps->chroma_format_idc > 2)
> -		/* Only 4:0:0, 4:2:0 and 4:2:2 are supported */
> -		return -EINVAL;
> -	if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
> -		/* Luma and chroma bit depth mismatch */
> -		return -EINVAL;
> -	if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2)
> -		/* Only 8-bit and 10-bit is supported */
> -		return -EINVAL;
> -
> -	width = (sps->pic_width_in_mbs_minus1 + 1) * 16;
> -	height = (sps->pic_height_in_map_units_minus1 + 1) * 16;
> -
> -	/*
> -	 * When frame_mbs_only_flag is not set, this is field height,
> -	 * which is half the final height (see (7-18) in the
> -	 * specification)
> -	 */
> -	if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY))
> -		height *= 2;
> -
> -	if (width > ctx->coded_fmt.fmt.pix_mp.width ||
> -	??? height > ctx->coded_fmt.fmt.pix_mp.height)
> -		return -EINVAL;
> -
> -	return 0;
> -}
> -
> ?static int rkvdec_h264_start(struct rkvdec_ctx *ctx)
> ?{
> ?	struct rkvdec_dev *rkvdec = ctx->dev;
> @@ -689,33 +407,13 @@ static void rkvdec_h264_stop(struct rkvdec_ctx *ctx)
> ?	kfree(h264_ctx);
> ?}
> ?
> -static void rkvdec_h264_run_preamble(struct rkvdec_ctx *ctx,
> -				???? struct rkvdec_h264_run *run)
> -{
> -	struct v4l2_ctrl *ctrl;
> -
> -	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> -			????? V4L2_CID_STATELESS_H264_DECODE_PARAMS);
> -	run->decode_params = ctrl ? ctrl->p_cur.p : NULL;
> -	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> -			????? V4L2_CID_STATELESS_H264_SPS);
> -	run->sps = ctrl ? ctrl->p_cur.p : NULL;
> -	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> -			????? V4L2_CID_STATELESS_H264_PPS);
> -	run->pps = ctrl ? ctrl->p_cur.p : NULL;
> -	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> -			????? V4L2_CID_STATELESS_H264_SCALING_MATRIX);
> -	run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL;
> -
> -	rkvdec_run_preamble(ctx, &run->base);
> -}
> -
> ?static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
> ?{
> ?	struct v4l2_h264_reflist_builder reflist_builder;
> ?	struct rkvdec_dev *rkvdec = ctx->dev;
> ?	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
> ?	struct rkvdec_h264_run run;
> +	struct rkvdec_h264_priv_tbl *tbl = h264_ctx->priv_tbl.cpu;
> ?
> ?	rkvdec_h264_run_preamble(ctx, &run);
> ?
> @@ -726,10 +424,10 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
> ?	v4l2_h264_build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0,
> ?				??? h264_ctx->reflists.b1);
> ?
> -	assemble_hw_scaling_list(ctx, &run);
> +	assemble_hw_scaling_list(&run, &tbl->scaling_list);
> ?	assemble_hw_pps(ctx, &run);
> ?	lookup_ref_buf_idx(ctx, &run);
> -	assemble_hw_rps(ctx, &reflist_builder, &run);
> +	assemble_hw_rps(&reflist_builder, &run, &h264_ctx->reflists, &tbl->rps);
> ?	config_registers(ctx, &run);
> ?
> ?	rkvdec_run_postamble(ctx, &run.base);
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251210/62624123/attachment-0001.sig>

From nicolas.dufresne at collabora.com  Wed Dec 10 12:22:06 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Wed, 10 Dec 2025 15:22:06 -0500
Subject: [PATCH v4 07/15] media: rkvdec: Move hevc functions to common
 file
In-Reply-To: <20251022174508.284929-8-detlev.casanova@collabora.com>
References: <20251022174508.284929-1-detlev.casanova@collabora.com>
	 <20251022174508.284929-8-detlev.casanova@collabora.com>
Message-ID: <faaf8950ae8d71d45345bc3534fa26188ccef7d9.camel@collabora.com>

Le mercredi 22 octobre 2025 ? 13:44 -0400, Detlev Casanova a ?crit?:
> This is a preparation commit to add support for new variants of the
> decoder.
> 
> The functions will later be shared with vdpu381 (rk3588) and vdpu383
> (rk3576).
> 
> Tested-by: Diederik de Haas <didi.debian at cknow.org>? # Rock 5B
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?.../media/platform/rockchip/rkvdec/Makefile?? |?? 1 +
> ?.../rockchip/rkvdec/rkvdec-hevc-common.c????? | 233 +++++++++++++++++
> ?.../rockchip/rkvdec/rkvdec-hevc-common.h????? |? 51 ++++
> ?.../platform/rockchip/rkvdec/rkvdec-hevc.c??? | 243 +-----------------
> ?4 files changed, 291 insertions(+), 237 deletions(-)
> ?create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
> ?create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
> index d2ba7a7c15e5..1b4bc44be23e 100644
> --- a/drivers/media/platform/rockchip/rkvdec/Makefile
> +++ b/drivers/media/platform/rockchip/rkvdec/Makefile
> @@ -6,4 +6,5 @@ rockchip-vdec-y += \
> ?		?? rkvdec-h264.o \
> ?		?? rkvdec-h264-common.o \
> ?		?? rkvdec-hevc.o \
> +		?? rkvdec-hevc-common.o \
> ?		?? rkvdec-vp9.o
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
> new file mode 100644
> index 000000000000..d571107f2242
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
> @@ -0,0 +1,233 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Rockchip video decoder hevc common functions
> + *
> + * Copyright (C) 2025 Collabora, Ltd.
> + *????? Detlev Casanova <detlev.casanova at collabora.com>
> + *
> + * Copyright (C) 2023 Collabora, Ltd.
> + *????? Sebastian Fricke <sebastian.fricke at collabora.com>
> + *
> + * Copyright (C) 2019 Collabora, Ltd.
> + *	Boris Brezillon <boris.brezillon at collabora.com>
> + *
> + * Copyright (C) 2016 Rockchip Electronics Co., Ltd.
> + *	Jeffy Chen <jeffy.chen at rock-chips.com>
> + */
> +
> +#include <linux/v4l2-common.h>
> +#include <media/v4l2-mem2mem.h>
> +
> +#include "rkvdec.h"
> +#include "rkvdec-hevc-common.h"
> +
> +/*
> + * Flip one or more matrices along their main diagonal and flatten them
> + * before writing it to the memory.
> + * Convert:
> + * ABCD???????? AEIM
> + * EFGH???? =>? BFJN???? =>???? AEIMBFJNCGKODHLP
> + * IJKL???????? CGKO
> + * MNOP???????? DHLP
> + */
> +static void transpose_and_flatten_matrices(u8 *output, const u8 *input,
> +					?? int matrices, int row_length)
> +{
> +	int i, j, row, x_offset, matrix_offset, rot_index, y_offset, matrix_size, new_value;
> +
> +	matrix_size = row_length * row_length;
> +	for (i = 0; i < matrices; i++) {
> +		row = 0;
> +		x_offset = 0;
> +		matrix_offset = i * matrix_size;
> +		for (j = 0; j < matrix_size; j++) {
> +			y_offset = j - (row * row_length);
> +			rot_index = y_offset * row_length + x_offset;
> +			new_value = *(input + i * matrix_size + j);
> +			output[matrix_offset + rot_index] = new_value;
> +			if ((j + 1) % row_length == 0) {
> +				row += 1;
> +				x_offset += 1;
> +			}
> +		}
> +	}
> +}
> +
> +static void assemble_scalingfactor0(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input)
> +{
> +	int offset = 0;
> +
> +	transpose_and_flatten_matrices(output, (const u8 *)input->scaling_list_4x4, 6, 4);
> +	offset = 6 * 16 * sizeof(u8);
> +	transpose_and_flatten_matrices(output + offset, (const u8 *)input->scaling_list_8x8, 6, 8);
> +	offset += 6 * 64 * sizeof(u8);
> +	transpose_and_flatten_matrices(output + offset,
> +				?????? (const u8 *)input->scaling_list_16x16, 6, 8);
> +	offset += 6 * 64 * sizeof(u8);
> +	/* Add a 128 byte padding with 0s between the two 32x32 matrices */
> +	transpose_and_flatten_matrices(output + offset,
> +				?????? (const u8 *)input->scaling_list_32x32, 1, 8);
> +	offset += 64 * sizeof(u8);
> +	memset(output + offset, 0, 128);
> +	offset += 128 * sizeof(u8);
> +	transpose_and_flatten_matrices(output + offset,
> +				?????? (const u8 *)input->scaling_list_32x32 + (64 * sizeof(u8)),
> +				?????? 1, 8);
> +	offset += 64 * sizeof(u8);
> +	memset(output + offset, 0, 128);
> +}
> +
> +/*
> + * Required layout:
> + * A = scaling_list_dc_coef_16x16
> + * B = scaling_list_dc_coef_32x32
> + * 0 = Padding
> + *
> + * A, A, A, A, A, A, B, 0, 0, B, 0, 0
> + */
> +static void assemble_scalingdc(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input)
> +{
> +	u8 list_32x32[6] = {0};
> +
> +	memcpy(output, input->scaling_list_dc_coef_16x16, 6 * sizeof(u8));
> +	list_32x32[0] = input->scaling_list_dc_coef_32x32[0];
> +	list_32x32[3] = input->scaling_list_dc_coef_32x32[1];
> +	memcpy(output + 6 * sizeof(u8), list_32x32, 6 * sizeof(u8));
> +}
> +
> +static void translate_scaling_list(struct scaling_factor *output,
> +				?? const struct v4l2_ctrl_hevc_scaling_matrix *input)
> +{
> +	assemble_scalingfactor0(output->scalingfactor0, input);
> +	memcpy(output->scalingfactor1, (const u8 *)input->scaling_list_4x4, 96);
> +	assemble_scalingdc(output->scalingdc, input);
> +	memset(output->reserved, 0, 4 * sizeof(u8));
> +}
> +
> +void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
> +					? struct scaling_factor *scaling_factor,
> +					? struct v4l2_ctrl_hevc_scaling_matrix *cache)
> +{
> +	const struct v4l2_ctrl_hevc_scaling_matrix *scaling = run->scaling_matrix;
> +
> +	if (!memcmp(cache, scaling,
> +		??? sizeof(struct v4l2_ctrl_hevc_scaling_matrix)))
> +		return;
> +
> +	translate_scaling_list(scaling_factor, scaling);
> +
> +	memcpy(cache, scaling,
> +	?????? sizeof(struct v4l2_ctrl_hevc_scaling_matrix));
> +}
> +
> +struct vb2_buffer *
> +get_ref_buf(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run,
> +	??? unsigned int dpb_idx)
> +{
> +	struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
> +	const struct v4l2_ctrl_hevc_decode_params *decode_params = run->decode_params;
> +	const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb;
> +	struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q;
> +	struct vb2_buffer *buf = NULL;
> +
> +	if (dpb_idx < decode_params->num_active_dpb_entries)
> +		buf = vb2_find_buffer(cap_q, dpb[dpb_idx].timestamp);
> +
> +	/*
> +	 * If a DPB entry is unused or invalid, the address of current destination
> +	 * buffer is returned.
> +	 */
> +	if (!buf)
> +		return &run->base.bufs.dst->vb2_buf;
> +
> +	return buf;
> +}
> +
> +#define RKVDEC_HEVC_MAX_DEPTH_IN_BYTES		2
> +
> +int rkvdec_hevc_adjust_fmt(struct rkvdec_ctx *ctx, struct v4l2_format *f)
> +{
> +	struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp;
> +
> +	fmt->num_planes = 1;
> +	if (!fmt->plane_fmt[0].sizeimage)
> +		fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height *
> +					????? RKVDEC_HEVC_MAX_DEPTH_IN_BYTES;
> +	return 0;
> +}
> +
> +enum rkvdec_image_fmt rkvdec_hevc_get_image_fmt(struct rkvdec_ctx *ctx,
> +						struct v4l2_ctrl *ctrl)
> +{
> +	const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps;
> +
> +	if (ctrl->id != V4L2_CID_STATELESS_HEVC_SPS)
> +		return RKVDEC_IMG_FMT_ANY;
> +
> +	if (sps->bit_depth_luma_minus8 == 0) {
> +		if (sps->chroma_format_idc == 2)
> +			return RKVDEC_IMG_FMT_422_8BIT;
> +		else
> +			return RKVDEC_IMG_FMT_420_8BIT;
> +	} else if (sps->bit_depth_luma_minus8 == 2) {
> +		if (sps->chroma_format_idc == 2)
> +			return RKVDEC_IMG_FMT_422_10BIT;
> +		else
> +			return RKVDEC_IMG_FMT_420_10BIT;
> +	}
> +
> +	return RKVDEC_IMG_FMT_ANY;
> +}
> +
> +static int rkvdec_hevc_validate_sps(struct rkvdec_ctx *ctx,
> +			???? const struct v4l2_ctrl_hevc_sps *sps)
> +{
> +	if (sps->chroma_format_idc > 1)
> +		/* Only 4:0:0 and 4:2:0 are supported */
> +		return -EINVAL;
> +	if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
> +		/* Luma and chroma bit depth mismatch */
> +		return -EINVAL;
> +	if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2)
> +		/* Only 8-bit and 10-bit are supported */
> +		return -EINVAL;
> +
> +	if (sps->pic_width_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.width ||
> +	??? sps->pic_height_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.height)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +void rkvdec_hevc_run_preamble(struct rkvdec_ctx *ctx,
> +			????? struct rkvdec_hevc_run *run)
> +{
> +	struct v4l2_ctrl *ctrl;
> +
> +	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> +			????? V4L2_CID_STATELESS_HEVC_DECODE_PARAMS);
> +	run->decode_params = ctrl ? ctrl->p_cur.p : NULL;
> +	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> +			????? V4L2_CID_STATELESS_HEVC_SLICE_PARAMS);
> +	run->slices_params = ctrl ? ctrl->p_cur.p : NULL;
> +	run->num_slices = ctrl ? ctrl->new_elems : 0;
> +	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> +			????? V4L2_CID_STATELESS_HEVC_SPS);
> +	run->sps = ctrl ? ctrl->p_cur.p : NULL;
> +	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> +			????? V4L2_CID_STATELESS_HEVC_PPS);
> +	run->pps = ctrl ? ctrl->p_cur.p : NULL;
> +	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> +			????? V4L2_CID_STATELESS_HEVC_SCALING_MATRIX);
> +	run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL;
> +
> +	rkvdec_run_preamble(ctx, &run->base);
> +}
> +
> +int rkvdec_hevc_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
> +{
> +	if (ctrl->id == V4L2_CID_STATELESS_HEVC_SPS)
> +		return rkvdec_hevc_validate_sps(ctx, ctrl->p_new.p_hevc_sps);
> +
> +	return 0;
> +}
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
> new file mode 100644
> index 000000000000..746b1bd73c08
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
> @@ -0,0 +1,51 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Rockchip video decoder hevc common functions
> + *
> + * Copyright (C) 2025 Collabora, Ltd.
> + *????? Detlev Casanova <detlev.casanova at collabora.com>
> + *
> + * Copyright (C) 2023 Collabora, Ltd.
> + *????? Sebastian Fricke <sebastian.fricke at collabora.com>
> + *
> + * Copyright (C) 2019 Collabora, Ltd.
> + *	Boris Brezillon <boris.brezillon at collabora.com>
> + *
> + * Copyright (C) 2016 Rockchip Electronics Co., Ltd.
> + *	Jeffy Chen <jeffy.chen at rock-chips.com>
> + */
> +
> +#include <media/v4l2-mem2mem.h>
> +#include "rkvdec.h"
> +
> +#define RKV_HEVC_CABAC_TABLE_SIZE		27456
> +extern const u8 rkvdec_hevc_cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
> +
> +struct rkvdec_hevc_run {
> +	struct rkvdec_run base;
> +	const struct v4l2_ctrl_hevc_slice_params *slices_params;
> +	const struct v4l2_ctrl_hevc_decode_params *decode_params;
> +	const struct v4l2_ctrl_hevc_sps *sps;
> +	const struct v4l2_ctrl_hevc_pps *pps;
> +	const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix;
> +	int num_slices;
> +};
> +
> +struct scaling_factor {
> +	u8 scalingfactor0[1248];
> +	u8 scalingfactor1[96];	/*4X4 TU Rotate, total 16X4*/
> +	u8 scalingdc[12];	/*N1005 Vienna Meeting*/
> +	u8 reserved[4];		/*16Bytes align*/
> +};
> +
> +enum rkvdec_image_fmt rkvdec_hevc_get_image_fmt(struct rkvdec_ctx *ctx,
> +						struct v4l2_ctrl *ctrl);
> +void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
> +					? struct scaling_factor *scaling_factor,
> +					? struct v4l2_ctrl_hevc_scaling_matrix *cache);
> +struct vb2_buffer *get_ref_buf(struct rkvdec_ctx *ctx,
> +			?????? struct rkvdec_hevc_run *run,
> +			?????? unsigned int dpb_idx);
> +int rkvdec_hevc_adjust_fmt(struct rkvdec_ctx *ctx, struct v4l2_format *f);
> +int rkvdec_hevc_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl);
> +void rkvdec_hevc_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run);
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
> index b01c1bb52a04..31a979698578 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
> @@ -16,6 +16,7 @@
> ?
> ?#include "rkvdec.h"
> ?#include "rkvdec-regs.h"
> +#include "rkvdec-hevc-common.h"
> ?
> ?/* Size in u8/u32 units. */
> ?#define RKV_SCALING_LIST_SIZE		1360
> @@ -24,9 +25,6 @@
> ?#define RKV_RPS_SIZE			(32 / 4)
> ?#define RKV_RPS_LEN			600
> ?
> -#define RKV_HEVC_CABAC_TABLE_SIZE		27456
> -extern const u8 rkvdec_hevc_cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
> -
> ?struct rkvdec_sps_pps_packet {
> ?	u32 info[RKV_PPS_SIZE];
> ?};
> @@ -113,34 +111,17 @@ struct rkvdec_ps_field {
> ?/* Data structure describing auxiliary buffer format. */
> ?struct rkvdec_hevc_priv_tbl {
> ?	u8 cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
> -	u8 scaling_list[RKV_SCALING_LIST_SIZE];
> +	struct scaling_factor scaling_list;
> ?	struct rkvdec_sps_pps_packet param_set[RKV_PPS_LEN];
> ?	struct rkvdec_rps_packet rps[RKV_RPS_LEN];
> ?};
> ?
> -struct rkvdec_hevc_run {
> -	struct rkvdec_run base;
> -	const struct v4l2_ctrl_hevc_slice_params *slices_params;
> -	const struct v4l2_ctrl_hevc_decode_params *decode_params;
> -	const struct v4l2_ctrl_hevc_sps *sps;
> -	const struct v4l2_ctrl_hevc_pps *pps;
> -	const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix;
> -	int num_slices;
> -};
> -
> ?struct rkvdec_hevc_ctx {
> ?	struct rkvdec_aux_buf priv_tbl;
> ?	struct v4l2_ctrl_hevc_scaling_matrix scaling_matrix_cache;
> ?	struct rkvdec_regs regs;
> ?};
> ?
> -struct scaling_factor {
> -	u8 scalingfactor0[1248];
> -	u8 scalingfactor1[96];		/*4X4 TU Rotate, total 16X4*/
> -	u8 scalingdc[12];		/*N1005 Vienna Meeting*/
> -	u8 reserved[4];		/*16Bytes align*/
> -};
> -
> ?static void set_ps_field(u32 *buf, struct rkvdec_ps_field field, u32 value)
> ?{
> ?	u8 bit = field.offset % 32, word = field.offset / 32;
> @@ -417,131 +398,6 @@ static void assemble_sw_rps(struct rkvdec_ctx *ctx,
> ?	}
> ?}
> ?
> -/*
> - * Flip one or more matrices along their main diagonal and flatten them
> - * before writing it to the memory.
> - * Convert:
> - * ABCD???????? AEIM
> - * EFGH???? =>? BFJN???? =>???? AEIMBFJNCGKODHLP
> - * IJKL???????? CGKO
> - * MNOP???????? DHLP
> - */
> -static void transpose_and_flatten_matrices(u8 *output, const u8 *input,
> -					?? int matrices, int row_length)
> -{
> -	int i, j, row, x_offset, matrix_offset, rot_index, y_offset, matrix_size, new_value;
> -
> -	matrix_size = row_length * row_length;
> -	for (i = 0; i < matrices; i++) {
> -		row = 0;
> -		x_offset = 0;
> -		matrix_offset = i * matrix_size;
> -		for (j = 0; j < matrix_size; j++) {
> -			y_offset = j - (row * row_length);
> -			rot_index = y_offset * row_length + x_offset;
> -			new_value = *(input + i * matrix_size + j);
> -			output[matrix_offset + rot_index] = new_value;
> -			if ((j + 1) % row_length == 0) {
> -				row += 1;
> -				x_offset += 1;
> -			}
> -		}
> -	}
> -}
> -
> -static void assemble_scalingfactor0(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input)
> -{
> -	int offset = 0;
> -
> -	transpose_and_flatten_matrices(output, (const u8 *)input->scaling_list_4x4, 6, 4);
> -	offset = 6 * 16 * sizeof(u8);
> -	transpose_and_flatten_matrices(output + offset, (const u8 *)input->scaling_list_8x8, 6, 8);
> -	offset += 6 * 64 * sizeof(u8);
> -	transpose_and_flatten_matrices(output + offset,
> -				?????? (const u8 *)input->scaling_list_16x16, 6, 8);
> -	offset += 6 * 64 * sizeof(u8);
> -	/* Add a 128 byte padding with 0s between the two 32x32 matrices */
> -	transpose_and_flatten_matrices(output + offset,
> -				?????? (const u8 *)input->scaling_list_32x32, 1, 8);
> -	offset += 64 * sizeof(u8);
> -	memset(output + offset, 0, 128);
> -	offset += 128 * sizeof(u8);
> -	transpose_and_flatten_matrices(output + offset,
> -				?????? (const u8 *)input->scaling_list_32x32 + (64 * sizeof(u8)),
> -				?????? 1, 8);
> -	offset += 64 * sizeof(u8);
> -	memset(output + offset, 0, 128);
> -}
> -
> -/*
> - * Required layout:
> - * A = scaling_list_dc_coef_16x16
> - * B = scaling_list_dc_coef_32x32
> - * 0 = Padding
> - *
> - * A, A, A, A, A, A, B, 0, 0, B, 0, 0
> - */
> -static void assemble_scalingdc(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input)
> -{
> -	u8 list_32x32[6] = {0};
> -
> -	memcpy(output, input->scaling_list_dc_coef_16x16, 6 * sizeof(u8));
> -	list_32x32[0] = input->scaling_list_dc_coef_32x32[0];
> -	list_32x32[3] = input->scaling_list_dc_coef_32x32[1];
> -	memcpy(output + 6 * sizeof(u8), list_32x32, 6 * sizeof(u8));
> -}
> -
> -static void translate_scaling_list(struct scaling_factor *output,
> -				?? const struct v4l2_ctrl_hevc_scaling_matrix *input)
> -{
> -	assemble_scalingfactor0(output->scalingfactor0, input);
> -	memcpy(output->scalingfactor1, (const u8 *)input->scaling_list_4x4, 96);
> -	assemble_scalingdc(output->scalingdc, input);
> -	memset(output->reserved, 0, 4 * sizeof(u8));
> -}
> -
> -static void assemble_hw_scaling_list(struct rkvdec_ctx *ctx,
> -				???? struct rkvdec_hevc_run *run)
> -{
> -	const struct v4l2_ctrl_hevc_scaling_matrix *scaling = run->scaling_matrix;
> -	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
> -	struct rkvdec_hevc_priv_tbl *tbl = hevc_ctx->priv_tbl.cpu;
> -	u8 *dst;
> -
> -	if (!memcmp((void *)&hevc_ctx->scaling_matrix_cache, scaling,
> -		??? sizeof(struct v4l2_ctrl_hevc_scaling_matrix)))
> -		return;
> -
> -	dst = tbl->scaling_list;
> -	translate_scaling_list((struct scaling_factor *)dst, scaling);
> -
> -	memcpy((void *)&hevc_ctx->scaling_matrix_cache, scaling,
> -	?????? sizeof(struct v4l2_ctrl_hevc_scaling_matrix));
> -}
> -
> -static struct vb2_buffer *
> -get_ref_buf(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run,
> -	??? unsigned int dpb_idx)
> -{
> -	struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
> -	const struct v4l2_ctrl_hevc_decode_params *decode_params = run->decode_params;
> -	const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb;
> -	struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q;
> -	struct vb2_buffer *buf = NULL;
> -
> -	if (dpb_idx < decode_params->num_active_dpb_entries)
> -		buf = vb2_find_buffer(cap_q, dpb[dpb_idx].timestamp);
> -
> -	/*
> -	 * If a DPB entry is unused or invalid, the address of current destination
> -	 * buffer is returned.
> -	 */
> -	if (!buf)
> -		return &run->base.bufs.dst->vb2_buf;
> -
> -	return buf;
> -}
> -
> ?static void config_registers(struct rkvdec_ctx *ctx,
> ?			???? struct rkvdec_hevc_run *run)
> ?{
> @@ -644,63 +500,6 @@ static void config_registers(struct rkvdec_ctx *ctx,
> ?	rkvdec_memcpy_toio(rkvdec->regs, regs, MIN(sizeof(*regs), 4 * rkvdec->variant->num_regs));
> ?}
> ?
> -#define RKVDEC_HEVC_MAX_DEPTH_IN_BYTES		2
> -
> -static int rkvdec_hevc_adjust_fmt(struct rkvdec_ctx *ctx,
> -				? struct v4l2_format *f)
> -{
> -	struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp;
> -
> -	fmt->num_planes = 1;
> -	if (!fmt->plane_fmt[0].sizeimage)
> -		fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height *
> -					????? RKVDEC_HEVC_MAX_DEPTH_IN_BYTES;
> -	return 0;
> -}
> -
> -static enum rkvdec_image_fmt rkvdec_hevc_get_image_fmt(struct rkvdec_ctx *ctx,
> -						?????? struct v4l2_ctrl *ctrl)
> -{
> -	const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps;
> -
> -	if (ctrl->id != V4L2_CID_STATELESS_HEVC_SPS)
> -		return RKVDEC_IMG_FMT_ANY;
> -
> -	if (sps->bit_depth_luma_minus8 == 0) {
> -		if (sps->chroma_format_idc == 2)
> -			return RKVDEC_IMG_FMT_422_8BIT;
> -		else
> -			return RKVDEC_IMG_FMT_420_8BIT;
> -	} else if (sps->bit_depth_luma_minus8 == 2) {
> -		if (sps->chroma_format_idc == 2)
> -			return RKVDEC_IMG_FMT_422_10BIT;
> -		else
> -			return RKVDEC_IMG_FMT_420_10BIT;
> -	}
> -
> -	return RKVDEC_IMG_FMT_ANY;
> -}
> -
> -static int rkvdec_hevc_validate_sps(struct rkvdec_ctx *ctx,
> -				??? const struct v4l2_ctrl_hevc_sps *sps)
> -{
> -	if (sps->chroma_format_idc > 1)
> -		/* Only 4:0:0 and 4:2:0 are supported */
> -		return -EINVAL;
> -	if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
> -		/* Luma and chroma bit depth mismatch */
> -		return -EINVAL;
> -	if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2)
> -		/* Only 8-bit and 10-bit is supported */
> -		return -EINVAL;
> -
> -	if (sps->pic_width_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.width ||
> -	??? sps->pic_height_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.height)
> -		return -EINVAL;
> -
> -	return 0;
> -}
> -
> ?static int rkvdec_hevc_start(struct rkvdec_ctx *ctx)
> ?{
> ?	struct rkvdec_dev *rkvdec = ctx->dev;
> @@ -737,40 +536,18 @@ static void rkvdec_hevc_stop(struct rkvdec_ctx *ctx)
> ?	kfree(hevc_ctx);
> ?}
> ?
> -static void rkvdec_hevc_run_preamble(struct rkvdec_ctx *ctx,
> -				???? struct rkvdec_hevc_run *run)
> -{
> -	struct v4l2_ctrl *ctrl;
> -
> -	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> -			????? V4L2_CID_STATELESS_HEVC_DECODE_PARAMS);
> -	run->decode_params = ctrl ? ctrl->p_cur.p : NULL;
> -	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> -			????? V4L2_CID_STATELESS_HEVC_SLICE_PARAMS);
> -	run->slices_params = ctrl ? ctrl->p_cur.p : NULL;
> -	run->num_slices = ctrl ? ctrl->new_elems : 0;
> -	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> -			????? V4L2_CID_STATELESS_HEVC_SPS);
> -	run->sps = ctrl ? ctrl->p_cur.p : NULL;
> -	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> -			????? V4L2_CID_STATELESS_HEVC_PPS);
> -	run->pps = ctrl ? ctrl->p_cur.p : NULL;
> -	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> -			????? V4L2_CID_STATELESS_HEVC_SCALING_MATRIX);
> -	run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL;
> -
> -	rkvdec_run_preamble(ctx, &run->base);
> -}
> -
> ?static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
> ?{
> ?	struct rkvdec_dev *rkvdec = ctx->dev;
> ?	struct rkvdec_hevc_run run;
> +	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
> +	struct rkvdec_hevc_priv_tbl *tbl = hevc_ctx->priv_tbl.cpu;
> ?	u32 reg;
> ?
> ?	rkvdec_hevc_run_preamble(ctx, &run);
> ?
> -	assemble_hw_scaling_list(ctx, &run);
> +	rkvdec_hevc_assemble_hw_scaling_list(&run, &tbl->scaling_list,
> +					???? &hevc_ctx->scaling_matrix_cache);
> ?	assemble_hw_pps(ctx, &run);
> ?	assemble_sw_rps(ctx, &run);
> ?	config_registers(ctx, &run);
> @@ -795,14 +572,6 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
> ?	return 0;
> ?}
> ?
> -static int rkvdec_hevc_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
> -{
> -	if (ctrl->id == V4L2_CID_STATELESS_HEVC_SPS)
> -		return rkvdec_hevc_validate_sps(ctx, ctrl->p_new.p_hevc_sps);
> -
> -	return 0;
> -}
> -
> ?const struct rkvdec_coded_fmt_ops rkvdec_hevc_fmt_ops = {
> ?	.adjust_fmt = rkvdec_hevc_adjust_fmt,
> ?	.start = rkvdec_hevc_start,
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251210/82432653/attachment-0001.sig>

From ariel.dalessandro at collabora.com  Wed Dec 10 12:19:37 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Wed, 10 Dec 2025 17:19:37 -0300
Subject: [PATCH RFC v2 03/20] drm: Factor out common color_pipeline
 property initialization code
In-Reply-To: <3c24d55c-76d1-4ba4-9942-fd5d85f9daca@amd.com>
References: <20250917-mtk-post-blend-color-pipeline-v2-0-ac4471b44758@collabora.com>
 <20250917-mtk-post-blend-color-pipeline-v2-3-ac4471b44758@collabora.com>
 <3c24d55c-76d1-4ba4-9942-fd5d85f9daca@amd.com>
Message-ID: <052890e9-4e51-4181-9b88-ab1d4f407fb7@collabora.com>

Harry,

Following up on Nicolas' series.

On 9/29/25 5:53 AM, Harry Wentland wrote:
> 
> 
> On 2025-09-17 20:43, N?colas F. R. A. Prado wrote:
>> In preparation for sharing the initialization code for the color
>> pipeline property between pre- and post-blend color pipelines, factor
>> out the common initialization to a separate function.
>>
>> Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
>> ---
>> ? drivers/gpu/drm/drm_crtc.c????????? | 44 +++++++++++++++++++++++++++ 
>> ++++++++++
>> ? drivers/gpu/drm/drm_crtc_internal.h |? 5 +++++
>> ? drivers/gpu/drm/drm_plane.c???????? | 36 +++++-------------------------
>> ? 3 files changed, 54 insertions(+), 31 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
>> index 
>> 46655339003db2a1b43441434839e26f61d79b4e..94e60cffd29972aa979ac2f1932be7a6a97f3ada 100644
>> --- a/drivers/gpu/drm/drm_crtc.c
>> +++ b/drivers/gpu/drm/drm_crtc.c
>> @@ -959,3 +959,47 @@ bool drm_crtc_in_clone_mode(struct drm_crtc_state 
>> *crtc_state)
>> ????? return hweight32(crtc_state->encoder_mask) > 1;
>> ? }
>> ? EXPORT_SYMBOL(drm_crtc_in_clone_mode);
>> +
>> +struct drm_property *
>> +drm_common_create_color_pipeline_property(struct drm_device *dev, 
>> struct drm_mode_object *obj,
>> +????????????????????? const struct drm_prop_enum_list *pipelines,
>> +????????????????????? int num_pipelines)
> 
> All other functions I see in drm_crtc seem to be quite crtc
> specific. Would there be a better place to put this? Possibly
> a new file if nothing else seems to fit?
> 
> Not a blocker in any way, though.
Agreed. I think drivers/gpu/drm/drm_property.c would be a better place, 
as it contains functions to create the different types of drm_property 
already.

Will submit a proposal in v3.

Thanks,
Ariel

-- 
Ariel D'Alessandro
Software Engineer

Collabora Ltd.
Platinum Building, St John's Innovation Park, Cambridge CB4 0DS, UK 
Registered in England & Wales, no. 5513718



From lkp at intel.com  Wed Dec 10 12:21:58 2025
From: lkp at intel.com (kernel test robot)
Date: Thu, 11 Dec 2025 04:21:58 +0800
Subject: [PATCH v5 09/24] perf: arm_pmuv3: Keep out of guest counter
 partition
In-Reply-To: <20251209205121.1871534-10-coltonlewis@google.com>
References: <20251209205121.1871534-10-coltonlewis@google.com>
Message-ID: <202512110439.UXwb1Qh4-lkp@intel.com>

Hi Colton,

kernel test robot noticed the following build warnings:

[auto build test WARNING on ac3fd01e4c1efce8f2c054cdeb2ddd2fc0fb150d]

url:    https://github.com/intel-lab-lkp/linux/commits/Colton-Lewis/arm64-cpufeature-Add-cpucap-for-HPMN0/20251210-055309
base:   ac3fd01e4c1efce8f2c054cdeb2ddd2fc0fb150d
patch link:    https://lore.kernel.org/r/20251209205121.1871534-10-coltonlewis%40google.com
patch subject: [PATCH v5 09/24] perf: arm_pmuv3: Keep out of guest counter partition
config: arm64-defconfig (https://download.01.org/0day-ci/archive/20251211/202512110439.UXwb1Qh4-lkp at intel.com/config)
compiler: aarch64-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251211/202512110439.UXwb1Qh4-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512110439.UXwb1Qh4-lkp at intel.com/

All warnings (new ones prefixed by >>):

>> Warning: arch/arm64/kvm/pmu-direct.c:75 function parameter 'pmu' not described in 'kvm_pmu_guest_counter_mask'

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From nicolas.dufresne at collabora.com  Wed Dec 10 12:24:59 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Wed, 10 Dec 2025 15:24:59 -0500
Subject: [PATCH v4 08/15] media: rkvdec: Add generic configuration for
 variants
In-Reply-To: <20251022174508.284929-9-detlev.casanova@collabora.com>
References: <20251022174508.284929-1-detlev.casanova@collabora.com>
	 <20251022174508.284929-9-detlev.casanova@collabora.com>
Message-ID: <a6e8003768f9daa9303e1ee82bedd8c48d59afd2.camel@collabora.com>

Hi,

Le mercredi 22 octobre 2025 ? 13:45 -0400, Detlev Casanova a ?crit?:
> This is to prepare for adding new versions of the decoder and
> support specific formats and ops per version.
> 
> Different rkvdec_variant instances will be able to share generic
> decoder configs.
> 
> Tested-by: Diederik de Haas <didi.debian at cknow.org>? # Rock 5B
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
> ---
> ?.../media/platform/rockchip/rkvdec/rkvdec.c?? | 37 ++++++++++++-------
> ?.../media/platform/rockchip/rkvdec/rkvdec.h?? |? 6 +++
> ?2 files changed, 30 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> index 776149f871b0..a7af1e3fdebd 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> @@ -373,15 +373,16 @@ static bool rkvdec_is_capable(struct rkvdec_ctx *ctx, unsigned int capability)
> ?static const struct rkvdec_coded_fmt_desc *
> ?rkvdec_enum_coded_fmt_desc(struct rkvdec_ctx *ctx, int index)
> ?{
> +	const struct rkvdec_config *cfg = ctx->dev->variant->config;
> ?	int fmt_idx = -1;
> ?	unsigned int i;
> ?
> -	for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++) {
> -		if (!rkvdec_is_capable(ctx, rkvdec_coded_fmts[i].capability))
> +	for (i = 0; i < cfg->coded_fmts_num; i++) {
> +		if (!rkvdec_is_capable(ctx, cfg->coded_fmts[i].capability))
> ?			continue;
> ?		fmt_idx++;
> ?		if (index == fmt_idx)
> -			return &rkvdec_coded_fmts[i];
> +			return &cfg->coded_fmts[i];
> ?	}
> ?
> ?	return NULL;
> @@ -390,12 +391,13 @@ rkvdec_enum_coded_fmt_desc(struct rkvdec_ctx *ctx, int index)
> ?static const struct rkvdec_coded_fmt_desc *
> ?rkvdec_find_coded_fmt_desc(struct rkvdec_ctx *ctx, u32 fourcc)
> ?{
> +	const struct rkvdec_config *cfg = ctx->dev->variant->config;
> ?	unsigned int i;
> ?
> -	for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++) {
> -		if (rkvdec_is_capable(ctx, rkvdec_coded_fmts[i].capability) &&
> -		??? rkvdec_coded_fmts[i].fourcc == fourcc)
> -			return &rkvdec_coded_fmts[i];
> +	for (i = 0; i < cfg->coded_fmts_num; i++) {
> +		if (rkvdec_is_capable(ctx, cfg->coded_fmts[i].capability) &&
> +		??? cfg->coded_fmts[i].fourcc == fourcc)
> +			return &cfg->coded_fmts[i];
> ?	}
> ?
> ?	return NULL;
> @@ -1014,18 +1016,19 @@ static int rkvdec_add_ctrls(struct rkvdec_ctx *ctx,
> ?
> ?static int rkvdec_init_ctrls(struct rkvdec_ctx *ctx)
> ?{
> +	const struct rkvdec_config *cfg = ctx->dev->variant->config;
> ?	unsigned int i, nctrls = 0;
> ?	int ret;
> ?
> -	for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++)
> -		if (rkvdec_is_capable(ctx, rkvdec_coded_fmts[i].capability))
> -			nctrls += rkvdec_coded_fmts[i].ctrls->num_ctrls;
> +	for (i = 0; i < cfg->coded_fmts_num; i++)
> +		if (rkvdec_is_capable(ctx, cfg->coded_fmts[i].capability))
> +			nctrls += cfg->coded_fmts[i].ctrls->num_ctrls;
> ?
> ?	v4l2_ctrl_handler_init(&ctx->ctrl_hdl, nctrls);
> ?
> -	for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++) {
> -		if (rkvdec_is_capable(ctx, rkvdec_coded_fmts[i].capability)) {
> -			ret = rkvdec_add_ctrls(ctx, rkvdec_coded_fmts[i].ctrls);
> +	for (i = 0; i < cfg->coded_fmts_num; i++) {
> +		if (rkvdec_is_capable(ctx, cfg->coded_fmts[i].capability)) {
> +			ret = rkvdec_add_ctrls(ctx, cfg->coded_fmts[i].ctrls);
> ?			if (ret)
> ?				goto err_free_handler;
> ?		}
> @@ -1240,13 +1243,20 @@ static void rkvdec_watchdog_func(struct work_struct *work)
> ?	}
> ?}
> ?
> +static const struct rkvdec_config config_rkvdec = {
> +	.coded_fmts = rkvdec_coded_fmts,
> +	.coded_fmts_num = ARRAY_SIZE(rkvdec_coded_fmts),

No true preference, I would intuitively used a sentinel. In any case:

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> +};
> +
> ?static const struct rkvdec_variant rk3288_rkvdec_variant = {
> ?	.num_regs = 68,
> +	.config = &config_rkvdec,
> ?	.capabilities = RKVDEC_CAPABILITY_HEVC,
> ?};
> ?
> ?static const struct rkvdec_variant rk3328_rkvdec_variant = {
> ?	.num_regs = 109,
> +	.config = &config_rkvdec,
> ?	.capabilities = RKVDEC_CAPABILITY_HEVC |
> ?			RKVDEC_CAPABILITY_H264 |
> ?			RKVDEC_CAPABILITY_VP9,
> @@ -1255,6 +1265,7 @@ static const struct rkvdec_variant rk3328_rkvdec_variant = {
> ?
> ?static const struct rkvdec_variant rk3399_rkvdec_variant = {
> ?	.num_regs = 78,
> +	.config = &config_rkvdec,
> ?	.capabilities = RKVDEC_CAPABILITY_HEVC |
> ?			RKVDEC_CAPABILITY_H264 |
> ?			RKVDEC_CAPABILITY_VP9,
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> index f35f6e80ea2e..3b1cc511412e 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> @@ -71,6 +71,7 @@ vb2_to_rkvdec_decoded_buf(struct vb2_buffer *buf)
> ?
> ?struct rkvdec_variant {
> ?	unsigned int num_regs;
> +	const struct rkvdec_config *config;
> ?	unsigned int capabilities;
> ?	unsigned int quirks;
> ?};
> @@ -113,6 +114,11 @@ struct rkvdec_coded_fmt_desc {
> ?	unsigned int capability;
> ?};
> ?
> +struct rkvdec_config {
> +	const struct rkvdec_coded_fmt_desc *coded_fmts;
> +	size_t coded_fmts_num;
> +};
> +
> ?struct rkvdec_dev {
> ?	struct v4l2_device v4l2_dev;
> ?	struct media_device mdev;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251210/ea0c908f/attachment-0001.sig>

From nicolas.dufresne at collabora.com  Wed Dec 10 12:32:47 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Wed, 10 Dec 2025 15:32:47 -0500
Subject: [PATCH v4 09/15] media: rkvdec: Add RCB and SRAM support
In-Reply-To: <20251022174508.284929-10-detlev.casanova@collabora.com>
References: <20251022174508.284929-1-detlev.casanova@collabora.com>
	 <20251022174508.284929-10-detlev.casanova@collabora.com>
Message-ID: <47c0290d3dce59988d6db1fc8d8fb6d45f5e68ab.camel@collabora.com>

Le mercredi 22 octobre 2025 ? 13:45 -0400, Detlev Casanova a ?crit?:
> The RCB (Rows and Cols Buffers) are a set of buffers used by other
> variations of the decoder to store temporary data.
> 
> Those variation come with a dedicated SRAM area used to store those
> buffers for better performances.
> 
> The buffer sizes are either the width or height of the frame being
> decoded multiplied by a documented factor and can be stored either
> in SRAM or RAM.
> A fallback to RAM is provided if the SRAM is full (e.g.: multiple
> streams are being decoded at the same time).
> 
> To manage the different kind of allocation, an enum is added to the
> rkvdec_aux_buf struct to specify how the buffer was allocated, and
> so, how to free it.
> 
> This commit is in preparation of other variants support.
> 
> Tested-by: Diederik de Haas <didi.debian at cknow.org>? # Rock 5B
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
> ---
> ?.../media/platform/rockchip/rkvdec/Makefile?? |?? 1 +
> ?.../platform/rockchip/rkvdec/rkvdec-rcb.c???? | 173 ++++++++++++++++++
> ?.../platform/rockchip/rkvdec/rkvdec-rcb.h???? |? 29 +++
> ?.../media/platform/rockchip/rkvdec/rkvdec.c?? |? 27 ++-
> ?.../media/platform/rockchip/rkvdec/rkvdec.h?? |? 13 ++
> ?5 files changed, 241 insertions(+), 2 deletions(-)
> ?create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c
> ?create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
> index 1b4bc44be23e..3d75103e536d 100644
> --- a/drivers/media/platform/rockchip/rkvdec/Makefile
> +++ b/drivers/media/platform/rockchip/rkvdec/Makefile
> @@ -7,4 +7,5 @@ rockchip-vdec-y += \
> ?		?? rkvdec-h264-common.o \
> ?		?? rkvdec-hevc.o \
> ?		?? rkvdec-hevc-common.o \
> +		?? rkvdec-rcb.o \
> ?		?? rkvdec-vp9.o
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c
> new file mode 100644
> index 000000000000..5a4959c239e3
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c
> @@ -0,0 +1,173 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Rockchip video decoder Rows and Cols Buffers manager
> + *
> + * Copyright (C) 2025 Collabora, Ltd.
> + *? Detlev Casanova <detlev.casanova at collabora.com>
> + */
> +
> +#include "rkvdec.h"
> +#include "rkvdec-rcb.h"
> +
> +#include <linux/types.h>
> +#include <linux/iommu.h>
> +#include <linux/genalloc.h>
> +
> +struct rkvdec_rcb_config {
> +	struct rkvdec_aux_buf *rcb_bufs;
> +	size_t rcb_count;
> +};
> +
> +static size_t rkvdec_rcb_size(const struct rcb_size_info *size_info,
> +			????? unsigned int width, unsigned int height)
> +{
> +	return size_info->multiplier * (size_info->axis == PIC_HEIGHT ? height : width);
> +}
> +
> +dma_addr_t rkvdec_rcb_buf_dma_addr(struct rkvdec_ctx *ctx, int id)
> +{
> +	return ctx->rcb_config->rcb_bufs[id].dma;
> +}
> +
> +size_t rkvdec_rcb_buf_size(struct rkvdec_ctx *ctx, int id)
> +{
> +	return ctx->rcb_config->rcb_bufs[id].size;
> +}
> +
> +int rkvdec_rcb_buf_count(struct rkvdec_ctx *ctx)
> +{
> +	return ctx->rcb_config->rcb_count;
> +}
> +
> +void rkvdec_free_rcb(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_dev *dev = ctx->dev;
> +	struct rkvdec_rcb_config *cfg = ctx->rcb_config;
> +	unsigned long virt_addr;
> +	int i;
> +
> +	if (!cfg)
> +		return;
> +
> +	for (i = 0; i < cfg->rcb_count; i++) {
> +		size_t rcb_size = cfg->rcb_bufs[i].size;
> +
> +		if (!cfg->rcb_bufs[i].cpu)
> +			continue;
> +
> +		switch (cfg->rcb_bufs[i].type) {
> +		case RKVDEC_ALLOC_SRAM:
> +			virt_addr = (unsigned long)cfg->rcb_bufs[i].cpu;
> +
> +			if (dev->iommu_domain)
> +				iommu_unmap(dev->iommu_domain, virt_addr, rcb_size);
> +			gen_pool_free(dev->sram_pool, virt_addr, rcb_size);
> +			break;
> +		case RKVDEC_ALLOC_DMA:
> +			dma_free_coherent(dev->dev,
> +					? rcb_size,
> +					? cfg->rcb_bufs[i].cpu,
> +					? cfg->rcb_bufs[i].dma);
> +			break;
> +		}
> +	}
> +
> +	if (cfg->rcb_bufs)
> +		devm_kfree(dev->dev, cfg->rcb_bufs);
> +
> +	devm_kfree(dev->dev, cfg);
> +}
> +
> +int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx,
> +			const struct rcb_size_info *size_info,
> +			size_t rcb_count)
> +{
> +	int ret, i;
> +	u32 width, height;
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	struct rkvdec_rcb_config *cfg;
> +
> +	ctx->rcb_config = devm_kzalloc(rkvdec->dev, sizeof(*ctx->rcb_config), GFP_KERNEL);
> +	if (!ctx->rcb_config)
> +		return -ENOMEM;
> +
> +	cfg = ctx->rcb_config;
> +
> +	cfg->rcb_bufs = devm_kzalloc(rkvdec->dev, sizeof(*cfg->rcb_bufs) * rcb_count, GFP_KERNEL);
> +	if (!cfg->rcb_bufs) {
> +		ret = -ENOMEM;
> +		goto err_alloc;
> +	}
> +
> +	width = ctx->decoded_fmt.fmt.pix_mp.width;
> +	height = ctx->decoded_fmt.fmt.pix_mp.height;
> +
> +	for (i = 0; i < rcb_count; i++) {
> +		void *cpu = NULL;
> +		dma_addr_t dma;
> +		size_t rcb_size = rkvdec_rcb_size(&size_info[i], width, height);
> +		enum rkvdec_alloc_type alloc_type = RKVDEC_ALLOC_SRAM;
> +
> +		/* Try allocating an SRAM buffer */
> +		if (ctx->dev->sram_pool) {
> +			if (rkvdec->iommu_domain)
> +				rcb_size = ALIGN(rcb_size, 0x1000);
> +
> +			cpu = gen_pool_dma_zalloc_align(ctx->dev->sram_pool,
> +							rcb_size,
> +							&dma,
> +							0x1000);
> +		}
> +
> +		/* If an IOMMU is used, map the SRAM address through it */
> +		if (cpu && rkvdec->iommu_domain) {
> +			unsigned long virt_addr = (unsigned long)cpu;
> +			phys_addr_t phys_addr = dma;
> +
> +			ret = iommu_map(rkvdec->iommu_domain, virt_addr, phys_addr,
> +					rcb_size, IOMMU_READ | IOMMU_WRITE, 0);
> +			if (ret) {
> +				gen_pool_free(ctx->dev->sram_pool,
> +					????? (unsigned long)cpu,
> +					????? rcb_size);
> +				cpu = NULL;
> +				goto ram_fallback;
> +			}
> +
> +			/*
> +			 * The registers will be configured with the virtual
> +			 * address so that it goes through the IOMMU
> +			 */
> +			dma = virt_addr;
> +		}
> +
> +ram_fallback:
> +		/* Fallback to RAM */
> +		if (!cpu) {
> +			cpu = dma_alloc_coherent(ctx->dev->dev,

Some dev_dbg would be nice, looks like its going to run slower, so having a way
to detect it during integration would be helpful. Also, something to be checked
on RK3576, RK3566 and RK3568 were users seems to report that it runs fine, but
under perform.

> +						 rcb_size,
> +						 &dma,
> +						 GFP_KERNEL);
> +			alloc_type = RKVDEC_ALLOC_DMA;
> +		}
> +
> +		if (!cpu) {
> +			ret = -ENOMEM;
> +			goto err_alloc;
> +		}
> +
> +		cfg->rcb_bufs[i].cpu = cpu;
> +		cfg->rcb_bufs[i].dma = dma;
> +		cfg->rcb_bufs[i].size = rcb_size;
> +		cfg->rcb_bufs[i].type = alloc_type;
> +
> +		cfg->rcb_count += 1;
> +	}
> +
> +	return 0;
> +
> +err_alloc:
> +	rkvdec_free_rcb(ctx);
> +
> +	return ret;
> +}
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h
> new file mode 100644
> index 000000000000..30e8002555c8
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h
> @@ -0,0 +1,29 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Rockchip video decoder Rows and Cols Buffers manager
> + *
> + * Copyright (C) 2025 Collabora, Ltd.
> + *? Detlev Casanova <detlev.casanova at collabora.com>
> + */
> +
> +#include <linux/types.h>
> +
> +struct rkvdec_ctx;
> +
> +enum rcb_axis {
> +	PIC_WIDTH = 0,
> +	PIC_HEIGHT = 1
> +};
> +
> +struct rcb_size_info {
> +	u8 multiplier;
> +	enum rcb_axis axis;
> +};
> +
> +int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx,
> +			const struct rcb_size_info *size_info,
> +			size_t rcb_count);
> +dma_addr_t rkvdec_rcb_buf_dma_addr(struct rkvdec_ctx *ctx, int id);
> +size_t rkvdec_rcb_buf_size(struct rkvdec_ctx *ctx, int id);
> +int rkvdec_rcb_buf_count(struct rkvdec_ctx *ctx);
> +void rkvdec_free_rcb(struct rkvdec_ctx *ctx);
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> index a7af1e3fdebd..5dd486edd64d 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> @@ -10,6 +10,7 @@
> ? */
> ?
> ?#include <linux/clk.h>
> +#include <linux/genalloc.h>
> ?#include <linux/interrupt.h>
> ?#include <linux/iommu.h>
> ?#include <linux/module.h>
> @@ -28,6 +29,7 @@
> ?
> ?#include "rkvdec.h"
> ?#include "rkvdec-regs.h"
> +#include "rkvdec-rcb.h"
> ?
> ?static bool rkvdec_image_fmt_match(enum rkvdec_image_fmt fmt1,
> ?				?? enum rkvdec_image_fmt fmt2)
> @@ -771,6 +773,7 @@ static int rkvdec_start_streaming(struct vb2_queue *q, unsigned int count)
> ?{
> ?	struct rkvdec_ctx *ctx = vb2_get_drv_priv(q);
> ?	const struct rkvdec_coded_fmt_desc *desc;
> +	const struct rkvdec_config *cfg = ctx->dev->variant->config;
> ?	int ret;
> ?
> ?	if (V4L2_TYPE_IS_CAPTURE(q->type))
> @@ -780,13 +783,22 @@ static int rkvdec_start_streaming(struct vb2_queue *q, unsigned int count)
> ?	if (WARN_ON(!desc))
> ?		return -EINVAL;
> ?
> +	ret = rkvdec_allocate_rcb(ctx, cfg->rcb_size_info, cfg->rcb_num);

Shouldn't this be conditional ? I read your commit message as only new variants
needs that.

Nicolas

> +	if (ret)
> +		return ret;
> +
> ?	if (desc->ops->start) {
> ?		ret = desc->ops->start(ctx);
> ?		if (ret)
> -			return ret;
> +			goto err_ops_start;
> ?	}
> ?
> ?	return 0;
> +
> +err_ops_start:
> +	rkvdec_free_rcb(ctx);
> +
> +	return ret;
> ?}
> ?
> ?static void rkvdec_queue_cleanup(struct vb2_queue *vq, u32 state)
> @@ -822,6 +834,8 @@ static void rkvdec_stop_streaming(struct vb2_queue *q)
> ?
> ?		if (desc->ops->stop)
> ?			desc->ops->stop(ctx);
> +
> +		rkvdec_free_rcb(ctx);
> ?	}
> ?
> ?	rkvdec_queue_cleanup(q, VB2_BUF_STATE_ERROR);
> @@ -1350,6 +1364,10 @@ static int rkvdec_probe(struct platform_device *pdev)
> ?		return ret;
> ?	}
> ?
> +	rkvdec->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0);
> +	if (!rkvdec->sram_pool && rkvdec->variant->config->rcb_num > 0)
> +		dev_info(&pdev->dev, "No sram node, RCB will be stored in RAM\n");
> +
> ?	pm_runtime_set_autosuspend_delay(&pdev->dev, 100);
> ?	pm_runtime_use_autosuspend(&pdev->dev);
> ?	pm_runtime_enable(&pdev->dev);
> @@ -1358,7 +1376,8 @@ static int rkvdec_probe(struct platform_device *pdev)
> ?	if (ret)
> ?		goto err_disable_runtime_pm;
> ?
> -	if (iommu_get_domain_for_dev(&pdev->dev)) {
> +	rkvdec->iommu_domain = iommu_get_domain_for_dev(&pdev->dev);
> +	if (rkvdec->iommu_domain) {
> ?		rkvdec->empty_domain = iommu_paging_domain_alloc(rkvdec->dev);
> ?
> ?		if (IS_ERR(rkvdec->empty_domain)) {
> @@ -1372,6 +1391,10 @@ static int rkvdec_probe(struct platform_device *pdev)
> ?err_disable_runtime_pm:
> ?	pm_runtime_dont_use_autosuspend(&pdev->dev);
> ?	pm_runtime_disable(&pdev->dev);
> +
> +	if (rkvdec->sram_pool)
> +		gen_pool_destroy(rkvdec->sram_pool);
> +
> ?	return ret;
> ?}
> ?
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> index 3b1cc511412e..74f71542e031 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> @@ -19,6 +19,7 @@
> ?#include <media/v4l2-ctrls.h>
> ?#include <media/v4l2-device.h>
> ?#include <media/v4l2-ioctl.h>
> +#include <media/v4l2-mem2mem.h>
> ?#include <media/videobuf2-core.h>
> ?#include <media/videobuf2-dma-contig.h>
> ?
> @@ -29,6 +30,7 @@
> ?#define RKVDEC_QUIRK_DISABLE_QOS	BIT(0)
> ?
> ?struct rkvdec_ctx;
> +struct rkvdec_rcb_config;
> ?
> ?struct rkvdec_ctrl_desc {
> ?	struct v4l2_ctrl_config cfg;
> @@ -117,6 +119,8 @@ struct rkvdec_coded_fmt_desc {
> ?struct rkvdec_config {
> ?	const struct rkvdec_coded_fmt_desc *coded_fmts;
> ?	size_t coded_fmts_num;
> +	const struct rcb_size_info *rcb_size_info;
> +	size_t rcb_num;
> ?};
> ?
> ?struct rkvdec_dev {
> @@ -129,6 +133,8 @@ struct rkvdec_dev {
> ?	void __iomem *regs;
> ?	struct mutex vdev_lock; /* serializes ioctls */
> ?	struct delayed_work watchdog_work;
> +	struct gen_pool *sram_pool;
> +	struct iommu_domain *iommu_domain;
> ?	struct iommu_domain *empty_domain;
> ?	const struct rkvdec_variant *variant;
> ?};
> @@ -141,6 +147,7 @@ struct rkvdec_ctx {
> ?	struct v4l2_ctrl_handler ctrl_hdl;
> ?	struct rkvdec_dev *dev;
> ?	enum rkvdec_image_fmt image_fmt;
> +	struct rkvdec_rcb_config *rcb_config;
> ?	void *priv;
> ?};
> ?
> @@ -149,10 +156,16 @@ static inline struct rkvdec_ctx *file_to_rkvdec_ctx(struct file *filp)
> ?	return container_of(file_to_v4l2_fh(filp), struct rkvdec_ctx, fh);
> ?}
> ?
> +enum rkvdec_alloc_type {
> +	RKVDEC_ALLOC_DMA? = 0,
> +	RKVDEC_ALLOC_SRAM = 1,
> +};
> +
> ?struct rkvdec_aux_buf {
> ?	void *cpu;
> ?	dma_addr_t dma;
> ?	size_t size;
> +	enum rkvdec_alloc_type type;
> ?};
> ?
> ?void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run);
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251210/85fed465/attachment.sig>

From nicolas.dufresne at collabora.com  Wed Dec 10 12:35:19 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Wed, 10 Dec 2025 15:35:19 -0500
Subject: [PATCH v4 10/15] media: rkvdec: Support per-variant interrupt
 handler
In-Reply-To: <20251022174508.284929-11-detlev.casanova@collabora.com>
References: <20251022174508.284929-1-detlev.casanova@collabora.com>
	 <20251022174508.284929-11-detlev.casanova@collabora.com>
Message-ID: <4c66b55f96577cd615d114cb1b7482f5fc6a991a.camel@collabora.com>

Le mercredi 22 octobre 2025 ? 13:45 -0400, Detlev Casanova a ?crit?:
> Preparation commit for supporting different variants with different
> interrupt management.
> 
> Tested-by: Diederik de Haas <didi.debian at cknow.org>? # Rock 5B
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
> ---
> ?drivers/media/platform/rockchip/rkvdec/rkvdec.c | 15 ++++++++++++---
> ?drivers/media/platform/rockchip/rkvdec/rkvdec.h |? 1 +
> ?2 files changed, 13 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> index 5dd486edd64d..b0e90c9b826e 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> @@ -1218,10 +1218,9 @@ static void rkvdec_iommu_restore(struct rkvdec_dev *rkvdec)
> ?	}
> ?}
> ?
> -static irqreturn_t rkvdec_irq_handler(int irq, void *priv)
> +static irqreturn_t rk3399_irq_handler(struct rkvdec_ctx *ctx)
> ?{
> -	struct rkvdec_dev *rkvdec = priv;
> -	struct rkvdec_ctx *ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev);
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> ?	enum vb2_buffer_state state;
> ?	u32 status;
> ?
> @@ -1242,6 +1241,15 @@ static irqreturn_t rkvdec_irq_handler(int irq, void *priv)
> ?	return IRQ_HANDLED;
> ?}
> ?
> +static irqreturn_t rkvdec_irq_handler(int irq, void *priv)
> +{
> +	struct rkvdec_dev *rkvdec = priv;
> +	struct rkvdec_ctx *ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev);
> +	const struct rkvdec_config *cfg = rkvdec->variant->config;
> +
> +	return cfg->irq_handler(ctx);
> +}
> +
> ?static void rkvdec_watchdog_func(struct work_struct *work)
> ?{
> ?	struct rkvdec_dev *rkvdec;
> @@ -1260,6 +1268,7 @@ static void rkvdec_watchdog_func(struct work_struct *work)
> ?static const struct rkvdec_config config_rkvdec = {
> ?	.coded_fmts = rkvdec_coded_fmts,
> ?	.coded_fmts_num = ARRAY_SIZE(rkvdec_coded_fmts),
> +	.irq_handler = rk3399_irq_handler,
> ?};
> ?
> ?static const struct rkvdec_variant rk3288_rkvdec_variant = {
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> index 74f71542e031..dfafb2c2cbc1 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> @@ -121,6 +121,7 @@ struct rkvdec_config {
> ?	size_t coded_fmts_num;
> ?	const struct rcb_size_info *rcb_size_info;
> ?	size_t rcb_num;
> +	irqreturn_t (*irq_handler)(struct rkvdec_ctx *ctx);

Its a tiny little odd to mix function pointers and configuration. I don't have a
great proposal, is that going to be the only function pointer ? perhaps cg->ops
? I'm not sure. Its just a small annoyance, I'll leave to you.

Nicolas

> ?};
> ?
> ?struct rkvdec_dev {
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251210/dcd48f3a/attachment.sig>

From nicolas.dufresne at collabora.com  Wed Dec 10 12:36:09 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Wed, 10 Dec 2025 15:36:09 -0500
Subject: [PATCH v4 11/15] media: rkvdec: Enable all clocks without
 naming them
In-Reply-To: <20251022174508.284929-12-detlev.casanova@collabora.com>
References: <20251022174508.284929-1-detlev.casanova@collabora.com>
	 <20251022174508.284929-12-detlev.casanova@collabora.com>
Message-ID: <1ba983fd1b805bd18406e8d614bc9c72a109a0f9.camel@collabora.com>

Le mercredi 22 octobre 2025 ? 13:45 -0400, Detlev Casanova a ?crit?:
> For other variants, the clock names and number will differ.
> 
> There is no need to keep track of the clock names in the driver so drop
> them to avoid having a list for each variant.
> 
> Tested-by: Diederik de Haas <didi.debian at cknow.org>? # Rock 5B
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?.../media/platform/rockchip/rkvdec/rkvdec.c?? | 24 +++++--------------
> ?.../media/platform/rockchip/rkvdec/rkvdec.h?? |? 1 +
> ?2 files changed, 7 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> index b0e90c9b826e..aa92b586429e 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> @@ -1311,15 +1311,10 @@ static const struct of_device_id of_rkvdec_match[] = {
> ?};
> ?MODULE_DEVICE_TABLE(of, of_rkvdec_match);
> ?
> -static const char * const rkvdec_clk_names[] = {
> -	"axi", "ahb", "cabac", "core"
> -};
> -
> ?static int rkvdec_probe(struct platform_device *pdev)
> ?{
> ?	const struct rkvdec_variant *variant;
> ?	struct rkvdec_dev *rkvdec;
> -	unsigned int i;
> ?	int ret, irq;
> ?
> ?	variant = of_device_get_match_data(&pdev->dev);
> @@ -1336,19 +1331,12 @@ static int rkvdec_probe(struct platform_device *pdev)
> ?	mutex_init(&rkvdec->vdev_lock);
> ?	INIT_DELAYED_WORK(&rkvdec->watchdog_work, rkvdec_watchdog_func);
> ?
> -	rkvdec->clocks = devm_kcalloc(&pdev->dev, ARRAY_SIZE(rkvdec_clk_names),
> -				????? sizeof(*rkvdec->clocks), GFP_KERNEL);
> -	if (!rkvdec->clocks)
> -		return -ENOMEM;
> -
> -	for (i = 0; i < ARRAY_SIZE(rkvdec_clk_names); i++)
> -		rkvdec->clocks[i].id = rkvdec_clk_names[i];
> -
> -	ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(rkvdec_clk_names),
> -				rkvdec->clocks);
> -	if (ret)
> +	ret = devm_clk_bulk_get_all_enabled(&pdev->dev, &rkvdec->clocks);
> +	if (ret < 0)
> ?		return ret;
> ?
> +	rkvdec->clk_count = ret;
> +
> ?	rkvdec->regs = devm_platform_ioremap_resource(pdev, 0);
> ?	if (IS_ERR(rkvdec->regs))
> ?		return PTR_ERR(rkvdec->regs);
> @@ -1426,7 +1414,7 @@ static int rkvdec_runtime_resume(struct device *dev)
> ?{
> ?	struct rkvdec_dev *rkvdec = dev_get_drvdata(dev);
> ?
> -	return clk_bulk_prepare_enable(ARRAY_SIZE(rkvdec_clk_names),
> +	return clk_bulk_prepare_enable(rkvdec->clk_count,
> ?				?????? rkvdec->clocks);
> ?}
> ?
> @@ -1434,7 +1422,7 @@ static int rkvdec_runtime_suspend(struct device *dev)
> ?{
> ?	struct rkvdec_dev *rkvdec = dev_get_drvdata(dev);
> ?
> -	clk_bulk_disable_unprepare(ARRAY_SIZE(rkvdec_clk_names),
> +	clk_bulk_disable_unprepare(rkvdec->clk_count,
> ?				?? rkvdec->clocks);
> ?	return 0;
> ?}
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> index dfafb2c2cbc1..4094f92f8a44 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> @@ -131,6 +131,7 @@ struct rkvdec_dev {
> ?	struct v4l2_m2m_dev *m2m_dev;
> ?	struct device *dev;
> ?	struct clk_bulk_data *clocks;
> +	unsigned int clk_count;
> ?	void __iomem *regs;
> ?	struct mutex vdev_lock; /* serializes ioctls */
> ?	struct delayed_work watchdog_work;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251210/5c02f35e/attachment-0001.sig>

From nicolas.dufresne at collabora.com  Wed Dec 10 12:41:22 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Wed, 10 Dec 2025 15:41:22 -0500
Subject: [PATCH v4 12/15] media: rkvdec: Add H264 support for the
 VDPU381 variant
In-Reply-To: <20251022174508.284929-13-detlev.casanova@collabora.com>
References: <20251022174508.284929-1-detlev.casanova@collabora.com>
	 <20251022174508.284929-13-detlev.casanova@collabora.com>
Message-ID: <70f7b80702ab5ec36f17f3bbee05a4246804b593.camel@collabora.com>

Le mercredi 22 octobre 2025 ? 13:45 -0400, Detlev Casanova a ?crit?:
> This decoder variant is found in Rockchip RK3588 SoC family.
> 
> Like for rkvdec on rk3399, it supports the NV12, NV15, NV16 and NV20
> output formats and level up to 5.1.
> 
> The maximum width and height have been significantly increased
> supporting up to 65520 pixels for both.

Did you test the new maximums to make sure it does not explodes somewhere else ?

Nicolas

> 
> Also make sure to only expose the first core and ignore the other
> until mutli-core is supported.
> 
> Fluster score for JVT-AVC_V1 is 129/135.
> 
> Tested-by: Diederik de Haas <didi.debian at cknow.org>? # Rock 5B
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
> ---
> ?.../media/platform/rockchip/rkvdec/Makefile?? |?? 1 +
> ?.../rockchip/rkvdec/rkvdec-h264-common.h????? |?? 2 +
> ?.../rockchip/rkvdec/rkvdec-vdpu381-h264.c???? | 469 ++++++++++++++++++
> ?.../rockchip/rkvdec/rkvdec-vdpu381-regs.h???? | 427 ++++++++++++++++
> ?.../media/platform/rockchip/rkvdec/rkvdec.c?? | 131 +++++
> ?.../media/platform/rockchip/rkvdec/rkvdec.h?? |?? 4 +
> ?6 files changed, 1034 insertions(+)
> ?create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c
> ?create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
> index 3d75103e536d..7bfd95151e40 100644
> --- a/drivers/media/platform/rockchip/rkvdec/Makefile
> +++ b/drivers/media/platform/rockchip/rkvdec/Makefile
> @@ -8,4 +8,5 @@ rockchip-vdec-y += \
> ?		?? rkvdec-hevc.o \
> ?		?? rkvdec-hevc-common.o \
> ?		?? rkvdec-rcb.o \
> +		?? rkvdec-vdpu381-h264.o \
> ?		?? rkvdec-vp9.o
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h
> index aea346744e4c..3984740e6f42 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h
> @@ -68,6 +68,8 @@ struct rkvdec_rps {
> ?	u32 reserved1[66];
> ?} __packed;
> ?
> +extern const s8 rkvdec_h264_cabac_table[4][464][2];
> +
> ?void lookup_ref_buf_idx(struct rkvdec_ctx *ctx, struct rkvdec_h264_run *run);
> ?void assemble_hw_rps(struct v4l2_h264_reflist_builder *builder,
> ?		???? struct rkvdec_h264_run *run,
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c
> new file mode 100644
> index 000000000000..e65a56bc9c63
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c
> @@ -0,0 +1,469 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Rockchip VDPU381 Video Decoder H264 backend
> + *
> + * Copyright (C) 2024 Collabora, Ltd.
> + *? Detlev Casanova <detlev.casanova at collabora.com>
> + */
> +
> +#include <media/v4l2-h264.h>
> +#include <media/v4l2-mem2mem.h>
> +
> +#include "rkvdec.h"
> +#include "rkvdec-rcb.h"
> +#include "rkvdec-h264-common.h"
> +#include "rkvdec-vdpu381-regs.h"
> +
> +struct rkvdec_sps {
> +	u16 seq_parameter_set_id:			4;
> +	u16 profile_idc:				8;
> +	u16 constraint_set3_flag:			1;
> +	u16 chroma_format_idc:				2;
> +	u16 bit_depth_luma:				3;
> +	u16 bit_depth_chroma:				3;
> +	u16 qpprime_y_zero_transform_bypass_flag:	1;
> +	u16 log2_max_frame_num_minus4:			4;
> +	u16 max_num_ref_frames:				5;
> +	u16 pic_order_cnt_type:				2;
> +	u16 log2_max_pic_order_cnt_lsb_minus4:		4;
> +	u16 delta_pic_order_always_zero_flag:		1;
> +	u16 pic_width_in_mbs:				12;
> +	u16 pic_height_in_mbs:				12;
> +	u16 frame_mbs_only_flag:			1;
> +	u16 mb_adaptive_frame_field_flag:		1;
> +	u16 direct_8x8_inference_flag:			1;
> +	u16 mvc_extension_enable:			1;
> +	u16 num_views:					2;
> +
> +	u16 reserved_bits:				12;
> +	u16 reserved[11];
> +} __packed;
> +
> +struct rkvdec_pps {
> +	u16 pic_parameter_set_id:				8;
> +	u16 pps_seq_parameter_set_id:				5;
> +	u16 entropy_coding_mode_flag:				1;
> +	u16 bottom_field_pic_order_in_frame_present_flag:	1;
> +	u16 num_ref_idx_l0_default_active_minus1:		5;
> +	u16 num_ref_idx_l1_default_active_minus1:		5;
> +	u16 weighted_pred_flag:					1;
> +	u16 weighted_bipred_idc:				2;
> +	u16 pic_init_qp_minus26:				7;
> +	u16 pic_init_qs_minus26:				6;
> +	u16 chroma_qp_index_offset:				5;
> +	u16 deblocking_filter_control_present_flag:		1;
> +	u16 constrained_intra_pred_flag:			1;
> +	u16 redundant_pic_cnt_present:				1;
> +	u16 transform_8x8_mode_flag:				1;
> +	u16 second_chroma_qp_index_offset:			5;
> +	u16 scaling_list_enable_flag:				1;
> +	u32 scaling_list_address;
> +	u16 is_longterm;
> +
> +	u8 reserved[3];
> +} __packed;
> +
> +struct rkvdec_sps_pps {
> +	struct rkvdec_sps sps;
> +	struct rkvdec_pps pps;
> +} __packed;
> +
> +/* Data structure describing auxiliary buffer format. */
> +struct rkvdec_h264_priv_tbl {
> +	s8 cabac_table[4][464][2];
> +	struct rkvdec_h264_scaling_list scaling_list;
> +	struct rkvdec_sps_pps param_set[256];
> +	struct rkvdec_rps rps;
> +};
> +
> +struct rkvdec_h264_ctx {
> +	struct rkvdec_aux_buf priv_tbl;
> +	struct rkvdec_h264_reflists reflists;
> +	struct rkvdec_vdpu381_regs_h264 regs;
> +};
> +
> +static void assemble_hw_pps(struct rkvdec_ctx *ctx,
> +			??? struct rkvdec_h264_run *run)
> +{
> +	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
> +	const struct v4l2_ctrl_h264_sps *sps = run->sps;
> +	const struct v4l2_ctrl_h264_pps *pps = run->pps;
> +	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
> +	const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb;
> +	struct rkvdec_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu;
> +	struct rkvdec_sps_pps *hw_ps;
> +	dma_addr_t scaling_list_address;
> +	u32 scaling_distance;
> +	u32 i;
> +
> +	/*
> +	 * HW read the SPS/PPS information from PPS packet index by PPS id.
> +	 * offset from the base can be calculated by PPS_id * 32 (size per PPS
> +	 * packet unit). so the driver copy SPS/PPS information to the exact PPS
> +	 * packet unit for HW accessing.
> +	 */
> +	hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id];
> +	memset(hw_ps, 0, sizeof(*hw_ps));
> +
> +	/* write sps */
> +	hw_ps->sps.seq_parameter_set_id = sps->seq_parameter_set_id;
> +	hw_ps->sps.profile_idc = sps->profile_idc;
> +	hw_ps->sps.constraint_set3_flag = !!(sps->constraint_set_flags & (1 << 3));
> +	hw_ps->sps.chroma_format_idc = sps->chroma_format_idc;
> +	hw_ps->sps.bit_depth_luma = sps->bit_depth_luma_minus8;
> +	hw_ps->sps.bit_depth_chroma = sps->bit_depth_chroma_minus8;
> +	hw_ps->sps.qpprime_y_zero_transform_bypass_flag =
> +		!!(sps->flags & V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS);
> +	hw_ps->sps.log2_max_frame_num_minus4 = sps->log2_max_frame_num_minus4;
> +	hw_ps->sps.max_num_ref_frames = sps->max_num_ref_frames;
> +	hw_ps->sps.pic_order_cnt_type = sps->pic_order_cnt_type;
> +	hw_ps->sps.log2_max_pic_order_cnt_lsb_minus4 =
> +		sps->log2_max_pic_order_cnt_lsb_minus4;
> +	hw_ps->sps.delta_pic_order_always_zero_flag =
> +		!!(sps->flags & V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO);
> +	hw_ps->sps.mvc_extension_enable = 1;
> +	hw_ps->sps.num_views = 1;
> +
> +	/*
> +	 * Use the SPS values since they are already in macroblocks
> +	 * dimensions, height can be field height (halved) if
> +	 * V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY is not set and also it allows
> +	 * decoding smaller images into larger allocation which can be used
> +	 * to implementing SVC spatial layer support.
> +	 */
> +	hw_ps->sps.pic_width_in_mbs = sps->pic_width_in_mbs_minus1 + 1;
> +	hw_ps->sps.pic_height_in_mbs = sps->pic_height_in_map_units_minus1 + 1;
> +	hw_ps->sps.frame_mbs_only_flag =
> +		!!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY);
> +	hw_ps->sps.mb_adaptive_frame_field_flag =
> +		!!(sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD);
> +	hw_ps->sps.direct_8x8_inference_flag =
> +		!!(sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE);
> +
> +	/* write pps */
> +	hw_ps->pps.pic_parameter_set_id = pps->pic_parameter_set_id;
> +	hw_ps->pps.pps_seq_parameter_set_id = pps->seq_parameter_set_id;
> +	hw_ps->pps.entropy_coding_mode_flag =
> +		!!(pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE);
> +	hw_ps->pps.bottom_field_pic_order_in_frame_present_flag =
> +		!!(pps->flags & V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT);
> +	hw_ps->pps.num_ref_idx_l0_default_active_minus1 =
> +		pps->num_ref_idx_l0_default_active_minus1;
> +	hw_ps->pps.num_ref_idx_l1_default_active_minus1 =
> +		pps->num_ref_idx_l1_default_active_minus1;
> +	hw_ps->pps.weighted_pred_flag =
> +		!!(pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED);
> +	hw_ps->pps.weighted_bipred_idc = pps->weighted_bipred_idc;
> +	hw_ps->pps.pic_init_qp_minus26 = pps->pic_init_qp_minus26;
> +	hw_ps->pps.pic_init_qs_minus26 = pps->pic_init_qs_minus26;
> +	hw_ps->pps.chroma_qp_index_offset = pps->chroma_qp_index_offset;
> +	hw_ps->pps.deblocking_filter_control_present_flag =
> +		!!(pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT);
> +	hw_ps->pps.constrained_intra_pred_flag =
> +		!!(pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED);
> +	hw_ps->pps.redundant_pic_cnt_present =
> +		!!(pps->flags & V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT);
> +	hw_ps->pps.transform_8x8_mode_flag =
> +		!!(pps->flags & V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE);
> +	hw_ps->pps.second_chroma_qp_index_offset = pps->second_chroma_qp_index_offset;
> +	hw_ps->pps.scaling_list_enable_flag =
> +		!!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT);
> +
> +	/*
> +	 * To be on the safe side, program the scaling matrix address
> +	 */
> +	scaling_distance = offsetof(struct rkvdec_h264_priv_tbl, scaling_list);
> +	scaling_list_address = h264_ctx->priv_tbl.dma + scaling_distance;
> +	hw_ps->pps.scaling_list_address = scaling_list_address;
> +
> +	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
> +		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
> +			hw_ps->pps.is_longterm |= (1 << i);
> +	}
> +}
> +
> +static void rkvdec_write_regs(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
> +
> +	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_REGS,
> +			?? &h264_ctx->regs.common,
> +			?? sizeof(h264_ctx->regs.common));
> +	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_PARAMS_REGS,
> +			?? &h264_ctx->regs.h264_param,
> +			?? sizeof(h264_ctx->regs.h264_param));
> +	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_ADDR_REGS,
> +			?? &h264_ctx->regs.common_addr,
> +			?? sizeof(h264_ctx->regs.common_addr));
> +	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_ADDR_REGS,
> +			?? &h264_ctx->regs.h264_addr,
> +			?? sizeof(h264_ctx->regs.h264_addr));
> +	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_POC_HIGHBIT_REGS,
> +			?? &h264_ctx->regs.h264_highpoc,
> +			?? sizeof(h264_ctx->regs.h264_highpoc));
> +}
> +
> +static void config_registers(struct rkvdec_ctx *ctx,
> +			???? struct rkvdec_h264_run *run)
> +{
> +	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
> +	const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb;
> +	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
> +	dma_addr_t priv_start_addr = h264_ctx->priv_tbl.dma;
> +	const struct v4l2_pix_format_mplane *dst_fmt;
> +	struct vb2_v4l2_buffer *src_buf = run->base.bufs.src;
> +	struct vb2_v4l2_buffer *dst_buf = run->base.bufs.dst;
> +	struct rkvdec_vdpu381_regs_h264 *regs = &h264_ctx->regs;
> +	const struct v4l2_format *f;
> +	dma_addr_t rlc_addr;
> +	dma_addr_t dst_addr;
> +	u32 hor_virstride;
> +	u32 ver_virstride;
> +	u32 y_virstride;
> +	u32 offset;
> +	u32 pixels;
> +	u32 i;
> +
> +	memset(regs, 0, sizeof(*regs));
> +
> +	/* Set H264 mode */
> +	regs->common.reg009.dec_mode = VDPU381_MODE_H264;
> +
> +	/* Set config */
> +	regs->common.reg011.buf_empty_en = 1;
> +	regs->common.reg011.dec_clkgate_e = 1;
> +	regs->common.reg011.dec_timeout_e = 1;
> +	regs->common.reg011.pix_range_detection_e = 1;
> +
> +	/*
> +	 * Even though the scan list address can be set in RPS,
> +	 * with some frames, it will try to use the address set in the register.
> +	 */
> +	regs->common.reg012.scanlist_addr_valid_en = 1;
> +
> +	/* Set IDR flag */
> +	regs->common.reg013.cur_pic_is_idr =
> +		!!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC);
> +
> +	/* Set input stream length */
> +	regs->common.stream_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
> +
> +	/* Set max slice number */
> +	regs->common.reg017.slice_num = MAX_SLICE_NUMBER;
> +
> +	/* Set strides */
> +	f = &ctx->decoded_fmt;
> +	dst_fmt = &f->fmt.pix_mp;
> +	hor_virstride = dst_fmt->plane_fmt[0].bytesperline;
> +	ver_virstride = dst_fmt->height;
> +	y_virstride = hor_virstride * ver_virstride;
> +
> +	pixels = dst_fmt->height * dst_fmt->width;
> +
> +	regs->common.reg018.y_hor_virstride = hor_virstride / 16;
> +	regs->common.reg019.uv_hor_virstride = hor_virstride / 16;
> +	regs->common.reg020.y_virstride = y_virstride / 16;
> +
> +	/* Activate block gating */
> +	regs->common.reg026.swreg_block_gating_e = 0xfffef;
> +	regs->common.reg026.reg_cfg_gating_en = 1;
> +
> +	/* Set timeout threshold */
> +	if (pixels < RKVDEC_1080P_PIXELS)
> +		regs->common.timeout_threshold = RKVDEC_TIMEOUT_1080p;
> +	else if (pixels < RKVDEC_4K_PIXELS)
> +		regs->common.timeout_threshold = RKVDEC_TIMEOUT_4K;
> +	else if (pixels < RKVDEC_8K_PIXELS)
> +		regs->common.timeout_threshold = RKVDEC_TIMEOUT_8K;
> +	else
> +		regs->common.timeout_threshold = RKVDEC_TIMEOUT_MAX;
> +
> +	/* Set TOP and BOTTOM POCs */
> +	regs->h264_param.cur_top_poc = dec_params->top_field_order_cnt;
> +	regs->h264_param.cur_bot_poc = dec_params->bottom_field_order_cnt;
> +
> +	/* Set ref pic address & poc */
> +	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
> +		struct vb2_buffer *vb_buf = run->ref_buf[i];
> +		dma_addr_t buf_dma;
> +
> +		/*
> +		 * If a DPB entry is unused or invalid, address of current destination
> +		 * buffer is returned.
> +		 */
> +		if (!vb_buf)
> +			vb_buf = &dst_buf->vb2_buf;
> +
> +		buf_dma = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
> +
> +		/* Set reference addresses */
> +		regs->h264_addr.ref_base[i] = buf_dma;
> +
> +		/* Set COLMV addresses */
> +		regs->h264_addr.colmv_base[i] = buf_dma + ctx->colmv_offset;
> +
> +		struct rkvdec_vdpu381_h264_ref_info *ref_info =
> +			&regs->h264_param.ref_info_regs[i / 4].ref_info[i % 4];
> +
> +		ref_info->ref_field =
> +			!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD);
> +		ref_info->ref_colmv_use_flag =
> +			!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE);
> +		ref_info->ref_topfield_used =
> +			!!(dpb[i].fields & V4L2_H264_TOP_FIELD_REF);
> +		ref_info->ref_botfield_used =
> +			!!(dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF);
> +
> +		regs->h264_param.ref_pocs[i * 2] =
> +			dpb[i].top_field_order_cnt;
> +		regs->h264_param.ref_pocs[i * 2 + 1] =
> +			dpb[i].bottom_field_order_cnt;
> +	}
> +
> +	/* Set rlc base address (input stream) */
> +	rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
> +	regs->common_addr.rlc_base = rlc_addr;
> +	regs->common_addr.rlcwrite_base = rlc_addr;
> +
> +	/* Set output base address */
> +	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
> +	regs->common_addr.decout_base = dst_addr;
> +	regs->common_addr.error_ref_base = dst_addr;
> +
> +	/* Set colmv address */
> +	regs->common_addr.colmv_cur_base = dst_addr + ctx->colmv_offset;
> +
> +	/* Set RCB addresses */
> +	for (i = 0; i < rkvdec_rcb_buf_count(ctx); i++)
> +		regs->common_addr.rcb_base[i] = rkvdec_rcb_buf_dma_addr(ctx, i);
> +
> +	/* Set hw pps address */
> +	offset = offsetof(struct rkvdec_h264_priv_tbl, param_set);
> +	regs->h264_addr.pps_base = priv_start_addr + offset;
> +
> +	/* Set hw rps address */
> +	offset = offsetof(struct rkvdec_h264_priv_tbl, rps);
> +	regs->h264_addr.rps_base = priv_start_addr + offset;
> +
> +	/* Set cabac table */
> +	offset = offsetof(struct rkvdec_h264_priv_tbl, cabac_table);
> +	regs->h264_addr.cabactbl_base = priv_start_addr + offset;
> +
> +	offset = offsetof(struct rkvdec_h264_priv_tbl, scaling_list);
> +	regs->h264_addr.scanlist_addr = priv_start_addr + offset;
> +
> +	rkvdec_write_regs(ctx);
> +}
> +
> +static int rkvdec_h264_start(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	struct rkvdec_h264_priv_tbl *priv_tbl;
> +	struct rkvdec_h264_ctx *h264_ctx;
> +	struct v4l2_ctrl *ctrl;
> +	int ret;
> +
> +	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> +			????? V4L2_CID_STATELESS_H264_SPS);
> +	if (!ctrl)
> +		return -EINVAL;
> +
> +	ret = rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps);
> +	if (ret)
> +		return ret;
> +
> +	h264_ctx = kzalloc(sizeof(*h264_ctx), GFP_KERNEL);
> +	if (!h264_ctx)
> +		return -ENOMEM;
> +
> +	priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl),
> +				????? &h264_ctx->priv_tbl.dma, GFP_KERNEL);
> +	if (!priv_tbl) {
> +		ret = -ENOMEM;
> +		goto err_free_ctx;
> +	}
> +
> +	h264_ctx->priv_tbl.size = sizeof(*priv_tbl);
> +	h264_ctx->priv_tbl.cpu = priv_tbl;
> +	memcpy(priv_tbl->cabac_table, rkvdec_h264_cabac_table,
> +	?????? sizeof(rkvdec_h264_cabac_table));
> +
> +	ctx->priv = h264_ctx;
> +	return 0;
> +
> +err_free_ctx:
> +	kfree(h264_ctx);
> +	return ret;
> +}
> +
> +static void rkvdec_h264_stop(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +
> +	dma_free_coherent(rkvdec->dev, h264_ctx->priv_tbl.size,
> +			? h264_ctx->priv_tbl.cpu, h264_ctx->priv_tbl.dma);
> +	kfree(h264_ctx);
> +}
> +
> +static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
> +{
> +	struct v4l2_h264_reflist_builder reflist_builder;
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
> +	struct rkvdec_h264_priv_tbl *tbl = h264_ctx->priv_tbl.cpu;
> +	struct rkvdec_h264_run run;
> +	u32 watchdog_time;
> +
> +	rkvdec_h264_run_preamble(ctx, &run);
> +
> +	/* Build the P/B{0,1} ref lists. */
> +	v4l2_h264_init_reflist_builder(&reflist_builder, run.decode_params,
> +				?????? run.sps, run.decode_params->dpb);
> +	v4l2_h264_build_p_ref_list(&reflist_builder, h264_ctx->reflists.p);
> +	v4l2_h264_build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0,
> +				??? h264_ctx->reflists.b1);
> +
> +	assemble_hw_scaling_list(&run, &tbl->scaling_list);
> +	assemble_hw_pps(ctx, &run);
> +	lookup_ref_buf_idx(ctx, &run);
> +	assemble_hw_rps(&reflist_builder, &run, &h264_ctx->reflists, &tbl->rps);
> +
> +	config_registers(ctx, &run);
> +
> +	rkvdec_run_postamble(ctx, &run.base);
> +
> +	/* Set watchdog at 2 times the hardware timeout threshold */
> +	u64 timeout_threshold = h264_ctx->regs.common.timeout_threshold;
> +	unsigned long axi_rate = clk_get_rate(rkvdec->axi_clk);
> +
> +	if (axi_rate)
> +		watchdog_time = 2 * (1000 * timeout_threshold) / axi_rate;
> +	else
> +		watchdog_time = 2000;
> +	schedule_delayed_work(&rkvdec->watchdog_work,
> +			????? msecs_to_jiffies(watchdog_time));
> +
> +	/* Start decoding! */
> +	writel(VDPU381_DEC_E_BIT, rkvdec->regs + VDPU381_REG_DEC_E);
> +
> +	return 0;
> +}
> +
> +static int rkvdec_h264_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
> +{
> +	if (ctrl->id == V4L2_CID_STATELESS_H264_SPS)
> +		return rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps);
> +
> +	return 0;
> +}
> +
> +const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_h264_fmt_ops = {
> +	.adjust_fmt = rkvdec_h264_adjust_fmt,
> +	.get_image_fmt = rkvdec_h264_get_image_fmt,
> +	.start = rkvdec_h264_start,
> +	.stop = rkvdec_h264_stop,
> +	.run = rkvdec_h264_run,
> +	.try_ctrl = rkvdec_h264_try_ctrl,
> +};
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h
> new file mode 100644
> index 000000000000..11b545e9ee7e
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h
> @@ -0,0 +1,427 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Rockchip VDPU381 Video Decoder driver registers description
> + *
> + * Copyright (C) 2024 Collabora, Ltd.
> + *? Detlev Casanova <detlev.casanova at collabora.com>
> + */
> +
> +#include <linux/types.h>
> +
> +#ifndef _RKVDEC_REGS_H_
> +#define _RKVDEC_REGS_H_
> +
> +#define OFFSET_COMMON_REGS		(8 * sizeof(u32))
> +#define OFFSET_CODEC_PARAMS_REGS	(64 * sizeof(u32))
> +#define OFFSET_COMMON_ADDR_REGS		(128 * sizeof(u32))
> +#define OFFSET_CODEC_ADDR_REGS		(160 * sizeof(u32))
> +#define OFFSET_POC_HIGHBIT_REGS		(200 * sizeof(u32))
> +
> +#define VDPU381_MODE_HEVC	0
> +#define VDPU381_MODE_H264	1
> +#define VDPU381_MODE_VP9	2
> +#define VDPU381_MODE_AVS2	3
> +
> +#define MAX_SLICE_NUMBER	0x3fff
> +
> +#define RKVDEC_1080P_PIXELS		(1920 * 1080)
> +#define RKVDEC_4K_PIXELS		(4096 * 2304)
> +#define RKVDEC_8K_PIXELS		(7680 * 4320)
> +#define RKVDEC_TIMEOUT_1080p		(0xefffff)
> +#define RKVDEC_TIMEOUT_4K		(0x2cfffff)
> +#define RKVDEC_TIMEOUT_8K		(0x4ffffff)
> +#define RKVDEC_TIMEOUT_MAX		(0xffffffff)
> +
> +#define VDPU381_REG_DEC_E		0x028
> +#define VDPU381_DEC_E_BIT		1
> +
> +#define VDPU381_REG_IMPORTANT_EN	0x02c
> +#define VDPU381_DEC_IRQ_DISABLE	BIT(4)
> +
> +#define VDPU381_REG_STA_INT		0x380
> +#define VDPU381_STA_INT_DEC_RDY_STA	BIT(2)
> +#define VDPU381_STA_INT_ERROR		BIT(4)
> +#define VDPU381_STA_INT_TIMEOUT		BIT(5)
> +#define VDPU381_STA_INT_SOFTRESET_RDY	BIT(9)
> +
> +/* base: OFFSET_COMMON_REGS */
> +struct rkvdec_vdpu381_regs_common {
> +	struct rkvdec_vdpu381_in_out {
> +		u32 in_endian		: 1;
> +		u32 in_swap32_e		: 1;
> +		u32 in_swap64_e		: 1;
> +		u32 str_endian		: 1;
> +		u32 str_swap32_e	: 1;
> +		u32 str_swap64_e	: 1;
> +		u32 out_endian		: 1;
> +		u32 out_swap32_e	: 1;
> +		u32 out_cbcr_swap	: 1;
> +		u32 out_swap64_e	: 1;
> +		u32 reserved		: 22;
> +	} reg008;
> +
> +	struct rkvdec_vdpu381_dec_mode {
> +		u32 dec_mode	: 10;
> +		u32 reserved	: 22;
> +	} reg009;
> +
> +	struct rkvdec_vdpu381_dec_e {
> +		u32 dec_e	: 1;
> +		u32 reserved	: 31;
> +	} reg010;
> +
> +	struct rkvdec_vdpu381_important_en {
> +		u32 reserved			: 1;
> +		u32 dec_clkgate_e		: 1;
> +		u32 dec_e_strmd_clkgate_dis	: 1;
> +		u32 reserved0			: 1;
> +
> +		u32 dec_irq_dis			: 1;
> +		u32 dec_timeout_e		: 1;
> +		u32 buf_empty_en		: 1;
> +		u32 reserved1			: 3;
> +
> +		u32 dec_e_rewrite_valid		: 1;
> +		u32 reserved2			: 9;
> +		u32 softrst_en_p		: 1;
> +		u32 force_softreset_valid	: 1;
> +		u32 reserved3			: 2;
> +		u32 pix_range_detection_e	: 1;
> +		u32 reserved4			: 7;
> +	} reg011;
> +
> +	struct rkvdec_vdpu381_sencodary_en {
> +		u32 wr_ddr_align_en		: 1;
> +		u32 colmv_compress_en		: 1;
> +		u32 fbc_e			: 1;
> +		u32 reserved0			: 1;
> +
> +		u32 buspr_slot_disable		: 1;
> +		u32 error_info_en		: 1;
> +		u32 info_collect_en		: 1;
> +		u32 wait_reset_en		: 1;
> +
> +		u32 scanlist_addr_valid_en	: 1;
> +		u32 scale_down_en		: 1;
> +		u32 error_cfg_wr_disable	: 1;
> +		u32 reserved1			: 21;
> +	} reg012;
> +
> +	struct rkvdec_vdpu381_en_mode_set {
> +		u32 timeout_mode		: 1;
> +		u32 req_timeout_rst_sel		: 1;
> +		u32 reserved0			: 1;
> +		u32 dec_commonirq_mode		: 1;
> +		u32 reserved1			: 2;
> +		u32 stmerror_waitdecfifo_empty	: 1;
> +		u32 reserved2			: 2;
> +		u32 h26x_streamd_error_mode	: 1;
> +		u32 reserved3			: 2;
> +		u32 allow_not_wr_unref_bframe	: 1;
> +		u32 fbc_output_wr_disable	: 1;
> +		u32 reserved4			: 1;
> +		u32 colmv_error_mode		: 1;
> +
> +		u32 reserved5			: 2;
> +		u32 h26x_error_mode		: 1;
> +		u32 reserved6			: 2;
> +		u32 ycacherd_prior		: 1;
> +		u32 reserved7			: 2;
> +		u32 cur_pic_is_idr		: 1;
> +		u32 reserved8			: 1;
> +		u32 right_auto_rst_disable	: 1;
> +		u32 frame_end_err_rst_flag	: 1;
> +		u32 rd_prior_mode		: 1;
> +		u32 rd_ctrl_prior_mode		: 1;
> +		u32 reserved9			: 1;
> +		u32 filter_outbuf_mode		: 1;
> +	} reg013;
> +
> +	struct rkvdec_vdpu381_fbc_param_set {
> +		u32 fbc_force_uncompress	: 1;
> +
> +		u32 reserved0			: 2;
> +		u32 allow_16x8_cp_flag		: 1;
> +		u32 reserved1			: 2;
> +
> +		u32 fbc_h264_exten_4or8_flag	: 1;
> +		u32 reserved2			: 25;
> +	} reg014;
> +
> +	struct rkvdec_vdpu381_stream_param_set {
> +		u32 rlc_mode_direct_write	: 1;
> +		u32 rlc_mode			: 1;
> +		u32 reserved0			: 3;
> +
> +		u32 strm_start_bit		: 7;
> +		u32 reserved1			: 20;
> +	} reg015;
> +
> +	u32 stream_len;
> +
> +	struct rkvdec_vdpu381_slice_number {
> +		u32 slice_num	: 25;
> +		u32 reserved	: 7;
> +	} reg017;
> +
> +	struct rkvdec_vdpu381_y_hor_stride {
> +		u32 y_hor_virstride	: 16;
> +		u32 reserved		: 16;
> +	} reg018;
> +
> +	struct rkvdec_vdpu381_uv_hor_stride {
> +		u32 uv_hor_virstride	: 16;
> +		u32 reserved		: 16;
> +	} reg019;
> +
> +	struct rkvdec_vdpu381_y_stride {
> +		u32 y_virstride		: 28;
> +		u32 reserved		: 4;
> +	} reg020;
> +
> +	struct rkvdec_vdpu381_error_ctrl_set {
> +		u32 inter_error_prc_mode		: 1;
> +		u32 error_intra_mode			: 1;
> +		u32 error_deb_en			: 1;
> +		u32 picidx_replace			: 5;
> +		u32 error_spread_e			: 1;
> +		u32 reserved0				: 3;
> +		u32 error_inter_pred_cross_slice	: 1;
> +		u32 reserved1				: 11;
> +		u32 roi_error_ctu_cal_en		: 1;
> +		u32 reserved2				: 7;
> +	} reg021;
> +
> +	struct rkvdec_vdpu381_err_roi_ctu_offset_start {
> +		u32 roi_x_ctu_offset_st	: 12;
> +		u32 reserved0		: 4;
> +		u32 roi_y_ctu_offset_st	: 12;
> +		u32 reserved1		: 4;
> +	} reg022;
> +
> +	struct rkvdec_vdpu381_err_roi_ctu_offset_end {
> +		u32 roi_x_ctu_offset_end	: 12;
> +		u32 reserved0			: 4;
> +		u32 roi_y_ctu_offset_end	: 12;
> +		u32 reserved1			: 4;
> +	} reg023;
> +
> +	struct rkvdec_vdpu381_cabac_error_en_lowbits {
> +		u32 cabac_err_en_lowbits	: 32;
> +	} reg024;
> +
> +	struct rkvdec_vdpu381_cabac_error_en_highbits {
> +		u32 cabac_err_en_highbits	: 30;
> +		u32 reserved			: 2;
> +	} reg025;
> +
> +	struct rkvdec_vdpu381_block_gating_en {
> +		u32 swreg_block_gating_e	: 20;
> +		u32 reserved			: 11;
> +		u32 reg_cfg_gating_en		: 1;
> +	} reg026;
> +
> +	struct SW027_CORE_SAFE_PIXELS {
> +		u32 core_safe_x_pixels	: 16;
> +		u32 core_safe_y_pixels	: 16;
> +	} reg027;
> +
> +	struct rkvdec_vdpu381_multiply_core_ctrl {
> +		u32 swreg_vp9_wr_prob_idx	: 3;
> +		u32 reserved0			: 1;
> +		u32 swreg_vp9_rd_prob_idx	: 3;
> +		u32 reserved1			: 1;
> +
> +		u32 swreg_ref_req_advance_flag	: 1;
> +		u32 sw_colmv_req_advance_flag	: 1;
> +		u32 sw_poc_only_highbit_flag	: 1;
> +		u32 sw_poc_arb_flag		: 1;
> +
> +		u32 reserved2			: 4;
> +		u32 sw_film_idx			: 10;
> +		u32 reserved3			: 2;
> +		u32 sw_pu_req_mismatch_dis	: 1;
> +		u32 sw_colmv_req_mismatch_dis	: 1;
> +		u32 reserved4			: 2;
> +	} reg028;
> +
> +	struct SW029_SCALE_DOWN_CTRL {
> +		u32 scale_down_hor_ratio	: 2;
> +		u32 reserved0			: 6;
> +		u32 scale_down_vrz_ratio	: 2;
> +		u32 reserved1			: 22;
> +	} reg029;
> +
> +	struct SW032_Y_SCALE_DOWN_TILE8x8_HOR_STRIDE {
> +		u32 y_scale_down_hor_stride	: 20;
> +		u32 reserved0			: 12;
> +	} reg030;
> +
> +	struct SW031_UV_SCALE_DOWN_TILE8x8_HOR_STRIDE {
> +		u32 uv_scale_down_hor_stride	: 20;
> +		u32 reserved0			: 12;
> +	} reg031;
> +
> +	u32 timeout_threshold;
> +} __packed;
> +
> +/* base: OFFSET_COMMON_ADDR_REGS */
> +struct rkvdec_vdpu381_regs_common_addr {
> +	u32 rlc_base;
> +	u32 rlcwrite_base;
> +	u32 decout_base;
> +	u32 colmv_cur_base;
> +	u32 error_ref_base;
> +	u32 rcb_base[10];
> +} __packed;
> +
> +struct rkvdec_vdpu381_h26x_set {
> +	u32 h26x_frame_orslice		: 1;
> +	u32 h26x_rps_mode		: 1;
> +	u32 h26x_stream_mode		: 1;
> +	u32 h26x_stream_lastpacket	: 1;
> +	u32 h264_firstslice_flag	: 1;
> +	u32 reserved			: 27;
> +} __packed;
> +
> +/* base: OFFSET_CODEC_PARAMS_REGS */
> +struct rkvdec_vdpu381_regs_h264_params {
> +	struct rkvdec_vdpu381_h26x_set reg064;
> +
> +	u32 cur_top_poc;
> +	u32 cur_bot_poc;
> +	u32 ref_pocs[32];
> +
> +	struct rkvdec_vdpu381_h264_info {
> +		struct rkvdec_vdpu381_h264_ref_info {
> +			u32 ref_field		: 1;
> +			u32 ref_topfield_used	: 1;
> +			u32 ref_botfield_used	: 1;
> +			u32 ref_colmv_use_flag	: 1;
> +			u32 ref_reserved	: 4;
> +		} __packed ref_info[4];
> +	} __packed ref_info_regs[4];
> +
> +	u32 reserved_103_111[9];
> +
> +	struct rkvdec_vdpu381_error_ref_info {
> +		u32 avs2_ref_error_field	: 1;
> +		u32 avs2_ref_error_topfield	: 1;
> +		u32 ref_error_topfield_used	: 1;
> +		u32 ref_error_botfield_used	: 1;
> +		u32 reserved			: 28;
> +	} reg112;
> +} __packed;
> +
> +struct rkvdec_vdpu381_regs_hevc_params {
> +	struct rkvdec_vdpu381_h26x_set reg064;
> +
> +	u32 cur_top_poc;
> +	u32 cur_bot_poc;
> +
> +	u32 reg067_082_ref_poc[16];
> +
> +	u32 reserved_083_098[16];
> +
> +	struct rkvdec_vdpu381_hevc_ref_valid {
> +		u32 hevc_ref_valid_0??? : 1;
> +		u32 hevc_ref_valid_1??? : 1;
> +		u32 hevc_ref_valid_2??? : 1;
> +		u32 hevc_ref_valid_3??? : 1;
> +		u32 reserve0??????????? : 4;
> +		u32 hevc_ref_valid_4??? : 1;
> +		u32 hevc_ref_valid_5??? : 1;
> +		u32 hevc_ref_valid_6??? : 1;
> +		u32 hevc_ref_valid_7??? : 1;
> +		u32 reserve1??????????? : 4;
> +		u32 hevc_ref_valid_8??? : 1;
> +		u32 hevc_ref_valid_9??? : 1;
> +		u32 hevc_ref_valid_10?? : 1;
> +		u32 hevc_ref_valid_11?? : 1;
> +		u32 reserve2??????????? : 4;
> +		u32 hevc_ref_valid_12?? : 1;
> +		u32 hevc_ref_valid_13?? : 1;
> +		u32 hevc_ref_valid_14?? : 1;
> +		u32 reserve3??????????? : 5;
> +	} reg099;
> +
> +	u32 reserved_100_102[3];
> +
> +	struct rkvdec_vdpu381_hevc_mvc0 {
> +		u32 ref_pic_layer_same_with_cur : 16;
> +		u32 reserve???????????????????? : 16;
> +	} reg103;
> +
> +	struct rkvdec_vdpu381_hevc_mvc1 {
> +		u32 poc_lsb_not_present_flag??????? : 1;
> +		u32 num_direct_ref_layers?????????? : 6;
> +		u32 reserve0??????????????????????? : 1;
> +
> +		u32 num_reflayer_pics?????????????? : 6;
> +		u32 default_ref_layers_active_flag? : 1;
> +		u32 max_one_active_ref_layer_flag?? : 1;
> +
> +		u32 poc_reset_info_present_flag???? : 1;
> +		u32 vps_poc_lsb_aligned_flag??????? : 1;
> +		u32 mvc_poc15_valid_flag??????????? : 1;
> +		u32 reserve1??????????????????????? : 13;
> +	} reg104;
> +
> +	u32 reserved_105_111[7];
> +
> +	struct rkvdec_vdpu381_hevc_ref_info {
> +		u32 avs2_ref_error_field??????? : 1;
> +		u32 avs2_ref_error_topfield???? : 1;
> +		u32 ref_error_topfield_used???? : 1;
> +		u32 ref_error_botfield_used???? : 1;
> +		u32 reserve???????????????????? : 28;
> +	} reg112;
> +
> +} __packed;
> +
> +/* base: OFFSET_CODEC_ADDR_REGS */
> +struct rkvdec_vdpu381_regs_h26x_addr {
> +	u32 reserved_160;
> +	u32 pps_base;
> +	u32 reserved_162;
> +	u32 rps_base;
> +	u32 ref_base[16];
> +	u32 scanlist_addr;
> +	u32 colmv_base[16];
> +	u32 cabactbl_base;
> +} __packed;
> +
> +struct rkvdec_vdpu381_regs_h26x_highpoc {
> +	struct rkvdec_vdpu381_ref_poc_highbit {
> +		u32 ref0_poc_highbit	: 4;
> +		u32 ref1_poc_highbit	: 4;
> +		u32 ref2_poc_highbit	: 4;
> +		u32 ref3_poc_highbit	: 4;
> +		u32 ref4_poc_highbit	: 4;
> +		u32 ref5_poc_highbit	: 4;
> +		u32 ref6_poc_highbit	: 4;
> +		u32 ref7_poc_highbit	: 4;
> +	} reg200[4];
> +	struct rkvdec_vdpu381_cur_poc_highbit {
> +		u32 cur_poc_highbit	: 4;
> +		u32 reserved		: 28;
> +	} reg204;
> +} __packed;
> +
> +struct rkvdec_vdpu381_regs_h264 {
> +	struct rkvdec_vdpu381_regs_common		common;
> +	struct rkvdec_vdpu381_regs_h264_params		h264_param;
> +	struct rkvdec_vdpu381_regs_common_addr		common_addr;
> +	struct rkvdec_vdpu381_regs_h26x_addr		h264_addr;
> +	struct rkvdec_vdpu381_regs_h26x_highpoc		h264_highpoc;
> +} __packed;
> +
> +struct rkvdec_vdpu381_regs_hevc {
> +	struct rkvdec_vdpu381_regs_common		common;
> +	struct rkvdec_vdpu381_regs_hevc_params		hevc_param;
> +	struct rkvdec_vdpu381_regs_common_addr		common_addr;
> +	struct rkvdec_vdpu381_regs_h26x_addr		hevc_addr;
> +	struct rkvdec_vdpu381_regs_h26x_highpoc		hevc_highpoc;
> +} __packed;
> +
> +#endif /* __RKVDEC_REGS_H__ */
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> index aa92b586429e..ecf6b9051543 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> @@ -29,6 +29,7 @@
> ?
> ?#include "rkvdec.h"
> ?#include "rkvdec-regs.h"
> +#include "rkvdec-vdpu381-regs.h"
> ?#include "rkvdec-rcb.h"
> ?
> ?static bool rkvdec_image_fmt_match(enum rkvdec_image_fmt fmt1,
> @@ -90,6 +91,9 @@ static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx,
> ?{
> ?	v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat,
> ?			??? pix_mp->width, pix_mp->height);
> +
> +	ctx->colmv_offset = pix_mp->plane_fmt[0].sizeimage;
> +
> ?	pix_mp->plane_fmt[0].sizeimage += 128 *
> ?		DIV_ROUND_UP(pix_mp->width, 16) *
> ?		DIV_ROUND_UP(pix_mp->height, 16);
> @@ -367,6 +371,26 @@ static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = {
> ?	}
> ?};
> ?
> +static const struct rkvdec_coded_fmt_desc vdpu381_coded_fmts[] = {
> +	{
> +		.fourcc = V4L2_PIX_FMT_H264_SLICE,
> +		.frmsize = {
> +			.min_width = 64,
> +			.max_width =? 65520,
> +			.step_width = 64,
> +			.min_height = 64,
> +			.max_height =? 65520,
> +			.step_height = 16,
> +		},
> +		.ctrls = &rkvdec_h264_ctrls,
> +		.ops = &rkvdec_vdpu381_h264_fmt_ops,
> +		.num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts),
> +		.decoded_fmts = rkvdec_h264_decoded_fmts,
> +		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
> +		.capability = RKVDEC_CAPABILITY_H264,
> +	},
> +};
> +
> ?static bool rkvdec_is_capable(struct rkvdec_ctx *ctx, unsigned int capability)
> ?{
> ?	return (ctx->dev->variant->capabilities & capability) == capability;
> @@ -1241,6 +1265,35 @@ static irqreturn_t rk3399_irq_handler(struct rkvdec_ctx *ctx)
> ?	return IRQ_HANDLED;
> ?}
> ?
> +static irqreturn_t vdpu381_irq_handler(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	enum vb2_buffer_state state;
> +	bool need_reset = 0;
> +	u32 status;
> +
> +	status = readl(rkvdec->regs + VDPU381_REG_STA_INT);
> +	writel(0, rkvdec->regs + VDPU381_REG_STA_INT);
> +
> +	if (status & VDPU381_STA_INT_DEC_RDY_STA) {
> +		state = VB2_BUF_STATE_DONE;
> +	} else {
> +		state = VB2_BUF_STATE_ERROR;
> +		if (status & (VDPU381_STA_INT_SOFTRESET_RDY |
> +			????? VDPU381_STA_INT_TIMEOUT |
> +			????? VDPU381_STA_INT_ERROR))
> +			rkvdec_iommu_restore(rkvdec);
> +	}
> +
> +	if (need_reset)
> +		rkvdec_iommu_restore(rkvdec);
> +
> +	if (cancel_delayed_work(&rkvdec->watchdog_work))
> +		rkvdec_job_finish(ctx, state);
> +
> +	return IRQ_HANDLED;
> +}
> +
> ?static irqreturn_t rkvdec_irq_handler(int irq, void *priv)
> ?{
> ?	struct rkvdec_dev *rkvdec = priv;
> @@ -1265,12 +1318,76 @@ static void rkvdec_watchdog_func(struct work_struct *work)
> ?	}
> ?}
> ?
> +/*
> + * Some SoCs, like RK3588 have multiple identical VDPU cores, but the
> + * kernel is currently missing support for multi-core handling. Exposing
> + * separate devices for each core to userspace is bad, since that does
> + * not allow scheduling tasks properly (and creates ABI). With this workaround
> + * the driver will only probe for the first core and early exit for the other
> + * cores. Once the driver gains multi-core support, the same technique
> + * for detecting the first core can be used to cluster all cores together.
> + */
> +static int rkvdec_disable_multicore(struct rkvdec_dev *rkvdec)
> +{
> +	struct device_node *node = NULL;
> +	const char *compatible;
> +	bool is_first_core;
> +	int ret;
> +
> +	/* Intentionally ignores the fallback strings */
> +	ret = of_property_read_string(rkvdec->dev->of_node, "compatible", &compatible);
> +	if (ret)
> +		return ret;
> +
> +	/* The first compatible and available node found is considered the main core */
> +	do {
> +		node = of_find_compatible_node(node, NULL, compatible);
> +		if (of_device_is_available(node))
> +			break;
> +	} while (node);
> +
> +	if (!node)
> +		return -EINVAL;
> +
> +	is_first_core = (rkvdec->dev->of_node == node);
> +
> +	of_node_put(node);
> +
> +	if (!is_first_core) {
> +		dev_info(rkvdec->dev, "missing multi-core support, ignoring this instance\n");
> +		return -ENODEV;
> +	}
> +
> +	return 0;
> +}
> +
> ?static const struct rkvdec_config config_rkvdec = {
> ?	.coded_fmts = rkvdec_coded_fmts,
> ?	.coded_fmts_num = ARRAY_SIZE(rkvdec_coded_fmts),
> ?	.irq_handler = rk3399_irq_handler,
> ?};
> ?
> +static const struct rcb_size_info vdpu381_rcb_sizes[] = {
> +	{6,	PIC_WIDTH},	// intrar
> +	{1,	PIC_WIDTH},	// transdr (Is actually 0.4*pic_width)
> +	{1,	PIC_HEIGHT},	// transdc (Is actually 0.1*pic_height)
> +	{3,	PIC_WIDTH},	// streamdr
> +	{6,	PIC_WIDTH},	// interr
> +	{3,	PIC_HEIGHT},	// interc
> +	{22,	PIC_WIDTH},	// dblkr
> +	{6,	PIC_WIDTH},	// saor
> +	{11,	PIC_WIDTH},	// fbcr
> +	{67,	PIC_HEIGHT},	// filtc col
> +};
> +
> +static const struct rkvdec_config config_vdpu381 = {
> +	.coded_fmts = vdpu381_coded_fmts,
> +	.coded_fmts_num = ARRAY_SIZE(vdpu381_coded_fmts),
> +	.rcb_size_info = vdpu381_rcb_sizes,
> +	.rcb_num = ARRAY_SIZE(vdpu381_rcb_sizes),
> +	.irq_handler = vdpu381_irq_handler,
> +};
> +
> ?static const struct rkvdec_variant rk3288_rkvdec_variant = {
> ?	.num_regs = 68,
> ?	.config = &config_rkvdec,
> @@ -1294,6 +1411,11 @@ static const struct rkvdec_variant rk3399_rkvdec_variant = {
> ?			RKVDEC_CAPABILITY_VP9,
> ?};
> ?
> +static const struct rkvdec_variant rk3588_vdpu381_variant = {
> +	.config = &config_vdpu381,
> +	.capabilities = RKVDEC_CAPABILITY_H264,
> +};
> +
> ?static const struct of_device_id of_rkvdec_match[] = {
> ?	{
> ?		.compatible = "rockchip,rk3288-vdec",
> @@ -1307,6 +1429,10 @@ static const struct of_device_id of_rkvdec_match[] = {
> ?		.compatible = "rockchip,rk3399-vdec",
> ?		.data = &rk3399_rkvdec_variant,
> ?	},
> +	{
> +		.compatible = "rockchip,rk3588-vdec",
> +		.data = &rk3588_vdpu381_variant,
> +	},
> ?	{ /* sentinel */ }
> ?};
> ?MODULE_DEVICE_TABLE(of, of_rkvdec_match);
> @@ -1331,11 +1457,16 @@ static int rkvdec_probe(struct platform_device *pdev)
> ?	mutex_init(&rkvdec->vdev_lock);
> ?	INIT_DELAYED_WORK(&rkvdec->watchdog_work, rkvdec_watchdog_func);
> ?
> +	ret = rkvdec_disable_multicore(rkvdec);
> +	if (ret)
> +		return ret;
> +
> ?	ret = devm_clk_bulk_get_all_enabled(&pdev->dev, &rkvdec->clocks);
> ?	if (ret < 0)
> ?		return ret;
> ?
> ?	rkvdec->clk_count = ret;
> +	rkvdec->axi_clk = devm_clk_get(&pdev->dev, "axi");
> ?
> ?	rkvdec->regs = devm_platform_ioremap_resource(pdev, 0);
> ?	if (IS_ERR(rkvdec->regs))
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> index 4094f92f8a44..5b86f5b85d20 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> @@ -132,6 +132,7 @@ struct rkvdec_dev {
> ?	struct device *dev;
> ?	struct clk_bulk_data *clocks;
> ?	unsigned int clk_count;
> +	struct clk *axi_clk;
> ?	void __iomem *regs;
> ?	struct mutex vdev_lock; /* serializes ioctls */
> ?	struct delayed_work watchdog_work;
> @@ -150,6 +151,7 @@ struct rkvdec_ctx {
> ?	struct rkvdec_dev *dev;
> ?	enum rkvdec_image_fmt image_fmt;
> ?	struct rkvdec_rcb_config *rcb_config;
> +	u32 colmv_offset;
> ?	void *priv;
> ?};
> ?
> @@ -180,4 +182,6 @@ extern const struct rkvdec_coded_fmt_ops rkvdec_h264_fmt_ops;
> ?extern const struct rkvdec_coded_fmt_ops rkvdec_hevc_fmt_ops;
> ?extern const struct rkvdec_coded_fmt_ops rkvdec_vp9_fmt_ops;
> ?
> +extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_h264_fmt_ops;
> +
> ?#endif /* RKVDEC_H_ */
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251210/30a82162/attachment-0001.sig>

From nicolas.dufresne at collabora.com  Wed Dec 10 12:45:12 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Wed, 10 Dec 2025 15:45:12 -0500
Subject: [PATCH v4 13/15] media: rkvdec: Add H264 support for the
 VDPU383 variant
In-Reply-To: <20251022174508.284929-14-detlev.casanova@collabora.com>
References: <20251022174508.284929-1-detlev.casanova@collabora.com>
	 <20251022174508.284929-14-detlev.casanova@collabora.com>
Message-ID: <1b4c87416fc2d7f18fb5a179c48c6cffeb1a7c7d.camel@collabora.com>

Le mercredi 22 octobre 2025 ? 13:45 -0400, Detlev Casanova a ?crit?:
> This variant is used on the RK3576 SoC.
> 
> The moving vectors size requirements are slightly different so support
> for a colmv_size function per variant is added.
> 
> Also, the link registers are used to start the decoder and read IRQ status.
> Per variant support for named register sections is added.
> 
> The fluster score is 128/135 for JVT-AVC_V1, with MPS_MW_A failing in
> addition to the usual ones.
> The other test suites are not supported yet.
> 
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
> ---
> ?.../media/platform/rockchip/rkvdec/Makefile?? |?? 1 +
> ?.../rockchip/rkvdec/rkvdec-vdpu383-h264.c???? | 582 ++++++++++++++++++
> ?.../rockchip/rkvdec/rkvdec-vdpu383-regs.h???? | 284 +++++++++
> ?.../media/platform/rockchip/rkvdec/rkvdec.c?? | 118 +++-
> ?.../media/platform/rockchip/rkvdec/rkvdec.h?? |?? 8 +
> ?5 files changed, 987 insertions(+), 6 deletions(-)
> ?create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c
> ?create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-regs.h
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
> index 7bfd95151e40..a58d4aede2fe 100644
> --- a/drivers/media/platform/rockchip/rkvdec/Makefile
> +++ b/drivers/media/platform/rockchip/rkvdec/Makefile
> @@ -9,4 +9,5 @@ rockchip-vdec-y += \
> ?		?? rkvdec-hevc-common.o \
> ?		?? rkvdec-rcb.o \
> ?		?? rkvdec-vdpu381-h264.o \
> +		?? rkvdec-vdpu383-h264.o \
> ?		?? rkvdec-vp9.o
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c
> new file mode 100644
> index 000000000000..bb2c62d9c3d4
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c
> @@ -0,0 +1,582 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Rockchip Video Decoder VDPU383 H264 backend
> + *
> + * Copyright (C) 2024 Collabora, Ltd.
> + *? Detlev Casanova <detlev.casanova at collabora.com>
> + */
> +
> +#include <media/v4l2-h264.h>
> +#include <media/v4l2-mem2mem.h>
> +
> +#include <linux/iopoll.h>
> +
> +#include "rkvdec-rcb.h"
> +#include "rkvdec-vdpu383-regs.h"
> +#include "rkvdec-h264-common.h"
> +
> +struct rkvdec_sps {
> +	u16 seq_parameter_set_id:			4;
> +	u16 profile_idc:				8;
> +	u16 constraint_set3_flag:			1;
> +	u16 chroma_format_idc:				2;
> +	u16 bit_depth_luma:				3;
> +	u16 bit_depth_chroma:				3;
> +	u16 qpprime_y_zero_transform_bypass_flag:	1;
> +	u16 log2_max_frame_num_minus4:			4;
> +	u16 max_num_ref_frames:				5;
> +	u16 pic_order_cnt_type:				2;
> +	u16 log2_max_pic_order_cnt_lsb_minus4:		4;
> +	u16 delta_pic_order_always_zero_flag:		1;
> +
> +	u16 pic_width_in_mbs:				16;
> +	u16 pic_height_in_mbs:				16;
> +
> +	u16 frame_mbs_only_flag:			1;
> +	u16 mb_adaptive_frame_field_flag:		1;
> +	u16 direct_8x8_inference_flag:			1;
> +	u16 mvc_extension_enable:			1;
> +	u16 num_views:					2;
> +	u16 view_id0:?????????????????????????????????? 10;
> +	u16 view_id1:?????????????????????????????????? 10;
> +} __packed;
> +
> +struct rkvdec_pps {
> +	u32 pic_parameter_set_id:				8;
> +	u32 pps_seq_parameter_set_id:				5;
> +	u32 entropy_coding_mode_flag:				1;
> +	u32 bottom_field_pic_order_in_frame_present_flag:	1;
> +	u32 num_ref_idx_l0_default_active_minus1:		5;
> +	u32 num_ref_idx_l1_default_active_minus1:		5;
> +	u32 weighted_pred_flag:					1;
> +	u32 weighted_bipred_idc:				2;
> +	u32 pic_init_qp_minus26:				7;
> +	u32 pic_init_qs_minus26:				6;
> +	u32 chroma_qp_index_offset:				5;
> +	u32 deblocking_filter_control_present_flag:		1;
> +	u32 constrained_intra_pred_flag:			1;
> +	u32 redundant_pic_cnt_present:				1;
> +	u32 transform_8x8_mode_flag:				1;
> +	u32 second_chroma_qp_index_offset:			5;
> +	u32 scaling_list_enable_flag:				1;
> +	u32 is_longterm:					16;
> +	u32 voidx:						16;
> +
> +	// dpb
> +	u32 pic_field_flag:???????????????????????????????????? 1;
> +	u32 pic_associated_flag:??????????????????????????????? 1;
> +	u32 cur_top_field:					32;
> +	u32 cur_bot_field:					32;
> +
> +	u32 top_field_order_cnt0:				32;
> +	u32 bot_field_order_cnt0:				32;
> +	u32 top_field_order_cnt1:				32;
> +	u32 bot_field_order_cnt1:				32;
> +	u32 top_field_order_cnt2:				32;
> +	u32 bot_field_order_cnt2:				32;
> +	u32 top_field_order_cnt3:				32;
> +	u32 bot_field_order_cnt3:				32;
> +	u32 top_field_order_cnt4:				32;
> +	u32 bot_field_order_cnt4:				32;
> +	u32 top_field_order_cnt5:				32;
> +	u32 bot_field_order_cnt5:				32;
> +	u32 top_field_order_cnt6:				32;
> +	u32 bot_field_order_cnt6:				32;
> +	u32 top_field_order_cnt7:				32;
> +	u32 bot_field_order_cnt7:				32;
> +	u32 top_field_order_cnt8:				32;
> +	u32 bot_field_order_cnt8:				32;
> +	u32 top_field_order_cnt9:				32;
> +	u32 bot_field_order_cnt9:				32;
> +	u32 top_field_order_cnt10:				32;
> +	u32 bot_field_order_cnt10:				32;
> +	u32 top_field_order_cnt11:				32;
> +	u32 bot_field_order_cnt11:				32;
> +	u32 top_field_order_cnt12:				32;
> +	u32 bot_field_order_cnt12:				32;
> +	u32 top_field_order_cnt13:				32;
> +	u32 bot_field_order_cnt13:				32;
> +	u32 top_field_order_cnt14:				32;
> +	u32 bot_field_order_cnt14:				32;
> +	u32 top_field_order_cnt15:				32;
> +	u32 bot_field_order_cnt15:				32;
> +
> +	u32 ref_field_flags:					16;
> +	u32 ref_topfield_used:					16;
> +	u32 ref_botfield_used:					16;
> +	u32 ref_colmv_use_flag:					16;
> +
> +	u32 reserved0:						30;
> +	u32 reserved[3];
> +} __packed;
> +
> +struct rkvdec_sps_pps {
> +	struct rkvdec_sps sps;
> +	struct rkvdec_pps pps;
> +} __packed;
> +
> +/* Data structure describing auxiliary buffer format. */
> +struct rkvdec_h264_priv_tbl {
> +	s8 cabac_table[4][464][2];
> +	struct rkvdec_h264_scaling_list scaling_list;
> +	struct rkvdec_sps_pps param_set[256];
> +	struct rkvdec_rps rps;
> +} __packed;
> +
> +struct rkvdec_h264_ctx {
> +	struct rkvdec_aux_buf priv_tbl;
> +	struct rkvdec_h264_reflists reflists;
> +	struct vdpu383_regs_h26x regs;
> +};
> +
> +static void set_field_order_cnt(struct rkvdec_sps_pps *hw_ps, int id, u32 top, u32 bottom)
> +{
> +	switch (id) {
> +	case 0:
> +		hw_ps->pps.top_field_order_cnt0 = top;
> +		hw_ps->pps.bot_field_order_cnt0 = bottom;
> +		break;
> +	case 1:
> +		hw_ps->pps.top_field_order_cnt1 = top;
> +		hw_ps->pps.bot_field_order_cnt1 = bottom;
> +		break;
> +	case 2:
> +		hw_ps->pps.top_field_order_cnt2 = top;
> +		hw_ps->pps.bot_field_order_cnt2 = bottom;
> +		break;
> +	case 3:
> +		hw_ps->pps.top_field_order_cnt3 = top;
> +		hw_ps->pps.bot_field_order_cnt3 = bottom;
> +		break;
> +	case 4:
> +		hw_ps->pps.top_field_order_cnt4 = top;
> +		hw_ps->pps.bot_field_order_cnt4 = bottom;
> +		break;
> +	case 5:
> +		hw_ps->pps.top_field_order_cnt5 = top;
> +		hw_ps->pps.bot_field_order_cnt5 = bottom;
> +		break;
> +	case 6:
> +		hw_ps->pps.top_field_order_cnt6 = top;
> +		hw_ps->pps.bot_field_order_cnt6 = bottom;
> +		break;
> +	case 7:
> +		hw_ps->pps.top_field_order_cnt7 = top;
> +		hw_ps->pps.bot_field_order_cnt7 = bottom;
> +		break;
> +	case 8:
> +		hw_ps->pps.top_field_order_cnt8 = top;
> +		hw_ps->pps.bot_field_order_cnt8 = bottom;
> +		break;
> +	case 9:
> +		hw_ps->pps.top_field_order_cnt9 = top;
> +		hw_ps->pps.bot_field_order_cnt9 = bottom;
> +		break;
> +	case 10:
> +		hw_ps->pps.top_field_order_cnt10 = top;
> +		hw_ps->pps.bot_field_order_cnt10 = bottom;
> +		break;
> +	case 11:
> +		hw_ps->pps.top_field_order_cnt11 = top;
> +		hw_ps->pps.bot_field_order_cnt11 = bottom;
> +		break;
> +	case 12:
> +		hw_ps->pps.top_field_order_cnt12 = top;
> +		hw_ps->pps.bot_field_order_cnt12 = bottom;
> +		break;
> +	case 13:
> +		hw_ps->pps.top_field_order_cnt13 = top;
> +		hw_ps->pps.bot_field_order_cnt13 = bottom;
> +		break;
> +	case 14:
> +		hw_ps->pps.top_field_order_cnt14 = top;
> +		hw_ps->pps.bot_field_order_cnt14 = bottom;
> +		break;
> +	case 15:
> +		hw_ps->pps.top_field_order_cnt15 = top;
> +		hw_ps->pps.bot_field_order_cnt15 = bottom;
> +		break;
> +	}
> +}
> +
> +static void assemble_hw_pps(struct rkvdec_ctx *ctx,
> +			??? struct rkvdec_h264_run *run)
> +{
> +	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
> +	const struct v4l2_ctrl_h264_sps *sps = run->sps;
> +	const struct v4l2_ctrl_h264_pps *pps = run->pps;
> +	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
> +	const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb;
> +	struct rkvdec_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu;
> +	struct rkvdec_sps_pps *hw_ps;
> +	u32 pic_width, pic_height;
> +	u32 i;
> +
> +	/*
> +	 * HW read the SPS/PPS information from PPS packet index by PPS id.
> +	 * offset from the base can be calculated by PPS_id * 32 (size per PPS
> +	 * packet unit). so the driver copy SPS/PPS information to the exact PPS
> +	 * packet unit for HW accessing.
> +	 */
> +	hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id];
> +	memset(hw_ps, 0, sizeof(*hw_ps));
> +
> +	/* write sps */
> +	hw_ps->sps.seq_parameter_set_id = sps->seq_parameter_set_id;
> +	hw_ps->sps.profile_idc = sps->profile_idc;
> +	hw_ps->sps.constraint_set3_flag = !!(sps->constraint_set_flags & (1 << 3));
> +	hw_ps->sps.chroma_format_idc = sps->chroma_format_idc;
> +	hw_ps->sps.bit_depth_luma = sps->bit_depth_luma_minus8;
> +	hw_ps->sps.bit_depth_chroma = sps->bit_depth_chroma_minus8;
> +	hw_ps->sps.qpprime_y_zero_transform_bypass_flag =
> +		!!(sps->flags & V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS);
> +	hw_ps->sps.log2_max_frame_num_minus4 = sps->log2_max_frame_num_minus4;
> +	hw_ps->sps.max_num_ref_frames = sps->max_num_ref_frames;
> +	hw_ps->sps.pic_order_cnt_type = sps->pic_order_cnt_type;
> +	hw_ps->sps.log2_max_pic_order_cnt_lsb_minus4 =
> +		sps->log2_max_pic_order_cnt_lsb_minus4;
> +	hw_ps->sps.delta_pic_order_always_zero_flag =
> +		!!(sps->flags & V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO);
> +	hw_ps->sps.mvc_extension_enable = 0;
> +	hw_ps->sps.num_views = 0;
> +
> +	/*
> +	 * Use the SPS values since they are already in macroblocks
> +	 * dimensions, height can be field height (halved) if
> +	 * V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY is not set and also it allows
> +	 * decoding smaller images into larger allocation which can be used
> +	 * to implementing SVC spatial layer support.
> +	 */
> +	pic_width = 16 * (sps->pic_width_in_mbs_minus1 + 1);
> +	pic_height = 16 * (sps->pic_height_in_map_units_minus1 + 1);
> +	if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY))
> +		pic_height *= 2;
> +	if (!!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC))
> +		pic_height /= 2;
> +
> +	hw_ps->sps.pic_width_in_mbs = pic_width;
> +	hw_ps->sps.pic_height_in_mbs = pic_height;
> +
> +	hw_ps->sps.frame_mbs_only_flag =
> +		!!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY);
> +	hw_ps->sps.mb_adaptive_frame_field_flag =
> +		!!(sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD);
> +	hw_ps->sps.direct_8x8_inference_flag =
> +		!!(sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE);
> +
> +	/* write pps */
> +	hw_ps->pps.pic_parameter_set_id = pps->pic_parameter_set_id;
> +	hw_ps->pps.pps_seq_parameter_set_id = pps->seq_parameter_set_id;
> +	hw_ps->pps.entropy_coding_mode_flag =
> +		!!(pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE);
> +	hw_ps->pps.bottom_field_pic_order_in_frame_present_flag =
> +		!!(pps->flags & V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT);
> +	hw_ps->pps.num_ref_idx_l0_default_active_minus1 =
> +		pps->num_ref_idx_l0_default_active_minus1;
> +	hw_ps->pps.num_ref_idx_l1_default_active_minus1 =
> +		pps->num_ref_idx_l1_default_active_minus1;
> +	hw_ps->pps.weighted_pred_flag =
> +		!!(pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED);
> +	hw_ps->pps.weighted_bipred_idc = pps->weighted_bipred_idc;
> +	hw_ps->pps.pic_init_qp_minus26 = pps->pic_init_qp_minus26;
> +	hw_ps->pps.pic_init_qs_minus26 = pps->pic_init_qs_minus26;
> +	hw_ps->pps.chroma_qp_index_offset = pps->chroma_qp_index_offset;
> +	hw_ps->pps.deblocking_filter_control_present_flag =
> +		!!(pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT);
> +	hw_ps->pps.constrained_intra_pred_flag =
> +		!!(pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED);
> +	hw_ps->pps.redundant_pic_cnt_present =
> +		!!(pps->flags & V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT);
> +	hw_ps->pps.transform_8x8_mode_flag =
> +		!!(pps->flags & V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE);
> +	hw_ps->pps.second_chroma_qp_index_offset = pps->second_chroma_qp_index_offset;
> +	hw_ps->pps.scaling_list_enable_flag =
> +		!!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT);
> +
> +	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
> +		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
> +			hw_ps->pps.is_longterm |= (1 << i);
> +
> +		set_field_order_cnt(hw_ps, i, dpb[i].top_field_order_cnt,
> +				??? dpb[i].bottom_field_order_cnt);
> +
> +		hw_ps->pps.ref_field_flags |=
> +			(!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD)) << i;
> +		hw_ps->pps.ref_colmv_use_flag |=
> +			(!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) << i;
> +		hw_ps->pps.ref_topfield_used |=
> +			(!!(dpb[i].fields & V4L2_H264_TOP_FIELD_REF)) << i;
> +		hw_ps->pps.ref_botfield_used |=
> +			(!!(dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF)) << i;
> +	}
> +
> +	hw_ps->pps.pic_field_flag =
> +		!!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC);
> +	hw_ps->pps.pic_associated_flag =
> +		!!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD);
> +
> +	hw_ps->pps.cur_top_field = dec_params->top_field_order_cnt;
> +	hw_ps->pps.cur_bot_field = dec_params->bottom_field_order_cnt;
> +}
> +
> +static void rkvdec_write_regs(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
> +
> +	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_COMMON_REGS,
> +			?? &h264_ctx->regs.common,
> +			?? sizeof(h264_ctx->regs.common));
> +	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_COMMON_ADDR_REGS,
> +			?? &h264_ctx->regs.common_addr,
> +			?? sizeof(h264_ctx->regs.common_addr));
> +	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_CODEC_PARAMS_REGS,
> +			?? &h264_ctx->regs.h26x_params,
> +			?? sizeof(h264_ctx->regs.h26x_params));
> +	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_CODEC_ADDR_REGS,
> +			?? &h264_ctx->regs.h26x_addr,
> +			?? sizeof(h264_ctx->regs.h26x_addr));
> +}
> +
> +static void config_registers(struct rkvdec_ctx *ctx,
> +			???? struct rkvdec_h264_run *run)
> +{
> +	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
> +	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
> +	dma_addr_t priv_start_addr = h264_ctx->priv_tbl.dma;
> +	const struct v4l2_pix_format_mplane *dst_fmt;
> +	struct vb2_v4l2_buffer *src_buf = run->base.bufs.src;
> +	struct vb2_v4l2_buffer *dst_buf = run->base.bufs.dst;
> +	struct vdpu383_regs_h26x *regs = &h264_ctx->regs;
> +	const struct v4l2_format *f;
> +	dma_addr_t rlc_addr;
> +	dma_addr_t dst_addr;
> +	u32 hor_virstride;
> +	u32 ver_virstride;
> +	u32 y_virstride;
> +	u32 offset;
> +	u32 pixels;
> +	u32 i;
> +
> +	memset(regs, 0, sizeof(*regs));
> +
> +	/* Set H264 mode */
> +	regs->common.reg008_dec_mode = VDPU383_MODE_H264;
> +
> +	/* Set input stream length */
> +	regs->h26x_params.reg066_stream_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
> +
> +	/* Set strides */
> +	f = &ctx->decoded_fmt;
> +	dst_fmt = &f->fmt.pix_mp;
> +	hor_virstride = dst_fmt->plane_fmt[0].bytesperline;
> +	ver_virstride = dst_fmt->height;
> +	y_virstride = hor_virstride * ver_virstride;
> +
> +	pixels = dst_fmt->height * dst_fmt->width;
> +
> +	regs->h26x_params.reg068_hor_virstride = hor_virstride / 16;
> +	regs->h26x_params.reg069_raster_uv_hor_virstride = hor_virstride / 16;
> +	regs->h26x_params.reg070_y_virstride = y_virstride / 16;
> +
> +	/* Activate block gating */
> +	regs->common.reg010.strmd_auto_gating_e????? = 1;
> +	regs->common.reg010.inter_auto_gating_e????? = 1;
> +	regs->common.reg010.intra_auto_gating_e????? = 1;
> +	regs->common.reg010.transd_auto_gating_e???? = 1;
> +	regs->common.reg010.recon_auto_gating_e????? = 1;
> +	regs->common.reg010.filterd_auto_gating_e??? = 1;
> +	regs->common.reg010.bus_auto_gating_e??????? = 1;
> +	regs->common.reg010.ctrl_auto_gating_e?????? = 1;
> +	regs->common.reg010.rcb_auto_gating_e??????? = 1;
> +	regs->common.reg010.err_prc_auto_gating_e??? = 1;
> +
> +	/* Set timeout threshold */
> +	if (pixels < VDPU383_1080P_PIXELS)
> +		regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_1080p;
> +	else if (pixels < VDPU383_4K_PIXELS)
> +		regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_4K;
> +	else if (pixels < VDPU383_8K_PIXELS)
> +		regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_8K;
> +	else
> +		regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_MAX;
> +
> +	regs->common.reg016.error_proc_disable = 1;
> +
> +	/* Set ref pic address & poc */
> +	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
> +		struct vb2_buffer *vb_buf = run->ref_buf[i];
> +		dma_addr_t buf_dma;
> +
> +		/*
> +		 * If a DPB entry is unused or invalid, address of current destination
> +		 * buffer is returned.
> +		 */
> +		if (!vb_buf)
> +			vb_buf = &dst_buf->vb2_buf;
> +
> +		buf_dma = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
> +
> +		/* Set reference addresses */
> +		regs->h26x_addr.reg170_185_ref_base[i] = buf_dma;
> +		regs->h26x_addr.reg195_210_payload_st_ref_base[i] = buf_dma;
> +
> +		/* Set COLMV addresses */
> +		regs->h26x_addr.reg217_232_colmv_ref_base[i] = buf_dma + ctx->colmv_offset;
> +	}
> +
> +	/* Set rlc base address (input stream) */
> +	rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
> +	regs->common_addr.reg128_strm_base = rlc_addr;
> +
> +	/* Set output base address */
> +	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
> +	regs->h26x_addr.reg168_decout_base = dst_addr;
> +	regs->h26x_addr.reg169_error_ref_base = dst_addr;
> +	regs->h26x_addr.reg192_payload_st_cur_base = dst_addr;
> +
> +	/* Set colmv address */
> +	regs->h26x_addr.reg216_colmv_cur_base = dst_addr + ctx->colmv_offset;
> +
> +	/* Set RCB addresses */
> +	for (i = 0; i < rkvdec_rcb_buf_count(ctx); i++) {
> +		regs->common_addr.reg140_162_rcb_info[i].offset = rkvdec_rcb_buf_dma_addr(ctx, i);
> +		regs->common_addr.reg140_162_rcb_info[i].size = rkvdec_rcb_buf_size(ctx, i);
> +	}
> +
> +	/* Set hw pps address */
> +	offset = offsetof(struct rkvdec_h264_priv_tbl, param_set);
> +	regs->common_addr.reg131_gbl_base = priv_start_addr + offset;
> +	regs->h26x_params.reg067_global_len = sizeof(struct rkvdec_sps_pps) / 16;
> +
> +	/* Set hw rps address */
> +	offset = offsetof(struct rkvdec_h264_priv_tbl, rps);
> +	regs->common_addr.reg129_rps_base = priv_start_addr + offset;
> +
> +	/* Set cabac table */
> +	offset = offsetof(struct rkvdec_h264_priv_tbl, cabac_table);
> +	regs->common_addr.reg130_cabactbl_base = priv_start_addr + offset;
> +
> +	/* Set scaling list address */
> +	offset = offsetof(struct rkvdec_h264_priv_tbl, scaling_list);
> +	regs->common_addr.reg132_scanlist_addr = priv_start_addr + offset;
> +
> +	rkvdec_write_regs(ctx);
> +}
> +
> +static int rkvdec_h264_start(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	struct rkvdec_h264_priv_tbl *priv_tbl;
> +	struct rkvdec_h264_ctx *h264_ctx;
> +	struct v4l2_ctrl *ctrl;
> +	int ret;
> +
> +	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> +			????? V4L2_CID_STATELESS_H264_SPS);
> +	if (!ctrl)
> +		return -EINVAL;
> +
> +	ret = rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps);
> +	if (ret)
> +		return ret;
> +
> +	h264_ctx = kzalloc(sizeof(*h264_ctx), GFP_KERNEL);
> +	if (!h264_ctx)
> +		return -ENOMEM;
> +
> +	priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl),
> +				????? &h264_ctx->priv_tbl.dma, GFP_KERNEL);
> +	if (!priv_tbl) {
> +		ret = -ENOMEM;
> +		goto err_free_ctx;
> +	}
> +
> +	h264_ctx->priv_tbl.size = sizeof(*priv_tbl);
> +	h264_ctx->priv_tbl.cpu = priv_tbl;
> +	memcpy(priv_tbl->cabac_table, rkvdec_h264_cabac_table,
> +	?????? sizeof(rkvdec_h264_cabac_table));
> +
> +	ctx->priv = h264_ctx;
> +
> +	return 0;
> +
> +err_free_ctx:
> +	kfree(h264_ctx);
> +	return ret;
> +}
> +
> +static void rkvdec_h264_stop(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +
> +	dma_free_coherent(rkvdec->dev, h264_ctx->priv_tbl.size,
> +			? h264_ctx->priv_tbl.cpu, h264_ctx->priv_tbl.dma);
> +	kfree(h264_ctx);
> +}
> +
> +static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
> +{
> +	struct v4l2_h264_reflist_builder reflist_builder;
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
> +	struct rkvdec_h264_run run;
> +	struct rkvdec_h264_priv_tbl *tbl = h264_ctx->priv_tbl.cpu;
> +	u32 watchdog_time;
> +	u64 timeout_threshold;
> +	unsigned long axi_rate;
> +
> +	rkvdec_h264_run_preamble(ctx, &run);
> +
> +	/* Build the P/B{0,1} ref lists. */
> +	v4l2_h264_init_reflist_builder(&reflist_builder, run.decode_params,
> +				?????? run.sps, run.decode_params->dpb);
> +	v4l2_h264_build_p_ref_list(&reflist_builder, h264_ctx->reflists.p);
> +	v4l2_h264_build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0,
> +				??? h264_ctx->reflists.b1);
> +
> +	assemble_hw_scaling_list(&run, &tbl->scaling_list);
> +	assemble_hw_pps(ctx, &run);
> +	lookup_ref_buf_idx(ctx, &run);
> +	assemble_hw_rps(&reflist_builder, &run, &h264_ctx->reflists, &tbl->rps);
> +
> +	config_registers(ctx, &run);
> +
> +	rkvdec_run_postamble(ctx, &run.base);
> +
> +	/* Set watchdog at 2 times the hardware timeout threshold */
> +	timeout_threshold = h264_ctx->regs.common.reg013_core_timeout_threshold;
> +	axi_rate = clk_get_rate(rkvdec->axi_clk);
> +
> +	if (axi_rate)
> +		watchdog_time = 2 * (1000 * timeout_threshold) / axi_rate;
> +	else
> +		watchdog_time = 2000;
> +	schedule_delayed_work(&rkvdec->watchdog_work,
> +			????? msecs_to_jiffies(watchdog_time));
> +
> +	/* Start decoding! */
> +	writel(timeout_threshold, rkvdec->link + VDPU383_LINK_TIMEOUT_THRESHOLD);
> +	writel(0, rkvdec->link + VDPU383_LINK_IP_ENABLE);
> +	writel(VDPU383_DEC_E_BIT, rkvdec->link + VDPU383_LINK_DEC_ENABLE);
> +
> +	return 0;
> +}
> +
> +static int rkvdec_h264_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
> +{
> +	if (ctrl->id == V4L2_CID_STATELESS_H264_SPS)
> +		return rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps);
> +
> +	return 0;
> +}
> +
> +const struct rkvdec_coded_fmt_ops rkvdec_vdpu383_h264_fmt_ops = {
> +	.adjust_fmt = rkvdec_h264_adjust_fmt,
> +	.get_image_fmt = rkvdec_h264_get_image_fmt,
> +	.start = rkvdec_h264_start,
> +	.stop = rkvdec_h264_stop,
> +	.run = rkvdec_h264_run,
> +	.try_ctrl = rkvdec_h264_try_ctrl,
> +};
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-regs.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-regs.h
> new file mode 100644
> index 000000000000..2b614393a3af
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-regs.h
> @@ -0,0 +1,284 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Rockchip Video Decoder VDPU383 driver registers description
> + *
> + * Copyright (C) 2025 Collabora, Ltd.
> + *? Detlev Casanova <detlev.casanova at collabora.com>
> + */
> +
> +#ifndef _RKVDEC_VDPU838_REGS_H_
> +#define _RKVDEC_VDPU838_REGS_H_
> +
> +#include <linux/types.h>
> +
> +#define VDPU383_OFFSET_COMMON_REGS		(8 * sizeof(u32))
> +#define VDPU383_OFFSET_CODEC_PARAMS_REGS	(64 * sizeof(u32))
> +#define VDPU383_OFFSET_COMMON_ADDR_REGS		(128 * sizeof(u32))
> +#define VDPU383_OFFSET_CODEC_ADDR_REGS		(168 * sizeof(u32))
> +#define VDPU383_OFFSET_POC_HIGHBIT_REGS		(200 * sizeof(u32))
> +
> +#define VDPU383_MODE_HEVC	0
> +#define VDPU383_MODE_H264	1
> +
> +#define VDPU383_1080P_PIXELS		(1920 * 1080)
> +#define VDPU383_4K_PIXELS		(4096 * 2304)
> +#define VDPU383_8K_PIXELS		(7680 * 4320)
> +#define VDPU383_TIMEOUT_1080p		(0xffffff)
> +#define VDPU383_TIMEOUT_4K		(0x2cfffff)
> +#define VDPU383_TIMEOUT_8K		(0x4ffffff)
> +#define VDPU383_TIMEOUT_MAX		(0xffffffff)
> +
> +#define VDPU383_LINK_TIMEOUT_THRESHOLD	0x54
> +
> +#define VDPU383_LINK_IP_ENABLE		0x58
> +#define VDPU383_IP_CRU_MODE		BIT(24)
> +
> +#define VDPU383_LINK_DEC_ENABLE		0x40
> +#define VDPU383_DEC_E_BIT		BIT(0)
> +
> +#define VDPU383_LINK_INT_EN		0x048
> +#define VDPU383_INT_EN_IRQ		BIT(0)
> +#define VDPU383_INT_EN_LINE_IRQ		BIT(1)
> +
> +#define VDPU383_LINK_STA_INT		0x04c
> +#define VDPU383_STA_INT_DEC_RDY_STA	BIT(0)
> +#define VDPU383_STA_INT_SOFTRESET_RDY	(BIT(10) | BIT(11))
> +#define VDPU383_STA_INT_ALL		0x3ff
> +
> +struct vdpu383_regs_common {
> +	u32 reg008_dec_mode;
> +
> +	struct swreg9_important_en {
> +		u32 fbc_e			: 1;
> +		u32 tile_e			: 1;
> +		u32 reserve0			: 2;
> +		u32 buf_empty_en		: 1;
> +		u32 scale_down_en		: 1;
> +		u32 reserve1			: 1;
> +		u32 pix_range_det_e		: 1;
> +		u32 av1_fgs_en			: 1;
> +		u32 reserve2			: 7;
> +		u32 line_irq_en			: 1;
> +		u32 out_cbcr_swap		: 1;
> +		u32 fbc_force_uncompress	: 1;
> +		u32 fbc_sparse_mode		: 1;
> +		u32 reserve3			: 12;
> +	} reg009;
> +
> +	struct swreg010_block_gating_en {
> +		u32 strmd_auto_gating_e		: 1;
> +		u32 inter_auto_gating_e		: 1;
> +		u32 intra_auto_gating_e		: 1;
> +		u32 transd_auto_gating_e	: 1;
> +		u32 recon_auto_gating_e		: 1;
> +		u32 filterd_auto_gating_e	: 1;
> +		u32 bus_auto_gating_e		: 1;
> +		u32 ctrl_auto_gating_e		: 1;
> +		u32 rcb_auto_gating_e		: 1;
> +		u32 err_prc_auto_gating_e	: 1;
> +		u32 reserve0			: 22;
> +	} reg010;
> +
> +	struct swreg011_cfg_para {
> +		u32 reserve0			: 9;
> +		u32 dec_timeout_dis		: 1;
> +		u32 reserve1			: 22;
> +	} reg011;
> +
> +	struct swreg012_cache_hash_mask {
> +		u32 reserve0			: 7;
> +		u32 cache_hash_mask		: 25;
> +	} reg012;
> +
> +	u32 reg013_core_timeout_threshold;
> +
> +	struct swreg014_line_irq_ctrl {
> +		u32 dec_line_irq_step		: 16;
> +		u32 dec_line_offset_y_st	: 16;
> +	} reg014;
> +
> +	struct swreg015_irq_sta {
> +		u32 rkvdec_frame_rdy_sta	: 1;
> +		u32 rkvdec_strm_error_sta	: 1;
> +		u32 rkvdec_core_timeout_sta	: 1;
> +		u32 rkvdec_ip_timeout_sta	: 1;
> +		u32 rkvdec_bus_error_sta	: 1;
> +		u32 rkvdec_buffer_empty_sta	: 1;
> +		u32 rkvdec_colmv_ref_error_sta	: 1;
> +		u32 rkvdec_error_spread_sta	: 1;
> +		u32 create_core_timeout_sta	: 1;
> +		u32 wlast_miss_match_sta	: 1;
> +		u32 rkvdec_core_rst_rdy_sta	: 1;
> +		u32 rkvdec_ip_rst_rdy_sta	: 1;
> +		u32 force_busidle_rdy_sta	: 1;
> +		u32 ltb_pause_rdy_sta		: 1;
> +		u32 ltb_end_flag		: 1;
> +		u32 unsupport_decmode_error_sta	: 1;
> +		u32 wmask_bits			: 15;
> +		u32 reserve0			: 1;
> +	} reg015;
> +
> +	struct swreg016_error_ctrl_set {
> +		u32 error_proc_disable		: 1;
> +		u32 reserve0			: 7;
> +		u32 error_spread_disable	: 1;
> +		u32 reserve1			: 15;
> +		u32 roi_error_ctu_cal_en	: 1;
> +		u32 reserve2			: 7;
> +	} reg016;
> +
> +	struct swreg017_err_roi_ctu_offset_start {
> +		u32 roi_x_ctu_offset_st		: 12;
> +		u32 reserve0			: 4;
> +		u32 roi_y_ctu_offset_st		: 12;
> +		u32 reserve1			: 4;
> +	} reg017;
> +
> +	struct swreg018_err_roi_ctu_offset_end {
> +		u32 roi_x_ctu_offset_end	: 12;
> +		u32 reserve0			: 4;
> +		u32 roi_y_ctu_offset_end	: 12;
> +		u32 reserve1			: 4;
> +	} reg018;
> +
> +	struct swreg019_error_ref_info {
> +		u32 avs2_ref_error_field	: 1;
> +		u32 avs2_ref_error_topfield	: 1;
> +		u32 ref_error_topfield_used	: 1;
> +		u32 ref_error_botfield_used	: 1;
> +		u32 reserve0			: 28;
> +	} reg019;
> +
> +	u32 reg020_cabac_error_en_lowbits;
> +	u32 reg021_cabac_error_en_highbits;
> +
> +	u32 reg022_reserved;
> +
> +	struct swreg023_invalid_pixel_fill {
> +		u32 fill_y			: 10;
> +		u32 fill_u			: 10;
> +		u32 fill_v			: 10;
> +		u32 reserve0			: 2;
> +	} reg023;
> +
> +	u32 reg024_026_reserved[3];
> +
> +	struct swreg027_align_en {
> +		u32 reserve0			: 4;
> +		u32 ctu_align_wr_en		: 1;
> +		u32 reserve1			: 27;
> +	} reg027;
> +
> +	struct swreg028_debug_perf_latency_ctrl0 {
> +		u32 axi_perf_work_e		: 1;
> +		u32 reserve0			: 2;
> +		u32 axi_cnt_type		: 1;
> +		u32 rd_latency_id		: 8;
> +		u32 reserve1			: 4;
> +		u32 rd_latency_thr		: 12;
> +		u32 reserve2			: 4;
> +	} reg028;
> +
> +	struct swreg029_debug_perf_latency_ctrl1 {
> +		u32 addr_align_type		: 2;
> +		u32 ar_cnt_id_type		: 1;
> +		u32 aw_cnt_id_type		: 1;
> +		u32 ar_count_id			: 8;
> +		u32 reserve0			: 4;
> +		u32 aw_count_id			: 8;
> +		u32 rd_band_width_mode		: 1;
> +		u32 reserve1			: 7;
> +	} reg029;
> +
> +	struct swreg030_qos_ctrl {
> +		u32 axi_wr_qos_level		: 4;
> +		u32 reserve0			: 4;
> +		u32 axi_wr_qos			: 4;
> +		u32 reserve1			: 4;
> +		u32 axi_rd_qos_level		: 4;
> +		u32 reserve2			: 4;
> +		u32 axi_rd_qos			: 4;
> +		u32 reserve3			: 4;
> +	} reg030;
> +};
> +
> +struct vdpu383_regs_common_addr {
> +	u32 reg128_strm_base;
> +	u32 reg129_rps_base;
> +	u32 reg130_cabactbl_base;
> +	u32 reg131_gbl_base;
> +	u32 reg132_scanlist_addr;
> +	u32 reg133_scale_down_base;
> +	u32 reg134_fgs_base;
> +	u32 reg135_139_reserved[5];
> +
> +	struct rcb_info {
> +	u32 offset;
> +	u32 size;
> +	} reg140_162_rcb_info[11];
> +};
> +
> +struct vdpu383_regs_h26x_addr {
> +	u32 reg168_decout_base;
> +	u32 reg169_error_ref_base;
> +	u32 reg170_185_ref_base[16];
> +	u32 reg186_191_reserved[6];
> +	u32 reg192_payload_st_cur_base;
> +	u32 reg193_fbc_payload_offset;
> +	u32 reg194_payload_st_error_ref_base;
> +	u32 reg195_210_payload_st_ref_base[16];
> +	u32 reg211_215_reserved[5];
> +	u32 reg216_colmv_cur_base;
> +	u32 reg217_232_colmv_ref_base[16];
> +};
> +
> +struct vdpu383_regs_h26x_params {
> +	u32 reg064_start_decoder;
> +	u32 reg065_strm_start_bit;
> +	u32 reg066_stream_len;
> +	u32 reg067_global_len;
> +	u32 reg068_hor_virstride;
> +	u32 reg069_raster_uv_hor_virstride;
> +	u32 reg070_y_virstride;
> +	u32 reg071_scl_ref_hor_virstride;
> +	u32 reg072_scl_ref_raster_uv_hor_virstride;
> +	u32 reg073_scl_ref_virstride;
> +	u32 reg074_fgs_ref_hor_virstride;
> +	u32 reg075_079_reserved[5];
> +	u32 reg080_error_ref_hor_virstride;
> +	u32 reg081_error_ref_raster_uv_hor_virstride;
> +	u32 reg082_error_ref_virstride;
> +	u32 reg083_ref0_hor_virstride;
> +	u32 reg084_ref0_raster_uv_hor_virstride;
> +	u32 reg085_ref0_virstride;
> +	u32 reg086_ref1_hor_virstride;
> +	u32 reg087_ref1_raster_uv_hor_virstride;
> +	u32 reg088_ref1_virstride;
> +	u32 reg089_ref2_hor_virstride;
> +	u32 reg090_ref2_raster_uv_hor_virstride;
> +	u32 reg091_ref2_virstride;
> +	u32 reg092_ref3_hor_virstride;
> +	u32 reg093_ref3_raster_uv_hor_virstride;
> +	u32 reg094_ref3_virstride;
> +	u32 reg095_ref4_hor_virstride;
> +	u32 reg096_ref4_raster_uv_hor_virstride;
> +	u32 reg097_ref4_virstride;
> +	u32 reg098_ref5_hor_virstride;
> +	u32 reg099_ref5_raster_uv_hor_virstride;
> +	u32 reg100_ref5_virstride;
> +	u32 reg101_ref6_hor_virstride;
> +	u32 reg102_ref6_raster_uv_hor_virstride;
> +	u32 reg103_ref6_virstride;
> +	u32 reg104_ref7_hor_virstride;
> +	u32 reg105_ref7_raster_uv_hor_virstride;
> +	u32 reg106_ref7_virstride;
> +};
> +
> +struct vdpu383_regs_h26x {
> +	struct vdpu383_regs_common		common;		/* 8-30 */
> +	struct vdpu383_regs_h26x_params		h26x_params;	/* 64-74, 80-106 */
> +	struct vdpu383_regs_common_addr		common_addr;	/* 128-134, 140-161 */
> +	struct vdpu383_regs_h26x_addr		h26x_addr;	/* 168-185, 192-210, 216-232 */
> +} __packed;
> +
> +#endif /* __RKVDEC_VDPU838_REGS_H__ */
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> index ecf6b9051543..1837f12f1aa1 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> @@ -9,6 +9,7 @@
> ? * Copyright (C) 2011 Samsung Electronics Co., Ltd.
> ? */
> ?
> +#include <linux/hw_bitfield.h>
> ?#include <linux/clk.h>
> ?#include <linux/genalloc.h>
> ?#include <linux/interrupt.h>
> @@ -30,6 +31,7 @@
> ?#include "rkvdec.h"
> ?#include "rkvdec-regs.h"
> ?#include "rkvdec-vdpu381-regs.h"
> +#include "rkvdec-vdpu383-regs.h"
> ?#include "rkvdec-rcb.h"
> ?
> ?static bool rkvdec_image_fmt_match(enum rkvdec_image_fmt fmt1,
> @@ -86,17 +88,27 @@ static bool rkvdec_is_valid_fmt(struct rkvdec_ctx *ctx, u32 fourcc,
> ?	return false;
> ?}
> ?
> +static u32 rkvdec_colmv_size(u16 width, u16 height)
> +{
> +	return 128 * DIV_ROUND_UP(width, 16) * DIV_ROUND_UP(height, 16);
> +}
> +
> +static u32 rkvdec_vdpu383_colmv_size(u16 width, u16 height)
> +{
> +	return ALIGN(width, 64) * ALIGN(height, 16);
> +}
> +
> ?static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx,
> ?				?????? struct v4l2_pix_format_mplane *pix_mp)
> ?{
> +	const struct rkvdec_config *cfg = ctx->dev->variant->config;
> +
> ?	v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat,
> ?			??? pix_mp->width, pix_mp->height);
> ?
> ?	ctx->colmv_offset = pix_mp->plane_fmt[0].sizeimage;
> ?
> -	pix_mp->plane_fmt[0].sizeimage += 128 *
> -		DIV_ROUND_UP(pix_mp->width, 16) *
> -		DIV_ROUND_UP(pix_mp->height, 16);
> +	pix_mp->plane_fmt[0].sizeimage += cfg->colmv_size(pix_mp->width, pix_mp->height);
> ?}
> ?
> ?static void rkvdec_reset_fmt(struct rkvdec_ctx *ctx, struct v4l2_format *f,
> @@ -391,6 +403,26 @@ static const struct rkvdec_coded_fmt_desc vdpu381_coded_fmts[] = {
> ?	},
> ?};
> ?
> +static const struct rkvdec_coded_fmt_desc vdpu383_coded_fmts[] = {
> +	{
> +		.fourcc = V4L2_PIX_FMT_H264_SLICE,
> +		.frmsize = {
> +			.min_width = 64,
> +			.max_width =? 65520,
> +			.step_width = 64,
> +			.min_height = 64,
> +			.max_height =? 65520,
> +			.step_height = 16,

Could possibly be initialize with a common macro since it seems shared.

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> +		},
> +		.ctrls = &rkvdec_h264_ctrls,
> +		.ops = &rkvdec_vdpu383_h264_fmt_ops,
> +		.num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts),
> +		.decoded_fmts = rkvdec_h264_decoded_fmts,
> +		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
> +		.capability = RKVDEC_CAPABILITY_H264,
> +	},
> +};
> +
> ?static bool rkvdec_is_capable(struct rkvdec_ctx *ctx, unsigned int capability)
> ?{
> ?	return (ctx->dev->variant->capabilities & capability) == capability;
> @@ -1294,6 +1326,35 @@ static irqreturn_t vdpu381_irq_handler(struct rkvdec_ctx *ctx)
> ?	return IRQ_HANDLED;
> ?}
> ?
> +static irqreturn_t vdpu383_irq_handler(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	enum vb2_buffer_state state;
> +	bool need_reset = 0;
> +	u32 status;
> +
> +	status = readl(rkvdec->link + VDPU383_LINK_STA_INT);
> +	writel(FIELD_PREP_WM16(VDPU383_STA_INT_ALL, 0), rkvdec->link + VDPU383_LINK_STA_INT);
> +	/* On vdpu383, the interrupts must be disabled */
> +	writel(FIELD_PREP_WM16(VDPU383_INT_EN_IRQ | VDPU383_INT_EN_LINE_IRQ, 0),
> +	?????? rkvdec->link + VDPU383_LINK_INT_EN);
> +
> +	if (status & VDPU383_STA_INT_DEC_RDY_STA) {
> +		state = VB2_BUF_STATE_DONE;
> +	} else {
> +		state = VB2_BUF_STATE_ERROR;
> +		rkvdec_iommu_restore(rkvdec);
> +	}
> +
> +	if (need_reset)
> +		rkvdec_iommu_restore(rkvdec);
> +
> +	if (cancel_delayed_work(&rkvdec->watchdog_work))
> +		rkvdec_job_finish(ctx, state);
> +
> +	return IRQ_HANDLED;
> +}
> +
> ?static irqreturn_t rkvdec_irq_handler(int irq, void *priv)
> ?{
> ?	struct rkvdec_dev *rkvdec = priv;
> @@ -1365,6 +1426,7 @@ static const struct rkvdec_config config_rkvdec = {
> ?	.coded_fmts = rkvdec_coded_fmts,
> ?	.coded_fmts_num = ARRAY_SIZE(rkvdec_coded_fmts),
> ?	.irq_handler = rk3399_irq_handler,
> +	.colmv_size = rkvdec_colmv_size,
> ?};
> ?
> ?static const struct rcb_size_info vdpu381_rcb_sizes[] = {
> @@ -1386,6 +1448,31 @@ static const struct rkvdec_config config_vdpu381 = {
> ?	.rcb_size_info = vdpu381_rcb_sizes,
> ?	.rcb_num = ARRAY_SIZE(vdpu381_rcb_sizes),
> ?	.irq_handler = vdpu381_irq_handler,
> +	.colmv_size = rkvdec_colmv_size,
> +	.named_regs = true,
> +};
> +
> +static const struct rcb_size_info vdpu383_rcb_sizes[] = {
> +	{6,	PIC_WIDTH},	// streamd
> +	{6,	PIC_WIDTH},	// streamd_tile
> +	{12,	PIC_WIDTH},	// inter
> +	{12,	PIC_WIDTH},	// inter_tile
> +	{16,	PIC_WIDTH},	// intra
> +	{10,	PIC_WIDTH},	// intra_tile
> +	{120,	PIC_WIDTH},	// filterd
> +	{120,	PIC_WIDTH},	// filterd_protect
> +	{120,	PIC_WIDTH},	// filterd_tile_row
> +	{180,	PIC_HEIGHT},	// filterd_tile_col
> +};
> +
> +static const struct rkvdec_config config_vdpu383 = {
> +	.coded_fmts = vdpu383_coded_fmts,
> +	.coded_fmts_num = ARRAY_SIZE(vdpu383_coded_fmts),
> +	.rcb_size_info = vdpu383_rcb_sizes,
> +	.rcb_num = ARRAY_SIZE(vdpu383_rcb_sizes),
> +	.irq_handler = vdpu383_irq_handler,
> +	.colmv_size = rkvdec_vdpu383_colmv_size,
> +	.named_regs = true,
> ?};
> ?
> ?static const struct rkvdec_variant rk3288_rkvdec_variant = {
> @@ -1416,6 +1503,11 @@ static const struct rkvdec_variant rk3588_vdpu381_variant = {
> ?	.capabilities = RKVDEC_CAPABILITY_H264,
> ?};
> ?
> +static const struct rkvdec_variant rk3576_vdpu383_variant = {
> +	.config = &config_vdpu383,
> +	.capabilities = RKVDEC_CAPABILITY_H264,
> +};
> +
> ?static const struct of_device_id of_rkvdec_match[] = {
> ?	{
> ?		.compatible = "rockchip,rk3288-vdec",
> @@ -1433,6 +1525,10 @@ static const struct of_device_id of_rkvdec_match[] = {
> ?		.compatible = "rockchip,rk3588-vdec",
> ?		.data = &rk3588_vdpu381_variant,
> ?	},
> +	{
> +		.compatible = "rockchip,rk3576-vdec",
> +		.data = &rk3576_vdpu383_variant,
> +	},
> ?	{ /* sentinel */ }
> ?};
> ?MODULE_DEVICE_TABLE(of, of_rkvdec_match);
> @@ -1468,9 +1564,19 @@ static int rkvdec_probe(struct platform_device *pdev)
> ?	rkvdec->clk_count = ret;
> ?	rkvdec->axi_clk = devm_clk_get(&pdev->dev, "axi");
> ?
> -	rkvdec->regs = devm_platform_ioremap_resource(pdev, 0);
> -	if (IS_ERR(rkvdec->regs))
> -		return PTR_ERR(rkvdec->regs);
> +	if (rkvdec->variant->config->named_regs) {
> +		rkvdec->regs = devm_platform_ioremap_resource_byname(pdev, "function");
> +		if (IS_ERR(rkvdec->regs))
> +			return PTR_ERR(rkvdec->regs);
> +
> +		rkvdec->link = devm_platform_ioremap_resource_byname(pdev, "link");
> +		if (IS_ERR(rkvdec->link))
> +			return PTR_ERR(rkvdec->link);
> +	} else {
> +		rkvdec->regs = devm_platform_ioremap_resource(pdev, 0);
> +		if (IS_ERR(rkvdec->regs))
> +			return PTR_ERR(rkvdec->regs);
> +	}
> ?
> ?	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
> ?	if (ret) {
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> index 5b86f5b85d20..e752706e9f5c 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> @@ -122,6 +122,8 @@ struct rkvdec_config {
> ?	const struct rcb_size_info *rcb_size_info;
> ?	size_t rcb_num;
> ?	irqreturn_t (*irq_handler)(struct rkvdec_ctx *ctx);
> +	u32 (*colmv_size)(u16 width, u16 height);
> +	bool named_regs;
> ?};
> ?
> ?struct rkvdec_dev {
> @@ -134,6 +136,7 @@ struct rkvdec_dev {
> ?	unsigned int clk_count;
> ?	struct clk *axi_clk;
> ?	void __iomem *regs;
> +	void __iomem *link;
> ?	struct mutex vdev_lock; /* serializes ioctls */
> ?	struct delayed_work watchdog_work;
> ?	struct gen_pool *sram_pool;
> @@ -178,10 +181,15 @@ void rkvdec_memcpy_toio(void __iomem *dst, void *src, size_t len);
> ?
> ?void rkvdec_quirks_disable_qos(struct rkvdec_ctx *ctx);
> ?
> +/* RKVDEC ops */
> ?extern const struct rkvdec_coded_fmt_ops rkvdec_h264_fmt_ops;
> ?extern const struct rkvdec_coded_fmt_ops rkvdec_hevc_fmt_ops;
> ?extern const struct rkvdec_coded_fmt_ops rkvdec_vp9_fmt_ops;
> ?
> +/* VDPU381 ops */
> ?extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_h264_fmt_ops;
> ?
> +/* VDPU383 ops */
> +extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu383_h264_fmt_ops;
> +
> ?#endif /* RKVDEC_H_ */
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251210/08f7ac88/attachment-0001.sig>

From nicolas.dufresne at collabora.com  Wed Dec 10 12:46:33 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Wed, 10 Dec 2025 15:46:33 -0500
Subject: [PATCH v4 14/15] media: rkvdec: Add HEVC support for the
 VDPU381 variant
In-Reply-To: <20251022174508.284929-15-detlev.casanova@collabora.com>
References: <20251022174508.284929-1-detlev.casanova@collabora.com>
	 <20251022174508.284929-15-detlev.casanova@collabora.com>
Message-ID: <46649ae5ec356e4e5198755fc28ef0d12cba606a.camel@collabora.com>

Le mercredi 22 octobre 2025 ? 13:45 -0400, Detlev Casanova a ?crit?:
> The VDPU381 supports HEVC decoding up to 7680x4320 at 30fps.
> It could double that when using both decoder cores.
> 
> It support YUV420 (8 and 10 bits) as well as AFBC (not implemented
> here)
> 
> The fluster score is 146/147 for JCT-VC-HEVC_V1, tested on ROCK 5B.
> None of the other test suites works.
> 
> Tested-by: Diederik de Haas <didi.debian at cknow.org>? # Rock 5B
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>


> ---
> ?.../media/platform/rockchip/rkvdec/Kconfig??? |?? 1 +
> ?.../media/platform/rockchip/rkvdec/Makefile?? |?? 1 +
> ?.../rockchip/rkvdec/rkvdec-hevc-common.c????? | 392 +++++++++++-
> ?.../rockchip/rkvdec/rkvdec-hevc-common.h????? |? 74 ++-
> ?.../rockchip/rkvdec/rkvdec-vdpu381-hevc.c???? | 596 ++++++++++++++++++
> ?.../media/platform/rockchip/rkvdec/rkvdec.c?? |? 86 ++-
> ?.../media/platform/rockchip/rkvdec/rkvdec.h?? |?? 3 +
> ?7 files changed, 1114 insertions(+), 39 deletions(-)
> ?create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/Kconfig b/drivers/media/platform/rockchip/rkvdec/Kconfig
> index 5f3bdd848a2c..3303b0ce3280 100644
> --- a/drivers/media/platform/rockchip/rkvdec/Kconfig
> +++ b/drivers/media/platform/rockchip/rkvdec/Kconfig
> @@ -8,6 +8,7 @@ config VIDEO_ROCKCHIP_VDEC
> ?	select VIDEOBUF2_VMALLOC
> ?	select V4L2_MEM2MEM_DEV
> ?	select V4L2_H264
> +	select V4L2_HEVC
> ?	select V4L2_VP9
> ?	help
> ?	? Support for the Rockchip Video Decoder IP present on Rockchip SoCs,
> diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
> index a58d4aede2fe..e30fdd7d51c3 100644
> --- a/drivers/media/platform/rockchip/rkvdec/Makefile
> +++ b/drivers/media/platform/rockchip/rkvdec/Makefile
> @@ -9,5 +9,6 @@ rockchip-vdec-y += \
> ?		?? rkvdec-hevc-common.o \
> ?		?? rkvdec-rcb.o \
> ?		?? rkvdec-vdpu381-h264.o \
> +		?? rkvdec-vdpu381-hevc.o \
> ?		?? rkvdec-vdpu383-h264.o \
> ?		?? rkvdec-vp9.o
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
> index d571107f2242..4b21b3ea67fd 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
> @@ -21,6 +21,143 @@
> ?#include "rkvdec.h"
> ?#include "rkvdec-hevc-common.h"
> ?
> +#define RKVDEC_HEVC_MAX_DEPTH_IN_BYTES		2
> +
> +/* Store the Short term ref pic set calculated values */
> +struct calculated_rps_st_set {
> +	u8 num_delta_pocs;
> +	u8 num_negative_pics;
> +	u8 num_positive_pics;
> +	u8 used_by_curr_pic_s0[16];
> +	u8 used_by_curr_pic_s1[16];
> +	s32 delta_poc_s0[16];
> +	s32 delta_poc_s1[16];
> +};
> +
> +enum rkvdec_image_fmt rkvdec_hevc_get_image_fmt(struct rkvdec_ctx *ctx,
> +						struct v4l2_ctrl *ctrl)
> +{
> +	const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps;
> +
> +	if (ctrl->id != V4L2_CID_STATELESS_HEVC_SPS)
> +		return RKVDEC_IMG_FMT_ANY;
> +
> +	if (sps->bit_depth_luma_minus8 == 0)
> +		return RKVDEC_IMG_FMT_420_8BIT;
> +	else if (sps->bit_depth_luma_minus8 == 2)
> +		return RKVDEC_IMG_FMT_420_10BIT;
> +
> +	return RKVDEC_IMG_FMT_ANY;
> +}
> +
> +void compute_tiles_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size,
> +			?? u16 width, u16 height, s32 pic_in_cts_width,
> +			?? s32 pic_in_cts_height, u16 *column_width, u16 *row_height)
> +{
> +	const struct v4l2_ctrl_hevc_pps *pps = run->pps;
> +	int i;
> +
> +	for (i = 0; i < pps->num_tile_columns_minus1 + 1; i++)
> +		column_width[i] = ((i + 1) * pic_in_cts_width) /
> +				? (pps->num_tile_columns_minus1 + 1) -
> +				? (i * pic_in_cts_width) /
> +				? (pps->num_tile_columns_minus1 + 1);
> +
> +	for (i = 0; i < pps->num_tile_rows_minus1 + 1; i++)
> +		row_height[i] = ((i + 1) * pic_in_cts_height) /
> +				(pps->num_tile_rows_minus1 + 1) -
> +				(i * pic_in_cts_height) /
> +				(pps->num_tile_rows_minus1 + 1);
> +}
> +
> +void compute_tiles_non_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size,
> +			?????? u16 width, u16 height, s32 pic_in_cts_width,
> +			?????? s32 pic_in_cts_height, u16 *column_width, u16 *row_height)
> +{
> +	const struct v4l2_ctrl_hevc_pps *pps = run->pps;
> +	s32 sum = 0;
> +	int i;
> +
> +	for (i = 0; i < pps->num_tile_columns_minus1; i++) {
> +		column_width[i] = pps->column_width_minus1[i] + 1;
> +		sum += column_width[i];
> +	}
> +	column_width[i] = pic_in_cts_width - sum;
> +
> +	sum = 0;
> +	for (i = 0; i < pps->num_tile_rows_minus1; i++) {
> +		row_height[i] = pps->row_height_minus1[i] + 1;
> +		sum += row_height[i];
> +	}
> +	row_height[i] = pic_in_cts_height - sum;
> +}
> +
> +static void set_ref_poc(struct rkvdec_rps_short_term_ref_set *set, int poc, int value, int flag)
> +{
> +	switch (poc) {
> +	case 0:
> +		set->delta_poc0 = value;
> +		set->used_flag0 = flag;
> +		break;
> +	case 1:
> +		set->delta_poc1 = value;
> +		set->used_flag1 = flag;
> +		break;
> +	case 2:
> +		set->delta_poc2 = value;
> +		set->used_flag2 = flag;
> +		break;
> +	case 3:
> +		set->delta_poc3 = value;
> +		set->used_flag3 = flag;
> +		break;
> +	case 4:
> +		set->delta_poc4 = value;
> +		set->used_flag4 = flag;
> +		break;
> +	case 5:
> +		set->delta_poc5 = value;
> +		set->used_flag5 = flag;
> +		break;
> +	case 6:
> +		set->delta_poc6 = value;
> +		set->used_flag6 = flag;
> +		break;
> +	case 7:
> +		set->delta_poc7 = value;
> +		set->used_flag7 = flag;
> +		break;
> +	case 8:
> +		set->delta_poc8 = value;
> +		set->used_flag8 = flag;
> +		break;
> +	case 9:
> +		set->delta_poc9 = value;
> +		set->used_flag9 = flag;
> +		break;
> +	case 10:
> +		set->delta_poc10 = value;
> +		set->used_flag10 = flag;
> +		break;
> +	case 11:
> +		set->delta_poc11 = value;
> +		set->used_flag11 = flag;
> +		break;
> +	case 12:
> +		set->delta_poc12 = value;
> +		set->used_flag12 = flag;
> +		break;
> +	case 13:
> +		set->delta_poc13 = value;
> +		set->used_flag13 = flag;
> +		break;
> +	case 14:
> +		set->delta_poc14 = value;
> +		set->used_flag14 = flag;
> +		break;
> +	}
> +}
> +
> ?/*
> ? * Flip one or more matrices along their main diagonal and flatten them
> ? * before writing it to the memory.
> @@ -105,7 +242,7 @@ static void translate_scaling_list(struct scaling_factor *output,
> ?}
> ?
> ?void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
> -					? struct scaling_factor *scaling_factor,
> +					? struct scaling_factor *scaling_list,
> ?					? struct v4l2_ctrl_hevc_scaling_matrix *cache)
> ?{
> ?	const struct v4l2_ctrl_hevc_scaling_matrix *scaling = run->scaling_matrix;
> @@ -114,15 +251,220 @@ void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
> ?		??? sizeof(struct v4l2_ctrl_hevc_scaling_matrix)))
> ?		return;
> ?
> -	translate_scaling_list(scaling_factor, scaling);
> +	translate_scaling_list(scaling_list, scaling);
> ?
> ?	memcpy(cache, scaling,
> ?	?????? sizeof(struct v4l2_ctrl_hevc_scaling_matrix));
> ?}
> ?
> -struct vb2_buffer *
> -get_ref_buf(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run,
> -	??? unsigned int dpb_idx)
> +static void rkvdec_hevc_assemble_hw_lt_rps(struct rkvdec_hevc_run *run, struct rkvdec_rps *rps)
> +{
> +	const struct v4l2_ctrl_hevc_sps *sps = run->sps;
> +
> +	if (!run->ext_sps_lt_rps)
> +		return;
> +
> +	for (int i = 0; i < sps->num_long_term_ref_pics_sps; i++) {
> +		rps->refs[i].lt_ref_pic_poc_lsb =
> +			run->ext_sps_lt_rps[i].lt_ref_pic_poc_lsb_sps;
> +		rps->refs[i].used_by_curr_pic_lt_flag =
> +			!!(run->ext_sps_lt_rps[i].flags & V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_USED_LT);
> +	}
> +}
> +
> +static void rkvdec_hevc_assemble_hw_st_rps(struct rkvdec_hevc_run *run, struct rkvdec_rps *rps,
> +					?? struct calculated_rps_st_set *calculated_rps_st_sets)
> +{
> +	const struct v4l2_ctrl_hevc_sps *sps = run->sps;
> +
> +	for (int i = 0; i < sps->num_short_term_ref_pic_sets; i++) {
> +		int poc = 0;
> +		int j = 0;
> +		const struct calculated_rps_st_set *set = &calculated_rps_st_sets[i];
> +
> +		rps->short_term_ref_sets[i].num_negative = set->num_negative_pics;
> +		rps->short_term_ref_sets[i].num_positive = set->num_positive_pics;
> +
> +		for (; j < set->num_negative_pics; j++) {
> +			set_ref_poc(&rps->short_term_ref_sets[i], j,
> +				??? set->delta_poc_s0[j], set->used_by_curr_pic_s0[j]);
> +		}
> +		poc = j;
> +
> +		for (j = 0; j < set->num_positive_pics; j++) {
> +			set_ref_poc(&rps->short_term_ref_sets[i], poc + j,
> +				??? set->delta_poc_s1[j], set->used_by_curr_pic_s1[j]);
> +		}
> +	}
> +}
> +
> +/*
> + * Compute the short term ref pic set parameters based on its reference short term ref pic
> + */
> +static void st_ref_pic_set_prediction(struct rkvdec_hevc_run *run, int idx,
> +				????? struct calculated_rps_st_set *calculated_rps_st_sets)
> +{
> +	const struct v4l2_ctrl_hevc_ext_sps_st_rps *rps_data = &run->ext_sps_st_rps[idx];
> +	struct calculated_rps_st_set *st_rps = &calculated_rps_st_sets[idx];
> +	struct calculated_rps_st_set *ref_rps;
> +	u8 st_rps_idx = idx;
> +	u8 ref_rps_idx = 0;
> +	s16 delta_rps = 0;
> +	u8 use_delta_flag[16] = { 0 };
> +	u8 used_by_curr_pic_flag[16] = { 0 };
> +	int i, j;
> +	int dPoc;
> +
> +	ref_rps_idx = st_rps_idx - (rps_data->delta_idx_minus1 + 1); /* 7-59 */
> +	delta_rps = (1 - 2 * rps_data->delta_rps_sign) *
> +		?? (rps_data->abs_delta_rps_minus1 + 1); /* 7-60 */
> +
> +	ref_rps = &calculated_rps_st_sets[ref_rps_idx];
> +
> +	for (j = 0; j <= ref_rps->num_delta_pocs; j++) {
> +		used_by_curr_pic_flag[j] = !!(rps_data->used_by_curr_pic & (1 << j));
> +		use_delta_flag[j] = !!(rps_data->use_delta_flag & (1 << j));
> +	}
> +
> +	/* 7-61: calculate num_negative_pics, delta_poc_s0 and used_by_curr_pic_s0 */
> +	i = 0;
> +	for (j = (ref_rps->num_positive_pics - 1); j >= 0; j--) {
> +		dPoc = ref_rps->delta_poc_s1[j] + delta_rps;
> +		if (dPoc < 0 && use_delta_flag[ref_rps->num_negative_pics + j]) {
> +			st_rps->delta_poc_s0[i] = dPoc;
> +			st_rps->used_by_curr_pic_s0[i++] =
> +				used_by_curr_pic_flag[ref_rps->num_negative_pics + j];
> +		}
> +	}
> +	if (delta_rps < 0 && use_delta_flag[ref_rps->num_delta_pocs]) {
> +		st_rps->delta_poc_s0[i] = delta_rps;
> +		st_rps->used_by_curr_pic_s0[i++] = used_by_curr_pic_flag[ref_rps->num_delta_pocs];
> +	}
> +	for (j = 0; j < ref_rps->num_negative_pics; j++) {
> +		dPoc = ref_rps->delta_poc_s0[j] + delta_rps;
> +		if (dPoc < 0 && use_delta_flag[j]) {
> +			st_rps->delta_poc_s0[i] = dPoc;
> +			st_rps->used_by_curr_pic_s0[i++] = used_by_curr_pic_flag[j];
> +		}
> +	}
> +	st_rps->num_negative_pics = i;
> +
> +	/* 7-62: calculate num_positive_pics, delta_poc_s1 and used_by_curr_pic_s1 */
> +	i = 0;
> +	for (j = (ref_rps->num_negative_pics - 1); j >= 0; j--) {
> +		dPoc = ref_rps->delta_poc_s0[j] + delta_rps;
> +		if (dPoc > 0 && use_delta_flag[j]) {
> +			st_rps->delta_poc_s1[i] = dPoc;
> +			st_rps->used_by_curr_pic_s1[i++] = used_by_curr_pic_flag[j];
> +		}
> +	}
> +	if (delta_rps > 0 && use_delta_flag[ref_rps->num_delta_pocs]) {
> +		st_rps->delta_poc_s1[i] = delta_rps;
> +		st_rps->used_by_curr_pic_s1[i++] = used_by_curr_pic_flag[ref_rps->num_delta_pocs];
> +	}
> +	for (j = 0; j < ref_rps->num_positive_pics; j++) {
> +		dPoc = ref_rps->delta_poc_s1[j] + delta_rps;
> +		if (dPoc > 0 && use_delta_flag[ref_rps->num_negative_pics + j]) {
> +			st_rps->delta_poc_s1[i] = dPoc;
> +			st_rps->used_by_curr_pic_s1[i++] =
> +				used_by_curr_pic_flag[ref_rps->num_negative_pics + j];
> +		}
> +	}
> +	st_rps->num_positive_pics = i;
> +
> +	st_rps->num_delta_pocs = st_rps->num_positive_pics + st_rps->num_negative_pics;
> +}
> +
> +/*
> + * Compute the short term ref pic set parameters based on the control's data.
> + */
> +static void st_ref_pic_set_calculate(struct rkvdec_hevc_run *run, int idx,
> +				???? struct calculated_rps_st_set *calculated_rps_st_sets)
> +{
> +	const struct v4l2_ctrl_hevc_ext_sps_st_rps *rps_data = &run->ext_sps_st_rps[idx];
> +	struct calculated_rps_st_set *st_rps = &calculated_rps_st_sets[idx];
> +	int j, i = 0;
> +
> +	/* 7-63 */
> +	st_rps->num_negative_pics = rps_data->num_negative_pics;
> +	/* 7-64 */
> +	st_rps->num_positive_pics = rps_data->num_positive_pics;
> +
> +	for (i = 0; i < st_rps->num_negative_pics; i++) {
> +		/* 7-65 */
> +		st_rps->used_by_curr_pic_s0[i] = !!(rps_data->used_by_curr_pic & (1 << i));
> +
> +		if (i == 0) {
> +			/* 7-67 */
> +			st_rps->delta_poc_s0[i] = -(rps_data->delta_poc_s0_minus1[i] + 1);
> +		} else {
> +			/* 7-69 */
> +			st_rps->delta_poc_s0[i] =
> +				st_rps->delta_poc_s0[i - 1] -
> +				(rps_data->delta_poc_s0_minus1[i] + 1);
> +		}
> +	}
> +
> +	for (j = 0; j < st_rps->num_positive_pics; j++) {
> +		/* 7-66 */
> +		st_rps->used_by_curr_pic_s1[j] = !!(rps_data->used_by_curr_pic & (1 << (i + j)));
> +
> +		if (j == 0) {
> +			/* 7-68 */
> +			st_rps->delta_poc_s1[j] = rps_data->delta_poc_s1_minus1[j] + 1;
> +		} else {
> +			/* 7-70 */
> +			st_rps->delta_poc_s1[j] =
> +				st_rps->delta_poc_s1[j - 1] +
> +				(rps_data->delta_poc_s1_minus1[j] + 1);
> +		}
> +	}
> +
> +	/* 7-71 */
> +	st_rps->num_delta_pocs = st_rps->num_positive_pics + st_rps->num_negative_pics;
> +}
> +
> +static void rkvdec_hevc_prepare_hw_st_rps(struct rkvdec_hevc_run *run, struct rkvdec_rps *rps,
> +					? struct v4l2_ctrl_hevc_ext_sps_st_rps *cache)
> +{
> +	int idx;
> +
> +	if (!run->ext_sps_st_rps)
> +		return;
> +
> +	if (!memcmp(cache, run->ext_sps_st_rps, sizeof(struct v4l2_ctrl_hevc_ext_sps_st_rps)))
> +		return;
> +
> +	struct calculated_rps_st_set *calculated_rps_st_sets =
> +		kzalloc(sizeof(struct calculated_rps_st_set) *
> +			run->sps->num_short_term_ref_pic_sets, GFP_KERNEL);
> +
> +	for (idx = 0; idx < run->sps->num_short_term_ref_pic_sets; idx++) {
> +		const struct v4l2_ctrl_hevc_ext_sps_st_rps *rps_data = &run->ext_sps_st_rps[idx];
> +
> +		if (rps_data->flags & V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED)
> +			st_ref_pic_set_prediction(run, idx, calculated_rps_st_sets);
> +		else
> +			st_ref_pic_set_calculate(run, idx, calculated_rps_st_sets);
> +	}
> +
> +	rkvdec_hevc_assemble_hw_st_rps(run, rps, calculated_rps_st_sets);
> +
> +	kfree(calculated_rps_st_sets);
> +
> +	memcpy(cache, run->ext_sps_st_rps, sizeof(struct v4l2_ctrl_hevc_ext_sps_st_rps));
> +}
> +
> +void rkvdec_hevc_assemble_hw_rps(struct rkvdec_hevc_run *run, struct rkvdec_rps *rps,
> +				 struct v4l2_ctrl_hevc_ext_sps_st_rps *st_cache)
> +{
> +	rkvdec_hevc_prepare_hw_st_rps(run, rps, st_cache);
> +	rkvdec_hevc_assemble_hw_lt_rps(run, rps);
> +}
> +
> +struct vb2_buffer *get_ref_buf(struct rkvdec_ctx *ctx,
> +			?????? struct rkvdec_hevc_run *run,
> +			?????? unsigned int dpb_idx)
> ?{
> ?	struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
> ?	const struct v4l2_ctrl_hevc_decode_params *decode_params = run->decode_params;
> @@ -143,8 +485,6 @@ get_ref_buf(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run,
> ?	return buf;
> ?}
> ?
> -#define RKVDEC_HEVC_MAX_DEPTH_IN_BYTES		2
> -
> ?int rkvdec_hevc_adjust_fmt(struct rkvdec_ctx *ctx, struct v4l2_format *f)
> ?{
> ?	struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp;
> @@ -156,38 +496,17 @@ int rkvdec_hevc_adjust_fmt(struct rkvdec_ctx *ctx, struct v4l2_format *f)
> ?	return 0;
> ?}
> ?
> -enum rkvdec_image_fmt rkvdec_hevc_get_image_fmt(struct rkvdec_ctx *ctx,
> -						struct v4l2_ctrl *ctrl)
> -{
> -	const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps;
> -
> -	if (ctrl->id != V4L2_CID_STATELESS_HEVC_SPS)
> -		return RKVDEC_IMG_FMT_ANY;
> -
> -	if (sps->bit_depth_luma_minus8 == 0) {
> -		if (sps->chroma_format_idc == 2)
> -			return RKVDEC_IMG_FMT_422_8BIT;
> -		else
> -			return RKVDEC_IMG_FMT_420_8BIT;
> -	} else if (sps->bit_depth_luma_minus8 == 2) {
> -		if (sps->chroma_format_idc == 2)
> -			return RKVDEC_IMG_FMT_422_10BIT;
> -		else
> -			return RKVDEC_IMG_FMT_420_10BIT;
> -	}
> -
> -	return RKVDEC_IMG_FMT_ANY;
> -}
> -
> -static int rkvdec_hevc_validate_sps(struct rkvdec_ctx *ctx,
> +int rkvdec_hevc_validate_sps(struct rkvdec_ctx *ctx,
> ?			???? const struct v4l2_ctrl_hevc_sps *sps)
> ?{
> ?	if (sps->chroma_format_idc > 1)
> ?		/* Only 4:0:0 and 4:2:0 are supported */
> ?		return -EINVAL;
> +
> ?	if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
> ?		/* Luma and chroma bit depth mismatch */
> ?		return -EINVAL;
> +
> ?	if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2)
> ?		/* Only 8-bit and 10-bit are supported */
> ?		return -EINVAL;
> @@ -221,6 +540,17 @@ void rkvdec_hevc_run_preamble(struct rkvdec_ctx *ctx,
> ?			????? V4L2_CID_STATELESS_HEVC_SCALING_MATRIX);
> ?	run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL;
> ?
> +	if (ctx->has_sps_st_rps) {
> +		ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> +				????? V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS);
> +		run->ext_sps_st_rps = ctrl ? ctrl->p_cur.p : NULL;
> +	}
> +	if (ctx->has_sps_lt_rps) {
> +		ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> +				????? V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS);
> +		run->ext_sps_lt_rps = ctrl ? ctrl->p_cur.p : NULL;
> +	}
> +
> ?	rkvdec_run_preamble(ctx, &run->base);
> ?}
> ?
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
> index 746b1bd73c08..0005b80bad79 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
> @@ -16,19 +16,70 @@
> ? */
> ?
> ?#include <media/v4l2-mem2mem.h>
> +#include <linux/types.h>
> ?#include "rkvdec.h"
> ?
> ?#define RKV_HEVC_CABAC_TABLE_SIZE		27456
> ?extern const u8 rkvdec_hevc_cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
> ?
> +struct rkvdec_rps_refs {
> +	u16 lt_ref_pic_poc_lsb;
> +	u16 used_by_curr_pic_lt_flag	: 1;
> +	u16 reserved			: 15;
> +} __packed;
> +
> +struct rkvdec_rps_short_term_ref_set {
> +	u32 num_negative	: 4;
> +	u32 num_positive	: 4;
> +	u32 delta_poc0		: 16;
> +	u32 used_flag0		: 1;
> +	u32 delta_poc1		: 16;
> +	u32 used_flag1		: 1;
> +	u32 delta_poc2		: 16;
> +	u32 used_flag2		: 1;
> +	u32 delta_poc3		: 16;
> +	u32 used_flag3		: 1;
> +	u32 delta_poc4		: 16;
> +	u32 used_flag4		: 1;
> +	u32 delta_poc5		: 16;
> +	u32 used_flag5		: 1;
> +	u32 delta_poc6		: 16;
> +	u32 used_flag6		: 1;
> +	u32 delta_poc7		: 16;
> +	u32 used_flag7		: 1;
> +	u32 delta_poc8		: 16;
> +	u32 used_flag8		: 1;
> +	u32 delta_poc9		: 16;
> +	u32 used_flag9		: 1;
> +	u32 delta_poc10		: 16;
> +	u32 used_flag10		: 1;
> +	u32 delta_poc11		: 16;
> +	u32 used_flag11		: 1;
> +	u32 delta_poc12		: 16;
> +	u32 used_flag12		: 1;
> +	u32 delta_poc13		: 16;
> +	u32 used_flag13		: 1;
> +	u32 delta_poc14		: 16;
> +	u32 used_flag14		: 1;
> +	u32 reserved_bits	: 25;
> +	u32 reserved[3];
> +} __packed;
> +
> +struct rkvdec_rps {
> +	struct rkvdec_rps_refs refs[32];
> +	struct rkvdec_rps_short_term_ref_set short_term_ref_sets[64];
> +} __packed;
> +
> ?struct rkvdec_hevc_run {
> -	struct rkvdec_run base;
> -	const struct v4l2_ctrl_hevc_slice_params *slices_params;
> -	const struct v4l2_ctrl_hevc_decode_params *decode_params;
> -	const struct v4l2_ctrl_hevc_sps *sps;
> -	const struct v4l2_ctrl_hevc_pps *pps;
> -	const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix;
> -	int num_slices;
> +	struct rkvdec_run				base;
> +	const struct v4l2_ctrl_hevc_decode_params	*decode_params;
> +	const struct v4l2_ctrl_hevc_slice_params	*slices_params;
> +	const struct v4l2_ctrl_hevc_sps			*sps;
> +	const struct v4l2_ctrl_hevc_pps			*pps;
> +	const struct v4l2_ctrl_hevc_scaling_matrix	*scaling_matrix;
> +	const struct v4l2_ctrl_hevc_ext_sps_st_rps	*ext_sps_st_rps;
> +	const struct v4l2_ctrl_hevc_ext_sps_lt_rps	*ext_sps_lt_rps;
> +	int						num_slices;
> ?};
> ?
> ?struct scaling_factor {
> @@ -40,6 +91,14 @@ struct scaling_factor {
> ?
> ?enum rkvdec_image_fmt rkvdec_hevc_get_image_fmt(struct rkvdec_ctx *ctx,
> ?						struct v4l2_ctrl *ctrl);
> +void compute_tiles_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size,
> +			?? u16 width, u16 height, s32 pic_in_cts_width,
> +			?? s32 pic_in_cts_height, u16 *column_width, u16 *row_height);
> +void compute_tiles_non_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size,
> +			?????? u16 width, u16 height, s32 pic_in_cts_width,
> +			?????? s32 pic_in_cts_height, u16 *column_width, u16 *row_height);
> +void rkvdec_hevc_assemble_hw_rps(struct rkvdec_hevc_run *run, struct rkvdec_rps *rps,
> +				 struct v4l2_ctrl_hevc_ext_sps_st_rps *st_cache);
> ?void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
> ?					? struct scaling_factor *scaling_factor,
> ?					? struct v4l2_ctrl_hevc_scaling_matrix *cache);
> @@ -47,5 +106,6 @@ struct vb2_buffer *get_ref_buf(struct rkvdec_ctx *ctx,
> ?			?????? struct rkvdec_hevc_run *run,
> ?			?????? unsigned int dpb_idx);
> ?int rkvdec_hevc_adjust_fmt(struct rkvdec_ctx *ctx, struct v4l2_format *f);
> +int rkvdec_hevc_validate_sps(struct rkvdec_ctx *ctx, const struct v4l2_ctrl_hevc_sps *sps);
> ?int rkvdec_hevc_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl);
> ?void rkvdec_hevc_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run);
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
> new file mode 100644
> index 000000000000..278f1dbf0910
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
> @@ -0,0 +1,596 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Rockchip VDPU381 HEVC backend
> + *
> + * Copyright (C) 2025 Collabora, Ltd.
> + *? Detlev Casanova <detlev.casanova at collabora.com>
> + */
> +
> +#include <media/v4l2-mem2mem.h>
> +
> +#include "rkvdec.h"
> +#include "rkvdec-rcb.h"
> +#include "rkvdec-hevc-common.h"
> +#include "rkvdec-vdpu381-regs.h"
> +
> +// SPS
> +struct rkvdec_hevc_sps {
> +	u16 video_parameters_set_id			: 4;
> +	u16 seq_parameters_set_id_sps			: 4;
> +	u16 chroma_format_idc				: 2;
> +	u16 width					: 16;
> +	u16 height					: 16;
> +	u16 bit_depth_luma				: 4;
> +	u16 bit_depth_chroma				: 4;
> +	u16 max_pic_order_count_lsb			: 5;
> +	u16 diff_max_min_luma_coding_block_size		: 2;
> +	u16 min_luma_coding_block_size			: 3;
> +	u16 min_transform_block_size			: 3;
> +	u16 diff_max_min_transform_block_size		: 2;
> +	u16 max_transform_hierarchy_depth_inter		: 3;
> +	u16 max_transform_hierarchy_depth_intra		: 3;
> +	u16 scaling_list_enabled_flag			: 1;
> +	u16 amp_enabled_flag				: 1;
> +	u16 sample_adaptive_offset_enabled_flag		: 1;
> +	u16 pcm_enabled_flag				: 1;
> +	u16 pcm_sample_bit_depth_luma			: 4;
> +	u16 pcm_sample_bit_depth_chroma			: 4;
> +	u16 pcm_loop_filter_disabled_flag		: 1;
> +	u16 diff_max_min_pcm_luma_coding_block_size	: 3;
> +	u16 min_pcm_luma_coding_block_size		: 3;
> +	u16 num_short_term_ref_pic_sets			: 7;
> +	u16 long_term_ref_pics_present_flag		: 1;
> +	u16 num_long_term_ref_pics_sps			: 6;
> +	u16 sps_temporal_mvp_enabled_flag		: 1;
> +	u16 strong_intra_smoothing_enabled_flag		: 1;
> +	u16 reserved_0					: 7;
> +	u16 sps_max_dec_pic_buffering_minus1		: 4;
> +	u16 reserved_0_2				: 3;
> +	u16 reserved_f					: 8;
> +} __packed;
> +
> +//PPS
> +struct rkvdec_hevc_pps {
> +	u16 picture_parameters_set_id			: 6;
> +	u16 seq_parameters_set_id_pps			: 4;
> +	u16 dependent_slice_segments_enabled_flag	: 1;
> +	u16 output_flag_present_flag			: 1;
> +	u16 num_extra_slice_header_bits			: 13;
> +	u16 sign_data_hiding_enabled_flag		: 1;
> +	u16 cabac_init_present_flag			: 1;
> +	u16 num_ref_idx_l0_default_active		: 4;
> +	u16 num_ref_idx_l1_default_active		: 4;
> +	u16 init_qp_minus26				: 7;
> +	u16 constrained_intra_pred_flag			: 1;
> +	u16 transform_skip_enabled_flag			: 1;
> +	u16 cu_qp_delta_enabled_flag			: 1;
> +	u16 log2_min_cb_size				: 3;
> +	u16 pps_cb_qp_offset				: 5;
> +	u16 pps_cr_qp_offset				: 5;
> +	u16 pps_slice_chroma_qp_offsets_present_flag	: 1;
> +	u16 weighted_pred_flag				: 1;
> +	u16 weighted_bipred_flag			: 1;
> +	u16 transquant_bypass_enabled_flag		: 1;
> +	u16 tiles_enabled_flag				: 1;
> +	u16 entropy_coding_sync_enabled_flag		: 1;
> +	u16 pps_loop_filter_across_slices_enabled_flag	: 1;
> +	u16 loop_filter_across_tiles_enabled_flag	: 1;
> +	u16 deblocking_filter_override_enabled_flag	: 1;
> +	u16 pps_deblocking_filter_disabled_flag		: 1;
> +	u16 pps_beta_offset_div2			: 4;
> +	u16 pps_tc_offset_div2				: 4;
> +	u16 lists_modification_present_flag		: 1;
> +	u16 log2_parallel_merge_level			: 3;
> +	u16 slice_segment_header_extension_present_flag	: 1;
> +	u16 zeroes					: 3;
> +	u16 num_tile_columns				: 5;
> +	u16 num_tile_rows				: 5;
> +	u16 sps_pps_mode				: 4;
> +	u16 reserved_bits				: 14;
> +	u16 reserved;
> +} __packed;
> +
> +struct rkvdec_hevc_tile {
> +	u16 value0	: 12;
> +	u16 value1	: 12;
> +} __packed;
> +
> +struct rkvdec_sps_pps_packet {
> +	struct rkvdec_hevc_sps sps;
> +	struct rkvdec_hevc_pps pps;
> +	struct rkvdec_hevc_tile column_width[10];
> +	struct rkvdec_hevc_tile row_height[11];
> +	u32 zeroes[3];
> +	u32 zeroes_bits		: 6;
> +	u32 padding_bits	: 2;
> +	u32 padding;
> +} __packed;
> +
> +struct rkvdec_hevc_priv_tbl {
> +	struct rkvdec_sps_pps_packet param_set[64];
> +	struct rkvdec_rps rps;
> +	struct scaling_factor scaling_list;
> +	u8 cabac_table[27456];
> +};
> +
> +struct rkvdec_hevc_ctx {
> +	struct rkvdec_aux_buf			priv_tbl;
> +	struct v4l2_ctrl_hevc_scaling_matrix	scaling_matrix_cache;
> +	struct v4l2_ctrl_hevc_ext_sps_st_rps	st_cache;
> +	struct rkvdec_vdpu381_regs_hevc		regs;
> +};
> +
> +static void assemble_hw_pps(struct rkvdec_ctx *ctx,
> +			??? struct rkvdec_hevc_run *run)
> +{
> +	struct rkvdec_hevc_ctx *h264_ctx = ctx->priv;
> +	const struct v4l2_ctrl_hevc_sps *sps = run->sps;
> +	const struct v4l2_ctrl_hevc_pps *pps = run->pps;
> +	struct rkvdec_hevc_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu;
> +	struct rkvdec_sps_pps_packet *hw_ps;
> +	bool tiles_enabled;
> +	s32 max_cu_width;
> +	s32 pic_in_cts_width;
> +	s32 pic_in_cts_height;
> +	u16 log2_min_cb_size, width, height;
> +	u16 column_width[20];
> +	u16 row_height[22];
> +	u8 pcm_enabled;
> +	u32 i;
> +
> +	/*
> +	 * HW read the SPS/PPS information from PPS packet index by PPS id.
> +	 * offset from the base can be calculated by PPS_id * 32 (size per PPS
> +	 * packet unit). so the driver copy SPS/PPS information to the exact PPS
> +	 * packet unit for HW accessing.
> +	 */
> +	hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id];
> +	memset(hw_ps, 0, sizeof(*hw_ps));
> +
> +	/* write sps */
> +	hw_ps->sps.video_parameters_set_id = sps->video_parameter_set_id;
> +	hw_ps->sps.seq_parameters_set_id_sps = sps->seq_parameter_set_id;
> +	hw_ps->sps.chroma_format_idc = sps->chroma_format_idc;
> +
> +	log2_min_cb_size = sps->log2_min_luma_coding_block_size_minus3 + 3;
> +	width = sps->pic_width_in_luma_samples;
> +	height = sps->pic_height_in_luma_samples;
> +	hw_ps->sps.width = width;
> +	hw_ps->sps.height = height;
> +	hw_ps->sps.bit_depth_luma = sps->bit_depth_luma_minus8 + 8;
> +	hw_ps->sps.bit_depth_chroma = sps->bit_depth_chroma_minus8 + 8;
> +	hw_ps->sps.max_pic_order_count_lsb = sps->log2_max_pic_order_cnt_lsb_minus4 + 4;
> +	hw_ps->sps.diff_max_min_luma_coding_block_size =
> +		sps->log2_diff_max_min_luma_coding_block_size;
> +	hw_ps->sps.min_luma_coding_block_size = sps->log2_min_luma_coding_block_size_minus3 + 3;
> +	hw_ps->sps.min_transform_block_size = sps->log2_min_luma_transform_block_size_minus2 + 2;
> +	hw_ps->sps.diff_max_min_transform_block_size =
> +		sps->log2_diff_max_min_luma_transform_block_size;
> +	hw_ps->sps.max_transform_hierarchy_depth_inter = sps->max_transform_hierarchy_depth_inter;
> +	hw_ps->sps.max_transform_hierarchy_depth_intra = sps->max_transform_hierarchy_depth_intra;
> +	hw_ps->sps.scaling_list_enabled_flag =
> +		!!(sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED);
> +	hw_ps->sps.amp_enabled_flag = !!(sps->flags & V4L2_HEVC_SPS_FLAG_AMP_ENABLED);
> +	hw_ps->sps.sample_adaptive_offset_enabled_flag =
> +		!!(sps->flags & V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET);
> +
> +	pcm_enabled = !!(sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED);
> +	hw_ps->sps.pcm_enabled_flag = pcm_enabled;
> +	hw_ps->sps.pcm_sample_bit_depth_luma =
> +		pcm_enabled ? sps->pcm_sample_bit_depth_luma_minus1 + 1 : 0;
> +	hw_ps->sps.pcm_sample_bit_depth_chroma =
> +		pcm_enabled ? sps->pcm_sample_bit_depth_chroma_minus1 + 1 : 0;
> +	hw_ps->sps.pcm_loop_filter_disabled_flag =
> +		!!(sps->flags & V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED);
> +	hw_ps->sps.diff_max_min_pcm_luma_coding_block_size =
> +		sps->log2_diff_max_min_pcm_luma_coding_block_size;
> +	hw_ps->sps.min_pcm_luma_coding_block_size =
> +		pcm_enabled ? sps->log2_min_pcm_luma_coding_block_size_minus3 + 3 : 0;
> +	hw_ps->sps.num_short_term_ref_pic_sets = sps->num_short_term_ref_pic_sets;
> +	hw_ps->sps.long_term_ref_pics_present_flag =
> +		!!(sps->flags & V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT);
> +	hw_ps->sps.num_long_term_ref_pics_sps = sps->num_long_term_ref_pics_sps;
> +	hw_ps->sps.sps_temporal_mvp_enabled_flag =
> +		!!(sps->flags & V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED);
> +	hw_ps->sps.strong_intra_smoothing_enabled_flag =
> +		!!(sps->flags & V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED);
> +	hw_ps->sps.sps_max_dec_pic_buffering_minus1 = sps->sps_max_dec_pic_buffering_minus1;
> +	hw_ps->sps.reserved_f = 0xff;
> +
> +	/* write pps */
> +	hw_ps->pps.picture_parameters_set_id = pps->pic_parameter_set_id;
> +	hw_ps->pps.seq_parameters_set_id_pps = sps->seq_parameter_set_id;
> +	hw_ps->pps.dependent_slice_segments_enabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED);
> +	hw_ps->pps.output_flag_present_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT);
> +	hw_ps->pps.num_extra_slice_header_bits = pps->num_extra_slice_header_bits;
> +	hw_ps->pps.sign_data_hiding_enabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED);
> +	hw_ps->pps.cabac_init_present_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT);
> +	hw_ps->pps.num_ref_idx_l0_default_active = pps->num_ref_idx_l0_default_active_minus1 + 1;
> +	hw_ps->pps.num_ref_idx_l1_default_active = pps->num_ref_idx_l1_default_active_minus1 + 1;
> +	hw_ps->pps.init_qp_minus26 = pps->init_qp_minus26;
> +	hw_ps->pps.constrained_intra_pred_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED);
> +	hw_ps->pps.transform_skip_enabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED);
> +	hw_ps->pps.cu_qp_delta_enabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED);
> +	hw_ps->pps.log2_min_cb_size = log2_min_cb_size +
> +				????? sps->log2_diff_max_min_luma_coding_block_size -
> +				????? pps->diff_cu_qp_delta_depth;
> +	hw_ps->pps.pps_cb_qp_offset = pps->pps_cb_qp_offset;
> +	hw_ps->pps.pps_cr_qp_offset = pps->pps_cr_qp_offset;
> +	hw_ps->pps.pps_slice_chroma_qp_offsets_present_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT);
> +	hw_ps->pps.weighted_pred_flag = !!(pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED);
> +	hw_ps->pps.weighted_bipred_flag = !!(pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED);
> +	hw_ps->pps.transquant_bypass_enabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED);
> +
> +	tiles_enabled = !!(pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED);
> +	hw_ps->pps.tiles_enabled_flag = tiles_enabled;
> +	hw_ps->pps.entropy_coding_sync_enabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED);
> +	hw_ps->pps.pps_loop_filter_across_slices_enabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED);
> +	hw_ps->pps.loop_filter_across_tiles_enabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED);
> +	hw_ps->pps.deblocking_filter_override_enabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED);
> +	hw_ps->pps.pps_deblocking_filter_disabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER);
> +	hw_ps->pps.pps_beta_offset_div2 = pps->pps_beta_offset_div2;
> +	hw_ps->pps.pps_tc_offset_div2 = pps->pps_tc_offset_div2;
> +	hw_ps->pps.lists_modification_present_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT);
> +	hw_ps->pps.log2_parallel_merge_level = pps->log2_parallel_merge_level_minus2 + 2;
> +	hw_ps->pps.slice_segment_header_extension_present_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT);
> +	hw_ps->pps.num_tile_columns = tiles_enabled ? pps->num_tile_columns_minus1 + 1 : 0;
> +	hw_ps->pps.num_tile_rows = tiles_enabled ? pps->num_tile_rows_minus1 + 1 : 0;
> +	hw_ps->pps.sps_pps_mode = 0;
> +	hw_ps->pps.reserved_bits = 0x3fff;
> +	hw_ps->pps.reserved = 0xffff;
> +
> +	// Setup tiles information
> +	memset(column_width, 0, sizeof(column_width));
> +	memset(row_height, 0, sizeof(row_height));
> +
> +	max_cu_width = 1 << (sps->log2_diff_max_min_luma_coding_block_size + log2_min_cb_size);
> +	pic_in_cts_width = (width + max_cu_width - 1) / max_cu_width;
> +	pic_in_cts_height = (height + max_cu_width - 1) / max_cu_width;
> +
> +	if (pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED) {
> +		if (pps->flags & V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING) {
> +			compute_tiles_uniform(run, log2_min_cb_size, width, height,
> +					????? pic_in_cts_width, pic_in_cts_height,
> +					????? column_width, row_height);
> +		} else {
> +			compute_tiles_non_uniform(run, log2_min_cb_size, width, height,
> +						? pic_in_cts_width, pic_in_cts_height,
> +						? column_width, row_height);
> +		}
> +	} else {
> +		column_width[0] = (width + max_cu_width - 1) / max_cu_width;
> +		row_height[0] = (height + max_cu_width - 1) / max_cu_width;
> +	}
> +
> +	for (i = 0; i < 20; i++) {
> +		if (column_width[i] > 0)
> +			column_width[i]--;
> +
> +		if (i & 1)
> +			hw_ps->column_width[i / 2].value1 = column_width[i];
> +		else
> +			hw_ps->column_width[i / 2].value0 = column_width[i];
> +	}
> +
> +	for (i = 0; i < 22; i++) {
> +		if (row_height[i] > 0)
> +			row_height[i]--;
> +
> +		if (i & 1)
> +			hw_ps->row_height[i / 2].value1 = row_height[i];
> +		else
> +			hw_ps->row_height[i / 2].value0 = row_height[i];
> +	}
> +
> +	hw_ps->padding = 0xffffffff;
> +	hw_ps->padding_bits = 0x3;
> +}
> +
> +static void set_ref_valid(struct rkvdec_vdpu381_regs_hevc *regs, int id, u32 valid)
> +{
> +	switch (id) {
> +	case 0:
> +		regs->hevc_param.reg099.hevc_ref_valid_0 = valid;
> +		break;
> +	case 1:
> +		regs->hevc_param.reg099.hevc_ref_valid_1 = valid;
> +		break;
> +	case 2:
> +		regs->hevc_param.reg099.hevc_ref_valid_2 = valid;
> +		break;
> +	case 3:
> +		regs->hevc_param.reg099.hevc_ref_valid_3 = valid;
> +		break;
> +	case 4:
> +		regs->hevc_param.reg099.hevc_ref_valid_4 = valid;
> +		break;
> +	case 5:
> +		regs->hevc_param.reg099.hevc_ref_valid_5 = valid;
> +		break;
> +	case 6:
> +		regs->hevc_param.reg099.hevc_ref_valid_6 = valid;
> +		break;
> +	case 7:
> +		regs->hevc_param.reg099.hevc_ref_valid_7 = valid;
> +		break;
> +	case 8:
> +		regs->hevc_param.reg099.hevc_ref_valid_8 = valid;
> +		break;
> +	case 9:
> +		regs->hevc_param.reg099.hevc_ref_valid_9 = valid;
> +		break;
> +	case 10:
> +		regs->hevc_param.reg099.hevc_ref_valid_10 = valid;
> +		break;
> +	case 11:
> +		regs->hevc_param.reg099.hevc_ref_valid_11 = valid;
> +		break;
> +	case 12:
> +		regs->hevc_param.reg099.hevc_ref_valid_12 = valid;
> +		break;
> +	case 13:
> +		regs->hevc_param.reg099.hevc_ref_valid_13 = valid;
> +		break;
> +	case 14:
> +		regs->hevc_param.reg099.hevc_ref_valid_14 = valid;
> +		break;
> +	}
> +}
> +
> +static void rkvdec_write_regs(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
> +
> +	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_REGS,
> +			?? &hevc_ctx->regs.common,
> +			?? sizeof(hevc_ctx->regs.common));
> +	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_PARAMS_REGS,
> +			?? &hevc_ctx->regs.hevc_param,
> +			?? sizeof(hevc_ctx->regs.hevc_param));
> +	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_ADDR_REGS,
> +			?? &hevc_ctx->regs.common_addr,
> +			?? sizeof(hevc_ctx->regs.common_addr));
> +	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_ADDR_REGS,
> +			?? &hevc_ctx->regs.hevc_addr,
> +			?? sizeof(hevc_ctx->regs.hevc_addr));
> +	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_POC_HIGHBIT_REGS,
> +			?? &hevc_ctx->regs.hevc_highpoc,
> +			?? sizeof(hevc_ctx->regs.hevc_highpoc));
> +}
> +
> +static void config_registers(struct rkvdec_ctx *ctx,
> +			???? struct rkvdec_hevc_run *run)
> +{
> +	const struct v4l2_ctrl_hevc_decode_params *dec_params = run->decode_params;
> +	const struct v4l2_hevc_dpb_entry *dpb = dec_params->dpb;
> +	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
> +	struct rkvdec_vdpu381_regs_hevc *regs = &hevc_ctx->regs;
> +	dma_addr_t priv_start_addr = hevc_ctx->priv_tbl.dma;
> +	const struct v4l2_pix_format_mplane *dst_fmt;
> +	struct vb2_v4l2_buffer *src_buf = run->base.bufs.src;
> +	struct vb2_v4l2_buffer *dst_buf = run->base.bufs.dst;
> +	const struct v4l2_format *f;
> +	dma_addr_t rlc_addr;
> +	u32 hor_virstride = 0;
> +	u32 ver_virstride = 0;
> +	u32 y_virstride = 0;
> +	u32 offset;
> +	u32 pixels;
> +	dma_addr_t dst_addr;
> +	u32 i;
> +
> +	memset(regs, 0, sizeof(*regs));
> +
> +	/* Set HEVC mode */
> +	regs->common.reg009.dec_mode = VDPU381_MODE_HEVC;
> +
> +	/* Set config */
> +	regs->common.reg011.buf_empty_en = 1;
> +	regs->common.reg011.dec_clkgate_e = 1;
> +	regs->common.reg011.dec_timeout_e = 1;
> +	regs->common.reg011.pix_range_detection_e = 1;
> +
> +	/* Set IDR flag */
> +	regs->common.reg013.cur_pic_is_idr =
> +		!!(dec_params->flags & V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC);
> +
> +	/* Set input stream length */
> +	regs->common.stream_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
> +
> +	/* Set max slice number */
> +	regs->common.reg017.slice_num = 1;
> +
> +	/* Set strides */
> +	f = &ctx->decoded_fmt;
> +	dst_fmt = &f->fmt.pix_mp;
> +	hor_virstride = dst_fmt->plane_fmt[0].bytesperline;
> +	ver_virstride = dst_fmt->height;
> +	y_virstride = hor_virstride * ver_virstride;
> +	pixels = dst_fmt->height * dst_fmt->width;
> +
> +	regs->common.reg018.y_hor_virstride = hor_virstride / 16;
> +	regs->common.reg019.uv_hor_virstride = hor_virstride / 16;
> +	regs->common.reg020.y_virstride = y_virstride / 16;
> +
> +	/* Activate block gating */
> +	regs->common.reg026.swreg_block_gating_e = 0xfffef;
> +	regs->common.reg026.reg_cfg_gating_en = 1;
> +
> +	/* Set timeout threshold */
> +	if (pixels < RKVDEC_1080P_PIXELS)
> +		regs->common.timeout_threshold = RKVDEC_TIMEOUT_1080p;
> +	else if (pixels < RKVDEC_4K_PIXELS)
> +		regs->common.timeout_threshold = RKVDEC_TIMEOUT_4K;
> +	else if (pixels < RKVDEC_8K_PIXELS)
> +		regs->common.timeout_threshold = RKVDEC_TIMEOUT_8K;
> +
> +	/* Set POC val */
> +	regs->hevc_param.cur_top_poc = dec_params->pic_order_cnt_val;
> +
> +	/* Set ref pic address & poc */
> +	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
> +		struct vb2_buffer *vb_buf = get_ref_buf(ctx, run, i);
> +		dma_addr_t buf_dma = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
> +		u32 valid = !!(dec_params->num_active_dpb_entries > i);
> +
> +		/* Set reference addresses */
> +		regs->hevc_addr.ref_base[i] = buf_dma;
> +
> +		/* Set COLMV addresses */
> +		regs->hevc_addr.colmv_base[i] = buf_dma + ctx->colmv_offset;
> +
> +		regs->hevc_param.reg067_082_ref_poc[i] =
> +			dpb[i].pic_order_cnt_val;
> +
> +		set_ref_valid(regs, i, valid);
> +		regs->hevc_param.reg103.ref_pic_layer_same_with_cur |= 1 << i;
> +	}
> +
> +	/* Set rlc base address (input stream) */
> +	rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
> +	regs->common_addr.rlc_base = rlc_addr;
> +	regs->common_addr.rlcwrite_base = rlc_addr;
> +
> +	/* Set output base address */
> +	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
> +	regs->common_addr.decout_base = dst_addr;
> +	regs->common_addr.error_ref_base = dst_addr;
> +
> +	/* Set colmv address */
> +	regs->common_addr.colmv_cur_base = dst_addr + ctx->colmv_offset;
> +
> +	/* Set RCB addresses */
> +	for (i = 0; i < rkvdec_rcb_buf_count(ctx); i++)
> +		regs->common_addr.rcb_base[i] = rkvdec_rcb_buf_dma_addr(ctx, i);
> +
> +	/* Set hw pps address */
> +	offset = offsetof(struct rkvdec_hevc_priv_tbl, param_set);
> +	regs->hevc_addr.pps_base = priv_start_addr + offset;
> +
> +	/* Set hw rps address */
> +	offset = offsetof(struct rkvdec_hevc_priv_tbl, rps);
> +	regs->hevc_addr.rps_base = priv_start_addr + offset;
> +
> +	/* Set cabac table */
> +	offset = offsetof(struct rkvdec_hevc_priv_tbl, cabac_table);
> +	regs->hevc_addr.cabactbl_base = priv_start_addr + offset;
> +
> +	/* Set scaling matrix */
> +	offset = offsetof(struct rkvdec_hevc_priv_tbl, scaling_list);
> +	regs->hevc_addr.scanlist_addr = priv_start_addr + offset;
> +
> +	rkvdec_write_regs(ctx);
> +}
> +
> +static int rkvdec_hevc_start(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	struct rkvdec_hevc_priv_tbl *priv_tbl;
> +	struct rkvdec_hevc_ctx *hevc_ctx;
> +	struct v4l2_ctrl *ctrl;
> +	int ret;
> +
> +	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> +			????? V4L2_CID_STATELESS_HEVC_SPS);
> +	if (!ctrl)
> +		return -EINVAL;
> +
> +	ret = rkvdec_hevc_validate_sps(ctx, ctrl->p_new.p_hevc_sps);
> +	if (ret)
> +		return ret;
> +
> +	hevc_ctx = kzalloc(sizeof(*hevc_ctx), GFP_KERNEL);
> +	if (!hevc_ctx)
> +		return -ENOMEM;
> +
> +	priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl),
> +				????? &hevc_ctx->priv_tbl.dma, GFP_KERNEL);
> +	if (!priv_tbl) {
> +		ret = -ENOMEM;
> +		goto err_free_ctx;
> +	}
> +
> +	hevc_ctx->priv_tbl.size = sizeof(*priv_tbl);
> +	hevc_ctx->priv_tbl.cpu = priv_tbl;
> +	memcpy(priv_tbl->cabac_table, rkvdec_hevc_cabac_table,
> +	?????? sizeof(rkvdec_hevc_cabac_table));
> +
> +	ctx->priv = hevc_ctx;
> +	return 0;
> +
> +err_free_ctx:
> +	kfree(hevc_ctx);
> +	return ret;
> +}
> +
> +static void rkvdec_hevc_stop(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +
> +	dma_free_coherent(rkvdec->dev, hevc_ctx->priv_tbl.size,
> +			? hevc_ctx->priv_tbl.cpu, hevc_ctx->priv_tbl.dma);
> +	kfree(hevc_ctx);
> +}
> +
> +static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	struct rkvdec_hevc_run run;
> +	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
> +	struct rkvdec_hevc_priv_tbl *tbl = hevc_ctx->priv_tbl.cpu;
> +
> +	rkvdec_hevc_run_preamble(ctx, &run);
> +
> +	/*
> +	 * On vdpu381, not setting the long and short term ref sets will just output wrong frames.
> +	 * Let's just warn about it and let the decoder run anyway.
> +	 */
> +	if ((!ctx->has_sps_lt_rps && run.sps->num_long_term_ref_pics_sps) ||
> +		(!ctx->has_sps_st_rps && run.sps->num_short_term_ref_pic_sets)) {
> +		dev_warn_ratelimited(rkvdec->dev, "Long and short term RPS not set\n");
> +	}
> +
> +	rkvdec_hevc_assemble_hw_scaling_list(&run,
> +					???? &tbl->scaling_list,
> +					???? &hevc_ctx->scaling_matrix_cache);
> +	assemble_hw_pps(ctx, &run);
> +	rkvdec_hevc_assemble_hw_rps(&run, &tbl->rps, &hevc_ctx->st_cache);
> +
> +	config_registers(ctx, &run);
> +
> +	rkvdec_run_postamble(ctx, &run.base);
> +
> +	schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000));
> +
> +	/* Start decoding! */
> +	writel(VDPU381_DEC_E_BIT, rkvdec->regs + VDPU381_REG_DEC_E);
> +
> +	return 0;
> +}
> +
> +const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_hevc_fmt_ops = {
> +	.adjust_fmt = rkvdec_hevc_adjust_fmt,
> +	.start = rkvdec_hevc_start,
> +	.stop = rkvdec_hevc_stop,
> +	.run = rkvdec_hevc_run,
> +	.try_ctrl = rkvdec_hevc_try_ctrl,
> +	.get_image_fmt = rkvdec_hevc_get_image_fmt,
> +};
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> index 1837f12f1aa1..b72cb07de70e 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> @@ -154,6 +154,16 @@ static int rkvdec_s_ctrl(struct v4l2_ctrl *ctrl)
> ?	enum rkvdec_image_fmt image_fmt;
> ?	struct vb2_queue *vq;
> ?
> +	if (ctrl->id == V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS) {
> +		ctx->has_sps_st_rps |= !!(ctrl->has_changed);
> +		return 0;
> +	}
> +
> +	if (ctrl->id == V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS) {
> +		ctx->has_sps_lt_rps |= !!(ctrl->has_changed);
> +		return 0;
> +	}
> +
> ?	/* Check if this change requires a capture format reset */
> ?	if (!desc->ops->get_image_fmt)
> ?		return 0;
> @@ -285,6 +295,62 @@ static const struct rkvdec_ctrls rkvdec_h264_ctrls = {
> ?	.num_ctrls = ARRAY_SIZE(rkvdec_h264_ctrl_descs),
> ?};
> ?
> +static const struct rkvdec_ctrl_desc vdpu38x_hevc_ctrl_descs[] = {
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_SPS,
> +		.cfg.ops = &rkvdec_ctrl_ops,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_PPS,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_MODE,
> +		.cfg.min = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
> +		.cfg.max = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
> +		.cfg.def = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_START_CODE,
> +		.cfg.min = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
> +		.cfg.def = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
> +		.cfg.max = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
> +		.cfg.min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
> +		.cfg.max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
> +		.cfg.menu_skip_mask =
> +			BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE),
> +		.cfg.def = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
> +		.cfg.min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
> +		.cfg.max = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS,
> +		.cfg.ops = &rkvdec_ctrl_ops,
> +		.cfg.dims = { 65 },
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS,
> +		.cfg.ops = &rkvdec_ctrl_ops,
> +		.cfg.dims = { 65 },
> +	},
> +};
> +
> +static const struct rkvdec_ctrls vdpu38x_hevc_ctrls = {
> +	.ctrls = vdpu38x_hevc_ctrl_descs,
> +	.num_ctrls = ARRAY_SIZE(vdpu38x_hevc_ctrl_descs),
> +};
> +
> ?static const struct rkvdec_decoded_fmt_desc rkvdec_h264_decoded_fmts[] = {
> ?	{
> ?		.fourcc = V4L2_PIX_FMT_NV12,
> @@ -401,6 +467,23 @@ static const struct rkvdec_coded_fmt_desc vdpu381_coded_fmts[] = {
> ?		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
> ?		.capability = RKVDEC_CAPABILITY_H264,
> ?	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_HEVC_SLICE,
> +		.frmsize = {
> +			.min_width = 64,
> +			.max_width = 65472,
> +			.step_width = 64,
> +			.min_height = 64,
> +			.max_height = 65472,
> +			.step_height = 16,
> +		},
> +		.ctrls = &vdpu38x_hevc_ctrls,
> +		.ops = &rkvdec_vdpu381_hevc_fmt_ops,
> +		.num_decoded_fmts = ARRAY_SIZE(rkvdec_hevc_decoded_fmts),
> +		.decoded_fmts = rkvdec_hevc_decoded_fmts,
> +		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
> +		.capability = RKVDEC_CAPABILITY_HEVC,
> +	},
> ?};
> ?
> ?static const struct rkvdec_coded_fmt_desc vdpu383_coded_fmts[] = {
> @@ -1500,7 +1583,8 @@ static const struct rkvdec_variant rk3399_rkvdec_variant = {
> ?
> ?static const struct rkvdec_variant rk3588_vdpu381_variant = {
> ?	.config = &config_vdpu381,
> -	.capabilities = RKVDEC_CAPABILITY_H264,
> +	.capabilities = RKVDEC_CAPABILITY_H264 |
> +			RKVDEC_CAPABILITY_HEVC,
> ?};
> ?
> ?static const struct rkvdec_variant rk3576_vdpu383_variant = {
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> index e752706e9f5c..94e2e6429992 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> @@ -156,6 +156,8 @@ struct rkvdec_ctx {
> ?	struct rkvdec_rcb_config *rcb_config;
> ?	u32 colmv_offset;
> ?	void *priv;
> +	u8 has_sps_st_rps: 1;
> +	u8 has_sps_lt_rps: 1;
> ?};
> ?
> ?static inline struct rkvdec_ctx *file_to_rkvdec_ctx(struct file *filp)
> @@ -188,6 +190,7 @@ extern const struct rkvdec_coded_fmt_ops rkvdec_vp9_fmt_ops;
> ?
> ?/* VDPU381 ops */
> ?extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_h264_fmt_ops;
> +extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_hevc_fmt_ops;
> ?
> ?/* VDPU383 ops */
> ?extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu383_h264_fmt_ops;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251210/fb84a384/attachment-0001.sig>

From nicolas.dufresne at collabora.com  Wed Dec 10 12:47:23 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Wed, 10 Dec 2025 15:47:23 -0500
Subject: [PATCH v4 15/15] media: rkvdec: Add HEVC support for the
 VDPU383 variant
In-Reply-To: <20251022174508.284929-16-detlev.casanova@collabora.com>
References: <20251022174508.284929-1-detlev.casanova@collabora.com>
	 <20251022174508.284929-16-detlev.casanova@collabora.com>
Message-ID: <8f7468a242b13ca1ea8f618e40bfb58f0d7950af.camel@collabora.com>

Le mercredi 22 octobre 2025 ? 13:45 -0400, Detlev Casanova a ?crit?:
> The VDPU383 decoder is used on the RK3576 SoC and has support for HEVC.
> 
> This patch also moves some functions to a common rkvdec-hevc-common.c
> file and adds a specific scaling matrix flatten function.
> 
> The fluster score for JCT-VC-HEVC_V1 is 146/147.
> 
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?.../media/platform/rockchip/rkvdec/Makefile?? |?? 1 +
> ?.../rockchip/rkvdec/rkvdec-hevc-common.c????? |? 60 +-
> ?.../rockchip/rkvdec/rkvdec-hevc-common.h????? |?? 3 +-
> ?.../platform/rockchip/rkvdec/rkvdec-hevc.c??? |?? 2 +-
> ?.../rockchip/rkvdec/rkvdec-vdpu381-hevc.c???? |?? 3 +-
> ?.../rockchip/rkvdec/rkvdec-vdpu383-hevc.c???? | 690 ++++++++++++++++++
> ?.../media/platform/rockchip/rkvdec/rkvdec.c?? |? 94 ++-
> ?.../media/platform/rockchip/rkvdec/rkvdec.h?? |?? 2 +
> ?8 files changed, 804 insertions(+), 51 deletions(-)
> ?create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
> index e30fdd7d51c3..e629d571e4d8 100644
> --- a/drivers/media/platform/rockchip/rkvdec/Makefile
> +++ b/drivers/media/platform/rockchip/rkvdec/Makefile
> @@ -11,4 +11,5 @@ rockchip-vdec-y += \
> ?		?? rkvdec-vdpu381-h264.o \
> ?		?? rkvdec-vdpu381-hevc.o \
> ?		?? rkvdec-vdpu383-h264.o \
> +		?? rkvdec-vdpu383-hevc.o \
> ?		?? rkvdec-vp9.o
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
> index 4b21b3ea67fd..8f1dc2d1e463 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
> @@ -158,58 +158,25 @@ static void set_ref_poc(struct rkvdec_rps_short_term_ref_set *set, int poc, int
> ?	}
> ?}
> ?
> -/*
> - * Flip one or more matrices along their main diagonal and flatten them
> - * before writing it to the memory.
> - * Convert:
> - * ABCD???????? AEIM
> - * EFGH???? =>? BFJN???? =>???? AEIMBFJNCGKODHLP
> - * IJKL???????? CGKO
> - * MNOP???????? DHLP
> - */
> -static void transpose_and_flatten_matrices(u8 *output, const u8 *input,
> -					?? int matrices, int row_length)
> -{
> -	int i, j, row, x_offset, matrix_offset, rot_index, y_offset, matrix_size, new_value;
> -
> -	matrix_size = row_length * row_length;
> -	for (i = 0; i < matrices; i++) {
> -		row = 0;
> -		x_offset = 0;
> -		matrix_offset = i * matrix_size;
> -		for (j = 0; j < matrix_size; j++) {
> -			y_offset = j - (row * row_length);
> -			rot_index = y_offset * row_length + x_offset;
> -			new_value = *(input + i * matrix_size + j);
> -			output[matrix_offset + rot_index] = new_value;
> -			if ((j + 1) % row_length == 0) {
> -				row += 1;
> -				x_offset += 1;
> -			}
> -		}
> -	}
> -}
> -
> -static void assemble_scalingfactor0(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input)
> +static void assemble_scalingfactor0(struct rkvdec_ctx *ctx, u8 *output,
> +				??? const struct v4l2_ctrl_hevc_scaling_matrix *input)
> ?{
> +	const struct rkvdec_config *cfg = ctx->dev->variant->config;
> ?	int offset = 0;
> ?
> -	transpose_and_flatten_matrices(output, (const u8 *)input->scaling_list_4x4, 6, 4);
> +	cfg->flatten_matrices(output, (const u8 *)input->scaling_list_4x4, 6, 4);
> ?	offset = 6 * 16 * sizeof(u8);
> -	transpose_and_flatten_matrices(output + offset, (const u8 *)input->scaling_list_8x8, 6, 8);
> +	cfg->flatten_matrices(output + offset, (const u8 *)input->scaling_list_8x8, 6, 8);
> ?	offset += 6 * 64 * sizeof(u8);
> -	transpose_and_flatten_matrices(output + offset,
> -				?????? (const u8 *)input->scaling_list_16x16, 6, 8);
> +	cfg->flatten_matrices(output + offset, (const u8 *)input->scaling_list_16x16, 6, 8);
> ?	offset += 6 * 64 * sizeof(u8);
> ?	/* Add a 128 byte padding with 0s between the two 32x32 matrices */
> -	transpose_and_flatten_matrices(output + offset,
> -				?????? (const u8 *)input->scaling_list_32x32, 1, 8);
> +	cfg->flatten_matrices(output + offset, (const u8 *)input->scaling_list_32x32, 1, 8);
> ?	offset += 64 * sizeof(u8);
> ?	memset(output + offset, 0, 128);
> ?	offset += 128 * sizeof(u8);
> -	transpose_and_flatten_matrices(output + offset,
> -				?????? (const u8 *)input->scaling_list_32x32 + (64 * sizeof(u8)),
> -				?????? 1, 8);
> +	cfg->flatten_matrices(output + offset,
> +			????? (const u8 *)input->scaling_list_32x32 + (64 * sizeof(u8)), 1, 8);
> ?	offset += 64 * sizeof(u8);
> ?	memset(output + offset, 0, 128);
> ?}
> @@ -232,16 +199,17 @@ static void assemble_scalingdc(u8 *output, const struct v4l2_ctrl_hevc_scaling_m
> ?	memcpy(output + 6 * sizeof(u8), list_32x32, 6 * sizeof(u8));
> ?}
> ?
> -static void translate_scaling_list(struct scaling_factor *output,
> +static void translate_scaling_list(struct rkvdec_ctx *ctx, struct scaling_factor *output,
> ?				?? const struct v4l2_ctrl_hevc_scaling_matrix *input)
> ?{
> -	assemble_scalingfactor0(output->scalingfactor0, input);
> +	assemble_scalingfactor0(ctx, output->scalingfactor0, input);
> ?	memcpy(output->scalingfactor1, (const u8 *)input->scaling_list_4x4, 96);
> ?	assemble_scalingdc(output->scalingdc, input);
> ?	memset(output->reserved, 0, 4 * sizeof(u8));
> ?}
> ?
> -void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
> +void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_ctx *ctx,
> +					? struct rkvdec_hevc_run *run,
> ?					? struct scaling_factor *scaling_list,
> ?					? struct v4l2_ctrl_hevc_scaling_matrix *cache)
> ?{
> @@ -251,7 +219,7 @@ void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
> ?		??? sizeof(struct v4l2_ctrl_hevc_scaling_matrix)))
> ?		return;
> ?
> -	translate_scaling_list(scaling_list, scaling);
> +	translate_scaling_list(ctx, scaling_list, scaling);
> ?
> ?	memcpy(cache, scaling,
> ?	?????? sizeof(struct v4l2_ctrl_hevc_scaling_matrix));
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
> index 0005b80bad79..c4947d2b983d 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
> @@ -99,7 +99,8 @@ void compute_tiles_non_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size
> ?			?????? s32 pic_in_cts_height, u16 *column_width, u16 *row_height);
> ?void rkvdec_hevc_assemble_hw_rps(struct rkvdec_hevc_run *run, struct rkvdec_rps *rps,
> ?				 struct v4l2_ctrl_hevc_ext_sps_st_rps *st_cache);
> -void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
> +void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_ctx *ctx,
> +					? struct rkvdec_hevc_run *run,
> ?					? struct scaling_factor *scaling_factor,
> ?					? struct v4l2_ctrl_hevc_scaling_matrix *cache);
> ?struct vb2_buffer *get_ref_buf(struct rkvdec_ctx *ctx,
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
> index 31a979698578..eb18f7c2bb0c 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
> @@ -546,7 +546,7 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
> ?
> ?	rkvdec_hevc_run_preamble(ctx, &run);
> ?
> -	rkvdec_hevc_assemble_hw_scaling_list(&run, &tbl->scaling_list,
> +	rkvdec_hevc_assemble_hw_scaling_list(ctx, &run, &tbl->scaling_list,
> ?					???? &hevc_ctx->scaling_matrix_cache);
> ?	assemble_hw_pps(ctx, &run);
> ?	assemble_sw_rps(ctx, &run);
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
> index 278f1dbf0910..0798d68f1af2 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
> @@ -568,8 +568,7 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
> ?		dev_warn_ratelimited(rkvdec->dev, "Long and short term RPS not set\n");
> ?	}
> ?
> -	rkvdec_hevc_assemble_hw_scaling_list(&run,
> -					???? &tbl->scaling_list,
> +	rkvdec_hevc_assemble_hw_scaling_list(ctx, &run, &tbl->scaling_list,
> ?					???? &hevc_ctx->scaling_matrix_cache);
> ?	assemble_hw_pps(ctx, &run);
> ?	rkvdec_hevc_assemble_hw_rps(&run, &tbl->rps, &hevc_ctx->st_cache);
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c
> new file mode 100644
> index 000000000000..ef29f0ee6c31
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c
> @@ -0,0 +1,690 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Rockchip VDPU383 HEVC backend
> + *
> + * Copyright (C) 2025 Collabora, Ltd.
> + *? Detlev Casanova <detlev.casanova at collabora.com>
> + */
> +
> +#include <media/v4l2-mem2mem.h>
> +
> +#include "rkvdec.h"
> +#include "rkvdec-rcb.h"
> +#include "rkvdec-hevc-common.h"
> +#include "rkvdec-vdpu383-regs.h"
> +
> +struct rkvdec_hevc_sps_pps {
> +	// SPS
> +	u16 video_parameters_set_id			: 4;
> +	u16 seq_parameters_set_id_sps			: 4;
> +	u16 chroma_format_idc				: 2;
> +	u16 width					: 16;
> +	u16 height					: 16;
> +	u16 bit_depth_luma				: 3;
> +	u16 bit_depth_chroma				: 3;
> +	u16 max_pic_order_count_lsb			: 5;
> +	u16 diff_max_min_luma_coding_block_size		: 2;
> +	u16 min_luma_coding_block_size			: 3;
> +	u16 min_transform_block_size			: 3;
> +	u16 diff_max_min_transform_block_size		: 2;
> +	u16 max_transform_hierarchy_depth_inter		: 3;
> +	u16 max_transform_hierarchy_depth_intra		: 3;
> +	u16 scaling_list_enabled_flag			: 1;
> +	u16 amp_enabled_flag				: 1;
> +	u16 sample_adaptive_offset_enabled_flag		: 1;
> +	u16 pcm_enabled_flag				: 1;
> +	u16 pcm_sample_bit_depth_luma			: 4;
> +	u16 pcm_sample_bit_depth_chroma			: 4;
> +	u16 pcm_loop_filter_disabled_flag		: 1;
> +	u16 diff_max_min_pcm_luma_coding_block_size	: 3;
> +	u16 min_pcm_luma_coding_block_size		: 3;
> +	u16 num_short_term_ref_pic_sets			: 7;
> +	u16 long_term_ref_pics_present_flag		: 1;
> +	u16 num_long_term_ref_pics_sps			: 6;
> +	u16 sps_temporal_mvp_enabled_flag		: 1;
> +	u16 strong_intra_smoothing_enabled_flag		: 1;
> +	u16 reserved0					: 7;
> +	u16 sps_max_dec_pic_buffering_minus1		: 4;
> +	u16 separate_colour_plane_flag			: 1;
> +	u16 high_precision_offsets_enabled_flag		: 1;
> +	u16 persistent_rice_adaptation_enabled_flag	: 1;
> +
> +	// PPS
> +	u16 picture_parameters_set_id			: 6;
> +	u16 seq_parameters_set_id_pps			: 4;
> +	u16 dependent_slice_segments_enabled_flag	: 1;
> +	u16 output_flag_present_flag			: 1;
> +	u16 num_extra_slice_header_bits			: 13;
> +	u16 sign_data_hiding_enabled_flag		: 1;
> +	u16 cabac_init_present_flag			: 1;
> +	u16 num_ref_idx_l0_default_active		: 4;
> +	u16 num_ref_idx_l1_default_active		: 4;
> +	u16 init_qp_minus26				: 7;
> +	u16 constrained_intra_pred_flag			: 1;
> +	u16 transform_skip_enabled_flag			: 1;
> +	u16 cu_qp_delta_enabled_flag			: 1;
> +	u16 log2_min_cb_size				: 3;
> +	u16 pps_cb_qp_offset				: 5;
> +	u16 pps_cr_qp_offset				: 5;
> +	u16 pps_slice_chroma_qp_offsets_present_flag	: 1;
> +	u16 weighted_pred_flag				: 1;
> +	u16 weighted_bipred_flag			: 1;
> +	u16 transquant_bypass_enabled_flag		: 1;
> +	u16 tiles_enabled_flag				: 1;
> +	u16 entropy_coding_sync_enabled_flag		: 1;
> +	u16 pps_loop_filter_across_slices_enabled_flag	: 1;
> +	u16 loop_filter_across_tiles_enabled_flag	: 1;
> +	u16 deblocking_filter_override_enabled_flag	: 1;
> +	u16 pps_deblocking_filter_disabled_flag		: 1;
> +	u16 pps_beta_offset_div2			: 4;
> +	u16 pps_tc_offset_div2				: 4;
> +	u16 lists_modification_present_flag		: 1;
> +	u16 log2_parallel_merge_level			: 3;
> +	u16 slice_segment_header_extension_present_flag	: 1;
> +	u16 reserved1					: 3;
> +
> +	// pps extensions
> +	u16 log2_max_transform_skip_block_size		: 2;
> +	u16 cross_component_prediction_enabled_flag	: 1;
> +	u16 chroma_qp_offset_list_enabled_flag		: 1;
> +	u16 log2_min_cu_chroma_qp_delta_size		: 3;
> +	u16 cb_qp_offset_list0				: 5;
> +	u16 cb_qp_offset_list1				: 5;
> +	u16 cb_qp_offset_list2				: 5;
> +	u16 cb_qp_offset_list3				: 5;
> +	u16 cb_qp_offset_list4				: 5;
> +	u16 cb_qp_offset_list5				: 5;
> +	u16 cb_cr_offset_list0				: 5;
> +	u16 cb_cr_offset_list1				: 5;
> +	u16 cb_cr_offset_list2				: 5;
> +	u16 cb_cr_offset_list3				: 5;
> +	u16 cb_cr_offset_list4				: 5;
> +	u16 cb_cr_offset_list5				: 5;
> +	u16 chroma_qp_offset_list_len_minus1		: 3;
> +
> +	/* mvc0 && mvc1 */
> +	u16 mvc_ff					: 16;
> +	u16 mvc_00					: 9;
> +
> +	/* poc info */
> +	u16 reserved2					: 3;
> +	u32 current_poc					: 32;
> +	u32 ref_pic_poc0				: 32;
> +	u32 ref_pic_poc1				: 32;
> +	u32 ref_pic_poc2				: 32;
> +	u32 ref_pic_poc3				: 32;
> +	u32 ref_pic_poc4				: 32;
> +	u32 ref_pic_poc5				: 32;
> +	u32 ref_pic_poc6				: 32;
> +	u32 ref_pic_poc7				: 32;
> +	u32 ref_pic_poc8				: 32;
> +	u32 ref_pic_poc9				: 32;
> +	u32 ref_pic_poc10				: 32;
> +	u32 ref_pic_poc11				: 32;
> +	u32 ref_pic_poc12				: 32;
> +	u32 ref_pic_poc13				: 32;
> +	u32 ref_pic_poc14				: 32;
> +	u32 reserved3					: 32;
> +	u32 ref_is_valid				: 15;
> +	u32 reserved4					: 1;
> +
> +	/* tile info*/
> +	u16 num_tile_columns				: 5;
> +	u16 num_tile_rows				: 5;
> +	u32 column_width0				: 24;
> +	u32 column_width1				: 24;
> +	u32 column_width2				: 24;
> +	u32 column_width3				: 24;
> +	u32 column_width4				: 24;
> +	u32 column_width5				: 24;
> +	u32 column_width6				: 24;
> +	u32 column_width7				: 24;
> +	u32 column_width8				: 24;
> +	u32 column_width9				: 24;
> +	u32 row_height0					: 24;
> +	u32 row_height1					: 24;
> +	u32 row_height2					: 24;
> +	u32 row_height3					: 24;
> +	u32 row_height4					: 24;
> +	u32 row_height5					: 24;
> +	u32 row_height6					: 24;
> +	u32 row_height7					: 24;
> +	u32 row_height8					: 24;
> +	u32 row_height9					: 24;
> +	u32 row_height10				: 24;
> +	u32 reserved5					: 2;
> +	u32 padding;
> +} __packed;
> +
> +struct rkvdec_hevc_priv_tbl {
> +	struct rkvdec_hevc_sps_pps param_set;
> +	struct rkvdec_rps rps;
> +	struct scaling_factor scaling_list;
> +	u8 cabac_table[27456];
> +}? __packed;
> +
> +struct rkvdec_hevc_ctx {
> +	struct rkvdec_aux_buf			priv_tbl;
> +	struct v4l2_ctrl_hevc_scaling_matrix	scaling_matrix_cache;
> +	struct v4l2_ctrl_hevc_ext_sps_st_rps	st_cache;
> +	struct vdpu383_regs_h26x		regs;
> +};
> +
> +static void set_column_row(struct rkvdec_hevc_sps_pps *hw_ps, u16 column, u16 row, int i)
> +{
> +	int shift = (i & 1) ? 12 : 0;
> +
> +	switch (i / 2) {
> +	case 0:
> +		hw_ps->column_width0 |= column << shift;
> +		hw_ps->row_height0 |= row << shift;
> +		break;
> +	case 1:
> +		hw_ps->column_width1 |= column << shift;
> +		hw_ps->row_height1 |= row << shift;
> +		break;
> +	case 2:
> +		hw_ps->column_width2 |= column << shift;
> +		hw_ps->row_height2 |= row << shift;
> +		break;
> +	case 3:
> +		hw_ps->column_width3 |= column << shift;
> +		hw_ps->row_height3 |= row << shift;
> +		break;
> +	case 4:
> +		hw_ps->column_width4 |= column << shift;
> +		hw_ps->row_height4 |= row << shift;
> +		break;
> +	case 5:
> +		hw_ps->column_width5 |= column << shift;
> +		hw_ps->row_height5 |= row << shift;
> +		break;
> +	case 6:
> +		hw_ps->column_width6 |= column << shift;
> +		hw_ps->row_height6 |= row << shift;
> +		break;
> +	case 7:
> +		hw_ps->column_width7 |= column << shift;
> +		hw_ps->row_height7 |= row << shift;
> +		break;
> +	case 8:
> +		hw_ps->column_width8 |= column << shift;
> +		hw_ps->row_height8 |= row << shift;
> +		break;
> +	case 9:
> +		hw_ps->column_width9 |= column << shift;
> +		hw_ps->row_height9 |= row << shift;
> +		break;
> +	case 10:
> +		hw_ps->row_height10 |= row << shift;
> +		break;
> +	}
> +}
> +
> +static void set_pps_ref_pic_poc(struct rkvdec_hevc_sps_pps *hw_ps, u32 poc, int i)
> +{
> +	switch (i) {
> +	case 0:
> +		hw_ps->ref_pic_poc0 = poc;
> +		break;
> +	case 1:
> +		hw_ps->ref_pic_poc1 = poc;
> +		break;
> +	case 2:
> +		hw_ps->ref_pic_poc2 = poc;
> +		break;
> +	case 3:
> +		hw_ps->ref_pic_poc3 = poc;
> +		break;
> +	case 4:
> +		hw_ps->ref_pic_poc4 = poc;
> +		break;
> +	case 5:
> +		hw_ps->ref_pic_poc5 = poc;
> +		break;
> +	case 6:
> +		hw_ps->ref_pic_poc6 = poc;
> +		break;
> +	case 7:
> +		hw_ps->ref_pic_poc7 = poc;
> +		break;
> +	case 8:
> +		hw_ps->ref_pic_poc8 = poc;
> +		break;
> +	case 9:
> +		hw_ps->ref_pic_poc9 = poc;
> +		break;
> +	case 10:
> +		hw_ps->ref_pic_poc10 = poc;
> +		break;
> +	case 11:
> +		hw_ps->ref_pic_poc11 = poc;
> +		break;
> +	case 12:
> +		hw_ps->ref_pic_poc12 = poc;
> +		break;
> +	case 13:
> +		hw_ps->ref_pic_poc13 = poc;
> +		break;
> +	case 14:
> +		hw_ps->ref_pic_poc14 = poc;
> +		break;
> +	}
> +}
> +
> +static void assemble_hw_pps(struct rkvdec_ctx *ctx,
> +			??? struct rkvdec_hevc_run *run)
> +{
> +	struct rkvdec_hevc_ctx *h264_ctx = ctx->priv;
> +	const struct v4l2_ctrl_hevc_sps *sps = run->sps;
> +	const struct v4l2_ctrl_hevc_pps *pps = run->pps;
> +	const struct v4l2_ctrl_hevc_decode_params *dec_params = run->decode_params;
> +	struct rkvdec_hevc_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu;
> +	struct rkvdec_hevc_sps_pps *hw_ps;
> +	bool tiles_enabled;
> +	s32 max_cu_width;
> +	s32 pic_in_cts_width;
> +	s32 pic_in_cts_height;
> +	u16 log2_min_cb_size, width, height;
> +	u16 column_width[22];
> +	u16 row_height[22];
> +	u8 pcm_enabled;
> +	u32 i;
> +
> +	/*
> +	 * HW read the SPS/PPS information from PPS packet index by PPS id.
> +	 * offset from the base can be calculated by PPS_id * 32 (size per PPS
> +	 * packet unit). so the driver copy SPS/PPS information to the exact PPS
> +	 * packet unit for HW accessing.
> +	 */
> +	hw_ps = &priv_tbl->param_set;
> +	memset(hw_ps, 0, sizeof(*hw_ps));
> +
> +	/* write sps */
> +	hw_ps->video_parameters_set_id = sps->video_parameter_set_id;
> +	hw_ps->seq_parameters_set_id_sps = sps->seq_parameter_set_id;
> +	hw_ps->chroma_format_idc = sps->chroma_format_idc;
> +
> +	log2_min_cb_size = sps->log2_min_luma_coding_block_size_minus3 + 3;
> +	width = sps->pic_width_in_luma_samples;
> +	height = sps->pic_height_in_luma_samples;
> +	hw_ps->width = width;
> +	hw_ps->height = height;
> +	hw_ps->bit_depth_luma = sps->bit_depth_luma_minus8 + 8;
> +	hw_ps->bit_depth_chroma = sps->bit_depth_chroma_minus8 + 8;
> +	hw_ps->max_pic_order_count_lsb = sps->log2_max_pic_order_cnt_lsb_minus4 + 4;
> +	hw_ps->diff_max_min_luma_coding_block_size = sps->log2_diff_max_min_luma_coding_block_size;
> +	hw_ps->min_luma_coding_block_size = sps->log2_min_luma_coding_block_size_minus3 + 3;
> +	hw_ps->min_transform_block_size = sps->log2_min_luma_transform_block_size_minus2 + 2;
> +	hw_ps->diff_max_min_transform_block_size =
> +		sps->log2_diff_max_min_luma_transform_block_size;
> +	hw_ps->max_transform_hierarchy_depth_inter = sps->max_transform_hierarchy_depth_inter;
> +	hw_ps->max_transform_hierarchy_depth_intra = sps->max_transform_hierarchy_depth_intra;
> +	hw_ps->scaling_list_enabled_flag =
> +		!!(sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED);
> +	hw_ps->amp_enabled_flag = !!(sps->flags & V4L2_HEVC_SPS_FLAG_AMP_ENABLED);
> +	hw_ps->sample_adaptive_offset_enabled_flag =
> +		!!(sps->flags & V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET);
> +
> +	pcm_enabled = !!(sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED);
> +	hw_ps->pcm_enabled_flag = pcm_enabled;
> +	hw_ps->pcm_sample_bit_depth_luma =
> +		pcm_enabled ? sps->pcm_sample_bit_depth_luma_minus1 + 1 : 0;
> +	hw_ps->pcm_sample_bit_depth_chroma =
> +		pcm_enabled ? sps->pcm_sample_bit_depth_chroma_minus1 + 1 : 0;
> +	hw_ps->pcm_loop_filter_disabled_flag =
> +		!!(sps->flags & V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED);
> +	hw_ps->diff_max_min_pcm_luma_coding_block_size =
> +		sps->log2_diff_max_min_pcm_luma_coding_block_size;
> +	hw_ps->min_pcm_luma_coding_block_size =
> +		pcm_enabled ? sps->log2_min_pcm_luma_coding_block_size_minus3 + 3 : 0;
> +	hw_ps->num_short_term_ref_pic_sets = sps->num_short_term_ref_pic_sets;
> +	hw_ps->long_term_ref_pics_present_flag =
> +		!!(sps->flags & V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT);
> +	hw_ps->num_long_term_ref_pics_sps = sps->num_long_term_ref_pics_sps;
> +	hw_ps->sps_temporal_mvp_enabled_flag =
> +		!!(sps->flags & V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED);
> +	hw_ps->strong_intra_smoothing_enabled_flag =
> +		!!(sps->flags & V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED);
> +	hw_ps->sps_max_dec_pic_buffering_minus1 = sps->sps_max_dec_pic_buffering_minus1;
> +
> +	/* write pps */
> +	hw_ps->picture_parameters_set_id = pps->pic_parameter_set_id;
> +	hw_ps->seq_parameters_set_id_pps = sps->seq_parameter_set_id;
> +	hw_ps->dependent_slice_segments_enabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED);
> +	hw_ps->output_flag_present_flag = !!(pps->flags & V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT);
> +	hw_ps->num_extra_slice_header_bits = pps->num_extra_slice_header_bits;
> +	hw_ps->sign_data_hiding_enabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED);
> +	hw_ps->cabac_init_present_flag = !!(pps->flags & V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT);
> +	hw_ps->num_ref_idx_l0_default_active = pps->num_ref_idx_l0_default_active_minus1 + 1;
> +	hw_ps->num_ref_idx_l1_default_active = pps->num_ref_idx_l1_default_active_minus1 + 1;
> +	hw_ps->init_qp_minus26 = pps->init_qp_minus26;
> +	hw_ps->constrained_intra_pred_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED);
> +	hw_ps->transform_skip_enabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED);
> +	hw_ps->cu_qp_delta_enabled_flag = !!(pps->flags & V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED);
> +	hw_ps->log2_min_cb_size = log2_min_cb_size +
> +				? sps->log2_diff_max_min_luma_coding_block_size -
> +				? pps->diff_cu_qp_delta_depth;
> +	hw_ps->pps_cb_qp_offset = pps->pps_cb_qp_offset;
> +	hw_ps->pps_cr_qp_offset = pps->pps_cr_qp_offset;
> +	hw_ps->pps_slice_chroma_qp_offsets_present_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT);
> +	hw_ps->weighted_pred_flag = !!(pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED);
> +	hw_ps->weighted_bipred_flag = !!(pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED);
> +	hw_ps->transquant_bypass_enabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED);
> +	tiles_enabled = !!(pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED);
> +	hw_ps->tiles_enabled_flag = tiles_enabled;
> +	hw_ps->entropy_coding_sync_enabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED);
> +	hw_ps->pps_loop_filter_across_slices_enabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED);
> +	hw_ps->loop_filter_across_tiles_enabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED);
> +	hw_ps->deblocking_filter_override_enabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED);
> +	hw_ps->pps_deblocking_filter_disabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER);
> +	hw_ps->pps_beta_offset_div2 = pps->pps_beta_offset_div2;
> +	hw_ps->pps_tc_offset_div2 = pps->pps_tc_offset_div2;
> +	hw_ps->lists_modification_present_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT);
> +	hw_ps->log2_parallel_merge_level = pps->log2_parallel_merge_level_minus2 + 2;
> +	hw_ps->slice_segment_header_extension_present_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT);
> +	hw_ps->num_tile_columns = tiles_enabled ? pps->num_tile_columns_minus1 + 1 : 1;
> +	hw_ps->num_tile_rows = tiles_enabled ? pps->num_tile_rows_minus1 + 1 : 1;
> +	hw_ps->mvc_ff = 0xffff;
> +
> +	// Setup tiles information
> +	memset(column_width, 0, sizeof(column_width));
> +	memset(row_height, 0, sizeof(row_height));
> +
> +	max_cu_width = 1 << (sps->log2_diff_max_min_luma_coding_block_size + log2_min_cb_size);
> +	pic_in_cts_width = (width + max_cu_width - 1) / max_cu_width;
> +	pic_in_cts_height = (height + max_cu_width - 1) / max_cu_width;
> +
> +	if (tiles_enabled) {
> +		if (pps->flags & V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING) {
> +			compute_tiles_uniform(run, log2_min_cb_size, width, height,
> +					????? pic_in_cts_width, pic_in_cts_height,
> +					????? column_width, row_height);
> +		} else {
> +			compute_tiles_non_uniform(run, log2_min_cb_size, width, height,
> +						? pic_in_cts_width, pic_in_cts_height,
> +						? column_width, row_height);
> +		}
> +	} else {
> +		column_width[0] = (width + max_cu_width - 1) / max_cu_width;
> +		row_height[0] = (height + max_cu_width - 1) / max_cu_width;
> +	}
> +
> +	for (i = 0; i < 22; i++)
> +		set_column_row(hw_ps, column_width[i], row_height[i], i);
> +
> +	// Setup POC information
> +	hw_ps->current_poc = dec_params->pic_order_cnt_val;
> +
> +	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
> +		u32 valid = !!(dec_params->num_active_dpb_entries > i);
> +
> +		set_pps_ref_pic_poc(hw_ps, dec_params->dpb[i].pic_order_cnt_val, i);
> +		hw_ps->ref_is_valid |= valid << i;
> +	}
> +}
> +
> +static void rkvdec_write_regs(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	struct rkvdec_hevc_ctx *h265_ctx = ctx->priv;
> +
> +	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_COMMON_REGS,
> +			?? &h265_ctx->regs.common,
> +			?? sizeof(h265_ctx->regs.common));
> +	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_COMMON_ADDR_REGS,
> +			?? &h265_ctx->regs.common_addr,
> +			?? sizeof(h265_ctx->regs.common_addr));
> +	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_CODEC_PARAMS_REGS,
> +			?? &h265_ctx->regs.h26x_params,
> +			?? sizeof(h265_ctx->regs.h26x_params));
> +	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_CODEC_ADDR_REGS,
> +			?? &h265_ctx->regs.h26x_addr,
> +			?? sizeof(h265_ctx->regs.h26x_addr));
> +}
> +
> +static void config_registers(struct rkvdec_ctx *ctx,
> +			???? struct rkvdec_hevc_run *run)
> +{
> +	const struct v4l2_ctrl_hevc_decode_params *dec_params = run->decode_params;
> +	struct rkvdec_hevc_ctx *h265_ctx = ctx->priv;
> +	const struct v4l2_ctrl_hevc_sps *sps = run->sps;
> +	dma_addr_t priv_start_addr = h265_ctx->priv_tbl.dma;
> +	const struct v4l2_pix_format_mplane *dst_fmt;
> +	struct vb2_v4l2_buffer *src_buf = run->base.bufs.src;
> +	struct vb2_v4l2_buffer *dst_buf = run->base.bufs.dst;
> +	struct vdpu383_regs_h26x *regs = &h265_ctx->regs;
> +	const struct v4l2_format *f;
> +	dma_addr_t rlc_addr;
> +	dma_addr_t dst_addr;
> +	u32 hor_virstride;
> +	u32 ver_virstride;
> +	u32 y_virstride;
> +	u32 offset;
> +	u32 pixels;
> +	u32 i;
> +
> +	memset(regs, 0, sizeof(*regs));
> +
> +	/* Set H264 mode */
> +	regs->common.reg008_dec_mode = VDPU383_MODE_HEVC;
> +
> +	/* Set input stream length */
> +	regs->h26x_params.reg066_stream_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
> +
> +	/* Set strides */
> +	f = &ctx->decoded_fmt;
> +	dst_fmt = &f->fmt.pix_mp;
> +	hor_virstride = dst_fmt->plane_fmt[0].bytesperline;
> +	ver_virstride = dst_fmt->height;
> +	y_virstride = hor_virstride * ver_virstride;
> +
> +	pixels = dst_fmt->height * dst_fmt->width;
> +
> +	regs->h26x_params.reg068_hor_virstride = hor_virstride / 16;
> +	regs->h26x_params.reg069_raster_uv_hor_virstride = hor_virstride / 16;
> +	regs->h26x_params.reg070_y_virstride = y_virstride / 16;
> +
> +	/* Activate block gating */
> +	regs->common.reg010.strmd_auto_gating_e????? = 1;
> +	regs->common.reg010.inter_auto_gating_e????? = 1;
> +	regs->common.reg010.intra_auto_gating_e????? = 1;
> +	regs->common.reg010.transd_auto_gating_e???? = 1;
> +	regs->common.reg010.recon_auto_gating_e????? = 1;
> +	regs->common.reg010.filterd_auto_gating_e??? = 1;
> +	regs->common.reg010.bus_auto_gating_e	???? = 1;
> +	regs->common.reg010.ctrl_auto_gating_e?????? = 1;
> +	regs->common.reg010.rcb_auto_gating_e	???? = 1;
> +	regs->common.reg010.err_prc_auto_gating_e??? = 1;
> +
> +	/* Set timeout threshold */
> +	if (pixels < VDPU383_1080P_PIXELS)
> +		regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_1080p;
> +	else if (pixels < VDPU383_4K_PIXELS)
> +		regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_4K;
> +	else if (pixels < VDPU383_8K_PIXELS)
> +		regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_8K;
> +	else
> +		regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_MAX;
> +
> +	regs->common.reg016.error_proc_disable = 1;
> +
> +	/* Set ref pic address & poc */
> +	for (i = 0; i < ARRAY_SIZE(dec_params->dpb) - 1; i++) {
> +		struct vb2_buffer *vb_buf = get_ref_buf(ctx, run, i);
> +		dma_addr_t buf_dma;
> +
> +		buf_dma = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
> +
> +		/* Set reference addresses */
> +		regs->h26x_addr.reg170_185_ref_base[i] = buf_dma;
> +		regs->h26x_addr.reg195_210_payload_st_ref_base[i] = buf_dma;
> +
> +		/* Set COLMV addresses */
> +		regs->h26x_addr.reg217_232_colmv_ref_base[i] = buf_dma + ctx->colmv_offset;
> +	}
> +
> +	/* Set rlc base address (input stream) */
> +	rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
> +	regs->common_addr.reg128_strm_base = rlc_addr;
> +
> +	/* Set output base address */
> +	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
> +	regs->h26x_addr.reg168_decout_base = dst_addr;
> +	regs->h26x_addr.reg169_error_ref_base = dst_addr;
> +	regs->h26x_addr.reg192_payload_st_cur_base = dst_addr;
> +
> +	/* Set colmv address */
> +	regs->h26x_addr.reg216_colmv_cur_base = dst_addr + ctx->colmv_offset;
> +
> +	/* Set RCB addresses */
> +	for (i = 0; i < rkvdec_rcb_buf_count(ctx); i++) {
> +		regs->common_addr.reg140_162_rcb_info[i].offset = rkvdec_rcb_buf_dma_addr(ctx, i);
> +		regs->common_addr.reg140_162_rcb_info[i].size = rkvdec_rcb_buf_size(ctx, i);
> +	}
> +
> +	if (sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED) {
> +		/* Set scaling matrix */
> +		offset = offsetof(struct rkvdec_hevc_priv_tbl, scaling_list);
> +		regs->common_addr.reg132_scanlist_addr = priv_start_addr + offset;
> +	}
> +
> +	/* Set hw pps address */
> +	offset = offsetof(struct rkvdec_hevc_priv_tbl, param_set);
> +	regs->common_addr.reg131_gbl_base = priv_start_addr + offset;
> +	regs->h26x_params.reg067_global_len = sizeof(struct rkvdec_hevc_sps_pps) / 16;
> +
> +	/* Set hw rps address */
> +	offset = offsetof(struct rkvdec_hevc_priv_tbl, rps);
> +	regs->common_addr.reg129_rps_base = priv_start_addr + offset;
> +
> +	/* Set cabac table */
> +	offset = offsetof(struct rkvdec_hevc_priv_tbl, cabac_table);
> +	regs->common_addr.reg130_cabactbl_base = priv_start_addr + offset;
> +
> +	rkvdec_write_regs(ctx);
> +}
> +
> +static int rkvdec_hevc_start(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	struct rkvdec_hevc_priv_tbl *priv_tbl;
> +	struct rkvdec_hevc_ctx *hevc_ctx;
> +	struct v4l2_ctrl *ctrl;
> +	int ret;
> +
> +	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> +			????? V4L2_CID_STATELESS_HEVC_SPS);
> +	if (!ctrl)
> +		return -EINVAL;
> +
> +	ret = rkvdec_hevc_validate_sps(ctx, ctrl->p_new.p_hevc_sps);
> +	if (ret)
> +		return ret;
> +
> +	hevc_ctx = kzalloc(sizeof(*hevc_ctx), GFP_KERNEL);
> +	if (!hevc_ctx)
> +		return -ENOMEM;
> +
> +	priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl),
> +				????? &hevc_ctx->priv_tbl.dma, GFP_KERNEL);
> +	if (!priv_tbl) {
> +		ret = -ENOMEM;
> +		goto err_free_ctx;
> +	}
> +
> +	hevc_ctx->priv_tbl.size = sizeof(*priv_tbl);
> +	hevc_ctx->priv_tbl.cpu = priv_tbl;
> +	memcpy(priv_tbl->cabac_table, rkvdec_hevc_cabac_table,
> +	?????? sizeof(rkvdec_hevc_cabac_table));
> +
> +	ctx->priv = hevc_ctx;
> +	return 0;
> +
> +err_free_ctx:
> +	kfree(hevc_ctx);
> +	return ret;
> +}
> +
> +static void rkvdec_hevc_stop(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +
> +	dma_free_coherent(rkvdec->dev, hevc_ctx->priv_tbl.size,
> +			? hevc_ctx->priv_tbl.cpu, hevc_ctx->priv_tbl.dma);
> +	kfree(hevc_ctx);
> +}
> +
> +static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	struct rkvdec_hevc_run run;
> +	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
> +	struct rkvdec_hevc_priv_tbl *tbl = hevc_ctx->priv_tbl.cpu;
> +	u32 watchdog_time;
> +	u64 timeout_threshold;
> +	unsigned long axi_rate;
> +
> +	rkvdec_hevc_run_preamble(ctx, &run);
> +
> +	/*
> +	 * On vdpu383, not setting the long and short term ref sets leads to IOMMU page faults.
> +	 * To be on the safe side for this new v4l2 control, write an error in the log and mark
> +	 * the buffer as failed by returning an error here.
> +	 */
> +	if ((!ctx->has_sps_lt_rps && run.sps->num_long_term_ref_pics_sps) ||
> +		(!ctx->has_sps_st_rps && run.sps->num_short_term_ref_pic_sets)) {
> +		dev_err_ratelimited(rkvdec->dev, "Long and short term RPS not set\n");
> +		return -EINVAL;
> +	}
> +
> +	rkvdec_hevc_assemble_hw_scaling_list(ctx, &run, &tbl->scaling_list,
> +					???? &hevc_ctx->scaling_matrix_cache);
> +	assemble_hw_pps(ctx, &run);
> +	rkvdec_hevc_assemble_hw_rps(&run, &tbl->rps, &hevc_ctx->st_cache);
> +
> +	config_registers(ctx, &run);
> +
> +	rkvdec_run_postamble(ctx, &run.base);
> +
> +	/* Set watchdog at 2 times the hardware timeout threshold */
> +	timeout_threshold = hevc_ctx->regs.common.reg013_core_timeout_threshold;
> +	axi_rate = clk_get_rate(rkvdec->axi_clk);
> +
> +	if (axi_rate)
> +		watchdog_time = 2 * (1000 * timeout_threshold) / axi_rate;
> +	else
> +		watchdog_time = 2000;
> +	schedule_delayed_work(&rkvdec->watchdog_work,
> +			????? msecs_to_jiffies(watchdog_time));
> +
> +	/* Start decoding! */
> +	writel(timeout_threshold, rkvdec->link + VDPU383_LINK_TIMEOUT_THRESHOLD);
> +	writel(VDPU383_IP_CRU_MODE, rkvdec->link + VDPU383_LINK_IP_ENABLE);
> +	writel(VDPU383_DEC_E_BIT, rkvdec->link + VDPU383_LINK_DEC_ENABLE);
> +
> +	return 0;
> +}
> +
> +const struct rkvdec_coded_fmt_ops rkvdec_vdpu383_hevc_fmt_ops = {
> +	.adjust_fmt = rkvdec_hevc_adjust_fmt,
> +	.start = rkvdec_hevc_start,
> +	.stop = rkvdec_hevc_stop,
> +	.run = rkvdec_hevc_run,
> +	.try_ctrl = rkvdec_hevc_try_ctrl,
> +	.get_image_fmt = rkvdec_hevc_get_image_fmt,
> +};
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> index b72cb07de70e..326ee8f307bc 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> @@ -504,6 +504,22 @@ static const struct rkvdec_coded_fmt_desc vdpu383_coded_fmts[] = {
> ?		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
> ?		.capability = RKVDEC_CAPABILITY_H264,
> ?	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_HEVC_SLICE,
> +		.frmsize = {
> +			.min_width = 64,
> +			.max_width = 65472,
> +			.step_width = 64,
> +			.min_height = 64,
> +			.max_height = 65472,
> +			.step_height = 16,
> +		},
> +		.ctrls = &vdpu38x_hevc_ctrls,
> +		.ops = &rkvdec_vdpu383_hevc_fmt_ops,
> +		.num_decoded_fmts = ARRAY_SIZE(rkvdec_hevc_decoded_fmts),
> +		.decoded_fmts = rkvdec_hevc_decoded_fmts,
> +		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
> +	},
> ?};
> ?
> ?static bool rkvdec_is_capable(struct rkvdec_ctx *ctx, unsigned int capability)
> @@ -1447,6 +1463,78 @@ static irqreturn_t rkvdec_irq_handler(int irq, void *priv)
> ?	return cfg->irq_handler(ctx);
> ?}
> ?
> +/*
> + * Flip one or more matrices along their main diagonal and flatten them
> + * before writing it to the memory.
> + * Convert:
> + * ABCD???????? AEIM
> + * EFGH???? =>? BFJN???? =>???? AEIMBFJNCGKODHLP
> + * IJKL???????? CGKO
> + * MNOP???????? DHLP
> + */
> +static void transpose_and_flatten_matrices(u8 *output, const u8 *input,
> +					?? int matrices, int row_length)
> +{
> +	int i, j, row, x_offset, matrix_offset, rot_index, y_offset, matrix_size, new_value;
> +
> +	matrix_size = row_length * row_length;
> +	for (i = 0; i < matrices; i++) {
> +		row = 0;
> +		x_offset = 0;
> +		matrix_offset = i * matrix_size;
> +		for (j = 0; j < matrix_size; j++) {
> +			y_offset = j - (row * row_length);
> +			rot_index = y_offset * row_length + x_offset;
> +			new_value = *(input + i * matrix_size + j);
> +			output[matrix_offset + rot_index] = new_value;
> +			if ((j + 1) % row_length == 0) {
> +				row += 1;
> +				x_offset += 1;
> +			}
> +		}
> +	}
> +}
> +
> +/*
> + * VDPU383 needs a specific order:
> + * The 8x8 flatten matrix is based on 4x4 blocks.
> + * Each 4x4 block is written separately in order.
> + *
> + * Base data??? =>? Transposed??? VDPU383 transposed
> + *
> + * ABCDEFGH???????? AIQYaiqy????? AIQYBJRZ
> + * IJKLMNOP???????? BJRZbjrz????? CKS0DLT1
> + * QRSTUVWX???????? CKS0cks6????? aiqybjrz
> + * YZ012345???? =>? DLT1dlt7????? cks6dlt7
> + * abcdefgh???????? EMU2emu8????? EMU2FNV3
> + * ijklmnop???????? FNV3fnv9????? GOW4HPX5
> + * qrstuvwx???????? GOW4gow#????? emu8fnv9
> + * yz6789#$???????? HPX5hpx$????? gow#hpx$
> + *
> + * As the function reads block of 4x4 it can be used for both 4x4 and 8x8 matrices.
> + *
> + */
> +static void vdpu383_flatten_matrices(u8 *output, const u8 *input, int matrices, int row_length)
> +{
> +	u8 block;
> +	int i, j, matrix_offset, matrix_size, new_value, input_idx, line_offset, block_offset;
> +
> +	matrix_size = row_length * row_length;
> +	for (i = 0; i < matrices; i++) {
> +		matrix_offset = i * matrix_size;
> +		for (j = 0; j < matrix_size; j++) {
> +			block = j / 16;
> +			line_offset = (j % 16) / 4;
> +			block_offset = (block & 1) * 32 + (block & 2) * 2;
> +			input_idx = ((j % 4) * row_length) + line_offset + block_offset;
> +
> +			new_value = *(input + i * matrix_size + input_idx);
> +
> +			output[matrix_offset + j] = new_value;
> +		}
> +	}
> +}
> +
> ?static void rkvdec_watchdog_func(struct work_struct *work)
> ?{
> ?	struct rkvdec_dev *rkvdec;
> @@ -1510,6 +1598,7 @@ static const struct rkvdec_config config_rkvdec = {
> ?	.coded_fmts_num = ARRAY_SIZE(rkvdec_coded_fmts),
> ?	.irq_handler = rk3399_irq_handler,
> ?	.colmv_size = rkvdec_colmv_size,
> +	.flatten_matrices = transpose_and_flatten_matrices,
> ?};
> ?
> ?static const struct rcb_size_info vdpu381_rcb_sizes[] = {
> @@ -1532,6 +1621,7 @@ static const struct rkvdec_config config_vdpu381 = {
> ?	.rcb_num = ARRAY_SIZE(vdpu381_rcb_sizes),
> ?	.irq_handler = vdpu381_irq_handler,
> ?	.colmv_size = rkvdec_colmv_size,
> +	.flatten_matrices = transpose_and_flatten_matrices,
> ?	.named_regs = true,
> ?};
> ?
> @@ -1555,6 +1645,7 @@ static const struct rkvdec_config config_vdpu383 = {
> ?	.rcb_num = ARRAY_SIZE(vdpu383_rcb_sizes),
> ?	.irq_handler = vdpu383_irq_handler,
> ?	.colmv_size = rkvdec_vdpu383_colmv_size,
> +	.flatten_matrices = vdpu383_flatten_matrices,
> ?	.named_regs = true,
> ?};
> ?
> @@ -1589,7 +1680,8 @@ static const struct rkvdec_variant rk3588_vdpu381_variant = {
> ?
> ?static const struct rkvdec_variant rk3576_vdpu383_variant = {
> ?	.config = &config_vdpu383,
> -	.capabilities = RKVDEC_CAPABILITY_H264,
> +	.capabilities = RKVDEC_CAPABILITY_H264 |
> +			RKVDEC_CAPABILITY_HEVC,
> ?};
> ?
> ?static const struct of_device_id of_rkvdec_match[] = {
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> index 94e2e6429992..aed684f14766 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> @@ -123,6 +123,7 @@ struct rkvdec_config {
> ?	size_t rcb_num;
> ?	irqreturn_t (*irq_handler)(struct rkvdec_ctx *ctx);
> ?	u32 (*colmv_size)(u16 width, u16 height);
> +	void (*flatten_matrices)(u8 *output, const u8 *input, int matrices, int row_length);
> ?	bool named_regs;
> ?};
> ?
> @@ -194,5 +195,6 @@ extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_hevc_fmt_ops;
> ?
> ?/* VDPU383 ops */
> ?extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu383_h264_fmt_ops;
> +extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu383_hevc_fmt_ops;
> ?
> ?#endif /* RKVDEC_H_ */
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251210/ad3036bb/attachment-0001.sig>

From ariel.dalessandro at collabora.com  Wed Dec 10 12:49:47 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Wed, 10 Dec 2025 17:49:47 -0300
Subject: [PATCH RFC v2 02/20] drm/colorop: Allow parenting colorop to CRTC
In-Reply-To: <bc2b7afa-96c0-4b33-a413-3758ab8fd571@bootlin.com>
References: <20250917-mtk-post-blend-color-pipeline-v2-0-ac4471b44758@collabora.com>
 <20250917-mtk-post-blend-color-pipeline-v2-2-ac4471b44758@collabora.com>
 <bc2b7afa-96c0-4b33-a413-3758ab8fd571@bootlin.com>
Message-ID: <5aa65d89-9bba-4b2b-8727-7a4e69d74cbb@collabora.com>

Louis,

Following up on Nicolas' series.

On 9/19/25 9:44 AM, Louis Chauvet wrote:
> 
> 
> Le 18/09/2025 ? 02:43, N?colas F. R. A. Prado a ?crit?:
>> In order to allow for post-blend color pipelines, colorops need to be
>> assigned to a crtc rather than a plane. Add a crtc to the colorop
>> struct to enable this. Either the plane or the crtc will be set for any
>> given colorop depending on whether it is part of a pre- or post-blend
>> color pipeline.
>>
>> Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
>> ---
>> ? include/drm/drm_colorop.h | 10 ++++++++--
>> ? 1 file changed, 8 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/drm/drm_colorop.h b/include/drm/drm_colorop.h
>> index 
>> d61c6c40e47162cb8b1e7db58b6746c43ac5d202..7a4e0d0c4a3d594abecef304b1d5990434cdb231 100644
>> --- a/include/drm/drm_colorop.h
>> +++ b/include/drm/drm_colorop.h
>> @@ -206,10 +206,16 @@ struct drm_colorop {
>> ????? /**
>> ?????? * @plane:
>> ?????? *
>> -???? * The plane on which the colorop sits. A drm_colorop is always 
>> unique
>> -???? * to a plane.
>> +???? * The plane on which the colorop sits if it is a pre-blend colorop.
>> +???? * In this case it is unique to the plane.
>> +???? *
>> +???? * @crtc:
>> +???? *
>> +???? * The CRTC on which the colorop sits if it is a post-blend colorop.
>> +???? * In this case it is unique to the CRTC.
>> ?????? */
> 
> If there is a v3 of this series, I think it could be nice to have 
> something like "plane and CRTC are mutually exclusive".

Sounds good, will add in v3.

> 
> With or without this:
> Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>

Thanks,

-- 
Ariel D'Alessandro
Software Engineer

Collabora Ltd.
Platinum Building, St John's Innovation Park, Cambridge CB4 0DS, UK 
Registered in England & Wales, no. 5513718



From robh at kernel.org  Wed Dec 10 12:55:01 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Wed, 10 Dec 2025 14:55:01 -0600
Subject: [PATCH v8 1/7] dt-bindings: arm: Add support for Qualcomm TGU
 trace
In-Reply-To: <20251203090055.2432719-2-songwei.chai@oss.qualcomm.com>
References: <20251203090055.2432719-1-songwei.chai@oss.qualcomm.com>
 <20251203090055.2432719-2-songwei.chai@oss.qualcomm.com>
Message-ID: <176540010050.3328122.16194666326592248573.robh@kernel.org>


On Wed, 03 Dec 2025 01:00:49 -0800, Songwei Chai wrote:
> The Trigger Generation Unit (TGU) is designed to detect patterns or
> sequences within a specific region of the System on Chip (SoC). Once
> configured and activated, it monitors sense inputs and can detect a
> pre-programmed state or sequence across clock cycles, subsequently
> producing a trigger.
> 
>    TGU configuration space
>         offset table
>  x-------------------------x
>  |                         |
>  |                         |
>  |                         |                           Step configuration
>  |                         |                             space layout
>  |   coresight management  |                           x-------------x
>  |        registers        |                     |---> |             |
>  |                         |                     |     |  reserve    |
>  |                         |                     |     |             |
>  |-------------------------|                     |     |-------------|
>  |                         |                     |     | priority[3] |
>  |         step[7]         |<--                  |     |-------------|
>  |-------------------------|   |                 |     | priority[2] |
>  |                         |   |                 |     |-------------|
>  |           ...           |   |Steps region     |     | priority[1] |
>  |                         |   |                 |     |-------------|
>  |-------------------------|   |                 |     | priority[0] |
>  |                         |<--                  |     |-------------|
>  |         step[0]         |-------------------->      |             |
>  |-------------------------|                           |  condition  |
>  |                         |                           |             |
>  |     control and status  |                           x-------------x
>  |           space         |                           |             |
>  x-------------------------x                           |Timer/Counter|
>                                                        |             |
> 						       x-------------x
> TGU Configuration in Hardware
> 
> The TGU provides a step region for user configuration, similar
> to a flow chart. Each step region consists of three register clusters:
> 
> 1.Priority Region: Sets the required signals with priority.
> 2.Condition Region: Defines specific requirements (e.g., signal A
> reaches three times) and the subsequent action once the requirement is
> met.
> 3.Timer/Counter (Optional): Provides timing or counting functionality.
> 
> Add a new tgu.yaml file to describe the bindings required to
> define the TGU in the device trees.
> 
> Signed-off-by: Songwei Chai <songwei.chai at oss.qualcomm.com>
> ---
>  .../devicetree/bindings/arm/qcom,tgu.yaml     | 92 +++++++++++++++++++
>  1 file changed, 92 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/arm/qcom,tgu.yaml
> 

Reviewed-by: Rob Herring (Arm) <robh at kernel.org>



From ariel.dalessandro at collabora.com  Wed Dec 10 13:00:10 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Wed, 10 Dec 2025 18:00:10 -0300
Subject: [PATCH RFC v2 04/20] drm/crtc: Add COLOR_PIPELINE property
In-Reply-To: <5aaecb8b-08c6-4982-86c8-18ebb4544f4c@bootlin.com>
References: <20250917-mtk-post-blend-color-pipeline-v2-0-ac4471b44758@collabora.com>
 <20250917-mtk-post-blend-color-pipeline-v2-4-ac4471b44758@collabora.com>
 <5aaecb8b-08c6-4982-86c8-18ebb4544f4c@bootlin.com>
Message-ID: <acd144d5-9bf7-4661-9f3a-5b55a8132b10@collabora.com>

Louis,

On 9/19/25 9:43 AM, Louis Chauvet wrote:
> 
> 
> Le 18/09/2025 ? 02:43, N?colas F. R. A. Prado a ?crit?:
>> Add a COLOR_PIPELINE property to the CRTC to allow userspace to set a
>> post-blend color pipeline analogously to how pre-blend color pipelines
>> are set on planes.
>>
>> Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
>> ---
>> ? drivers/gpu/drm/drm_atomic_uapi.c | 49 +++++++++++++++++++++++++++++ 
>> ++++++----
>> ? drivers/gpu/drm/drm_crtc.c??????? | 33 ++++++++++++++++++++++++++
>> ? include/drm/drm_atomic_uapi.h???? |? 2 ++
>> ? include/drm/drm_crtc.h??????????? | 11 +++++++++
>> ? 4 files changed, 91 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/ 
>> drm_atomic_uapi.c
>> index 
>> b7cc6945864274bedd21dd5b73494f9aae216888..063c142fd9b656e228cfc660d005a3fbb4640d32 100644
>> --- a/drivers/gpu/drm/drm_atomic_uapi.c
>> +++ b/drivers/gpu/drm/drm_atomic_uapi.c
>> @@ -287,6 +287,33 @@ drm_atomic_set_colorop_for_plane(struct 
>> drm_plane_state *plane_state,
>> ? }
>> ? EXPORT_SYMBOL(drm_atomic_set_colorop_for_plane);
>> +/**
>> + * drm_atomic_set_colorop_for_crtc - set colorop for crtc
>> + * @crtc_state: atomic state object for the crtc
>> + * @colorop: colorop to use for the crtc
>> + *
>> + * Helper function to select the color pipeline on a crtc by setting
>> + * it to the first drm_colorop element of the pipeline.
>> + */
>> +void
>> +drm_atomic_set_colorop_for_crtc(struct drm_crtc_state *crtc_state,
>> +???????????????? struct drm_colorop *colorop)
>> +{
>> +??? struct drm_crtc *crtc = crtc_state->crtc;
>> +
>> +??? if (colorop)
>> +??????? drm_dbg_atomic(crtc->dev,
>> +?????????????????? "Set [COLOROP:%d] for [CRTC:%d:%s] state %p\n",
>> +?????????????????? colorop->base.id, crtc->base.id, crtc->name,
>> +?????????????????? crtc_state);
>> +??? else
>> +??????? drm_dbg_atomic(crtc->dev,
>> +?????????????????? "Set [NOCOLOROP] for [CRTC:%d:%s] state %p\n",
>> +?????????????????? crtc->base.id, crtc->name, crtc_state);
>> +
>> +??? crtc_state->color_pipeline = colorop;
>> +}
>> +EXPORT_SYMBOL(drm_atomic_set_colorop_for_crtc);
>> ? /**
>> ?? * drm_atomic_set_crtc_for_connector - set CRTC for connector
>> @@ -396,8 +423,8 @@ static s32 __user 
>> *get_out_fence_for_connector(struct drm_atomic_state *state,
>> ? }
>> ? static int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
>> -??????? struct drm_crtc_state *state, struct drm_property *property,
>> -??????? uint64_t val)
>> +??????? struct drm_crtc_state *state, struct drm_file *file_priv,
>> +??????? struct drm_property *property, uint64_t val)
>> ? {
>> ????? struct drm_device *dev = crtc->dev;
>> ????? struct drm_mode_config *config = &dev->mode_config;
>> @@ -406,7 +433,17 @@ static int drm_atomic_crtc_set_property(struct 
>> drm_crtc *crtc,
>> ????? if (property == config->prop_active)
>> ????????? state->active = val;
>> -??? else if (property == config->prop_mode_id) {
>> +??? else if (property == crtc->color_pipeline_property) {
>> +??????? /* find DRM colorop object */
>> +??????? struct drm_colorop *colorop = NULL;
>> +
>> +??????? colorop = drm_colorop_find(dev, file_priv, val);
>> +
>> +??????? if (val && !colorop)
>> +??????????? return -EACCES;
>> +
>> +??????? drm_atomic_set_colorop_for_crtc(state, colorop);
> 
> I don't know if this is needed, but you added a warning/early return for 
> ctm/degamma_lut if file_priv->post_blend_color_pipeline is true.
> 
> Does it make sense to add this?
> 
>  ????if (!file_priv->post_blend_color_pipeline) {
>  ??????????? drm_dbg_atomic(dev,
>  ??????????????? "Setting COLOR_PIPELINE property not permitted without 
> DRM_CLIENT_CAP_POST_BLEND_COLOR_PIPELINE client cap\n");
>  ??????????? return -EINVAL;
>  ??????? }

Indeed that makes sense. Will add in v3.

Thanks,

-- 
Ariel D'Alessandro
Software Engineer

Collabora Ltd.
Platinum Building, St John's Innovation Park, Cambridge CB4 0DS, UK 
Registered in England & Wales, no. 5513718



From robh at kernel.org  Wed Dec 10 13:13:08 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Wed, 10 Dec 2025 15:13:08 -0600
Subject: [PATCH 01/12] dt-bindings: phy: mediatek,hdmi-phy: Fix clock
 output names for MT8195
In-Reply-To: <20251209-mtk-genio-evk-hdmi-support-v1-1-9a6106effba6@collabora.com>
References: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>
 <20251209-mtk-genio-evk-hdmi-support-v1-1-9a6106effba6@collabora.com>
Message-ID: <176540118761.3352108.7929645042751556704.robh@kernel.org>


On Tue, 09 Dec 2025 17:34:31 +0100, Louis-Alexis Eyraud wrote:
> From: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
> 
> For all of the HDMI PHYs compatible with the one found on MT8195
> the output clock has a different datasheet name and specifically
> it is called "hdmi_txpll", differently from the older HDMI PHYs
> which output block is called "hdmitx_dig_cts".
> 
> Replace clock output name string check by max item number one to allow
> the new name on all of the HDMI PHY IPs that are perfectly compatible
> with MT8195.
> 
> Fixes: c78fe548b062 ("dt-bindings: phy: mediatek: hdmi-phy: Add mt8195 compatible")
> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
> [Louis-Alexis Eyraud: splitted patch, addressed previous feedback from
> mailing list, and reworded description]
> Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
> ---
>  Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)
> 

Reviewed-by: Rob Herring (Arm) <robh at kernel.org>



From ariel.dalessandro at collabora.com  Wed Dec 10 13:15:20 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Wed, 10 Dec 2025 18:15:20 -0300
Subject: [PATCH RFC v2 19/20] drm/vkms: Introduce support for post-blend
 color pipeline
In-Reply-To: <951318ca-f43a-48d7-a419-3bd89d135248@bootlin.com>
References: <20250917-mtk-post-blend-color-pipeline-v2-0-ac4471b44758@collabora.com>
 <20250917-mtk-post-blend-color-pipeline-v2-19-ac4471b44758@collabora.com>
 <951318ca-f43a-48d7-a419-3bd89d135248@bootlin.com>
Message-ID: <4c393a1a-3ded-490c-a6f8-c120dfcf1188@collabora.com>

Louis,

On 9/19/25 9:50 AM, Louis Chauvet wrote:
> 
> 
> Le 18/09/2025 ? 02:43, N?colas F. R. A. Prado a ?crit?:
>> Introduce a post-blend color pipeline with the same colorop blocks as
>> the pre-blend color pipeline.
>>
>> Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
>> ---
>> ? drivers/gpu/drm/vkms/vkms_colorop.c? | 98 ++++++++++++++++++++++++++ 
>> ++++++++++
>> ? drivers/gpu/drm/vkms/vkms_composer.c |? 5 +-
>> ? drivers/gpu/drm/vkms/vkms_crtc.c???? |? 1 +
>> ? drivers/gpu/drm/vkms/vkms_drv.h????? |? 1 +
>> ? 4 files changed, 104 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/gpu/drm/vkms/vkms_colorop.c b/drivers/gpu/drm/ 
>> vkms/vkms_colorop.c
>> index 
>> 5924ae2bd40fc904048f99bc9b96308140709e25..54c512db68eef16435d5f79453784f7784d540fb 100644
>> --- a/drivers/gpu/drm/vkms/vkms_colorop.c
>> +++ b/drivers/gpu/drm/vkms/vkms_colorop.c
>> @@ -98,6 +98,86 @@ vkms_initialize_pre_blend_color_pipeline(struct 
>> drm_plane *plane,
>> ????? return ret;
>> ? }
>> +static int
>> +vkms_initialize_post_blend_color_pipeline(struct drm_crtc *crtc,
>> +????????????????????? struct drm_prop_enum_list *list)
>> +{
>> +??? struct drm_colorop *ops[MAX_COLOR_PIPELINE_OPS];
>> +??? struct drm_device *dev = crtc->dev;
>> +??? int ret;
>> +??? int i = 0;
>> +
>> +??? memset(ops, 0, sizeof(ops));
>> +
>> +??? /* 1st op: 1d curve */
>> +??? ops[i] = kzalloc(sizeof(*ops[i]), GFP_KERNEL);
>> +??? if (!ops[i]) {
>> +??????? ret = -ENOMEM;
>> +??????? goto cleanup;
>> +??? }
>> +
>> +??? ret = drm_crtc_colorop_curve_1d_init(dev, ops[i], crtc, 
>> supported_tfs,
>> +???????????????????????? DRM_COLOROP_FLAG_ALLOW_BYPASS);
>> +??? if (ret)
>> +??????? goto cleanup;
>> +
>> +??? list->type = ops[i]->base.id;
>> +??? list->name = kasprintf(GFP_KERNEL, "Color Pipeline %d", ops[i]- 
>> >base.id);
>> +
>> +??? i++;
>> +
>> +??? /* 2nd op: 3x4 matrix */
>> +??? ops[i] = kzalloc(sizeof(*ops[i]), GFP_KERNEL);
>> +??? if (!ops[i]) {
>> +??????? ret = -ENOMEM;
>> +??????? goto cleanup;
>> +??? }
>> +
>> +??? ret = drm_crtc_colorop_ctm_3x4_init(dev, ops[i], crtc, 
>> DRM_COLOROP_FLAG_ALLOW_BYPASS);
>> +??? if (ret)
>> +??????? goto cleanup;
>> +
>> +??? drm_colorop_set_next_property(ops[i - 1], ops[i]);
>> +
>> +??? i++;
>> +
>> +??? /* 3rd op: 3x4 matrix */
>> +??? ops[i] = kzalloc(sizeof(*ops[i]), GFP_KERNEL);
>> +??? if (!ops[i]) {
>> +??????? ret = -ENOMEM;
>> +??????? goto cleanup;
>> +??? }
>> +
>> +??? ret = drm_crtc_colorop_ctm_3x4_init(dev, ops[i], crtc, 
>> DRM_COLOROP_FLAG_ALLOW_BYPASS);
>> +??? if (ret)
>> +??????? goto cleanup;
>> +
>> +??? drm_colorop_set_next_property(ops[i - 1], ops[i]);
>> +
>> +??? i++;
>> +
>> +??? /* 4th op: 1d curve */
>> +??? ops[i] = kzalloc(sizeof(*ops[i]), GFP_KERNEL);
>> +??? if (!ops[i]) {
>> +??????? ret = -ENOMEM;
>> +??????? goto cleanup;
>> +??? }
>> +
>> +??? ret = drm_crtc_colorop_curve_1d_init(dev, ops[i], crtc, 
>> supported_tfs,
>> +???????????????????????? DRM_COLOROP_FLAG_ALLOW_BYPASS);
>> +??? if (ret)
>> +??????? goto cleanup;
>> +
>> +??? drm_colorop_set_next_property(ops[i - 1], ops[i]);
>> +
>> +??? return 0;
>> +
>> +cleanup:
>> +??? drm_colorop_pipeline_destroy(dev);
> 
> Same comment as for pre_blend colorops, it feel strange to destroy all 
> the pipelines here.
> 
> The suggestion in [1] is better (don't forget to add the kfree).
> 
> [1]: https://lore.kernel.org/all/73f01810-df2d-4e39-a20b- 
> fc1cec2c5e12 at amd.com/
Ack, will be addressed in v3.

Regards,

-- 
Ariel D'Alessandro
Software Engineer

Collabora Ltd.
Platinum Building, St John's Innovation Park, Cambridge CB4 0DS, UK 
Registered in England & Wales, no. 5513718



From vaibhavgupta40 at gmail.com  Wed Dec 10 13:17:25 2025
From: vaibhavgupta40 at gmail.com (Vaibhav Gupta)
Date: Wed, 10 Dec 2025 21:17:25 +0000
Subject: [PATCH v1 1/2] Bluetooth: hci_bcm4377: Use generic power management
Message-ID: <20251210211728.544677-1-vaibhavgupta40@gmail.com>

Switch to the generic PCI power management framework and remove legacy
callbacks like .suspend() and .resume(). With the generic framework, the
standard PCI related work like:
        - pci_save/restore_state()
        - pci_enable/disable_device()
        - pci_set_power_state()
is handled by the PCI core and this driver should implement only
hci_bcm4377 specific operations in its respective callback functions.

Signed-off-by: Vaibhav Gupta <vaibhavgupta40 at gmail.com>
---
 drivers/bluetooth/hci_bcm4377.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/bluetooth/hci_bcm4377.c b/drivers/bluetooth/hci_bcm4377.c
index 45e6d84224ee..925d0a635945 100644
--- a/drivers/bluetooth/hci_bcm4377.c
+++ b/drivers/bluetooth/hci_bcm4377.c
@@ -2416,8 +2416,9 @@ static int bcm4377_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 					hdev);
 }
 
-static int bcm4377_suspend(struct pci_dev *pdev, pm_message_t state)
+static int bcm4377_suspend(struct device *dev)
 {
+	struct pci_dev *pdev = to_pci_dev(dev);
 	struct bcm4377_data *bcm4377 = pci_get_drvdata(pdev);
 	int ret;
 
@@ -2431,8 +2432,9 @@ static int bcm4377_suspend(struct pci_dev *pdev, pm_message_t state)
 	return 0;
 }
 
-static int bcm4377_resume(struct pci_dev *pdev)
+static int bcm4377_resume(struct device *dev)
 {
+	struct pci_dev *pdev = to_pci_dev(dev);
 	struct bcm4377_data *bcm4377 = pci_get_drvdata(pdev);
 
 	iowrite32(BCM4377_BAR0_SLEEP_CONTROL_UNQUIESCE,
@@ -2441,6 +2443,8 @@ static int bcm4377_resume(struct pci_dev *pdev)
 	return hci_resume_dev(bcm4377->hdev);
 }
 
+static DEFINE_SIMPLE_DEV_PM_OPS(bcm4377_ops, bcm4377_suspend, bcm4377_resume);
+
 static const struct dmi_system_id bcm4377_dmi_board_table[] = {
 	{
 		.matches = {
@@ -2541,8 +2545,7 @@ static struct pci_driver bcm4377_pci_driver = {
 	.name = "hci_bcm4377",
 	.id_table = bcm4377_devid_table,
 	.probe = bcm4377_probe,
-	.suspend = bcm4377_suspend,
-	.resume = bcm4377_resume,
+	.driver.pm = &bcm4377_ops,
 };
 module_pci_driver(bcm4377_pci_driver);
 
-- 
2.51.0



From robh at kernel.org  Wed Dec 10 13:19:03 2025
From: robh at kernel.org (Rob Herring)
Date: Wed, 10 Dec 2025 15:19:03 -0600
Subject: [PATCH 03/12] dt-bindings: phy: mediatek,hdmi-phy: Document
 extra clocks for MT8195
In-Reply-To: <20251209-mtk-genio-evk-hdmi-support-v1-3-9a6106effba6@collabora.com>
References: <20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6@collabora.com>
 <20251209-mtk-genio-evk-hdmi-support-v1-3-9a6106effba6@collabora.com>
Message-ID: <20251210211903.GA3352325-robh@kernel.org>

On Tue, Dec 09, 2025 at 05:34:33PM +0100, Louis-Alexis Eyraud wrote:
> From: "N?colas F. R. A. Prado" <nfraprado at collabora.com>
> 
> MT8195's HDMI PHY block has 4 clocks instead of just a single one.
> Describe the extra clocks for it.
> 
> Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
> Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
> ---
>  .../devicetree/bindings/phy/mediatek,hdmi-phy.yaml | 36 +++++++++++++++++++---
>  1 file changed, 32 insertions(+), 4 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml
> index cd4ac42ee45e4648ed512f68f6f28d1f3f2e1116..91f8118689d5e838c4d75264822bb09a00fea21b 100644
> --- a/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml
> +++ b/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml
> @@ -38,12 +38,12 @@ properties:
>      maxItems: 1
>  
>    clocks:
> -    items:
> -      - description: PLL reference clock
> +    minItems: 1
> +    maxItems: 4
>  
>    clock-names:
> -    items:
> -      - const: pll_ref
> +    minItems: 1
> +    maxItems: 4
>  
>    clock-output-names:
>      maxItems: 1
> @@ -79,6 +79,34 @@ required:
>    - "#phy-cells"
>    - "#clock-cells"
>  
> +allOf:
> +  - if:
> +      properties:
> +        compatible:
> +          const: mediatek,mt8195-hdmi-phy

You just said mt8188 is compatible, but it's excluded here. If mt8188 
can work without knowing about the 3 new clocks (and no driver changes), 
then it is compatible .

> +    then:
> +      properties:
> +        clocks:
> +          items:
> +            - description: PLL reference clock
> +            - description: HDMI 26MHz clock
> +            - description: HDMI PLL1 clock
> +            - description: HDMI PLL2 clock
> +        clock-names:
> +          items:
> +            - const: pll_ref
> +            - const: hdmi_26m
> +            - const: hdmi_pll1
> +            - const: hdmi_pll2

Move all this to the top-level (so just add entries 2-4) and add 
'minItems: 1'. Here, just put 'minItems: 4' except that I assume it did 
work with 1 clock, so requiring 4 breaks the ABI.

Also, drop 'hdmi_'. It's redundant.

> +    else:
> +      properties:
> +        clocks:
> +          items:
> +            - description: PLL reference clock
> +        clock-names:
> +          items:
> +            - const: pll_ref

And here, just 'maxItems: 1'

> +
>  additionalProperties: false
>  
>  examples:
> 
> -- 
> 2.52.0
> 


From paulk at sys-base.io  Wed Dec 10 14:09:33 2025
From: paulk at sys-base.io (Paul Kocialkowski)
Date: Wed, 10 Dec 2025 23:09:33 +0100
Subject: Kconfig dangling references (BZ 216748)
In-Reply-To: <20251208200555.GA333481@robin.jannau.net>
References: <22b92ddf-6321-41b5-8073-f9c7064d3432@infradead.org>
 <aTcVXrUXVsyjaT22@shepard>
 <20251208200555.GA333481@robin.jannau.net>
Message-ID: <aTnvnaRuJ5lF4dVv@collins>

Hi Janne,

Le Mon 08 Dec 25, 21:05, Janne Grunau a ?crit :
> On Mon, Dec 08, 2025 at 07:13:50PM +0100, Paul Kocialkowski wrote:
> > Hi Randy,
> > 
> > On Sun 07 Dec 25, 18:04, Randy Dunlap wrote:
> > > from  https://bugzilla.kernel.org/show_bug.cgi?id=216748
> > > 
> > > The bugzilla entry includes a Perl script and a shell script.
> > > This is the edited result of running them (I removed some entries that were noise).
> > 
> > [...]
> > 
> > > DRM_KMS_DMA_HELPER ---
> > > drivers/gpu/drm/adp/Kconfig:9:	select DRM_KMS_DMA_HELPER
> > > drivers/gpu/drm/logicvc/Kconfig:7:	select DRM_KMS_DMA_HELPER
> > 
> > For these two, the symbol was removed in commit
> > 09717af7d13d63df141ae6e71686289989d17efd
> 
> That commit removed DRM_KMS_CMA_HELPER. Later commit 6bcfe8eaeef0
> ("drm/fb: rename FB CMA helpers to FB DMA helpers") renamed
> DRM_KMS_CMA_HELPER erroneously to DRM_KMS_DMA_HELPER.
> 
> > but these two drivers either were
> > missed by the batch rename or were introduced a bit later.
> 
> In the case of drivers/gpu/drm/adp/Kconfig it was missed much later
> during review (but iirc went through the same rename out of tree).
> 
> > Since the symbol selected DRM_GEM_CMA_HELPER (which is still needed by the
> > drivers), it should be replaced with DRM_GEM_CMA_HELPER.
> 
> That symbol doesn't exist anymore either. It's now DRM_GEM_DMA_HELPER
> which is already present in both files.

Thanks for the details! It seems that I was looking at an older tree.

> So the "select DRM_KMS_DMA_HELPER" lines can be removed from both files.

Good, then I'll craft a patch removing these two lines.

All the best,

Paul

-- 
Paul Kocialkowski,

Independent contractor - sys-base - https://www.sys-base.io/
Free software developer - https://www.paulk.fr/

Expert in multimedia, graphics and embedded hardware support with Linux.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251210/a269f810/attachment-0001.sig>

From helgaas at kernel.org  Wed Dec 10 14:50:55 2025
From: helgaas at kernel.org (Bjorn Helgaas)
Date: Wed, 10 Dec 2025 16:50:55 -0600
Subject: [PATCH 2/8] PCI: endpoint: pci-epf-test: use new DMA API to
 simple code
In-Reply-To: <20251208-dma_prep_config-v1-2-53490c5e1e2a@nxp.com>
Message-ID: <20251210225055.GA3544934@bhelgaas>

On Mon, Dec 08, 2025 at 12:09:41PM -0500, Frank Li wrote:
> Using new API dmaengine_prep_slave_single_config() to simple code.

Capitalize and include actual interface:

  PCI: endpoint: pci-epf-test: Use dmaengine_prep_slave_single_config() to simplify code

  Use dmaengine_prep_slave_single_config() to simplify code


From helgaas at kernel.org  Wed Dec 10 14:53:25 2025
From: helgaas at kernel.org (Bjorn Helgaas)
Date: Wed, 10 Dec 2025 16:53:25 -0600
Subject: [PATCH 7/8] PCI: epf-mhi:Using new API
 dmaengine_prep_slave_single_config() to simple code.
In-Reply-To: <20251208-dma_prep_config-v1-7-53490c5e1e2a@nxp.com>
Message-ID: <20251210225325.GA3545039@bhelgaas>

On Mon, Dec 08, 2025 at 12:09:46PM -0500, Frank Li wrote:

Add space, include actual interface, add commit log:

  PCI: epf-mhi: Use dmaengine_prep_slave_single_config() to simplify code

  Use dmaengine_prep_slave_single_config() to simplify
  pci_epf_mhi_edma_read(), pci_epf_mhi_edma_write(), etc.


From helgaas at kernel.org  Wed Dec 10 14:54:55 2025
From: helgaas at kernel.org (Bjorn Helgaas)
Date: Wed, 10 Dec 2025 16:54:55 -0600
Subject: [PATCH 6/8] nvmet: pci-epf: Use
 dmaengine_prep_slave_single_config() API
In-Reply-To: <20251208-dma_prep_config-v1-6-53490c5e1e2a@nxp.com>
Message-ID: <20251210225455.GA3544539@bhelgaas>

On Mon, Dec 08, 2025 at 12:09:45PM -0500, Frank Li wrote:
> Use the new dmaengine_prep_slave_single_config() API to combine the
> configuration and descriptor preparation into a single call.
> 
> Since dmaengine_prep_slave_single_config() performs the configuration
> and preparation atomically, the mutex can be removed.

> @@ -386,22 +386,16 @@ static int nvmet_pci_epf_dma_transfer(struct nvmet_pci_epf *nvme_epf,
>  		return -EINVAL;
>  	}
>  
> -	mutex_lock(lock);
> -
>  	dma_dev = dmaengine_get_dma_device(chan);
>  	dma_addr = dma_map_single(dma_dev, seg->buf, seg->length, dir);
>  	ret = dma_mapping_error(dma_dev, dma_addr);
>  	if (ret)
> -		goto unlock;
> -
> -	ret = dmaengine_slave_config(chan, &sconf);
> -	if (ret) {
> -		dev_err(dev, "Failed to configure DMA channel\n");
> -		goto unmap;
> -	}
> +		return ret;
>  
> -	desc = dmaengine_prep_slave_single(chan, dma_addr, seg->length,
> -					   sconf.direction, DMA_CTRL_ACK);
> +	desc = dmaengine_prep_slave_single_config(chan, dma_addr, seg->length,
> +						  sconf.direction,
> +						  DMA_CTRL_ACK,
> +						  &sconf);
>  	if (!desc) {
>  		dev_err(dev, "Failed to prepare DMA\n");
>  		ret = -EIO;
> @@ -423,9 +417,6 @@ static int nvmet_pci_epf_dma_transfer(struct nvmet_pci_epf *nvme_epf,
>  unmap:
>  	dma_unmap_single(dma_dev, dma_addr, seg->length, dir);
>  
> -unlock:
> -	mutex_unlock(lock);
> -

I don't know the dmaengine code, but it's not obvious to me what makes
dmaengine_prep_slave_single_config() itself atomic, since it doesn't
contain any locking.

Bjorn


From helgaas at kernel.org  Wed Dec 10 14:55:44 2025
From: helgaas at kernel.org (Bjorn Helgaas)
Date: Wed, 10 Dec 2025 16:55:44 -0600
Subject: [PATCH 1/8] dmaengine: Add API to combine configuration and
 preparation (sg and single)
In-Reply-To: <20251208-dma_prep_config-v1-1-53490c5e1e2a@nxp.com>
Message-ID: <20251210225544.GA3542977@bhelgaas>

On Mon, Dec 08, 2025 at 12:09:40PM -0500, Frank Li wrote:
> Previously, configuration and preparation required two separate calls. This
> works well when configuration is done only once during initialization.
> 
> However, in cases where the burst length or source/destination address must
> be adjusted for each transfer, calling two functions is verbose and
> requires additional locking to ensure both steps complete atomically.
> 
> Add a new API and callback device_prep_slave_sg_config that combines
> configuration and preparation into a single operation. If the configuration
> argument is passed as NULL, fall back to the existing implementation.

Add "()" after function name.

> Signed-off-by: Frank Li <Frank.Li at nxp.com>
> ---
>  include/linux/dmaengine.h | 64 +++++++++++++++++++++++++++++++++++++++++------
>  1 file changed, 57 insertions(+), 7 deletions(-)
> 
> diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
> index 99efe2b9b4ea9844ca6161208362ef18ef111d96..6c563549133a28e26f1bdc367372b1e4a748afcf 100644
> --- a/include/linux/dmaengine.h
> +++ b/include/linux/dmaengine.h
> @@ -835,6 +835,8 @@ struct dma_filter {
>   *	where the address and size of each segment is located in one entry of
>   *	the dma_vec array.
>   * @device_prep_slave_sg: prepares a slave dma operation
> + *	(Depericated, use @device_prep_slave_sg_config)
> + * @device_prep_slave_sg_config: prepares a slave dma operation

s/Depericated/Deprecated/
s/slave dma/slave DMA/ to match other "DMA" uses


From vaibhavgupta40 at gmail.com  Wed Dec 10 15:21:09 2025
From: vaibhavgupta40 at gmail.com (Vaibhav Gupta)
Date: Wed, 10 Dec 2025 23:21:09 +0000
Subject: [PATCH v2] Bluetooth: hci_bcm4377: Use generic power management
In-Reply-To: <20251210211728.544677-1-vaibhavgupta40@gmail.com>
References: <20251210211728.544677-1-vaibhavgupta40@gmail.com>
Message-ID: <20251210232115.547729-1-vaibhavgupta40@gmail.com>

Switch to the generic PCI power management framework and remove legacy
callbacks like .suspend() and .resume(). With the generic framework, the
standard PCI related work like:
        - pci_save/restore_state()
        - pci_enable/disable_device()
        - pci_set_power_state()
is handled by the PCI core and this driver should implement only
hci_bcm4377 specific operations in its respective callback functions.

Signed-off-by: Vaibhav Gupta <vaibhavgupta40 at gmail.com>
---
v2: v1 has a typo in its subject. This patch is not part of a series. So
there should be no '[.... 1/2]'.
---
 drivers/bluetooth/hci_bcm4377.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/bluetooth/hci_bcm4377.c b/drivers/bluetooth/hci_bcm4377.c
index 45e6d84224ee..925d0a635945 100644
--- a/drivers/bluetooth/hci_bcm4377.c
+++ b/drivers/bluetooth/hci_bcm4377.c
@@ -2416,8 +2416,9 @@ static int bcm4377_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 					hdev);
 }
 
-static int bcm4377_suspend(struct pci_dev *pdev, pm_message_t state)
+static int bcm4377_suspend(struct device *dev)
 {
+	struct pci_dev *pdev = to_pci_dev(dev);
 	struct bcm4377_data *bcm4377 = pci_get_drvdata(pdev);
 	int ret;
 
@@ -2431,8 +2432,9 @@ static int bcm4377_suspend(struct pci_dev *pdev, pm_message_t state)
 	return 0;
 }
 
-static int bcm4377_resume(struct pci_dev *pdev)
+static int bcm4377_resume(struct device *dev)
 {
+	struct pci_dev *pdev = to_pci_dev(dev);
 	struct bcm4377_data *bcm4377 = pci_get_drvdata(pdev);
 
 	iowrite32(BCM4377_BAR0_SLEEP_CONTROL_UNQUIESCE,
@@ -2441,6 +2443,8 @@ static int bcm4377_resume(struct pci_dev *pdev)
 	return hci_resume_dev(bcm4377->hdev);
 }
 
+static DEFINE_SIMPLE_DEV_PM_OPS(bcm4377_ops, bcm4377_suspend, bcm4377_resume);
+
 static const struct dmi_system_id bcm4377_dmi_board_table[] = {
 	{
 		.matches = {
@@ -2541,8 +2545,7 @@ static struct pci_driver bcm4377_pci_driver = {
 	.name = "hci_bcm4377",
 	.id_table = bcm4377_devid_table,
 	.probe = bcm4377_probe,
-	.suspend = bcm4377_suspend,
-	.resume = bcm4377_resume,
+	.driver.pm = &bcm4377_ops,
 };
 module_pci_driver(bcm4377_pci_driver);
 
-- 
2.51.0



From vivek.aknurwar at oss.qualcomm.com  Wed Dec 10 15:28:37 2025
From: vivek.aknurwar at oss.qualcomm.com (Vivek Aknurwar)
Date: Wed, 10 Dec 2025 15:28:37 -0800
Subject: [PATCH 1/1] firmware: arm_scmi: Increase MAX_OPPS to 64
In-Reply-To: <20251014073454.461999-1-vivek.aknurwar@oss.qualcomm.com>
References: <20251014073454.461999-1-vivek.aknurwar@oss.qualcomm.com>
Message-ID: <6af5945e-7d5c-4596-ac42-c5898b4c49b7@oss.qualcomm.com>

Hello Sudeep/Cristian,

Just following up on this patch. If there?s anything missing or
needs adjustment, please let me know.

Thanks,
Vivek
On 10/14/2025 12:34 AM, Vivek Aknurwar wrote:
> Some upcoming SoCs define more than 32 operating performance points (OPPs),
> exceeding the current SCMI protocol limit. Increase MAX_OPPS to 64
> (next power of 2) to support these configurations.
> 
> Signed-off-by: Vivek Aknurwar <vivek.aknurwar at oss.qualcomm.com>
> ---
>  drivers/firmware/arm_scmi/perf.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c
> index 683fd9b85c5c..2249ef7fe790 100644
> --- a/drivers/firmware/arm_scmi/perf.c
> +++ b/drivers/firmware/arm_scmi/perf.c
> @@ -27,7 +27,7 @@
>  /* Updated only after ALL the mandatory features for that version are merged */
>  #define SCMI_PROTOCOL_SUPPORTED_VERSION		0x40000
>  
> -#define MAX_OPPS		32
> +#define MAX_OPPS		64
>  
>  enum scmi_performance_protocol_cmd {
>  	PERF_DOMAIN_ATTRIBUTES = 0x3,



From jassisinghbrar at gmail.com  Wed Dec 10 15:31:04 2025
From: jassisinghbrar at gmail.com (Jassi Brar)
Date: Wed, 10 Dec 2025 17:31:04 -0600
Subject: [GIT PULL] Mailbox changes for v6.19
Message-ID: <CABb+yY0Uvkc4g0=gi79j+CCJzKkeuHGD9u_6P5ScAFkNS0F+2w@mail.gmail.com>

Hi Linus,
The following changes since commit 7d0a66e4bb9081d75c82ec4957c50034cb0ea449:

  Linux 6.18 (2025-11-30 14:42:10 -0800)

are available in the Git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/jassibrar/mailbox.git
tags/mailbox-v6.19

for you to fetch changes up to 175956b6672f93491da9c78d686f310311f0855e:

  mailbox: mtk-cmdq: Remove unsued cmdq_get_shift_pa() (2025-12-10
17:17:01 -0600)

----------------------------------------------------------------
pcc:      refactor and improve initialisation and interrupt handling
qcom:     enable Kaanapali and Glymur platforms
renesas:  add MFIS mailbox driver
mediatek: add mtk-vcp-mailbox driver and bindings
          add support for MT8196 into mtk-cmdq
misc:     mtk-cmdq: Remove unsued cmdq_get_shift_pa
          remove unneeded double quotation in Kconfig
          drop POLARFIRE from ARCH_MICROCHIP_POLARFIRE
          fix out-of-bounds access in mchp_ipc_get_cluster_aggr_irq

----------------------------------------------------------------
Conor Dooley (1):
      mailbox: mpfs: drop POLARFIRE from ARCH_MICROCHIP_POLARFIRE

Jason-JH Lin (5):
      mailbox: mtk-cmdq: Add cmdq private data to cmdq_pkt for
generating instruction
      mailbox: mtk-cmdq: Add GCE hardware virtualization configuration
      mailbox: mtk-cmdq: Add mminfra_offset configuration for DRAM transaction
      mailbox: mtk-cmdq: Add driver data to support for MT8196
      mailbox: mtk-cmdq: Remove unsued cmdq_get_shift_pa()

Jingyi Wang (2):
      dt-bindings: mailbox: qcom: Add IPCC support for Kaanapali and
Glymur Platforms
      dt-bindings: mailbox: qcom: Add CPUCP mailbox controller
bindings for Kaanapali

Jjian Zhou (2):
      dt-bindings: mailbox: mediatek,mt8196-vcp-mbox: add mtk vcp-mbox document
      mailbox: mediatek: Add mtk-vcp-mailbox driver

Joonwon Kang (1):
      mailbox: Prevent out-of-bounds access in fw_mbox_index_xlate()

Kuninori Morimoto (2):
      mailbox: remove unneeded double quotation
      mailbox: renesas: Support MFIS mailbox driver

Pierre-Henry Moussay (1):
      dt-bindings: mbox: add pic64gx mailbox compatibility to mpfs mailbox

Sudeep Holla (6):
      Revert "mailbox/pcc: support mailbox management of the shared buffer"
      mailbox: pcc: Wire up ->last_tx_done() for PCC channels
      mailbox: pcc: Set txdone_irq/txdone_poll based on PCCT flags
      mailbox: pcc: Mark Tx as complete in PCC IRQ handler
      mailbox: pcc: Initialize SHMEM before binding the channel with the client
      mailbox: pcc: Clear any pending responder interrupts before enabling it

Valentina Fernandez (1):
      mailbox: mchp-ipc-sbi: fix out-of-bounds access in
mchp_ipc_get_cluster_aggr_irq()

 .../bindings/mailbox/mediatek,mt8196-vcp-mbox.yaml |  49 ++++++
 .../bindings/mailbox/microchip,mpfs-mailbox.yaml   |   6 +-
 .../bindings/mailbox/qcom,cpucp-mbox.yaml          |   1 +
 .../devicetree/bindings/mailbox/qcom-ipcc.yaml     |   2 +
 drivers/mailbox/Kconfig                            |  22 ++-
 drivers/mailbox/Makefile                           |   4 +
 drivers/mailbox/mailbox-mchp-ipc-sbi.c             |  22 +--
 drivers/mailbox/mailbox.c                          |   6 +-
 drivers/mailbox/mtk-cmdq-mailbox.c                 |  72 ++++++++-
 drivers/mailbox/mtk-vcp-mailbox.c                  | 170 +++++++++++++++++++++
 drivers/mailbox/pcc.c                              | 118 +++-----------
 drivers/mailbox/rcar-mfis-mailbox.c                | 168 ++++++++++++++++++++
 include/acpi/pcc.h                                 |  29 ----
 include/linux/mailbox/mtk-cmdq-mailbox.h           |  19 ++-
 include/linux/mailbox/mtk-vcp-mailbox.h            |  32 ++++
 15 files changed, 567 insertions(+), 153 deletions(-)
 create mode 100644
Documentation/devicetree/bindings/mailbox/mediatek,mt8196-vcp-mbox.yaml
 create mode 100644 drivers/mailbox/mtk-vcp-mailbox.c
 create mode 100644 drivers/mailbox/rcar-mfis-mailbox.c
 create mode 100644 include/linux/mailbox/mtk-vcp-mailbox.h


From lkp at intel.com  Wed Dec 10 15:38:13 2025
From: lkp at intel.com (kernel test robot)
Date: Thu, 11 Dec 2025 07:38:13 +0800
Subject: [PATCH 8/8] crypto: atmel: Use
 dmaengine_prep_slave_single_config() API
In-Reply-To: <20251208-dma_prep_config-v1-8-53490c5e1e2a@nxp.com>
References: <20251208-dma_prep_config-v1-8-53490c5e1e2a@nxp.com>
Message-ID: <202512110702.EhO0gmFG-lkp@intel.com>

Hi Frank,

kernel test robot noticed the following build warnings:

[auto build test WARNING on bc04acf4aeca588496124a6cf54bfce3db327039]

url:    https://github.com/intel-lab-lkp/linux/commits/Frank-Li/dmaengine-Add-API-to-combine-configuration-and-preparation-sg-and-single/20251209-011820
base:   bc04acf4aeca588496124a6cf54bfce3db327039
patch link:    https://lore.kernel.org/r/20251208-dma_prep_config-v1-8-53490c5e1e2a%40nxp.com
patch subject: [PATCH 8/8] crypto: atmel: Use dmaengine_prep_slave_single_config() API
config: i386-allmodconfig (https://download.01.org/0day-ci/archive/20251211/202512110702.EhO0gmFG-lkp at intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251211/202512110702.EhO0gmFG-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512110702.EhO0gmFG-lkp at intel.com/

All warnings (new ones prefixed by >>):

   drivers/crypto/atmel-aes.c: In function 'atmel_aes_dma_transfer_start':
>> drivers/crypto/atmel-aes.c:798:13: warning: unused variable 'err' [-Wunused-variable]
     798 |         int err;
         |             ^~~


vim +/err +798 drivers/crypto/atmel-aes.c

cadc4ab8f6f737 Nicolas Royer   2013-02-20  788  
bbe628ed897d72 Cyrille Pitchen 2015-12-17  789  static int atmel_aes_dma_transfer_start(struct atmel_aes_dev *dd,
bbe628ed897d72 Cyrille Pitchen 2015-12-17  790  					enum dma_slave_buswidth addr_width,
bbe628ed897d72 Cyrille Pitchen 2015-12-17  791  					enum dma_transfer_direction dir,
bbe628ed897d72 Cyrille Pitchen 2015-12-17  792  					u32 maxburst)
bbe628ed897d72 Cyrille Pitchen 2015-12-17  793  {
bbe628ed897d72 Cyrille Pitchen 2015-12-17  794  	struct dma_async_tx_descriptor *desc;
bbe628ed897d72 Cyrille Pitchen 2015-12-17  795  	struct dma_slave_config config;
bbe628ed897d72 Cyrille Pitchen 2015-12-17  796  	dma_async_tx_callback callback;
bbe628ed897d72 Cyrille Pitchen 2015-12-17  797  	struct atmel_aes_dma *dma;
bbe628ed897d72 Cyrille Pitchen 2015-12-17 @798  	int err;
bbe628ed897d72 Cyrille Pitchen 2015-12-17  799  
bbe628ed897d72 Cyrille Pitchen 2015-12-17  800  	memset(&config, 0, sizeof(config));
bbe628ed897d72 Cyrille Pitchen 2015-12-17  801  	config.src_addr_width = addr_width;
bbe628ed897d72 Cyrille Pitchen 2015-12-17  802  	config.dst_addr_width = addr_width;
bbe628ed897d72 Cyrille Pitchen 2015-12-17  803  	config.src_maxburst = maxburst;
bbe628ed897d72 Cyrille Pitchen 2015-12-17  804  	config.dst_maxburst = maxburst;
bbe628ed897d72 Cyrille Pitchen 2015-12-17  805  
bbe628ed897d72 Cyrille Pitchen 2015-12-17  806  	switch (dir) {
bbe628ed897d72 Cyrille Pitchen 2015-12-17  807  	case DMA_MEM_TO_DEV:
bbe628ed897d72 Cyrille Pitchen 2015-12-17  808  		dma = &dd->src;
bbe628ed897d72 Cyrille Pitchen 2015-12-17  809  		callback = NULL;
bbe628ed897d72 Cyrille Pitchen 2015-12-17  810  		config.dst_addr = dd->phys_base + AES_IDATAR(0);
bbe628ed897d72 Cyrille Pitchen 2015-12-17  811  		break;
cadc4ab8f6f737 Nicolas Royer   2013-02-20  812  
bbe628ed897d72 Cyrille Pitchen 2015-12-17  813  	case DMA_DEV_TO_MEM:
bbe628ed897d72 Cyrille Pitchen 2015-12-17  814  		dma = &dd->dst;
bbe628ed897d72 Cyrille Pitchen 2015-12-17  815  		callback = atmel_aes_dma_callback;
bbe628ed897d72 Cyrille Pitchen 2015-12-17  816  		config.src_addr = dd->phys_base + AES_ODATAR(0);
bbe628ed897d72 Cyrille Pitchen 2015-12-17  817  		break;
cadc4ab8f6f737 Nicolas Royer   2013-02-20  818  
bbe628ed897d72 Cyrille Pitchen 2015-12-17  819  	default:
cadc4ab8f6f737 Nicolas Royer   2013-02-20  820  		return -EINVAL;
cadc4ab8f6f737 Nicolas Royer   2013-02-20  821  	}
cadc4ab8f6f737 Nicolas Royer   2013-02-20  822  
c8695132080931 Frank Li        2025-12-08  823  	desc = dmaengine_prep_slave_sg_config(dma->chan, dma->sg, dma->sg_len,
c8695132080931 Frank Li        2025-12-08  824  					      dir,
c8695132080931 Frank Li        2025-12-08  825  					      DMA_PREP_INTERRUPT | DMA_CTRL_ACK,
c8695132080931 Frank Li        2025-12-08  826  					      &config);
bbe628ed897d72 Cyrille Pitchen 2015-12-17  827  	if (!desc)
bbe628ed897d72 Cyrille Pitchen 2015-12-17  828  		return -ENOMEM;
bbe628ed897d72 Cyrille Pitchen 2015-12-17  829  
bbe628ed897d72 Cyrille Pitchen 2015-12-17  830  	desc->callback = callback;
bbe628ed897d72 Cyrille Pitchen 2015-12-17  831  	desc->callback_param = dd;
bbe628ed897d72 Cyrille Pitchen 2015-12-17  832  	dmaengine_submit(desc);
bbe628ed897d72 Cyrille Pitchen 2015-12-17  833  	dma_async_issue_pending(dma->chan);
bbe628ed897d72 Cyrille Pitchen 2015-12-17  834  
bbe628ed897d72 Cyrille Pitchen 2015-12-17  835  	return 0;
cadc4ab8f6f737 Nicolas Royer   2013-02-20  836  }
cadc4ab8f6f737 Nicolas Royer   2013-02-20  837  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From sfr at canb.auug.org.au  Wed Dec 10 16:23:43 2025
From: sfr at canb.auug.org.au (Stephen Rothwell)
Date: Thu, 11 Dec 2025 11:23:43 +1100
Subject: [GIT PULL] Mailbox changes for v6.19
In-Reply-To: <CABb+yY0Uvkc4g0=gi79j+CCJzKkeuHGD9u_6P5ScAFkNS0F+2w@mail.gmail.com>
References: <CABb+yY0Uvkc4g0=gi79j+CCJzKkeuHGD9u_6P5ScAFkNS0F+2w@mail.gmail.com>
Message-ID: <20251211112343.51f4ff1c@canb.auug.org.au>

Hi Jassi,

On Wed, 10 Dec 2025 17:31:04 -0600 Jassi Brar <jassisinghbrar at gmail.com> wrote:
>
>       mailbox: mtk-cmdq: Remove unsued cmdq_get_shift_pa()

This commit causes a build failure.

I am disappointed that none of these commits have been in linux-next
until today.

-- 
Cheers,
Stephen Rothwell
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 488 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251211/030cfede/attachment.sig>

From festevam at gmail.com  Wed Dec 10 16:46:16 2025
From: festevam at gmail.com (Fabio Estevam)
Date: Wed, 10 Dec 2025 21:46:16 -0300
Subject: [PATCH v1 3/6] arm64: dts: imx8mp-var-som: Remove UART2 console
In-Reply-To: <20251210152000.42265-4-stefano.r@variscite.com>
References: <20251210152000.42265-1-stefano.r@variscite.com> <20251210152000.42265-4-stefano.r@variscite.com>
Message-ID: <CAOMZO5B2__4qgJRni=DPxd1QoPQLwO+r9ZbdbsOWXZemVU86aw@mail.gmail.com>

Hi Stefano,

On Wed, Dec 10, 2025 at 12:20?PM Stefano Radaelli
<stefano.r at variscite.com> wrote:
>
> The VAR-SOM-MX8MP does not include an onboard console connector. The
> debug UART is provided on the Symphony carrier board, and customers may
> choose to expose any UART controller on their own carrier designs.
>
> Since UART2 is not populated on the SOM, drop the UART2 node from the
> SOM device tree.

This change is OK, but you need a patch for
imx8mp-var-som-symphony.dts to describe UART2, right?

Otherwise, people using imx8mp-var-som-symphony.dts will lose the console.

The same applies to other patches of this series.


From krzk at kernel.org  Wed Dec 10 17:16:55 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 11 Dec 2025 02:16:55 +0100
Subject: [PATCH 1/2] dt-bindings: arm: fsl: Add FRDM-IMX91S board
In-Reply-To: <aTkTz-5QoB8BuLs7@lsvm11u0000554.swis.ap-northeast-2.aws.nxp.com>
References: <20251205-imx91s-frdm-v1-0-afd6cd01c299@nxp.com>
 <20251205-imx91s-frdm-v1-1-afd6cd01c299@nxp.com>
 <4b29cc46-28a1-45f1-b24e-548513178884@kernel.org>
 <aTkTz-5QoB8BuLs7@lsvm11u0000554.swis.ap-northeast-2.aws.nxp.com>
Message-ID: <a252e741-aab3-4fec-ae8f-38634d071d77@kernel.org>

On 10/12/2025 07:31, Yanan Yang wrote:
> On Fri, Dec 05, 2025 at 09:21:55AM +0100, Krzysztof Kozlowski wrote:
>> On 05/12/2025 09:03, Yanan.Yang wrote:
>>> Add DT compatible string for NXP FRDM-IMX91S board
>>>
>>> The FRDM i.MX 91S development board is an low-cost and compact
>>> development board featuring the i.MX 91 applications processor.
>>>
>>> Signed-off-by: Yanan.Yang <yanan.yang at nxp.com>
>>
>> Are you sure your Latin name contains '.' character? Or you just copied
>> login?
>>
>>> ---
>>>  Documentation/devicetree/bindings/arm/fsl.yaml | 1 +
>>>  1 file changed, 1 insertion(+)
>>>
>>> diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
>>> index 68a2d5fecc43..82f28be401b8 100644
>>> --- a/Documentation/devicetree/bindings/arm/fsl.yaml
>>> +++ b/Documentation/devicetree/bindings/arm/fsl.yaml
>>> @@ -1412,6 +1412,7 @@ properties:
>>>          items:
>>>            - enum:
>>>                - fsl,imx91-11x11-evk       # i.MX91 11x11 EVK Board
>>> +              - fsl,imx91-11x11-frdm-s    # FRDM-IMX91S Board
>>
>> Anyway, this was sent, or something almost the same.
>>
>> Align internally before posting duplicates or at least explain why this
>> is not a duplicate It is not the job of the community to coordinate how
>> NXP employees should work. Srsly, it's NXP's job.
>>
> Hi Krzysztof,
> Thank you for your review and for pointing this out.
> 
> This patch set is not a duplicate of the FRDM-IMX91 series. It introduces
> support for a new board: FRDM-IMX91S. While FRDM-IMX91S is similar to
> FRDM-IMX91, there are hardware differences that require a separate DTS:
> 
> - 512MB LPDDR4 (FRDM-IMX91 uses 1GB)
> - 256MB FlexSPI-NAND (FRDM-IMX91 uses 8GB eMMC)
> - Single GbE port (FRDM-IMX91 has dual GbE)
> - PMIC PF9453 (FRDM-IMX91 uses PCA9451A)
> 
> These differences were described in the cover letter and commit message,
> but I can make them more explicit if needed.

I cannot find anything about it in commit msg. Look, you wrote:

"Add DT compatible string for NXP FRDM-IMX91S board

The FRDM i.MX 91S development board is an low-cost and compact
development board featuring the i.MX 91 applications processor."

so where is it? About cover letter, I usually do not read them, some
maintainers skip entirely.

Best regards,
Krzysztof


From ebiggers at kernel.org  Wed Dec 10 17:18:33 2025
From: ebiggers at kernel.org (Eric Biggers)
Date: Wed, 10 Dec 2025 17:18:33 -0800
Subject: [PATCH 01/12] lib/crypto: nh: Add NH library
In-Reply-To: <20251211011846.8179-1-ebiggers@kernel.org>
References: <20251211011846.8179-1-ebiggers@kernel.org>
Message-ID: <20251211011846.8179-2-ebiggers@kernel.org>

Add support for the NH "almost-universal hash function" to lib/crypto/,
specifically the variant of NH used in Adiantum.

This will replace the need for the "nhpoly1305" crypto_shash algorithm.
All the implementations of "nhpoly1305" use architecture-optimized code
only for the NH stage; they just use the generic C Poly1305 code for the
Poly1305 stage.  We can achieve the same result in a simpler way using
an (architecture-optimized) nh() function combined with code in
crypto/adiantum.c that passes the results to the Poly1305 library.

This commit begins this cleanup by adding the nh() function.  The code
is derived from crypto/nhpoly1305.c and include/crypto/nhpoly1305.h.

Signed-off-by: Eric Biggers <ebiggers at kernel.org>
---
 include/crypto/nh.h | 52 ++++++++++++++++++++++++++++
 lib/crypto/Kconfig  | 10 ++++++
 lib/crypto/Makefile |  8 +++++
 lib/crypto/nh.c     | 82 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 152 insertions(+)
 create mode 100644 include/crypto/nh.h
 create mode 100644 lib/crypto/nh.c

diff --git a/include/crypto/nh.h b/include/crypto/nh.h
new file mode 100644
index 000000000000..465e85bf203f
--- /dev/null
+++ b/include/crypto/nh.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * NH hash function for Adiantum
+ */
+
+#ifndef _CRYPTO_NH_H
+#define _CRYPTO_NH_H
+
+#include <linux/types.h>
+
+/* NH parameterization: */
+
+/* Endianness: little */
+/* Word size: 32 bits (works well on NEON, SSE2, AVX2) */
+
+/* Stride: 2 words (optimal on ARM32 NEON; works okay on other CPUs too) */
+#define NH_PAIR_STRIDE		2
+#define NH_MESSAGE_UNIT		(NH_PAIR_STRIDE * 2 * sizeof(u32))
+
+/* Num passes (Toeplitz iteration count): 4, to give ? = 2^{-128} */
+#define NH_NUM_PASSES		4
+#define NH_HASH_BYTES		(NH_NUM_PASSES * sizeof(u64))
+
+/* Max message size: 1024 bytes (32x compression factor) */
+#define NH_NUM_STRIDES		64
+#define NH_MESSAGE_WORDS	(NH_PAIR_STRIDE * 2 * NH_NUM_STRIDES)
+#define NH_MESSAGE_BYTES	(NH_MESSAGE_WORDS * sizeof(u32))
+#define NH_KEY_WORDS		(NH_MESSAGE_WORDS + \
+				 NH_PAIR_STRIDE * 2 * (NH_NUM_PASSES - 1))
+#define NH_KEY_BYTES		(NH_KEY_WORDS * sizeof(u32))
+
+/**
+ * nh() - NH hash function for Adiantum
+ * @key: The key.  @message_len + 48 bytes of it are used.  This is NH_KEY_BYTES
+ *	 if @message_len has its maximum length of NH_MESSAGE_BYTES.
+ * @message: The message
+ * @message_len: The message length in bytes.  Must be a multiple of 16
+ *		 (NH_MESSAGE_UNIT) and at most 1024 (NH_MESSAGE_BYTES).
+ * @hash: (output) The resulting hash value
+ *
+ * Note: the pseudocode for NH in the Adiantum paper iterates over 1024-byte
+ * segments of the message, computes a 32-byte hash for each, and returns all
+ * the hashes concatenated together.  In contrast, this function just hashes one
+ * segment and returns one hash.  It's the caller's responsibility to call this
+ * function for each 1024-byte segment and collect all the hashes.
+ *
+ * Context: Any context.
+ */
+void nh(const u32 *key, const u8 *message, size_t message_len,
+	__le64 hash[NH_NUM_PASSES]);
+
+#endif /* _CRYPTO_NH_H */
diff --git a/lib/crypto/Kconfig b/lib/crypto/Kconfig
index ee6ab129d0cf..f14c9f5974d8 100644
--- a/lib/crypto/Kconfig
+++ b/lib/crypto/Kconfig
@@ -106,10 +106,20 @@ config CRYPTO_LIB_MLDSA
 	select CRYPTO_LIB_SHA3
 	help
 	  The ML-DSA library functions.  Select this if your module uses any of
 	  the functions from <crypto/mldsa.h>.
 
+config CRYPTO_LIB_NH
+	tristate
+	help
+	  Implementation of the NH almost-universal hash function, specifically
+	  the variant of NH used in Adiantum.
+
+config CRYPTO_LIB_NH_ARCH
+	bool
+	depends on CRYPTO_LIB_NH && !UML
+
 config CRYPTO_LIB_POLY1305
 	tristate
 	help
 	  The Poly1305 library functions.  Select this if your module uses any
 	  of the functions from <crypto/poly1305.h>.
diff --git a/lib/crypto/Makefile b/lib/crypto/Makefile
index a0578105266f..929b84568809 100644
--- a/lib/crypto/Makefile
+++ b/lib/crypto/Makefile
@@ -129,10 +129,18 @@ endif # CONFIG_CRYPTO_LIB_MD5_ARCH
 obj-$(CONFIG_CRYPTO_LIB_MLDSA) += libmldsa.o
 libmldsa-y := mldsa.o
 
 ################################################################################
 
+obj-$(CONFIG_CRYPTO_LIB_NH) += libnh.o
+libnh-y := nh.o
+ifeq ($(CONFIG_CRYPTO_LIB_NH_ARCH),y)
+CFLAGS_nh.o += -I$(src)/$(SRCARCH)
+endif
+
+################################################################################
+
 obj-$(CONFIG_CRYPTO_LIB_POLY1305) += libpoly1305.o
 libpoly1305-y := poly1305.o
 ifeq ($(CONFIG_ARCH_SUPPORTS_INT128),y)
 libpoly1305-$(CONFIG_CRYPTO_LIB_POLY1305_GENERIC) += poly1305-donna64.o
 else
diff --git a/lib/crypto/nh.c b/lib/crypto/nh.c
new file mode 100644
index 000000000000..e1d0095b5289
--- /dev/null
+++ b/lib/crypto/nh.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2018 Google LLC
+ */
+
+/*
+ * Implementation of the NH almost-universal hash function, specifically the
+ * variant of NH used in Adiantum.  This is *not* a cryptographic hash function.
+ *
+ * Reference: section 6.3 of "Adiantum: length-preserving encryption for
+ * entry-level processors" (https://eprint.iacr.org/2018/720.pdf).
+ */
+
+#include <crypto/nh.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/unaligned.h>
+
+#ifdef CONFIG_CRYPTO_LIB_NH_ARCH
+#include "nh.h" /* $(SRCARCH)/nh.h */
+#else
+static bool nh_arch(const u32 *key, const u8 *message, size_t message_len,
+		    __le64 hash[NH_NUM_PASSES])
+{
+	return false;
+}
+#endif
+
+void nh(const u32 *key, const u8 *message, size_t message_len,
+	__le64 hash[NH_NUM_PASSES])
+{
+	u64 sums[4] = { 0, 0, 0, 0 };
+
+	if (nh_arch(key, message, message_len, hash))
+		return;
+
+	static_assert(NH_PAIR_STRIDE == 2);
+	static_assert(NH_NUM_PASSES == 4);
+
+	while (message_len) {
+		u32 m0 = get_unaligned_le32(message + 0);
+		u32 m1 = get_unaligned_le32(message + 4);
+		u32 m2 = get_unaligned_le32(message + 8);
+		u32 m3 = get_unaligned_le32(message + 12);
+
+		sums[0] += (u64)(u32)(m0 + key[0]) * (u32)(m2 + key[2]);
+		sums[1] += (u64)(u32)(m0 + key[4]) * (u32)(m2 + key[6]);
+		sums[2] += (u64)(u32)(m0 + key[8]) * (u32)(m2 + key[10]);
+		sums[3] += (u64)(u32)(m0 + key[12]) * (u32)(m2 + key[14]);
+		sums[0] += (u64)(u32)(m1 + key[1]) * (u32)(m3 + key[3]);
+		sums[1] += (u64)(u32)(m1 + key[5]) * (u32)(m3 + key[7]);
+		sums[2] += (u64)(u32)(m1 + key[9]) * (u32)(m3 + key[11]);
+		sums[3] += (u64)(u32)(m1 + key[13]) * (u32)(m3 + key[15]);
+		key += NH_MESSAGE_UNIT / sizeof(key[0]);
+		message += NH_MESSAGE_UNIT;
+		message_len -= NH_MESSAGE_UNIT;
+	}
+
+	hash[0] = cpu_to_le64(sums[0]);
+	hash[1] = cpu_to_le64(sums[1]);
+	hash[2] = cpu_to_le64(sums[2]);
+	hash[3] = cpu_to_le64(sums[3]);
+}
+EXPORT_SYMBOL_GPL(nh);
+
+#ifdef nh_mod_init_arch
+static int __init nh_mod_init(void)
+{
+	nh_mod_init_arch();
+	return 0;
+}
+subsys_initcall(nh_mod_init);
+
+static void __exit nh_mod_exit(void)
+{
+}
+module_exit(nh_mod_exit);
+#endif
+
+MODULE_DESCRIPTION("NH almost-universal hash function");
+MODULE_LICENSE("GPL");
-- 
2.52.0



From ebiggers at kernel.org  Wed Dec 10 17:18:34 2025
From: ebiggers at kernel.org (Eric Biggers)
Date: Wed, 10 Dec 2025 17:18:34 -0800
Subject: [PATCH 02/12] lib/crypto: tests: Add KUnit tests for NH
In-Reply-To: <20251211011846.8179-1-ebiggers@kernel.org>
References: <20251211011846.8179-1-ebiggers@kernel.org>
Message-ID: <20251211011846.8179-3-ebiggers@kernel.org>

Add some simple KUnit tests for the nh() function.

These replace the test coverage which will be lost by removing the
nhpoly1305 crypto_shash.

Note that the NH code also continues to be tested indirectly as well,
via the tests for the "adiantum(xchacha12,aes)" crypto_skcipher.

Signed-off-by: Eric Biggers <ebiggers at kernel.org>
---
 lib/crypto/tests/Kconfig            |   8 +
 lib/crypto/tests/Makefile           |   1 +
 lib/crypto/tests/nh-testvecs.h      | 298 ++++++++++++++++++++++++++++
 lib/crypto/tests/nh_kunit.c         |  43 ++++
 scripts/crypto/gen-hash-testvecs.py |  40 ++++
 5 files changed, 390 insertions(+)
 create mode 100644 lib/crypto/tests/nh-testvecs.h
 create mode 100644 lib/crypto/tests/nh_kunit.c

diff --git a/lib/crypto/tests/Kconfig b/lib/crypto/tests/Kconfig
index c9165c14fc46..4970463ea0aa 100644
--- a/lib/crypto/tests/Kconfig
+++ b/lib/crypto/tests/Kconfig
@@ -45,10 +45,18 @@ config CRYPTO_LIB_MLDSA_KUNIT_TEST
 	select CRYPTO_LIB_BENCHMARK_VISIBLE
 	select CRYPTO_LIB_MLDSA
 	help
 	  KUnit tests for the ML-DSA digital signature algorithm.
 
+config CRYPTO_LIB_NH_KUNIT_TEST
+	tristate "KUnit tests for NH" if !KUNIT_ALL_TESTS
+	depends on KUNIT
+	default KUNIT_ALL_TESTS || CRYPTO_SELFTESTS
+	select CRYPTO_LIB_NH
+	help
+	  KUnit tests for the NH almost-universal hash function.
+
 config CRYPTO_LIB_POLY1305_KUNIT_TEST
 	tristate "KUnit tests for Poly1305" if !KUNIT_ALL_TESTS
 	depends on KUNIT
 	default KUNIT_ALL_TESTS || CRYPTO_SELFTESTS
 	select CRYPTO_LIB_BENCHMARK_VISIBLE
diff --git a/lib/crypto/tests/Makefile b/lib/crypto/tests/Makefile
index 3dde0b40b2c5..f4262379f56c 100644
--- a/lib/crypto/tests/Makefile
+++ b/lib/crypto/tests/Makefile
@@ -3,10 +3,11 @@
 obj-$(CONFIG_CRYPTO_LIB_BLAKE2B_KUNIT_TEST) += blake2b_kunit.o
 obj-$(CONFIG_CRYPTO_LIB_BLAKE2S_KUNIT_TEST) += blake2s_kunit.o
 obj-$(CONFIG_CRYPTO_LIB_CURVE25519_KUNIT_TEST) += curve25519_kunit.o
 obj-$(CONFIG_CRYPTO_LIB_MD5_KUNIT_TEST) += md5_kunit.o
 obj-$(CONFIG_CRYPTO_LIB_MLDSA_KUNIT_TEST) += mldsa_kunit.o
+obj-$(CONFIG_CRYPTO_LIB_NH_KUNIT_TEST) += nh_kunit.o
 obj-$(CONFIG_CRYPTO_LIB_POLY1305_KUNIT_TEST) += poly1305_kunit.o
 obj-$(CONFIG_CRYPTO_LIB_POLYVAL_KUNIT_TEST) += polyval_kunit.o
 obj-$(CONFIG_CRYPTO_LIB_SHA1_KUNIT_TEST) += sha1_kunit.o
 obj-$(CONFIG_CRYPTO_LIB_SHA256_KUNIT_TEST) += sha224_kunit.o sha256_kunit.o
 obj-$(CONFIG_CRYPTO_LIB_SHA512_KUNIT_TEST) += sha384_kunit.o sha512_kunit.o
diff --git a/lib/crypto/tests/nh-testvecs.h b/lib/crypto/tests/nh-testvecs.h
new file mode 100644
index 000000000000..b393e1f90f31
--- /dev/null
+++ b/lib/crypto/tests/nh-testvecs.h
@@ -0,0 +1,298 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* This file was generated by: ./scripts/crypto/gen-hash-testvecs.py nh */
+
+static const u8 nh_test_key[NH_KEY_BYTES] = {
+	0x04, 0x59, 0x66, 0x92, 0x81, 0xd7, 0xe9, 0x25,
+	0x68, 0xfa, 0xb0, 0xca, 0x9f, 0xea, 0x98, 0xca,
+	0xcd, 0xbf, 0x6d, 0xa5, 0x0c, 0x22, 0xc3, 0x57,
+	0xdc, 0x35, 0x05, 0xdd, 0x5b, 0xb0, 0xce, 0xf6,
+	0xb2, 0x4c, 0x77, 0x2e, 0xd2, 0x63, 0xf0, 0x17,
+	0x60, 0xd8, 0xd3, 0xd9, 0xed, 0x34, 0xb6, 0xed,
+	0x6a, 0x11, 0xc0, 0x25, 0xda, 0xba, 0x7e, 0xef,
+	0x49, 0x13, 0xf7, 0xd9, 0xfc, 0xb6, 0xfd, 0x58,
+	0xe9, 0x5f, 0xc5, 0xc4, 0x69, 0x89, 0xba, 0xa6,
+	0x2b, 0x58, 0x8d, 0x36, 0x6c, 0xb9, 0x90, 0x1e,
+	0x64, 0xc7, 0x44, 0x84, 0x03, 0x70, 0x30, 0x47,
+	0xdd, 0x58, 0xf4, 0x87, 0x61, 0xfd, 0x9c, 0x6b,
+	0x51, 0x1b, 0x39, 0x1d, 0x6d, 0x50, 0xae, 0x19,
+	0x71, 0x03, 0xc7, 0xa7, 0x42, 0x82, 0x8f, 0xa5,
+	0x63, 0x6a, 0xe2, 0x8a, 0xad, 0x4b, 0x40, 0xa7,
+	0x3f, 0x8b, 0xe4, 0xae, 0xb2, 0x8a, 0x14, 0x78,
+	0x91, 0x07, 0xba, 0x02, 0x08, 0xc1, 0x34, 0xb8,
+	0xda, 0x61, 0x67, 0xf6, 0x98, 0x97, 0x1a, 0xcb,
+	0x0f, 0x82, 0x80, 0xff, 0x02, 0x54, 0x16, 0x57,
+	0x18, 0x35, 0xaf, 0x16, 0x17, 0x68, 0xcc, 0xc7,
+	0x52, 0xac, 0x31, 0x39, 0x60, 0xe4, 0xb4, 0xcb,
+	0x0e, 0xf9, 0x57, 0xe9, 0x96, 0xff, 0x99, 0xd6,
+	0x10, 0x96, 0x09, 0xab, 0x28, 0x92, 0x1b, 0x9f,
+	0x10, 0xde, 0x3e, 0x87, 0xb8, 0x9d, 0x2d, 0xa0,
+	0x3c, 0x91, 0x85, 0x8c, 0x9e, 0xc0, 0x97, 0x9a,
+	0xb4, 0x54, 0x7f, 0x4a, 0x63, 0xc2, 0x75, 0x0f,
+	0x0d, 0x2f, 0x62, 0x56, 0x48, 0x0e, 0xb6, 0xc7,
+	0xcf, 0x0d, 0x78, 0xca, 0xbd, 0x31, 0x9e, 0x4c,
+	0xf7, 0x3f, 0x9e, 0xc2, 0xea, 0x5e, 0x44, 0x6d,
+	0x76, 0xf9, 0xc5, 0xe0, 0x29, 0xea, 0x15, 0xbf,
+	0xaf, 0xd4, 0x75, 0xc8, 0x89, 0xcf, 0x4f, 0x17,
+	0xfd, 0x4a, 0x45, 0xa5, 0x4d, 0x2d, 0x87, 0x11,
+	0x2b, 0x3e, 0x64, 0xa2, 0x6b, 0xc5, 0x23, 0x8c,
+	0xfa, 0x71, 0x13, 0x72, 0x0e, 0x7c, 0xe1, 0x2c,
+	0x9f, 0x0e, 0x29, 0xc9, 0x15, 0xde, 0x4e, 0xd7,
+	0x42, 0x1f, 0x8e, 0xe1, 0x91, 0x99, 0x50, 0x38,
+	0x7f, 0x15, 0xc0, 0xf6, 0x4b, 0xfd, 0x9d, 0x40,
+	0xe9, 0x44, 0x51, 0xca, 0x3b, 0x83, 0x41, 0x9f,
+	0x82, 0x64, 0x66, 0x22, 0x12, 0x43, 0x1c, 0x4f,
+	0x45, 0x11, 0x3a, 0x46, 0xb1, 0x7c, 0x62, 0x0a,
+	0x9d, 0x4c, 0x99, 0x85, 0xb0, 0x10, 0x19, 0xcf,
+	0xeb, 0xf9, 0x65, 0xaf, 0xd8, 0x05, 0x9e, 0x61,
+	0x03, 0x5f, 0x15, 0x99, 0xa9, 0x05, 0x20, 0xc8,
+	0xaf, 0xab, 0x31, 0x9d, 0xd5, 0xdf, 0x24, 0xce,
+	0x2b, 0x6d, 0xd7, 0x17, 0xc3, 0x04, 0xff, 0x82,
+	0xa7, 0x18, 0x39, 0xe9, 0x0d, 0x0a, 0x5f, 0xb9,
+	0xc9, 0x86, 0x1d, 0xf8, 0x02, 0x2d, 0xc3, 0x88,
+	0x28, 0x73, 0x5c, 0xac, 0x25, 0xc9, 0xfe, 0xcb,
+	0xd2, 0xfd, 0x63, 0x74, 0xac, 0xe1, 0xb8, 0xa2,
+	0xc6, 0x2b, 0xb5, 0x40, 0x01, 0x9b, 0xed, 0xee,
+	0x7b, 0x63, 0x66, 0x05, 0x45, 0xc2, 0x6c, 0xd8,
+	0x58, 0xf1, 0xa1, 0x3d, 0xc8, 0x43, 0x59, 0x4b,
+	0x39, 0x87, 0x24, 0x64, 0x92, 0xb0, 0xab, 0x75,
+	0xf1, 0xb7, 0xbf, 0x7c, 0xde, 0xc0, 0xaf, 0x4a,
+	0xc2, 0x7b, 0xd9, 0x8a, 0x99, 0xcd, 0x83, 0x01,
+	0xe6, 0xae, 0xeb, 0x16, 0xe7, 0x54, 0x9c, 0x95,
+	0x0a, 0x91, 0x02, 0xaf, 0x9f, 0x79, 0x40, 0x45,
+	0xce, 0x47, 0x41, 0x65, 0xca, 0x80, 0x0d, 0x14,
+	0x46, 0x58, 0x5d, 0x4d, 0x28, 0x55, 0x70, 0x49,
+	0x7c, 0x32, 0x1f, 0x01, 0xaa, 0x05, 0x2f, 0xf1,
+	0xeb, 0xa3, 0xe6, 0x1d, 0xf9, 0x43, 0xe0, 0x58,
+	0x05, 0x61, 0x22, 0xc3, 0xee, 0xe4, 0x6f, 0x94,
+	0xaf, 0x82, 0xda, 0x18, 0x18, 0x63, 0x9c, 0xfa,
+	0xc0, 0x04, 0x27, 0xc5, 0x39, 0x5e, 0x7a, 0xa6,
+	0x85, 0x46, 0xb7, 0x76, 0xc9, 0x16, 0xf2, 0xf8,
+	0x40, 0x8d, 0x4b, 0x5e, 0x72, 0xf3, 0x3e, 0x12,
+	0xa4, 0x80, 0x39, 0xb2, 0x92, 0xfe, 0x6e, 0x5b,
+	0x5b, 0xad, 0xea, 0x29, 0xbc, 0x66, 0xe6, 0xfe,
+	0x80, 0x02, 0x5d, 0x83, 0x37, 0xfc, 0xde, 0x6c,
+	0x25, 0x54, 0xa2, 0xff, 0x7d, 0xb6, 0xe1, 0xd6,
+	0xcf, 0xdb, 0x60, 0xe3, 0xbe, 0x2f, 0x4e, 0xb4,
+	0xf5, 0xb4, 0x51, 0xf7, 0x5a, 0x25, 0xda, 0x40,
+	0x84, 0x5e, 0xc0, 0x0a, 0x6b, 0xfa, 0x0c, 0xfb,
+	0x5e, 0x3e, 0x12, 0x6c, 0x39, 0x35, 0xc0, 0x28,
+	0xd6, 0x1b, 0x3a, 0x72, 0xc3, 0xfe, 0xa5, 0x4c,
+	0x35, 0xa2, 0x42, 0xf6, 0x3d, 0xa5, 0xbf, 0xb5,
+	0x39, 0xe3, 0xc9, 0xd5, 0x8c, 0x1b, 0xe5, 0xef,
+	0x91, 0xd2, 0x80, 0x6f, 0xcc, 0x77, 0x44, 0x50,
+	0x62, 0xc7, 0xac, 0x29, 0xcb, 0x72, 0xda, 0x6d,
+	0xc5, 0xfe, 0xa7, 0xee, 0x8b, 0xeb, 0xfc, 0xa3,
+	0x46, 0x18, 0x5f, 0xaa, 0xc3, 0x65, 0xd0, 0x8f,
+	0x67, 0x98, 0xd6, 0xce, 0x5f, 0x84, 0xd4, 0x96,
+	0x1b, 0x67, 0xa0, 0xcf, 0xfc, 0x94, 0x55, 0x5e,
+	0x4b, 0x51, 0x68, 0xa7, 0x6d, 0x02, 0xf9, 0x53,
+	0x54, 0x86, 0x6b, 0x53, 0x39, 0xe0, 0x36, 0x23,
+	0x87, 0x1a, 0xfb, 0x53, 0x1a, 0x65, 0xd8, 0x42,
+	0xa8, 0x85, 0xfd, 0x2c, 0x7f, 0x6b, 0x7f, 0x67,
+	0x70, 0x23, 0x6c, 0xe9, 0x0b, 0xf0, 0x1e, 0x0d,
+	0x0b, 0xb4, 0xd4, 0x96, 0x14, 0x95, 0x7e, 0xf3,
+	0x9b, 0xdd, 0xd7, 0xc4, 0x24, 0x22, 0xb9, 0x9d,
+	0xb3, 0xa6, 0xac, 0x09, 0x7c, 0x00, 0xbf, 0xd0,
+	0xdc, 0xfb, 0x9b, 0x7c, 0x8c, 0xbd, 0xd4, 0x1a,
+	0x13, 0x2b, 0x82, 0x3d, 0x7c, 0x8c, 0x10, 0x47,
+	0x49, 0x6c, 0x53, 0xeb, 0xa7, 0xc2, 0xde, 0xed,
+	0xe2, 0x55, 0x93, 0x2c, 0x1a, 0x5a, 0x7d, 0xe1,
+	0x37, 0x62, 0xdd, 0x29, 0x1a, 0x72, 0x82, 0xc0,
+	0x14, 0x73, 0x5d, 0x0e, 0x9b, 0xcc, 0x54, 0x68,
+	0x3a, 0x4d, 0x56, 0x8f, 0xc9, 0x4e, 0xaf, 0x7b,
+	0xde, 0x17, 0x9c, 0x5e, 0x83, 0x82, 0x22, 0xe3,
+	0x28, 0xdf, 0x1b, 0xb6, 0xdb, 0x17, 0x90, 0x48,
+	0xb5, 0x13, 0x4e, 0xd3, 0x97, 0x5e, 0xb3, 0x9c,
+	0x16, 0x08, 0xc8, 0x77, 0xb3, 0xcd, 0x94, 0x90,
+	0x4f, 0x77, 0xaf, 0x67, 0xdd, 0x80, 0x15, 0x1c,
+	0x59, 0xfb, 0x3c, 0xec, 0xf8, 0xb3, 0x67, 0xfb,
+	0xa0, 0x94, 0x3c, 0x53, 0x99, 0x49, 0x94, 0x2c,
+	0x85, 0x26, 0x92, 0x6d, 0x8d, 0x48, 0xf6, 0x72,
+	0xdd, 0xfb, 0xb2, 0x10, 0x51, 0x5b, 0xbe, 0xd5,
+	0x70, 0x3d, 0x28, 0x94, 0x98, 0x4f, 0x6e, 0x20,
+	0x7b, 0x7d, 0x0f, 0x56, 0xc9, 0x96, 0x5f, 0x60,
+	0x2e, 0x2f, 0x9b, 0x38, 0x7f, 0xc7, 0x3c, 0x6b,
+	0x2f, 0x2b, 0x8f, 0x1f, 0x07, 0x1c, 0x85, 0x57,
+	0x16, 0x2e, 0xc7, 0x74, 0xe5, 0xf2, 0x0d, 0xfe,
+	0xef, 0x57, 0xb0, 0xa4, 0x4f, 0x4c, 0x7d, 0x81,
+	0xbb, 0xaa, 0xcb, 0xa0, 0xb0, 0x51, 0xcf, 0xc2,
+	0xee, 0x90, 0x2e, 0x5e, 0x27, 0xca, 0xd3, 0xe8,
+	0xf3, 0x55, 0x02, 0x56, 0x06, 0xa5, 0xad, 0xdf,
+	0xa3, 0xa9, 0x06, 0x05, 0x53, 0x74, 0x55, 0xd5,
+	0xd2, 0x20, 0x0a, 0x6d, 0x4a, 0xef, 0x16, 0xbf,
+	0xc3, 0xb2, 0x75, 0x93, 0xd8, 0x6e, 0x0f, 0xd2,
+	0xae, 0x3b, 0xc0, 0x00, 0x22, 0x6f, 0xb5, 0x0a,
+	0x41, 0xfc, 0xf9, 0x41, 0xfc, 0x16, 0x4f, 0xa6,
+	0x1c, 0x18, 0x41, 0x67, 0x73, 0xa8, 0x79, 0xa9,
+	0x54, 0x18, 0x4e, 0x88, 0x44, 0x0f, 0xa1, 0x5b,
+	0xf0, 0x68, 0xea, 0x3c, 0x62, 0x59, 0x8d, 0xc7,
+	0x6f, 0xd7, 0x72, 0x20, 0x74, 0x39, 0xd4, 0x3a,
+	0x41, 0x1b, 0x58, 0x57, 0x54, 0x85, 0x60, 0xca,
+	0x49, 0x4b, 0xa1, 0x04, 0x91, 0xb6, 0xf2, 0xcd,
+	0x62, 0x63, 0x67, 0xd1, 0xee, 0x6b, 0x9e, 0x5d,
+	0xd6, 0xc4, 0x58, 0x6b, 0xe1, 0xe6, 0x4a, 0xdb,
+	0xe8, 0xb1, 0x35, 0x03, 0x15, 0x8d, 0x34, 0x69,
+	0x4c, 0xd2, 0x54, 0xce, 0xe8, 0x6a, 0x69, 0x6f,
+	0xaa, 0xb5, 0x1f, 0x86, 0xed, 0xac, 0x4f, 0x16,
+	0x1e, 0x48, 0x93, 0xe8, 0x6c, 0x24, 0x1c, 0xd0,
+	0xbb, 0x61, 0xc2, 0x34, 0xdd, 0xc9, 0x5c, 0xce,
+};
+
+static const u8 nh_test_msg[NH_MESSAGE_BYTES] = {
+	0x99, 0x57, 0x61, 0x41, 0xad, 0x08, 0x7e, 0x17,
+	0xd4, 0xef, 0x0b, 0x23, 0xff, 0x0b, 0x96, 0x0a,
+	0x6c, 0x98, 0xac, 0x78, 0x5e, 0xb6, 0xb2, 0x67,
+	0x0f, 0x48, 0xf4, 0xa1, 0xe5, 0x1e, 0xfe, 0x83,
+	0xe4, 0x56, 0x2a, 0x03, 0x64, 0xff, 0x7a, 0xf3,
+	0x03, 0xfe, 0xa7, 0x86, 0xdc, 0x35, 0x79, 0x13,
+	0xf8, 0xe1, 0x59, 0x19, 0x04, 0x43, 0x24, 0x82,
+	0x44, 0x82, 0x41, 0x2b, 0xc7, 0xcf, 0xf5, 0xa4,
+	0xdc, 0xca, 0xf5, 0x34, 0xc4, 0x23, 0x3c, 0x1f,
+	0xa8, 0x84, 0x1f, 0x2a, 0xcd, 0xae, 0x9d, 0x5e,
+	0x05, 0xe2, 0xfb, 0x0c, 0x68, 0x81, 0x90, 0x11,
+	0x44, 0xf6, 0xdd, 0x5b, 0x51, 0xd3, 0xe0, 0xab,
+	0x29, 0x3a, 0xa9, 0x9c, 0xf6, 0x7e, 0x2d, 0xe3,
+	0x6c, 0x09, 0x59, 0xd7, 0xfa, 0x7f, 0x6a, 0x33,
+	0x3b, 0x23, 0x7b, 0x1b, 0xb2, 0x79, 0x5f, 0x5c,
+	0xb6, 0x2d, 0xb0, 0xf8, 0xab, 0x33, 0x28, 0xe0,
+	0x72, 0x2e, 0x2f, 0x03, 0x22, 0x16, 0xb4, 0x87,
+	0xf7, 0x14, 0x3f, 0x55, 0x8a, 0xb0, 0x47, 0xdb,
+	0x42, 0x2d, 0xc0, 0x0c, 0x0a, 0x33, 0xf8, 0xab,
+	0x44, 0xae, 0xa3, 0xc9, 0xfc, 0xf6, 0x34, 0x8c,
+	0x60, 0x30, 0x6d, 0x31, 0x70, 0xf3, 0x39, 0x53,
+	0xf1, 0x2d, 0xb9, 0x6c, 0xa6, 0x48, 0x9c, 0x9c,
+	0xc2, 0x88, 0xb3, 0xa9, 0x98, 0xb6, 0xc3, 0x47,
+	0x94, 0x02, 0x9d, 0x98, 0x6e, 0x25, 0x6c, 0xf5,
+	0x9b, 0xc6, 0x4d, 0xee, 0x07, 0x1e, 0x25, 0x8f,
+	0x01, 0xde, 0xad, 0xe5, 0x77, 0x4f, 0xd1, 0xc0,
+	0x62, 0xbb, 0x3a, 0xb9, 0x83, 0x0b, 0x29, 0x76,
+	0x4f, 0xb1, 0x86, 0x2c, 0x27, 0xc7, 0x38, 0x65,
+	0xcb, 0x78, 0xb7, 0x02, 0x10, 0x9e, 0xde, 0x83,
+	0xd1, 0xac, 0x05, 0x86, 0x23, 0xce, 0x4f, 0x8d,
+	0xcc, 0x4e, 0x3f, 0x04, 0xf4, 0x39, 0x91, 0x81,
+	0x1c, 0x42, 0x47, 0x4d, 0x50, 0xe5, 0x01, 0x22,
+	0x98, 0xcf, 0x91, 0x36, 0xb3, 0x7c, 0xcf, 0x78,
+	0x07, 0x22, 0xa9, 0x18, 0xd2, 0xcd, 0x7d, 0x4d,
+	0xa6, 0xcb, 0xaa, 0x52, 0x13, 0x49, 0x64, 0xb0,
+	0xa5, 0x3d, 0xc7, 0xc3, 0x10, 0x87, 0x2e, 0x76,
+	0xa9, 0x52, 0xc5, 0x50, 0x18, 0xc0, 0x5d, 0xb4,
+	0x4c, 0xc6, 0x7f, 0x64, 0xae, 0x53, 0xc3, 0x46,
+	0x99, 0xb7, 0x61, 0x6b, 0x08, 0x43, 0x08, 0x4c,
+	0x90, 0x2c, 0xee, 0x56, 0x91, 0xb4, 0x28, 0xa8,
+	0xa8, 0x8b, 0x3b, 0x1a, 0x67, 0x71, 0xf2, 0x81,
+	0x48, 0x20, 0x71, 0x30, 0xdd, 0x69, 0x8a, 0xc2,
+	0x4c, 0x9d, 0x4e, 0x17, 0xfb, 0x2e, 0xe7, 0x9b,
+	0x86, 0x94, 0xa5, 0xce, 0xf9, 0x74, 0x56, 0xff,
+	0x3b, 0xff, 0xd9, 0x5a, 0xc8, 0x98, 0xf5, 0x25,
+	0xa2, 0xb9, 0x66, 0x46, 0x89, 0x17, 0x39, 0x08,
+	0x69, 0x03, 0x59, 0x1e, 0x13, 0x12, 0x68, 0xe7,
+	0x2f, 0x00, 0xd3, 0xf3, 0x71, 0xd1, 0x20, 0xc5,
+	0x0b, 0x38, 0x89, 0xda, 0x62, 0x3c, 0xce, 0xea,
+	0x04, 0x19, 0x47, 0x6d, 0xd8, 0x64, 0x38, 0x60,
+	0x96, 0x71, 0x68, 0x48, 0x79, 0xf8, 0xf4, 0x76,
+	0x33, 0xf6, 0x60, 0x8d, 0x21, 0xd0, 0xee, 0x41,
+	0xc0, 0xbe, 0x33, 0x61, 0x5e, 0x66, 0xe6, 0x16,
+	0x14, 0xc7, 0xfb, 0x6c, 0xf3, 0x58, 0xef, 0x12,
+	0x7c, 0x70, 0x65, 0x5d, 0x55, 0xe8, 0xf2, 0x92,
+	0x3a, 0xfe, 0x34, 0x64, 0x31, 0x7c, 0x29, 0xbb,
+	0x01, 0x18, 0xbd, 0xb6, 0xe4, 0x1e, 0xa4, 0xf3,
+	0x7b, 0x4c, 0x6a, 0x0d, 0x01, 0xfc, 0xc7, 0x66,
+	0xc3, 0x88, 0x37, 0x25, 0xcf, 0xe9, 0xca, 0x82,
+	0xeb, 0xa1, 0x38, 0x40, 0xc9, 0xdb, 0x38, 0x7b,
+	0x78, 0xcf, 0x11, 0xa3, 0x1c, 0x6b, 0x70, 0xc8,
+	0xe1, 0x2f, 0x7c, 0x17, 0x2c, 0x58, 0x28, 0xa4,
+	0x13, 0x40, 0xc7, 0x69, 0x0f, 0x04, 0xe5, 0x8e,
+	0xf0, 0x67, 0x53, 0xea, 0x10, 0xf5, 0x83, 0xc9,
+	0xcb, 0x6b, 0x16, 0xef, 0x2e, 0x55, 0xb3, 0xdd,
+	0xed, 0xf9, 0x1a, 0x52, 0x9a, 0x73, 0x78, 0x14,
+	0x14, 0x21, 0xfc, 0xef, 0x3c, 0x40, 0xa9, 0xfe,
+	0xef, 0xd7, 0x6e, 0x28, 0x2f, 0xd3, 0x73, 0xed,
+	0xa3, 0x73, 0xb5, 0x62, 0x41, 0xe6, 0xd4, 0x79,
+	0x49, 0x31, 0x2b, 0x86, 0x74, 0x56, 0x21, 0xfe,
+	0x6d, 0xb2, 0xbe, 0x81, 0x80, 0xa6, 0x81, 0x19,
+	0x90, 0x79, 0x6f, 0xc4, 0x4e, 0x7d, 0x6f, 0x2f,
+	0xa8, 0x6f, 0xd5, 0xc4, 0x7e, 0x23, 0x3b, 0xe6,
+	0x9b, 0x60, 0x97, 0x7b, 0xe2, 0x08, 0x8a, 0xaa,
+	0xc7, 0x7c, 0xf6, 0xe5, 0x01, 0x3e, 0xd2, 0x29,
+	0x7d, 0xd7, 0x40, 0x84, 0x95, 0xfa, 0xdf, 0xd8,
+	0x81, 0xe9, 0x5e, 0xdd, 0x0d, 0x17, 0x51, 0x6b,
+	0x8c, 0x0e, 0x47, 0xf9, 0x0c, 0x92, 0x1b, 0x60,
+	0xca, 0x06, 0x8a, 0xe5, 0xe8, 0x0f, 0x06, 0x75,
+	0x5d, 0x76, 0xc9, 0x32, 0x2c, 0x52, 0x2c, 0x2e,
+	0xd8, 0x66, 0x38, 0x75, 0x16, 0xc7, 0x7d, 0x51,
+	0xc4, 0xc2, 0x22, 0xc8, 0x19, 0xfc, 0x3d, 0x69,
+	0x1e, 0xd9, 0x64, 0x47, 0x5d, 0x21, 0x84, 0x46,
+	0xd7, 0xe1, 0xf0, 0x95, 0x3a, 0x8f, 0xbd, 0x7a,
+	0x53, 0x71, 0x4c, 0x54, 0xc1, 0x3e, 0x27, 0xde,
+	0xeb, 0x04, 0x11, 0xb0, 0x33, 0x4d, 0x57, 0x0b,
+	0x6b, 0x7d, 0x6c, 0xd5, 0x87, 0x7e, 0xb4, 0xe2,
+	0x94, 0x9e, 0x9f, 0x74, 0xe8, 0xb7, 0xfa, 0x05,
+	0x9b, 0x8f, 0x81, 0x43, 0x35, 0x82, 0xb8, 0x5b,
+	0xa8, 0x5e, 0xfa, 0x7a, 0x80, 0x8d, 0xd2, 0x90,
+	0x58, 0x79, 0x89, 0x56, 0x90, 0x2b, 0xff, 0x92,
+	0x3c, 0x35, 0xbe, 0x99, 0x5f, 0xd2, 0x4b, 0x15,
+	0x58, 0x4b, 0xbf, 0x08, 0x9b, 0x9b, 0x97, 0x10,
+	0xa4, 0x55, 0xc7, 0xec, 0x29, 0xc5, 0x14, 0x3e,
+	0x8f, 0x56, 0xa3, 0x92, 0x9e, 0x33, 0xcc, 0x9e,
+	0x77, 0x2f, 0x33, 0xcb, 0xc4, 0xe9, 0x19, 0xf4,
+	0x32, 0x2b, 0xef, 0x6c, 0x1c, 0x92, 0x2c, 0x45,
+	0x88, 0x74, 0x5f, 0xcf, 0x56, 0xfd, 0x87, 0x5f,
+	0xb6, 0x9b, 0xa2, 0x51, 0xda, 0x9b, 0x83, 0x4f,
+	0xec, 0x14, 0xe8, 0xd2, 0x42, 0x03, 0xcb, 0xe8,
+	0xd0, 0xb7, 0xf8, 0x38, 0xde, 0x6f, 0xdf, 0x43,
+	0xfa, 0x41, 0xab, 0xec, 0x2e, 0x3c, 0x93, 0x39,
+	0x76, 0xd1, 0x6f, 0x5b, 0x6c, 0x6e, 0x8d, 0xeb,
+	0x45, 0x6b, 0xc5, 0x76, 0x00, 0x29, 0xca, 0x3b,
+	0xdb, 0x78, 0xc2, 0x32, 0x09, 0x39, 0x19, 0x50,
+	0xa2, 0x44, 0x92, 0x09, 0xdb, 0x8b, 0x9e, 0x16,
+	0x76, 0x7f, 0xf1, 0x78, 0x7b, 0xb2, 0x51, 0xbc,
+	0x28, 0xbd, 0xb0, 0x7f, 0x25, 0x63, 0x7d, 0x34,
+	0xfb, 0xf6, 0x36, 0x24, 0xc7, 0xf9, 0x41, 0xb6,
+	0x2a, 0x06, 0xfc, 0xf0, 0x83, 0xf2, 0x12, 0x3d,
+	0x60, 0x2e, 0x10, 0x70, 0x31, 0x6f, 0x37, 0x08,
+	0x3e, 0x91, 0x93, 0xb5, 0xda, 0xb8, 0x4c, 0x1b,
+	0xd8, 0xb8, 0x3b, 0xd5, 0x3e, 0xb6, 0xc0, 0xbb,
+	0x38, 0x0f, 0xd2, 0x68, 0x4f, 0x78, 0x56, 0xf6,
+	0xda, 0x65, 0xb4, 0x0b, 0xb4, 0xaf, 0xa8, 0x19,
+	0x2f, 0x70, 0x55, 0xe0, 0x47, 0x31, 0x9f, 0x37,
+	0x1a, 0x47, 0xb9, 0x0c, 0x97, 0x79, 0xfc, 0xa9,
+	0x76, 0xe6, 0xfa, 0x38, 0x67, 0x25, 0xd3, 0x89,
+	0x8d, 0xad, 0xc6, 0x11, 0x2d, 0x77, 0x0b, 0x35,
+	0xa2, 0xe2, 0xdf, 0xc8, 0x94, 0xd5, 0xdf, 0xd2,
+	0x69, 0x2a, 0x99, 0x93, 0xfa, 0x4a, 0x5f, 0xc7,
+	0x8a, 0x14, 0x5f, 0x2a, 0xf3, 0x02, 0xf0, 0x3e,
+	0x21, 0x8e, 0x2e, 0x4b, 0xc4, 0xd2, 0xc8, 0xa6,
+	0x41, 0x6e, 0x17, 0x36, 0xe9, 0xad, 0x73, 0x33,
+	0x6c, 0xea, 0xc2, 0x31, 0x8f, 0x30, 0x51, 0x5c,
+	0x1c, 0x20, 0xe6, 0x05, 0x1a, 0x17, 0x15, 0x5d,
+	0x3e, 0x8f, 0xd2, 0x7f, 0xa1, 0xc5, 0x47, 0xb3,
+	0xb2, 0x9c, 0xe8, 0xf0, 0x6d, 0xc1, 0xc3, 0xa2,
+};
+
+static const u8 nh_test_val16[NH_HASH_BYTES] = {
+	0x30, 0x77, 0x55, 0x7c, 0x45, 0xd8, 0xce, 0xf7,
+	0x2a, 0xb5, 0x14, 0x8c, 0x35, 0x7e, 0xaa, 0x00,
+	0x50, 0xbc, 0x50, 0x7c, 0xd3, 0x20, 0x7c, 0x9c,
+	0xb4, 0xf1, 0x91, 0x26, 0x81, 0x03, 0xa5, 0x68,
+};
+
+static const u8 nh_test_val96[NH_HASH_BYTES] = {
+	0xd2, 0x19, 0xca, 0xa5, 0x6c, 0x0c, 0xdf, 0x2f,
+	0x69, 0xfa, 0x75, 0xc1, 0x63, 0xdb, 0xfa, 0x4d,
+	0x45, 0x2b, 0xb8, 0xdb, 0xac, 0xee, 0x61, 0xc6,
+	0x7a, 0x83, 0xb6, 0x0f, 0x32, 0x82, 0xe4, 0xd0,
+};
+
+static const u8 nh_test_val256[NH_HASH_BYTES] = {
+	0x33, 0x8f, 0xb4, 0x96, 0xf1, 0xb6, 0xf1, 0xb5,
+	0x05, 0x19, 0xbb, 0x6b, 0xda, 0xd9, 0x95, 0x75,
+	0x96, 0x3f, 0x8b, 0x42, 0xb6, 0xcd, 0xb7, 0xb7,
+	0xe7, 0x97, 0xb5, 0xa9, 0x0b, 0xd7, 0xdd, 0x33,
+};
+
+static const u8 nh_test_val1024[NH_HASH_BYTES] = {
+	0x32, 0x3d, 0x51, 0xe1, 0x77, 0xb6, 0xac, 0x06,
+	0x84, 0x67, 0xb7, 0xf2, 0x24, 0xe7, 0xec, 0xfd,
+	0x96, 0x64, 0xff, 0x55, 0xc7, 0x1b, 0xf9, 0xdc,
+	0xa3, 0xc7, 0x32, 0x06, 0x79, 0xcf, 0xca, 0xb6,
+};
diff --git a/lib/crypto/tests/nh_kunit.c b/lib/crypto/tests/nh_kunit.c
new file mode 100644
index 000000000000..a8a3c3f345cb
--- /dev/null
+++ b/lib/crypto/tests/nh_kunit.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2025 Google LLC
+ */
+#include <crypto/nh.h>
+#include <kunit/test.h>
+#include "nh-testvecs.h"
+
+static void test_nh(struct kunit *test)
+{
+	u32 *key = kunit_kmalloc(test, NH_KEY_BYTES, GFP_KERNEL);
+	__le64 hash[NH_NUM_PASSES];
+
+	KUNIT_ASSERT_NOT_NULL(test, key);
+	memcpy(key, nh_test_key, NH_KEY_BYTES);
+	le32_to_cpu_array(key, NH_KEY_WORDS);
+
+	nh(key, nh_test_msg, 16, hash);
+	KUNIT_ASSERT_MEMEQ(test, hash, nh_test_val16, NH_HASH_BYTES);
+
+	nh(key, nh_test_msg, 96, hash);
+	KUNIT_ASSERT_MEMEQ(test, hash, nh_test_val96, NH_HASH_BYTES);
+
+	nh(key, nh_test_msg, 256, hash);
+	KUNIT_ASSERT_MEMEQ(test, hash, nh_test_val256, NH_HASH_BYTES);
+
+	nh(key, nh_test_msg, 1024, hash);
+	KUNIT_ASSERT_MEMEQ(test, hash, nh_test_val1024, NH_HASH_BYTES);
+}
+
+static struct kunit_case nh_test_cases[] = {
+	KUNIT_CASE(test_nh),
+	{},
+};
+
+static struct kunit_suite nh_test_suite = {
+	.name = "nh",
+	.test_cases = nh_test_cases,
+};
+kunit_test_suite(nh_test_suite);
+
+MODULE_DESCRIPTION("KUnit tests for NH");
+MODULE_LICENSE("GPL");
diff --git a/scripts/crypto/gen-hash-testvecs.py b/scripts/crypto/gen-hash-testvecs.py
index c1d0517140bd..1e20ecb46314 100755
--- a/scripts/crypto/gen-hash-testvecs.py
+++ b/scripts/crypto/gen-hash-testvecs.py
@@ -182,10 +182,48 @@ def gen_additional_blake2_testvecs(alg):
             hashes += h.digest()
     print_static_u8_array_definition(
             f'{alg}_keyed_testvec_consolidated[{alg_digest_size_const(alg)}]',
             compute_hash(alg, hashes))
 
+def nh_extract_int(bytestr, pos, length):
+    assert pos % 8 == 0 and length % 8 == 0
+    return int.from_bytes(bytestr[pos//8 : pos//8 + length//8], byteorder='little')
+
+# The NH "almost-universal hash function" used in Adiantum.  This is a
+# straightforward translation of the pseudocode from Section 6.3 of the Adiantum
+# paper (https://eprint.iacr.org/2018/720.pdf), except the outer loop is omitted
+# because we assume len(msg) <= 1024.  (The kernel's nh() function is only
+# expected to handle up to 1024 bytes; it's just called repeatedly as needed.)
+def nh(key, msg):
+    (w, s, r, u) = (32, 2, 4, 8192)
+    l = 8 * len(msg)
+    assert l <= u
+    assert l % (2*s*w) == 0
+    h = bytes()
+    for i in range(0, 2*s*w*r, 2*s*w):
+        p = 0
+        for j in range(0, l, 2*s*w):
+            for k in range(0, w*s, w):
+                a0 = nh_extract_int(key, i + j + k, w)
+                a1 = nh_extract_int(key, i + j + k + s*w, w)
+                b0 = nh_extract_int(msg, j + k, w)
+                b1 = nh_extract_int(msg, j + k + s*w, w)
+                p += ((a0 + b0) % 2**w) * ((a1 + b1) % 2**w)
+        h += (p % 2**64).to_bytes(8, byteorder='little')
+    return h
+
+def gen_nh_testvecs():
+    NH_KEY_BYTES = 1072
+    NH_MESSAGE_BYTES = 1024
+    key = rand_bytes(NH_KEY_BYTES)
+    msg = rand_bytes(NH_MESSAGE_BYTES)
+    print_static_u8_array_definition('nh_test_key[NH_KEY_BYTES]', key)
+    print_static_u8_array_definition('nh_test_msg[NH_MESSAGE_BYTES]', msg)
+    for length in [16, 96, 256, 1024]:
+        print_static_u8_array_definition(f'nh_test_val{length}[NH_HASH_BYTES]',
+                                         nh(key, msg[:length]))
+
 def gen_additional_poly1305_testvecs():
     key = b'\xff' * POLY1305_KEY_SIZE
     data = b''
     ctx = Poly1305(key)
     for _ in range(32):
@@ -215,10 +253,12 @@ alg = sys.argv[1]
 print('/* SPDX-License-Identifier: GPL-2.0-or-later */')
 print(f'/* This file was generated by: {sys.argv[0]} {" ".join(sys.argv[1:])} */')
 if alg.startswith('blake2'):
     gen_unkeyed_testvecs(alg)
     gen_additional_blake2_testvecs(alg)
+elif alg == 'nh':
+    gen_nh_testvecs()
 elif alg == 'poly1305':
     gen_unkeyed_testvecs(alg)
     gen_additional_poly1305_testvecs()
 elif alg == 'polyval':
     gen_unkeyed_testvecs(alg)
-- 
2.52.0



From ebiggers at kernel.org  Wed Dec 10 17:18:37 2025
From: ebiggers at kernel.org (Eric Biggers)
Date: Wed, 10 Dec 2025 17:18:37 -0800
Subject: [PATCH 05/12] lib/crypto: x86/nh: Migrate optimized code into library
In-Reply-To: <20251211011846.8179-1-ebiggers@kernel.org>
References: <20251211011846.8179-1-ebiggers@kernel.org>
Message-ID: <20251211011846.8179-6-ebiggers@kernel.org>

Migrate the x86_64 implementations of NH into lib/crypto/.  This makes
the nh() function be optimized on x86_64 kernels.

Note: this temporarily makes the adiantum template not utilize the
x86_64 optimized NH code.  This is resolved in a later commit that
converts the adiantum template to use nh() instead of "nhpoly1305".

Signed-off-by: Eric Biggers <ebiggers at kernel.org>
---
 arch/x86/crypto/Kconfig                       | 20 -----
 arch/x86/crypto/Makefile                      |  5 --
 arch/x86/crypto/nhpoly1305-avx2-glue.c        | 81 -------------------
 arch/x86/crypto/nhpoly1305-sse2-glue.c        | 80 ------------------
 lib/crypto/Kconfig                            |  1 +
 lib/crypto/Makefile                           |  1 +
 .../crypto/x86/nh-avx2.S                      |  3 +-
 .../crypto/x86/nh-sse2.S                      |  3 +-
 lib/crypto/x86/nh.h                           | 45 +++++++++++
 9 files changed, 49 insertions(+), 190 deletions(-)
 delete mode 100644 arch/x86/crypto/nhpoly1305-avx2-glue.c
 delete mode 100644 arch/x86/crypto/nhpoly1305-sse2-glue.c
 rename arch/x86/crypto/nh-avx2-x86_64.S => lib/crypto/x86/nh-avx2.S (98%)
 rename arch/x86/crypto/nh-sse2-x86_64.S => lib/crypto/x86/nh-sse2.S (97%)
 create mode 100644 lib/crypto/x86/nh.h

diff --git a/arch/x86/crypto/Kconfig b/arch/x86/crypto/Kconfig
index 3fd2423d3cf8..ebb0838eaf30 100644
--- a/arch/x86/crypto/Kconfig
+++ b/arch/x86/crypto/Kconfig
@@ -331,30 +331,10 @@ config CRYPTO_AEGIS128_AESNI_SSE2
 
 	  Architecture: x86_64 using:
 	  - AES-NI (AES New Instructions)
 	  - SSE4.1 (Streaming SIMD Extensions 4.1)
 
-config CRYPTO_NHPOLY1305_SSE2
-	tristate "Hash functions: NHPoly1305 (SSE2)"
-	depends on 64BIT
-	select CRYPTO_NHPOLY1305
-	help
-	  NHPoly1305 hash function for Adiantum
-
-	  Architecture: x86_64 using:
-	  - SSE2 (Streaming SIMD Extensions 2)
-
-config CRYPTO_NHPOLY1305_AVX2
-	tristate "Hash functions: NHPoly1305 (AVX2)"
-	depends on 64BIT
-	select CRYPTO_NHPOLY1305
-	help
-	  NHPoly1305 hash function for Adiantum
-
-	  Architecture: x86_64 using:
-	  - AVX2 (Advanced Vector Extensions 2)
-
 config CRYPTO_SM3_AVX_X86_64
 	tristate "Hash functions: SM3 (AVX)"
 	depends on 64BIT
 	select CRYPTO_HASH
 	select CRYPTO_LIB_SM3
diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile
index 5f2fb4f148fe..b21ad0978c52 100644
--- a/arch/x86/crypto/Makefile
+++ b/arch/x86/crypto/Makefile
@@ -51,15 +51,10 @@ aesni-intel-$(CONFIG_64BIT) += aes-ctr-avx-x86_64.o \
 			       aes-xts-avx-x86_64.o
 
 obj-$(CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL) += ghash-clmulni-intel.o
 ghash-clmulni-intel-y := ghash-clmulni-intel_asm.o ghash-clmulni-intel_glue.o
 
-obj-$(CONFIG_CRYPTO_NHPOLY1305_SSE2) += nhpoly1305-sse2.o
-nhpoly1305-sse2-y := nh-sse2-x86_64.o nhpoly1305-sse2-glue.o
-obj-$(CONFIG_CRYPTO_NHPOLY1305_AVX2) += nhpoly1305-avx2.o
-nhpoly1305-avx2-y := nh-avx2-x86_64.o nhpoly1305-avx2-glue.o
-
 obj-$(CONFIG_CRYPTO_SM3_AVX_X86_64) += sm3-avx-x86_64.o
 sm3-avx-x86_64-y := sm3-avx-asm_64.o sm3_avx_glue.o
 
 obj-$(CONFIG_CRYPTO_SM4_AESNI_AVX_X86_64) += sm4-aesni-avx-x86_64.o
 sm4-aesni-avx-x86_64-y := sm4-aesni-avx-asm_64.o sm4_aesni_avx_glue.o
diff --git a/arch/x86/crypto/nhpoly1305-avx2-glue.c b/arch/x86/crypto/nhpoly1305-avx2-glue.c
deleted file mode 100644
index c3a872f4d6a7..000000000000
--- a/arch/x86/crypto/nhpoly1305-avx2-glue.c
+++ /dev/null
@@ -1,81 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * NHPoly1305 - ?-almost-?-universal hash function for Adiantum
- * (AVX2 accelerated version)
- *
- * Copyright 2018 Google LLC
- */
-
-#include <crypto/internal/hash.h>
-#include <crypto/internal/simd.h>
-#include <crypto/nhpoly1305.h>
-#include <linux/module.h>
-#include <linux/sizes.h>
-#include <asm/simd.h>
-
-asmlinkage void nh_avx2(const u32 *key, const u8 *message, size_t message_len,
-			__le64 hash[NH_NUM_PASSES]);
-
-static int nhpoly1305_avx2_update(struct shash_desc *desc,
-				  const u8 *src, unsigned int srclen)
-{
-	if (srclen < 64 || !crypto_simd_usable())
-		return crypto_nhpoly1305_update(desc, src, srclen);
-
-	do {
-		unsigned int n = min_t(unsigned int, srclen, SZ_4K);
-
-		kernel_fpu_begin();
-		crypto_nhpoly1305_update_helper(desc, src, n, nh_avx2);
-		kernel_fpu_end();
-		src += n;
-		srclen -= n;
-	} while (srclen);
-	return 0;
-}
-
-static int nhpoly1305_avx2_digest(struct shash_desc *desc,
-				  const u8 *src, unsigned int srclen, u8 *out)
-{
-	return crypto_nhpoly1305_init(desc) ?:
-	       nhpoly1305_avx2_update(desc, src, srclen) ?:
-	       crypto_nhpoly1305_final(desc, out);
-}
-
-static struct shash_alg nhpoly1305_alg = {
-	.base.cra_name		= "nhpoly1305",
-	.base.cra_driver_name	= "nhpoly1305-avx2",
-	.base.cra_priority	= 300,
-	.base.cra_ctxsize	= sizeof(struct nhpoly1305_key),
-	.base.cra_module	= THIS_MODULE,
-	.digestsize		= POLY1305_DIGEST_SIZE,
-	.init			= crypto_nhpoly1305_init,
-	.update			= nhpoly1305_avx2_update,
-	.final			= crypto_nhpoly1305_final,
-	.digest			= nhpoly1305_avx2_digest,
-	.setkey			= crypto_nhpoly1305_setkey,
-	.descsize		= sizeof(struct nhpoly1305_state),
-};
-
-static int __init nhpoly1305_mod_init(void)
-{
-	if (!boot_cpu_has(X86_FEATURE_AVX2) ||
-	    !boot_cpu_has(X86_FEATURE_OSXSAVE))
-		return -ENODEV;
-
-	return crypto_register_shash(&nhpoly1305_alg);
-}
-
-static void __exit nhpoly1305_mod_exit(void)
-{
-	crypto_unregister_shash(&nhpoly1305_alg);
-}
-
-module_init(nhpoly1305_mod_init);
-module_exit(nhpoly1305_mod_exit);
-
-MODULE_DESCRIPTION("NHPoly1305 ?-almost-?-universal hash function (AVX2-accelerated)");
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Eric Biggers <ebiggers at google.com>");
-MODULE_ALIAS_CRYPTO("nhpoly1305");
-MODULE_ALIAS_CRYPTO("nhpoly1305-avx2");
diff --git a/arch/x86/crypto/nhpoly1305-sse2-glue.c b/arch/x86/crypto/nhpoly1305-sse2-glue.c
deleted file mode 100644
index a268a8439a5c..000000000000
--- a/arch/x86/crypto/nhpoly1305-sse2-glue.c
+++ /dev/null
@@ -1,80 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * NHPoly1305 - ?-almost-?-universal hash function for Adiantum
- * (SSE2 accelerated version)
- *
- * Copyright 2018 Google LLC
- */
-
-#include <crypto/internal/hash.h>
-#include <crypto/internal/simd.h>
-#include <crypto/nhpoly1305.h>
-#include <linux/module.h>
-#include <linux/sizes.h>
-#include <asm/simd.h>
-
-asmlinkage void nh_sse2(const u32 *key, const u8 *message, size_t message_len,
-			__le64 hash[NH_NUM_PASSES]);
-
-static int nhpoly1305_sse2_update(struct shash_desc *desc,
-				  const u8 *src, unsigned int srclen)
-{
-	if (srclen < 64 || !crypto_simd_usable())
-		return crypto_nhpoly1305_update(desc, src, srclen);
-
-	do {
-		unsigned int n = min_t(unsigned int, srclen, SZ_4K);
-
-		kernel_fpu_begin();
-		crypto_nhpoly1305_update_helper(desc, src, n, nh_sse2);
-		kernel_fpu_end();
-		src += n;
-		srclen -= n;
-	} while (srclen);
-	return 0;
-}
-
-static int nhpoly1305_sse2_digest(struct shash_desc *desc,
-				  const u8 *src, unsigned int srclen, u8 *out)
-{
-	return crypto_nhpoly1305_init(desc) ?:
-	       nhpoly1305_sse2_update(desc, src, srclen) ?:
-	       crypto_nhpoly1305_final(desc, out);
-}
-
-static struct shash_alg nhpoly1305_alg = {
-	.base.cra_name		= "nhpoly1305",
-	.base.cra_driver_name	= "nhpoly1305-sse2",
-	.base.cra_priority	= 200,
-	.base.cra_ctxsize	= sizeof(struct nhpoly1305_key),
-	.base.cra_module	= THIS_MODULE,
-	.digestsize		= POLY1305_DIGEST_SIZE,
-	.init			= crypto_nhpoly1305_init,
-	.update			= nhpoly1305_sse2_update,
-	.final			= crypto_nhpoly1305_final,
-	.digest			= nhpoly1305_sse2_digest,
-	.setkey			= crypto_nhpoly1305_setkey,
-	.descsize		= sizeof(struct nhpoly1305_state),
-};
-
-static int __init nhpoly1305_mod_init(void)
-{
-	if (!boot_cpu_has(X86_FEATURE_XMM2))
-		return -ENODEV;
-
-	return crypto_register_shash(&nhpoly1305_alg);
-}
-
-static void __exit nhpoly1305_mod_exit(void)
-{
-	crypto_unregister_shash(&nhpoly1305_alg);
-}
-
-module_init(nhpoly1305_mod_init);
-module_exit(nhpoly1305_mod_exit);
-
-MODULE_DESCRIPTION("NHPoly1305 ?-almost-?-universal hash function (SSE2-accelerated)");
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Eric Biggers <ebiggers at google.com>");
-MODULE_ALIAS_CRYPTO("nhpoly1305");
-MODULE_ALIAS_CRYPTO("nhpoly1305-sse2");
diff --git a/lib/crypto/Kconfig b/lib/crypto/Kconfig
index aa3f850ece24..33cf46bbadc8 100644
--- a/lib/crypto/Kconfig
+++ b/lib/crypto/Kconfig
@@ -117,10 +117,11 @@ config CRYPTO_LIB_NH
 config CRYPTO_LIB_NH_ARCH
 	bool
 	depends on CRYPTO_LIB_NH && !UML
 	default y if ARM && KERNEL_MODE_NEON
 	default y if ARM64 && KERNEL_MODE_NEON
+	default y if X86_64
 
 config CRYPTO_LIB_POLY1305
 	tristate
 	help
 	  The Poly1305 library functions.  Select this if your module uses any
diff --git a/lib/crypto/Makefile b/lib/crypto/Makefile
index e3a13952bc2a..45128eccedef 100644
--- a/lib/crypto/Makefile
+++ b/lib/crypto/Makefile
@@ -135,10 +135,11 @@ obj-$(CONFIG_CRYPTO_LIB_NH) += libnh.o
 libnh-y := nh.o
 ifeq ($(CONFIG_CRYPTO_LIB_NH_ARCH),y)
 CFLAGS_nh.o += -I$(src)/$(SRCARCH)
 libnh-$(CONFIG_ARM) += arm/nh-neon-core.o
 libnh-$(CONFIG_ARM64) += arm64/nh-neon-core.o
+libnh-$(CONFIG_X86) += x86/nh-sse2.o x86/nh-avx2.o
 endif
 
 ################################################################################
 
 obj-$(CONFIG_CRYPTO_LIB_POLY1305) += libpoly1305.o
diff --git a/arch/x86/crypto/nh-avx2-x86_64.S b/lib/crypto/x86/nh-avx2.S
similarity index 98%
rename from arch/x86/crypto/nh-avx2-x86_64.S
rename to lib/crypto/x86/nh-avx2.S
index 791386d9a83a..9c085a31b137 100644
--- a/arch/x86/crypto/nh-avx2-x86_64.S
+++ b/lib/crypto/x86/nh-avx2.S
@@ -6,11 +6,10 @@
  *
  * Author: Eric Biggers <ebiggers at google.com>
  */
 
 #include <linux/linkage.h>
-#include <linux/cfi_types.h>
 
 #define		PASS0_SUMS	%ymm0
 #define		PASS1_SUMS	%ymm1
 #define		PASS2_SUMS	%ymm2
 #define		PASS3_SUMS	%ymm3
@@ -68,11 +67,11 @@
  * void nh_avx2(const u32 *key, const u8 *message, size_t message_len,
  *		__le64 hash[NH_NUM_PASSES])
  *
  * It's guaranteed that message_len % 16 == 0.
  */
-SYM_TYPED_FUNC_START(nh_avx2)
+SYM_FUNC_START(nh_avx2)
 
 	vmovdqu		0x00(KEY), K0
 	vmovdqu		0x10(KEY), K1
 	add		$0x20, KEY
 	vpxor		PASS0_SUMS, PASS0_SUMS, PASS0_SUMS
diff --git a/arch/x86/crypto/nh-sse2-x86_64.S b/lib/crypto/x86/nh-sse2.S
similarity index 97%
rename from arch/x86/crypto/nh-sse2-x86_64.S
rename to lib/crypto/x86/nh-sse2.S
index 75fb994b6d17..d36c0e6d5556 100644
--- a/arch/x86/crypto/nh-sse2-x86_64.S
+++ b/lib/crypto/x86/nh-sse2.S
@@ -6,11 +6,10 @@
  *
  * Author: Eric Biggers <ebiggers at google.com>
  */
 
 #include <linux/linkage.h>
-#include <linux/cfi_types.h>
 
 #define		PASS0_SUMS	%xmm0
 #define		PASS1_SUMS	%xmm1
 #define		PASS2_SUMS	%xmm2
 #define		PASS3_SUMS	%xmm3
@@ -70,11 +69,11 @@
  * void nh_sse2(const u32 *key, const u8 *message, size_t message_len,
  *		__le64 hash[NH_NUM_PASSES])
  *
  * It's guaranteed that message_len % 16 == 0.
  */
-SYM_TYPED_FUNC_START(nh_sse2)
+SYM_FUNC_START(nh_sse2)
 
 	movdqu		0x00(KEY), K0
 	movdqu		0x10(KEY), K1
 	movdqu		0x20(KEY), K2
 	add		$0x30, KEY
diff --git a/lib/crypto/x86/nh.h b/lib/crypto/x86/nh.h
new file mode 100644
index 000000000000..83361c2e9783
--- /dev/null
+++ b/lib/crypto/x86/nh.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * x86_64 accelerated implementation of NH
+ *
+ * Copyright 2018 Google LLC
+ */
+
+#include <asm/fpu/api.h>
+#include <linux/static_call.h>
+
+static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_sse2);
+static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_avx2);
+
+asmlinkage void nh_sse2(const u32 *key, const u8 *message, size_t message_len,
+			__le64 hash[NH_NUM_PASSES]);
+asmlinkage void nh_avx2(const u32 *key, const u8 *message, size_t message_len,
+			__le64 hash[NH_NUM_PASSES]);
+
+static bool nh_arch(const u32 *key, const u8 *message, size_t message_len,
+		    __le64 hash[NH_NUM_PASSES])
+{
+	if (message_len >= 64 && static_branch_likely(&have_sse2) &&
+	    irq_fpu_usable()) {
+		kernel_fpu_begin();
+		if (static_branch_likely(&have_avx2))
+			nh_avx2(key, message, message_len, hash);
+		else
+			nh_sse2(key, message, message_len, hash);
+		kernel_fpu_end();
+		return true;
+	}
+	return false;
+}
+
+#define nh_mod_init_arch nh_mod_init_arch
+static void nh_mod_init_arch(void)
+{
+	if (boot_cpu_has(X86_FEATURE_XMM2)) {
+		static_branch_enable(&have_sse2);
+		if (boot_cpu_has(X86_FEATURE_AVX2) &&
+		    cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM,
+				      NULL))
+			static_branch_enable(&have_avx2);
+	}
+}
-- 
2.52.0



From ebiggers at kernel.org  Wed Dec 10 17:18:32 2025
From: ebiggers at kernel.org (Eric Biggers)
Date: Wed, 10 Dec 2025 17:18:32 -0800
Subject: [PATCH 00/12] NH library and Adiantum cleanup
Message-ID: <20251211011846.8179-1-ebiggers@kernel.org>

This series can also be retrieved from:

    git fetch https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git nh-lib-v1

This series removes the nhpoly1305 crypto_shash algorithm, which existed
only to fit Adiantum hashing into the traditional Linux crypto API
paradigm.  It replaces it with an nh() library function, combined with
code in the "adiantum" template that handles the Poly1305 step.

The result is simpler code.  As usual, I've also fixed the issue where
the architecture-optimized code was disabled by default.

I've also included some additional cleanups for the Adiantum code.

I'm planning to take this via libcrypto-next.

Eric Biggers (12):
  lib/crypto: nh: Add NH library
  lib/crypto: tests: Add KUnit tests for NH
  lib/crypto: arm/nh: Migrate optimized code into library
  lib/crypto: arm64/nh: Migrate optimized code into library
  lib/crypto: x86/nh: Migrate optimized code into library
  crypto: adiantum - Convert to use NH library
  crypto: adiantum - Use scatter_walk API instead of sg_miter
  crypto: adiantum - Use memcpy_{to,from}_sglist()
  crypto: adiantum - Drop support for asynchronous xchacha ciphers
  crypto: nhpoly1305 - Remove crypto_shash support
  crypto: testmgr - Remove nhpoly1305 tests
  fscrypt: Drop obsolete recommendation to enable optimized NHPoly1305

 Documentation/filesystems/fscrypt.rst         |    5 -
 arch/arm/crypto/Kconfig                       |   10 -
 arch/arm/crypto/Makefile                      |    2 -
 arch/arm/crypto/nhpoly1305-neon-glue.c        |   80 -
 arch/arm64/crypto/Kconfig                     |   10 -
 arch/arm64/crypto/Makefile                    |    3 -
 arch/arm64/crypto/nhpoly1305-neon-glue.c      |   79 -
 arch/x86/crypto/Kconfig                       |   20 -
 arch/x86/crypto/Makefile                      |    5 -
 arch/x86/crypto/nhpoly1305-avx2-glue.c        |   81 -
 arch/x86/crypto/nhpoly1305-sse2-glue.c        |   80 -
 crypto/Kconfig                                |    8 +-
 crypto/Makefile                               |    1 -
 crypto/adiantum.c                             |  442 +++---
 crypto/nhpoly1305.c                           |  255 ---
 crypto/testmgr.c                              |   10 +-
 crypto/testmgr.h                              | 1372 -----------------
 include/crypto/nh.h                           |   52 +
 include/crypto/nhpoly1305.h                   |   74 -
 lib/crypto/Kconfig                            |   13 +
 lib/crypto/Makefile                           |   11 +
 .../crypto => lib/crypto/arm}/nh-neon-core.S  |    0
 lib/crypto/arm/nh.h                           |   33 +
 .../crypto/arm64}/nh-neon-core.S              |    3 +-
 lib/crypto/arm64/nh.h                         |   34 +
 lib/crypto/nh.c                               |   82 +
 lib/crypto/tests/Kconfig                      |    8 +
 lib/crypto/tests/Makefile                     |    1 +
 lib/crypto/tests/nh-testvecs.h                |  298 ++++
 lib/crypto/tests/nh_kunit.c                   |   43 +
 .../crypto/x86/nh-avx2.S                      |    3 +-
 .../crypto/x86/nh-sse2.S                      |    3 +-
 lib/crypto/x86/nh.h                           |   45 +
 scripts/crypto/gen-hash-testvecs.py           |   40 +
 34 files changed, 909 insertions(+), 2297 deletions(-)
 delete mode 100644 arch/arm/crypto/nhpoly1305-neon-glue.c
 delete mode 100644 arch/arm64/crypto/nhpoly1305-neon-glue.c
 delete mode 100644 arch/x86/crypto/nhpoly1305-avx2-glue.c
 delete mode 100644 arch/x86/crypto/nhpoly1305-sse2-glue.c
 delete mode 100644 crypto/nhpoly1305.c
 create mode 100644 include/crypto/nh.h
 delete mode 100644 include/crypto/nhpoly1305.h
 rename {arch/arm/crypto => lib/crypto/arm}/nh-neon-core.S (100%)
 create mode 100644 lib/crypto/arm/nh.h
 rename {arch/arm64/crypto => lib/crypto/arm64}/nh-neon-core.S (97%)
 create mode 100644 lib/crypto/arm64/nh.h
 create mode 100644 lib/crypto/nh.c
 create mode 100644 lib/crypto/tests/nh-testvecs.h
 create mode 100644 lib/crypto/tests/nh_kunit.c
 rename arch/x86/crypto/nh-avx2-x86_64.S => lib/crypto/x86/nh-avx2.S (98%)
 rename arch/x86/crypto/nh-sse2-x86_64.S => lib/crypto/x86/nh-sse2.S (97%)
 create mode 100644 lib/crypto/x86/nh.h


base-commit: 0914d5848096af6496c7aa5e1ac051fcdb3f755b
-- 
2.52.0



From ebiggers at kernel.org  Wed Dec 10 17:18:35 2025
From: ebiggers at kernel.org (Eric Biggers)
Date: Wed, 10 Dec 2025 17:18:35 -0800
Subject: [PATCH 03/12] lib/crypto: arm/nh: Migrate optimized code into library
In-Reply-To: <20251211011846.8179-1-ebiggers@kernel.org>
References: <20251211011846.8179-1-ebiggers@kernel.org>
Message-ID: <20251211011846.8179-4-ebiggers@kernel.org>

Migrate the arm32 NEON implementation of NH into lib/crypto/.  This
makes the nh() function be optimized on arm32 kernels.

Note: this temporarily makes the adiantum template not utilize the arm32
optimized NH code.  This is resolved in a later commit that converts the
adiantum template to use nh() instead of "nhpoly1305".

Signed-off-by: Eric Biggers <ebiggers at kernel.org>
---
 arch/arm/crypto/Kconfig                       | 10 ---
 arch/arm/crypto/Makefile                      |  2 -
 arch/arm/crypto/nhpoly1305-neon-glue.c        | 80 -------------------
 lib/crypto/Kconfig                            |  1 +
 lib/crypto/Makefile                           |  1 +
 .../crypto => lib/crypto/arm}/nh-neon-core.S  |  0
 lib/crypto/arm/nh.h                           | 33 ++++++++
 7 files changed, 35 insertions(+), 92 deletions(-)
 delete mode 100644 arch/arm/crypto/nhpoly1305-neon-glue.c
 rename {arch/arm/crypto => lib/crypto/arm}/nh-neon-core.S (100%)
 create mode 100644 lib/crypto/arm/nh.h

diff --git a/arch/arm/crypto/Kconfig b/arch/arm/crypto/Kconfig
index f30d743df264..3eb5071bea14 100644
--- a/arch/arm/crypto/Kconfig
+++ b/arch/arm/crypto/Kconfig
@@ -21,20 +21,10 @@ config CRYPTO_GHASH_ARM_CE
 	  Use an implementation of GHASH (used by the GCM AEAD chaining mode)
 	  that uses the 64x64 to 128 bit polynomial multiplication (vmull.p64)
 	  that is part of the ARMv8 Crypto Extensions, or a slower variant that
 	  uses the vmull.p8 instruction that is part of the basic NEON ISA.
 
-config CRYPTO_NHPOLY1305_NEON
-	tristate "Hash functions: NHPoly1305 (NEON)"
-	depends on KERNEL_MODE_NEON
-	select CRYPTO_NHPOLY1305
-	help
-	  NHPoly1305 hash function (Adiantum)
-
-	  Architecture: arm using:
-	  - NEON (Advanced SIMD) extensions
-
 config CRYPTO_AES_ARM
 	tristate "Ciphers: AES"
 	select CRYPTO_ALGAPI
 	select CRYPTO_AES
 	help
diff --git a/arch/arm/crypto/Makefile b/arch/arm/crypto/Makefile
index 86dd43313dbf..d6683e9d4992 100644
--- a/arch/arm/crypto/Makefile
+++ b/arch/arm/crypto/Makefile
@@ -3,15 +3,13 @@
 # Arch-specific CryptoAPI modules.
 #
 
 obj-$(CONFIG_CRYPTO_AES_ARM) += aes-arm.o
 obj-$(CONFIG_CRYPTO_AES_ARM_BS) += aes-arm-bs.o
-obj-$(CONFIG_CRYPTO_NHPOLY1305_NEON) += nhpoly1305-neon.o
 
 obj-$(CONFIG_CRYPTO_AES_ARM_CE) += aes-arm-ce.o
 obj-$(CONFIG_CRYPTO_GHASH_ARM_CE) += ghash-arm-ce.o
 
 aes-arm-y	:= aes-cipher-core.o aes-cipher-glue.o
 aes-arm-bs-y	:= aes-neonbs-core.o aes-neonbs-glue.o
 aes-arm-ce-y	:= aes-ce-core.o aes-ce-glue.o
 ghash-arm-ce-y	:= ghash-ce-core.o ghash-ce-glue.o
-nhpoly1305-neon-y := nh-neon-core.o nhpoly1305-neon-glue.o
diff --git a/arch/arm/crypto/nhpoly1305-neon-glue.c b/arch/arm/crypto/nhpoly1305-neon-glue.c
deleted file mode 100644
index 62cf7ccdde73..000000000000
--- a/arch/arm/crypto/nhpoly1305-neon-glue.c
+++ /dev/null
@@ -1,80 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * NHPoly1305 - ?-almost-?-universal hash function for Adiantum
- * (NEON accelerated version)
- *
- * Copyright 2018 Google LLC
- */
-
-#include <asm/neon.h>
-#include <asm/simd.h>
-#include <crypto/internal/hash.h>
-#include <crypto/internal/simd.h>
-#include <crypto/nhpoly1305.h>
-#include <linux/module.h>
-
-asmlinkage void nh_neon(const u32 *key, const u8 *message, size_t message_len,
-			__le64 hash[NH_NUM_PASSES]);
-
-static int nhpoly1305_neon_update(struct shash_desc *desc,
-				  const u8 *src, unsigned int srclen)
-{
-	if (srclen < 64 || !crypto_simd_usable())
-		return crypto_nhpoly1305_update(desc, src, srclen);
-
-	do {
-		unsigned int n = min_t(unsigned int, srclen, SZ_4K);
-
-		kernel_neon_begin();
-		crypto_nhpoly1305_update_helper(desc, src, n, nh_neon);
-		kernel_neon_end();
-		src += n;
-		srclen -= n;
-	} while (srclen);
-	return 0;
-}
-
-static int nhpoly1305_neon_digest(struct shash_desc *desc,
-				  const u8 *src, unsigned int srclen, u8 *out)
-{
-	return crypto_nhpoly1305_init(desc) ?:
-	       nhpoly1305_neon_update(desc, src, srclen) ?:
-	       crypto_nhpoly1305_final(desc, out);
-}
-
-static struct shash_alg nhpoly1305_alg = {
-	.base.cra_name		= "nhpoly1305",
-	.base.cra_driver_name	= "nhpoly1305-neon",
-	.base.cra_priority	= 200,
-	.base.cra_ctxsize	= sizeof(struct nhpoly1305_key),
-	.base.cra_module	= THIS_MODULE,
-	.digestsize		= POLY1305_DIGEST_SIZE,
-	.init			= crypto_nhpoly1305_init,
-	.update			= nhpoly1305_neon_update,
-	.final			= crypto_nhpoly1305_final,
-	.digest			= nhpoly1305_neon_digest,
-	.setkey			= crypto_nhpoly1305_setkey,
-	.descsize		= sizeof(struct nhpoly1305_state),
-};
-
-static int __init nhpoly1305_mod_init(void)
-{
-	if (!(elf_hwcap & HWCAP_NEON))
-		return -ENODEV;
-
-	return crypto_register_shash(&nhpoly1305_alg);
-}
-
-static void __exit nhpoly1305_mod_exit(void)
-{
-	crypto_unregister_shash(&nhpoly1305_alg);
-}
-
-module_init(nhpoly1305_mod_init);
-module_exit(nhpoly1305_mod_exit);
-
-MODULE_DESCRIPTION("NHPoly1305 ?-almost-?-universal hash function (NEON-accelerated)");
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Eric Biggers <ebiggers at google.com>");
-MODULE_ALIAS_CRYPTO("nhpoly1305");
-MODULE_ALIAS_CRYPTO("nhpoly1305-neon");
diff --git a/lib/crypto/Kconfig b/lib/crypto/Kconfig
index f14c9f5974d8..c6ee7ca77632 100644
--- a/lib/crypto/Kconfig
+++ b/lib/crypto/Kconfig
@@ -115,10 +115,11 @@ config CRYPTO_LIB_NH
 	  the variant of NH used in Adiantum.
 
 config CRYPTO_LIB_NH_ARCH
 	bool
 	depends on CRYPTO_LIB_NH && !UML
+	default y if ARM && KERNEL_MODE_NEON
 
 config CRYPTO_LIB_POLY1305
 	tristate
 	help
 	  The Poly1305 library functions.  Select this if your module uses any
diff --git a/lib/crypto/Makefile b/lib/crypto/Makefile
index 929b84568809..6dae7e182847 100644
--- a/lib/crypto/Makefile
+++ b/lib/crypto/Makefile
@@ -133,10 +133,11 @@ libmldsa-y := mldsa.o
 
 obj-$(CONFIG_CRYPTO_LIB_NH) += libnh.o
 libnh-y := nh.o
 ifeq ($(CONFIG_CRYPTO_LIB_NH_ARCH),y)
 CFLAGS_nh.o += -I$(src)/$(SRCARCH)
+libnh-$(CONFIG_ARM) += arm/nh-neon-core.o
 endif
 
 ################################################################################
 
 obj-$(CONFIG_CRYPTO_LIB_POLY1305) += libpoly1305.o
diff --git a/arch/arm/crypto/nh-neon-core.S b/lib/crypto/arm/nh-neon-core.S
similarity index 100%
rename from arch/arm/crypto/nh-neon-core.S
rename to lib/crypto/arm/nh-neon-core.S
diff --git a/lib/crypto/arm/nh.h b/lib/crypto/arm/nh.h
new file mode 100644
index 000000000000..c9f39d819336
--- /dev/null
+++ b/lib/crypto/arm/nh.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * ARM32 accelerated implementation of NH
+ *
+ * Copyright 2018 Google LLC
+ */
+
+#include <asm/neon.h>
+#include <asm/simd.h>
+
+static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon);
+
+asmlinkage void nh_neon(const u32 *key, const u8 *message, size_t message_len,
+			__le64 hash[NH_NUM_PASSES]);
+
+static bool nh_arch(const u32 *key, const u8 *message, size_t message_len,
+		    __le64 hash[NH_NUM_PASSES])
+{
+	if (static_branch_likely(&have_neon) && message_len >= 64 &&
+	    may_use_simd()) {
+		scoped_ksimd()
+			nh_neon(key, message, message_len, hash);
+		return true;
+	}
+	return false;
+}
+
+#define nh_mod_init_arch nh_mod_init_arch
+static void nh_mod_init_arch(void)
+{
+	if (elf_hwcap & HWCAP_NEON)
+		static_branch_enable(&have_neon);
+}
-- 
2.52.0



From ebiggers at kernel.org  Wed Dec 10 17:18:39 2025
From: ebiggers at kernel.org (Eric Biggers)
Date: Wed, 10 Dec 2025 17:18:39 -0800
Subject: [PATCH 07/12] crypto: adiantum - Use scatter_walk API instead of sg_miter
In-Reply-To: <20251211011846.8179-1-ebiggers@kernel.org>
References: <20251211011846.8179-1-ebiggers@kernel.org>
Message-ID: <20251211011846.8179-8-ebiggers@kernel.org>

Make adiantum_hash_message() use the scatter_walk API instead of
sg_miter.  scatter_walk is a bit simpler and also more efficient.  For
example, unlike sg_miter, scatter_walk doesn't require that the number
of scatterlist entries be calculated up-front.

Signed-off-by: Eric Biggers <ebiggers at kernel.org>
---
 crypto/adiantum.c | 33 +++++++++++++++------------------
 1 file changed, 15 insertions(+), 18 deletions(-)

diff --git a/crypto/adiantum.c b/crypto/adiantum.c
index bbe519fbd739..519e95228ad8 100644
--- a/crypto/adiantum.c
+++ b/crypto/adiantum.c
@@ -367,30 +367,27 @@ static void nhpoly1305_final(struct nhpoly1305_ctx *ctx,
  * evaluated as a polynomial in GF(2^{130}-5), like in the Poly1305 MAC.  Note
  * that the polynomial evaluation by itself would suffice to achieve the ?-?U
  * property; NH is used for performance since it's much faster than Poly1305.
  */
 static void adiantum_hash_message(struct skcipher_request *req,
-				  struct scatterlist *sgl, unsigned int nents,
-				  le128 *out)
+				  struct scatterlist *sgl, le128 *out)
 {
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 	const struct adiantum_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
 	struct adiantum_request_ctx *rctx = skcipher_request_ctx(req);
-	const unsigned int bulk_len = req->cryptlen - BLOCKCIPHER_BLOCK_SIZE;
-	struct sg_mapping_iter miter;
-	unsigned int i, n;
+	unsigned int len = req->cryptlen - BLOCKCIPHER_BLOCK_SIZE;
+	struct scatter_walk walk;
 
 	nhpoly1305_init(&rctx->u.hash_ctx);
+	scatterwalk_start(&walk, sgl);
+	while (len) {
+		unsigned int n = scatterwalk_next(&walk, len);
 
-	sg_miter_start(&miter, sgl, nents, SG_MITER_FROM_SG | SG_MITER_ATOMIC);
-	for (i = 0; i < bulk_len; i += n) {
-		sg_miter_next(&miter);
-		n = min_t(unsigned int, miter.length, bulk_len - i);
-		nhpoly1305_update(&rctx->u.hash_ctx, tctx, miter.addr, n);
+		nhpoly1305_update(&rctx->u.hash_ctx, tctx, walk.addr, n);
+		scatterwalk_done_src(&walk, n);
+		len -= n;
 	}
-	sg_miter_stop(&miter);
-
 	nhpoly1305_final(&rctx->u.hash_ctx, tctx, out);
 }
 
 /* Continue Adiantum encryption/decryption after the stream cipher step */
 static int adiantum_finish(struct skcipher_request *req)
@@ -398,11 +395,10 @@ static int adiantum_finish(struct skcipher_request *req)
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 	const struct adiantum_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
 	struct adiantum_request_ctx *rctx = skcipher_request_ctx(req);
 	const unsigned int bulk_len = req->cryptlen - BLOCKCIPHER_BLOCK_SIZE;
 	struct scatterlist *dst = req->dst;
-	const unsigned int dst_nents = sg_nents(dst);
 	le128 digest;
 
 	/* If decrypting, decrypt C_M with the block cipher to get P_M */
 	if (!rctx->enc)
 		crypto_cipher_decrypt_one(tctx->blockcipher, rctx->rbuf.bytes,
@@ -412,11 +408,12 @@ static int adiantum_finish(struct skcipher_request *req)
 	 * Second hash step
 	 *	enc: C_R = C_M - H_{K_H}(T, C_L)
 	 *	dec: P_R = P_M - H_{K_H}(T, P_L)
 	 */
 	le128_sub(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &rctx->header_hash);
-	if (dst_nents == 1 && dst->offset + req->cryptlen <= PAGE_SIZE) {
+	if (dst->length >= req->cryptlen &&
+	    dst->offset + req->cryptlen <= PAGE_SIZE) {
 		/* Fast path for single-page destination */
 		struct page *page = sg_page(dst);
 		void *virt = kmap_local_page(page) + dst->offset;
 
 		nhpoly1305_init(&rctx->u.hash_ctx);
@@ -426,11 +423,11 @@ static int adiantum_finish(struct skcipher_request *req)
 		memcpy(virt + bulk_len, &rctx->rbuf.bignum, sizeof(le128));
 		flush_dcache_page(page);
 		kunmap_local(virt);
 	} else {
 		/* Slow path that works for any destination scatterlist */
-		adiantum_hash_message(req, dst, dst_nents, &digest);
+		adiantum_hash_message(req, dst, &digest);
 		le128_sub(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &digest);
 		scatterwalk_map_and_copy(&rctx->rbuf.bignum, dst,
 					 bulk_len, sizeof(le128), 1);
 	}
 	return 0;
@@ -451,11 +448,10 @@ static int adiantum_crypt(struct skcipher_request *req, bool enc)
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 	const struct adiantum_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
 	struct adiantum_request_ctx *rctx = skcipher_request_ctx(req);
 	const unsigned int bulk_len = req->cryptlen - BLOCKCIPHER_BLOCK_SIZE;
 	struct scatterlist *src = req->src;
-	const unsigned int src_nents = sg_nents(src);
 	unsigned int stream_len;
 	le128 digest;
 
 	if (req->cryptlen < BLOCKCIPHER_BLOCK_SIZE)
 		return -EINVAL;
@@ -466,22 +462,23 @@ static int adiantum_crypt(struct skcipher_request *req, bool enc)
 	 * First hash step
 	 *	enc: P_M = P_R + H_{K_H}(T, P_L)
 	 *	dec: C_M = C_R + H_{K_H}(T, C_L)
 	 */
 	adiantum_hash_header(req);
-	if (src_nents == 1 && src->offset + req->cryptlen <= PAGE_SIZE) {
+	if (src->length >= req->cryptlen &&
+	    src->offset + req->cryptlen <= PAGE_SIZE) {
 		/* Fast path for single-page source */
 		void *virt = kmap_local_page(sg_page(src)) + src->offset;
 
 		nhpoly1305_init(&rctx->u.hash_ctx);
 		nhpoly1305_update(&rctx->u.hash_ctx, tctx, virt, bulk_len);
 		nhpoly1305_final(&rctx->u.hash_ctx, tctx, &digest);
 		memcpy(&rctx->rbuf.bignum, virt + bulk_len, sizeof(le128));
 		kunmap_local(virt);
 	} else {
 		/* Slow path that works for any source scatterlist */
-		adiantum_hash_message(req, src, src_nents, &digest);
+		adiantum_hash_message(req, src, &digest);
 		scatterwalk_map_and_copy(&rctx->rbuf.bignum, src,
 					 bulk_len, sizeof(le128), 0);
 	}
 	le128_add(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &rctx->header_hash);
 	le128_add(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &digest);
-- 
2.52.0



From ebiggers at kernel.org  Wed Dec 10 17:18:36 2025
From: ebiggers at kernel.org (Eric Biggers)
Date: Wed, 10 Dec 2025 17:18:36 -0800
Subject: [PATCH 04/12] lib/crypto: arm64/nh: Migrate optimized code into library
In-Reply-To: <20251211011846.8179-1-ebiggers@kernel.org>
References: <20251211011846.8179-1-ebiggers@kernel.org>
Message-ID: <20251211011846.8179-5-ebiggers@kernel.org>

Migrate the arm64 NEON implementation of NH into lib/crypto/.  This
makes the nh() function be optimized on arm64 kernels.

Note: this temporarily makes the adiantum template not utilize the arm64
optimized NH code.  This is resolved in a later commit that converts the
adiantum template to use nh() instead of "nhpoly1305".

Signed-off-by: Eric Biggers <ebiggers at kernel.org>
---
 arch/arm64/crypto/Kconfig                     | 10 ---
 arch/arm64/crypto/Makefile                    |  3 -
 arch/arm64/crypto/nhpoly1305-neon-glue.c      | 79 -------------------
 lib/crypto/Kconfig                            |  1 +
 lib/crypto/Makefile                           |  1 +
 .../crypto/arm64}/nh-neon-core.S              |  3 +-
 lib/crypto/arm64/nh.h                         | 34 ++++++++
 7 files changed, 37 insertions(+), 94 deletions(-)
 delete mode 100644 arch/arm64/crypto/nhpoly1305-neon-glue.c
 rename {arch/arm64/crypto => lib/crypto/arm64}/nh-neon-core.S (97%)
 create mode 100644 lib/crypto/arm64/nh.h

diff --git a/arch/arm64/crypto/Kconfig b/arch/arm64/crypto/Kconfig
index bdd276a6e540..da1c9ea8ea83 100644
--- a/arch/arm64/crypto/Kconfig
+++ b/arch/arm64/crypto/Kconfig
@@ -13,20 +13,10 @@ config CRYPTO_GHASH_ARM64_CE
 	  GCM GHASH function (NIST SP800-38D)
 
 	  Architecture: arm64 using:
 	  - ARMv8 Crypto Extensions
 
-config CRYPTO_NHPOLY1305_NEON
-	tristate "Hash functions: NHPoly1305 (NEON)"
-	depends on KERNEL_MODE_NEON
-	select CRYPTO_NHPOLY1305
-	help
-	  NHPoly1305 hash function (Adiantum)
-
-	  Architecture: arm64 using:
-	  - NEON (Advanced SIMD) extensions
-
 config CRYPTO_SM3_NEON
 	tristate "Hash functions: SM3 (NEON)"
 	depends on KERNEL_MODE_NEON
 	select CRYPTO_HASH
 	select CRYPTO_LIB_SM3
diff --git a/arch/arm64/crypto/Makefile b/arch/arm64/crypto/Makefile
index 1e330aa08d3f..3ab4b58e5c4c 100644
--- a/arch/arm64/crypto/Makefile
+++ b/arch/arm64/crypto/Makefile
@@ -39,13 +39,10 @@ obj-$(CONFIG_CRYPTO_AES_ARM64_CE_BLK) += aes-ce-blk.o
 aes-ce-blk-y := aes-glue-ce.o aes-ce.o
 
 obj-$(CONFIG_CRYPTO_AES_ARM64_NEON_BLK) += aes-neon-blk.o
 aes-neon-blk-y := aes-glue-neon.o aes-neon.o
 
-obj-$(CONFIG_CRYPTO_NHPOLY1305_NEON) += nhpoly1305-neon.o
-nhpoly1305-neon-y := nh-neon-core.o nhpoly1305-neon-glue.o
-
 obj-$(CONFIG_CRYPTO_AES_ARM64) += aes-arm64.o
 aes-arm64-y := aes-cipher-core.o aes-cipher-glue.o
 
 obj-$(CONFIG_CRYPTO_AES_ARM64_BS) += aes-neon-bs.o
 aes-neon-bs-y := aes-neonbs-core.o aes-neonbs-glue.o
diff --git a/arch/arm64/crypto/nhpoly1305-neon-glue.c b/arch/arm64/crypto/nhpoly1305-neon-glue.c
deleted file mode 100644
index 013de6ac569a..000000000000
--- a/arch/arm64/crypto/nhpoly1305-neon-glue.c
+++ /dev/null
@@ -1,79 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * NHPoly1305 - ?-almost-?-universal hash function for Adiantum
- * (ARM64 NEON accelerated version)
- *
- * Copyright 2018 Google LLC
- */
-
-#include <asm/neon.h>
-#include <asm/simd.h>
-#include <crypto/internal/hash.h>
-#include <crypto/internal/simd.h>
-#include <crypto/nhpoly1305.h>
-#include <linux/module.h>
-
-asmlinkage void nh_neon(const u32 *key, const u8 *message, size_t message_len,
-			__le64 hash[NH_NUM_PASSES]);
-
-static int nhpoly1305_neon_update(struct shash_desc *desc,
-				  const u8 *src, unsigned int srclen)
-{
-	if (srclen < 64 || !crypto_simd_usable())
-		return crypto_nhpoly1305_update(desc, src, srclen);
-
-	do {
-		unsigned int n = min_t(unsigned int, srclen, SZ_4K);
-
-		scoped_ksimd()
-			crypto_nhpoly1305_update_helper(desc, src, n, nh_neon);
-		src += n;
-		srclen -= n;
-	} while (srclen);
-	return 0;
-}
-
-static int nhpoly1305_neon_digest(struct shash_desc *desc,
-				  const u8 *src, unsigned int srclen, u8 *out)
-{
-	return crypto_nhpoly1305_init(desc) ?:
-	       nhpoly1305_neon_update(desc, src, srclen) ?:
-	       crypto_nhpoly1305_final(desc, out);
-}
-
-static struct shash_alg nhpoly1305_alg = {
-	.base.cra_name		= "nhpoly1305",
-	.base.cra_driver_name	= "nhpoly1305-neon",
-	.base.cra_priority	= 200,
-	.base.cra_ctxsize	= sizeof(struct nhpoly1305_key),
-	.base.cra_module	= THIS_MODULE,
-	.digestsize		= POLY1305_DIGEST_SIZE,
-	.init			= crypto_nhpoly1305_init,
-	.update			= nhpoly1305_neon_update,
-	.final			= crypto_nhpoly1305_final,
-	.digest			= nhpoly1305_neon_digest,
-	.setkey			= crypto_nhpoly1305_setkey,
-	.descsize		= sizeof(struct nhpoly1305_state),
-};
-
-static int __init nhpoly1305_mod_init(void)
-{
-	if (!cpu_have_named_feature(ASIMD))
-		return -ENODEV;
-
-	return crypto_register_shash(&nhpoly1305_alg);
-}
-
-static void __exit nhpoly1305_mod_exit(void)
-{
-	crypto_unregister_shash(&nhpoly1305_alg);
-}
-
-module_init(nhpoly1305_mod_init);
-module_exit(nhpoly1305_mod_exit);
-
-MODULE_DESCRIPTION("NHPoly1305 ?-almost-?-universal hash function (NEON-accelerated)");
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Eric Biggers <ebiggers at google.com>");
-MODULE_ALIAS_CRYPTO("nhpoly1305");
-MODULE_ALIAS_CRYPTO("nhpoly1305-neon");
diff --git a/lib/crypto/Kconfig b/lib/crypto/Kconfig
index c6ee7ca77632..aa3f850ece24 100644
--- a/lib/crypto/Kconfig
+++ b/lib/crypto/Kconfig
@@ -116,10 +116,11 @@ config CRYPTO_LIB_NH
 
 config CRYPTO_LIB_NH_ARCH
 	bool
 	depends on CRYPTO_LIB_NH && !UML
 	default y if ARM && KERNEL_MODE_NEON
+	default y if ARM64 && KERNEL_MODE_NEON
 
 config CRYPTO_LIB_POLY1305
 	tristate
 	help
 	  The Poly1305 library functions.  Select this if your module uses any
diff --git a/lib/crypto/Makefile b/lib/crypto/Makefile
index 6dae7e182847..e3a13952bc2a 100644
--- a/lib/crypto/Makefile
+++ b/lib/crypto/Makefile
@@ -134,10 +134,11 @@ libmldsa-y := mldsa.o
 obj-$(CONFIG_CRYPTO_LIB_NH) += libnh.o
 libnh-y := nh.o
 ifeq ($(CONFIG_CRYPTO_LIB_NH_ARCH),y)
 CFLAGS_nh.o += -I$(src)/$(SRCARCH)
 libnh-$(CONFIG_ARM) += arm/nh-neon-core.o
+libnh-$(CONFIG_ARM64) += arm64/nh-neon-core.o
 endif
 
 ################################################################################
 
 obj-$(CONFIG_CRYPTO_LIB_POLY1305) += libpoly1305.o
diff --git a/arch/arm64/crypto/nh-neon-core.S b/lib/crypto/arm64/nh-neon-core.S
similarity index 97%
rename from arch/arm64/crypto/nh-neon-core.S
rename to lib/crypto/arm64/nh-neon-core.S
index 13eda08fda1e..6fa57fce8085 100644
--- a/arch/arm64/crypto/nh-neon-core.S
+++ b/lib/crypto/arm64/nh-neon-core.S
@@ -6,11 +6,10 @@
  *
  * Author: Eric Biggers <ebiggers at google.com>
  */
 
 #include <linux/linkage.h>
-#include <linux/cfi_types.h>
 
 	KEY		.req	x0
 	MESSAGE		.req	x1
 	MESSAGE_LEN	.req	x2
 	HASH		.req	x3
@@ -61,11 +60,11 @@
  * void nh_neon(const u32 *key, const u8 *message, size_t message_len,
  *		__le64 hash[NH_NUM_PASSES])
  *
  * It's guaranteed that message_len % 16 == 0.
  */
-SYM_TYPED_FUNC_START(nh_neon)
+SYM_FUNC_START(nh_neon)
 
 	ld1		{K0.4s,K1.4s}, [KEY], #32
 	  movi		PASS0_SUMS.2d, #0
 	  movi		PASS1_SUMS.2d, #0
 	ld1		{K2.4s}, [KEY], #16
diff --git a/lib/crypto/arm64/nh.h b/lib/crypto/arm64/nh.h
new file mode 100644
index 000000000000..08902630bdd1
--- /dev/null
+++ b/lib/crypto/arm64/nh.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * ARM64 accelerated implementation of NH
+ *
+ * Copyright 2018 Google LLC
+ */
+
+#include <asm/hwcap.h>
+#include <asm/simd.h>
+#include <linux/cpufeature.h>
+
+static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon);
+
+asmlinkage void nh_neon(const u32 *key, const u8 *message, size_t message_len,
+			__le64 hash[NH_NUM_PASSES]);
+
+static bool nh_arch(const u32 *key, const u8 *message, size_t message_len,
+		    __le64 hash[NH_NUM_PASSES])
+{
+	if (static_branch_likely(&have_neon) && message_len >= 64 &&
+	    may_use_simd()) {
+		scoped_ksimd()
+			nh_neon(key, message, message_len, hash);
+		return true;
+	}
+	return false;
+}
+
+#define nh_mod_init_arch nh_mod_init_arch
+static void nh_mod_init_arch(void)
+{
+	if (cpu_have_named_feature(ASIMD))
+		static_branch_enable(&have_neon);
+}
-- 
2.52.0



From ebiggers at kernel.org  Wed Dec 10 17:18:38 2025
From: ebiggers at kernel.org (Eric Biggers)
Date: Wed, 10 Dec 2025 17:18:38 -0800
Subject: [PATCH 06/12] crypto: adiantum - Convert to use NH library
In-Reply-To: <20251211011846.8179-1-ebiggers@kernel.org>
References: <20251211011846.8179-1-ebiggers@kernel.org>
Message-ID: <20251211011846.8179-7-ebiggers@kernel.org>

Reimplement the Adiantum message hashing using the nh() library
function, combined with some code which directly handles the Poly1305
stage.  The latter code is derived from crypto/nhpoly1305.c.

This eliminates the dependency on the "nhpoly1305" crypto_shash
algorithm, which existed only to fit Adiantum message hashing into the
traditional Linux crypto API paradigm.  Now that simple,
architecture-optimized library functions are a well-established option
too, we can switch to this simpler implementation.

Note: I've dropped the support for the optional third parameter of the
adiantum template, which specified the nhpoly1305 implementation.  We
could keep accepting some strings in this parameter for backwards
compatibility, but I don't think it's being used.  I believe only
"adiantum(xchacha12,aes)" and "adiantum(xchacha20,aes)" are used.

Signed-off-by: Eric Biggers <ebiggers at kernel.org>
---
 crypto/Kconfig    |   2 +-
 crypto/adiantum.c | 295 +++++++++++++++++++++++++++++-----------------
 crypto/testmgr.c  |   4 +-
 3 files changed, 191 insertions(+), 110 deletions(-)

diff --git a/crypto/Kconfig b/crypto/Kconfig
index 2e5b195b1b06..89d1ccaa1fa0 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -599,13 +599,13 @@ endmenu
 menu "Length-preserving ciphers and modes"
 
 config CRYPTO_ADIANTUM
 	tristate "Adiantum"
 	select CRYPTO_CHACHA20
+	select CRYPTO_LIB_NH
 	select CRYPTO_LIB_POLY1305
 	select CRYPTO_LIB_POLY1305_GENERIC
-	select CRYPTO_NHPOLY1305
 	select CRYPTO_MANAGER
 	help
 	  Adiantum tweakable, length-preserving encryption mode
 
 	  Designed for fast and secure disk encryption, especially on
diff --git a/crypto/adiantum.c b/crypto/adiantum.c
index a6bca877c3c7..bbe519fbd739 100644
--- a/crypto/adiantum.c
+++ b/crypto/adiantum.c
@@ -18,27 +18,18 @@
  *
  * For flexibility, this implementation also allows other ciphers:
  *
  *	- Stream cipher: XChaCha12 or XChaCha20
  *	- Block cipher: any with a 128-bit block size and 256-bit key
- *
- * This implementation doesn't currently allow other ?-?U hash functions, i.e.
- * HPolyC is not supported.  This is because Adiantum is ~20% faster than HPolyC
- * but still provably as secure, and also the ?-?U hash function of HBSH is
- * formally defined to take two inputs (tweak, message) which makes it difficult
- * to wrap with the crypto_shash API.  Rather, some details need to be handled
- * here.  Nevertheless, if needed in the future, support for other ?-?U hash
- * functions could be added here.
  */
 
 #include <crypto/b128ops.h>
 #include <crypto/chacha.h>
 #include <crypto/internal/cipher.h>
-#include <crypto/internal/hash.h>
 #include <crypto/internal/poly1305.h>
 #include <crypto/internal/skcipher.h>
-#include <crypto/nhpoly1305.h>
+#include <crypto/nh.h>
 #include <crypto/scatterwalk.h>
 #include <linux/module.h>
 
 /*
  * Size of right-hand part of input data, in bytes; also the size of the block
@@ -48,11 +39,11 @@
 
 /* Size of the block cipher key (K_E) in bytes */
 #define BLOCKCIPHER_KEY_SIZE		32
 
 /* Size of the hash key (K_H) in bytes */
-#define HASH_KEY_SIZE		(POLY1305_BLOCK_SIZE + NHPOLY1305_KEY_SIZE)
+#define HASH_KEY_SIZE		(2 * POLY1305_BLOCK_SIZE + NH_KEY_BYTES)
 
 /*
  * The specification allows variable-length tweaks, but Linux's crypto API
  * currently only allows algorithms to support a single length.  The "natural"
  * tweak length for Adiantum is 16, since that fits into one Poly1305 block for
@@ -62,18 +53,35 @@
 #define TWEAK_SIZE		32
 
 struct adiantum_instance_ctx {
 	struct crypto_skcipher_spawn streamcipher_spawn;
 	struct crypto_cipher_spawn blockcipher_spawn;
-	struct crypto_shash_spawn hash_spawn;
 };
 
 struct adiantum_tfm_ctx {
 	struct crypto_skcipher *streamcipher;
 	struct crypto_cipher *blockcipher;
-	struct crypto_shash *hash;
 	struct poly1305_core_key header_hash_key;
+	struct poly1305_core_key msg_poly_key;
+	u32 nh_key[NH_KEY_WORDS];
+};
+
+struct nhpoly1305_ctx {
+	/* Running total of polynomial evaluation */
+	struct poly1305_state poly_state;
+
+	/* Partial block buffer */
+	u8 buffer[NH_MESSAGE_UNIT];
+	unsigned int buflen;
+
+	/*
+	 * Number of bytes remaining until the current NH message reaches
+	 * NH_MESSAGE_BYTES.  When nonzero, 'nh_hash' holds the partial NH hash.
+	 */
+	unsigned int nh_remaining;
+
+	__le64 nh_hash[NH_NUM_PASSES];
 };
 
 struct adiantum_request_ctx {
 
 	/*
@@ -96,13 +104,16 @@ struct adiantum_request_ctx {
 	 * The result of the Poly1305 ?-?U hash function applied to
 	 * (bulk length, tweak)
 	 */
 	le128 header_hash;
 
-	/* Sub-requests, must be last */
+	/*
+	 * skcipher sub-request size is unknown at compile-time, so it needs to
+	 * go after the members with known sizes.
+	 */
 	union {
-		struct shash_desc hash_desc;
+		struct nhpoly1305_ctx hash_ctx;
 		struct skcipher_request streamcipher_req;
 	} u;
 };
 
 /*
@@ -168,16 +179,15 @@ static int adiantum_setkey(struct crypto_skcipher *tfm, const u8 *key,
 	keyp += BLOCKCIPHER_KEY_SIZE;
 
 	/* Set the hash key (K_H) */
 	poly1305_core_setkey(&tctx->header_hash_key, keyp);
 	keyp += POLY1305_BLOCK_SIZE;
-
-	crypto_shash_clear_flags(tctx->hash, CRYPTO_TFM_REQ_MASK);
-	crypto_shash_set_flags(tctx->hash, crypto_skcipher_get_flags(tfm) &
-					   CRYPTO_TFM_REQ_MASK);
-	err = crypto_shash_setkey(tctx->hash, keyp, NHPOLY1305_KEY_SIZE);
-	keyp += NHPOLY1305_KEY_SIZE;
+	poly1305_core_setkey(&tctx->msg_poly_key, keyp);
+	keyp += POLY1305_BLOCK_SIZE;
+	for (int i = 0; i < NH_KEY_WORDS; i++)
+		tctx->nh_key[i] = get_unaligned_le32(&keyp[i * 4]);
+	keyp += NH_KEY_BYTES;
 	WARN_ON(keyp != &data->derived_keys[ARRAY_SIZE(data->derived_keys)]);
 out:
 	kfree_sensitive(data);
 	return err;
 }
@@ -241,39 +251,147 @@ static void adiantum_hash_header(struct skcipher_request *req)
 			     TWEAK_SIZE / POLY1305_BLOCK_SIZE, 1);
 
 	poly1305_core_emit(&state, NULL, &rctx->header_hash);
 }
 
-/* Hash the left-hand part (the "bulk") of the message using NHPoly1305 */
-static int adiantum_hash_message(struct skcipher_request *req,
-				 struct scatterlist *sgl, unsigned int nents,
-				 le128 *digest)
+/* Pass the next NH hash value through Poly1305 */
+static void process_nh_hash_value(struct nhpoly1305_ctx *ctx,
+				  const struct adiantum_tfm_ctx *key)
+{
+	static_assert(NH_HASH_BYTES % POLY1305_BLOCK_SIZE == 0);
+
+	poly1305_core_blocks(&ctx->poly_state, &key->msg_poly_key, ctx->nh_hash,
+			     NH_HASH_BYTES / POLY1305_BLOCK_SIZE, 1);
+}
+
+/*
+ * Feed the next portion of the message data, as a whole number of 16-byte
+ * "NH message units", through NH and Poly1305.  Each NH hash is taken over
+ * 1024 bytes, except possibly the final one which is taken over a multiple of
+ * 16 bytes up to 1024.  Also, in the case where data is passed in misaligned
+ * chunks, we combine partial hashes; the end result is the same either way.
+ */
+static void nhpoly1305_units(struct nhpoly1305_ctx *ctx,
+			     const struct adiantum_tfm_ctx *key,
+			     const u8 *data, size_t len)
+{
+	do {
+		unsigned int bytes;
+
+		if (ctx->nh_remaining == 0) {
+			/* Starting a new NH message */
+			bytes = min(len, NH_MESSAGE_BYTES);
+			nh(key->nh_key, data, bytes, ctx->nh_hash);
+			ctx->nh_remaining = NH_MESSAGE_BYTES - bytes;
+		} else {
+			/* Continuing a previous NH message */
+			__le64 tmp_hash[NH_NUM_PASSES];
+			unsigned int pos;
+
+			pos = NH_MESSAGE_BYTES - ctx->nh_remaining;
+			bytes = min(len, ctx->nh_remaining);
+			nh(&key->nh_key[pos / 4], data, bytes, tmp_hash);
+			for (int i = 0; i < NH_NUM_PASSES; i++)
+				le64_add_cpu(&ctx->nh_hash[i],
+					     le64_to_cpu(tmp_hash[i]));
+			ctx->nh_remaining -= bytes;
+		}
+		if (ctx->nh_remaining == 0)
+			process_nh_hash_value(ctx, key);
+		data += bytes;
+		len -= bytes;
+	} while (len);
+}
+
+static void nhpoly1305_init(struct nhpoly1305_ctx *ctx)
+{
+	poly1305_core_init(&ctx->poly_state);
+	ctx->buflen = 0;
+	ctx->nh_remaining = 0;
+}
+
+static void nhpoly1305_update(struct nhpoly1305_ctx *ctx,
+			      const struct adiantum_tfm_ctx *key,
+			      const u8 *data, size_t len)
 {
+	unsigned int bytes;
+
+	if (ctx->buflen) {
+		bytes = min(len, (int)NH_MESSAGE_UNIT - ctx->buflen);
+		memcpy(&ctx->buffer[ctx->buflen], data, bytes);
+		ctx->buflen += bytes;
+		if (ctx->buflen < NH_MESSAGE_UNIT)
+			return;
+		nhpoly1305_units(ctx, key, ctx->buffer, NH_MESSAGE_UNIT);
+		ctx->buflen = 0;
+		data += bytes;
+		len -= bytes;
+	}
+
+	if (len >= NH_MESSAGE_UNIT) {
+		bytes = round_down(len, NH_MESSAGE_UNIT);
+		nhpoly1305_units(ctx, key, data, bytes);
+		data += bytes;
+		len -= bytes;
+	}
+
+	if (len) {
+		memcpy(ctx->buffer, data, len);
+		ctx->buflen = len;
+	}
+}
+
+static void nhpoly1305_final(struct nhpoly1305_ctx *ctx,
+			     const struct adiantum_tfm_ctx *key, le128 *out)
+{
+	if (ctx->buflen) {
+		memset(&ctx->buffer[ctx->buflen], 0,
+		       NH_MESSAGE_UNIT - ctx->buflen);
+		nhpoly1305_units(ctx, key, ctx->buffer, NH_MESSAGE_UNIT);
+	}
+
+	if (ctx->nh_remaining)
+		process_nh_hash_value(ctx, key);
+
+	poly1305_core_emit(&ctx->poly_state, NULL, out);
+}
+
+/*
+ * Hash the left-hand part (the "bulk") of the message as follows:
+ *
+ *	H_L ? Poly1305_{K_L}(NH_{K_N}(pad_{128}(L)))
+ *
+ * See section 6.4 of the Adiantum paper.  This is an ?-almost-?-universal
+ * (?-?U) hash function for equal-length inputs over Z/(2^{128}Z), where the "?"
+ * operation is addition.  It hashes 1024-byte chunks of the input with the NH
+ * hash function, reducing the input length by 32x.  The resulting NH hashes are
+ * evaluated as a polynomial in GF(2^{130}-5), like in the Poly1305 MAC.  Note
+ * that the polynomial evaluation by itself would suffice to achieve the ?-?U
+ * property; NH is used for performance since it's much faster than Poly1305.
+ */
+static void adiantum_hash_message(struct skcipher_request *req,
+				  struct scatterlist *sgl, unsigned int nents,
+				  le128 *out)
+{
+	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+	const struct adiantum_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
 	struct adiantum_request_ctx *rctx = skcipher_request_ctx(req);
 	const unsigned int bulk_len = req->cryptlen - BLOCKCIPHER_BLOCK_SIZE;
-	struct shash_desc *hash_desc = &rctx->u.hash_desc;
 	struct sg_mapping_iter miter;
 	unsigned int i, n;
-	int err;
 
-	err = crypto_shash_init(hash_desc);
-	if (err)
-		return err;
+	nhpoly1305_init(&rctx->u.hash_ctx);
 
 	sg_miter_start(&miter, sgl, nents, SG_MITER_FROM_SG | SG_MITER_ATOMIC);
 	for (i = 0; i < bulk_len; i += n) {
 		sg_miter_next(&miter);
 		n = min_t(unsigned int, miter.length, bulk_len - i);
-		err = crypto_shash_update(hash_desc, miter.addr, n);
-		if (err)
-			break;
+		nhpoly1305_update(&rctx->u.hash_ctx, tctx, miter.addr, n);
 	}
 	sg_miter_stop(&miter);
-	if (err)
-		return err;
 
-	return crypto_shash_final(hash_desc, (u8 *)digest);
+	nhpoly1305_final(&rctx->u.hash_ctx, tctx, out);
 }
 
 /* Continue Adiantum encryption/decryption after the stream cipher step */
 static int adiantum_finish(struct skcipher_request *req)
 {
@@ -282,11 +400,10 @@ static int adiantum_finish(struct skcipher_request *req)
 	struct adiantum_request_ctx *rctx = skcipher_request_ctx(req);
 	const unsigned int bulk_len = req->cryptlen - BLOCKCIPHER_BLOCK_SIZE;
 	struct scatterlist *dst = req->dst;
 	const unsigned int dst_nents = sg_nents(dst);
 	le128 digest;
-	int err;
 
 	/* If decrypting, decrypt C_M with the block cipher to get P_M */
 	if (!rctx->enc)
 		crypto_cipher_decrypt_one(tctx->blockcipher, rctx->rbuf.bytes,
 					  rctx->rbuf.bytes);
@@ -294,32 +411,26 @@ static int adiantum_finish(struct skcipher_request *req)
 	/*
 	 * Second hash step
 	 *	enc: C_R = C_M - H_{K_H}(T, C_L)
 	 *	dec: P_R = P_M - H_{K_H}(T, P_L)
 	 */
-	rctx->u.hash_desc.tfm = tctx->hash;
 	le128_sub(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &rctx->header_hash);
 	if (dst_nents == 1 && dst->offset + req->cryptlen <= PAGE_SIZE) {
 		/* Fast path for single-page destination */
 		struct page *page = sg_page(dst);
 		void *virt = kmap_local_page(page) + dst->offset;
 
-		err = crypto_shash_digest(&rctx->u.hash_desc, virt, bulk_len,
-					  (u8 *)&digest);
-		if (err) {
-			kunmap_local(virt);
-			return err;
-		}
+		nhpoly1305_init(&rctx->u.hash_ctx);
+		nhpoly1305_update(&rctx->u.hash_ctx, tctx, virt, bulk_len);
+		nhpoly1305_final(&rctx->u.hash_ctx, tctx, &digest);
 		le128_sub(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &digest);
 		memcpy(virt + bulk_len, &rctx->rbuf.bignum, sizeof(le128));
 		flush_dcache_page(page);
 		kunmap_local(virt);
 	} else {
 		/* Slow path that works for any destination scatterlist */
-		err = adiantum_hash_message(req, dst, dst_nents, &digest);
-		if (err)
-			return err;
+		adiantum_hash_message(req, dst, dst_nents, &digest);
 		le128_sub(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &digest);
 		scatterwalk_map_and_copy(&rctx->rbuf.bignum, dst,
 					 bulk_len, sizeof(le128), 1);
 	}
 	return 0;
@@ -343,11 +454,10 @@ static int adiantum_crypt(struct skcipher_request *req, bool enc)
 	const unsigned int bulk_len = req->cryptlen - BLOCKCIPHER_BLOCK_SIZE;
 	struct scatterlist *src = req->src;
 	const unsigned int src_nents = sg_nents(src);
 	unsigned int stream_len;
 	le128 digest;
-	int err;
 
 	if (req->cryptlen < BLOCKCIPHER_BLOCK_SIZE)
 		return -EINVAL;
 
 	rctx->enc = enc;
@@ -356,27 +466,25 @@ static int adiantum_crypt(struct skcipher_request *req, bool enc)
 	 * First hash step
 	 *	enc: P_M = P_R + H_{K_H}(T, P_L)
 	 *	dec: C_M = C_R + H_{K_H}(T, C_L)
 	 */
 	adiantum_hash_header(req);
-	rctx->u.hash_desc.tfm = tctx->hash;
 	if (src_nents == 1 && src->offset + req->cryptlen <= PAGE_SIZE) {
 		/* Fast path for single-page source */
 		void *virt = kmap_local_page(sg_page(src)) + src->offset;
 
-		err = crypto_shash_digest(&rctx->u.hash_desc, virt, bulk_len,
-					  (u8 *)&digest);
+		nhpoly1305_init(&rctx->u.hash_ctx);
+		nhpoly1305_update(&rctx->u.hash_ctx, tctx, virt, bulk_len);
+		nhpoly1305_final(&rctx->u.hash_ctx, tctx, &digest);
 		memcpy(&rctx->rbuf.bignum, virt + bulk_len, sizeof(le128));
 		kunmap_local(virt);
 	} else {
 		/* Slow path that works for any source scatterlist */
-		err = adiantum_hash_message(req, src, src_nents, &digest);
+		adiantum_hash_message(req, src, src_nents, &digest);
 		scatterwalk_map_and_copy(&rctx->rbuf.bignum, src,
 					 bulk_len, sizeof(le128), 0);
 	}
-	if (err)
-		return err;
 	le128_add(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &rctx->header_hash);
 	le128_add(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &digest);
 
 	/* If encrypting, encrypt P_M with the block cipher to get C_M */
 	if (enc)
@@ -429,12 +537,10 @@ static int adiantum_init_tfm(struct crypto_skcipher *tfm)
 	struct skcipher_instance *inst = skcipher_alg_instance(tfm);
 	struct adiantum_instance_ctx *ictx = skcipher_instance_ctx(inst);
 	struct adiantum_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
 	struct crypto_skcipher *streamcipher;
 	struct crypto_cipher *blockcipher;
-	struct crypto_shash *hash;
-	unsigned int subreq_size;
 	int err;
 
 	streamcipher = crypto_spawn_skcipher(&ictx->streamcipher_spawn);
 	if (IS_ERR(streamcipher))
 		return PTR_ERR(streamcipher);
@@ -443,36 +549,22 @@ static int adiantum_init_tfm(struct crypto_skcipher *tfm)
 	if (IS_ERR(blockcipher)) {
 		err = PTR_ERR(blockcipher);
 		goto err_free_streamcipher;
 	}
 
-	hash = crypto_spawn_shash(&ictx->hash_spawn);
-	if (IS_ERR(hash)) {
-		err = PTR_ERR(hash);
-		goto err_free_blockcipher;
-	}
-
 	tctx->streamcipher = streamcipher;
 	tctx->blockcipher = blockcipher;
-	tctx->hash = hash;
 
 	BUILD_BUG_ON(offsetofend(struct adiantum_request_ctx, u) !=
 		     sizeof(struct adiantum_request_ctx));
-	subreq_size = max(sizeof_field(struct adiantum_request_ctx,
-				       u.hash_desc) +
-			  crypto_shash_descsize(hash),
-			  sizeof_field(struct adiantum_request_ctx,
-				       u.streamcipher_req) +
-			  crypto_skcipher_reqsize(streamcipher));
-
-	crypto_skcipher_set_reqsize(tfm,
-				    offsetof(struct adiantum_request_ctx, u) +
-				    subreq_size);
+	crypto_skcipher_set_reqsize(
+		tfm, max(sizeof(struct adiantum_request_ctx),
+			 offsetofend(struct adiantum_request_ctx,
+				     u.streamcipher_req) +
+				 crypto_skcipher_reqsize(streamcipher)));
 	return 0;
 
-err_free_blockcipher:
-	crypto_free_cipher(blockcipher);
 err_free_streamcipher:
 	crypto_free_skcipher(streamcipher);
 	return err;
 }
 
@@ -480,30 +572,28 @@ static void adiantum_exit_tfm(struct crypto_skcipher *tfm)
 {
 	struct adiantum_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
 
 	crypto_free_skcipher(tctx->streamcipher);
 	crypto_free_cipher(tctx->blockcipher);
-	crypto_free_shash(tctx->hash);
 }
 
 static void adiantum_free_instance(struct skcipher_instance *inst)
 {
 	struct adiantum_instance_ctx *ictx = skcipher_instance_ctx(inst);
 
 	crypto_drop_skcipher(&ictx->streamcipher_spawn);
 	crypto_drop_cipher(&ictx->blockcipher_spawn);
-	crypto_drop_shash(&ictx->hash_spawn);
 	kfree(inst);
 }
 
 /*
  * Check for a supported set of inner algorithms.
  * See the comment at the beginning of this file.
  */
-static bool adiantum_supported_algorithms(struct skcipher_alg_common *streamcipher_alg,
-					  struct crypto_alg *blockcipher_alg,
-					  struct shash_alg *hash_alg)
+static bool
+adiantum_supported_algorithms(struct skcipher_alg_common *streamcipher_alg,
+			      struct crypto_alg *blockcipher_alg)
 {
 	if (strcmp(streamcipher_alg->base.cra_name, "xchacha12") != 0 &&
 	    strcmp(streamcipher_alg->base.cra_name, "xchacha20") != 0)
 		return false;
 
@@ -511,25 +601,20 @@ static bool adiantum_supported_algorithms(struct skcipher_alg_common *streamciph
 	    blockcipher_alg->cra_cipher.cia_max_keysize < BLOCKCIPHER_KEY_SIZE)
 		return false;
 	if (blockcipher_alg->cra_blocksize != BLOCKCIPHER_BLOCK_SIZE)
 		return false;
 
-	if (strcmp(hash_alg->base.cra_name, "nhpoly1305") != 0)
-		return false;
-
 	return true;
 }
 
 static int adiantum_create(struct crypto_template *tmpl, struct rtattr **tb)
 {
 	u32 mask;
-	const char *nhpoly1305_name;
 	struct skcipher_instance *inst;
 	struct adiantum_instance_ctx *ictx;
 	struct skcipher_alg_common *streamcipher_alg;
 	struct crypto_alg *blockcipher_alg;
-	struct shash_alg *hash_alg;
 	int err;
 
 	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SKCIPHER, &mask);
 	if (err)
 		return err;
@@ -553,27 +638,25 @@ static int adiantum_create(struct crypto_template *tmpl, struct rtattr **tb)
 				 crypto_attr_alg_name(tb[2]), 0, mask);
 	if (err)
 		goto err_free_inst;
 	blockcipher_alg = crypto_spawn_cipher_alg(&ictx->blockcipher_spawn);
 
-	/* NHPoly1305 ?-?U hash function */
-	nhpoly1305_name = crypto_attr_alg_name(tb[3]);
-	if (nhpoly1305_name == ERR_PTR(-ENOENT))
-		nhpoly1305_name = "nhpoly1305";
-	err = crypto_grab_shash(&ictx->hash_spawn,
-				skcipher_crypto_instance(inst),
-				nhpoly1305_name, 0, mask);
-	if (err)
+	/*
+	 * Originally there was an optional third parameter, for requesting a
+	 * specific implementation of "nhpoly1305" for message hashing.  This is
+	 * no longer supported.  The best implementation is just always used.
+	 */
+	if (crypto_attr_alg_name(tb[3]) != ERR_PTR(-ENOENT)) {
+		err = -ENOENT;
 		goto err_free_inst;
-	hash_alg = crypto_spawn_shash_alg(&ictx->hash_spawn);
+	}
 
 	/* Check the set of algorithms */
-	if (!adiantum_supported_algorithms(streamcipher_alg, blockcipher_alg,
-					   hash_alg)) {
-		pr_warn("Unsupported Adiantum instantiation: (%s,%s,%s)\n",
+	if (!adiantum_supported_algorithms(streamcipher_alg, blockcipher_alg)) {
+		pr_warn("Unsupported Adiantum instantiation: (%s,%s)\n",
 			streamcipher_alg->base.cra_name,
-			blockcipher_alg->cra_name, hash_alg->base.cra_name);
+			blockcipher_alg->cra_name);
 		err = -EINVAL;
 		goto err_free_inst;
 	}
 
 	/* Instance fields */
@@ -582,28 +665,26 @@ static int adiantum_create(struct crypto_template *tmpl, struct rtattr **tb)
 	if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
 		     "adiantum(%s,%s)", streamcipher_alg->base.cra_name,
 		     blockcipher_alg->cra_name) >= CRYPTO_MAX_ALG_NAME)
 		goto err_free_inst;
 	if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
-		     "adiantum(%s,%s,%s)",
-		     streamcipher_alg->base.cra_driver_name,
-		     blockcipher_alg->cra_driver_name,
-		     hash_alg->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
+		     "adiantum(%s,%s)", streamcipher_alg->base.cra_driver_name,
+		     blockcipher_alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
 		goto err_free_inst;
 
 	inst->alg.base.cra_blocksize = BLOCKCIPHER_BLOCK_SIZE;
 	inst->alg.base.cra_ctxsize = sizeof(struct adiantum_tfm_ctx);
 	inst->alg.base.cra_alignmask = streamcipher_alg->base.cra_alignmask;
 	/*
 	 * The block cipher is only invoked once per message, so for long
 	 * messages (e.g. sectors for disk encryption) its performance doesn't
-	 * matter as much as that of the stream cipher and hash function.  Thus,
-	 * weigh the block cipher's ->cra_priority less.
+	 * matter as much as that of the stream cipher.  Thus, weigh the block
+	 * cipher's ->cra_priority less.
 	 */
 	inst->alg.base.cra_priority = (4 * streamcipher_alg->base.cra_priority +
-				       2 * hash_alg->base.cra_priority +
-				       blockcipher_alg->cra_priority) / 7;
+				       blockcipher_alg->cra_priority) /
+				      5;
 
 	inst->alg.setkey = adiantum_setkey;
 	inst->alg.encrypt = adiantum_encrypt;
 	inst->alg.decrypt = adiantum_decrypt;
 	inst->alg.init = adiantum_init_tfm;
@@ -620,11 +701,11 @@ static int adiantum_create(struct crypto_template *tmpl, struct rtattr **tb)
 		adiantum_free_instance(inst);
 	}
 	return err;
 }
 
-/* adiantum(streamcipher_name, blockcipher_name [, nhpoly1305_name]) */
+/* adiantum(streamcipher_name, blockcipher_name) */
 static struct crypto_template adiantum_tmpl = {
 	.name = "adiantum",
 	.create = adiantum_create,
 	.module = THIS_MODULE,
 };
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index a302be53896d..d9fc671d5941 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -4059,18 +4059,18 @@ static int alg_test_null(const struct alg_test_desc *desc,
 
 /* Please keep this list sorted by algorithm name. */
 static const struct alg_test_desc alg_test_descs[] = {
 	{
 		.alg = "adiantum(xchacha12,aes)",
-		.generic_driver = "adiantum(xchacha12-lib,aes-generic,nhpoly1305-generic)",
+		.generic_driver = "adiantum(xchacha12-lib,aes-generic)",
 		.test = alg_test_skcipher,
 		.suite = {
 			.cipher = __VECS(adiantum_xchacha12_aes_tv_template)
 		},
 	}, {
 		.alg = "adiantum(xchacha20,aes)",
-		.generic_driver = "adiantum(xchacha20-lib,aes-generic,nhpoly1305-generic)",
+		.generic_driver = "adiantum(xchacha20-lib,aes-generic)",
 		.test = alg_test_skcipher,
 		.suite = {
 			.cipher = __VECS(adiantum_xchacha20_aes_tv_template)
 		},
 	}, {
-- 
2.52.0



From ebiggers at kernel.org  Wed Dec 10 17:18:40 2025
From: ebiggers at kernel.org (Eric Biggers)
Date: Wed, 10 Dec 2025 17:18:40 -0800
Subject: [PATCH 08/12] crypto: adiantum - Use memcpy_{to,from}_sglist()
In-Reply-To: <20251211011846.8179-1-ebiggers@kernel.org>
References: <20251211011846.8179-1-ebiggers@kernel.org>
Message-ID: <20251211011846.8179-9-ebiggers@kernel.org>

Call the newer, easier-to-read functions memcpy_to_sglist() and
memcpy_from_sglist() directly instead of calling
scatterwalk_map_and_copy().  No change in behavior.

Signed-off-by: Eric Biggers <ebiggers at kernel.org>
---
 crypto/adiantum.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/crypto/adiantum.c b/crypto/adiantum.c
index 519e95228ad8..6d882f926ab0 100644
--- a/crypto/adiantum.c
+++ b/crypto/adiantum.c
@@ -425,12 +425,12 @@ static int adiantum_finish(struct skcipher_request *req)
 		kunmap_local(virt);
 	} else {
 		/* Slow path that works for any destination scatterlist */
 		adiantum_hash_message(req, dst, &digest);
 		le128_sub(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &digest);
-		scatterwalk_map_and_copy(&rctx->rbuf.bignum, dst,
-					 bulk_len, sizeof(le128), 1);
+		memcpy_to_sglist(dst, bulk_len, &rctx->rbuf.bignum,
+				 sizeof(le128));
 	}
 	return 0;
 }
 
 static void adiantum_streamcipher_done(void *data, int err)
@@ -475,12 +475,12 @@ static int adiantum_crypt(struct skcipher_request *req, bool enc)
 		memcpy(&rctx->rbuf.bignum, virt + bulk_len, sizeof(le128));
 		kunmap_local(virt);
 	} else {
 		/* Slow path that works for any source scatterlist */
 		adiantum_hash_message(req, src, &digest);
-		scatterwalk_map_and_copy(&rctx->rbuf.bignum, src,
-					 bulk_len, sizeof(le128), 0);
+		memcpy_from_sglist(&rctx->rbuf.bignum, src, bulk_len,
+				   sizeof(le128));
 	}
 	le128_add(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &rctx->header_hash);
 	le128_add(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &digest);
 
 	/* If encrypting, encrypt P_M with the block cipher to get C_M */
-- 
2.52.0



From ebiggers at kernel.org  Wed Dec 10 17:18:41 2025
From: ebiggers at kernel.org (Eric Biggers)
Date: Wed, 10 Dec 2025 17:18:41 -0800
Subject: [PATCH 09/12] crypto: adiantum - Drop support for asynchronous xchacha ciphers
In-Reply-To: <20251211011846.8179-1-ebiggers@kernel.org>
References: <20251211011846.8179-1-ebiggers@kernel.org>
Message-ID: <20251211011846.8179-10-ebiggers@kernel.org>

This feature isn't useful in practice.  Simplify and streamline the code
in the synchronous case, i.e. the case that actually matters, instead.

For example, by no longer having to support resuming the calculation
after an asynchronous return of the xchacha cipher, we can just keep
more of the state on the stack instead of in the request context.

Signed-off-by: Eric Biggers <ebiggers at kernel.org>
---
 crypto/adiantum.c | 174 +++++++++++++++++++---------------------------
 1 file changed, 70 insertions(+), 104 deletions(-)

diff --git a/crypto/adiantum.c b/crypto/adiantum.c
index 6d882f926ab0..5ddf585abb66 100644
--- a/crypto/adiantum.c
+++ b/crypto/adiantum.c
@@ -81,33 +81,10 @@ struct nhpoly1305_ctx {
 
 	__le64 nh_hash[NH_NUM_PASSES];
 };
 
 struct adiantum_request_ctx {
-
-	/*
-	 * Buffer for right-hand part of data, i.e.
-	 *
-	 *    P_L => P_M => C_M => C_R when encrypting, or
-	 *    C_R => C_M => P_M => P_L when decrypting.
-	 *
-	 * Also used to build the IV for the stream cipher.
-	 */
-	union {
-		u8 bytes[XCHACHA_IV_SIZE];
-		__le32 words[XCHACHA_IV_SIZE / sizeof(__le32)];
-		le128 bignum;	/* interpret as element of Z/(2^{128}Z) */
-	} rbuf;
-
-	bool enc; /* true if encrypting, false if decrypting */
-
-	/*
-	 * The result of the Poly1305 ?-?U hash function applied to
-	 * (bulk length, tweak)
-	 */
-	le128 header_hash;
-
 	/*
 	 * skcipher sub-request size is unknown at compile-time, so it needs to
 	 * go after the members with known sizes.
 	 */
 	union {
@@ -214,25 +191,24 @@ static inline void le128_sub(le128 *r, const le128 *v1, const le128 *v2)
 			   (x - y > x));
 }
 
 /*
  * Apply the Poly1305 ?-?U hash function to (bulk length, tweak) and save the
- * result to rctx->header_hash.  This is the calculation
+ * result to @out.  This is the calculation
  *
  *	H_T ? Poly1305_{K_T}(bin_{128}(|L|) || T)
  *
  * from the procedure in section 6.4 of the Adiantum paper.  The resulting value
  * is reused in both the first and second hash steps.  Specifically, it's added
  * to the result of an independently keyed ?-?U hash function (for equal length
  * inputs only) taken over the left-hand part (the "bulk") of the message, to
  * give the overall Adiantum hash of the (tweak, left-hand part) pair.
  */
-static void adiantum_hash_header(struct skcipher_request *req)
+static void adiantum_hash_header(struct skcipher_request *req, le128 *out)
 {
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 	const struct adiantum_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
-	struct adiantum_request_ctx *rctx = skcipher_request_ctx(req);
 	const unsigned int bulk_len = req->cryptlen - BLOCKCIPHER_BLOCK_SIZE;
 	struct {
 		__le64 message_bits;
 		__le64 padding;
 	} header = {
@@ -248,11 +224,11 @@ static void adiantum_hash_header(struct skcipher_request *req)
 
 	BUILD_BUG_ON(TWEAK_SIZE % POLY1305_BLOCK_SIZE != 0);
 	poly1305_core_blocks(&state, &tctx->header_hash_key, req->iv,
 			     TWEAK_SIZE / POLY1305_BLOCK_SIZE, 1);
 
-	poly1305_core_emit(&state, NULL, &rctx->header_hash);
+	poly1305_core_emit(&state, NULL, out);
 }
 
 /* Pass the next NH hash value through Poly1305 */
 static void process_nh_hash_value(struct nhpoly1305_ctx *ctx,
 				  const struct adiantum_tfm_ctx *key)
@@ -387,116 +363,73 @@ static void adiantum_hash_message(struct skcipher_request *req,
 		len -= n;
 	}
 	nhpoly1305_final(&rctx->u.hash_ctx, tctx, out);
 }
 
-/* Continue Adiantum encryption/decryption after the stream cipher step */
-static int adiantum_finish(struct skcipher_request *req)
+static int adiantum_crypt(struct skcipher_request *req, bool enc)
 {
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 	const struct adiantum_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
 	struct adiantum_request_ctx *rctx = skcipher_request_ctx(req);
 	const unsigned int bulk_len = req->cryptlen - BLOCKCIPHER_BLOCK_SIZE;
-	struct scatterlist *dst = req->dst;
-	le128 digest;
-
-	/* If decrypting, decrypt C_M with the block cipher to get P_M */
-	if (!rctx->enc)
-		crypto_cipher_decrypt_one(tctx->blockcipher, rctx->rbuf.bytes,
-					  rctx->rbuf.bytes);
-
+	struct scatterlist *src = req->src, *dst = req->dst;
 	/*
-	 * Second hash step
-	 *	enc: C_R = C_M - H_{K_H}(T, C_L)
-	 *	dec: P_R = P_M - H_{K_H}(T, P_L)
+	 * Buffer for right-hand part of data, i.e.
+	 *
+	 *    P_L => P_M => C_M => C_R when encrypting, or
+	 *    C_R => C_M => P_M => P_L when decrypting.
+	 *
+	 * Also used to build the IV for the stream cipher.
 	 */
-	le128_sub(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &rctx->header_hash);
-	if (dst->length >= req->cryptlen &&
-	    dst->offset + req->cryptlen <= PAGE_SIZE) {
-		/* Fast path for single-page destination */
-		struct page *page = sg_page(dst);
-		void *virt = kmap_local_page(page) + dst->offset;
-
-		nhpoly1305_init(&rctx->u.hash_ctx);
-		nhpoly1305_update(&rctx->u.hash_ctx, tctx, virt, bulk_len);
-		nhpoly1305_final(&rctx->u.hash_ctx, tctx, &digest);
-		le128_sub(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &digest);
-		memcpy(virt + bulk_len, &rctx->rbuf.bignum, sizeof(le128));
-		flush_dcache_page(page);
-		kunmap_local(virt);
-	} else {
-		/* Slow path that works for any destination scatterlist */
-		adiantum_hash_message(req, dst, &digest);
-		le128_sub(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &digest);
-		memcpy_to_sglist(dst, bulk_len, &rctx->rbuf.bignum,
-				 sizeof(le128));
-	}
-	return 0;
-}
-
-static void adiantum_streamcipher_done(void *data, int err)
-{
-	struct skcipher_request *req = data;
-
-	if (!err)
-		err = adiantum_finish(req);
-
-	skcipher_request_complete(req, err);
-}
-
-static int adiantum_crypt(struct skcipher_request *req, bool enc)
-{
-	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
-	const struct adiantum_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
-	struct adiantum_request_ctx *rctx = skcipher_request_ctx(req);
-	const unsigned int bulk_len = req->cryptlen - BLOCKCIPHER_BLOCK_SIZE;
-	struct scatterlist *src = req->src;
+	union {
+		u8 bytes[XCHACHA_IV_SIZE];
+		__le32 words[XCHACHA_IV_SIZE / sizeof(__le32)];
+		le128 bignum; /* interpret as element of Z/(2^{128}Z) */
+	} rbuf;
+	le128 header_hash, msg_hash;
 	unsigned int stream_len;
-	le128 digest;
+	int err;
 
 	if (req->cryptlen < BLOCKCIPHER_BLOCK_SIZE)
 		return -EINVAL;
 
-	rctx->enc = enc;
-
 	/*
 	 * First hash step
 	 *	enc: P_M = P_R + H_{K_H}(T, P_L)
 	 *	dec: C_M = C_R + H_{K_H}(T, C_L)
 	 */
-	adiantum_hash_header(req);
+	adiantum_hash_header(req, &header_hash);
 	if (src->length >= req->cryptlen &&
 	    src->offset + req->cryptlen <= PAGE_SIZE) {
 		/* Fast path for single-page source */
 		void *virt = kmap_local_page(sg_page(src)) + src->offset;
 
 		nhpoly1305_init(&rctx->u.hash_ctx);
 		nhpoly1305_update(&rctx->u.hash_ctx, tctx, virt, bulk_len);
-		nhpoly1305_final(&rctx->u.hash_ctx, tctx, &digest);
-		memcpy(&rctx->rbuf.bignum, virt + bulk_len, sizeof(le128));
+		nhpoly1305_final(&rctx->u.hash_ctx, tctx, &msg_hash);
+		memcpy(&rbuf.bignum, virt + bulk_len, sizeof(le128));
 		kunmap_local(virt);
 	} else {
 		/* Slow path that works for any source scatterlist */
-		adiantum_hash_message(req, src, &digest);
-		memcpy_from_sglist(&rctx->rbuf.bignum, src, bulk_len,
-				   sizeof(le128));
+		adiantum_hash_message(req, src, &msg_hash);
+		memcpy_from_sglist(&rbuf.bignum, src, bulk_len, sizeof(le128));
 	}
-	le128_add(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &rctx->header_hash);
-	le128_add(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &digest);
+	le128_add(&rbuf.bignum, &rbuf.bignum, &header_hash);
+	le128_add(&rbuf.bignum, &rbuf.bignum, &msg_hash);
 
 	/* If encrypting, encrypt P_M with the block cipher to get C_M */
 	if (enc)
-		crypto_cipher_encrypt_one(tctx->blockcipher, rctx->rbuf.bytes,
-					  rctx->rbuf.bytes);
+		crypto_cipher_encrypt_one(tctx->blockcipher, rbuf.bytes,
+					  rbuf.bytes);
 
 	/* Initialize the rest of the XChaCha IV (first part is C_M) */
 	BUILD_BUG_ON(BLOCKCIPHER_BLOCK_SIZE != 16);
 	BUILD_BUG_ON(XCHACHA_IV_SIZE != 32);	/* nonce || stream position */
-	rctx->rbuf.words[4] = cpu_to_le32(1);
-	rctx->rbuf.words[5] = 0;
-	rctx->rbuf.words[6] = 0;
-	rctx->rbuf.words[7] = 0;
+	rbuf.words[4] = cpu_to_le32(1);
+	rbuf.words[5] = 0;
+	rbuf.words[6] = 0;
+	rbuf.words[7] = 0;
 
 	/*
 	 * XChaCha needs to be done on all the data except the last 16 bytes;
 	 * for disk encryption that usually means 4080 or 496 bytes.  But ChaCha
 	 * implementations tend to be most efficient when passed a whole number
@@ -509,16 +442,48 @@ static int adiantum_crypt(struct skcipher_request *req, bool enc)
 	if (round_up(stream_len, CHACHA_BLOCK_SIZE) <= req->cryptlen)
 		stream_len = round_up(stream_len, CHACHA_BLOCK_SIZE);
 
 	skcipher_request_set_tfm(&rctx->u.streamcipher_req, tctx->streamcipher);
 	skcipher_request_set_crypt(&rctx->u.streamcipher_req, req->src,
-				   req->dst, stream_len, &rctx->rbuf);
+				   req->dst, stream_len, &rbuf);
 	skcipher_request_set_callback(&rctx->u.streamcipher_req,
-				      req->base.flags,
-				      adiantum_streamcipher_done, req);
-	return crypto_skcipher_encrypt(&rctx->u.streamcipher_req) ?:
-		adiantum_finish(req);
+				      req->base.flags, NULL, NULL);
+	err = crypto_skcipher_encrypt(&rctx->u.streamcipher_req);
+	if (err)
+		return err;
+
+	/* If decrypting, decrypt C_M with the block cipher to get P_M */
+	if (!enc)
+		crypto_cipher_decrypt_one(tctx->blockcipher, rbuf.bytes,
+					  rbuf.bytes);
+
+	/*
+	 * Second hash step
+	 *	enc: C_R = C_M - H_{K_H}(T, C_L)
+	 *	dec: P_R = P_M - H_{K_H}(T, P_L)
+	 */
+	le128_sub(&rbuf.bignum, &rbuf.bignum, &header_hash);
+	if (dst->length >= req->cryptlen &&
+	    dst->offset + req->cryptlen <= PAGE_SIZE) {
+		/* Fast path for single-page destination */
+		struct page *page = sg_page(dst);
+		void *virt = kmap_local_page(page) + dst->offset;
+
+		nhpoly1305_init(&rctx->u.hash_ctx);
+		nhpoly1305_update(&rctx->u.hash_ctx, tctx, virt, bulk_len);
+		nhpoly1305_final(&rctx->u.hash_ctx, tctx, &msg_hash);
+		le128_sub(&rbuf.bignum, &rbuf.bignum, &msg_hash);
+		memcpy(virt + bulk_len, &rbuf.bignum, sizeof(le128));
+		flush_dcache_page(page);
+		kunmap_local(virt);
+	} else {
+		/* Slow path that works for any destination scatterlist */
+		adiantum_hash_message(req, dst, &msg_hash);
+		le128_sub(&rbuf.bignum, &rbuf.bignum, &msg_hash);
+		memcpy_to_sglist(dst, bulk_len, &rbuf.bignum, sizeof(le128));
+	}
+	return 0;
 }
 
 static int adiantum_encrypt(struct skcipher_request *req)
 {
 	return adiantum_crypt(req, true);
@@ -622,11 +587,12 @@ static int adiantum_create(struct crypto_template *tmpl, struct rtattr **tb)
 	ictx = skcipher_instance_ctx(inst);
 
 	/* Stream cipher, e.g. "xchacha12" */
 	err = crypto_grab_skcipher(&ictx->streamcipher_spawn,
 				   skcipher_crypto_instance(inst),
-				   crypto_attr_alg_name(tb[1]), 0, mask);
+				   crypto_attr_alg_name(tb[1]), 0,
+				   mask | CRYPTO_ALG_ASYNC /* sync only */);
 	if (err)
 		goto err_free_inst;
 	streamcipher_alg = crypto_spawn_skcipher_alg_common(&ictx->streamcipher_spawn);
 
 	/* Block cipher, e.g. "aes" */
-- 
2.52.0



From ebiggers at kernel.org  Wed Dec 10 17:18:44 2025
From: ebiggers at kernel.org (Eric Biggers)
Date: Wed, 10 Dec 2025 17:18:44 -0800
Subject: [PATCH 12/12] fscrypt: Drop obsolete recommendation to enable optimized NHPoly1305
In-Reply-To: <20251211011846.8179-1-ebiggers@kernel.org>
References: <20251211011846.8179-1-ebiggers@kernel.org>
Message-ID: <20251211011846.8179-13-ebiggers@kernel.org>

CONFIG_CRYPTO_NHPOLY1305_NEON, CONFIG_CRYPTO_NHPOLY1305_SSE2, and
CONFIG_CRYPTO_NHPOLY1305_AVX2 no longer exist.  The equivalent
optimizations are now just enabled automatically when Adiantum support
is enabled.  Update the fscrypt documentation accordingly.

Signed-off-by: Eric Biggers <ebiggers at kernel.org>
---
 Documentation/filesystems/fscrypt.rst | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/Documentation/filesystems/fscrypt.rst b/Documentation/filesystems/fscrypt.rst
index 70af896822e1..c0dd35f1af12 100644
--- a/Documentation/filesystems/fscrypt.rst
+++ b/Documentation/filesystems/fscrypt.rst
@@ -453,15 +453,10 @@ API, but the filenames mode still does.
         - x86: CONFIG_CRYPTO_AES_NI_INTEL
 
 - Adiantum
     - Mandatory:
         - CONFIG_CRYPTO_ADIANTUM
-    - Recommended:
-        - arm32: CONFIG_CRYPTO_NHPOLY1305_NEON
-        - arm64: CONFIG_CRYPTO_NHPOLY1305_NEON
-        - x86: CONFIG_CRYPTO_NHPOLY1305_SSE2
-        - x86: CONFIG_CRYPTO_NHPOLY1305_AVX2
 
 - AES-128-CBC-ESSIV and AES-128-CBC-CTS:
     - Mandatory:
         - CONFIG_CRYPTO_ESSIV
         - CONFIG_CRYPTO_SHA256 or another SHA-256 implementation
-- 
2.52.0



From ebiggers at kernel.org  Wed Dec 10 17:18:42 2025
From: ebiggers at kernel.org (Eric Biggers)
Date: Wed, 10 Dec 2025 17:18:42 -0800
Subject: [PATCH 10/12] crypto: nhpoly1305 - Remove crypto_shash support
In-Reply-To: <20251211011846.8179-1-ebiggers@kernel.org>
References: <20251211011846.8179-1-ebiggers@kernel.org>
Message-ID: <20251211011846.8179-11-ebiggers@kernel.org>

Remove nhpoly1305 support from crypto_shash.  It no longer has any user
now that crypto/adiantum.c no longer uses it.

Signed-off-by: Eric Biggers <ebiggers at kernel.org>
---
 crypto/Kconfig              |   6 -
 crypto/Makefile             |   1 -
 crypto/nhpoly1305.c         | 255 ------------------------------------
 include/crypto/nhpoly1305.h |  74 -----------
 4 files changed, 336 deletions(-)
 delete mode 100644 crypto/nhpoly1305.c
 delete mode 100644 include/crypto/nhpoly1305.h

diff --git a/crypto/Kconfig b/crypto/Kconfig
index 89d1ccaa1fa0..12a87f7cf150 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -757,16 +757,10 @@ config CRYPTO_XTS
 
 	  Use with aes-xts-plain, key size 256, 384 or 512 bits. This
 	  implementation currently can't handle a sectorsize which is not a
 	  multiple of 16 bytes.
 
-config CRYPTO_NHPOLY1305
-	tristate
-	select CRYPTO_HASH
-	select CRYPTO_LIB_POLY1305
-	select CRYPTO_LIB_POLY1305_GENERIC
-
 endmenu
 
 menu "AEAD (authenticated encryption with associated data) ciphers"
 
 config CRYPTO_AEGIS128
diff --git a/crypto/Makefile b/crypto/Makefile
index 16a35649dd91..23d3db7be425 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -92,11 +92,10 @@ obj-$(CONFIG_CRYPTO_LRW) += lrw.o
 obj-$(CONFIG_CRYPTO_XTS) += xts.o
 obj-$(CONFIG_CRYPTO_CTR) += ctr.o
 obj-$(CONFIG_CRYPTO_XCTR) += xctr.o
 obj-$(CONFIG_CRYPTO_HCTR2) += hctr2.o
 obj-$(CONFIG_CRYPTO_ADIANTUM) += adiantum.o
-obj-$(CONFIG_CRYPTO_NHPOLY1305) += nhpoly1305.o
 obj-$(CONFIG_CRYPTO_GCM) += gcm.o
 obj-$(CONFIG_CRYPTO_CCM) += ccm.o
 obj-$(CONFIG_CRYPTO_CHACHA20POLY1305) += chacha20poly1305.o
 obj-$(CONFIG_CRYPTO_AEGIS128) += aegis128.o
 aegis128-y := aegis128-core.o
diff --git a/crypto/nhpoly1305.c b/crypto/nhpoly1305.c
deleted file mode 100644
index 2b648615b5ec..000000000000
--- a/crypto/nhpoly1305.c
+++ /dev/null
@@ -1,255 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * NHPoly1305 - ?-almost-?-universal hash function for Adiantum
- *
- * Copyright 2018 Google LLC
- */
-
-/*
- * "NHPoly1305" is the main component of Adiantum hashing.
- * Specifically, it is the calculation
- *
- *	H_L ? Poly1305_{K_L}(NH_{K_N}(pad_{128}(L)))
- *
- * from the procedure in section 6.4 of the Adiantum paper [1].  It is an
- * ?-almost-?-universal (?-?U) hash function for equal-length inputs over
- * Z/(2^{128}Z), where the "?" operation is addition.  It hashes 1024-byte
- * chunks of the input with the NH hash function [2], reducing the input length
- * by 32x.  The resulting NH digests are evaluated as a polynomial in
- * GF(2^{130}-5), like in the Poly1305 MAC [3].  Note that the polynomial
- * evaluation by itself would suffice to achieve the ?-?U property; NH is used
- * for performance since it's over twice as fast as Poly1305.
- *
- * This is *not* a cryptographic hash function; do not use it as such!
- *
- * [1] Adiantum: length-preserving encryption for entry-level processors
- *     (https://eprint.iacr.org/2018/720.pdf)
- * [2] UMAC: Fast and Secure Message Authentication
- *     (https://fastcrypto.org/umac/umac_proc.pdf)
- * [3] The Poly1305-AES message-authentication code
- *     (https://cr.yp.to/mac/poly1305-20050329.pdf)
- */
-
-#include <linux/unaligned.h>
-#include <crypto/algapi.h>
-#include <crypto/internal/hash.h>
-#include <crypto/internal/poly1305.h>
-#include <crypto/nhpoly1305.h>
-#include <linux/crypto.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-
-static void nh_generic(const u32 *key, const u8 *message, size_t message_len,
-		       __le64 hash[NH_NUM_PASSES])
-{
-	u64 sums[4] = { 0, 0, 0, 0 };
-
-	BUILD_BUG_ON(NH_PAIR_STRIDE != 2);
-	BUILD_BUG_ON(NH_NUM_PASSES != 4);
-
-	while (message_len) {
-		u32 m0 = get_unaligned_le32(message + 0);
-		u32 m1 = get_unaligned_le32(message + 4);
-		u32 m2 = get_unaligned_le32(message + 8);
-		u32 m3 = get_unaligned_le32(message + 12);
-
-		sums[0] += (u64)(u32)(m0 + key[ 0]) * (u32)(m2 + key[ 2]);
-		sums[1] += (u64)(u32)(m0 + key[ 4]) * (u32)(m2 + key[ 6]);
-		sums[2] += (u64)(u32)(m0 + key[ 8]) * (u32)(m2 + key[10]);
-		sums[3] += (u64)(u32)(m0 + key[12]) * (u32)(m2 + key[14]);
-		sums[0] += (u64)(u32)(m1 + key[ 1]) * (u32)(m3 + key[ 3]);
-		sums[1] += (u64)(u32)(m1 + key[ 5]) * (u32)(m3 + key[ 7]);
-		sums[2] += (u64)(u32)(m1 + key[ 9]) * (u32)(m3 + key[11]);
-		sums[3] += (u64)(u32)(m1 + key[13]) * (u32)(m3 + key[15]);
-		key += NH_MESSAGE_UNIT / sizeof(key[0]);
-		message += NH_MESSAGE_UNIT;
-		message_len -= NH_MESSAGE_UNIT;
-	}
-
-	hash[0] = cpu_to_le64(sums[0]);
-	hash[1] = cpu_to_le64(sums[1]);
-	hash[2] = cpu_to_le64(sums[2]);
-	hash[3] = cpu_to_le64(sums[3]);
-}
-
-/* Pass the next NH hash value through Poly1305 */
-static void process_nh_hash_value(struct nhpoly1305_state *state,
-				  const struct nhpoly1305_key *key)
-{
-	BUILD_BUG_ON(NH_HASH_BYTES % POLY1305_BLOCK_SIZE != 0);
-
-	poly1305_core_blocks(&state->poly_state, &key->poly_key, state->nh_hash,
-			     NH_HASH_BYTES / POLY1305_BLOCK_SIZE, 1);
-}
-
-/*
- * Feed the next portion of the source data, as a whole number of 16-byte
- * "NH message units", through NH and Poly1305.  Each NH hash is taken over
- * 1024 bytes, except possibly the final one which is taken over a multiple of
- * 16 bytes up to 1024.  Also, in the case where data is passed in misaligned
- * chunks, we combine partial hashes; the end result is the same either way.
- */
-static void nhpoly1305_units(struct nhpoly1305_state *state,
-			     const struct nhpoly1305_key *key,
-			     const u8 *src, unsigned int srclen, nh_t nh_fn)
-{
-	do {
-		unsigned int bytes;
-
-		if (state->nh_remaining == 0) {
-			/* Starting a new NH message */
-			bytes = min_t(unsigned int, srclen, NH_MESSAGE_BYTES);
-			nh_fn(key->nh_key, src, bytes, state->nh_hash);
-			state->nh_remaining = NH_MESSAGE_BYTES - bytes;
-		} else {
-			/* Continuing a previous NH message */
-			__le64 tmp_hash[NH_NUM_PASSES];
-			unsigned int pos;
-			int i;
-
-			pos = NH_MESSAGE_BYTES - state->nh_remaining;
-			bytes = min(srclen, state->nh_remaining);
-			nh_fn(&key->nh_key[pos / 4], src, bytes, tmp_hash);
-			for (i = 0; i < NH_NUM_PASSES; i++)
-				le64_add_cpu(&state->nh_hash[i],
-					     le64_to_cpu(tmp_hash[i]));
-			state->nh_remaining -= bytes;
-		}
-		if (state->nh_remaining == 0)
-			process_nh_hash_value(state, key);
-		src += bytes;
-		srclen -= bytes;
-	} while (srclen);
-}
-
-int crypto_nhpoly1305_setkey(struct crypto_shash *tfm,
-			     const u8 *key, unsigned int keylen)
-{
-	struct nhpoly1305_key *ctx = crypto_shash_ctx(tfm);
-	int i;
-
-	if (keylen != NHPOLY1305_KEY_SIZE)
-		return -EINVAL;
-
-	poly1305_core_setkey(&ctx->poly_key, key);
-	key += POLY1305_BLOCK_SIZE;
-
-	for (i = 0; i < NH_KEY_WORDS; i++)
-		ctx->nh_key[i] = get_unaligned_le32(key + i * sizeof(u32));
-
-	return 0;
-}
-EXPORT_SYMBOL(crypto_nhpoly1305_setkey);
-
-int crypto_nhpoly1305_init(struct shash_desc *desc)
-{
-	struct nhpoly1305_state *state = shash_desc_ctx(desc);
-
-	poly1305_core_init(&state->poly_state);
-	state->buflen = 0;
-	state->nh_remaining = 0;
-	return 0;
-}
-EXPORT_SYMBOL(crypto_nhpoly1305_init);
-
-int crypto_nhpoly1305_update_helper(struct shash_desc *desc,
-				    const u8 *src, unsigned int srclen,
-				    nh_t nh_fn)
-{
-	struct nhpoly1305_state *state = shash_desc_ctx(desc);
-	const struct nhpoly1305_key *key = crypto_shash_ctx(desc->tfm);
-	unsigned int bytes;
-
-	if (state->buflen) {
-		bytes = min(srclen, (int)NH_MESSAGE_UNIT - state->buflen);
-		memcpy(&state->buffer[state->buflen], src, bytes);
-		state->buflen += bytes;
-		if (state->buflen < NH_MESSAGE_UNIT)
-			return 0;
-		nhpoly1305_units(state, key, state->buffer, NH_MESSAGE_UNIT,
-				 nh_fn);
-		state->buflen = 0;
-		src += bytes;
-		srclen -= bytes;
-	}
-
-	if (srclen >= NH_MESSAGE_UNIT) {
-		bytes = round_down(srclen, NH_MESSAGE_UNIT);
-		nhpoly1305_units(state, key, src, bytes, nh_fn);
-		src += bytes;
-		srclen -= bytes;
-	}
-
-	if (srclen) {
-		memcpy(state->buffer, src, srclen);
-		state->buflen = srclen;
-	}
-	return 0;
-}
-EXPORT_SYMBOL(crypto_nhpoly1305_update_helper);
-
-int crypto_nhpoly1305_update(struct shash_desc *desc,
-			     const u8 *src, unsigned int srclen)
-{
-	return crypto_nhpoly1305_update_helper(desc, src, srclen, nh_generic);
-}
-EXPORT_SYMBOL(crypto_nhpoly1305_update);
-
-int crypto_nhpoly1305_final_helper(struct shash_desc *desc, u8 *dst, nh_t nh_fn)
-{
-	struct nhpoly1305_state *state = shash_desc_ctx(desc);
-	const struct nhpoly1305_key *key = crypto_shash_ctx(desc->tfm);
-
-	if (state->buflen) {
-		memset(&state->buffer[state->buflen], 0,
-		       NH_MESSAGE_UNIT - state->buflen);
-		nhpoly1305_units(state, key, state->buffer, NH_MESSAGE_UNIT,
-				 nh_fn);
-	}
-
-	if (state->nh_remaining)
-		process_nh_hash_value(state, key);
-
-	poly1305_core_emit(&state->poly_state, NULL, dst);
-	return 0;
-}
-EXPORT_SYMBOL(crypto_nhpoly1305_final_helper);
-
-int crypto_nhpoly1305_final(struct shash_desc *desc, u8 *dst)
-{
-	return crypto_nhpoly1305_final_helper(desc, dst, nh_generic);
-}
-EXPORT_SYMBOL(crypto_nhpoly1305_final);
-
-static struct shash_alg nhpoly1305_alg = {
-	.base.cra_name		= "nhpoly1305",
-	.base.cra_driver_name	= "nhpoly1305-generic",
-	.base.cra_priority	= 100,
-	.base.cra_ctxsize	= sizeof(struct nhpoly1305_key),
-	.base.cra_module	= THIS_MODULE,
-	.digestsize		= POLY1305_DIGEST_SIZE,
-	.init			= crypto_nhpoly1305_init,
-	.update			= crypto_nhpoly1305_update,
-	.final			= crypto_nhpoly1305_final,
-	.setkey			= crypto_nhpoly1305_setkey,
-	.descsize		= sizeof(struct nhpoly1305_state),
-};
-
-static int __init nhpoly1305_mod_init(void)
-{
-	return crypto_register_shash(&nhpoly1305_alg);
-}
-
-static void __exit nhpoly1305_mod_exit(void)
-{
-	crypto_unregister_shash(&nhpoly1305_alg);
-}
-
-module_init(nhpoly1305_mod_init);
-module_exit(nhpoly1305_mod_exit);
-
-MODULE_DESCRIPTION("NHPoly1305 ?-almost-?-universal hash function");
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Eric Biggers <ebiggers at google.com>");
-MODULE_ALIAS_CRYPTO("nhpoly1305");
-MODULE_ALIAS_CRYPTO("nhpoly1305-generic");
diff --git a/include/crypto/nhpoly1305.h b/include/crypto/nhpoly1305.h
deleted file mode 100644
index 306925fea190..000000000000
--- a/include/crypto/nhpoly1305.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Common values and helper functions for the NHPoly1305 hash function.
- */
-
-#ifndef _NHPOLY1305_H
-#define _NHPOLY1305_H
-
-#include <crypto/hash.h>
-#include <crypto/internal/poly1305.h>
-
-/* NH parameterization: */
-
-/* Endianness: little */
-/* Word size: 32 bits (works well on NEON, SSE2, AVX2) */
-
-/* Stride: 2 words (optimal on ARM32 NEON; works okay on other CPUs too) */
-#define NH_PAIR_STRIDE		2
-#define NH_MESSAGE_UNIT		(NH_PAIR_STRIDE * 2 * sizeof(u32))
-
-/* Num passes (Toeplitz iteration count): 4, to give ? = 2^{-128} */
-#define NH_NUM_PASSES		4
-#define NH_HASH_BYTES		(NH_NUM_PASSES * sizeof(u64))
-
-/* Max message size: 1024 bytes (32x compression factor) */
-#define NH_NUM_STRIDES		64
-#define NH_MESSAGE_WORDS	(NH_PAIR_STRIDE * 2 * NH_NUM_STRIDES)
-#define NH_MESSAGE_BYTES	(NH_MESSAGE_WORDS * sizeof(u32))
-#define NH_KEY_WORDS		(NH_MESSAGE_WORDS + \
-				 NH_PAIR_STRIDE * 2 * (NH_NUM_PASSES - 1))
-#define NH_KEY_BYTES		(NH_KEY_WORDS * sizeof(u32))
-
-#define NHPOLY1305_KEY_SIZE	(POLY1305_BLOCK_SIZE + NH_KEY_BYTES)
-
-struct nhpoly1305_key {
-	struct poly1305_core_key poly_key;
-	u32 nh_key[NH_KEY_WORDS];
-};
-
-struct nhpoly1305_state {
-
-	/* Running total of polynomial evaluation */
-	struct poly1305_state poly_state;
-
-	/* Partial block buffer */
-	u8 buffer[NH_MESSAGE_UNIT];
-	unsigned int buflen;
-
-	/*
-	 * Number of bytes remaining until the current NH message reaches
-	 * NH_MESSAGE_BYTES.  When nonzero, 'nh_hash' holds the partial NH hash.
-	 */
-	unsigned int nh_remaining;
-
-	__le64 nh_hash[NH_NUM_PASSES];
-};
-
-typedef void (*nh_t)(const u32 *key, const u8 *message, size_t message_len,
-		     __le64 hash[NH_NUM_PASSES]);
-
-int crypto_nhpoly1305_setkey(struct crypto_shash *tfm,
-			     const u8 *key, unsigned int keylen);
-
-int crypto_nhpoly1305_init(struct shash_desc *desc);
-int crypto_nhpoly1305_update(struct shash_desc *desc,
-			     const u8 *src, unsigned int srclen);
-int crypto_nhpoly1305_update_helper(struct shash_desc *desc,
-				    const u8 *src, unsigned int srclen,
-				    nh_t nh_fn);
-int crypto_nhpoly1305_final(struct shash_desc *desc, u8 *dst);
-int crypto_nhpoly1305_final_helper(struct shash_desc *desc, u8 *dst,
-				   nh_t nh_fn);
-
-#endif /* _NHPOLY1305_H */
-- 
2.52.0



From ebiggers at kernel.org  Wed Dec 10 17:18:43 2025
From: ebiggers at kernel.org (Eric Biggers)
Date: Wed, 10 Dec 2025 17:18:43 -0800
Subject: [PATCH 11/12] crypto: testmgr - Remove nhpoly1305 tests
In-Reply-To: <20251211011846.8179-1-ebiggers@kernel.org>
References: <20251211011846.8179-1-ebiggers@kernel.org>
Message-ID: <20251211011846.8179-12-ebiggers@kernel.org>

These are no longer used, since nhpoly1305 support has been removed from
the crypto_shash API.

Signed-off-by: Eric Biggers <ebiggers at kernel.org>
---
 crypto/testmgr.c |    6 -
 crypto/testmgr.h | 1372 ----------------------------------------------
 2 files changed, 1378 deletions(-)

diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index d9fc671d5941..5df204d9c9dd 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -5170,16 +5170,10 @@ static const struct alg_test_desc alg_test_descs[] = {
 		.alg = "michael_mic",
 		.test = alg_test_hash,
 		.suite = {
 			.hash = __VECS(michael_mic_tv_template)
 		}
-	}, {
-		.alg = "nhpoly1305",
-		.test = alg_test_hash,
-		.suite = {
-			.hash = __VECS(nhpoly1305_tv_template)
-		}
 	}, {
 		.alg = "p1363(ecdsa-nist-p192)",
 		.test = alg_test_null,
 	}, {
 		.alg = "p1363(ecdsa-nist-p256)",
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index 80bf5f1b67a6..1a3329e1c325 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -7597,1382 +7597,10 @@ static const struct hash_testvec hmac_sha3_512_tv_template[] = {
 			  "\xd1\xb9\x78\x9f\x97\xae\x5b\x83"
 			  "\xc6\xf4\x4d\xfc\xf1\xd6\x7e\xba",
 	},
 };
 
-/* NHPoly1305 test vectors from https://github.com/google/adiantum */
-static const struct hash_testvec nhpoly1305_tv_template[] = {
-	{
-		.key	= "\xd2\x5d\x4c\xdd\x8d\x2b\x7f\x7a"
-			  "\xd9\xbe\x71\xec\xd1\x83\x52\xe3"
-			  "\xe1\xad\xd7\x5c\x0a\x75\x9d\xec"
-			  "\x1d\x13\x7e\x5d\x71\x07\xc9\xe4"
-			  "\x57\x2d\x44\x68\xcf\xd8\xd6\xc5"
-			  "\x39\x69\x7d\x32\x75\x51\x4f\x7e"
-			  "\xb2\x4c\xc6\x90\x51\x6e\xd9\xd6"
-			  "\xa5\x8b\x2d\xf1\x94\xf9\xf7\x5e"
-			  "\x2c\x84\x7b\x41\x0f\x88\x50\x89"
-			  "\x30\xd9\xa1\x38\x46\x6c\xc0\x4f"
-			  "\xe8\xdf\xdc\x66\xab\x24\x43\x41"
-			  "\x91\x55\x29\x65\x86\x28\x5e\x45"
-			  "\xd5\x2d\xb7\x80\x08\x9a\xc3\xd4"
-			  "\x9a\x77\x0a\xd4\xef\x3e\xe6\x3f"
-			  "\x6f\x2f\x9b\x3a\x7d\x12\x1e\x80"
-			  "\x6c\x44\xa2\x25\xe1\xf6\x60\xe9"
-			  "\x0d\xaf\xc5\x3c\xa5\x79\xae\x64"
-			  "\xbc\xa0\x39\xa3\x4d\x10\xe5\x4d"
-			  "\xd5\xe7\x89\x7a\x13\xee\x06\x78"
-			  "\xdc\xa4\xdc\x14\x27\xe6\x49\x38"
-			  "\xd0\xe0\x45\x25\x36\xc5\xf4\x79"
-			  "\x2e\x9a\x98\x04\xe4\x2b\x46\x52"
-			  "\x7c\x33\xca\xe2\x56\x51\x50\xe2"
-			  "\xa5\x9a\xae\x18\x6a\x13\xf8\xd2"
-			  "\x21\x31\x66\x02\xe2\xda\x8d\x7e"
-			  "\x41\x19\xb2\x61\xee\x48\x8f\xf1"
-			  "\x65\x24\x2e\x1e\x68\xce\x05\xd9"
-			  "\x2a\xcf\xa5\x3a\x57\xdd\x35\x91"
-			  "\x93\x01\xca\x95\xfc\x2b\x36\x04"
-			  "\xe6\x96\x97\x28\xf6\x31\xfe\xa3"
-			  "\x9d\xf6\x6a\x1e\x80\x8d\xdc\xec"
-			  "\xaf\x66\x11\x13\x02\x88\xd5\x27"
-			  "\x33\xb4\x1a\xcd\xa3\xf6\xde\x31"
-			  "\x8e\xc0\x0e\x6c\xd8\x5a\x97\x5e"
-			  "\xdd\xfd\x60\x69\x38\x46\x3f\x90"
-			  "\x5e\x97\xd3\x32\x76\xc7\x82\x49"
-			  "\xfe\xba\x06\x5f\x2f\xa2\xfd\xff"
-			  "\x80\x05\x40\xe4\x33\x03\xfb\x10"
-			  "\xc0\xde\x65\x8c\xc9\x8d\x3a\x9d"
-			  "\xb5\x7b\x36\x4b\xb5\x0c\xcf\x00"
-			  "\x9c\x87\xe4\x49\xad\x90\xda\x4a"
-			  "\xdd\xbd\xff\xe2\x32\x57\xd6\x78"
-			  "\x36\x39\x6c\xd3\x5b\x9b\x88\x59"
-			  "\x2d\xf0\x46\xe4\x13\x0e\x2b\x35"
-			  "\x0d\x0f\x73\x8a\x4f\x26\x84\x75"
-			  "\x88\x3c\xc5\x58\x66\x18\x1a\xb4"
-			  "\x64\x51\x34\x27\x1b\xa4\x11\xc9"
-			  "\x6d\x91\x8a\xfa\x32\x60\x9d\xd7"
-			  "\x87\xe5\xaa\x43\x72\xf8\xda\xd1"
-			  "\x48\x44\x13\x61\xdc\x8c\x76\x17"
-			  "\x0c\x85\x4e\xf3\xdd\xa2\x42\xd2"
-			  "\x74\xc1\x30\x1b\xeb\x35\x31\x29"
-			  "\x5b\xd7\x4c\x94\x46\x35\xa1\x23"
-			  "\x50\xf2\xa2\x8e\x7e\x4f\x23\x4f"
-			  "\x51\xff\xe2\xc9\xa3\x7d\x56\x8b"
-			  "\x41\xf2\xd0\xc5\x57\x7e\x59\xac"
-			  "\xbb\x65\xf3\xfe\xf7\x17\xef\x63"
-			  "\x7c\x6f\x23\xdd\x22\x8e\xed\x84"
-			  "\x0e\x3b\x09\xb3\xf3\xf4\x8f\xcd"
-			  "\x37\xa8\xe1\xa7\x30\xdb\xb1\xa2"
-			  "\x9c\xa2\xdf\x34\x17\x3e\x68\x44"
-			  "\xd0\xde\x03\x50\xd1\x48\x6b\x20"
-			  "\xe2\x63\x45\xa5\xea\x87\xc2\x42"
-			  "\x95\x03\x49\x05\xed\xe0\x90\x29"
-			  "\x1a\xb8\xcf\x9b\x43\xcf\x29\x7a"
-			  "\x63\x17\x41\x9f\xe0\xc9\x10\xfd"
-			  "\x2c\x56\x8c\x08\x55\xb4\xa9\x27"
-			  "\x0f\x23\xb1\x05\x6a\x12\x46\xc7"
-			  "\xe1\xfe\x28\x93\x93\xd7\x2f\xdc"
-			  "\x98\x30\xdb\x75\x8a\xbe\x97\x7a"
-			  "\x02\xfb\x8c\xba\xbe\x25\x09\xbe"
-			  "\xce\xcb\xa2\xef\x79\x4d\x0e\x9d"
-			  "\x1b\x9d\xb6\x39\x34\x38\xfa\x07"
-			  "\xec\xe8\xfc\x32\x85\x1d\xf7\x85"
-			  "\x63\xc3\x3c\xc0\x02\x75\xd7\x3f"
-			  "\xb2\x68\x60\x66\x65\x81\xc6\xb1"
-			  "\x42\x65\x4b\x4b\x28\xd7\xc7\xaa"
-			  "\x9b\xd2\xdc\x1b\x01\xe0\x26\x39"
-			  "\x01\xc1\x52\x14\xd1\x3f\xb7\xe6"
-			  "\x61\x41\xc7\x93\xd2\xa2\x67\xc6"
-			  "\xf7\x11\xb5\xf5\xea\xdd\x19\xfb"
-			  "\x4d\x21\x12\xd6\x7d\xf1\x10\xb0"
-			  "\x89\x07\xc7\x5a\x52\x73\x70\x2f"
-			  "\x32\xef\x65\x2b\x12\xb2\xf0\xf5"
-			  "\x20\xe0\x90\x59\x7e\x64\xf1\x4c"
-			  "\x41\xb3\xa5\x91\x08\xe6\x5e\x5f"
-			  "\x05\x56\x76\xb4\xb0\xcd\x70\x53"
-			  "\x10\x48\x9c\xff\xc2\x69\x55\x24"
-			  "\x87\xef\x84\xea\xfb\xa7\xbf\xa0"
-			  "\x91\x04\xad\x4f\x8b\x57\x54\x4b"
-			  "\xb6\xe9\xd1\xac\x37\x2f\x1d\x2e"
-			  "\xab\xa5\xa4\xe8\xff\xfb\xd9\x39"
-			  "\x2f\xb7\xac\xd1\xfe\x0b\x9a\x80"
-			  "\x0f\xb6\xf4\x36\x39\x90\x51\xe3"
-			  "\x0a\x2f\xb6\x45\x76\x89\xcd\x61"
-			  "\xfe\x48\x5f\x75\x1d\x13\x00\x62"
-			  "\x80\x24\x47\xe7\xbc\x37\xd7\xe3"
-			  "\x15\xe8\x68\x22\xaf\x80\x6f\x4b"
-			  "\xa8\x9f\x01\x10\x48\x14\xc3\x02"
-			  "\x52\xd2\xc7\x75\x9b\x52\x6d\x30"
-			  "\xac\x13\x85\xc8\xf7\xa3\x58\x4b"
-			  "\x49\xf7\x1c\x45\x55\x8c\x39\x9a"
-			  "\x99\x6d\x97\x27\x27\xe6\xab\xdd"
-			  "\x2c\x42\x1b\x35\xdd\x9d\x73\xbb"
-			  "\x6c\xf3\x64\xf1\xfb\xb9\xf7\xe6"
-			  "\x4a\x3c\xc0\x92\xc0\x2e\xb7\x1a"
-			  "\xbe\xab\xb3\x5a\xe5\xea\xb1\x48"
-			  "\x58\x13\x53\x90\xfd\xc3\x8e\x54"
-			  "\xf9\x18\x16\x73\xe8\xcb\x6d\x39"
-			  "\x0e\xd7\xe0\xfe\xb6\x9f\x43\x97"
-			  "\xe8\xd0\x85\x56\x83\x3e\x98\x68"
-			  "\x7f\xbd\x95\xa8\x9a\x61\x21\x8f"
-			  "\x06\x98\x34\xa6\xc8\xd6\x1d\xf3"
-			  "\x3d\x43\xa4\x9a\x8c\xe5\xd3\x5a"
-			  "\x32\xa2\x04\x22\xa4\x19\x1a\x46"
-			  "\x42\x7e\x4d\xe5\xe0\xe6\x0e\xca"
-			  "\xd5\x58\x9d\x2c\xaf\xda\x33\x5c"
-			  "\xb0\x79\x9e\xc9\xfc\xca\xf0\x2f"
-			  "\xa8\xb2\x77\xeb\x7a\xa2\xdd\x37"
-			  "\x35\x83\x07\xd6\x02\x1a\xb6\x6c"
-			  "\x24\xe2\x59\x08\x0e\xfd\x3e\x46"
-			  "\xec\x40\x93\xf4\x00\x26\x4f\x2a"
-			  "\xff\x47\x2f\xeb\x02\x92\x26\x5b"
-			  "\x53\x17\xc2\x8d\x2a\xc7\xa3\x1b"
-			  "\xcd\xbc\xa7\xe8\xd1\x76\xe3\x80"
-			  "\x21\xca\x5d\x3b\xe4\x9c\x8f\xa9"
-			  "\x5b\x7f\x29\x7f\x7c\xd8\xed\x6d"
-			  "\x8c\xb2\x86\x85\xe7\x77\xf2\x85"
-			  "\xab\x38\xa9\x9d\xc1\x4e\xc5\x64"
-			  "\x33\x73\x8b\x59\x03\xad\x05\xdf"
-			  "\x25\x98\x31\xde\xef\x13\xf1\x9b"
-			  "\x3c\x91\x9d\x7b\xb1\xfa\xe6\xbf"
-			  "\x5b\xed\xa5\x55\xe6\xea\x6c\x74"
-			  "\xf4\xb9\xe4\x45\x64\x72\x81\xc2"
-			  "\x4c\x28\xd4\xcd\xac\xe2\xde\xf9"
-			  "\xeb\x5c\xeb\x61\x60\x5a\xe5\x28",
-		.ksize	= 1088,
-		.plaintext	= "",
-		.psize	= 0,
-		.digest	= "\x00\x00\x00\x00\x00\x00\x00\x00"
-			  "\x00\x00\x00\x00\x00\x00\x00\x00",
-	}, {
-		.key	= "\x29\x21\x43\xcb\xcb\x13\x07\xde"
-			  "\xbf\x48\xdf\x8a\x7f\xa2\x84\xde"
-			  "\x72\x23\x9d\xf5\xf0\x07\xf2\x4c"
-			  "\x20\x3a\x93\xb9\xcd\x5d\xfe\xcb"
-			  "\x99\x2c\x2b\x58\xc6\x50\x5f\x94"
-			  "\x56\xc3\x7c\x0d\x02\x3f\xb8\x5e"
-			  "\x7b\xc0\x6c\x51\x34\x76\xc0\x0e"
-			  "\xc6\x22\xc8\x9e\x92\xa0\x21\xc9"
-			  "\x85\x5c\x7c\xf8\xe2\x64\x47\xc9"
-			  "\xe4\xa2\x57\x93\xf8\xa2\x69\xcd"
-			  "\x62\x98\x99\xf4\xd7\x7b\x14\xb1"
-			  "\xd8\x05\xff\x04\x15\xc9\xe1\x6e"
-			  "\x9b\xe6\x50\x6b\x0b\x3f\x22\x1f"
-			  "\x08\xde\x0c\x5b\x08\x7e\xc6\x2f"
-			  "\x6c\xed\xd6\xb2\x15\xa4\xb3\xf9"
-			  "\xa7\x46\x38\x2a\xea\x69\xa5\xde"
-			  "\x02\xc3\x96\x89\x4d\x55\x3b\xed"
-			  "\x3d\x3a\x85\x77\xbf\x97\x45\x5c"
-			  "\x9e\x02\x69\xe2\x1b\x68\xbe\x96"
-			  "\xfb\x64\x6f\x0f\xf6\x06\x40\x67"
-			  "\xfa\x04\xe3\x55\xfa\xbe\xa4\x60"
-			  "\xef\x21\x66\x97\xe6\x9d\x5c\x1f"
-			  "\x62\x37\xaa\x31\xde\xe4\x9c\x28"
-			  "\x95\xe0\x22\x86\xf4\x4d\xf3\x07"
-			  "\xfd\x5f\x3a\x54\x2c\x51\x80\x71"
-			  "\xba\x78\x69\x5b\x65\xab\x1f\x81"
-			  "\xed\x3b\xff\x34\xa3\xfb\xbc\x73"
-			  "\x66\x7d\x13\x7f\xdf\x6e\xe2\xe2"
-			  "\xeb\x4f\x6c\xda\x7d\x33\x57\xd0"
-			  "\xd3\x7c\x95\x4f\x33\x58\x21\xc7"
-			  "\xc0\xe5\x6f\x42\x26\xc6\x1f\x5e"
-			  "\x85\x1b\x98\x9a\xa2\x1e\x55\x77"
-			  "\x23\xdf\x81\x5e\x79\x55\x05\xfc"
-			  "\xfb\xda\xee\xba\x5a\xba\xf7\x77"
-			  "\x7f\x0e\xd3\xe1\x37\xfe\x8d\x2b"
-			  "\xd5\x3f\xfb\xd0\xc0\x3c\x0b\x3f"
-			  "\xcf\x3c\x14\xcf\xfb\x46\x72\x4c"
-			  "\x1f\x39\xe2\xda\x03\x71\x6d\x23"
-			  "\xef\x93\xcd\x39\xd9\x37\x80\x4d"
-			  "\x65\x61\xd1\x2c\x03\xa9\x47\x72"
-			  "\x4d\x1e\x0e\x16\x33\x0f\x21\x17"
-			  "\xec\x92\xea\x6f\x37\x22\xa4\xd8"
-			  "\x03\x33\x9e\xd8\x03\x69\x9a\xe8"
-			  "\xb2\x57\xaf\x78\x99\x05\x12\xab"
-			  "\x48\x90\x80\xf0\x12\x9b\x20\x64"
-			  "\x7a\x1d\x47\x5f\xba\x3c\xf9\xc3"
-			  "\x0a\x0d\x8d\xa1\xf9\x1b\x82\x13"
-			  "\x3e\x0d\xec\x0a\x83\xc0\x65\xe1"
-			  "\xe9\x95\xff\x97\xd6\xf2\xe4\xd5"
-			  "\x86\xc0\x1f\x29\x27\x63\xd7\xde"
-			  "\xb7\x0a\x07\x99\x04\x2d\xa3\x89"
-			  "\xa2\x43\xcf\xf3\xe1\x43\xac\x4a"
-			  "\x06\x97\xd0\x05\x4f\x87\xfa\xf9"
-			  "\x9b\xbf\x52\x70\xbd\xbc\x6c\xf3"
-			  "\x03\x13\x60\x41\x28\x09\xec\xcc"
-			  "\xb1\x1a\xec\xd6\xfb\x6f\x2a\x89"
-			  "\x5d\x0b\x53\x9c\x59\xc1\x84\x21"
-			  "\x33\x51\x47\x19\x31\x9c\xd4\x0a"
-			  "\x4d\x04\xec\x50\x90\x61\xbd\xbc"
-			  "\x7e\xc8\xd9\x6c\x98\x1d\x45\x41"
-			  "\x17\x5e\x97\x1c\xc5\xa8\xe8\xea"
-			  "\x46\x58\x53\xf7\x17\xd5\xad\x11"
-			  "\xc8\x54\xf5\x7a\x33\x90\xf5\x19"
-			  "\xba\x36\xb4\xfc\x52\xa5\x72\x3d"
-			  "\x14\xbb\x55\xa7\xe9\xe3\x12\xf7"
-			  "\x1c\x30\xa2\x82\x03\xbf\x53\x91"
-			  "\x2e\x60\x41\x9f\x5b\x69\x39\xf6"
-			  "\x4d\xc8\xf8\x46\x7a\x7f\xa4\x98"
-			  "\x36\xff\x06\xcb\xca\xe7\x33\xf2"
-			  "\xc0\x4a\xf4\x3c\x14\x44\x5f\x6b"
-			  "\x75\xef\x02\x36\x75\x08\x14\xfd"
-			  "\x10\x8e\xa5\x58\xd0\x30\x46\x49"
-			  "\xaf\x3a\xf8\x40\x3d\x35\xdb\x84"
-			  "\x11\x2e\x97\x6a\xb7\x87\x7f\xad"
-			  "\xf1\xfa\xa5\x63\x60\xd8\x5e\xbf"
-			  "\x41\x78\x49\xcf\x77\xbb\x56\xbb"
-			  "\x7d\x01\x67\x05\x22\xc8\x8f\x41"
-			  "\xba\x81\xd2\xca\x2c\x38\xac\x76"
-			  "\x06\xc1\x1a\xc2\xce\xac\x90\x67"
-			  "\x57\x3e\x20\x12\x5b\xd9\x97\x58"
-			  "\x65\x05\xb7\x04\x61\x7e\xd8\x3a"
-			  "\xbf\x55\x3b\x13\xe9\x34\x5a\x37"
-			  "\x36\xcb\x94\x45\xc5\x32\xb3\xa0"
-			  "\x0c\x3e\x49\xc5\xd3\xed\xa7\xf0"
-			  "\x1c\x69\xcc\xea\xcc\x83\xc9\x16"
-			  "\x95\x72\x4b\xf4\x89\xd5\xb9\x10"
-			  "\xf6\x2d\x60\x15\xea\x3c\x06\x66"
-			  "\x9f\x82\xad\x17\xce\xd2\xa4\x48"
-			  "\x7c\x65\xd9\xf8\x02\x4d\x9b\x4c"
-			  "\x89\x06\x3a\x34\x85\x48\x89\x86"
-			  "\xf9\x24\xa9\x54\x72\xdb\x44\x95"
-			  "\xc7\x44\x1c\x19\x11\x4c\x04\xdc"
-			  "\x13\xb9\x67\xc8\xc3\x3a\x6a\x50"
-			  "\xfa\xd1\xfb\xe1\x88\xb6\xf1\xa3"
-			  "\xc5\x3b\xdc\x38\x45\x16\x26\x02"
-			  "\x3b\xb8\x8f\x8b\x58\x7d\x23\x04"
-			  "\x50\x6b\x81\x9f\xae\x66\xac\x6f"
-			  "\xcf\x2a\x9d\xf1\xfd\x1d\x57\x07"
-			  "\xbe\x58\xeb\x77\x0c\xe3\xc2\x19"
-			  "\x14\x74\x1b\x51\x1c\x4f\x41\xf3"
-			  "\x32\x89\xb3\xe7\xde\x62\xf6\x5f"
-			  "\xc7\x6a\x4a\x2a\x5b\x0f\x5f\x87"
-			  "\x9c\x08\xb9\x02\x88\xc8\x29\xb7"
-			  "\x94\x52\xfa\x52\xfe\xaa\x50\x10"
-			  "\xba\x48\x75\x5e\x11\x1b\xe6\x39"
-			  "\xd7\x82\x2c\x87\xf1\x1e\xa4\x38"
-			  "\x72\x3e\x51\xe7\xd8\x3e\x5b\x7b"
-			  "\x31\x16\x89\xba\xd6\xad\x18\x5e"
-			  "\xba\xf8\x12\xb3\xf4\x6c\x47\x30"
-			  "\xc0\x38\x58\xb3\x10\x8d\x58\x5d"
-			  "\xb4\xfb\x19\x7e\x41\xc3\x66\xb8"
-			  "\xd6\x72\x84\xe1\x1a\xc2\x71\x4c"
-			  "\x0d\x4a\x21\x7a\xab\xa2\xc0\x36"
-			  "\x15\xc5\xe9\x46\xd7\x29\x17\x76"
-			  "\x5e\x47\x36\x7f\x72\x05\xa7\xcc"
-			  "\x36\x63\xf9\x47\x7d\xe6\x07\x3c"
-			  "\x8b\x79\x1d\x96\x61\x8d\x90\x65"
-			  "\x7c\xf5\xeb\x4e\x6e\x09\x59\x6d"
-			  "\x62\x50\x1b\x0f\xe0\xdc\x78\xf2"
-			  "\x5b\x83\x1a\xa1\x11\x75\xfd\x18"
-			  "\xd7\xe2\x8d\x65\x14\x21\xce\xbe"
-			  "\xb5\x87\xe3\x0a\xda\x24\x0a\x64"
-			  "\xa9\x9f\x03\x8d\x46\x5d\x24\x1a"
-			  "\x8a\x0c\x42\x01\xca\xb1\x5f\x7c"
-			  "\xa5\xac\x32\x4a\xb8\x07\x91\x18"
-			  "\x6f\xb0\x71\x3c\xc9\xb1\xa8\xf8"
-			  "\x5f\x69\xa5\xa1\xca\x9e\x7a\xaa"
-			  "\xac\xe9\xc7\x47\x41\x75\x25\xc3"
-			  "\x73\xe2\x0b\xdd\x6d\x52\x71\xbe"
-			  "\xc5\xdc\xb4\xe7\x01\x26\x53\x77"
-			  "\x86\x90\x85\x68\x6b\x7b\x03\x53"
-			  "\xda\x52\x52\x51\x68\xc8\xf3\xec"
-			  "\x6c\xd5\x03\x7a\xa3\x0e\xb4\x02"
-			  "\x5f\x1a\xab\xee\xca\x67\x29\x7b"
-			  "\xbd\x96\x59\xb3\x8b\x32\x7a\x92"
-			  "\x9f\xd8\x25\x2b\xdf\xc0\x4c\xda",
-		.ksize	= 1088,
-		.plaintext	= "\xbc\xda\x81\xa8\x78\x79\x1c\xbf"
-			  "\x77\x53\xba\x4c\x30\x5b\xb8\x33",
-		.psize	= 16,
-		.digest	= "\x04\xbf\x7f\x6a\xce\x72\xea\x6a"
-			  "\x79\xdb\xb0\xc9\x60\xf6\x12\xcc",
-	}, {
-		.key	= "\x2e\x77\x1e\x2c\x63\x76\x34\x3f"
-			  "\x71\x08\x4f\x5a\xe3\x3d\x74\x56"
-			  "\xc7\x98\x46\x52\xe5\x8a\xba\x0d"
-			  "\x72\x41\x11\x15\x14\x72\x50\x8a"
-			  "\xd5\xec\x60\x09\xdd\x71\xcc\xb9"
-			  "\x59\x81\x65\x2d\x9e\x50\x18\xf3"
-			  "\x32\xf3\xf1\xe7\x01\x82\x1c\xad"
-			  "\x88\xa0\x21\x0c\x4b\x80\x5e\x62"
-			  "\xfc\x81\xec\x52\xaa\xe4\xa5\x86"
-			  "\xc2\xe6\x03\x11\xdc\x66\x09\x86"
-			  "\x3c\x3b\xf0\x59\x0f\xb3\xf7\x44"
-			  "\x24\xb7\x88\xc5\xfc\xc8\x77\x9f"
-			  "\x8c\x44\xc4\x11\x55\xce\x7a\xa3"
-			  "\xe0\xa2\xb8\xbf\xb5\x3d\x07\x2c"
-			  "\x32\xb6\x6c\xfc\xb4\x42\x95\x95"
-			  "\x98\x32\x81\xc4\xe7\xe2\xd9\x6a"
-			  "\x87\xf4\xf4\x1e\x74\x7c\xb5\xcd"
-			  "\x51\x45\x68\x38\x51\xdb\x30\x74"
-			  "\x11\xe0\xaa\xae\x19\x8f\x15\x55"
-			  "\xdd\x47\x4a\x35\xb9\x0c\xb4\x4e"
-			  "\xa9\xce\x2f\xfa\x8f\xc1\x8a\x5e"
-			  "\x5b\xec\xa5\x81\x3b\xb3\x43\x06"
-			  "\x24\x81\xf4\x24\xe2\x21\xfa\xcb"
-			  "\x49\xa8\xf8\xbd\x31\x4a\x5b\x2d"
-			  "\x64\x0a\x07\xf0\x80\xc9\x0d\x81"
-			  "\x14\x58\x54\x2b\xba\x22\x31\xba"
-			  "\xef\x66\xc9\x49\x69\x69\x83\x0d"
-			  "\xf2\xf9\x80\x9d\x30\x36\xfb\xe3"
-			  "\xc0\x72\x2b\xcc\x5a\x81\x2c\x5d"
-			  "\x3b\x5e\xf8\x2b\xd3\x14\x28\x73"
-			  "\xf9\x1c\x70\xe6\xd8\xbb\xac\x30"
-			  "\xf9\xd9\xa0\xe2\x33\x7c\x33\x34"
-			  "\xa5\x6a\x77\x6d\xd5\xaf\xf4\xf3"
-			  "\xc7\xb3\x0e\x83\x3d\xcb\x01\xcc"
-			  "\x81\xc0\xf9\x4a\xae\x36\x92\xf7"
-			  "\x69\x7b\x65\x01\xc3\xc8\xb8\xae"
-			  "\x16\xd8\x30\xbb\xba\x6d\x78\x6e"
-			  "\x0d\xf0\x7d\x84\xb7\x87\xda\x28"
-			  "\x7a\x18\x10\x0b\x29\xec\x29\xf3"
-			  "\xb0\x7b\xa1\x28\xbf\xbc\x2b\x2c"
-			  "\x92\x2c\x16\xfb\x02\x39\xf9\xa6"
-			  "\xa2\x15\x05\xa6\x72\x10\xbc\x62"
-			  "\x4a\x6e\xb8\xb5\x5d\x59\xae\x3c"
-			  "\x32\xd3\x68\xd7\x8e\x5a\xcd\x1b"
-			  "\xef\xf6\xa7\x5e\x10\x51\x15\x4b"
-			  "\x2c\xe3\xba\x70\x4f\x2c\xa0\x1c"
-			  "\x7b\x97\xd7\xb2\xa5\x05\x17\xcc"
-			  "\xf7\x3a\x29\x6f\xd5\x4b\xb8\x24"
-			  "\xf4\x65\x95\x12\xc0\x86\xd1\x64"
-			  "\x81\xdf\x46\x55\x0d\x22\x06\x77"
-			  "\xd8\xca\x8d\xc8\x87\xc3\xfa\xb9"
-			  "\xe1\x98\x94\xe6\x7b\xed\x65\x66"
-			  "\x0e\xc7\x25\x15\xee\x4a\xe6\x7e"
-			  "\xea\x1b\x58\xee\x96\xa0\x75\x9a"
-			  "\xa3\x00\x9e\x42\xc2\x26\x20\x8c"
-			  "\x3d\x22\x1f\x94\x3e\x74\x43\x72"
-			  "\xe9\x1d\xa6\xa1\x6c\xa7\xb8\x03"
-			  "\xdf\xb9\x7a\xaf\xe9\xe9\x3b\xfe"
-			  "\xdf\x91\xc1\x01\xa8\xba\x5d\x29"
-			  "\xa5\xe0\x98\x9b\x13\xe5\x13\x11"
-			  "\x7c\x04\x3a\xe8\x44\x7e\x78\xfc"
-			  "\xd6\x96\xa8\xbc\x7d\xc1\x89\x3d"
-			  "\x75\x64\xa9\x0e\x86\x33\xfb\x73"
-			  "\xf7\x15\xbc\x2c\x9a\x3f\x29\xce"
-			  "\x1c\x9d\x10\x4e\x85\xe1\x77\x41"
-			  "\x01\xe2\xbc\x88\xec\x81\xef\xc2"
-			  "\x6a\xed\x4f\xf7\xdf\xac\x10\x71"
-			  "\x94\xed\x71\xa4\x01\xd4\xd6\xbe"
-			  "\xfe\x3e\xc3\x92\x6a\xf2\x2b\xb5"
-			  "\xab\x15\x96\xb7\x88\x2c\xc2\xe1"
-			  "\xb0\x04\x22\xe7\x3d\xa9\xc9\x7d"
-			  "\x2c\x7c\x21\xff\x97\x86\x6b\x0c"
-			  "\x2b\x5b\xe0\xb6\x48\x74\x8f\x24"
-			  "\xef\x8e\xdd\x0f\x2a\x5f\xff\x33"
-			  "\xf4\x8e\xc5\xeb\x9c\xd7\x2a\x45"
-			  "\xf3\x50\xf1\xc0\x91\x8f\xc7\xf9"
-			  "\x97\xc1\x3c\x9c\xf4\xed\x8a\x23"
-			  "\x61\x5b\x40\x1a\x09\xee\x23\xa8"
-			  "\x7c\x7a\x96\xe1\x31\x55\x3d\x12"
-			  "\x04\x1f\x21\x78\x72\xf0\x0f\xa5"
-			  "\x80\x58\x7c\x2f\x37\xb5\x67\x24"
-			  "\x2f\xce\xf9\xf6\x86\x9f\xb3\x34"
-			  "\x0c\xfe\x0a\xaf\x27\xe6\x5e\x0a"
-			  "\x21\x44\x68\xe1\x5d\x84\x25\xae"
-			  "\x2c\x5a\x94\x66\x9a\x3f\x0e\x5a"
-			  "\xd0\x60\x2a\xd5\x3a\x4e\x2f\x40"
-			  "\x87\xe9\x27\x3e\xee\x92\xe1\x07"
-			  "\x22\x43\x52\xed\x67\x49\x13\xdd"
-			  "\x68\xd7\x54\xc2\x76\x72\x7e\x75"
-			  "\xaf\x24\x98\x5c\xe8\x22\xaa\x35"
-			  "\x0f\x9a\x1c\x4c\x0b\x43\x68\x99"
-			  "\x45\xdd\xbf\x82\xa5\x6f\x0a\xef"
-			  "\x44\x90\x85\xe7\x57\x23\x22\x41"
-			  "\x2e\xda\x24\x28\x65\x7f\x96\x85"
-			  "\x9f\x4b\x0d\x43\xb9\xa8\xbd\x84"
-			  "\xad\x0b\x09\xcc\x2c\x4a\x0c\xec"
-			  "\x71\x58\xba\xf1\xfc\x49\x4c\xca"
-			  "\x5c\x5d\xb2\x77\x0c\x99\xae\x1c"
-			  "\xce\x70\x05\x5b\x73\x6b\x7c\x28"
-			  "\x3b\xeb\x21\x3f\xa3\x71\xe1\x6a"
-			  "\xf4\x87\xd0\xbf\x73\xaa\x0b\x0b"
-			  "\xed\x70\xb3\xd4\xa3\xca\x76\x3a"
-			  "\xdb\xfa\xd8\x08\x95\xec\xac\x59"
-			  "\xd0\x79\x90\xc2\x33\x7b\xcc\x28"
-			  "\x65\xb6\x5f\x92\xc4\xac\x23\x40"
-			  "\xd1\x20\x44\x1f\xd7\x29\xab\x46"
-			  "\x79\x32\xc6\x8f\x79\xe5\xaa\x2c"
-			  "\xa6\x76\x70\x3a\x9e\x46\x3f\x8c"
-			  "\x1a\x89\x32\x28\x61\x5c\xcf\x93"
-			  "\x1e\xde\x9e\x98\xbe\x06\x30\x23"
-			  "\xc4\x8b\xda\x1c\xd1\x67\x46\x93"
-			  "\x9d\x41\xa2\x8c\x03\x22\xbd\x55"
-			  "\x7e\x91\x51\x13\xdc\xcf\x5c\x1e"
-			  "\xcb\x5d\xfb\x14\x16\x1a\x44\x56"
-			  "\x27\x77\xfd\xed\x7d\xbd\xd1\x49"
-			  "\x7f\x0d\xc3\x59\x48\x6b\x3c\x02"
-			  "\x6b\xb5\xd0\x83\xd5\x81\x29\xe7"
-			  "\xe0\xc9\x36\x23\x8d\x41\x33\x77"
-			  "\xff\x5f\x54\xde\x4d\x3f\xd2\x4e"
-			  "\xb6\x4d\xdd\x85\xf8\x9b\x20\x7d"
-			  "\x39\x27\x68\x63\xd3\x8e\x61\x39"
-			  "\xfa\xe1\xc3\x04\x74\x27\x5a\x34"
-			  "\x7f\xec\x59\x2d\xc5\x6e\x54\x23"
-			  "\xf5\x7b\x4b\xbe\x58\x2b\xf2\x81"
-			  "\x93\x63\xcc\x13\xd9\x90\xbb\x6a"
-			  "\x41\x03\x8d\x95\xeb\xbb\x5d\x06"
-			  "\x38\x4c\x0e\xd6\xa9\x5b\x84\x97"
-			  "\x3e\x64\x72\xe9\x96\x07\x0f\x73"
-			  "\x6e\xc6\x3b\x32\xbe\xac\x13\x14"
-			  "\xd0\x0a\x17\x5f\xb9\x9c\x3e\x34"
-			  "\xd9\xec\xd6\x8f\x89\xbf\x1e\xd3"
-			  "\xda\x80\xb2\x29\xff\x28\x96\xb3"
-			  "\x46\x50\x5b\x15\x80\x97\xee\x1f"
-			  "\x6c\xd8\xe8\xe0\xbd\x09\xe7\x20"
-			  "\x8c\x23\x8e\xd9\xbb\x92\xfa\x82"
-			  "\xaa\x0f\xb5\xf8\x78\x60\x11\xf0",
-		.ksize	= 1088,
-		.plaintext	= "\x0b\xb2\x31\x2d\xad\xfe\xce\xf9"
-			  "\xec\x5d\x3d\x64\x5f\x3f\x75\x43"
-			  "\x05\x5b\x97",
-		.psize	= 19,
-		.digest	= "\x5f\x02\xae\x65\x6c\x13\x21\x67"
-			  "\x77\x9e\xc4\x43\x58\x68\xde\x8f",
-	}, {
-		.key	= "\x65\x4d\xe3\xf8\xd2\x4c\xac\x28"
-			  "\x68\xf5\xb3\x81\x71\x4b\xa1\xfa"
-			  "\x04\x0e\xd3\x81\x36\xbe\x0c\x81"
-			  "\x5e\xaf\xbc\x3a\xa4\xc0\x8e\x8b"
-			  "\x55\x63\xd3\x52\x97\x88\xd6\x19"
-			  "\xbc\x96\xdf\x49\xff\x04\x63\xf5"
-			  "\x0c\x11\x13\xaa\x9e\x1f\x5a\xf7"
-			  "\xdd\xbd\x37\x80\xc3\xd0\xbe\xa7"
-			  "\x05\xc8\x3c\x98\x1e\x05\x3c\x84"
-			  "\x39\x61\xc4\xed\xed\x71\x1b\xc4"
-			  "\x74\x45\x2c\xa1\x56\x70\x97\xfd"
-			  "\x44\x18\x07\x7d\xca\x60\x1f\x73"
-			  "\x3b\x6d\x21\xcb\x61\x87\x70\x25"
-			  "\x46\x21\xf1\x1f\x21\x91\x31\x2d"
-			  "\x5d\xcc\xb7\xd1\x84\x3e\x3d\xdb"
-			  "\x03\x53\x2a\x82\xa6\x9a\x95\xbc"
-			  "\x1a\x1e\x0a\x5e\x07\x43\xab\x43"
-			  "\xaf\x92\x82\x06\x91\x04\x09\xf4"
-			  "\x17\x0a\x9a\x2c\x54\xdb\xb8\xf4"
-			  "\xd0\xf0\x10\x66\x24\x8d\xcd\xda"
-			  "\xfe\x0e\x45\x9d\x6f\xc4\x4e\xf4"
-			  "\x96\xaf\x13\xdc\xa9\xd4\x8c\xc4"
-			  "\xc8\x57\x39\x3c\xc2\xd3\x0a\x76"
-			  "\x4a\x1f\x75\x83\x44\xc7\xd1\x39"
-			  "\xd8\xb5\x41\xba\x73\x87\xfa\x96"
-			  "\xc7\x18\x53\xfb\x9b\xda\xa0\x97"
-			  "\x1d\xee\x60\x85\x9e\x14\xc3\xce"
-			  "\xc4\x05\x29\x3b\x95\x30\xa3\xd1"
-			  "\x9f\x82\x6a\x04\xf5\xa7\x75\x57"
-			  "\x82\x04\xfe\x71\x51\x71\xb1\x49"
-			  "\x50\xf8\xe0\x96\xf1\xfa\xa8\x88"
-			  "\x3f\xa0\x86\x20\xd4\x60\x79\x59"
-			  "\x17\x2d\xd1\x09\xf4\xec\x05\x57"
-			  "\xcf\x62\x7e\x0e\x7e\x60\x78\xe6"
-			  "\x08\x60\x29\xd8\xd5\x08\x1a\x24"
-			  "\xc4\x6c\x24\xe7\x92\x08\x3d\x8a"
-			  "\x98\x7a\xcf\x99\x0a\x65\x0e\xdc"
-			  "\x8c\x8a\xbe\x92\x82\x91\xcc\x62"
-			  "\x30\xb6\xf4\x3f\xc6\x8a\x7f\x12"
-			  "\x4a\x8a\x49\xfa\x3f\x5c\xd4\x5a"
-			  "\xa6\x82\xa3\xe6\xaa\x34\x76\xb2"
-			  "\xab\x0a\x30\xef\x6c\x77\x58\x3f"
-			  "\x05\x6b\xcc\x5c\xae\xdc\xd7\xb9"
-			  "\x51\x7e\x8d\x32\x5b\x24\x25\xbe"
-			  "\x2b\x24\x01\xcf\x80\xda\x16\xd8"
-			  "\x90\x72\x2c\xad\x34\x8d\x0c\x74"
-			  "\x02\xcb\xfd\xcf\x6e\xef\x97\xb5"
-			  "\x4c\xf2\x68\xca\xde\x43\x9e\x8a"
-			  "\xc5\x5f\x31\x7f\x14\x71\x38\xec"
-			  "\xbd\x98\xe5\x71\xc4\xb5\xdb\xef"
-			  "\x59\xd2\xca\xc0\xc1\x86\x75\x01"
-			  "\xd4\x15\x0d\x6f\xa4\xf7\x7b\x37"
-			  "\x47\xda\x18\x93\x63\xda\xbe\x9e"
-			  "\x07\xfb\xb2\x83\xd5\xc4\x34\x55"
-			  "\xee\x73\xa1\x42\x96\xf9\x66\x41"
-			  "\xa4\xcc\xd2\x93\x6e\xe1\x0a\xbb"
-			  "\xd2\xdd\x18\x23\xe6\x6b\x98\x0b"
-			  "\x8a\x83\x59\x2c\xc3\xa6\x59\x5b"
-			  "\x01\x22\x59\xf7\xdc\xb0\x87\x7e"
-			  "\xdb\x7d\xf4\x71\x41\xab\xbd\xee"
-			  "\x79\xbe\x3c\x01\x76\x0b\x2d\x0a"
-			  "\x42\xc9\x77\x8c\xbb\x54\x95\x60"
-			  "\x43\x2e\xe0\x17\x52\xbd\x90\xc9"
-			  "\xc2\x2c\xdd\x90\x24\x22\x76\x40"
-			  "\x5c\xb9\x41\xc9\xa1\xd5\xbd\xe3"
-			  "\x44\xe0\xa4\xab\xcc\xb8\xe2\x32"
-			  "\x02\x15\x04\x1f\x8c\xec\x5d\x14"
-			  "\xac\x18\xaa\xef\x6e\x33\x19\x6e"
-			  "\xde\xfe\x19\xdb\xeb\x61\xca\x18"
-			  "\xad\xd8\x3d\xbf\x09\x11\xc7\xa5"
-			  "\x86\x0b\x0f\xe5\x3e\xde\xe8\xd9"
-			  "\x0a\x69\x9e\x4c\x20\xff\xf9\xc5"
-			  "\xfa\xf8\xf3\x7f\xa5\x01\x4b\x5e"
-			  "\x0f\xf0\x3b\x68\xf0\x46\x8c\x2a"
-			  "\x7a\xc1\x8f\xa0\xfe\x6a\x5b\x44"
-			  "\x70\x5c\xcc\x92\x2c\x6f\x0f\xbd"
-			  "\x25\x3e\xb7\x8e\x73\x58\xda\xc9"
-			  "\xa5\xaa\x9e\xf3\x9b\xfd\x37\x3e"
-			  "\xe2\x88\xa4\x7b\xc8\x5c\xa8\x93"
-			  "\x0e\xe7\x9a\x9c\x2e\x95\x18\x9f"
-			  "\xc8\x45\x0c\x88\x9e\x53\x4f\x3a"
-			  "\x76\xc1\x35\xfa\x17\xd8\xac\xa0"
-			  "\x0c\x2d\x47\x2e\x4f\x69\x9b\xf7"
-			  "\xd0\xb6\x96\x0c\x19\xb3\x08\x01"
-			  "\x65\x7a\x1f\xc7\x31\x86\xdb\xc8"
-			  "\xc1\x99\x8f\xf8\x08\x4a\x9d\x23"
-			  "\x22\xa8\xcf\x27\x01\x01\x88\x93"
-			  "\x9c\x86\x45\xbd\xe0\x51\xca\x52"
-			  "\x84\xba\xfe\x03\xf7\xda\xc5\xce"
-			  "\x3e\x77\x75\x86\xaf\x84\xc8\x05"
-			  "\x44\x01\x0f\x02\xf3\x58\xb0\x06"
-			  "\x5a\xd7\x12\x30\x8d\xdf\x1f\x1f"
-			  "\x0a\xe6\xd2\xea\xf6\x3a\x7a\x99"
-			  "\x63\xe8\xd2\xc1\x4a\x45\x8b\x40"
-			  "\x4d\x0a\xa9\x76\x92\xb3\xda\x87"
-			  "\x36\x33\xf0\x78\xc3\x2f\x5f\x02"
-			  "\x1a\x6a\x2c\x32\xcd\x76\xbf\xbd"
-			  "\x5a\x26\x20\x28\x8c\x8c\xbc\x52"
-			  "\x3d\x0a\xc9\xcb\xab\xa4\x21\xb0"
-			  "\x54\x40\x81\x44\xc7\xd6\x1c\x11"
-			  "\x44\xc6\x02\x92\x14\x5a\xbf\x1a"
-			  "\x09\x8a\x18\xad\xcd\x64\x3d\x53"
-			  "\x4a\xb6\xa5\x1b\x57\x0e\xef\xe0"
-			  "\x8c\x44\x5f\x7d\xbd\x6c\xfd\x60"
-			  "\xae\x02\x24\xb6\x99\xdd\x8c\xaf"
-			  "\x59\x39\x75\x3c\xd1\x54\x7b\x86"
-			  "\xcc\x99\xd9\x28\x0c\xb0\x94\x62"
-			  "\xf9\x51\xd1\x19\x96\x2d\x66\xf5"
-			  "\x55\xcf\x9e\x59\xe2\x6b\x2c\x08"
-			  "\xc0\x54\x48\x24\x45\xc3\x8c\x73"
-			  "\xea\x27\x6e\x66\x7d\x1d\x0e\x6e"
-			  "\x13\xe8\x56\x65\x3a\xb0\x81\x5c"
-			  "\xf0\xe8\xd8\x00\x6b\xcd\x8f\xad"
-			  "\xdd\x53\xf3\xa4\x6c\x43\xd6\x31"
-			  "\xaf\xd2\x76\x1e\x91\x12\xdb\x3c"
-			  "\x8c\xc2\x81\xf0\x49\xdb\xe2\x6b"
-			  "\x76\x62\x0a\x04\xe4\xaa\x8a\x7c"
-			  "\x08\x0b\x5d\xd0\xee\x1d\xfb\xc4"
-			  "\x02\x75\x42\xd6\xba\xa7\x22\xa8"
-			  "\x47\x29\xb7\x85\x6d\x93\x3a\xdb"
-			  "\x00\x53\x0b\xa2\xeb\xf8\xfe\x01"
-			  "\x6f\x8a\x31\xd6\x17\x05\x6f\x67"
-			  "\x88\x95\x32\xfe\x4f\xa6\x4b\xf8"
-			  "\x03\xe4\xcd\x9a\x18\xe8\x4e\x2d"
-			  "\xf7\x97\x9a\x0c\x7d\x9f\x7e\x44"
-			  "\x69\x51\xe0\x32\x6b\x62\x86\x8f"
-			  "\xa6\x8e\x0b\x21\x96\xe5\xaf\x77"
-			  "\xc0\x83\xdf\xa5\x0e\xd0\xa1\x04"
-			  "\xaf\xc1\x10\xcb\x5a\x40\xe4\xe3"
-			  "\x38\x7e\x07\xe8\x4d\xfa\xed\xc5"
-			  "\xf0\x37\xdf\xbb\x8a\xcf\x3d\xdc"
-			  "\x61\xd2\xc6\x2b\xff\x07\xc9\x2f"
-			  "\x0c\x2d\x5c\x07\xa8\x35\x6a\xfc"
-			  "\xae\x09\x03\x45\x74\x51\x4d\xc4"
-			  "\xb8\x23\x87\x4a\x99\x27\x20\x87"
-			  "\x62\x44\x0a\x4a\xce\x78\x47\x22",
-		.ksize	= 1088,
-		.plaintext	= "\x8e\xb0\x4c\xde\x9c\x4a\x04\x5a"
-			  "\xf6\xa9\x7f\x45\x25\xa5\x7b\x3a"
-			  "\xbc\x4d\x73\x39\x81\xb5\xbd\x3d"
-			  "\x21\x6f\xd7\x37\x50\x3c\x7b\x28"
-			  "\xd1\x03\x3a\x17\xed\x7b\x7c\x2a"
-			  "\x16\xbc\xdf\x19\x89\x52\x71\x31"
-			  "\xb6\xc0\xfd\xb5\xd3\xba\x96\x99"
-			  "\xb6\x34\x0b\xd0\x99\x93\xfc\x1a"
-			  "\x01\x3c\x85\xc6\x9b\x78\x5c\x8b"
-			  "\xfe\xae\xd2\xbf\xb2\x6f\xf9\xed"
-			  "\xc8\x25\x17\xfe\x10\x3b\x7d\xda"
-			  "\xf4\x8d\x35\x4b\x7c\x7b\x82\xe7"
-			  "\xc2\xb3\xee\x60\x4a\x03\x86\xc9"
-			  "\x4e\xb5\xc4\xbe\xd2\xbd\x66\xf1"
-			  "\x13\xf1\x09\xab\x5d\xca\x63\x1f"
-			  "\xfc\xfb\x57\x2a\xfc\xca\x66\xd8"
-			  "\x77\x84\x38\x23\x1d\xac\xd3\xb3"
-			  "\x7a\xad\x4c\x70\xfa\x9c\xc9\x61"
-			  "\xa6\x1b\xba\x33\x4b\x4e\x33\xec"
-			  "\xa0\xa1\x64\x39\x40\x05\x1c\xc2"
-			  "\x3f\x49\x9d\xae\xf2\xc5\xf2\xc5"
-			  "\xfe\xe8\xf4\xc2\xf9\x96\x2d\x28"
-			  "\x92\x30\x44\xbc\xd2\x7f\xe1\x6e"
-			  "\x62\x02\x8f\x3d\x1c\x80\xda\x0e"
-			  "\x6a\x90\x7e\x75\xff\xec\x3e\xc4"
-			  "\xcd\x16\x34\x3b\x05\x6d\x4d\x20"
-			  "\x1c\x7b\xf5\x57\x4f\xfa\x3d\xac"
-			  "\xd0\x13\x55\xe8\xb3\xe1\x1b\x78"
-			  "\x30\xe6\x9f\x84\xd4\x69\xd1\x08"
-			  "\x12\x77\xa7\x4a\xbd\xc0\xf2\xd2"
-			  "\x78\xdd\xa3\x81\x12\xcb\x6c\x14"
-			  "\x90\x61\xe2\x84\xc6\x2b\x16\xcc"
-			  "\x40\x99\x50\x88\x01\x09\x64\x4f"
-			  "\x0a\x80\xbe\x61\xae\x46\xc9\x0a"
-			  "\x5d\xe0\xfb\x72\x7a\x1a\xdd\x61"
-			  "\x63\x20\x05\xa0\x4a\xf0\x60\x69"
-			  "\x7f\x92\xbc\xbf\x4e\x39\x4d\xdd"
-			  "\x74\xd1\xb7\xc0\x5a\x34\xb7\xae"
-			  "\x76\x65\x2e\xbc\x36\xb9\x04\x95"
-			  "\x42\xe9\x6f\xca\x78\xb3\x72\x07"
-			  "\xa3\xba\x02\x94\x67\x4c\xb1\xd7"
-			  "\xe9\x30\x0d\xf0\x3b\xb8\x10\x6d"
-			  "\xea\x2b\x21\xbf\x74\x59\x82\x97"
-			  "\x85\xaa\xf1\xd7\x54\x39\xeb\x05"
-			  "\xbd\xf3\x40\xa0\x97\xe6\x74\xfe"
-			  "\xb4\x82\x5b\xb1\x36\xcb\xe8\x0d"
-			  "\xce\x14\xd9\xdf\xf1\x94\x22\xcd"
-			  "\xd6\x00\xba\x04\x4c\x05\x0c\xc0"
-			  "\xd1\x5a\xeb\x52\xd5\xa8\x8e\xc8"
-			  "\x97\xa1\xaa\xc1\xea\xc1\xbe\x7c"
-			  "\x36\xb3\x36\xa0\xc6\x76\x66\xc5"
-			  "\xe2\xaf\xd6\x5c\xe2\xdb\x2c\xb3"
-			  "\x6c\xb9\x99\x7f\xff\x9f\x03\x24"
-			  "\xe1\x51\x44\x66\xd8\x0c\x5d\x7f"
-			  "\x5c\x85\x22\x2a\xcf\x6d\x79\x28"
-			  "\xab\x98\x01\x72\xfe\x80\x87\x5f"
-			  "\x46\xba\xef\x81\x24\xee\xbf\xb0"
-			  "\x24\x74\xa3\x65\x97\x12\xc4\xaf"
-			  "\x8b\xa0\x39\xda\x8a\x7e\x74\x6e"
-			  "\x1b\x42\xb4\x44\x37\xfc\x59\xfd"
-			  "\x86\xed\xfb\x8c\x66\x33\xda\x63"
-			  "\x75\xeb\xe1\xa4\x85\x4f\x50\x8f"
-			  "\x83\x66\x0d\xd3\x37\xfa\xe6\x9c"
-			  "\x4f\x30\x87\x35\x18\xe3\x0b\xb7"
-			  "\x6e\x64\x54\xcd\x70\xb3\xde\x54"
-			  "\xb7\x1d\xe6\x4c\x4d\x55\x12\x12"
-			  "\xaf\x5f\x7f\x5e\xee\x9d\xe8\x8e"
-			  "\x32\x9d\x4e\x75\xeb\xc6\xdd\xaa"
-			  "\x48\x82\xa4\x3f\x3c\xd7\xd3\xa8"
-			  "\x63\x9e\x64\xfe\xe3\x97\x00\x62"
-			  "\xe5\x40\x5d\xc3\xad\x72\xe1\x28"
-			  "\x18\x50\xb7\x75\xef\xcd\x23\xbf"
-			  "\x3f\xc0\x51\x36\xf8\x41\xc3\x08"
-			  "\xcb\xf1\x8d\x38\x34\xbd\x48\x45"
-			  "\x75\xed\xbc\x65\x7b\xb5\x0c\x9b"
-			  "\xd7\x67\x7d\x27\xb4\xc4\x80\xd7"
-			  "\xa9\xb9\xc7\x4a\x97\xaa\xda\xc8"
-			  "\x3c\x74\xcf\x36\x8f\xe4\x41\xe3"
-			  "\xd4\xd3\x26\xa7\xf3\x23\x9d\x8f"
-			  "\x6c\x20\x05\x32\x3e\xe0\xc3\xc8"
-			  "\x56\x3f\xa7\x09\xb7\xfb\xc7\xf7"
-			  "\xbe\x2a\xdd\x0f\x06\x7b\x0d\xdd"
-			  "\xb0\xb4\x86\x17\xfd\xb9\x04\xe5"
-			  "\xc0\x64\x5d\xad\x2a\x36\x38\xdb"
-			  "\x24\xaf\x5b\xff\xca\xf9\x41\xe8"
-			  "\xf9\x2f\x1e\x5e\xf9\xf5\xd5\xf2"
-			  "\xb2\x88\xca\xc9\xa1\x31\xe2\xe8"
-			  "\x10\x95\x65\xbf\xf1\x11\x61\x7a"
-			  "\x30\x1a\x54\x90\xea\xd2\x30\xf6"
-			  "\xa5\xad\x60\xf9\x4d\x84\x21\x1b"
-			  "\xe4\x42\x22\xc8\x12\x4b\xb0\x58"
-			  "\x3e\x9c\x2d\x32\x95\x0a\x8e\xb0"
-			  "\x0a\x7e\x77\x2f\xe8\x97\x31\x6a"
-			  "\xf5\x59\xb4\x26\xe6\x37\x12\xc9"
-			  "\xcb\xa0\x58\x33\x6f\xd5\x55\x55"
-			  "\x3c\xa1\x33\xb1\x0b\x7e\x2e\xb4"
-			  "\x43\x2a\x84\x39\xf0\x9c\xf4\x69"
-			  "\x4f\x1e\x79\xa6\x15\x1b\x87\xbb"
-			  "\xdb\x9b\xe0\xf1\x0b\xba\xe3\x6e"
-			  "\xcc\x2f\x49\x19\x22\x29\xfc\x71"
-			  "\xbb\x77\x38\x18\x61\xaf\x85\x76"
-			  "\xeb\xd1\x09\xcc\x86\x04\x20\x9a"
-			  "\x66\x53\x2f\x44\x8b\xc6\xa3\xd2"
-			  "\x5f\xc7\x79\x82\x66\xa8\x6e\x75"
-			  "\x7d\x94\xd1\x86\x75\x0f\xa5\x4f"
-			  "\x3c\x7a\x33\xce\xd1\x6e\x9d\x7b"
-			  "\x1f\x91\x37\xb8\x37\x80\xfb\xe0"
-			  "\x52\x26\xd0\x9a\xd4\x48\x02\x41"
-			  "\x05\xe3\x5a\x94\xf1\x65\x61\x19"
-			  "\xb8\x88\x4e\x2b\xea\xba\x8b\x58"
-			  "\x8b\x42\x01\x00\xa8\xfe\x00\x5c"
-			  "\xfe\x1c\xee\x31\x15\x69\xfa\xb3"
-			  "\x9b\x5f\x22\x8e\x0d\x2c\xe3\xa5"
-			  "\x21\xb9\x99\x8a\x8e\x94\x5a\xef"
-			  "\x13\x3e\x99\x96\x79\x6e\xd5\x42"
-			  "\x36\x03\xa9\xe2\xca\x65\x4e\x8a"
-			  "\x8a\x30\xd2\x7d\x74\xe7\xf0\xaa"
-			  "\x23\x26\xdd\xcb\x82\x39\xfc\x9d"
-			  "\x51\x76\x21\x80\xa2\xbe\x93\x03"
-			  "\x47\xb0\xc1\xb6\xdc\x63\xfd\x9f"
-			  "\xca\x9d\xa5\xca\x27\x85\xe2\xd8"
-			  "\x15\x5b\x7e\x14\x7a\xc4\x89\xcc"
-			  "\x74\x14\x4b\x46\xd2\xce\xac\x39"
-			  "\x6b\x6a\x5a\xa4\x0e\xe3\x7b\x15"
-			  "\x94\x4b\x0f\x74\xcb\x0c\x7f\xa9"
-			  "\xbe\x09\x39\xa3\xdd\x56\x5c\xc7"
-			  "\x99\x56\x65\x39\xf4\x0b\x7d\x87"
-			  "\xec\xaa\xe3\x4d\x22\x65\x39\x4e",
-		.psize	= 1024,
-		.digest	= "\x64\x3a\xbc\xc3\x3f\x74\x40\x51"
-			  "\x6e\x56\x01\x1a\x51\xec\x36\xde",
-	}, {
-		.key	= "\x1b\x82\x2e\x1b\x17\x23\xb9\x6d"
-			  "\xdc\x9c\xda\x99\x07\xe3\x5f\xd8"
-			  "\xd2\xf8\x43\x80\x8d\x86\x7d\x80"
-			  "\x1a\xd0\xcc\x13\xb9\x11\x05\x3f"
-			  "\x7e\xcf\x7e\x80\x0e\xd8\x25\x48"
-			  "\x8b\xaa\x63\x83\x92\xd0\x72\xf5"
-			  "\x4f\x67\x7e\x50\x18\x25\xa4\xd1"
-			  "\xe0\x7e\x1e\xba\xd8\xa7\x6e\xdb"
-			  "\x1a\xcc\x0d\xfe\x9f\x6d\x22\x35"
-			  "\xe1\xe6\xe0\xa8\x7b\x9c\xb1\x66"
-			  "\xa3\xf8\xff\x4d\x90\x84\x28\xbc"
-			  "\xdc\x19\xc7\x91\x49\xfc\xf6\x33"
-			  "\xc9\x6e\x65\x7f\x28\x6f\x68\x2e"
-			  "\xdf\x1a\x75\xe9\xc2\x0c\x96\xb9"
-			  "\x31\x22\xc4\x07\xc6\x0a\x2f\xfd"
-			  "\x36\x06\x5f\x5c\xc5\xb1\x3a\xf4"
-			  "\x5e\x48\xa4\x45\x2b\x88\xa7\xee"
-			  "\xa9\x8b\x52\xcc\x99\xd9\x2f\xb8"
-			  "\xa4\x58\x0a\x13\xeb\x71\x5a\xfa"
-			  "\xe5\x5e\xbe\xf2\x64\xad\x75\xbc"
-			  "\x0b\x5b\x34\x13\x3b\x23\x13\x9a"
-			  "\x69\x30\x1e\x9a\xb8\x03\xb8\x8b"
-			  "\x3e\x46\x18\x6d\x38\xd9\xb3\xd8"
-			  "\xbf\xf1\xd0\x28\xe6\x51\x57\x80"
-			  "\x5e\x99\xfb\xd0\xce\x1e\x83\xf7"
-			  "\xe9\x07\x5a\x63\xa9\xef\xce\xa5"
-			  "\xfb\x3f\x37\x17\xfc\x0b\x37\x0e"
-			  "\xbb\x4b\x21\x62\xb7\x83\x0e\xa9"
-			  "\x9e\xb0\xc4\xad\x47\xbe\x35\xe7"
-			  "\x51\xb2\xf2\xac\x2b\x65\x7b\x48"
-			  "\xe3\x3f\x5f\xb6\x09\x04\x0c\x58"
-			  "\xce\x99\xa9\x15\x2f\x4e\xc1\xf2"
-			  "\x24\x48\xc0\xd8\x6c\xd3\x76\x17"
-			  "\x83\x5d\xe6\xe3\xfd\x01\x8e\xf7"
-			  "\x42\xa5\x04\x29\x30\xdf\xf9\x00"
-			  "\x4a\xdc\x71\x22\x1a\x33\x15\xb6"
-			  "\xd7\x72\xfb\x9a\xb8\xeb\x2b\x38"
-			  "\xea\xa8\x61\xa8\x90\x11\x9d\x73"
-			  "\x2e\x6c\xce\x81\x54\x5a\x9f\xcd"
-			  "\xcf\xd5\xbd\x26\x5d\x66\xdb\xfb"
-			  "\xdc\x1e\x7c\x10\xfe\x58\x82\x10"
-			  "\x16\x24\x01\xce\x67\x55\x51\xd1"
-			  "\xdd\x6b\x44\xa3\x20\x8e\xa9\xa6"
-			  "\x06\xa8\x29\x77\x6e\x00\x38\x5b"
-			  "\xde\x4d\x58\xd8\x1f\x34\xdf\xf9"
-			  "\x2c\xac\x3e\xad\xfb\x92\x0d\x72"
-			  "\x39\xa4\xac\x44\x10\xc0\x43\xc4"
-			  "\xa4\x77\x3b\xfc\xc4\x0d\x37\xd3"
-			  "\x05\x84\xda\x53\x71\xf8\x80\xd3"
-			  "\x34\x44\xdb\x09\xb4\x2b\x8e\xe3"
-			  "\x00\x75\x50\x9e\x43\x22\x00\x0b"
-			  "\x7c\x70\xab\xd4\x41\xf1\x93\xcd"
-			  "\x25\x2d\x84\x74\xb5\xf2\x92\xcd"
-			  "\x0a\x28\xea\x9a\x49\x02\x96\xcb"
-			  "\x85\x9e\x2f\x33\x03\x86\x1d\xdc"
-			  "\x1d\x31\xd5\xfc\x9d\xaa\xc5\xe9"
-			  "\x9a\xc4\x57\xf5\x35\xed\xf4\x4b"
-			  "\x3d\x34\xc2\x29\x13\x86\x36\x42"
-			  "\x5d\xbf\x90\x86\x13\x77\xe5\xc3"
-			  "\x62\xb4\xfe\x0b\x70\x39\x35\x65"
-			  "\x02\xea\xf6\xce\x57\x0c\xbb\x74"
-			  "\x29\xe3\xfd\x60\x90\xfd\x10\x38"
-			  "\xd5\x4e\x86\xbd\x37\x70\xf0\x97"
-			  "\xa6\xab\x3b\x83\x64\x52\xca\x66"
-			  "\x2f\xf9\xa4\xca\x3a\x55\x6b\xb0"
-			  "\xe8\x3a\x34\xdb\x9e\x48\x50\x2f"
-			  "\x3b\xef\xfd\x08\x2d\x5f\xc1\x37"
-			  "\x5d\xbe\x73\xe4\xd8\xe9\xac\xca"
-			  "\x8a\xaa\x48\x7c\x5c\xf4\xa6\x96"
-			  "\x5f\xfa\x70\xa6\xb7\x8b\x50\xcb"
-			  "\xa6\xf5\xa9\xbd\x7b\x75\x4c\x22"
-			  "\x0b\x19\x40\x2e\xc9\x39\x39\x32"
-			  "\x83\x03\xa8\xa4\x98\xe6\x8e\x16"
-			  "\xb9\xde\x08\xc5\xfc\xbf\xad\x39"
-			  "\xa8\xc7\x93\x6c\x6f\x23\xaf\xc1"
-			  "\xab\xe1\xdf\xbb\x39\xae\x93\x29"
-			  "\x0e\x7d\x80\x8d\x3e\x65\xf3\xfd"
-			  "\x96\x06\x65\x90\xa1\x28\x64\x4b"
-			  "\x69\xf9\xa8\x84\x27\x50\xfc\x87"
-			  "\xf7\xbf\x55\x8e\x56\x13\x58\x7b"
-			  "\x85\xb4\x6a\x72\x0f\x40\xf1\x4f"
-			  "\x83\x81\x1f\x76\xde\x15\x64\x7a"
-			  "\x7a\x80\xe4\xc7\x5e\x63\x01\x91"
-			  "\xd7\x6b\xea\x0b\x9b\xa2\x99\x3b"
-			  "\x6c\x88\xd8\xfd\x59\x3c\x8d\x22"
-			  "\x86\x56\xbe\xab\xa1\x37\x08\x01"
-			  "\x50\x85\x69\x29\xee\x9f\xdf\x21"
-			  "\x3e\x20\x20\xf5\xb0\xbb\x6b\xd0"
-			  "\x9c\x41\x38\xec\x54\x6f\x2d\xbd"
-			  "\x0f\xe1\xbd\xf1\x2b\x6e\x60\x56"
-			  "\x29\xe5\x7a\x70\x1c\xe2\xfc\x97"
-			  "\x82\x68\x67\xd9\x3d\x1f\xfb\xd8"
-			  "\x07\x9f\xbf\x96\x74\xba\x6a\x0e"
-			  "\x10\x48\x20\xd8\x13\x1e\xb5\x44"
-			  "\xf2\xcc\xb1\x8b\xfb\xbb\xec\xd7"
-			  "\x37\x70\x1f\x7c\x55\xd2\x4b\xb9"
-			  "\xfd\x70\x5e\xa3\x91\x73\x63\x52"
-			  "\x13\x47\x5a\x06\xfb\x01\x67\xa5"
-			  "\xc0\xd0\x49\x19\x56\x66\x9a\x77"
-			  "\x64\xaf\x8c\x25\x91\x52\x87\x0e"
-			  "\x18\xf3\x5f\x97\xfd\x71\x13\xf8"
-			  "\x05\xa5\x39\xcc\x65\xd3\xcc\x63"
-			  "\x5b\xdb\x5f\x7e\x5f\x6e\xad\xc4"
-			  "\xf4\xa0\xc5\xc2\x2b\x4d\x97\x38"
-			  "\x4f\xbc\xfa\x33\x17\xb4\x47\xb9"
-			  "\x43\x24\x15\x8d\xd2\xed\x80\x68"
-			  "\x84\xdb\x04\x80\xca\x5e\x6a\x35"
-			  "\x2c\x2c\xe7\xc5\x03\x5f\x54\xb0"
-			  "\x5e\x4f\x1d\x40\x54\x3d\x78\x9a"
-			  "\xac\xda\x80\x27\x4d\x15\x4c\x1a"
-			  "\x6e\x80\xc9\xc4\x3b\x84\x0e\xd9"
-			  "\x2e\x93\x01\x8c\xc3\xc8\x91\x4b"
-			  "\xb3\xaa\x07\x04\x68\x5b\x93\xa5"
-			  "\xe7\xc4\x9d\xe7\x07\xee\xf5\x3b"
-			  "\x40\x89\xcc\x60\x34\x9d\xb4\x06"
-			  "\x1b\xef\x92\xe6\xc1\x2a\x7d\x0f"
-			  "\x81\xaa\x56\xe3\xd7\xed\xa7\xd4"
-			  "\xa7\x3a\x49\xc4\xad\x81\x5c\x83"
-			  "\x55\x8e\x91\x54\xb7\x7d\x65\xa5"
-			  "\x06\x16\xd5\x9a\x16\xc1\xb0\xa2"
-			  "\x06\xd8\x98\x47\x73\x7e\x73\xa0"
-			  "\xb8\x23\xb1\x52\xbf\x68\x74\x5d"
-			  "\x0b\xcb\xfa\x8c\x46\xe3\x24\xe6"
-			  "\xab\xd4\x69\x8d\x8c\xf2\x8a\x59"
-			  "\xbe\x48\x46\x50\x8c\x9a\xe8\xe3"
-			  "\x31\x55\x0a\x06\xed\x4f\xf8\xb7"
-			  "\x4f\xe3\x85\x17\x30\xbd\xd5\x20"
-			  "\xe7\x5b\xb2\x32\xcf\x6b\x16\x44"
-			  "\xd2\xf5\x7e\xd7\xd1\x2f\xee\x64"
-			  "\x3e\x9d\x10\xef\x27\x35\x43\x64"
-			  "\x67\xfb\x7a\x7b\xe0\x62\x31\x9a"
-			  "\x4d\xdf\xa5\xab\xc0\x20\xbb\x01"
-			  "\xe9\x7b\x54\xf1\xde\xb2\x79\x50"
-			  "\x6c\x4b\x91\xdb\x7f\xbb\x50\xc1"
-			  "\x55\x44\x38\x9a\xe0\x9f\xe8\x29"
-			  "\x6f\x15\xf8\x4e\xa6\xec\xa0\x60",
-		.ksize	= 1088,
-		.plaintext	= "\x15\x68\x9e\x2f\xad\x15\x52\xdf"
-			  "\xf0\x42\x62\x24\x2a\x2d\xea\xbf"
-			  "\xc7\xf3\xb4\x1a\xf5\xed\xb2\x08"
-			  "\x15\x60\x1c\x00\x77\xbf\x0b\x0e"
-			  "\xb7\x2c\xcf\x32\x3a\xc7\x01\x77"
-			  "\xef\xa6\x75\xd0\x29\xc7\x68\x20"
-			  "\xb2\x92\x25\xbf\x12\x34\xe9\xa4"
-			  "\xfd\x32\x7b\x3f\x7c\xbd\xa5\x02"
-			  "\x38\x41\xde\xc9\xc1\x09\xd9\xfc"
-			  "\x6e\x78\x22\x83\x18\xf7\x50\x8d"
-			  "\x8f\x9c\x2d\x02\xa5\x30\xac\xff"
-			  "\xea\x63\x2e\x80\x37\x83\xb0\x58"
-			  "\xda\x2f\xef\x21\x55\xba\x7b\xb1"
-			  "\xb6\xed\xf5\xd2\x4d\xaa\x8c\xa9"
-			  "\xdd\xdb\x0f\xb4\xce\xc1\x9a\xb1"
-			  "\xc1\xdc\xbd\xab\x86\xc2\xdf\x0b"
-			  "\xe1\x2c\xf9\xbe\xf6\xd8\xda\x62"
-			  "\x72\xdd\x98\x09\x52\xc0\xc4\xb6"
-			  "\x7b\x17\x5c\xf5\xd8\x4b\x88\xd6"
-			  "\x6b\xbf\x84\x4a\x3f\xf5\x4d\xd2"
-			  "\x94\xe2\x9c\xff\xc7\x3c\xd9\xc8"
-			  "\x37\x38\xbc\x8c\xf3\xe7\xb7\xd0"
-			  "\x1d\x78\xc4\x39\x07\xc8\x5e\x79"
-			  "\xb6\x5a\x90\x5b\x6e\x97\xc9\xd4"
-			  "\x82\x9c\xf3\x83\x7a\xe7\x97\xfc"
-			  "\x1d\xbb\xef\xdb\xce\xe0\x82\xad"
-			  "\xca\x07\x6c\x54\x62\x6f\x81\xe6"
-			  "\x7a\x5a\x96\x6e\x80\x3a\xa2\x37"
-			  "\x6f\xc6\xa4\x29\xc3\x9e\x19\x94"
-			  "\x9f\xb0\x3e\x38\xfb\x3c\x2b\x7d"
-			  "\xaa\xb8\x74\xda\x54\x23\x51\x12"
-			  "\x4b\x96\x36\x8f\x91\x4f\x19\x37"
-			  "\x83\xc9\xdd\xc7\x1a\x32\x2d\xab"
-			  "\xc7\x89\xe2\x07\x47\x6c\xe8\xa6"
-			  "\x70\x6b\x8e\x0c\xda\x5c\x6a\x59"
-			  "\x27\x33\x0e\xe1\xe1\x20\xe8\xc8"
-			  "\xae\xdc\xd0\xe3\x6d\xa8\xa6\x06"
-			  "\x41\xb4\xd4\xd4\xcf\x91\x3e\x06"
-			  "\xb0\x9a\xf7\xf1\xaa\xa6\x23\x92"
-			  "\x10\x86\xf0\x94\xd1\x7c\x2e\x07"
-			  "\x30\xfb\xc5\xd8\xf3\x12\xa9\xe8"
-			  "\x22\x1c\x97\x1a\xad\x96\xb0\xa1"
-			  "\x72\x6a\x6b\xb4\xfd\xf7\xe8\xfa"
-			  "\xe2\x74\xd8\x65\x8d\x35\x17\x4b"
-			  "\x00\x23\x5c\x8c\x70\xad\x71\xa2"
-			  "\xca\xc5\x6c\x59\xbf\xb4\xc0\x6d"
-			  "\x86\x98\x3e\x19\x5a\x90\x92\xb1"
-			  "\x66\x57\x6a\x91\x68\x7c\xbc\xf3"
-			  "\xf1\xdb\x94\xf8\x48\xf1\x36\xd8"
-			  "\x78\xac\x1c\xa9\xcc\xd6\x27\xba"
-			  "\x91\x54\x22\xf5\xe6\x05\x3f\xcc"
-			  "\xc2\x8f\x2c\x3b\x2b\xc3\x2b\x2b"
-			  "\x3b\xb8\xb6\x29\xb7\x2f\x94\xb6"
-			  "\x7b\xfc\x94\x3e\xd0\x7a\x41\x59"
-			  "\x7b\x1f\x9a\x09\xa6\xed\x4a\x82"
-			  "\x9d\x34\x1c\xbd\x4e\x1c\x3a\x66"
-			  "\x80\x74\x0e\x9a\x4f\x55\x54\x47"
-			  "\x16\xba\x2a\x0a\x03\x35\x99\xa3"
-			  "\x5c\x63\x8d\xa2\x72\x8b\x17\x15"
-			  "\x68\x39\x73\xeb\xec\xf2\xe8\xf5"
-			  "\x95\x32\x27\xd6\xc4\xfe\xb0\x51"
-			  "\xd5\x0c\x50\xc5\xcd\x6d\x16\xb3"
-			  "\xa3\x1e\x95\x69\xad\x78\x95\x06"
-			  "\xb9\x46\xf2\x6d\x24\x5a\x99\x76"
-			  "\x73\x6a\x91\xa6\xac\x12\xe1\x28"
-			  "\x79\xbc\x08\x4e\x97\x00\x98\x63"
-			  "\x07\x1c\x4e\xd1\x68\xf3\xb3\x81"
-			  "\xa8\xa6\x5f\xf1\x01\xc9\xc1\xaf"
-			  "\x3a\x96\xf9\x9d\xb5\x5a\x5f\x8f"
-			  "\x7e\xc1\x7e\x77\x0a\x40\xc8\x8e"
-			  "\xfc\x0e\xed\xe1\x0d\xb0\xe5\x5e"
-			  "\x5e\x6f\xf5\x7f\xab\x33\x7d\xcd"
-			  "\xf0\x09\x4b\xb2\x11\x37\xdc\x65"
-			  "\x97\x32\x62\x71\x3a\x29\x54\xb9"
-			  "\xc7\xa4\xbf\x75\x0f\xf9\x40\xa9"
-			  "\x8d\xd7\x8b\xa7\xe0\x9a\xbe\x15"
-			  "\xc6\xda\xd8\x00\x14\x69\x1a\xaf"
-			  "\x5f\x79\xc3\xf5\xbb\x6c\x2a\x9d"
-			  "\xdd\x3c\x5f\x97\x21\xe1\x3a\x03"
-			  "\x84\x6a\xe9\x76\x11\x1f\xd3\xd5"
-			  "\xf0\x54\x20\x4d\xc2\x91\xc3\xa4"
-			  "\x36\x25\xbe\x1b\x2a\x06\xb7\xf3"
-			  "\xd1\xd0\x55\x29\x81\x4c\x83\xa3"
-			  "\xa6\x84\x1e\x5c\xd1\xd0\x6c\x90"
-			  "\xa4\x11\xf0\xd7\x63\x6a\x48\x05"
-			  "\xbc\x48\x18\x53\xcd\xb0\x8d\xdb"
-			  "\xdc\xfe\x55\x11\x5c\x51\xb3\xab"
-			  "\xab\x63\x3e\x31\x5a\x8b\x93\x63"
-			  "\x34\xa9\xba\x2b\x69\x1a\xc0\xe3"
-			  "\xcb\x41\xbc\xd7\xf5\x7f\x82\x3e"
-			  "\x01\xa3\x3c\x72\xf4\xfe\xdf\xbe"
-			  "\xb1\x67\x17\x2b\x37\x60\x0d\xca"
-			  "\x6f\xc3\x94\x2c\xd2\x92\x6d\x9d"
-			  "\x75\x18\x77\xaa\x29\x38\x96\xed"
-			  "\x0e\x20\x70\x92\xd5\xd0\xb4\x00"
-			  "\xc0\x31\xf2\xc9\x43\x0e\x75\x1d"
-			  "\x4b\x64\xf2\x1f\xf2\x29\x6c\x7b"
-			  "\x7f\xec\x59\x7d\x8c\x0d\xd4\xd3"
-			  "\xac\x53\x4c\xa3\xde\x42\x92\x95"
-			  "\x6d\xa3\x4f\xd0\xe6\x3d\xe7\xec"
-			  "\x7a\x4d\x68\xf1\xfe\x67\x66\x09"
-			  "\x83\x22\xb1\x98\x43\x8c\xab\xb8"
-			  "\x45\xe6\x6d\xdf\x5e\x50\x71\xce"
-			  "\xf5\x4e\x40\x93\x2b\xfa\x86\x0e"
-			  "\xe8\x30\xbd\x82\xcc\x1c\x9c\x5f"
-			  "\xad\xfd\x08\x31\xbe\x52\xe7\xe6"
-			  "\xf2\x06\x01\x62\x25\x15\x99\x74"
-			  "\x33\x51\x52\x57\x3f\x57\x87\x61"
-			  "\xb9\x7f\x29\x3d\xcd\x92\x5e\xa6"
-			  "\x5c\x3b\xf1\xed\x5f\xeb\x82\xed"
-			  "\x56\x7b\x61\xe7\xfd\x02\x47\x0e"
-			  "\x2a\x15\xa4\xce\x43\x86\x9b\xe1"
-			  "\x2b\x4c\x2a\xd9\x42\x97\xf7\x9a"
-			  "\xe5\x47\x46\x48\xd3\x55\x6f\x4d"
-			  "\xd9\xeb\x4b\xdd\x7b\x21\x2f\xb3"
-			  "\xa8\x36\x28\xdf\xca\xf1\xf6\xd9"
-			  "\x10\xf6\x1c\xfd\x2e\x0c\x27\xe0"
-			  "\x01\xb3\xff\x6d\x47\x08\x4d\xd4"
-			  "\x00\x25\xee\x55\x4a\xe9\xe8\x5b"
-			  "\xd8\xf7\x56\x12\xd4\x50\xb2\xe5"
-			  "\x51\x6f\x34\x63\x69\xd2\x4e\x96"
-			  "\x4e\xbc\x79\xbf\x18\xae\xc6\x13"
-			  "\x80\x92\x77\xb0\xb4\x0f\x29\x94"
-			  "\x6f\x4c\xbb\x53\x11\x36\xc3\x9f"
-			  "\x42\x8e\x96\x8a\x91\xc8\xe9\xfc"
-			  "\xfe\xbf\x7c\x2d\x6f\xf9\xb8\x44"
-			  "\x89\x1b\x09\x53\x0a\x2a\x92\xc3"
-			  "\x54\x7a\x3a\xf9\xe2\xe4\x75\x87"
-			  "\xa0\x5e\x4b\x03\x7a\x0d\x8a\xf4"
-			  "\x55\x59\x94\x2b\x63\x96\x0e\xf5",
-		.psize	= 1040,
-		.digest	= "\xb5\xb9\x08\xb3\x24\x3e\x03\xf0"
-			  "\xd6\x0b\x57\xbc\x0a\x6d\x89\x59",
-	}, {
-		.key	= "\xf6\x34\x42\x71\x35\x52\x8b\x58"
-			  "\x02\x3a\x8e\x4a\x8d\x41\x13\xe9"
-			  "\x7f\xba\xb9\x55\x9d\x73\x4d\xf8"
-			  "\x3f\x5d\x73\x15\xff\xd3\x9e\x7f"
-			  "\x20\x2a\x6a\xa8\xd1\xf0\x8f\x12"
-			  "\x6b\x02\xd8\x6c\xde\xba\x80\x22"
-			  "\x19\x37\xc8\xd0\x4e\x89\x17\x7c"
-			  "\x7c\xdd\x88\xfd\x41\xc0\x04\xb7"
-			  "\x1d\xac\x19\xe3\x20\xc7\x16\xcf"
-			  "\x58\xee\x1d\x7a\x61\x69\xa9\x12"
-			  "\x4b\xef\x4f\xb6\x38\xdd\x78\xf8"
-			  "\x28\xee\x70\x08\xc7\x7c\xcc\xc8"
-			  "\x1e\x41\xf5\x80\x86\x70\xd0\xf0"
-			  "\xa3\x87\x6b\x0a\x00\xd2\x41\x28"
-			  "\x74\x26\xf1\x24\xf3\xd0\x28\x77"
-			  "\xd7\xcd\xf6\x2d\x61\xf4\xa2\x13"
-			  "\x77\xb4\x6f\xa0\xf4\xfb\xd6\xb5"
-			  "\x38\x9d\x5a\x0c\x51\xaf\xad\x63"
-			  "\x27\x67\x8c\x01\xea\x42\x1a\x66"
-			  "\xda\x16\x7c\x3c\x30\x0c\x66\x53"
-			  "\x1c\x88\xa4\x5c\xb2\xe3\x78\x0a"
-			  "\x13\x05\x6d\xe2\xaf\xb3\xe4\x75"
-			  "\x00\x99\x58\xee\x76\x09\x64\xaa"
-			  "\xbb\x2e\xb1\x81\xec\xd8\x0e\xd3"
-			  "\x0c\x33\x5d\xb7\x98\xef\x36\xb6"
-			  "\xd2\x65\x69\x41\x70\x12\xdc\x25"
-			  "\x41\x03\x99\x81\x41\x19\x62\x13"
-			  "\xd1\x0a\x29\xc5\x8c\xe0\x4c\xf3"
-			  "\xd6\xef\x4c\xf4\x1d\x83\x2e\x6d"
-			  "\x8e\x14\x87\xed\x80\xe0\xaa\xd3"
-			  "\x08\x04\x73\x1a\x84\x40\xf5\x64"
-			  "\xbd\x61\x32\x65\x40\x42\xfb\xb0"
-			  "\x40\xf6\x40\x8d\xc7\x7f\x14\xd0"
-			  "\x83\x99\xaa\x36\x7e\x60\xc6\xbf"
-			  "\x13\x8a\xf9\x21\xe4\x7e\x68\x87"
-			  "\xf3\x33\x86\xb4\xe0\x23\x7e\x0a"
-			  "\x21\xb1\xf5\xad\x67\x3c\x9c\x9d"
-			  "\x09\xab\xaf\x5f\xba\xe0\xd0\x82"
-			  "\x48\x22\x70\xb5\x6d\x53\xd6\x0e"
-			  "\xde\x64\x92\x41\xb0\xd3\xfb\xda"
-			  "\x21\xfe\xab\xea\x20\xc4\x03\x58"
-			  "\x18\x2e\x7d\x2f\x03\xa9\x47\x66"
-			  "\xdf\x7b\xa4\x6b\x34\x6b\x55\x9c"
-			  "\x4f\xd7\x9c\x47\xfb\xa9\x42\xec"
-			  "\x5a\x12\xfd\xfe\x76\xa0\x92\x9d"
-			  "\xfe\x1e\x16\xdd\x24\x2a\xe4\x27"
-			  "\xd5\xa9\xf2\x05\x4f\x83\xa2\xaf"
-			  "\xfe\xee\x83\x7a\xad\xde\xdf\x9a"
-			  "\x80\xd5\x81\x14\x93\x16\x7e\x46"
-			  "\x47\xc2\x14\xef\x49\x6e\xb9\xdb"
-			  "\x40\xe8\x06\x6f\x9c\x2a\xfd\x62"
-			  "\x06\x46\xfd\x15\x1d\x36\x61\x6f"
-			  "\x77\x77\x5e\x64\xce\x78\x1b\x85"
-			  "\xbf\x50\x9a\xfd\x67\xa6\x1a\x65"
-			  "\xad\x5b\x33\x30\xf1\x71\xaa\xd9"
-			  "\x23\x0d\x92\x24\x5f\xae\x57\xb0"
-			  "\x24\x37\x0a\x94\x12\xfb\xb5\xb1"
-			  "\xd3\xb8\x1d\x12\x29\xb0\x80\x24"
-			  "\x2d\x47\x9f\x96\x1f\x95\xf1\xb1"
-			  "\xda\x35\xf6\x29\xe0\xe1\x23\x96"
-			  "\xc7\xe8\x22\x9b\x7c\xac\xf9\x41"
-			  "\x39\x01\xe5\x73\x15\x5e\x99\xec"
-			  "\xb4\xc1\xf4\xe7\xa7\x97\x6a\xd5"
-			  "\x90\x9a\xa0\x1d\xf3\x5a\x8b\x5f"
-			  "\xdf\x01\x52\xa4\x93\x31\x97\xb0"
-			  "\x93\x24\xb5\xbc\xb2\x14\x24\x98"
-			  "\x4a\x8f\x19\x85\xc3\x2d\x0f\x74"
-			  "\x9d\x16\x13\x80\x5e\x59\x62\x62"
-			  "\x25\xe0\xd1\x2f\x64\xef\xba\xac"
-			  "\xcd\x09\x07\x15\x8a\xcf\x73\xb5"
-			  "\x8b\xc9\xd8\x24\xb0\x53\xd5\x6f"
-			  "\xe1\x2b\x77\xb1\xc5\xe4\xa7\x0e"
-			  "\x18\x45\xab\x36\x03\x59\xa8\xbd"
-			  "\x43\xf0\xd8\x2c\x1a\x69\x96\xbb"
-			  "\x13\xdf\x6c\x33\x77\xdf\x25\x34"
-			  "\x5b\xa5\x5b\x8c\xf9\x51\x05\xd4"
-			  "\x8b\x8b\x44\x87\x49\xfc\xa0\x8f"
-			  "\x45\x15\x5b\x40\x42\xc4\x09\x92"
-			  "\x98\x0c\x4d\xf4\x26\x37\x1b\x13"
-			  "\x76\x01\x93\x8d\x4f\xe6\xed\x18"
-			  "\xd0\x79\x7b\x3f\x44\x50\xcb\xee"
-			  "\xf7\x4a\xc9\x9e\xe0\x96\x74\xa7"
-			  "\xe6\x93\xb2\x53\xca\x55\xa8\xdc"
-			  "\x1e\x68\x07\x87\xb7\x2e\xc1\x08"
-			  "\xb2\xa4\x5b\xaf\xc6\xdb\x5c\x66"
-			  "\x41\x1c\x51\xd9\xb0\x07\x00\x0d"
-			  "\xf0\x4c\xdc\x93\xde\xa9\x1e\x8e"
-			  "\xd3\x22\x62\xd8\x8b\x88\x2c\xea"
-			  "\x5e\xf1\x6e\x14\x40\xc7\xbe\xaa"
-			  "\x42\x28\xd0\x26\x30\x78\x01\x9b"
-			  "\x83\x07\xbc\x94\xc7\x57\xa2\x9f"
-			  "\x03\x07\xff\x16\xff\x3c\x6e\x48"
-			  "\x0a\xd0\xdd\x4c\xf6\x64\x9a\xf1"
-			  "\xcd\x30\x12\x82\x2c\x38\xd3\x26"
-			  "\x83\xdb\xab\x3e\xc6\xf8\xe6\xfa"
-			  "\x77\x0a\x78\x82\x75\xf8\x63\x51"
-			  "\x59\xd0\x8d\x24\x9f\x25\xe6\xa3"
-			  "\x4c\xbc\x34\xfc\xe3\x10\xc7\x62"
-			  "\xd4\x23\xc8\x3d\xa7\xc6\xa6\x0a"
-			  "\x4f\x7e\x29\x9d\x6d\xbe\xb5\xf1"
-			  "\xdf\xa4\x53\xfa\xc0\x23\x0f\x37"
-			  "\x84\x68\xd0\xb5\xc8\xc6\xae\xf8"
-			  "\xb7\x8d\xb3\x16\xfe\x8f\x87\xad"
-			  "\xd0\xc1\x08\xee\x12\x1c\x9b\x1d"
-			  "\x90\xf8\xd1\x63\xa4\x92\x3c\xf0"
-			  "\xc7\x34\xd8\xf1\x14\xed\xa3\xbc"
-			  "\x17\x7e\xd4\x62\x42\x54\x57\x2c"
-			  "\x3e\x7a\x35\x35\x17\x0f\x0b\x7f"
-			  "\x81\xa1\x3f\xd0\xcd\xc8\x3b\x96"
-			  "\xe9\xe0\x4a\x04\xe1\xb6\x3c\xa1"
-			  "\xd6\xca\xc4\xbd\xb6\xb5\x95\x34"
-			  "\x12\x9d\xc5\x96\xf2\xdf\xba\x54"
-			  "\x76\xd1\xb2\x6b\x3b\x39\xe0\xb9"
-			  "\x18\x62\xfb\xf7\xfc\x12\xf1\x5f"
-			  "\x7e\xc7\xe3\x59\x4c\xa6\xc2\x3d"
-			  "\x40\x15\xf9\xa3\x95\x64\x4c\x74"
-			  "\x8b\x73\x77\x33\x07\xa7\x04\x1d"
-			  "\x33\x5a\x7e\x8f\xbd\x86\x01\x4f"
-			  "\x3e\xb9\x27\x6f\xe2\x41\xf7\x09"
-			  "\x67\xfd\x29\x28\xc5\xe4\xf6\x18"
-			  "\x4c\x1b\x49\xb2\x9c\x5b\xf6\x81"
-			  "\x4f\xbb\x5c\xcc\x0b\xdf\x84\x23"
-			  "\x58\xd6\x28\x34\x93\x3a\x25\x97"
-			  "\xdf\xb2\xc3\x9e\x97\x38\x0b\x7d"
-			  "\x10\xb3\x54\x35\x23\x8c\x64\xee"
-			  "\xf0\xd8\x66\xff\x8b\x22\xd2\x5b"
-			  "\x05\x16\x3c\x89\xf7\xb1\x75\xaf"
-			  "\xc0\xae\x6a\x4f\x3f\xaf\x9a\xf4"
-			  "\xf4\x9a\x24\xd9\x80\x82\xc0\x12"
-			  "\xde\x96\xd1\xbe\x15\x0b\x8d\x6a"
-			  "\xd7\x12\xe4\x85\x9f\x83\xc9\xc3"
-			  "\xff\x0b\xb5\xaf\x3b\xd8\x6d\x67"
-			  "\x81\x45\xe6\xac\xec\xc1\x7b\x16"
-			  "\x18\x0a\xce\x4b\xc0\x2e\x76\xbc"
-			  "\x1b\xfa\xb4\x34\xb8\xfc\x3e\xc8"
-			  "\x5d\x90\x71\x6d\x7a\x79\xef\x06",
-		.ksize	= 1088,
-		.plaintext	= "\xaa\x5d\x54\xcb\xea\x1e\x46\x0f"
-			  "\x45\x87\x70\x51\x8a\x66\x7a\x33"
-			  "\xb4\x18\xff\xa9\x82\xf9\x45\x4b"
-			  "\x93\xae\x2e\x7f\xab\x98\xfe\xbf"
-			  "\x01\xee\xe5\xa0\x37\x8f\x57\xa6"
-			  "\xb0\x76\x0d\xa4\xd6\x28\x2b\x5d"
-			  "\xe1\x03\xd6\x1c\x6f\x34\x0d\xe7"
-			  "\x61\x2d\x2e\xe5\xae\x5d\x47\xc7"
-			  "\x80\x4b\x18\x8f\xa8\x99\xbc\x28"
-			  "\xed\x1d\x9d\x86\x7d\xd7\x41\xd1"
-			  "\xe0\x2b\xe1\x8c\x93\x2a\xa7\x80"
-			  "\xe1\x07\xa0\xa9\x9f\x8c\x8d\x1a"
-			  "\x55\xfc\x6b\x24\x7a\xbd\x3e\x51"
-			  "\x68\x4b\x26\x59\xc8\xa7\x16\xd9"
-			  "\xb9\x61\x13\xde\x8b\x63\x1c\xf6"
-			  "\x60\x01\xfb\x08\xb3\x5b\x0a\xbf"
-			  "\x34\x73\xda\x87\x87\x3d\x6f\x97"
-			  "\x4a\x0c\xa3\x58\x20\xa2\xc0\x81"
-			  "\x5b\x8c\xef\xa9\xc2\x01\x1e\x64"
-			  "\x83\x8c\xbc\x03\xb6\xd0\x29\x9f"
-			  "\x54\xe2\xce\x8b\xc2\x07\x85\x78"
-			  "\x25\x38\x96\x4c\xb4\xbe\x17\x4a"
-			  "\x65\xa6\xfa\x52\x9d\x66\x9d\x65"
-			  "\x4a\xd1\x01\x01\xf0\xcb\x13\xcc"
-			  "\xa5\x82\xf3\xf2\x66\xcd\x3f\x9d"
-			  "\xd1\xaa\xe4\x67\xea\xf2\xad\x88"
-			  "\x56\x76\xa7\x9b\x59\x3c\xb1\x5d"
-			  "\x78\xfd\x69\x79\x74\x78\x43\x26"
-			  "\x7b\xde\x3f\xf1\xf5\x4e\x14\xd9"
-			  "\x15\xf5\x75\xb5\x2e\x19\xf3\x0c"
-			  "\x48\x72\xd6\x71\x6d\x03\x6e\xaa"
-			  "\xa7\x08\xf9\xaa\x70\xa3\x0f\x4d"
-			  "\x12\x8a\xdd\xe3\x39\x73\x7e\xa7"
-			  "\xea\x1f\x6d\x06\x26\x2a\xf2\xc5"
-			  "\x52\xb4\xbf\xfd\x52\x0c\x06\x60"
-			  "\x90\xd1\xb2\x7b\x56\xae\xac\x58"
-			  "\x5a\x6b\x50\x2a\xf5\xe0\x30\x3c"
-			  "\x2a\x98\x0f\x1b\x5b\x0a\x84\x6c"
-			  "\x31\xae\x92\xe2\xd4\xbb\x7f\x59"
-			  "\x26\x10\xb9\x89\x37\x68\x26\xbf"
-			  "\x41\xc8\x49\xc4\x70\x35\x7d\xff"
-			  "\x2d\x7f\xf6\x8a\x93\x68\x8c\x78"
-			  "\x0d\x53\xce\x7d\xff\x7d\xfb\xae"
-			  "\x13\x1b\x75\xc4\x78\xd7\x71\xd8"
-			  "\xea\xd3\xf4\x9d\x95\x64\x8e\xb4"
-			  "\xde\xb8\xe4\xa6\x68\xc8\xae\x73"
-			  "\x58\xaf\xa8\xb0\x5a\x20\xde\x87"
-			  "\x43\xb9\x0f\xe3\xad\x41\x4b\xd5"
-			  "\xb7\xad\x16\x00\xa6\xff\xf6\x74"
-			  "\xbf\x8c\x9f\xb3\x58\x1b\xb6\x55"
-			  "\xa9\x90\x56\x28\xf0\xb5\x13\x4e"
-			  "\x9e\xf7\x25\x86\xe0\x07\x7b\x98"
-			  "\xd8\x60\x5d\x38\x95\x3c\xe4\x22"
-			  "\x16\x2f\xb2\xa2\xaf\xe8\x90\x17"
-			  "\xec\x11\x83\x1a\xf4\xa9\x26\xda"
-			  "\x39\x72\xf5\x94\x61\x05\x51\xec"
-			  "\xa8\x30\x8b\x2c\x13\xd0\x72\xac"
-			  "\xb9\xd2\xa0\x4c\x4b\x78\xe8\x6e"
-			  "\x04\x85\xe9\x04\x49\x82\x91\xff"
-			  "\x89\xe5\xab\x4c\xaa\x37\x03\x12"
-			  "\xca\x8b\x74\x10\xfd\x9e\xd9\x7b"
-			  "\xcb\xdb\x82\x6e\xce\x2e\x33\x39"
-			  "\xce\xd2\x84\x6e\x34\x71\x51\x6e"
-			  "\x0d\xd6\x01\x87\xc7\xfa\x0a\xd3"
-			  "\xad\x36\xf3\x4c\x9f\x96\x5e\x62"
-			  "\x62\x54\xc3\x03\x78\xd6\xab\xdd"
-			  "\x89\x73\x55\x25\x30\xf8\xa7\xe6"
-			  "\x4f\x11\x0c\x7c\x0a\xa1\x2b\x7b"
-			  "\x3d\x0d\xde\x81\xd4\x9d\x0b\xae"
-			  "\xdf\x00\xf9\x4c\xb6\x90\x8e\x16"
-			  "\xcb\x11\xc8\xd1\x2e\x73\x13\x75"
-			  "\x75\x3e\xaa\xf5\xee\x02\xb3\x18"
-			  "\xa6\x2d\xf5\x3b\x51\xd1\x1f\x47"
-			  "\x6b\x2c\xdb\xc4\x10\xe0\xc8\xba"
-			  "\x9d\xac\xb1\x9d\x75\xd5\x41\x0e"
-			  "\x7e\xbe\x18\x5b\xa4\x1f\xf8\x22"
-			  "\x4c\xc1\x68\xda\x6d\x51\x34\x6c"
-			  "\x19\x59\xec\xb5\xb1\xec\xa7\x03"
-			  "\xca\x54\x99\x63\x05\x6c\xb1\xac"
-			  "\x9c\x31\xd6\xdb\xba\x7b\x14\x12"
-			  "\x7a\xc3\x2f\xbf\x8d\xdc\x37\x46"
-			  "\xdb\xd2\xbc\xd4\x2f\xab\x30\xd5"
-			  "\xed\x34\x99\x8e\x83\x3e\xbe\x4c"
-			  "\x86\x79\x58\xe0\x33\x8d\x9a\xb8"
-			  "\xa9\xa6\x90\x46\xa2\x02\xb8\xdd"
-			  "\xf5\xf9\x1a\x5c\x8c\x01\xaa\x6e"
-			  "\xb4\x22\x12\xf5\x0c\x1b\x9b\x7a"
-			  "\xc3\x80\xf3\x06\x00\x5f\x30\xd5"
-			  "\x06\xdb\x7d\x82\xc2\xd4\x0b\x4c"
-			  "\x5f\xe9\xc5\xf5\xdf\x97\x12\xbf"
-			  "\x56\xaf\x9b\x69\xcd\xee\x30\xb4"
-			  "\xa8\x71\xff\x3e\x7d\x73\x7a\xb4"
-			  "\x0d\xa5\x46\x7a\xf3\xf4\x15\x87"
-			  "\x5d\x93\x2b\x8c\x37\x64\xb5\xdd"
-			  "\x48\xd1\xe5\x8c\xae\xd4\xf1\x76"
-			  "\xda\xf4\xba\x9e\x25\x0e\xad\xa3"
-			  "\x0d\x08\x7c\xa8\x82\x16\x8d\x90"
-			  "\x56\x40\x16\x84\xe7\x22\x53\x3a"
-			  "\x58\xbc\xb9\x8f\x33\xc8\xc2\x84"
-			  "\x22\xe6\x0d\xe7\xb3\xdc\x5d\xdf"
-			  "\xd7\x2a\x36\xe4\x16\x06\x07\xd2"
-			  "\x97\x60\xb2\xf5\x5e\x14\xc9\xfd"
-			  "\x8b\x05\xd1\xce\xee\x9a\x65\x99"
-			  "\xb7\xae\x19\xb7\xc8\xbc\xd5\xa2"
-			  "\x7b\x95\xe1\xcc\xba\x0d\xdc\x8a"
-			  "\x1d\x59\x52\x50\xaa\x16\x02\x82"
-			  "\xdf\x61\x33\x2e\x44\xce\x49\xc7"
-			  "\xe5\xc6\x2e\x76\xcf\x80\x52\xf0"
-			  "\x3d\x17\x34\x47\x3f\xd3\x80\x48"
-			  "\xa2\xba\xd5\xc7\x7b\x02\x28\xdb"
-			  "\xac\x44\xc7\x6e\x05\x5c\xc2\x79"
-			  "\xb3\x7d\x6a\x47\x77\x66\xf1\x38"
-			  "\xf0\xf5\x4f\x27\x1a\x31\xca\x6c"
-			  "\x72\x95\x92\x8e\x3f\xb0\xec\x1d"
-			  "\xc7\x2a\xff\x73\xee\xdf\x55\x80"
-			  "\x93\xd2\xbd\x34\xd3\x9f\x00\x51"
-			  "\xfb\x2e\x41\xba\x6c\x5a\x7c\x17"
-			  "\x7f\xe6\x70\xac\x8d\x39\x3f\x77"
-			  "\xe2\x23\xac\x8f\x72\x4e\xe4\x53"
-			  "\xcc\xf1\x1b\xf1\x35\xfe\x52\xa4"
-			  "\xd6\xb8\x40\x6b\xc1\xfd\xa0\xa1"
-			  "\xf5\x46\x65\xc2\x50\xbb\x43\xe2"
-			  "\xd1\x43\x28\x34\x74\xf5\x87\xa0"
-			  "\xf2\x5e\x27\x3b\x59\x2b\x3e\x49"
-			  "\xdf\x46\xee\xaf\x71\xd7\x32\x36"
-			  "\xc7\x14\x0b\x58\x6e\x3e\x2d\x41"
-			  "\xfa\x75\x66\x3a\x54\xe0\xb2\xb9"
-			  "\xaf\xdd\x04\x80\x15\x19\x3f\x6f"
-			  "\xce\x12\xb4\xd8\xe8\x89\x3c\x05"
-			  "\x30\xeb\xf3\x3d\xcd\x27\xec\xdc"
-			  "\x56\x70\x12\xcf\x78\x2b\x77\xbf"
-			  "\x22\xf0\x1b\x17\x9c\xcc\xd6\x1b"
-			  "\x2d\x3d\xa0\x3b\xd8\xc9\x70\xa4"
-			  "\x7a\x3e\x07\xb9\x06\xc3\xfa\xb0"
-			  "\x33\xee\xc1\xd8\xf6\xe0\xf0\xb2"
-			  "\x61\x12\x69\xb0\x5f\x28\x99\xda"
-			  "\xc3\x61\x48\xfa\x07\x16\x03\xc4"
-			  "\xa8\xe1\x3c\xe8\x0e\x64\x15\x30"
-			  "\xc1\x9d\x84\x2f\x73\x98\x0e\x3a"
-			  "\xf2\x86\x21\xa4\x9e\x1d\xb5\x86"
-			  "\x16\xdb\x2b\x9a\x06\x64\x8e\x79"
-			  "\x8d\x76\x3e\xc3\xc2\x64\x44\xe3"
-			  "\xda\xbc\x1a\x52\xd7\x61\x03\x65"
-			  "\x54\x32\x77\x01\xed\x9d\x8a\x43"
-			  "\x25\x24\xe3\xc1\xbe\xb8\x2f\xcb"
-			  "\x89\x14\x64\xab\xf6\xa0\x6e\x02"
-			  "\x57\xe4\x7d\xa9\x4e\x9a\x03\x36"
-			  "\xad\xf1\xb1\xfc\x0b\xe6\x79\x51"
-			  "\x9f\x81\x77\xc4\x14\x78\x9d\xbf"
-			  "\xb6\xd6\xa3\x8c\xba\x0b\x26\xe7"
-			  "\xc8\xb9\x5c\xcc\xe1\x5f\xd5\xc6"
-			  "\xc4\xca\xc2\xa3\x45\xba\x94\x13"
-			  "\xb2\x8f\xc3\x54\x01\x09\xe7\x8b"
-			  "\xda\x2a\x0a\x11\x02\x43\xcb\x57"
-			  "\xc9\xcc\xb5\x5c\xab\xc4\xec\x54"
-			  "\x00\x06\x34\xe1\x6e\x03\x89\x7c"
-			  "\xc6\xfb\x6a\xc7\x60\x43\xd6\xc5"
-			  "\xb5\x68\x72\x89\x8f\x42\xc3\x74"
-			  "\xbd\x25\xaa\x9f\x67\xb5\xdf\x26"
-			  "\x20\xe8\xb7\x01\x3c\xe4\x77\xce"
-			  "\xc4\x65\xa7\x23\x79\xea\x33\xc7"
-			  "\x82\x14\x5c\x82\xf2\x4e\x3d\xf6"
-			  "\xc6\x4a\x0e\x29\xbb\xec\x44\xcd"
-			  "\x2f\xd1\x4f\x21\x71\xa9\xce\x0f"
-			  "\x5c\xf2\x72\x5c\x08\x2e\x21\xd2"
-			  "\xc3\x29\x13\xd8\xac\xc3\xda\x13"
-			  "\x1a\x9d\xa7\x71\x1d\x27\x1d\x27"
-			  "\x1d\xea\xab\x44\x79\xad\xe5\xeb"
-			  "\xef\x1f\x22\x0a\x44\x4f\xcb\x87"
-			  "\xa7\x58\x71\x0e\x66\xf8\x60\xbf"
-			  "\x60\x74\x4a\xb4\xec\x2e\xfe\xd3"
-			  "\xf5\xb8\xfe\x46\x08\x50\x99\x6c"
-			  "\x66\xa5\xa8\x34\x44\xb5\xe5\xf0"
-			  "\xdd\x2c\x67\x4e\x35\x96\x8e\x67"
-			  "\x48\x3f\x5f\x37\x44\x60\x51\x2e"
-			  "\x14\x91\x5e\x57\xc3\x0e\x79\x77"
-			  "\x2f\x03\xf4\xe2\x1c\x72\xbf\x85"
-			  "\x5d\xd3\x17\xdf\x6c\xc5\x70\x24"
-			  "\x42\xdf\x51\x4e\x2a\xb2\xd2\x5b"
-			  "\x9e\x69\x83\x41\x11\xfe\x73\x22"
-			  "\xde\x8a\x9e\xd8\x8a\xfb\x20\x38"
-			  "\xd8\x47\x6f\xd5\xed\x8f\x41\xfd"
-			  "\x13\x7a\x18\x03\x7d\x0f\xcd\x7d"
-			  "\xa6\x7d\x31\x9e\xf1\x8f\x30\xa3"
-			  "\x8b\x4c\x24\xb7\xf5\x48\xd7\xd9"
-			  "\x12\xe7\x84\x97\x5c\x31\x6d\xfb"
-			  "\xdf\xf3\xd3\xd1\xd5\x0c\x30\x06"
-			  "\x01\x6a\xbc\x6c\x78\x7b\xa6\x50"
-			  "\xfa\x0f\x3c\x42\x2d\xa5\xa3\x3b"
-			  "\xcf\x62\x50\xff\x71\x6d\xe7\xda"
-			  "\x27\xab\xc6\x67\x16\x65\x68\x64"
-			  "\xc7\xd5\x5f\x81\xa9\xf6\x65\xb3"
-			  "\x5e\x43\x91\x16\xcd\x3d\x55\x37"
-			  "\x55\xb3\xf0\x28\xc5\x54\x19\xc0"
-			  "\xe0\xd6\x2a\x61\xd4\xc8\x72\x51"
-			  "\xe9\xa1\x7b\x48\x21\xad\x44\x09"
-			  "\xe4\x01\x61\x3c\x8a\x5b\xf9\xa1"
-			  "\x6e\x1b\xdf\xc0\x04\xa8\x8b\xf2"
-			  "\x21\xbe\x34\x7b\xfc\xa1\xcd\xc9"
-			  "\xa9\x96\xf4\xa4\x4c\xf7\x4e\x8f"
-			  "\x84\xcc\xd3\xa8\x92\x77\x8f\x36"
-			  "\xe2\x2e\x8c\x33\xe8\x84\xa6\x0c"
-			  "\x6c\x8a\xda\x14\x32\xc2\x96\xff"
-			  "\xc6\x4a\xc2\x9b\x30\x7f\xd1\x29"
-			  "\xc0\xd5\x78\x41\x00\x80\x80\x03"
-			  "\x2a\xb1\xde\x26\x03\x48\x49\xee"
-			  "\x57\x14\x76\x51\x3c\x36\x5d\x0a"
-			  "\x5c\x9f\xe8\xd8\x53\xdb\x4f\xd4"
-			  "\x38\xbf\x66\xc9\x75\x12\x18\x75"
-			  "\x34\x2d\x93\x22\x96\x51\x24\x6e"
-			  "\x4e\xd9\x30\xea\x67\xff\x92\x1c"
-			  "\x16\x26\xe9\xb5\x33\xab\x8c\x22"
-			  "\x47\xdb\xa0\x2c\x08\xf0\x12\x69"
-			  "\x7e\x93\x52\xda\xa5\xe5\xca\xc1"
-			  "\x0f\x55\x2a\xbd\x09\x30\x88\x1b"
-			  "\x9c\xc6\x9f\xe6\xdb\xa6\x92\xeb"
-			  "\xf4\xbd\x5c\xc4\xdb\xc6\x71\x09"
-			  "\xab\x5e\x48\x0c\xed\x6f\xda\x8e"
-			  "\x8d\x0c\x98\x71\x7d\x10\xd0\x9c"
-			  "\x20\x9b\x79\x53\x26\x5d\xb9\x85"
-			  "\x8a\x31\xb8\xc5\x1c\x97\xde\x88"
-			  "\x61\x55\x7f\x7c\x21\x06\xea\xc4"
-			  "\x5f\xaf\xf2\xf0\xd5\x5e\x7d\xb4"
-			  "\x6e\xcf\xe9\xae\x1b\x0e\x11\x80"
-			  "\xc1\x9a\x74\x7e\x52\x6f\xa0\xb7"
-			  "\x24\xcd\x8d\x0a\x11\x40\x63\x72"
-			  "\xfa\xe2\xc5\xb3\x94\xef\x29\xa2"
-			  "\x1a\x23\x43\x04\x37\x55\x0d\xe9"
-			  "\x83\xb2\x29\x51\x49\x64\xa0\xbd"
-			  "\xde\x73\xfd\xa5\x7c\x95\x70\x62"
-			  "\x58\xdc\xe2\xd0\xbf\x98\xf5\x8a"
-			  "\x6a\xfd\xce\xa8\x0e\x42\x2a\xeb"
-			  "\xd2\xff\x83\x27\x53\x5c\xa0\x6e"
-			  "\x93\xef\xe2\xb9\x5d\x35\xd6\x98"
-			  "\xf6\x71\x19\x7a\x54\xa1\xa7\xe8"
-			  "\x09\xfe\xf6\x9e\xc7\xbd\x3e\x29"
-			  "\xbd\x6b\x17\xf4\xe7\x3e\x10\x5c"
-			  "\xc1\xd2\x59\x4f\x4b\x12\x1a\x5b"
-			  "\x50\x80\x59\xb9\xec\x13\x66\xa8"
-			  "\xd2\x31\x7b\x6a\x61\x22\xdd\x7d"
-			  "\x61\xee\x87\x16\x46\x9f\xf9\xc7"
-			  "\x41\xee\x74\xf8\xd0\x96\x2c\x76"
-			  "\x2a\xac\x7d\x6e\x9f\x0e\x7f\x95"
-			  "\xfe\x50\x16\xb2\x23\xca\x62\xd5"
-			  "\x68\xcf\x07\x3f\x3f\x97\x85\x2a"
-			  "\x0c\x25\x45\xba\xdb\x32\xcb\x83"
-			  "\x8c\x4f\xe0\x6d\x9a\x99\xf9\xc9"
-			  "\xda\xd4\x19\x31\xc1\x7c\x6d\xd9"
-			  "\x9c\x56\xd3\xec\xc1\x81\x4c\xed"
-			  "\x28\x9d\x87\xeb\x19\xd7\x1a\x4f"
-			  "\x04\x6a\xcb\x1f\xcf\x1f\xa2\x16"
-			  "\xfc\x2a\x0d\xa1\x14\x2d\xfa\xc5"
-			  "\x5a\xd2\xc5\xf9\x19\x7c\x20\x1f"
-			  "\x2d\x10\xc0\x66\x7c\xd9\x2d\xe5"
-			  "\x88\x70\x59\xa7\x85\xd5\x2e\x7c"
-			  "\x5c\xe3\xb7\x12\xd6\x97\x3f\x29",
-		.psize	= 2048,
-		.digest	= "\x37\x90\x92\xc2\xeb\x01\x87\xd9"
-			  "\x95\xc7\x91\xc3\x17\x8b\x38\x52",
-	}
-};
-
-
 /*
  * DES test vectors.
  */
 static const struct cipher_testvec des_tv_template[] = {
 	{ /* From Applied Cryptography */
-- 
2.52.0



From broonie at kernel.org  Wed Dec 10 17:48:24 2025
From: broonie at kernel.org (Mark Brown)
Date: Thu, 11 Dec 2025 10:48:24 +0900
Subject: [PATCH 4/7] ASoC: soc-dai: define TDM idle behaviour modes
In-Reply-To: <CAHgNfTxmYxNaYOdGK4Eb4ouCqmUCjVuhzGdgTAL=+ybObqrCmw@mail.gmail.com>
References: <20251209-tdm-idle-slots-v1-0-38dabf6bc01e@gmail.com>
 <20251209-tdm-idle-slots-v1-4-38dabf6bc01e@gmail.com>
 <aTjZc3mgu7CQOkDU@sirena.co.uk>
 <CAHgNfTxmYxNaYOdGK4Eb4ouCqmUCjVuhzGdgTAL=+ybObqrCmw@mail.gmail.com>
Message-ID: <aToi6OMxiAcdBrnV@sirena.co.uk>

On Wed, Dec 10, 2025 at 01:57:50PM +1000, James Calligeros wrote:

> We have the use case where a codec enjoys exclusive use of a bus. For
> these, the codec can transmit 0 on any unused slots to hold the bus.

> We also have the case where multiple codecs share a single bus. One
> codec can weakly pull the bus low when it's not being actively driven by
> any of the attached codecs.

Or configure so you don't have any idle slots.

> However, a number of machines split six codecs into groups of three
> across two electrical lines and then OR them at the receiving
> port such that they appear on a single bus at the SoC. Because the two
> data lines are ORed at the receiver, we have to guarantee that line B is
> zero while line A is active, and vice versa. To do this, we set a single codec
> from each group to zero-fill during the active slots of the other group.

So this is an actual logical OR gate somewhere rather than a direct
electrical connection?

It'd be good to have an explanation more like this in the commit
messages to make it clearer to users what this is intended to do.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251211/8b2cce6f/attachment.sig>

From nathan at kernel.org  Wed Dec 10 17:50:03 2025
From: nathan at kernel.org (Nathan Chancellor)
Date: Thu, 11 Dec 2025 10:50:03 +0900
Subject: [PATCH] ALSA: hda: cix-ipbloq: Use modern PM ops
Message-ID: <20251211-hda-cix-ipbloq-modern-pm-ops-v1-1-c7a5580af021@kernel.org>

When building without CONFIG_PM_SLEEP, there are several warnings (or
errors with CONFIG_WERROR=y / W=e) from the cix-ipbloq driver:

  sound/hda/controllers/cix-ipbloq.c:378:12: error: 'cix_ipbloq_hda_runtime_resume' defined but not used [-Werror=unused-function]
    378 | static int cix_ipbloq_hda_runtime_resume(struct device *dev)
        |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  sound/hda/controllers/cix-ipbloq.c:362:12: error: 'cix_ipbloq_hda_runtime_suspend' defined but not used [-Werror=unused-function]
    362 | static int cix_ipbloq_hda_runtime_suspend(struct device *dev)
        |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  sound/hda/controllers/cix-ipbloq.c:349:12: error: 'cix_ipbloq_hda_resume' defined but not used [-Werror=unused-function]
    349 | static int cix_ipbloq_hda_resume(struct device *dev)
        |            ^~~~~~~~~~~~~~~~~~~~~
  sound/hda/controllers/cix-ipbloq.c:336:12: error: 'cix_ipbloq_hda_suspend' defined but not used [-Werror=unused-function]
    336 | static int cix_ipbloq_hda_suspend(struct device *dev)
        |            ^~~~~~~~~~~~~~~~~~~~~~

When CONFIG_PM and CONFIG_PM_SLEEP are unset, SET_SYSTEM_SLEEP_PM_OPS()
and SET_RUNTIME_PM_OPS() evaluate to nothing, so these functions appear
unused to the compiler in this configuration.

Use the modern SYSTEM_SLEEP_PM_OPS and RUNTIME_PM_OPS macros to resolve
these warnings, which is what they are intended to do. Additionally,
wrap &cix_ipbloq_hda_pm in pm_ptr() to ensure the compiler can drop the
entire structure when CONFIG_PM is unset.

Fixes: d91e9bd10125 ("ALSA: hda: add CIX IPBLOQ HDA controller support")
Signed-off-by: Nathan Chancellor <nathan at kernel.org>
---
 sound/hda/controllers/cix-ipbloq.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/sound/hda/controllers/cix-ipbloq.c b/sound/hda/controllers/cix-ipbloq.c
index cc9153692ef5..99f9f48e91d4 100644
--- a/sound/hda/controllers/cix-ipbloq.c
+++ b/sound/hda/controllers/cix-ipbloq.c
@@ -407,10 +407,10 @@ static int cix_ipbloq_hda_runtime_resume(struct device *dev)
 }
 
 static const struct dev_pm_ops cix_ipbloq_hda_pm = {
-	SET_SYSTEM_SLEEP_PM_OPS(cix_ipbloq_hda_suspend,
-				cix_ipbloq_hda_resume)
-	SET_RUNTIME_PM_OPS(cix_ipbloq_hda_runtime_suspend,
-			   cix_ipbloq_hda_runtime_resume, NULL)
+	SYSTEM_SLEEP_PM_OPS(cix_ipbloq_hda_suspend,
+			    cix_ipbloq_hda_resume)
+	RUNTIME_PM_OPS(cix_ipbloq_hda_runtime_suspend,
+		       cix_ipbloq_hda_runtime_resume, NULL)
 };
 
 static const struct of_device_id cix_ipbloq_hda_match[] = {
@@ -422,7 +422,7 @@ MODULE_DEVICE_TABLE(of, cix_ipbloq_hda_match);
 static struct platform_driver cix_ipbloq_hda_driver = {
 	.driver = {
 		.name = "cix-ipbloq-hda",
-		.pm = &cix_ipbloq_hda_pm,
+		.pm = pm_ptr(&cix_ipbloq_hda_pm),
 		.of_match_table = cix_ipbloq_hda_match,
 	},
 	.probe = cix_ipbloq_hda_probe,

---
base-commit: 161a0c617ab172bbcda7ce61803addeb2124dbff
change-id: 20251211-hda-cix-ipbloq-modern-pm-ops-a6b6754bf170

Best regards,
--  
Nathan Chancellor <nathan at kernel.org>



From yanan.yang at nxp.com  Wed Dec 10 17:55:44 2025
From: yanan.yang at nxp.com (Yanan Yang)
Date: Thu, 11 Dec 2025 10:55:44 +0900
Subject: [PATCH 1/2] dt-bindings: arm: fsl: Add FRDM-IMX91S board
In-Reply-To: <a252e741-aab3-4fec-ae8f-38634d071d77@kernel.org>
References: <20251205-imx91s-frdm-v1-0-afd6cd01c299@nxp.com>
 <20251205-imx91s-frdm-v1-1-afd6cd01c299@nxp.com>
 <4b29cc46-28a1-45f1-b24e-548513178884@kernel.org>
 <aTkTz-5QoB8BuLs7@lsvm11u0000554.swis.ap-northeast-2.aws.nxp.com>
 <a252e741-aab3-4fec-ae8f-38634d071d77@kernel.org>
Message-ID: <aTokoPlN-II2qA9V@lsvm11u0000554.swis.ap-northeast-2.aws.nxp.com>

On Thu, Dec 11, 2025 at 02:16:55AM +0100, Krzysztof Kozlowski wrote:
> On 10/12/2025 07:31, Yanan Yang wrote:
> > On Fri, Dec 05, 2025 at 09:21:55AM +0100, Krzysztof Kozlowski wrote:
> >> On 05/12/2025 09:03, Yanan.Yang wrote:
> >>> Add DT compatible string for NXP FRDM-IMX91S board
> >>>
> >>> The FRDM i.MX 91S development board is an low-cost and compact
> >>> development board featuring the i.MX 91 applications processor.
> >>>
> >>> Signed-off-by: Yanan.Yang <yanan.yang at nxp.com>
> >>
> >> Are you sure your Latin name contains '.' character? Or you just copied
> >> login?
> >>
> >>> ---
> >>>  Documentation/devicetree/bindings/arm/fsl.yaml | 1 +
> >>>  1 file changed, 1 insertion(+)
> >>>
> >>> diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
> >>> index 68a2d5fecc43..82f28be401b8 100644
> >>> --- a/Documentation/devicetree/bindings/arm/fsl.yaml
> >>> +++ b/Documentation/devicetree/bindings/arm/fsl.yaml
> >>> @@ -1412,6 +1412,7 @@ properties:
> >>>          items:
> >>>            - enum:
> >>>                - fsl,imx91-11x11-evk       # i.MX91 11x11 EVK Board
> >>> +              - fsl,imx91-11x11-frdm-s    # FRDM-IMX91S Board
> >>
> >> Anyway, this was sent, or something almost the same.
> >>
> >> Align internally before posting duplicates or at least explain why this
> >> is not a duplicate It is not the job of the community to coordinate how
> >> NXP employees should work. Srsly, it's NXP's job.
> >>
> > Hi Krzysztof,
> > Thank you for your review and for pointing this out.
> > 
> > This patch set is not a duplicate of the FRDM-IMX91 series. It introduces
> > support for a new board: FRDM-IMX91S. While FRDM-IMX91S is similar to
> > FRDM-IMX91, there are hardware differences that require a separate DTS:
> > 
> > - 512MB LPDDR4 (FRDM-IMX91 uses 1GB)
> > - 256MB FlexSPI-NAND (FRDM-IMX91 uses 8GB eMMC)
> > - Single GbE port (FRDM-IMX91 has dual GbE)
> > - PMIC PF9453 (FRDM-IMX91 uses PCA9451A)
> > 
> > These differences were described in the cover letter and commit message,
> > but I can make them more explicit if needed.
> 
> I cannot find anything about it in commit msg. Look, you wrote:
> 
> "Add DT compatible string for NXP FRDM-IMX91S board
> 
> The FRDM i.MX 91S development board is an low-cost and compact
> development board featuring the i.MX 91 applications processor."
> 
> so where is it? About cover letter, I usually do not read them, some
> maintainers skip entirely.
>

Hi Krzysztof,

Thank you for the feedback. I?ve added the detailed description in the DTS
patch. For the DT binding commit message, I?m planning to update it as below.
Please let me know if this looks acceptable or if you have further suggestions:

The FRDM-IMX91S is a low-cost, compact development board based on the
i.MX91 applications processor. It is a cost-optimized variant of the
FRDM-IMX91 board, with notable hardware differences that require a
separate DTS:
- 512MB LPDDR4 (FRDM-IMX91 uses 1GB)
- 256MB FlexSPI-NAND (FRDM-IMX91 uses 8GB eMMC)
- Single GbE port (FRDM-IMX91 has dual GbE)
- PMIC PF9453 (FRDM-IMX91 uses PCA9451A)

Regards,
Yanan

> Best regards,
> Krzysztof


From will at kernel.org  Wed Dec 10 18:09:01 2025
From: will at kernel.org (Will Deacon)
Date: Thu, 11 Dec 2025 11:09:01 +0900
Subject: [PATCH] iommu/io-pgtable-arm: Add misisng concatenated PGD cases
In-Reply-To: <8e058f60-60da-47c2-9947-2ea26cca1639@arm.com>
References: <20251130194506.593700-1-smostafa@google.com>
 <18a39079-2285-47fb-b306-040f2bc1bbaa@arm.com>
 <aTgX9qhaLyrQ5iye@google.com>
 <498bbad4-ea64-4a24-a63f-e131d271990a@arm.com>
 <aTjCDvtANr2WIv3L@google.com>
 <8e058f60-60da-47c2-9947-2ea26cca1639@arm.com>
Message-ID: <aTonvd9_4hY4-CpS@google.com>

On Wed, Dec 10, 2025 at 12:06:10PM +0000, Robin Murphy wrote:
> On 2025-12-10 12:42 am, Will Deacon wrote:
> > On Tue, Dec 09, 2025 at 01:33:36PM +0000, Robin Murphy wrote:
> > > On 2025-12-09 12:37 pm, Mostafa Saleh wrote:
> > > > On Tue, Dec 09, 2025 at 11:34:34AM +0000, Robin Murphy wrote:
> > > > > On 2025-11-30 7:45 pm, Mostafa Saleh wrote:
> > > > > > arm_lpae_concat_mandatory() assumes that OAS >= IAS which is not
> > > > > > correct for SMMUs supporting AArch32, and have OAS = 32/36 bits,
> > > > > > as IAS would be 40 bits.
> > > > > 
> > > > > But that is only when *using* AArch32 format. The bit in chapter 3.4 of the
> > > > > SMMU architecture is talking about the maximum IAS that an SMMU
> > > > > implementation needs to be able to accommodate based on its configuration,
> > > > > but it does then attempt to clarify that the actual IPA size in use by any
> > > > > given context should depend on the VMSA format in use:
> > > > > 
> > > > > "VMSAv8-32 LPAE always supports an IPA size of 40 bits, whereas VMSAv8-64
> > > > > and VMSAv9-128 limits the maximum IPA size to the maximum PA size."
> > > > > 
> > > > > Rule R_SRKBC in the Arm ARM lays out the exact T0SZ constraints with this
> > > > > AArch32/AArch64 detail.
> > > > 
> > > > I see, thanks a lot for the explanation, I got confused by the this
> > > > statement:
> > > > Note: If AArch32 is implemented, IAS == MAX(40, OAS), otherwise IAS == OAS.
> > > 
> > > Indeed, that appears confusingly contradictory; I've filed a bug.
> > 
> > I think the spec has always been worded like this. My reading is that, in
> > isolation:
> > 
> >    - VMSAv8-32 LPAE always uses a 40-bit IAS
> >    - VMSAv8-64 has IAS == OAS and this can be smaller than 40 bits
> > 
> > so if AArch32 is implemented, we know that the hardware supports at
> > least a 40-bit IAS and in that case the VMSAv8-64 IAS can be bigger
> > than the OAS.
> 
> No, the VMSAv8-64 IAS can never be bigger than OAS, as that would violate
> VMSA (see rules R_DTLMN and R_SRKBC). The SMMU spec seems mostly fixated on
> the notional maximum IAS that an SMMU must accommodate in general across all
> supported formats; the limitations of using any particular format must still
> apply though (similarly, the fact that AArch32 has a fixed 40-bit output
> doesn't mean that OAS and S2PS don't still matter for AArch64 format.)

A VMSAv8-32 stage-1 could still input a 40-bit IAS into a VMSAv8-64
stage-2 when the OAS < 40-bit though, right? If that's the only case
where this happens, then I agree we should ditch the complexity from the
driver on the grounds that we don't ever use the 32-bit formats.

Will


From ricardo.neri-calderon at linux.intel.com  Wed Dec 10 19:00:06 2025
From: ricardo.neri-calderon at linux.intel.com (Ricardo Neri)
Date: Wed, 10 Dec 2025 19:00:06 -0800
Subject: [PATCH v8 17/17] Documentation: KHO: Add memblock bindings
In-Reply-To: <20250509074635.3187114-18-changyuanl@google.com>
References: <20250509074635.3187114-1-changyuanl@google.com>
 <20250509074635.3187114-18-changyuanl@google.com>
Message-ID: <20251211030006.GA9333@ranerica-svr.sc.intel.com>

On Fri, May 09, 2025 at 12:46:35AM -0700, Changyuan Lyu wrote:
> From: "Mike Rapoport (Microsoft)" <rppt at kernel.org>
> 
> We introduced KHO into Linux: A framework that allows Linux to pass
> metadata and memory across kexec from Linux to Linux. KHO reuses fdt
> as file format and shares a lot of the same properties of firmware-to-
> Linux boot formats: It needs a stable, documented ABI that allows for
> forward and backward compatibility as well as versioning.
> 
> As first user of KHO, we introduced memblock which can now preserve
> memory ranges reserved with reserve_mem command line options contents
> across kexec, so you can use the post-kexec kernel to read traces from
> the pre-kexec kernel.
> 
> This patch adds memblock schemas similar to "device" device tree ones to
> a new kho bindings directory. This allows us to force contributors to
> document the data that moves across KHO kexecs and catch breaking change
> during review.
> 
> Co-developed-by: Alexander Graf <graf at amazon.com>
> Signed-off-by: Alexander Graf <graf at amazon.com>
> Signed-off-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
> Signed-off-by: Changyuan Lyu <changyuanl at google.com>
> ---
>  .../kho/bindings/memblock/memblock.yaml       | 39 ++++++++++++++++++
>  .../kho/bindings/memblock/reserve-mem.yaml    | 40 +++++++++++++++++++
>  MAINTAINERS                                   |  1 +
>  3 files changed, 80 insertions(+)
>  create mode 100644 Documentation/core-api/kho/bindings/memblock/memblock.yaml
>  create mode 100644 Documentation/core-api/kho/bindings/memblock/reserve-mem.yaml
> 
> diff --git a/Documentation/core-api/kho/bindings/memblock/memblock.yaml b/Documentation/core-api/kho/bindings/memblock/memblock.yaml
> new file mode 100644
> index 0000000000000..d388c28eb91d1
> --- /dev/null
> +++ b/Documentation/core-api/kho/bindings/memblock/memblock.yaml
> @@ -0,0 +1,39 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +title: Memblock reserved memory
> +
> +maintainers:
> +  - Mike Rapoport <rppt at kernel.org>
> +
> +description: |
> +  Memblock can serialize its current memory reservations created with
> +  reserve_mem command line option across kexec through KHO.
> +  The post-KHO kernel can then consume these reservations and they are
> +  guaranteed to have the same physical address.

Hi Changyuan, Mike,

I am sorry I am late to this patchset. I am working on a patchset to use
KHO to pass reserved memory regions to a driver after kexec and I have a
few questions.

> +
> +properties:
> +  compatible:
> +    enum:
> +      - reserve-mem-v1

Shouldn't this be "memblock-v1". IIUC, the compatible "reserve-mem-v1" is
to be used for the memblock reserved memory regions, not the memblock node.


> +
> +patternProperties:
> +  "$[0-9a-f_]+^":

Shouldn't this be "^[0-9a-f_]+$": ^ at the start of the pattern and $ at
the end of it? Or is this a KHO-specific rule?

Also, IIUC, this means that names of the nodes are hexadecimal numbers
whereas the example below has a "membloc" name. I assume this does not
refer to the subnode named "n1" as this does not follow the pattern
either Moreover, it should have been documented in the reserve-mem binding.

> +    $ref: reserve-mem.yaml#
> +    description: reserved memory regions
> +
> +required:
> +  - compatible
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    memblock {
> +      compatible = "memblock-v1";
> +      n1 {
> +        compatible = "reserve-mem-v1";
> +        start = <0xc06b 0x4000000>;
> +        size = <0x04 0x00>;
> +      };
> +    };

Thanks and BR,
Ricardo


From herbert at gondor.apana.org.au  Wed Dec 10 19:02:16 2025
From: herbert at gondor.apana.org.au (Herbert Xu)
Date: Thu, 11 Dec 2025 11:02:16 +0800
Subject: [PATCH 08/12] crypto: adiantum - Use memcpy_{to,from}_sglist()
In-Reply-To: <20251211011846.8179-9-ebiggers@kernel.org>
References: <20251211011846.8179-1-ebiggers@kernel.org>
 <20251211011846.8179-9-ebiggers@kernel.org>
Message-ID: <aTo0OIhv3IOHbzvy@gondor.apana.org.au>

On Wed, Dec 10, 2025 at 05:18:40PM -0800, Eric Biggers wrote:
> Call the newer, easier-to-read functions memcpy_to_sglist() and
> memcpy_from_sglist() directly instead of calling
> scatterwalk_map_and_copy().  No change in behavior.
> 
> Signed-off-by: Eric Biggers <ebiggers at kernel.org>
> ---
>  crypto/adiantum.c | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)

Acked-by: Herbert Xu <herbert at gondor.apana.org.au>
-- 
Email: Herbert Xu <herbert at gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt


From herbert at gondor.apana.org.au  Wed Dec 10 19:02:47 2025
From: herbert at gondor.apana.org.au (Herbert Xu)
Date: Thu, 11 Dec 2025 11:02:47 +0800
Subject: [PATCH 10/12] crypto: nhpoly1305 - Remove crypto_shash support
In-Reply-To: <20251211011846.8179-11-ebiggers@kernel.org>
References: <20251211011846.8179-1-ebiggers@kernel.org>
 <20251211011846.8179-11-ebiggers@kernel.org>
Message-ID: <aTo0V7fD6PqrArFN@gondor.apana.org.au>

On Wed, Dec 10, 2025 at 05:18:42PM -0800, Eric Biggers wrote:
> Remove nhpoly1305 support from crypto_shash.  It no longer has any user
> now that crypto/adiantum.c no longer uses it.
> 
> Signed-off-by: Eric Biggers <ebiggers at kernel.org>
> ---
>  crypto/Kconfig              |   6 -
>  crypto/Makefile             |   1 -
>  crypto/nhpoly1305.c         | 255 ------------------------------------
>  include/crypto/nhpoly1305.h |  74 -----------
>  4 files changed, 336 deletions(-)
>  delete mode 100644 crypto/nhpoly1305.c
>  delete mode 100644 include/crypto/nhpoly1305.h

Acked-by: Herbert Xu <herbert at gondor.apana.org.au>

Thanks,
-- 
Email: Herbert Xu <herbert at gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt


From herbert at gondor.apana.org.au  Wed Dec 10 19:03:13 2025
From: herbert at gondor.apana.org.au (Herbert Xu)
Date: Thu, 11 Dec 2025 11:03:13 +0800
Subject: [PATCH 11/12] crypto: testmgr - Remove nhpoly1305 tests
In-Reply-To: <20251211011846.8179-12-ebiggers@kernel.org>
References: <20251211011846.8179-1-ebiggers@kernel.org>
 <20251211011846.8179-12-ebiggers@kernel.org>
Message-ID: <aTo0cfjLr5qi2nmY@gondor.apana.org.au>

On Wed, Dec 10, 2025 at 05:18:43PM -0800, Eric Biggers wrote:
> These are no longer used, since nhpoly1305 support has been removed from
> the crypto_shash API.
> 
> Signed-off-by: Eric Biggers <ebiggers at kernel.org>
> ---
>  crypto/testmgr.c |    6 -
>  crypto/testmgr.h | 1372 ----------------------------------------------
>  2 files changed, 1378 deletions(-)

Acked-by: Herbert Xu <herbert at gondor.apana.org.au>
-- 
Email: Herbert Xu <herbert at gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt


From jassisinghbrar at gmail.com  Wed Dec 10 19:28:56 2025
From: jassisinghbrar at gmail.com (Jassi Brar)
Date: Wed, 10 Dec 2025 21:28:56 -0600
Subject: [GIT PULL] Mailbox changes for v6.19
In-Reply-To: <CABb+yY0Uvkc4g0=gi79j+CCJzKkeuHGD9u_6P5ScAFkNS0F+2w@mail.gmail.com>
References: <CABb+yY0Uvkc4g0=gi79j+CCJzKkeuHGD9u_6P5ScAFkNS0F+2w@mail.gmail.com>
Message-ID: <CABb+yY2or-wT46Z3jGZ_ks91tHGM2D-1OYeL0xtHfuZURatg9A@mail.gmail.com>

Hi Linus,
The following changes since commit 7d0a66e4bb9081d75c82ec4957c50034cb0ea449:

  Linux 6.18 (2025-11-30 14:42:10 -0800)

are available in the Git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/jassibrar/mailbox.git
tags/mailbox-v6.19

for you to fetch changes up to 1ec6e0e8c0dd6599472af944b8d703d526ff1031:

  mailbox: mtk-cmdq: Add driver data to support for MT8196 (2025-12-10
17:17:01 -0600)

----------------------------------------------------------------
pcc: refactor and improve initialisation and interrupt handling
qcom:     enable Kaanapali and Glymur platforms
renesas:  add MFIS mailbox driver
mediatek: add mtk-vcp-mailbox driver and bindings
          add support for MT8196 into mtk-cmdq
misc:     remove unneeded double quotation in Kconfig
          drop POLARFIRE from ARCH_MICROCHIP_POLARFIRE
          fix out-of-bounds access in mchp_ipc_get_cluster_aggr_irq

----------------------------------------------------------------
Conor Dooley (1):
      mailbox: mpfs: drop POLARFIRE from ARCH_MICROCHIP_POLARFIRE

Jason-JH Lin (4):
      mailbox: mtk-cmdq: Add cmdq private data to cmdq_pkt for
generating instruction
      mailbox: mtk-cmdq: Add GCE hardware virtualization configuration
      mailbox: mtk-cmdq: Add mminfra_offset configuration for DRAM transaction
      mailbox: mtk-cmdq: Add driver data to support for MT8196

Jingyi Wang (2):
      dt-bindings: mailbox: qcom: Add IPCC support for Kaanapali and
Glymur Platforms
      dt-bindings: mailbox: qcom: Add CPUCP mailbox controller
bindings for Kaanapali

Jjian Zhou (2):
      dt-bindings: mailbox: mediatek,mt8196-vcp-mbox: add mtk vcp-mbox document
      mailbox: mediatek: Add mtk-vcp-mailbox driver

Joonwon Kang (1):
      mailbox: Prevent out-of-bounds access in fw_mbox_index_xlate()

Kuninori Morimoto (2):
      mailbox: remove unneeded double quotation
      mailbox: renesas: Support MFIS mailbox driver

Pierre-Henry Moussay (1):
      dt-bindings: mbox: add pic64gx mailbox compatibility to mpfs mailbox

Sudeep Holla (6):
      Revert "mailbox/pcc: support mailbox management of the shared buffer"
      mailbox: pcc: Wire up ->last_tx_done() for PCC channels
      mailbox: pcc: Set txdone_irq/txdone_poll based on PCCT flags
      mailbox: pcc: Mark Tx as complete in PCC IRQ handler
      mailbox: pcc: Initialize SHMEM before binding the channel with the client
      mailbox: pcc: Clear any pending responder interrupts before enabling it

Valentina Fernandez (1):
      mailbox: mchp-ipc-sbi: fix out-of-bounds access in
mchp_ipc_get_cluster_aggr_irq()

 .../bindings/mailbox/mediatek,mt8196-vcp-mbox.yaml |  49 ++++++
 .../bindings/mailbox/microchip,mpfs-mailbox.yaml   |   6 +-
 .../bindings/mailbox/qcom,cpucp-mbox.yaml          |   1 +
 .../devicetree/bindings/mailbox/qcom-ipcc.yaml     |   2 +
 drivers/mailbox/Kconfig                            |  22 ++-
 drivers/mailbox/Makefile                           |   4 +
 drivers/mailbox/mailbox-mchp-ipc-sbi.c             |  22 +--
 drivers/mailbox/mailbox.c                          |   6 +-
 drivers/mailbox/mtk-cmdq-mailbox.c                 |  74 ++++++++-
 drivers/mailbox/mtk-vcp-mailbox.c                  | 170 +++++++++++++++++++++
 drivers/mailbox/pcc.c                              | 118 +++-----------
 drivers/mailbox/rcar-mfis-mailbox.c                | 168 ++++++++++++++++++++
 include/acpi/pcc.h                                 |  29 ----
 include/linux/mailbox/mtk-cmdq-mailbox.h           |  19 +++
 include/linux/mailbox/mtk-vcp-mailbox.h            |  32 ++++
 15 files changed, 578 insertions(+), 144 deletions(-)
 create mode 100644
Documentation/devicetree/bindings/mailbox/mediatek,mt8196-vcp-mbox.yaml
 create mode 100644 drivers/mailbox/mtk-vcp-mailbox.c
 create mode 100644 drivers/mailbox/rcar-mfis-mailbox.c
 create mode 100644 include/linux/mailbox/mtk-vcp-mailbox.h


From jassisinghbrar at gmail.com  Wed Dec 10 19:30:21 2025
From: jassisinghbrar at gmail.com (Jassi Brar)
Date: Wed, 10 Dec 2025 21:30:21 -0600
Subject: [GIT PULL] Mailbox changes for v6.19
In-Reply-To: <20251211112343.51f4ff1c@canb.auug.org.au>
References: <CABb+yY0Uvkc4g0=gi79j+CCJzKkeuHGD9u_6P5ScAFkNS0F+2w@mail.gmail.com>
 <20251211112343.51f4ff1c@canb.auug.org.au>
Message-ID: <CABb+yY2PhSgWTpiv+oGVtcX3HidMniUQhb=EeHBEBEbfW3sSow@mail.gmail.com>

On Wed, Dec 10, 2025 at 6:23?PM Stephen Rothwell <sfr at canb.auug.org.au> wrote:
>
> Hi Jassi,
>
> On Wed, 10 Dec 2025 17:31:04 -0600 Jassi Brar <jassisinghbrar at gmail.com> wrote:
> >
> >       mailbox: mtk-cmdq: Remove unsued cmdq_get_shift_pa()
>
> This commit causes a build failure.
>
> I am disappointed that none of these commits have been in linux-next
> until today.
>
Sorry, I will take care of that in the future.
Regards,
Jassi


From torvalds at linux-foundation.org  Wed Dec 10 19:44:13 2025
From: torvalds at linux-foundation.org (Linus Torvalds)
Date: Thu, 11 Dec 2025 12:44:13 +0900
Subject: [GIT PULL] Mailbox changes for v6.19
In-Reply-To: <CABb+yY2or-wT46Z3jGZ_ks91tHGM2D-1OYeL0xtHfuZURatg9A@mail.gmail.com>
References: <CABb+yY0Uvkc4g0=gi79j+CCJzKkeuHGD9u_6P5ScAFkNS0F+2w@mail.gmail.com>
 <CABb+yY2or-wT46Z3jGZ_ks91tHGM2D-1OYeL0xtHfuZURatg9A@mail.gmail.com>
Message-ID: <CAHk-=wiCyKE3auGX7tTpQnnXNH3==6hzCWNqQvwLxzuAKivQjQ@mail.gmail.com>

On Thu, 11 Dec 2025 at 12:29, Jassi Brar <jassisinghbrar at gmail.com> wrote:
>
>   git://git.kernel.org/pub/scm/linux/kernel/git/jassibrar/mailbox.git
> tags/mailbox-v6.19

No.

This is now the second pull request I get today that came in late in
the merge window. Rebased today, because the first version didn't even
build.

Do it right, do it timely, and don't send me crap that was rebased the
same day because it wasn't ready before the merge window started.

In other words - do it next merge window.

          Linus


From andyshrk at 163.com  Wed Dec 10 19:45:31 2025
From: andyshrk at 163.com (Andy Yan)
Date: Thu, 11 Dec 2025 11:45:31 +0800 (CST)
Subject: [PATCH v3 6/8] drm/rockchip: vop2: Enforce AFBC transform stride
 align in plane_check
In-Reply-To: <20251209-vop2-atomic-fixups-v3-6-07c48f0f1f0d@collabora.com>
References: <20251209-vop2-atomic-fixups-v3-0-07c48f0f1f0d@collabora.com>
 <20251209-vop2-atomic-fixups-v3-6-07c48f0f1f0d@collabora.com>
Message-ID: <6aed0bff.3ccf.19b0b839621.Coremail.andyshrk@163.com>


Hello Nicolas?

At 2025-12-09 19:14:19, "Nicolas Frattaroli" <nicolas.frattaroli at collabora.com> wrote:
>From: Daniel Stone <daniels at collabora.com>
>
>Make sure we can't break the hardware by requesting an unsupported
>configuration.
>
>Signed-off-by: Daniel Stone <daniels at collabora.com>
>Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
>---
> drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 12 +++++++++---
> 1 file changed, 9 insertions(+), 3 deletions(-)
>
>diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
>index a029ed73dda7..337b01ed29a6 100644
>--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
>+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
>@@ -1083,6 +1083,15 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
> 		return -EINVAL;
> 	}
> 
>+	if (drm_is_afbc(fb->modifier) &&
>+	    pstate->rotation &
>+		(DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270) &&
>+	    (fb->pitches[0] << 3) / vop2_get_bpp(fb->format) % 64) {
>+		drm_dbg_kms(vop2->drm,
>+			    "AFBC buffers must be 64-byte aligned for horizontal rotation or mirroring\n");
>+		return -EINVAL;
>+	}

As Diederik previously pointed out?s/64-byte/64 pixel/ 

>+
> 	return 0;
> }
> 
>@@ -1290,9 +1299,6 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
> 		 * with WIN_VIR_STRIDE.
> 		 */
> 		stride = (fb->pitches[0] << 3) / bpp;
>-		if ((stride & 0x3f) && (xmirror || rotate_90 || rotate_270))
>-			drm_dbg_kms(vop2->drm, "vp%d %s stride[%d] not 64 pixel aligned\n",
>-				    vp->id, win->data->name, stride);
> 
> 		 /* It's for head stride, each head size is 16 byte */
> 		stride = ALIGN(stride, block_w) / block_w * 16;
>
>-- 
>2.52.0

From vulab at iscas.ac.cn  Wed Dec 10 20:02:52 2025
From: vulab at iscas.ac.cn (Wentao Liang)
Date: Thu, 11 Dec 2025 04:02:52 +0000
Subject: [PATCH v4] pmdomain: imx: Fix reference count leak in imx_gpc_probe()
Message-ID: <20251211040252.497759-1-vulab@iscas.ac.cn>

of_get_child_by_name() returns a node pointer with refcount incremented.
Use the __free() attribute to manage the pgc_node reference, ensuring
automatic of_node_put() cleanup when pgc_node goes out of scope.

This eliminates the need for explicit error handling paths and avoids
reference count leaks.

Fixes: 721cabf6c660 ("soc: imx: move PGC handling to a new GPC driver")
Cc: stable at vger.kernel.org
Signed-off-by: Wentao Liang <vulab at iscas.ac.cn>

---
Change in V4:
- Fix typo error in code

Change in V3:
- Ensure variable is assigned when using cleanup attribute

Change in V2:
- Use __free() attribute instead of explicit of_node_put() calls
---
 drivers/pmdomain/imx/gpc.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/pmdomain/imx/gpc.c b/drivers/pmdomain/imx/gpc.c
index f18c7e6e75dd..56a78cc86584 100644
--- a/drivers/pmdomain/imx/gpc.c
+++ b/drivers/pmdomain/imx/gpc.c
@@ -403,13 +403,12 @@ static int imx_gpc_old_dt_init(struct device *dev, struct regmap *regmap,
 static int imx_gpc_probe(struct platform_device *pdev)
 {
 	const struct imx_gpc_dt_data *of_id_data = device_get_match_data(&pdev->dev);
-	struct device_node *pgc_node;
+	struct device_node *pgc_node __free(device_node)
+		= of_get_child_by_name(pdev->dev.of_node, "pgc");
 	struct regmap *regmap;
 	void __iomem *base;
 	int ret;
 
-	pgc_node = of_get_child_by_name(pdev->dev.of_node, "pgc");
-
 	/* bail out if DT too old and doesn't provide the necessary info */
 	if (!of_property_present(pdev->dev.of_node, "#power-domain-cells") &&
 	    !pgc_node)
-- 
2.34.1



From xieyuanbin1 at huawei.com  Wed Dec 10 20:07:08 2025
From: xieyuanbin1 at huawei.com (Xie Yuanbin)
Date: Thu, 11 Dec 2025 12:07:08 +0800
Subject: [PATCH 0/3] ARM: fix hash_name() and branch predictor issues
In-Reply-To: <aTmNrPVmd7sG7J8s@shell.armlinux.org.uk>
References: <aTmNrPVmd7sG7J8s@shell.armlinux.org.uk>
Message-ID: <20251211040708.187155-1-xieyuanbin1@huawei.com>

On Wed, 10 Dec 2025 15:11:40 +0000, Russell King wrote:
> Thanks. I've updated the three patches, and pushed out the updated
> tree. See the top four commits:
>
> https://git.kernel.org/pub/scm/linux/kernel/git/rmk/linux.git/log/?h=fixes
>
> Given the timings, I doubt that linux-next will pick this up before
> I need to send Linus a pull request before going on vacation for the
> remainder of this year:
>
> https://git.kernel.org/pub/scm/linux/kernel/git/rmk/linux.git/log/?h=for-linus
>
> However, I also can't guarantee that I'll be able to look at mainline
> at the start of next year due to other pressures - and I don't yet
> know for how long that's likely to be at the moment.
>
> So, it's either a pull request for the for-linus tag later today,
> at some point next year likely not before mid-January and splitting
> it up into fixes (for -rc) and the two PREEMPT_RT non-fix patches (for
> the next merge window.)

Thanks! These patches seem to have been merged into the linux-next branch.

By the way, before the PREEMPT_RT enabled patch are finally merged,
something like this should be applied first:
Link: https://lore.kernel.org/20251127140109.191657-2-xieyuanbin1 at huawei.com

I believe you won't forget this, but I currently don't see it in any patch
queue/list/system. Therefore, out of caution, I still sent this email.


From ardb at kernel.org  Wed Dec 10 20:09:36 2025
From: ardb at kernel.org (Ard Biesheuvel)
Date: Thu, 11 Dec 2025 05:09:36 +0100
Subject: [RFC PATCH] arm64: Bring back linear map randomization using PArange override
Message-ID: <20251211040935.1288349-2-ardb@kernel.org>

Commit

  1db780bafa4ce ("arm64/mm: Remove randomization of the linear map")

removed linear map randomization from the arm64 port, on the basis that
a prior change to the logic rendered it non-functional on the majority
of relevant CPU implementations.

As has been reported numerous times now, the upshot of this is that the
virtual addresses of statically allocated kernel data structures are
highly predictable if the kernel is loaded at a known physical address.
Any bootloader that still adheres to the original arm64 boot protocol,
which stipulated that the kernel should be loaded at the lowest
available physical address, is affected by this.

So bring back the most recent version of linear map randomization, which
is based on the CPU's physical address range, but this time, allow this
PA range to be overridden on the kernel command line.

E.g., by passing

  id_aa64mmfr0.parange=1 # 36 bits
  id_aa64mmfr0.parange=2 # 40 bits

the CPU's supported physical range can be reduced to the point where
linear map randomization becomes feasible again. It also means that
nothing else is permitted to appear in that physical window, i.e.,
hotplug memory but also non-memory peripherals, or stage-2 mappings on
behalf of KVM guests.

Signed-off-by: Ard Biesheuvel <ardb at kernel.org>
---
Cc: Liz Prucka <lizprucka at google.com>
Cc: Seth Jenkins <sethjenkins at google.com>

This is posted as an RFC because there are obvious shortcomings to this
approach. However, before I spend more time on this, I'd like to gauge
if there is any consensus that bringing this back is a good idea.

 arch/arm64/include/asm/cpufeature.h   | 13 +++++++++++++
 arch/arm64/kernel/image-vars.h        |  1 +
 arch/arm64/kernel/kaslr.c             |  2 ++
 arch/arm64/kernel/pi/idreg-override.c |  1 +
 arch/arm64/kernel/pi/kaslr_early.c    |  4 ++++
 arch/arm64/mm/init.c                  | 16 ++++++++++++++++
 6 files changed, 37 insertions(+)

diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index 4de51f8d92cb..fdb1331c406d 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -1078,6 +1078,19 @@ static inline bool cpu_has_lpa2(void)
 #endif
 }
 
+static inline u64 cpu_get_phys_range(void)
+{
+	u64 mmfr0 = read_sysreg(id_aa64mmfr0_el1);
+
+	mmfr0 &= ~id_aa64mmfr0_override.mask;
+	mmfr0 |= id_aa64mmfr0_override.val;
+
+	int parange = cpuid_feature_extract_unsigned_field(mmfr0,
+						ID_AA64MMFR0_EL1_PARANGE_SHIFT);
+
+	return BIT(id_aa64mmfr0_parange_to_phys_shift(parange));
+}
+
 #endif /* __ASSEMBLER__ */
 
 #endif
diff --git a/arch/arm64/kernel/image-vars.h b/arch/arm64/kernel/image-vars.h
index 85bc629270bd..263543ad6155 100644
--- a/arch/arm64/kernel/image-vars.h
+++ b/arch/arm64/kernel/image-vars.h
@@ -58,6 +58,7 @@ PI_EXPORT_SYM(id_aa64zfr0_override);
 PI_EXPORT_SYM(arm64_sw_feature_override);
 PI_EXPORT_SYM(arm64_use_ng_mappings);
 PI_EXPORT_SYM(_ctype);
+PI_EXPORT_SYM(memstart_offset_seed);
 
 PI_EXPORT_SYM(swapper_pg_dir);
 
diff --git a/arch/arm64/kernel/kaslr.c b/arch/arm64/kernel/kaslr.c
index c9503ed45a6c..1da3e25f9d9e 100644
--- a/arch/arm64/kernel/kaslr.c
+++ b/arch/arm64/kernel/kaslr.c
@@ -10,6 +10,8 @@
 #include <asm/cpufeature.h>
 #include <asm/memory.h>
 
+u16 __initdata memstart_offset_seed;
+
 bool __ro_after_init __kaslr_is_enabled = false;
 
 void __init kaslr_init(void)
diff --git a/arch/arm64/kernel/pi/idreg-override.c b/arch/arm64/kernel/pi/idreg-override.c
index bc57b290e5e7..a8351ba70300 100644
--- a/arch/arm64/kernel/pi/idreg-override.c
+++ b/arch/arm64/kernel/pi/idreg-override.c
@@ -43,6 +43,7 @@ static const struct ftr_set_desc mmfr0 __prel64_initconst = {
 	.override	= &id_aa64mmfr0_override,
 	.fields		= {
 		FIELD("ecv", ID_AA64MMFR0_EL1_ECV_SHIFT, NULL),
+		FIELD("parange", ID_AA64MMFR0_EL1_PARANGE_SHIFT, NULL),
 		{}
 	},
 };
diff --git a/arch/arm64/kernel/pi/kaslr_early.c b/arch/arm64/kernel/pi/kaslr_early.c
index e0e018046a46..0257b43819db 100644
--- a/arch/arm64/kernel/pi/kaslr_early.c
+++ b/arch/arm64/kernel/pi/kaslr_early.c
@@ -18,6 +18,8 @@
 
 #include "pi.h"
 
+extern u16 memstart_offset_seed;
+
 static u64 __init get_kaslr_seed(void *fdt, int node)
 {
 	static char const seed_str[] __initconst = "kaslr-seed";
@@ -51,6 +53,8 @@ u64 __init kaslr_early_init(void *fdt, int chosen)
 			return 0;
 	}
 
+	memstart_offset_seed = seed & U16_MAX;
+
 	/*
 	 * OK, so we are proceeding with KASLR enabled. Calculate a suitable
 	 * kernel image offset from the seed. Let's place the kernel in the
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 524d34a0e921..6c55eca6ccad 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -275,6 +275,22 @@ void __init arm64_memblock_init(void)
 		}
 	}
 
+	if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
+		extern u16 memstart_offset_seed;
+		s64 range = linear_region_size - cpu_get_phys_range();
+
+		/*
+		 * If the size of the linear region exceeds, by a sufficient
+		 * margin, the size of the region that the physical memory can
+		 * span, randomize the linear region as well.
+		 */
+		if (memstart_offset_seed > 0 && range >= (s64)ARM64_MEMSTART_ALIGN) {
+			range /= ARM64_MEMSTART_ALIGN;
+			memstart_addr -= ARM64_MEMSTART_ALIGN *
+					 ((range * memstart_offset_seed) >> 16);
+		}
+	}
+
 	/*
 	 * Register the kernel text, kernel data, initrd, and initial
 	 * pagetables with memblock.
-- 
2.47.3



From nicolinc at nvidia.com  Wed Dec 10 22:09:05 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Wed, 10 Dec 2025 22:09:05 -0800
Subject: [PATCH V4 1/3] iommu/arm-smmu-v3: Add device-tree support for
 CMDQV driver
In-Reply-To: <e7c69e9c-6af4-468a-88ed-fb8829afb92e@arm.com>
References: <20251205065850.3841834-2-amhetre@nvidia.com>
 <202512090331.QAFgb6vQ-lkp@intel.com>
 <2bf7bb25-9a6b-42d5-b095-978f7bb81f35@nvidia.com>
 <e7c69e9c-6af4-468a-88ed-fb8829afb92e@arm.com>
Message-ID: <aTpgAU6FjinhclQH@nvidia.com>

On Wed, Dec 10, 2025 at 12:39:49PM +0000, Robin Murphy wrote:
> On 2025-12-10 5:19 am, Ashish Mhetre wrote:
> [...]
> > Hi Robin, Nic,
> > We removed ACPI dependency in Kconfig but driver still depends
> > on ACPI for these functions. I will be protecting ACPIspecific
> > tegra241-cmdqv code under CONFIG_ACPI similar to what is done
> > in arm-smmu-v3 driver. Is this the correct thing to do or do you
> > have any other suggestions?
> 
> Yes, when I commented that "depends on ACPI || OF" was functionally the same
> as just removing "depends on ACPI", I didn't mean to suggest that wasn't
> necessarily a genuine dependency still.
> 
> I guess if you can wrap the ACPI-specific functions in a single #ifdef block
> that's reasonable, however I do now wonder whether things couldn't be
> factored out a bit more - if it's a standard DSDT/SSDT namespace device,
> shouldn't there also be a corresponding platform device created for it,
> which we could look up instead of delving directly into the _CRS of the ACPI
> node itself? (not sure off-hand if there's a straightforward inverse of
> ACPI_COMPANION()...)

Ah, I did a quick tracer at acpi_create_platform_device(). And I
do see platform devices being created. So, we could have made it
ACPI-independent from the beginning, as you expected :)

Ashish, let's attach the following patch in your series:

>From 7b69a638276e66b16b923b0ce1743d3efc85a04c Mon Sep 17 00:00:00 2001
From: Nicolin Chen <nicolinc at nvidia.com>
Date: Thu, 11 Dec 2025 05:47:05 +0000
Subject: [PATCH] iommu/tegra241-cmdqv: Decouple driver from ACPI

A platform device is created by acpi_create_platform_device() per CMDQV's
adev. That means there is no point in going through _CRS of ACPI.

Replace all the ACPI functions with standard platform functions. And drop
all ACPI dependencies. This will make the driver compatible with DT also.

Suggested-by: Robin Murphy <robin.murphy at arm.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/Kconfig                     |  1 -
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   |  2 +-
 .../iommu/arm/arm-smmu-v3/tegra241-cmdqv.c    | 84 +++----------------
 3 files changed, 13 insertions(+), 74 deletions(-)

diff --git a/drivers/iommu/arm/Kconfig b/drivers/iommu/arm/Kconfig
index ef42bbe07dbef..5fac08b89deea 100644
--- a/drivers/iommu/arm/Kconfig
+++ b/drivers/iommu/arm/Kconfig
@@ -121,7 +121,6 @@ config ARM_SMMU_V3_KUNIT_TEST
 
 config TEGRA241_CMDQV
 	bool "NVIDIA Tegra241 CMDQ-V extension support for ARM SMMUv3"
-	depends on ACPI
 	help
 	  Support for NVIDIA CMDQ-Virtualization extension for ARM SMMUv3. The
 	  CMDQ-V extension is similar to v3.3 ECMDQ for multi command queues
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 38028e4a52f7f..0c98be3135c63 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -5280,7 +5280,7 @@ static void acpi_smmu_dsdt_probe_tegra241_cmdqv(struct acpi_iort_node *node,
 	adev = acpi_dev_get_first_match_dev("NVDA200C", uid, -1);
 	if (adev) {
 		/* Tegra241 CMDQV driver is responsible for put_device() */
-		smmu->impl_dev = &adev->dev;
+		smmu->impl_dev = acpi_get_first_physical_node(adev);
 		smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
 		dev_info(smmu->dev, "found companion CMDQV device: %s\n",
 			 dev_name(smmu->impl_dev));
diff --git a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
index 378104cd395e5..1fc03b72beb88 100644
--- a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
+++ b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
@@ -3,17 +3,15 @@
 
 #define dev_fmt(fmt) "tegra241_cmdqv: " fmt
 
-#include <linux/acpi.h>
 #include <linux/debugfs.h>
 #include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
 #include <linux/iommu.h>
 #include <linux/iommufd.h>
 #include <linux/iopoll.h>
+#include <linux/platform_device.h>
 #include <uapi/linux/iommufd.h>
 
-#include <acpi/acpixf.h>
-
 #include "arm-smmu-v3.h"
 
 /* CMDQV register page base and size defines */
@@ -854,69 +852,6 @@ static struct arm_smmu_impl_ops tegra241_cmdqv_impl_ops = {
 
 /* Probe Functions */
 
-static int tegra241_cmdqv_acpi_is_memory(struct acpi_resource *res, void *data)
-{
-	struct resource_win win;
-
-	return !acpi_dev_resource_address_space(res, &win);
-}
-
-static int tegra241_cmdqv_acpi_get_irqs(struct acpi_resource *ares, void *data)
-{
-	struct resource r;
-	int *irq = data;
-
-	if (*irq <= 0 && acpi_dev_resource_interrupt(ares, 0, &r))
-		*irq = r.start;
-	return 1; /* No need to add resource to the list */
-}
-
-static struct resource *
-tegra241_cmdqv_find_acpi_resource(struct device *dev, int *irq)
-{
-	struct acpi_device *adev = to_acpi_device(dev);
-	struct list_head resource_list;
-	struct resource_entry *rentry;
-	struct resource *res = NULL;
-	int ret;
-
-	INIT_LIST_HEAD(&resource_list);
-	ret = acpi_dev_get_resources(adev, &resource_list,
-				     tegra241_cmdqv_acpi_is_memory, NULL);
-	if (ret < 0) {
-		dev_err(dev, "failed to get memory resource: %d\n", ret);
-		return NULL;
-	}
-
-	rentry = list_first_entry_or_null(&resource_list,
-					  struct resource_entry, node);
-	if (!rentry) {
-		dev_err(dev, "failed to get memory resource entry\n");
-		goto free_list;
-	}
-
-	/* Caller must free the res */
-	res = kzalloc(sizeof(*res), GFP_KERNEL);
-	if (!res)
-		goto free_list;
-
-	*res = *rentry->res;
-
-	acpi_dev_free_resource_list(&resource_list);
-
-	INIT_LIST_HEAD(&resource_list);
-
-	if (irq)
-		ret = acpi_dev_get_resources(adev, &resource_list,
-					     tegra241_cmdqv_acpi_get_irqs, irq);
-	if (ret < 0 || !irq || *irq <= 0)
-		dev_warn(dev, "no interrupt. errors will not be reported\n");
-
-free_list:
-	acpi_dev_free_resource_list(&resource_list);
-	return res;
-}
-
 static int tegra241_cmdqv_init_structures(struct arm_smmu_device *smmu)
 {
 	struct tegra241_cmdqv *cmdqv =
@@ -1042,18 +977,23 @@ __tegra241_cmdqv_probe(struct arm_smmu_device *smmu, struct resource *res,
 
 struct arm_smmu_device *tegra241_cmdqv_probe(struct arm_smmu_device *smmu)
 {
+	struct platform_device *pdev = to_platform_device(smmu->impl_dev);
 	struct arm_smmu_device *new_smmu;
-	struct resource *res = NULL;
+	struct resource *res;
 	int irq;
 
-	if (!smmu->dev->of_node)
-		res = tegra241_cmdqv_find_acpi_resource(smmu->impl_dev, &irq);
-	if (!res)
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "no memory resource found for CMDQV\n");
 		goto out_fallback;
+	}
 
-	new_smmu = __tegra241_cmdqv_probe(smmu, res, irq);
-	kfree(res);
+	irq = platform_get_irq_optional(pdev, 0);
+	if (irq <= 0)
+		dev_warn(&pdev->dev,
+			 "no interrupt. errors will not be reported\n");
 
+	new_smmu = __tegra241_cmdqv_probe(smmu, res, irq);
 	if (new_smmu)
 		return new_smmu;
 
-- 
2.43.0


From jie.gan at oss.qualcomm.com  Wed Dec 10 22:10:39 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Thu, 11 Dec 2025 14:10:39 +0800
Subject: [PATCH v8 0/8] coresight: ctcu: Enable byte-cntr function for TMC
 ETR
Message-ID: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>

The byte-cntr function provided by the CTCU device is used to count the
trace data entering the ETR. An interrupt is triggered if the data size
exceeds the threshold set in the BYTECNTRVAL register. The interrupt
handler counts the number of triggered interruptions.

Based on this concept, the irq_cnt can be used to determine whether
the etr_buf is full. The ETR device will be disabled when the active
etr_buf is nearly full or a timeout occurs. The nearly full buffer will
be switched to background after synced. A new buffer will be picked from
the etr_buf_list, then restart the ETR device.

The byte-cntr reading functions can access data from the synced and
deactivated buffer, transferring trace data from the etr_buf to userspace
without stopping the ETR device.

The byte-cntr read operation has integrated with the file node tmc_etr,
for example:
/dev/tmc_etr0
/dev/tmc_etr1

There are two scenarios for the tmc_etr file node with byte-cntr function:
1. BYTECNTRVAL register is configured and byte-cntr is enabled -> byte-cntr read
2. BYTECNTRVAL register is reset or byte-cntr is disabled -> original behavior

Shell commands to enable byte-cntr reading for etr0:
echo 0x10000 > /sys/bus/coresight/devices/ctcu0/irq_threshold
echo 1 > /sys/bus/coresight/devices/tmc_etr0/enable_sink
echo 1 > /sys/bus/coresight/devices/etm0/enable_source
cat /dev/tmc_etr0

Enable both ETR0 and ETR1:
echo 0x10000 0x10000 > /sys/bus/coresight/devices/ctcu0/irq_threshold

Reset the BYTECNTR register for etr0:
echo 0 > /sys/bus/coresight/devices/ctcu0/irq_threshold

Changes in V8:
1. Optimizing the patch 1 and patch 2 according to Suzuki's comments.
2. Combine the patch 3 and patch 4 together.
3. Rename the interrupt-name to prevent confusion, for example:etr0->etrirq0.
Link to V7 - https://lore.kernel.org/all/20251013-enable-byte-cntr-for-ctcu-v7-0-e1e8f41e15dd at oss.qualcomm.com/

Changes in V7:
1. rebased on tag next-20251010
2. updated info for sysfs node document
Link to V6 - https://lore.kernel.org/all/20250908-enable-byte-cntr-for-tmc-v6-0-1db9e621441a at oss.qualcomm.com/

Changes in V6:
1. rebased on next-20250905.
2. fixed the issue that the dtsi file has re-named from sa8775p.dtsi to
   lemans.dtsi.
3. fixed some minor issues about comments.
Link to V5 - https://lore.kernel.org/all/20250812083731.549-1-jie.gan at oss.qualcomm.com/

Changes in V5:
1. Add Mike's reviewed-by tag for patchset 1,2,5.
2. Remove the function pointer added to helper_ops according to Mike's
   comment, it also results the patchset has been removed.
3. Optimizing the paired create/clean functions for etr_buf_list.
4. Remove the unneeded parameter "reading" from the etr_buf_node.
Link to V4 - https://lore.kernel.org/all/20250725100806.1157-1-jie.gan at oss.qualcomm.com/

Changes in V4:
1. Rename the function to coresight_get_in_port_dest regarding to Mike's
comment (patch 1/10).
2. Add lock to protect the connections regarding to Mike's comment
(patch 2/10).
3. Move all byte-cntr functions to coresight-ctcu-byte-cntr file.
4. Add tmc_read_ops to wrap all read operations for TMC device.
5. Add a function in helper_ops to check whether the byte-cntr is
enabkled.
6. Call byte-cntr's read_ops if byte-cntr is enabled when reading data
from the sysfs node.
Link to V3 resend - https://lore.kernel.org/all/20250714063109.591-1-jie.gan at oss.qualcomm.com/

Changes in V3 resend:
1. rebased on next-20250711.
Link to V3 - https://lore.kernel.org/all/20250624060438.7469-1-jie.gan at oss.qualcomm.com/

Changes in V3:
1. The previous solution has been deprecated.
2. Add a etr_buf_list to manage allcated etr buffers.
3. Add a logic to switch buffer for ETR.
4. Add read functions to read trace data from synced etr buffer.
Link to V2 - https://lore.kernel.org/all/20250410013330.3609482-1-jie.gan at oss.qualcomm.com/

Changes in V2:
1. Removed the independent file node /dev/byte_cntr.
2. Integrated the byte-cntr's file operations with current ETR file
   node.
3. Optimized the driver code of the CTCU that associated with byte-cntr.
4. Add kernel document for the export API tmc_etr_get_rwp_offset.
5. Optimized the way to read the rwp_offset according to Mike's
   suggestion.
6. Removed the dependency of the dts patch.
Link to V1 - https://lore.kernel.org/all/20250310090407.2069489-1-quic_jiegan at quicinc.com/

Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
Jie Gan (8):
      coresight: core: Refactoring ctcu_get_active_port and make it generic
      coresight: core: add a new API to retrieve the helper device
      coresight: tmc: add create/clean functions for etr_buf_list
      coresight: tmc: Introduce sysfs_read_ops to wrap sysfs read operations
      dt-bindings: arm: add an interrupt property for Coresight CTCU
      coresight: ctcu: enable byte-cntr for TMC ETR devices
      coresight: tmc: integrate byte-cntr's read_ops with sysfs file_ops
      arm64: dts: qcom: lemans: Add interrupts to CTCU device

 .../ABI/testing/sysfs-bus-coresight-devices-ctcu   |   6 +
 .../bindings/arm/qcom,coresight-ctcu.yaml          |  17 +
 arch/arm64/boot/dts/qcom/lemans.dtsi               |   5 +
 drivers/hwtracing/coresight/Makefile               |   2 +-
 drivers/hwtracing/coresight/coresight-core.c       |  59 ++++
 .../hwtracing/coresight/coresight-ctcu-byte-cntr.c | 368 +++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-ctcu-core.c  | 107 ++++--
 drivers/hwtracing/coresight/coresight-ctcu.h       |  62 +++-
 drivers/hwtracing/coresight/coresight-priv.h       |   4 +
 drivers/hwtracing/coresight/coresight-tmc-core.c   | 104 ++++--
 drivers/hwtracing/coresight/coresight-tmc-etr.c    | 112 +++++++
 drivers/hwtracing/coresight/coresight-tmc.h        |  37 +++
 12 files changed, 824 insertions(+), 59 deletions(-)
---
base-commit: 47b7b5e32bb7264b51b89186043e1ada4090b558
change-id: 20251203-enable-byte-cntr-for-ctcu-5a4b88f2feb9

Best regards,
-- 
Jie Gan <jie.gan at oss.qualcomm.com>



From jie.gan at oss.qualcomm.com  Wed Dec 10 22:10:40 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Thu, 11 Dec 2025 14:10:40 +0800
Subject: [PATCH v8 1/8] coresight: core: Refactoring ctcu_get_active_port
 and make it generic
In-Reply-To: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
References: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
Message-ID: <20251211-enable-byte-cntr-for-ctcu-v8-1-3e12ff313191@oss.qualcomm.com>

Remove ctcu_get_active_port from CTCU module and add it to the core
framework.

The port number is crucial for the CTCU device to identify which ETR
it serves. With the port number we can correctly get required parameters
of the CTCU device in TMC module.

Reviewed-by: Mike Leach <mike.leach at linaro.org>
Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 drivers/hwtracing/coresight/coresight-core.c      | 24 +++++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-ctcu-core.c | 19 +-----------------
 drivers/hwtracing/coresight/coresight-priv.h      |  2 ++
 3 files changed, 27 insertions(+), 18 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index c660cf8adb1c..0e8448784c62 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -585,6 +585,30 @@ struct coresight_device *coresight_get_sink(struct coresight_path *path)
 }
 EXPORT_SYMBOL_GPL(coresight_get_sink);
 
+/**
+ * coresight_get_in_port: Find the input port number at @csdev where a @remote
+ * device is connected to.
+ *
+ * @csdev: csdev of the device.
+ * @remote: csdev of the remote device which is connected to @csdev.
+ *
+ * Return: port number upon success or -EINVAL for fail.
+ */
+int coresight_get_in_port(struct coresight_device *csdev,
+			  struct coresight_device *remote)
+{
+	struct coresight_platform_data *pdata = remote->pdata;
+	int i;
+
+	for (i = 0; i < pdata->nr_inconns; ++i) {
+		if (pdata->in_conns[i]->src_dev == csdev)
+			return pdata->in_conns[i]->dest_port;
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(coresight_get_in_port);
+
 u32 coresight_get_sink_id(struct coresight_device *csdev)
 {
 	if (!csdev->ea)
diff --git a/drivers/hwtracing/coresight/coresight-ctcu-core.c b/drivers/hwtracing/coresight/coresight-ctcu-core.c
index abed15eb72b4..78be783b3cb2 100644
--- a/drivers/hwtracing/coresight/coresight-ctcu-core.c
+++ b/drivers/hwtracing/coresight/coresight-ctcu-core.c
@@ -118,23 +118,6 @@ static int __ctcu_set_etr_traceid(struct coresight_device *csdev, u8 traceid, in
 	return 0;
 }
 
-/*
- * Searching the sink device from helper's view in case there are multiple helper devices
- * connected to the sink device.
- */
-static int ctcu_get_active_port(struct coresight_device *sink, struct coresight_device *helper)
-{
-	struct coresight_platform_data *pdata = helper->pdata;
-	int i;
-
-	for (i = 0; i < pdata->nr_inconns; ++i) {
-		if (pdata->in_conns[i]->src_dev == sink)
-			return pdata->in_conns[i]->dest_port;
-	}
-
-	return -EINVAL;
-}
-
 static int ctcu_set_etr_traceid(struct coresight_device *csdev, struct coresight_path *path,
 				bool enable)
 {
@@ -147,7 +130,7 @@ static int ctcu_set_etr_traceid(struct coresight_device *csdev, struct coresight
 		return -EINVAL;
 	}
 
-	port_num = ctcu_get_active_port(sink, csdev);
+	port_num = coresight_get_in_port(sink, csdev);
 	if (port_num < 0)
 		return -EINVAL;
 
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
index fd896ac07942..cbf80b83e5ce 100644
--- a/drivers/hwtracing/coresight/coresight-priv.h
+++ b/drivers/hwtracing/coresight/coresight-priv.h
@@ -155,6 +155,8 @@ void coresight_remove_links(struct coresight_device *orig,
 u32 coresight_get_sink_id(struct coresight_device *csdev);
 void coresight_path_assign_trace_id(struct coresight_path *path,
 				   enum cs_mode mode);
+int coresight_get_in_port(struct coresight_device *csdev,
+			  struct coresight_device *remote);
 
 #if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM3X)
 int etm_readl_cp14(u32 off, unsigned int *val);

-- 
2.34.1



From jie.gan at oss.qualcomm.com  Wed Dec 10 22:10:41 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Thu, 11 Dec 2025 14:10:41 +0800
Subject: [PATCH v8 2/8] coresight: core: add a new API to retrieve the
 helper device
In-Reply-To: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
References: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
Message-ID: <20251211-enable-byte-cntr-for-ctcu-v8-2-3e12ff313191@oss.qualcomm.com>

Retrieving the helper device of the specific coresight device based on
its helper_subtype because a single coresight device may has multiple types
of the helper devices.

Reviewed-by: Mike Leach <mike.leach at linaro.org>
Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 drivers/hwtracing/coresight/coresight-core.c | 35 ++++++++++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-priv.h |  2 ++
 2 files changed, 37 insertions(+)

diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 0e8448784c62..667883ccb4b7 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -585,6 +585,41 @@ struct coresight_device *coresight_get_sink(struct coresight_path *path)
 }
 EXPORT_SYMBOL_GPL(coresight_get_sink);
 
+/**
+ * coresight_get_helper: find the helper device of the assigned csdev.
+ *
+ * @csdev: The csdev the helper device is conntected to.
+ * @type:  helper_subtype of the expected helper device.
+ *
+ * Retrieve the helper device for the specific csdev based on its
+ * helper_subtype.
+ *
+ * Return: the helper's csdev upon success or NULL for fail.
+ */
+struct coresight_device *coresight_get_helper(struct coresight_device *csdev,
+					      enum coresight_dev_subtype_helper subtype)
+{
+	int i;
+	struct coresight_device *helper;
+
+	/* protect the connections */
+	mutex_lock(&coresight_mutex);
+	for (i = 0; i < csdev->pdata->nr_outconns; ++i) {
+		helper = csdev->pdata->out_conns[i]->dest_dev;
+		if (!helper || !coresight_is_helper(helper))
+			continue;
+
+		if (helper->subtype.helper_subtype == subtype) {
+			mutex_unlock(&coresight_mutex);
+			return helper;
+		}
+	}
+	mutex_unlock(&coresight_mutex);
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(coresight_get_helper);
+
 /**
  * coresight_get_in_port: Find the input port number at @csdev where a @remote
  * device is connected to.
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
index cbf80b83e5ce..8e39a4dc7256 100644
--- a/drivers/hwtracing/coresight/coresight-priv.h
+++ b/drivers/hwtracing/coresight/coresight-priv.h
@@ -157,6 +157,8 @@ void coresight_path_assign_trace_id(struct coresight_path *path,
 				   enum cs_mode mode);
 int coresight_get_in_port(struct coresight_device *csdev,
 			  struct coresight_device *remote);
+struct coresight_device *coresight_get_helper(struct coresight_device *csdev,
+					      enum coresight_dev_subtype_helper subtype);
 
 #if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM3X)
 int etm_readl_cp14(u32 off, unsigned int *val);

-- 
2.34.1



From jie.gan at oss.qualcomm.com  Wed Dec 10 22:10:42 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Thu, 11 Dec 2025 14:10:42 +0800
Subject: [PATCH v8 3/8] coresight: tmc: add create/clean functions for
 etr_buf_list
In-Reply-To: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
References: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
Message-ID: <20251211-enable-byte-cntr-for-ctcu-v8-3-3e12ff313191@oss.qualcomm.com>

Introduce functions for creating and inserting or removing the
etr_buf_node to/from the etr_buf_list.

The byte-cntr functionality requires two etr_buf to receive trace data.
The active etr_buf collects the trace data from source device, while the
byte-cntr reading function accesses the deactivated etr_buf after is
has been filled and synced, transferring data to the userspace.

Reviewed-by: Mike Leach <mike.leach at linaro.org>
Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 drivers/hwtracing/coresight/coresight-tmc-core.c |  1 +
 drivers/hwtracing/coresight/coresight-tmc-etr.c  | 94 ++++++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-tmc.h      | 19 +++++
 3 files changed, 114 insertions(+)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c
index 36599c431be6..1ea255ffa67c 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-core.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-core.c
@@ -840,6 +840,7 @@ static int __tmc_probe(struct device *dev, struct resource *res)
 		idr_init(&drvdata->idr);
 		mutex_init(&drvdata->idr_mutex);
 		dev_list = &etr_devs;
+		INIT_LIST_HEAD(&drvdata->etr_buf_list);
 		break;
 	case TMC_CONFIG_TYPE_ETF:
 		desc.groups = coresight_etf_groups;
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index e0d83ee01b77..2b6ca1f8bed2 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -1919,6 +1919,100 @@ const struct coresight_ops tmc_etr_cs_ops = {
 	.panic_ops	= &tmc_etr_sync_ops,
 };
 
+/**
+ * tmc_clean_etr_buf_list - clean the etr_buf_list.
+ * @drvdata:	driver data of the TMC device.
+ *
+ * Remove the allocated node from the list and free the extra buffer.
+ */
+void tmc_clean_etr_buf_list(struct tmc_drvdata *drvdata)
+{
+	struct etr_buf_node *nd, *next;
+
+	list_for_each_entry_safe(nd, next, &drvdata->etr_buf_list, node) {
+		if (nd->sysfs_buf == drvdata->sysfs_buf) {
+			if (coresight_get_mode(drvdata->csdev) == CS_MODE_DISABLED) {
+				drvdata->sysfs_buf = NULL;
+				tmc_free_etr_buf(nd->sysfs_buf);
+				nd->sysfs_buf = NULL;
+			}
+			list_del(&nd->node);
+			kfree(nd);
+		} else {
+			/* Free allocated buffers which are not utilized by ETR */
+			list_del(&nd->node);
+			tmc_free_etr_buf(nd->sysfs_buf);
+			nd->sysfs_buf = NULL;
+			kfree(nd);
+		}
+	}
+}
+EXPORT_SYMBOL_GPL(tmc_clean_etr_buf_list);
+
+/**
+ * tmc_create_etr_buf_list - create a list to manage the etr_buf_node.
+ * @drvdata:	driver data of the TMC device.
+ * @num_nodes:	number of nodes want to create with the list.
+ *
+ * Return 0 upon success and return the error number if fail.
+ */
+int tmc_create_etr_buf_list(struct tmc_drvdata *drvdata, int num_nodes)
+{
+	struct etr_buf_node *new_node;
+	struct etr_buf *sysfs_buf;
+	int i = 0, ret = 0;
+
+	/* We dont need a list if there is only one node */
+	if (num_nodes < 2)
+		return -EINVAL;
+
+	/* We expect that sysfs_buf in drvdata has already been allocated. */
+	if (drvdata->sysfs_buf) {
+		/* Directly insert the allocated sysfs_buf into the list first */
+		new_node = kzalloc(sizeof(struct etr_buf_node), GFP_KERNEL);
+		if (IS_ERR(new_node))
+			return PTR_ERR(new_node);
+
+		new_node->sysfs_buf = drvdata->sysfs_buf;
+		new_node->is_free = false;
+		list_add(&new_node->node, &drvdata->etr_buf_list);
+		i++;
+	}
+
+	while (i < num_nodes) {
+		new_node = kzalloc(sizeof(struct etr_buf_node), GFP_KERNEL);
+		if (IS_ERR(new_node)) {
+			ret = PTR_ERR(new_node);
+			break;
+		}
+
+		sysfs_buf = tmc_alloc_etr_buf(drvdata, drvdata->size, 0, cpu_to_node(0), NULL);
+		if (IS_ERR(sysfs_buf)) {
+			kfree(new_node);
+			ret = PTR_ERR(new_node);
+			break;
+		}
+
+		/* We dont have a available sysfs_buf in drvdata, setup one */
+		if (!drvdata->sysfs_buf) {
+			drvdata->sysfs_buf = sysfs_buf;
+			new_node->is_free = false;
+		} else
+			new_node->is_free = true;
+
+		new_node->sysfs_buf = sysfs_buf;
+		list_add(&new_node->node, &drvdata->etr_buf_list);
+		i++;
+	}
+
+	/* Clean the list if there is an error */
+	if (ret)
+		tmc_clean_etr_buf_list(drvdata);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(tmc_create_etr_buf_list);
+
 int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
 {
 	int ret = 0;
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 95473d131032..9b3c4e6f0a5e 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -208,6 +208,19 @@ struct tmc_resrv_buf {
 	s64		len;
 };
 
+/**
+ * @sysfs_buf:	Allocated sysfs_buf.
+ * @is_free:	Indicates whether the buffer is free to choose.
+ * @pos:	Position of the buffer.
+ * @node:	Node in etr_buf_list.
+ */
+struct etr_buf_node {
+	struct etr_buf		*sysfs_buf;
+	bool			is_free;
+	loff_t			pos;
+	struct list_head	node;
+};
+
 /**
  * struct tmc_drvdata - specifics associated to an TMC component
  * @atclk:	optional clock for the core parts of the TMC.
@@ -243,6 +256,8 @@ struct tmc_resrv_buf {
  *		(after crash) by default.
  * @crash_mdata: Reserved memory for storing tmc crash metadata.
  *		 Used by ETR/ETF.
+ * @etr_buf_list: List that is used to manage allocated etr_buf.
+ * @reading_node: Available buffer_node for byte-cntr reading.
  */
 struct tmc_drvdata {
 	struct clk		*atclk;
@@ -273,6 +288,8 @@ struct tmc_drvdata {
 	struct etr_buf		*perf_buf;
 	struct tmc_resrv_buf	resrv_buf;
 	struct tmc_resrv_buf	crash_mdata;
+	struct list_head        etr_buf_list;
+	struct etr_buf_node     *reading_node;
 };
 
 struct etr_buf_operations {
@@ -445,5 +462,7 @@ struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev,
 				   enum cs_mode mode,
 				   struct coresight_path *path);
 extern const struct attribute_group coresight_etr_group;
+void tmc_clean_etr_buf_list(struct tmc_drvdata *drvdata);
+int tmc_create_etr_buf_list(struct tmc_drvdata *drvdata, int num_nodes);
 
 #endif

-- 
2.34.1



From jie.gan at oss.qualcomm.com  Wed Dec 10 22:10:43 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Thu, 11 Dec 2025 14:10:43 +0800
Subject: [PATCH v8 4/8] coresight: tmc: Introduce sysfs_read_ops to wrap
 sysfs read operations
In-Reply-To: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
References: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
Message-ID: <20251211-enable-byte-cntr-for-ctcu-v8-4-3e12ff313191@oss.qualcomm.com>

Introduce sysfs_read_ops as a wrapper, wrap sysfs read operations, for reading
trace data from the TMC buffer.

Reviewed-by: Mike Leach <mike.leach at linaro.org>
Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 drivers/hwtracing/coresight/coresight-tmc-core.c | 50 +++++++++++-------------
 drivers/hwtracing/coresight/coresight-tmc.h      | 17 ++++++++
 2 files changed, 40 insertions(+), 27 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c
index 1ea255ffa67c..8b0397a77e57 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-core.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-core.c
@@ -232,17 +232,10 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata)
 {
 	int ret = 0;
 
-	switch (drvdata->config_type) {
-	case TMC_CONFIG_TYPE_ETB:
-	case TMC_CONFIG_TYPE_ETF:
-		ret = tmc_read_prepare_etb(drvdata);
-		break;
-	case TMC_CONFIG_TYPE_ETR:
-		ret = tmc_read_prepare_etr(drvdata);
-		break;
-	default:
+	if (drvdata->sysfs_ops)
+		ret = drvdata->sysfs_ops->read_prepare(drvdata);
+	else
 		ret = -EINVAL;
-	}
 
 	if (!ret)
 		dev_dbg(&drvdata->csdev->dev, "TMC read start\n");
@@ -254,17 +247,10 @@ static int tmc_read_unprepare(struct tmc_drvdata *drvdata)
 {
 	int ret = 0;
 
-	switch (drvdata->config_type) {
-	case TMC_CONFIG_TYPE_ETB:
-	case TMC_CONFIG_TYPE_ETF:
-		ret = tmc_read_unprepare_etb(drvdata);
-		break;
-	case TMC_CONFIG_TYPE_ETR:
-		ret = tmc_read_unprepare_etr(drvdata);
-		break;
-	default:
+	if (drvdata->sysfs_ops)
+		ret = drvdata->sysfs_ops->read_unprepare(drvdata);
+	else
 		ret = -EINVAL;
-	}
 
 	if (!ret)
 		dev_dbg(&drvdata->csdev->dev, "TMC read end\n");
@@ -291,13 +277,8 @@ static int tmc_open(struct inode *inode, struct file *file)
 static ssize_t tmc_get_sysfs_trace(struct tmc_drvdata *drvdata, loff_t pos, size_t len,
 				   char **bufpp)
 {
-	switch (drvdata->config_type) {
-	case TMC_CONFIG_TYPE_ETB:
-	case TMC_CONFIG_TYPE_ETF:
-		return tmc_etb_get_sysfs_trace(drvdata, pos, len, bufpp);
-	case TMC_CONFIG_TYPE_ETR:
-		return tmc_etr_get_sysfs_trace(drvdata, pos, len, bufpp);
-	}
+	if (drvdata->sysfs_ops)
+		return drvdata->sysfs_ops->get_trace_data(drvdata, pos, len, bufpp);
 
 	return -EINVAL;
 }
@@ -769,6 +750,18 @@ static void register_crash_dev_interface(struct tmc_drvdata *drvdata,
 			"Valid crash tracedata found\n");
 }
 
+static const struct sysfs_read_ops tmc_etb_sysfs_read_ops = {
+	.read_prepare	= tmc_read_prepare_etb,
+	.read_unprepare	= tmc_read_unprepare_etb,
+	.get_trace_data	= tmc_etb_get_sysfs_trace,
+};
+
+static const struct sysfs_read_ops tmc_etr_sysfs_read_ops = {
+	.read_prepare	= tmc_read_prepare_etr,
+	.read_unprepare	= tmc_read_unprepare_etr,
+	.get_trace_data	= tmc_etr_get_sysfs_trace,
+};
+
 static int __tmc_probe(struct device *dev, struct resource *res)
 {
 	int ret = 0;
@@ -828,6 +821,7 @@ static int __tmc_probe(struct device *dev, struct resource *res)
 		desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
 		desc.ops = &tmc_etb_cs_ops;
 		dev_list = &etb_devs;
+		drvdata->sysfs_ops = &tmc_etb_sysfs_read_ops;
 		break;
 	case TMC_CONFIG_TYPE_ETR:
 		desc.groups = coresight_etr_groups;
@@ -841,6 +835,7 @@ static int __tmc_probe(struct device *dev, struct resource *res)
 		mutex_init(&drvdata->idr_mutex);
 		dev_list = &etr_devs;
 		INIT_LIST_HEAD(&drvdata->etr_buf_list);
+		drvdata->sysfs_ops = &tmc_etr_sysfs_read_ops;
 		break;
 	case TMC_CONFIG_TYPE_ETF:
 		desc.groups = coresight_etf_groups;
@@ -849,6 +844,7 @@ static int __tmc_probe(struct device *dev, struct resource *res)
 		desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO;
 		desc.ops = &tmc_etf_cs_ops;
 		dev_list = &etf_devs;
+		drvdata->sysfs_ops = &tmc_etb_sysfs_read_ops;
 		break;
 	default:
 		pr_err("%s: Unsupported TMC config\n", desc.name);
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 9b3c4e6f0a5e..c9a82ff6cd00 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -221,6 +221,8 @@ struct etr_buf_node {
 	struct list_head	node;
 };
 
+struct sysfs_read_ops;
+
 /**
  * struct tmc_drvdata - specifics associated to an TMC component
  * @atclk:	optional clock for the core parts of the TMC.
@@ -258,6 +260,7 @@ struct etr_buf_node {
  *		 Used by ETR/ETF.
  * @etr_buf_list: List that is used to manage allocated etr_buf.
  * @reading_node: Available buffer_node for byte-cntr reading.
+ * @sysfs_ops:	Read operations for sysfs mode.
  */
 struct tmc_drvdata {
 	struct clk		*atclk;
@@ -290,6 +293,20 @@ struct tmc_drvdata {
 	struct tmc_resrv_buf	crash_mdata;
 	struct list_head        etr_buf_list;
 	struct etr_buf_node     *reading_node;
+	const struct sysfs_read_ops	*sysfs_ops;
+};
+
+/**
+ * struct sysfs_read_ops - read operations for TMC and its helper devices
+ * @read_prepare:	prepare operation.
+ * @read_unprepare:	unprepare operation.
+ * @get_trace_data:	read operation.
+ */
+struct sysfs_read_ops {
+	int (*read_prepare)(struct tmc_drvdata *drvdata);
+	int (*read_unprepare)(struct tmc_drvdata *drvdata);
+	ssize_t (*get_trace_data)(struct tmc_drvdata *drvdata, loff_t pos,
+				  size_t len, char **bufpp);
 };
 
 struct etr_buf_operations {

-- 
2.34.1



From jie.gan at oss.qualcomm.com  Wed Dec 10 22:10:44 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Thu, 11 Dec 2025 14:10:44 +0800
Subject: [PATCH v8 5/8] dt-bindings: arm: add an interrupt property for
 Coresight CTCU
In-Reply-To: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
References: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
Message-ID: <20251211-enable-byte-cntr-for-ctcu-v8-5-3e12ff313191@oss.qualcomm.com>

Add an interrupt property to CTCU device. The interrupt will be triggered
when the data size in the ETR buffer exceeds the threshold of the
BYTECNTRVAL register. Programming a threshold in the BYTECNTRVAL register
of CTCU device will enable the interrupt.

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
Reviewed-by: Mike Leach <mike.leach at linaro.org>
Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 .../devicetree/bindings/arm/qcom,coresight-ctcu.yaml    | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
index c969c16c21ef..90f88cc6cd3e 100644
--- a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
+++ b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
@@ -39,6 +39,16 @@ properties:
     items:
       - const: apb
 
+  interrupts:
+    items:
+      - description: Byte cntr interrupt for the first etr device
+      - description: Byte cntr interrupt for the second etr device
+
+  interrupt-names:
+    items:
+      - const: etrirq0
+      - const: etrirq1
+
   label:
     description:
       Description of a coresight device.
@@ -60,6 +70,8 @@ additionalProperties: false
 
 examples:
   - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
     ctcu at 1001000 {
         compatible = "qcom,sa8775p-ctcu";
         reg = <0x1001000 0x1000>;
@@ -67,6 +79,11 @@ examples:
         clocks = <&aoss_qmp>;
         clock-names = "apb";
 
+        interrupts = <GIC_SPI 270 IRQ_TYPE_EDGE_RISING>,
+                     <GIC_SPI 262 IRQ_TYPE_EDGE_RISING>;
+        interrupt-names = "etrirq0",
+                          "etrirq1;
+
         in-ports {
             #address-cells = <1>;
             #size-cells = <0>;

-- 
2.34.1



From jie.gan at oss.qualcomm.com  Wed Dec 10 22:10:45 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Thu, 11 Dec 2025 14:10:45 +0800
Subject: [PATCH v8 6/8] coresight: ctcu: enable byte-cntr for TMC ETR
 devices
In-Reply-To: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
References: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
Message-ID: <20251211-enable-byte-cntr-for-ctcu-v8-6-3e12ff313191@oss.qualcomm.com>

The byte-cntr function provided by the CTCU device is used to transfer data
from the ETR buffer to the userspace. An interrupt is triggered if the data
size exceeds the threshold set in the BYTECNTRVAL register. The interrupt
handler counts the number of triggered interruptions and the read function
will read the data from the synced ETR buffer.

Switching the sysfs_buf when current buffer is full or the timeout is
triggered and resets rrp and rwp registers after switched the buffer.
The synced buffer will become available for reading after the switch.

Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 .../ABI/testing/sysfs-bus-coresight-devices-ctcu   |   6 +
 drivers/hwtracing/coresight/Makefile               |   2 +-
 .../hwtracing/coresight/coresight-ctcu-byte-cntr.c | 368 +++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-ctcu-core.c  |  88 ++++-
 drivers/hwtracing/coresight/coresight-ctcu.h       |  62 +++-
 drivers/hwtracing/coresight/coresight-tmc-etr.c    |  18 +
 drivers/hwtracing/coresight/coresight-tmc.h        |   1 +
 7 files changed, 532 insertions(+), 13 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-ctcu b/Documentation/ABI/testing/sysfs-bus-coresight-devices-ctcu
new file mode 100644
index 000000000000..de1e87b4a72e
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-ctcu
@@ -0,0 +1,6 @@
+What:           /sys/bus/coresight/devices/<ctcu-name>/irq_threshold
+Date:           Dec. 2025
+KernelVersion:  6.19
+Contact:        Tingwei Zhang <tingwei.zhang at oss.qualcomm.com>; Jinlong Mao <jinlong.mao at oss.qualcomm.com>; Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Configure the IRQ value for byte-cntr register.
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile
index ab16d06783a5..821a1b06b20c 100644
--- a/drivers/hwtracing/coresight/Makefile
+++ b/drivers/hwtracing/coresight/Makefile
@@ -55,5 +55,5 @@ coresight-cti-y := coresight-cti-core.o	coresight-cti-platform.o \
 obj-$(CONFIG_ULTRASOC_SMB) += ultrasoc-smb.o
 obj-$(CONFIG_CORESIGHT_DUMMY) += coresight-dummy.o
 obj-$(CONFIG_CORESIGHT_CTCU) += coresight-ctcu.o
-coresight-ctcu-y := coresight-ctcu-core.o
+coresight-ctcu-y := coresight-ctcu-core.o coresight-ctcu-byte-cntr.o
 obj-$(CONFIG_CORESIGHT_KUNIT_TESTS) += coresight-kunit-tests.o
diff --git a/drivers/hwtracing/coresight/coresight-ctcu-byte-cntr.c b/drivers/hwtracing/coresight/coresight-ctcu-byte-cntr.c
new file mode 100644
index 000000000000..99a871c5585c
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-ctcu-byte-cntr.c
@@ -0,0 +1,368 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/coresight.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/of_irq.h>
+#include <linux/uaccess.h>
+
+#include "coresight-ctcu.h"
+#include "coresight-priv.h"
+#include "coresight-tmc.h"
+
+static irqreturn_t byte_cntr_handler(int irq, void *data)
+{
+	struct ctcu_byte_cntr *byte_cntr_data = (struct ctcu_byte_cntr *)data;
+
+	atomic_inc(&byte_cntr_data->irq_cnt);
+	wake_up(&byte_cntr_data->wq);
+
+	return IRQ_HANDLED;
+}
+
+static void ctcu_reset_sysfs_buf(struct tmc_drvdata *drvdata)
+{
+	u32 sts;
+
+	CS_UNLOCK(drvdata->base);
+	tmc_write_rrp(drvdata, drvdata->sysfs_buf->hwaddr);
+	tmc_write_rwp(drvdata, drvdata->sysfs_buf->hwaddr);
+	sts = readl_relaxed(drvdata->base + TMC_STS) & ~TMC_STS_FULL;
+	writel_relaxed(sts, drvdata->base + TMC_STS);
+	CS_LOCK(drvdata->base);
+}
+
+static void ctcu_cfg_byte_cntr_reg(struct tmc_drvdata *drvdata, u32 val, u32 offset)
+{
+	struct ctcu_drvdata *ctcu_drvdata;
+	struct coresight_device *helper;
+
+	helper = coresight_get_helper(drvdata->csdev, CORESIGHT_DEV_SUBTYPE_HELPER_CTCU);
+	if (!helper)
+		return;
+
+	ctcu_drvdata = dev_get_drvdata(helper->dev.parent);
+	/* A one value for IRQCTRL register represents 8 bytes */
+	ctcu_program_register(ctcu_drvdata, val / 8, offset);
+}
+
+static struct ctcu_byte_cntr *ctcu_get_byte_cntr_data(struct tmc_drvdata *drvdata)
+{
+	struct ctcu_byte_cntr *byte_cntr_data;
+	struct ctcu_drvdata *ctcu_drvdata;
+	struct coresight_device *helper;
+	int port;
+
+	helper = coresight_get_helper(drvdata->csdev, CORESIGHT_DEV_SUBTYPE_HELPER_CTCU);
+	if (!helper)
+		return NULL;
+
+	port = coresight_get_in_port(drvdata->csdev, helper);
+	if (port < 0)
+		return NULL;
+
+	ctcu_drvdata = dev_get_drvdata(helper->dev.parent);
+	byte_cntr_data = &ctcu_drvdata->byte_cntr_data[port];
+	return byte_cntr_data;
+}
+
+static bool ctcu_byte_cntr_switch_buffer(struct tmc_drvdata *drvdata,
+					 struct ctcu_byte_cntr *byte_cntr_data)
+{
+	struct etr_buf_node *nd, *next, *curr_node, *picked_node;
+	struct etr_buf *curr_buf = drvdata->sysfs_buf;
+	bool found_free_buf = false;
+
+	if (WARN_ON(!drvdata || !byte_cntr_data))
+		return found_free_buf;
+
+	/* Stop the ETR before we start the switch */
+	if (coresight_get_mode(drvdata->csdev) != CS_MODE_DISABLED)
+		tmc_etr_enable_disable_hw(drvdata, false);
+
+	list_for_each_entry_safe(nd, next, &drvdata->etr_buf_list, node) {
+		/* curr_buf is free for next round */
+		if (nd->sysfs_buf == curr_buf) {
+			nd->is_free = true;
+			curr_node = nd;
+		}
+
+		if (!found_free_buf && nd->is_free && nd->sysfs_buf != curr_buf) {
+			picked_node = nd;
+			found_free_buf = true;
+		}
+	}
+
+	if (found_free_buf) {
+		curr_node->pos = 0;
+		drvdata->reading_node = curr_node;
+		drvdata->sysfs_buf = picked_node->sysfs_buf;
+		drvdata->etr_buf = picked_node->sysfs_buf;
+		picked_node->is_free = false;
+		/* Reset irq_cnt for next etr_buf */
+		atomic_set(&byte_cntr_data->irq_cnt, 0);
+		/* Reset rrp and rwp when the system has switched the buffer*/
+		ctcu_reset_sysfs_buf(drvdata);
+		/* Restart the ETR when we find a free buffer */
+		if (coresight_get_mode(drvdata->csdev) != CS_MODE_DISABLED)
+			tmc_etr_enable_disable_hw(drvdata, true);
+	}
+
+	return found_free_buf;
+}
+
+/*
+ * ctcu_byte_cntr_get_data() - reads data from the deactivated and filled buffer.
+ * The byte-cntr reading work reads data from the deactivated and filled buffer.
+ * The read operation waits for a buffer to become available, either filled or
+ * upon timeout, and then reads trace data from the synced buffer.
+ */
+static ssize_t ctcu_byte_cntr_get_data(struct tmc_drvdata *drvdata, loff_t pos,
+				       size_t len, char **bufpp)
+{
+	struct etr_buf *sysfs_buf = drvdata->sysfs_buf;
+	struct device *dev = &drvdata->csdev->dev;
+	ssize_t actual, size = sysfs_buf->size;
+	struct ctcu_byte_cntr *byte_cntr_data;
+	size_t thresh_val;
+	atomic_t *irq_cnt;
+	int ret;
+
+	byte_cntr_data = ctcu_get_byte_cntr_data(drvdata);
+	if (!byte_cntr_data)
+		return -EINVAL;
+
+	thresh_val = byte_cntr_data->thresh_val;
+	irq_cnt = &byte_cntr_data->irq_cnt;
+
+wait_buffer:
+	if (!byte_cntr_data->reading_buf) {
+		ret = wait_event_interruptible_timeout(byte_cntr_data->wq,
+				((atomic_read(irq_cnt) + 1) * thresh_val >= size) ||
+				!byte_cntr_data->enable,
+				BYTE_CNTR_TIMEOUT);
+		if (ret < 0)
+			return ret;
+		/*
+		 * The current etr_buf is almost full or timeout is triggered,
+		 * so switch the buffer and mark the switched buffer as reading.
+		 */
+		if (byte_cntr_data->enable) {
+			if (!ctcu_byte_cntr_switch_buffer(drvdata, byte_cntr_data)) {
+				dev_err(dev, "Switch buffer failed for byte-cntr\n");
+				return -EINVAL;
+			}
+
+			byte_cntr_data->reading_buf = true;
+		} else {
+			/*
+			 * TMC-ETR has been disabled, so directly reads data from
+			 * the drvdata->sysfs_buf.
+			 */
+			actual = drvdata->sysfs_ops->get_trace_data(drvdata, pos, len, bufpp);
+			if (actual > 0) {
+				byte_cntr_data->total_size += actual;
+				return actual;
+			}
+
+			/* Exit byte-cntr reading */
+			return 0;
+		}
+	}
+
+	/* Check the status of current etr_buf*/
+	if ((atomic_read(irq_cnt) + 1) * thresh_val >= size)
+		/*
+		 * Unlikely to find a free buffer to switch, so just disable
+		 * the ETR for a while.
+		 */
+		if (!ctcu_byte_cntr_switch_buffer(drvdata, byte_cntr_data))
+			dev_warn(dev, "No available buffer to store data, disable ETR\n");
+
+	pos = drvdata->reading_node->pos;
+	actual = drvdata->sysfs_ops->get_trace_data(drvdata, pos, len, bufpp);
+	if (actual <= 0) {
+		/* Reset flags upon reading is finished or failed */
+		byte_cntr_data->reading_buf = false;
+		drvdata->reading_node = NULL;
+
+		/*
+		 * Nothing in the buffer, waiting for the next buffer
+		 * to be filled.
+		 */
+		if (actual == 0)
+			goto wait_buffer;
+	} else
+		byte_cntr_data->total_size += actual;
+
+	return actual;
+}
+
+static int ctcu_read_prepare_byte_cntr(struct tmc_drvdata *drvdata)
+{
+	struct ctcu_byte_cntr *byte_cntr_data;
+	unsigned long flags;
+	int ret = 0;
+
+	/* config types are set a boot time and never change */
+	if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR))
+		return -EINVAL;
+
+	/*
+	 * Byte counter reading should start only after the TMC-ETR has been
+	 * enabled, which implies that the sysfs_buf has already been setup
+	 * in drvdata.
+	 */
+	if (!drvdata->sysfs_buf)
+		return -EINVAL;
+
+	byte_cntr_data = ctcu_get_byte_cntr_data(drvdata);
+	if (!byte_cntr_data)
+		return -EINVAL;
+
+	/*
+	 * The threshold value must not exceed the buffer size.
+	 * A margin should be maintained between the two values to account
+	 * for the time gap between the interrupt and buffer switching.
+	 */
+	if (byte_cntr_data->thresh_val + SZ_16K >= drvdata->size) {
+		dev_err(&drvdata->csdev->dev, "The threshold value is too large\n");
+		return -EINVAL;
+	}
+
+	raw_spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (byte_cntr_data->reading) {
+		ret = -EBUSY;
+		goto out_unlock;
+	}
+
+	byte_cntr_data->reading = true;
+	raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+	/* Setup an available etr_buf_list for byte-cntr */
+	ret = tmc_create_etr_buf_list(drvdata, 2);
+	if (ret)
+		goto out;
+
+	raw_spin_lock_irqsave(&drvdata->spinlock, flags);
+	atomic_set(&byte_cntr_data->irq_cnt, 0);
+	/* Configure the byte-cntr register to enable IRQ */
+	ctcu_cfg_byte_cntr_reg(drvdata, byte_cntr_data->thresh_val,
+			       byte_cntr_data->irq_ctrl_offset);
+	enable_irq_wake(byte_cntr_data->irq);
+	byte_cntr_data->total_size = 0;
+
+out_unlock:
+	raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+out:
+	return ret;
+}
+
+static int ctcu_read_unprepare_byte_cntr(struct tmc_drvdata *drvdata)
+{
+	struct device *dev = &drvdata->csdev->dev;
+	struct ctcu_byte_cntr *byte_cntr_data;
+	unsigned long flags;
+
+	byte_cntr_data = ctcu_get_byte_cntr_data(drvdata);
+	if (!byte_cntr_data)
+		return -EINVAL;
+
+	raw_spin_lock_irqsave(&drvdata->spinlock, flags);
+	/* Configure the byte-cntr register to disable IRQ */
+	ctcu_cfg_byte_cntr_reg(drvdata, 0, byte_cntr_data->irq_ctrl_offset);
+	disable_irq_wake(byte_cntr_data->irq);
+	byte_cntr_data->reading = false;
+	byte_cntr_data->reading_buf = false;
+	drvdata->reading_node = NULL;
+	raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+	dev_dbg(dev, "send data total size:%llu bytes\n", byte_cntr_data->total_size);
+	tmc_clean_etr_buf_list(drvdata);
+
+	return 0;
+}
+
+static const struct sysfs_read_ops byte_cntr_sysfs_read_ops = {
+	.read_prepare	= ctcu_read_prepare_byte_cntr,
+	.read_unprepare	= ctcu_read_unprepare_byte_cntr,
+	.get_trace_data	= ctcu_byte_cntr_get_data,
+};
+
+/* Start the byte-cntr function when the path is enabled. */
+void ctcu_byte_cntr_start(struct coresight_device *csdev, struct coresight_path *path)
+{
+	struct ctcu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	struct coresight_device *sink = coresight_get_sink(path);
+	struct ctcu_byte_cntr *byte_cntr_data;
+	int port_num;
+
+	if (!sink)
+		return;
+
+	port_num = coresight_get_in_port(sink, csdev);
+	if (port_num < 0)
+		return;
+
+	byte_cntr_data = &drvdata->byte_cntr_data[port_num];
+	/* Don't start byte-cntr function when threshold is not set. */
+	if (!byte_cntr_data->thresh_val || byte_cntr_data->enable)
+		return;
+
+	guard(raw_spinlock_irqsave)(&byte_cntr_data->spin_lock);
+	byte_cntr_data->enable = true;
+	byte_cntr_data->reading_buf = false;
+}
+
+/* Stop the byte-cntr function when the path is disabled. */
+void ctcu_byte_cntr_stop(struct coresight_device *csdev, struct coresight_path *path)
+{
+	struct ctcu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	struct coresight_device *sink = coresight_get_sink(path);
+	struct ctcu_byte_cntr *byte_cntr_data;
+	int port_num;
+
+	if (!sink || coresight_get_mode(sink) == CS_MODE_SYSFS)
+		return;
+
+	port_num = coresight_get_in_port(sink, csdev);
+	if (port_num < 0)
+		return;
+
+	byte_cntr_data = &drvdata->byte_cntr_data[port_num];
+	guard(raw_spinlock_irqsave)(&byte_cntr_data->spin_lock);
+	byte_cntr_data->enable = false;
+}
+
+void ctcu_byte_cntr_init(struct device *dev, struct ctcu_drvdata *drvdata, int etr_num)
+{
+	struct ctcu_byte_cntr *byte_cntr_data;
+	struct device_node *nd = dev->of_node;
+	int irq_num, ret, i;
+
+	drvdata->byte_cntr_sysfs_read_ops = &byte_cntr_sysfs_read_ops;
+	for (i = 0; i < etr_num; i++) {
+		byte_cntr_data = &drvdata->byte_cntr_data[i];
+		irq_num = of_irq_get_byname(nd, byte_cntr_data->irq_name);
+		if (irq_num < 0) {
+			dev_err(dev, "Failed to get IRQ from DT for %s\n",
+				byte_cntr_data->irq_name);
+			continue;
+		}
+
+		ret = devm_request_irq(dev, irq_num, byte_cntr_handler,
+				       IRQF_TRIGGER_RISING | IRQF_SHARED,
+				       dev_name(dev), byte_cntr_data);
+		if (ret) {
+			dev_err(dev, "Failed to register IRQ for %s\n",
+				byte_cntr_data->irq_name);
+			continue;
+		}
+
+		byte_cntr_data->irq = irq_num;
+		init_waitqueue_head(&byte_cntr_data->wq);
+	}
+}
diff --git a/drivers/hwtracing/coresight/coresight-ctcu-core.c b/drivers/hwtracing/coresight/coresight-ctcu-core.c
index 78be783b3cb2..44dbd43f5382 100644
--- a/drivers/hwtracing/coresight/coresight-ctcu-core.c
+++ b/drivers/hwtracing/coresight/coresight-ctcu-core.c
@@ -15,6 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
+#include <linux/sizes.h>
 
 #include "coresight-ctcu.h"
 #include "coresight-priv.h"
@@ -45,17 +46,23 @@ DEFINE_CORESIGHT_DEVLIST(ctcu_devs, "ctcu");
 
 #define CTCU_ATID_REG_BIT(traceid)	(traceid % 32)
 #define CTCU_ATID_REG_SIZE		0x10
+#define CTCU_ETR0_IRQCTRL               0x6c
+#define CTCU_ETR1_IRQCTRL               0x70
 #define CTCU_ETR0_ATID0			0xf8
 #define CTCU_ETR1_ATID0			0x108
 
 static const struct ctcu_etr_config sa8775p_etr_cfgs[] = {
 	{
-		.atid_offset	= CTCU_ETR0_ATID0,
-		.port_num	= 0,
+		.atid_offset		= CTCU_ETR0_ATID0,
+		.irq_ctrl_offset	= CTCU_ETR0_IRQCTRL,
+		.irq_name		= "etrirq0",
+		.port_num		= 0,
 	},
 	{
-		.atid_offset	= CTCU_ETR1_ATID0,
-		.port_num	= 1,
+		.atid_offset		= CTCU_ETR1_ATID0,
+		.irq_ctrl_offset	= CTCU_ETR1_IRQCTRL,
+		.irq_name		= "etrirq1",
+		.port_num		= 1,
 	},
 };
 
@@ -64,6 +71,70 @@ static const struct ctcu_config sa8775p_cfgs = {
 	.num_etr_config	= ARRAY_SIZE(sa8775p_etr_cfgs),
 };
 
+void ctcu_program_register(struct ctcu_drvdata *drvdata, u32 val, u32 offset)
+{
+	CS_UNLOCK(drvdata->base);
+	ctcu_writel(drvdata, val, offset);
+	CS_LOCK(drvdata->base);
+}
+
+static ssize_t irq_threshold_show(struct device *dev, struct device_attribute *attr,
+				  char *buf)
+{
+	struct ctcu_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	int i, len = 0;
+
+	for (i = 0; i < ETR_MAX_NUM; i++) {
+		if (drvdata->byte_cntr_data[i].irq_ctrl_offset)
+			len += scnprintf(buf + len, PAGE_SIZE - len, "%u ",
+					 drvdata->byte_cntr_data[i].thresh_val);
+	}
+
+	len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
+
+	return len;
+}
+
+static ssize_t irq_threshold_store(struct device *dev, struct device_attribute *attr,
+				   const char *buf, size_t size)
+{
+	struct ctcu_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	u32 thresh_vals[ETR_MAX_NUM] = { 0 };
+	int num, i;
+
+	num = sscanf(buf, "%i %i", &thresh_vals[0], &thresh_vals[1]);
+	if (num <= 0 || num > ETR_MAX_NUM)
+		return -EINVAL;
+
+	/* Threshold 0 disables the interruption. */
+	guard(raw_spinlock_irqsave)(&drvdata->spin_lock);
+	for (i = 0; i < num; i++) {
+		/* A small threshold will result in a large number of interruptions */
+		if (thresh_vals[i] && thresh_vals[i] < SZ_4K)
+			return -EINVAL;
+
+		if (drvdata->byte_cntr_data[i].irq_ctrl_offset)
+			drvdata->byte_cntr_data[i].thresh_val = thresh_vals[i];
+	}
+
+	return size;
+}
+static DEVICE_ATTR_RW(irq_threshold);
+
+static struct attribute *ctcu_attrs[] = {
+	&dev_attr_irq_threshold.attr,
+	NULL,
+};
+
+static struct attribute_group ctcu_attr_grp = {
+	.attrs = ctcu_attrs,
+};
+
+static const struct attribute_group *ctcu_attr_grps[] = {
+	&ctcu_attr_grp,
+	NULL,
+};
+
 static void ctcu_program_atid_register(struct ctcu_drvdata *drvdata, u32 reg_offset,
 				       u8 bit, bool enable)
 {
@@ -142,11 +213,15 @@ static int ctcu_set_etr_traceid(struct coresight_device *csdev, struct coresight
 static int ctcu_enable(struct coresight_device *csdev, enum cs_mode mode,
 		       struct coresight_path *path)
 {
+	ctcu_byte_cntr_start(csdev, path);
+
 	return ctcu_set_etr_traceid(csdev, path, true);
 }
 
 static int ctcu_disable(struct coresight_device *csdev, struct coresight_path *path)
 {
+	ctcu_byte_cntr_stop(csdev, path);
+
 	return ctcu_set_etr_traceid(csdev, path, false);
 }
 
@@ -197,7 +272,11 @@ static int ctcu_probe(struct platform_device *pdev)
 			for (i = 0; i < cfgs->num_etr_config; i++) {
 				etr_cfg = &cfgs->etr_cfgs[i];
 				drvdata->atid_offset[i] = etr_cfg->atid_offset;
+				drvdata->byte_cntr_data[i].irq_name = etr_cfg->irq_name;
+				drvdata->byte_cntr_data[i].irq_ctrl_offset =
+					etr_cfg->irq_ctrl_offset;
 			}
+			ctcu_byte_cntr_init(dev, drvdata, cfgs->num_etr_config);
 		}
 	}
 
@@ -209,6 +288,7 @@ static int ctcu_probe(struct platform_device *pdev)
 	desc.subtype.helper_subtype = CORESIGHT_DEV_SUBTYPE_HELPER_CTCU;
 	desc.pdata = pdata;
 	desc.dev = dev;
+	desc.groups = ctcu_attr_grps;
 	desc.ops = &ctcu_ops;
 	desc.access = CSDEV_ACCESS_IOMEM(base);
 
diff --git a/drivers/hwtracing/coresight/coresight-ctcu.h b/drivers/hwtracing/coresight/coresight-ctcu.h
index e9594c38dd91..21938a201dbb 100644
--- a/drivers/hwtracing/coresight/coresight-ctcu.h
+++ b/drivers/hwtracing/coresight/coresight-ctcu.h
@@ -5,19 +5,28 @@
 
 #ifndef _CORESIGHT_CTCU_H
 #define _CORESIGHT_CTCU_H
+
+#include <linux/time.h>
 #include "coresight-trace-id.h"
+#include "coresight-tmc.h"
 
 /* Maximum number of supported ETR devices for a single CTCU. */
 #define ETR_MAX_NUM	2
 
+#define BYTE_CNTR_TIMEOUT	(5 * HZ)
+
 /**
  * struct ctcu_etr_config
  * @atid_offset:	offset to the ATID0 Register.
- * @port_num:		in-port number of CTCU device that connected to ETR.
+ * @port_num:		in-port number of the CTCU device that connected to ETR.
+ * @irq_ctrl_offset:    offset to the BYTECNTRVAL register.
+ * @irq_name:           IRQ name in dt node.
  */
 struct ctcu_etr_config {
 	const u32 atid_offset;
 	const u32 port_num;
+	const u32 irq_ctrl_offset;
+	const char *irq_name;
 };
 
 struct ctcu_config {
@@ -25,15 +34,52 @@ struct ctcu_config {
 	int num_etr_config;
 };
 
-struct ctcu_drvdata {
-	void __iomem		*base;
-	struct clk		*apb_clk;
-	struct device		*dev;
-	struct coresight_device	*csdev;
+/**
+ * struct ctcu_byte_cntr
+ * @enable:		indicates that byte_cntr function is enabled or not.
+ * @reading:		indicates that byte-cntr reading is started.
+ * @reading_buf:	indicates that byte-cntr is reading data from the buffer.
+ * @thresh_val:		threshold to trigger a interruption.
+ * @total_size:		total size of transferred data.
+ * @irq:		allocated number of the IRQ.
+ * @irq_cnt:		IRQ count number for triggered interruptions.
+ * @wq:			waitqueue for reading data from ETR buffer.
+ * @spin_lock:		spinlock of byte_cntr_data.
+ * @irq_ctrl_offset:	offset to the BYTECNTVAL Register.
+ * @irq_name:		IRQ name defined in DT.
+ */
+struct ctcu_byte_cntr {
+	bool			enable;
+	bool                    reading;
+	bool			reading_buf;
+	u32			thresh_val;
+	u64			total_size;
+	int			irq;
+	atomic_t		irq_cnt;
+	wait_queue_head_t	wq;
 	raw_spinlock_t		spin_lock;
-	u32			atid_offset[ETR_MAX_NUM];
+	u32			irq_ctrl_offset;
+	const char		*irq_name;
+};
+
+struct ctcu_drvdata {
+	void __iomem			*base;
+	struct clk			*apb_clk;
+	struct device			*dev;
+	struct coresight_device		*csdev;
+	struct ctcu_byte_cntr		byte_cntr_data[ETR_MAX_NUM];
+	raw_spinlock_t			spin_lock;
+	u32				atid_offset[ETR_MAX_NUM];
 	/* refcnt for each traceid of each sink */
-	u8			traceid_refcnt[ETR_MAX_NUM][CORESIGHT_TRACE_ID_RES_TOP];
+	u8				traceid_refcnt[ETR_MAX_NUM][CORESIGHT_TRACE_ID_RES_TOP];
+	const struct sysfs_read_ops	*byte_cntr_sysfs_read_ops;
 };
 
+void ctcu_program_register(struct ctcu_drvdata *drvdata, u32 val, u32 offset);
+
+/* Byte-cntr functions */
+void ctcu_byte_cntr_start(struct coresight_device *csdev, struct coresight_path *path);
+void ctcu_byte_cntr_stop(struct coresight_device *csdev, struct coresight_path *path);
+void ctcu_byte_cntr_init(struct device *dev, struct ctcu_drvdata *drvdata, int port_num);
+
 #endif
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 2b6ca1f8bed2..3aeb0cbc720a 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -1163,6 +1163,10 @@ ssize_t tmc_etr_get_sysfs_trace(struct tmc_drvdata *drvdata,
 	ssize_t actual = len;
 	struct etr_buf *etr_buf = drvdata->sysfs_buf;
 
+	/* Reading the buffer from the buf_node if it exists*/
+	if (drvdata->reading_node)
+		etr_buf = drvdata->reading_node->sysfs_buf;
+
 	if (pos + actual > etr_buf->len)
 		actual = etr_buf->len - pos;
 	if (actual <= 0)
@@ -1226,6 +1230,20 @@ static void __tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
 
 }
 
+/**
+ * tmc_etr_enable_disable_hw - enable/disable the ETR hw.
+ * @drvdata:	drvdata of the TMC device.
+ * @enable:	indicates enable/disable.
+ */
+void tmc_etr_enable_disable_hw(struct tmc_drvdata *drvdata, bool enable)
+{
+	if (enable)
+		__tmc_etr_enable_hw(drvdata);
+	else
+		__tmc_etr_disable_hw(drvdata);
+}
+EXPORT_SYMBOL_GPL(tmc_etr_enable_disable_hw);
+
 void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
 {
 	__tmc_etr_disable_hw(drvdata);
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index c9a82ff6cd00..36f82e012fc6 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -481,5 +481,6 @@ struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev,
 extern const struct attribute_group coresight_etr_group;
 void tmc_clean_etr_buf_list(struct tmc_drvdata *drvdata);
 int tmc_create_etr_buf_list(struct tmc_drvdata *drvdata, int num_nodes);
+void tmc_etr_enable_disable_hw(struct tmc_drvdata *drvdata, bool enable);
 
 #endif

-- 
2.34.1



From jie.gan at oss.qualcomm.com  Wed Dec 10 22:10:46 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Thu, 11 Dec 2025 14:10:46 +0800
Subject: [PATCH v8 7/8] coresight: tmc: integrate byte-cntr's read_ops with
 sysfs file_ops
In-Reply-To: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
References: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
Message-ID: <20251211-enable-byte-cntr-for-ctcu-v8-7-3e12ff313191@oss.qualcomm.com>

Add code logic to invoke byte-cntr's sysfs_read_ops if the byte-cntr
is enabled.

Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 drivers/hwtracing/coresight/coresight-tmc-core.c | 53 +++++++++++++++++++++++-
 1 file changed, 52 insertions(+), 1 deletion(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c
index 8b0397a77e57..41ac99b35a84 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-core.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-core.c
@@ -31,6 +31,7 @@
 
 #include "coresight-priv.h"
 #include "coresight-tmc.h"
+#include "coresight-ctcu.h"
 
 DEFINE_CORESIGHT_DEVLIST(etb_devs, "tmc_etb");
 DEFINE_CORESIGHT_DEVLIST(etf_devs, "tmc_etf");
@@ -228,15 +229,47 @@ static int tmc_prepare_crashdata(struct tmc_drvdata *drvdata)
 	return 0;
 }
 
+/* Return the byte-cntr's sysfs_read_ops if in use */
+static const struct sysfs_read_ops *tmc_get_byte_cntr_sysfs_ops(struct tmc_drvdata *drvdata)
+{
+	struct ctcu_byte_cntr *byte_cntr_data;
+	struct ctcu_drvdata *ctcu_drvdata;
+	struct coresight_device *helper;
+	int port;
+
+	helper = coresight_get_helper(drvdata->csdev, CORESIGHT_DEV_SUBTYPE_HELPER_CTCU);
+	if (!helper)
+		return NULL;
+
+	port = coresight_get_in_port(drvdata->csdev, helper);
+	if (port < 0)
+		return NULL;
+
+	ctcu_drvdata = dev_get_drvdata(helper->dev.parent);
+	byte_cntr_data = &ctcu_drvdata->byte_cntr_data[port];
+	if (byte_cntr_data && byte_cntr_data->thresh_val)
+		return ctcu_drvdata->byte_cntr_sysfs_read_ops;
+
+	return NULL;
+}
+
 static int tmc_read_prepare(struct tmc_drvdata *drvdata)
 {
+	const struct sysfs_read_ops *byte_cntr_sysfs_read_ops;
 	int ret = 0;
 
+	byte_cntr_sysfs_read_ops = tmc_get_byte_cntr_sysfs_ops(drvdata);
+	if (byte_cntr_sysfs_read_ops) {
+		ret = byte_cntr_sysfs_read_ops->read_prepare(drvdata);
+		goto out;
+	}
+
 	if (drvdata->sysfs_ops)
 		ret = drvdata->sysfs_ops->read_prepare(drvdata);
 	else
 		ret = -EINVAL;
 
+out:
 	if (!ret)
 		dev_dbg(&drvdata->csdev->dev, "TMC read start\n");
 
@@ -245,13 +278,21 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata)
 
 static int tmc_read_unprepare(struct tmc_drvdata *drvdata)
 {
+	const struct sysfs_read_ops *byte_cntr_sysfs_read_ops;
 	int ret = 0;
 
+	byte_cntr_sysfs_read_ops = tmc_get_byte_cntr_sysfs_ops(drvdata);
+	if (byte_cntr_sysfs_read_ops) {
+		ret = byte_cntr_sysfs_read_ops->read_unprepare(drvdata);
+		goto out;
+	}
+
 	if (drvdata->sysfs_ops)
 		ret = drvdata->sysfs_ops->read_unprepare(drvdata);
 	else
 		ret = -EINVAL;
 
+out:
 	if (!ret)
 		dev_dbg(&drvdata->csdev->dev, "TMC read end\n");
 
@@ -277,6 +318,12 @@ static int tmc_open(struct inode *inode, struct file *file)
 static ssize_t tmc_get_sysfs_trace(struct tmc_drvdata *drvdata, loff_t pos, size_t len,
 				   char **bufpp)
 {
+	const struct sysfs_read_ops *byte_cntr_sysfs_read_ops;
+
+	byte_cntr_sysfs_read_ops = tmc_get_byte_cntr_sysfs_ops(drvdata);
+	if (byte_cntr_sysfs_read_ops)
+		return byte_cntr_sysfs_read_ops->get_trace_data(drvdata, pos, len, bufpp);
+
 	if (drvdata->sysfs_ops)
 		return drvdata->sysfs_ops->get_trace_data(drvdata, pos, len, bufpp);
 
@@ -300,7 +347,11 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len,
 		return -EFAULT;
 	}
 
-	*ppos += actual;
+	if (drvdata->reading_node)
+		drvdata->reading_node->pos += actual;
+	else
+		*ppos += actual;
+
 	dev_dbg(&drvdata->csdev->dev, "%zu bytes copied\n", actual);
 
 	return actual;

-- 
2.34.1



From jie.gan at oss.qualcomm.com  Wed Dec 10 22:10:47 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Thu, 11 Dec 2025 14:10:47 +0800
Subject: [PATCH v8 8/8] arm64: dts: qcom: lemans: Add interrupts to CTCU
 device
In-Reply-To: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
References: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
Message-ID: <20251211-enable-byte-cntr-for-ctcu-v8-8-3e12ff313191@oss.qualcomm.com>

Add interrupts to enable byte-cntr function for TMC ETR devices.

Reviewed-by: Konrad Dybcio <konrad.dybcio at oss.qualcomm.com>
Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 arch/arm64/boot/dts/qcom/lemans.dtsi | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi
index 0b154d57ba24..3c4633e044d9 100644
--- a/arch/arm64/boot/dts/qcom/lemans.dtsi
+++ b/arch/arm64/boot/dts/qcom/lemans.dtsi
@@ -2776,6 +2776,11 @@ ctcu at 4001000 {
 			clocks = <&aoss_qmp>;
 			clock-names = "apb";
 
+			interrupts = <GIC_SPI 270 IRQ_TYPE_EDGE_RISING>,
+				     <GIC_SPI 262 IRQ_TYPE_EDGE_RISING>;
+			interrupt-names = "etrirq0",
+					  "etrirq1";
+
 			in-ports {
 				#address-cells = <1>;
 				#size-cells = <0>;

-- 
2.34.1



From krzk at kernel.org  Wed Dec 10 22:16:25 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 11 Dec 2025 07:16:25 +0100
Subject: [PATCH v6 2/5] dt-bindings: clock: add Amlogic T7 SCMI clock
 controller
In-Reply-To: <1jy0ncvu23.fsf@starbuckisacylon.baylibre.com>
References: <20251204053635.1234150-1-jian.hu@amlogic.com>
 <20251204053635.1234150-3-jian.hu@amlogic.com>
 <20251208-independent-warping-macaw-74a169@quoll>
 <dd90b445-bafb-46d4-8cec-e0877cf425b3@amlogic.com>
 <4f5ec838-f8d6-4c3b-94f2-b2a60cfe64ec@kernel.org>
 <1jy0ncvu23.fsf@starbuckisacylon.baylibre.com>
Message-ID: <38ef7ee0-1879-42d5-a7fd-d32b96d01367@kernel.org>

On 09/12/2025 11:16, Jerome Brunet wrote:
> On Tue 09 Dec 2025 at 07:01, Krzysztof Kozlowski <krzk at kernel.org> wrote:
> 
>> On 08/12/2025 09:40, Jian Hu wrote:
>>> Hi, Krzysztof
>>>
>>>
>>> Thans for your review.
>>>
>>> On 12/8/2025 2:17 PM, Krzysztof Kozlowski wrote:
>>>> [ EXTERNAL EMAIL ]
>>>>
>>>> On Thu, Dec 04, 2025 at 01:36:31PM +0800, Jian Hu wrote:
>>>>> Add DT bindings for the SCMI clock controller of the Amlogic T7 SoC family.
>>>>>
>>>>> Signed-off-by: Jian Hu <jian.hu at amlogic.com>
>>>>> Acked-by: Rob Herring (Arm) <robh at kernel.org>
>>>>> ---
>>>>>   include/dt-bindings/clock/amlogic,t7-scmi.h | 47 +++++++++++++++++++++
>>>>>   1 file changed, 47 insertions(+)
>>>>>   create mode 100644 include/dt-bindings/clock/amlogic,t7-scmi.h
>>>>>
>>>> Where is any binding doc for this? Why is this a separate patch?
>>>
>>>
>>> The ARM SCMI device tree binding specification is located at 
>>> ./Documentation/devicetree/bindings/firmware/arm,scmi.yaml.
>>
>> Then git grep for the file name - there is no such compatible. Are you
>> sure you follow writing bindings doc?
>>
>> Think how are you going to use these values. You will have phandle, yes?
>> To some controller, yes? Which one?
> 
> For the C3 (I believe the T7 is the same), the compatible being used is
> "arm,scmi-smc". It is a generic one documented here:
> 
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/firmware/arm,scmi.yaml?h=v6.18#n202
> 
> The phandle used is a subnode of that, to clock protocol:
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi?h=v6.18#n116
> 
> Same things is done on imx, stm and rockchip platforms from what I can
> see.

I see, thanks for explanation, it's fine.

> 
> Jian is just adding the arbitrary IDs used to identify the clocks in the
> FW. I don't think there is anything out of the ordirnary here.
> 
> Is there something else Rob and I missed reviewing this ?
> 
>>
>>>
>>> Certain secure clocks on the T7 rely on the ARM SCMI driver stack, which 
>>> is officially supported by ARM.
>>>
>>> The kernel-side SCMI client implementation resides in 
>>> ./drivers/firmware/arm_scmi/.
>>>
>>> To enable ARM SCMI on T7, three components are needed:
>>>
>>> - Kernel-side definition of ARM SCMI clock indices (this patch addresses 
>>> this component);
>>> - SCMI server implementation in the ARM Trusted Firmware (ATF) running 
>>> at Exception Level 3 (EL3), which has been integrated into the bootloader;
>>> - Device Tree Source (DTS) configuration for ARM SCMI clock nodes (the 
>>> DTS changes will be submitted after the T7 clock driver patches are 
>>> merged upstream).
>>
>> So silently you keep the users hidden? No, I want to see the users.
>>
> 
> Is there a new requirement to submit the DTS file changes along with the
> driver changes now ?
> 
> This has never been case before, especially since the changes are merged
> through different trees.

There is no such requirement, but "has never been case before" is
clearly not accurate, because I raised this question multiple times last
two-three years.

There is no reasonable way to hold publishing of DTS, therefore if
someone uses arguments like above with waiting for driver, I usually got
suspicious.

Also note, that many contributions from various people (not saying that
this one here is) were bad quality and badly designed but without seeing
DTS it takes me significantly more time to understand that design. So
yes, publish your DTS solving all of the questions and making reviewing
easier. Or don't and receive questions...


Best regards,
Krzysztof


From zhongqiu.han at oss.qualcomm.com  Wed Dec 10 22:20:48 2025
From: zhongqiu.han at oss.qualcomm.com (Zhongqiu Han)
Date: Thu, 11 Dec 2025 14:20:48 +0800
Subject: [PATCH] remoteproc: imx_rproc: Use strstarts for "rsc-table"
 check
In-Reply-To: <20251208233302.684139-1-shenwei.wang@nxp.com>
References: <20251208233302.684139-1-shenwei.wang@nxp.com>
Message-ID: <12888de0-1475-46a7-a594-bf7166227eee@oss.qualcomm.com>

On 12/9/2025 7:33 AM, Shenwei Wang wrote:
> The resource name may include an address suffix, for example:
> rsc-table at 1fff8000.
> 
> To handle such cases, use strstarts() instead of strcmp() when checking
> for "rsc-table".
> 
> Signed-off-by: Shenwei Wang <shenwei.wang at nxp.com>

Reviewed-by: Zhongqiu Han <zhongqiu.han at oss.qualcomm.com>

> ---
>   drivers/remoteproc/imx_rproc.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
> index 3be8790c14a2..33f21ab24c92 100644
> --- a/drivers/remoteproc/imx_rproc.c
> +++ b/drivers/remoteproc/imx_rproc.c
> @@ -694,7 +694,7 @@ static int imx_rproc_addr_init(struct imx_rproc *priv,
>   		}
>   		priv->mem[b].sys_addr = res.start;
>   		priv->mem[b].size = resource_size(&res);
> -		if (!strcmp(res.name, "rsc-table"))
> +		if (strstarts(res.name, "rsc-table"))
>   			priv->rsc_table = priv->mem[b].cpu_addr;
>   		b++;
>   	}


-- 
Thx and BRs,
Zhongqiu Han


From jacky_chou at aspeedtech.com  Wed Dec 10 22:24:58 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Thu, 11 Dec 2025 14:24:58 +0800
Subject: [PATCH net v3] net: mdio: aspeed: add dummy read to avoid
 read-after-write issue
Message-ID: <20251211-aspeed_mdio_add_dummy_read-v3-1-382868869004@aspeedtech.com>

The Aspeed MDIO controller may return incorrect data when a read operation
follows immediately after a write. Due to a controller bug, the subsequent
read can latch stale data, causing the polling logic to terminate earlier
than expected.

To work around this hardware issue, insert a dummy read after each write
operation. This ensures that the next actual read returns the correct
data and prevents premature polling exit.

This workaround has been verified to stabilize MDIO transactions on
affected Aspeed platforms.

Fixes: f160e99462c6 ("net: phy: Add mdio-aspeed")
Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
---
Changes in v3:
- Remove (void)
- Link to v2: https://lore.kernel.org/r/20251209-aspeed_mdio_add_dummy_read-v2-1-5f6061641989 at aspeedtech.com

Changes in v2:
- Updated the Fixes: tag
- Link to v1: https://lore.kernel.org/r/20251208-aspeed_mdio_add_dummy_read-v1-1-0a1861ad2161 at aspeedtech.com
---
 drivers/net/mdio/mdio-aspeed.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/net/mdio/mdio-aspeed.c b/drivers/net/mdio/mdio-aspeed.c
index e55be6dc9ae7..d6b9004c61dc 100644
--- a/drivers/net/mdio/mdio-aspeed.c
+++ b/drivers/net/mdio/mdio-aspeed.c
@@ -63,6 +63,13 @@ static int aspeed_mdio_op(struct mii_bus *bus, u8 st, u8 op, u8 phyad, u8 regad,
 
 	iowrite32(ctrl, ctx->base + ASPEED_MDIO_CTRL);
 
+	/* Workaround for read-after-write issue.
+	 * The controller may return stale data if a read follows immediately
+	 * after a write. A dummy read forces the hardware to update its
+	 * internal state, ensuring that the next real read returns correct data.
+	 */
+	ioread32(ctx->base + ASPEED_MDIO_CTRL);
+
 	return readl_poll_timeout(ctx->base + ASPEED_MDIO_CTRL, ctrl,
 				!(ctrl & ASPEED_MDIO_CTRL_FIRE),
 				ASPEED_MDIO_INTERVAL_US,

---
base-commit: 6bcb7727d9e612011b70d64a34401688b986d6ab
change-id: 20251208-aspeed_mdio_add_dummy_read-587ab8808817

Best regards,
-- 
Jacky Chou <jacky_chou at aspeedtech.com>



From amhetre at nvidia.com  Wed Dec 10 22:41:15 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Thu, 11 Dec 2025 12:11:15 +0530
Subject: [PATCH V4 1/3] iommu/arm-smmu-v3: Add device-tree support for
 CMDQV driver
In-Reply-To: <aTpgAU6FjinhclQH@nvidia.com>
References: <20251205065850.3841834-2-amhetre@nvidia.com>
 <202512090331.QAFgb6vQ-lkp@intel.com>
 <2bf7bb25-9a6b-42d5-b095-978f7bb81f35@nvidia.com>
 <e7c69e9c-6af4-468a-88ed-fb8829afb92e@arm.com> <aTpgAU6FjinhclQH@nvidia.com>
Message-ID: <b949c36e-f72c-49be-a243-535c43189d1b@nvidia.com>


On 12/11/2025 11:39 AM, Nicolin Chen wrote:
> On Wed, Dec 10, 2025 at 12:39:49PM +0000, Robin Murphy wrote:
>> On 2025-12-10 5:19 am, Ashish Mhetre wrote:
>> [...]
>>> Hi Robin, Nic,
>>> We removed ACPI dependency in Kconfig but driver still depends
>>> on ACPI for these functions. I will be protecting ACPIspecific
>>> tegra241-cmdqv code under CONFIG_ACPI similar to what is done
>>> in arm-smmu-v3 driver. Is this the correct thing to do or do you
>>> have any other suggestions?
>> Yes, when I commented that "depends on ACPI || OF" was functionally the same
>> as just removing "depends on ACPI", I didn't mean to suggest that wasn't
>> necessarily a genuine dependency still.
>>
>> I guess if you can wrap the ACPI-specific functions in a single #ifdef block
>> that's reasonable, however I do now wonder whether things couldn't be
>> factored out a bit more - if it's a standard DSDT/SSDT namespace device,
>> shouldn't there also be a corresponding platform device created for it,
>> which we could look up instead of delving directly into the _CRS of the ACPI
>> node itself? (not sure off-hand if there's a straightforward inverse of
>> ACPI_COMPANION()...)
> Ah, I did a quick tracer at acpi_create_platform_device(). And I
> do see platform devices being created. So, we could have made it
> ACPI-independent from the beginning, as you expected :)
>
> Ashish, let's attach the following patch in your series:

Ack, thanks Robin and Nic. I'll update my patches on top of Nic's patch
and re-post.

>  From 7b69a638276e66b16b923b0ce1743d3efc85a04c Mon Sep 17 00:00:00 2001
> From: Nicolin Chen <nicolinc at nvidia.com>
> Date: Thu, 11 Dec 2025 05:47:05 +0000
> Subject: [PATCH] iommu/tegra241-cmdqv: Decouple driver from ACPI
>
> A platform device is created by acpi_create_platform_device() per CMDQV's
> adev. That means there is no point in going through _CRS of ACPI.
>
> Replace all the ACPI functions with standard platform functions. And drop
> all ACPI dependencies. This will make the driver compatible with DT also.
>
> Suggested-by: Robin Murphy <robin.murphy at arm.com>
> Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
> ---
>   drivers/iommu/arm/Kconfig                     |  1 -
>   drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   |  2 +-
>   .../iommu/arm/arm-smmu-v3/tegra241-cmdqv.c    | 84 +++----------------
>   3 files changed, 13 insertions(+), 74 deletions(-)
>
> diff --git a/drivers/iommu/arm/Kconfig b/drivers/iommu/arm/Kconfig
> index ef42bbe07dbef..5fac08b89deea 100644
> --- a/drivers/iommu/arm/Kconfig
> +++ b/drivers/iommu/arm/Kconfig
> @@ -121,7 +121,6 @@ config ARM_SMMU_V3_KUNIT_TEST
>   
>   config TEGRA241_CMDQV
>   	bool "NVIDIA Tegra241 CMDQ-V extension support for ARM SMMUv3"
> -	depends on ACPI
>   	help
>   	  Support for NVIDIA CMDQ-Virtualization extension for ARM SMMUv3. The
>   	  CMDQ-V extension is similar to v3.3 ECMDQ for multi command queues
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index 38028e4a52f7f..0c98be3135c63 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -5280,7 +5280,7 @@ static void acpi_smmu_dsdt_probe_tegra241_cmdqv(struct acpi_iort_node *node,
>   	adev = acpi_dev_get_first_match_dev("NVDA200C", uid, -1);
>   	if (adev) {
>   		/* Tegra241 CMDQV driver is responsible for put_device() */
> -		smmu->impl_dev = &adev->dev;
> +		smmu->impl_dev = acpi_get_first_physical_node(adev);
>   		smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
>   		dev_info(smmu->dev, "found companion CMDQV device: %s\n",
>   			 dev_name(smmu->impl_dev));
> diff --git a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
> index 378104cd395e5..1fc03b72beb88 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
> @@ -3,17 +3,15 @@
>   
>   #define dev_fmt(fmt) "tegra241_cmdqv: " fmt
>   
> -#include <linux/acpi.h>
>   #include <linux/debugfs.h>
>   #include <linux/dma-mapping.h>
>   #include <linux/interrupt.h>
>   #include <linux/iommu.h>
>   #include <linux/iommufd.h>
>   #include <linux/iopoll.h>
> +#include <linux/platform_device.h>
>   #include <uapi/linux/iommufd.h>
>   
> -#include <acpi/acpixf.h>
> -
>   #include "arm-smmu-v3.h"
>   
>   /* CMDQV register page base and size defines */
> @@ -854,69 +852,6 @@ static struct arm_smmu_impl_ops tegra241_cmdqv_impl_ops = {
>   
>   /* Probe Functions */
>   
> -static int tegra241_cmdqv_acpi_is_memory(struct acpi_resource *res, void *data)
> -{
> -	struct resource_win win;
> -
> -	return !acpi_dev_resource_address_space(res, &win);
> -}
> -
> -static int tegra241_cmdqv_acpi_get_irqs(struct acpi_resource *ares, void *data)
> -{
> -	struct resource r;
> -	int *irq = data;
> -
> -	if (*irq <= 0 && acpi_dev_resource_interrupt(ares, 0, &r))
> -		*irq = r.start;
> -	return 1; /* No need to add resource to the list */
> -}
> -
> -static struct resource *
> -tegra241_cmdqv_find_acpi_resource(struct device *dev, int *irq)
> -{
> -	struct acpi_device *adev = to_acpi_device(dev);
> -	struct list_head resource_list;
> -	struct resource_entry *rentry;
> -	struct resource *res = NULL;
> -	int ret;
> -
> -	INIT_LIST_HEAD(&resource_list);
> -	ret = acpi_dev_get_resources(adev, &resource_list,
> -				     tegra241_cmdqv_acpi_is_memory, NULL);
> -	if (ret < 0) {
> -		dev_err(dev, "failed to get memory resource: %d\n", ret);
> -		return NULL;
> -	}
> -
> -	rentry = list_first_entry_or_null(&resource_list,
> -					  struct resource_entry, node);
> -	if (!rentry) {
> -		dev_err(dev, "failed to get memory resource entry\n");
> -		goto free_list;
> -	}
> -
> -	/* Caller must free the res */
> -	res = kzalloc(sizeof(*res), GFP_KERNEL);
> -	if (!res)
> -		goto free_list;
> -
> -	*res = *rentry->res;
> -
> -	acpi_dev_free_resource_list(&resource_list);
> -
> -	INIT_LIST_HEAD(&resource_list);
> -
> -	if (irq)
> -		ret = acpi_dev_get_resources(adev, &resource_list,
> -					     tegra241_cmdqv_acpi_get_irqs, irq);
> -	if (ret < 0 || !irq || *irq <= 0)
> -		dev_warn(dev, "no interrupt. errors will not be reported\n");
> -
> -free_list:
> -	acpi_dev_free_resource_list(&resource_list);
> -	return res;
> -}
> -
>   static int tegra241_cmdqv_init_structures(struct arm_smmu_device *smmu)
>   {
>   	struct tegra241_cmdqv *cmdqv =
> @@ -1042,18 +977,23 @@ __tegra241_cmdqv_probe(struct arm_smmu_device *smmu, struct resource *res,
>   
>   struct arm_smmu_device *tegra241_cmdqv_probe(struct arm_smmu_device *smmu)
>   {
> +	struct platform_device *pdev = to_platform_device(smmu->impl_dev);
>   	struct arm_smmu_device *new_smmu;
> -	struct resource *res = NULL;
> +	struct resource *res;
>   	int irq;
>   
> -	if (!smmu->dev->of_node)
> -		res = tegra241_cmdqv_find_acpi_resource(smmu->impl_dev, &irq);
> -	if (!res)
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res) {
> +		dev_err(&pdev->dev, "no memory resource found for CMDQV\n");
>   		goto out_fallback;
> +	}
>   
> -	new_smmu = __tegra241_cmdqv_probe(smmu, res, irq);
> -	kfree(res);
> +	irq = platform_get_irq_optional(pdev, 0);
> +	if (irq <= 0)
> +		dev_warn(&pdev->dev,
> +			 "no interrupt. errors will not be reported\n");
>   
> +	new_smmu = __tegra241_cmdqv_probe(smmu, res, irq);
>   	if (new_smmu)
>   		return new_smmu;
>   


From hongxing.zhu at nxp.com  Wed Dec 10 22:48:17 2025
From: hongxing.zhu at nxp.com (Richard Zhu)
Date: Thu, 11 Dec 2025 14:48:17 +0800
Subject: [PATCH v10 0/4] PCI: imx6: Add external reference clock mode support
Message-ID: <20251211064821.2707001-1-hongxing.zhu@nxp.com>

I'm really sorry to send this version patch-set late, because that I was
engaged in other emergent tasks in the past weeks. And didn't have time
to continue this topic. Now, I have chance to continue doing this again.
Sorry to bring the inconvenience to the patch review.

i.MX95 PCIes have two reference clock inputs: one from internal PLL.
It's wired inside chip and present as "ref" clock. It's not an optional
clock. The other from off chip crystal oscillator. The "extref" clock
refers to a reference clock from an external crystal oscillator through
the CLKIN_N/P pair PADs. It is an optional clock, relied on the board
design.

Add additional optional external reference clock input for i.MX95 PCIes.

Main change in v10:
Thanks for Krzysztof's kindly review. 
- Change the miniItem of i.MX95 PCIe clocks from '4' to '5', since the "ref"
  clock is not optional. Update the commit message to describe why an
  additional optinal external reference clock input is added for i.MX95 PCIe.
- Add a new patch to fix the dtbs_check error after changing the miniItem of
  i.MX95 PCIe clocks in timx95-tqma9596sa-mb-smarc-2.dts.

Main change in v9:
Thanks for Conor's kindly review.
- Enlarge the maxItem of clocks for i.MX95 PCIe.
https://lore.kernel.org/imx/20251031031907.1390870-1-hongxing.zhu at nxp.com/

Main change in v8:
- Rebase to v6.18-rc1.
- No need to initialize bool parameter to the deault value "false" refer
  to Mani' comments in v7
https://lore.kernel.org/imx/20251024024013.775836-1-hongxing.zhu at nxp.com/

Main change in v7:
- Refine the subjects and commit message refer to Bjorn's comments.
https://lore.kernel.org/imx/20250918032555.3987157-1-hongxing.zhu at nxp.com/

Main change in v6:
- Refer to Krzysztof's comments, let i.MX95 PCIes has the "ref" clock
  since it is wired actually, and add one more optional "extref" clock
  for i.MX95 PCIes.
https://lore.kernel.org/imx/20250917045238.1048484-1-hongxing.zhu at nxp.com/

Main change in v5:
- Update the commit message of first patch refer to Bjorn's comments.
- Correct the typo error and update the description of property in the
  first patch.
https://lore.kernel.org/imx/20250915035348.3252353-1-hongxing.zhu at nxp.com/

Main change in v4:
- Add one more reference clock "extref" to be onhalf the reference clock
  that comes from external crystal oscillator.
https://lore.kernel.org/imx/20250626073804.3113757-1-hongxing.zhu at nxp.com/

Main change in v3:
- Update the logic check external reference clock mode is enabled or
  not in the driver codes.
https://lore.kernel.org/imx/20250620031350.674442-1-hongxing.zhu at nxp.com/

Main change in v2:
- Fix yamllint warning.
- Refine the driver codes.
https://lore.kernel.org/imx/20250619091004.338419-1-hongxing.zhu at nxp.com/

[PATCH v10 1/4] dt-bindings: PCI: dwc: Add external reference clock
[PATCH v10 2/4] dt-bindings: PCI: pci-imx6: Add external reference
[PATCH v10 3/4] PCI: imx6: Add external reference clock input mode
[PATCH v10 4/4] arm64: dt: imx95: Add the missed ref clock for

Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml      |  7 +++++--
Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml |  6 ++++++
arch/arm64/boot/dts/freescale/imx95-tqma9596sa-mb-smarc-2.dts  | 10 ++++++----
drivers/pci/controller/dwc/pci-imx6.c                          | 19 ++++++++++++-------
4 files changed, 29 insertions(+), 13 deletions(-)



From hongxing.zhu at nxp.com  Wed Dec 10 22:48:18 2025
From: hongxing.zhu at nxp.com (Richard Zhu)
Date: Thu, 11 Dec 2025 14:48:18 +0800
Subject: [PATCH v10 1/4] dt-bindings: PCI: dwc: Add external reference clock input
In-Reply-To: <20251211064821.2707001-1-hongxing.zhu@nxp.com>
References: <20251211064821.2707001-1-hongxing.zhu@nxp.com>
Message-ID: <20251211064821.2707001-2-hongxing.zhu@nxp.com>

Add external reference clock input "extref" for a reference clock that
comes from external crystal oscillator.

Signed-off-by: Richard Zhu <hongxing.zhu at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
 .../devicetree/bindings/pci/snps,dw-pcie-common.yaml        | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml b/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml
index 34594972d8dbe..0134a759185ec 100644
--- a/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml
+++ b/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml
@@ -105,6 +105,12 @@ properties:
             define it with this name (for instance pipe, core and aux can
             be connected to a single source of the periodic signal).
           const: ref
+        - description:
+            Some dwc wrappers (like i.MX95 PCIes) have two reference clock
+            inputs, one from an internal PLL, the other from an off-chip crystal
+            oscillator. If present, 'extref' refers to a reference clock from
+            an external oscillator.
+          const: extref
         - description:
             Clock for the PHY registers interface. Originally this is
             a PHY-viewport-based interface, but some platform may have
-- 
2.37.1



From hongxing.zhu at nxp.com  Wed Dec 10 22:48:19 2025
From: hongxing.zhu at nxp.com (Richard Zhu)
Date: Thu, 11 Dec 2025 14:48:19 +0800
Subject: [PATCH v10 2/4] dt-bindings: PCI: pci-imx6: Add external reference clock input
In-Reply-To: <20251211064821.2707001-1-hongxing.zhu@nxp.com>
References: <20251211064821.2707001-1-hongxing.zhu@nxp.com>
Message-ID: <20251211064821.2707001-3-hongxing.zhu@nxp.com>

i.MX95 PCIes have two reference clock inputs: one from internal PLL.
It's wired inside chip and present as "ref" clock. It's not an optional
clock. The other from off chip crystal oscillator. The "extref" clock
refers to a reference clock from an external crystal oscillator through
the CLKIN_N/P pair PADs. It is an optional clock, relied on the board
design.

Add additional optional external reference clock input for i.MX95 PCIes.

Signed-off-by: Richard Zhu <hongxing.zhu at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
 Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml
index ca5f2970f217c..12a01f7a57443 100644
--- a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml
@@ -44,7 +44,7 @@ properties:
 
   clock-names:
     minItems: 3
-    maxItems: 5
+    maxItems: 6
 
   interrupts:
     minItems: 1
@@ -212,14 +212,17 @@ allOf:
     then:
       properties:
         clocks:
-          maxItems: 5
+          minItems: 5
+          maxItems: 6
         clock-names:
+          minItems: 5
           items:
             - const: pcie
             - const: pcie_bus
             - const: pcie_phy
             - const: pcie_aux
             - const: ref
+            - const: extref  # Optional
 
 unevaluatedProperties: false
 
-- 
2.37.1



From hongxing.zhu at nxp.com  Wed Dec 10 22:48:20 2025
From: hongxing.zhu at nxp.com (Richard Zhu)
Date: Thu, 11 Dec 2025 14:48:20 +0800
Subject: [PATCH v10 3/4] PCI: imx6: Add external reference clock input mode support
In-Reply-To: <20251211064821.2707001-1-hongxing.zhu@nxp.com>
References: <20251211064821.2707001-1-hongxing.zhu@nxp.com>
Message-ID: <20251211064821.2707001-4-hongxing.zhu@nxp.com>

i.MX95 PCIes have two reference clock inputs: one from internal PLL, the
other from off chip crystal oscillator. The "extref" clock refers to a
reference clock from an external crystal oscillator.

Add external reference clock input mode support for i.MX95 PCIes.

Signed-off-by: Richard Zhu <hongxing.zhu at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/pci/controller/dwc/pci-imx6.c | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
index 4668fc9648bff..a6db1f0f73c36 100644
--- a/drivers/pci/controller/dwc/pci-imx6.c
+++ b/drivers/pci/controller/dwc/pci-imx6.c
@@ -149,6 +149,7 @@ struct imx_pcie {
 	struct gpio_desc	*reset_gpiod;
 	struct clk_bulk_data	*clks;
 	int			num_clks;
+	bool			enable_ext_refclk;
 	struct regmap		*iomuxc_gpr;
 	u16			msi_ctrl;
 	u32			controller_id;
@@ -241,6 +242,8 @@ static unsigned int imx_pcie_grp_offset(const struct imx_pcie *imx_pcie)
 
 static int imx95_pcie_init_phy(struct imx_pcie *imx_pcie)
 {
+	bool ext = imx_pcie->enable_ext_refclk;
+
 	/*
 	 * ERR051624: The Controller Without Vaux Cannot Exit L23 Ready
 	 * Through Beacon or PERST# De-assertion
@@ -259,13 +262,12 @@ static int imx95_pcie_init_phy(struct imx_pcie *imx_pcie)
 			IMX95_PCIE_PHY_CR_PARA_SEL,
 			IMX95_PCIE_PHY_CR_PARA_SEL);
 
-	regmap_update_bits(imx_pcie->iomuxc_gpr,
-			   IMX95_PCIE_PHY_GEN_CTRL,
-			   IMX95_PCIE_REF_USE_PAD, 0);
-	regmap_update_bits(imx_pcie->iomuxc_gpr,
-			   IMX95_PCIE_SS_RW_REG_0,
+	regmap_update_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_PHY_GEN_CTRL,
+			   ext ? IMX95_PCIE_REF_USE_PAD : 0,
+			   IMX95_PCIE_REF_USE_PAD);
+	regmap_update_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_0,
 			   IMX95_PCIE_REF_CLKEN,
-			   IMX95_PCIE_REF_CLKEN);
+			   ext ? 0 : IMX95_PCIE_REF_CLKEN);
 
 	return 0;
 }
@@ -1602,7 +1604,7 @@ static int imx_pcie_probe(struct platform_device *pdev)
 	struct imx_pcie *imx_pcie;
 	struct device_node *np;
 	struct device_node *node = dev->of_node;
-	int ret, domain;
+	int i, ret, domain;
 	u16 val;
 
 	imx_pcie = devm_kzalloc(dev, sizeof(*imx_pcie), GFP_KERNEL);
@@ -1653,6 +1655,9 @@ static int imx_pcie_probe(struct platform_device *pdev)
 	if (imx_pcie->num_clks < 0)
 		return dev_err_probe(dev, imx_pcie->num_clks,
 				     "failed to get clocks\n");
+	for (i = 0; i < imx_pcie->num_clks; i++)
+		if (strncmp(imx_pcie->clks[i].id, "extref", 6) == 0)
+			imx_pcie->enable_ext_refclk = true;
 
 	if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_HAS_PHYDRV)) {
 		imx_pcie->phy = devm_phy_get(dev, "pcie-phy");
-- 
2.37.1



From hongxing.zhu at nxp.com  Wed Dec 10 22:48:21 2025
From: hongxing.zhu at nxp.com (Richard Zhu)
Date: Thu, 11 Dec 2025 14:48:21 +0800
Subject: [PATCH v10 4/4] arm64: dt: imx95: Add the missed ref clock for PCIe[0,1]
In-Reply-To: <20251211064821.2707001-1-hongxing.zhu@nxp.com>
References: <20251211064821.2707001-1-hongxing.zhu@nxp.com>
Message-ID: <20251211064821.2707001-5-hongxing.zhu@nxp.com>

i.MX95 PCIes have two reference clock inputs, one of them is from
internal PLL. It's wired inside chip and present as "ref" clock. It's
not an optional clock.

Add the missed ref clock for PCIe[0,1].

Signed-off-by: Richard Zhu <hongxing.zhu at nxp.com>
---
 .../boot/dts/freescale/imx95-tqma9596sa-mb-smarc-2.dts | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx95-tqma9596sa-mb-smarc-2.dts b/arch/arm64/boot/dts/freescale/imx95-tqma9596sa-mb-smarc-2.dts
index 5b6b2bb80b288..1258fcb54681e 100644
--- a/arch/arm64/boot/dts/freescale/imx95-tqma9596sa-mb-smarc-2.dts
+++ b/arch/arm64/boot/dts/freescale/imx95-tqma9596sa-mb-smarc-2.dts
@@ -237,8 +237,9 @@ &pcie0 {
 	clocks = <&scmi_clk IMX95_CLK_HSIO>,
 		 <&pcieclk 1>,
 		 <&scmi_clk IMX95_CLK_HSIOPLL_VCO>,
-		 <&scmi_clk IMX95_CLK_HSIOPCIEAUX>;
-	clock-names = "pcie", "pcie_bus", "pcie_phy", "pcie_aux";
+		 <&scmi_clk IMX95_CLK_HSIOPCIEAUX>,
+		 <&hsio_blk_ctl 0>;
+	clock-names = "pcie", "pcie_bus", "pcie_phy", "pcie_aux", "ref";
 	reset-gpio = <&expander2 9 GPIO_ACTIVE_LOW>;
 	status = "okay";
 };
@@ -250,8 +251,9 @@ &pcie1 {
 	clocks = <&scmi_clk IMX95_CLK_HSIO>,
 		 <&pcieclk 0>,
 		 <&scmi_clk IMX95_CLK_HSIOPLL_VCO>,
-		 <&scmi_clk IMX95_CLK_HSIOPCIEAUX>;
-	clock-names = "pcie", "pcie_bus", "pcie_phy", "pcie_aux";
+		 <&scmi_clk IMX95_CLK_HSIOPCIEAUX>,
+		 <&hsio_blk_ctl 0>;
+	clock-names = "pcie", "pcie_bus", "pcie_phy", "pcie_aux", "ref";
 	reset-gpio = <&expander2 10 GPIO_ACTIVE_LOW>;
 	status = "okay";
 };
-- 
2.37.1



From tglx at linutronix.de  Wed Dec 10 22:55:02 2025
From: tglx at linutronix.de (Thomas Gleixner)
Date: Thu, 11 Dec 2025 15:55:02 +0900
Subject: [PATCH v9 15/16] entry: Inline syscall_exit_work()
In-Reply-To: <b382cc8a-3ce9-4fb1-bc0a-a3d9796251d1@arm.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
 <20251204082123.2792067-16-ruanjinjie@huawei.com>
 <b382cc8a-3ce9-4fb1-bc0a-a3d9796251d1@arm.com>
Message-ID: <87345hfqyh.ffs@tglx>

On Tue, Dec 09 2025 at 14:48, Kevin Brodsky wrote:
> On 04/12/2025 09:21, Jinjie Ruan wrote:
>> After switch arm64 to Generic Entry, a new hotspot syscall_exit_work()
>> appeared because syscall_exit_work() is no longer inlined. so inline
>
> Before this series the call to syscall_trace_exit() in el0_svc_common()
> could not be inlined, so "no longer inlined" doesn't seem to be accurate.
>
>> syscall_exit_work(), and it has 2.6% performance uplift on perf bench
>> basic syscall on kunpeng920 as below.
>
> That seems strange. syscall_exit_work() is only called if some flag in
> SYSCALL_WORK_EXIT is set, which means that we're doing something special
> like tracing. That shouldn't be the case when running a simple perf
> bench syscall.
>
> Also worth nothing that its counterpart (syscall_trace_enter())) is not
> currently inlined, the asymmetry would have to be justified.
>
>>     | Metric     | W/O this patch | With this patch | Change    |
>>     | ---------- | -------------- | --------------- | --------- |
>>     | Total time | 2.171 [sec]    | 2.114 [sec]     |  ?2.6%    |
>>     | usecs/op   | 0.217192       | 0.211453        |  ?2.6%    |
>>     | ops/sec    | 4,604,225      | 4,729,178       |  ?2.7%    |
>>
>> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
>> ---
>>  include/linux/entry-common.h  | 63 ++++++++++++++++++++++++++++++++++-
>>  kernel/entry/syscall-common.c | 59 ++------------------------------
>
> These changes are purely generic, surely all architectures using
> GENERIC_ENTRY should get similar benefits (assuming LTO isn't used)?

Correct, but as you said this does not make sense as the syscall exit
work should be rare.

Jinjie, can you please figure out which TIF bit is causing this to be
invoked?

I have a suspicion that it is TIF_NOTIFY_RESUME. If that's the case
you're seing the RSEQ overhead, which should be completely gone with the
rewrite that got just merged into Linus tree.

Thanks,

        tglx




From robh at kernel.org  Wed Dec 10 23:27:02 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Thu, 11 Dec 2025 01:27:02 -0600
Subject: [PATCH v8 5/8] dt-bindings: arm: add an interrupt property for
 Coresight CTCU
In-Reply-To: <20251211-enable-byte-cntr-for-ctcu-v8-5-3e12ff313191@oss.qualcomm.com>
References: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
 <20251211-enable-byte-cntr-for-ctcu-v8-5-3e12ff313191@oss.qualcomm.com>
Message-ID: <176543802198.60924.10267408914731981420.robh@kernel.org>


On Thu, 11 Dec 2025 14:10:44 +0800, Jie Gan wrote:
> Add an interrupt property to CTCU device. The interrupt will be triggered
> when the data size in the ETR buffer exceeds the threshold of the
> BYTECNTRVAL register. Programming a threshold in the BYTECNTRVAL register
> of CTCU device will enable the interrupt.
> 
> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
> Reviewed-by: Mike Leach <mike.leach at linaro.org>
> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
> ---
>  .../devicetree/bindings/arm/qcom,coresight-ctcu.yaml    | 17 +++++++++++++++++
>  1 file changed, 17 insertions(+)
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:
Error: Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.example.dts:36.31-32 syntax error
FATAL ERROR: Unable to parse input tree
make[2]: *** [scripts/Makefile.dtbs:141: Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.example.dtb] Error 1
make[2]: *** Waiting for unfinished jobs....
make[1]: *** [/builds/robherring/dt-review-ci/linux/Makefile:1559: 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/20251211-enable-byte-cntr-for-ctcu-v8-5-3e12ff313191 at 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.



From jie.gan at oss.qualcomm.com  Wed Dec 10 23:35:32 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Thu, 11 Dec 2025 15:35:32 +0800
Subject: [PATCH v8 5/8] dt-bindings: arm: add an interrupt property for
 Coresight CTCU
In-Reply-To: <176543802198.60924.10267408914731981420.robh@kernel.org>
References: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
 <20251211-enable-byte-cntr-for-ctcu-v8-5-3e12ff313191@oss.qualcomm.com>
 <176543802198.60924.10267408914731981420.robh@kernel.org>
Message-ID: <44b8df0e-2786-420b-9402-ee19f4cda0d2@oss.qualcomm.com>



On 12/11/2025 3:27 PM, Rob Herring (Arm) wrote:
> 
> On Thu, 11 Dec 2025 14:10:44 +0800, Jie Gan wrote:
>> Add an interrupt property to CTCU device. The interrupt will be triggered
>> when the data size in the ETR buffer exceeds the threshold of the
>> BYTECNTRVAL register. Programming a threshold in the BYTECNTRVAL register
>> of CTCU device will enable the interrupt.
>>
>> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
>> Reviewed-by: Mike Leach <mike.leach at linaro.org>
>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> ---
>>   .../devicetree/bindings/arm/qcom,coresight-ctcu.yaml    | 17 +++++++++++++++++
>>   1 file changed, 17 insertions(+)
>>
> 
> My bot found errors running 'make dt_binding_check' on your patch:
> 
> yamllint warnings/errors:
> 
> dtschema/dtc warnings/errors:
> Error: Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.example.dts:36.31-32 syntax error
> FATAL ERROR: Unable to parse input tree

Will fix it in next version.

Thanks,
Jie

> make[2]: *** [scripts/Makefile.dtbs:141: Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.example.dtb] Error 1
> make[2]: *** Waiting for unfinished jobs....
> make[1]: *** [/builds/robherring/dt-review-ci/linux/Makefile:1559: 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/20251211-enable-byte-cntr-for-ctcu-v8-5-3e12ff313191 at 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.
> 



From ziniu.wang_1 at nxp.com  Wed Dec 10 23:56:03 2025
From: ziniu.wang_1 at nxp.com (ziniu.wang_1 at nxp.com)
Date: Thu, 11 Dec 2025 15:56:03 +0800
Subject: [PATCH v3] mmc: sdhci-esdhc-imx: wait for data transfer completion before reset
Message-ID: <20251211075603.533033-1-ziniu.wang_1@nxp.com>

From: Luke Wang <ziniu.wang_1 at nxp.com>

On IMX7ULP platforms, certain SD cards (e.g. Kingston Canvas Go! Plus)
cause system hangs and reboots during manual tuning. These cards exhibit
large gaps (~16us) between tuning command response and data transmission.
When cmd CRC errors occur during tuning, the code assumes data errors even
tuning data hasn't been fully received and then reset host data circuit.

Per IMX7ULP reference manual, reset operations (RESET_DATA/ALL) need to
make sure no active data transfers. Previously, resetting while data was
in-flight would clear data circuit, including ADMA/SDMA address, causing
data to be transmitted to incorrect memory address. This patch adds
polling for data transfer completion before executing resets.

Signed-off-by: Luke Wang <ziniu.wang_1 at nxp.com>
Reviewed-by: Bough Chen <haibo.chen at nxp.com>
---
v3: add define for timeout value
v2: amend commit message
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index a7a5df673b0f..97461e20425d 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -216,6 +216,8 @@
 #define ESDHC_FLAG_DUMMY_PAD		BIT(19)
 
 #define ESDHC_AUTO_TUNING_WINDOW	3
+/* 100ms timeout for data inhibit */
+#define ESDHC_DATA_INHIBIT_WAIT_US	100000
 
 enum wp_types {
 	ESDHC_WP_NONE,		/* no WP, neither controller nor gpio */
@@ -1453,6 +1455,22 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
 
 static void esdhc_reset(struct sdhci_host *host, u8 mask)
 {
+	u32 present_state;
+	int ret;
+
+	/*
+	 * For data or full reset, ensure any active data transfer completes
+	 * before resetting to avoid system hang.
+	 */
+	if (mask & (SDHCI_RESET_DATA | SDHCI_RESET_ALL)) {
+		ret = readl_poll_timeout_atomic(host->ioaddr + ESDHC_PRSSTAT, present_state,
+						!(present_state & SDHCI_DATA_INHIBIT), 2,
+						ESDHC_DATA_INHIBIT_WAIT_US);
+		if (ret == -ETIMEDOUT)
+			dev_warn(mmc_dev(host->mmc),
+				 "timeout waiting for data transfer completion\n");
+	}
+
 	sdhci_and_cqhci_reset(host, mask);
 
 	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
-- 
2.34.1



From chou.cosmo at gmail.com  Thu Dec 11 00:03:11 2025
From: chou.cosmo at gmail.com (Cosmo Chou)
Date: Thu, 11 Dec 2025 16:03:11 +0800
Subject: [PATCH] ARM: dts: aspeed: bletchley: Fix dt-schema warnings
Message-ID: <20251211080311.242771-1-chou.cosmo@gmail.com>

Update the device tree to fix dt-schema warnings:
- Use generic node names for SPI, LEDs, and GPIO keys.
- Update SPI GPIO properties to use the "-gpios" suffix.
- Remove unused address/size cells from pca9539 nodes.
- Use 'aspeed,int-vref-microvolt' in ADC nodes.
- Remove unused 'aspeed,hw-timeout-ms' from i2c13.

Signed-off-by: Cosmo Chou <chou.cosmo at gmail.com>
---
 .../aspeed/aspeed-bmc-facebook-bletchley.dts  | 100 ++++++++++--------
 1 file changed, 54 insertions(+), 46 deletions(-)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts
index abdb1562115a..7c27bf6bb51d 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts
+++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts
@@ -34,14 +34,14 @@ iio-hwmon {
 			<&adc1 4>, <&adc1 5>, <&adc1 6>, <&adc1 7>;
 	};
 
-	spi1_gpio: spi1-gpio {
+	spi1_gpio: spi {
 		compatible = "spi-gpio";
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		gpio-sck = <&gpio0 ASPEED_GPIO(Z, 3) GPIO_ACTIVE_HIGH>;
-		gpio-mosi = <&gpio0 ASPEED_GPIO(Z, 4) GPIO_ACTIVE_HIGH>;
-		gpio-miso = <&gpio0 ASPEED_GPIO(Z, 5) GPIO_ACTIVE_HIGH>;
+		sck-gpios = <&gpio0 ASPEED_GPIO(Z, 3) GPIO_ACTIVE_HIGH>;
+		mosi-gpios = <&gpio0 ASPEED_GPIO(Z, 4) GPIO_ACTIVE_HIGH>;
+		miso-gpios = <&gpio0 ASPEED_GPIO(Z, 5) GPIO_ACTIVE_HIGH>;
 		num-chipselects = <1>;
 		cs-gpios = <&gpio0 ASPEED_GPIO(Z, 0) GPIO_ACTIVE_LOW>;
 
@@ -54,7 +54,8 @@ tpm at 0 {
 
 	front_gpio_leds {
 		compatible = "gpio-leds";
-		sys_log_id {
+		led-0 {
+			label = "sys_log_id";
 			default-state = "off";
 			gpios = <&front_leds 0 GPIO_ACTIVE_LOW>;
 		};
@@ -62,42 +63,50 @@ sys_log_id {
 
 	fan_gpio_leds {
 		compatible = "gpio-leds";
-		fan0_blue {
+		led-0 {
+			label = "fan0_blue";
 			retain-state-shutdown;
 			default-state = "on";
 			gpios = <&fan_leds 8 GPIO_ACTIVE_HIGH>;
 		};
-		fan1_blue {
+		led-1 {
+			label = "fan1_blue";
 			retain-state-shutdown;
 			default-state = "on";
 			gpios = <&fan_leds 9 GPIO_ACTIVE_HIGH>;
 		};
-		fan2_blue {
+		led-2 {
+			label = "fan2_blue";
 			retain-state-shutdown;
 			default-state = "on";
 			gpios = <&fan_leds 10 GPIO_ACTIVE_HIGH>;
 		};
-		fan3_blue {
+		led-3 {
+			label = "fan3_blue";
 			retain-state-shutdown;
 			default-state = "on";
 			gpios = <&fan_leds 11 GPIO_ACTIVE_HIGH>;
 		};
-		fan0_amber {
+		led-4 {
+			label = "fan0_amber";
 			retain-state-shutdown;
 			default-state = "off";
 			gpios = <&fan_leds 12 GPIO_ACTIVE_HIGH>;
 		};
-		fan1_amber {
+		led-5 {
+			label = "fan1_amber";
 			retain-state-shutdown;
 			default-state = "off";
 			gpios = <&fan_leds 13 GPIO_ACTIVE_HIGH>;
 		};
-		fan2_amber {
+		led-6 {
+			label = "fan2_amber";
 			retain-state-shutdown;
 			default-state = "off";
 			gpios = <&fan_leds 14 GPIO_ACTIVE_HIGH>;
 		};
-		fan3_amber {
+		led-7 {
+			label = "fan3_amber";
 			retain-state-shutdown;
 			default-state = "off";
 			gpios = <&fan_leds 15 GPIO_ACTIVE_HIGH>;
@@ -106,12 +115,14 @@ fan3_amber {
 
 	sled1_gpio_leds {
 		compatible = "gpio-leds";
-		sled1_amber {
+		led-0 {
+			label = "sled1_amber";
 			retain-state-shutdown;
 			default-state = "keep";
 			gpios = <&sled1_leds 0 GPIO_ACTIVE_LOW>;
 		};
-		sled1_blue {
+		led-1 {
+			label = "sled1_blue";
 			retain-state-shutdown;
 			default-state = "keep";
 			gpios = <&sled1_leds 1 GPIO_ACTIVE_LOW>;
@@ -120,12 +131,14 @@ sled1_blue {
 
 	sled2_gpio_leds {
 		compatible = "gpio-leds";
-		sled2_amber {
+		led-0 {
+			label = "sled2_amber";
 			retain-state-shutdown;
 			default-state = "keep";
 			gpios = <&sled2_leds 0 GPIO_ACTIVE_LOW>;
 		};
-		sled2_blue {
+		led-1 {
+			label = "sled2_blue";
 			retain-state-shutdown;
 			default-state = "keep";
 			gpios = <&sled2_leds 1 GPIO_ACTIVE_LOW>;
@@ -134,12 +147,14 @@ sled2_blue {
 
 	sled3_gpio_leds {
 		compatible = "gpio-leds";
-		sled3_amber {
+		led-0 {
+			label = "sled3_amber";
 			retain-state-shutdown;
 			default-state = "keep";
 			gpios = <&sled3_leds 0 GPIO_ACTIVE_LOW>;
 		};
-		sled3_blue {
+		led-1 {
+			label = "sled3_blue";
 			retain-state-shutdown;
 			default-state = "keep";
 			gpios = <&sled3_leds 1 GPIO_ACTIVE_LOW>;
@@ -148,12 +163,14 @@ sled3_blue {
 
 	sled4_gpio_leds {
 		compatible = "gpio-leds";
-		sled4_amber {
+		led-0 {
+			label = "sled4_amber";
 			retain-state-shutdown;
 			default-state = "keep";
 			gpios = <&sled4_leds 0 GPIO_ACTIVE_LOW>;
 		};
-		sled4_blue {
+		led-1 {
+			label = "sled4_blue";
 			retain-state-shutdown;
 			default-state = "keep";
 			gpios = <&sled4_leds 1 GPIO_ACTIVE_LOW>;
@@ -162,12 +179,14 @@ sled4_blue {
 
 	sled5_gpio_leds {
 		compatible = "gpio-leds";
-		sled5_amber {
+		led-0 {
+			label = "sled5_amber";
 			retain-state-shutdown;
 			default-state = "keep";
 			gpios = <&sled5_leds 0 GPIO_ACTIVE_LOW>;
 		};
-		sled5_blue {
+		led-1 {
+			label = "sled5_blue";
 			retain-state-shutdown;
 			default-state = "keep";
 			gpios = <&sled5_leds 1 GPIO_ACTIVE_LOW>;
@@ -176,12 +195,14 @@ sled5_blue {
 
 	sled6_gpio_leds {
 		compatible = "gpio-leds";
-		sled6_amber {
+		led-0 {
+			label = "sled6_amber";
 			retain-state-shutdown;
 			default-state = "keep";
 			gpios = <&sled6_leds 0 GPIO_ACTIVE_LOW>;
 		};
-		sled6_blue {
+		led-1 {
+			label = "sled6_blue";
 			retain-state-shutdown;
 			default-state = "keep";
 			gpios = <&sled6_leds 1 GPIO_ACTIVE_LOW>;
@@ -191,32 +212,32 @@ sled6_blue {
 	gpio-keys {
 		compatible = "gpio-keys";
 
-		presence-sled1 {
+		presence-sled1-switch {
 			label = "presence-sled1";
 			gpios = <&gpio0 ASPEED_GPIO(H, 2) GPIO_ACTIVE_LOW>;
 			linux,code = <ASPEED_GPIO(H, 2)>;
 		};
-		presence-sled2 {
+		presence-sled2-switch {
 			label = "presence-sled2";
 			gpios = <&gpio0 ASPEED_GPIO(H, 3) GPIO_ACTIVE_LOW>;
 			linux,code = <ASPEED_GPIO(H, 3)>;
 		};
-		presence-sled3 {
+		presence-sled3-switch {
 			label = "presence-sled3";
 			gpios = <&gpio0 ASPEED_GPIO(H, 4) GPIO_ACTIVE_LOW>;
 			linux,code = <ASPEED_GPIO(H, 4)>;
 		};
-		presence-sled4 {
+		presence-sled4-switch {
 			label = "presence-sled4";
 			gpios = <&gpio0 ASPEED_GPIO(H, 5) GPIO_ACTIVE_LOW>;
 			linux,code = <ASPEED_GPIO(H, 5)>;
 		};
-		presence-sled5 {
+		presence-sled5-switch {
 			label = "presence-sled5";
 			gpios = <&gpio0 ASPEED_GPIO(H, 6) GPIO_ACTIVE_LOW>;
 			linux,code = <ASPEED_GPIO(H, 6)>;
 		};
-		presence-sled6 {
+		presence-sled6-switch {
 			label = "presence-sled6";
 			gpios = <&gpio0 ASPEED_GPIO(H, 7) GPIO_ACTIVE_LOW>;
 			linux,code = <ASPEED_GPIO(H, 7)>;
@@ -352,8 +373,6 @@ sled1_ioexp41: pca9536 at 41 {
 	sled1_ioexp: pca9539 at 76 {
 		compatible = "nxp,pca9539";
 		reg = <0x76>;
-		#address-cells = <1>;
-		#size-cells = <0>;
 		gpio-controller;
 		#gpio-cells = <2>;
 
@@ -441,8 +460,6 @@ sled2_ioexp41: pca9536 at 41 {
 	sled2_ioexp: pca9539 at 76 {
 		compatible = "nxp,pca9539";
 		reg = <0x76>;
-		#address-cells = <1>;
-		#size-cells = <0>;
 		gpio-controller;
 		#gpio-cells = <2>;
 
@@ -530,8 +547,6 @@ sled3_ioexp41: pca9536 at 41 {
 	sled3_ioexp: pca9539 at 76 {
 		compatible = "nxp,pca9539";
 		reg = <0x76>;
-		#address-cells = <1>;
-		#size-cells = <0>;
 		gpio-controller;
 		#gpio-cells = <2>;
 
@@ -619,8 +634,6 @@ sled4_ioexp41: pca9536 at 41 {
 	sled4_ioexp: pca9539 at 76 {
 		compatible = "nxp,pca9539";
 		reg = <0x76>;
-		#address-cells = <1>;
-		#size-cells = <0>;
 		gpio-controller;
 		#gpio-cells = <2>;
 
@@ -708,8 +721,6 @@ sled5_ioexp41: pca9536 at 41 {
 	sled5_ioexp: pca9539 at 76 {
 		compatible = "nxp,pca9539";
 		reg = <0x76>;
-		#address-cells = <1>;
-		#size-cells = <0>;
 		gpio-controller;
 		#gpio-cells = <2>;
 
@@ -797,8 +808,6 @@ sled6_ioexp41: pca9536 at 41 {
 	sled6_ioexp: pca9539 at 76 {
 		compatible = "nxp,pca9539";
 		reg = <0x76>;
-		#address-cells = <1>;
-		#size-cells = <0>;
 		gpio-controller;
 		#gpio-cells = <2>;
 
@@ -953,7 +962,6 @@ fan_leds: pca9552 at 67 {
 
 &i2c13 {
 	multi-master;
-	aspeed,hw-timeout-ms = <1000>;
 	status = "okay";
 
 	//USB Debug Connector
@@ -1024,7 +1032,7 @@ &gpio0 {
 };
 
 &adc0 {
-	vref = <1800>;
+	aspeed,int-vref-microvolt = <2500000>;
 	status = "okay";
 
 	pinctrl-names = "default";
@@ -1035,7 +1043,7 @@ &pinctrl_adc4_default &pinctrl_adc5_default
 };
 
 &adc1 {
-	vref = <2500>;
+	aspeed,int-vref-microvolt = <2500000>;
 	status = "okay";
 
 	pinctrl-names = "default";
-- 
2.43.0



From linmq006 at gmail.com  Thu Dec 11 00:13:13 2025
From: linmq006 at gmail.com (Miaoqian Lin)
Date: Thu, 11 Dec 2025 12:13:13 +0400
Subject: [PATCH] net: phy: mediatek: fix nvmem cell reference leak in mt798x_phy_calibration
Message-ID: <20251211081313.2368460-1-linmq006@gmail.com>

When nvmem_cell_read() fails in mt798x_phy_calibration(), the function
returns without calling nvmem_cell_put(), leaking the cell reference.

Move nvmem_cell_put() right after nvmem_cell_read() to ensure the cell
reference is always released regardless of the read result.

Found via static analysis and code review.

Fixes: 98c485eaf509 ("net: phy: add driver for MediaTek SoC built-in GE PHYs")
Cc: stable at vger.kernel.org
Signed-off-by: Miaoqian Lin <linmq006 at gmail.com>
---
 drivers/net/phy/mediatek/mtk-ge-soc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c
index cd09fbf92ef2..2c4bbc236202 100644
--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
@@ -1167,9 +1167,9 @@ static int mt798x_phy_calibration(struct phy_device *phydev)
 	}
 
 	buf = (u32 *)nvmem_cell_read(cell, &len);
+	nvmem_cell_put(cell);
 	if (IS_ERR(buf))
 		return PTR_ERR(buf);
-	nvmem_cell_put(cell);
 
 	if (!buf[0] || !buf[1] || !buf[2] || !buf[3] || len < 4 * sizeof(u32)) {
 		phydev_err(phydev, "invalid efuse data\n");
-- 
2.25.1



From maz at kernel.org  Thu Dec 11 00:15:28 2025
From: maz at kernel.org (Marc Zyngier)
Date: Thu, 11 Dec 2025 08:15:28 +0000
Subject: [PATCH 2/2] KVM: arm64: Remove extra argument for __pvkm_host_{share,unshare}_hyp()
In-Reply-To: <20251210132102.137631-3-alexandru.elisei@arm.com>
References: <20251210132102.137631-1-alexandru.elisei@arm.com>
	<20251210132102.137631-3-alexandru.elisei@arm.com>
Message-ID: <86zf7po2n3.wl-maz@kernel.org>

On Wed, 10 Dec 2025 13:21:02 +0000,
Alexandru Elisei <alexandru.elisei at arm.com> wrote:
> 
> __pvkm_host_share_hyp() and __pkvm_host_unshare_hyp() both have one
> parameter, the pfn, not two. Even though correctness isn't impacted because
> the SMCCC handlers pass the first argument and ignore the second one, let's
> call the functions with the proper number of arguments.
> 
> Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
> ---
>  arch/arm64/kvm/mmu.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
> index 7cc964af8d30..6c6abcd8e89e 100644
> --- a/arch/arm64/kvm/mmu.c
> +++ b/arch/arm64/kvm/mmu.c
> @@ -497,7 +497,7 @@ static int share_pfn_hyp(u64 pfn)
>  	this->count = 1;
>  	rb_link_node(&this->node, parent, node);
>  	rb_insert_color(&this->node, &hyp_shared_pfns);
> -	ret = kvm_call_hyp_nvhe(__pkvm_host_share_hyp, pfn, 1);
> +	ret = kvm_call_hyp_nvhe(__pkvm_host_share_hyp, pfn);
>  unlock:
>  	mutex_unlock(&hyp_shared_pfns_lock);
>  

Yeah, we lost all form of type-checking when everything was hastily
converted to SMCCC to avoid function pointers. Somehow, I feel that
the cure was worse than the disease.

I wish we'd reintroduce some form of compile-time checks, maybe by
having generated stubs?

Thanks,

	M.

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


From baolin.wang at linux.alibaba.com  Thu Dec 11 00:16:53 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Thu, 11 Dec 2025 16:16:53 +0800
Subject: [PATCH v2 0/3] support batch checking of references and unmapping for large folios
Message-ID: <cover.1765439380.git.baolin.wang@linux.alibaba.com>

Currently, folio_referenced_one() always checks the young flag for each PTE
sequentially, which is inefficient for large folios. This inefficiency is
especially noticeable when reclaiming clean file-backed large folios, where
folio_referenced() is observed as a significant performance hotspot.

Moreover, on Arm architecture, which supports contiguous PTEs, there is already
an optimization to clear the young flags for PTEs within a contiguous range.
However, this is not sufficient. We can extend this to perform batched operations
for the entire large folio (which might exceed the contiguous range: CONT_PTE_SIZE).

Similar to folio_referenced_one(), we can also apply batched unmapping for large
file folios to optimize the performance of file folio reclamation. By supporting
batched checking of the young flags, flushing TLB entries, and unmapping, I can
observed a significant performance improvements in my performance tests for file
folios reclamation. Please check the performance data in the commit message of
each patch.

Run stress-ng and mm selftests, no issues were found.

Changes from v1:
 - Add a new patch to support batched unmapping for file large folios.
 - Update the cover letter.

Baolin Wang (3):
  arm64: mm: support batch clearing of the young flag for large folios
  mm: rmap: support batched checks of the references for large folios
  mm: rmap: support batched unmapping for file large folios

 arch/arm64/include/asm/pgtable.h | 23 ++++++++++++-----
 arch/arm64/mm/contpte.c          | 44 ++++++++++++++++++++++----------
 include/linux/mmu_notifier.h     |  9 ++++---
 include/linux/pgtable.h          | 19 ++++++++++++++
 mm/rmap.c                        | 29 +++++++++++++++++----
 5 files changed, 96 insertions(+), 28 deletions(-)

-- 
2.47.3



From baolin.wang at linux.alibaba.com  Thu Dec 11 00:16:56 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Thu, 11 Dec 2025 16:16:56 +0800
Subject: [PATCH v2 3/3] mm: rmap: support batched unmapping for file large folios
In-Reply-To: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
Message-ID: <af330c9ea188bd0f28189b1e6e5803f6de9d2abe.1765439381.git.baolin.wang@linux.alibaba.com>

Similar to folio_referenced_one(), we can apply batched unmapping for file
large folios to optimize the performance of file folios reclamation.

Performance testing:
Allocate 10G clean file-backed folios by mmap() in a memory cgroup, and try to
reclaim 8G file-backed folios via the memory.reclaim interface. I can observe
75% performance improvement on my Arm64 32-core server.

W/o patch:
real    0m1.018s
user    0m0.000s
sys     0m1.018s

W/ patch:
real	0m0.249s
user	0m0.000s
sys	0m0.249s

Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
---
 mm/rmap.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/mm/rmap.c b/mm/rmap.c
index ec232165c47d..4c9d5777c8da 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1855,9 +1855,10 @@ static inline unsigned int folio_unmap_pte_batch(struct folio *folio,
 	end_addr = pmd_addr_end(addr, vma->vm_end);
 	max_nr = (end_addr - addr) >> PAGE_SHIFT;
 
-	/* We only support lazyfree batching for now ... */
-	if (!folio_test_anon(folio) || folio_test_swapbacked(folio))
+	/* We only support lazyfree or file folios batching for now ... */
+	if (folio_test_anon(folio) && folio_test_swapbacked(folio))
 		return 1;
+
 	if (pte_unused(pte))
 		return 1;
 
@@ -2223,7 +2224,7 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
 			 *
 			 * See Documentation/mm/mmu_notifier.rst
 			 */
-			dec_mm_counter(mm, mm_counter_file(folio));
+			add_mm_counter(mm, mm_counter_file(folio), -nr_pages);
 		}
 discard:
 		if (unlikely(folio_test_hugetlb(folio))) {
-- 
2.47.3



From baolin.wang at linux.alibaba.com  Thu Dec 11 00:16:55 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Thu, 11 Dec 2025 16:16:55 +0800
Subject: [PATCH v2 2/3] mm: rmap: support batched checks of the references for large folios
In-Reply-To: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
Message-ID: <545dba5e899634bc6c8ca782417d16fef3bd049f.1765439381.git.baolin.wang@linux.alibaba.com>

Currently, folio_referenced_one() always checks the young flag for each PTE
sequentially, which is inefficient for large folios. This inefficiency is
especially noticeable when reclaiming clean file-backed large folios, where
folio_referenced() is observed as a significant performance hotspot.

Moreover, on Arm architecture, which supports contiguous PTEs, there is already
an optimization to clear the young flags for PTEs within a contiguous range.
However, this is not sufficient. We can extend this to perform batched operations
for the entire large folio (which might exceed the contiguous range: CONT_PTE_SIZE).

Introduce a new API: clear_flush_young_ptes() to facilitate batched checking
of the young flags and flushing TLB entries, thereby improving performance
during large folio reclamation.

Performance testing:
Allocate 10G clean file-backed folios by mmap() in a memory cgroup, and try to
reclaim 8G file-backed folios via the memory.reclaim interface. I can observe
33% performance improvement on my Arm64 32-core server (and 10%+ improvement
on my X86 machine). Meanwhile, the hotspot folio_check_references() dropped
from approximately 35% to around 5%.

W/o patchset:
real	0m1.518s
user	0m0.000s
sys	0m1.518s

W/ patchset:
real	0m1.018s
user	0m0.000s
sys	0m1.018s

Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
---
 arch/arm64/include/asm/pgtable.h | 11 +++++++++++
 include/linux/mmu_notifier.h     |  9 +++++----
 include/linux/pgtable.h          | 19 +++++++++++++++++++
 mm/rmap.c                        | 22 ++++++++++++++++++++--
 4 files changed, 55 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index e03034683156..a865bd8c46a3 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -1869,6 +1869,17 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
 	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
 }
 
+#define clear_flush_young_ptes clear_flush_young_ptes
+static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
+					unsigned long addr, pte_t *ptep,
+					unsigned int nr)
+{
+	if (likely(nr == 1))
+		return __ptep_clear_flush_young(vma, addr, ptep);
+
+	return contpte_clear_flush_young_ptes(vma, addr, ptep, nr);
+}
+
 #define wrprotect_ptes wrprotect_ptes
 static __always_inline void wrprotect_ptes(struct mm_struct *mm,
 				unsigned long addr, pte_t *ptep, unsigned int nr)
diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h
index d1094c2d5fb6..be594b274729 100644
--- a/include/linux/mmu_notifier.h
+++ b/include/linux/mmu_notifier.h
@@ -515,16 +515,17 @@ static inline void mmu_notifier_range_init_owner(
 	range->owner = owner;
 }
 
-#define ptep_clear_flush_young_notify(__vma, __address, __ptep)		\
+#define ptep_clear_flush_young_notify(__vma, __address, __ptep, __nr)	\
 ({									\
 	int __young;							\
 	struct vm_area_struct *___vma = __vma;				\
 	unsigned long ___address = __address;				\
-	__young = ptep_clear_flush_young(___vma, ___address, __ptep);	\
+	unsigned int ___nr = __nr;					\
+	__young = clear_flush_young_ptes(___vma, ___address, __ptep, ___nr);	\
 	__young |= mmu_notifier_clear_flush_young(___vma->vm_mm,	\
 						  ___address,		\
 						  ___address +		\
-							PAGE_SIZE);	\
+						nr * PAGE_SIZE);	\
 	__young;							\
 })
 
@@ -650,7 +651,7 @@ static inline void mmu_notifier_subscriptions_destroy(struct mm_struct *mm)
 
 #define mmu_notifier_range_update_to_read_only(r) false
 
-#define ptep_clear_flush_young_notify ptep_clear_flush_young
+#define ptep_clear_flush_young_notify clear_flush_young_ptes
 #define pmdp_clear_flush_young_notify pmdp_clear_flush_young
 #define ptep_clear_young_notify ptep_test_and_clear_young
 #define pmdp_clear_young_notify pmdp_test_and_clear_young
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index b13b6f42be3c..c7d0fd228cb7 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -947,6 +947,25 @@ static inline void wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
 }
 #endif
 
+#ifndef clear_flush_young_ptes
+static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
+					 unsigned long addr, pte_t *ptep,
+					 unsigned int nr)
+{
+	int young = 0;
+
+	for (;;) {
+		young |= ptep_clear_flush_young(vma, addr, ptep);
+		if (--nr == 0)
+			break;
+		ptep++;
+		addr += PAGE_SIZE;
+	}
+
+	return young;
+}
+#endif
+
 /*
  * On some architectures hardware does not set page access bit when accessing
  * memory page, it is responsibility of software setting this bit. It brings
diff --git a/mm/rmap.c b/mm/rmap.c
index d6799afe1114..ec232165c47d 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -827,9 +827,11 @@ static bool folio_referenced_one(struct folio *folio,
 	struct folio_referenced_arg *pra = arg;
 	DEFINE_FOLIO_VMA_WALK(pvmw, folio, vma, address, 0);
 	int ptes = 0, referenced = 0;
+	unsigned int nr;
 
 	while (page_vma_mapped_walk(&pvmw)) {
 		address = pvmw.address;
+		nr = 1;
 
 		if (vma->vm_flags & VM_LOCKED) {
 			ptes++;
@@ -874,9 +876,21 @@ static bool folio_referenced_one(struct folio *folio,
 			if (lru_gen_look_around(&pvmw))
 				referenced++;
 		} else if (pvmw.pte) {
+			if (folio_test_large(folio)) {
+				unsigned long end_addr = pmd_addr_end(address, vma->vm_end);
+				unsigned int max_nr = (end_addr - address) >> PAGE_SHIFT;
+				pte_t pteval = ptep_get(pvmw.pte);
+
+				nr = folio_pte_batch(folio, pvmw.pte, pteval, max_nr);
+			}
+
+			ptes += nr;
 			if (ptep_clear_flush_young_notify(vma, address,
-						pvmw.pte))
+						pvmw.pte, nr))
 				referenced++;
+			/* Skip the batched PTEs */
+			pvmw.pte += nr - 1;
+			pvmw.address += (nr - 1) * PAGE_SIZE;
 		} else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) {
 			if (pmdp_clear_flush_young_notify(vma, address,
 						pvmw.pmd))
@@ -886,7 +900,11 @@ static bool folio_referenced_one(struct folio *folio,
 			WARN_ON_ONCE(1);
 		}
 
-		pra->mapcount--;
+		pra->mapcount -= nr;
+		if (ptes == pvmw.nr_pages) {
+			page_vma_mapped_walk_done(&pvmw);
+			break;
+		}
 	}
 
 	if (referenced)
-- 
2.47.3



From baolin.wang at linux.alibaba.com  Thu Dec 11 00:16:54 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Thu, 11 Dec 2025 16:16:54 +0800
Subject: [PATCH v2 1/3] arm64: mm: support batch clearing of the young flag for large folios
In-Reply-To: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
Message-ID: <e10f876ce130134fa089befe83f30561b48b9889.1765439380.git.baolin.wang@linux.alibaba.com>

Currently, contpte_ptep_test_and_clear_young() and contpte_ptep_clear_flush_young()
only clear the young flag and flush TLBs for PTEs within the contiguous range.
To support batch PTE operations for other sized large folios in the following
patches, adding a new parameter to specify the number of PTEs.

While we are at it, rename the functions to maintain consistency with other
contpte_*() functions.

Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
---
 arch/arm64/include/asm/pgtable.h | 12 ++++-----
 arch/arm64/mm/contpte.c          | 44 ++++++++++++++++++++++----------
 2 files changed, 37 insertions(+), 19 deletions(-)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 0944e296dd4a..e03034683156 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -1679,10 +1679,10 @@ extern void contpte_clear_full_ptes(struct mm_struct *mm, unsigned long addr,
 extern pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
 				unsigned long addr, pte_t *ptep,
 				unsigned int nr, int full);
-extern int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
-				unsigned long addr, pte_t *ptep);
-extern int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
-				unsigned long addr, pte_t *ptep);
+extern int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
+				unsigned long addr, pte_t *ptep, unsigned int nr);
+extern int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
+				unsigned long addr, pte_t *ptep, unsigned int nr);
 extern void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
 				pte_t *ptep, unsigned int nr);
 extern int contpte_ptep_set_access_flags(struct vm_area_struct *vma,
@@ -1854,7 +1854,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
 	if (likely(!pte_valid_cont(orig_pte)))
 		return __ptep_test_and_clear_young(vma, addr, ptep);
 
-	return contpte_ptep_test_and_clear_young(vma, addr, ptep);
+	return contpte_test_and_clear_young_ptes(vma, addr, ptep, CONT_PTES);
 }
 
 #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
@@ -1866,7 +1866,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
 	if (likely(!pte_valid_cont(orig_pte)))
 		return __ptep_clear_flush_young(vma, addr, ptep);
 
-	return contpte_ptep_clear_flush_young(vma, addr, ptep);
+	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
 }
 
 #define wrprotect_ptes wrprotect_ptes
diff --git a/arch/arm64/mm/contpte.c b/arch/arm64/mm/contpte.c
index c0557945939c..19b122441be3 100644
--- a/arch/arm64/mm/contpte.c
+++ b/arch/arm64/mm/contpte.c
@@ -488,8 +488,9 @@ pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
 }
 EXPORT_SYMBOL_GPL(contpte_get_and_clear_full_ptes);
 
-int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
-					unsigned long addr, pte_t *ptep)
+int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
+					unsigned long addr, pte_t *ptep,
+					unsigned int nr)
 {
 	/*
 	 * ptep_clear_flush_young() technically requires us to clear the access
@@ -500,39 +501,56 @@ int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
 	 * having to unfold.
 	 */
 
+	unsigned long start = addr;
+	unsigned long end = start + nr * PAGE_SIZE;
 	int young = 0;
 	int i;
 
-	ptep = contpte_align_down(ptep);
-	addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
+	if (pte_cont(__ptep_get(ptep + nr - 1)))
+		end = ALIGN(end, CONT_PTE_SIZE);
 
-	for (i = 0; i < CONT_PTES; i++, ptep++, addr += PAGE_SIZE)
-		young |= __ptep_test_and_clear_young(vma, addr, ptep);
+	if (pte_cont(__ptep_get(ptep))) {
+		start = ALIGN_DOWN(start, CONT_PTE_SIZE);
+		ptep = contpte_align_down(ptep);
+	}
+
+	nr = (end - start) / PAGE_SIZE;
+	for (i = 0; i < nr; i++, ptep++, start += PAGE_SIZE)
+		young |= __ptep_test_and_clear_young(vma, start, ptep);
 
 	return young;
 }
-EXPORT_SYMBOL_GPL(contpte_ptep_test_and_clear_young);
+EXPORT_SYMBOL_GPL(contpte_test_and_clear_young_ptes);
 
-int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
-					unsigned long addr, pte_t *ptep)
+int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
+				unsigned long addr, pte_t *ptep,
+				unsigned int nr)
 {
 	int young;
 
-	young = contpte_ptep_test_and_clear_young(vma, addr, ptep);
+	young = contpte_test_and_clear_young_ptes(vma, addr, ptep, nr);
 
 	if (young) {
+		unsigned long start = addr;
+		unsigned long end = start + nr * PAGE_SIZE;
+
+		if (pte_cont(__ptep_get(ptep + nr - 1)))
+			end = ALIGN(end, CONT_PTE_SIZE);
+
+		if (pte_cont(__ptep_get(ptep)))
+			start = ALIGN_DOWN(start, CONT_PTE_SIZE);
+
 		/*
 		 * See comment in __ptep_clear_flush_young(); same rationale for
 		 * eliding the trailing DSB applies here.
 		 */
-		addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
-		__flush_tlb_range_nosync(vma->vm_mm, addr, addr + CONT_PTE_SIZE,
+		__flush_tlb_range_nosync(vma->vm_mm, start, end,
 					 PAGE_SIZE, true, 3);
 	}
 
 	return young;
 }
-EXPORT_SYMBOL_GPL(contpte_ptep_clear_flush_young);
+EXPORT_SYMBOL_GPL(contpte_clear_flush_young_ptes);
 
 void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
 					pte_t *ptep, unsigned int nr)
-- 
2.47.3



From jbrunet at baylibre.com  Thu Dec 11 00:30:37 2025
From: jbrunet at baylibre.com (Jerome Brunet)
Date: Thu, 11 Dec 2025 09:30:37 +0100
Subject: [PATCH v6 2/5] dt-bindings: clock: add Amlogic T7 SCMI clock
 controller
In-Reply-To: <38ef7ee0-1879-42d5-a7fd-d32b96d01367@kernel.org> (Krzysztof
	Kozlowski's message of "Thu, 11 Dec 2025 07:16:25 +0100")
References: <20251204053635.1234150-1-jian.hu@amlogic.com>
	<20251204053635.1234150-3-jian.hu@amlogic.com>
	<20251208-independent-warping-macaw-74a169@quoll>
	<dd90b445-bafb-46d4-8cec-e0877cf425b3@amlogic.com>
	<4f5ec838-f8d6-4c3b-94f2-b2a60cfe64ec@kernel.org>
	<1jy0ncvu23.fsf@starbuckisacylon.baylibre.com>
	<38ef7ee0-1879-42d5-a7fd-d32b96d01367@kernel.org>
Message-ID: <1j8qf92zf6.fsf@starbuckisacylon.baylibre.com>

On Thu 11 Dec 2025 at 07:16, Krzysztof Kozlowski <krzk at kernel.org> wrote:


>> 
>> Is there a new requirement to submit the DTS file changes along with the
>> driver changes now ?
>> 
>> This has never been case before, especially since the changes are merged
>> through different trees.
>
> There is no such requirement, but "has never been case before" is
> clearly not accurate, because I raised this question multiple times last
> two-three years.
>
> There is no reasonable way to hold publishing of DTS, therefore if
> someone uses arguments like above with waiting for driver, I usually got
> suspicious.
>
> Also note, that many contributions from various people (not saying that
> this one here is) were bad quality and badly designed but without seeing
> DTS it takes me significantly more time to understand that design. So
> yes, publish your DTS solving all of the questions and making reviewing
> easier. Or don't and receive questions...
>

That's fair. Thanks for clarifying.

>
> Best regards,
> Krzysztof

-- 
Jerome


From tiwai at suse.de  Thu Dec 11 00:45:21 2025
From: tiwai at suse.de (Takashi Iwai)
Date: Thu, 11 Dec 2025 09:45:21 +0100
Subject: [PATCH] ALSA: hda: cix-ipbloq: Use modern PM ops
In-Reply-To: <20251211-hda-cix-ipbloq-modern-pm-ops-v1-1-c7a5580af021@kernel.org>
References: <20251211-hda-cix-ipbloq-modern-pm-ops-v1-1-c7a5580af021@kernel.org>
Message-ID: <874ipxcspq.wl-tiwai@suse.de>

On Thu, 11 Dec 2025 02:50:03 +0100,
Nathan Chancellor wrote:
> 
> When building without CONFIG_PM_SLEEP, there are several warnings (or
> errors with CONFIG_WERROR=y / W=e) from the cix-ipbloq driver:
> 
>   sound/hda/controllers/cix-ipbloq.c:378:12: error: 'cix_ipbloq_hda_runtime_resume' defined but not used [-Werror=unused-function]
>     378 | static int cix_ipbloq_hda_runtime_resume(struct device *dev)
>         |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>   sound/hda/controllers/cix-ipbloq.c:362:12: error: 'cix_ipbloq_hda_runtime_suspend' defined but not used [-Werror=unused-function]
>     362 | static int cix_ipbloq_hda_runtime_suspend(struct device *dev)
>         |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>   sound/hda/controllers/cix-ipbloq.c:349:12: error: 'cix_ipbloq_hda_resume' defined but not used [-Werror=unused-function]
>     349 | static int cix_ipbloq_hda_resume(struct device *dev)
>         |            ^~~~~~~~~~~~~~~~~~~~~
>   sound/hda/controllers/cix-ipbloq.c:336:12: error: 'cix_ipbloq_hda_suspend' defined but not used [-Werror=unused-function]
>     336 | static int cix_ipbloq_hda_suspend(struct device *dev)
>         |            ^~~~~~~~~~~~~~~~~~~~~~
> 
> When CONFIG_PM and CONFIG_PM_SLEEP are unset, SET_SYSTEM_SLEEP_PM_OPS()
> and SET_RUNTIME_PM_OPS() evaluate to nothing, so these functions appear
> unused to the compiler in this configuration.
> 
> Use the modern SYSTEM_SLEEP_PM_OPS and RUNTIME_PM_OPS macros to resolve
> these warnings, which is what they are intended to do. Additionally,
> wrap &cix_ipbloq_hda_pm in pm_ptr() to ensure the compiler can drop the
> entire structure when CONFIG_PM is unset.
> 
> Fixes: d91e9bd10125 ("ALSA: hda: add CIX IPBLOQ HDA controller support")
> Signed-off-by: Nathan Chancellor <nathan at kernel.org>

Applied now.  Thanks.


Takashi


From andrew at codeconstruct.com.au  Thu Dec 11 00:45:42 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Thu, 11 Dec 2025 17:45:42 +0900
Subject: [PATCH RFC 00/16] Eliminate warnings for AST2500 and AST2600 EVB
 devicetrees
Message-ID: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>

Hi all,

This series removes the remaining warnings produced by `make
CHECK_DTBS=y ...` for the AST2500 and AST2600 EVBs and their related
DTSIs. The tidy-up has the usual benefit of making it clear to
contributors that any warnings are likely their own to fix before their
patches will be considered for merging.

I've framed it as an RFC with all patches contained in the one series
so the goal is clear, we can see what's needed to reach it, and we can
decide whether and how it should be split or merged going forward.

As it stands there's little in the way of code change, except to
pinctrl (though also not much there). As such I've included the
binding maintainers and subsystem lists as recipients but not yet Cc'ed
subsystem maintainers directly because there are quite a few and I hope
to avoid mostly uninteresting patches being a source of irritation.

The patches fall into several groups:

Patch 1:
  Rob's conversion of the PWM/tach binding to DT schema with fixes
  applied for the license and typos identified by Krzysztof.

Patches 2-5:
  Fixes for the warnings related to the LPC and pinctrl nodes, touching
  relevant drivers and the devicetrees.

  I expect that if this approach is acceptable that we'll need to split
  application of the patches across successive release cycles, with the
  driver changes going in first.

Patches 6-8:
  Fix MMC/SDHCI warnings, touching the relevant binding and devicetrees

Patches 9-10:
  Clarify the relationships between the ACRY and AHB controller

Patches 11-16:
  The remaining pieces that eliminate the warnings

I'm at plumbers so don't have hardware on hand to test with, but some
brief smoke tests under qemu look okay. Given that it's all RFC that
should be enough for the moment. I'll do more testing after discussions
and when I have boards at hand.

Please review!

Andrew

Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
---
Andrew Jeffery (15):
      pinctrl: aspeed: g5: Constrain LPC binding revision workaround to AST2500
      pinctrl: aspeed: g5: Allow use of LPC node instead of LPC host controller
      ARM: dts: aspeed: g5: Use LPC phandle for pinctrl aspeed,external-nodes
      ARM: dts: aspeed: Remove unspecified LPC host controller node
      dt-bindings: mmc: Switch ref to sdhci-common.yaml
      ARM: dts: aspeed: Remove sdhci-drive-type property from AST2600 EVB
      ARM: dts: aspeed: Use specified wp-inverted property for AST2600 EVB
      dt-bindings: bus: aspeed: Require syscon for AST2600 AHB controller
      dt-bindings: crypto: Document aspeed,ahbc property for Aspeed ACRY
      ARM: dts: aspeed: Drop syscon compatible from EDAC in g6 dtsi
      ARM: dts: aspeed: g6: Drop unspecified aspeed,ast2600-udma node
      ARM: dts: aspeed: ast2600-evb: Tidy up A0 work-around for UART5
      dt-bindings: iio: adc: Allow interrupts property for AST2600
      ARM: dts: aspeed: g6: Drop clocks property from arm,armv7-timer
      dt-bindings: mfd: Document smp-memram node for AST2600 SCU

Rob Herring (Arm) (1):
      dt-bindings: hwmon: Convert aspeed,ast2400-pwm-tacho to DT schema

 .../bindings/bus/aspeed,ast2600-ahbc.yaml          |   8 +-
 .../bindings/crypto/aspeed,ast2600-acry.yaml       |   7 ++
 .../bindings/hwmon/aspeed,ast2400-pwm-tacho.yaml   | 106 +++++++++++++++++++++
 .../devicetree/bindings/hwmon/aspeed-pwm-tacho.txt |  73 --------------
 .../bindings/iio/adc/aspeed,ast2600-adc.yaml       |   3 +
 .../bindings/mfd/aspeed,ast2x00-scu.yaml           |  18 ++++
 .../devicetree/bindings/mmc/aspeed,sdhci.yaml      |   2 +-
 arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts    |   7 +-
 .../dts/aspeed/aspeed-bmc-facebook-clemente.dts    |   4 -
 arch/arm/boot/dts/aspeed/aspeed-g4.dtsi            |   5 -
 arch/arm/boot/dts/aspeed/aspeed-g5.dtsi            |   8 +-
 arch/arm/boot/dts/aspeed/aspeed-g6.dtsi            |  17 +---
 drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c         |  32 ++++---
 13 files changed, 165 insertions(+), 125 deletions(-)
---
base-commit: 5ce74bc1b7cb2732b22f9c93082545bc655d6547
change-id: 20251211-dev-dt-warnings-all-bd5854b04d60

Best regards,
-- 
Andrew Jeffery <andrew at codeconstruct.com.au>



From andrew at codeconstruct.com.au  Thu Dec 11 00:45:43 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Thu, 11 Dec 2025 17:45:43 +0900
Subject: [PATCH RFC 01/16] dt-bindings: hwmon: Convert
 aspeed,ast2400-pwm-tacho to DT schema
In-Reply-To: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
Message-ID: <20251211-dev-dt-warnings-all-v1-1-21b18b9ada77@codeconstruct.com.au>

From: "Rob Herring (Arm)" <robh at kernel.org>

Convert the ASpeed fan controller binding to DT schema format.

The '#cooling-cells' value used is 1 rather than 2. '#size-cells' is 0
rather 1.

Some users define more that 8 fan nodes where 2 fans share a PWM. The
driver seems to let the 2nd fan just overwrite the 1st one. That also
creates some addressing errors in the DT (duplicate addresses and wrong
unit-addresses).

Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
---
 .../bindings/hwmon/aspeed,ast2400-pwm-tacho.yaml   | 106 +++++++++++++++++++++
 .../devicetree/bindings/hwmon/aspeed-pwm-tacho.txt |  73 --------------
 2 files changed, 106 insertions(+), 73 deletions(-)

diff --git a/Documentation/devicetree/bindings/hwmon/aspeed,ast2400-pwm-tacho.yaml b/Documentation/devicetree/bindings/hwmon/aspeed,ast2400-pwm-tacho.yaml
new file mode 100644
index 000000000000..21f18e9d0dd4
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwmon/aspeed,ast2400-pwm-tacho.yaml
@@ -0,0 +1,106 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/hwmon/aspeed,ast2400-pwm-tacho.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ASPEED AST2400/AST2500 PWM and Fan Tacho controller
+
+maintainers:
+  - Joel Stanley <joel at jms.id.au>
+  - Andrew Jeffery <andrew at codeconstruct.com.au>
+
+description: >
+  The ASPEED PWM controller can support up to 8 PWM outputs. The ASPEED Fan
+  Tacho controller can support up to 16 Fan tachometer inputs.
+
+  There can be up to 8 fans supported. Each fan can have 1 PWM output and
+  1-2 Fan tach inputs.
+
+properties:
+  compatible:
+    enum:
+      - aspeed,ast2400-pwm-tacho
+      - aspeed,ast2500-pwm-tacho
+
+  reg:
+    maxItems: 1
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
+  '#cooling-cells':
+    const: 1
+
+  clocks:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+patternProperties:
+  '^fan@[0-7]$':
+    description: Fan subnode
+    type: object
+    additionalProperties: false
+
+    properties:
+      reg:
+        description: PWM source port index (0 = PWM A, ..., 7 = PWM H)
+        maximum: 7
+
+      cooling-levels:
+        description: PWM duty cycle values for cooling states
+        $ref: /schemas/types.yaml#/definitions/uint8-array
+        minItems: 1
+        maxItems: 16  # Should be enough
+
+      aspeed,fan-tach-ch:
+        description: Fan tachometer input channel
+        $ref: /schemas/types.yaml#/definitions/uint8-array
+        minItems: 1
+        maxItems: 2
+        items:
+          maximum: 15
+
+    required:
+      - reg
+      - aspeed,fan-tach-ch
+
+required:
+  - compatible
+  - reg
+  - '#address-cells'
+  - '#size-cells'
+  - clocks
+  - resets
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/aspeed-clock.h>
+
+    fan-controller at 1e786000 {
+        compatible = "aspeed,ast2500-pwm-tacho";
+        reg = <0x1e786000 0x1000>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+        #cooling-cells = <1>;
+        clocks = <&syscon ASPEED_CLK_APB>;
+        resets = <&syscon ASPEED_RESET_PWM>;
+
+        fan at 0 {
+            reg = <0x00>;
+            cooling-levels = /bits/ 8 <125 151 177 203 229 255>;
+            aspeed,fan-tach-ch = /bits/ 8 <0x00>;
+        };
+
+        fan at 1 {
+            reg = <0x01>;
+            aspeed,fan-tach-ch = /bits/ 8 <0x01 0x02>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt b/Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt
deleted file mode 100644
index 8645cd3b867a..000000000000
--- a/Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt
+++ /dev/null
@@ -1,73 +0,0 @@
-ASPEED AST2400/AST2500 PWM and Fan Tacho controller device driver
-
-The ASPEED PWM controller can support upto 8 PWM outputs. The ASPEED Fan Tacho
-controller can support upto 16 Fan tachometer inputs.
-
-There can be upto 8 fans supported. Each fan can have one PWM output and
-one/two Fan tach inputs.
-
-Required properties for pwm-tacho node:
-- #address-cells : should be 1.
-
-- #size-cells : should be 1.
-
-- #cooling-cells: should be 2.
-
-- reg : address and length of the register set for the device.
-
-- pinctrl-names : a pinctrl state named "default" must be defined.
-
-- pinctrl-0 : phandle referencing pin configuration of the PWM ports.
-
-- compatible : should be "aspeed,ast2400-pwm-tacho" for AST2400 and
-	       "aspeed,ast2500-pwm-tacho" for AST2500.
-
-- clocks : phandle to clock provider with the clock number in the second cell
-
-- resets : phandle to reset controller with the reset number in the second cell
-
-fan subnode format:
-===================
-Under fan subnode there can upto 8 child nodes, with each child node
-representing a fan. If there are 8 fans each fan can have one PWM port and
-one/two Fan tach inputs.
-For PWM port can be configured cooling-levels to create cooling device.
-Cooling device could be bound to a thermal zone for the thermal control.
-
-Required properties for each child node:
-- reg : should specify PWM source port.
-	integer value in the range 0 to 7 with 0 indicating PWM port A and
-	7 indicating PWM port H.
-
-- cooling-levels: PWM duty cycle values in a range from 0 to 255
-                  which correspond to thermal cooling states.
-
-- aspeed,fan-tach-ch : should specify the Fan tach input channel.
-                integer value in the range 0 through 15, with 0 indicating
-		Fan tach channel 0 and 15 indicating Fan tach channel 15.
-		At least one Fan tach input channel is required.
-
-Examples:
-
-pwm_tacho: pwmtachocontroller at 1e786000 {
-	#address-cells = <1>;
-	#size-cells = <1>;
-	#cooling-cells = <2>;
-	reg = <0x1E786000 0x1000>;
-	compatible = "aspeed,ast2500-pwm-tacho";
-	clocks = <&syscon ASPEED_CLK_APB>;
-	resets = <&syscon ASPEED_RESET_PWM>;
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default>;
-
-	fan at 0 {
-		reg = <0x00>;
-		cooling-levels = /bits/ 8 <125 151 177 203 229 255>;
-		aspeed,fan-tach-ch = /bits/ 8 <0x00>;
-	};
-
-	fan at 1 {
-		reg = <0x01>;
-		aspeed,fan-tach-ch = /bits/ 8 <0x01 0x02>;
-	};
-};

-- 
2.47.3



From andrew at codeconstruct.com.au  Thu Dec 11 00:45:44 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Thu, 11 Dec 2025 17:45:44 +0900
Subject: [PATCH RFC 02/16] pinctrl: aspeed: g5: Constrain LPC binding
 revision workaround to AST2500
In-Reply-To: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
Message-ID: <20251211-dev-dt-warnings-all-v1-2-21b18b9ada77@codeconstruct.com.au>

Discovering a phandle to an AST2400 or AST2600 LPC node indicates an
error for the purpose of the AST2500 pinctrl driver.

Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
---
 drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
index 792089628362..d4c364d19d64 100644
--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
@@ -2654,9 +2654,7 @@ static struct regmap *aspeed_g5_acquire_regmap(struct aspeed_pinmux_data *ctx,
 		np = of_parse_phandle(ctx->dev->of_node,
 					"aspeed,external-nodes", 1);
 		if (np) {
-			if (!of_device_is_compatible(np->parent, "aspeed,ast2400-lpc-v2") &&
-			    !of_device_is_compatible(np->parent, "aspeed,ast2500-lpc-v2") &&
-			    !of_device_is_compatible(np->parent, "aspeed,ast2600-lpc-v2"))
+			if (!of_device_is_compatible(np->parent, "aspeed,ast2500-lpc-v2"))
 				return ERR_PTR(-ENODEV);
 
 			map = syscon_node_to_regmap(np->parent);

-- 
2.47.3



From andrew at codeconstruct.com.au  Thu Dec 11 00:45:45 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Thu, 11 Dec 2025 17:45:45 +0900
Subject: [PATCH RFC 03/16] pinctrl: aspeed: g5: Allow use of LPC node
 instead of LPC host controller
In-Reply-To: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
Message-ID: <20251211-dev-dt-warnings-all-v1-3-21b18b9ada77@codeconstruct.com.au>

There's currently a wart where the Aspeed LPC host controller has no
binding specified, but the pinctrl binding depends on referencing its
node.

Allow specification of a phandle to the parent LPC controller instead.
Fall back to testing for a compatible parent node if the provided
phandle doesn't directly resolve to the LPC controller node.

Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
---
 drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c | 30 ++++++++++++++++++++----------
 1 file changed, 20 insertions(+), 10 deletions(-)

diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
index d4c364d19d64..7d818b4da1e3 100644
--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
@@ -2648,24 +2648,34 @@ static struct regmap *aspeed_g5_acquire_regmap(struct aspeed_pinmux_data *ctx,
 	}
 
 	if (ip == ASPEED_IP_LPC) {
-		struct device_node *np;
+		struct device_node *np, *rnp;
 		struct regmap *map;
 
 		np = of_parse_phandle(ctx->dev->of_node,
 					"aspeed,external-nodes", 1);
-		if (np) {
-			if (!of_device_is_compatible(np->parent, "aspeed,ast2500-lpc-v2"))
-				return ERR_PTR(-ENODEV);
-
-			map = syscon_node_to_regmap(np->parent);
-			of_node_put(np);
-			if (IS_ERR(map))
-				return map;
-		} else
+		if (!np)
 			return ERR_PTR(-ENODEV);
 
+		if (of_device_is_compatible(np, "aspeed,ast2500-lpc-v2")) {
+			rnp = np;
+		} else if (of_device_is_compatible(np->parent, "aspeed,ast2500-lpc-v2")) {
+			/* Maintain compatibility with old aspeed,ast2500-lhc node */
+			rnp = np->parent;
+		} else {
+			map = ERR_PTR(-ENODEV);
+			goto put_external_node;
+		}
+
+		map = syscon_node_to_regmap(rnp);
+		if (IS_ERR(map))
+			goto put_external_node;
+
 		ctx->maps[ASPEED_IP_LPC] = map;
 		dev_dbg(ctx->dev, "Acquired LPC regmap");
+
+put_external_node:
+		of_node_put(np);
+
 		return map;
 	}
 

-- 
2.47.3



From andrew at codeconstruct.com.au  Thu Dec 11 00:45:46 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Thu, 11 Dec 2025 17:45:46 +0900
Subject: [PATCH RFC 04/16] ARM: dts: aspeed: g5: Use LPC phandle for
 pinctrl aspeed,external-nodes
In-Reply-To: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
Message-ID: <20251211-dev-dt-warnings-all-v1-4-21b18b9ada77@codeconstruct.com.au>

The LPC host controller has no binding specified, and the pinctrl driver
can now determine whether its been provided a phandle to the LPC host
controller or the parent LPC controller. Switch to using the LPC node
phandle to avoid specifying a binding for the LPC host controller for
the moment.

Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
---
 arch/arm/boot/dts/aspeed/aspeed-g5.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed/aspeed-g5.dtsi
index 39500bdb4747..1456f04c2139 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-g5.dtsi
+++ b/arch/arm/boot/dts/aspeed/aspeed-g5.dtsi
@@ -251,7 +251,7 @@ silicon-id at 7c {
 				pinctrl: pinctrl at 80 {
 					compatible = "aspeed,ast2500-pinctrl";
 					reg = <0x80 0x18>, <0xa0 0x10>;
-					aspeed,external-nodes = <&gfx>, <&lhc>;
+					aspeed,external-nodes = <&gfx>, <&lpc>;
 				};
 			};
 

-- 
2.47.3



From andrew at codeconstruct.com.au  Thu Dec 11 00:45:47 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Thu, 11 Dec 2025 17:45:47 +0900
Subject: [PATCH RFC 05/16] ARM: dts: aspeed: Remove unspecified LPC host
 controller node
In-Reply-To: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
Message-ID: <20251211-dev-dt-warnings-all-v1-5-21b18b9ada77@codeconstruct.com.au>

For the AST2500 the node was used for pinctrl purposes, and while the
hardware capability is also present in the AST2400 and AST2600, the
their pinctrl no relationship to it. Further, there's no corresponding
binding, remove the node for now to
eliminate the warnings.

Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
---
 arch/arm/boot/dts/aspeed/aspeed-g4.dtsi | 5 -----
 arch/arm/boot/dts/aspeed/aspeed-g5.dtsi | 6 ------
 arch/arm/boot/dts/aspeed/aspeed-g6.dtsi | 5 -----
 3 files changed, 16 deletions(-)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed/aspeed-g4.dtsi
index c3d4d916c69b..c0a4057fa53f 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-g4.dtsi
+++ b/arch/arm/boot/dts/aspeed/aspeed-g4.dtsi
@@ -376,11 +376,6 @@ lpc_snoop: lpc-snoop at 90 {
 					status = "disabled";
 				};
 
-				lhc: lhc at a0 {
-					compatible = "aspeed,ast2400-lhc";
-					reg = <0xa0 0x24 0xc8 0x8>;
-				};
-
 				lpc_reset: reset-controller at 98 {
 					compatible = "aspeed,ast2400-lpc-reset";
 					reg = <0x98 0x4>;
diff --git a/arch/arm/boot/dts/aspeed/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed/aspeed-g5.dtsi
index 1456f04c2139..086c40fd12b8 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-g5.dtsi
+++ b/arch/arm/boot/dts/aspeed/aspeed-g5.dtsi
@@ -504,12 +504,6 @@ uart_routing: uart-routing at 9c {
 					status = "disabled";
 				};
 
-				lhc: lhc at a0 {
-					compatible = "aspeed,ast2500-lhc";
-					reg = <0xa0 0x24 0xc8 0x8>;
-				};
-
-
 				ibt: ibt at 140 {
 					compatible = "aspeed,ast2500-ibt-bmc";
 					reg = <0x140 0x18>;
diff --git a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
index f8662c8ac089..1ae816087f6b 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
+++ b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
@@ -624,11 +624,6 @@ lpc_snoop: lpc-snoop at 80 {
 					status = "disabled";
 				};
 
-				lhc: lhc at a0 {
-					compatible = "aspeed,ast2600-lhc";
-					reg = <0xa0 0x24 0xc8 0x8>;
-				};
-
 				lpc_reset: reset-controller at 98 {
 					compatible = "aspeed,ast2600-lpc-reset";
 					reg = <0x98 0x4>;

-- 
2.47.3



From andrew at codeconstruct.com.au  Thu Dec 11 00:45:48 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Thu, 11 Dec 2025 17:45:48 +0900
Subject: [PATCH RFC 06/16] dt-bindings: mmc: Switch ref to
 sdhci-common.yaml
In-Reply-To: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
Message-ID: <20251211-dev-dt-warnings-all-v1-6-21b18b9ada77@codeconstruct.com.au>

Enable use of common SDHCI-related properties such as sdhci-caps-mask as
found in the AST2600 EVB DTS.

Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
---
 Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml b/Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml
index 9fce8cd7b0b6..d24950ccea95 100644
--- a/Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml
+++ b/Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml
@@ -41,7 +41,7 @@ properties:
 patternProperties:
   "^sdhci@[0-9a-f]+$":
     type: object
-    $ref: mmc-controller.yaml
+    $ref: sdhci-common.yaml
     unevaluatedProperties: false
 
     properties:

-- 
2.47.3



From andrew at codeconstruct.com.au  Thu Dec 11 00:45:49 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Thu, 11 Dec 2025 17:45:49 +0900
Subject: [PATCH RFC 07/16] ARM: dts: aspeed: Remove sdhci-drive-type
 property from AST2600 EVB
In-Reply-To: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
Message-ID: <20251211-dev-dt-warnings-all-v1-7-21b18b9ada77@codeconstruct.com.au>

The property isn't specified in the bindings and is not used by the
corresponding driver, so drop it.

Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
---
 arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts | 2 --
 1 file changed, 2 deletions(-)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts b/arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts
index de83c0eb1d6e..3eba676e57f1 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts
+++ b/arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts
@@ -314,7 +314,6 @@ &sdhci0 {
 	status = "okay";
 	bus-width = <4>;
 	max-frequency = <100000000>;
-	sdhci-drive-type = /bits/ 8 <3>;
 	sdhci-caps-mask = <0x7 0x0>;
 	sdhci,wp-inverted;
 	vmmc-supply = <&vcc_sdhci0>;
@@ -326,7 +325,6 @@ &sdhci1 {
 	status = "okay";
 	bus-width = <4>;
 	max-frequency = <100000000>;
-	sdhci-drive-type = /bits/ 8 <3>;
 	sdhci-caps-mask = <0x7 0x0>;
 	sdhci,wp-inverted;
 	vmmc-supply = <&vcc_sdhci1>;

-- 
2.47.3



From andrew at codeconstruct.com.au  Thu Dec 11 00:45:50 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Thu, 11 Dec 2025 17:45:50 +0900
Subject: [PATCH RFC 08/16] ARM: dts: aspeed: Use specified wp-inverted
 property for AST2600 EVB
In-Reply-To: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
Message-ID: <20251211-dev-dt-warnings-all-v1-8-21b18b9ada77@codeconstruct.com.au>

While sdhci-pltfm supports sdhci,wp-inverted, it also supports
the un-prefixed and specified wp-inverted property. Switch the EVB
devicetree to use the specified property to remove warnings when
checking the DTB.

Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
---
 arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts b/arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts
index 3eba676e57f1..c51977dcb56b 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts
+++ b/arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts
@@ -315,7 +315,7 @@ &sdhci0 {
 	bus-width = <4>;
 	max-frequency = <100000000>;
 	sdhci-caps-mask = <0x7 0x0>;
-	sdhci,wp-inverted;
+	wp-inverted;
 	vmmc-supply = <&vcc_sdhci0>;
 	vqmmc-supply = <&vccq_sdhci0>;
 	clk-phase-sd-hs = <7>, <200>;
@@ -326,7 +326,7 @@ &sdhci1 {
 	bus-width = <4>;
 	max-frequency = <100000000>;
 	sdhci-caps-mask = <0x7 0x0>;
-	sdhci,wp-inverted;
+	wp-inverted;
 	vmmc-supply = <&vcc_sdhci1>;
 	vqmmc-supply = <&vccq_sdhci1>;
 	clk-phase-sd-hs = <7>, <200>;

-- 
2.47.3



From andrew at codeconstruct.com.au  Thu Dec 11 00:45:51 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Thu, 11 Dec 2025 17:45:51 +0900
Subject: [PATCH RFC 09/16] dt-bindings: bus: aspeed: Require syscon for
 AST2600 AHB controller
In-Reply-To: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
Message-ID: <20251211-dev-dt-warnings-all-v1-9-21b18b9ada77@codeconstruct.com.au>

The AST2600's ACRY (eliptic curve and RSA crypto engine) requires access
to configuration exposed by the AHB controller. The devicetree already
describes the AHB controller node as a syscon, so require this in the
binding to satisfy the ACRY relationship.

Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
---
 Documentation/devicetree/bindings/bus/aspeed,ast2600-ahbc.yaml | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/bus/aspeed,ast2600-ahbc.yaml b/Documentation/devicetree/bindings/bus/aspeed,ast2600-ahbc.yaml
index 2894256c976d..77e60b32d52e 100644
--- a/Documentation/devicetree/bindings/bus/aspeed,ast2600-ahbc.yaml
+++ b/Documentation/devicetree/bindings/bus/aspeed,ast2600-ahbc.yaml
@@ -17,8 +17,10 @@ description: |
 
 properties:
   compatible:
-    enum:
-      - aspeed,ast2600-ahbc
+    items:
+      - enum:
+          - aspeed,ast2600-ahbc
+      - const: syscon
 
   reg:
     maxItems: 1
@@ -32,6 +34,6 @@ additionalProperties: false
 examples:
   - |
     ahbc at 1e600000 {
-        compatible = "aspeed,ast2600-ahbc";
+        compatible = "aspeed,ast2600-ahbc", "syscon";
         reg = <0x1e600000 0x100>;
     };

-- 
2.47.3



From andrew at codeconstruct.com.au  Thu Dec 11 00:45:52 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Thu, 11 Dec 2025 17:45:52 +0900
Subject: [PATCH RFC 10/16] dt-bindings: crypto: Document aspeed,ahbc
 property for Aspeed ACRY
In-Reply-To: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
Message-ID: <20251211-dev-dt-warnings-all-v1-10-21b18b9ada77@codeconstruct.com.au>

The g6 DTSI already provides the property and the driver errors out if
the AHB controller's syscon can't be located, so define the property and
mark it as required.

Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
---
 Documentation/devicetree/bindings/crypto/aspeed,ast2600-acry.yaml | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/Documentation/devicetree/bindings/crypto/aspeed,ast2600-acry.yaml b/Documentation/devicetree/bindings/crypto/aspeed,ast2600-acry.yaml
index b18f178aac06..0dac6ee5043e 100644
--- a/Documentation/devicetree/bindings/crypto/aspeed,ast2600-acry.yaml
+++ b/Documentation/devicetree/bindings/crypto/aspeed,ast2600-acry.yaml
@@ -30,11 +30,17 @@ properties:
   interrupts:
     maxItems: 1
 
+  aspeed,ahbc:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      A phandle to the AHB controller node, which must be a syscon
+
 required:
   - compatible
   - reg
   - clocks
   - interrupts
+  - aspeed,ahbc
 
 additionalProperties: false
 
@@ -46,4 +52,5 @@ examples:
         reg = <0x1e6fa000 0x400>, <0x1e710000 0x1800>;
         interrupts = <160>;
         clocks = <&syscon ASPEED_CLK_GATE_RSACLK>;
+        aspeed,ahbc = <&ahbc>;
     };

-- 
2.47.3



From andrew at codeconstruct.com.au  Thu Dec 11 00:45:53 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Thu, 11 Dec 2025 17:45:53 +0900
Subject: [PATCH RFC 11/16] ARM: dts: aspeed: Drop syscon compatible from
 EDAC in g6 dtsi
In-Reply-To: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
Message-ID: <20251211-dev-dt-warnings-all-v1-11-21b18b9ada77@codeconstruct.com.au>

Its presence is not required by the binding, its addition was not
discussed in commit aac82707fa45 ("ARM: dts: aspeed: Add AST2600 EDAC
into common devicetree"), and its inconsistent with the g4 and g5
dtsis.

Further, the corresponding driver instantiates its own regmap rather
than fetching the syscon regmap, in theory breaking any users of the
syscon, but of which there appear to be none in-tree.

Drop it for now, and we can add it back with the necessary rework if
it's ever required.

Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
---
 arch/arm/boot/dts/aspeed/aspeed-g6.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
index 1ae816087f6b..86b30e38fa25 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
+++ b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
@@ -74,7 +74,7 @@ timer {
 	};
 
 	edac: sdram at 1e6e0000 {
-		compatible = "aspeed,ast2600-sdram-edac", "syscon";
+		compatible = "aspeed,ast2600-sdram-edac";
 		reg = <0x1e6e0000 0x174>;
 		interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
 	};

-- 
2.47.3



From andrew at codeconstruct.com.au  Thu Dec 11 00:45:54 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Thu, 11 Dec 2025 17:45:54 +0900
Subject: [PATCH RFC 12/16] ARM: dts: aspeed: g6: Drop unspecified
 aspeed,ast2600-udma node
In-Reply-To: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
Message-ID: <20251211-dev-dt-warnings-all-v1-12-21b18b9ada77@codeconstruct.com.au>

There's neither a binding defined nor a driver that matches on the
compatible, so drop it from the devicetree until someone is motivated to
solve the problems.

Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
---
 arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-clemente.dts | 4 ----
 arch/arm/boot/dts/aspeed/aspeed-g6.dtsi                   | 9 ---------
 2 files changed, 13 deletions(-)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-clemente.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-clemente.dts
index ea1bf6f402bd..2aff21442f11 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-clemente.dts
+++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-clemente.dts
@@ -1293,10 +1293,6 @@ &mac3 {
 	use-ncsi;
 };
 
-&udma {
-	status = "okay";
-};
-
 &uart1 {
 	status = "okay";
 };
diff --git a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
index 86b30e38fa25..4583c68748c2 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
+++ b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
@@ -861,15 +861,6 @@ fsim1: fsi at 1e79b100 {
 				interrupt-controller;
 				status = "disabled";
 			};
-
-			udma: dma-controller at 1e79e000 {
-				compatible = "aspeed,ast2600-udma";
-				reg = <0x1e79e000 0x1000>;
-				interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
-				dma-channels = <28>;
-				#dma-cells = <1>;
-				status = "disabled";
-			};
 		};
 	};
 };

-- 
2.47.3



From andrew at codeconstruct.com.au  Thu Dec 11 00:45:55 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Thu, 11 Dec 2025 17:45:55 +0900
Subject: [PATCH RFC 13/16] ARM: dts: aspeed: ast2600-evb: Tidy up A0
 work-around for UART5
In-Reply-To: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
Message-ID: <20251211-dev-dt-warnings-all-v1-13-21b18b9ada77@codeconstruct.com.au>

Changing the compatible changes the properties allowed -
snps,dw-apb-uart doesn't specify no-loopback-test, so remove it.

Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
---
 arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts b/arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts
index c51977dcb56b..3f2ca9da0be2 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts
+++ b/arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts
@@ -205,6 +205,7 @@ flash at 0 {
 &uart5 {
 	// Workaround for A0
 	compatible = "snps,dw-apb-uart";
+	/delete-property/ no-loopback-test;
 };
 
 &i2c0 {

-- 
2.47.3



From andrew at codeconstruct.com.au  Thu Dec 11 00:45:56 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Thu, 11 Dec 2025 17:45:56 +0900
Subject: [PATCH RFC 14/16] dt-bindings: iio: adc: Allow interrupts property
 for AST2600
In-Reply-To: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
Message-ID: <20251211-dev-dt-warnings-all-v1-14-21b18b9ada77@codeconstruct.com.au>

The device has interrupts allocated according to the datasheet, and
the devicetree already defines the interrupt property. Address existing
warnings by allowing the property.

Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
---
 Documentation/devicetree/bindings/iio/adc/aspeed,ast2600-adc.yaml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/iio/adc/aspeed,ast2600-adc.yaml b/Documentation/devicetree/bindings/iio/adc/aspeed,ast2600-adc.yaml
index 509bfb1007c4..249101b55cf4 100644
--- a/Documentation/devicetree/bindings/iio/adc/aspeed,ast2600-adc.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/aspeed,ast2600-adc.yaml
@@ -44,6 +44,9 @@ properties:
       Input clock used to derive the sample clock. Expected to be the
       SoC's APB clock.
 
+  interrupts:
+    maxItems: 1
+
   resets:
     maxItems: 1
 

-- 
2.47.3



From andrew at codeconstruct.com.au  Thu Dec 11 00:45:57 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Thu, 11 Dec 2025 17:45:57 +0900
Subject: [PATCH RFC 15/16] ARM: dts: aspeed: g6: Drop clocks property from
 arm,armv7-timer
In-Reply-To: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
Message-ID: <20251211-dev-dt-warnings-all-v1-15-21b18b9ada77@codeconstruct.com.au>

The property is not specified by the binding, nor used by the driver.

Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
---
 arch/arm/boot/dts/aspeed/aspeed-g6.dtsi | 1 -
 1 file changed, 1 deletion(-)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
index 4583c68748c2..567f8040eb8f 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
+++ b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
@@ -68,7 +68,6 @@ timer {
 			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
 			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
 			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>;
-		clocks = <&syscon ASPEED_CLK_HPLL>;
 		arm,cpu-registers-not-fw-configured;
 		always-on;
 	};

-- 
2.47.3



From andrew at codeconstruct.com.au  Thu Dec 11 00:45:58 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Thu, 11 Dec 2025 17:45:58 +0900
Subject: [PATCH RFC 16/16] dt-bindings: mfd: Document smp-memram node for
 AST2600 SCU
In-Reply-To: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
Message-ID: <20251211-dev-dt-warnings-all-v1-16-21b18b9ada77@codeconstruct.com.au>

The platform initialisation code for the AST2600 implements the custom
SMP bringup protocol, and searches for the relevant compatible. As a
consequence, define the requisite node and the compatible string, which
in-turn tidies up the dtb check results.

Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
---
 .../devicetree/bindings/mfd/aspeed,ast2x00-scu.yaml    | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/Documentation/devicetree/bindings/mfd/aspeed,ast2x00-scu.yaml b/Documentation/devicetree/bindings/mfd/aspeed,ast2x00-scu.yaml
index da1887d7a8fe..3406b98c4d0b 100644
--- a/Documentation/devicetree/bindings/mfd/aspeed,ast2x00-scu.yaml
+++ b/Documentation/devicetree/bindings/mfd/aspeed,ast2x00-scu.yaml
@@ -130,6 +130,24 @@ patternProperties:
           - description: silicon id information registers
           - description: unique chip id registers
 
+  '^smp-memram@[0-9a-f]+$':
+    description: Memory region used for the AST2600's custom SMP bringup protocol
+    type: object
+    additionalProperties: false
+
+    properties:
+      compatible:
+        const: "aspeed,ast2600-smpmem"
+
+      reg:
+        description:
+          The SMP memory region
+        maxItems: 1
+
+    required:
+      - compatible
+      - reg
+
 required:
   - compatible
   - reg

-- 
2.47.3



From alexandru.elisei at arm.com  Thu Dec 11 01:33:40 2025
From: alexandru.elisei at arm.com (Alexandru Elisei)
Date: Thu, 11 Dec 2025 09:33:40 +0000
Subject: [PATCH 2/2] KVM: arm64: Remove extra argument for
 __pvkm_host_{share,unshare}_hyp()
In-Reply-To: <86zf7po2n3.wl-maz@kernel.org>
References: <20251210132102.137631-1-alexandru.elisei@arm.com>
 <20251210132102.137631-3-alexandru.elisei@arm.com>
 <86zf7po2n3.wl-maz@kernel.org>
Message-ID: <aTqP9M_E7ROGpfbB@raptor>

Hi Marc,

On Thu, Dec 11, 2025 at 08:15:28AM +0000, Marc Zyngier wrote:
> On Wed, 10 Dec 2025 13:21:02 +0000,
> Alexandru Elisei <alexandru.elisei at arm.com> wrote:
> > 
> > __pvkm_host_share_hyp() and __pkvm_host_unshare_hyp() both have one
> > parameter, the pfn, not two. Even though correctness isn't impacted because
> > the SMCCC handlers pass the first argument and ignore the second one, let's
> > call the functions with the proper number of arguments.
> > 
> > Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
> > ---
> >  arch/arm64/kvm/mmu.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
> > index 7cc964af8d30..6c6abcd8e89e 100644
> > --- a/arch/arm64/kvm/mmu.c
> > +++ b/arch/arm64/kvm/mmu.c
> > @@ -497,7 +497,7 @@ static int share_pfn_hyp(u64 pfn)
> >  	this->count = 1;
> >  	rb_link_node(&this->node, parent, node);
> >  	rb_insert_color(&this->node, &hyp_shared_pfns);
> > -	ret = kvm_call_hyp_nvhe(__pkvm_host_share_hyp, pfn, 1);
> > +	ret = kvm_call_hyp_nvhe(__pkvm_host_share_hyp, pfn);
> >  unlock:
> >  	mutex_unlock(&hyp_shared_pfns_lock);
> >  
> 
> Yeah, we lost all form of type-checking when everything was hastily
> converted to SMCCC to avoid function pointers. Somehow, I feel that
> the cure was worse than the disease.
> 
> I wish we'd reintroduce some form of compile-time checks, maybe by
> having generated stubs?

I also think compile-time checks would be useful, do you have something
particular in mind?

If not, right now I can't think of a way to generate the stubs automagically,
but I can give it a (probably bad) try and take it from there.

Thanks,
Alex


From kory.maincent at bootlin.com  Thu Dec 11 01:40:24 2025
From: kory.maincent at bootlin.com (Kory Maincent)
Date: Thu, 11 Dec 2025 10:40:24 +0100
Subject: [PATCH 03/21] drm/tilcdc: Remove simulate_vesa_sync flag
In-Reply-To: <DEUQM2HNEOQU.3K4ZPL44GVZAJ@bootlin.com>
References: <20251126-feature_tilcdc-v1-0-49b9ef2e3aa0@bootlin.com>
	<20251126-feature_tilcdc-v1-3-49b9ef2e3aa0@bootlin.com>
	<DEUQM2HNEOQU.3K4ZPL44GVZAJ@bootlin.com>
Message-ID: <20251211104024.1e7d5c42@kmaincent-XPS-13-7390>

On Wed, 10 Dec 2025 19:10:45 +0100
"Luca Ceresoli" <luca.ceresoli at bootlin.com> wrote:

> Hi K?ry,
> 
> On Wed Nov 26, 2025 at 6:35 PM CET, Kory Maincent (TI.com) wrote:
> > The tilcdc hardware does not generate VESA-compliant sync signals. It
> > aligns the vertical sync (VS) on the second edge of the horizontal sync
> > (HS) instead of the first edge. To compensate for this hardware
> > behavior, the driver applies a timing adjustment in mode_fixup().
> >
> > Previously, this adjustment was conditional based on the simulate_vesa_sync
> > flag, which was only set when using external encoders. This appears
> > problematic because:
> >
> > 1. The timing adjustment seems needed for the hardware behavior regardless
> >    of whether an external encoder is used
> > 2. The external encoder infrastructure is driver-specific and being
> >    removed due to design issues
> > 3. Boards using tilcdc without bridges (e.g., am335x-evm, am335x-evmsk)
> >    may not be getting the necessary timing adjustments
> >
> > Remove the simulate_vesa_sync flag and apply the VESA sync timing
> > adjustment unconditionally, ensuring consistent behavior across all
> > configurations. While it's unclear if the previous conditional behavior
> > was causing actual issues, the unconditional adjustment better reflects
> > the hardware's characteristics.
> >
> > Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
> > ---
> >
> > Only few board currently use tilcdc not associated to a bridge like the
> > am335x_evm or the am335x-evmsk.  
> 
> Have you tested this change on any affected board?
> 
> The change looks good to me but without some testing it would be risky.

I have tested it on few boards but not these mainline devicetree as I don't
have them.

I have tested a tilcdc with tda998x bridge (BeagleBone Black), a tilcdc with
ti,tilcdc,panel panel (BeagleBone with LCD cape), a tilcdc with it66121 bridge
(new Beagle Bone Green Eco board with HDMI cape).
That's all the boards I have.

Regards,
-- 
K?ry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com


From luca.ceresoli at bootlin.com  Thu Dec 11 01:42:50 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Thu, 11 Dec 2025 10:42:50 +0100
Subject: [PATCH 08/21] drm/tilcdc: Remove component framework support
In-Reply-To: <20251126-feature_tilcdc-v1-8-49b9ef2e3aa0@bootlin.com>
References: <20251126-feature_tilcdc-v1-0-49b9ef2e3aa0@bootlin.com>
 <20251126-feature_tilcdc-v1-8-49b9ef2e3aa0@bootlin.com>
Message-ID: <DEVAFQ7XD89Z.XPEGS4AOAF1W@bootlin.com>

On Wed Nov 26, 2025 at 6:35 PM CET, Kory Maincent (TI.com) wrote:
> The tilcdc driver previously used the component framework to bind
> external encoder subdrivers (specifically the TDA998x HDMI encoder).
> With the removal of these subdrivers in previous commits, the component
> framework is no longer needed.
>
> This commit removes all component framework infrastructure including:
> - Component master operations and bind/unbind callbacks
> - The is_componentized flag and conditional code paths
> - tilcdc_get_external_components() and tilcdc_add_component_encoder()
> - TDA998x-specific panel configuration
>
> The driver now uses a simplified initialization path that directly
> attaches external devices via the DRM bridge API, eliminating the
> complexity of dual code paths for componentized vs non-componentized
> configurations.
>
> This cleanup removes approximately 140 lines of code and makes the
> driver initialization flow more straightforward.
>
> Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>

This driver is complex already, supporting two different modes (one of
which used in a single case only) makes it just worse. So this cleanup
looks very useful.

Provided it's tested on hardware:
Reviewed-by: Luca Ceresoli <luca.ceresoli at bootlin.com>

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From luca.ceresoli at bootlin.com  Thu Dec 11 01:44:10 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Thu, 11 Dec 2025 10:44:10 +0100
Subject: [PATCH 09/21] drm/tilcdc: Remove tilcdc_panel_info structure
In-Reply-To: <20251126-feature_tilcdc-v1-9-49b9ef2e3aa0@bootlin.com>
References: <20251126-feature_tilcdc-v1-0-49b9ef2e3aa0@bootlin.com>
 <20251126-feature_tilcdc-v1-9-49b9ef2e3aa0@bootlin.com>
Message-ID: <DEVAGR1ZP5RJ.3GQ5EPCVDUXWJ@bootlin.com>

On Wed Nov 26, 2025 at 6:35 PM CET, Kory Maincent (TI.com) wrote:
> Remove the tilcdc_panel_info structure and its associated helper
> function as the structure contains only redundant or unused parameters.
>
> Most panel configuration parameters in tilcdc_panel_info are either:
> - Already represented by existing DRM mode flags (invert_pxl_clk,
>   sync_edge via DRM_BUS_FLAG_*), or
> - Set to identical values across all instances (panel_info_default),
>   making them effectively constants
>
> The removed fifo_th field is already handled by priv->fifo_th when set.
> Other removed fields (tft_alt_mode, raster_order) were always set to 0
> in the only instance (panel_info_default) and thus had no effect.
>
> This simplifies the code by eliminating unnecessary abstraction while
> preserving all functional behavior.
>
> Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>

Reviewed-by: Luca Ceresoli <luca.ceresoli at bootlin.com>

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From luca.ceresoli at bootlin.com  Thu Dec 11 01:47:39 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Thu, 11 Dec 2025 10:47:39 +0100
Subject: [PATCH 03/21] drm/tilcdc: Remove simulate_vesa_sync flag
In-Reply-To: <20251211104024.1e7d5c42@kmaincent-XPS-13-7390>
References: <20251126-feature_tilcdc-v1-0-49b9ef2e3aa0@bootlin.com>
 <20251126-feature_tilcdc-v1-3-49b9ef2e3aa0@bootlin.com>
 <DEUQM2HNEOQU.3K4ZPL44GVZAJ@bootlin.com>
 <20251211104024.1e7d5c42@kmaincent-XPS-13-7390>
Message-ID: <DEVAJEYEL7SW.2F8RT465LAL5U@bootlin.com>

On Thu Dec 11, 2025 at 10:40 AM CET, Kory Maincent wrote:
> On Wed, 10 Dec 2025 19:10:45 +0100
> "Luca Ceresoli" <luca.ceresoli at bootlin.com> wrote:
>
>> Hi K?ry,
>>
>> On Wed Nov 26, 2025 at 6:35 PM CET, Kory Maincent (TI.com) wrote:
>> > The tilcdc hardware does not generate VESA-compliant sync signals. It
>> > aligns the vertical sync (VS) on the second edge of the horizontal sync
>> > (HS) instead of the first edge. To compensate for this hardware
>> > behavior, the driver applies a timing adjustment in mode_fixup().
>> >
>> > Previously, this adjustment was conditional based on the simulate_vesa_sync
>> > flag, which was only set when using external encoders. This appears
>> > problematic because:
>> >
>> > 1. The timing adjustment seems needed for the hardware behavior regardless
>> >    of whether an external encoder is used
>> > 2. The external encoder infrastructure is driver-specific and being
>> >    removed due to design issues
>> > 3. Boards using tilcdc without bridges (e.g., am335x-evm, am335x-evmsk)
>> >    may not be getting the necessary timing adjustments
>> >
>> > Remove the simulate_vesa_sync flag and apply the VESA sync timing
>> > adjustment unconditionally, ensuring consistent behavior across all
>> > configurations. While it's unclear if the previous conditional behavior
>> > was causing actual issues, the unconditional adjustment better reflects
>> > the hardware's characteristics.
>> >
>> > Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
>> > ---
>> >
>> > Only few board currently use tilcdc not associated to a bridge like the
>> > am335x_evm or the am335x-evmsk.
>>
>> Have you tested this change on any affected board?
>>
>> The change looks good to me but without some testing it would be risky.
>
> I have tested it on few boards but not these mainline devicetree as I don't
> have them.
>
> I have tested a tilcdc with tda998x bridge (BeagleBone Black), a tilcdc with
> ti,tilcdc,panel panel (BeagleBone with LCD cape), a tilcdc with it66121 bridge
> (new Beagle Bone Green Eco board with HDMI cape).
> That's all the boards I have.

OK, thanks for the info. For future iterations, I think it's useful to
mention, for all patches that may potentially break existing hardware, such
info on which hardware you have tested.

Luca

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From sudeep.holla at arm.com  Thu Dec 11 01:50:27 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Thu, 11 Dec 2025 09:50:27 +0000
Subject: [PATCH 1/1] firmware: arm_scmi: Increase MAX_OPPS to 64
In-Reply-To: <6af5945e-7d5c-4596-ac42-c5898b4c49b7@oss.qualcomm.com>
References: <20251014073454.461999-1-vivek.aknurwar@oss.qualcomm.com>
 <6af5945e-7d5c-4596-ac42-c5898b4c49b7@oss.qualcomm.com>
Message-ID: <20251211-delectable-axiomatic-hummingbird-55a792@sudeepholla>

On Wed, Dec 10, 2025 at 03:28:37PM -0800, Vivek Aknurwar wrote:
> Hello Sudeep/Cristian,
> 
> Just following up on this patch. If there?s anything missing or
> needs adjustment, please let me know.
> 

Sorry seem to have slipped through the cracks while I was away. I will
queue it for next merge window soon.

-- 
Regards,
Sudeep


From hi at josie.lol  Thu Dec 11 01:50:49 2025
From: hi at josie.lol (Josephine Pfeiffer)
Date: Thu, 11 Dec 2025 10:50:49 +0100
Subject: [PATCH 1/4] arm64: ptdump: use seq_puts() in pt_dump_seq_puts() macro
In-Reply-To: <20251101210201.43210-1-hi@josie.lol>
References: <20251018170416.3355249-1-hi@josie.lol> <aQNyaoXKsMdkIDrc@willie-the-truck> <20251101210201.43210-1-hi@josie.lol>
Message-ID: <20251211095049.182437-1-hi@josie.lol>

Hi Will,

Friendly ping on this patch. The s390 and RISC-V patches from this series
have been merged to master. Is there anything else needed for the arm64
version?

Thanks,
Josie


From kevin.brodsky at arm.com  Thu Dec 11 01:52:11 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Thu, 11 Dec 2025 10:52:11 +0100
Subject: [PATCH v9 15/16] entry: Inline syscall_exit_work()
In-Reply-To: <87345hfqyh.ffs@tglx>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
 <20251204082123.2792067-16-ruanjinjie@huawei.com>
 <b382cc8a-3ce9-4fb1-bc0a-a3d9796251d1@arm.com> <87345hfqyh.ffs@tglx>
Message-ID: <e55e9aae-1d84-42a2-bf6a-edc73608733a@arm.com>

On 11/12/2025 07:55, Thomas Gleixner wrote:
> I have a suspicion that it is TIF_NOTIFY_RESUME. If that's the case
> you're seing the RSEQ overhead, which should be completely gone with the
> rewrite that got just merged into Linus tree.

I don't think this is related. This patch inlines syscall_exit_work(),
which is called if some flag in SYSCALL_WORK_EXIT is set. This includes
syscall-specific stuff like tracing and singlestep. TIF_NOTIFY_RESUME is
part of EXIT_TO_USER_MODE_WORK, handled in exit_to_user_mode_prepare(),
and isn't specific to syscall handling.

- Kevin


From david at ixit.cz  Thu Dec 11 02:41:20 2025
From: david at ixit.cz (David Heidelberg)
Date: Thu, 11 Dec 2025 11:41:20 +0100
Subject: [PATCH QUESTION] arm64: configs: Add Snapdragon 845 config
 fragment
In-Reply-To: <8f8baac8-3b1a-442d-a64f-5a90f9e30552@app.fastmail.com>
References: <20251126-sdm845-config-question-v1-1-ffa91ed53095@ixit.cz>
 <8f8baac8-3b1a-442d-a64f-5a90f9e30552@app.fastmail.com>
Message-ID: <9221ccef-f1b9-4491-83e2-7116b7523857@ixit.cz>

On 03/12/2025 22:35, Arnd Bergmann wrote:
> On Wed, Nov 26, 2025, at 17:19, David Heidelberg via B4 Relay wrote:
>>
>> This patch is a question, if it would be viable to introduce this
>> configuration fragment as part of mainline kernel, so keeping it in sync
>> with recent kernel updates would be more straighforward.
> 
> I don't mind the idea of having additional fragments for specific
> purposes, but as others have said this one does not seem that useful.
> 
> I think it does too many things at once and is still too specific to
> a relatively uncommon usecase. Having an SDM845 specific fragment is
> clearly too narrow, but I can see us adding a fragment for phones
> overall, which would then turn on options for Qualcomm, Mediatek
> and Samsung based phones.

I agree there are too specific things. I sent this as a conversation 
starter more than "a fragment to ship".

Having something like a pure mobile fragment would be awesome.
Bringing up phones is challenging enough, so when people have one more 
pillar to rely on, it'll definitely accelerate work.

I believe it would help many close-to-mainline projects to have a more 
stable base in the kernel instead of every repository playing on own 
small playground.

> 
>> +# Samsung S9 SM-G9600(starqltechn)
>> +CONFIG_SND_SOC_MAX98512=y
>> +CONFIG_SND_SOC_MAXIM_DSM=y
>> +CONFIG_SND_SOC_MAXIM_DSM_CAL=y
>> +CONFIG_DRM_PANEL_SAMSUNG_S6E3HA8=y
>> +CONFIG_TOUCHSCREEN_S6SY761=m
>> +CONFIG_MFD_SEC_CORE=m
>> +CONFIG_REGULATOR_S2DOS05=m
>> +CONFIG_MFD_MAX77705=m
>> +CONFIG_LEDS_MAX77705=m
>> +CONFIG_CHARGER_MAX77705=m
>> +CONFIG_BATTERY_MAX17042=m
>> +CONFIG_INPUT_MAX77693_HAPTIC=m
>> +CONFIG_PWM_CLK=m
>> +
>> +# SHIFT6mq
>> +CONFIG_DRM_PANEL_VISIONOX_RM69299=y
>> +CONFIG_SND_SOC_TFA989X=m
> 
> I think overall we can be fairly liberal with adding
> more loadable modules to the common defconfig, but much
> less so the built-in drivers.
> 
>> +# SOC
>> +CONFIG_FORCE_NR_CPUS=y
>> +CONFIG_NR_CPUS=8
> 
> This would break other devices that have more CPUs, which in turn
> makes it impossible to combine the fragment with other fragments.

Yes, I just used the original data from the fragment, as we know it's 8 
cores, it's safe option. For the final fragment this will go away (if we 
talk about mobile generic fragment).

> 
>> +CONFIG_SCSI_UFS_QCOM=y
>> +CONFIG_QCOM_GSBI=y
>> +CONFIG_QCOM_LLCC=y
>> +CONFIG_QCOM_OCMEM=y
>> +CONFIG_QCOM_RMTFS_MEM=y
>> +CONFIG_QCOM_SOCINFO=y
>> +CONFIG_QCOM_WCNSS_CTRL=y
>> +CONFIG_QCOM_APR=y
>> +CONFIG_POWER_RESET_QCOM_PON=y
>> +CONFIG_QCOM_SPMI_TEMP_ALARM=y
>> +CONFIG_QCOM_LMH=y
>> +CONFIG_SCHED_CLUSTER=y
>> +CONFIG_SND_SOC_QDSP6_Q6VOICE=m
>> +CONFIG_SCSI_UFS_BSG=y
>> +CONFIG_PHY_QCOM_QMP_PCIE=y
>> +CONFIG_BACKLIGHT_CLASS_DEVICE=y
>> +CONFIG_INTERCONNECT_QCOM_OSM_L3=y
> 
> Again, these should mosely be loadable modules.

Probably, some of these workarounds are here because of some issue in 
the kernel, which leads to boot failure.

There will be more of these bug-avoid changes.

We'll test how many of these are necessary.

The question is, if documented, could we push some of these into the 
initial fragments? I assume fixing some of these may take some time.

> 
>> +# Notification LED
>> +# Must be builtin as it won't be automatically modprobed
>> +CONFIG_LEDS_TRIGGER_PATTERN=y
> 
> This sounds like bug that we should fix and not work around.
> 
>> +# Graphics
>> +CONFIG_DRM=y
>> +CONFIG_FB_SIMPLE=y
> 
> I don't want to enable more fbdev drivers. Right now the
> only one we enable is FB_EFI, and we should probably replace
> that with DRM_SIMPLEDRM in order to turn off CONFIG_FB
> entirely.

Useful with debugging, but this can handle Mobian, NixOS Mobile, pmOS by 
their fragments, so that's fine to drop.

> 
>> +# Power management
>> +CONFIG_PM_AUTOSLEEP=y
>> +CONFIG_PM_WAKELOCKS=y
>> +
>> +# MGLRU
>> +CONFIG_LRU_GEN=y
>> +CONFIG_LRU_GEN_ENABLED=y
>> +
>> +# Usage clamping (scale CPU for specific tasks)
>> +CONFIG_UCLAMP_TASK=y
>> +CONFIG_UCLAMP_TASK_GROUP=y
> 
> We can discuss changing the defaults for these in the defconfig,
> but this doesn't seem to belong with the other stuff.

Great :)

> 
>> +# HID/Input
>> +CONFIG_LCD_CLASS_DEVICE=m
> 
> This is not an input option

Thanks, removed.

> 
>> +CONFIG_I2C_HID=y
>> +CONFIG_HID_GENERIC=m
>> +CONFIG_UHID=m
>> +CONFIG_USB_HID=m
>> +CONFIG_INPUT_EVDEV=y
>> +CONFIG_BT_HIDP=m
>> +CONFIG_INPUT_JOYDEV=m
>> +CONFIG_HID_ACCUTOUCH=m
>> +CONFIG_HID_ACRUX=m
>> +CONFIG_HID_ACRUX_FF=y
>> +CONFIG_HID_ALPS=m
>> +CONFIG_HID_APPLEIR=m
> 
> This looks like you are just enabling every single USB HID
> driver, which is probably not something we want in a commonly
> used fragment, though having a well-maintained fragment for
> popular pluggable USB devices may be useful for others as well.

Yeah, this part make sense for distro-specific.

> 
>> +# Qcom stuff
>> +CONFIG_RPMSG_CHAR=y
>> +CONFIG_QCOM_Q6V5_ADSP=m
>> +CONFIG_BT_RFCOMM=m
>> +CONFIG_BT_RFCOMM_TTY=y
>> +CONFIG_BT_BNEP=m
>> +CONFIG_BT_BNEP_MC_FILTER=y
>> +CONFIG_BT_BNEP_PROTO_FILTER=y
>> +CONFIG_BT_HS=y
>> +CONFIG_BT_LE=y
>> +CONFIG_HID_BATTERY_STRENGTH=y
>> +CONFIG_HIDRAW=y
>> +CONFIG_QCOM_COINCELL=m
>> +CONFIG_QCOM_FASTRPC=m
>> +CONFIG_QCOM_SPMI_VADC=y
>> +CONFIG_QCOM_SPMI_ADC5=y
>> +CONFIG_PHY_QCOM_QMP=y
>> +CONFIG_PHY_QCOM_QUSB2=y
>> +CONFIG_PHY_QCOM_QMP_UFS=y
>> +CONFIG_TYPEC=y
>> +CONFIG_PHY_QCOM_QMP_COMBO=y
>> +CONFIG_LEDS_CLASS_FLASH=y
>> +CONFIG_TCP_CONG_ADVANCED=y
>> +CONFIG_TCP_CONG_WESTWOOD=y
>> +CONFIG_DEFAULT_WESTWOOD=y
>> +CONFIG_BLK_DEV_RAM=y
>> +CONFIG_BLK_DEV_RAM_SIZE=8192
>> +CONFIG_BTRFS_FS=y
>> +CONFIG_BTRFS_FS_POSIX_ACL=y
>> +CONFIG_F2FS_FS=y
> 
> Most of these don't look like "Qcom stuff" to me. In particular
> BTRFS is probably not something you'd even want to enable on
> a phone, though that could be part of a generic distro config
> that we have discussed several times in the past.

Yeah, pmOS specific changes will be dropped.

> 
>> +# WLAN debugging
>> +CONFIG_ATH10K_DEBUG=y
>> +CONFIG_ATH10K_DEBUGFS=y
>> +CONFIG_ATH10K_SPECTRAL=y
> 
> This particular one seem arbitrary, but having a "debugging"
> fragment is something others may find helpful as well. The
> hard part there is figuring out which debug options are the
> most helpful for the least overhead, as everyone is debugging
> different bugs.

I was thinking having "fragment pack" for "early bringup-er", something 
like common things you need to verify, when you setting up
  - regulators
  - clocks
  - serial
  - framebuffer

When people are new to the kernel development and still don't know all, 
I think this may accelerate their progress.


> 
>> +# Disable all unrelated stuffs afaik
>> +CONFIG_ARCH_BLAIZE=n
>> +CONFIG_ARCH_SPARX5=n
>> +CONFIG_HIBERNATION=n
>> +CONFIG_FW_LOADER_USER_HELPER=n
>> +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=n
>> +CONFIG_BLK_DEV_NVME=n
> 
> It feels wrong to turn things off in the same fragment
> that turns other things on.

Here, would it make sense to do 3-4 categories, dropping things which 
CANNOT in general setups on devices such as:

  - servers (phone battery, vibrator, etc.)
  - desktops and laptops (embedded drivers, etc.)
  - mobile, e.g., phone and tablets (RAID array on PCIe, network routing 
chip, etc.)
  - basic embedded and routers

If we go by the Pareto principle (~ 80/20) with low effort and easy 
maintenance, we could manage smaller, more efficient images. 
Distributions (or people) who don't want to risk any inconvenience or 
have an obscure setup will just not use the fragments.

What do you think?

If there is a consensus on some parts, I'll prepare some basic small series.

David

P.S. Sorry for the late reply, Thunderbird decided to encrypt my Draft, 
but somehow forgot how to decrypt it...

> 
>        Arnd

-- 
David Heidelberg



From francesco at dolcini.it  Thu Dec 11 02:43:32 2025
From: francesco at dolcini.it (Francesco Dolcini)
Date: Thu, 11 Dec 2025 11:43:32 +0100
Subject: [EXT] Re: [PATCH v2] arm64: errata: Add NXP iMX8QM workaround
 for A53 Cache coherency issue
In-Reply-To: <DU2PR04MB8951DEE7CB2D29D7E83CE03388A0A@DU2PR04MB8951.eurprd04.prod.outlook.com>
References: <20230420112952.28340-1-iivanov@suse.de>
 <20251210074550.GA10733@francesco-nb>
 <DU2PR04MB8951DEE7CB2D29D7E83CE03388A0A@DU2PR04MB8951.eurprd04.prod.outlook.com>
Message-ID: <20251211104332.GA9632@francesco-nb>

Hello Frank,

On Wed, Dec 10, 2025 at 02:55:12PM +0000, Frank Li wrote:
> > On Thu, Apr 20, 2023 at 02:29:52PM +0300, Ivan T. Ivanov wrote:
> > > According to NXP errata document[1] i.MX8QuadMax SoC suffers from
> > > serious cache coherence issue. It was also mentioned in initial
> > > support[2] for imx8qm mek machine.
> > 
> > Ivan, from what I can see this patch was never merged and there was not any
> > follow-up on this. What's the status? Are you planning to work on it?
> > 
> > Frank, it would be nice to have this issue sorted out in mainline, any
> > chance that NXP can help move this forward?
> 
> Jason worked the original solution, what's difficult of upstream accept the
> Solution?

Was it ever sent to mainline for inclusion?

Can NXP help on having a workaround for this errata implemented in
mainline Linux, whatever is the actual final technical solution?

Francesco



From tabba at google.com  Thu Dec 11 02:47:00 2025
From: tabba at google.com (Fuad Tabba)
Date: Thu, 11 Dec 2025 10:47:00 +0000
Subject: [PATCH v6 0/9] KVM: arm64: Fixes for guest CPU feature trapping and enabling
Message-ID: <20251211104710.151771-1-tabba@google.com>

Hi,

This series contains several fixes for guest feature trapping and
enabling in pKVM, as well as a bit of tidying up.

Changes from v6 [1]:
- Fixes to the patch that tracks KVM IOCTLs and their associated KVM
  caps. Move static header data and function definitions to arm.c.
- Introduce a capability KVM_CAP_ARM_BASIC instead of KVM_CAP_CORE,
  since it is ARM-specific and that it only checks basic ARM ioctls.
- Tidying up code and commit messages.
- Based on Linux 6.18

Cheers,
/fuad

[1] https://lore.kernel.org/all/20251118103807.707500-1-tabba at google.com/

Fuad Tabba (9):
  KVM: arm64: Fix Trace Buffer trapping for protected VMs
  KVM: arm64: Fix Trace Buffer trap polarity for protected VMs
  KVM: arm64: Fix MTE flag initialization for protected VMs
  KVM: arm64: Introduce helper to calculate fault IPA offset
  KVM: arm64: Include VM type when checking VM capabilities in pKVM
  KVM: arm64: Do not allow KVM_CAP_ARM_MTE for any guest in pKVM
  KVM: arm64: Track KVM IOCTLs and their associated KVM caps
  KVM: arm64: Check whether a VM IOCTL is allowed in pKVM
  KVM: arm64: Prevent host from managing timer offsets for protected VMs

 arch/arm64/include/asm/kvm_arm.h         |  2 +
 arch/arm64/include/asm/kvm_host.h        |  2 +
 arch/arm64/include/asm/kvm_pkvm.h        | 33 ++++++++++++++--
 arch/arm64/kvm/arch_timer.c              | 18 ++++++---
 arch/arm64/kvm/arm.c                     | 49 +++++++++++++++++++++++-
 arch/arm64/kvm/hyp/nvhe/pkvm.c           | 18 ++++-----
 arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c |  2 +-
 arch/arm64/kvm/inject_fault.c            |  2 +-
 arch/arm64/kvm/mmu.c                     |  4 +-
 include/uapi/linux/kvm.h                 |  1 +
 10 files changed, 107 insertions(+), 24 deletions(-)


base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
-- 
2.52.0.223.gf5cc29aaa4-goog



From tabba at google.com  Thu Dec 11 02:47:01 2025
From: tabba at google.com (Fuad Tabba)
Date: Thu, 11 Dec 2025 10:47:01 +0000
Subject: [PATCH v6 1/9] KVM: arm64: Fix Trace Buffer trapping for protected VMs
In-Reply-To: <20251211104710.151771-1-tabba@google.com>
References: <20251211104710.151771-1-tabba@google.com>
Message-ID: <20251211104710.151771-2-tabba@google.com>

For protected VMs in pKVM, the hypervisor should trap accesses to trace
buffer system registers if Trace Buffer isn't supported by the VM.
However, the current code only traps if Trace Buffer External Mode isn't
supported.

Fix this by checking for FEAT_TRBE (Trace Buffer) rather than
FEAT_TRBE_EXT.

Fixes: 9d5261269098 ("KVM: arm64: Trap external trace for protected VMs")
Reported-by: Suzuki K Poulose <suzuki.poulose at arm.com>
Reviewed-by: Suzuki K Poulose <suzuki.poulose at arm.com>
Signed-off-by: Fuad Tabba <tabba at google.com>
---
 arch/arm64/kvm/hyp/nvhe/pkvm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index 43bde061b65d..8d06a246dfd1 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -117,7 +117,7 @@ static void pvm_init_traps_mdcr(struct kvm_vcpu *vcpu)
 	if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, TraceFilt, IMP))
 		val |= MDCR_EL2_TTRF;
 
-	if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, ExtTrcBuff, IMP))
+	if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, TraceBuffer, IMP))
 		val |= MDCR_EL2_E2TB_MASK;
 
 	/* Trap Debug Communications Channel registers */
-- 
2.52.0.223.gf5cc29aaa4-goog



From tabba at google.com  Thu Dec 11 02:47:02 2025
From: tabba at google.com (Fuad Tabba)
Date: Thu, 11 Dec 2025 10:47:02 +0000
Subject: [PATCH v6 2/9] KVM: arm64: Fix Trace Buffer trap polarity for
 protected VMs
In-Reply-To: <20251211104710.151771-1-tabba@google.com>
References: <20251211104710.151771-1-tabba@google.com>
Message-ID: <20251211104710.151771-3-tabba@google.com>

The E2TB bits in MDCR_EL2 control trapping of Trace Buffer system
register accesses. These accesses are trapped to EL2 when the bits are
clear.

The trap initialization logic for protected VMs in pvm_init_traps_mdcr()
had the polarity inverted. When a guest did not support the Trace Buffer
feature, the code was setting E2TB. This incorrectly disabled the trap,
potentially allowing a protected guest to access registers for a feature
it was not given.

Fix this by inverting the operation.

Fixes: f50758260bff ("KVM: arm64: Group setting traps for protected VMs by control register")
Reviewed-by: Suzuki K Poulose <suzuki.poulose at arm.com>
Signed-off-by: Fuad Tabba <tabba at google.com>
---
 arch/arm64/kvm/hyp/nvhe/pkvm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index 8d06a246dfd1..f6f8996c4f97 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -118,7 +118,7 @@ static void pvm_init_traps_mdcr(struct kvm_vcpu *vcpu)
 		val |= MDCR_EL2_TTRF;
 
 	if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, TraceBuffer, IMP))
-		val |= MDCR_EL2_E2TB_MASK;
+		val &= ~MDCR_EL2_E2TB_MASK;
 
 	/* Trap Debug Communications Channel registers */
 	if (!kvm_has_feat(kvm, ID_AA64MMFR0_EL1, FGT, IMP))
-- 
2.52.0.223.gf5cc29aaa4-goog



From tabba at google.com  Thu Dec 11 02:47:03 2025
From: tabba at google.com (Fuad Tabba)
Date: Thu, 11 Dec 2025 10:47:03 +0000
Subject: [PATCH v6 3/9] KVM: arm64: Fix MTE flag initialization for protected VMs
In-Reply-To: <20251211104710.151771-1-tabba@google.com>
References: <20251211104710.151771-1-tabba@google.com>
Message-ID: <20251211104710.151771-4-tabba@google.com>

The function pkvm_init_features_from_host() initializes guest
features, propagating them from the host. The logic to propagate
KVM_ARCH_FLAG_MTE_ENABLED (Memory Tagging Extension)
has a couple of issues.

First, the check was in the common path, before the divergence for
protected and non-protected VMs. For non-protected VMs, this was
unnecessary, as 'kvm->arch.flags' is completely overwritten by
host_arch_flags immediately after, which already contains the MTE flag.
For protected VMs, this was setting the flag even if the feature is not
allowed.

Second, the check was reading 'host_kvm->arch.flags' instead of using
the local 'host_arch_flags', which is read once from the host flags.

Fix these by moving the MTE flag check inside the protected-VM-only
path, checking if the feature is allowed, and changing it to use the
correct host_arch_flags local variable. This ensures non-protected VMs
get the flag via the bulk copy, and protected VMs get it via an explicit
check.

Fixes: b7f345fbc32a ("KVM: arm64: Fix FEAT_MTE in pKVM")
Reviewed-by: Ben Horgan <ben.horgan at arm.com>
Signed-off-by: Fuad Tabba <tabba at google.com>
---
 arch/arm64/kvm/hyp/nvhe/pkvm.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index f6f8996c4f97..16d7bf493c18 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -337,9 +337,6 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
 	/* CTR_EL0 is always under host control, even for protected VMs. */
 	hyp_vm->kvm.arch.ctr_el0 = host_kvm->arch.ctr_el0;
 
-	if (test_bit(KVM_ARCH_FLAG_MTE_ENABLED, &host_kvm->arch.flags))
-		set_bit(KVM_ARCH_FLAG_MTE_ENABLED, &kvm->arch.flags);
-
 	/* No restrictions for non-protected VMs. */
 	if (!kvm_vm_is_protected(kvm)) {
 		hyp_vm->kvm.arch.flags = host_arch_flags;
@@ -354,6 +351,9 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
 		return;
 	}
 
+	if (kvm_pvm_ext_allowed(KVM_CAP_ARM_MTE))
+		kvm->arch.flags |= host_arch_flags & BIT(KVM_ARCH_FLAG_MTE_ENABLED);
+
 	bitmap_zero(allowed_features, KVM_VCPU_MAX_FEATURES);
 
 	set_bit(KVM_ARM_VCPU_PSCI_0_2, allowed_features);
-- 
2.52.0.223.gf5cc29aaa4-goog



From tabba at google.com  Thu Dec 11 02:47:04 2025
From: tabba at google.com (Fuad Tabba)
Date: Thu, 11 Dec 2025 10:47:04 +0000
Subject: [PATCH v6 4/9] KVM: arm64: Introduce helper to calculate fault IPA offset
In-Reply-To: <20251211104710.151771-1-tabba@google.com>
References: <20251211104710.151771-1-tabba@google.com>
Message-ID: <20251211104710.151771-5-tabba@google.com>

This 12-bit FAR fault IPA offset mask is hard-coded as 'GENMASK(11, 0)'
in several places to reconstruct the full fault IPA.

Introduce FAR_TO_FIPA_OFFSET() to calculate this value in a shared
header and replace all open-coded instances to improve readability.

No functional change intended.

Signed-off-by: Fuad Tabba <tabba at google.com>
---
 arch/arm64/include/asm/kvm_arm.h         | 2 ++
 arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c | 2 +-
 arch/arm64/kvm/inject_fault.c            | 2 +-
 arch/arm64/kvm/mmu.c                     | 4 ++--
 4 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 1da290aeedce..73abe697bc2d 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -343,6 +343,8 @@
 #define PAR_TO_HPFAR(par)		\
 	(((par) & GENMASK_ULL(52 - 1, 12)) >> 8)
 
+#define FAR_TO_FIPA_OFFSET(far) ((far) & GENMASK_ULL(11, 0))
+
 #define ECN(x) { ESR_ELx_EC_##x, #x }
 
 #define kvm_arm_exception_class \
diff --git a/arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c b/arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c
index 78579b31a420..43d7dfa2c517 100644
--- a/arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c
+++ b/arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c
@@ -44,7 +44,7 @@ int __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
 
 	/* Build the full address */
 	fault_ipa  = kvm_vcpu_get_fault_ipa(vcpu);
-	fault_ipa |= kvm_vcpu_get_hfar(vcpu) & GENMASK(11, 0);
+	fault_ipa |= FAR_TO_FIPA_OFFSET(kvm_vcpu_get_hfar(vcpu));
 
 	/* If not for GICV, move on */
 	if (fault_ipa <  vgic->vgic_cpu_base ||
diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
index dfcd66c65517..c9bbce017dee 100644
--- a/arch/arm64/kvm/inject_fault.c
+++ b/arch/arm64/kvm/inject_fault.c
@@ -258,7 +258,7 @@ void kvm_inject_size_fault(struct kvm_vcpu *vcpu)
 	unsigned long addr, esr;
 
 	addr  = kvm_vcpu_get_fault_ipa(vcpu);
-	addr |= kvm_vcpu_get_hfar(vcpu) & GENMASK(11, 0);
+	addr |= FAR_TO_FIPA_OFFSET(kvm_vcpu_get_hfar(vcpu));
 
 	__kvm_inject_sea(vcpu, kvm_vcpu_trap_is_iabt(vcpu), addr);
 
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index 7cc964af8d30..5b159cf0d203 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -1959,7 +1959,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
 
 		/* Falls between the IPA range and the PARange? */
 		if (fault_ipa >= BIT_ULL(VTCR_EL2_IPA(vcpu->arch.hw_mmu->vtcr))) {
-			fault_ipa |= kvm_vcpu_get_hfar(vcpu) & GENMASK(11, 0);
+			fault_ipa |= FAR_TO_FIPA_OFFSET(kvm_vcpu_get_hfar(vcpu));
 
 			return kvm_inject_sea(vcpu, is_iabt, fault_ipa);
 		}
@@ -2059,7 +2059,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
 		 * faulting VA. This is always 12 bits, irrespective
 		 * of the page size.
 		 */
-		ipa |= kvm_vcpu_get_hfar(vcpu) & GENMASK(11, 0);
+		ipa |= FAR_TO_FIPA_OFFSET(kvm_vcpu_get_hfar(vcpu));
 		ret = io_mem_abort(vcpu, ipa);
 		goto out_unlock;
 	}
-- 
2.52.0.223.gf5cc29aaa4-goog



From tabba at google.com  Thu Dec 11 02:47:05 2025
From: tabba at google.com (Fuad Tabba)
Date: Thu, 11 Dec 2025 10:47:05 +0000
Subject: [PATCH v6 5/9] KVM: arm64: Include VM type when checking VM
 capabilities in pKVM
In-Reply-To: <20251211104710.151771-1-tabba@google.com>
References: <20251211104710.151771-1-tabba@google.com>
Message-ID: <20251211104710.151771-6-tabba@google.com>

Certain features and capabilities are restricted in protected mode. Most
of these features are restricted only for protected VMs, but some
are restricted for ALL VMs in protected mode.

Extend the pKVM capability check to pass the VM (kvm), and use that when
determining supported features.

Signed-off-by: Fuad Tabba <tabba at google.com>
---
 arch/arm64/include/asm/kvm_pkvm.h | 10 ++++++----
 arch/arm64/kvm/arm.c              |  4 ++--
 arch/arm64/kvm/hyp/nvhe/pkvm.c    | 10 +++++-----
 3 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm_pkvm.h
index 08be89c95466..7195be508d99 100644
--- a/arch/arm64/include/asm/kvm_pkvm.h
+++ b/arch/arm64/include/asm/kvm_pkvm.h
@@ -23,10 +23,12 @@ void pkvm_destroy_hyp_vm(struct kvm *kvm);
 int pkvm_create_hyp_vcpu(struct kvm_vcpu *vcpu);
 
 /*
- * This functions as an allow-list of protected VM capabilities.
- * Features not explicitly allowed by this function are denied.
+ * Check whether the specific capability is allowed in pKVM.
+ *
+ * Certain features are allowed only for non-protected VMs in pKVM, which is why
+ * this takes the VM (kvm) as a parameter.
  */
-static inline bool kvm_pvm_ext_allowed(long ext)
+static inline bool kvm_pkvm_ext_allowed(struct kvm *kvm, long ext)
 {
 	switch (ext) {
 	case KVM_CAP_IRQCHIP:
@@ -43,7 +45,7 @@ static inline bool kvm_pvm_ext_allowed(long ext)
 	case KVM_CAP_ARM_PTRAUTH_GENERIC:
 		return true;
 	default:
-		return false;
+		return !kvm || !kvm_vm_is_protected(kvm);
 	}
 }
 
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 052bf0d4d0b0..e4936cb9c8c3 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -87,7 +87,7 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
 	if (cap->flags)
 		return -EINVAL;
 
-	if (kvm_vm_is_protected(kvm) && !kvm_pvm_ext_allowed(cap->cap))
+	if (is_protected_kvm_enabled() && !kvm_pkvm_ext_allowed(kvm, cap->cap))
 		return -EINVAL;
 
 	switch (cap->cap) {
@@ -299,7 +299,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 {
 	int r;
 
-	if (kvm && kvm_vm_is_protected(kvm) && !kvm_pvm_ext_allowed(ext))
+	if (is_protected_kvm_enabled() && !kvm_pkvm_ext_allowed(kvm, ext))
 		return 0;
 
 	switch (ext) {
diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index 16d7bf493c18..581dec4b8271 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -351,23 +351,23 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
 		return;
 	}
 
-	if (kvm_pvm_ext_allowed(KVM_CAP_ARM_MTE))
+	if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_MTE))
 		kvm->arch.flags |= host_arch_flags & BIT(KVM_ARCH_FLAG_MTE_ENABLED);
 
 	bitmap_zero(allowed_features, KVM_VCPU_MAX_FEATURES);
 
 	set_bit(KVM_ARM_VCPU_PSCI_0_2, allowed_features);
 
-	if (kvm_pvm_ext_allowed(KVM_CAP_ARM_PMU_V3))
+	if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_PMU_V3))
 		set_bit(KVM_ARM_VCPU_PMU_V3, allowed_features);
 
-	if (kvm_pvm_ext_allowed(KVM_CAP_ARM_PTRAUTH_ADDRESS))
+	if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_PTRAUTH_ADDRESS))
 		set_bit(KVM_ARM_VCPU_PTRAUTH_ADDRESS, allowed_features);
 
-	if (kvm_pvm_ext_allowed(KVM_CAP_ARM_PTRAUTH_GENERIC))
+	if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_PTRAUTH_GENERIC))
 		set_bit(KVM_ARM_VCPU_PTRAUTH_GENERIC, allowed_features);
 
-	if (kvm_pvm_ext_allowed(KVM_CAP_ARM_SVE)) {
+	if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_SVE)) {
 		set_bit(KVM_ARM_VCPU_SVE, allowed_features);
 		kvm->arch.flags |= host_arch_flags & BIT(KVM_ARCH_FLAG_GUEST_HAS_SVE);
 	}
-- 
2.52.0.223.gf5cc29aaa4-goog



From tabba at google.com  Thu Dec 11 02:47:06 2025
From: tabba at google.com (Fuad Tabba)
Date: Thu, 11 Dec 2025 10:47:06 +0000
Subject: [PATCH v6 6/9] KVM: arm64: Do not allow KVM_CAP_ARM_MTE for any guest
 in pKVM
In-Reply-To: <20251211104710.151771-1-tabba@google.com>
References: <20251211104710.151771-1-tabba@google.com>
Message-ID: <20251211104710.151771-7-tabba@google.com>

Supporting MTE in pKVM introduces significant complexity to the
hypervisor at EL2, even for non-protected VMs, since it would require
EL2 to handle tag management.

For now, do not allow KVM_CAP_ARM_MTE for any VM type in protected mode.

Signed-off-by: Fuad Tabba <tabba at google.com>
---
 arch/arm64/include/asm/kvm_pkvm.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm_pkvm.h
index 7195be508d99..5b564576160d 100644
--- a/arch/arm64/include/asm/kvm_pkvm.h
+++ b/arch/arm64/include/asm/kvm_pkvm.h
@@ -44,6 +44,8 @@ static inline bool kvm_pkvm_ext_allowed(struct kvm *kvm, long ext)
 	case KVM_CAP_ARM_PTRAUTH_ADDRESS:
 	case KVM_CAP_ARM_PTRAUTH_GENERIC:
 		return true;
+	case KVM_CAP_ARM_MTE:
+		return false;
 	default:
 		return !kvm || !kvm_vm_is_protected(kvm);
 	}
-- 
2.52.0.223.gf5cc29aaa4-goog



From tabba at google.com  Thu Dec 11 02:47:07 2025
From: tabba at google.com (Fuad Tabba)
Date: Thu, 11 Dec 2025 10:47:07 +0000
Subject: [PATCH v6 7/9] KVM: arm64: Track KVM IOCTLs and their associated KVM caps
In-Reply-To: <20251211104710.151771-1-tabba@google.com>
References: <20251211104710.151771-1-tabba@google.com>
Message-ID: <20251211104710.151771-8-tabba@google.com>

Track KVM IOCTLs (VM IOCTLs for now), and the associated KVM capability
that enables that IOCTL. Add a function that performs the lookup.

This will be used by CoCo VM Hypervisors (e.g., pKVM) to determine
whether a particular KVM IOCTL is allowed for its VMs.

Suggested-by: Oliver Upton <oupton at kernel.org>
Signed-off-by: Fuad Tabba <tabba at google.com>
---
 arch/arm64/include/asm/kvm_host.h |  2 ++
 arch/arm64/kvm/arm.c              | 42 +++++++++++++++++++++++++++++++
 include/uapi/linux/kvm.h          |  1 +
 3 files changed, 45 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 64302c438355..9def5e1f536c 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -1652,4 +1652,6 @@ static __always_inline enum fgt_group_id __fgt_reg_to_group_id(enum vcpu_sysreg
 		p;							\
 	})
 
+long kvm_get_cap_for_kvm_ioctl(unsigned int ioctl, long *ext);
+
 #endif /* __ARM64_KVM_HOST_H__ */
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index e4936cb9c8c3..1bbba79e2686 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -58,6 +58,48 @@ enum kvm_wfx_trap_policy {
 static enum kvm_wfx_trap_policy kvm_wfi_trap_policy __read_mostly = KVM_WFX_NOTRAP_SINGLE_TASK;
 static enum kvm_wfx_trap_policy kvm_wfe_trap_policy __read_mostly = KVM_WFX_NOTRAP_SINGLE_TASK;
 
+/*
+ * Tracks KVM IOCTLs and their associated KVM capabilities.
+ */
+struct kvm_ioctl_cap_map {
+	unsigned int ioctl;
+	long ext;
+};
+
+/*
+ * Sorted by ioctl to allow for potential binary search,
+ * though linear scan is sufficient for this size.
+ */
+static const struct kvm_ioctl_cap_map vm_ioctl_caps[] = {
+	{ KVM_CREATE_IRQCHIP, KVM_CAP_IRQCHIP },
+	{ KVM_ARM_SET_DEVICE_ADDR, KVM_CAP_ARM_SET_DEVICE_ADDR },
+	{ KVM_ARM_MTE_COPY_TAGS, KVM_CAP_ARM_MTE },
+	{ KVM_SET_DEVICE_ATTR, KVM_CAP_DEVICE_CTRL },
+	{ KVM_GET_DEVICE_ATTR, KVM_CAP_DEVICE_CTRL },
+	{ KVM_HAS_DEVICE_ATTR, KVM_CAP_DEVICE_CTRL },
+	{ KVM_ARM_SET_COUNTER_OFFSET, KVM_CAP_COUNTER_OFFSET },
+	{ KVM_ARM_GET_REG_WRITABLE_MASKS, KVM_CAP_ARM_SUPPORTED_REG_MASK_RANGES },
+	{ KVM_ARM_PREFERRED_TARGET, KVM_CAP_ARM_BASIC },
+};
+
+/*
+ * Set *ext to the capability.
+ * Return 0 if found, or -EINVAL if no IOCTL matches.
+ */
+long kvm_get_cap_for_kvm_ioctl(unsigned int ioctl, long *ext)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(vm_ioctl_caps); i++) {
+		if (vm_ioctl_caps[i].ioctl == ioctl) {
+			*ext = vm_ioctl_caps[i].ext;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
 DECLARE_KVM_HYP_PER_CPU(unsigned long, kvm_hyp_vector);
 
 DEFINE_PER_CPU(unsigned long, kvm_arm_hyp_stack_base);
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 52f6000ab020..861733b8f159 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -963,6 +963,7 @@ struct kvm_enable_cap {
 #define KVM_CAP_RISCV_MP_STATE_RESET 242
 #define KVM_CAP_ARM_CACHEABLE_PFNMAP_SUPPORTED 243
 #define KVM_CAP_GUEST_MEMFD_FLAGS 244
+#define KVM_CAP_ARM_BASIC 245
 
 struct kvm_irq_routing_irqchip {
 	__u32 irqchip;
-- 
2.52.0.223.gf5cc29aaa4-goog



From tabba at google.com  Thu Dec 11 02:47:08 2025
From: tabba at google.com (Fuad Tabba)
Date: Thu, 11 Dec 2025 10:47:08 +0000
Subject: [PATCH v6 8/9] KVM: arm64: Check whether a VM IOCTL is allowed in pKVM
In-Reply-To: <20251211104710.151771-1-tabba@google.com>
References: <20251211104710.151771-1-tabba@google.com>
Message-ID: <20251211104710.151771-9-tabba@google.com>

Certain VM IOCTLs are tied to specific VM features. Since pKVM does not
support all features, restrict which IOCTLs are allowed depending on
whether the associated feature is supported.

Use the existing VM capability check as the source of truth to whether
an IOCTL is allowed for a particular VM by mapping the IOCTLs with their
associated capabilities.

Suggested-by: Oliver Upton <oupton at kernel.org>
Signed-off-by: Fuad Tabba <tabba at google.com>
---
 arch/arm64/include/asm/kvm_pkvm.h | 21 +++++++++++++++++++++
 arch/arm64/kvm/arm.c              |  3 +++
 2 files changed, 24 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm_pkvm.h
index 5b564576160d..0fa8c84816fd 100644
--- a/arch/arm64/include/asm/kvm_pkvm.h
+++ b/arch/arm64/include/asm/kvm_pkvm.h
@@ -9,6 +9,7 @@
 #include <linux/arm_ffa.h>
 #include <linux/memblock.h>
 #include <linux/scatterlist.h>
+#include <asm/kvm_host.h>
 #include <asm/kvm_pgtable.h>
 
 /* Maximum number of VMs that can co-exist under pKVM. */
@@ -43,6 +44,7 @@ static inline bool kvm_pkvm_ext_allowed(struct kvm *kvm, long ext)
 	case KVM_CAP_ARM_SVE:
 	case KVM_CAP_ARM_PTRAUTH_ADDRESS:
 	case KVM_CAP_ARM_PTRAUTH_GENERIC:
+	case KVM_CAP_ARM_BASIC:
 		return true;
 	case KVM_CAP_ARM_MTE:
 		return false;
@@ -51,6 +53,25 @@ static inline bool kvm_pkvm_ext_allowed(struct kvm *kvm, long ext)
 	}
 }
 
+/*
+ * Check whether the KVM VM IOCTL is allowed in pKVM.
+ *
+ * Certain features are allowed only for non-protected VMs in pKVM, which is why
+ * this takes the VM (kvm) as a parameter.
+ */
+static inline bool kvm_pkvm_ioctl_allowed(struct kvm *kvm, unsigned int ioctl)
+{
+	long ext;
+	int r;
+
+	r = kvm_get_cap_for_kvm_ioctl(ioctl, &ext);
+
+	if (WARN_ON_ONCE(r < 0))
+		return false;
+
+	return kvm_pkvm_ext_allowed(kvm, ext);
+}
+
 extern struct memblock_region kvm_nvhe_sym(hyp_memory)[];
 extern unsigned int kvm_nvhe_sym(hyp_memblock_nr);
 
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 1bbba79e2686..d9a8745d0bd6 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -1921,6 +1921,9 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
 	void __user *argp = (void __user *)arg;
 	struct kvm_device_attr attr;
 
+	if (is_protected_kvm_enabled() && !kvm_pkvm_ioctl_allowed(kvm, ioctl))
+		return -EINVAL;
+
 	switch (ioctl) {
 	case KVM_CREATE_IRQCHIP: {
 		int ret;
-- 
2.52.0.223.gf5cc29aaa4-goog



From tabba at google.com  Thu Dec 11 02:47:09 2025
From: tabba at google.com (Fuad Tabba)
Date: Thu, 11 Dec 2025 10:47:09 +0000
Subject: [PATCH v6 9/9] KVM: arm64: Prevent host from managing timer offsets
 for protected VMs
In-Reply-To: <20251211104710.151771-1-tabba@google.com>
References: <20251211104710.151771-1-tabba@google.com>
Message-ID: <20251211104710.151771-10-tabba@google.com>

For protected VMs, the guest's timer offset state should not be
controlled by the host and must always run with a virtual counter offset
of 0. The existing timer logic allowed the host to set and manage the
timer counter offsets for protected VMs in certain cases.

Disable all host-side management of timer offsets for protected VMs by
adding checks in the relevant code paths.

Signed-off-by: Fuad Tabba <tabba at google.com>
---
 arch/arm64/kvm/arch_timer.c | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c
index 3f675875abea..f5407301c8f9 100644
--- a/arch/arm64/kvm/arch_timer.c
+++ b/arch/arm64/kvm/arch_timer.c
@@ -1056,10 +1056,14 @@ static void timer_context_init(struct kvm_vcpu *vcpu, int timerid)
 
 	ctxt->timer_id = timerid;
 
-	if (timerid == TIMER_VTIMER)
-		ctxt->offset.vm_offset = &kvm->arch.timer_data.voffset;
-	else
-		ctxt->offset.vm_offset = &kvm->arch.timer_data.poffset;
+	if (!kvm_vm_is_protected(vcpu->kvm)) {
+		if (timerid == TIMER_VTIMER)
+			ctxt->offset.vm_offset = &kvm->arch.timer_data.voffset;
+		else
+			ctxt->offset.vm_offset = &kvm->arch.timer_data.poffset;
+	} else {
+		ctxt->offset.vm_offset = NULL;
+	}
 
 	hrtimer_setup(&ctxt->hrtimer, kvm_hrtimer_expire, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_HARD);
 
@@ -1083,7 +1087,8 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
 		timer_context_init(vcpu, i);
 
 	/* Synchronize offsets across timers of a VM if not already provided */
-	if (!test_bit(KVM_ARCH_FLAG_VM_COUNTER_OFFSET, &vcpu->kvm->arch.flags)) {
+	if (!vcpu_is_protected(vcpu) &&
+	    !test_bit(KVM_ARCH_FLAG_VM_COUNTER_OFFSET, &vcpu->kvm->arch.flags)) {
 		timer_set_offset(vcpu_vtimer(vcpu), kvm_phys_timer_read());
 		timer_set_offset(vcpu_ptimer(vcpu), 0);
 	}
@@ -1687,6 +1692,9 @@ int kvm_vm_ioctl_set_counter_offset(struct kvm *kvm,
 	if (offset->reserved)
 		return -EINVAL;
 
+	if (kvm_vm_is_protected(kvm))
+		return -EINVAL;
+
 	mutex_lock(&kvm->lock);
 
 	if (!kvm_trylock_all_vcpus(kvm)) {
-- 
2.52.0.223.gf5cc29aaa4-goog



From robin.murphy at arm.com  Thu Dec 11 03:04:29 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Thu, 11 Dec 2025 11:04:29 +0000
Subject: [PATCH] iommu/io-pgtable-arm: Add misisng concatenated PGD cases
In-Reply-To: <aTonvd9_4hY4-CpS@google.com>
References: <20251130194506.593700-1-smostafa@google.com>
 <18a39079-2285-47fb-b306-040f2bc1bbaa@arm.com> <aTgX9qhaLyrQ5iye@google.com>
 <498bbad4-ea64-4a24-a63f-e131d271990a@arm.com> <aTjCDvtANr2WIv3L@google.com>
 <8e058f60-60da-47c2-9947-2ea26cca1639@arm.com> <aTonvd9_4hY4-CpS@google.com>
Message-ID: <47689561-ed13-4525-825d-60eb8c36ae4c@arm.com>

On 2025-12-11 2:09 am, Will Deacon wrote:
> On Wed, Dec 10, 2025 at 12:06:10PM +0000, Robin Murphy wrote:
>> On 2025-12-10 12:42 am, Will Deacon wrote:
>>> On Tue, Dec 09, 2025 at 01:33:36PM +0000, Robin Murphy wrote:
>>>> On 2025-12-09 12:37 pm, Mostafa Saleh wrote:
>>>>> On Tue, Dec 09, 2025 at 11:34:34AM +0000, Robin Murphy wrote:
>>>>>> On 2025-11-30 7:45 pm, Mostafa Saleh wrote:
>>>>>>> arm_lpae_concat_mandatory() assumes that OAS >= IAS which is not
>>>>>>> correct for SMMUs supporting AArch32, and have OAS = 32/36 bits,
>>>>>>> as IAS would be 40 bits.
>>>>>>
>>>>>> But that is only when *using* AArch32 format. The bit in chapter 3.4 of the
>>>>>> SMMU architecture is talking about the maximum IAS that an SMMU
>>>>>> implementation needs to be able to accommodate based on its configuration,
>>>>>> but it does then attempt to clarify that the actual IPA size in use by any
>>>>>> given context should depend on the VMSA format in use:
>>>>>>
>>>>>> "VMSAv8-32 LPAE always supports an IPA size of 40 bits, whereas VMSAv8-64
>>>>>> and VMSAv9-128 limits the maximum IPA size to the maximum PA size."
>>>>>>
>>>>>> Rule R_SRKBC in the Arm ARM lays out the exact T0SZ constraints with this
>>>>>> AArch32/AArch64 detail.
>>>>>
>>>>> I see, thanks a lot for the explanation, I got confused by the this
>>>>> statement:
>>>>> Note: If AArch32 is implemented, IAS == MAX(40, OAS), otherwise IAS == OAS.
>>>>
>>>> Indeed, that appears confusingly contradictory; I've filed a bug.
>>>
>>> I think the spec has always been worded like this. My reading is that, in
>>> isolation:
>>>
>>>     - VMSAv8-32 LPAE always uses a 40-bit IAS
>>>     - VMSAv8-64 has IAS == OAS and this can be smaller than 40 bits
>>>
>>> so if AArch32 is implemented, we know that the hardware supports at
>>> least a 40-bit IAS and in that case the VMSAv8-64 IAS can be bigger
>>> than the OAS.
>>
>> No, the VMSAv8-64 IAS can never be bigger than OAS, as that would violate
>> VMSA (see rules R_DTLMN and R_SRKBC). The SMMU spec seems mostly fixated on
>> the notional maximum IAS that an SMMU must accommodate in general across all
>> supported formats; the limitations of using any particular format must still
>> apply though (similarly, the fact that AArch32 has a fixed 40-bit output
>> doesn't mean that OAS and S2PS don't still matter for AArch64 format.)
> 
> A VMSAv8-32 stage-1 could still input a 40-bit IAS into a VMSAv8-64
> stage-2 when the OAS < 40-bit though, right? If that's the only case
> where this happens, then I agree we should ditch the complexity from the
> driver on the grounds that we don't ever use the 32-bit formats.

Yes, it is perfectly possible with either format to configure the S1 
*output* size (CD.IPS, or 40 when CD.AA64==0) to be larger than the S2 
input size (STE.S2T0SZ), and if S1 tries to use an IPA beyond the actual 
S2 range then it gets a S2 translation fault, per VMSA rule R_BZHGM.

Cheers,
Robin.


From daniel at makrotopia.org  Thu Dec 11 03:05:35 2025
From: daniel at makrotopia.org (Daniel Golle)
Date: Thu, 11 Dec 2025 11:05:35 +0000
Subject: [PATCH] net: phy: mediatek: fix nvmem cell reference leak in
 mt798x_phy_calibration
In-Reply-To: <20251211081313.2368460-1-linmq006@gmail.com>
References: <20251211081313.2368460-1-linmq006@gmail.com>
Message-ID: <aTqlf6pUC6uMp3bk@makrotopia.org>

On Thu, Dec 11, 2025 at 12:13:13PM +0400, Miaoqian Lin wrote:
> When nvmem_cell_read() fails in mt798x_phy_calibration(), the function
> returns without calling nvmem_cell_put(), leaking the cell reference.
> 
> Move nvmem_cell_put() right after nvmem_cell_read() to ensure the cell
> reference is always released regardless of the read result.
> 
> Found via static analysis and code review.
> 
> Fixes: 98c485eaf509 ("net: phy: add driver for MediaTek SoC built-in GE PHYs")
> Cc: stable at vger.kernel.org
> Signed-off-by: Miaoqian Lin <linmq006 at gmail.com>

Reviewed-by: Daniel Golle <daniel at makrotopia.org>


From chaoyi.chen at rock-chips.com  Thu Dec 11 03:06:38 2025
From: chaoyi.chen at rock-chips.com (Chaoyi Chen)
Date: Thu, 11 Dec 2025 19:06:38 +0800
Subject: [PATCH v2 5/8] drm/rockchip: vop2: Enforce AFBC source alignment
 in plane_check
In-Reply-To: <8655687.NyiUUSuA9g@workhorse>
References: <20251206-vop2-atomic-fixups-v2-0-7fb45bbfbebd@collabora.com>
 <f9f7b446-8575-4f16-aa96-5197b22846e3@rock-chips.com>
 <4696988.LvFx2qVVIh@workhorse> <8655687.NyiUUSuA9g@workhorse>
Message-ID: <fdd333ac-0542-4312-8ec0-22fded3b1ce0@rock-chips.com>

Hello Nicolas,

On 12/9/2025 6:58 PM, Nicolas Frattaroli wrote:
> Hi Chaoyi Chen, Andy Yan,
> 
> On Monday, 8 December 2025 08:24:52 Central European Standard Time Nicolas Frattaroli wrote:
>> On Monday, 8 December 2025 03:48:24 Central European Standard Time Chaoyi Chen wrote:
>>> Hello Nicolas, Daniel,
>>>
>>> On 12/7/2025 4:45 AM, Nicolas Frattaroli wrote:
>>>> From: Daniel Stone <daniels at collabora.com>
>>>>
>>>> Planes can only source AFBC framebuffers at multiples of 4px wide on
>>>> RK3566/RK3568. Instead of clipping on all SoCs when the user asks for an
>>>> unaligned source rectangle, reject the configuration in the plane's
>>>> atomic check on RK3566/RK3568 only.
>>>>
>>>> Signed-off-by: Daniel Stone <daniels at collabora.com>
>>>> [Make RK3566/RK3568 specific, reword message]
>>>> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
>>>> ---
>>>>  drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 14 +++++++++-----
>>>>  1 file changed, 9 insertions(+), 5 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
>>>> index bc1ed0ffede0..e23213337104 100644
>>>> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
>>>> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
>>>> @@ -1076,6 +1076,13 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
>>>>  		return -EINVAL;
>>>>  	}
>>>>  
>>>> +	if (vop2->version == VOP_VERSION_RK3568 && drm_is_afbc(fb->modifier) && src_w % 4) {
>>>> +		drm_dbg_kms(vop2->drm,
>>>> +			    "AFBC source rectangles must be 4-byte aligned; is %d\n",
>>>> +			    src_w);
>>>> +		return -EINVAL;
>>>> +	}
>>>> +
>>>>  	return 0;
>>>>  }
>>>>  
>>>> @@ -1237,11 +1244,8 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
>>>>  	WARN_ON(src_w < 4);
>>>>  	WARN_ON(src_h < 4);
>>>>  
>>>> -	if (afbc_en && src_w % 4) {
>>>> -		drm_dbg_kms(vop2->drm, "vp%d %s src_w[%d] not 4 pixel aligned\n",
>>>> -			    vp->id, win->data->name, src_w);
>>>> -		src_w = ALIGN_DOWN(src_w, 4);
>>>> -	}
>>>> +	if (vop2->version == VOP_VERSION_RK3568 && drm_is_afbc(fb->modifier))
>>>> +		WARN_ON(src_w % 4);
>>>>  
>>>>  	act_info = (src_h - 1) << 16 | ((src_w - 1) & 0xffff);
>>>>  	dsp_info = (dsp_h - 1) << 16 | ((dsp_w - 1) & 0xffff);
>>>>
>>>
>>> You haven't replied to Andy's comment yet [0].
>>>
>>> [0] https://lore.kernel.org/dri-devel/7b4e26ec.75f3.19a77276b53.Coremail.andyshrk at 163.com/
>>>
>>
>> Hello,
>>
>> I addressed the follow-ups where it was clarified that the 4 pixel
>> limitation was RK3566/RK3568-only. I'm not going to bring back the
>> post-atomic_check modification for a fast path, but I'm open to
>> suggestions on how to do this differently.
>>
>> One solution might be to modify the state with the ALIGN_DOWN stuff
>> in atomic_check instead, where userspace is then aware of the change
>> being done to its requested parameters. I'll need to double-check
>> whether this is in line with atomic modesetting's design.
>>
>> Kind regards,
>> Nicolas Frattaroli
> 
> Okay, so I've asked internally, and atomic_check isn't allowed to
> modify any of the parameters either. There's efforts [0] underway
> to allow error codes to be more specific, so that userspace knows
> which constraint is being violated. That would allow userspace
> applications to react by either adjusting their size or turning
> off AFBC in this case. Turning off AFBC seems more generally
> applicable here, since it means it won't need to resize the plane
> and it'll save more than enough memory bandwidth by not going
> through the GPU.
> 
> On that note: Andy, I didn't find a weston-simple-egl test in the
> Weston 14.0.2 or git test suite, and weston-simple-egl itself does
> not tell me whether GPU compositing is being used or not. Do you
> have more information on how to test for this? I'd like to know
> for when we have the necessary functionality in place to make
> userspace smart enough to pick the fast path again.
> 

I think weston-simple-egl is part of the weston client. When you build
weston from source, you should obtain it. Just run `weston-simple-egl` 
after compile and install weston.

And I guess you're using Debian... The weston package there also ships
with a weston-simple-egl binary [2].

[1]: https://gitlab.freedesktop.org/wayland/weston/-/blob/main/clients/simple-egl.c
[2]: https://packages.debian.org/sid/arm64/weston/filelist

> In either case, I think adhering to the atomic API to ensure
> artifact-free presentation is more important here than enabling
> a fast-path on RK3568. I do think in most real-world use case
> scenarios, the fallback won't degrade user experience, because
> almost everything performance intensive I can think of (video
> playback, games) will likely already use a plane geometry
> where the width is divisible by 4. 800, 1024, 1280, 1600, 1920,
> 2560, 3840 are all divisible by 4, so a window or full-screen
> playback of common content won't need to fall back to GPU
> compositing.
> 
> I'll send a v2 to fix another instance of "eSmart" left in a
> message, but beyond that I think we should be good.
> 
> Kind regards,
> Nicolas Frattaroli
> 
> https://lore.kernel.org/dri-devel/20251009-atomic-v6-0-d209709cc3ba at intel.com/ [0]
> 
> 
> 
> 

-- 
Best, 
Chaoyi


From ben.horgan at arm.com  Thu Dec 11 03:23:29 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Thu, 11 Dec 2025 11:23:29 +0000
Subject: [RFC PATCH 02/38] arm64: mpam: Re-initialise MPAM regs when CPU
 comes online
In-Reply-To: <0ea282be-c44f-4562-9104-1efe57348a3e@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-3-james.morse@arm.com>
 <0ea282be-c44f-4562-9104-1efe57348a3e@arm.com>
Message-ID: <b922ff73-c583-482e-8925-ad7758280705@arm.com>

Hi James,

On 12/9/25 15:13, Ben Horgan wrote:
> Hi James,
> 
> On 12/5/25 21:58, James Morse wrote:
>> Now that the MPAM system registers are expected to have values that change,
>> reprogram them based on struct task_struct when a CPU is brought online.
>>
>> Previously MPAM's 'default PARTID' of 0 was used this is the PARTID that
>> hardware guarantees to reset. Because there are a limited number of
>> PARTID, this value is exposed to user space, meaning resctrl changes
>> to the resctrl default group would also affect kernel threads.
>> Instead, use the task's PARTID value for kernel work on behalf of
>> user-space too.
>>
>> Signed-off-by: James Morse <james.morse at arm.com>
>> ---
>>  arch/arm64/kernel/cpufeature.c | 18 +++++++++++-------
>>  1 file changed, 11 insertions(+), 7 deletions(-)
>>
>> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
>> index 5ed401ff79e3..429128a181ac 100644
>> --- a/arch/arm64/kernel/cpufeature.c
>> +++ b/arch/arm64/kernel/cpufeature.c
>> @@ -86,6 +86,7 @@
>>  #include <asm/kvm_host.h>
>>  #include <asm/mmu.h>
>>  #include <asm/mmu_context.h>
>> +#include <asm/mpam.h>
>>  #include <asm/mte.h>
>>  #include <asm/hypervisor.h>
>>  #include <asm/processor.h>
>> @@ -2439,13 +2440,16 @@ test_has_mpam(const struct arm64_cpu_capabilities *entry, int scope)
>>  static void
>>  cpu_enable_mpam(const struct arm64_cpu_capabilities *entry)
>>  {
>> -	/*
>> -	 * Access by the kernel (at EL1) should use the reserved PARTID
>> -	 * which is configured unrestricted. This avoids priority-inversion
>> -	 * where latency sensitive tasks have to wait for a task that has
>> -	 * been throttled to release the lock.
>> -	 */
>> -	write_sysreg_s(0, SYS_MPAM1_EL1);
>> +	int cpu = smp_processor_id();
>> +	u64 regval = 0;
>> +
>> +	if (IS_ENABLED(CONFIG_MPAM))
>> +		regval = READ_ONCE(per_cpu(arm64_mpam_current, cpu));
> 
> CONFIG_MPAM -> CONFIG_ARM64_MPAM

Actually, this code is only run before the mpam enablement is finished,
importantly before the mpam_enabled static key is set, and so
arm64_mpam_current is still 0 for every cpu. For cpus that are brought
up after boot time this is never run.

As SYS_MPAM0_EL1 and SYS_MPAM1_EL1 are unknown out of reset we should
set them to 0 whenever a cpu comes online to make sure they initially
use PARTID 0 as that is the only one guaranteed to have sensible
defaults in the MSC. Once the mpam driver has configured the MSC we can
start setting other values.

> 
>> +
>> +	write_sysreg_s(regval, SYS_MPAM1_EL1);
>> +	isb();
>> +
>> +	write_sysreg_s(regval, SYS_MPAM0_EL1);
>>  }
>>  
>>  static bool
> 
> Thanks,
> 
> Ben
> 
> 

Thanks,

Ben



From ulf.hansson at linaro.org  Thu Dec 11 03:31:38 2025
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Thu, 11 Dec 2025 12:31:38 +0100
Subject: [PATCH RFC 06/16] dt-bindings: mmc: Switch ref to sdhci-common.yaml
In-Reply-To: <20251211-dev-dt-warnings-all-v1-6-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
 <20251211-dev-dt-warnings-all-v1-6-21b18b9ada77@codeconstruct.com.au>
Message-ID: <CAPDyKFrbS_3XRTSuexFxTpP1ydgvfFvXNv_tninnTqum7+92ZA@mail.gmail.com>

On Thu, 11 Dec 2025 at 09:47, Andrew Jeffery
<andrew at codeconstruct.com.au> wrote:
>
> Enable use of common SDHCI-related properties such as sdhci-caps-mask as
> found in the AST2600 EVB DTS.
>
> Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>

Applied for fixes and by adding a stable-tag, thanks!

Kind regards
Uffe


> ---
>  Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml b/Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml
> index 9fce8cd7b0b6..d24950ccea95 100644
> --- a/Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml
> +++ b/Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml
> @@ -41,7 +41,7 @@ properties:
>  patternProperties:
>    "^sdhci@[0-9a-f]+$":
>      type: object
> -    $ref: mmc-controller.yaml
> +    $ref: sdhci-common.yaml
>      unevaluatedProperties: false
>
>      properties:
>
> --
> 2.47.3
>
>


From ulf.hansson at linaro.org  Thu Dec 11 03:31:45 2025
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Thu, 11 Dec 2025 12:31:45 +0100
Subject: [PATCH RFC 07/16] ARM: dts: aspeed: Remove sdhci-drive-type
 property from AST2600 EVB
In-Reply-To: <20251211-dev-dt-warnings-all-v1-7-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
 <20251211-dev-dt-warnings-all-v1-7-21b18b9ada77@codeconstruct.com.au>
Message-ID: <CAPDyKFqZQUurBNSNUBKE7rgBf+UHxKiYBWt+xxSY+dh7PgdPPQ@mail.gmail.com>

On Thu, 11 Dec 2025 at 09:47, Andrew Jeffery
<andrew at codeconstruct.com.au> wrote:
>
> The property isn't specified in the bindings and is not used by the
> corresponding driver, so drop it.
>
> Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>

FWIW:

Reviewed-by: Ulf Hansson <ulf.hansson at linaro.org>


> ---
>  arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts | 2 --
>  1 file changed, 2 deletions(-)
>
> diff --git a/arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts b/arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts
> index de83c0eb1d6e..3eba676e57f1 100644
> --- a/arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts
> +++ b/arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts
> @@ -314,7 +314,6 @@ &sdhci0 {
>         status = "okay";
>         bus-width = <4>;
>         max-frequency = <100000000>;
> -       sdhci-drive-type = /bits/ 8 <3>;
>         sdhci-caps-mask = <0x7 0x0>;
>         sdhci,wp-inverted;
>         vmmc-supply = <&vcc_sdhci0>;
> @@ -326,7 +325,6 @@ &sdhci1 {
>         status = "okay";
>         bus-width = <4>;
>         max-frequency = <100000000>;
> -       sdhci-drive-type = /bits/ 8 <3>;
>         sdhci-caps-mask = <0x7 0x0>;
>         sdhci,wp-inverted;
>         vmmc-supply = <&vcc_sdhci1>;
>
> --
> 2.47.3
>
>


From ulf.hansson at linaro.org  Thu Dec 11 03:31:50 2025
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Thu, 11 Dec 2025 12:31:50 +0100
Subject: [PATCH RFC 08/16] ARM: dts: aspeed: Use specified wp-inverted
 property for AST2600 EVB
In-Reply-To: <20251211-dev-dt-warnings-all-v1-8-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
 <20251211-dev-dt-warnings-all-v1-8-21b18b9ada77@codeconstruct.com.au>
Message-ID: <CAPDyKFpQXYFFrZ-unVxa9m2+tKLEyFZyo7Tv7JD_7vTbqqfmDQ@mail.gmail.com>

On Thu, 11 Dec 2025 at 09:47, Andrew Jeffery
<andrew at codeconstruct.com.au> wrote:
>
> While sdhci-pltfm supports sdhci,wp-inverted, it also supports
> the un-prefixed and specified wp-inverted property. Switch the EVB
> devicetree to use the specified property to remove warnings when
> checking the DTB.
>
> Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>

FWIW:

Reviewed-by: Ulf Hansson <ulf.hansson at linaro.org>


> ---
>  arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts b/arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts
> index 3eba676e57f1..c51977dcb56b 100644
> --- a/arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts
> +++ b/arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts
> @@ -315,7 +315,7 @@ &sdhci0 {
>         bus-width = <4>;
>         max-frequency = <100000000>;
>         sdhci-caps-mask = <0x7 0x0>;
> -       sdhci,wp-inverted;
> +       wp-inverted;
>         vmmc-supply = <&vcc_sdhci0>;
>         vqmmc-supply = <&vccq_sdhci0>;
>         clk-phase-sd-hs = <7>, <200>;
> @@ -326,7 +326,7 @@ &sdhci1 {
>         bus-width = <4>;
>         max-frequency = <100000000>;
>         sdhci-caps-mask = <0x7 0x0>;
> -       sdhci,wp-inverted;
> +       wp-inverted;
>         vmmc-supply = <&vcc_sdhci1>;
>         vqmmc-supply = <&vccq_sdhci1>;
>         clk-phase-sd-hs = <7>, <200>;
>
> --
> 2.47.3
>
>


From ben.horgan at arm.com  Thu Dec 11 03:32:47 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Thu, 11 Dec 2025 11:32:47 +0000
Subject: [RFC PATCH 02/38] arm64: mpam: Re-initialise MPAM regs when CPU
 comes online
In-Reply-To: <b922ff73-c583-482e-8925-ad7758280705@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-3-james.morse@arm.com>
 <0ea282be-c44f-4562-9104-1efe57348a3e@arm.com>
 <b922ff73-c583-482e-8925-ad7758280705@arm.com>
Message-ID: <b798402a-1bc4-4765-aff6-6e3c3a398987@arm.com>

Retraction... sorry

On 12/11/25 11:23, Ben Horgan wrote:
> Hi James,
> 
> On 12/9/25 15:13, Ben Horgan wrote:
>> Hi James,
>>
>> On 12/5/25 21:58, James Morse wrote:

> 
> Actually, this code is only run before the mpam enablement is finished,
> importantly before the mpam_enabled static key is set, and so
> arm64_mpam_current is still 0 for every cpu. For cpus that are brought
> up after boot time this is never run.

Actually, actually, this is run whenever a cpu comes online, even if by
hotplug later, and so arm64_mpam_current will be 0 as need on the first
switch on and the previous value for the cpu when it has previously been
off.

> 
> As SYS_MPAM0_EL1 and SYS_MPAM1_EL1 are unknown out of reset we should
> set them to 0 whenever a cpu comes online to make sure they initially
> use PARTID 0 as that is the only one guaranteed to have sensible
> defaults in the MSC. Once the mpam driver has configured the MSC we can
> start setting other values.
> 
>>
>>> +
>>> +	write_sysreg_s(regval, SYS_MPAM1_EL1);
>>> +	isb();
>>> +
>>> +	write_sysreg_s(regval, SYS_MPAM0_EL1);
>>>  }
>>>  
>>>  static bool
>>
>> Thanks,
>>
>> Ben
>>
>>
> 
> Thanks,
> 
> Ben
> 
> 

-- 
Thanks,

Ben



From tabba at google.com  Thu Dec 11 03:38:23 2025
From: tabba at google.com (Fuad Tabba)
Date: Thu, 11 Dec 2025 11:38:23 +0000
Subject: [PATCH v2 0/5] KVM: arm64: Enforce MTE disablement at EL2
Message-ID: <20251211113828.370370-1-tabba@google.com>

pKVM never exposes MTE to protected guests (pVM), but we must also
ensure a malicious host cannot use MTE to attack the hypervisor or a
pVM.

If MTE is supported by the hardware (and is enabled at EL3), it remains
available to lower exception levels by default. Disabling it in the host
kernel (e.g., via 'arm64.nomte') only stops the kernel from advertising
the feature; it does not physically disable MTE in the hardware.

The ability to disable MTE in the host kernel is used by some systems,
such as Android, so that the physical memory otherwise used as tag
storage can be used for other things (i.e. treated just like the rest of
memory).

In this scenario, a malicious host could still access tags in pages
donated to a guest using MTE instructions (e.g., STG and LDG), bypassing
the kernel's configuration.

To prevent this, explicitly disable MTE at EL2 (by clearing HCR_EL2.ATA)
when the host has MTE disabled. This causes any MTE instruction usage to
generate a Data Abort (trap) to the hypervisor.

Additionally, to faithfully mimic hardware that does not support MTE,
trap accesses to MTE system registers (e.g., GCR_EL1) and inject an
Undefined Instruction exception back to the host.

This logic is applied in all non-VHE modes. For non-protected modes,
this remains beneficial as it prevents unpredictable behavior caused by
accessing allocation tags when the system considers them disabled.

Note that this ties into my other outgoing patch series [1], which also
has some MTE-related fixes, but is not dependent on it.

Based on Linux 6.18

Cheers,
/fuad

[1] https://lore.kernel.org/all/20251211104710.151771-1-tabba at google.com/
[2] https://lore.kernel.org/all/20251127122210.4111702-1-tabba at google.com/

Fuad Tabba (4):
  arm64: Remove dead code resetting HCR_EL2 for pKVM
  arm64: Clear HCR_EL2.ATA when MTE is not supported or disabled
  arm64: Inject UNDEF when accessing MTE sysregs with MTE disabled
  KVM: arm64: Use kvm_has_mte() in pKVM trap initialization

Quentin Perret (1):
  KVM: arm64: Refactor enter_exception64()

 arch/arm64/include/asm/kvm_arm.h     |   2 +-
 arch/arm64/include/asm/kvm_emulate.h |   5 ++
 arch/arm64/kernel/head.S             |   2 +-
 arch/arm64/kvm/arm.c                 |   4 ++
 arch/arm64/kvm/hyp/exception.c       | 100 ++++++++++++++++-----------
 arch/arm64/kvm/hyp/nvhe/hyp-init.S   |   5 --
 arch/arm64/kvm/hyp/nvhe/hyp-main.c   |  44 ++++++++++++
 arch/arm64/kvm/hyp/nvhe/pkvm.c       |   2 +-
 8 files changed, 114 insertions(+), 50 deletions(-)


base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
-- 
2.52.0.223.gf5cc29aaa4-goog



From tabba at google.com  Thu Dec 11 03:38:24 2025
From: tabba at google.com (Fuad Tabba)
Date: Thu, 11 Dec 2025 11:38:24 +0000
Subject: [PATCH v2 1/5] arm64: Remove dead code resetting HCR_EL2 for pKVM
In-Reply-To: <20251211113828.370370-1-tabba@google.com>
References: <20251211113828.370370-1-tabba@google.com>
Message-ID: <20251211113828.370370-2-tabba@google.com>

The pKVM lifecycle does not support tearing down the hypervisor and
returning to the hyp stub once initialized. The transition to protected
mode is one-way.

Consequently, the code path in hyp-init.S responsible for resetting
EL2 registers (triggered by kexec or hibernation) is unreachable in
protected mode.

Remove the dead code handling HCR_EL2 reset for
ARM64_KVM_PROTECTED_MODE.

No functional change intended.

Signed-off-by: Fuad Tabba <tabba at google.com>
---
 arch/arm64/kvm/hyp/nvhe/hyp-init.S | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-init.S b/arch/arm64/kvm/hyp/nvhe/hyp-init.S
index aada42522e7b..0d42eedc7167 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-init.S
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-init.S
@@ -260,11 +260,6 @@ reset:
 	msr	sctlr_el2, x5
 	isb
 
-alternative_if ARM64_KVM_PROTECTED_MODE
-	mov_q	x5, HCR_HOST_NVHE_FLAGS
-	msr_hcr_el2 x5
-alternative_else_nop_endif
-
 	/* Install stub vectors */
 	adr_l	x5, __hyp_stub_vectors
 	msr	vbar_el2, x5
-- 
2.52.0.223.gf5cc29aaa4-goog



From tabba at google.com  Thu Dec 11 03:38:25 2025
From: tabba at google.com (Fuad Tabba)
Date: Thu, 11 Dec 2025 11:38:25 +0000
Subject: [PATCH v2 2/5] arm64: Clear HCR_EL2.ATA when MTE is not supported or disabled
In-Reply-To: <20251211113828.370370-1-tabba@google.com>
References: <20251211113828.370370-1-tabba@google.com>
Message-ID: <20251211113828.370370-3-tabba@google.com>

If MTE is not supported by the hardware, or is disabled in the kernel
configuration (CONFIG_ARM64_MTE=n) or command line (arm64.nomte), the
kernel stops advertising MTE to userspace and avoids using MTE
instructions. However, this is a software-level disable only.

When MTE hardware is present and enabled by EL3 firmware, leaving
HCR_EL2.ATA set allows the host to execute MTE instructions (STG, LDG,
etc.) and access allocation tags in physical memory. This creates a
security risk where a malicious or buggy host could lead to system
crashes, undefined behavior, or compromise guests.

Prevent this by clearing HCR_EL2.ATA when MTE is disabled. Remove it
from the HCR_HOST_NVHE_FLAGS default, and conditionally set it in
cpu_prepare_hyp_mode() only when system_supports_mte() returns true.
This causes MTE instructions to trap to EL2 when HCR_EL2.ATA is cleared.

Early boot code in head.S temporarily keeps HCR_ATA set to avoid
special-casing initialization paths. This is safe because this code
executes before untrusted code runs and will clear HCR_ATA if MTE is
disabled.

Signed-off-by: Fuad Tabba <tabba at google.com>
---
 arch/arm64/include/asm/kvm_arm.h | 2 +-
 arch/arm64/kernel/head.S         | 2 +-
 arch/arm64/kvm/arm.c             | 4 ++++
 3 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 1da290aeedce..a41e3087e00a 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -101,7 +101,7 @@
 			 HCR_BSU_IS | HCR_FB | HCR_TACR | \
 			 HCR_AMO | HCR_SWIO | HCR_TIDCP | HCR_RW | HCR_TLOR | \
 			 HCR_FMO | HCR_IMO | HCR_PTW | HCR_TID3 | HCR_TID1)
-#define HCR_HOST_NVHE_FLAGS (HCR_RW | HCR_API | HCR_APK | HCR_ATA)
+#define HCR_HOST_NVHE_FLAGS (HCR_RW | HCR_API | HCR_APK)
 #define HCR_HOST_NVHE_PROTECTED_FLAGS (HCR_HOST_NVHE_FLAGS | HCR_TSC)
 #define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H | HCR_AMO | HCR_IMO | HCR_FMO)
 
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index ca04b338cb0d..87a822e5c4ca 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -299,7 +299,7 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
 	isb
 0:
 
-	init_el2_hcr	HCR_HOST_NVHE_FLAGS
+	init_el2_hcr	HCR_HOST_NVHE_FLAGS | HCR_ATA
 	init_el2_state
 
 	/* Hypervisor stub */
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 052bf0d4d0b0..c03006b1c5bc 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -2030,6 +2030,10 @@ static void __init cpu_prepare_hyp_mode(int cpu, u32 hyp_va_bits)
 		params->hcr_el2 = HCR_HOST_NVHE_PROTECTED_FLAGS;
 	else
 		params->hcr_el2 = HCR_HOST_NVHE_FLAGS;
+
+	if (system_supports_mte())
+		params->hcr_el2 |= HCR_ATA;
+
 	if (cpus_have_final_cap(ARM64_KVM_HVHE))
 		params->hcr_el2 |= HCR_E2H;
 	params->vttbr = params->vtcr = 0;
-- 
2.52.0.223.gf5cc29aaa4-goog



From tabba at google.com  Thu Dec 11 03:38:26 2025
From: tabba at google.com (Fuad Tabba)
Date: Thu, 11 Dec 2025 11:38:26 +0000
Subject: [PATCH v2 3/5] KVM: arm64: Refactor enter_exception64()
In-Reply-To: <20251211113828.370370-1-tabba@google.com>
References: <20251211113828.370370-1-tabba@google.com>
Message-ID: <20251211113828.370370-4-tabba@google.com>

From: Quentin Perret <qperret at google.com>

To simplify the injection of exceptions into the host in pKVM context,
refactor enter_exception64() to split out the logic for calculating the
exception vector offset and the target CPSR.

Extract two new helper functions:
 - get_except64_offset(): Calculates exception vector offset based on
   current/target exception levels and exception type
 - get_except64_cpsr(): Computes the new CPSR/PSTATE when taking an
   exception

A subsequent patch will use these helpers to inject UNDEF exceptions
into the host when MTE system registers are accessed with MTE disabled.
Extracting the helpers allows that code to reuse the exception entry
logic without duplicating the CPSR and vector offset calculations.

No functional change intended.

Signed-off-by: Quentin Perret <qperret at google.com>
Signed-off-by: Fuad Tabba <tabba at google.com>
---
 arch/arm64/include/asm/kvm_emulate.h |   5 ++
 arch/arm64/kvm/hyp/exception.c       | 100 ++++++++++++++++-----------
 2 files changed, 63 insertions(+), 42 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index c9eab316398e..c3f04bd5b2a5 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -71,6 +71,11 @@ static inline int kvm_inject_serror(struct kvm_vcpu *vcpu)
 	return kvm_inject_serror_esr(vcpu, ESR_ELx_ISV);
 }
 
+unsigned long get_except64_offset(unsigned long psr, unsigned long target_mode,
+				  enum exception_type type);
+unsigned long get_except64_cpsr(unsigned long old, bool has_mte,
+				unsigned long sctlr, unsigned long mode);
+
 void kvm_vcpu_wfi(struct kvm_vcpu *vcpu);
 
 void kvm_emulate_nested_eret(struct kvm_vcpu *vcpu);
diff --git a/arch/arm64/kvm/hyp/exception.c b/arch/arm64/kvm/hyp/exception.c
index bef40ddb16db..d3bcda665612 100644
--- a/arch/arm64/kvm/hyp/exception.c
+++ b/arch/arm64/kvm/hyp/exception.c
@@ -65,12 +65,25 @@ static void __vcpu_write_spsr_und(struct kvm_vcpu *vcpu, u64 val)
 		vcpu->arch.ctxt.spsr_und = val;
 }
 
+unsigned long get_except64_offset(unsigned long psr, unsigned long target_mode,
+				  enum exception_type type)
+{
+	u64 mode = psr & (PSR_MODE_MASK | PSR_MODE32_BIT);
+	u64 exc_offset;
+
+	if      (mode == target_mode)
+		exc_offset = CURRENT_EL_SP_ELx_VECTOR;
+	else if ((mode | PSR_MODE_THREAD_BIT) == target_mode)
+		exc_offset = CURRENT_EL_SP_EL0_VECTOR;
+	else if (!(mode & PSR_MODE32_BIT))
+		exc_offset = LOWER_EL_AArch64_VECTOR;
+	else
+		exc_offset = LOWER_EL_AArch32_VECTOR;
+
+	return exc_offset + type;
+}
+
 /*
- * This performs the exception entry at a given EL (@target_mode), stashing PC
- * and PSTATE into ELR and SPSR respectively, and compute the new PC/PSTATE.
- * The EL passed to this function *must* be a non-secure, privileged mode with
- * bit 0 being set (PSTATE.SP == 1).
- *
  * When an exception is taken, most PSTATE fields are left unchanged in the
  * handler. However, some are explicitly overridden (e.g. M[4:0]). Luckily all
  * of the inherited bits have the same position in the AArch64/AArch32 SPSR_ELx
@@ -82,50 +95,17 @@ static void __vcpu_write_spsr_und(struct kvm_vcpu *vcpu, u64 val)
  * Here we manipulate the fields in order of the AArch64 SPSR_ELx layout, from
  * MSB to LSB.
  */
-static void enter_exception64(struct kvm_vcpu *vcpu, unsigned long target_mode,
-			      enum exception_type type)
+unsigned long get_except64_cpsr(unsigned long old, bool has_mte,
+				unsigned long sctlr, unsigned long target_mode)
 {
-	unsigned long sctlr, vbar, old, new, mode;
-	u64 exc_offset;
-
-	mode = *vcpu_cpsr(vcpu) & (PSR_MODE_MASK | PSR_MODE32_BIT);
-
-	if      (mode == target_mode)
-		exc_offset = CURRENT_EL_SP_ELx_VECTOR;
-	else if ((mode | PSR_MODE_THREAD_BIT) == target_mode)
-		exc_offset = CURRENT_EL_SP_EL0_VECTOR;
-	else if (!(mode & PSR_MODE32_BIT))
-		exc_offset = LOWER_EL_AArch64_VECTOR;
-	else
-		exc_offset = LOWER_EL_AArch32_VECTOR;
-
-	switch (target_mode) {
-	case PSR_MODE_EL1h:
-		vbar = __vcpu_read_sys_reg(vcpu, VBAR_EL1);
-		sctlr = __vcpu_read_sys_reg(vcpu, SCTLR_EL1);
-		__vcpu_write_sys_reg(vcpu, *vcpu_pc(vcpu), ELR_EL1);
-		break;
-	case PSR_MODE_EL2h:
-		vbar = __vcpu_read_sys_reg(vcpu, VBAR_EL2);
-		sctlr = __vcpu_read_sys_reg(vcpu, SCTLR_EL2);
-		__vcpu_write_sys_reg(vcpu, *vcpu_pc(vcpu), ELR_EL2);
-		break;
-	default:
-		/* Don't do that */
-		BUG();
-	}
-
-	*vcpu_pc(vcpu) = vbar + exc_offset + type;
-
-	old = *vcpu_cpsr(vcpu);
-	new = 0;
+	u64 new = 0;
 
 	new |= (old & PSR_N_BIT);
 	new |= (old & PSR_Z_BIT);
 	new |= (old & PSR_C_BIT);
 	new |= (old & PSR_V_BIT);
 
-	if (kvm_has_mte(kern_hyp_va(vcpu->kvm)))
+	if (has_mte)
 		new |= PSR_TCO_BIT;
 
 	new |= (old & PSR_DIT_BIT);
@@ -161,6 +141,42 @@ static void enter_exception64(struct kvm_vcpu *vcpu, unsigned long target_mode,
 
 	new |= target_mode;
 
+	return new;
+}
+
+/*
+ * This performs the exception entry at a given EL (@target_mode), stashing PC
+ * and PSTATE into ELR and SPSR respectively, and compute the new PC/PSTATE.
+ * The EL passed to this function *must* be a non-secure, privileged mode with
+ * bit 0 being set (PSTATE.SP == 1).
+ */
+static void enter_exception64(struct kvm_vcpu *vcpu, unsigned long target_mode,
+			      enum exception_type type)
+{
+	u64 offset = get_except64_offset(*vcpu_cpsr(vcpu), target_mode, type);
+	unsigned long sctlr, vbar, old, new;
+
+	switch (target_mode) {
+	case PSR_MODE_EL1h:
+		vbar = __vcpu_read_sys_reg(vcpu, VBAR_EL1);
+		sctlr = __vcpu_read_sys_reg(vcpu, SCTLR_EL1);
+		__vcpu_write_sys_reg(vcpu, *vcpu_pc(vcpu), ELR_EL1);
+		break;
+	case PSR_MODE_EL2h:
+		vbar = __vcpu_read_sys_reg(vcpu, VBAR_EL2);
+		sctlr = __vcpu_read_sys_reg(vcpu, SCTLR_EL2);
+		__vcpu_write_sys_reg(vcpu, *vcpu_pc(vcpu), ELR_EL2);
+		break;
+	default:
+		/* Don't do that */
+		BUG();
+	}
+
+	*vcpu_pc(vcpu) = vbar + offset;
+
+	old = *vcpu_cpsr(vcpu);
+	new = get_except64_cpsr(old, kvm_has_mte(kern_hyp_va(vcpu->kvm)), sctlr,
+				target_mode);
 	*vcpu_cpsr(vcpu) = new;
 	__vcpu_write_spsr(vcpu, target_mode, old);
 }
-- 
2.52.0.223.gf5cc29aaa4-goog



From tabba at google.com  Thu Dec 11 03:38:27 2025
From: tabba at google.com (Fuad Tabba)
Date: Thu, 11 Dec 2025 11:38:27 +0000
Subject: [PATCH v2 4/5] arm64: Inject UNDEF when accessing MTE sysregs with
 MTE disabled
In-Reply-To: <20251211113828.370370-1-tabba@google.com>
References: <20251211113828.370370-1-tabba@google.com>
Message-ID: <20251211113828.370370-5-tabba@google.com>

When MTE hardware is present but disabled via software (arm64.nomte or
CONFIG_ARM64_MTE=n), HCR_EL2.ATA is cleared to prevent use of MTE
instructions. However, this alone doesn't fully emulate hardware that
lacks MTE support.

With HCR_EL2.ATA cleared, accesses to certain MTE system registers trap
to EL2 with exception class ESR_ELx_EC_SYS64. To faithfully emulate
hardware without MTE (where such accesses would cause an Undefined
Instruction exception), inject UNDEF into the host.

The ability to disable MTE in the host kernel is used by some systems,
such as Android, so that the physical memory otherwise used as tag
storage can be used for other things (i.e. treated just like the rest of
memory).

Signed-off-by: Fuad Tabba <tabba at google.com>
---
 arch/arm64/kvm/hyp/nvhe/hyp-main.c | 44 ++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 29430c031095..f542e4c17156 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -686,6 +686,46 @@ static void handle_host_smc(struct kvm_cpu_context *host_ctxt)
 	kvm_skip_host_instr();
 }
 
+static void inject_undef64(void)
+{
+	unsigned long sctlr, vbar, old, new;
+	u64 offset, esr;
+
+	vbar = read_sysreg_el1(SYS_VBAR);
+	sctlr = read_sysreg_el1(SYS_SCTLR);
+	old = read_sysreg_el2(SYS_SPSR);
+	new = get_except64_cpsr(old, system_supports_mte(), sctlr, PSR_MODE_EL1h);
+	offset = get_except64_offset(old, PSR_MODE_EL1h, except_type_sync);
+	esr = (ESR_ELx_EC_UNKNOWN << ESR_ELx_EC_SHIFT) | ESR_ELx_IL;
+
+	write_sysreg_el1(esr, SYS_ESR);
+	write_sysreg_el1(read_sysreg_el2(SYS_ELR), SYS_ELR);
+	write_sysreg_el1(old, SYS_SPSR);
+	write_sysreg_el2(vbar + offset, SYS_ELR);
+	write_sysreg_el2(new, SYS_SPSR);
+}
+
+static bool handle_host_mte(u64 esr)
+{
+	/* If we're here for any reason other than MTE, then it's a bug. */
+
+	if (read_sysreg(HCR_EL2) & HCR_ATA)
+		return false;
+
+	switch (esr_sys64_to_sysreg(esr)) {
+	case SYS_RGSR_EL1:
+	case SYS_GCR_EL1:
+	case SYS_TFSR_EL1:
+	case SYS_TFSRE0_EL1:
+		break;
+	default:
+		return false;
+	}
+
+	inject_undef64();
+	return true;
+}
+
 void handle_trap(struct kvm_cpu_context *host_ctxt)
 {
 	u64 esr = read_sysreg_el2(SYS_ESR);
@@ -701,6 +741,10 @@ void handle_trap(struct kvm_cpu_context *host_ctxt)
 	case ESR_ELx_EC_DABT_LOW:
 		handle_host_mem_abort(host_ctxt);
 		break;
+	case ESR_ELx_EC_SYS64:
+		if (handle_host_mte(esr))
+			break;
+		fallthrough;
 	default:
 		BUG();
 	}
-- 
2.52.0.223.gf5cc29aaa4-goog



From tabba at google.com  Thu Dec 11 03:38:28 2025
From: tabba at google.com (Fuad Tabba)
Date: Thu, 11 Dec 2025 11:38:28 +0000
Subject: [PATCH v2 5/5] KVM: arm64: Use kvm_has_mte() in pKVM trap initialization
In-Reply-To: <20251211113828.370370-1-tabba@google.com>
References: <20251211113828.370370-1-tabba@google.com>
Message-ID: <20251211113828.370370-6-tabba@google.com>

When initializing HCR traps in protected mode, use kvm_has_mte() to
check for MTE support rather than kvm_has_feat(kvm, ID_AA64PFR1_EL1,
MTE, IMP).

kvm_has_mte() provides a more comprehensive check:
 - kvm_has_feat() only checks if MTE is in the guest's ID register view
   (i.e., what we advertise to the guest)
 - kvm_has_mte() checks both system_supports_mte() AND whether
   KVM_ARCH_FLAG_MTE_ENABLED is set for this VM instance

Signed-off-by: Fuad Tabba <tabba at google.com>
---
 arch/arm64/kvm/hyp/nvhe/pkvm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index 43bde061b65d..f2060ca66e5d 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -82,7 +82,7 @@ static void pvm_init_traps_hcr(struct kvm_vcpu *vcpu)
 	if (!kvm_has_feat(kvm, ID_AA64PFR0_EL1, AMU, IMP))
 		val &= ~(HCR_AMVOFFEN);
 
-	if (!kvm_has_feat(kvm, ID_AA64PFR1_EL1, MTE, IMP)) {
+	if (!kvm_has_mte(kvm)) {
 		val |= HCR_TID5;
 		val &= ~(HCR_DCT | HCR_ATA);
 	}
-- 
2.52.0.223.gf5cc29aaa4-goog



From anshuman.khandual at arm.com  Thu Dec 11 03:45:35 2025
From: anshuman.khandual at arm.com (Anshuman Khandual)
Date: Thu, 11 Dec 2025 17:15:35 +0530
Subject: [PATCH 1/4] arm64: ptdump: use seq_puts() in pt_dump_seq_puts()
 macro
In-Reply-To: <20251018170416.3355249-1-hi@josie.lol>
References: <20251018170416.3355249-1-hi@josie.lol>
Message-ID: <e702e529-efe3-41a4-953c-cdf838b4e7c5@arm.com>

On 18/10/25 10:34 PM, Josephine Pfeiffer wrote:
> The pt_dump_seq_puts() macro incorrectly uses seq_printf() instead of
> seq_puts(). This is both a performance issue and conceptually wrong,
> as the macro name suggests plain string output (puts) but the
> implementation uses formatted output (printf).
> 
> All call sites pass constant strings without format specifiers, so
> using seq_printf() adds unnecessary overhead for format string parsing.
> 
> This bug was introduced in commit ae5d1cf358a5 ("arm64: dump: Make the
> page table dumping seq_file optional") in 2016, where seq_puts() was
> replaced with a new pt_dump_seq_puts() macro that mistakenly used
> seq_printf().
> 
> Fixes: ae5d1cf358a5 ("arm64: dump: Make the page table dumping seq_file optional")
> Signed-off-by: Josephine Pfeiffer <hi at josie.lol>
> ---
>  arch/arm64/mm/ptdump.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/mm/ptdump.c b/arch/arm64/mm/ptdump.c
> index ab9899ca1e5f..a35fcd62bf75 100644
> --- a/arch/arm64/mm/ptdump.c
> +++ b/arch/arm64/mm/ptdump.c
> @@ -35,7 +35,7 @@
>  #define pt_dump_seq_puts(m, fmt)	\
>  ({					\
>  	if (m)				\
> -		seq_printf(m, fmt);	\
> +		seq_puts(m, fmt);	\
>  })
>  
>  static const struct ptdump_prot_bits pte_bits[] = {

LGTM and also did no see any problem while dumping via the
sysfs file /sys/kernel/debug/kernel_page_tables

Reviewed-by: Anshuman Khandual <anshuman.khandual at arm.com>


From maz at kernel.org  Thu Dec 11 03:57:23 2025
From: maz at kernel.org (Marc Zyngier)
Date: Thu, 11 Dec 2025 11:57:23 +0000
Subject: [PATCH 2/2] KVM: arm64: Remove extra argument for __pvkm_host_{share,unshare}_hyp()
In-Reply-To: <aTqP9M_E7ROGpfbB@raptor>
References: <20251210132102.137631-1-alexandru.elisei@arm.com>
	<20251210132102.137631-3-alexandru.elisei@arm.com>
	<86zf7po2n3.wl-maz@kernel.org>
	<aTqP9M_E7ROGpfbB@raptor>
Message-ID: <86wm2tnsd8.wl-maz@kernel.org>

On Thu, 11 Dec 2025 09:33:40 +0000,
Alexandru Elisei <alexandru.elisei at arm.com> wrote:
> 
> Hi Marc,
> 
> On Thu, Dec 11, 2025 at 08:15:28AM +0000, Marc Zyngier wrote:
> > On Wed, 10 Dec 2025 13:21:02 +0000,
> > Alexandru Elisei <alexandru.elisei at arm.com> wrote:
> > > 
> > > __pvkm_host_share_hyp() and __pkvm_host_unshare_hyp() both have one
> > > parameter, the pfn, not two. Even though correctness isn't impacted because
> > > the SMCCC handlers pass the first argument and ignore the second one, let's
> > > call the functions with the proper number of arguments.
> > > 
> > > Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
> > > ---
> > >  arch/arm64/kvm/mmu.c | 2 +-
> > >  1 file changed, 1 insertion(+), 1 deletion(-)
> > > 
> > > diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
> > > index 7cc964af8d30..6c6abcd8e89e 100644
> > > --- a/arch/arm64/kvm/mmu.c
> > > +++ b/arch/arm64/kvm/mmu.c
> > > @@ -497,7 +497,7 @@ static int share_pfn_hyp(u64 pfn)
> > >  	this->count = 1;
> > >  	rb_link_node(&this->node, parent, node);
> > >  	rb_insert_color(&this->node, &hyp_shared_pfns);
> > > -	ret = kvm_call_hyp_nvhe(__pkvm_host_share_hyp, pfn, 1);
> > > +	ret = kvm_call_hyp_nvhe(__pkvm_host_share_hyp, pfn);
> > >  unlock:
> > >  	mutex_unlock(&hyp_shared_pfns_lock);
> > >  
> > 
> > Yeah, we lost all form of type-checking when everything was hastily
> > converted to SMCCC to avoid function pointers. Somehow, I feel that
> > the cure was worse than the disease.
> > 
> > I wish we'd reintroduce some form of compile-time checks, maybe by
> > having generated stubs?
> 
> I also think compile-time checks would be useful, do you have something
> particular in mind?
> 
> If not, right now I can't think of a way to generate the stubs automagically,
> but I can give it a (probably bad) try and take it from there.

On first approximation, all the hypercalls are implemented like this
(taking __pkvm_init() as an example):


We have the body of the function, with its forward declaration:

int __pkvm_init(phys_addr_t phys, unsigned long size, unsigned long nr_cpus,
		unsigned long *per_cpu_base, u32 hyp_va_bits);

int __pkvm_init(phys_addr_t phys, unsigned long size, unsigned long nr_cpus,
		unsigned long *per_cpu_base, u32 hyp_va_bits)
{
	[...]
}

We also have the callee stub that does the argument un-marshalling:

static void handle___pkvm_init(struct kvm_cpu_context *host_ctxt)
{
	DECLARE_REG(phys_addr_t, phys, host_ctxt, 1);
	DECLARE_REG(unsigned long, size, host_ctxt, 2);
	DECLARE_REG(unsigned long, nr_cpus, host_ctxt, 3);
	DECLARE_REG(unsigned long *, per_cpu_base, host_ctxt, 4);
	DECLARE_REG(u32, hyp_va_bits, host_ctxt, 5);

	/*
	 * __pkvm_init() will return only if an error occurred, otherwise it
	 * will tail-call in __pkvm_init_finalise() which will have to deal
	 * with the host context directly.
	 */
	cpu_reg(host_ctxt, 1) = __pkvm_init(phys, size, nr_cpus, per_cpu_base,
					    hyp_va_bits);
}

and then the call site:

	ret = kvm_call_hyp_nvhe(__pkvm_init, hyp_mem_base, hyp_mem_size,
				num_possible_cpus(), kern_hyp_va(per_cpu_base),
				hyp_va_bits);

The problem is that kvm_call_hyp_nvhe() ignores the type conveyed by
"__pkvm_init", as it is immediately tokenized as an SMCCC function
number.

One idea would be to add something like this:

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index b552a1e03848c..fdf09beeae380 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -1208,10 +1208,11 @@ void kvm_arm_resume_guest(struct kvm *kvm);
 #define vcpu_has_run_once(vcpu)	(!!READ_ONCE((vcpu)->pid))
 
 #ifndef __KVM_NVHE_HYPERVISOR__
-#define kvm_call_hyp_nvhe(f, ...)						\
+#define kvm_call_hyp_nvhe(f, ...)					\
 	({								\
 		struct arm_smccc_res res;				\
 									\
+		(void)f(##__VA_ARGS__);					\
 		arm_smccc_1_1_hvc(KVM_HOST_SMCCC_FUNC(f),		\
 				  ##__VA_ARGS__, &res);			\
 		WARN_ON(res.a0 != SMCCC_RET_SUCCESS);			\

and generate stub functions that don't do anything, can be eliminated
by the compiler, but not before type-checking.

Another possible idea would be:

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index b552a1e03848c..4f53a3240a511 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -1208,12 +1208,11 @@ void kvm_arm_resume_guest(struct kvm *kvm);
 #define vcpu_has_run_once(vcpu)	(!!READ_ONCE((vcpu)->pid))
 
 #ifndef __KVM_NVHE_HYPERVISOR__
-#define kvm_call_hyp_nvhe(f, ...)						\
+#define kvm_call_hyp_nvhe(f, ...)					\
 	({								\
 		struct arm_smccc_res res;				\
 									\
-		arm_smccc_1_1_hvc(KVM_HOST_SMCCC_FUNC(f),		\
-				  ##__VA_ARGS__, &res);			\
+		nvhe_hvc_ ## f(##__VA_ARGS__, &res);			\
 		WARN_ON(res.a0 != SMCCC_RET_SUCCESS);			\
 									\
 		res.a1;							\

where the stub function would actually do the type checking. I tend to
prefer this.

In any case, you would need have some form of declarative IDL, and get
both the caller and callee stubs to be totally generated. It shouldn't
be too complicated to do it in awk or some other stuff.

Thoughts?

	M.

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


From festevam at gmail.com  Thu Dec 11 04:31:25 2025
From: festevam at gmail.com (Fabio Estevam)
Date: Thu, 11 Dec 2025 09:31:25 -0300
Subject: [PATCH v1 3/6] arm64: dts: imx8mp-var-som: Remove UART2 console
In-Reply-To: <DB4PR08MB103414303516B7FAFF29DB571E9A1A@DB4PR08MB10341.eurprd08.prod.outlook.com>
References: <20251210152000.42265-1-stefano.r@variscite.com>
 <20251210152000.42265-4-stefano.r@variscite.com> <CAOMZO5B2__4qgJRni=DPxd1QoPQLwO+r9ZbdbsOWXZemVU86aw@mail.gmail.com>
 <DB4PR08MB103414303516B7FAFF29DB571E9A1A@DB4PR08MB10341.eurprd08.prod.outlook.com>
Message-ID: <CAOMZO5Aq8iO2w7MsQz+BCNBsCUEewApoU=keGjSpFMZzSwhgyA@mail.gmail.com>

On Thu, Dec 11, 2025 at 5:08?AM Stefano Radaelli
<stefano.r at variscite.com> wrote:

> you are absolutely right, the Symphony DTS needs to provide UART2 (and the
> other interfaces moved out of the SOM) so that users relying on
> imx8mp-var-som-symphony.dts do not lose functionality.
> For this series, my intention was strictly to clean up the SOM and ensure
> it only describes what is physically present on the module.
> As soon as our new V2 symphony carrier is ready, I will submit the corresponding
> patches for the Symphony DTS as well.

This means the series cannot be applied as-is; otherwise, it will
cause regressions.

The move of UART from SoM dtsi to Symphony dts should be part of the same patch.


From 21cnbao at gmail.com  Thu Dec 11 04:36:51 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Thu, 11 Dec 2025 20:36:51 +0800
Subject: [PATCH v2 3/3] mm: rmap: support batched unmapping for file large folios
In-Reply-To: <af330c9ea188bd0f28189b1e6e5803f6de9d2abe.1765439381.git.baolin.wang@linux.alibaba.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com> <af330c9ea188bd0f28189b1e6e5803f6de9d2abe.1765439381.git.baolin.wang@linux.alibaba.com>
Message-ID: <CAGsJ_4yVCbP9EJ2KZu-83PL-LViB+zn3NPC5E61LKf+nWWNsWw@mail.gmail.com>

On Thu, Dec 11, 2025 at 4:17?PM Baolin Wang
<baolin.wang at linux.alibaba.com> wrote:
>
> Similar to folio_referenced_one(), we can apply batched unmapping for file
> large folios to optimize the performance of file folios reclamation.
>
> Performance testing:
> Allocate 10G clean file-backed folios by mmap() in a memory cgroup, and try to
> reclaim 8G file-backed folios via the memory.reclaim interface. I can observe
> 75% performance improvement on my Arm64 32-core server.
>
> W/o patch:
> real    0m1.018s
> user    0m0.000s
> sys     0m1.018s
>
> W/ patch:
> real    0m0.249s
> user    0m0.000s
> sys     0m0.249s
>
> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>

It appears quite straightforward to introduce file folios support based on the
current lazyfree implementation.

Acked-by: Barry Song <baohua at kernel.org>


From yuzenghui at huawei.com  Thu Dec 11 05:02:27 2025
From: yuzenghui at huawei.com (Zenghui Yu)
Date: Thu, 11 Dec 2025 21:02:27 +0800
Subject: [PATCH v4 2/3] KVM: selftests: Test for KVM_EXIT_ARM_SEA
In-Reply-To: <20251013185903.1372553-3-jiaqiyan@google.com>
References: <20251013185903.1372553-1-jiaqiyan@google.com>
 <20251013185903.1372553-3-jiaqiyan@google.com>
Message-ID: <3061f5f8-cef0-b7b1-c4de-f2ceea29af9a@huawei.com>

Hi Jiaqi,

I had run into several problems when testing it on different servers. I
haven't figured them out yet but post it early for discussion.

On 2025/10/14 2:59, Jiaqi Yan wrote:
> Test how KVM handles guest SEA when APEI is unable to claim it, and
> KVM_CAP_ARM_SEA_TO_USER is enabled.
> 
> The behavior is triggered by consuming recoverable memory error (UER)
> injected via EINJ. The test asserts two major things:
> 1. KVM returns to userspace with KVM_EXIT_ARM_SEA exit reason, and
>    has provided expected fault information, e.g. esr, flags, gva, gpa.
> 2. Userspace is able to handle KVM_EXIT_ARM_SEA by injecting SEA to
>    guest and KVM injects expected SEA into the VCPU.
> 
> Tested on a data center server running Siryn AmpereOne processor
> that has RAS support.
> 
> Several things to notice before attempting to run this selftest:
> - The test relies on EINJ support in both firmware and kernel to
>   inject UER. Otherwise the test will be skipped.
> - The under-test platform's APEI should be unable to claim the SEA.
>   Otherwise the test will be skipped.
> - Some platform doesn't support notrigger in EINJ, which may cause
>   APEI and GHES to offline the memory before guest can consume
>   injected UER, and making test unable to trigger SEA.
> 
> Signed-off-by: Jiaqi Yan <jiaqiyan at google.com>

[...]

> +static void inject_uer(uint64_t paddr)
> +{
> +	if (access("/sys/firmware/acpi/tables/EINJ", R_OK) == -1)
> +		ksft_test_result_skip("EINJ table no available in firmware");

Missing '\n'.

We should return early (to actually skip the test) if the file can not
be accessed, right?

> +
> +	if (access(EINJ_ETYPE, R_OK | W_OK) == -1)
> +		ksft_test_result_skip("EINJ module probably not loaded?");
> +
> +	write_einj_entry(EINJ_ETYPE, ERROR_TYPE_MEMORY_UER);
> +	write_einj_entry(EINJ_FLAGS, MASK_MEMORY_UER);
> +	write_einj_entry(EINJ_ADDR, paddr);
> +	write_einj_entry(EINJ_MASK, ~0x0UL);
> +	write_einj_entry(EINJ_NOTRIGGER, 1);
> +	write_einj_entry(EINJ_DOIT, 1);
> +}
> +
> +/*
> + * When host APEI successfully claims the SEA caused by guest_code, kernel
> + * will send SIGBUS signal with BUS_MCEERR_AR to test thread.
> + *
> + * We set up this SIGBUS handler to skip the test for that case.
> + */
> +static void sigbus_signal_handler(int sig, siginfo_t *si, void *v)
> +{
> +	ksft_print_msg("SIGBUS (%d) received, dumping siginfo...\n", sig);
> +	ksft_print_msg("si_signo=%d, si_errno=%d, si_code=%d, si_addr=%p\n",
> +		       si->si_signo, si->si_errno, si->si_code, si->si_addr);
> +	if (si->si_code == BUS_MCEERR_AR)
> +		ksft_test_result_skip("SEA is claimed by host APEI\n");
> +	else
> +		ksft_test_result_fail("Exit with signal unhandled\n");
> +
> +	exit(0);
> +}
> +
> +static void setup_sigbus_handler(void)
> +{
> +	struct sigaction act;
> +
> +	memset(&act, 0, sizeof(act));
> +	sigemptyset(&act.sa_mask);
> +	act.sa_sigaction = sigbus_signal_handler;
> +	act.sa_flags = SA_SIGINFO;
> +	TEST_ASSERT(sigaction(SIGBUS, &act, NULL) == 0,
> +		    "Failed to setup SIGBUS handler");
> +}
> +
> +static void guest_code(void)
> +{
> +	uint64_t guest_data;
> +
> +	/* Consumes error will cause a SEA. */
> +	guest_data = *(uint64_t *)EINJ_GVA;
> +
> +	GUEST_FAIL("Poison not protected by SEA: gva=%#lx, guest_data=%#lx\n",
> +		   EINJ_GVA, guest_data);
> +}
> +
> +static void expect_sea_handler(struct ex_regs *regs)
> +{
> +	u64 esr = read_sysreg(esr_el1);
> +	u64 far = read_sysreg(far_el1);
> +	bool expect_far_invalid = far_invalid;
> +
> +	GUEST_PRINTF("Handling Guest SEA\n");
> +	GUEST_PRINTF("ESR_EL1=%#lx, FAR_EL1=%#lx\n", esr, far);
> +
> +	GUEST_ASSERT_EQ(ESR_ELx_EC(esr), ESR_ELx_EC_DABT_CUR);
> +	GUEST_ASSERT_EQ(esr & ESR_ELx_FSC_TYPE, ESR_ELx_FSC_EXTABT);
> +
> +	if (expect_far_invalid) {
> +		GUEST_ASSERT_EQ(esr & ESR_ELx_FnV, ESR_ELx_FnV);

I hit this ASSERT with:

# Mapped 0x40000 pages: gva=0x80000000 to gpa=0xff80000000
# Before EINJect: data=0xbaadcafe
# EINJ_GVA=0x81234bad, einj_gpa=0xff81234bad, einj_hva=0xffff41234bad,
einj_hpa=0x202841234bad
# echo 0x10 > /sys/kernel/debug/apei/einj/error_type - done
# echo 0x2 > /sys/kernel/debug/apei/einj/flags - done
# echo 0x202841234bad > /sys/kernel/debug/apei/einj/param1 - done
# echo 0xffffffffffffffff > /sys/kernel/debug/apei/einj/param2 - done
# echo 0x1 > /sys/kernel/debug/apei/einj/notrigger - done
# echo 0x1 > /sys/kernel/debug/apei/einj/error_inject - done
# Memory UER EINJected
# Dump kvm_run info about KVM_EXIT_ARM_SEA
# kvm_run.arm_sea: esr=0x92000610, flags=0
# kvm_run.arm_sea: gva=0, gpa=0
# From guest: Handling Guest SEA
# From guest: ESR_EL1=0x96000010, FAR_EL1=0xaaaadf254828
# Guest aborted!
==== Test Assertion Failure ====
  arm64/sea_to_user.c:172: esr & ESR_ELx_FnV == ESR_ELx_FnV
  pid=38112 tid=38112 errno=4 - Interrupted system call
     1	0x0000000000402f9b: run_vm at sea_to_user.c:246
     2	0x0000000000402467: main at sea_to_user.c:330
     3	0x0000ffff8e22b03f: ?? ??:0
     4	0x0000ffff8e22b117: ?? ??:0
     5	0x00000000004026ef: _start at ??:?
  0x0 != 0x400 (esr & ESR_ELx_FnV != ESR_ELx_FnV)

It seems that KVM doesn't emulate FnV when injecting an abort.

> +		GUEST_PRINTF("Guest observed garbage value in FAR\n");
> +	} else {
> +		GUEST_ASSERT_EQ(esr & ESR_ELx_FnV, 0);
> +		GUEST_ASSERT_EQ(far, EINJ_GVA);
> +	}
> +
> +	GUEST_DONE();
> +}
> +
> +static void vcpu_inject_sea(struct kvm_vcpu *vcpu)
> +{
> +	struct kvm_vcpu_events events = {};
> +
> +	events.exception.ext_dabt_pending = true;
> +	vcpu_events_set(vcpu, &events);
> +}
> +
> +static void run_vm(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
> +{
> +	struct ucall uc;
> +	bool guest_done = false;
> +	struct kvm_run *run = vcpu->run;
> +	u64 esr;
> +
> +	/* Resume the vCPU after error injection to consume the error. */
> +	vcpu_run(vcpu);
> +
> +	ksft_print_msg("Dump kvm_run info about KVM_EXIT_%s\n",
> +		       exit_reason_str(run->exit_reason));
> +	ksft_print_msg("kvm_run.arm_sea: esr=%#llx, flags=%#llx\n",
> +		       run->arm_sea.esr, run->arm_sea.flags);
> +	ksft_print_msg("kvm_run.arm_sea: gva=%#llx, gpa=%#llx\n",
> +		       run->arm_sea.gva, run->arm_sea.gpa);
> +
> +	TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_ARM_SEA);

I can also hit this ASSERT with:

Random seed: 0x6b8b4567
# Mapped 0x40000 pages: gva=0x80000000 to gpa=0xff80000000
# Before EINJect: data=0xbaadcafe
# EINJ_GVA=0x81234bad, einj_gpa=0xff81234bad, einj_hva=0xffff41234bad,
einj_hpa=0x2841234bad
# echo 0x10 > /sys/kernel/debug/apei/einj/error_type - done
# echo 0x2 > /sys/kernel/debug/apei/einj/flags - done
# echo 0x2841234bad > /sys/kernel/debug/apei/einj/param1 - done
# echo 0xffffffffffffffff > /sys/kernel/debug/apei/einj/param2 - done
# echo 0x1 > /sys/kernel/debug/apei/einj/notrigger - done
# echo 0x1 > /sys/kernel/debug/apei/einj/error_inject - done
# Memory UER EINJected
# Dump kvm_run info about KVM_EXIT_MMIO
# kvm_run.arm_sea: esr=0xffff90ba0040, flags=0x691000
# kvm_run.arm_sea: gva=0x100000008, gpa=0
==== Test Assertion Failure ====
  arm64/sea_to_user.c:207: exit_reason == (41)
  pid=38023 tid=38023 errno=4 - Interrupted system call
     1	0x0000000000402d1b: run_vm at sea_to_user.c:207
     2	0x0000000000402467: main at sea_to_user.c:330
     3	0x0000ffff9122b03f: ?? ??:0
     4	0x0000ffff9122b117: ?? ??:0
     5	0x00000000004026ef: _start at ??:?
  Wanted KVM exit reason: 41 (ARM_SEA), got: 6 (MMIO)

Not sure what's wrong it..

> +
> +	esr = run->arm_sea.esr;
> +	TEST_ASSERT_EQ(ESR_ELx_EC(esr), ESR_ELx_EC_DABT_LOW);
> +	TEST_ASSERT_EQ(esr & ESR_ELx_FSC_TYPE, ESR_ELx_FSC_EXTABT);
> +	TEST_ASSERT_EQ(ESR_ELx_ISS2(esr), 0);
> +	TEST_ASSERT_EQ((esr & ESR_ELx_INST_SYNDROME), 0);
> +	TEST_ASSERT_EQ(esr & ESR_ELx_VNCR, 0);
> +
> +	if (!(esr & ESR_ELx_FnV)) {
> +		ksft_print_msg("Expect gva to match given FnV bit is 0\n");
> +		TEST_ASSERT_EQ(run->arm_sea.gva, EINJ_GVA);
> +	}
> +
> +	if (run->arm_sea.flags & KVM_EXIT_ARM_SEA_FLAG_GPA_VALID) {
> +		ksft_print_msg("Expect gpa to match given KVM_EXIT_ARM_SEA_FLAG_GPA_VALID is set\n");
> +		TEST_ASSERT_EQ(run->arm_sea.gpa, einj_gpa & PAGE_ADDR_MASK);
> +	}
> +
> +	far_invalid = esr & ESR_ELx_FnV;

Missing sync_global_to_guest()?

Thanks,
Zenghui


From linusw at kernel.org  Thu Dec 11 05:05:01 2025
From: linusw at kernel.org (Linus Walleij)
Date: Thu, 11 Dec 2025 14:05:01 +0100
Subject: [PATCH] ARM: dts: ixp4xx: Fix up Actiontec MI424WR DTS files
Message-ID: <20251211-ixp4xx-actiontec-dts-fix-v1-1-97af8e79d474@kernel.org>

The KS8995 switch was unconditionally wired to EthC (eth1)
on both MI424WR variants, this is wrong: the D revision has
the switch connected to EthB (eth0) so pull this assingment
out of the generic MI424WR DTSI file and make it a property
of the respective variants instead.

Signed-off-by: Linus Walleij <linusw at kernel.org>
---
SoC maintainers: please apply this patch directly for fixes.
---
 .../boot/dts/intel/ixp/intel-ixp42x-actiontec-mi424wr-ac.dts  | 11 +++++++++++
 .../boot/dts/intel/ixp/intel-ixp42x-actiontec-mi424wr-d.dts   | 11 +++++++++++
 .../boot/dts/intel/ixp/intel-ixp42x-actiontec-mi424wr.dtsi    |  1 -
 3 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/intel/ixp/intel-ixp42x-actiontec-mi424wr-ac.dts b/arch/arm/boot/dts/intel/ixp/intel-ixp42x-actiontec-mi424wr-ac.dts
index 413b9255f9e3..19a8d7b07758 100644
--- a/arch/arm/boot/dts/intel/ixp/intel-ixp42x-actiontec-mi424wr-ac.dts
+++ b/arch/arm/boot/dts/intel/ixp/intel-ixp42x-actiontec-mi424wr-ac.dts
@@ -12,6 +12,17 @@ / {
 	model = "Actiontec MI424WR rev A/C";
 	compatible = "actiontec,mi424wr-ac", "intel,ixp42x";
 
+	/* Connect the switch to EthC */
+	spi {
+		ethernet-switch at 0 {
+			ethernet-ports {
+				ethernet-port at 4 {
+					ethernet = <&ethc>;
+				};
+			};
+		};
+	};
+
 	soc {
 		/* EthB used for WAN */
 		ethernet at c8009000 {
diff --git a/arch/arm/boot/dts/intel/ixp/intel-ixp42x-actiontec-mi424wr-d.dts b/arch/arm/boot/dts/intel/ixp/intel-ixp42x-actiontec-mi424wr-d.dts
index 3619c6411a5c..244c6ea0973f 100644
--- a/arch/arm/boot/dts/intel/ixp/intel-ixp42x-actiontec-mi424wr-d.dts
+++ b/arch/arm/boot/dts/intel/ixp/intel-ixp42x-actiontec-mi424wr-d.dts
@@ -12,6 +12,17 @@ / {
 	model = "Actiontec MI424WR rev D";
 	compatible = "actiontec,mi424wr-d", "intel,ixp42x";
 
+	/* Connect the switch to EthB */
+	spi {
+		ethernet-switch at 0 {
+			ethernet-ports {
+				ethernet-port at 4 {
+					ethernet = <&ethb>;
+				};
+			};
+		};
+	};
+
 	soc {
 		/* EthB used for LAN */
 		ethernet at c8009000 {
diff --git a/arch/arm/boot/dts/intel/ixp/intel-ixp42x-actiontec-mi424wr.dtsi b/arch/arm/boot/dts/intel/ixp/intel-ixp42x-actiontec-mi424wr.dtsi
index 76fd97c5beb6..9b54e3c01a34 100644
--- a/arch/arm/boot/dts/intel/ixp/intel-ixp42x-actiontec-mi424wr.dtsi
+++ b/arch/arm/boot/dts/intel/ixp/intel-ixp42x-actiontec-mi424wr.dtsi
@@ -152,7 +152,6 @@ ethernet-port at 3 {
 				};
 				ethernet-port at 4 {
 					reg = <4>;
-					ethernet = <&ethc>;
 					phy-mode = "mii";
 					fixed-link {
 						speed = <100>;

---
base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
change-id: 20251211-ixp4xx-actiontec-dts-fix-ec4a7249f435

Best regards,
-- 
Linus Walleij <linusw at kernel.org>



From alexey.klimov at linaro.org  Thu Dec 11 05:14:06 2025
From: alexey.klimov at linaro.org (Alexey Klimov)
Date: Thu, 11 Dec 2025 13:14:06 +0000
Subject: [PATCH 1/1] firmware: arm_scmi: Increase MAX_OPPS to 64
In-Reply-To: <6af5945e-7d5c-4596-ac42-c5898b4c49b7@oss.qualcomm.com>
References: <20251014073454.461999-1-vivek.aknurwar@oss.qualcomm.com>
 <6af5945e-7d5c-4596-ac42-c5898b4c49b7@oss.qualcomm.com>
Message-ID: <DEVEXHI9CEFA.19RL3BXTV8E38@linaro.org>

On Wed Dec 10, 2025 at 11:28 PM GMT, Vivek Aknurwar wrote:
> Hello Sudeep/Cristian,
>
> Just following up on this patch. If there?s anything missing or
> needs adjustment, please let me know.

Vivek, please avoid top-posting.

> On 10/14/2025 12:34 AM, Vivek Aknurwar wrote:
>> Some upcoming SoCs define more than 32 operating performance points (OPPs),
>> exceeding the current SCMI protocol limit. Increase MAX_OPPS to 64
>> (next power of 2) to support these configurations.

Didn't touch for a while. The way it is stated confuses me a bit.
Should the value defined by protocol be updated out of the blue?
Should the protocol (defined by spec) be changed first?

If protocol changes, then should the version/minor version be
updated/added?

Thanks,
Alexey


>> Signed-off-by: Vivek Aknurwar <vivek.aknurwar at oss.qualcomm.com>
>> ---
>>  drivers/firmware/arm_scmi/perf.c | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>> 
>> diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c
>> index 683fd9b85c5c..2249ef7fe790 100644
>> --- a/drivers/firmware/arm_scmi/perf.c
>> +++ b/drivers/firmware/arm_scmi/perf.c
>> @@ -27,7 +27,7 @@
>>  /* Updated only after ALL the mandatory features for that version are merged */
>>  #define SCMI_PROTOCOL_SUPPORTED_VERSION		0x40000
>>  
>> -#define MAX_OPPS		32
>> +#define MAX_OPPS		64
>>  
>>  enum scmi_performance_protocol_cmd {
>>  	PERF_DOMAIN_ATTRIBUTES = 0x3,



From smostafa at google.com  Thu Dec 11 05:18:35 2025
From: smostafa at google.com (Mostafa Saleh)
Date: Thu, 11 Dec 2025 13:18:35 +0000
Subject: [PATCH] iommu/arm-smmu-v3: Remove IAS
Message-ID: <20251211131835.3267022-1-smostafa@google.com>

The driver only supports AArch64 page tables where OAS == IAS.

Remove the extra IAS tracking for AArch32 as this feature was
never implemented and that was creating BAD_STEs for SMMUv3
with stage-2 and OAS < 40.

Further discussion on this in:
https://lore.kernel.org/linux-iommu/20251130194506.593700-1-smostafa at google.com/

Reported-by: Tomasz Nowicki <tnowicki at google.com>
Fixes: f0c453dbcce7 ("iommu/arm-smmu: Ensure IAS is set correctly for AArch32-capable SMMUs")
Signed-off-by: Mostafa Saleh <smostafa at google.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 18 +++++-------------
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h |  2 --
 2 files changed, 5 insertions(+), 15 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index d16d35c78c06..019211db621d 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2551,7 +2551,7 @@ static int arm_smmu_domain_finalise(struct arm_smmu_domain *smmu_domain,
 				     ARM_SMMU_FEAT_VAX) ? 52 : 48;
 
 		pgtbl_cfg.ias = min_t(unsigned long, ias, VA_BITS);
-		pgtbl_cfg.oas = smmu->ias;
+		pgtbl_cfg.oas = smmu->oas;
 		if (enable_dirty)
 			pgtbl_cfg.quirks |= IO_PGTABLE_QUIRK_ARM_HD;
 		fmt = ARM_64_LPAE_S1;
@@ -2561,7 +2561,7 @@ static int arm_smmu_domain_finalise(struct arm_smmu_domain *smmu_domain,
 	case ARM_SMMU_DOMAIN_S2:
 		if (enable_dirty)
 			return -EOPNOTSUPP;
-		pgtbl_cfg.ias = smmu->ias;
+		pgtbl_cfg.ias = smmu->oas;
 		pgtbl_cfg.oas = smmu->oas;
 		fmt = ARM_64_LPAE_S2;
 		finalise_stage_fn = arm_smmu_domain_finalise_s2;
@@ -4395,13 +4395,7 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
 	}
 
 	/* We only support the AArch64 table format at present */
-	switch (FIELD_GET(IDR0_TTF, reg)) {
-	case IDR0_TTF_AARCH32_64:
-		smmu->ias = 40;
-		fallthrough;
-	case IDR0_TTF_AARCH64:
-		break;
-	default:
+	if (!(FIELD_GET(IDR0_TTF, reg) & IDR0_TTF_AARCH64)) {
 		dev_err(smmu->dev, "AArch64 table format not supported!\n");
 		return -ENXIO;
 	}
@@ -4514,8 +4508,6 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
 		dev_warn(smmu->dev,
 			 "failed to set DMA mask for table walker\n");
 
-	smmu->ias = max(smmu->ias, smmu->oas);
-
 	if ((smmu->features & ARM_SMMU_FEAT_TRANS_S1) &&
 	    (smmu->features & ARM_SMMU_FEAT_TRANS_S2))
 		smmu->features |= ARM_SMMU_FEAT_NESTING;
@@ -4525,8 +4517,8 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
 	if (arm_smmu_sva_supported(smmu))
 		smmu->features |= ARM_SMMU_FEAT_SVA;
 
-	dev_info(smmu->dev, "ias %lu-bit, oas %lu-bit (features 0x%08x)\n",
-		 smmu->ias, smmu->oas, smmu->features);
+	dev_info(smmu->dev, "oas %lu-bit (features 0x%08x)\n",
+		 smmu->oas, smmu->features);
 	return 0;
 }
 
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index ae23aacc3840..0a5bb57dbdfe 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -43,7 +43,6 @@ struct arm_vsmmu;
 #define IDR0_COHACC			(1 << 4)
 #define IDR0_TTF			GENMASK(3, 2)
 #define IDR0_TTF_AARCH64		2
-#define IDR0_TTF_AARCH32_64		3
 #define IDR0_S1P			(1 << 1)
 #define IDR0_S2P			(1 << 0)
 
@@ -784,7 +783,6 @@ struct arm_smmu_device {
 	int				gerr_irq;
 	int				combined_irq;
 
-	unsigned long			ias; /* IPA */
 	unsigned long			oas; /* PA */
 	unsigned long			pgsize_bitmap;
 
-- 
2.52.0.223.gf5cc29aaa4-goog



From sjg at chromium.org  Thu Dec 11 05:20:07 2025
From: sjg at chromium.org (Simon Glass)
Date: Thu, 11 Dec 2025 06:20:07 -0700
Subject: [PATCH v6 4/8] scripts/make_fit: Provide a way to add built modules
In-Reply-To: <f0211065-bca2-4a5b-9b97-66397deac20a@pengutronix.de>
References: <20251119181333.991099-1-sjg@chromium.org> <20251119181333.991099-5-sjg@chromium.org>
 <f0211065-bca2-4a5b-9b97-66397deac20a@pengutronix.de>
Message-ID: <CAFLszTiiXU5X+7H6zE6sNrCtS5ocCHnEjoYe6cOr2WcdjBz4fw@mail.gmail.com>

Hi Ahmad,

On Wed, 26 Nov 2025 at 04:09, Ahmad Fatoum <a.fatoum at pengutronix.de> wrote:
>
> Hello Simon,
>
> On 11/19/25 7:13 PM, Simon Glass wrote:
> > Provide arguments to support building a ramdisk from a directory tree of
> > modules. This is a convenient way to try out a kernel with its modules.
> >
> > This makes use usr/gen_initramfs.sh where it can be found. Failing that
> > it uses the cpio tool rather than attempting to use a python module or
> > our own code. The list of modules is provided in a file.
>
> I don't think the fallback is a good idea. This script is part of the
> kernel tree and usr/gen_initramfs.sh is as well, so we shouldn't
> duplicate the logic. With a dependency on gen_init_cpio (See my
> modules-cpio-pkg patch), we should always have the script and the
> executable available and it's fine to throw an error if it's not.

For now I would like to leave it in, since it works. I mentioned the
trouble I had trying to depend on a target which depends on an install
target. But once your patch goes in I can try again with the targets
and see if I can make it work.

>
> Thanks for putting in the work!

Cheers! It has certainly been an effort :-)

Regards,
Simon

>
> >
> > Signed-off-by: Simon Glass <sjg at chromium.org>
> > Suggested-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> > ---
> > Note: The approach of depending on modules_install caused build problems
> > as mentioned in the cover letter.
> >
> > I dropped the review tag from Nicolas Schier since there are quite a few
> > changes in this version.
> >
> > Changes in v6:
> > - Using the modules.order file instead of 'find'
> > - Use gen_initramfs.sh where available
> >
> > Changes in v4:
> > - Provide the list of modules from the Makefile
> > - Reduce verbosity (don't print every module filename)
> >
> > Changes in v3:
> > - Add a way to add built modules into the FIT
> >
> >  scripts/make_fit.py | 127 +++++++++++++++++++++++++++++++++++++++++---
> >  1 file changed, 119 insertions(+), 8 deletions(-)
> >
> > diff --git a/scripts/make_fit.py b/scripts/make_fit.py
> > index 1a74a9dcd85e..9dfef11fc4b3 100755
> > --- a/scripts/make_fit.py
> > +++ b/scripts/make_fit.py
> > @@ -13,11 +13,17 @@ Usage:
> >          -r /boot/initrd.img-6.14.0-27-generic @arch/arm64/boot/dts/dtbs-list
> >          -E -c gzip
> >
> > +    # Build with modules ramdisk instead of external ramdisk:
> > +    make_fit.py -A arm64 -n 'Linux-6.17' -O linux
> > +        -o arch/arm64/boot/image.fit -k /tmp/kern/arch/arm64/boot/image.itk
> > +        -m module1.ko module2.ko module3.ko @arch/arm64/boot/dts/dtbs-list
> > +
> >  Creates a FIT containing the supplied kernel, an optional ramdisk, and a set of
> >  devicetree files, either specified individually or listed in a file (with an
> >  '@' prefix).
> >
> >  Use -r to specify an existing ramdisk/initrd file.
> > +Use -m to build a ramdisk from specified kernel module files.
> >
> >  Use -E to generate an external FIT (where the data is placed after the
> >  FIT data structure). This allows parsing of the data without loading
> > @@ -38,6 +44,7 @@ as U-Boot, Linuxboot, Tianocore, etc.
> >  import argparse
> >  import collections
> >  import os
> > +import shutil
> >  import subprocess
> >  import sys
> >  import tempfile
> > @@ -83,8 +90,14 @@ def parse_args():
> >            help='Specifies the operating system')
> >      parser.add_argument('-k', '--kernel', type=str, required=True,
> >            help='Specifies the (uncompressed) kernel input file (.itk)')
> > -    parser.add_argument('-r', '--ramdisk', type=str,
> > +
> > +    # Create mutually exclusive group for ramdisk options
> > +    rd_group = parser.add_mutually_exclusive_group()
> > +    rd_group.add_argument('-r', '--ramdisk', type=str,
> >            help='Specifies the ramdisk/initrd input file')
> > +    rd_group.add_argument('-m', '--modules', type=str, nargs='+',
> > +          help='List of module filenames to include in ramdisk')
> > +
> >      parser.add_argument('-v', '--verbose', action='store_true',
> >                          help='Enable verbose output')
> >      parser.add_argument('dtbs', type=str, nargs='*',
> > @@ -240,6 +253,89 @@ def output_dtb(fsw, seq, fname, arch, compress):
> >          fsw.property('data', compressed)
> >
> >
> > +def find_gen_initramfs():
> > +    """Find the gen_initramfs.sh script
> > +
> > +    Looks for usr/gen_initramfs.sh relative to the current directory,
> > +    or in the source directory if running from a build directory.
> > +
> > +    Returns:
> > +        str: Path to gen_initramfs.sh if found, None otherwise
> > +    """
> > +    path = 'usr/gen_initramfs.sh'
> > +    if not os.path.exists(path):
> > +        srctree = os.environ.get('srctree')
> > +        if not srctree:
> > +            return None
> > +        path = os.path.join(srctree, path)
> > +        if not os.path.exists(path):
> > +            return None
> > +
> > +    return path
> > +
> > +
> > +def build_ramdisk(args, tmpdir):
> > +    """Build a cpio ramdisk containing kernel modules
> > +
> > +    Similar to mkinitramfs, this creates a compressed cpio-archive containing
> > +    the kernel modules for the current kernel version.
> > +
> > +    Args:
> > +        args (Namespace): Program arguments
> > +        tmpdir (str): Temporary directory to use for modules installation
> > +
> > +    Returns:
> > +        tuple:
> > +            bytes: Compressed cpio data containing modules
> > +            int: total uncompressed size
> > +    """
> > +    suppress = None if args.verbose else subprocess.DEVNULL
> > +
> > +    if args.verbose:
> > +        print(f'Copying {len(args.modules)} modules to ramdisk')
> > +
> > +    # Create output-directory structure
> > +    outdir = os.path.join(tmpdir, 'initramfs')
> > +    modules_dir = os.path.join(outdir, 'usr', 'lib', 'modules')
> > +    os.makedirs(modules_dir, exist_ok=True)
> > +
> > +    # Copy in the specified modules, renaming .o to .ko
> > +    for module in args.modules:
> > +        name, ext = os.path.splitext(module)
> > +        dest = name + '.ko' if ext == '.o' else module
> > +
> > +        # Preserve directory structure under modules_dir
> > +        dest_path = os.path.join(modules_dir, dest)
> > +        os.makedirs(os.path.dirname(dest_path), exist_ok=True)
> > +        shutil.copy2(module, dest_path)
> > +
> > +    if args.verbose:
> > +        print(f'Creating cpio archive from {outdir}')
> > +
> > +    with tempfile.NamedTemporaryFile() as cpio_file:
> > +        # Use gen_initramfs.sh to create the cpio archive if possible
> > +        gen_initramfs = find_gen_initramfs()
> > +        if gen_initramfs:
> > +            subprocess.run([gen_initramfs, '-o', cpio_file.name, outdir],
> > +                           check=True, stdout=suppress, stderr=suppress)
> > +        else:
> > +            # Change to initramfs directory and create cpio archive
> > +            with subprocess.Popen(['find', '.', '-print0'], cwd=outdir,
> > +                                  stdout=subprocess.PIPE) as find:
> > +                with subprocess.Popen(['cpio', '-o', '-0', '-H', 'newc'],
> > +                                      stdin=find.stdout, stdout=cpio_file,
> > +                                      stderr=suppress, cwd=outdir) as cpio:
> > +                    find.stdout.close()
> > +                    cpio.wait()
> > +                    find.wait()
> > +
> > +        cpio_file.seek(0)  # Reset to beginning for reading
> > +        if args.verbose:
> > +            print('Reading ramdisk...' if args.compress == 'none' else
> > +                  f'Compressing ramdisk with {args.compress}...')
> > +        return compress_data(cpio_file, args.compress), cpio_file.tell()
>
> I don't think the fallback is a good idea as it duplicates logic we have
> elsewhere. Just t
>
> > +
> > +
> >  def process_dtb(fname, args):
> >      """Process an input DTB, decomposing it if requested and is possible
> >
> > @@ -318,11 +414,12 @@ def _process_dtbs(args, fsw, entries, fdts):
> >      return seq, size
> >
> >
> > -def build_fit(args):
> > +def build_fit(args, tmpdir):
> >      """Build the FIT from the provided files and arguments
> >
> >      Args:
> >          args (Namespace): Program arguments
> > +        tmpdir (str): Temporary directory for any temporary files
> >
> >      Returns:
> >          tuple:
> > @@ -344,20 +441,29 @@ def build_fit(args):
> >
> >      # Handle the ramdisk if provided. Compression is not supported as it is
> >      # already compressed.
> > +    ramdisk_data = None
> >      if args.ramdisk:
> >          with open(args.ramdisk, 'rb') as inf:
> > -            data = inf.read()
> > -        size += len(data)
> > -        write_ramdisk(fsw, data, args)
> > +            ramdisk_data = inf.read()
> > +        size += len(ramdisk_data)
> > +    elif args.modules:
> > +        if args.verbose:
> > +            print('Building modules ramdisk...')
> > +        ramdisk_data, uncomp_size = build_ramdisk(args, tmpdir)
> > +        size += uncomp_size
> > +
> > +    if ramdisk_data:
> > +        write_ramdisk(fsw, ramdisk_data, args)
> >
> >      count, fdt_size = _process_dtbs(args, fsw, entries, fdts)
> >      size += fdt_size
> >
> > -    finish_fit(fsw, entries, bool(args.ramdisk))
> > +    finish_fit(fsw, entries, has_ramdisk=bool(ramdisk_data))
> >
> > -    # Include the kernel itself in the returned file count
> >      fdt = fsw.as_fdt()
> >      fdt.pack()
> > +
> > +    # Count FDT files, kernel, plus ramdisk if present
> >      return fdt.as_bytearray(), count + 1 + bool(args.ramdisk), size
> >
> >
> > @@ -365,7 +471,12 @@ def run_make_fit():
> >      """Run the tool's main logic"""
> >      args = parse_args()
> >
> > -    out_data, count, size = build_fit(args)
> > +    tmpdir = tempfile.mkdtemp(prefix='make_fit_')
> > +    try:
> > +        out_data, count, size = build_fit(args, tmpdir)
> > +    finally:
> > +        shutil.rmtree(tmpdir)
> > +
> >      with open(args.output, 'wb') as outf:
> >          outf.write(out_data)
> >
>
> --
> Pengutronix e.K.                  |                             |
> Steuerwalder Str. 21              | http://www.pengutronix.de/  |
> 31137 Hildesheim, Germany         | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686  | Fax:   +49-5121-206917-5555 |
>


From sjg at chromium.org  Thu Dec 11 05:29:28 2025
From: sjg at chromium.org (Simon Glass)
Date: Thu, 11 Dec 2025 06:29:28 -0700
Subject: [PATCH v6 7/8] scripts/make_fit: Support a few more parallel compressors
In-Reply-To: <CAGXv+5HiV7EE9CNPRT5EbL8AM8n68Ac1r-=esQL5dgaPDKPTWQ@mail.gmail.com>
References: <20251119181333.991099-1-sjg@chromium.org> <20251119181333.991099-8-sjg@chromium.org>
 <CAGXv+5HiV7EE9CNPRT5EbL8AM8n68Ac1r-=esQL5dgaPDKPTWQ@mail.gmail.com>
Message-ID: <CAFLszThEu4j+Fcxm4VYYVTtqf-9Yp_OnEKes0sD+TACkoHuhbQ@mail.gmail.com>

Hi Chen-Yu,

On Tue, 2 Dec 2025 at 03:18, Chen-Yu Tsai <wenst at chromium.org> wrote:
>
> On Thu, Nov 20, 2025 at 2:14?AM Simon Glass <sjg at chromium.org> wrote:
> >
> > Add support for pbzip2 and plzip which can compress in parallel. This
> > speeds up the ramdisk compression.
> >
> > Signed-off-by: Simon Glass <sjg at chromium.org>
> > ---
> >
> > (no changes since v1)
> >
> >  scripts/make_fit.py | 11 ++++++++---
> >  1 file changed, 8 insertions(+), 3 deletions(-)
> >
> > diff --git a/scripts/make_fit.py b/scripts/make_fit.py
> > index 9dfef11fc4b3..64038f17a51e 100755
> > --- a/scripts/make_fit.py
> > +++ b/scripts/make_fit.py
> > @@ -57,10 +57,10 @@ import libfdt
> >  CompTool = collections.namedtuple('CompTool', 'ext,tools')
> >
> >  COMP_TOOLS = {
> > -    'bzip2': CompTool('.bz2', 'bzip2'),
> > +    'bzip2': CompTool('.bz2', 'pbzip2,bzip2'),
> >      'gzip': CompTool('.gz', 'pigz,gzip'),
> >      'lz4': CompTool('.lz4', 'lz4'),
> > -    'lzma': CompTool('.lzma', 'lzma'),
> > +    'lzma': CompTool('.lzma', 'plzip,lzma'),
> >      'lzo': CompTool('.lzo', 'lzop'),
> >      'zstd': CompTool('.zstd', 'zstd'),
> >  }
> > @@ -220,7 +220,12 @@ def compress_data(inf, compress):
> >              done = False
> >              for tool in comp.tools.split(','):
> >                  try:
> > -                    subprocess.call([tool, '-c'], stdin=inf, stdout=outf)
> > +                    # Add parallel flags for tools that support them
> > +                    cmd = [tool]
> > +                    if tool in ('zstd', 'xz'):
>
> There's no 'xz' tool in the list though.
>
> And this hunk isn't mentioned or explained in the commit message.

OK I will update it.

>
> > +                        cmd.extend(['-T0'])  # Use all available cores
>
> Zero is already the default for 'xz' in 5.8.1.

My system is fairly up-to-date (Noble) and I have:

xz -V
xz (XZ Utils) 5.4.5
liblzma 5.4.5

Does the new version reject -T0 ? If not, then I think it is best to
provide it in this script.

>
>
> ChenYu
>
> > +                    cmd.append('-c')
> > +                    subprocess.call(cmd, stdin=inf, stdout=outf)
> >                      done = True
> >                      break
> >                  except FileNotFoundError:
> > --
> > 2.43.0
> >

Regards,
Simon


From andrew at lunn.ch  Thu Dec 11 05:29:20 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Thu, 11 Dec 2025 14:29:20 +0100
Subject: [PATCH net v3] net: mdio: aspeed: add dummy read to avoid
 read-after-write issue
In-Reply-To: <20251211-aspeed_mdio_add_dummy_read-v3-1-382868869004@aspeedtech.com>
References: <20251211-aspeed_mdio_add_dummy_read-v3-1-382868869004@aspeedtech.com>
Message-ID: <f53fcaf3-0154-4cc7-87be-ab815fa8b6f5@lunn.ch>

On Thu, Dec 11, 2025 at 02:24:58PM +0800, Jacky Chou wrote:
> The Aspeed MDIO controller may return incorrect data when a read operation
> follows immediately after a write. Due to a controller bug, the subsequent
> read can latch stale data, causing the polling logic to terminate earlier
> than expected.
> 
> To work around this hardware issue, insert a dummy read after each write
> operation. This ensures that the next actual read returns the correct
> data and prevents premature polling exit.
> 
> This workaround has been verified to stabilize MDIO transactions on
> affected Aspeed platforms.
> 
> Fixes: f160e99462c6 ("net: phy: Add mdio-aspeed")
> Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>

Reviewed-by: Andrew Lunn <andrew at lunn.ch>

    Andrew


From sjg at chromium.org  Thu Dec 11 05:31:43 2025
From: sjg at chromium.org (Simon Glass)
Date: Thu, 11 Dec 2025 06:31:43 -0700
Subject: [PATCH v6 6/8] kbuild: Allow adding modules into the FIT ramdisk
In-Reply-To: <20251202112039-b03af7ec-ae06-41ab-914b-703940cc98a2@linutronix.de>
References: <20251119181333.991099-1-sjg@chromium.org> <20251119181333.991099-7-sjg@chromium.org>
 <20251120084201-53a3c98f-6a3c-4116-8635-be67d58fd57b@linutronix.de>
 <CAFLszTjsgkPV_-Si79RY5T_Fxd5+f-b1VbpG11uS3E9Lk4Ofmg@mail.gmail.com>
 <20251126080620-921e6880-cacf-44c5-bd8b-f380fbb8090a@linutronix.de>
 <28e18785-1336-4fbc-9f2b-69aa6bb06375@pengutronix.de> <20251202112039-b03af7ec-ae06-41ab-914b-703940cc98a2@linutronix.de>
Message-ID: <CAFLszTh3sM3AEW2MVvR-3szkEtvgnNMsWUcwH6AgBa+KThNF7w@mail.gmail.com>

Hi Thomas,

On Tue, 2 Dec 2025 at 03:31, Thomas Wei?schuh
<thomas.weissschuh at linutronix.de> wrote:
>
> On Wed, Nov 26, 2025 at 12:26:49PM +0100, Ahmad Fatoum wrote:
> > On 11/26/25 8:16 AM, Thomas Wei?schuh wrote:
> > > On Tue, Nov 25, 2025 at 02:58:12PM -0700, Simon Glass wrote:
> > >> On Thu, 20 Nov 2025 at 00:49, Thomas Wei?schuh
> > >> <thomas.weissschuh at linutronix.de> wrote:
> > >>>
> > >>> On Wed, Nov 19, 2025 at 11:13:27AM -0700, Simon Glass wrote:
> > >
> > > (...)
> > >
> > >>>>  quiet_cmd_fit = FIT     $@
> > >>>>        cmd_fit = $(MAKE_FIT) -o $@ --arch $(UIMAGE_ARCH) --os linux \
> > >>>> -             --name '$(UIMAGE_NAME)' \
> > >>>> +             --name '$(UIMAGE_NAME)' $(MAKE_FIT_FLAGS) \
> > >>>
> > >>> Remnant of a previous revision?
> > >>
> > >> The flags are there to allow extra options to be passed if needed.
> > >
> > > Are they necessary for the module functionality added here?
> > > If not I'd put them into a dedicated commit.
> > >
> > >>>
> > >>>>               $(if $(findstring 1,$(KBUILD_VERBOSE)),-v) \
> > >>>>               $(if $(FIT_DECOMPOSE_DTBS),--decompose-dtbs) \
> > >>>> +             $(if $(FIT_MODULES),--modules @$(objtree)/modules.order) \
> > >>>
> > >>> I am wondering how module dependencies work without the depmod invocation
> > >>> and modules.dep file.
> > >>
> > >> We have a mechanism to place a pre-build initrd with the filesystem,
> > >> etc. into the FIT. But for this particular feature (suggested by Ahmad
> > >> Fatoum) we are just providing the raw modules. Presumably another
> > >> initrd would be needed to provide the startup files?
> > >
> > > modules.dep is more than optional and generic startup files but an integral
> > > part of a module tree. Without it, any module depending on another module's
> > > symbols will fail to load. Also the modules will be unsigned, potentially
> > > making them unloadable.
> >
> > I'll use the occasion to elaborate a bit on why I thought adding modules
> > is a good idea.
> >
> > - You have a system boot from FIT and maybe even a r/o rootfs
> > - You want to boot a different kernel without any userspace changes,
> > e.g. to bisect
> > - Fortunately, you have a build target that generates you a FIT with
> > kernel, enabled device trees and all modules (including deps and such)
> > - In the bootloader[1], you specify that a CPIO with a minimal init[2]
> > that bindmounts /lib/modules in the initramfs over the rootfs modules
> > before pivot_root
> >
> > and that's it, you are running your new kernel with the old rootfs
> > unchanged. I believe this would be really handy, which is why I
> > suggested it.
>
> The idea sounds good.
>
> > > Ahmad's patch does produce a complete and fully
> > > functional module tree by means of 'make headers_install'.
> >
> > I originally thought that we could generate the CPIO normally as part of
> > the kernel build and then we can readily depend on it in the rule that
> > invokes make_fit.py.
>
> That works, but it is not what the patch under discussion does, or did.
>
> > If this proves to be too cumbersome, I think it's already an improvement
> > if the user can manually run make modules-cpio-pkg and then make
> > image.fit with the initrd specified. A single target would be neater of
> > course, but I didn't intend for this to stall the series.
>
> The single target idea would require 'modules-cpio-pkg' to not be a PHONY
> target anymore but to properly track dependencies. Otherwise the CPIO and FIT
> image will be rebuilt even if no sources change. Proper dependencies are always
> better than PHONY targets, but it will be a bit of additional work.
>
> > It can always follow later.
>
> Yep. But for the patch as it is proposed I am still wondering how it will work
> without modules.dep and friends.
>
> (...)

I'm going to send a v7 and perhaps Ahmad can help to refine this.
Unfortunately the modules generation has turned into a significant
detour. We can either drop it, or continue to try to resolve this.

Regards,
SImon


From andrew at lunn.ch  Thu Dec 11 05:34:30 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Thu, 11 Dec 2025 14:34:30 +0100
Subject: [PATCH] net: phy: mediatek: fix nvmem cell reference leak in
 mt798x_phy_calibration
In-Reply-To: <20251211081313.2368460-1-linmq006@gmail.com>
References: <20251211081313.2368460-1-linmq006@gmail.com>
Message-ID: <57437939-6983-4db8-9178-dd19f1c7b971@lunn.ch>

On Thu, Dec 11, 2025 at 12:13:13PM +0400, Miaoqian Lin wrote:
> When nvmem_cell_read() fails in mt798x_phy_calibration(), the function
> returns without calling nvmem_cell_put(), leaking the cell reference.
> 
> Move nvmem_cell_put() right after nvmem_cell_read() to ensure the cell
> reference is always released regardless of the read result.
> 
> Found via static analysis and code review.
> 
> Fixes: 98c485eaf509 ("net: phy: add driver for MediaTek SoC built-in GE PHYs")
> Cc: stable at vger.kernel.org
> Signed-off-by: Miaoqian Lin <linmq006 at gmail.com>

Reviewed-by: Andrew Lunn <andrew at lunn.ch>

    Andrew


From robh at kernel.org  Thu Dec 11 05:37:23 2025
From: robh at kernel.org (Rob Herring)
Date: Thu, 11 Dec 2025 07:37:23 -0600
Subject: [PATCH v8 5/8] dt-bindings: arm: add an interrupt property for
 Coresight CTCU
In-Reply-To: <20251211-enable-byte-cntr-for-ctcu-v8-5-3e12ff313191@oss.qualcomm.com>
References: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
 <20251211-enable-byte-cntr-for-ctcu-v8-5-3e12ff313191@oss.qualcomm.com>
Message-ID: <20251211133723.GA859302-robh@kernel.org>

On Thu, Dec 11, 2025 at 02:10:44PM +0800, Jie Gan wrote:
> Add an interrupt property to CTCU device. The interrupt will be triggered
> when the data size in the ETR buffer exceeds the threshold of the
> BYTECNTRVAL register. Programming a threshold in the BYTECNTRVAL register
> of CTCU device will enable the interrupt.
> 
> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
> Reviewed-by: Mike Leach <mike.leach at linaro.org>
> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
> ---
>  .../devicetree/bindings/arm/qcom,coresight-ctcu.yaml    | 17 +++++++++++++++++
>  1 file changed, 17 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
> index c969c16c21ef..90f88cc6cd3e 100644
> --- a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
> +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
> @@ -39,6 +39,16 @@ properties:
>      items:
>        - const: apb
>  
> +  interrupts:
> +    items:
> +      - description: Byte cntr interrupt for the first etr device
> +      - description: Byte cntr interrupt for the second etr device
> +
> +  interrupt-names:
> +    items:
> +      - const: etrirq0
> +      - const: etrirq1

Names are kind of pointless when it is just foo<index>.

> +
>    label:
>      description:
>        Description of a coresight device.
> @@ -60,6 +70,8 @@ additionalProperties: false
>  
>  examples:
>    - |
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +
>      ctcu at 1001000 {
>          compatible = "qcom,sa8775p-ctcu";
>          reg = <0x1001000 0x1000>;
> @@ -67,6 +79,11 @@ examples:
>          clocks = <&aoss_qmp>;
>          clock-names = "apb";
>  
> +        interrupts = <GIC_SPI 270 IRQ_TYPE_EDGE_RISING>,
> +                     <GIC_SPI 262 IRQ_TYPE_EDGE_RISING>;
> +        interrupt-names = "etrirq0",
> +                          "etrirq1;
> +
>          in-ports {
>              #address-cells = <1>;
>              #size-cells = <0>;
> 
> -- 
> 2.34.1
> 


From rebecca at bsdio.com  Thu Dec 11 05:37:17 2025
From: rebecca at bsdio.com (Rebecca Cran)
Date: Thu, 11 Dec 2025 06:37:17 -0700
Subject: [PATCH v4 0/2] Add device tree for ASRock Rack ALTRAD8 BMC
Message-ID: <20251211133721.18269-1-rebecca@bsdio.com>

The ASRock Rack ALTRAD8 BMC is an Aspeed AST2500-based BMC for the
ALTRAD8UD-1L2T and ALTRAD8UD2-1L2Q boards with an Ampere Altra
processor. The BMC runs OpenBMC.

These patches add a device tree and binding for the BMC.

**Changes between v3 and v4**

- Re-added system fault LED after verifying it works with an
  LED connected to the AUX header.
- Fixed GPIOs based on Tan's feedback.
- Dropped DT schema commit in favour of Rob's changes.

**Testing**

Ran `make ARCH=arm CHECK_DTBS=y aspeed/aspeed-bmc-asrock-altrad8.dtb`.

Rebecca Cran (2):
  dt-bindings: arm: aspeed: add ASRock Rack ALTRAD8 board
  ARM: dts: aspeed: add device tree for ASRock Rack ALTRAD8 BMC

 Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml |   1 +
 arch/arm/boot/dts/aspeed/Makefile                        |   1 +
 arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts   | 625 ++++++++++++++++++++
 3 files changed, 627 insertions(+)
 create mode 100644 arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts

-- 
2.47.3



From rebecca at bsdio.com  Thu Dec 11 05:37:18 2025
From: rebecca at bsdio.com (Rebecca Cran)
Date: Thu, 11 Dec 2025 06:37:18 -0700
Subject: [PATCH v4 1/2] dt-bindings: arm: aspeed: add ASRock Rack ALTRAD8 board
In-Reply-To: <20251211133721.18269-1-rebecca@bsdio.com>
References: <20251211133721.18269-1-rebecca@bsdio.com>
Message-ID: <20251211133721.18269-2-rebecca@bsdio.com>

Document ASRock Rack ALTRAD8 (ALTRAD8UD-1L2T and ALTRAD8UD2-1L2Q)
compatibles.

Signed-off-by: Rebecca Cran <rebecca at bsdio.com>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
 Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
index 9298c1a75dd1..aefad2d02993 100644
--- a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
+++ b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
@@ -34,6 +34,7 @@ properties:
               - amd,ethanolx-bmc
               - ampere,mtjade-bmc
               - aspeed,ast2500-evb
+              - asrock,altrad8-bmc
               - asrock,e3c246d4i-bmc
               - asrock,e3c256d4i-bmc
               - asrock,romed8hm3-bmc
-- 
2.47.3



From rebecca at bsdio.com  Thu Dec 11 05:37:19 2025
From: rebecca at bsdio.com (Rebecca Cran)
Date: Thu, 11 Dec 2025 06:37:19 -0700
Subject: [PATCH v4 2/2] ARM: dts: aspeed: add device tree for ASRock Rack ALTRAD8 BMC
In-Reply-To: <20251211133721.18269-1-rebecca@bsdio.com>
References: <20251211133721.18269-1-rebecca@bsdio.com>
Message-ID: <20251211133721.18269-3-rebecca@bsdio.com>

The ALTRAD8 BMC is an Aspeed AST2500-based BMC for the ASRock Rack
ALTRAD8UD-1L2T and ALTRAD8UD2-1L2Q boards.

Signed-off-by: Rebecca Cran <rebecca at bsdio.com>
---
 arch/arm/boot/dts/aspeed/Makefile                      |   1 +
 arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts | 625 ++++++++++++++++++++
 2 files changed, 626 insertions(+)

diff --git a/arch/arm/boot/dts/aspeed/Makefile b/arch/arm/boot/dts/aspeed/Makefile
index 9adf9278dc94..f073f126ddac 100644
--- a/arch/arm/boot/dts/aspeed/Makefile
+++ b/arch/arm/boot/dts/aspeed/Makefile
@@ -9,6 +9,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \
 	aspeed-bmc-ampere-mtjefferson.dtb \
 	aspeed-bmc-ampere-mtmitchell.dtb \
 	aspeed-bmc-arm-stardragon4800-rep2.dtb \
+	aspeed-bmc-asrock-altrad8.dtb \
 	aspeed-bmc-asrock-e3c246d4i.dtb \
 	aspeed-bmc-asrock-e3c256d4i.dtb \
 	aspeed-bmc-asrock-romed8hm3.dtb \
diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts
new file mode 100644
index 000000000000..b60046fd214b
--- /dev/null
+++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts
@@ -0,0 +1,625 @@
+// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+
+#include "aspeed-g5.dtsi"
+#include <dt-bindings/gpio/aspeed-gpio.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/i2c/i2c.h>
+
+/ {
+	model = "ASRock ALTRAD8 BMC";
+	compatible = "asrock,altrad8-bmc", "aspeed,ast2500";
+
+	aliases {
+		serial4 = &uart5;
+		i2c50 = &nvme1;
+		i2c51 = &pcie4;
+		i2c52 = &pcie5;
+		i2c53 = &pcie6;
+		i2c54 = &pcie7;
+		i2c55 = &nvme3;
+		i2c56 = &nvme2;
+		i2c57 = &nvme0;
+		i2c58 = &nvme4;
+		i2c59 = &nvme5;
+		i2c60 = &nvme6;
+		i2c61 = &nvme7;
+		i2c62 = &nvme8;
+		i2c63 = &nvme9;
+		i2c64 = &nvme10;
+		i2c65 = &nvme11;
+	};
+
+	chosen {
+		stdout-path = "uart5:115200n8";
+	};
+
+	iio-hwmon {
+		compatible = "iio-hwmon";
+		io-channels =	<&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>,
+				<&adc 4> ,<&adc 5>, <&adc 6>, <&adc 7>,
+				<&adc 8>, <&adc 9>, <&adc 10>, <&adc 11>,
+				<&adc 12>, <&adc 13>, <&adc 14>, <&adc 15>;
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		led-system-fault {
+			gpios = <&gpio ASPEED_GPIO(G,3) GPIO_ACTIVE_LOW>;
+			label = "platform:red:fault";
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_FAULT;
+		};
+
+		led-heartbeat {
+			gpios = <&gpio ASPEED_GPIO(G,0) GPIO_ACTIVE_LOW>;
+			label = "platform:green:heartbeat";
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_INDICATOR;
+			linux,default-trigger = "timer";
+		};
+
+		led-fan1-fault {
+			retain-state-shutdown;
+			default-state = "off";
+			gpios = <&io_expander0 0 GPIO_ACTIVE_LOW>;
+			label = "fan1:red:fault";
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_FAULT;
+		};
+
+		led-fan2-fault {
+			retain-state-shutdown;
+			default-state = "off";
+			gpios = <&io_expander0 1 GPIO_ACTIVE_LOW>;
+			label = "fan2:red:fault";
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_FAULT;
+		};
+
+		led-fan3-fault {
+			retain-state-shutdown;
+			default-state = "off";
+			gpios = <&io_expander0 2 GPIO_ACTIVE_LOW>;
+			label = "fan3:red:fault";
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_FAULT;
+		};
+
+		led-fan4-fault {
+			retain-state-shutdown;
+			default-state = "off";
+			gpios = <&io_expander0 3 GPIO_ACTIVE_LOW>;
+			label = "fan4:red:fault";
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_FAULT;
+		};
+
+		led-fan5-fault {
+			retain-state-shutdown;
+			default-state = "off";
+			gpios = <&io_expander0 4 GPIO_ACTIVE_LOW>;
+			label = "fan5:red:fault";
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_FAULT;
+		};
+	};
+
+	memory at 80000000 {
+		reg = <0x80000000 0x20000000>;
+	};
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		gfx_memory: framebuffer {
+			compatible = "shared-dma-pool";
+			size = <0x01000000>;
+			alignment = <0x01000000>;
+			reusable;
+		};
+
+		vga_memory: framebuffer at 9f000000 {
+			no-map;
+			reg = <0x9f000000 0x01000000>; /* 16M */
+		};
+
+		video_engine_memory: jpegbuffer {
+			compatible = "shared-dma-pool";
+			size = <0x02000000>;	/* 32M */
+			alignment = <0x01000000>;
+			reusable;
+		};
+	};
+};
+
+&adc {
+	status = "okay";
+};
+
+&fmc {
+	status = "okay";
+
+	flash at 0 {
+		label = "bmc";
+		m25p,fast-read;
+		spi-max-frequency = <50000000>;
+		status = "okay";
+#include "openbmc-flash-layout-64.dtsi"
+	};
+};
+
+&gfx {
+	memory-region = <&gfx_memory>;
+	status = "okay";
+};
+
+&gpio {
+	gpio-line-names =
+	/*A0-A7*/	"","","","bmc-ready","","","","",
+	/*B0-B7*/	"i2c-backup-sel","","","","","","","host0-shd-ack-n",
+	/*C0-C7*/	"","","","","","","","",
+	/*D0-D7*/	"power-button-n","control-power-n","button-reset-n",
+			"host0-sysreset-n","","","power-chassis-good","",
+	/*E0-E7*/	"","s0-vrd1-vddq0123-fault-n",
+			"s0-vrd1-vddq4567-fault-n","s0-vrd0-vddc-fault-n",
+			"s0-vrd3-p0v75-fault-n","","","",
+	/*F0-F7*/	"","","ps-atx-on-n","","","","","",
+	/*G0-G7*/	"led-bmc-heartbeat-n","button-identify-n","",\
+			"led-system-fault-n","uboot-ready","bmc-salt2-n","","",
+	/*H0-H7*/	"ps-pwr-ok","uart1-mode1","uart2-mode1","uart3-mode1",
+			"uart4-mode1","","led-bmc-heartbeat","",
+	/*I0-I7*/	"","","","","","","","",
+	/*J0-J7*/	"s0-hightemp-n","","","","","","","",
+	/*K0-K7*/	"","","","","","","","",
+	/*L0-L7*/	"","","","","","","","",
+	/*M0-M7*/	"cpld-disable-bmc-n","","","","","s0-spi-auth-fail-n","","",
+	/*N0-N7*/	"","","","","","","","",
+	/*O0-O7*/	"","","","","","","","",
+	/*P0-P7*/	"","","","","","","","",
+	/*Q0-Q7*/	"","","","","","","led-identify-n",
+			"chassis-intrusion-n",
+	/*R0-R7*/	"","","ext-hightemp-n","spi0-program-sel","",
+			"output-hwm-bat-en","","",
+	/*S0-S7*/	"s0-vr-hot-n","","input-salt2-n","bmc-sysreset-n","","","","",
+	/*T0-T7*/	"","","","","","","","",
+	/*U0-U7*/	"","","","","","","","",
+	/*V0-V7*/	"","","","","","","","",
+	/*W0-W7*/	"","","","","","","","",
+	/*X0-X7*/	"","","","","","","","",
+	/*Y0-Y7*/	"","","","","","","","",
+	/*Z0-Z7*/	"","","","s0-rtc-lock","","","","",
+	/*AA0-AA7*/	"s0-rtc-int-n","","","","","pmbus-sel-n","","",
+	/*AB0-AB7*/	"host0-reboot-ack-n","s0-sys-auth-failure-n",
+			"","","","","","",
+	/*AC0-AC7*/	"s0-fault-alert","host0-ready","s0-overtemp-n",
+			"","bmc-ok","host0-special-boot","presence-cpu0",
+			"host0-shd-req-n";
+
+	status = "okay";
+};
+
+&i2c0 {
+	status = "okay";
+
+	ipmb at 10 {
+		compatible = "ipmb-dev";
+		reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>;
+		i2c-protocol;
+	};
+
+};
+
+&i2c1 {
+	status = "okay";
+
+	i2c-mux1 at 73 {
+		compatible = "nxp,pca9548";
+		reg = <0x73>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		nvme1: i2c at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+		};
+
+		pcie4: i2c at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+		};
+
+		pcie5: i2c at 2 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2>;
+		};
+
+		pcie6: i2c at 3 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <3>;
+		};
+
+		pcie7: i2c at 4 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <4>;
+		};
+
+		nvme3: i2c at 5 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <5>;
+		};
+
+		nvme2: i2c at 6 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <6>;
+		};
+
+		nvme0: i2c at 7 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <7>;
+		};
+	};
+
+	i2c-mux2 at 75 {
+		compatible = "nxp,pca9548";
+		reg = <0x75>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		nvme4: i2c at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+		};
+
+		nvme5: i2c at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+		};
+
+		nvme6: i2c at 2 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2>;
+		};
+
+		nvme7: i2c at 3 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <3>;
+		};
+
+		nvme8: i2c at 4 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <4>;
+		};
+
+		nvme9: i2c at 5 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <5>;
+		};
+
+		nvme10: i2c at 6 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <6>;
+		};
+
+		nvme11: i2c at 7 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <7>;
+		};
+	};
+};
+
+&i2c2 {
+	status = "okay";
+
+	smpro at 4f {
+		compatible = "ampere,smpro";
+		reg = <0x4f>;
+	};
+};
+
+&i2c3 {
+	status = "okay";
+
+	// PSU FRU
+	eeprom at 38 {
+		compatible = "atmel,24c02";
+		reg = <0x38>;
+	};
+};
+
+&i2c4 {
+	status = "okay";
+
+	temperature-sensor at 29 {
+		compatible = "nuvoton,nct7802";
+		reg = <0x29>;
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		channel at 0 { /* LTD */
+			reg = <0>;
+			status = "okay";
+		};
+
+		channel at 1 { /* RTD1 */
+			reg = <1>;
+			sensor-type = "temperature";
+			temperature-mode = "thermistor";
+		};
+
+		channel at 2 { /* RTD2 */
+			reg = <2>;
+			sensor-type = "temperature";
+			temperature-mode = "thermal-diode";
+		};
+	};
+
+	temperature-sensor at 4c {
+		compatible = "nuvoton,w83773g";
+		reg = <0x4c>;
+	};
+};
+
+&i2c5 {
+	status = "okay";
+};
+
+&i2c6 {
+	status = "okay";
+
+	rtc at 6f {
+		compatible = "isil,isl1208";
+		reg = <0x6f>;
+	};
+};
+
+&i2c7 {
+	status = "okay";
+
+	// BMC FRU
+	eeprom at 57 {
+		compatible = "atmel,24c128";
+		reg = <0x57>;
+
+		nvmem-layout {
+			compatible = "fixed-layout";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			eth1_macaddress: macaddress at 3f80 {
+				reg = <0x3f80 6>;
+			};
+
+			// The offset for eth0 really is at 0x3f88.
+			// eth0 and eth1 are swapped from what might be
+			// expected.
+			eth0_macaddress: macaddress at 3f88 {
+				reg = <0x3f88 6>;
+			};
+		};
+	};
+};
+
+&i2c8 {
+	status = "okay";
+
+	io_expander0: gpio at 1c {
+		compatible = "nxp,pca9557";
+		reg = <0x1c>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+};
+
+&i2c9 {
+	status = "okay";
+};
+
+&i2c10 {
+	status = "okay";
+};
+
+&i2c11 {
+	status = "okay";
+};
+
+// Bus for accessing the SCP EEPROM
+&i2c12 {
+	status = "okay";
+};
+
+&i2c13 {
+	status = "okay";
+
+	ssif-bmc at 10 {
+		compatible = "ssif-bmc";
+		reg = <0x10>;
+	};
+};
+
+// Connected to host Intel X550 (ALTRAD8UD-1L2T) or
+// Broadcom BCM57414 (ALTRAD8UD2-1L2Q) interface.
+// Unconnected on ALTRAD8UD-1L
+&mac0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_rmii1_default>;
+	clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+		 <&syscon ASPEED_CLK_MAC1RCLK>;
+	clock-names = "MACCLK", "RCLK";
+	use-ncsi;
+	nvmem-cells = <&eth0_macaddress>;
+	nvmem-cell-names = "mac-address";
+
+	status = "okay";
+};
+
+// Connected to Realtek RTL8211E
+&mac1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>;
+
+	nvmem-cells = <&eth1_macaddress>;
+	nvmem-cell-names = "mac-address";
+
+	status = "okay";
+};
+
+&pinctrl {
+	aspeed,external-nodes = <&gfx &lhc>;
+};
+
+&pwm_tacho {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pwm0_default
+			&pinctrl_pwm1_default
+			&pinctrl_pwm2_default
+			&pinctrl_pwm3_default
+			&pinctrl_pwm4_default
+			&pinctrl_pwm5_default
+			&pinctrl_pwm6_default
+			&pinctrl_pwm7_default>;
+
+	status = "okay";
+
+	fan at 0 {
+		reg = <0x00>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x00 0x08>;
+	};
+
+	fan at 1 {
+		reg = <0x01>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x01 0x09>;
+	};
+
+	fan at 2 {
+		reg = <0x02>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x02 0x0a>;
+	};
+
+	fan at 3 {
+		reg = <0x03>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x03 0x0b>;
+	};
+
+	fan at 4 {
+		reg = <0x04>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x04 0x0c>;
+	};
+
+	fan at 5 {
+		reg = <0x05>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x05 0x0d>;
+	};
+
+	fan at 6 {
+		reg = <0x06>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x06 0x0e>;
+	};
+
+	fan at 7 {
+		reg = <0x07>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x07 0x0f>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_spi1_default>;
+
+	status = "okay";
+
+	// Host BIOS/UEFI EEPROM
+	flash at 0 {
+		m25p,fast-read;
+		label = "pnor";
+		spi-max-frequency = <100000000>;
+		status = "okay";
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			tfa at 400000 {
+				reg = <0x400000 0x200000>;
+				label = "pnor-tfa";
+			};
+
+			uefi at 600000 {
+				reg = <0x600000 0x1A00000>;
+				label = "pnor-uefi";
+			};
+		};
+	};
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_txd1_default
+			 &pinctrl_rxd1_default
+			 &pinctrl_ncts1_default
+			 &pinctrl_nrts1_default>;
+
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_txd2_default
+			&pinctrl_rxd2_default>;
+
+	status = "okay";
+};
+
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_txd3_default
+			&pinctrl_rxd3_default>;
+
+	status = "okay";
+};
+
+&uart4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_txd4_default
+			&pinctrl_rxd4_default>;
+
+	status = "okay";
+};
+
+// The BMC's uart
+&uart5 {
+	status = "okay";
+};
+
+&vhub {
+	status = "okay";
+};
+
+&video {
+	memory-region = <&video_engine_memory>;
+
+	status = "okay";
+};
-- 
2.47.3



From tabba at google.com  Thu Dec 11 05:37:50 2025
From: tabba at google.com (Fuad Tabba)
Date: Thu, 11 Dec 2025 13:37:50 +0000
Subject: [PATCH v2 1/6] KVM: arm64: Fix EL2 S1 XN handling for hVHE setups
In-Reply-To: <20251210173024.561160-2-maz@kernel.org>
References: <20251210173024.561160-1-maz@kernel.org> <20251210173024.561160-2-maz@kernel.org>
Message-ID: <CA+EHjTwh=Vop_v5+2_wj57Y-Wg=Q12aw7hUYdNB2CGA4Kq0ZKQ@mail.gmail.com>

Hi Marc,


On Wed, 10 Dec 2025 at 17:30, Marc Zyngier <maz at kernel.org> wrote:
>
> The current XN implementation is tied to the EL2 translation regime,
> and fall flat on its face with the EL2&0 one that is used for hVHE,
> as the permission bit for privileged execution is a different one.
>
> Fixes: 6537565fd9b7f ("KVM: arm64: Adjust EL2 stage-1 leaf AP bits when ARM64_KVM_HVHE is set")
> Signed-off-by: Marc Zyngier <maz at kernel.org>
> ---
>  arch/arm64/include/asm/kvm_pgtable.h | 10 +++++++++-
>  1 file changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h
> index fc02de43c68dd..be68b89692065 100644
> --- a/arch/arm64/include/asm/kvm_pgtable.h
> +++ b/arch/arm64/include/asm/kvm_pgtable.h
> @@ -87,7 +87,15 @@ typedef u64 kvm_pte_t;
>
>  #define KVM_PTE_LEAF_ATTR_HI_SW                GENMASK(58, 55)
>
> -#define KVM_PTE_LEAF_ATTR_HI_S1_XN     BIT(54)
> +#define __KVM_PTE_LEAF_ATTR_HI_S1_XN   BIT(54)
> +#define __KVM_PTE_LEAF_ATTR_HI_S1_UXN  BIT(54)
> +#define __KVM_PTE_LEAF_ATTR_HI_S1_PXN  BIT(53)
> +
> +#define KVM_PTE_LEAF_ATTR_HI_S1_XN                                     \
> +       ({ cpus_have_final_cap(ARM64_KVM_HVHE) ?                        \
> +                       (__KVM_PTE_LEAF_ATTR_HI_S1_UXN |                \
> +                        __KVM_PTE_LEAF_ATTR_HI_S1_PXN) :               \
> +                       __KVM_PTE_LEAF_ATTR_HI_S1_XN; })
>
>  #define KVM_PTE_LEAF_ATTR_HI_S2_XN     GENMASK(54, 53)

I was just wondering, is this patch really necessary, considering
patch 6/6 redos the whole thing and fixes the bug?

That said:
Reviewed-by: Fuad Tabba <tabba at google.com>

Cheers,
/fuad

> --
> 2.47.3
>


From tabba at google.com  Thu Dec 11 05:38:00 2025
From: tabba at google.com (Fuad Tabba)
Date: Thu, 11 Dec 2025 13:38:00 +0000
Subject: [PATCH v2 2/6] arm64: Convert ID_AA64MMFR0_EL1.TGRAN{4,16,64}_2
 to UnsignedEnum
In-Reply-To: <20251210173024.561160-3-maz@kernel.org>
References: <20251210173024.561160-1-maz@kernel.org> <20251210173024.561160-3-maz@kernel.org>
Message-ID: <CA+EHjTwNVxPz6rZ0d59_qz1Szpe6gRCyLa094Wi6sinbzAJ8iw@mail.gmail.com>

Hi Marc,

On Wed, 10 Dec 2025 at 17:30, Marc Zyngier <maz at kernel.org> wrote:
>
> ID_AA64MMFR0_EL1.TGRAN{4,16,64}_2 are currently represented as unordered
> enumerations. However, the architecture treats them as Unsigned,
> as hinted to by the MRS data:
>
> (FEAT_S2TGran4K <=> (((UInt(ID_AA64MMFR0_EL1.TGran4_2) == 0) &&
>                        FEAT_TGran4K) ||
>                      (UInt(ID_AA64MMFR0_EL1.TGran4_2) >= 2))))
>
> and similar descriptions exist for 16 and 64k.
>
> This is also confirmed by D24.1.3.3 ("Alternative ID scheme used for
> ID_AA64MMFR0_EL1 stage 2 granule sizes") in the L.b revision of
> the ARM ARM.
>
> Turn these fields into UnsignedEnum so that we can use the above
> description more or less literally.
>
> Signed-off-by: Marc Zyngier <maz at kernel.org>
> ---

Reviewed-by: Fuad Tabba <tabba at google.com>

Cheers,
/fuad


>  arch/arm64/tools/sysreg | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
> index 1c6cdf9d54bba..9d388f87d9a13 100644
> --- a/arch/arm64/tools/sysreg
> +++ b/arch/arm64/tools/sysreg
> @@ -2098,18 +2098,18 @@ UnsignedEnum    47:44   EXS
>         0b0000  NI
>         0b0001  IMP
>  EndEnum
> -Enum   43:40   TGRAN4_2
> +UnsignedEnum   43:40   TGRAN4_2
>         0b0000  TGRAN4
>         0b0001  NI
>         0b0010  IMP
>         0b0011  52_BIT
>  EndEnum
> -Enum   39:36   TGRAN64_2
> +UnsignedEnum   39:36   TGRAN64_2
>         0b0000  TGRAN64
>         0b0001  NI
>         0b0010  IMP
>  EndEnum
> -Enum   35:32   TGRAN16_2
> +UnsignedEnum   35:32   TGRAN16_2
>         0b0000  TGRAN16
>         0b0001  NI
>         0b0010  IMP
> --
> 2.47.3
>


From nirmoyd at nvidia.com  Thu Dec 11 05:39:33 2025
From: nirmoyd at nvidia.com (Nirmoy Das)
Date: Thu, 11 Dec 2025 05:39:33 -0800
Subject: [RFC PATCH] iommu/arm-smmu-v3: Allow stream ID sharing for devices behind PCIe-to-PCI bridges
Message-ID: <20251211133933.4128100-1-nirmoyd@nvidia.com>

ASPEED BMC controllers have VGA and USB functions behind a PCIe-to-PCI
bridge that causes them to share the same stream ID:

  \-[0005:e0]---00.0-[e1-e2]----00.0-[e2]--+-00.0  ASPEED Graphics Family
                                           \-02.0  ASPEED USB Controller

Both devices get stream ID(0x5e200) due to bridge aliasing. Currently this
USB controller gets rejected with "Aliasing StreamID unsupported", causing
USB timeout errors. Allow stream ID sharing when both devices are on
the same bus behind a PCIe-to-PCI bridge to fix this issue.

Signed-off-by: Nirmoy Das <nirmoyd at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 2a8b46b948f05..411b8803eb46f 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -3480,6 +3480,17 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
 			if (existing_master == master)
 				continue;

+			/* Allow PCI devices on the same bus to share stream IDs
+			 * due to PCIe-to-PCI bridge aliasing.
+			 */
+			if (dev_is_pci(master->dev) && dev_is_pci(existing_master->dev)) {
+				struct pci_dev *pdev = to_pci_dev(master->dev);
+				struct pci_dev *existing_pdev = to_pci_dev(existing_master->dev);
+
+				if (pdev->bus == existing_pdev->bus)
+					continue;
+			}
+
 			dev_warn(master->dev,
 				 "Aliasing StreamID 0x%x (from %s) unsupported, expect DMA to be broken\n",
 				 sid, dev_name(existing_master->dev));
--
2.43.0



From ben.horgan at arm.com  Thu Dec 11 05:41:06 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Thu, 11 Dec 2025 13:41:06 +0000
Subject: [RFC PATCH 04/38] arm64: mpam: Add cpu_pm notifier to restore
 MPAM sysregs
In-Reply-To: <20251205215901.17772-5-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-5-james.morse@arm.com>
Message-ID: <a9e70c54-318a-43d3-b5d8-2d102390c363@arm.com>

Hi James,

On 12/5/25 21:58, James Morse wrote:
> The MPAM system registers will be lost if the CPU is reset during
> PSCI's CPU_SUSPEND.
> 
> Add a PM notifier to restore them.
> 
> mpam_thread_switch(current) can't be used as this won't make any
> changes if the in-memory copy says the register already has the
> correct value. In reality the system register is UNKNOWN out of reset.

If CONFIG_ARM64_MPAM is not enabled then the PM notifier is never
registered but the MPAMx_ELy will still come out of reset with UNKNOWN
values and we need to set the PARTID values back to 0 as the MSC are
only guaranteed to provide good defaults for that value. (We aren't
using the MPAM driver to initialise the other PARTID.)

> 
> Signed-off-by: James Morse <james.morse at arm.com>
> ---
>  arch/arm64/kernel/mpam.c | 30 ++++++++++++++++++++++++++++++
>  1 file changed, 30 insertions(+)
> 
> diff --git a/arch/arm64/kernel/mpam.c b/arch/arm64/kernel/mpam.c
> index e6feff2324ac..dbe0a2d05abb 100644
> --- a/arch/arm64/kernel/mpam.c
> +++ b/arch/arm64/kernel/mpam.c
> @@ -4,6 +4,7 @@
>  #include <asm/mpam.h>
>  
>  #include <linux/arm_mpam.h>
> +#include <linux/cpu_pm.h>
>  #include <linux/jump_label.h>
>  #include <linux/percpu.h>
>  
> @@ -13,12 +14,41 @@ DEFINE_PER_CPU(u64, arm64_mpam_current);
>  
>  u64 arm64_mpam_global_default;
>  
> +static int mpam_pm_notifier(struct notifier_block *self,
> +			    unsigned long cmd, void *v)
> +{
> +	u64 regval;
> +	int cpu = smp_processor_id();
> +
> +	switch (cmd) {
> +	case CPU_PM_EXIT:
> +		/*
> +		 * Don't use mpam_thread_switch() as the system register
> +		 * value has changed under our feet.
> +		 */
> +		regval = READ_ONCE(per_cpu(arm64_mpam_current, cpu));
> +		write_sysreg_s(regval, SYS_MPAM1_EL1);
> +		isb();
> +
> +		write_sysreg_s(regval, SYS_MPAM0_EL1);
> +
> +		return NOTIFY_OK;
> +	default:
> +		return NOTIFY_DONE;
> +	}
> +}
> +
> +static struct notifier_block mpam_pm_nb = {
> +	.notifier_call = mpam_pm_notifier,
> +};
> +
>  static int __init arm64_mpam_register_cpus(void)
>  {
>  	u64 mpamidr = read_sanitised_ftr_reg(SYS_MPAMIDR_EL1);
>  	u16 partid_max = FIELD_GET(MPAMIDR_EL1_PARTID_MAX, mpamidr);
>  	u8 pmg_max = FIELD_GET(MPAMIDR_EL1_PMG_MAX, mpamidr);
>  
> +	cpu_pm_register_notifier(&mpam_pm_nb);
>  	return mpam_register_requestor(partid_max, pmg_max);
>  }
>  /* Must occur before mpam_msc_driver_init() from subsys_initcall() */

Thanks,

Ben



From sudeep.holla at arm.com  Thu Dec 11 05:48:25 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Thu, 11 Dec 2025 13:48:25 +0000
Subject: [PATCH 1/1] firmware: arm_scmi: Increase MAX_OPPS to 64
In-Reply-To: <DEVEXHI9CEFA.19RL3BXTV8E38@linaro.org>
References: <20251014073454.461999-1-vivek.aknurwar@oss.qualcomm.com>
 <6af5945e-7d5c-4596-ac42-c5898b4c49b7@oss.qualcomm.com>
 <DEVEXHI9CEFA.19RL3BXTV8E38@linaro.org>
Message-ID: <20251211-masterful-caterpillar-of-love-bc2d4c@sudeepholla>

On Thu, Dec 11, 2025 at 01:14:06PM +0000, Alexey Klimov wrote:
> > On 10/14/2025 12:34 AM, Vivek Aknurwar wrote:
> >> Some upcoming SoCs define more than 32 operating performance points (OPPs),
> >> exceeding the current SCMI protocol limit. Increase MAX_OPPS to 64
> >> (next power of 2) to support these configurations.
> 
> Didn't touch for a while. The way it is stated confuses me a bit.
> Should the value defined by protocol be updated out of the blue?
> Should the protocol (defined by spec) be changed first?
> 

Ah good point on confusing commit message. I just assumed it is limitation
of the implementation. I can update the log when applying. It is not spec
or protocol limitation for sure.

How about this ?

  | firmware: arm_scmi: Increase performance MAX_OPPS limit to 64
  |
  | Some platforms expose more than 32 operating performance points (OPPs)
  | per performance domain via the SCMI performance protocol, but the
  | driver currently limits the number of OPPs it can handle to 32 via
  | MAX_OPPS.
  |
  | Bump MAX_OPPS to 64 so that these platforms can register all their
  | performance levels. This is an internal limit in the driver only and
  | does not affect the SCMI protocol ABI.
  |
  | 64 is chosen as the next power of two above the existing limit.


-- 
Regards,
Sudeep


From a.fatoum at pengutronix.de  Thu Dec 11 05:49:42 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Thu, 11 Dec 2025 14:49:42 +0100
Subject: [PATCH v6 6/8] kbuild: Allow adding modules into the FIT ramdisk
In-Reply-To: <CAFLszTh3sM3AEW2MVvR-3szkEtvgnNMsWUcwH6AgBa+KThNF7w@mail.gmail.com>
References: <20251119181333.991099-1-sjg@chromium.org>
 <20251119181333.991099-7-sjg@chromium.org>
 <20251120084201-53a3c98f-6a3c-4116-8635-be67d58fd57b@linutronix.de>
 <CAFLszTjsgkPV_-Si79RY5T_Fxd5+f-b1VbpG11uS3E9Lk4Ofmg@mail.gmail.com>
 <20251126080620-921e6880-cacf-44c5-bd8b-f380fbb8090a@linutronix.de>
 <28e18785-1336-4fbc-9f2b-69aa6bb06375@pengutronix.de>
 <20251202112039-b03af7ec-ae06-41ab-914b-703940cc98a2@linutronix.de>
 <CAFLszTh3sM3AEW2MVvR-3szkEtvgnNMsWUcwH6AgBa+KThNF7w@mail.gmail.com>
Message-ID: <a7c0306e-4799-4c5c-a72c-367298e3fe3e@pengutronix.de>

Hi Simon,

On 12/11/25 2:31 PM, Simon Glass wrote:
> Hi Thomas,
> 
> On Tue, 2 Dec 2025 at 03:31, Thomas Wei?schuh
> <thomas.weissschuh at linutronix.de> wrote:
>>
>> On Wed, Nov 26, 2025 at 12:26:49PM +0100, Ahmad Fatoum wrote:
>>> On 11/26/25 8:16 AM, Thomas Wei?schuh wrote:
>>>> On Tue, Nov 25, 2025 at 02:58:12PM -0700, Simon Glass wrote:
>>>>> On Thu, 20 Nov 2025 at 00:49, Thomas Wei?schuh
>>>>> <thomas.weissschuh at linutronix.de> wrote:
>>>>>>
>>>>>> On Wed, Nov 19, 2025 at 11:13:27AM -0700, Simon Glass wrote:
>>>>
>>>> (...)
>>>>
>>>>>>>  quiet_cmd_fit = FIT     $@
>>>>>>>        cmd_fit = $(MAKE_FIT) -o $@ --arch $(UIMAGE_ARCH) --os linux \
>>>>>>> -             --name '$(UIMAGE_NAME)' \
>>>>>>> +             --name '$(UIMAGE_NAME)' $(MAKE_FIT_FLAGS) \
>>>>>>
>>>>>> Remnant of a previous revision?
>>>>>
>>>>> The flags are there to allow extra options to be passed if needed.
>>>>
>>>> Are they necessary for the module functionality added here?
>>>> If not I'd put them into a dedicated commit.
>>>>
>>>>>>
>>>>>>>               $(if $(findstring 1,$(KBUILD_VERBOSE)),-v) \
>>>>>>>               $(if $(FIT_DECOMPOSE_DTBS),--decompose-dtbs) \
>>>>>>> +             $(if $(FIT_MODULES),--modules @$(objtree)/modules.order) \
>>>>>>
>>>>>> I am wondering how module dependencies work without the depmod invocation
>>>>>> and modules.dep file.
>>>>>
>>>>> We have a mechanism to place a pre-build initrd with the filesystem,
>>>>> etc. into the FIT. But for this particular feature (suggested by Ahmad
>>>>> Fatoum) we are just providing the raw modules. Presumably another
>>>>> initrd would be needed to provide the startup files?
>>>>
>>>> modules.dep is more than optional and generic startup files but an integral
>>>> part of a module tree. Without it, any module depending on another module's
>>>> symbols will fail to load. Also the modules will be unsigned, potentially
>>>> making them unloadable.
>>>
>>> I'll use the occasion to elaborate a bit on why I thought adding modules
>>> is a good idea.
>>>
>>> - You have a system boot from FIT and maybe even a r/o rootfs
>>> - You want to boot a different kernel without any userspace changes,
>>> e.g. to bisect
>>> - Fortunately, you have a build target that generates you a FIT with
>>> kernel, enabled device trees and all modules (including deps and such)
>>> - In the bootloader[1], you specify that a CPIO with a minimal init[2]
>>> that bindmounts /lib/modules in the initramfs over the rootfs modules
>>> before pivot_root
>>>
>>> and that's it, you are running your new kernel with the old rootfs
>>> unchanged. I believe this would be really handy, which is why I
>>> suggested it.
>>
>> The idea sounds good.
>>
>>>> Ahmad's patch does produce a complete and fully
>>>> functional module tree by means of 'make headers_install'.
>>>
>>> I originally thought that we could generate the CPIO normally as part of
>>> the kernel build and then we can readily depend on it in the rule that
>>> invokes make_fit.py.
>>
>> That works, but it is not what the patch under discussion does, or did.
>>
>>> If this proves to be too cumbersome, I think it's already an improvement
>>> if the user can manually run make modules-cpio-pkg and then make
>>> image.fit with the initrd specified. A single target would be neater of
>>> course, but I didn't intend for this to stall the series.
>>
>> The single target idea would require 'modules-cpio-pkg' to not be a PHONY
>> target anymore but to properly track dependencies. Otherwise the CPIO and FIT
>> image will be rebuilt even if no sources change. Proper dependencies are always
>> better than PHONY targets, but it will be a bit of additional work.
>>
>>> It can always follow later.
>>
>> Yep. But for the patch as it is proposed I am still wondering how it will work
>> without modules.dep and friends.
>>
>> (...)
> 
> I'm going to send a v7 and perhaps Ahmad can help to refine this.
> Unfortunately the modules generation has turned into a significant
> detour. We can either drop it, or continue to try to resolve this.

I'd suggest to drop it and tackle that separately.

Sorry for the inconvenience,
Ahmad

> 
> Regards,
> SImon
> 

-- 
Pengutronix e.K.                  |                             |
Steuerwalder Str. 21              | http://www.pengutronix.de/  |
31137 Hildesheim, Germany         | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686  | Fax:   +49-5121-206917-5555 |



From alexey.klimov at linaro.org  Thu Dec 11 05:54:01 2025
From: alexey.klimov at linaro.org (Alexey Klimov)
Date: Thu, 11 Dec 2025 13:54:01 +0000
Subject: [PATCH 1/1] firmware: arm_scmi: Increase MAX_OPPS to 64
In-Reply-To: <20251211-masterful-caterpillar-of-love-bc2d4c@sudeepholla>
References: <20251014073454.461999-1-vivek.aknurwar@oss.qualcomm.com>
 <6af5945e-7d5c-4596-ac42-c5898b4c49b7@oss.qualcomm.com>
 <DEVEXHI9CEFA.19RL3BXTV8E38@linaro.org>
 <20251211-masterful-caterpillar-of-love-bc2d4c@sudeepholla>
Message-ID: <DEVFS1MAP8J6.2263USIPE4Y74@linaro.org>

On Thu Dec 11, 2025 at 1:48 PM GMT, Sudeep Holla wrote:
> On Thu, Dec 11, 2025 at 01:14:06PM +0000, Alexey Klimov wrote:
>> > On 10/14/2025 12:34 AM, Vivek Aknurwar wrote:
>> >> Some upcoming SoCs define more than 32 operating performance points (OPPs),
>> >> exceeding the current SCMI protocol limit. Increase MAX_OPPS to 64
>> >> (next power of 2) to support these configurations.
>> 
>> Didn't touch for a while. The way it is stated confuses me a bit.
>> Should the value defined by protocol be updated out of the blue?
>> Should the protocol (defined by spec) be changed first?
>> 
>
> Ah good point on confusing commit message. I just assumed it is limitation
> of the implementation. I can update the log when applying. It is not spec
> or protocol limitation for sure.
>
> How about this ?
>
>   | firmware: arm_scmi: Increase performance MAX_OPPS limit to 64
>   |
>   | Some platforms expose more than 32 operating performance points (OPPs)
>   | per performance domain via the SCMI performance protocol, but the
>   | driver currently limits the number of OPPs it can handle to 32 via
>   | MAX_OPPS.
>   |
>   | Bump MAX_OPPS to 64 so that these platforms can register all their
>   | performance levels. This is an internal limit in the driver only and
>   | does not affect the SCMI protocol ABI.
>   |
>   | 64 is chosen as the next power of two above the existing limit.

Yeah, that sounds better :)

I also thought that this was a driver limitation, not the protocol/spec one
as stated in the original patch.

I don't mind updating the commit message like this (but I am not the author
of the original patch).

Best regards,
Alexey



From sjg at chromium.org  Thu Dec 11 06:02:57 2025
From: sjg at chromium.org (Simon Glass)
Date: Thu, 11 Dec 2025 07:02:57 -0700
Subject: [PATCH v7 0/6] scripts/make_fit: Support ramdisks and faster operations
Message-ID: <20251211140309.1910613-1-sjg@chromium.org>

This series updates 'make image.fit' to support adding a ramdisk to the
FIT, provided as a parameter.

It also includes a few performance improvement, so that building a FIT
from ~450MB of kernel/module/devicetree files only takes a few seconds
on a modern machine.

For this version I have dropped inclusion of built modules, as there is
still more discussion to happen in that area.

Changes in v7:
- Add a note about the " -> ' change
- Add a new patch with the MAKE_FIT_FLAGS change
- Mention xz as well, in the commit message
- Drop patch 'scripts/make_fit: Provide a way to add built modules'
- Drop patch 'kbuild: Split out module targets into a variable'
- Drop patch 'kbuild: Allow adding modules into the FIT ramdisk'

Changes in v6:
- Drop the load address for ramdisk, as it is not needed
- Bring back the ramdisk 'compression' property, set to 'none'

Changes in v5:
- Fix 'use' typo

Changes in v4:
- Update the commit message

Changes in v3:
- Move the ramdisk chunk into the correct patch
- Add a comment at the top of the file about the -r option
- Count the ramdisk in the total files
- Update the commit message

Changes in v2:
- Don't compress the ramdisk as it is already compressed

Simon Glass (6):
  scripts/make_fit: Speed up operation
  scripts/make_fit: Support an initial ramdisk
  scripts/make_fit: Move dtb processing into a function
  kbuild: Support a MAKE_FIT_FLAGS environment variable
  scripts/make_fit: Support a few more parallel compressors
  scripts/make_fit: Compress dtbs in parallel

 scripts/Makefile.lib |   2 +-
 scripts/make_fit.py  | 179 ++++++++++++++++++++++++++++++++++---------
 2 files changed, 145 insertions(+), 36 deletions(-)

-- 
2.43.0

base-commit: d358e5254674b70f34c847715ca509e46eb81e6f
branch: fita7


From sjg at chromium.org  Thu Dec 11 06:02:58 2025
From: sjg at chromium.org (Simon Glass)
Date: Thu, 11 Dec 2025 07:02:58 -0700
Subject: [PATCH v7 1/6] scripts/make_fit: Speed up operation
In-Reply-To: <20251211140309.1910613-1-sjg@chromium.org>
References: <20251211140309.1910613-1-sjg@chromium.org>
Message-ID: <20251211140309.1910613-2-sjg@chromium.org>

The kernel is likely at least 16MB so we may as well use that as a step
size when reallocating space for the FIT in memory. Pack the FIT at the
end, so there is no wasted space.

This reduces the time to pack by an order of magnitude, or so.

Signed-off-by: Simon Glass <sjg at chromium.org>
Reviewed-by: Nicolas Schier <nsc at kernel.org>
Reviewed-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
Tested-by: Chen-Yu Tsai <wenst at chromium.org>
---

(no changes since v3)

Changes in v3:
- Move the ramdisk chunk into the correct patch

 scripts/make_fit.py | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/scripts/make_fit.py b/scripts/make_fit.py
index 1683e5ec6e67..0f5e7c4b8aed 100755
--- a/scripts/make_fit.py
+++ b/scripts/make_fit.py
@@ -98,7 +98,7 @@ def setup_fit(fsw, name):
         fsw (libfdt.FdtSw): Object to use for writing
         name (str): Name of kernel image
     """
-    fsw.INC_SIZE = 65536
+    fsw.INC_SIZE = 16 << 20
     fsw.finish_reservemap()
     fsw.begin_node('')
     fsw.property_string('description', f'{name} with devicetree set')
@@ -299,7 +299,9 @@ def build_fit(args):
     finish_fit(fsw, entries)
 
     # Include the kernel itself in the returned file count
-    return fsw.as_fdt().as_bytearray(), seq + 1, size
+    fdt = fsw.as_fdt()
+    fdt.pack()
+    return fdt.as_bytearray(), seq + 1, size
 
 
 def run_make_fit():
-- 
2.43.0



From sjg at chromium.org  Thu Dec 11 06:02:59 2025
From: sjg at chromium.org (Simon Glass)
Date: Thu, 11 Dec 2025 07:02:59 -0700
Subject: [PATCH v7 2/6] scripts/make_fit: Support an initial ramdisk
In-Reply-To: <20251211140309.1910613-1-sjg@chromium.org>
References: <20251211140309.1910613-1-sjg@chromium.org>
Message-ID: <20251211140309.1910613-3-sjg@chromium.org>

FIT (Flat Image Tree) allows a ramdisk to be included in each
configuration. Add support for this to the script.

This feature is not available via 'make image.fit' since the ramdisk
likely needs to be built separately anyway, e.g. using modules from
the kernel build. Future work may provide support for doing that.

Note that the uncompressed size is not correct when a ramdisk is used,
since it is too expensive to decompress the ramdisk.

Signed-off-by: Simon Glass <sjg at chromium.org>
Reviewed-by: Nicolas Schier <nsc at kernel.org>
Reviewed-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---

(no changes since v6)

Changes in v6:
- Drop the load address for ramdisk, as it is not needed
- Bring back the ramdisk 'compression' property, set to 'none'

Changes in v5:
- Fix 'use' typo

Changes in v4:
- Update the commit message

Changes in v3:
- Add a comment at the top of the file about the -r option
- Count the ramdisk in the total files
- Update the commit message

Changes in v2:
- Don't compress the ramdisk as it is already compressed

 scripts/make_fit.py | 52 ++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 44 insertions(+), 8 deletions(-)

diff --git a/scripts/make_fit.py b/scripts/make_fit.py
index 0f5e7c4b8aed..66cd73711506 100755
--- a/scripts/make_fit.py
+++ b/scripts/make_fit.py
@@ -10,10 +10,14 @@
 Usage:
     make_fit.py -A arm64 -n 'Linux-6.6' -O linux
         -o arch/arm64/boot/image.fit -k /tmp/kern/arch/arm64/boot/image.itk
-        @arch/arm64/boot/dts/dtbs-list -E -c gzip
+        -r /boot/initrd.img-6.14.0-27-generic @arch/arm64/boot/dts/dtbs-list
+        -E -c gzip
 
-Creates a FIT containing the supplied kernel and a set of devicetree files,
-either specified individually or listed in a file (with an '@' prefix).
+Creates a FIT containing the supplied kernel, an optional ramdisk, and a set of
+devicetree files, either specified individually or listed in a file (with an
+'@' prefix).
+
+Use -r to specify an existing ramdisk/initrd file.
 
 Use -E to generate an external FIT (where the data is placed after the
 FIT data structure). This allows parsing of the data without loading
@@ -29,8 +33,6 @@ looks at the .cmd files produced by the kernel build.
 
 The resulting FIT can be booted by bootloaders which support FIT, such
 as U-Boot, Linuxboot, Tianocore, etc.
-
-Note that this tool does not yet support adding a ramdisk / initrd.
 """
 
 import argparse
@@ -81,6 +83,8 @@ def parse_args():
           help='Specifies the operating system')
     parser.add_argument('-k', '--kernel', type=str, required=True,
           help='Specifies the (uncompressed) kernel input file (.itk)')
+    parser.add_argument('-r', '--ramdisk', type=str,
+          help='Specifies the ramdisk/initrd input file')
     parser.add_argument('-v', '--verbose', action='store_true',
                         help='Enable verbose output')
     parser.add_argument('dtbs', type=str, nargs='*',
@@ -133,7 +137,28 @@ def write_kernel(fsw, data, args):
         fsw.property_u32('entry', 0)
 
 
-def finish_fit(fsw, entries):
+def write_ramdisk(fsw, data, args):
+    """Write out the ramdisk image
+
+    Writes a ramdisk node along with the required properties
+
+    Args:
+        fsw (libfdt.FdtSw): Object to use for writing
+        data (bytes): Data to write (possibly compressed)
+        args (Namespace): Contains necessary strings:
+            arch: FIT architecture, e.g. 'arm64'
+            fit_os: Operating Systems, e.g. 'linux'
+    """
+    with fsw.add_node('ramdisk'):
+        fsw.property_string('description', 'Ramdisk')
+        fsw.property_string('type', 'ramdisk')
+        fsw.property_string('arch', args.arch)
+        fsw.property_string('compression', 'none')
+        fsw.property_string('os', args.os)
+        fsw.property('data', data)
+
+
+def finish_fit(fsw, entries, has_ramdisk=False):
     """Finish the FIT ready for use
 
     Writes the /configurations node and subnodes
@@ -143,6 +168,7 @@ def finish_fit(fsw, entries):
         entries (list of tuple): List of configurations:
             str: Description of model
             str: Compatible stringlist
+        has_ramdisk (bool): True if a ramdisk is included in the FIT
     """
     fsw.end_node()
     seq = 0
@@ -154,6 +180,8 @@ def finish_fit(fsw, entries):
                 fsw.property_string('description', model)
                 fsw.property('fdt', bytes(''.join(f'fdt-{x}\x00' for x in files), "ascii"))
                 fsw.property_string('kernel', 'kernel')
+                if has_ramdisk:
+                    fsw.property_string('ramdisk', 'ramdisk')
     fsw.end_node()
 
 
@@ -274,6 +302,14 @@ def build_fit(args):
     size += os.path.getsize(args.kernel)
     write_kernel(fsw, comp_data, args)
 
+    # Handle the ramdisk if provided. Compression is not supported as it is
+    # already compressed.
+    if args.ramdisk:
+        with open(args.ramdisk, 'rb') as inf:
+            data = inf.read()
+        size += len(data)
+        write_ramdisk(fsw, data, args)
+
     for fname in args.dtbs:
         # Ignore non-DTB (*.dtb) files
         if os.path.splitext(fname)[1] != '.dtb':
@@ -296,12 +332,12 @@ def build_fit(args):
 
         entries.append([model, compat, files_seq])
 
-    finish_fit(fsw, entries)
+    finish_fit(fsw, entries, bool(args.ramdisk))
 
     # Include the kernel itself in the returned file count
     fdt = fsw.as_fdt()
     fdt.pack()
-    return fdt.as_bytearray(), seq + 1, size
+    return fdt.as_bytearray(), seq + 1 + bool(args.ramdisk), size
 
 
 def run_make_fit():
-- 
2.43.0



From sjg at chromium.org  Thu Dec 11 06:03:00 2025
From: sjg at chromium.org (Simon Glass)
Date: Thu, 11 Dec 2025 07:03:00 -0700
Subject: [PATCH v7 3/6] scripts/make_fit: Move dtb processing into a function
In-Reply-To: <20251211140309.1910613-1-sjg@chromium.org>
References: <20251211140309.1910613-1-sjg@chromium.org>
Message-ID: <20251211140309.1910613-4-sjg@chromium.org>

Since build_fit() is getting quite long, move the dtb processing into a
separate function.

Change the double quotes in the write() call to single, to match the
rest of the script.

Signed-off-by: Simon Glass <sjg at chromium.org>
Reviewed-by: Nicolas Schier <nsc at kernel.org>
Reviewed-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
Reviewed-by: Chen-Yu Tsai <wenst at chromium.org>
---

Changes in v7:
- Add a note about the " -> ' change

 scripts/make_fit.py | 67 +++++++++++++++++++++++++++++----------------
 1 file changed, 44 insertions(+), 23 deletions(-)

diff --git a/scripts/make_fit.py b/scripts/make_fit.py
index 66cd73711506..7ddaf3c0d783 100755
--- a/scripts/make_fit.py
+++ b/scripts/make_fit.py
@@ -277,6 +277,47 @@ def process_dtb(fname, args):
 
     return (model, compat, files)
 
+
+def _process_dtbs(args, fsw, entries, fdts):
+    """Process all DTB files and add them to the FIT
+
+    Args:
+        args: Program arguments
+        fsw: FIT writer object
+        entries: List to append entries to
+        fdts: Dictionary of processed DTBs
+
+    Returns:
+        tuple:
+            Number of files processed
+            Total size of files processed
+    """
+    seq = 0
+    size = 0
+    for fname in args.dtbs:
+        # Ignore non-DTB (*.dtb) files
+        if os.path.splitext(fname)[1] != '.dtb':
+            continue
+
+        try:
+            (model, compat, files) = process_dtb(fname, args)
+        except Exception as e:
+            sys.stderr.write(f'Error processing {fname}:\n')
+            raise e
+
+        for fn in files:
+            if fn not in fdts:
+                seq += 1
+                size += os.path.getsize(fn)
+                output_dtb(fsw, seq, fn, args.arch, args.compress)
+                fdts[fn] = seq
+
+        files_seq = [fdts[fn] for fn in files]
+        entries.append([model, compat, files_seq])
+
+    return seq, size
+
+
 def build_fit(args):
     """Build the FIT from the provided files and arguments
 
@@ -289,7 +330,6 @@ def build_fit(args):
             int: Number of configurations generated
             size: Total uncompressed size of data
     """
-    seq = 0
     size = 0
     fsw = libfdt.FdtSw()
     setup_fit(fsw, args.name)
@@ -310,34 +350,15 @@ def build_fit(args):
         size += len(data)
         write_ramdisk(fsw, data, args)
 
-    for fname in args.dtbs:
-        # Ignore non-DTB (*.dtb) files
-        if os.path.splitext(fname)[1] != '.dtb':
-            continue
-
-        try:
-            (model, compat, files) = process_dtb(fname, args)
-        except Exception as e:
-            sys.stderr.write(f"Error processing {fname}:\n")
-            raise e
-
-        for fn in files:
-            if fn not in fdts:
-                seq += 1
-                size += os.path.getsize(fn)
-                output_dtb(fsw, seq, fn, args.arch, args.compress)
-                fdts[fn] = seq
-
-        files_seq = [fdts[fn] for fn in files]
-
-        entries.append([model, compat, files_seq])
+    count, fdt_size = _process_dtbs(args, fsw, entries, fdts)
+    size += fdt_size
 
     finish_fit(fsw, entries, bool(args.ramdisk))
 
     # Include the kernel itself in the returned file count
     fdt = fsw.as_fdt()
     fdt.pack()
-    return fdt.as_bytearray(), seq + 1 + bool(args.ramdisk), size
+    return fdt.as_bytearray(), count + 1 + bool(args.ramdisk), size
 
 
 def run_make_fit():
-- 
2.43.0



From sjg at chromium.org  Thu Dec 11 06:03:01 2025
From: sjg at chromium.org (Simon Glass)
Date: Thu, 11 Dec 2025 07:03:01 -0700
Subject: [PATCH v7 4/6] kbuild: Support a MAKE_FIT_FLAGS environment variable
In-Reply-To: <20251211140309.1910613-1-sjg@chromium.org>
References: <20251211140309.1910613-1-sjg@chromium.org>
Message-ID: <20251211140309.1910613-5-sjg@chromium.org>

In some cases it is useful to be able to pass additional flags to the
make_fit.py script. For example, since ramdisks are typically large,
passing -E to use external data can be helpful.

Add a new MAKE_FIT_FLAGS variable for this.

Signed-off-by: Simon Glass <sjg at chromium.org>
---

Changes in v7:
- Add a new patch with the MAKE_FIT_FLAGS change

 scripts/Makefile.lib | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 28a1c08e3b22..a5641a6538b1 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -400,7 +400,7 @@ FIT_COMPRESSION ?= gzip
 
 quiet_cmd_fit = FIT     $@
       cmd_fit = $(MAKE_FIT) -o $@ --arch $(UIMAGE_ARCH) --os linux \
-		--name '$(UIMAGE_NAME)' \
+		--name '$(UIMAGE_NAME)' $(MAKE_FIT_FLAGS) \
 		$(if $(findstring 1,$(KBUILD_VERBOSE)),-v) \
 		$(if $(FIT_DECOMPOSE_DTBS),--decompose-dtbs) \
 		--compress $(FIT_COMPRESSION) -k $< @$(word 2,$^)
-- 
2.43.0



From sjg at chromium.org  Thu Dec 11 06:03:02 2025
From: sjg at chromium.org (Simon Glass)
Date: Thu, 11 Dec 2025 07:03:02 -0700
Subject: [PATCH v7 5/6] scripts/make_fit: Support a few more parallel compressors
In-Reply-To: <20251211140309.1910613-1-sjg@chromium.org>
References: <20251211140309.1910613-1-sjg@chromium.org>
Message-ID: <20251211140309.1910613-6-sjg@chromium.org>

Add support for pbzip2, xz and plzip which can compress in parallel.
This speeds up the ramdisk compression.

Signed-off-by: Simon Glass <sjg at chromium.org>
---

Changes in v7:
- Mention xz as well, in the commit message

 scripts/make_fit.py | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/scripts/make_fit.py b/scripts/make_fit.py
index 7ddaf3c0d783..defb87f223d7 100755
--- a/scripts/make_fit.py
+++ b/scripts/make_fit.py
@@ -50,11 +50,12 @@ import libfdt
 CompTool = collections.namedtuple('CompTool', 'ext,tools')
 
 COMP_TOOLS = {
-    'bzip2': CompTool('.bz2', 'bzip2'),
+    'bzip2': CompTool('.bz2', 'pbzip2,bzip2'),
     'gzip': CompTool('.gz', 'pigz,gzip'),
     'lz4': CompTool('.lz4', 'lz4'),
-    'lzma': CompTool('.lzma', 'lzma'),
+    'lzma': CompTool('.lzma', 'plzip,lzma'),
     'lzo': CompTool('.lzo', 'lzop'),
+    'xz': CompTool('.xz', 'xz'),
     'zstd': CompTool('.zstd', 'zstd'),
 }
 
@@ -207,7 +208,12 @@ def compress_data(inf, compress):
             done = False
             for tool in comp.tools.split(','):
                 try:
-                    subprocess.call([tool, '-c'], stdin=inf, stdout=outf)
+                    # Add parallel flags for tools that support them
+                    cmd = [tool]
+                    if tool in ('zstd', 'xz'):
+                        cmd.extend(['-T0'])  # Use all available cores
+                    cmd.append('-c')
+                    subprocess.call(cmd, stdin=inf, stdout=outf)
                     done = True
                     break
                 except FileNotFoundError:
-- 
2.43.0



From sjg at chromium.org  Thu Dec 11 06:03:03 2025
From: sjg at chromium.org (Simon Glass)
Date: Thu, 11 Dec 2025 07:03:03 -0700
Subject: [PATCH v7 6/6] scripts/make_fit: Compress dtbs in parallel
In-Reply-To: <20251211140309.1910613-1-sjg@chromium.org>
References: <20251211140309.1910613-1-sjg@chromium.org>
Message-ID: <20251211140309.1910613-7-sjg@chromium.org>

When there are 1500 device tree files it takes quite a while to compress
them. Do it in parallel.

kbuild: Allow adding modules into the FIT ramdisk

Signed-off-by: Simon Glass <sjg at chromium.org>
---

(no changes since v1)

 scripts/make_fit.py | 56 ++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 50 insertions(+), 6 deletions(-)

diff --git a/scripts/make_fit.py b/scripts/make_fit.py
index defb87f223d7..e923cc8b05b7 100755
--- a/scripts/make_fit.py
+++ b/scripts/make_fit.py
@@ -37,6 +37,7 @@ as U-Boot, Linuxboot, Tianocore, etc.
 
 import argparse
 import collections
+import multiprocessing
 import os
 import subprocess
 import sys
@@ -225,15 +226,31 @@ def compress_data(inf, compress):
     return comp_data
 
 
-def output_dtb(fsw, seq, fname, arch, compress):
+def compress_dtb(fname, compress):
+    """Compress a single DTB file
+
+    Args:
+        fname (str): Filename containing the DTB
+        compress (str): Compression algorithm, e.g. 'gzip'
+
+    Returns:
+        tuple: (str: fname, bytes: compressed_data)
+    """
+    with open(fname, 'rb') as inf:
+        compressed = compress_data(inf, compress)
+    return fname, compressed
+
+
+def output_dtb(fsw, seq, fname, arch, compress, data=None):
     """Write out a single devicetree to the FIT
 
     Args:
         fsw (libfdt.FdtSw): Object to use for writing
         seq (int): Sequence number (1 for first)
         fname (str): Filename containing the DTB
-        arch: FIT architecture, e.g. 'arm64'
+        arch (str): FIT architecture, e.g. 'arm64'
         compress (str): Compressed algorithm, e.g. 'gzip'
+        data (bytes): Pre-compressed data (optional)
     """
     with fsw.add_node(f'fdt-{seq}'):
         fsw.property_string('description', os.path.basename(fname))
@@ -241,9 +258,10 @@ def output_dtb(fsw, seq, fname, arch, compress):
         fsw.property_string('arch', arch)
         fsw.property_string('compression', compress)
 
-        with open(fname, 'rb') as inf:
-            compressed = compress_data(inf, compress)
-        fsw.property('data', compressed)
+        if data is None:
+            with open(fname, 'rb') as inf:
+                data = compress_data(inf, compress)
+        fsw.property('data', data)
 
 
 def process_dtb(fname, args):
@@ -300,6 +318,11 @@ def _process_dtbs(args, fsw, entries, fdts):
     """
     seq = 0
     size = 0
+
+    # First figure out the unique DTB files that need compression
+    todo = []
+    file_info = []  # List of (fname, model, compat, files) tuples
+
     for fname in args.dtbs:
         # Ignore non-DTB (*.dtb) files
         if os.path.splitext(fname)[1] != '.dtb':
@@ -311,11 +334,32 @@ def _process_dtbs(args, fsw, entries, fdts):
             sys.stderr.write(f'Error processing {fname}:\n')
             raise e
 
+        file_info.append((fname, model, compat, files))
+        for fn in files:
+            if fn not in fdts and fn not in todo:
+                todo.append(fn)
+
+    # Compress all DTBs in parallel
+    cache = {}
+    if todo and args.compress != 'none':
+        if args.verbose:
+            print(f'Compressing {len(todo)} DTBs...')
+
+        with multiprocessing.Pool() as pool:
+            compress_args = [(fn, args.compress) for fn in todo]
+            # unpacks each tuple, calls compress_dtb(fn, compress) in parallel
+            results = pool.starmap(compress_dtb, compress_args)
+
+        cache = dict(results)
+
+    # Now write all DTBs to the FIT using pre-compressed data
+    for fname, model, compat, files in file_info:
         for fn in files:
             if fn not in fdts:
                 seq += 1
                 size += os.path.getsize(fn)
-                output_dtb(fsw, seq, fn, args.arch, args.compress)
+                output_dtb(fsw, seq, fn, args.arch, args.compress,
+                           cache.get(fn))
                 fdts[fn] = seq
 
         files_seq = [fdts[fn] for fn in files]
-- 
2.43.0



From sudeep.holla at arm.com  Thu Dec 11 06:07:07 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Thu, 11 Dec 2025 14:07:07 +0000
Subject: [PATCH 1/1] firmware: arm_scmi: Increase MAX_OPPS to 64
In-Reply-To: <DEVFS1MAP8J6.2263USIPE4Y74@linaro.org>
References: <20251014073454.461999-1-vivek.aknurwar@oss.qualcomm.com>
 <6af5945e-7d5c-4596-ac42-c5898b4c49b7@oss.qualcomm.com>
 <DEVEXHI9CEFA.19RL3BXTV8E38@linaro.org>
 <20251211-masterful-caterpillar-of-love-bc2d4c@sudeepholla>
 <DEVFS1MAP8J6.2263USIPE4Y74@linaro.org>
Message-ID: <20251211-wandering-magnificent-yak-5fb19e@sudeepholla>

On Thu, Dec 11, 2025 at 01:54:01PM +0000, Alexey Klimov wrote:
> On Thu Dec 11, 2025 at 1:48 PM GMT, Sudeep Holla wrote:
> > On Thu, Dec 11, 2025 at 01:14:06PM +0000, Alexey Klimov wrote:
> >> > On 10/14/2025 12:34 AM, Vivek Aknurwar wrote:
> >> >> Some upcoming SoCs define more than 32 operating performance points (OPPs),
> >> >> exceeding the current SCMI protocol limit. Increase MAX_OPPS to 64
> >> >> (next power of 2) to support these configurations.
> >> 
> >> Didn't touch for a while. The way it is stated confuses me a bit.
> >> Should the value defined by protocol be updated out of the blue?
> >> Should the protocol (defined by spec) be changed first?
> >> 
> >
> > Ah good point on confusing commit message. I just assumed it is limitation
> > of the implementation. I can update the log when applying. It is not spec
> > or protocol limitation for sure.
> >
> > How about this ?
> >
> >   | firmware: arm_scmi: Increase performance MAX_OPPS limit to 64
> >   |
> >   | Some platforms expose more than 32 operating performance points (OPPs)
> >   | per performance domain via the SCMI performance protocol, but the
> >   | driver currently limits the number of OPPs it can handle to 32 via
> >   | MAX_OPPS.
> >   |
> >   | Bump MAX_OPPS to 64 so that these platforms can register all their
> >   | performance levels. This is an internal limit in the driver only and
> >   | does not affect the SCMI protocol ABI.
> >   |
> >   | 64 is chosen as the next power of two above the existing limit.
> 
> Yeah, that sounds better :)
> 

Thanks!

> I also thought that this was a driver limitation, not the protocol/spec one
> as stated in the original patch.
> 
> I don't mind updating the commit message like this (but I am not the author
> of the original patch).
> 

Vivek, are you happy with the above edited commit message ?

-- 
Regards,
Sudeep


From robh at kernel.org  Thu Dec 11 06:07:44 2025
From: robh at kernel.org (Rob Herring)
Date: Thu, 11 Dec 2025 08:07:44 -0600
Subject: [PATCH] ARM: dts: aspeed: bletchley: Fix dt-schema warnings
In-Reply-To: <20251211080311.242771-1-chou.cosmo@gmail.com>
References: <20251211080311.242771-1-chou.cosmo@gmail.com>
Message-ID: <176546187995.970978.16806289735144663383.robh@kernel.org>


On Thu, 11 Dec 2025 16:03:11 +0800, Cosmo Chou wrote:
> Update the device tree to fix dt-schema warnings:
> - Use generic node names for SPI, LEDs, and GPIO keys.
> - Update SPI GPIO properties to use the "-gpios" suffix.
> - Remove unused address/size cells from pca9539 nodes.
> - Use 'aspeed,int-vref-microvolt' in ADC nodes.
> - Remove unused 'aspeed,hw-timeout-ms' from i2c13.
> 
> Signed-off-by: Cosmo Chou <chou.cosmo at gmail.com>
> ---
>  .../aspeed/aspeed-bmc-facebook-bletchley.dts  | 100 ++++++++++--------
>  1 file changed, 54 insertions(+), 46 deletions(-)
> 


My bot found new DTB warnings on the .dts files added or changed in this
series.

Some warnings may be from an existing SoC .dtsi. Or perhaps the warnings
are fixed by another series. Ultimately, it is up to the platform
maintainer whether these warnings are acceptable or not. No need to reply
unless the platform maintainer has comments.

If you already ran DT checks and didn't see these error(s), then
make sure dt-schema is up to date:

  pip3 install dtschema --upgrade


This patch series was applied (using b4) to base:
 Base: attempting to guess base-commit...
 Base: tags/next-20251211 (exact match)
 Base: tags/next-20251211 (use --merge-base to override)

If this is not the correct base, please add 'base-commit' tag
(or use b4 which does this automatically)

New warnings running 'make CHECK_DTBS=y for arch/arm/boot/dts/aspeed/' for 20251211080311.242771-1-chou.cosmo at gmail.com:

arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dtb: adc at 1e6e9000 (aspeed,ast2600-adc0): 'interrupts' does not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/iio/adc/aspeed,ast2600-adc.yaml
arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dtb: adc at 1e6e9100 (aspeed,ast2600-adc1): 'interrupts' does not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/iio/adc/aspeed,ast2600-adc.yaml







From robh at kernel.org  Thu Dec 11 06:07:47 2025
From: robh at kernel.org (Rob Herring)
Date: Thu, 11 Dec 2025 08:07:47 -0600
Subject: [PATCH RFC 00/16] Eliminate warnings for AST2500 and AST2600
 EVB devicetrees
In-Reply-To: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
Message-ID: <176546188070.971010.10583431722134708925.robh@kernel.org>


On Thu, 11 Dec 2025 17:45:42 +0900, Andrew Jeffery wrote:
> Hi all,
> 
> This series removes the remaining warnings produced by `make
> CHECK_DTBS=y ...` for the AST2500 and AST2600 EVBs and their related
> DTSIs. The tidy-up has the usual benefit of making it clear to
> contributors that any warnings are likely their own to fix before their
> patches will be considered for merging.
> 
> I've framed it as an RFC with all patches contained in the one series
> so the goal is clear, we can see what's needed to reach it, and we can
> decide whether and how it should be split or merged going forward.
> 
> As it stands there's little in the way of code change, except to
> pinctrl (though also not much there). As such I've included the
> binding maintainers and subsystem lists as recipients but not yet Cc'ed
> subsystem maintainers directly because there are quite a few and I hope
> to avoid mostly uninteresting patches being a source of irritation.
> 
> The patches fall into several groups:
> 
> Patch 1:
>   Rob's conversion of the PWM/tach binding to DT schema with fixes
>   applied for the license and typos identified by Krzysztof.
> 
> Patches 2-5:
>   Fixes for the warnings related to the LPC and pinctrl nodes, touching
>   relevant drivers and the devicetrees.
> 
>   I expect that if this approach is acceptable that we'll need to split
>   application of the patches across successive release cycles, with the
>   driver changes going in first.
> 
> Patches 6-8:
>   Fix MMC/SDHCI warnings, touching the relevant binding and devicetrees
> 
> Patches 9-10:
>   Clarify the relationships between the ACRY and AHB controller
> 
> Patches 11-16:
>   The remaining pieces that eliminate the warnings
> 
> I'm at plumbers so don't have hardware on hand to test with, but some
> brief smoke tests under qemu look okay. Given that it's all RFC that
> should be enough for the moment. I'll do more testing after discussions
> and when I have boards at hand.
> 
> Please review!
> 
> Andrew
> 
> Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
> ---
> Andrew Jeffery (15):
>       pinctrl: aspeed: g5: Constrain LPC binding revision workaround to AST2500
>       pinctrl: aspeed: g5: Allow use of LPC node instead of LPC host controller
>       ARM: dts: aspeed: g5: Use LPC phandle for pinctrl aspeed,external-nodes
>       ARM: dts: aspeed: Remove unspecified LPC host controller node
>       dt-bindings: mmc: Switch ref to sdhci-common.yaml
>       ARM: dts: aspeed: Remove sdhci-drive-type property from AST2600 EVB
>       ARM: dts: aspeed: Use specified wp-inverted property for AST2600 EVB
>       dt-bindings: bus: aspeed: Require syscon for AST2600 AHB controller
>       dt-bindings: crypto: Document aspeed,ahbc property for Aspeed ACRY
>       ARM: dts: aspeed: Drop syscon compatible from EDAC in g6 dtsi
>       ARM: dts: aspeed: g6: Drop unspecified aspeed,ast2600-udma node
>       ARM: dts: aspeed: ast2600-evb: Tidy up A0 work-around for UART5
>       dt-bindings: iio: adc: Allow interrupts property for AST2600
>       ARM: dts: aspeed: g6: Drop clocks property from arm,armv7-timer
>       dt-bindings: mfd: Document smp-memram node for AST2600 SCU
> 
> Rob Herring (Arm) (1):
>       dt-bindings: hwmon: Convert aspeed,ast2400-pwm-tacho to DT schema
> 
>  .../bindings/bus/aspeed,ast2600-ahbc.yaml          |   8 +-
>  .../bindings/crypto/aspeed,ast2600-acry.yaml       |   7 ++
>  .../bindings/hwmon/aspeed,ast2400-pwm-tacho.yaml   | 106 +++++++++++++++++++++
>  .../devicetree/bindings/hwmon/aspeed-pwm-tacho.txt |  73 --------------
>  .../bindings/iio/adc/aspeed,ast2600-adc.yaml       |   3 +
>  .../bindings/mfd/aspeed,ast2x00-scu.yaml           |  18 ++++
>  .../devicetree/bindings/mmc/aspeed,sdhci.yaml      |   2 +-
>  arch/arm/boot/dts/aspeed/aspeed-ast2600-evb.dts    |   7 +-
>  .../dts/aspeed/aspeed-bmc-facebook-clemente.dts    |   4 -
>  arch/arm/boot/dts/aspeed/aspeed-g4.dtsi            |   5 -
>  arch/arm/boot/dts/aspeed/aspeed-g5.dtsi            |   8 +-
>  arch/arm/boot/dts/aspeed/aspeed-g6.dtsi            |  17 +---
>  drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c         |  32 ++++---
>  13 files changed, 165 insertions(+), 125 deletions(-)
> ---
> base-commit: 5ce74bc1b7cb2732b22f9c93082545bc655d6547
> change-id: 20251211-dev-dt-warnings-all-bd5854b04d60
> 
> Best regards,
> --
> Andrew Jeffery <andrew at codeconstruct.com.au>
> 
> 
> 


My bot found new DTB warnings on the .dts files added or changed in this
series.

Some warnings may be from an existing SoC .dtsi. Or perhaps the warnings
are fixed by another series. Ultimately, it is up to the platform
maintainer whether these warnings are acceptable or not. No need to reply
unless the platform maintainer has comments.

If you already ran DT checks and didn't see these error(s), then
make sure dt-schema is up to date:

  pip3 install dtschema --upgrade


This patch series was applied (using b4) to base:
 Base: 5ce74bc1b7cb2732b22f9c93082545bc655d6547 (use --merge-base to override)

If this is not the correct base, please add 'base-commit' tag
(or use b4 which does this automatically)

New warnings running 'make CHECK_DTBS=y for arch/arm/boot/dts/aspeed/' for 20251211-dev-dt-warnings-all-v1-0-21b18b9ada77 at codeconstruct.com.au:

arch/arm/boot/dts/aspeed/aspeed-bmc-quanta-s6q.dtb: adc at 1e6e9000 (aspeed,ast2600-adc0): 'vref' does not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/iio/adc/aspeed,ast2600-adc.yaml
arch/arm/boot/dts/aspeed/aspeed-bmc-quanta-s6q.dtb: adc at 1e6e9100 (aspeed,ast2600-adc1): 'vref' does not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/iio/adc/aspeed,ast2600-adc.yaml
arch/arm/boot/dts/aspeed/aspeed-bmc-opp-mowgli.dtb: pwm-tacho-controller at 1e786000 (aspeed,ast2500-pwm-tacho): 'fan at 8', 'fan at 9' do not match any of the regexes: '^fan@[0-7]$', '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/hwmon/aspeed,ast2400-pwm-tacho.yaml
arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dtb: adc at 1e6e9000 (aspeed,ast2600-adc0): 'vref' does not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/iio/adc/aspeed,ast2600-adc.yaml
arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dtb: adc at 1e6e9100 (aspeed,ast2600-adc1): 'vref' does not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/iio/adc/aspeed,ast2600-adc.yaml
arch/arm/boot/dts/aspeed/aspeed-bmc-ampere-mtjade.dtb: pwm-tacho-controller at 1e786000 (aspeed,ast2500-pwm-tacho): 'fan at 10', 'fan at 11', 'fan at 8', 'fan at 9' do not match any of the regexes: '^fan@[0-7]$', '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/hwmon/aspeed,ast2400-pwm-tacho.yaml
arch/arm/boot/dts/aspeed/aspeed-bmc-asus-x4tf.dtb: adc at 1e6e9000 (aspeed,ast2600-adc0): 'vref' does not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/iio/adc/aspeed,ast2600-adc.yaml
arch/arm/boot/dts/aspeed/aspeed-bmc-asus-x4tf.dtb: adc at 1e6e9100 (aspeed,ast2600-adc1): 'vref' does not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/iio/adc/aspeed,ast2600-adc.yaml
arch/arm/boot/dts/aspeed/aspeed-bmc-lenovo-hr855xg2.dtb: pwm-tacho-controller at 1e786000 (aspeed,ast2500-pwm-tacho): 'fan at 10', 'fan at 11', 'fan at 12', 'fan at 13', 'fan at 14', 'fan at 15', 'fan at 16', 'fan at 8', 'fan at 9' do not match any of the regexes: '^fan@[0-7]$', '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/hwmon/aspeed,ast2400-pwm-tacho.yaml
arch/arm/boot/dts/aspeed/aspeed-bmc-amd-daytonax.dtb: pwm-tacho-controller at 1e786000 (aspeed,ast2500-pwm-tacho): 'fan at 10', 'fan at 11', 'fan at 12', 'fan at 13', 'fan at 14', 'fan at 15', 'fan at 8', 'fan at 9' do not match any of the regexes: '^fan@[0-7]$', '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/hwmon/aspeed,ast2400-pwm-tacho.yaml
arch/arm/boot/dts/aspeed/aspeed-bmc-lenovo-hr630.dtb: pwm-tacho-controller at 1e786000 (aspeed,ast2500-pwm-tacho): 'fan at 10', 'fan at 11', 'fan at 12', 'fan at 13', 'fan at 8', 'fan at 9' do not match any of the regexes: '^fan@[0-7]$', '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/hwmon/aspeed,ast2400-pwm-tacho.yaml
arch/arm/boot/dts/aspeed/aspeed-bmc-ufispace-ncplite.dtb: adc at 1e6e9000 (aspeed,ast2600-adc0): 'vref' does not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/iio/adc/aspeed,ast2600-adc.yaml
arch/arm/boot/dts/aspeed/aspeed-bmc-ufispace-ncplite.dtb: adc at 1e6e9100 (aspeed,ast2600-adc1): 'vref' does not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/iio/adc/aspeed,ast2600-adc.yaml







From tabba at google.com  Thu Dec 11 06:13:22 2025
From: tabba at google.com (Fuad Tabba)
Date: Thu, 11 Dec 2025 14:13:22 +0000
Subject: [PATCH v2 3/6] arm64: Convert VTCR_EL2 to sysreg infratructure
In-Reply-To: <20251210173024.561160-4-maz@kernel.org>
References: <20251210173024.561160-1-maz@kernel.org> <20251210173024.561160-4-maz@kernel.org>
Message-ID: <CA+EHjTyJFZttD4jTH=q_T28BwMR2CDdYSyH7G-WTQvULyjy-Tw@mail.gmail.com>

Hi Marc,

In subject: infratructure -> infrastructure


On Wed, 10 Dec 2025 at 17:30, Marc Zyngier <maz at kernel.org> wrote:
>
> Our definition of VTCR_EL2 is both partial (tons of fields are
> missing) and totally inconsistent (some constants are shifted,
> some are not). They are also expressed in terms of TCR, which is
> rather inconvenient.
>
> Replace the ad-hoc definitions with the the generated version.

Duplicate "the"

> This results in a bunch of additional changes to make the code
> with the unshifted nature of generated enumerations.
>
> The register data was extracted from the BSD licenced AARCHMRS
> (AARCHMRS_OPENSOURCE_A_profile_FAT-2025-09_ASL0).
>
> Reviewed-by: Alexandru Elisei <alexandru.elisei at arm.com>
> Signed-off-by: Marc Zyngier <maz at kernel.org>

After checking the bits against the spec, and with the nits above:

Reviewed-by: Fuad Tabba <tabba at google.com>

/fuad

> ---
>  arch/arm64/include/asm/kvm_arm.h | 52 +++++++----------------------
>  arch/arm64/include/asm/sysreg.h  |  1 -
>  arch/arm64/kvm/hyp/pgtable.c     |  8 ++---
>  arch/arm64/kvm/nested.c          |  8 ++---
>  arch/arm64/tools/sysreg          | 57 ++++++++++++++++++++++++++++++++
>  5 files changed, 76 insertions(+), 50 deletions(-)
>
> diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
> index e500600e4b9b8..dfdbd2b65db9e 100644
> --- a/arch/arm64/include/asm/kvm_arm.h
> +++ b/arch/arm64/include/asm/kvm_arm.h
> @@ -124,37 +124,7 @@
>  #define TCR_EL2_MASK   (TCR_EL2_TG0_MASK | TCR_EL2_SH0_MASK | \
>                          TCR_EL2_ORGN0_MASK | TCR_EL2_IRGN0_MASK)
>
> -/* VTCR_EL2 Registers bits */
> -#define VTCR_EL2_DS            TCR_EL2_DS
> -#define VTCR_EL2_RES1          (1U << 31)
> -#define VTCR_EL2_HD            (1 << 22)
> -#define VTCR_EL2_HA            (1 << 21)
> -#define VTCR_EL2_PS_SHIFT      TCR_EL2_PS_SHIFT
> -#define VTCR_EL2_PS_MASK       TCR_EL2_PS_MASK
> -#define VTCR_EL2_TG0_MASK      TCR_TG0_MASK
> -#define VTCR_EL2_TG0_4K                TCR_TG0_4K
> -#define VTCR_EL2_TG0_16K       TCR_TG0_16K
> -#define VTCR_EL2_TG0_64K       TCR_TG0_64K
> -#define VTCR_EL2_SH0_MASK      TCR_SH0_MASK
> -#define VTCR_EL2_SH0_INNER     TCR_SH0_INNER
> -#define VTCR_EL2_ORGN0_MASK    TCR_ORGN0_MASK
> -#define VTCR_EL2_ORGN0_WBWA    TCR_ORGN0_WBWA
> -#define VTCR_EL2_IRGN0_MASK    TCR_IRGN0_MASK
> -#define VTCR_EL2_IRGN0_WBWA    TCR_IRGN0_WBWA
> -#define VTCR_EL2_SL0_SHIFT     6
> -#define VTCR_EL2_SL0_MASK      (3 << VTCR_EL2_SL0_SHIFT)
> -#define VTCR_EL2_T0SZ_MASK     0x3f
> -#define VTCR_EL2_VS_SHIFT      19
> -#define VTCR_EL2_VS_8BIT       (0 << VTCR_EL2_VS_SHIFT)
> -#define VTCR_EL2_VS_16BIT      (1 << VTCR_EL2_VS_SHIFT)
> -
> -#define VTCR_EL2_T0SZ(x)       TCR_T0SZ(x)
> -
>  /*
> - * We configure the Stage-2 page tables to always restrict the IPA space to be
> - * 40 bits wide (T0SZ = 24).  Systems with a PARange smaller than 40 bits are
> - * not known to exist and will break with this configuration.
> - *
>   * The VTCR_EL2 is configured per VM and is initialised in kvm_init_stage2_mmu.
>   *
>   * Note that when using 4K pages, we concatenate two first level page tables
> @@ -162,9 +132,6 @@
>   *
>   */
>
> -#define VTCR_EL2_COMMON_BITS   (VTCR_EL2_SH0_INNER | VTCR_EL2_ORGN0_WBWA | \
> -                                VTCR_EL2_IRGN0_WBWA | VTCR_EL2_RES1)
> -
>  /*
>   * VTCR_EL2:SL0 indicates the entry level for Stage2 translation.
>   * Interestingly, it depends on the page size.
> @@ -196,30 +163,35 @@
>   */
>  #ifdef CONFIG_ARM64_64K_PAGES
>
> -#define VTCR_EL2_TGRAN                 VTCR_EL2_TG0_64K
> +#define VTCR_EL2_TGRAN                 64K
>  #define VTCR_EL2_TGRAN_SL0_BASE                3UL
>
>  #elif defined(CONFIG_ARM64_16K_PAGES)
>
> -#define VTCR_EL2_TGRAN                 VTCR_EL2_TG0_16K
> +#define VTCR_EL2_TGRAN                 16K
>  #define VTCR_EL2_TGRAN_SL0_BASE                3UL
>
>  #else  /* 4K */
>
> -#define VTCR_EL2_TGRAN                 VTCR_EL2_TG0_4K
> +#define VTCR_EL2_TGRAN                 4K
>  #define VTCR_EL2_TGRAN_SL0_BASE                2UL
>
>  #endif
>
>  #define VTCR_EL2_LVLS_TO_SL0(levels)   \
> -       ((VTCR_EL2_TGRAN_SL0_BASE - (4 - (levels))) << VTCR_EL2_SL0_SHIFT)
> +       FIELD_PREP(VTCR_EL2_SL0, (VTCR_EL2_TGRAN_SL0_BASE - (4 - (levels))))
>  #define VTCR_EL2_SL0_TO_LVLS(sl0)      \
>         ((sl0) + 4 - VTCR_EL2_TGRAN_SL0_BASE)
>  #define VTCR_EL2_LVLS(vtcr)            \
> -       VTCR_EL2_SL0_TO_LVLS(((vtcr) & VTCR_EL2_SL0_MASK) >> VTCR_EL2_SL0_SHIFT)
> +       VTCR_EL2_SL0_TO_LVLS(FIELD_GET(VTCR_EL2_SL0, (vtcr)))
> +
> +#define VTCR_EL2_FLAGS (SYS_FIELD_PREP_ENUM(VTCR_EL2, SH0, INNER)          | \
> +                        SYS_FIELD_PREP_ENUM(VTCR_EL2, ORGN0, WBWA)         | \
> +                        SYS_FIELD_PREP_ENUM(VTCR_EL2, IRGN0, WBWA)         | \
> +                        SYS_FIELD_PREP_ENUM(VTCR_EL2, TG0, VTCR_EL2_TGRAN) | \
> +                        VTCR_EL2_RES1)
>
> -#define VTCR_EL2_FLAGS                 (VTCR_EL2_COMMON_BITS | VTCR_EL2_TGRAN)
> -#define VTCR_EL2_IPA(vtcr)             (64 - ((vtcr) & VTCR_EL2_T0SZ_MASK))
> +#define VTCR_EL2_IPA(vtcr)             (64 - FIELD_GET(VTCR_EL2_T0SZ, (vtcr)))
>
>  /*
>   * ARM VMSAv8-64 defines an algorithm for finding the translation table
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index c231d2a3e5159..acad7a7621b9e 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -516,7 +516,6 @@
>  #define SYS_TTBR1_EL2                  sys_reg(3, 4, 2, 0, 1)
>  #define SYS_TCR_EL2                    sys_reg(3, 4, 2, 0, 2)
>  #define SYS_VTTBR_EL2                  sys_reg(3, 4, 2, 1, 0)
> -#define SYS_VTCR_EL2                   sys_reg(3, 4, 2, 1, 2)
>
>  #define SYS_HAFGRTR_EL2                        sys_reg(3, 4, 3, 1, 6)
>  #define SYS_SPSR_EL2                   sys_reg(3, 4, 4, 0, 0)
> diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
> index 947ac1a951a5b..e0bd6a0172729 100644
> --- a/arch/arm64/kvm/hyp/pgtable.c
> +++ b/arch/arm64/kvm/hyp/pgtable.c
> @@ -583,8 +583,8 @@ u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
>         u64 vtcr = VTCR_EL2_FLAGS;
>         s8 lvls;
>
> -       vtcr |= kvm_get_parange(mmfr0) << VTCR_EL2_PS_SHIFT;
> -       vtcr |= VTCR_EL2_T0SZ(phys_shift);
> +       vtcr |= FIELD_PREP(VTCR_EL2_PS, kvm_get_parange(mmfr0));
> +       vtcr |= FIELD_PREP(VTCR_EL2_T0SZ, (UL(64) - phys_shift));
>         /*
>          * Use a minimum 2 level page table to prevent splitting
>          * host PMD huge pages at stage2.
> @@ -624,9 +624,7 @@ u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
>                 vtcr |= VTCR_EL2_DS;
>
>         /* Set the vmid bits */
> -       vtcr |= (get_vmid_bits(mmfr1) == 16) ?
> -               VTCR_EL2_VS_16BIT :
> -               VTCR_EL2_VS_8BIT;
> +       vtcr |= (get_vmid_bits(mmfr1) == 16) ? VTCR_EL2_VS : 0;
>
>         return vtcr;
>  }
> diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
> index 911fc99ed99d9..e1ef8930c97b3 100644
> --- a/arch/arm64/kvm/nested.c
> +++ b/arch/arm64/kvm/nested.c
> @@ -377,7 +377,7 @@ static void vtcr_to_walk_info(u64 vtcr, struct s2_walk_info *wi)
>  {
>         wi->t0sz = vtcr & TCR_EL2_T0SZ_MASK;
>
> -       switch (vtcr & VTCR_EL2_TG0_MASK) {
> +       switch (FIELD_GET(VTCR_EL2_TG0_MASK, vtcr)) {
>         case VTCR_EL2_TG0_4K:
>                 wi->pgshift = 12;        break;
>         case VTCR_EL2_TG0_16K:
> @@ -513,7 +513,7 @@ static u8 get_guest_mapping_ttl(struct kvm_s2_mmu *mmu, u64 addr)
>
>         lockdep_assert_held_write(&kvm_s2_mmu_to_kvm(mmu)->mmu_lock);
>
> -       switch (vtcr & VTCR_EL2_TG0_MASK) {
> +       switch (FIELD_GET(VTCR_EL2_TG0_MASK, vtcr)) {
>         case VTCR_EL2_TG0_4K:
>                 ttl = (TLBI_TTL_TG_4K << 2);
>                 break;
> @@ -530,7 +530,7 @@ static u8 get_guest_mapping_ttl(struct kvm_s2_mmu *mmu, u64 addr)
>
>  again:
>         /* Iteratively compute the block sizes for a particular granule size */
> -       switch (vtcr & VTCR_EL2_TG0_MASK) {
> +       switch (FIELD_GET(VTCR_EL2_TG0_MASK, vtcr)) {
>         case VTCR_EL2_TG0_4K:
>                 if      (sz < SZ_4K)    sz = SZ_4K;
>                 else if (sz < SZ_2M)    sz = SZ_2M;
> @@ -593,7 +593,7 @@ unsigned long compute_tlb_inval_range(struct kvm_s2_mmu *mmu, u64 val)
>
>         if (!max_size) {
>                 /* Compute the maximum extent of the invalidation */
> -               switch (mmu->tlb_vtcr & VTCR_EL2_TG0_MASK) {
> +               switch (FIELD_GET(VTCR_EL2_TG0_MASK, mmu->tlb_vtcr)) {
>                 case VTCR_EL2_TG0_4K:
>                         max_size = SZ_1G;
>                         break;
> diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
> index 9d388f87d9a13..6f43b2ae5993b 100644
> --- a/arch/arm64/tools/sysreg
> +++ b/arch/arm64/tools/sysreg
> @@ -4400,6 +4400,63 @@ Field    56:12   BADDR
>  Res0   11:0
>  EndSysreg
>
> +Sysreg VTCR_EL2        3       4       2       1       2
> +Res0   63:46
> +Field  45      HDBSS
> +Field  44      HAFT
> +Res0   43:42
> +Field  41      TL0
> +Field  40      GCSH
> +Res0   39
> +Field  38      D128
> +Field  37      S2POE
> +Field  36      S2PIE
> +Field  35      TL1
> +Field  34      AssuredOnly
> +Field  33      SL2
> +Field  32      DS
> +Res1   31
> +Field  30      NSA
> +Field  29      NSW
> +Field  28      HWU62
> +Field  27      HWU61
> +Field  26      HWU60
> +Field  25      HWU59
> +Res0   24:23
> +Field  22      HD
> +Field  21      HA
> +Res0   20
> +Enum   19      VS
> +       0b0     8BIT
> +       0b1     16BIT
> +EndEnum
> +Field  18:16   PS
> +Enum   15:14   TG0
> +       0b00    4K
> +       0b01    64K
> +       0b10    16K
> +EndEnum
> +Enum   13:12   SH0
> +       0b00    NONE
> +       0b01    OUTER
> +       0b11    INNER
> +EndEnum
> +Enum   11:10   ORGN0
> +       0b00    NC
> +       0b01    WBWA
> +       0b10    WT
> +       0b11    WBnWA
> +EndEnum
> +Enum   9:8     IRGN0
> +       0b00    NC
> +       0b01    WBWA
> +       0b10    WT
> +       0b11    WBnWA
> +EndEnum
> +Field  7:6     SL0
> +Field  5:0     T0SZ
> +EndSysreg
> +
>  Sysreg GCSCR_EL2       3       4       2       5       0
>  Fields GCSCR_ELx
>  EndSysreg
> --
> 2.47.3
>


From nicolas.frattaroli at collabora.com  Thu Dec 11 06:16:51 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 11 Dec 2025 15:16:51 +0100
Subject: [PATCH v2 5/8] drm/rockchip: vop2: Enforce AFBC source alignment in
 plane_check
In-Reply-To: <fdd333ac-0542-4312-8ec0-22fded3b1ce0@rock-chips.com>
References: <20251206-vop2-atomic-fixups-v2-0-7fb45bbfbebd@collabora.com>
 <8655687.NyiUUSuA9g@workhorse>
 <fdd333ac-0542-4312-8ec0-22fded3b1ce0@rock-chips.com>
Message-ID: <3520923.e9J7NaK4W3@workhorse>

On Thursday, 11 December 2025 12:06:38 Central European Standard Time Chaoyi Chen wrote:
> Hello Nicolas,
> 
> On 12/9/2025 6:58 PM, Nicolas Frattaroli wrote:
> > Hi Chaoyi Chen, Andy Yan,
> > 
> > On Monday, 8 December 2025 08:24:52 Central European Standard Time Nicolas Frattaroli wrote:
> >> On Monday, 8 December 2025 03:48:24 Central European Standard Time Chaoyi Chen wrote:
> >>> Hello Nicolas, Daniel,
> >>>
> >>> On 12/7/2025 4:45 AM, Nicolas Frattaroli wrote:
> >>>> From: Daniel Stone <daniels at collabora.com>
> >>>>
> >>>> Planes can only source AFBC framebuffers at multiples of 4px wide on
> >>>> RK3566/RK3568. Instead of clipping on all SoCs when the user asks for an
> >>>> unaligned source rectangle, reject the configuration in the plane's
> >>>> atomic check on RK3566/RK3568 only.
> >>>>
> >>>> Signed-off-by: Daniel Stone <daniels at collabora.com>
> >>>> [Make RK3566/RK3568 specific, reword message]
> >>>> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
> >>>> ---
> >>>>  drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 14 +++++++++-----
> >>>>  1 file changed, 9 insertions(+), 5 deletions(-)
> >>>>
> >>>> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> >>>> index bc1ed0ffede0..e23213337104 100644
> >>>> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> >>>> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> >>>> @@ -1076,6 +1076,13 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
> >>>>  		return -EINVAL;
> >>>>  	}
> >>>>  
> >>>> +	if (vop2->version == VOP_VERSION_RK3568 && drm_is_afbc(fb->modifier) && src_w % 4) {
> >>>> +		drm_dbg_kms(vop2->drm,
> >>>> +			    "AFBC source rectangles must be 4-byte aligned; is %d\n",
> >>>> +			    src_w);
> >>>> +		return -EINVAL;
> >>>> +	}
> >>>> +
> >>>>  	return 0;
> >>>>  }
> >>>>  
> >>>> @@ -1237,11 +1244,8 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
> >>>>  	WARN_ON(src_w < 4);
> >>>>  	WARN_ON(src_h < 4);
> >>>>  
> >>>> -	if (afbc_en && src_w % 4) {
> >>>> -		drm_dbg_kms(vop2->drm, "vp%d %s src_w[%d] not 4 pixel aligned\n",
> >>>> -			    vp->id, win->data->name, src_w);
> >>>> -		src_w = ALIGN_DOWN(src_w, 4);
> >>>> -	}
> >>>> +	if (vop2->version == VOP_VERSION_RK3568 && drm_is_afbc(fb->modifier))
> >>>> +		WARN_ON(src_w % 4);
> >>>>  
> >>>>  	act_info = (src_h - 1) << 16 | ((src_w - 1) & 0xffff);
> >>>>  	dsp_info = (dsp_h - 1) << 16 | ((dsp_w - 1) & 0xffff);
> >>>>
> >>>
> >>> You haven't replied to Andy's comment yet [0].
> >>>
> >>> [0] https://lore.kernel.org/dri-devel/7b4e26ec.75f3.19a77276b53.Coremail.andyshrk at 163.com/
> >>>
> >>
> >> Hello,
> >>
> >> I addressed the follow-ups where it was clarified that the 4 pixel
> >> limitation was RK3566/RK3568-only. I'm not going to bring back the
> >> post-atomic_check modification for a fast path, but I'm open to
> >> suggestions on how to do this differently.
> >>
> >> One solution might be to modify the state with the ALIGN_DOWN stuff
> >> in atomic_check instead, where userspace is then aware of the change
> >> being done to its requested parameters. I'll need to double-check
> >> whether this is in line with atomic modesetting's design.
> >>
> >> Kind regards,
> >> Nicolas Frattaroli
> > 
> > Okay, so I've asked internally, and atomic_check isn't allowed to
> > modify any of the parameters either. There's efforts [0] underway
> > to allow error codes to be more specific, so that userspace knows
> > which constraint is being violated. That would allow userspace
> > applications to react by either adjusting their size or turning
> > off AFBC in this case. Turning off AFBC seems more generally
> > applicable here, since it means it won't need to resize the plane
> > and it'll save more than enough memory bandwidth by not going
> > through the GPU.
> > 
> > On that note: Andy, I didn't find a weston-simple-egl test in the
> > Weston 14.0.2 or git test suite, and weston-simple-egl itself does
> > not tell me whether GPU compositing is being used or not. Do you
> > have more information on how to test for this? I'd like to know
> > for when we have the necessary functionality in place to make
> > userspace smart enough to pick the fast path again.
> > 
> 
> I think weston-simple-egl is part of the weston client. When you build
> weston from source, you should obtain it. Just run `weston-simple-egl` 
> after compile and install weston.
> 
> And I guess you're using Debian... The weston package there also ships
> with a weston-simple-egl binary [2].

Yeah, I know there's a tool called that, but I'm specifically curious
about how to determine whether it's using GPU compositing or what I
presume is fixed-function compositing.

When I enable some more logging with

  weston -l log,drm-backend,gl-renderer

and also some kms debug messages with

  echo 4 > /sys/module/drm/parameters/debug

then I see weston outputting

[atomic] drmModeAtomicCommit
        [repaint] Using mixed state composition
        [repaint] view 0xaaab18c00c10 using renderer composition
        [repaint] view 0xaaab18b68f00 using renderer composition
        [repaint] view 0xaaab18c00ec0 using renderer composition

regardless of whether the size is 250x250 or fullscreen. With
250x250, I know we're failing the plane check, because I see

  [  776.160101] rockchip-drm display-subsystem: [drm:vop2_plane_atomic_check
                 [rockchipdrm]] AFBC source rectangles must be 4-pixel
                 aligned; is 250

on the console, but with fullscreen I don't see any errors from plane-check
as the src_w is now divisible by 4, yet it's also "using renderer composition"
for all views.

Same goes for using `weston-simple-dmabuf-egl` (which is 256x256) instead of
the fullscreen simple-egl.

So basically, I need to know where a change in behaviour is actually
observed.

> 
> [1]: https://gitlab.freedesktop.org/wayland/weston/-/blob/main/clients/simple-egl.c
> [2]: https://packages.debian.org/sid/arm64/weston/filelist
> 
> > In either case, I think adhering to the atomic API to ensure
> > artifact-free presentation is more important here than enabling
> > a fast-path on RK3568. I do think in most real-world use case
> > scenarios, the fallback won't degrade user experience, because
> > almost everything performance intensive I can think of (video
> > playback, games) will likely already use a plane geometry
> > where the width is divisible by 4. 800, 1024, 1280, 1600, 1920,
> > 2560, 3840 are all divisible by 4, so a window or full-screen
> > playback of common content won't need to fall back to GPU
> > compositing.
> > 
> > I'll send a v2 to fix another instance of "eSmart" left in a
> > message, but beyond that I think we should be good.
> > 
> > Kind regards,
> > Nicolas Frattaroli
> > 
> > https://lore.kernel.org/dri-devel/20251009-atomic-v6-0-d209709cc3ba at intel.com/ [0]
> > 
> > 
> > 
> > 
> 
> 






From alexey.klimov at linaro.org  Thu Dec 11 06:25:08 2025
From: alexey.klimov at linaro.org (Alexey Klimov)
Date: Thu, 11 Dec 2025 14:25:08 +0000
Subject: [PATCH 1/1] firmware: arm_scmi: Increase MAX_OPPS to 64
In-Reply-To: <20251211-wandering-magnificent-yak-5fb19e@sudeepholla>
References: <20251014073454.461999-1-vivek.aknurwar@oss.qualcomm.com>
 <6af5945e-7d5c-4596-ac42-c5898b4c49b7@oss.qualcomm.com>
 <DEVEXHI9CEFA.19RL3BXTV8E38@linaro.org>
 <20251211-masterful-caterpillar-of-love-bc2d4c@sudeepholla>
 <DEVFS1MAP8J6.2263USIPE4Y74@linaro.org>
 <20251211-wandering-magnificent-yak-5fb19e@sudeepholla>
Message-ID: <DEVGFVA8N0N9.13ZJADVNM9PHO@linaro.org>

On Thu Dec 11, 2025 at 2:07 PM GMT, Sudeep Holla wrote:

[..]

>> > Ah good point on confusing commit message. I just assumed it is limitation
>> > of the implementation. I can update the log when applying. It is not spec
>> > or protocol limitation for sure.
>> >
>> > How about this ?
>> >
>> >   | firmware: arm_scmi: Increase performance MAX_OPPS limit to 64
>> >   |
>> >   | Some platforms expose more than 32 operating performance points (OPPs)
>> >   | per performance domain via the SCMI performance protocol, but the
>> >   | driver currently limits the number of OPPs it can handle to 32 via
>> >   | MAX_OPPS.
>> >   |
>> >   | Bump MAX_OPPS to 64 so that these platforms can register all their
>> >   | performance levels. This is an internal limit in the driver only and
>> >   | does not affect the SCMI protocol ABI.
>> >   |
>> >   | 64 is chosen as the next power of two above the existing limit.
>> 
>> Yeah, that sounds better :)
>> 
> Thanks!
>
>> I also thought that this was a driver limitation, not the protocol/spec one
>> as stated in the original patch.
>> 
>> I don't mind updating the commit message like this (but I am not the author
>> of the original patch).
>> 
> Vivek, are you happy with the above edited commit message ?

FWIW, with updated commit message feel free to use:

Reviewed-by: Alexey Klimov <alexey.klimov at linaro.org>

Best regards,
Alexey


From tabba at google.com  Thu Dec 11 06:30:03 2025
From: tabba at google.com (Fuad Tabba)
Date: Thu, 11 Dec 2025 14:30:03 +0000
Subject: [PATCH v2 4/6] KVM: arm64: Account for RES1 bits in
 DECLARE_FEAT_MAP() and co
In-Reply-To: <20251210173024.561160-5-maz@kernel.org>
References: <20251210173024.561160-1-maz@kernel.org> <20251210173024.561160-5-maz@kernel.org>
Message-ID: <CA+EHjTy2=NjAOwG32_Aj2akEDS8yo92nTMmd_rkUPABDAAcdAA@mail.gmail.com>

On Wed, 10 Dec 2025 at 17:30, Marc Zyngier <maz at kernel.org> wrote:
>
> None of the registers we manage in the feature dependency infrastructure
> so far has any RES1 bit. This is about to change, as VTCR_EL2 has
> its bit 31 being RES1.
>
> In order to not fail the consistency checks by not describing a bit,
> add RES1 bits to the set of immutable bits. This requires some extra
> surgery for the FGT handling, as we now need to track RES1 bits there
> as well.
>
> There are no RES1 FGT bits *yet*. Watch this space.
>
> Signed-off-by: Marc Zyngier <maz at kernel.org>


Reviewed-by: Fuad Tabba <tabba at google.com>

/fuad

> ---
>  arch/arm64/include/asm/kvm_host.h |  1 +
>  arch/arm64/kvm/config.c           | 25 +++++++-------
>  arch/arm64/kvm/emulate-nested.c   | 55 +++++++++++++++++--------------
>  3 files changed, 45 insertions(+), 36 deletions(-)
>
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index ac7f970c78830..b552a1e03848c 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -638,6 +638,7 @@ struct fgt_masks {
>         u64             mask;
>         u64             nmask;
>         u64             res0;
> +       u64             res1;
>  };
>
>  extern struct fgt_masks hfgrtr_masks;
> diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
> index 24bb3f36e9d59..3845b188551b6 100644
> --- a/arch/arm64/kvm/config.c
> +++ b/arch/arm64/kvm/config.c
> @@ -16,14 +16,14 @@
>   */
>  struct reg_bits_to_feat_map {
>         union {
> -               u64     bits;
> -               u64     *res0p;
> +               u64              bits;
> +               struct fgt_masks *masks;
>         };
>
>  #define        NEVER_FGU       BIT(0)  /* Can trap, but never UNDEF */
>  #define        CALL_FUNC       BIT(1)  /* Needs to evaluate tons of crap */
>  #define        FIXED_VALUE     BIT(2)  /* RAZ/WI or RAO/WI in KVM */
> -#define        RES0_POINTER    BIT(3)  /* Pointer to RES0 value instead of bits */
> +#define        MASKS_POINTER   BIT(3)  /* Pointer to fgt_masks struct instead of bits */
>
>         unsigned long   flags;
>
> @@ -92,8 +92,8 @@ struct reg_feat_map_desc {
>  #define NEEDS_FEAT_FIXED(m, ...)                       \
>         __NEEDS_FEAT_FLAG(m, FIXED_VALUE, bits, __VA_ARGS__, 0)
>
> -#define NEEDS_FEAT_RES0(p, ...)                                \
> -       __NEEDS_FEAT_FLAG(p, RES0_POINTER, res0p, __VA_ARGS__)
> +#define NEEDS_FEAT_MASKS(p, ...)                               \
> +       __NEEDS_FEAT_FLAG(p, MASKS_POINTER, masks, __VA_ARGS__)
>
>  /*
>   * Declare the dependency between a set of bits and a set of features,
> @@ -109,19 +109,20 @@ struct reg_feat_map_desc {
>  #define DECLARE_FEAT_MAP(n, r, m, f)                                   \
>         struct reg_feat_map_desc n = {                                  \
>                 .name                   = #r,                           \
> -               .feat_map               = NEEDS_FEAT(~r##_RES0, f),     \
> +               .feat_map               = NEEDS_FEAT(~(r##_RES0 |       \
> +                                                      r##_RES1), f),   \
>                 .bit_feat_map           = m,                            \
>                 .bit_feat_map_sz        = ARRAY_SIZE(m),                \
>         }
>
>  /*
>   * Specialised version of the above for FGT registers that have their
> - * RES0 masks described as struct fgt_masks.
> + * RESx masks described as struct fgt_masks.
>   */
>  #define DECLARE_FEAT_MAP_FGT(n, msk, m, f)                             \
>         struct reg_feat_map_desc n = {                                  \
>                 .name                   = #msk,                         \
> -               .feat_map               = NEEDS_FEAT_RES0(&msk.res0, f),\
> +               .feat_map               = NEEDS_FEAT_MASKS(&msk, f),    \
>                 .bit_feat_map           = m,                            \
>                 .bit_feat_map_sz        = ARRAY_SIZE(m),                \
>         }
> @@ -1168,21 +1169,21 @@ static const DECLARE_FEAT_MAP(mdcr_el2_desc, MDCR_EL2,
>                               mdcr_el2_feat_map, FEAT_AA64EL2);
>
>  static void __init check_feat_map(const struct reg_bits_to_feat_map *map,
> -                                 int map_size, u64 res0, const char *str)
> +                                 int map_size, u64 resx, const char *str)
>  {
>         u64 mask = 0;
>
>         for (int i = 0; i < map_size; i++)
>                 mask |= map[i].bits;
>
> -       if (mask != ~res0)
> +       if (mask != ~resx)
>                 kvm_err("Undefined %s behaviour, bits %016llx\n",
> -                       str, mask ^ ~res0);
> +                       str, mask ^ ~resx);
>  }
>
>  static u64 reg_feat_map_bits(const struct reg_bits_to_feat_map *map)
>  {
> -       return map->flags & RES0_POINTER ? ~(*map->res0p) : map->bits;
> +       return map->flags & MASKS_POINTER ? (map->masks->mask | map->masks->nmask) : map->bits;
>  }
>
>  static void __init check_reg_desc(const struct reg_feat_map_desc *r)
> diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c
> index 834f13fb1fb7d..75d49f83342a5 100644
> --- a/arch/arm64/kvm/emulate-nested.c
> +++ b/arch/arm64/kvm/emulate-nested.c
> @@ -2105,23 +2105,24 @@ static u32 encoding_next(u32 encoding)
>  }
>
>  #define FGT_MASKS(__n, __m)                                            \
> -       struct fgt_masks __n = { .str = #__m, .res0 = __m, }
> -
> -FGT_MASKS(hfgrtr_masks, HFGRTR_EL2_RES0);
> -FGT_MASKS(hfgwtr_masks, HFGWTR_EL2_RES0);
> -FGT_MASKS(hfgitr_masks, HFGITR_EL2_RES0);
> -FGT_MASKS(hdfgrtr_masks, HDFGRTR_EL2_RES0);
> -FGT_MASKS(hdfgwtr_masks, HDFGWTR_EL2_RES0);
> -FGT_MASKS(hafgrtr_masks, HAFGRTR_EL2_RES0);
> -FGT_MASKS(hfgrtr2_masks, HFGRTR2_EL2_RES0);
> -FGT_MASKS(hfgwtr2_masks, HFGWTR2_EL2_RES0);
> -FGT_MASKS(hfgitr2_masks, HFGITR2_EL2_RES0);
> -FGT_MASKS(hdfgrtr2_masks, HDFGRTR2_EL2_RES0);
> -FGT_MASKS(hdfgwtr2_masks, HDFGWTR2_EL2_RES0);
> +       struct fgt_masks __n = { .str = #__m, .res0 = __m ## _RES0, .res1 = __m ## _RES1 }
> +
> +FGT_MASKS(hfgrtr_masks, HFGRTR_EL2);
> +FGT_MASKS(hfgwtr_masks, HFGWTR_EL2);
> +FGT_MASKS(hfgitr_masks, HFGITR_EL2);
> +FGT_MASKS(hdfgrtr_masks, HDFGRTR_EL2);
> +FGT_MASKS(hdfgwtr_masks, HDFGWTR_EL2);
> +FGT_MASKS(hafgrtr_masks, HAFGRTR_EL2);
> +FGT_MASKS(hfgrtr2_masks, HFGRTR2_EL2);
> +FGT_MASKS(hfgwtr2_masks, HFGWTR2_EL2);
> +FGT_MASKS(hfgitr2_masks, HFGITR2_EL2);
> +FGT_MASKS(hdfgrtr2_masks, HDFGRTR2_EL2);
> +FGT_MASKS(hdfgwtr2_masks, HDFGWTR2_EL2);
>
>  static __init bool aggregate_fgt(union trap_config tc)
>  {
>         struct fgt_masks *rmasks, *wmasks;
> +       u64 rresx, wresx;
>
>         switch (tc.fgt) {
>         case HFGRTR_GROUP:
> @@ -2154,24 +2155,27 @@ static __init bool aggregate_fgt(union trap_config tc)
>                 break;
>         }
>
> +       rresx = rmasks->res0 | rmasks->res1;
> +       if (wmasks)
> +               wresx = wmasks->res0 | wmasks->res1;
> +
>         /*
>          * A bit can be reserved in either the R or W register, but
>          * not both.
>          */
> -       if ((BIT(tc.bit) & rmasks->res0) &&
> -           (!wmasks || (BIT(tc.bit) & wmasks->res0)))
> +       if ((BIT(tc.bit) & rresx) && (!wmasks || (BIT(tc.bit) & wresx)))
>                 return false;
>
>         if (tc.pol)
> -               rmasks->mask |= BIT(tc.bit) & ~rmasks->res0;
> +               rmasks->mask |= BIT(tc.bit) & ~rresx;
>         else
> -               rmasks->nmask |= BIT(tc.bit) & ~rmasks->res0;
> +               rmasks->nmask |= BIT(tc.bit) & ~rresx;
>
>         if (wmasks) {
>                 if (tc.pol)
> -                       wmasks->mask |= BIT(tc.bit) & ~wmasks->res0;
> +                       wmasks->mask |= BIT(tc.bit) & ~wresx;
>                 else
> -                       wmasks->nmask |= BIT(tc.bit) & ~wmasks->res0;
> +                       wmasks->nmask |= BIT(tc.bit) & ~wresx;
>         }
>
>         return true;
> @@ -2180,7 +2184,6 @@ static __init bool aggregate_fgt(union trap_config tc)
>  static __init int check_fgt_masks(struct fgt_masks *masks)
>  {
>         unsigned long duplicate = masks->mask & masks->nmask;
> -       u64 res0 = masks->res0;
>         int ret = 0;
>
>         if (duplicate) {
> @@ -2194,10 +2197,14 @@ static __init int check_fgt_masks(struct fgt_masks *masks)
>                 ret = -EINVAL;
>         }
>
> -       masks->res0 = ~(masks->mask | masks->nmask);
> -       if (masks->res0 != res0)
> -               kvm_info("Implicit %s = %016llx, expecting %016llx\n",
> -                        masks->str, masks->res0, res0);
> +       if ((masks->res0 | masks->res1 | masks->mask | masks->nmask) != GENMASK(63, 0) ||
> +           (masks->res0 & masks->res1)  || (masks->res0 & masks->mask) ||
> +           (masks->res0 & masks->nmask) || (masks->res1 & masks->mask)  ||
> +           (masks->res1 & masks->nmask) || (masks->mask & masks->nmask)) {
> +               kvm_info("Inconsistent masks for %s (%016llx, %016llx, %016llx, %016llx)\n",
> +                        masks->str, masks->res0, masks->res1, masks->mask, masks->nmask);
> +               masks->res0 = ~(masks->res1 | masks->mask | masks->nmask);
> +       }
>
>         return ret;
>  }
> --
> 2.47.3
>


From maz at kernel.org  Thu Dec 11 06:30:53 2025
From: maz at kernel.org (Marc Zyngier)
Date: Thu, 11 Dec 2025 14:30:53 +0000
Subject: [PATCH v2 1/6] KVM: arm64: Fix EL2 S1 XN handling for hVHE setups
In-Reply-To: <CA+EHjTwh=Vop_v5+2_wj57Y-Wg=Q12aw7hUYdNB2CGA4Kq0ZKQ@mail.gmail.com>
References: <20251210173024.561160-1-maz@kernel.org>
	<20251210173024.561160-2-maz@kernel.org>
	<CA+EHjTwh=Vop_v5+2_wj57Y-Wg=Q12aw7hUYdNB2CGA4Kq0ZKQ@mail.gmail.com>
Message-ID: <86v7idnl9e.wl-maz@kernel.org>

On Thu, 11 Dec 2025 13:37:50 +0000,
Fuad Tabba <tabba at google.com> wrote:
> 
> Hi Marc,
> 
> 
> On Wed, 10 Dec 2025 at 17:30, Marc Zyngier <maz at kernel.org> wrote:
> >
> > The current XN implementation is tied to the EL2 translation regime,
> > and fall flat on its face with the EL2&0 one that is used for hVHE,
> > as the permission bit for privileged execution is a different one.
> >
> > Fixes: 6537565fd9b7f ("KVM: arm64: Adjust EL2 stage-1 leaf AP bits when ARM64_KVM_HVHE is set")
> > Signed-off-by: Marc Zyngier <maz at kernel.org>
> > ---
> >  arch/arm64/include/asm/kvm_pgtable.h | 10 +++++++++-
> >  1 file changed, 9 insertions(+), 1 deletion(-)
> >
> > diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h
> > index fc02de43c68dd..be68b89692065 100644
> > --- a/arch/arm64/include/asm/kvm_pgtable.h
> > +++ b/arch/arm64/include/asm/kvm_pgtable.h
> > @@ -87,7 +87,15 @@ typedef u64 kvm_pte_t;
> >
> >  #define KVM_PTE_LEAF_ATTR_HI_SW                GENMASK(58, 55)
> >
> > -#define KVM_PTE_LEAF_ATTR_HI_S1_XN     BIT(54)
> > +#define __KVM_PTE_LEAF_ATTR_HI_S1_XN   BIT(54)
> > +#define __KVM_PTE_LEAF_ATTR_HI_S1_UXN  BIT(54)
> > +#define __KVM_PTE_LEAF_ATTR_HI_S1_PXN  BIT(53)
> > +
> > +#define KVM_PTE_LEAF_ATTR_HI_S1_XN                                     \
> > +       ({ cpus_have_final_cap(ARM64_KVM_HVHE) ?                        \
> > +                       (__KVM_PTE_LEAF_ATTR_HI_S1_UXN |                \
> > +                        __KVM_PTE_LEAF_ATTR_HI_S1_PXN) :               \
> > +                       __KVM_PTE_LEAF_ATTR_HI_S1_XN; })
> >
> >  #define KVM_PTE_LEAF_ATTR_HI_S2_XN     GENMASK(54, 53)
> 
> I was just wondering, is this patch really necessary, considering
> patch 6/6 redos the whole thing and fixes the bug?

I want this one to be in a state where it can be backported, without
having to deal with the NV-induced FEAT_XNX support. This is why it is
a standalone patch.

> That said:
> Reviewed-by: Fuad Tabba <tabba at google.com>

Thanks!

	M.

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


From tabba at google.com  Thu Dec 11 06:44:11 2025
From: tabba at google.com (Fuad Tabba)
Date: Thu, 11 Dec 2025 14:44:11 +0000
Subject: [PATCH v2 5/6] KVM: arm64: Convert VTCR_EL2 to config-driven sanitisation
In-Reply-To: <20251210173024.561160-6-maz@kernel.org>
References: <20251210173024.561160-1-maz@kernel.org> <20251210173024.561160-6-maz@kernel.org>
Message-ID: <CA+EHjTxzoN_rg9RQsq0BLgp9zp29rAx5Zxrndas07d5sjSQXLQ@mail.gmail.com>

On Wed, 10 Dec 2025 at 17:30, Marc Zyngier <maz at kernel.org> wrote:
>
> Describe all the VTCR_EL2 fields and their respective configurations,
> making sure that we correctly ignore the bits that are not defined
> for a given guest configuration.
>
> Reviewed-by: Alexandru Elisei <alexandru.elisei at arm.com>
> Signed-off-by: Marc Zyngier <maz at kernel.org>
> ---

Reviewed-by: Fuad Tabba <tabba at google.com>

/fuad

>  arch/arm64/kvm/config.c | 69 +++++++++++++++++++++++++++++++++++++++++
>  arch/arm64/kvm/nested.c |  3 +-
>  2 files changed, 70 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
> index 3845b188551b6..9c04f895d3769 100644
> --- a/arch/arm64/kvm/config.c
> +++ b/arch/arm64/kvm/config.c
> @@ -141,6 +141,7 @@ struct reg_feat_map_desc {
>  #define FEAT_AA64EL1           ID_AA64PFR0_EL1, EL1, IMP
>  #define FEAT_AA64EL2           ID_AA64PFR0_EL1, EL2, IMP
>  #define FEAT_AA64EL3           ID_AA64PFR0_EL1, EL3, IMP
> +#define FEAT_SEL2              ID_AA64PFR0_EL1, SEL2, IMP
>  #define FEAT_AIE               ID_AA64MMFR3_EL1, AIE, IMP
>  #define FEAT_S2POE             ID_AA64MMFR3_EL1, S2POE, IMP
>  #define FEAT_S1POE             ID_AA64MMFR3_EL1, S1POE, IMP
> @@ -202,6 +203,8 @@ struct reg_feat_map_desc {
>  #define FEAT_ASID2             ID_AA64MMFR4_EL1, ASID2, IMP
>  #define FEAT_MEC               ID_AA64MMFR3_EL1, MEC, IMP
>  #define FEAT_HAFT              ID_AA64MMFR1_EL1, HAFDBS, HAFT
> +#define FEAT_HDBSS             ID_AA64MMFR1_EL1, HAFDBS, HDBSS
> +#define FEAT_HPDS2             ID_AA64MMFR1_EL1, HPDS, HPDS2
>  #define FEAT_BTI               ID_AA64PFR1_EL1, BT, IMP
>  #define FEAT_ExS               ID_AA64MMFR0_EL1, EXS, IMP
>  #define FEAT_IESB              ID_AA64MMFR2_EL1, IESB, IMP
> @@ -219,6 +222,7 @@ struct reg_feat_map_desc {
>  #define FEAT_FGT2              ID_AA64MMFR0_EL1, FGT, FGT2
>  #define FEAT_MTPMU             ID_AA64DFR0_EL1, MTPMU, IMP
>  #define FEAT_HCX               ID_AA64MMFR1_EL1, HCX, IMP
> +#define FEAT_S2PIE             ID_AA64MMFR3_EL1, S2PIE, IMP
>
>  static bool not_feat_aa64el3(struct kvm *kvm)
>  {
> @@ -362,6 +366,28 @@ static bool feat_pmuv3p9(struct kvm *kvm)
>         return check_pmu_revision(kvm, V3P9);
>  }
>
> +#define has_feat_s2tgran(k, s)                                         \
> +  ((kvm_has_feat_enum(kvm, ID_AA64MMFR0_EL1, TGRAN##s##_2, TGRAN##s) && \
> +    kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN##s, IMP))                     || \
> +   kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN##s##_2, IMP))
> +
> +static bool feat_lpa2(struct kvm *kvm)
> +{
> +       return ((kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4, 52_BIT)    ||
> +                !kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4, IMP))     &&
> +               (kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16, 52_BIT)   ||
> +                !kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16, IMP))    &&
> +               (kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN4_2, 52_BIT)  ||
> +                !has_feat_s2tgran(kvm, 4))                             &&
> +               (kvm_has_feat(kvm, ID_AA64MMFR0_EL1, TGRAN16_2, 52_BIT) ||
> +                !has_feat_s2tgran(kvm, 16)));
> +}
> +
> +static bool feat_vmid16(struct kvm *kvm)
> +{
> +       return kvm_has_feat_enum(kvm, ID_AA64MMFR1_EL1, VMIDBits, 16);
> +}
> +
>  static bool compute_hcr_rw(struct kvm *kvm, u64 *bits)
>  {
>         /* This is purely academic: AArch32 and NV are mutually exclusive */
> @@ -1168,6 +1194,44 @@ static const struct reg_bits_to_feat_map mdcr_el2_feat_map[] = {
>  static const DECLARE_FEAT_MAP(mdcr_el2_desc, MDCR_EL2,
>                               mdcr_el2_feat_map, FEAT_AA64EL2);
>
> +static const struct reg_bits_to_feat_map vtcr_el2_feat_map[] = {
> +       NEEDS_FEAT(VTCR_EL2_HDBSS, FEAT_HDBSS),
> +       NEEDS_FEAT(VTCR_EL2_HAFT, FEAT_HAFT),
> +       NEEDS_FEAT(VTCR_EL2_TL0         |
> +                  VTCR_EL2_TL1         |
> +                  VTCR_EL2_AssuredOnly |
> +                  VTCR_EL2_GCSH,
> +                  FEAT_THE),
> +       NEEDS_FEAT(VTCR_EL2_D128, FEAT_D128),
> +       NEEDS_FEAT(VTCR_EL2_S2POE, FEAT_S2POE),
> +       NEEDS_FEAT(VTCR_EL2_S2PIE, FEAT_S2PIE),
> +       NEEDS_FEAT(VTCR_EL2_SL2         |
> +                  VTCR_EL2_DS,
> +                  feat_lpa2),
> +       NEEDS_FEAT(VTCR_EL2_NSA         |
> +                  VTCR_EL2_NSW,
> +                  FEAT_SEL2),
> +       NEEDS_FEAT(VTCR_EL2_HWU62       |
> +                  VTCR_EL2_HWU61       |
> +                  VTCR_EL2_HWU60       |
> +                  VTCR_EL2_HWU59,
> +                  FEAT_HPDS2),
> +       NEEDS_FEAT(VTCR_EL2_HD, ID_AA64MMFR1_EL1, HAFDBS, DBM),
> +       NEEDS_FEAT(VTCR_EL2_HA, ID_AA64MMFR1_EL1, HAFDBS, AF),
> +       NEEDS_FEAT(VTCR_EL2_VS, feat_vmid16),
> +       NEEDS_FEAT(VTCR_EL2_PS          |
> +                  VTCR_EL2_TG0         |
> +                  VTCR_EL2_SH0         |
> +                  VTCR_EL2_ORGN0       |
> +                  VTCR_EL2_IRGN0       |
> +                  VTCR_EL2_SL0         |
> +                  VTCR_EL2_T0SZ,
> +                  FEAT_AA64EL1),
> +};
> +
> +static const DECLARE_FEAT_MAP(vtcr_el2_desc, VTCR_EL2,
> +                             vtcr_el2_feat_map, FEAT_AA64EL2);
> +
>  static void __init check_feat_map(const struct reg_bits_to_feat_map *map,
>                                   int map_size, u64 resx, const char *str)
>  {
> @@ -1211,6 +1275,7 @@ void __init check_feature_map(void)
>         check_reg_desc(&tcr2_el2_desc);
>         check_reg_desc(&sctlr_el1_desc);
>         check_reg_desc(&mdcr_el2_desc);
> +       check_reg_desc(&vtcr_el2_desc);
>  }
>
>  static bool idreg_feat_match(struct kvm *kvm, const struct reg_bits_to_feat_map *map)
> @@ -1425,6 +1490,10 @@ void get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg, u64 *res0, u64 *r
>                 *res0 = compute_reg_res0_bits(kvm, &mdcr_el2_desc, 0, 0);
>                 *res1 = MDCR_EL2_RES1;
>                 break;
> +       case VTCR_EL2:
> +               *res0 = compute_reg_res0_bits(kvm, &vtcr_el2_desc, 0, 0);
> +               *res1 = VTCR_EL2_RES1;
> +               break;
>         default:
>                 WARN_ON_ONCE(1);
>                 *res0 = *res1 = 0;
> diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
> index e1ef8930c97b3..606cebcaa7c09 100644
> --- a/arch/arm64/kvm/nested.c
> +++ b/arch/arm64/kvm/nested.c
> @@ -1719,8 +1719,7 @@ int kvm_init_nv_sysregs(struct kvm_vcpu *vcpu)
>         set_sysreg_masks(kvm, VTTBR_EL2, res0, res1);
>
>         /* VTCR_EL2 */
> -       res0 = GENMASK(63, 32) | GENMASK(30, 20);
> -       res1 = BIT(31);
> +       get_reg_fixed_bits(kvm, VTCR_EL2, &res0, &res1);
>         set_sysreg_masks(kvm, VTCR_EL2, res0, res1);
>
>         /* VMPIDR_EL2 */
> --
> 2.47.3
>


From tabba at google.com  Thu Dec 11 06:51:25 2025
From: tabba at google.com (Fuad Tabba)
Date: Thu, 11 Dec 2025 14:51:25 +0000
Subject: [PATCH v2 6/6] KVM: arm64: Honor UX/PX attributes for EL2 S1 mappings
In-Reply-To: <20251210173024.561160-7-maz@kernel.org>
References: <20251210173024.561160-1-maz@kernel.org> <20251210173024.561160-7-maz@kernel.org>
Message-ID: <CA+EHjTwi3S-BVYQWf6_TAyd4fi18Ng3G3HkxKh2MB8PrE_32Uw@mail.gmail.com>

On Wed, 10 Dec 2025 at 17:30, Marc Zyngier <maz at kernel.org> wrote:
>
> Now that we potentially have two bits to deal with when setting
> execution permissions, make sure we correctly handle them when both
> when building the page tables and when reading back from them.
>
> Reported-by: Alexandru Elisei <alexandru.elisei at arm.com>
> Signed-off-by: Marc Zyngier <maz at kernel.org>

Reviewed-by: Fuad Tabba <tabba at google.com>

/fuad

> ---
>  arch/arm64/include/asm/kvm_pgtable.h | 12 +++---------
>  arch/arm64/kvm/hyp/pgtable.c         | 24 +++++++++++++++++++++---
>  2 files changed, 24 insertions(+), 12 deletions(-)
>
> diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h
> index be68b89692065..095e6b73740a6 100644
> --- a/arch/arm64/include/asm/kvm_pgtable.h
> +++ b/arch/arm64/include/asm/kvm_pgtable.h
> @@ -87,15 +87,9 @@ typedef u64 kvm_pte_t;
>
>  #define KVM_PTE_LEAF_ATTR_HI_SW                GENMASK(58, 55)
>
> -#define __KVM_PTE_LEAF_ATTR_HI_S1_XN   BIT(54)
> -#define __KVM_PTE_LEAF_ATTR_HI_S1_UXN  BIT(54)
> -#define __KVM_PTE_LEAF_ATTR_HI_S1_PXN  BIT(53)
> -
> -#define KVM_PTE_LEAF_ATTR_HI_S1_XN                                     \
> -       ({ cpus_have_final_cap(ARM64_KVM_HVHE) ?                        \
> -                       (__KVM_PTE_LEAF_ATTR_HI_S1_UXN |                \
> -                        __KVM_PTE_LEAF_ATTR_HI_S1_PXN) :               \
> -                       __KVM_PTE_LEAF_ATTR_HI_S1_XN; })
> +#define KVM_PTE_LEAF_ATTR_HI_S1_XN     BIT(54)
> +#define KVM_PTE_LEAF_ATTR_HI_S1_UXN    BIT(54)
> +#define KVM_PTE_LEAF_ATTR_HI_S1_PXN    BIT(53)
>
>  #define KVM_PTE_LEAF_ATTR_HI_S2_XN     GENMASK(54, 53)
>
> diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
> index e0bd6a0172729..97c0835d25590 100644
> --- a/arch/arm64/kvm/hyp/pgtable.c
> +++ b/arch/arm64/kvm/hyp/pgtable.c
> @@ -342,6 +342,9 @@ static int hyp_set_prot_attr(enum kvm_pgtable_prot prot, kvm_pte_t *ptep)
>         if (!(prot & KVM_PGTABLE_PROT_R))
>                 return -EINVAL;
>
> +       if (!cpus_have_final_cap(ARM64_KVM_HVHE))
> +               prot &= ~KVM_PGTABLE_PROT_UX;
> +
>         if (prot & KVM_PGTABLE_PROT_X) {
>                 if (prot & KVM_PGTABLE_PROT_W)
>                         return -EINVAL;
> @@ -351,8 +354,16 @@ static int hyp_set_prot_attr(enum kvm_pgtable_prot prot, kvm_pte_t *ptep)
>
>                 if (system_supports_bti_kernel())
>                         attr |= KVM_PTE_LEAF_ATTR_HI_S1_GP;
> +       }
> +
> +       if (cpus_have_final_cap(ARM64_KVM_HVHE)) {
> +               if (!(prot & KVM_PGTABLE_PROT_PX))
> +                       attr |= KVM_PTE_LEAF_ATTR_HI_S1_PXN;
> +               if (!(prot & KVM_PGTABLE_PROT_UX))
> +                       attr |= KVM_PTE_LEAF_ATTR_HI_S1_UXN;
>         } else {
> -               attr |= KVM_PTE_LEAF_ATTR_HI_S1_XN;
> +               if (!(prot & KVM_PGTABLE_PROT_PX))
> +                       attr |= KVM_PTE_LEAF_ATTR_HI_S1_XN;
>         }
>
>         attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_AP, ap);
> @@ -373,8 +384,15 @@ enum kvm_pgtable_prot kvm_pgtable_hyp_pte_prot(kvm_pte_t pte)
>         if (!kvm_pte_valid(pte))
>                 return prot;
>
> -       if (!(pte & KVM_PTE_LEAF_ATTR_HI_S1_XN))
> -               prot |= KVM_PGTABLE_PROT_X;
> +       if (cpus_have_final_cap(ARM64_KVM_HVHE)) {
> +               if (!(pte & KVM_PTE_LEAF_ATTR_HI_S1_PXN))
> +                       prot |= KVM_PGTABLE_PROT_PX;
> +               if (!(pte & KVM_PTE_LEAF_ATTR_HI_S1_UXN))
> +                       prot |= KVM_PGTABLE_PROT_UX;
> +       } else {
> +               if (!(pte & KVM_PTE_LEAF_ATTR_HI_S1_XN))
> +                       prot |= KVM_PGTABLE_PROT_PX;
> +       }
>
>         ap = FIELD_GET(KVM_PTE_LEAF_ATTR_LO_S1_AP, pte);
>         if (ap == KVM_PTE_LEAF_ATTR_LO_S1_AP_RO)
> --
> 2.47.3
>


From tabba at google.com  Thu Dec 11 06:55:39 2025
From: tabba at google.com (Fuad Tabba)
Date: Thu, 11 Dec 2025 14:55:39 +0000
Subject: [PATCH v2 0/6] KVM: arm64: VTCR_EL2 conversion to feature
 dependency framework
In-Reply-To: <20251210173024.561160-1-maz@kernel.org>
References: <20251210173024.561160-1-maz@kernel.org>
Message-ID: <CA+EHjTx8LYCCY=W+ifaQ4Ny3mJ_+u0GL5T2FaKWvaX-oqVPT6A@mail.gmail.com>

Hi Marc,

On Wed, 10 Dec 2025 at 17:30, Marc Zyngier <maz at kernel.org> wrote:
>
> This is a follow-up on my VTCR_EL2 sanitisation series, with extra
> goodies, mostly as a consequence of Alexandru's patches and review.
>
> * From [1]:
>
>   - Added two patches fixing some FEAT_XNX issues: one dating back
>     from the hVHE introduction, and the other related to the newer
>     stuff in 6.19.
>
>   - Expanded the scope of the RES1 handling in DECLARE_FEAT_MAP() to
>     deal with FGTs, as we're about to get quality stuff thanks to
>     GICv5.
>
>   - Simplified the S2TGRANx detection slightly.
>
>   - Collected RBs, with thanks
>
> [1] https://lore.kernel.org/r/20251129144525.2609207-1-maz at kernel.org
>
> Marc Zyngier (6):
>   KVM: arm64: Fix EL2 S1 XN handling for hVHE setups
>   arm64: Convert ID_AA64MMFR0_EL1.TGRAN{4,16,64}_2 to UnsignedEnum
>   arm64: Convert VTCR_EL2 to sysreg infratructure
>   KVM: arm64: Account for RES1 bits in DECLARE_FEAT_MAP() and co
>   KVM: arm64: Convert VTCR_EL2 to config-driven sanitisation
>   KVM: arm64: Honor UX/PX attributes for EL2 S1 mappings

For the series, on qemu, hVHE and protected hVHE:
Tested-by: Fuad Tabba <tabba at google.com>


Cheers,
/fuad



>  arch/arm64/include/asm/kvm_arm.h     | 52 ++++-----------
>  arch/arm64/include/asm/kvm_host.h    |  1 +
>  arch/arm64/include/asm/kvm_pgtable.h |  2 +
>  arch/arm64/include/asm/sysreg.h      |  1 -
>  arch/arm64/kvm/config.c              | 94 ++++++++++++++++++++++++----
>  arch/arm64/kvm/emulate-nested.c      | 55 +++++++++-------
>  arch/arm64/kvm/hyp/pgtable.c         | 32 +++++++---
>  arch/arm64/kvm/nested.c              | 11 ++--
>  arch/arm64/tools/sysreg              | 63 ++++++++++++++++++-
>  9 files changed, 217 insertions(+), 94 deletions(-)
>
> --
> 2.47.3
>


From ariel.dalessandro at collabora.com  Thu Dec 11 07:16:08 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Thu, 11 Dec 2025 12:16:08 -0300
Subject: [PATCH RFC v2 07/20] drm/atomic: Pass post_blend_color_pipeline
 client cap to atomic check
In-Reply-To: <93edf489-c4f6-4f0d-a0d5-673da051983d@amd.com>
References: <20250917-mtk-post-blend-color-pipeline-v2-0-ac4471b44758@collabora.com>
 <20250917-mtk-post-blend-color-pipeline-v2-7-ac4471b44758@collabora.com>
 <93edf489-c4f6-4f0d-a0d5-673da051983d@amd.com>
Message-ID: <68c83842-16e9-429b-96c8-50c8a15c659c@collabora.com>

Harry,

On 9/29/25 6:50 AM, Harry Wentland wrote:
> 
> 
> On 2025-09-17 20:43, N?colas F. R. A. Prado wrote:
>> Pass the state of the post-blend color pipeline client cap to the atomic
>> state so that drivers can rely on it to enable color pipeline
>> functionality and ignore the deprecated color management CRTC
>> properties.
>>
>> Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
>> ---
>> ? drivers/gpu/drm/drm_atomic_uapi.c |? 1 +
>> ? include/drm/drm_atomic.h????????? | 20 ++++++++++++++++++++
>> ? 2 files changed, 21 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/ 
>> drm_atomic_uapi.c
>> index 
>> f5125fa3fa28ff2a6ff07fd7cf07d4bdf77ab738..56a440a9390c7730c4c41b491f29b933a2bbb889 100644
>> --- a/drivers/gpu/drm/drm_atomic_uapi.c
>> +++ b/drivers/gpu/drm/drm_atomic_uapi.c
>> @@ -1660,6 +1660,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
>> ????? state->acquire_ctx = &ctx;
>> ????? state->allow_modeset = !!(arg->flags & 
>> DRM_MODE_ATOMIC_ALLOW_MODESET);
>> ????? state->plane_color_pipeline = file_priv->plane_color_pipeline;
>> +??? state->post_blend_color_pipeline = file_priv- 
>> >post_blend_color_pipeline;
>> ? retry:
>> ????? copied_objs = 0;
>> diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
>> index 
>> 678708df9cdb90b4266127193a92183069f18688..8c42c584aefbf0034b2163d90538e80099b0dadb 100644
>> --- a/include/drm/drm_atomic.h
>> +++ b/include/drm/drm_atomic.h
>> @@ -482,6 +482,26 @@ struct drm_atomic_state {
>> ?????? */
>> ????? bool plane_color_pipeline : 1;
>> +??? /**
>> +???? * @post_blend_color_pipeline:
>> +???? *
>> +???? * Indicates whether this atomic state originated with a client that
>> +???? * set the DRM_CLIENT_CAP_POST_BLEND_COLOR_PIPELINE.
>> +???? *
>> +???? * Drivers and helper functions should use this to ignore legacy
>> +???? * properties that are incompatible with the drm_crtc COLOR_PIPELINE
>> +???? * behavior, such as:
>> +???? *
>> +???? *? - GAMMA_LUT
>> +???? *? - DEGAMMA_LUT
>> +???? *? - GAMMA_LUT_SIZE
>> +???? *? - CTM
>> +???? *
>> +???? * or any other driver-specific properties that might affect pixel
>> +???? * values.
>> +???? */
>> +??? bool post_blend_color_pipeline : 1;
> 
> As with the client cap name, I recommend calling this
> crtc_color_pipeline.

Agreed. As per the rest of the comments, I think it's worth moving all 
naming in this series from post_blend to crtc, matching the criteria 
used in plane (a.k.a. pre-blend) color pipelines.

Will submit the related changes in v3.

Regards,

-- 
Ariel D'Alessandro
Software Engineer

Collabora Ltd.
Platinum Building, St John's Innovation Park, Cambridge CB4 0DS, UK 
Registered in England & Wales, no. 5513718



From joey.gouly at arm.com  Thu Dec 11 07:18:51 2025
From: joey.gouly at arm.com (Joey Gouly)
Date: Thu, 11 Dec 2025 15:18:51 +0000
Subject: [PATCH v2 6/6] KVM: arm64: Honor UX/PX attributes for EL2 S1
 mappings
In-Reply-To: <20251210173024.561160-7-maz@kernel.org>
References: <20251210173024.561160-1-maz@kernel.org>
 <20251210173024.561160-7-maz@kernel.org>
Message-ID: <20251211151810.GA867614@e124191.cambridge.arm.com>

Question,

On Wed, Dec 10, 2025 at 05:30:24PM +0000, Marc Zyngier wrote:
> Now that we potentially have two bits to deal with when setting
> execution permissions, make sure we correctly handle them when both
> when building the page tables and when reading back from them.
> 
> Reported-by: Alexandru Elisei <alexandru.elisei at arm.com>
> Signed-off-by: Marc Zyngier <maz at kernel.org>
> ---
>  arch/arm64/include/asm/kvm_pgtable.h | 12 +++---------
>  arch/arm64/kvm/hyp/pgtable.c         | 24 +++++++++++++++++++++---
>  2 files changed, 24 insertions(+), 12 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h
> index be68b89692065..095e6b73740a6 100644
> --- a/arch/arm64/include/asm/kvm_pgtable.h
> +++ b/arch/arm64/include/asm/kvm_pgtable.h
> @@ -87,15 +87,9 @@ typedef u64 kvm_pte_t;
>  
>  #define KVM_PTE_LEAF_ATTR_HI_SW		GENMASK(58, 55)
>  
> -#define __KVM_PTE_LEAF_ATTR_HI_S1_XN	BIT(54)
> -#define __KVM_PTE_LEAF_ATTR_HI_S1_UXN	BIT(54)
> -#define __KVM_PTE_LEAF_ATTR_HI_S1_PXN	BIT(53)
> -
> -#define KVM_PTE_LEAF_ATTR_HI_S1_XN					\
> -	({ cpus_have_final_cap(ARM64_KVM_HVHE) ?			\
> -			(__KVM_PTE_LEAF_ATTR_HI_S1_UXN |		\
> -			 __KVM_PTE_LEAF_ATTR_HI_S1_PXN) :		\
> -			__KVM_PTE_LEAF_ATTR_HI_S1_XN; })
> +#define KVM_PTE_LEAF_ATTR_HI_S1_XN	BIT(54)
> +#define KVM_PTE_LEAF_ATTR_HI_S1_UXN	BIT(54)
> +#define KVM_PTE_LEAF_ATTR_HI_S1_PXN	BIT(53)
>  
>  #define KVM_PTE_LEAF_ATTR_HI_S2_XN	GENMASK(54, 53)
>  
> diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
> index e0bd6a0172729..97c0835d25590 100644
> --- a/arch/arm64/kvm/hyp/pgtable.c
> +++ b/arch/arm64/kvm/hyp/pgtable.c
> @@ -342,6 +342,9 @@ static int hyp_set_prot_attr(enum kvm_pgtable_prot prot, kvm_pte_t *ptep)
>  	if (!(prot & KVM_PGTABLE_PROT_R))
>  		return -EINVAL;
>  
> +	if (!cpus_have_final_cap(ARM64_KVM_HVHE))
> +		prot &= ~KVM_PGTABLE_PROT_UX;

Trying to understand this part. We don't consider KVM_PGTABLE_PROT_UX below
when !HVHE, and we don't set it in kvm_pgtable_hyp_pte_prot() when !HVHE
either, so can it ever actually be set?

Otherwise LGTM!

Thanks,
Joey

> +
>  	if (prot & KVM_PGTABLE_PROT_X) {
>  		if (prot & KVM_PGTABLE_PROT_W)
>  			return -EINVAL;
> @@ -351,8 +354,16 @@ static int hyp_set_prot_attr(enum kvm_pgtable_prot prot, kvm_pte_t *ptep)
>  
>  		if (system_supports_bti_kernel())
>  			attr |= KVM_PTE_LEAF_ATTR_HI_S1_GP;
> +	}
> +
> +	if (cpus_have_final_cap(ARM64_KVM_HVHE)) {
> +		if (!(prot & KVM_PGTABLE_PROT_PX))
> +			attr |= KVM_PTE_LEAF_ATTR_HI_S1_PXN;
> +		if (!(prot & KVM_PGTABLE_PROT_UX))
> +			attr |= KVM_PTE_LEAF_ATTR_HI_S1_UXN;
>  	} else {
> -		attr |= KVM_PTE_LEAF_ATTR_HI_S1_XN;
> +		if (!(prot & KVM_PGTABLE_PROT_PX))
> +			attr |= KVM_PTE_LEAF_ATTR_HI_S1_XN;
>  	}
>  
>  	attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_AP, ap);
> @@ -373,8 +384,15 @@ enum kvm_pgtable_prot kvm_pgtable_hyp_pte_prot(kvm_pte_t pte)
>  	if (!kvm_pte_valid(pte))
>  		return prot;
>  
> -	if (!(pte & KVM_PTE_LEAF_ATTR_HI_S1_XN))
> -		prot |= KVM_PGTABLE_PROT_X;
> +	if (cpus_have_final_cap(ARM64_KVM_HVHE)) {
> +		if (!(pte & KVM_PTE_LEAF_ATTR_HI_S1_PXN))
> +			prot |= KVM_PGTABLE_PROT_PX;
> +		if (!(pte & KVM_PTE_LEAF_ATTR_HI_S1_UXN))
> +			prot |= KVM_PGTABLE_PROT_UX;
> +	} else {
> +		if (!(pte & KVM_PTE_LEAF_ATTR_HI_S1_XN))
> +			prot |= KVM_PGTABLE_PROT_PX;
> +	}
>  
>  	ap = FIELD_GET(KVM_PTE_LEAF_ATTR_LO_S1_AP, pte);
>  	if (ap == KVM_PTE_LEAF_ATTR_LO_S1_AP_RO)
> -- 
> 2.47.3
> 


From robh at kernel.org  Thu Dec 11 07:20:07 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Thu, 11 Dec 2025 09:20:07 -0600
Subject: [PATCH v10 2/4] dt-bindings: PCI: pci-imx6: Add external
 reference clock input
In-Reply-To: <20251211064821.2707001-3-hongxing.zhu@nxp.com>
References: <20251211064821.2707001-1-hongxing.zhu@nxp.com>
 <20251211064821.2707001-3-hongxing.zhu@nxp.com>
Message-ID: <176546640668.1250530.16683675929770601103.robh@kernel.org>


On Thu, 11 Dec 2025 14:48:19 +0800, Richard Zhu wrote:
> i.MX95 PCIes have two reference clock inputs: one from internal PLL.
> It's wired inside chip and present as "ref" clock. It's not an optional
> clock. The other from off chip crystal oscillator. The "extref" clock
> refers to a reference clock from an external crystal oscillator through
> the CLKIN_N/P pair PADs. It is an optional clock, relied on the board
> design.
> 
> Add additional optional external reference clock input for i.MX95 PCIes.
> 
> Signed-off-by: Richard Zhu <hongxing.zhu at nxp.com>
> Reviewed-by: Frank Li <Frank.Li at nxp.com>
> ---
>  Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml | 7 +++++--
>  1 file changed, 5 insertions(+), 2 deletions(-)
> 

Reviewed-by: Rob Herring (Arm) <robh at kernel.org>



From ariel.dalessandro at collabora.com  Thu Dec 11 07:26:29 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Thu, 11 Dec 2025 12:26:29 -0300
Subject: [PATCH RFC v2 06/20] drm: Introduce
 DRM_CLIENT_CAP_POST_BLEND_COLOR_PIPELINE
In-Reply-To: <5e5017ae-b71a-4933-b248-e68d52fab7ff@amd.com>
References: <20250917-mtk-post-blend-color-pipeline-v2-0-ac4471b44758@collabora.com>
 <20250917-mtk-post-blend-color-pipeline-v2-6-ac4471b44758@collabora.com>
 <5e5017ae-b71a-4933-b248-e68d52fab7ff@amd.com>
Message-ID: <c81767da-baf5-4531-abb2-c23f8005ea12@collabora.com>

Harry,

On 9/29/25 6:48 AM, Harry Wentland wrote:
> 
> 
> On 2025-09-17 20:43, N?colas F. R. A. Prado wrote:
>> Introduce DRM_CLIENT_CAP_POST_BLEND_COLOR_PIPELINE which a DRM client
>> can set to enable the usage of post-blend color pipelines instead of the
>> now deprecated CRTC color management properties: "GAMMA_LUT",
>> "DEGAMMA_LUT" and "CTM".
>>
>> Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
>> ---
>> ? drivers/gpu/drm/drm_atomic_uapi.c?? | 15 +++++++++++++++
>> ? drivers/gpu/drm/drm_connector.c???? |? 1 +
>> ? drivers/gpu/drm/drm_crtc_internal.h |? 1 +
>> ? drivers/gpu/drm/drm_ioctl.c???????? |? 9 +++++++++
>> ? drivers/gpu/drm/drm_mode_object.c?? |? 9 +++++++++
>> ? include/drm/drm_file.h????????????? |? 7 +++++++
>> ? include/uapi/drm/drm.h????????????? | 19 +++++++++++++++++++
>> ? 7 files changed, 61 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/ 
>> drm_atomic_uapi.c
>> index 
>> 063c142fd9b656e228cfc660d005a3fbb4640d32..f5125fa3fa28ff2a6ff07fd7cf07d4bdf77ab738 100644
>> --- a/drivers/gpu/drm/drm_atomic_uapi.c
>> +++ b/drivers/gpu/drm/drm_atomic_uapi.c
>> @@ -452,6 +452,11 @@ static int drm_atomic_crtc_set_property(struct 
>> drm_crtc *crtc,
>> ????? } else if (property == config->prop_vrr_enabled) {
>> ????????? state->vrr_enabled = val;
>> ????? } else if (property == config->degamma_lut_property) {
>> +??????? if (file_priv->post_blend_color_pipeline) {
>> +??????????? drm_dbg_atomic(dev,
>> +??????????????? "Setting DEGAMMA_LUT CRTC property not permitted with 
>> DRM_CLIENT_CAP_POST_BLEND_COLOR_PIPELINE client cap\n");
>> +??????????? return -EINVAL;
>> +??????? }
>> ????????? ret = drm_property_replace_blob_from_id(dev,
>> ????????????????????? &state->degamma_lut,
>> ????????????????????? val,
>> @@ -460,6 +465,11 @@ static int drm_atomic_crtc_set_property(struct 
>> drm_crtc *crtc,
>> ????????? state->color_mgmt_changed |= replaced;
>> ????????? return ret;
>> ????? } else if (property == config->ctm_property) {
>> +??????? if (file_priv->post_blend_color_pipeline) {
>> +??????????? drm_dbg_atomic(dev,
>> +??????????????? "Setting CTM CRTC property not permitted with 
>> DRM_CLIENT_CAP_POST_BLEND_COLOR_PIPELINE client cap\n");
>> +??????????? return -EINVAL;
>> +??????? }
>> ????????? ret = drm_property_replace_blob_from_id(dev,
>> ????????????????????? &state->ctm,
>> ????????????????????? val,
>> @@ -468,6 +478,11 @@ static int drm_atomic_crtc_set_property(struct 
>> drm_crtc *crtc,
>> ????????? state->color_mgmt_changed |= replaced;
>> ????????? return ret;
>> ????? } else if (property == config->gamma_lut_property) {
>> +??????? if (file_priv->post_blend_color_pipeline) {
>> +??????????? drm_dbg_atomic(dev,
>> +??????????????? "Setting GAMMA_LUT CRTC property not permitted with 
>> DRM_CLIENT_CAP_POST_BLEND_COLOR_PIPELINE client cap\n");
>> +??????????? return -EINVAL;
>> +??????? }
>> ????????? ret = drm_property_replace_blob_from_id(dev,
>> ????????????????????? &state->gamma_lut,
>> ????????????????????? val,
>> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/ 
>> drm_connector.c
>> index 
>> 4d6dc9ebfdb5bc730b1aff7a184448af7b93f078..f58cfd2131139ff3e613adc4dbb9ddbedf724dc7 100644
>> --- a/drivers/gpu/drm/drm_connector.c
>> +++ b/drivers/gpu/drm/drm_connector.c
>> @@ -3440,6 +3440,7 @@ int drm_mode_getconnector(struct drm_device 
>> *dev, void *data,
>> ?????? */
>> ????? ret = drm_mode_object_get_properties(&connector->base, 
>> file_priv->atomic,
>> ????????????? file_priv->plane_color_pipeline,
>> +??????????? file_priv->post_blend_color_pipeline,
>> ????????????? (uint32_t __user *)(unsigned long)(out_resp->props_ptr),
>> ????????????? (uint64_t __user *)(unsigned long)(out_resp- 
>> >prop_values_ptr),
>> ????????????? &out_resp->count_props);
>> diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/ 
>> drm_crtc_internal.h
>> index 
>> e3dbdcbfa385b940ec0b5476adde6146fe4afde1..c53f154e5392a10c326c844b7321666275f9ac02 100644
>> --- a/drivers/gpu/drm/drm_crtc_internal.h
>> +++ b/drivers/gpu/drm/drm_crtc_internal.h
>> @@ -169,6 +169,7 @@ void drm_mode_object_unregister(struct drm_device 
>> *dev,
>> ????????????????? struct drm_mode_object *object);
>> ? int drm_mode_object_get_properties(struct drm_mode_object *obj, bool 
>> atomic,
>> ???????????????????? bool plane_color_pipeline,
>> +?????????????????? bool post_blend_color_pipeline,
>> ???????????????????? uint32_t __user *prop_ptr,
>> ???????????????????? uint64_t __user *prop_values,
>> ???????????????????? uint32_t *arg_count_props);
>> diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
>> index 
>> 01592d10e3465ddceddef94bc417f98d3ec12087..ea9600f5392f520a2b42ba7ef363d2f08ce19812 100644
>> --- a/drivers/gpu/drm/drm_ioctl.c
>> +++ b/drivers/gpu/drm/drm_ioctl.c
>> @@ -383,6 +383,15 @@ drm_setclientcap(struct drm_device *dev, void 
>> *data, struct drm_file *file_priv)
>> ????????????? return -EINVAL;
>> ????????? file_priv->plane_color_pipeline = req->value;
>> ????????? break;
>> +??? case DRM_CLIENT_CAP_POST_BLEND_COLOR_PIPELINE:
>> +??????? if (!file_priv->atomic)
>> +??????????? return -EINVAL;
>> +??????? if (req->value > 1)
>> +??????????? return -EINVAL;
>> +??????? if (!drm_core_check_feature(dev, 
>> DRIVER_POST_BLEND_COLOR_PIPELINE))
>> +??????????? return -EINVAL;
>> +??????? file_priv->post_blend_color_pipeline = req->value;
>> +??????? break;
>> ????? default:
>> ????????? return -EINVAL;
>> ????? }
>> diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/ 
>> drm_mode_object.c
>> index 
>> b45d501b10c868c6d9b7a5a8760eadbd7b372a6a..5e6c3de9456b997985142a68b9cef57771a58bdc 100644
>> --- a/drivers/gpu/drm/drm_mode_object.c
>> +++ b/drivers/gpu/drm/drm_mode_object.c
>> @@ -388,6 +388,7 @@ EXPORT_SYMBOL(drm_object_property_get_default_value);
>> ? /* helper for getconnector and getproperties ioctls */
>> ? int drm_mode_object_get_properties(struct drm_mode_object *obj, bool 
>> atomic,
>> ???????????????????? bool plane_color_pipeline,
>> +?????????????????? bool post_blend_color_pipeline,
>> ???????????????????? uint32_t __user *prop_ptr,
>> ???????????????????? uint64_t __user *prop_values,
>> ???????????????????? uint32_t *arg_count_props)
>> @@ -416,6 +417,13 @@ int drm_mode_object_get_properties(struct 
>> drm_mode_object *obj, bool atomic,
>> ????????????????? continue;
>> ????????? }
>> +??????? if (!post_blend_color_pipeline && obj->type == 
>> DRM_MODE_OBJECT_CRTC) {
>> +??????????? struct drm_crtc *crtc = obj_to_crtc(obj);
>> +
>> +??????????? if (prop == crtc->color_pipeline_property)
>> +??????????????? continue;
>> +??????? }
>> +
>> ????????? if (*arg_count_props > count) {
>> ????????????? ret = __drm_object_property_get_value(obj, prop, &val);
>> ????????????? if (ret)
>> @@ -475,6 +483,7 @@ int drm_mode_obj_get_properties_ioctl(struct 
>> drm_device *dev, void *data,
>> ????? ret = drm_mode_object_get_properties(obj, file_priv->atomic,
>> ????????????? file_priv->plane_color_pipeline,
>> +??????????? file_priv->post_blend_color_pipeline,
>> ????????????? (uint32_t __user *)(unsigned long)(arg->props_ptr),
>> ????????????? (uint64_t __user *)(unsigned long)(arg->prop_values_ptr),
>> ????????????? &arg->count_props);
>> diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h
>> index 
>> 1a3018e4a537b3341acb50187d47371f6b781b9d..42b9a43baa18079af8ec2ea5b1484b23c497beb0 100644
>> --- a/include/drm/drm_file.h
>> +++ b/include/drm/drm_file.h
>> @@ -213,6 +213,13 @@ struct drm_file {
>> ?????? */
>> ????? bool plane_color_pipeline;
>> +??? /**
>> +???? * @post_blend_color_pipeline:
>> +???? *
>> +???? * True if client understands post-blend color pipelines
>> +???? */
>> +??? bool post_blend_color_pipeline;
>> +
>> ????? /**
>> ?????? * @was_master:
>> ?????? *
>> diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
>> index 
>> c6c53e57958e951204154ce41a69696a6876f0e8..f9ac10b3e4876f71005a87dedefa4aed320566f0 100644
>> --- a/include/uapi/drm/drm.h
>> +++ b/include/uapi/drm/drm.h
>> @@ -927,6 +927,25 @@ struct drm_get_cap {
>> ?? */
>> ? #define DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE??? 7
>> +/**
>> + * DRM_CLIENT_CAP_POST_BLEND_COLOR_PIPELINE
> 
> DRM_CLIENT_CAP_CRTC_COLOR_PIPELINE might be better to align
> terminology between pre- and post-blend pipelines. It would
> also make it clear that this is about the color pipeline on
> a drm_crtc (which pretty much by definition means post-
> blending).
Same answer here. Will be replacing s/post_blend/crtc in v3.

Thanks!

-- 
Ariel D'Alessandro
Software Engineer

Collabora Ltd.
Platinum Building, St John's Innovation Park, Cambridge CB4 0DS, UK 
Registered in England & Wales, no. 5513718



From tan.siewert at hetzner.com  Thu Dec 11 07:38:46 2025
From: tan.siewert at hetzner.com (Tan Siewert)
Date: Thu, 11 Dec 2025 16:38:46 +0100
Subject: [PATCH v4 2/2] ARM: dts: aspeed: add device tree for ASRock Rack
 ALTRAD8 BMC
In-Reply-To: <20251211133721.18269-3-rebecca@bsdio.com>
References: <20251211133721.18269-1-rebecca@bsdio.com>
 <20251211133721.18269-3-rebecca@bsdio.com>
Message-ID: <57676277-b56d-47f7-80f5-2cf4088412e1@hetzner.com>

On 11.12.25 14:37, Rebecca Cran wrote:
> The ALTRAD8 BMC is an Aspeed AST2500-based BMC for the ASRock Rack
> ALTRAD8UD-1L2T and ALTRAD8UD2-1L2Q boards.
> 
> Signed-off-by: Rebecca Cran <rebecca at bsdio.com>
> ---
>   arch/arm/boot/dts/aspeed/Makefile                      |   1 +
>   arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts | 625 ++++++++++++++++++++
>   2 files changed, 626 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/aspeed/Makefile b/arch/arm/boot/dts/aspeed/Makefile
> index 9adf9278dc94..f073f126ddac 100644
> --- a/arch/arm/boot/dts/aspeed/Makefile
> +++ b/arch/arm/boot/dts/aspeed/Makefile
> @@ -9,6 +9,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \
>   	aspeed-bmc-ampere-mtjefferson.dtb \
>   	aspeed-bmc-ampere-mtmitchell.dtb \
>   	aspeed-bmc-arm-stardragon4800-rep2.dtb \
> +	aspeed-bmc-asrock-altrad8.dtb \
>   	aspeed-bmc-asrock-e3c246d4i.dtb \
>   	aspeed-bmc-asrock-e3c256d4i.dtb \
>   	aspeed-bmc-asrock-romed8hm3.dtb \
> diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts
> new file mode 100644
> index 000000000000..b60046fd214b
> --- /dev/null
> +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts
> @@ -0,0 +1,625 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/dts-v1/;
> +
> +#include "aspeed-g5.dtsi"
> +#include <dt-bindings/gpio/aspeed-gpio.h>
> +#include <dt-bindings/leds/common.h>
> +#include <dt-bindings/i2c/i2c.h>
> +
> +/ {
> +	model = "ASRock ALTRAD8 BMC";
> +	compatible = "asrock,altrad8-bmc", "aspeed,ast2500";
> +
> +	aliases {
> +		serial4 = &uart5;
> +		i2c50 = &nvme1;
> +		i2c51 = &pcie4;
> +		i2c52 = &pcie5;
> +		i2c53 = &pcie6;
> +		i2c54 = &pcie7;
> +		i2c55 = &nvme3;
> +		i2c56 = &nvme2;
> +		i2c57 = &nvme0;
> +		i2c58 = &nvme4;
> +		i2c59 = &nvme5;
> +		i2c60 = &nvme6;
> +		i2c61 = &nvme7;
> +		i2c62 = &nvme8;
> +		i2c63 = &nvme9;
> +		i2c64 = &nvme10;
> +		i2c65 = &nvme11;
> +	};
> +
> +	chosen {
> +		stdout-path = "uart5:115200n8";
> +	};
> +
> +	iio-hwmon {
> +		compatible = "iio-hwmon";
> +		io-channels =	<&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>,
> +				<&adc 4> ,<&adc 5>, <&adc 6>, <&adc 7>,
> +				<&adc 8>, <&adc 9>, <&adc 10>, <&adc 11>,
> +				<&adc 12>, <&adc 13>, <&adc 14>, <&adc 15>;
> +	};
> +
> +	leds {
> +		compatible = "gpio-leds";
> +
> +		led-system-fault {
> +			gpios = <&gpio ASPEED_GPIO(G,3) GPIO_ACTIVE_LOW>;
> +			label = "platform:red:fault";
> +			color = <LED_COLOR_ID_RED>;
> +			function = LED_FUNCTION_FAULT;
> +		};
> +
> +		led-heartbeat {
> +			gpios = <&gpio ASPEED_GPIO(G,0) GPIO_ACTIVE_LOW>;
> +			label = "platform:green:heartbeat";
> +			color = <LED_COLOR_ID_GREEN>;
> +			function = LED_FUNCTION_INDICATOR;
> +			linux,default-trigger = "timer";
> +		};
> +
> +		led-fan1-fault {
> +			retain-state-shutdown;
> +			default-state = "off";
> +			gpios = <&io_expander0 0 GPIO_ACTIVE_LOW>;
> +			label = "fan1:red:fault";
> +			color = <LED_COLOR_ID_RED>;
> +			function = LED_FUNCTION_FAULT;
> +		};
> +
> +		led-fan2-fault {
> +			retain-state-shutdown;
> +			default-state = "off";
> +			gpios = <&io_expander0 1 GPIO_ACTIVE_LOW>;
> +			label = "fan2:red:fault";
> +			color = <LED_COLOR_ID_RED>;
> +			function = LED_FUNCTION_FAULT;
> +		};
> +
> +		led-fan3-fault {
> +			retain-state-shutdown;
> +			default-state = "off";
> +			gpios = <&io_expander0 2 GPIO_ACTIVE_LOW>;
> +			label = "fan3:red:fault";
> +			color = <LED_COLOR_ID_RED>;
> +			function = LED_FUNCTION_FAULT;
> +		};
> +
> +		led-fan4-fault {
> +			retain-state-shutdown;
> +			default-state = "off";
> +			gpios = <&io_expander0 3 GPIO_ACTIVE_LOW>;
> +			label = "fan4:red:fault";
> +			color = <LED_COLOR_ID_RED>;
> +			function = LED_FUNCTION_FAULT;
> +		};
> +
> +		led-fan5-fault {
> +			retain-state-shutdown;
> +			default-state = "off";
> +			gpios = <&io_expander0 4 GPIO_ACTIVE_LOW>;
> +			label = "fan5:red:fault";
> +			color = <LED_COLOR_ID_RED>;
> +			function = LED_FUNCTION_FAULT;
> +		};
> +	};
> +
> +	memory at 80000000 {
> +		reg = <0x80000000 0x20000000>;
> +	};
> +
> +	reserved-memory {
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		ranges;
> +
> +		gfx_memory: framebuffer {
> +			compatible = "shared-dma-pool";
> +			size = <0x01000000>;
> +			alignment = <0x01000000>;
> +			reusable;
> +		};
> +
> +		vga_memory: framebuffer at 9f000000 {
> +			no-map;
> +			reg = <0x9f000000 0x01000000>; /* 16M */
> +		};
> +
> +		video_engine_memory: jpegbuffer {
> +			compatible = "shared-dma-pool";
> +			size = <0x02000000>;	/* 32M */
> +			alignment = <0x01000000>;
> +			reusable;
> +		};
> +	};
> +};
> +
> +&adc {
> +	status = "okay";
> +};
> +
> +&fmc {
> +	status = "okay";
> +
> +	flash at 0 {
> +		label = "bmc";
> +		m25p,fast-read;
> +		spi-max-frequency = <50000000>;
> +		status = "okay";
> +#include "openbmc-flash-layout-64.dtsi"
> +	};
> +};
> +
> +&gfx {
> +	memory-region = <&gfx_memory>;
> +	status = "okay";
> +};
> +
> +&gpio {
> +	gpio-line-names =
> +	/*A0-A7*/	"","","","bmc-ready","","","","",
> +	/*B0-B7*/	"i2c-backup-sel","","","","","","","host0-shd-ack-n",
> +	/*C0-C7*/	"","","","","","","","",
> +	/*D0-D7*/	"power-button-n","control-power-n","button-reset-n",

Probably got lost from my review in v3.

`power-button-n` should be `button-power-n` (consistent with the other 
buttons)

> +			"host0-sysreset-n","","","power-chassis-good","",
> +	/*E0-E7*/	"","s0-vrd1-vddq0123-fault-n",
> +			"s0-vrd1-vddq4567-fault-n","s0-vrd0-vddc-fault-n",
> +			"s0-vrd3-p0v75-fault-n","","","",
> +	/*F0-F7*/	"","","ps-atx-on-n","","","","","",
> +	/*G0-G7*/	"led-bmc-heartbeat-n","button-identify-n","",\

Please remove the `\` at the end of the line.

> +			"led-system-fault-n","uboot-ready","bmc-salt2-n","","",
> +	/*H0-H7*/	"ps-pwr-ok","uart1-mode1","uart2-mode1","uart3-mode1",
> +			"uart4-mode1","","led-bmc-heartbeat","",

led-bmc-heartbeat-n (active-low as defined in `/leds/led-heartbeat`)

-- Tan

> +	/*I0-I7*/	"","","","","","","","",
> +	/*J0-J7*/	"s0-hightemp-n","","","","","","","",
> +	/*K0-K7*/	"","","","","","","","",
> +	/*L0-L7*/	"","","","","","","","",
> +	/*M0-M7*/	"cpld-disable-bmc-n","","","","","s0-spi-auth-fail-n","","",
> +	/*N0-N7*/	"","","","","","","","",
> +	/*O0-O7*/	"","","","","","","","",
> +	/*P0-P7*/	"","","","","","","","",
> +	/*Q0-Q7*/	"","","","","","","led-identify-n",
> +			"chassis-intrusion-n",
> +	/*R0-R7*/	"","","ext-hightemp-n","spi0-program-sel","",
> +			"output-hwm-bat-en","","",
> +	/*S0-S7*/	"s0-vr-hot-n","","input-salt2-n","bmc-sysreset-n","","","","",
> +	/*T0-T7*/	"","","","","","","","",
> +	/*U0-U7*/	"","","","","","","","",
> +	/*V0-V7*/	"","","","","","","","",
> +	/*W0-W7*/	"","","","","","","","",
> +	/*X0-X7*/	"","","","","","","","",
> +	/*Y0-Y7*/	"","","","","","","","",
> +	/*Z0-Z7*/	"","","","s0-rtc-lock","","","","",
> +	/*AA0-AA7*/	"s0-rtc-int-n","","","","","pmbus-sel-n","","",
> +	/*AB0-AB7*/	"host0-reboot-ack-n","s0-sys-auth-failure-n",
> +			"","","","","","",
> +	/*AC0-AC7*/	"s0-fault-alert","host0-ready","s0-overtemp-n",
> +			"","bmc-ok","host0-special-boot","presence-cpu0",
> +			"host0-shd-req-n";
> +
> +	status = "okay";
> +};
> +
> +&i2c0 {
> +	status = "okay";
> +
> +	ipmb at 10 {
> +		compatible = "ipmb-dev";
> +		reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>;
> +		i2c-protocol;
> +	};
> +
> +};
> +
> +&i2c1 {
> +	status = "okay";
> +
> +	i2c-mux1 at 73 {
> +		compatible = "nxp,pca9548";
> +		reg = <0x73>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		i2c-mux-idle-disconnect;
> +
> +		nvme1: i2c at 0 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <0>;
> +		};
> +
> +		pcie4: i2c at 1 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <1>;
> +		};
> +
> +		pcie5: i2c at 2 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <2>;
> +		};
> +
> +		pcie6: i2c at 3 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <3>;
> +		};
> +
> +		pcie7: i2c at 4 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <4>;
> +		};
> +
> +		nvme3: i2c at 5 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <5>;
> +		};
> +
> +		nvme2: i2c at 6 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <6>;
> +		};
> +
> +		nvme0: i2c at 7 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <7>;
> +		};
> +	};
> +
> +	i2c-mux2 at 75 {
> +		compatible = "nxp,pca9548";
> +		reg = <0x75>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		i2c-mux-idle-disconnect;
> +
> +		nvme4: i2c at 0 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <0>;
> +		};
> +
> +		nvme5: i2c at 1 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <1>;
> +		};
> +
> +		nvme6: i2c at 2 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <2>;
> +		};
> +
> +		nvme7: i2c at 3 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <3>;
> +		};
> +
> +		nvme8: i2c at 4 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <4>;
> +		};
> +
> +		nvme9: i2c at 5 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <5>;
> +		};
> +
> +		nvme10: i2c at 6 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <6>;
> +		};
> +
> +		nvme11: i2c at 7 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <7>;
> +		};
> +	};
> +};
> +
> +&i2c2 {
> +	status = "okay";
> +
> +	smpro at 4f {
> +		compatible = "ampere,smpro";
> +		reg = <0x4f>;
> +	};
> +};
> +
> +&i2c3 {
> +	status = "okay";
> +
> +	// PSU FRU
> +	eeprom at 38 {
> +		compatible = "atmel,24c02";
> +		reg = <0x38>;
> +	};
> +};
> +
> +&i2c4 {
> +	status = "okay";
> +
> +	temperature-sensor at 29 {
> +		compatible = "nuvoton,nct7802";
> +		reg = <0x29>;
> +
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		channel at 0 { /* LTD */
> +			reg = <0>;
> +			status = "okay";
> +		};
> +
> +		channel at 1 { /* RTD1 */
> +			reg = <1>;
> +			sensor-type = "temperature";
> +			temperature-mode = "thermistor";
> +		};
> +
> +		channel at 2 { /* RTD2 */
> +			reg = <2>;
> +			sensor-type = "temperature";
> +			temperature-mode = "thermal-diode";
> +		};
> +	};
> +
> +	temperature-sensor at 4c {
> +		compatible = "nuvoton,w83773g";
> +		reg = <0x4c>;
> +	};
> +};
> +
> +&i2c5 {
> +	status = "okay";
> +};
> +
> +&i2c6 {
> +	status = "okay";
> +
> +	rtc at 6f {
> +		compatible = "isil,isl1208";
> +		reg = <0x6f>;
> +	};
> +};
> +
> +&i2c7 {
> +	status = "okay";
> +
> +	// BMC FRU
> +	eeprom at 57 {
> +		compatible = "atmel,24c128";
> +		reg = <0x57>;
> +
> +		nvmem-layout {
> +			compatible = "fixed-layout";
> +			#address-cells = <1>;
> +			#size-cells = <1>;
> +
> +			eth1_macaddress: macaddress at 3f80 {
> +				reg = <0x3f80 6>;
> +			};
> +
> +			// The offset for eth0 really is at 0x3f88.
> +			// eth0 and eth1 are swapped from what might be
> +			// expected.
> +			eth0_macaddress: macaddress at 3f88 {
> +				reg = <0x3f88 6>;
> +			};
> +		};
> +	};
> +};
> +
> +&i2c8 {
> +	status = "okay";
> +
> +	io_expander0: gpio at 1c {
> +		compatible = "nxp,pca9557";
> +		reg = <0x1c>;
> +		gpio-controller;
> +		#gpio-cells = <2>;
> +	};
> +};
> +
> +&i2c9 {
> +	status = "okay";
> +};
> +
> +&i2c10 {
> +	status = "okay";
> +};
> +
> +&i2c11 {
> +	status = "okay";
> +};
> +
> +// Bus for accessing the SCP EEPROM
> +&i2c12 {
> +	status = "okay";
> +};
> +
> +&i2c13 {
> +	status = "okay";
> +
> +	ssif-bmc at 10 {
> +		compatible = "ssif-bmc";
> +		reg = <0x10>;
> +	};
> +};
> +
> +// Connected to host Intel X550 (ALTRAD8UD-1L2T) or
> +// Broadcom BCM57414 (ALTRAD8UD2-1L2Q) interface.
> +// Unconnected on ALTRAD8UD-1L
> +&mac0 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_rmii1_default>;
> +	clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
> +		 <&syscon ASPEED_CLK_MAC1RCLK>;
> +	clock-names = "MACCLK", "RCLK";
> +	use-ncsi;
> +	nvmem-cells = <&eth0_macaddress>;
> +	nvmem-cell-names = "mac-address";
> +
> +	status = "okay";
> +};
> +
> +// Connected to Realtek RTL8211E
> +&mac1 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>;
> +
> +	nvmem-cells = <&eth1_macaddress>;
> +	nvmem-cell-names = "mac-address";
> +
> +	status = "okay";
> +};
> +
> +&pinctrl {
> +	aspeed,external-nodes = <&gfx &lhc>;
> +};
> +
> +&pwm_tacho {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_pwm0_default
> +			&pinctrl_pwm1_default
> +			&pinctrl_pwm2_default
> +			&pinctrl_pwm3_default
> +			&pinctrl_pwm4_default
> +			&pinctrl_pwm5_default
> +			&pinctrl_pwm6_default
> +			&pinctrl_pwm7_default>;
> +
> +	status = "okay";
> +
> +	fan at 0 {
> +		reg = <0x00>;
> +		aspeed,fan-tach-ch = /bits/ 8 <0x00 0x08>;
> +	};
> +
> +	fan at 1 {
> +		reg = <0x01>;
> +		aspeed,fan-tach-ch = /bits/ 8 <0x01 0x09>;
> +	};
> +
> +	fan at 2 {
> +		reg = <0x02>;
> +		aspeed,fan-tach-ch = /bits/ 8 <0x02 0x0a>;
> +	};
> +
> +	fan at 3 {
> +		reg = <0x03>;
> +		aspeed,fan-tach-ch = /bits/ 8 <0x03 0x0b>;
> +	};
> +
> +	fan at 4 {
> +		reg = <0x04>;
> +		aspeed,fan-tach-ch = /bits/ 8 <0x04 0x0c>;
> +	};
> +
> +	fan at 5 {
> +		reg = <0x05>;
> +		aspeed,fan-tach-ch = /bits/ 8 <0x05 0x0d>;
> +	};
> +
> +	fan at 6 {
> +		reg = <0x06>;
> +		aspeed,fan-tach-ch = /bits/ 8 <0x06 0x0e>;
> +	};
> +
> +	fan at 7 {
> +		reg = <0x07>;
> +		aspeed,fan-tach-ch = /bits/ 8 <0x07 0x0f>;
> +	};
> +};
> +
> +&spi1 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_spi1_default>;
> +
> +	status = "okay";
> +
> +	// Host BIOS/UEFI EEPROM
> +	flash at 0 {
> +		m25p,fast-read;
> +		label = "pnor";
> +		spi-max-frequency = <100000000>;
> +		status = "okay";
> +
> +		partitions {
> +			compatible = "fixed-partitions";
> +			#address-cells = <1>;
> +			#size-cells = <1>;
> +
> +			tfa at 400000 {
> +				reg = <0x400000 0x200000>;
> +				label = "pnor-tfa";
> +			};
> +
> +			uefi at 600000 {
> +				reg = <0x600000 0x1A00000>;
> +				label = "pnor-uefi";
> +			};
> +		};
> +	};
> +};
> +
> +&uart1 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_txd1_default
> +			 &pinctrl_rxd1_default
> +			 &pinctrl_ncts1_default
> +			 &pinctrl_nrts1_default>;
> +
> +	status = "okay";
> +};
> +
> +&uart2 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_txd2_default
> +			&pinctrl_rxd2_default>;
> +
> +	status = "okay";
> +};
> +
> +&uart3 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_txd3_default
> +			&pinctrl_rxd3_default>;
> +
> +	status = "okay";
> +};
> +
> +&uart4 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_txd4_default
> +			&pinctrl_rxd4_default>;
> +
> +	status = "okay";
> +};
> +
> +// The BMC's uart
> +&uart5 {
> +	status = "okay";
> +};
> +
> +&vhub {
> +	status = "okay";
> +};
> +
> +&video {
> +	memory-region = <&video_engine_memory>;
> +
> +	status = "okay";
> +};
-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature.asc
Type: application/pgp-signature
Size: 840 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251211/8ad28a5c/attachment-0001.sig>

From robh at kernel.org  Thu Dec 11 07:57:47 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Thu, 11 Dec 2025 09:57:47 -0600
Subject: [PATCH RFC 06/16] dt-bindings: mmc: Switch ref to
 sdhci-common.yaml
In-Reply-To: <20251211-dev-dt-warnings-all-v1-6-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
 <20251211-dev-dt-warnings-all-v1-6-21b18b9ada77@codeconstruct.com.au>
Message-ID: <176546866607.1487115.6798113196659439308.robh@kernel.org>


On Thu, 11 Dec 2025 17:45:48 +0900, Andrew Jeffery wrote:
> Enable use of common SDHCI-related properties such as sdhci-caps-mask as
> found in the AST2600 EVB DTS.
> 
> Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
> ---
>  Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/hwmon/aspeed,ast2400-pwm-tacho.example.dtb: fan-controller at 1e786000 (aspeed,ast2500-pwm-tacho): #cooling-cells: 2 was expected
	from schema $id: http://devicetree.org/schemas/thermal/thermal-cooling-devices.yaml

doc reference errors (make refcheckdocs):

See https://patchwork.kernel.org/project/devicetree/patch/20251211-dev-dt-warnings-all-v1-6-21b18b9ada77 at codeconstruct.com.au

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.



From robh at kernel.org  Thu Dec 11 07:57:50 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Thu, 11 Dec 2025 09:57:50 -0600
Subject: [PATCH RFC 16/16] dt-bindings: mfd: Document smp-memram node
 for AST2600 SCU
In-Reply-To: <20251211-dev-dt-warnings-all-v1-16-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
 <20251211-dev-dt-warnings-all-v1-16-21b18b9ada77@codeconstruct.com.au>
Message-ID: <176546866713.1487167.4918701456595372928.robh@kernel.org>


On Thu, 11 Dec 2025 17:45:58 +0900, Andrew Jeffery wrote:
> The platform initialisation code for the AST2600 implements the custom
> SMP bringup protocol, and searches for the relevant compatible. As a
> consequence, define the requisite node and the compatible string, which
> in-turn tidies up the dtb check results.
> 
> Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
> ---
>  .../devicetree/bindings/mfd/aspeed,ast2x00-scu.yaml    | 18 ++++++++++++++++++
>  1 file changed, 18 insertions(+)
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:
./Documentation/devicetree/bindings/mfd/aspeed,ast2x00-scu.yaml:140:16: [error] string value is redundantly quoted with any quotes (quoted-strings)

dtschema/dtc warnings/errors:

doc reference errors (make refcheckdocs):

See https://patchwork.kernel.org/project/devicetree/patch/20251211-dev-dt-warnings-all-v1-16-21b18b9ada77 at codeconstruct.com.au

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.



From robh at kernel.org  Thu Dec 11 08:00:13 2025
From: robh at kernel.org (Rob Herring)
Date: Thu, 11 Dec 2025 10:00:13 -0600
Subject: [PATCH RESEND v2 03/11] dt-bindings: arm: stm32: Modify
 STM32MP15x Phytec board items types
In-Reply-To: <20251210101611.27008-4-c.parant@phytec.fr>
References: <20251210101611.27008-1-c.parant@phytec.fr>
 <20251210101611.27008-4-c.parant@phytec.fr>
Message-ID: <20251211160013.GA1485420-robh@kernel.org>

On Wed, Dec 10, 2025 at 11:16:03AM +0100, Christophe Parant wrote:
> As Phytec manages different SoM configurations with different STM32MP15
> SoC versions, modify the phyBOARD and SoM compatible items to "enum"
> instead of "const".

Change to enum when you add a 2nd string. I don't follow why you would 
do that either. You have more than 1 SoM for stm32mp157?

> The description concerns PHYTEC SoM equipped with STM32MP157
> ("st,stm32mp157" is "const").
> Also add comments in front of the enum items to be able to identify the
> compatible string with the phyBOARD/phyCORE names.
> 
> Signed-off-by: Christophe Parant <c.parant at phytec.fr>
> ---
>  Documentation/devicetree/bindings/arm/stm32/stm32.yaml | 8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/arm/stm32/stm32.yaml b/Documentation/devicetree/bindings/arm/stm32/stm32.yaml
> index 408532504a24..fbd3d364c1f7 100644
> --- a/Documentation/devicetree/bindings/arm/stm32/stm32.yaml
> +++ b/Documentation/devicetree/bindings/arm/stm32/stm32.yaml
> @@ -182,10 +182,12 @@ properties:
>            - const: seeed,stm32mp157c-odyssey-som
>            - const: st,stm32mp157
>  
> -      - description: Phytec STM32MP1 SoM based Boards
> +      - description: Phytec STM32MP157 SoM based Boards
>          items:
> -          - const: phytec,phycore-stm32mp1-3
> -          - const: phytec,phycore-stm32mp157c-som
> +          - enum:
> +              - phytec,phycore-stm32mp1-3 # phyBOARD-Sargas with phyCORE-STM32MP157C SoM
> +          - enum:
> +              - phytec,phycore-stm32mp157c-som # phyCORE-STM32MP157C SoM
>            - const: st,stm32mp157
>  
>        - description: Ultratronik STM32MP1 SBC based Boards
> -- 
> 2.34.1
> 


From maz at kernel.org  Thu Dec 11 08:21:20 2025
From: maz at kernel.org (Marc Zyngier)
Date: Thu, 11 Dec 2025 16:21:20 +0000
Subject: [PATCH v2 6/6] KVM: arm64: Honor UX/PX attributes for EL2 S1 mappings
In-Reply-To: <20251211151810.GA867614@e124191.cambridge.arm.com>
References: <20251210173024.561160-1-maz@kernel.org>
	<20251210173024.561160-7-maz@kernel.org>
	<20251211151810.GA867614@e124191.cambridge.arm.com>
Message-ID: <86tsxxng5b.wl-maz@kernel.org>

On Thu, 11 Dec 2025 15:18:51 +0000,
Joey Gouly <joey.gouly at arm.com> wrote:
> 
> Question,
> 
> On Wed, Dec 10, 2025 at 05:30:24PM +0000, Marc Zyngier wrote:
> > Now that we potentially have two bits to deal with when setting
> > execution permissions, make sure we correctly handle them when both
> > when building the page tables and when reading back from them.
> > 
> > Reported-by: Alexandru Elisei <alexandru.elisei at arm.com>
> > Signed-off-by: Marc Zyngier <maz at kernel.org>
> > ---
> >  arch/arm64/include/asm/kvm_pgtable.h | 12 +++---------
> >  arch/arm64/kvm/hyp/pgtable.c         | 24 +++++++++++++++++++++---
> >  2 files changed, 24 insertions(+), 12 deletions(-)
> > 
> > diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h
> > index be68b89692065..095e6b73740a6 100644
> > --- a/arch/arm64/include/asm/kvm_pgtable.h
> > +++ b/arch/arm64/include/asm/kvm_pgtable.h
> > @@ -87,15 +87,9 @@ typedef u64 kvm_pte_t;
> >  
> >  #define KVM_PTE_LEAF_ATTR_HI_SW		GENMASK(58, 55)
> >  
> > -#define __KVM_PTE_LEAF_ATTR_HI_S1_XN	BIT(54)
> > -#define __KVM_PTE_LEAF_ATTR_HI_S1_UXN	BIT(54)
> > -#define __KVM_PTE_LEAF_ATTR_HI_S1_PXN	BIT(53)
> > -
> > -#define KVM_PTE_LEAF_ATTR_HI_S1_XN					\
> > -	({ cpus_have_final_cap(ARM64_KVM_HVHE) ?			\
> > -			(__KVM_PTE_LEAF_ATTR_HI_S1_UXN |		\
> > -			 __KVM_PTE_LEAF_ATTR_HI_S1_PXN) :		\
> > -			__KVM_PTE_LEAF_ATTR_HI_S1_XN; })
> > +#define KVM_PTE_LEAF_ATTR_HI_S1_XN	BIT(54)
> > +#define KVM_PTE_LEAF_ATTR_HI_S1_UXN	BIT(54)
> > +#define KVM_PTE_LEAF_ATTR_HI_S1_PXN	BIT(53)
> >  
> >  #define KVM_PTE_LEAF_ATTR_HI_S2_XN	GENMASK(54, 53)
> >  
> > diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
> > index e0bd6a0172729..97c0835d25590 100644
> > --- a/arch/arm64/kvm/hyp/pgtable.c
> > +++ b/arch/arm64/kvm/hyp/pgtable.c
> > @@ -342,6 +342,9 @@ static int hyp_set_prot_attr(enum kvm_pgtable_prot prot, kvm_pte_t *ptep)
> >  	if (!(prot & KVM_PGTABLE_PROT_R))
> >  		return -EINVAL;
> >  
> > +	if (!cpus_have_final_cap(ARM64_KVM_HVHE))
> > +		prot &= ~KVM_PGTABLE_PROT_UX;
> 
> Trying to understand this part. We don't consider KVM_PGTABLE_PROT_UX below
> when !HVHE, and we don't set it in kvm_pgtable_hyp_pte_prot() when !HVHE
> either, so can it ever actually be set?

Because KVM_PGTABLE_PROT_X, which is directly passed by the high-level
code, is defined as such:

	KVM_PGTABLE_PROT_X			= KVM_PGTABLE_PROT_PX	|
						  KVM_PGTABLE_PROT_UX,

We *could* make that value dependent on HVHE, but since that's in an
enum, it is pretty ugly to do (not impossible though).

But it is in the following code that this becomes useful...

>
> Otherwise LGTM!
> 
> Thanks,
> Joey
> 
> > +
> >  	if (prot & KVM_PGTABLE_PROT_X) {
> >  		if (prot & KVM_PGTABLE_PROT_W)
> >  			return -EINVAL;

... here. If you were passed UX (and only that), and that you're
!HVHE, you won't have execution at all, and can allow writes.

Does that make sense?

	M.

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


From leo.yan at arm.com  Thu Dec 11 08:34:25 2025
From: leo.yan at arm.com (Leo Yan)
Date: Thu, 11 Dec 2025 16:34:25 +0000
Subject: [RFC PATCH v6 00/35] KVM: arm64: Add Statistical Profiling
 Extension (SPE) support
In-Reply-To: <20251114160717.163230-1-alexandru.elisei@arm.com>
References: <20251114160717.163230-1-alexandru.elisei@arm.com>
Message-ID: <20251211163425.GA4113166@e132581.arm.com>

Hi Alexandru,

Just couples general questions for myself to easier understand the series
(sorry if I asked duplicated questions).

> I wanted the focus to be on pinning memory at stage 2 (that's patches #29, 'KVM:
> arm64: Pin the SPE buffer in the host and map it at stage 2', to #3, 'KVM:
> arm64: Add hugetlb support for SPE') and I would very much like to start a
> discussion around that.

I am confused for "pinning memory at stage 2" and then I read "Pin the
SPE buffer in the host".  I read Chapter 2 Specification, ARM DEN 0154,
my conclusion is:

1) You set PMBLIMITR_EL1.nVM == 0 (virtual address mode) so that the
   driver uses the same mode whether it is running in a host or in a
   guest.

2) The KVM hypervisor needs to parse the VA -> IPA -> PA with:

   Guest stage-1 table (managed in guest OS);
   Guest stage-2 table (managed in KVM hypervisor);

3) In the end, the KVM hypervisor pins physical pages on the host
   stage-1 page table for:

   The physical pages are pinned for Guest stage-1 table;
   The physical pages are pinned for Guest stage-2 table;
   The physical pages are pinned for used for TRBE buffer in guest.

Due the host might migrate or swap pages, so all the pin operations
happen on the host's page table.  The pin operations never to be set up
in guest's stage-2 table, right?

> The problem
> ===========
> 
> When the Statistical Profiling Unit (SPU from now on) encounter a fault when
> it attempts to write a record to memory, two things happen: profiling is
> stopped, and the fault is reported to the CPU via an interrupt, not an
> exception. This creates a blackout window during which the CPU executes
> instructions which aren't profiled. The SPE driver avoid this by keeping the
> buffer mapped while ProfilingBufferEnabled() = true. But when running as a
> guest under KVM, the SPU will trigger stage 2 faults, with the associated
> blackout windows.

My understanding is that there are two prominent challenges for SPE
virtualization:

1) Allocation: we need to allocate trace buffer with mapping both
   guest's stage-1 and stage-2 before enabling SPU.  (For me, the free
   buffer is never an issue as we always disable the SPU before
   releasing the resource).

2) Pin: the physical pages used by trace buffer and the relevant stage-1
   and stage-2 tables must be pinned during the session.

I will read (and learn) the patches in next days.

Thanks,
Leo


From kory.maincent at bootlin.com  Thu Dec 11 08:38:44 2025
From: kory.maincent at bootlin.com (Kory Maincent (TI.com))
Date: Thu, 11 Dec 2025 17:38:44 +0100
Subject: [PATCH v2 00/20] Clean and update tilcdc driver to support
 DRM_BRIDGE_ATTACH_NO_CONNECTOR
Message-ID: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>

The starting point for this work was adding support for the HDMI cape:
https://www.seeedstudio.com/Seeed-Studio-BeagleBone-Green-HDMI-Cape.html
This will be sent in a later series.

Initially, Miguel proposed modifying the ite-it66121 bridge to support
the legacy behavior without the DRM_BRIDGE_ATTACH_NO_CONNECTOR flag:
https://lore.kernel.org/lkml/20250909-it66121-fix-v1-1-bc79ca83df17 at bootlin.com/
This patch was NAK'd as we don't want to add more legacy code. Maxime
requested that the tilcdc driver be updated to use
DRM_BRIDGE_ATTACH_NO_CONNECTOR instead.

While working on this update, I discovered that the tilcdc driver
contained significant amounts of legacy code that needed cleaning.
Since this driver was developed alongside the tda998x driver for
several AM335x boards, the tda998x driver also required cleanup and
support for the DRM_BRIDGE_ATTACH_NO_CONNECTOR flag.

A new tilcdc_panel_legacy driver replaces the old tilcdc_panel driver.
It modifies the devicetree at boot time to properly bind the tilcdc driver
with the standard panel-simple driver.

This series is based on the tilcdc fix sent to mainline:
https://lore.kernel.org/lkml/20251125090546.137193-1-kory.maincent at bootlin.com/

This series has been tested on:
- BeagleBone Black (tilcdc + tda998x bridge)
- BeagleBone Black with LCD cape (tilcdc + ti,tilcdc,panel binding)
- BeagleBone Green Eco with HDMI cape (tilcdc + it66121 bridge)

The following mainline devicetrees still use ti,tilcdc,panel binding.
I believe this series maintains compatibility, but I cannot test without
hardware:
- da850-evm.dts
- am335x-guardian.dts
- am335x-pdu001.dts
- am335x-pepper.dts
- am335x-sbc-t335.dts
- am335x-sl50.dts

Patches 1-2: Convert tilcdc binding to YAML and set the ti,tilcdc,panel
	     sub-binding as legacy.
Patches 3-6: Replace tilcdc_panel driver to the new tilcdc_panel_legacy
	     driver which is tweaking the devicetree at boot time.
Patches 7-15: Clean up tilcdc driver.
Patches 16-18: Clean up tda998x driver.
Patch 19: Add DRM_BRIDGE_ATTACH_NO_CONNECTOR support for tda998x driver.
Patch 20: Add DRM_BRIDGE_ATTACH_NO_CONNECTOR support for tilcdc driver.

Changes in v2:
- Remove patch 2 that add fifo-threshold property. Use FIFO threshold
  value from SoC id instead.
- Remove the part that breaks DTB compatibility.
- Add tilcdc_panel_legacy to modify the devicetree at boot time to properly
  bind the tilcdc driver with the standard panel-simple driver.
- Link to v1: https://lore.kernel.org/r/20251126-feature_tilcdc-v1-0-49b9ef2e3aa0 at bootlin.com

Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
---
Kory Maincent (TI.com) (20):
      dt-bindings: display: tilcdc: Convert to DT schema
      dt-bindings: display: tilcdc: Mark panel binding as deprecated
      drm/tilcdc: Remove simulate_vesa_sync flag
      drm/tilcdc: Add support for DRM bus flags and simplify panel config
      drm/tilcdc: Convert legacy panel binding via DT overlay at boot time
      drm/tilcdc: Remove tilcdc panel driver
      drm/tilcdc: Remove component framework support
      drm/tilcdc: Remove tilcdc_panel_info structure
      drm/tilcdc: Remove redundant #endif/#ifdef in debugfs code
      drm/tilcdc: Remove unused encoder and connector tracking arrays
      drm/tilcdc: Rename external_encoder and external_connector to encoder and connector
      drm/tilcdc: Rename tilcdc_external to tilcdc_encoder
      drm/tilcdc: Remove the useless module list support
      drm/tilcdc: Modernize driver initialization and cleanup paths
      drm/tilcdc: Remove the use of drm_device private_data
      drm/bridge: tda998x: Remove component support
      drm/bridge: tda998x: Move tda998x_create/destroy into probe and remove
      drm/bridge: tda998x: Remove useless tda998x_connector_destroy wrapper
      drm/bridge: tda998x: Add support for DRM_BRIDGE_ATTACH_NO_CONNECTOR
      drm/tilcdc: Add support for DRM_BRIDGE_ATTACH_NO_CONNECTOR

 .../devicetree/bindings/display/tilcdc/panel.txt   |   1 +
 .../devicetree/bindings/display/tilcdc/tilcdc.txt  |  82 ----
 .../devicetree/bindings/display/tilcdc/tilcdc.yaml |  96 +++++
 drivers/gpu/drm/bridge/tda998x_drv.c               | 251 +++++------
 drivers/gpu/drm/tilcdc/Kconfig                     |  14 +
 drivers/gpu/drm/tilcdc/Makefile                    |   5 +-
 drivers/gpu/drm/tilcdc/tilcdc_crtc.c               | 117 ++---
 drivers/gpu/drm/tilcdc/tilcdc_drv.c                | 479 ++++++++-------------
 drivers/gpu/drm/tilcdc/tilcdc_drv.h                |  88 +---
 drivers/gpu/drm/tilcdc/tilcdc_encoder.c            |  93 ++++
 .../tilcdc/{tilcdc_external.h => tilcdc_encoder.h} |   5 +-
 drivers/gpu/drm/tilcdc/tilcdc_external.c           | 179 --------
 drivers/gpu/drm/tilcdc/tilcdc_panel.c              | 408 ------------------
 drivers/gpu/drm/tilcdc/tilcdc_panel.h              |  15 -
 drivers/gpu/drm/tilcdc/tilcdc_panel_legacy.c       | 159 +++++++
 drivers/gpu/drm/tilcdc/tilcdc_panel_legacy.dtso    |  44 ++
 drivers/gpu/drm/tilcdc/tilcdc_plane.c              |   2 +-
 drivers/gpu/drm/tilcdc/tilcdc_regs.h               |   8 +-
 18 files changed, 752 insertions(+), 1294 deletions(-)
---
base-commit: f1c12d4576a46c82d3fdace1343e040daa0561f2
change-id: 20251014-feature_tilcdc-79cd49e67bf9

Best regards,
-- 
K?ry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com



From kory.maincent at bootlin.com  Thu Dec 11 08:38:45 2025
From: kory.maincent at bootlin.com (Kory Maincent (TI.com))
Date: Thu, 11 Dec 2025 17:38:45 +0100
Subject: [PATCH v2 01/20] dt-bindings: display: tilcdc: Convert to DT
 schema
In-Reply-To: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
Message-ID: <20251211-feature_tilcdc-v2-1-f48bac3cd33e@bootlin.com>

Convert the device tree binding documentation for tilcdc
from plain text to DT binding schema.

Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
---
 .../devicetree/bindings/display/tilcdc/tilcdc.txt  | 82 ------------------
 .../devicetree/bindings/display/tilcdc/tilcdc.yaml | 96 ++++++++++++++++++++++
 2 files changed, 96 insertions(+), 82 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt b/Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt
deleted file mode 100644
index 3b3d0bbfcfff4..0000000000000
--- a/Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt
+++ /dev/null
@@ -1,82 +0,0 @@
-Device-Tree bindings for tilcdc DRM driver
-
-Required properties:
- - compatible: value should be one of the following:
-    - "ti,am33xx-tilcdc" for AM335x based boards
-    - "ti,da850-tilcdc" for DA850/AM18x/OMAP-L138 based boards
- - interrupts: the interrupt number
- - reg: base address and size of the LCDC device
-
-Recommended properties:
- - ti,hwmods: Name of the hwmod associated to the LCDC
-
-Optional properties:
- - max-bandwidth: The maximum pixels per second that the memory
-   interface / lcd controller combination can sustain
- - max-width: The maximum horizontal pixel width supported by
-   the lcd controller.
- - max-pixelclock: The maximum pixel clock that can be supported
-   by the lcd controller in KHz.
- - blue-and-red-wiring: Recognized values "straight" or "crossed".
-   This property deals with the LCDC revision 2 (found on AM335x)
-   color errata [1].
-    - "straight" indicates normal wiring that supports RGB565,
-      BGR888, and XBGR8888 color formats.
-    - "crossed" indicates wiring that has blue and red wires
-      crossed. This setup supports BGR565, RGB888 and XRGB8888
-      formats.
-    - If the property is not present or its value is not recognized
-      the legacy mode is assumed. This configuration supports RGB565,
-      RGB888 and XRGB8888 formats. However, depending on wiring, the red
-      and blue colors are swapped in either 16 or 24-bit color modes.
-
-Optional nodes:
-
- - port/ports: to describe a connection to an external encoder. The
-   binding follows Documentation/devicetree/bindings/graph.txt and
-   supports a single port with a single endpoint.
-
- - See also Documentation/devicetree/bindings/display/tilcdc/panel.txt and
-   Documentation/devicetree/bindings/display/bridge/ti,tfp410.yaml for connecting
-   tfp410 DVI encoder or lcd panel to lcdc
-
-[1] There is an errata about AM335x color wiring. For 16-bit color mode
-    the wires work as they should (LCD_DATA[0:4] is for Blue[3:7]),
-    but for 24 bit color modes the wiring of blue and red components is
-    crossed and LCD_DATA[0:4] is for Red[3:7] and LCD_DATA[11:15] is
-    for Blue[3-7]. For more details see section 3.1.1 in AM335x
-    Silicon Errata:
-    https://www.ti.com/general/docs/lit/getliterature.tsp?baseLiteratureNumber=sprz360
-
-Example:
-
-	fb: fb at 4830e000 {
-		compatible = "ti,am33xx-tilcdc", "ti,da850-tilcdc";
-		reg = <0x4830e000 0x1000>;
-		interrupt-parent = <&intc>;
-		interrupts = <36>;
-		ti,hwmods = "lcdc";
-
-		blue-and-red-wiring = "crossed";
-
-		port {
-			lcdc_0: endpoint {
-				remote-endpoint = <&hdmi_0>;
-			};
-		};
-	};
-
-	tda19988: tda19988 {
-		compatible = "nxp,tda998x";
-		reg = <0x70>;
-
-		pinctrl-names = "default", "off";
-		pinctrl-0 = <&nxp_hdmi_bonelt_pins>;
-		pinctrl-1 = <&nxp_hdmi_bonelt_off_pins>;
-
-		port {
-			hdmi_0: endpoint {
-				remote-endpoint = <&lcdc_0>;
-			};
-		};
-	};
diff --git a/Documentation/devicetree/bindings/display/tilcdc/tilcdc.yaml b/Documentation/devicetree/bindings/display/tilcdc/tilcdc.yaml
new file mode 100644
index 0000000000000..34ac1fd04d5c6
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/tilcdc/tilcdc.yaml
@@ -0,0 +1,96 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/tilcdc/tilcdc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: TI LCD Controller, found on AM335x, DA850, AM18x and OMAP-L138
+
+maintainers:
+  - Kory Maincent <kory.maincent at bootlin.com>
+
+properties:
+  compatible:
+    enum:
+      - ti,am33xx-tilcdc
+      - ti,da850-tilcdc
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  port:
+    $ref: /schemas/graph.yaml#/properties/port
+
+  ti,hwmods:
+    $ref: /schemas/types.yaml#/definitions/string
+    description:
+      Name of the hwmod associated to the LCDC
+
+  max-bandwidth:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      The maximum pixels per second that the memory interface / lcd
+      controller combination can sustain
+
+  max-width:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      The maximum horizontal pixel width supported by the lcd controller.
+
+  max-pixelclock:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      The maximum pixel clock that can be supported by the lcd controller
+      in KHz.
+
+  blue-and-red-wiring:
+    enum: [straight, crossed]
+    description:
+      This property deals with the LCDC revision 2 (found on AM335x)
+      color errata [1].
+       - "straight" indicates normal wiring that supports RGB565,
+         BGR888, and XBGR8888 color formats.
+       - "crossed" indicates wiring that has blue and red wires
+         crossed. This setup supports BGR565, RGB888 and XRGB8888
+         formats.
+       - If the property is not present or its value is not recognized
+         the legacy mode is assumed. This configuration supports RGB565,
+         RGB888 and XRGB8888 formats. However, depending on wiring, the red
+         and blue colors are swapped in either 16 or 24-bit color modes.
+
+       [1] There is an errata about AM335x color wiring. For 16-bit color
+       mode the wires work as they should (LCD_DATA[0:4] is for Blue[3:7]),
+       but for 24 bit color modes the wiring of blue and red components is
+       crossed and LCD_DATA[0:4] is for Red[3:7] and LCD_DATA[11:15] is
+       for Blue[3-7]. For more details see section 3.1.1 in AM335x
+       Silicon Errata
+       https://www.ti.com/general/docs/lit/getliterature.tsp?baseLiteratureNumber=sprz360
+
+required:
+  - compatible
+  - interrupts
+  - reg
+  - port
+
+additionalProperties: false
+
+examples:
+  - |
+    tilcdc: tilcdc at 4830e000 {
+        compatible = "ti,am33xx-tilcdc";
+        reg = <0x4830e000 0x1000>;
+        interrupt-parent = <&intc>;
+        interrupts = <36>;
+        ti,hwmods = "lcdc";
+
+        blue-and-red-wiring = "crossed";
+
+        port {
+            lcdc_0: endpoint {
+                remote-endpoint = <&hdmi_0>;
+            };
+        };
+    };

-- 
2.43.0



From kory.maincent at bootlin.com  Thu Dec 11 08:38:46 2025
From: kory.maincent at bootlin.com (Kory Maincent (TI.com))
Date: Thu, 11 Dec 2025 17:38:46 +0100
Subject: [PATCH v2 02/20] dt-bindings: display: tilcdc: Mark panel binding
 as deprecated
In-Reply-To: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
Message-ID: <20251211-feature_tilcdc-v2-2-f48bac3cd33e@bootlin.com>

Mark the ti,tilcdc,panel binding as deprecated in the documentation.
This legacy binding should no longer be used for new designs. Users
should migrate to the standard DRM panel bindings instead.

Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
---

Change in v2:
- New patch
---
 Documentation/devicetree/bindings/display/tilcdc/panel.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/display/tilcdc/panel.txt b/Documentation/devicetree/bindings/display/tilcdc/panel.txt
index 808216310ea27..b973174d704ed 100644
--- a/Documentation/devicetree/bindings/display/tilcdc/panel.txt
+++ b/Documentation/devicetree/bindings/display/tilcdc/panel.txt
@@ -1,4 +1,5 @@
 Device-Tree bindings for tilcdc DRM generic panel output driver
+This binding is deprecated and should not be used.
 
 Required properties:
  - compatible: value should be "ti,tilcdc,panel".

-- 
2.43.0



From kory.maincent at bootlin.com  Thu Dec 11 08:38:47 2025
From: kory.maincent at bootlin.com (Kory Maincent (TI.com))
Date: Thu, 11 Dec 2025 17:38:47 +0100
Subject: [PATCH v2 03/20] drm/tilcdc: Remove simulate_vesa_sync flag
In-Reply-To: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
Message-ID: <20251211-feature_tilcdc-v2-3-f48bac3cd33e@bootlin.com>

The tilcdc hardware does not generate VESA-compliant sync signals. It
aligns the vertical sync (VS) on the second edge of the horizontal sync
(HS) instead of the first edge. To compensate for this hardware
behavior, the driver applies a timing adjustment in mode_fixup().

Previously, this adjustment was conditional based on the simulate_vesa_sync
flag, which was only set when using external encoders. This appears
problematic because:

1. The timing adjustment seems needed for the hardware behavior regardless
   of whether an external encoder is used
2. The external encoder infrastructure is driver-specific and being
   removed due to design issues
3. Boards using tilcdc without bridges (e.g., am335x-evm, am335x-evmsk)
   may not be getting the necessary timing adjustments

Remove the simulate_vesa_sync flag and apply the VESA sync timing
adjustment unconditionally, ensuring consistent behavior across all
configurations. While it's unclear if the previous conditional behavior
was causing actual issues, the unconditional adjustment better reflects
the hardware's characteristics.

Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
---

Only few board currently use tilcdc not associated to a bridge like the
am335x_evm or the am335x-evmsk.
---
 drivers/gpu/drm/tilcdc/tilcdc_crtc.c     | 16 ----------------
 drivers/gpu/drm/tilcdc/tilcdc_drv.h      |  2 --
 drivers/gpu/drm/tilcdc/tilcdc_external.c |  1 -
 3 files changed, 19 deletions(-)

diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index 52c95131af5af..b06b1453db2dd 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -47,9 +47,6 @@ struct tilcdc_crtc {
 
 	struct drm_framebuffer *next_fb;
 
-	/* Only set if an external encoder is connected */
-	bool simulate_vesa_sync;
-
 	int sync_lost_count;
 	bool frame_intact;
 	struct work_struct recover_work;
@@ -642,11 +639,6 @@ static bool tilcdc_crtc_mode_fixup(struct drm_crtc *crtc,
 		const struct drm_display_mode *mode,
 		struct drm_display_mode *adjusted_mode)
 {
-	struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
-
-	if (!tilcdc_crtc->simulate_vesa_sync)
-		return true;
-
 	/*
 	 * tilcdc does not generate VESA-compliant sync but aligns
 	 * VS on the second edge of HS instead of first edge.
@@ -866,14 +858,6 @@ void tilcdc_crtc_set_panel_info(struct drm_crtc *crtc,
 	tilcdc_crtc->info = info;
 }
 
-void tilcdc_crtc_set_simulate_vesa_sync(struct drm_crtc *crtc,
-					bool simulate_vesa_sync)
-{
-	struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
-
-	tilcdc_crtc->simulate_vesa_sync = simulate_vesa_sync;
-}
-
 void tilcdc_crtc_update_clk(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
index 58b276f82a669..3aba3a1155ba0 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
@@ -160,8 +160,6 @@ irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc);
 void tilcdc_crtc_update_clk(struct drm_crtc *crtc);
 void tilcdc_crtc_set_panel_info(struct drm_crtc *crtc,
 		const struct tilcdc_panel_info *info);
-void tilcdc_crtc_set_simulate_vesa_sync(struct drm_crtc *crtc,
-					bool simulate_vesa_sync);
 void tilcdc_crtc_shutdown(struct drm_crtc *crtc);
 void tilcdc_crtc_destroy(struct drm_crtc *crtc);
 int tilcdc_crtc_update_fb(struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.c b/drivers/gpu/drm/tilcdc/tilcdc_external.c
index 3b86d002ef62e..da755a411d9ff 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_external.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_external.c
@@ -80,7 +80,6 @@ int tilcdc_add_component_encoder(struct drm_device *ddev)
 		return -ENODEV;
 
 	/* Only tda998x is supported at the moment. */
-	tilcdc_crtc_set_simulate_vesa_sync(priv->crtc, true);
 	tilcdc_crtc_set_panel_info(priv->crtc, &panel_info_tda998x);
 
 	return 0;

-- 
2.43.0



From kory.maincent at bootlin.com  Thu Dec 11 08:38:48 2025
From: kory.maincent at bootlin.com (Kory Maincent (TI.com))
Date: Thu, 11 Dec 2025 17:38:48 +0100
Subject: [PATCH v2 04/20] drm/tilcdc: Add support for DRM bus flags and
 simplify panel config
In-Reply-To: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
Message-ID: <20251211-feature_tilcdc-v2-4-f48bac3cd33e@bootlin.com>

Migrate CRTC mode configuration to use standard DRM bus flags in
preparation for removing the tilcdc_panel driver and its custom
tilcdc_panel_info structure.

Add support for DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE and
DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE flags to control pixel clock and sync
signal edge polarity, while maintaining backward compatibility with the
existing tilcdc panel info structure.

Simplify several hardware parameters by setting them to fixed defaults
based on common usage across existing device trees:
- DMA burst size: 16 (previously configurable via switch statement)
- AC bias frequency: 255 (previously panel-specific)
- FIFO DMA request delay: 128 (previously panel-specific)

These parameters show no variation in real-world usage, so hardcoding
them simplifies the driver without losing functionality.

Preserve FIFO threshold configurability by detecting the SoC type, as
this parameter varies between AM33xx (8) and DA850 (16) platforms.

Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
---

Change in v2:
- Use SoC type instead of devicetree parameter to set FIFO threshold
  value.
---
 drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 47 +++++++++++++-----------------------
 drivers/gpu/drm/tilcdc/tilcdc_drv.c  | 29 ++++++++++++++++------
 drivers/gpu/drm/tilcdc/tilcdc_drv.h  |  2 ++
 3 files changed, 41 insertions(+), 37 deletions(-)

diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index b06b1453db2dd..2309a9a0c925d 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -285,27 +285,15 @@ static void tilcdc_crtc_set_mode(struct drm_crtc *crtc)
 
 	/* Configure the Burst Size and fifo threshold of DMA: */
 	reg = tilcdc_read(dev, LCDC_DMA_CTRL_REG) & ~0x00000770;
-	switch (info->dma_burst_sz) {
-	case 1:
-		reg |= LCDC_DMA_BURST_SIZE(LCDC_DMA_BURST_1);
-		break;
-	case 2:
-		reg |= LCDC_DMA_BURST_SIZE(LCDC_DMA_BURST_2);
-		break;
-	case 4:
-		reg |= LCDC_DMA_BURST_SIZE(LCDC_DMA_BURST_4);
-		break;
-	case 8:
-		reg |= LCDC_DMA_BURST_SIZE(LCDC_DMA_BURST_8);
-		break;
-	case 16:
-		reg |= LCDC_DMA_BURST_SIZE(LCDC_DMA_BURST_16);
-		break;
-	default:
-		dev_err(dev->dev, "invalid burst size\n");
-		return;
+	/* Use 16 bit DMA burst size by default */
+	reg |= LCDC_DMA_BURST_SIZE(LCDC_DMA_BURST_16);
+	if (priv->fifo_th) {
+		int fifo_th_val = ilog2(priv->fifo_th) - 3;
+
+		reg |= (fifo_th_val << 8);
+	} else {
+		reg |= (info->fifo_th << 8);
 	}
-	reg |= (info->fifo_th << 8);
 	tilcdc_write(dev, LCDC_DMA_CTRL_REG, reg);
 
 	/* Configure timings: */
@@ -321,8 +309,8 @@ static void tilcdc_crtc_set_mode(struct drm_crtc *crtc)
 
 	/* Set AC Bias Period and Number of Transitions per Interrupt: */
 	reg = tilcdc_read(dev, LCDC_RASTER_TIMING_2_REG) & ~0x000fff00;
-	reg |= LCDC_AC_BIAS_FREQUENCY(info->ac_bias) |
-		LCDC_AC_BIAS_TRANSITIONS_PER_INT(info->ac_bias_intrpt);
+	/* Use 255 AC Bias Pin Frequency by default */
+	reg |= LCDC_AC_BIAS_FREQUENCY(255);
 
 	/*
 	 * subtract one from hfp, hbp, hsw because the hardware uses
@@ -392,20 +380,19 @@ static void tilcdc_crtc_set_mode(struct drm_crtc *crtc)
 			return;
 		}
 	}
-	reg |= info->fdd << 12;
+	/* Use 128 FIFO DMA Request Delay by default */
+	reg |= 128 << 12;
 	tilcdc_write(dev, LCDC_RASTER_CTRL_REG, reg);
 
-	if (info->invert_pxl_clk)
+	if (info->invert_pxl_clk ||
+	    mode->flags == DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
 		tilcdc_set(dev, LCDC_RASTER_TIMING_2_REG, LCDC_INVERT_PIXEL_CLOCK);
 	else
 		tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG, LCDC_INVERT_PIXEL_CLOCK);
 
-	if (info->sync_ctrl)
-		tilcdc_set(dev, LCDC_RASTER_TIMING_2_REG, LCDC_SYNC_CTRL);
-	else
-		tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG, LCDC_SYNC_CTRL);
-
-	if (info->sync_edge)
+	tilcdc_set(dev, LCDC_RASTER_TIMING_2_REG, LCDC_SYNC_CTRL);
+	if (info->sync_edge ||
+	    mode->flags == DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE)
 		tilcdc_set(dev, LCDC_RASTER_TIMING_2_REG, LCDC_SYNC_EDGE);
 	else
 		tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG, LCDC_SYNC_EDGE);
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index 3dcbec312bacb..60230fa9cec95 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -31,6 +31,11 @@
 #include "tilcdc_panel.h"
 #include "tilcdc_regs.h"
 
+enum {
+	AM33XX_TILCDC,
+	DA850_TILCDC,
+};
+
 static LIST_HEAD(module_list);
 
 static const u32 tilcdc_rev1_formats[] = { DRM_FORMAT_RGB565 };
@@ -192,11 +197,19 @@ static void tilcdc_fini(struct drm_device *dev)
 	drm_dev_put(dev);
 }
 
+static const struct of_device_id tilcdc_of_match[] = {
+		{ .compatible = "ti,am33xx-tilcdc", .data = (void *)AM33XX_TILCDC},
+		{ .compatible = "ti,da850-tilcdc", .data = (void *)DA850_TILCDC},
+		{ },
+};
+MODULE_DEVICE_TABLE(of, tilcdc_of_match);
+
 static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev)
 {
 	struct drm_device *ddev;
 	struct platform_device *pdev = to_platform_device(dev);
 	struct device_node *node = dev->of_node;
+	const struct of_device_id *of_id;
 	struct tilcdc_drm_private *priv;
 	u32 bpp = 0;
 	int ret;
@@ -209,6 +222,10 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev)
 	if (IS_ERR(ddev))
 		return PTR_ERR(ddev);
 
+	of_id = of_match_node(tilcdc_of_match, node);
+	if (!of_id)
+		return -ENODEV;
+
 	ddev->dev_private = priv;
 	platform_set_drvdata(pdev, ddev);
 	drm_mode_config_init(ddev);
@@ -309,6 +326,11 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev)
 
 	DBG("Maximum Pixel Clock Value %dKHz", priv->max_pixelclock);
 
+	if ((unsigned int)of_id->data == DA850_TILCDC)
+		priv->fifo_th = 16;
+	else
+		priv->fifo_th = 8;
+
 	ret = tilcdc_crtc_create(ddev);
 	if (ret < 0) {
 		dev_err(dev, "failed to create crtc\n");
@@ -597,13 +619,6 @@ static void tilcdc_pdev_shutdown(struct platform_device *pdev)
 	drm_atomic_helper_shutdown(platform_get_drvdata(pdev));
 }
 
-static const struct of_device_id tilcdc_of_match[] = {
-		{ .compatible = "ti,am33xx-tilcdc", },
-		{ .compatible = "ti,da850-tilcdc", },
-		{ },
-};
-MODULE_DEVICE_TABLE(of, tilcdc_of_match);
-
 static struct platform_driver tilcdc_platform_driver = {
 	.probe      = tilcdc_pdev_probe,
 	.remove     = tilcdc_pdev_remove,
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
index 3aba3a1155ba0..79078b4ae7393 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
@@ -61,6 +61,8 @@ struct tilcdc_drm_private {
 	 */
 	uint32_t max_width;
 
+	u32 fifo_th;
+
 	/* Supported pixel formats */
 	const uint32_t *pixelformats;
 	uint32_t num_pixelformats;

-- 
2.43.0



From kory.maincent at bootlin.com  Thu Dec 11 08:38:49 2025
From: kory.maincent at bootlin.com (Kory Maincent (TI.com))
Date: Thu, 11 Dec 2025 17:38:49 +0100
Subject: [PATCH v2 05/20] drm/tilcdc: Convert legacy panel binding via DT
 overlay at boot time
In-Reply-To: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
Message-ID: <20251211-feature_tilcdc-v2-5-f48bac3cd33e@bootlin.com>

To maintain backward compatibility while removing the deprecated
tilcdc_panel driver, add a tilcdc_panel_legacy subdriver that converts
the legacy "ti,tilcdc,panel" devicetree binding to the standard
panel-dpi binding at early boot.

The conversion uses an embedded device tree overlay that is applied and
modified during subsys_initcall. The process:

- Apply embedded overlay to create a panel-dpi node with placeholder
  timing properties and port/endpoint connections to the LCDC
- Copy all properties from the legacy panel node to the new panel-dpi
- Copy display-timings from the legacy panel
- Convert legacy panel-info properties (invert-pxl-clk, sync-edge) to
  standard display timing properties (pixelclk-active, syncclk-active)
- Disable the legacy panel by removing its compatible property to
  prevent the deprecated driver from binding

The result is a standard panel-dpi node with proper endpoints and
timing properties, allowing the DRM panel infrastructure to work with
legacy devicetrees without modification.

Other legacy panel-info properties are not migrated as they consistently
use default values across all mainline devicetrees and can be hardcoded
in the tilcdc driver.

This feature is optional via CONFIG_DRM_TILCDC_PANEL_LEGACY and should
only be enabled for systems with legacy devicetrees containing
"ti,tilcdc,panel" nodes.

Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
---

Using the approach of applying an overlay and then modifying the live
device tree is the solution I found that requires no modification of the
OF core. Dealing entirely with overlay changesets would bring additional
requirements such as phandle resolution management, which is internal to
the OF framework. I intend to avoid OF core change to support this legacy
binding.

Change in v2:
- New patch.
---
 drivers/gpu/drm/tilcdc/Kconfig                  |  14 +++
 drivers/gpu/drm/tilcdc/Makefile                 |   2 +
 drivers/gpu/drm/tilcdc/tilcdc_panel_legacy.c    | 159 ++++++++++++++++++++++++
 drivers/gpu/drm/tilcdc/tilcdc_panel_legacy.dtso |  44 +++++++
 4 files changed, 219 insertions(+)

diff --git a/drivers/gpu/drm/tilcdc/Kconfig b/drivers/gpu/drm/tilcdc/Kconfig
index 24f9a245ba593..4dcae0a06b819 100644
--- a/drivers/gpu/drm/tilcdc/Kconfig
+++ b/drivers/gpu/drm/tilcdc/Kconfig
@@ -14,3 +14,17 @@ config DRM_TILCDC
 	  controller, for example AM33xx in beagle-bone, DA8xx, or
 	  OMAP-L1xx.  This driver replaces the FB_DA8XX fbdev driver.
 
+config DRM_TILCDC_PANEL_LEGACY
+	bool "Support device tree blobs using TI LCDC Panel binding"
+	default n
+	depends on DRM_TILCDC
+        depends on OF
+        depends on BACKLIGHT_CLASS_DEVICE
+        depends on PM
+	select OF_OVERLAY
+	select DRM_PANEL_SIMPLE
+	help
+	  Choose this option if you need a kernel that is compatible
+	  with device tree blobs using the obsolete "ti,tilcdc,panel"
+	  binding. If you find "ti,tilcdc,panel"-string from your DTB,
+	  you probably need this. Otherwise you do not.
diff --git a/drivers/gpu/drm/tilcdc/Makefile b/drivers/gpu/drm/tilcdc/Makefile
index f5190477de721..6d6a08b5adf40 100644
--- a/drivers/gpu/drm/tilcdc/Makefile
+++ b/drivers/gpu/drm/tilcdc/Makefile
@@ -11,3 +11,5 @@ tilcdc-y := \
 	tilcdc_drv.o
 
 obj-$(CONFIG_DRM_TILCDC)	+= tilcdc.o
+obj-$(CONFIG_DRM_TILCDC_PANEL_LEGACY)	+= tilcdc_panel_legacy.o \
+					   tilcdc_panel_legacy.dtbo.o
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel_legacy.c b/drivers/gpu/drm/tilcdc/tilcdc_panel_legacy.c
new file mode 100644
index 0000000000000..a9651dd9f9935
--- /dev/null
+++ b/drivers/gpu/drm/tilcdc/tilcdc_panel_legacy.c
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025 Kory Maincent <kory.maincent at bootlin.com>
+ *
+ * To support the legacy "ti,tilcdc,panel" binding, the devicetree has to
+ * be transformed to the new panel-dpi binding with the endpoint associated.
+ */
+
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/slab.h>
+
+/* Embedded dtbo symbols created by cmd_wrap_S_dtb in scripts/Makefile.lib */
+extern char __dtbo_tilcdc_panel_legacy_begin[];
+extern char __dtbo_tilcdc_panel_legacy_end[];
+
+static void __init
+tilcdc_panel_update_prop(struct device_node *node, char *name,
+			 void *val, int length)
+{
+	struct property *prop;
+
+	prop = kzalloc(sizeof(*prop), GFP_KERNEL);
+	if (!prop)
+		return;
+
+	prop->name = kstrdup(name, GFP_KERNEL);
+	prop->length = length;
+	prop->value = kmemdup(val, length, GFP_KERNEL);
+	of_update_property(node, prop);
+}
+
+static int __init tilcdc_panel_copy_props(struct device_node *old_panel,
+					  struct device_node *new_panel)
+{
+	struct device_node *child, *old_timing, *new_timing, *panel_info;
+	u32 invert_pxl_clk = 0, sync_edge = 0;
+	struct property *prop;
+
+	/* Copy all panel properties to the new panel node */
+	for_each_property_of_node(old_panel, prop) {
+		if (!strncmp(prop->name, "compatible", sizeof("compatible")))
+			continue;
+
+		tilcdc_panel_update_prop(new_panel, prop->name,
+					 prop->value, prop->length);
+	}
+
+	child = of_get_child_by_name(old_panel, "display-timings");
+	if (!child)
+		return -EINVAL;
+
+	/* The default display timing is the one specified as native-mode.
+	 * If no native-mode is specified then the first node is assumed
+	 * to be the native mode.
+	 */
+	old_timing = of_parse_phandle(child, "native-mode", 0);
+	if (!old_timing) {
+		old_timing = of_get_next_child(child, NULL);
+		if (!old_timing) {
+			of_node_put(child);
+			return -EINVAL;
+		}
+	}
+	of_node_put(child);
+
+	new_timing = of_get_child_by_name(new_panel, "panel-timing");
+	if (!new_timing)
+		return -EINVAL;
+
+	/* Copy all panel timing property to the new panel node */
+	for_each_property_of_node(old_timing, prop)
+		tilcdc_panel_update_prop(new_timing, prop->name,
+					 prop->value, prop->length);
+
+	panel_info = of_get_child_by_name(old_panel, "panel-info");
+	if (!panel_info)
+		return -EINVAL;
+
+	/* Looked only for these two parameter as all the other are always
+	 * set to default and not related to common DRM properties.
+	 */
+	of_property_read_u32(panel_info, "invert-pxl-clk", &invert_pxl_clk);
+	of_property_read_u32(panel_info, "sync-edge", &sync_edge);
+
+	if (!invert_pxl_clk)
+		tilcdc_panel_update_prop(new_timing, "pixelclk-active",
+					 &(int){1}, sizeof(int));
+
+	if (!sync_edge)
+		tilcdc_panel_update_prop(new_timing, "syncclk-active",
+					 &(int){1}, sizeof(int));
+
+	of_node_put(panel_info);
+	of_node_put(old_timing);
+	of_node_put(new_timing);
+	return 0;
+}
+
+static const struct of_device_id tilcdc_panel_of_match[] __initconst = {
+	{ .compatible = "ti,tilcdc,panel", },
+	{},
+};
+
+static const struct of_device_id tilcdc_of_match[] __initconst = {
+	{ .compatible = "ti,am33xx-tilcdc", },
+	{ .compatible = "ti,da850-tilcdc", },
+	{},
+};
+
+static int __init tilcdc_panel_legacy_init(void)
+{
+	struct device_node *panel, *lcdc, *new_panel;
+	void *dtbo_start;
+	u32 dtbo_size;
+	int ovcs_id;
+	int ret;
+
+	lcdc = of_find_matching_node(NULL, tilcdc_of_match);
+	panel = of_find_matching_node(NULL, tilcdc_panel_of_match);
+
+	if (!of_device_is_available(panel) ||
+	    !of_device_is_available(lcdc)) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	dtbo_start = __dtbo_tilcdc_panel_legacy_begin;
+	dtbo_size = __dtbo_tilcdc_panel_legacy_end -
+		    __dtbo_tilcdc_panel_legacy_begin;
+
+	ret = of_overlay_fdt_apply(dtbo_start, dtbo_size, &ovcs_id, NULL);
+	if (ret)
+		goto out;
+
+	new_panel = of_find_node_by_name(NULL, "panel-dpi");
+	if (!new_panel) {
+		ret = -ENODEV;
+		goto overlay_remove;
+	}
+
+	ret = tilcdc_panel_copy_props(panel, new_panel);
+	if (ret)
+		goto overlay_remove;
+
+	/* Remove compatible property to avoid any driver compatible match */
+	of_remove_property(panel, of_find_property(panel, "compatible",
+						   NULL));
+overlay_remove:
+	of_overlay_remove(&ovcs_id);
+out:
+	of_node_put(new_panel);
+	of_node_put(panel);
+	of_node_put(lcdc);
+	return ret;
+}
+
+subsys_initcall(tilcdc_panel_legacy_init);
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel_legacy.dtso b/drivers/gpu/drm/tilcdc/tilcdc_panel_legacy.dtso
new file mode 100644
index 0000000000000..77f3ec9391d55
--- /dev/null
+++ b/drivers/gpu/drm/tilcdc/tilcdc_panel_legacy.dtso
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * DTS overlay for converting ti,tilcdc,panel binding to new binding.
+ *
+ * Copyright (C) Kory Maincent <kory.maincent at bootlin.com>
+ */
+
+/dts-v1/;
+/plugin/;
+
+&{/} {
+	panel-dpi {
+		compatible = "panel-dpi";
+		port {
+			panel_in: endpoint at 0 {
+				remote-endpoint = <&lcd_0>;
+			};
+		};
+		panel-timing {
+			clock-frequency = <0>;
+			hactive = <0>;
+			vactive = <0>;
+			hfront-porch = <0>;
+			hback-porch = <0>;
+			hsync-len = <0>;
+			vfront-porch = <0>;
+			vback-porch = <0>;
+			vsync-len = <0>;
+			hsync-active = <0>;
+			vsync-active = <0>;
+			de-active = <0>;
+			pixelclk-active = <0>;
+			syncclk-active = <0>;
+		};
+	};
+};
+
+&lcdc {
+	port {
+		lcd_0: endpoint at 0 {
+			remote-endpoint = <&panel_in>;
+		};
+	};
+};

-- 
2.43.0



From kory.maincent at bootlin.com  Thu Dec 11 08:38:50 2025
From: kory.maincent at bootlin.com (Kory Maincent (TI.com))
Date: Thu, 11 Dec 2025 17:38:50 +0100
Subject: [PATCH v2 06/20] drm/tilcdc: Remove tilcdc panel driver
In-Reply-To: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
Message-ID: <20251211-feature_tilcdc-v2-6-f48bac3cd33e@bootlin.com>

The tilcdc panel subdriver is a legacy, non-standard driver that has been
replaced by the standard panel-dpi driver and panel-simple infrastructure.

With the device tree bindings removed and all in-tree users migrated to
use panel-dpi, this driver no longer has any associated device tree
bindings or users. The panel-dpi driver combined with DRM bus flags
provides equivalent functionality in a standard way that is compatible
with the broader DRM panel ecosystem.

This removal eliminates 400+ lines of redundant code and completes the
migration to standard panel handling.

Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
---
 drivers/gpu/drm/tilcdc/Makefile       |   1 -
 drivers/gpu/drm/tilcdc/tilcdc_drv.c   |   3 -
 drivers/gpu/drm/tilcdc/tilcdc_panel.c | 408 ----------------------------------
 drivers/gpu/drm/tilcdc/tilcdc_panel.h |  15 --
 4 files changed, 427 deletions(-)

diff --git a/drivers/gpu/drm/tilcdc/Makefile b/drivers/gpu/drm/tilcdc/Makefile
index 6d6a08b5adf40..b78204a65ce29 100644
--- a/drivers/gpu/drm/tilcdc/Makefile
+++ b/drivers/gpu/drm/tilcdc/Makefile
@@ -6,7 +6,6 @@ endif
 tilcdc-y := \
 	tilcdc_plane.o \
 	tilcdc_crtc.o \
-	tilcdc_panel.o \
 	tilcdc_external.o \
 	tilcdc_drv.o
 
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index 60230fa9cec95..28f09b9c1879b 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -28,7 +28,6 @@
 
 #include "tilcdc_drv.h"
 #include "tilcdc_external.h"
-#include "tilcdc_panel.h"
 #include "tilcdc_regs.h"
 
 enum {
@@ -636,7 +635,6 @@ static int __init tilcdc_drm_init(void)
 		return -ENODEV;
 
 	DBG("init");
-	tilcdc_panel_init();
 	return platform_driver_register(&tilcdc_platform_driver);
 }
 
@@ -644,7 +642,6 @@ static void __exit tilcdc_drm_fini(void)
 {
 	DBG("fini");
 	platform_driver_unregister(&tilcdc_platform_driver);
-	tilcdc_panel_fini();
 }
 
 module_init(tilcdc_drm_init);
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel.c b/drivers/gpu/drm/tilcdc/tilcdc_panel.c
deleted file mode 100644
index 262f290d85d91..0000000000000
--- a/drivers/gpu/drm/tilcdc/tilcdc_panel.c
+++ /dev/null
@@ -1,408 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2012 Texas Instruments
- * Author: Rob Clark <robdclark at gmail.com>
- */
-
-#include <linux/backlight.h>
-#include <linux/gpio/consumer.h>
-#include <linux/platform_device.h>
-
-#include <video/display_timing.h>
-#include <video/of_display_timing.h>
-#include <video/videomode.h>
-
-#include <drm/drm_atomic_state_helper.h>
-#include <drm/drm_connector.h>
-#include <drm/drm_modeset_helper_vtables.h>
-#include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
-
-#include "tilcdc_drv.h"
-#include "tilcdc_panel.h"
-
-struct panel_module {
-	struct tilcdc_module base;
-	struct tilcdc_panel_info *info;
-	struct display_timings *timings;
-	struct backlight_device *backlight;
-	struct gpio_desc *enable_gpio;
-};
-#define to_panel_module(x) container_of(x, struct panel_module, base)
-
-
-/*
- * Encoder:
- */
-
-struct panel_encoder {
-	struct drm_encoder base;
-	struct panel_module *mod;
-};
-#define to_panel_encoder(x) container_of(x, struct panel_encoder, base)
-
-static void panel_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
-	struct panel_encoder *panel_encoder = to_panel_encoder(encoder);
-	struct backlight_device *backlight = panel_encoder->mod->backlight;
-	struct gpio_desc *gpio = panel_encoder->mod->enable_gpio;
-
-	if (backlight) {
-		backlight->props.power = mode == DRM_MODE_DPMS_ON ?
-					 BACKLIGHT_POWER_ON : BACKLIGHT_POWER_OFF;
-		backlight_update_status(backlight);
-	}
-
-	if (gpio)
-		gpiod_set_value_cansleep(gpio,
-					 mode == DRM_MODE_DPMS_ON ? 1 : 0);
-}
-
-static void panel_encoder_prepare(struct drm_encoder *encoder)
-{
-	panel_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
-}
-
-static void panel_encoder_commit(struct drm_encoder *encoder)
-{
-	panel_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
-}
-
-static void panel_encoder_mode_set(struct drm_encoder *encoder,
-		struct drm_display_mode *mode,
-		struct drm_display_mode *adjusted_mode)
-{
-	/* nothing needed */
-}
-
-static const struct drm_encoder_helper_funcs panel_encoder_helper_funcs = {
-		.dpms           = panel_encoder_dpms,
-		.prepare        = panel_encoder_prepare,
-		.commit         = panel_encoder_commit,
-		.mode_set       = panel_encoder_mode_set,
-};
-
-static struct drm_encoder *panel_encoder_create(struct drm_device *dev,
-		struct panel_module *mod)
-{
-	struct panel_encoder *panel_encoder;
-	struct drm_encoder *encoder;
-	int ret;
-
-	panel_encoder = devm_kzalloc(dev->dev, sizeof(*panel_encoder),
-				     GFP_KERNEL);
-	if (!panel_encoder)
-		return NULL;
-
-	panel_encoder->mod = mod;
-
-	encoder = &panel_encoder->base;
-	encoder->possible_crtcs = 1;
-
-	ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_LVDS);
-	if (ret < 0)
-		goto fail;
-
-	drm_encoder_helper_add(encoder, &panel_encoder_helper_funcs);
-
-	return encoder;
-
-fail:
-	drm_encoder_cleanup(encoder);
-	return NULL;
-}
-
-/*
- * Connector:
- */
-
-struct panel_connector {
-	struct drm_connector base;
-
-	struct drm_encoder *encoder;  /* our connected encoder */
-	struct panel_module *mod;
-};
-#define to_panel_connector(x) container_of(x, struct panel_connector, base)
-
-
-static void panel_connector_destroy(struct drm_connector *connector)
-{
-	drm_connector_unregister(connector);
-	drm_connector_cleanup(connector);
-}
-
-static int panel_connector_get_modes(struct drm_connector *connector)
-{
-	struct drm_device *dev = connector->dev;
-	struct panel_connector *panel_connector = to_panel_connector(connector);
-	struct display_timings *timings = panel_connector->mod->timings;
-	int i;
-
-	for (i = 0; i < timings->num_timings; i++) {
-		struct drm_display_mode *mode;
-		struct videomode vm;
-
-		if (videomode_from_timings(timings, &vm, i))
-			break;
-
-		mode = drm_mode_create(dev);
-		if (!mode)
-			break;
-
-		drm_display_mode_from_videomode(&vm, mode);
-
-		mode->type = DRM_MODE_TYPE_DRIVER;
-
-		if (timings->native_mode == i)
-			mode->type |= DRM_MODE_TYPE_PREFERRED;
-
-		drm_mode_set_name(mode);
-		drm_mode_probed_add(connector, mode);
-	}
-
-	return i;
-}
-
-static struct drm_encoder *panel_connector_best_encoder(
-		struct drm_connector *connector)
-{
-	struct panel_connector *panel_connector = to_panel_connector(connector);
-	return panel_connector->encoder;
-}
-
-static const struct drm_connector_funcs panel_connector_funcs = {
-	.destroy            = panel_connector_destroy,
-	.fill_modes         = drm_helper_probe_single_connector_modes,
-	.reset              = drm_atomic_helper_connector_reset,
-	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
-	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-};
-
-static const struct drm_connector_helper_funcs panel_connector_helper_funcs = {
-	.get_modes          = panel_connector_get_modes,
-	.best_encoder       = panel_connector_best_encoder,
-};
-
-static struct drm_connector *panel_connector_create(struct drm_device *dev,
-		struct panel_module *mod, struct drm_encoder *encoder)
-{
-	struct panel_connector *panel_connector;
-	struct drm_connector *connector;
-	int ret;
-
-	panel_connector = devm_kzalloc(dev->dev, sizeof(*panel_connector),
-				       GFP_KERNEL);
-	if (!panel_connector)
-		return NULL;
-
-	panel_connector->encoder = encoder;
-	panel_connector->mod = mod;
-
-	connector = &panel_connector->base;
-
-	drm_connector_init(dev, connector, &panel_connector_funcs,
-			DRM_MODE_CONNECTOR_LVDS);
-	drm_connector_helper_add(connector, &panel_connector_helper_funcs);
-
-	connector->interlace_allowed = 0;
-	connector->doublescan_allowed = 0;
-
-	ret = drm_connector_attach_encoder(connector, encoder);
-	if (ret)
-		goto fail;
-
-	return connector;
-
-fail:
-	panel_connector_destroy(connector);
-	return NULL;
-}
-
-/*
- * Module:
- */
-
-static int panel_modeset_init(struct tilcdc_module *mod, struct drm_device *dev)
-{
-	struct panel_module *panel_mod = to_panel_module(mod);
-	struct tilcdc_drm_private *priv = dev->dev_private;
-	struct drm_encoder *encoder;
-	struct drm_connector *connector;
-
-	encoder = panel_encoder_create(dev, panel_mod);
-	if (!encoder)
-		return -ENOMEM;
-
-	connector = panel_connector_create(dev, panel_mod, encoder);
-	if (!connector)
-		return -ENOMEM;
-
-	priv->encoders[priv->num_encoders++] = encoder;
-	priv->connectors[priv->num_connectors++] = connector;
-
-	tilcdc_crtc_set_panel_info(priv->crtc,
-				   to_panel_encoder(encoder)->mod->info);
-
-	return 0;
-}
-
-static const struct tilcdc_module_ops panel_module_ops = {
-		.modeset_init = panel_modeset_init,
-};
-
-/*
- * Device:
- */
-
-/* maybe move this somewhere common if it is needed by other outputs? */
-static struct tilcdc_panel_info *of_get_panel_info(struct device_node *np)
-{
-	struct device_node *info_np;
-	struct tilcdc_panel_info *info;
-	int ret = 0;
-
-	if (!np) {
-		pr_err("%s: no devicenode given\n", __func__);
-		return NULL;
-	}
-
-	info_np = of_get_child_by_name(np, "panel-info");
-	if (!info_np) {
-		pr_err("%s: could not find panel-info node\n", __func__);
-		return NULL;
-	}
-
-	info = kzalloc(sizeof(*info), GFP_KERNEL);
-	if (!info)
-		goto put_node;
-
-	ret |= of_property_read_u32(info_np, "ac-bias", &info->ac_bias);
-	ret |= of_property_read_u32(info_np, "ac-bias-intrpt", &info->ac_bias_intrpt);
-	ret |= of_property_read_u32(info_np, "dma-burst-sz", &info->dma_burst_sz);
-	ret |= of_property_read_u32(info_np, "bpp", &info->bpp);
-	ret |= of_property_read_u32(info_np, "fdd", &info->fdd);
-	ret |= of_property_read_u32(info_np, "sync-edge", &info->sync_edge);
-	ret |= of_property_read_u32(info_np, "sync-ctrl", &info->sync_ctrl);
-	ret |= of_property_read_u32(info_np, "raster-order", &info->raster_order);
-	ret |= of_property_read_u32(info_np, "fifo-th", &info->fifo_th);
-
-	/* optional: */
-	info->tft_alt_mode      = of_property_read_bool(info_np, "tft-alt-mode");
-	info->invert_pxl_clk    = of_property_read_bool(info_np, "invert-pxl-clk");
-
-	if (ret) {
-		pr_err("%s: error reading panel-info properties\n", __func__);
-		kfree(info);
-		info = NULL;
-	}
-
-put_node:
-	of_node_put(info_np);
-	return info;
-}
-
-static int panel_probe(struct platform_device *pdev)
-{
-	struct device_node *node = pdev->dev.of_node;
-	struct backlight_device *backlight;
-	struct panel_module *panel_mod;
-	struct tilcdc_module *mod;
-	int ret;
-
-	/* bail out early if no DT data: */
-	if (!node) {
-		dev_err(&pdev->dev, "device-tree data is missing\n");
-		return -ENXIO;
-	}
-
-	panel_mod = devm_kzalloc(&pdev->dev, sizeof(*panel_mod), GFP_KERNEL);
-	if (!panel_mod)
-		return -ENOMEM;
-
-	backlight = devm_of_find_backlight(&pdev->dev);
-	if (IS_ERR(backlight))
-		return PTR_ERR(backlight);
-	panel_mod->backlight = backlight;
-
-	panel_mod->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
-							 GPIOD_OUT_LOW);
-	if (IS_ERR(panel_mod->enable_gpio)) {
-		ret = PTR_ERR(panel_mod->enable_gpio);
-		dev_err(&pdev->dev, "failed to request enable GPIO\n");
-		goto fail_backlight;
-	}
-
-	if (panel_mod->enable_gpio)
-		dev_info(&pdev->dev, "found enable GPIO\n");
-
-	mod = &panel_mod->base;
-	pdev->dev.platform_data = mod;
-
-	tilcdc_module_init(mod, "panel", &panel_module_ops);
-
-	panel_mod->timings = of_get_display_timings(node);
-	if (!panel_mod->timings) {
-		dev_err(&pdev->dev, "could not get panel timings\n");
-		ret = -EINVAL;
-		goto fail_free;
-	}
-
-	panel_mod->info = of_get_panel_info(node);
-	if (!panel_mod->info) {
-		dev_err(&pdev->dev, "could not get panel info\n");
-		ret = -EINVAL;
-		goto fail_timings;
-	}
-
-	return 0;
-
-fail_timings:
-	display_timings_release(panel_mod->timings);
-
-fail_free:
-	tilcdc_module_cleanup(mod);
-
-fail_backlight:
-	if (panel_mod->backlight)
-		put_device(&panel_mod->backlight->dev);
-	return ret;
-}
-
-static void panel_remove(struct platform_device *pdev)
-{
-	struct tilcdc_module *mod = dev_get_platdata(&pdev->dev);
-	struct panel_module *panel_mod = to_panel_module(mod);
-	struct backlight_device *backlight = panel_mod->backlight;
-
-	if (backlight)
-		put_device(&backlight->dev);
-
-	display_timings_release(panel_mod->timings);
-
-	tilcdc_module_cleanup(mod);
-	kfree(panel_mod->info);
-}
-
-static const struct of_device_id panel_of_match[] = {
-		{ .compatible = "ti,tilcdc,panel", },
-		{ },
-};
-
-static struct platform_driver panel_driver = {
-	.probe = panel_probe,
-	.remove = panel_remove,
-	.driver = {
-		.name = "tilcdc-panel",
-		.of_match_table = panel_of_match,
-	},
-};
-
-int __init tilcdc_panel_init(void)
-{
-	return platform_driver_register(&panel_driver);
-}
-
-void __exit tilcdc_panel_fini(void)
-{
-	platform_driver_unregister(&panel_driver);
-}
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel.h b/drivers/gpu/drm/tilcdc/tilcdc_panel.h
deleted file mode 100644
index 65d735d773a48..0000000000000
--- a/drivers/gpu/drm/tilcdc/tilcdc_panel.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) 2012 Texas Instruments
- * Author: Rob Clark <robdclark at gmail.com>
- */
-
-#ifndef __TILCDC_PANEL_H__
-#define __TILCDC_PANEL_H__
-
-/* sub-module for generic lcd panel output */
-
-int tilcdc_panel_init(void);
-void tilcdc_panel_fini(void);
-
-#endif /* __TILCDC_PANEL_H__ */

-- 
2.43.0



From kory.maincent at bootlin.com  Thu Dec 11 08:38:51 2025
From: kory.maincent at bootlin.com (Kory Maincent (TI.com))
Date: Thu, 11 Dec 2025 17:38:51 +0100
Subject: [PATCH v2 07/20] drm/tilcdc: Remove component framework support
In-Reply-To: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
Message-ID: <20251211-feature_tilcdc-v2-7-f48bac3cd33e@bootlin.com>

The tilcdc driver previously used the component framework to bind
external encoder subdrivers (specifically the TDA998x HDMI encoder).
With the removal of these subdrivers in previous commits, the component
framework is no longer needed.

This commit removes all component framework infrastructure including:
- Component master operations and bind/unbind callbacks
- The is_componentized flag and conditional code paths
- tilcdc_get_external_components() and tilcdc_add_component_encoder()
- TDA998x-specific panel configuration

The driver now uses a simplified initialization path that directly
attaches external devices via the DRM bridge API, eliminating the
complexity of dual code paths for componentized vs non-componentized
configurations.

This cleanup removes approximately 140 lines of code and makes the
driver initialization flow more straightforward.

Reviewed-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
---
 drivers/gpu/drm/tilcdc/tilcdc_crtc.c     | 10 ----
 drivers/gpu/drm/tilcdc/tilcdc_drv.c      | 80 ++++----------------------------
 drivers/gpu/drm/tilcdc/tilcdc_drv.h      |  1 -
 drivers/gpu/drm/tilcdc/tilcdc_external.c | 65 --------------------------
 drivers/gpu/drm/tilcdc/tilcdc_external.h |  3 --
 5 files changed, 9 insertions(+), 150 deletions(-)

diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index 2309a9a0c925d..252e5adaeb6e2 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -1021,16 +1021,6 @@ int tilcdc_crtc_create(struct drm_device *dev)
 
 	drm_crtc_helper_add(crtc, &tilcdc_crtc_helper_funcs);
 
-	if (priv->is_componentized) {
-		crtc->port = of_graph_get_port_by_id(dev->dev->of_node, 0);
-		if (!crtc->port) { /* This should never happen */
-			dev_err(dev->dev, "Port node not found in %pOF\n",
-				dev->dev->of_node);
-			ret = -EINVAL;
-			goto fail;
-		}
-	}
-
 	priv->crtc = crtc;
 	return 0;
 
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index 28f09b9c1879b..9b3a0435a8d2d 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -6,7 +6,6 @@
 
 /* LCDC DRM driver, based on da8xx-fb */
 
-#include <linux/component.h>
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/pinctrl/consumer.h>
@@ -229,9 +228,6 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev)
 	platform_set_drvdata(pdev, ddev);
 	drm_mode_config_init(ddev);
 
-	priv->is_componentized =
-		tilcdc_get_external_components(dev, NULL) > 0;
-
 	priv->wq = alloc_ordered_workqueue("tilcdc", 0);
 	if (!priv->wq) {
 		ret = -ENOMEM;
@@ -348,42 +344,32 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev)
 	}
 #endif
 
-	if (priv->is_componentized) {
-		ret = component_bind_all(dev, ddev);
-		if (ret < 0)
-			goto unregister_cpufreq_notif;
-
-		ret = tilcdc_add_component_encoder(ddev);
-		if (ret < 0)
-			goto unbind_component;
-	} else {
-		ret = tilcdc_attach_external_device(ddev);
-		if (ret)
-			goto unregister_cpufreq_notif;
-	}
+	ret = tilcdc_attach_external_device(ddev);
+	if (ret)
+		goto unregister_cpufreq_notif;
 
 	if (!priv->external_connector &&
 	    ((priv->num_encoders == 0) || (priv->num_connectors == 0))) {
 		dev_err(dev, "no encoders/connectors found\n");
 		ret = -EPROBE_DEFER;
-		goto unbind_component;
+		goto unregister_cpufreq_notif;
 	}
 
 	ret = drm_vblank_init(ddev, 1);
 	if (ret < 0) {
 		dev_err(dev, "failed to initialize vblank\n");
-		goto unbind_component;
+		goto unregister_cpufreq_notif;
 	}
 
 	ret = platform_get_irq(pdev, 0);
 	if (ret < 0)
-		goto unbind_component;
+		goto unregister_cpufreq_notif;
 	priv->irq = ret;
 
 	ret = tilcdc_irq_install(ddev, priv->irq);
 	if (ret < 0) {
 		dev_err(dev, "failed to install IRQ handler\n");
-		goto unbind_component;
+		goto unregister_cpufreq_notif;
 	}
 
 	drm_mode_config_reset(ddev);
@@ -401,9 +387,6 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev)
 stop_poll:
 	drm_kms_helper_poll_fini(ddev);
 	tilcdc_irq_uninstall(ddev);
-unbind_component:
-	if (priv->is_componentized)
-		component_unbind_all(dev, ddev);
 unregister_cpufreq_notif:
 #ifdef CONFIG_CPU_FREQ
 	cpufreq_unregister_notifier(&priv->freq_transition,
@@ -552,65 +535,20 @@ static int tilcdc_pm_resume(struct device *dev)
 static DEFINE_SIMPLE_DEV_PM_OPS(tilcdc_pm_ops,
 				tilcdc_pm_suspend, tilcdc_pm_resume);
 
-/*
- * Platform driver:
- */
-static int tilcdc_bind(struct device *dev)
-{
-	return tilcdc_init(&tilcdc_driver, dev);
-}
-
-static void tilcdc_unbind(struct device *dev)
-{
-	struct drm_device *ddev = dev_get_drvdata(dev);
-
-	/* Check if a subcomponent has already triggered the unloading. */
-	if (!ddev->dev_private)
-		return;
-
-	tilcdc_fini(ddev);
-	dev_set_drvdata(dev, NULL);
-}
-
-static const struct component_master_ops tilcdc_comp_ops = {
-	.bind = tilcdc_bind,
-	.unbind = tilcdc_unbind,
-};
-
 static int tilcdc_pdev_probe(struct platform_device *pdev)
 {
-	struct component_match *match = NULL;
-	int ret;
-
 	/* bail out early if no DT data: */
 	if (!pdev->dev.of_node) {
 		dev_err(&pdev->dev, "device-tree data is missing\n");
 		return -ENXIO;
 	}
 
-	ret = tilcdc_get_external_components(&pdev->dev, &match);
-	if (ret < 0)
-		return ret;
-	else if (ret == 0)
-		return tilcdc_init(&tilcdc_driver, &pdev->dev);
-	else
-		return component_master_add_with_match(&pdev->dev,
-						       &tilcdc_comp_ops,
-						       match);
+	return tilcdc_init(&tilcdc_driver, &pdev->dev);
 }
 
 static void tilcdc_pdev_remove(struct platform_device *pdev)
 {
-	int ret;
-
-	ret = tilcdc_get_external_components(&pdev->dev, NULL);
-	if (ret < 0)
-		dev_err(&pdev->dev, "tilcdc_get_external_components() failed (%pe)\n",
-			ERR_PTR(ret));
-	else if (ret == 0)
-		tilcdc_fini(platform_get_drvdata(pdev));
-	else
-		component_master_del(&pdev->dev, &tilcdc_comp_ops);
+	tilcdc_fini(platform_get_drvdata(pdev));
 }
 
 static void tilcdc_pdev_shutdown(struct platform_device *pdev)
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
index 79078b4ae7393..c23b593dc61f6 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
@@ -84,7 +84,6 @@ struct tilcdc_drm_private {
 	struct drm_encoder *external_encoder;
 	struct drm_connector *external_connector;
 
-	bool is_componentized;
 	bool irq_enabled;
 };
 
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.c b/drivers/gpu/drm/tilcdc/tilcdc_external.c
index da755a411d9ff..2970c41d9c3eb 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_external.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_external.c
@@ -4,7 +4,6 @@
  * Author: Jyri Sarha <jsarha at ti.com>
  */
 
-#include <linux/component.h>
 #include <linux/of_graph.h>
 
 #include <drm/drm_atomic_helper.h>
@@ -15,19 +14,6 @@
 #include "tilcdc_drv.h"
 #include "tilcdc_external.h"
 
-static const struct tilcdc_panel_info panel_info_tda998x = {
-		.ac_bias                = 255,
-		.ac_bias_intrpt         = 0,
-		.dma_burst_sz           = 16,
-		.bpp                    = 16,
-		.fdd                    = 0x80,
-		.tft_alt_mode           = 0,
-		.invert_pxl_clk		= 1,
-		.sync_edge              = 1,
-		.sync_ctrl              = 1,
-		.raster_order           = 0,
-};
-
 static const struct tilcdc_panel_info panel_info_default = {
 		.ac_bias                = 255,
 		.ac_bias_intrpt         = 0,
@@ -57,34 +43,6 @@ struct drm_connector *tilcdc_encoder_find_connector(struct drm_device *ddev,
 	return NULL;
 }
 
-int tilcdc_add_component_encoder(struct drm_device *ddev)
-{
-	struct tilcdc_drm_private *priv = ddev->dev_private;
-	struct drm_encoder *encoder = NULL, *iter;
-
-	list_for_each_entry(iter, &ddev->mode_config.encoder_list, head)
-		if (iter->possible_crtcs & (1 << priv->crtc->index)) {
-			encoder = iter;
-			break;
-		}
-
-	if (!encoder) {
-		dev_err(ddev->dev, "%s: No suitable encoder found\n", __func__);
-		return -ENODEV;
-	}
-
-	priv->external_connector =
-		tilcdc_encoder_find_connector(ddev, encoder);
-
-	if (!priv->external_connector)
-		return -ENODEV;
-
-	/* Only tda998x is supported at the moment. */
-	tilcdc_crtc_set_panel_info(priv->crtc, &panel_info_tda998x);
-
-	return 0;
-}
-
 static
 int tilcdc_attach_bridge(struct drm_device *ddev, struct drm_bridge *bridge)
 {
@@ -153,26 +111,3 @@ int tilcdc_attach_external_device(struct drm_device *ddev)
 	drm_encoder_cleanup(priv->external_encoder);
 	return ret;
 }
-
-static int dev_match_of(struct device *dev, void *data)
-{
-	return dev->of_node == data;
-}
-
-int tilcdc_get_external_components(struct device *dev,
-				   struct component_match **match)
-{
-	struct device_node *node;
-
-	node = of_graph_get_remote_node(dev->of_node, 0, 0);
-
-	if (!of_device_is_compatible(node, "nxp,tda998x")) {
-		of_node_put(node);
-		return 0;
-	}
-
-	if (match)
-		drm_of_component_match_add(dev, match, dev_match_of, node);
-	of_node_put(node);
-	return 1;
-}
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.h b/drivers/gpu/drm/tilcdc/tilcdc_external.h
index fb4476694cd89..285a132f3035d 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_external.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_external.h
@@ -7,8 +7,5 @@
 #ifndef __TILCDC_EXTERNAL_H__
 #define __TILCDC_EXTERNAL_H__
 
-int tilcdc_add_component_encoder(struct drm_device *dev);
-int tilcdc_get_external_components(struct device *dev,
-				   struct component_match **match);
 int tilcdc_attach_external_device(struct drm_device *ddev);
 #endif /* __TILCDC_SLAVE_H__ */

-- 
2.43.0



From kory.maincent at bootlin.com  Thu Dec 11 08:38:52 2025
From: kory.maincent at bootlin.com (Kory Maincent (TI.com))
Date: Thu, 11 Dec 2025 17:38:52 +0100
Subject: [PATCH v2 08/20] drm/tilcdc: Remove tilcdc_panel_info structure
In-Reply-To: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
Message-ID: <20251211-feature_tilcdc-v2-8-f48bac3cd33e@bootlin.com>

Remove the tilcdc_panel_info structure and its associated helper
function as the structure contains only redundant or unused parameters.

Most panel configuration parameters in tilcdc_panel_info are either:
- Already represented by existing DRM mode flags (invert_pxl_clk,
  sync_edge via DRM_BUS_FLAG_*), or
- Set to identical values across all instances (panel_info_default),
  making them effectively constants

The removed fifo_th field is already handled by priv->fifo_th when set.
Other removed fields (tft_alt_mode, raster_order) were always set to 0
in the only instance (panel_info_default) and thus had no effect.

This simplifies the code by eliminating unnecessary abstraction while
preserving all functional behavior.

Reviewed-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
---
 drivers/gpu/drm/tilcdc/tilcdc_crtc.c     | 28 +++------------------
 drivers/gpu/drm/tilcdc/tilcdc_drv.h      | 42 --------------------------------
 drivers/gpu/drm/tilcdc/tilcdc_external.c | 14 -----------
 3 files changed, 3 insertions(+), 81 deletions(-)

diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index 252e5adaeb6e2..5b8aba0765f9b 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -31,7 +31,6 @@ struct tilcdc_crtc {
 	struct drm_crtc base;
 
 	struct drm_plane primary;
-	const struct tilcdc_panel_info *info;
 	struct drm_pending_vblank_event *event;
 	struct mutex enable_lock;
 	bool enabled;
@@ -272,14 +271,10 @@ static void tilcdc_crtc_set_mode(struct drm_crtc *crtc)
 	struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
 	struct tilcdc_drm_private *priv = dev->dev_private;
-	const struct tilcdc_panel_info *info = tilcdc_crtc->info;
 	uint32_t reg, hbp, hfp, hsw, vbp, vfp, vsw;
 	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
 	struct drm_framebuffer *fb = crtc->primary->state->fb;
 
-	if (WARN_ON(!info))
-		return;
-
 	if (WARN_ON(!fb))
 		return;
 
@@ -287,12 +282,11 @@ static void tilcdc_crtc_set_mode(struct drm_crtc *crtc)
 	reg = tilcdc_read(dev, LCDC_DMA_CTRL_REG) & ~0x00000770;
 	/* Use 16 bit DMA burst size by default */
 	reg |= LCDC_DMA_BURST_SIZE(LCDC_DMA_BURST_16);
+
 	if (priv->fifo_th) {
 		int fifo_th_val = ilog2(priv->fifo_th) - 3;
 
 		reg |= (fifo_th_val << 8);
-	} else {
-		reg |= (info->fifo_th << 8);
 	}
 	tilcdc_write(dev, LCDC_DMA_CTRL_REG, reg);
 
@@ -360,8 +354,6 @@ static void tilcdc_crtc_set_mode(struct drm_crtc *crtc)
 		  LCDC_V2_TFT_24BPP_MODE | LCDC_V2_TFT_24BPP_UNPACK |
 		  0x000ff000 /* Palette Loading Delay bits */);
 	reg |= LCDC_TFT_MODE; /* no monochrome/passive support */
-	if (info->tft_alt_mode)
-		reg |= LCDC_TFT_ALT_ENABLE;
 	if (priv->rev == 2) {
 		switch (fb->format->format) {
 		case DRM_FORMAT_BGR565:
@@ -384,15 +376,13 @@ static void tilcdc_crtc_set_mode(struct drm_crtc *crtc)
 	reg |= 128 << 12;
 	tilcdc_write(dev, LCDC_RASTER_CTRL_REG, reg);
 
-	if (info->invert_pxl_clk ||
-	    mode->flags == DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
+	if (mode->flags == DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
 		tilcdc_set(dev, LCDC_RASTER_TIMING_2_REG, LCDC_INVERT_PIXEL_CLOCK);
 	else
 		tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG, LCDC_INVERT_PIXEL_CLOCK);
 
 	tilcdc_set(dev, LCDC_RASTER_TIMING_2_REG, LCDC_SYNC_CTRL);
-	if (info->sync_edge ||
-	    mode->flags == DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE)
+	if (mode->flags == DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE)
 		tilcdc_set(dev, LCDC_RASTER_TIMING_2_REG, LCDC_SYNC_EDGE);
 	else
 		tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG, LCDC_SYNC_EDGE);
@@ -407,11 +397,6 @@ static void tilcdc_crtc_set_mode(struct drm_crtc *crtc)
 	else
 		tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG, LCDC_INVERT_VSYNC);
 
-	if (info->raster_order)
-		tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ORDER);
-	else
-		tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ORDER);
-
 	tilcdc_crtc_set_clk(crtc);
 
 	tilcdc_crtc_load_palette(crtc);
@@ -838,13 +823,6 @@ static const struct drm_crtc_helper_funcs tilcdc_crtc_helper_funcs = {
 	.atomic_flush	= tilcdc_crtc_atomic_flush,
 };
 
-void tilcdc_crtc_set_panel_info(struct drm_crtc *crtc,
-		const struct tilcdc_panel_info *info)
-{
-	struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
-	tilcdc_crtc->info = info;
-}
-
 void tilcdc_crtc_update_clk(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
index c23b593dc61f6..181b9d7a515b6 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
@@ -114,53 +114,11 @@ void tilcdc_module_init(struct tilcdc_module *mod, const char *name,
 		const struct tilcdc_module_ops *funcs);
 void tilcdc_module_cleanup(struct tilcdc_module *mod);
 
-/* Panel config that needs to be set in the crtc, but is not coming from
- * the mode timings.  The display module is expected to call
- * tilcdc_crtc_set_panel_info() to set this during modeset.
- */
-struct tilcdc_panel_info {
-
-	/* AC Bias Pin Frequency */
-	uint32_t ac_bias;
-
-	/* AC Bias Pin Transitions per Interrupt */
-	uint32_t ac_bias_intrpt;
-
-	/* DMA burst size */
-	uint32_t dma_burst_sz;
-
-	/* Bits per pixel */
-	uint32_t bpp;
-
-	/* FIFO DMA Request Delay */
-	uint32_t fdd;
-
-	/* TFT Alternative Signal Mapping (Only for active) */
-	bool tft_alt_mode;
-
-	/* Invert pixel clock */
-	bool invert_pxl_clk;
-
-	/* Horizontal and Vertical Sync Edge: 0=rising 1=falling */
-	uint32_t sync_edge;
-
-	/* Horizontal and Vertical Sync: Control: 0=ignore */
-	uint32_t sync_ctrl;
-
-	/* Raster Data Order Select: 1=Most-to-least 0=Least-to-most */
-	uint32_t raster_order;
-
-	/* DMA FIFO threshold */
-	uint32_t fifo_th;
-};
-
 #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
 
 int tilcdc_crtc_create(struct drm_device *dev);
 irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc);
 void tilcdc_crtc_update_clk(struct drm_crtc *crtc);
-void tilcdc_crtc_set_panel_info(struct drm_crtc *crtc,
-		const struct tilcdc_panel_info *info);
 void tilcdc_crtc_shutdown(struct drm_crtc *crtc);
 void tilcdc_crtc_destroy(struct drm_crtc *crtc);
 int tilcdc_crtc_update_fb(struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.c b/drivers/gpu/drm/tilcdc/tilcdc_external.c
index 2970c41d9c3eb..81c90c2754c6c 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_external.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_external.c
@@ -14,18 +14,6 @@
 #include "tilcdc_drv.h"
 #include "tilcdc_external.h"
 
-static const struct tilcdc_panel_info panel_info_default = {
-		.ac_bias                = 255,
-		.ac_bias_intrpt         = 0,
-		.dma_burst_sz           = 16,
-		.bpp                    = 16,
-		.fdd                    = 0x80,
-		.tft_alt_mode           = 0,
-		.sync_edge              = 0,
-		.sync_ctrl              = 1,
-		.raster_order           = 0,
-};
-
 static
 struct drm_connector *tilcdc_encoder_find_connector(struct drm_device *ddev,
 						    struct drm_encoder *encoder)
@@ -55,8 +43,6 @@ int tilcdc_attach_bridge(struct drm_device *ddev, struct drm_bridge *bridge)
 	if (ret)
 		return ret;
 
-	tilcdc_crtc_set_panel_info(priv->crtc, &panel_info_default);
-
 	priv->external_connector =
 		tilcdc_encoder_find_connector(ddev, priv->external_encoder);
 	if (!priv->external_connector)

-- 
2.43.0



From kory.maincent at bootlin.com  Thu Dec 11 08:38:53 2025
From: kory.maincent at bootlin.com (Kory Maincent (TI.com))
Date: Thu, 11 Dec 2025 17:38:53 +0100
Subject: [PATCH v2 09/20] drm/tilcdc: Remove redundant #endif/#ifdef in
 debugfs code
In-Reply-To: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
Message-ID: <20251211-feature_tilcdc-v2-9-f48bac3cd33e@bootlin.com>

Remove the unnecessary #endif/#ifdef CONFIG_DEBUG_FS pair that splits
the debugfs code section. This keeps all debugfs-related code within a
single preprocessor conditional block, improving code readability.

Reviewed-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
---
 drivers/gpu/drm/tilcdc/tilcdc_drv.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index 9b3a0435a8d2d..d2aae731b72c6 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -438,9 +438,6 @@ static const struct {
 #undef REG
 };
 
-#endif
-
-#ifdef CONFIG_DEBUG_FS
 static int tilcdc_regs_show(struct seq_file *m, void *arg)
 {
 	struct drm_info_node *node = (struct drm_info_node *) m->private;

-- 
2.43.0



From kory.maincent at bootlin.com  Thu Dec 11 08:38:55 2025
From: kory.maincent at bootlin.com (Kory Maincent (TI.com))
Date: Thu, 11 Dec 2025 17:38:55 +0100
Subject: [PATCH v2 11/20] drm/tilcdc: Rename external_encoder and
 external_connector to encoder and connector
In-Reply-To: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
Message-ID: <20251211-feature_tilcdc-v2-11-f48bac3cd33e@bootlin.com>

Remove the "external_" prefix from encoder and connector members in the
tilcdc driver. These are internal driver structures and the "external"
naming is misleading. The simpler names better reflect that these are
the primary encoder and connector managed by this driver.

Also rename tilcdc_attach_external_device() to tilcdc_encoder_create()
for consistency and to better describe the function's purpose.

Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
---
 drivers/gpu/drm/tilcdc/tilcdc_drv.c      |  4 ++--
 drivers/gpu/drm/tilcdc/tilcdc_drv.h      |  4 ++--
 drivers/gpu/drm/tilcdc/tilcdc_external.c | 24 ++++++++++++------------
 drivers/gpu/drm/tilcdc/tilcdc_external.h |  2 +-
 4 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index a753cc47a59d7..bf6cd763ecd0f 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -344,11 +344,11 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev)
 	}
 #endif
 
-	ret = tilcdc_attach_external_device(ddev);
+	ret = tilcdc_encoder_create(ddev);
 	if (ret)
 		goto unregister_cpufreq_notif;
 
-	if (!priv->external_connector) {
+	if (!priv->connector) {
 		dev_err(dev, "no encoders/connectors found\n");
 		ret = -EPROBE_DEFER;
 		goto unregister_cpufreq_notif;
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
index 717529a331009..dafb00908d1d4 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
@@ -75,8 +75,8 @@ struct tilcdc_drm_private {
 
 	struct drm_crtc *crtc;
 
-	struct drm_encoder *external_encoder;
-	struct drm_connector *external_connector;
+	struct drm_encoder *encoder;
+	struct drm_connector *connector;
 
 	bool irq_enabled;
 };
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.c b/drivers/gpu/drm/tilcdc/tilcdc_external.c
index 81c90c2754c6c..0c18d05dc7101 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_external.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_external.c
@@ -37,21 +37,21 @@ int tilcdc_attach_bridge(struct drm_device *ddev, struct drm_bridge *bridge)
 	struct tilcdc_drm_private *priv = ddev->dev_private;
 	int ret;
 
-	priv->external_encoder->possible_crtcs = BIT(0);
+	priv->encoder->possible_crtcs = BIT(0);
 
-	ret = drm_bridge_attach(priv->external_encoder, bridge, NULL, 0);
+	ret = drm_bridge_attach(priv->encoder, bridge, NULL, 0);
 	if (ret)
 		return ret;
 
-	priv->external_connector =
-		tilcdc_encoder_find_connector(ddev, priv->external_encoder);
-	if (!priv->external_connector)
+	priv->connector =
+		tilcdc_encoder_find_connector(ddev, priv->encoder);
+	if (!priv->connector)
 		return -ENODEV;
 
 	return 0;
 }
 
-int tilcdc_attach_external_device(struct drm_device *ddev)
+int tilcdc_encoder_create(struct drm_device *ddev)
 {
 	struct tilcdc_drm_private *priv = ddev->dev_private;
 	struct drm_bridge *bridge;
@@ -65,13 +65,13 @@ int tilcdc_attach_external_device(struct drm_device *ddev)
 	else if (ret)
 		return ret;
 
-	priv->external_encoder = devm_kzalloc(ddev->dev,
-					      sizeof(*priv->external_encoder),
-					      GFP_KERNEL);
-	if (!priv->external_encoder)
+	priv->encoder = devm_kzalloc(ddev->dev,
+				     sizeof(*priv->encoder),
+				     GFP_KERNEL);
+	if (!priv->encoder)
 		return -ENOMEM;
 
-	ret = drm_simple_encoder_init(ddev, priv->external_encoder,
+	ret = drm_simple_encoder_init(ddev, priv->encoder,
 				      DRM_MODE_ENCODER_NONE);
 	if (ret) {
 		dev_err(ddev->dev, "drm_encoder_init() failed %d\n", ret);
@@ -94,6 +94,6 @@ int tilcdc_attach_external_device(struct drm_device *ddev)
 	return 0;
 
 err_encoder_cleanup:
-	drm_encoder_cleanup(priv->external_encoder);
+	drm_encoder_cleanup(priv->encoder);
 	return ret;
 }
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.h b/drivers/gpu/drm/tilcdc/tilcdc_external.h
index 285a132f3035d..c8f87f59024e6 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_external.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_external.h
@@ -7,5 +7,5 @@
 #ifndef __TILCDC_EXTERNAL_H__
 #define __TILCDC_EXTERNAL_H__
 
-int tilcdc_attach_external_device(struct drm_device *ddev);
+int tilcdc_encoder_create(struct drm_device *ddev);
 #endif /* __TILCDC_SLAVE_H__ */

-- 
2.43.0



From kory.maincent at bootlin.com  Thu Dec 11 08:38:56 2025
From: kory.maincent at bootlin.com (Kory Maincent (TI.com))
Date: Thu, 11 Dec 2025 17:38:56 +0100
Subject: [PATCH v2 12/20] drm/tilcdc: Rename tilcdc_external to
 tilcdc_encoder
In-Reply-To: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
Message-ID: <20251211-feature_tilcdc-v2-12-f48bac3cd33e@bootlin.com>

The tilcdc_external module describes the encoder part of the tilcdc
driver. Rename it to tilcdc_encoder for better clarity and to make
the naming more consistent with DRM subsystem conventions, where
encoder-related files typically use "encoder" in their names.

Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
---
 drivers/gpu/drm/tilcdc/Makefile                                | 2 +-
 drivers/gpu/drm/tilcdc/tilcdc_drv.c                            | 2 +-
 drivers/gpu/drm/tilcdc/{tilcdc_external.c => tilcdc_encoder.c} | 2 +-
 drivers/gpu/drm/tilcdc/{tilcdc_external.h => tilcdc_encoder.h} | 0
 4 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/tilcdc/Makefile b/drivers/gpu/drm/tilcdc/Makefile
index b78204a65ce29..c6b484dad711a 100644
--- a/drivers/gpu/drm/tilcdc/Makefile
+++ b/drivers/gpu/drm/tilcdc/Makefile
@@ -6,7 +6,7 @@ endif
 tilcdc-y := \
 	tilcdc_plane.o \
 	tilcdc_crtc.o \
-	tilcdc_external.o \
+	tilcdc_encoder.o \
 	tilcdc_drv.o
 
 obj-$(CONFIG_DRM_TILCDC)	+= tilcdc.o
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index bf6cd763ecd0f..6a08f50762af9 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -26,7 +26,7 @@
 
 
 #include "tilcdc_drv.h"
-#include "tilcdc_external.h"
+#include "tilcdc_encoder.h"
 #include "tilcdc_regs.h"
 
 enum {
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.c b/drivers/gpu/drm/tilcdc/tilcdc_encoder.c
similarity index 98%
rename from drivers/gpu/drm/tilcdc/tilcdc_external.c
rename to drivers/gpu/drm/tilcdc/tilcdc_encoder.c
index 0c18d05dc7101..bca91226351dd 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_external.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_encoder.c
@@ -12,7 +12,7 @@
 #include <drm/drm_simple_kms_helper.h>
 
 #include "tilcdc_drv.h"
-#include "tilcdc_external.h"
+#include "tilcdc_encoder.h"
 
 static
 struct drm_connector *tilcdc_encoder_find_connector(struct drm_device *ddev,
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.h b/drivers/gpu/drm/tilcdc/tilcdc_encoder.h
similarity index 100%
rename from drivers/gpu/drm/tilcdc/tilcdc_external.h
rename to drivers/gpu/drm/tilcdc/tilcdc_encoder.h

-- 
2.43.0



From kory.maincent at bootlin.com  Thu Dec 11 08:38:57 2025
From: kory.maincent at bootlin.com (Kory Maincent (TI.com))
Date: Thu, 11 Dec 2025 17:38:57 +0100
Subject: [PATCH v2 13/20] drm/tilcdc: Remove the useless module list
 support
In-Reply-To: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
Message-ID: <20251211-feature_tilcdc-v2-13-f48bac3cd33e@bootlin.com>

The tilcdc driver previously supported a sub-module system where
external display drivers (panels, encoders) could register themselves
through tilcdc_module_init() and be automatically initialized through
a module list. This infrastructure became unused after the component
framework support and panel driver was removed.

Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
---
 drivers/gpu/drm/tilcdc/tilcdc_drv.c | 48 +------------------------------------
 drivers/gpu/drm/tilcdc/tilcdc_drv.h | 27 ---------------------
 2 files changed, 1 insertion(+), 74 deletions(-)

diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index 6a08f50762af9..4630e56c3f028 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -7,7 +7,6 @@
 /* LCDC DRM driver, based on da8xx-fb */
 
 #include <linux/mod_devicetable.h>
-#include <linux/module.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
@@ -34,8 +33,6 @@ enum {
 	DA850_TILCDC,
 };
 
-static LIST_HEAD(module_list);
-
 static const u32 tilcdc_rev1_formats[] = { DRM_FORMAT_RGB565 };
 
 static const u32 tilcdc_straight_formats[] = { DRM_FORMAT_RGB565,
@@ -50,20 +47,6 @@ static const u32 tilcdc_legacy_formats[] = { DRM_FORMAT_RGB565,
 					     DRM_FORMAT_RGB888,
 					     DRM_FORMAT_XRGB8888 };
 
-void tilcdc_module_init(struct tilcdc_module *mod, const char *name,
-		const struct tilcdc_module_ops *funcs)
-{
-	mod->name = name;
-	mod->funcs = funcs;
-	INIT_LIST_HEAD(&mod->list);
-	list_add(&mod->list, &module_list);
-}
-
-void tilcdc_module_cleanup(struct tilcdc_module *mod)
-{
-	list_del(&mod->list);
-}
-
 static int tilcdc_atomic_check(struct drm_device *dev,
 			       struct drm_atomic_state *state)
 {
@@ -97,12 +80,6 @@ static const struct drm_mode_config_funcs mode_config_funcs = {
 static void modeset_init(struct drm_device *dev)
 {
 	struct tilcdc_drm_private *priv = dev->dev_private;
-	struct tilcdc_module *mod;
-
-	list_for_each_entry(mod, &module_list, list) {
-		DBG("loading module: %s", mod->name);
-		mod->funcs->modeset_init(mod, dev);
-	}
 
 	dev->mode_config.min_width = 0;
 	dev->mode_config.min_height = 0;
@@ -474,15 +451,9 @@ static struct drm_info_list tilcdc_debugfs_list[] = {
 
 static void tilcdc_debugfs_init(struct drm_minor *minor)
 {
-	struct tilcdc_module *mod;
-
 	drm_debugfs_create_files(tilcdc_debugfs_list,
 				 ARRAY_SIZE(tilcdc_debugfs_list),
 				 minor->debugfs_root, minor);
-
-	list_for_each_entry(mod, &module_list, list)
-		if (mod->funcs->debugfs_init)
-			mod->funcs->debugfs_init(mod, minor);
 }
 #endif
 
@@ -562,24 +533,7 @@ static struct platform_driver tilcdc_platform_driver = {
 		.of_match_table = tilcdc_of_match,
 	},
 };
-
-static int __init tilcdc_drm_init(void)
-{
-	if (drm_firmware_drivers_only())
-		return -ENODEV;
-
-	DBG("init");
-	return platform_driver_register(&tilcdc_platform_driver);
-}
-
-static void __exit tilcdc_drm_fini(void)
-{
-	DBG("fini");
-	platform_driver_unregister(&tilcdc_platform_driver);
-}
-
-module_init(tilcdc_drm_init);
-module_exit(tilcdc_drm_fini);
+module_platform_driver(tilcdc_platform_driver);
 
 MODULE_AUTHOR("Rob Clark <robdclark at gmail.com");
 MODULE_DESCRIPTION("TI LCD Controller DRM Driver");
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
index dafb00908d1d4..60e85e29b1063 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
@@ -81,33 +81,6 @@ struct tilcdc_drm_private {
 	bool irq_enabled;
 };
 
-/* Sub-module for display.  Since we don't know at compile time what panels
- * or display adapter(s) might be present (for ex, off chip dvi/tfp410,
- * hdmi encoder, various lcd panels), the connector/encoder(s) are split into
- * separate drivers.  If they are probed and found to be present, they
- * register themselves with tilcdc_register_module().
- */
-struct tilcdc_module;
-
-struct tilcdc_module_ops {
-	/* create appropriate encoders/connectors: */
-	int (*modeset_init)(struct tilcdc_module *mod, struct drm_device *dev);
-#ifdef CONFIG_DEBUG_FS
-	/* create debugfs nodes (can be NULL): */
-	int (*debugfs_init)(struct tilcdc_module *mod, struct drm_minor *minor);
-#endif
-};
-
-struct tilcdc_module {
-	const char *name;
-	struct list_head list;
-	const struct tilcdc_module_ops *funcs;
-};
-
-void tilcdc_module_init(struct tilcdc_module *mod, const char *name,
-		const struct tilcdc_module_ops *funcs);
-void tilcdc_module_cleanup(struct tilcdc_module *mod);
-
 #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
 
 int tilcdc_crtc_create(struct drm_device *dev);

-- 
2.43.0



From kory.maincent at bootlin.com  Thu Dec 11 08:38:58 2025
From: kory.maincent at bootlin.com (Kory Maincent (TI.com))
Date: Thu, 11 Dec 2025 17:38:58 +0100
Subject: [PATCH v2 14/20] drm/tilcdc: Modernize driver initialization and
 cleanup paths
In-Reply-To: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
Message-ID: <20251211-feature_tilcdc-v2-14-f48bac3cd33e@bootlin.com>

Refactor the driver initialization to use modern DRM managed resource
APIs, simplifying the code.

The tilcdc_init and tilcdc_fini wrapper functions are removed since they
served no purpose after the component framework was eliminated. Their
logic is integrated directly into probe and remove.

Key changes:
- Use devm_drm_dev_alloc() instead of drm_dev_alloc().
- Use drmm_mode_config_init() instead of drm_mode_config_init().
- Align the remove path with the probe error path to ensure consistent
  cleanup ordering in both success and failure cases.
- Adjust platform_set_drvdata() to store the private structure instead
  of the drm_device, matching the new allocation pattern.

These changes reduce error-prone code while maintaining the same
functional behavior.

Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
---
 drivers/gpu/drm/tilcdc/tilcdc_drv.c | 308 ++++++++++++++++--------------------
 drivers/gpu/drm/tilcdc/tilcdc_drv.h |   2 +
 2 files changed, 139 insertions(+), 171 deletions(-)

diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index 4630e56c3f028..2cbe390a1ee54 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -139,39 +139,125 @@ static void tilcdc_irq_uninstall(struct drm_device *dev)
  * DRM operations:
  */
 
-static void tilcdc_fini(struct drm_device *dev)
+#if defined(CONFIG_DEBUG_FS)
+static const struct {
+	const char *name;
+	uint8_t  rev;
+	uint8_t  save;
+	uint32_t reg;
+} registers[] =		{
+#define REG(rev, save, reg) { #reg, rev, save, reg }
+		/* exists in revision 1: */
+		REG(1, false, LCDC_PID_REG),
+		REG(1, true,  LCDC_CTRL_REG),
+		REG(1, false, LCDC_STAT_REG),
+		REG(1, true,  LCDC_RASTER_CTRL_REG),
+		REG(1, true,  LCDC_RASTER_TIMING_0_REG),
+		REG(1, true,  LCDC_RASTER_TIMING_1_REG),
+		REG(1, true,  LCDC_RASTER_TIMING_2_REG),
+		REG(1, true,  LCDC_DMA_CTRL_REG),
+		REG(1, true,  LCDC_DMA_FB_BASE_ADDR_0_REG),
+		REG(1, true,  LCDC_DMA_FB_CEILING_ADDR_0_REG),
+		REG(1, true,  LCDC_DMA_FB_BASE_ADDR_1_REG),
+		REG(1, true,  LCDC_DMA_FB_CEILING_ADDR_1_REG),
+		/* new in revision 2: */
+		REG(2, false, LCDC_RAW_STAT_REG),
+		REG(2, false, LCDC_MASKED_STAT_REG),
+		REG(2, true, LCDC_INT_ENABLE_SET_REG),
+		REG(2, false, LCDC_INT_ENABLE_CLR_REG),
+		REG(2, false, LCDC_END_OF_INT_IND_REG),
+		REG(2, true,  LCDC_CLK_ENABLE_REG),
+#undef REG
+};
+
+static int tilcdc_regs_show(struct seq_file *m, void *arg)
 {
+	struct drm_info_node *node = (struct drm_info_node *) m->private;
+	struct drm_device *dev = node->minor->dev;
 	struct tilcdc_drm_private *priv = dev->dev_private;
+	unsigned i;
 
-#ifdef CONFIG_CPU_FREQ
-	if (priv->freq_transition.notifier_call)
-		cpufreq_unregister_notifier(&priv->freq_transition,
-					    CPUFREQ_TRANSITION_NOTIFIER);
+	pm_runtime_get_sync(dev->dev);
+
+	seq_printf(m, "revision: %d\n", priv->rev);
+
+	for (i = 0; i < ARRAY_SIZE(registers); i++)
+		if (priv->rev >= registers[i].rev)
+			seq_printf(m, "%s:\t %08x\n", registers[i].name,
+					tilcdc_read(dev, registers[i].reg));
+
+	pm_runtime_put_sync(dev->dev);
+
+	return 0;
+}
+
+static int tilcdc_mm_show(struct seq_file *m, void *arg)
+{
+	struct drm_info_node *node = (struct drm_info_node *) m->private;
+	struct drm_device *dev = node->minor->dev;
+	struct drm_printer p = drm_seq_file_printer(m);
+	drm_mm_print(&dev->vma_offset_manager->vm_addr_space_mm, &p);
+	return 0;
+}
+
+static struct drm_info_list tilcdc_debugfs_list[] = {
+		{ "regs", tilcdc_regs_show, 0, NULL },
+		{ "mm",   tilcdc_mm_show,   0, NULL },
+};
+
+static void tilcdc_debugfs_init(struct drm_minor *minor)
+{
+	drm_debugfs_create_files(tilcdc_debugfs_list,
+				 ARRAY_SIZE(tilcdc_debugfs_list),
+				 minor->debugfs_root, minor);
+}
 #endif
 
-	if (priv->crtc)
-		tilcdc_crtc_shutdown(priv->crtc);
+DEFINE_DRM_GEM_DMA_FOPS(fops);
 
-	drm_dev_unregister(dev);
+static const struct drm_driver tilcdc_driver = {
+	.driver_features    = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
+	DRM_GEM_DMA_DRIVER_OPS,
+	DRM_FBDEV_DMA_DRIVER_OPS,
+#ifdef CONFIG_DEBUG_FS
+	.debugfs_init       = tilcdc_debugfs_init,
+#endif
+	.fops               = &fops,
+	.name               = "tilcdc",
+	.desc               = "TI LCD Controller DRM",
+	.major              = 1,
+	.minor              = 0,
+};
 
-	drm_kms_helper_poll_fini(dev);
-	drm_atomic_helper_shutdown(dev);
-	tilcdc_irq_uninstall(dev);
-	drm_mode_config_cleanup(dev);
+/*
+ * Power management:
+ */
 
-	if (priv->clk)
-		clk_put(priv->clk);
+static int tilcdc_pm_suspend(struct device *dev)
+{
+	struct drm_device *ddev = dev_get_drvdata(dev);
+	int ret = 0;
 
-	if (priv->wq)
-		destroy_workqueue(priv->wq);
+	ret = drm_mode_config_helper_suspend(ddev);
+
+	/* Select sleep pin state */
+	pinctrl_pm_select_sleep_state(dev);
 
-	dev->dev_private = NULL;
+	return ret;
+}
 
-	pm_runtime_disable(dev->dev);
+static int tilcdc_pm_resume(struct device *dev)
+{
+	struct drm_device *ddev = dev_get_drvdata(dev);
 
-	drm_dev_put(dev);
+	/* Select default pin state */
+	pinctrl_pm_select_default_state(dev);
+	return  drm_mode_config_helper_resume(ddev);
 }
 
+static DEFINE_SIMPLE_DEV_PM_OPS(tilcdc_pm_ops,
+				tilcdc_pm_suspend, tilcdc_pm_resume);
+
 static const struct of_device_id tilcdc_of_match[] = {
 		{ .compatible = "ti,am33xx-tilcdc", .data = (void *)AM33XX_TILCDC},
 		{ .compatible = "ti,da850-tilcdc", .data = (void *)DA850_TILCDC},
@@ -179,37 +265,35 @@ static const struct of_device_id tilcdc_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, tilcdc_of_match);
 
-static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev)
+static int tilcdc_pdev_probe(struct platform_device *pdev)
 {
-	struct drm_device *ddev;
-	struct platform_device *pdev = to_platform_device(dev);
-	struct device_node *node = dev->of_node;
+	struct device_node *node = pdev->dev.of_node;
 	const struct of_device_id *of_id;
 	struct tilcdc_drm_private *priv;
+	struct device *dev = &pdev->dev;
+	struct drm_device *ddev;
 	u32 bpp = 0;
 	int ret;
 
-	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
-	ddev = drm_dev_alloc(ddrv, dev);
-	if (IS_ERR(ddev))
-		return PTR_ERR(ddev);
+	priv = devm_drm_dev_alloc(dev, &tilcdc_driver,
+				  struct tilcdc_drm_private, ddev);
+	if (IS_ERR(priv))
+		return PTR_ERR(priv);
 
 	of_id = of_match_node(tilcdc_of_match, node);
 	if (!of_id)
 		return -ENODEV;
 
+	platform_set_drvdata(pdev, priv);
+	ddev = &priv->ddev;
 	ddev->dev_private = priv;
-	platform_set_drvdata(pdev, ddev);
-	drm_mode_config_init(ddev);
+	ret = drmm_mode_config_init(ddev);
+	if (ret)
+		return ret;
 
 	priv->wq = alloc_ordered_workqueue("tilcdc", 0);
-	if (!priv->wq) {
-		ret = -ENOMEM;
-		goto put_drm;
-	}
+	if (!priv->wq)
+		return -ENOMEM;
 
 	priv->mmio = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(priv->mmio)) {
@@ -375,152 +459,34 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev)
 	clk_put(priv->clk);
 free_wq:
 	destroy_workqueue(priv->wq);
-put_drm:
-	platform_set_drvdata(pdev, NULL);
-	ddev->dev_private = NULL;
-	drm_dev_put(ddev);
 
 	return ret;
 }
 
-#if defined(CONFIG_DEBUG_FS)
-static const struct {
-	const char *name;
-	uint8_t  rev;
-	uint8_t  save;
-	uint32_t reg;
-} registers[] =		{
-#define REG(rev, save, reg) { #reg, rev, save, reg }
-		/* exists in revision 1: */
-		REG(1, false, LCDC_PID_REG),
-		REG(1, true,  LCDC_CTRL_REG),
-		REG(1, false, LCDC_STAT_REG),
-		REG(1, true,  LCDC_RASTER_CTRL_REG),
-		REG(1, true,  LCDC_RASTER_TIMING_0_REG),
-		REG(1, true,  LCDC_RASTER_TIMING_1_REG),
-		REG(1, true,  LCDC_RASTER_TIMING_2_REG),
-		REG(1, true,  LCDC_DMA_CTRL_REG),
-		REG(1, true,  LCDC_DMA_FB_BASE_ADDR_0_REG),
-		REG(1, true,  LCDC_DMA_FB_CEILING_ADDR_0_REG),
-		REG(1, true,  LCDC_DMA_FB_BASE_ADDR_1_REG),
-		REG(1, true,  LCDC_DMA_FB_CEILING_ADDR_1_REG),
-		/* new in revision 2: */
-		REG(2, false, LCDC_RAW_STAT_REG),
-		REG(2, false, LCDC_MASKED_STAT_REG),
-		REG(2, true, LCDC_INT_ENABLE_SET_REG),
-		REG(2, false, LCDC_INT_ENABLE_CLR_REG),
-		REG(2, false, LCDC_END_OF_INT_IND_REG),
-		REG(2, true,  LCDC_CLK_ENABLE_REG),
-#undef REG
-};
-
-static int tilcdc_regs_show(struct seq_file *m, void *arg)
-{
-	struct drm_info_node *node = (struct drm_info_node *) m->private;
-	struct drm_device *dev = node->minor->dev;
-	struct tilcdc_drm_private *priv = dev->dev_private;
-	unsigned i;
-
-	pm_runtime_get_sync(dev->dev);
-
-	seq_printf(m, "revision: %d\n", priv->rev);
-
-	for (i = 0; i < ARRAY_SIZE(registers); i++)
-		if (priv->rev >= registers[i].rev)
-			seq_printf(m, "%s:\t %08x\n", registers[i].name,
-					tilcdc_read(dev, registers[i].reg));
-
-	pm_runtime_put_sync(dev->dev);
-
-	return 0;
-}
-
-static int tilcdc_mm_show(struct seq_file *m, void *arg)
-{
-	struct drm_info_node *node = (struct drm_info_node *) m->private;
-	struct drm_device *dev = node->minor->dev;
-	struct drm_printer p = drm_seq_file_printer(m);
-	drm_mm_print(&dev->vma_offset_manager->vm_addr_space_mm, &p);
-	return 0;
-}
-
-static struct drm_info_list tilcdc_debugfs_list[] = {
-		{ "regs", tilcdc_regs_show, 0, NULL },
-		{ "mm",   tilcdc_mm_show,   0, NULL },
-};
-
-static void tilcdc_debugfs_init(struct drm_minor *minor)
+static void tilcdc_pdev_remove(struct platform_device *pdev)
 {
-	drm_debugfs_create_files(tilcdc_debugfs_list,
-				 ARRAY_SIZE(tilcdc_debugfs_list),
-				 minor->debugfs_root, minor);
-}
-#endif
-
-DEFINE_DRM_GEM_DMA_FOPS(fops);
+	struct tilcdc_drm_private *priv = platform_get_drvdata(pdev);
+	struct drm_device *ddev = &priv->ddev;
 
-static const struct drm_driver tilcdc_driver = {
-	.driver_features    = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
-	DRM_GEM_DMA_DRIVER_OPS,
-	DRM_FBDEV_DMA_DRIVER_OPS,
-#ifdef CONFIG_DEBUG_FS
-	.debugfs_init       = tilcdc_debugfs_init,
+	drm_dev_unregister(ddev);
+	drm_kms_helper_poll_fini(ddev);
+	tilcdc_irq_uninstall(ddev);
+#ifdef CONFIG_CPU_FREQ
+	cpufreq_unregister_notifier(&priv->freq_transition,
+				    CPUFREQ_TRANSITION_NOTIFIER);
 #endif
-	.fops               = &fops,
-	.name               = "tilcdc",
-	.desc               = "TI LCD Controller DRM",
-	.major              = 1,
-	.minor              = 0,
-};
-
-/*
- * Power management:
- */
-
-static int tilcdc_pm_suspend(struct device *dev)
-{
-	struct drm_device *ddev = dev_get_drvdata(dev);
-	int ret = 0;
-
-	ret = drm_mode_config_helper_suspend(ddev);
-
-	/* Select sleep pin state */
-	pinctrl_pm_select_sleep_state(dev);
-
-	return ret;
-}
-
-static int tilcdc_pm_resume(struct device *dev)
-{
-	struct drm_device *ddev = dev_get_drvdata(dev);
-
-	/* Select default pin state */
-	pinctrl_pm_select_default_state(dev);
-	return  drm_mode_config_helper_resume(ddev);
-}
-
-static DEFINE_SIMPLE_DEV_PM_OPS(tilcdc_pm_ops,
-				tilcdc_pm_suspend, tilcdc_pm_resume);
-
-static int tilcdc_pdev_probe(struct platform_device *pdev)
-{
-	/* bail out early if no DT data: */
-	if (!pdev->dev.of_node) {
-		dev_err(&pdev->dev, "device-tree data is missing\n");
-		return -ENXIO;
-	}
-
-	return tilcdc_init(&tilcdc_driver, &pdev->dev);
-}
-
-static void tilcdc_pdev_remove(struct platform_device *pdev)
-{
-	tilcdc_fini(platform_get_drvdata(pdev));
+	tilcdc_crtc_destroy(priv->crtc);
+	pm_runtime_disable(&pdev->dev);
+	clk_put(priv->clk);
+	destroy_workqueue(priv->wq);
 }
 
 static void tilcdc_pdev_shutdown(struct platform_device *pdev)
 {
-	drm_atomic_helper_shutdown(platform_get_drvdata(pdev));
+	struct tilcdc_drm_private *priv = platform_get_drvdata(pdev);
+	struct drm_device *ddev = &priv->ddev;
+
+	drm_atomic_helper_shutdown(ddev);
 }
 
 static struct platform_driver tilcdc_platform_driver = {
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
index 60e85e29b1063..e3d04a3eb25b4 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
@@ -48,6 +48,8 @@ struct tilcdc_drm_private {
 
 	unsigned int irq;
 
+	struct drm_device ddev;
+
 	/* don't attempt resolutions w/ higher W * H * Hz: */
 	uint32_t max_bandwidth;
 	/*

-- 
2.43.0



From kory.maincent at bootlin.com  Thu Dec 11 08:38:54 2025
From: kory.maincent at bootlin.com (Kory Maincent (TI.com))
Date: Thu, 11 Dec 2025 17:38:54 +0100
Subject: [PATCH v2 10/20] drm/tilcdc: Remove unused encoder and connector
 tracking arrays
In-Reply-To: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
Message-ID: <20251211-feature_tilcdc-v2-10-f48bac3cd33e@bootlin.com>

The num_encoders/encoders and num_connectors/connectors arrays in
tilcdc_drm_private are never populated or used by the driver.

Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
---
 drivers/gpu/drm/tilcdc/tilcdc_drv.c | 3 +--
 drivers/gpu/drm/tilcdc/tilcdc_drv.h | 6 ------
 2 files changed, 1 insertion(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index d2aae731b72c6..a753cc47a59d7 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -348,8 +348,7 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev)
 	if (ret)
 		goto unregister_cpufreq_notif;
 
-	if (!priv->external_connector &&
-	    ((priv->num_encoders == 0) || (priv->num_connectors == 0))) {
+	if (!priv->external_connector) {
 		dev_err(dev, "no encoders/connectors found\n");
 		ret = -EPROBE_DEFER;
 		goto unregister_cpufreq_notif;
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
index 181b9d7a515b6..717529a331009 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
@@ -75,12 +75,6 @@ struct tilcdc_drm_private {
 
 	struct drm_crtc *crtc;
 
-	unsigned int num_encoders;
-	struct drm_encoder *encoders[8];
-
-	unsigned int num_connectors;
-	struct drm_connector *connectors[8];
-
 	struct drm_encoder *external_encoder;
 	struct drm_connector *external_connector;
 

-- 
2.43.0



From kory.maincent at bootlin.com  Thu Dec 11 08:38:59 2025
From: kory.maincent at bootlin.com (Kory Maincent (TI.com))
Date: Thu, 11 Dec 2025 17:38:59 +0100
Subject: [PATCH v2 15/20] drm/tilcdc: Remove the use of drm_device
 private_data
In-Reply-To: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
Message-ID: <20251211-feature_tilcdc-v2-15-f48bac3cd33e@bootlin.com>

The DRM core documentation recommends against using dev_private:
"Instead of using this pointer it is recommended that drivers use
embed the struct &drm_device in their larger per-device structure."

This patch refactors the tilcdc driver to follow this recommendation
by embedding struct drm_device within struct tilcdc_drm_private and
replacing all dev->dev_private accesses with the ddev_to_tilcdc_priv()
helper macro that uses container_of().

This change aligns the driver with modern DRM best practices.

Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
---
 drivers/gpu/drm/tilcdc/tilcdc_crtc.c    | 28 ++++++++++++++--------------
 drivers/gpu/drm/tilcdc/tilcdc_drv.c     | 11 +++++------
 drivers/gpu/drm/tilcdc/tilcdc_drv.h     |  2 ++
 drivers/gpu/drm/tilcdc/tilcdc_encoder.c |  4 ++--
 drivers/gpu/drm/tilcdc/tilcdc_plane.c   |  2 +-
 drivers/gpu/drm/tilcdc/tilcdc_regs.h    |  8 ++++----
 6 files changed, 28 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index 5b8aba0765f9b..0bd99a2efeeb4 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -59,7 +59,7 @@ struct tilcdc_crtc {
 static void set_scanout(struct drm_crtc *crtc, struct drm_framebuffer *fb)
 {
 	struct drm_device *dev = crtc->dev;
-	struct tilcdc_drm_private *priv = dev->dev_private;
+	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(dev);
 	struct drm_gem_dma_object *gem;
 	dma_addr_t start, end;
 	u64 dma_base_and_ceiling;
@@ -94,7 +94,7 @@ static void tilcdc_crtc_load_palette(struct drm_crtc *crtc)
 {
 	struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
-	struct tilcdc_drm_private *priv = dev->dev_private;
+	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(dev);
 	int ret;
 
 	reinit_completion(&tilcdc_crtc->palette_loaded);
@@ -136,7 +136,7 @@ static void tilcdc_crtc_load_palette(struct drm_crtc *crtc)
 
 static void tilcdc_crtc_enable_irqs(struct drm_device *dev)
 {
-	struct tilcdc_drm_private *priv = dev->dev_private;
+	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(dev);
 
 	tilcdc_clear_irqstatus(dev, 0xffffffff);
 
@@ -153,7 +153,7 @@ static void tilcdc_crtc_enable_irqs(struct drm_device *dev)
 
 static void tilcdc_crtc_disable_irqs(struct drm_device *dev)
 {
-	struct tilcdc_drm_private *priv = dev->dev_private;
+	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(dev);
 
 	/* disable irqs that we might have enabled: */
 	if (priv->rev == 1) {
@@ -173,7 +173,7 @@ static void tilcdc_crtc_disable_irqs(struct drm_device *dev)
 static void reset(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
-	struct tilcdc_drm_private *priv = dev->dev_private;
+	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(dev);
 
 	if (priv->rev != 2)
 		return;
@@ -198,7 +198,7 @@ static unsigned int tilcdc_pclk_diff(unsigned long rate,
 static void tilcdc_crtc_set_clk(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
-	struct tilcdc_drm_private *priv = dev->dev_private;
+	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(dev);
 	struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
 	unsigned long clk_rate, real_pclk_rate, pclk_rate;
 	unsigned int clkdiv;
@@ -270,7 +270,7 @@ static void tilcdc_crtc_set_mode(struct drm_crtc *crtc)
 {
 	struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
-	struct tilcdc_drm_private *priv = dev->dev_private;
+	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(dev);
 	uint32_t reg, hbp, hfp, hsw, vbp, vfp, vsw;
 	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
 	struct drm_framebuffer *fb = crtc->primary->state->fb;
@@ -557,7 +557,7 @@ static void tilcdc_crtc_recover_work(struct work_struct *work)
 
 void tilcdc_crtc_destroy(struct drm_crtc *crtc)
 {
-	struct tilcdc_drm_private *priv = crtc->dev->dev_private;
+	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(crtc->dev);
 
 	tilcdc_crtc_shutdown(crtc);
 
@@ -647,7 +647,7 @@ static int tilcdc_crtc_enable_vblank(struct drm_crtc *crtc)
 {
 	struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
-	struct tilcdc_drm_private *priv = dev->dev_private;
+	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(dev);
 	unsigned long flags;
 
 	spin_lock_irqsave(&tilcdc_crtc->irq_lock, flags);
@@ -670,7 +670,7 @@ static void tilcdc_crtc_disable_vblank(struct drm_crtc *crtc)
 {
 	struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
-	struct tilcdc_drm_private *priv = dev->dev_private;
+	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(dev);
 	unsigned long flags;
 
 	spin_lock_irqsave(&tilcdc_crtc->irq_lock, flags);
@@ -728,7 +728,7 @@ static enum drm_mode_status
 tilcdc_crtc_mode_valid(struct drm_crtc *crtc,
 		       const struct drm_display_mode *mode)
 {
-	struct tilcdc_drm_private *priv = crtc->dev->dev_private;
+	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(crtc->dev);
 	unsigned int bandwidth;
 	uint32_t hbp, hfp, hsw, vbp, vfp, vsw;
 
@@ -826,7 +826,7 @@ static const struct drm_crtc_helper_funcs tilcdc_crtc_helper_funcs = {
 void tilcdc_crtc_update_clk(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
-	struct tilcdc_drm_private *priv = dev->dev_private;
+	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(dev);
 	struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
 
 	drm_modeset_lock(&crtc->mutex, NULL);
@@ -850,7 +850,7 @@ irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc)
 {
 	struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
-	struct tilcdc_drm_private *priv = dev->dev_private;
+	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(dev);
 	uint32_t stat, reg;
 
 	stat = tilcdc_read_irqstatus(dev);
@@ -958,7 +958,7 @@ irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc)
 
 int tilcdc_crtc_create(struct drm_device *dev)
 {
-	struct tilcdc_drm_private *priv = dev->dev_private;
+	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(dev);
 	struct tilcdc_crtc *tilcdc_crtc;
 	struct drm_crtc *crtc;
 	int ret;
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index 2cbe390a1ee54..89afd32b52baf 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -79,7 +79,7 @@ static const struct drm_mode_config_funcs mode_config_funcs = {
 
 static void modeset_init(struct drm_device *dev)
 {
-	struct tilcdc_drm_private *priv = dev->dev_private;
+	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(dev);
 
 	dev->mode_config.min_width = 0;
 	dev->mode_config.min_height = 0;
@@ -105,14 +105,14 @@ static int cpufreq_transition(struct notifier_block *nb,
 static irqreturn_t tilcdc_irq(int irq, void *arg)
 {
 	struct drm_device *dev = arg;
-	struct tilcdc_drm_private *priv = dev->dev_private;
+	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(dev);
 
 	return tilcdc_crtc_irq(priv->crtc);
 }
 
 static int tilcdc_irq_install(struct drm_device *dev, unsigned int irq)
 {
-	struct tilcdc_drm_private *priv = dev->dev_private;
+	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(dev);
 	int ret;
 
 	ret = request_irq(irq, tilcdc_irq, 0, dev->driver->name, dev);
@@ -126,7 +126,7 @@ static int tilcdc_irq_install(struct drm_device *dev, unsigned int irq)
 
 static void tilcdc_irq_uninstall(struct drm_device *dev)
 {
-	struct tilcdc_drm_private *priv = dev->dev_private;
+	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(dev);
 
 	if (!priv->irq_enabled)
 		return;
@@ -174,7 +174,7 @@ static int tilcdc_regs_show(struct seq_file *m, void *arg)
 {
 	struct drm_info_node *node = (struct drm_info_node *) m->private;
 	struct drm_device *dev = node->minor->dev;
-	struct tilcdc_drm_private *priv = dev->dev_private;
+	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(dev);
 	unsigned i;
 
 	pm_runtime_get_sync(dev->dev);
@@ -286,7 +286,6 @@ static int tilcdc_pdev_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, priv);
 	ddev = &priv->ddev;
-	ddev->dev_private = priv;
 	ret = drmm_mode_config_init(ddev);
 	if (ret)
 		return ret;
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
index e3d04a3eb25b4..c69e279a2539d 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
@@ -85,6 +85,8 @@ struct tilcdc_drm_private {
 
 #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
 
+#define ddev_to_tilcdc_priv(x) container_of(x, struct tilcdc_drm_private, ddev)
+
 int tilcdc_crtc_create(struct drm_device *dev);
 irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc);
 void tilcdc_crtc_update_clk(struct drm_crtc *crtc);
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_encoder.c b/drivers/gpu/drm/tilcdc/tilcdc_encoder.c
index bca91226351dd..d01e7a31a286c 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_encoder.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_encoder.c
@@ -34,7 +34,7 @@ struct drm_connector *tilcdc_encoder_find_connector(struct drm_device *ddev,
 static
 int tilcdc_attach_bridge(struct drm_device *ddev, struct drm_bridge *bridge)
 {
-	struct tilcdc_drm_private *priv = ddev->dev_private;
+	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(ddev);
 	int ret;
 
 	priv->encoder->possible_crtcs = BIT(0);
@@ -53,7 +53,7 @@ int tilcdc_attach_bridge(struct drm_device *ddev, struct drm_bridge *bridge)
 
 int tilcdc_encoder_create(struct drm_device *ddev)
 {
-	struct tilcdc_drm_private *priv = ddev->dev_private;
+	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(ddev);
 	struct drm_bridge *bridge;
 	struct drm_panel *panel;
 	int ret;
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_plane.c b/drivers/gpu/drm/tilcdc/tilcdc_plane.c
index aa72ca679598b..a77a5b22ebd96 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_plane.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_plane.c
@@ -101,7 +101,7 @@ static const struct drm_plane_helper_funcs plane_helper_funcs = {
 int tilcdc_plane_init(struct drm_device *dev,
 		      struct drm_plane *plane)
 {
-	struct tilcdc_drm_private *priv = dev->dev_private;
+	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(dev);
 	int ret;
 
 	ret = drm_universal_plane_init(dev, plane, 1, &tilcdc_plane_funcs,
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_regs.h b/drivers/gpu/drm/tilcdc/tilcdc_regs.h
index f90e2dc3457cd..26ebaf1e0f70f 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_regs.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_regs.h
@@ -113,13 +113,13 @@
 
 static inline void tilcdc_write(struct drm_device *dev, u32 reg, u32 data)
 {
-	struct tilcdc_drm_private *priv = dev->dev_private;
+	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(dev);
 	iowrite32(data, priv->mmio + reg);
 }
 
 static inline void tilcdc_write64(struct drm_device *dev, u32 reg, u64 data)
 {
-	struct tilcdc_drm_private *priv = dev->dev_private;
+	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(dev);
 	volatile void __iomem *addr = priv->mmio + reg;
 
 #if defined(iowrite64) && !defined(iowrite64_is_nonatomic)
@@ -133,7 +133,7 @@ static inline void tilcdc_write64(struct drm_device *dev, u32 reg, u64 data)
 
 static inline u32 tilcdc_read(struct drm_device *dev, u32 reg)
 {
-	struct tilcdc_drm_private *priv = dev->dev_private;
+	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(dev);
 	return ioread32(priv->mmio + reg);
 }
 
@@ -156,7 +156,7 @@ static inline void tilcdc_clear(struct drm_device *dev, u32 reg, u32 mask)
 /* the register to read/clear irqstatus differs between v1 and v2 of the IP */
 static inline u32 tilcdc_irqstatus_reg(struct drm_device *dev)
 {
-	struct tilcdc_drm_private *priv = dev->dev_private;
+	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(dev);
 	return (priv->rev == 2) ? LCDC_MASKED_STAT_REG : LCDC_STAT_REG;
 }
 

-- 
2.43.0



From kory.maincent at bootlin.com  Thu Dec 11 08:39:00 2025
From: kory.maincent at bootlin.com (Kory Maincent (TI.com))
Date: Thu, 11 Dec 2025 17:39:00 +0100
Subject: [PATCH v2 16/20] drm/bridge: tda998x: Remove component support
In-Reply-To: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
Message-ID: <20251211-feature_tilcdc-v2-16-f48bac3cd33e@bootlin.com>

The tilcdc driver no longer uses the component framework to bind the
tda998x bridge driver. The component bind/unbind operations and the
encoder initialization code are now dead code and can be safely removed.

Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
---
 drivers/gpu/drm/bridge/tda998x_drv.c | 69 +-----------------------------------
 1 file changed, 1 insertion(+), 68 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tda998x_drv.c b/drivers/gpu/drm/bridge/tda998x_drv.c
index e636459d91857..865285ba2bd8c 100644
--- a/drivers/gpu/drm/bridge/tda998x_drv.c
+++ b/drivers/gpu/drm/bridge/tda998x_drv.c
@@ -4,7 +4,6 @@
  * Author: Rob Clark <robdclark at gmail.com>
  */
 
-#include <linux/component.h>
 #include <linux/gpio/consumer.h>
 #include <linux/hdmi.h>
 #include <linux/i2c.h>
@@ -1963,85 +1962,19 @@ static int tda998x_create(struct device *dev)
 	return ret;
 }
 
-/* DRM encoder functions */
-
-static int tda998x_encoder_init(struct device *dev, struct drm_device *drm)
-{
-	struct tda998x_priv *priv = dev_get_drvdata(dev);
-	u32 crtcs = 0;
-	int ret;
-
-	if (dev->of_node)
-		crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
-
-	/* If no CRTCs were found, fall back to our old behaviour */
-	if (crtcs == 0) {
-		dev_warn(dev, "Falling back to first CRTC\n");
-		crtcs = 1 << 0;
-	}
-
-	priv->encoder.possible_crtcs = crtcs;
-
-	ret = drm_simple_encoder_init(drm, &priv->encoder,
-				      DRM_MODE_ENCODER_TMDS);
-	if (ret)
-		goto err_encoder;
-
-	ret = drm_bridge_attach(&priv->encoder, &priv->bridge, NULL, 0);
-	if (ret)
-		goto err_bridge;
-
-	return 0;
-
-err_bridge:
-	drm_encoder_cleanup(&priv->encoder);
-err_encoder:
-	return ret;
-}
-
-static int tda998x_bind(struct device *dev, struct device *master, void *data)
-{
-	struct drm_device *drm = data;
-
-	return tda998x_encoder_init(dev, drm);
-}
-
-static void tda998x_unbind(struct device *dev, struct device *master,
-			   void *data)
-{
-	struct tda998x_priv *priv = dev_get_drvdata(dev);
-
-	drm_encoder_cleanup(&priv->encoder);
-}
-
-static const struct component_ops tda998x_ops = {
-	.bind = tda998x_bind,
-	.unbind = tda998x_unbind,
-};
-
 static int
 tda998x_probe(struct i2c_client *client)
 {
-	int ret;
-
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
 		dev_warn(&client->dev, "adapter does not support I2C\n");
 		return -EIO;
 	}
 
-	ret = tda998x_create(&client->dev);
-	if (ret)
-		return ret;
-
-	ret = component_add(&client->dev, &tda998x_ops);
-	if (ret)
-		tda998x_destroy(&client->dev);
-	return ret;
+	return tda998x_create(&client->dev);
 }
 
 static void tda998x_remove(struct i2c_client *client)
 {
-	component_del(&client->dev, &tda998x_ops);
 	tda998x_destroy(&client->dev);
 }
 

-- 
2.43.0



From kory.maincent at bootlin.com  Thu Dec 11 08:39:01 2025
From: kory.maincent at bootlin.com (Kory Maincent (TI.com))
Date: Thu, 11 Dec 2025 17:39:01 +0100
Subject: [PATCH v2 17/20] drm/bridge: tda998x: Move tda998x_create/destroy
 into probe and remove
In-Reply-To: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
Message-ID: <20251211-feature_tilcdc-v2-17-f48bac3cd33e@bootlin.com>

Now that tda998x_create and tda998x_destroy are called only in the probe
function, there is no need for separate functions.
Move the code into the tda998x_probe and tda998x_remove functions.
Rewrite the cleanup path using goto calls in probe and reorder it in the
remove function.

Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
---
 drivers/gpu/drm/bridge/tda998x_drv.c | 99 +++++++++++++++++++-----------------
 1 file changed, 51 insertions(+), 48 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tda998x_drv.c b/drivers/gpu/drm/bridge/tda998x_drv.c
index 865285ba2bd8c..4be49dd5bfc01 100644
--- a/drivers/gpu/drm/bridge/tda998x_drv.c
+++ b/drivers/gpu/drm/bridge/tda998x_drv.c
@@ -1748,38 +1748,20 @@ static int tda998x_get_audio_ports(struct tda998x_priv *priv,
 	return 0;
 }
 
-static void tda998x_destroy(struct device *dev)
-{
-	struct tda998x_priv *priv = dev_get_drvdata(dev);
-
-	drm_bridge_remove(&priv->bridge);
-
-	/* disable all IRQs and free the IRQ handler */
-	cec_write(priv, REG_CEC_RXSHPDINTENA, 0);
-	reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
-
-	if (priv->audio_pdev)
-		platform_device_unregister(priv->audio_pdev);
-
-	if (priv->hdmi->irq)
-		free_irq(priv->hdmi->irq, priv);
-
-	timer_delete_sync(&priv->edid_delay_timer);
-	cancel_work_sync(&priv->detect_work);
-
-	i2c_unregister_device(priv->cec);
-
-	cec_notifier_conn_unregister(priv->cec_notify);
-}
-
-static int tda998x_create(struct device *dev)
+static int
+tda998x_probe(struct i2c_client *client)
 {
-	struct i2c_client *client = to_i2c_client(dev);
 	struct device_node *np = client->dev.of_node;
+	struct device *dev = &client->dev;
 	struct i2c_board_info cec_info;
 	struct tda998x_priv *priv;
-	u32 video;
 	int rev_lo, rev_hi, ret;
+	u32 video;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_warn(&client->dev, "adapter does not support I2C\n");
+		return -EIO;
+	}
 
 	priv = devm_drm_bridge_alloc(dev, struct tda998x_priv, bridge, &tda998x_bridge_funcs);
 	if (IS_ERR(priv))
@@ -1814,13 +1796,15 @@ static int tda998x_create(struct device *dev)
 	rev_lo = reg_read(priv, REG_VERSION_LSB);
 	if (rev_lo < 0) {
 		dev_err(dev, "failed to read version: %d\n", rev_lo);
-		return rev_lo;
+		ret = rev_lo;
+		goto cancel_work;
 	}
 
 	rev_hi = reg_read(priv, REG_VERSION_MSB);
 	if (rev_hi < 0) {
 		dev_err(dev, "failed to read version: %d\n", rev_hi);
-		return rev_hi;
+		ret = rev_hi;
+		goto cancel_work;
 	}
 
 	priv->rev = rev_lo | rev_hi << 8;
@@ -1843,7 +1827,8 @@ static int tda998x_create(struct device *dev)
 		break;
 	default:
 		dev_err(dev, "found unsupported device: %04x\n", priv->rev);
-		return -ENXIO;
+		ret = -ENXIO;
+		goto cancel_work;
 	}
 
 	/* after reset, enable DDC: */
@@ -1887,7 +1872,7 @@ static int tda998x_create(struct device *dev)
 		if (ret) {
 			dev_err(dev, "failed to request IRQ#%u: %d\n",
 				client->irq, ret);
-			goto err_irq;
+			goto cancel_work;
 		}
 
 		/* enable HPD irq */
@@ -1897,7 +1882,7 @@ static int tda998x_create(struct device *dev)
 	priv->cec_notify = cec_notifier_conn_register(dev, NULL, NULL);
 	if (!priv->cec_notify) {
 		ret = -ENOMEM;
-		goto fail;
+		goto free_irq;
 	}
 
 	priv->cec_glue.parent = dev;
@@ -1924,7 +1909,7 @@ static int tda998x_create(struct device *dev)
 	priv->cec = i2c_new_client_device(client->adapter, &cec_info);
 	if (IS_ERR(priv->cec)) {
 		ret = PTR_ERR(priv->cec);
-		goto fail;
+		goto notifier_conn_unregister;
 	}
 
 	/* enable EDID read irq: */
@@ -1941,7 +1926,7 @@ static int tda998x_create(struct device *dev)
 
 		ret = tda998x_get_audio_ports(priv, np);
 		if (ret)
-			goto fail;
+			goto unregister_dev;
 
 		if (priv->audio_port_enable[AUDIO_ROUTE_I2S] ||
 		    priv->audio_port_enable[AUDIO_ROUTE_SPDIF])
@@ -1956,26 +1941,44 @@ static int tda998x_create(struct device *dev)
 
 	return 0;
 
-fail:
-	tda998x_destroy(dev);
-err_irq:
+unregister_dev:
+	i2c_unregister_device(priv->cec);
+notifier_conn_unregister:
+	cec_notifier_conn_unregister(priv->cec_notify);
+free_irq:
+	if (client->irq) {
+		free_irq(client->irq, priv);
+		cec_write(priv, REG_CEC_RXSHPDINTENA, 0);
+		reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
+	}
+cancel_work:
+	timer_delete_sync(&priv->edid_delay_timer);
+	cancel_work_sync(&priv->detect_work);
 	return ret;
 }
 
-static int
-tda998x_probe(struct i2c_client *client)
+static void tda998x_remove(struct i2c_client *client)
 {
-	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
-		dev_warn(&client->dev, "adapter does not support I2C\n");
-		return -EIO;
-	}
+	struct tda998x_priv *priv = dev_get_drvdata(&client->dev);
 
-	return tda998x_create(&client->dev);
-}
+	drm_bridge_remove(&priv->bridge);
 
-static void tda998x_remove(struct i2c_client *client)
-{
-	tda998x_destroy(&client->dev);
+	if (priv->audio_pdev)
+		platform_device_unregister(priv->audio_pdev);
+
+	i2c_unregister_device(priv->cec);
+
+	cec_notifier_conn_unregister(priv->cec_notify);
+
+	/* disable all IRQs and free the IRQ handler */
+	if (client->irq) {
+		cec_write(priv, REG_CEC_RXSHPDINTENA, 0);
+		reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
+		free_irq(priv->hdmi->irq, priv);
+	}
+
+	timer_delete_sync(&priv->edid_delay_timer);
+	cancel_work_sync(&priv->detect_work);
 }
 
 #ifdef CONFIG_OF

-- 
2.43.0



From kory.maincent at bootlin.com  Thu Dec 11 08:39:02 2025
From: kory.maincent at bootlin.com (Kory Maincent (TI.com))
Date: Thu, 11 Dec 2025 17:39:02 +0100
Subject: [PATCH v2 18/20] drm/bridge: tda998x: Remove useless
 tda998x_connector_destroy wrapper
In-Reply-To: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
Message-ID: <20251211-feature_tilcdc-v2-18-f48bac3cd33e@bootlin.com>

Use directly drm_connector_cleanup in the destroy ops instead of having
a custom function that does nothing more.

Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
---
 drivers/gpu/drm/bridge/tda998x_drv.c | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tda998x_drv.c b/drivers/gpu/drm/bridge/tda998x_drv.c
index 4be49dd5bfc01..43ace6ee2ca35 100644
--- a/drivers/gpu/drm/bridge/tda998x_drv.c
+++ b/drivers/gpu/drm/bridge/tda998x_drv.c
@@ -1203,16 +1203,11 @@ tda998x_connector_detect(struct drm_connector *connector, bool force)
 			connector_status_disconnected;
 }
 
-static void tda998x_connector_destroy(struct drm_connector *connector)
-{
-	drm_connector_cleanup(connector);
-}
-
 static const struct drm_connector_funcs tda998x_connector_funcs = {
 	.reset = drm_atomic_helper_connector_reset,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.detect = tda998x_connector_detect,
-	.destroy = tda998x_connector_destroy,
+	.destroy = drm_connector_cleanup,
 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };

-- 
2.43.0



From kory.maincent at bootlin.com  Thu Dec 11 08:39:03 2025
From: kory.maincent at bootlin.com (Kory Maincent (TI.com))
Date: Thu, 11 Dec 2025 17:39:03 +0100
Subject: [PATCH v2 19/20] drm/bridge: tda998x: Add support for
 DRM_BRIDGE_ATTACH_NO_CONNECTOR
In-Reply-To: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
Message-ID: <20251211-feature_tilcdc-v2-19-f48bac3cd33e@bootlin.com>

Add support for the DRM_BRIDGE_ATTACH_NO_CONNECTOR flag to allow display
controller drivers to create their own connectors. This modernizes the
driver to work with the current DRM bridge framework.

The implementation includes:
- Refactoring detection and EDID reading into bridge-usable helpers
- Adding bridge operations: edid_read, detect, hpd_enable, hpd_disable
- Setting appropriate bridge ops (DRM_BRIDGE_OP_EDID, DRM_BRIDGE_OP_DETECT,
  DRM_BRIDGE_OP_HPD) and connector type (HDMIA)
- Skipping connector creation when DRM_BRIDGE_ATTACH_NO_CONNECTOR is set
- Handling conditional connector cleanup in bridge_detach

The driver maintains backward compatibility by continuing to create its
own connector when the flag is not set.

Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
---
 drivers/gpu/drm/bridge/tda998x_drv.c | 96 +++++++++++++++++++++++++++++++-----
 1 file changed, 85 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tda998x_drv.c b/drivers/gpu/drm/bridge/tda998x_drv.c
index 43ace6ee2ca35..4d78615634691 100644
--- a/drivers/gpu/drm/bridge/tda998x_drv.c
+++ b/drivers/gpu/drm/bridge/tda998x_drv.c
@@ -1193,16 +1193,22 @@ static int tda998x_audio_codec_init(struct tda998x_priv *priv,
 
 /* DRM connector functions */
 
-static enum drm_connector_status
-tda998x_connector_detect(struct drm_connector *connector, bool force)
+static enum drm_connector_status tda998x_conn_detect(struct tda998x_priv *priv)
 {
-	struct tda998x_priv *priv = conn_to_tda998x_priv(connector);
 	u8 val = cec_read(priv, REG_CEC_RXSHPDLEV);
 
 	return (val & CEC_RXSHPDLEV_HPD) ? connector_status_connected :
 			connector_status_disconnected;
 }
 
+static enum drm_connector_status
+tda998x_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct tda998x_priv *priv = conn_to_tda998x_priv(connector);
+
+	return tda998x_conn_detect(priv);
+}
+
 static const struct drm_connector_funcs tda998x_connector_funcs = {
 	.reset = drm_atomic_helper_connector_reset,
 	.fill_modes = drm_helper_probe_single_connector_modes,
@@ -1276,11 +1282,10 @@ static int read_edid_block(void *data, u8 *buf, unsigned int blk, size_t length)
 	return ret;
 }
 
-static int tda998x_connector_get_modes(struct drm_connector *connector)
+static const struct drm_edid *tda998x_edid_read(struct tda998x_priv *priv,
+						struct drm_connector *connector)
 {
-	struct tda998x_priv *priv = conn_to_tda998x_priv(connector);
 	const struct drm_edid *drm_edid;
-	int n;
 
 	/*
 	 * If we get killed while waiting for the HPD timeout, return
@@ -1298,6 +1303,16 @@ static int tda998x_connector_get_modes(struct drm_connector *connector)
 	if (priv->rev == TDA19988)
 		reg_set(priv, REG_TX4, TX4_PD_RAM);
 
+	return drm_edid;
+}
+
+static int tda998x_connector_get_modes(struct drm_connector *connector)
+{
+	struct tda998x_priv *priv = conn_to_tda998x_priv(connector);
+	const struct drm_edid *drm_edid;
+	int n;
+
+	drm_edid = tda998x_edid_read(priv, connector);
 	drm_edid_connector_update(connector, drm_edid);
 	cec_notifier_set_phys_addr(priv->cec_notify,
 				   connector->display_info.source_physical_address);
@@ -1365,10 +1380,8 @@ static int tda998x_bridge_attach(struct drm_bridge *bridge,
 {
 	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
 
-	if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
-		DRM_ERROR("Fix bridge driver to make connector optional!");
-		return -EINVAL;
-	}
+	if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
+		return 0;
 
 	return tda998x_connector_init(priv, bridge->dev);
 }
@@ -1377,7 +1390,8 @@ static void tda998x_bridge_detach(struct drm_bridge *bridge)
 {
 	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
 
-	drm_connector_cleanup(&priv->connector);
+	if (priv->connector.dev)
+		drm_connector_cleanup(&priv->connector);
 }
 
 static enum drm_mode_status tda998x_bridge_mode_valid(struct drm_bridge *bridge,
@@ -1677,6 +1691,59 @@ static void tda998x_bridge_mode_set(struct drm_bridge *bridge,
 	mutex_unlock(&priv->audio_mutex);
 }
 
+static const struct drm_edid *
+tda998x_bridge_edid_read(struct drm_bridge *bridge,
+			 struct drm_connector *connector)
+{
+	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
+	const struct drm_edid *drm_edid;
+	const struct edid *edid;
+
+	drm_edid = tda998x_edid_read(priv, connector);
+	if (!drm_edid) {
+		dev_dbg(&priv->hdmi->dev, "failed to get edid\n");
+		return NULL;
+	}
+
+	/*
+	 * FIXME: This should use connector->display_info.has_audio from
+	 * a path that has read the EDID and called
+	 * drm_edid_connector_update().
+	 */
+	edid = drm_edid_raw(drm_edid);
+
+	dev_dbg(&priv->hdmi->dev, "got edid: width[%d] x height[%d]\n",
+		edid->width_cm, edid->height_cm);
+
+	priv->sink_has_audio = drm_detect_monitor_audio(edid);
+	cec_notifier_set_phys_addr_from_edid(priv->cec_notify, edid);
+
+	return drm_edid;
+}
+
+static enum drm_connector_status
+tda998x_bridge_detect(struct drm_bridge *bridge,
+		      struct drm_connector *connector)
+{
+	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
+
+	return tda998x_conn_detect(priv);
+}
+
+static void tda998x_bridge_hpd_enable(struct drm_bridge *bridge)
+{
+	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
+
+	cec_write(priv, REG_CEC_RXSHPDINTENA, CEC_RXSHPDLEV_HPD);
+}
+
+static void tda998x_bridge_hpd_disable(struct drm_bridge *bridge)
+{
+	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
+
+	cec_write(priv, REG_CEC_RXSHPDINTENA, 0);
+}
+
 static const struct drm_bridge_funcs tda998x_bridge_funcs = {
 	.attach = tda998x_bridge_attach,
 	.detach = tda998x_bridge_detach,
@@ -1684,6 +1751,10 @@ static const struct drm_bridge_funcs tda998x_bridge_funcs = {
 	.disable = tda998x_bridge_disable,
 	.mode_set = tda998x_bridge_mode_set,
 	.enable = tda998x_bridge_enable,
+	.edid_read = tda998x_bridge_edid_read,
+	.detect = tda998x_bridge_detect,
+	.hpd_enable = tda998x_bridge_hpd_enable,
+	.hpd_disable = tda998x_bridge_hpd_disable,
 };
 
 /* I2C driver functions */
@@ -1872,6 +1943,7 @@ tda998x_probe(struct i2c_client *client)
 
 		/* enable HPD irq */
 		cec_write(priv, REG_CEC_RXSHPDINTENA, CEC_RXSHPDLEV_HPD);
+		priv->bridge.ops = DRM_BRIDGE_OP_HPD;
 	}
 
 	priv->cec_notify = cec_notifier_conn_register(dev, NULL, NULL);
@@ -1932,6 +2004,8 @@ tda998x_probe(struct i2c_client *client)
 	priv->bridge.of_node = dev->of_node;
 #endif
 
+	priv->bridge.ops |= DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT;
+	priv->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
 	drm_bridge_add(&priv->bridge);
 
 	return 0;

-- 
2.43.0



From kory.maincent at bootlin.com  Thu Dec 11 08:39:04 2025
From: kory.maincent at bootlin.com (Kory Maincent (TI.com))
Date: Thu, 11 Dec 2025 17:39:04 +0100
Subject: [PATCH v2 20/20] drm/tilcdc: Add support for
 DRM_BRIDGE_ATTACH_NO_CONNECTOR
In-Reply-To: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
Message-ID: <20251211-feature_tilcdc-v2-20-f48bac3cd33e@bootlin.com>

Convert the driver to use the DRM_BRIDGE_ATTACH_NO_CONNECTOR flag when
attaching bridges. This modernizes the driver by delegating connector
creation to the bridge subsystem through drm_bridge_connector_init()
instead of manually searching for connectors created by the bridge.

The custom tilcdc_encoder_find_connector() function is removed and
replaced with the standard drm_bridge_connector infrastructure, which
simplifies the code and aligns with current DRM bridge best practices.

This change is safe as there are now no in-tree devicetrees that
connect tilcdc to bridges which do not support the
DRM_BRIDGE_ATTACH_NO_CONNECTOR flag.

Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
---
 drivers/gpu/drm/tilcdc/tilcdc_encoder.c | 38 ++++++++++++++-------------------
 1 file changed, 16 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/tilcdc/tilcdc_encoder.c b/drivers/gpu/drm/tilcdc/tilcdc_encoder.c
index d01e7a31a286c..11fde3a2be353 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_encoder.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_encoder.c
@@ -8,46 +8,40 @@
 
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_bridge.h>
+#include <drm/drm_bridge_connector.h>
 #include <drm/drm_of.h>
 #include <drm/drm_simple_kms_helper.h>
 
 #include "tilcdc_drv.h"
 #include "tilcdc_encoder.h"
 
-static
-struct drm_connector *tilcdc_encoder_find_connector(struct drm_device *ddev,
-						    struct drm_encoder *encoder)
-{
-	struct drm_connector *connector;
-
-	list_for_each_entry(connector, &ddev->mode_config.connector_list, head) {
-		if (drm_connector_has_possible_encoder(connector, encoder))
-			return connector;
-	}
-
-	dev_err(ddev->dev, "No connector found for %s encoder (id %d)\n",
-		encoder->name, encoder->base.id);
-
-	return NULL;
-}
-
 static
 int tilcdc_attach_bridge(struct drm_device *ddev, struct drm_bridge *bridge)
 {
 	struct tilcdc_drm_private *priv = ddev_to_tilcdc_priv(ddev);
+	struct drm_connector *connector;
 	int ret;
 
 	priv->encoder->possible_crtcs = BIT(0);
 
-	ret = drm_bridge_attach(priv->encoder, bridge, NULL, 0);
+	ret = drm_bridge_attach(priv->encoder, bridge, NULL,
+				DRM_BRIDGE_ATTACH_NO_CONNECTOR);
 	if (ret)
 		return ret;
 
-	priv->connector =
-		tilcdc_encoder_find_connector(ddev, priv->encoder);
-	if (!priv->connector)
-		return -ENODEV;
+	connector = drm_bridge_connector_init(ddev, priv->encoder);
+	if (IS_ERR(connector)) {
+		dev_err(ddev->dev, "bridge_connector create failed\n");
+		return PTR_ERR(connector);
+	}
+
+	ret = drm_connector_attach_encoder(connector, priv->encoder);
+	if (ret) {
+		dev_err(ddev->dev, "attaching encoder to connector failed\n");
+		return ret;
+	}
 
+	priv->connector = connector;
 	return 0;
 }
 

-- 
2.43.0



From rebecca at bsdio.com  Thu Dec 11 08:56:55 2025
From: rebecca at bsdio.com (Rebecca Cran)
Date: Thu, 11 Dec 2025 09:56:55 -0700
Subject: [PATCH v5 0/2] Add device tree for ASRock Rack ALTRAD8 BMC
Message-ID: <20251211165700.29206-1-rebecca@bsdio.com>

The ASRock Rack ALTRAD8 BMC is an Aspeed AST2500-based BMC for the
ALTRAD8UD-1L2T and ALTRAD8UD2-1L2Q boards with an Ampere Altra
processor. The BMC runs OpenBMC.

These patches add a device tree and binding for the BMC.

**Changes between v4 and v5**

- Removed the uartx-mode1 GPIOs, which were wrong.
- Fixed button-power-n GPIO name.
- Removed backslash from end of line, which isn't needed.
- Removed duplicate/wrong bmc heartbeat GPIO.

**Testing**

Ran `make ARCH=arm CHECK_DTBS=y aspeed/aspeed-bmc-asrock-altrad8.dtb`.


Rebecca Cran (2):
  dt-bindings: arm: aspeed: add ASRock Rack ALTRAD8 board
  ARM: dts: aspeed: add device tree for ASRock Rack ALTRAD8 BMC

 Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml |   1 +
 arch/arm/boot/dts/aspeed/Makefile                        |   1 +
 arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts   | 624 ++++++++++++++++++++
 3 files changed, 626 insertions(+)
 create mode 100644 arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts

-- 
2.47.3



From rebecca at bsdio.com  Thu Dec 11 08:56:56 2025
From: rebecca at bsdio.com (Rebecca Cran)
Date: Thu, 11 Dec 2025 09:56:56 -0700
Subject: [PATCH v5 1/2] dt-bindings: arm: aspeed: add ASRock Rack ALTRAD8 board
In-Reply-To: <20251211165700.29206-1-rebecca@bsdio.com>
References: <20251211165700.29206-1-rebecca@bsdio.com>
Message-ID: <20251211165700.29206-2-rebecca@bsdio.com>

Document ASRock Rack ALTRAD8 (ALTRAD8UD-1L2T and ALTRAD8UD2-1L2Q)
compatibles.

Signed-off-by: Rebecca Cran <rebecca at bsdio.com>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
 Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
index 9298c1a75dd1..aefad2d02993 100644
--- a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
+++ b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
@@ -34,6 +34,7 @@ properties:
               - amd,ethanolx-bmc
               - ampere,mtjade-bmc
               - aspeed,ast2500-evb
+              - asrock,altrad8-bmc
               - asrock,e3c246d4i-bmc
               - asrock,e3c256d4i-bmc
               - asrock,romed8hm3-bmc
-- 
2.47.3



From rebecca at bsdio.com  Thu Dec 11 08:56:57 2025
From: rebecca at bsdio.com (Rebecca Cran)
Date: Thu, 11 Dec 2025 09:56:57 -0700
Subject: [PATCH v5 2/2] ARM: dts: aspeed: add device tree for ASRock Rack ALTRAD8 BMC
In-Reply-To: <20251211165700.29206-1-rebecca@bsdio.com>
References: <20251211165700.29206-1-rebecca@bsdio.com>
Message-ID: <20251211165700.29206-3-rebecca@bsdio.com>

The ALTRAD8 BMC is an Aspeed AST2500-based BMC for the ASRock Rack
ALTRAD8UD-1L2T and ALTRAD8UD2-1L2Q boards.

Signed-off-by: Rebecca Cran <rebecca at bsdio.com>
---
 arch/arm/boot/dts/aspeed/Makefile                      |   1 +
 arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts | 624 ++++++++++++++++++++
 2 files changed, 625 insertions(+)

diff --git a/arch/arm/boot/dts/aspeed/Makefile b/arch/arm/boot/dts/aspeed/Makefile
index 9adf9278dc94..f073f126ddac 100644
--- a/arch/arm/boot/dts/aspeed/Makefile
+++ b/arch/arm/boot/dts/aspeed/Makefile
@@ -9,6 +9,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \
 	aspeed-bmc-ampere-mtjefferson.dtb \
 	aspeed-bmc-ampere-mtmitchell.dtb \
 	aspeed-bmc-arm-stardragon4800-rep2.dtb \
+	aspeed-bmc-asrock-altrad8.dtb \
 	aspeed-bmc-asrock-e3c246d4i.dtb \
 	aspeed-bmc-asrock-e3c256d4i.dtb \
 	aspeed-bmc-asrock-romed8hm3.dtb \
diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts
new file mode 100644
index 000000000000..4898ddede1c2
--- /dev/null
+++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts
@@ -0,0 +1,624 @@
+// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+
+#include "aspeed-g5.dtsi"
+#include <dt-bindings/gpio/aspeed-gpio.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/i2c/i2c.h>
+
+/ {
+	model = "ASRock ALTRAD8 BMC";
+	compatible = "asrock,altrad8-bmc", "aspeed,ast2500";
+
+	aliases {
+		serial4 = &uart5;
+		i2c50 = &nvme1;
+		i2c51 = &pcie4;
+		i2c52 = &pcie5;
+		i2c53 = &pcie6;
+		i2c54 = &pcie7;
+		i2c55 = &nvme3;
+		i2c56 = &nvme2;
+		i2c57 = &nvme0;
+		i2c58 = &nvme4;
+		i2c59 = &nvme5;
+		i2c60 = &nvme6;
+		i2c61 = &nvme7;
+		i2c62 = &nvme8;
+		i2c63 = &nvme9;
+		i2c64 = &nvme10;
+		i2c65 = &nvme11;
+	};
+
+	chosen {
+		stdout-path = "uart5:115200n8";
+	};
+
+	iio-hwmon {
+		compatible = "iio-hwmon";
+		io-channels =	<&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>,
+				<&adc 4> ,<&adc 5>, <&adc 6>, <&adc 7>,
+				<&adc 8>, <&adc 9>, <&adc 10>, <&adc 11>,
+				<&adc 12>, <&adc 13>, <&adc 14>, <&adc 15>;
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		led-system-fault {
+			gpios = <&gpio ASPEED_GPIO(G,3) GPIO_ACTIVE_LOW>;
+			label = "platform:red:fault";
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_FAULT;
+		};
+
+		led-heartbeat {
+			gpios = <&gpio ASPEED_GPIO(G,0) GPIO_ACTIVE_LOW>;
+			label = "platform:green:heartbeat";
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_INDICATOR;
+			linux,default-trigger = "timer";
+		};
+
+		led-fan1-fault {
+			retain-state-shutdown;
+			default-state = "off";
+			gpios = <&io_expander0 0 GPIO_ACTIVE_LOW>;
+			label = "fan1:red:fault";
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_FAULT;
+		};
+
+		led-fan2-fault {
+			retain-state-shutdown;
+			default-state = "off";
+			gpios = <&io_expander0 1 GPIO_ACTIVE_LOW>;
+			label = "fan2:red:fault";
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_FAULT;
+		};
+
+		led-fan3-fault {
+			retain-state-shutdown;
+			default-state = "off";
+			gpios = <&io_expander0 2 GPIO_ACTIVE_LOW>;
+			label = "fan3:red:fault";
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_FAULT;
+		};
+
+		led-fan4-fault {
+			retain-state-shutdown;
+			default-state = "off";
+			gpios = <&io_expander0 3 GPIO_ACTIVE_LOW>;
+			label = "fan4:red:fault";
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_FAULT;
+		};
+
+		led-fan5-fault {
+			retain-state-shutdown;
+			default-state = "off";
+			gpios = <&io_expander0 4 GPIO_ACTIVE_LOW>;
+			label = "fan5:red:fault";
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_FAULT;
+		};
+	};
+
+	memory at 80000000 {
+		reg = <0x80000000 0x20000000>;
+	};
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		gfx_memory: framebuffer {
+			compatible = "shared-dma-pool";
+			size = <0x01000000>;
+			alignment = <0x01000000>;
+			reusable;
+		};
+
+		vga_memory: framebuffer at 9f000000 {
+			no-map;
+			reg = <0x9f000000 0x01000000>; /* 16M */
+		};
+
+		video_engine_memory: jpegbuffer {
+			compatible = "shared-dma-pool";
+			size = <0x02000000>;	/* 32M */
+			alignment = <0x01000000>;
+			reusable;
+		};
+	};
+};
+
+&adc {
+	status = "okay";
+};
+
+&fmc {
+	status = "okay";
+
+	flash at 0 {
+		label = "bmc";
+		m25p,fast-read;
+		spi-max-frequency = <50000000>;
+		status = "okay";
+#include "openbmc-flash-layout-64.dtsi"
+	};
+};
+
+&gfx {
+	memory-region = <&gfx_memory>;
+	status = "okay";
+};
+
+&gpio {
+	gpio-line-names =
+	/*A0-A7*/	"","","","bmc-ready","","","","",
+	/*B0-B7*/	"i2c-backup-sel","","","","","","","host0-shd-ack-n",
+	/*C0-C7*/	"","","","","","","","",
+	/*D0-D7*/	"button-power-n","control-power-n","button-reset-n",
+			"host0-sysreset-n","","","power-chassis-good","",
+	/*E0-E7*/	"","s0-vrd1-vddq0123-fault-n",
+			"s0-vrd1-vddq4567-fault-n","s0-vrd0-vddc-fault-n",
+			"s0-vrd3-p0v75-fault-n","","","",
+	/*F0-F7*/	"","","ps-atx-on-n","","","","","",
+	/*G0-G7*/	"led-bmc-heartbeat-n","button-identify-n","",
+			"led-system-fault-n","uboot-ready","bmc-salt2-n","","",
+	/*H0-H7*/	"ps-pwr-ok","","","","","","","",
+	/*I0-I7*/	"","","","","","","","",
+	/*J0-J7*/	"s0-hightemp-n","","","","","","","",
+	/*K0-K7*/	"","","","","","","","",
+	/*L0-L7*/	"","","","","","","","",
+	/*M0-M7*/	"cpld-disable-bmc-n","","","","","s0-spi-auth-fail-n","","",
+	/*N0-N7*/	"","","","","","","","",
+	/*O0-O7*/	"","","","","","","","",
+	/*P0-P7*/	"","","","","","","","",
+	/*Q0-Q7*/	"","","","","","","led-identify-n",
+			"chassis-intrusion-n",
+	/*R0-R7*/	"","","ext-hightemp-n","spi0-program-sel","",
+			"output-hwm-bat-en","","",
+	/*S0-S7*/	"s0-vr-hot-n","","input-salt2-n","bmc-sysreset-n","","","","",
+	/*T0-T7*/	"","","","","","","","",
+	/*U0-U7*/	"","","","","","","","",
+	/*V0-V7*/	"","","","","","","","",
+	/*W0-W7*/	"","","","","","","","",
+	/*X0-X7*/	"","","","","","","","",
+	/*Y0-Y7*/	"","","","","","","","",
+	/*Z0-Z7*/	"","","","s0-rtc-lock","","","","",
+	/*AA0-AA7*/	"s0-rtc-int-n","","","","","pmbus-sel-n","","",
+	/*AB0-AB7*/	"host0-reboot-ack-n","s0-sys-auth-failure-n",
+			"","","","","","",
+	/*AC0-AC7*/	"s0-fault-alert","host0-ready","s0-overtemp-n",
+			"","bmc-ok","host0-special-boot","presence-cpu0",
+			"host0-shd-req-n";
+
+	status = "okay";
+};
+
+&i2c0 {
+	status = "okay";
+
+	ipmb at 10 {
+		compatible = "ipmb-dev";
+		reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>;
+		i2c-protocol;
+	};
+
+};
+
+&i2c1 {
+	status = "okay";
+
+	i2c-mux1 at 73 {
+		compatible = "nxp,pca9548";
+		reg = <0x73>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		nvme1: i2c at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+		};
+
+		pcie4: i2c at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+		};
+
+		pcie5: i2c at 2 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2>;
+		};
+
+		pcie6: i2c at 3 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <3>;
+		};
+
+		pcie7: i2c at 4 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <4>;
+		};
+
+		nvme3: i2c at 5 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <5>;
+		};
+
+		nvme2: i2c at 6 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <6>;
+		};
+
+		nvme0: i2c at 7 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <7>;
+		};
+	};
+
+	i2c-mux2 at 75 {
+		compatible = "nxp,pca9548";
+		reg = <0x75>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		nvme4: i2c at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+		};
+
+		nvme5: i2c at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+		};
+
+		nvme6: i2c at 2 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2>;
+		};
+
+		nvme7: i2c at 3 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <3>;
+		};
+
+		nvme8: i2c at 4 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <4>;
+		};
+
+		nvme9: i2c at 5 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <5>;
+		};
+
+		nvme10: i2c at 6 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <6>;
+		};
+
+		nvme11: i2c at 7 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <7>;
+		};
+	};
+};
+
+&i2c2 {
+	status = "okay";
+
+	smpro at 4f {
+		compatible = "ampere,smpro";
+		reg = <0x4f>;
+	};
+};
+
+&i2c3 {
+	status = "okay";
+
+	// PSU FRU
+	eeprom at 38 {
+		compatible = "atmel,24c02";
+		reg = <0x38>;
+	};
+};
+
+&i2c4 {
+	status = "okay";
+
+	temperature-sensor at 29 {
+		compatible = "nuvoton,nct7802";
+		reg = <0x29>;
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		channel at 0 { /* LTD */
+			reg = <0>;
+			status = "okay";
+		};
+
+		channel at 1 { /* RTD1 */
+			reg = <1>;
+			sensor-type = "temperature";
+			temperature-mode = "thermistor";
+		};
+
+		channel at 2 { /* RTD2 */
+			reg = <2>;
+			sensor-type = "temperature";
+			temperature-mode = "thermal-diode";
+		};
+	};
+
+	temperature-sensor at 4c {
+		compatible = "nuvoton,w83773g";
+		reg = <0x4c>;
+	};
+};
+
+&i2c5 {
+	status = "okay";
+};
+
+&i2c6 {
+	status = "okay";
+
+	rtc at 6f {
+		compatible = "isil,isl1208";
+		reg = <0x6f>;
+	};
+};
+
+&i2c7 {
+	status = "okay";
+
+	// BMC FRU
+	eeprom at 57 {
+		compatible = "atmel,24c128";
+		reg = <0x57>;
+
+		nvmem-layout {
+			compatible = "fixed-layout";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			eth1_macaddress: macaddress at 3f80 {
+				reg = <0x3f80 6>;
+			};
+
+			// The offset for eth0 really is at 0x3f88.
+			// eth0 and eth1 are swapped from what might be
+			// expected.
+			eth0_macaddress: macaddress at 3f88 {
+				reg = <0x3f88 6>;
+			};
+		};
+	};
+};
+
+&i2c8 {
+	status = "okay";
+
+	io_expander0: gpio at 1c {
+		compatible = "nxp,pca9557";
+		reg = <0x1c>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+};
+
+&i2c9 {
+	status = "okay";
+};
+
+&i2c10 {
+	status = "okay";
+};
+
+&i2c11 {
+	status = "okay";
+};
+
+// Bus for accessing the SCP EEPROM
+&i2c12 {
+	status = "okay";
+};
+
+&i2c13 {
+	status = "okay";
+
+	ssif-bmc at 10 {
+		compatible = "ssif-bmc";
+		reg = <0x10>;
+	};
+};
+
+// Connected to host Intel X550 (ALTRAD8UD-1L2T) or
+// Broadcom BCM57414 (ALTRAD8UD2-1L2Q) interface.
+// Unconnected on ALTRAD8UD-1L
+&mac0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_rmii1_default>;
+	clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+		 <&syscon ASPEED_CLK_MAC1RCLK>;
+	clock-names = "MACCLK", "RCLK";
+	use-ncsi;
+	nvmem-cells = <&eth0_macaddress>;
+	nvmem-cell-names = "mac-address";
+
+	status = "okay";
+};
+
+// Connected to Realtek RTL8211E
+&mac1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>;
+
+	nvmem-cells = <&eth1_macaddress>;
+	nvmem-cell-names = "mac-address";
+
+	status = "okay";
+};
+
+&pinctrl {
+	aspeed,external-nodes = <&gfx &lhc>;
+};
+
+&pwm_tacho {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pwm0_default
+			&pinctrl_pwm1_default
+			&pinctrl_pwm2_default
+			&pinctrl_pwm3_default
+			&pinctrl_pwm4_default
+			&pinctrl_pwm5_default
+			&pinctrl_pwm6_default
+			&pinctrl_pwm7_default>;
+
+	status = "okay";
+
+	fan at 0 {
+		reg = <0x00>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x00 0x08>;
+	};
+
+	fan at 1 {
+		reg = <0x01>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x01 0x09>;
+	};
+
+	fan at 2 {
+		reg = <0x02>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x02 0x0a>;
+	};
+
+	fan at 3 {
+		reg = <0x03>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x03 0x0b>;
+	};
+
+	fan at 4 {
+		reg = <0x04>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x04 0x0c>;
+	};
+
+	fan at 5 {
+		reg = <0x05>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x05 0x0d>;
+	};
+
+	fan at 6 {
+		reg = <0x06>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x06 0x0e>;
+	};
+
+	fan at 7 {
+		reg = <0x07>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x07 0x0f>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_spi1_default>;
+
+	status = "okay";
+
+	// Host BIOS/UEFI EEPROM
+	flash at 0 {
+		m25p,fast-read;
+		label = "pnor";
+		spi-max-frequency = <100000000>;
+		status = "okay";
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			tfa at 400000 {
+				reg = <0x400000 0x200000>;
+				label = "pnor-tfa";
+			};
+
+			uefi at 600000 {
+				reg = <0x600000 0x1A00000>;
+				label = "pnor-uefi";
+			};
+		};
+	};
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_txd1_default
+			 &pinctrl_rxd1_default
+			 &pinctrl_ncts1_default
+			 &pinctrl_nrts1_default>;
+
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_txd2_default
+			&pinctrl_rxd2_default>;
+
+	status = "okay";
+};
+
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_txd3_default
+			&pinctrl_rxd3_default>;
+
+	status = "okay";
+};
+
+&uart4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_txd4_default
+			&pinctrl_rxd4_default>;
+
+	status = "okay";
+};
+
+// The BMC's uart
+&uart5 {
+	status = "okay";
+};
+
+&vhub {
+	status = "okay";
+};
+
+&video {
+	memory-region = <&video_engine_memory>;
+
+	status = "okay";
+};
-- 
2.47.3



From Frank.li at nxp.com  Thu Dec 11 08:57:04 2025
From: Frank.li at nxp.com (Frank Li)
Date: Thu, 11 Dec 2025 11:57:04 -0500
Subject: [PATCH v4] pmdomain: imx: Fix reference count leak in
 imx_gpc_probe()
In-Reply-To: <20251211040252.497759-1-vulab@iscas.ac.cn>
References: <20251211040252.497759-1-vulab@iscas.ac.cn>
Message-ID: <aTr34BiVU+xPvuq9@lizhi-Precision-Tower-5810>

On Thu, Dec 11, 2025 at 04:02:52AM +0000, Wentao Liang wrote:
> of_get_child_by_name() returns a node pointer with refcount incremented.
> Use the __free() attribute to manage the pgc_node reference, ensuring
> automatic of_node_put() cleanup when pgc_node goes out of scope.
>
> This eliminates the need for explicit error handling paths and avoids
> reference count leaks.
>
> Fixes: 721cabf6c660 ("soc: imx: move PGC handling to a new GPC driver")
> Cc: stable at vger.kernel.org
> Signed-off-by: Wentao Liang <vulab at iscas.ac.cn>

Reviewed-by: Frank Li <Frank.Li at nxp.com>

>
> ---
> Change in V4:
> - Fix typo error in code
>
> Change in V3:
> - Ensure variable is assigned when using cleanup attribute
>
> Change in V2:
> - Use __free() attribute instead of explicit of_node_put() calls
> ---
>  drivers/pmdomain/imx/gpc.c | 5 ++---
>  1 file changed, 2 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/pmdomain/imx/gpc.c b/drivers/pmdomain/imx/gpc.c
> index f18c7e6e75dd..56a78cc86584 100644
> --- a/drivers/pmdomain/imx/gpc.c
> +++ b/drivers/pmdomain/imx/gpc.c
> @@ -403,13 +403,12 @@ static int imx_gpc_old_dt_init(struct device *dev, struct regmap *regmap,
>  static int imx_gpc_probe(struct platform_device *pdev)
>  {
>  	const struct imx_gpc_dt_data *of_id_data = device_get_match_data(&pdev->dev);
> -	struct device_node *pgc_node;
> +	struct device_node *pgc_node __free(device_node)
> +		= of_get_child_by_name(pdev->dev.of_node, "pgc");
>  	struct regmap *regmap;
>  	void __iomem *base;
>  	int ret;
>
> -	pgc_node = of_get_child_by_name(pdev->dev.of_node, "pgc");
> -
>  	/* bail out if DT too old and doesn't provide the necessary info */
>  	if (!of_property_present(pdev->dev.of_node, "#power-domain-cells") &&
>  	    !pgc_node)
> --
> 2.34.1
>


From robh at kernel.org  Thu Dec 11 09:03:33 2025
From: robh at kernel.org (Rob Herring)
Date: Thu, 11 Dec 2025 11:03:33 -0600
Subject: [PATCH RFC 06/16] dt-bindings: mmc: Switch ref to
 sdhci-common.yaml
In-Reply-To: <176546866607.1487115.6798113196659439308.robh@kernel.org>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
 <20251211-dev-dt-warnings-all-v1-6-21b18b9ada77@codeconstruct.com.au>
 <176546866607.1487115.6798113196659439308.robh@kernel.org>
Message-ID: <20251211170333.GA1557987-robh@kernel.org>

On Thu, Dec 11, 2025 at 09:57:47AM -0600, Rob Herring (Arm) wrote:
> 
> On Thu, 11 Dec 2025 17:45:48 +0900, Andrew Jeffery wrote:
> > Enable use of common SDHCI-related properties such as sdhci-caps-mask as
> > found in the AST2600 EVB DTS.
> > 
> > Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
> > ---
> >  Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> 
> My bot found errors running 'make dt_binding_check' on your patch:
> 
> yamllint warnings/errors:
> 
> dtschema/dtc warnings/errors:
> /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/hwmon/aspeed,ast2400-pwm-tacho.example.dtb: fan-controller at 1e786000 (aspeed,ast2500-pwm-tacho): #cooling-cells: 2 was expected
> 	from schema $id: http://devicetree.org/schemas/thermal/thermal-cooling-devices.yaml

Not sure what happened here. This is a real error, but on the wrong 
patch. The already applied change here looks fine.

We need to determine 1 cooling cell makes any sense or not, and allow 
for 1 in thermal-cooling-devices.yaml if it does.

Rob


From chourasiarohit27 at gmail.com  Thu Dec 11 09:05:35 2025
From: chourasiarohit27 at gmail.com (chourasiarohit27 at gmail.com)
Date: Thu, 11 Dec 2025 22:35:35 +0530
Subject: [PATCH] arm: kconfig: fix duplicated word "the" in help text
Message-ID: <20251211170535.33836-1-chourasiarohit27@gmail.com>

From: Rohit Chourasia <chourasiarohit27 at gmail.com>

Signed-off-by: Rohit Chourasia <chourasiarohit27 at gmail.com>
---
 arch/arm/Kconfig | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index fa83c040ee2d..bc7b05a954a5 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1484,7 +1484,7 @@ config ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND
 	bool "Extend with bootloader kernel arguments"
 	help
 	  The command-line arguments provided by the boot loader will be
-	  appended to the the device tree bootargs property.
+	  appended to the device tree bootargs property.
 
 endchoice
 
@@ -1626,7 +1626,7 @@ config DMI
 	  continue to boot on existing non-UEFI platforms.
 
 	  NOTE: This does *NOT* enable or encourage the use of DMI quirks,
-	  i.e., the the practice of identifying the platform via DMI to
+	  i.e., the practice of identifying the platform via DMI to
 	  decide whether certain workarounds for buggy hardware and/or
 	  firmware need to be enabled. This would require the DMI subsystem
 	  to be enabled much earlier than we do on ARM, which is non-trivial.
-- 
2.25.1



From u.kleine-koenig at baylibre.com  Thu Dec 11 09:14:54 2025
From: u.kleine-koenig at baylibre.com (=?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?=)
Date: Thu, 11 Dec 2025 18:14:54 +0100
Subject: [PATCH v1 00/17] tee: Use bus callbacks instead of driver callbacks
Message-ID: <cover.1765472125.git.u.kleine-koenig@baylibre.com>

Hello,

the objective of this series is to make tee driver stop using callbacks
in struct device_driver. These were superseded by bus methods in 2006
(commit 594c8281f905 ("[PATCH] Add bus_type probe, remove, shutdown
methods.")) but nobody cared to convert all subsystems accordingly.

Here the tee drivers are converted. The first commit is somewhat
unrelated, but simplifies the conversion (and the drivers). It
introduces driver registration helpers that care about setting the bus
and owner. (The latter is missing in all drivers, so by using these
helpers the drivers become more correct.)

The patches #4 - #17 depend on the first two, so if they should be
applied to their respective subsystem trees these must contain the first
two patches first.

Note that after patch #2 is applied, unconverted drivers provoke a
warning in driver_register(), so it would be good for the user
experience if the whole series goes in during a single merge window. So
I guess an immutable branch containing the frist three patches that can
be merged into the other subsystem trees would be sensible.

After all patches are applied, tee_bus_type can be made private to
drivers/tee as it's not used in other places any more.

Best regards
Uwe

Uwe Kleine-K?nig (17):
  tee: Add some helpers to reduce boilerplate for tee client drivers
  tee: Add probe, remove and shutdown bus callbacks to tee_client_driver
  tee: Adapt documentation to cover recent additions
  hwrng: optee - Make use of module_tee_client_driver()
  hwrng: optee - Make use of tee bus methods
  rtc: optee: Migrate to use tee specific driver registration function
  rtc: optee: Make use of tee bus methods
  efi: stmm: Make use of module_tee_client_driver()
  efi: stmm: Make use of tee bus methods
  firmware: arm_scmi: optee: Make use of module_tee_client_driver()
  firmware: arm_scmi: Make use of tee bus methods
  firmware: tee_bnxt: Make use of module_tee_client_driver()
  firmware: tee_bnxt: Make use of tee bus methods
  KEYS: trusted: Migrate to use tee specific driver registration
    function
  KEYS: trusted: Make use of tee bus methods
  tpm/tpm_ftpm_tee: Make use of tee specific driver registration
  tpm/tpm_ftpm_tee: Make use of tee bus methods

 Documentation/driver-api/tee.rst             | 18 +----
 drivers/char/hw_random/optee-rng.c           | 26 ++----
 drivers/char/tpm/tpm_ftpm_tee.c              | 31 +++++---
 drivers/firmware/arm_scmi/transports/optee.c | 32 +++-----
 drivers/firmware/broadcom/tee_bnxt_fw.c      | 30 ++-----
 drivers/firmware/efi/stmm/tee_stmm_efi.c     | 25 ++----
 drivers/rtc/rtc-optee.c                      | 27 ++-----
 drivers/tee/tee_core.c                       | 84 ++++++++++++++++++++
 include/linux/tee_drv.h                      | 12 +++
 security/keys/trusted-keys/trusted_tee.c     | 17 ++--
 10 files changed, 164 insertions(+), 138 deletions(-)


base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
-- 
2.47.3



From u.kleine-koenig at baylibre.com  Thu Dec 11 09:15:02 2025
From: u.kleine-koenig at baylibre.com (=?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?=)
Date: Thu, 11 Dec 2025 18:15:02 +0100
Subject: [PATCH v1 08/17] efi: stmm: Make use of module_tee_client_driver()
In-Reply-To: <cover.1765472125.git.u.kleine-koenig@baylibre.com>
References: <cover.1765472125.git.u.kleine-koenig@baylibre.com>
Message-ID: <0896270bc530d1e3b7fbcf5f7e168172dcc05d1e.1765472125.git.u.kleine-koenig@baylibre.com>

Reduce boilerplate by using the newly introduced module_tee_client_driver().
That takes care of assigning the driver's bus, so the explicit assigning
in this driver can be dropped.

Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig at baylibre.com>
---
 drivers/firmware/efi/stmm/tee_stmm_efi.c | 14 +-------------
 1 file changed, 1 insertion(+), 13 deletions(-)

diff --git a/drivers/firmware/efi/stmm/tee_stmm_efi.c b/drivers/firmware/efi/stmm/tee_stmm_efi.c
index 65c0fe1ba275..5903811858b6 100644
--- a/drivers/firmware/efi/stmm/tee_stmm_efi.c
+++ b/drivers/firmware/efi/stmm/tee_stmm_efi.c
@@ -584,24 +584,12 @@ static struct tee_client_driver tee_stmm_efi_driver = {
 	.id_table	= tee_stmm_efi_id_table,
 	.driver		= {
 		.name		= "tee-stmm-efi",
-		.bus		= &tee_bus_type,
 		.probe		= tee_stmm_efi_probe,
 		.remove		= tee_stmm_efi_remove,
 	},
 };
 
-static int __init tee_stmm_efi_mod_init(void)
-{
-	return driver_register(&tee_stmm_efi_driver.driver);
-}
-
-static void __exit tee_stmm_efi_mod_exit(void)
-{
-	driver_unregister(&tee_stmm_efi_driver.driver);
-}
-
-module_init(tee_stmm_efi_mod_init);
-module_exit(tee_stmm_efi_mod_exit);
+module_tee_client_driver(tee_stmm_efi_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Ilias Apalodimas <ilias.apalodimas at linaro.org>");
-- 
2.47.3



From u.kleine-koenig at baylibre.com  Thu Dec 11 09:15:03 2025
From: u.kleine-koenig at baylibre.com (=?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?=)
Date: Thu, 11 Dec 2025 18:15:03 +0100
Subject: [PATCH v1 09/17] efi: stmm: Make use of tee bus methods
In-Reply-To: <cover.1765472125.git.u.kleine-koenig@baylibre.com>
References: <cover.1765472125.git.u.kleine-koenig@baylibre.com>
Message-ID: <9e3d9ab0f7987f313237b51911865f0cccae8eb5.1765472125.git.u.kleine-koenig@baylibre.com>

The tee bus got dedicated callbacks for probe and remove.
Make use of these. This fixes a runtime warning about the driver needing
to be converted to the bus methods.

Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig at baylibre.com>
---
 drivers/firmware/efi/stmm/tee_stmm_efi.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/firmware/efi/stmm/tee_stmm_efi.c b/drivers/firmware/efi/stmm/tee_stmm_efi.c
index 5903811858b6..7b04dd649629 100644
--- a/drivers/firmware/efi/stmm/tee_stmm_efi.c
+++ b/drivers/firmware/efi/stmm/tee_stmm_efi.c
@@ -520,8 +520,9 @@ static void tee_stmm_restore_efivars_generic_ops(void)
 	efivars_generic_ops_register();
 }
 
-static int tee_stmm_efi_probe(struct device *dev)
+static int tee_stmm_efi_probe(struct tee_client_device *tee_dev)
 {
+	struct device *dev = &tee_dev->dev;
 	struct tee_ioctl_open_session_arg sess_arg;
 	efi_status_t ret;
 	int rc;
@@ -571,21 +572,19 @@ static int tee_stmm_efi_probe(struct device *dev)
 	return 0;
 }
 
-static int tee_stmm_efi_remove(struct device *dev)
+static void tee_stmm_efi_remove(struct tee_client_device *dev)
 {
 	tee_stmm_restore_efivars_generic_ops();
-
-	return 0;
 }
 
 MODULE_DEVICE_TABLE(tee, tee_stmm_efi_id_table);
 
 static struct tee_client_driver tee_stmm_efi_driver = {
 	.id_table	= tee_stmm_efi_id_table,
+	.probe		= tee_stmm_efi_probe,
+	.remove		= tee_stmm_efi_remove,
 	.driver		= {
 		.name		= "tee-stmm-efi",
-		.probe		= tee_stmm_efi_probe,
-		.remove		= tee_stmm_efi_remove,
 	},
 };
 
-- 
2.47.3



From u.kleine-koenig at baylibre.com  Thu Dec 11 09:15:04 2025
From: u.kleine-koenig at baylibre.com (=?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?=)
Date: Thu, 11 Dec 2025 18:15:04 +0100
Subject: [PATCH v1 10/17] firmware: arm_scmi: optee: Make use of module_tee_client_driver()
In-Reply-To: <cover.1765472125.git.u.kleine-koenig@baylibre.com>
References: <cover.1765472125.git.u.kleine-koenig@baylibre.com>
Message-ID: <537c48e3db243b5c68c3192179a948efb3a180c7.1765472125.git.u.kleine-koenig@baylibre.com>

Reduce boilerplate by using the newly introduced module_tee_client_driver().
That takes care of assigning the driver's bus, so the explicit assigning
in this driver can be dropped.

Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig at baylibre.com>
---
 drivers/firmware/arm_scmi/transports/optee.c | 13 +------------
 1 file changed, 1 insertion(+), 12 deletions(-)

diff --git a/drivers/firmware/arm_scmi/transports/optee.c b/drivers/firmware/arm_scmi/transports/optee.c
index dc0f46340153..8fdb80d3fabd 100644
--- a/drivers/firmware/arm_scmi/transports/optee.c
+++ b/drivers/firmware/arm_scmi/transports/optee.c
@@ -612,23 +612,12 @@ static struct tee_client_driver scmi_optee_service_driver = {
 	.id_table	= scmi_optee_service_id,
 	.driver		= {
 		.name = "scmi-optee",
-		.bus = &tee_bus_type,
 		.probe = scmi_optee_service_probe,
 		.remove = scmi_optee_service_remove,
 	},
 };
 
-static int __init scmi_transport_optee_init(void)
-{
-	return driver_register(&scmi_optee_service_driver.driver);
-}
-module_init(scmi_transport_optee_init);
-
-static void __exit scmi_transport_optee_exit(void)
-{
-	driver_unregister(&scmi_optee_service_driver.driver);
-}
-module_exit(scmi_transport_optee_exit);
+module_tee_client_driver(scmi_optee_service_driver);
 
 MODULE_AUTHOR("Etienne Carriere <etienne.carriere at foss.st.com>");
 MODULE_DESCRIPTION("SCMI OPTEE Transport driver");
-- 
2.47.3



From u.kleine-koenig at baylibre.com  Thu Dec 11 09:15:05 2025
From: u.kleine-koenig at baylibre.com (=?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?=)
Date: Thu, 11 Dec 2025 18:15:05 +0100
Subject: [PATCH v1 11/17] firmware: arm_scmi: Make use of tee bus methods
In-Reply-To: <cover.1765472125.git.u.kleine-koenig@baylibre.com>
References: <cover.1765472125.git.u.kleine-koenig@baylibre.com>
Message-ID: <46dae3cada663b3a5ae1989881d9e74ef40acce5.1765472125.git.u.kleine-koenig@baylibre.com>

The tee bus got dedicated callbacks for probe and remove.
Make use of these. This fixes a runtime warning about the driver needing
to be converted to the bus methods. Note that the return value of .remove()
was already ignored before, so there is no problem introduced by dropping
the error returns.

Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig at baylibre.com>
---
 drivers/firmware/arm_scmi/transports/optee.c | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/drivers/firmware/arm_scmi/transports/optee.c b/drivers/firmware/arm_scmi/transports/optee.c
index 8fdb80d3fabd..07ae18d5279d 100644
--- a/drivers/firmware/arm_scmi/transports/optee.c
+++ b/drivers/firmware/arm_scmi/transports/optee.c
@@ -529,8 +529,9 @@ static const struct of_device_id scmi_of_match[] = {
 DEFINE_SCMI_TRANSPORT_DRIVER(scmi_optee, scmi_optee_driver, scmi_optee_desc,
 			     scmi_of_match, core);
 
-static int scmi_optee_service_probe(struct device *dev)
+static int scmi_optee_service_probe(struct tee_client_device *scmi_pta)
 {
+	struct device *dev = &scmi_pta->dev;
 	struct scmi_optee_agent *agent;
 	struct tee_context *tee_ctx;
 	int ret;
@@ -578,24 +579,22 @@ static int scmi_optee_service_probe(struct device *dev)
 	return ret;
 }
 
-static int scmi_optee_service_remove(struct device *dev)
+static void scmi_optee_service_remove(struct tee_client_device *scmi_pta)
 {
 	struct scmi_optee_agent *agent = scmi_optee_private;
 
 	if (!scmi_optee_private)
-		return -EINVAL;
+		return;
 
 	platform_driver_unregister(&scmi_optee_driver);
 
 	if (!list_empty(&scmi_optee_private->channel_list))
-		return -EBUSY;
+		return;
 
 	/* Ensure cleared reference is visible before resources are released */
 	smp_store_mb(scmi_optee_private, NULL);
 
 	tee_client_close_context(agent->tee_ctx);
-
-	return 0;
 }
 
 static const struct tee_client_device_id scmi_optee_service_id[] = {
@@ -609,11 +608,11 @@ static const struct tee_client_device_id scmi_optee_service_id[] = {
 MODULE_DEVICE_TABLE(tee, scmi_optee_service_id);
 
 static struct tee_client_driver scmi_optee_service_driver = {
-	.id_table	= scmi_optee_service_id,
-	.driver		= {
+	.probe = scmi_optee_service_probe,
+	.remove = scmi_optee_service_remove,
+	.id_table = scmi_optee_service_id,
+	.driver = {
 		.name = "scmi-optee",
-		.probe = scmi_optee_service_probe,
-		.remove = scmi_optee_service_remove,
 	},
 };
 
-- 
2.47.3



From Sascha.Bischoff at arm.com  Thu Dec 11 09:23:17 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Thu, 11 Dec 2025 17:23:17 +0000
Subject: [PATCH v2 4/6] KVM: arm64: Account for RES1 bits in
 DECLARE_FEAT_MAP() and co
In-Reply-To: <20251210173024.561160-5-maz@kernel.org>
References: <20251210173024.561160-1-maz@kernel.org>
	 <20251210173024.561160-5-maz@kernel.org>
Message-ID: <91a09142b6cb76ab68903095eefd5b9e17dfcf37.camel@arm.com>

On Wed, 2025-12-10 at 17:30 +0000, Marc Zyngier wrote:
> None of the registers we manage in the feature dependency
> infrastructure
> so far has any RES1 bit. This is about to change, as VTCR_EL2 has
> its bit 31 being RES1.
> 
> In order to not fail the consistency checks by not describing a bit,
> add RES1 bits to the set of immutable bits. This requires some extra
> surgery for the FGT handling, as we now need to track RES1 bits there
> as well.
> 
> There are no RES1 FGT bits *yet*. Watch this space.
> 
> Signed-off-by: Marc Zyngier <maz at kernel.org>

I've tested this change with my WIP vgic_v5 support, which indeed
introduces a RES1 FGT bit. I can confirm that the FGT support is now
working as I'd expect it to. Thanks for this change!

Tested-by: Sascha Bischoff <sascha.bischoff at arm.com>

Thanks,
Sascha

> ---
> ?arch/arm64/include/asm/kvm_host.h |? 1 +
> ?arch/arm64/kvm/config.c?????????? | 25 +++++++-------
> ?arch/arm64/kvm/emulate-nested.c?? | 55 +++++++++++++++++------------
> --
> ?3 files changed, 45 insertions(+), 36 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h
> b/arch/arm64/include/asm/kvm_host.h
> index ac7f970c78830..b552a1e03848c 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -638,6 +638,7 @@ struct fgt_masks {
> ?	u64		mask;
> ?	u64		nmask;
> ?	u64		res0;
> +	u64		res1;
> ?};
> ?
> ?extern struct fgt_masks hfgrtr_masks;
> diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
> index 24bb3f36e9d59..3845b188551b6 100644
> --- a/arch/arm64/kvm/config.c
> +++ b/arch/arm64/kvm/config.c
> @@ -16,14 +16,14 @@
> ? */
> ?struct reg_bits_to_feat_map {
> ?	union {
> -		u64	bits;
> -		u64	*res0p;
> +		u64		 bits;
> +		struct fgt_masks *masks;
> ?	};
> ?
> ?#define	NEVER_FGU	BIT(0)	/* Can trap, but never UNDEF
> */
> ?#define	CALL_FUNC	BIT(1)	/* Needs to evaluate tons of
> crap */
> ?#define	FIXED_VALUE	BIT(2)	/* RAZ/WI or RAO/WI in KVM
> */
> -#define	RES0_POINTER	BIT(3)	/* Pointer to RES0 value
> instead of bits */
> +#define	MASKS_POINTER	BIT(3)	/* Pointer to fgt_masks
> struct instead of bits */
> ?
> ?	unsigned long	flags;
> ?
> @@ -92,8 +92,8 @@ struct reg_feat_map_desc {
> ?#define NEEDS_FEAT_FIXED(m, ...)			\
> ?	__NEEDS_FEAT_FLAG(m, FIXED_VALUE, bits, __VA_ARGS__, 0)
> ?
> -#define NEEDS_FEAT_RES0(p, ...)				\
> -	__NEEDS_FEAT_FLAG(p, RES0_POINTER, res0p, __VA_ARGS__)
> +#define NEEDS_FEAT_MASKS(p, ...)				\
> +	__NEEDS_FEAT_FLAG(p, MASKS_POINTER, masks, __VA_ARGS__)
> ?
> ?/*
> ? * Declare the dependency between a set of bits and a set of
> features,
> @@ -109,19 +109,20 @@ struct reg_feat_map_desc {
> ?#define DECLARE_FEAT_MAP(n, r, m,
> f)					\
> ?	struct reg_feat_map_desc n =
> {					\
> ?		.name			=
> #r,				\
> -		.feat_map		= NEEDS_FEAT(~r##_RES0,
> f),?	\
> +		.feat_map		= NEEDS_FEAT(~(r##_RES0
> |	\
> +						?????? r##_RES1),
> f),	\
> ?		.bit_feat_map		=
> m,				\
> ?		.bit_feat_map_sz	=
> ARRAY_SIZE(m),		\
> ?	}
> ?
> ?/*
> ? * Specialised version of the above for FGT registers that have
> their
> - * RES0 masks described as struct fgt_masks.
> + * RESx masks described as struct fgt_masks.
> ? */
> ?#define DECLARE_FEAT_MAP_FGT(n, msk, m,
> f)				\
> ?	struct reg_feat_map_desc n =
> {					\
> ?		.name			=
> #msk,				\
> -		.feat_map		= NEEDS_FEAT_RES0(&msk.res0,
> f),\
> +		.feat_map		= NEEDS_FEAT_MASKS(&msk,
> f),	\
> ?		.bit_feat_map		=
> m,				\
> ?		.bit_feat_map_sz	=
> ARRAY_SIZE(m),		\
> ?	}
> @@ -1168,21 +1169,21 @@ static const DECLARE_FEAT_MAP(mdcr_el2_desc,
> MDCR_EL2,
> ?			????? mdcr_el2_feat_map, FEAT_AA64EL2);
> ?
> ?static void __init check_feat_map(const struct reg_bits_to_feat_map
> *map,
> -				? int map_size, u64 res0, const char
> *str)
> +				? int map_size, u64 resx, const char
> *str)
> ?{
> ?	u64 mask = 0;
> ?
> ?	for (int i = 0; i < map_size; i++)
> ?		mask |= map[i].bits;
> ?
> -	if (mask != ~res0)
> +	if (mask != ~resx)
> ?		kvm_err("Undefined %s behaviour, bits %016llx\n",
> -			str, mask ^ ~res0);
> +			str, mask ^ ~resx);
> ?}
> ?
> ?static u64 reg_feat_map_bits(const struct reg_bits_to_feat_map *map)
> ?{
> -	return map->flags & RES0_POINTER ? ~(*map->res0p) : map-
> >bits;
> +	return map->flags & MASKS_POINTER ? (map->masks->mask | map-
> >masks->nmask) : map->bits;
> ?}
> ?
> ?static void __init check_reg_desc(const struct reg_feat_map_desc *r)
> diff --git a/arch/arm64/kvm/emulate-nested.c
> b/arch/arm64/kvm/emulate-nested.c
> index 834f13fb1fb7d..75d49f83342a5 100644
> --- a/arch/arm64/kvm/emulate-nested.c
> +++ b/arch/arm64/kvm/emulate-nested.c
> @@ -2105,23 +2105,24 @@ static u32 encoding_next(u32 encoding)
> ?}
> ?
> ?#define FGT_MASKS(__n,
> __m)						\
> -	struct fgt_masks __n = { .str = #__m, .res0 = __m, }
> -
> -FGT_MASKS(hfgrtr_masks, HFGRTR_EL2_RES0);
> -FGT_MASKS(hfgwtr_masks, HFGWTR_EL2_RES0);
> -FGT_MASKS(hfgitr_masks, HFGITR_EL2_RES0);
> -FGT_MASKS(hdfgrtr_masks, HDFGRTR_EL2_RES0);
> -FGT_MASKS(hdfgwtr_masks, HDFGWTR_EL2_RES0);
> -FGT_MASKS(hafgrtr_masks, HAFGRTR_EL2_RES0);
> -FGT_MASKS(hfgrtr2_masks, HFGRTR2_EL2_RES0);
> -FGT_MASKS(hfgwtr2_masks, HFGWTR2_EL2_RES0);
> -FGT_MASKS(hfgitr2_masks, HFGITR2_EL2_RES0);
> -FGT_MASKS(hdfgrtr2_masks, HDFGRTR2_EL2_RES0);
> -FGT_MASKS(hdfgwtr2_masks, HDFGWTR2_EL2_RES0);
> +	struct fgt_masks __n = { .str = #__m, .res0 = __m ## _RES0,
> .res1 = __m ## _RES1 }
> +
> +FGT_MASKS(hfgrtr_masks, HFGRTR_EL2);
> +FGT_MASKS(hfgwtr_masks, HFGWTR_EL2);
> +FGT_MASKS(hfgitr_masks, HFGITR_EL2);
> +FGT_MASKS(hdfgrtr_masks, HDFGRTR_EL2);
> +FGT_MASKS(hdfgwtr_masks, HDFGWTR_EL2);
> +FGT_MASKS(hafgrtr_masks, HAFGRTR_EL2);
> +FGT_MASKS(hfgrtr2_masks, HFGRTR2_EL2);
> +FGT_MASKS(hfgwtr2_masks, HFGWTR2_EL2);
> +FGT_MASKS(hfgitr2_masks, HFGITR2_EL2);
> +FGT_MASKS(hdfgrtr2_masks, HDFGRTR2_EL2);
> +FGT_MASKS(hdfgwtr2_masks, HDFGWTR2_EL2);
> ?
> ?static __init bool aggregate_fgt(union trap_config tc)
> ?{
> ?	struct fgt_masks *rmasks, *wmasks;
> +	u64 rresx, wresx;
> ?
> ?	switch (tc.fgt) {
> ?	case HFGRTR_GROUP:
> @@ -2154,24 +2155,27 @@ static __init bool aggregate_fgt(union
> trap_config tc)
> ?		break;
> ?	}
> ?
> +	rresx = rmasks->res0 | rmasks->res1;
> +	if (wmasks)
> +		wresx = wmasks->res0 | wmasks->res1;
> +
> ?	/*
> ?	 * A bit can be reserved in either the R or W register, but
> ?	 * not both.
> ?	 */
> -	if ((BIT(tc.bit) & rmasks->res0) &&
> -	??? (!wmasks || (BIT(tc.bit) & wmasks->res0)))
> +	if ((BIT(tc.bit) & rresx) && (!wmasks || (BIT(tc.bit) &
> wresx)))
> ?		return false;
> ?
> ?	if (tc.pol)
> -		rmasks->mask |= BIT(tc.bit) & ~rmasks->res0;
> +		rmasks->mask |= BIT(tc.bit) & ~rresx;
> ?	else
> -		rmasks->nmask |= BIT(tc.bit) & ~rmasks->res0;
> +		rmasks->nmask |= BIT(tc.bit) & ~rresx;
> ?
> ?	if (wmasks) {
> ?		if (tc.pol)
> -			wmasks->mask |= BIT(tc.bit) & ~wmasks->res0;
> +			wmasks->mask |= BIT(tc.bit) & ~wresx;
> ?		else
> -			wmasks->nmask |= BIT(tc.bit) & ~wmasks-
> >res0;
> +			wmasks->nmask |= BIT(tc.bit) & ~wresx;
> ?	}
> ?
> ?	return true;
> @@ -2180,7 +2184,6 @@ static __init bool aggregate_fgt(union
> trap_config tc)
> ?static __init int check_fgt_masks(struct fgt_masks *masks)
> ?{
> ?	unsigned long duplicate = masks->mask & masks->nmask;
> -	u64 res0 = masks->res0;
> ?	int ret = 0;
> ?
> ?	if (duplicate) {
> @@ -2194,10 +2197,14 @@ static __init int check_fgt_masks(struct
> fgt_masks *masks)
> ?		ret = -EINVAL;
> ?	}
> ?
> -	masks->res0 = ~(masks->mask | masks->nmask);
> -	if (masks->res0 != res0)
> -		kvm_info("Implicit %s = %016llx, expecting
> %016llx\n",
> -			 masks->str, masks->res0, res0);
> +	if ((masks->res0 | masks->res1 | masks->mask | masks->nmask)
> != GENMASK(63, 0) ||
> +	??? (masks->res0 & masks->res1)? || (masks->res0 & masks-
> >mask) ||
> +	??? (masks->res0 & masks->nmask) || (masks->res1 & masks-
> >mask)? ||
> +	??? (masks->res1 & masks->nmask) || (masks->mask & masks-
> >nmask)) {
> +		kvm_info("Inconsistent masks for %s (%016llx,
> %016llx, %016llx, %016llx)\n",
> +			 masks->str, masks->res0, masks->res1,
> masks->mask, masks->nmask);
> +		masks->res0 = ~(masks->res1 | masks->mask | masks-
> >nmask);
> +	}
> ?
> ?	return ret;
> ?}


From Jason-JH.Lin at mediatek.com  Thu Dec 11 09:34:52 2025
From: Jason-JH.Lin at mediatek.com (=?utf-8?B?SmFzb24tSkggTGluICjmnpfnnb/npaUp?=)
Date: Thu, 11 Dec 2025 17:34:52 +0000
Subject: [PATCH v7 17/20] media: platform: mtk-mdp3: Use
 cmdq_pkt_jump_rel() without shift_pa
In-Reply-To: <ae08e53e055a238cde639dc9d9c7263fa296af5f.camel@ndufresne.ca>
References: <20250827114006.3310175-1-jason-jh.lin@mediatek.com>
	 <20250827114006.3310175-18-jason-jh.lin@mediatek.com>
	 <ae08e53e055a238cde639dc9d9c7263fa296af5f.camel@ndufresne.ca>
Message-ID: <8270743bbea41ec9fe7d694908ec0c677ed7ba09.camel@mediatek.com>

Hi Nicolas,

On Tue, 2025-12-09 at 16:01 -0500, Nicolas Dufresne wrote:
> Hi,
> 
> Le mercredi 27 ao?t 2025 ? 19:37 +0800, Jason-JH Lin a ?crit?:
> > With the removal of the shift_pa parameter,
> > cmdq_pkt_jump_rel_temp()
> > can be replaced by the new cmdq_pkt_jump_rel() without shift_pa.
> > 
> > Then, remove the cmdq_shift_pa variable in the mdp_dev structure
> > for
> > each mbox client.
> > 
> > Fixes: ade176534112 ("soc: mediatek: cmdq: Add parameter shift_pa
> > to cmdq_pkt_jump()")
> > Signed-off-by: Jason-JH Lin <jason-jh.lin at mediatek.com>
> > ---
> > ?drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c | 2 +-
> > ?drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c | 2 --
> > ?drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.h | 1 -
> > ?3 files changed, 1 insertion(+), 4 deletions(-)
> > 
> > diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c
> > b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c
> > index 7575ec376367..c35fe0e3a4d5 100644
> > --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c
> > +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c
> > @@ -638,7 +638,7 @@ static struct mdp_cmdq_cmd
> > *mdp_cmdq_prepare(struct mdp_dev *mdp,
> > ?		goto err_free_path;
> > ?	}
> > ?	cmdq_pkt_eoc(&cmd->pkt);
> > -	cmdq_pkt_jump_rel_temp(&cmd->pkt, CMDQ_INST_SIZE, mdp-
> > >cmdq_shift_pa[pp_idx]);
> > +	cmdq_pkt_jump_rel(&cmd->pkt, CMDQ_INST_SIZE);
> 
> That effectively revert another patch that is pending, and remove the
> use of the
> new cmdq_pkt_jump_rel_temp(). I don't follow what is doing on here, I
> think some
> context must be lost.
> 

Please forget about this patch. I separated this series to 5 different
series.

Please refer to series application order:
1. [Fixes] Refine DMA address handling for the command buffer
https://lore.kernel.org/all/20251022171847.379470-1-jason-jh.lin at mediatek.com/
2. [Series 1/4] Add GCE support for MT8196 and update CMDQ APIs
https://lore.kernel.org/all/20251031155838.1650833-1-jason-jh.lin at mediatek.com/
3. [Series 2/4] Migrate subsystems to new CMDQ APIs
https://lore.kernel.org/all/20251031160309.1654761-1-jason-jh.lin at mediatek.com/
4. [Series 3/4] Remove shift_pa from CMDQ jump functions
https://lore.kernel.org/all/20251031160712.1657810-1-jason-jh.lin at mediatek.com/
5. [Series 4/4] Remove deprecated CMDQ APIs 
https://lore.kernel.org/all/20251031160955.1659524-1-jason-jh.lin at mediatek.com/

Thanks!

Regards,
Jason-JH Lin

> Nicolas

From Jason-JH.Lin at mediatek.com  Thu Dec 11 09:37:15 2025
From: Jason-JH.Lin at mediatek.com (=?utf-8?B?SmFzb24tSkggTGluICjmnpfnnb/npaUp?=)
Date: Thu, 11 Dec 2025 17:37:15 +0000
Subject: [PATCH 5/5] media: platform: mtk-mdp3: Change cmdq_pkt_jump_rel()
 to cmdq_pkt_jump_rel_temp()
In-Reply-To: <e0144120e0943b94454b1cddd5359c34b5a15412.camel@ndufresne.ca>
References: <20251031160309.1654761-1-jason-jh.lin@mediatek.com>
	 <20251031160309.1654761-6-jason-jh.lin@mediatek.com>
	 <e0144120e0943b94454b1cddd5359c34b5a15412.camel@ndufresne.ca>
Message-ID: <380a7eee3a949a6fb28116820285cc895eb5d65b.camel@mediatek.com>

On Tue, 2025-12-09 at 15:47 -0500, Nicolas Dufresne wrote:
> Hi,
> 
> 
> Le samedi 01 novembre 2025 ? 00:02 +0800, Jason-JH Lin a ?crit?:
> > To facilitate the removal of the shift_pa parameter from
> > cmdq_pkt_jump_rel(), current users of cmdq_pkt_jump_rel() need to
> > transition to using cmdq_pkt_jump_rel_temp() before the API change
> > is implemented.
> > 
> > Signed-off-by: Jason-JH Lin <jason-jh.lin at mediatek.com>
> > Reviewed-by: AngeloGioacchino Del Regno
> > <angelogioacchino.delregno at collabora.com>
> > ---
> > ?drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c | 2 +-
> > ?1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c
> > b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c
> > index d0b0b072f953..5fc9263ccb78 100644
> > --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c
> > +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c
> > @@ -628,7 +628,7 @@ static struct mdp_cmdq_cmd
> > *mdp_cmdq_prepare(struct mdp_dev *mdp,
> > ?		goto err_free_path;
> > ?	}
> > ?	cmdq_pkt_eoc(&cmd->pkt);
> > -	cmdq_pkt_jump_rel(&cmd->pkt, CMDQ_INST_SIZE, mdp-
> > >cmdq_shift_pa[pp_idx]);
> > +	cmdq_pkt_jump_rel_temp(&cmd->pkt, CMDQ_INST_SIZE, mdp-
> > >cmdq_shift_pa[pp_idx]);
> 
> I cannot take that right now in the media tree, as it won't build.
> Can the SoC
> maintainer help me know if I just leave that on hold, or perhaps
> you'd like to
> take it ? (or its in next, and I just have to wait for next udpate?)
> 
> I also doubt patch 4/5 is make much of a difference without the soc
> changes ?
> 

Hi Angelo,

Can you help us? Thanks!

Regards,
Jason-JH Lin

> regards,
> Nicolas

From tan.siewert at hetzner.com  Thu Dec 11 10:12:14 2025
From: tan.siewert at hetzner.com (Tan Siewert)
Date: Thu, 11 Dec 2025 19:12:14 +0100
Subject: [PATCH v5 0/2] Add device tree for ASRock Rack ALTRAD8 BMC
In-Reply-To: <20251211165700.29206-1-rebecca@bsdio.com>
References: <20251211165700.29206-1-rebecca@bsdio.com>
Message-ID: <9b58d801-43b5-4c5b-b734-a83c86912df4@hetzner.com>

On 11.12.25 17:56, Rebecca Cran wrote:
> The ASRock Rack ALTRAD8 BMC is an Aspeed AST2500-based BMC for the
> ALTRAD8UD-1L2T and ALTRAD8UD2-1L2Q boards with an Ampere Altra
> processor. The BMC runs OpenBMC.
> 
> These patches add a device tree and binding for the BMC.
> 
> **Changes between v4 and v5**
> 
> - Removed the uartx-mode1 GPIOs, which were wrong.
> - Fixed button-power-n GPIO name.
> - Removed backslash from end of line, which isn't needed.
> - Removed duplicate/wrong bmc heartbeat GPIO.
> 
> **Testing**
> 
> Ran `make ARCH=arm CHECK_DTBS=y aspeed/aspeed-bmc-asrock-altrad8.dtb`.
> 
> 
> Rebecca Cran (2):
>    dt-bindings: arm: aspeed: add ASRock Rack ALTRAD8 board
>    ARM: dts: aspeed: add device tree for ASRock Rack ALTRAD8 BMC
> 
>   Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml |   1 +
>   arch/arm/boot/dts/aspeed/Makefile                        |   1 +
>   arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts   | 624 ++++++++++++++++++++
>   3 files changed, 626 insertions(+)
>   create mode 100644 arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts
> 

For the series,

Tested-by: Tan Siewert <tan.siewert at hetzner.com>
Reviewed-by: Tan Siewert <tan.siewert at hetzner.com>

Many thanks, Rebecca!

-- Tan
-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature.asc
Type: application/pgp-signature
Size: 840 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251211/c8783330/attachment-0001.sig>

From robh at kernel.org  Thu Dec 11 10:42:40 2025
From: robh at kernel.org (Rob Herring)
Date: Thu, 11 Dec 2025 12:42:40 -0600
Subject: [PATCH v2] arm64: dts: broadcom: bcm2712: rpi-5: Add ethernet0 alias
In-Reply-To: <20251102111443.18206-1-laurent.pinchart@ideasonboard.com>
References: <20251102111443.18206-1-laurent.pinchart@ideasonboard.com>
Message-ID: <CAL_JsqJg4aYGyd49UAAPBw+FGpmGxV5JkdkXp2FK_7Gt+7DLZA@mail.gmail.com>

On Sun, Nov 2, 2025 at 5:15?AM Laurent Pinchart
<laurent.pinchart at ideasonboard.com> wrote:
>
> The RP1 ethernet controller DT node contains a local-mac-address
> property to pass the MAC address from the boot loader to the kernel. The
> boot loader does not fill the MAC address as the ethernet0 alias is
> missing. Add it.

My change here[1] is going to effectively revert this. The RP1 stuff
needs to either be an overlay or not. We don't need both ways.
/aliases don't work for overlays. I suppose that could be added as a
fixup when applying. The kernel also assumes aliases are not dynamic
and uses indexes which aren't present, so even if it did work there
would still be problems. OTOH, if the bootloader might use the
ethernet controller, then why would this ever be an overlay in the
first place?

Turns out digging into RP1 stuff, it is a mess and needs reworking[2].

Right now, I just want the warning gone so I don't get further complaints[3].

Rob

[1] https://lore.kernel.org/all/20251117211503.728354-2-robh at kernel.org/
[2] https://lore.kernel.org/all/CAL_JsqJUzB71QdMcxJtNZ7raoPcK+SfTh7EVzGmk=syo8xLKQw at mail.gmail.com/
[3] https://lore.kernel.org/all/CAHk-=wi+ge-gtCg+iLd6dgjisGchjtsKY8AXG9tXGOxqVv8Fkw at mail.gmail.com/


From nicolas.frattaroli at collabora.com  Thu Dec 11 11:34:22 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 11 Dec 2025 20:34:22 +0100
Subject: [PATCH v5 04/17] drm/bridge: Act on the DRM color format property
In-Reply-To: <20251209-smart-oarfish-of-wind-0c1c8b@houat>
References: <20251128-color-format-v5-0-63e82f1db1e1@collabora.com>
 <20251128-color-format-v5-4-63e82f1db1e1@collabora.com>
 <20251209-smart-oarfish-of-wind-0c1c8b@houat>
Message-ID: <3772903.e9J7NaK4W3@workhorse>

On Tuesday, 9 December 2025 15:27:28 Central European Standard Time Maxime Ripard wrote:
> Hi,
> 
> On Fri, Nov 28, 2025 at 10:05:40PM +0100, Nicolas Frattaroli wrote:
> > The new DRM color format property allows userspace to request a specific
> > color format on a connector. In turn, this fills the connector state's
> > color_format member to switch color formats.
> > 
> > Make drm_bridges consider the color_format set in the connector state
> > during the atomic bridge check. Specifically, reject any output bus
> > formats that do not correspond to the requested color format.
> > 
> > Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
> > ---
> >  drivers/gpu/drm/drm_bridge.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 45 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> > index 8f355df883d8..8aac9747f35e 100644
> > --- a/drivers/gpu/drm/drm_bridge.c
> > +++ b/drivers/gpu/drm/drm_bridge.c
> > @@ -1052,6 +1052,47 @@ static int select_bus_fmt_recursive(struct drm_bridge *first_bridge,
> >  	return ret;
> >  }
> >  
> > +static bool __pure bus_format_is_color_fmt(u32 bus_fmt, enum drm_color_format fmt)
> > +{
> > +	if (fmt == DRM_COLOR_FORMAT_AUTO)
> > +		return true;
> > +
> > +	switch (bus_fmt) {
> > +	case MEDIA_BUS_FMT_FIXED:
> > +		return true;
> > +	case MEDIA_BUS_FMT_RGB888_1X24:
> > +	case MEDIA_BUS_FMT_RGB101010_1X30:
> > +	case MEDIA_BUS_FMT_RGB121212_1X36:
> > +	case MEDIA_BUS_FMT_RGB161616_1X48:
> > +		return fmt == DRM_COLOR_FORMAT_RGB444;
> > +	case MEDIA_BUS_FMT_YUV8_1X24:
> > +	case MEDIA_BUS_FMT_YUV10_1X30:
> > +	case MEDIA_BUS_FMT_YUV12_1X36:
> > +	case MEDIA_BUS_FMT_YUV16_1X48:
> > +		return fmt == DRM_COLOR_FORMAT_YCBCR444;
> > +	case MEDIA_BUS_FMT_UYVY8_1X16:
> > +	case MEDIA_BUS_FMT_VYUY8_1X16:
> > +	case MEDIA_BUS_FMT_YUYV8_1X16:
> > +	case MEDIA_BUS_FMT_YVYU8_1X16:
> > +	case MEDIA_BUS_FMT_UYVY10_1X20:
> > +	case MEDIA_BUS_FMT_YUYV10_1X20:
> > +	case MEDIA_BUS_FMT_VYUY10_1X20:
> > +	case MEDIA_BUS_FMT_YVYU10_1X20:
> > +	case MEDIA_BUS_FMT_UYVY12_1X24:
> > +	case MEDIA_BUS_FMT_VYUY12_1X24:
> > +	case MEDIA_BUS_FMT_YUYV12_1X24:
> > +	case MEDIA_BUS_FMT_YVYU12_1X24:
> > +		return fmt == DRM_COLOR_FORMAT_YCBCR422;
> > +	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
> > +	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
> > +	case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
> > +	case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
> > +		return fmt == DRM_COLOR_FORMAT_YCBCR420;
> > +	default:
> > +		return false;
> > +	}
> > +}
> > +
> >  /*
> >   * This function is called by &drm_atomic_bridge_chain_check() just before
> >   * calling &drm_bridge_funcs.atomic_check() on all elements of the chain.
> > @@ -1137,6 +1178,10 @@ drm_atomic_bridge_chain_select_bus_fmts(struct drm_bridge *bridge,
> >  	}
> >  
> >  	for (i = 0; i < num_out_bus_fmts; i++) {
> > +		if (!bus_format_is_color_fmt(out_bus_fmts[i], conn_state->color_format)) {
> > +			ret = -ENOTSUPP;
> > +			continue;
> > +		}
> 
> Sorry, I'm struggling a bit to understand how this would work if a bridge both supports the bus
> format selection and HDMI state helpers? Can you expand on it?

I have very little idea of whether this makes conceptual sense. The
hope is that by working backwards from the last bridge and only
accepting either fixed formats or something that corresponds to
the target color format, we don't claim that a setup can do a
colour format if the whole bridge chain isn't able to do it.

Of course, format conversions along the bridge chain where one
input format can be converted to a set of output formats by some
bridge will throw a massive wrench into this. And this is all
assuming that the bus format is in any way related to the color
format that will be sent out on the wire.

In practice, I don't have any hardware where whatever counts as
a "bridge" is an actually more involved setup than just the TX
controller. I tried looking into getting a board with one of the
supported DSI-to-HDMI bridge chips so I can at least test how it
would work in such a scenario, and I got one, but I'd need to make
my own flat flex PCB to adapt it to the pinout of my SBC's DSI
port.

So yeah I don't know how it's supposed to work, I just know this
works for the case I'm working with, and any more complex case
is literally unobtanium hardware which I'm not going to bother
blowing days on maybe making a cable for when I'm already touching
three different GPU drivers here and the intel-gfx-ci is screaming
into my inbox about vague failures in unrelated codepaths in its
native language, Klingon.

Which is all to say: is there a virtual drm bridge driver that
exists, where I can set what formats it supports on the input
and on the output, so that I can actually get a feel for how this
is conceptually supposed to work without needing special hardware?

Better yet: do you have a specific setup in mind where you know
this approach does not work?

> 
> Maxime
> 






From robh at kernel.org  Thu Dec 11 11:38:53 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Thu, 11 Dec 2025 13:38:53 -0600
Subject: [PATCH v2] arm64: broadcom: bcm2712: Drop rp1 overlay
Message-ID: <20251211193854.1778221-1-robh@kernel.org>

It's a requirement that DT overlays be applied at build time in order to
validate them as overlays are not validated on their own, but the
rp1.dtbo is not applied to anything. The rp1.dtso overlay doesn't work
on its own as there are additional settings needed as seen in
bcm2712-rpi-5-b.dts. In addition, the 'rp1_nexus' node is applied to the
wrong place in the DT as it should be under a PCIe root port rather than
the host bridge. There's also a duplicate overlay in drivers/misc/rp1/.

For these reasons, just drop the overlay to fix the warning until all
these issues can be fixed.

Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
---
The missing applying of rp1.dtbo is now a warning in v6.19-rc1. This
should be sent to Linus ASAP.

v2:
 - Drop the overlay instead of trying to rework. The addition of
   ethernet0 alias complicates that.
---
 arch/arm64/boot/dts/broadcom/Makefile | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/broadcom/Makefile b/arch/arm64/boot/dts/broadcom/Makefile
index 83d45afc6588..031875a277d7 100644
--- a/arch/arm64/boot/dts/broadcom/Makefile
+++ b/arch/arm64/boot/dts/broadcom/Makefile
@@ -14,8 +14,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-400.dtb \
 			      bcm2837-rpi-3-b.dtb \
 			      bcm2837-rpi-3-b-plus.dtb \
 			      bcm2837-rpi-cm3-io3.dtb \
-			      bcm2837-rpi-zero-2-w.dtb \
-			      rp1.dtbo
+			      bcm2837-rpi-zero-2-w.dtb
 
 subdir-y	+= bcmbca
 subdir-y	+= northstar2
-- 
2.51.0



From nicolas.frattaroli at collabora.com  Thu Dec 11 11:42:00 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 11 Dec 2025 20:42:00 +0100
Subject: [PATCH v5 05/17] drm/display: hdmi-state-helper: Act on color format DRM
 property
In-Reply-To: <20251209-uptight-radical-chupacabra-ac3d6d@houat>
References: <20251128-color-format-v5-0-63e82f1db1e1@collabora.com>
 <20251128-color-format-v5-5-63e82f1db1e1@collabora.com>
 <20251209-uptight-radical-chupacabra-ac3d6d@houat>
Message-ID: <3084118.iZASKD2KPV@workhorse>

On Tuesday, 9 December 2025 15:16:58 Central European Standard Time Maxime Ripard wrote:
> On Fri, Nov 28, 2025 at 10:05:41PM +0100, Nicolas Frattaroli wrote:
> > With the introduction of the "color format" DRM property, which allows
> > userspace to request a specific color format, the HDMI state helper
> > should implement this.
> > 
> > Implement it by checking whether the property is set and set to
> > something other than auto. If so, pass the requested color format, and
> > otherwise set RGB.
> > 
> > Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
> > ---
> >  drivers/gpu/drm/display/drm_hdmi_state_helper.c | 12 +++++++++++-
> >  1 file changed, 11 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> > index a561f124be99..5da956bdd68c 100644
> > --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> > +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> > @@ -649,11 +649,21 @@ hdmi_compute_config(const struct drm_connector *connector,
> >  	unsigned int max_bpc = clamp_t(unsigned int,
> >  				       conn_state->max_bpc,
> >  				       8, connector->max_bpc);
> > +	enum hdmi_colorspace hdmi_colorspace =
> > +		drm_color_format_to_hdmi_colorspace(conn_state->color_format);
> >  	int ret;
> >  
> >  	ret = hdmi_compute_format_bpc(connector, conn_state, mode, max_bpc,
> > -				      HDMI_COLORSPACE_RGB);
> > +				      hdmi_colorspace);
> >  	if (ret) {
> > +		/* If a color format was explicitly requested, don't fall back */
> > +		if (conn_state->color_format) {
> > +			drm_dbg_kms(connector->dev,
> > +				    "Explicitly set color format '%s' doesn't work.\n",
> > +				    drm_get_color_format_name(conn_state->color_format));
> > +			return ret;
> > +		}
> > +
> 
> I think the following would be more readable:
> 
> 
> if (conn_state->color_format && conn_state->color_format != DRM_COLOR_FORMAT_AUTO) {
>     enum hdmi_colorspace hdmi_colorspace =
>         drm_color_format_to_hdmi_colorspace(conn_state->color_format);
> 
>     return hdmi_compute_format_bpc(connector, conn_state, mode, max_bpc, hdmi_colorspace)
> }
> 
> ret = ret = hdmi_compute_format_bpc(connector, conn_state, mode, max_bpc,
>                                     HDMI_COLORSPACE_RGB);
> 
> ...

I think I get what you mean: if conn_state->color_format is set, return
directly, instead of bailing out in the fallback path. I can do that.

However, `conn_state->color_format && conn_state->color_format != DRM_COLOR_FORMAT_AUTO`
is redundant now as of v5 since DRM_COLOR_FORMAT_AUTO is 0 (and
I use its falsy nature in many other places, and don't intend to
stop doing that).

> 
> Maxime
> 






From robh at kernel.org  Thu Dec 11 11:56:28 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Thu, 11 Dec 2025 13:56:28 -0600
Subject: [PATCH RFC 09/16] dt-bindings: bus: aspeed: Require syscon for
 AST2600 AHB controller
In-Reply-To: <20251211-dev-dt-warnings-all-v1-9-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
 <20251211-dev-dt-warnings-all-v1-9-21b18b9ada77@codeconstruct.com.au>
Message-ID: <176548298699.1799665.1259025609428986424.robh@kernel.org>


On Thu, 11 Dec 2025 17:45:51 +0900, Andrew Jeffery wrote:
> The AST2600's ACRY (eliptic curve and RSA crypto engine) requires access
> to configuration exposed by the AHB controller. The devicetree already
> describes the AHB controller node as a syscon, so require this in the
> binding to satisfy the ACRY relationship.
> 
> Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
> ---
>  Documentation/devicetree/bindings/bus/aspeed,ast2600-ahbc.yaml | 8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)
> 

Applied, thanks!



From robh at kernel.org  Thu Dec 11 11:57:38 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Thu, 11 Dec 2025 13:57:38 -0600
Subject: [PATCH RFC 10/16] dt-bindings: crypto: Document aspeed,ahbc
 property for Aspeed ACRY
In-Reply-To: <20251211-dev-dt-warnings-all-v1-10-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
 <20251211-dev-dt-warnings-all-v1-10-21b18b9ada77@codeconstruct.com.au>
Message-ID: <176548305816.1801207.6301308659120970227.robh@kernel.org>


On Thu, 11 Dec 2025 17:45:52 +0900, Andrew Jeffery wrote:
> The g6 DTSI already provides the property and the driver errors out if
> the AHB controller's syscon can't be located, so define the property and
> mark it as required.
> 
> Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
> ---
>  Documentation/devicetree/bindings/crypto/aspeed,ast2600-acry.yaml | 7 +++++++
>  1 file changed, 7 insertions(+)
> 

Applied, thanks!



From robh at kernel.org  Thu Dec 11 11:57:57 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Thu, 11 Dec 2025 13:57:57 -0600
Subject: [PATCH RFC 14/16] dt-bindings: iio: adc: Allow interrupts
 property for AST2600
In-Reply-To: <20251211-dev-dt-warnings-all-v1-14-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
 <20251211-dev-dt-warnings-all-v1-14-21b18b9ada77@codeconstruct.com.au>
Message-ID: <176548307744.1801669.10354753289483698774.robh@kernel.org>


On Thu, 11 Dec 2025 17:45:56 +0900, Andrew Jeffery wrote:
> The device has interrupts allocated according to the datasheet, and
> the devicetree already defines the interrupt property. Address existing
> warnings by allowing the property.
> 
> Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
> ---
>  Documentation/devicetree/bindings/iio/adc/aspeed,ast2600-adc.yaml | 3 +++
>  1 file changed, 3 insertions(+)
> 

Acked-by: Rob Herring (Arm) <robh at kernel.org>



From nicolas.frattaroli at collabora.com  Thu Dec 11 11:59:14 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 11 Dec 2025 20:59:14 +0100
Subject: [PATCH v5 06/17] drm/display: hdmi-state-helper: Try subsampling in
 mode_valid
In-Reply-To: <20251209-dramatic-caiman-of-luck-db9d0f@houat>
References: <20251128-color-format-v5-0-63e82f1db1e1@collabora.com>
 <20251128-color-format-v5-6-63e82f1db1e1@collabora.com>
 <20251209-dramatic-caiman-of-luck-db9d0f@houat>
Message-ID: <9409315.NyiUUSuA9g@workhorse>

On Tuesday, 9 December 2025 15:18:25 Central European Standard Time Maxime Ripard wrote:
> On Fri, Nov 28, 2025 at 10:05:42PM +0100, Nicolas Frattaroli wrote:
> > drm_hdmi_connector_mode_valid assumes modes are only valid if they work
> > with RGB. The reality is more complex however: YCbCr 4:2:0
> > chroma-subsampled modes only require half the pixel clock that the same
> > mode would require in RGB.
> > 
> > This leads to drm_hdmi_connector_mode_valid rejecting perfectly valid
> > 420-only modes.
> > 
> > Fix this by checking whether the mode is 420-only first. If so, then
> > proceed by checking it with HDMI_COLORSPACE_YUV420 so long as the
> > connector has legalized 420, otherwise error out. If the mode is not
> > 420-only, check with RGB as was previously always the case.
> > 
> > Fixes: 47368ab437fd ("drm/display: hdmi: add generic mode_valid helper")
> > Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
> > ---
> >  drivers/gpu/drm/display/drm_hdmi_state_helper.c | 12 +++++++++++-
> >  1 file changed, 11 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> > index 5da956bdd68c..1800e00b30c5 100644
> > --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> > +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> > @@ -892,8 +892,18 @@ drm_hdmi_connector_mode_valid(struct drm_connector *connector,
> >  			      const struct drm_display_mode *mode)
> >  {
> >  	unsigned long long clock;
> > +	enum hdmi_colorspace fmt;
> > +
> > +	if (drm_mode_is_420_only(&connector->display_info, mode)) {
> > +		if (connector->ycbcr_420_allowed)
> > +			fmt = HDMI_COLORSPACE_YUV420;
> > +		else
> > +			return MODE_NO_420;
> > +	} else {
> > +		fmt = HDMI_COLORSPACE_RGB;
> > +	}
> >  
> > -	clock = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_RGB);
> > +	clock = drm_hdmi_compute_mode_clock(mode, 8, fmt);
> 
> I agree on principle, but we need to have a test for this.

I'd like to change `drm_mode_is_420_only` to `drm_mode_is_420` in
the next revision, and modify the control flow to work correctly
in this case, because rejecting 420-also modes on the basis that
we can't do them in RGB isn't correct either.

But my concern with adding yet more tests is that I found this bug
in a function unrelated to the series while adding tests you asked
for, because the tests relied on this function to not be broken as
part of the test setup. Yes, I was not be able to get any 4:2:0
modes on the test connector in the kunit tests because
drm_hdmi_connector_mode_valid helpfully discarded all of them.

So now I am wondering whether adding yet more tests will uncover
more bugs in functions unrelated to implementing the "color format"
property, that were only called because the new test required them
to set up some test fixture. And then I have to add another fix and
another test to this series, rinse and repeat.

Can we just agree that I am not going to expand the scope of this
series any further? If you want me to send a follow-up series that
adds tests to some of the hdmi state helper functions, then I can
do that, but I don't want to do it as a precondition for the 17
other patches in this series to get merged.

> 
> Maxime
> 






From nicolas.dufresne at collabora.com  Thu Dec 11 12:11:34 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Thu, 11 Dec 2025 15:11:34 -0500
Subject: [PATCH v6 02/10] media: mediatek: decoder: Add a new platform
 data member
In-Reply-To: <20251202074038.3173-3-kyrie.wu@mediatek.com>
References: <20251202074038.3173-1-kyrie.wu@mediatek.com>
	 <20251202074038.3173-3-kyrie.wu@mediatek.com>
Message-ID: <777147df01b9d939ba86a9a006e3615d6478a773.camel@collabora.com>

Hi,

Le mardi 02 d?cembre 2025 ? 15:40 +0800, Kyrie Wu a ?crit?:
> Add a new platform data member to indicate each decoder IC
> to avoid the chip name definition keep growing.
> 
> Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
> ---
> ?.../mediatek/vcodec/decoder/mtk_vcodec_dec.h? |?? 5 +
> ?.../vcodec/decoder/mtk_vcodec_dec_drv.c?????? |? 35 +----
> ?.../vcodec/decoder/mtk_vcodec_dec_drv.h?????? |? 15 +-
> ?.../vcodec/decoder/mtk_vcodec_dec_hw.c??????? |?? 2 +-
> ?.../vcodec/decoder/mtk_vcodec_dec_stateful.c? |?? 1 +
> ?.../vcodec/decoder/mtk_vcodec_dec_stateless.c | 137 +++++++++++++++---
> ?6 files changed, 131 insertions(+), 64 deletions(-)
> 
> diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.h b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.h
> index 1af075fc0194..80cb46f1cded 100644
> --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.h
> +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.h
> @@ -69,6 +69,11 @@ extern const struct v4l2_m2m_ops mtk_vdec_m2m_ops;
> ?extern const struct media_device_ops mtk_vcodec_media_ops;
> ?extern const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata;
> ?extern const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata;
> +extern const struct mtk_vcodec_dec_pdata mtk_vdec_8186_pdata;
> +extern const struct mtk_vcodec_dec_pdata mtk_vdec_8188_pdata;
> +extern const struct mtk_vcodec_dec_pdata mtk_vdec_8192_pdata;
> +extern const struct mtk_vcodec_dec_pdata mtk_vdec_8195_pdata;
> +extern const struct mtk_vcodec_dec_pdata mtk_vdec_8196_pdata;
> ?extern const struct mtk_vcodec_dec_pdata mtk_lat_sig_core_pdata;
> ?extern const struct mtk_vcodec_dec_pdata mtk_vdec_single_core_pdata;
> ?
> diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
> index 6fb05bb00641..d7a269045fd6 100644
> --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
> +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
> @@ -331,24 +331,7 @@ static const struct v4l2_file_operations mtk_vcodec_fops = {
> ?
> ?static void mtk_vcodec_dec_get_chip_name(struct mtk_vcodec_dec_dev *vdec_dev)
> ?{
> -	struct device *dev = &vdec_dev->plat_dev->dev;
> -
> -	if (of_device_is_compatible(dev->of_node, "mediatek,mt8173-vcodec-dec"))
> -		vdec_dev->chip_name = MTK_VDEC_MT8173;
> -	else if (of_device_is_compatible(dev->of_node, "mediatek,mt8183-vcodec-dec"))
> -		vdec_dev->chip_name = MTK_VDEC_MT8183;
> -	else if (of_device_is_compatible(dev->of_node, "mediatek,mt8192-vcodec-dec"))
> -		vdec_dev->chip_name = MTK_VDEC_MT8192;
> -	else if (of_device_is_compatible(dev->of_node, "mediatek,mt8195-vcodec-dec"))
> -		vdec_dev->chip_name = MTK_VDEC_MT8195;
> -	else if (of_device_is_compatible(dev->of_node, "mediatek,mt8186-vcodec-dec"))
> -		vdec_dev->chip_name = MTK_VDEC_MT8186;
> -	else if (of_device_is_compatible(dev->of_node, "mediatek,mt8188-vcodec-dec"))
> -		vdec_dev->chip_name = MTK_VDEC_MT8188;
> -	else if (of_device_is_compatible(dev->of_node, "mediatek,mt8196-vcodec-dec"))
> -		vdec_dev->chip_name = MTK_VDEC_MT8196;
> -	else
> -		vdec_dev->chip_name = MTK_VDEC_INVAL;
> +	vdec_dev->chip_name = vdec_dev->vdec_pdata->chip_name;
> ?}
> ?
> ?static int mtk_vcodec_probe(struct platform_device *pdev)
> @@ -367,10 +350,6 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
> ?	dev->plat_dev = pdev;
> ?
> ?	mtk_vcodec_dec_get_chip_name(dev);
> -	if (dev->chip_name == MTK_VDEC_INVAL) {
> -		dev_err(&pdev->dev, "Failed to get decoder chip name");
> -		return -EINVAL;
> -	}
> ?
> ?	dev->vdec_pdata = of_device_get_match_data(&pdev->dev);
> ?	if (!of_property_read_u32(pdev->dev.of_node, "mediatek,vpu",
> @@ -387,7 +366,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
> ?		return -ENODEV;
> ?	}
> ?	dma_set_max_seg_size(&pdev->dev, UINT_MAX);
> -	if (dev->chip_name == MTK_VDEC_MT8196) {
> +	if (dev->chip_name == 8196) {
> ?		ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(36));
> ?		if (ret) {
> ?			dev_err(&pdev->dev, "Failed to enable 36-bit DMA: %d\n", ret);
> @@ -556,23 +535,23 @@ static const struct of_device_id mtk_vcodec_match[] = {
> ?	},
> ?	{
> ?		.compatible = "mediatek,mt8192-vcodec-dec",
> -		.data = &mtk_lat_sig_core_pdata,
> +		.data = &mtk_vdec_8192_pdata,
> ?	},
> ?	{
> ?		.compatible = "mediatek,mt8186-vcodec-dec",
> -		.data = &mtk_vdec_single_core_pdata,
> +		.data = &mtk_vdec_8186_pdata,
> ?	},
> ?	{
> ?		.compatible = "mediatek,mt8195-vcodec-dec",
> -		.data = &mtk_lat_sig_core_pdata,
> +		.data = &mtk_vdec_8195_pdata,
> ?	},
> ?	{
> ?		.compatible = "mediatek,mt8188-vcodec-dec",
> -		.data = &mtk_lat_sig_core_pdata,
> +		.data = &mtk_vdec_8188_pdata,
> ?	},
> ?	{
> ?		.compatible = "mediatek,mt8196-vcodec-dec",
> -		.data = &mtk_lat_sig_core_pdata,
> +		.data = &mtk_vdec_8196_pdata,
> ?	},
> ?	{},
> ?};
> diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h
> index 429b32952194..2dbde8d00e6f 100644
> --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h
> +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h
> @@ -19,17 +19,6 @@
> ?#define IS_VDEC_INNER_RACING(capability) ((capability) & MTK_VCODEC_INNER_RACING)
> ?#define IS_VDEC_SUPPORT_EXT(capability) ((capability) & MTK_VDEC_IS_SUPPORT_EXT)
> ?
> -enum mtk_vcodec_dec_chip_name {
> -	MTK_VDEC_INVAL = 0,
> -	MTK_VDEC_MT8173 = 8173,
> -	MTK_VDEC_MT8183 = 8183,
> -	MTK_VDEC_MT8186 = 8186,
> -	MTK_VDEC_MT8188 = 8188,
> -	MTK_VDEC_MT8192 = 8192,
> -	MTK_VDEC_MT8195 = 8195,
> -	MTK_VDEC_MT8196 = 8196,
> -};
> -
> ?/*
> ? * enum mtk_vdec_format_types - Structure used to get supported
> ? *		? format types according to decoder capability
> @@ -106,6 +95,7 @@ struct vdec_pic_info {
> ? *
> ? * @is_subdev_supported: whether support parent-node architecture(subdev)
> ? * @uses_stateless_api: whether the decoder uses the stateless API with requests
> + * @chip_name: platforms configuration values
> ? */
> ?struct mtk_vcodec_dec_pdata {
> ?	void (*init_vdec_params)(struct mtk_vcodec_dec_ctx *ctx);
> @@ -127,6 +117,7 @@ struct mtk_vcodec_dec_pdata {
> ?
> ?	bool is_subdev_supported;
> ?	bool uses_stateless_api;
> +	unsigned int chip_name;
> ?};
> ?
> ?/**
> @@ -307,7 +298,7 @@ struct mtk_vcodec_dec_dev {
> ?	struct mutex dec_racing_info_mutex;
> ?	struct mtk_vcodec_dbgfs dbgfs;
> ?
> -	enum mtk_vcodec_dec_chip_name chip_name;
> +	unsigned int chip_name;
> ?};
> ?
> ?static inline struct mtk_vcodec_dec_ctx *fh_to_dec_ctx(struct v4l2_fh *fh)
> diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_hw.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_hw.c
> index e4e527fe54dc..a926dc14d39d 100644
> --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_hw.c
> +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_hw.c
> @@ -76,7 +76,7 @@ static void mtk_vdec_hw_clean_xpc(struct mtk_vdec_hw_dev *dev)
> ?{
> ?	u32 val, mask, addr = VDEC_XPC_CLEAN_ADDR;
> ?
> -	if (dev->main_dev->chip_name != MTK_VDEC_MT8196)
> +	if (dev->main_dev->chip_name != 8196)
> ?		return;
> ?
> ?	val = dev->hw_idx == MTK_VDEC_LAT0 ? VDEC_XPC_LAT_VAL : VDEC_XPC_CORE_VAL;
> diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c
> index aa9bdee7a96c..8ddb61670dc6 100644
> --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c
> +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c
> @@ -618,4 +618,5 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata = {
> ?	.flush_decoder = mtk_vdec_flush_decoder,
> ?	.is_subdev_supported = false,
> ?	.hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
> +	.chip_name = 8173,
> ?};
> diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
> index c1cef78471a9..d249a8774948 100644
> --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
> +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
> @@ -550,16 +550,16 @@ static void mtk_vcodec_dec_fill_h264_level(struct v4l2_ctrl_config *cfg,
> ?					?? struct mtk_vcodec_dec_ctx *ctx)
> ?{
> ?	switch (ctx->dev->chip_name) {
> -	case MTK_VDEC_MT8192:
> -	case MTK_VDEC_MT8188:
> +	case 8192:
> +	case 8188:
> ?		cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_5_2;
> ?		break;
> -	case MTK_VDEC_MT8195:
> -	case MTK_VDEC_MT8196:
> +	case 8195:
> +	case 8196:
> ?		cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_6_0;
> ?		break;
> -	case MTK_VDEC_MT8183:
> -	case MTK_VDEC_MT8186:
> +	case 8183:
> +	case 8186:
> ?		cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_4_2;
> ?		break;
> ?	default:
> @@ -572,9 +572,9 @@ static void mtk_vcodec_dec_fill_h264_profile(struct v4l2_ctrl_config *cfg,
> ?					???? struct mtk_vcodec_dec_ctx *ctx)
> ?{
> ?	switch (ctx->dev->chip_name) {
> -	case MTK_VDEC_MT8188:
> -	case MTK_VDEC_MT8195:
> -	case MTK_VDEC_MT8196:
> +	case 8188:
> +	case 8195:
> +	case 8196:
> ?		cfg->max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10;
> ?		break;
> ?	default:
> @@ -587,11 +587,11 @@ static void mtk_vcodec_dec_fill_h265_level(struct v4l2_ctrl_config *cfg,
> ?					?? struct mtk_vcodec_dec_ctx *ctx)
> ?{
> ?	switch (ctx->dev->chip_name) {
> -	case MTK_VDEC_MT8188:
> +	case 8188:
> ?		cfg->max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1;
> ?		break;
> -	case MTK_VDEC_MT8195:
> -	case MTK_VDEC_MT8196:
> +	case 8195:
> +	case 8196:
> ?		cfg->max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2;
> ?		break;
> ?	default:
> @@ -604,9 +604,9 @@ static void mtk_vcodec_dec_fill_h265_profile(struct v4l2_ctrl_config *cfg,
> ?					???? struct mtk_vcodec_dec_ctx *ctx)
> ?{
> ?	switch (ctx->dev->chip_name) {
> -	case MTK_VDEC_MT8188:
> -	case MTK_VDEC_MT8195:
> -	case MTK_VDEC_MT8196:
> +	case 8188:
> +	case 8195:
> +	case 8196:
> ?		cfg->max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10;
> ?		break;
> ?	default:
> @@ -619,15 +619,15 @@ static void mtk_vcodec_dec_fill_vp9_level(struct v4l2_ctrl_config *cfg,
> ?					? struct mtk_vcodec_dec_ctx *ctx)
> ?{
> ?	switch (ctx->dev->chip_name) {
> -	case MTK_VDEC_MT8192:
> -	case MTK_VDEC_MT8188:
> +	case 8192:
> +	case 8188:
> ?		cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_5_1;
> ?		break;
> -	case MTK_VDEC_MT8195:
> -	case MTK_VDEC_MT8196:
> +	case 8195:
> +	case 8196:
> ?		cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2;
> ?		break;
> -	case MTK_VDEC_MT8186:
> +	case 8186:
> ?		cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_4_1;
> ?		break;
> ?	default:
> @@ -640,9 +640,9 @@ static void mtk_vcodec_dec_fill_vp9_profile(struct v4l2_ctrl_config *cfg,
> ?					??? struct mtk_vcodec_dec_ctx *ctx)
> ?{
> ?	switch (ctx->dev->chip_name) {
> -	case MTK_VDEC_MT8188:
> -	case MTK_VDEC_MT8195:
> -	case MTK_VDEC_MT8196:
> +	case 8188:
> +	case 8195:
> +	case 8196:
> ?		cfg->max = V4L2_MPEG_VIDEO_VP9_PROFILE_2;
> ?		break;
> ?	default:
> @@ -886,6 +886,7 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata = {
> ?	.get_cap_buffer = vdec_get_cap_buffer,
> ?	.is_subdev_supported = false,
> ?	.hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
> +	.chip_name = 8183,
> ?};
> ?
> ?/* This platform data is used for one lat and one core architecture. */
> @@ -906,6 +907,78 @@ const struct mtk_vcodec_dec_pdata mtk_lat_sig_core_pdata = {
> ?	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
> ?};
> ?
> +const struct mtk_vcodec_dec_pdata mtk_vdec_8188_pdata = {
> +	.init_vdec_params = mtk_init_vdec_params,
> +	.ctrls_setup = mtk_vcodec_dec_ctrls_setup,
> +	.vdec_vb2_ops = &mtk_vdec_request_vb2_ops,
> +	.vdec_formats = mtk_video_formats,
> +	.num_formats = &num_formats,
> +	.default_out_fmt = &default_out_format,
> +	.default_cap_fmt = &default_cap_format,
> +	.uses_stateless_api = true,
> +	.worker = mtk_vdec_worker,
> +	.flush_decoder = mtk_vdec_flush_decoder,
> +	.cap_to_disp = mtk_vdec_stateless_cap_to_disp,
> +	.get_cap_buffer = vdec_get_cap_buffer,
> +	.is_subdev_supported = true,
> +	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
> +	.chip_name = 8188,
> +};
> +
> +const struct mtk_vcodec_dec_pdata mtk_vdec_8192_pdata = {
> +	.init_vdec_params = mtk_init_vdec_params,
> +	.ctrls_setup = mtk_vcodec_dec_ctrls_setup,
> +	.vdec_vb2_ops = &mtk_vdec_request_vb2_ops,
> +	.vdec_formats = mtk_video_formats,
> +	.num_formats = &num_formats,
> +	.default_out_fmt = &default_out_format,
> +	.default_cap_fmt = &default_cap_format,
> +	.uses_stateless_api = true,
> +	.worker = mtk_vdec_worker,
> +	.flush_decoder = mtk_vdec_flush_decoder,
> +	.cap_to_disp = mtk_vdec_stateless_cap_to_disp,
> +	.get_cap_buffer = vdec_get_cap_buffer,
> +	.is_subdev_supported = true,
> +	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
> +	.chip_name = 8192,
> +};

I really like the change overall, but this adds a lot of code duplication.
Perhaps you could do something like:

+#define MTK_STATELESS_DEC_DATA \
+	.init_vdec_params = mtk_init_vdec_params,
+	.ctrls_setup = mtk_vcodec_dec_ctrls_setup,
+	.vdec_vb2_ops = &mtk_vdec_request_vb2_ops,
+	.vdec_formats = mtk_video_formats,
+	.num_formats = &num_formats,
+	.default_out_fmt = &default_out_format,
+	.default_cap_fmt = &default_cap_format,
+	.uses_stateless_api = true,
+	.worker = mtk_vdec_worker,
+	.flush_decoder = mtk_vdec_flush_decoder,
+	.cap_to_disp = mtk_vdec_stateless_cap_to_disp,
+	.get_cap_buffer = vdec_get_cap_buffer,
+	.is_subdev_supported = true

+const struct mtk_vcodec_dec_pdata mtk_vdec_8192_pdata = {
+	MTK_STATELESS_DEC_DATA,
+	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
+	.chip_name = 8192,
+};

The other method also used in various drivers is to embed a pointer to another
structure. The benefit of this second method is that it reduce the driver binary
size. With one solution to the copy paste issue implemented, the patch looks
good.

regards,
Nicolas

> +
> +const struct mtk_vcodec_dec_pdata mtk_vdec_8195_pdata = {
> +	.init_vdec_params = mtk_init_vdec_params,
> +	.ctrls_setup = mtk_vcodec_dec_ctrls_setup,
> +	.vdec_vb2_ops = &mtk_vdec_request_vb2_ops,
> +	.vdec_formats = mtk_video_formats,
> +	.num_formats = &num_formats,
> +	.default_out_fmt = &default_out_format,
> +	.default_cap_fmt = &default_cap_format,
> +	.uses_stateless_api = true,
> +	.worker = mtk_vdec_worker,
> +	.flush_decoder = mtk_vdec_flush_decoder,
> +	.cap_to_disp = mtk_vdec_stateless_cap_to_disp,
> +	.get_cap_buffer = vdec_get_cap_buffer,
> +	.is_subdev_supported = true,
> +	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
> +	.chip_name = 8195,
> +};
> +
> +const struct mtk_vcodec_dec_pdata mtk_vdec_8196_pdata = {
> +	.init_vdec_params = mtk_init_vdec_params,
> +	.ctrls_setup = mtk_vcodec_dec_ctrls_setup,
> +	.vdec_vb2_ops = &mtk_vdec_request_vb2_ops,
> +	.vdec_formats = mtk_video_formats,
> +	.num_formats = &num_formats,
> +	.default_out_fmt = &default_out_format,
> +	.default_cap_fmt = &default_cap_format,
> +	.uses_stateless_api = true,
> +	.worker = mtk_vdec_worker,
> +	.flush_decoder = mtk_vdec_flush_decoder,
> +	.cap_to_disp = mtk_vdec_stateless_cap_to_disp,
> +	.get_cap_buffer = vdec_get_cap_buffer,
> +	.is_subdev_supported = true,
> +	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
> +	.chip_name = 8196,
> +};
> +
> ?const struct mtk_vcodec_dec_pdata mtk_vdec_single_core_pdata = {
> ?	.init_vdec_params = mtk_init_vdec_params,
> ?	.ctrls_setup = mtk_vcodec_dec_ctrls_setup,
> @@ -922,3 +995,21 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_single_core_pdata = {
> ?	.is_subdev_supported = true,
> ?	.hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
> ?};
> +
> +const struct mtk_vcodec_dec_pdata mtk_vdec_8186_pdata = {
> +	.init_vdec_params = mtk_init_vdec_params,
> +	.ctrls_setup = mtk_vcodec_dec_ctrls_setup,
> +	.vdec_vb2_ops = &mtk_vdec_request_vb2_ops,
> +	.vdec_formats = mtk_video_formats,
> +	.num_formats = &num_formats,
> +	.default_out_fmt = &default_out_format,
> +	.default_cap_fmt = &default_cap_format,
> +	.uses_stateless_api = true,
> +	.worker = mtk_vdec_worker,
> +	.flush_decoder = mtk_vdec_flush_decoder,
> +	.cap_to_disp = mtk_vdec_stateless_cap_to_disp,
> +	.get_cap_buffer = vdec_get_cap_buffer,
> +	.is_subdev_supported = true,
> +	.hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
> +	.chip_name = 8186,
> +};
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251211/ccc8b125/attachment-0001.sig>

From nicolas.dufresne at collabora.com  Thu Dec 11 12:19:04 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Thu, 11 Dec 2025 15:19:04 -0500
Subject: [PATCH v6 04/10] media: mediatek: vcodec: add profile and level
 supporting for MT8189
In-Reply-To: <20251202074038.3173-5-kyrie.wu@mediatek.com>
References: <20251202074038.3173-1-kyrie.wu@mediatek.com>
	 <20251202074038.3173-5-kyrie.wu@mediatek.com>
Message-ID: <370389b51412209ae6aa6d8c388f29af7ed456a5.camel@collabora.com>

Hi,

in the subject, supporting -> suppport.

Le mardi 02 d?cembre 2025 ? 15:40 +0800, Kyrie Wu a ?crit?:
> add profile and level supporting for H264 and vp9 of MT8189

You already said that, perhaps say:


   The MT8189 SoC support H.264 up to high-10 at level 5.2, HEVC up to profile
   main-still at level 4 and VP9 profile 2 up to level 5.2. 

> 
> Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
> Reviewed-by: AngeloGioacchino Del Regno
> <angelogioacchino.delregno at collabora.com>
> ---
> ?.../vcodec/decoder/mtk_vcodec_dec_drv.h?????? |? 16 ++
> ?.../vcodec/decoder/mtk_vcodec_dec_stateful.c? |? 12 ++
> ?.../vcodec/decoder/mtk_vcodec_dec_stateless.c | 177 ++++++++++--------
> ?3 files changed, 130 insertions(+), 75 deletions(-)
> 
> diff --git
> a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h
> b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h
> index 2dbde8d00e6f..a8baeab98477 100644
> --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h
> +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h
> @@ -76,6 +76,16 @@ struct vdec_pic_info {
> ?	unsigned int reserved;
> ?};
> ?
> +/**
> + * struct mtk_vcodec_dec_params - decoder supported parameters
> + * @level: decoder supported vcodec level
> + * @profile: decoder supported vcodec profile
> + */
> +struct mtk_vcodec_dec_params {
> +	s64 level;
> +	s64 profile;
> +};
> +
> ?/**
> ? * struct mtk_vcodec_dec_pdata - compatible data for each IC
> ? * @init_vdec_params: init vdec params
> @@ -96,6 +106,9 @@ struct vdec_pic_info {
> ? * @is_subdev_supported: whether support parent-node architecture(subdev)
> ? * @uses_stateless_api: whether the decoder uses the stateless API with
> requests
> ? * @chip_name: platforms configuration values
> + * @h264_params: H264 decoder default supported params
> + * @h265_params: H265 decoder default supported params
> + * @vp9_params: VP9 decoder default supported params
> ? */
> ?struct mtk_vcodec_dec_pdata {
> ?	void (*init_vdec_params)(struct mtk_vcodec_dec_ctx *ctx);
> @@ -118,6 +131,9 @@ struct mtk_vcodec_dec_pdata {
> ?	bool is_subdev_supported;
> ?	bool uses_stateless_api;
> ?	unsigned int chip_name;
> +	struct mtk_vcodec_dec_params h264_params;
> +	struct mtk_vcodec_dec_params h265_params;
> +	struct mtk_vcodec_dec_params vp9_params;
> ?};
> ?
> ?/**
> diff --git
> a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c
> b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c
> index 8ddb61670dc6..a47906b9d717 100644
> --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c
> +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c
> @@ -619,4 +619,16 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata = {
> ?	.is_subdev_supported = false,
> ?	.hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
> ?	.chip_name = 8173,
> +	.h264_params = {
> +		.level = V4L2_MPEG_VIDEO_H264_LEVEL_4_1,
> +		.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
> +	},
> +	.h265_params = {
> +		.level = V4L2_MPEG_VIDEO_HEVC_LEVEL_4,
> +		.profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE,
> +	},
> +	.vp9_params = {
> +		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_4_0,
> +		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_1,
> +	},
> ?};
> diff --git
> a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
> b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
> index 9e43c54f8c4d..dc3e9a2ccc2c 100644
> ---
> a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
> +++
> b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
> @@ -549,106 +549,49 @@ static const struct v4l2_ctrl_ops
> mtk_vcodec_dec_ctrl_ops = {
> ?static void mtk_vcodec_dec_fill_h264_level(struct v4l2_ctrl_config *cfg,
> ?					?? struct mtk_vcodec_dec_ctx *ctx)
> ?{
> -	switch (ctx->dev->chip_name) {
> -	case 8192:
> -	case 8188:
> -		cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_5_2;
> -		break;
> -	case 8195:
> -	case 8196:
> -		cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_6_0;
> -		break;
> -	case 8183:
> -	case 8186:
> -		cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_4_2;
> -		break;
> -	default:
> -		cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_4_1;
> -		break;
> -	}
> +	struct mtk_vcodec_dec_dev *pdev = ctx->dev;
> +
> +	cfg->max = pdev->vdec_pdata->h264_params.level;
> ?}

Only remaining issue is that this is two changes. Please refactor first, and add
the configuration after. This is a nice cleanup.

regards,
Nicolas

> ?
> ?static void mtk_vcodec_dec_fill_h264_profile(struct v4l2_ctrl_config *cfg,
> ?					???? struct mtk_vcodec_dec_ctx *ctx)
> ?{
> -	switch (ctx->dev->chip_name) {
> -	case 8188:
> -	case 8195:
> -	case 8196:
> -		cfg->max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10;
> -		break;
> -	default:
> -		cfg->max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH;
> -		break;
> -	}
> +	struct mtk_vcodec_dec_dev *pdev = ctx->dev;
> +
> +	cfg->max = pdev->vdec_pdata->h264_params.profile;
> ?}
> ?
> ?static void mtk_vcodec_dec_fill_h265_level(struct v4l2_ctrl_config *cfg,
> ?					?? struct mtk_vcodec_dec_ctx *ctx)
> ?{
> -	switch (ctx->dev->chip_name) {
> -	case 8188:
> -		cfg->max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1;
> -		break;
> -	case 8195:
> -	case 8196:
> -		cfg->max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2;
> -		break;
> -	default:
> -		cfg->max = V4L2_MPEG_VIDEO_HEVC_LEVEL_4;
> -		break;
> -	}
> +	struct mtk_vcodec_dec_dev *pdev = ctx->dev;
> +
> +	cfg->max = pdev->vdec_pdata->h265_params.level;
> ?}
> ?
> ?static void mtk_vcodec_dec_fill_h265_profile(struct v4l2_ctrl_config *cfg,
> ?					???? struct mtk_vcodec_dec_ctx *ctx)
> ?{
> -	switch (ctx->dev->chip_name) {
> -	case 8188:
> -	case 8195:
> -	case 8196:
> -		cfg->max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10;
> -		break;
> -	default:
> -		cfg->max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE;
> -		break;
> -	}
> +	struct mtk_vcodec_dec_dev *pdev = ctx->dev;
> +
> +	cfg->max = pdev->vdec_pdata->h265_params.profile;
> ?}
> ?
> ?static void mtk_vcodec_dec_fill_vp9_level(struct v4l2_ctrl_config *cfg,
> ?					? struct mtk_vcodec_dec_ctx *ctx)
> ?{
> -	switch (ctx->dev->chip_name) {
> -	case 8192:
> -	case 8188:
> -		cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_5_1;
> -		break;
> -	case 8195:
> -	case 8196:
> -		cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2;
> -		break;
> -	case 8186:
> -		cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_4_1;
> -		break;
> -	default:
> -		cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_4_0;
> -		break;
> -	}
> +	struct mtk_vcodec_dec_dev *pdev = ctx->dev;
> +
> +	cfg->max = pdev->vdec_pdata->vp9_params.level;
> ?}
> ?
> ?static void mtk_vcodec_dec_fill_vp9_profile(struct v4l2_ctrl_config *cfg,
> ?					??? struct mtk_vcodec_dec_ctx *ctx)
> ?{
> -	switch (ctx->dev->chip_name) {
> -	case 8188:
> -	case 8195:
> -	case 8196:
> -		cfg->max = V4L2_MPEG_VIDEO_VP9_PROFILE_2;
> -		break;
> -	default:
> -		cfg->max = V4L2_MPEG_VIDEO_VP9_PROFILE_1;
> -		break;
> -	}
> +	struct mtk_vcodec_dec_dev *pdev = ctx->dev;
> +
> +	cfg->max = pdev->vdec_pdata->vp9_params.profile;
> ?}
> ?
> ?static void mtk_vcodec_dec_reset_controls(struct v4l2_ctrl_config *cfg,
> @@ -887,6 +830,18 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata = {
> ?	.is_subdev_supported = false,
> ?	.hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
> ?	.chip_name = 8183,
> +	.h264_params = {
> +		.level = V4L2_MPEG_VIDEO_H264_LEVEL_4_2,
> +		.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
> +	},
> +	.h265_params = {
> +		.level = V4L2_MPEG_VIDEO_HEVC_LEVEL_4,
> +		.profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE,
> +	},
> +	.vp9_params = {
> +		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_4_0,
> +		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_1,
> +	},
> ?};
> ?
> ?/* This platform data is used for one lat and one core architecture. */
> @@ -923,6 +878,18 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8188_pdata = {
> ?	.is_subdev_supported = true,
> ?	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
> ?	.chip_name = 8188,
> +	.h264_params = {
> +		.level = V4L2_MPEG_VIDEO_H264_LEVEL_5_2,
> +		.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10,
> +	},
> +	.h265_params = {
> +		.level = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1,
> +		.profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
> +	},
> +	.vp9_params = {
> +		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_1,
> +		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
> +	},
> ?};
> ?
> ?const struct mtk_vcodec_dec_pdata mtk_vdec_8192_pdata = {
> @@ -941,6 +908,18 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8192_pdata = {
> ?	.is_subdev_supported = true,
> ?	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
> ?	.chip_name = 8192,
> +	.h264_params = {
> +		.level = V4L2_MPEG_VIDEO_H264_LEVEL_5_2,
> +		.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
> +	},
> +	.h265_params = {
> +		.level = V4L2_MPEG_VIDEO_HEVC_LEVEL_4,
> +		.profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE,
> +	},
> +	.vp9_params = {
> +		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_1,
> +		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_1,
> +	},
> ?};
> ?
> ?const struct mtk_vcodec_dec_pdata mtk_vdec_8195_pdata = {
> @@ -959,6 +938,18 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8195_pdata = {
> ?	.is_subdev_supported = true,
> ?	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
> ?	.chip_name = 8195,
> +	.h264_params = {
> +		.level = V4L2_MPEG_VIDEO_H264_LEVEL_6_0,
> +		.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10,
> +	},
> +	.h265_params = {
> +		.level = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2,
> +		.profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
> +	},
> +	.vp9_params = {
> +		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2,
> +		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
> +	},
> ?};
> ?
> ?const struct mtk_vcodec_dec_pdata mtk_vdec_8196_pdata = {
> @@ -977,6 +968,18 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8196_pdata = {
> ?	.is_subdev_supported = true,
> ?	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
> ?	.chip_name = 8196,
> +	.h264_params = {
> +		.level = V4L2_MPEG_VIDEO_H264_LEVEL_6_0,
> +		.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10,
> +	},
> +	.h265_params = {
> +		.level = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2,
> +		.profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
> +	},
> +	.vp9_params = {
> +		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2,
> +		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
> +	},
> ?};
> ?
> ?const struct mtk_vcodec_dec_pdata mtk_vdec_single_core_pdata = {
> @@ -1012,6 +1015,18 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8186_pdata =
> {
> ?	.is_subdev_supported = true,
> ?	.hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
> ?	.chip_name = 8186,
> +	.h264_params = {
> +		.level = V4L2_MPEG_VIDEO_H264_LEVEL_4_2,
> +		.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
> +	},
> +	.h265_params = {
> +		.level = V4L2_MPEG_VIDEO_HEVC_LEVEL_4,
> +		.profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE,
> +	},
> +	.vp9_params = {
> +		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_4_1,
> +		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_1,
> +	},
> ?};
> ?
> ?const struct mtk_vcodec_dec_pdata mtk_vdec_8189_pdata = {
> @@ -1030,4 +1045,16 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8189_pdata =
> {
> ?	.is_subdev_supported = true,
> ?	.hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
> ?	.chip_name = 8189,
> +	.h264_params = {
> +		.level = V4L2_MPEG_VIDEO_H264_LEVEL_5_2,
> +		.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10,
> +	},
> +	.h265_params = {
> +		.level = V4L2_MPEG_VIDEO_HEVC_LEVEL_4,
> +		.profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE,
> +	},
> +	.vp9_params = {
> +		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2,
> +		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
> +	},
> ?};
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251211/0a712bdc/attachment.sig>

From linux at roeck-us.net  Thu Dec 11 12:27:48 2025
From: linux at roeck-us.net (Guenter Roeck)
Date: Thu, 11 Dec 2025 12:27:48 -0800
Subject: [PATCH RFC 01/16] dt-bindings: hwmon: Convert
 aspeed,ast2400-pwm-tacho to DT schema
In-Reply-To: <20251211-dev-dt-warnings-all-v1-1-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
 <20251211-dev-dt-warnings-all-v1-1-21b18b9ada77@codeconstruct.com.au>
Message-ID: <f17d93db-f96b-469d-88f0-0878a0fc9fe7@roeck-us.net>

On 12/11/25 00:45, Andrew Jeffery wrote:
> From: "Rob Herring (Arm)" <robh at kernel.org>
> 
> Convert the ASpeed fan controller binding to DT schema format.
> 
> The '#cooling-cells' value used is 1 rather than 2. '#size-cells' is 0
> rather 1.
> 
> Some users define more that 8 fan nodes where 2 fans share a PWM. The
> driver seems to let the 2nd fan just overwrite the 1st one. That also
> creates some addressing errors in the DT (duplicate addresses and wrong
> unit-addresses).
> 
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>

I am not sure I understand what the plan is here. I am assuming it will be
applied through a non-hwmon branch.

Acked-by: Guenter Roeck <linux at roeck-us.net>



From nicolas.dufresne at collabora.com  Thu Dec 11 12:29:24 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Thu, 11 Dec 2025 15:29:24 -0500
Subject: [PATCH v6 05/10] media: mediatek: vcodec: refactor setup dst
 buffer metadata interface for VP9 decoder
In-Reply-To: <20251202074038.3173-6-kyrie.wu@mediatek.com>
References: <20251202074038.3173-1-kyrie.wu@mediatek.com>
	 <20251202074038.3173-6-kyrie.wu@mediatek.com>
Message-ID: <d9a58ddf9b90d8320562ec54f2bd74fa77f0bc67.camel@collabora.com>

Hi,

Le mardi 02 d?cembre 2025 ? 15:40 +0800, Kyrie Wu a ?crit?:
> Previously, calling vdec_vp9_slice_setup_single_from_src_to_dst
> with v4l2_m2m_next_src_buf to obtain both buffers resulted in -EINVAL,
> interrupting the decoding process. To resolve this,
> the interface should be updated to set both src and dst buffers
> for metadata configuration.

I'm haven't figure-out why this happens, perhaps you can add more details ?

> 
> Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
> ---
> ?.../vcodec/decoder/vdec/vdec_vp9_req_lat_if.c | 21 ++++++++++---------
> ?1 file changed, 11 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
> index fa0f406f7726..9513ddde7c7c 100644
> --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
> +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
> @@ -696,21 +696,22 @@ static int vdec_vp9_slice_tile_offset(int idx, int mi_num, int tile_log2)
> ?	return min(offset, mi_num);
> ?}
> ?
> -static
> -int vdec_vp9_slice_setup_single_from_src_to_dst(struct vdec_vp9_slice_instance *instance)
> +static int vdec_vp9_slice_setup_single_from_src_to_dst(struct vdec_vp9_slice_instance *instance,
> +						?????? struct mtk_vcodec_mem *bs,
> +						?????? struct vdec_fb *fb)
> ?{
> -	struct vb2_v4l2_buffer *src;
> -	struct vb2_v4l2_buffer *dst;
> +	struct mtk_video_dec_buf *src_buf_info;
> +	struct mtk_video_dec_buf *dst_buf_info;
> ?
> -	src = v4l2_m2m_next_src_buf(instance->ctx->m2m_ctx);

My concern is that vdec_vp9_slice_setup_lat_from_src_buf() also depends on the
tip of the OUTPUT queue, why it this problem with limited to single core ?

Can you apply the manual completion fixes, and check if the problem still
appear? Is that something you reproduce every time ? Perhaps it should be kept
out of this serie ?


> -	if (!src)
> +	src_buf_info = container_of(bs, struct mtk_video_dec_buf, bs_buffer);
> +	if (!src_buf_info)
> ?		return -EINVAL;

Its a bit of a concern in term of memory lifetime / possible use after free.
Who's holding on the buffer if its not in the queue ?

Nicolas

> ?
> -	dst = v4l2_m2m_next_dst_buf(instance->ctx->m2m_ctx);
> -	if (!dst)
> +	dst_buf_info = container_of(fb, struct mtk_video_dec_buf, frame_buffer);
> +	if (!dst_buf_info)
> ?		return -EINVAL;
> ?
> -	v4l2_m2m_buf_copy_metadata(src, dst, true);
> +	v4l2_m2m_buf_copy_metadata(&src_buf_info->m2m_buf.vb, &dst_buf_info->m2m_buf.vb, true);
> ?
> ?	return 0;
> ?}
> @@ -1800,7 +1801,7 @@ static int vdec_vp9_slice_setup_single(struct vdec_vp9_slice_instance *instance,
> ?	struct vdec_vp9_slice_vsi *vsi = &pfc->vsi;
> ?	int ret;
> ?
> -	ret = vdec_vp9_slice_setup_single_from_src_to_dst(instance);
> +	ret = vdec_vp9_slice_setup_single_from_src_to_dst(instance, bs, fb);
> ?	if (ret)
> ?		goto err;
> ?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251211/ee28f6fa/attachment-0001.sig>

From nicolas.dufresne at collabora.com  Thu Dec 11 12:31:41 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Thu, 11 Dec 2025 15:31:41 -0500
Subject: [PATCH v6 06/10] media: mediatek: vcodec: Add 4K prob size
 supporting for VP9 decoder
In-Reply-To: <20251202074038.3173-7-kyrie.wu@mediatek.com>
References: <20251202074038.3173-1-kyrie.wu@mediatek.com>
	 <20251202074038.3173-7-kyrie.wu@mediatek.com>
Message-ID: <898905035315552215b13402d29e2eeb1350c74c.camel@collabora.com>

Hi,

Le mardi 02 d?cembre 2025 ? 15:40 +0800, Kyrie Wu a ?crit?:
> From: Kyrie Wu <kyrie.wu at mediatek.corp-partner.google.com>

I don't think you meant to commit with your Google partner email ?

> 
> add config to support prob size both 3840 and 2560.

Prob mean probability ? Commit message is the place to you full words. Can you
extend why the difference, and use defines instead of magic number?

> 
> Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.corp-partner.google.com>

Or even sign it ?

Nicolas

> ---
> ?.../platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h? | 2 ++
> ?.../mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c????? | 1 +
> ?.../mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c???? | 7 +++++++
> ?.../mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c???? | 4 ++--
> ?4 files changed, 12 insertions(+), 2 deletions(-)
> 
> diff --git
> a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h
> b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h
> index a8baeab98477..ecf0d7ad0d54 100644
> --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h
> +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h
> @@ -80,10 +80,12 @@ struct vdec_pic_info {
> ? * struct mtk_vcodec_dec_params - decoder supported parameters
> ? * @level: decoder supported vcodec level
> ? * @profile: decoder supported vcodec profile
> + * @prob_size: vp9 decoder prob size
> ? */
> ?struct mtk_vcodec_dec_params {
> ?	s64 level;
> ?	s64 profile;
> +	size_t prob_size;
> ?};
> ?
> ?/**
> diff --git
> a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c
> b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c
> index a47906b9d717..99c252e0a2e1 100644
> --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c
> +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c
> @@ -630,5 +630,6 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata = {
> ?	.vp9_params = {
> ?		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_4_0,
> ?		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_1,
> +		.prob_size = 2560,
> ?	},
> ?};
> diff --git
> a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
> b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
> index dc3e9a2ccc2c..f18aafd08c76 100644
> ---
> a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
> +++
> b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
> @@ -841,6 +841,7 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata = {
> ?	.vp9_params = {
> ?		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_4_0,
> ?		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_1,
> +		.prob_size = 2560,
> ?	},
> ?};
> ?
> @@ -889,6 +890,7 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8188_pdata = {
> ?	.vp9_params = {
> ?		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_1,
> ?		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
> +		.prob_size = 2560,
> ?	},
> ?};
> ?
> @@ -919,6 +921,7 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8192_pdata = {
> ?	.vp9_params = {
> ?		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_1,
> ?		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_1,
> +		.prob_size = 2560,
> ?	},
> ?};
> ?
> @@ -949,6 +952,7 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8195_pdata = {
> ?	.vp9_params = {
> ?		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2,
> ?		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
> +		.prob_size = 2560,
> ?	},
> ?};
> ?
> @@ -979,6 +983,7 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8196_pdata = {
> ?	.vp9_params = {
> ?		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2,
> ?		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
> +		.prob_size = 3840,
> ?	},
> ?};
> ?
> @@ -1026,6 +1031,7 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8186_pdata =
> {
> ?	.vp9_params = {
> ?		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_4_1,
> ?		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_1,
> +		.prob_size = 2560,
> ?	},
> ?};
> ?
> @@ -1056,5 +1062,6 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8189_pdata =
> {
> ?	.vp9_params = {
> ?		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2,
> ?		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
> +		.prob_size = 3840,
> ?	},
> ?};
> diff --git
> a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
> b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
> index 9513ddde7c7c..36a87b455d11 100644
> ---
> a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
> +++
> b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
> @@ -22,7 +22,6 @@
> ?#define VP9_RESET_FRAME_CONTEXT_ALL 3
> ?
> ?#define VP9_TILE_BUF_SIZE 4096
> -#define VP9_PROB_BUF_SIZE 2560
> ?#define VP9_COUNTS_BUF_SIZE 16384
> ?
> ?#define HDR_FLAG(x) (!!((hdr)->flags & V4L2_VP9_FRAME_FLAG_##x))
> @@ -546,6 +545,7 @@ static int vdec_vp9_slice_alloc_working_buffer(struct
> vdec_vp9_slice_instance *i
> ?					?????? struct vdec_vp9_slice_vsi
> *vsi)
> ?{
> ?	struct mtk_vcodec_dec_ctx *ctx = instance->ctx;
> +	struct mtk_vcodec_dec_dev *pdev = ctx->dev;
> ?	enum vdec_vp9_slice_resolution_level level;
> ?	/* super blocks */
> ?	unsigned int max_sb_w;
> @@ -616,7 +616,7 @@ static int vdec_vp9_slice_alloc_working_buffer(struct
> vdec_vp9_slice_instance *i
> ?	}
> ?
> ?	if (!instance->prob.va) {
> -		instance->prob.size = VP9_PROB_BUF_SIZE;
> +		instance->prob.size = pdev->vdec_pdata->vp9_params.prob_size;
> ?		if (mtk_vcodec_mem_alloc(ctx, &instance->prob))
> ?			goto err;
> ?	}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251211/fe2067a1/attachment.sig>

From nicolas.dufresne at collabora.com  Thu Dec 11 12:32:30 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Thu, 11 Dec 2025 15:32:30 -0500
Subject: [PATCH v6 07/10] media: mediatek: vcodec: Fix vp9 4096x2176
 fail for profile2
In-Reply-To: <20251202074038.3173-8-kyrie.wu@mediatek.com>
References: <20251202074038.3173-1-kyrie.wu@mediatek.com>
	 <20251202074038.3173-8-kyrie.wu@mediatek.com>
Message-ID: <03d3228206dbeb7f3fdb9466f84511f598ae9d65.camel@collabora.com>

Le mardi 02 d?cembre 2025 ? 15:40 +0800, Kyrie Wu a ?crit?:
> The DRAM address of the VP9 decoder tile info buffers may require
> as much as 36bits for 4096x2176 resolution. Fold the 4 most significant
> bits into the lower (padding) four bits of address.
> 
> Fixes: 5d418351ca8f1 ("media: mediatek: vcodec: support stateless VP9 decoding")
> 
> Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
> Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?.../mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c | 10 +++++++++-
> ?1 file changed, 9 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
> index 36a87b455d11..eca6280098be 100644
> --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
> +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
> @@ -1134,9 +1134,17 @@ static int vdec_vp9_slice_setup_tile_buffer(struct vdec_vp9_slice_instance *inst
> ?					return -EINVAL;
> ?			}
> ?			tiles->size[i][j] = size;
> +			/*
> +			 * If the system supports 64-bit DMA addresses, the upper 4 bits
> +			 * of the address are also encoded into the buffer entry.
> +			 * The buffer pointer (tb) is incremented after each entry is written.
> +			 */
> ?			if (tiles->mi_rows[i]) {
> ?				*tb++ = (size << 3) + ((offset << 3) & 0x7f);
> -				*tb++ = pa & ~0xf;
> +				*tb = pa & GENMASK(31, 4);
> +				if (IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT))
> +					*tb |= (pa >> 32) & GENMASK(3, 0);
> +				tb++;
> ?				*tb++ = (pa << 3) & 0x7f;
> ?				mi_row = (tiles->mi_rows[i] - 1) & 0x1ff;
> ?				mi_col = (tiles->mi_cols[j] - 1) & 0x3f;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251211/0bc61c5a/attachment.sig>

From nicolas.dufresne at collabora.com  Thu Dec 11 12:33:14 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Thu, 11 Dec 2025 15:33:14 -0500
Subject: [PATCH v6 08/10] media: mediatek: vcodec: Fix media device node
 number
In-Reply-To: <20251202074038.3173-9-kyrie.wu@mediatek.com>
References: <20251202074038.3173-1-kyrie.wu@mediatek.com>
	 <20251202074038.3173-9-kyrie.wu@mediatek.com>
Message-ID: <66cb982fd78c85a33006647e0d2f1fe4b0c10a86.camel@collabora.com>

Le mardi 02 d?cembre 2025 ? 15:40 +0800, Kyrie Wu a ?crit?:
> change media register device node number to a correct value.
> The vfd minor is used to record the number of registered
> video device nodes. The mdev_dec.devnode minor counter is
> used to record the number of registered media device nodes.
> 
> Fixes: 41f03c673cb7b ("media: mediatek: vcodec: replace pr_* with dev_* for v4l2 debug message")
> 
> Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?.../platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c????? | 3 ++-
> ?1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
> index 2d1a545e727c..bf6e792283a1 100644
> --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
> +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
> @@ -493,7 +493,8 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
> ?			goto err_media_reg;
> ?		}
> ?
> -		dev_dbg(&pdev->dev, "media registered as /dev/media%d", vfd_dec->minor);
> +		dev_dbg(&pdev->dev, "media registered as /dev/media%d",
> +			dev->mdev_dec.devnode->minor);
> ?	}
> ?
> ?	mtk_vcodec_dbgfs_init(dev, false);
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251211/62eac2a9/attachment-0001.sig>

From will at kernel.org  Thu Dec 11 12:36:01 2025
From: will at kernel.org (Will Deacon)
Date: Fri, 12 Dec 2025 05:36:01 +0900
Subject: [PATCH 1/2] KVM: arm64: Copy FGT traps to unprotected pKVM VCPU
 on VCPU load
In-Reply-To: <20251210132102.137631-2-alexandru.elisei@arm.com>
References: <20251210132102.137631-1-alexandru.elisei@arm.com>
 <20251210132102.137631-2-alexandru.elisei@arm.com>
Message-ID: <aTsrMUGan1AH5suO@google.com>

Hey Alexandru,

[+Fuad as we ran into this last week]

On Wed, Dec 10, 2025 at 01:21:01PM +0000, Alexandru Elisei wrote:
> Commit fb10ddf35c1c ("KVM: arm64: Compute per-vCPU FGTs at vcpu_load()")
> introduced per-VCPU FGT traps. For an unprotected pKVM VCPU, the untrusted
> host FGT configuration is copied in pkvm_vcpu_init_traps(), which is called
> from __pkvm_init_vcpu(). __pkvm_init_vcpu() is called once per VCPU (when
> the VCPU is first run) which means that the uninitialized, zero, values for
> the FGT registers end up being used for the entire lifetime of the VCPU.
> This causes both unwanted traps (for the inverse polarity trap bits) and
> the guest being allowed to access registers it shouldn't.
> 
> Fix it by copying the FGT traps for unprotected pKVM VCPUs when the
> untrusted host loads the VCPU.
> 
> Fixes: fb10ddf35c1c ("KVM: arm64: Compute per-vCPU FGTs at vcpu_load()")
> Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
> ---
>  arch/arm64/kvm/hyp/nvhe/hyp-main.c | 12 ++++++++++--
>  arch/arm64/kvm/hyp/nvhe/pkvm.c     |  1 -
>  2 files changed, 10 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> index 29430c031095..ee0f1343100c 100644
> --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> @@ -167,6 +167,7 @@ static void handle___pkvm_vcpu_load(struct kvm_cpu_context *host_ctxt)
>  	DECLARE_REG(unsigned int, vcpu_idx, host_ctxt, 2);
>  	DECLARE_REG(u64, hcr_el2, host_ctxt, 3);
>  	struct pkvm_hyp_vcpu *hyp_vcpu;
> +	struct kvm_vcpu *hyp_kvm_vcpu;
>  
>  	if (!is_protected_kvm_enabled())
>  		return;
> @@ -175,10 +176,17 @@ static void handle___pkvm_vcpu_load(struct kvm_cpu_context *host_ctxt)
>  	if (!hyp_vcpu)
>  		return;
>  
> +	hyp_kvm_vcpu = &hyp_vcpu->vcpu;
> +
>  	if (pkvm_hyp_vcpu_is_protected(hyp_vcpu)) {
>  		/* Propagate WFx trapping flags */
> -		hyp_vcpu->vcpu.arch.hcr_el2 &= ~(HCR_TWE | HCR_TWI);
> -		hyp_vcpu->vcpu.arch.hcr_el2 |= hcr_el2 & (HCR_TWE | HCR_TWI);
> +		hyp_kvm_vcpu->arch.hcr_el2 &= ~(HCR_TWE | HCR_TWI);
> +		hyp_kvm_vcpu->arch.hcr_el2 |= hcr_el2 & (HCR_TWE | HCR_TWI);

I don't think the 'hyp_kvm_vcpu' really makes this much clearer and it's
the line only ends up being a single character shorter. Just continue to
use 'hyp_vcpu->vcpu.'?

> +	} else {
> +		struct kvm_vcpu *host_vcpu = hyp_vcpu->host_vcpu;
> +
> +		memcpy(&hyp_kvm_vcpu->arch.fgt, host_vcpu->arch.fgt,
> +		       sizeof(hyp_kvm_vcpu->arch.fgt));
>  	}
>  }
>  
> diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
> index 43bde061b65d..05774aed09cb 100644
> --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
> +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
> @@ -172,7 +172,6 @@ static int pkvm_vcpu_init_traps(struct pkvm_hyp_vcpu *hyp_vcpu)
>  
>  		/* Trust the host for non-protected vcpu features. */
>  		vcpu->arch.hcrx_el2 = host_vcpu->arch.hcrx_el2;
> -		memcpy(vcpu->arch.fgt, host_vcpu->arch.fgt, sizeof(vcpu->arch.fgt));
>  		return 0;
>  	}

Otherwise, looks good to me:

Acked-by: Will Deacon <will at kernel.org>

Will


From nicolas.frattaroli at collabora.com  Thu Dec 11 12:40:30 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 11 Dec 2025 21:40:30 +0100
Subject: [PATCH v4 0/8] drm/rockchip: No more post-atomic_check fixups
Message-ID: <20251211-vop2-atomic-fixups-v4-0-5d50eda26bf8@collabora.com>

I'm taking over this series to get it across the finish line. Original
cover letter from Daniel Stone on v1:

> Hi,
> This series is a pretty small and consistent one for VOP2. The atomic
> uAPI very clearly specifies that drivers should either do what userspace
> requested (on a successful commit), or fail atomic_check if it is not
> for any reason possible to do what userspace requested.
> 
> VOP2 is unfortunately littered with a bunch of cases where it will apply
> fixups after atomic_check - doing something different to what userspace
> requested, e.g. clipping or aligning regions - or throw error messages
> into the log when userspace does request a condition which can't be met.
> 
> Doing something different to what was requested is bad because it
> results in unexpected visual output which can look like artifacts.
> Throwing errors into the log is bad because generic userspace will
> reasonably attempt to try any configuration it can. For example,
> throwing an error message on a plane not being aligned to a 16 pixel
> boundary can result in 15 frames' worth of error output in the log when
> a window is being animated across a screen.
> 
> This series removes all post-check fixups - failing the check if the
> configuration cannot be applied - and also demotes all messages about
> unsupported configurations to DEBUG_KMS.
> 
> Cheers,
> Daniel

---
Changes in v4:
- s/64-byte/64-pixel/
- Link to v3: https://lore.kernel.org/r/20251209-vop2-atomic-fixups-v3-0-07c48f0f1f0d at collabora.com

Changes in v3:
- Change the AFBC source rectangle debug message to talk about 4-pixel
  alignment instead of 4-byte alignment.
- Fix another eSmart->Esmart casing case in a debug message
- Link to v2: https://lore.kernel.org/r/20251206-vop2-atomic-fixups-v2-0-7fb45bbfbebd at collabora.com

Changes in v2:
- Dropped patches [1, 5] as they were already applied.
- Changed the patch subject to use prefix "drm/rockchip: vop2:" for the
  remaining ones.
- Fixed a checkpatch nag about commenting style in "Switch impossible
  pos conditional to WARN_ON".
- Reworded "eSmart" to "Esmart" for consistency, and to avoid drawing
  Tim Apple's ire.
- Make the hopefully impossible WARN_ON format conditional in
  vop2_plane_atomic_check still bubble the error up to userspace,
  instead of continuing on.
- Use dest_w instead of dsp_w in patch "Enforce scaling workaround
  in plane_check", to avoid a compiler error.
- Only reject non-multiple-of-4-pixel-wide framebuffers on
  RK3566/RK3568, as the other SoCs have no such limitation. (Thank you
  to Andy Yan for doing the research to confirm this!)
- Consequently also only WARN_ON if this condition is violated in
  atomic_update on those SoCs.
- Link to v1: https://lore.kernel.org/dri-devel/20251015110042.41273-1-daniels at collabora.com/

Signed-off-by: Daniel Stone <daniels at collabora.com>
Cc: Daniel Stone <daniels at collabora.com>
To: Chaoyi Chen <chaoyi.chen at rock-chips.com>
To: Sandy Huang <hjc at rock-chips.com>
To: Heiko St?bner <heiko at sntech.de>
To: Andy Yan <andy.yan at rock-chips.com>
To: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
To: Maxime Ripard <mripard at kernel.org>
To: Thomas Zimmermann <tzimmermann at suse.de>
To: David Airlie <airlied at gmail.com>
To: Simona Vetter <simona at ffwll.ch>
Cc: dri-devel at lists.freedesktop.org
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-rockchip at lists.infradead.org
Cc: linux-kernel at vger.kernel.org
Cc: kernel at collabora.com
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>

---
Daniel Stone (8):
      drm/rockchip: vop2: Switch impossible format conditional to WARN_ON
      drm/rockchip: vop2: Switch impossible pos conditional to WARN_ON
      drm/rockchip: vop2: Fix Esmart test condition
      drm/rockchip: vop2: Enforce scaling workaround in plane_check
      drm/rockchip: vop2: Enforce AFBC source alignment in plane_check
      drm/rockchip: vop2: Enforce AFBC transform stride align in plane_check
      drm/rockchip: vop2: Use drm_is_afbc helper function
      drm/rockchip: vop2: Simplify format_mod_supported

 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 137 ++++++++++++---------------
 1 file changed, 62 insertions(+), 75 deletions(-)
---
base-commit: 7b1d0dfc434030b66fd2837f17db5c966a72590e
change-id: 20251206-vop2-atomic-fixups-0c30e0980f85

Best regards,
-- 
Nicolas Frattaroli <nicolas.frattaroli at collabora.com>



From nicolas.frattaroli at collabora.com  Thu Dec 11 12:40:31 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 11 Dec 2025 21:40:31 +0100
Subject: [PATCH v4 1/8] drm/rockchip: vop2: Switch impossible format
 conditional to WARN_ON
In-Reply-To: <20251211-vop2-atomic-fixups-v4-0-5d50eda26bf8@collabora.com>
References: <20251211-vop2-atomic-fixups-v4-0-5d50eda26bf8@collabora.com>
Message-ID: <20251211-vop2-atomic-fixups-v4-1-5d50eda26bf8@collabora.com>

From: Daniel Stone <daniels at collabora.com>

We should never be able to create a framebuffer with an unsupported
format, so throw a warning if this ever happens, instead of attempting
to stagger on.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 498df0ce4680..20b49209ddcd 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1030,7 +1030,8 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
 		return 0;
 
 	format = vop2_convert_format(fb->format->format);
-	if (format < 0)
+	/* We shouldn't be able to create a fb for an unsupported format */
+	if (WARN_ON(format < 0))
 		return format;
 
 	/* Co-ordinates have now been clipped */

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 11 12:40:32 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 11 Dec 2025 21:40:32 +0100
Subject: [PATCH v4 2/8] drm/rockchip: vop2: Switch impossible pos
 conditional to WARN_ON
In-Reply-To: <20251211-vop2-atomic-fixups-v4-0-5d50eda26bf8@collabora.com>
References: <20251211-vop2-atomic-fixups-v4-0-5d50eda26bf8@collabora.com>
Message-ID: <20251211-vop2-atomic-fixups-v4-2-5d50eda26bf8@collabora.com>

From: Daniel Stone <daniels at collabora.com>

We already clip the plane to the display bounds in atomic_check, and
ensure that it is sufficiently sized. Instead of trying to catch this
and adjust for it in atomic_update, just assert that atomic_check has
done its job.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 29 +++++++++-------------------
 1 file changed, 9 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 20b49209ddcd..81b3eba07095 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1214,28 +1214,17 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
 	src_w = drm_rect_width(src) >> 16;
 	src_h = drm_rect_height(src) >> 16;
 	dsp_w = drm_rect_width(dest);
-
-	if (dest->x1 + dsp_w > adjusted_mode->hdisplay) {
-		drm_dbg_kms(vop2->drm,
-			    "vp%d %s dest->x1[%d] + dsp_w[%d] exceed mode hdisplay[%d]\n",
-			    vp->id, win->data->name, dest->x1, dsp_w, adjusted_mode->hdisplay);
-		dsp_w = adjusted_mode->hdisplay - dest->x1;
-		if (dsp_w < 4)
-			dsp_w = 4;
-		src_w = dsp_w * src_w / drm_rect_width(dest);
-	}
-
 	dsp_h = drm_rect_height(dest);
 
-	if (dest->y1 + dsp_h > adjusted_mode->vdisplay) {
-		drm_dbg_kms(vop2->drm,
-			    "vp%d %s dest->y1[%d] + dsp_h[%d] exceed mode vdisplay[%d]\n",
-			    vp->id, win->data->name, dest->y1, dsp_h, adjusted_mode->vdisplay);
-		dsp_h = adjusted_mode->vdisplay - dest->y1;
-		if (dsp_h < 4)
-			dsp_h = 4;
-		src_h = dsp_h * src_h / drm_rect_height(dest);
-	}
+	/* drm_atomic_helper_check_plane_state calls drm_rect_clip_scaled for
+	 * us, which keeps our planes bounded within the CRTC active area
+	 */
+	WARN_ON(dest->x1 + dsp_w > adjusted_mode->hdisplay);
+	WARN_ON(dest->y1 + dsp_h > adjusted_mode->vdisplay);
+	WARN_ON(dsp_w < 4);
+	WARN_ON(dsp_h < 4);
+	WARN_ON(src_w < 4);
+	WARN_ON(src_h < 4);
 
 	/*
 	 * This is workaround solution for IC design:

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 11 12:40:33 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 11 Dec 2025 21:40:33 +0100
Subject: [PATCH v4 3/8] drm/rockchip: vop2: Fix Esmart test condition
In-Reply-To: <20251211-vop2-atomic-fixups-v4-0-5d50eda26bf8@collabora.com>
References: <20251211-vop2-atomic-fixups-v4-0-5d50eda26bf8@collabora.com>
Message-ID: <20251211-vop2-atomic-fixups-v4-3-5d50eda26bf8@collabora.com>

From: Daniel Stone <daniels at collabora.com>

If we want to find out if a window is Esmart or not, test for not being
a cluster window, rather than AFBDC presence.

No functional effect as only cluster windows support AFBC decode.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 81b3eba07095..9d715d7659af 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1230,12 +1230,10 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
 	 * This is workaround solution for IC design:
 	 * esmart can't support scale down when src_w % 16 == 1.
 	 */
-	if (!(win->data->feature & WIN_FEATURE_AFBDC)) {
-		if (src_w > dsp_w && (src_w & 0xf) == 1) {
-			drm_dbg_kms(vop2->drm, "vp%d %s act_w[%d] MODE 16 == 1\n",
-				    vp->id, win->data->name, src_w);
-			src_w -= 1;
-		}
+	if (!vop2_cluster_window(win) && src_w > dsp_w && (src_w & 1)) {
+		drm_dbg_kms(vop2->drm, "vp%d %s act_w[%d] MODE 16 == 1\n",
+			    vp->id, win->data->name, src_w);
+		src_w -= 1;
 	}
 
 	if (afbc_en && src_w % 4) {

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 11 12:40:34 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 11 Dec 2025 21:40:34 +0100
Subject: [PATCH v4 4/8] drm/rockchip: vop2: Enforce scaling workaround in
 plane_check
In-Reply-To: <20251211-vop2-atomic-fixups-v4-0-5d50eda26bf8@collabora.com>
References: <20251211-vop2-atomic-fixups-v4-0-5d50eda26bf8@collabora.com>
Message-ID: <20251211-vop2-atomic-fixups-v4-4-5d50eda26bf8@collabora.com>

From: Daniel Stone <daniels at collabora.com>

It seems only cluster windows are capable of applying downscaling when
the source region has an odd width. Instead of applying a workaround
inside atomic_update, fail the plane check if this is requested.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 9d715d7659af..6d4f22872e67 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -998,6 +998,7 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
 	struct drm_crtc *crtc = pstate->crtc;
 	struct drm_crtc_state *cstate;
 	struct vop2_video_port *vp;
+	struct vop2_win *win = to_vop2_win(plane);
 	struct vop2 *vop2;
 	const struct vop2_data *vop2_data;
 	struct drm_rect *dest = &pstate->dst;
@@ -1065,6 +1066,16 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
 		return -EINVAL;
 	}
 
+	/*
+	 * This is workaround solution for IC design:
+	 * esmart can't support scale down when src_w % 16 == 1.
+	 */
+	if (!vop2_cluster_window(win) && src_w > dest_w && (src_w & 1)) {
+		drm_dbg_kms(vop2->drm,
+			    "Esmart windows cannot downscale odd-width source regions\n");
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
@@ -1226,16 +1237,6 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
 	WARN_ON(src_w < 4);
 	WARN_ON(src_h < 4);
 
-	/*
-	 * This is workaround solution for IC design:
-	 * esmart can't support scale down when src_w % 16 == 1.
-	 */
-	if (!vop2_cluster_window(win) && src_w > dsp_w && (src_w & 1)) {
-		drm_dbg_kms(vop2->drm, "vp%d %s act_w[%d] MODE 16 == 1\n",
-			    vp->id, win->data->name, src_w);
-		src_w -= 1;
-	}
-
 	if (afbc_en && src_w % 4) {
 		drm_dbg_kms(vop2->drm, "vp%d %s src_w[%d] not 4 pixel aligned\n",
 			    vp->id, win->data->name, src_w);

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 11 12:40:35 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 11 Dec 2025 21:40:35 +0100
Subject: [PATCH v4 5/8] drm/rockchip: vop2: Enforce AFBC source alignment
 in plane_check
In-Reply-To: <20251211-vop2-atomic-fixups-v4-0-5d50eda26bf8@collabora.com>
References: <20251211-vop2-atomic-fixups-v4-0-5d50eda26bf8@collabora.com>
Message-ID: <20251211-vop2-atomic-fixups-v4-5-5d50eda26bf8@collabora.com>

From: Daniel Stone <daniels at collabora.com>

Planes can only source AFBC framebuffers at multiples of 4px wide on
RK3566/RK3568. Instead of clipping on all SoCs when the user asks for an
unaligned source rectangle, reject the configuration in the plane's
atomic check on RK3566/RK3568 only.

Signed-off-by: Daniel Stone <daniels at collabora.com>
[Make RK3566/RK3568 specific, reword message, s/byte/pixel/]
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 6d4f22872e67..a029ed73dda7 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1076,6 +1076,13 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
 		return -EINVAL;
 	}
 
+	if (vop2->version == VOP_VERSION_RK3568 && drm_is_afbc(fb->modifier) && src_w % 4) {
+		drm_dbg_kms(vop2->drm,
+			    "AFBC source rectangles must be 4-pixel aligned; is %d\n",
+			    src_w);
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
@@ -1237,11 +1244,8 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
 	WARN_ON(src_w < 4);
 	WARN_ON(src_h < 4);
 
-	if (afbc_en && src_w % 4) {
-		drm_dbg_kms(vop2->drm, "vp%d %s src_w[%d] not 4 pixel aligned\n",
-			    vp->id, win->data->name, src_w);
-		src_w = ALIGN_DOWN(src_w, 4);
-	}
+	if (vop2->version == VOP_VERSION_RK3568 && drm_is_afbc(fb->modifier))
+		WARN_ON(src_w % 4);
 
 	act_info = (src_h - 1) << 16 | ((src_w - 1) & 0xffff);
 	dsp_info = (dsp_h - 1) << 16 | ((dsp_w - 1) & 0xffff);

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 11 12:40:36 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 11 Dec 2025 21:40:36 +0100
Subject: [PATCH v4 6/8] drm/rockchip: vop2: Enforce AFBC transform stride
 align in plane_check
In-Reply-To: <20251211-vop2-atomic-fixups-v4-0-5d50eda26bf8@collabora.com>
References: <20251211-vop2-atomic-fixups-v4-0-5d50eda26bf8@collabora.com>
Message-ID: <20251211-vop2-atomic-fixups-v4-6-5d50eda26bf8@collabora.com>

From: Daniel Stone <daniels at collabora.com>

Make sure we can't break the hardware by requesting an unsupported
configuration.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index a029ed73dda7..1d12e00ec49f 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1083,6 +1083,15 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
 		return -EINVAL;
 	}
 
+	if (drm_is_afbc(fb->modifier) &&
+	    pstate->rotation &
+		(DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270) &&
+	    (fb->pitches[0] << 3) / vop2_get_bpp(fb->format) % 64) {
+		drm_dbg_kms(vop2->drm,
+			    "AFBC buffers must be 64-pixel aligned for horizontal rotation or mirroring\n");
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
@@ -1290,9 +1299,6 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
 		 * with WIN_VIR_STRIDE.
 		 */
 		stride = (fb->pitches[0] << 3) / bpp;
-		if ((stride & 0x3f) && (xmirror || rotate_90 || rotate_270))
-			drm_dbg_kms(vop2->drm, "vp%d %s stride[%d] not 64 pixel aligned\n",
-				    vp->id, win->data->name, stride);
 
 		 /* It's for head stride, each head size is 16 byte */
 		stride = ALIGN(stride, block_w) / block_w * 16;

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 11 12:40:37 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 11 Dec 2025 21:40:37 +0100
Subject: [PATCH v4 7/8] drm/rockchip: vop2: Use drm_is_afbc helper function
In-Reply-To: <20251211-vop2-atomic-fixups-v4-0-5d50eda26bf8@collabora.com>
References: <20251211-vop2-atomic-fixups-v4-0-5d50eda26bf8@collabora.com>
Message-ID: <20251211-vop2-atomic-fixups-v4-7-5d50eda26bf8@collabora.com>

From: Daniel Stone <daniels at collabora.com>

We don't need to do a long open-coded walk here; we can simply check the
modifier value.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 1d12e00ec49f..494f4d48f9fe 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1207,7 +1207,7 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
 		return;
 	}
 
-	afbc_en = rockchip_afbc(plane, fb->modifier);
+	afbc_en = drm_is_afbc(fb->modifier);
 
 	offset = (src->x1 >> 16) * fb->format->cpp[0];
 

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 11 12:40:38 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 11 Dec 2025 21:40:38 +0100
Subject: [PATCH v4 8/8] drm/rockchip: vop2: Simplify format_mod_supported
In-Reply-To: <20251211-vop2-atomic-fixups-v4-0-5d50eda26bf8@collabora.com>
References: <20251211-vop2-atomic-fixups-v4-0-5d50eda26bf8@collabora.com>
Message-ID: <20251211-vop2-atomic-fixups-v4-8-5d50eda26bf8@collabora.com>

From: Daniel Stone <daniels at collabora.com>

Make it a little less convoluted, and just directly check if the
combination of plane + format + modifier is supported.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 56 +++++++++++-----------------
 1 file changed, 22 insertions(+), 34 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 494f4d48f9fe..4659c55d0da4 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -367,59 +367,47 @@ static bool is_yuv_output(u32 bus_format)
 	}
 }
 
-static bool rockchip_afbc(struct drm_plane *plane, u64 modifier)
-{
-	int i;
-
-	if (modifier == DRM_FORMAT_MOD_LINEAR)
-		return false;
-
-	for (i = 0 ; i < plane->modifier_count; i++)
-		if (plane->modifiers[i] == modifier)
-			return true;
-
-	return false;
-}
-
 static bool rockchip_vop2_mod_supported(struct drm_plane *plane, u32 format,
 					u64 modifier)
 {
 	struct vop2_win *win = to_vop2_win(plane);
 	struct vop2 *vop2 = win->vop2;
+	int i;
 
+	/* No support for implicit modifiers */
 	if (modifier == DRM_FORMAT_MOD_INVALID)
 		return false;
 
-	if (vop2->version == VOP_VERSION_RK3568) {
-		if (vop2_cluster_window(win)) {
-			if (modifier == DRM_FORMAT_MOD_LINEAR) {
-				drm_dbg_kms(vop2->drm,
-					    "Cluster window only supports format with afbc\n");
-				return false;
-			}
-		}
+	/* The cluster window on 3568 is AFBC-only */
+	if (vop2->version == VOP_VERSION_RK3568 && vop2_cluster_window(win) &&
+	    !drm_is_afbc(modifier)) {
+		drm_dbg_kms(vop2->drm,
+			    "Cluster window only supports format with afbc\n");
+		return false;
 	}
 
-	if (format == DRM_FORMAT_XRGB2101010 || format == DRM_FORMAT_XBGR2101010) {
-		if (vop2->version == VOP_VERSION_RK3588) {
-			if (!rockchip_afbc(plane, modifier)) {
-				drm_dbg_kms(vop2->drm, "Only support 32 bpp format with afbc\n");
-				return false;
-			}
-		}
+	/* 10bpc formats on 3588 are AFBC-only */
+	if (vop2->version == VOP_VERSION_RK3588 && !drm_is_afbc(modifier) &&
+	    (format == DRM_FORMAT_XRGB2101010 || format == DRM_FORMAT_XBGR2101010)) {
+		drm_dbg_kms(vop2->drm, "Only support 10bpc format with afbc\n");
+		return false;
 	}
 
+	/* Linear is otherwise supported everywhere */
 	if (modifier == DRM_FORMAT_MOD_LINEAR)
 		return true;
 
-	if (!rockchip_afbc(plane, modifier)) {
-		drm_dbg_kms(vop2->drm, "Unsupported format modifier 0x%llx\n",
-			    modifier);
-
+	/* Not all format+modifier combinations are allowable */
+	if (vop2_convert_afbc_format(format) == VOP2_AFBC_FMT_INVALID)
 		return false;
+
+	/* Different windows have different format/modifier support */
+	for (i = 0; i < plane->modifier_count; i++) {
+		if (plane->modifiers[i] == modifier)
+			return true;
 	}
 
-	return vop2_convert_afbc_format(format) >= 0;
+	return false;
 }
 
 /*

-- 
2.52.0



From molberding at nvidia.com  Thu Dec 11 13:35:29 2025
From: molberding at nvidia.com (Marc Olberding)
Date: Thu, 11 Dec 2025 13:35:29 -0800
Subject: [PATCH] arm: dts: aspeed: add an alt 128M flash layout
Message-ID: <20251211-alt-128-layout-v1-1-100f57d2bc4a@nvidia.com>

Add a 128M layout for the BMC flash chip we didn't boot from. Including
this allows the user to write to each partition on the alternate spi
chip. This dtsi follows the existing standard of using the same layout
as non alt version and prepending `alt` to each partition's name.

Testing: Include this in msx4 and cat size, offsets and name
```
for devdir in /sys/class/mtd/mtd*; do
>     [[ -d $devdir && -r $devdir/name ]] || continue
>     name=$(<"$devdir/name")
>     [[ $name == alt* ]] || continue
>
>     size=$(<"$devdir/size")
>     offset=0
>     [[ -r $devdir/offset ]] && offset=$(<"$devdir/offset")
>
>     dev=$(basename "$devdir")
>     printf "%s name=%s offset=0x%X size=0x%X\n" "$dev" "$name" \
>        "$offset" "$size"
> done
mtd10 name=alt-rofs offset=0xA00000 size=0x5600000
mtd11 name=alt-rwfs offset=0x6000000 size=0x2000000
mtd7 name=alt-u-boot offset=0x0 size=0xE0000
mtd8 name=alt-u-boot-env offset=0xE0000 size=0x20000
mtd9 name=alt-kernel offset=0x100000 size=0x900000
```

Also ran dtbs_check on an existing dts with this included.

Signed-off-by: Marc Olberding <molberding at nvidia.com>
---
Add a layout for an alternate 128M flash layout. This is
useful for the aspeed ast2500[2] and ast2600[1] SoCs,
where it has the ability to boot from one of two spi chips,
nominally the primary and backup SPIs. Adding a layout allows userspace
to flash the alternate spi by partition and switch over to it, allowing
lower downtime for firmware flash, or for updating the primary
flash from the golden backup flash. This is already an established
scheme for the 32M and 64M layouts, where the layout is the same
but each partition has `alt` prepended to its name. This allows
userspace to just prepend alt to the images in the update process
to specify which flash chip to update.

References:

[1] https://www.aspeedtech.com/server_ast2600/
[2] https://www.aspeedtech.com/server_ast2500/
---
 .../dts/aspeed/openbmc-flash-layout-128-alt.dtsi   | 32 ++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/arch/arm/boot/dts/aspeed/openbmc-flash-layout-128-alt.dtsi b/arch/arm/boot/dts/aspeed/openbmc-flash-layout-128-alt.dtsi
new file mode 100644
index 0000000000000000000000000000000000000000..08ce2eab472c3da4aa3d841adb0eb1c971e6a25a
--- /dev/null
+++ b/arch/arm/boot/dts/aspeed/openbmc-flash-layout-128-alt.dtsi
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+partitions {
+	compatible = "fixed-partitions";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	u-boot at 0 {
+		reg = <0x0 0xe0000>; // 896KB
+		label = "alt-u-boot";
+	};
+
+	u-boot-env at e0000 {
+		reg = <0xe0000 0x20000>; // 128KB
+		label = "alt-u-boot-env";
+	};
+
+	kernel at 100000 {
+		reg = <0x100000 0x900000>; // 9MB
+		label = "alt-kernel";
+	};
+
+	rofs at a00000 {
+		reg = <0xa00000 0x5600000>; // 86MB
+		label = "alt-rofs";
+	};
+
+	rwfs at 6000000 {
+		reg = <0x6000000 0x2000000>; // 32MB
+		label = "alt-rwfs";
+	};
+};

---
base-commit: d358e5254674b70f34c847715ca509e46eb81e6f
change-id: 20251211-alt-128-layout-221a40665f08

Best regards,
-- 
Marc Olberding <molberding at nvidia.com>



From david.laight.linux at gmail.com  Thu Dec 11 14:38:22 2025
From: david.laight.linux at gmail.com (David Laight)
Date: Thu, 11 Dec 2025 22:38:22 +0000
Subject: [PATCH v4 1/8] drm/rockchip: vop2: Switch impossible format
 conditional to WARN_ON
In-Reply-To: <20251211-vop2-atomic-fixups-v4-1-5d50eda26bf8@collabora.com>
References: <20251211-vop2-atomic-fixups-v4-0-5d50eda26bf8@collabora.com>
	<20251211-vop2-atomic-fixups-v4-1-5d50eda26bf8@collabora.com>
Message-ID: <20251211223822.6eeabb4d@pumpkin>

On Thu, 11 Dec 2025 21:40:31 +0100
Nicolas Frattaroli <nicolas.frattaroli at collabora.com> wrote:

> From: Daniel Stone <daniels at collabora.com>
> 
> We should never be able to create a framebuffer with an unsupported
> format, so throw a warning if this ever happens, instead of attempting
> to stagger on.

It doesn't look like you've changed the behaviour.
Except that all the systems with PANIC_ON_WARN set will panic.
I believe that is somewhere over 90% of systems.

	David

> 
> Signed-off-by: Daniel Stone <daniels at collabora.com>
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
> ---
>  drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> index 498df0ce4680..20b49209ddcd 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> @@ -1030,7 +1030,8 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
>  		return 0;
>  
>  	format = vop2_convert_format(fb->format->format);
> -	if (format < 0)
> +	/* We shouldn't be able to create a fb for an unsupported format */
> +	if (WARN_ON(format < 0))
>  		return format;
>  
>  	/* Co-ordinates have now been clipped */
> 



From david.laight.linux at gmail.com  Thu Dec 11 14:41:02 2025
From: david.laight.linux at gmail.com (David Laight)
Date: Thu, 11 Dec 2025 22:41:02 +0000
Subject: [PATCH v4 2/8] drm/rockchip: vop2: Switch impossible pos
 conditional to WARN_ON
In-Reply-To: <20251211-vop2-atomic-fixups-v4-2-5d50eda26bf8@collabora.com>
References: <20251211-vop2-atomic-fixups-v4-0-5d50eda26bf8@collabora.com>
	<20251211-vop2-atomic-fixups-v4-2-5d50eda26bf8@collabora.com>
Message-ID: <20251211224102.5e079d70@pumpkin>

On Thu, 11 Dec 2025 21:40:32 +0100
Nicolas Frattaroli <nicolas.frattaroli at collabora.com> wrote:

> From: Daniel Stone <daniels at collabora.com>
> 
> We already clip the plane to the display bounds in atomic_check, and
> ensure that it is sufficiently sized. Instead of trying to catch this
> and adjust for it in atomic_update, just assert that atomic_check has
> done its job.
> 
> Signed-off-by: Daniel Stone <daniels at collabora.com>
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
> ---
>  drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 29 +++++++++-------------------
>  1 file changed, 9 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> index 20b49209ddcd..81b3eba07095 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> @@ -1214,28 +1214,17 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
>  	src_w = drm_rect_width(src) >> 16;
>  	src_h = drm_rect_height(src) >> 16;
>  	dsp_w = drm_rect_width(dest);
> -
> -	if (dest->x1 + dsp_w > adjusted_mode->hdisplay) {
> -		drm_dbg_kms(vop2->drm,
> -			    "vp%d %s dest->x1[%d] + dsp_w[%d] exceed mode hdisplay[%d]\n",
> -			    vp->id, win->data->name, dest->x1, dsp_w, adjusted_mode->hdisplay);
> -		dsp_w = adjusted_mode->hdisplay - dest->x1;
> -		if (dsp_w < 4)
> -			dsp_w = 4;
> -		src_w = dsp_w * src_w / drm_rect_width(dest);
> -	}
> -
>  	dsp_h = drm_rect_height(dest);
>  
> -	if (dest->y1 + dsp_h > adjusted_mode->vdisplay) {
> -		drm_dbg_kms(vop2->drm,
> -			    "vp%d %s dest->y1[%d] + dsp_h[%d] exceed mode vdisplay[%d]\n",
> -			    vp->id, win->data->name, dest->y1, dsp_h, adjusted_mode->vdisplay);
> -		dsp_h = adjusted_mode->vdisplay - dest->y1;
> -		if (dsp_h < 4)
> -			dsp_h = 4;
> -		src_h = dsp_h * src_h / drm_rect_height(dest);
> -	}
> +	/* drm_atomic_helper_check_plane_state calls drm_rect_clip_scaled for
> +	 * us, which keeps our planes bounded within the CRTC active area
> +	 */
> +	WARN_ON(dest->x1 + dsp_w > adjusted_mode->hdisplay);
> +	WARN_ON(dest->y1 + dsp_h > adjusted_mode->vdisplay);
> +	WARN_ON(dsp_w < 4);
> +	WARN_ON(dsp_h < 4);
> +	WARN_ON(src_w < 4);
> +	WARN_ON(src_h < 4);

You need to do something when the tests fail.
Carrying on regardless is never right.

	David



>  
>  	/*
>  	 * This is workaround solution for IC design:
> 



From osama.abdelkader at gmail.com  Thu Dec 11 14:40:28 2025
From: osama.abdelkader at gmail.com (Osama Abdelkader)
Date: Thu, 11 Dec 2025 23:40:28 +0100
Subject: [PATCH] KVM: arm64: vgic: add default case to switch statement
Message-ID: <20251211224033.18079-1-osama.abdelkader@gmail.com>

The switch statement in vgic_validate_injection() handles all enum
values for irq->config, but lacked a default case. Add one to match
the pattern used in other switch statements in the same file and make
the defensive return explicit.

Signed-off-by: Osama Abdelkader <osama.abdelkader at gmail.com>
---
 arch/arm64/kvm/vgic/vgic.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index 430aa98888fd..a035ce6231e2 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -369,9 +369,9 @@ static bool vgic_validate_injection(struct vgic_irq *irq, bool level, void *owne
 		return irq->line_level != level;
 	case VGIC_CONFIG_EDGE:
 		return level;
+	default:
+		return false;
 	}
-
-	return false;
 }
 
 static bool vgic_model_needs_bcst_kick(struct kvm *kvm)
-- 
2.43.0



From osama.abdelkader at gmail.com  Thu Dec 11 14:51:09 2025
From: osama.abdelkader at gmail.com (Osama Abdelkader)
Date: Thu, 11 Dec 2025 23:51:09 +0100
Subject: [PATCH] KVM: arm64: vgic: simplify vgic_v3_redist_region_full()
Message-ID: <20251211225114.20474-1-osama.abdelkader@gmail.com>

Simplify the function by converting the if-return-false pattern to a
direct boolean expression return, making the code more concise and
readable.

Signed-off-by: Osama Abdelkader <osama.abdelkader at gmail.com>
---
 arch/arm64/kvm/vgic/vgic.h | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index 5f0fc96b4dc2..04dd2055e7df 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -382,10 +382,7 @@ static inline int vgic_v3_max_apr_idx(struct kvm_vcpu *vcpu)
 static inline bool
 vgic_v3_redist_region_full(struct vgic_redist_region *region)
 {
-	if (!region->count)
-		return false;
-
-	return (region->free_index >= region->count);
+	return region->count > 0 && region->free_index >= region->count;
 }
 
 struct vgic_redist_region *vgic_v3_rdist_free_slot(struct list_head *rdregs);
-- 
2.43.0



From bmasney at redhat.com  Thu Dec 11 15:14:44 2025
From: bmasney at redhat.com (Brian Masney)
Date: Fri, 12 Dec 2025 08:14:44 +0900
Subject: [PATCH v3 0/9] phy: convert from clk round_rate() to
 determine_rate()
Message-ID: <20251212-phy-clk-round-rate-v3-0-4fa18b61f521@redhat.com>

The round_rate() clk ops is deprecated in the clk framework in favor
of the determine_rate() clk ops, so let's go ahead and convert the
drivers in the phy subsystem using the Coccinelle semantic patch
posted below. I did a few minor cosmetic cleanups of the code in a
few cases.

Changes since v2:
- Patch 8 (phy-rockchip-samsung-hdptx): fixed merge conflict so this now
  applies against next-20251211. Cristian / Heiko: I kept your
  Reviewed-by since structurally the code is still the same as before.
- Link to v2: https://lore.kernel.org/r/20250810-phy-clk-round-rate-v2-0-9162470bb9f2 at redhat.com

Changes since v1:
- Patch 8 (phy-rockchip-samsung-hdptx): fix returning error code
  (Cristian)

Coccinelle semantic patch:

    virtual patch

    // Look up the current name of the round_rate function
    @ has_round_rate @
    identifier round_rate_name =~ ".*_round_rate";
    identifier hw_param, rate_param, parent_rate_param;
    @@

    long round_rate_name(struct clk_hw *hw_param, unsigned long rate_param,
                  unsigned long *parent_rate_param)
    {
    	...
    }

    // Rename the route_rate function name to determine_rate()
    @ script:python generate_name depends on has_round_rate @
    round_rate_name << has_round_rate.round_rate_name;
    new_name;
    @@

    coccinelle.new_name = round_rate_name.replace("_round_rate", "_determine_rate")

    // Change rate to req->rate; also change occurrences of 'return XXX'.
    @ chg_rate depends on generate_name @
    identifier has_round_rate.round_rate_name;
    identifier has_round_rate.hw_param;
    identifier has_round_rate.rate_param;
    identifier has_round_rate.parent_rate_param;
    identifier ERR =~ "E.*";
    expression E;
    @@

    long round_rate_name(struct clk_hw *hw_param, unsigned long rate_param,
                  unsigned long *parent_rate_param)
    {
    <...
    (
    -return -ERR;
    +return -ERR;
    |
    - return rate_param;
    + return 0;
    |
    - return E;
    + req->rate = E;
    +
    + return 0;
    |
    - rate_param
    + req->rate
    )
    ...>
    }

    // Coccinelle only transforms the first occurrence of the rate parameter
    // Run a second time. FIXME: Is there a better way to do this?
    @ chg_rate2 depends on generate_name @
    identifier has_round_rate.round_rate_name;
    identifier has_round_rate.hw_param;
    identifier has_round_rate.rate_param;
    identifier has_round_rate.parent_rate_param;
    @@

    long round_rate_name(struct clk_hw *hw_param, unsigned long rate_param,
                  unsigned long *parent_rate_param)
    {
    <...
    - rate_param
    + req->rate
    ...>
    }

    // Change parent_rate to req->best_parent_rate
    @ chg_parent_rate depends on generate_name @
    identifier has_round_rate.round_rate_name;
    identifier has_round_rate.hw_param;
    identifier has_round_rate.rate_param;
    identifier has_round_rate.parent_rate_param;
    @@

    long round_rate_name(struct clk_hw *hw_param, unsigned long rate_param,
                  unsigned long *parent_rate_param)
    {
    <...
    (
    - *parent_rate_param
    + req->best_parent_rate
    |
    - parent_rate_param
    + &req->best_parent_rate
    )
    ...>
    }

    // Convert the function definition from round_rate() to determine_rate()
    @ func_definition depends on chg_rate @
    identifier has_round_rate.round_rate_name;
    identifier has_round_rate.hw_param;
    identifier has_round_rate.rate_param;
    identifier has_round_rate.parent_rate_param;
    identifier generate_name.new_name;
    @@

    - long round_rate_name(struct clk_hw *hw_param, unsigned long rate_param,
    -               unsigned long *parent_rate_param)
    + int new_name(struct clk_hw *hw, struct clk_rate_request *req)
    {
        ...
    }

    // Update the ops from round_rate() to determine_rate()
    @ ops depends on func_definition @
    identifier has_round_rate.round_rate_name;
    identifier generate_name.new_name;
    @@

    {
        ...,
    -   .round_rate = round_rate_name,
    +   .determine_rate = new_name,
        ...,
    }

Note that I used coccinelle 1.2 instead of 1.3 since the newer version
adds unnecessary braces as described in this post.
https://lore.kernel.org/cocci/67642477-5f3e-4b2a-914d-579a54f48cbd at intel.com/

Signed-off-by: Brian Masney <bmasney at redhat.com>
---
Brian Masney (9):
      phy: freescale: phy-fsl-samsung-hdmi: convert from round_rate() to determine_rate()
      phy: mediatek: phy-mtk-hdmi-mt2701: convert from round_rate() to determine_rate()
      phy: mediatek: phy-mtk-hdmi-mt8173: convert from round_rate() to determine_rate()
      phy: mediatek: phy-mtk-hdmi-mt8195: convert from round_rate() to determine_rate()
      phy: mediatek: phy-mtk-mipi-dsi-mt8173: convert from round_rate() to determine_rate()
      phy: mediatek: phy-mtk-mipi-dsi-mt8183: convert from round_rate() to determine_rate()
      phy: rockchip: phy-rockchip-inno-hdmi: convert from round_rate() to determine_rate()
      phy: rockchip: phy-rockchip-samsung-hdptx: convert from round_rate() to determine_rate()
      phy: ti: phy-j721e-wiz: convert from round_rate() to determine_rate()

 drivers/phy/freescale/phy-fsl-samsung-hdmi.c      | 13 ++++++----
 drivers/phy/mediatek/phy-mtk-hdmi-mt2701.c        |  8 +++---
 drivers/phy/mediatek/phy-mtk-hdmi-mt8173.c        | 16 ++++++------
 drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c        | 10 ++++----
 drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8173.c    | 10 +++++---
 drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8183.c    | 10 +++++---
 drivers/phy/rockchip/phy-rockchip-inno-hdmi.c     | 30 ++++++++++++-----------
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 15 +++++++-----
 drivers/phy/ti/phy-j721e-wiz.c                    | 11 ++++++---
 9 files changed, 69 insertions(+), 54 deletions(-)
---
base-commit: 5ce74bc1b7cb2732b22f9c93082545bc655d6547
change-id: 20250710-phy-clk-round-rate-4aa7ef160fe9

Best regards,
-- 
Brian Masney <bmasney at redhat.com>



From bmasney at redhat.com  Thu Dec 11 15:16:18 2025
From: bmasney at redhat.com (Brian Masney)
Date: Fri, 12 Dec 2025 08:16:18 +0900
Subject: [PATCH v3 0/9] phy: convert from clk round_rate() to
 determine_rate()
Message-ID: <20251212-phy-clk-round-rate-v3-0-beae3962f767@redhat.com>

The round_rate() clk ops is deprecated in the clk framework in favor
of the determine_rate() clk ops, so let's go ahead and convert the
drivers in the phy subsystem using the Coccinelle semantic patch
posted below. I did a few minor cosmetic cleanups of the code in a
few cases.

Changes since v2:
- Patch 8 (phy-rockchip-samsung-hdptx): fixed merge conflict so this now
  applies against next-20251211. Cristian / Heiko: I kept your
  Reviewed-by since structurally the code is still the same as before.
- Link to v2: https://lore.kernel.org/r/20250810-phy-clk-round-rate-v2-0-9162470bb9f2 at redhat.com

Changes since v1:
- Patch 8 (phy-rockchip-samsung-hdptx): fix returning error code
  (Cristian)

Coccinelle semantic patch:

    virtual patch

    // Look up the current name of the round_rate function
    @ has_round_rate @
    identifier round_rate_name =~ ".*_round_rate";
    identifier hw_param, rate_param, parent_rate_param;
    @@

    long round_rate_name(struct clk_hw *hw_param, unsigned long rate_param,
                  unsigned long *parent_rate_param)
    {
    	...
    }

    // Rename the route_rate function name to determine_rate()
    @ script:python generate_name depends on has_round_rate @
    round_rate_name << has_round_rate.round_rate_name;
    new_name;
    @@

    coccinelle.new_name = round_rate_name.replace("_round_rate", "_determine_rate")

    // Change rate to req->rate; also change occurrences of 'return XXX'.
    @ chg_rate depends on generate_name @
    identifier has_round_rate.round_rate_name;
    identifier has_round_rate.hw_param;
    identifier has_round_rate.rate_param;
    identifier has_round_rate.parent_rate_param;
    identifier ERR =~ "E.*";
    expression E;
    @@

    long round_rate_name(struct clk_hw *hw_param, unsigned long rate_param,
                  unsigned long *parent_rate_param)
    {
    <...
    (
    -return -ERR;
    +return -ERR;
    |
    - return rate_param;
    + return 0;
    |
    - return E;
    + req->rate = E;
    +
    + return 0;
    |
    - rate_param
    + req->rate
    )
    ...>
    }

    // Coccinelle only transforms the first occurrence of the rate parameter
    // Run a second time. FIXME: Is there a better way to do this?
    @ chg_rate2 depends on generate_name @
    identifier has_round_rate.round_rate_name;
    identifier has_round_rate.hw_param;
    identifier has_round_rate.rate_param;
    identifier has_round_rate.parent_rate_param;
    @@

    long round_rate_name(struct clk_hw *hw_param, unsigned long rate_param,
                  unsigned long *parent_rate_param)
    {
    <...
    - rate_param
    + req->rate
    ...>
    }

    // Change parent_rate to req->best_parent_rate
    @ chg_parent_rate depends on generate_name @
    identifier has_round_rate.round_rate_name;
    identifier has_round_rate.hw_param;
    identifier has_round_rate.rate_param;
    identifier has_round_rate.parent_rate_param;
    @@

    long round_rate_name(struct clk_hw *hw_param, unsigned long rate_param,
                  unsigned long *parent_rate_param)
    {
    <...
    (
    - *parent_rate_param
    + req->best_parent_rate
    |
    - parent_rate_param
    + &req->best_parent_rate
    )
    ...>
    }

    // Convert the function definition from round_rate() to determine_rate()
    @ func_definition depends on chg_rate @
    identifier has_round_rate.round_rate_name;
    identifier has_round_rate.hw_param;
    identifier has_round_rate.rate_param;
    identifier has_round_rate.parent_rate_param;
    identifier generate_name.new_name;
    @@

    - long round_rate_name(struct clk_hw *hw_param, unsigned long rate_param,
    -               unsigned long *parent_rate_param)
    + int new_name(struct clk_hw *hw, struct clk_rate_request *req)
    {
        ...
    }

    // Update the ops from round_rate() to determine_rate()
    @ ops depends on func_definition @
    identifier has_round_rate.round_rate_name;
    identifier generate_name.new_name;
    @@

    {
        ...,
    -   .round_rate = round_rate_name,
    +   .determine_rate = new_name,
        ...,
    }

Note that I used coccinelle 1.2 instead of 1.3 since the newer version
adds unnecessary braces as described in this post.
https://lore.kernel.org/cocci/67642477-5f3e-4b2a-914d-579a54f48cbd at intel.com/

Signed-off-by: Brian Masney <bmasney at redhat.com>
---
Brian Masney (9):
      phy: freescale: phy-fsl-samsung-hdmi: convert from round_rate() to determine_rate()
      phy: mediatek: phy-mtk-hdmi-mt2701: convert from round_rate() to determine_rate()
      phy: mediatek: phy-mtk-hdmi-mt8173: convert from round_rate() to determine_rate()
      phy: mediatek: phy-mtk-hdmi-mt8195: convert from round_rate() to determine_rate()
      phy: mediatek: phy-mtk-mipi-dsi-mt8173: convert from round_rate() to determine_rate()
      phy: mediatek: phy-mtk-mipi-dsi-mt8183: convert from round_rate() to determine_rate()
      phy: rockchip: phy-rockchip-inno-hdmi: convert from round_rate() to determine_rate()
      phy: rockchip: phy-rockchip-samsung-hdptx: convert from round_rate() to determine_rate()
      phy: ti: phy-j721e-wiz: convert from round_rate() to determine_rate()

 drivers/phy/freescale/phy-fsl-samsung-hdmi.c      | 13 ++++++----
 drivers/phy/mediatek/phy-mtk-hdmi-mt2701.c        |  8 +++---
 drivers/phy/mediatek/phy-mtk-hdmi-mt8173.c        | 16 ++++++------
 drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c        | 10 ++++----
 drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8173.c    | 10 +++++---
 drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8183.c    | 10 +++++---
 drivers/phy/rockchip/phy-rockchip-inno-hdmi.c     | 30 ++++++++++++-----------
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 15 +++++++-----
 drivers/phy/ti/phy-j721e-wiz.c                    | 11 ++++++---
 9 files changed, 69 insertions(+), 54 deletions(-)
---
base-commit: 5ce74bc1b7cb2732b22f9c93082545bc655d6547
change-id: 20250710-phy-clk-round-rate-4aa7ef160fe9

Best regards,
-- 
Brian Masney <bmasney at redhat.com>



From bmasney at redhat.com  Thu Dec 11 15:16:19 2025
From: bmasney at redhat.com (Brian Masney)
Date: Fri, 12 Dec 2025 08:16:19 +0900
Subject: [PATCH v3 1/9] phy: freescale: phy-fsl-samsung-hdmi: convert from
 round_rate() to determine_rate()
In-Reply-To: <20251212-phy-clk-round-rate-v3-0-beae3962f767@redhat.com>
References: <20251212-phy-clk-round-rate-v3-0-beae3962f767@redhat.com>
Message-ID: <20251212-phy-clk-round-rate-v3-1-beae3962f767@redhat.com>

The round_rate() clk ops is deprecated, so migrate this driver from
round_rate() to determine_rate() using the Coccinelle semantic patch
on the cover letter of this series.

Signed-off-by: Brian Masney <bmasney at redhat.com>
---
 drivers/phy/freescale/phy-fsl-samsung-hdmi.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/phy/freescale/phy-fsl-samsung-hdmi.c b/drivers/phy/freescale/phy-fsl-samsung-hdmi.c
index 191c282246d96e3f6c5a8d17abe078892882bf44..d010fec15671d33cc363af79e9f1c3f26ecb3464 100644
--- a/drivers/phy/freescale/phy-fsl-samsung-hdmi.c
+++ b/drivers/phy/freescale/phy-fsl-samsung-hdmi.c
@@ -570,17 +570,20 @@ const struct phy_config *fsl_samsung_hdmi_phy_find_settings(struct fsl_samsung_h
 	return fract_div_phy;
 }
 
-static long fsl_samsung_hdmi_phy_clk_round_rate(struct clk_hw *hw,
-						unsigned long rate, unsigned long *parent_rate)
+static int fsl_samsung_hdmi_phy_clk_determine_rate(struct clk_hw *hw,
+						   struct clk_rate_request *req)
 {
 	struct fsl_samsung_hdmi_phy *phy = to_fsl_samsung_hdmi_phy(hw);
-	const struct phy_config *target_settings = fsl_samsung_hdmi_phy_find_settings(phy, rate);
+	const struct phy_config *target_settings = fsl_samsung_hdmi_phy_find_settings(phy,
+										      req->rate);
 
 	if (target_settings == NULL)
 		return -EINVAL;
 
 	dev_dbg(phy->dev, "round_rate, closest rate = %u\n", target_settings->pixclk);
-	return target_settings->pixclk;
+	req->rate = target_settings->pixclk;
+
+	return 0;
 }
 
 static int fsl_samsung_hdmi_phy_clk_set_rate(struct clk_hw *hw,
@@ -599,7 +602,7 @@ static int fsl_samsung_hdmi_phy_clk_set_rate(struct clk_hw *hw,
 
 static const struct clk_ops phy_clk_ops = {
 	.recalc_rate = phy_clk_recalc_rate,
-	.round_rate = fsl_samsung_hdmi_phy_clk_round_rate,
+	.determine_rate = fsl_samsung_hdmi_phy_clk_determine_rate,
 	.set_rate = fsl_samsung_hdmi_phy_clk_set_rate,
 };
 

-- 
2.52.0



From bmasney at redhat.com  Thu Dec 11 15:16:21 2025
From: bmasney at redhat.com (Brian Masney)
Date: Fri, 12 Dec 2025 08:16:21 +0900
Subject: [PATCH v3 3/9] phy: mediatek: phy-mtk-hdmi-mt8173: convert from
 round_rate() to determine_rate()
In-Reply-To: <20251212-phy-clk-round-rate-v3-0-beae3962f767@redhat.com>
References: <20251212-phy-clk-round-rate-v3-0-beae3962f767@redhat.com>
Message-ID: <20251212-phy-clk-round-rate-v3-3-beae3962f767@redhat.com>

The round_rate() clk ops is deprecated, so migrate this driver from
round_rate() to determine_rate() using the Coccinelle semantic patch
on the cover letter of this series.

Signed-off-by: Brian Masney <bmasney at redhat.com>
---
 drivers/phy/mediatek/phy-mtk-hdmi-mt8173.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/phy/mediatek/phy-mtk-hdmi-mt8173.c b/drivers/phy/mediatek/phy-mtk-hdmi-mt8173.c
index d04758396046363ab9edc584ae10bf31e9c5fb0f..58c6596c8c20bdacf96a97709b8f5709f447e85b 100644
--- a/drivers/phy/mediatek/phy-mtk-hdmi-mt8173.c
+++ b/drivers/phy/mediatek/phy-mtk-hdmi-mt8173.c
@@ -118,18 +118,18 @@ static void mtk_hdmi_pll_unprepare(struct clk_hw *hw)
 	usleep_range(100, 150);
 }
 
-static long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate,
-				    unsigned long *parent_rate)
+static int mtk_hdmi_pll_determine_rate(struct clk_hw *hw,
+				       struct clk_rate_request *req)
 {
 	struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw);
 
-	hdmi_phy->pll_rate = rate;
-	if (rate <= 74250000)
-		*parent_rate = rate;
+	hdmi_phy->pll_rate = req->rate;
+	if (req->rate <= 74250000)
+		req->best_parent_rate = req->rate;
 	else
-		*parent_rate = rate / 2;
+		req->best_parent_rate = req->rate / 2;
 
-	return rate;
+	return 0;
 }
 
 static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -223,7 +223,7 @@ static const struct clk_ops mtk_hdmi_phy_pll_ops = {
 	.prepare = mtk_hdmi_pll_prepare,
 	.unprepare = mtk_hdmi_pll_unprepare,
 	.set_rate = mtk_hdmi_pll_set_rate,
-	.round_rate = mtk_hdmi_pll_round_rate,
+	.determine_rate = mtk_hdmi_pll_determine_rate,
 	.recalc_rate = mtk_hdmi_pll_recalc_rate,
 };
 

-- 
2.52.0



From bmasney at redhat.com  Thu Dec 11 15:16:20 2025
From: bmasney at redhat.com (Brian Masney)
Date: Fri, 12 Dec 2025 08:16:20 +0900
Subject: [PATCH v3 2/9] phy: mediatek: phy-mtk-hdmi-mt2701: convert from
 round_rate() to determine_rate()
In-Reply-To: <20251212-phy-clk-round-rate-v3-0-beae3962f767@redhat.com>
References: <20251212-phy-clk-round-rate-v3-0-beae3962f767@redhat.com>
Message-ID: <20251212-phy-clk-round-rate-v3-2-beae3962f767@redhat.com>

The round_rate() clk ops is deprecated, so migrate this driver from
round_rate() to determine_rate() using the Coccinelle semantic patch
on the cover letter of this series.

Signed-off-by: Brian Masney <bmasney at redhat.com>
---
 drivers/phy/mediatek/phy-mtk-hdmi-mt2701.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/phy/mediatek/phy-mtk-hdmi-mt2701.c b/drivers/phy/mediatek/phy-mtk-hdmi-mt2701.c
index e51b2d13eab473dddace48c75c2a8d73c8c65635..b0b6497e7eedcb6867541b573d22156ded29a4d5 100644
--- a/drivers/phy/mediatek/phy-mtk-hdmi-mt2701.c
+++ b/drivers/phy/mediatek/phy-mtk-hdmi-mt2701.c
@@ -90,10 +90,10 @@ static void mtk_hdmi_pll_unprepare(struct clk_hw *hw)
 	usleep_range(80, 100);
 }
 
-static long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate,
-				    unsigned long *parent_rate)
+static int mtk_hdmi_pll_determine_rate(struct clk_hw *hw,
+				       struct clk_rate_request *req)
 {
-	return rate;
+	return 0;
 }
 
 static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -170,7 +170,7 @@ static const struct clk_ops mtk_hdmi_phy_pll_ops = {
 	.prepare = mtk_hdmi_pll_prepare,
 	.unprepare = mtk_hdmi_pll_unprepare,
 	.set_rate = mtk_hdmi_pll_set_rate,
-	.round_rate = mtk_hdmi_pll_round_rate,
+	.determine_rate = mtk_hdmi_pll_determine_rate,
 	.recalc_rate = mtk_hdmi_pll_recalc_rate,
 };
 

-- 
2.52.0



From bmasney at redhat.com  Thu Dec 11 15:16:22 2025
From: bmasney at redhat.com (Brian Masney)
Date: Fri, 12 Dec 2025 08:16:22 +0900
Subject: [PATCH v3 4/9] phy: mediatek: phy-mtk-hdmi-mt8195: convert from
 round_rate() to determine_rate()
In-Reply-To: <20251212-phy-clk-round-rate-v3-0-beae3962f767@redhat.com>
References: <20251212-phy-clk-round-rate-v3-0-beae3962f767@redhat.com>
Message-ID: <20251212-phy-clk-round-rate-v3-4-beae3962f767@redhat.com>

The round_rate() clk ops is deprecated, so migrate this driver from
round_rate() to determine_rate() using the Coccinelle semantic patch
on the cover letter of this series.

Tested-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
Signed-off-by: Brian Masney <bmasney at redhat.com>
---
 drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c b/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c
index b38f3ae26b3f3d8c9e73b43d86510acf6cedb471..1426a2db984d53b91125b18f7725738c44f19555 100644
--- a/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c
+++ b/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c
@@ -418,13 +418,13 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
 	return mtk_hdmi_pll_calc(hdmi_phy, hw, rate, parent_rate);
 }
 
-static long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate,
-				    unsigned long *parent_rate)
+static int mtk_hdmi_pll_determine_rate(struct clk_hw *hw,
+				       struct clk_rate_request *req)
 {
 	struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw);
 
-	hdmi_phy->pll_rate = rate;
-	return rate;
+	hdmi_phy->pll_rate = req->rate;
+	return 0;
 }
 
 static unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw,
@@ -439,7 +439,7 @@ static const struct clk_ops mtk_hdmi_pll_ops = {
 	.prepare = mtk_hdmi_pll_prepare,
 	.unprepare = mtk_hdmi_pll_unprepare,
 	.set_rate = mtk_hdmi_pll_set_rate,
-	.round_rate = mtk_hdmi_pll_round_rate,
+	.determine_rate = mtk_hdmi_pll_determine_rate,
 	.recalc_rate = mtk_hdmi_pll_recalc_rate,
 };
 

-- 
2.52.0



From bmasney at redhat.com  Thu Dec 11 15:16:24 2025
From: bmasney at redhat.com (Brian Masney)
Date: Fri, 12 Dec 2025 08:16:24 +0900
Subject: [PATCH v3 6/9] phy: mediatek: phy-mtk-mipi-dsi-mt8183: convert
 from round_rate() to determine_rate()
In-Reply-To: <20251212-phy-clk-round-rate-v3-0-beae3962f767@redhat.com>
References: <20251212-phy-clk-round-rate-v3-0-beae3962f767@redhat.com>
Message-ID: <20251212-phy-clk-round-rate-v3-6-beae3962f767@redhat.com>

The round_rate() clk ops is deprecated, so migrate this driver from
round_rate() to determine_rate() using the Coccinelle semantic patch
on the cover letter of this series.

Signed-off-by: Brian Masney <bmasney at redhat.com>
---
 drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8183.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8183.c b/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8183.c
index 553725e1269c9d7ad88f89367dfa1cf367aaf1ce..a54d44ef70ab49937d210f04fdf42300e8e5f2de 100644
--- a/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8183.c
+++ b/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8183.c
@@ -97,16 +97,18 @@ static void mtk_mipi_tx_pll_disable(struct clk_hw *hw)
 	mtk_phy_clear_bits(base + MIPITX_PLL_PWR, AD_DSI_PLL_SDM_PWR_ON);
 }
 
-static long mtk_mipi_tx_pll_round_rate(struct clk_hw *hw, unsigned long rate,
-				       unsigned long *prate)
+static int mtk_mipi_tx_pll_determine_rate(struct clk_hw *hw,
+					  struct clk_rate_request *req)
 {
-	return clamp_val(rate, 125000000, 1600000000);
+	req->rate = clamp_val(req->rate, 125000000, 1600000000);
+
+	return 0;
 }
 
 static const struct clk_ops mtk_mipi_tx_pll_ops = {
 	.enable = mtk_mipi_tx_pll_enable,
 	.disable = mtk_mipi_tx_pll_disable,
-	.round_rate = mtk_mipi_tx_pll_round_rate,
+	.determine_rate = mtk_mipi_tx_pll_determine_rate,
 	.set_rate = mtk_mipi_tx_pll_set_rate,
 	.recalc_rate = mtk_mipi_tx_pll_recalc_rate,
 };

-- 
2.52.0



From bmasney at redhat.com  Thu Dec 11 15:16:23 2025
From: bmasney at redhat.com (Brian Masney)
Date: Fri, 12 Dec 2025 08:16:23 +0900
Subject: [PATCH v3 5/9] phy: mediatek: phy-mtk-mipi-dsi-mt8173: convert
 from round_rate() to determine_rate()
In-Reply-To: <20251212-phy-clk-round-rate-v3-0-beae3962f767@redhat.com>
References: <20251212-phy-clk-round-rate-v3-0-beae3962f767@redhat.com>
Message-ID: <20251212-phy-clk-round-rate-v3-5-beae3962f767@redhat.com>

The round_rate() clk ops is deprecated, so migrate this driver from
round_rate() to determine_rate() using the Coccinelle semantic patch
on the cover letter of this series.

Signed-off-by: Brian Masney <bmasney at redhat.com>
---
 drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8173.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8173.c b/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8173.c
index 673cb0f08959e0e4f2b1ade2ebaf796e8b76f8bc..438ff3605d90121b7bfe02b3ddca8194437ed9ba 100644
--- a/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8173.c
+++ b/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8173.c
@@ -237,16 +237,18 @@ static void mtk_mipi_tx_pll_unprepare(struct clk_hw *hw)
 	mtk_phy_clear_bits(base + MIPITX_DSI_PLL_CON0, RG_DSI_MPPLL_DIV_MSK);
 }
 
-static long mtk_mipi_tx_pll_round_rate(struct clk_hw *hw, unsigned long rate,
-				       unsigned long *prate)
+static int mtk_mipi_tx_pll_determine_rate(struct clk_hw *hw,
+					  struct clk_rate_request *req)
 {
-	return clamp_val(rate, 50000000, 1250000000);
+	req->rate = clamp_val(req->rate, 50000000, 1250000000);
+
+	return 0;
 }
 
 static const struct clk_ops mtk_mipi_tx_pll_ops = {
 	.prepare = mtk_mipi_tx_pll_prepare,
 	.unprepare = mtk_mipi_tx_pll_unprepare,
-	.round_rate = mtk_mipi_tx_pll_round_rate,
+	.determine_rate = mtk_mipi_tx_pll_determine_rate,
 	.set_rate = mtk_mipi_tx_pll_set_rate,
 	.recalc_rate = mtk_mipi_tx_pll_recalc_rate,
 };

-- 
2.52.0



From bmasney at redhat.com  Thu Dec 11 15:16:25 2025
From: bmasney at redhat.com (Brian Masney)
Date: Fri, 12 Dec 2025 08:16:25 +0900
Subject: [PATCH v3 7/9] phy: rockchip: phy-rockchip-inno-hdmi: convert from
 round_rate() to determine_rate()
In-Reply-To: <20251212-phy-clk-round-rate-v3-0-beae3962f767@redhat.com>
References: <20251212-phy-clk-round-rate-v3-0-beae3962f767@redhat.com>
Message-ID: <20251212-phy-clk-round-rate-v3-7-beae3962f767@redhat.com>

The round_rate() clk ops is deprecated, so migrate this driver from
round_rate() to determine_rate() using the Coccinelle semantic patch
on the cover letter of this series.

Reviewed-by: Heiko Stuebner <heiko at sntech.de>
Signed-off-by: Brian Masney <bmasney at redhat.com>
---
 drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 30 ++++++++++++++-------------
 1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
index 8dcc2bb777b5455d21a10f06c5ad842b2ddbc834..1483907413faa5ce1dc8614db05e6e929410404d 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
@@ -749,22 +749,23 @@ unsigned long inno_hdmi_phy_rk3228_clk_recalc_rate(struct clk_hw *hw,
 	return vco;
 }
 
-static long inno_hdmi_phy_rk3228_clk_round_rate(struct clk_hw *hw,
-						unsigned long rate,
-						unsigned long *parent_rate)
+static int inno_hdmi_phy_rk3228_clk_determine_rate(struct clk_hw *hw,
+						   struct clk_rate_request *req)
 {
 	const struct pre_pll_config *cfg = pre_pll_cfg_table;
 
-	rate = (rate / 1000) * 1000;
+	req->rate = (req->rate / 1000) * 1000;
 
 	for (; cfg->pixclock != 0; cfg++)
-		if (cfg->pixclock == rate && !cfg->fracdiv)
+		if (cfg->pixclock == req->rate && !cfg->fracdiv)
 			break;
 
 	if (cfg->pixclock == 0)
 		return -EINVAL;
 
-	return cfg->pixclock;
+	req->rate = cfg->pixclock;
+
+	return 0;
 }
 
 static int inno_hdmi_phy_rk3228_clk_set_rate(struct clk_hw *hw,
@@ -835,7 +836,7 @@ static const struct clk_ops inno_hdmi_phy_rk3228_clk_ops = {
 	.unprepare = inno_hdmi_phy_rk3228_clk_unprepare,
 	.is_prepared = inno_hdmi_phy_rk3228_clk_is_prepared,
 	.recalc_rate = inno_hdmi_phy_rk3228_clk_recalc_rate,
-	.round_rate = inno_hdmi_phy_rk3228_clk_round_rate,
+	.determine_rate = inno_hdmi_phy_rk3228_clk_determine_rate,
 	.set_rate = inno_hdmi_phy_rk3228_clk_set_rate,
 };
 
@@ -906,22 +907,23 @@ unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw,
 	return inno->pixclock;
 }
 
-static long inno_hdmi_phy_rk3328_clk_round_rate(struct clk_hw *hw,
-						unsigned long rate,
-						unsigned long *parent_rate)
+static int inno_hdmi_phy_rk3328_clk_determine_rate(struct clk_hw *hw,
+						   struct clk_rate_request *req)
 {
 	const struct pre_pll_config *cfg = pre_pll_cfg_table;
 
-	rate = (rate / 1000) * 1000;
+	req->rate = (req->rate / 1000) * 1000;
 
 	for (; cfg->pixclock != 0; cfg++)
-		if (cfg->pixclock == rate)
+		if (cfg->pixclock == req->rate)
 			break;
 
 	if (cfg->pixclock == 0)
 		return -EINVAL;
 
-	return cfg->pixclock;
+	req->rate = cfg->pixclock;
+
+	return 0;
 }
 
 static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw,
@@ -989,7 +991,7 @@ static const struct clk_ops inno_hdmi_phy_rk3328_clk_ops = {
 	.unprepare = inno_hdmi_phy_rk3328_clk_unprepare,
 	.is_prepared = inno_hdmi_phy_rk3328_clk_is_prepared,
 	.recalc_rate = inno_hdmi_phy_rk3328_clk_recalc_rate,
-	.round_rate = inno_hdmi_phy_rk3328_clk_round_rate,
+	.determine_rate = inno_hdmi_phy_rk3328_clk_determine_rate,
 	.set_rate = inno_hdmi_phy_rk3328_clk_set_rate,
 };
 

-- 
2.52.0



From bmasney at redhat.com  Thu Dec 11 15:16:26 2025
From: bmasney at redhat.com (Brian Masney)
Date: Fri, 12 Dec 2025 08:16:26 +0900
Subject: [PATCH v3 8/9] phy: rockchip: phy-rockchip-samsung-hdptx: convert
 from round_rate() to determine_rate()
In-Reply-To: <20251212-phy-clk-round-rate-v3-0-beae3962f767@redhat.com>
References: <20251212-phy-clk-round-rate-v3-0-beae3962f767@redhat.com>
Message-ID: <20251212-phy-clk-round-rate-v3-8-beae3962f767@redhat.com>

The round_rate() clk ops is deprecated, so migrate this driver from
round_rate() to determine_rate() using the Coccinelle semantic patch
on the cover letter of this series.

Reviewed-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
Reviewed-by: Heiko Stuebner <heiko at sntech.de>
Signed-off-by: Brian Masney <bmasney at redhat.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index 29de2f7bdae8a31958e31b0a64281532fd76e64d..315ac97f52d8af6d3010dc87788575039c7a6b40 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -1870,8 +1870,8 @@ static unsigned long rk_hdptx_phy_clk_recalc_rate(struct clk_hw *hw,
 	return hdptx->hw_rate;
 }
 
-static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate,
-					unsigned long *parent_rate)
+static int rk_hdptx_phy_clk_determine_rate(struct clk_hw *hw,
+					   struct clk_rate_request *req)
 {
 	struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
 
@@ -1880,9 +1880,9 @@ static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate,
 	 * To be dropped as soon as the RK DW HDMI QP bridge driver
 	 * switches to make use of phy_configure().
 	 */
-	if (!hdptx->restrict_rate_change && rate != hdptx->hdmi_cfg.tmds_char_rate) {
+	if (!hdptx->restrict_rate_change && req->rate != hdptx->hdmi_cfg.tmds_char_rate) {
 		struct phy_configure_opts_hdmi hdmi = {
-			.tmds_char_rate = rate,
+			.tmds_char_rate = req->rate,
 		};
 		int ret = rk_hdptx_phy_verify_hdmi_config(hdptx, &hdmi);
 
@@ -1897,7 +1897,10 @@ static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate,
 	 * hence ensure rk_hdptx_phy_clk_set_rate() won't be invoked with
 	 * a different rate argument.
 	 */
-	return DIV_ROUND_CLOSEST_ULL(hdptx->hdmi_cfg.tmds_char_rate * 8, hdptx->hdmi_cfg.bpc);
+	req->rate = DIV_ROUND_CLOSEST_ULL(hdptx->hdmi_cfg.tmds_char_rate * 8,
+					  hdptx->hdmi_cfg.bpc);
+
+	return 0;
 }
 
 static int rk_hdptx_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -1927,7 +1930,7 @@ static const struct clk_ops hdptx_phy_clk_ops = {
 	.prepare = rk_hdptx_phy_clk_prepare,
 	.unprepare = rk_hdptx_phy_clk_unprepare,
 	.recalc_rate = rk_hdptx_phy_clk_recalc_rate,
-	.round_rate = rk_hdptx_phy_clk_round_rate,
+	.determine_rate = rk_hdptx_phy_clk_determine_rate,
 	.set_rate = rk_hdptx_phy_clk_set_rate,
 };
 

-- 
2.52.0



From bmasney at redhat.com  Thu Dec 11 15:16:27 2025
From: bmasney at redhat.com (Brian Masney)
Date: Fri, 12 Dec 2025 08:16:27 +0900
Subject: [PATCH v3 9/9] phy: ti: phy-j721e-wiz: convert from round_rate()
 to determine_rate()
In-Reply-To: <20251212-phy-clk-round-rate-v3-0-beae3962f767@redhat.com>
References: <20251212-phy-clk-round-rate-v3-0-beae3962f767@redhat.com>
Message-ID: <20251212-phy-clk-round-rate-v3-9-beae3962f767@redhat.com>

The round_rate() clk ops is deprecated, so migrate this driver from
round_rate() to determine_rate() using the Coccinelle semantic patch
on the cover letter of this series.

Signed-off-by: Brian Masney <bmasney at redhat.com>
---
 drivers/phy/ti/phy-j721e-wiz.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c
index a8b440c6c46bb0c754845655f9c2c0ba6b435b8d..cbc98d4dec74560e6403fb899ebe2bb916440f45 100644
--- a/drivers/phy/ti/phy-j721e-wiz.c
+++ b/drivers/phy/ti/phy-j721e-wiz.c
@@ -934,12 +934,15 @@ static unsigned long wiz_clk_div_recalc_rate(struct clk_hw *hw,
 	return divider_recalc_rate(hw, parent_rate, val, div->table, 0x0, 2);
 }
 
-static long wiz_clk_div_round_rate(struct clk_hw *hw, unsigned long rate,
-				   unsigned long *prate)
+static int wiz_clk_div_determine_rate(struct clk_hw *hw,
+				      struct clk_rate_request *req)
 {
 	struct wiz_clk_divider *div = to_wiz_clk_div(hw);
 
-	return divider_round_rate(hw, rate, prate, div->table, 2, 0x0);
+	req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate,
+				       div->table, 2, 0x0);
+
+	return 0;
 }
 
 static int wiz_clk_div_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -958,7 +961,7 @@ static int wiz_clk_div_set_rate(struct clk_hw *hw, unsigned long rate,
 
 static const struct clk_ops wiz_clk_div_ops = {
 	.recalc_rate = wiz_clk_div_recalc_rate,
-	.round_rate = wiz_clk_div_round_rate,
+	.determine_rate = wiz_clk_div_determine_rate,
 	.set_rate = wiz_clk_div_set_rate,
 };
 

-- 
2.52.0



From tglx at linutronix.de  Thu Dec 11 17:12:13 2025
From: tglx at linutronix.de (Thomas Gleixner)
Date: Fri, 12 Dec 2025 10:12:13 +0900
Subject: [PATCH v9 15/16] entry: Inline syscall_exit_work()
In-Reply-To: <e55e9aae-1d84-42a2-bf6a-edc73608733a@arm.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
 <20251204082123.2792067-16-ruanjinjie@huawei.com>
 <b382cc8a-3ce9-4fb1-bc0a-a3d9796251d1@arm.com> <87345hfqyh.ffs@tglx>
 <e55e9aae-1d84-42a2-bf6a-edc73608733a@arm.com>
Message-ID: <87wm2sec5u.ffs@tglx>

On Thu, Dec 11 2025 at 10:52, Kevin Brodsky wrote:
> On 11/12/2025 07:55, Thomas Gleixner wrote:
>> I have a suspicion that it is TIF_NOTIFY_RESUME. If that's the case
>> you're seing the RSEQ overhead, which should be completely gone with the
>> rewrite that got just merged into Linus tree.
>
> I don't think this is related. This patch inlines syscall_exit_work(),
> which is called if some flag in SYSCALL_WORK_EXIT is set. This includes
> syscall-specific stuff like tracing and singlestep. TIF_NOTIFY_RESUME is
> part of EXIT_TO_USER_MODE_WORK, handled in exit_to_user_mode_prepare(),
> and isn't specific to syscall handling.

Indeed. Confused myself.


From jie.gan at oss.qualcomm.com  Thu Dec 11 17:12:19 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Fri, 12 Dec 2025 09:12:19 +0800
Subject: [PATCH v8 5/8] dt-bindings: arm: add an interrupt property for
 Coresight CTCU
In-Reply-To: <20251211133723.GA859302-robh@kernel.org>
References: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
 <20251211-enable-byte-cntr-for-ctcu-v8-5-3e12ff313191@oss.qualcomm.com>
 <20251211133723.GA859302-robh@kernel.org>
Message-ID: <dfa43a63-ca14-4dd7-a7ab-acd95748a8b9@oss.qualcomm.com>



On 12/11/2025 9:37 PM, Rob Herring wrote:
> On Thu, Dec 11, 2025 at 02:10:44PM +0800, Jie Gan wrote:
>> Add an interrupt property to CTCU device. The interrupt will be triggered
>> when the data size in the ETR buffer exceeds the threshold of the
>> BYTECNTRVAL register. Programming a threshold in the BYTECNTRVAL register
>> of CTCU device will enable the interrupt.
>>
>> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
>> Reviewed-by: Mike Leach <mike.leach at linaro.org>
>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> ---
>>   .../devicetree/bindings/arm/qcom,coresight-ctcu.yaml    | 17 +++++++++++++++++
>>   1 file changed, 17 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
>> index c969c16c21ef..90f88cc6cd3e 100644
>> --- a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
>> +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
>> @@ -39,6 +39,16 @@ properties:
>>       items:
>>         - const: apb
>>   
>> +  interrupts:
>> +    items:
>> +      - description: Byte cntr interrupt for the first etr device
>> +      - description: Byte cntr interrupt for the second etr device
>> +
>> +  interrupt-names:
>> +    items:
>> +      - const: etrirq0
>> +      - const: etrirq1
> 
> Names are kind of pointless when it is just foo<index>.

Hi Rob,

I was naming them as etr0/etr1. Are these names acceptable?
The interrupts are assigned exclusively to a specific ETR device.

But Suzuki is concerned that this might cause confusion because the ETR 
device is named randomly in the driver. Suzuki suggested using ?port-0? 
and ?port-1? and would also like to hear your feedback on these names.

Usually, the probe sequence follows the order of the addresses. In our 
specification, ?ETR0? is always probed before ?ETR1? because its address 
is lower.

I would greatly appreciate your suggestion for the interrupt name, if 
possible.

Thanks,
Jie

> 
>> +
>>     label:
>>       description:
>>         Description of a coresight device.
>> @@ -60,6 +70,8 @@ additionalProperties: false
>>   
>>   examples:
>>     - |
>> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
>> +
>>       ctcu at 1001000 {
>>           compatible = "qcom,sa8775p-ctcu";
>>           reg = <0x1001000 0x1000>;
>> @@ -67,6 +79,11 @@ examples:
>>           clocks = <&aoss_qmp>;
>>           clock-names = "apb";
>>   
>> +        interrupts = <GIC_SPI 270 IRQ_TYPE_EDGE_RISING>,
>> +                     <GIC_SPI 262 IRQ_TYPE_EDGE_RISING>;
>> +        interrupt-names = "etrirq0",
>> +                          "etrirq1;
>> +
>>           in-ports {
>>               #address-cells = <1>;
>>               #size-cells = <0>;
>>
>> -- 
>> 2.34.1
>>



From ruanjinjie at huawei.com  Thu Dec 11 17:26:37 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Fri, 12 Dec 2025 09:26:37 +0800
Subject: [PATCH v9 15/16] entry: Inline syscall_exit_work()
In-Reply-To: <87345hfqyh.ffs@tglx>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
 <20251204082123.2792067-16-ruanjinjie@huawei.com>
 <b382cc8a-3ce9-4fb1-bc0a-a3d9796251d1@arm.com> <87345hfqyh.ffs@tglx>
Message-ID: <77e16fa4-3024-2068-9bb2-82a904eec112@huawei.com>



On 2025/12/11 14:55, Thomas Gleixner wrote:
> On Tue, Dec 09 2025 at 14:48, Kevin Brodsky wrote:
>> On 04/12/2025 09:21, Jinjie Ruan wrote:
>>> After switch arm64 to Generic Entry, a new hotspot syscall_exit_work()
>>> appeared because syscall_exit_work() is no longer inlined. so inline
>>
>> Before this series the call to syscall_trace_exit() in el0_svc_common()
>> could not be inlined, so "no longer inlined" doesn't seem to be accurate.
>>
>>> syscall_exit_work(), and it has 2.6% performance uplift on perf bench
>>> basic syscall on kunpeng920 as below.
>>
>> That seems strange. syscall_exit_work() is only called if some flag in
>> SYSCALL_WORK_EXIT is set, which means that we're doing something special
>> like tracing. That shouldn't be the case when running a simple perf
>> bench syscall.
>>
>> Also worth nothing that its counterpart (syscall_trace_enter())) is not
>> currently inlined, the asymmetry would have to be justified.
>>
>>>     | Metric     | W/O this patch | With this patch | Change    |
>>>     | ---------- | -------------- | --------------- | --------- |
>>>     | Total time | 2.171 [sec]    | 2.114 [sec]     |  ?2.6%    |
>>>     | usecs/op   | 0.217192       | 0.211453        |  ?2.6%    |
>>>     | ops/sec    | 4,604,225      | 4,729,178       |  ?2.7%    |
>>>
>>> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
>>> ---
>>>  include/linux/entry-common.h  | 63 ++++++++++++++++++++++++++++++++++-
>>>  kernel/entry/syscall-common.c | 59 ++------------------------------
>>
>> These changes are purely generic, surely all architectures using
>> GENERIC_ENTRY should get similar benefits (assuming LTO isn't used)?
> 
> Correct, but as you said this does not make sense as the syscall exit
> work should be rare.
> 
> Jinjie, can you please figure out which TIF bit is causing this to be
> invoked?
> 
> I have a suspicion that it is TIF_NOTIFY_RESUME. If that's the case
> you're seing the RSEQ overhead, which should be completely gone with the
> rewrite that got just merged into Linus tree.

It maybe audit flag, the test is with audit on.

> 
> Thanks,
> 
>         tglx
> 
> 


From jiaqiyan at google.com  Thu Dec 11 17:53:26 2025
From: jiaqiyan at google.com (Jiaqi Yan)
Date: Thu, 11 Dec 2025 17:53:26 -0800
Subject: [PATCH v4 2/3] KVM: selftests: Test for KVM_EXIT_ARM_SEA
In-Reply-To: <3061f5f8-cef0-b7b1-c4de-f2ceea29af9a@huawei.com>
References: <20251013185903.1372553-1-jiaqiyan@google.com> <20251013185903.1372553-3-jiaqiyan@google.com>
 <3061f5f8-cef0-b7b1-c4de-f2ceea29af9a@huawei.com>
Message-ID: <CACw3F51mRXCDz7Hd4Vve98NoskhB2cSc88zAGfd6Hwr4uCBxPA@mail.gmail.com>

On Thu, Dec 11, 2025 at 5:02?AM Zenghui Yu <yuzenghui at huawei.com> wrote:
>
> Hi Jiaqi,
>
> I had run into several problems when testing it on different servers. I
> haven't figured them out yet but post it early for discussion.

Thanks for testing, and I will be happy to work with you to improve
this test code.

>
> On 2025/10/14 2:59, Jiaqi Yan wrote:
> > Test how KVM handles guest SEA when APEI is unable to claim it, and
> > KVM_CAP_ARM_SEA_TO_USER is enabled.
> >
> > The behavior is triggered by consuming recoverable memory error (UER)
> > injected via EINJ. The test asserts two major things:
> > 1. KVM returns to userspace with KVM_EXIT_ARM_SEA exit reason, and
> >    has provided expected fault information, e.g. esr, flags, gva, gpa.
> > 2. Userspace is able to handle KVM_EXIT_ARM_SEA by injecting SEA to
> >    guest and KVM injects expected SEA into the VCPU.
> >
> > Tested on a data center server running Siryn AmpereOne processor
> > that has RAS support.
> >
> > Several things to notice before attempting to run this selftest:
> > - The test relies on EINJ support in both firmware and kernel to
> >   inject UER. Otherwise the test will be skipped.
> > - The under-test platform's APEI should be unable to claim the SEA.
> >   Otherwise the test will be skipped.
> > - Some platform doesn't support notrigger in EINJ, which may cause
> >   APEI and GHES to offline the memory before guest can consume
> >   injected UER, and making test unable to trigger SEA.
> >
> > Signed-off-by: Jiaqi Yan <jiaqiyan at google.com>
>
> [...]
>
> > +static void inject_uer(uint64_t paddr)
> > +{
> > +     if (access("/sys/firmware/acpi/tables/EINJ", R_OK) == -1)
> > +             ksft_test_result_skip("EINJ table no available in firmware");
>
> Missing '\n'.

Thanks.

>
> We should return early (to actually skip the test) if the file can not
> be accessed, right?

Oh you mean I missed exit(KSFT_SKIP), right? Agreed.

>
> > +
> > +     if (access(EINJ_ETYPE, R_OK | W_OK) == -1)
> > +             ksft_test_result_skip("EINJ module probably not loaded?");
> > +
> > +     write_einj_entry(EINJ_ETYPE, ERROR_TYPE_MEMORY_UER);
> > +     write_einj_entry(EINJ_FLAGS, MASK_MEMORY_UER);
> > +     write_einj_entry(EINJ_ADDR, paddr);
> > +     write_einj_entry(EINJ_MASK, ~0x0UL);
> > +     write_einj_entry(EINJ_NOTRIGGER, 1);
> > +     write_einj_entry(EINJ_DOIT, 1);
> > +}
> > +
> > +/*
> > + * When host APEI successfully claims the SEA caused by guest_code, kernel
> > + * will send SIGBUS signal with BUS_MCEERR_AR to test thread.
> > + *
> > + * We set up this SIGBUS handler to skip the test for that case.
> > + */
> > +static void sigbus_signal_handler(int sig, siginfo_t *si, void *v)
> > +{
> > +     ksft_print_msg("SIGBUS (%d) received, dumping siginfo...\n", sig);
> > +     ksft_print_msg("si_signo=%d, si_errno=%d, si_code=%d, si_addr=%p\n",
> > +                    si->si_signo, si->si_errno, si->si_code, si->si_addr);
> > +     if (si->si_code == BUS_MCEERR_AR)
> > +             ksft_test_result_skip("SEA is claimed by host APEI\n");
> > +     else
> > +             ksft_test_result_fail("Exit with signal unhandled\n");
> > +
> > +     exit(0);
> > +}
> > +
> > +static void setup_sigbus_handler(void)
> > +{
> > +     struct sigaction act;
> > +
> > +     memset(&act, 0, sizeof(act));
> > +     sigemptyset(&act.sa_mask);
> > +     act.sa_sigaction = sigbus_signal_handler;
> > +     act.sa_flags = SA_SIGINFO;
> > +     TEST_ASSERT(sigaction(SIGBUS, &act, NULL) == 0,
> > +                 "Failed to setup SIGBUS handler");
> > +}
> > +
> > +static void guest_code(void)
> > +{
> > +     uint64_t guest_data;
> > +
> > +     /* Consumes error will cause a SEA. */
> > +     guest_data = *(uint64_t *)EINJ_GVA;
> > +
> > +     GUEST_FAIL("Poison not protected by SEA: gva=%#lx, guest_data=%#lx\n",
> > +                EINJ_GVA, guest_data);
> > +}
> > +
> > +static void expect_sea_handler(struct ex_regs *regs)
> > +{
> > +     u64 esr = read_sysreg(esr_el1);
> > +     u64 far = read_sysreg(far_el1);
> > +     bool expect_far_invalid = far_invalid;
> > +
> > +     GUEST_PRINTF("Handling Guest SEA\n");
> > +     GUEST_PRINTF("ESR_EL1=%#lx, FAR_EL1=%#lx\n", esr, far);
> > +
> > +     GUEST_ASSERT_EQ(ESR_ELx_EC(esr), ESR_ELx_EC_DABT_CUR);
> > +     GUEST_ASSERT_EQ(esr & ESR_ELx_FSC_TYPE, ESR_ELx_FSC_EXTABT);
> > +
> > +     if (expect_far_invalid) {
> > +             GUEST_ASSERT_EQ(esr & ESR_ELx_FnV, ESR_ELx_FnV);
>
> I hit this ASSERT with:
>
> # Mapped 0x40000 pages: gva=0x80000000 to gpa=0xff80000000
> # Before EINJect: data=0xbaadcafe
> # EINJ_GVA=0x81234bad, einj_gpa=0xff81234bad, einj_hva=0xffff41234bad,
> einj_hpa=0x202841234bad
> # echo 0x10 > /sys/kernel/debug/apei/einj/error_type - done
> # echo 0x2 > /sys/kernel/debug/apei/einj/flags - done
> # echo 0x202841234bad > /sys/kernel/debug/apei/einj/param1 - done
> # echo 0xffffffffffffffff > /sys/kernel/debug/apei/einj/param2 - done
> # echo 0x1 > /sys/kernel/debug/apei/einj/notrigger - done
> # echo 0x1 > /sys/kernel/debug/apei/einj/error_inject - done
> # Memory UER EINJected
> # Dump kvm_run info about KVM_EXIT_ARM_SEA
> # kvm_run.arm_sea: esr=0x92000610, flags=0
> # kvm_run.arm_sea: gva=0, gpa=0
> # From guest: Handling Guest SEA
> # From guest: ESR_EL1=0x96000010, FAR_EL1=0xaaaadf254828
> # Guest aborted!
> ==== Test Assertion Failure ====
>   arm64/sea_to_user.c:172: esr & ESR_ELx_FnV == ESR_ELx_FnV
>   pid=38112 tid=38112 errno=4 - Interrupted system call
>      1  0x0000000000402f9b: run_vm at sea_to_user.c:246
>      2  0x0000000000402467: main at sea_to_user.c:330
>      3  0x0000ffff8e22b03f: ?? ??:0
>      4  0x0000ffff8e22b117: ?? ??:0
>      5  0x00000000004026ef: _start at ??:?
>   0x0 != 0x400 (esr & ESR_ELx_FnV != ESR_ELx_FnV)
>
> It seems that KVM doesn't emulate FnV when injecting an abort.

I believe so; this happened to me when I tested on an architecture
that doesn't provide valid FAR. I tried to fix this in [1] in the
past, but didn't get any traction and somehow escaped my attention...

Oliver and Marc, what do you think about [1]? If it sounds like a
valid fix, I can re-send it out as an individual patch.

[1] https://lore.kernel.org/kvmarm/20250604050902.3944054-3-jiaqiyan at google.com


>
> > +             GUEST_PRINTF("Guest observed garbage value in FAR\n");
> > +     } else {
> > +             GUEST_ASSERT_EQ(esr & ESR_ELx_FnV, 0);
> > +             GUEST_ASSERT_EQ(far, EINJ_GVA);
> > +     }
> > +
> > +     GUEST_DONE();
> > +}
> > +
> > +static void vcpu_inject_sea(struct kvm_vcpu *vcpu)
> > +{
> > +     struct kvm_vcpu_events events = {};
> > +
> > +     events.exception.ext_dabt_pending = true;
> > +     vcpu_events_set(vcpu, &events);
> > +}
> > +
> > +static void run_vm(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
> > +{
> > +     struct ucall uc;
> > +     bool guest_done = false;
> > +     struct kvm_run *run = vcpu->run;
> > +     u64 esr;
> > +
> > +     /* Resume the vCPU after error injection to consume the error. */
> > +     vcpu_run(vcpu);
> > +
> > +     ksft_print_msg("Dump kvm_run info about KVM_EXIT_%s\n",
> > +                    exit_reason_str(run->exit_reason));
> > +     ksft_print_msg("kvm_run.arm_sea: esr=%#llx, flags=%#llx\n",
> > +                    run->arm_sea.esr, run->arm_sea.flags);
> > +     ksft_print_msg("kvm_run.arm_sea: gva=%#llx, gpa=%#llx\n",
> > +                    run->arm_sea.gva, run->arm_sea.gpa);
> > +
> > +     TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_ARM_SEA);
>
> I can also hit this ASSERT with:
>
> Random seed: 0x6b8b4567
> # Mapped 0x40000 pages: gva=0x80000000 to gpa=0xff80000000
> # Before EINJect: data=0xbaadcafe
> # EINJ_GVA=0x81234bad, einj_gpa=0xff81234bad, einj_hva=0xffff41234bad,
> einj_hpa=0x2841234bad
> # echo 0x10 > /sys/kernel/debug/apei/einj/error_type - done
> # echo 0x2 > /sys/kernel/debug/apei/einj/flags - done
> # echo 0x2841234bad > /sys/kernel/debug/apei/einj/param1 - done
> # echo 0xffffffffffffffff > /sys/kernel/debug/apei/einj/param2 - done
> # echo 0x1 > /sys/kernel/debug/apei/einj/notrigger - done
> # echo 0x1 > /sys/kernel/debug/apei/einj/error_inject - done
> # Memory UER EINJected
> # Dump kvm_run info about KVM_EXIT_MMIO
> # kvm_run.arm_sea: esr=0xffff90ba0040, flags=0x691000
> # kvm_run.arm_sea: gva=0x100000008, gpa=0
> ==== Test Assertion Failure ====
>   arm64/sea_to_user.c:207: exit_reason == (41)
>   pid=38023 tid=38023 errno=4 - Interrupted system call
>      1  0x0000000000402d1b: run_vm at sea_to_user.c:207
>      2  0x0000000000402467: main at sea_to_user.c:330
>      3  0x0000ffff9122b03f: ?? ??:0
>      4  0x0000ffff9122b117: ?? ??:0
>      5  0x00000000004026ef: _start at ??:?
>   Wanted KVM exit reason: 41 (ARM_SEA), got: 6 (MMIO)
>
> Not sure what's wrong it..

Does your test machine have SDEI or SCI enabled for host APEI? Do you
see any kernel log from "Memory failure:" saying hugetlb page
recovered, and recovered significant earlier than the KVM exit here.
It maybe the kernel has already unmapped hugepage in response to SDEI
or SCI before this test actually consumes memory error, so no SEA is
actually triggered.

>
> > +
> > +     esr = run->arm_sea.esr;
> > +     TEST_ASSERT_EQ(ESR_ELx_EC(esr), ESR_ELx_EC_DABT_LOW);
> > +     TEST_ASSERT_EQ(esr & ESR_ELx_FSC_TYPE, ESR_ELx_FSC_EXTABT);
> > +     TEST_ASSERT_EQ(ESR_ELx_ISS2(esr), 0);
> > +     TEST_ASSERT_EQ((esr & ESR_ELx_INST_SYNDROME), 0);
> > +     TEST_ASSERT_EQ(esr & ESR_ELx_VNCR, 0);
> > +
> > +     if (!(esr & ESR_ELx_FnV)) {
> > +             ksft_print_msg("Expect gva to match given FnV bit is 0\n");
> > +             TEST_ASSERT_EQ(run->arm_sea.gva, EINJ_GVA);
> > +     }
> > +
> > +     if (run->arm_sea.flags & KVM_EXIT_ARM_SEA_FLAG_GPA_VALID) {
> > +             ksft_print_msg("Expect gpa to match given KVM_EXIT_ARM_SEA_FLAG_GPA_VALID is set\n");
> > +             TEST_ASSERT_EQ(run->arm_sea.gpa, einj_gpa & PAGE_ADDR_MASK);
> > +     }
> > +
> > +     far_invalid = esr & ESR_ELx_FnV;
>
> Missing sync_global_to_guest()?

Ah, yes, and I can add sync_global_to_guest and get rid of
expect_far_invalid in expect_sea_handler.

>
> Thanks,
> Zenghui


From jianhua.lin at mediatek.com  Thu Dec 11 17:52:14 2025
From: jianhua.lin at mediatek.com (Jianhua Lin)
Date: Fri, 12 Dec 2025 09:52:14 +0800
Subject: [PATCH 0/4] Mediatek MT8189 JPEG support
Message-ID: <20251212015218.4689-1-jianhua.lin@mediatek.com>

This series is based on tag: next-20251211, linux-next/master

Jianhua Lin (4):
  arm64: dts: mt8188: update JPEG encoder/decoder compatible
  dt-bindings: media: mediatek-jpeg-decoder: add MT8189 compatible
    string
  dt-bindings: media: mediatek-jpeg-encoder: add MT8189 compatible
    string
  media: mediatek: jpeg: add compatible for MT8189 SoC

 .../bindings/media/mediatek-jpeg-decoder.yaml | 46 +++++++++++++++++--
 .../bindings/media/mediatek-jpeg-encoder.yaml | 27 ++++++++---
 arch/arm64/boot/dts/mediatek/mt8188.dtsi      |  9 ++--
 .../platform/mediatek/jpeg/mtk_jpeg_core.c    | 44 ++++++++++++++++++
 4 files changed, 109 insertions(+), 17 deletions(-)

-- 
2.45.2



From jianhua.lin at mediatek.com  Thu Dec 11 17:52:15 2025
From: jianhua.lin at mediatek.com (Jianhua Lin)
Date: Fri, 12 Dec 2025 09:52:15 +0800
Subject: [PATCH 1/4] arm64: dts: mt8188: update JPEG encoder/decoder compatible
In-Reply-To: <20251212015218.4689-1-jianhua.lin@mediatek.com>
References: <20251212015218.4689-1-jianhua.lin@mediatek.com>
Message-ID: <20251212015218.4689-2-jianhua.lin@mediatek.com>

The MT8188 JPEG encoder and decoder shares the same architecture
and features as the MT8189 JPEG encoder and decoder.
This improvement enables the MT8188 JPEG encoder and decoder to
support a 34-bit iova address-space.
Therefore, update "mediatek,mtk-jpgenc" to "mediatek,mt8189-jpgenc",
update "mediatek,mt2701-jpgdec" to "mediatek,mt8189-jpgdec".

Signed-off-by: Jianhua Lin <jianhua.lin at mediatek.com>
---
 arch/arm64/boot/dts/mediatek/mt8188.dtsi | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/boot/dts/mediatek/mt8188.dtsi b/arch/arm64/boot/dts/mediatek/mt8188.dtsi
index 90c388f1890f..ff9a774f5911 100644
--- a/arch/arm64/boot/dts/mediatek/mt8188.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8188.dtsi
@@ -2846,7 +2846,7 @@ video_encoder: video-encoder at 1a020000 {
 		};
 
 		jpeg_encoder: jpeg-encoder at 1a030000 {
-			compatible = "mediatek,mt8188-jpgenc", "mediatek,mtk-jpgenc";
+			compatible = "mediatek,mt8188-jpgenc", "mediatek,mt8189-jpgenc";
 			reg = <0 0x1a030000 0 0x10000>;
 			clocks = <&vencsys CLK_VENC1_JPGENC>;
 			clock-names = "jpgenc";
@@ -2859,11 +2859,10 @@ jpeg_encoder: jpeg-encoder at 1a030000 {
 		};
 
 		jpeg_decoder: jpeg-decoder at 1a040000 {
-			compatible = "mediatek,mt8188-jpgdec", "mediatek,mt2701-jpgdec";
+			compatible = "mediatek,mt8188-jpgdec", "mediatek,mt8189-jpgdec";
 			reg = <0 0x1a040000 0 0x10000>;
-			clocks = <&vencsys CLK_VENC1_LARB>,
-				 <&vencsys CLK_VENC1_JPGDEC>;
-			clock-names = "jpgdec-smi", "jpgdec";
+			clocks = <&vencsys CLK_VENC1_JPGDEC>;
+			clock-names = "jpgdec";
 			interrupts = <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH 0>;
 			iommus = <&vdo_iommu M4U_PORT_L19_JPGDEC_WDMA_0>,
 				 <&vdo_iommu M4U_PORT_L19_JPGDEC_BSDMA_0>,
-- 
2.45.2



From jianhua.lin at mediatek.com  Thu Dec 11 17:52:16 2025
From: jianhua.lin at mediatek.com (Jianhua Lin)
Date: Fri, 12 Dec 2025 09:52:16 +0800
Subject: [PATCH 2/4] dt-bindings: media: mediatek-jpeg-decoder: add MT8189 compatible string
In-Reply-To: <20251212015218.4689-1-jianhua.lin@mediatek.com>
References: <20251212015218.4689-1-jianhua.lin@mediatek.com>
Message-ID: <20251212015218.4689-3-jianhua.lin@mediatek.com>

Compared to the previous generation IC, the MT8189 uses 34-bit
iova address-space. Therefore, add "mediatek,mt8189-jpgdec"
compatible to the binding document.

Signed-off-by: Jianhua Lin <jianhua.lin at mediatek.com>
---
 .../bindings/media/mediatek-jpeg-decoder.yaml | 46 +++++++++++++++++--
 1 file changed, 41 insertions(+), 5 deletions(-)

diff --git a/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml b/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml
index a4aacd3eb189..935a908465c8 100644
--- a/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml
+++ b/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml
@@ -19,11 +19,15 @@ properties:
           - enum:
               - mediatek,mt8173-jpgdec
               - mediatek,mt2701-jpgdec
+              - mediatek,mt8189-jpgdec
       - items:
           - enum:
               - mediatek,mt7623-jpgdec
-              - mediatek,mt8188-jpgdec
           - const: mediatek,mt2701-jpgdec
+      - items:
+          - enum:
+              - mediatek,mt8188-jpgdec
+          - const: mediatek,mt8189-jpgdec
 
   reg:
     maxItems: 1
@@ -32,13 +36,16 @@ properties:
     maxItems: 1
 
   clocks:
+    minItems: 1
     maxItems: 2
-    minItems: 2
 
   clock-names:
-    items:
-      - const: jpgdec-smi
-      - const: jpgdec
+    minItems: 1
+    maxItems: 2
+
+  mediatek,larb:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: a phandle to the smi_larb node.
 
   power-domains:
     maxItems: 1
@@ -51,6 +58,35 @@ properties:
       Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml for details.
       Ports are according to the HW.
 
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - mediatek,mt8189-jpgdec
+
+    then:
+      properties:
+        clock-names:
+          items:
+            - const: jpgdec
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - mediatek,mt8173-jpgdec
+              - mediatek,mt2701-jpgdec
+
+    then:
+      properties:
+        clock-names:
+          items:
+            - const: jpgdec-smi
+            - const: jpgdec
+
 required:
   - compatible
   - reg
-- 
2.45.2



From jianhua.lin at mediatek.com  Thu Dec 11 17:52:17 2025
From: jianhua.lin at mediatek.com (Jianhua Lin)
Date: Fri, 12 Dec 2025 09:52:17 +0800
Subject: [PATCH 3/4] dt-bindings: media: mediatek-jpeg-encoder: add MT8189 compatible string
In-Reply-To: <20251212015218.4689-1-jianhua.lin@mediatek.com>
References: <20251212015218.4689-1-jianhua.lin@mediatek.com>
Message-ID: <20251212015218.4689-4-jianhua.lin@mediatek.com>

Compared to the previous generation IC, the MT8189 uses 34-bit
iova address-space. Therefore, add "mediatek,mt8189-jpgenc"
compatible to the binding document.

Signed-off-by: Jianhua Lin <jianhua.lin at mediatek.com>
---
 .../bindings/media/mediatek-jpeg-encoder.yaml | 27 ++++++++++++++-----
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml b/Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml
index 5b15f8977f67..3044c7fc5c18 100644
--- a/Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml
+++ b/Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml
@@ -14,13 +14,22 @@ description: |-
 
 properties:
   compatible:
-    items:
-      - enum:
-          - mediatek,mt2701-jpgenc
-          - mediatek,mt8183-jpgenc
-          - mediatek,mt8186-jpgenc
-          - mediatek,mt8188-jpgenc
-      - const: mediatek,mtk-jpgenc
+    oneOf:
+      - items:
+          - enum:
+              - mediatek,mtk-jpgenc
+              - mediatek,mt8189-jpgenc
+      - items:
+          - enum:
+              - mediatek,mt2701-jpgenc
+              - mediatek,mt8183-jpgenc
+              - mediatek,mt8186-jpgenc
+          - const: mediatek,mtk-jpgenc
+      - items:
+          - enum:
+              - mediatek,mt8188-jpgenc
+          - const: mediatek,mt8189-jpgenc
+
   reg:
     maxItems: 1
 
@@ -34,6 +43,10 @@ properties:
     items:
       - const: jpgenc
 
+  mediatek,larb:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: a phandle to the smi_larb node.
+
   power-domains:
     maxItems: 1
 
-- 
2.45.2



From jianhua.lin at mediatek.com  Thu Dec 11 17:52:18 2025
From: jianhua.lin at mediatek.com (Jianhua Lin)
Date: Fri, 12 Dec 2025 09:52:18 +0800
Subject: [PATCH 4/4] media: mediatek: jpeg: add compatible for MT8189 SoC
In-Reply-To: <20251212015218.4689-1-jianhua.lin@mediatek.com>
References: <20251212015218.4689-1-jianhua.lin@mediatek.com>
Message-ID: <20251212015218.4689-5-jianhua.lin@mediatek.com>

add jpeg decoder and encoder compatible for MT8189 SoC.

Signed-off-by: Jianhua Lin <jianhua.lin at mediatek.com>
---
 .../platform/mediatek/jpeg/mtk_jpeg_core.c    | 44 +++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
index d08fe365cbb2..9ea8d8f56e9b 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
@@ -1866,6 +1866,10 @@ static struct clk_bulk_data mt8173_jpeg_dec_clocks[] = {
 	{ .id = "jpgdec" },
 };
 
+static struct clk_bulk_data mtk_jpeg_dec_clocks[] = {
+	{ .id = "jpgdec" },
+};
+
 static const struct mtk_jpeg_variant mt8173_jpeg_drvdata = {
 	.clks = mt8173_jpeg_dec_clocks,
 	.num_clks = ARRAY_SIZE(mt8173_jpeg_dec_clocks),
@@ -1897,6 +1901,38 @@ static const struct mtk_jpeg_variant mtk_jpeg_drvdata = {
 	.multi_core = false,
 };
 
+static const struct mtk_jpeg_variant mtk8189_jpegenc_drvdata = {
+	.clks = mtk_jpeg_clocks,
+	.num_clks = ARRAY_SIZE(mtk_jpeg_clocks),
+	.formats = mtk_jpeg_enc_formats,
+	.num_formats = MTK_JPEG_ENC_NUM_FORMATS,
+	.qops = &mtk_jpeg_enc_qops,
+	.irq_handler = mtk_jpeg_enc_irq,
+	.hw_reset = mtk_jpeg_enc_reset,
+	.m2m_ops = &mtk_jpeg_enc_m2m_ops,
+	.dev_name = "mtk-jpeg-enc",
+	.ioctl_ops = &mtk_jpeg_enc_ioctl_ops,
+	.out_q_default_fourcc = V4L2_PIX_FMT_YUYV,
+	.cap_q_default_fourcc = V4L2_PIX_FMT_JPEG,
+	.support_34bit = true,
+};
+
+static const struct mtk_jpeg_variant mtk8189_jpegdec_drvdata = {
+	.clks = mtk_jpeg_dec_clocks,
+	.num_clks = ARRAY_SIZE(mtk_jpeg_dec_clocks),
+	.formats = mtk_jpeg_dec_formats,
+	.num_formats = MTK_JPEG_DEC_NUM_FORMATS,
+	.qops = &mtk_jpeg_dec_qops,
+	.irq_handler = mtk_jpeg_dec_irq,
+	.hw_reset = mtk_jpeg_dec_reset,
+	.m2m_ops = &mtk_jpeg_dec_m2m_ops,
+	.dev_name = "mtk-jpeg-dec",
+	.ioctl_ops = &mtk_jpeg_dec_ioctl_ops,
+	.out_q_default_fourcc = V4L2_PIX_FMT_JPEG,
+	.cap_q_default_fourcc = V4L2_PIX_FMT_YUV420M,
+	.support_34bit = true,
+};
+
 static struct mtk_jpeg_variant mtk8195_jpegenc_drvdata = {
 	.formats = mtk_jpeg_enc_formats,
 	.num_formats = MTK_JPEG_ENC_NUM_FORMATS,
@@ -1936,6 +1972,14 @@ static const struct of_device_id mtk_jpeg_match[] = {
 		.compatible = "mediatek,mtk-jpgenc",
 		.data = &mtk_jpeg_drvdata,
 	},
+	{
+		.compatible = "mediatek,mt8189-jpgenc",
+		.data = &mtk8189_jpegenc_drvdata,
+	},
+	{
+		.compatible = "mediatek,mt8189-jpgdec",
+		.data = &mtk8189_jpegdec_drvdata,
+	},
 	{
 		.compatible = "mediatek,mt8195-jpgenc",
 		.data = &mtk8195_jpegenc_drvdata,
-- 
2.45.2



From jian.hu at amlogic.com  Thu Dec 11 18:26:13 2025
From: jian.hu at amlogic.com (Jian Hu)
Date: Fri, 12 Dec 2025 10:26:13 +0800
Subject: [PATCH v7 0/5] add support for T7 family clock controller
Message-ID: <20251212022619.3072132-1-jian.hu@amlogic.com>

It introduces three clock controllers:
- SCMI clock controller: these clocks are managed by the SCP and handled through SCMI.
- PLL clock controller.
- peripheral clock controller.

Changes v7 since v6 at [6]:
- add COMMON_CLK_MESON_MPLL for T7 PLL Kconfig

Changes v6 since v5 at [5]:
- add a blank line after each PLL register region
- update GP1 PLL note
- update PLL and peripherals help message
- add parentheses around the _iflags member in MESON_COMP_GATE
- drop CLK_SET_RATE_PARENT and the 4th parent for rtc
- move sd_emmc_c after sd_emmc_b

Changes v5 since v4 at [4]:
- rename rtc and cec dualdiv clocks
- rename dsp clocks
- rename anakin clocks
- rename fdiv2_divn to 25m and fix its parent
- add flag for T7_COMP_GATE
- use T7_COMP_SEL/DIV/GATE to define glitch clocks
- add CLK_SET_RATE_NO_REPARENT for t7_eth_rmii_sel and rtc
- move module_platform_driver after clock driver

Changes v4 since v3 at [3]:
- drop amlogic_t7_pll_probe, use meson_clkc_mmio_probe instead
- add CLK_DIVIDER_MAX_AT_ZERO for pcie_pll_od clk
- add frac for hifi_dco_pll_dco
- add l_detect for mclk_pll_dco
- drop v3 5/6 patch, and use MESON_PCLK
- drop SPI_PWM_CLK_XX macro and use MESON_COMP_XX
- drop the register's prefix

Changes v3 since v2 at [2]:
- update T7 PLL YAML
- add 't7_' prefix for t7 clock name and variable in t7-pll.c and t7-peripherals.c
- correct v1 patch link
- add new macro MESON_PCLK_V2
- update the driver,header,yaml file license

Changes v2 since v1 at [1]:
- add CLK_MESON import
- add const for clkc_regmap_config in PLL driver
- fix eth_rmii_sel parent
- update T7 PLL YAML file

[1]: https://lore.kernel.org/all/20241231060047.2298871-1-jian.hu at amlogic.com
[2]: https://lore.kernel.org/all/20250108094025.2664201-1-jian.hu at amlogic.com
[3]: https://lore.kernel.org/all/20250509074825.1933254-1-jian.hu at amlogic.com
[4]: https://lore.kernel.org/all/20251030094345.2571222-1-jian.hu at amlogic.com
[5]: https://lore.kernel.org/all/20251121105934.1759745-1-jian.hu at amlogic.com
[6]: https://lore.kernel.org/all/20251204053635.1234150-1-jian.hu at amlogic.com
Jian Hu (5):
  dt-bindings: clock: add Amlogic T7 PLL clock controller
  dt-bindings: clock: add Amlogic T7 SCMI clock controller
  dt-bindings: clock: add Amlogic T7 peripherals clock controller
  clk: meson: t7: add support for the T7 SoC PLL clock
  clk: meson: t7: add t7 clock peripherals controller driver

 .../clock/amlogic,t7-peripherals-clkc.yaml    |  116 ++
 .../bindings/clock/amlogic,t7-pll-clkc.yaml   |  114 ++
 drivers/clk/meson/Kconfig                     |   28 +
 drivers/clk/meson/Makefile                    |    2 +
 drivers/clk/meson/t7-peripherals.c            | 1271 +++++++++++++++++
 drivers/clk/meson/t7-pll.c                    | 1074 ++++++++++++++
 .../clock/amlogic,t7-peripherals-clkc.h       |  228 +++
 .../dt-bindings/clock/amlogic,t7-pll-clkc.h   |   56 +
 include/dt-bindings/clock/amlogic,t7-scmi.h   |   47 +
 9 files changed, 2936 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/amlogic,t7-peripherals-clkc.yaml
 create mode 100644 Documentation/devicetree/bindings/clock/amlogic,t7-pll-clkc.yaml
 create mode 100644 drivers/clk/meson/t7-peripherals.c
 create mode 100644 drivers/clk/meson/t7-pll.c
 create mode 100644 include/dt-bindings/clock/amlogic,t7-peripherals-clkc.h
 create mode 100644 include/dt-bindings/clock/amlogic,t7-pll-clkc.h
 create mode 100644 include/dt-bindings/clock/amlogic,t7-scmi.h

-- 
2.47.1



From jian.hu at amlogic.com  Thu Dec 11 18:26:14 2025
From: jian.hu at amlogic.com (Jian Hu)
Date: Fri, 12 Dec 2025 10:26:14 +0800
Subject: [PATCH v7 1/5] dt-bindings: clock: add Amlogic T7 PLL clock controller
In-Reply-To: <20251212022619.3072132-1-jian.hu@amlogic.com>
References: <20251212022619.3072132-1-jian.hu@amlogic.com>
Message-ID: <20251212022619.3072132-2-jian.hu@amlogic.com>

Add DT bindings for the PLL clock controller of the Amlogic T7 SoC family.

Signed-off-by: Jian Hu <jian.hu at amlogic.com>
Reviewed-by: Conor Dooley <conor.dooley at microchip.com>
---
 .../bindings/clock/amlogic,t7-pll-clkc.yaml   | 114 ++++++++++++++++++
 .../dt-bindings/clock/amlogic,t7-pll-clkc.h   |  56 +++++++++
 2 files changed, 170 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/amlogic,t7-pll-clkc.yaml
 create mode 100644 include/dt-bindings/clock/amlogic,t7-pll-clkc.h

diff --git a/Documentation/devicetree/bindings/clock/amlogic,t7-pll-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,t7-pll-clkc.yaml
new file mode 100644
index 000000000000..49c61f65deff
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/amlogic,t7-pll-clkc.yaml
@@ -0,0 +1,114 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2024-2025 Amlogic, Inc. All rights reserved
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/amlogic,t7-pll-clkc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Amlogic T7 PLL Clock Control Controller
+
+maintainers:
+  - Neil Armstrong <neil.armstrong at linaro.org>
+  - Jerome Brunet <jbrunet at baylibre.com>
+  - Jian Hu <jian.hu at amlogic.com>
+  - Xianwei Zhao <xianwei.zhao at amlogic.com>
+
+properties:
+  compatible:
+    enum:
+      - amlogic,t7-gp0-pll
+      - amlogic,t7-gp1-pll
+      - amlogic,t7-hifi-pll
+      - amlogic,t7-pcie-pll
+      - amlogic,t7-mpll
+      - amlogic,t7-hdmi-pll
+      - amlogic,t7-mclk-pll
+
+  reg:
+    maxItems: 1
+
+  '#clock-cells':
+    const: 1
+
+  clocks:
+    items:
+      - description: mclk pll input oscillator gate
+      - description: oscillator input clock source for mclk_sel_0
+      - description: fixed input clock source for mclk_sel_0
+    minItems: 1
+
+  clock-names:
+    items:
+      - const: in0
+      - const: in1
+      - const: in2
+    minItems: 1
+
+required:
+  - compatible
+  - '#clock-cells'
+  - reg
+  - clocks
+  - clock-names
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: amlogic,t7-mclk-pll
+
+    then:
+      properties:
+        clocks:
+          minItems: 3
+
+        clock-names:
+          minItems: 3
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - amlogic,t7-gp0-pll
+              - amlogic,t7-gp1--pll
+              - amlogic,t7-hifi-pll
+              - amlogic,t7-pcie-pll
+              - amlogic,t7-mpll
+              - amlogic,t7-hdmi-pll
+
+    then:
+      properties:
+        clocks:
+          maxItems: 1
+
+        clock-names:
+          maxItems: 1
+
+additionalProperties: false
+
+examples:
+  - |
+    apb {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        clock-controller at 8080 {
+            compatible = "amlogic,t7-gp0-pll";
+            reg = <0 0x8080 0 0x20>;
+            clocks = <&scmi_clk 2>;
+            clock-names = "in0";
+            #clock-cells = <1>;
+        };
+
+        clock-controller at 8300 {
+            compatible = "amlogic,t7-mclk-pll";
+            reg = <0 0x8300 0 0x18>;
+            clocks = <&scmi_clk 2>,
+                     <&xtal>,
+                     <&scmi_clk 31>;
+            clock-names = "in0", "in1", "in2";
+            #clock-cells = <1>;
+        };
+    };
diff --git a/include/dt-bindings/clock/amlogic,t7-pll-clkc.h b/include/dt-bindings/clock/amlogic,t7-pll-clkc.h
new file mode 100644
index 000000000000..e2481f2f1163
--- /dev/null
+++ b/include/dt-bindings/clock/amlogic,t7-pll-clkc.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
+/*
+ * Copyright (C) 2024-2025 Amlogic, Inc. All rights reserved
+ */
+
+#ifndef __T7_PLL_CLKC_H
+#define __T7_PLL_CLKC_H
+
+/* GP0 */
+#define CLKID_GP0_PLL_DCO	0
+#define CLKID_GP0_PLL		1
+
+/* GP1 */
+#define CLKID_GP1_PLL_DCO	0
+#define CLKID_GP1_PLL		1
+
+/* HIFI */
+#define CLKID_HIFI_PLL_DCO	0
+#define CLKID_HIFI_PLL		1
+
+/* PCIE */
+#define CLKID_PCIE_PLL_DCO	0
+#define CLKID_PCIE_PLL_DCO_DIV2	1
+#define CLKID_PCIE_PLL_OD	2
+#define CLKID_PCIE_PLL		3
+
+/* MPLL */
+#define CLKID_MPLL_PREDIV	0
+#define CLKID_MPLL0_DIV		1
+#define CLKID_MPLL0		2
+#define CLKID_MPLL1_DIV		3
+#define CLKID_MPLL1		4
+#define CLKID_MPLL2_DIV		5
+#define CLKID_MPLL2		6
+#define CLKID_MPLL3_DIV		7
+#define CLKID_MPLL3		8
+
+/* HDMI */
+#define CLKID_HDMI_PLL_DCO	0
+#define CLKID_HDMI_PLL_OD	1
+#define CLKID_HDMI_PLL		2
+
+/* MCLK */
+#define CLKID_MCLK_PLL_DCO	0
+#define CLKID_MCLK_PRE		1
+#define CLKID_MCLK_PLL		2
+#define CLKID_MCLK_0_SEL	3
+#define CLKID_MCLK_0_DIV2	4
+#define CLKID_MCLK_0_PRE	5
+#define CLKID_MCLK_0		6
+#define CLKID_MCLK_1_SEL	7
+#define CLKID_MCLK_1_DIV2	8
+#define CLKID_MCLK_1_PRE	9
+#define CLKID_MCLK_1		10
+
+#endif /* __T7_PLL_CLKC_H */
-- 
2.47.1



From jian.hu at amlogic.com  Thu Dec 11 18:26:15 2025
From: jian.hu at amlogic.com (Jian Hu)
Date: Fri, 12 Dec 2025 10:26:15 +0800
Subject: [PATCH v7 2/5] dt-bindings: clock: add Amlogic T7 SCMI clock controller
In-Reply-To: <20251212022619.3072132-1-jian.hu@amlogic.com>
References: <20251212022619.3072132-1-jian.hu@amlogic.com>
Message-ID: <20251212022619.3072132-3-jian.hu@amlogic.com>

Add DT bindings for the SCMI clock controller of the Amlogic T7 SoC family.

Signed-off-by: Jian Hu <jian.hu at amlogic.com>
Acked-by: Rob Herring (Arm) <robh at kernel.org>
---
 include/dt-bindings/clock/amlogic,t7-scmi.h | 47 +++++++++++++++++++++
 1 file changed, 47 insertions(+)
 create mode 100644 include/dt-bindings/clock/amlogic,t7-scmi.h

diff --git a/include/dt-bindings/clock/amlogic,t7-scmi.h b/include/dt-bindings/clock/amlogic,t7-scmi.h
new file mode 100644
index 000000000000..27bd257bd4ea
--- /dev/null
+++ b/include/dt-bindings/clock/amlogic,t7-scmi.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
+/*
+ * Copyright (C) 2024-2025 Amlogic, Inc. All rights reserved
+ */
+
+#ifndef __T7_SCMI_CLKC_H
+#define __T7_SCMI_CLKC_H
+
+#define CLKID_DDR_PLL_OSC			0
+#define CLKID_AUD_PLL_OSC			1
+#define CLKID_TOP_PLL_OSC			2
+#define CLKID_TCON_PLL_OSC			3
+#define CLKID_USB_PLL0_OSC			4
+#define CLKID_USB_PLL1_OSC			5
+#define CLKID_MCLK_PLL_OSC			6
+#define CLKID_PCIE_OSC				7
+#define CLKID_ETH_PLL_OSC			8
+#define CLKID_PCIE_REFCLK_PLL_OSC		9
+#define CLKID_EARC_OSC				10
+#define CLKID_SYS1_PLL_OSC			11
+#define CLKID_HDMI_PLL_OSC			12
+#define CLKID_SYS_CLK				13
+#define CLKID_AXI_CLK				14
+#define CLKID_FIXED_PLL_DCO			15
+#define CLKID_FIXED_PLL				16
+#define CLKID_FCLK_DIV2_DIV			17
+#define CLKID_FCLK_DIV2				18
+#define CLKID_FCLK_DIV2P5_DIV			19
+#define CLKID_FCLK_DIV2P5			20
+#define CLKID_FCLK_DIV3_DIV			21
+#define CLKID_FCLK_DIV3				22
+#define CLKID_FCLK_DIV4_DIV			23
+#define CLKID_FCLK_DIV4				24
+#define CLKID_FCLK_DIV5_DIV			25
+#define CLKID_FCLK_DIV5				26
+#define CLKID_FCLK_DIV7_DIV			27
+#define CLKID_FCLK_DIV7				28
+#define CLKID_FCLK_50M_DIV			29
+#define CLKID_FCLK_50M				30
+#define CLKID_CPU_CLK				31
+#define CLKID_A73_CLK				32
+#define CLKID_CPU_CLK_DIV16_DIV			33
+#define CLKID_CPU_CLK_DIV16			34
+#define CLKID_A73_CLK_DIV16_DIV			35
+#define CLKID_A73_CLK_DIV16			36
+
+#endif /* __T7_SCMI_CLKC_H */
-- 
2.47.1



From jian.hu at amlogic.com  Thu Dec 11 18:26:16 2025
From: jian.hu at amlogic.com (Jian Hu)
Date: Fri, 12 Dec 2025 10:26:16 +0800
Subject: [PATCH v7 3/5] dt-bindings: clock: add Amlogic T7 peripherals clock controller
In-Reply-To: <20251212022619.3072132-1-jian.hu@amlogic.com>
References: <20251212022619.3072132-1-jian.hu@amlogic.com>
Message-ID: <20251212022619.3072132-4-jian.hu@amlogic.com>

Add DT bindings for the peripheral clock controller of the Amlogic T7
SoC family.

Signed-off-by: Jian Hu <jian.hu at amlogic.com>
Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
---
 .../clock/amlogic,t7-peripherals-clkc.yaml    | 116 +++++++++
 .../clock/amlogic,t7-peripherals-clkc.h       | 228 ++++++++++++++++++
 2 files changed, 344 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/amlogic,t7-peripherals-clkc.yaml
 create mode 100644 include/dt-bindings/clock/amlogic,t7-peripherals-clkc.h

diff --git a/Documentation/devicetree/bindings/clock/amlogic,t7-peripherals-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,t7-peripherals-clkc.yaml
new file mode 100644
index 000000000000..55bb73707d58
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/amlogic,t7-peripherals-clkc.yaml
@@ -0,0 +1,116 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2024-2025 Amlogic, Inc. All rights reserved
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/amlogic,t7-peripherals-clkc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Amlogic T7 Peripherals Clock Controller
+
+maintainers:
+  - Neil Armstrong <neil.armstrong at linaro.org>
+  - Jerome Brunet <jbrunet at baylibre.com>
+  - Xianwei Zhao <xianwei.zhao at amlogic.com>
+  - Jian Hu <jian.hu at amlogic.com>
+
+properties:
+  compatible:
+    const: amlogic,t7-peripherals-clkc
+
+  reg:
+    maxItems: 1
+
+  '#clock-cells':
+    const: 1
+
+  clocks:
+    minItems: 14
+    items:
+      - description: input oscillator
+      - description: input sys clk
+      - description: input fixed pll
+      - description: input fclk div 2
+      - description: input fclk div 2p5
+      - description: input fclk div 3
+      - description: input fclk div 4
+      - description: input fclk div 5
+      - description: input fclk div 7
+      - description: input hifi pll
+      - description: input gp0 pll
+      - description: input gp1 pll
+      - description: input mpll1
+      - description: input mpll2
+      - description: external input rmii oscillator (optional)
+      - description: input video pll0 (optional)
+      - description: external pad input for rtc (optional)
+
+  clock-names:
+    minItems: 14
+    items:
+      - const: xtal
+      - const: sys
+      - const: fix
+      - const: fdiv2
+      - const: fdiv2p5
+      - const: fdiv3
+      - const: fdiv4
+      - const: fdiv5
+      - const: fdiv7
+      - const: hifi
+      - const: gp0
+      - const: gp1
+      - const: mpll1
+      - const: mpll2
+      - const: ext_rmii
+      - const: vid_pll0
+      - const: ext_rtc
+
+required:
+  - compatible
+  - '#clock-cells'
+  - reg
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    apb {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        clkc_periphs:clock-controller at 0 {
+            compatible = "amlogic,t7-peripherals-clkc";
+            reg = <0 0x0 0 0x1c8>;
+            #clock-cells = <1>;
+            clocks = <&xtal>,
+                     <&scmi_clk 13>,
+                     <&scmi_clk 16>,
+                     <&scmi_clk 18>,
+                     <&scmi_clk 20>,
+                     <&scmi_clk 22>,
+                     <&scmi_clk 24>,
+                     <&scmi_clk 26>,
+                     <&scmi_clk 28>,
+                     <&hifi 1>,
+                     <&gp0 1>,
+                     <&gp1 1>,
+                     <&mpll 4>,
+                     <&mpll 6>;
+            clock-names = "xtal",
+                          "sys",
+                          "fix",
+                          "fdiv2",
+                          "fdiv2p5",
+                          "fdiv3",
+                          "fdiv4",
+                          "fdiv5",
+                          "fdiv7",
+                          "hifi",
+                          "gp0",
+                          "gp1",
+                          "mpll1",
+                          "mpll2";
+        };
+    };
diff --git a/include/dt-bindings/clock/amlogic,t7-peripherals-clkc.h b/include/dt-bindings/clock/amlogic,t7-peripherals-clkc.h
new file mode 100644
index 000000000000..32c4b62037de
--- /dev/null
+++ b/include/dt-bindings/clock/amlogic,t7-peripherals-clkc.h
@@ -0,0 +1,228 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
+/*
+ * Copyright (C) 2024-2025 Amlogic, Inc. All rights reserved
+ */
+
+#ifndef __T7_PERIPHERALS_CLKC_H
+#define __T7_PERIPHERALS_CLKC_H
+
+#define CLKID_RTC_DUALDIV_IN		0
+#define CLKID_RTC_DUALDIV_DIV		1
+#define CLKID_RTC_DUALDIV_SEL		2
+#define CLKID_RTC_DUALDIV		3
+#define CLKID_RTC			4
+#define CLKID_CECA_DUALDIV_IN		5
+#define CLKID_CECA_DUALDIV_DIV		6
+#define CLKID_CECA_DUALDIV_SEL		7
+#define CLKID_CECA_DUALDIV		8
+#define CLKID_CECA			9
+#define CLKID_CECB_DUALDIV_IN		10
+#define CLKID_CECB_DUALDIV_DIV		11
+#define CLKID_CECB_DUALDIV_SEL		12
+#define CLKID_CECB_DUALDIV		13
+#define CLKID_CECB			14
+#define CLKID_SC_SEL			15
+#define CLKID_SC_DIV			16
+#define CLKID_SC			17
+#define CLKID_DSPA_0_SEL		18
+#define CLKID_DSPA_0_DIV		19
+#define CLKID_DSPA_0			20
+#define CLKID_DSPA_1_SEL		21
+#define CLKID_DSPA_1_DIV		22
+#define CLKID_DSPA_1			23
+#define CLKID_DSPA			24
+#define CLKID_DSPB_0_SEL		25
+#define CLKID_DSPB_0_DIV		26
+#define CLKID_DSPB_0			27
+#define CLKID_DSPB_1_SEL		28
+#define CLKID_DSPB_1_DIV		29
+#define CLKID_DSPB_1			30
+#define CLKID_DSPB			31
+#define CLKID_24M			32
+#define CLKID_24M_DIV2			33
+#define CLKID_12M			34
+#define CLKID_25M_DIV			35
+#define CLKID_25M			36
+#define CLKID_ANAKIN_0_SEL		37
+#define CLKID_ANAKIN_0_DIV		38
+#define CLKID_ANAKIN_0			39
+#define CLKID_ANAKIN_1_SEL		40
+#define CLKID_ANAKIN_1_DIV		41
+#define CLKID_ANAKIN_1			42
+#define CLKID_ANAKIN_01_SEL		43
+#define CLKID_ANAKIN			44
+#define CLKID_TS_DIV			45
+#define CLKID_TS			46
+#define CLKID_MIPI_CSI_PHY_0_SEL	47
+#define CLKID_MIPI_CSI_PHY_0_DIV	48
+#define CLKID_MIPI_CSI_PHY_0		49
+#define CLKID_MIPI_CSI_PHY_1_SEL	50
+#define CLKID_MIPI_CSI_PHY_1_DIV	51
+#define CLKID_MIPI_CSI_PHY_1		52
+#define CLKID_MIPI_CSI_PHY		53
+#define CLKID_MIPI_ISP_SEL		54
+#define CLKID_MIPI_ISP_DIV		55
+#define CLKID_MIPI_ISP			56
+#define CLKID_MALI_0_SEL		57
+#define CLKID_MALI_0_DIV		58
+#define CLKID_MALI_0			59
+#define CLKID_MALI_1_SEL		60
+#define CLKID_MALI_1_DIV		61
+#define CLKID_MALI_1			62
+#define CLKID_MALI			63
+#define CLKID_ETH_RMII_SEL		64
+#define CLKID_ETH_RMII_DIV		65
+#define CLKID_ETH_RMII			66
+#define CLKID_FCLK_DIV2_DIV8		67
+#define CLKID_ETH_125M			68
+#define CLKID_SD_EMMC_A_SEL		69
+#define CLKID_SD_EMMC_A_DIV		70
+#define CLKID_SD_EMMC_A			71
+#define CLKID_SD_EMMC_B_SEL		72
+#define CLKID_SD_EMMC_B_DIV		73
+#define CLKID_SD_EMMC_B			74
+#define CLKID_SD_EMMC_C_SEL		75
+#define CLKID_SD_EMMC_C_DIV		76
+#define CLKID_SD_EMMC_C			77
+#define CLKID_SPICC0_SEL		78
+#define CLKID_SPICC0_DIV		79
+#define CLKID_SPICC0			80
+#define CLKID_SPICC1_SEL		81
+#define CLKID_SPICC1_DIV		82
+#define CLKID_SPICC1			83
+#define CLKID_SPICC2_SEL		84
+#define CLKID_SPICC2_DIV		85
+#define CLKID_SPICC2			86
+#define CLKID_SPICC3_SEL		87
+#define CLKID_SPICC3_DIV		88
+#define CLKID_SPICC3			89
+#define CLKID_SPICC4_SEL		90
+#define CLKID_SPICC4_DIV		91
+#define CLKID_SPICC4			92
+#define CLKID_SPICC5_SEL		93
+#define CLKID_SPICC5_DIV		94
+#define CLKID_SPICC5			95
+#define CLKID_SARADC_SEL		96
+#define CLKID_SARADC_DIV		97
+#define CLKID_SARADC			98
+#define CLKID_PWM_A_SEL			99
+#define CLKID_PWM_A_DIV			100
+#define CLKID_PWM_A			101
+#define CLKID_PWM_B_SEL			102
+#define CLKID_PWM_B_DIV			103
+#define CLKID_PWM_B			104
+#define CLKID_PWM_C_SEL			105
+#define CLKID_PWM_C_DIV			106
+#define CLKID_PWM_C			107
+#define CLKID_PWM_D_SEL			108
+#define CLKID_PWM_D_DIV			109
+#define CLKID_PWM_D			110
+#define CLKID_PWM_E_SEL			111
+#define CLKID_PWM_E_DIV			112
+#define CLKID_PWM_E			113
+#define CLKID_PWM_F_SEL			114
+#define CLKID_PWM_F_DIV			115
+#define CLKID_PWM_F			116
+#define CLKID_PWM_AO_A_SEL		117
+#define CLKID_PWM_AO_A_DIV		118
+#define CLKID_PWM_AO_A			119
+#define CLKID_PWM_AO_B_SEL		120
+#define CLKID_PWM_AO_B_DIV		121
+#define CLKID_PWM_AO_B			122
+#define CLKID_PWM_AO_C_SEL		123
+#define CLKID_PWM_AO_C_DIV		124
+#define CLKID_PWM_AO_C			125
+#define CLKID_PWM_AO_D_SEL		126
+#define CLKID_PWM_AO_D_DIV		127
+#define CLKID_PWM_AO_D			128
+#define CLKID_PWM_AO_E_SEL		129
+#define CLKID_PWM_AO_E_DIV		130
+#define CLKID_PWM_AO_E			131
+#define CLKID_PWM_AO_F_SEL		132
+#define CLKID_PWM_AO_F_DIV		133
+#define CLKID_PWM_AO_F			134
+#define CLKID_PWM_AO_G_SEL		135
+#define CLKID_PWM_AO_G_DIV		136
+#define CLKID_PWM_AO_G			137
+#define CLKID_PWM_AO_H_SEL		138
+#define CLKID_PWM_AO_H_DIV		139
+#define CLKID_PWM_AO_H			140
+#define CLKID_SYS_DDR			141
+#define CLKID_SYS_DOS			142
+#define CLKID_SYS_MIPI_DSI_A		143
+#define CLKID_SYS_MIPI_DSI_B		144
+#define CLKID_SYS_ETHPHY		145
+#define CLKID_SYS_MALI			146
+#define CLKID_SYS_AOCPU			147
+#define CLKID_SYS_AUCPU			148
+#define CLKID_SYS_CEC			149
+#define CLKID_SYS_GDC			150
+#define CLKID_SYS_DESWARP		151
+#define CLKID_SYS_AMPIPE_NAND		152
+#define CLKID_SYS_AMPIPE_ETH		153
+#define CLKID_SYS_AM2AXI0		154
+#define CLKID_SYS_AM2AXI1		155
+#define CLKID_SYS_AM2AXI2		156
+#define CLKID_SYS_SD_EMMC_A		157
+#define CLKID_SYS_SD_EMMC_B		158
+#define CLKID_SYS_SD_EMMC_C		159
+#define CLKID_SYS_SMARTCARD		160
+#define CLKID_SYS_ACODEC		161
+#define CLKID_SYS_SPIFC			162
+#define CLKID_SYS_MSR_CLK		163
+#define CLKID_SYS_IR_CTRL		164
+#define CLKID_SYS_AUDIO			165
+#define CLKID_SYS_ETH			166
+#define CLKID_SYS_UART_A		167
+#define CLKID_SYS_UART_B		168
+#define CLKID_SYS_UART_C		169
+#define CLKID_SYS_UART_D		170
+#define CLKID_SYS_UART_E		171
+#define CLKID_SYS_UART_F		172
+#define CLKID_SYS_AIFIFO		173
+#define CLKID_SYS_SPICC2		174
+#define CLKID_SYS_SPICC3		175
+#define CLKID_SYS_SPICC4		176
+#define CLKID_SYS_TS_A73		177
+#define CLKID_SYS_TS_A53		178
+#define CLKID_SYS_SPICC5		179
+#define CLKID_SYS_G2D			180
+#define CLKID_SYS_SPICC0		181
+#define CLKID_SYS_SPICC1		182
+#define CLKID_SYS_PCIE			183
+#define CLKID_SYS_USB			184
+#define CLKID_SYS_PCIE_PHY		185
+#define CLKID_SYS_I2C_AO_A		186
+#define CLKID_SYS_I2C_AO_B		187
+#define CLKID_SYS_I2C_M_A		188
+#define CLKID_SYS_I2C_M_B		189
+#define CLKID_SYS_I2C_M_C		190
+#define CLKID_SYS_I2C_M_D		191
+#define CLKID_SYS_I2C_M_E		192
+#define CLKID_SYS_I2C_M_F		193
+#define CLKID_SYS_HDMITX_APB		194
+#define CLKID_SYS_I2C_S_A		195
+#define CLKID_SYS_HDMIRX_PCLK		196
+#define CLKID_SYS_MMC_APB		197
+#define CLKID_SYS_MIPI_ISP_PCLK		198
+#define CLKID_SYS_RSA			199
+#define CLKID_SYS_PCLK_SYS_APB		200
+#define CLKID_SYS_A73PCLK_APB		201
+#define CLKID_SYS_DSPA			202
+#define CLKID_SYS_DSPB			203
+#define CLKID_SYS_VPU_INTR		204
+#define CLKID_SYS_SAR_ADC		205
+#define CLKID_SYS_GIC			206
+#define CLKID_SYS_TS_GPU		207
+#define CLKID_SYS_TS_NNA		208
+#define CLKID_SYS_TS_VPU		209
+#define CLKID_SYS_TS_HEVC		210
+#define CLKID_SYS_PWM_AB		211
+#define CLKID_SYS_PWM_CD		212
+#define CLKID_SYS_PWM_EF		213
+#define CLKID_SYS_PWM_AO_AB		214
+#define CLKID_SYS_PWM_AO_CD		215
+#define CLKID_SYS_PWM_AO_EF		216
+#define CLKID_SYS_PWM_AO_GH		217
+
+#endif /* __T7_PERIPHERALS_CLKC_H */
-- 
2.47.1



From jian.hu at amlogic.com  Thu Dec 11 18:26:17 2025
From: jian.hu at amlogic.com (Jian Hu)
Date: Fri, 12 Dec 2025 10:26:17 +0800
Subject: [PATCH v7 4/5] clk: meson: t7: add support for the T7 SoC PLL clock
In-Reply-To: <20251212022619.3072132-1-jian.hu@amlogic.com>
References: <20251212022619.3072132-1-jian.hu@amlogic.com>
Message-ID: <20251212022619.3072132-5-jian.hu@amlogic.com>

Add PLL clock controller driver for the Amlogic T7 SoC family.

Signed-off-by: Jian Hu <jian.hu at amlogic.com>
---
 drivers/clk/meson/Kconfig  |   15 +
 drivers/clk/meson/Makefile |    1 +
 drivers/clk/meson/t7-pll.c | 1074 ++++++++++++++++++++++++++++++++++++
 3 files changed, 1090 insertions(+)
 create mode 100644 drivers/clk/meson/t7-pll.c

diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index 71481607a6d5..e6a059bcf636 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -201,4 +201,19 @@ config COMMON_CLK_S4_PERIPHERALS
 	help
 	  Support for the peripherals clock controller on Amlogic S805X2 and S905Y4
 	  devices, AKA S4. Say Y if you want S4 peripherals clock controller to work.
+
+config COMMON_CLK_T7_PLL
+	tristate "Amlogic T7 SoC PLL controller support"
+	depends on ARM64
+	default ARCH_MESON
+	select COMMON_CLK_MESON_REGMAP
+	select COMMON_CLK_MESON_CLKC_UTILS
+	select COMMON_CLK_MESON_MPLL
+	select COMMON_CLK_MESON_PLL
+	imply COMMON_CLK_SCMI
+	help
+	  Support for the PLL clock controller on Amlogic A311D2 based
+	  device, AKA T7. PLLs are required by most peripheral to operate.
+	  Say Y if you want T7 PLL clock controller to work.
+
 endmenu
diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
index c6998e752c68..8e3f7f94c639 100644
--- a/drivers/clk/meson/Makefile
+++ b/drivers/clk/meson/Makefile
@@ -26,3 +26,4 @@ obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o
 obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o meson8-ddr.o
 obj-$(CONFIG_COMMON_CLK_S4_PLL) += s4-pll.o
 obj-$(CONFIG_COMMON_CLK_S4_PERIPHERALS) += s4-peripherals.o
+obj-$(CONFIG_COMMON_CLK_T7_PLL) += t7-pll.o
diff --git a/drivers/clk/meson/t7-pll.c b/drivers/clk/meson/t7-pll.c
new file mode 100644
index 000000000000..0a622f45fa36
--- /dev/null
+++ b/drivers/clk/meson/t7-pll.c
@@ -0,0 +1,1074 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
+/*
+ * Copyright (C) 2024-2025 Amlogic, Inc. All rights reserved.
+ * Author: Jian Hu <jian.hu at amlogic.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/platform_device.h>
+#include "clk-regmap.h"
+#include "clk-pll.h"
+#include "clk-mpll.h"
+#include "meson-clkc-utils.h"
+#include <dt-bindings/clock/amlogic,t7-pll-clkc.h>
+
+#define GP0PLL_CTRL0		0x00
+#define GP0PLL_CTRL1		0x04
+#define GP0PLL_CTRL2		0x08
+#define GP0PLL_CTRL3		0x0c
+#define GP0PLL_CTRL4		0x10
+#define GP0PLL_CTRL5		0x14
+#define GP0PLL_CTRL6		0x18
+#define GP0PLL_STS		0x1c
+
+#define GP1PLL_CTRL0		0x00
+#define GP1PLL_CTRL1		0x04
+#define GP1PLL_CTRL2		0x08
+#define GP1PLL_CTRL3		0x0c
+#define GP1PLL_STS		0x1c
+
+#define HIFIPLL_CTRL0		0x00
+#define HIFIPLL_CTRL1		0x04
+#define HIFIPLL_CTRL2		0x08
+#define HIFIPLL_CTRL3		0x0c
+#define HIFIPLL_CTRL4		0x10
+#define HIFIPLL_CTRL5		0x14
+#define HIFIPLL_CTRL6		0x18
+#define HIFIPLL_STS		0x1c
+
+#define PCIEPLL_CTRL0		0x00
+#define PCIEPLL_CTRL1		0x04
+#define PCIEPLL_CTRL2		0x08
+#define PCIEPLL_CTRL3		0x0c
+#define PCIEPLL_CTRL4		0x10
+#define PCIEPLL_CTRL5		0x14
+#define PCIEPLL_STS		0x18
+
+#define MPLL_CTRL0		0x00
+#define MPLL_CTRL1		0x04
+#define MPLL_CTRL2		0x08
+#define MPLL_CTRL3		0x0c
+#define MPLL_CTRL4		0x10
+#define MPLL_CTRL5		0x14
+#define MPLL_CTRL6		0x18
+#define MPLL_CTRL7		0x1c
+#define MPLL_CTRL8		0x20
+#define MPLL_STS		0x24
+
+#define HDMIPLL_CTRL0		0x00
+#define HDMIPLL_CTRL1		0x04
+#define HDMIPLL_CTRL2		0x08
+#define HDMIPLL_CTRL3		0x0c
+#define HDMIPLL_CTRL4		0x10
+#define HDMIPLL_CTRL5		0x14
+#define HDMIPLL_CTRL6		0x18
+#define HDMIPLL_STS		0x1c
+
+#define MCLK_PLL_CNTL0		0x00
+#define MCLK_PLL_CNTL1		0x04
+#define MCLK_PLL_CNTL2		0x08
+#define MCLK_PLL_CNTL3		0x0c
+#define MCLK_PLL_CNTL4		0x10
+#define MCLK_PLL_STS		0x14
+
+static const struct pll_mult_range t7_media_pll_mult_range = {
+	.min = 125,
+	.max = 250,
+};
+
+static const struct reg_sequence t7_gp0_init_regs[] = {
+	{ .reg = GP0PLL_CTRL1,  .def = 0x00000000 },
+	{ .reg = GP0PLL_CTRL2,  .def = 0x00000000 },
+	{ .reg = GP0PLL_CTRL3,  .def = 0x48681c00 },
+	{ .reg = GP0PLL_CTRL4,  .def = 0x88770290 },
+	{ .reg = GP0PLL_CTRL5,  .def = 0x3927200a },
+	{ .reg = GP0PLL_CTRL6,  .def = 0x56540000 },
+};
+
+static struct clk_regmap t7_gp0_pll_dco = {
+	.data = &(struct meson_clk_pll_data){
+		.en = {
+			.reg_off = GP0PLL_CTRL0,
+			.shift   = 28,
+			.width   = 1,
+		},
+		.m = {
+			.reg_off = GP0PLL_CTRL0,
+			.shift   = 0,
+			.width   = 8,
+		},
+		.n = {
+			.reg_off = GP0PLL_CTRL0,
+			.shift   = 10,
+			.width   = 5,
+		},
+		.l = {
+			.reg_off = GP0PLL_STS,
+			.shift   = 31,
+			.width   = 1,
+		},
+		.rst = {
+			.reg_off = GP0PLL_CTRL0,
+			.shift   = 29,
+			.width   = 1,
+		},
+		.range = &t7_media_pll_mult_range,
+		.init_regs = t7_gp0_init_regs,
+		.init_count = ARRAY_SIZE(t7_gp0_init_regs),
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "gp0_pll_dco",
+		.ops = &meson_clk_pll_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "in0",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_gp0_pll = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = GP0PLL_CTRL0,
+		.shift = 16,
+		.width = 3,
+		.flags = CLK_DIVIDER_POWER_OF_TWO,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "gp0_pll",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_gp0_pll_dco.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+/*
+ * Compared with GP0 PLL, GP1 PLL is a newly designed PLL with
+ * a DCO range of 1.6GHz to 3.2GHz.
+ */
+static const struct pll_mult_range t7_gp1_pll_mult_range = {
+	.min = 67,
+	.max = 133,
+};
+
+static const struct reg_sequence t7_gp1_init_regs[] = {
+	{ .reg = GP1PLL_CTRL1,  .def = 0x1420500f },
+	{ .reg = GP1PLL_CTRL2,  .def = 0x00023001 },
+	{ .reg = GP1PLL_CTRL3,  .def = 0x00000000 },
+};
+
+static struct clk_regmap t7_gp1_pll_dco = {
+	.data = &(struct meson_clk_pll_data){
+		.en = {
+			.reg_off = GP1PLL_CTRL0,
+			.shift   = 28,
+			.width   = 1,
+		},
+		.m = {
+			.reg_off = GP1PLL_CTRL0,
+			.shift   = 0,
+			.width   = 8,
+		},
+		.n = {
+			.reg_off = GP1PLL_CTRL0,
+			.shift   = 16,
+			.width   = 5,
+		},
+		.l = {
+			.reg_off = GP1PLL_STS,
+			.shift   = 31,
+			.width   = 1,
+		},
+		.rst = {
+			.reg_off = GP1PLL_CTRL0,
+			.shift   = 29,
+			.width   = 1,
+		},
+		.range = &t7_gp1_pll_mult_range,
+		.init_regs = t7_gp1_init_regs,
+		.init_count = ARRAY_SIZE(t7_gp1_init_regs),
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "gp1_pll_dco",
+		.ops = &meson_clk_pll_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "in0",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_gp1_pll = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = GP1PLL_CTRL0,
+		.shift = 12,
+		.width = 3,
+		.flags = CLK_DIVIDER_POWER_OF_TWO,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "gp1_pll",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_gp1_pll_dco.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static const struct reg_sequence t7_hifi_init_regs[] = {
+	{ .reg = HIFIPLL_CTRL1, .def = 0x00000000 },
+	{ .reg = HIFIPLL_CTRL2, .def = 0x00000000 },
+	{ .reg = HIFIPLL_CTRL3, .def = 0x6a285c00 },
+	{ .reg = HIFIPLL_CTRL4, .def = 0x65771290 },
+	{ .reg = HIFIPLL_CTRL5, .def = 0x3927200a },
+	{ .reg = HIFIPLL_CTRL6, .def = 0x56540000 }
+};
+
+static struct clk_regmap t7_hifi_pll_dco = {
+	.data = &(struct meson_clk_pll_data){
+		.en = {
+			.reg_off = HIFIPLL_CTRL0,
+			.shift   = 28,
+			.width   = 1,
+		},
+		.m = {
+			.reg_off = HIFIPLL_CTRL0,
+			.shift   = 0,
+			.width   = 8,
+		},
+		.n = {
+			.reg_off = HIFIPLL_CTRL0,
+			.shift   = 10,
+			.width   = 5,
+		},
+		.frac = {
+			.reg_off = HIFIPLL_CTRL1,
+			.shift   = 0,
+			.width   = 17,
+		},
+		.l = {
+			.reg_off = HIFIPLL_STS,
+			.shift   = 31,
+			.width   = 1,
+		},
+		.rst = {
+			.reg_off = HIFIPLL_CTRL0,
+			.shift   = 29,
+			.width   = 1,
+		},
+		.range = &t7_media_pll_mult_range,
+		.init_regs = t7_hifi_init_regs,
+		.init_count = ARRAY_SIZE(t7_hifi_init_regs),
+		.frac_max = 100000,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "hifi_pll_dco",
+		.ops = &meson_clk_pll_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "in0",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_hifi_pll = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = HIFIPLL_CTRL0,
+		.shift = 16,
+		.width = 2,
+		.flags = CLK_DIVIDER_POWER_OF_TWO,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "hifi_pll",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_hifi_pll_dco.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+/*
+ * The T7 PCIE PLL is fined tuned to deliver a very precise
+ * 100MHz reference clock for the PCIe Analog PHY, and thus requires
+ * a strict register sequence to enable the PLL.
+ */
+static const struct reg_sequence t7_pcie_pll_init_regs[] = {
+	{ .reg = PCIEPLL_CTRL0,	.def = 0x200c04c8 },
+	{ .reg = PCIEPLL_CTRL0,	.def = 0x300c04c8 },
+	{ .reg = PCIEPLL_CTRL1,	.def = 0x30000000 },
+	{ .reg = PCIEPLL_CTRL2,	.def = 0x00001100 },
+	{ .reg = PCIEPLL_CTRL3,	.def = 0x10058e00 },
+	{ .reg = PCIEPLL_CTRL4,	.def = 0x000100c0 },
+	{ .reg = PCIEPLL_CTRL5,	.def = 0x68000048 },
+	{ .reg = PCIEPLL_CTRL5,	.def = 0x68000068, .delay_us = 20 },
+	{ .reg = PCIEPLL_CTRL4,	.def = 0x008100c0, .delay_us = 20 },
+	{ .reg = PCIEPLL_CTRL0,	.def = 0x340c04c8 },
+	{ .reg = PCIEPLL_CTRL0,	.def = 0x140c04c8, .delay_us = 20 },
+	{ .reg = PCIEPLL_CTRL2,	.def = 0x00001000 }
+};
+
+static struct clk_regmap t7_pcie_pll_dco = {
+	.data = &(struct meson_clk_pll_data){
+		.en = {
+			.reg_off = PCIEPLL_CTRL0,
+			.shift   = 28,
+			.width   = 1,
+		},
+		.m = {
+			.reg_off = PCIEPLL_CTRL0,
+			.shift   = 0,
+			.width   = 8,
+		},
+		.n = {
+			.reg_off = PCIEPLL_CTRL0,
+			.shift   = 10,
+			.width   = 5,
+		},
+		.l = {
+			.reg_off = PCIEPLL_CTRL0,
+			.shift   = 31,
+			.width   = 1,
+		},
+		.rst = {
+			.reg_off = PCIEPLL_CTRL0,
+			.shift   = 29,
+			.width   = 1,
+		},
+		.init_regs = t7_pcie_pll_init_regs,
+		.init_count = ARRAY_SIZE(t7_pcie_pll_init_regs),
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "pcie_pll_dco",
+		.ops = &meson_clk_pcie_pll_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "in0",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_fixed_factor t7_pcie_pll_dco_div2 = {
+	.mult = 1,
+	.div = 2,
+	.hw.init = &(struct clk_init_data){
+		.name = "pcie_pll_dco_div2",
+		.ops = &clk_fixed_factor_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_pcie_pll_dco.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_pcie_pll_od = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = PCIEPLL_CTRL0,
+		.shift = 16,
+		.width = 5,
+		/* the divisor is 32 when [16:21] = 0 */
+		.flags = CLK_DIVIDER_MAX_AT_ZERO,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "pcie_pll_od",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_pcie_pll_dco_div2.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_fixed_factor t7_pcie_pll = {
+	.mult = 1,
+	.div = 2,
+	.hw.init = &(struct clk_init_data){
+		.name = "pcie_pll",
+		.ops = &clk_fixed_factor_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_pcie_pll_od.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_fixed_factor t7_mpll_prediv = {
+	.mult = 1,
+	.div = 2,
+	.hw.init = &(struct clk_init_data){
+		.name = "mpll_prediv",
+		.ops = &clk_fixed_factor_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "in0",
+		},
+		.num_parents = 1,
+	},
+};
+
+static const struct reg_sequence t7_mpll0_init_regs[] = {
+	{ .reg = MPLL_CTRL2, .def = 0x40000033 }
+};
+
+static struct clk_regmap t7_mpll0_div = {
+	.data = &(struct meson_clk_mpll_data){
+		.sdm = {
+			.reg_off = MPLL_CTRL1,
+			.shift   = 0,
+			.width   = 14,
+		},
+		.sdm_en = {
+			.reg_off = MPLL_CTRL1,
+			.shift   = 30,
+			.width	 = 1,
+		},
+		.n2 = {
+			.reg_off = MPLL_CTRL1,
+			.shift   = 20,
+			.width   = 9,
+		},
+		.ssen = {
+			.reg_off = MPLL_CTRL1,
+			.shift   = 29,
+			.width	 = 1,
+		},
+		.init_regs = t7_mpll0_init_regs,
+		.init_count = ARRAY_SIZE(t7_mpll0_init_regs),
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mpll0_div",
+		.ops = &meson_clk_mpll_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_mpll_prediv.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_mpll0 = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = MPLL_CTRL1,
+		.bit_idx = 31,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mpll0",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) { &t7_mpll0_div.hw },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static const struct reg_sequence t7_mpll1_init_regs[] = {
+	{ .reg = MPLL_CTRL4,	.def = 0x40000033 }
+};
+
+static struct clk_regmap t7_mpll1_div = {
+	.data = &(struct meson_clk_mpll_data){
+		.sdm = {
+			.reg_off = MPLL_CTRL3,
+			.shift   = 0,
+			.width   = 14,
+		},
+		.sdm_en = {
+			.reg_off = MPLL_CTRL3,
+			.shift   = 30,
+			.width	 = 1,
+		},
+		.n2 = {
+			.reg_off = MPLL_CTRL3,
+			.shift   = 20,
+			.width   = 9,
+		},
+		.ssen = {
+			.reg_off = MPLL_CTRL3,
+			.shift   = 29,
+			.width	 = 1,
+		},
+		.init_regs = t7_mpll1_init_regs,
+		.init_count = ARRAY_SIZE(t7_mpll1_init_regs),
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mpll1_div",
+		.ops = &meson_clk_mpll_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_mpll_prediv.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_mpll1 = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = MPLL_CTRL3,
+		.bit_idx = 31,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mpll1",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) { &t7_mpll1_div.hw },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static const struct reg_sequence t7_mpll2_init_regs[] = {
+	{ .reg = MPLL_CTRL6, .def = 0x40000033 }
+};
+
+static struct clk_regmap t7_mpll2_div = {
+	.data = &(struct meson_clk_mpll_data){
+		.sdm = {
+			.reg_off = MPLL_CTRL5,
+			.shift   = 0,
+			.width   = 14,
+		},
+		.sdm_en = {
+			.reg_off = MPLL_CTRL5,
+			.shift   = 30,
+			.width	 = 1,
+		},
+		.n2 = {
+			.reg_off = MPLL_CTRL5,
+			.shift   = 20,
+			.width   = 9,
+		},
+		.ssen = {
+			.reg_off = MPLL_CTRL5,
+			.shift   = 29,
+			.width	 = 1,
+		},
+		.init_regs = t7_mpll2_init_regs,
+		.init_count = ARRAY_SIZE(t7_mpll2_init_regs),
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mpll2_div",
+		.ops = &meson_clk_mpll_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_mpll_prediv.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_mpll2 = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = MPLL_CTRL5,
+		.bit_idx = 31,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mpll2",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) { &t7_mpll2_div.hw },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static const struct reg_sequence t7_mpll3_init_regs[] = {
+	{ .reg = MPLL_CTRL8, .def = 0x40000033 }
+};
+
+static struct clk_regmap t7_mpll3_div = {
+	.data = &(struct meson_clk_mpll_data){
+		.sdm = {
+			.reg_off = MPLL_CTRL7,
+			.shift   = 0,
+			.width   = 14,
+		},
+		.sdm_en = {
+			.reg_off = MPLL_CTRL7,
+			.shift   = 30,
+			.width	 = 1,
+		},
+		.n2 = {
+			.reg_off = MPLL_CTRL7,
+			.shift   = 20,
+			.width   = 9,
+		},
+		.ssen = {
+			.reg_off = MPLL_CTRL7,
+			.shift   = 29,
+			.width	 = 1,
+		},
+		.init_regs = t7_mpll3_init_regs,
+		.init_count = ARRAY_SIZE(t7_mpll3_init_regs),
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mpll3_div",
+		.ops = &meson_clk_mpll_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_mpll_prediv.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_mpll3 = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = MPLL_CTRL7,
+		.bit_idx = 31,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mpll3",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) { &t7_mpll3_div.hw },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static const struct reg_sequence t7_hdmi_init_regs[] = {
+	{ .reg = HDMIPLL_CTRL1, .def = 0x00000000 },
+	{ .reg = HDMIPLL_CTRL2, .def = 0x00000000 },
+	{ .reg = HDMIPLL_CTRL3, .def = 0x6a28dc00 },
+	{ .reg = HDMIPLL_CTRL4, .def = 0x65771290 },
+	{ .reg = HDMIPLL_CTRL5, .def = 0x39272000 },
+	{ .reg = HDMIPLL_CTRL6, .def = 0x56540000 }
+};
+
+static struct clk_regmap t7_hdmi_pll_dco = {
+	.data = &(struct meson_clk_pll_data){
+		.en = {
+			.reg_off = HDMIPLL_CTRL0,
+			.shift   = 28,
+			.width   = 1,
+		},
+		.m = {
+			.reg_off = HDMIPLL_CTRL0,
+			.shift   = 0,
+			.width   = 9,
+		},
+		.n = {
+			.reg_off = HDMIPLL_CTRL0,
+			.shift   = 10,
+			.width   = 5,
+		},
+		.l = {
+			.reg_off = HDMIPLL_CTRL0,
+			.shift   = 31,
+			.width   = 1,
+		},
+		.rst = {
+			.reg_off = HDMIPLL_CTRL0,
+			.shift   = 29,
+			.width   = 1,
+		},
+		.range = &t7_media_pll_mult_range,
+		.init_regs = t7_hdmi_init_regs,
+		.init_count = ARRAY_SIZE(t7_hdmi_init_regs),
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "hdmi_pll_dco",
+		.ops = &meson_clk_pll_ops,
+		.parent_data = (const struct clk_parent_data []) {
+			{ .fw_name = "in0", }
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_hdmi_pll_od = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = HDMIPLL_CTRL0,
+		.shift = 16,
+		.width = 4,
+		.flags = CLK_DIVIDER_POWER_OF_TWO,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "hdmi_pll_od",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_hdmi_pll_dco.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_hdmi_pll = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = HDMIPLL_CTRL0,
+		.shift = 20,
+		.width = 2,
+		.flags = CLK_DIVIDER_POWER_OF_TWO,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "hdmi_pll",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_hdmi_pll_od.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static const struct pll_mult_range t7_mclk_pll_mult_range = {
+	.min = 67,
+	.max = 133,
+};
+
+static const struct reg_sequence t7_mclk_init_regs[] = {
+	{ .reg = MCLK_PLL_CNTL1, .def = 0x1470500f },
+	{ .reg = MCLK_PLL_CNTL2, .def = 0x00023001 },
+	{ .reg = MCLK_PLL_CNTL3, .def = 0x18180000 },
+	{ .reg = MCLK_PLL_CNTL4, .def = 0x00180303 },
+};
+
+static struct clk_regmap t7_mclk_pll_dco = {
+	.data = &(struct meson_clk_pll_data){
+		.en = {
+			.reg_off = MCLK_PLL_CNTL0,
+			.shift   = 28,
+			.width   = 1,
+		},
+		.m = {
+			.reg_off = MCLK_PLL_CNTL0,
+			.shift   = 0,
+			.width   = 8,
+		},
+		.n = {
+			.reg_off = MCLK_PLL_CNTL0,
+			.shift   = 16,
+			.width   = 5,
+		},
+		.l = {
+			.reg_off = MCLK_PLL_CNTL0,
+			.shift   = 31,
+			.width   = 1,
+		},
+		.rst = {
+			.reg_off = MCLK_PLL_CNTL0,
+			.shift   = 29,
+			.width   = 1,
+		},
+		.l_detect = {
+			.reg_off = MCLK_PLL_CNTL2,
+			.shift   = 6,
+			.width   = 1,
+		},
+		.range = &t7_mclk_pll_mult_range,
+		.init_regs = t7_mclk_init_regs,
+		.init_count = ARRAY_SIZE(t7_mclk_init_regs),
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mclk_pll_dco",
+		.ops = &meson_clk_pll_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "in0",
+		},
+		.num_parents = 1,
+	},
+};
+
+/* max div is 16 */
+static const struct clk_div_table t7_mclk_div[] = {
+	{ .val = 0, .div = 1 },
+	{ .val = 1, .div = 2 },
+	{ .val = 2, .div = 4 },
+	{ .val = 3, .div = 8 },
+	{ .val = 4, .div = 16 },
+	{ /* sentinel */ }
+};
+
+static struct clk_regmap t7_mclk_pre_od = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = MCLK_PLL_CNTL0,
+		.shift = 12,
+		.width = 3,
+		.table = t7_mclk_div,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mclk_pre_od",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_mclk_pll_dco.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_mclk_pll = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = MCLK_PLL_CNTL4,
+		.shift = 16,
+		.width = 5,
+		.flags = CLK_DIVIDER_ONE_BASED,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mclk_pll",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_mclk_pre_od.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_mclk_0_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = MCLK_PLL_CNTL4,
+		.mask = 0x3,
+		.shift = 4,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mclk_0_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = (const struct clk_parent_data []) {
+			{ .hw = &t7_mclk_pll.hw },
+			{ .fw_name = "in1", },
+			{ .fw_name = "in2", },
+		},
+		.num_parents = 3,
+	},
+};
+
+static struct clk_fixed_factor t7_mclk_0_div2 = {
+	.mult = 1,
+	.div = 2,
+	.hw.init = &(struct clk_init_data){
+		.name = "mclk_0_div2",
+		.ops = &clk_fixed_factor_ops,
+		.parent_hws = (const struct clk_hw *[]) { &t7_mclk_0_sel.hw },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_mclk_0_pre = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = MCLK_PLL_CNTL4,
+		.bit_idx = 2,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "mclk_0_pre",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_mclk_0_div2.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_mclk_0 = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = MCLK_PLL_CNTL4,
+		.bit_idx = 0,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "mclk_0",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_mclk_0_pre.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_mclk_1_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = MCLK_PLL_CNTL4,
+		.mask = 0x3,
+		.shift = 12,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mclk_1_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = (const struct clk_parent_data []) {
+			{ .hw = &t7_mclk_pll.hw },
+			{ .fw_name = "in1", },
+			{ .fw_name = "in2", },
+		},
+		.num_parents = 3,
+	},
+};
+
+static struct clk_fixed_factor t7_mclk_1_div2 = {
+	.mult = 1,
+	.div = 2,
+	.hw.init = &(struct clk_init_data){
+		.name = "mclk_1_div2",
+		.ops = &clk_fixed_factor_ops,
+		.parent_hws = (const struct clk_hw *[]) { &t7_mclk_1_sel.hw },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_mclk_1_pre = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = MCLK_PLL_CNTL4,
+		.bit_idx = 10,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "mclk_1_pre",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_mclk_1_div2.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_mclk_1 = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = MCLK_PLL_CNTL4,
+		.bit_idx = 8,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "mclk_1",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_mclk_1_pre.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_hw *t7_gp0_hw_clks[] = {
+	[CLKID_GP0_PLL_DCO]		= &t7_gp0_pll_dco.hw,
+	[CLKID_GP0_PLL]			= &t7_gp0_pll.hw,
+};
+
+static struct clk_hw *t7_gp1_hw_clks[] = {
+	[CLKID_GP1_PLL_DCO]		= &t7_gp1_pll_dco.hw,
+	[CLKID_GP1_PLL]			= &t7_gp1_pll.hw,
+};
+
+static struct clk_hw *t7_hifi_hw_clks[] = {
+	[CLKID_HIFI_PLL_DCO]		= &t7_hifi_pll_dco.hw,
+	[CLKID_HIFI_PLL]		= &t7_hifi_pll.hw,
+};
+
+static struct clk_hw *t7_pcie_hw_clks[] = {
+	[CLKID_PCIE_PLL_DCO]		= &t7_pcie_pll_dco.hw,
+	[CLKID_PCIE_PLL_DCO_DIV2]	= &t7_pcie_pll_dco_div2.hw,
+	[CLKID_PCIE_PLL_OD]		= &t7_pcie_pll_od.hw,
+	[CLKID_PCIE_PLL]		= &t7_pcie_pll.hw,
+};
+
+static struct clk_hw *t7_mpll_hw_clks[] = {
+	[CLKID_MPLL_PREDIV]		= &t7_mpll_prediv.hw,
+	[CLKID_MPLL0_DIV]		= &t7_mpll0_div.hw,
+	[CLKID_MPLL0]			= &t7_mpll0.hw,
+	[CLKID_MPLL1_DIV]		= &t7_mpll1_div.hw,
+	[CLKID_MPLL1]			= &t7_mpll1.hw,
+	[CLKID_MPLL2_DIV]		= &t7_mpll2_div.hw,
+	[CLKID_MPLL2]			= &t7_mpll2.hw,
+	[CLKID_MPLL3_DIV]		= &t7_mpll3_div.hw,
+	[CLKID_MPLL3]			= &t7_mpll3.hw,
+};
+
+static struct clk_hw *t7_hdmi_hw_clks[] = {
+	[CLKID_HDMI_PLL_DCO]		= &t7_hdmi_pll_dco.hw,
+	[CLKID_HDMI_PLL_OD]		= &t7_hdmi_pll_od.hw,
+	[CLKID_HDMI_PLL]		= &t7_hdmi_pll.hw,
+};
+
+static struct clk_hw *t7_mclk_hw_clks[] = {
+	[CLKID_MCLK_PLL_DCO]		= &t7_mclk_pll_dco.hw,
+	[CLKID_MCLK_PRE]		= &t7_mclk_pre_od.hw,
+	[CLKID_MCLK_PLL]		= &t7_mclk_pll.hw,
+	[CLKID_MCLK_0_SEL]		= &t7_mclk_0_sel.hw,
+	[CLKID_MCLK_0_DIV2]		= &t7_mclk_0_div2.hw,
+	[CLKID_MCLK_0_PRE]		= &t7_mclk_0_pre.hw,
+	[CLKID_MCLK_0]			= &t7_mclk_0.hw,
+	[CLKID_MCLK_1_SEL]		= &t7_mclk_1_sel.hw,
+	[CLKID_MCLK_1_DIV2]		= &t7_mclk_1_div2.hw,
+	[CLKID_MCLK_1_PRE]		= &t7_mclk_1_pre.hw,
+	[CLKID_MCLK_1]			= &t7_mclk_1.hw,
+};
+
+static const struct meson_clkc_data t7_gp0_data = {
+	.hw_clks = {
+		.hws = t7_gp0_hw_clks,
+		.num = ARRAY_SIZE(t7_gp0_hw_clks),
+	},
+};
+
+static const struct meson_clkc_data t7_gp1_data = {
+	.hw_clks = {
+		.hws = t7_gp1_hw_clks,
+		.num = ARRAY_SIZE(t7_gp1_hw_clks),
+	},
+};
+
+static const struct meson_clkc_data t7_hifi_data = {
+	.hw_clks = {
+		.hws = t7_hifi_hw_clks,
+		.num = ARRAY_SIZE(t7_hifi_hw_clks),
+	},
+};
+
+static const struct meson_clkc_data t7_pcie_data = {
+	.hw_clks = {
+		.hws = t7_pcie_hw_clks,
+		.num = ARRAY_SIZE(t7_pcie_hw_clks),
+	},
+};
+
+static const struct reg_sequence t7_mpll_init_regs[] = {
+	{ .reg = MPLL_CTRL0, .def = 0x00000543 }
+};
+
+static const struct meson_clkc_data t7_mpll_data = {
+	.hw_clks = {
+		.hws = t7_mpll_hw_clks,
+		.num = ARRAY_SIZE(t7_mpll_hw_clks),
+	},
+	.init_regs = t7_mpll_init_regs,
+	.init_count = ARRAY_SIZE(t7_mpll_init_regs),
+};
+
+static const struct meson_clkc_data t7_hdmi_data = {
+	.hw_clks = {
+		.hws = t7_hdmi_hw_clks,
+		.num = ARRAY_SIZE(t7_hdmi_hw_clks),
+	},
+};
+
+static const struct meson_clkc_data t7_mclk_data = {
+	.hw_clks = {
+		.hws = t7_mclk_hw_clks,
+		.num = ARRAY_SIZE(t7_mclk_hw_clks),
+	},
+};
+
+static const struct of_device_id t7_pll_clkc_match_table[] = {
+	{ .compatible = "amlogic,t7-gp0-pll",	.data = &t7_gp0_data, },
+	{ .compatible = "amlogic,t7-gp1-pll",	.data = &t7_gp1_data, },
+	{ .compatible = "amlogic,t7-hifi-pll",	.data = &t7_hifi_data, },
+	{ .compatible = "amlogic,t7-pcie-pll",	.data = &t7_pcie_data, },
+	{ .compatible = "amlogic,t7-mpll",	.data = &t7_mpll_data, },
+	{ .compatible = "amlogic,t7-hdmi-pll",	.data = &t7_hdmi_data, },
+	{ .compatible = "amlogic,t7-mclk-pll",	.data = &t7_mclk_data, },
+	{}
+};
+MODULE_DEVICE_TABLE(of, t7_pll_clkc_match_table);
+
+static struct platform_driver t7_pll_clkc_driver = {
+	.probe = meson_clkc_mmio_probe,
+	.driver = {
+		.name = "t7-pll-clkc",
+		.of_match_table = t7_pll_clkc_match_table,
+	},
+};
+module_platform_driver(t7_pll_clkc_driver);
+
+MODULE_DESCRIPTION("Amlogic T7 PLL Clock Controller driver");
+MODULE_AUTHOR("Jian Hu <jian.hu at amlogic.com>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("CLK_MESON");
-- 
2.47.1



From jian.hu at amlogic.com  Thu Dec 11 18:26:18 2025
From: jian.hu at amlogic.com (Jian Hu)
Date: Fri, 12 Dec 2025 10:26:18 +0800
Subject: [PATCH v7 5/5] clk: meson: t7: add t7 clock peripherals controller driver
In-Reply-To: <20251212022619.3072132-1-jian.hu@amlogic.com>
References: <20251212022619.3072132-1-jian.hu@amlogic.com>
Message-ID: <20251212022619.3072132-6-jian.hu@amlogic.com>

Add Peripheral clock controller driver for the Amlogic T7 SoC family.

Signed-off-by: Jian Hu <jian.hu at amlogic.com>
---
 drivers/clk/meson/Kconfig          |   13 +
 drivers/clk/meson/Makefile         |    1 +
 drivers/clk/meson/t7-peripherals.c | 1271 ++++++++++++++++++++++++++++
 3 files changed, 1285 insertions(+)
 create mode 100644 drivers/clk/meson/t7-peripherals.c

diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index e6a059bcf636..cf8cf3f9e4ee 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -216,4 +216,17 @@ config COMMON_CLK_T7_PLL
 	  device, AKA T7. PLLs are required by most peripheral to operate.
 	  Say Y if you want T7 PLL clock controller to work.
 
+config COMMON_CLK_T7_PERIPHERALS
+	tristate "Amlogic T7 SoC peripherals clock controller support"
+	depends on ARM64
+	default ARCH_MESON
+	select COMMON_CLK_MESON_REGMAP
+	select COMMON_CLK_MESON_CLKC_UTILS
+	select COMMON_CLK_MESON_DUALDIV
+	imply COMMON_CLK_SCMI
+	imply COMMON_CLK_T7_PLL
+	help
+	  Support for the peripherals clock controller on Amlogic A311D2 based
+	  device, AKA T7. Peripherals are required by most peripheral to operate.
+	  Say Y if you want T7 peripherals clock controller to work.
 endmenu
diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
index 8e3f7f94c639..c6719694a242 100644
--- a/drivers/clk/meson/Makefile
+++ b/drivers/clk/meson/Makefile
@@ -27,3 +27,4 @@ obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o meson8-ddr.o
 obj-$(CONFIG_COMMON_CLK_S4_PLL) += s4-pll.o
 obj-$(CONFIG_COMMON_CLK_S4_PERIPHERALS) += s4-peripherals.o
 obj-$(CONFIG_COMMON_CLK_T7_PLL) += t7-pll.o
+obj-$(CONFIG_COMMON_CLK_T7_PERIPHERALS) += t7-peripherals.o
diff --git a/drivers/clk/meson/t7-peripherals.c b/drivers/clk/meson/t7-peripherals.c
new file mode 100644
index 000000000000..214db7850d86
--- /dev/null
+++ b/drivers/clk/meson/t7-peripherals.c
@@ -0,0 +1,1271 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
+/*
+ * Copyright (C) 2024-2025 Amlogic, Inc. All rights reserved.
+ * Author: Jian Hu <jian.hu at amlogic.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/platform_device.h>
+#include "clk-dualdiv.h"
+#include "clk-regmap.h"
+#include "meson-clkc-utils.h"
+#include <dt-bindings/clock/amlogic,t7-peripherals-clkc.h>
+
+#define RTC_BY_OSCIN_CTRL0	0x8
+#define RTC_BY_OSCIN_CTRL1	0xc
+#define RTC_CTRL		0x10
+#define SYS_CLK_CTRL0		0x40
+#define SYS_CLK_EN0_REG0	0x44
+#define SYS_CLK_EN0_REG1	0x48
+#define SYS_CLK_EN0_REG2	0x4c
+#define SYS_CLK_EN0_REG3	0x50
+#define CECA_CTRL0		0x88
+#define CECA_CTRL1		0x8c
+#define CECB_CTRL0		0x90
+#define CECB_CTRL1		0x94
+#define SC_CLK_CTRL		0x98
+#define DSPA_CLK_CTRL0		0x9c
+#define DSPB_CLK_CTRL0		0xa0
+#define CLK12_24_CTRL		0xa8
+#define ANAKIN_CLK_CTRL		0xac
+#define MIPI_CSI_PHY_CLK_CTRL	0x10c
+#define MIPI_ISP_CLK_CTRL	0x110
+#define TS_CLK_CTRL		0x158
+#define MALI_CLK_CTRL		0x15c
+#define ETH_CLK_CTRL		0x164
+#define NAND_CLK_CTRL		0x168
+#define SD_EMMC_CLK_CTRL	0x16c
+#define SPICC_CLK_CTRL		0x174
+#define SAR_CLK_CTRL0		0x17c
+#define PWM_CLK_AB_CTRL		0x180
+#define PWM_CLK_CD_CTRL		0x184
+#define PWM_CLK_EF_CTRL		0x188
+#define PWM_CLK_AO_AB_CTRL	0x1a0
+#define PWM_CLK_AO_CD_CTRL	0x1a4
+#define PWM_CLK_AO_EF_CTRL	0x1a8
+#define PWM_CLK_AO_GH_CTRL	0x1ac
+#define SPICC_CLK_CTRL1		0x1c0
+#define SPICC_CLK_CTRL2		0x1c4
+
+#define T7_COMP_SEL(_name, _reg, _shift, _mask, _pdata) \
+	MESON_COMP_SEL(t7_, _name, _reg, _shift, _mask, _pdata, NULL, 0, 0)
+
+#define T7_COMP_DIV(_name, _reg, _shift, _width) \
+	MESON_COMP_DIV(t7_, _name, _reg, _shift, _width, 0, CLK_SET_RATE_PARENT)
+
+#define T7_COMP_GATE(_name, _reg, _bit, _iflags) \
+	MESON_COMP_GATE(t7_, _name, _reg, _bit, CLK_SET_RATE_PARENT | (_iflags))
+
+static struct clk_regmap t7_rtc_dualdiv_in = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = RTC_BY_OSCIN_CTRL0,
+		.bit_idx = 31,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "rtc_duandiv_in",
+		.ops = &clk_regmap_gate_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "xtal",
+		},
+		.num_parents = 1,
+	},
+};
+
+static const struct meson_clk_dualdiv_param t7_dualdiv_table[] = {
+	{
+		.n1	= 733, .m1	= 8,
+		.n2	= 732, .m2	= 11,
+		.dual	= 1,
+	},
+	{}
+};
+
+static struct clk_regmap t7_rtc_dualdiv_div = {
+	.data = &(struct meson_clk_dualdiv_data){
+		.n1 = {
+			.reg_off = RTC_BY_OSCIN_CTRL0,
+			.shift   = 0,
+			.width   = 12,
+		},
+		.n2 = {
+			.reg_off = RTC_BY_OSCIN_CTRL0,
+			.shift   = 12,
+			.width   = 12,
+		},
+		.m1 = {
+			.reg_off = RTC_BY_OSCIN_CTRL1,
+			.shift   = 0,
+			.width   = 12,
+		},
+		.m2 = {
+			.reg_off = RTC_BY_OSCIN_CTRL1,
+			.shift   = 12,
+			.width   = 12,
+		},
+		.dual = {
+			.reg_off = RTC_BY_OSCIN_CTRL0,
+			.shift   = 28,
+			.width   = 1,
+		},
+		.table = t7_dualdiv_table,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "rtc_dualdiv_div",
+		.ops = &meson_clk_dualdiv_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_rtc_dualdiv_in.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_rtc_dualdiv_sel = {
+	.data = &(struct clk_regmap_mux_data) {
+		.offset = RTC_BY_OSCIN_CTRL1,
+		.mask = 0x1,
+		.shift = 24,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "rtc_dualdiv_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_rtc_dualdiv_div.hw,
+			&t7_rtc_dualdiv_in.hw,
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_rtc_dualdiv = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = RTC_BY_OSCIN_CTRL0,
+		.bit_idx = 30,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "rtc_dualdiv",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_rtc_dualdiv_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_rtc = {
+	.data = &(struct clk_regmap_mux_data) {
+		.offset = RTC_CTRL,
+		.mask = 0x3,
+		.shift = 0,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "rtc",
+		.ops = &clk_regmap_mux_ops,
+		/*
+		 * xtal is also on parent input #3 but that it is not useful to CCF since
+		 * the same parent is available with parent input #0
+		 */
+		.parent_data = (const struct clk_parent_data []) {
+			{ .fw_name = "xtal", },
+			{ .hw = &t7_rtc_dualdiv.hw },
+			{ .fw_name = "ext_rtc", },
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_NO_REPARENT,
+	},
+};
+
+static struct clk_regmap t7_ceca_dualdiv_in = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = CECA_CTRL0,
+		.bit_idx = 31,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "ceca_dualdiv_in",
+		.ops = &clk_regmap_gate_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "xtal",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_ceca_dualdiv_div = {
+	.data = &(struct meson_clk_dualdiv_data){
+		.n1 = {
+			.reg_off = CECA_CTRL0,
+			.shift   = 0,
+			.width   = 12,
+		},
+		.n2 = {
+			.reg_off = CECA_CTRL0,
+			.shift   = 12,
+			.width   = 12,
+		},
+		.m1 = {
+			.reg_off = CECA_CTRL1,
+			.shift   = 0,
+			.width   = 12,
+		},
+		.m2 = {
+			.reg_off = CECA_CTRL1,
+			.shift   = 12,
+			.width   = 12,
+		},
+		.dual = {
+			.reg_off = CECA_CTRL0,
+			.shift   = 28,
+			.width   = 1,
+		},
+		.table = t7_dualdiv_table,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "ceca_dualdiv_div",
+		.ops = &meson_clk_dualdiv_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_ceca_dualdiv_in.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_ceca_dualdiv_sel = {
+	.data = &(struct clk_regmap_mux_data) {
+		.offset = CECA_CTRL1,
+		.mask = 0x1,
+		.shift = 24,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "ceca_dualdiv_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_ceca_dualdiv_div.hw,
+			&t7_ceca_dualdiv_in.hw,
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_ceca_dualdiv = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = CECA_CTRL0,
+		.bit_idx = 30,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "ceca_dualdiv",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_ceca_dualdiv_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_ceca = {
+	.data = &(struct clk_regmap_mux_data) {
+		.offset = CECA_CTRL1,
+		.mask = 0x1,
+		.shift = 31,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "ceca",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_ceca_dualdiv.hw,
+			&t7_rtc.hw,
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_cecb_dualdiv_in = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = CECB_CTRL0,
+		.bit_idx = 31,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "cecb_dualdiv_in",
+		.ops = &clk_regmap_gate_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "xtal",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_cecb_dualdiv_div = {
+	.data = &(struct meson_clk_dualdiv_data){
+		.n1 = {
+			.reg_off = CECB_CTRL0,
+			.shift   = 0,
+			.width   = 12,
+		},
+		.n2 = {
+			.reg_off = CECB_CTRL0,
+			.shift   = 12,
+			.width   = 12,
+		},
+		.m1 = {
+			.reg_off = CECB_CTRL1,
+			.shift   = 0,
+			.width   = 12,
+		},
+		.m2 = {
+			.reg_off = CECB_CTRL1,
+			.shift   = 12,
+			.width   = 12,
+		},
+		.dual = {
+			.reg_off = CECB_CTRL0,
+			.shift   = 28,
+			.width   = 1,
+		},
+		.table = t7_dualdiv_table,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "cecb_dualdiv_div",
+		.ops = &meson_clk_dualdiv_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_cecb_dualdiv_in.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_cecb_dualdiv_sel = {
+	.data = &(struct clk_regmap_mux_data) {
+		.offset = CECB_CTRL1,
+		.mask = 0x1,
+		.shift = 24,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "cecb_dualdiv_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_cecb_dualdiv_div.hw,
+			&t7_cecb_dualdiv_in.hw,
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_cecb_dualdiv = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = CECB_CTRL0,
+		.bit_idx = 30,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "cecb_dualdiv",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_cecb_dualdiv_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_cecb = {
+	.data = &(struct clk_regmap_mux_data) {
+		.offset = CECB_CTRL1,
+		.mask = 0x1,
+		.shift = 31,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "cecb",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_cecb_dualdiv.hw,
+			&t7_rtc.hw,
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static const struct clk_parent_data t7_sc_parents[] = {
+	{ .fw_name = "fdiv4", },
+	{ .fw_name = "fdiv3", },
+	{ .fw_name = "fdiv5", },
+	{ .fw_name = "xtal", },
+};
+
+static T7_COMP_SEL(sc, SC_CLK_CTRL, 9, 0x3, t7_sc_parents);
+static T7_COMP_DIV(sc, SC_CLK_CTRL, 0, 8);
+static T7_COMP_GATE(sc, SC_CLK_CTRL, 8, 0);
+
+static const struct clk_parent_data t7_dsp_parents[] = {
+	{ .fw_name = "xtal", },
+	{ .fw_name = "fdiv2p5", },
+	{ .fw_name = "fdiv3", },
+	{ .fw_name = "fdiv5", },
+	{ .fw_name = "hifi", },
+	{ .fw_name = "fdiv4", },
+	{ .fw_name = "fdiv7", },
+	{ .hw = &t7_rtc.hw },
+};
+
+static T7_COMP_SEL(dspa_0, DSPA_CLK_CTRL0, 10, 0x7, t7_dsp_parents);
+static T7_COMP_DIV(dspa_0, DSPA_CLK_CTRL0, 0, 10);
+static T7_COMP_GATE(dspa_0, DSPA_CLK_CTRL0, 13, CLK_SET_RATE_GATE);
+
+static T7_COMP_SEL(dspa_1, DSPA_CLK_CTRL0, 26, 0x7, t7_dsp_parents);
+static T7_COMP_DIV(dspa_1, DSPA_CLK_CTRL0, 16, 10);
+static T7_COMP_GATE(dspa_1, DSPA_CLK_CTRL0, 29, CLK_SET_RATE_GATE);
+
+static struct clk_regmap t7_dspa = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = DSPA_CLK_CTRL0,
+		.mask = 0x1,
+		.shift = 15,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "dspa",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_dspa_0.hw,
+			&t7_dspa_1.hw,
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static T7_COMP_SEL(dspb_0, DSPB_CLK_CTRL0, 10, 0x7, t7_dsp_parents);
+static T7_COMP_DIV(dspb_0, DSPB_CLK_CTRL0, 0, 10);
+static T7_COMP_GATE(dspb_0, DSPB_CLK_CTRL0, 13, CLK_SET_RATE_GATE);
+
+static T7_COMP_SEL(dspb_1, DSPB_CLK_CTRL0, 26, 0x7, t7_dsp_parents);
+static T7_COMP_DIV(dspb_1, DSPB_CLK_CTRL0, 16, 10);
+static T7_COMP_GATE(dspb_1, DSPB_CLK_CTRL0, 29, CLK_SET_RATE_GATE);
+
+static struct clk_regmap t7_dspb = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = DSPB_CLK_CTRL0,
+		.mask = 0x1,
+		.shift = 15,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "dspb",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_dspb_0.hw,
+			&t7_dspb_1.hw,
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_24m = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = CLK12_24_CTRL,
+		.bit_idx = 11,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "24m",
+		.ops = &clk_regmap_gate_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "xtal",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_fixed_factor t7_24m_div2 = {
+	.mult = 1,
+	.div = 2,
+	.hw.init = &(struct clk_init_data){
+		.name = "24m_div2",
+		.ops = &clk_fixed_factor_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_24m.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_12m = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = CLK12_24_CTRL,
+		.bit_idx = 10,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "12m",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_24m_div2.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_25m_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = CLK12_24_CTRL,
+		.shift = 0,
+		.width = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "25m_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "fix",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_25m = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = CLK12_24_CTRL,
+		.bit_idx = 12,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "25m",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_25m_div.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static const struct clk_parent_data t7_anakin_parents[] = {
+	{ .fw_name = "fdiv4", },
+	{ .fw_name = "fdiv3", },
+	{ .fw_name = "fdiv5", },
+	{ .fw_name = "fdiv2", },
+	{ .fw_name = "vid_pll0", },
+	{ .fw_name = "mpll1", },
+	{ .fw_name = "mpll2", },
+	{ .fw_name = "fdiv2p5", },
+};
+
+static T7_COMP_SEL(anakin_0, ANAKIN_CLK_CTRL, 9, 0x7, t7_anakin_parents);
+static T7_COMP_DIV(anakin_0, ANAKIN_CLK_CTRL, 0, 7);
+static T7_COMP_GATE(anakin_0, ANAKIN_CLK_CTRL, 8, CLK_SET_RATE_GATE);
+
+static T7_COMP_SEL(anakin_1, ANAKIN_CLK_CTRL, 25, 0x7, t7_anakin_parents);
+static T7_COMP_DIV(anakin_1, ANAKIN_CLK_CTRL, 16, 7);
+static T7_COMP_GATE(anakin_1, ANAKIN_CLK_CTRL, 24, CLK_SET_RATE_GATE);
+
+static struct clk_regmap t7_anakin_01_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = ANAKIN_CLK_CTRL,
+		.mask = 1,
+		.shift = 31,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "anakin_01_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_anakin_0.hw,
+			&t7_anakin_1.hw
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT
+	},
+};
+
+static struct clk_regmap t7_anakin = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = ANAKIN_CLK_CTRL,
+		.bit_idx = 30,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "anakin",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_anakin_01_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT
+	},
+};
+
+static const struct clk_parent_data t7_mipi_csi_phy_parents[] = {
+	{ .fw_name = "xtal", },
+	{ .fw_name = "gp1", },
+	{ .fw_name = "mpll1", },
+	{ .fw_name = "mpll2", },
+	{ .fw_name = "fdiv3", },
+	{ .fw_name = "fdiv4", },
+	{ .fw_name = "fdiv5", },
+	{ .fw_name = "fdiv7", },
+};
+
+static T7_COMP_SEL(mipi_csi_phy_0, MIPI_CSI_PHY_CLK_CTRL, 9, 0x7, t7_mipi_csi_phy_parents);
+static T7_COMP_DIV(mipi_csi_phy_0, MIPI_CSI_PHY_CLK_CTRL, 0, 7);
+static T7_COMP_GATE(mipi_csi_phy_0, MIPI_CSI_PHY_CLK_CTRL, 8, CLK_SET_RATE_GATE);
+
+static T7_COMP_SEL(mipi_csi_phy_1, MIPI_CSI_PHY_CLK_CTRL, 25, 0x7, t7_mipi_csi_phy_parents);
+static T7_COMP_DIV(mipi_csi_phy_1, MIPI_CSI_PHY_CLK_CTRL, 16, 7);
+static T7_COMP_GATE(mipi_csi_phy_1, MIPI_CSI_PHY_CLK_CTRL, 24, CLK_SET_RATE_GATE);
+
+static struct clk_regmap t7_mipi_csi_phy = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = MIPI_CSI_PHY_CLK_CTRL,
+		.mask = 0x1,
+		.shift = 31,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mipi_csi_phy",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_mipi_csi_phy_0.hw,
+			&t7_mipi_csi_phy_1.hw
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static const struct clk_parent_data t7_mipi_isp_parents[] = {
+	{ .fw_name = "xtal", },
+	{ .fw_name = "fdiv4", },
+	{ .fw_name = "fdiv3", },
+	{ .fw_name = "fdiv5", },
+	{ .fw_name = "fdiv7", },
+	{ .fw_name = "mpll2", },
+	{ .fw_name = "mpll3", },
+	{ .fw_name = "gp1", },
+};
+
+static T7_COMP_SEL(mipi_isp, MIPI_ISP_CLK_CTRL, 9, 0x7, t7_mipi_isp_parents);
+static T7_COMP_DIV(mipi_isp, MIPI_ISP_CLK_CTRL, 0, 7);
+static T7_COMP_GATE(mipi_isp, MIPI_ISP_CLK_CTRL, 8, 0);
+
+static struct clk_regmap t7_ts_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = TS_CLK_CTRL,
+		.shift = 0,
+		.width = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "ts_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "xtal",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_ts = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = TS_CLK_CTRL,
+		.bit_idx = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "ts",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_ts_div.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static const struct clk_parent_data t7_mali_parents[] = {
+	{ .fw_name = "xtal", },
+	{ .fw_name = "gp0", },
+	{ .fw_name = "gp1", },
+	{ .fw_name = "fdiv2p5", },
+	{ .fw_name = "fdiv3", },
+	{ .fw_name = "fdiv4", },
+	{ .fw_name = "fdiv5", },
+	{ .fw_name = "fdiv7", },
+};
+
+static T7_COMP_SEL(mali_0, MALI_CLK_CTRL, 9, 0x7, t7_mali_parents);
+static T7_COMP_DIV(mali_0, MALI_CLK_CTRL, 0, 7);
+static T7_COMP_GATE(mali_0, MALI_CLK_CTRL, 8, CLK_SET_RATE_GATE);
+
+static T7_COMP_SEL(mali_1, MALI_CLK_CTRL, 25, 0x7, t7_mali_parents);
+static T7_COMP_DIV(mali_1, MALI_CLK_CTRL, 16, 7);
+static T7_COMP_GATE(mali_1, MALI_CLK_CTRL, 24, CLK_SET_RATE_GATE);
+
+static struct clk_regmap t7_mali = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = MALI_CLK_CTRL,
+		.mask = 1,
+		.shift = 31,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mali",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_mali_0.hw,
+			&t7_mali_1.hw,
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+/*
+ * parent index 2, 3, 4, 5, 6 not connect any clock signal,
+ * the last parent connect external PAD
+ */
+static u32 t7_eth_rmii_parents_val_table[] = { 0, 1, 7 };
+static const struct clk_parent_data t7_eth_rmii_parents[] = {
+	{ .fw_name = "fdiv2", },
+	{ .fw_name = "gp1", },
+	{ .fw_name = "ext_rmii", },
+};
+
+static struct clk_regmap t7_eth_rmii_sel = {
+	.data = &(struct clk_regmap_mux_data) {
+		.offset = ETH_CLK_CTRL,
+		.mask = 0x7,
+		.shift = 9,
+		.table = t7_eth_rmii_parents_val_table,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "eth_rmii_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = t7_eth_rmii_parents,
+		.num_parents = ARRAY_SIZE(t7_eth_rmii_parents),
+		.flags = CLK_SET_RATE_NO_REPARENT,
+	},
+};
+
+static struct clk_regmap t7_eth_rmii_div = {
+	.data = &(struct clk_regmap_div_data) {
+		.offset = ETH_CLK_CTRL,
+		.shift = 0,
+		.width = 7,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "eth_rmii_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_eth_rmii_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap t7_eth_rmii = {
+	.data = &(struct clk_regmap_gate_data) {
+		.offset = ETH_CLK_CTRL,
+		.bit_idx = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "eth_rmii",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_eth_rmii_div.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_fixed_factor t7_fdiv2_div8 = {
+	.mult = 1,
+	.div = 8,
+	.hw.init = &(struct clk_init_data){
+		.name = "fdiv2_div8",
+		.ops = &clk_fixed_factor_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "fdiv2",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap t7_eth_125m = {
+	.data = &(struct clk_regmap_gate_data) {
+		.offset = ETH_CLK_CTRL,
+		.bit_idx = 7,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "eth_125m",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&t7_fdiv2_div8.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static const struct clk_parent_data t7_sd_emmc_parents[] = {
+	{ .fw_name = "xtal", },
+	{ .fw_name = "fdiv2", },
+	{ .fw_name = "fdiv3", },
+	{ .fw_name = "hifi", },
+	{ .fw_name = "fdiv2p5", },
+	{ .fw_name = "mpll2", },
+	{ .fw_name = "mpll3", },
+	{ .fw_name = "gp0", },
+};
+
+static T7_COMP_SEL(sd_emmc_a, SD_EMMC_CLK_CTRL, 9, 0x7, t7_sd_emmc_parents);
+static T7_COMP_DIV(sd_emmc_a, SD_EMMC_CLK_CTRL, 0, 7);
+static T7_COMP_GATE(sd_emmc_a, SD_EMMC_CLK_CTRL, 7, 0);
+
+static T7_COMP_SEL(sd_emmc_b, SD_EMMC_CLK_CTRL, 25, 0x7, t7_sd_emmc_parents);
+static T7_COMP_DIV(sd_emmc_b, SD_EMMC_CLK_CTRL, 16, 7);
+static T7_COMP_GATE(sd_emmc_b, SD_EMMC_CLK_CTRL, 23, 0);
+
+static T7_COMP_SEL(sd_emmc_c, NAND_CLK_CTRL, 9, 0x7, t7_sd_emmc_parents);
+static T7_COMP_DIV(sd_emmc_c, NAND_CLK_CTRL, 0, 7);
+static T7_COMP_GATE(sd_emmc_c, NAND_CLK_CTRL, 7, 0);
+
+static const struct clk_parent_data t7_spicc_parents[] = {
+	{ .fw_name = "xtal", },
+	{ .fw_name = "sys", },
+	{ .fw_name = "fdiv4", },
+	{ .fw_name = "fdiv3", },
+	{ .fw_name = "fdiv2", },
+	{ .fw_name = "fdiv5", },
+	{ .fw_name = "fdiv7", },
+	{ .fw_name = "gp1", },
+};
+
+static T7_COMP_SEL(spicc0, SPICC_CLK_CTRL, 7, 0x7, t7_spicc_parents);
+static T7_COMP_DIV(spicc0, SPICC_CLK_CTRL, 0, 6);
+static T7_COMP_GATE(spicc0, SPICC_CLK_CTRL, 6, 0);
+
+static T7_COMP_SEL(spicc1, SPICC_CLK_CTRL, 23, 0x7, t7_spicc_parents);
+static T7_COMP_DIV(spicc1, SPICC_CLK_CTRL, 16, 6);
+static T7_COMP_GATE(spicc1, SPICC_CLK_CTRL, 22, 0);
+
+static T7_COMP_SEL(spicc2, SPICC_CLK_CTRL1, 7, 0x7, t7_spicc_parents);
+static T7_COMP_DIV(spicc2, SPICC_CLK_CTRL1, 0, 6);
+static T7_COMP_GATE(spicc2, SPICC_CLK_CTRL1, 6, 0);
+
+static T7_COMP_SEL(spicc3, SPICC_CLK_CTRL1, 23, 0x7, t7_spicc_parents);
+static T7_COMP_DIV(spicc3, SPICC_CLK_CTRL1, 16, 6);
+static T7_COMP_GATE(spicc3, SPICC_CLK_CTRL1, 22, 0);
+
+static T7_COMP_SEL(spicc4, SPICC_CLK_CTRL2, 7, 0x7, t7_spicc_parents);
+static T7_COMP_DIV(spicc4, SPICC_CLK_CTRL2, 0, 6);
+static T7_COMP_GATE(spicc4, SPICC_CLK_CTRL2, 6, 0);
+
+static T7_COMP_SEL(spicc5, SPICC_CLK_CTRL2, 23, 0x7, t7_spicc_parents);
+static T7_COMP_DIV(spicc5, SPICC_CLK_CTRL2, 16, 6);
+static T7_COMP_GATE(spicc5, SPICC_CLK_CTRL2, 22, 0);
+
+static const struct clk_parent_data t7_saradc_parents[] = {
+	{ .fw_name = "xtal" },
+	{ .fw_name = "sys" },
+};
+
+static T7_COMP_SEL(saradc, SAR_CLK_CTRL0, 9, 0x1, t7_saradc_parents);
+static T7_COMP_DIV(saradc, SAR_CLK_CTRL0, 0, 8);
+static T7_COMP_GATE(saradc, SAR_CLK_CTRL0, 8, 0);
+
+static const struct clk_parent_data t7_pwm_parents[]  = {
+	{ .fw_name = "xtal", },
+	{ .fw_name = "vid_pll0", },
+	{ .fw_name = "fdiv4", },
+	{ .fw_name = "fdiv3", },
+};
+
+static T7_COMP_SEL(pwm_a, PWM_CLK_AB_CTRL, 9, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_a, PWM_CLK_AB_CTRL, 0, 8);
+static T7_COMP_GATE(pwm_a, PWM_CLK_AB_CTRL, 8, 0);
+
+static T7_COMP_SEL(pwm_b, PWM_CLK_AB_CTRL, 25, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_b, PWM_CLK_AB_CTRL, 16, 8);
+static T7_COMP_GATE(pwm_b, PWM_CLK_AB_CTRL, 24, 0);
+
+static T7_COMP_SEL(pwm_c, PWM_CLK_CD_CTRL, 9, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_c, PWM_CLK_CD_CTRL, 0, 8);
+static T7_COMP_GATE(pwm_c, PWM_CLK_CD_CTRL, 8, 0);
+
+static T7_COMP_SEL(pwm_d, PWM_CLK_CD_CTRL, 25, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_d, PWM_CLK_CD_CTRL, 16, 8);
+static T7_COMP_GATE(pwm_d, PWM_CLK_CD_CTRL, 24, 0);
+
+static T7_COMP_SEL(pwm_e, PWM_CLK_EF_CTRL, 9, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_e, PWM_CLK_EF_CTRL, 0, 8);
+static T7_COMP_GATE(pwm_e, PWM_CLK_EF_CTRL, 8, 0);
+
+static T7_COMP_SEL(pwm_f, PWM_CLK_EF_CTRL, 25, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_f, PWM_CLK_EF_CTRL, 16, 8);
+static T7_COMP_GATE(pwm_f, PWM_CLK_EF_CTRL, 24, 0);
+
+static T7_COMP_SEL(pwm_ao_a, PWM_CLK_AO_AB_CTRL, 9, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_ao_a, PWM_CLK_AO_AB_CTRL, 0, 8);
+static T7_COMP_GATE(pwm_ao_a, PWM_CLK_AO_AB_CTRL, 8, 0);
+
+static T7_COMP_SEL(pwm_ao_b, PWM_CLK_AO_AB_CTRL, 25, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_ao_b, PWM_CLK_AO_AB_CTRL, 16, 8);
+static T7_COMP_GATE(pwm_ao_b, PWM_CLK_AO_AB_CTRL, 24, 0);
+
+static T7_COMP_SEL(pwm_ao_c, PWM_CLK_AO_CD_CTRL, 9, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_ao_c, PWM_CLK_AO_CD_CTRL, 0, 8);
+static T7_COMP_GATE(pwm_ao_c, PWM_CLK_AO_CD_CTRL, 8, 0);
+
+static T7_COMP_SEL(pwm_ao_d, PWM_CLK_AO_CD_CTRL, 25, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_ao_d, PWM_CLK_AO_CD_CTRL, 16, 8);
+static T7_COMP_GATE(pwm_ao_d, PWM_CLK_AO_CD_CTRL, 24, 0);
+
+static T7_COMP_SEL(pwm_ao_e, PWM_CLK_AO_EF_CTRL, 9, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_ao_e, PWM_CLK_AO_EF_CTRL, 0, 8);
+static T7_COMP_GATE(pwm_ao_e, PWM_CLK_AO_EF_CTRL, 8, 0);
+
+static T7_COMP_SEL(pwm_ao_f, PWM_CLK_AO_EF_CTRL, 25, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_ao_f, PWM_CLK_AO_EF_CTRL, 16, 8);
+static T7_COMP_GATE(pwm_ao_f, PWM_CLK_AO_EF_CTRL, 24, 0);
+
+static T7_COMP_SEL(pwm_ao_g, PWM_CLK_AO_GH_CTRL, 9, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_ao_g, PWM_CLK_AO_GH_CTRL, 0, 8);
+static T7_COMP_GATE(pwm_ao_g, PWM_CLK_AO_GH_CTRL, 8, 0);
+
+static T7_COMP_SEL(pwm_ao_h, PWM_CLK_AO_GH_CTRL, 25, 0x3, t7_pwm_parents);
+static T7_COMP_DIV(pwm_ao_h, PWM_CLK_AO_GH_CTRL, 16, 8);
+static T7_COMP_GATE(pwm_ao_h, PWM_CLK_AO_GH_CTRL, 24, 0);
+
+static const struct clk_parent_data t7_sys_pclk_parents = { .fw_name = "sys" };
+
+#define T7_SYS_PCLK(_name, _reg, _bit, _flags) \
+	MESON_PCLK(t7_##_name, _reg, _bit, &t7_sys_pclk_parents, _flags)
+
+static T7_SYS_PCLK(sys_ddr,		SYS_CLK_EN0_REG0, 0,	0);
+static T7_SYS_PCLK(sys_dos,		SYS_CLK_EN0_REG0, 1,	0);
+static T7_SYS_PCLK(sys_mipi_dsi_a,	SYS_CLK_EN0_REG0, 2,	0);
+static T7_SYS_PCLK(sys_mipi_dsi_b,	SYS_CLK_EN0_REG0, 3,	0);
+static T7_SYS_PCLK(sys_ethphy,		SYS_CLK_EN0_REG0, 4,	0);
+static T7_SYS_PCLK(sys_mali,		SYS_CLK_EN0_REG0, 6,	0);
+static T7_SYS_PCLK(sys_aocpu,		SYS_CLK_EN0_REG0, 13,	0);
+static T7_SYS_PCLK(sys_aucpu,		SYS_CLK_EN0_REG0, 14,	0);
+static T7_SYS_PCLK(sys_cec,		SYS_CLK_EN0_REG0, 16,	0);
+static T7_SYS_PCLK(sys_gdc,		SYS_CLK_EN0_REG0, 17,	0);
+static T7_SYS_PCLK(sys_deswarp,		SYS_CLK_EN0_REG0, 18,	0);
+static T7_SYS_PCLK(sys_ampipe_nand,	SYS_CLK_EN0_REG0, 19,	0);
+static T7_SYS_PCLK(sys_ampipe_eth,	SYS_CLK_EN0_REG0, 20,	0);
+static T7_SYS_PCLK(sys_am2axi0,		SYS_CLK_EN0_REG0, 21,	0);
+static T7_SYS_PCLK(sys_am2axi1,		SYS_CLK_EN0_REG0, 22,	0);
+static T7_SYS_PCLK(sys_am2axi2,		SYS_CLK_EN0_REG0, 23,	0);
+static T7_SYS_PCLK(sys_sd_emmc_a,	SYS_CLK_EN0_REG0, 24,	0);
+static T7_SYS_PCLK(sys_sd_emmc_b,	SYS_CLK_EN0_REG0, 25,	0);
+static T7_SYS_PCLK(sys_sd_emmc_c,	SYS_CLK_EN0_REG0, 26,	0);
+static T7_SYS_PCLK(sys_smartcard,	SYS_CLK_EN0_REG0, 27,	0);
+static T7_SYS_PCLK(sys_acodec,		SYS_CLK_EN0_REG0, 28,	0);
+static T7_SYS_PCLK(sys_spifc,		SYS_CLK_EN0_REG0, 29,	0);
+static T7_SYS_PCLK(sys_msr_clk,		SYS_CLK_EN0_REG0, 30,	0);
+static T7_SYS_PCLK(sys_ir_ctrl,		SYS_CLK_EN0_REG0, 31,	0);
+static T7_SYS_PCLK(sys_audio,		SYS_CLK_EN0_REG1, 0,	0);
+static T7_SYS_PCLK(sys_eth,		SYS_CLK_EN0_REG1, 3,	0);
+static T7_SYS_PCLK(sys_uart_a,		SYS_CLK_EN0_REG1, 5,	0);
+static T7_SYS_PCLK(sys_uart_b,		SYS_CLK_EN0_REG1, 6,	0);
+static T7_SYS_PCLK(sys_uart_c,		SYS_CLK_EN0_REG1, 7,	0);
+static T7_SYS_PCLK(sys_uart_d,		SYS_CLK_EN0_REG1, 8,	0);
+static T7_SYS_PCLK(sys_uart_e,		SYS_CLK_EN0_REG1, 9,	0);
+static T7_SYS_PCLK(sys_uart_f,		SYS_CLK_EN0_REG1, 10,	0);
+static T7_SYS_PCLK(sys_aififo,		SYS_CLK_EN0_REG1, 11,	0);
+static T7_SYS_PCLK(sys_spicc2,		SYS_CLK_EN0_REG1, 12,	0);
+static T7_SYS_PCLK(sys_spicc3,		SYS_CLK_EN0_REG1, 13,	0);
+static T7_SYS_PCLK(sys_spicc4,		SYS_CLK_EN0_REG1, 14,	0);
+static T7_SYS_PCLK(sys_ts_a73,		SYS_CLK_EN0_REG1, 15,	0);
+static T7_SYS_PCLK(sys_ts_a53,		SYS_CLK_EN0_REG1, 16,	0);
+static T7_SYS_PCLK(sys_spicc5,		SYS_CLK_EN0_REG1, 17,	0);
+static T7_SYS_PCLK(sys_g2d,		SYS_CLK_EN0_REG1, 20,	0);
+static T7_SYS_PCLK(sys_spicc0,		SYS_CLK_EN0_REG1, 21,	0);
+static T7_SYS_PCLK(sys_spicc1,		SYS_CLK_EN0_REG1, 22,	0);
+static T7_SYS_PCLK(sys_pcie,		SYS_CLK_EN0_REG1, 24,	0);
+static T7_SYS_PCLK(sys_usb,		SYS_CLK_EN0_REG1, 26,	0);
+static T7_SYS_PCLK(sys_pcie_phy,	SYS_CLK_EN0_REG1, 27,	0);
+static T7_SYS_PCLK(sys_i2c_ao_a,	SYS_CLK_EN0_REG1, 28,	0);
+static T7_SYS_PCLK(sys_i2c_ao_b,	SYS_CLK_EN0_REG1, 29,	0);
+static T7_SYS_PCLK(sys_i2c_m_a,		SYS_CLK_EN0_REG1, 30,	0);
+static T7_SYS_PCLK(sys_i2c_m_b,		SYS_CLK_EN0_REG1, 31,	0);
+static T7_SYS_PCLK(sys_i2c_m_c,		SYS_CLK_EN0_REG2, 0,	0);
+static T7_SYS_PCLK(sys_i2c_m_d,		SYS_CLK_EN0_REG2, 1,	0);
+static T7_SYS_PCLK(sys_i2c_m_e,		SYS_CLK_EN0_REG2, 2,	0);
+static T7_SYS_PCLK(sys_i2c_m_f,		SYS_CLK_EN0_REG2, 3,	0);
+static T7_SYS_PCLK(sys_hdmitx_apb,	SYS_CLK_EN0_REG2, 4,	0);
+static T7_SYS_PCLK(sys_i2c_s_a,		SYS_CLK_EN0_REG2, 5,	0);
+static T7_SYS_PCLK(sys_hdmirx_pclk,	SYS_CLK_EN0_REG2, 8,	0);
+static T7_SYS_PCLK(sys_mmc_apb,		SYS_CLK_EN0_REG2, 11,	0);
+static T7_SYS_PCLK(sys_mipi_isp_pclk,	SYS_CLK_EN0_REG2, 17,	0);
+static T7_SYS_PCLK(sys_rsa,		SYS_CLK_EN0_REG2, 18,	0);
+static T7_SYS_PCLK(sys_pclk_sys_apb,	SYS_CLK_EN0_REG2, 19,	0);
+static T7_SYS_PCLK(sys_a73pclk_apb,	SYS_CLK_EN0_REG2, 20,	0);
+static T7_SYS_PCLK(sys_dspa,		SYS_CLK_EN0_REG2, 21,	0);
+static T7_SYS_PCLK(sys_dspb,		SYS_CLK_EN0_REG2, 22,	0);
+static T7_SYS_PCLK(sys_vpu_intr,	SYS_CLK_EN0_REG2, 25,	0);
+static T7_SYS_PCLK(sys_sar_adc,		SYS_CLK_EN0_REG2, 28,	0);
+/*
+ * sys_gic provides the clock for GIC(Generic Interrupt Controller).
+ * After clock is disabled, The GIC cannot work properly. At present, the driver
+ * used by our GIC is the public driver in kernel, and there is no management
+ * clock in the driver.
+ */
+static T7_SYS_PCLK(sys_gic,		SYS_CLK_EN0_REG2, 30,	CLK_IS_CRITICAL);
+static T7_SYS_PCLK(sys_ts_gpu,		SYS_CLK_EN0_REG2, 31,	0);
+static T7_SYS_PCLK(sys_ts_nna,		SYS_CLK_EN0_REG3, 0,	0);
+static T7_SYS_PCLK(sys_ts_vpu,		SYS_CLK_EN0_REG3, 1,	0);
+static T7_SYS_PCLK(sys_ts_hevc,		SYS_CLK_EN0_REG3, 2,	0);
+static T7_SYS_PCLK(sys_pwm_ao_ab,	SYS_CLK_EN0_REG3, 3,	0);
+static T7_SYS_PCLK(sys_pwm_ao_cd,	SYS_CLK_EN0_REG3, 4,	0);
+static T7_SYS_PCLK(sys_pwm_ao_ef,	SYS_CLK_EN0_REG3, 5,	0);
+static T7_SYS_PCLK(sys_pwm_ao_gh,	SYS_CLK_EN0_REG3, 6,	0);
+static T7_SYS_PCLK(sys_pwm_ab,		SYS_CLK_EN0_REG3, 7,	0);
+static T7_SYS_PCLK(sys_pwm_cd,		SYS_CLK_EN0_REG3, 8,	0);
+static T7_SYS_PCLK(sys_pwm_ef,		SYS_CLK_EN0_REG3, 9,	0);
+
+/* Array of all clocks registered by this provider */
+static struct clk_hw *t7_peripherals_hw_clks[] = {
+	[CLKID_RTC_DUALDIV_IN]		= &t7_rtc_dualdiv_in.hw,
+	[CLKID_RTC_DUALDIV_DIV]		= &t7_rtc_dualdiv_div.hw,
+	[CLKID_RTC_DUALDIV_SEL]		= &t7_rtc_dualdiv_sel.hw,
+	[CLKID_RTC_DUALDIV]		= &t7_rtc_dualdiv.hw,
+	[CLKID_RTC]			= &t7_rtc.hw,
+	[CLKID_CECA_DUALDIV_IN]		= &t7_ceca_dualdiv_in.hw,
+	[CLKID_CECA_DUALDIV_DIV]	= &t7_ceca_dualdiv_div.hw,
+	[CLKID_CECA_DUALDIV_SEL]	= &t7_ceca_dualdiv_sel.hw,
+	[CLKID_CECA_DUALDIV]		= &t7_ceca_dualdiv.hw,
+	[CLKID_CECA]			= &t7_ceca.hw,
+	[CLKID_CECB_DUALDIV_IN]		= &t7_cecb_dualdiv_in.hw,
+	[CLKID_CECB_DUALDIV_DIV]	= &t7_cecb_dualdiv_div.hw,
+	[CLKID_CECB_DUALDIV_SEL]	= &t7_cecb_dualdiv_sel.hw,
+	[CLKID_CECB_DUALDIV]		= &t7_cecb_dualdiv.hw,
+	[CLKID_CECB]			= &t7_cecb.hw,
+	[CLKID_SC_SEL]			= &t7_sc_sel.hw,
+	[CLKID_SC_DIV]			= &t7_sc_div.hw,
+	[CLKID_SC]			= &t7_sc.hw,
+	[CLKID_DSPA_0_SEL]		= &t7_dspa_0_sel.hw,
+	[CLKID_DSPA_0_DIV]		= &t7_dspa_0_div.hw,
+	[CLKID_DSPA_0]			= &t7_dspa_0.hw,
+	[CLKID_DSPA_1_SEL]		= &t7_dspa_1_sel.hw,
+	[CLKID_DSPA_1_DIV]		= &t7_dspa_1_div.hw,
+	[CLKID_DSPA_1]			= &t7_dspa_1.hw,
+	[CLKID_DSPA]			= &t7_dspa.hw,
+	[CLKID_DSPB_0_SEL]		= &t7_dspb_0_sel.hw,
+	[CLKID_DSPB_0_DIV]		= &t7_dspb_0_div.hw,
+	[CLKID_DSPB_0]			= &t7_dspb_0.hw,
+	[CLKID_DSPB_1_SEL]		= &t7_dspb_1_sel.hw,
+	[CLKID_DSPB_1_DIV]		= &t7_dspb_1_div.hw,
+	[CLKID_DSPB_1]			= &t7_dspb_1.hw,
+	[CLKID_DSPB]			= &t7_dspb.hw,
+	[CLKID_24M]			= &t7_24m.hw,
+	[CLKID_24M_DIV2]		= &t7_24m_div2.hw,
+	[CLKID_12M]			= &t7_12m.hw,
+	[CLKID_25M_DIV]			= &t7_25m_div.hw,
+	[CLKID_25M]			= &t7_25m.hw,
+	[CLKID_ANAKIN_0_SEL]		= &t7_anakin_0_sel.hw,
+	[CLKID_ANAKIN_0_DIV]		= &t7_anakin_0_div.hw,
+	[CLKID_ANAKIN_0]		= &t7_anakin_0.hw,
+	[CLKID_ANAKIN_1_SEL]		= &t7_anakin_1_sel.hw,
+	[CLKID_ANAKIN_1_DIV]		= &t7_anakin_1_div.hw,
+	[CLKID_ANAKIN_1]		= &t7_anakin_1.hw,
+	[CLKID_ANAKIN_01_SEL]		= &t7_anakin_01_sel.hw,
+	[CLKID_ANAKIN]			= &t7_anakin.hw,
+	[CLKID_MIPI_CSI_PHY_0_SEL]	= &t7_mipi_csi_phy_0_sel.hw,
+	[CLKID_MIPI_CSI_PHY_0_DIV]	= &t7_mipi_csi_phy_0_div.hw,
+	[CLKID_MIPI_CSI_PHY_0]		= &t7_mipi_csi_phy_0.hw,
+	[CLKID_MIPI_CSI_PHY_1_SEL]	= &t7_mipi_csi_phy_1_sel.hw,
+	[CLKID_MIPI_CSI_PHY_1_DIV]	= &t7_mipi_csi_phy_1_div.hw,
+	[CLKID_MIPI_CSI_PHY_1]		= &t7_mipi_csi_phy_1.hw,
+	[CLKID_MIPI_CSI_PHY]		= &t7_mipi_csi_phy.hw,
+	[CLKID_MIPI_ISP_SEL]		= &t7_mipi_isp_sel.hw,
+	[CLKID_MIPI_ISP_DIV]		= &t7_mipi_isp_div.hw,
+	[CLKID_MIPI_ISP]		= &t7_mipi_isp.hw,
+	[CLKID_TS_DIV]			= &t7_ts_div.hw,
+	[CLKID_TS]			= &t7_ts.hw,
+	[CLKID_MALI_0_SEL]		= &t7_mali_0_sel.hw,
+	[CLKID_MALI_0_DIV]		= &t7_mali_0_div.hw,
+	[CLKID_MALI_0]			= &t7_mali_0.hw,
+	[CLKID_MALI_1_SEL]		= &t7_mali_1_sel.hw,
+	[CLKID_MALI_1_DIV]		= &t7_mali_1_div.hw,
+	[CLKID_MALI_1]			= &t7_mali_1.hw,
+	[CLKID_MALI]			= &t7_mali.hw,
+	[CLKID_ETH_RMII_SEL]		= &t7_eth_rmii_sel.hw,
+	[CLKID_ETH_RMII_DIV]		= &t7_eth_rmii_div.hw,
+	[CLKID_ETH_RMII]		= &t7_eth_rmii.hw,
+	[CLKID_FCLK_DIV2_DIV8]		= &t7_fdiv2_div8.hw,
+	[CLKID_ETH_125M]		= &t7_eth_125m.hw,
+	[CLKID_SD_EMMC_A_SEL]		= &t7_sd_emmc_a_sel.hw,
+	[CLKID_SD_EMMC_A_DIV]		= &t7_sd_emmc_a_div.hw,
+	[CLKID_SD_EMMC_A]		= &t7_sd_emmc_a.hw,
+	[CLKID_SD_EMMC_B_SEL]		= &t7_sd_emmc_b_sel.hw,
+	[CLKID_SD_EMMC_B_DIV]		= &t7_sd_emmc_b_div.hw,
+	[CLKID_SD_EMMC_B]		= &t7_sd_emmc_b.hw,
+	[CLKID_SD_EMMC_C_SEL]		= &t7_sd_emmc_c_sel.hw,
+	[CLKID_SD_EMMC_C_DIV]		= &t7_sd_emmc_c_div.hw,
+	[CLKID_SD_EMMC_C]		= &t7_sd_emmc_c.hw,
+	[CLKID_SPICC0_SEL]		= &t7_spicc0_sel.hw,
+	[CLKID_SPICC0_DIV]		= &t7_spicc0_div.hw,
+	[CLKID_SPICC0]			= &t7_spicc0.hw,
+	[CLKID_SPICC1_SEL]		= &t7_spicc1_sel.hw,
+	[CLKID_SPICC1_DIV]		= &t7_spicc1_div.hw,
+	[CLKID_SPICC1]			= &t7_spicc1.hw,
+	[CLKID_SPICC2_SEL]		= &t7_spicc2_sel.hw,
+	[CLKID_SPICC2_DIV]		= &t7_spicc2_div.hw,
+	[CLKID_SPICC2]			= &t7_spicc2.hw,
+	[CLKID_SPICC3_SEL]		= &t7_spicc3_sel.hw,
+	[CLKID_SPICC3_DIV]		= &t7_spicc3_div.hw,
+	[CLKID_SPICC3]			= &t7_spicc3.hw,
+	[CLKID_SPICC4_SEL]		= &t7_spicc4_sel.hw,
+	[CLKID_SPICC4_DIV]		= &t7_spicc4_div.hw,
+	[CLKID_SPICC4]			= &t7_spicc4.hw,
+	[CLKID_SPICC5_SEL]		= &t7_spicc5_sel.hw,
+	[CLKID_SPICC5_DIV]		= &t7_spicc5_div.hw,
+	[CLKID_SPICC5]			= &t7_spicc5.hw,
+	[CLKID_SARADC_SEL]		= &t7_saradc_sel.hw,
+	[CLKID_SARADC_DIV]		= &t7_saradc_div.hw,
+	[CLKID_SARADC]			= &t7_saradc.hw,
+	[CLKID_PWM_A_SEL]		= &t7_pwm_a_sel.hw,
+	[CLKID_PWM_A_DIV]		= &t7_pwm_a_div.hw,
+	[CLKID_PWM_A]			= &t7_pwm_a.hw,
+	[CLKID_PWM_B_SEL]		= &t7_pwm_b_sel.hw,
+	[CLKID_PWM_B_DIV]		= &t7_pwm_b_div.hw,
+	[CLKID_PWM_B]			= &t7_pwm_b.hw,
+	[CLKID_PWM_C_SEL]		= &t7_pwm_c_sel.hw,
+	[CLKID_PWM_C_DIV]		= &t7_pwm_c_div.hw,
+	[CLKID_PWM_C]			= &t7_pwm_c.hw,
+	[CLKID_PWM_D_SEL]		= &t7_pwm_d_sel.hw,
+	[CLKID_PWM_D_DIV]		= &t7_pwm_d_div.hw,
+	[CLKID_PWM_D]			= &t7_pwm_d.hw,
+	[CLKID_PWM_E_SEL]		= &t7_pwm_e_sel.hw,
+	[CLKID_PWM_E_DIV]		= &t7_pwm_e_div.hw,
+	[CLKID_PWM_E]			= &t7_pwm_e.hw,
+	[CLKID_PWM_F_SEL]		= &t7_pwm_f_sel.hw,
+	[CLKID_PWM_F_DIV]		= &t7_pwm_f_div.hw,
+	[CLKID_PWM_F]			= &t7_pwm_f.hw,
+	[CLKID_PWM_AO_A_SEL]		= &t7_pwm_ao_a_sel.hw,
+	[CLKID_PWM_AO_A_DIV]		= &t7_pwm_ao_a_div.hw,
+	[CLKID_PWM_AO_A]		= &t7_pwm_ao_a.hw,
+	[CLKID_PWM_AO_B_SEL]		= &t7_pwm_ao_b_sel.hw,
+	[CLKID_PWM_AO_B_DIV]		= &t7_pwm_ao_b_div.hw,
+	[CLKID_PWM_AO_B]		= &t7_pwm_ao_b.hw,
+	[CLKID_PWM_AO_C_SEL]		= &t7_pwm_ao_c_sel.hw,
+	[CLKID_PWM_AO_C_DIV]		= &t7_pwm_ao_c_div.hw,
+	[CLKID_PWM_AO_C]		= &t7_pwm_ao_c.hw,
+	[CLKID_PWM_AO_D_SEL]		= &t7_pwm_ao_d_sel.hw,
+	[CLKID_PWM_AO_D_DIV]		= &t7_pwm_ao_d_div.hw,
+	[CLKID_PWM_AO_D]		= &t7_pwm_ao_d.hw,
+	[CLKID_PWM_AO_E_SEL]		= &t7_pwm_ao_e_sel.hw,
+	[CLKID_PWM_AO_E_DIV]		= &t7_pwm_ao_e_div.hw,
+	[CLKID_PWM_AO_E]		= &t7_pwm_ao_e.hw,
+	[CLKID_PWM_AO_F_SEL]		= &t7_pwm_ao_f_sel.hw,
+	[CLKID_PWM_AO_F_DIV]		= &t7_pwm_ao_f_div.hw,
+	[CLKID_PWM_AO_F]		= &t7_pwm_ao_f.hw,
+	[CLKID_PWM_AO_G_SEL]		= &t7_pwm_ao_g_sel.hw,
+	[CLKID_PWM_AO_G_DIV]		= &t7_pwm_ao_g_div.hw,
+	[CLKID_PWM_AO_G]		= &t7_pwm_ao_g.hw,
+	[CLKID_PWM_AO_H_SEL]		= &t7_pwm_ao_h_sel.hw,
+	[CLKID_PWM_AO_H_DIV]		= &t7_pwm_ao_h_div.hw,
+	[CLKID_PWM_AO_H]		= &t7_pwm_ao_h.hw,
+	[CLKID_SYS_DDR]			= &t7_sys_ddr.hw,
+	[CLKID_SYS_DOS]			= &t7_sys_dos.hw,
+	[CLKID_SYS_MIPI_DSI_A]		= &t7_sys_mipi_dsi_a.hw,
+	[CLKID_SYS_MIPI_DSI_B]		= &t7_sys_mipi_dsi_b.hw,
+	[CLKID_SYS_ETHPHY]		= &t7_sys_ethphy.hw,
+	[CLKID_SYS_MALI]		= &t7_sys_mali.hw,
+	[CLKID_SYS_AOCPU]		= &t7_sys_aocpu.hw,
+	[CLKID_SYS_AUCPU]		= &t7_sys_aucpu.hw,
+	[CLKID_SYS_CEC]			= &t7_sys_cec.hw,
+	[CLKID_SYS_GDC]			= &t7_sys_gdc.hw,
+	[CLKID_SYS_DESWARP]		= &t7_sys_deswarp.hw,
+	[CLKID_SYS_AMPIPE_NAND]		= &t7_sys_ampipe_nand.hw,
+	[CLKID_SYS_AMPIPE_ETH]		= &t7_sys_ampipe_eth.hw,
+	[CLKID_SYS_AM2AXI0]		= &t7_sys_am2axi0.hw,
+	[CLKID_SYS_AM2AXI1]		= &t7_sys_am2axi1.hw,
+	[CLKID_SYS_AM2AXI2]		= &t7_sys_am2axi2.hw,
+	[CLKID_SYS_SD_EMMC_A]		= &t7_sys_sd_emmc_a.hw,
+	[CLKID_SYS_SD_EMMC_B]		= &t7_sys_sd_emmc_b.hw,
+	[CLKID_SYS_SD_EMMC_C]		= &t7_sys_sd_emmc_c.hw,
+	[CLKID_SYS_SMARTCARD]		= &t7_sys_smartcard.hw,
+	[CLKID_SYS_ACODEC]		= &t7_sys_acodec.hw,
+	[CLKID_SYS_SPIFC]		= &t7_sys_spifc.hw,
+	[CLKID_SYS_MSR_CLK]		= &t7_sys_msr_clk.hw,
+	[CLKID_SYS_IR_CTRL]		= &t7_sys_ir_ctrl.hw,
+	[CLKID_SYS_AUDIO]		= &t7_sys_audio.hw,
+	[CLKID_SYS_ETH]			= &t7_sys_eth.hw,
+	[CLKID_SYS_UART_A]		= &t7_sys_uart_a.hw,
+	[CLKID_SYS_UART_B]		= &t7_sys_uart_b.hw,
+	[CLKID_SYS_UART_C]		= &t7_sys_uart_c.hw,
+	[CLKID_SYS_UART_D]		= &t7_sys_uart_d.hw,
+	[CLKID_SYS_UART_E]		= &t7_sys_uart_e.hw,
+	[CLKID_SYS_UART_F]		= &t7_sys_uart_f.hw,
+	[CLKID_SYS_AIFIFO]		= &t7_sys_aififo.hw,
+	[CLKID_SYS_SPICC2]		= &t7_sys_spicc2.hw,
+	[CLKID_SYS_SPICC3]		= &t7_sys_spicc3.hw,
+	[CLKID_SYS_SPICC4]		= &t7_sys_spicc4.hw,
+	[CLKID_SYS_TS_A73]		= &t7_sys_ts_a73.hw,
+	[CLKID_SYS_TS_A53]		= &t7_sys_ts_a53.hw,
+	[CLKID_SYS_SPICC5]		= &t7_sys_spicc5.hw,
+	[CLKID_SYS_G2D]			= &t7_sys_g2d.hw,
+	[CLKID_SYS_SPICC0]		= &t7_sys_spicc0.hw,
+	[CLKID_SYS_SPICC1]		= &t7_sys_spicc1.hw,
+	[CLKID_SYS_PCIE]		= &t7_sys_pcie.hw,
+	[CLKID_SYS_USB]			= &t7_sys_usb.hw,
+	[CLKID_SYS_PCIE_PHY]		= &t7_sys_pcie_phy.hw,
+	[CLKID_SYS_I2C_AO_A]		= &t7_sys_i2c_ao_a.hw,
+	[CLKID_SYS_I2C_AO_B]		= &t7_sys_i2c_ao_b.hw,
+	[CLKID_SYS_I2C_M_A]		= &t7_sys_i2c_m_a.hw,
+	[CLKID_SYS_I2C_M_B]		= &t7_sys_i2c_m_b.hw,
+	[CLKID_SYS_I2C_M_C]		= &t7_sys_i2c_m_c.hw,
+	[CLKID_SYS_I2C_M_D]		= &t7_sys_i2c_m_d.hw,
+	[CLKID_SYS_I2C_M_E]		= &t7_sys_i2c_m_e.hw,
+	[CLKID_SYS_I2C_M_F]		= &t7_sys_i2c_m_f.hw,
+	[CLKID_SYS_HDMITX_APB]		= &t7_sys_hdmitx_apb.hw,
+	[CLKID_SYS_I2C_S_A]		= &t7_sys_i2c_s_a.hw,
+	[CLKID_SYS_HDMIRX_PCLK]		= &t7_sys_hdmirx_pclk.hw,
+	[CLKID_SYS_MMC_APB]		= &t7_sys_mmc_apb.hw,
+	[CLKID_SYS_MIPI_ISP_PCLK]	= &t7_sys_mipi_isp_pclk.hw,
+	[CLKID_SYS_RSA]			= &t7_sys_rsa.hw,
+	[CLKID_SYS_PCLK_SYS_APB]	= &t7_sys_pclk_sys_apb.hw,
+	[CLKID_SYS_A73PCLK_APB]		= &t7_sys_a73pclk_apb.hw,
+	[CLKID_SYS_DSPA]		= &t7_sys_dspa.hw,
+	[CLKID_SYS_DSPB]		= &t7_sys_dspb.hw,
+	[CLKID_SYS_VPU_INTR]		= &t7_sys_vpu_intr.hw,
+	[CLKID_SYS_SAR_ADC]		= &t7_sys_sar_adc.hw,
+	[CLKID_SYS_GIC]			= &t7_sys_gic.hw,
+	[CLKID_SYS_TS_GPU]		= &t7_sys_ts_gpu.hw,
+	[CLKID_SYS_TS_NNA]		= &t7_sys_ts_nna.hw,
+	[CLKID_SYS_TS_VPU]		= &t7_sys_ts_vpu.hw,
+	[CLKID_SYS_TS_HEVC]		= &t7_sys_ts_hevc.hw,
+	[CLKID_SYS_PWM_AO_AB]		= &t7_sys_pwm_ao_ab.hw,
+	[CLKID_SYS_PWM_AO_CD]		= &t7_sys_pwm_ao_cd.hw,
+	[CLKID_SYS_PWM_AO_EF]		= &t7_sys_pwm_ao_ef.hw,
+	[CLKID_SYS_PWM_AO_GH]		= &t7_sys_pwm_ao_gh.hw,
+	[CLKID_SYS_PWM_AB]		= &t7_sys_pwm_ab.hw,
+	[CLKID_SYS_PWM_CD]		= &t7_sys_pwm_cd.hw,
+	[CLKID_SYS_PWM_EF]		= &t7_sys_pwm_ef.hw,
+};
+
+static const struct meson_clkc_data t7_peripherals_data = {
+	.hw_clks = {
+		.hws = t7_peripherals_hw_clks,
+		.num = ARRAY_SIZE(t7_peripherals_hw_clks),
+	},
+};
+
+static const struct of_device_id t7_peripherals_clkc_match_table[] = {
+	{
+		.compatible = "amlogic,t7-peripherals-clkc",
+		.data = &t7_peripherals_data
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, t7_peripherals_clkc_match_table);
+
+static struct platform_driver t7_peripherals_clkc_driver = {
+	.probe = meson_clkc_mmio_probe,
+	.driver = {
+		.name = "t7-peripherals-clkc",
+		.of_match_table = t7_peripherals_clkc_match_table,
+	},
+};
+module_platform_driver(t7_peripherals_clkc_driver);
+
+MODULE_DESCRIPTION("Amlogic T7 Peripherals Clock Controller driver");
+MODULE_AUTHOR("Jian Hu <jian.hu at amlogic.com>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("CLK_MESON");
-- 
2.47.1



From qijian.guo at nxp.com  Thu Dec 11 18:31:32 2025
From: qijian.guo at nxp.com (Joseph Guo)
Date: Fri, 12 Dec 2025 11:31:32 +0900
Subject: [PATCH v2 0/2] Add FRDM i.MX 91 Development board support
Message-ID: <20251212-imx91_frdm-v2-0-4dd6d289e81d@nxp.com>

FRDM-IMX91 board is a low cost development platform based on i.MX91 SoC:
https://www.nxp.com/design/design-center/development-boards-and-designs/FRDM-IMX91

Add device tree and dt-binding for FRDM-IMX91.

Signed-off-by: Joseph Guo <qijian.guo at nxp.com>
---
Changes in v2:
- rename compatible 'frdm-imx91' to 'imx91-11x11-frdm'
- rename 'sw-keys' to 'gpio-keys'
- rename 'user_btn' to 'button-k'
- drop lpspi3 node
- rename iomuxc 'grpsleep' to 'sleepgrp'
- move dt-binding patch before the dts patch
- add board page link in cover letter
- use CAN PHY to manage the stby gpio of flexcan2
- drop realtek property
- add pcf2131 aliase
- add bootph- property for nodes should be kept in bootloader phase
- add reset-gpio and assert for eqos and fec
- delete unused alias
- Link to v1: https://lore.kernel.org/r/20251114-imx91_frdm-v1-0-e5763bdf9336 at nxp.com

---
Joseph Guo (2):
      dt-bindings: arm: imx Add FRDM-IMX91 board
      arm64: dts: freescale: Add FRDM-IMX91 basic support

 Documentation/devicetree/bindings/arm/fsl.yaml     |   1 +
 arch/arm64/boot/dts/freescale/Makefile             |   1 +
 arch/arm64/boot/dts/freescale/imx91-11x11-frdm.dts | 904 +++++++++++++++++++++
 3 files changed, 906 insertions(+)
---
base-commit: 73f1e611b076de705c2f1c26cfdfc5b8e96f4733
change-id: 20251114-imx91_frdm-add2b2c07e78

Best regards,
-- 
Joseph Guo <qijian.guo at nxp.com>



From qijian.guo at nxp.com  Thu Dec 11 18:31:33 2025
From: qijian.guo at nxp.com (Joseph Guo)
Date: Fri, 12 Dec 2025 11:31:33 +0900
Subject: [PATCH v2 1/2] dt-bindings: arm: imx Add FRDM-IMX91 board
In-Reply-To: <20251212-imx91_frdm-v2-0-4dd6d289e81d@nxp.com>
References: <20251212-imx91_frdm-v2-0-4dd6d289e81d@nxp.com>
Message-ID: <20251212-imx91_frdm-v2-1-4dd6d289e81d@nxp.com>

Add the board FRDM-IMX91 in the binding document.

Signed-off-by: Joseph Guo <qijian.guo at nxp.com>
---
Change in v2:
- rename 'frdm-imx91' to 'imx91-11x11-frdm'
---
 Documentation/devicetree/bindings/arm/fsl.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
index 68a2d5fecc43b06711e2efce61ac1fc2794b79bc..12d72057b1b817283754a2857d8106a409b594e7 100644
--- a/Documentation/devicetree/bindings/arm/fsl.yaml
+++ b/Documentation/devicetree/bindings/arm/fsl.yaml
@@ -1412,6 +1412,7 @@ properties:
         items:
           - enum:
               - fsl,imx91-11x11-evk       # i.MX91 11x11 EVK Board
+              - fsl,imx91-11x11-frdm      # FRDM i.MX91 Development Board
           - const: fsl,imx91
 
       - description: i.MX93 based Boards

-- 
2.34.1



From qijian.guo at nxp.com  Thu Dec 11 18:31:34 2025
From: qijian.guo at nxp.com (Joseph Guo)
Date: Fri, 12 Dec 2025 11:31:34 +0900
Subject: [PATCH v2 2/2] arm64: dts: freescale: Add FRDM-IMX91 basic support
In-Reply-To: <20251212-imx91_frdm-v2-0-4dd6d289e81d@nxp.com>
References: <20251212-imx91_frdm-v2-0-4dd6d289e81d@nxp.com>
Message-ID: <20251212-imx91_frdm-v2-2-4dd6d289e81d@nxp.com>

The FRDM i.MX 91 development board is a low-cost and
compact developmentboard featuring the i.MX 91 applications processor:
https://www.nxp.com/design/design-center/development-boards-and-designs/FRDM-IMX91

Add FRDM-IMX91 board dts support.
- Enable ADC1.
- Enable lpuart1 and lpuart5.
- Enable network eqos and fec.
- Enable I2C bus and children nodes under I2C bus.
- Enable USB and related nodes.
- Enable uSDHC1, uSDHC2 and uSDHC3.
- Enable MU1 and MU2.
- Enable Watchdog3.
- Enable MQS

Co-developed-by: Tom Zheng <haidong.zheng at nxp.com>
Signed-off-by: Tom Zheng <haidong.zheng at nxp.com>
Co-developed-by: Steven Yang <steven.yang at nxp.com>
Signed-off-by: Steven Yang <steven.yang at nxp.com>
Signed-off-by: Joseph Guo <qijian.guo at nxp.com>
---
Changes in v2:
- rename compatible 'frdm-imx91' to 'imx91-11x11-frdm'
- rename model to 'NXP i.MX91 11x11 FRDM Board'
- rename 'sw-keys' to 'gpio-keys'
- rename 'user_btn' to 'button-k'
- drop lpspi3 node
- rename iomuxc 'grpsleep' to 'sleepgrp'
- use CAN PHY to manage the stby gpio of flexcan2
- drop realtek property
- add pcf2131 aliase
- add bootph- property for nodes should be kept in bootloader phase
- add reset-gpio and assert for eqos and fec
- delete unused alias
---
 arch/arm64/boot/dts/freescale/Makefile             |   1 +
 arch/arm64/boot/dts/freescale/imx91-11x11-frdm.dts | 904 +++++++++++++++++++++
 2 files changed, 905 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index f30d3fd724d0ce6b38f7bef10e3970ac34f70f4a..d0808ec3c1c4ab848ad9edf45cf453ce40a5f2c6 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -368,6 +368,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8qxp-tqma8xqps-mb-smarc-2.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8ulp-9x9-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8ulp-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx91-11x11-evk.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx91-11x11-frdm.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx91-phyboard-segin.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx91-tqma9131-mba91xxca.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx93-9x9-qsb.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx91-11x11-frdm.dts b/arch/arm64/boot/dts/freescale/imx91-11x11-frdm.dts
new file mode 100644
index 0000000000000000000000000000000000000000..066a319b4df824515843f20076533857064a09be
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx91-11x11-frdm.dts
@@ -0,0 +1,904 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2025 NXP
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/usb/pd.h>
+#include "imx91.dtsi"
+
+/ {
+	compatible = "fsl,imx91-11x11-frdm", "fsl,imx91";
+	model = "NXP i.MX91 11x11 FRDM Board";
+
+	aliases {
+		ethernet0 = &fec;
+		ethernet1 = &eqos;
+		gpio0 = &gpio1;
+		gpio1 = &gpio2;
+		gpio2 = &gpio3;
+		gpio3 = &gpio4;
+		i2c0 = &lpi2c1;
+		i2c1 = &lpi2c2;
+		i2c2 = &lpi2c3;
+		mmc0 = &usdhc1;
+		mmc1 = &usdhc2;
+		mmc2 = &usdhc3;
+		rtc0 = &bbnsm_rtc;
+		rtc1 = &pcf2131;
+		serial0 = &lpuart1;
+		serial4 = &lpuart5;
+	};
+
+	chosen {
+		stdout-path = &lpuart1;
+	};
+
+	flexcan_phy: can-phy {
+		compatible = "nxp,tja1051";
+		#phy-cells = <0>;
+		max-bitrate = <5000000>;
+		enable-gpios = <&pcal6524 23 GPIO_ACTIVE_LOW>;
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		button-k2 {
+			interrupt-parent = <&pcal6524>;
+			interrupts = <5 IRQ_TYPE_EDGE_FALLING>;
+			label = "Button K2";
+			gpios = <&pcal6524 5 GPIO_PULL_UP>;
+			linux,code = <BTN_1>;
+		};
+
+		button-k3 {
+			interrupt-parent = <&pcal6524>;
+			interrupts = <6 IRQ_TYPE_EDGE_FALLING>;
+			label = "Button K3";
+			gpios = <&pcal6524 6 GPIO_PULL_UP>;
+			linux,code = <BTN_2>;
+		};
+	};
+
+	reg_vref_1v8: regulator-adc-vref {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <1800000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-name = "vref_1v8";
+	};
+
+	reg_m2_pwr: regulator-m2-pwr {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "M.2-power";
+		gpio = <&pcal6524 13 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_usdhc2_vmmc: regulator-usdhc2 {
+		compatible = "regulator-fixed";
+		off-on-delay-us = <12000>;
+		pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
+		pinctrl-names = "default";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "VSD_3V3";
+		gpio = <&gpio3 7 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		bootph-pre-ram;
+		bootph-some-ram;
+	};
+
+	reg_usdhc3_vmmc: regulator-usdhc3 {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "WLAN_EN";
+		vin-supply = <&reg_m2_pwr>;
+		gpio = <&pcal6524 20 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		/*
+		 * This regulator defined as PDn pin of the IW610 wifi module.
+		 * IW610 wifi chip needs more delay than other wifi chips to complete
+		 * the host interface initialization after power up, otherwise the
+		 * internal state of IW610 may be unstable, resulting in the failure of
+		 * the SDIO3.0 switch voltage.
+		 */
+		startup-delay-us = <20000>;
+	};
+
+	reg_vdd_12v: regulator-vdd-12v {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <12000000>;
+		regulator-min-microvolt = <12000000>;
+		regulator-name = "reg_vdd_12v";
+		gpio = <&pcal6524 14 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_vexp_3v3: regulator-vexp-3v3 {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "VEXP_3V3";
+		vin-supply = <&buck4>;
+		gpio = <&pcal6524 2 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_vexp_5v: regulator-vexp-5v {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <5000000>;
+		regulator-min-microvolt = <5000000>;
+		regulator-name = "VEXP_5V";
+		gpio = <&pcal6524 8 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reserved-memory {
+		ranges;
+		#address-cells = <2>;
+		#size-cells = <2>;
+
+		linux,cma {
+			compatible = "shared-dma-pool";
+			alloc-ranges = <0 0x80000000 0 0x30000000>;
+			reusable;
+			size = <0 0x10000000>;
+			linux,cma-default;
+		};
+	};
+
+	soc at 0 {
+		bootph-all;
+		bootph-pre-ram;
+	};
+
+	sound-mqs {
+		compatible = "fsl,imx6sx-sdb-mqs",
+			     "fsl,imx-audio-mqs";
+		audio-codec = <&mqs1>;
+		audio-cpu = <&sai1>;
+		model = "mqs-audio";
+	};
+
+	usdhc3_pwrseq: usdhc3-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&pcal6524 12 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&adc1 {
+	vref-supply = <&reg_vref_1v8>;
+	status = "okay";
+};
+
+&aips1 {
+	bootph-pre-ram;
+	bootph-all;
+};
+
+&aips2 {
+	bootph-pre-ram;
+	bootph-some-ram;
+};
+
+&aips3 {
+	bootph-pre-ram;
+	bootph-some-ram;
+};
+
+&clk {
+	bootph-all;
+	bootph-pre-ram;
+};
+
+&clk_ext1 {
+	bootph-all;
+	bootph-pre-ram;
+};
+
+&eqos {
+	phy-handle = <&ethphy1>;
+	phy-mode = "rgmii-id";
+	pinctrl-0 = <&pinctrl_eqos>;
+	pinctrl-1 = <&pinctrl_eqos_sleep>;
+	pinctrl-names = "default", "sleep";
+	status = "okay";
+
+	mdio {
+		compatible = "snps,dwmac-mdio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-frequency = <5000000>;
+
+		ethphy1: ethernet-phy at 1 {
+			reg = <1>;
+			reset-gpios = <&pcal6524 15 GPIO_ACTIVE_LOW>;
+			reset-assert-us = <15000>;
+			reset-deassert-us = <100000>;
+		};
+	};
+};
+
+&fec {
+	phy-handle = <&ethphy2>;
+	phy-mode = "rgmii-id";
+	pinctrl-0 = <&pinctrl_fec>;
+	pinctrl-1 = <&pinctrl_fec_sleep>;
+	pinctrl-names = "default", "sleep";
+	fsl,magic-packet;
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-frequency = <5000000>;
+
+		ethphy2: ethernet-phy at 2 {
+			reg = <2>;
+			reset-gpios = <&pcal6524 16 GPIO_ACTIVE_LOW>;
+			reset-assert-us = <15000>;
+			reset-deassert-us = <100000>;
+		};
+	};
+};
+
+&flexcan2 {
+	pinctrl-0 = <&pinctrl_flexcan2>;
+	pinctrl-1 = <&pinctrl_flexcan2_sleep>;
+	pinctrl-names = "default", "sleep";
+	phys = <&flexcan_phy>;
+	status = "okay";
+};
+
+&gpio1 {
+	bootph-pre-ram;
+	bootph-some-ram;
+};
+
+&gpio2 {
+	bootph-pre-ram;
+	bootph-some-ram;
+};
+
+&gpio3 {
+	bootph-pre-ram;
+	bootph-some-ram;
+};
+
+&gpio4 {
+	bootph-pre-ram;
+	bootph-some-ram;
+};
+
+&lpi2c1 {
+	clock-frequency = <400000>;
+	pinctrl-0 = <&pinctrl_lpi2c1>;
+	pinctrl-names = "default";
+	status = "okay";
+	bootph-pre-ram;
+	bootph-some-ram;
+
+	pcal6408: gpio at 20 {
+		compatible = "nxp,pcal9554b";
+		reg = <0x20>;
+		#gpio-cells = <2>;
+		gpio-controller;
+		vcc-supply = <&reg_usdhc3_vmmc>;
+		status = "okay";
+	};
+};
+
+&lpi2c2 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	clock-frequency = <400000>;
+	pinctrl-0 = <&pinctrl_lpi2c2>;
+	pinctrl-names = "default";
+	status = "okay";
+	bootph-pre-ram;
+	bootph-some-ram;
+
+	pcal6524: gpio at 22 {
+		compatible = "nxp,pcal6524";
+		reg = <0x22>;
+		#interrupt-cells = <2>;
+		interrupt-controller;
+		interrupts = <27 IRQ_TYPE_LEVEL_LOW>;
+		#gpio-cells = <2>;
+		gpio-controller;
+		interrupt-parent = <&gpio3>;
+		pinctrl-0 = <&pinctrl_pcal6524>;
+		pinctrl-names = "default";
+	};
+
+	pmic at 25 {
+		compatible = "nxp,pca9451a";
+		reg = <0x25>;
+		interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
+		interrupt-parent = <&pcal6524>;
+		bootph-pre-ram;
+		bootph-some-ram;
+
+		regulators {
+			bootph-pre-ram;
+			bootph-some-ram;
+			buck1: BUCK1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <2237500>;
+				regulator-min-microvolt = <650000>;
+				regulator-name = "BUCK1";
+				regulator-ramp-delay = <3125>;
+			};
+
+			buck2: BUCK2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <2187500>;
+				regulator-min-microvolt = <600000>;
+				regulator-name = "BUCK2";
+				regulator-ramp-delay = <3125>;
+			};
+
+			buck4: BUCK4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <3400000>;
+				regulator-min-microvolt = <600000>;
+				regulator-name = "BUCK4";
+			};
+
+			buck5: BUCK5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <3400000>;
+				regulator-min-microvolt = <600000>;
+				regulator-name = "BUCK5";
+			};
+
+			buck6: BUCK6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <3400000>;
+				regulator-min-microvolt = <600000>;
+				regulator-name = "BUCK6";
+			};
+
+			ldo1: LDO1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <3300000>;
+				regulator-min-microvolt = <1600000>;
+				regulator-name = "LDO1";
+			};
+
+			ldo4: LDO4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <3300000>;
+				regulator-min-microvolt = <800000>;
+				regulator-name = "LDO4";
+			};
+
+			ldo5: LDO5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <3300000>;
+				regulator-min-microvolt = <1800000>;
+				regulator-name = "LDO5";
+			};
+		};
+	};
+};
+
+&lpi2c3 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	clock-frequency = <400000>;
+	pinctrl-0 = <&pinctrl_lpi2c3>;
+	pinctrl-names = "default";
+	status = "okay";
+	bootph-pre-ram;
+	bootph-some-ram;
+
+	ptn5110: tcpc at 50 {
+		compatible = "nxp,ptn5110", "tcpci";
+		reg = <0x50>;
+		interrupts = <27 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio3>;
+
+		typec1_con: connector {
+			compatible = "usb-c-connector";
+			data-role = "dual";
+			label = "USB-C";
+			op-sink-microwatt = <15000000>;
+			power-role = "dual";
+			self-powered;
+			sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)
+				     PDO_VAR(5000, 20000, 3000)>;
+			source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
+			try-power-role = "sink";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+
+					typec1_dr_sw: endpoint {
+						remote-endpoint = <&usb1_drd_sw>;
+					};
+				};
+			};
+		};
+	};
+
+	pcf2131: rtc at 53 {
+		compatible = "nxp,pcf2131";
+		reg = <0x53>;
+		interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
+		interrupt-parent = <&pcal6524>;
+		status = "okay";
+	};
+};
+
+&lpuart1 {
+	pinctrl-0 = <&pinctrl_uart1>;
+	pinctrl-names = "default";
+	status = "okay";
+	bootph-pre-ram;
+	bootph-some-ram;
+};
+
+&lpuart5 {
+	pinctrl-0 = <&pinctrl_uart5>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	bluetooth {
+		compatible = "nxp,88w8987-bt";
+	};
+};
+
+&mqs1 {
+	clocks = <&clk IMX93_CLK_MQS1_GATE>;
+	clock-names = "mclk";
+	pinctrl-0 = <&pinctrl_mqs1>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&osc_32k {
+	bootph-all;
+	bootph-pre-ram;
+};
+
+&osc_24m {
+	bootph-all;
+	bootph-pre-ram;
+};
+
+&sai1 {
+	clocks = <&clk IMX93_CLK_SAI1_IPG>, <&clk IMX93_CLK_DUMMY>,
+		 <&clk IMX93_CLK_SAI1_GATE>, <&clk IMX93_CLK_DUMMY>,
+		 <&clk IMX93_CLK_DUMMY>, <&clk IMX93_CLK_AUDIO_PLL>;
+	clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3", "pll8k";
+	assigned-clocks = <&clk IMX93_CLK_SAI1>;
+	assigned-clock-parents = <&clk IMX93_CLK_AUDIO_PLL>;
+	assigned-clock-rates = <24576000>;
+	#sound-dai-cells = <0>;
+	fsl,sai-mclk-direction-output;
+	status = "okay";
+};
+
+&usbotg1 {
+	adp-disable;
+	disable-over-current;
+	dr_mode = "otg";
+	hnp-disable;
+	srp-disable;
+	usb-role-switch;
+	samsung,picophy-dc-vol-level-adjust = <7>;
+	samsung,picophy-pre-emp-curr-control = <3>;
+	status = "okay";
+
+	port {
+		usb1_drd_sw: endpoint {
+			remote-endpoint = <&typec1_dr_sw>;
+		};
+	};
+};
+
+&usbotg2 {
+	disable-over-current;
+	dr_mode = "host";
+	samsung,picophy-dc-vol-level-adjust = <7>;
+	samsung,picophy-pre-emp-curr-control = <3>;
+	status = "okay";
+};
+
+&usdhc1 {
+	bus-width = <8>;
+	non-removable;
+	pinctrl-0 = <&pinctrl_usdhc1>;
+	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	status = "okay";
+	bootph-pre-ram;
+	bootph-some-ram;
+};
+
+&usdhc2 {
+	bus-width = <4>;
+	cd-gpios = <&gpio3 00 GPIO_ACTIVE_LOW>;
+	no-mmc;
+	no-sdio;
+	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-3 = <&pinctrl_usdhc2_sleep>, <&pinctrl_usdhc2_gpio_sleep>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	status = "okay";
+	bootph-pre-ram;
+	bootph-some-ram;
+};
+
+&usdhc3 {
+	bus-width = <4>;
+	keep-power-in-suspend;
+	mmc-pwrseq = <&usdhc3_pwrseq>;
+	non-removable;
+	pinctrl-0 = <&pinctrl_usdhc3>, <&pinctrl_usdhc3_wlan>;
+	pinctrl-1 = <&pinctrl_usdhc3_100mhz>, <&pinctrl_usdhc3_wlan>;
+	pinctrl-2 = <&pinctrl_usdhc3_200mhz>, <&pinctrl_usdhc3_wlan>;
+	pinctrl-3 = <&pinctrl_usdhc3_sleep>, <&pinctrl_usdhc3_wlan>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
+	vmmc-supply = <&reg_usdhc3_vmmc>;
+	wakeup-source;
+	status = "okay";
+};
+
+&wdog3 {
+	fsl,ext-reset-output;
+	status = "okay";
+};
+
+&iomuxc {
+	bootph-pre-ram;
+	bootph-some-ram;
+	pinctrl_eqos: eqosgrp {
+		fsl,pins = <
+			MX91_PAD_ENET1_MDC__ENET1_MDC				0x57e
+			MX91_PAD_ENET1_MDIO__ENET_QOS_MDIO			0x57e
+			MX91_PAD_ENET1_RD0__ENET_QOS_RGMII_RD0			0x57e
+			MX91_PAD_ENET1_RD1__ENET_QOS_RGMII_RD1			0x57e
+			MX91_PAD_ENET1_RD2__ENET_QOS_RGMII_RD2			0x57e
+			MX91_PAD_ENET1_RD3__ENET_QOS_RGMII_RD3			0x57e
+			MX91_PAD_ENET1_RXC__ENET_QOS_RGMII_RXC			0x5fe
+			MX91_PAD_ENET1_RX_CTL__ENET_QOS_RGMII_RX_CTL		0x57e
+			MX91_PAD_ENET1_TD0__ENET_QOS_RGMII_TD0			0x57e
+			MX91_PAD_ENET1_TD1__ENET1_RGMII_TD1			0x57e
+			MX91_PAD_ENET1_TD2__ENET_QOS_RGMII_TD2			0x57e
+			MX91_PAD_ENET1_TD3__ENET_QOS_RGMII_TD3			0x57e
+			MX91_PAD_ENET1_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK	0x5fe
+			MX91_PAD_ENET1_TX_CTL__ENET_QOS_RGMII_TX_CTL		0x57e
+		>;
+	};
+
+	pinctrl_eqos_sleep: eqossleepgrp {
+		fsl,pins = <
+			MX91_PAD_ENET1_MDC__GPIO4_IO0				0x31e
+			MX91_PAD_ENET1_MDIO__GPIO4_IO1				0x31e
+			MX91_PAD_ENET1_RD0__GPIO4_IO10				0x31e
+			MX91_PAD_ENET1_RD1__GPIO4_IO11				0x31e
+			MX91_PAD_ENET1_RD2__GPIO4_IO12				0x31e
+			MX91_PAD_ENET1_RD3__GPIO4_IO13				0x31e
+			MX91_PAD_ENET1_RXC__GPIO4_IO9				0x31e
+			MX91_PAD_ENET1_RX_CTL__GPIO4_IO8			0x31e
+			MX91_PAD_ENET1_TD0__GPIO4_IO5				0x31e
+			MX91_PAD_ENET1_TD1__GPIO4_IO4				0x31e
+			MX91_PAD_ENET1_TD2__GPIO4_IO3				0x31e
+			MX91_PAD_ENET1_TD3__GPIO4_IO2				0x31e
+			MX91_PAD_ENET1_TXC__GPIO4_IO7				0x31e
+			MX91_PAD_ENET1_TX_CTL__GPIO4_IO6			0x31e
+		>;
+	};
+
+	pinctrl_fec: fecgrp {
+		fsl,pins = <
+			MX91_PAD_ENET2_MDC__ENET2_MDC				0x57e
+			MX91_PAD_ENET2_MDIO__ENET2_MDIO				0x57e
+			MX91_PAD_ENET2_RD0__ENET2_RGMII_RD0			0x57e
+			MX91_PAD_ENET2_RD1__ENET2_RGMII_RD1			0x57e
+			MX91_PAD_ENET2_RD2__ENET2_RGMII_RD2			0x57e
+			MX91_PAD_ENET2_RD3__ENET2_RGMII_RD3			0x57e
+			MX91_PAD_ENET2_RXC__ENET2_RGMII_RXC			0x5fe
+			MX91_PAD_ENET2_RX_CTL__ENET2_RGMII_RX_CTL		0x57e
+			MX91_PAD_ENET2_TD0__ENET2_RGMII_TD0			0x57e
+			MX91_PAD_ENET2_TD1__ENET2_RGMII_TD1			0x57e
+			MX91_PAD_ENET2_TD2__ENET2_RGMII_TD2			0x57e
+			MX91_PAD_ENET2_TD3__ENET2_RGMII_TD3			0x57e
+			MX91_PAD_ENET2_TXC__ENET2_RGMII_TXC			0x5fe
+			MX91_PAD_ENET2_TX_CTL__ENET2_RGMII_TX_CTL		0x57e
+		>;
+	};
+
+	pinctrl_fec_sleep: fecsleepgrp {
+		fsl,pins = <
+			MX91_PAD_ENET2_MDC__GPIO4_IO14				0x51e
+			MX91_PAD_ENET2_MDIO__GPIO4_IO15				0x51e
+			MX91_PAD_ENET2_RD0__GPIO4_IO24				0x51e
+			MX91_PAD_ENET2_RD1__GPIO4_IO25				0x51e
+			MX91_PAD_ENET2_RD2__GPIO4_IO26				0x51e
+			MX91_PAD_ENET2_RD3__GPIO4_IO27				0x51e
+			MX91_PAD_ENET2_RXC__GPIO4_IO23				0x51e
+			MX91_PAD_ENET2_RX_CTL__GPIO4_IO22			0x51e
+			MX91_PAD_ENET2_TD0__GPIO4_IO19				0x51e
+			MX91_PAD_ENET2_TD1__GPIO4_IO18				0x51e
+			MX91_PAD_ENET2_TD2__GPIO4_IO17				0x51e
+			MX91_PAD_ENET2_TD3__GPIO4_IO16				0x51e
+			MX91_PAD_ENET2_TXC__GPIO4_IO21				0x51e
+			MX91_PAD_ENET2_TX_CTL__GPIO4_IO20			0x51e
+		>;
+	};
+
+	pinctrl_flexcan2: flexcan2grp {
+		fsl,pins = <
+			MX91_PAD_GPIO_IO25__CAN2_TX				0x139e
+			MX91_PAD_GPIO_IO27__CAN2_RX				0x139e
+		>;
+	};
+
+	pinctrl_flexcan2_sleep: flexcan2sleepgrp {
+		fsl,pins = <
+			MX91_PAD_GPIO_IO25__GPIO2_IO25				0x31e
+			MX91_PAD_GPIO_IO27__GPIO2_IO27				0x31e
+		>;
+	};
+
+	pinctrl_lpi2c1: lpi2c1grp {
+		fsl,pins = <
+			MX91_PAD_I2C1_SCL__LPI2C1_SCL				0x40000b9e
+			MX91_PAD_I2C1_SDA__LPI2C1_SDA				0x40000b9e
+		>;
+		bootph-pre-ram;
+		bootph-some-ram;
+	};
+
+	pinctrl_lpi2c2: lpi2c2grp {
+		fsl,pins = <
+			MX91_PAD_I2C2_SCL__LPI2C2_SCL				0x40000b9e
+			MX91_PAD_I2C2_SDA__LPI2C2_SDA				0x40000b9e
+		>;
+		bootph-pre-ram;
+		bootph-some-ram;
+	};
+
+	pinctrl_lpi2c3: lpi2c3grp {
+		fsl,pins = <
+			MX91_PAD_GPIO_IO28__LPI2C3_SDA				0x40000b9e
+			MX91_PAD_GPIO_IO29__LPI2C3_SCL				0x40000b9e
+		>;
+		bootph-pre-ram;
+		bootph-some-ram;
+	};
+
+	pinctrl_lpspi3: lpspi3grp {
+		fsl,pins = <
+			MX91_PAD_GPIO_IO08__GPIO2_IO8				0x3fe
+			MX91_PAD_GPIO_IO09__LPSPI3_SIN				0x3fe
+			MX91_PAD_GPIO_IO10__LPSPI3_SOUT				0x3fe
+			MX91_PAD_GPIO_IO11__LPSPI3_SCK				0x3fe
+		>;
+	};
+
+	pinctrl_mqs1: mqs1grp {
+		fsl,pins = <
+			MX91_PAD_PDM_CLK__MQS1_LEFT				0x31e
+			MX91_PAD_PDM_BIT_STREAM0__MQS1_RIGHT			0x31e
+		>;
+	};
+
+	pinctrl_pcal6524: pcal6524grp {
+		fsl,pins = <
+			MX91_PAD_CCM_CLKO2__GPIO3_IO27				0x31e
+		>;
+	};
+
+	pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
+		fsl,pins = <
+			MX91_PAD_SD2_RESET_B__GPIO3_IO7				0x31e
+		>;
+		bootph-pre-ram;
+	};
+
+	pinctrl_uart1: uart1grp {
+		fsl,pins = <
+			MX91_PAD_UART1_RXD__LPUART1_RX				0x31e
+			MX91_PAD_UART1_TXD__LPUART1_TX				0x31e
+		>;
+		bootph-pre-ram;
+		bootph-some-ram;
+	};
+
+	pinctrl_uart5: uart5grp {
+		fsl,pins = <
+			MX91_PAD_DAP_TDO_TRACESWO__LPUART5_TX			0x31e
+			MX91_PAD_DAP_TDI__LPUART5_RX				0x31e
+			MX91_PAD_DAP_TMS_SWDIO__LPUART5_RTS_B			0x31e
+			MX91_PAD_DAP_TCLK_SWCLK__LPUART5_CTS_B			0x31e
+		>;
+	};
+
+	pinctrl_usdhc1: usdhc1grp {
+		fsl,pins = <
+			MX91_PAD_SD1_CLK__USDHC1_CLK				0x1582
+			MX91_PAD_SD1_CMD__USDHC1_CMD				0x1382
+			MX91_PAD_SD1_DATA0__USDHC1_DATA0			0x1382
+			MX91_PAD_SD1_DATA1__USDHC1_DATA1			0x1382
+			MX91_PAD_SD1_DATA2__USDHC1_DATA2			0x1382
+			MX91_PAD_SD1_DATA3__USDHC1_DATA3			0x1382
+			MX91_PAD_SD1_DATA4__USDHC1_DATA4			0x1382
+			MX91_PAD_SD1_DATA5__USDHC1_DATA5			0x1382
+			MX91_PAD_SD1_DATA6__USDHC1_DATA6			0x1382
+			MX91_PAD_SD1_DATA7__USDHC1_DATA7			0x1382
+			MX91_PAD_SD1_STROBE__USDHC1_STROBE			0x1582
+		>;
+		bootph-pre-ram;
+		bootph-some-ram;
+	};
+
+	pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp {
+		fsl,pins = <
+			MX91_PAD_SD1_CLK__USDHC1_CLK				0x158e
+			MX91_PAD_SD1_CMD__USDHC1_CMD				0x138e
+			MX91_PAD_SD1_DATA0__USDHC1_DATA0			0x138e
+			MX91_PAD_SD1_DATA1__USDHC1_DATA1			0x138e
+			MX91_PAD_SD1_DATA2__USDHC1_DATA2			0x138e
+			MX91_PAD_SD1_DATA3__USDHC1_DATA3			0x138e
+			MX91_PAD_SD1_DATA4__USDHC1_DATA4			0x138e
+			MX91_PAD_SD1_DATA5__USDHC1_DATA5			0x138e
+			MX91_PAD_SD1_DATA6__USDHC1_DATA6			0x138e
+			MX91_PAD_SD1_DATA7__USDHC1_DATA7			0x138e
+			MX91_PAD_SD1_STROBE__USDHC1_STROBE			0x158e
+		>;
+	};
+
+	pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp {
+		fsl,pins = <
+			MX91_PAD_SD1_CLK__USDHC1_CLK				0x15fe
+			MX91_PAD_SD1_CMD__USDHC1_CMD				0x13fe
+			MX91_PAD_SD1_DATA0__USDHC1_DATA0			0x13fe
+			MX91_PAD_SD1_DATA1__USDHC1_DATA1			0x13fe
+			MX91_PAD_SD1_DATA2__USDHC1_DATA2			0x13fe
+			MX91_PAD_SD1_DATA3__USDHC1_DATA3			0x13fe
+			MX91_PAD_SD1_DATA4__USDHC1_DATA4			0x13fe
+			MX91_PAD_SD1_DATA5__USDHC1_DATA5			0x13fe
+			MX91_PAD_SD1_DATA6__USDHC1_DATA6			0x13fe
+			MX91_PAD_SD1_DATA7__USDHC1_DATA7			0x13fe
+			MX91_PAD_SD1_STROBE__USDHC1_STROBE			0x15fe
+		>;
+	};
+
+	pinctrl_usdhc2_gpio: usdhc2gpiogrp {
+		fsl,pins = <
+			MX91_PAD_SD2_CD_B__GPIO3_IO0				0x31e
+		>;
+		bootph-pre-ram;
+		bootph-some-ram;
+	};
+
+	pinctrl_usdhc2_gpio_sleep: usdhc2gpiosleepgrp {
+		fsl,pins = <
+			MX91_PAD_SD2_CD_B__GPIO3_IO0				0x51e
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			MX91_PAD_SD2_CLK__USDHC2_CLK				0x1582
+			MX91_PAD_SD2_CMD__USDHC2_CMD				0x1382
+			MX91_PAD_SD2_DATA0__USDHC2_DATA0			0x1382
+			MX91_PAD_SD2_DATA1__USDHC2_DATA1			0x1382
+			MX91_PAD_SD2_DATA2__USDHC2_DATA2			0x1382
+			MX91_PAD_SD2_DATA3__USDHC2_DATA3			0x1382
+			MX91_PAD_SD2_VSELECT__USDHC2_VSELECT			0x51e
+		>;
+		bootph-pre-ram;
+		bootph-some-ram;
+	};
+
+	pinctrl_usdhc2_sleep: usdhc2sleepgrp {
+		fsl,pins = <
+			MX91_PAD_SD2_CLK__GPIO3_IO1				0x51e
+			MX91_PAD_SD2_CMD__GPIO3_IO2				0x51e
+			MX91_PAD_SD2_DATA0__GPIO3_IO3				0x51e
+			MX91_PAD_SD2_DATA1__GPIO3_IO4				0x51e
+			MX91_PAD_SD2_DATA2__GPIO3_IO5				0x51e
+			MX91_PAD_SD2_DATA3__GPIO3_IO6				0x51e
+			MX91_PAD_SD2_VSELECT__GPIO3_IO19			0x51e
+		>;
+	};
+
+	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+		fsl,pins = <
+			MX91_PAD_SD2_CLK__USDHC2_CLK				0x158e
+			MX91_PAD_SD2_CMD__USDHC2_CMD				0x138e
+			MX91_PAD_SD2_DATA0__USDHC2_DATA0			0x138e
+			MX91_PAD_SD2_DATA1__USDHC2_DATA1			0x138e
+			MX91_PAD_SD2_DATA2__USDHC2_DATA2			0x138e
+			MX91_PAD_SD2_DATA3__USDHC2_DATA3			0x138e
+			MX91_PAD_SD2_VSELECT__USDHC2_VSELECT			0x51e
+		>;
+	};
+
+	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+		fsl,pins = <
+			MX91_PAD_SD2_CLK__USDHC2_CLK				0x15fe
+			MX91_PAD_SD2_CMD__USDHC2_CMD				0x13fe
+			MX91_PAD_SD2_DATA0__USDHC2_DATA0			0x13fe
+			MX91_PAD_SD2_DATA1__USDHC2_DATA1			0x13fe
+			MX91_PAD_SD2_DATA2__USDHC2_DATA2			0x13fe
+			MX91_PAD_SD2_DATA3__USDHC2_DATA3			0x13fe
+			MX91_PAD_SD2_VSELECT__USDHC2_VSELECT			0x51e
+		>;
+	};
+
+	pinctrl_usdhc3: usdhc3grp {
+		fsl,pins = <
+			MX91_PAD_SD3_CLK__USDHC3_CLK				0x1582
+			MX91_PAD_SD3_CMD__USDHC3_CMD				0x1382
+			MX91_PAD_SD3_DATA0__USDHC3_DATA0			0x1382
+			MX91_PAD_SD3_DATA1__USDHC3_DATA1			0x1382
+			MX91_PAD_SD3_DATA2__USDHC3_DATA2			0x1382
+			MX91_PAD_SD3_DATA3__USDHC3_DATA3			0x1382
+		>;
+	};
+
+	pinctrl_usdhc3_sleep: usdhc3sleepgrp {
+		fsl,pins = <
+			MX91_PAD_SD3_CLK__GPIO3_IO20				0x31e
+			MX91_PAD_SD3_CMD__GPIO3_IO21				0x31e
+			MX91_PAD_SD3_DATA0__GPIO3_IO22				0x31e
+			MX91_PAD_SD3_DATA1__GPIO3_IO23				0x31e
+			MX91_PAD_SD3_DATA2__GPIO3_IO24				0x31e
+			MX91_PAD_SD3_DATA3__GPIO3_IO25				0x31e
+		>;
+	};
+
+	pinctrl_usdhc3_wlan: usdhc3wlangrp {
+		fsl,pins = <
+			MX91_PAD_CCM_CLKO1__GPIO3_IO26				0x31e
+		>;
+	};
+
+	pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp {
+		fsl,pins = <
+			MX91_PAD_SD3_CLK__USDHC3_CLK				0x158e
+			MX91_PAD_SD3_CMD__USDHC3_CMD				0x138e
+			MX91_PAD_SD3_DATA0__USDHC3_DATA0			0x138e
+			MX91_PAD_SD3_DATA1__USDHC3_DATA1			0x138e
+			MX91_PAD_SD3_DATA2__USDHC3_DATA2			0x138e
+			MX91_PAD_SD3_DATA3__USDHC3_DATA3			0x138e
+		>;
+	};
+
+	pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp {
+		fsl,pins = <
+			MX91_PAD_SD3_CLK__USDHC3_CLK				0x15fe
+			MX91_PAD_SD3_CMD__USDHC3_CMD				0x13fe
+			MX91_PAD_SD3_DATA0__USDHC3_DATA0			0x13fe
+			MX91_PAD_SD3_DATA1__USDHC3_DATA1			0x13fe
+			MX91_PAD_SD3_DATA2__USDHC3_DATA2			0x13fe
+			MX91_PAD_SD3_DATA3__USDHC3_DATA3			0x13fe
+		>;
+	};
+};

-- 
2.34.1



From laurent.pinchart at ideasonboard.com  Thu Dec 11 18:37:49 2025
From: laurent.pinchart at ideasonboard.com (Laurent Pinchart)
Date: Fri, 12 Dec 2025 11:37:49 +0900
Subject: [PATCH v2] arm64: dts: broadcom: bcm2712: rpi-5: Add ethernet0
 alias
In-Reply-To: <CAL_JsqJg4aYGyd49UAAPBw+FGpmGxV5JkdkXp2FK_7Gt+7DLZA@mail.gmail.com>
References: <20251102111443.18206-1-laurent.pinchart@ideasonboard.com>
 <CAL_JsqJg4aYGyd49UAAPBw+FGpmGxV5JkdkXp2FK_7Gt+7DLZA@mail.gmail.com>
Message-ID: <20251212023749.GF28411@pendragon.ideasonboard.com>

Hi Rob,

On Thu, Dec 11, 2025 at 12:42:40PM -0600, Rob Herring wrote:
> On Sun, Nov 2, 2025 at 5:15?AM Laurent Pinchart wrote:
> >
> > The RP1 ethernet controller DT node contains a local-mac-address
> > property to pass the MAC address from the boot loader to the kernel. The
> > boot loader does not fill the MAC address as the ethernet0 alias is
> > missing. Add it.
> 
> My change here[1] is going to effectively revert this.

:-(

> The RP1 stuff
> needs to either be an overlay or not. We don't need both ways.
> /aliases don't work for overlays. I suppose that could be added as a
> fixup when applying. The kernel also assumes aliases are not dynamic
> and uses indexes which aren't present, so even if it did work there
> would still be problems. OTOH, if the bootloader might use the
> ethernet controller, then why would this ever be an overlay in the
> first place?
> 
> Turns out digging into RP1 stuff, it is a mess and needs reworking[2].

I don't have a strong opinion personally. As far as I understand from
https://lore.kernel.org/all/cover.1748526284.git.andrea.porta at suse.com/,
non-overlay support was added for compatibility with downstream. I don't
know why the overlay option was considered better for upstream. Andrea,
could you comment on this ?

> Right now, I just want the warning gone so I don't get further complaints[3].
> 
> Rob
> 
> [1] https://lore.kernel.org/all/20251117211503.728354-2-robh at kernel.org/
> [2] https://lore.kernel.org/all/CAL_JsqJUzB71QdMcxJtNZ7raoPcK+SfTh7EVzGmk=syo8xLKQw at mail.gmail.com/
> [3] https://lore.kernel.org/all/CAHk-=wi+ge-gtCg+iLd6dgjisGchjtsKY8AXG9tXGOxqVv8Fkw at mail.gmail.com/

-- 
Regards,

Laurent Pinchart


From cuiyunhui at bytedance.com  Thu Dec 11 19:09:40 2025
From: cuiyunhui at bytedance.com (yunhui cui)
Date: Fri, 12 Dec 2025 11:09:40 +0800
Subject: [External] Re: [PATCH v3 5/8] riscv: smp: use NMI for CPU stop
In-Reply-To: <DEULRAM55E2G.1464D4JSWL3SZ@ventanamicro.com>
References: <20251127125305.89961-1-cuiyunhui@bytedance.com>
 <20251127125305.89961-6-cuiyunhui@bytedance.com> <DEP4X1DAIOU5.2WLIV4BMWLMRR@ventanamicro.com>
 <CAEEQ3wmAn=9w=fR=OMTMF17_tAcEnsdJWL_w8fw-3wA-Bfi6xw@mail.gmail.com>
 <DEPGLFUVHA0O.XSZVD2T1ENLD@ventanamicro.com> <CAEEQ3wngwxjiytt7g6XY0bC1PL4A1NEmirML7FiqXMA4_K0irw@mail.gmail.com>
 <DEULRAM55E2G.1464D4JSWL3SZ@ventanamicro.com>
Message-ID: <CAEEQ3wmEVVHC=S795dFsQ9iM5Xkz-KOBe_CxXbvzyDBUo3wU6A@mail.gmail.com>

Hi Radim,

On Wed, Dec 10, 2025 at 10:22?PM Radim Kr?m?? <rkrcmar at ventanamicro.com> wrote:
>
> 2025-12-08T19:40:39+08:00, yunhui cui <cuiyunhui at bytedance.com>:
> > Hi Radim,
> >
> > On Thu, Dec 4, 2025 at 9:16?PM Radim Kr?m?? <rkrcmar at ventanamicro.com> wrote:
> >>
> >> 2025-12-04T13:28:45+08:00, yunhui cui <cuiyunhui at bytedance.com>:
> >> > Hi Radim,
> >> >
> >> > On Thu, Dec 4, 2025 at 12:07?PM Radim Kr?m?? <rkrcmar at ventanamicro.com> wrote:
> >> >>
> >> >> 2025-11-27T20:53:02+08:00, Yunhui Cui <cuiyunhui at bytedance.com>:
> >> >> > Use NMI instead of IPI for CPU stop if RISC-V SSE NMI is supported.
> >> >> >
> >> >> > Signed-off-by: Yunhui Cui <cuiyunhui at bytedance.com>
> >> >> > ---
> >> >> > diff --git a/drivers/firmware/riscv/riscv_sse_nmi.c b/drivers/firmware/riscv/riscv_sse_nmi.c
> >> >> > @@ -58,6 +58,7 @@ static int local_nmi_handler(u32 evt, void *arg, struct pt_regs *regs)
> >> >> >       type = atomic_read(this_cpu_ptr(&local_nmi));
> >> >> >
> >> >> >       NMI_HANDLE(LOCAL_NMI_CRASH, cpu_crash_stop, cpu, regs);
> >> >> > +     NMI_HANDLE(LOCAL_NMI_STOP, cpu_stop);
> >> >>
> >> >> Please document the intended preemption design for all SSE events,
> >> >> because it will be a nightmare if we forget some assumptions in the
> >> >> coming years.  (That includes the relative priorities of RAS/PMU/...)
> >> >
> >> > Actually, LOCAL_NMI_CRASH, LOCAL_NMI_STOP, LOCAL_NMI_BACKTRACE,
> >> > LOCAL_NMI_KGDB, ... are all implemented via the single SSE event
> >> > SBI_SSE_EVENT_LOCAL_SOFTWARE_INJECTED. Per the SSE design, no
> >> > preemption will occur among CRASH, STOP, BACKTRACE, and KGDB events.
> >>
> >> That is how it is.  I don't understand why it must be like that.
> >>
> >> For example: PMU_OVERFLOW has lower event_id than SOFTWARE_INJECTED, so
> >> it will currently interrupt NMI_CRASH as they both have priority 0,
> >> although NMI_CRASH probably shouldn't be masked by anything, and should
> >> preempt everything.
> >> NMI_BACKTRACE, on the other hand, probably shouldn't have that high
> >> priority as there seem more important events (e.g. RAS and NMI_CRASH).
> >>
> >> The issues can be avoided by event priorities, masking, or deemed as
> >> non-issue, but I think it would be beneficial to provide some reasoning
> >> behind the design, as the choices don't seem obvious to me.
> >
> > Indeed, it is necessary to consider the priority among different
> > events. Should different priorities also be assigned to NMI_CRASH,
> > NMI_BACKTRACE, NMI_STOP, and NMI_KGDB?
>
> I think it would be beneficial to document the desired behavior even if
> we can't (currently?) implement it, because like you said, SSE can't
> directly express the priority when multiplexing SOFTWARE_INJECTED.
>
> >                                        Do these operations need to be
> > visible to the BIOS?
>
> BIOS shouldn't care what lower privilege wants to do.
> SBI could define more events for software use, though.
>
> >                      Could you kindly provide some good suggestions?
>
> I think it would be good practice to explicitly set a unique priority
> when registering SSE events.  Maybe through a global priority enum, and
> make sure that all event registrations are passing a value from that
> enum.

Yes, each distinct event should have a preset priority. I noticed that
SBI_SSE_EVENT_LOCAL_PMU_OVERFLOW in Cl?ment's patchset
(https://lore.kernel.org/all/20251105082639.342973-5-cleger at rivosinc.com/)
also does not explicitly set a priority.
As you mentioned, a "global priority enum" is required. I will also
respond to Cl?ment's email.

>
> That would make sure that different events interact like we expect them
> to, but it doesn't solve the multiplexing issue of SOFTWARE_INJECTED.
>
> If we're fine with all SOFTWARE_INJECTED sub-handlers having the maximal
> priority (higher than RAS/PMU/UNKNOWN_NMI/...), then we could hope that
> lower imporance handlers (e.g. BACKTRACE) won't hang, so the higher
> importance handlers (e.g. CRASH) would eventually run.
> We're dealing with low-occurrence scenarios, so this might be "good
> enough for now"...

Currently, x86 also handles multiple local NMI events, including
BACKTRACE, via a single NMI vector. We might as well set the priority
of SOFTWARE_INJECTED to the highest.

>
> Situation would get simpler if we could avoid some sub-handlers;
> alternatively, it would get more complicated if SOFTWARE_INJECTED had
> lower priority than some other event -- we'd make CRASH partially
> recover its high priority image by masking other SSE events during its
> execution (and we'd need warding amulets against hangs and starvation).
>
> Thanks.

Thanks,
Yunhui


From xiaoshun.xu at mediatek.corp-partner.google.com  Thu Dec 11 19:13:41 2025
From: xiaoshun.xu at mediatek.corp-partner.google.com (Xiaoshun Xu)
Date: Fri, 12 Dec 2025 11:13:41 +0800
Subject: [PATCH 0/4] *** SUBJECT HERE ***
Message-ID: <20251212031450.489128-1-xiaoshun.xu@mediatek.corp-partner.google.com>


External email : Please do not click links or open attachments until you have verified the sender or the content.


From: Xiaoshun Xu <xiaoshun.xu at mediatek.com>

v1:
1. Add dt-bindings compatible and vio-idx-num attribute of MT8189
2. Add support DEVAPC of MT8189
3. Refine MT8189 DEVAPC clock control flow
4. Refine MT8189 DEVAPC interrupt handler

*** BLURB HERE ***

xiaoshun.xu (4):
  dt-bindings: soc: devapc: Add for support MT8189
  soc: mediatek: mtk-devapc: Add support for MT8189 DEVAPC
  soc: mediatek: mtk-devapc: refine DEVAPC clock control
  soc: mediatek: mtk-devapc: refine devapc interrupt handler

 .../bindings/soc/mediatek/devapc.yaml         |   6 +
 drivers/soc/mediatek/mtk-devapc.c             | 176 ++++++++++++++----
 2 files changed, 144 insertions(+), 38 deletions(-)

--
2.45.2



From xiaoshun.xu at mediatek.corp-partner.google.com  Thu Dec 11 19:13:42 2025
From: xiaoshun.xu at mediatek.corp-partner.google.com (Xiaoshun Xu)
Date: Fri, 12 Dec 2025 11:13:42 +0800
Subject: [PATCH 1/4] dt-bindings: soc: devapc: Add for support MT8189
In-Reply-To: <20251212031450.489128-1-xiaoshun.xu@mediatek.corp-partner.google.com>
References: <20251212031450.489128-1-xiaoshun.xu@mediatek.corp-partner.google.com>
Message-ID: <20251212031450.489128-2-xiaoshun.xu@mediatek.corp-partner.google.com>


External email : Please do not click links or open attachments until you have verified the sender or the content.


From: "xiaoshun.xu" <xiaoshun.xu at mediatek.com>

Add compatible and vio-idx-num attribute of MT8189

Signed-off-by: xiaoshun.xu <xiaoshun.xu at mediatek.com>
---
 Documentation/devicetree/bindings/soc/mediatek/devapc.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/soc/mediatek/devapc.yaml b/Documentation/devicetree/bindings/soc/mediatek/devapc.yaml
index 99e2caafeadf..4068786d3bb1 100644
--- a/Documentation/devicetree/bindings/soc/mediatek/devapc.yaml
+++ b/Documentation/devicetree/bindings/soc/mediatek/devapc.yaml
@@ -21,6 +21,7 @@ properties:
     enum:
       - mediatek,mt6779-devapc
       - mediatek,mt8186-devapc
+      - mediatek,mt8189-devapc

   reg:
     description: The base address of devapc register bank
@@ -30,6 +31,10 @@ properties:
     description: A single interrupt specifier
     maxItems: 1

+  vio-idx-num:
+    description: Describe the number of bus slaves controlled by devapc
+    maxItems: 1
+
   clocks:
     description: Contains module clock source and clock names
     maxItems: 1
@@ -55,6 +60,7 @@ examples:
     devapc: devapc at 10207000 {
       compatible = "mediatek,mt6779-devapc";
       reg = <0x10207000 0x1000>;
+      vio-idx-num = <132>;
       interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_LOW>;
       clocks = <&infracfg_ao CLK_INFRA_DEVICE_APC>;
       clock-names = "devapc-infra-clock";
--
2.45.2



From xiaoshun.xu at mediatek.corp-partner.google.com  Thu Dec 11 19:13:44 2025
From: xiaoshun.xu at mediatek.corp-partner.google.com (Xiaoshun Xu)
Date: Fri, 12 Dec 2025 11:13:44 +0800
Subject: [PATCH 3/4] soc: mediatek: mtk-devapc: refine DEVAPC clock control
In-Reply-To: <20251212031450.489128-1-xiaoshun.xu@mediatek.corp-partner.google.com>
References: <20251212031450.489128-1-xiaoshun.xu@mediatek.corp-partner.google.com>
Message-ID: <20251212031450.489128-4-xiaoshun.xu@mediatek.corp-partner.google.com>


External email : Please do not click links or open attachments until you have verified the sender or the content.


From: "xiaoshun.xu" <xiaoshun.xu at mediatek.com>

Because the new DEVAPC design, DEVAPC clock is controlled by
HW power domains, the control flow of DEVAPC clock is not
necessary, but to maintain compatibility with legacy ICs,
keep this part of code.

Signed-off-by: xiaoshun.xu <xiaoshun.xu at mediatek.com>
---
 drivers/soc/mediatek/mtk-devapc.c | 21 ++++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/drivers/soc/mediatek/mtk-devapc.c b/drivers/soc/mediatek/mtk-devapc.c
index 6dbec4016a24..18964d82ff08 100644
--- a/drivers/soc/mediatek/mtk-devapc.c
+++ b/drivers/soc/mediatek/mtk-devapc.c
@@ -359,16 +359,25 @@ static int mtk_devapc_probe(struct platform_device *pdev)
                goto err;
        }

-       ctx->infra_clk = devm_clk_get_enabled(&pdev->dev, "devapc-infra-clock");
+       /*
+        * The new design of DAPC clock is controlled by HW power domains,
+        * making it unnecessary to provide the clock control driver.
+        */
+       ctx->infra_clk = devm_clk_get_optional(&pdev->dev, "devapc-infra-clock");
        if (IS_ERR(ctx->infra_clk)) {
-               ret = -EINVAL;
-               goto err;
+               dev_dbg(ctx->dev, "Cannot get devapc clock from CCF\n");
+               ctx->infra_clk = NULL;
+       } else {
+               if (clk_prepare_enable(ctx->infra_clk))
+                       return -EINVAL;
        }

        ret = devm_request_irq(&pdev->dev, devapc_irq, devapc_violation_irq,
-                              IRQF_TRIGGER_NONE, "devapc", ctx);
-       if (ret)
+                              IRQF_TRIGGER_NONE | IRQF_SHARED, "devapc", ctx);
+       if (ret) {
+               clk_disable_unprepare(ctx->infra_clk);
                goto err;
+       }

        platform_set_drvdata(pdev, ctx);

@@ -387,6 +396,8 @@ static void mtk_devapc_remove(struct platform_device *pdev)

        stop_devapc(ctx);

+       clk_disable_unprepare(ctx->infra_clk);
+
        iounmap(ctx->base);
 }

--
2.45.2



From xiaoshun.xu at mediatek.corp-partner.google.com  Thu Dec 11 19:13:45 2025
From: xiaoshun.xu at mediatek.corp-partner.google.com (Xiaoshun Xu)
Date: Fri, 12 Dec 2025 11:13:45 +0800
Subject: [PATCH 4/4] soc: mediatek: mtk-devapc: refine DEVAPC irq handler
In-Reply-To: <20251212031450.489128-1-xiaoshun.xu@mediatek.corp-partner.google.com>
References: <20251212031450.489128-1-xiaoshun.xu@mediatek.corp-partner.google.com>
Message-ID: <20251212031450.489128-5-xiaoshun.xu@mediatek.corp-partner.google.com>


External email : Please do not click links or open attachments until you have verified the sender or the content.


From: "xiaoshun.xu" <xiaoshun.xu at mediatek.com>

Because the violation IRQ uses a while loop, it might cause the
system to remain in the interrupt handler indefinitely. We are
currently optimizing this part of the process to handle only 20
violations for debug violation issues, and then exit the loop

Signed-off-by: xiaoshun.xu <xiaoshun.xu at mediatek.com>
---
 drivers/soc/mediatek/mtk-devapc.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/soc/mediatek/mtk-devapc.c b/drivers/soc/mediatek/mtk-devapc.c
index 18964d82ff08..30b7ee8b880a 100644
--- a/drivers/soc/mediatek/mtk-devapc.c
+++ b/drivers/soc/mediatek/mtk-devapc.c
@@ -15,6 +15,8 @@
 #define VIO_MOD_TO_REG_IND(m)  ((m) / 32)
 #define VIO_MOD_TO_REG_OFF(m)  ((m) % 32)

+#define MAX_VIO_NUM 20
+
 struct mtk_devapc_vio_dbgs {
        union {
                u32 vio_dbg0;
@@ -234,13 +236,18 @@ static void devapc_extract_vio_dbg(struct mtk_devapc_context *ctx)
  */
 static irqreturn_t devapc_violation_irq(int irq_number, void *data)
 {
+       unsigned int vio_num = 0;
        struct mtk_devapc_context *ctx = data;

-       while (devapc_sync_vio_dbg(ctx))
+       mask_module_irq(ctx, true);
+
+       for (vio_num = 0; (vio_num < MAX_VIO_NUM) && (devapc_sync_vio_dbg(ctx)); ++vio_num)
                devapc_extract_vio_dbg(ctx);

        clear_vio_status(ctx);

+       mask_module_irq(ctx, false);
+
        return IRQ_HANDLED;
 }

--
2.45.2



From xiaoshun.xu at mediatek.corp-partner.google.com  Thu Dec 11 19:13:43 2025
From: xiaoshun.xu at mediatek.corp-partner.google.com (Xiaoshun Xu)
Date: Fri, 12 Dec 2025 11:13:43 +0800
Subject: [PATCH 2/4] soc: mediatek: mtk-devapc: Add support for MT8189 DEVAPC
In-Reply-To: <20251212031450.489128-1-xiaoshun.xu@mediatek.corp-partner.google.com>
References: <20251212031450.489128-1-xiaoshun.xu@mediatek.corp-partner.google.com>
Message-ID: <20251212031450.489128-3-xiaoshun.xu@mediatek.corp-partner.google.com>


External email : Please do not click links or open attachments until you have verified the sender or the content.


From: "xiaoshun.xu" <xiaoshun.xu at mediatek.com>

Add support for MT8189 DEVAPC, DEVAPC debug registers have new version,
so refine the structure of devapc_regs_ofs_xxxx to devapc_regs_ofs_verX,
and rename the infra_base to base in mtk_devapc_context because DEVAPC
not only access the infra_base to dump debug information when violation
happens

Signed-off-by: xiaoshun.xu <xiaoshun.xu at mediatek.com>
---
 drivers/soc/mediatek/mtk-devapc.c | 146 +++++++++++++++++++++++-------
 1 file changed, 114 insertions(+), 32 deletions(-)

diff --git a/drivers/soc/mediatek/mtk-devapc.c b/drivers/soc/mediatek/mtk-devapc.c
index f54c966138b5..6dbec4016a24 100644
--- a/drivers/soc/mediatek/mtk-devapc.c
+++ b/drivers/soc/mediatek/mtk-devapc.c
@@ -26,9 +26,19 @@ struct mtk_devapc_vio_dbgs {
                        u32 addr_h:4;
                        u32 resv:4;
                } dbg0_bits;
+
+               struct {
+                       u32 dmnid:6;
+                       u32 vio_w:1;
+                       u32 vio_r:1;
+                       u32 addr_h:4;
+                       u32 resv:20;
+               } dbg0_bits_ver2;
        };

        u32 vio_dbg1;
+       u32 vio_dbg2;
+       u32 vio_dbg3;
 };

 struct mtk_devapc_regs_ofs {
@@ -37,6 +47,8 @@ struct mtk_devapc_regs_ofs {
        u32 vio_sta_offset;
        u32 vio_dbg0_offset;
        u32 vio_dbg1_offset;
+       u32 vio_dbg2_offset;
+       u32 vio_dbg3_offset;
        u32 apc_con_offset;
        u32 vio_shift_sta_offset;
        u32 vio_shift_sel_offset;
@@ -44,16 +56,20 @@ struct mtk_devapc_regs_ofs {
 };

 struct mtk_devapc_data {
-       /* numbers of violation index */
-       u32 vio_idx_num;
+       u32 version;
+       /* Default numbers of violation index */
+       u32 default_vio_idx_num;
        const struct mtk_devapc_regs_ofs *regs_ofs;
 };

 struct mtk_devapc_context {
        struct device *dev;
-       void __iomem *infra_base;
+       void __iomem *base;
        struct clk *infra_clk;
        const struct mtk_devapc_data *data;
+
+       /* numbers of violation index */
+       u32 vio_idx_num;
 };

 static void clear_vio_status(struct mtk_devapc_context *ctx)
@@ -61,12 +77,12 @@ static void clear_vio_status(struct mtk_devapc_context *ctx)
        void __iomem *reg;
        int i;

-       reg = ctx->infra_base + ctx->data->regs_ofs->vio_sta_offset;
+       reg = ctx->base + ctx->data->regs_ofs->vio_sta_offset;

-       for (i = 0; i < VIO_MOD_TO_REG_IND(ctx->data->vio_idx_num) - 1; i++)
+       for (i = 0; i < VIO_MOD_TO_REG_IND(ctx->vio_idx_num - 1); i++)
                writel(GENMASK(31, 0), reg + 4 * i);

-       writel(GENMASK(VIO_MOD_TO_REG_OFF(ctx->data->vio_idx_num) - 1, 0),
+       writel(GENMASK(VIO_MOD_TO_REG_OFF(ctx->vio_idx_num - 1), 0),
               reg + 4 * i);
 }

@@ -76,22 +92,22 @@ static void mask_module_irq(struct mtk_devapc_context *ctx, bool mask)
        u32 val;
        int i;

-       reg = ctx->infra_base + ctx->data->regs_ofs->vio_mask_offset;
+       reg = ctx->base + ctx->data->regs_ofs->vio_mask_offset;

        if (mask)
                val = GENMASK(31, 0);
        else
                val = 0;

-       for (i = 0; i < VIO_MOD_TO_REG_IND(ctx->data->vio_idx_num) - 1; i++)
+       for (i = 0; i < VIO_MOD_TO_REG_IND(ctx->vio_idx_num - 1); i++)
                writel(val, reg + 4 * i);

        val = readl(reg + 4 * i);
        if (mask)
-               val |= GENMASK(VIO_MOD_TO_REG_OFF(ctx->data->vio_idx_num) - 1,
+               val |= GENMASK(VIO_MOD_TO_REG_OFF(ctx->vio_idx_num - 1),
                               0);
        else
-               val &= ~GENMASK(VIO_MOD_TO_REG_OFF(ctx->data->vio_idx_num) - 1,
+               val &= ~GENMASK(VIO_MOD_TO_REG_OFF(ctx->vio_idx_num - 1),
                                0);

        writel(val, reg + 4 * i);
@@ -118,11 +134,11 @@ static int devapc_sync_vio_dbg(struct mtk_devapc_context *ctx)
        int ret;
        u32 val;

-       pd_vio_shift_sta_reg = ctx->infra_base +
+       pd_vio_shift_sta_reg = ctx->base +
                               ctx->data->regs_ofs->vio_shift_sta_offset;
-       pd_vio_shift_sel_reg = ctx->infra_base +
+       pd_vio_shift_sel_reg = ctx->base +
                               ctx->data->regs_ofs->vio_shift_sel_offset;
-       pd_vio_shift_con_reg = ctx->infra_base +
+       pd_vio_shift_con_reg = ctx->base +
                               ctx->data->regs_ofs->vio_shift_con_offset;

        /* Find the minimum shift group which has violation */
@@ -163,22 +179,52 @@ static void devapc_extract_vio_dbg(struct mtk_devapc_context *ctx)
        struct mtk_devapc_vio_dbgs vio_dbgs;
        void __iomem *vio_dbg0_reg;
        void __iomem *vio_dbg1_reg;
+       void __iomem *vio_dbg2_reg;
+       void __iomem *vio_dbg3_reg;
+       u32 vio_addr_l, vio_addr_h, bus_id, domain_id;
+       u32 vio_w, vio_r;
+       u64 vio_addr;

-       vio_dbg0_reg = ctx->infra_base + ctx->data->regs_ofs->vio_dbg0_offset;
-       vio_dbg1_reg = ctx->infra_base + ctx->data->regs_ofs->vio_dbg1_offset;
+       vio_dbg0_reg = ctx->base + ctx->data->regs_ofs->vio_dbg0_offset;
+       vio_dbg1_reg = ctx->base + ctx->data->regs_ofs->vio_dbg1_offset;
+       vio_dbg2_reg = ctx->base + ctx->data->regs_ofs->vio_dbg2_offset;
+       vio_dbg3_reg = ctx->base + ctx->data->regs_ofs->vio_dbg3_offset;

        vio_dbgs.vio_dbg0 = readl(vio_dbg0_reg);
        vio_dbgs.vio_dbg1 = readl(vio_dbg1_reg);
+       if (ctx->data->version >= 2U)
+               vio_dbgs.vio_dbg2 = readl(vio_dbg2_reg);
+       if (ctx->data->version == 3U)
+               vio_dbgs.vio_dbg3 = readl(vio_dbg3_reg);
+
+       if (ctx->data->version == 1U) {
+               /* arch version 1 */
+               bus_id = vio_dbgs.dbg0_bits.mstid;
+               vio_addr = vio_dbgs.vio_dbg1;
+               domain_id = vio_dbgs.dbg0_bits.dmnid;
+               vio_w = vio_dbgs.dbg0_bits.vio_w;
+               vio_r = vio_dbgs.dbg0_bits.vio_r;
+       } else {
+               /* arch version 2 & 3 */
+               bus_id = vio_dbgs.vio_dbg1;
+
+               vio_addr_l = vio_dbgs.vio_dbg2;
+               vio_addr_h = ctx->data->version == 2U ? vio_dbgs.dbg0_bits_ver2.addr_h :
+                                                       vio_dbgs.vio_dbg3;
+               vio_addr = ((u64)vio_addr_h << 32) + vio_addr_l;
+               domain_id = vio_dbgs.dbg0_bits_ver2.dmnid;
+               vio_w = vio_dbgs.dbg0_bits_ver2.vio_w;
+               vio_r = vio_dbgs.dbg0_bits_ver2.vio_r;
+       }

        /* Print violation information */
-       if (vio_dbgs.dbg0_bits.vio_w)
+       if (vio_w)
                dev_info(ctx->dev, "Write Violation\n");
-       else if (vio_dbgs.dbg0_bits.vio_r)
+       else if (vio_r)
                dev_info(ctx->dev, "Read Violation\n");

-       dev_info(ctx->dev, "Bus ID:0x%x, Dom ID:0x%x, Vio Addr:0x%x\n",
-                vio_dbgs.dbg0_bits.mstid, vio_dbgs.dbg0_bits.dmnid,
-                vio_dbgs.vio_dbg1);
+       dev_info(ctx->dev, "Bus ID:0x%x, Dom ID:0x%x, Vio Addr:0x%llx\n",
+                bus_id, domain_id, vio_addr);
 }

 /*
@@ -203,7 +249,8 @@ static irqreturn_t devapc_violation_irq(int irq_number, void *data)
  */
 static void start_devapc(struct mtk_devapc_context *ctx)
 {
-       writel(BIT(31), ctx->infra_base + ctx->data->regs_ofs->apc_con_offset);
+
+       writel(BIT(31), ctx->base + ctx->data->regs_ofs->apc_con_offset);

        mask_module_irq(ctx, false);
 }
@@ -215,10 +262,10 @@ static void stop_devapc(struct mtk_devapc_context *ctx)
 {
        mask_module_irq(ctx, true);

-       writel(BIT(2), ctx->infra_base + ctx->data->regs_ofs->apc_con_offset);
+       writel(BIT(2), ctx->base + ctx->data->regs_ofs->apc_con_offset);
 }

-static const struct mtk_devapc_regs_ofs devapc_regs_ofs_mt6779 = {
+static const struct mtk_devapc_regs_ofs devapc_regs_ofs_ver1 = {
        .vio_mask_offset = 0x0,
        .vio_sta_offset = 0x400,
        .vio_dbg0_offset = 0x900,
@@ -229,14 +276,34 @@ static const struct mtk_devapc_regs_ofs devapc_regs_ofs_mt6779 = {
        .vio_shift_con_offset = 0xF20,
 };

+static const struct mtk_devapc_regs_ofs devapc_regs_ofs_ver2 = {
+       .vio_mask_offset = 0x0,
+       .vio_sta_offset = 0x400,
+       .vio_dbg0_offset = 0x900,
+       .vio_dbg1_offset = 0x904,
+       .vio_dbg2_offset = 0x908,
+       .vio_dbg3_offset = 0x90c,
+       .apc_con_offset = 0xF00,
+       .vio_shift_sta_offset = 0xF20,
+       .vio_shift_sel_offset = 0xF30,
+       .vio_shift_con_offset = 0xF10,
+};
+
 static const struct mtk_devapc_data devapc_mt6779 = {
-       .vio_idx_num = 511,
-       .regs_ofs = &devapc_regs_ofs_mt6779,
+       .version = 1,
+       .default_vio_idx_num = 511,
+       .regs_ofs = &devapc_regs_ofs_ver1,
 };

 static const struct mtk_devapc_data devapc_mt8186 = {
-       .vio_idx_num = 519,
-       .regs_ofs = &devapc_regs_ofs_mt6779,
+       .version = 1,
+       .default_vio_idx_num = 519,
+       .regs_ofs = &devapc_regs_ofs_ver1,
+};
+
+static const struct mtk_devapc_data devapc_mt8189 = {
+       .version = 3,
+       .regs_ofs = &devapc_regs_ofs_ver2,
 };

 static const struct of_device_id mtk_devapc_dt_match[] = {
@@ -246,6 +313,9 @@ static const struct of_device_id mtk_devapc_dt_match[] = {
        }, {
                .compatible = "mediatek,mt8186-devapc",
                .data = &devapc_mt8186,
+       }, {
+               .compatible = "mediatek,mt8189-devapc",
+               .data = &devapc_mt8189,
        }, {
        },
 };
@@ -268,10 +338,21 @@ static int mtk_devapc_probe(struct platform_device *pdev)
        ctx->data = of_device_get_match_data(&pdev->dev);
        ctx->dev = &pdev->dev;

-       ctx->infra_base = of_iomap(node, 0);
-       if (!ctx->infra_base)
+       ctx->base = of_iomap(node, 0);
+       if (!ctx->base)
                return -EINVAL;

+       /*
+        * Set effective vio_idx_num from default value.
+        * If vio_idx_num is 0, get the info from DT.
+        */
+       ctx->vio_idx_num = ctx->data->default_vio_idx_num;
+       if (ctx->vio_idx_num == 0)
+               if (of_property_read_u32(node,
+                                        "vio-idx-num",
+                                        &ctx->vio_idx_num))
+                       return -EINVAL;
+
        devapc_irq = irq_of_parse_and_map(node, 0);
        if (!devapc_irq) {
                ret = -EINVAL;
@@ -296,7 +377,7 @@ static int mtk_devapc_probe(struct platform_device *pdev)
        return 0;

 err:
-       iounmap(ctx->infra_base);
+       iounmap(ctx->base);
        return ret;
 }

@@ -305,12 +386,13 @@ static void mtk_devapc_remove(struct platform_device *pdev)
        struct mtk_devapc_context *ctx = platform_get_drvdata(pdev);

        stop_devapc(ctx);
-       iounmap(ctx->infra_base);
+
+       iounmap(ctx->base);
 }

 static struct platform_driver mtk_devapc_driver = {
        .probe = mtk_devapc_probe,
-       .remove = mtk_devapc_remove,
+       .remove_new = mtk_devapc_remove,
        .driver = {
                .name = "mtk-devapc",
                .of_match_table = mtk_devapc_dt_match,
--
2.45.2



From krzk at kernel.org  Thu Dec 11 19:16:28 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 12 Dec 2025 04:16:28 +0100
Subject: [PATCH 2/4] dt-bindings: media: mediatek-jpeg-decoder: add MT8189
 compatible string
In-Reply-To: <20251212015218.4689-3-jianhua.lin@mediatek.com>
References: <20251212015218.4689-1-jianhua.lin@mediatek.com>
 <20251212015218.4689-3-jianhua.lin@mediatek.com>
Message-ID: <a2810e51-1c59-46be-aa3a-411149001c70@kernel.org>

On 12/12/2025 02:52, Jianhua Lin wrote:
> Compared to the previous generation IC, the MT8189 uses 34-bit
> iova address-space. Therefore, add "mediatek,mt8189-jpgdec"
> compatible to the binding document.
> 
> Signed-off-by: Jianhua Lin <jianhua.lin at mediatek.com>
> ---
>  .../bindings/media/mediatek-jpeg-decoder.yaml | 46 +++++++++++++++++--
>  1 file changed, 41 insertions(+), 5 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml b/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml
> index a4aacd3eb189..935a908465c8 100644
> --- a/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml
> +++ b/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml
> @@ -19,11 +19,15 @@ properties:
>            - enum:
>                - mediatek,mt8173-jpgdec
>                - mediatek,mt2701-jpgdec
> +              - mediatek,mt8189-jpgdec
>        - items:
>            - enum:
>                - mediatek,mt7623-jpgdec
> -              - mediatek,mt8188-jpgdec

That's ABI beak completely unexplained in the commit msg.

No, please read carefully writing bindings doc before posting next DT patch.

I am not reviewing the rest.

Best regards,
Krzysztof


From cuiyunhui at bytedance.com  Thu Dec 11 19:16:57 2025
From: cuiyunhui at bytedance.com (yunhui cui)
Date: Fri, 12 Dec 2025 11:16:57 +0800
Subject: [External] [PATCH v8 4/5] perf: RISC-V: add support for SSE event
In-Reply-To: <20251105082639.342973-5-cleger@rivosinc.com>
References: <20251105082639.342973-1-cleger@rivosinc.com> <20251105082639.342973-5-cleger@rivosinc.com>
Message-ID: <CAEEQ3wnQiUdNVjUpdDgAx1=y76vSo66vCD0Wf3EGes274jnkxw@mail.gmail.com>

Hi Cl?ment,

On Wed, Nov 5, 2025 at 4:29?PM Cl?ment L?ger <cleger at rivosinc.com> wrote:
>
> In order to use SSE within PMU drivers, register a SSE handler for the
> local PMU event. Reuse the existing overflow IRQ handler and pass
> appropriate pt_regs. Add a config option RISCV_PMU_SSE to select event
> delivery via SSE events.
>
> Signed-off-by: Cl?ment L?ger <cleger at rivosinc.com>
> ---
>  drivers/perf/Kconfig           | 10 +++++
>  drivers/perf/riscv_pmu.c       | 23 +++++++++++
>  drivers/perf/riscv_pmu_sbi.c   | 71 +++++++++++++++++++++++++++++-----
>  include/linux/perf/riscv_pmu.h |  5 +++
>  4 files changed, 99 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig
> index 638321fc9800..d6ffc2b036e5 100644
> --- a/drivers/perf/Kconfig
> +++ b/drivers/perf/Kconfig
> @@ -105,6 +105,16 @@ config RISCV_PMU_SBI
>           full perf feature support i.e. counter overflow, privilege mode
>           filtering, counter configuration.
>
> +config RISCV_PMU_SBI_SSE
> +       depends on RISCV_PMU && RISCV_SBI_SSE
> +       bool "RISC-V PMU SSE events"
> +       default n
> +       help
> +         Say y if you want to use SSE events to deliver PMU interrupts. This
> +         provides a way to profile the kernel at any level by using NMI-like
> +         SSE events. SSE events being really intrusive, this option allows
> +         to select it only if needed.
> +
>  config STARFIVE_STARLINK_PMU
>         depends on ARCH_STARFIVE || COMPILE_TEST
>         depends on 64BIT
> diff --git a/drivers/perf/riscv_pmu.c b/drivers/perf/riscv_pmu.c
> index 7644147d50b4..dda2814801c0 100644
> --- a/drivers/perf/riscv_pmu.c
> +++ b/drivers/perf/riscv_pmu.c
> @@ -13,6 +13,7 @@
>  #include <linux/irqdesc.h>
>  #include <linux/perf/riscv_pmu.h>
>  #include <linux/printk.h>
> +#include <linux/riscv_sbi_sse.h>
>  #include <linux/smp.h>
>  #include <linux/sched_clock.h>
>
> @@ -254,6 +255,24 @@ void riscv_pmu_start(struct perf_event *event, int flags)
>         perf_event_update_userpage(event);
>  }
>
> +#ifdef CONFIG_RISCV_PMU_SBI_SSE
> +static void riscv_pmu_disable(struct pmu *pmu)
> +{
> +       struct riscv_pmu *rvpmu = to_riscv_pmu(pmu);
> +
> +       if (rvpmu->sse_evt)
> +               sse_event_disable_local(rvpmu->sse_evt);
> +}
> +
> +static void riscv_pmu_enable(struct pmu *pmu)
> +{
> +       struct riscv_pmu *rvpmu = to_riscv_pmu(pmu);
> +
> +       if (rvpmu->sse_evt)
> +               sse_event_enable_local(rvpmu->sse_evt);
> +}
> +#endif
> +
>  static int riscv_pmu_add(struct perf_event *event, int flags)
>  {
>         struct riscv_pmu *rvpmu = to_riscv_pmu(event->pmu);
> @@ -411,6 +430,10 @@ struct riscv_pmu *riscv_pmu_alloc(void)
>                 .event_mapped   = riscv_pmu_event_mapped,
>                 .event_unmapped = riscv_pmu_event_unmapped,
>                 .event_idx      = riscv_pmu_event_idx,
> +#ifdef CONFIG_RISCV_PMU_SBI_SSE
> +               .pmu_enable     = riscv_pmu_enable,
> +               .pmu_disable    = riscv_pmu_disable,
> +#endif
>                 .add            = riscv_pmu_add,
>                 .del            = riscv_pmu_del,
>                 .start          = riscv_pmu_start,
> diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
> index e255c1b069ec..c852f64a5022 100644
> --- a/drivers/perf/riscv_pmu_sbi.c
> +++ b/drivers/perf/riscv_pmu_sbi.c
> @@ -17,6 +17,7 @@
>  #include <linux/irqdomain.h>
>  #include <linux/of_irq.h>
>  #include <linux/of.h>
> +#include <linux/riscv_sbi_sse.h>
>  #include <linux/cpu_pm.h>
>  #include <linux/sched/clock.h>
>  #include <linux/soc/andes/irq.h>
> @@ -1038,10 +1039,10 @@ static void pmu_sbi_start_overflow_mask(struct riscv_pmu *pmu,
>                 pmu_sbi_start_ovf_ctrs_sbi(cpu_hw_evt, ctr_ovf_mask);
>  }
>
> -static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
> +static irqreturn_t pmu_sbi_ovf_handler(struct cpu_hw_events *cpu_hw_evt,
> +                                      struct pt_regs *regs, bool from_sse)
>  {
>         struct perf_sample_data data;
> -       struct pt_regs *regs;
>         struct hw_perf_event *hw_evt;
>         union sbi_pmu_ctr_info *info;
>         int lidx, hidx, fidx;
> @@ -1049,7 +1050,6 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
>         struct perf_event *event;
>         u64 overflow;
>         u64 overflowed_ctrs = 0;
> -       struct cpu_hw_events *cpu_hw_evt = dev;
>         u64 start_clock = sched_clock();
>         struct riscv_pmu_snapshot_data *sdata = cpu_hw_evt->snapshot_addr;
>
> @@ -1059,13 +1059,15 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
>         /* Firmware counter don't support overflow yet */
>         fidx = find_first_bit(cpu_hw_evt->used_hw_ctrs, RISCV_MAX_COUNTERS);
>         if (fidx == RISCV_MAX_COUNTERS) {
> -               csr_clear(CSR_SIP, BIT(riscv_pmu_irq_num));
> +               if (!from_sse)
> +                       csr_clear(CSR_SIP, BIT(riscv_pmu_irq_num));
>                 return IRQ_NONE;
>         }
>
>         event = cpu_hw_evt->events[fidx];
>         if (!event) {
> -               ALT_SBI_PMU_OVF_CLEAR_PENDING(riscv_pmu_irq_mask);
> +               if (!from_sse)
> +                       ALT_SBI_PMU_OVF_CLEAR_PENDING(riscv_pmu_irq_mask);
>                 return IRQ_NONE;
>         }
>
> @@ -1080,16 +1082,16 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
>
>         /*
>          * Overflow interrupt pending bit should only be cleared after stopping
> -        * all the counters to avoid any race condition.
> +        * all the counters to avoid any race condition. When using SSE,
> +        * interrupt is cleared when stopping counters.
>          */
> -       ALT_SBI_PMU_OVF_CLEAR_PENDING(riscv_pmu_irq_mask);
> +       if (!from_sse)
> +               ALT_SBI_PMU_OVF_CLEAR_PENDING(riscv_pmu_irq_mask);
>
>         /* No overflow bit is set */
>         if (!overflow)
>                 return IRQ_NONE;
>
> -       regs = get_irq_regs();
> -
>         for_each_set_bit(lidx, cpu_hw_evt->used_hw_ctrs, RISCV_MAX_COUNTERS) {
>                 struct perf_event *event = cpu_hw_evt->events[lidx];
>
> @@ -1145,6 +1147,51 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
>         return IRQ_HANDLED;
>  }
>
> +static irqreturn_t pmu_sbi_ovf_irq_handler(int irq, void *dev)
> +{
> +       return pmu_sbi_ovf_handler(dev, get_irq_regs(), false);
> +}
> +
> +#ifdef CONFIG_RISCV_PMU_SBI_SSE
> +static int pmu_sbi_ovf_sse_handler(u32 evt, void *arg, struct pt_regs *regs)
> +{
> +       struct cpu_hw_events __percpu *hw_events = arg;
> +       struct cpu_hw_events *hw_event = raw_cpu_ptr(hw_events);
> +
> +       pmu_sbi_ovf_handler(hw_event, regs, true);
> +
> +       return 0;
> +}
> +
> +static int pmu_sbi_setup_sse(struct riscv_pmu *pmu)
> +{
> +       int ret;
> +       struct sse_event *evt;
> +       struct cpu_hw_events __percpu *hw_events = pmu->hw_events;
> +
> +       evt = sse_event_register(SBI_SSE_EVENT_LOCAL_PMU_OVERFLOW, 0,
> +                                pmu_sbi_ovf_sse_handler, hw_events);

As Radim suggested, we had better preset a priority for different
events, such as these events and future ones:
SBI_SSE_EVENT_LOCAL_HIGH_PRIO_RAS
SBI_SSE_EVENT_LOCAL_DOUBLE_TRAP
SBI_SSE_EVENT_GLOBAL_HIGH_PRIO_RAS
SBI_SSE_EVENT_LOCAL_PMU_OVERFLOW
SBI_SSE_EVENT_LOCAL_LOW_PRIO_RAS
SBI_SSE_EVENT_GLOBAL_LOW_PRIO_RAS
SBI_SSE_EVENT_LOCAL_SOFTWARE_INJECTED
SBI_SSE_EVENT_LOCAL_UNKNOWN_NMI
SBI_SSE_EVENT_GLOBAL_SOFTWARE_INJECTED

Could you please help add a "global priority enum"?


> +       if (IS_ERR(evt))
> +               return PTR_ERR(evt);
> +
> +       ret = sse_event_enable(evt);
> +       if (ret) {
> +               sse_event_unregister(evt);
> +               return ret;
> +       }
> +
> +       pr_info("using SSE for PMU event delivery\n");
> +       pmu->sse_evt = evt;
> +
> +       return ret;
> +}
> +#else
> +static int pmu_sbi_setup_sse(struct riscv_pmu *pmu)
> +{
> +       return -EOPNOTSUPP;
> +}
> +#endif
> +
>  static int pmu_sbi_starting_cpu(unsigned int cpu, struct hlist_node *node)
>  {
>         struct riscv_pmu *pmu = hlist_entry_safe(node, struct riscv_pmu, node);
> @@ -1195,6 +1242,10 @@ static int pmu_sbi_setup_irqs(struct riscv_pmu *pmu, struct platform_device *pde
>         struct cpu_hw_events __percpu *hw_events = pmu->hw_events;
>         struct irq_domain *domain = NULL;
>
> +       ret = pmu_sbi_setup_sse(pmu);
> +       if (!ret)
> +               return 0;
> +
>         if (riscv_isa_extension_available(NULL, SSCOFPMF)) {
>                 riscv_pmu_irq_num = RV_IRQ_PMU;
>                 riscv_pmu_use_irq = true;
> @@ -1229,7 +1280,7 @@ static int pmu_sbi_setup_irqs(struct riscv_pmu *pmu, struct platform_device *pde
>                 return -ENODEV;
>         }
>
> -       ret = request_percpu_irq(riscv_pmu_irq, pmu_sbi_ovf_handler, "riscv-pmu", hw_events);
> +       ret = request_percpu_irq(riscv_pmu_irq, pmu_sbi_ovf_irq_handler, "riscv-pmu", hw_events);
>         if (ret) {
>                 pr_err("registering percpu irq failed [%d]\n", ret);
>                 return ret;
> diff --git a/include/linux/perf/riscv_pmu.h b/include/linux/perf/riscv_pmu.h
> index f82a28040594..08fdcf6baf4e 100644
> --- a/include/linux/perf/riscv_pmu.h
> +++ b/include/linux/perf/riscv_pmu.h
> @@ -28,6 +28,8 @@
>
>  #define RISCV_PMU_CONFIG1_GUEST_EVENTS 0x1
>
> +struct sse_event;
> +
>  struct cpu_hw_events {
>         /* currently enabled events */
>         int                     n_events;
> @@ -54,6 +56,9 @@ struct riscv_pmu {
>         char            *name;
>
>         irqreturn_t     (*handle_irq)(int irq_num, void *dev);
> +#ifdef CONFIG_RISCV_PMU_SBI_SSE
> +       struct sse_event *sse_evt;
> +#endif
>
>         unsigned long   cmask;
>         u64             (*ctr_read)(struct perf_event *event);
> --
> 2.43.0
>

Thanks,
Yunhui


From krzk at kernel.org  Thu Dec 11 19:18:30 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 12 Dec 2025 04:18:30 +0100
Subject: [PATCH 3/4] dt-bindings: media: mediatek-jpeg-encoder: add MT8189
 compatible string
In-Reply-To: <20251212015218.4689-4-jianhua.lin@mediatek.com>
References: <20251212015218.4689-1-jianhua.lin@mediatek.com>
 <20251212015218.4689-4-jianhua.lin@mediatek.com>
Message-ID: <9493a11e-7c4e-4c28-91c3-a896d499e151@kernel.org>

On 12/12/2025 02:52, Jianhua Lin wrote:
> Compared to the previous generation IC, the MT8189 uses 34-bit
> iova address-space. Therefore, add "mediatek,mt8189-jpgenc"
> compatible to the binding document.
> 
> Signed-off-by: Jianhua Lin <jianhua.lin at mediatek.com>
> ---
>  .../bindings/media/mediatek-jpeg-encoder.yaml | 27 ++++++++++++++-----
>  1 file changed, 20 insertions(+), 7 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml b/Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml
> index 5b15f8977f67..3044c7fc5c18 100644
> --- a/Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml
> +++ b/Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml
> @@ -14,13 +14,22 @@ description: |-
>  
>  properties:
>    compatible:
> -    items:
> -      - enum:
> -          - mediatek,mt2701-jpgenc
> -          - mediatek,mt8183-jpgenc
> -          - mediatek,mt8186-jpgenc
> -          - mediatek,mt8188-jpgenc
> -      - const: mediatek,mtk-jpgenc
> +    oneOf:
> +      - items:
> +          - enum:
> +              - mediatek,mtk-jpgenc

NAK, makes absolutely no sense. It is contradictory to the main DT
rules, expressed in writing bindings or on numerous presentations.

You cannot have generic front compatible because it expressed nothing.
Plus this is really, really not properly explained in the commit msg.

Did you receive proper internal review, before posting? Considering
absolutely poor quality patches from Mediatek, I find it as a
requirement now.

Best regards,
Krzysztof


From liujianfeng1994 at gmail.com  Thu Dec 11 19:31:57 2025
From: liujianfeng1994 at gmail.com (Jianfeng Liu)
Date: Fri, 12 Dec 2025 11:31:57 +0800
Subject: [PATCH v9 3/7] iommu: Add verisilicon IOMMU driver
In-Reply-To: <20250911155720.180465-4-benjamin.gaignard@collabora.com>
References: <20250911155720.180465-4-benjamin.gaignard@collabora.com>
Message-ID: <20251212033157.3036182-1-liujianfeng1994@gmail.com>

Hi,

On Thu, 11 Sep 2025 17:57:13 +0200, Benjamin Gaignard wrote:
>+#ifdef CONFIG_VSI_IOMMU
>+void vsi_iommu_restore_ctx(struct iommu_domain *domain);
>+#else
>+static inline void vsi_iommu_restore_ctx(struct iommu_domain *domain) {}
>+#endif

After applying this patch to v6.18, I get error when building this driver
as module:

drivers/iommu/vsi-iommu.c:541:6: error: redefinition of 'vsi_iommu_restore_ctx'
  541 | void vsi_iommu_restore_ctx(struct iommu_domain *domain)
   |      ^~~~~~~~~~~~~~~~~~~~~
In file included from drivers/iommu/vsi-iommu.c:31:
./include/linux/vsi-iommu.h:18:20: note: previous definition of 'vsi_iommu_restore_ctx' with type 'void(struct iommu_domain *)'
18 | static inline void vsi_iommu_restore_ctx(struct iommu_domain *domain) {}
   |                    ^~~~~~~~~~~~~~~~~~~~~

I have to use:
#if IS_ENABLED(CONFIG_VSI_IOMMU)
instead.

Best regards,
Jianfeng


From pasha.tatashin at soleen.com  Thu Dec 11 19:35:27 2025
From: pasha.tatashin at soleen.com (Pasha Tatashin)
Date: Fri, 12 Dec 2025 12:35:27 +0900
Subject: [PATCH v17 00/12] Support page table check on PowerPC
In-Reply-To: <20250925161726.2b34890070e6d8dcf8ad3ba9@linux-foundation.org>
References: <20250909091335.183439-1-ajd@linux.ibm.com> <336c0402c59363956d0c4eefc1b8a059e1fcc8e4.camel@linux.ibm.com>
 <20250925161726.2b34890070e6d8dcf8ad3ba9@linux-foundation.org>
Message-ID: <CA+CK2bDDZi0TR9fhAuKpxz+XJU6-rOS_iM-akU=oTb5wVoVxMQ@mail.gmail.com>

On Fri, Sep 26, 2025 at 8:17?AM Andrew Morton <akpm at linux-foundation.org> wrote:
>
> On Fri, 26 Sep 2025 08:42:35 +1000 Andrew Donnellan <ajd at linux.ibm.com> wrote:
>
> > On Tue, 2025-09-09 at 19:13 +1000, Andrew Donnellan wrote:
> > > Support page table check on all PowerPC platforms. This works by serialising
> > > assignments, reassignments and clears of page table entries at each level in
> > > order to ensure that anonymous mappings have at most one writable consumer,
> > > and likewise that file-backed mappings are not simultaneously also anonymous
> > > mappings.
> > >
> > > In order to support this infrastructure, a number of helpers or stubs must be
> > > defined or updated for all powerpc platforms. Additionally, we separate
> > > set_pte_at() and set_pte_at_unchecked(), to allow for internal, uninstrumented
> > > mappings.
> > >
> > > On some PowerPC platforms, implementing {pte,pmd,pud}_user_accessible_page()
> > > requires the address. We revert previous changes that removed the address
> > > parameter from various interfaces, and add it to some other interfaces,
> > > in order to allow this.
> > >
> > > Note that on 32 bit systems with CONFIG_KFENCE=y, you need [0] to avoid
> > > possible failures in init code (this is a code patching/static keys issue,
> > > which was discovered by a user testing this series but isn't a bug in page
> > > table check).
> > >
> > > (This series was initially written by Rohan McLure, who has left IBM and
> > > is no longer working on powerpc.)
> >
> > Is this likely to make it in in time for 6.18, or should I respin it post merge
> > window?
>
> The latter, please.

Andrew Donnelan, looks like the merge window missed again, could you
please re-send this series so we could get it into 6.20?

Thank you,
Pasha


From krzk at kernel.org  Thu Dec 11 19:37:12 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 12 Dec 2025 04:37:12 +0100
Subject: [PATCH] ARM: dts: aspeed: bletchley: Fix dt-schema warnings
In-Reply-To: <20251211080311.242771-1-chou.cosmo@gmail.com>
References: <20251211080311.242771-1-chou.cosmo@gmail.com>
Message-ID: <18848885-48a9-49b5-91d1-e832e2276f00@kernel.org>

On 11/12/2025 09:03, Cosmo Chou wrote:
> Update the device tree to fix dt-schema warnings:
> - Use generic node names for SPI, LEDs, and GPIO keys.
> - Update SPI GPIO properties to use the "-gpios" suffix.
> - Remove unused address/size cells from pca9539 nodes.
> - Use 'aspeed,int-vref-microvolt' in ADC nodes.
> - Remove unused 'aspeed,hw-timeout-ms' from i2c13.


You need to split your commit. Please see submitting patches describing
the process.

Best regards,
Krzysztof


From ajd at linux.ibm.com  Thu Dec 11 19:37:04 2025
From: ajd at linux.ibm.com (Andrew Donnellan)
Date: Fri, 12 Dec 2025 14:37:04 +1100
Subject: [PATCH v17 00/12] Support page table check on PowerPC
In-Reply-To: <CA+CK2bDDZi0TR9fhAuKpxz+XJU6-rOS_iM-akU=oTb5wVoVxMQ@mail.gmail.com>
References: <20250909091335.183439-1-ajd@linux.ibm.com>
	 <336c0402c59363956d0c4eefc1b8a059e1fcc8e4.camel@linux.ibm.com>
	 <20250925161726.2b34890070e6d8dcf8ad3ba9@linux-foundation.org>
	 <CA+CK2bDDZi0TR9fhAuKpxz+XJU6-rOS_iM-akU=oTb5wVoVxMQ@mail.gmail.com>
Message-ID: <13664f203137541ce8aba74cac3777099992e856.camel@linux.ibm.com>

On Fri, 2025-12-12 at 12:35 +0900, Pasha Tatashin wrote:
> 
> Andrew Donnelan, looks like the merge window missed again, could you
> please re-send this series so we could get it into 6.20?
> 

Yes, sorry I have been busy and I am prepping this to send in the next few days.


-- 
Andrew Donnellan    OzLabs, ADL Canberra
ajd at linux.ibm.com   IBM Australia Limited


From andrew at lunn.ch  Thu Dec 11 19:39:50 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Fri, 12 Dec 2025 04:39:50 +0100
Subject: [PATCH v2 2/2] arm64: dts: freescale: Add FRDM-IMX91 basic
 support
In-Reply-To: <20251212-imx91_frdm-v2-2-4dd6d289e81d@nxp.com>
References: <20251212-imx91_frdm-v2-0-4dd6d289e81d@nxp.com>
 <20251212-imx91_frdm-v2-2-4dd6d289e81d@nxp.com>
Message-ID: <55fa5159-768c-4785-b0ba-5553193932ab@lunn.ch>

> +&fec {
> +	phy-handle = <&ethphy2>;
> +	phy-mode = "rgmii-id";
> +	pinctrl-0 = <&pinctrl_fec>;
> +	pinctrl-1 = <&pinctrl_fec_sleep>;
> +	pinctrl-names = "default", "sleep";
> +	fsl,magic-packet;

Have you tested WoL?

	Andrew


From ruanjinjie at huawei.com  Thu Dec 11 19:49:51 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Fri, 12 Dec 2025 11:49:51 +0800
Subject: [PATCH v9 15/16] entry: Inline syscall_exit_work()
In-Reply-To: <b382cc8a-3ce9-4fb1-bc0a-a3d9796251d1@arm.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
 <20251204082123.2792067-16-ruanjinjie@huawei.com>
 <b382cc8a-3ce9-4fb1-bc0a-a3d9796251d1@arm.com>
Message-ID: <4f71fa6e-3026-7921-7da5-3c917c6e956d@huawei.com>



On 2025/12/9 21:48, Kevin Brodsky wrote:
> On 04/12/2025 09:21, Jinjie Ruan wrote:
>> After switch arm64 to Generic Entry, a new hotspot syscall_exit_work()
>> appeared because syscall_exit_work() is no longer inlined. so inline
> 
> Before this series the call to syscall_trace_exit() in el0_svc_common()
> could not be inlined, so "no longer inlined" doesn't seem to be accurate.

I think the original "syscall_trace_exit()" is on an equal footing with
new introduced syscall_exit_to_user_mode_prepare() which is now inlined.

> 
>> syscall_exit_work(), and it has 2.6% performance uplift on perf bench
>> basic syscall on kunpeng920 as below.
> 
> That seems strange. syscall_exit_work() is only called if some flag in
> SYSCALL_WORK_EXIT is set, which means that we're doing something special
> like tracing. That shouldn't be the case when running a simple perf
> bench syscall.
> 
> Also worth nothing that its counterpart (syscall_trace_enter())) is not
> currently inlined, the asymmetry would have to be justified.

Will check the "syscall_trace_enter" inline performance impact.

> 
>>     | Metric     | W/O this patch | With this patch | Change    |
>>     | ---------- | -------------- | --------------- | --------- |
>>     | Total time | 2.171 [sec]    | 2.114 [sec]     |  ?2.6%    |
>>     | usecs/op   | 0.217192       | 0.211453        |  ?2.6%    |
>>     | ops/sec    | 4,604,225      | 4,729,178       |  ?2.7%    |
>>
>> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
>> ---
>>  include/linux/entry-common.h  | 63 ++++++++++++++++++++++++++++++++++-
>>  kernel/entry/syscall-common.c | 59 ++------------------------------
> 
> These changes are purely generic, surely all architectures using
> GENERIC_ENTRY should get similar benefits (assuming LTO isn't used)?

It would be great if someone could help test the performance differences.

> 
>>  2 files changed, 64 insertions(+), 58 deletions(-)
>>
>> diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h
>> index cd6dacb2d8bf..2f84377fb016 100644
>> --- a/include/linux/entry-common.h
>> +++ b/include/linux/entry-common.h
>> @@ -2,6 +2,7 @@
>>  #ifndef __LINUX_ENTRYCOMMON_H
>>  #define __LINUX_ENTRYCOMMON_H
>>  
>> +#include <linux/audit.h>
>>  #include <linux/irq-entry-common.h>
>>  #include <linux/ptrace.h>
>>  #include <linux/seccomp.h>
>> @@ -128,6 +129,41 @@ static __always_inline long syscall_enter_from_user_mode(struct pt_regs *regs, l
>>  	return ret;
>>  }
>>  
>> +/*
>> + * If SYSCALL_EMU is set, then the only reason to report is when
>> + * SINGLESTEP is set (i.e. PTRACE_SYSEMU_SINGLESTEP).  This syscall
>> + * instruction has been already reported in syscall_enter_from_user_mode().
>> + */
>> +static __always_inline bool report_single_step(unsigned long work)
>> +{
>> +	if (work & SYSCALL_WORK_SYSCALL_EMU)
>> +		return false;
>> +
>> +	return work & SYSCALL_WORK_SYSCALL_EXIT_TRAP;
>> +}
>> +
>> +/**
>> + * arch_ptrace_report_syscall_exit - Architecture specific
>> + *				     ptrace_report_syscall_exit.
>> + *
>> + * Invoked from syscall_exit_work() to wrap ptrace_report_syscall_exit().
>> + *
>> + * The main purpose is to support arch-specific ptrace_report_syscall_exit
>> + * implementation.
>> + */
>> +static __always_inline void arch_ptrace_report_syscall_exit(struct pt_regs *regs,
>> +							    int step);
>> +
>> +#ifndef arch_ptrace_report_syscall_exit
>> +static __always_inline void arch_ptrace_report_syscall_exit(struct pt_regs *regs,
>> +							    int step)
>> +{
>> +	ptrace_report_syscall_exit(regs, step);
>> +}
>> +#endif
> 
> If we want syscall_exit_work() to be inline, then why would we define
> this hook in syscall-common.c in patch 12? Might as well define both
> hooks in entry-common.h right away and avoid some noise here.

Make sense.

> 
> - Kevin
> 
>> [...]
> 


From mani at kernel.org  Thu Dec 11 19:52:35 2025
From: mani at kernel.org (Manivannan Sadhasivam)
Date: Fri, 12 Dec 2025 12:52:35 +0900
Subject: [PATCH v2] PCI: dwc: Make Link Up IRQ logic handle already
 powered on PCIe switches
In-Reply-To: <aTe1bA7lcVzFD5L7@dhcp-10-89-81-223>
References: <20251201063634.4115762-2-cassel@kernel.org>
 <f1059d5d-3fa5-423a-8093-0e99b65d5f4c@oss.qualcomm.com>
 <aTev28wihes6iJqs@dhcp-10-89-81-223>
 <dad4957c-ca13-4742-b46d-03f0478911d5@oss.qualcomm.com>
 <aTe1bA7lcVzFD5L7@dhcp-10-89-81-223>
Message-ID: <pjn2gs43rqbe3odh6zvh4qaftxxl6qvdzpm6pgpadxeeid42ko@4a2qradscaqd>

On Tue, Dec 09, 2025 at 02:36:44PM +0900, Niklas Cassel wrote:
> On Tue, Dec 09, 2025 at 10:57:18AM +0530, Krishna Chaitanya Chundru wrote:
> > On 12/9/2025 10:42 AM, Niklas Cassel wrote:
> > > 
> > > So I don't really understand your concern with this series, at least not if
> > > it goes on top of your series:
> > > https://lore.kernel.org/linux-pci/20251124-pci-pwrctrl-rework-v1-0-78a72627683d at oss.qualcomm.com/
> > Hi Niklas,
> > 
> > If this series goes on top of the our series i.e pwrctrl rework series, I
> > don't have any concerns.
> > My only concern is link up IRQ never fires if this patch goes before series.
> > 
> > - Krishna Chaitanya.
> 
> This patch missed the v6.19 merge window (and so did the pwrctrl rework
> series), so as long as Mani queues up both for v6.20 (with the pwrctrl
> rework series getting applied first), I think we are good.
> 

The plan is to merge pwrctrl series to v6.20 (unless we get strong objections),
but once that happens, Qcom doesn't need this patch.

So it'd be good if you can just limit this patch to just Rockchip. Then once the
Rockchip also moves to pwrctrl, we can revert this patch (also the whole IRQ
based link up since the Root Port is not hotplug capable).

- Mani

-- 
????????? ????????


From ruanjinjie at huawei.com  Thu Dec 11 20:00:42 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Fri, 12 Dec 2025 12:00:42 +0800
Subject: [PATCH v9 03/16] arm64/ptrace: Return early for
 ptrace_report_syscall_entry() error
In-Reply-To: <52f63e40-541f-4ed8-9d05-626eab4b39cb@arm.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
 <20251204082123.2792067-4-ruanjinjie@huawei.com>
 <52f63e40-541f-4ed8-9d05-626eab4b39cb@arm.com>
Message-ID: <051fe45b-f158-85be-3f8e-60c830fb47a2@huawei.com>



On 2025/12/9 21:46, Kevin Brodsky wrote:
> On 04/12/2025 09:21, Jinjie Ruan wrote:
>> The generic entry abort the syscall_trace_enter() sequence if
>> ptrace_report_syscall_entry() errors out, but arm64 not.
>>
>> As the ptrace_report_syscall_entry() comment said, the calling arch code
>> should abort the system call and must prevent normal entry so no system
>> call is made if ptrace_report_syscall_entry() return nonzero.
> 
> This patch is now in the right position, which means that arm64 does
> abort the syscall already without this patch. What we're changing here
> is that the tracing sequence is interrupted. The comment you're
> referring to says nothing about tracing so I'm not sure it helps to
> refer to it.

I think ?must prevent normal entry ?means When ptrace requests
interception, all subsequent processing, including audit and seccomp,
should completely bypassed.

> 
> Otherwise:
> 
> Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
> 
>> In preparation for moving arm64 over to the generic entry code,
>> return early if ptrace_report_syscall_entry() encounters an error.
>>
>> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
>> ---
>>  arch/arm64/kernel/ptrace.c | 14 +++++++++-----
>>  1 file changed, 9 insertions(+), 5 deletions(-)
>>
>> diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
>> index 4532e9831856..3926ce6aa268 100644
>> --- a/arch/arm64/kernel/ptrace.c
>> +++ b/arch/arm64/kernel/ptrace.c
>> @@ -2346,15 +2346,18 @@ static __always_inline unsigned long ptrace_save_reg(struct pt_regs *regs,
>>  	return saved_reg;
>>  }
>>  
>> -static void report_syscall_entry(struct pt_regs *regs)
>> +static int report_syscall_entry(struct pt_regs *regs)
>>  {
>>  	unsigned long saved_reg;
>> -	int regno;
>> +	int regno, ret;
>>  
>>  	saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_ENTER, &regno);
>> -	if (ptrace_report_syscall_entry(regs))
>> +	ret = ptrace_report_syscall_entry(regs);
>> +	if (ret)
>>  		forget_syscall(regs);
>>  	regs->regs[regno] = saved_reg;
>> +
>> +	return ret;
>>  }
>>  
>>  static void report_syscall_exit(struct pt_regs *regs)
>> @@ -2381,10 +2384,11 @@ static void report_syscall_exit(struct pt_regs *regs)
>>  int syscall_trace_enter(struct pt_regs *regs)
>>  {
>>  	unsigned long flags = read_thread_flags();
>> +	int ret;
>>  
>>  	if (flags & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE)) {
>> -		report_syscall_entry(regs);
>> -		if (flags & _TIF_SYSCALL_EMU)
>> +		ret = report_syscall_entry(regs);
>> +		if (ret || (flags & _TIF_SYSCALL_EMU))
>>  			return NO_SYSCALL;
>>  	}
>>  
> 


From dev.jain at arm.com  Thu Dec 11 20:26:59 2025
From: dev.jain at arm.com (Dev Jain)
Date: Fri, 12 Dec 2025 09:56:59 +0530
Subject: [RESEND RFC PATCH 0/2] Enable vmalloc huge mappings by default on arm64
Message-ID: <20251212042701.71993-1-dev.jain@arm.com>

In the quest for reducing TLB pressure via block mappings, enable huge
vmalloc by default on arm64 for BBML2-noabort systems which support kernel
live mapping split.

This series is an RFC, because I cannot get a performance improvement for
the usual benchmarks which we have. Currently, vmalloc follows an opt-in
approach for block mappings - the users calling vmalloc_huge() are the ones
which expect the most advantage from block mappings. Most users of
vmalloc(), kvmalloc() and kvzalloc() map a single page. After applying this
series, it is expected that a considerable number of users will produce
cont mappings, and probably none will produce PMD mappings.

I am asking for help from the community in testing - I believe that one of
the testing methods is xfstests: a lot of code uses the APIs mentioned
above. I am hoping that someone can jump in and run at least xfstests, and
probably some other tests which can take advantage of the reduced TLB
pressure from vmalloc cont mappings.

---
Patchset applies on Linus' master (d358e5254674).

Dev Jain (2):
  mm/vmalloc: Do not align size to huge size
  arm64/mm: Enable huge-vmalloc by default

 arch/arm64/include/asm/vmalloc.h |  6 +++++
 arch/arm64/mm/pageattr.c         |  4 +--
 include/linux/vmalloc.h          |  7 ++++++
 mm/vmalloc.c                     | 43 +++++++++++++++++++++++++-------
 4 files changed, 48 insertions(+), 12 deletions(-)

-- 
2.30.2



From dev.jain at arm.com  Thu Dec 11 20:27:00 2025
From: dev.jain at arm.com (Dev Jain)
Date: Fri, 12 Dec 2025 09:57:00 +0530
Subject: [RESEND RFC PATCH 1/2] mm/vmalloc: Do not align size to huge size
In-Reply-To: <20251212042701.71993-1-dev.jain@arm.com>
References: <20251212042701.71993-1-dev.jain@arm.com>
Message-ID: <20251212042701.71993-2-dev.jain@arm.com>

vmalloc() consists of the following:

(1) find empty space in the vmalloc space -> (2) get physical pages from
the buddy system -> (3) map the pages into the pagetable.

It turns out that the cost of (1) and (3) is pretty insignificant. Hence,
the cost of vmalloc becomes highly sensitive to physical memory allocation
time.

Currently, if we decide to use huge mappings, apart from aligning the start
of the target vm_struct region to the huge-alignment, we also align the
size. This does not seem to produce any benefit (apart from simplification
of the code), and there is a clear disadvantage - as mentioned above, the
main cost of vmalloc comes from its interaction with the buddy system, and
thus requesting more memory than was requested by the caller is suboptimal
and unnecessary.

This change is also motivated due to the next patch ("arm64/mm: Enable
vmalloc-huge by default"). Suppose that some user of vmalloc maps 17 pages,
uses that mapping for an extremely short time, and vfree's it. That patch,
without this patch, on arm64 will ultimately map 16 * 2 = 32 pages in a
contiguous way. Since the mapping is used for a very short time, it is
likely that the extra cost of mapping 15 pages defeats any benefit from
reduced TLB pressure, and regresses that code path. 

Signed-off-by: Dev Jain <dev.jain at arm.com>
---
 mm/vmalloc.c | 38 ++++++++++++++++++++++++++++++--------
 1 file changed, 30 insertions(+), 8 deletions(-)

diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index ecbac900c35f..389225a6f7ef 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -654,7 +654,7 @@ static int vmap_small_pages_range_noflush(unsigned long addr, unsigned long end,
 int __vmap_pages_range_noflush(unsigned long addr, unsigned long end,
 		pgprot_t prot, struct page **pages, unsigned int page_shift)
 {
-	unsigned int i, nr = (end - addr) >> PAGE_SHIFT;
+	unsigned int i, step, nr = (end - addr) >> PAGE_SHIFT;
 
 	WARN_ON(page_shift < PAGE_SHIFT);
 
@@ -662,7 +662,8 @@ int __vmap_pages_range_noflush(unsigned long addr, unsigned long end,
 			page_shift == PAGE_SHIFT)
 		return vmap_small_pages_range_noflush(addr, end, prot, pages);
 
-	for (i = 0; i < nr; i += 1U << (page_shift - PAGE_SHIFT)) {
+	step = 1U << (page_shift - PAGE_SHIFT);
+	for (i = 0; i < ALIGN_DOWN(nr, step); i += step) {
 		int err;
 
 		err = vmap_range_noflush(addr, addr + (1UL << page_shift),
@@ -673,8 +674,9 @@ int __vmap_pages_range_noflush(unsigned long addr, unsigned long end,
 
 		addr += 1UL << page_shift;
 	}
-
-	return 0;
+	if (IS_ALIGNED(nr, step))
+		return 0;
+	return vmap_small_pages_range_noflush(addr, end, prot, pages + i);
 }
 
 int vmap_pages_range_noflush(unsigned long addr, unsigned long end,
@@ -3197,7 +3199,7 @@ struct vm_struct *__get_vm_area_node(unsigned long size,
 	unsigned long requested_size = size;
 
 	BUG_ON(in_interrupt());
-	size = ALIGN(size, 1ul << shift);
+	size = PAGE_ALIGN(size);
 	if (unlikely(!size))
 		return NULL;
 
@@ -3353,7 +3355,7 @@ static void vm_reset_perms(struct vm_struct *area)
 	 * Find the start and end range of the direct mappings to make sure that
 	 * the vm_unmap_aliases() flush includes the direct map.
 	 */
-	for (i = 0; i < area->nr_pages; i += 1U << page_order) {
+	for (i = 0; i < ALIGN_DOWN(area->nr_pages, 1U << page_order); i += (1U << page_order)) {
 		unsigned long addr = (unsigned long)page_address(area->pages[i]);
 
 		if (addr) {
@@ -3365,6 +3367,18 @@ static void vm_reset_perms(struct vm_struct *area)
 			flush_dmap = 1;
 		}
 	}
+	for (; i < area->nr_pages; ++i) {
+		unsigned long addr = (unsigned long)page_address(area->pages[i]);
+
+		if (addr) {
+			unsigned long page_size;
+
+			page_size = PAGE_SIZE;
+			start = min(addr, start);
+			end = max(addr + page_size, end);
+			flush_dmap = 1;
+		}
+	}
 
 	/*
 	 * Set direct map to something invalid so that it won't be cached if
@@ -3673,6 +3687,7 @@ vm_area_alloc_pages(gfp_t gfp, int nid,
 	 * more permissive.
 	 */
 	if (!order) {
+single_page:
 		while (nr_allocated < nr_pages) {
 			unsigned int nr, nr_pages_request;
 
@@ -3704,13 +3719,18 @@ vm_area_alloc_pages(gfp_t gfp, int nid,
 			 * If zero or pages were obtained partly,
 			 * fallback to a single page allocator.
 			 */
-			if (nr != nr_pages_request)
+			if (nr != nr_pages_request) {
+				order = 0;
 				break;
+			}
 		}
 	}
 
 	/* High-order pages or fallback path if "bulk" fails. */
 	while (nr_allocated < nr_pages) {
+		if (nr_pages - nr_allocated < (1UL << order)) {
+			goto single_page;
+		}
 		if (!(gfp & __GFP_NOFAIL) && fatal_signal_pending(current))
 			break;
 
@@ -5179,7 +5199,9 @@ static void show_numa_info(struct seq_file *m, struct vm_struct *v,
 
 	memset(counters, 0, nr_node_ids * sizeof(unsigned int));
 
-	for (nr = 0; nr < v->nr_pages; nr += step)
+	for (nr = 0; nr < ALIGN_DOWN(v->nr_pages, step); nr += step)
+		counters[page_to_nid(v->pages[nr])] += step;
+	for (; nr < v->nr_pages; ++nr)
 		counters[page_to_nid(v->pages[nr])] += step;
 	for_each_node_state(nr, N_HIGH_MEMORY)
 		if (counters[nr])
-- 
2.30.2



From dev.jain at arm.com  Thu Dec 11 20:27:01 2025
From: dev.jain at arm.com (Dev Jain)
Date: Fri, 12 Dec 2025 09:57:01 +0530
Subject: [RESEND RFC PATCH 2/2] arm64/mm: Enable huge-vmalloc by default
In-Reply-To: <20251212042701.71993-1-dev.jain@arm.com>
References: <20251212042701.71993-1-dev.jain@arm.com>
Message-ID: <20251212042701.71993-3-dev.jain@arm.com>

For BBML2-noabort arm64 systems, enable vmalloc cont mappings and PMD
mappings by default.

There is benefit to be gained in any code path which maps >= 16 pages using
vmalloc, since any usage of that mapping will now come with reduced TLB
pressure.

Currently, I am not being able to produce a reliable statistically
significant improvement for the benchmarks which we have. I am optimistic
that xfs benchmarks should give some benefit.

Upon running test_vmalloc.sh, this series produces an optimization and
some regressions. I conclude that we should ignore the results of this
testsuite. I explain the regression in the long_busy_list_alloc_test below:
upon running ./test_vmalloc.sh run_test_mask=4 nr_threads=1, a regression
of approx 17% is observed (which increases to 31% if we do *not* apply the
previous patch ("mm/vmalloc: Do not align size to huge size")).

The long_busy_list_alloc_test first maps a lot of single pages to fragment
the vmalloc space. Then, it does the following in a loop: map 100 pages,
map a single page, then vfree both of them. My investigation reveals that
the majority of time is *not* spent in finding a free space in the vmalloc
region (which is exactly the time which the setup of this particular
test wants to increase), but in the interaction with the physical memory
allocator.

It turns out that mapping 100 pages in a contiguous way is *faster* than
bulk mapping 100 single pages. The regression is actually carried by
vfree(). When we contpte map 100 pages, we get 6 * 16 = 96 pages from
the free lists of the buddy allocator, and not the pcp lists. Then, vmalloc
subsystem splits this page into individual pages because drivers can
operate on individual pages, messing up the refcounts. As a result, vfree
frees these pages as single 4k pages, freeing them into the pcp lists.
Thus, now we have got a behaviour of taking from the freelists of the
buddy, and freeing into the pcp lists, which forces pcp draining into the
freelists. By playing with the following code in mm/page_alloc.c:

	high = nr_pcp_high(pcp, zone, batch, free_high);
	if (pcp->count < high)
		return;
The time taken by the test is highly sensitive to the value returned by
nr_pcp_high (although, increasing the value of high does not reduce the
regression).

Summarizing, the regression is due to messing up the state of the buddy
system by rapidly stealing from the freelists and not giving back to them.

If we insert an msleep(1) just before we vfree() both the regions, the
regression reduces. If we reduce the number of iterations in the test, the
regression is gone. This proves that the regression is due to the unnatural
behaviour of the test - it allocates memory, does absolutely nothing with
that memory, and releases it. No workload is expected to map memory without
actually utilizing it for some time. The time between vmalloc() and vfree()
will give time for the buddy to stabilize, and the regression is
eliminated.

The optimization is observed in fix_size_alloc_test with nr_pages = 512,
because both vmalloc() and vfree() will now operate to and from the pcp.

Signed-off-by: Dev Jain <dev.jain at arm.com>
---
 arch/arm64/include/asm/vmalloc.h | 6 ++++++
 arch/arm64/mm/pageattr.c         | 4 +---
 include/linux/vmalloc.h          | 7 +++++++
 mm/vmalloc.c                     | 5 ++++-
 4 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/include/asm/vmalloc.h b/arch/arm64/include/asm/vmalloc.h
index 4ec1acd3c1b3..c72ae9bd7360 100644
--- a/arch/arm64/include/asm/vmalloc.h
+++ b/arch/arm64/include/asm/vmalloc.h
@@ -6,6 +6,12 @@
 
 #ifdef CONFIG_HAVE_ARCH_HUGE_VMAP
 
+#define arch_wants_vmalloc_huge_always arch_wants_vmalloc_huge_always
+static inline bool arch_wants_vmalloc_huge_always(void)
+{
+	return system_supports_bbml2_noabort();
+}
+
 #define arch_vmap_pud_supported arch_vmap_pud_supported
 static inline bool arch_vmap_pud_supported(pgprot_t prot)
 {
diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c
index f0e784b963e6..eddbc202ffdd 100644
--- a/arch/arm64/mm/pageattr.c
+++ b/arch/arm64/mm/pageattr.c
@@ -163,8 +163,6 @@ static int change_memory_common(unsigned long addr, int numpages,
 	 * we are operating on does not result in such splitting.
 	 *
 	 * Let's restrict ourselves to mappings created by vmalloc (or vmap).
-	 * Disallow VM_ALLOW_HUGE_VMAP mappings to guarantee that only page
-	 * mappings are updated and splitting is never needed.
 	 *
 	 * So check whether the [addr, addr + size) interval is entirely
 	 * covered by precisely one VM area that has the VM_ALLOC flag set.
@@ -172,7 +170,7 @@ static int change_memory_common(unsigned long addr, int numpages,
 	area = find_vm_area((void *)addr);
 	if (!area ||
 	    end > (unsigned long)kasan_reset_tag(area->addr) + area->size ||
-	    ((area->flags & (VM_ALLOC | VM_ALLOW_HUGE_VMAP)) != VM_ALLOC))
+	    ((area->flags & VM_ALLOC) != VM_ALLOC))
 		return -EINVAL;
 
 	if (!numpages)
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index e8e94f90d686..59bd6ce96706 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -88,6 +88,13 @@ struct vmap_area {
 	unsigned long flags; /* mark type of vm_map_ram area */
 };
 
+#ifndef arch_wants_vmalloc_huge_always
+static inline bool arch_wants_vmalloc_huge_always(void)
+{
+	return false;
+}
+#endif
+
 /* archs that select HAVE_ARCH_HUGE_VMAP should override one or more of these */
 #ifndef arch_vmap_p4d_supported
 static inline bool arch_vmap_p4d_supported(pgprot_t prot)
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 389225a6f7ef..88004e803adc 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -4011,7 +4011,7 @@ void *__vmalloc_node_range_noprof(unsigned long size, unsigned long align,
 		return NULL;
 	}
 
-	if (vmap_allow_huge && (vm_flags & VM_ALLOW_HUGE_VMAP)) {
+	if (vmap_allow_huge && ((arch_wants_vmalloc_huge_always()) || (vm_flags & VM_ALLOW_HUGE_VMAP))) {
 		/*
 		 * Try huge pages. Only try for PAGE_KERNEL allocations,
 		 * others like modules don't yet expect huge pages in
@@ -4025,6 +4025,9 @@ void *__vmalloc_node_range_noprof(unsigned long size, unsigned long align,
 			shift = arch_vmap_pte_supported_shift(size);
 
 		align = max(original_align, 1UL << shift);
+
+		/* If arch wants huge by default, set flag unconditionally */
+		vm_flags |= VM_ALLOW_HUGE_VMAP;
 	}
 
 again:
-- 
2.30.2



From gshan at redhat.com  Thu Dec 11 20:27:08 2025
From: gshan at redhat.com (Gavin Shan)
Date: Fri, 12 Dec 2025 14:27:08 +1000
Subject: [RFC PATCH 16/38] arm_mpam: resctrl: Add support for 'MB'
 resource
In-Reply-To: <20251205215901.17772-17-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-17-james.morse@arm.com>
Message-ID: <6d257a70-d27f-4741-8fa5-fa765fa10643@redhat.com>

Hi James and Ben,

On 12/6/25 7:58 AM, James Morse wrote:
> resctrl supports 'MB', as a percentage throttling of traffic somewhere
> after the L3. This is the control that mba_sc uses, so ideally the
> class chosen should be as close as possible to the counters used for
> mba_local.
> 
> MB's percentage control should be backed either with the fixed point
> fraction MBW_MAX. The bandwidth portion bitmaps is not used as its
> tricky to pick which bits to use to avoid contention, and may be
> possible to expose this as something other than a percentage in the
> future.
> 
> CC: Zeng Heng <zengheng4 at huawei.com>
> Co-developed-by: Dave Martin <Dave.Martin at arm.com>
> Signed-off-by: Dave Martin <Dave.Martin at arm.com>
> Signed-off-by: James Morse <james.morse at arm.com>>
> ---
>   drivers/resctrl/mpam_resctrl.c | 212 ++++++++++++++++++++++++++++++++-
>   1 file changed, 211 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
> index 55576d0caf12..b9f3f00d8cad 100644
> --- a/drivers/resctrl/mpam_resctrl.c
> +++ b/drivers/resctrl/mpam_resctrl.c
> @@ -247,6 +247,33 @@ static bool cache_has_usable_cpor(struct mpam_class *class)
>   	return (class->props.cpbm_wd <= 32);
>   }
>   
> +static bool mba_class_use_mbw_max(struct mpam_props *cprops)
> +{
> +	return (mpam_has_feature(mpam_feat_mbw_max, cprops) &&
> +		cprops->bwa_wd);
> +}
> +
> +static bool class_has_usable_mba(struct mpam_props *cprops)
> +{
> +	return mba_class_use_mbw_max(cprops);
> +}
> +
> +/*
> + * Calculate the worst-case percentage change from each implemented step
> + * in the control.
> + */
> +static u32 get_mba_granularity(struct mpam_props *cprops)
> +{
> +	if (!mba_class_use_mbw_max(cprops))
> +		return 0;
> +
> +	/*
> +	 * bwa_wd is the number of bits implemented in the 0.xxx
> +	 * fixed point fraction. 1 bit is 50%, 2 is 25% etc.
> +	 */
> +	return DIV_ROUND_UP(MAX_MBA_BW, 1 << cprops->bwa_wd);
> +}
> +
>   /*
>    * Each fixed-point hardware value architecturally represents a range
>    * of values: the full range 0% - 100% is split contiguously into
> @@ -287,6 +314,96 @@ static u16 percent_to_mbw_max(u8 pc, struct mpam_props *cprops)
>   	return val;
>   }
>   
> +static u32 get_mba_min(struct mpam_props *cprops)
> +{
> +	u32 val = 0;
> +
> +	if (mba_class_use_mbw_max(cprops))
> +		val = mbw_max_to_percent(val, cprops);
> +	else
> +		WARN_ON_ONCE(1);
> +
> +	return val;
> +}
> +
> +/* Find the L3 cache that has affinity with this CPU */
> +static int find_l3_equivalent_bitmask(int cpu, cpumask_var_t tmp_cpumask)
> +{
> +	u32 cache_id = get_cpu_cacheinfo_id(cpu, 3);
> +
> +	lockdep_assert_cpus_held();
> +
> +	return mpam_get_cpumask_from_cache_id(cache_id, 3, tmp_cpumask);
> +}
> +
> +/*
> + * topology_matches_l3() - Is the provided class the same shape as L3
> + * @victim:		The class we'd like to pretend is L3.
> + *
> + * resctrl expects all the world's a Xeon, and all counters are on the
> + * L3. We play fast and loose with this, mapping counters on other
> + * classes - provided the CPU->domain mapping is the same kind of shape.
> + *
> + * Using cacheinfo directly would make this work even if resctrl can't
> + * use the L3 - but cacheinfo can't tell us anything about offline CPUs.
> + * Using the L3 resctrl domain list also depends on CPUs being online.
> + * Using the mpam_class we picked for L3 so we can use its domain list
> + * assumes that there are MPAM controls on the L3.
> + * Instead, this path eventually uses the mpam_get_cpumask_from_cache_id()
> + * helper which can tell us about offline CPUs ... but getting the cache_id
> + * to start with relies on at least one CPU per L3 cache being online at
> + * boot.
> + *
> + * Walk the victim component list and compare the affinity mask with the
> + * corresponding L3. The topology matches if each victim:component's affinity
> + * mask is the same as the CPU's corresponding L3's. These lists/masks are
> + * computed from firmware tables so don't change at runtime.
> + */
> +static bool topology_matches_l3(struct mpam_class *victim)
> +{
> +	int cpu, err;
> +	struct mpam_component *victim_iter;
> +	cpumask_var_t __free(free_cpumask_var) tmp_cpumask;
> +
> +	if (!alloc_cpumask_var(&tmp_cpumask, GFP_KERNEL))
> +		return false;
> +
> +	guard(srcu)(&mpam_srcu);
> +	list_for_each_entry_srcu(victim_iter, &victim->components, class_list,
> +				 srcu_read_lock_held(&mpam_srcu)) {
> +		if (cpumask_empty(&victim_iter->affinity)) {
> +			pr_debug("class %u has CPU-less component %u - can't match L3!\n",
> +				 victim->level, victim_iter->comp_id);
> +			return false;
> +		}
> +
> +		cpu = cpumask_any(&victim_iter->affinity);
> +		if (WARN_ON_ONCE(cpu >= nr_cpu_ids))
> +			return false;
> +
> +		cpumask_clear(tmp_cpumask);
> +		err = find_l3_equivalent_bitmask(cpu, tmp_cpumask);
> +		if (err) {
> +			pr_debug("Failed to find L3's equivalent component to class %u component %u\n",
> +				 victim->level, victim_iter->comp_id);
> +			return false;
> +		}
> +
> +		/* Any differing bits in the affinity mask? */
> +		if (!cpumask_equal(tmp_cpumask, &victim_iter->affinity)) {
> +			pr_debug("class %u component %u has Mismatched CPU mask with L3 equivalent\n"
> +				 "L3:%*pbl != victim:%*pbl\n",
> +				 victim->level, victim_iter->comp_id,
> +				 cpumask_pr_args(tmp_cpumask),
> +				 cpumask_pr_args(&victim_iter->affinity));
> +
> +			return false;
> +		}
> +	}
> +
> +	return true;
> +}
> +
>   /* Test whether we can export MPAM_CLASS_CACHE:{2,3}? */
>   static void mpam_resctrl_pick_caches(void)
>   {
> @@ -330,10 +447,63 @@ static void mpam_resctrl_pick_caches(void)
>   	}
>   }
>   
> +static void mpam_resctrl_pick_mba(void)
> +{
> +	struct mpam_class *class, *candidate_class = NULL;
> +	struct mpam_resctrl_res *res;
> +
> +	lockdep_assert_cpus_held();
> +
> +	guard(srcu)(&mpam_srcu);
> +	list_for_each_entry_srcu(class, &mpam_classes, classes_list,
> +				 srcu_read_lock_held(&mpam_srcu)) {
> +		struct mpam_props *cprops = &class->props;
> +
> +		if (class->level < 3) {
> +			pr_debug("class %u is before L3\n", class->level);
> +			continue;
> +		}
> +
> +		if (!class_has_usable_mba(cprops)) {
> +			pr_debug("class %u has no bandwidth control\n",
> +				 class->level);
> +			continue;
> +		}
> +
> +		if (!cpumask_equal(&class->affinity, cpu_possible_mask)) {
> +			pr_debug("class %u has missing CPUs\n", class->level);
> +			continue;
> +		}
> +
> +		if (!topology_matches_l3(class)) {
> +			pr_debug("class %u topology doesn't match L3\n",
> +				 class->level);
> +			continue;
> +		}
> +
> +		/*
> +		 * mba_sc reads the mbm_local counter, and waggles the MBA
> +		 * controls. mbm_local is implicitly part of the L3, pick a
> +		 * resource to be MBA that as close as possible to the L3.
> +		 */
> +		if (!candidate_class || class->level < candidate_class->level)
> +			candidate_class = class;
> +	}
> +
> +	if (candidate_class) {
> +		pr_debug("selected class %u to back MBA\n",
> +			 candidate_class->level);
> +		res = &mpam_resctrl_controls[RDT_RESOURCE_MBA];
> +		res->class = candidate_class;
> +		exposed_alloc_capable = true;
> +	}
> +}
> +
>   static int mpam_resctrl_control_init(struct mpam_resctrl_res *res,
>   				     enum resctrl_res_level type)
>   {
>   	struct mpam_class *class = res->class;
> +	struct mpam_props *cprops = &class->props;
>   	struct rdt_resource *r = &res->resctrl_res;
>   
>   	switch (res->resctrl_res.rid) {
> @@ -362,6 +532,20 @@ static int mpam_resctrl_control_init(struct mpam_resctrl_res *res,
>   		 * 'all the bits' is the correct answer here.
>   		 */
>   		r->cache.shareable_bits = resctrl_get_default_ctrl(r);
> +		break;
> +	case RDT_RESOURCE_MBA:
> +		r->alloc_capable = true;
> +		r->schema_fmt = RESCTRL_SCHEMA_RANGE;
> +		r->ctrl_scope = RESCTRL_L3_CACHE;
> +
> +		r->membw.delay_linear = true;
> +		r->membw.throttle_mode = THREAD_THROTTLE_UNDEFINED;
> +		r->membw.min_bw = get_mba_min(cprops);
> +		r->membw.max_bw = MAX_MBA_BW;
> +		r->membw.bw_gran = get_mba_granularity(cprops);
> +
> +		r->name = "MB";
> +
>   		break;
>   	default:
>   		break;
> @@ -377,7 +561,17 @@ static int mpam_resctrl_pick_domain_id(int cpu, struct mpam_component *comp)
>   	if (class->type == MPAM_CLASS_CACHE)
>   		return comp->comp_id;
>   
> -	/* TODO: repaint domain ids to match the L3 domain ids */
> +	if (topology_matches_l3(class)) {
> +		/* Use the corresponding L3 component ID as the domain ID */
> +		int id = get_cpu_cacheinfo_id(cpu, 3);
> +
> +		/* Implies topology_matches_l3() made a mistake */
> +		if (WARN_ON_ONCE(id == -1))
> +			return comp->comp_id;
> +
> +		return id;
> +	}
> +
>   	/*
>   	 * Otherwise, expose the ID used by the firmware table code.
>   	 */
> @@ -419,6 +613,12 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
>   	case RDT_RESOURCE_L3:
>   		configured_by = mpam_feat_cpor_part;
>   		break;
> +	case RDT_RESOURCE_MBA:
> +		if (mpam_has_feature(mpam_feat_mbw_max, cprops)) {
> +			configured_by = mpam_feat_mbw_max;
> +			break;
> +		}
> +		fallthrough;
>   	default:
>   		return resctrl_get_default_ctrl(r);
>   	}
> @@ -430,6 +630,8 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
>   	switch (configured_by) {
>   	case mpam_feat_cpor_part:
>   		return cfg->cpbm;
> +	case mpam_feat_mbw_max:
> +		return mbw_max_to_percent(cfg->mbw_max, cprops);
>   	default:
>   		return resctrl_get_default_ctrl(r);
>   	}
> @@ -474,6 +676,13 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
>   		cfg.cpbm = cfg_val;
>   		mpam_set_feature(mpam_feat_cpor_part, &cfg);
>   		break;
> +	case RDT_RESOURCE_MBA:
> +		if (mpam_has_feature(mpam_feat_mbw_max, cprops)) {
> +			cfg.mbw_max = percent_to_mbw_max(cfg_val, cprops);
> +			mpam_set_feature(mpam_feat_mbw_max, &cfg);
> +			break;
> +		}
> +		fallthrough;

I think mpam_feat_mbw_min peroperly need to be cleared in '&cfg', whose content
is copied from that of the component. mpam_feat_mbw_min may have been existing
in '&cfg' and struct mpam_config::mbw_min won't be updated correctly in the
subsequent call mpam_extend_config(). It means register MPAMCFG_MBW_MIN isn't
updated correctly.

On NVidia's grace-hopper machine, I got:

host$ mount none -tresctrl /sys/fs/resctrl/
host$ mkdir -p /sys/fs/resctrl/all
host$ mkdir -p /sys/fs/resctrl/test
host$ cat /proc/dump_feat_regs
MPAMF_IDR         0000008057010027
MAPMF_MBW_IDR     00000c07

host$ echo "MB:1=98" > /sys/fs/resctrl/test/schemata
host$ cat /proc/dump_cfg_regs
MPAMCFG_PART_SEL  00000002
MPAMCFG_MBW_MAX   0000f9ff
MPAMCFG_MBW_MIN   0000f000

host$ echo "MB:1=2" > /sys/fs/resctrl/test/schemata
host$ cat /proc/dump_cfg_regs
MPAMCFG_PART_SEL  00000002
MPAMCFG_MBW_MAX   000005ff
MPAMCFG_MBW_MIN   0000f000

With 'mpam_clear_feature(mpam_feat_mbw_min, &cfg);' applied here, the register
can be updated correctly. It also makes my (soft) MBW limiting tests happy.

host$ echo "MB:1=98" > /sys/fs/resctrl/test/schemata
host$ cat /proc/dump_cfg_regs
MPAMCFG_PART_SEL  00000002
MPAMCFG_MBW_MAX   0000f9ff
MPAMCFG_MBW_MIN   0000ea00

host$ echo "MB:1=2" > /sys/fs/resctrl/test/schemata
host$ cat /proc/dump_cfg_regs
MPAMCFG_PART_SEL  00000002
MPAMCFG_MBW_MAX   000005ff
MPAMCFG_MBW_MIN   00000200


Thanks,
Gavin

>   	default:
>   		return -EINVAL;
>   	}
> @@ -743,6 +952,7 @@ int mpam_resctrl_setup(void)
>   
>   	/* Find some classes to use for controls */
>   	mpam_resctrl_pick_caches();
> +	mpam_resctrl_pick_mba();
>   
>   	/* Initialise the resctrl structures from the classes */
>   	for (i = 0; i < RDT_NUM_RESOURCES; i++) {



From robh at kernel.org  Thu Dec 11 20:29:14 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Thu, 11 Dec 2025 22:29:14 -0600
Subject: [PATCH 1/4] dt-bindings: soc: devapc: Add for support MT8189
In-Reply-To: <20251212031450.489128-2-xiaoshun.xu@mediatek.corp-partner.google.com>
References: <20251212031450.489128-1-xiaoshun.xu@mediatek.corp-partner.google.com>
 <20251212031450.489128-2-xiaoshun.xu@mediatek.corp-partner.google.com>
Message-ID: <176551375433.2514847.16610029422866924600.robh@kernel.org>


On Fri, 12 Dec 2025 11:13:42 +0800, Xiaoshun Xu wrote:
> 
> External email : Please do not click links or open attachments until you have verified the sender or the content.
> 
> 
> From: "xiaoshun.xu" <xiaoshun.xu at mediatek.com>
> 
> Add compatible and vio-idx-num attribute of MT8189
> 
> Signed-off-by: xiaoshun.xu <xiaoshun.xu at mediatek.com>
> ---
>  Documentation/devicetree/bindings/soc/mediatek/devapc.yaml | 6 ++++++
>  1 file changed, 6 insertions(+)
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/soc/mediatek/devapc.yaml: vio-idx-num: missing type definition

doc reference errors (make refcheckdocs):

See https://patchwork.kernel.org/project/devicetree/patch/20251212031450.489128-2-xiaoshun.xu at mediatek.corp-partner.google.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.



From hariconscious at gmail.com  Thu Dec 11 20:44:09 2025
From: hariconscious at gmail.com (hariconscious at gmail.com)
Date: Fri, 12 Dec 2025 10:14:09 +0530
Subject: [PATCH RESEND] ASoC: mediatek: mt8195: optimize property formatting error handling by using scnprintf()
Message-ID: <20251212044408.1286-2-hariconscious@gmail.com>

From: HariKrishna Sagala <hariconscious at gmail.com>

Replace snprintf() with scnprintf() when constructing the property
and remove negative return error handling as scnprintf() returns the
actual number of bytes written to buffer.

snprintf() as defined by the C99 standard,returns the number of 
characters that *would have been* written if enough space were 
available.Use scnprintf() that returns the actual number of 
characters written.

Link: https://github.com/KSPP/linux/issues/105
Signed-off-by: HariKrishna Sagala <hariconscious at gmail.com>
---
This patch optimizes the error handling part of property formatting
using the scnrpintf().
Removed the error check ret < 0 as scnprintf() doesn't return the
negative value as per contract.
https://www.kernel.org/doc/html/latest/core-api/kernel-api.html#c.scnprintf

Thank you.

 sound/soc/mediatek/mt8195/mt8195-dai-etdm.c | 44 ++++++---------------
 1 file changed, 12 insertions(+), 32 deletions(-)

diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c
index fd4f9f8f032d..77c58c9ec3e2 100644
--- a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c
+++ b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c
@@ -2652,14 +2652,9 @@ static void mt8195_dai_etdm_parse_of(struct mtk_base_afe *afe)
 
 		etdm_data = afe_priv->dai_priv[dai_id];
 
-		ret = snprintf(prop, sizeof(prop),
-			       "mediatek,%s-mclk-always-on-rate",
-			       of_afe_etdms[i].name);
-		if (ret < 0) {
-			dev_info(afe->dev, "%s snprintf err=%d\n",
-				 __func__, ret);
-			return;
-		}
+		scnprintf(prop, sizeof(prop),
+			    "mediatek,%s-mclk-always-on-rate",
+			    of_afe_etdms[i].name);
 		ret = of_property_read_u32(of_node, prop, &sel);
 		if (ret == 0) {
 			etdm_data->mclk_dir = SND_SOC_CLOCK_OUT;
@@ -2668,24 +2663,14 @@ static void mt8195_dai_etdm_parse_of(struct mtk_base_afe *afe)
 					 __func__, sel);
 		}
 
-		ret = snprintf(prop, sizeof(prop),
-			       "mediatek,%s-multi-pin-mode",
-			       of_afe_etdms[i].name);
-		if (ret < 0) {
-			dev_info(afe->dev, "%s snprintf err=%d\n",
-				 __func__, ret);
-			return;
-		}
+		scnprintf(prop, sizeof(prop),
+			    "mediatek,%s-multi-pin-mode",
+			    of_afe_etdms[i].name);
 		etdm_data->data_mode = of_property_read_bool(of_node, prop);
 
-		ret = snprintf(prop, sizeof(prop),
-			       "mediatek,%s-cowork-source",
-			       of_afe_etdms[i].name);
-		if (ret < 0) {
-			dev_info(afe->dev, "%s snprintf err=%d\n",
-				 __func__, ret);
-			return;
-		}
+		scnprintf(prop, sizeof(prop),
+			    "mediatek,%s-cowork-source",
+			    of_afe_etdms[i].name);
 		ret = of_property_read_u32(of_node, prop, &sel);
 		if (ret == 0) {
 			if (sel >= MT8195_AFE_IO_ETDM_NUM) {
@@ -2707,14 +2692,9 @@ static void mt8195_dai_etdm_parse_of(struct mtk_base_afe *afe)
 		dai_id = ETDM_TO_DAI_ID(i);
 		etdm_data = afe_priv->dai_priv[dai_id];
 
-		ret = snprintf(prop, sizeof(prop),
-			       "mediatek,%s-chn-disabled",
-			       of_afe_etdms[i].name);
-		if (ret < 0) {
-			dev_info(afe->dev, "%s snprintf err=%d\n",
-				 __func__, ret);
-			return;
-		}
+		scnprintf(prop, sizeof(prop),
+			    "mediatek,%s-chn-disabled",
+			    of_afe_etdms[i].name);
 		ret = of_property_read_variable_u8_array(of_node, prop,
 							 disable_chn,
 							 1, max_chn);

base-commit: 30f09200cc4aefbd8385b01e41bde2e4565a6f0e
-- 
2.43.0



From ebiggers at kernel.org  Thu Dec 11 21:40:20 2025
From: ebiggers at kernel.org (Eric Biggers)
Date: Thu, 11 Dec 2025 21:40:20 -0800
Subject: [PATCH] crypto: arm64/ghash - Fix incorrect output from
 ghash-neon
In-Reply-To: <CAMj1kXEQkB9MWB+PAi4XE_MuBt0ScitxTsKMDo1-7Cp-=xXOpw@mail.gmail.com>
References: <DETXT7QI62KE.F3CGH2VWX1SC@cknow-tech.com>
 <20251209223417.112294-1-ebiggers@kernel.org>
 <DEUFDH7FJURL.3J0FN5I19VV8F@cknow-tech.com>
 <CAMj1kXEQkB9MWB+PAi4XE_MuBt0ScitxTsKMDo1-7Cp-=xXOpw@mail.gmail.com>
Message-ID: <20251212054020.GB4838@sol>

On Wed, Dec 10, 2025 at 06:31:44PM +0900, Ard Biesheuvel wrote:
> On Wed, 10 Dec 2025 at 18:22, Diederik de Haas <diederik at cknow-tech.com> wrote:
> >
> > On Tue Dec 9, 2025 at 11:34 PM CET, Eric Biggers wrote:
> > > Commit 9a7c987fb92b ("crypto: arm64/ghash - Use API partial block
> > > handling") made ghash_finup() pass the wrong buffer to
> > > ghash_do_simd_update().  As a result, ghash-neon now produces incorrect
> > > outputs when the message length isn't divisible by 16 bytes.  Fix this.
> >
> > I was hoping to not have to do a 'git bisect', but this is much better
> > :-D I can confirm that this patch fixes the error I was seeing, so
> >
> > Tested-by: Diederik de Haas <diederik at cknow-tech.com>
> >
> > > (I didn't notice this earlier because this code is reached only on CPUs
> > > that support NEON but not PMULL.  I haven't yet found a way to get
> > > qemu-system-aarch64 to emulate that configuration.)
> >
> > https://www.qemu.org/docs/master/system/arm/raspi.html indicates it can
> > emulate various Raspberry Pi models. I've only tested it with RPi 3B+
> > (bc of its wifi+bt chip), but I wouldn't be surprised if all RPi models
> > would have this problem? Dunno if QEMU emulates that though.
> >
> 
> All 64-bit RPi models except the RPi5 are affected by this, as those
> do not implement the crypto extensions. So I would expect QEMU to do
> the same.
> 
> It would be nice, though, if we could emulate this on the mach-virt
> machine model too. It should be fairly trivial to do, so if there is
> demand for this I can look into it.

I'm definitely interested in it.  I'm already testing multiple "-cpu"
options, and it's easy to add more.

With qemu-system-aarch64 I'm currently only using "-M virt", since the
other machine models I've tried don't boot with arm64 defconfig,
including "-M raspi3b" and "-M raspi4b".

There may be some tricks I'm missing.  Regardless, expanding the
selection of available CPUs for "-M virt" would be helpful.  Either by
adding "real" CPUs that have "interesting" combinations of features, or
by just allowing turning features off like
"-cpu max,aes=off,pmull=off,sha256=off".  (Certain features like sve can
already be turned off in that way, but not the ones relevant to us.)

- Eric


From andrew at codeconstruct.com.au  Thu Dec 11 21:53:42 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Fri, 12 Dec 2025 14:53:42 +0900
Subject: [PATCH RFC 01/16] dt-bindings: hwmon: Convert
 aspeed,ast2400-pwm-tacho to DT schema
In-Reply-To: <f17d93db-f96b-469d-88f0-0878a0fc9fe7@roeck-us.net>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
	 <20251211-dev-dt-warnings-all-v1-1-21b18b9ada77@codeconstruct.com.au>
	 <f17d93db-f96b-469d-88f0-0878a0fc9fe7@roeck-us.net>
Message-ID: <97f2eee63e1ed908866c10721b9f0a57036723dc.camel@codeconstruct.com.au>

On Thu, 2025-12-11 at 12:27 -0800, Guenter Roeck wrote:
> On 12/11/25 00:45, Andrew Jeffery wrote:
> > From: "Rob Herring (Arm)" <robh at kernel.org>
> > 
> > Convert the ASpeed fan controller binding to DT schema format.
> > 
> > The '#cooling-cells' value used is 1 rather than 2. '#size-cells' is 0
> > rather 1.
> > 
> > Some users define more that 8 fan nodes where 2 fans share a PWM. The
> > driver seems to let the 2nd fan just overwrite the 1st one. That also
> > creates some addressing errors in the DT (duplicate addresses and wrong
> > unit-addresses).
> > 
> > Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> > Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
> 
> I am not sure I understand what the plan is here. I am assuming it will be
> applied through a non-hwmon branch.
> 
> Acked-by: Guenter Roeck <linux at roeck-us.net>

Thanks Guenter.

Apologies for confusion there. The series is currently a collection of
miscellaneous binding stuff that I felt needed DT maintainer input, so
I avoided adding driver subsystem maintainers in To/Cc to minimise
noise. Rob's feedback at [1] needs to be addressed - I'll make sure
you're in To: once that's sorted.

Andrew

[1]:
https://lore.kernel.org/all/20251211170333.GA1557987-robh at kernel.org/


From andrew at codeconstruct.com.au  Thu Dec 11 21:57:01 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Fri, 12 Dec 2025 14:57:01 +0900
Subject: [PATCH RFC 16/16] dt-bindings: mfd: Document smp-memram node
 for AST2600 SCU
In-Reply-To: <176546866713.1487167.4918701456595372928.robh@kernel.org>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
	 <20251211-dev-dt-warnings-all-v1-16-21b18b9ada77@codeconstruct.com.au>
	 <176546866713.1487167.4918701456595372928.robh@kernel.org>
Message-ID: <b31b9876a981f782ea9481402a4c9041cfef748a.camel@codeconstruct.com.au>

On Thu, 2025-12-11 at 09:57 -0600, Rob Herring (Arm) wrote:
> 
> On Thu, 11 Dec 2025 17:45:58 +0900, Andrew Jeffery wrote:
> > The platform initialisation code for the AST2600 implements the custom
> > SMP bringup protocol, and searches for the relevant compatible. As a
> > consequence, define the requisite node and the compatible string, which
> > in-turn tidies up the dtb check results.
> > 
> > Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
> > ---
> > ?.../devicetree/bindings/mfd/aspeed,ast2x00-scu.yaml??? | 18 ++++++++++++++++++
> > ?1 file changed, 18 insertions(+)
> > 
> 
> My bot found errors running 'make dt_binding_check' on your patch:
> 
> yamllint warnings/errors:
> ./Documentation/devicetree/bindings/mfd/aspeed,ast2x00-scu.yaml:140:16: [error] string value is redundantly quoted with any quotes (quoted-strings)

Bah, didn't update dt-validate prior to testing the series. Done so now
and have fixed the issue.

Andrew


From qijian.guo at oss.nxp.com  Thu Dec 11 22:03:03 2025
From: qijian.guo at oss.nxp.com (Joseph Guo (OSS))
Date: Fri, 12 Dec 2025 14:03:03 +0800
Subject: [PATCH v2 2/2] arm64: dts: freescale: Add FRDM-IMX91 basic
 support
In-Reply-To: <55fa5159-768c-4785-b0ba-5553193932ab@lunn.ch>
References: <20251212-imx91_frdm-v2-0-4dd6d289e81d@nxp.com>
 <20251212-imx91_frdm-v2-2-4dd6d289e81d@nxp.com>
 <55fa5159-768c-4785-b0ba-5553193932ab@lunn.ch>
Message-ID: <15608952-e974-4b9f-9832-e6a23860fc62@oss.nxp.com>



On 12/12/2025 11:39 AM, Andrew Lunn wrote:
> [You don't often get email from andrew at lunn.ch. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
> 
>> +&fec {
>> +     phy-handle = <&ethphy2>;
>> +     phy-mode = "rgmii-id";
>> +     pinctrl-0 = <&pinctrl_fec>;
>> +     pinctrl-1 = <&pinctrl_fec_sleep>;
>> +     pinctrl-names = "default", "sleep";
>> +     fsl,magic-packet;
> 
> Have you tested WoL?
> 
>          Andrew

Hi Andrew,

Yes, already tested.

Regards,
Joseph



From amhetre at nvidia.com  Thu Dec 11 22:08:01 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Fri, 12 Dec 2025 06:08:01 +0000
Subject: [PATCH V6 2/4] iommu/arm-smmu-v3: Add device-tree support for CMDQV driver
In-Reply-To: <20251212060803.1712637-1-amhetre@nvidia.com>
References: <20251212060803.1712637-1-amhetre@nvidia.com>
Message-ID: <20251212060803.1712637-3-amhetre@nvidia.com>

Add device tree support to the CMDQV driver to enable usage on Tegra264
SoCs. The implementation parses the nvidia,cmdqv phandle from the SMMU
device tree node to associate each SMMU with its corresponding CMDQV
instance based on compatible string.

Reviewed-by: Nicolin Chen <nicolinc at nvidia.com>
Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 32 +++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 42de3da54858..fbd16b210e88 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -4530,6 +4530,35 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
 	return 0;
 }
 
+#ifdef CONFIG_TEGRA241_CMDQV
+static void tegra_cmdqv_dt_probe(struct device_node *smmu_node,
+				 struct arm_smmu_device *smmu)
+{
+	struct platform_device *pdev;
+	struct device_node *np;
+
+	np = of_parse_phandle(smmu_node, "nvidia,cmdqv", 0);
+	if (!np)
+		return;
+
+	/* Tegra241 CMDQV driver is responsible for put_device() */
+	pdev = of_find_device_by_node(np);
+	of_node_put(np);
+	if (!pdev)
+		return;
+
+	smmu->impl_dev = &pdev->dev;
+	smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
+	dev_info(smmu->dev, "found companion CMDQV device: %s\n",
+		 dev_name(smmu->impl_dev));
+}
+#else
+static void tegra_cmdqv_dt_probe(struct device_node *smmu_node,
+				 struct arm_smmu_device *smmu)
+{
+}
+#endif
+
 #ifdef CONFIG_ACPI
 #ifdef CONFIG_TEGRA241_CMDQV
 static void acpi_smmu_dsdt_probe_tegra241_cmdqv(struct acpi_iort_node *node,
@@ -4634,6 +4663,9 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev,
 	if (of_dma_is_coherent(dev->of_node))
 		smmu->features |= ARM_SMMU_FEAT_COHERENCY;
 
+	if (of_device_is_compatible(dev->of_node, "nvidia,tegra264-smmu"))
+		tegra_cmdqv_dt_probe(dev->of_node, smmu);
+
 	return ret;
 }
 
-- 
2.25.1



From amhetre at nvidia.com  Thu Dec 11 22:07:59 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Fri, 12 Dec 2025 06:07:59 +0000
Subject: [PATCH V6 0/4] Add device tree support for NVIDIA Tegra CMDQV
Message-ID: <20251212060803.1712637-1-amhetre@nvidia.com>

This series adds device tree support for the CMDQ-Virtualization (CMDQV)
hardware on NVIDIA Tegra264 SoCs.

CMDQV is a hardware block that works alongside the ARM SMMUv3 to assist in
virtualizing the command queue. It was previously only supported through
ACPI on Tegra241. This series extends the existing driver to support device
tree based initialization, which is required for Tegra264 platforms.

The series is structured as follows:

Patch 1: Decouple tegra241-cmdqv driver from ACPI by replacing all the
         ACPI functions with standard platform functions.

Patch 2: Extends the tegra241-cmdqv driver to support device tree probing
         alongside the existing ACPI support. The SMMU driver now parses
         the nvidia,cmdqv phandle to associate each SMMU with its
         corresponding CMDQV instance.

Patch 3: Adds device tree binding documentation for nvidia,tegra264-cmdqv
         and extends the arm,smmu-v3 binding with an optional nvidia,cmdqv
         property.

Patch 4: Adds CMDQV device nodes to the Tegra264 device tree and enables
         them on the tegra264-p3834 platform.

The implementation follows the existing ACPI probe path to minimize code
divergence and maintain consistency with Tegra241 support.

Changes in V6:
- Added Nicolin's patch for decoupling tegra241-cmdqv from ACPI and
  rebased other patches on top of it.
- Removed put_device() from DT path as tegra241-cmdqv driver takes care
  of dropping reference in remove callback.

Changes in V5:
- Guard ACPI functions with CONFIG_ACPI to fix build without ACPI.

Changes in V4:
- Removed platform driver registration from tegra241-cmdqv.c to avoid
  duplicate module init/cleanup symbols
- Fixed the ordering of properties in CMDQV device tree nodes
- Added "Reviewed-by: Rob Herring" for binding documentation patch(2/3)
  carry-forwarding from V3.

Changes in V3:
- Remove the Kconfig dependency for CONFIG_TEGRA241_CMDQV
- Drop the reference on the platform device after getting it from
  of_find_device_by_node()
- Remove the unnecessary "nvidia,tegra264-smmu" compatible string from
  arm-smmu-v3 match table
- Order CMDQV nodes in device tree files according to its address

Changes in V2:
- Updated dependency for CONFIG_TEGRA241_CMDQV on OF || ACPI
- Changed maintainer to Nicolin Chen
- Removed interrupt-names property

Ashish Mhetre (3):
  iommu/arm-smmu-v3: Add device-tree support for CMDQV driver
  dt-bindings: iommu: Add NVIDIA Tegra CMDQV support
  arm64: dts: nvidia: Add nodes for CMDQV

Nicolin Chen (1):
  iommu/tegra241-cmdqv: Decouple driver from ACPI

 .../bindings/iommu/arm,smmu-v3.yaml           | 30 ++++++-
 .../bindings/iommu/nvidia,tegra264-cmdqv.yaml | 42 ++++++++++
 .../arm64/boot/dts/nvidia/tegra264-p3834.dtsi |  8 ++
 arch/arm64/boot/dts/nvidia/tegra264.dtsi      | 50 +++++++++--
 drivers/iommu/arm/Kconfig                     |  1 -
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 34 +++++++-
 .../iommu/arm/arm-smmu-v3/tegra241-cmdqv.c    | 84 +++----------------
 7 files changed, 168 insertions(+), 81 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/iommu/nvidia,tegra264-cmdqv.yaml

-- 
2.25.1



From amhetre at nvidia.com  Thu Dec 11 22:08:00 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Fri, 12 Dec 2025 06:08:00 +0000
Subject: [PATCH V6 1/4] iommu/tegra241-cmdqv: Decouple driver from ACPI
In-Reply-To: <20251212060803.1712637-1-amhetre@nvidia.com>
References: <20251212060803.1712637-1-amhetre@nvidia.com>
Message-ID: <20251212060803.1712637-2-amhetre@nvidia.com>

From: Nicolin Chen <nicolinc at nvidia.com>

A platform device is created by acpi_create_platform_device() per CMDQV's
adev. That means there is no point in going through _CRS of ACPI.

Replace all the ACPI functions with standard platform functions. And drop
all ACPI dependencies. This will make the driver compatible with DT also.

Suggested-by: Robin Murphy <robin.murphy at arm.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/Kconfig                     |  1 -
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   |  2 +-
 .../iommu/arm/arm-smmu-v3/tegra241-cmdqv.c    | 84 +++----------------
 3 files changed, 13 insertions(+), 74 deletions(-)

diff --git a/drivers/iommu/arm/Kconfig b/drivers/iommu/arm/Kconfig
index ef42bbe07dbe..5fac08b89dee 100644
--- a/drivers/iommu/arm/Kconfig
+++ b/drivers/iommu/arm/Kconfig
@@ -121,7 +121,6 @@ config ARM_SMMU_V3_KUNIT_TEST
 
 config TEGRA241_CMDQV
 	bool "NVIDIA Tegra241 CMDQ-V extension support for ARM SMMUv3"
-	depends on ACPI
 	help
 	  Support for NVIDIA CMDQ-Virtualization extension for ARM SMMUv3. The
 	  CMDQ-V extension is similar to v3.3 ECMDQ for multi command queues
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index d16d35c78c06..42de3da54858 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -4542,7 +4542,7 @@ static void acpi_smmu_dsdt_probe_tegra241_cmdqv(struct acpi_iort_node *node,
 	adev = acpi_dev_get_first_match_dev("NVDA200C", uid, -1);
 	if (adev) {
 		/* Tegra241 CMDQV driver is responsible for put_device() */
-		smmu->impl_dev = &adev->dev;
+		smmu->impl_dev = acpi_get_first_physical_node(adev);
 		smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
 		dev_info(smmu->dev, "found companion CMDQV device: %s\n",
 			 dev_name(smmu->impl_dev));
diff --git a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
index 378104cd395e..1fc03b72beb8 100644
--- a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
+++ b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
@@ -3,17 +3,15 @@
 
 #define dev_fmt(fmt) "tegra241_cmdqv: " fmt
 
-#include <linux/acpi.h>
 #include <linux/debugfs.h>
 #include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
 #include <linux/iommu.h>
 #include <linux/iommufd.h>
 #include <linux/iopoll.h>
+#include <linux/platform_device.h>
 #include <uapi/linux/iommufd.h>
 
-#include <acpi/acpixf.h>
-
 #include "arm-smmu-v3.h"
 
 /* CMDQV register page base and size defines */
@@ -854,69 +852,6 @@ static struct arm_smmu_impl_ops tegra241_cmdqv_impl_ops = {
 
 /* Probe Functions */
 
-static int tegra241_cmdqv_acpi_is_memory(struct acpi_resource *res, void *data)
-{
-	struct resource_win win;
-
-	return !acpi_dev_resource_address_space(res, &win);
-}
-
-static int tegra241_cmdqv_acpi_get_irqs(struct acpi_resource *ares, void *data)
-{
-	struct resource r;
-	int *irq = data;
-
-	if (*irq <= 0 && acpi_dev_resource_interrupt(ares, 0, &r))
-		*irq = r.start;
-	return 1; /* No need to add resource to the list */
-}
-
-static struct resource *
-tegra241_cmdqv_find_acpi_resource(struct device *dev, int *irq)
-{
-	struct acpi_device *adev = to_acpi_device(dev);
-	struct list_head resource_list;
-	struct resource_entry *rentry;
-	struct resource *res = NULL;
-	int ret;
-
-	INIT_LIST_HEAD(&resource_list);
-	ret = acpi_dev_get_resources(adev, &resource_list,
-				     tegra241_cmdqv_acpi_is_memory, NULL);
-	if (ret < 0) {
-		dev_err(dev, "failed to get memory resource: %d\n", ret);
-		return NULL;
-	}
-
-	rentry = list_first_entry_or_null(&resource_list,
-					  struct resource_entry, node);
-	if (!rentry) {
-		dev_err(dev, "failed to get memory resource entry\n");
-		goto free_list;
-	}
-
-	/* Caller must free the res */
-	res = kzalloc(sizeof(*res), GFP_KERNEL);
-	if (!res)
-		goto free_list;
-
-	*res = *rentry->res;
-
-	acpi_dev_free_resource_list(&resource_list);
-
-	INIT_LIST_HEAD(&resource_list);
-
-	if (irq)
-		ret = acpi_dev_get_resources(adev, &resource_list,
-					     tegra241_cmdqv_acpi_get_irqs, irq);
-	if (ret < 0 || !irq || *irq <= 0)
-		dev_warn(dev, "no interrupt. errors will not be reported\n");
-
-free_list:
-	acpi_dev_free_resource_list(&resource_list);
-	return res;
-}
-
 static int tegra241_cmdqv_init_structures(struct arm_smmu_device *smmu)
 {
 	struct tegra241_cmdqv *cmdqv =
@@ -1042,18 +977,23 @@ __tegra241_cmdqv_probe(struct arm_smmu_device *smmu, struct resource *res,
 
 struct arm_smmu_device *tegra241_cmdqv_probe(struct arm_smmu_device *smmu)
 {
+	struct platform_device *pdev = to_platform_device(smmu->impl_dev);
 	struct arm_smmu_device *new_smmu;
-	struct resource *res = NULL;
+	struct resource *res;
 	int irq;
 
-	if (!smmu->dev->of_node)
-		res = tegra241_cmdqv_find_acpi_resource(smmu->impl_dev, &irq);
-	if (!res)
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "no memory resource found for CMDQV\n");
 		goto out_fallback;
+	}
 
-	new_smmu = __tegra241_cmdqv_probe(smmu, res, irq);
-	kfree(res);
+	irq = platform_get_irq_optional(pdev, 0);
+	if (irq <= 0)
+		dev_warn(&pdev->dev,
+			 "no interrupt. errors will not be reported\n");
 
+	new_smmu = __tegra241_cmdqv_probe(smmu, res, irq);
 	if (new_smmu)
 		return new_smmu;
 
-- 
2.25.1



From amhetre at nvidia.com  Thu Dec 11 22:08:03 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Fri, 12 Dec 2025 06:08:03 +0000
Subject: [PATCH V6 4/4] arm64: dts: nvidia: Add nodes for CMDQV
In-Reply-To: <20251212060803.1712637-1-amhetre@nvidia.com>
References: <20251212060803.1712637-1-amhetre@nvidia.com>
Message-ID: <20251212060803.1712637-5-amhetre@nvidia.com>

The Command Queue Virtualization (CMDQV) hardware is part of the
SMMUv3 implementation on NVIDIA Tegra SoCs. It assists in
virtualizing the command queue for the SMMU.

Update SMMU compatible strings to use nvidia,tegra264-smmu to enable
CMDQV support. Add device tree nodes for the CMDQV hardware and enable
them on the tegra264-p3834 platform where SMMUs are enabled. Each SMMU
instance is paired with its corresponding CMDQV instance via the
nvidia,cmdqv property.

Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
---
 .../arm64/boot/dts/nvidia/tegra264-p3834.dtsi |  8 +++
 arch/arm64/boot/dts/nvidia/tegra264.dtsi      | 50 +++++++++++++++++--
 2 files changed, 53 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi b/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
index 06795c82427a..7e2c3e66c2ab 100644
--- a/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
@@ -23,8 +23,16 @@ iommu at 5000000 {
 			status = "okay";
 		};
 
+		cmdqv at 5200000 {
+			status = "okay";
+		};
+
 		iommu at 6000000 {
 			status = "okay";
 		};
+
+		cmdqv at 6200000 {
+			status = "okay";
+		};
 	};
 };
diff --git a/arch/arm64/boot/dts/nvidia/tegra264.dtsi b/arch/arm64/boot/dts/nvidia/tegra264.dtsi
index f137565da804..9eb7058e3149 100644
--- a/arch/arm64/boot/dts/nvidia/tegra264.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra264.dtsi
@@ -3361,7 +3361,7 @@ bus at 8100000000 {
 			 <0x02 0x00000000 0xd0 0x00000000 0x08 0x80000000>; /* ECAM, prefetchable memory, I/O */
 
 		smmu1: iommu at 5000000 {
-			compatible = "arm,smmu-v3";
+			compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
 			reg = <0x00 0x5000000 0x0 0x200000>;
 			interrupts = <GIC_SPI 12 IRQ_TYPE_EDGE_RISING>,
 				     <GIC_SPI 13 IRQ_TYPE_EDGE_RISING>;
@@ -3370,10 +3370,18 @@ smmu1: iommu at 5000000 {
 
 			#iommu-cells = <1>;
 			dma-coherent;
+			nvidia,cmdqv = <&cmdqv1>;
+		};
+
+		cmdqv1: cmdqv at 5200000 {
+			compatible = "nvidia,tegra264-cmdqv";
+			reg = <0x00 0x5200000 0x0 0x830000>;
+			interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
 		};
 
 		smmu2: iommu at 6000000 {
-			compatible = "arm,smmu-v3";
+			compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
 			reg = <0x00 0x6000000 0x0 0x200000>;
 			interrupts = <GIC_SPI 1 IRQ_TYPE_EDGE_RISING>,
 				     <GIC_SPI 2 IRQ_TYPE_EDGE_RISING>;
@@ -3382,6 +3390,14 @@ smmu2: iommu at 6000000 {
 
 			#iommu-cells = <1>;
 			dma-coherent;
+			nvidia,cmdqv = <&cmdqv2>;
+		};
+
+		cmdqv2: cmdqv at 6200000 {
+			compatible = "nvidia,tegra264-cmdqv";
+			reg = <0x00 0x6200000 0x0 0x830000>;
+			interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
 		};
 
 		mc: memory-controller at 8020000 {
@@ -3437,7 +3453,7 @@ emc: external-memory-controller at 8800000 {
 		};
 
 		smmu0: iommu at a000000 {
-			compatible = "arm,smmu-v3";
+			compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
 			reg = <0x00 0xa000000 0x0 0x200000>;
 			interrupts = <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>,
 				     <GIC_SPI 22 IRQ_TYPE_EDGE_RISING>;
@@ -3446,10 +3462,18 @@ smmu0: iommu at a000000 {
 
 			#iommu-cells = <1>;
 			dma-coherent;
+			nvidia,cmdqv = <&cmdqv0>;
+		};
+
+		cmdqv0: cmdqv at a200000 {
+			compatible = "nvidia,tegra264-cmdqv";
+			reg = <0x00 0xa200000 0x0 0x830000>;
+			interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
 		};
 
 		smmu4: iommu at b000000 {
-			compatible = "arm,smmu-v3";
+			compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
 			reg = <0x00 0xb000000 0x0 0x200000>;
 			interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
 				     <GIC_SPI 31 IRQ_TYPE_EDGE_RISING>;
@@ -3458,6 +3482,14 @@ smmu4: iommu at b000000 {
 
 			#iommu-cells = <1>;
 			dma-coherent;
+			nvidia,cmdqv = <&cmdqv4>;
+		};
+
+		cmdqv4: cmdqv at b200000 {
+			compatible = "nvidia,tegra264-cmdqv";
+			reg = <0x00 0xb200000 0x0 0x830000>;
+			interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
 		};
 
 		i2c14: i2c at c410000 {
@@ -3690,7 +3722,7 @@ bus at 8800000000 {
 		ranges = <0x00 0x00000000 0x88 0x00000000 0x01 0x00000000>;
 
 		smmu3: iommu at 6000000 {
-			compatible = "arm,smmu-v3";
+			compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
 			reg = <0x00 0x6000000 0x0 0x200000>;
 			interrupts = <GIC_SPI 225 IRQ_TYPE_EDGE_RISING>,
 				     <GIC_SPI 226 IRQ_TYPE_EDGE_RISING>;
@@ -3699,6 +3731,14 @@ smmu3: iommu at 6000000 {
 
 			#iommu-cells = <1>;
 			dma-coherent;
+			nvidia,cmdqv = <&cmdqv3>;
+		};
+
+		cmdqv3: cmdqv at 6200000 {
+			compatible = "nvidia,tegra264-cmdqv";
+			reg = <0x00 0x6200000 0x0 0x830000>;
+			interrupts = <GIC_SPI 232 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
 		};
 
 		hda at 90b0000 {
-- 
2.25.1



From amhetre at nvidia.com  Thu Dec 11 22:08:02 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Fri, 12 Dec 2025 06:08:02 +0000
Subject: [PATCH V6 3/4] dt-bindings: iommu: Add NVIDIA Tegra CMDQV support
In-Reply-To: <20251212060803.1712637-1-amhetre@nvidia.com>
References: <20251212060803.1712637-1-amhetre@nvidia.com>
Message-ID: <20251212060803.1712637-4-amhetre@nvidia.com>

The Command Queue Virtualization (CMDQV) hardware is part of the
SMMUv3 implementation on NVIDIA Tegra SoCs. It assists in
virtualizing the command queue for the SMMU.

Add a new device tree binding document for nvidia,tegra264-cmdqv.

Also update the arm,smmu-v3 binding to include an optional nvidia,cmdqv
property. This property is a phandle to the CMDQV device node, allowing
the SMMU driver to associate with its corresponding CMDQV instance.
Restrict this property usage to Nvidia Tegra264 only.

Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
---
 .../bindings/iommu/arm,smmu-v3.yaml           | 30 ++++++++++++-
 .../bindings/iommu/nvidia,tegra264-cmdqv.yaml | 42 +++++++++++++++++++
 2 files changed, 70 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/iommu/nvidia,tegra264-cmdqv.yaml

diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
index 75fcf4cb52d9..1c03482e4c61 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
@@ -20,7 +20,12 @@ properties:
   $nodename:
     pattern: "^iommu@[0-9a-f]*"
   compatible:
-    const: arm,smmu-v3
+    oneOf:
+      - const: arm,smmu-v3
+      - items:
+          - enum:
+              - nvidia,tegra264-smmu
+          - const: arm,smmu-v3
 
   reg:
     maxItems: 1
@@ -58,6 +63,15 @@ properties:
 
   msi-parent: true
 
+  nvidia,cmdqv:
+    description: |
+      A phandle to its pairing CMDQV extension for an implementation on NVIDIA
+      Tegra SoC.
+
+      If this property is absent, CMDQ-Virtualization won't be used and SMMU
+      will only use its own CMDQ.
+    $ref: /schemas/types.yaml#/definitions/phandle
+
   hisilicon,broken-prefetch-cmd:
     type: boolean
     description: Avoid sending CMD_PREFETCH_* commands to the SMMU.
@@ -69,6 +83,17 @@ properties:
       register access with page 0 offsets. Set for Cavium ThunderX2 silicon that
       doesn't support SMMU page1 register space.
 
+allOf:
+  - if:
+      not:
+        properties:
+          compatible:
+            contains:
+              const: nvidia,tegra264-smmu
+    then:
+      properties:
+        nvidia,cmdqv: false
+
 required:
   - compatible
   - reg
@@ -82,7 +107,7 @@ examples:
     #include <dt-bindings/interrupt-controller/irq.h>
 
     iommu at 2b400000 {
-            compatible = "arm,smmu-v3";
+            compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
             reg = <0x2b400000 0x20000>;
             interrupts = <GIC_SPI 74 IRQ_TYPE_EDGE_RISING>,
                          <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>,
@@ -92,4 +117,5 @@ examples:
             dma-coherent;
             #iommu-cells = <1>;
             msi-parent = <&its 0xff0000>;
+            nvidia,cmdqv = <&cmdqv>;
     };
diff --git a/Documentation/devicetree/bindings/iommu/nvidia,tegra264-cmdqv.yaml b/Documentation/devicetree/bindings/iommu/nvidia,tegra264-cmdqv.yaml
new file mode 100644
index 000000000000..3f5006a59805
--- /dev/null
+++ b/Documentation/devicetree/bindings/iommu/nvidia,tegra264-cmdqv.yaml
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iommu/nvidia,tegra264-cmdqv.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra264 CMDQV
+
+description:
+  The CMDQ-Virtualization hardware block is part of the SMMUv3 implementation
+  on Tegra264 SoCs. It assists in virtualizing the command queue for the SMMU.
+
+maintainers:
+  - Nicolin Chen <nicolinc at nvidia.com>
+
+properties:
+  compatible:
+    const: nvidia,tegra264-cmdqv
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    cmdqv at 5200000 {
+            compatible = "nvidia,tegra264-cmdqv";
+            reg = <0x5200000 0x830000>;
+            interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+    };
-- 
2.25.1



From sashal at kernel.org  Thu Dec 11 22:12:12 2025
From: sashal at kernel.org (Sasha Levin)
Date: Fri, 12 Dec 2025 01:12:12 -0500
Subject: [PATCH AUTOSEL 6.18-5.10] ARM: 9461/1: Disable HIGHPTE on PREEMPT_RT kernels
In-Reply-To: <20251212061223.305139-1-sashal@kernel.org>
References: <20251212061223.305139-1-sashal@kernel.org>
Message-ID: <20251212061223.305139-2-sashal@kernel.org>

From: Sebastian Andrzej Siewior <bigeasy at linutronix.de>

[ Upstream commit fedadc4137234c3d00c4785eeed3e747fe9036ae ]

gup_pgd_range() is invoked with disabled interrupts and invokes
__kmap_local_page_prot() via pte_offset_map(), gup_p4d_range().
With HIGHPTE enabled, __kmap_local_page_prot() invokes kmap_high_get()
which uses a spinlock_t via lock_kmap_any(). This leads to an
sleeping-while-atomic error on PREEMPT_RT because spinlock_t becomes a
sleeping lock and must not be acquired in atomic context.

The loop in map_new_virtual() uses wait_queue_head_t for wake up which
also is using a spinlock_t.

Since HIGHPTE is rarely needed at all, turn it off for PREEMPT_RT
to allow the use of get_user_pages_fast().

[arnd: rework patch to turn off HIGHPTE instead of HAVE_PAST_GUP]

Co-developed-by: Arnd Bergmann <arnd at arndb.de>

Acked-by: Linus Walleij <linus.walleij at linaro.org>
Reviewed-by: Arnd Bergmann <arnd at arndb.de>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy at linutronix.de>
Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---

LLM Generated explanations, may be completely bogus:

# Commit Analysis: ARM: 9461/1: Disable HIGHPTE on PREEMPT_RT kernels

## 1. COMMIT MESSAGE ANALYSIS

**Problem identified**: The commit addresses a "sleeping-while-atomic"
bug on PREEMPT_RT ARM kernels. The issue occurs because:
- `gup_pgd_range()` runs with interrupts disabled (atomic context)
- With HIGHPTE enabled, the code path calls `kmap_high_get()` which
  acquires a `spinlock_t` via `lock_kmap_any()`
- On PREEMPT_RT, `spinlock_t` becomes a sleeping lock (mutex)
- Attempting to acquire a sleeping lock in atomic context is a bug

**Tags present**:
- Acked-by: Linus Walleij (ARM/pinctrl maintainer)
- Reviewed-by: Arnd Bergmann (major ARM contributor)
- Signed-off-by: Sebastian Andrzej Siewior (PREEMPT_RT maintainer)
- Signed-off-by: Russell King (ARM maintainer)

**Missing tags**: No `Cc: stable at vger.kernel.org` or `Fixes:` tag.

## 2. CODE CHANGE ANALYSIS

The change is a single-line Kconfig modification:

```diff
- depends on HIGHMEM
+       depends on HIGHMEM && !PREEMPT_RT
```

This simply prevents the `HIGHPTE` configuration option from being
selected when `PREEMPT_RT` is enabled. The technical mechanism of the
bug is clear:

1. `get_user_pages_fast()` ? `gup_pgd_range()` (runs with interrupts
   disabled)
2. ? `pte_offset_map()` ? `__kmap_local_page_prot()` ? `kmap_high_get()`
3. `kmap_high_get()` calls `lock_kmap_any()` which uses `spinlock_t`
4. On PREEMPT_RT: `spinlock_t` = sleeping lock ? BUG in atomic context

The commit message notes that "HIGHPTE is rarely needed at all" - it's
an optimization to put page tables in high memory, which is typically
unnecessary on modern systems.

## 3. CLASSIFICATION

- **Bug type**: Runtime crash/BUG (sleeping-while-atomic violation)
- **Not a new feature**: Disables a problematic configuration
  combination
- **Not a security fix**: No CVE or security-sensitive code
- **Build fix category**: No, this is a runtime issue

## 4. SCOPE AND RISK ASSESSMENT

**Scope**:
- 1 file changed (`arch/arm/Kconfig`)
- 1 line modified
- Affects only ARM + PREEMPT_RT + HIGHMEM configurations

**Risk**: **Very low**
- This is a Kconfig dependency change only
- Users who previously had HIGHPTE enabled will now have it disabled on
  PREEMPT_RT
- The workaround is conservative (disable the problematic feature rather
  than complex code fixes)
- Cannot introduce regressions in other code paths

## 5. USER IMPACT

**Affected users**: ARM systems running PREEMPT_RT kernels with HIGHMEM
(systems with >~800MB RAM on 32-bit ARM)

**Severity**: High for affected users
- `get_user_pages_fast()` is a commonly used path for I/O and memory
  management
- Without this fix, users would hit kernel warnings/crashes when GUP
  fast path is used
- This completely breaks PREEMPT_RT usability on affected configurations

## 6. STABILITY INDICATORS

**Review chain is strong**:
- Sebastian Andrzej Siewior (PREEMPT_RT maintainer) developed this
- Arnd Bergmann reworked and reviewed it
- Linus Walleij acked it
- Russell King (ARM maintainer) accepted it

## 7. DEPENDENCY CHECK

This is a standalone Kconfig change. Dependencies:
- `PREEMPT_RT` must exist in the kernel - PREEMPT_RT was merged into
  mainline in kernel 6.12
- `HIGHPTE` and `HIGHMEM` options exist on ARM in all relevant kernel
  versions

The fix should apply cleanly to any stable tree with PREEMPT_RT support.

## STABLE KERNEL CRITERIA EVALUATION

| Criterion | Assessment |
|-----------|------------|
| Obviously correct | ? Yes - disables problematic config combination |
| Fixes real bug | ? Yes - sleeping-while-atomic crash |
| Important issue | ? Yes - crashes on PREEMPT_RT systems |
| Small and contained | ? Yes - 1 line Kconfig change |
| No new features | ? Yes - only disables an option |
| Clean application | ? Yes - simple dependency addition |

## CONCERNS

1. **No explicit stable request**: Maintainers didn't add `Cc: stable`.
   However, the fix is clearly appropriate for stable.
2. **PREEMPT_RT availability**: Only relevant for kernels 6.12+ where
   PREEMPT_RT was merged into mainline.

## CONCLUSION

This commit fixes a real, reproducible crash on ARM PREEMPT_RT systems.
The fix is minimal (1 line), obviously correct (disables problematic
feature combination), well-reviewed by relevant maintainers (ARM, RT),
and carries essentially zero risk. While there's no explicit stable tag,
the technical merits strongly support backporting.

The sleeping-while-atomic bug would make `get_user_pages_fast()`
unusable on affected configurations, which is a serious correctness
issue for PREEMPT_RT users who require deterministic behavior.

**YES**

 arch/arm/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 4fb985b76e97f..70cd3b5b5a059 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1215,7 +1215,7 @@ config HIGHMEM
 
 config HIGHPTE
 	bool "Allocate 2nd-level pagetables from highmem" if EXPERT
-	depends on HIGHMEM
+	depends on HIGHMEM && !PREEMPT_RT
 	default y
 	help
 	  The VM uses one page of physical memory for each page table.
-- 
2.51.0



From sai.krishna.potthuri at amd.com  Thu Dec 11 22:35:09 2025
From: sai.krishna.potthuri at amd.com (Sai Krishna Potthuri)
Date: Fri, 12 Dec 2025 12:05:09 +0530
Subject: [PATCH] mmc: sdhci-of-arasan: Increase CD stable timeout to 2 seconds
Message-ID: <20251212063509.2002910-1-sai.krishna.potthuri@amd.com>

On Xilinx/AMD platforms, the CD stable bit take slightly longer than
one second(about an additional 100ms) to assert after a host
controller reset. Although no functional failure observed with the
existing one second delay but to ensure reliable initialization, increase
the CD stable timeout to 2 seconds.

Fixes: e251709aaddb ("mmc: sdhci-of-arasan: Ensure CD logic stabilization before power-up")
Signed-off-by: Sai Krishna Potthuri <sai.krishna.potthuri at amd.com>
---
 drivers/mmc/host/sdhci-of-arasan.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index b97d042897ad..ab7f0ffe7b4f 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -99,7 +99,7 @@
 #define HIWORD_UPDATE(val, mask, shift) \
 		((val) << (shift) | (mask) << ((shift) + 16))
 
-#define CD_STABLE_TIMEOUT_US		1000000
+#define CD_STABLE_TIMEOUT_US		2000000
 #define CD_STABLE_MAX_SLEEP_US		10
 
 /**
-- 
2.25.1



From cassel at kernel.org  Thu Dec 11 22:37:26 2025
From: cassel at kernel.org (Niklas Cassel)
Date: Fri, 12 Dec 2025 15:37:26 +0900
Subject: [PATCH v2] PCI: dwc: Make Link Up IRQ logic handle already
 powered on PCIe switches
In-Reply-To: <pjn2gs43rqbe3odh6zvh4qaftxxl6qvdzpm6pgpadxeeid42ko@4a2qradscaqd>
References: <20251201063634.4115762-2-cassel@kernel.org>
 <f1059d5d-3fa5-423a-8093-0e99b65d5f4c@oss.qualcomm.com>
 <aTev28wihes6iJqs@dhcp-10-89-81-223>
 <dad4957c-ca13-4742-b46d-03f0478911d5@oss.qualcomm.com>
 <aTe1bA7lcVzFD5L7@dhcp-10-89-81-223>
 <pjn2gs43rqbe3odh6zvh4qaftxxl6qvdzpm6pgpadxeeid42ko@4a2qradscaqd>
Message-ID: <aTu4JgDcfb_58qBK@fedora>

Hello Mani,

On Fri, Dec 12, 2025 at 12:52:35PM +0900, Manivannan Sadhasivam wrote:
> > This patch missed the v6.19 merge window (and so did the pwrctrl rework
> > series), so as long as Mani queues up both for v6.20 (with the pwrctrl
> > rework series getting applied first), I think we are good.
> > 
> 
> The plan is to merge pwrctrl series to v6.20 (unless we get strong objections),
> but once that happens, Qcom doesn't need this patch.
> 
> So it'd be good if you can just limit this patch to just Rockchip. Then once the
> Rockchip also moves to pwrctrl, we can revert this patch (also the whole IRQ
> based link up since the Root Port is not hotplug capable).

The main reason why I did not like a revert, was because it would remove
the nice feature where the bus is enumerated automatically on link up.

I assumed that the plan was to add Link Up IRQ support in pwrctrl in the
future.

If that is not the case, and the plan is instead to eventually remove the
existing Link Up IRQ support, then perhaps you could simply apply patches
from:
https://lore.kernel.org/linux-pci/20251111105100.869997-8-cassel at kernel.org/

Either the whole series or just patch 1 and 2, maintainer's choice :)


Kind regards,
Niklas


From jgg at ziepe.ca  Thu Dec 11 22:40:06 2025
From: jgg at ziepe.ca (Jason Gunthorpe)
Date: Fri, 12 Dec 2025 02:40:06 -0400
Subject: [RFC PATCH] iommu/arm-smmu-v3: Allow stream ID sharing for
 devices behind PCIe-to-PCI bridges
In-Reply-To: <20251211133933.4128100-1-nirmoyd@nvidia.com>
References: <20251211133933.4128100-1-nirmoyd@nvidia.com>
Message-ID: <aTu4xsAApNupRGYC@ziepe.ca>

On Thu, Dec 11, 2025 at 05:39:33AM -0800, Nirmoy Das wrote:
> ASPEED BMC controllers have VGA and USB functions behind a PCIe-to-PCI
> bridge that causes them to share the same stream ID:
> 
>   \-[0005:e0]---00.0-[e1-e2]----00.0-[e2]--+-00.0  ASPEED Graphics Family
>                                            \-02.0  ASPEED USB Controller
> 
> Both devices get stream ID(0x5e200) due to bridge aliasing. Currently this
> USB controller gets rejected with "Aliasing StreamID unsupported", causing
> USB timeout errors. Allow stream ID sharing when both devices are on
> the same bus behind a PCIe-to-PCI bridge to fix this issue.

I don't think this is right, if you actually need stream ID sharing
then I seem to recall the driver needs more changes. We don't want
this in general.

IMHO ASPEED has wrong PCI config space and there isn't any actual PCI
bus here that would force RID aliasing to worry about. I suggest going
to ASPEED to find out and confirm that they don't actually share the
RIDs and then let's quirk the PCI devices to disable alias generation
in the first place.

Also, complain to them to fix their config space to report a PCIe bridge
type in future devices. :)

Jason


From dan.carpenter at linaro.org  Thu Dec 11 22:41:08 2025
From: dan.carpenter at linaro.org (Dan Carpenter)
Date: Fri, 12 Dec 2025 09:41:08 +0300
Subject: [PATCH 1/4] net: stmmac: s32: use the syscon interface
 PHY_INTF_SEL_RGMII
In-Reply-To: <aS3GzJljbfp2xJmW@shell.armlinux.org.uk>
References: <cover.1764592300.git.dan.carpenter@linaro.org>
 <6275e666a7ef78bd4c758d3f7f6fb6f30407393e.1764592300.git.dan.carpenter@linaro.org>
 <aS3GzJljbfp2xJmW@shell.armlinux.org.uk>
Message-ID: <aTu5BB0pMfgzIodh@stanley.mountain>

On Mon, Dec 01, 2025 at 04:48:12PM +0000, Russell King (Oracle) wrote:
> On Mon, Dec 01, 2025 at 04:08:20PM +0300, Dan Carpenter wrote:
> > On the s32 chipset the GMAC_0_CTRL_STS register is in GPR region.
> > Originally, accessing this register was done in a sort of ad-hoc way,
> > but we want to use the syscon interface to do it.
> > 
> > This is a little bit uglier because we to maintain backwards compatibility
> > to the old device trees so we have to support both ways to access this
> > register.
> > 
> > Signed-off-by: Dan Carpenter <dan.carpenter at linaro.org>
> > ---
> >  .../net/ethernet/stmicro/stmmac/dwmac-s32.c   | 23 +++++++++++++++----
> >  1 file changed, 18 insertions(+), 5 deletions(-)
> > 
> > diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c
> > index 5a485ee98fa7..20de761b7d28 100644
> > --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c
> > +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c
> > @@ -11,12 +11,14 @@
> >  #include <linux/device.h>
> >  #include <linux/ethtool.h>
> >  #include <linux/io.h>
> > +#include <linux/mfd/syscon.h>
> >  #include <linux/module.h>
> >  #include <linux/of_mdio.h>
> >  #include <linux/of_address.h>
> >  #include <linux/phy.h>
> >  #include <linux/phylink.h>
> >  #include <linux/platform_device.h>
> > +#include <linux/regmap.h>
> >  #include <linux/stmmac.h>
> >  
> >  #include "stmmac_platform.h"
> > @@ -32,6 +34,8 @@
> >  struct s32_priv_data {
> >  	void __iomem *ioaddr;
> >  	void __iomem *ctrl_sts;
> > +	struct regmap *sts_regmap;
> > +	unsigned int sts_offset;
> >  	struct device *dev;
> >  	phy_interface_t *intf_mode;
> >  	struct clk *tx_clk;
> > @@ -40,7 +44,10 @@ struct s32_priv_data {
> >  
> >  static int s32_gmac_write_phy_intf_select(struct s32_priv_data *gmac)
> >  {
> > -	writel(S32_PHY_INTF_SEL_RGMII, gmac->ctrl_sts);
> > +	if (gmac->ctrl_sts)
> > +		writel(S32_PHY_INTF_SEL_RGMII, gmac->ctrl_sts);
> > +	else
> > +		regmap_write(gmac->sts_regmap, gmac->sts_offset, PHY_INTF_SEL_RGMII);
> 
> Sorry, but even if that regmap_write() is targetting the exact same
> register, these are not identical.
> 
> S32_PHY_INTF_SEL_RGMII, which is a S32-specific value, takes the value 2.
> PHY_INTF_SEL_RGMII is the dwmac specific value, and takes the value 1.
> 
> If this targets the same register, then by writing PHY_INTF_SEL_RGMII,
> you are in effect writing the equivalent of S32_PHY_INTF_SEL_SGMII to
> it. This seems like a bug.
> 

Yeah.  Sorry, I forward ported this, then back ported it, then forward
ported this again and I messed up.  :(

regards,
dan carpenter


From krzk at kernel.org  Thu Dec 11 23:03:52 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 12 Dec 2025 08:03:52 +0100
Subject: [PATCH 1/4] dt-bindings: soc: devapc: Add for support MT8189
In-Reply-To: <176551375433.2514847.16610029422866924600.robh@kernel.org>
References: <20251212031450.489128-1-xiaoshun.xu@mediatek.corp-partner.google.com>
 <20251212031450.489128-2-xiaoshun.xu@mediatek.corp-partner.google.com>
 <176551375433.2514847.16610029422866924600.robh@kernel.org>
Message-ID: <bf3dfa16-b6d5-44ad-bb0b-b1bf2d1c2b6c@kernel.org>

On 12/12/2025 05:29, Rob Herring (Arm) wrote:
> 
> On Fri, 12 Dec 2025 11:13:42 +0800, Xiaoshun Xu wrote:
>>
>> External email : Please do not click links or open attachments until you have verified the sender or the content.
>>
>>
>> From: "xiaoshun.xu" <xiaoshun.xu at mediatek.com>
>>
>> Add compatible and vio-idx-num attribute of MT8189
>>
>> Signed-off-by: xiaoshun.xu <xiaoshun.xu at mediatek.com>
>> ---
>>  Documentation/devicetree/bindings/soc/mediatek/devapc.yaml | 6 ++++++
>>  1 file changed, 6 insertions(+)
>>
> 
> My bot found errors running 'make dt_binding_check' on your patch:
> 
> yamllint warnings/errors:
> 
> dtschema/dtc warnings/errors:
> /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/soc/mediatek/devapc.yaml: vio-idx-num: missing type definition
> 
> doc reference errors (make refcheckdocs):
> 


None of these patches here managed to pass spam checks on my inbox, so I
got only this report. Considering patch containing "External email"
clause in the commit msg, I would say posting was somehow non-standard
or just broken.

That's obviously a no-go and finally mediatek corp-partners need to act
on these poor postings (not an exception here).

Best regards,
Krzysztof


From thomas.perrot at bootlin.com  Thu Dec 11 23:41:03 2025
From: thomas.perrot at bootlin.com (Thomas Perrot (Schneider Electric))
Date: Fri, 12 Dec 2025 08:41:03 +0100
Subject: [PATCH 0/8] Add support for AAEON SRG-IMX8PL MCU
Message-ID: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com>

This patch series introduces support for the AAEON SRG-IMX8PL embedded
controller (MCU). The MCU is connected via I2C and provides GPIO and
watchdog functionality for the SRG-IMX8PL board.

The series includes:
- Device tree bindings for the MFD, GPIO, and watchdog subsystems
- MFD driver that serves as the core driver for the MCU
- GPIO driver implementing the GPIO functionality
- Watchdog driver for system monitoring
- MAINTAINERS entry for the new drivers

The drivers follow the standard Linux kernel subsystem patterns, with
the MFD driver registering the sub-devices (GPIO and watchdog) which
are then handled by their respective subsystem drivers.

Signed-off-by: Thomas Perrot (Schneider Electric) <thomas.perrot at bootlin.com>
---
Thomas Perrot (Schneider Electric) (8):
      dt-bindings: vendor-prefixes: Add AAEON vendor prefix
      dt-bindings: gpio: Add AAEON embedded controller GPIO binding
      dt-bindings: watchdog: Add AAEON embedded controller watchdog binding
      dt-bindings: mfd: Add AAEON embedded controller binding
      mfd: aaeon: Add SRG-IMX8PL MCU driver
      gpio: aaeon: Add GPIO driver for SRG-IMX8PL MCU
      watchdog: aaeon: Add watchdog driver for SRG-IMX8PL MCU
      MAINTAINERS: Add entry for AAEON SRG-IMX8PL MCU driver

 .../bindings/gpio/aaeon,srg-imx8pl-gpio.yaml       |  54 +++++
 .../bindings/mfd/aaeon,srg-imx8pl-mcu.yaml         |  58 +++++
 .../devicetree/bindings/vendor-prefixes.yaml       |   2 +
 .../bindings/watchdog/aaeon,srg-imx8pl-wdt.yaml    |  38 ++++
 MAINTAINERS                                        |   9 +
 drivers/gpio/Kconfig                               |  10 +
 drivers/gpio/Makefile                              |   1 +
 drivers/gpio/gpio-aaeon-mcu.c                      | 248 +++++++++++++++++++++
 drivers/mfd/Kconfig                                |  10 +
 drivers/mfd/aaeon-mcu.c                            | 133 +++++++++++
 drivers/watchdog/Kconfig                           |  10 +
 drivers/watchdog/Makefile                          |   1 +
 drivers/watchdog/aaeon_mcu_wdt.c                   | 140 ++++++++++++
 include/linux/mfd/aaeon-mcu.h                      |  30 +++
 14 files changed, 744 insertions(+)
---
base-commit: d358e5254674b70f34c847715ca509e46eb81e6f
change-id: 20251211-dev-b4-aaeon-mcu-driver-e0e89ebf4afb

Best regards,
-- 
Thomas Perrot (Schneider Electric) <thomas.perrot at bootlin.com>



From thomas.perrot at bootlin.com  Thu Dec 11 23:41:04 2025
From: thomas.perrot at bootlin.com (Thomas Perrot (Schneider Electric))
Date: Fri, 12 Dec 2025 08:41:04 +0100
Subject: [PATCH 1/8] dt-bindings: vendor-prefixes: Add AAEON vendor prefix
In-Reply-To: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com>
References: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com>
Message-ID: <20251212-dev-b4-aaeon-mcu-driver-v1-1-6bd65bc8ef12@bootlin.com>

Add the AAEON vendor prefix to support the AAEON SRG-IMX8PL MCU driver
devicetree bindings.

Signed-off-by: Thomas Perrot (Schneider Electric) <thomas.perrot at bootlin.com>
---
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index c7591b2aec2a74560a4f687fe7a2070ca21b0752..0f84ee93b3a8473719ee92f8c046e350c4a20825 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -32,6 +32,8 @@ patternProperties:
     description: 8devices, UAB
   "^9tripod,.*":
     description: Shenzhen 9Tripod Innovation and Development CO., LTD.
+  "^aaeon,.*":
+    description: AAEON
   "^abb,.*":
     description: ABB
   "^abilis,.*":

-- 
2.52.0



From thomas.perrot at bootlin.com  Thu Dec 11 23:41:05 2025
From: thomas.perrot at bootlin.com (Thomas Perrot (Schneider Electric))
Date: Fri, 12 Dec 2025 08:41:05 +0100
Subject: [PATCH 2/8] dt-bindings: gpio: Add AAEON embedded controller GPIO
 binding
In-Reply-To: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com>
References: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com>
Message-ID: <20251212-dev-b4-aaeon-mcu-driver-v1-2-6bd65bc8ef12@bootlin.com>

Add device tree binding documentation for the GPIO controller functionality
provided by the AAEON embedded controller. This controller provides 7 GPOs
and 12 GPIOs for a total of 19 GPIO lines.

The GPIO controller is defined as a child node of the AAEON MCU device.

Signed-off-by: Thomas Perrot (Schneider Electric) <thomas.perrot at bootlin.com>
---
 .../bindings/gpio/aaeon,srg-imx8pl-gpio.yaml       | 54 ++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/Documentation/devicetree/bindings/gpio/aaeon,srg-imx8pl-gpio.yaml b/Documentation/devicetree/bindings/gpio/aaeon,srg-imx8pl-gpio.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..8040dc0a36ee5650488520c2218f09fd08cdf64a
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/aaeon,srg-imx8pl-gpio.yaml
@@ -0,0 +1,54 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/gpio/aaeon,srg-imx8pl-gpio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: AAEON Embedded Controller GPIO
+
+maintainers:
+  - J?r?mie Dautheribes <jeremie.dautheribes at bootlin.com>
+  - Thomas Perrot <thomas.perrot at bootlin.com>
+
+description: |
+  GPIO controller functionality provided by the AAEON embedded controller.
+  This controller provides 7 GPOs and 12 GPIOs.
+
+  The GPIO controller is a sub-device of the AAEON MCU and must be defined
+  as a child node of the MCU device.
+
+properties:
+  compatible:
+    const: aaeon,srg-imx8pl-gpio
+
+  gpio-controller: true
+
+  "#gpio-cells":
+    const: 2
+    description: |
+      The first cell is the GPIO number (0-6 for GPOs, 7-18 for
+      general-purpose GPIOs).
+      The second cell is the GPIO flags as defined in
+      <dt-bindings/gpio/gpio.h>.
+
+  ngpios:
+    description: |
+      Total number of GPIOs available (GPOs + GPIOs).
+      This should be 19 (7 GPOs + 12 GPIOs).
+    const: 19
+
+required:
+  - compatible
+  - gpio-controller
+  - "#gpio-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    gpio {
+      compatible = "aaeon,srg-imx8pl-gpio";
+      gpio-controller;
+      #gpio-cells = <2>;
+      ngpios = <19>;
+    };

-- 
2.52.0



From thomas.perrot at bootlin.com  Thu Dec 11 23:41:06 2025
From: thomas.perrot at bootlin.com (Thomas Perrot (Schneider Electric))
Date: Fri, 12 Dec 2025 08:41:06 +0100
Subject: [PATCH 3/8] dt-bindings: watchdog: Add AAEON embedded controller
 watchdog binding
In-Reply-To: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com>
References: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com>
Message-ID: <20251212-dev-b4-aaeon-mcu-driver-v1-3-6bd65bc8ef12@bootlin.com>

Add device tree binding documentation for the watchdog timer functionality
provided by the AAEON embedded controller. The watchdog has a maximum
hardware heartbeat of 25 seconds and supports a timeout of up to 240
seconds through automatic pinging.

The watchdog is defined as a child node of the AAEON MCU device.

Signed-off-by: Thomas Perrot (Schneider Electric) <thomas.perrot at bootlin.com>
---
 .../bindings/watchdog/aaeon,srg-imx8pl-wdt.yaml    | 38 ++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/Documentation/devicetree/bindings/watchdog/aaeon,srg-imx8pl-wdt.yaml b/Documentation/devicetree/bindings/watchdog/aaeon,srg-imx8pl-wdt.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d19a2f4fd38826ff4d1ce6b0b7f12e8b6879445f
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/aaeon,srg-imx8pl-wdt.yaml
@@ -0,0 +1,38 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/watchdog/aaeon,srg-imx8pl-wdt.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: AAEON Embedded Controller Watchdog Timer
+
+maintainers:
+  - J?r?mie Dautheribes <jeremie.dautheribes at bootlin.com>
+  - Thomas Perrot <thomas.perrot at bootlin.com>
+
+description: |
+  Watchdog timer functionality provided by the AAEON embedded controller.
+  The watchdog has a fixed maximum hardware heartbeat of 25 seconds and supports
+  a timeout of 240 seconds through automatic pinging. The timeout is not
+  programmable and cannot be changed via device tree properties.
+
+  The watchdog is a sub-device of the AAEON MCU and must be defined as a
+  child node of the MCU device.
+
+allOf:
+  - $ref: watchdog.yaml#
+
+properties:
+  compatible:
+    const: aaeon,srg-imx8pl-wdt
+
+required:
+  - compatible
+
+additionalProperties: false
+
+examples:
+  - |
+    watchdog {
+      compatible = "aaeon,srg-imx8pl-wdt";
+    };

-- 
2.52.0



From thomas.perrot at bootlin.com  Thu Dec 11 23:41:07 2025
From: thomas.perrot at bootlin.com (Thomas Perrot (Schneider Electric))
Date: Fri, 12 Dec 2025 08:41:07 +0100
Subject: [PATCH 4/8] dt-bindings: mfd: Add AAEON embedded controller
 binding
In-Reply-To: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com>
References: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com>
Message-ID: <20251212-dev-b4-aaeon-mcu-driver-v1-4-6bd65bc8ef12@bootlin.com>

Add device tree binding documentation for the AAEON embedded controller
(MCU). This microcontroller is found on AAEON embedded boards and provides
system features such as GPIO control, watchdog timer, and LED management.

The MCU is connected via I2C and acts as a multi-function device with
GPIO and watchdog as child nodes.

Signed-off-by: Thomas Perrot (Schneider Electric) <thomas.perrot at bootlin.com>
---
 .../bindings/mfd/aaeon,srg-imx8pl-mcu.yaml         | 58 ++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/Documentation/devicetree/bindings/mfd/aaeon,srg-imx8pl-mcu.yaml b/Documentation/devicetree/bindings/mfd/aaeon,srg-imx8pl-mcu.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..680d06a7e7cb3754bdfc67a1b8c484811eba55d1
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/aaeon,srg-imx8pl-mcu.yaml
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/aaeon,srg-imx8pl-mcu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: AAEON Embedded Controller
+
+maintainers:
+  - J?r?mie Dautheribes <jeremie.dautheribes at bootlin.com>
+  - Thomas Perrot <thomas.perrot at bootlin.com>
+
+description: |
+  AAEON embeds a microcontroller on their embedded boards providing system
+  features such as GPIO control, watchdog timer, and LED management.
+  The MCU is connected via I2C bus.
+
+properties:
+  compatible:
+    const: aaeon,srg-imx8pl-mcu
+
+  reg:
+    maxItems: 1
+
+  gpio:
+    $ref: /schemas/gpio/aaeon,srg-imx8pl-gpio.yaml
+
+  watchdog:
+    $ref: /schemas/watchdog/aaeon,srg-imx8pl-wdt.yaml
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      aaeon_mcu: embedded-controller at 62 {
+        compatible = "aaeon,srg-imx8pl-mcu";
+        reg = <0x62>;
+
+        gpio {
+          compatible = "aaeon,srg-imx8pl-gpio";
+          gpio-controller;
+          #gpio-cells = <2>;
+          ngpios = <19>;
+        };
+
+        watchdog {
+          compatible = "aaeon,srg-imx8pl-wdt";
+        };
+      };
+    };

-- 
2.52.0



From thomas.perrot at bootlin.com  Thu Dec 11 23:41:08 2025
From: thomas.perrot at bootlin.com (Thomas Perrot (Schneider Electric))
Date: Fri, 12 Dec 2025 08:41:08 +0100
Subject: [PATCH 5/8] mfd: aaeon: Add SRG-IMX8PL MCU driver
In-Reply-To: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com>
References: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com>
Message-ID: <20251212-dev-b4-aaeon-mcu-driver-v1-5-6bd65bc8ef12@bootlin.com>

Add Multi-Function Device (MFD) driver for the Aaeon SRG-IMX8PL
embedded controller. This driver provides the core I2C communication
interface and registers child devices (GPIO and watchdog controllers).

The MCU firmware version is queried during probe and logged for
diagnostic purposes. All I2C transactions are serialized using a mutex
to ensure proper communication with the microcontroller.

Co-developed-by: J?r?mie Dautheribes (Schneider Electric) <jeremie.dautheribes at bootlin.com>
Signed-off-by: J?r?mie Dautheribes (Schneider Electric) <jeremie.dautheribes at bootlin.com>
Signed-off-by: Thomas Perrot (Schneider Electric) <thomas.perrot at bootlin.com>
---
 drivers/mfd/Kconfig           |  10 ++++
 drivers/mfd/aaeon-mcu.c       | 133 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/mfd/aaeon-mcu.h |  30 ++++++++++
 3 files changed, 173 insertions(+)

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index aace5766b38aa5e46e32a8a7b42eea238159fbcf..9195115c7bcd619439cb9ff71d70e46629291867 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1574,6 +1574,16 @@ config AB8500_CORE
 	  the irq_chip parts for handling the Mixed Signal chip events.
 	  This chip embeds various other multimedia functionalities as well.
 
+config MFD_AAEON_MCU
+	tristate "Aaeon SRG-IMX8PL MCU Driver"
+	depends on I2C
+	select MFD_CORE
+	help
+	  Select this option to enable support for the Aaeon SRG-IMX8PL
+	  onboard microcontroller (MCU). This driver provides the core
+	  functionality to communicate with the MCU over I2C. The MCU
+	  provides various sub-devices including GPIO and watchdog controllers.
+
 config MFD_DB8500_PRCMU
 	bool "ST-Ericsson DB8500 Power Reset Control Management Unit"
 	depends on UX500_SOC_DB8500
diff --git a/drivers/mfd/aaeon-mcu.c b/drivers/mfd/aaeon-mcu.c
new file mode 100644
index 0000000000000000000000000000000000000000..472d44d5e8627f46806015599542753a5bda4526
--- /dev/null
+++ b/drivers/mfd/aaeon-mcu.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Aaeon MCU MFD driver
+ *
+ * Copyright (C) 2025 Bootlin
+ * Author: J?r?mie Dautheribes <jeremie.dautheribes at bootlin.com>
+ * Author: Thomas Perrot <thomas.perrot at bootlin.com>
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/aaeon-mcu.h>
+
+#define AAEON_MCU_GET_FW_VERSION 0x76
+
+static struct mfd_cell aaeon_mcu_devs[] = {
+	{
+		.name = "aaeon-mcu-wdt",
+		.of_compatible = "aaeon,srg-imx8pl-wdt",
+	},
+	{
+		.name = "aaeon-mcu-gpio",
+		.of_compatible = "aaeon,srg-imx8pl-gpio",
+	},
+};
+
+static int aaeon_mcu_print_fw_version(struct i2c_client *client)
+{
+	u8 cmd[3], version[2];
+	int ret;
+
+	/* Major version number */
+	cmd[0] = AAEON_MCU_GET_FW_VERSION;
+	cmd[1] = 0x00;
+	cmd[2] = 0x00;
+
+	ret = aaeon_mcu_i2c_xfer(client, cmd, 3, &version[0], 1);
+	if (ret < 0)
+		return ret;
+
+	/* Minor version number */
+	cmd[0] = AAEON_MCU_GET_FW_VERSION;
+	cmd[1] = 0x01;
+	/* cmd[2] = 0x00; */
+
+	ret = aaeon_mcu_i2c_xfer(client, cmd, 3, &version[1], 1);
+	if (ret < 0)
+		return ret;
+
+	dev_info(&client->dev, "firmware version: v%d.%d\n",
+		 version[0], version[1]);
+
+	return 0;
+}
+
+static int aaeon_mcu_probe(struct i2c_client *client)
+{
+	struct aaeon_mcu_dev *mcu;
+	int ret;
+
+	mcu = devm_kzalloc(&client->dev, sizeof(*mcu), GFP_KERNEL);
+	if (!mcu)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, mcu);
+	mcu->dev = &client->dev;
+	mcu->i2c_client = client;
+	mutex_init(&mcu->i2c_lock);
+
+	ret = aaeon_mcu_print_fw_version(client);
+	if (ret) {
+		dev_err(&client->dev, "unable to read firmware version\n");
+		return ret;
+	}
+
+	return devm_mfd_add_devices(mcu->dev, PLATFORM_DEVID_NONE, aaeon_mcu_devs,
+				    ARRAY_SIZE(aaeon_mcu_devs), NULL, 0, NULL);
+}
+
+int aaeon_mcu_i2c_xfer(struct i2c_client *client,
+		       const u8 *cmd, int cmd_len,
+		       u8 *rsp, int rsp_len)
+{
+	struct aaeon_mcu_dev *mcu = i2c_get_clientdata(client);
+	int ret;
+
+	mutex_lock(&mcu->i2c_lock);
+
+	ret = i2c_master_send(client, cmd, cmd_len);
+	if (ret < 0)
+		goto unlock;
+
+	ret = i2c_master_recv(client, rsp, rsp_len);
+	if (ret < 0)
+		goto unlock;
+
+	if (ret != rsp_len) {
+		dev_err(&client->dev,
+			"i2c recv count error (expected: %d, actual: %d)\n",
+			rsp_len, ret);
+		ret = -EIO;
+		goto unlock;
+	}
+
+	ret = 0;
+
+unlock:
+	mutex_unlock(&mcu->i2c_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(aaeon_mcu_i2c_xfer);
+
+static const struct of_device_id aaeon_mcu_of_match[] = {
+	{ .compatible = "aaeon,srg-imx8pl-mcu" },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, aaeon_mcu_of_match);
+
+static struct i2c_driver aaeon_mcu_driver = {
+	.driver = {
+		.name = "aaeon_mcu",
+		.of_match_table = aaeon_mcu_of_match,
+	},
+	.probe = aaeon_mcu_probe,
+};
+
+module_i2c_driver(aaeon_mcu_driver);
+
+MODULE_DESCRIPTION("Aaeon MCU MFD Driver");
+MODULE_AUTHOR("J?r?mie Dautheribes");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/aaeon-mcu.h b/include/linux/mfd/aaeon-mcu.h
new file mode 100644
index 0000000000000000000000000000000000000000..89632cb46bc6c9518755dc43afb87faa94acb6f5
--- /dev/null
+++ b/include/linux/mfd/aaeon-mcu.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Aaeon MCU driver definitions
+ *
+ * Copyright (C) 2025 Bootlin
+ * Author: J?r?mie Dautheribes <jeremie.dautheribes at bootlin.com>
+ * Author: Thomas Perrot <thomas.perrot at bootlin.com>
+ */
+
+#ifndef __LINUX_MFD_AAEON_MCU_H
+#define __LINUX_MFD_AAEON_MCU_H
+
+/**
+ * struct aaeon_mcu_dev - Internal representation of the Aaeon MCU
+ * @dev: Pointer to kernel device structure
+ * @i2c_client: Pointer to the Aaeon MCU I2C client
+ * @i2c_lock: Mutex to serialize I2C bus access
+ */
+
+struct aaeon_mcu_dev {
+	struct device *dev;
+	struct i2c_client *i2c_client;
+	struct mutex i2c_lock;
+};
+
+int aaeon_mcu_i2c_xfer(struct i2c_client *client,
+		       const u8 *cmd, int cmd_len,
+		       u8 *rsp, int rsp_len);
+
+#endif /*  __LINUX_MFD_AAEON_MCU_H */

-- 
2.52.0



From thomas.perrot at bootlin.com  Thu Dec 11 23:41:11 2025
From: thomas.perrot at bootlin.com (Thomas Perrot (Schneider Electric))
Date: Fri, 12 Dec 2025 08:41:11 +0100
Subject: [PATCH 8/8] MAINTAINERS: Add entry for AAEON SRG-IMX8PL MCU driver
In-Reply-To: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com>
References: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com>
Message-ID: <20251212-dev-b4-aaeon-mcu-driver-v1-8-6bd65bc8ef12@bootlin.com>

Add maintainer entry for the Aaeon SRG-IMX8PL MCU MFD driver and its
sub-device drivers (GPIO and watchdog).

Signed-off-by: Thomas Perrot (Schneider Electric) <thomas.perrot at bootlin.com>
---
 MAINTAINERS | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index c9e416ba74c64e90629c0b7d7941f879c9ac589e..13a4eced229acd970b9e5de864a441f28fa2aa91 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -186,6 +186,15 @@ W:	http://www.adaptec.com/
 F:	Documentation/scsi/aacraid.rst
 F:	drivers/scsi/aacraid/
 
+AAEON SRG-IMX8PL CONTROLLER MFD DRIVER
+M:	Thomas Perrot <thomas.perrot at bootlin.com>
+R:	J?r?mie Dautheribes <jeremie.dautheribes at bootlin.com>
+S:	Maintained
+F:	drivers/gpio/gpio-aaeon-mcu.c
+F:	drivers/mfd/aaeon-mcu.c
+F:	drivers/watchdog/aaeon_mcu_wdt.c
+F:	include/linux/mfd/aaeon-mcu.h
+
 AAEON UPBOARD FPGA MFD DRIVER
 M:	Thomas Richard <thomas.richard at bootlin.com>
 S:	Maintained

-- 
2.52.0



From thomas.perrot at bootlin.com  Thu Dec 11 23:41:10 2025
From: thomas.perrot at bootlin.com (Thomas Perrot (Schneider Electric))
Date: Fri, 12 Dec 2025 08:41:10 +0100
Subject: [PATCH 7/8] watchdog: aaeon: Add watchdog driver for SRG-IMX8PL
 MCU
In-Reply-To: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com>
References: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com>
Message-ID: <20251212-dev-b4-aaeon-mcu-driver-v1-7-6bd65bc8ef12@bootlin.com>

Add watchdog driver for the Aaeon SRG-IMX8PL embedded controller.
This driver provides system monitoring and recovery capabilities
through the MCU's watchdog timer.

The watchdog supports start, stop, and ping operations with a maximum
hardware heartbeat of 25 seconds and a default timeout of 240 seconds.
The driver assumes the watchdog is already running at probe time, as
the MCU typically enables it by default.

Co-developed-by: J?r?mie Dautheribes (Schneider Electric) <jeremie.dautheribes at bootlin.com>
Signed-off-by: J?r?mie Dautheribes (Schneider Electric) <jeremie.dautheribes at bootlin.com>
Signed-off-by: Thomas Perrot (Schneider Electric) <thomas.perrot at bootlin.com>
---
 drivers/watchdog/Kconfig         |  10 +++
 drivers/watchdog/Makefile        |   1 +
 drivers/watchdog/aaeon_mcu_wdt.c | 140 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 151 insertions(+)

diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index d3b9df7d466b0b7215ee87b3040811d44ee53d2a..1bd4a7bee303e5e2508f540dc2c16e9e19ed18b0 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -168,6 +168,16 @@ config SOFT_WATCHDOG_PRETIMEOUT
 	  watchdog. Be aware that governors might affect the watchdog because it
 	  is purely software, e.g. the panic governor will stall it!
 
+config AAEON_MCU_WATCHDOG
+	tristate "Aaeon MCU Watchdog"
+	depends on MFD_AAEON_MCU
+	select WATCHDOG_CORE
+	help
+	  Select this option to enable watchdog timer support for the Aaeon
+	  SRG-IMX8PL onboard microcontroller (MCU). This driver provides
+	  watchdog functionality through the MCU, allowing system monitoring
+	  and automatic recovery from system hangs.
+
 config BD957XMUF_WATCHDOG
 	tristate "ROHM BD9576MUF and BD9573MUF PMIC Watchdog"
 	depends on MFD_ROHM_BD957XMUF
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index ba52099b125398a32f80dad23317e223cc4af028..2deec425d3eafb6b208e061fda9f216f4baa8ecc 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
 # ALPHA Architecture
 
 # ARM Architecture
+obj-$(CONFIG_AAEON_MCU_WATCHDOG) += aaeon_mcu_wdt.o
 obj-$(CONFIG_ARM_SP805_WATCHDOG) += sp805_wdt.o
 obj-$(CONFIG_ARM_SBSA_WATCHDOG) += sbsa_gwdt.o
 obj-$(CONFIG_ARMADA_37XX_WATCHDOG) += armada_37xx_wdt.o
diff --git a/drivers/watchdog/aaeon_mcu_wdt.c b/drivers/watchdog/aaeon_mcu_wdt.c
new file mode 100644
index 0000000000000000000000000000000000000000..8413ea3bce99585d989cf13e4494e8daff2d9e4c
--- /dev/null
+++ b/drivers/watchdog/aaeon_mcu_wdt.c
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Aaeon MCU Watchdog driver
+ *
+ * Copyright (C) 2025 Bootlin
+ * Author: J?r?mie Dautheribes <jeremie.dautheribes at bootlin.com>
+ * Author: Thomas Perrot <thomas.perrot at bootlin.com>
+ */
+
+#include <linux/i2c.h>
+#include <linux/mfd/aaeon-mcu.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+
+#define AAEON_MCU_CONTROL_WDT 0x63
+#define AAEON_MCU_PING_WDT 0x73
+
+#define AAEON_MCU_WDT_TIMEOUT         240
+#define AAEON_MCU_WDT_HEARTBEAT_MS    25000
+
+struct aaeon_mcu_wdt {
+	struct watchdog_device wdt;
+	struct aaeon_mcu_dev *mfd;
+};
+
+static int aaeon_mcu_wdt_start_cmd(struct aaeon_mcu_wdt *data)
+{
+	u8 cmd[3], rsp;
+
+	cmd[0] = AAEON_MCU_CONTROL_WDT;
+	cmd[1] = 0x01;
+	cmd[2] = 0x00;
+
+	return aaeon_mcu_i2c_xfer(data->mfd->i2c_client, cmd, 3, &rsp, 1);
+}
+
+static int aaeon_mcu_wdt_start(struct watchdog_device *wdt)
+{
+	struct aaeon_mcu_wdt *data = watchdog_get_drvdata(wdt);
+
+	return aaeon_mcu_wdt_start_cmd(data);
+}
+
+static int aaeon_mcu_wdt_stop_cmd(struct aaeon_mcu_wdt *data)
+{
+	u8 cmd[3], rsp;
+
+	cmd[0] = AAEON_MCU_CONTROL_WDT;
+	cmd[1] = 0x00;
+	cmd[2] = 0x00;
+
+	return aaeon_mcu_i2c_xfer(data->mfd->i2c_client, cmd, 3, &rsp, 1);
+}
+
+static int aaeon_mcu_wdt_stop(struct watchdog_device *wdt)
+{
+	struct aaeon_mcu_wdt *data = watchdog_get_drvdata(wdt);
+
+	return aaeon_mcu_wdt_stop_cmd(data);
+}
+
+static int aaeon_mcu_wdt_ping_cmd(struct aaeon_mcu_wdt *data)
+{
+	u8 cmd[3], rsp;
+
+	cmd[0] = AAEON_MCU_PING_WDT;
+	cmd[1] = 0x00;
+	cmd[2] = 0x00;
+
+	return aaeon_mcu_i2c_xfer(data->mfd->i2c_client, cmd, 3, &rsp, 1);
+}
+
+static int aaeon_mcu_wdt_ping(struct watchdog_device *wdt)
+{
+	struct aaeon_mcu_wdt *data = watchdog_get_drvdata(wdt);
+
+	return aaeon_mcu_wdt_ping_cmd(data);
+}
+
+static const struct watchdog_info aaeon_mcu_wdt_info = {
+	.identity	= "Aaeon MCU Watchdog",
+	.options	= WDIOF_KEEPALIVEPING
+};
+
+static const struct watchdog_ops aaeon_mcu_wdt_ops = {
+	.owner		= THIS_MODULE,
+	.start		= aaeon_mcu_wdt_start,
+	.stop		= aaeon_mcu_wdt_stop,
+	.ping		= aaeon_mcu_wdt_ping,
+};
+
+static int aaeon_mcu_wdt_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct aaeon_mcu_dev *mcu = dev_get_drvdata(dev->parent);
+	struct watchdog_device *wdt;
+	struct aaeon_mcu_wdt *data;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->mfd = mcu;
+
+	wdt = &data->wdt;
+	wdt->parent = dev;
+
+	wdt->info = &aaeon_mcu_wdt_info;
+	wdt->ops = &aaeon_mcu_wdt_ops;
+	wdt->max_hw_heartbeat_ms = AAEON_MCU_WDT_HEARTBEAT_MS;
+	watchdog_init_timeout(wdt, AAEON_MCU_WDT_TIMEOUT, dev);
+
+	watchdog_set_drvdata(wdt, data);
+	platform_set_drvdata(pdev, data);
+	set_bit(WDOG_HW_RUNNING, &wdt->status);
+
+	return devm_watchdog_register_device(dev, wdt);
+}
+
+static const struct of_device_id aaeon_mcu_wdt_of_match[] = {
+	{ .compatible = "aaeon,srg-imx8pl-wdt" },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, aaeon_mcu_wdt_of_match);
+
+static struct platform_driver aaeon_mcu_wdt_driver = {
+	.driver		= {
+		.name	= "aaeon-mcu-wdt",
+		.of_match_table = aaeon_mcu_wdt_of_match,
+	},
+	.probe		= aaeon_mcu_wdt_probe,
+};
+
+module_platform_driver(aaeon_mcu_wdt_driver);
+
+MODULE_DESCRIPTION("Aaeon MCU Watchdog Driver");
+MODULE_AUTHOR("J?r?mie Dautheribes");
+MODULE_LICENSE("GPL");

-- 
2.52.0



From thomas.perrot at bootlin.com  Thu Dec 11 23:41:09 2025
From: thomas.perrot at bootlin.com (Thomas Perrot (Schneider Electric))
Date: Fri, 12 Dec 2025 08:41:09 +0100
Subject: [PATCH 6/8] gpio: aaeon: Add GPIO driver for SRG-IMX8PL MCU
In-Reply-To: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com>
References: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com>
Message-ID: <20251212-dev-b4-aaeon-mcu-driver-v1-6-6bd65bc8ef12@bootlin.com>

Add GPIO driver for the Aaeon SRG-IMX8PL embedded controller. This
driver supports 7 GPO (General Purpose Output) pins and 12 GPIO pins
that can be configured as inputs or outputs.

The driver implements proper state management for GPO pins (which are
output-only) and full direction control for GPIO pins. During probe,
all pins are reset to a known state (GPOs low, GPIOs as inputs) to
prevent undefined behavior across system reboots, as the MCU does not
reset GPIO states on soft reboot.

Co-developed-by: J?r?mie Dautheribes (Schneider Electric) <jeremie.dautheribes at bootlin.com>
Signed-off-by: J?r?mie Dautheribes (Schneider Electric) <jeremie.dautheribes at bootlin.com>
Signed-off-by: Thomas Perrot (Schneider Electric) <thomas.perrot at bootlin.com>
---
 drivers/gpio/Kconfig          |  10 ++
 drivers/gpio/Makefile         |   1 +
 drivers/gpio/gpio-aaeon-mcu.c | 248 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 259 insertions(+)

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index c74da29253e810b51540684b1186e8f274066b69..7e0f675b664fa25243fc2802edc3380572c94c41 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -157,6 +157,16 @@ config GPIO_74XX_MMIO
 	    8 bits:	74244 (Input), 74273 (Output)
 	    16 bits:	741624 (Input), 7416374 (Output)
 
+config GPIO_AAEON_MCU
+	tristate "Aaeon MCU GPIO support"
+	depends on MFD_AAEON_MCU && OF_GPIO
+	select GPIO_GENERIC
+	help
+	  Select this option to enable GPIO support for the Aaeon SRG-IMX8PL
+	  onboard MCU. This driver provides access to GPIO pins and GPO
+	  (General Purpose Output) pins controlled by the microcontroller.
+	  The driver handles both input and output configuration.
+
 config GPIO_ALTERA
 	tristate "Altera GPIO"
 	select GPIOLIB_IRQCHIP
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 2421a8fd3733e0b06c2581262aaa9cd629f66c7d..1ba6318bc558743fbe5910966c2c8fc3f792efe9 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_GPIO_104_IDI_48)		+= gpio-104-idi-48.o
 obj-$(CONFIG_GPIO_104_IDIO_16)		+= gpio-104-idio-16.o
 obj-$(CONFIG_GPIO_74X164)		+= gpio-74x164.o
 obj-$(CONFIG_GPIO_74XX_MMIO)		+= gpio-74xx-mmio.o
+obj-$(CONFIG_GPIO_AAEON_MCU)		+= gpio-aaeon-mcu.o
 obj-$(CONFIG_GPIO_ADNP)			+= gpio-adnp.o
 obj-$(CONFIG_GPIO_ADP5520)		+= gpio-adp5520.o
 obj-$(CONFIG_GPIO_ADP5585)		+= gpio-adp5585.o
diff --git a/drivers/gpio/gpio-aaeon-mcu.c b/drivers/gpio/gpio-aaeon-mcu.c
new file mode 100644
index 0000000000000000000000000000000000000000..cebd17d1877147b987ea673b081334c8062f5fc0
--- /dev/null
+++ b/drivers/gpio/gpio-aaeon-mcu.c
@@ -0,0 +1,248 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Aaeon MCU GPIO driver
+ *
+ * Copyright (C) 2025 Bootlin
+ * Author: J?r?mie Dautheribes <jeremie.dautheribes at bootlin.com>
+ * Author: Thomas Perrot <thomas.perrot at bootlin.com>
+ */
+
+#include <linux/bitmap.h>
+#include <linux/gpio/driver.h>
+#include <linux/mfd/aaeon-mcu.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#define AAEON_MCU_CONFIG_GPIO_INPUT 0x69
+#define AAEON_MCU_CONFIG_GPIO_OUTPUT 0x6F
+#define AAEON_MCU_READ_GPIO 0x72
+#define AAEON_MCU_WRITE_GPIO 0x77
+
+#define AAEON_MCU_CONTROL_GPO 0x6C
+
+#define MAX_GPIOS 12
+#define MAX_GPOS 7
+
+struct aaeon_mcu_gpio {
+	struct gpio_chip gc;
+	struct aaeon_mcu_dev *mfd;
+	DECLARE_BITMAP(dir_in, MAX_GPOS + MAX_GPIOS);
+	DECLARE_BITMAP(gpo_state, MAX_GPOS);
+};
+
+static int aaeon_mcu_gpio_config_input_cmd(struct aaeon_mcu_gpio *data,
+					    unsigned int offset)
+{
+	u8 cmd[3], rsp;
+
+	cmd[0] = AAEON_MCU_CONFIG_GPIO_INPUT;
+	cmd[1] = offset - 7;
+	cmd[2] = 0x00;
+
+	return aaeon_mcu_i2c_xfer(data->mfd->i2c_client, cmd, 3, &rsp, 1);
+}
+
+static int aaeon_mcu_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)
+{
+	struct aaeon_mcu_gpio *data = gpiochip_get_data(gc);
+	int ret;
+
+	if (offset < MAX_GPOS) {
+		dev_err(gc->parent, "GPIO offset (%d) must be an output GPO\n", offset);
+		return -EOPNOTSUPP;
+	}
+
+	ret = aaeon_mcu_gpio_config_input_cmd(data, offset);
+	if (ret < 0)
+		return ret;
+
+	set_bit(offset, data->dir_in);
+
+	return 0;
+}
+
+static int aaeon_mcu_gpio_config_output_cmd(struct aaeon_mcu_gpio *data,
+					     unsigned int offset,
+					     int value)
+{
+	u8 cmd[3], rsp;
+	int ret;
+
+	cmd[0] = AAEON_MCU_CONFIG_GPIO_OUTPUT;
+	cmd[1] = offset - 7;
+	cmd[2] = 0x00;
+
+	ret = aaeon_mcu_i2c_xfer(data->mfd->i2c_client, cmd, 3, &rsp, 1);
+	if (ret < 0)
+		return ret;
+
+	cmd[0] = AAEON_MCU_WRITE_GPIO;
+	/* cmd[1] = offset - 7; */
+	cmd[2] = !!value;
+
+	return aaeon_mcu_i2c_xfer(data->mfd->i2c_client, cmd, 3, &rsp, 1);
+}
+
+static int aaeon_mcu_gpio_direction_output(struct gpio_chip *gc, unsigned int offset, int value)
+{
+	struct aaeon_mcu_gpio *data = gpiochip_get_data(gc);
+	int ret;
+
+	if (offset < MAX_GPOS)
+		return 0;
+
+	ret = aaeon_mcu_gpio_config_output_cmd(data, offset, value);
+	if (ret < 0)
+		return ret;
+
+	clear_bit(offset, data->dir_in);
+
+	return 0;
+}
+
+static int aaeon_mcu_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+	struct aaeon_mcu_gpio *data = gpiochip_get_data(gc);
+
+	return test_bit(offset, data->dir_in) ?
+		GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT;
+}
+
+static int aaeon_mcu_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+	struct aaeon_mcu_gpio *data = gpiochip_get_data(gc);
+	u8 cmd[3], rsp;
+	int ret;
+
+	if (offset < MAX_GPOS)
+		return test_bit(offset, data->gpo_state);
+
+	cmd[0] = AAEON_MCU_READ_GPIO;
+	cmd[1] = offset - 7;
+	cmd[2] = 0x00;
+
+	ret = aaeon_mcu_i2c_xfer(data->mfd->i2c_client, cmd, 3, &rsp, 1);
+	if (ret < 0)
+		return ret;
+
+	return rsp;
+}
+
+static int aaeon_mcu_gpo_set_cmd(struct aaeon_mcu_gpio *data, unsigned int offset, int value)
+{
+	u8 cmd[3], rsp;
+
+	cmd[0] = AAEON_MCU_CONTROL_GPO;
+	cmd[1] = offset + 1;
+	cmd[2] = !!value;
+
+	return aaeon_mcu_i2c_xfer(data->mfd->i2c_client, cmd, 3, &rsp, 1);
+}
+
+static int aaeon_mcu_gpio_set_cmd(struct aaeon_mcu_gpio *data, unsigned int offset, int value)
+{
+	u8 cmd[3], rsp;
+
+	cmd[0] = AAEON_MCU_WRITE_GPIO;
+	cmd[1] = offset - 7;
+	cmd[2] = !!value;
+
+	return aaeon_mcu_i2c_xfer(data->mfd->i2c_client, cmd, 3, &rsp, 1);
+}
+
+static int aaeon_mcu_gpio_set(struct gpio_chip *gc, unsigned int offset,
+			      int value)
+{
+	struct aaeon_mcu_gpio *data = gpiochip_get_data(gc);
+
+	if (offset < MAX_GPOS) {
+		if (aaeon_mcu_gpo_set_cmd(data, offset, value) == 0)
+			assign_bit(offset, data->gpo_state, value);
+	} else {
+		return aaeon_mcu_gpio_set_cmd(data, offset, value);
+	}
+	return 0;
+}
+
+static const struct gpio_chip aaeon_mcu_chip = {
+	.label			= "gpio-aaeon-mcu",
+	.owner			= THIS_MODULE,
+	.get_direction		= aaeon_mcu_gpio_get_direction,
+	.direction_input	= aaeon_mcu_gpio_direction_input,
+	.direction_output	= aaeon_mcu_gpio_direction_output,
+	.get			= aaeon_mcu_gpio_get,
+	.set			= aaeon_mcu_gpio_set,
+	.base			= -1,
+	.ngpio			= MAX_GPOS + MAX_GPIOS,
+	.can_sleep		= true,
+};
+
+static void aaeon_mcu_gpio_reset(struct aaeon_mcu_gpio *data, struct device *dev)
+{
+	unsigned int i;
+	int ret;
+
+	/* Reset all GPOs */
+	for (i = 0; i < MAX_GPOS; i++) {
+		ret = aaeon_mcu_gpo_set_cmd(data, i, 0);
+		if (ret < 0)
+			dev_warn(dev, "Failed to reset GPO %u state: %d\n", i, ret);
+		clear_bit(i, data->dir_in);
+	}
+
+	/* Reset all GPIOs */
+	for (i = MAX_GPOS; i < MAX_GPOS + MAX_GPIOS; i++) {
+		ret = aaeon_mcu_gpio_config_input_cmd(data, i);
+		if (ret < 0)
+			dev_warn(dev, "Failed to reset GPIO %u state: %d\n", i, ret);
+		set_bit(i, data->dir_in);
+	}
+}
+
+static int aaeon_mcu_gpio_probe(struct platform_device *pdev)
+{
+	struct aaeon_mcu_dev *mfd = dev_get_drvdata(pdev->dev.parent);
+	struct aaeon_mcu_gpio *data;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->mfd = mfd;
+	data->gc = aaeon_mcu_chip;
+	data->gc.parent = &pdev->dev;
+
+	/*
+	 * Reset all GPIO states to a known configuration. The MCU does not
+	 * reset GPIO state on soft reboot, only on power cycle (hard reboot).
+	 * Without this reset, GPIOs would retain their previous state across
+	 * reboots, which could lead to unexpected behavior.
+	 */
+	aaeon_mcu_gpio_reset(data, &pdev->dev);
+
+	platform_set_drvdata(pdev, data);
+
+	return devm_gpiochip_add_data(&pdev->dev, &data->gc,
+				      data);
+}
+
+static const struct of_device_id aaeon_mcu_gpio_of_match[] = {
+	{ .compatible = "aaeon,srg-imx8pl-gpio" },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, aaeon_mcu_gpio_of_match);
+
+static struct platform_driver aaeon_mcu_gpio_driver = {
+	.driver = {
+		.name = "aaeon-mcu-gpio",
+		.of_match_table = aaeon_mcu_gpio_of_match,
+	},
+	.probe = aaeon_mcu_gpio_probe,
+};
+
+module_platform_driver(aaeon_mcu_gpio_driver);
+
+MODULE_DESCRIPTION("GPIO interface for Aaeon MCU");
+MODULE_AUTHOR("J?r?mie Dautherbes <jeremie.dautheribes at bootlin.com>");
+MODULE_LICENSE("GPL");

-- 
2.52.0



From richard.genoud at bootlin.com  Thu Dec 11 23:50:31 2025
From: richard.genoud at bootlin.com (Richard GENOUD)
Date: Fri, 12 Dec 2025 08:50:31 +0100
Subject: [PATCH 1/4] dt-bindings: pwm: sunxi: add PWM controller for
 Allwinner H616
In-Reply-To: <20251208-gorgeous-capuchin-of-protection-4ad0c2@quoll>
References: <20251205100239.1563353-1-richard.genoud@bootlin.com>
 <20251205100239.1563353-2-richard.genoud@bootlin.com>
 <20251208-gorgeous-capuchin-of-protection-4ad0c2@quoll>
Message-ID: <4d34658b-874d-4681-95c1-616f5b385550@bootlin.com>

Hi Krzysztof,

Le 08/12/2025 ? 07:52, Krzysztof Kozlowski a ?crit?:
> On Fri, Dec 05, 2025 at 11:02:36AM +0100, Richard Genoud wrote:
>> Allwinner H616 SoC contains a PWM controller quite different from the A10.
>> It has 6 channels than can generate PWM waveforms or clocks if bypass is
>> enabled.
>>
>> Signed-off-by: Richard Genoud <richard.genoud at bootlin.com>
>> ---
>>   .../pwm/allwinner,sun50i-h616-pwm.yaml        | 67 +++++++++++++++++++
>>   1 file changed, 67 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/pwm/allwinner,sun50i-h616-pwm.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/pwm/allwinner,sun50i-h616-pwm.yaml b/Documentation/devicetree/bindings/pwm/allwinner,sun50i-h616-pwm.yaml
>> new file mode 100644
>> index 000000000000..b89735ad3a43
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/pwm/allwinner,sun50i-h616-pwm.yaml
>> @@ -0,0 +1,67 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/pwm/allwinner,sun50i-h616-pwm.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Allwinner H616 PWM
>> +
>> +maintainers:
>> +  - Richard Genoud <richard.genoud at bootlin.com>
>> +
>> +description: |
> 
> Do not need '|' unless you need to preserve formatting.
Ok, I was thinking that it was nicer with the formatting.

> 
>> +  Allwinner H616 PWM can generate standard PWM signals with variable pulse width
>> +  and period.
>> +  Also, instead of a PWM signal, a channel can be used to provide a clock.
>> +
>> +properties:
>> +  compatible:
>> +    const: allwinner,sun50i-h616-pwm
>> +
>> +  reg:
>> +    maxItems: 1
>> +
>> +  clocks:
>> +    items:
>> +      - description: Bus Clock
>> +
> 
> Are you sure there is no first clock? Really, really sure? If you add it
> later, I would be pretty sad, because that's unnecessary duplication of
> binidngs....
I surely don't want to make you sad :)

Having a second look at the sun4i binding, I think there's a way to use it.
The sun4i, as you said, has a module clock (OSC24M) and an optional bus 
clock.
Here, the bus clock is mandatory, but the H616 PWM uses OSC24M and APB1 
as clock sources.

So, I guess that if we add something like that:
    clocks:
      minItems: 1
      items:
        - description: Module Clock
        - description: Bus Clock
+      - description: APB Clock

    clock-names:
      minItems: 1
      items:
        - const: mod
        - const: bus
+      - const: apb

    resets:
      maxItems: 1

In the sun4i pwm binding, we could re-use it for the H616 pwm right?
(APB clock is maybe not the best name, could be secondary module clock)

> 
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
> 
> Best regards,
> Krzysztof
> 
Thanks for your review!

Regards,
Richard



From peng.fan at oss.nxp.com  Thu Dec 11 23:51:13 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Fri, 12 Dec 2025 15:51:13 +0800
Subject: [PATCH 0/3] thermal/drivers/imx91: minor updates
Message-ID: <20251212-imx91-thermal-v1-0-c208545b44cb@nxp.com>

patch 1: wait status ready before reading data
patch 2 and 3: minor cleanup

Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
Peng Fan (3):
      thermal/drivers/imx91: Check status before reading data
      thermal/drivers/imx91: Drop extra spaces
      thermal/drivers/imx91: Drop macro for continues mode

 drivers/thermal/imx91_thermal.c | 31 ++++++++++++++++++++-----------
 1 file changed, 20 insertions(+), 11 deletions(-)
---
base-commit: 008d3547aae5bc86fac3eda317489169c3fda112
change-id: 20251211-imx91-thermal-a0d185587349

Best regards,
-- 
Peng Fan <peng.fan at nxp.com>



From peng.fan at oss.nxp.com  Thu Dec 11 23:51:14 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Fri, 12 Dec 2025 15:51:14 +0800
Subject: [PATCH 1/3] thermal/drivers/imx91: Check status before reading
 data
In-Reply-To: <20251212-imx91-thermal-v1-0-c208545b44cb@nxp.com>
References: <20251212-imx91-thermal-v1-0-c208545b44cb@nxp.com>
Message-ID: <20251212-imx91-thermal-v1-1-c208545b44cb@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

Per periodic mode from reference mannual:
Write 1b to CTRL1[START]. Wait until STATm[DRDYn] becomes 1.
Read DATAn[DATA_VAL]. It clears the corresponding STATm[DRDYn].
DATAn[DATA_VAL] and STATm[DRDYn_IF] keep refreshing at a periodic interval
of time, corresponding to PERIOD_CTRL[MEAS_FREQ].

Need to check STAT[DRDY] before reading the DATA register.

And check the returned temperature to make sure it fits into the supported
range (-40?C to +125?C).

Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 drivers/thermal/imx91_thermal.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/thermal/imx91_thermal.c b/drivers/thermal/imx91_thermal.c
index 9b20be03d6dec18553967548d0ca31d1c1fb387c..77e8e6a921c6af308b830c36721293c007256ca6 100644
--- a/drivers/thermal/imx91_thermal.c
+++ b/drivers/thermal/imx91_thermal.c
@@ -108,10 +108,20 @@ static int imx91_tmu_get_temp(struct thermal_zone_device *tz, int *temp)
 {
 	struct imx91_tmu *tmu = thermal_zone_device_priv(tz);
 	s16 data;
+	int ret;
+	u32 val;
+
+	ret = readl_relaxed_poll_timeout(tmu->base + IMX91_TMU_STAT0, val,
+					 val & IMX91_TMU_STAT0_DRDY0_IF_MASK, 1000,
+					 40000);
+	if (ret)
+		return -EAGAIN;
 
 	/* DATA0 is 16bit signed number */
 	data = readw_relaxed(tmu->base + IMX91_TMU_DATA0);
 	*temp = imx91_tmu_to_mcelsius(data);
+	if (*temp < IMX91_TMU_TEMP_LOW_LIMIT || *temp > IMX91_TMU_TEMP_HIGH_LIMIT)
+		return -EAGAIN;
 
 	return 0;
 }

-- 
2.37.1



From peng.fan at oss.nxp.com  Thu Dec 11 23:51:15 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Fri, 12 Dec 2025 15:51:15 +0800
Subject: [PATCH 2/3] thermal/drivers/imx91: Drop extra spaces
In-Reply-To: <20251212-imx91-thermal-v1-0-c208545b44cb@nxp.com>
References: <20251212-imx91-thermal-v1-0-c208545b44cb@nxp.com>
Message-ID: <20251212-imx91-thermal-v1-2-c208545b44cb@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

Unify the code style, drop extra spaces for the macros.

Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 drivers/thermal/imx91_thermal.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/drivers/thermal/imx91_thermal.c b/drivers/thermal/imx91_thermal.c
index 77e8e6a921c6af308b830c36721293c007256ca6..768c5acc384eca1c2203098bd4749628d9ffb8e6 100644
--- a/drivers/thermal/imx91_thermal.c
+++ b/drivers/thermal/imx91_thermal.c
@@ -22,17 +22,17 @@
 #define REG_TOG					0xc
 
 #define IMX91_TMU_CTRL0				0x0
-#define   IMX91_TMU_CTRL0_THR1_IE		BIT(9)
-#define   IMX91_TMU_CTRL0_THR1_MASK		GENMASK(3, 2)
-#define   IMX91_TMU_CTRL0_CLR_FLT1		BIT(21)
+#define IMX91_TMU_CTRL0_THR1_IE			BIT(9)
+#define IMX91_TMU_CTRL0_THR1_MASK		GENMASK(3, 2)
+#define IMX91_TMU_CTRL0_CLR_FLT1		BIT(21)
 
 #define IMX91_TMU_THR_MODE_LE			0
 #define IMX91_TMU_THR_MODE_GE			1
 
 #define IMX91_TMU_STAT0				0x10
-#define   IMX91_TMU_STAT0_THR1_IF		BIT(9)
-#define   IMX91_TMU_STAT0_THR1_STAT		BIT(13)
-#define   IMX91_TMU_STAT0_DRDY0_IF_MASK		BIT(16)
+#define IMX91_TMU_STAT0_THR1_IF			BIT(9)
+#define IMX91_TMU_STAT0_THR1_STAT		BIT(13)
+#define IMX91_TMU_STAT0_DRDY0_IF_MASK		BIT(16)
 
 #define IMX91_TMU_DATA0				0x20
 
@@ -42,12 +42,12 @@
 #define IMX91_TMU_CTRL1_STOP			BIT(29)
 #define IMX91_TMU_CTRL1_RES_MASK		GENMASK(19, 18)
 #define IMX91_TMU_CTRL1_MEAS_MODE_MASK		GENMASK(25, 24)
-#define   IMX91_TMU_CTRL1_MEAS_MODE_SINGLE	0
-#define   IMX91_TMU_CTRL1_MEAS_MODE_CONTINUES	1
-#define   IMX91_TMU_CTRL1_MEAS_MODE_PERIODIC	2
+#define IMX91_TMU_CTRL1_MEAS_MODE_SINGLE	0
+#define IMX91_TMU_CTRL1_MEAS_MODE_CONTINUES	1
+#define IMX91_TMU_CTRL1_MEAS_MODE_PERIODIC	2
 
 #define IMX91_TMU_THR_CTRL01			0x30
-#define   IMX91_TMU_THR_CTRL01_THR1_MASK	GENMASK(31, 16)
+#define IMX91_TMU_THR_CTRL01_THR1_MASK		GENMASK(31, 16)
 
 #define IMX91_TMU_REF_DIV			0x280
 #define IMX91_TMU_DIV_EN			BIT(31)
@@ -67,7 +67,7 @@
 #define IMX91_TMU_DEFAULT_TRIM2_CONFIG		0x65d4
 
 #define IMX91_TMU_PERIOD_CTRL			0x270
-#define   IMX91_TMU_PERIOD_CTRL_MEAS_MASK	GENMASK(23, 0)
+#define IMX91_TMU_PERIOD_CTRL_MEAS_MASK		GENMASK(23, 0)
 
 #define IMX91_TMP_FRAC				64
 

-- 
2.37.1



From peng.fan at oss.nxp.com  Thu Dec 11 23:51:16 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Fri, 12 Dec 2025 15:51:16 +0800
Subject: [PATCH 3/3] thermal/drivers/imx91: Drop macro for continues mode
In-Reply-To: <20251212-imx91-thermal-v1-0-c208545b44cb@nxp.com>
References: <20251212-imx91-thermal-v1-0-c208545b44cb@nxp.com>
Message-ID: <20251212-imx91-thermal-v1-3-c208545b44cb@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

i.MX91 TMU measure mode register definition as below:
00b Single One-Shot Measurement
01b Reserved
10b Periodic One-Shot Measurement
11b Reserved

Drop the definition of continues mode which does not exists.

Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 drivers/thermal/imx91_thermal.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/thermal/imx91_thermal.c b/drivers/thermal/imx91_thermal.c
index 768c5acc384eca1c2203098bd4749628d9ffb8e6..aa45eb83f9c7b58badd596d2d433592a9ee9e041 100644
--- a/drivers/thermal/imx91_thermal.c
+++ b/drivers/thermal/imx91_thermal.c
@@ -43,7 +43,6 @@
 #define IMX91_TMU_CTRL1_RES_MASK		GENMASK(19, 18)
 #define IMX91_TMU_CTRL1_MEAS_MODE_MASK		GENMASK(25, 24)
 #define IMX91_TMU_CTRL1_MEAS_MODE_SINGLE	0
-#define IMX91_TMU_CTRL1_MEAS_MODE_CONTINUES	1
 #define IMX91_TMU_CTRL1_MEAS_MODE_PERIODIC	2
 
 #define IMX91_TMU_THR_CTRL01			0x30

-- 
2.37.1



From tabba at google.com  Fri Dec 12 00:04:07 2025
From: tabba at google.com (Fuad Tabba)
Date: Fri, 12 Dec 2025 08:04:07 +0000
Subject: [PATCH 1/2] KVM: arm64: Copy FGT traps to unprotected pKVM VCPU
 on VCPU load
In-Reply-To: <20251210132102.137631-2-alexandru.elisei@arm.com>
References: <20251210132102.137631-1-alexandru.elisei@arm.com> <20251210132102.137631-2-alexandru.elisei@arm.com>
Message-ID: <CA+EHjTxMmNrJT5-biZJDiTE4E5RaKpr+SGuj_jnpAfsbxzaR3g@mail.gmail.com>

Hi Alexandru,

On Wed, 10 Dec 2025 at 13:21, Alexandru Elisei <alexandru.elisei at arm.com> wrote:
>
> Commit fb10ddf35c1c ("KVM: arm64: Compute per-vCPU FGTs at vcpu_load()")
> introduced per-VCPU FGT traps. For an unprotected pKVM VCPU, the untrusted
> host FGT configuration is copied in pkvm_vcpu_init_traps(), which is called
> from __pkvm_init_vcpu(). __pkvm_init_vcpu() is called once per VCPU (when
> the VCPU is first run) which means that the uninitialized, zero, values for
> the FGT registers end up being used for the entire lifetime of the VCPU.
> This causes both unwanted traps (for the inverse polarity trap bits) and
> the guest being allowed to access registers it shouldn't.
>
> Fix it by copying the FGT traps for unprotected pKVM VCPUs when the
> untrusted host loads the VCPU.
>
> Fixes: fb10ddf35c1c ("KVM: arm64: Compute per-vCPU FGTs at vcpu_load()")
> Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
> ---
>  arch/arm64/kvm/hyp/nvhe/hyp-main.c | 12 ++++++++++--
>  arch/arm64/kvm/hyp/nvhe/pkvm.c     |  1 -
>  2 files changed, 10 insertions(+), 3 deletions(-)
>
> diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> index 29430c031095..ee0f1343100c 100644
> --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> @@ -167,6 +167,7 @@ static void handle___pkvm_vcpu_load(struct kvm_cpu_context *host_ctxt)
>         DECLARE_REG(unsigned int, vcpu_idx, host_ctxt, 2);
>         DECLARE_REG(u64, hcr_el2, host_ctxt, 3);
>         struct pkvm_hyp_vcpu *hyp_vcpu;
> +       struct kvm_vcpu *hyp_kvm_vcpu;
>
>         if (!is_protected_kvm_enabled())
>                 return;
> @@ -175,10 +176,17 @@ static void handle___pkvm_vcpu_load(struct kvm_cpu_context *host_ctxt)
>         if (!hyp_vcpu)
>                 return;
>
> +       hyp_kvm_vcpu = &hyp_vcpu->vcpu;
> +
>         if (pkvm_hyp_vcpu_is_protected(hyp_vcpu)) {
>                 /* Propagate WFx trapping flags */
> -               hyp_vcpu->vcpu.arch.hcr_el2 &= ~(HCR_TWE | HCR_TWI);
> -               hyp_vcpu->vcpu.arch.hcr_el2 |= hcr_el2 & (HCR_TWE | HCR_TWI);
> +               hyp_kvm_vcpu->arch.hcr_el2 &= ~(HCR_TWE | HCR_TWI);
> +               hyp_kvm_vcpu->arch.hcr_el2 |= hcr_el2 & (HCR_TWE | HCR_TWI);
> +       } else {
> +               struct kvm_vcpu *host_vcpu = hyp_vcpu->host_vcpu;
> +
> +               memcpy(&hyp_kvm_vcpu->arch.fgt, host_vcpu->arch.fgt,
> +                      sizeof(hyp_kvm_vcpu->arch.fgt));
>         }
>  }

With the fix Will mentioned (hyp-main.c never uses the variable name
hyp_kvm_vcpu, it's vcpu for the hyp, or host_vcpu for the host's).

Tested-by: Fuad Tabba <tabba at google.com>
Reviewed-by: Fuad Tabba <tabba at google.com>

Cheers,
/fuad
>
> diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
> index 43bde061b65d..05774aed09cb 100644
> --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
> +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
> @@ -172,7 +172,6 @@ static int pkvm_vcpu_init_traps(struct pkvm_hyp_vcpu *hyp_vcpu)
>
>                 /* Trust the host for non-protected vcpu features. */
>                 vcpu->arch.hcrx_el2 = host_vcpu->arch.hcrx_el2;
> -               memcpy(vcpu->arch.fgt, host_vcpu->arch.fgt, sizeof(vcpu->arch.fgt));
>                 return 0;
>         }
>
> --
> 2.52.0
>
>


From krzk at kernel.org  Fri Dec 12 00:19:51 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 12 Dec 2025 09:19:51 +0100
Subject: [PATCH 2/8] dt-bindings: gpio: Add AAEON embedded controller GPIO
 binding
In-Reply-To: <20251212-dev-b4-aaeon-mcu-driver-v1-2-6bd65bc8ef12@bootlin.com>
References: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com>
 <20251212-dev-b4-aaeon-mcu-driver-v1-2-6bd65bc8ef12@bootlin.com>
Message-ID: <297c2582-0879-433f-a854-211ad1d21837@kernel.org>

On 12/12/2025 08:41, Thomas Perrot (Schneider Electric) wrote:
> Add device tree binding documentation for the GPIO controller functionality
> provided by the AAEON embedded controller. This controller provides 7 GPOs
> and 12 GPIOs for a total of 19 GPIO lines.
> 
> The GPIO controller is defined as a child node of the AAEON MCU device.
> 
> Signed-off-by: Thomas Perrot (Schneider Electric) <thomas.perrot at bootlin.com>
> ---
>  .../bindings/gpio/aaeon,srg-imx8pl-gpio.yaml       | 54 ++++++++++++++++++++++
>  1 file changed, 54 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/gpio/aaeon,srg-imx8pl-gpio.yaml b/Documentation/devicetree/bindings/gpio/aaeon,srg-imx8pl-gpio.yaml
> new file mode 100644
> index 0000000000000000000000000000000000000000..8040dc0a36ee5650488520c2218f09fd08cdf64a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/gpio/aaeon,srg-imx8pl-gpio.yaml
> @@ -0,0 +1,54 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/gpio/aaeon,srg-imx8pl-gpio.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: AAEON Embedded Controller GPIO
> +
> +maintainers:
> +  - J?r?mie Dautheribes <jeremie.dautheribes at bootlin.com>
> +  - Thomas Perrot <thomas.perrot at bootlin.com>
> +
> +description: |
> +  GPIO controller functionality provided by the AAEON embedded controller.
> +  This controller provides 7 GPOs and 12 GPIOs.
> +
> +  The GPIO controller is a sub-device of the AAEON MCU and must be defined
> +  as a child node of the MCU device.
> +
> +properties:
> +  compatible:
> +    const: aaeon,srg-imx8pl-gpio
> +
> +  gpio-controller: true


That's not really separate node if you do not have any resources. Fold
it into the parent.

Best regards,
Krzysztof


From krzk at kernel.org  Fri Dec 12 00:20:43 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 12 Dec 2025 09:20:43 +0100
Subject: [PATCH 3/8] dt-bindings: watchdog: Add AAEON embedded controller
 watchdog binding
In-Reply-To: <20251212-dev-b4-aaeon-mcu-driver-v1-3-6bd65bc8ef12@bootlin.com>
References: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com>
 <20251212-dev-b4-aaeon-mcu-driver-v1-3-6bd65bc8ef12@bootlin.com>
Message-ID: <019aa49f-fe59-488d-aff8-f07cf07ee68d@kernel.org>

On 12/12/2025 08:41, Thomas Perrot (Schneider Electric) wrote:
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    watchdog {
> +      compatible = "aaeon,srg-imx8pl-wdt";

No, that was discussed many times on the mailing list already. Fold the
child into the parent. Your driver model really do not matter for DT.

> +    };
> 


Best regards,
Krzysztof


From krzk at kernel.org  Fri Dec 12 00:22:13 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 12 Dec 2025 09:22:13 +0100
Subject: [PATCH 4/8] dt-bindings: mfd: Add AAEON embedded controller
 binding
In-Reply-To: <20251212-dev-b4-aaeon-mcu-driver-v1-4-6bd65bc8ef12@bootlin.com>
References: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com>
 <20251212-dev-b4-aaeon-mcu-driver-v1-4-6bd65bc8ef12@bootlin.com>
Message-ID: <160d61b0-7819-4566-9543-2dabec226713@kernel.org>

On 12/12/2025 08:41, Thomas Perrot (Schneider Electric) wrote:
> Add device tree binding documentation for the AAEON embedded controller
> (MCU). This microcontroller is found on AAEON embedded boards and provides
> system features such as GPIO control, watchdog timer, and LED management.

A nit, subject: drop second/last, redundant "binding". The "dt-bindings"
prefix is already stating that these are bindings.
See also:
https://elixir.bootlin.com/linux/v6.17-rc3/source/Documentation/devicetree/bindings/submitting-patches.rst#L18

> 
> The MCU is connected via I2C and acts as a multi-function device with
> GPIO and watchdog as child nodes.
> 
> Signed-off-by: Thomas Perrot (Schneider Electric) <thomas.perrot at bootlin.com>
> ---
>  .../bindings/mfd/aaeon,srg-imx8pl-mcu.yaml         | 58 ++++++++++++++++++++++
>  1 file changed, 58 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/mfd/aaeon,srg-imx8pl-mcu.yaml b/Documentation/devicetree/bindings/mfd/aaeon,srg-imx8pl-mcu.yaml
> new file mode 100644
> index 0000000000000000000000000000000000000000..680d06a7e7cb3754bdfc67a1b8c484811eba55d1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/aaeon,srg-imx8pl-mcu.yaml
> @@ -0,0 +1,58 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/mfd/aaeon,srg-imx8pl-mcu.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: AAEON Embedded Controller
> +
> +maintainers:
> +  - J?r?mie Dautheribes <jeremie.dautheribes at bootlin.com>
> +  - Thomas Perrot <thomas.perrot at bootlin.com>
> +
> +description: |

Do not need '|' unless you need to preserve formatting.

> +  AAEON embeds a microcontroller on their embedded boards providing system
> +  features such as GPIO control, watchdog timer, and LED management.
> +  The MCU is connected via I2C bus.
> +
> +properties:
> +  compatible:
> +    const: aaeon,srg-imx8pl-mcu

What is srg? Why isn't this explained anywhere here?

> +
> +  reg:
> +    maxItems: 1
> +
> +  gpio:

Drop the child, properties go here directly.

> +    $ref: /schemas/gpio/aaeon,srg-imx8pl-gpio.yaml
> +
> +  watchdog:

Same here

> +    $ref: /schemas/watchdog/aaeon,srg-imx8pl-wdt.yaml
> +
> +required:
> +  - compatible
> +  - reg
> +



Best regards,
Krzysztof


From krzk at kernel.org  Fri Dec 12 00:23:25 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 12 Dec 2025 09:23:25 +0100
Subject: [PATCH 8/8] MAINTAINERS: Add entry for AAEON SRG-IMX8PL MCU
 driver
In-Reply-To: <20251212-dev-b4-aaeon-mcu-driver-v1-8-6bd65bc8ef12@bootlin.com>
References: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com>
 <20251212-dev-b4-aaeon-mcu-driver-v1-8-6bd65bc8ef12@bootlin.com>
Message-ID: <ac5d7935-3285-416d-8024-02a26753c564@kernel.org>

On 12/12/2025 08:41, Thomas Perrot (Schneider Electric) wrote:
> +AAEON SRG-IMX8PL CONTROLLER MFD DRIVER
> +M:	Thomas Perrot <thomas.perrot at bootlin.com>
> +R:	J?r?mie Dautheribes <jeremie.dautheribes at bootlin.com>
> +S:	Maintained
> +F:	drivers/gpio/gpio-aaeon-mcu.c
> +F:	drivers/mfd/aaeon-mcu.c
> +F:	drivers/watchdog/aaeon_mcu_wdt.c
> +F:	include/linux/mfd/aaeon-mcu.h

Incomplete - missing bindings.

Best regards,
Krzysztof


From krzk at kernel.org  Fri Dec 12 00:25:16 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 12 Dec 2025 09:25:16 +0100
Subject: [PATCH 1/4] dt-bindings: pwm: sunxi: add PWM controller for
 Allwinner H616
In-Reply-To: <4d34658b-874d-4681-95c1-616f5b385550@bootlin.com>
References: <20251205100239.1563353-1-richard.genoud@bootlin.com>
 <20251205100239.1563353-2-richard.genoud@bootlin.com>
 <20251208-gorgeous-capuchin-of-protection-4ad0c2@quoll>
 <4d34658b-874d-4681-95c1-616f5b385550@bootlin.com>
Message-ID: <93224408-6b09-4cec-8e84-a66d9ef138e6@kernel.org>

On 12/12/2025 08:50, Richard GENOUD wrote:
>>> +
>>> +  clocks:
>>> +    items:
>>> +      - description: Bus Clock
>>> +
>>
>> Are you sure there is no first clock? Really, really sure? If you add it
>> later, I would be pretty sad, because that's unnecessary duplication of
>> binidngs....
> I surely don't want to make you sad :)
> 
> Having a second look at the sun4i binding, I think there's a way to use it.
> The sun4i, as you said, has a module clock (OSC24M) and an optional bus 
> clock.
> Here, the bus clock is mandatory, but the H616 PWM uses OSC24M and APB1 
> as clock sources.
> 
> So, I guess that if we add something like that:
>     clocks:
>       minItems: 1
>       items:
>         - description: Module Clock
>         - description: Bus Clock
> +      - description: APB Clock
> 
>     clock-names:
>       minItems: 1
>       items:
>         - const: mod
>         - const: bus
> +      - const: apb
> 
>     resets:
>       maxItems: 1
> 
> In the sun4i pwm binding, we could re-use it for the H616 pwm right?
> (APB clock is maybe not the best name, could be secondary module clock)


apb is probably the bus clock, so you don't need to change the bindings
at all.

Best regards,
Krzysztof


From balejk at matfyz.cz  Fri Dec 12 00:36:50 2025
From: balejk at matfyz.cz (Karel Balej)
Date: Fri, 12 Dec 2025 09:36:50 +0100
Subject: [DONOTAPPLY RFC PATCH v2 4/4] arm64: dts:
 samsung,coreprimevelte: add wifi node
In-Reply-To: <aTCv75hjdX5XvgCh@google.com>
References: <20251026182602.26464-1-balejk@matfyz.cz>
 <20251026182602.26464-5-balejk@matfyz.cz> <aTCv75hjdX5XvgCh@google.com>
Message-ID: <DEW3NQVZ84JU.22G38WMULFZJG@matfyz.cz>

Brian Norris, 2025-12-03T13:47:27-08:00:
> On Sun, Oct 26, 2025 at 07:20:41PM +0100, Karel Balej wrote:
>> Add a node for the phone's WiFi serviced by the Marvell SD8777 chip a
>> communication with which happens over the SDIO. Also enable a regulator
>> without which it is not possible to connect to networks although they
>> are discovered properly.
>> 
>> Signed-off-by: Karel Balej <balejk at matfyz.cz>
>> ---
>>  .../mmp/pxa1908-samsung-coreprimevelte.dts        | 15 +++++++++++++++
>>  1 file changed, 15 insertions(+)
>> 
>> diff --git a/arch/arm64/boot/dts/marvell/mmp/pxa1908-samsung-coreprimevelte.dts b/arch/arm64/boot/dts/marvell/mmp/pxa1908-samsung-coreprimevelte.dts
>> index b2ce5edd9c6a..36d6ae4e902e 100644
>> --- a/arch/arm64/boot/dts/marvell/mmp/pxa1908-samsung-coreprimevelte.dts
>> +++ b/arch/arm64/boot/dts/marvell/mmp/pxa1908-samsung-coreprimevelte.dts
>> @@ -475,6 +475,14 @@ ldo14: ldo14 {
>>  				regulator-min-microvolt = <1200000>;
>>  				regulator-max-microvolt = <3300000>;
>>  			};
>> +
>> +			/*
>> +			 * Needs to be enabled in order for the WiFi to be able
>> +			 * to connect to networks.
>> +			 */
>> +			ldo15 {
>> +				regulator-always-on;
>
> Do we have a min/max voltage for this regulator?

The downstream node is defined with the same values as the above ldo14,
they however are however only defined in the PMIC dtsi and correspond to
the actual physical limits of the regulator specified also in the
driver, so this doesn't really give any specific constraints for the
board itself.

The downstream code enabling WiFi seems to force it to 3300000 (which
also seems to be the startup value) unconditionally, so I suppose I will
just set the both limits to this value?

>
>> +			};
>>  		};
>>  	};
>>  };
>> @@ -523,6 +531,13 @@ &sdh1 {
>>  	pinctrl-1 = <&sdh1_fast_pins_0 &sdh1_fast_pins_1 &sdh1_pins_2>;
>>  	bus-width = <4>;
>>  	non-removable;
>> +	#address-cells = <1>;
>> +	#size-cells = <0>;
>
> I wonder if this should have:
>
> 	vmmc-supply = <&ldo16>;
>
> rather than regulator-always-on above.

You mean ldo15 right?

Not having any board schematics, I don't really know what exactly the
regulator's purpose is. As I mentioned in the commit message, the
communication with the chipset seems to work even if this is disabled
(e. g. FW loads, networks can be scanned for,...) which doesn't seem
like it should be the case if this was a main power supply for the bus,
only actual connecting to networks doesn't work (gives
CONNECT_ERR_ASSOC_ERR_TIMEOUT errors).

So this didn't seem too fitting for either vmmc nor vqmmc as far as I
understand their semantics, so I went with the regulator-always-on
approach to be safe.

Thank you for the comments,
K. B.


From benjamin.gaignard at collabora.com  Fri Dec 12 00:51:50 2025
From: benjamin.gaignard at collabora.com (Benjamin Gaignard)
Date: Fri, 12 Dec 2025 09:51:50 +0100
Subject: [PATCH v9 3/7] iommu: Add verisilicon IOMMU driver
In-Reply-To: <20251212033157.3036182-1-liujianfeng1994@gmail.com>
References: <20250911155720.180465-4-benjamin.gaignard@collabora.com>
 <20251212033157.3036182-1-liujianfeng1994@gmail.com>
Message-ID: <ea3241f1-14a4-44a0-9d85-3fa2a2f6f1ae@collabora.com>


Le 12/12/2025 ? 04:31, Jianfeng Liu a ?crit?:
> Hi,
>
> On Thu, 11 Sep 2025 17:57:13 +0200, Benjamin Gaignard wrote:
>> +#ifdef CONFIG_VSI_IOMMU
>> +void vsi_iommu_restore_ctx(struct iommu_domain *domain);
>> +#else
>> +static inline void vsi_iommu_restore_ctx(struct iommu_domain *domain) {}
>> +#endif
> After applying this patch to v6.18, I get error when building this driver
> as module:
>
> drivers/iommu/vsi-iommu.c:541:6: error: redefinition of 'vsi_iommu_restore_ctx'
>    541 | void vsi_iommu_restore_ctx(struct iommu_domain *domain)
>     |      ^~~~~~~~~~~~~~~~~~~~~
> In file included from drivers/iommu/vsi-iommu.c:31:
> ./include/linux/vsi-iommu.h:18:20: note: previous definition of 'vsi_iommu_restore_ctx' with type 'void(struct iommu_domain *)'
> 18 | static inline void vsi_iommu_restore_ctx(struct iommu_domain *domain) {}
>     |                    ^~~~~~~~~~~~~~~~~~~~~
>
> I have to use:
> #if IS_ENABLED(CONFIG_VSI_IOMMU)
> instead.

I have fix in my internal v10 branch:
https://gitlab.collabora.com/linux/for-upstream/-/commits/verisilicon_mmu_v10
I don't plan to send this update because that will change nothing about code duplication remarks.

Thanks for the report.
Regards,
Benjamin

> Best regards,
> Jianfeng
>


From richard.genoud at bootlin.com  Fri Dec 12 00:52:41 2025
From: richard.genoud at bootlin.com (Richard GENOUD)
Date: Fri, 12 Dec 2025 09:52:41 +0100
Subject: [PATCH 1/4] dt-bindings: pwm: sunxi: add PWM controller for
 Allwinner H616
In-Reply-To: <93224408-6b09-4cec-8e84-a66d9ef138e6@kernel.org>
References: <20251205100239.1563353-1-richard.genoud@bootlin.com>
 <20251205100239.1563353-2-richard.genoud@bootlin.com>
 <20251208-gorgeous-capuchin-of-protection-4ad0c2@quoll>
 <4d34658b-874d-4681-95c1-616f5b385550@bootlin.com>
 <93224408-6b09-4cec-8e84-a66d9ef138e6@kernel.org>
Message-ID: <1c8fe534-4b87-46a7-9806-9cbbe5560545@bootlin.com>

Le 12/12/2025 ? 09:25, Krzysztof Kozlowski a ?crit?:
> On 12/12/2025 08:50, Richard GENOUD wrote:
>>>> +
>>>> +  clocks:
>>>> +    items:
>>>> +      - description: Bus Clock
>>>> +
>>>
>>> Are you sure there is no first clock? Really, really sure? If you add it
>>> later, I would be pretty sad, because that's unnecessary duplication of
>>> binidngs....
>> I surely don't want to make you sad :)
>>
>> Having a second look at the sun4i binding, I think there's a way to use it.
>> The sun4i, as you said, has a module clock (OSC24M) and an optional bus
>> clock.
>> Here, the bus clock is mandatory, but the H616 PWM uses OSC24M and APB1
>> as clock sources.
>>
>> So, I guess that if we add something like that:
>>      clocks:
>>        minItems: 1
>>        items:
>>          - description: Module Clock
>>          - description: Bus Clock
>> +      - description: APB Clock
>>
>>      clock-names:
>>        minItems: 1
>>        items:
>>          - const: mod
>>          - const: bus
>> +      - const: apb
>>
>>      resets:
>>        maxItems: 1
>>
>> In the sun4i pwm binding, we could re-use it for the H616 pwm right?
>> (APB clock is maybe not the best name, could be secondary module clock)
> 
> 
> apb is probably the bus clock, so you don't need to change the bindings
> at all.
Indeed, your're right!
So the only difference will the the #clock-cells for h616.
I'll send a v2 using the sun4i binding.

Thanks!

Regards,
Richard

> 
> Best regards,
> Krzysztof


-- 
Richard Genoud, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From alexander.stein at ew.tq-group.com  Fri Dec 12 00:58:59 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Fri, 12 Dec 2025 09:58:59 +0100
Subject: [PATCH 1/2] dt-bindings: power: fsl,imx-gpc: Document address-cells
Message-ID: <20251212085902.103507-1-alexander.stein@ew.tq-group.com>

The GPC power controller is an interrupt controllers and can be referenced
in interrupt-map properties, e.g. PCIe controller, thus the node should
have address-cells property.

Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 Documentation/devicetree/bindings/power/fsl,imx-gpc.yaml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/power/fsl,imx-gpc.yaml b/Documentation/devicetree/bindings/power/fsl,imx-gpc.yaml
index 9de3fe73c1eb6..d49a5130b87c7 100644
--- a/Documentation/devicetree/bindings/power/fsl,imx-gpc.yaml
+++ b/Documentation/devicetree/bindings/power/fsl,imx-gpc.yaml
@@ -38,6 +38,9 @@ properties:
   reg:
     maxItems: 1
 
+  "#address-cells":
+    const: 0
+
   interrupts:
     maxItems: 1
 
-- 
2.43.0



From alexander.stein at ew.tq-group.com  Fri Dec 12 00:59:00 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Fri, 12 Dec 2025 09:59:00 +0100
Subject: [PATCH 2/2] ARM: dts: imx6qdl: Add default GIC address cells
In-Reply-To: <20251212085902.103507-1-alexander.stein@ew.tq-group.com>
References: <20251212085902.103507-1-alexander.stein@ew.tq-group.com>
Message-ID: <20251212085902.103507-2-alexander.stein@ew.tq-group.com>

Add missing address-cells 0 to GPC interrupt node to silence W=1
warning:

  imx6qdl.dtsi:281.4-284.29: Warning (interrupt_map): /soc/pcie at 1ffc000:interrupt-map:
    Missing property '#address-cells' in node /soc/bus at 2000000/gpc at 20dc000, using 0 as fallback

Value '0' is correct because:
1. GPC interrupt controller children are only power domains,
2. interrupt-map property (in PCI node) consists of five components and
   the fourth component "parent unit address", which size is defined by
   '#address-cells' of the node pointed to by the interrupt-parent
   component, is not used (=0)

Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
This is based on commit faf183a02ed6b ("arm64: dts: imx8mp: Add default GIC
address cells")

 arch/arm/boot/dts/nxp/imx/imx6qdl.dtsi | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl.dtsi
index 45bcfd7faf9db..9793feee63947 100644
--- a/arch/arm/boot/dts/nxp/imx/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/nxp/imx/imx6qdl.dtsi
@@ -875,6 +875,7 @@ src: reset-controller at 20d8000 {
 			gpc: gpc at 20dc000 {
 				compatible = "fsl,imx6q-gpc";
 				reg = <0x020dc000 0x4000>;
+				#address-cells = <0>;
 				interrupt-controller;
 				#interrupt-cells = <3>;
 				interrupts = <0 89 IRQ_TYPE_LEVEL_HIGH>;
-- 
2.43.0



From marco.crivellari at suse.com  Fri Dec 12 01:00:36 2025
From: marco.crivellari at suse.com (Marco Crivellari)
Date: Fri, 12 Dec 2025 10:00:36 +0100
Subject: [PATCH] media: platform: mtk-mdp3: add WQ_PERCPU to
 alloc_workqueue users
In-Reply-To: <fd401d1b4f1e7b7178699227d31976453de5891e.camel@ndufresne.ca>
References: <20251107141303.223254-1-marco.crivellari@suse.com>
 <7e24110636db36e8c0a877d90d2ed9570c4aecf5.camel@ndufresne.ca>
 <CAAofZF44pUoyDPnnv9UUuMkYvqiSWP4gELg4rutgo=3tNpBZsw@mail.gmail.com> <fd401d1b4f1e7b7178699227d31976453de5891e.camel@ndufresne.ca>
Message-ID: <CAAofZF45i42hvn9bN=77WzcRmAj8eGXFjY7uA+cmnSLrJUNaLA@mail.gmail.com>

Hi,

On Wed, Dec 10, 2025 at 5:04?PM Nicolas Dufresne <nicolas at ndufresne.ca> wrote:
> I don't have strong opinion, if you think this driver can be ported in one step,
> that is always my preference, and making things explicit is also nice. But I'm
> also fine picking this as-is for now. Let me know, your preference, available
> time and safety of not breaking anything is valid argument to me.

I would like to wait before the conversion in this case, to avoid
breaking the driver.
So I would like to keep WQ_PERCPU instead, like it is now.

Many thanks, and sorry for the late reply.

-- 

Marco Crivellari

L3 Support Engineer


From pankaj.gupta at nxp.com  Fri Dec 12 01:04:29 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Fri, 12 Dec 2025 09:04:29 +0000
Subject: [EXT] Re: [PATCH v20 3/7] firmware: imx: add driver for NXP
 EdgeLock Enclave
In-Reply-To: <202512091557.d5dOvFff-lkp@intel.com>
References: <20251203-imx-se-if-v20-3-a04a25c4255f@nxp.com>
 <202512091557.d5dOvFff-lkp@intel.com>
Message-ID: <AM9PR04MB8604547F2631FF8CE8992AE595AEA@AM9PR04MB8604.eurprd04.prod.outlook.com>

> 
> smatch warnings:
> drivers/firmware/imx/ele_common.c:264 se_save_imem_state() warn:
> missing error code? 'ret'
> drivers/firmware/imx/ele_common.c:302 se_restore_imem_state() warn:
> missing error code? 'ret'
> 

Accepted.
Will return -EIO;

> vim +/ret +264 drivers/firmware/imx/ele_common.c
> 
> a9e23a74789346 Pankaj Gupta 2025-12-03  251  int
> se_save_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem)
> a9e23a74789346 Pankaj Gupta 2025-12-03  252  {
> a9e23a74789346 Pankaj Gupta 2025-12-03  253     struct ele_dev_info s_info =
> {0};
> a9e23a74789346 Pankaj Gupta 2025-12-03  254     int ret;
> a9e23a74789346 Pankaj Gupta 2025-12-03  255
> a9e23a74789346 Pankaj Gupta 2025-12-03  256     ret = ele_get_info(priv,
> &s_info);
> a9e23a74789346 Pankaj Gupta 2025-12-03  257     if (ret) {
> a9e23a74789346 Pankaj Gupta 2025-12-03  258             dev_err(priv->dev,
> "Failed to get info from ELE.\n");
> a9e23a74789346 Pankaj Gupta 2025-12-03  259             return ret;
> a9e23a74789346 Pankaj Gupta 2025-12-03  260     }
> a9e23a74789346 Pankaj Gupta 2025-12-03  261
> a9e23a74789346 Pankaj Gupta 2025-12-03  262     /* Do not save the IMEM
> buffer, if the current IMEM state is BAD. */
> a9e23a74789346 Pankaj Gupta 2025-12-03  263     if
> (s_info.d_addn_info.imem_state == ELE_IMEM_STATE_BAD)
> a9e23a74789346 Pankaj Gupta 2025-12-03 @264             return ret;
> 
> This returns success if the state is _BAD.
> 
> a9e23a74789346 Pankaj Gupta 2025-12-03  265
> a9e23a74789346 Pankaj Gupta 2025-12-03  266     /*
> a9e23a74789346 Pankaj Gupta 2025-12-03  267      * EXPORT command will
> save encrypted IMEM to given address,
> a9e23a74789346 Pankaj Gupta 2025-12-03  268      * so later in resume, IMEM
> can be restored from the given
> a9e23a74789346 Pankaj Gupta 2025-12-03  269      * address.
> a9e23a74789346 Pankaj Gupta 2025-12-03  270      *
> a9e23a74789346 Pankaj Gupta 2025-12-03  271      * Size must be at least 64
> kB.
> a9e23a74789346 Pankaj Gupta 2025-12-03  272      */
> a9e23a74789346 Pankaj Gupta 2025-12-03  273     ret = ele_service_swap(priv,
> imem->phyaddr, ELE_IMEM_SIZE, ELE_IMEM_EXPORT);
> a9e23a74789346 Pankaj Gupta 2025-12-03  274     if (ret < 0) {
> a9e23a74789346 Pankaj Gupta 2025-12-03  275             dev_err(priv->dev,
> "Failed to export IMEM.");
> a9e23a74789346 Pankaj Gupta 2025-12-03  276             imem->size = 0;
> a9e23a74789346 Pankaj Gupta 2025-12-03  277     } else {
> a9e23a74789346 Pankaj Gupta 2025-12-03  278             dev_dbg(priv->dev,
> a9e23a74789346 Pankaj Gupta 2025-12-03  279                     "Exported %d
> bytes of encrypted IMEM.",
> a9e23a74789346 Pankaj Gupta 2025-12-03  280                     ret);
> a9e23a74789346 Pankaj Gupta 2025-12-03  281             imem->size = ret;
> a9e23a74789346 Pankaj Gupta 2025-12-03  282     }
> a9e23a74789346 Pankaj Gupta 2025-12-03  283
> a9e23a74789346 Pankaj Gupta 2025-12-03  284     return ret > 0 ? 0 : ret;
> a9e23a74789346 Pankaj Gupta 2025-12-03  285  }
> a9e23a74789346 Pankaj Gupta 2025-12-03  286
> a9e23a74789346 Pankaj Gupta 2025-12-03  287  int
> se_restore_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem)
> a9e23a74789346 Pankaj Gupta 2025-12-03  288  {
> a9e23a74789346 Pankaj Gupta 2025-12-03  289     struct ele_dev_info s_info;
> a9e23a74789346 Pankaj Gupta 2025-12-03  290     int ret;
> a9e23a74789346 Pankaj Gupta 2025-12-03  291
> a9e23a74789346 Pankaj Gupta 2025-12-03  292     /* get info from ELE */
> a9e23a74789346 Pankaj Gupta 2025-12-03  293     ret = ele_get_info(priv,
> &s_info);
> a9e23a74789346 Pankaj Gupta 2025-12-03  294     if (ret) {
> a9e23a74789346 Pankaj Gupta 2025-12-03  295             dev_err(priv->dev,
> "Failed to get info from ELE.");
> a9e23a74789346 Pankaj Gupta 2025-12-03  296             return ret;
> a9e23a74789346 Pankaj Gupta 2025-12-03  297     }
> a9e23a74789346 Pankaj Gupta 2025-12-03  298     imem->state =
> s_info.d_addn_info.imem_state;
> a9e23a74789346 Pankaj Gupta 2025-12-03  299
> a9e23a74789346 Pankaj Gupta 2025-12-03  300     /* Get IMEM state, if 0xFE
> then import IMEM if imem size is non-zero. */
> 
> I really can't understand this comment at all.  :(

Accepted.
Will update the this comment in V21, with the following:
-       /* Get IMEM state, if 0xFE then import IMEM if imem size is non-zero. */
+       /* Check for the imem-state and imem-size before continue to
+        * restore imem state.
+        */

> 
> a9e23a74789346 Pankaj Gupta 2025-12-03  301     if
> (s_info.d_addn_info.imem_state != ELE_IMEM_STATE_BAD || !imem->size)
> a9e23a74789346 Pankaj Gupta 2025-12-03 @302             return ret;
> 
> This feels like returning zero is intentional, but please return a literal zero.
> s/return ret;/return 0;/.

Accepted. As mentioned above, will return -EIO;

> 



From pankaj.gupta at nxp.com  Fri Dec 12 01:05:28 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Fri, 12 Dec 2025 09:05:28 +0000
Subject: [EXT] Re: [PATCH v20 3/7] firmware: imx: add driver for NXP
 EdgeLock Enclave
In-Reply-To: <33d659bd-eba9-4b47-a374-32b6c763d640@infradead.org>
References: <20251203-imx-se-if-v20-0-a04a25c4255f@nxp.com>
 <20251203-imx-se-if-v20-3-a04a25c4255f@nxp.com>
 <33d659bd-eba9-4b47-a374-32b6c763d640@infradead.org>
Message-ID: <AM9PR04MB86048456E6BA337E3AF5754195AEA@AM9PR04MB8604.eurprd04.prod.outlook.com>

> On 12/2/25 10:48 PM, Pankaj Gupta wrote:
> > diff --git a/drivers/firmware/imx/Kconfig
> > b/drivers/firmware/imx/Kconfig index 127ad752acf8..5fe96299b704
> 100644
> > --- a/drivers/firmware/imx/Kconfig
> > +++ b/drivers/firmware/imx/Kconfig
> > @@ -55,3 +55,16 @@ config IMX_SCMI_MISC_DRV
> >         core that could provide misc functions such as board control.
> >
> >         This driver can also be built as a module.
> > +
> > +config IMX_SEC_ENCLAVE
> > +     tristate "i.MX Embedded Secure Enclave - EdgeLock Enclave Firmware
> driver."
> > +     depends on IMX_MBOX && ARCH_MXC && ARM64
> 
> Is it possible to work COMPILE_TEST into this dependency?

Accepted. Will add it in v21.

> 
> > +     select FW_LOADER
> > +     default m if ARCH_MXC
> > +
> > +     help
> > +       Exposes APIs supported by the iMX Secure Enclave HW IP called:
> > +       - EdgeLock Enclave Firmware (for i.MX8ULP, i.MX93),
> > +         like base, HSM, V2X & SHE using the SAB protocol via the shared
> Messaging
> > +         Unit. This driver exposes these interfaces via a set of file descriptors
> > +         allowing to configure shared memory, send and receive messages.
> 
> thanks.
> --
> ~Randy

Thanks
Pankaj

From pankaj.gupta at nxp.com  Fri Dec 12 01:07:12 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Fri, 12 Dec 2025 09:07:12 +0000
Subject: [EXT] Re: [PATCH v20 3/7] firmware: imx: add driver for NXP
 EdgeLock Enclave
In-Reply-To: <48d5895d-fde0-4795-8049-788fa3171fde@kernel.org>
References: <20251203-imx-se-if-v20-0-a04a25c4255f@nxp.com>
 <20251203-imx-se-if-v20-3-a04a25c4255f@nxp.com>
 <1ee383c7-ccbc-4c90-adf3-bfbe87fb6765@kernel.org>
 <aTBsdW0lpZSCVsgp@lizhi-Precision-Tower-5810>
 <48d5895d-fde0-4795-8049-788fa3171fde@kernel.org>
Message-ID: <AM9PR04MB86046ACCE6AF2BE7099FD3AE95AEA@AM9PR04MB8604.eurprd04.prod.outlook.com>

> >>> NXP hardware IP(s) for secure-enclaves like Edgelock Enclave(ELE),
> >>> are embedded in the SoC to support the features like HSM, SHE & V2X,
> >>> using message based communication interface.
> >>>
> >>> The secure enclave FW communicates with Linux over single or
> >>> multiple dedicated messaging unit(MU) based interface(s).
> >>> Exists on i.MX SoC(s) like i.MX8ULP, i.MX93, i.MX95 etc.
> >>>
> >>> For i.MX9x SoC(s) there is at least one dedicated ELE MU(s) for each
> >>> world - Linux(one or more) and OPTEE-OS (one or more).
> >>>
> >>> Other dependent kernel drivers will be:
> >>> - NVMEM: that supports non-volatile devices like EFUSES,
> >>>          managed by NXP's secure-enclave.
> >>>
> >>> Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
> >>> Reviewed-by: Frank Li <Frank.Li at nxp.com>
> >>> ---
> >>>  drivers/firmware/imx/Kconfig        |  13 ++
> >>>  drivers/firmware/imx/Makefile       |   2 +
> >>>  drivers/firmware/imx/ele_base_msg.c | 269
> ++++++++++++++++++++++++
> >>> drivers/firmware/imx/ele_base_msg.h |  95 +++++++++
> >>>  drivers/firmware/imx/ele_common.c   | 333
> ++++++++++++++++++++++++++++++
> >>>  drivers/firmware/imx/ele_common.h   |  45 ++++
> >>>  drivers/firmware/imx/se_ctrl.c      | 401
> ++++++++++++++++++++++++++++++++++++
> >>>  drivers/firmware/imx/se_ctrl.h      |  86 ++++++++
> >>>  include/linux/firmware/imx/se_api.h |  14 ++
> >>>  9 files changed, 1258 insertions(+)
> >>>
> >>> diff --git a/drivers/firmware/imx/Kconfig
> >>> b/drivers/firmware/imx/Kconfig index 127ad752acf8..5fe96299b704
> >>> 100644
> >>> --- a/drivers/firmware/imx/Kconfig
> >>> +++ b/drivers/firmware/imx/Kconfig
> >>> @@ -55,3 +55,16 @@ config IMX_SCMI_MISC_DRV
> >>>       core that could provide misc functions such as board control.
> >>>
> >>>       This driver can also be built as a module.
> >>> +
> >>> +config IMX_SEC_ENCLAVE
> >>> +   tristate "i.MX Embedded Secure Enclave - EdgeLock Enclave Firmware
> driver."
> >>> +   depends on IMX_MBOX && ARCH_MXC && ARM64
> >>> +   select FW_LOADER
> >>> +   default m if ARCH_MXC
> >>> +
> >>> +   help
> >>> +     Exposes APIs supported by the iMX Secure Enclave HW IP called:
> >>> +     - EdgeLock Enclave Firmware (for i.MX8ULP, i.MX93),
> >>> +       like base, HSM, V2X & SHE using the SAB protocol via the shared
> Messaging
> >>> +       Unit. This driver exposes these interfaces via a set of file descriptors
> >>> +       allowing to configure shared memory, send and receive messages.
> >>> diff --git a/drivers/firmware/imx/Makefile
> >>> b/drivers/firmware/imx/Makefile index 3bbaffa6e347..4412b15846b1
> >>> 100644
> >>> --- a/drivers/firmware/imx/Makefile
> >>> +++ b/drivers/firmware/imx/Makefile
> >>> @@ -4,3 +4,5 @@ obj-$(CONFIG_IMX_SCU)               += imx-scu.o misc.o
> imx-scu-irq.o rm.o imx-scu-soc.o
> >>>  obj-${CONFIG_IMX_SCMI_CPU_DRV}     += sm-cpu.o
> >>>  obj-${CONFIG_IMX_SCMI_MISC_DRV}    += sm-misc.o
> >>>  obj-${CONFIG_IMX_SCMI_LMM_DRV}     += sm-lmm.o
> >>> +sec_enclave-objs           = se_ctrl.o ele_common.o ele_base_msg.o
> >>> +obj-${CONFIG_IMX_SEC_ENCLAVE}      += sec_enclave.o
> >>> diff --git a/drivers/firmware/imx/ele_base_msg.c
> >>> b/drivers/firmware/imx/ele_base_msg.c
> >>> new file mode 100644
> >>> index 000000000000..a070acbd895c
> >>> --- /dev/null
> >>> +++ b/drivers/firmware/imx/ele_base_msg.c
> >>> @@ -0,0 +1,269 @@
> >>> +// SPDX-License-Identifier: GPL-2.0+
> >>> +/*
> >>> + * Copyright 2025 NXP
> >>> + */
> >>> +
> >>> +#include <linux/types.h>
> >>> +
> >>> +#include <linux/completion.h>
> >>> +#include <linux/dma-mapping.h>
> >>> +#include <linux/genalloc.h>
> >>> +
> >>> +#include "ele_base_msg.h"
> >>> +#include "ele_common.h"
> >>> +
> >>> +#define FW_DBG_DUMP_FIXED_STR              "ELE"
> >>> +
> >>> +int ele_get_info(struct se_if_priv *priv, struct ele_dev_info
> >>> +*s_info) {
> >>> +   struct se_api_msg *tx_msg __free(kfree) = NULL;
> >>> +   struct se_api_msg *rx_msg __free(kfree) = NULL;
> >>
> >> No, don't use this syntax. This is explicitly discouraged.
> >>
> >> NAK

Accepted.
Will fix this in V21 patch-set.

> >
> > Add link for reference.
> >
> > https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flore
> > .kernel.org%2Fall%2FCAHk-
> %3DwhPZoi03ZwphxiW6cuWPtC3nyKYS8_BThgztCdgPWP
> >
> 1WA%40mail.gmail.com%2F&data=05%7C02%7Cpankaj.gupta%40nxp.com
> %7C10fcf6
> >
> 46c5424c32be3508de32934df5%7C686ea1d3bc2b4c6fa92cd99c5c301635
> %7C0%7C0%
> >
> 7C639003805451655771%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hc
> GkiOnRydWUsI
> >
> lYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3
> D%7C
> >
> 0%7C%7C%7C&sdata=qxkxvyfwzl970fCJNa6iMr1i1zWYIdCIg4AIQMowvX4%
> 3D&reserv
> > ed=0
> 
> This is since beginning documented in kernel, so contributor could read
> cleanup docs before using them. Above Linus remark is nothing new, he
> already wrote it ~2 years ago.
> 
> Best regards,
> Krzysztof

Best Regards
Pankaj


From pankaj.gupta at nxp.com  Fri Dec 12 01:14:11 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Fri, 12 Dec 2025 14:44:11 +0530
Subject: [PATCH v21 0/7] firmware: imx: driver for NXP secure-enclave
Message-ID: <20251212-imx-se-if-v21-0-ee7d6052d848@nxp.com>

The NXP's i.MX EdgeLock Enclave, a HW IP creating an embedded secure
enclave within the SoC boundary to enable features like
- HSM
- SHE
- V2X

Communicates via message unit with linux kernel. This driver is
enables communication ensuring well defined message sequence protocol
between Application Core and enclave's firmware.

Driver configures multiple misc-device on the MU, for multiple
user-space applications can communicate on single MU.

It exists on some i.MX processors. e.g. i.MX8ULP, i.MX93 etc.

-------
Changes in v21:
3/7
- smatch warning fixes.
- Added "COMPILE_TEST" into "depends on IMX_MBOX && ARCH_MXC && ARM64"
- removed "__free(kfree)" & added kfree();

5/7
- removed "__free(kfree)" & added kfree();

1/2, 2/7, 4/7, & 7/7
- No changes

Reference:
- Link to v20: https://lore.kernel.org/r/20251203-imx-se-if-v20-0-a04a25c4255f at nxp.com

Changes in v20:
5/7:
- adds a func "se_chk_tx_msg_hdr", to check the validity of the in-coming message from usersapce.

1/2, 2/7, 3/7, 4/7, 6/7 & 7/7
- No changes

Reference:
- Link to v19: https://lore.kernel.org/r/20250927-imx-se-if-v19-0-d1e7e960c118 at nxp.com

Changes in v19:

1/7
- Added 9 lines to the Introduction from line 73-82.

3/7
-  Update the commit message for " For i.MX9x SoC(s) there is at least one
dedicated ELE MU(s) for each world - Linux(one or more) and OP-TEE OS (one or
more), that needs to be shared between them.."

Reference:
- Link to v18: https://lore.kernel.org/r/20250619-imx-se-if-v18-0-c98391ba446d at nxp.com

Changes in v18:

1/7
- Wrap both diagrams above in literal code block by using double-colon

3/7 & 5/7
- Collected Frank's R-b tag.

2/7, 4/7, 6/7 & 7/7
- No changes

Reference:
- Link to v17: https://lore.kernel.org/r/20250426-imx-se-if-v17-0-0c85155a50d1 at nxp.com

Changes in v17:
- Changes to 3/7 & 5/7: to wrap code text at 80 character whereever possible.

Reference:
- Link to v16: https://lore.kernel.org/r/20250409-imx-se-if-v16-0-5394e5f3417e at nxp.com

Changes in v16:
- commit 3/7 and 4/7 are moved to end commits making them as 6/7 and 7/7 respectively.
- No change in 1/7 & 2/7.

7/7
- Collected Frank's R-b tag.

6/7
- commit message is updated to wrap at 75 characters.

5/7
- func add_b_desc_to_pending_list, removed the initialization of b_desc to
  NULL.
- variable timeout in func ele_msg_rcv(), is renamed to timeout_ms.
- struct se_if_priv, member variable se_rcv_msg_timeout, is renamed to
  se_rcv_msg_timeout_ms.
- in func load_firmware, move the label exit after dma_free_coherent.

4/7
- commit message is updated to wrap at 75 characters.

3/7
- ele_debug_dump, updated the assignment of keep_logging.
- ele_fw_authenticate function definition is updated to take two address
  as arguments.

Reference:
- Link to v15: https://lore.kernel.org/r/20250407-imx-se-if-v15-0-e3382cecda01 at nxp.com

Changes in v15:
- Patch 3/6 is split into two:
  - 3/7: arm64: dts: imx8ulp-evk: add reserved memory property
  - 4/7: arm64: dts: imx8ulp: add nxp secure enclave firmware
- No change in 1/7 & 2/7.

7/7
- removed the se_intance_id structure member variable.
- replace variable name from wait to timeout.
- used 'goto' to follow the common exit path calling "release_firmware(fw);" in case of error path.
- removed TBD string.
- Used ARRAY_SIZE(pending_lists).
- moved init_device_context after init_misc_device_context.
- defined err as long to avoid force convert in func
- added se_rcv_msg_timeout to priv, to control probe/suspend/resume per interface.

6/7
- removed the se_intance_id structure member variable.
- Added dev_ctx to the structure se_clbk_handle, too.
- Collected Frank's R-b tag.

5/7
- removed the se_intance_id structure member variable.
- since added se_if_probe_cleanup to devm, se_if_remove() is redundant. hence removed it.
- rename se_add_msg_chksum to se_get_msg_chksum
- added check if msg-size is 4 byte aligned.
- Fixed multiline comments.
- ele_debug_dump api is updated as part of comment disposition like single setting of flag "keep_logging" & adding if (ret).
- moved dev_err to dev_dbg, for imem save/restore functions.
- moved func get_se_if_name, from 7/7 to here.

3/7
- Updated the commit message.
- split the current patch into two:
  -- 3/7 for board dts, and
  -- 4/7 for chip dts

Reference:
- Link to v14: https://lore.kernel.org/r/20250327-imx-se-if-v14-0-2219448932e4 at nxp.com

Changes in v14:

- Patch 5/5 is split into two:
  - firmware: drivers: imx: adds miscdev
  - Introduce dev-ctx dedicated to private.
    -- Base patch before enabling misc-device context, to have the send-receive path, based on device context.
- No change in 1/6 & 2/6.
- Copied change logs from individual commits.

6/6
- moved definition of func se_load_firmware, from 4/6 patch to this patch.
- split init_device_context to init_misc_device_context.
- Different value of se_rcv_msg_timeout is required to be set. Receiving the response of 4K RSA operation can to take upto 3 minutes.
  This long value cannot be set during Linux: boot-up and suspend-resume.
  Hence, it will be set to default small-value during Linux: boot-up and suspend-resume.
- func se_dev_ctx_cpy_out_data(), in either case: do_cpy true or false, the clean-up needs to be done and it is implemented like wise.
  Once do_cpy is false, no need to continue copy to user buffer. But continue to do clean-up. hence cannot return.
  And every dev-ctx operation is done after taking the lock. Hence, two operations with same dev-ctx is not possible in parallel.
- func "init_device_context", for 0th misc dev_ctx, which is created at the time of probe, the device memory management is required. hence there is a difference.
- func "init_device_context", dev_er is replaced with return dev_err_probe.
- func "init_device_context", devm_add_action is replaced by devm_add_action_reset.
- removed type-cast from func se_ioctl_get_se_soc_info_handler().
- used scoped_cond_guard(mutex, _intr, return -EBUSY, &<mutex_lock>)
- combined dev_err & dev_dbg to one dev_err in se_if_fops_read().
- removed the structure member "se_shared_mem_mgmt->secure_mem".

4/6
- trimmed the ele_fetch_soc_info.
- removed the function ptr "se_info->se_fetch_soc_info" and replaced with ele_fetch_soc_info.
- moved definition of func se_load_firmware, to 6/6 patch.
- Different SoC, different ways to fetch soc_info. Generic function declaration for ele_fetch_soc_info() is needed. Hence wrapping ele_get_info() in it.
- Updated Kconfig help text for assertive tone.
- func ele_debug_dump is updated, to remove constructing the format string.
- removed the macro usage for SOC_ID_MASK.
- used low case hex number.
- Condition will never occur, where msg_len satisfy the following condition "msg_len % 4 != 0". Err msg is added if it occurs.
- Function description is added to se_add_msg_crc.
- timeout is added to function ele_msg_rcv, in 5/5 patch.
- local variable "header" is initialized with "tx_msg" and replaced "return err" with "return tx_msg_sz" in func ele_msg_send().
- replace function name from "exception_for_size" to "check_hdr_exception_for_sz"
- replaced "return ret > 0 ? 0 : -1;" with "return ret > 0 ? 0 : ret;" in func "se_save_imem_state".
- func "se_restore_imem_state", to return if the condition is false to proceed.
- removed casting by (void *).
- removed devm_kasprintf and done direct allocatiion for attr->soc_id = "i.MX8ULP" & attr->soc_id = "i.MX8ULP", & attr->family.
- Followed Reverse christmas tree order, whereever missing.
- There is no return if ele_fw_authenticate fails. Execution flow continue forward and execute the fucn dma_free_coherent().
- The loop is not for retry. The loop is needed to load secondary fw followed by loading primary fw, first. This is the case when ELE also got reset.
- dev_err_probe is corrected in func "se_if_request_channel".

3/6
-

Reference:
- Link to v13: https://lore.kernel.org/r/20250311-imx-se-if-v13-0-9cc6d8fd6d1c at nxp.com

Changes in v13:

5/5
- Updated the commit message for imperative mood.
- Remove the usage of macros- NODE_NAME, GET_ASCII_TO_U8, GET_IDX_FROM_DEV_NODE_NAME.
- Clean-up the return path by replacing "ret = -<err>; return ret;" with "return -<err>;"
- Clean-up the return path by replacing "ret = -<err>; goto exit;" with "return -<err>;"
- Removed goto statements from the entire driver, where there is no common code at function's exit.
- Fixes the check-patch erros reported with flag "--strict"
- Replaced devm_add_action, with devm_add_action_or_reset
- Removed the un-necesary and obvious code comments.
- Removed dev_probe_err at the exit of function se_if_probe().

4/5
- Clean-up the return path by replacing "ret = -<err>; return ret;" with "return -<err>;"
- Clean-up the return path by replacing "ret = -<err>; goto exit;" with "return -<err>;"
- Removed goto statements from the entire driver, where there is no common code at function's exit.
- fixes the check-patch erros reported with flag "--strict"
- removed the un-necesary and obvious code comments.
- variable received msg timeout to be different at boot-up & suspend/resume and send/recv ioctlis.

3/5
- compatible string is modified from "fsl,imx8ulp-se" to "fsl,imx8ulp-se-ele-hsm".
- updated the alias name.

2/5
- compatible string is modified from "fsl,imx8ulp-se" to "fsl,imx8ulp-se-ele-hsm".
- compatible string is modified from "fsl,imx93-se" to "fsl,imx93-se-ele-hsm".
- compatible string is modified from "fsl,imx95-se" to "fsl,imx95-se-ele-hsm".
- Mis-understood the +1 from Conor. Hence dropped the Reviewed-by tag.
- Collected Rob's R-b tag on v7 (https://lore.kernel.org/all/172589152997.4184616.5889493628960272898.robh at kernel.org/)

1/5
- No change

Reference:
- Link to v12: https://lore.kernel.org/r/20250120-imx-se-if-v12-0-c5ec9754570c at nxp.com

Changes in v12:

5/5
- increased the wait-timeout.

4/5
- rename flag "handle_susp_resm" to "imem_mgmt"
- moved the buffer allocation ot load_fw->imem.buf, to se_probe_if.
- setting imem state at initialization.

3/5
- No change

2/5
- No change

1/5
- No change

Reference:
- Link to v11: https://lore.kernel.org/r/20241220-imx-se-if-v11-0-0c7e65d7ae7b at nxp.com

Changes in v11:

5/5
- devname is constructed by concatinating get_se_if_name(se_if_id) & se_if_instance_id.
- ele_rcv_msg(), is updated to add the wait_interruptible_timeout for the non-NVM-Daemon message exchanges, such that in case of no response from FW,
  Linux donot hangs.
- added a new helper function get_se_if_name(), to return the secure-enclave interface owner's name string.
- added a new helper function get_se_soc_id(), to return the secure-enclave's SoC id.

4/5
- moved the se_if_node_info member "soc_register", to the struct "se_if_node_info_list"; as soc registration done once, not per interface.
- moved the se_if_node_info member "se_fetch_soc_info", to the struct "se_if_node_info_list"; as soc info fetching is done once, not per interface.
- Added two member variable se_if_id and se_if_instance_id to struct se_if_defines.
- removed the member "se_name" from struct "se_if_node_info". Rather, it will constructed by concatinating get_se_if_name(se_if_id) & se_if_instance_id.
- moved the static global variable "se_version", to the newly created structure "struct se_var_info".
- moved the member "struct se_fw_load_info load_fw" of "se_if_node_info_list", to the newly created structure "struct se_var_info".
- Replaced RUNTIME_PM_OPS with SET_SYSTEM_SLEEP_PM_OPS, in power-managment ops.

3/5
- No change

2/5
- No change

1/5
- No change

Reference:
- Link to v10: https://lore.kernel.org/r/20241104-imx-se-if-v10-0-bf06083cc97f at nxp.com

v10: firmware: imx: driver for NXP secure-enclave

Changes in v10:
5/5
- replaced the u8, u16, u32, u64, with __u8, __u16, __u32, __u64 in
  'include/uapi/linux/se_ioctl.h'.

4/5
- No change

3/5
- No change

2/5
- No change

1/5
- No change

Reference:
- Link to v9: https://lore.kernel.org/r/20241016-imx-se-if-v9-0-fd8fa0c04eab at nxp.com

Changes in v9:

4/5
- change se_if_remove function signature, required after rebase to v6.12-rc1.
- move the info->macros to a structure "struct se_if_defines if_defs".
- Removed "info" from "struct se_if_defines if_defs".
- Moved "mem_pool" from "struct se_if_defines if_defs" to "priv".
- Fetching "info" using container-of.

5/5
- Fetching "info" using container-of.
- Fixed issue reported by sparse.

Reference:
- Link to v8: https://lore.kernel.org/r/20241015-imx-se-if-v8-0-915438e267d3 at nxp.com

Changes in v8:

5/5
- Remove the check for SE_IF_CTX_OPENED.
- replaced dev_ctx->priv-dev, priv->dev, whereever possible.
- func "if_misc_deregister" moved before func "init_device_context".
- func "init_device_context" before func "se_ioctl_cmd_snd_rcv_rsp_handler".
- func "se_if_fops_write" and "se_if_fops_read", are moved after func "se_ioctl_get_mu_info".
- non static functions "se_dev_ctx_cpy_out_data, se_dev_ctx_shared_mem_cleanup & init_device_context" are moved static and local scope.
- Removed back & forth between the two structs "struct se_if_device_ctx *dev_ctx" and "struct se_shared_mem_mgmt_info *se_shared_mem_mgmt"
- removed the NULL check for bdesc.
- fops_open, is corrected for acquiring the fops_lock.
- Fops_close, mutex unlock is removed. Infact check for waiting_rsp_clbk_hdl.dev_ctx, is removed.
- sema_init(&dev_ctx->fops_lock, 1);, replaced with Mutex.
- structure member se_notify, is removed.

4/5
- removed initializing err to zero in func ele_fetch_soc_info(),
- replaced 'return 0', with 'goto exit', if the condition (!priv->mem_pool) is true.
- replaced "struct *dev" with "struct se_if_priv *priv", in base_message API(s) and others.
- Created a separate structure "struct se_if_defines" to maintain interface's fixed values like cmd_tag, rsp_tag, success_tag etc.
- removed the macros "WORD_SZ", "SOC_VER_MASK", "DEFAULT_IMX_SOC_VER", "RESERVED_DMA_POOL".
- Added handling for "ctrl+c", by postponing the interrupt, till the response to the "command in flight" is received.
- Removed the mutext lock "se_if_lock".
- furnction prototype for "se_save_imem_state" and "se_restore_imem_state", is changed to pass "imem" by reference.
- Added a new structure "struct se_fw_load_info", dedicated to contain FW loading relevant info. It is a member of struct info_list.
- split "imem_mgmt_file_in_rfs" into two "prim_fw_nm_in_rfs" and "seco_fw_nm_in_rfs", to be part of "struct se_fw_load_info".
- moved the function "se_load_firmware" prior to func "if_mbox_free_channel".
- function "se_load_firmware" is updated to use "request_firmware", instead of "request_firmware_no_wait".
- function "se_load_firmware" is updated to load "primary" fw image, if the imem_state is not BAD. Then load the "secondary FW" image.
- Added a new mutex_lock in the function "se_load_firmware", for ensuring FW loading done once, when there are multiple application are in play.
- instead of "wait_queue_head_t wq", used "sruct completion".
- add devm_add_action with action as se_if_probe_cleanup.

Reference:
- Link to v7: https://lore.kernel.org/r/20240904-imx-se-if-v7-0-5afd2ab74264 at nxp.com

Changes in v7:

5/5
- struct se_clbk_handle, is added with a member struct se_if_device_ctx *dev_ctx.
- func call to ele_miscdev_msg_rcv() & ele_miscdev_msg_send(), are removed.
- func se_ioctl_cmd_snd_rcv_rsp_handler(), is modified to remove the func call to ele_miscdev_msg_rcv() & ele_miscdev_msg_send()
- func se_ioctl_cmd_snd_rcv_rsp_handler is callig func ele_msg_send_rcv(), instead.
- Mutext "se_cmd_if_lock", handling is removed from this patch.
- func ele_miscdev_msg_send() is replaced with func ele_msg_send(), in fops_write.
- func ele_miscdev_msg_rcv() is replaced with func ele_msg_rcv(), in fops_read.
- fops_open is modified to create the new dev_ctx instance (using func init_device_context()), which is not registered as miscdev.
- Only one dev_ctx is registered as miscdev and its reference is stored in the struct se_if_priv, as priv_dev_ctx.
- Separate func cleanup_se_shared_mem() & func init_se_shared_mem(), for shared memory handling part of struct dev_ctx.
- Input param for func(s) ele_msg_rcv(), ele_msg_send() & ele_msg_send_rcv(), is replaced from struct se_if_priv to struct se_if_device_ctx.

4/5
- A new structure is defined name struct "se_clbk_handle", to contain members processed in mailbox call-back function.
- "struct se_if_priv" is modified to contain the two structures of "se_clbk_handle" - waiting_rsp_clbk_hdl & cmd_receiver_clbk_hdl.
- func ele_msg_rcv() is modified to take a new additional input reference param "struct se_clbk_handle *se_clbk_hdl".
- func ele_msg_send() is modified to take a new additional input tx_msg_sz.
- func ele_msg_send_rcv(), is modified to take 2 more inputs - tx_msg_sz & exp_rx_msg_sz.
- func se_val_rsp_hdr_n_status(), is modified to take input of rx_msg buffer, instead of header value, as input param.
- each caller of the func ele_msg_send_rcv(), is sending these two additional input params.
- func se_if_callback(), is modified to work on two structures of "se_clbk_handle" - waiting_rsp_clbk_hdl & cmd_receiver_clbk_hdl.
- Variable "max_dev_ctx", is removed from info & priv struture, as well its usage.
- New member variable "se_img_file_to_load", is added to structure "priv".
- Other member variables - rx_msg(ptr), rx_msg_sz, completion done & list of dev_ctxs, is removed from priv struture, along with their usage.
- func se_resume(), updated to wakeup the two "wq", part of "struct se_clbk_handle": priv->waiting_rsp_clbk_hdl & priv->cmd_receiver_clbk_hdl.

3/5
- Node name is changed from senclave-firmware at 0 to "secure-enclave"

2/5
- Node name is changed to "secure-enclave".

Reference:
- Link to v6: https://lore.kernel.org/r/20240722-imx-se-if-v6-0-ee26a87b824a at nxp.com

Changes in v6:

5/5
- replaced scope_gaurd with gaurd.

4/5
- replaced scope_gaurd with gaurd.
- remove reading the regs property from dtb.
- Added NULL check for priv data fetched from device, as a sanity check, for ele_base_msg apis)

3/5
- replace firmware with senclave-firmware.

2/5
- replace firmware with senclave-firmware.
- drop description for mbox
- Replaced "items:" with maxItems:1 for "memory-region"
- Replaced "items:" with maxItems:1 for "sram"
- remove regs property.
- remove "$nodename"

Reference:
- Link to v5: https://lore.kernel.org/r/20240712-imx-se-if-v5-0-66a79903a872 at nxp.com

Changes in v5:

2/5
- updated the description of mboxes
- updated the description & items for mbox-names.
- updated the description of memory-region
- move "additional properties: false" after allOf block.
- removed other example except one.

4/5
- Corrected the indentation in Kconfig.
- info members:mbox_tx_name & mbox_rx_name, are replaced with macros.

5/5
- Replaced "for  secure enclaves", with "for secure enclaves"
- Replaced "user space" with "userspace".
- End the line "[include]<linux/firmware/imx/ele_mu_ioctl.h>" with a period.

Reference:
- Link to v4: https://lore.kernel.org/r/20240705-imx-se-if-v4-0-52d000e18a1d at nxp.com

Changes in v4:

1/5
a. Removed - from EdgeLock Enclave.

b. Removed , after "Each of the above feature,"

c. replace "can exists" with "can exist".

d.
-messaging units(MU) per SE. Each co-existing 'se' can have one or multiple exclusive
-MU(s), dedicated to itself. None of the MU is shared between two SEs.
+messaging units(MU) per SE. Each co-existing SE can have one or multiple exclusive
+MUs, dedicated to itself. None of the MU is shared between two SEs.
 Communication of the MU is realized using the Linux mailbox driver.

e.
-All those SE interfaces 'se-if' that is/are dedicated to a particular SE, will be
-enumerated and provisioned under the very single 'SE' node.
+Although MU(s) is/are not shared between SE(s). But for SoC like i.MX95 which has
+multiple SE(s) like HSM, V2X-HSM, V2X-SHE; all the SE(s) and their interfaces 'se-if'
+that is/are dedicated to a particular SE will be enumerated and provisioned using the
+single compatible node("fsl,imx95-se").

f. Removed ",". Replaced for "Each 'se-if'," with "Each se-if'.

g. removed ","
-  This layer is responsible for ensuring the communication protocol, that is defined
+  This layer is responsible for ensuring the communication protocol that is defined

h. removed "-"
-  - FW can handle one command-message at a time.
+  - FW can handle one command message at a time.

i.
-  Using these multiple device contexts, that are getting multiplexed over a single MU,
-  user-space application(s) can call fops like write/read to send the command-message,
-  and read back the command-response-message to/from Firmware.
-  fops like read & write uses the above defined service layer API(s) to communicate with
+  Using these multiple device contexts that are getting multiplexed over a single MU,
+  userspace application(s) can call fops like write/read to send the command message,
+  and read back the command response message to/from Firmware.
+  fops like read & write use the above defined service layer API(s) to communicate with
   Firmware.

j. Uppercase for word "Linux".

2/5
a. Rephrased the description to remove list of phandles.

b. Moved required before allOf:
+required:
+  - compatible
+  - reg
+  - mboxes
+  - mbox-names
+
+additionalProperties: false
+
 allOf:

c. replaced not: required: with properties: <property-name>: false.
   # memory-region
-      not:
-        required:
-          - memory-region
+      properties:
+        memory-region: false

   # sram
-    else:
-      not:
-        required:
-          - sram

d. Reduced examples. keeping example of i.MX95.
e. node-name is changed to "firmware@<hex>"

3/5
- node name changed to "firmware@<hex>".

4/5
- used sizeof(*s_info)
- return early, rather than doing goto exit, in ele_get_info().
- Use upper_32_bits() and lower_32_bits()
- use rx_msg here instead of priv->rx_msg
- Moved the status check to validate_rsp_hdr. Rename the function to "se_val_rsp_hdr_n_status"
- typecasting removed header = (struct se_msg_hdr *) msg;
- Converted the API name with prefix imx_ele_* or imx_se_*, to ele_* and se_*, respectively.
- Removed the functions definition & declaration for: free_phybuf_mem_pool() & get_phybuf_mem_pool()
- removed the mbox_free_channel() calls from clean-up.
- Flag "priv->flags" is removed.
- Converted the int se_if_probe_cleanup() to void se_if_probe_cleanup().
- Replaced NULL initialization of structure members: priv->cmd_receiver_dev & priv->waiting_rsp_dev , with comments.
- Removed the function's declaration get_phy_buf_mem_pool1

5/5
Changes to Documentation/ABI/testing/se-cdev.
a. Removed "-" from "secure-enclave" and "file-descriptor".

b. Removed "-" from "shared-library"

c. Replaced "get" with "getting".

d. Added description for the new IOCTL "send command and receive command response"

e. Replaced "wakeup_intruptible" with "wait_event_interruptible"

f. Removed ";"

g. Removd "," from "mailbox_lock,"

h. Replaced "free" with "frees"

i. In mailbox callback function, checking the buffer size before
copying.

Reference:
- Link to v3: https://lore.kernel.org/r/20240617-imx-se-if-v3-0-a7d28dea5c4a at nxp.com

Changes in v3:
5/5:
- Initialize tx_msg with NULL.
- memdup_user() returns an error pointer, not NULL. correct it by adding check for err_ptr.
- new IOCTL is added to send & recieve the message.
- replaced the while loop till list is empty, with list_for_each_entry.
- replaced __list_del_entry, with list_del.
- Removed the dev_err message from copy to user.
- Removed the casting of void *.
- corrected the typcasting in copy to user.
- removed un-necessary goto statement.
- Removed dead code for clean-up of memory.
- Removed un-mapping of secured memory
- Passing se_if_priv structure to init_device_context.
- Updated the below check to replace io.length with round_up(io.length).
	if (shared_mem->size < shared_mem->pos|| io.length >= shared_mem->size - shared_mem->pos)
- Created a function to cleanup the list of shared memory buffers.
- Used list_for_each_entry_safe(). created a separate functions: se_dev_ctx_cpy_out_data() & se_dev_ctx_shared_mem_cleanup()

4/5
- Changed the compatible string to replace "-ele", to "-se".
- Declaration of imx_se_node_info, is done as const in the whole file
- Remove the unused macros from ele_base_msg.h
- Remove the function declaration get_phy_buf_mem_pool1, from the header file.
- Replace the use of dmam_alloc_coherent to dma_alloc_coherent
- Check for function pointer, before calling the fucntion pointer in imx_fetch_se_soc_info
- Removed the unused flag for SE_MU_IO_FLAGS_USE_SEC_MEM.
-  Removed the unused macros WORD_SZ
- instead of struct device *dev, struct se_if_priv *priv, is used as argument to the funtions:se_save_imem_state, se_restore_imem_state, imx_fetch_se_soc_info
- Removed ret from validate_rsp_hdr.
- changed the prefix of the funtion: plat_add_msg_crc and plat_fill_cmd_msg_hdr.
- indentation correction for info structures.
- remove the check for priv not null from se_if_probe_cleanup
- Removed the casting of void *.
- se_load_firmware function is corrected for not freeing the buffer when allocation fails.
- Checking if get_imx_se_node_info() can return NULL, in se_if_probe()
- imem.size has type u32. return value from se_save_imem_state() will be assigned to imem.size in case of success only.
- removed the flag un-setting in case of failure. priv->flags &= (~RESERVED_DMA_POOL);
- removed the function call for devm_of_platform_populate(dev);
- Checking for not-NULL,  before calling the funtion pointer se_fetch_soc_info.
- Removed the checking for reserved memory flag, before freeing up the reserved memory, in se_probe_if_cleanup.

3/5
- Changed the compatible string to replace "-ele", to "-se".

2/5
- to fix the warning error, replaced the "-ele" & "-v2x" in compatible string, to "-se".
- Added an example for ele at 0 for compatible string "fsl,imx95-se"

Reference
- Link to v2: https://lore.kernel.org/r/20240523-imx-se-if-v2-0-5a6fd189a539 at nxp.com

Changes in v2:

4/4
- Split this patch into two: 1. base driver & 2. Miscdev
- Initialize the return variable "err" as 0, before calling 'return err', in the file ele_common.c
- Fix the usage of un-iniitialized pointer variable, by initializing them with NULL, in ele_base_msg.c.
- Fix initializing the ret variable, to return the correct error code in case of issue.
- replaced dmam_alloc_coherent with dma_alloc_coherent.
- Replace the use of ELE_GET_INFO_READ_SZ, with sizeof(soc_info).
- Replaced -1 with -EPERM
- Removed the safety check on func-input param, in ele_get_info().
- fix the assigning data[1] with lower 32 address, rather than zero, for ele_fw_authenticate API.
- Correctly initializing the function's return error code, for file  ele_base_msg.c.
- replaced 'return' with 'goto'.
- Use length in bytes.
- Corrected the structure se_msg_hdr.
- Moved setting of rx_msg  to priv, into the function imx_ele_msg_send_rcv
- Will add lockdep_assert_held, to receive path, in v2.
- corrected the spacing at "ret  = validate_rsp_hdr"
- FIELD_GET() used for RES_STATUS
- Re-write the structure soc_info, matching the information provided in response to this api.
- The "|" goes to the end of the previous line.
- Moved the locking and unlocking of the command lock to the caller of the function.
- removed the safety check for device private data.
- Structure memory reference, used to read message header.
- In the interrupt call back function, remove assigning waiting_rsp_dev to NULL, in case of response message rcv from FW.
- do while removed.
- replaced BIT(1) for RESERVED_DMA_POOL, to BIT(0)
- The backslash is removed while assigning the file name with absolute path to structure variable.fw_name_in_rfs =.
- Update the 'if' condition by removing "idx < 0".
- mbox_request_channel_byname() uses a "char" for the name not a u8. Corrected.
- devm managed resources, are not cleaned now, in function se_probe_if_cleanup
- Used dev_err_probe().
- Used %pe to print error string.
- remove "__maybe_unused" for "struct platform_device *enum_plat_dev __maybe_unused;"
- used FIELD_GET(), for  RES_STATUS. Removed the use of MSG_TAG, MSG_COMMAND, MSG_SIZE, MSG_VER.
- Depricated the used of member of struct se_if_priv, bool no_dev_ctx_used;
- Moved the text explaing the synchronization logic via mutexes, from patch 1/4 to se_ctrl.h.
- removed the type casting of info_list = (struct imx_se_node_info_list *) device_get_match_data(dev->parent);
- Used static variable priv->soc_rev in the se_ctrl.c, replaced the following condition: if (info_list->soc_rev) to if (priv->soc_rev) for checking if this flow is already executed or not.
- imx_fetch_soc_info will return failure if the get_info function fails.
- Removed devm_free from imx_fetch_soc_info too.

3/3
- Made changes to move all the properties to parent node, without any child node.

2/4
- Use Hex pattern string.
- Move the properties to parent node, with no child node.
- Add i.MX95-ele to compatible nodes to fix the warning "/example-2/v2x: failed to match any schema with compatible: ['fsl,imx95-v2x']"

1/1
- Corrected the spelling from creats to creates.
- drop the braces around the plural 's' for interfaces
- written se in upper case SE.
- Replace "multiple message(s)" with messages.
- Removed too much details about locks.

Testing
- make CHECK_DTBS=y freescale/imx8ulp-evk.dtb;
- make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j8  dt_binding_check DT_SCHEMA_FILES=fsl,imx-se.yaml
- make C=1 CHECK=scripts/coccicheck drivers/firmware/imx/*.* W=1 > r.txt
- ./scripts/checkpatch.pl --git <>..HEAD
- Tested the Image and .dtb, on the i.MX8ULP.

Reference
- Link to v1: https://lore.kernel.org/r/20240510-imx-se-if-v1-0-27c5a674916d at nxp.com

---
Pankaj Gupta (7):
      Documentation/firmware: add imx/se to other_interfaces
      dt-bindings: arm: fsl: add imx-se-fw binding doc
      firmware: imx: add driver for NXP EdgeLock Enclave
      firmware: imx: device context dedicated to priv
      firmware: drivers: imx: adds miscdev
      arm64: dts: imx8ulp: add secure enclave node
      arm64: dts: imx8ulp-evk: add reserved memory property

 Documentation/ABI/testing/se-cdev                  |   43 +
 .../devicetree/bindings/firmware/fsl,imx-se.yaml   |   91 ++
 .../driver-api/firmware/other_interfaces.rst       |  131 +++
 arch/arm64/boot/dts/freescale/imx8ulp-evk.dts      |   12 +-
 arch/arm64/boot/dts/freescale/imx8ulp.dtsi         |   11 +-
 drivers/firmware/imx/Kconfig                       |   13 +
 drivers/firmware/imx/Makefile                      |    2 +
 drivers/firmware/imx/ele_base_msg.c                |  322 ++++++
 drivers/firmware/imx/ele_base_msg.h                |  115 ++
 drivers/firmware/imx/ele_common.c                  |  373 +++++++
 drivers/firmware/imx/ele_common.h                  |   51 +
 drivers/firmware/imx/se_ctrl.c                     | 1163 ++++++++++++++++++++
 drivers/firmware/imx/se_ctrl.h                     |  128 +++
 include/linux/firmware/imx/se_api.h                |   14 +
 include/uapi/linux/se_ioctl.h                      |   97 ++
 15 files changed, 2563 insertions(+), 3 deletions(-)
---
base-commit: 4a26e7032d7d57c998598c08a034872d6f0d3945
change-id: 20240507-imx-se-if-a40055093dc6

Best regards,
-- 
Pankaj Gupta <pankaj.gupta at nxp.com>



From pankaj.gupta at nxp.com  Fri Dec 12 01:14:12 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Fri, 12 Dec 2025 14:44:12 +0530
Subject: [PATCH v21 1/7] Documentation/firmware: add imx/se to
 other_interfaces
In-Reply-To: <20251212-imx-se-if-v21-0-ee7d6052d848@nxp.com>
References: <20251212-imx-se-if-v21-0-ee7d6052d848@nxp.com>
Message-ID: <20251212-imx-se-if-v21-1-ee7d6052d848@nxp.com>

Documents i.MX SoC's Service layer and C_DEV driver for selected SoC(s)
that contains the NXP hardware IP(s) for Secure Enclaves(se) like:
- NXP EdgeLock Enclave on i.MX93 & i.MX8ULP

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
---
 .../driver-api/firmware/other_interfaces.rst       | 131 +++++++++++++++++++++
 1 file changed, 131 insertions(+)

diff --git a/Documentation/driver-api/firmware/other_interfaces.rst b/Documentation/driver-api/firmware/other_interfaces.rst
index 06ac89adaafb..2a7d7100fdd4 100644
--- a/Documentation/driver-api/firmware/other_interfaces.rst
+++ b/Documentation/driver-api/firmware/other_interfaces.rst
@@ -49,3 +49,134 @@ of the requests on to a secure monitor (EL3).
 
 .. kernel-doc:: drivers/firmware/stratix10-svc.c
    :export:
+
+NXP Secure Enclave Firmware Interface
+=====================================
+
+Introduction
+------------
+The NXP's i.MX HW IP like EdgeLock Enclave, V2X etc., creates an embedded secure
+enclave within the SoC boundary to enable features like
+ - Hardware Security Module (HSM)
+ - Security Hardware Extension (SHE)
+ - Vehicular to Anything (V2X)
+
+Each of the above feature is enabled through dedicated NXP H/W IP on the SoC.
+On a single SoC, multiple hardware IP (or can say more than one secure enclave)
+can exist.
+
+NXP SoCs enabled with the such secure enclaves(SEs) IPs are:
+i.MX93, i.MX8ULP
+
+To communicate with one or more co-existing SE(s) on SoC, there is/are dedicated
+messaging units(MU) per SE. Each co-existing SE can have one or multiple exclusive
+MUs, dedicated to itself. None of the MU is shared between two SEs. Communication
+of the MU is realized using the mailbox driver. Each secure enclave can cater to
+multiple clients by virtue of these exclusive MUs. Also, they can distinguish
+transactions originating from these clients based on the MU used and core security
+state. The communication between the clients and secure enclaves is in form of
+command/response mechanism. Each client could expose specific set of secure enclave
+features to the higher layers, based on the commands supported by that client. For
+example, the secure enclave could simultaneously support an OPTEE TA and Linux
+middleware as clients. Each of these clients can expose specific set of secure
+enclave features based on the command set supported by them.
+
+NXP Secure Enclave(SE) Interface
+--------------------------------
+Although MU(s) is/are not shared between SE(s). But for SoC like i.MX95 which has
+multiple SE(s) like HSM, V2X-HSM, V2X-SHE; all the SE(s) and their interfaces 'se-if'
+that is/are dedicated to a particular SE will be enumerated and provisioned using the
+single compatible node("fsl,imx95-se").
+
+Each 'se-if' comprise of twp layers:
+- (C_DEV Layer) User-Space software-access interface.
+- (Service Layer) OS-level software-access interface.
+
+::
+   +--------------------------------------------+
+   |            Character Device(C_DEV)         |
+   |                                            |
+   |   +---------+ +---------+     +---------+  |
+   |   | misc #1 | | misc #2 | ... | misc #n |  |
+   |   |  dev    | |  dev    |     | dev     |  |
+   |   +---------+ +---------+     +---------+  |
+   |        +-------------------------+         |
+   |        | Misc. Dev Synchr. Logic |         |
+   |        +-------------------------+         |
+   |                                            |
+   +--------------------------------------------+
+
+   +--------------------------------------------+
+   |               Service Layer                |
+   |                                            |
+   |      +-----------------------------+       |
+   |      | Message Serialization Logic |       |
+   |      +-----------------------------+       |
+   |          +---------------+                 |
+   |          |  imx-mailbox  |                 |
+   |          |   mailbox.c   |                 |
+   |          +---------------+                 |
+   |                                            |
+   +--------------------------------------------+
+
+- service layer:
+  This layer is responsible for ensuring the communication protocol that is defined
+  for communication with firmware.
+
+  FW Communication protocol ensures two things:
+  - Serializing the messages to be sent over an MU.
+
+  - FW can handle one command message at a time.
+
+- c_dev:
+  This layer offers character device contexts, created as '/dev/<se>_mux_chx'.
+  Using these multiple device contexts that are getting multiplexed over a single MU,
+  userspace application(s) can call fops like write/read to send the command message,
+  and read back the command response message to/from Firmware.
+  fops like read & write use the above defined service layer API(s) to communicate with
+  Firmware.
+
+  Misc-device(/dev/<se>_mux_chn) synchronization protocol:
+::
+
+                                Non-Secure               +   Secure
+                                                         |
+                                                         |
+                  +---------+      +-------------+       |
+                  | se_fw.c +<---->+imx-mailbox.c|       |
+                  |         |      |  mailbox.c  +<-->+------+    +------+
+                  +---+-----+      +-------------+    | MU X +<-->+ ELE |
+                      |                               +------+    +------+
+                      +----------------+                 |
+                      |                |                 |
+                      v                v                 |
+                  logical           logical              |
+                  receiver          waiter               |
+                     +                 +                 |
+                     |                 |                 |
+                     |                 |                 |
+                     |            +----+------+          |
+                     |            |           |          |
+                     |            |           |          |
+              device_ctx     device_ctx     device_ctx   |
+                                                         |
+                User 0        User 1       User Y        |
+                +------+      +------+     +------+      |
+                |misc.c|      |misc.c|     |misc.c|      |
+ kernel space   +------+      +------+     +------+      |
+                                                         |
+ +------------------------------------------------------ |
+                    |             |           |          |
+ userspace     /dev/ele_muXch0    |           |          |
+                          /dev/ele_muXch1     |          |
+                                        /dev/ele_muXchY  |
+                                                         |
+
+When a user sends a command to the firmware, it registers its device_ctx
+as waiter of a response from firmware.
+
+Enclave's Firmware owns the storage management, over Linux filesystem.
+For this c_dev provisions a dedicated slave device called "receiver".
+
+.. kernel-doc:: drivers/firmware/imx/se_fw.c
+   :export:

-- 
2.43.0



From pankaj.gupta at nxp.com  Fri Dec 12 01:14:13 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Fri, 12 Dec 2025 14:44:13 +0530
Subject: [PATCH v21 2/7] dt-bindings: arm: fsl: add imx-se-fw binding doc
In-Reply-To: <20251212-imx-se-if-v21-0-ee7d6052d848@nxp.com>
References: <20251212-imx-se-if-v21-0-ee7d6052d848@nxp.com>
Message-ID: <20251212-imx-se-if-v21-2-ee7d6052d848@nxp.com>

The NXP security hardware IP(s) like: i.MX EdgeLock Enclave, V2X etc.,
creates an embedded secure enclave within the SoC boundary to enable
features like:
- HSM
- SHE
- V2X

Secure-Enclave(s) communication interface are typically via message
unit, i.e., based on mailbox linux kernel driver. This driver enables
communication ensuring well defined message sequence protocol between
Application Core and enclave's firmware.

Driver configures multiple misc-device on the MU, for multiple
user-space applications, to be able to communicate over single MU.

It exists on some i.MX processors. e.g. i.MX8ULP, i.MX93 etc.

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
---
 .../devicetree/bindings/firmware/fsl,imx-se.yaml   | 91 ++++++++++++++++++++++
 1 file changed, 91 insertions(+)

diff --git a/Documentation/devicetree/bindings/firmware/fsl,imx-se.yaml b/Documentation/devicetree/bindings/firmware/fsl,imx-se.yaml
new file mode 100644
index 000000000000..fa81adbf9b80
--- /dev/null
+++ b/Documentation/devicetree/bindings/firmware/fsl,imx-se.yaml
@@ -0,0 +1,91 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/firmware/fsl,imx-se.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP i.MX HW Secure Enclave(s) EdgeLock Enclave
+
+maintainers:
+  - Pankaj Gupta <pankaj.gupta at nxp.com>
+
+description: |
+  NXP's SoC may contain one or multiple embedded secure-enclave HW
+  IP(s) like i.MX EdgeLock Enclave, V2X etc. These NXP's HW IP(s)
+  enables features like
+    - Hardware Security Module (HSM),
+    - Security Hardware Extension (SHE), and
+    - Vehicular to Anything (V2X)
+
+  Communication interface to the secure-enclaves(se) is based on the
+  messaging unit(s).
+
+properties:
+  compatible:
+    enum:
+      - fsl,imx8ulp-se-ele-hsm
+      - fsl,imx93-se-ele-hsm
+      - fsl,imx95-se-ele-hsm
+
+  mboxes:
+    items:
+      - description: mailbox phandle to send message to se firmware
+      - description: mailbox phandle to receive message from se firmware
+
+  mbox-names:
+    items:
+      - const: tx
+      - const: rx
+
+  memory-region:
+    maxItems: 1
+
+  sram:
+    maxItems: 1
+
+required:
+  - compatible
+  - mboxes
+  - mbox-names
+
+allOf:
+  # memory-region
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - fsl,imx8ulp-se-ele-hsm
+              - fsl,imx93-se-ele-hsm
+    then:
+      required:
+        - memory-region
+    else:
+      properties:
+        memory-region: false
+
+  # sram
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - fsl,imx8ulp-se-ele-hsm
+    then:
+      required:
+        - sram
+
+    else:
+      properties:
+        sram: false
+
+additionalProperties: false
+
+examples:
+  - |
+    secure-enclave {
+      compatible = "fsl,imx95-se-ele-hsm";
+      mboxes = <&ele_mu0 0 0>, <&ele_mu0 1 0>;
+      mbox-names = "tx", "rx";
+    };
+...

-- 
2.43.0



From pankaj.gupta at nxp.com  Fri Dec 12 01:14:14 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Fri, 12 Dec 2025 14:44:14 +0530
Subject: [PATCH v21 3/7] firmware: imx: add driver for NXP EdgeLock Enclave
In-Reply-To: <20251212-imx-se-if-v21-0-ee7d6052d848@nxp.com>
References: <20251212-imx-se-if-v21-0-ee7d6052d848@nxp.com>
Message-ID: <20251212-imx-se-if-v21-3-ee7d6052d848@nxp.com>

Add driver for enabling MU based communication interface to secure-enclave.

NXP hardware IP(s) for secure-enclaves like Edgelock Enclave(ELE), are
embedded in the SoC to support the features like HSM, SHE & V2X, using
message based communication interface.

The secure enclave FW communicates with Linux over single or multiple
dedicated messaging unit(MU) based interface(s).
Exists on i.MX SoC(s) like i.MX8ULP, i.MX93, i.MX95 etc.

For i.MX9x SoC(s) there is at least one dedicated ELE MU(s) for each
world - Linux(one or more) and OPTEE-OS (one or more).

Other dependent kernel drivers will be:
- NVMEM: that supports non-volatile devices like EFUSES,
         managed by NXP's secure-enclave.

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
Changes from v20 to v21:
- smatch warning fixes.
- Added "COMPILE_TEST" into "depends on IMX_MBOX && ARCH_MXC && ARM64"
- removed "__free(kfree)" & added kfree();
---
 drivers/firmware/imx/Kconfig        |  13 ++
 drivers/firmware/imx/Makefile       |   2 +
 drivers/firmware/imx/ele_base_msg.c | 294 ++++++++++++++++++++++++++
 drivers/firmware/imx/ele_base_msg.h |  95 +++++++++
 drivers/firmware/imx/ele_common.c   | 335 +++++++++++++++++++++++++++++
 drivers/firmware/imx/ele_common.h   |  45 ++++
 drivers/firmware/imx/se_ctrl.c      | 408 ++++++++++++++++++++++++++++++++++++
 drivers/firmware/imx/se_ctrl.h      |  86 ++++++++
 include/linux/firmware/imx/se_api.h |  14 ++
 9 files changed, 1292 insertions(+)

diff --git a/drivers/firmware/imx/Kconfig b/drivers/firmware/imx/Kconfig
index 127ad752acf8..1f89dd140113 100644
--- a/drivers/firmware/imx/Kconfig
+++ b/drivers/firmware/imx/Kconfig
@@ -55,3 +55,16 @@ config IMX_SCMI_MISC_DRV
 	  core that could provide misc functions such as board control.
 
 	  This driver can also be built as a module.
+
+config IMX_SEC_ENCLAVE
+	tristate "i.MX Embedded Secure Enclave - EdgeLock Enclave Firmware driver."
+	depends on (IMX_MBOX && ARCH_MXC && ARM64) || COMPILE_TEST
+	select FW_LOADER
+	default m if ARCH_MXC
+
+	help
+	  Exposes APIs supported by the iMX Secure Enclave HW IP called:
+	  - EdgeLock Enclave Firmware (for i.MX8ULP, i.MX93),
+	    like base, HSM, V2X & SHE using the SAB protocol via the shared Messaging
+	    Unit. This driver exposes these interfaces via a set of file descriptors
+	    allowing to configure shared memory, send and receive messages.
diff --git a/drivers/firmware/imx/Makefile b/drivers/firmware/imx/Makefile
index 3bbaffa6e347..4412b15846b1 100644
--- a/drivers/firmware/imx/Makefile
+++ b/drivers/firmware/imx/Makefile
@@ -4,3 +4,5 @@ obj-$(CONFIG_IMX_SCU)		+= imx-scu.o misc.o imx-scu-irq.o rm.o imx-scu-soc.o
 obj-${CONFIG_IMX_SCMI_CPU_DRV}	+= sm-cpu.o
 obj-${CONFIG_IMX_SCMI_MISC_DRV}	+= sm-misc.o
 obj-${CONFIG_IMX_SCMI_LMM_DRV}	+= sm-lmm.o
+sec_enclave-objs		= se_ctrl.o ele_common.o ele_base_msg.o
+obj-${CONFIG_IMX_SEC_ENCLAVE}	+= sec_enclave.o
diff --git a/drivers/firmware/imx/ele_base_msg.c b/drivers/firmware/imx/ele_base_msg.c
new file mode 100644
index 000000000000..b44041bc41e0
--- /dev/null
+++ b/drivers/firmware/imx/ele_base_msg.c
@@ -0,0 +1,294 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 NXP
+ */
+
+#include <linux/types.h>
+
+#include <linux/completion.h>
+#include <linux/dma-mapping.h>
+#include <linux/genalloc.h>
+
+#include "ele_base_msg.h"
+#include "ele_common.h"
+
+#define FW_DBG_DUMP_FIXED_STR		"ELE"
+
+int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info)
+{
+	struct se_api_msg *tx_msg = NULL;
+	struct se_api_msg *rx_msg = NULL;
+	dma_addr_t get_info_addr = 0;
+	u32 *get_info_data = NULL;
+	int ret = 0;
+
+	if (!priv)
+		return -EINVAL;
+
+	memset(s_info, 0x0, sizeof(*s_info));
+
+	tx_msg = kzalloc(ELE_GET_INFO_REQ_MSG_SZ, GFP_KERNEL);
+	if (!tx_msg)
+		return -ENOMEM;
+
+	rx_msg = kzalloc(ELE_GET_INFO_RSP_MSG_SZ, GFP_KERNEL);
+	if (!rx_msg) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	if (priv->mem_pool)
+		get_info_data = gen_pool_dma_alloc(priv->mem_pool,
+						   ELE_GET_INFO_BUFF_SZ,
+						   &get_info_addr);
+	else
+		get_info_data = dma_alloc_coherent(priv->dev,
+						   ELE_GET_INFO_BUFF_SZ,
+						   &get_info_addr,
+						   GFP_KERNEL);
+	if (!get_info_data) {
+		dev_dbg(priv->dev,
+			"%s: Failed to allocate get_info_addr.", __func__);
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	ret = se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
+				  ELE_GET_INFO_REQ, ELE_GET_INFO_REQ_MSG_SZ,
+				  true);
+	if (ret)
+		goto exit;
+
+	tx_msg->data[0] = upper_32_bits(get_info_addr);
+	tx_msg->data[1] = lower_32_bits(get_info_addr);
+	tx_msg->data[2] = sizeof(*s_info);
+	ret = ele_msg_send_rcv(priv, tx_msg, ELE_GET_INFO_REQ_MSG_SZ, rx_msg,
+			       ELE_GET_INFO_RSP_MSG_SZ);
+	if (ret < 0)
+		goto exit;
+
+	ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_GET_INFO_REQ,
+				      ELE_GET_INFO_RSP_MSG_SZ, true);
+
+	memcpy(s_info, get_info_data, sizeof(*s_info));
+
+exit:
+	if (priv->mem_pool)
+		gen_pool_free(priv->mem_pool, (u64)get_info_data,
+			      ELE_GET_INFO_BUFF_SZ);
+	else
+		dma_free_coherent(priv->dev, ELE_GET_INFO_BUFF_SZ,
+				  get_info_data, get_info_addr);
+
+	kfree(tx_msg);
+	kfree(rx_msg);
+	return ret;
+}
+
+int ele_fetch_soc_info(struct se_if_priv *priv, void *data)
+{
+	return ele_get_info(priv, data);
+}
+
+int ele_ping(struct se_if_priv *priv)
+{
+	struct se_api_msg *tx_msg = NULL;
+	struct se_api_msg *rx_msg = NULL;
+	int ret = 0;
+
+	if (!priv)
+		return -EINVAL;
+
+	tx_msg = kzalloc(ELE_PING_REQ_SZ, GFP_KERNEL);
+	if (!tx_msg)
+		return -ENOMEM;
+
+	rx_msg = kzalloc(ELE_PING_RSP_SZ, GFP_KERNEL);
+	if (!rx_msg) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	ret = se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
+				  ELE_PING_REQ, ELE_PING_REQ_SZ, true);
+	if (ret) {
+		dev_err(priv->dev, "Error: se_fill_cmd_msg_hdr failed.");
+		goto exit;
+	}
+
+	ret = ele_msg_send_rcv(priv, tx_msg, ELE_PING_REQ_SZ, rx_msg,
+			       ELE_PING_RSP_SZ);
+	if (ret < 0)
+		goto exit;
+
+	ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_PING_REQ,
+				      ELE_PING_RSP_SZ, true);
+exit:
+	kfree(tx_msg);
+	kfree(rx_msg);
+	return ret;
+}
+
+int ele_service_swap(struct se_if_priv *priv,
+		     phys_addr_t addr,
+		     u32 addr_size, u16 flag)
+{
+	struct se_api_msg *tx_msg = NULL;
+	struct se_api_msg *rx_msg = NULL;
+	int ret = 0;
+
+	if (!priv)
+		return -EINVAL;
+
+	tx_msg = kzalloc(ELE_SERVICE_SWAP_REQ_MSG_SZ, GFP_KERNEL);
+	if (!tx_msg)
+		return -ENOMEM;
+
+	rx_msg = kzalloc(ELE_SERVICE_SWAP_RSP_MSG_SZ, GFP_KERNEL);
+	if (!rx_msg) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	ret = se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
+				  ELE_SERVICE_SWAP_REQ,
+				  ELE_SERVICE_SWAP_REQ_MSG_SZ, true);
+	if (ret)
+		goto exit;
+
+	tx_msg->data[0] = flag;
+	tx_msg->data[1] = addr_size;
+	tx_msg->data[2] = ELE_NONE_VAL;
+	tx_msg->data[3] = lower_32_bits(addr);
+	tx_msg->data[4] = se_get_msg_chksum((u32 *)&tx_msg[0],
+					    ELE_SERVICE_SWAP_REQ_MSG_SZ);
+	if (!tx_msg->data[4]) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	ret = ele_msg_send_rcv(priv, tx_msg, ELE_SERVICE_SWAP_REQ_MSG_SZ,
+			       rx_msg, ELE_SERVICE_SWAP_RSP_MSG_SZ);
+	if (ret < 0)
+		goto exit;
+
+	ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_SERVICE_SWAP_REQ,
+				      ELE_SERVICE_SWAP_RSP_MSG_SZ, true);
+	if (ret)
+		goto exit;
+
+	if (flag == ELE_IMEM_EXPORT)
+		ret = rx_msg->data[1];
+	else
+		ret = 0;
+exit:
+	kfree(tx_msg);
+	kfree(rx_msg);
+	return ret;
+}
+
+int ele_fw_authenticate(struct se_if_priv *priv, phys_addr_t contnr_addr,
+			phys_addr_t img_addr)
+{
+	struct se_api_msg *tx_msg = NULL;
+	struct se_api_msg *rx_msg = NULL;
+	int ret = 0;
+
+	if (!priv)
+		return -EINVAL;
+
+	tx_msg = kzalloc(ELE_FW_AUTH_REQ_SZ, GFP_KERNEL);
+	if (!tx_msg)
+		return -ENOMEM;
+
+	rx_msg = kzalloc(ELE_FW_AUTH_RSP_MSG_SZ, GFP_KERNEL);
+	if (!rx_msg) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	ret = se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
+				  ELE_FW_AUTH_REQ, ELE_FW_AUTH_REQ_SZ, true);
+	if (ret)
+		goto exit;
+
+	tx_msg->data[0] = lower_32_bits(contnr_addr);
+	tx_msg->data[1] = upper_32_bits(contnr_addr);
+	tx_msg->data[2] = img_addr;
+
+	ret = ele_msg_send_rcv(priv, tx_msg, ELE_FW_AUTH_REQ_SZ, rx_msg,
+			       ELE_FW_AUTH_RSP_MSG_SZ);
+	if (ret < 0)
+		goto exit;
+
+	ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_FW_AUTH_REQ,
+				      ELE_FW_AUTH_RSP_MSG_SZ, true);
+exit:
+	kfree(tx_msg);
+	kfree(rx_msg);
+	return ret;
+}
+
+int ele_debug_dump(struct se_if_priv *priv)
+{
+	struct se_api_msg *tx_msg = NULL;
+	struct se_api_msg *rx_msg = NULL;
+	bool keep_logging;
+	int msg_ex_cnt;
+	int ret = 0;
+	int i;
+
+	if (!priv)
+		return -EINVAL;
+
+	tx_msg = kzalloc(ELE_DEBUG_DUMP_REQ_SZ, GFP_KERNEL);
+	if (!tx_msg)
+		return -ENOMEM;
+
+	rx_msg = kzalloc(ELE_DEBUG_DUMP_RSP_SZ, GFP_KERNEL);
+	if (!rx_msg) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	ret = se_fill_cmd_msg_hdr(priv, &tx_msg->header, ELE_DEBUG_DUMP_REQ,
+				  ELE_DEBUG_DUMP_REQ_SZ, true);
+	if (ret)
+		goto exit;
+
+	msg_ex_cnt = 0;
+	do {
+		memset(rx_msg, 0x0, ELE_DEBUG_DUMP_RSP_SZ);
+
+		ret = ele_msg_send_rcv(priv, tx_msg, ELE_DEBUG_DUMP_REQ_SZ,
+				       rx_msg, ELE_DEBUG_DUMP_RSP_SZ);
+		if (ret < 0)
+			goto exit;
+
+		ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_DEBUG_DUMP_REQ,
+					      ELE_DEBUG_DUMP_RSP_SZ, true);
+		if (ret) {
+			dev_err(priv->dev, "Dump_Debug_Buffer Error: %x.", ret);
+			break;
+		}
+		keep_logging = (rx_msg->header.size >= (ELE_DEBUG_DUMP_RSP_SZ >> 2) &&
+				msg_ex_cnt < ELE_MAX_DBG_DMP_PKT);
+
+		rx_msg->header.size -= 2;
+
+		if (rx_msg->header.size > 4)
+			rx_msg->header.size--;
+
+		for (i = 0; i < rx_msg->header.size; i += 2)
+			dev_info(priv->dev, "%s%02x_%02x: 0x%08x 0x%08x",
+				 FW_DBG_DUMP_FIXED_STR,	msg_ex_cnt, i,
+				 rx_msg->data[i + 1], rx_msg->data[i + 2]);
+
+		msg_ex_cnt++;
+	} while (keep_logging);
+
+exit:
+	kfree(tx_msg);
+	kfree(rx_msg);
+	return ret;
+}
diff --git a/drivers/firmware/imx/ele_base_msg.h b/drivers/firmware/imx/ele_base_msg.h
new file mode 100644
index 000000000000..8e5b015e99a2
--- /dev/null
+++ b/drivers/firmware/imx/ele_base_msg.h
@@ -0,0 +1,95 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2025 NXP
+ *
+ * Header file for the EdgeLock Enclave Base API(s).
+ */
+
+#ifndef ELE_BASE_MSG_H
+#define ELE_BASE_MSG_H
+
+#include <linux/device.h>
+#include <linux/types.h>
+
+#include "se_ctrl.h"
+
+#define ELE_NONE_VAL			0x0
+
+#define ELE_GET_INFO_REQ		0xda
+#define ELE_GET_INFO_REQ_MSG_SZ		0x10
+#define ELE_GET_INFO_RSP_MSG_SZ		0x08
+
+#define MAX_UID_SIZE                     (16)
+#define DEV_GETINFO_ROM_PATCH_SHA_SZ     (32)
+#define DEV_GETINFO_FW_SHA_SZ            (32)
+#define DEV_GETINFO_OEM_SRKH_SZ          (64)
+#define DEV_GETINFO_MIN_VER_MASK	0xff
+#define DEV_GETINFO_MAJ_VER_MASK	0xff00
+#define ELE_DEV_INFO_EXTRA_SZ		0x60
+
+struct dev_info {
+	u8  cmd;
+	u8  ver;
+	u16 length;
+	u16 soc_id;
+	u16 soc_rev;
+	u16 lmda_val;
+	u8  ssm_state;
+	u8  dev_atts_api_ver;
+	u8  uid[MAX_UID_SIZE];
+	u8  sha_rom_patch[DEV_GETINFO_ROM_PATCH_SHA_SZ];
+	u8  sha_fw[DEV_GETINFO_FW_SHA_SZ];
+};
+
+struct dev_addn_info {
+	u8  oem_srkh[DEV_GETINFO_OEM_SRKH_SZ];
+	u8  trng_state;
+	u8  csal_state;
+	u8  imem_state;
+	u8  reserved2;
+};
+
+struct ele_dev_info {
+	struct dev_info d_info;
+	struct dev_addn_info d_addn_info;
+};
+
+#define ELE_GET_INFO_BUFF_SZ		(sizeof(struct ele_dev_info) \
+						+ ELE_DEV_INFO_EXTRA_SZ)
+
+#define GET_SERIAL_NUM_FROM_UID(x, uid_word_sz) \
+	(((u64)(((u32 *)(x))[(uid_word_sz) - 1]) << 32) | ((u32 *)(x))[0])
+
+#define ELE_MAX_DBG_DMP_PKT		50
+#define ELE_DEBUG_DUMP_REQ		0x21
+#define ELE_DEBUG_DUMP_REQ_SZ		0x4
+#define ELE_DEBUG_DUMP_RSP_SZ		0x5c
+
+#define ELE_PING_REQ			0x01
+#define ELE_PING_REQ_SZ			0x04
+#define ELE_PING_RSP_SZ			0x08
+
+#define ELE_SERVICE_SWAP_REQ		0xdf
+#define ELE_SERVICE_SWAP_REQ_MSG_SZ	0x18
+#define ELE_SERVICE_SWAP_RSP_MSG_SZ	0x0c
+#define ELE_IMEM_SIZE			0x10000
+#define ELE_IMEM_STATE_OK		0xca
+#define ELE_IMEM_STATE_BAD		0xfe
+#define ELE_IMEM_STATE_WORD		0x27
+#define ELE_IMEM_STATE_MASK		0x00ff0000
+#define ELE_IMEM_EXPORT			0x1
+#define ELE_IMEM_IMPORT			0x2
+
+#define ELE_FW_AUTH_REQ			0x02
+#define ELE_FW_AUTH_REQ_SZ		0x10
+#define ELE_FW_AUTH_RSP_MSG_SZ		0x08
+
+int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info);
+int ele_fetch_soc_info(struct se_if_priv *priv, void *data);
+int ele_ping(struct se_if_priv *priv);
+int ele_service_swap(struct se_if_priv *priv, phys_addr_t addr,
+		     u32 addr_size, u16 flag);
+int ele_fw_authenticate(struct se_if_priv *priv, phys_addr_t contnr_addr,
+			phys_addr_t img_addr);
+int ele_debug_dump(struct se_if_priv *priv);
+#endif
diff --git a/drivers/firmware/imx/ele_common.c b/drivers/firmware/imx/ele_common.c
new file mode 100644
index 000000000000..a7150ff8e3b9
--- /dev/null
+++ b/drivers/firmware/imx/ele_common.c
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 NXP
+ */
+
+#include "ele_base_msg.h"
+#include "ele_common.h"
+
+/*
+ * se_get_msg_chksum() - to calculate checksum word by word.
+ *
+ * @msg : reference to the input msg-data.
+ * @msg_len : reference to the input msg-data length in bytes.
+ *            Includes extra 4 bytes (or 1 words) chksum.
+ *
+ * This function returns the checksum calculated by ORing word by word.
+ *
+ * Return:
+ *  0: if the input length is not 4 byte aligned, or num of words < 5.
+ *  chksum: calculated word by word.
+ */
+u32 se_get_msg_chksum(u32 *msg, u32 msg_len)
+{
+	u32 nb_words = msg_len / (u32)sizeof(u32);
+	u32 chksum = 0;
+	u32 i;
+
+	if (nb_words < 5)
+		return chksum;
+
+	if (msg_len % SE_MSG_WORD_SZ) {
+		pr_err("Msg-len is not 4-byte aligned.");
+		return chksum;
+	}
+
+	/* nb_words include one checksum word, so skip it. */
+	nb_words--;
+
+	for (i = 0; i < nb_words; i++)
+		chksum ^= *(msg + i);
+
+	return chksum;
+}
+
+int ele_msg_rcv(struct se_if_priv *priv, struct se_clbk_handle *se_clbk_hdl)
+{
+	unsigned long timeout;
+	int ret;
+
+	do {
+		timeout = MAX_SCHEDULE_TIMEOUT;
+
+		ret = wait_for_completion_interruptible_timeout(&se_clbk_hdl->done, timeout);
+		if (ret == -ERESTARTSYS) {
+			if (priv->waiting_rsp_clbk_hdl.rx_msg) {
+				priv->waiting_rsp_clbk_hdl.signal_rcvd = true;
+				continue;
+			}
+			ret = -EINTR;
+			break;
+		}
+		ret = se_clbk_hdl->rx_msg_sz;
+		break;
+	} while (ret < 0);
+
+	return ret;
+}
+
+int ele_msg_send(struct se_if_priv *priv,
+		 void *tx_msg,
+		 int tx_msg_sz)
+{
+	struct se_msg_hdr *header = tx_msg;
+	int err;
+
+	/*
+	 * Check that the size passed as argument matches the size
+	 * carried in the message.
+	 */
+	if (header->size << 2 != tx_msg_sz) {
+		dev_err(priv->dev,
+			"User buf hdr: 0x%x, sz mismatced with input-sz (%d != %d).",
+			*(u32 *)header, header->size << 2, tx_msg_sz);
+		return -EINVAL;
+	}
+
+	err = mbox_send_message(priv->tx_chan, tx_msg);
+	if (err < 0) {
+		dev_err(priv->dev, "Error: mbox_send_message failure.\n");
+		return err;
+	}
+
+	return tx_msg_sz;
+}
+
+/* API used for send/receive blocking call. */
+int ele_msg_send_rcv(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz,
+		     void *rx_msg, int exp_rx_msg_sz)
+{
+	int err;
+
+	guard(mutex)(&priv->se_if_cmd_lock);
+
+	priv->waiting_rsp_clbk_hdl.rx_msg_sz = exp_rx_msg_sz;
+	priv->waiting_rsp_clbk_hdl.rx_msg = rx_msg;
+
+	err = ele_msg_send(priv, tx_msg, tx_msg_sz);
+	if (err < 0)
+		return err;
+
+	err = ele_msg_rcv(priv, &priv->waiting_rsp_clbk_hdl);
+
+	if (priv->waiting_rsp_clbk_hdl.signal_rcvd) {
+		err = -EINTR;
+		priv->waiting_rsp_clbk_hdl.signal_rcvd = false;
+		dev_err(priv->dev, "Err[0x%x]:Interrupted by signal.\n", err);
+	}
+
+	return err;
+}
+
+static bool check_hdr_exception_for_sz(struct se_if_priv *priv,
+				       struct se_msg_hdr *header)
+{
+	/*
+	 * List of API(s) header that can be accepte variable length
+	 * response buffer.
+	 */
+	if (header->command == ELE_DEBUG_DUMP_REQ &&
+	    header->ver == priv->if_defs->base_api_ver &&
+	    header->size >= 0 && header->size <= ELE_DEBUG_DUMP_RSP_SZ)
+		return true;
+
+	return false;
+}
+
+/*
+ * Callback called by mailbox FW, when data is received.
+ */
+void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg)
+{
+	struct se_clbk_handle *se_clbk_hdl;
+	struct device *dev = mbox_cl->dev;
+	struct se_msg_hdr *header;
+	struct se_if_priv *priv;
+	u32 rx_msg_sz;
+
+	priv = dev_get_drvdata(dev);
+
+	/* The function can be called with NULL msg */
+	if (!msg) {
+		dev_err(dev, "Message is invalid\n");
+		return;
+	}
+
+	header = msg;
+	rx_msg_sz = header->size << 2;
+
+	/* Incoming command: wake up the receiver if any. */
+	if (header->tag == priv->if_defs->cmd_tag) {
+		se_clbk_hdl = &priv->cmd_receiver_clbk_hdl;
+		dev_dbg(dev, "Selecting cmd receiver for mesg header:0x%x.",
+			*(u32 *)header);
+
+		/*
+		 * Pre-allocated buffer of MAX_NVM_MSG_LEN
+		 * as the NVM command are initiated by FW.
+		 * Size is revealed as part of this call function.
+		 */
+		if (rx_msg_sz > MAX_NVM_MSG_LEN) {
+			dev_err(dev,
+				"CMD-RCVER NVM: hdr(0x%x) with different sz(%d != %d).\n",
+				*(u32 *)header, rx_msg_sz, se_clbk_hdl->rx_msg_sz);
+
+			se_clbk_hdl->rx_msg_sz = MAX_NVM_MSG_LEN;
+		}
+		se_clbk_hdl->rx_msg_sz = rx_msg_sz;
+
+	} else if (header->tag == priv->if_defs->rsp_tag) {
+		se_clbk_hdl = &priv->waiting_rsp_clbk_hdl;
+		dev_dbg(dev, "Selecting resp waiter for mesg header:0x%x.",
+			*(u32 *)header);
+
+		if (rx_msg_sz != se_clbk_hdl->rx_msg_sz &&
+		    check_hdr_exception_for_sz(priv, header)) {
+			dev_err(dev,
+				"Rsp to CMD: hdr(0x%x) with different sz(%d != %d).\n",
+				*(u32 *)header, rx_msg_sz, se_clbk_hdl->rx_msg_sz);
+
+			se_clbk_hdl->rx_msg_sz = min(rx_msg_sz, se_clbk_hdl->rx_msg_sz);
+		}
+	} else {
+		dev_err(dev, "Failed to select a device for message: %.8x\n",
+			*((u32 *)header));
+		return;
+	}
+
+	memcpy(se_clbk_hdl->rx_msg, msg, se_clbk_hdl->rx_msg_sz);
+
+	/* Allow user to read */
+	complete(&se_clbk_hdl->done);
+}
+
+int se_val_rsp_hdr_n_status(struct se_if_priv *priv, struct se_api_msg *msg,
+			    u8 msg_id, u8 sz, bool is_base_api)
+{
+	struct se_msg_hdr *header = &msg->header;
+	u32 status;
+
+	if (header->tag != priv->if_defs->rsp_tag) {
+		dev_err(priv->dev, "MSG[0x%x] Hdr: Resp tag mismatch. (0x%x != 0x%x)",
+			msg_id, header->tag, priv->if_defs->rsp_tag);
+		return -EINVAL;
+	}
+
+	if (header->command != msg_id) {
+		dev_err(priv->dev, "MSG Header: Cmd id mismatch. (0x%x != 0x%x)",
+			header->command, msg_id);
+		return -EINVAL;
+	}
+
+	if ((sz % 4) || (header->size != (sz >> 2) &&
+			 !check_hdr_exception_for_sz(priv, header))) {
+		dev_err(priv->dev, "MSG[0x%x] Hdr: Cmd size mismatch. (0x%x != 0x%x)",
+			msg_id, header->size, (sz >> 2));
+		return -EINVAL;
+	}
+
+	if (is_base_api && header->ver != priv->if_defs->base_api_ver) {
+		dev_err(priv->dev,
+			"MSG[0x%x] Hdr: Base API Vers mismatch. (0x%x != 0x%x)",
+			msg_id, header->ver, priv->if_defs->base_api_ver);
+		return -EINVAL;
+	} else if (!is_base_api && header->ver != priv->if_defs->fw_api_ver) {
+		dev_err(priv->dev,
+			"MSG[0x%x] Hdr: FW API Vers mismatch. (0x%x != 0x%x)",
+			msg_id, header->ver, priv->if_defs->fw_api_ver);
+		return -EINVAL;
+	}
+
+	status = RES_STATUS(msg->data[0]);
+	if (status != priv->if_defs->success_tag) {
+		dev_err(priv->dev, "Command Id[%x], Response Failure = 0x%x",
+			header->command, status);
+		return -EPERM;
+	}
+
+	return 0;
+}
+
+int se_save_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem)
+{
+	struct ele_dev_info s_info = {0};
+	int ret;
+
+	ret = ele_get_info(priv, &s_info);
+	if (ret) {
+		dev_err(priv->dev, "Failed to get info from ELE.\n");
+		return ret;
+	}
+
+	/* Check for the imem-state before continue to save imem state. */
+	if (s_info.d_addn_info.imem_state == ELE_IMEM_STATE_BAD)
+		return -EIO;
+
+	/*
+	 * EXPORT command will save encrypted IMEM to given address,
+	 * so later in resume, IMEM can be restored from the given
+	 * address.
+	 *
+	 * Size must be at least 64 kB.
+	 */
+	ret = ele_service_swap(priv, imem->phyaddr, ELE_IMEM_SIZE, ELE_IMEM_EXPORT);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to export IMEM.");
+		imem->size = 0;
+	} else {
+		dev_dbg(priv->dev,
+			"Exported %d bytes of encrypted IMEM.",
+			ret);
+		imem->size = ret;
+	}
+
+	return ret > 0 ? 0 : ret;
+}
+
+int se_restore_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem)
+{
+	struct ele_dev_info s_info;
+	int ret;
+
+	/* get info from ELE */
+	ret = ele_get_info(priv, &s_info);
+	if (ret) {
+		dev_err(priv->dev, "Failed to get info from ELE.");
+		return ret;
+	}
+	imem->state = s_info.d_addn_info.imem_state;
+
+	/* Check for the imem-state and imem-size before continue to
+	 * restore imem state.
+	 */
+	if (s_info.d_addn_info.imem_state != ELE_IMEM_STATE_BAD || !imem->size)
+		return -EIO;
+
+	/*
+	 * IMPORT command will restore IMEM from the given
+	 * address, here size is the actual size returned by ELE
+	 * during the export operation
+	 */
+	ret = ele_service_swap(priv, imem->phyaddr, imem->size, ELE_IMEM_IMPORT);
+	if (ret) {
+		dev_err(priv->dev, "Failed to import IMEM");
+		return ret;
+	}
+
+	/*
+	 * After importing IMEM, check if IMEM state is equal to 0xCA
+	 * to ensure IMEM is fully loaded and
+	 * ELE functionality can be used.
+	 */
+	ret = ele_get_info(priv, &s_info);
+	if (ret) {
+		dev_err(priv->dev, "Failed to get info from ELE.");
+		return ret;
+	}
+	imem->state = s_info.d_addn_info.imem_state;
+
+	if (s_info.d_addn_info.imem_state == ELE_IMEM_STATE_OK)
+		dev_dbg(priv->dev, "Successfully restored IMEM.");
+	else
+		dev_err(priv->dev, "Failed to restore IMEM.");
+
+	return ret;
+}
diff --git a/drivers/firmware/imx/ele_common.h b/drivers/firmware/imx/ele_common.h
new file mode 100644
index 000000000000..96e987ef6f88
--- /dev/null
+++ b/drivers/firmware/imx/ele_common.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2025 NXP
+ */
+
+#ifndef __ELE_COMMON_H__
+#define __ELE_COMMON_H__
+
+#include "se_ctrl.h"
+
+#define ELE_SUCCESS_IND			0xD6
+
+#define IMX_ELE_FW_DIR                 "imx/ele/"
+
+u32 se_get_msg_chksum(u32 *msg, u32 msg_len);
+
+int ele_msg_rcv(struct se_if_priv *priv, struct se_clbk_handle *se_clbk_hdl);
+
+int ele_msg_send(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz);
+
+int ele_msg_send_rcv(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz,
+		     void *rx_msg, int exp_rx_msg_sz);
+
+void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg);
+
+int se_val_rsp_hdr_n_status(struct se_if_priv *priv, struct se_api_msg *msg,
+			    u8 msg_id, u8 sz, bool is_base_api);
+
+/* Fill a command message header with a given command ID and length in bytes. */
+static inline int se_fill_cmd_msg_hdr(struct se_if_priv *priv, struct se_msg_hdr *hdr,
+				      u8 cmd, u32 len, bool is_base_api)
+{
+	hdr->tag = priv->if_defs->cmd_tag;
+	hdr->ver = (is_base_api) ? priv->if_defs->base_api_ver : priv->if_defs->fw_api_ver;
+	hdr->command = cmd;
+	hdr->size = len >> 2;
+
+	return 0;
+}
+
+int se_save_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem);
+
+int se_restore_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem);
+
+#endif /*__ELE_COMMON_H__ */
diff --git a/drivers/firmware/imx/se_ctrl.c b/drivers/firmware/imx/se_ctrl.c
new file mode 100644
index 000000000000..1c91b4698465
--- /dev/null
+++ b/drivers/firmware/imx/se_ctrl.c
@@ -0,0 +1,408 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 NXP
+ */
+
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/firmware.h>
+#include <linux/firmware/imx/se_api.h>
+#include <linux/genalloc.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/miscdevice.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/sys_soc.h>
+
+#include "ele_base_msg.h"
+#include "ele_common.h"
+#include "se_ctrl.h"
+
+#define MAX_SOC_INFO_DATA_SZ		256
+#define MBOX_TX_NAME			"tx"
+#define MBOX_RX_NAME			"rx"
+
+#define SE_TYPE_STR_DBG			"dbg"
+#define SE_TYPE_STR_HSM			"hsm"
+
+#define SE_TYPE_ID_DBG			0x1
+#define SE_TYPE_ID_HSM			0x2
+
+struct se_fw_img_name {
+	const u8 *prim_fw_nm_in_rfs;
+	const u8 *seco_fw_nm_in_rfs;
+};
+
+struct se_fw_load_info {
+	const struct se_fw_img_name *se_fw_img_nm;
+	bool is_fw_tobe_loaded;
+	bool imem_mgmt;
+	struct se_imem_buf imem;
+};
+
+struct se_var_info {
+	u16 soc_rev;
+	struct se_fw_load_info load_fw;
+};
+
+/* contains fixed information */
+struct se_soc_info {
+	const u16 soc_id;
+	const bool soc_register;
+	const struct se_fw_img_name se_fw_img_nm;
+};
+
+struct se_if_node {
+	struct se_soc_info *se_info;
+	u8 *pool_name;
+	bool reserved_dma_ranges;
+	struct se_if_defines if_defs;
+};
+
+/* common for all the SoC. */
+static struct se_var_info var_se_info;
+
+static struct se_soc_info se_imx8ulp_info = {
+	.soc_id = SOC_ID_OF_IMX8ULP,
+	.soc_register = true,
+	.se_fw_img_nm = {
+		.prim_fw_nm_in_rfs = IMX_ELE_FW_DIR
+			"mx8ulpa2-ahab-container.img",
+		.seco_fw_nm_in_rfs = IMX_ELE_FW_DIR
+			"mx8ulpa2ext-ahab-container.img",
+	},
+};
+
+static struct se_if_node imx8ulp_se_ele_hsm = {
+	.se_info = &se_imx8ulp_info,
+	.pool_name = "sram",
+	.reserved_dma_ranges = true,
+	.if_defs = {
+		.se_if_type = SE_TYPE_ID_HSM,
+		.cmd_tag = 0x17,
+		.rsp_tag = 0xe1,
+		.success_tag = ELE_SUCCESS_IND,
+		.base_api_ver = MESSAGING_VERSION_6,
+		.fw_api_ver = MESSAGING_VERSION_7,
+	},
+};
+
+static struct se_soc_info se_imx93_info = {
+	.soc_id = SOC_ID_OF_IMX93,
+};
+
+static struct se_if_node imx93_se_ele_hsm = {
+	.se_info = &se_imx93_info,
+	.reserved_dma_ranges = true,
+	.if_defs = {
+		.se_if_type = SE_TYPE_ID_HSM,
+		.cmd_tag = 0x17,
+		.rsp_tag = 0xe1,
+		.success_tag = ELE_SUCCESS_IND,
+		.base_api_ver = MESSAGING_VERSION_6,
+		.fw_api_ver = MESSAGING_VERSION_7,
+	},
+};
+
+static const struct of_device_id se_match[] = {
+	{ .compatible = "fsl,imx8ulp-se-ele-hsm", .data = &imx8ulp_se_ele_hsm},
+	{ .compatible = "fsl,imx93-se-ele-hsm", .data = &imx93_se_ele_hsm},
+	{},
+};
+
+char *get_se_if_name(u8 se_if_id)
+{
+	switch (se_if_id) {
+	case SE_TYPE_ID_DBG: return SE_TYPE_STR_DBG;
+	case SE_TYPE_ID_HSM: return SE_TYPE_STR_HSM;
+	}
+
+	return NULL;
+}
+
+static struct se_fw_load_info *get_load_fw_instance(struct se_if_priv *priv)
+{
+	return &var_se_info.load_fw;
+}
+
+static int get_se_soc_info(struct se_if_priv *priv, const struct se_soc_info *se_info)
+{
+	struct se_fw_load_info *load_fw = get_load_fw_instance(priv);
+	struct soc_device_attribute *attr;
+	u8 data[MAX_SOC_INFO_DATA_SZ];
+	struct ele_dev_info *s_info;
+	struct soc_device *sdev;
+	int err = 0;
+
+	/*
+	 * This function should be called once.
+	 * Check if the se_soc_rev is zero to continue.
+	 */
+	if (var_se_info.soc_rev)
+		return err;
+
+	err = ele_fetch_soc_info(priv, &data);
+	if (err < 0)
+		return dev_err_probe(priv->dev, err, "Failed to fetch SoC Info.");
+	s_info = (void *)data;
+	var_se_info.soc_rev = s_info->d_info.soc_rev;
+	load_fw->imem.state = s_info->d_addn_info.imem_state;
+
+	if (!se_info->soc_register)
+		return 0;
+
+	attr = devm_kzalloc(priv->dev, sizeof(*attr), GFP_KERNEL);
+	if (!attr)
+		return -ENOMEM;
+
+	if (FIELD_GET(DEV_GETINFO_MIN_VER_MASK, var_se_info.soc_rev))
+		attr->revision = devm_kasprintf(priv->dev, GFP_KERNEL, "%x.%x",
+						FIELD_GET(DEV_GETINFO_MIN_VER_MASK,
+							  var_se_info.soc_rev),
+						FIELD_GET(DEV_GETINFO_MAJ_VER_MASK,
+							  var_se_info.soc_rev));
+	else
+		attr->revision = devm_kasprintf(priv->dev, GFP_KERNEL, "%x",
+						FIELD_GET(DEV_GETINFO_MAJ_VER_MASK,
+							  var_se_info.soc_rev));
+
+	switch (se_info->soc_id) {
+	case SOC_ID_OF_IMX8ULP:
+		attr->soc_id = "i.MX8ULP";
+		break;
+	case SOC_ID_OF_IMX93:
+		attr->soc_id = "i.MX93";
+		break;
+	}
+
+	err = of_property_read_string(of_root, "model", &attr->machine);
+	if (err)
+		return -EINVAL;
+
+	attr->family = "Freescale i.MX";
+
+	attr->serial_number = devm_kasprintf(priv->dev,
+					     GFP_KERNEL, "%016llX",
+					     GET_SERIAL_NUM_FROM_UID(s_info->d_info.uid,
+								     MAX_UID_SIZE >> 2));
+
+	sdev = soc_device_register(attr);
+	if (IS_ERR(sdev))
+		return PTR_ERR(sdev);
+
+	return 0;
+}
+
+/* interface for managed res to free a mailbox channel */
+static void if_mbox_free_channel(void *mbox_chan)
+{
+	mbox_free_channel(mbox_chan);
+}
+
+static int se_if_request_channel(struct device *dev, struct mbox_chan **chan,
+				 struct mbox_client *cl, const char *name)
+{
+	struct mbox_chan *t_chan;
+	int ret = 0;
+
+	t_chan = mbox_request_channel_byname(cl, name);
+	if (IS_ERR(t_chan))
+		return dev_err_probe(dev, PTR_ERR(t_chan),
+				     "Failed to request %s channel.", name);
+
+	ret = devm_add_action_or_reset(dev, if_mbox_free_channel, t_chan);
+	if (ret)
+		return dev_err_probe(dev, -EPERM,
+				     "Failed to add-action for removal of mbox: %s\n",
+				     name);
+	*chan = t_chan;
+
+	return ret;
+}
+
+static void se_if_probe_cleanup(void *plat_dev)
+{
+	struct platform_device *pdev = plat_dev;
+	struct se_fw_load_info *load_fw;
+	struct device *dev = &pdev->dev;
+	struct se_if_priv *priv;
+
+	priv = dev_get_drvdata(dev);
+	load_fw = get_load_fw_instance(priv);
+
+	/*
+	 * In se_if_request_channel(), passed the clean-up functional
+	 * pointer reference as action to devm_add_action_or_reset().
+	 * No need to free the mbox channels here.
+	 */
+
+	/*
+	 * free the buffer in se remove, previously allocated
+	 * in se probe to store encrypted IMEM
+	 */
+	if (load_fw && load_fw->imem.buf) {
+		dmam_free_coherent(dev, ELE_IMEM_SIZE, load_fw->imem.buf,
+				   load_fw->imem.phyaddr);
+		load_fw->imem.buf = NULL;
+	}
+
+	/*
+	 * No need to check, if reserved memory is allocated
+	 * before calling for its release. Or clearing the
+	 * un-set bit.
+	 */
+	of_reserved_mem_device_release(dev);
+}
+
+static int se_if_probe(struct platform_device *pdev)
+{
+	const struct se_soc_info *se_info;
+	const struct se_if_node *if_node;
+	struct se_fw_load_info *load_fw;
+	struct device *dev = &pdev->dev;
+	struct se_if_priv *priv;
+	int ret;
+
+	if_node = device_get_match_data(dev);
+	if (!if_node)
+		return -EINVAL;
+
+	se_info = if_node->se_info;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = dev;
+	priv->if_defs = &if_node->if_defs;
+	dev_set_drvdata(dev, priv);
+
+	ret = devm_add_action_or_reset(dev, se_if_probe_cleanup, pdev);
+	if (ret)
+		return ret;
+
+	/* Mailbox client configuration */
+	priv->se_mb_cl.dev		= dev;
+	priv->se_mb_cl.tx_block		= false;
+	priv->se_mb_cl.knows_txdone	= true;
+	priv->se_mb_cl.rx_callback	= se_if_rx_callback;
+
+	ret = se_if_request_channel(dev, &priv->tx_chan, &priv->se_mb_cl, MBOX_TX_NAME);
+	if (ret)
+		return ret;
+
+	ret = se_if_request_channel(dev, &priv->rx_chan, &priv->se_mb_cl, MBOX_RX_NAME);
+	if (ret)
+		return ret;
+
+	mutex_init(&priv->se_if_cmd_lock);
+
+	init_completion(&priv->waiting_rsp_clbk_hdl.done);
+	init_completion(&priv->cmd_receiver_clbk_hdl.done);
+
+	if (if_node->pool_name) {
+		priv->mem_pool = of_gen_pool_get(dev->of_node, if_node->pool_name, 0);
+		if (!priv->mem_pool)
+			return dev_err_probe(dev, -ENOMEM,
+					     "Unable to get sram pool = %s.",
+					     if_node->pool_name);
+	}
+
+	if (if_node->reserved_dma_ranges) {
+		ret = of_reserved_mem_device_init(dev);
+		if (ret)
+			return dev_err_probe(dev, ret,
+					    "Failed to init reserved memory region.");
+	}
+
+	if (if_node->if_defs.se_if_type == SE_TYPE_ID_HSM) {
+		ret = get_se_soc_info(priv, se_info);
+		if (ret)
+			return dev_err_probe(dev, ret, "Failed to fetch SoC Info.");
+	}
+
+	/* By default, there is no pending FW to be loaded.*/
+	if (se_info->se_fw_img_nm.seco_fw_nm_in_rfs) {
+		load_fw = get_load_fw_instance(priv);
+		load_fw->se_fw_img_nm = &se_info->se_fw_img_nm;
+		load_fw->is_fw_tobe_loaded = true;
+
+		if (load_fw->se_fw_img_nm->prim_fw_nm_in_rfs) {
+			/* allocate buffer where SE store encrypted IMEM */
+			load_fw->imem.buf = dmam_alloc_coherent(priv->dev, ELE_IMEM_SIZE,
+								&load_fw->imem.phyaddr,
+								GFP_KERNEL);
+			if (!load_fw->imem.buf)
+				return dev_err_probe(dev, -ENOMEM,
+						     "dmam-alloc-failed: To store encr-IMEM.");
+			load_fw->imem_mgmt = true;
+		}
+	}
+	dev_info(dev, "i.MX secure-enclave: %s0 interface to firmware, configured.",
+		 get_se_if_name(priv->if_defs->se_if_type));
+
+	return ret;
+}
+
+static int se_suspend(struct device *dev)
+{
+	struct se_if_priv *priv = dev_get_drvdata(dev);
+	struct se_fw_load_info *load_fw;
+	int ret = 0;
+
+	load_fw = get_load_fw_instance(priv);
+
+	if (load_fw->imem_mgmt) {
+		ret = se_save_imem_state(priv, &load_fw->imem);
+		if (ret)
+			dev_err(dev, "Failure saving IMEM state[0x%x]", ret);
+	}
+
+	return 0;
+}
+
+static int se_resume(struct device *dev)
+{
+	struct se_if_priv *priv = dev_get_drvdata(dev);
+	struct se_fw_load_info *load_fw;
+	int ret = 0;
+
+	load_fw = get_load_fw_instance(priv);
+
+	if (load_fw->imem_mgmt) {
+		se_restore_imem_state(priv, &load_fw->imem);
+		if (ret)
+			dev_err(dev, "Failure restoring IMEM state[0x%x]", ret);
+	}
+
+	return 0;
+}
+
+static const struct dev_pm_ops se_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(se_suspend, se_resume)
+};
+
+static struct platform_driver se_driver = {
+	.driver = {
+		.name = "fsl-se",
+		.of_match_table = se_match,
+		.pm = &se_pm,
+	},
+	.probe = se_if_probe,
+};
+MODULE_DEVICE_TABLE(of, se_match);
+
+module_platform_driver(se_driver);
+MODULE_AUTHOR("Pankaj Gupta <pankaj.gupta at nxp.com>");
+MODULE_DESCRIPTION("iMX Secure Enclave Driver.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/imx/se_ctrl.h b/drivers/firmware/imx/se_ctrl.h
new file mode 100644
index 000000000000..b15c4022a46c
--- /dev/null
+++ b/drivers/firmware/imx/se_ctrl.h
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2025 NXP
+ */
+
+#ifndef SE_MU_H
+#define SE_MU_H
+
+#include <linux/miscdevice.h>
+#include <linux/semaphore.h>
+#include <linux/mailbox_client.h>
+
+#define MAX_FW_LOAD_RETRIES		50
+#define SE_MSG_WORD_SZ			0x4
+
+#define RES_STATUS(x)			FIELD_GET(0x000000ff, x)
+#define MAX_NVM_MSG_LEN			(256)
+#define MESSAGING_VERSION_6		0x6
+#define MESSAGING_VERSION_7		0x7
+
+struct se_clbk_handle {
+	struct completion done;
+	bool signal_rcvd;
+	u32 rx_msg_sz;
+	/*
+	 * Assignment of the rx_msg buffer to held till the
+	 * received content as part callback function, is copied.
+	 */
+	struct se_api_msg *rx_msg;
+};
+
+struct se_imem_buf {
+	u8 *buf;
+	phys_addr_t phyaddr;
+	u32 size;
+	u32 state;
+};
+
+/* Header of the messages exchange with the EdgeLock Enclave */
+struct se_msg_hdr {
+	u8 ver;
+	u8 size;
+	u8 command;
+	u8 tag;
+}  __packed;
+
+#define SE_MU_HDR_SZ	4
+
+struct se_api_msg {
+	struct se_msg_hdr header;
+	u32 data[];
+};
+
+struct se_if_defines {
+	const u8 se_if_type;
+	u8 cmd_tag;
+	u8 rsp_tag;
+	u8 success_tag;
+	u8 base_api_ver;
+	u8 fw_api_ver;
+};
+
+struct se_if_priv {
+	struct device *dev;
+
+	struct se_clbk_handle cmd_receiver_clbk_hdl;
+	/*
+	 * Update to the waiting_rsp_dev, to be protected
+	 * under se_if_cmd_lock.
+	 */
+	struct se_clbk_handle waiting_rsp_clbk_hdl;
+	/*
+	 * prevent new command to be sent on the se interface while previous
+	 * command is still processing. (response is awaited)
+	 */
+	struct mutex se_if_cmd_lock;
+
+	struct mbox_client se_mb_cl;
+	struct mbox_chan *tx_chan, *rx_chan;
+
+	struct gen_pool *mem_pool;
+	const struct se_if_defines *if_defs;
+};
+
+char *get_se_if_name(u8 se_if_id);
+#endif
diff --git a/include/linux/firmware/imx/se_api.h b/include/linux/firmware/imx/se_api.h
new file mode 100644
index 000000000000..b1c4c9115d7b
--- /dev/null
+++ b/include/linux/firmware/imx/se_api.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2025 NXP
+ */
+
+#ifndef __SE_API_H__
+#define __SE_API_H__
+
+#include <linux/types.h>
+
+#define SOC_ID_OF_IMX8ULP		0x084d
+#define SOC_ID_OF_IMX93			0x9300
+
+#endif /* __SE_API_H__ */

-- 
2.43.0



From pankaj.gupta at nxp.com  Fri Dec 12 01:14:15 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Fri, 12 Dec 2025 14:44:15 +0530
Subject: [PATCH v21 4/7] firmware: imx: device context dedicated to priv
In-Reply-To: <20251212-imx-se-if-v21-0-ee7d6052d848@nxp.com>
References: <20251212-imx-se-if-v21-0-ee7d6052d848@nxp.com>
Message-ID: <20251212-imx-se-if-v21-4-ee7d6052d848@nxp.com>

Add priv_dev_ctx to prepare enabling misc-device context based send-receive
path, to communicate with FW.

No functionality change.

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/firmware/imx/ele_base_msg.c | 14 +++++-----
 drivers/firmware/imx/ele_common.c   | 51 +++++++++++++++++++++----------------
 drivers/firmware/imx/ele_common.h   |  8 +++---
 drivers/firmware/imx/se_ctrl.c      | 29 +++++++++++++++++++++
 drivers/firmware/imx/se_ctrl.h      |  9 +++++++
 5 files changed, 78 insertions(+), 33 deletions(-)

diff --git a/drivers/firmware/imx/ele_base_msg.c b/drivers/firmware/imx/ele_base_msg.c
index b44041bc41e0..4d1f0d43963e 100644
--- a/drivers/firmware/imx/ele_base_msg.c
+++ b/drivers/firmware/imx/ele_base_msg.c
@@ -62,8 +62,8 @@ int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info)
 	tx_msg->data[0] = upper_32_bits(get_info_addr);
 	tx_msg->data[1] = lower_32_bits(get_info_addr);
 	tx_msg->data[2] = sizeof(*s_info);
-	ret = ele_msg_send_rcv(priv, tx_msg, ELE_GET_INFO_REQ_MSG_SZ, rx_msg,
-			       ELE_GET_INFO_RSP_MSG_SZ);
+	ret = ele_msg_send_rcv(priv->priv_dev_ctx, tx_msg, ELE_GET_INFO_REQ_MSG_SZ,
+			       rx_msg, ELE_GET_INFO_RSP_MSG_SZ);
 	if (ret < 0)
 		goto exit;
 
@@ -116,8 +116,8 @@ int ele_ping(struct se_if_priv *priv)
 		goto exit;
 	}
 
-	ret = ele_msg_send_rcv(priv, tx_msg, ELE_PING_REQ_SZ, rx_msg,
-			       ELE_PING_RSP_SZ);
+	ret = ele_msg_send_rcv(priv->priv_dev_ctx, tx_msg, ELE_PING_REQ_SZ,
+			       rx_msg, ELE_PING_RSP_SZ);
 	if (ret < 0)
 		goto exit;
 
@@ -167,7 +167,7 @@ int ele_service_swap(struct se_if_priv *priv,
 		goto exit;
 	}
 
-	ret = ele_msg_send_rcv(priv, tx_msg, ELE_SERVICE_SWAP_REQ_MSG_SZ,
+	ret = ele_msg_send_rcv(priv->priv_dev_ctx, tx_msg, ELE_SERVICE_SWAP_REQ_MSG_SZ,
 			       rx_msg, ELE_SERVICE_SWAP_RSP_MSG_SZ);
 	if (ret < 0)
 		goto exit;
@@ -216,7 +216,7 @@ int ele_fw_authenticate(struct se_if_priv *priv, phys_addr_t contnr_addr,
 	tx_msg->data[1] = upper_32_bits(contnr_addr);
 	tx_msg->data[2] = img_addr;
 
-	ret = ele_msg_send_rcv(priv, tx_msg, ELE_FW_AUTH_REQ_SZ, rx_msg,
+	ret = ele_msg_send_rcv(priv->priv_dev_ctx, tx_msg, ELE_FW_AUTH_REQ_SZ, rx_msg,
 			       ELE_FW_AUTH_RSP_MSG_SZ);
 	if (ret < 0)
 		goto exit;
@@ -260,7 +260,7 @@ int ele_debug_dump(struct se_if_priv *priv)
 	do {
 		memset(rx_msg, 0x0, ELE_DEBUG_DUMP_RSP_SZ);
 
-		ret = ele_msg_send_rcv(priv, tx_msg, ELE_DEBUG_DUMP_REQ_SZ,
+		ret = ele_msg_send_rcv(priv->priv_dev_ctx, tx_msg, ELE_DEBUG_DUMP_REQ_SZ,
 				       rx_msg, ELE_DEBUG_DUMP_RSP_SZ);
 		if (ret < 0)
 			goto exit;
diff --git a/drivers/firmware/imx/ele_common.c b/drivers/firmware/imx/ele_common.c
index a7150ff8e3b9..fcd0f561d72d 100644
--- a/drivers/firmware/imx/ele_common.c
+++ b/drivers/firmware/imx/ele_common.c
@@ -42,7 +42,7 @@ u32 se_get_msg_chksum(u32 *msg, u32 msg_len)
 	return chksum;
 }
 
-int ele_msg_rcv(struct se_if_priv *priv, struct se_clbk_handle *se_clbk_hdl)
+int ele_msg_rcv(struct se_if_device_ctx *dev_ctx, struct se_clbk_handle *se_clbk_hdl)
 {
 	unsigned long timeout;
 	int ret;
@@ -52,8 +52,8 @@ int ele_msg_rcv(struct se_if_priv *priv, struct se_clbk_handle *se_clbk_hdl)
 
 		ret = wait_for_completion_interruptible_timeout(&se_clbk_hdl->done, timeout);
 		if (ret == -ERESTARTSYS) {
-			if (priv->waiting_rsp_clbk_hdl.rx_msg) {
-				priv->waiting_rsp_clbk_hdl.signal_rcvd = true;
+			if (dev_ctx->priv->waiting_rsp_clbk_hdl.dev_ctx) {
+				dev_ctx->priv->waiting_rsp_clbk_hdl.signal_rcvd = true;
 				continue;
 			}
 			ret = -EINTR;
@@ -66,7 +66,7 @@ int ele_msg_rcv(struct se_if_priv *priv, struct se_clbk_handle *se_clbk_hdl)
 	return ret;
 }
 
-int ele_msg_send(struct se_if_priv *priv,
+int ele_msg_send(struct se_if_device_ctx *dev_ctx,
 		 void *tx_msg,
 		 int tx_msg_sz)
 {
@@ -78,15 +78,16 @@ int ele_msg_send(struct se_if_priv *priv,
 	 * carried in the message.
 	 */
 	if (header->size << 2 != tx_msg_sz) {
-		dev_err(priv->dev,
-			"User buf hdr: 0x%x, sz mismatced with input-sz (%d != %d).",
-			*(u32 *)header, header->size << 2, tx_msg_sz);
+		dev_err(dev_ctx->priv->dev,
+			"%s: User buf hdr: 0x%x, sz mismatced with input-sz (%d != %d).",
+			dev_ctx->devname, *(u32 *)header, header->size << 2, tx_msg_sz);
 		return -EINVAL;
 	}
 
-	err = mbox_send_message(priv->tx_chan, tx_msg);
+	err = mbox_send_message(dev_ctx->priv->tx_chan, tx_msg);
 	if (err < 0) {
-		dev_err(priv->dev, "Error: mbox_send_message failure.\n");
+		dev_err(dev_ctx->priv->dev,
+			"%s: Error: mbox_send_message failure.", dev_ctx->devname);
 		return err;
 	}
 
@@ -94,27 +95,31 @@ int ele_msg_send(struct se_if_priv *priv,
 }
 
 /* API used for send/receive blocking call. */
-int ele_msg_send_rcv(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz,
-		     void *rx_msg, int exp_rx_msg_sz)
+int ele_msg_send_rcv(struct se_if_device_ctx *dev_ctx, void *tx_msg,
+		     int tx_msg_sz, void *rx_msg, int exp_rx_msg_sz)
 {
+	struct se_if_priv *priv = dev_ctx->priv;
 	int err;
 
 	guard(mutex)(&priv->se_if_cmd_lock);
 
+	priv->waiting_rsp_clbk_hdl.dev_ctx = dev_ctx;
 	priv->waiting_rsp_clbk_hdl.rx_msg_sz = exp_rx_msg_sz;
 	priv->waiting_rsp_clbk_hdl.rx_msg = rx_msg;
 
-	err = ele_msg_send(priv, tx_msg, tx_msg_sz);
+	err = ele_msg_send(dev_ctx, tx_msg, tx_msg_sz);
 	if (err < 0)
 		return err;
 
-	err = ele_msg_rcv(priv, &priv->waiting_rsp_clbk_hdl);
+	err = ele_msg_rcv(dev_ctx, &priv->waiting_rsp_clbk_hdl);
 
 	if (priv->waiting_rsp_clbk_hdl.signal_rcvd) {
 		err = -EINTR;
 		priv->waiting_rsp_clbk_hdl.signal_rcvd = false;
-		dev_err(priv->dev, "Err[0x%x]:Interrupted by signal.\n", err);
+		dev_err(priv->dev, "%s: Err[0x%x]:Interrupted by signal.",
+			dev_ctx->devname, err);
 	}
+	priv->waiting_rsp_clbk_hdl.dev_ctx = NULL;
 
 	return err;
 }
@@ -159,8 +164,8 @@ void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg)
 	/* Incoming command: wake up the receiver if any. */
 	if (header->tag == priv->if_defs->cmd_tag) {
 		se_clbk_hdl = &priv->cmd_receiver_clbk_hdl;
-		dev_dbg(dev, "Selecting cmd receiver for mesg header:0x%x.",
-			*(u32 *)header);
+		dev_dbg(dev, "Selecting cmd receiver:%s for mesg header:0x%x.",
+			se_clbk_hdl->dev_ctx->devname,  *(u32 *)header);
 
 		/*
 		 * Pre-allocated buffer of MAX_NVM_MSG_LEN
@@ -169,8 +174,9 @@ void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg)
 		 */
 		if (rx_msg_sz > MAX_NVM_MSG_LEN) {
 			dev_err(dev,
-				"CMD-RCVER NVM: hdr(0x%x) with different sz(%d != %d).\n",
-				*(u32 *)header, rx_msg_sz, se_clbk_hdl->rx_msg_sz);
+				"%s: CMD-RCVER NVM: hdr(0x%x) with different sz(%d != %d).\n",
+				se_clbk_hdl->dev_ctx->devname, *(u32 *)header,
+				rx_msg_sz, se_clbk_hdl->rx_msg_sz);
 
 			se_clbk_hdl->rx_msg_sz = MAX_NVM_MSG_LEN;
 		}
@@ -178,14 +184,15 @@ void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg)
 
 	} else if (header->tag == priv->if_defs->rsp_tag) {
 		se_clbk_hdl = &priv->waiting_rsp_clbk_hdl;
-		dev_dbg(dev, "Selecting resp waiter for mesg header:0x%x.",
-			*(u32 *)header);
+		dev_dbg(dev, "Selecting resp waiter:%s for mesg header:0x%x.",
+			se_clbk_hdl->dev_ctx->devname, *(u32 *)header);
 
 		if (rx_msg_sz != se_clbk_hdl->rx_msg_sz &&
 		    check_hdr_exception_for_sz(priv, header)) {
 			dev_err(dev,
-				"Rsp to CMD: hdr(0x%x) with different sz(%d != %d).\n",
-				*(u32 *)header, rx_msg_sz, se_clbk_hdl->rx_msg_sz);
+				"%s: Rsp to CMD: hdr(0x%x) with different sz(%d != %d).\n",
+				se_clbk_hdl->dev_ctx->devname, *(u32 *)header,
+				rx_msg_sz, se_clbk_hdl->rx_msg_sz);
 
 			se_clbk_hdl->rx_msg_sz = min(rx_msg_sz, se_clbk_hdl->rx_msg_sz);
 		}
diff --git a/drivers/firmware/imx/ele_common.h b/drivers/firmware/imx/ele_common.h
index 96e987ef6f88..5bac14439d7d 100644
--- a/drivers/firmware/imx/ele_common.h
+++ b/drivers/firmware/imx/ele_common.h
@@ -14,12 +14,12 @@
 
 u32 se_get_msg_chksum(u32 *msg, u32 msg_len);
 
-int ele_msg_rcv(struct se_if_priv *priv, struct se_clbk_handle *se_clbk_hdl);
+int ele_msg_rcv(struct se_if_device_ctx *dev_ctx, struct se_clbk_handle *se_clbk_hdl);
 
-int ele_msg_send(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz);
+int ele_msg_send(struct se_if_device_ctx *dev_ctx, void *tx_msg, int tx_msg_sz);
 
-int ele_msg_send_rcv(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz,
-		     void *rx_msg, int exp_rx_msg_sz);
+int ele_msg_send_rcv(struct se_if_device_ctx *dev_ctx, void *tx_msg,
+		     int tx_msg_sz, void *rx_msg, int exp_rx_msg_sz);
 
 void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg);
 
diff --git a/drivers/firmware/imx/se_ctrl.c b/drivers/firmware/imx/se_ctrl.c
index 1c91b4698465..63562a4d9a3e 100644
--- a/drivers/firmware/imx/se_ctrl.c
+++ b/drivers/firmware/imx/se_ctrl.c
@@ -203,6 +203,29 @@ static int get_se_soc_info(struct se_if_priv *priv, const struct se_soc_info *se
 	return 0;
 }
 
+static int init_misc_device_context(struct se_if_priv *priv, int ch_id,
+				    struct se_if_device_ctx **new_dev_ctx)
+{
+	struct se_if_device_ctx *dev_ctx;
+	int ret = 0;
+
+	dev_ctx = devm_kzalloc(priv->dev, sizeof(*dev_ctx), GFP_KERNEL);
+
+	if (!dev_ctx)
+		return -ENOMEM;
+
+	dev_ctx->devname = devm_kasprintf(priv->dev, GFP_KERNEL, "%s0_ch%d",
+					  get_se_if_name(priv->if_defs->se_if_type),
+					  ch_id);
+	if (!dev_ctx->devname)
+		return -ENOMEM;
+
+	dev_ctx->priv = priv;
+	*new_dev_ctx = dev_ctx;
+
+	return ret;
+}
+
 /* interface for managed res to free a mailbox channel */
 static void if_mbox_free_channel(void *mbox_chan)
 {
@@ -325,6 +348,12 @@ static int se_if_probe(struct platform_device *pdev)
 					    "Failed to init reserved memory region.");
 	}
 
+	ret = init_misc_device_context(priv, 0, &priv->priv_dev_ctx);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed[0x%x] to create device contexts.",
+				     ret);
+
 	if (if_node->if_defs.se_if_type == SE_TYPE_ID_HSM) {
 		ret = get_se_soc_info(priv, se_info);
 		if (ret)
diff --git a/drivers/firmware/imx/se_ctrl.h b/drivers/firmware/imx/se_ctrl.h
index b15c4022a46c..b5e7705e2f26 100644
--- a/drivers/firmware/imx/se_ctrl.h
+++ b/drivers/firmware/imx/se_ctrl.h
@@ -19,6 +19,7 @@
 #define MESSAGING_VERSION_7		0x7
 
 struct se_clbk_handle {
+	struct se_if_device_ctx *dev_ctx;
 	struct completion done;
 	bool signal_rcvd;
 	u32 rx_msg_sz;
@@ -36,6 +37,12 @@ struct se_imem_buf {
 	u32 state;
 };
 
+/* Private struct for each char device instance. */
+struct se_if_device_ctx {
+	struct se_if_priv *priv;
+	const char *devname;
+};
+
 /* Header of the messages exchange with the EdgeLock Enclave */
 struct se_msg_hdr {
 	u8 ver;
@@ -80,6 +87,8 @@ struct se_if_priv {
 
 	struct gen_pool *mem_pool;
 	const struct se_if_defines *if_defs;
+
+	struct se_if_device_ctx *priv_dev_ctx;
 };
 
 char *get_se_if_name(u8 se_if_id);

-- 
2.43.0



From pankaj.gupta at nxp.com  Fri Dec 12 01:14:16 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Fri, 12 Dec 2025 14:44:16 +0530
Subject: [PATCH v21 5/7] firmware: drivers: imx: adds miscdev
In-Reply-To: <20251212-imx-se-if-v21-0-ee7d6052d848@nxp.com>
References: <20251212-imx-se-if-v21-0-ee7d6052d848@nxp.com>
Message-ID: <20251212-imx-se-if-v21-5-ee7d6052d848@nxp.com>

Adds the driver for communication interface to secure-enclave, that
enables exchanging messages with NXP secure enclave HW IP(s)
like EdgeLock Enclave, from:
- User-Space Applications via character driver.

ABI documentation for the NXP secure-enclave driver.

User-space library using this driver:
- i.MX Secure Enclave library:
  -- URL: https://github.com/nxp-imx/imx-secure-enclave.git,
- i.MX Secure Middle-Ware:
  -- URL: https://github.com/nxp-imx/imx-smw.git

Following checks are performed on the incoming msg-header,
to block exchanging invalid arbitrary commands:
- maximum allowed words,
- check if command-tag & response-tag are valid
- version,
- command id validation check, to allow limited base-line API(s)
  and restrict following:
  - exchanging power management commands.
  - reset requests.
  - BBSM configuration requests.
  - re-initializing the FW.
  - RNG init
  - CAAM resource release management
  - SE's internal memory management.
from user-space.

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
changes from v20 to v21
- removed "__free(kfree)" & added kfree();
---
 Documentation/ABI/testing/se-cdev   |  43 +++
 drivers/firmware/imx/ele_base_msg.c |  28 ++
 drivers/firmware/imx/ele_base_msg.h |  20 +
 drivers/firmware/imx/ele_common.c   |  37 +-
 drivers/firmware/imx/ele_common.h   |   6 +
 drivers/firmware/imx/se_ctrl.c      | 744 +++++++++++++++++++++++++++++++++++-
 drivers/firmware/imx/se_ctrl.h      |  33 ++
 include/uapi/linux/se_ioctl.h       |  97 +++++
 8 files changed, 996 insertions(+), 12 deletions(-)

diff --git a/Documentation/ABI/testing/se-cdev b/Documentation/ABI/testing/se-cdev
new file mode 100644
index 000000000000..dad39ffd245a
--- /dev/null
+++ b/Documentation/ABI/testing/se-cdev
@@ -0,0 +1,43 @@
+What:		/dev/<se>_mu[0-9]+_ch[0-9]+
+Date:		Mar 2025
+KernelVersion:	6.8
+Contact:	linux-imx at nxp.com, pankaj.gupta at nxp.com
+Description:
+		NXP offers multiple hardware IP(s) for secure enclaves like EdgeLock-
+		Enclave(ELE), SECO. The character device file descriptors
+		/dev/<se>_mu*_ch* are the interface between userspace NXP's secure-
+		enclave shared library and the kernel driver.
+
+		The ioctl(2)-based ABI is defined and documented in
+		[include]<linux/firmware/imx/ele_mu_ioctl.h>.
+		ioctl(s) are used primarily for:
+			- shared memory management
+			- allocation of I/O buffers
+			- getting mu info
+			- setting a dev-ctx as receiver to receive all the commands from FW
+			- getting SoC info
+			- send command and receive command response
+
+		The following file operations are supported:
+
+		open(2)
+		  Currently the only useful flags are O_RDWR.
+
+		read(2)
+		  Every read() from the opened character device context is waiting on
+		  wait_event_interruptible, that gets set by the registered mailbox callback
+		  function, indicating a message received from the firmware on message-
+		  unit.
+
+		write(2)
+		  Every write() to the opened character device context needs to acquire
+		  mailbox_lock before sending message on to the message unit.
+
+		close(2)
+		  Stops and frees up the I/O contexts that were associated
+		  with the file descriptor.
+
+Users:		https://github.com/nxp-imx/imx-secure-enclave.git,
+		https://github.com/nxp-imx/imx-smw.git
+		crypto/skcipher,
+		drivers/nvmem/imx-ocotp-ele.c
diff --git a/drivers/firmware/imx/ele_base_msg.c b/drivers/firmware/imx/ele_base_msg.c
index 4d1f0d43963e..185ba890765c 100644
--- a/drivers/firmware/imx/ele_base_msg.c
+++ b/drivers/firmware/imx/ele_base_msg.c
@@ -14,6 +14,34 @@
 
 #define FW_DBG_DUMP_FIXED_STR		"ELE"
 
+int ele_uapi_allowed_base_cmd(struct se_if_priv *priv,
+			      struct se_msg_hdr *header)
+{
+	switch (header->command) {
+	case ELE_PING_REQ: return 0;
+	case ELE_DEBUG_DUMP_REQ: return 0;
+	case ELE_OEM_AUTH_CONTAINER_REQ: return 0;
+	case ELE_OEM_VERIFY_IMAGE_REQ: return 0;
+	case ELE_OEM_REL_CONTAINER_REQ: return 0;
+	case ELE_FW_LIFE_CYCLE_REQ: return 0;
+	case ELE_READ_FUSE_REQ: return 0;
+	case ELE_GET_FW_VERS_REQ: return 0;
+	case ELE_RETURN_LIFE_CYCLE_REQ: return 0;
+	case ELE_GET_EVENT_REQ: return 0;
+	case ELE_COMMIT_REQ: return 0;
+	case ELE_GEN_KEY_BLOB_REQ: return 0;
+	case ELE_GET_FW_STATUS_REQ: return 0;
+	case ELE_XIP_DECRYPT_REQ: return 0;
+	case ELE_WRITE_FUSE: return 0;
+	case ELE_GET_INFO_REQ: return 0;
+	case ELE_DEV_ATTEST_REQ: return 0;
+	case ELE_WRITE_SHADOW_FUSE_REQ: return 0;
+	case ELE_READ_SHADOW_FUSE_REQ: return 0;
+	default:
+		return -EACCES;
+	}
+}
+
 int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info)
 {
 	struct se_api_msg *tx_msg = NULL;
diff --git a/drivers/firmware/imx/ele_base_msg.h b/drivers/firmware/imx/ele_base_msg.h
index 8e5b015e99a2..f8fabac331fd 100644
--- a/drivers/firmware/imx/ele_base_msg.h
+++ b/drivers/firmware/imx/ele_base_msg.h
@@ -15,6 +15,24 @@
 
 #define ELE_NONE_VAL			0x0
 
+
+#define ELE_OEM_AUTH_CONTAINER_REQ	0x87
+#define ELE_OEM_VERIFY_IMAGE_REQ	0x88
+#define ELE_OEM_REL_CONTAINER_REQ	0x89
+#define ELE_FW_LIFE_CYCLE_REQ		0x95
+#define ELE_READ_FUSE_REQ		0x97
+#define ELE_GET_FW_VERS_REQ		0x9d
+#define ELE_RETURN_LIFE_CYCLE_REQ	0xa0
+#define ELE_GET_EVENT_REQ		0xa2
+#define ELE_COMMIT_REQ			0xa8
+#define ELE_GEN_KEY_BLOB_REQ		0xaf
+#define ELE_GET_FW_STATUS_REQ		0xc5
+#define ELE_XIP_DECRYPT_REQ		0xc6
+#define ELE_WRITE_FUSE                  0xd6
+#define ELE_DEV_ATTEST_REQ              0xdb
+#define ELE_WRITE_SHADOW_FUSE_REQ       0xf2
+#define ELE_READ_SHADOW_FUSE_REQ        0xf3
+
 #define ELE_GET_INFO_REQ		0xda
 #define ELE_GET_INFO_REQ_MSG_SZ		0x10
 #define ELE_GET_INFO_RSP_MSG_SZ		0x08
@@ -92,4 +110,6 @@ int ele_service_swap(struct se_if_priv *priv, phys_addr_t addr,
 int ele_fw_authenticate(struct se_if_priv *priv, phys_addr_t contnr_addr,
 			phys_addr_t img_addr);
 int ele_debug_dump(struct se_if_priv *priv);
+int ele_uapi_allowed_base_cmd(struct se_if_priv *priv,
+			      struct se_msg_hdr *header);
 #endif
diff --git a/drivers/firmware/imx/ele_common.c b/drivers/firmware/imx/ele_common.c
index fcd0f561d72d..78440f62bf92 100644
--- a/drivers/firmware/imx/ele_common.c
+++ b/drivers/firmware/imx/ele_common.c
@@ -6,6 +6,23 @@
 #include "ele_base_msg.h"
 #include "ele_common.h"
 
+int se_chk_tx_msg_hdr(struct se_if_priv *priv, struct se_msg_hdr *header)
+{
+	if (!header->size || header->size > MAX_WORD_SIZE)
+		return -EINVAL;
+
+	if (header->tag != priv->if_defs->cmd_tag &&
+	    header->tag != priv->if_defs->rsp_tag)
+		return -EINVAL;
+
+	if (header->ver == priv->if_defs->base_api_ver)
+		return ele_uapi_allowed_base_cmd(priv, header);
+	else if (header->ver == priv->if_defs->fw_api_ver)
+		return 0;
+
+	return -EINVAL;
+}
+
 /*
  * se_get_msg_chksum() - to calculate checksum word by word.
  *
@@ -42,15 +59,22 @@ u32 se_get_msg_chksum(u32 *msg, u32 msg_len)
 	return chksum;
 }
 
+void set_se_rcv_msg_timeout(struct se_if_priv *priv, u32 timeout_ms)
+{
+	priv->se_rcv_msg_timeout_ms = timeout_ms;
+}
+
 int ele_msg_rcv(struct se_if_device_ctx *dev_ctx, struct se_clbk_handle *se_clbk_hdl)
 {
-	unsigned long timeout;
+	unsigned long timeout_ms;
 	int ret;
 
 	do {
-		timeout = MAX_SCHEDULE_TIMEOUT;
+		timeout_ms = MAX_SCHEDULE_TIMEOUT;
+		if (dev_ctx->priv->cmd_receiver_clbk_hdl.dev_ctx != dev_ctx)
+			timeout_ms = msecs_to_jiffies(dev_ctx->priv->se_rcv_msg_timeout_ms);
 
-		ret = wait_for_completion_interruptible_timeout(&se_clbk_hdl->done, timeout);
+		ret = wait_for_completion_interruptible_timeout(&se_clbk_hdl->done, timeout_ms);
 		if (ret == -ERESTARTSYS) {
 			if (dev_ctx->priv->waiting_rsp_clbk_hdl.dev_ctx) {
 				dev_ctx->priv->waiting_rsp_clbk_hdl.signal_rcvd = true;
@@ -59,6 +83,13 @@ int ele_msg_rcv(struct se_if_device_ctx *dev_ctx, struct se_clbk_handle *se_clbk
 			ret = -EINTR;
 			break;
 		}
+		if (ret == 0) {
+			ret = -ETIMEDOUT;
+			dev_err(dev_ctx->priv->dev,
+				"Fatal Error: SE interface: %s0, hangs indefinitely.\n",
+				get_se_if_name(dev_ctx->priv->if_defs->se_if_type));
+			break;
+		}
 		ret = se_clbk_hdl->rx_msg_sz;
 		break;
 	} while (ret < 0);
diff --git a/drivers/firmware/imx/ele_common.h b/drivers/firmware/imx/ele_common.h
index 5bac14439d7d..bdc13d1b715d 100644
--- a/drivers/firmware/imx/ele_common.h
+++ b/drivers/firmware/imx/ele_common.h
@@ -12,6 +12,11 @@
 
 #define IMX_ELE_FW_DIR                 "imx/ele/"
 
+#define MAX_WORD_SIZE			0x20
+#define SE_RCV_MSG_DEFAULT_TIMEOUT	5000
+#define SE_RCV_MSG_LONG_TIMEOUT		5000000
+
+void set_se_rcv_msg_timeout(struct se_if_priv *priv, u32 val);
 u32 se_get_msg_chksum(u32 *msg, u32 msg_len);
 
 int ele_msg_rcv(struct se_if_device_ctx *dev_ctx, struct se_clbk_handle *se_clbk_hdl);
@@ -42,4 +47,5 @@ int se_save_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem);
 
 int se_restore_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem);
 
+int se_chk_tx_msg_hdr(struct se_if_priv *priv, struct se_msg_hdr *header);
 #endif /*__ELE_COMMON_H__ */
diff --git a/drivers/firmware/imx/se_ctrl.c b/drivers/firmware/imx/se_ctrl.c
index 63562a4d9a3e..33afbdc752da 100644
--- a/drivers/firmware/imx/se_ctrl.c
+++ b/drivers/firmware/imx/se_ctrl.c
@@ -23,6 +23,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/sys_soc.h>
+#include <uapi/linux/se_ioctl.h>
 
 #include "ele_base_msg.h"
 #include "ele_common.h"
@@ -32,12 +33,6 @@
 #define MBOX_TX_NAME			"tx"
 #define MBOX_RX_NAME			"rx"
 
-#define SE_TYPE_STR_DBG			"dbg"
-#define SE_TYPE_STR_HSM			"hsm"
-
-#define SE_TYPE_ID_DBG			0x1
-#define SE_TYPE_ID_HSM			0x2
-
 struct se_fw_img_name {
 	const u8 *prim_fw_nm_in_rfs;
 	const u8 *seco_fw_nm_in_rfs;
@@ -130,6 +125,13 @@ char *get_se_if_name(u8 se_if_id)
 	return NULL;
 }
 
+static u32 get_se_soc_id(struct se_if_priv *priv)
+{
+	const struct se_soc_info *se_info = device_get_match_data(priv->dev);
+
+	return se_info->soc_id;
+}
+
 static struct se_fw_load_info *get_load_fw_instance(struct se_if_priv *priv)
 {
 	return &var_se_info.load_fw;
@@ -203,8 +205,213 @@ static int get_se_soc_info(struct se_if_priv *priv, const struct se_soc_info *se
 	return 0;
 }
 
+static int load_firmware(struct se_if_priv *priv, const u8 *se_img_file_to_load)
+{
+	const struct firmware *fw = NULL;
+	phys_addr_t se_fw_phyaddr;
+	u8 *se_fw_buf;
+	int ret;
+
+	if (!se_img_file_to_load) {
+		dev_err(priv->dev, "FW image is not provided.");
+		return -EINVAL;
+	}
+	ret = request_firmware(&fw, se_img_file_to_load, priv->dev);
+	if (ret)
+		return ret;
+
+	dev_info(priv->dev, "loading firmware %s.", se_img_file_to_load);
+
+	/* allocate buffer to store the SE FW */
+	se_fw_buf = dma_alloc_coherent(priv->dev, fw->size, &se_fw_phyaddr, GFP_KERNEL);
+	if (!se_fw_buf) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	memcpy(se_fw_buf, fw->data, fw->size);
+	ret = ele_fw_authenticate(priv, se_fw_phyaddr, se_fw_phyaddr);
+	if (ret < 0) {
+		dev_err(priv->dev,
+			"Error %pe: Authenticate & load SE firmware %s.",
+			ERR_PTR(ret), se_img_file_to_load);
+		ret = -EPERM;
+	}
+	dma_free_coherent(priv->dev, fw->size, se_fw_buf, se_fw_phyaddr);
+exit:
+	release_firmware(fw);
+
+	return ret;
+}
+
+static int se_load_firmware(struct se_if_priv *priv)
+{
+	struct se_fw_load_info *load_fw = get_load_fw_instance(priv);
+	int ret = 0;
+
+	if (!load_fw->is_fw_tobe_loaded)
+		return 0;
+
+	if (load_fw->imem.state == ELE_IMEM_STATE_BAD) {
+		ret = load_firmware(priv, load_fw->se_fw_img_nm->prim_fw_nm_in_rfs);
+		if (ret) {
+			dev_err(priv->dev, "Failed to load boot firmware.");
+			return -EPERM;
+		}
+	}
+
+	ret = load_firmware(priv, load_fw->se_fw_img_nm->seco_fw_nm_in_rfs);
+	if (ret) {
+		dev_err(priv->dev, "Failed to load runtime firmware.");
+		return -EPERM;
+	}
+
+	load_fw->is_fw_tobe_loaded = false;
+
+	return ret;
+}
+
+static int init_se_shared_mem(struct se_if_device_ctx *dev_ctx)
+{
+	struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
+	struct se_if_priv *priv = dev_ctx->priv;
+
+	INIT_LIST_HEAD(&se_shared_mem_mgmt->pending_out);
+	INIT_LIST_HEAD(&se_shared_mem_mgmt->pending_in);
+
+	/*
+	 * Allocate some memory for data exchanges with S40x.
+	 * This will be used for data not requiring secure memory.
+	 */
+	se_shared_mem_mgmt->non_secure_mem.ptr =
+			dma_alloc_coherent(priv->dev, MAX_DATA_SIZE_PER_USER,
+					   &se_shared_mem_mgmt->non_secure_mem.dma_addr,
+					   GFP_KERNEL);
+	if (!se_shared_mem_mgmt->non_secure_mem.ptr)
+		return -ENOMEM;
+
+	se_shared_mem_mgmt->non_secure_mem.size = MAX_DATA_SIZE_PER_USER;
+	se_shared_mem_mgmt->non_secure_mem.pos = 0;
+
+	return 0;
+}
+
+static void cleanup_se_shared_mem(struct se_if_device_ctx *dev_ctx)
+{
+	struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
+	struct se_if_priv *priv = dev_ctx->priv;
+
+	/* Free non-secure shared buffer. */
+	dma_free_coherent(priv->dev, MAX_DATA_SIZE_PER_USER,
+			  se_shared_mem_mgmt->non_secure_mem.ptr,
+			  se_shared_mem_mgmt->non_secure_mem.dma_addr);
+
+	se_shared_mem_mgmt->non_secure_mem.ptr = NULL;
+	se_shared_mem_mgmt->non_secure_mem.dma_addr = 0;
+	se_shared_mem_mgmt->non_secure_mem.size = 0;
+	se_shared_mem_mgmt->non_secure_mem.pos = 0;
+}
+
+/* Need to copy the output data to user-device context.
+ */
+static int se_dev_ctx_cpy_out_data(struct se_if_device_ctx *dev_ctx)
+{
+	struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
+	struct se_if_priv *priv = dev_ctx->priv;
+	struct se_buf_desc *b_desc, *temp;
+	bool do_cpy = true;
+
+	list_for_each_entry_safe(b_desc, temp, &se_shared_mem_mgmt->pending_out, link) {
+		if (b_desc->usr_buf_ptr && b_desc->shared_buf_ptr && do_cpy) {
+			dev_dbg(priv->dev, "Copying output data to user.");
+			if (do_cpy && copy_to_user(b_desc->usr_buf_ptr,
+						   b_desc->shared_buf_ptr,
+						   b_desc->size)) {
+				dev_err(priv->dev, "Failure copying output data to user.");
+				do_cpy = false;
+			}
+		}
+
+		if (b_desc->shared_buf_ptr)
+			memset(b_desc->shared_buf_ptr, 0, b_desc->size);
+
+		list_del(&b_desc->link);
+		kfree(b_desc);
+	}
+
+	return do_cpy ? 0 : -EFAULT;
+}
+
+/*
+ * Clean the used Shared Memory space,
+ * whether its Input Data copied from user buffers, or
+ * Data received from FW.
+ */
+static void se_dev_ctx_shared_mem_cleanup(struct se_if_device_ctx *dev_ctx)
+{
+	struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
+	struct list_head *pending_lists[] = {&se_shared_mem_mgmt->pending_in,
+						&se_shared_mem_mgmt->pending_out};
+	struct se_buf_desc *b_desc, *temp;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pending_lists); i++) {
+		list_for_each_entry_safe(b_desc, temp, pending_lists[i], link) {
+			if (b_desc->shared_buf_ptr)
+				memset(b_desc->shared_buf_ptr, 0, b_desc->size);
+
+			list_del(&b_desc->link);
+			kfree(b_desc);
+		}
+	}
+	se_shared_mem_mgmt->non_secure_mem.pos = 0;
+}
+
+static int add_b_desc_to_pending_list(void *shared_ptr_with_pos,
+				      struct se_ioctl_setup_iobuf *io,
+				      struct se_if_device_ctx *dev_ctx)
+{
+	struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
+	struct se_buf_desc *b_desc;
+
+	b_desc = kzalloc(sizeof(*b_desc), GFP_KERNEL);
+	if (!b_desc)
+		return -ENOMEM;
+
+	b_desc->shared_buf_ptr = shared_ptr_with_pos;
+	b_desc->usr_buf_ptr = io->user_buf;
+	b_desc->size = io->length;
+
+	if (io->flags & SE_IO_BUF_FLAGS_IS_INPUT) {
+		/*
+		 * buffer is input:
+		 * add an entry in the "pending input buffers" list so
+		 * that copied data can be cleaned from shared memory
+		 * later.
+		 */
+		list_add_tail(&b_desc->link, &se_shared_mem_mgmt->pending_in);
+	} else {
+		/*
+		 * buffer is output:
+		 * add an entry in the "pending out buffers" list so data
+		 * can be copied to user space when receiving Secure-Enclave
+		 * response.
+		 */
+		list_add_tail(&b_desc->link, &se_shared_mem_mgmt->pending_out);
+	}
+
+	return 0;
+}
+
+/* interface for managed res to unregister a character device */
+static void if_misc_deregister(void *miscdevice)
+{
+	misc_deregister(miscdevice);
+}
+
 static int init_misc_device_context(struct se_if_priv *priv, int ch_id,
-				    struct se_if_device_ctx **new_dev_ctx)
+				    struct se_if_device_ctx **new_dev_ctx,
+				    const struct file_operations *se_if_fops)
 {
 	struct se_if_device_ctx *dev_ctx;
 	int ret = 0;
@@ -220,12 +427,520 @@ static int init_misc_device_context(struct se_if_priv *priv, int ch_id,
 	if (!dev_ctx->devname)
 		return -ENOMEM;
 
+	mutex_init(&dev_ctx->fops_lock);
+
 	dev_ctx->priv = priv;
 	*new_dev_ctx = dev_ctx;
 
+	dev_ctx->miscdev = devm_kzalloc(priv->dev, sizeof(*dev_ctx->miscdev), GFP_KERNEL);
+	if (!dev_ctx->miscdev) {
+		*new_dev_ctx = NULL;
+		return -ENOMEM;
+	}
+
+	dev_ctx->miscdev->name = dev_ctx->devname;
+	dev_ctx->miscdev->minor = MISC_DYNAMIC_MINOR;
+	dev_ctx->miscdev->fops = se_if_fops;
+	dev_ctx->miscdev->parent = priv->dev;
+	ret = misc_register(dev_ctx->miscdev);
+	if (ret)
+		return dev_err_probe(priv->dev, ret, "Failed to register misc device.");
+
+	ret = devm_add_action_or_reset(priv->dev, if_misc_deregister, dev_ctx->miscdev);
+	if (ret)
+		return dev_err_probe(priv->dev, ret,
+				     "Failed to add action to the misc-dev.");
 	return ret;
 }
 
+static int init_device_context(struct se_if_priv *priv, int ch_id,
+			       struct se_if_device_ctx **new_dev_ctx)
+{
+	struct se_if_device_ctx *dev_ctx;
+	int ret = 0;
+
+	dev_ctx = kzalloc(sizeof(*dev_ctx), GFP_KERNEL);
+
+	if (!dev_ctx)
+		return -ENOMEM;
+
+	dev_ctx->devname = kasprintf(GFP_KERNEL, "%s0_ch%d",
+				     get_se_if_name(priv->if_defs->se_if_type),
+				     ch_id);
+	if (!dev_ctx->devname) {
+		kfree(dev_ctx);
+		return -ENOMEM;
+	}
+
+	mutex_init(&dev_ctx->fops_lock);
+	dev_ctx->priv = priv;
+	*new_dev_ctx = dev_ctx;
+
+	list_add_tail(&dev_ctx->link, &priv->dev_ctx_list);
+	priv->active_devctx_count++;
+
+	ret = init_se_shared_mem(dev_ctx);
+	if (ret < 0) {
+		kfree(dev_ctx->devname);
+		kfree(dev_ctx);
+		*new_dev_ctx = NULL;
+	}
+
+	return ret;
+}
+
+static int se_ioctl_cmd_snd_rcv_rsp_handler(struct se_if_device_ctx *dev_ctx,
+					    u64 arg)
+{
+	struct se_ioctl_cmd_snd_rcv_rsp_info cmd_snd_rcv_rsp_info = {0};
+	struct se_api_msg *tx_msg = NULL;
+	struct se_api_msg *rx_msg = NULL;
+	struct se_if_priv *priv = dev_ctx->priv;
+	int err = 0;
+
+	if (copy_from_user(&cmd_snd_rcv_rsp_info, (u8 __user *)arg,
+			   sizeof(cmd_snd_rcv_rsp_info))) {
+		dev_err(priv->dev,
+			"%s: Failed to copy cmd_snd_rcv_rsp_info from user.",
+			dev_ctx->devname);
+		err = -EFAULT;
+		goto exit;
+	}
+
+	if (cmd_snd_rcv_rsp_info.tx_buf_sz < SE_MU_HDR_SZ) {
+		dev_err(priv->dev, "%s: User buffer too small(%d < %d)",
+			dev_ctx->devname, cmd_snd_rcv_rsp_info.tx_buf_sz, SE_MU_HDR_SZ);
+		err = -ENOSPC;
+		goto exit;
+	}
+
+	err = se_chk_tx_msg_hdr(priv, (struct se_msg_hdr *)cmd_snd_rcv_rsp_info.tx_buf);
+	if (err)
+		goto exit;
+
+	rx_msg = kzalloc(cmd_snd_rcv_rsp_info.rx_buf_sz, GFP_KERNEL);
+	if (!rx_msg) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	tx_msg = memdup_user(cmd_snd_rcv_rsp_info.tx_buf,
+			     cmd_snd_rcv_rsp_info.tx_buf_sz);
+	if (IS_ERR(tx_msg)) {
+		err = PTR_ERR(tx_msg);
+		goto exit;
+	}
+
+	if (tx_msg->header.tag != priv->if_defs->cmd_tag) {
+		err = -EINVAL;
+		goto exit;
+	}
+
+	if (tx_msg->header.ver == priv->if_defs->fw_api_ver &&
+	    get_load_fw_instance(priv)->is_fw_tobe_loaded) {
+		err = se_load_firmware(priv);
+		if (err) {
+			dev_err(priv->dev, "Could not send msg as FW is not loaded.");
+			err = -EPERM;
+			goto exit;
+		}
+	}
+	set_se_rcv_msg_timeout(priv, SE_RCV_MSG_LONG_TIMEOUT);
+
+	err = ele_msg_send_rcv(dev_ctx, tx_msg, cmd_snd_rcv_rsp_info.tx_buf_sz,
+			       rx_msg, cmd_snd_rcv_rsp_info.rx_buf_sz);
+	if (err < 0)
+		goto exit;
+
+	dev_dbg(priv->dev, "%s: %s %s.", dev_ctx->devname, __func__,
+		"message received, start transmit to user");
+
+	/* We may need to copy the output data to user before
+	 * delivering the completion message.
+	 */
+	err = se_dev_ctx_cpy_out_data(dev_ctx);
+	if (err < 0)
+		goto exit;
+
+	/* Copy data from the buffer */
+	print_hex_dump_debug("to user ", DUMP_PREFIX_OFFSET, 4, 4, rx_msg,
+			     cmd_snd_rcv_rsp_info.rx_buf_sz, false);
+
+	if (copy_to_user(cmd_snd_rcv_rsp_info.rx_buf, rx_msg,
+			 cmd_snd_rcv_rsp_info.rx_buf_sz)) {
+		dev_err(priv->dev, "%s: Failed to copy to user.", dev_ctx->devname);
+		err = -EFAULT;
+	}
+
+exit:
+
+	/* shared memory is allocated before this IOCTL */
+	se_dev_ctx_shared_mem_cleanup(dev_ctx);
+
+	if (copy_to_user((void __user *)arg, &cmd_snd_rcv_rsp_info,
+			 sizeof(cmd_snd_rcv_rsp_info))) {
+		dev_err(priv->dev, "%s: Failed to copy cmd_snd_rcv_rsp_info from user.",
+			dev_ctx->devname);
+		err = -EFAULT;
+	}
+
+	kfree(tx_msg);
+	kfree(rx_msg);
+	return err;
+}
+
+static int se_ioctl_get_mu_info(struct se_if_device_ctx *dev_ctx,
+				u64 arg)
+{
+	struct se_if_priv *priv = dev_ctx->priv;
+	struct se_ioctl_get_if_info if_info;
+	struct se_if_node *if_node;
+	int err = 0;
+
+	if_node = container_of(priv->if_defs, typeof(*if_node), if_defs);
+
+	if_info.se_if_id = 0;
+	if_info.interrupt_idx = 0;
+	if_info.tz = 0;
+	if_info.did = 0;
+	if_info.cmd_tag = priv->if_defs->cmd_tag;
+	if_info.rsp_tag = priv->if_defs->rsp_tag;
+	if_info.success_tag = priv->if_defs->success_tag;
+	if_info.base_api_ver = priv->if_defs->base_api_ver;
+	if_info.fw_api_ver = priv->if_defs->fw_api_ver;
+
+	dev_dbg(priv->dev, "%s: info [se_if_id: %d, irq_idx: %d, tz: 0x%x, did: 0x%x].",
+		dev_ctx->devname, if_info.se_if_id, if_info.interrupt_idx, if_info.tz,
+		if_info.did);
+
+	if (copy_to_user((u8 __user *)arg, &if_info, sizeof(if_info))) {
+		dev_err(priv->dev, "%s: Failed to copy mu info to user.",
+			dev_ctx->devname);
+		err = -EFAULT;
+	}
+
+	return err;
+}
+
+/*
+ * Copy a buffer of data to/from the user and return the address to use in
+ * messages
+ */
+static int se_ioctl_setup_iobuf_handler(struct se_if_device_ctx *dev_ctx,
+					u64 arg)
+{
+	struct se_shared_mem *shared_mem = NULL;
+	struct se_ioctl_setup_iobuf io = {0};
+	int err = 0;
+	u32 pos;
+
+	if (copy_from_user(&io, (u8 __user *)arg, sizeof(io))) {
+		dev_err(dev_ctx->priv->dev, "%s: Failed copy iobuf config from user.",
+			dev_ctx->devname);
+		return -EFAULT;
+	}
+
+	dev_dbg(dev_ctx->priv->dev, "%s: io [buf: %p(%d) flag: %x].", dev_ctx->devname,
+		io.user_buf, io.length, io.flags);
+
+	if (io.length == 0 || !io.user_buf) {
+		/*
+		 * Accept NULL pointers since some buffers are optional
+		 * in FW commands. In this case we should return 0 as
+		 * pointer to be embedded into the message.
+		 * Skip all data copy part of code below.
+		 */
+		io.ele_addr = 0;
+		goto copy;
+	}
+
+	/* No specific requirement for this buffer. */
+	shared_mem = &dev_ctx->se_shared_mem_mgmt.non_secure_mem;
+
+	/* Check there is enough space in the shared memory. */
+	dev_dbg(dev_ctx->priv->dev, "%s: req_size = %d, max_size= %d, curr_pos = %d",
+		dev_ctx->devname, round_up(io.length, 8u), shared_mem->size,
+		shared_mem->pos);
+
+	if (shared_mem->size < shared_mem->pos ||
+	    round_up(io.length, 8u) > (shared_mem->size - shared_mem->pos)) {
+		dev_err(dev_ctx->priv->dev, "%s: Not enough space in shared memory.",
+			dev_ctx->devname);
+		return -ENOMEM;
+	}
+
+	/* Allocate space in shared memory. 8 bytes aligned. */
+	pos = shared_mem->pos;
+	shared_mem->pos += round_up(io.length, 8u);
+	io.ele_addr = (u64)shared_mem->dma_addr + pos;
+
+	memset(shared_mem->ptr + pos, 0, io.length);
+	if ((io.flags & SE_IO_BUF_FLAGS_IS_INPUT) ||
+	    (io.flags & SE_IO_BUF_FLAGS_IS_IN_OUT)) {
+		/*
+		 * buffer is input:
+		 * copy data from user space to this allocated buffer.
+		 */
+		if (copy_from_user(shared_mem->ptr + pos, io.user_buf, io.length)) {
+			dev_err(dev_ctx->priv->dev,
+				"%s: Failed copy data to shared memory.",
+				dev_ctx->devname);
+			return -EFAULT;
+		}
+	}
+
+	err = add_b_desc_to_pending_list(shared_mem->ptr + pos, &io, dev_ctx);
+	if (err < 0)
+		dev_err(dev_ctx->priv->dev, "%s: Failed to allocate/link b_desc.",
+			dev_ctx->devname);
+
+copy:
+	/* Provide the EdgeLock Enclave address to user space only if success.*/
+	if (copy_to_user((u8 __user *)arg, &io, sizeof(io))) {
+		dev_err(dev_ctx->priv->dev, "%s: Failed to copy iobuff setup to user.",
+			dev_ctx->devname);
+		err = -EFAULT;
+	}
+
+	return err;
+}
+
+/* IOCTL to provide SoC information */
+static int se_ioctl_get_se_soc_info_handler(struct se_if_device_ctx *dev_ctx, u64 arg)
+{
+	struct se_ioctl_get_soc_info soc_info;
+	int err = -EINVAL;
+
+	soc_info.soc_id = get_se_soc_id(dev_ctx->priv);
+	soc_info.soc_rev = var_se_info.soc_rev;
+
+	err = copy_to_user((u8 __user *)arg, (u8 *)(&soc_info), sizeof(soc_info));
+	if (err) {
+		dev_err(dev_ctx->priv->dev, "%s: Failed to copy soc info to user.",
+			dev_ctx->devname);
+		err = -EFAULT;
+	}
+
+	return err;
+}
+
+/*
+ * File operations for user-space
+ */
+
+/* Write a message to the MU. */
+static ssize_t se_if_fops_write(struct file *fp, const char __user *buf,
+				size_t size, loff_t *ppos)
+{
+	struct se_if_device_ctx *dev_ctx = fp->private_data;
+	struct se_api_msg *tx_msg = NULL;
+	struct se_if_priv *priv = dev_ctx->priv;
+	int err;
+
+	dev_dbg(priv->dev, "%s: write from buf (%p)%zu, ppos=%lld.", dev_ctx->devname,
+		buf, size, ((ppos) ? *ppos : 0));
+
+	scoped_cond_guard(mutex_intr, return -EBUSY, &dev_ctx->fops_lock) {
+		if (dev_ctx != priv->cmd_receiver_clbk_hdl.dev_ctx)
+			return -EINVAL;
+
+		err = se_chk_tx_msg_hdr(priv, (struct se_msg_hdr *)buf);
+		if (err)
+			return err;
+
+		if (size < SE_MU_HDR_SZ) {
+			dev_err(priv->dev, "%s: User buffer too small(%zu < %d).",
+				dev_ctx->devname, size, SE_MU_HDR_SZ);
+			return -ENOSPC;
+		}
+
+		tx_msg = memdup_user(buf, size);
+		if (IS_ERR(tx_msg))
+			return PTR_ERR(tx_msg);
+
+		print_hex_dump_debug("from user ", DUMP_PREFIX_OFFSET, 4, 4,
+				     tx_msg, size, false);
+
+		err = ele_msg_send(dev_ctx, tx_msg, size);
+
+		kfree(tx_msg);
+		return err;
+	}
+}
+
+/*
+ * Read a message from the MU.
+ * Blocking until a message is available.
+ */
+static ssize_t se_if_fops_read(struct file *fp, char __user *buf, size_t size,
+			       loff_t *ppos)
+{
+	struct se_if_device_ctx *dev_ctx = fp->private_data;
+	struct se_if_priv *priv = dev_ctx->priv;
+	int err;
+
+	dev_dbg(priv->dev, "%s: read to buf %p(%zu), ppos=%lld.", dev_ctx->devname,
+		buf, size, ((ppos) ? *ppos : 0));
+
+	scoped_cond_guard(mutex_intr, return -EBUSY, &dev_ctx->fops_lock) {
+		if (dev_ctx != priv->cmd_receiver_clbk_hdl.dev_ctx) {
+			err = -EINVAL;
+			goto exit;
+		}
+
+		err = ele_msg_rcv(dev_ctx, &priv->cmd_receiver_clbk_hdl);
+		if (err < 0) {
+			dev_err(priv->dev, "%s: Err[0x%x]:Interrupted by signal."
+				"Current active dev-ctx count = %d.",
+				dev_ctx->devname, err, dev_ctx->priv->active_devctx_count);
+			goto exit;
+		}
+
+		/* We may need to copy the output data to user before
+		 * delivering the completion message.
+		 */
+		err = se_dev_ctx_cpy_out_data(dev_ctx);
+		if (err < 0)
+			goto exit;
+
+		/* Copy data from the buffer */
+		print_hex_dump_debug("to user ", DUMP_PREFIX_OFFSET, 4, 4,
+				     priv->cmd_receiver_clbk_hdl.rx_msg,
+				     priv->cmd_receiver_clbk_hdl.rx_msg_sz,
+				     false);
+
+		if (copy_to_user(buf, priv->cmd_receiver_clbk_hdl.rx_msg,
+				 priv->cmd_receiver_clbk_hdl.rx_msg_sz)) {
+			dev_err(priv->dev, "%s: Failed to copy to user.",
+				dev_ctx->devname);
+			err = -EFAULT;
+		} else {
+			err = priv->cmd_receiver_clbk_hdl.rx_msg_sz;
+		}
+exit:
+		priv->cmd_receiver_clbk_hdl.rx_msg_sz = 0;
+
+		se_dev_ctx_shared_mem_cleanup(dev_ctx);
+
+		return err;
+	}
+}
+
+/* Open a character device. */
+static int se_if_fops_open(struct inode *nd, struct file *fp)
+{
+	struct miscdevice *miscdev = fp->private_data;
+	struct se_if_device_ctx *misc_dev_ctx;
+	struct se_if_device_ctx *dev_ctx;
+	struct se_if_priv *priv;
+	int err = 0;
+
+	priv = dev_get_drvdata(miscdev->parent);
+	misc_dev_ctx = priv->priv_dev_ctx;
+
+	scoped_cond_guard(mutex_intr, return -EBUSY, &misc_dev_ctx->fops_lock) {
+		priv->dev_ctx_mono_count++;
+		err = init_device_context(priv,
+					  priv->dev_ctx_mono_count ?
+					  priv->dev_ctx_mono_count
+					  : priv->dev_ctx_mono_count++,
+					  &dev_ctx);
+		if (err)
+			dev_err(priv->dev, "Failed[0x%x] to create dev-ctx.", err);
+		else
+			fp->private_data = dev_ctx;
+
+		return err;
+	}
+}
+
+/* Close a character device. */
+static int se_if_fops_close(struct inode *nd, struct file *fp)
+{
+	struct se_if_device_ctx *dev_ctx = fp->private_data;
+	struct se_if_priv *priv = dev_ctx->priv;
+
+	scoped_cond_guard(mutex_intr, return -EBUSY, &dev_ctx->fops_lock) {
+		/* check if this device was registered as command receiver. */
+		if (priv->cmd_receiver_clbk_hdl.dev_ctx == dev_ctx) {
+			priv->cmd_receiver_clbk_hdl.dev_ctx = NULL;
+			kfree(priv->cmd_receiver_clbk_hdl.rx_msg);
+			priv->cmd_receiver_clbk_hdl.rx_msg = NULL;
+		}
+
+		se_dev_ctx_shared_mem_cleanup(dev_ctx);
+		cleanup_se_shared_mem(dev_ctx);
+
+		priv->active_devctx_count--;
+		list_del(&dev_ctx->link);
+
+		kfree(dev_ctx->devname);
+		kfree(dev_ctx);
+	}
+
+	return 0;
+}
+
+/* IOCTL entry point of a character device */
+static long se_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
+{
+	struct se_if_device_ctx *dev_ctx = fp->private_data;
+	struct se_if_priv *priv = dev_ctx->priv;
+	long err;
+
+	/* Prevent race during change of device context */
+	scoped_cond_guard(mutex_intr, return -EBUSY, &dev_ctx->fops_lock) {
+		switch (cmd) {
+		case SE_IOCTL_ENABLE_CMD_RCV:
+			if (!priv->cmd_receiver_clbk_hdl.dev_ctx) {
+				if (!priv->cmd_receiver_clbk_hdl.rx_msg) {
+					priv->cmd_receiver_clbk_hdl.rx_msg =
+						kzalloc(MAX_NVM_MSG_LEN,
+							GFP_KERNEL);
+					if (!priv->cmd_receiver_clbk_hdl.rx_msg) {
+						err = -ENOMEM;
+						break;
+					}
+				}
+				priv->cmd_receiver_clbk_hdl.rx_msg_sz = MAX_NVM_MSG_LEN;
+				priv->cmd_receiver_clbk_hdl.dev_ctx = dev_ctx;
+				err = 0;
+			} else {
+				err = -EBUSY;
+			}
+			break;
+		case SE_IOCTL_GET_MU_INFO:
+			err = se_ioctl_get_mu_info(dev_ctx, arg);
+			break;
+		case SE_IOCTL_SETUP_IOBUF:
+			err = se_ioctl_setup_iobuf_handler(dev_ctx, arg);
+			break;
+		case SE_IOCTL_GET_SOC_INFO:
+			err = se_ioctl_get_se_soc_info_handler(dev_ctx, arg);
+			break;
+		case SE_IOCTL_CMD_SEND_RCV_RSP:
+			err = se_ioctl_cmd_snd_rcv_rsp_handler(dev_ctx, arg);
+			break;
+		default:
+			err = -EINVAL;
+			dev_dbg(priv->dev, "%s: IOCTL %.8x not supported.",
+				dev_ctx->devname, cmd);
+		}
+	}
+
+	return err;
+}
+
+/* Char driver setup */
+static const struct file_operations se_if_fops = {
+	.open		= se_if_fops_open,
+	.owner		= THIS_MODULE,
+	.release	= se_if_fops_close,
+	.unlocked_ioctl = se_ioctl,
+	.read		= se_if_fops_read,
+	.write		= se_if_fops_write,
+};
+
 /* interface for managed res to free a mailbox channel */
 static void if_mbox_free_channel(void *mbox_chan)
 {
@@ -246,7 +961,7 @@ static int se_if_request_channel(struct device *dev, struct mbox_chan **chan,
 	ret = devm_add_action_or_reset(dev, if_mbox_free_channel, t_chan);
 	if (ret)
 		return dev_err_probe(dev, -EPERM,
-				     "Failed to add-action for removal of mbox: %s\n",
+				     "Failed to add-action for removal of mbox: %s.",
 				     name);
 	*chan = t_chan;
 
@@ -255,6 +970,7 @@ static int se_if_request_channel(struct device *dev, struct mbox_chan **chan,
 
 static void se_if_probe_cleanup(void *plat_dev)
 {
+	struct se_if_device_ctx *dev_ctx, *t_dev_ctx;
 	struct platform_device *pdev = plat_dev;
 	struct se_fw_load_info *load_fw;
 	struct device *dev = &pdev->dev;
@@ -279,6 +995,13 @@ static void se_if_probe_cleanup(void *plat_dev)
 		load_fw->imem.buf = NULL;
 	}
 
+	if (priv->dev_ctx_mono_count) {
+		list_for_each_entry_safe(dev_ctx, t_dev_ctx, &priv->dev_ctx_list, link) {
+			list_del(&dev_ctx->link);
+			priv->active_devctx_count--;
+		}
+	}
+
 	/*
 	 * No need to check, if reserved memory is allocated
 	 * before calling for its release. Or clearing the
@@ -319,6 +1042,7 @@ static int se_if_probe(struct platform_device *pdev)
 	priv->se_mb_cl.tx_block		= false;
 	priv->se_mb_cl.knows_txdone	= true;
 	priv->se_mb_cl.rx_callback	= se_if_rx_callback;
+	set_se_rcv_msg_timeout(priv, SE_RCV_MSG_DEFAULT_TIMEOUT);
 
 	ret = se_if_request_channel(dev, &priv->tx_chan, &priv->se_mb_cl, MBOX_TX_NAME);
 	if (ret)
@@ -340,6 +1064,7 @@ static int se_if_probe(struct platform_device *pdev)
 					     "Unable to get sram pool = %s.",
 					     if_node->pool_name);
 	}
+	INIT_LIST_HEAD(&priv->dev_ctx_list);
 
 	if (if_node->reserved_dma_ranges) {
 		ret = of_reserved_mem_device_init(dev);
@@ -348,7 +1073,7 @@ static int se_if_probe(struct platform_device *pdev)
 					    "Failed to init reserved memory region.");
 	}
 
-	ret = init_misc_device_context(priv, 0, &priv->priv_dev_ctx);
+	ret = init_misc_device_context(priv, 0, &priv->priv_dev_ctx, &se_if_fops);
 	if (ret)
 		return dev_err_probe(dev, ret,
 				     "Failed[0x%x] to create device contexts.",
@@ -389,6 +1114,7 @@ static int se_suspend(struct device *dev)
 	struct se_fw_load_info *load_fw;
 	int ret = 0;
 
+	set_se_rcv_msg_timeout(priv, SE_RCV_MSG_DEFAULT_TIMEOUT);
 	load_fw = get_load_fw_instance(priv);
 
 	if (load_fw->imem_mgmt) {
diff --git a/drivers/firmware/imx/se_ctrl.h b/drivers/firmware/imx/se_ctrl.h
index b5e7705e2f26..5fcdcfe3e8e5 100644
--- a/drivers/firmware/imx/se_ctrl.h
+++ b/drivers/firmware/imx/se_ctrl.h
@@ -14,6 +14,7 @@
 #define SE_MSG_WORD_SZ			0x4
 
 #define RES_STATUS(x)			FIELD_GET(0x000000ff, x)
+#define MAX_DATA_SIZE_PER_USER		(65 * 1024)
 #define MAX_NVM_MSG_LEN			(256)
 #define MESSAGING_VERSION_6		0x6
 #define MESSAGING_VERSION_7		0x7
@@ -37,10 +38,38 @@ struct se_imem_buf {
 	u32 state;
 };
 
+struct se_buf_desc {
+	u8 *shared_buf_ptr;
+	void __user *usr_buf_ptr;
+	u32 size;
+	struct list_head link;
+};
+
+struct se_shared_mem {
+	dma_addr_t dma_addr;
+	u32 size;
+	u32 pos;
+	u8 *ptr;
+};
+
+struct se_shared_mem_mgmt_info {
+	struct list_head pending_in;
+	struct list_head pending_out;
+
+	struct se_shared_mem non_secure_mem;
+};
+
 /* Private struct for each char device instance. */
 struct se_if_device_ctx {
 	struct se_if_priv *priv;
+	struct miscdevice *miscdev;
 	const char *devname;
+
+	/* process one file operation at a time. */
+	struct mutex fops_lock;
+
+	struct se_shared_mem_mgmt_info se_shared_mem_mgmt;
+	struct list_head link;
 };
 
 /* Header of the messages exchange with the EdgeLock Enclave */
@@ -89,6 +118,10 @@ struct se_if_priv {
 	const struct se_if_defines *if_defs;
 
 	struct se_if_device_ctx *priv_dev_ctx;
+	struct list_head dev_ctx_list;
+	u32 active_devctx_count;
+	u32 dev_ctx_mono_count;
+	u32 se_rcv_msg_timeout_ms;
 };
 
 char *get_se_if_name(u8 se_if_id);
diff --git a/include/uapi/linux/se_ioctl.h b/include/uapi/linux/se_ioctl.h
new file mode 100644
index 000000000000..0c948bdc8c26
--- /dev/null
+++ b/include/uapi/linux/se_ioctl.h
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause*/
+/*
+ * Copyright 2025 NXP
+ */
+
+#ifndef SE_IOCTL_H
+#define SE_IOCTL_H
+
+#include <linux/types.h>
+
+#define SE_TYPE_STR_DBG			"dbg"
+#define SE_TYPE_STR_HSM			"hsm"
+#define SE_TYPE_ID_UNKWN		0x0
+#define SE_TYPE_ID_DBG			0x1
+#define SE_TYPE_ID_HSM			0x2
+/* IOCTL definitions. */
+
+struct se_ioctl_setup_iobuf {
+	void __user *user_buf;
+	__u32 length;
+	__u32 flags;
+	__u64 ele_addr;
+};
+
+struct se_ioctl_shared_mem_cfg {
+	__u32 base_offset;
+	__u32 size;
+};
+
+struct se_ioctl_get_if_info {
+	__u8 se_if_id;
+	__u8 interrupt_idx;
+	__u8 tz;
+	__u8 did;
+	__u8 cmd_tag;
+	__u8 rsp_tag;
+	__u8 success_tag;
+	__u8 base_api_ver;
+	__u8 fw_api_ver;
+};
+
+struct se_ioctl_cmd_snd_rcv_rsp_info {
+	__u32 __user *tx_buf;
+	int tx_buf_sz;
+	__u32 __user *rx_buf;
+	int rx_buf_sz;
+};
+
+struct se_ioctl_get_soc_info {
+	__u16 soc_id;
+	__u16 soc_rev;
+};
+
+/* IO Buffer Flags */
+#define SE_IO_BUF_FLAGS_IS_OUTPUT	(0x00u)
+#define SE_IO_BUF_FLAGS_IS_INPUT	(0x01u)
+#define SE_IO_BUF_FLAGS_USE_SEC_MEM	(0x02u)
+#define SE_IO_BUF_FLAGS_USE_SHORT_ADDR	(0x04u)
+#define SE_IO_BUF_FLAGS_IS_IN_OUT	(0x10u)
+
+/* IOCTLS */
+#define SE_IOCTL			0x0A /* like MISC_MAJOR. */
+
+/*
+ * ioctl to designated the current fd as logical-reciever.
+ * This is ioctl is send when the nvm-daemon, a slave to the
+ * firmware is started by the user.
+ */
+#define SE_IOCTL_ENABLE_CMD_RCV	_IO(SE_IOCTL, 0x01)
+
+/*
+ * ioctl to get the buffer allocated from the memory, which is shared
+ * between kernel and FW.
+ * Post allocation, the kernel tagged the allocated memory with:
+ *  Output
+ *  Input
+ *  Input-Output
+ *  Short address
+ *  Secure-memory
+ */
+#define SE_IOCTL_SETUP_IOBUF	_IOWR(SE_IOCTL, 0x03, struct se_ioctl_setup_iobuf)
+
+/*
+ * ioctl to get the mu information, that is used to exchange message
+ * with FW, from user-spaced.
+ */
+#define SE_IOCTL_GET_MU_INFO	_IOR(SE_IOCTL, 0x04, struct se_ioctl_get_if_info)
+/*
+ * ioctl to get SoC Info from user-space.
+ */
+#define SE_IOCTL_GET_SOC_INFO      _IOR(SE_IOCTL, 0x06, struct se_ioctl_get_soc_info)
+
+/*
+ * ioctl to send command and receive response from user-space.
+ */
+#define SE_IOCTL_CMD_SEND_RCV_RSP _IOWR(SE_IOCTL, 0x07, struct se_ioctl_cmd_snd_rcv_rsp_info)
+#endif

-- 
2.43.0



From pankaj.gupta at nxp.com  Fri Dec 12 01:14:17 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Fri, 12 Dec 2025 14:44:17 +0530
Subject: [PATCH v21 6/7] arm64: dts: imx8ulp: add secure enclave node
In-Reply-To: <20251212-imx-se-if-v21-0-ee7d6052d848@nxp.com>
References: <20251212-imx-se-if-v21-0-ee7d6052d848@nxp.com>
Message-ID: <20251212-imx-se-if-v21-6-ee7d6052d848@nxp.com>

Add support for NXP secure enclave called EdgeLock Enclave firmware (se-fw)
for imx8ulp-evk.

Add label sram0 for sram at 2201f000 and add secure-enclave node

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
 arch/arm64/boot/dts/freescale/imx8ulp.dtsi | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8ulp.dtsi b/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
index 13b01f3aa2a4..10a4779dd24c 100644
--- a/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
- * Copyright 2021 NXP
+ * Copyright 2021, 2025 NXP
  */
 
 #include <dt-bindings/clock/imx8ulp-clock.h>
@@ -154,7 +154,7 @@ sosc: clock-sosc {
 		#clock-cells = <0>;
 	};
 
-	sram at 2201f000 {
+	sram0: sram at 2201f000 {
 		compatible = "mmio-sram";
 		reg = <0x0 0x2201f000 0x0 0x1000>;
 
@@ -186,6 +186,13 @@ scmi_sensor: protocol at 15 {
 				#thermal-sensor-cells = <1>;
 			};
 		};
+
+		hsm0: secure-enclave {
+			 compatible = "fsl,imx8ulp-se-ele-hsm";
+			 mbox-names = "tx", "rx";
+			 mboxes = <&s4muap 0 0>, <&s4muap 1 0>;
+			 sram = <&sram0>;
+		 };
 	};
 
 	cm33: remoteproc-cm33 {

-- 
2.43.0



From pankaj.gupta at nxp.com  Fri Dec 12 01:14:18 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Fri, 12 Dec 2025 14:44:18 +0530
Subject: [PATCH v21 7/7] arm64: dts: imx8ulp-evk: add reserved memory
 property
In-Reply-To: <20251212-imx-se-if-v21-0-ee7d6052d848@nxp.com>
References: <20251212-imx-se-if-v21-0-ee7d6052d848@nxp.com>
Message-ID: <20251212-imx-se-if-v21-7-ee7d6052d848@nxp.com>

Reserve 1MB of DDR memory region due to EdgeLock Enclave's hardware
limitation restricting access to DDR addresses from 0x80000000
to 0xafffffff.

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
 arch/arm64/boot/dts/freescale/imx8ulp-evk.dts | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8ulp-evk.dts b/arch/arm64/boot/dts/freescale/imx8ulp-evk.dts
index 290a49bea2f7..10aaf02f8ea7 100644
--- a/arch/arm64/boot/dts/freescale/imx8ulp-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8ulp-evk.dts
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
- * Copyright 2021 NXP
+ * Copyright 2021, 2025 NXP
  */
 
 /dts-v1/;
@@ -37,6 +37,12 @@ linux,cma {
 			linux,cma-default;
 		};
 
+		ele_reserved: memory at 90000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x90000000 0 0x100000>;
+			no-map;
+		};
+
 		m33_reserved: noncacheable-section at a8600000 {
 			reg = <0 0xa8600000 0 0x1000000>;
 			no-map;
@@ -259,6 +265,10 @@ &usdhc0 {
 	status = "okay";
 };
 
+&hsm0 {
+	memory-region = <&ele_reserved>;
+};
+
 &fec {
 	pinctrl-names = "default", "sleep";
 	pinctrl-0 = <&pinctrl_enet>;

-- 
2.43.0



From peng.fan at oss.nxp.com  Fri Dec 12 01:16:06 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Fri, 12 Dec 2025 17:16:06 +0800
Subject: [PATCH 0/4] arm64: dts: imx91: misc updates
Message-ID: <20251212-imx91-dts-v1-0-2bb3c13762dd@nxp.com>

Patch 1,2: add temp sensor and thermal zone
Patch 3: Update file name
Patch 4: Add gpio4 alias

Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
Peng Fan (4):
      arm64: dts: imx91: Add tempsensor node
      arm64: dts: imx91: Add thermal zone node
      arm64: dts: imx91: Update file name with dash
      arm64: dts: imx91-11x11-evk: Add gpio4 alias

 arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts  |    1 +
 arch/arm64/boot/dts/freescale/imx91.dtsi           |   58 +-
 arch/arm64/boot/dts/freescale/imx91_93_common.dtsi | 1187 --------------------
 arch/arm64/boot/dts/freescale/imx93.dtsi           |    2 +-
 4 files changed, 59 insertions(+), 1189 deletions(-)
---
base-commit: 008d3547aae5bc86fac3eda317489169c3fda112
change-id: 20251212-imx91-dts-8d2e483191f7

Best regards,
-- 
Peng Fan <peng.fan at nxp.com>



From peng.fan at oss.nxp.com  Fri Dec 12 01:16:07 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Fri, 12 Dec 2025 17:16:07 +0800
Subject: [PATCH 1/4] arm64: dts: imx91: Add tempsensor node
In-Reply-To: <20251212-imx91-dts-v1-0-2bb3c13762dd@nxp.com>
References: <20251212-imx91-dts-v1-0-2bb3c13762dd@nxp.com>
Message-ID: <20251212-imx91-dts-v1-1-2bb3c13762dd@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

Add tempsensor node and trim sub-nodes in ocotp.

Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 arch/arm64/boot/dts/freescale/imx91.dtsi | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx91.dtsi b/arch/arm64/boot/dts/freescale/imx91.dtsi
index 4d8300b2a7bca33bd0613db9e79d2fba6b40c052..c08db08ca9607b9780a77e215cdb5997e4daae4e 100644
--- a/arch/arm64/boot/dts/freescale/imx91.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx91.dtsi
@@ -6,6 +6,21 @@
 #include "imx91-pinfunc.h"
 #include "imx91_93_common.dtsi"
 
+&aips1 {
+	tempsense0: thermal-sensor at 44482000 {
+		compatible = "fsl,imx91-tmu";
+		reg = <0x44482000 0x1000>;
+		clocks = <&clk IMX93_CLK_TMC_GATE>;
+		interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "thr1", "thr2", "ready";
+		#thermal-sensor-cells = <0>;
+		nvmem-cells = <&tmu_trim1>, <&tmu_trim2>;
+		nvmem-cell-names = "trim1", "trim2";
+	};
+};
+
 &clk {
 	compatible = "fsl,imx91-ccm";
 };
@@ -69,3 +84,13 @@ &media_blk_ctrl {
 	clock-names = "apb", "axi", "nic", "disp", "cam",
 		      "lcdif", "isi", "csi";
 };
+
+&ocotp {
+	tmu_trim1: tmu-trim at a0 {
+		reg = <0xa0 0x4>;
+	};
+
+	tmu_trim2: tmu-trim at a4 {
+		reg = <0xa4 0x4>;
+	};
+};

-- 
2.37.1



From peng.fan at oss.nxp.com  Fri Dec 12 01:16:08 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Fri, 12 Dec 2025 17:16:08 +0800
Subject: [PATCH 2/4] arm64: dts: imx91: Add thermal zone node
In-Reply-To: <20251212-imx91-dts-v1-0-2bb3c13762dd@nxp.com>
References: <20251212-imx91-dts-v1-0-2bb3c13762dd@nxp.com>
Message-ID: <20251212-imx91-dts-v1-2-2bb3c13762dd@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

Add thermal zone node

Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 arch/arm64/boot/dts/freescale/imx91.dtsi | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx91.dtsi b/arch/arm64/boot/dts/freescale/imx91.dtsi
index c08db08ca9607b9780a77e215cdb5997e4daae4e..d8b5e188949f59b7452df54407d2126a5e1a54e7 100644
--- a/arch/arm64/boot/dts/freescale/imx91.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx91.dtsi
@@ -6,6 +6,37 @@
 #include "imx91-pinfunc.h"
 #include "imx91_93_common.dtsi"
 
+/{
+	thermal_zones: thermal-zones {
+		cpu-thermal {
+			polling-delay-passive = <250>;
+			polling-delay = <2000>;
+			thermal-sensors = <&tempsense0>;
+			trips {
+				cpu_alert0: trip0 {
+					temperature = <80000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_crit0: trip1 {
+					temperature = <90000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+
+			cooling-maps {
+				map0 {
+					trip = <&cpu_alert0>;
+					cooling-device =
+						<&A55_0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+		};
+	};
+};
+
 &aips1 {
 	tempsense0: thermal-sensor at 44482000 {
 		compatible = "fsl,imx91-tmu";

-- 
2.37.1



From peng.fan at oss.nxp.com  Fri Dec 12 01:16:09 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Fri, 12 Dec 2025 17:16:09 +0800
Subject: [PATCH 3/4] arm64: dts: imx91: Update file name with dash
In-Reply-To: <20251212-imx91-dts-v1-0-2bb3c13762dd@nxp.com>
References: <20251212-imx91-dts-v1-0-2bb3c13762dd@nxp.com>
Message-ID: <20251212-imx91-dts-v1-3-2bb3c13762dd@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

Update "imx91_93_common.dtsi" to "imx91-93-common.dtsi" to align with
others.

Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 arch/arm64/boot/dts/freescale/imx91.dtsi           |    2 +-
 arch/arm64/boot/dts/freescale/imx91_93_common.dtsi | 1187 --------------------
 arch/arm64/boot/dts/freescale/imx93.dtsi           |    2 +-
 3 files changed, 2 insertions(+), 1189 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx91.dtsi b/arch/arm64/boot/dts/freescale/imx91.dtsi
index d8b5e188949f59b7452df54407d2126a5e1a54e7..89d0b394fcba83fe16f3ebf9c5f1ede50c5675ef 100644
--- a/arch/arm64/boot/dts/freescale/imx91.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx91.dtsi
@@ -4,7 +4,7 @@
  */
 
 #include "imx91-pinfunc.h"
-#include "imx91_93_common.dtsi"
+#include "imx91-93-common.dtsi"
 
 /{
 	thermal_zones: thermal-zones {
diff --git a/arch/arm64/boot/dts/freescale/imx91_93_common.dtsi b/arch/arm64/boot/dts/freescale/imx91_93_common.dtsi
deleted file mode 100644
index 7958cef353766a430df5e626ff2403dc05a974b1..0000000000000000000000000000000000000000
--- a/arch/arm64/boot/dts/freescale/imx91_93_common.dtsi
+++ /dev/null
@@ -1,1187 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
-/*
- * Copyright 2022,2025 NXP
- */
-
-#include <dt-bindings/clock/imx93-clock.h>
-#include <dt-bindings/dma/fsl-edma.h>
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/input/input.h>
-#include <dt-bindings/interrupt-controller/arm-gic.h>
-#include <dt-bindings/power/fsl,imx93-power.h>
-#include <dt-bindings/thermal/thermal.h>
-
-#include "imx93-pinfunc.h"
-
-/ {
-	interrupt-parent = <&gic>;
-	#address-cells = <2>;
-	#size-cells = <2>;
-
-	cpus: cpus {
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		idle-states {
-			entry-method = "psci";
-
-			cpu_pd_wait: cpu-pd-wait {
-				compatible = "arm,idle-state";
-				arm,psci-suspend-param = <0x0010033>;
-				local-timer-stop;
-				entry-latency-us = <10000>;
-				exit-latency-us = <7000>;
-				min-residency-us = <27000>;
-				wakeup-latency-us = <15000>;
-			};
-		};
-
-		A55_0: cpu at 0 {
-			device_type = "cpu";
-			compatible = "arm,cortex-a55";
-			reg = <0x0>;
-			enable-method = "psci";
-			#cooling-cells = <2>;
-			cpu-idle-states = <&cpu_pd_wait>;
-		};
-	};
-
-	osc_32k: clock-osc-32k {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <32768>;
-		clock-output-names = "osc_32k";
-	};
-
-	osc_24m: clock-osc-24m {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <24000000>;
-		clock-output-names = "osc_24m";
-	};
-
-	clk_ext1: clock-ext1 {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <133000000>;
-		clock-output-names = "clk_ext1";
-	};
-
-	pmu {
-		compatible = "arm,cortex-a55-pmu";
-		interrupts = <GIC_PPI 7 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
-	};
-
-	psci {
-		compatible = "arm,psci-1.0";
-		method = "smc";
-	};
-
-	timer {
-		compatible = "arm,armv8-timer";
-		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
-			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
-			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
-			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>;
-		clock-frequency = <24000000>;
-		arm,no-tick-in-suspend;
-		interrupt-parent = <&gic>;
-	};
-
-	gic: interrupt-controller at 48000000 {
-		compatible = "arm,gic-v3";
-		reg = <0 0x48000000 0 0x10000>,
-		      <0 0x48040000 0 0xc0000>;
-		#interrupt-cells = <3>;
-		interrupt-controller;
-		interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-parent = <&gic>;
-	};
-
-	mqs1: mqs1 {
-		compatible = "fsl,imx93-mqs";
-		gpr = <&aonmix_ns_gpr>;
-		status = "disabled";
-	};
-
-	mqs2: mqs2 {
-		compatible = "fsl,imx93-mqs";
-		gpr = <&wakeupmix_gpr>;
-		status = "disabled";
-	};
-
-	usbphynop1: usbphynop1 {
-		compatible = "usb-nop-xceiv";
-		#phy-cells = <0>;
-		clocks = <&clk IMX93_CLK_USB_PHY_BURUNIN>;
-		clock-names = "main_clk";
-	};
-
-	usbphynop2: usbphynop2 {
-		compatible = "usb-nop-xceiv";
-		#phy-cells = <0>;
-		clocks = <&clk IMX93_CLK_USB_PHY_BURUNIN>;
-		clock-names = "main_clk";
-	};
-
-	soc at 0 {
-		compatible = "simple-bus";
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges = <0x0 0x0 0x0 0x80000000>,
-			 <0x28000000 0x0 0x28000000 0x10000000>;
-
-		aips1: bus at 44000000 {
-			compatible = "fsl,aips-bus", "simple-bus";
-			reg = <0x44000000 0x800000>;
-			#address-cells = <1>;
-			#size-cells = <1>;
-			ranges;
-
-			edma1: dma-controller at 44000000 {
-				compatible = "fsl,imx93-edma3";
-				reg = <0x44000000 0x200000>;
-				#dma-cells = <3>;
-				dma-channels = <31>;
-				interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>,  //  0: Reserved
-					     <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>,  //  1: CANFD1
-					     <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>,  //  2: Reserved
-					     <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>,  //  3: GPIO1 CH0
-					     <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>,  //  4: GPIO1 CH1
-					     <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>, //  5: I3C1 TO Bus
-					     <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>, //  6: I3C1 From Bus
-					     <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>, //  7: LPI2C1 M TX
-					     <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>, //  8: LPI2C1 S TX
-					     <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>, //  9: LPI2C2 M RX
-					     <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>, // 10: LPI2C2 S RX
-					     <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>, // 11: LPSPI1 TX
-					     <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>, // 12: LPSPI1 RX
-					     <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>, // 13: LPSPI2 TX
-					     <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>, // 14: LPSPI2 RX
-					     <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, // 15: LPTMR1
-					     <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>, // 16: LPUART1 TX
-					     <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>, // 17: LPUART1 RX
-					     <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>, // 18: LPUART2 TX
-					     <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>, // 19: LPUART2 RX
-					     <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>, // 20: S400
-					     <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>, // 21: SAI TX
-					     <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>, // 22: SAI RX
-					     <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>, // 23: TPM1 CH0/CH2
-					     <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>, // 24: TPM1 CH1/CH3
-					     <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, // 25: TPM1 Overflow
-					     <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>, // 26: TMP2 CH0/CH2
-					     <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>, // 27: TMP2 CH1/CH3
-					     <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>, // 28: TMP2 Overflow
-					     <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>, // 29: PDM
-					     <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>, // 30: ADC1
-					     <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;  // err
-				clocks = <&clk IMX93_CLK_EDMA1_GATE>;
-				clock-names = "dma";
-			};
-
-			aonmix_ns_gpr: syscon at 44210000 {
-				compatible = "fsl,imx93-aonmix-ns-syscfg", "syscon";
-				reg = <0x44210000 0x1000>;
-			};
-
-			system_counter: timer at 44290000 {
-				compatible = "nxp,sysctr-timer";
-				reg = <0x44290000 0x30000>;
-				interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&osc_24m>;
-				clock-names = "per";
-				nxp,no-divider;
-			};
-
-			wdog1: watchdog at 442d0000 {
-				compatible = "fsl,imx93-wdt";
-				reg = <0x442d0000 0x10000>;
-				interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_WDOG1_GATE>;
-				timeout-sec = <40>;
-				status = "disabled";
-			};
-
-			wdog2: watchdog at 442e0000 {
-				compatible = "fsl,imx93-wdt";
-				reg = <0x442e0000 0x10000>;
-				interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_WDOG2_GATE>;
-				timeout-sec = <40>;
-				status = "disabled";
-			};
-
-			tpm1: pwm at 44310000 {
-				compatible = "fsl,imx7ulp-pwm";
-				reg = <0x44310000 0x1000>;
-				clocks = <&clk IMX93_CLK_TPM1_GATE>;
-				#pwm-cells = <3>;
-				status = "disabled";
-			};
-
-			tpm2: pwm at 44320000 {
-				compatible = "fsl,imx7ulp-pwm";
-				reg = <0x44320000 0x10000>;
-				clocks = <&clk IMX93_CLK_TPM2_GATE>;
-				#pwm-cells = <3>;
-				status = "disabled";
-			};
-
-			i3c1: i3c at 44330000 {
-				compatible = "silvaco,i3c-master-v1";
-				reg = <0x44330000 0x10000>;
-				interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
-				#address-cells = <3>;
-				#size-cells = <0>;
-				clocks = <&clk IMX93_CLK_BUS_AON>,
-					 <&clk IMX93_CLK_I3C1_GATE>,
-					 <&clk IMX93_CLK_I3C1_SLOW>;
-				clock-names = "pclk", "fast_clk", "slow_clk";
-				status = "disabled";
-			};
-
-			lpi2c1: i2c at 44340000 {
-				compatible = "fsl,imx93-lpi2c", "fsl,imx7ulp-lpi2c";
-				reg = <0x44340000 0x10000>;
-				#address-cells = <1>;
-				#size-cells = <0>;
-				interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_LPI2C1_GATE>,
-					 <&clk IMX93_CLK_BUS_AON>;
-				clock-names = "per", "ipg";
-				dmas = <&edma1 7 0 0>, <&edma1 8 0 FSL_EDMA_RX>;
-				dma-names = "tx", "rx";
-				status = "disabled";
-			};
-
-			lpi2c2: i2c at 44350000 {
-				compatible = "fsl,imx93-lpi2c", "fsl,imx7ulp-lpi2c";
-				reg = <0x44350000 0x10000>;
-				#address-cells = <1>;
-				#size-cells = <0>;
-				interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_LPI2C2_GATE>,
-					 <&clk IMX93_CLK_BUS_AON>;
-				clock-names = "per", "ipg";
-				dmas = <&edma1 9 0 0>, <&edma1 10 0 FSL_EDMA_RX>;
-				dma-names = "tx", "rx";
-				status = "disabled";
-			};
-
-			lpspi1: spi at 44360000 {
-				#address-cells = <1>;
-				#size-cells = <0>;
-				compatible = "fsl,imx93-spi", "fsl,imx7ulp-spi";
-				reg = <0x44360000 0x10000>;
-				interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_LPSPI1_GATE>,
-					 <&clk IMX93_CLK_BUS_AON>;
-				clock-names = "per", "ipg";
-				dmas = <&edma1 11 0 0>, <&edma1 12 0 FSL_EDMA_RX>;
-				dma-names = "tx", "rx";
-				status = "disabled";
-			};
-
-			lpspi2: spi at 44370000 {
-				#address-cells = <1>;
-				#size-cells = <0>;
-				compatible = "fsl,imx93-spi", "fsl,imx7ulp-spi";
-				reg = <0x44370000 0x10000>;
-				interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_LPSPI2_GATE>,
-					 <&clk IMX93_CLK_BUS_AON>;
-				clock-names = "per", "ipg";
-				dmas = <&edma1 13 0 0>, <&edma1 14 0 FSL_EDMA_RX>;
-				dma-names = "tx", "rx";
-				status = "disabled";
-			};
-
-			lpuart1: serial at 44380000 {
-				compatible = "fsl,imx93-lpuart", "fsl,imx8ulp-lpuart", "fsl,imx7ulp-lpuart";
-				reg = <0x44380000 0x1000>;
-				interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_LPUART1_GATE>;
-				clock-names = "ipg";
-				dmas = <&edma1 17 0 FSL_EDMA_RX>, <&edma1 16 0 0>;
-				dma-names = "rx", "tx";
-				status = "disabled";
-			};
-
-			lpuart2: serial at 44390000 {
-				compatible = "fsl,imx93-lpuart", "fsl,imx8ulp-lpuart", "fsl,imx7ulp-lpuart";
-				reg = <0x44390000 0x1000>;
-				interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_LPUART2_GATE>;
-				clock-names = "ipg";
-				dmas = <&edma1 19 0 FSL_EDMA_RX>, <&edma1 18 0 0>;
-				dma-names = "rx", "tx";
-				status = "disabled";
-			};
-
-			flexcan1: can at 443a0000 {
-				compatible = "fsl,imx93-flexcan";
-				reg = <0x443a0000 0x10000>;
-				interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_BUS_AON>,
-					 <&clk IMX93_CLK_CAN1_GATE>;
-				clock-names = "ipg", "per";
-				assigned-clocks = <&clk IMX93_CLK_CAN1>;
-				assigned-clock-parents = <&clk IMX93_CLK_SYS_PLL_PFD1_DIV2>;
-				assigned-clock-rates = <40000000>;
-				fsl,clk-source = /bits/ 8 <0>;
-				fsl,stop-mode = <&aonmix_ns_gpr 0x14 0>;
-				status = "disabled";
-			};
-
-			sai1: sai at 443b0000 {
-				compatible = "fsl,imx93-sai";
-				reg = <0x443b0000 0x10000>;
-				interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_SAI1_IPG>, <&clk IMX93_CLK_DUMMY>,
-					 <&clk IMX93_CLK_SAI1_GATE>, <&clk IMX93_CLK_DUMMY>,
-					 <&clk IMX93_CLK_DUMMY>;
-				clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
-				dmas = <&edma1 22 0 FSL_EDMA_RX>, <&edma1 21 0 0>;
-				dma-names = "rx", "tx";
-				#sound-dai-cells = <0>;
-				status = "disabled";
-			};
-
-			iomuxc: pinctrl at 443c0000 {
-				compatible = "fsl,imx93-iomuxc";
-				reg = <0x443c0000 0x10000>;
-				status = "okay";
-			};
-
-			bbnsm: bbnsm at 44440000 {
-				compatible = "nxp,imx93-bbnsm", "syscon", "simple-mfd";
-				reg = <0x44440000 0x10000>;
-
-				bbnsm_rtc: rtc {
-					compatible = "nxp,imx93-bbnsm-rtc";
-					interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
-				};
-
-				bbnsm_pwrkey: pwrkey {
-					compatible = "nxp,imx93-bbnsm-pwrkey";
-					interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
-					linux,code = <KEY_POWER>;
-				};
-			};
-
-			clk: clock-controller at 44450000 {
-				compatible = "fsl,imx93-ccm";
-				reg = <0x44450000 0x10000>;
-				#clock-cells = <1>;
-				clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>;
-				clock-names = "osc_32k", "osc_24m", "clk_ext1";
-				assigned-clocks = <&clk IMX93_CLK_AUDIO_PLL>;
-				assigned-clock-rates = <393216000>;
-				status = "okay";
-			};
-
-			src: system-controller at 44460000 {
-				compatible = "fsl,imx93-src", "syscon";
-				reg = <0x44460000 0x10000>;
-				#address-cells = <1>;
-				#size-cells = <1>;
-				ranges;
-
-				mediamix: power-domain at 44462400 {
-					compatible = "fsl,imx93-src-slice";
-					reg = <0x44462400 0x400>, <0x44465800 0x400>;
-					#power-domain-cells = <0>;
-					clocks = <&clk IMX93_CLK_NIC_MEDIA_GATE>,
-						 <&clk IMX93_CLK_MEDIA_APB>;
-				};
-			};
-
-			clock-controller at 44480000 {
-				compatible = "fsl,imx93-anatop";
-				reg = <0x44480000 0x2000>;
-				#clock-cells = <1>;
-			};
-
-			micfil: micfil at 44520000 {
-				compatible = "fsl,imx93-micfil";
-				reg = <0x44520000 0x10000>;
-				interrupts = <GIC_SPI 202 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 201 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_PDM_IPG>,
-					 <&clk IMX93_CLK_PDM_GATE>,
-					 <&clk IMX93_CLK_AUDIO_PLL>;
-				clock-names = "ipg_clk", "ipg_clk_app", "pll8k";
-				dmas = <&edma1 29 0 5>;
-				dma-names = "rx";
-				#sound-dai-cells = <0>;
-				status = "disabled";
-			};
-
-			adc1: adc at 44530000 {
-				compatible = "nxp,imx93-adc";
-				reg = <0x44530000 0x10000>;
-				interrupts = <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_ADC1_GATE>;
-				clock-names = "ipg";
-				#io-channel-cells = <1>;
-				status = "disabled";
-			};
-		};
-
-		aips2: bus at 42000000 {
-			compatible = "fsl,aips-bus", "simple-bus";
-			reg = <0x42000000 0x800000>;
-			#address-cells = <1>;
-			#size-cells = <1>;
-			ranges;
-
-			edma2: dma-controller at 42000000 {
-				compatible = "fsl,imx93-edma4";
-				reg = <0x42000000 0x210000>;
-				#dma-cells = <3>;
-				dma-channels = <64>;
-				interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_EDMA2_GATE>;
-				clock-names = "dma";
-			};
-
-			wakeupmix_gpr: syscon at 42420000 {
-				compatible = "fsl,imx93-wakeupmix-syscfg", "syscon";
-				reg = <0x42420000 0x1000>;
-			};
-
-			wdog3: watchdog at 42490000 {
-				compatible = "fsl,imx93-wdt";
-				reg = <0x42490000 0x10000>;
-				interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_WDOG3_GATE>;
-				timeout-sec = <40>;
-				status = "disabled";
-			};
-
-			wdog4: watchdog at 424a0000 {
-				compatible = "fsl,imx93-wdt";
-				reg = <0x424a0000 0x10000>;
-				interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_WDOG4_GATE>;
-				timeout-sec = <40>;
-				status = "disabled";
-			};
-
-			wdog5: watchdog at 424b0000 {
-				compatible = "fsl,imx93-wdt";
-				reg = <0x424b0000 0x10000>;
-				interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_WDOG5_GATE>;
-				timeout-sec = <40>;
-				status = "disabled";
-			};
-
-			tpm3: pwm at 424e0000 {
-				compatible = "fsl,imx7ulp-pwm";
-				reg = <0x424e0000 0x1000>;
-				clocks = <&clk IMX93_CLK_TPM3_GATE>;
-				#pwm-cells = <3>;
-				status = "disabled";
-			};
-
-			tpm4: pwm at 424f0000 {
-				compatible = "fsl,imx7ulp-pwm";
-				reg = <0x424f0000 0x10000>;
-				clocks = <&clk IMX93_CLK_TPM4_GATE>;
-				#pwm-cells = <3>;
-				status = "disabled";
-			};
-
-			tpm5: pwm at 42500000 {
-				compatible = "fsl,imx7ulp-pwm";
-				reg = <0x42500000 0x10000>;
-				clocks = <&clk IMX93_CLK_TPM5_GATE>;
-				#pwm-cells = <3>;
-				status = "disabled";
-			};
-
-			tpm6: pwm at 42510000 {
-				compatible = "fsl,imx7ulp-pwm";
-				reg = <0x42510000 0x10000>;
-				clocks = <&clk IMX93_CLK_TPM6_GATE>;
-				#pwm-cells = <3>;
-				status = "disabled";
-			};
-
-			i3c2: i3c at 42520000 {
-				compatible = "silvaco,i3c-master-v1";
-				reg = <0x42520000 0x10000>;
-				interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
-				#address-cells = <3>;
-				#size-cells = <0>;
-				clocks = <&clk IMX93_CLK_BUS_WAKEUP>,
-					 <&clk IMX93_CLK_I3C2_GATE>,
-					 <&clk IMX93_CLK_I3C2_SLOW>;
-				clock-names = "pclk", "fast_clk", "slow_clk";
-				status = "disabled";
-			};
-
-			lpi2c3: i2c at 42530000 {
-				compatible = "fsl,imx93-lpi2c", "fsl,imx7ulp-lpi2c";
-				reg = <0x42530000 0x10000>;
-				#address-cells = <1>;
-				#size-cells = <0>;
-				interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_LPI2C3_GATE>,
-					 <&clk IMX93_CLK_BUS_WAKEUP>;
-				clock-names = "per", "ipg";
-				dmas = <&edma2 8 0 0>, <&edma2 9 0 FSL_EDMA_RX>;
-				dma-names = "tx", "rx";
-				status = "disabled";
-			};
-
-			lpi2c4: i2c at 42540000 {
-				compatible = "fsl,imx93-lpi2c", "fsl,imx7ulp-lpi2c";
-				reg = <0x42540000 0x10000>;
-				#address-cells = <1>;
-				#size-cells = <0>;
-				interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_LPI2C4_GATE>,
-					 <&clk IMX93_CLK_BUS_WAKEUP>;
-				clock-names = "per", "ipg";
-				dmas = <&edma2 10 0 0>, <&edma2 11 0 FSL_EDMA_RX>;
-				dma-names = "tx", "rx";
-				status = "disabled";
-			};
-
-			lpspi3: spi at 42550000 {
-				#address-cells = <1>;
-				#size-cells = <0>;
-				compatible = "fsl,imx93-spi", "fsl,imx7ulp-spi";
-				reg = <0x42550000 0x10000>;
-				interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_LPSPI3_GATE>,
-					 <&clk IMX93_CLK_BUS_WAKEUP>;
-				clock-names = "per", "ipg";
-				dmas = <&edma2 12 0 0>, <&edma2 13 0 FSL_EDMA_RX>;
-				dma-names = "tx", "rx";
-				status = "disabled";
-			};
-
-			lpspi4: spi at 42560000 {
-				#address-cells = <1>;
-				#size-cells = <0>;
-				compatible = "fsl,imx93-spi", "fsl,imx7ulp-spi";
-				reg = <0x42560000 0x10000>;
-				interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_LPSPI4_GATE>,
-					 <&clk IMX93_CLK_BUS_WAKEUP>;
-				clock-names = "per", "ipg";
-				dmas = <&edma2 14 0 0>, <&edma2 15 0 FSL_EDMA_RX>;
-				dma-names = "tx", "rx";
-				status = "disabled";
-			};
-
-			lpuart3: serial at 42570000 {
-				compatible = "fsl,imx93-lpuart", "fsl,imx8ulp-lpuart", "fsl,imx7ulp-lpuart";
-				reg = <0x42570000 0x1000>;
-				interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_LPUART3_GATE>;
-				clock-names = "ipg";
-				dmas = <&edma2 18 0 FSL_EDMA_RX>, <&edma2 17 0 0>;
-				dma-names = "rx", "tx";
-				status = "disabled";
-			};
-
-			lpuart4: serial at 42580000 {
-				compatible = "fsl,imx93-lpuart", "fsl,imx8ulp-lpuart", "fsl,imx7ulp-lpuart";
-				reg = <0x42580000 0x1000>;
-				interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_LPUART4_GATE>;
-				clock-names = "ipg";
-				dmas = <&edma2 20 0 FSL_EDMA_RX>, <&edma2 19 0 0>;
-				dma-names = "rx", "tx";
-				status = "disabled";
-			};
-
-			lpuart5: serial at 42590000 {
-				compatible = "fsl,imx93-lpuart", "fsl,imx8ulp-lpuart", "fsl,imx7ulp-lpuart";
-				reg = <0x42590000 0x1000>;
-				interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_LPUART5_GATE>;
-				clock-names = "ipg";
-				dmas = <&edma2 22 0 FSL_EDMA_RX>, <&edma2 21 0 0>;
-				dma-names = "rx", "tx";
-				status = "disabled";
-			};
-
-			lpuart6: serial at 425a0000 {
-				compatible = "fsl,imx93-lpuart", "fsl,imx8ulp-lpuart", "fsl,imx7ulp-lpuart";
-				reg = <0x425a0000 0x1000>;
-				interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_LPUART6_GATE>;
-				clock-names = "ipg";
-				dmas = <&edma2 24 0 FSL_EDMA_RX>, <&edma2 23 0 0>;
-				dma-names = "rx", "tx";
-				status = "disabled";
-			};
-
-			flexcan2: can at 425b0000 {
-				compatible = "fsl,imx93-flexcan";
-				reg = <0x425b0000 0x10000>;
-				interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_BUS_WAKEUP>,
-					 <&clk IMX93_CLK_CAN2_GATE>;
-				clock-names = "ipg", "per";
-				assigned-clocks = <&clk IMX93_CLK_CAN2>;
-				assigned-clock-parents = <&clk IMX93_CLK_SYS_PLL_PFD1_DIV2>;
-				assigned-clock-rates = <40000000>;
-				fsl,clk-source = /bits/ 8 <0>;
-				fsl,stop-mode = <&wakeupmix_gpr 0x0c 2>;
-				status = "disabled";
-			};
-
-			flexspi1: spi at 425e0000 {
-				compatible = "nxp,imx93-fspi", "nxp,imx8mm-fspi";
-				reg = <0x425e0000 0x10000>, <0x28000000 0x10000000>;
-				reg-names = "fspi_base", "fspi_mmap";
-				#address-cells = <1>;
-				#size-cells = <0>;
-				interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_FLEXSPI1_GATE>,
-					 <&clk IMX93_CLK_FLEXSPI1_GATE>;
-				clock-names = "fspi_en", "fspi";
-				assigned-clocks = <&clk IMX93_CLK_FLEXSPI1>;
-				assigned-clock-parents = <&clk IMX93_CLK_SYS_PLL_PFD1>;
-				status = "disabled";
-			};
-
-			sai2: sai at 42650000 {
-				compatible = "fsl,imx93-sai";
-				reg = <0x42650000 0x10000>;
-				interrupts = <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_SAI2_IPG>, <&clk IMX93_CLK_DUMMY>,
-					 <&clk IMX93_CLK_SAI2_GATE>, <&clk IMX93_CLK_DUMMY>,
-					 <&clk IMX93_CLK_DUMMY>;
-				clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
-				dmas = <&edma2 59 0 FSL_EDMA_RX>, <&edma2 58 0 0>;
-				dma-names = "rx", "tx";
-				#sound-dai-cells = <0>;
-				status = "disabled";
-			};
-
-			sai3: sai at 42660000 {
-				compatible = "fsl,imx93-sai";
-				reg = <0x42660000 0x10000>;
-				interrupts = <GIC_SPI 171 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_SAI3_IPG>, <&clk IMX93_CLK_DUMMY>,
-					 <&clk IMX93_CLK_SAI3_GATE>, <&clk IMX93_CLK_DUMMY>,
-					 <&clk IMX93_CLK_DUMMY>;
-				clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
-				dmas = <&edma2 61 0 FSL_EDMA_RX>, <&edma2 60 0 0>;
-				dma-names = "rx", "tx";
-				#sound-dai-cells = <0>;
-				status = "disabled";
-			};
-
-			xcvr: xcvr at 42680000 {
-				compatible = "fsl,imx93-xcvr";
-				reg = <0x42680000 0x800>,
-				      <0x42680800 0x400>,
-				      <0x42680c00 0x080>,
-				      <0x42680e00 0x080>;
-				reg-names = "ram", "regs", "rxfifo", "txfifo";
-				interrupts = <GIC_SPI 203 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 204 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_SPDIF_IPG>,
-					 <&clk IMX93_CLK_SPDIF_GATE>,
-					 <&clk IMX93_CLK_DUMMY>,
-					 <&clk IMX93_CLK_AUD_XCVR_GATE>;
-				clock-names = "ipg", "phy", "spba", "pll_ipg";
-				dmas = <&edma2 65 0 FSL_EDMA_RX>, <&edma2 66 0 0>;
-				dma-names = "rx", "tx";
-				#sound-dai-cells = <0>;
-				status = "disabled";
-			};
-
-			lpuart7: serial at 42690000 {
-				compatible = "fsl,imx93-lpuart", "fsl,imx8ulp-lpuart", "fsl,imx7ulp-lpuart";
-				reg = <0x42690000 0x1000>;
-				interrupts = <GIC_SPI 210 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_LPUART7_GATE>;
-				clock-names = "ipg";
-				dmas = <&edma2 88 0 FSL_EDMA_RX>, <&edma2 87 0 0>;
-				dma-names = "rx", "tx";
-				status = "disabled";
-			};
-
-			lpuart8: serial at 426a0000 {
-				compatible = "fsl,imx93-lpuart", "fsl,imx8ulp-lpuart", "fsl,imx7ulp-lpuart";
-				reg = <0x426a0000 0x1000>;
-				interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_LPUART8_GATE>;
-				clock-names = "ipg";
-				dmas = <&edma2 90 0 FSL_EDMA_RX>, <&edma2 89 0 0>;
-				dma-names = "rx", "tx";
-				status = "disabled";
-			};
-
-			lpi2c5: i2c at 426b0000 {
-				compatible = "fsl,imx93-lpi2c", "fsl,imx7ulp-lpi2c";
-				reg = <0x426b0000 0x10000>;
-				#address-cells = <1>;
-				#size-cells = <0>;
-				interrupts = <GIC_SPI 195 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_LPI2C5_GATE>,
-					 <&clk IMX93_CLK_BUS_WAKEUP>;
-				clock-names = "per", "ipg";
-				dmas = <&edma2 71 0 0>, <&edma2 72 0 FSL_EDMA_RX>;
-				dma-names = "tx", "rx";
-				status = "disabled";
-			};
-
-			lpi2c6: i2c at 426c0000 {
-				compatible = "fsl,imx93-lpi2c", "fsl,imx7ulp-lpi2c";
-				reg = <0x426c0000 0x10000>;
-				#address-cells = <1>;
-				#size-cells = <0>;
-				interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_LPI2C6_GATE>,
-					 <&clk IMX93_CLK_BUS_WAKEUP>;
-				clock-names = "per", "ipg";
-				dmas = <&edma2 73 0 0>, <&edma2 74 0 FSL_EDMA_RX>;
-				dma-names = "tx", "rx";
-				status = "disabled";
-			};
-
-			lpi2c7: i2c at 426d0000 {
-				compatible = "fsl,imx93-lpi2c", "fsl,imx7ulp-lpi2c";
-				reg = <0x426d0000 0x10000>;
-				#address-cells = <1>;
-				#size-cells = <0>;
-				interrupts = <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_LPI2C7_GATE>,
-					 <&clk IMX93_CLK_BUS_WAKEUP>;
-				clock-names = "per", "ipg";
-				dmas = <&edma2 75 0 0>, <&edma2 76 0 FSL_EDMA_RX>;
-				dma-names = "tx", "rx";
-				status = "disabled";
-			};
-
-			lpi2c8: i2c at 426e0000 {
-				compatible = "fsl,imx93-lpi2c", "fsl,imx7ulp-lpi2c";
-				reg = <0x426e0000 0x10000>;
-				#address-cells = <1>;
-				#size-cells = <0>;
-				interrupts = <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_LPI2C8_GATE>,
-					 <&clk IMX93_CLK_BUS_WAKEUP>;
-				clock-names = "per", "ipg";
-				dmas = <&edma2 77 0 0>, <&edma2 78 0 FSL_EDMA_RX>;
-				dma-names = "tx", "rx";
-				status = "disabled";
-			};
-
-			lpspi5: spi at 426f0000 {
-				#address-cells = <1>;
-				#size-cells = <0>;
-				compatible = "fsl,imx93-spi", "fsl,imx7ulp-spi";
-				reg = <0x426f0000 0x10000>;
-				interrupts = <GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_LPSPI5_GATE>,
-					 <&clk IMX93_CLK_BUS_WAKEUP>;
-				clock-names = "per", "ipg";
-				dmas = <&edma2 79 0 0>, <&edma2 80 0 FSL_EDMA_RX>;
-				dma-names = "tx", "rx";
-				status = "disabled";
-			};
-
-			lpspi6: spi at 42700000 {
-				#address-cells = <1>;
-				#size-cells = <0>;
-				compatible = "fsl,imx93-spi", "fsl,imx7ulp-spi";
-				reg = <0x42700000 0x10000>;
-				interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_LPSPI6_GATE>,
-					 <&clk IMX93_CLK_BUS_WAKEUP>;
-				clock-names = "per", "ipg";
-				dmas = <&edma2 81 0 0>, <&edma2 82 0 FSL_EDMA_RX>;
-				dma-names = "tx", "rx";
-				status = "disabled";
-			};
-
-			lpspi7: spi at 42710000 {
-				#address-cells = <1>;
-				#size-cells = <0>;
-				compatible = "fsl,imx93-spi", "fsl,imx7ulp-spi";
-				reg = <0x42710000 0x10000>;
-				interrupts = <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_LPSPI7_GATE>,
-					 <&clk IMX93_CLK_BUS_WAKEUP>;
-				clock-names = "per", "ipg";
-				dmas = <&edma2 83 0 0>, <&edma2 84 0 FSL_EDMA_RX>;
-				dma-names = "tx", "rx";
-				status = "disabled";
-			};
-
-			lpspi8: spi at 42720000 {
-				#address-cells = <1>;
-				#size-cells = <0>;
-				compatible = "fsl,imx93-spi", "fsl,imx7ulp-spi";
-				reg = <0x42720000 0x10000>;
-				interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_LPSPI8_GATE>,
-					 <&clk IMX93_CLK_BUS_WAKEUP>;
-				clock-names = "per", "ipg";
-				dmas = <&edma2 85 0 0>, <&edma2 86 0 FSL_EDMA_RX>;
-				dma-names = "tx", "rx";
-				status = "disabled";
-			};
-
-		};
-
-		aips3: bus at 42800000 {
-			compatible = "fsl,aips-bus", "simple-bus";
-			reg = <0x42800000 0x800000>;
-			#address-cells = <1>;
-			#size-cells = <1>;
-			ranges;
-
-			usdhc1: mmc at 42850000 {
-				compatible = "fsl,imx93-usdhc", "fsl,imx8mm-usdhc";
-				reg = <0x42850000 0x10000>;
-				interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_BUS_WAKEUP>,
-					 <&clk IMX93_CLK_WAKEUP_AXI>,
-					 <&clk IMX93_CLK_USDHC1_GATE>;
-				clock-names = "ipg", "ahb", "per";
-				assigned-clocks = <&clk IMX93_CLK_USDHC1>;
-				assigned-clock-parents = <&clk IMX93_CLK_SYS_PLL_PFD1>;
-				assigned-clock-rates = <400000000>;
-				bus-width = <8>;
-				fsl,tuning-start-tap = <1>;
-				fsl,tuning-step = <2>;
-				status = "disabled";
-			};
-
-			usdhc2: mmc at 42860000 {
-				compatible = "fsl,imx93-usdhc", "fsl,imx8mm-usdhc";
-				reg = <0x42860000 0x10000>;
-				interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_BUS_WAKEUP>,
-					 <&clk IMX93_CLK_WAKEUP_AXI>,
-					 <&clk IMX93_CLK_USDHC2_GATE>;
-				clock-names = "ipg", "ahb", "per";
-				assigned-clocks = <&clk IMX93_CLK_USDHC2>;
-				assigned-clock-parents = <&clk IMX93_CLK_SYS_PLL_PFD1>;
-				assigned-clock-rates = <400000000>;
-				bus-width = <4>;
-				fsl,tuning-start-tap = <1>;
-				fsl,tuning-step = <2>;
-				status = "disabled";
-			};
-
-			fec: ethernet at 42890000 {
-				compatible = "fsl,imx93-fec", "fsl,imx8mq-fec", "fsl,imx6sx-fec";
-				reg = <0x42890000 0x10000>;
-				interrupts = <GIC_SPI 179 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 181 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 182 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_ENET1_GATE>,
-					 <&clk IMX93_CLK_ENET1_GATE>,
-					 <&clk IMX93_CLK_ENET_TIMER1>,
-					 <&clk IMX93_CLK_ENET_REF>,
-					 <&clk IMX93_CLK_ENET_REF_PHY>;
-				clock-names = "ipg", "ahb", "ptp",
-					      "enet_clk_ref", "enet_out";
-				assigned-clocks = <&clk IMX93_CLK_ENET_TIMER1>,
-						  <&clk IMX93_CLK_ENET_REF>,
-						  <&clk IMX93_CLK_ENET_REF_PHY>;
-				assigned-clock-parents = <&clk IMX93_CLK_SYS_PLL_PFD1_DIV2>,
-							 <&clk IMX93_CLK_SYS_PLL_PFD0_DIV2>,
-							 <&clk IMX93_CLK_SYS_PLL_PFD1_DIV2>;
-				assigned-clock-rates = <100000000>, <250000000>, <50000000>;
-				fsl,num-tx-queues = <3>;
-				fsl,num-rx-queues = <3>;
-				fsl,stop-mode = <&wakeupmix_gpr 0x0c 1>;
-				nvmem-cells = <&eth_mac1>;
-				nvmem-cell-names = "mac-address";
-				status = "disabled";
-			};
-
-			eqos: ethernet at 428a0000 {
-				compatible = "nxp,imx93-dwmac-eqos", "snps,dwmac-5.10a";
-				reg = <0x428a0000 0x10000>;
-				interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 183 IRQ_TYPE_LEVEL_HIGH>;
-				interrupt-names = "macirq", "eth_wake_irq";
-				clocks = <&clk IMX93_CLK_ENET_QOS_GATE>,
-					 <&clk IMX93_CLK_ENET_QOS_GATE>,
-					 <&clk IMX93_CLK_ENET_TIMER2>,
-					 <&clk IMX93_CLK_ENET>,
-					 <&clk IMX93_CLK_ENET_QOS_GATE>;
-				clock-names = "stmmaceth", "pclk", "ptp_ref", "tx", "mem";
-				assigned-clocks = <&clk IMX93_CLK_ENET_TIMER2>,
-						  <&clk IMX93_CLK_ENET>;
-				assigned-clock-parents = <&clk IMX93_CLK_SYS_PLL_PFD1_DIV2>,
-							 <&clk IMX93_CLK_SYS_PLL_PFD0_DIV2>;
-				assigned-clock-rates = <100000000>, <250000000>;
-				intf_mode = <&wakeupmix_gpr 0x28>;
-				snps,clk-csr = <6>;
-				nvmem-cells = <&eth_mac2>;
-				nvmem-cell-names = "mac-address";
-				status = "disabled";
-			};
-
-			usdhc3: mmc at 428b0000 {
-				compatible = "fsl,imx93-usdhc", "fsl,imx8mm-usdhc";
-				reg = <0x428b0000 0x10000>;
-				interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX93_CLK_BUS_WAKEUP>,
-					 <&clk IMX93_CLK_WAKEUP_AXI>,
-					 <&clk IMX93_CLK_USDHC3_GATE>;
-				clock-names = "ipg", "ahb", "per";
-				assigned-clocks = <&clk IMX93_CLK_USDHC3>;
-				assigned-clock-parents = <&clk IMX93_CLK_SYS_PLL_PFD1>;
-				assigned-clock-rates = <400000000>;
-				bus-width = <4>;
-				fsl,tuning-start-tap = <1>;
-				fsl,tuning-step = <2>;
-				status = "disabled";
-			};
-		};
-
-		gpio2: gpio at 43810000 {
-			compatible = "fsl,imx93-gpio", "fsl,imx8ulp-gpio";
-			reg = <0x43810000 0x1000>;
-			gpio-controller;
-			#gpio-cells = <2>;
-			interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
-			interrupt-controller;
-			#interrupt-cells = <2>;
-			clocks = <&clk IMX93_CLK_GPIO2_GATE>,
-				 <&clk IMX93_CLK_GPIO2_GATE>;
-			clock-names = "gpio", "port";
-			gpio-ranges = <&iomuxc 0 4 30>;
-			ngpios = <30>;
-		};
-
-		gpio3: gpio at 43820000 {
-			compatible = "fsl,imx93-gpio", "fsl,imx8ulp-gpio";
-			reg = <0x43820000 0x1000>;
-			gpio-controller;
-			#gpio-cells = <2>;
-			interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
-			interrupt-controller;
-			#interrupt-cells = <2>;
-			clocks = <&clk IMX93_CLK_GPIO3_GATE>,
-				 <&clk IMX93_CLK_GPIO3_GATE>;
-			clock-names = "gpio", "port";
-			gpio-ranges = <&iomuxc 0 84 8>, <&iomuxc 8 66 18>,
-				      <&iomuxc 26 34 2>, <&iomuxc 28 0 4>;
-			ngpios = <32>;
-		};
-
-		gpio4: gpio at 43830000 {
-			compatible = "fsl,imx93-gpio", "fsl,imx8ulp-gpio";
-			reg = <0x43830000 0x1000>;
-			gpio-controller;
-			#gpio-cells = <2>;
-			interrupts = <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>;
-			interrupt-controller;
-			#interrupt-cells = <2>;
-			clocks = <&clk IMX93_CLK_GPIO4_GATE>,
-				 <&clk IMX93_CLK_GPIO4_GATE>;
-			clock-names = "gpio", "port";
-			gpio-ranges = <&iomuxc 0 38 28>, <&iomuxc 28 36 2>;
-			ngpios = <30>;
-		};
-
-		gpio1: gpio at 47400000 {
-			compatible = "fsl,imx93-gpio", "fsl,imx8ulp-gpio";
-			reg = <0x47400000 0x1000>;
-			gpio-controller;
-			#gpio-cells = <2>;
-			interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
-			interrupt-controller;
-			#interrupt-cells = <2>;
-			clocks = <&clk IMX93_CLK_GPIO1_GATE>,
-				 <&clk IMX93_CLK_GPIO1_GATE>;
-			clock-names = "gpio", "port";
-			gpio-ranges = <&iomuxc 0 92 16>;
-			ngpios = <16>;
-		};
-
-		ocotp: efuse at 47510000 {
-			compatible = "fsl,imx93-ocotp", "syscon";
-			reg = <0x47510000 0x10000>;
-			#address-cells = <1>;
-			#size-cells = <1>;
-
-			eth_mac1: mac-address at 4ec {
-				reg = <0x4ec 0x6>;
-			};
-
-			eth_mac2: mac-address at 4f2 {
-				reg = <0x4f2 0x6>;
-			};
-
-		};
-
-		s4muap: mailbox at 47520000 {
-			compatible = "fsl,imx93-mu-s4";
-			reg = <0x47520000 0x10000>;
-			interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
-			interrupt-names = "tx", "rx";
-			#mbox-cells = <2>;
-		};
-
-		media_blk_ctrl: system-controller at 4ac10000 {
-			compatible = "fsl,imx93-media-blk-ctrl", "syscon";
-			reg = <0x4ac10000 0x10000>;
-			power-domains = <&mediamix>;
-			clocks = <&clk IMX93_CLK_MEDIA_APB>,
-				 <&clk IMX93_CLK_MEDIA_AXI>,
-				 <&clk IMX93_CLK_NIC_MEDIA_GATE>,
-				 <&clk IMX93_CLK_MEDIA_DISP_PIX>,
-				 <&clk IMX93_CLK_CAM_PIX>,
-				 <&clk IMX93_CLK_PXP_GATE>,
-				 <&clk IMX93_CLK_LCDIF_GATE>,
-				 <&clk IMX93_CLK_ISI_GATE>,
-				 <&clk IMX93_CLK_MIPI_CSI_GATE>,
-				 <&clk IMX93_CLK_MIPI_DSI_GATE>;
-			clock-names = "apb", "axi", "nic", "disp", "cam",
-				      "pxp", "lcdif", "isi", "csi", "dsi";
-			#power-domain-cells = <1>;
-			status = "disabled";
-		};
-
-		usbotg1: usb at 4c100000 {
-			compatible = "fsl,imx93-usb", "fsl,imx7d-usb", "fsl,imx27-usb";
-			reg = <0x4c100000 0x200>;
-			interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&clk IMX93_CLK_USB_CONTROLLER_GATE>,
-				 <&clk IMX93_CLK_HSIO_32K_GATE>;
-			clock-names = "usb_ctrl_root", "usb_wakeup";
-			assigned-clocks = <&clk IMX93_CLK_HSIO>;
-			assigned-clock-parents = <&clk IMX93_CLK_SYS_PLL_PFD1_DIV2>;
-			assigned-clock-rates = <133000000>;
-			phys = <&usbphynop1>;
-			fsl,usbmisc = <&usbmisc1 0>;
-			status = "disabled";
-		};
-
-		usbmisc1: usbmisc at 4c100200 {
-			compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc",
-				     "fsl,imx6q-usbmisc";
-			reg = <0x4c100200 0x200>;
-			#index-cells = <1>;
-		};
-
-		usbotg2: usb at 4c200000 {
-			compatible = "fsl,imx93-usb", "fsl,imx7d-usb", "fsl,imx27-usb";
-			reg = <0x4c200000 0x200>;
-			interrupts = <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&clk IMX93_CLK_USB_CONTROLLER_GATE>,
-				 <&clk IMX93_CLK_HSIO_32K_GATE>;
-			clock-names = "usb_ctrl_root", "usb_wakeup";
-			assigned-clocks = <&clk IMX93_CLK_HSIO>;
-			assigned-clock-parents = <&clk IMX93_CLK_SYS_PLL_PFD1_DIV2>;
-			assigned-clock-rates = <133000000>;
-			phys = <&usbphynop2>;
-			fsl,usbmisc = <&usbmisc2 0>;
-			status = "disabled";
-		};
-
-		usbmisc2: usbmisc at 4c200200 {
-			compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc",
-				     "fsl,imx6q-usbmisc";
-			reg = <0x4c200200 0x200>;
-			#index-cells = <1>;
-		};
-
-		memory-controller at 4e300000 {
-			compatible = "nxp,imx9-memory-controller";
-			reg = <0x4e300000 0x800>, <0x4e301000 0x1000>;
-			reg-names = "ctrl", "inject";
-			interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
-			little-endian;
-		};
-
-		ddr_pmu: ddr-pmu at 4e300dc0 {
-			compatible = "fsl,imx93-ddr-pmu";
-			reg = <0x4e300dc0 0x200>;
-			interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>;
-		};
-	};
-};
diff --git a/arch/arm64/boot/dts/freescale/imx93.dtsi b/arch/arm64/boot/dts/freescale/imx93.dtsi
index 7b27012dfcb564650882dc8c40e836e797b2fda1..14bb3b419c565fbc48e5ef9f069ec7cb9116929e 100644
--- a/arch/arm64/boot/dts/freescale/imx93.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx93.dtsi
@@ -3,7 +3,7 @@
  * Copyright 2022,2025 NXP
  */
 
-#include "imx91_93_common.dtsi"
+#include "imx91-93-common.dtsi"
 
 /{
 	cm33: remoteproc-cm33 {

-- 
2.37.1



From peng.fan at oss.nxp.com  Fri Dec 12 01:16:10 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Fri, 12 Dec 2025 17:16:10 +0800
Subject: [PATCH 4/4] arm64: dts: imx91-11x11-evk: Add gpio4 alias
In-Reply-To: <20251212-imx91-dts-v1-0-2bb3c13762dd@nxp.com>
References: <20251212-imx91-dts-v1-0-2bb3c13762dd@nxp.com>
Message-ID: <20251212-imx91-dts-v1-4-2bb3c13762dd@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

gpio4 is default enabled in imx91-93-common.dtsi, so add the alias for
gpio4.

Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts b/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
index aca78768dbd4bf30d9d6ae4a1cc37a29256d8f97..a2cad45432b3a8e34e365530da8edf3a89503f22 100644
--- a/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
@@ -18,6 +18,7 @@ aliases {
 		gpio0 = &gpio1;
 		gpio1 = &gpio2;
 		gpio2 = &gpio3;
+		gpio3 = &gpio4;
 		i2c0 = &lpi2c1;
 		i2c1 = &lpi2c2;
 		i2c2 = &lpi2c3;

-- 
2.37.1



From mripard at kernel.org  Fri Dec 12 01:19:13 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Fri, 12 Dec 2025 10:19:13 +0100
Subject: [PATCH v5 17/17] drm/tests: hdmi: Add tests for the color_format
 property
In-Reply-To: <20251128-color-format-v5-17-63e82f1db1e1@collabora.com>
References: <20251128-color-format-v5-0-63e82f1db1e1@collabora.com>
 <20251128-color-format-v5-17-63e82f1db1e1@collabora.com>
Message-ID: <20251212-discreet-wisteria-perch-edccad@penduick>

On Fri, Nov 28, 2025 at 10:05:53PM +0100, Nicolas Frattaroli wrote:
> Add some KUnit tests to check the color_format property is working as
> expected with the HDMI state helper.
> 
> The added tests check that AUTO results in RGB, and the YCBCR modes
> result in the corresponding YUV modes. An additional test ensures that
> only DRM_COLOR_FORMAT_AUTO falls back to YUV420 with a YUV420-only mode,
> and RGB errors out instead, while explicitly asking for YUV420 still
> works.
> 
> This requires exporting hdmi_compute_config, so that it is accessible
> from the tests.
> 
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
> ---
>  drivers/gpu/drm/display/drm_hdmi_state_helper.c    |   3 +-
>  drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 109 +++++++++++++++++++++
>  include/drm/display/drm_hdmi_state_helper.h        |   4 +
>  3 files changed, 115 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> index 1800e00b30c5..e86fb837ceaf 100644
> --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> @@ -641,7 +641,7 @@ hdmi_compute_format_bpc(const struct drm_connector *connector,
>  	return -EINVAL;
>  }
>  
> -static int
> +int
>  hdmi_compute_config(const struct drm_connector *connector,
>  		    struct drm_connector_state *conn_state,
>  		    const struct drm_display_mode *mode)
> @@ -680,6 +680,7 @@ hdmi_compute_config(const struct drm_connector *connector,
>  
>  	return ret;
>  }
> +EXPORT_SYMBOL(hdmi_compute_config);

I don't think we need to export hdmi_compute_config directly, and if we
do, it shouldn't be named that way.

The rest of the tests in the suite manage to test everything fine
without exporting it. Is there any reason you can't do it for these
tests?

>  static int hdmi_generate_avi_infoframe(const struct drm_connector *connector,
>  				       struct drm_connector_state *conn_state)
> diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
> index 8bd412735000..e7050cd9cb12 100644
> --- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
> +++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
> @@ -55,6 +55,23 @@ static struct drm_display_mode *find_preferred_mode(struct drm_connector *connec
>  	return preferred;
>  }
>  
> +static struct drm_display_mode *find_420_only_mode(struct drm_connector *connector)
> +{
> +	struct drm_device *drm = connector->dev;
> +	struct drm_display_mode *mode;
> +
> +	mutex_lock(&drm->mode_config.mutex);
> +	list_for_each_entry(mode, &connector->modes, head) {
> +		if (drm_mode_is_420_only(&connector->display_info, mode)) {
> +			mutex_unlock(&drm->mode_config.mutex);
> +			return mode;
> +		}
> +	}
> +	mutex_unlock(&drm->mode_config.mutex);
> +
> +	return NULL;
> +}
> +
>  static int set_connector_edid(struct kunit *test, struct drm_connector *connector,
>  			      const void *edid, size_t edid_len)
>  {
> @@ -1999,6 +2016,95 @@ static void drm_test_check_disable_connector(struct kunit *test)
>  	drm_modeset_acquire_fini(&ctx);
>  }
>  
> +struct color_format_test_param {
> +	enum drm_color_format fmt;
> +	enum hdmi_colorspace expected;
> +	const char *desc;
> +};
> +
> +/* Test that AUTO results in RGB, and explicit choices result in those */

We need a bit more details. Which EDID are you using, with which monitor
capabilities?

IIRC, we already have tests to make sure that the fallback happens and
only when it's supposed to. We just need to make sure we have asserts on
the property being auto for those.

This means we only need to test the !auto values, but we need to test it
both ways: that when the property is set and the display supports it,
the format chosen is indeed the one we asked for, but also that when the
property is set but the display doesn't support it, we get an error.

> +static void drm_test_check_hdmi_color_format(struct kunit *test)
> +{
> +	const struct color_format_test_param *param = test->param_value;
> +	struct drm_atomic_helper_connector_hdmi_priv *priv;
> +	struct drm_connector_state *conn_state;
> +	struct drm_display_info *info;
> +	struct drm_display_mode *preferred;
> +	int ret;
> +
> +	priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
> +				BIT(HDMI_COLORSPACE_RGB) |
> +				BIT(HDMI_COLORSPACE_YUV422) |
> +				BIT(HDMI_COLORSPACE_YUV420) |
> +				BIT(HDMI_COLORSPACE_YUV444),
> +				12,
> +				&dummy_connector_hdmi_funcs,
> +				test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz);
> +	KUNIT_ASSERT_NOT_NULL(test, priv);
> +
> +	conn_state = priv->connector.state;
> +	info = &priv->connector.display_info;
> +	conn_state->color_format = param->fmt;
> +	KUNIT_ASSERT_TRUE(test, priv->connector.ycbcr_420_allowed);
> +
> +	preferred = find_preferred_mode(&priv->connector);
> +	KUNIT_ASSERT_TRUE(test, drm_mode_is_420(info, preferred));
> +
> +	ret = hdmi_compute_config(&priv->connector, conn_state, preferred);
> +	KUNIT_EXPECT_EQ(test, ret, 0);
> +	KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, param->expected);
> +}
> +
> +static const struct color_format_test_param hdmi_color_format_params[] = {
> +	{ DRM_COLOR_FORMAT_AUTO, HDMI_COLORSPACE_RGB, "AUTO -> RGB" },
> +	{ DRM_COLOR_FORMAT_YCBCR422, HDMI_COLORSPACE_YUV422, "YCBCR422 -> YUV422" },
> +	{ DRM_COLOR_FORMAT_YCBCR420, HDMI_COLORSPACE_YUV420, "YCBCR420 -> YUV420" },
> +	{ DRM_COLOR_FORMAT_YCBCR444, HDMI_COLORSPACE_YUV444, "YCBCR444 -> YUV444" },
> +	{ DRM_COLOR_FORMAT_RGB444, HDMI_COLORSPACE_RGB, "RGB -> RGB" },
> +};
> +
> +KUNIT_ARRAY_PARAM_DESC(check_hdmi_color_format,
> +		  hdmi_color_format_params, desc);
> +
> +
> +/* Test that AUTO falls back to YUV420, and that RGB does not, but YUV420 works */

Same thing, the description needs to be improved here.

Maxime
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 273 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251212/754cf3ff/attachment.sig>

From mripard at kernel.org  Fri Dec 12 01:20:00 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Fri, 12 Dec 2025 10:20:00 +0100
Subject: [PATCH v5 05/17] drm/display: hdmi-state-helper: Act on color
 format DRM property
In-Reply-To: <3084118.iZASKD2KPV@workhorse>
References: <20251128-color-format-v5-0-63e82f1db1e1@collabora.com>
 <20251128-color-format-v5-5-63e82f1db1e1@collabora.com>
 <20251209-uptight-radical-chupacabra-ac3d6d@houat>
 <3084118.iZASKD2KPV@workhorse>
Message-ID: <20251212-chubby-optimistic-goldfish-aece5f@penduick>

On Thu, Dec 11, 2025 at 08:42:00PM +0100, Nicolas Frattaroli wrote:
> On Tuesday, 9 December 2025 15:16:58 Central European Standard Time Maxime Ripard wrote:
> > On Fri, Nov 28, 2025 at 10:05:41PM +0100, Nicolas Frattaroli wrote:
> > > With the introduction of the "color format" DRM property, which allows
> > > userspace to request a specific color format, the HDMI state helper
> > > should implement this.
> > > 
> > > Implement it by checking whether the property is set and set to
> > > something other than auto. If so, pass the requested color format, and
> > > otherwise set RGB.
> > > 
> > > Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
> > > ---
> > >  drivers/gpu/drm/display/drm_hdmi_state_helper.c | 12 +++++++++++-
> > >  1 file changed, 11 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> > > index a561f124be99..5da956bdd68c 100644
> > > --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> > > +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> > > @@ -649,11 +649,21 @@ hdmi_compute_config(const struct drm_connector *connector,
> > >  	unsigned int max_bpc = clamp_t(unsigned int,
> > >  				       conn_state->max_bpc,
> > >  				       8, connector->max_bpc);
> > > +	enum hdmi_colorspace hdmi_colorspace =
> > > +		drm_color_format_to_hdmi_colorspace(conn_state->color_format);
> > >  	int ret;
> > >  
> > >  	ret = hdmi_compute_format_bpc(connector, conn_state, mode, max_bpc,
> > > -				      HDMI_COLORSPACE_RGB);
> > > +				      hdmi_colorspace);
> > >  	if (ret) {
> > > +		/* If a color format was explicitly requested, don't fall back */
> > > +		if (conn_state->color_format) {
> > > +			drm_dbg_kms(connector->dev,
> > > +				    "Explicitly set color format '%s' doesn't work.\n",
> > > +				    drm_get_color_format_name(conn_state->color_format));
> > > +			return ret;
> > > +		}
> > > +
> > 
> > I think the following would be more readable:
> > 
> > 
> > if (conn_state->color_format && conn_state->color_format != DRM_COLOR_FORMAT_AUTO) {
> >     enum hdmi_colorspace hdmi_colorspace =
> >         drm_color_format_to_hdmi_colorspace(conn_state->color_format);
> > 
> >     return hdmi_compute_format_bpc(connector, conn_state, mode, max_bpc, hdmi_colorspace)
> > }
> > 
> > ret = ret = hdmi_compute_format_bpc(connector, conn_state, mode, max_bpc,
> >                                     HDMI_COLORSPACE_RGB);
> > 
> > ...
> 
> I think I get what you mean: if conn_state->color_format is set, return
> directly, instead of bailing out in the fallback path. I can do that.

Yes

> However, `conn_state->color_format && conn_state->color_format != DRM_COLOR_FORMAT_AUTO`
> is redundant now as of v5 since DRM_COLOR_FORMAT_AUTO is 0 (and
> I use its falsy nature in many other places, and don't intend to
> stop doing that).

Ok, that makes sense.

Maxime
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 273 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251212/67f4d9a2/attachment-0001.sig>

From yuzenghui at huawei.com  Fri Dec 12 01:21:55 2025
From: yuzenghui at huawei.com (Zenghui Yu)
Date: Fri, 12 Dec 2025 17:21:55 +0800
Subject: [PATCH v4 2/3] KVM: selftests: Test for KVM_EXIT_ARM_SEA
In-Reply-To: <CACw3F51mRXCDz7Hd4Vve98NoskhB2cSc88zAGfd6Hwr4uCBxPA@mail.gmail.com>
References: <20251013185903.1372553-1-jiaqiyan@google.com>
 <20251013185903.1372553-3-jiaqiyan@google.com>
 <3061f5f8-cef0-b7b1-c4de-f2ceea29af9a@huawei.com>
 <CACw3F51mRXCDz7Hd4Vve98NoskhB2cSc88zAGfd6Hwr4uCBxPA@mail.gmail.com>
Message-ID: <dbcfb853-5853-5967-1bf9-76c6b3839717@huawei.com>

On 2025/12/12 9:53, Jiaqi Yan wrote:
> On Thu, Dec 11, 2025 at 5:02?AM Zenghui Yu <yuzenghui at huawei.com> wrote:
> >
> > I can also hit this ASSERT with:
> >
> > Random seed: 0x6b8b4567
> > # Mapped 0x40000 pages: gva=0x80000000 to gpa=0xff80000000
> > # Before EINJect: data=0xbaadcafe
> > # EINJ_GVA=0x81234bad, einj_gpa=0xff81234bad, einj_hva=0xffff41234bad,
> > einj_hpa=0x2841234bad
> > # echo 0x10 > /sys/kernel/debug/apei/einj/error_type - done
> > # echo 0x2 > /sys/kernel/debug/apei/einj/flags - done
> > # echo 0x2841234bad > /sys/kernel/debug/apei/einj/param1 - done
> > # echo 0xffffffffffffffff > /sys/kernel/debug/apei/einj/param2 - done
> > # echo 0x1 > /sys/kernel/debug/apei/einj/notrigger - done
> > # echo 0x1 > /sys/kernel/debug/apei/einj/error_inject - done
> > # Memory UER EINJected
> > # Dump kvm_run info about KVM_EXIT_MMIO
> > # kvm_run.arm_sea: esr=0xffff90ba0040, flags=0x691000
> > # kvm_run.arm_sea: gva=0x100000008, gpa=0
> > ==== Test Assertion Failure ====
> >   arm64/sea_to_user.c:207: exit_reason == (41)
> >   pid=38023 tid=38023 errno=4 - Interrupted system call
> >      1  0x0000000000402d1b: run_vm at sea_to_user.c:207
> >      2  0x0000000000402467: main at sea_to_user.c:330
> >      3  0x0000ffff9122b03f: ?? ??:0
> >      4  0x0000ffff9122b117: ?? ??:0
> >      5  0x00000000004026ef: _start at ??:?
> >   Wanted KVM exit reason: 41 (ARM_SEA), got: 6 (MMIO)
> >
> > Not sure what's wrong it..
> 
> Does your test machine have SDEI or SCI enabled for host APEI? Do you
> see any kernel log from "Memory failure:" saying hugetlb page
> recovered, and recovered significant earlier than the KVM exit here.
> It maybe the kernel has already unmapped hugepage in response to SDEI
> or SCI before this test actually consumes memory error, so no SEA is
> actually triggered.

No kernel log was printed when I saw this failure.

Thanks,
Zenghui


From zhenglifeng1 at huawei.com  Fri Dec 12 01:27:09 2025
From: zhenglifeng1 at huawei.com (zhenglifeng (A))
Date: Fri, 12 Dec 2025 17:27:09 +0800
Subject: [PATCH v6 0/3] arm64: topology: Handle AMU FIE setup on CPU
 hotplug
In-Reply-To: <aS8GZOuaS1-j14MD@arm.com>
References: <20251119081356.2495290-1-zhenglifeng1@huawei.com>
 <aS2z0EURwHbbGZab@arm.com> <9b6882dc-a91a-42d6-bf76-347338930d71@huawei.com>
 <aS8GZOuaS1-j14MD@arm.com>
Message-ID: <29253319-ced9-4ab6-a58e-28afdf235cde@huawei.com>

On 2025/12/2 23:31, Beata Michalska wrote:
> On Tue, Dec 02, 2025 at 11:05:25AM +0800, zhenglifeng (A) wrote:
>> On 2025/12/1 23:27, Beata Michalska wrote:
>>> Hi,
>>>
>>> Apologies for the delay in reviewing this - currently in progress....
>>> Out of curiosity: what's the cpufreq driver used for testing this series ?
>>
>> I used cppc_cpufreq for testing this. But with some modifications in
>> processor_driver.c, or you'll find that the driver will fail to load with
>> maxcpus set. The modification below is only a temporary solution. I'm still
>> working on that.
>>
> Right, so overall the implementation looks good - thanks for that.
> There are two issues though with the cppc cpufreq driver.
> 
> One: as you have already noticed - it fails to register when
> cpumask_present != cpumask_online.
> 
> Second: it will mix the sources of the freq scale if not all CPUs within the
> policy have AMUs enabled/valid. This is due to the fact that at the time of
> registering the driver and initializing the FIE support policy->cpus ==
> policy->related_cpus. Assuming scenario when there are two CPUs within the
> policy, one being offline and missing valid AMU counters,
> the topology_set_scale_freq_source from cppc cpufreq driver will register
> the tick handler for both CPUs, whereas AMU support will (rightly so) register
> only for the firs one. When the second CPU comes online, the mismatch will be
> detected and the arch callback will get cleared for the first CPU, but the
> second one will remain unchanged.
> 
> That said, I do not think any of those issues is a blocker for this series.
> But both would need fixing.

Hi Catalin,

I believe Beata is OK with this series. So I think we can move ahead with it
now.

Thanks.

> 
> ---
> BR
> Beata
> 
> 
>> ---
>> diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
>> index 5d824435b26b..2f286a1b0b02 100644
>> --- a/drivers/acpi/processor_driver.c
>> +++ b/drivers/acpi/processor_driver.c
>> @@ -33,6 +33,7 @@ MODULE_AUTHOR("Paul Diefenbaugh");
>>  MODULE_DESCRIPTION("ACPI Processor Driver");
>>  MODULE_LICENSE("GPL");
>>  
>> +static int acpi_processor_start(struct device *dev);
>>  static int acpi_processor_stop(struct device *dev);
>>  
>>  static const struct acpi_device_id processor_device_ids[] = {
>> @@ -46,6 +47,7 @@ static struct device_driver acpi_processor_driver = {
>>  	.name = "processor",
>>  	.bus = &cpu_subsys,
>>  	.acpi_match_table = processor_device_ids,
>> +	.probe = acpi_processor_start,
>>  	.remove = acpi_processor_stop,
>>  };
>>  
>> @@ -191,6 +193,21 @@ static int __acpi_processor_start(struct acpi_device *device)
>>  	return result;
>>  }
>>  
>> +static int acpi_processor_start(struct device *dev)
>> +{
>> +	struct acpi_device *device = ACPI_COMPANION(dev);
>> +	int ret;
>> +
>> +	if (!device)
>> +		return -ENODEV;
>> +
>> +	/* Protect against concurrent CPU hotplug operations */
>> +	cpu_hotplug_disable();
>> +	ret = __acpi_processor_start(device);
>> +	cpu_hotplug_enable();
>> +	return ret;
>> +}
>> +
>>  static int acpi_processor_stop(struct device *dev)
>>  {
>>  	struct acpi_device *device = ACPI_COMPANION(dev);
>> @@ -264,9 +281,9 @@ static int __init acpi_processor_driver_init(void)
>>  
>>  	acpi_processor_register_idle_driver();
>>  
>> -	result = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
>> -				   "acpi/cpu-drv:online",
>> -				   acpi_soft_cpu_online, NULL);
>> +	result = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
>> +					   "acpi/cpu-drv:online",
>> +					   acpi_soft_cpu_online, NULL);
>>  	if (result < 0)
>>  		goto err;
>>  	hp_online = result;
>>
>>>
>>> ---
>>> BR
>>> Beata
>>> On Wed, Nov 19, 2025 at 04:13:53PM +0800, Lifeng Zheng wrote:
>>>> Solve a problem that causes CPUs Setup AMU FIE failed in a corner case,
>>>> even though they're eligible.
>>>>
>>>>
>>>
>>
> 



From maz at kernel.org  Fri Dec 12 01:28:33 2025
From: maz at kernel.org (Marc Zyngier)
Date: Fri, 12 Dec 2025 09:28:33 +0000
Subject: [PATCH] KVM: arm64: vgic: add default case to switch statement
In-Reply-To: <20251211224033.18079-1-osama.abdelkader@gmail.com>
References: <20251211224033.18079-1-osama.abdelkader@gmail.com>
Message-ID: <86qzt0nj5q.wl-maz@kernel.org>

On Thu, 11 Dec 2025 22:40:28 +0000,
Osama Abdelkader <osama.abdelkader at gmail.com> wrote:
> 
> The switch statement in vgic_validate_injection() handles all enum
> values for irq->config, but lacked a default case. Add one to match
> the pattern used in other switch statements in the same file and make

News flash: there is no other switch statement in this file. This is
the only one.

> the defensive return explicit.

I'd suggest you read the code more carefully, and consider the
following observations:

enum vgic_irq_config {
	VGIC_CONFIG_EDGE = 0,
	VGIC_CONFIG_LEVEL
};

struct vgic_irq {
	[...]
	enum vgic_irq_config config:1;	/* Level or edge */
	[...]
};

With these two definitions in mind, let's revisit the function you are
patching:

static bool vgic_validate_injection(struct vgic_irq *irq, bool level, void *owner)
{
	[...]

	switch (irq->config) {
	case VGIC_CONFIG_LEVEL:
		return irq->line_level != level;
	case VGIC_CONFIG_EDGE:
		return level;
	}

	return false;
}

Please explain how it is possible that the switch does not cover
*exhaustively* all the possible values that are constraint to exactly
One. Single. Bit? How adding a default case makes things better? The
compiler already knows that we are covering all the possible values of
the enum (yes, even a C compiler can achieve that), so it can *prove*
that there is no need for a default.

If anything, I'd have expected a patch dropping the last return, as it
is remarkably pointless. But just moving it? What does it change?

I'd suggest you think a bit more before posting random patches and
wasting people's time. I spent a good 15 minutes writing this, which
you could have used yourself to realise this change is pointless.

Thanks,

	M.

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


From mripard at kernel.org  Fri Dec 12 01:29:07 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Fri, 12 Dec 2025 10:29:07 +0100
Subject: [PATCH v5 06/17] drm/display: hdmi-state-helper: Try subsampling
 in mode_valid
In-Reply-To: <9409315.NyiUUSuA9g@workhorse>
References: <20251128-color-format-v5-0-63e82f1db1e1@collabora.com>
 <20251128-color-format-v5-6-63e82f1db1e1@collabora.com>
 <20251209-dramatic-caiman-of-luck-db9d0f@houat>
 <9409315.NyiUUSuA9g@workhorse>
Message-ID: <20251212-simple-beneficial-koel-daaeb7@penduick>

On Thu, Dec 11, 2025 at 08:59:14PM +0100, Nicolas Frattaroli wrote:
> On Tuesday, 9 December 2025 15:18:25 Central European Standard Time Maxime Ripard wrote:
> > On Fri, Nov 28, 2025 at 10:05:42PM +0100, Nicolas Frattaroli wrote:
> > > drm_hdmi_connector_mode_valid assumes modes are only valid if they work
> > > with RGB. The reality is more complex however: YCbCr 4:2:0
> > > chroma-subsampled modes only require half the pixel clock that the same
> > > mode would require in RGB.
> > > 
> > > This leads to drm_hdmi_connector_mode_valid rejecting perfectly valid
> > > 420-only modes.
> > > 
> > > Fix this by checking whether the mode is 420-only first. If so, then
> > > proceed by checking it with HDMI_COLORSPACE_YUV420 so long as the
> > > connector has legalized 420, otherwise error out. If the mode is not
> > > 420-only, check with RGB as was previously always the case.
> > > 
> > > Fixes: 47368ab437fd ("drm/display: hdmi: add generic mode_valid helper")
> > > Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
> > > ---
> > >  drivers/gpu/drm/display/drm_hdmi_state_helper.c | 12 +++++++++++-
> > >  1 file changed, 11 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> > > index 5da956bdd68c..1800e00b30c5 100644
> > > --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> > > +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> > > @@ -892,8 +892,18 @@ drm_hdmi_connector_mode_valid(struct drm_connector *connector,
> > >  			      const struct drm_display_mode *mode)
> > >  {
> > >  	unsigned long long clock;
> > > +	enum hdmi_colorspace fmt;
> > > +
> > > +	if (drm_mode_is_420_only(&connector->display_info, mode)) {
> > > +		if (connector->ycbcr_420_allowed)
> > > +			fmt = HDMI_COLORSPACE_YUV420;
> > > +		else
> > > +			return MODE_NO_420;
> > > +	} else {
> > > +		fmt = HDMI_COLORSPACE_RGB;
> > > +	}
> > >  
> > > -	clock = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_RGB);
> > > +	clock = drm_hdmi_compute_mode_clock(mode, 8, fmt);
> > 
> > I agree on principle, but we need to have a test for this.
> 
> I'd like to change `drm_mode_is_420_only` to `drm_mode_is_420` in
> the next revision, and modify the control flow to work correctly
> in this case, because rejecting 420-also modes on the basis that
> we can't do them in RGB isn't correct either.
> 
> But my concern with adding yet more tests is that I found this bug
> in a function unrelated to the series while adding tests you asked
> for, because the tests relied on this function to not be broken as
> part of the test setup. Yes, I was not be able to get any 4:2:0
> modes on the test connector in the kunit tests because
> drm_hdmi_connector_mode_valid helpfully discarded all of them.
> 
> So now I am wondering whether adding yet more tests will uncover
> more bugs in functions unrelated to implementing the "color format"
> property, that were only called because the new test required them
> to set up some test fixture. And then I have to add another fix and
> another test to this series, rinse and repeat.
>
> Can we just agree that I am not going to expand the scope of this
> series any further? If you want me to send a follow-up series that
> adds tests to some of the hdmi state helper functions, then I can
> do that, but I don't want to do it as a precondition for the 17
> other patches in this series to get merged.

But it is a precondition. See

https://docs.kernel.org/gpu/drm-internals.html#kunit-coverage-rules

You're adding code to a port of DRM that is covered by tests already,
and are fixing a hole in that test coverage. We must add a test to close
that hole too.

Now, if you want to take that fix out of your series and work on those
tests, fine, but we'll still need them.

Maxime
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 273 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251212/da718c22/attachment-0001.sig>

From maz at kernel.org  Fri Dec 12 01:35:22 2025
From: maz at kernel.org (Marc Zyngier)
Date: Fri, 12 Dec 2025 09:35:22 +0000
Subject: [PATCH] KVM: arm64: vgic: simplify vgic_v3_redist_region_full()
In-Reply-To: <20251211225114.20474-1-osama.abdelkader@gmail.com>
References: <20251211225114.20474-1-osama.abdelkader@gmail.com>
Message-ID: <86pl8kniud.wl-maz@kernel.org>

On Thu, 11 Dec 2025 22:51:09 +0000,
Osama Abdelkader <osama.abdelkader at gmail.com> wrote:
> 
> Simplify the function by converting the if-return-false pattern to a
> direct boolean expression return, making the code more concise and
> readable.
> 
> Signed-off-by: Osama Abdelkader <osama.abdelkader at gmail.com>
> ---
>  arch/arm64/kvm/vgic/vgic.h | 5 +----
>  1 file changed, 1 insertion(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
> index 5f0fc96b4dc2..04dd2055e7df 100644
> --- a/arch/arm64/kvm/vgic/vgic.h
> +++ b/arch/arm64/kvm/vgic/vgic.h
> @@ -382,10 +382,7 @@ static inline int vgic_v3_max_apr_idx(struct kvm_vcpu *vcpu)
>  static inline bool
>  vgic_v3_redist_region_full(struct vgic_redist_region *region)
>  {
> -	if (!region->count)
> -		return false;
> -
> -	return (region->free_index >= region->count);
> +	return region->count > 0 && region->free_index >= region->count;
>  }
>  
>  struct vgic_redist_region *vgic_v3_rdist_free_slot(struct list_head *rdregs);

This is not clearer. Checking for 0 is pretty important as it outlines
a specific condition, which is why this is written as a separate
statement.

Please stop sending patches that are only aligning things to your
personal taste. There is no shortage of real problems to fix in the
kernel, your time is better spent on that, and mine on reviewing
useful patches.

	M.

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


From alexandru.elisei at arm.com  Fri Dec 12 01:39:43 2025
From: alexandru.elisei at arm.com (Alexandru Elisei)
Date: Fri, 12 Dec 2025 09:39:43 +0000
Subject: [RFC PATCH v6 01/35] arm64/sysreg: Add new SPE fields
In-Reply-To: <20251210183827.GA3920451@e132581.arm.com>
References: <20251114160717.163230-1-alexandru.elisei@arm.com>
 <20251114160717.163230-2-alexandru.elisei@arm.com>
 <20251210183827.GA3920451@e132581.arm.com>
Message-ID: <aTvi33vLZU5S9CoM@raptor>

Hi Leo,

On Wed, Dec 10, 2025 at 06:38:27PM +0000, Leo Yan wrote:
> On Fri, Nov 14, 2025 at 04:06:42PM +0000, Alexandru Elisei wrote:
> 
> [...]
> 
> >  Sysreg	PMBIDR_EL1	3	0	9	10	7
> > -Res0	63:12
> > +Res0	63:48
> > +Field	47:32	MaxBuffSize
> > +Res0	31:12
> >  Enum	11:8	EA
> >  	0b0000	NotDescribed
> >  	0b0001	Ignored
> >  	0b0010	SError
> >  EndEnum
> > -Res0	7:6
> > +Enum	7:6	AddrMode
> > +	0b00	VM_ONLY
> > +	0b01	BOTH
> > +	0b10	RESERVED
> > +	0b11	nVM_ONLY
> > +EndEnum
> 
> Not sure how to select the enum names, but seems names above don't match
> well to the definitions.  How about:
> 
>   Enum  7:6     AddrMode
>         0b00    VA_ONLY         // Virtual address only
>         0b01    VA_PA           // Virtual and physical address supported
>         0b10    RESERVED
>         0b11    VM_PA_ONLY      // Physical address only in VM

Why not, but I would name the last value PA_ONLY.

Thanks,
Alex


From mripard at kernel.org  Fri Dec 12 01:50:26 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Fri, 12 Dec 2025 10:50:26 +0100
Subject: [PATCH v5 04/17] drm/bridge: Act on the DRM color format property
In-Reply-To: <3772903.e9J7NaK4W3@workhorse>
References: <20251128-color-format-v5-0-63e82f1db1e1@collabora.com>
 <20251128-color-format-v5-4-63e82f1db1e1@collabora.com>
 <20251209-smart-oarfish-of-wind-0c1c8b@houat>
 <3772903.e9J7NaK4W3@workhorse>
Message-ID: <20251212-hidden-armored-mule-66dd32@penduick>

On Thu, Dec 11, 2025 at 08:34:22PM +0100, Nicolas Frattaroli wrote:
> On Tuesday, 9 December 2025 15:27:28 Central European Standard Time Maxime Ripard wrote:
> > On Fri, Nov 28, 2025 at 10:05:40PM +0100, Nicolas Frattaroli wrote:
> > > The new DRM color format property allows userspace to request a specific
> > > color format on a connector. In turn, this fills the connector state's
> > > color_format member to switch color formats.
> > > 
> > > Make drm_bridges consider the color_format set in the connector state
> > > during the atomic bridge check. Specifically, reject any output bus
> > > formats that do not correspond to the requested color format.
> > > 
> > > Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
> > > ---
> > >  drivers/gpu/drm/drm_bridge.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
> > >  1 file changed, 45 insertions(+)
> > > 
> > > diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> > > index 8f355df883d8..8aac9747f35e 100644
> > > --- a/drivers/gpu/drm/drm_bridge.c
> > > +++ b/drivers/gpu/drm/drm_bridge.c
> > > @@ -1052,6 +1052,47 @@ static int select_bus_fmt_recursive(struct drm_bridge *first_bridge,
> > >  	return ret;
> > >  }
> > >  
> > > +static bool __pure bus_format_is_color_fmt(u32 bus_fmt, enum drm_color_format fmt)
> > > +{
> > > +	if (fmt == DRM_COLOR_FORMAT_AUTO)
> > > +		return true;
> > > +
> > > +	switch (bus_fmt) {
> > > +	case MEDIA_BUS_FMT_FIXED:
> > > +		return true;
> > > +	case MEDIA_BUS_FMT_RGB888_1X24:
> > > +	case MEDIA_BUS_FMT_RGB101010_1X30:
> > > +	case MEDIA_BUS_FMT_RGB121212_1X36:
> > > +	case MEDIA_BUS_FMT_RGB161616_1X48:
> > > +		return fmt == DRM_COLOR_FORMAT_RGB444;
> > > +	case MEDIA_BUS_FMT_YUV8_1X24:
> > > +	case MEDIA_BUS_FMT_YUV10_1X30:
> > > +	case MEDIA_BUS_FMT_YUV12_1X36:
> > > +	case MEDIA_BUS_FMT_YUV16_1X48:
> > > +		return fmt == DRM_COLOR_FORMAT_YCBCR444;
> > > +	case MEDIA_BUS_FMT_UYVY8_1X16:
> > > +	case MEDIA_BUS_FMT_VYUY8_1X16:
> > > +	case MEDIA_BUS_FMT_YUYV8_1X16:
> > > +	case MEDIA_BUS_FMT_YVYU8_1X16:
> > > +	case MEDIA_BUS_FMT_UYVY10_1X20:
> > > +	case MEDIA_BUS_FMT_YUYV10_1X20:
> > > +	case MEDIA_BUS_FMT_VYUY10_1X20:
> > > +	case MEDIA_BUS_FMT_YVYU10_1X20:
> > > +	case MEDIA_BUS_FMT_UYVY12_1X24:
> > > +	case MEDIA_BUS_FMT_VYUY12_1X24:
> > > +	case MEDIA_BUS_FMT_YUYV12_1X24:
> > > +	case MEDIA_BUS_FMT_YVYU12_1X24:
> > > +		return fmt == DRM_COLOR_FORMAT_YCBCR422;
> > > +	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
> > > +	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
> > > +	case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
> > > +	case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
> > > +		return fmt == DRM_COLOR_FORMAT_YCBCR420;
> > > +	default:
> > > +		return false;
> > > +	}
> > > +}
> > > +
> > >  /*
> > >   * This function is called by &drm_atomic_bridge_chain_check() just before
> > >   * calling &drm_bridge_funcs.atomic_check() on all elements of the chain.
> > > @@ -1137,6 +1178,10 @@ drm_atomic_bridge_chain_select_bus_fmts(struct drm_bridge *bridge,
> > >  	}
> > >  
> > >  	for (i = 0; i < num_out_bus_fmts; i++) {
> > > +		if (!bus_format_is_color_fmt(out_bus_fmts[i], conn_state->color_format)) {
> > > +			ret = -ENOTSUPP;
> > > +			continue;
> > > +		}
> > 
> > Sorry, I'm struggling a bit to understand how this would work if a bridge both supports the bus
> > format selection and HDMI state helpers? Can you expand on it?
> 
> I have very little idea of whether this makes conceptual sense.

.. I wasn't asking you if it makes sense, I was asking you to explain
how you wanted it to work.

> The hope is that by working backwards from the last bridge and only
> accepting either fixed formats or something that corresponds to the
> target color format, we don't claim that a setup can do a colour
> format if the whole bridge chain isn't able to do it.
> 
> Of course, format conversions along the bridge chain where one
> input format can be converted to a set of output formats by some
> bridge will throw a massive wrench into this. And this is all
> assuming that the bus format is in any way related to the color
> format that will be sent out on the wire.

I'm not really concerned about this. As we move more and more bridges to
the state helpers, we can always fix it, but it needs at the very least
to document how you envision the whole thing to work, and ideally have
bunch of tests to make sure it still does.

> In practice, I don't have any hardware where whatever counts as
> a "bridge" is an actually more involved setup than just the TX
> controller. I tried looking into getting a board with one of the
> supported DSI-to-HDMI bridge chips so I can at least test how it
> would work in such a scenario, and I got one, but I'd need to make
> my own flat flex PCB to adapt it to the pinout of my SBC's DSI
> port.
> 
> So yeah I don't know how it's supposed to work, I just know this
> works for the case I'm working with, and any more complex case
> is literally unobtanium hardware which I'm not going to bother
> blowing days on maybe making a cable for when I'm already touching
> three different GPU drivers here and the intel-gfx-ci is screaming
> into my inbox about vague failures in unrelated codepaths in its
> native language, Klingon.

That's uncalled for.

> Which is all to say: is there a virtual drm bridge driver that
> exists, where I can set what formats it supports on the input
> and on the output, so that I can actually get a feel for how this
> is conceptually supposed to work without needing special hardware?

If your question is "do we have a way to replicate and test an arbitrary
setup to check how it behaves?", then yes, we do, it's what we're doing
in kunit. But you don't seem too fond of those.

> Better yet: do you have a specific setup in mind where you know
> this approach does not work?

Look. I was asking a genuine question. If you want to get all defensive
about it, go ahead. But sending a series implementing something with a
lot of history, complex interactions, etc. and then expecting it to be a
breeze that will get merged in a few revisions is not going to work.

Pushing back when asked to follow our documented rules, or being
dismissive when asked design questions is not going to help you push
this forward. If anything, and because it's complex, the more tests you
add the better because we A) know it works in a specific set of cases,
and B) know it will still work going forward.

I'm sure you know what you're doing, but so do we.

Maxime
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 273 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251212/e1f6502c/attachment.sig>

From daniel.baluta at gmail.com  Fri Dec 12 01:57:12 2025
From: daniel.baluta at gmail.com (Daniel Baluta)
Date: Fri, 12 Dec 2025 11:57:12 +0200
Subject: [PATCH v2 1/2] dt-bindings: arm: imx Add FRDM-IMX91 board
In-Reply-To: <20251212-imx91_frdm-v2-1-4dd6d289e81d@nxp.com>
References: <20251212-imx91_frdm-v2-0-4dd6d289e81d@nxp.com> <20251212-imx91_frdm-v2-1-4dd6d289e81d@nxp.com>
Message-ID: <CAEnQRZB7BtSu2ec4wh0353MYkwgzbpQxD7qa0r6NC_kf+hRfKg@mail.gmail.com>

On Fri, Dec 12, 2025 at 4:32?AM Joseph Guo <qijian.guo at nxp.com> wrote:
>
> Add the board FRDM-IMX91 in the binding document.
>
> Signed-off-by: Joseph Guo <qijian.guo at nxp.com>

Reviewed-by: Daniel Baluta <daniel.baluta at nxp.com>


From peng.fan at oss.nxp.com  Fri Dec 12 01:57:18 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Fri, 12 Dec 2025 17:57:18 +0800
Subject: [PATCH 0/3] arm64: dts: freescale: Use phys to replace
 xceiver-supply
Message-ID: <20251212-imx9-can-phy-v1-0-a421d7023e13@nxp.com>

This is a pick up of patch 6-8 from [1].

The drivers changes have been picked in 6.18, just resend the dts changes.

[1]https://lore.kernel.org/linux-phy/20251001-can-v7-0-fad29efc3884 at nxp.com/

There are still some other device trees not converted to use phys,
those will be converted later.

Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
Peng Fan (3):
      arm64: dts: imx95-15x15-evk: Use phys to replace xceiver-supply
      arm64: dts: imx8mp-evk: Use phys to replace xceiver-supply
      arm64: dts: imx93-11x11-evk: Use phys to replace xceiver-supply

 arch/arm64/boot/dts/freescale/imx8mp-evk.dts      | 43 +++++++----------------
 arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts | 17 +++++----
 arch/arm64/boot/dts/freescale/imx95-15x15-evk.dts | 13 ++++---
 3 files changed, 27 insertions(+), 46 deletions(-)
---
base-commit: 008d3547aae5bc86fac3eda317489169c3fda112
change-id: 20251212-imx9-can-phy-328c2085afc7

Best regards,
-- 
Peng Fan <peng.fan at nxp.com>



From peng.fan at oss.nxp.com  Fri Dec 12 01:57:19 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Fri, 12 Dec 2025 17:57:19 +0800
Subject: [PATCH 1/3] arm64: dts: imx95-15x15-evk: Use phys to replace
 xceiver-supply
In-Reply-To: <20251212-imx9-can-phy-v1-0-a421d7023e13@nxp.com>
References: <20251212-imx9-can-phy-v1-0-a421d7023e13@nxp.com>
Message-ID: <20251212-imx9-can-phy-v1-1-a421d7023e13@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

The TJA1051T/3 used on i.MX95-15x15-EVK is actually high-speed CAN
transceiver, not a regulator supply. So use phys to reflect the truth.

Reviewed-by: Frank Li <Frank.Li at nxp.com>
Acked-by: Marc Kleine-Budde <mkl at pengutronix.de>
Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 arch/arm64/boot/dts/freescale/imx95-15x15-evk.dts | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx95-15x15-evk.dts b/arch/arm64/boot/dts/freescale/imx95-15x15-evk.dts
index c1e245ecea9c16078cf5b59ac527721e156cf939..b934295bac15ee73c2a65a70c462b2cf75534cc1 100644
--- a/arch/arm64/boot/dts/freescale/imx95-15x15-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx95-15x15-evk.dts
@@ -107,12 +107,11 @@ reg_audio_switch1: regulator-audio-switch1 {
 		gpio = <&pcal6524 0 GPIO_ACTIVE_LOW>;
 	};
 
-	reg_can2_stby: regulator-can2-stby {
-		compatible = "regulator-fixed";
-		regulator-max-microvolt = <3300000>;
-		regulator-min-microvolt = <3300000>;
-		regulator-name = "can2-stby";
-		gpio = <&pcal6524 14 GPIO_ACTIVE_LOW>;
+	flexcan2_phy: can-phy {
+		compatible = "nxp,tja1051";
+		#phy-cells = <0>;
+		max-bitrate = <5000000>;
+		silent-gpios = <&pcal6524 14 GPIO_ACTIVE_HIGH>;
 	};
 
 	reg_m2_pwr: regulator-m2-pwr {
@@ -318,7 +317,7 @@ &enetc_port1 {
 &flexcan2 {
 	pinctrl-0 = <&pinctrl_flexcan2>;
 	pinctrl-names = "default";
-	xceiver-supply = <&reg_can2_stby>;
+	phys = <&flexcan2_phy>;
 	status = "okay";
 };
 

-- 
2.37.1



From peng.fan at oss.nxp.com  Fri Dec 12 01:57:20 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Fri, 12 Dec 2025 17:57:20 +0800
Subject: [PATCH 2/3] arm64: dts: imx8mp-evk: Use phys to replace
 xceiver-supply
In-Reply-To: <20251212-imx9-can-phy-v1-0-a421d7023e13@nxp.com>
References: <20251212-imx9-can-phy-v1-0-a421d7023e13@nxp.com>
Message-ID: <20251212-imx9-can-phy-v1-2-a421d7023e13@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

The TJA1048 used on i.MX8MP-EVK is actually high-speed CAN transceiver,
not a regulator supply. So use phys to reflect the truth.

Reviewed-by: Frank Li <Frank.Li at nxp.com>
Acked-by: Marc Kleine-Budde <mkl at pengutronix.de>
Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 arch/arm64/boot/dts/freescale/imx8mp-evk.dts | 43 +++++++++-------------------
 1 file changed, 13 insertions(+), 30 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
index c6facb2ad9aaa210d355a0f40eecde5e4b2f4c5d..7ededc1a06179808070f1f82172d313c8d043de8 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
@@ -56,6 +56,16 @@ memory at 40000000 {
 		      <0x1 0x00000000 0 0xc0000000>;
 	};
 
+	flexcan_phy: can-phy {
+		compatible = "nxp,tja1048";
+		#phy-cells = <1>;
+		max-bitrate = <5000000>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_flexcan_phy>;
+		standby-gpios = <&gpio5 5 GPIO_ACTIVE_LOW>,
+				<&gpio4 27 GPIO_ACTIVE_LOW>;
+	};
+
 	native-hdmi-connector {
 		compatible = "hdmi-connector";
 		label = "HDMI OUT";
@@ -103,28 +113,6 @@ reg_audio_pwr: regulator-audio-pwr {
 		enable-active-high;
 	};
 
-	reg_can1_stby: regulator-can1-stby {
-		compatible = "regulator-fixed";
-		regulator-name = "can1-stby";
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_flexcan1_reg>;
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		gpio = <&gpio5 5 GPIO_ACTIVE_HIGH>;
-		enable-active-high;
-	};
-
-	reg_can2_stby: regulator-can2-stby {
-		compatible = "regulator-fixed";
-		regulator-name = "can2-stby";
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_flexcan2_reg>;
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		gpio = <&gpio4 27 GPIO_ACTIVE_HIGH>;
-		enable-active-high;
-	};
-
 	reg_pcie0: regulator-pcie {
 		compatible = "regulator-fixed";
 		pinctrl-names = "default";
@@ -431,14 +419,14 @@ ethphy1: ethernet-phy at 1 {
 &flexcan1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_flexcan1>;
-	xceiver-supply = <&reg_can1_stby>;
+	phys = <&flexcan_phy 0>;
 	status = "okay";
 };
 
 &flexcan2 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_flexcan2>;
-	xceiver-supply = <&reg_can2_stby>;
+	phys = <&flexcan_phy 1>;
 	status = "disabled";/* can2 pin conflict with pdm */
 };
 
@@ -909,14 +897,9 @@ MX8MP_IOMUXC_SAI5_RXD3__CAN2_TX         0x154
 		>;
 	};
 
-	pinctrl_flexcan1_reg: flexcan1reggrp {
+	pinctrl_flexcan_phy: flexcanphygrp {
 		fsl,pins = <
 			MX8MP_IOMUXC_SPDIF_EXT_CLK__GPIO5_IO05  0x154   /* CAN1_STBY */
-		>;
-	};
-
-	pinctrl_flexcan2_reg: flexcan2reggrp {
-		fsl,pins = <
 			MX8MP_IOMUXC_SAI2_MCLK__GPIO4_IO27      0x154   /* CAN2_STBY */
 		>;
 	};

-- 
2.37.1



From peng.fan at oss.nxp.com  Fri Dec 12 01:57:21 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Fri, 12 Dec 2025 17:57:21 +0800
Subject: [PATCH 3/3] arm64: dts: imx93-11x11-evk: Use phys to replace
 xceiver-supply
In-Reply-To: <20251212-imx9-can-phy-v1-0-a421d7023e13@nxp.com>
References: <20251212-imx9-can-phy-v1-0-a421d7023e13@nxp.com>
Message-ID: <20251212-imx9-can-phy-v1-3-a421d7023e13@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

The TJA1057 used on i.MX93 EVK is actually high-speed CAN
transceiver, not a regulator supply. So use phys to reflect the truth.

Reviewed-by: Frank Li <Frank.Li at nxp.com>
Acked-by: Marc Kleine-Budde <mkl at pengutronix.de>
Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts
index b94a24193e199b266943c58466f4f620e81480ba..8dd5340e8141f44913be8167e85337f179f5edbf 100644
--- a/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts
@@ -81,6 +81,13 @@ vdevbuffer: vdevbuffer at a4020000 {
 
 	};
 
+	flexcan_phy: can-phy {
+		compatible = "nxp,tja1057";
+		#phy-cells = <0>;
+		max-bitrate = <5000000>;
+		silent-gpios = <&adp5585 6 GPIO_ACTIVE_HIGH>;
+	};
+
 	reg_vdd_12v: regulator-vdd-12v {
 		compatible = "regulator-fixed";
 		regulator-name = "VDD_12V";
@@ -106,14 +113,6 @@ reg_audio_pwr: regulator-audio-pwr {
 		enable-active-high;
 	};
 
-	reg_can2_standby: regulator-can2-standby {
-		compatible = "regulator-fixed";
-		regulator-name = "can2-stby";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		gpio = <&adp5585 6 GPIO_ACTIVE_LOW>;
-	};
-
 	reg_m2_pwr: regulator-m2-pwr {
 		compatible = "regulator-fixed";
 		regulator-name = "M.2-power";
@@ -302,7 +301,7 @@ ethphy2: ethernet-phy at 2 {
 &flexcan2 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_flexcan2>;
-	xceiver-supply = <&reg_can2_standby>;
+	phys = <&flexcan_phy>;
 	status = "okay";
 };
 

-- 
2.37.1



From maqianga at uniontech.com  Fri Dec 12 01:56:46 2025
From: maqianga at uniontech.com (Qiang Ma)
Date: Fri, 12 Dec 2025 17:56:46 +0800
Subject: [PATCH v1 0/3] kexec: add kexec flag to control debug printing
Message-ID: <20251212095649.857796-1-maqianga@uniontech.com>

Overview:
=========
The commit cbc2fe9d9cb2 ("kexec_file: add kexec_file flag to control
debug printing") added the kexec_file flag to control debug printing.
However, for arm64, after commit 6f8c1da071a4 ("kexec_file, arm64: print
out debugging message if required"), when using the kexec_load interface,
the kexec_image_info function is called to print debug message, but
it uses kexec_dprintk, which is only available under kexec_file,
then when specifying 'kexec -d', kexec_load interface will print nothing.

For riscv, commit eb7622d908a09 ("kexec_file, riscv: print out debugging
message if required") remove kexec_image_info(), because the content has
been printed out in generic code in kexec_file_load, but not in kexec_load.

Therefore, in order to solve the two problems mentioned above, for this
patchset, several things need to be done:

1. Enabling kexec_dprintk is available for kexec_load.
2. Add some debugging message of the deleted kexec_image_info
   to generic code.
3. Remove duplicate debugging prints for arm64.

Since kexec_load and kexec_file_load are not triggered simultaneously,
we can unify the debug flag of kexec and kexec_file as kexec_dbg_print.

In this way, kexec_dprintk is available for kexec_load and kexec_file_load.

Then when specifying 'kexec -d', the debugging message using kexec_dprintk in
kexec_image_info can be printed normally.

The following are the key points of the specific changes:

1. rename kexec_file_dbg_print to kexec_dbg_print
2. Add KEXEC_DEBUG
3. Initialize kexec_dbg_print for kexec
4. Set the reset of kexec_dbg_print to kimage_free

Testing:
=========
I did testing on x86_64, arm64 and loongarch. On x86_64, the printed messages
look like below:

Unset CONFIG_KEXEC_FILE:
[   36.774228] kexec_file: kernel: 0000000066c386c8 kernel_size: 0xd78400
[   36.821814] kexec-bzImage64: Loaded purgatory at 0x23fffb000
[   36.821826] kexec-bzImage64: Loaded boot_param, command line and misc at 0x23fff9000 bufsz=0x12d0 memsz=0x2000
[   36.821829] kexec-bzImage64: Loaded 64bit kernel at 0x23d400000 bufsz=0xd73400 memsz=0x2ab7000
[   36.821918] kexec-bzImage64: Loaded initrd at 0x23bd0b000 bufsz=0x16f40a8 memsz=0x16f40a8
[   36.821920] kexec-bzImage64: Final command line is: root=/dev/mapper/test-root crashkernel=auto rd.lvm.lv=test/root
[   36.821925] kexec-bzImage64: E820 memmap:
[   36.821926] kexec-bzImage64: 0000000000000000-000000000009ffff (1)
[   36.821928] kexec-bzImage64: 0000000000100000-0000000000811fff (1)
[   36.821930] kexec-bzImage64: 0000000000812000-0000000000812fff (2)
[   36.821931] kexec-bzImage64: 0000000000813000-00000000bee38fff (1)
[   36.821933] kexec-bzImage64: 00000000bee39000-00000000beec2fff (2)
[   36.821934] kexec-bzImage64: 00000000beec3000-00000000bf8ecfff (1)
[   36.821935] kexec-bzImage64: 00000000bf8ed000-00000000bfb6cfff (2)
[   36.821936] kexec-bzImage64: 00000000bfb6d000-00000000bfb7efff (3)
[   36.821937] kexec-bzImage64: 00000000bfb7f000-00000000bfbfefff (4)
[   36.821938] kexec-bzImage64: 00000000bfbff000-00000000bff7bfff (1)
[   36.821939] kexec-bzImage64: 00000000bff7c000-00000000bfffffff (2)
[   36.821940] kexec-bzImage64: 00000000feffc000-00000000feffffff (2)
[   36.821941] kexec-bzImage64: 00000000ffc00000-00000000ffffffff (2)
[   36.821942] kexec-bzImage64: 0000000100000000-000000023fffffff (1)
[   36.872348] kexec_file: nr_segments = 4
[   36.872356] kexec_file: segment[0]: buf=0x000000005314ece7 bufsz=0x4000 mem=0x23fffb000 memsz=0x5000
[   36.872370] kexec_file: segment[1]: buf=0x000000006e59b143 bufsz=0x12d0 mem=0x23fff9000 memsz=0x2000
[   36.872374] kexec_file: segment[2]: buf=0x00000000eb7b1fc3 bufsz=0xd73400 mem=0x23d400000 memsz=0x2ab7000
[   36.882172] kexec_file: segment[3]: buf=0x000000006af76441 bufsz=0x16f40a8 mem=0x23bd0b000 memsz=0x16f5000
[   36.889113] kexec_file: kexec_file_load: type:0, start:0x23fffb150 head:0x101a2e002 flags:0x8

On aarch64, the printed messages look like below:

Set CONFIG_KEXEC_FILE
[   39.033203] kexec_file: kernel: 0000000073414684 kernel_size: 0x3123a00
[   39.047010] kexec_file: Loaded initrd at 0x43cf0000 bufsz=0x17e0e19 memsz=0x17e1000
[   39.047054] kexec_file: Loaded dtb at 0x23ec00000 bufsz=0x386 memsz=0x1000
[   39.047056] kexec_file(Image): Loaded kernel at 0x40000000 bufsz=0x3123a00 memsz=0x3cf0000
[   39.047063] kexec_file: nr_segments = 3
[   39.047064] kexec_file: segment[0]: buf=0x0000000073414684 bufsz=0x3123a00 mem=0x40000000 memsz=0x3cf0000
[   39.073612] kexec_file: segment[1]: buf=0x000000005cd5746b bufsz=0x17e0e19 mem=0x43cf0000 memsz=0x17e1000
[   39.085309] kexec_file: segment[2]: buf=0x0000000084c4a0f1 bufsz=0x386 mem=0x23ec00000 memsz=0x1000
[   39.085459] machine_kexec_post_load:155:
[   39.085463]   kexec kimage info:
[   39.085467]     kern_reloc: 0x00000001620e2000
[   39.085468]     el2_vectors: 0x0000000000000000
[   39.085470] kexec_file: kexec_file_load: type:0, start:0x40000000 head:0x1620e4002 flags:0x8

Unset CONFIG_KEXEC_FILE:

With this patch:
[   35.156088] machine_kexec_post_load:155:
[   35.156097]   kexec kimage info:
[   35.156101]     kern_reloc: 0x000000011c134000
[   35.156102]     el2_vectors: 0x0000000000000000
[   35.156104] kexec: kexec_load: type:0, start:0x454d26b0 head:0x105c14002 flags:0xb70010

Without this patch:
There is no kexec print in dmesg.

Previous posts:
Link: https://lore.kernel.org/all/aTdxEvqY6Bcy7Wa1 at MiWiFi-R3L-srv/

Qiang Ma (3):
  kexec: add kexec flag to control debug printing
  kexec: print out debugging message if required for kexec_load
  arm64: kexec: Adjust the debug print of kexec_image_info

 arch/arm64/kernel/machine_kexec.c | 2 --
 include/linux/kexec.h             | 9 +++++----
 include/uapi/linux/kexec.h        | 1 +
 kernel/kexec.c                    | 4 ++++
 kernel/kexec_core.c               | 4 +++-
 kernel/kexec_file.c               | 4 +---
 6 files changed, 14 insertions(+), 10 deletions(-)

-- 
2.20.1



From maqianga at uniontech.com  Fri Dec 12 01:56:48 2025
From: maqianga at uniontech.com (Qiang Ma)
Date: Fri, 12 Dec 2025 17:56:48 +0800
Subject: [PATCH v1 2/3] kexec: print out debugging message if required for kexec_load
In-Reply-To: <20251212095649.857796-1-maqianga@uniontech.com>
References: <20251212095649.857796-1-maqianga@uniontech.com>
Message-ID: <20251212095649.857796-3-maqianga@uniontech.com>

The commit a85ee18c7900 ("kexec_file: print out debugging message
if required") has added general code printing in kexec_file_load(),
but not in kexec_load().

As a result, when using '-d' for the kexec_load interface,
print nothing in the kernel space.

Since the segments debugging message has already been printed by the
user-space tool kexec-tools, it will not be printed here in the
kernel space.

And print out type/start/head of kimage and flags to help debug.

Signed-off-by: Qiang Ma <maqianga at uniontech.com>
Reported-by: kernel test robot <lkp at intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202510310332.6XrLe70K-lkp at intel.com/
---
 kernel/kexec.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/kernel/kexec.c b/kernel/kexec.c
index f6c58c767eb0..37e4ac8af9f3 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -166,6 +166,9 @@ static int do_kexec_load(unsigned long entry, unsigned long nr_segments,
 	if (ret)
 		goto out;
 
+	kexec_dprintk("kexec_load: type:%u, start:0x%lx head:0x%lx flags:0x%lx\n",
+		      image->type, image->start, image->head, flags);
+
 	/* Install the new kernel and uninstall the old */
 	image = xchg(dest_image, image);
 
-- 
2.20.1



From maqianga at uniontech.com  Fri Dec 12 01:56:47 2025
From: maqianga at uniontech.com (Qiang Ma)
Date: Fri, 12 Dec 2025 17:56:47 +0800
Subject: [PATCH v1 1/3] kexec: add kexec flag to control debug printing
In-Reply-To: <20251212095649.857796-1-maqianga@uniontech.com>
References: <20251212095649.857796-1-maqianga@uniontech.com>
Message-ID: <20251212095649.857796-2-maqianga@uniontech.com>

The commit cbc2fe9d9cb2 ("kexec_file: add kexec_file flag to control
debug printing") added the kexec_file flag to control debug printing.
However, for arm64, after commit 6f8c1da071a4 ("kexec_file, arm64: print
out debugging message if required"), when using the kexec_load interface,
the kexec_image_info function is called to print debug message, but
it uses kexec_dprintk, which is only available under kexec_file,
then when specifying 'kexec -d', kexec_load interface will print nothing.

For riscv, commit eb7622d908a09 ("kexec_file, riscv: print out debugging
message if required") remove kexec_image_info(), because the content has
been printed out in generic code in kexec_file_load, but not in kexec_load.

Therefore, in order to solve the two problems mentioned above, for this
patchset, several things need to be done:

1. Enabling kexec_dprintk is available for kexec_load.
2. Add some debugging message of the deleted kexec_image_info
   to generic code.
3. Remove duplicate debugging prints for arm64

Since kexec_load and kexec_file_load are not triggered simultaneously,
we can unify the debug flag of kexec and kexec_file as kexec_dbg_print.

In this way, kexec_dprintk is available for kexec_load and kexec_file_load.

The following are the key points of the specific changes:

1. rename kexec_file_dbg_print to kexec_dbg_print
2. Add KEXEC_DEBUG
3. Initialize kexec_dbg_print for kexec
4. Set the reset of kexec_dbg_print to kimage_free

Signed-off-by: Qiang Ma <maqianga at uniontech.com>
---
 include/linux/kexec.h      | 9 +++++----
 include/uapi/linux/kexec.h | 1 +
 kernel/kexec.c             | 1 +
 kernel/kexec_core.c        | 4 +++-
 kernel/kexec_file.c        | 4 +---
 5 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index ff7e231b0485..23f10aec0b34 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -455,10 +455,11 @@ bool kexec_load_permitted(int kexec_image_type);
 
 /* List of defined/legal kexec flags */
 #ifndef CONFIG_KEXEC_JUMP
-#define KEXEC_FLAGS    (KEXEC_ON_CRASH | KEXEC_UPDATE_ELFCOREHDR | KEXEC_CRASH_HOTPLUG_SUPPORT)
+#define KEXEC_FLAGS    (KEXEC_ON_CRASH | KEXEC_UPDATE_ELFCOREHDR | KEXEC_CRASH_HOTPLUG_SUPPORT | \
+			KEXEC_DEBUG)
 #else
 #define KEXEC_FLAGS    (KEXEC_ON_CRASH | KEXEC_PRESERVE_CONTEXT | KEXEC_UPDATE_ELFCOREHDR | \
-			KEXEC_CRASH_HOTPLUG_SUPPORT)
+			KEXEC_CRASH_HOTPLUG_SUPPORT | KEXEC_DEBUG)
 #endif
 
 /* List of defined/legal kexec file flags */
@@ -525,10 +526,10 @@ static inline int arch_kexec_post_alloc_pages(void *vaddr, unsigned int pages, g
 static inline void arch_kexec_pre_free_pages(void *vaddr, unsigned int pages) { }
 #endif
 
-extern bool kexec_file_dbg_print;
+extern bool kexec_dbg_print;
 
 #define kexec_dprintk(fmt, arg...) \
-        do { if (kexec_file_dbg_print) pr_info(fmt, ##arg); } while (0)
+	do { if (kexec_dbg_print) pr_info(fmt, ##arg); } while (0)
 
 extern void *kimage_map_segment(struct kimage *image, unsigned long addr, unsigned long size);
 extern void kimage_unmap_segment(void *buffer);
diff --git a/include/uapi/linux/kexec.h b/include/uapi/linux/kexec.h
index 55749cb0b81d..819c600af125 100644
--- a/include/uapi/linux/kexec.h
+++ b/include/uapi/linux/kexec.h
@@ -14,6 +14,7 @@
 #define KEXEC_PRESERVE_CONTEXT	0x00000002
 #define KEXEC_UPDATE_ELFCOREHDR	0x00000004
 #define KEXEC_CRASH_HOTPLUG_SUPPORT 0x00000008
+#define KEXEC_DEBUG		0x00000010
 #define KEXEC_ARCH_MASK		0xffff0000
 
 /*
diff --git a/kernel/kexec.c b/kernel/kexec.c
index 9bb1f2b6b268..f6c58c767eb0 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -42,6 +42,7 @@ static int kimage_alloc_init(struct kimage **rimage, unsigned long entry,
 	if (!image)
 		return -ENOMEM;
 
+	kexec_dbg_print = !!(flags & KEXEC_DEBUG);
 	image->start = entry;
 	image->nr_segments = nr_segments;
 	memcpy(image->segment, segments, nr_segments * sizeof(*segments));
diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index fa00b239c5d9..7bc1cd4105fc 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -53,7 +53,7 @@ atomic_t __kexec_lock = ATOMIC_INIT(0);
 /* Flag to indicate we are going to kexec a new kernel */
 bool kexec_in_progress = false;
 
-bool kexec_file_dbg_print;
+bool kexec_dbg_print;
 
 /*
  * When kexec transitions to the new kernel there is a one-to-one
@@ -576,6 +576,8 @@ void kimage_free(struct kimage *image)
 	kimage_entry_t *ptr, entry;
 	kimage_entry_t ind = 0;
 
+	kexec_dbg_print = false;
+
 	if (!image)
 		return;
 
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index eb62a9794242..3f1d6c4e8ff2 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -138,8 +138,6 @@ void kimage_file_post_load_cleanup(struct kimage *image)
 	 */
 	kfree(image->image_loader_data);
 	image->image_loader_data = NULL;
-
-	kexec_file_dbg_print = false;
 }
 
 #ifdef CONFIG_KEXEC_SIG
@@ -314,7 +312,7 @@ kimage_file_alloc_init(struct kimage **rimage, int kernel_fd,
 	if (!image)
 		return -ENOMEM;
 
-	kexec_file_dbg_print = !!(flags & KEXEC_FILE_DEBUG);
+	kexec_dbg_print = !!(flags & KEXEC_FILE_DEBUG);
 	image->file_mode = 1;
 
 #ifdef CONFIG_CRASH_DUMP
-- 
2.20.1



From maqianga at uniontech.com  Fri Dec 12 01:56:49 2025
From: maqianga at uniontech.com (Qiang Ma)
Date: Fri, 12 Dec 2025 17:56:49 +0800
Subject: [PATCH v1 3/3] arm64: kexec: Adjust the debug print of kexec_image_info
In-Reply-To: <20251212095649.857796-1-maqianga@uniontech.com>
References: <20251212095649.857796-1-maqianga@uniontech.com>
Message-ID: <20251212095649.857796-4-maqianga@uniontech.com>

In the previous patch, we move start/head of kimage to the
generic code, so, we remove them to avoid duplicate printing.

Signed-off-by: Qiang Ma <maqianga at uniontech.com>
---
 arch/arm64/kernel/machine_kexec.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c
index 239c16e3d02f..0896e3e6a811 100644
--- a/arch/arm64/kernel/machine_kexec.c
+++ b/arch/arm64/kernel/machine_kexec.c
@@ -34,8 +34,6 @@ static void _kexec_image_info(const char *func, int line,
 {
 	kexec_dprintk("%s:%d:\n", func, line);
 	kexec_dprintk("  kexec kimage info:\n");
-	kexec_dprintk("    type:        %d\n", kimage->type);
-	kexec_dprintk("    head:        %lx\n", kimage->head);
 	kexec_dprintk("    kern_reloc: %pa\n", &kimage->arch.kern_reloc);
 	kexec_dprintk("    el2_vectors: %pa\n", &kimage->arch.el2_vectors);
 }
-- 
2.20.1



From chaoyi.chen at rock-chips.com  Fri Dec 12 01:59:34 2025
From: chaoyi.chen at rock-chips.com (Chaoyi Chen)
Date: Fri, 12 Dec 2025 17:59:34 +0800
Subject: [PATCH v2 5/8] drm/rockchip: vop2: Enforce AFBC source alignment
 in plane_check
In-Reply-To: <3520923.e9J7NaK4W3@workhorse>
References: <20251206-vop2-atomic-fixups-v2-0-7fb45bbfbebd@collabora.com>
 <8655687.NyiUUSuA9g@workhorse>
 <fdd333ac-0542-4312-8ec0-22fded3b1ce0@rock-chips.com>
 <3520923.e9J7NaK4W3@workhorse>
Message-ID: <72e06301-5f3e-4ea8-a9af-f3b1f0b329aa@rock-chips.com>

Hi Nicolas,

On 12/11/2025 10:16 PM, Nicolas Frattaroli wrote:
> On Thursday, 11 December 2025 12:06:38 Central European Standard Time Chaoyi Chen wrote:
>> Hello Nicolas,
>>
>> On 12/9/2025 6:58 PM, Nicolas Frattaroli wrote:
>>> Hi Chaoyi Chen, Andy Yan,
>>>
>>> On Monday, 8 December 2025 08:24:52 Central European Standard Time Nicolas Frattaroli wrote:
>>>> On Monday, 8 December 2025 03:48:24 Central European Standard Time Chaoyi Chen wrote:
>>>>> Hello Nicolas, Daniel,
>>>>>
>>>>> On 12/7/2025 4:45 AM, Nicolas Frattaroli wrote:
>>>>>> From: Daniel Stone <daniels at collabora.com>
>>>>>>
>>>>>> Planes can only source AFBC framebuffers at multiples of 4px wide on
>>>>>> RK3566/RK3568. Instead of clipping on all SoCs when the user asks for an
>>>>>> unaligned source rectangle, reject the configuration in the plane's
>>>>>> atomic check on RK3566/RK3568 only.
>>>>>>
>>>>>> Signed-off-by: Daniel Stone <daniels at collabora.com>
>>>>>> [Make RK3566/RK3568 specific, reword message]
>>>>>> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
>>>>>> ---
>>>>>>  drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 14 +++++++++-----
>>>>>>  1 file changed, 9 insertions(+), 5 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
>>>>>> index bc1ed0ffede0..e23213337104 100644
>>>>>> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
>>>>>> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
>>>>>> @@ -1076,6 +1076,13 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
>>>>>>  		return -EINVAL;
>>>>>>  	}
>>>>>>  
>>>>>> +	if (vop2->version == VOP_VERSION_RK3568 && drm_is_afbc(fb->modifier) && src_w % 4) {
>>>>>> +		drm_dbg_kms(vop2->drm,
>>>>>> +			    "AFBC source rectangles must be 4-byte aligned; is %d\n",
>>>>>> +			    src_w);
>>>>>> +		return -EINVAL;
>>>>>> +	}
>>>>>> +
>>>>>>  	return 0;
>>>>>>  }
>>>>>>  
>>>>>> @@ -1237,11 +1244,8 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
>>>>>>  	WARN_ON(src_w < 4);
>>>>>>  	WARN_ON(src_h < 4);
>>>>>>  
>>>>>> -	if (afbc_en && src_w % 4) {
>>>>>> -		drm_dbg_kms(vop2->drm, "vp%d %s src_w[%d] not 4 pixel aligned\n",
>>>>>> -			    vp->id, win->data->name, src_w);
>>>>>> -		src_w = ALIGN_DOWN(src_w, 4);
>>>>>> -	}
>>>>>> +	if (vop2->version == VOP_VERSION_RK3568 && drm_is_afbc(fb->modifier))
>>>>>> +		WARN_ON(src_w % 4);
>>>>>>  
>>>>>>  	act_info = (src_h - 1) << 16 | ((src_w - 1) & 0xffff);
>>>>>>  	dsp_info = (dsp_h - 1) << 16 | ((dsp_w - 1) & 0xffff);
>>>>>>
>>>>>
>>>>> You haven't replied to Andy's comment yet [0].
>>>>>
>>>>> [0] https://lore.kernel.org/dri-devel/7b4e26ec.75f3.19a77276b53.Coremail.andyshrk at 163.com/
>>>>>
>>>>
>>>> Hello,
>>>>
>>>> I addressed the follow-ups where it was clarified that the 4 pixel
>>>> limitation was RK3566/RK3568-only. I'm not going to bring back the
>>>> post-atomic_check modification for a fast path, but I'm open to
>>>> suggestions on how to do this differently.
>>>>
>>>> One solution might be to modify the state with the ALIGN_DOWN stuff
>>>> in atomic_check instead, where userspace is then aware of the change
>>>> being done to its requested parameters. I'll need to double-check
>>>> whether this is in line with atomic modesetting's design.
>>>>
>>>> Kind regards,
>>>> Nicolas Frattaroli
>>>
>>> Okay, so I've asked internally, and atomic_check isn't allowed to
>>> modify any of the parameters either. There's efforts [0] underway
>>> to allow error codes to be more specific, so that userspace knows
>>> which constraint is being violated. That would allow userspace
>>> applications to react by either adjusting their size or turning
>>> off AFBC in this case. Turning off AFBC seems more generally
>>> applicable here, since it means it won't need to resize the plane
>>> and it'll save more than enough memory bandwidth by not going
>>> through the GPU.
>>>
>>> On that note: Andy, I didn't find a weston-simple-egl test in the
>>> Weston 14.0.2 or git test suite, and weston-simple-egl itself does
>>> not tell me whether GPU compositing is being used or not. Do you
>>> have more information on how to test for this? I'd like to know
>>> for when we have the necessary functionality in place to make
>>> userspace smart enough to pick the fast path again.
>>>
>>
>> I think weston-simple-egl is part of the weston client. When you build
>> weston from source, you should obtain it. Just run `weston-simple-egl` 
>> after compile and install weston.
>>
>> And I guess you're using Debian... The weston package there also ships
>> with a weston-simple-egl binary [2].
> 
> Yeah, I know there's a tool called that, but I'm specifically curious
> about how to determine whether it's using GPU compositing or what I
> presume is fixed-function compositing.
> 
> When I enable some more logging with
> 
>   weston -l log,drm-backend,gl-renderer
> 
> and also some kms debug messages with
> 
>   echo 4 > /sys/module/drm/parameters/debug
> 
> then I see weston outputting
> 
> [atomic] drmModeAtomicCommit
>         [repaint] Using mixed state composition
>         [repaint] view 0xaaab18c00c10 using renderer composition
>         [repaint] view 0xaaab18b68f00 using renderer composition
>         [repaint] view 0xaaab18c00ec0 using renderer composition
> 
> regardless of whether the size is 250x250 or fullscreen. With
> 250x250, I know we're failing the plane check, because I see
> 
>   [  776.160101] rockchip-drm display-subsystem: [drm:vop2_plane_atomic_check
>                  [rockchipdrm]] AFBC source rectangles must be 4-pixel
>                  aligned; is 250
> 
> on the console, but with fullscreen I don't see any errors from plane-check
> as the src_w is now divisible by 4, yet it's also "using renderer composition"
> for all views.
> 
> Same goes for using `weston-simple-dmabuf-egl` (which is 256x256) instead of
> the fullscreen simple-egl.
> 
> So basically, I need to know where a change in behaviour is actually
> observed.
> 

Hmm, I don't think weston logs make this obvious. We also need the drm kms logs.

Test results may vary across different platforms. But it's certain that 
fullscreen and non-fullscreen modes are identical in the following respects:

- fullscreen: Try to use only one plane (may be AFBC) .
- non fullscreen: Try to use 2 plane (may be AFBC) .

- On the RK3588, we won't get two planes without modifying the code, because
the primary plane is already assign to AFBC background plane.
- On the RK356x, we'll get a primary plane in linear format, while
weston-simple-egl will use an overlay plane with AFBC format.
- On the RK3576, we should be able to obtain an AFBC primary plane and an AFBC
overlay plane.

Try to set env `export WESTON_LIBINPUT_LOG_PRIORITY=debug` and you will see
these log in non fullscreen mode:

```
Layer 5 (pos 0x50000000):
        View 0 (role xdg_toplevel, PID 686, surface ID 14, top-level window 'simple-egl' of org.freedesktop.weston.simple-egl, 0xaaaae61a62d0):

...

                        [view] evaluating view 0xaaaae61a62d0 for plane assignment on output HDMI-A-1 (0)
                        [plane] started with zpos 18446744073709551615
                                [primary] not assigning view 0xaaaae61a62d0 on primary, plane 33 (format ARGB8888 (0x34325241) with modifier 0x800000000000051) not supported
                                [primary] not assigning view 0xaaaae61a62d0 on primary, plane 39 (format ARGB8888 (0x34325241) with modifier 0x800000000000051) not supported
                                [overlay] not assigning view 0xaaaae61a62d0 on overlay, plane 63 (format ARGB8888 (0x34325241) with modifier 0x800000000000051) not supported
                                [overlay] not assigning view 0xaaaae61a62d0 on overlay, plane 69 (format ARGB8888 (0x34325241) with modifier 0x800000000000051) not supported
                                [overlay] not assigning view 0xaaaae61a62d0 on overlay, plane 75 (format ARGB8888 (0x34325241) with modifier 0x800000000000051) not supported
                        [view] view 0xaaaae61a62d0 format: ARGB8888
                                [plane] plane 51 picked from candidate list, type: overlay
```

When vop2_plane_atomic_check() fails, in addition to the above logs, you will
also get the following log:

```
[view] not placing view 0xaaaad9ec8e40 on plane 51: atomic test failed
```

I don't think there's any more log information that can indicate the error here.
The relevant code is here [3].

[3]: https://gitlab.freedesktop.org/wayland/weston/-/blob/main/libweston/backend-drm/state-propose.c?ref_type=heads#L181

>>
>> [1]: https://gitlab.freedesktop.org/wayland/weston/-/blob/main/clients/simple-egl.c
>> [2]: https://packages.debian.org/sid/arm64/weston/filelist
>>
>>> In either case, I think adhering to the atomic API to ensure
>>> artifact-free presentation is more important here than enabling
>>> a fast-path on RK3568. I do think in most real-world use case
>>> scenarios, the fallback won't degrade user experience, because
>>> almost everything performance intensive I can think of (video
>>> playback, games) will likely already use a plane geometry
>>> where the width is divisible by 4. 800, 1024, 1280, 1600, 1920,
>>> 2560, 3840 are all divisible by 4, so a window or full-screen
>>> playback of common content won't need to fall back to GPU
>>> compositing.
>>>
>>> I'll send a v2 to fix another instance of "eSmart" left in a
>>> message, but beyond that I think we should be good.
>>>
>>> Kind regards,
>>> Nicolas Frattaroli
>>>
>>> https://lore.kernel.org/dri-devel/20251009-atomic-v6-0-d209709cc3ba at intel.com/ [0]
>>>
>>>
>>>
>>>
>>
>>
> 
> 
> 
> 
> 
> 

-- 
Best, 
Chaoyi


From ronak.jain at amd.com  Fri Dec 12 02:05:40 2025
From: ronak.jain at amd.com (Ronak Jain)
Date: Fri, 12 Dec 2025 02:05:40 -0800
Subject: [PATCH v2 0/2] Update firmware dt-binding
Message-ID: <20251212100542.2756757-1-ronak.jain@amd.com>

The patch fixes/enhances below problems,
    1. Add missing compatible property under the example section for
    zynqmp_firmware node.
    2. Add conditional pinctrl schema

Changes in v2:
- Added acked-by signature in patch #1
- Following up on the queries again in patch #2. No code changes in
the patch itself
- Dropped off patch #3

Ronak Jain (2):
  dt-bindings: firmware: xilinx: Add xlnx,zynqmp-firmware compatible
  dt-bindings: firmware: xilinx: Add conditional pinctrl schema

 .../firmware/xilinx/xlnx,zynqmp-firmware.yaml | 21 ++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

-- 
2.34.1



From ronak.jain at amd.com  Fri Dec 12 02:05:41 2025
From: ronak.jain at amd.com (Ronak Jain)
Date: Fri, 12 Dec 2025 02:05:41 -0800
Subject: [PATCH v2 1/2] dt-bindings: firmware: xilinx: Add xlnx,zynqmp-firmware compatible
In-Reply-To: <20251212100542.2756757-1-ronak.jain@amd.com>
References: <20251212100542.2756757-1-ronak.jain@amd.com>
Message-ID: <20251212100542.2756757-2-ronak.jain@amd.com>

The absence of a compatible property caused dt_binding_check to skip
the zynqmp_firmware node.

To address this, add "xlnx,zynqmp-firmware" to the compatible property
in the example section for the zynqmp_firmware node.

Signed-off-by: Ronak Jain <ronak.jain at amd.com>
Acked-by: Rob Herring (Arm) <robh at kernel.org>
---
Changes in v2:
- Added acked-by signature
- No functional changes
---
 .../bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml           | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml b/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml
index bd413b6aeaf4..7020eeeb4ec0 100644
--- a/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml
+++ b/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml
@@ -124,6 +124,7 @@ examples:
     #include <dt-bindings/power/xlnx-zynqmp-power.h>
     firmware {
       zynqmp_firmware: zynqmp-firmware {
+        compatible = "xlnx,zynqmp-firmware";
         #power-domain-cells = <1>;
         soc-nvmem {
           compatible = "xlnx,zynqmp-nvmem-fw";
-- 
2.34.1



From ronak.jain at amd.com  Fri Dec 12 02:05:42 2025
From: ronak.jain at amd.com (Ronak Jain)
Date: Fri, 12 Dec 2025 02:05:42 -0800
Subject: [PATCH v2 2/2] dt-bindings: firmware: xilinx: Add conditional pinctrl schema
In-Reply-To: <20251212100542.2756757-1-ronak.jain@amd.com>
References: <20251212100542.2756757-1-ronak.jain@amd.com>
Message-ID: <20251212100542.2756757-3-ronak.jain@amd.com>

Updates the Device Tree bindings for Xilinx firmware by introducing
conditional schema references for the pinctrl node.

Previously, the pinctrl node directly referenced
xlnx,zynqmp-pinctrl.yaml. However, this patch modifies the schema to
conditionally apply the correct pinctrl schema based on the compatible
property. Specifically:
- If compatible contains "xlnx,zynqmp-pinctrl", reference
  xlnx,zynqmp-pinctrl.yaml.
- If compatible contains "xlnx,versal-pinctrl", reference
  xlnx,versal-pinctrl.yaml.

Additionally, an example entry for "xlnx,versal-pinctrl" has been
added under the examples section.

Signed-off-by: Ronak Jain <ronak.jain at amd.com>
---
Suggestion from Rob:

The somewhat preferred way to do this would be to do this in the top
level:

pinctrl:
  type: object
  additionalProperties: true
  properties:
    compatible:
      contains:
        enum:
          - xlnx,zynqmp-pinctrl
          - xlnx,versal-pinctrl
  required:
    - compatible

Otherwise, the pinctrl schema ends up being applied twice.


My response:

In your suggested code, the schema allows either xlnx,zynqmp-pinctrl
or xlnx,versal-pinctrl on any platform, which is incorrect. This
means that if a user mistakenly assigns xlnx,versal-pinctrl to a
ZynqMP platform or xlnx,zynqmp-pinctrl to a Versal platform, the
wrong reference will be used, but no error is reported. The
dt-binding check still passes instead of flagging this as an issue.

By using a conditional schema, we can enforce platform-specific
compatibility, ensuring that the correct compatible string is used
for the corresponding platform. This would also generate an error if
an incorrect compatible string is provided, preventing
misconfigurations.


Please review and let me know your thoughts.

---
 .../firmware/xilinx/xlnx,zynqmp-firmware.yaml | 20 ++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml b/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml
index 7020eeeb4ec0..c4a137f8e06e 100644
--- a/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml
+++ b/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml
@@ -79,7 +79,6 @@ properties:
     type: object
 
   pinctrl:
-    $ref: /schemas/pinctrl/xlnx,zynqmp-pinctrl.yaml#
     description: The pinctrl node provides access to pinconfig and pincontrol
       functionality available in firmware.
     type: object
@@ -114,6 +113,21 @@ properties:
     type: object
     deprecated: true
 
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: xlnx,zynqmp-firmware
+    then:
+      properties:
+        pinctrl:
+          $ref: /schemas/pinctrl/xlnx,zynqmp-pinctrl.yaml#
+    else:
+      properties:
+        pinctrl:
+          $ref: /schemas/pinctrl/xlnx,versal-pinctrl.yaml#
+
 required:
   - compatible
 
@@ -172,6 +186,10 @@ examples:
         compatible = "xlnx,versal-fpga";
       };
 
+      pinctrl {
+        compatible = "xlnx,versal-pinctrl";
+      };
+
       xlnx_aes: zynqmp-aes {
         compatible = "xlnx,zynqmp-aes";
       };
-- 
2.34.1



From peng.fan at oss.nxp.com  Fri Dec 12 02:08:25 2025
From: peng.fan at oss.nxp.com (Peng Fan)
Date: Fri, 12 Dec 2025 18:08:25 +0800
Subject: [PATCH v6 0/6] clk: Support spread spectrum and use it in
 clk-scmi
In-Reply-To: <20251128-clk-ssc-v6-2-v6-0-cfafdb5d6811@nxp.com>
References: <20251128-clk-ssc-v6-2-v6-0-cfafdb5d6811@nxp.com>
Message-ID: <aTvpmQAPE6HfIy+r@shlinux89>

Hi All,

Sorry for top-posting. There is only one comment from Krzysztof regarding
cleanup API usage. Since 6.19 rc1 still not out, I will wait two more weeks
to collect comments, then post v7. Hopefully, you are ok with current
clk-scmi-oem stuff.

Thanks,
Peng.

On Fri, Nov 28, 2025 at 11:14:09AM +0800, Peng Fan (OSS) wrote:
>Since the assigned-clock-sscs property [1] has been accepted into the device
>tree schema, we can now support it in the Linux clock driver. Therefore,
>I've picked up the previously submitted work [2] titled "clk: Support
>spread spectrum and use it in clk-pll144x and clk-scmi."
>As more than six months have passed since [2] was posted, I?m treating this
>patchset as a new submission rather than a v3.
>
>- Introduce clk_set_spread_spectrum to set the parameters for enabling
>  spread spectrum of a clock.
>- Parse 'assigned-clock-sscs' and configure it by default before using the
>  clock. This property is parsed before parsing clock rate.
>- Enable this feature for clk-scmi on i.MX95.
>
>Because SCMI spec will not include spread spectrum as a standard
>extension, we still need to use NXP i.MX OEM extension.
>
>[1] https://github.com/devicetree-org/dt-schema/pull/154
>[2] https://lore.kernel.org/all/20250205-clk-ssc-v2-0-fa73083caa92 at nxp.com/
>
>Signed-off-by: Peng Fan <peng.fan at nxp.com>
>---
>Changes in v6:
>- Add kunit build warning
>- Update OEM string comparation per Sebin
>
>Changes in v5:
>- Per Stephen, export clk_hw_set_spread_spectrum, use enum for method,
>  add const for set_spread_spectrum and rename clk_ss/conf to ss_conf.
>- Per Sebin, Cristian, Sudeep, I added clk-scmi-oem.c to support vendor
>  extensions.
>- Link to v4: https://lore.kernel.org/arm-scmi/aNQPWO6pfA_3mmxf at redhat.com/T/#me81231bf286e2a8e4e00a68707ed1e525a2b4a3d
>
>Changes in v4:
>- Add R-b for patch 1 from Brian
>- Drop unecessary change in patch 4 Per Brian
>- Link to v3: https://lore.kernel.org/r/20250912-clk-ssc-version1-v3-0-fd1e07476ba1 at nxp.com
>
>Changes in v3:
>- New patch 1 for dt-bindings per comment from Brian
>  https://lore.kernel.org/all/aLeEFzXkPog_dt2B at x1/
>  This might not be good to add a new dt-binding file in v3. But this is
>  quite a simple file that just has four macros to encode modulation
>  method. So hope this is fine for DT maintainers.
>- Add Brain's R-b for patch 2
>- New patch 3 to add Kunit test per Brain. Since Brain helped
>  draft part of the code, I added Co-developed-by tag from Brain.
>- Link to v2: https://lore.kernel.org/r/20250901-clk-ssc-version1-v2-0-1d0a486dffe6 at nxp.com
>
>Changes in v2:
>- Simplify the code in patch 2 per Dan Carpenter and Brian Masney
>- Rebased to next-20250829
>- Link to v1: https://lore.kernel.org/r/20250812-clk-ssc-version1-v1-0-cef60f20d770 at nxp.com
>
>---
>Peng Fan (6):
>      dt-bindings: clock: Add spread spectrum definition
>      clk: Introduce clk_hw_set_spread_spectrum
>      clk: conf: Support assigned-clock-sscs
>      clk: Add KUnit tests for assigned-clock-sscs
>      clk: scmi: Introduce common header for SCMI clock interface
>      clk: scmi: Add i.MX95 OEM extension support for SCMI clock driver
>
> drivers/clk/Makefile                               |   8 +-
> drivers/clk/clk-conf.c                             |  69 ++++++++++++
> drivers/clk/clk-scmi-oem.c                         | 103 ++++++++++++++++++
> drivers/clk/clk-scmi.c                             |  44 +++-----
> drivers/clk/clk-scmi.h                             |  51 +++++++++
> drivers/clk/clk.c                                  |  27 +++++
> drivers/clk/clk_test.c                             | 121 ++++++++++++++++++++-
> drivers/clk/kunit_clk_assigned_rates.h             |  10 ++
> drivers/clk/kunit_clk_assigned_rates_multiple.dtso |   6 +
> ...kunit_clk_assigned_rates_multiple_consumer.dtso |   6 +
> drivers/clk/kunit_clk_assigned_rates_one.dtso      |   3 +
> .../clk/kunit_clk_assigned_rates_one_consumer.dtso |   3 +
> .../clk/kunit_clk_assigned_rates_u64_multiple.dtso |   6 +
> ...t_clk_assigned_rates_u64_multiple_consumer.dtso |   6 +
> drivers/clk/kunit_clk_assigned_rates_u64_one.dtso  |   3 +
> .../kunit_clk_assigned_rates_u64_one_consumer.dtso |   3 +
> drivers/clk/kunit_clk_assigned_sscs_null.dtso      |  16 +++
> .../clk/kunit_clk_assigned_sscs_null_consumer.dtso |  20 ++++
> drivers/clk/kunit_clk_assigned_sscs_without.dtso   |  15 +++
> .../kunit_clk_assigned_sscs_without_consumer.dtso  |  19 ++++
> drivers/clk/kunit_clk_assigned_sscs_zero.dtso      |  12 ++
> .../clk/kunit_clk_assigned_sscs_zero_consumer.dtso |  16 +++
> include/dt-bindings/clock/clock.h                  |  14 +++
> include/linux/clk-provider.h                       |  31 ++++++
> 24 files changed, 580 insertions(+), 32 deletions(-)
>---
>base-commit: ef68bf704646690aba5e81c2f7be8d6ef13d7ad8
>change-id: 20251127-clk-ssc-v6-2-57658f944324
>
>Best regards,
>-- 
>Peng Fan <peng.fan at nxp.com>
>


From robert.marko at sartura.hr  Fri Dec 12 02:09:01 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Fri, 12 Dec 2025 11:09:01 +0100
Subject: [PATCH 2/4] dt-bindings: arm: Document Microchip LAN969x
In-Reply-To: <20251208-absolute-diploma-6575729ab43f@spud>
References: <20251203122313.1287950-1-robert.marko@sartura.hr>
 <20251203122313.1287950-2-robert.marko@sartura.hr> <20251203-duly-leotard-86b83bd840c6@spud>
 <CA+HBbNH6wO2VWOp1Dn52ArrYg6z89FgYnT3x-jsHsTVJ5xSBSA@mail.gmail.com> <20251208-absolute-diploma-6575729ab43f@spud>
Message-ID: <CA+HBbNHuYCq9oV4ZjWGjwnJM=oz-O85p_tqB+UnTBmivzDoowg@mail.gmail.com>

On Mon, Dec 8, 2025 at 6:10?PM Conor Dooley <conor at kernel.org> wrote:
>
> On Mon, Dec 08, 2025 at 11:30:28AM +0100, Robert Marko wrote:
> > On Wed, Dec 3, 2025 at 8:19?PM Conor Dooley <conor at kernel.org> wrote:
> > >
> > > On Wed, Dec 03, 2025 at 01:21:30PM +0100, Robert Marko wrote:
> > > > Microchip LAN969x is a series of multi-port, multi-gigabit switches based
> > > > on ARMv8 Cortex-A53 CPU.
> > > >
> > > > Signed-off-by: Robert Marko <robert.marko at sartura.hr>
> > > > ---
> > > >  .../bindings/arm/microchip,lan969x.yaml       | 32 +++++++++++++++++++
> > >
> > > This should not be in a unique file, put it in with the other microchip
> > > arm devices please. Also, the wildcard in the compatible is not
> > > permitted, only way it'd make sense is if these are different binnings
> > > of the same silicon. If that's the case, you need to explain why,
> > > because compatibles are meant to be soc-specific.
> >
> > Hi Conor,
> > The issue is that there is no unique place for Microchip SoC-s,
> > LAN966x series is in the AT91 bindings
> > while SparX-5 has its own bindings file.
> >
> > What would you suggest in this case?
>
> Ideally, arm/atmel-at91.yaml and arm/microchip,sparx5.yaml would just
> become arm/microchip.yaml. The axi at 600000000 thing in the sparx5 file
> looks pointless and can be deleted IMO.

Ok, I merged them all in one generic microchip.yaml binding, but I noticed that
arm/atmel-at91.yaml is licensed under GPL-2.0 while arm/microchip,sparx5.yaml
is dual-licensed as its preferred for bindings.

Is that going to be an issue?

Regards,
Robert
>


-- 
Robert Marko
Staff Embedded Linux Engineer
Sartura d.d.
Lendavska ulica 16a
10000 Zagreb, Croatia
Email: robert.marko at sartura.hr
Web: www.sartura.hr


From brgl at kernel.org  Fri Dec 12 02:11:11 2025
From: brgl at kernel.org (Bartosz Golaszewski)
Date: Fri, 12 Dec 2025 02:11:11 -0800
Subject: [PATCH 6/8] gpio: aaeon: Add GPIO driver for SRG-IMX8PL MCU
In-Reply-To: <20251212-dev-b4-aaeon-mcu-driver-v1-6-6bd65bc8ef12@bootlin.com>
References: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com> <20251212-dev-b4-aaeon-mcu-driver-v1-6-6bd65bc8ef12@bootlin.com>
Message-ID: <CAMRc=McSHcYfz2L-jeJa9Dnb=fp8ACRAwNtDJmHEMQ3b+BOd+A@mail.gmail.com>

On Fri, 12 Dec 2025 08:41:09 +0100, "Thomas Perrot (Schneider
Electric)" <thomas.perrot at bootlin.com> said:
> Add GPIO driver for the Aaeon SRG-IMX8PL embedded controller. This
> driver supports 7 GPO (General Purpose Output) pins and 12 GPIO pins
> that can be configured as inputs or outputs.
>
> The driver implements proper state management for GPO pins (which are
> output-only) and full direction control for GPIO pins. During probe,
> all pins are reset to a known state (GPOs low, GPIOs as inputs) to
> prevent undefined behavior across system reboots, as the MCU does not
> reset GPIO states on soft reboot.
>
> Co-developed-by: J?r?mie Dautheribes (Schneider Electric) <jeremie.dautheribes at bootlin.com>
> Signed-off-by: J?r?mie Dautheribes (Schneider Electric) <jeremie.dautheribes at bootlin.com>
> Signed-off-by: Thomas Perrot (Schneider Electric) <thomas.perrot at bootlin.com>
> ---
>  drivers/gpio/Kconfig          |  10 ++
>  drivers/gpio/Makefile         |   1 +
>  drivers/gpio/gpio-aaeon-mcu.c | 248 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 259 insertions(+)
>
> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> index c74da29253e810b51540684b1186e8f274066b69..7e0f675b664fa25243fc2802edc3380572c94c41 100644
> --- a/drivers/gpio/Kconfig
> +++ b/drivers/gpio/Kconfig
> @@ -157,6 +157,16 @@ config GPIO_74XX_MMIO
>  	    8 bits:	74244 (Input), 74273 (Output)
>  	    16 bits:	741624 (Input), 7416374 (Output)
>
> +config GPIO_AAEON_MCU
> +	tristate "Aaeon MCU GPIO support"
> +	depends on MFD_AAEON_MCU && OF_GPIO

You don't need OF_GPIO, please drop it.

> +	select GPIO_GENERIC
> +	help
> +	  Select this option to enable GPIO support for the Aaeon SRG-IMX8PL
> +	  onboard MCU. This driver provides access to GPIO pins and GPO
> +	  (General Purpose Output) pins controlled by the microcontroller.
> +	  The driver handles both input and output configuration.
> +
>  config GPIO_ALTERA
>  	tristate "Altera GPIO"
>  	select GPIOLIB_IRQCHIP
> diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
> index 2421a8fd3733e0b06c2581262aaa9cd629f66c7d..1ba6318bc558743fbe5910966c2c8fc3f792efe9 100644
> --- a/drivers/gpio/Makefile
> +++ b/drivers/gpio/Makefile
> @@ -29,6 +29,7 @@ obj-$(CONFIG_GPIO_104_IDI_48)		+= gpio-104-idi-48.o
>  obj-$(CONFIG_GPIO_104_IDIO_16)		+= gpio-104-idio-16.o
>  obj-$(CONFIG_GPIO_74X164)		+= gpio-74x164.o
>  obj-$(CONFIG_GPIO_74XX_MMIO)		+= gpio-74xx-mmio.o
> +obj-$(CONFIG_GPIO_AAEON_MCU)		+= gpio-aaeon-mcu.o
>  obj-$(CONFIG_GPIO_ADNP)			+= gpio-adnp.o
>  obj-$(CONFIG_GPIO_ADP5520)		+= gpio-adp5520.o
>  obj-$(CONFIG_GPIO_ADP5585)		+= gpio-adp5585.o
> diff --git a/drivers/gpio/gpio-aaeon-mcu.c b/drivers/gpio/gpio-aaeon-mcu.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..cebd17d1877147b987ea673b081334c8062f5fc0
> --- /dev/null
> +++ b/drivers/gpio/gpio-aaeon-mcu.c
> @@ -0,0 +1,248 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Aaeon MCU GPIO driver
> + *
> + * Copyright (C) 2025 Bootlin
> + * Author: J?r?mie Dautheribes <jeremie.dautheribes at bootlin.com>
> + * Author: Thomas Perrot <thomas.perrot at bootlin.com>
> + */
> +
> +#include <linux/bitmap.h>
> +#include <linux/gpio/driver.h>
> +#include <linux/mfd/aaeon-mcu.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>

You need more headers than that. At least device.h for devm_kzalloc(),
mod_devicetable.h, bitops.h and probably some more.

> +
> +#define AAEON_MCU_CONFIG_GPIO_INPUT 0x69
> +#define AAEON_MCU_CONFIG_GPIO_OUTPUT 0x6F
> +#define AAEON_MCU_READ_GPIO 0x72
> +#define AAEON_MCU_WRITE_GPIO 0x77
> +
> +#define AAEON_MCU_CONTROL_GPO 0x6C
> +
> +#define MAX_GPIOS 12
> +#define MAX_GPOS 7
> +
> +struct aaeon_mcu_gpio {
> +	struct gpio_chip gc;
> +	struct aaeon_mcu_dev *mfd;
> +	DECLARE_BITMAP(dir_in, MAX_GPOS + MAX_GPIOS);
> +	DECLARE_BITMAP(gpo_state, MAX_GPOS);
> +};
> +
> +static int aaeon_mcu_gpio_config_input_cmd(struct aaeon_mcu_gpio *data,
> +					    unsigned int offset)
> +{
> +	u8 cmd[3], rsp;
> +
> +	cmd[0] = AAEON_MCU_CONFIG_GPIO_INPUT;
> +	cmd[1] = offset - 7;
> +	cmd[2] = 0x00;
> +
> +	return aaeon_mcu_i2c_xfer(data->mfd->i2c_client, cmd, 3, &rsp, 1);
> +}
> +
> +static int aaeon_mcu_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)
> +{
> +	struct aaeon_mcu_gpio *data = gpiochip_get_data(gc);
> +	int ret;
> +
> +	if (offset < MAX_GPOS) {
> +		dev_err(gc->parent, "GPIO offset (%d) must be an output GPO\n", offset);
> +		return -EOPNOTSUPP;
> +	}
> +
> +	ret = aaeon_mcu_gpio_config_input_cmd(data, offset);
> +	if (ret < 0)
> +		return ret;
> +
> +	set_bit(offset, data->dir_in);
> +
> +	return 0;
> +}
> +
> +static int aaeon_mcu_gpio_config_output_cmd(struct aaeon_mcu_gpio *data,
> +					     unsigned int offset,
> +					     int value)
> +{
> +	u8 cmd[3], rsp;
> +	int ret;
> +
> +	cmd[0] = AAEON_MCU_CONFIG_GPIO_OUTPUT;
> +	cmd[1] = offset - 7;
> +	cmd[2] = 0x00;
> +
> +	ret = aaeon_mcu_i2c_xfer(data->mfd->i2c_client, cmd, 3, &rsp, 1);
> +	if (ret < 0)
> +		return ret;
> +
> +	cmd[0] = AAEON_MCU_WRITE_GPIO;
> +	/* cmd[1] = offset - 7; */
> +	cmd[2] = !!value;
> +
> +	return aaeon_mcu_i2c_xfer(data->mfd->i2c_client, cmd, 3, &rsp, 1);
> +}
> +
> +static int aaeon_mcu_gpio_direction_output(struct gpio_chip *gc, unsigned int offset, int value)
> +{
> +	struct aaeon_mcu_gpio *data = gpiochip_get_data(gc);
> +	int ret;
> +
> +	if (offset < MAX_GPOS)
> +		return 0;
> +
> +	ret = aaeon_mcu_gpio_config_output_cmd(data, offset, value);
> +	if (ret < 0)
> +		return ret;
> +
> +	clear_bit(offset, data->dir_in);
> +
> +	return 0;
> +}
> +
> +static int aaeon_mcu_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
> +{
> +	struct aaeon_mcu_gpio *data = gpiochip_get_data(gc);
> +
> +	return test_bit(offset, data->dir_in) ?
> +		GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT;
> +}
> +
> +static int aaeon_mcu_gpio_get(struct gpio_chip *gc, unsigned int offset)
> +{
> +	struct aaeon_mcu_gpio *data = gpiochip_get_data(gc);
> +	u8 cmd[3], rsp;
> +	int ret;
> +
> +	if (offset < MAX_GPOS)
> +		return test_bit(offset, data->gpo_state);

Are you sure the bit ops in this driver need to be atomic?

> +
> +	cmd[0] = AAEON_MCU_READ_GPIO;
> +	cmd[1] = offset - 7;
> +	cmd[2] = 0x00;
> +
> +	ret = aaeon_mcu_i2c_xfer(data->mfd->i2c_client, cmd, 3, &rsp, 1);
> +	if (ret < 0)
> +		return ret;
> +
> +	return rsp;
> +}
> +
> +static int aaeon_mcu_gpo_set_cmd(struct aaeon_mcu_gpio *data, unsigned int offset, int value)
> +{
> +	u8 cmd[3], rsp;
> +
> +	cmd[0] = AAEON_MCU_CONTROL_GPO;
> +	cmd[1] = offset + 1;
> +	cmd[2] = !!value;
> +
> +	return aaeon_mcu_i2c_xfer(data->mfd->i2c_client, cmd, 3, &rsp, 1);
> +}
> +
> +static int aaeon_mcu_gpio_set_cmd(struct aaeon_mcu_gpio *data, unsigned int offset, int value)
> +{
> +	u8 cmd[3], rsp;
> +
> +	cmd[0] = AAEON_MCU_WRITE_GPIO;
> +	cmd[1] = offset - 7;
> +	cmd[2] = !!value;
> +
> +	return aaeon_mcu_i2c_xfer(data->mfd->i2c_client, cmd, 3, &rsp, 1);
> +}
> +
> +static int aaeon_mcu_gpio_set(struct gpio_chip *gc, unsigned int offset,
> +			      int value)
> +{
> +	struct aaeon_mcu_gpio *data = gpiochip_get_data(gc);
> +
> +	if (offset < MAX_GPOS) {
> +		if (aaeon_mcu_gpo_set_cmd(data, offset, value) == 0)
> +			assign_bit(offset, data->gpo_state, value);
> +	} else {
> +		return aaeon_mcu_gpio_set_cmd(data, offset, value);
> +	}
> +	return 0;


It would be much cleaner if you did it like:

	if (offset >= MAX_GPOS)
		return aaeon_mcu_gpio_set_cmd(data, offset, value);

	if (aaeon_mcu_gpo_set_cmd(data, offset, value) == 0)
		assign_bit(offset, data->gpo_state, value);

	return 0;

> +}
> +
> +static const struct gpio_chip aaeon_mcu_chip = {
> +	.label			= "gpio-aaeon-mcu",
> +	.owner			= THIS_MODULE,
> +	.get_direction		= aaeon_mcu_gpio_get_direction,
> +	.direction_input	= aaeon_mcu_gpio_direction_input,
> +	.direction_output	= aaeon_mcu_gpio_direction_output,
> +	.get			= aaeon_mcu_gpio_get,
> +	.set			= aaeon_mcu_gpio_set,
> +	.base			= -1,
> +	.ngpio			= MAX_GPOS + MAX_GPIOS,
> +	.can_sleep		= true,
> +};

There's no point in keeping it in memory if you copy it into data->gc anyway.
Use compound literals in aaeon_mcu_gpio_probe() if you want to initialize
members explicitly.

> +
> +static void aaeon_mcu_gpio_reset(struct aaeon_mcu_gpio *data, struct device *dev)
> +{
> +	unsigned int i;
> +	int ret;
> +
> +	/* Reset all GPOs */
> +	for (i = 0; i < MAX_GPOS; i++) {
> +		ret = aaeon_mcu_gpo_set_cmd(data, i, 0);
> +		if (ret < 0)
> +			dev_warn(dev, "Failed to reset GPO %u state: %d\n", i, ret);
> +		clear_bit(i, data->dir_in);
> +	}
> +
> +	/* Reset all GPIOs */
> +	for (i = MAX_GPOS; i < MAX_GPOS + MAX_GPIOS; i++) {
> +		ret = aaeon_mcu_gpio_config_input_cmd(data, i);
> +		if (ret < 0)
> +			dev_warn(dev, "Failed to reset GPIO %u state: %d\n", i, ret);
> +		set_bit(i, data->dir_in);
> +	}
> +}
> +
> +static int aaeon_mcu_gpio_probe(struct platform_device *pdev)
> +{
> +	struct aaeon_mcu_dev *mfd = dev_get_drvdata(pdev->dev.parent);
> +	struct aaeon_mcu_gpio *data;
> +
> +	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	data->mfd = mfd;

It looks like all you need is the i2c_client, maybe just store its address and
avoid constant dereferencing.

> +	data->gc = aaeon_mcu_chip;
> +	data->gc.parent = &pdev->dev;
> +
> +	/*
> +	 * Reset all GPIO states to a known configuration. The MCU does not
> +	 * reset GPIO state on soft reboot, only on power cycle (hard reboot).
> +	 * Without this reset, GPIOs would retain their previous state across
> +	 * reboots, which could lead to unexpected behavior.
> +	 */
> +	aaeon_mcu_gpio_reset(data, &pdev->dev);
> +
> +	platform_set_drvdata(pdev, data);

Where is the corresponding call to platform_get_drvdata()?

> +
> +	return devm_gpiochip_add_data(&pdev->dev, &data->gc,
> +				      data);
> +}
> +
> +static const struct of_device_id aaeon_mcu_gpio_of_match[] = {
> +	{ .compatible = "aaeon,srg-imx8pl-gpio" },
> +	{},
> +};
> +
> +MODULE_DEVICE_TABLE(of, aaeon_mcu_gpio_of_match);
> +
> +static struct platform_driver aaeon_mcu_gpio_driver = {
> +	.driver = {
> +		.name = "aaeon-mcu-gpio",
> +		.of_match_table = aaeon_mcu_gpio_of_match,
> +	},
> +	.probe = aaeon_mcu_gpio_probe,
> +};
> +
> +module_platform_driver(aaeon_mcu_gpio_driver);
> +
> +MODULE_DESCRIPTION("GPIO interface for Aaeon MCU");
> +MODULE_AUTHOR("J?r?mie Dautherbes <jeremie.dautheribes at bootlin.com>");
> +MODULE_LICENSE("GPL");
>
> --
> 2.52.0
>
>

Bart


From alexandru.elisei at arm.com  Fri Dec 12 02:18:27 2025
From: alexandru.elisei at arm.com (Alexandru Elisei)
Date: Fri, 12 Dec 2025 10:18:27 +0000
Subject: [RFC PATCH v6 00/35] KVM: arm64: Add Statistical Profiling
 Extension (SPE) support
In-Reply-To: <20251211163425.GA4113166@e132581.arm.com>
References: <20251114160717.163230-1-alexandru.elisei@arm.com>
 <20251211163425.GA4113166@e132581.arm.com>
Message-ID: <aTvr8_xjoKY6pB8P@raptor>

Hi Leo,

On Thu, Dec 11, 2025 at 04:34:25PM +0000, Leo Yan wrote:
> Hi Alexandru,
> 
> Just couples general questions for myself to easier understand the series
> (sorry if I asked duplicated questions).
> 
> > I wanted the focus to be on pinning memory at stage 2 (that's patches #29, 'KVM:
> > arm64: Pin the SPE buffer in the host and map it at stage 2', to #3, 'KVM:
> > arm64: Add hugetlb support for SPE') and I would very much like to start a
> > discussion around that.
> 
> I am confused for "pinning memory at stage 2" and then I read "Pin the
> SPE buffer in the host".  I read Chapter 2 Specification, ARM DEN 0154,
> my conclusion is:
> 
> 1) You set PMBLIMITR_EL1.nVM == 0 (virtual address mode) so that the
>    driver uses the same mode whether it is running in a host or in a
>    guest.

KVM does not advertise FEAT_SPE_nVM and treats PMBLIMITR_EL1.nVM as RES0 on a
guest access. The value of PMSCR_EL2.EnVM is always zero while a guest is
running.

So yes, and the Linux driver is not aware of physical addressing mode and
that's what I used for testing.

> 
> 2) The KVM hypervisor needs to parse the VA -> IPA -> PA with:
> 
>    Guest stage-1 table (managed in guest OS);

Yes.

>    Guest stage-2 table (managed in KVM hypervisor);

Yes.

> 
> 3) In the end, the KVM hypervisor pins physical pages on the host
>    stage-1 page table for:

By 'pin' meaning using pin_user_pages(), yes.

> 
>    The physical pages are pinned for Guest stage-1 table;

Yes.

>    The physical pages are pinned for Guest stage-2 table;

Yes and no. The pages allocated for the stage 2 translation tables are not
mapped in the host's userspace, they are mapped in the kernel linear address
space. This means that they are not subject to migration/swap/compaction/etc,
they will only be reused after KVM frees them.

But that's how KVM manages stage 2 for all VMs, so maybe I misunderstood what
you were saying.

>    The physical pages are pinned for used for TRBE buffer in guest.

SPE, but yes, the same principle.

> 
> Due the host might migrate or swap pages, so all the pin operations
> happen on the host's page table.  The pin operations never to be set up
> in guest's stage-2 table, right?

I'm not sure what you mean.

> 
> > The problem
> > ===========
> > 
> > When the Statistical Profiling Unit (SPU from now on) encounter a fault when
> > it attempts to write a record to memory, two things happen: profiling is
> > stopped, and the fault is reported to the CPU via an interrupt, not an
> > exception. This creates a blackout window during which the CPU executes
> > instructions which aren't profiled. The SPE driver avoid this by keeping the
> > buffer mapped while ProfilingBufferEnabled() = true. But when running as a
> > guest under KVM, the SPU will trigger stage 2 faults, with the associated
> > blackout windows.
> 
> My understanding is that there are two prominent challenges for SPE
> virtualization:
> 
> 1) Allocation: we need to allocate trace buffer with mapping both
>    guest's stage-1 and stage-2 before enabling SPU.  (For me, the free

It's the guest responsibility to map the buffer in the guest stage 1 before
enabling it. When the guest enables the buffer, KVM walks the guest's stage 1
and if it doesn't find a translation for a buffer guest VA, it will inject a
profiling buffer management event to the guest, with EC stage 1 data abort.

If the buffer was mapped in the guest stage 1 when the guest enabled the buffer,
but at same point in the future the guest unmaps the buffer from stage 1, the
statistical profiling unit might encounter a stage 1 data abort when attempting
to write to memory. If that's the case, the interrupt is taken by the host, and
KVM will inject the buffer management event back to the guest.

>    buffer is never an issue as we always disable the SPU before
>    releasing the resource).
> 
> 2) Pin: the physical pages used by trace buffer and the relevant stage-1
>    and stage-2 tables must be pinned during the session.

If by pinning you mean pin_user_pages() and friends, then KVM does not need to
do that for the stage 2 tables, pin_user_pages() makes sense only for userspace
addresses.

Thanks,
Alex


From andrea.porta at suse.com  Fri Dec 12 02:25:51 2025
From: andrea.porta at suse.com (Andrea della Porta)
Date: Fri, 12 Dec 2025 11:25:51 +0100
Subject: [PATCH v2] arm64: dts: broadcom: bcm2712: rpi-5: Add ethernet0
 alias
In-Reply-To: <20251212023749.GF28411@pendragon.ideasonboard.com>
References: <20251102111443.18206-1-laurent.pinchart@ideasonboard.com>
 <CAL_JsqJg4aYGyd49UAAPBw+FGpmGxV5JkdkXp2FK_7Gt+7DLZA@mail.gmail.com>
 <20251212023749.GF28411@pendragon.ideasonboard.com>
Message-ID: <aTvtr5v4DjuqctdY@apocalypse>

Hi Laurent, Rob,

On 11:37 Fri 12 Dec     , Laurent Pinchart wrote:
> Hi Rob,
> 
> On Thu, Dec 11, 2025 at 12:42:40PM -0600, Rob Herring wrote:
> > On Sun, Nov 2, 2025 at 5:15?AM Laurent Pinchart wrote:
> > >
> > > The RP1 ethernet controller DT node contains a local-mac-address
> > > property to pass the MAC address from the boot loader to the kernel. The
> > > boot loader does not fill the MAC address as the ethernet0 alias is
> > > missing. Add it.
> > 
> > My change here[1] is going to effectively revert this.
> 
> :-(
> 
> > The RP1 stuff
> > needs to either be an overlay or not. We don't need both ways.
> > /aliases don't work for overlays. I suppose that could be added as a
> > fixup when applying. The kernel also assumes aliases are not dynamic
> > and uses indexes which aren't present, so even if it did work there
> > would still be problems. OTOH, if the bootloader might use the
> > ethernet controller, then why would this ever be an overlay in the
> > first place?
> > 
> > Turns out digging into RP1 stuff, it is a mess and needs reworking[2].

I'm currently working on it.

> 
> I don't have a strong opinion personally. As far as I understand from
> https://lore.kernel.org/all/cover.1748526284.git.andrea.porta at suse.com/,
> non-overlay support was added for compatibility with downstream. I don't
> know why the overlay option was considered better for upstream. Andrea,
> could you comment on this ?

The overlay support was initially conceived for three main reasons:

- it was mildly asked for the driver to work also on ACPI based system. It was
  not clear if the ACPI tables would also include entries for the RP1 so I
  assumeed they did not (which would be most probably the case). I'm not aware
  of any hw which complies with these scenario.

- there was a non zero (even though close to zero) chance that RP1 could be used
  on other appliances (i.e. some PCI cards), which makes teh overlay approach 
  appealing. Again, I'm not aware of any real existing hw, if ever.

- paving the way already opened by Bootlin's LAN driver seemed IMHO a good thing
  to pursue (I would say that drivers for FPGA peripherals could benefit the most
  from this approach but there could be others), so why not kicking it off with
  this driver.

Unfortunately, the overlay support is not fully working for all but the simplest
peripherals that requires referencing their nodes from the main DTB, for reasons
debated starting from this thread [1].

This is why the full DT has been provided as the default. Now that I see that the
overlay support is causing a lot of pain and concerns, I'm planning to evict it
in favor of the full DT only, overlay is not used anyway and will not be functional
until we solve all those issues which could be in a very long time, if ever feasible.

> 
> > Right now, I just want the warning gone so I don't get further complaints[3].

I'm also on this. Please provide a priority between fixing this warning (I need to
do a round of tests) and fixing the RP1 DT hierarchy (there will be changes in
both DT and driver code).

Many thanks,
Andrea

[1] - https://lore.kernel.org/all/CAMEGJJ3=W8_R0xBvm8r+Q7iExZx8xPBHEWWGAT9ngpGWDSKCaQ at mail.gmail.com/

> > 
> > Rob
> > 
> > [1] https://lore.kernel.org/all/20251117211503.728354-2-robh at kernel.org/
> > [2] https://lore.kernel.org/all/CAL_JsqJUzB71QdMcxJtNZ7raoPcK+SfTh7EVzGmk=syo8xLKQw at mail.gmail.com/
> > [3] https://lore.kernel.org/all/CAHk-=wi+ge-gtCg+iLd6dgjisGchjtsKY8AXG9tXGOxqVv8Fkw at mail.gmail.com/
> 
> -- 
> Regards,
> 
> Laurent Pinchart


From quentin.schulz at cherry.de  Fri Dec 12 02:25:35 2025
From: quentin.schulz at cherry.de (Quentin Schulz)
Date: Fri, 12 Dec 2025 11:25:35 +0100
Subject: Issues with DRM_ACCEL_ROCKET (Oops, power-domain, probe-ordering)
In-Reply-To: <CAAObsKBneQrciukH-eZ8qY92n1YxRFChpXV9s6G8oQP5jSMwRA@mail.gmail.com>
References: <0b20d760-ad4f-41c0-b733-39db10d6cc41@cherry.de>
 <77685900-2c34-49b8-8c7e-14718841ef17@rock-chips.com>
 <fa82d11f-ce11-4feb-bdb4-c31d360a2a62@rock-chips.com>
 <CAAObsKDYLXVf1GdYUNeaOya+pWD4jTOEf55ouXAL9iM_kWCcMw@mail.gmail.com>
 <75166475-d6a8-45b8-8092-f31d292d4206@rock-chips.com>
 <CAAObsKABYQnw9rUfxwTS-yiQSoH9rdxZ_ffUBtp2H3tMJqMb7w@mail.gmail.com>
 <e7b2ceaf-1fbd-4f02-9d75-be4feab724e3@rock-chips.com>
 <CAAObsKBneQrciukH-eZ8qY92n1YxRFChpXV9s6G8oQP5jSMwRA@mail.gmail.com>
Message-ID: <f752d42c-5f1c-48f2-92d1-f63d772ca1d4@cherry.de>

Hi Tomeu,

On 12/10/25 5:39 PM, Tomeu Vizoso wrote:
> [You don't often get email from tomeu at tomeuvizoso.net. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
> 
> On Wed, Dec 10, 2025 at 11:47?AM Chaoyi Chen <chaoyi.chen at rock-chips.com> wrote:
>>
>> Hello Tomeu,
>>
>> On 12/10/2025 2:50 PM, Tomeu Vizoso wrote:
>>> On Tue, Dec 9, 2025 at 10:31?AM Chaoyi Chen <chaoyi.chen at rock-chips.com> wrote:
>>>>
>>>> Hello Tomeu,
>>>>
>>>> On 12/9/2025 2:55 PM, Tomeu Vizoso wrote:
>>>>> On Tue, Dec 2, 2025 at 8:00?AM Chaoyi Chen <chaoyi.chen at rock-chips.com> wrote:
>>>>
>>>> [...]
>>>>
>>>>>
>>>>> This need was questioned during the review process, and during my
>>>>> stress testing I didn't find a need for core 0 to be treated
>>>>> specially. So it was considered unneeded complexity and the code was
>>>>> dropped.
>>>>>
>>>>
>>>> Oh, I just noticed that the commit comment in the devicetree still
>>>> contains a relevant description.
>>>>
>>>>> My testing involves running the supported models as a whole, and also
>>>>> their individual operations as individual tests. I run them in 8
>>>>> parallel processes, in batches so we have continuous bring up and down
>>>>> of clients.
>>>>>
>>>>> I'm a bit surprised that that testing worked stably but we have still
>>>>> failures in some setups.
>>>>
>>>> Could you please describe the failures that still exist? Thank you.
>>>
>>> I was referring to the ones that Quentin reported when starting this thread.
>>>
>>
>> I believe this pmdomain patch can alleviate some of the problems [0].
>>
>> However, the problem Quentin mentioned still exists. For example, if
>> there is an invalid device on core0, while core1 and core2 are valid,
>> accessing the relevant data on core0 will cause problems. Quentin's
>> patch can fix this, but he doesn't seem to have time for it lately...
> 
> Has anybody reproduced this problem with the pmdomain fix applied?
> 

If I've written my reboot-loop script properly, 715 successful boots and 
0 failed, so I guess this works.

The script:
"""
#!/usr/bin/env bash

set -ux

myreboot() {
	/bin/sync
	echo rebooting
	echo 1 > /proc/sys/kernel/sysrq
	echo b > /proc/sysrq-trigger
}

mount -t proc none /proc
mount -t sysfs none /sys

FAIL_TXT=/root/fail.txt
SUCCESS_TXT=/root/success.txt

[ -d /sys/bus/platform/drivers/rocket/fdab0000.npu/ ] && [ -d 
/sys/bus/platform/drivers/rocket/fdac0000.npu/ ] && [ -d 
/sys/bus/platform/drivers/rocket/fdad0000.npu/ ]
RES=$?
if [ $RES -ne 0 ]; then
	VAL=$(cat $FAIL_TXT)
	VAL=$(( VAL + 1 ))
	echo -n $VAL > $FAIL_TXT
	echo "FAILED!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
	myreboot
fi
TEFLON_DEBUG=verbose /root/mesa/venv/bin/python3 
/root/mesa/src/gallium/frontends/teflon/tests/classification.py -i 
/root/mesa/grace_hopper.bmp -m 
/root/mesa/src/gallium/targets/teflon/tests/models/mobilenetv1/mobilenet_v1_1_224_quant.tflite 
-l 
/root/mesa/src/gallium/frontends/teflon/tests/labels_mobilenet_quant_v1_224.txt 
-e /root/mesa/builddir/src/gallium/targets/teflon/libteflon.so
RES=$?
if [ $RES -ne 0 ]; then
	VAL=$(cat $FAIL_TXT)
	VAL=$(( VAL + 1 ))
	echo -n $VAL > $FAIL_TXT
	echo "FAILED!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
else
	VAL=$(cat $SUCCESS_TXT)
	VAL=$(( VAL + 1 ))
	echo -n $VAL > $SUCCESS_TXT
fi
myreboot
"""

Seems like the cores are always listed in 
/sys/bus/platform/drivers/rocket/ even when one fails to probe, but then 
classification.py triggers an Oops and it seems the exit code of that 
script is not 0 when it happens. This info was gathered from the one 
boot I tested *without* the patch applied.

Cheers,
Quentin


From alexandru.elisei at arm.com  Fri Dec 12 02:30:54 2025
From: alexandru.elisei at arm.com (Alexandru Elisei)
Date: Fri, 12 Dec 2025 10:30:54 +0000
Subject: [PATCH 1/2] KVM: arm64: Copy FGT traps to unprotected pKVM VCPU
 on VCPU load
In-Reply-To: <aTsrMUGan1AH5suO@google.com>
References: <20251210132102.137631-1-alexandru.elisei@arm.com>
 <20251210132102.137631-2-alexandru.elisei@arm.com>
 <aTsrMUGan1AH5suO@google.com>
Message-ID: <aTvu3tbCpztzj8bm@raptor>

Hi Will,

On Fri, Dec 12, 2025 at 05:36:01AM +0900, Will Deacon wrote:
> Hey Alexandru,
> 
> [+Fuad as we ran into this last week]
> 
> On Wed, Dec 10, 2025 at 01:21:01PM +0000, Alexandru Elisei wrote:
> > Commit fb10ddf35c1c ("KVM: arm64: Compute per-vCPU FGTs at vcpu_load()")
> > introduced per-VCPU FGT traps. For an unprotected pKVM VCPU, the untrusted
> > host FGT configuration is copied in pkvm_vcpu_init_traps(), which is called
> > from __pkvm_init_vcpu(). __pkvm_init_vcpu() is called once per VCPU (when
> > the VCPU is first run) which means that the uninitialized, zero, values for
> > the FGT registers end up being used for the entire lifetime of the VCPU.
> > This causes both unwanted traps (for the inverse polarity trap bits) and
> > the guest being allowed to access registers it shouldn't.
> > 
> > Fix it by copying the FGT traps for unprotected pKVM VCPUs when the
> > untrusted host loads the VCPU.
> > 
> > Fixes: fb10ddf35c1c ("KVM: arm64: Compute per-vCPU FGTs at vcpu_load()")
> > Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
> > ---
> >  arch/arm64/kvm/hyp/nvhe/hyp-main.c | 12 ++++++++++--
> >  arch/arm64/kvm/hyp/nvhe/pkvm.c     |  1 -
> >  2 files changed, 10 insertions(+), 3 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > index 29430c031095..ee0f1343100c 100644
> > --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > @@ -167,6 +167,7 @@ static void handle___pkvm_vcpu_load(struct kvm_cpu_context *host_ctxt)
> >  	DECLARE_REG(unsigned int, vcpu_idx, host_ctxt, 2);
> >  	DECLARE_REG(u64, hcr_el2, host_ctxt, 3);
> >  	struct pkvm_hyp_vcpu *hyp_vcpu;
> > +	struct kvm_vcpu *hyp_kvm_vcpu;
> >  
> >  	if (!is_protected_kvm_enabled())
> >  		return;
> > @@ -175,10 +176,17 @@ static void handle___pkvm_vcpu_load(struct kvm_cpu_context *host_ctxt)
> >  	if (!hyp_vcpu)
> >  		return;
> >  
> > +	hyp_kvm_vcpu = &hyp_vcpu->vcpu;
> > +
> >  	if (pkvm_hyp_vcpu_is_protected(hyp_vcpu)) {
> >  		/* Propagate WFx trapping flags */
> > -		hyp_vcpu->vcpu.arch.hcr_el2 &= ~(HCR_TWE | HCR_TWI);
> > -		hyp_vcpu->vcpu.arch.hcr_el2 |= hcr_el2 & (HCR_TWE | HCR_TWI);
> > +		hyp_kvm_vcpu->arch.hcr_el2 &= ~(HCR_TWE | HCR_TWI);
> > +		hyp_kvm_vcpu->arch.hcr_el2 |= hcr_el2 & (HCR_TWE | HCR_TWI);
> 
> I don't think the 'hyp_kvm_vcpu' really makes this much clearer and it's
> the line only ends up being a single character shorter. Just continue to
> use 'hyp_vcpu->vcpu.'?

That makes sense, I'll respin after rc1.

> 
> > +	} else {
> > +		struct kvm_vcpu *host_vcpu = hyp_vcpu->host_vcpu;
> > +
> > +		memcpy(&hyp_kvm_vcpu->arch.fgt, host_vcpu->arch.fgt,
> > +		       sizeof(hyp_kvm_vcpu->arch.fgt));
> >  	}
> >  }
> >  
> > diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
> > index 43bde061b65d..05774aed09cb 100644
> > --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
> > +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
> > @@ -172,7 +172,6 @@ static int pkvm_vcpu_init_traps(struct pkvm_hyp_vcpu *hyp_vcpu)
> >  
> >  		/* Trust the host for non-protected vcpu features. */
> >  		vcpu->arch.hcrx_el2 = host_vcpu->arch.hcrx_el2;
> > -		memcpy(vcpu->arch.fgt, host_vcpu->arch.fgt, sizeof(vcpu->arch.fgt));
> >  		return 0;
> >  	}
> 
> Otherwise, looks good to me:
> 
> Acked-by: Will Deacon <will at kernel.org>

Thanks,
Alex


From robin.murphy at arm.com  Fri Dec 12 02:46:15 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Fri, 12 Dec 2025 10:46:15 +0000
Subject: [RFC PATCH] iommu/arm-smmu-v3: Allow stream ID sharing for
 devices behind PCIe-to-PCI bridges
In-Reply-To: <aTu4xsAApNupRGYC@ziepe.ca>
References: <20251211133933.4128100-1-nirmoyd@nvidia.com>
 <aTu4xsAApNupRGYC@ziepe.ca>
Message-ID: <650659ac-22f0-4fc0-ad43-8d4169cf2432@arm.com>

On 2025-12-12 6:40 am, Jason Gunthorpe wrote:
> On Thu, Dec 11, 2025 at 05:39:33AM -0800, Nirmoy Das wrote:
>> ASPEED BMC controllers have VGA and USB functions behind a PCIe-to-PCI
>> bridge that causes them to share the same stream ID:
>>
>>    \-[0005:e0]---00.0-[e1-e2]----00.0-[e2]--+-00.0  ASPEED Graphics Family
>>                                             \-02.0  ASPEED USB Controller
>>
>> Both devices get stream ID(0x5e200) due to bridge aliasing. Currently this
>> USB controller gets rejected with "Aliasing StreamID unsupported", causing
>> USB timeout errors. Allow stream ID sharing when both devices are on
>> the same bus behind a PCIe-to-PCI bridge to fix this issue.
> 
> I don't think this is right, if you actually need stream ID sharing
> then I seem to recall the driver needs more changes. We don't want
> this in general.

Yes, as I said on the last one not so long ago, we cannot simply cross 
our fingers and hope that aliasing at the SMMU StreamID level stems from 
something at the PCI RID level that pci_device_group() would be aware 
of, because there is no guarantee that RID->StreamID mappings are 1:1.

Thanks,
Robin.

> IMHO ASPEED has wrong PCI config space and there isn't any actual PCI
> bus here that would force RID aliasing to worry about. I suggest going
> to ASPEED to find out and confirm that they don't actually share the
> RIDs and then let's quirk the PCI devices to disable alias generation
> in the first place.
> 
> Also, complain to them to fix their config space to report a PCIe bridge
> type in future devices. :)
> 
> Jason



From andrea.porta at suse.com  Fri Dec 12 02:52:44 2025
From: andrea.porta at suse.com (Andrea della Porta)
Date: Fri, 12 Dec 2025 11:52:44 +0100
Subject: [PATCH] dt-bindings: pci: brcmstb: Add rp1-nexus node to fix DTC
 warning
In-Reply-To: <20251210150008.2ef2f8c4@bootlin.com>
References: <20250812085037.13517-1-andrea.porta@suse.com>
 <4fee3870-f9d5-48e3-a5be-6df581d3e296@kernel.org>
 <aKc5nMT1xXpY03ip@apocalypse>
 <e7875f70-2b79-48e0-a63b-caf6f1fd287b@kernel.org>
 <aLVePQRfU4IB1zK8@apocalypse>
 <CAL_JsqJUzB71QdMcxJtNZ7raoPcK+SfTh7EVzGmk=syo8xLKQw@mail.gmail.com>
 <aThjYt3ux0U-9-3A@apocalypse>
 <aThp99OfgAfNFUX-@apocalypse>
 <20251210150008.2ef2f8c4@bootlin.com>
Message-ID: <aTvz_OeVnciiqATz@apocalypse>

Hi Herve, Rob,

On 15:00 Wed 10 Dec     , Herve Codina wrote:
> Hi Andrea,
> 
> On Tue, 9 Dec 2025 19:27:03 +0100
> Andrea della Porta <andrea.porta at suse.com> wrote:
> 
> > [+cc Herve]
> > 
> > On 18:58 Tue 09 Dec     , Andrea della Porta wrote:
> > > Hi Rob,
> > > 
> > > On 11:09 Thu 04 Dec     , Rob Herring wrote:  
> > > > On Mon, Sep 1, 2025 at 3:48?AM Andrea della Porta <andrea.porta at suse.com> wrote:  
> > > > >
> > > > > Hi Krzysztof,
> > > > >
> > > > > On 08:50 Fri 22 Aug     , Krzysztof Kozlowski wrote:  
> > > > > > On 21/08/2025 17:22, Andrea della Porta wrote:  
> > > > > > > Hi Krzysztof,
> > > > > > >
> > > > > > > On 10:55 Tue 12 Aug     , Krzysztof Kozlowski wrote:  
> > > > > > >> On 12/08/2025 10:50, Andrea della Porta wrote:  
> > > > > > >>> The devicetree compiler is complaining as follows:
> > > > > > >>>
> > > > > > >>> arch/arm64/boot/dts/broadcom/rp1-nexus.dtsi:3.11-14.3: Warning (unit_address_vs_reg): /axi/pcie at 1000120000/rp1_nexus: node has a reg or ranges property, but no unit name
> > > > > > >>> /home/andrea/linux-torvalds/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dtb: pcie at 1000120000: Unevaluated properties are not allowed ('rp1_nexus' was unexpected)  
> > > > > > >>
> > > > > > >> Please trim the paths.  
> > > > > > >
> > > > > > > Ack.
> > > > > > >  
> > > > > > >>  
> > > > > > >>>
> > > > > > >>> Add the optional node that fix this to the DT binding.
> > > > > > >>>
> > > > > > >>> Reported-by: kernel test robot <lkp at intel.com>
> > > > > > >>> Closes: https://lore.kernel.org/oe-kbuild-all/202506041952.baJDYBT4-lkp at intel.com/
> > > > > > >>> Signed-off-by: Andrea della Porta <andrea.porta at suse.com>
> > > > > > >>> ---
> > > > > > >>>  Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml | 9 +++++++++
> > > > > > >>>  1 file changed, 9 insertions(+)
> > > > > > >>>
> > > > > > >>> diff --git a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
> > > > > > >>> index 812ef5957cfc..7d8ba920b652 100644
> > > > > > >>> --- a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
> > > > > > >>> +++ b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
> > > > > > >>> @@ -126,6 +126,15 @@ required:
> > > > > > >>>  allOf:
> > > > > > >>>    - $ref: /schemas/pci/pci-host-bridge.yaml#
> > > > > > >>>    - $ref: /schemas/interrupt-controller/msi-controller.yaml#
> > > > > > >>> +  - if:
> > > > > > >>> +      properties:
> > > > > > >>> +        compatible:
> > > > > > >>> +          contains:
> > > > > > >>> +            const: brcm,bcm2712-pcie
> > > > > > >>> +    then:
> > > > > > >>> +      properties:
> > > > > > >>> +        rp1_nexus:  
> > > > > > >>
> > > > > > >> No, you cannot document post-factum... This does not follow DTS coding
> > > > > > >> style.  
> > > > > > >
> > > > > > > I think I didn't catch what you mean here: would that mean that
> > > > > > > we cannot resolve that warning since we cannot add anything to the
> > > > > > > binding?  
> > > > > >
> > > > > > I meant, you cannot use a warning from the code you recently introduced
> > > > > > as a reason to use incorrect style.
> > > > > >
> > > > > > Fixing warning is of course fine and correct, but for the code recently
> > > > > > introduced and which bypassed ABI review it is basically like new review
> > > > > > of new ABI.
> > > > > >
> > > > > > This needs standard review practice, so you need to document WHY you
> > > > > > need such node. Warning is not the reason here why you are doing. If
> > > > > > this was part of original patchset, like it should have been, you would
> > > > > > not use some imaginary warning as reason, right?
> > > > > >
> > > > > > So provide reason why you need here this dedicated child, what is that
> > > > > > child representing.  
> > > > >
> > > > > Ack.
> > > > >  
> > > > > >
> > > > > > Otherwise I can suggest: drop the child and DTSO, this also solves the
> > > > > > warning...  
> > > > >
> > > > > This would not fix the issue: it's the non overlay that needs the specific
> > > > > node. But I got the point, and we have a solution for that (see below).
> > > > >  
> > > > > >  
> > > > > > >
> > > > > > > Regarding rp1_nexus, you're right I guess it should be
> > > > > > > rp1-nexus as per DTS coding style.
> > > > > > >  
> > > > > > >>
> > > > > > >> Also:
> > > > > > >>
> > > > > > >> Node names should be generic. See also an explanation and list of
> > > > > > >> examples (not exhaustive) in DT specification:
> > > > > > >> https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation  
> > > > > > >
> > > > > > > In this case it could be difficult: we need to search for a DT node  
> > > > > >
> > > > > > Search like in driver? That's wrong, you should be searching by compatible.  
> > > > >
> > > > > Thanks for the hint. Searching by compatble is the solution.  
> > > > 
> > > > No, it is not.  
> > > 
> > > This is partly true, indeed. On one side there's the need to avoid a
> > > specific node name ('rp1_nexus'), so the only other unique identifier would
> > > be the compatible string ('pci1de4,1' in this case, which identifies that specific
> > > device). Unfortunately, the same compatible string is also assigned to the pci
> > > endpoint node filled automatically by enabling CONFIG_PCI_DYNAMIC_OF_NODES.
> > > We would end up with two nodes with the same compatible, which is not unique
> > > anymore. 
> > > This applies only when using 'full' dtb (bcm2712-rpi-5-b.dtb) *and* you enable
> > > CONFIG_PCI_DYNAMIC_OF_NODES, the latter being not necessary since the overlay dtb
> > > (...-ovl-rp1.dtb) is not in use here. To overcome this problem, the solutions
> > > I can think of are the following:
> > > 
> > > 1- Just disable CONFIG_PCI_DYNAMIC_OF_NODES should work, but only when using the
> > >    full dtb version. However, if the user enable that option for debug or to use
> > >    the overlay dtb version, he better be sure not to use teh full dtb or it won't
> > >    work.
> > >    This solution seems really weak.
> > > 
> > > 2- Add another compatible string other than 'pci1de4,1', so it will be really
> > >    unique.
> > >   
> > > >   
> > > > > >  
> > > > > > > starting from the DT root and using generic names like pci at 0,0 or
> > > > > > > dev at 0,0 could possibly led to conflicts with other peripherals.
> > > > > > > That's why I chose a specific name.  
> > > > > >
> > > > > > Dunno, depends what can be there, but you do not get a specific
> > > > > > (non-generic) device node name for a generic PCI device or endpoint.  
> > > > >
> > > > > I would use 'port' instead of rp1-nexus. Would it work for you?  
> > > > 
> > > > Do you still plan to fix this? This is broken far worse than just the node name.  
> > > 
> > > Yes, if we want to get rid of that nasty warning and comply with DT guidelines,
> > > I think I really need to fix that.
> > >   
> > > > 
> > > > The 'rp1_nexus' node is applied to the PCI host bridge. That's wrong
> > > > unless this is PCI rather than PCIe. There's the root port device in
> > > > between.
> > > > 
> > > > The clue that things are wrong are start in the driver here:
> > > > 
> > > > rp1_node = of_find_node_by_name(NULL, "rp1_nexus");
> > > > if (!rp1_node) {
> > > >   rp1_node = dev_of_node(dev);
> > > >   skip_ovl = false;
> > > > }
> 
> I don't fully understand what you want to do.
> 
> This piece of code is present in the drivers/misc/rp1/rp1_pci.c driver.
> This driver is used when a specific PCI device is available on the system.
> This device is PCI_DEVICE(PCI_VENDOR_ID_RPI, PCI_DEVICE_ID_RPI_RP1_C0)
> 
> In order to work, the driver needs either CONFIG_PCI_DYNAMIC_OF_NODES or
> having the full PCI hierarchy described in the DT leading to this device.
> Indeed, it needs a DT node related to the PCI device.
> 
> I don't understand why rp1_nexus should be described at the PCI controller
> root level.
> 
> Only PCI devices (or bridges as they are particular devices) at this level
> as decribed in the pci-bus-common.yaml binding [1].

Ack. As you and Rob pointed out, I will amend the full DT hierarchy with the
PCI nodes in the way as they are dynamically created by CONFIG_PCI_DYNAMIC_OF_NODES.

> 
> If the purpose of this 'rp1_nexus' node is to only avoid the application of
> the overlay, even if I don't understand why, you should search for something
> added by the overlay and not for the 'rp1_nexus' node in the whole DT.

I cannot search for something added by the overlay if I need to choose whether
to apply the overlay or not in teh first place (iIOW the overlay is not yet loaded).
This is not of a concern however, since I'm planning to get rid of the overlay
for reasons already explained here [1]. This will not only solve all of this
problems but it will also address Rob's concern of not relying on 
CONFIG_PCI_DYNAMIC_OF_NODES.

> 
> Instead of:
>   rp1_node = of_find_node_by_name(NULL, "rp1_nexus");
> 
> You should search for a sub-node added by the overlay. Something like the
> following for instance:
> --- 8< ---
> int rp1_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> {
> 	struct device_node *np;
> 
> 	np = dev_of_node(&pdev->dev);
> 
> 	...
> 	if ( np && of_find_node_by_name(np, "pci-ep-bus at 1");
>         ...
> }
> --- 8< ---
> 
> If you really want to be sure that the "pci-ep-bus at 1" comes from an overlay
> you can check for the OF_OVERLAY flag.
> --- 8< ---
>   node = of_find_node_by_name(np, "pci-ep-bus at 1");
>   if (node && of_node_check_flag(node, OF_OVERLAY))
> --- 8< ---
> 
> Also your overlay has to be applied on the DT node related to your PCI
> device and not the rp1_nexus you search for in the whole DT. In other
> word, in your driver, the following is not correct:
> 
>    err = of_overlay_fdt_apply(dtbo_start, dtbo_size, &rp1->ovcs_id,
>                                            rp1_node);
> 
> It should be:
> 
>    err = of_overlay_fdt_apply(dtbo_start, dtbo_size, &rp1->ovcs_id,
>                                            dev_of_node(&pdev->dev));
>  
> In your overlay, your have
> 	__overlay__ {
> 		compatible = "pci1de4,1";
> 		#address-cells = <3>;
> 		#size-cells = <2>;
> 		interrupt-controller;
> 		#interrupt-cells = <2>;
> 
> 		#include "arm64/broadcom/rp1-common.dtsi"
>        };
> 
> Only sub-nodes should be present (#address-cells = <3> and #size-cells = <2>)
> can be there just to make DTC happy.
> 
> It is worth noting that any properties other than #address-cells and
> #size-cells lead to memleaks. And so avoid them.
> 
> Memleaks are reported at runtime when the overlay is applied with this
> kind of logs:
>  OF: overlay: WARNING: memory leak will occur if overlay removed, property: ...
> 
> I am pretty sure that you have those kind of traces when you apply your
> overlay.

Indeed.

Many thanks,
Andrea

[1] - https://lore.kernel.org/all/aTvtr5v4DjuqctdY at apocalypse/

> 
> compatible, interrupt-controller and #interrupt-cells should not be added by
> the overlay. Either they are added by when PCI nodes are created by 
> CONFIG_PCI_DYNAMIC_OF_NODES either they are already available in the base
> DT if the PCI device is described in the base DT.
> 
> [1] https://github.com/devicetree-org/dt-schema/blob/aa859412ce8e38c63bb13fa55c5e1c6ba66a8e3b/dtschema/schemas/pci/pci-bus-common.yaml#L226
> 
> Best regards,
> Herv?


From leo.yan at arm.com  Fri Dec 12 03:15:41 2025
From: leo.yan at arm.com (Leo Yan)
Date: Fri, 12 Dec 2025 11:15:41 +0000
Subject: [RFC PATCH v6 00/35] KVM: arm64: Add Statistical Profiling
 Extension (SPE) support
In-Reply-To: <aTvr8_xjoKY6pB8P@raptor>
References: <20251114160717.163230-1-alexandru.elisei@arm.com>
 <20251211163425.GA4113166@e132581.arm.com>
 <aTvr8_xjoKY6pB8P@raptor>
Message-ID: <20251212111541.GA138375@e132581.arm.com>

On Fri, Dec 12, 2025 at 10:18:27AM +0000, Alexandru Elisei wrote:

[...]


> > 3) In the end, the KVM hypervisor pins physical pages on the host
> >    stage-1 page table for:
> 
> By 'pin' meaning using pin_user_pages(), yes.
> 
> > 
> >    The physical pages are pinned for Guest stage-1 table;
> 
> Yes.
> 
> >    The physical pages are pinned for Guest stage-2 table;
> 
> Yes and no. The pages allocated for the stage 2 translation tables are not
> mapped in the host's userspace, they are mapped in the kernel linear address
> space. This means that they are not subject to migration/swap/compaction/etc,
> they will only be reused after KVM frees them.
> 
> But that's how KVM manages stage 2 for all VMs, so maybe I misunderstood what
> you were saying.

No, you did not misunderstand.  I did not understand stage-2 table
allocation before ? it is allocated by KVM, not from user memory via
the VMM.

[...]

> > Due the host might migrate or swap pages, so all the pin operations
> > happen on the host's page table.  The pin operations never to be set up
> > in guest's stage-2 table, right?
> 
> I'm not sure what you mean.

Never mind.  I think you have answered this below (pin user memory via
pin_user_pages() and no matter with stage-2 tables).

> > My understanding is that there are two prominent challenges for SPE
> > virtualization:
> > 
> > 1) Allocation: we need to allocate trace buffer with mapping both
> >    guest's stage-1 and stage-2 before enabling SPU.  (For me, the free
> 
> It's the guest responsibility to map the buffer in the guest stage 1 before
> enabling it. When the guest enables the buffer, KVM walks the guest's stage 1
> and if it doesn't find a translation for a buffer guest VA, it will inject a
> profiling buffer management event to the guest, with EC stage 1 data abort.

IIUC, KVM will inject a buffer management interrupt to guest and then
guest driver can detect EC="stage 1 data abort".  KVM does not raise a
data abort exception in this case.

> If the buffer was mapped in the guest stage 1 when the guest enabled the buffer,
> but at same point in the future the guest unmaps the buffer from stage 1, the
> statistical profiling unit might encounter a stage 1 data abort when attempting
> to write to memory. If that's the case, the interrupt is taken by the host, and
> KVM will inject the buffer management event back to the guest.

Hmm... just a note, it would be straightforward for guest to directly
respond IRQ for "stage-1 data abort" (TBH, I don't know how to inject
IRQ vs fast-forward IRQ, you could ignore this note until I dig a bit).

Thanks for quick response.  The info is quite helpful for me.

Leo


From adrian.hunter at intel.com  Fri Dec 12 03:17:57 2025
From: adrian.hunter at intel.com (Adrian Hunter)
Date: Fri, 12 Dec 2025 13:17:57 +0200
Subject: [PATCH] mmc: sdhci-of-arasan: Increase CD stable timeout to 2
 seconds
In-Reply-To: <20251212063509.2002910-1-sai.krishna.potthuri@amd.com>
References: <20251212063509.2002910-1-sai.krishna.potthuri@amd.com>
Message-ID: <9744b89a-9a60-4f04-bcca-526a6bb7eddc@intel.com>

On 12/12/2025 08:35, Sai Krishna Potthuri wrote:
> On Xilinx/AMD platforms, the CD stable bit take slightly longer than
> one second(about an additional 100ms) to assert after a host
> controller reset. Although no functional failure observed with the
> existing one second delay but to ensure reliable initialization, increase
> the CD stable timeout to 2 seconds.
> 
> Fixes: e251709aaddb ("mmc: sdhci-of-arasan: Ensure CD logic stabilization before power-up")
> Signed-off-by: Sai Krishna Potthuri <sai.krishna.potthuri at amd.com>

Acked-by: Adrian Hunter <adrian.hunter at intel.com>

> ---
>  drivers/mmc/host/sdhci-of-arasan.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
> index b97d042897ad..ab7f0ffe7b4f 100644
> --- a/drivers/mmc/host/sdhci-of-arasan.c
> +++ b/drivers/mmc/host/sdhci-of-arasan.c
> @@ -99,7 +99,7 @@
>  #define HIWORD_UPDATE(val, mask, shift) \
>  		((val) << (shift) | (mask) << ((shift) + 16))
>  
> -#define CD_STABLE_TIMEOUT_US		1000000
> +#define CD_STABLE_TIMEOUT_US		2000000
>  #define CD_STABLE_MAX_SLEEP_US		10
>  
>  /**



From Xiaoshun.Xu at mediatek.com  Fri Dec 12 03:30:03 2025
From: Xiaoshun.Xu at mediatek.com (=?utf-8?B?WGlhb3NodW4gWHUgKOW+kOaZk+mhuik=?=)
Date: Fri, 12 Dec 2025 11:30:03 +0000
Subject: [PATCH 0/4] *** SUBJECT HERE ***
In-Reply-To: <20251212031450.489128-1-xiaoshun.xu@mediatek.corp-partner.google.com>
References: <20251212031450.489128-1-xiaoshun.xu@mediatek.corp-partner.google.com>
Message-ID: <29107c86bffb5107eb6740444b9de97bd6606e90.camel@mediatek.com>

On Fri, 2025-12-12 at 11:13 +0800, Xiaoshun Xu wrote:
Sorry, there are some mistakes in my patch sets. I will provide a new
version later. Thank you!
> 
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
> 
> 
> From: Xiaoshun Xu <xiaoshun.xu at mediatek.com>
> 
> v1:
> 1. Add dt-bindings compatible and vio-idx-num attribute of MT8189
> 2. Add support DEVAPC of MT8189
> 3. Refine MT8189 DEVAPC clock control flow
> 4. Refine MT8189 DEVAPC interrupt handler
> 
> *** BLURB HERE ***
> 
> xiaoshun.xu (4):
> ? dt-bindings: soc: devapc: Add for support MT8189
> ? soc: mediatek: mtk-devapc: Add support for MT8189 DEVAPC
> ? soc: mediatek: mtk-devapc: refine DEVAPC clock control
> ? soc: mediatek: mtk-devapc: refine devapc interrupt handler
> 
> ?.../bindings/soc/mediatek/devapc.yaml???????? |?? 6 +
> ?drivers/soc/mediatek/mtk-devapc.c???????????? | 176 ++++++++++++++--
> --
> ?2 files changed, 144 insertions(+), 38 deletions(-)
> 
> --
> 2.45.2
> 


From ben.horgan at arm.com  Fri Dec 12 03:31:36 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 12 Dec 2025 11:31:36 +0000
Subject: [RFC PATCH 06/38] KVM: arm64: Force guest EL1 to use user-space's
 partid configuration
In-Reply-To: <20251205215901.17772-7-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-7-james.morse@arm.com>
Message-ID: <24c964ca-ecf5-44af-8bea-4d97b549935c@arm.com>

Hi James,

On 12/5/25 21:58, James Morse wrote:
> While we trap the guest's attempts to read/write the MPAM control
> registers, the hardware continues to use them. Guest-EL0 uses KVM's
> user-space's configuration, as the value is left in the register, and
> guest-EL1 uses either the host kernel's configuration, or in the case of
> VHE, the UNKNOWN reset value of MPAM1_EL1.
> 
> On nVHE systems, EL2 continues to use partid-0 for world-switch, even
> when the host may have configured its kernel threads to use a different
> partid. 0 may have been assigned to another task.
> 
> We want to force the guest-EL1 to use KVM's user-space's MPAM
> configuration, and EL2s to match the host's EL1 config.
> 
> On a nVHE system, copy the EL1 MPAM register to EL2. This ensures
> world-switch uses the same partid as the kernel thread does on the host.
> 
> When loading the guest's EL1 registers, copy the VMM's EL0 partid to
> the EL1 register.
> 
> For VHE systems, we can skip restoring the EL1 register for the host,
> as it is out-of-context once HCR_EL2.TGE is set.
> 
> This is done outside the usual sysreg save/restore as the values can
> change behind KVMs back, so should not be stored in the guest context.
> 
> Signed-off-by: James Morse <james.morse at arm.com>
> ---
>  arch/arm64/include/asm/kvm_host.h          |  1 +
>  arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h | 16 ++++++++++++++++
>  arch/arm64/kvm/hyp/nvhe/switch.c           | 12 ++++++++++++
>  arch/arm64/kvm/hyp/vhe/sysreg-sr.c         |  1 +
>  4 files changed, 30 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index b763293281c8..baba23b7ce97 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -447,6 +447,7 @@ enum vcpu_sysreg {
>  	MDCCINT_EL1,	/* Monitor Debug Comms Channel Interrupt Enable Reg */
>  	OSLSR_EL1,	/* OS Lock Status Register */
>  	DISR_EL1,	/* Deferred Interrupt Status Register */
> +	MPAM1_EL1,	/* Memory Partitioning And Monitoring register */
>  
>  	/* Performance Monitors Registers */
>  	PMCR_EL0,	/* Control Register */
> diff --git a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
> index a17cbe7582de..d8ab0ced0403 100644
> --- a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
> +++ b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
> @@ -166,6 +166,9 @@ static inline void __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
>  		ctxt_sys_reg(ctxt, TFSRE0_EL1) = read_sysreg_s(SYS_TFSRE0_EL1);
>  	}
>  
> +	if (system_supports_mpam())
> +		ctxt_sys_reg(ctxt, MPAM1_EL1) = read_sysreg_el1(SYS_MPAM1);
> +
>  	ctxt_sys_reg(ctxt, SP_EL1)	= read_sysreg(sp_el1);
>  	ctxt_sys_reg(ctxt, ELR_EL1)	= read_sysreg_el1(SYS_ELR);
>  	ctxt_sys_reg(ctxt, SPSR_EL1)	= read_sysreg_el1(SYS_SPSR);
> @@ -261,6 +264,9 @@ static inline void __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt,
>  		write_sysreg_s(ctxt_sys_reg(ctxt, TFSRE0_EL1), SYS_TFSRE0_EL1);
>  	}
>  
> +	if (system_supports_mpam())
> +		write_sysreg_el1(ctxt_sys_reg(ctxt, MPAM1_EL1), SYS_MPAM1);
> +

I don't think this
__sysreg_save_el1_state()/__sysreg_restore_el1_state() mpam change adds
anything. Assuming MPAM0 and MPAM1 are always set together and that we
continue to trap accesses from the guest there is nothing to change the
value away from that of the task. If MPAM0 and MPAM1 were set separately
then we would need a way to restore the host value of MPAM1 in the nvhe
case due to the copy from MPAM0 to MPAM1.

>  	if (!has_vhe() &&
>  	    cpus_have_final_cap(ARM64_WORKAROUND_SPECULATIVE_AT) &&
>  	    ctxt->__hyp_running_vcpu) {
> @@ -374,4 +380,14 @@ static inline void __sysreg32_restore_state(struct kvm_vcpu *vcpu)
>  		write_sysreg(__vcpu_sys_reg(vcpu, DBGVCR32_EL2), dbgvcr32_el2);
>  }
>  
> +/*
> + * The _EL0 value was written by the host's context switch and belongs to the
> + * VMM. Copy this into the guest's _EL1 register.
> + */
> +static inline void __mpam_guest_load(void)
> +{
> +	if (system_supports_mpam())
> +		write_sysreg_el1(read_sysreg_s(SYS_MPAM0_EL1), SYS_MPAM1);
> +}
> +
>  #endif /* __ARM64_KVM_HYP_SYSREG_SR_H__ */
> diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c
> index d3b9ec8a7c28..b785977aa61e 100644
> --- a/arch/arm64/kvm/hyp/nvhe/switch.c
> +++ b/arch/arm64/kvm/hyp/nvhe/switch.c
> @@ -238,6 +238,15 @@ static inline bool fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
>  	return __fixup_guest_exit(vcpu, exit_code, handlers);
>  }
>  
> +/* Use the host thread's partid and pmg for world switch */
> +static void __mpam_copy_el1_to_el2(void)
> +{
> +	if (system_supports_mpam()) {
> +		write_sysreg_s(read_sysreg_s(SYS_MPAM1_EL1), SYS_MPAM2_EL2);
> +		isb();
> +	}
> +}
> +
>  /* Switch to the guest for legacy non-VHE systems */
>  int __kvm_vcpu_run(struct kvm_vcpu *vcpu)
>  {
> @@ -247,6 +256,8 @@ int __kvm_vcpu_run(struct kvm_vcpu *vcpu)
>  	bool pmu_switch_needed;
>  	u64 exit_code;
>  
> +	__mpam_copy_el1_to_el2();
> +

What about the other hypercalls? E.g. __pkvm_init_vm(). Don't we end up
just running them all with the MPAM settings of the previous vcpu that ran?

>  	/*
>  	 * Having IRQs masked via PMR when entering the guest means the GIC
>  	 * will not signal the CPU of interrupts of lower priority, and the
> @@ -306,6 +317,7 @@ int __kvm_vcpu_run(struct kvm_vcpu *vcpu)
>  	__timer_enable_traps(vcpu);
>  
>  	__debug_switch_to_guest(vcpu);
> +	__mpam_guest_load();

As MPAM0 and MPAM1 are kept in sync this doesn't do anything in the nvhe
case.

>  
>  	do {
>  		/* Jump in the fire! */
> diff --git a/arch/arm64/kvm/hyp/vhe/sysreg-sr.c b/arch/arm64/kvm/hyp/vhe/sysreg-sr.c
> index f28c6cf4fe1b..2a84edc90465 100644
> --- a/arch/arm64/kvm/hyp/vhe/sysreg-sr.c
> +++ b/arch/arm64/kvm/hyp/vhe/sysreg-sr.c
> @@ -222,6 +222,7 @@ void __vcpu_load_switch_sysregs(struct kvm_vcpu *vcpu)
>  	 */
>  	__sysreg32_restore_state(vcpu);
>  	__sysreg_restore_user_state(guest_ctxt);
> +	__mpam_guest_load();
>  
>  	if (unlikely(is_hyp_ctxt(vcpu))) {
>  		__sysreg_restore_vel2_state(vcpu);

Thanks,

Ben



From linux at roeck-us.net  Fri Dec 12 03:44:35 2025
From: linux at roeck-us.net (Guenter Roeck)
Date: Fri, 12 Dec 2025 03:44:35 -0800
Subject: [PATCH 7/8] watchdog: aaeon: Add watchdog driver for SRG-IMX8PL
 MCU
In-Reply-To: <20251212-dev-b4-aaeon-mcu-driver-v1-7-6bd65bc8ef12@bootlin.com>
References: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com>
 <20251212-dev-b4-aaeon-mcu-driver-v1-7-6bd65bc8ef12@bootlin.com>
Message-ID: <4483f8fe-2bad-46f1-b37f-157515098f54@roeck-us.net>

On 12/11/25 23:41, Thomas Perrot (Schneider Electric) wrote:
> Add watchdog driver for the Aaeon SRG-IMX8PL embedded controller.
> This driver provides system monitoring and recovery capabilities
> through the MCU's watchdog timer.
> 
> The watchdog supports start, stop, and ping operations with a maximum
> hardware heartbeat of 25 seconds and a default timeout of 240 seconds.
> The driver assumes the watchdog is already running at probe time, as
> the MCU typically enables it by default.
> 
> Co-developed-by: J?r?mie Dautheribes (Schneider Electric) <jeremie.dautheribes at bootlin.com>
> Signed-off-by: J?r?mie Dautheribes (Schneider Electric) <jeremie.dautheribes at bootlin.com>
> Signed-off-by: Thomas Perrot (Schneider Electric) <thomas.perrot at bootlin.com>
> ---
>   drivers/watchdog/Kconfig         |  10 +++
>   drivers/watchdog/Makefile        |   1 +
>   drivers/watchdog/aaeon_mcu_wdt.c | 140 +++++++++++++++++++++++++++++++++++++++
>   3 files changed, 151 insertions(+)
> 
> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> index d3b9df7d466b0b7215ee87b3040811d44ee53d2a..1bd4a7bee303e5e2508f540dc2c16e9e19ed18b0 100644
> --- a/drivers/watchdog/Kconfig
> +++ b/drivers/watchdog/Kconfig
> @@ -168,6 +168,16 @@ config SOFT_WATCHDOG_PRETIMEOUT
>   	  watchdog. Be aware that governors might affect the watchdog because it
>   	  is purely software, e.g. the panic governor will stall it!
>   
> +config AAEON_MCU_WATCHDOG
> +	tristate "Aaeon MCU Watchdog"
> +	depends on MFD_AAEON_MCU
> +	select WATCHDOG_CORE
> +	help
> +	  Select this option to enable watchdog timer support for the Aaeon
> +	  SRG-IMX8PL onboard microcontroller (MCU). This driver provides
> +	  watchdog functionality through the MCU, allowing system monitoring
> +	  and automatic recovery from system hangs.
> +
>   config BD957XMUF_WATCHDOG
>   	tristate "ROHM BD9576MUF and BD9573MUF PMIC Watchdog"
>   	depends on MFD_ROHM_BD957XMUF
> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
> index ba52099b125398a32f80dad23317e223cc4af028..2deec425d3eafb6b208e061fda9f216f4baa8ecc 100644
> --- a/drivers/watchdog/Makefile
> +++ b/drivers/watchdog/Makefile
> @@ -37,6 +37,7 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
>   # ALPHA Architecture
>   
>   # ARM Architecture
> +obj-$(CONFIG_AAEON_MCU_WATCHDOG) += aaeon_mcu_wdt.o
>   obj-$(CONFIG_ARM_SP805_WATCHDOG) += sp805_wdt.o
>   obj-$(CONFIG_ARM_SBSA_WATCHDOG) += sbsa_gwdt.o
>   obj-$(CONFIG_ARMADA_37XX_WATCHDOG) += armada_37xx_wdt.o
> diff --git a/drivers/watchdog/aaeon_mcu_wdt.c b/drivers/watchdog/aaeon_mcu_wdt.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..8413ea3bce99585d989cf13e4494e8daff2d9e4c
> --- /dev/null
> +++ b/drivers/watchdog/aaeon_mcu_wdt.c
> @@ -0,0 +1,140 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Aaeon MCU Watchdog driver
> + *
> + * Copyright (C) 2025 Bootlin
> + * Author: J?r?mie Dautheribes <jeremie.dautheribes at bootlin.com>
> + * Author: Thomas Perrot <thomas.perrot at bootlin.com>
> + */
> +
> +#include <linux/i2c.h>
> +#include <linux/mfd/aaeon-mcu.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/watchdog.h>
> +
> +#define AAEON_MCU_CONTROL_WDT 0x63
> +#define AAEON_MCU_PING_WDT 0x73

tab after the macro name, please.

> +
> +#define AAEON_MCU_WDT_TIMEOUT         240
> +#define AAEON_MCU_WDT_HEARTBEAT_MS    25000
> +
> +struct aaeon_mcu_wdt {
> +	struct watchdog_device wdt;
> +	struct aaeon_mcu_dev *mfd;

mfd is not used anywhere. Just store and use the i2c client.

> +};
> +
> +static int aaeon_mcu_wdt_start_cmd(struct aaeon_mcu_wdt *data)
> +{
> +	u8 cmd[3], rsp;
> +
> +	cmd[0] = AAEON_MCU_CONTROL_WDT;
> +	cmd[1] = 0x01;
> +	cmd[2] = 0x00;
> +
> +	return aaeon_mcu_i2c_xfer(data->mfd->i2c_client, cmd, 3, &rsp, 1);
> +}
> +
> +static int aaeon_mcu_wdt_start(struct watchdog_device *wdt)
> +{
> +	struct aaeon_mcu_wdt *data = watchdog_get_drvdata(wdt);
> +
> +	return aaeon_mcu_wdt_start_cmd(data);
> +}
> +
> +static int aaeon_mcu_wdt_stop_cmd(struct aaeon_mcu_wdt *data)
> +{
> +	u8 cmd[3], rsp;
> +
> +	cmd[0] = AAEON_MCU_CONTROL_WDT;
> +	cmd[1] = 0x00;
> +	cmd[2] = 0x00;
> +
> +	return aaeon_mcu_i2c_xfer(data->mfd->i2c_client, cmd, 3, &rsp, 1);
> +}
> +
> +static int aaeon_mcu_wdt_stop(struct watchdog_device *wdt)
> +{
> +	struct aaeon_mcu_wdt *data = watchdog_get_drvdata(wdt);
> +
> +	return aaeon_mcu_wdt_stop_cmd(data);
> +}
> +
> +static int aaeon_mcu_wdt_ping_cmd(struct aaeon_mcu_wdt *data)
> +{
> +	u8 cmd[3], rsp;
> +
> +	cmd[0] = AAEON_MCU_PING_WDT;
> +	cmd[1] = 0x00;
> +	cmd[2] = 0x00;
> +
> +	return aaeon_mcu_i2c_xfer(data->mfd->i2c_client, cmd, 3, &rsp, 1);

This code is pretty much always the same. It would be much simpler to just pass
i2c_client and the opcodes (first two bytes of the 3-byte message) as parameters
to a single function.

> +}
> +
> +static int aaeon_mcu_wdt_ping(struct watchdog_device *wdt)
> +{
> +	struct aaeon_mcu_wdt *data = watchdog_get_drvdata(wdt);
> +
> +	return aaeon_mcu_wdt_ping_cmd(data);
> +}
> +
> +static const struct watchdog_info aaeon_mcu_wdt_info = {
> +	.identity	= "Aaeon MCU Watchdog",
> +	.options	= WDIOF_KEEPALIVEPING
> +};
> +
> +static const struct watchdog_ops aaeon_mcu_wdt_ops = {
> +	.owner		= THIS_MODULE,
> +	.start		= aaeon_mcu_wdt_start,
> +	.stop		= aaeon_mcu_wdt_stop,
> +	.ping		= aaeon_mcu_wdt_ping,
> +};
> +
> +static int aaeon_mcu_wdt_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct aaeon_mcu_dev *mcu = dev_get_drvdata(dev->parent);
> +	struct watchdog_device *wdt;
> +	struct aaeon_mcu_wdt *data;
> +
> +	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	data->mfd = mcu;
> +
> +	wdt = &data->wdt;
> +	wdt->parent = dev;
> +
> +	wdt->info = &aaeon_mcu_wdt_info;
> +	wdt->ops = &aaeon_mcu_wdt_ops;
> +	wdt->max_hw_heartbeat_ms = AAEON_MCU_WDT_HEARTBEAT_MS;
> +	watchdog_init_timeout(wdt, AAEON_MCU_WDT_TIMEOUT, dev);

Calling watchdog_init_timeout() only makes sense if an (optional)
module parameter is passed to it. Passing a constant is pointless.
Just set wdt->timeout.

> +
> +	watchdog_set_drvdata(wdt, data);
> +	platform_set_drvdata(pdev, data);
> +	set_bit(WDOG_HW_RUNNING, &wdt->status);

The driver does not know if that is the case. Guessing is insufficient.
Either stop the watchdog or start it explicitly if the status can not
be retrieved from the MCU.

> +
> +	return devm_watchdog_register_device(dev, wdt);
> +}
> +
> +static const struct of_device_id aaeon_mcu_wdt_of_match[] = {
> +	{ .compatible = "aaeon,srg-imx8pl-wdt" },
> +	{},
> +};
> +
> +MODULE_DEVICE_TABLE(of, aaeon_mcu_wdt_of_match);
> +
> +static struct platform_driver aaeon_mcu_wdt_driver = {
> +	.driver		= {
> +		.name	= "aaeon-mcu-wdt",
> +		.of_match_table = aaeon_mcu_wdt_of_match,
> +	},
> +	.probe		= aaeon_mcu_wdt_probe,
> +};
> +
> +module_platform_driver(aaeon_mcu_wdt_driver);
> +
> +MODULE_DESCRIPTION("Aaeon MCU Watchdog Driver");
> +MODULE_AUTHOR("J?r?mie Dautheribes");
> +MODULE_LICENSE("GPL");
> 



From linux at roeck-us.net  Fri Dec 12 03:46:32 2025
From: linux at roeck-us.net (Guenter Roeck)
Date: Fri, 12 Dec 2025 03:46:32 -0800
Subject: [PATCH 3/8] dt-bindings: watchdog: Add AAEON embedded controller
 watchdog binding
In-Reply-To: <019aa49f-fe59-488d-aff8-f07cf07ee68d@kernel.org>
References: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com>
 <20251212-dev-b4-aaeon-mcu-driver-v1-3-6bd65bc8ef12@bootlin.com>
 <019aa49f-fe59-488d-aff8-f07cf07ee68d@kernel.org>
Message-ID: <cb8031bb-9213-49b7-a85a-5ca9091aee5c@roeck-us.net>

On 12/12/25 00:20, Krzysztof Kozlowski wrote:
> On 12/12/2025 08:41, Thomas Perrot (Schneider Electric) wrote:
>> +
>> +additionalProperties: false
>> +
>> +examples:
>> +  - |
>> +    watchdog {
>> +      compatible = "aaeon,srg-imx8pl-wdt";
> 
> No, that was discussed many times on the mailing list already. Fold the
> child into the parent. Your driver model really do not matter for DT.
> 

Theoretically there could be a 'timeout' property since this is
a watchdog driver, but that isn't supported by the driver, so
I agree.

Guenter



From alexandru.elisei at arm.com  Fri Dec 12 03:54:09 2025
From: alexandru.elisei at arm.com (Alexandru Elisei)
Date: Fri, 12 Dec 2025 11:54:09 +0000
Subject: [RFC PATCH v6 00/35] KVM: arm64: Add Statistical Profiling
 Extension (SPE) support
In-Reply-To: <20251212111541.GA138375@e132581.arm.com>
References: <20251114160717.163230-1-alexandru.elisei@arm.com>
 <20251211163425.GA4113166@e132581.arm.com>
 <aTvr8_xjoKY6pB8P@raptor>
 <20251212111541.GA138375@e132581.arm.com>
Message-ID: <aTwCYSitrJHIue8t@raptor>

Hi Leo,

On Fri, Dec 12, 2025 at 11:15:41AM +0000, Leo Yan wrote:
> On Fri, Dec 12, 2025 at 10:18:27AM +0000, Alexandru Elisei wrote:
> 
> [...]
> 
> 
> > > 3) In the end, the KVM hypervisor pins physical pages on the host
> > >    stage-1 page table for:
> > 
> > By 'pin' meaning using pin_user_pages(), yes.
> > 
> > > 
> > >    The physical pages are pinned for Guest stage-1 table;
> > 
> > Yes.
> > 
> > >    The physical pages are pinned for Guest stage-2 table;
> > 
> > Yes and no. The pages allocated for the stage 2 translation tables are not
> > mapped in the host's userspace, they are mapped in the kernel linear address
> > space. This means that they are not subject to migration/swap/compaction/etc,
> > they will only be reused after KVM frees them.
> > 
> > But that's how KVM manages stage 2 for all VMs, so maybe I misunderstood what
> > you were saying.
> 
> No, you did not misunderstand.  I did not understand stage-2 table
> allocation before ? it is allocated by KVM, not from user memory via
> the VMM.
> 
> [...]
> 
> > > Due the host might migrate or swap pages, so all the pin operations
> > > happen on the host's page table.  The pin operations never to be set up
> > > in guest's stage-2 table, right?
> > 
> > I'm not sure what you mean.
> 
> Never mind.  I think you have answered this below (pin user memory via
> pin_user_pages() and no matter with stage-2 tables).
> 
> > > My understanding is that there are two prominent challenges for SPE
> > > virtualization:
> > > 
> > > 1) Allocation: we need to allocate trace buffer with mapping both
> > >    guest's stage-1 and stage-2 before enabling SPU.  (For me, the free
> > 
> > It's the guest responsibility to map the buffer in the guest stage 1 before
> > enabling it. When the guest enables the buffer, KVM walks the guest's stage 1
> > and if it doesn't find a translation for a buffer guest VA, it will inject a
> > profiling buffer management event to the guest, with EC stage 1 data abort.
> 
> IIUC, KVM will inject a buffer management interrupt to guest and then
> guest driver can detect EC="stage 1 data abort".  KVM does not raise a
> data abort exception in this case.
> 
> > If the buffer was mapped in the guest stage 1 when the guest enabled the buffer,
> > but at same point in the future the guest unmaps the buffer from stage 1, the
> > statistical profiling unit might encounter a stage 1 data abort when attempting
> > to write to memory. If that's the case, the interrupt is taken by the host, and
> > KVM will inject the buffer management event back to the guest.
> 
> Hmm... just a note, it would be straightforward for guest to directly
> respond IRQ for "stage-1 data abort" (TBH, I don't know how to inject
> IRQ vs fast-forward IRQ, you could ignore this note until I dig a bit).

PMBIRQ is a purely virtual interrupt for KVM. Very early on guest exit, KVM
saves the hardware value for PMBSR_EL1 and clears PMBSR_EL1.S, which leads to
the SPU deasserting PMBIRQ to the GIC.

>From my very limited testing, the GIC is always fast enough to deasserts the
interrupt to the CPU before interrupts are enabled much later in the VCPU run
loop. If that doesn't happen (GIC is still asserting PMBIRQ when interrupts on
enabled on the CPU), the SPE driver interrupt handler will treat it as a
spurious interrupt because the driver reads PMBSR_EL1.S = 0.

Thanks,
Alex


From adrian.hunter at intel.com  Fri Dec 12 03:58:41 2025
From: adrian.hunter at intel.com (Adrian Hunter)
Date: Fri, 12 Dec 2025 13:58:41 +0200
Subject: [PATCH v3] mmc: sdhci-esdhc-imx: wait for data transfer
 completion before reset
In-Reply-To: <20251211075603.533033-1-ziniu.wang_1@nxp.com>
References: <20251211075603.533033-1-ziniu.wang_1@nxp.com>
Message-ID: <fc3ffb7b-d2f4-4337-8086-8dcb146bfa07@intel.com>

On 11/12/2025 09:56, ziniu.wang_1 at nxp.com wrote:
> From: Luke Wang <ziniu.wang_1 at nxp.com>
> 
> On IMX7ULP platforms, certain SD cards (e.g. Kingston Canvas Go! Plus)
> cause system hangs and reboots during manual tuning. These cards exhibit
> large gaps (~16us) between tuning command response and data transmission.
> When cmd CRC errors occur during tuning, the code assumes data errors even
> tuning data hasn't been fully received and then reset host data circuit.
> 
> Per IMX7ULP reference manual, reset operations (RESET_DATA/ALL) need to
> make sure no active data transfers. Previously, resetting while data was
> in-flight would clear data circuit, including ADMA/SDMA address, causing
> data to be transmitted to incorrect memory address. This patch adds
> polling for data transfer completion before executing resets.
> 
> Signed-off-by: Luke Wang <ziniu.wang_1 at nxp.com>
> Reviewed-by: Bough Chen <haibo.chen at nxp.com>

Acked-by: Adrian Hunter <adrian.hunter at intel.com>

> ---
> v3: add define for timeout value
> v2: amend commit message
> ---
>  drivers/mmc/host/sdhci-esdhc-imx.c | 18 ++++++++++++++++++
>  1 file changed, 18 insertions(+)
> 
> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
> index a7a5df673b0f..97461e20425d 100644
> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> @@ -216,6 +216,8 @@
>  #define ESDHC_FLAG_DUMMY_PAD		BIT(19)
>  
>  #define ESDHC_AUTO_TUNING_WINDOW	3
> +/* 100ms timeout for data inhibit */
> +#define ESDHC_DATA_INHIBIT_WAIT_US	100000
>  
>  enum wp_types {
>  	ESDHC_WP_NONE,		/* no WP, neither controller nor gpio */
> @@ -1453,6 +1455,22 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
>  
>  static void esdhc_reset(struct sdhci_host *host, u8 mask)
>  {
> +	u32 present_state;
> +	int ret;
> +
> +	/*
> +	 * For data or full reset, ensure any active data transfer completes
> +	 * before resetting to avoid system hang.
> +	 */
> +	if (mask & (SDHCI_RESET_DATA | SDHCI_RESET_ALL)) {
> +		ret = readl_poll_timeout_atomic(host->ioaddr + ESDHC_PRSSTAT, present_state,
> +						!(present_state & SDHCI_DATA_INHIBIT), 2,
> +						ESDHC_DATA_INHIBIT_WAIT_US);
> +		if (ret == -ETIMEDOUT)
> +			dev_warn(mmc_dev(host->mmc),
> +				 "timeout waiting for data transfer completion\n");
> +	}
> +
>  	sdhci_and_cqhci_reset(host, mask);
>  
>  	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);



From robin.murphy at arm.com  Fri Dec 12 04:01:41 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Fri, 12 Dec 2025 12:01:41 +0000
Subject: [PATCH V6 1/4] iommu/tegra241-cmdqv: Decouple driver from ACPI
In-Reply-To: <20251212060803.1712637-2-amhetre@nvidia.com>
References: <20251212060803.1712637-1-amhetre@nvidia.com>
 <20251212060803.1712637-2-amhetre@nvidia.com>
Message-ID: <54fce1f8-7675-4351-b292-0009b2e8c599@arm.com>

On 2025-12-12 6:08 am, Ashish Mhetre wrote:
> From: Nicolin Chen <nicolinc at nvidia.com>
> 
> A platform device is created by acpi_create_platform_device() per CMDQV's
> adev. That means there is no point in going through _CRS of ACPI.
> 
> Replace all the ACPI functions with standard platform functions. And drop
> all ACPI dependencies. This will make the driver compatible with DT also.
> 
> Suggested-by: Robin Murphy <robin.murphy at arm.com>
> Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
> ---
>   drivers/iommu/arm/Kconfig                     |  1 -
>   drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   |  2 +-
>   .../iommu/arm/arm-smmu-v3/tegra241-cmdqv.c    | 84 +++----------------
>   3 files changed, 13 insertions(+), 74 deletions(-)
> 
> diff --git a/drivers/iommu/arm/Kconfig b/drivers/iommu/arm/Kconfig
> index ef42bbe07dbe..5fac08b89dee 100644
> --- a/drivers/iommu/arm/Kconfig
> +++ b/drivers/iommu/arm/Kconfig
> @@ -121,7 +121,6 @@ config ARM_SMMU_V3_KUNIT_TEST
>   
>   config TEGRA241_CMDQV
>   	bool "NVIDIA Tegra241 CMDQ-V extension support for ARM SMMUv3"
> -	depends on ACPI
>   	help
>   	  Support for NVIDIA CMDQ-Virtualization extension for ARM SMMUv3. The
>   	  CMDQ-V extension is similar to v3.3 ECMDQ for multi command queues
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index d16d35c78c06..42de3da54858 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -4542,7 +4542,7 @@ static void acpi_smmu_dsdt_probe_tegra241_cmdqv(struct acpi_iort_node *node,
>   	adev = acpi_dev_get_first_match_dev("NVDA200C", uid, -1);
>   	if (adev) {
>   		/* Tegra241 CMDQV driver is responsible for put_device() */

Don't we need to bring the put_device(adev) out to this level, since 
impl_dev is now something else that AFAICS we are *not* taking a new 
reference on (and thus should not be putting either)?

Otherwise this looks pretty nice!

Thanks,
Robin.

> -		smmu->impl_dev = &adev->dev;
> +		smmu->impl_dev = acpi_get_first_physical_node(adev);
>   		smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
>   		dev_info(smmu->dev, "found companion CMDQV device: %s\n",
>   			 dev_name(smmu->impl_dev));
> diff --git a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
> index 378104cd395e..1fc03b72beb8 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
> @@ -3,17 +3,15 @@
>   
>   #define dev_fmt(fmt) "tegra241_cmdqv: " fmt
>   
> -#include <linux/acpi.h>
>   #include <linux/debugfs.h>
>   #include <linux/dma-mapping.h>
>   #include <linux/interrupt.h>
>   #include <linux/iommu.h>
>   #include <linux/iommufd.h>
>   #include <linux/iopoll.h>
> +#include <linux/platform_device.h>
>   #include <uapi/linux/iommufd.h>
>   
> -#include <acpi/acpixf.h>
> -
>   #include "arm-smmu-v3.h"
>   
>   /* CMDQV register page base and size defines */
> @@ -854,69 +852,6 @@ static struct arm_smmu_impl_ops tegra241_cmdqv_impl_ops = {
>   
>   /* Probe Functions */
>   
> -static int tegra241_cmdqv_acpi_is_memory(struct acpi_resource *res, void *data)
> -{
> -	struct resource_win win;
> -
> -	return !acpi_dev_resource_address_space(res, &win);
> -}
> -
> -static int tegra241_cmdqv_acpi_get_irqs(struct acpi_resource *ares, void *data)
> -{
> -	struct resource r;
> -	int *irq = data;
> -
> -	if (*irq <= 0 && acpi_dev_resource_interrupt(ares, 0, &r))
> -		*irq = r.start;
> -	return 1; /* No need to add resource to the list */
> -}
> -
> -static struct resource *
> -tegra241_cmdqv_find_acpi_resource(struct device *dev, int *irq)
> -{
> -	struct acpi_device *adev = to_acpi_device(dev);
> -	struct list_head resource_list;
> -	struct resource_entry *rentry;
> -	struct resource *res = NULL;
> -	int ret;
> -
> -	INIT_LIST_HEAD(&resource_list);
> -	ret = acpi_dev_get_resources(adev, &resource_list,
> -				     tegra241_cmdqv_acpi_is_memory, NULL);
> -	if (ret < 0) {
> -		dev_err(dev, "failed to get memory resource: %d\n", ret);
> -		return NULL;
> -	}
> -
> -	rentry = list_first_entry_or_null(&resource_list,
> -					  struct resource_entry, node);
> -	if (!rentry) {
> -		dev_err(dev, "failed to get memory resource entry\n");
> -		goto free_list;
> -	}
> -
> -	/* Caller must free the res */
> -	res = kzalloc(sizeof(*res), GFP_KERNEL);
> -	if (!res)
> -		goto free_list;
> -
> -	*res = *rentry->res;
> -
> -	acpi_dev_free_resource_list(&resource_list);
> -
> -	INIT_LIST_HEAD(&resource_list);
> -
> -	if (irq)
> -		ret = acpi_dev_get_resources(adev, &resource_list,
> -					     tegra241_cmdqv_acpi_get_irqs, irq);
> -	if (ret < 0 || !irq || *irq <= 0)
> -		dev_warn(dev, "no interrupt. errors will not be reported\n");
> -
> -free_list:
> -	acpi_dev_free_resource_list(&resource_list);
> -	return res;
> -}
> -
>   static int tegra241_cmdqv_init_structures(struct arm_smmu_device *smmu)
>   {
>   	struct tegra241_cmdqv *cmdqv =
> @@ -1042,18 +977,23 @@ __tegra241_cmdqv_probe(struct arm_smmu_device *smmu, struct resource *res,
>   
>   struct arm_smmu_device *tegra241_cmdqv_probe(struct arm_smmu_device *smmu)
>   {
> +	struct platform_device *pdev = to_platform_device(smmu->impl_dev);
>   	struct arm_smmu_device *new_smmu;
> -	struct resource *res = NULL;
> +	struct resource *res;
>   	int irq;
>   
> -	if (!smmu->dev->of_node)
> -		res = tegra241_cmdqv_find_acpi_resource(smmu->impl_dev, &irq);
> -	if (!res)
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res) {
> +		dev_err(&pdev->dev, "no memory resource found for CMDQV\n");
>   		goto out_fallback;
> +	}
>   
> -	new_smmu = __tegra241_cmdqv_probe(smmu, res, irq);
> -	kfree(res);
> +	irq = platform_get_irq_optional(pdev, 0);
> +	if (irq <= 0)
> +		dev_warn(&pdev->dev,
> +			 "no interrupt. errors will not be reported\n");
>   
> +	new_smmu = __tegra241_cmdqv_probe(smmu, res, irq);
>   	if (new_smmu)
>   		return new_smmu;
>   



From tomas.melin at vaisala.com  Fri Dec 12 04:09:30 2025
From: tomas.melin at vaisala.com (Tomas Melin)
Date: Fri, 12 Dec 2025 14:09:30 +0200
Subject: [PATCH] Revert "arm64: zynqmp: Add an OP-TEE node to the device
 tree"
In-Reply-To: <199062ba-9a0d-40ae-ac8c-0fbed5615cf8@vaisala.com>
References: <20251125-revert-zynqmp-optee-v1-1-d2ce4c0fcaf6@vaisala.com>
 <88b72343-e86f-4b13-adcc-ba09683eb898@amd.com>
 <199062ba-9a0d-40ae-ac8c-0fbed5615cf8@vaisala.com>
Message-ID: <3654c600-553f-429a-8bec-1add7f6eb5c6@vaisala.com>

Hi,

Is there some more specific information I can provide regarding this patch?

Thanks,
Tomas


On 25/11/2025 13:42, Tomas Melin wrote:
> Hi,
> 
> On 25/11/2025 12:30, Michal Simek wrote:
>>
>>
>> On 11/25/25 08:53, Tomas Melin wrote:
>>> This reverts commit 06d22ed6b6635b17551f386b50bb5aaff9b75fbe.
>>>
>>> OP-TEE logic in U-Boot automatically injects a reserved-memory
>>> node along with optee firmware node to kernel device tree.
>>> The injection logic is dependent on that there is no manually
>>> defined optee node. Having the node in zynqmp.dtsi effectively
>>> breaks OP-TEE's insertion of the reserved-memory node, causing
>>> memory access violations during runtime.
>>>
>>> Signed-off-by: Tomas Melin <tomas.melin at vaisala.com>
>>> ---
>>> For further information about the U-Boot logic related
>>> to this, see lib/optee/optee.c in U-Boot repository.
>>
>> What's the behavior with EDK2?
> Sorry, I cannot comment on that.
> 
>>
>> U-Boot also have optee driver. How is it probed when you remove this node?
> This is about the injection of the nodes to the kernel device tree. So
> in the U-Boot side, optee driver can be enabled or not. This passing of
> the optee nodes will happen outside of optee driver context (image-fdt).
> The OP-TEE logic will not insert the required reserved memory regions
> into the kernel side devicetree in case the node is already present and
> that is a real problem.
> If this change eventually is mapped from kernel to U-Boot side, OP-TEE
> needs to be enabled by boards that use OP-TEE from U-Boot. But that
> sounds logical and how it was before, why would OP-TEE be automatically
> enabled.
> 
> Thanks,
> Tomas
> 
> 
>>
>> Thanks,
>> Michal
>>
>>
> 



From ryan.roberts at arm.com  Fri Dec 12 04:12:05 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Fri, 12 Dec 2025 12:12:05 +0000
Subject: [PATCH 00/10] arm64: Replace TLB invalidation preprocessor macros
 with C functions
In-Reply-To: <eb583fda-cbd1-4ef2-900a-a86e08a0b5d3@arm.com>
References: <20250711161732.384-1-will@kernel.org>
 <eb583fda-cbd1-4ef2-900a-a86e08a0b5d3@arm.com>
Message-ID: <b40ee164-f533-43da-a4e2-068c9ae1e771@arm.com>

On 10/12/2025 12:29, Ryan Roberts wrote:
> On 11/07/2025 17:17, Will Deacon wrote:
>> Hi all,
>>
>> I cooked this series following a complaint from Linus back in March
>> about our range-based TLB invalidation macro after we fixed an
>> over-invalidation bug thanks to incorrect handling of its arguments:
>>
>>   https://lore.kernel.org/all/CAHk-=wgiX0q0WCL+SFwVCYtG7JR3=2Rshse-5J3AO2Y4AgT7Jw at mail.gmail.com/
>>
>> Once I started trying to rework the range macro into a C function, I
>> spotted a few other opportunities for cleanup and so I've ended up with
>> this series.
>>
>> Testing and feedback welcome.
> 
> Hi Will,
> 
> Did this go anywhere/are you planning to post a new version? There are a couple
> of other cleanups I'd like to do in this area, and also I'd like to add tlbip
> support. But I don't want to spend time on it if the baseline is going to
> drastically change.
> 
> If you're not planning a v2, perhaps I could have a go then extend for the
> extras I want to do?

Since I didn't hear back, I've reworked the series to include Linus's suggestion
and am currently testing. Plan to post against -rc1.

> 
> Thanks,
> Ryan
> 
> 
>>
>> Cheers,
>>
>> Will
>>
>> Cc: Ard Biesheuvel <ardb at kernel.org>
>> Cc: Catalin Marinas <catalin.marinas at arm.com>
>> Cc: Ryan Roberts <ryan.roberts at arm.com>
>> Cc: Mark Rutland <mark.rutland at arm.com>
>> Cc: Linus Torvalds <torvalds at linux-foundation.org>
>> Cc: Oliver Upton <oliver.upton at linux.dev>
>> Cc: Marc Zyngier <maz at kernel.org>
>>
>> --->8
>>
>> Will Deacon (10):
>>   arm64: mm: Introduce a C wrapper for by-level TLB invalidation helpers
>>   arm64: mm: Introduce a C wrapper for by-range TLB invalidation helpers
>>   arm64: mm: Implicitly invalidate user ASID based on TLBI operation
>>   arm64: mm: Remove unused 'tlbi_user' argument from
>>     __flush_tlb_range_op()
>>   arm64: mm: Re-implement the __tlbi_level macro in C
>>   arm64: mm: Simplify __TLBI_RANGE_NUM() macro
>>   arm64: mm: Push __TLBI_VADDR() into __tlbi_level()
>>   arm64: mm: Inline __TLBI_VADDR_RANGE() into __tlbi_range()
>>   arm64: mm: Simplify __flush_tlb_range_limit_excess()
>>   arm64: mm: Re-implement the __flush_tlb_range_op macro in C
>>
>>  arch/arm64/include/asm/tlbflush.h | 230 ++++++++++++++++++------------
>>  arch/arm64/kernel/sys_compat.c    |   2 +-
>>  arch/arm64/kvm/hyp/nvhe/mm.c      |   2 +-
>>  arch/arm64/kvm/hyp/pgtable.c      |   4 +-
>>  4 files changed, 140 insertions(+), 98 deletions(-)
>>
> 



From ben.horgan at arm.com  Fri Dec 12 04:30:26 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 12 Dec 2025 12:30:26 +0000
Subject: [RFC PATCH 01/38] arm64: mpam: Context switch the MPAM registers
In-Reply-To: <20251205215901.17772-2-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-2-james.morse@arm.com>
Message-ID: <e5dfd85d-c431-490d-8946-54ebad81a0e4@arm.com>

Hi James,

On 12/5/25 21:58, James Morse wrote:
> MPAM allows traffic in the SoC to be labeled by the OS, these labels
> are used to apply policy in caches and bandwidth regulators, and to
> monitor traffic in the SoC. The label is made up of a PARTID and PMG
> value. The x86 equivalent calls these CLOSID and RMID, but they don't
> map precisely.
> 
> MPAM has two CPU system registers that is used to hold the PARTID and PMG
> values that traffic generated at each exception level will use. These can be
> set per-task by the resctrl file system. (resctrl is the defacto interface
> for controlling this stuff).
> 
> Add a helper to switch this.
> 
> struct task_struct's separate CLOSID and RMID fields are insufficient
> to implement resctrl using MPAM, as resctrl can change the PARTID (CLOSID)
> and PMG (sort of like the RMID) separately. On x86, the rmid is an
> independent number, so a race that writes a mismatched  closid and rmid
> into hardware is benign. On arm64, the pmg bits extend the partid.
> (i.e. partid-5 has a pmg-0 that is not the same as partid-6's pmg-0).
> In this case, mismatching the values will 'dirty' a pmg value that
> resctrl believes is clean, and is not tracking with its 'limbo' code.
> 
> To avoid this, the partid and pmg are always read and written as a pair.
> Instead of making struct task_struct's closid and rmid fields an
> endian-unsafe union, add the value to struct thread_info and always use
> READ_ONCE()/WRITE_ONCE() when accessing this field.
> 
> Resctrl allows a per-cpu 'default' value to be set, this overrides the
> values when scheduling a task in the default control-group, which has
> PARTID 0. The way 'code data prioritisation' gets emulated means the
> register value for the default group needs to be a variable.
> 
> The current system register value is kept in a per-cpu variable to
> avoid writing to the system register if the value isn't going to change.
> Writes to this register may reset the hardware state for regulating
> bandwidth.
> 
> Finally, there is no reason to context switch these registers unless
> there is a driver changing the values in struct task_struct. Hide
> the whole thing behind a static key. This also allows the driver to
> disable MPAM in response to errors reported by hardware. Move the
> existing static key to belong to the arch code, as in the future
> the MPAM driver may become a loadable module.
> 
> All this should depend on whether there is an MPAM driver, hide
> it behind CONFIG_MPAM.
> 
> CC: Amit Singh Tomar <amitsinght at marvell.com>
> Signed-off-by: James Morse <james.morse at arm.com>
[...]
> +
> +static inline void mpam_thread_switch(struct task_struct *tsk)
> +{
> +	u64 oldregval;
> +	int cpu = smp_processor_id();
> +	u64 regval = mpam_get_regval(tsk);
> +
> +	if (!IS_ENABLED(CONFIG_ARM64_MPAM) ||
> +	    !static_branch_likely(&mpam_enabled))
> +		return;
> +
> +	if (regval == READ_ONCE(arm64_mpam_global_default))
> +		regval = READ_ONCE(per_cpu(arm64_mpam_default, cpu));
> +
> +	oldregval = READ_ONCE(per_cpu(arm64_mpam_current, cpu));
> +	if (oldregval == regval)
> +		return;
> +
> +	write_sysreg_s(regval, SYS_MPAM1_EL1);
> +	isb();
> +
> +	/* Synchronising the EL0 write is left until the ERET to EL0 */
> +	write_sysreg_s(regval, SYS_MPAM0_EL1);

SYS_MPAMSM_EL1 needs to be written here too to account for accesses
generated by SME loads. Also, when in streaming mode, SVE and FP loads,
stores and SVE prefetches.

SYS_MPAMSM_EL1 should also be considered in initialisation code too.

> +
> +	WRITE_ONCE(per_cpu(arm64_mpam_current, cpu), regval);
> +}
Thanks,

Ben



From sudeep.holla at arm.com  Fri Dec 12 04:33:40 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Fri, 12 Dec 2025 12:33:40 +0000
Subject: [PATCH v1 10/17] firmware: arm_scmi: optee: Make use of
 module_tee_client_driver()
In-Reply-To: <537c48e3db243b5c68c3192179a948efb3a180c7.1765472125.git.u.kleine-koenig@baylibre.com>
References: <cover.1765472125.git.u.kleine-koenig@baylibre.com>
 <537c48e3db243b5c68c3192179a948efb3a180c7.1765472125.git.u.kleine-koenig@baylibre.com>
Message-ID: <20251212-rapid-vengeful-lionfish-85aef4@sudeepholla>

On Thu, Dec 11, 2025 at 06:15:04PM +0100, Uwe Kleine-K?nig wrote:
> Reduce boilerplate by using the newly introduced module_tee_client_driver().
> That takes care of assigning the driver's bus, so the explicit assigning
> in this driver can be dropped.
> 

Reviewed-by: Sudeep Holla <sudeep.holla at arm.com>

-- 
Regards,
Sudeep


From sudeep.holla at arm.com  Fri Dec 12 04:34:15 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Fri, 12 Dec 2025 12:34:15 +0000
Subject: [PATCH v1 11/17] firmware: arm_scmi: Make use of tee bus methods
In-Reply-To: <46dae3cada663b3a5ae1989881d9e74ef40acce5.1765472125.git.u.kleine-koenig@baylibre.com>
References: <cover.1765472125.git.u.kleine-koenig@baylibre.com>
 <46dae3cada663b3a5ae1989881d9e74ef40acce5.1765472125.git.u.kleine-koenig@baylibre.com>
Message-ID: <20251212-cuddly-viridian-armadillo-be28fe@sudeepholla>

On Thu, Dec 11, 2025 at 06:15:05PM +0100, Uwe Kleine-K?nig wrote:
> The tee bus got dedicated callbacks for probe and remove.
> Make use of these. This fixes a runtime warning about the driver needing
> to be converted to the bus methods. Note that the return value of .remove()
> was already ignored before, so there is no problem introduced by dropping
> the error returns.
> 

Reviewed-by: Sudeep Holla <sudeep.holla at arm.com>

-- 
Regards,
Sudeep


From nirmoyd at nvidia.com  Fri Dec 12 04:40:58 2025
From: nirmoyd at nvidia.com (Nirmoy Das)
Date: Fri, 12 Dec 2025 13:40:58 +0100
Subject: [RFC PATCH] iommu/arm-smmu-v3: Allow stream ID sharing for
 devices behind PCIe-to-PCI bridges
In-Reply-To: <650659ac-22f0-4fc0-ad43-8d4169cf2432@arm.com>
References: <20251211133933.4128100-1-nirmoyd@nvidia.com>
 <aTu4xsAApNupRGYC@ziepe.ca> <650659ac-22f0-4fc0-ad43-8d4169cf2432@arm.com>
Message-ID: <716d6455-0c0f-4005-ba47-f4222d935465@nvidia.com>


On 12.12.25 11:46, Robin Murphy wrote:
> On 2025-12-12 6:40 am, Jason Gunthorpe wrote:
>> On Thu, Dec 11, 2025 at 05:39:33AM -0800, Nirmoy Das wrote:
>>> ASPEED BMC controllers have VGA and USB functions behind a PCIe-to-PCI
>>> bridge that causes them to share the same stream ID:
>>>
>>> ?? \-[0005:e0]---00.0-[e1-e2]----00.0-[e2]--+-00.0? ASPEED Graphics 
>>> Family
>>> ??????????????????????????????????????????? \-02.0? ASPEED USB 
>>> Controller
>>>
>>> Both devices get stream ID(0x5e200) due to bridge aliasing. 
>>> Currently this
>>> USB controller gets rejected with "Aliasing StreamID unsupported", 
>>> causing
>>> USB timeout errors. Allow stream ID sharing when both devices are on
>>> the same bus behind a PCIe-to-PCI bridge to fix this issue.
>>
>> I don't think this is right, if you actually need stream ID sharing
>> then I seem to recall the driver needs more changes. We don't want
>> this in general.
>
> Yes, as I said on the last one not so long ago, we cannot simply cross 
> our fingers and hope that aliasing at the SMMU StreamID level stems 
> from something at the PCI RID level that pci_device_group() would be 
> aware of, because there is no guarantee that RID->StreamID mappings 
> are 1:1.
>
> Thanks,
> Robin.
>

Thanks, Jason and Robin for your feedback. I will reach out to ASPEED to 
find out if they are actually sharing RID as suggested by Jason.

>> IMHO ASPEED has wrong PCI config space and there isn't any actual PCI
>> bus here that would force RID aliasing to worry about. I suggest going
>> to ASPEED to find out and confirm that they don't actually share the
>> RIDs and then let's quirk the PCI devices to disable alias generation
>> in the first place.
>>
>> Also, complain to them to fix their config space to report a PCIe bridge
>> type in future devices. :)

I will do that :)


Thanks,

Nirmoy

>>
>> Jason
>


From leo.yan at arm.com  Fri Dec 12 04:44:02 2025
From: leo.yan at arm.com (Leo Yan)
Date: Fri, 12 Dec 2025 12:44:02 +0000
Subject: [PATCH 0/2] perf arm_spe: Minor event configs housekeeping
Message-ID: <20251212-perf_c2c_update_event-v1-0-29a26c7a949b@arm.com>

This series is to clean up event configs and update the doc for default
events used for Arm SPE.

A quick verifying on Orion6 board with commands:

  perf c2c record -e spe-load -- test
  perf c2c record -e spe-store -- test

Signed-off-by: Leo Yan <leo.yan at arm.com>
---
Leo Yan (2):
      perf mem: Simplify Arm SPE event config
      perf c2c: Update documentation for Arm SPE events

 tools/perf/Documentation/perf-c2c.txt   | 7 ++++++-
 tools/perf/arch/arm64/util/mem-events.c | 4 ++--
 2 files changed, 8 insertions(+), 3 deletions(-)
---
base-commit: cb015814f8b6eebcbb8e46e111d108892c5e6821
change-id: 20251212-perf_c2c_update_event-76d4eddebd23

Best regards,
-- 
Leo Yan <leo.yan at arm.com>



From leo.yan at arm.com  Fri Dec 12 04:44:03 2025
From: leo.yan at arm.com (Leo Yan)
Date: Fri, 12 Dec 2025 12:44:03 +0000
Subject: [PATCH 1/2] perf mem: Simplify Arm SPE event config
In-Reply-To: <20251212-perf_c2c_update_event-v1-0-29a26c7a949b@arm.com>
References: <20251212-perf_c2c_update_event-v1-0-29a26c7a949b@arm.com>
Message-ID: <20251212-perf_c2c_update_event-v1-1-29a26c7a949b@arm.com>

Since configuration fields default to zero, the zero assignments are
redundant, remove them.

Signed-off-by: Leo Yan <leo.yan at arm.com>
---
 tools/perf/arch/arm64/util/mem-events.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/perf/arch/arm64/util/mem-events.c b/tools/perf/arch/arm64/util/mem-events.c
index 9f8da7937255cc9b14c3c58a1119b40bd0c76f6b..eaf00e0609c6c1b7d939a02fe3794471d1ed119b 100644
--- a/tools/perf/arch/arm64/util/mem-events.c
+++ b/tools/perf/arch/arm64/util/mem-events.c
@@ -6,7 +6,7 @@
 #define E(t, n, s, l, a) { .tag = t, .name = n, .event_name = s, .ldlat = l, .aux_event = a }
 
 struct perf_mem_event perf_mem_events_arm[PERF_MEM_EVENTS__MAX] = {
-	E("spe-load",	"%s/ts_enable=1,pa_enable=1,load_filter=1,store_filter=0,min_latency=%u/",	NULL,	true,	0),
-	E("spe-store",	"%s/ts_enable=1,pa_enable=1,load_filter=0,store_filter=1/",			NULL,	false,	0),
+	E("spe-load",	"%s/ts_enable=1,pa_enable=1,load_filter=1,min_latency=%u/",	NULL,	true,	0),
+	E("spe-store",	"%s/ts_enable=1,pa_enable=1,store_filter=1/",			NULL,	false,	0),
 	E("spe-ldst",	"%s/ts_enable=1,pa_enable=1,load_filter=1,store_filter=1,min_latency=%u/",	NULL,	true,	0),
 };

-- 
2.34.1



From leo.yan at arm.com  Fri Dec 12 04:44:04 2025
From: leo.yan at arm.com (Leo Yan)
Date: Fri, 12 Dec 2025 12:44:04 +0000
Subject: [PATCH 2/2] perf c2c: Update documentation for Arm SPE events
In-Reply-To: <20251212-perf_c2c_update_event-v1-0-29a26c7a949b@arm.com>
References: <20251212-perf_c2c_update_event-v1-0-29a26c7a949b@arm.com>
Message-ID: <20251212-perf_c2c_update_event-v1-2-29a26c7a949b@arm.com>

Document the default Arm SPE events used by the perf c2c tool.  Make a
minor adjustment to the PowerPC entry for formatting consistency.

Suggested-by: Al Grant <al.grant at arm.com>
Signed-off-by: Leo Yan <leo.yan at arm.com>
---
 tools/perf/Documentation/perf-c2c.txt | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/tools/perf/Documentation/perf-c2c.txt b/tools/perf/Documentation/perf-c2c.txt
index 40b0f71a2c44eb642ff3bb234631a614b7c4fc9d..b765ae2511d2418a63092fb8a90a61faa335ac91 100644
--- a/tools/perf/Documentation/perf-c2c.txt
+++ b/tools/perf/Documentation/perf-c2c.txt
@@ -170,11 +170,16 @@ following on AMD:
 
   ibs_op//
 
-and following on PowerPC:
+following on PowerPC:
 
   cpu/mem-loads/
   cpu/mem-stores/
 
+following on Arm:
+
+  arm_spe_0/ts_enable=1,pa_enable=1,load_filter=1,min_latency=30/
+  arm_spe_0/ts_enable=1,pa_enable=1,store_filter=1/
+
 User can pass any 'perf record' option behind '--' mark, like (to enable
 callchains and system wide monitoring):
 

-- 
2.34.1



From nicolas.frattaroli at collabora.com  Fri Dec 12 04:43:55 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Fri, 12 Dec 2025 13:43:55 +0100
Subject: [PATCH v4 1/8] drm/rockchip: vop2: Switch impossible format conditional
 to WARN_ON
In-Reply-To: <20251211223822.6eeabb4d@pumpkin>
References: <20251211-vop2-atomic-fixups-v4-0-5d50eda26bf8@collabora.com>
 <20251211-vop2-atomic-fixups-v4-1-5d50eda26bf8@collabora.com>
 <20251211223822.6eeabb4d@pumpkin>
Message-ID: <14738785.uLZWGnKmhe@workhorse>

On Thursday, 11 December 2025 23:38:22 Central European Standard Time David Laight wrote:
> On Thu, 11 Dec 2025 21:40:31 +0100
> Nicolas Frattaroli <nicolas.frattaroli at collabora.com> wrote:
> 
> > From: Daniel Stone <daniels at collabora.com>
> > 
> > We should never be able to create a framebuffer with an unsupported
> > format, so throw a warning if this ever happens, instead of attempting
> > to stagger on.
> 
> It doesn't look like you've changed the behaviour.

Yes, the commit message needs to be adjusted.

> Except that all the systems with PANIC_ON_WARN set will panic.
> I believe that is somewhere over 90% of systems.

I also like making up statistics. Warning here is the correct move
in my opinion because this warning being triggered indicates a bug
in the kernel code, and with PANIC_ON_WARN the user explicitly says
they would rather panic in such a case than treat it as an abnormal
condition that is recoverable.

The reason why this condition ever occurring should be treated as an
abnormal condition is because the DRM subsystem should guarantee we
don't get a framebuffer of a format we didn't explicitly declare
support for in the first place. So this condition being hit either
means drm_universal_plane_init is broken, or the array of formats
that's passed to it is out of sync with the conversion code, which
is also a bug. Or someone managed to thoroughly hose DRM's internal
kernel-side data structures, which is precisely the kind of thing
PANIC_ON_WARN users want to abort for.

> 
> 	David
> 
> > 
> > Signed-off-by: Daniel Stone <daniels at collabora.com>
> > Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
> > ---
> >  drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 3 ++-
> >  1 file changed, 2 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> > index 498df0ce4680..20b49209ddcd 100644
> > --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> > @@ -1030,7 +1030,8 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
> >  		return 0;
> >  
> >  	format = vop2_convert_format(fb->format->format);
> > -	if (format < 0)
> > +	/* We shouldn't be able to create a fb for an unsupported format */
> > +	if (WARN_ON(format < 0))
> >  		return format;
> >  
> >  	/* Co-ordinates have now been clipped */
> > 
> 
> 






From andrew at lunn.ch  Fri Dec 12 05:32:59 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Fri, 12 Dec 2025 14:32:59 +0100
Subject: [PATCH v2 2/2] arm64: dts: freescale: Add FRDM-IMX91 basic
 support
In-Reply-To: <15608952-e974-4b9f-9832-e6a23860fc62@oss.nxp.com>
References: <20251212-imx91_frdm-v2-0-4dd6d289e81d@nxp.com>
 <20251212-imx91_frdm-v2-2-4dd6d289e81d@nxp.com>
 <55fa5159-768c-4785-b0ba-5553193932ab@lunn.ch>
 <15608952-e974-4b9f-9832-e6a23860fc62@oss.nxp.com>
Message-ID: <8334a902-fd56-4860-82c5-402e1d982fa9@lunn.ch>

On Fri, Dec 12, 2025 at 02:03:03PM +0800, Joseph Guo (OSS) wrote:
> 
> 
> On 12/12/2025 11:39 AM, Andrew Lunn wrote:
> > [You don't often get email from andrew at lunn.ch. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
> > 
> > > +&fec {
> > > +     phy-handle = <&ethphy2>;
> > > +     phy-mode = "rgmii-id";
> > > +     pinctrl-0 = <&pinctrl_fec>;
> > > +     pinctrl-1 = <&pinctrl_fec_sleep>;
> > > +     pinctrl-names = "default", "sleep";
> > > +     fsl,magic-packet;
> > 
> > Have you tested WoL?
> > 
> >          Andrew
> 
> Hi Andrew,
> 
> Yes, already tested.

Great. There is a tendency to just copy/paste this propriety without
understanding what it implies, so i just wanted to check...

For the Ethernet & PHY nodes only:

Reviewed-by: Andrew Lunn <andrew at lunn.ch>

    Andrew


From john.ogness at linutronix.de  Fri Dec 12 05:36:14 2025
From: john.ogness at linutronix.de (John Ogness)
Date: Fri, 12 Dec 2025 14:42:14 +0106
Subject: [PATCH v2] printk/nbcon: Restore IRQ in atomic flush after each
 emitted record
In-Reply-To: <20251212124520.244483-1-pmladek@suse.com>
References: <20251212124520.244483-1-pmladek@suse.com>
Message-ID: <87v7ibhlf5.fsf@jogness.linutronix.de>

On 2025-12-12, Petr Mladek <pmladek at suse.com> wrote:
> The commit d5d399efff6577 ("printk/nbcon: Release nbcon consoles ownership
> in atomic flush after each emitted record") prevented stall of a CPU
> which lost nbcon console ownership because another CPU entered
> an emergency flush.
>
> But there is still the problem that the CPU doing the emergency flush
> might cause a stall on its own.
>
> Let's go even further and restore IRQ in the atomic flush after
> each emitted record.
>
> It is not a complete solution. The interrupts and/or scheduling might
> still be blocked when the emergency atomic flush was called with
> IRQs and/or scheduling disabled. But it should remove the following
> lockup:
>
>   mlx5_core 0000:03:00.0: Shutdown was called
>   kvm: exiting hardware virtualization
>   arm-smmu-v3 arm-smmu-v3.10.auto: CMD_SYNC timeout at 0x00000103 [hwprod 0x00000104, hwcons 0x00000102]
>   smp: csd: Detected non-responsive CSD lock (#1) on CPU#4, waiting 5000000032 ns for CPU#00 do_nothing (kernel/smp.c:1057)
>   smp:     csd: CSD lock (#1) unresponsive.
>   [...]
>   Call trace:
>   pl011_console_write_atomic (./arch/arm64/include/asm/vdso/processor.h:12 drivers/tty/serial/amba-pl011.c:2540) (P)
>   nbcon_emit_next_record (kernel/printk/nbcon.c:1049)
>   __nbcon_atomic_flush_pending_con (kernel/printk/nbcon.c:1517)
>   __nbcon_atomic_flush_pending.llvm.15488114865160659019 (./arch/arm64/include/asm/alternative-macros.h:254 ./arch/arm64/include/asm/cpufeature.h:808 ./arch/arm64/include/asm/irqflags.h:192 kernel/printk/nbcon.c:1562 kernel/printk/nbcon.c:1612)
>   nbcon_atomic_flush_pending (kernel/printk/nbcon.c:1629)
>   printk_kthreads_shutdown (kernel/printk/printk.c:?)
>   syscore_shutdown (drivers/base/syscore.c:120)
>   kernel_kexec (kernel/kexec_core.c:1045)
>   __arm64_sys_reboot (kernel/reboot.c:794 kernel/reboot.c:722 kernel/reboot.c:722)
>   invoke_syscall (arch/arm64/kernel/syscall.c:50)
>   el0_svc_common.llvm.14158405452757855239 (arch/arm64/kernel/syscall.c:?)
>   do_el0_svc (arch/arm64/kernel/syscall.c:152)
>   el0_svc (./arch/arm64/include/asm/alternative-macros.h:254 ./arch/arm64/include/asm/cpufeature.h:808 ./arch/arm64/include/asm/irqflags.h:73 arch/arm64/kernel/entry-common.c:169 arch/arm64/kernel/entry-common.c:182 arch/arm64/kernel/entry-common.c:749)
>   el0t_64_sync_handler (arch/arm64/kernel/entry-common.c:820)
>   el0t_64_sync (arch/arm64/kernel/entry.S:600)
>
> In this case, nbcon_atomic_flush_pending() is called from
> printk_kthreads_shutdown() with IRQs and scheduling enabled.
>
> Note that __nbcon_atomic_flush_pending_con() is directly called also from
> nbcon_device_release() where the disabled IRQs might break PREEMPT_RT
> guarantees. But the atomic flush is called only in emergency or panic
> situations where the latencies are irrelevant anyway.
>
> An ultimate solution would be a touching of watchdogs. But it would hide
> all problems. Let's do it later when anyone reports a stall which does
> not have a better solution.
>
> Closes: https://lore.kernel.org/r/sqwajvt7utnt463tzxgwu2yctyn5m6bjwrslsnupfexeml6hkd at v6sqmpbu3vvu
> Tested-by: Breno Leitao <leitao at debian.org>
> Signed-off-by: Petr Mladek <pmladek at suse.com>

Reviewed-by: John Ogness <john.ogness at linutronix.de>


From nicolas at ndufresne.ca  Fri Dec 12 05:51:34 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Fri, 12 Dec 2025 08:51:34 -0500
Subject: [PATCH RFC v2 2/3] decoder: Add V4L2 stateless H.264 decoder
 driver
In-Reply-To: <12f26bf8-409b-4206-a39b-4bb2a14edec0@amlogic.com>
References: <20251124-b4-s4-vdec-upstream-v2-0-bdbbce3f11a6@amlogic.com>
	 <20251124-b4-s4-vdec-upstream-v2-2-bdbbce3f11a6@amlogic.com>
	 <9b74086ac938475328904960add2c284b81efd4a.camel@ndufresne.ca>
	 <12f26bf8-409b-4206-a39b-4bb2a14edec0@amlogic.com>
Message-ID: <f9c113914290a0701614c64b5e2167d4b3e21646.camel@ndufresne.ca>

Hi,

Le vendredi 12 d?cembre 2025 ? 12:11 +0800, Zhentao Guo a ?crit?:
> > strcpy() would be the preferred helper for this, no need to fill the leading
> > zero liek this, see include/linux/string.h
> Ok, it should be more suitable to use strcpy.

I have to correct myself, I meant to suggest strscpy(dst, src, size). Passing
the size for safety seems important, and unlike strncpy() it takes care of the
leading zero.

Nicolas
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251212/3ac01c8d/attachment-0001.sig>

From tomi.valkeinen at ideasonboard.com  Fri Dec 12 06:21:41 2025
From: tomi.valkeinen at ideasonboard.com (Tomi Valkeinen)
Date: Fri, 12 Dec 2025 16:21:41 +0200
Subject: [PATCH 0/4] drm: Revert and fix enable/disable sequence
In-Reply-To: <20251205-drm-seq-fix-v1-0-fda68fa1b3de@ideasonboard.com>
References: <20251205-drm-seq-fix-v1-0-fda68fa1b3de@ideasonboard.com>
Message-ID: <3b13c7a2-f7e6-49fd-b3bb-3e0a1fe9acf3@ideasonboard.com>

Hi,

On 05/12/2025 11:51, Tomi Valkeinen wrote:
> Changing the enable/disable sequence in commit c9b1150a68d9
> ("drm/atomic-helper: Re-order bridge chain pre-enable and post-disable")
> has caused regressions on multiple platforms: R-Car, MCDE, Rockchip.
> 
> This is an alternate series to Linus' series:
> 
> https://lore.kernel.org/all/20251202-mcde-drm-regression-thirdfix-v6-0-f1bffd4ec0fa%40kernel.org/
> 
> This series first reverts the original commit and reverts a fix for
> mediatek which is no longer needed. It then exposes helper functions
> from DRM core, and finally implements the new sequence only in the tidss
> driver.
> 
> There is one more fix in upstream for the original commit, commit
> 5d91394f2361 ("drm/exynos: fimd: Guard display clock control with
> runtime PM calls"), but I have not reverted that one as it looks like a
> valid patch in its own.
> 
> I added Cc stable v6.17+ to all patches, but I didn't add Fixes tags, as
> I wasn't sure what should they point to. But I could perhaps add Fixes:
> <original commit> to all of these.
There has been no comments, so I assume this is the way to go.

Should we merge this series as a fix for 6.18 rcs?

 Tomi



From robh at kernel.org  Fri Dec 12 06:39:36 2025
From: robh at kernel.org (Rob Herring)
Date: Fri, 12 Dec 2025 08:39:36 -0600
Subject: [PATCH 0/4] arm64: dts: imx91: misc updates
In-Reply-To: <20251212-imx91-dts-v1-0-2bb3c13762dd@nxp.com>
References: <20251212-imx91-dts-v1-0-2bb3c13762dd@nxp.com>
Message-ID: <176555030606.3954208.10492221378451090067.robh@kernel.org>


On Fri, 12 Dec 2025 17:16:06 +0800, Peng Fan (OSS) wrote:
> Patch 1,2: add temp sensor and thermal zone
> Patch 3: Update file name
> Patch 4: Add gpio4 alias
> 
> Signed-off-by: Peng Fan <peng.fan at nxp.com>
> ---
> Peng Fan (4):
>       arm64: dts: imx91: Add tempsensor node
>       arm64: dts: imx91: Add thermal zone node
>       arm64: dts: imx91: Update file name with dash
>       arm64: dts: imx91-11x11-evk: Add gpio4 alias
> 
>  arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts  |    1 +
>  arch/arm64/boot/dts/freescale/imx91.dtsi           |   58 +-
>  arch/arm64/boot/dts/freescale/imx91_93_common.dtsi | 1187 --------------------
>  arch/arm64/boot/dts/freescale/imx93.dtsi           |    2 +-
>  4 files changed, 59 insertions(+), 1189 deletions(-)
> ---
> base-commit: 008d3547aae5bc86fac3eda317489169c3fda112
> change-id: 20251212-imx91-dts-8d2e483191f7
> 
> Best regards,
> --
> Peng Fan <peng.fan at nxp.com>
> 
> 
> 


My bot found new DTB warnings on the .dts files added or changed in this
series.

Some warnings may be from an existing SoC .dtsi. Or perhaps the warnings
are fixed by another series. Ultimately, it is up to the platform
maintainer whether these warnings are acceptable or not. No need to reply
unless the platform maintainer has comments.

If you already ran DT checks and didn't see these error(s), then
make sure dt-schema is up to date:

  pip3 install dtschema --upgrade


This patch series was applied (using b4) to base:
 Base: 008d3547aae5bc86fac3eda317489169c3fda112 (use --merge-base to override)

If this is not the correct base, please add 'base-commit' tag
(or use b4 which does this automatically)

New warnings running 'make CHECK_DTBS=y for arch/arm64/boot/dts/freescale/' for 20251212-imx91-dts-v1-0-2bb3c13762dd at nxp.com:

In file included from arch/arm64/boot/dts/freescale/imx93-14x14-evk.dts:9:
arch/arm64/boot/dts/freescale/imx93.dtsi:6:10: fatal error: imx91-93-common.dtsi: No such file or directory
    6 | #include "imx91-93-common.dtsi"
      |          ^~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[3]: *** [scripts/Makefile.dtbs:141: arch/arm64/boot/dts/freescale/imx93-14x14-evk.dtb] Error 1
make[2]: *** [scripts/Makefile.build:556: arch/arm64/boot/dts/freescale] Error 2
make[2]: Target 'arch/arm64/boot/dts/freescale/imx93-14x14-evk.dtb' not remade because of errors.
make[1]: *** [/home/rob/proj/linux-dt-testing/Makefile:1512: freescale/imx93-14x14-evk.dtb] Error 2
In file included from arch/arm64/boot/dts/freescale/imx93-tqma9352.dtsi:8,
                 from arch/arm64/boot/dts/freescale/imx93-tqma9352-mba93xxca.dts:15:
arch/arm64/boot/dts/freescale/imx93.dtsi:6:10: fatal error: imx91-93-common.dtsi: No such file or directory
    6 | #include "imx91-93-common.dtsi"
      |          ^~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
In file included from arch/arm64/boot/dts/freescale/imx93-9x9-qsb.dts:9:
arch/arm64/boot/dts/freescale/imx93.dtsi:6:10: fatal error: imx91-93-common.dtsi: No such file or directory
    6 | #include "imx91-93-common.dtsi"
      |          ^~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[3]: *** [scripts/Makefile.dtbs:141: arch/arm64/boot/dts/freescale/imx93-tqma9352-mba93xxca.dtb] Error 1
make[3]: *** [scripts/Makefile.dtbs:141: arch/arm64/boot/dts/freescale/imx93-9x9-qsb.dtb] Error 1
make[2]: *** [scripts/Makefile.build:556: arch/arm64/boot/dts/freescale] Error 2
make[2]: Target 'arch/arm64/boot/dts/freescale/imx93-tqma9352-mba93xxca.dtb' not remade because of errors.
make[2]: *** [scripts/Makefile.build:556: arch/arm64/boot/dts/freescale] Error 2
make[2]: Target 'arch/arm64/boot/dts/freescale/imx93-9x9-qsb.dtb' not remade because of errors.
make[1]: *** [/home/rob/proj/linux-dt-testing/Makefile:1512: freescale/imx93-tqma9352-mba93xxca.dtb] Error 2
make[1]: *** [/home/rob/proj/linux-dt-testing/Makefile:1512: freescale/imx93-9x9-qsb.dtb] Error 2
In file included from arch/arm64/boot/dts/freescale/imx93-var-som.dtsi:9,
                 from arch/arm64/boot/dts/freescale/imx93-var-som-symphony.dts:10:
arch/arm64/boot/dts/freescale/imx93.dtsi:6:10: fatal error: imx91-93-common.dtsi: No such file or directory
    6 | #include "imx91-93-common.dtsi"
      |          ^~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[3]: *** [scripts/Makefile.dtbs:141: arch/arm64/boot/dts/freescale/imx93-var-som-symphony.dtb] Error 1
make[2]: *** [scripts/Makefile.build:556: arch/arm64/boot/dts/freescale] Error 2
make[2]: Target 'arch/arm64/boot/dts/freescale/imx93-var-som-symphony.dtb' not remade because of errors.
make[1]: *** [/home/rob/proj/linux-dt-testing/Makefile:1512: freescale/imx93-var-som-symphony.dtb] Error 2
In file included from arch/arm64/boot/dts/freescale/imx93-tqma9352.dtsi:8,
                 from arch/arm64/boot/dts/freescale/imx93-tqma9352-mba91xxca.dts:15:
arch/arm64/boot/dts/freescale/imx93.dtsi:6:10: fatal error: imx91-93-common.dtsi: No such file or directory
    6 | #include "imx91-93-common.dtsi"
      |          ^~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[3]: *** [scripts/Makefile.dtbs:141: arch/arm64/boot/dts/freescale/imx93-tqma9352-mba91xxca.dtb] Error 1
make[2]: *** [scripts/Makefile.build:556: arch/arm64/boot/dts/freescale] Error 2
make[2]: Target 'arch/arm64/boot/dts/freescale/imx93-tqma9352-mba91xxca.dtb' not remade because of errors.
make[1]: *** [/home/rob/proj/linux-dt-testing/Makefile:1512: freescale/imx93-tqma9352-mba91xxca.dtb] Error 2
In file included from arch/arm64/boot/dts/freescale/imx91-tqma9131.dtsi:9,
                 from arch/arm64/boot/dts/freescale/imx91-tqma9131-mba91xxca.dts:15:
arch/arm64/boot/dts/freescale/imx91.dtsi:7:10: fatal error: imx91-93-common.dtsi: No such file or directory
    7 | #include "imx91-93-common.dtsi"
      |          ^~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[3]: *** [scripts/Makefile.dtbs:141: arch/arm64/boot/dts/freescale/imx91-tqma9131-mba91xxca.dtb] Error 1
make[2]: *** [scripts/Makefile.build:556: arch/arm64/boot/dts/freescale] Error 2
make[2]: Target 'arch/arm64/boot/dts/freescale/imx91-tqma9131-mba91xxca.dtb' not remade because of errors.
make[1]: *** [/home/rob/proj/linux-dt-testing/Makefile:1512: freescale/imx91-tqma9131-mba91xxca.dtb] Error 2
In file included from arch/arm64/boot/dts/freescale/imx91-phycore-som.dtsi:12,
                 from arch/arm64/boot/dts/freescale/imx91-phyboard-segin.dts:12:
arch/arm64/boot/dts/freescale/imx91.dtsi:7:10: fatal error: imx91-93-common.dtsi: No such file or directory
    7 | #include "imx91-93-common.dtsi"
      |          ^~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[3]: *** [scripts/Makefile.dtbs:141: arch/arm64/boot/dts/freescale/imx91-phyboard-segin.dtb] Error 1
make[2]: *** [scripts/Makefile.build:556: arch/arm64/boot/dts/freescale] Error 2
make[2]: Target 'arch/arm64/boot/dts/freescale/imx91-phyboard-segin.dtb' not remade because of errors.
make[1]: *** [/home/rob/proj/linux-dt-testing/Makefile:1512: freescale/imx91-phyboard-segin.dtb] Error 2
In file included from arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts:9:
arch/arm64/boot/dts/freescale/imx91.dtsi:7:10: fatal error: imx91-93-common.dtsi: No such file or directory
    7 | #include "imx91-93-common.dtsi"
      |          ^~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[3]: *** [scripts/Makefile.dtbs:141: arch/arm64/boot/dts/freescale/imx91-11x11-evk.dtb] Error 1
make[2]: *** [scripts/Makefile.build:556: arch/arm64/boot/dts/freescale] Error 2
make[2]: Target 'arch/arm64/boot/dts/freescale/imx91-11x11-evk.dtb' not remade because of errors.
make[1]: *** [/home/rob/proj/linux-dt-testing/Makefile:1512: freescale/imx91-11x11-evk.dtb] Error 2
In file included from arch/arm64/boot/dts/freescale/imx93-tqma9352.dtsi:8,
                 from arch/arm64/boot/dts/freescale/imx93-tqma9352-mba93xxla.dts:15:
arch/arm64/boot/dts/freescale/imx93.dtsi:6:10: fatal error: imx91-93-common.dtsi: No such file or directory
    6 | #include "imx91-93-common.dtsi"
      |          ^~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[3]: *** [scripts/Makefile.dtbs:141: arch/arm64/boot/dts/freescale/imx93-tqma9352-mba93xxla.dtb] Error 1
make[2]: *** [scripts/Makefile.build:556: arch/arm64/boot/dts/freescale] Error 2
make[2]: Target 'arch/arm64/boot/dts/freescale/imx93-tqma9352-mba93xxla.dtb' not remade because of errors.
make[1]: *** [/home/rob/proj/linux-dt-testing/Makefile:1512: freescale/imx93-tqma9352-mba93xxla.dtb] Error 2
In file included from arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts:9:
arch/arm64/boot/dts/freescale/imx93.dtsi:6:10: fatal error: imx91-93-common.dtsi: No such file or directory
    6 | #include "imx91-93-common.dtsi"
      |          ^~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[3]: *** [scripts/Makefile.dtbs:141: arch/arm64/boot/dts/freescale/imx93-11x11-evk.dtb] Error 1
make[2]: *** [scripts/Makefile.build:556: arch/arm64/boot/dts/freescale] Error 2
make[2]: Target 'arch/arm64/boot/dts/freescale/imx93-11x11-evk.dtb' not remade because of errors.
make[1]: *** [/home/rob/proj/linux-dt-testing/Makefile:1512: freescale/imx93-11x11-evk.dtb] Error 2
In file included from arch/arm64/boot/dts/freescale/imx93-phycore-som.dtsi:13,
                 from arch/arm64/boot/dts/freescale/imx93-phyboard-nash.dts:13:
arch/arm64/boot/dts/freescale/imx93.dtsi:6:10: fatal error: imx91-93-common.dtsi: No such file or directory
    6 | #include "imx91-93-common.dtsi"
      |          ^~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[3]: *** [scripts/Makefile.dtbs:141: arch/arm64/boot/dts/freescale/imx93-phyboard-nash.dtb] Error 1
make[2]: *** [scripts/Makefile.build:556: arch/arm64/boot/dts/freescale] Error 2
make[2]: Target 'arch/arm64/boot/dts/freescale/imx93-phyboard-nash.dtb' not remade because of errors.
make[1]: *** [/home/rob/proj/linux-dt-testing/Makefile:1512: freescale/imx93-phyboard-nash.dtb] Error 2
In file included from arch/arm64/boot/dts/freescale/imx93-phycore-som.dtsi:13,
                 from arch/arm64/boot/dts/freescale/imx93-phyboard-segin.dts:13:
arch/arm64/boot/dts/freescale/imx93.dtsi:6:10: fatal error: imx91-93-common.dtsi: No such file or directory
    6 | #include "imx91-93-common.dtsi"
      |          ^~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[3]: *** [scripts/Makefile.dtbs:141: arch/arm64/boot/dts/freescale/imx93-phyboard-segin.dtb] Error 1
make[2]: *** [scripts/Makefile.build:556: arch/arm64/boot/dts/freescale] Error 2
make[2]: Target 'arch/arm64/boot/dts/freescale/imx93-phyboard-segin.dtb' not remade because of errors.
make[1]: *** [/home/rob/proj/linux-dt-testing/Makefile:1512: freescale/imx93-phyboard-segin.dtb] Error 2
In file included from arch/arm64/boot/dts/freescale/imx93-kontron-osm-s.dtsi:7,
                 from arch/arm64/boot/dts/freescale/imx93-kontron-bl-osm-s.dts:8:
arch/arm64/boot/dts/freescale/imx93.dtsi:6:10: fatal error: imx91-93-common.dtsi: No such file or directory
    6 | #include "imx91-93-common.dtsi"
      |          ^~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[3]: *** [scripts/Makefile.dtbs:141: arch/arm64/boot/dts/freescale/imx93-kontron-bl-osm-s.dtb] Error 1
make[2]: *** [scripts/Makefile.build:556: arch/arm64/boot/dts/freescale] Error 2
make[2]: Target 'arch/arm64/boot/dts/freescale/imx93-kontron-bl-osm-s.dtb' not remade because of errors.
make[1]: *** [/home/rob/proj/linux-dt-testing/Makefile:1512: freescale/imx93-kontron-bl-osm-s.dtb] Error 2
make: *** [Makefile:248: __sub-make] Error 2
make: Target 'freescale/imx8dx-colibri-eval-v3.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-var-som-symphony.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-nitrogen-enc-carrier-board.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1046a-qds.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-prt8mm.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1028a-kontron-sl28.dtb' not remade because of errors.
make: Target 'freescale/imx8qxp-tqma8xqp-mba8xx.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-beacon-kit.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-venice-gw73xx-2x.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-var-som-symphony.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-icore-mx8mp-edimm2.2.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-innocomm-wb15-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8qm-apalis-v1.1-eval.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-aristainetos3-proton2s.dtb' not remade because of errors.
make: Target 'freescale/imx8dx-colibri-iris-v2.dtb' not remade because of errors.
make: Target 'freescale/imx8mn-ddr3l-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-icore-mx8mm-edimm2.2.dtb' not remade because of errors.
make: Target 'freescale/imx8mn-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-dhcom-pdk3.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1028a-kontron-kbox-a-230-ls.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-phyboard-polis-rdk.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-venice-gw72xx-2x.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-venice-gw7901.dtb' not remade because of errors.
make: Target 'freescale/imx8mn-beacon-kit.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1028a-kontron-sl28-var1.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1028a-kontron-sl28-var3.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-debix-som-a-bmb-08.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-verdin-nonwifi-dahlia.dtb' not remade because of errors.
make: Target 'freescale/imx8qxp-ai_ml.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-verdin-wifi-dev.dtb' not remade because of errors.
make: Target 'freescale/s32v234-evb.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-skov-revb-lt6.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-phg.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-nitrogen-smarc-universal-board.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-venice-gw71xx-0x.dtb' not remade because of errors.
make: Target 'freescale/imx8ulp-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8qxp-colibri-iris.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-emtop-baseboard.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-hummingboard-pro.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1028a-kontron-sl28-var4.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-librem5-r4.dtb' not remade because of errors.
make: Target 'freescale/imx8dx-colibri-aster.dtb' not remade because of errors.
make: Target 'freescale/imx8mn-rve-gateway.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-venice-gw71xx-2x.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls2080a-rdb.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-pico-pi.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-verdin-wifi-mallow.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-msc-sm2s-ep1.dtb' not remade because of errors.
make: Target 'freescale/imx8dxl-evk.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1043a-qds.dtb' not remade because of errors.
make: Target 'freescale/s32g399a-rdb3.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-venice-gw72xx-0x.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-verdin-wifi-ivy.dtb' not remade because of errors.
make: Target 'freescale/imx8mn-bsh-smm-s2.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-aristainetos3-adpismarc.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-tx8p-ml81-moduline-display-106.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-verdin-nonwifi-mallow.dtb' not remade because of errors.
make: Target 'freescale/imx8qxp-tqma8xqps-mb-smarc-2.dtb' not remade because of errors.
make: Target 'freescale/imx8mn-dimonoff-gateway-evk.dtb' not remade because of errors.
make: Target 'freescale/imx93-tqma9352-mba93xxca.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-tqma8mq-mba8mx.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1012a-oxalis.dtb' not remade because of errors.
make: Target 'freescale/imx93-14x14-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8dx-colibri-iris.dtb' not remade because of errors.
make: Target 'freescale/imx8mn-var-som-symphony.dtb' not remade because of errors.
make: Target 'freescale/imx95-toradex-smarc-dev.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-kontron-smarc-eval-carrier.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls2080a-simu.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1046a-frwy.dtb' not remade because of errors.
make: Target 'freescale/imx93-9x9-qsb.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-verdin-wifi-yavia.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-verdin-nonwifi-yavia.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-verdin-wifi-mallow.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-debix-model-a.dtb' not remade because of errors.
make: Target 'freescale/imx8qm-apalis-v1.1-ixora-v1.2.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-icore-mx8mm-ctouch2.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-zii-ultra-rmb3.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-phygate-tauri-l.dtb' not remade because of errors.
make: Target 'freescale/imx8qm-apalis-v1.1-eval-v1.2.dtb' not remade because of errors.
make: Target 'freescale/fsl-lx2162a-clearfog.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-data-modul-edm-sbc.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-librem5-devkit.dtb' not remade because of errors.
make: Target 'freescale/fsl-lx2160a-tqmlx2160a-mblx2160a.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1012a-tqmls1012al-mbls1012al-emmc.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-cubox-m.dtb' not remade because of errors.
make: Target 'freescale/fsl-lx2160a-honeycomb.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-skov-revb-hdmi.dtb' not remade because of errors.
make: Target 'freescale/imx8qm-apalis-eval.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-venice-gw7904.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-skov-revb-mi1010ait-1cp1.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-navqp.dtb' not remade because of errors.
make: Target 'freescale/fsl-lx2160a-qds.dtb' not remade because of errors.
make: Target 'freescale/fsl-lx2160a-bluebox3.dtb' not remade because of errors.
make: Target 'freescale/imx93-var-som-symphony.dtb' not remade because of errors.
make: Target 'freescale/imx8dxp-tqma8xdps-mb-smarc-2.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-nitrogen-r2.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1028a-kontron-sl28-var3-ads2.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1046a-rdb.dtb' not remade because of errors.
make: Target 'freescale/imx93-tqma9352-mba91xxca.dtb' not remade because of errors.
make: Target 'freescale/imx95-tqma9596sa-mb-smarc-2.dtb' not remade because of errors.
make: Target 'freescale/imx8mn-ddr4-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8mn-bsh-smm-s2pro.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-phanbell.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-venice-gw7903.dtb' not remade because of errors.
make: Target 'freescale/s32g274a-evb.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-ddr4-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-dhcom-pdk2.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1012a-frdm.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1012a-qds.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1043a-rdb.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-phyboard-pollux-rdk.dtb' not remade because of errors.
make: Target 'freescale/imx8qm-mek.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1088a-qds.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1088a-rdb.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-verdin-wifi-dev.dtb' not remade because of errors.
make: Target 'freescale/imx8qm-apalis-v1.1-ixora-v1.1.dtb' not remade because of errors.
make: Target 'freescale/imx91-tqma9131-mba91xxca.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-hummingboard-mate.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-venice-gw75xx-0x.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-venice-gw74xx.dtb' not remade because of errors.
make: Target 'freescale/imx8qm-apalis-ixora-v1.1.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-aristainetos3-helios.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-skov-revc-bd500.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-prt8ml.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-verdin-nonwifi-dahlia.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-iot-gateway.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-librem5-r2.dtb' not remade because of errors.
make: Target 'freescale/imx95-libra-rdk-fpsc.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1088a-ten64.dtb' not remade because of errors.
make: Target 'freescale/imx8ulp-9x9-evk.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1028a-qds.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-verdin-wifi-dahlia.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-beacon-kit.dtb' not remade because of errors.
make: Target 'freescale/imx91-phyboard-segin.dtb' not remade because of errors.
make: Target 'freescale/fsl-lx2162a-qds.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1046a-tqmls1046a-mbls10xxa.dtb' not remade because of errors.
make: Target 'freescale/imx91-11x11-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-verdin-wifi-dahlia.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-evkb.dtb' not remade because of errors.
make: Target 'freescale/imx93-tqma9352-mba93xxla.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-emcon-avari.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-edm-g-wb.dtb' not remade because of errors.
make: Target 'freescale/imx93-11x11-evk.dtb' not remade because of errors.
make: Target 'freescale/imx95-19x19-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-hummingboard-ripple.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1012a-tqmls1012al-mbls1012al.dtb' not remade because of errors.
make: Target 'freescale/fsl-lx2160a-clearfog-cx.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-tqma8mqml-mba8mx.dtb' not remade because of errors.
make: Target 'freescale/imx95-19x19-verdin-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-verdin-nonwifi-ivy.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-dhcom-drc02.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-toradex-smarc-dev.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-verdin-wifi-ivy.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-skov-revc-hdmi.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-tqma8mpql-mba8mp-ras314.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-verdin-nonwifi-yavia.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1012a-rdb.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1012a-frwy.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1028a-kontron-sl28-var2.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-verdin-nonwifi-mallow.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-venice-gw73xx-0x.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1043a-tqmls1043a-mbls10xxa.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-kontron-bl-osm-s.dtb' not remade because of errors.
make: Target 'freescale/fsl-lx2160a-bluebox3-rev-a.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1088a-tqmls1088a-mbls10xxa.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-verdin-wifi-yavia.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-mx8menlo.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls2081a-rdb.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-mnt-reform2.dtb' not remade because of errors.
make: Target 'freescale/imx8qxp-colibri-iris-v2.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls2088a-rdb.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-zii-ultra-zest.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-tqma8mpql-mba8mpxl.dtb' not remade because of errors.
make: Target 'freescale/imx8qm-apalis-eval-v1.2.dtb' not remade because of errors.
make: Target 'freescale/s32g274a-rdb2.dtb' not remade because of errors.
make: Target 'freescale/imx93-phyboard-nash.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-verdin-nonwifi-dev.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-ultra-mach-sbc.dtb' not remade because of errors.
make: Target 'freescale/imx8mn-tqma8mqnl-mba8mx.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-kontron-bl-osm-s.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls2080a-qds.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-verdin-nonwifi-ivy.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-data-modul-edm-sbc.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-librem5-r3.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls2088a-qds.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-kontron-pitx-imx8m.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-venice-gw7902.dtb' not remade because of errors.
make: Target 'freescale/fsl-lx2160a-rdb.dtb' not remade because of errors.
make: Target 'freescale/imx95-19x19-evk-sof.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-venice-gw82xx-2x.dtb' not remade because of errors.
make: Target 'freescale/imx93-phyboard-segin.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-verdin-nonwifi-dev.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-kontron-bl.dtb' not remade because of errors.
make: Target 'freescale/imx8dxp-tqma8xdp-mba8xx.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-hummingboard-pulse.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-skov-revc-jutouch-jt101tm023.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-libra-rdk-fpsc.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-venice-gw75xx-2x.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8qxp-colibri-eval-v3.dtb' not remade because of errors.
make: Target 'freescale/imx943-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8qxp-colibri-aster.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-nitrogen.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-skov-basic.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-thor96.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1028a-rdb.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-hummingboard-pulse.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-iota2-lumpy.dtb' not remade because of errors.
make: Target 'freescale/imx8mn-venice-gw7902.dtb' not remade because of errors.
make: Target 'freescale/imx8qxp-mek.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-skov-revc-tian-g07017.dtb' not remade because of errors.
make: Target 'freescale/imx93-kontron-bl-osm-s.dtb' not remade because of errors.
make: Target 'freescale/imx95-15x15-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-dhcom-picoitx.dtb' not remade because of errors.







From james.clark at linaro.org  Fri Dec 12 06:43:57 2025
From: james.clark at linaro.org (James Clark)
Date: Fri, 12 Dec 2025 16:43:57 +0200
Subject: [PATCH v2 01/12] perf parse-events: Refactor get_config_terms()
 to remove macros
In-Reply-To: <CAP-5=fW6_MVrezxT6ssjhWnYtF_51nvuFCCSPaHzqwYw9EK4Wg@mail.gmail.com>
References: <20251208-james-perf-config-bits-v2-0-4ac0281993b0@linaro.org>
 <20251208-james-perf-config-bits-v2-1-4ac0281993b0@linaro.org>
 <6ba6bde3-f56b-4354-b336-4739cb1edb71@linaro.org>
 <CAP-5=fV_Y5W2RyJhBgnk49JuTf8EsyisY-LfL3sVhC4TVRC_gg@mail.gmail.com>
 <d275d2fb-8670-4832-b9c4-de98376e58ad@linaro.org>
 <CAP-5=fW6_MVrezxT6ssjhWnYtF_51nvuFCCSPaHzqwYw9EK4Wg@mail.gmail.com>
Message-ID: <99e9614d-a956-40dc-a86b-a4c5aea0fe8a@linaro.org>



On 09/12/2025 20:09, Ian Rogers wrote:
> On Tue, Dec 9, 2025 at 9:55?AM James Clark <james.clark at linaro.org> wrote:
>>
>> On 09/12/2025 15:58, Ian Rogers wrote:
>>> On Tue, Dec 9, 2025 at 4:48?AM James Clark <james.clark at linaro.org> wrote:
>>>>
>>>> On 08/12/2025 2:22 pm, James Clark wrote:
>>>>> The ADD_CONFIG_TERM() macros build the __type argument out of a partial
>>>>> EVSEL__CONFIG_TERM_x enum name. This means that they can't be called
>>>>> from a function where __type is a variable and it's also impossible to
>>>>> grep the codebase to find usages of these enums as they're never typed
>>>>> in full.
>>>>>
>>>>> Fix this by removing the macros and replacing them with an
>>>>> add_config_term() function. It seems the main reason these existed in
>>>>> the first place was to avoid type punning and to write to a specific
>>>>> field in the union, but the same thing can be achieved with a single
>>>>> write to a u64 'val' field.
>>>>>
>>>>> Signed-off-by: James Clark <james.clark at linaro.org>
>>>>> ---
>>>>>     tools/perf/util/evsel_config.h |   1 +
>>>>>     tools/perf/util/parse-events.c | 146 ++++++++++++++++++++++++-----------------
>>>>>     2 files changed, 86 insertions(+), 61 deletions(-)
>>>>>
>>>>> diff --git a/tools/perf/util/evsel_config.h b/tools/perf/util/evsel_config.h
>>>>> index bcd3a978f0c4..685fd8d5c4a8 100644
>>>>> --- a/tools/perf/util/evsel_config.h
>>>>> +++ b/tools/perf/util/evsel_config.h
>>>>> @@ -50,6 +50,7 @@ struct evsel_config_term {
>>>>>                 u64           cfg_chg;
>>>>>                 char          *str;
>>>>>                 int           cpu;
>>>>> +             u64           val;
>>>>>         } val;
>>>>>         bool weak;
>>>>>     };
>>>>> diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
>>>>> index 17c1c36a7bf9..d5b009b4ebab 100644
>>>>> --- a/tools/perf/util/parse-events.c
>>>>> +++ b/tools/perf/util/parse-events.c
>>>>> @@ -1116,105 +1116,107 @@ static int config_attr(struct perf_event_attr *attr,
>>>>>         return 0;
>>>>>     }
>>>>>
>>>>> -static int get_config_terms(const struct parse_events_terms *head_config,
>>>>> -                         struct list_head *head_terms)
>>>>> +static struct evsel_config_term *add_config_term(enum evsel_term_type type,
>>>>> +                                              struct list_head *head_terms,
>>>>> +                                              bool weak)
>>>>>     {
>>>>> -#define ADD_CONFIG_TERM(__type, __weak)                              \
>>>>> -     struct evsel_config_term *__t;                  \
>>>>> -                                                             \
>>>>> -     __t = zalloc(sizeof(*__t));                             \
>>>>> -     if (!__t)                                               \
>>>>> -             return -ENOMEM;                                 \
>>>>> -                                                             \
>>>>> -     INIT_LIST_HEAD(&__t->list);                             \
>>>>> -     __t->type       = EVSEL__CONFIG_TERM_ ## __type;        \
>>>>> -     __t->weak       = __weak;                               \
>>>>> -     list_add_tail(&__t->list, head_terms)
>>>>> -
>>>>> -#define ADD_CONFIG_TERM_VAL(__type, __name, __val, __weak)   \
>>>>> -do {                                                         \
>>>>> -     ADD_CONFIG_TERM(__type, __weak);                        \
>>>>> -     __t->val.__name = __val;                                \
>>>>> -} while (0)
>>>>> +     struct evsel_config_term *t;
>>>>>
>>>>> -#define ADD_CONFIG_TERM_STR(__type, __val, __weak)           \
>>>>> -do {                                                         \
>>>>> -     ADD_CONFIG_TERM(__type, __weak);                        \
>>>>> -     __t->val.str = strdup(__val);                           \
>>>>> -     if (!__t->val.str) {                                    \
>>>>> -             zfree(&__t);                                    \
>>>>> -             return -ENOMEM;                                 \
>>>>> -     }                                                       \
>>>>> -     __t->free_str = true;                                   \
>>>>> -} while (0)
>>>>> +     t = zalloc(sizeof(*t));
>>>>> +     if (!t)
>>>>> +             return NULL;
>>>>> +
>>>>> +     INIT_LIST_HEAD(&t->list);
>>>>> +     t->type = type;
>>>>> +     t->weak = weak;
>>>>> +     list_add_tail(&t->list, head_terms);
>>>>>
>>>>> +     return t;
>>>>> +}
>>>>> +
>>>>> +static int get_config_terms(const struct parse_events_terms *head_config,
>>>>> +                         struct list_head *head_terms)
>>>>> +{
>>>>>         struct parse_events_term *term;
>>>>>
>>>>>         list_for_each_entry(term, &head_config->terms, list) {
>>>>> +             struct evsel_config_term *new_term;
>>>>> +             enum evsel_term_type new_type;
>>>>> +             char *str = NULL;
>>>>> +             u64 val;
>>>>> +
>>>>>                 switch (term->type_term) {
>>>>>                 case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
>>>>> -                     ADD_CONFIG_TERM_VAL(PERIOD, period, term->val.num, term->weak);
>>>>> +                     new_type = EVSEL__CONFIG_TERM_PERIOD;
>>>>> +                     val = term->val.num;
>>>>>                         break;
>>>>>                 case PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ:
>>>>> -                     ADD_CONFIG_TERM_VAL(FREQ, freq, term->val.num, term->weak);
>>>>> +                     new_type = EVSEL__CONFIG_TERM_FREQ;
>>>>> +                     val = term->val.num;
>>>>>                         break;
>>>>>                 case PARSE_EVENTS__TERM_TYPE_TIME:
>>>>> -                     ADD_CONFIG_TERM_VAL(TIME, time, term->val.num, term->weak);
>>>>> +                     new_type = EVSEL__CONFIG_TERM_TIME;
>>>>> +                     val = term->val.num;
>>>>>                         break;
>>>>>                 case PARSE_EVENTS__TERM_TYPE_CALLGRAPH:
>>>>> -                     ADD_CONFIG_TERM_STR(CALLGRAPH, term->val.str, term->weak);
>>>>> +                     new_type = EVSEL__CONFIG_TERM_CALLGRAPH;
>>>>> +                     str = term->val.str;
>>>>>                         break;
>>>>>                 case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
>>>>> -                     ADD_CONFIG_TERM_STR(BRANCH, term->val.str, term->weak);
>>>>> +                     new_type = EVSEL__CONFIG_TERM_BRANCH;
>>>>> +                     str = term->val.str;
>>>>>                         break;
>>>>>                 case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
>>>>> -                     ADD_CONFIG_TERM_VAL(STACK_USER, stack_user,
>>>>> -                                         term->val.num, term->weak);
>>>>> +                     new_type = EVSEL__CONFIG_TERM_STACK_USER;
>>>>> +                     val = term->val.num;
>>>>>                         break;
>>>>>                 case PARSE_EVENTS__TERM_TYPE_INHERIT:
>>>>> -                     ADD_CONFIG_TERM_VAL(INHERIT, inherit,
>>>>> -                                         term->val.num ? 1 : 0, term->weak);
>>>>> +                     new_type = EVSEL__CONFIG_TERM_INHERIT;
>>>>> +                     val = term->val.num ? 1 : 0;
>>>>>                         break;
>>>>>                 case PARSE_EVENTS__TERM_TYPE_NOINHERIT:
>>>>> -                     ADD_CONFIG_TERM_VAL(INHERIT, inherit,
>>>>> -                                         term->val.num ? 0 : 1, term->weak);
>>>>> +                     new_type = EVSEL__CONFIG_TERM_INHERIT;
>>>>> +                     val = term->val.num ? 0 : 1;
>>>>>                         break;
>>>>>                 case PARSE_EVENTS__TERM_TYPE_MAX_STACK:
>>>>> -                     ADD_CONFIG_TERM_VAL(MAX_STACK, max_stack,
>>>>> -                                         term->val.num, term->weak);
>>>>> +                     new_type = EVSEL__CONFIG_TERM_MAX_STACK;
>>>>> +                     val = term->val.num;
>>>>>                         break;
>>>>>                 case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS:
>>>>> -                     ADD_CONFIG_TERM_VAL(MAX_EVENTS, max_events,
>>>>> -                                         term->val.num, term->weak);
>>>>> +                     new_type = EVSEL__CONFIG_TERM_MAX_EVENTS;
>>>>> +                     val = term->val.num;
>>>>>                         break;
>>>>>                 case PARSE_EVENTS__TERM_TYPE_OVERWRITE:
>>>>> -                     ADD_CONFIG_TERM_VAL(OVERWRITE, overwrite,
>>>>> -                                         term->val.num ? 1 : 0, term->weak);
>>>>> +                     new_type = EVSEL__CONFIG_TERM_OVERWRITE;
>>>>> +                     val = term->val.num ? 1 : 0;
>>>>>                         break;
>>>>>                 case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE:
>>>>> -                     ADD_CONFIG_TERM_VAL(OVERWRITE, overwrite,
>>>>> -                                         term->val.num ? 0 : 1, term->weak);
>>>>> +                     new_type = EVSEL__CONFIG_TERM_OVERWRITE;
>>>>> +                     val = term->val.num ? 0 : 1;
>>>>>                         break;
>>>>>                 case PARSE_EVENTS__TERM_TYPE_DRV_CFG:
>>>>> -                     ADD_CONFIG_TERM_STR(DRV_CFG, term->val.str, term->weak);
>>>>> +                     new_type = EVSEL__CONFIG_TERM_DRV_CFG;
>>>>> +                     str = term->val.str;
>>>>>                         break;
>>>>>                 case PARSE_EVENTS__TERM_TYPE_PERCORE:
>>>>> -                     ADD_CONFIG_TERM_VAL(PERCORE, percore,
>>>>> -                                         term->val.num ? true : false, term->weak);
>>>>> +                     new_type = EVSEL__CONFIG_TERM_PERCORE;
>>>>> +                     val = term->val.num ? true : false;
>>>>>                         break;
>>>>>                 case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT:
>>>>> -                     ADD_CONFIG_TERM_VAL(AUX_OUTPUT, aux_output,
>>>>> -                                         term->val.num ? 1 : 0, term->weak);
>>>>> +                     new_type = EVSEL__CONFIG_TERM_AUX_OUTPUT;
>>>>> +                     val = term->val.num ? 1 : 0;
>>>>>                         break;
>>>>>                 case PARSE_EVENTS__TERM_TYPE_AUX_ACTION:
>>>>> -                     ADD_CONFIG_TERM_STR(AUX_ACTION, term->val.str, term->weak);
>>>>> +                     new_type = EVSEL__CONFIG_TERM_AUX_ACTION;
>>>>> +                     str = term->val.str;
>>>>>                         break;
>>>>>                 case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE:
>>>>> -                     ADD_CONFIG_TERM_VAL(AUX_SAMPLE_SIZE, aux_sample_size,
>>>>> -                                         term->val.num, term->weak);
>>>>> +                     new_type = EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE;
>>>>> +                     val = term->val.num;
>>>>>                         break;
>>>>>                 case PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV:
>>>>> -                     ADD_CONFIG_TERM_STR(RATIO_TO_PREV, term->val.str, term->weak);
>>>>> +                     new_type = EVSEL__CONFIG_TERM_RATIO_TO_PREV;
>>>>> +                     str = term->val.str;
>>>>>                         break;
>>>>>                 case PARSE_EVENTS__TERM_TYPE_USER:
>>>>>                 case PARSE_EVENTS__TERM_TYPE_CONFIG:
>>>>> @@ -1229,7 +1231,23 @@ do {                                                           \
>>>>>                 case PARSE_EVENTS__TERM_TYPE_RAW:
>>>>>                 case PARSE_EVENTS__TERM_TYPE_CPU:
>>>>>                 default:
>>>>> -                     break;
>>>>> +                     /* Don't add a new term for these ones */
>>>>> +                     continue;
>>>>> +             }
>>>>> +
>>>>> +             new_term = add_config_term(new_type, head_terms, term->weak);
>>>>> +             if (!new_term)
>>>>> +                     return -ENOMEM;
>>>>> +
>>>>> +             if (str) {
>>>>> +                     new_term->val.str = strdup(str);
>>>>> +                     if (!new_term->val.str) {
>>>>> +                             zfree(&new_term);
>>>>> +                             return -ENOMEM;
>>>>> +                     }
>>>>> +                     new_term->free_str = true;
>>>>> +             } else {
>>>>
>>>> This will incorrectly hit the else if term->val.str is NULL. Not sure if
>>>> that can happen but will fix anyway.
>>>>
>>>>> +                     new_term->val.val = val;
>>>>
>>>> There's an uninitialized variable warning for val here on release
>>>> builds. Will fix too
>>>
>>> I'm not sure how I feel about the change, but did you check that it is
>>> ubsan clean? I worry it is introducing writes to "val" and then reads
>>> from say "period" in the evsel_config_term val union. I believe ubsan
>>> will flag this as:
>>> https://en.cppreference.com/w/cpp/language/union.html
>>> "It is undefined behavior to read from the member of the union that
>>> wasn't most recently written."
>>>
>>> Thanks,
>>> Ian
>>>
>>
>> Maybe for C++, but not for C [1]:
>>
>>     Accessing my_union.i after most recently writing to the other member,
>>     my_union.d, is an allowed form of type-punning in C, provided that the
>>     member read is not larger than the one whose value was set
>>
>> Type punning with unions is widely used in the kernel and there are a
>> couple of instances in Perf. There are tons of discussions about it on
>> the mailing lists too. I can check it with ubsan though.
> 
> Thanks. I'm mostly worried about ubsan being clean. One of those
> mailing list discussions, or sadly outside the usual trolls lack of
> discussion, is my trying to remove a prevalent source of type punning:
> https://lore.kernel.org/lkml/20251016205126.2882625-1-irogers at google.com/
> 
> Ian
> 

No ubsan issues on any Perf tests from this, but I did forget a free in 
the new test that I saw with asan so I'll send a new version.


>> [1]: https://en.wikipedia.org/wiki/Type_punning#C_and_C++
>>
>>>>>                 }
>>>>>         }
>>>>>         return 0;
>>>>> @@ -1290,10 +1308,16 @@ static int get_config_chgs(struct perf_pmu *pmu, struct parse_events_terms *head
>>>>>                 }
>>>>>         }
>>>>>
>>>>> -     if (bits)
>>>>> -             ADD_CONFIG_TERM_VAL(CFG_CHG, cfg_chg, bits, false);
>>>>> +     if (bits) {
>>>>> +             struct evsel_config_term *new_term;
>>>>> +
>>>>> +             new_term = add_config_term(EVSEL__CONFIG_TERM_CFG_CHG,
>>>>> +                                        head_terms, false);
>>>>> +             if (!new_term)
>>>>> +                     return -ENOMEM;
>>>>> +             new_term->val.cfg_chg = bits;
>>>>> +     }
>>>>>
>>>>> -#undef ADD_CONFIG_TERM
>>>>>         return 0;
>>>>>     }
>>>>>
>>>>>
>>>>
>>



From nicolas.frattaroli at collabora.com  Fri Dec 12 06:45:05 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Fri, 12 Dec 2025 15:45:05 +0100
Subject: [PATCH v5 04/17] drm/bridge: Act on the DRM color format property
In-Reply-To: <20251212-hidden-armored-mule-66dd32@penduick>
References: <20251128-color-format-v5-0-63e82f1db1e1@collabora.com>
 <3772903.e9J7NaK4W3@workhorse> <20251212-hidden-armored-mule-66dd32@penduick>
Message-ID: <2747638.atdPhlSkOF@workhorse>

On Friday, 12 December 2025 10:50:26 Central European Standard Time Maxime Ripard wrote:
> On Thu, Dec 11, 2025 at 08:34:22PM +0100, Nicolas Frattaroli wrote:
> > On Tuesday, 9 December 2025 15:27:28 Central European Standard Time Maxime Ripard wrote:
> > > On Fri, Nov 28, 2025 at 10:05:40PM +0100, Nicolas Frattaroli wrote:
> > > > The new DRM color format property allows userspace to request a specific
> > > > color format on a connector. In turn, this fills the connector state's
> > > > color_format member to switch color formats.
> > > > 
> > > > Make drm_bridges consider the color_format set in the connector state
> > > > during the atomic bridge check. Specifically, reject any output bus
> > > > formats that do not correspond to the requested color format.
> > > > 
> > > > Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
> > > > ---
> > > >  drivers/gpu/drm/drm_bridge.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
> > > >  1 file changed, 45 insertions(+)
> > > > 
> > > > diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> > > > index 8f355df883d8..8aac9747f35e 100644
> > > > --- a/drivers/gpu/drm/drm_bridge.c
> > > > +++ b/drivers/gpu/drm/drm_bridge.c
> > > > @@ -1052,6 +1052,47 @@ static int select_bus_fmt_recursive(struct drm_bridge *first_bridge,
> > > >  	return ret;
> > > >  }
> > > >  
> > > > +static bool __pure bus_format_is_color_fmt(u32 bus_fmt, enum drm_color_format fmt)
> > > > +{
> > > > +	if (fmt == DRM_COLOR_FORMAT_AUTO)
> > > > +		return true;
> > > > +
> > > > +	switch (bus_fmt) {
> > > > +	case MEDIA_BUS_FMT_FIXED:
> > > > +		return true;
> > > > +	case MEDIA_BUS_FMT_RGB888_1X24:
> > > > +	case MEDIA_BUS_FMT_RGB101010_1X30:
> > > > +	case MEDIA_BUS_FMT_RGB121212_1X36:
> > > > +	case MEDIA_BUS_FMT_RGB161616_1X48:
> > > > +		return fmt == DRM_COLOR_FORMAT_RGB444;
> > > > +	case MEDIA_BUS_FMT_YUV8_1X24:
> > > > +	case MEDIA_BUS_FMT_YUV10_1X30:
> > > > +	case MEDIA_BUS_FMT_YUV12_1X36:
> > > > +	case MEDIA_BUS_FMT_YUV16_1X48:
> > > > +		return fmt == DRM_COLOR_FORMAT_YCBCR444;
> > > > +	case MEDIA_BUS_FMT_UYVY8_1X16:
> > > > +	case MEDIA_BUS_FMT_VYUY8_1X16:
> > > > +	case MEDIA_BUS_FMT_YUYV8_1X16:
> > > > +	case MEDIA_BUS_FMT_YVYU8_1X16:
> > > > +	case MEDIA_BUS_FMT_UYVY10_1X20:
> > > > +	case MEDIA_BUS_FMT_YUYV10_1X20:
> > > > +	case MEDIA_BUS_FMT_VYUY10_1X20:
> > > > +	case MEDIA_BUS_FMT_YVYU10_1X20:
> > > > +	case MEDIA_BUS_FMT_UYVY12_1X24:
> > > > +	case MEDIA_BUS_FMT_VYUY12_1X24:
> > > > +	case MEDIA_BUS_FMT_YUYV12_1X24:
> > > > +	case MEDIA_BUS_FMT_YVYU12_1X24:
> > > > +		return fmt == DRM_COLOR_FORMAT_YCBCR422;
> > > > +	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
> > > > +	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
> > > > +	case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
> > > > +	case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
> > > > +		return fmt == DRM_COLOR_FORMAT_YCBCR420;
> > > > +	default:
> > > > +		return false;
> > > > +	}
> > > > +}
> > > > +
> > > >  /*
> > > >   * This function is called by &drm_atomic_bridge_chain_check() just before
> > > >   * calling &drm_bridge_funcs.atomic_check() on all elements of the chain.
> > > > @@ -1137,6 +1178,10 @@ drm_atomic_bridge_chain_select_bus_fmts(struct drm_bridge *bridge,
> > > >  	}
> > > >  
> > > >  	for (i = 0; i < num_out_bus_fmts; i++) {
> > > > +		if (!bus_format_is_color_fmt(out_bus_fmts[i], conn_state->color_format)) {
> > > > +			ret = -ENOTSUPP;
> > > > +			continue;
> > > > +		}
> > > 
> > > Sorry, I'm struggling a bit to understand how this would work if a bridge both supports the bus
> > > format selection and HDMI state helpers? Can you expand on it?
> > 
> > I have very little idea of whether this makes conceptual sense.
> 
> .. I wasn't asking you if it makes sense, I was asking you to explain
> how you wanted it to work.
> 
> > The hope is that by working backwards from the last bridge and only
> > accepting either fixed formats or something that corresponds to the
> > target color format, we don't claim that a setup can do a colour
> > format if the whole bridge chain isn't able to do it.
> > 
> > Of course, format conversions along the bridge chain where one
> > input format can be converted to a set of output formats by some
> > bridge will throw a massive wrench into this. And this is all
> > assuming that the bus format is in any way related to the color
> > format that will be sent out on the wire.
> 
> I'm not really concerned about this. As we move more and more bridges to
> the state helpers, we can always fix it, but it needs at the very least
> to document how you envision the whole thing to work, and ideally have
> bunch of tests to make sure it still does.

Where should I document the intended behavior? A code comment here is
probably not visible to people implementing new bridge drivers, so I
imagine there's a place in the docs?

On the drm-kms docs page, I see:

  Note that currently the bridge chaining and interactions with
  connectors and panels are still in-flux and not really fully
  sorted out yet.

Which means maybe adding a sub-heading for DRM bridge there might
make sense.

For a complete solution, it should probably do a graph traversal
starting from the last bridge's output format, and then looking
to reach the first bridge output format in the chain in any way
possible over a DAG where edges connect from input formats of
the next bridge to the output formats of the previous bridge,
and the output format of each bridge connects to whichever
of its input formats can convert to this output format.

Here's a diagram of what I mean:

    .-----------------------------------.
    |       SoC Video Processor         |
    |-----------------------------------|
    | out rgb | out yuv444 | out yuv420 |
    '---------|------------|------------'
        ^
        |
    .---------|------.
    | in  rgb |      |
    |---------| MIPI |
    |    ^    | DSI  |
    |    |    | TX   |
    |---------|      |
    | out rgb |      |
    '---------|------'
        ^
        |
        '----------.
                    |
    .----------|---------|-----------|----------------------------.
    |          | in  rgb | in yuv444 |               |            |
    |----------|---------|-----------|---------------|   BOB'S    |
    |              ^   ^    ^  ^                     |  BARGAIN   |
    |              |   |    |  '--------------.      |  MIPI DSI  |
    |    .---------'   |    '----.            |      |  TO HDMI   |
    |    |          .--'         |            |      |  BRIDGE    |
    |---------|------------|------------|------------|            |
    | out rgb | out yuv444 | out yuv422 | out yuv420 |            |
    '---------|------------|------------|------------|------------'
        ^           ^            ^
        |           |            |
    .---------|------------|------------.
    | in  rgb | in  yuv444 | in  yuv422 |
    |-----------------------------------|
    |          HDMI CONNECTOR           |
    '-----------------------------------'

In this case, the MIPI DSI to HDMI bridge isn't very good so it can
only convert YUV444 to YUV422 and YUV420, despite being able to
convert RGB to YUV444 as well. The important bit is that there is
a path back from "out yuv444" on the "HDMI CONNECTOR" all the way
to the "SoC Video Processor", even though the processor's only going
to be outputting RGB. So setting color_format to yuv444 should be
possible in this case.

My current code doesn't handle this case. It only works if bridges
that convert can convert to any of their output formats regardless
of the input format. Additionally, I don't think I'd have a good
time if the SoC's video output processor sets the bus format to
"fixed", because if everyone along the chain says they can do
fixed formats then the output is going to claim it can do anything,
which isn't the case.

> 
> > In practice, I don't have any hardware where whatever counts as
> > a "bridge" is an actually more involved setup than just the TX
> > controller. I tried looking into getting a board with one of the
> > supported DSI-to-HDMI bridge chips so I can at least test how it
> > would work in such a scenario, and I got one, but I'd need to make
> > my own flat flex PCB to adapt it to the pinout of my SBC's DSI
> > port.
> > 
> > So yeah I don't know how it's supposed to work, I just know this
> > works for the case I'm working with, and any more complex case
> > is literally unobtanium hardware which I'm not going to bother
> > blowing days on maybe making a cable for when I'm already touching
> > three different GPU drivers here and the intel-gfx-ci is screaming
> > into my inbox about vague failures in unrelated codepaths in its
> > native language, Klingon.
> 
> That's uncalled for.
> 
> > Which is all to say: is there a virtual drm bridge driver that
> > exists, where I can set what formats it supports on the input
> > and on the output, so that I can actually get a feel for how this
> > is conceptually supposed to work without needing special hardware?
> 
> If your question is "do we have a way to replicate and test an arbitrary
> setup to check how it behaves?", then yes, we do, it's what we're doing
> in kunit. But you don't seem too fond of those.

Okay, I will look into virtual bridge tests in kunit.

> 
> > Better yet: do you have a specific setup in mind where you know
> > this approach does not work?
> 
> Look. I was asking a genuine question. If you want to get all defensive
> about it, go ahead. But sending a series implementing something with a
> lot of history, complex interactions, etc. and then expecting it to be a
> breeze that will get merged in a few revisions is not going to work.
> 
> Pushing back when asked to follow our documented rules, or being
> dismissive when asked design questions is not going to help you push
> this forward. If anything, and because it's complex, the more tests you
> add the better because we A) know it works in a specific set of cases,
> and B) know it will still work going forward.
> 
> I'm sure you know what you're doing, but so do we.

I worked under the assumption that the general vagueness of the
questions were part of some elaborate dt-bindings-esque hazing
ritual, and not that I was literally the first person to try and
specify how drm bridge bus format selection should work. I apologise
for my tone in light of that.

I'm not convinced unit tests that test whether a single pre-defined
mode is valid, as the existing mode_valid one does, have any value
though. I'll comply however and add another with a yuv420-only mode,
and another with a yuv420-also mode. My criticism is that in a
scenario like this where "working" vs "broken" is highly dependent
on the result based on the input data, the coverage of taken code
branches is mostly irrelevant, and the real information comes from
comprehensive testing of a wide set of inputs with attention paid
to edge cases, verifying that they match the expected outputs.

Kind regards,
Nicolas Frattaroli

> 
> Maxime
> 






From james.clark at linaro.org  Fri Dec 12 06:50:52 2025
From: james.clark at linaro.org (James Clark)
Date: Fri, 12 Dec 2025 16:50:52 +0200
Subject: [PATCH 07/19] coresight: trbe: Refactor AUX flag setting
In-Reply-To: <20251210154308.GZ724103@e132581.arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-7-7da32b076b28@arm.com>
 <a638f74f-94bc-4052-b8e1-e940aca2d4ce@linaro.org>
 <20251210154308.GZ724103@e132581.arm.com>
Message-ID: <27417fd5-902e-4474-8d60-356a94ac9590@linaro.org>



On 10/12/2025 17:43, Leo Yan wrote:
> On Tue, Dec 09, 2025 at 01:37:39PM +0000, James Clark wrote:
> 
> [...]
> 
>>> +	if (!is_trbe_running(trbsr))
>>> +		perf_aux_output_flag(handle, PERF_AUX_FLAG_COLLISION);
>>> +
>>
>> Do we need the complexity of COLLISION (changed to PARTIAL in a later
>> commit) and TRUNCATED at the same time?
> 
>>  From my understanding, TRUNCATED would be when Perf is too slow and we want
>> to disable the event for it to catch up, and PARTIAL is when there was some
>> buffer error so technically we don't need the event to be disabled, but Perf
>> still needs to be notified if we want to start only resetting the decoder
>> when a flag is set rather than on all aux records?
> 
> The main difference between the TRUNCATED flag and the COLLISION/PARTIAL
> flags is that the TRUNCATED flag implicitly asks the event core layer to
> disable the PMU event.  In contrast, the COLLISION and PARTIAL flags are
> only stored in AUX record and no additional action in the event core
> layer.
> 
> Setting the TRUNCATED flag would be a over-killer if the buffer has
> free space, as it would run the expensive sequence of disabling both ETE
> and TRBE and then requiring userspace to re-enable them.
> 
>> There is no happy path where there is a buffer error, so I'm not sure why we
>> need the complexity of an extra case? There's no harm in disabling the event
>> on a buffer error. Also it's hard to see what the exact scenario for PARTIAL
>> is, because we set truncated anyway for fatal statuses. The comment in the
>> later commit for the PARTIAL change just says "trace was stopped", but not
>> why.
> 
> The trace can be stopped on Fill mode (stop on wrap) or Stop on trigger, so
> it is not (only) about buffer error.  In these cases, even though the trace
> unit is stopped, the buffer may still have space available, tracing can be
> directly re-enabled in interrupt handler, thus the COLLISION/PARTIAL flags
> are better choices.

I suppose this is the bit that I don't understand. If there is space 
left then why is the stop hit at all?

For the other cases, I agree that it's overkill, but my point is that 
doesn't matter because we don't expect it to be hit in normal cases 
anyway. So it's worth the simplification of not doing anything different 
than TRUNCATED.

> 
> Only when the buffer is actually used out (i.e., handle->size == 0), it is
> appropriate to set TRUNCATED flag, since at that point we must wait for
> userspace to read out the data.
> 
> Thanks,
> Leo



From m.tretter at pengutronix.de  Fri Dec 12 06:52:43 2025
From: m.tretter at pengutronix.de (Michael Tretter)
Date: Fri, 12 Dec 2025 15:52:43 +0100
Subject: [PATCH RESEND v6 0/4] media: Add Gen 3 IP stateful decoder driver
In-Reply-To: <20251208-allegro_dvt_al300_dec_driver-v6-0-128956555677@allegrodvt.com>
References: <20251208-allegro_dvt_al300_dec_driver-v6-0-128956555677@allegrodvt.com>
Message-ID: <aTwsO1T85-6Y9yLv@pengutronix.de>

Hi Yassine,

On Mon, 08 Dec 2025 16:49:15 +0100, Yassine Ouaissa via B4 Relay wrote:
> This patch series introduces a new stateful decoder driver for the
> allegrodvt GEN 3 IPs.
> 
> Changes in v6:
> - Reset the file->private_data to NULL in v4l2_fh_del()
> - Link to v5: https://lore.kernel.org/r/20250813-allegro_dvt_al300_dec_driver-v5-0-a312ddebc4d8 at allegrodvt.com

Have you seen my comments on your v5? I haven't received any responses
to these comments and don't see them being addressed in v6.

Michael

> 
> Changes in v5:
> - Fix the include issues.
> - Fix the faulty warning, by adding the __maybe_unused attribute to the 'v4l2_al_dec_dt_match'.
> - Fix the get_mcu_offset(), the physical address limit is set to the
>   flat memory size ( 264GB ).
> - Get the mcu physical addresses offset at al_common_setup_dma.
> - Link to v4: https://lore.kernel.org/r/20250716-allegro_dvt_al300_dec_driver-v4-0-f87c01c9f7b5 at allegrodvt.com
> 
> Changes in v4:
> - Use debugfs instead of build time DEBUG (Michael Tretter).
> - Add capture and output pixelformats and resolution to the debugfs.
> - Support 64-bit of physical addresses, by configuring the mcu data and
>   instruction offset registers.
> - Link to v3: https://lore.kernel.org/r/20250616-allegro_dvt_al300_dec_driver-v3-0-7d746cb9e5f9 at allegrodvt.com
> 
> Changes in v3:
> - Remove blank line after description.(Krzysztof Kozlowski)
> - Drop minItems on the reg property.(Krzysztof Kozlowski)
> - Reword the patch 2 subject and description.(Krzysztof Kozlowski)
> - Add the memory-region property to the example.(Krzysztof Kozlowski)
> - Rename the reg-name "regs" with top. the first reg is the
>   video-decoder top registers.(Krzysztof Kozlowski)
> - Link to v2: https://lore.kernel.org/r/20250605-allegro_dvt_al300_dec_driver-v2-0-1ef4839f5f06 at allegrodvt.com
> 
> Changes in v2:
> - patch 2:
> - Change the YAML file name, use the existing vendor-prefix.
> - Improuve the dt-bindings description.
> - Change the device compatible identifier, from "allegrodvt, al300-vdec",
>   to "allegro, al300-vdec"
> - Simplify the register property specification,
>   by using the simple min/max items constraint (Krzysztof Kozlowski)
> - Remove the clock-names property. And remove it from the required
>   properties list (Krzysztof Kozlowski) (Conor Dooley)
> - Use the simple maxItems constraint for the memory-region property.
>   Also for the firmware-name (Krzysztof Kozlowski)
> - Example changes:
>   - Use header provides definitions for the interrupts (Conor Dooley)
>   - Improuve Interrupt specification using GIC constants (Conor Dooley)
>   - Use generic node name "video-decoder" (Krzysztof Kozlowski) (Conor Dooley)
>   - Remove unused label (Krzysztof Kozlowski)
>   - Change clock reference from <&mcu_clock_dec> to <&mcu_core_clk>
>   - Use hex format for reg property (Krzysztof Kozlowski) (Conor Dooley)
>   - Reduce memory region size (Krzysztof Kozlowski) (Conor Dooley)
> 
> - patch 4: Fix code reviews (Nicolas Dufresne)
> - MAINTAINERS: Remove my self from the "ALLEGRO DVT VIDEO IP CORE
>   DRIVER".
>   Link to v1: https://lore.kernel.org/all/20250523134207.68481-1-yassine.ouaissa at allegrodvt.com/
> 
> # V4L2 Video Decoder Driver System Description
> 
> ** Hardware Architecture **
> 
> The system implements a heterogeneous computing architecture with two primary components:
> 
> - **Host Subsystem**: Linux-based CPU running the V4L2 framework and associated drivers
> - **IP Subsystem**: Dedicated hardware containing an MCU and a hardware video CODEC
> 
> The communication between the two subsystems uses a shared DDR shared memory with bidirectional interrupt mechanism for synchronization.
> 
> The architecture is represented in the following diagram:
> 
> ```
> +---------------------+                  +----------------------+
> |       Host          |                  |        IP            |
> |                     |                  |                      |
> |  +---------------+  |                  |  +----------------+  |
> |  |               |  |   DDR Shared     |  |                |  |
> |  | Linux Kernel  |<-|----------------->|->|     MCU        |  |
> |  | (CPU)         |  |    Memory        |  |                |  |
> |  |   +--------+  |  |                  |  +----------------+  |
> |  |   |        |  |  |    IRQ when      |           ^          |
> |  |   | V4L2   |  |<-|----new message-->|           |          |
> |  |   | Drivers|  |  |                  |           |          |
> |  |   |        |  |  |                  |           | APB      |
> |  |   +--------+  |  |                  |           |          |
> |  |               |  |                  |           v          |
> |  +---------------+  |                  |  +----------------+  |
> |                     |                  |  |                |  |
> |                     |                  |  |     CODEC      |  |
> |                     |                  |  |                |  |
> |                     |                  |  |                |  |
> +---------------------+                  +----------------------+
> ```
> 
> ** Communication Protocol **
> 
> -- Current Implementation - Custom Mailbox --
> 
> The host CPU and MCU currently communicate through a custom mailbox protocol implemented over shared memory. The protocol operates as follows:
> 
> 1. When the host has a new message for the MCU:
>    - The host writes data to a dedicated shared memory region
>    - The host triggers an interrupt to the MCU
>    - The MCU reads the shared memory to obtain the message type and data
> 
> 2. Similarly, when the MCU has a message for the host:
>    - The MCU writes to the shared memory
>    - The MCU triggers an interrupt to the host
>    - The host reads the shared memory to process the message
> 
> -- Migration to RPMSG --
> 
> The custom mailbox implementation will be replaced by the standard Linux RPMSG framework.
> 
> ** Driver Implementation **
> 
> This driver implements a V4L2-compliant stateful video decoder with the following characteristics:
> 
> -- Technical Specifications --
> 
> - **Codec Support**: AVC (H.264), HEVC (H.265), and JPEG
> - **Resolution Support**: Up to 4K
> - **Pixel Formats**:
>   - Currently supported: V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_NV16, V4L2_PIX_FMT_P010
>   - Additional formats planned for future releases
> - **Buffer Configuration**: Currently supports semi-planar format only; multiplanar support forthcoming
> 
> -- Initialization Sequence --
> 
> During probe, the driver performs the following operations:
> 
> 1. Allocates memory for the MCU firmware
> 2. Loads the firmware into the allocated memory
> 3. Initializes the MCU by configuring internal registers (e.g BOOT_ADDR)
> 4. Establishes the shared memory communication interface (to be replaced by RPMSG)
> 5. Sets up interrupt handlers for MCU communication
> 
> -- Processing Model --
> 
> The driver implements a stateful decoding model with the following workflow:
> 
> -- Stream Initialization --
> 
> 1. Upon `VIDIOC_STREAMON` on the OUTPUT queue:
>    - The driver sends a context creation request to the MCU
>    - This operation is blocking; the driver waits until the MCU responds with a context handler
>    - The context handler is stored in a driver-maintained list for subsequent operations
>    - Each context has its own unique handler to support multiple simultaneous streams
> 
> 2. Initial stream analysis:
>    - The driver submits the first compressed buffer (OUTPUT queue)
>    - The MCU analyzes the stream and reports capability via:
>      - `resolution_found_event`: Stream is supported, includes stream parameters
>      - `error_event`: Stream format is unsupported or invalid
> 
> -- Decoding Pipeline --
> 
> 1. After successful stream initialization and receiving the resolution_found_evt:
>    - The driver can begin normal decoding operations
>    - V4L2 framework can be informed of format requirements
> 
> 2. For each compressed buffer (OUTPUT queue):
>    - The driver submits buffer to MCU with the appropriate context handler
>    - The MCU processes the buffer and sends `release_bitstream_evt` when complete
>    - This event signals that the input buffer can be returned to the application
> 
> 3. For each decoded buffer (CAPTURE queue):
>    - The MCU fills the buffer with decoded frame data
>    - The MCU sends `frame_buffer_decode_evt` with important metadata including:
>      - Original source buffer timestamp
>      - Flags
>      - Timecode
>      - Actual payload size (bytes used in the decoded frame)
>    - This enables the driver to properly queue the filled buffer to the application
> 
> 4. End-of-stream handling:
>    - The MCU sends an event with `eos_evt` when reaching the end of stream
>    - This allows proper handling of end-of-stream conditions
> 
> -- Multi-stream Support --
> 
> The driver architecture supports multiple simultaneous decoding contexts with the following characteristics:
> 
> 1. Each context maintains separate state information
> 2. The driver manages multiple context handlers returned by the MCU
> 3. Buffer submissions include the appropriate context handler for routing
> 4. The system can decode multiple independent streams concurrently
> 
> -- Stream Termination --
> 
> When `VIDIOC_STREAMOFF` is called:
> 
> 1. The driver sends a flush command to the MCU for the specific context
> 2. The driver issues a non-blocking destroy context message
> 3. All associated resources are released
> 4. The context handler is removed from the driver's context list
> 
> ** Error Handling **
> 
> The driver implements comprehensive error handling including:
> 
> 1. Firmware loading failures
> 2. MCU initialization errors
> 3. Context creation failures
> 4. Unsupported stream formats
> 5. Decoding errors reported by the MCU
> 6. Timeout handling for unresponsive hardware
> 
> ** Memory Management **
> 
> The system uses the following memory management strategy:
> 
> 1. Firmware memory is allocated during probe
> 2. Buffer memory is managed through the V4L2 buffer management interfaces
> 3. DMA-capable memory is used for buffer transfers between host and MCU
> 4. The driver properly synchronizes memory access to avoid coherency issues
> 
> ** Future Enhancements **
> 
> Planned future enhancements include:
> 
> 1. Migration from custom mailbox to RPMSG (in progress)
> 2. Support for additional pixel formats
> 3. Implementation of multiplanar buffer support
> 
> This comprehensive architecture enables efficient hardware-accelerated video decoding while adhering to standard V4L2 interfaces, making it suitable for upstream inclusion in the Linux kernel.
> 
> ** Decoder Compliance Testing **
> 
> -- AVC and HEVC Fluster Report --
> 
> This section contains the compliance test results from Fluster framework for both AVC and HEVC decoders.
> The reports validate the decoder's conformance to relevant standards and demonstrate compatibility with a wide range of video streams.
> 
> [FLUSTER REPORT FOR THE H.264]
>  -- JVT-AVC_V1
> 
> | Test                     | FFmpeg-H.264-v4l2m2m |
> | ------------------------ | -------------------- |
> | TOTAL                    | 79/135               |
> | TOTAL TIME               | 437.031s             |
> | -                        | -                    |
> | AUD_MW_E                 | OK                   |
> | BA1_FT_C                 | OK                   |
> | BA1_Sony_D               | OK                   |
> | BA2_Sony_F               | OK                   |
> | BA3_SVA_C                | OK                   |
> | BA_MW_D                  | OK                   |
> | BAMQ1_JVC_C              | OK                   |
> | BAMQ2_JVC_C              | OK                   |
> | BANM_MW_D                | OK                   |
> | BASQP1_Sony_C            | OK                   |
> | CABA1_Sony_D             | OK                   |
> | CABA1_SVA_B              | OK                   |
> | CABA2_Sony_E             | OK                   |
> | CABA2_SVA_B              | OK                   |
> | CABA3_Sony_C             | OK                   |
> | CABA3_SVA_B              | OK                   |
> | CABA3_TOSHIBA_E          | OK                   |
> | cabac_mot_fld0_full      | ER                   |
> | cabac_mot_frm0_full      | OK                   |
> | cabac_mot_mbaff0_full    | ER                   |
> | cabac_mot_picaff0_full   | KO                   |
> | CABACI3_Sony_B           | OK                   |
> | CABAST3_Sony_E           | OK                   |
> | CABASTBR3_Sony_B         | OK                   |
> | CABREF3_Sand_D           | ER                   |
> | CACQP3_Sony_D            | OK                   |
> | CAFI1_SVA_C              | ER                   |
> | CAMA1_Sony_C             | ER                   |
> | CAMA1_TOSHIBA_B          | ER                   |
> | cama1_vtc_c              | ER                   |
> | cama2_vtc_b              | ER                   |
> | CAMA3_Sand_E             | ER                   |
> | cama3_vtc_b              | ER                   |
> | CAMACI3_Sony_C           | ER                   |
> | CAMANL1_TOSHIBA_B        | ER                   |
> | CAMANL2_TOSHIBA_B        | ER                   |
> | CAMANL3_Sand_E           | ER                   |
> | CAMASL3_Sony_B           | ER                   |
> | CAMP_MOT_MBAFF_L30       | ER                   |
> | CAMP_MOT_MBAFF_L31       | ER                   |
> | CANL1_Sony_E             | OK                   |
> | CANL1_SVA_B              | OK                   |
> | CANL1_TOSHIBA_G          | OK                   |
> | CANL2_Sony_E             | OK                   |
> | CANL2_SVA_B              | OK                   |
> | CANL3_Sony_C             | OK                   |
> | CANL3_SVA_B              | OK                   |
> | CANL4_SVA_B              | OK                   |
> | CANLMA2_Sony_C           | ER                   |
> | CANLMA3_Sony_C           | ER                   |
> | CAPA1_TOSHIBA_B          | ER                   |
> | CAPAMA3_Sand_F           | ER                   |
> | CAPCM1_Sand_E            | OK                   |
> | CAPCMNL1_Sand_E          | OK                   |
> | CAPM3_Sony_D             | OK                   |
> | CAQP1_Sony_B             | OK                   |
> | cavlc_mot_fld0_full_B    | ER                   |
> | cavlc_mot_frm0_full_B    | OK                   |
> | cavlc_mot_mbaff0_full_B  | ER                   |
> | cavlc_mot_picaff0_full_B | KO                   |
> | CAWP1_TOSHIBA_E          | OK                   |
> | CAWP5_TOSHIBA_E          | OK                   |
> | CI1_FT_B                 | OK                   |
> | CI_MW_D                  | OK                   |
> | CVBS3_Sony_C             | OK                   |
> | CVCANLMA2_Sony_C         | ER                   |
> | CVFC1_Sony_C             | OK                   |
> | CVFI1_Sony_D             | ER                   |
> | CVFI1_SVA_C              | ER                   |
> | CVFI2_Sony_H             | ER                   |
> | CVFI2_SVA_C              | ER                   |
> | CVMA1_Sony_D             | ER                   |
> | CVMA1_TOSHIBA_B          | ER                   |
> | CVMANL1_TOSHIBA_B        | ER                   |
> | CVMANL2_TOSHIBA_B        | ER                   |
> | CVMAPAQP3_Sony_E         | ER                   |
> | CVMAQP2_Sony_G           | ER                   |
> | CVMAQP3_Sony_D           | ER                   |
> | CVMP_MOT_FLD_L30_B       | ER                   |
> | CVMP_MOT_FRM_L31_B       | ER                   |
> | CVNLFI1_Sony_C           | ER                   |
> | CVNLFI2_Sony_H           | ER                   |
> | CVPA1_TOSHIBA_B          | ER                   |
> | CVPCMNL1_SVA_C           | OK                   |
> | CVPCMNL2_SVA_C           | OK                   |
> | CVSE2_Sony_B             | OK                   |
> | CVSE3_Sony_H             | OK                   |
> | CVSEFDFT3_Sony_E         | OK                   |
> | CVWP1_TOSHIBA_E          | OK                   |
> | CVWP2_TOSHIBA_E          | OK                   |
> | CVWP3_TOSHIBA_E          | OK                   |
> | CVWP5_TOSHIBA_E          | OK                   |
> | FI1_Sony_E               | ER                   |
> | FM1_BT_B                 | ER                   |
> | FM1_FT_E                 | KO                   |
> | FM2_SVA_C                | ER                   |
> | HCBP1_HHI_A              | OK                   |
> | HCBP2_HHI_A              | OK                   |
> | HCMP1_HHI_A              | OK                   |
> | LS_SVA_D                 | OK                   |
> | MIDR_MW_D                | OK                   |
> | MPS_MW_A                 | OK                   |
> | MR1_BT_A                 | OK                   |
> | MR1_MW_A                 | OK                   |
> | MR2_MW_A                 | OK                   |
> | MR2_TANDBERG_E           | OK                   |
> | MR3_TANDBERG_B           | OK                   |
> | MR4_TANDBERG_C           | OK                   |
> | MR5_TANDBERG_C           | OK                   |
> | MR6_BT_B                 | ER                   |
> | MR7_BT_B                 | OK                   |
> | MR8_BT_B                 | ER                   |
> | MR9_BT_B                 | ER                   |
> | MV1_BRCM_D               | OK                   |
> | NL1_Sony_D               | OK                   |
> | NL2_Sony_H               | OK                   |
> | NL3_SVA_E                | OK                   |
> | NLMQ1_JVC_C              | OK                   |
> | NLMQ2_JVC_C              | OK                   |
> | NRF_MW_E                 | OK                   |
> | Sharp_MP_Field_1_B       | ER                   |
> | Sharp_MP_Field_2_B       | ER                   |
> | Sharp_MP_Field_3_B       | ER                   |
> | Sharp_MP_PAFF_1r2        | ER                   |
> | Sharp_MP_PAFF_2r         | ER                   |
> | SL1_SVA_B                | OK                   |
> | SP1_BT_A                 | ER                   |
> | sp2_bt_b                 | ER                   |
> | SVA_BA1_B                | OK                   |
> | SVA_BA2_D                | OK                   |
> | SVA_Base_B               | OK                   |
> | SVA_CL1_E                | OK                   |
> | SVA_FM1_E                | OK                   |
> | SVA_NL1_B                | OK                   |
> | SVA_NL2_E                | OK                   |
> | -                        | -                    |
> | Test                     | FFmpeg-H.264-v4l2m2m |
> | TOTAL                    | 79/135               |
> | TOTAL TIME               | 439.031s             |
> 
> NOTE: The ER (ERROR) streams are not supported by the decoder.
>       The driver print error message "Unsupported stream"
> 
> - JVT-FR-EXT
> 
> | Test                | FFmpeg-H.264-v4l2m2m |
> | ------------------- | -------------------- |
> | TOTAL               | 23/69                |
> | TOTAL TIME          | 182.362s             |
> | -                   | -                    |
> | alphaconformanceG   | OK                   |
> | brcm_freh10         | ER                   |
> | brcm_freh11         | ER                   |
> | brcm_freh3          | OK                   |
> | brcm_freh4          | ER                   |
> | brcm_freh5          | ER                   |
> | brcm_freh6          | ER                   |
> | brcm_freh8          | OK                   |
> | brcm_freh9          | OK                   |
> | FREH10-1            | ER                   |
> | FREH10-2            | ER                   |
> | freh12_b            | OK                   |
> | freh1_b             | OK                   |
> | freh2_b             | OK                   |
> | freh7_b             | ER                   |
> | FREXT01_JVC_D       | ER                   |
> | FREXT02_JVC_C       | ER                   |
> | FRExt1_Panasonic_D  | OK                   |
> | FREXT1_TANDBERG_A   | ER                   |
> | FRExt2_Panasonic_C  | ER                   |
> | FREXT2_TANDBERG_A   | ER                   |
> | FRExt3_Panasonic_E  | OK                   |
> | FREXT3_TANDBERG_A   | ER                   |
> | FRExt4_Panasonic_B  | ER                   |
> | FRExt_MMCO4_Sony_B  | OK                   |
> | HCAFF1_HHI_B        | ER                   |
> | HCAFR1_HHI_C        | OK                   |
> | HCAFR2_HHI_A        | OK                   |
> | HCAFR3_HHI_A        | OK                   |
> | HCAFR4_HHI_A        | OK                   |
> | HCAMFF1_HHI_B       | ER                   |
> | HCHP1_HHI_B         | OK                   |
> | HCHP2_HHI_A         | OK                   |
> | HCHP3_HHI_A         | ER                   |
> | Hi422FR10_SONY_A    | ER                   |
> | Hi422FR11_SONY_A    | ER                   |
> | Hi422FR12_SONY_A    | ER                   |
> | Hi422FR13_SONY_A    | ER                   |
> | Hi422FR14_SONY_A    | ER                   |
> | Hi422FR15_SONY_A    | ER                   |
> | Hi422FR1_SONY_A     | ER                   |
> | Hi422FR2_SONY_A     | ER                   |
> | Hi422FR3_SONY_A     | ER                   |
> | Hi422FR4_SONY_A     | ER                   |
> | Hi422FR6_SONY_A     | ER                   |
> | Hi422FR7_SONY_A     | ER                   |
> | Hi422FR8_SONY_A     | ER                   |
> | Hi422FR9_SONY_A     | ER                   |
> | Hi422FREXT16_SONY_A | ER                   |
> | Hi422FREXT17_SONY_A | ER                   |
> | Hi422FREXT18_SONY_A | ER                   |
> | Hi422FREXT19_SONY_A | ER                   |
> | HPCA_BRCM_C         | OK                   |
> | HPCADQ_BRCM_B       | OK                   |
> | HPCAFL_BRCM_C       | ER                   |
> | HPCAFLNL_BRCM_C     | ER                   |
> | HPCALQ_BRCM_B       | OK                   |
> | HPCAMAPALQ_BRCM_B   | ER                   |
> | HPCAMOLQ_BRCM_B     | ER                   |
> | HPCANL_BRCM_C       | OK                   |
> | HPCAQ2LQ_BRCM_B     | OK                   |
> | HPCV_BRCM_A         | OK                   |
> | HPCVFL_BRCM_A       | ER                   |
> | HPCVFLNL_BRCM_A     | ER                   |
> | HPCVMOLQ_BRCM_B     | ER                   |
> | HPCVNL_BRCM_A       | OK                   |
> | HVLCFI0_Sony_B      | ER                   |
> | HVLCMFF0_Sony_B     | ER                   |
> | HVLCPFF0_Sony_B     | ER                   |
> | -                   | -                    |
> | Test                | FFmpeg-H.264-v4l2m2m |
> | TOTAL               | 23/69                |
> | TOTAL TIME          | 182.362s             |
> 
> NOTE: The ER (ERROR) streams are not supported by the decoder.
>       The driver print error message "Unsupported stream"
> 
> - JVT-MVC
> 
> | Test       | FFmpeg-H.264-v4l2m2m |
> | ---------- | -------------------- |
> | TOTAL      | 18/20                |
> | TOTAL TIME | 147.076s             |
> | -          | -                    |
> | MVCDS-4    | OK                   |
> | MVCDS-5    | OK                   |
> | MVCDS-6    | OK                   |
> | MVCDS1     | OK                   |
> | MVCDS2     | OK                   |
> | MVCDS3     | OK                   |
> | MVCICT-1   | ER                   |
> | MVCICT-2   | ER                   |
> | MVCNV-2    | OK                   |
> | MVCNV-3    | OK                   |
> | MVCNV1     | OK                   |
> | MVCNV4     | OK                   |
> | MVCRP_1    | OK                   |
> | MVCRP_2    | OK                   |
> | MVCRP_3    | OK                   |
> | MVCRP_4    | OK                   |
> | MVCRP_5    | OK                   |
> | MVCRP_6    | OK                   |
> | MVCSPS-1   | OK                   |
> | MVCSPS-2   | OK                   |
> | -          | -                    |
> | Test       | FFmpeg-H.264-v4l2m2m |
> | TOTAL      | 18/20                |
> | TOTAL TIME | 147.076s             |
> 
> - JVT-SVC
> 
> | Test            | FFmpeg-H.264-v4l2m2m |
> | --------------- | -------------------- |
> | TOTAL           | 75/185               |
> | TOTAL TIME      | 727.240s             |
> | -               | -                    |
> | SVCBC-1-L0      | OK                   |
> | SVCBC-1-L1      | KO                   |
> | SVCBCT-1-L0     | OK                   |
> | SVCBCT-1-L1     | KO                   |
> | SVCBCTS-1-r1-L0 | OK                   |
> | SVCBCTS-1-r1-L1 | KO                   |
> | SVCBCTS-1-r1-L2 | KO                   |
> | SVCBCTS-2-r1-L0 | OK                   |
> | SVCBCTS-2-r1-L1 | KO                   |
> | SVCBCTS-2-r1-L2 | KO                   |
> | SVCBCTS-3-L0    | OK                   |
> | SVCBCTS-3-L1    | KO                   |
> | SVCBCTS-3-L2    | KO                   |
> | SVCBM-1-L0      | OK                   |
> | SVCBM-1-L1      | KO                   |
> | SVCBM-2-L0      | OK                   |
> | SVCBM-2-L1      | KO                   |
> | SVCBM-3-L0      | OK                   |
> | SVCBM-3-L1      | KO                   |
> | SVCBM-4-r1-L0   | OK                   |
> | SVCBM-4-r1-L1   | KO                   |
> | SVCBM-4-r1-L2   | KO                   |
> | SVCBM-5-L0      | OK                   |
> | SVCBM-5-L1      | KO                   |
> | SVCBM-5-L2      | KO                   |
> | SVCBM-5-L3      | KO                   |
> | SVCBMST-1-L0    | OK                   |
> | SVCBMST-1-L1    | KO                   |
> | SVCBMST-1-L2    | KO                   |
> | SVCBMST-2-L0    | OK                   |
> | SVCBMST-2-L1    | KO                   |
> | SVCBMST-2-L2    | KO                   |
> | SVCBMST-3-L0    | OK                   |
> | SVCBMST-3-L1    | KO                   |
> | SVCBMST-3-L2    | KO                   |
> | SVCBMT-1-L0     | OK                   |
> | SVCBMT-1-L1     | KO                   |
> | SVCBMT-10-L0    | OK                   |
> | SVCBMT-10-L1    | KO                   |
> | SVCBMT-11-L0    | OK                   |
> | SVCBMT-11-L1    | KO                   |
> | SVCBMT-12-L0    | OK                   |
> | SVCBMT-12-L1    | KO                   |
> | SVCBMT-13-L0    | OK                   |
> | SVCBMT-13-L1    | KO                   |
> | SVCBMT-13-L2    | KO                   |
> | SVCBMT-2-L0     | OK                   |
> | SVCBMT-2-L1     | KO                   |
> | SVCBMT-3-L0     | OK                   |
> | SVCBMT-3-L1     | KO                   |
> | SVCBMT-4-L0     | OK                   |
> | SVCBMT-4-L1     | KO                   |
> | SVCBMT-5-L0     | OK                   |
> | SVCBMT-5-L1     | KO                   |
> | SVCBMT-6-L0     | OK                   |
> | SVCBMT-6-L1     | KO                   |
> | SVCBMT-7-L0     | OK                   |
> | SVCBMT-7-L1     | KO                   |
> | SVCBMT-8-L0     | OK                   |
> | SVCBMT-8-L1     | KO                   |
> | SVCBMT-9-L0     | OK                   |
> | SVCBMT-9-L1     | KO                   |
> | SVCBS-1-L0      | OK                   |
> | SVCBS-1-L1      | KO                   |
> | SVCBS-2-L0      | OK                   |
> | SVCBS-2-L1      | KO                   |
> | SVCBS-3-r1-L0   | OK                   |
> | SVCBS-3-r1-L1   | KO                   |
> | SVCBS-4-r1-L0   | OK                   |
> | SVCBS-4-r1-L1   | KO                   |
> | SVCBS-5-r1-L0   | OK                   |
> | SVCBS-5-r1-L1   | KO                   |
> | SVCBS-6-r1-L0   | OK                   |
> | SVCBS-6-r1-L1   | KO                   |
> | SVCBS-6-r1-L2   | KO                   |
> | SVCBS-7-L0      | OK                   |
> | SVCBS-7-L1      | KO                   |
> | SVCBS-8-L0      | OK                   |
> | SVCBS-8-L1      | KO                   |
> | SVCBST-1-L0     | OK                   |
> | SVCBST-1-L1     | KO                   |
> | SVCBST-10-r1-L0 | OK                   |
> | SVCBST-10-r1-L1 | KO                   |
> | SVCBST-11-r1-L0 | OK                   |
> | SVCBST-11-r1-L1 | KO                   |
> | SVCBST-12-r1-L0 | OK                   |
> | SVCBST-12-r1-L1 | KO                   |
> | SVCBST-13-L0    | OK                   |
> | SVCBST-13-L1    | KO                   |
> | SVCBST-14-L0    | OK                   |
> | SVCBST-14-L1    | KO                   |
> | SVCBST-14-L2    | KO                   |
> | SVCBST-15-L0    | OK                   |
> | SVCBST-15-L1    | KO                   |
> | SVCBST-15-L2    | KO                   |
> | SVCBST-16-r1-L0 | OK                   |
> | SVCBST-16-r1-L1 | KO                   |
> | SVCBST-16-r1-L2 | KO                   |
> | SVCBST-17-r1-L0 | OK                   |
> | SVCBST-17-r1-L1 | KO                   |
> | SVCBST-17-r1-L2 | KO                   |
> | SVCBST-18-r1-L0 | OK                   |
> | SVCBST-18-r1-L1 | KO                   |
> | SVCBST-18-r1-L2 | KO                   |
> | SVCBST-19-L0    | OK                   |
> | SVCBST-19-L1    | KO                   |
> | SVCBST-2-L0     | OK                   |
> | SVCBST-2-L1     | KO                   |
> | SVCBST-20-L0    | OK                   |
> | SVCBST-20-L1    | KO                   |
> | SVCBST-3-L0     | OK                   |
> | SVCBST-3-L1     | KO                   |
> | SVCBST-4-L0     | OK                   |
> | SVCBST-4-L1     | KO                   |
> | SVCBST-5-L0     | OK                   |
> | SVCBST-5-L1     | KO                   |
> | SVCBST-6-r1-L0  | OK                   |
> | SVCBST-6-r1-L1  | KO                   |
> | SVCBST-7-r1-L0  | OK                   |
> | SVCBST-7-r1-L1  | KO                   |
> | SVCBST-8-r1-L0  | OK                   |
> | SVCBST-8-r1-L1  | KO                   |
> | SVCBST-9-r1-L0  | OK                   |
> | SVCBST-9-r1-L1  | KO                   |
> | SVCBSTC-1-L0    | OK                   |
> | SVCBSTC-1-L1    | KO                   |
> | SVCBSTC-1-L2    | KO                   |
> | SVCHCTS-1-r1-L0 | OK                   |
> | SVCHCTS-1-r1-L1 | KO                   |
> | SVCHCTS-1-r1-L2 | KO                   |
> | SVCHCTS-1-r1-L3 | KO                   |
> | SVCHCTS-1-r1-L4 | KO                   |
> | SVCHCTS-1-r1-L5 | KO                   |
> | SVCHCTS-1-r1-L6 | KO                   |
> | SVCHCTS-1-r1-L7 | KO                   |
> | SVCHICS-1-L0    | OK                   |
> | SVCHICS-1-L1    | KO                   |
> | SVCHICS-1-L2    | KO                   |
> | SVCHICS-1-L3    | KO                   |
> | SVCHIS-1-L0     | OK                   |
> | SVCHIS-1-L1     | KO                   |
> | SVCHIS-1-L2     | KO                   |
> | SVCHIS-2-L0     | OK                   |
> | SVCHIS-2-L1     | KO                   |
> | SVCHIS-2-L2     | KO                   |
> | SVCHIS-3-L0     | OK                   |
> | SVCHIS-3-L1     | KO                   |
> | SVCHIS-3-L2     | KO                   |
> | SVCHM-1-L0      | OK                   |
> | SVCHM-1-L1      | KO                   |
> | SVCHM-1-L2      | KO                   |
> | SVCHM-1-L3      | KO                   |
> | SVCHM-2-L0      | OK                   |
> | SVCHM-2-L1      | OK                   |
> | SVCHM-3-L0      | OK                   |
> | SVCHM-3-L1      | OK                   |
> | SVCHM-4-L0      | OK                   |
> | SVCHM-4-L1      | OK                   |
> | SVCHM-4-L2      | OK                   |
> | SVCHMTS-1-r1-L0 | OK                   |
> | SVCHMTS-1-r1-L1 | KO                   |
> | SVCHMTS-1-r1-L2 | KO                   |
> | SVCHMTS-1-r1-L3 | KO                   |
> | SVCHMTS-1-r1-L4 | KO                   |
> | SVCHMTS-1-r1-L5 | KO                   |
> | SVCHMTS-2-r1-L0 | OK                   |
> | SVCHMTS-2-r1-L1 | KO                   |
> | SVCHMTS-2-r1-L2 | KO                   |
> | SVCHS-1-r1-L0   | OK                   |
> | SVCHS-1-r1-L1   | KO                   |
> | SVCHS-2-r1-L0   | OK                   |
> | SVCHS-2-r1-L1   | KO                   |
> | SVCHST-1-r1-L0  | OK                   |
> | SVCHST-1-r1-L1  | KO                   |
> | SVCHST-1-r1-L2  | KO                   |
> | SVCHST-2-r1-L0  | OK                   |
> | SVCHST-2-r1-L1  | KO                   |
> | SVCHST-2-r1-L2  | KO                   |
> | SVCHST-3-r1-L0  | ER                   |
> | SVCHST-3-r1-L1  | ER                   |
> | SVCHST-4-r1-L0  | ER                   |
> | SVCHST-4-r1-L1  | ER                   |
> | SVCHSTC-1-r1-L0 | OK                   |
> | SVCHSTC-1-r1-L1 | KO                   |
> | SVCHSTC-1-r1-L2 | KO                   |
> | -               | -                    |
> | Test            | FFmpeg-H.264-v4l2m2m |
> | TOTAL           | 75/185               |
> | TOTAL TIME      | 727.240s             |
> 
> NOTE: The current implementation of the decoder only supports Layer 0 (base layer) processing.
> When attempting to decode streams that contain multiple layers (such as scalable or multi-view content), the decoding operation fails.
> This limitation means that enhanced features requiring layer-based processing beyond the base layer cannot be properly handled by the current decoder.
> For successful decoding, input streams must be limited to single-layer content only.
> 
> [FLUSTER REPORT FOR THE H.265]
> 
> | -                               | -                    |
> | AMP_A_Samsung_7                 | OK                   |
> | AMP_B_Samsung_7                 | OK                   |
> | AMP_D_Hisilicon_3               | OK                   |
> | AMP_E_Hisilicon_3               | OK                   |
> | AMP_F_Hisilicon_3               | ER                   |
> | AMVP_A_MTK_4                    | ER                   |
> | AMVP_B_MTK_4                    | OK                   |
> | AMVP_C_Samsung_7                | ER                   |
> | BUMPING_A_ericsson_1            | OK                   |
> | CAINIT_A_SHARP_4                | OK                   |
> | CAINIT_B_SHARP_4                | OK                   |
> | CAINIT_C_SHARP_3                | OK                   |
> | CAINIT_D_SHARP_3                | OK                   |
> | CAINIT_E_SHARP_3                | OK                   |
> | CAINIT_F_SHARP_3                | OK                   |
> | CAINIT_G_SHARP_3                | OK                   |
> | CAINIT_H_SHARP_3                | OK                   |
> | CIP_A_Panasonic_3               | OK                   |
> | cip_B_NEC_3                     | OK                   |
> | CIP_C_Panasonic_2               | OK                   |
> | CONFWIN_A_Sony_1                | OK                   |
> | DBLK_A_MAIN10_VIXS_4            | ER                   |
> | DBLK_A_SONY_3                   | OK                   |
> | DBLK_B_SONY_3                   | OK                   |
> | DBLK_C_SONY_3                   | OK                   |
> | DBLK_D_VIXS_2                   | OK                   |
> | DBLK_E_VIXS_2                   | OK                   |
> | DBLK_F_VIXS_2                   | OK                   |
> | DBLK_G_VIXS_2                   | OK                   |
> | DELTAQP_A_BRCM_4                | OK                   |
> | DELTAQP_B_SONY_3                | OK                   |
> | DELTAQP_C_SONY_3                | OK                   |
> | DSLICE_A_HHI_5                  | OK                   |
> | DSLICE_B_HHI_5                  | OK                   |
> | DSLICE_C_HHI_5                  | OK                   |
> | ENTP_A_QUALCOMM_1               | OK                   |
> | ENTP_B_Qualcomm_1               | OK                   |
> | ENTP_C_Qualcomm_1               | OK                   |
> | EXT_A_ericsson_4                | OK                   |
> | FILLER_A_Sony_1                 | OK                   |
> | HRD_A_Fujitsu_3                 | OK                   |
> | INITQP_A_Sony_1                 | OK                   |
> | INITQP_B_Main10_Sony_1          | ER                   |
> | ipcm_A_NEC_3                    | OK                   |
> | ipcm_B_NEC_3                    | OK                   |
> | ipcm_C_NEC_3                    | OK                   |
> | ipcm_D_NEC_3                    | OK                   |
> | ipcm_E_NEC_2                    | OK                   |
> | IPRED_A_docomo_2                | OK                   |
> | IPRED_B_Nokia_3                 | OK                   |
> | IPRED_C_Mitsubishi_3            | OK                   |
> | LS_A_Orange_2                   | OK                   |
> | LS_B_Orange_4                   | OK                   |
> | LTRPSPS_A_Qualcomm_1            | KO                   |
> | MAXBINS_A_TI_5                  | OK                   |
> | MAXBINS_B_TI_5                  | OK                   |
> | MAXBINS_C_TI_5                  | OK                   |
> | MERGE_A_TI_3                    | OK                   |
> | MERGE_B_TI_3                    | OK                   |
> | MERGE_C_TI_3                    | OK                   |
> | MERGE_D_TI_3                    | OK                   |
> | MERGE_E_TI_3                    | OK                   |
> | MERGE_F_MTK_4                   | OK                   |
> | MERGE_G_HHI_4                   | OK                   |
> | MVCLIP_A_qualcomm_3             | OK                   |
> | MVDL1ZERO_A_docomo_4            | OK                   |
> | MVEDGE_A_qualcomm_3             | OK                   |
> | NoOutPrior_A_Qualcomm_1         | OK                   |
> | NoOutPrior_B_Qualcomm_1         | OK                   |
> | NUT_A_ericsson_5                | OK                   |
> | OPFLAG_A_Qualcomm_1             | OK                   |
> | OPFLAG_B_Qualcomm_1             | OK                   |
> | OPFLAG_C_Qualcomm_1             | OK                   |
> | PICSIZE_A_Bossen_1              | OK                   |
> | PICSIZE_B_Bossen_1              | ER                   |
> | PICSIZE_C_Bossen_1              | OK                   |
> | PICSIZE_D_Bossen_1              | ER                   |
> | PMERGE_A_TI_3                   | OK                   |
> | PMERGE_B_TI_3                   | OK                   |
> | PMERGE_C_TI_3                   | OK                   |
> | PMERGE_D_TI_3                   | OK                   |
> | PMERGE_E_TI_3                   | OK                   |
> | POC_A_Bossen_3                  | OK                   |
> | PPS_A_qualcomm_7                | OK                   |
> | PS_B_VIDYO_3                    | ER                   |
> | RAP_A_docomo_6                  | OK                   |
> | RAP_B_Bossen_2                  | OK                   |
> | RPLM_A_qualcomm_4               | OK                   |
> | RPLM_B_qualcomm_4               | OK                   |
> | RPS_A_docomo_5                  | OK                   |
> | RPS_B_qualcomm_5                | OK                   |
> | RPS_C_ericsson_5                | OK                   |
> | RPS_D_ericsson_6                | OK                   |
> | RPS_E_qualcomm_5                | OK                   |
> | RPS_F_docomo_2                  | OK                   |
> | RQT_A_HHI_4                     | OK                   |
> | RQT_B_HHI_4                     | OK                   |
> | RQT_C_HHI_4                     | OK                   |
> | RQT_D_HHI_4                     | OK                   |
> | RQT_E_HHI_4                     | OK                   |
> | RQT_F_HHI_4                     | OK                   |
> | RQT_G_HHI_4                     | OK                   |
> | SAO_A_MediaTek_4                | OK                   |
> | SAO_B_MediaTek_5                | OK                   |
> | SAO_C_Samsung_5                 | OK                   |
> | SAO_D_Samsung_5                 | OK                   |
> | SAO_E_Canon_4                   | OK                   |
> | SAO_F_Canon_3                   | OK                   |
> | SAO_G_Canon_3                   | OK                   |
> | SAO_H_Parabola_1                | OK                   |
> | SAODBLK_A_MainConcept_4         | OK                   |
> | SAODBLK_B_MainConcept_4         | OK                   |
> | SDH_A_Orange_4                  | OK                   |
> | SLICES_A_Rovi_3                 | OK                   |
> | SLIST_A_Sony_5                  | OK                   |
> | SLIST_B_Sony_9                  | OK                   |
> | SLIST_C_Sony_4                  | OK                   |
> | SLIST_D_Sony_9                  | OK                   |
> | SLPPLP_A_VIDYO_2                | ER                   |
> | STRUCT_A_Samsung_7              | ER                   |
> | STRUCT_B_Samsung_7              | ER                   |
> | TILES_A_Cisco_2                 | ER                   |
> | TILES_B_Cisco_1                 | ER                   |
> | TMVP_A_MS_3                     | OK                   |
> | TSCL_A_VIDYO_5                  | OK                   |
> | TSCL_B_VIDYO_4                  | ER                   |
> | TSKIP_A_MS_3                    | OK                   |
> | TSUNEQBD_A_MAIN10_Technicolor_2 | ER                   |
> | TUSIZE_A_Samsung_1              | OK                   |
> | VPSID_A_VIDYO_2                 | ER                   |
> | VPSSPSPPS_A_MainConcept_1       | KO                   |
> | WP_A_MAIN10_Toshiba_3           | ER                   |
> | WP_A_Toshiba_3                  | ER                   |
> | WP_B_Toshiba_3                  | OK                   |
> | WP_MAIN10_B_Toshiba_3           | ER                   |
> | WPP_A_ericsson_MAIN10_2         | ER                   |
> | WPP_A_ericsson_MAIN_2           | OK                   |
> | WPP_B_ericsson_MAIN10_2         | ER                   |
> | WPP_B_ericsson_MAIN_2           | OK                   |
> | WPP_C_ericsson_MAIN10_2         | ER                   |
> | WPP_C_ericsson_MAIN_2           | OK                   |
> | WPP_D_ericsson_MAIN10_2         | ER                   |
> | WPP_D_ericsson_MAIN_2           | OK                   |
> | WPP_E_ericsson_MAIN10_2         | ER                   |
> | WPP_E_ericsson_MAIN_2           | OK                   |
> | WPP_F_ericsson_MAIN10_2         | ER                   |
> | WPP_F_ericsson_MAIN_2           | OK                   |
> | -                               | -                    |
> | Test                            | FFmpeg-H.265-v4l2m2m |
> | TOTAL                           | 120/147              |
> | TOTAL TIME                      | 12669.641s           |
> 
> Failed streams :
>  - VPSSPSPPS_A_MainConcept_1 : Failed due to evolutive dynamic resolution increases. The decoder cannot properly handle upward resolution changes within the same stream.
>  - LTRPSPS_A_Qualcomm_1
> 
> Yassine Ouaissa (5):
>   media: allegro-dvt: Move the current driver to a subdirectory
>   dt-bindings: media: allegro-dvt: add decoder dt-bindings for Gen3 IP
>   MAINTAINERS: Add entry for allegrodvt Gen 3 drivers
>   dt-bindings: vendor-prefixes: Update the description of allegro prefix
>   media: allegro-dvt: Add Gen 3 IP stateful decoder driver
> 
>  .../bindings/media/allegro,al300-vdec.yaml    |   75 +
>  .../devicetree/bindings/vendor-prefixes.yaml  |    2 +-
>  MAINTAINERS                                   |    5 +-
>  drivers/media/platform/allegro-dvt/Kconfig    |   17 +-
>  drivers/media/platform/allegro-dvt/Makefile   |    6 +-
>  .../media/platform/allegro-dvt/al300/Kconfig  |   23 +
>  .../media/platform/allegro-dvt/al300/Makefile |    6 +
>  .../allegro-dvt/al300/al_codec_common.c       |  754 ++++++++
>  .../allegro-dvt/al300/al_codec_common.h       |  247 +++
>  .../allegro-dvt/al300/al_codec_util.c         |  177 ++
>  .../allegro-dvt/al300/al_codec_util.h         |  185 ++
>  .../platform/allegro-dvt/al300/al_vdec_drv.c  | 1530 +++++++++++++++++
>  .../platform/allegro-dvt/al300/al_vdec_drv.h  |   94 +
>  .../media/platform/allegro-dvt/zynqmp/Kconfig |   17 +
>  .../platform/allegro-dvt/zynqmp/Makefile      |    6 +
>  .../allegro-dvt/{ => zynqmp}/allegro-core.c   |    0
>  .../allegro-dvt/{ => zynqmp}/allegro-mail.c   |    0
>  .../allegro-dvt/{ => zynqmp}/allegro-mail.h   |    0
>  .../allegro-dvt/{ => zynqmp}/nal-h264.c       |    0
>  .../allegro-dvt/{ => zynqmp}/nal-h264.h       |    0
>  .../allegro-dvt/{ => zynqmp}/nal-hevc.c       |    0
>  .../allegro-dvt/{ => zynqmp}/nal-hevc.h       |    0
>  .../allegro-dvt/{ => zynqmp}/nal-rbsp.c       |    0
>  .../allegro-dvt/{ => zynqmp}/nal-rbsp.h       |    0
>  24 files changed, 3123 insertions(+), 21 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/media/allegro,al300-vdec.yaml
>  create mode 100644 drivers/media/platform/allegro-dvt/al300/Kconfig
>  create mode 100644 drivers/media/platform/allegro-dvt/al300/Makefile
>  create mode 100644 drivers/media/platform/allegro-dvt/al300/al_codec_common.c
>  create mode 100644 drivers/media/platform/allegro-dvt/al300/al_codec_common.h
>  create mode 100644 drivers/media/platform/allegro-dvt/al300/al_codec_util.c
>  create mode 100644 drivers/media/platform/allegro-dvt/al300/al_codec_util.h
>  create mode 100644 drivers/media/platform/allegro-dvt/al300/al_vdec_drv.c
>  create mode 100644 drivers/media/platform/allegro-dvt/al300/al_vdec_drv.h
>  create mode 100644 drivers/media/platform/allegro-dvt/zynqmp/Kconfig
>  create mode 100644 drivers/media/platform/allegro-dvt/zynqmp/Makefile
>  rename drivers/media/platform/allegro-dvt/{ => zynqmp}/allegro-core.c (100%)
>  rename drivers/media/platform/allegro-dvt/{ => zynqmp}/allegro-mail.c (100%)
>  rename drivers/media/platform/allegro-dvt/{ => zynqmp}/allegro-mail.h (100%)
>  rename drivers/media/platform/allegro-dvt/{ => zynqmp}/nal-h264.c (100%)
>  rename drivers/media/platform/allegro-dvt/{ => zynqmp}/nal-h264.h (100%)
>  rename drivers/media/platform/allegro-dvt/{ => zynqmp}/nal-hevc.c (100%)
>  rename drivers/media/platform/allegro-dvt/{ => zynqmp}/nal-hevc.h (100%)
>  rename drivers/media/platform/allegro-dvt/{ => zynqmp}/nal-rbsp.c (100%)
>  rename drivers/media/platform/allegro-dvt/{ => zynqmp}/nal-rbsp.h (100%)
> 
> --
> 2.30.2
> 
> ---
> Yassine Ouaissa (4):
>       media: allegro-dvt: Move the current driver to a subdirectory
>       dt-bindings: media: allegro: Add al300 decoder IPs
>       dt-bindings: vendor-prefixes: Update the description of allegro prefix
>       media: allegro-dvt: Add Gen 3 IP stateful decoder driver
> 
>  .../bindings/media/allegro,al300-vdec.yaml         |   76 +
>  .../devicetree/bindings/vendor-prefixes.yaml       |    2 +-
>  MAINTAINERS                                        |    4 +-
>  drivers/media/platform/allegro-dvt/Kconfig         |   17 +-
>  drivers/media/platform/allegro-dvt/Makefile        |    6 +-
>  drivers/media/platform/allegro-dvt/al300/Kconfig   |   23 +
>  drivers/media/platform/allegro-dvt/al300/Makefile  |    9 +
>  .../platform/allegro-dvt/al300/al_codec_common.c   |  764 ++++++++++
>  .../platform/allegro-dvt/al300/al_codec_common.h   |  252 ++++
>  .../platform/allegro-dvt/al300/al_codec_dbgfs.c    |  229 +++
>  .../platform/allegro-dvt/al300/al_codec_dbgfs.h    |   71 +
>  .../platform/allegro-dvt/al300/al_codec_util.c     |  180 +++
>  .../platform/allegro-dvt/al300/al_codec_util.h     |  196 +++
>  .../media/platform/allegro-dvt/al300/al_vdec_drv.c | 1514 ++++++++++++++++++++
>  .../media/platform/allegro-dvt/al300/al_vdec_drv.h |   98 ++
>  drivers/media/platform/allegro-dvt/zynqmp/Kconfig  |   17 +
>  drivers/media/platform/allegro-dvt/zynqmp/Makefile |    6 +
>  .../allegro-dvt/{ => zynqmp}/allegro-core.c        |    0
>  .../allegro-dvt/{ => zynqmp}/allegro-mail.c        |    0
>  .../allegro-dvt/{ => zynqmp}/allegro-mail.h        |    0
>  .../platform/allegro-dvt/{ => zynqmp}/nal-h264.c   |    0
>  .../platform/allegro-dvt/{ => zynqmp}/nal-h264.h   |    0
>  .../platform/allegro-dvt/{ => zynqmp}/nal-hevc.c   |    0
>  .../platform/allegro-dvt/{ => zynqmp}/nal-hevc.h   |    0
>  .../platform/allegro-dvt/{ => zynqmp}/nal-rbsp.c   |    0
>  .../platform/allegro-dvt/{ => zynqmp}/nal-rbsp.h   |    0
>  26 files changed, 3443 insertions(+), 21 deletions(-)
> ---
> base-commit: c2f2b01b74be8b40a2173372bcd770723f87e7b2
> change-id: 20250527-allegro_dvt_al300_dec_driver-4e75a94af6dc
> 
> Best regards,
> -- 
> Yassine Ouaissa <yassine.ouaissa at allegrodvt.com>
> 
> 
> 

-- 
Pengutronix e.K.                           | Michael Tretter             |
Steuerwalder Str. 21                       | https://www.pengutronix.de/ |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From duje at dujemihanovic.xyz  Fri Dec 12 06:55:48 2025
From: duje at dujemihanovic.xyz (=?UTF-8?Q?Duje_Mihanovi=C4=87?=)
Date: Fri, 12 Dec 2025 15:55:48 +0100
Subject: [DONOTAPPLY RFC PATCH v2 4/4] arm64: dts: samsung,coreprimevelte:
 add wifi node
In-Reply-To: <DEW3NQVZ84JU.22G38WMULFZJG@matfyz.cz>
References: <20251026182602.26464-1-balejk@matfyz.cz>
 <20251026182602.26464-5-balejk@matfyz.cz> <aTCv75hjdX5XvgCh@google.com>
 <DEW3NQVZ84JU.22G38WMULFZJG@matfyz.cz>
Message-ID: <b92172f3-10f4-470f-b90a-121ff7fea988@dujemihanovic.xyz>

On 12/12/25 09:36, Karel Balej wrote:
> Brian Norris, 2025-12-03T13:47:27-08:00:
>>
>> Do we have a min/max voltage for this regulator?
> 
> The downstream node is defined with the same values as the above ldo14,
> they however are however only defined in the PMIC dtsi and correspond to
> the actual physical limits of the regulator specified also in the
> driver, so this doesn't really give any specific constraints for the
> board itself.
> 
> The downstream code enabling WiFi seems to force it to 3300000 (which
> also seems to be the startup value) unconditionally, so I suppose I will
> just set the both limits to this value?

This sounds reasonable to me.

>>
>>> +			};
>>>   		};
>>>   	};
>>>   };
>>> @@ -523,6 +531,13 @@ &sdh1 {
>>>   	pinctrl-1 = <&sdh1_fast_pins_0 &sdh1_fast_pins_1 &sdh1_pins_2>;
>>>   	bus-width = <4>;
>>>   	non-removable;
>>> +	#address-cells = <1>;
>>> +	#size-cells = <0>;
>>
>> I wonder if this should have:
>>
>> 	vmmc-supply = <&ldo16>;
>>
>> rather than regulator-always-on above.
> 
> You mean ldo15 right?
> 
> Not having any board schematics, I don't really know what exactly the
> regulator's purpose is. As I mentioned in the commit message, the
> communication with the chipset seems to work even if this is disabled
> (e. g. FW loads, networks can be scanned for,...) which doesn't seem
> like it should be the case if this was a main power supply for the bus,
> only actual connecting to networks doesn't work (gives
> CONNECT_ERR_ASSOC_ERR_TIMEOUT errors).

To me, this strongly suggests that the regulator powers the WiFi 
transmitter or at least a part of it (such as the RF amp).

> So this didn't seem too fitting for either vmmc nor vqmmc as far as I
> understand their semantics, so I went with the regulator-always-on
> approach to be safe.

Considering the above, I'd reckon it'd be good to have the option to 
toggle it for rfkill if anything. I'm however not sure what would be the 
right way to do so, nor how rfkill even works, if at all, with mwifiex 
(from what I see, the driver does not use the API).

Regards,
--
Duje


From james.clark at linaro.org  Fri Dec 12 07:00:26 2025
From: james.clark at linaro.org (James Clark)
Date: Fri, 12 Dec 2025 17:00:26 +0200
Subject: [PATCH 2/2] perf c2c: Update documentation for Arm SPE events
In-Reply-To: <20251212-perf_c2c_update_event-v1-2-29a26c7a949b@arm.com>
References: <20251212-perf_c2c_update_event-v1-0-29a26c7a949b@arm.com>
 <20251212-perf_c2c_update_event-v1-2-29a26c7a949b@arm.com>
Message-ID: <c3fa97dc-3377-4a62-9fc1-561fc904cf5c@linaro.org>



On 12/12/2025 14:44, Leo Yan wrote:
> Document the default Arm SPE events used by the perf c2c tool.  Make a
> minor adjustment to the PowerPC entry for formatting consistency.
> 
> Suggested-by: Al Grant <al.grant at arm.com>
> Signed-off-by: Leo Yan <leo.yan at arm.com>
> ---
>   tools/perf/Documentation/perf-c2c.txt | 7 ++++++-
>   1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/tools/perf/Documentation/perf-c2c.txt b/tools/perf/Documentation/perf-c2c.txt
> index 40b0f71a2c44eb642ff3bb234631a614b7c4fc9d..b765ae2511d2418a63092fb8a90a61faa335ac91 100644
> --- a/tools/perf/Documentation/perf-c2c.txt
> +++ b/tools/perf/Documentation/perf-c2c.txt
> @@ -170,11 +170,16 @@ following on AMD:
>   
>     ibs_op//
>   
> -and following on PowerPC:
> +following on PowerPC:
>   
>     cpu/mem-loads/
>     cpu/mem-stores/
>   
> +following on Arm:
> +
> +  arm_spe_0/ts_enable=1,pa_enable=1,load_filter=1,min_latency=30/
> +  arm_spe_0/ts_enable=1,pa_enable=1,store_filter=1/
> +

Technically there's 3 different ones on Arm because 
PERF_MEM_EVENTS__LOAD_STORE is also supported. Although I question the 
usefulness of these without labels or any text to say what the 
difference is, but that's an existing problem.

>   User can pass any 'perf record' option behind '--' mark, like (to enable
>   callchains and system wide monitoring):
>   
> 



From jkangas at redhat.com  Fri Dec 12 07:03:17 2025
From: jkangas at redhat.com (Jared Kangas)
Date: Fri, 12 Dec 2025 07:03:17 -0800
Subject: [PATCH] mmc: sdhci-esdhc-imx: add alternate ARCH_S32 dependency to
 Kconfig
Message-ID: <20251212-s32g-sdhci-kconfig-v1-1-8e278c8d7f78@redhat.com>

MMC_SDHCI_ESDHC_IMX requires ARCH_MXC despite also being used on
ARCH_S32, which results in unmet dependencies when compiling strictly
for ARCH_S32. Resolve this by adding ARCH_S32 as an alternative to
ARCH_MXC in the driver's dependencies.

Fixes: 5c4f00627c9a ("mmc: sdhci-esdhc-imx: add NXP S32G2 support")
Signed-off-by: Jared Kangas <jkangas at redhat.com>
---
 drivers/mmc/host/Kconfig | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 10d0ef58ef493102d3586d7a31d755543297999a..c94ae4794545de1c818ad50be7f91331862b6acf 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -315,14 +315,14 @@ config MMC_SDHCI_ESDHC_MCF
 
 config MMC_SDHCI_ESDHC_IMX
 	tristate "SDHCI support for the Freescale eSDHC/uSDHC i.MX controller"
-	depends on ARCH_MXC || COMPILE_TEST
+	depends on ARCH_MXC || ARCH_S32 || COMPILE_TEST
 	depends on MMC_SDHCI_PLTFM
 	depends on OF
 	select MMC_SDHCI_IO_ACCESSORS
 	select MMC_CQHCI
 	help
 	  This selects the Freescale eSDHC/uSDHC controller support
-	  found on i.MX25, i.MX35 i.MX5x and i.MX6x.
+	  found on i.MX25, i.MX35, i.MX5x, i.MX6x, and S32G.
 
 	  If you have a controller with this interface, say Y or M here.
 

---
base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
change-id: 20251211-s32g-sdhci-kconfig-585b6909f7b4

Best regards,
-- 
Jared Kangas <jkangas at redhat.com>



From robh at kernel.org  Fri Dec 12 07:06:31 2025
From: robh at kernel.org (Rob Herring)
Date: Fri, 12 Dec 2025 09:06:31 -0600
Subject: [PATCH RFC 00/16] Eliminate warnings for AST2500 and AST2600 EVB
 devicetrees
In-Reply-To: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
Message-ID: <20251212150631.GA3997751-robh@kernel.org>

On Thu, Dec 11, 2025 at 05:45:42PM +0900, Andrew Jeffery wrote:
> Hi all,
> 
> This series removes the remaining warnings produced by `make
> CHECK_DTBS=y ...` for the AST2500 and AST2600 EVBs and their related
> DTSIs. The tidy-up has the usual benefit of making it clear to
> contributors that any warnings are likely their own to fix before their
> patches will be considered for merging.
> 
> I've framed it as an RFC with all patches contained in the one series
> so the goal is clear, we can see what's needed to reach it, and we can
> decide whether and how it should be split or merged going forward.
> 
> As it stands there's little in the way of code change, except to
> pinctrl (though also not much there). As such I've included the
> binding maintainers and subsystem lists as recipients but not yet Cc'ed
> subsystem maintainers directly because there are quite a few and I hope
> to avoid mostly uninteresting patches being a source of irritation.
> 
> The patches fall into several groups:
> 
> Patch 1:
>   Rob's conversion of the PWM/tach binding to DT schema with fixes
>   applied for the license and typos identified by Krzysztof.
> 
> Patches 2-5:
>   Fixes for the warnings related to the LPC and pinctrl nodes, touching
>   relevant drivers and the devicetrees.
> 
>   I expect that if this approach is acceptable that we'll need to split
>   application of the patches across successive release cycles, with the
>   driver changes going in first.
> 
> Patches 6-8:
>   Fix MMC/SDHCI warnings, touching the relevant binding and devicetrees
> 
> Patches 9-10:
>   Clarify the relationships between the ACRY and AHB controller
> 
> Patches 11-16:
>   The remaining pieces that eliminate the warnings

Don't you see warnings for at25:

     89 (atmel,at25): 'size' is a required property
     89 (atmel,at25): 'pagesize' is a required property
     89 (atmel,at25): 'address-width' is a required property

These are due to using the deprecated (since 2012) at25,byte-len, 
at25,addr-mode, and at25,page-size properties. I think it has been long 
enough you can just replace them with the new ones.

Rob


From james.clark at linaro.org  Fri Dec 12 07:17:56 2025
From: james.clark at linaro.org (James Clark)
Date: Fri, 12 Dec 2025 17:17:56 +0200
Subject: [PATCH 1/2] perf mem: Simplify Arm SPE event config
In-Reply-To: <20251212-perf_c2c_update_event-v1-1-29a26c7a949b@arm.com>
References: <20251212-perf_c2c_update_event-v1-0-29a26c7a949b@arm.com>
 <20251212-perf_c2c_update_event-v1-1-29a26c7a949b@arm.com>
Message-ID: <6a642215-2834-4c27-b716-477d5444ad9c@linaro.org>



On 12/12/2025 14:44, Leo Yan wrote:
> Since configuration fields default to zero, the zero assignments are
> redundant, remove them.
> 
> Signed-off-by: Leo Yan <leo.yan at arm.com>
> ---
>   tools/perf/arch/arm64/util/mem-events.c | 4 ++--
>   1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/tools/perf/arch/arm64/util/mem-events.c b/tools/perf/arch/arm64/util/mem-events.c
> index 9f8da7937255cc9b14c3c58a1119b40bd0c76f6b..eaf00e0609c6c1b7d939a02fe3794471d1ed119b 100644
> --- a/tools/perf/arch/arm64/util/mem-events.c
> +++ b/tools/perf/arch/arm64/util/mem-events.c
> @@ -6,7 +6,7 @@
>   #define E(t, n, s, l, a) { .tag = t, .name = n, .event_name = s, .ldlat = l, .aux_event = a }
>   
>   struct perf_mem_event perf_mem_events_arm[PERF_MEM_EVENTS__MAX] = {
> -	E("spe-load",	"%s/ts_enable=1,pa_enable=1,load_filter=1,store_filter=0,min_latency=%u/",	NULL,	true,	0),
> -	E("spe-store",	"%s/ts_enable=1,pa_enable=1,load_filter=0,store_filter=1/",			NULL,	false,	0),
> +	E("spe-load",	"%s/ts_enable=1,pa_enable=1,load_filter=1,min_latency=%u/",	NULL,	true,	0),
> +	E("spe-store",	"%s/ts_enable=1,pa_enable=1,store_filter=1/",			NULL,	false,	0),
>   	E("spe-ldst",	"%s/ts_enable=1,pa_enable=1,load_filter=1,store_filter=1,min_latency=%u/",	NULL,	true,	0),
>   };
> 

Reviewed-by: James Clark <james.clark at linaro.org>




From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:37 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:37 +0000
Subject: [PATCH 07/32] KVM: arm64: gic: Introduce interrupt type helpers
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-8-sascha.bischoff@arm.com>

GICv5 has moved from using interrupt ranges for different interrupt
types to using some of the upper bits of the interrupt ID to denote
the interrupt type. This is not compatible with older GICs (which rely
on ranges of interrupts to determine the type), and hence a set of
helpers is introduced. These helpers take a struct kvm*, and use the
vgic model to determine how to interpret the interrupt ID.

Helpers are introduced for PPIs, SPIs, and LPIs. Additionally, a
helper is introduced to determine if an interrupt is private - SGIs
and PPIs for older GICs, and PPIs only for GICv5.

The helpers are plumbed into the core vgic code, as well as the Arch
Timer and PMU code.

There should be no functional changes as part of this change.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/arch_timer.c           |  2 +-
 arch/arm64/kvm/pmu-emul.c             |  6 +++---
 arch/arm64/kvm/vgic/vgic-kvm-device.c |  2 +-
 arch/arm64/kvm/vgic/vgic.c            | 14 +++++++-------
 include/kvm/arm_vgic.h                | 27 +++++++++++++++++++++++----
 5 files changed, 35 insertions(+), 16 deletions(-)

diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c
index 99a07972068d1..6f033f6644219 100644
--- a/arch/arm64/kvm/arch_timer.c
+++ b/arch/arm64/kvm/arch_timer.c
@@ -1598,7 +1598,7 @@ int kvm_arm_timer_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
 	if (get_user(irq, uaddr))
 		return -EFAULT;
 
-	if (!(irq_is_ppi(irq)))
+	if (!(irq_is_ppi(vcpu->kvm, irq)))
 		return -EINVAL;
 
 	mutex_lock(&vcpu->kvm->arch.config_lock);
diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c
index b03dbda7f1ab9..0baf8e0fe23bd 100644
--- a/arch/arm64/kvm/pmu-emul.c
+++ b/arch/arm64/kvm/pmu-emul.c
@@ -939,7 +939,7 @@ int kvm_arm_pmu_v3_enable(struct kvm_vcpu *vcpu)
 		 * number against the dimensions of the vgic and make sure
 		 * it's valid.
 		 */
-		if (!irq_is_ppi(irq) && !vgic_valid_spi(vcpu->kvm, irq))
+		if (!irq_is_ppi(vcpu->kvm, irq) && !vgic_valid_spi(vcpu->kvm, irq))
 			return -EINVAL;
 	} else if (kvm_arm_pmu_irq_initialized(vcpu)) {
 		   return -EINVAL;
@@ -991,7 +991,7 @@ static bool pmu_irq_is_valid(struct kvm *kvm, int irq)
 		if (!kvm_arm_pmu_irq_initialized(vcpu))
 			continue;
 
-		if (irq_is_ppi(irq)) {
+		if (irq_is_ppi(kvm, irq)) {
 			if (vcpu->arch.pmu.irq_num != irq)
 				return false;
 		} else {
@@ -1142,7 +1142,7 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
 			return -EFAULT;
 
 		/* The PMU overflow interrupt can be a PPI or a valid SPI. */
-		if (!(irq_is_ppi(irq) || irq_is_spi(irq)))
+		if (!(irq_is_ppi(vcpu->kvm, irq) || irq_is_spi(vcpu->kvm, irq)))
 			return -EINVAL;
 
 		if (!pmu_irq_is_valid(kvm, irq))
diff --git a/arch/arm64/kvm/vgic/vgic-kvm-device.c b/arch/arm64/kvm/vgic/vgic-kvm-device.c
index 3d1a776b716d7..b12ba99a423e5 100644
--- a/arch/arm64/kvm/vgic/vgic-kvm-device.c
+++ b/arch/arm64/kvm/vgic/vgic-kvm-device.c
@@ -639,7 +639,7 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
 		if (vgic_initialized(dev->kvm))
 			return -EBUSY;
 
-		if (!irq_is_ppi(val))
+		if (!irq_is_ppi(dev->kvm, val))
 			return -EINVAL;
 
 		dev->kvm->arch.vgic.mi_intid = val;
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index 430aa98888fda..2c0e8803342e2 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -94,7 +94,7 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, u32 intid)
 	}
 
 	/* LPIs */
-	if (intid >= VGIC_MIN_LPI)
+	if (irq_is_lpi(kvm, intid))
 		return vgic_get_lpi(kvm, intid);
 
 	return NULL;
@@ -123,7 +123,7 @@ static void vgic_release_lpi_locked(struct vgic_dist *dist, struct vgic_irq *irq
 
 static __must_check bool __vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
 {
-	if (irq->intid < VGIC_MIN_LPI)
+	if (!irq_is_lpi(kvm, irq->intid))
 		return false;
 
 	return refcount_dec_and_test(&irq->refcount);
@@ -148,7 +148,7 @@ void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
 	 * Acquire/release it early on lockdep kernels to make locking issues
 	 * in rare release paths a bit more obvious.
 	 */
-	if (IS_ENABLED(CONFIG_LOCKDEP) && irq->intid >= VGIC_MIN_LPI) {
+	if (IS_ENABLED(CONFIG_LOCKDEP) && irq_is_lpi(kvm, irq->intid)) {
 		guard(spinlock_irqsave)(&dist->lpi_xa.xa_lock);
 	}
 
@@ -186,7 +186,7 @@ void vgic_flush_pending_lpis(struct kvm_vcpu *vcpu)
 	raw_spin_lock_irqsave(&vgic_cpu->ap_list_lock, flags);
 
 	list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
-		if (irq->intid >= VGIC_MIN_LPI) {
+		if (irq_is_lpi(vcpu->kvm, irq->intid)) {
 			raw_spin_lock(&irq->irq_lock);
 			list_del(&irq->ap_list);
 			irq->vcpu = NULL;
@@ -521,12 +521,12 @@ int kvm_vgic_inject_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 	if (ret)
 		return ret;
 
-	if (!vcpu && intid < VGIC_NR_PRIVATE_IRQS)
+	if (!vcpu && irq_is_private(kvm, intid))
 		return -EINVAL;
 
 	trace_vgic_update_irq_pending(vcpu ? vcpu->vcpu_idx : 0, intid, level);
 
-	if (intid < VGIC_NR_PRIVATE_IRQS)
+	if (irq_is_private(kvm, intid))
 		irq = vgic_get_vcpu_irq(vcpu, intid);
 	else
 		irq = vgic_get_irq(kvm, intid);
@@ -685,7 +685,7 @@ int kvm_vgic_set_owner(struct kvm_vcpu *vcpu, unsigned int intid, void *owner)
 		return -EAGAIN;
 
 	/* SGIs and LPIs cannot be wired up to any device */
-	if (!irq_is_ppi(intid) && !vgic_valid_spi(vcpu->kvm, intid))
+	if (!irq_is_ppi(vcpu->kvm, intid) && !vgic_valid_spi(vcpu->kvm, intid))
 		return -EINVAL;
 
 	irq = vgic_get_vcpu_irq(vcpu, intid);
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index b261fb3968d03..be1f45a494f78 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -19,6 +19,7 @@
 #include <linux/jump_label.h>
 
 #include <linux/irqchip/arm-gic-v4.h>
+#include <linux/irqchip/arm-gic-v5.h>
 
 #define VGIC_V3_MAX_CPUS	512
 #define VGIC_V2_MAX_CPUS	8
@@ -31,9 +32,22 @@
 #define VGIC_MIN_LPI		8192
 #define KVM_IRQCHIP_NUM_PINS	(1020 - 32)
 
-#define irq_is_ppi(irq) ((irq) >= VGIC_NR_SGIS && (irq) < VGIC_NR_PRIVATE_IRQS)
-#define irq_is_spi(irq) ((irq) >= VGIC_NR_PRIVATE_IRQS && \
-			 (irq) <= VGIC_MAX_SPI)
+#define irq_is_ppi_legacy(irq) ((irq) >= VGIC_NR_SGIS && (irq) < VGIC_NR_PRIVATE_IRQS)
+#define irq_is_spi_legacy(irq) ((irq) >= VGIC_NR_PRIVATE_IRQS && \
+					(irq) <= VGIC_MAX_SPI)
+#define irq_is_lpi_legacy(irq) ((irq) > VGIC_MAX_SPI)
+
+#define irq_is_ppi_v5(irq) (FIELD_GET(GICV5_HWIRQ_TYPE, irq) == GICV5_HWIRQ_TYPE_PPI)
+#define irq_is_spi_v5(irq) (FIELD_GET(GICV5_HWIRQ_TYPE, irq) == GICV5_HWIRQ_TYPE_SPI)
+#define irq_is_lpi_v5(irq) (FIELD_GET(GICV5_HWIRQ_TYPE, irq) == GICV5_HWIRQ_TYPE_LPI)
+
+#define gic_is_v5(k) ((k)->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5)
+
+#define irq_is_ppi(k, i) (gic_is_v5(k) ? irq_is_ppi_v5(i) : irq_is_ppi_legacy(i))
+#define irq_is_spi(k, i) (gic_is_v5(k) ? irq_is_spi_v5(i) : irq_is_spi_legacy(i))
+#define irq_is_lpi(k, i) (gic_is_v5(k) ? irq_is_lpi_v5(i) : irq_is_lpi_legacy(i))
+
+#define irq_is_private(k, i) (gic_is_v5(k) ? irq_is_ppi_v5(i) : i < VGIC_NR_PRIVATE_IRQS)
 
 enum vgic_type {
 	VGIC_V2,		/* Good ol' GICv2 */
@@ -418,8 +432,13 @@ u64 vgic_v3_get_misr(struct kvm_vcpu *vcpu);
 
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
 #define vgic_initialized(k)	((k)->arch.vgic.initialized)
-#define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
+#define vgic_ready(k)		((k)->arch.vgic.ready)
+#define vgic_valid_spi_legacy(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
 			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
+#define vgic_valid_spi_v5(k, i)	(irq_is_spi(k, i) && \
+				 (FIELD_GET(GICV5_HWIRQ_ID, i) < (k)->arch.vgic.nr_spis))
+#define vgic_valid_spi(k, i) (((k)->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V5) ? \
+				vgic_valid_spi_legacy(k, i) : vgic_valid_spi_v5(k, i))
 
 bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
 void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:37 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:37 +0000
Subject: [PATCH 06/32] KVM: arm64: gic-v5: Add ARM_VGIC_V5 device to KVM
 headers
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-7-sascha.bischoff@arm.com>

This is the base GICv5 device which is to be used with the
KVM_CREATE_DEVICE ioctl to create a GICv5-based vgic.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 include/uapi/linux/kvm.h       | 2 ++
 tools/include/uapi/linux/kvm.h | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index dddb781b0507d..f7dabbf17e1a7 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1209,6 +1209,8 @@ enum kvm_device_type {
 #define KVM_DEV_TYPE_LOONGARCH_EIOINTC	KVM_DEV_TYPE_LOONGARCH_EIOINTC
 	KVM_DEV_TYPE_LOONGARCH_PCHPIC,
 #define KVM_DEV_TYPE_LOONGARCH_PCHPIC	KVM_DEV_TYPE_LOONGARCH_PCHPIC
+	KVM_DEV_TYPE_ARM_VGIC_V5,
+#define KVM_DEV_TYPE_ARM_VGIC_V5	KVM_DEV_TYPE_ARM_VGIC_V5
 
 	KVM_DEV_TYPE_MAX,
 
diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h
index 52f6000ab0208..8303124973e2a 100644
--- a/tools/include/uapi/linux/kvm.h
+++ b/tools/include/uapi/linux/kvm.h
@@ -1198,6 +1198,8 @@ enum kvm_device_type {
 #define KVM_DEV_TYPE_LOONGARCH_EIOINTC	KVM_DEV_TYPE_LOONGARCH_EIOINTC
 	KVM_DEV_TYPE_LOONGARCH_PCHPIC,
 #define KVM_DEV_TYPE_LOONGARCH_PCHPIC	KVM_DEV_TYPE_LOONGARCH_PCHPIC
+	KVM_DEV_TYPE_ARM_VGIC_V5,
+#define KVM_DEV_TYPE_ARM_VGIC_V5	KVM_DEV_TYPE_ARM_VGIC_V5
 
 	KVM_DEV_TYPE_MAX,
 
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:36 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:36 +0000
Subject: [PATCH 05/32] arm64/sysreg: Add GICR CDNMIA encoding
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-6-sascha.bischoff@arm.com>

The encoding for the GICR CDNMIA system instruction is thus far unused
(and shall remain unused for the time being). However, in order to
plumb the FGTs into KVM correctly, KVM needs to be made aware of the
encoding of this system instruction.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/include/asm/sysreg.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index b3b8b8cd7bf1e..e99acb6dbd5d8 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -1059,6 +1059,7 @@
 #define GICV5_OP_GIC_CDPRI		sys_insn(1, 0, 12, 1, 2)
 #define GICV5_OP_GIC_CDRCFG		sys_insn(1, 0, 12, 1, 5)
 #define GICV5_OP_GICR_CDIA		sys_insn(1, 0, 12, 3, 0)
+#define GICV5_OP_GICR_CDNMIA		sys_insn(1, 0, 12, 3, 1)
 
 /* Definitions for GIC CDAFF */
 #define GICV5_GIC_CDAFF_IAFFID_MASK	GENMASK_ULL(47, 32)
@@ -1105,6 +1106,12 @@
 #define GICV5_GIC_CDIA_TYPE_MASK	GENMASK_ULL(31, 29)
 #define GICV5_GIC_CDIA_ID_MASK		GENMASK_ULL(23, 0)
 
+/* Definitions for GICR CDNMIA */
+#define GICV5_GIC_CDNMIA_VALID_MASK	BIT_ULL(32)
+#define GICV5_GICR_CDNMIA_VALID(r)	FIELD_GET(GICV5_GIC_CDNMIA_VALID_MASK, r)
+#define GICV5_GIC_CDNMIA_TYPE_MASK	GENMASK_ULL(31, 29)
+#define GICV5_GIC_CDNMIA_ID_MASK	GENMASK_ULL(23, 0)
+
 #define gicr_insn(insn)			read_sysreg_s(GICV5_OP_GICR_##insn)
 #define gic_insn(v, insn)		write_sysreg_s(v, GICV5_OP_GIC_##insn)
 
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:35 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:35 +0000
Subject: [PATCH 01/32] KVM: arm64: Account for RES1 bits in DECLARE_FEAT_MAP()
 and co
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-2-sascha.bischoff@arm.com>

From: Marc Zyngier <maz at kernel.org>

None of the registers we manage in the feature dependency infrastructure
so far has any RES1 bit. This is about to change, as VTCR_EL2 has
its bit 31 being RES1.

In order to not fail the consistency checks by not describing a bit,
add RES1 bits to the set of immutable bits. This requires some extra
surgery for the FGT handling, as we now need to track RES1 bits there
as well.

There are no RES1 FGT bits *yet*. Watch this space.

Signed-off-by: Marc Zyngier <maz at kernel.org>
---
 arch/arm64/include/asm/kvm_host.h |  1 +
 arch/arm64/kvm/config.c           | 25 +++++++-------
 arch/arm64/kvm/emulate-nested.c   | 55 +++++++++++++++++--------------
 3 files changed, 45 insertions(+), 36 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index ac7f970c78830..b552a1e03848c 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -638,6 +638,7 @@ struct fgt_masks {
 	u64		mask;
 	u64		nmask;
 	u64		res0;
+	u64		res1;
 };
 
 extern struct fgt_masks hfgrtr_masks;
diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index 24bb3f36e9d59..3845b188551b6 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -16,14 +16,14 @@
  */
 struct reg_bits_to_feat_map {
 	union {
-		u64	bits;
-		u64	*res0p;
+		u64		 bits;
+		struct fgt_masks *masks;
 	};
 
 #define	NEVER_FGU	BIT(0)	/* Can trap, but never UNDEF */
 #define	CALL_FUNC	BIT(1)	/* Needs to evaluate tons of crap */
 #define	FIXED_VALUE	BIT(2)	/* RAZ/WI or RAO/WI in KVM */
-#define	RES0_POINTER	BIT(3)	/* Pointer to RES0 value instead of bits */
+#define	MASKS_POINTER	BIT(3)	/* Pointer to fgt_masks struct instead of bits */
 
 	unsigned long	flags;
 
@@ -92,8 +92,8 @@ struct reg_feat_map_desc {
 #define NEEDS_FEAT_FIXED(m, ...)			\
 	__NEEDS_FEAT_FLAG(m, FIXED_VALUE, bits, __VA_ARGS__, 0)
 
-#define NEEDS_FEAT_RES0(p, ...)				\
-	__NEEDS_FEAT_FLAG(p, RES0_POINTER, res0p, __VA_ARGS__)
+#define NEEDS_FEAT_MASKS(p, ...)				\
+	__NEEDS_FEAT_FLAG(p, MASKS_POINTER, masks, __VA_ARGS__)
 
 /*
  * Declare the dependency between a set of bits and a set of features,
@@ -109,19 +109,20 @@ struct reg_feat_map_desc {
 #define DECLARE_FEAT_MAP(n, r, m, f)					\
 	struct reg_feat_map_desc n = {					\
 		.name			= #r,				\
-		.feat_map		= NEEDS_FEAT(~r##_RES0, f), 	\
+		.feat_map		= NEEDS_FEAT(~(r##_RES0 |	\
+						       r##_RES1), f),	\
 		.bit_feat_map		= m,				\
 		.bit_feat_map_sz	= ARRAY_SIZE(m),		\
 	}
 
 /*
  * Specialised version of the above for FGT registers that have their
- * RES0 masks described as struct fgt_masks.
+ * RESx masks described as struct fgt_masks.
  */
 #define DECLARE_FEAT_MAP_FGT(n, msk, m, f)				\
 	struct reg_feat_map_desc n = {					\
 		.name			= #msk,				\
-		.feat_map		= NEEDS_FEAT_RES0(&msk.res0, f),\
+		.feat_map		= NEEDS_FEAT_MASKS(&msk, f),	\
 		.bit_feat_map		= m,				\
 		.bit_feat_map_sz	= ARRAY_SIZE(m),		\
 	}
@@ -1168,21 +1169,21 @@ static const DECLARE_FEAT_MAP(mdcr_el2_desc, MDCR_EL2,
 			      mdcr_el2_feat_map, FEAT_AA64EL2);
 
 static void __init check_feat_map(const struct reg_bits_to_feat_map *map,
-				  int map_size, u64 res0, const char *str)
+				  int map_size, u64 resx, const char *str)
 {
 	u64 mask = 0;
 
 	for (int i = 0; i < map_size; i++)
 		mask |= map[i].bits;
 
-	if (mask != ~res0)
+	if (mask != ~resx)
 		kvm_err("Undefined %s behaviour, bits %016llx\n",
-			str, mask ^ ~res0);
+			str, mask ^ ~resx);
 }
 
 static u64 reg_feat_map_bits(const struct reg_bits_to_feat_map *map)
 {
-	return map->flags & RES0_POINTER ? ~(*map->res0p) : map->bits;
+	return map->flags & MASKS_POINTER ? (map->masks->mask | map->masks->nmask) : map->bits;
 }
 
 static void __init check_reg_desc(const struct reg_feat_map_desc *r)
diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c
index 834f13fb1fb7d..75d49f83342a5 100644
--- a/arch/arm64/kvm/emulate-nested.c
+++ b/arch/arm64/kvm/emulate-nested.c
@@ -2105,23 +2105,24 @@ static u32 encoding_next(u32 encoding)
 }
 
 #define FGT_MASKS(__n, __m)						\
-	struct fgt_masks __n = { .str = #__m, .res0 = __m, }
-
-FGT_MASKS(hfgrtr_masks, HFGRTR_EL2_RES0);
-FGT_MASKS(hfgwtr_masks, HFGWTR_EL2_RES0);
-FGT_MASKS(hfgitr_masks, HFGITR_EL2_RES0);
-FGT_MASKS(hdfgrtr_masks, HDFGRTR_EL2_RES0);
-FGT_MASKS(hdfgwtr_masks, HDFGWTR_EL2_RES0);
-FGT_MASKS(hafgrtr_masks, HAFGRTR_EL2_RES0);
-FGT_MASKS(hfgrtr2_masks, HFGRTR2_EL2_RES0);
-FGT_MASKS(hfgwtr2_masks, HFGWTR2_EL2_RES0);
-FGT_MASKS(hfgitr2_masks, HFGITR2_EL2_RES0);
-FGT_MASKS(hdfgrtr2_masks, HDFGRTR2_EL2_RES0);
-FGT_MASKS(hdfgwtr2_masks, HDFGWTR2_EL2_RES0);
+	struct fgt_masks __n = { .str = #__m, .res0 = __m ## _RES0, .res1 = __m ## _RES1 }
+
+FGT_MASKS(hfgrtr_masks, HFGRTR_EL2);
+FGT_MASKS(hfgwtr_masks, HFGWTR_EL2);
+FGT_MASKS(hfgitr_masks, HFGITR_EL2);
+FGT_MASKS(hdfgrtr_masks, HDFGRTR_EL2);
+FGT_MASKS(hdfgwtr_masks, HDFGWTR_EL2);
+FGT_MASKS(hafgrtr_masks, HAFGRTR_EL2);
+FGT_MASKS(hfgrtr2_masks, HFGRTR2_EL2);
+FGT_MASKS(hfgwtr2_masks, HFGWTR2_EL2);
+FGT_MASKS(hfgitr2_masks, HFGITR2_EL2);
+FGT_MASKS(hdfgrtr2_masks, HDFGRTR2_EL2);
+FGT_MASKS(hdfgwtr2_masks, HDFGWTR2_EL2);
 
 static __init bool aggregate_fgt(union trap_config tc)
 {
 	struct fgt_masks *rmasks, *wmasks;
+	u64 rresx, wresx;
 
 	switch (tc.fgt) {
 	case HFGRTR_GROUP:
@@ -2154,24 +2155,27 @@ static __init bool aggregate_fgt(union trap_config tc)
 		break;
 	}
 
+	rresx = rmasks->res0 | rmasks->res1;
+	if (wmasks)
+		wresx = wmasks->res0 | wmasks->res1;
+
 	/*
 	 * A bit can be reserved in either the R or W register, but
 	 * not both.
 	 */
-	if ((BIT(tc.bit) & rmasks->res0) &&
-	    (!wmasks || (BIT(tc.bit) & wmasks->res0)))
+	if ((BIT(tc.bit) & rresx) && (!wmasks || (BIT(tc.bit) & wresx)))
 		return false;
 
 	if (tc.pol)
-		rmasks->mask |= BIT(tc.bit) & ~rmasks->res0;
+		rmasks->mask |= BIT(tc.bit) & ~rresx;
 	else
-		rmasks->nmask |= BIT(tc.bit) & ~rmasks->res0;
+		rmasks->nmask |= BIT(tc.bit) & ~rresx;
 
 	if (wmasks) {
 		if (tc.pol)
-			wmasks->mask |= BIT(tc.bit) & ~wmasks->res0;
+			wmasks->mask |= BIT(tc.bit) & ~wresx;
 		else
-			wmasks->nmask |= BIT(tc.bit) & ~wmasks->res0;
+			wmasks->nmask |= BIT(tc.bit) & ~wresx;
 	}
 
 	return true;
@@ -2180,7 +2184,6 @@ static __init bool aggregate_fgt(union trap_config tc)
 static __init int check_fgt_masks(struct fgt_masks *masks)
 {
 	unsigned long duplicate = masks->mask & masks->nmask;
-	u64 res0 = masks->res0;
 	int ret = 0;
 
 	if (duplicate) {
@@ -2194,10 +2197,14 @@ static __init int check_fgt_masks(struct fgt_masks *masks)
 		ret = -EINVAL;
 	}
 
-	masks->res0 = ~(masks->mask | masks->nmask);
-	if (masks->res0 != res0)
-		kvm_info("Implicit %s = %016llx, expecting %016llx\n",
-			 masks->str, masks->res0, res0);
+	if ((masks->res0 | masks->res1 | masks->mask | masks->nmask) != GENMASK(63, 0) ||
+	    (masks->res0 & masks->res1)  || (masks->res0 & masks->mask) ||
+	    (masks->res0 & masks->nmask) || (masks->res1 & masks->mask)  ||
+	    (masks->res1 & masks->nmask) || (masks->mask & masks->nmask)) {
+		kvm_info("Inconsistent masks for %s (%016llx, %016llx, %016llx, %016llx)\n",
+			 masks->str, masks->res0, masks->res1, masks->mask, masks->nmask);
+		masks->res0 = ~(masks->res1 | masks->mask | masks->nmask);
+	}
 
 	return ret;
 }
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:37 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:37 +0000
Subject: [PATCH 08/32] KVM: arm64: gic-v5: Sanitize ID_AA64PFR2_EL1.GCIE
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-9-sascha.bischoff@arm.com>

Set the guest's view of the GCIE field to IMP when running a GICv5 VM,
NI otherwise. Reject any writes to the register that try to do
anything but set GCIE to IMP when running a GICv5 VM.

As part of this change, we also introduce vgic_is_v5(kvm), in order to
check if the guest is a GICv5-native VM. We're also required to extend
vgic_is_v3_compat to check for the actual vgic_model. This has one
potential issue - if any of the vgic_is_v* checks are used prior to
setting the vgic_model (that is, before kvm_vgic_create) then
vgic_model will be set to 0, which can result in a false-positive.

Co-authored-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/sys_regs.c  | 39 ++++++++++++++++++++++++++++++--------
 arch/arm64/kvm/vgic/vgic.h | 15 ++++++++++++++-
 2 files changed, 45 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index c8fd7c6a12a13..a065f8939bc8f 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1758,6 +1758,7 @@ static u8 pmuver_to_perfmon(u8 pmuver)
 
 static u64 sanitise_id_aa64pfr0_el1(const struct kvm_vcpu *vcpu, u64 val);
 static u64 sanitise_id_aa64pfr1_el1(const struct kvm_vcpu *vcpu, u64 val);
+static u64 sanitise_id_aa64pfr2_el1(const struct kvm_vcpu *vcpu, u64 val);
 static u64 sanitise_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val);
 
 /* Read a sanitised cpufeature ID register by sys_reg_desc */
@@ -1783,10 +1784,7 @@ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu,
 		val = sanitise_id_aa64pfr1_el1(vcpu, val);
 		break;
 	case SYS_ID_AA64PFR2_EL1:
-		val &= ID_AA64PFR2_EL1_FPMR |
-			(kvm_has_mte(vcpu->kvm) ?
-			 ID_AA64PFR2_EL1_MTEFAR | ID_AA64PFR2_EL1_MTESTOREONLY :
-			 0);
+		val = sanitise_id_aa64pfr2_el1(vcpu, val);
 		break;
 	case SYS_ID_AA64ISAR1_EL1:
 		if (!vcpu_has_ptrauth(vcpu))
@@ -2024,6 +2022,20 @@ static u64 sanitise_id_aa64pfr1_el1(const struct kvm_vcpu *vcpu, u64 val)
 	return val;
 }
 
+static u64 sanitise_id_aa64pfr2_el1(const struct kvm_vcpu *vcpu, u64 val)
+{
+	val &= ID_AA64PFR2_EL1_FPMR |
+		(kvm_has_mte(vcpu->kvm) ?
+			ID_AA64PFR2_EL1_MTEFAR | ID_AA64PFR2_EL1_MTESTOREONLY : 0);
+
+	if (vgic_is_v5(vcpu->kvm)) {
+		val &= ~ID_AA64PFR2_EL1_GCIE_MASK;
+		val |= SYS_FIELD_PREP_ENUM(ID_AA64PFR2_EL1, GCIE, IMP);
+	}
+
+	return val;
+}
+
 static u64 sanitise_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val)
 {
 	val = ID_REG_LIMIT_FIELD_ENUM(val, ID_AA64DFR0_EL1, DebugVer, V8P8);
@@ -2221,6 +2233,16 @@ static int set_id_aa64pfr1_el1(struct kvm_vcpu *vcpu,
 	return set_id_reg(vcpu, rd, user_val);
 }
 
+static int set_id_aa64pfr2_el1(struct kvm_vcpu *vcpu,
+			       const struct sys_reg_desc *rd, u64 user_val)
+{
+	if (vgic_is_v5(vcpu->kvm) &&
+	    FIELD_GET(ID_AA64PFR2_EL1_GCIE_MASK, user_val) != ID_AA64PFR2_EL1_GCIE_IMP)
+		return -EINVAL;
+
+	return set_id_reg(vcpu, rd, user_val);
+}
+
 /*
  * Allow userspace to de-feature a stage-2 translation granule but prevent it
  * from claiming the impossible.
@@ -3202,10 +3224,11 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 				       ID_AA64PFR1_EL1_RES0 |
 				       ID_AA64PFR1_EL1_MPAM_frac |
 				       ID_AA64PFR1_EL1_MTE)),
-	ID_WRITABLE(ID_AA64PFR2_EL1,
-		    ID_AA64PFR2_EL1_FPMR |
-		    ID_AA64PFR2_EL1_MTEFAR |
-		    ID_AA64PFR2_EL1_MTESTOREONLY),
+	ID_FILTERED(ID_AA64PFR2_EL1, id_aa64pfr2_el1,
+		    ~(ID_AA64PFR2_EL1_FPMR |
+		      ID_AA64PFR2_EL1_MTEFAR |
+		      ID_AA64PFR2_EL1_MTESTOREONLY |
+		      ID_AA64PFR2_EL1_GCIE)),
 	ID_UNALLOCATED(4,3),
 	ID_WRITABLE(ID_AA64ZFR0_EL1, ~ID_AA64ZFR0_EL1_RES0),
 	ID_HIDDEN(ID_AA64SMFR0_EL1),
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index 5f0fc96b4dc29..bf5bae023751b 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -455,8 +455,16 @@ void vgic_v3_nested_update_mi(struct kvm_vcpu *vcpu);
 
 static inline bool vgic_is_v3_compat(struct kvm *kvm)
 {
+	/*
+	 * We need to be careful here. This could be called early,
+	 * which means that there is no vgic_model set. For the time
+	 * being, fall back to assuming that we're trying run a legacy
+	 * VM in that case, which keeps existing software happy. Long
+	 * term, this will need to be revisited a little.
+	 */
 	return cpus_have_final_cap(ARM64_HAS_GICV5_CPUIF) &&
-		kvm_vgic_global_state.has_gcie_v3_compat;
+		kvm_vgic_global_state.has_gcie_v3_compat &&
+		kvm->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V5;
 }
 
 static inline bool vgic_is_v3(struct kvm *kvm)
@@ -464,6 +472,11 @@ static inline bool vgic_is_v3(struct kvm *kvm)
 	return kvm_vgic_global_state.type == VGIC_V3 || vgic_is_v3_compat(kvm);
 }
 
+static inline bool vgic_is_v5(struct kvm *kvm)
+{
+	return kvm_vgic_global_state.type == VGIC_V5 && !vgic_is_v3_compat(kvm);
+}
+
 int vgic_its_debug_init(struct kvm_device *dev);
 void vgic_its_debug_destroy(struct kvm_device *dev);
 
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:36 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:36 +0000
Subject: [PATCH 03/32] arm64/sysreg: Drop ICH_HFGRTR_EL2.ICC_HAPR_EL1 and make
 RES1
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-4-sascha.bischoff@arm.com>

The GICv5 architecture is dropping the ICC_HAPR_EL1 and ICV_HAPR_EL1
system registers. These registers were never added to the sysregs, but
the traps for them were.

Drop the trap bit from the ICH_HFGRTR_EL2 and make it Res1 as per the
upcoming GICv5 spec change. Additionally, update the EL2 setup code to
not attempt to set that bit.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/include/asm/el2_setup.h | 1 -
 arch/arm64/tools/sysreg            | 2 +-
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h
index cacd20df1786e..07c12f4a69b41 100644
--- a/arch/arm64/include/asm/el2_setup.h
+++ b/arch/arm64/include/asm/el2_setup.h
@@ -225,7 +225,6 @@
 		     ICH_HFGRTR_EL2_ICC_ICSR_EL1		| \
 		     ICH_HFGRTR_EL2_ICC_PCR_EL1			| \
 		     ICH_HFGRTR_EL2_ICC_HPPIR_EL1		| \
-		     ICH_HFGRTR_EL2_ICC_HAPR_EL1		| \
 		     ICH_HFGRTR_EL2_ICC_CR0_EL1			| \
 		     ICH_HFGRTR_EL2_ICC_IDRn_EL1		| \
 		     ICH_HFGRTR_EL2_ICC_APR_EL1)
diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
index 8921b51866d64..dab5bfe8c9686 100644
--- a/arch/arm64/tools/sysreg
+++ b/arch/arm64/tools/sysreg
@@ -4579,7 +4579,7 @@ Field	7	ICC_IAFFIDR_EL1
 Field	6	ICC_ICSR_EL1
 Field	5	ICC_PCR_EL1
 Field	4	ICC_HPPIR_EL1
-Field	3	ICC_HAPR_EL1
+Res1	3
 Field	2	ICC_CR0_EL1
 Field	1	ICC_IDRn_EL1
 Field	0	ICC_APR_EL1
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:40 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:40 +0000
Subject: [PATCH 14/32] KVM: arm64: gic-v5: Implement GICv5 load/put and
 save/restore
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-15-sascha.bischoff@arm.com>

This change introduces GICv5 load/put. Additionally, it plumbs in
save/restore for:

* PPIs (ICH_PPI_x_EL2 regs)
* ICH_VMCR_EL2
* ICH_APR_EL2
* ICC_ICSR_EL1

A GICv5-specific enable bit is added to struct vgic_vmcr as this
differs from previous GICs. On GICv5-native systems, the VMCR only
contains the enable bit (driven by the guest via ICC_CR0_EL1.EN) and
the priority mask (PCR).

A struct gicv5_vpe is also introduced. This currently only contains a
single field - bool resident - which is used to track if a VPE is
currently running or not, and is used to avoid a case of double load
or double put on the WFI path for a vCPU. This struct will be extended
as additional GICv5 support is merged, specifically for VPE doorbells.

Co-authored-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/hyp/nvhe/switch.c   | 10 ++++
 arch/arm64/kvm/vgic/vgic-mmio.c    | 28 +++++++----
 arch/arm64/kvm/vgic/vgic-v5.c      | 77 ++++++++++++++++++++++++++++++
 arch/arm64/kvm/vgic/vgic.c         | 32 ++++++++-----
 arch/arm64/kvm/vgic/vgic.h         |  7 +++
 include/kvm/arm_vgic.h             |  2 +
 include/linux/irqchip/arm-gic-v5.h |  9 ++++
 7 files changed, 146 insertions(+), 19 deletions(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c
index c23e22ffac080..e25f1f000536b 100644
--- a/arch/arm64/kvm/hyp/nvhe/switch.c
+++ b/arch/arm64/kvm/hyp/nvhe/switch.c
@@ -113,6 +113,11 @@ static void __deactivate_traps(struct kvm_vcpu *vcpu)
 /* Save VGICv3 state on non-VHE systems */
 static void __hyp_vgic_save_state(struct kvm_vcpu *vcpu)
 {
+	if (kern_hyp_va(vcpu->kvm)->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5) {
+		__vgic_v5_save_icsr(&vcpu->arch.vgic_cpu.vgic_v5);
+		__vgic_v5_save_ppi_state(&vcpu->arch.vgic_cpu.vgic_v5);
+	}
+
 	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif)) {
 		__vgic_v3_save_state(&vcpu->arch.vgic_cpu.vgic_v3);
 		__vgic_v3_deactivate_traps(&vcpu->arch.vgic_cpu.vgic_v3);
@@ -122,6 +127,11 @@ static void __hyp_vgic_save_state(struct kvm_vcpu *vcpu)
 /* Restore VGICv3 state on non-VHE systems */
 static void __hyp_vgic_restore_state(struct kvm_vcpu *vcpu)
 {
+	if (kern_hyp_va(vcpu->kvm)->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5) {
+		__vgic_v5_restore_icsr(&vcpu->arch.vgic_cpu.vgic_v5);
+		__vgic_v5_restore_ppi_state(&vcpu->arch.vgic_cpu.vgic_v5);
+	}
+
 	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif)) {
 		__vgic_v3_activate_traps(&vcpu->arch.vgic_cpu.vgic_v3);
 		__vgic_v3_restore_state(&vcpu->arch.vgic_cpu.vgic_v3);
diff --git a/arch/arm64/kvm/vgic/vgic-mmio.c b/arch/arm64/kvm/vgic/vgic-mmio.c
index a573b1f0c6cbe..675c2844f5e5c 100644
--- a/arch/arm64/kvm/vgic/vgic-mmio.c
+++ b/arch/arm64/kvm/vgic/vgic-mmio.c
@@ -842,18 +842,30 @@ vgic_find_mmio_region(const struct vgic_register_region *regions,
 
 void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
 {
-	if (kvm_vgic_global_state.type == VGIC_V2)
-		vgic_v2_set_vmcr(vcpu, vmcr);
-	else
-		vgic_v3_set_vmcr(vcpu, vmcr);
+	const struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+
+	if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5) {
+		vgic_v5_set_vmcr(vcpu, vmcr);
+	} else {
+		if (kvm_vgic_global_state.type == VGIC_V2)
+			vgic_v2_set_vmcr(vcpu, vmcr);
+		else
+			vgic_v3_set_vmcr(vcpu, vmcr);
+	}
 }
 
 void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
 {
-	if (kvm_vgic_global_state.type == VGIC_V2)
-		vgic_v2_get_vmcr(vcpu, vmcr);
-	else
-		vgic_v3_get_vmcr(vcpu, vmcr);
+	const struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+
+	if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5) {
+		vgic_v5_get_vmcr(vcpu, vmcr);
+	} else {
+		if (kvm_vgic_global_state.type == VGIC_V2)
+			vgic_v2_get_vmcr(vcpu, vmcr);
+		else
+			vgic_v3_get_vmcr(vcpu, vmcr);
+	}
 }
 
 /*
diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index 2d3811f4e1174..2fb2db23ed39a 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -1,4 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2025 Arm Ltd.
+ */
 
 #include <kvm/arm_vgic.h>
 #include <linux/irqchip/arm-vgic-info.h>
@@ -50,3 +53,77 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
 
 	return 0;
 }
+
+void vgic_v5_load(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+
+	/*
+	 * On the WFI path, vgic_load is called a second time. The first is when
+	 * scheduling in the vcpu thread again, and the second is when leaving
+	 * WFI. Skip the second instance as it serves no purpose and just
+	 * restores the same state again.
+	 */
+	if (READ_ONCE(cpu_if->gicv5_vpe.resident))
+		return;
+
+	kvm_call_hyp(__vgic_v5_restore_vmcr_aprs, cpu_if);
+
+	WRITE_ONCE(cpu_if->gicv5_vpe.resident, true);
+}
+
+void vgic_v5_put(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+
+	/*
+	 * Do nothing if we're not resident. This can happen in the WFI path
+	 * where we do a vgic_put in the WFI path and again later when
+	 * descheduling the thread. We risk losing VMCR state if we sync it
+	 * twice, so instead return early in this case.
+	 */
+	if (!READ_ONCE(cpu_if->gicv5_vpe.resident))
+		return;
+
+	kvm_call_hyp(__vgic_v5_save_vmcr_aprs, cpu_if);
+
+	WRITE_ONCE(cpu_if->gicv5_vpe.resident, false);
+}
+
+void vgic_v5_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+	u64 vmcr = cpu_if->vgic_vmcr;
+
+	vmcrp->en = FIELD_GET(FEAT_GCIE_ICH_VMCR_EL2_EN, vmcr);
+	vmcrp->pmr = FIELD_GET(FEAT_GCIE_ICH_VMCR_EL2_VPMR, vmcr);
+}
+
+void vgic_v5_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+	u64 vmcr;
+
+	vmcr = FIELD_PREP(FEAT_GCIE_ICH_VMCR_EL2_VPMR, vmcrp->pmr) |
+	       FIELD_PREP(FEAT_GCIE_ICH_VMCR_EL2_EN, vmcrp->en);
+
+	cpu_if->vgic_vmcr = vmcr;
+}
+
+void vgic_v5_restore_state(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+
+	__vgic_v5_restore_icsr(cpu_if);
+	kvm_call_hyp(__vgic_v5_restore_ppi_state, cpu_if);
+	dsb(sy);
+}
+
+void vgic_v5_save_state(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+
+	__vgic_v5_save_icsr(cpu_if);
+	kvm_call_hyp(__vgic_v5_save_ppi_state, cpu_if);
+	dsb(sy);
+}
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index 2c0e8803342e2..1005ff5f36235 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -996,7 +996,9 @@ static inline bool can_access_vgic_from_kernel(void)
 
 static inline void vgic_save_state(struct kvm_vcpu *vcpu)
 {
-	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
+	if (vgic_is_v5(vcpu->kvm))
+		vgic_v5_save_state(vcpu);
+	else if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		vgic_v2_save_state(vcpu);
 	else
 		__vgic_v3_save_state(&vcpu->arch.vgic_cpu.vgic_v3);
@@ -1005,14 +1007,16 @@ static inline void vgic_save_state(struct kvm_vcpu *vcpu)
 /* Sync back the hardware VGIC state into our emulation after a guest's run. */
 void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 {
-	/* If nesting, emulate the HW effect from L0 to L1 */
-	if (vgic_state_is_nested(vcpu)) {
-		vgic_v3_sync_nested(vcpu);
-		return;
-	}
+	if (!vgic_is_v5(vcpu->kvm)) {
+		/* If nesting, emulate the HW effect from L0 to L1 */
+		if (vgic_state_is_nested(vcpu)) {
+			vgic_v3_sync_nested(vcpu);
+			return;
+		}
 
-	if (vcpu_has_nv(vcpu))
-		vgic_v3_nested_update_mi(vcpu);
+		if (vcpu_has_nv(vcpu))
+			vgic_v3_nested_update_mi(vcpu);
+	}
 
 	if (can_access_vgic_from_kernel())
 		vgic_save_state(vcpu);
@@ -1034,7 +1038,9 @@ void kvm_vgic_process_async_update(struct kvm_vcpu *vcpu)
 
 static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
 {
-	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
+	if (vgic_is_v5(vcpu->kvm))
+		vgic_v5_restore_state(vcpu);
+	else if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		vgic_v2_restore_state(vcpu);
 	else
 		__vgic_v3_restore_state(&vcpu->arch.vgic_cpu.vgic_v3);
@@ -1094,7 +1100,9 @@ void kvm_vgic_load(struct kvm_vcpu *vcpu)
 		return;
 	}
 
-	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
+	if (vgic_is_v5(vcpu->kvm))
+		vgic_v5_load(vcpu);
+	else if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		vgic_v2_load(vcpu);
 	else
 		vgic_v3_load(vcpu);
@@ -1108,7 +1116,9 @@ void kvm_vgic_put(struct kvm_vcpu *vcpu)
 		return;
 	}
 
-	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
+	if (vgic_is_v5(vcpu->kvm))
+		vgic_v5_put(vcpu);
+	else if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		vgic_v2_put(vcpu);
 	else
 		vgic_v3_put(vcpu);
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index bf5bae023751b..6e1f386dffade 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -187,6 +187,7 @@ static inline u64 vgic_ich_hcr_trap_bits(void)
  * registers regardless of the hardware backed GIC used.
  */
 struct vgic_vmcr {
+	u32	en; /* GICv5-specific */
 	u32	grpen0;
 	u32	grpen1;
 
@@ -362,6 +363,12 @@ void vgic_debug_init(struct kvm *kvm);
 void vgic_debug_destroy(struct kvm *kvm);
 
 int vgic_v5_probe(const struct gic_kvm_info *info);
+void vgic_v5_load(struct kvm_vcpu *vcpu);
+void vgic_v5_put(struct kvm_vcpu *vcpu);
+void vgic_v5_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_v5_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_v5_restore_state(struct kvm_vcpu *vcpu);
+void vgic_v5_save_state(struct kvm_vcpu *vcpu);
 
 static inline int vgic_v3_max_apr_idx(struct kvm_vcpu *vcpu)
 {
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 525c8b83e83c9..45d83f45b065d 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -388,6 +388,8 @@ struct vgic_v5_cpu_if {
 	 * it is the hyp's responsibility to keep the state constistent.
 	 */
 	u64	vgic_icsr;
+
+	struct gicv5_vpe gicv5_vpe;
 };
 
 struct vgic_cpu {
diff --git a/include/linux/irqchip/arm-gic-v5.h b/include/linux/irqchip/arm-gic-v5.h
index 68ddcdb1cec5a..ff10d6c7be2ae 100644
--- a/include/linux/irqchip/arm-gic-v5.h
+++ b/include/linux/irqchip/arm-gic-v5.h
@@ -354,6 +354,15 @@ int gicv5_spi_irq_set_type(struct irq_data *d, unsigned int type);
 int gicv5_irs_iste_alloc(u32 lpi);
 void gicv5_irs_syncr(void);
 
+#ifdef CONFIG_KVM
+
+/* Embedded in kvm.arch */
+struct gicv5_vpe {
+	bool			resident;
+};
+
+#endif // CONFIG_KVM
+
 struct gicv5_its_devtab_cfg {
 	union {
 		struct {
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:40 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:40 +0000
Subject: [PATCH 15/32] KVM: arm64: gic-v5: Implement direct injection of PPIs
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-16-sascha.bischoff@arm.com>

GICv5 is able to directly inject PPI pending state into a guest using
a mechanism called DVI whereby the pending bit for a paticular PPI is
driven directly by the physically-connected hardware. This mechanism
itself doesn't allow for any ID translation, so the host interrupt is
directly mapped into a guest with the same interrupt ID.

When mapping a virtual interrupt to a physical interrupt via
kvm_vgic_map_irq for a GICv5 guest, check if the interrupt itself is a
PPI or not. If it is, and the host's interrupt ID matches that used
for the guest DVI is enabled, and the interrupt itself is marked as
directly_injected.

When the interrupt is unmapped again, this process is reversed, and
DVI is disabled for the interrupt again.

Note: the expectation is that a directly injected PPI is disabled on
the host while the guest state is loaded. The reason is that although
DVI is enabled to drive the guest's pending state directly, the host
pending state also remains driven. In order to avoid the same PPI
firing on both the host and the guest, the host's interrupt must be
disabled (masked). This is left up to the code that owns the device
generating the PPI as this needs to be handled on a per-VM basis. One
VM might use DVI, while another might not, in which case the physical
PPI should be enabled for the latter.

Co-authored-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/vgic/vgic-v5.c | 22 ++++++++++++++++++++++
 arch/arm64/kvm/vgic/vgic.c    | 16 ++++++++++++++++
 arch/arm64/kvm/vgic/vgic.h    |  1 +
 include/kvm/arm_vgic.h        |  1 +
 4 files changed, 40 insertions(+)

diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index 2fb2db23ed39a..22558080711eb 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -54,6 +54,28 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
 	return 0;
 }
 
+/*
+ * Sets/clears the corresponding bit in the ICH_PPI_DVIR register.
+ */
+int vgic_v5_set_ppi_dvi(struct kvm_vcpu *vcpu, u32 irq, bool dvi)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+	u32 ppi = FIELD_GET(GICV5_HWIRQ_ID, irq);
+
+	if (ppi >= 128)
+		return -EINVAL;
+
+	if (dvi) {
+		/* Set the bit */
+		cpu_if->vgic_ppi_dvir[ppi / 64] |= 1UL << (ppi % 64);
+	} else {
+		/* Clear the bit */
+		cpu_if->vgic_ppi_dvir[ppi / 64] &= ~(1UL << (ppi % 64));
+	}
+
+	return 0;
+}
+
 void vgic_v5_load(struct kvm_vcpu *vcpu)
 {
 	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index 1005ff5f36235..1fe3dcc997860 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -577,12 +577,28 @@ static int kvm_vgic_map_irq(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
 	irq->host_irq = host_irq;
 	irq->hwintid = data->hwirq;
 	irq->ops = ops;
+
+	if (vgic_is_v5(vcpu->kvm)) {
+		/* Nothing for us to do */
+		if (!irq_is_ppi_v5(irq->intid))
+			return 0;
+
+		if (FIELD_GET(GICV5_HWIRQ_ID, irq->intid) == irq->hwintid) {
+			if (!vgic_v5_set_ppi_dvi(vcpu, irq->hwintid, true))
+				irq->directly_injected = true;
+		}
+	}
+
 	return 0;
 }
 
 /* @irq->irq_lock must be held */
 static inline void kvm_vgic_unmap_irq(struct vgic_irq *irq)
 {
+	if (irq->directly_injected && vgic_is_v5(irq->target_vcpu->kvm))
+		WARN_ON(vgic_v5_set_ppi_dvi(irq->target_vcpu, irq->hwintid, false));
+
+	irq->directly_injected = false;
 	irq->hw = false;
 	irq->hwintid = 0;
 	irq->ops = NULL;
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index 6e1f386dffade..b6e3f5e3aba18 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -363,6 +363,7 @@ void vgic_debug_init(struct kvm *kvm);
 void vgic_debug_destroy(struct kvm *kvm);
 
 int vgic_v5_probe(const struct gic_kvm_info *info);
+int vgic_v5_set_ppi_dvi(struct kvm_vcpu *vcpu, u32 irq, bool dvi);
 void vgic_v5_load(struct kvm_vcpu *vcpu);
 void vgic_v5_put(struct kvm_vcpu *vcpu);
 void vgic_v5_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 45d83f45b065d..ce9e149b85a58 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -163,6 +163,7 @@ struct vgic_irq {
 	bool enabled:1;
 	bool active:1;
 	bool hw:1;			/* Tied to HW IRQ */
+	bool directly_injected:1;	/* A directly injected HW IRQ */
 	bool on_lr:1;			/* Present in a CPU LR */
 	refcount_t refcount;		/* Used for LPIs */
 	u32 hwintid;			/* HW INTID number */
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:39 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:39 +0000
Subject: [PATCH 11/32] KVM: arm64: gic-v5: Trap and emulate ICH_PPI_HMRx_EL1
 accesses
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-12-sascha.bischoff@arm.com>

The ICC_PPI_HMRx_EL1 register is used to determine which PPIs use
Level-sensitive semantics, and which use Edge. For a GICv5 guest, the
correct view of the virtual PPIs must be provided to the guest.

The GICv5 architecture doesn't provide an ICV_PPI_HMRx_EL1 or
ICH_PPI_HMRx_EL2 register, and therefore all guest accesses must be
trapped to avoid the guest directly accessing the host's
ICC_PPI_HMRx_EL1 state. This change hence configures the FGTs to
always trap and emulate guest accesses to the HMR running a
GICv5-based guest.

This change also introduces the struct vgic_v5_cpu_if, which includes
the vgic_hmr. This is not yet populated as it can only be correctly
populated at vcpu reset time. This will be introduced in a subsquent
change.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/config.c   |  6 +++++-
 arch/arm64/kvm/sys_regs.c | 26 ++++++++++++++++++++++++++
 include/kvm/arm_vgic.h    |  5 +++++
 3 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index cbdd8ac90f4d0..7683407ce052a 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -1586,8 +1586,12 @@ static void __compute_ich_hfgrtr(struct kvm_vcpu *vcpu)
 {
 	__compute_fgt(vcpu, ICH_HFGRTR_EL2);
 
-	/* ICC_IAFFIDR_EL1 *always* needs to be trapped when running a guest */
+	/*
+	 * ICC_IAFFIDR_EL1 and ICH_PPI_HMRx_EL1 *always* needs to be
+	 * trapped when running a guest.
+	 **/
 	*vcpu_fgt(vcpu, ICH_HFGRTR_EL2) &= ~ICH_HFGRTR_EL2_ICC_IAFFIDR_EL1;
+	*vcpu_fgt(vcpu, ICH_HFGRTR_EL2) &= ~ICH_HFGRTR_EL2_ICC_PPI_HMRn_EL1;
 }
 
 void kvm_vcpu_load_fgt(struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 31c08fd591d08..a4ae034340040 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -699,6 +699,30 @@ static bool access_gicv5_iaffid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
+static bool access_gicv5_ppi_hmr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+				 const struct sys_reg_desc *r)
+{
+	if (!vgic_is_v5(vcpu->kvm))
+		return undef_access(vcpu, p, r);
+
+	if (p->is_write)
+		return ignore_write(vcpu, p);
+
+	/*
+	 * For GICv5 VMs, the IAFFID value is the same as the VPE ID. The VPE ID
+	 * is the same as the VCPU's ID.
+	 */
+
+	if (p->Op2 == 0) {	/* ICC_PPI_HMR0_EL1 */
+		p->regval = vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_hmr[0];
+	} else {		/* ICC_PPI_HMR1_EL1 */
+		p->regval = vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_hmr[1];
+	}
+
+	return true;
+}
+
+
 static bool trap_raz_wi(struct kvm_vcpu *vcpu,
 			struct sys_reg_params *p,
 			const struct sys_reg_desc *r)
@@ -3429,6 +3453,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	{ SYS_DESC(SYS_ICC_AP1R1_EL1), undef_access },
 	{ SYS_DESC(SYS_ICC_AP1R2_EL1), undef_access },
 	{ SYS_DESC(SYS_ICC_AP1R3_EL1), undef_access },
+	{ SYS_DESC(SYS_ICC_PPI_HMR0_EL1), access_gicv5_ppi_hmr },
+	{ SYS_DESC(SYS_ICC_PPI_HMR1_EL1), access_gicv5_ppi_hmr },
 	{ SYS_DESC(SYS_ICC_IAFFIDR_EL1), access_gicv5_iaffid },
 	{ SYS_DESC(SYS_ICC_DIR_EL1), access_gic_dir },
 	{ SYS_DESC(SYS_ICC_RPR_EL1), undef_access },
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index be1f45a494f78..fbbaef4ad2114 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -358,11 +358,16 @@ struct vgic_v3_cpu_if {
 	unsigned int used_lrs;
 };
 
+struct vgic_v5_cpu_if {
+	u64	vgic_ppi_hmr[2];
+};
+
 struct vgic_cpu {
 	/* CPU vif control registers for world switch */
 	union {
 		struct vgic_v2_cpu_if	vgic_v2;
 		struct vgic_v3_cpu_if	vgic_v3;
+		struct vgic_v5_cpu_if	vgic_v5;
 	};
 
 	struct vgic_irq *private_irqs;
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:39 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:39 +0000
Subject: [PATCH 12/32] KVM: arm64: gic: Set vgic_model before initing private
 IRQs
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-13-sascha.bischoff@arm.com>

Different GIC types require the private IRQs to be initialised
differently. GICv5 is the culprit as it supports both a different
number of private IRQs, and all of these are PPIs (there are no
SGIs). Moreover, as GICv5 uses the top bits of the interrupt ID to
encode the type, the intid also needs to computed differently.

Up until now, the GIC model has been set after initialising the
private IRQs for a VCPU. Move this earlier to ensure that the GIC
model is available when configuring the private IRQs.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/vgic/vgic-init.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index dc9f9db310264..b246cb6eae71b 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -140,6 +140,12 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
 		goto out_unlock;
 	}
 
+	kvm->arch.vgic.in_kernel = true;
+	kvm->arch.vgic.vgic_model = type;
+	kvm->arch.vgic.implementation_rev = KVM_VGIC_IMP_REV_LATEST;
+
+	kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
+
 	kvm_for_each_vcpu(i, vcpu, kvm) {
 		ret = vgic_allocate_private_irqs_locked(vcpu, type);
 		if (ret)
@@ -156,12 +162,6 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
 		goto out_unlock;
 	}
 
-	kvm->arch.vgic.in_kernel = true;
-	kvm->arch.vgic.vgic_model = type;
-	kvm->arch.vgic.implementation_rev = KVM_VGIC_IMP_REV_LATEST;
-
-	kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
-
 	aa64pfr0 = kvm_read_vm_id_reg(kvm, SYS_ID_AA64PFR0_EL1) & ~ID_AA64PFR0_EL1_GIC;
 	pfr1 = kvm_read_vm_id_reg(kvm, SYS_ID_PFR1_EL1) & ~ID_PFR1_EL1_GIC;
 
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:36 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:36 +0000
Subject: [PATCH 04/32] arm64/sysreg: Add remaining GICv5 ICC_ & ICH_ sysregs
 for KVM support
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-5-sascha.bischoff@arm.com>

Add the GICv5 system registers required to support native GICv5 guests
with KVM. Many of the GICv5 sysregs have already been added as part of
the host GICv5 driver, keeping this set relatively small. The
registers added in this change complete the set by adding those
required by KVM either directly (ICH_) or indirectly (FGTs for the
ICC_ sysregs).

The following system registers and their fields are added:

	ICC_APR_EL1
	ICC_HPPIR_EL1
	ICC_IAFFIDR_EL1
	ICH_APR_EL2
	ICH_CONTEXTR_EL2
	ICH_PPI_ACTIVER<n>_EL2
	ICH_PPI_DVI<n>_EL2
	ICH_PPI_ENABLER<n>_EL2
	ICH_PPI_PENDR<n>_EL2
	ICH_PPI_PRIORITYR<n>_EL2

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/tools/sysreg | 480 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 480 insertions(+)

diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
index dab5bfe8c9686..2f44a568ebf4e 100644
--- a/arch/arm64/tools/sysreg
+++ b/arch/arm64/tools/sysreg
@@ -3248,6 +3248,14 @@ UnsignedEnum	3:0	ID_BITS
 EndEnum
 EndSysreg
 
+Sysreg	ICC_HPPIR_EL1	3	0	12	10	3
+Res0	63:33
+Field	32	HPPIV
+Field	31:29	TYPE
+Res0	28:24
+Field	23:0	ID
+EndSysreg
+
 Sysreg	ICC_ICSR_EL1	3	0	12	10	4
 Res0	63:48
 Field	47:32	IAFFID
@@ -3262,6 +3270,11 @@ Field	1	Enabled
 Field	0	F
 EndSysreg
 
+Sysreg	ICC_IAFFIDR_EL1	3	0	12	10	5
+Res0	63:16
+Field	15:0	IAFFID
+EndSysreg
+
 SysregFields	ICC_PPI_ENABLERx_EL1
 Field	63	EN63
 Field	62	EN62
@@ -3668,6 +3681,42 @@ Res0	14:12
 Field	11:0	AFFINITY
 EndSysreg
 
+Sysreg	ICC_APR_EL1	3	1	12	0	0
+Res0	63:32
+Field	31	P31
+Field	30	P30
+Field	29	P29
+Field	28	P28
+Field	27	P27
+Field	26	P26
+Field	25	P25
+Field	24	P24
+Field	23	P23
+Field	22	P22
+Field	21	P21
+Field	20	P20
+Field	19	P19
+Field	18	P18
+Field	17	P17
+Field	16	P16
+Field	15	P15
+Field	14	P14
+Field	13	P13
+Field	12	P12
+Field	11	P11
+Field	10	P10
+Field	9	P9
+Field	8	P8
+Field	7	P7
+Field	6	P6
+Field	5	P5
+Field	4	P4
+Field	3	P3
+Field	2	P2
+Field	1	P1
+Field	0	P0
+EndSysreg
+
 Sysreg	ICC_CR0_EL1	3	1	12	0	1
 Res0	63:39
 Field	38	PID
@@ -4567,6 +4616,42 @@ Field	31:16	PhyPARTID29
 Field	15:0	PhyPARTID28
 EndSysreg
 
+Sysreg	ICH_APR_EL2	3	4	12	8	4
+Res0	63:32
+Field	31	P31
+Field	30	P30
+Field	29	P29
+Field	28	P28
+Field	27	P27
+Field	26	P26
+Field	25	P25
+Field	24	P24
+Field	23	P23
+Field	22	P22
+Field	21	P21
+Field	20	P20
+Field	19	P19
+Field	18	P18
+Field	17	P17
+Field	16	P16
+Field	15	P15
+Field	14	P14
+Field	13	P13
+Field	12	P12
+Field	11	P11
+Field	10	P10
+Field	9	P9
+Field	8	P8
+Field	7	P7
+Field	6	P6
+Field	5	P5
+Field	4	P4
+Field	3	P3
+Field	2	P2
+Field	1	P1
+Field	0	P0
+EndSysreg
+
 Sysreg	ICH_HFGRTR_EL2	3	4	12	9	4
 Res0	63:21
 Field	20	ICC_PPI_ACTIVERn_EL1
@@ -4615,6 +4700,306 @@ Field	1	GICCDDIS
 Field	0	GICCDEN
 EndSysreg
 
+SysregFields	ICH_PPI_DVIRx_EL2
+Field	63	DVI63
+Field	62	DVI62
+Field	61	DVI61
+Field	60	DVI60
+Field	59	DVI59
+Field	58	DVI58
+Field	57	DVI57
+Field	56	DVI56
+Field	55	DVI55
+Field	54	DVI54
+Field	53	DVI53
+Field	52	DVI52
+Field	51	DVI51
+Field	50	DVI50
+Field	49	DVI49
+Field	48	DVI48
+Field	47	DVI47
+Field	46	DVI46
+Field	45	DVI45
+Field	44	DVI44
+Field	43	DVI43
+Field	42	DVI42
+Field	41	DVI41
+Field	40	DVI40
+Field	39	DVI39
+Field	38	DVI38
+Field	37	DVI37
+Field	36	DVI36
+Field	35	DVI35
+Field	34	DVI34
+Field	33	DVI33
+Field	32	DVI32
+Field	31	DVI31
+Field	30	DVI30
+Field	29	DVI29
+Field	28	DVI28
+Field	27	DVI27
+Field	26	DVI26
+Field	25	DVI25
+Field	24	DVI24
+Field	23	DVI23
+Field	22	DVI22
+Field	21	DVI21
+Field	20	DVI20
+Field	19	DVI19
+Field	18	DVI18
+Field	17	DVI17
+Field	16	DVI16
+Field	15	DVI15
+Field	14	DVI14
+Field	13	DVI13
+Field	12	DVI12
+Field	11	DVI11
+Field	10	DVI10
+Field	9	DVI9
+Field	8	DVI8
+Field	7	DVI7
+Field	6	DVI6
+Field	5	DVI5
+Field	4	DVI4
+Field	3	DVI3
+Field	2	DVI2
+Field	1	DVI1
+Field	0	DVI0
+EndSysregFields
+
+Sysreg	ICH_PPI_DVIR0_EL2	3	4	12	10	0
+Fields ICH_PPI_DVIx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_DVIR1_EL2	3	4	12	10	1
+Fields ICH_PPI_DVIx_EL2
+EndSysreg
+
+SysregFields	ICH_PPI_ENABLERx_EL2
+Field	63	EN63
+Field	62	EN62
+Field	61	EN61
+Field	60	EN60
+Field	59	EN59
+Field	58	EN58
+Field	57	EN57
+Field	56	EN56
+Field	55	EN55
+Field	54	EN54
+Field	53	EN53
+Field	52	EN52
+Field	51	EN51
+Field	50	EN50
+Field	49	EN49
+Field	48	EN48
+Field	47	EN47
+Field	46	EN46
+Field	45	EN45
+Field	44	EN44
+Field	43	EN43
+Field	42	EN42
+Field	41	EN41
+Field	40	EN40
+Field	39	EN39
+Field	38	EN38
+Field	37	EN37
+Field	36	EN36
+Field	35	EN35
+Field	34	EN34
+Field	33	EN33
+Field	32	EN32
+Field	31	EN31
+Field	30	EN30
+Field	29	EN29
+Field	28	EN28
+Field	27	EN27
+Field	26	EN26
+Field	25	EN25
+Field	24	EN24
+Field	23	EN23
+Field	22	EN22
+Field	21	EN21
+Field	20	EN20
+Field	19	EN19
+Field	18	EN18
+Field	17	EN17
+Field	16	EN16
+Field	15	EN15
+Field	14	EN14
+Field	13	EN13
+Field	12	EN12
+Field	11	EN11
+Field	10	EN10
+Field	9	EN9
+Field	8	EN8
+Field	7	EN7
+Field	6	EN6
+Field	5	EN5
+Field	4	EN4
+Field	3	EN3
+Field	2	EN2
+Field	1	EN1
+Field	0	EN0
+EndSysregFields
+
+Sysreg	ICH_PPI_ENABLER0_EL2	3	4	12	10	2
+Fields ICH_PPI_ENABLERx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_ENABLER1_EL2	3	4	12	10	3
+Fields ICH_PPI_ENABLERx_EL2
+EndSysreg
+
+SysregFields	ICH_PPI_PENDRx_EL2
+Field	63	PEND63
+Field	62	PEND62
+Field	61	PEND61
+Field	60	PEND60
+Field	59	PEND59
+Field	58	PEND58
+Field	57	PEND57
+Field	56	PEND56
+Field	55	PEND55
+Field	54	PEND54
+Field	53	PEND53
+Field	52	PEND52
+Field	51	PEND51
+Field	50	PEND50
+Field	49	PEND49
+Field	48	PEND48
+Field	47	PEND47
+Field	46	PEND46
+Field	45	PEND45
+Field	44	PEND44
+Field	43	PEND43
+Field	42	PEND42
+Field	41	PEND41
+Field	40	PEND40
+Field	39	PEND39
+Field	38	PEND38
+Field	37	PEND37
+Field	36	PEND36
+Field	35	PEND35
+Field	34	PEND34
+Field	33	PEND33
+Field	32	PEND32
+Field	31	PEND31
+Field	30	PEND30
+Field	29	PEND29
+Field	28	PEND28
+Field	27	PEND27
+Field	26	PEND26
+Field	25	PEND25
+Field	24	PEND24
+Field	23	PEND23
+Field	22	PEND22
+Field	21	PEND21
+Field	20	PEND20
+Field	19	PEND19
+Field	18	PEND18
+Field	17	PEND17
+Field	16	PEND16
+Field	15	PEND15
+Field	14	PEND14
+Field	13	PEND13
+Field	12	PEND12
+Field	11	PEND11
+Field	10	PEND10
+Field	9	PEND9
+Field	8	PEND8
+Field	7	PEND7
+Field	6	PEND6
+Field	5	PEND5
+Field	4	PEND4
+Field	3	PEND3
+Field	2	PEND2
+Field	1	PEND1
+Field	0	PEND0
+EndSysregFields
+
+Sysreg	ICH_PPI_PENDR0_EL2	3	4	12	10	4
+Fields ICH_PPI_PENDRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PENDR1_EL2	3	4	12	10	5
+Fields ICH_PPI_PENDRx_EL2
+EndSysreg
+
+SysregFields	ICH_PPI_ACTIVERx_EL2
+Field	63	ACTIVE63
+Field	62	ACTIVE62
+Field	61	ACTIVE61
+Field	60	ACTIVE60
+Field	59	ACTIVE59
+Field	58	ACTIVE58
+Field	57	ACTIVE57
+Field	56	ACTIVE56
+Field	55	ACTIVE55
+Field	54	ACTIVE54
+Field	53	ACTIVE53
+Field	52	ACTIVE52
+Field	51	ACTIVE51
+Field	50	ACTIVE50
+Field	49	ACTIVE49
+Field	48	ACTIVE48
+Field	47	ACTIVE47
+Field	46	ACTIVE46
+Field	45	ACTIVE45
+Field	44	ACTIVE44
+Field	43	ACTIVE43
+Field	42	ACTIVE42
+Field	41	ACTIVE41
+Field	40	ACTIVE40
+Field	39	ACTIVE39
+Field	38	ACTIVE38
+Field	37	ACTIVE37
+Field	36	ACTIVE36
+Field	35	ACTIVE35
+Field	34	ACTIVE34
+Field	33	ACTIVE33
+Field	32	ACTIVE32
+Field	31	ACTIVE31
+Field	30	ACTIVE30
+Field	29	ACTIVE29
+Field	28	ACTIVE28
+Field	27	ACTIVE27
+Field	26	ACTIVE26
+Field	25	ACTIVE25
+Field	24	ACTIVE24
+Field	23	ACTIVE23
+Field	22	ACTIVE22
+Field	21	ACTIVE21
+Field	20	ACTIVE20
+Field	19	ACTIVE19
+Field	18	ACTIVE18
+Field	17	ACTIVE17
+Field	16	ACTIVE16
+Field	15	ACTIVE15
+Field	14	ACTIVE14
+Field	13	ACTIVE13
+Field	12	ACTIVE12
+Field	11	ACTIVE11
+Field	10	ACTIVE10
+Field	9	ACTIVE9
+Field	8	ACTIVE8
+Field	7	ACTIVE7
+Field	6	ACTIVE6
+Field	5	ACTIVE5
+Field	4	ACTIVE4
+Field	3	ACTIVE3
+Field	2	ACTIVE2
+Field	1	ACTIVE1
+Field	0	ACTIVE0
+EndSysregFields
+
+Sysreg	ICH_PPI_ACTIVER0_EL2	3	4	12	10	6
+Fields ICH_PPI_ACTIVERx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_ACTIVER1_EL2	3	4	12	10	7
+Fields ICH_PPI_ACTIVERx_EL2
+EndSysreg
+
 Sysreg	ICH_HCR_EL2	3	4	12	11	0
 Res0	63:32
 Field	31:27	EOIcount
@@ -4669,6 +5054,18 @@ Field	1	V3
 Field	0	En
 EndSysreg
 
+Sysreg	ICH_CONTEXTR_EL2	3	4	12	11	6
+Field	63	V
+Field	62	F
+Field	61	IRICHPPIDIS
+Field	60	DB
+Field	59:55	DBPM
+Res0	54:48
+Field	47:32	VPE
+Res0	31:16
+Field	15:0	VM
+EndSysreg
+
 Sysreg	ICH_VMCR_EL2	3	4	12	11	7
 Prefix	FEAT_GCIE
 Res0	63:32
@@ -4690,6 +5087,89 @@ Field	1	VENG1
 Field	0	VENG0
 EndSysreg
 
+SysregFields	ICH_PPI_PRIORITYRx_EL2
+Res0	63:61
+Field	60:56	Priority7
+Res0	55:53
+Field	52:48	Priority6
+Res0	47:45
+Field	44:40	Priority5
+Res0	39:37
+Field	36:32	Priority4
+Res0	31:29
+Field	28:24	Priority3
+Res0	23:21
+Field	20:16	Priority2
+Res0	15:13
+Field	12:8	Priority1
+Res0	7:5
+Field	4:0	Priority0
+EndSysregFields
+
+Sysreg	ICH_PPI_PRIORITYR0_EL2	3	4	12	14	0
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR1_EL2	3	4	12	14	1
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR2_EL2	3	4	12	14	2
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR3_EL2	3	4	12	14	3
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR4_EL2	3	4	12	14	4
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR5_EL2	3	4	12	14	5
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR6_EL2	3	4	12	14	6
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR7_EL2	3	4	12	14	7
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR8_EL2	3	4	12	15	0
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR9_EL2	3	4	12	15	1
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR10_EL2	3	4	12	15	2
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR11_EL2	3	4	12	15	3
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR12_EL2	3	4	12	15	4
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR13_EL2	3	4	12	15	5
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR14_EL2	3	4	12	15	6
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR15_EL2	3	4	12	15	7
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
 Sysreg	CONTEXTIDR_EL2	3	4	13	0	1
 Fields	CONTEXTIDR_ELx
 EndSysreg
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:41 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:41 +0000
Subject: [PATCH 18/32] KVM: arm64: gic-v5: Check for pending PPIs
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-19-sascha.bischoff@arm.com>

This change allows KVM to check for pending PPI interrupts. This has
two main components:

First of all, the effective priority mask is calculated.  This is a
combination of the priority mask in the VPEs ICC_PCR_EL1.PRIORITY and
the currently running priority as determined from the VPE's
ICH_APR_EL1. If an interrupt's prioirity is greater than or equal to
the effective priority mask, it can be signalled. Otherwise, it
cannot.

Secondly, any Enabled and Pending PPIs must be checked against this
compound priority mask. The reqires the PPI priorities to by synced
back to the KVM shadow state - this is skipped in general operation as
it isn't required and is rather expensive. If any Enabled and Pending
PPIs are of sufficient priority to be signalled, then there are
pending PPIs. Else, there are not.  This ensures that a VPE is not
woken when it cannot actually process the pending interrupts.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/vgic/vgic-v5.c | 123 ++++++++++++++++++++++++++++++++++
 arch/arm64/kvm/vgic/vgic.c    |  10 ++-
 arch/arm64/kvm/vgic/vgic.h    |   1 +
 3 files changed, 131 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index d54595fbf4586..35740e88b3591 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -54,6 +54,31 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
 	return 0;
 }
 
+static u32 vgic_v5_get_effective_priority_mask(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+	unsigned highest_ap, priority_mask;
+
+	/*
+	 * Counting the number of trailing zeros gives the current
+	 * active priority. Explicitly use the 32-bit version here as
+	 * we have 32 priorities. 0x20 then means that there are no
+	 * active priorities.
+	 */
+	highest_ap = __builtin_ctz(cpu_if->vgic_apr);
+
+	/*
+	 * An interrupt is of sufficient priority if it is equal to or
+	 * greater than the priority mask. Add 1 to the priority mask
+	 * (i.e., lower priority) to match the APR logic before taking
+	 * the min. This gives us the lowest priority that is masked.
+	 */
+	priority_mask = FIELD_GET(FEAT_GCIE_ICH_VMCR_EL2_VPMR, cpu_if->vgic_vmcr);
+	priority_mask = min(highest_ap, priority_mask + 1);
+
+	return priority_mask;
+}
+
 static bool vgic_v5_ppi_set_pending_state(struct kvm_vcpu *vcpu,
 					  struct vgic_irq *irq)
 {
@@ -121,6 +146,104 @@ void vgic_v5_set_ppi_ops(struct vgic_irq *irq)
 	irq->ops = &vgic_v5_ppi_irq_ops;
 }
 
+
+/*
+ * Sync back the PPI priorities to the vgic_irq shadow state
+ */
+static void vgic_v5_sync_ppi_priorities(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+	unsigned long flags;
+	int i, reg;
+
+	/* We have 16 PPI Priority regs */
+	for (reg = 0; reg < 16; reg++) {
+		const unsigned long priorityr = cpu_if->vgic_ppi_priorityr[reg];
+
+		for (i = 0; i < 8; ++i) {
+			struct vgic_irq *irq;
+			u32 intid;
+			u8 priority;
+
+			priority = (priorityr >> (i * 8)) & 0x1f;
+
+			intid = FIELD_PREP(GICV5_HWIRQ_TYPE, GICV5_HWIRQ_TYPE_PPI);
+			intid |= FIELD_PREP(GICV5_HWIRQ_ID, reg * 8 + i);
+
+			irq = vgic_get_vcpu_irq(vcpu, intid);
+			raw_spin_lock_irqsave(&irq->irq_lock, flags);
+
+			irq->priority = priority;
+
+			raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
+			vgic_put_irq(vcpu->kvm, irq);
+		}
+	}
+}
+
+bool vgic_v5_has_pending_ppi(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+	unsigned long flags;
+	int i, reg;
+	unsigned int priority_mask;
+
+	/* If no pending bits are set, exit early */
+	if (likely(!cpu_if->vgic_ppi_pendr[0] && !cpu_if->vgic_ppi_pendr[1]))
+		return false;
+
+	priority_mask = vgic_v5_get_effective_priority_mask(vcpu);
+
+	/* If the combined priority mask is 0, nothing can be signalled! */
+	if (!priority_mask)
+		return false;
+
+	/* The shadow priority is only updated on demand, sync it across first */
+	vgic_v5_sync_ppi_priorities(vcpu);
+
+	for (reg = 0; reg < 2; reg++) {
+		unsigned long possible_bits;
+		const unsigned long enabler = cpu_if->vgic_ich_ppi_enabler_exit[reg];
+		const unsigned long pendr = cpu_if->vgic_ppi_pendr_exit[reg];
+		bool has_pending = false;
+
+		/* Check all interrupts that are enabled and pending */
+		possible_bits = enabler & pendr;
+
+		/*
+		 * Optimisation: pending and enabled with no active priorities
+		 */
+		if (possible_bits && priority_mask > 0x1f)
+			return true;
+
+		for_each_set_bit(i, &possible_bits, 64) {
+			struct vgic_irq *irq;
+			u32 intid;
+
+			intid = FIELD_PREP(GICV5_HWIRQ_TYPE, GICV5_HWIRQ_TYPE_PPI);
+			intid |= FIELD_PREP(GICV5_HWIRQ_ID, reg * 64 + i);
+
+			irq = vgic_get_vcpu_irq(vcpu, intid);
+			raw_spin_lock_irqsave(&irq->irq_lock, flags);
+
+			/*
+			 * We know that the interrupt is enabled and pending, so
+			 * only check the priority.
+			 */
+			if (irq->priority <= priority_mask)
+				has_pending = true;
+
+			raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
+			vgic_put_irq(vcpu->kvm, irq);
+
+			if (has_pending)
+				return true;
+		}
+	}
+
+	return false;
+}
+
 /*
  * Detect any PPIs state changes, and propagate the state with KVM's
  * shadow structures.
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index e534876656ca7..5d18a03cc11d5 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -1174,11 +1174,15 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
 	unsigned long flags;
 	struct vgic_vmcr vmcr;
 
-	if (!vcpu->kvm->arch.vgic.enabled)
+	if (!vcpu->kvm->arch.vgic.enabled && !vgic_is_v5(vcpu->kvm))
 		return false;
 
-	if (vcpu->arch.vgic_cpu.vgic_v3.its_vpe.pending_last)
-		return true;
+	if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5) {
+		return vgic_v5_has_pending_ppi(vcpu);
+	} else {
+		if (vcpu->arch.vgic_cpu.vgic_v3.its_vpe.pending_last)
+			return true;
+	}
 
 	vgic_get_vmcr(vcpu, &vmcr);
 
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index 5a77318ddb87a..4b3a1e7ca3fb4 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -387,6 +387,7 @@ void vgic_debug_destroy(struct kvm *kvm);
 int vgic_v5_probe(const struct gic_kvm_info *info);
 void vgic_v5_set_ppi_ops(struct vgic_irq *irq);
 int vgic_v5_set_ppi_dvi(struct kvm_vcpu *vcpu, u32 irq, bool dvi);
+bool vgic_v5_has_pending_ppi(struct kvm_vcpu *vcpu);
 void vgic_v5_flush_ppi_state(struct kvm_vcpu *vcpu);
 void vgic_v5_fold_irq_state(struct kvm_vcpu *vcpu);
 void vgic_v5_load(struct kvm_vcpu *vcpu);
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:39 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:39 +0000
Subject: [PATCH 13/32] KVM: arm64: gic-v5: Add vgic-v5 save/restore hyp
 interface
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-14-sascha.bischoff@arm.com>

Introduce hyp functions to save/restore the following GICv5 state:

* ICC_ICSR_EL1
* ICH_APR_EL2
* ICH_PPI_ACTIVERx_EL2
* ICH_PPI_DVIRx_EL2
* ICH_PPI_ENABLERx_EL2
* ICH_PPI_PENDRRx_EL2
* ICH_PPI_PRIORITYRx_EL2
* ICH_VMCR_EL2

All of these are saved/restored to/from the KVM vgic_v5 CPUIF shadow
state.

The ICSR must be save/restored as this register is shared between host
and guest. Therefore, to avoid leaking host state to the guest, this
must be saved and restored. Moreover, as this can by used by the host
at any time, it must be save/restored eagerly. Note: the host state is
not preserved as the host should only use this register when
preemption is disabled.

As part of restoring the ICH_VMCR_EL2 and ICH_APR_EL2, GICv3-compat
mode is also disabled by setting the ICH_VCTLR_EL2.V3 bit to 0. The
correspoinding GICv3-compat mode enable is part of the VMCR & APR
restore for a GICv3 guest as it only takes effect when actually
running a guest.

Co-authored-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/include/asm/kvm_asm.h   |   4 +
 arch/arm64/include/asm/kvm_hyp.h   |   8 ++
 arch/arm64/kvm/hyp/nvhe/Makefile   |   2 +-
 arch/arm64/kvm/hyp/nvhe/hyp-main.c |  32 ++++++
 arch/arm64/kvm/hyp/vgic-v5.c       | 155 +++++++++++++++++++++++++++++
 arch/arm64/kvm/hyp/vhe/Makefile    |   2 +-
 include/kvm/arm_vgic.h             |  28 ++++++
 7 files changed, 229 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm64/kvm/hyp/vgic-v5.c

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index a1ad12c72ebf1..5f669299fb956 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -89,6 +89,10 @@ enum __kvm_host_smccc_func {
 	__KVM_HOST_SMCCC_FUNC___pkvm_vcpu_load,
 	__KVM_HOST_SMCCC_FUNC___pkvm_vcpu_put,
 	__KVM_HOST_SMCCC_FUNC___pkvm_tlb_flush_vmid,
+	__KVM_HOST_SMCCC_FUNC___vgic_v5_save_vmcr_aprs,
+	__KVM_HOST_SMCCC_FUNC___vgic_v5_restore_vmcr_aprs,
+	__KVM_HOST_SMCCC_FUNC___vgic_v5_save_ppi_state,
+	__KVM_HOST_SMCCC_FUNC___vgic_v5_restore_ppi_state,
 };
 
 #define DECLARE_KVM_VHE_SYM(sym)	extern char sym[]
diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index 76ce2b94bd97e..f6cf59a719ac6 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -87,6 +87,14 @@ void __vgic_v3_save_aprs(struct vgic_v3_cpu_if *cpu_if);
 void __vgic_v3_restore_vmcr_aprs(struct vgic_v3_cpu_if *cpu_if);
 int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);
 
+/* GICv5 */
+void __vgic_v5_save_vmcr_aprs(struct vgic_v5_cpu_if *cpu_if);
+void __vgic_v5_restore_vmcr_aprs(struct vgic_v5_cpu_if *cpu_if);
+void __vgic_v5_save_ppi_state(struct vgic_v5_cpu_if *cpu_if);
+void __vgic_v5_restore_ppi_state(struct vgic_v5_cpu_if *cpu_if);
+void __vgic_v5_save_icsr(struct vgic_v5_cpu_if *cpu_if);
+void __vgic_v5_restore_icsr(struct vgic_v5_cpu_if *cpu_if);
+
 #ifdef __KVM_NVHE_HYPERVISOR__
 void __timer_enable_traps(struct kvm_vcpu *vcpu);
 void __timer_disable_traps(struct kvm_vcpu *vcpu);
diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile
index a244ec25f8c5b..d860fbe9bc476 100644
--- a/arch/arm64/kvm/hyp/nvhe/Makefile
+++ b/arch/arm64/kvm/hyp/nvhe/Makefile
@@ -26,7 +26,7 @@ hyp-obj-y := timer-sr.o sysreg-sr.o debug-sr.o switch.o tlb.o hyp-init.o host.o
 	 hyp-main.o hyp-smp.o psci-relay.o early_alloc.o page_alloc.o \
 	 cache.o setup.o mm.o mem_protect.o sys_regs.o pkvm.o stacktrace.o ffa.o
 hyp-obj-y += ../vgic-v3-sr.o ../aarch32.o ../vgic-v2-cpuif-proxy.o ../entry.o \
-	 ../fpsimd.o ../hyp-entry.o ../exception.o ../pgtable.o
+	 ../fpsimd.o ../hyp-entry.o ../exception.o ../pgtable.o ../vgic-v5.o
 hyp-obj-y += ../../../kernel/smccc-call.o
 hyp-obj-$(CONFIG_LIST_HARDENED) += list_debug.o
 hyp-obj-y += $(lib-objs)
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index a7c689152f686..6bc5a4f75fd01 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -586,6 +586,34 @@ static void handle___pkvm_teardown_vm(struct kvm_cpu_context *host_ctxt)
 	cpu_reg(host_ctxt, 1) = __pkvm_teardown_vm(handle);
 }
 
+static void handle___vgic_v5_save_vmcr_aprs(struct kvm_cpu_context *host_ctxt)
+{
+	DECLARE_REG(struct vgic_v5_cpu_if *, cpu_if, host_ctxt, 1);
+
+	__vgic_v5_save_vmcr_aprs(kern_hyp_va(cpu_if));
+}
+
+static void handle___vgic_v5_restore_vmcr_aprs(struct kvm_cpu_context *host_ctxt)
+{
+	DECLARE_REG(struct vgic_v5_cpu_if *, cpu_if, host_ctxt, 1);
+
+	__vgic_v5_restore_vmcr_aprs(kern_hyp_va(cpu_if));
+}
+
+static void handle___vgic_v5_save_ppi_state(struct kvm_cpu_context *host_ctxt)
+{
+	DECLARE_REG(struct vgic_v5_cpu_if *, cpu_if, host_ctxt, 1);
+
+	__vgic_v5_save_ppi_state(kern_hyp_va(cpu_if));
+}
+
+static void handle___vgic_v5_restore_ppi_state(struct kvm_cpu_context *host_ctxt)
+{
+	DECLARE_REG(struct vgic_v5_cpu_if *, cpu_if, host_ctxt, 1);
+
+	__vgic_v5_restore_ppi_state(kern_hyp_va(cpu_if));
+}
+
 typedef void (*hcall_t)(struct kvm_cpu_context *);
 
 #define HANDLE_FUNC(x)	[__KVM_HOST_SMCCC_FUNC_##x] = (hcall_t)handle_##x
@@ -627,6 +655,10 @@ static const hcall_t host_hcall[] = {
 	HANDLE_FUNC(__pkvm_vcpu_load),
 	HANDLE_FUNC(__pkvm_vcpu_put),
 	HANDLE_FUNC(__pkvm_tlb_flush_vmid),
+	HANDLE_FUNC(__vgic_v5_save_vmcr_aprs),
+	HANDLE_FUNC(__vgic_v5_restore_vmcr_aprs),
+	HANDLE_FUNC(__vgic_v5_save_ppi_state),
+	HANDLE_FUNC(__vgic_v5_restore_ppi_state),
 };
 
 static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
diff --git a/arch/arm64/kvm/hyp/vgic-v5.c b/arch/arm64/kvm/hyp/vgic-v5.c
new file mode 100644
index 0000000000000..11b67ae09e326
--- /dev/null
+++ b/arch/arm64/kvm/hyp/vgic-v5.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2025 - ARM Ltd
+ */
+
+#include <hyp/adjust_pc.h>
+
+#include <linux/compiler.h>
+#include <linux/irqchip/arm-gic-v5.h>
+#include <linux/kvm_host.h>
+
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_hyp.h>
+#include <asm/kvm_mmu.h>
+
+void __vgic_v5_save_vmcr_aprs(struct vgic_v5_cpu_if *cpu_if)
+{
+	cpu_if->vgic_vmcr = read_sysreg_s(SYS_ICH_VMCR_EL2);
+	cpu_if->vgic_apr = read_sysreg_s(SYS_ICH_APR_EL2);
+}
+
+static void  __vgic_v5_compat_mode_disable(void)
+{
+	sysreg_clear_set_s(SYS_ICH_VCTLR_EL2, ICH_VCTLR_EL2_V3, 0);
+	isb();
+}
+
+void __vgic_v5_restore_vmcr_aprs(struct vgic_v5_cpu_if *cpu_if)
+{
+	__vgic_v5_compat_mode_disable();
+
+	write_sysreg_s(cpu_if->vgic_vmcr, SYS_ICH_VMCR_EL2);
+	write_sysreg_s(cpu_if->vgic_apr, SYS_ICH_APR_EL2);
+}
+
+void __vgic_v5_save_ppi_state(struct vgic_v5_cpu_if *cpu_if)
+{
+	cpu_if->vgic_ppi_activer_exit[0] =
+		read_sysreg_s(SYS_ICH_PPI_ACTIVER0_EL2);
+	cpu_if->vgic_ppi_activer_exit[1] =
+		read_sysreg_s(SYS_ICH_PPI_ACTIVER1_EL2);
+
+	cpu_if->vgic_ich_ppi_enabler_exit[0] =
+		read_sysreg_s(SYS_ICH_PPI_ENABLER0_EL2);
+	cpu_if->vgic_ich_ppi_enabler_exit[1] =
+		read_sysreg_s(SYS_ICH_PPI_ENABLER1_EL2);
+
+	cpu_if->vgic_ppi_pendr_exit[0] = read_sysreg_s(SYS_ICH_PPI_PENDR0_EL2);
+	cpu_if->vgic_ppi_pendr_exit[1] = read_sysreg_s(SYS_ICH_PPI_PENDR1_EL2);
+
+	cpu_if->vgic_ppi_priorityr[0] =
+		read_sysreg_s(SYS_ICH_PPI_PRIORITYR0_EL2);
+	cpu_if->vgic_ppi_priorityr[1] =
+		read_sysreg_s(SYS_ICH_PPI_PRIORITYR1_EL2);
+	cpu_if->vgic_ppi_priorityr[2] =
+		read_sysreg_s(SYS_ICH_PPI_PRIORITYR2_EL2);
+	cpu_if->vgic_ppi_priorityr[3] =
+		read_sysreg_s(SYS_ICH_PPI_PRIORITYR3_EL2);
+	cpu_if->vgic_ppi_priorityr[4] =
+		read_sysreg_s(SYS_ICH_PPI_PRIORITYR4_EL2);
+	cpu_if->vgic_ppi_priorityr[5] =
+		read_sysreg_s(SYS_ICH_PPI_PRIORITYR5_EL2);
+	cpu_if->vgic_ppi_priorityr[6] =
+		read_sysreg_s(SYS_ICH_PPI_PRIORITYR6_EL2);
+	cpu_if->vgic_ppi_priorityr[7] =
+		read_sysreg_s(SYS_ICH_PPI_PRIORITYR7_EL2);
+	cpu_if->vgic_ppi_priorityr[8] =
+		read_sysreg_s(SYS_ICH_PPI_PRIORITYR8_EL2);
+	cpu_if->vgic_ppi_priorityr[9] =
+		read_sysreg_s(SYS_ICH_PPI_PRIORITYR9_EL2);
+	cpu_if->vgic_ppi_priorityr[10] =
+		read_sysreg_s(SYS_ICH_PPI_PRIORITYR10_EL2);
+	cpu_if->vgic_ppi_priorityr[11] =
+		read_sysreg_s(SYS_ICH_PPI_PRIORITYR11_EL2);
+	cpu_if->vgic_ppi_priorityr[12] =
+		read_sysreg_s(SYS_ICH_PPI_PRIORITYR12_EL2);
+	cpu_if->vgic_ppi_priorityr[13] =
+		read_sysreg_s(SYS_ICH_PPI_PRIORITYR13_EL2);
+	cpu_if->vgic_ppi_priorityr[14] =
+		read_sysreg_s(SYS_ICH_PPI_PRIORITYR14_EL2);
+	cpu_if->vgic_ppi_priorityr[15] =
+		read_sysreg_s(SYS_ICH_PPI_PRIORITYR15_EL2);
+
+	/* Now that we are done, disable DVI */
+	write_sysreg_s(0, SYS_ICH_PPI_DVIR0_EL2);
+	write_sysreg_s(0, SYS_ICH_PPI_DVIR1_EL2);
+}
+
+void __vgic_v5_restore_ppi_state(struct vgic_v5_cpu_if *cpu_if)
+{
+	 /* Now enable DVI so that the guest's interrupt config takes over */
+	 write_sysreg_s(cpu_if->vgic_ppi_dvir[0], SYS_ICH_PPI_DVIR0_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_dvir[1], SYS_ICH_PPI_DVIR1_EL2);
+
+	 write_sysreg_s(cpu_if->vgic_ppi_activer_entry[0],
+			SYS_ICH_PPI_ACTIVER0_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_activer_entry[1],
+			SYS_ICH_PPI_ACTIVER1_EL2);
+
+	 write_sysreg_s(cpu_if->vgic_ich_ppi_enabler_entry[0],
+			SYS_ICH_PPI_ENABLER0_EL2);
+	 write_sysreg_s(cpu_if->vgic_ich_ppi_enabler_entry[1],
+			SYS_ICH_PPI_ENABLER1_EL2);
+
+	 /* Update the pending state of the NON-DVI'd PPIs, only */
+	 write_sysreg_s(cpu_if->vgic_ppi_pendr_entry[0] &
+				~cpu_if->vgic_ppi_dvir[0],
+			SYS_ICH_PPI_PENDR0_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_pendr_entry[1] &
+				~cpu_if->vgic_ppi_dvir[1],
+			SYS_ICH_PPI_PENDR1_EL2);
+
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[0],
+			SYS_ICH_PPI_PRIORITYR0_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[1],
+			SYS_ICH_PPI_PRIORITYR1_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[2],
+			SYS_ICH_PPI_PRIORITYR2_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[3],
+			SYS_ICH_PPI_PRIORITYR3_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[4],
+			SYS_ICH_PPI_PRIORITYR4_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[5],
+			SYS_ICH_PPI_PRIORITYR5_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[6],
+			SYS_ICH_PPI_PRIORITYR6_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[7],
+			SYS_ICH_PPI_PRIORITYR7_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[8],
+			SYS_ICH_PPI_PRIORITYR8_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[9],
+			SYS_ICH_PPI_PRIORITYR9_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[10],
+			SYS_ICH_PPI_PRIORITYR10_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[11],
+			SYS_ICH_PPI_PRIORITYR11_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[12],
+			SYS_ICH_PPI_PRIORITYR12_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[13],
+			SYS_ICH_PPI_PRIORITYR13_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[14],
+			SYS_ICH_PPI_PRIORITYR14_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[15],
+			SYS_ICH_PPI_PRIORITYR15_EL2);
+}
+
+void __vgic_v5_save_icsr(struct vgic_v5_cpu_if *cpu_if)
+{
+	cpu_if->vgic_icsr = read_sysreg_s(SYS_ICC_ICSR_EL1);
+}
+
+void __vgic_v5_restore_icsr(struct vgic_v5_cpu_if *cpu_if)
+{
+	write_sysreg_s(cpu_if->vgic_icsr, SYS_ICC_ICSR_EL1);
+}
diff --git a/arch/arm64/kvm/hyp/vhe/Makefile b/arch/arm64/kvm/hyp/vhe/Makefile
index afc4aed9231ac..fcf5e68ab591c 100644
--- a/arch/arm64/kvm/hyp/vhe/Makefile
+++ b/arch/arm64/kvm/hyp/vhe/Makefile
@@ -10,4 +10,4 @@ CFLAGS_switch.o += -Wno-override-init
 
 obj-y := timer-sr.o sysreg-sr.o debug-sr.o switch.o tlb.o
 obj-y += ../vgic-v3-sr.o ../aarch32.o ../vgic-v2-cpuif-proxy.o ../entry.o \
-	 ../fpsimd.o ../hyp-entry.o ../exception.o
+	 ../fpsimd.o ../hyp-entry.o ../exception.o ../vgic-v5.o
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index fbbaef4ad2114..525c8b83e83c9 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -359,7 +359,35 @@ struct vgic_v3_cpu_if {
 };
 
 struct vgic_v5_cpu_if {
+	u64	vgic_apr;
+	u64	vgic_vmcr;
+
+	/* PPI register state */
 	u64	vgic_ppi_hmr[2];
+	u64	vgic_ppi_dvir[2];
+	u64	vgic_ppi_priorityr[16];
+
+	/* The pending state of the guest. This is merged with the exit state */
+	u64	vgic_ppi_pendr[2];
+
+	/* The state flushed to the regs when entering the guest */
+	u64	vgic_ppi_activer_entry[2];
+	u64	vgic_ich_ppi_enabler_entry[2];
+	u64	vgic_ppi_pendr_entry[2];
+
+	/* The saved state of the regs when leaving the guest */
+	u64	vgic_ppi_activer_exit[2];
+	u64	vgic_ich_ppi_enabler_exit[2];
+	u64	vgic_ppi_pendr_exit[2];
+
+	/*
+	 * The ICSR is re-used across host and guest, and hence it needs to be
+	 * saved/restored. Only one copy is required as the host should block
+	 * preemption between executing GIC CDRCFG and acccessing the
+	 * ICC_ICSR_EL1. A guest, of course, can never guarantee this, and hence
+	 * it is the hyp's responsibility to keep the state constistent.
+	 */
+	u64	vgic_icsr;
 };
 
 struct vgic_cpu {
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:38 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:38 +0000
Subject: [PATCH 10/32] KVM: arm64: gic-v5: Add emulation for ICC_IAFFID_EL1
 accesses
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-11-sascha.bischoff@arm.com>

GICv5 doesn't include an ICV_IAFFIDR_EL1 or ICH_IAFFIDR_EL2 for
providing the IAFFID to the guest. A guest access to the
ICH_IAFFIDR_EL1 must therefore be trapped and emulated to avoid the
guest accessing the host's ICC_IAFFIDR_EL1.

For GICv5, the VPE ID corresponds to the virtual IAFFID for the
purposes of specifying the affinity of virtual interrupts. The VPE ID
is the index into the VPE Table, which will be the same as the
vcpu->vcpu_id once the various GICv5 VM tables are introduced. At this
stage, said VM tables have yet to be introduced as they are not
required for PPI support. Moreover, the IAFFID should go largely
unused by any guest using just PPIs as they are not routable to a
different PE. That said, we still need to trap and emulate the guest's
accesses to avoid leaking host state into the guest.

The virtual IAFFID is provided to the guest when it reads
ICC_IAFFID_EL1 (which always traps back to the hypervisor). Writes are
rightly ignored.

The trapping for the ICC_IAFFIDR_EL2 is always enabled when in a guest
context.

Co-authored-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/config.c   | 10 +++++++++-
 arch/arm64/kvm/sys_regs.c | 19 +++++++++++++++++++
 2 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index 57ef67f718113..cbdd8ac90f4d0 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -1582,6 +1582,14 @@ static void __compute_hdfgwtr(struct kvm_vcpu *vcpu)
 		*vcpu_fgt(vcpu, HDFGWTR_EL2) |= HDFGWTR_EL2_MDSCR_EL1;
 }
 
+static void __compute_ich_hfgrtr(struct kvm_vcpu *vcpu)
+{
+	__compute_fgt(vcpu, ICH_HFGRTR_EL2);
+
+	/* ICC_IAFFIDR_EL1 *always* needs to be trapped when running a guest */
+	*vcpu_fgt(vcpu, ICH_HFGRTR_EL2) &= ~ICH_HFGRTR_EL2_ICC_IAFFIDR_EL1;
+}
+
 void kvm_vcpu_load_fgt(struct kvm_vcpu *vcpu)
 {
 	if (!cpus_have_final_cap(ARM64_HAS_FGT))
@@ -1607,7 +1615,7 @@ void kvm_vcpu_load_fgt(struct kvm_vcpu *vcpu)
 	if (!cpus_have_final_cap(ARM64_HAS_GICV5_CPUIF))
 		return;
 
-	__compute_fgt(vcpu, ICH_HFGRTR_EL2);
+	__compute_ich_hfgrtr(vcpu);
 	__compute_fgt(vcpu, ICH_HFGWTR_EL2);
 	__compute_fgt(vcpu, ICH_HFGITR_EL2);
 }
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index fbbd7b6ff6507..31c08fd591d08 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -681,6 +681,24 @@ static bool access_gic_dir(struct kvm_vcpu *vcpu,
 	return true;
 }
 
+static bool access_gicv5_iaffid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+				const struct sys_reg_desc *r)
+{
+	if (!vgic_is_v5(vcpu->kvm))
+		return undef_access(vcpu, p, r);
+
+	if (p->is_write)
+		return ignore_write(vcpu, p);
+
+	/*
+	 * For GICv5 VMs, the IAFFID value is the same as the VPE ID. The VPE ID
+	 * is the same as the VCPU's ID.
+	 */
+	p->regval = FIELD_PREP(ICC_IAFFIDR_EL1_IAFFID, vcpu->vcpu_id);
+
+	return true;
+}
+
 static bool trap_raz_wi(struct kvm_vcpu *vcpu,
 			struct sys_reg_params *p,
 			const struct sys_reg_desc *r)
@@ -3411,6 +3429,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	{ SYS_DESC(SYS_ICC_AP1R1_EL1), undef_access },
 	{ SYS_DESC(SYS_ICC_AP1R2_EL1), undef_access },
 	{ SYS_DESC(SYS_ICC_AP1R3_EL1), undef_access },
+	{ SYS_DESC(SYS_ICC_IAFFIDR_EL1), access_gicv5_iaffid },
 	{ SYS_DESC(SYS_ICC_DIR_EL1), access_gic_dir },
 	{ SYS_DESC(SYS_ICC_RPR_EL1), undef_access },
 	{ SYS_DESC(SYS_ICC_SGI1R_EL1), access_gic_sgi },
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:40 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:40 +0000
Subject: [PATCH 16/32] KVM: arm64: gic: Introduce irq_queue and
 set_pending_state to irq_ops
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-17-sascha.bischoff@arm.com>

There are times when the default behaviour of vgic_queue_irq_unlock is
undesirable. This is because some GICs, such a GICv5 which is the main
driver for this change, handle the majority of the interrupt lifecycle
in hardware. In this case, there is no need for a per-VCPU AP list as
the interrupt can be made pending directly. This is done either via
the ICH_PPI_x_EL2 registers for PPIs, or with the VDPEND system
instruction for SPIs and LPIs.

The queue_irq_unlock function is made overridable using a new function
pointer in struct irq_ops. In kvm_vgic_inject_irq,
vgic_queue_irq_unlock is overridden if the function pointer is
non-null.

Additionally, a new function is added via a function pointer -
set_pending_state. The intent is for this to be used to directly set
the pending state in hardware.

Both of these new irq_ops are unused in this change - it is purely
providing the infrastructure itself. The subsequent PPI injection
changes provide a demonstration of their usage.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/vgic/vgic.c |  9 ++++++++-
 include/kvm/arm_vgic.h     | 15 +++++++++++++++
 2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index 1fe3dcc997860..fc01c6d07fe62 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -547,7 +547,14 @@ int kvm_vgic_inject_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 	else
 		irq->pending_latch = true;
 
-	vgic_queue_irq_unlock(kvm, irq, flags);
+	if (irq->ops && irq->ops->set_pending_state)
+		WARN_ON_ONCE(!irq->ops->set_pending_state(vcpu, irq));
+
+	if (irq->ops && irq->ops->queue_irq_unlock)
+		WARN_ON_ONCE(!irq->ops->queue_irq_unlock(kvm, irq, flags));
+	else
+		vgic_queue_irq_unlock(kvm, irq, flags);
+
 	vgic_put_irq(kvm, irq);
 
 	return 0;
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index ce9e149b85a58..20c908730fa00 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -115,6 +115,8 @@ enum vgic_irq_config {
 	VGIC_CONFIG_LEVEL
 };
 
+struct vgic_irq;
+
 /*
  * Per-irq ops overriding some common behavious.
  *
@@ -133,6 +135,19 @@ struct irq_ops {
 	 * peaking into the physical GIC.
 	 */
 	bool (*get_input_level)(int vintid);
+
+	/*
+	 * Function pointer to directly set the pending state for interrupts
+	 * that don't need to be enqueued on AP lists (for example, GICv5 PPIs).
+	 */
+	bool (*set_pending_state)(struct kvm_vcpu *vcpu, struct vgic_irq *irq);
+
+	/*
+	 * Function pointer to override the queuing of an IRQ.
+	 */
+	bool (*queue_irq_unlock)(struct kvm *kvm, struct vgic_irq *irq,
+				unsigned long flags) __releases(&irq->irq_lock);
+
 };
 
 struct vgic_irq {
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:35 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:35 +0000
Subject: [PATCH 02/32] KVM: arm64: gic-v3: Switch vGIC-v3 to use generated
 ICH_VMCR_EL2
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-3-sascha.bischoff@arm.com>

From: Sascha Bischoff <Sascha.Bischoff at arm.com>

The VGIC-v3 code relied on hand-written definitions for the
ICH_VMCR_EL2 register. This register, and the associated fields, is
now generated as part of the sysreg framework. Move to using the
generated definitions instead of the hand-written ones.

There are no functional changes as part of this change.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/include/asm/sysreg.h      | 21 ---------
 arch/arm64/kvm/hyp/vgic-v3-sr.c      | 64 ++++++++++++----------------
 arch/arm64/kvm/vgic/vgic-v3-nested.c |  8 ++--
 arch/arm64/kvm/vgic/vgic-v3.c        | 48 ++++++++++-----------
 4 files changed, 54 insertions(+), 87 deletions(-)

diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 9df51accbb025..b3b8b8cd7bf1e 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -560,7 +560,6 @@
 #define SYS_ICC_SRE_EL2			sys_reg(3, 4, 12, 9, 5)
 #define SYS_ICH_EISR_EL2		sys_reg(3, 4, 12, 11, 3)
 #define SYS_ICH_ELRSR_EL2		sys_reg(3, 4, 12, 11, 5)
-#define SYS_ICH_VMCR_EL2		sys_reg(3, 4, 12, 11, 7)
 
 #define __SYS__LR0_EL2(x)		sys_reg(3, 4, 12, 12, x)
 #define SYS_ICH_LR0_EL2			__SYS__LR0_EL2(0)
@@ -988,26 +987,6 @@
 #define ICH_LR_PRIORITY_SHIFT	48
 #define ICH_LR_PRIORITY_MASK	(0xffULL << ICH_LR_PRIORITY_SHIFT)
 
-/* ICH_VMCR_EL2 bit definitions */
-#define ICH_VMCR_ACK_CTL_SHIFT	2
-#define ICH_VMCR_ACK_CTL_MASK	(1 << ICH_VMCR_ACK_CTL_SHIFT)
-#define ICH_VMCR_FIQ_EN_SHIFT	3
-#define ICH_VMCR_FIQ_EN_MASK	(1 << ICH_VMCR_FIQ_EN_SHIFT)
-#define ICH_VMCR_CBPR_SHIFT	4
-#define ICH_VMCR_CBPR_MASK	(1 << ICH_VMCR_CBPR_SHIFT)
-#define ICH_VMCR_EOIM_SHIFT	9
-#define ICH_VMCR_EOIM_MASK	(1 << ICH_VMCR_EOIM_SHIFT)
-#define ICH_VMCR_BPR1_SHIFT	18
-#define ICH_VMCR_BPR1_MASK	(7 << ICH_VMCR_BPR1_SHIFT)
-#define ICH_VMCR_BPR0_SHIFT	21
-#define ICH_VMCR_BPR0_MASK	(7 << ICH_VMCR_BPR0_SHIFT)
-#define ICH_VMCR_PMR_SHIFT	24
-#define ICH_VMCR_PMR_MASK	(0xffUL << ICH_VMCR_PMR_SHIFT)
-#define ICH_VMCR_ENG0_SHIFT	0
-#define ICH_VMCR_ENG0_MASK	(1 << ICH_VMCR_ENG0_SHIFT)
-#define ICH_VMCR_ENG1_SHIFT	1
-#define ICH_VMCR_ENG1_MASK	(1 << ICH_VMCR_ENG1_SHIFT)
-
 /*
  * Permission Indirection Extension (PIE) permission encodings.
  * Encodings with the _O suffix, have overlays applied (Permission Overlay Extension).
diff --git a/arch/arm64/kvm/hyp/vgic-v3-sr.c b/arch/arm64/kvm/hyp/vgic-v3-sr.c
index 0b670a033fd87..24a2074f3a8cf 100644
--- a/arch/arm64/kvm/hyp/vgic-v3-sr.c
+++ b/arch/arm64/kvm/hyp/vgic-v3-sr.c
@@ -569,11 +569,11 @@ static int __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu, u32 vmcr,
 			continue;
 
 		/* Group-0 interrupt, but Group-0 disabled? */
-		if (!(val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG0_MASK))
+		if (!(val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_EL2_VENG0_MASK))
 			continue;
 
 		/* Group-1 interrupt, but Group-1 disabled? */
-		if ((val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG1_MASK))
+		if ((val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_EL2_VENG1_MASK))
 			continue;
 
 		/* Not the highest priority? */
@@ -646,19 +646,19 @@ static int __vgic_v3_get_highest_active_priority(void)
 
 static unsigned int __vgic_v3_get_bpr0(u32 vmcr)
 {
-	return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
+	return FIELD_GET(ICH_VMCR_EL2_VBPR0, vmcr);
 }
 
 static unsigned int __vgic_v3_get_bpr1(u32 vmcr)
 {
 	unsigned int bpr;
 
-	if (vmcr & ICH_VMCR_CBPR_MASK) {
+	if (vmcr & ICH_VMCR_EL2_VCBPR_MASK) {
 		bpr = __vgic_v3_get_bpr0(vmcr);
 		if (bpr < 7)
 			bpr++;
 	} else {
-		bpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
+		bpr = FIELD_GET(ICH_VMCR_EL2_VBPR1, vmcr);
 	}
 
 	return bpr;
@@ -758,7 +758,7 @@ static void __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 	if (grp != !!(lr_val & ICH_LR_GROUP))
 		goto spurious;
 
-	pmr = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
+	pmr = FIELD_GET(ICH_VMCR_EL2_VPMR, vmcr);
 	lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
 	if (pmr <= lr_prio)
 		goto spurious;
@@ -806,7 +806,7 @@ static int ___vgic_v3_write_dir(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 	int lr;
 
 	/* EOImode == 0, nothing to be done here */
-	if (!(vmcr & ICH_VMCR_EOIM_MASK))
+	if (!FIELD_GET(ICH_VMCR_EL2_VEOIM_MASK, vmcr))
 		return 1;
 
 	/* No deactivate to be performed on an LPI */
@@ -849,7 +849,7 @@ static void __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 	}
 
 	/* EOImode == 1 and not an LPI, nothing to be done here */
-	if ((vmcr & ICH_VMCR_EOIM_MASK) && !(vid >= VGIC_MIN_LPI))
+	if (FIELD_GET(ICH_VMCR_EL2_VEOIM_MASK, vmcr) && !(vid >= VGIC_MIN_LPI))
 		return;
 
 	lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
@@ -865,12 +865,12 @@ static void __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 
 static void __vgic_v3_read_igrpen0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 {
-	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG0_MASK));
+	vcpu_set_reg(vcpu, rt, !!FIELD_GET(ICH_VMCR_EL2_VENG0_MASK, vmcr));
 }
 
 static void __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 {
-	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
+	vcpu_set_reg(vcpu, rt, !!FIELD_GET(ICH_VMCR_EL2_VENG1_MASK, vmcr));
 }
 
 static void __vgic_v3_write_igrpen0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
@@ -878,9 +878,9 @@ static void __vgic_v3_write_igrpen0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 	u64 val = vcpu_get_reg(vcpu, rt);
 
 	if (val & 1)
-		vmcr |= ICH_VMCR_ENG0_MASK;
+		vmcr |= ICH_VMCR_EL2_VENG0_MASK;
 	else
-		vmcr &= ~ICH_VMCR_ENG0_MASK;
+		vmcr &= ~ICH_VMCR_EL2_VENG0_MASK;
 
 	__vgic_v3_write_vmcr(vmcr);
 }
@@ -890,9 +890,9 @@ static void __vgic_v3_write_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 	u64 val = vcpu_get_reg(vcpu, rt);
 
 	if (val & 1)
-		vmcr |= ICH_VMCR_ENG1_MASK;
+		vmcr |= ICH_VMCR_EL2_VENG1_MASK;
 	else
-		vmcr &= ~ICH_VMCR_ENG1_MASK;
+		vmcr &= ~ICH_VMCR_EL2_VENG1_MASK;
 
 	__vgic_v3_write_vmcr(vmcr);
 }
@@ -916,10 +916,8 @@ static void __vgic_v3_write_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 	if (val < bpr_min)
 		val = bpr_min;
 
-	val <<= ICH_VMCR_BPR0_SHIFT;
-	val &= ICH_VMCR_BPR0_MASK;
-	vmcr &= ~ICH_VMCR_BPR0_MASK;
-	vmcr |= val;
+	vmcr &= ~ICH_VMCR_EL2_VBPR0_MASK;
+	vmcr |= FIELD_PREP(ICH_VMCR_EL2_VBPR0, val);
 
 	__vgic_v3_write_vmcr(vmcr);
 }
@@ -929,17 +927,15 @@ static void __vgic_v3_write_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 	u64 val = vcpu_get_reg(vcpu, rt);
 	u8 bpr_min = __vgic_v3_bpr_min();
 
-	if (vmcr & ICH_VMCR_CBPR_MASK)
+	if (FIELD_GET(ICH_VMCR_EL2_VCBPR_MASK, val))
 		return;
 
 	/* Enforce BPR limiting */
 	if (val < bpr_min)
 		val = bpr_min;
 
-	val <<= ICH_VMCR_BPR1_SHIFT;
-	val &= ICH_VMCR_BPR1_MASK;
-	vmcr &= ~ICH_VMCR_BPR1_MASK;
-	vmcr |= val;
+	vmcr &= ~ICH_VMCR_EL2_VBPR1_MASK;
+	vmcr |= FIELD_PREP(ICH_VMCR_EL2_VBPR1, val);
 
 	__vgic_v3_write_vmcr(vmcr);
 }
@@ -1029,19 +1025,15 @@ static void __vgic_v3_read_hppir(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 
 static void __vgic_v3_read_pmr(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 {
-	vmcr &= ICH_VMCR_PMR_MASK;
-	vmcr >>= ICH_VMCR_PMR_SHIFT;
-	vcpu_set_reg(vcpu, rt, vmcr);
+	vcpu_set_reg(vcpu, rt, FIELD_GET(ICH_VMCR_EL2_VPMR, vmcr));
 }
 
 static void __vgic_v3_write_pmr(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 {
 	u32 val = vcpu_get_reg(vcpu, rt);
 
-	val <<= ICH_VMCR_PMR_SHIFT;
-	val &= ICH_VMCR_PMR_MASK;
-	vmcr &= ~ICH_VMCR_PMR_MASK;
-	vmcr |= val;
+	vmcr &= ~ICH_VMCR_EL2_VPMR_MASK;
+	vmcr |= FIELD_PREP(ICH_VMCR_EL2_VPMR, val);
 
 	write_gicreg(vmcr, ICH_VMCR_EL2);
 }
@@ -1064,9 +1056,9 @@ static void __vgic_v3_read_ctlr(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 	/* A3V */
 	val |= ((vtr >> 21) & 1) << ICC_CTLR_EL1_A3V_SHIFT;
 	/* EOImode */
-	val |= ((vmcr & ICH_VMCR_EOIM_MASK) >> ICH_VMCR_EOIM_SHIFT) << ICC_CTLR_EL1_EOImode_SHIFT;
+	val |= FIELD_GET(ICH_VMCR_EL2_VEOIM, vmcr) << ICC_CTLR_EL1_EOImode_SHIFT;
 	/* CBPR */
-	val |= (vmcr & ICH_VMCR_CBPR_MASK) >> ICH_VMCR_CBPR_SHIFT;
+	val |= FIELD_GET(ICH_VMCR_EL2_VCBPR, vmcr);
 
 	vcpu_set_reg(vcpu, rt, val);
 }
@@ -1076,14 +1068,14 @@ static void __vgic_v3_write_ctlr(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 	u32 val = vcpu_get_reg(vcpu, rt);
 
 	if (val & ICC_CTLR_EL1_CBPR_MASK)
-		vmcr |= ICH_VMCR_CBPR_MASK;
+		vmcr |= ICH_VMCR_EL2_VCBPR_MASK;
 	else
-		vmcr &= ~ICH_VMCR_CBPR_MASK;
+		vmcr &= ~ICH_VMCR_EL2_VCBPR_MASK;
 
 	if (val & ICC_CTLR_EL1_EOImode_MASK)
-		vmcr |= ICH_VMCR_EOIM_MASK;
+		vmcr |= ICH_VMCR_EL2_VEOIM_MASK;
 	else
-		vmcr &= ~ICH_VMCR_EOIM_MASK;
+		vmcr &= ~ICH_VMCR_EL2_VEOIM_MASK;
 
 	write_gicreg(vmcr, ICH_VMCR_EL2);
 }
diff --git a/arch/arm64/kvm/vgic/vgic-v3-nested.c b/arch/arm64/kvm/vgic/vgic-v3-nested.c
index 61b44f3f2bf14..c9e35ec671173 100644
--- a/arch/arm64/kvm/vgic/vgic-v3-nested.c
+++ b/arch/arm64/kvm/vgic/vgic-v3-nested.c
@@ -202,16 +202,16 @@ u64 vgic_v3_get_misr(struct kvm_vcpu *vcpu)
 	if ((hcr & ICH_HCR_EL2_NPIE) && !mi_state.pend)
 		reg |= ICH_MISR_EL2_NP;
 
-	if ((hcr & ICH_HCR_EL2_VGrp0EIE) && (vmcr & ICH_VMCR_ENG0_MASK))
+	if ((hcr & ICH_HCR_EL2_VGrp0EIE) && (vmcr & ICH_VMCR_EL2_VENG0_MASK))
 		reg |= ICH_MISR_EL2_VGrp0E;
 
-	if ((hcr & ICH_HCR_EL2_VGrp0DIE) && !(vmcr & ICH_VMCR_ENG0_MASK))
+	if ((hcr & ICH_HCR_EL2_VGrp0DIE) && !(vmcr & ICH_VMCR_EL2_VENG0_MASK))
 		reg |= ICH_MISR_EL2_VGrp0D;
 
-	if ((hcr & ICH_HCR_EL2_VGrp1EIE) && (vmcr & ICH_VMCR_ENG1_MASK))
+	if ((hcr & ICH_HCR_EL2_VGrp1EIE) && (vmcr & ICH_VMCR_EL2_VENG1_MASK))
 		reg |= ICH_MISR_EL2_VGrp1E;
 
-	if ((hcr & ICH_HCR_EL2_VGrp1DIE) && !(vmcr & ICH_VMCR_ENG1_MASK))
+	if ((hcr & ICH_HCR_EL2_VGrp1DIE) && !(vmcr & ICH_VMCR_EL2_VENG1_MASK))
 		reg |= ICH_MISR_EL2_VGrp1D;
 
 	return reg;
diff --git a/arch/arm64/kvm/vgic/vgic-v3.c b/arch/arm64/kvm/vgic/vgic-v3.c
index 1d6dd1b545bdd..2afc041672311 100644
--- a/arch/arm64/kvm/vgic/vgic-v3.c
+++ b/arch/arm64/kvm/vgic/vgic-v3.c
@@ -41,9 +41,9 @@ void vgic_v3_configure_hcr(struct kvm_vcpu *vcpu,
 	if (!als->nr_sgi)
 		cpuif->vgic_hcr |= ICH_HCR_EL2_vSGIEOICount;
 
-	cpuif->vgic_hcr |= (cpuif->vgic_vmcr & ICH_VMCR_ENG0_MASK) ?
+	cpuif->vgic_hcr |= (cpuif->vgic_vmcr & ICH_VMCR_EL2_VENG0_MASK) ?
 		ICH_HCR_EL2_VGrp0DIE : ICH_HCR_EL2_VGrp0EIE;
-	cpuif->vgic_hcr |= (cpuif->vgic_vmcr & ICH_VMCR_ENG1_MASK) ?
+	cpuif->vgic_hcr |= (cpuif->vgic_vmcr & ICH_VMCR_EL2_VENG1_MASK) ?
 		ICH_HCR_EL2_VGrp1DIE : ICH_HCR_EL2_VGrp1EIE;
 
 	/*
@@ -215,7 +215,7 @@ void vgic_v3_deactivate(struct kvm_vcpu *vcpu, u64 val)
 	 * We only deal with DIR when EOIMode==1, and only for SGI,
 	 * PPI or SPI.
 	 */
-	if (!(cpuif->vgic_vmcr & ICH_VMCR_EOIM_MASK) ||
+	if (!(cpuif->vgic_vmcr & ICH_VMCR_EL2_VEOIM_MASK) ||
 	    val >= vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS)
 		return;
 
@@ -408,25 +408,23 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 	u32 vmcr;
 
 	if (model == KVM_DEV_TYPE_ARM_VGIC_V2) {
-		vmcr = (vmcrp->ackctl << ICH_VMCR_ACK_CTL_SHIFT) &
-			ICH_VMCR_ACK_CTL_MASK;
-		vmcr |= (vmcrp->fiqen << ICH_VMCR_FIQ_EN_SHIFT) &
-			ICH_VMCR_FIQ_EN_MASK;
+		vmcr = FIELD_PREP(ICH_VMCR_EL2_VAckCtl, vmcrp->ackctl);
+		vmcr |= FIELD_PREP(ICH_VMCR_EL2_VFIQEn, vmcrp->fiqen);
 	} else {
 		/*
 		 * When emulating GICv3 on GICv3 with SRE=1 on the
 		 * VFIQEn bit is RES1 and the VAckCtl bit is RES0.
 		 */
-		vmcr = ICH_VMCR_FIQ_EN_MASK;
+		vmcr = ICH_VMCR_EL2_VFIQEn_MASK;
 	}
 
-	vmcr |= (vmcrp->cbpr << ICH_VMCR_CBPR_SHIFT) & ICH_VMCR_CBPR_MASK;
-	vmcr |= (vmcrp->eoim << ICH_VMCR_EOIM_SHIFT) & ICH_VMCR_EOIM_MASK;
-	vmcr |= (vmcrp->abpr << ICH_VMCR_BPR1_SHIFT) & ICH_VMCR_BPR1_MASK;
-	vmcr |= (vmcrp->bpr << ICH_VMCR_BPR0_SHIFT) & ICH_VMCR_BPR0_MASK;
-	vmcr |= (vmcrp->pmr << ICH_VMCR_PMR_SHIFT) & ICH_VMCR_PMR_MASK;
-	vmcr |= (vmcrp->grpen0 << ICH_VMCR_ENG0_SHIFT) & ICH_VMCR_ENG0_MASK;
-	vmcr |= (vmcrp->grpen1 << ICH_VMCR_ENG1_SHIFT) & ICH_VMCR_ENG1_MASK;
+	vmcr |= FIELD_PREP(ICH_VMCR_EL2_VCBPR, vmcrp->cbpr);
+	vmcr |= FIELD_PREP(ICH_VMCR_EL2_VEOIM, vmcrp->eoim);
+	vmcr |= FIELD_PREP(ICH_VMCR_EL2_VBPR1, vmcrp->abpr);
+	vmcr |= FIELD_PREP(ICH_VMCR_EL2_VBPR0, vmcrp->bpr);
+	vmcr |= FIELD_PREP(ICH_VMCR_EL2_VPMR, vmcrp->pmr);
+	vmcr |= FIELD_PREP(ICH_VMCR_EL2_VENG0, vmcrp->grpen0);
+	vmcr |= FIELD_PREP(ICH_VMCR_EL2_VENG1, vmcrp->grpen1);
 
 	cpu_if->vgic_vmcr = vmcr;
 }
@@ -440,10 +438,8 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 	vmcr = cpu_if->vgic_vmcr;
 
 	if (model == KVM_DEV_TYPE_ARM_VGIC_V2) {
-		vmcrp->ackctl = (vmcr & ICH_VMCR_ACK_CTL_MASK) >>
-			ICH_VMCR_ACK_CTL_SHIFT;
-		vmcrp->fiqen = (vmcr & ICH_VMCR_FIQ_EN_MASK) >>
-			ICH_VMCR_FIQ_EN_SHIFT;
+		vmcrp->ackctl = FIELD_GET(ICH_VMCR_EL2_VAckCtl, vmcr);
+		vmcrp->fiqen = FIELD_GET(ICH_VMCR_EL2_VFIQEn, vmcr);
 	} else {
 		/*
 		 * When emulating GICv3 on GICv3 with SRE=1 on the
@@ -453,13 +449,13 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 		vmcrp->ackctl = 0;
 	}
 
-	vmcrp->cbpr = (vmcr & ICH_VMCR_CBPR_MASK) >> ICH_VMCR_CBPR_SHIFT;
-	vmcrp->eoim = (vmcr & ICH_VMCR_EOIM_MASK) >> ICH_VMCR_EOIM_SHIFT;
-	vmcrp->abpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
-	vmcrp->bpr  = (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
-	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
-	vmcrp->grpen0 = (vmcr & ICH_VMCR_ENG0_MASK) >> ICH_VMCR_ENG0_SHIFT;
-	vmcrp->grpen1 = (vmcr & ICH_VMCR_ENG1_MASK) >> ICH_VMCR_ENG1_SHIFT;
+	vmcrp->cbpr = FIELD_GET(ICH_VMCR_EL2_VCBPR, vmcr);
+	vmcrp->eoim = FIELD_GET(ICH_VMCR_EL2_VEOIM, vmcr);
+	vmcrp->abpr = FIELD_GET(ICH_VMCR_EL2_VBPR1, vmcr);
+	vmcrp->bpr  = FIELD_GET(ICH_VMCR_EL2_VBPR0, vmcr);
+	vmcrp->pmr  = FIELD_GET(ICH_VMCR_EL2_VPMR, vmcr);
+	vmcrp->grpen0 = FIELD_GET(ICH_VMCR_EL2_VENG0, vmcr);
+	vmcrp->grpen1 = FIELD_GET(ICH_VMCR_EL2_VENG1, vmcr);
 }
 
 #define INITIAL_PENDBASER_VALUE						  \
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:38 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:38 +0000
Subject: [PATCH 09/32] KVM: arm64: gic-v5: Compute GICv5 FGTs on vcpu load
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-10-sascha.bischoff@arm.com>

Extend the existing FGT infrastructure to calculate and activate any
required GICv5 traps (ICH_HFGRTR_EL2, ICH_HFGWTR_EL2, ICH_HFGITR_EL2)
before entering the guest, and restore the original ICH_HFGxTR_EL2
contents on the return path. This ensures that the host and guest
behaviour remains independent.

As of this change, none of the GICv5 instructions or register accesses
are being trapped, but this will change in subsequent commits as some
GICv5 system registers must always be trapped (ICC_IAFFIDR_EL1,
ICH_PPI_HMRx_EL1).

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/include/asm/kvm_host.h       | 19 +++++
 arch/arm64/include/asm/vncr_mapping.h   |  3 +
 arch/arm64/kvm/arm.c                    |  3 +
 arch/arm64/kvm/config.c                 | 96 ++++++++++++++++++++++++-
 arch/arm64/kvm/emulate-nested.c         | 68 ++++++++++++++++++
 arch/arm64/kvm/hyp/include/hyp/switch.h | 27 +++++++
 arch/arm64/kvm/hyp/nvhe/switch.c        |  3 +
 arch/arm64/kvm/sys_regs.c               |  2 +
 8 files changed, 219 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index b552a1e03848c..0e535ef50c231 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -287,6 +287,9 @@ enum fgt_group_id {
 	HDFGRTR2_GROUP,
 	HDFGWTR2_GROUP = HDFGRTR2_GROUP,
 	HFGITR2_GROUP,
+	ICH_HFGRTR_GROUP,
+	ICH_HFGWTR_GROUP = ICH_HFGRTR_GROUP,
+	ICH_HFGITR_GROUP,
 
 	/* Must be last */
 	__NR_FGT_GROUP_IDS__
@@ -623,6 +626,10 @@ enum vcpu_sysreg {
 	VNCR(ICH_HCR_EL2),
 	VNCR(ICH_VMCR_EL2),
 
+	VNCR(ICH_HFGRTR_EL2),
+	VNCR(ICH_HFGWTR_EL2),
+	VNCR(ICH_HFGITR_EL2),
+
 	NR_SYS_REGS	/* Nothing after this line! */
 };
 
@@ -652,6 +659,9 @@ extern struct fgt_masks hfgwtr2_masks;
 extern struct fgt_masks hfgitr2_masks;
 extern struct fgt_masks hdfgrtr2_masks;
 extern struct fgt_masks hdfgwtr2_masks;
+extern struct fgt_masks ich_hfgrtr_masks;
+extern struct fgt_masks ich_hfgwtr_masks;
+extern struct fgt_masks ich_hfgitr_masks;
 
 extern struct fgt_masks kvm_nvhe_sym(hfgrtr_masks);
 extern struct fgt_masks kvm_nvhe_sym(hfgwtr_masks);
@@ -664,6 +674,9 @@ extern struct fgt_masks kvm_nvhe_sym(hfgwtr2_masks);
 extern struct fgt_masks kvm_nvhe_sym(hfgitr2_masks);
 extern struct fgt_masks kvm_nvhe_sym(hdfgrtr2_masks);
 extern struct fgt_masks kvm_nvhe_sym(hdfgwtr2_masks);
+extern struct fgt_masks kvm_nvhe_sym(ich_hfgrtr_masks);
+extern struct fgt_masks kvm_nvhe_sym(ich_hfgwtr_masks);
+extern struct fgt_masks kvm_nvhe_sym(ich_hfgitr_masks);
 
 struct kvm_cpu_context {
 	struct user_pt_regs regs;	/* sp = sp_el0 */
@@ -1632,6 +1645,11 @@ static __always_inline enum fgt_group_id __fgt_reg_to_group_id(enum vcpu_sysreg
 	case HDFGRTR2_EL2:
 	case HDFGWTR2_EL2:
 		return HDFGRTR2_GROUP;
+	case ICH_HFGRTR_EL2:
+	case ICH_HFGWTR_EL2:
+		return ICH_HFGRTR_GROUP;
+	case ICH_HFGITR_EL2:
+		return ICH_HFGITR_GROUP;
 	default:
 		BUILD_BUG_ON(1);
 	}
@@ -1646,6 +1664,7 @@ static __always_inline enum fgt_group_id __fgt_reg_to_group_id(enum vcpu_sysreg
 		case HDFGWTR_EL2:					\
 		case HFGWTR2_EL2:					\
 		case HDFGWTR2_EL2:					\
+		case ICH_HFGWTR_EL2:					\
 			p = &(vcpu)->arch.fgt[id].w;			\
 			break;						\
 		default:						\
diff --git a/arch/arm64/include/asm/vncr_mapping.h b/arch/arm64/include/asm/vncr_mapping.h
index c2485a862e690..14366d35ce82f 100644
--- a/arch/arm64/include/asm/vncr_mapping.h
+++ b/arch/arm64/include/asm/vncr_mapping.h
@@ -108,5 +108,8 @@
 #define VNCR_MPAMVPM5_EL2       0x968
 #define VNCR_MPAMVPM6_EL2       0x970
 #define VNCR_MPAMVPM7_EL2       0x978
+#define VNCR_ICH_HFGITR_EL2	0xB10
+#define VNCR_ICH_HFGRTR_EL2	0xB18
+#define VNCR_ICH_HFGWTR_EL2	0xB20
 
 #endif /* __ARM64_VNCR_MAPPING_H__ */
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 4f80da0c0d1de..b7cf9d86aabb7 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -2474,6 +2474,9 @@ static void kvm_hyp_init_symbols(void)
 	kvm_nvhe_sym(hfgitr2_masks) = hfgitr2_masks;
 	kvm_nvhe_sym(hdfgrtr2_masks)= hdfgrtr2_masks;
 	kvm_nvhe_sym(hdfgwtr2_masks)= hdfgwtr2_masks;
+	kvm_nvhe_sym(ich_hfgrtr_masks) = ich_hfgrtr_masks;
+	kvm_nvhe_sym(ich_hfgwtr_masks) = ich_hfgwtr_masks;
+	kvm_nvhe_sym(ich_hfgitr_masks) = ich_hfgitr_masks;
 
 	/*
 	 * Flush entire BSS since part of its data containing init symbols is read
diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index 3845b188551b6..57ef67f718113 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -219,6 +219,7 @@ struct reg_feat_map_desc {
 #define FEAT_FGT2		ID_AA64MMFR0_EL1, FGT, FGT2
 #define FEAT_MTPMU		ID_AA64DFR0_EL1, MTPMU, IMP
 #define FEAT_HCX		ID_AA64MMFR1_EL1, HCX, IMP
+#define FEAT_GCIE		ID_AA64PFR2_EL1, GCIE, IMP
 
 static bool not_feat_aa64el3(struct kvm *kvm)
 {
@@ -1168,6 +1169,58 @@ static const struct reg_bits_to_feat_map mdcr_el2_feat_map[] = {
 static const DECLARE_FEAT_MAP(mdcr_el2_desc, MDCR_EL2,
 			      mdcr_el2_feat_map, FEAT_AA64EL2);
 
+static const struct reg_bits_to_feat_map ich_hfgrtr_feat_map[] = {
+	NEEDS_FEAT(ICH_HFGRTR_EL2_ICC_APR_EL1 |
+		   ICH_HFGRTR_EL2_ICC_IDRn_EL1 |
+		   ICH_HFGRTR_EL2_ICC_CR0_EL1 |
+		   ICH_HFGRTR_EL2_ICC_HPPIR_EL1 |
+		   ICH_HFGRTR_EL2_ICC_PCR_EL1 |
+		   ICH_HFGRTR_EL2_ICC_ICSR_EL1 |
+		   ICH_HFGRTR_EL2_ICC_IAFFIDR_EL1 |
+		   ICH_HFGRTR_EL2_ICC_PPI_HMRn_EL1 |
+		   ICH_HFGRTR_EL2_ICC_PPI_ENABLERn_EL1 |
+		   ICH_HFGRTR_EL2_ICC_PPI_PENDRn_EL1 |
+		   ICH_HFGRTR_EL2_ICC_PPI_PRIORITYRn_EL1 |
+		   ICH_HFGRTR_EL2_ICC_PPI_ACTIVERn_EL1,
+		   FEAT_GCIE),
+};
+
+static const DECLARE_FEAT_MAP_FGT(ich_hfgrtr_desc, ich_hfgrtr_masks,
+				  ich_hfgrtr_feat_map, FEAT_GCIE);
+
+static const struct reg_bits_to_feat_map ich_hfgwtr_feat_map[] = {
+	NEEDS_FEAT(ICH_HFGWTR_EL2_ICC_APR_EL1 |
+		   ICH_HFGWTR_EL2_ICC_CR0_EL1 |
+		   ICH_HFGWTR_EL2_ICC_PCR_EL1 |
+		   ICH_HFGWTR_EL2_ICC_ICSR_EL1 |
+		   ICH_HFGWTR_EL2_ICC_PPI_ENABLERn_EL1 |
+		   ICH_HFGWTR_EL2_ICC_PPI_PENDRn_EL1 |
+		   ICH_HFGWTR_EL2_ICC_PPI_PRIORITYRn_EL1 |
+		   ICH_HFGWTR_EL2_ICC_PPI_ACTIVERn_EL1,
+		   FEAT_GCIE),
+};
+
+static const DECLARE_FEAT_MAP_FGT(ich_hfgwtr_desc, ich_hfgwtr_masks,
+				  ich_hfgwtr_feat_map, FEAT_GCIE);
+
+static const struct reg_bits_to_feat_map ich_hfgitr_feat_map[] = {
+	NEEDS_FEAT(ICH_HFGITR_EL2_GICCDEN |
+		   ICH_HFGITR_EL2_GICCDDIS |
+		   ICH_HFGITR_EL2_GICCDPRI |
+		   ICH_HFGITR_EL2_GICCDAFF |
+		   ICH_HFGITR_EL2_GICCDPEND |
+		   ICH_HFGITR_EL2_GICCDRCFG |
+		   ICH_HFGITR_EL2_GICCDHM |
+		   ICH_HFGITR_EL2_GICCDEOI |
+		   ICH_HFGITR_EL2_GICCDDI |
+		   ICH_HFGITR_EL2_GICRCDIA |
+		   ICH_HFGITR_EL2_GICRCDNMIA,
+		   FEAT_GCIE),
+};
+
+static const DECLARE_FEAT_MAP_FGT(ich_hfgitr_desc, ich_hfgitr_masks,
+				  ich_hfgitr_feat_map, FEAT_GCIE);
+
 static void __init check_feat_map(const struct reg_bits_to_feat_map *map,
 				  int map_size, u64 resx, const char *str)
 {
@@ -1211,6 +1264,9 @@ void __init check_feature_map(void)
 	check_reg_desc(&tcr2_el2_desc);
 	check_reg_desc(&sctlr_el1_desc);
 	check_reg_desc(&mdcr_el2_desc);
+	check_reg_desc(&ich_hfgrtr_desc);
+	check_reg_desc(&ich_hfgwtr_desc);
+	check_reg_desc(&ich_hfgitr_desc);
 }
 
 static bool idreg_feat_match(struct kvm *kvm, const struct reg_bits_to_feat_map *map)
@@ -1342,6 +1398,16 @@ void compute_fgu(struct kvm *kvm, enum fgt_group_id fgt)
 		val |= compute_reg_res0_bits(kvm, &hdfgwtr2_desc,
 					     0, NEVER_FGU);
 		break;
+	case ICH_HFGRTR_GROUP:
+		val |= compute_reg_res0_bits(kvm, &ich_hfgrtr_desc,
+					     0, NEVER_FGU);
+		val |= compute_reg_res0_bits(kvm, &ich_hfgwtr_desc,
+					     0, NEVER_FGU);
+		break;
+	case ICH_HFGITR_GROUP:
+		val |= compute_reg_res0_bits(kvm, &ich_hfgitr_desc,
+					     0, NEVER_FGU);
+		break;
 	default:
 		BUG();
 	}
@@ -1425,6 +1491,18 @@ void get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg, u64 *res0, u64 *r
 		*res0 = compute_reg_res0_bits(kvm, &mdcr_el2_desc, 0, 0);
 		*res1 = MDCR_EL2_RES1;
 		break;
+	case ICH_HFGRTR_EL2:
+		*res0 = compute_reg_res0_bits(kvm, &ich_hfgrtr_desc, 0, 0);
+		*res1 = ICH_HFGRTR_EL2_RES1;
+		break;
+	case ICH_HFGWTR_EL2:
+		*res0 = compute_reg_res0_bits(kvm, &ich_hfgwtr_desc, 0, 0);
+		*res1 = ICH_HFGWTR_EL2_RES1;
+		break;
+	case ICH_HFGITR_EL2:
+		*res0 = compute_reg_res0_bits(kvm, &ich_hfgitr_desc, 0, 0);
+		*res1 = ICH_HFGITR_EL2_RES1;
+		break;
 	default:
 		WARN_ON_ONCE(1);
 		*res0 = *res1 = 0;
@@ -1457,6 +1535,12 @@ static __always_inline struct fgt_masks *__fgt_reg_to_masks(enum vcpu_sysreg reg
 		return &hdfgrtr2_masks;
 	case HDFGWTR2_EL2:
 		return &hdfgwtr2_masks;
+	case ICH_HFGRTR_EL2:
+		return &ich_hfgrtr_masks;
+	case ICH_HFGWTR_EL2:
+		return &ich_hfgwtr_masks;
+	case ICH_HFGITR_EL2:
+		return &ich_hfgitr_masks;
 	default:
 		BUILD_BUG_ON(1);
 	}
@@ -1501,7 +1585,7 @@ static void __compute_hdfgwtr(struct kvm_vcpu *vcpu)
 void kvm_vcpu_load_fgt(struct kvm_vcpu *vcpu)
 {
 	if (!cpus_have_final_cap(ARM64_HAS_FGT))
-		return;
+		goto skip_feat_fgt;
 
 	__compute_fgt(vcpu, HFGRTR_EL2);
 	__compute_hfgwtr(vcpu);
@@ -1511,11 +1595,19 @@ void kvm_vcpu_load_fgt(struct kvm_vcpu *vcpu)
 	__compute_fgt(vcpu, HAFGRTR_EL2);
 
 	if (!cpus_have_final_cap(ARM64_HAS_FGT2))
-		return;
+		goto skip_feat_fgt;
 
 	__compute_fgt(vcpu, HFGRTR2_EL2);
 	__compute_fgt(vcpu, HFGWTR2_EL2);
 	__compute_fgt(vcpu, HFGITR2_EL2);
 	__compute_fgt(vcpu, HDFGRTR2_EL2);
 	__compute_fgt(vcpu, HDFGWTR2_EL2);
+
+skip_feat_fgt:
+	if (!cpus_have_final_cap(ARM64_HAS_GICV5_CPUIF))
+		return;
+
+	__compute_fgt(vcpu, ICH_HFGRTR_EL2);
+	__compute_fgt(vcpu, ICH_HFGWTR_EL2);
+	__compute_fgt(vcpu, ICH_HFGITR_EL2);
 }
diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c
index 75d49f83342a5..de316bdf90d46 100644
--- a/arch/arm64/kvm/emulate-nested.c
+++ b/arch/arm64/kvm/emulate-nested.c
@@ -2044,6 +2044,60 @@ static const struct encoding_to_trap_config encoding_to_fgt[] __initconst = {
 	SR_FGT(SYS_AMEVCNTR0_EL0(2),	HAFGRTR, AMEVCNTR02_EL0, 1),
 	SR_FGT(SYS_AMEVCNTR0_EL0(1),	HAFGRTR, AMEVCNTR01_EL0, 1),
 	SR_FGT(SYS_AMEVCNTR0_EL0(0),	HAFGRTR, AMEVCNTR00_EL0, 1),
+
+	/*
+	 * ICH_HFGRTR_EL2 & ICH_HFGWTR_EL2
+	 */
+	SR_FGT(SYS_ICC_APR_EL1,			ICH_HFGRTR, ICC_APR_EL1, 0),
+	SR_FGT(SYS_ICC_IDR0_EL1,		ICH_HFGRTR, ICC_IDRn_EL1, 0),
+	SR_FGT(SYS_ICC_CR0_EL1,			ICH_HFGRTR, ICC_CR0_EL1, 0),
+	SR_FGT(SYS_ICC_HPPIR_EL1,		ICH_HFGRTR, ICC_HPPIR_EL1, 0),
+	SR_FGT(SYS_ICC_PCR_EL1,			ICH_HFGRTR, ICC_PCR_EL1, 0),
+	SR_FGT(SYS_ICC_ICSR_EL1,		ICH_HFGRTR, ICC_ICSR_EL1, 0),
+	SR_FGT(SYS_ICC_IAFFIDR_EL1,		ICH_HFGRTR, ICC_IAFFIDR_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_HMR0_EL1,		ICH_HFGRTR, ICC_PPI_HMRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_HMR1_EL1,		ICH_HFGRTR, ICC_PPI_HMRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_ENABLER0_EL1,	ICH_HFGRTR, ICC_PPI_ENABLERn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_ENABLER1_EL1,	ICH_HFGRTR, ICC_PPI_ENABLERn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_CPENDR0_EL1,		ICH_HFGRTR, ICC_PPI_PENDRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_CPENDR1_EL1,		ICH_HFGRTR, ICC_PPI_PENDRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_SPENDR0_EL1,		ICH_HFGRTR, ICC_PPI_PENDRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_SPENDR1_EL1,		ICH_HFGRTR, ICC_PPI_PENDRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR0_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR1_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR2_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR3_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR4_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR5_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR6_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR7_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR8_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR9_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR10_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR11_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR12_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR13_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR14_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR15_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_CACTIVER0_EL1,	ICH_HFGRTR, ICC_PPI_ACTIVERn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_CACTIVER1_EL1,	ICH_HFGRTR, ICC_PPI_ACTIVERn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_SACTIVER0_EL1,	ICH_HFGRTR, ICC_PPI_ACTIVERn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_SACTIVER1_EL1,	ICH_HFGRTR, ICC_PPI_ACTIVERn_EL1, 0),
+
+	/*
+	 * ICH_HFGITR_EL2
+	 */
+	SR_FGT(GICV5_OP_GIC_CDEN,	ICH_HFGITR, GICCDEN, 0),
+	SR_FGT(GICV5_OP_GIC_CDDIS,	ICH_HFGITR, GICCDDIS, 0),
+	SR_FGT(GICV5_OP_GIC_CDPRI,	ICH_HFGITR, GICCDPRI, 0),
+	SR_FGT(GICV5_OP_GIC_CDAFF,	ICH_HFGITR, GICCDAFF, 0),
+	SR_FGT(GICV5_OP_GIC_CDPEND,	ICH_HFGITR, GICCDPEND, 0),
+	SR_FGT(GICV5_OP_GIC_CDRCFG,	ICH_HFGITR, GICCDRCFG, 0),
+	SR_FGT(GICV5_OP_GIC_CDHM,	ICH_HFGITR, GICCDHM, 0),
+	SR_FGT(GICV5_OP_GIC_CDEOI,	ICH_HFGITR, GICCDEOI, 0),
+	SR_FGT(GICV5_OP_GIC_CDDI,	ICH_HFGITR, GICCDDI, 0),
+	SR_FGT(GICV5_OP_GICR_CDIA,	ICH_HFGITR, GICRCDIA, 0),
+	SR_FGT(GICV5_OP_GICR_CDNMIA,	ICH_HFGITR, GICRCDNMIA, 0),
 };
 
 /*
@@ -2118,6 +2172,9 @@ FGT_MASKS(hfgwtr2_masks, HFGWTR2_EL2);
 FGT_MASKS(hfgitr2_masks, HFGITR2_EL2);
 FGT_MASKS(hdfgrtr2_masks, HDFGRTR2_EL2);
 FGT_MASKS(hdfgwtr2_masks, HDFGWTR2_EL2);
+FGT_MASKS(ich_hfgrtr_masks, ICH_HFGRTR_EL2);
+FGT_MASKS(ich_hfgwtr_masks, ICH_HFGWTR_EL2);
+FGT_MASKS(ich_hfgitr_masks, ICH_HFGITR_EL2);
 
 static __init bool aggregate_fgt(union trap_config tc)
 {
@@ -2153,6 +2210,14 @@ static __init bool aggregate_fgt(union trap_config tc)
 		rmasks = &hfgitr2_masks;
 		wmasks = NULL;
 		break;
+	case ICH_HFGRTR_GROUP:
+		rmasks = &ich_hfgrtr_masks;
+		wmasks = &ich_hfgwtr_masks;
+		break;
+	case ICH_HFGITR_GROUP:
+		rmasks = &ich_hfgitr_masks;
+		wmasks = NULL;
+		break;
 	}
 
 	rresx = rmasks->res0 | rmasks->res1;
@@ -2223,6 +2288,9 @@ static __init int check_all_fgt_masks(int ret)
 		&hfgitr2_masks,
 		&hdfgrtr2_masks,
 		&hdfgwtr2_masks,
+		&ich_hfgrtr_masks,
+		&ich_hfgwtr_masks,
+		&ich_hfgitr_masks,
 	};
 	int err = 0;
 
diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index c5d5e5b86eaf0..14805336725f5 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -235,6 +235,18 @@ static inline void __activate_traps_hfgxtr(struct kvm_vcpu *vcpu)
 	__activate_fgt(hctxt, vcpu, HDFGWTR2_EL2);
 }
 
+static inline void __activate_traps_ich_hfgxtr(struct kvm_vcpu *vcpu)
+{
+	struct kvm_cpu_context *hctxt = host_data_ptr(host_ctxt);
+
+	if (!cpus_have_final_cap(ARM64_HAS_GICV5_CPUIF))
+		return;
+
+	__activate_fgt(hctxt, vcpu, ICH_HFGRTR_EL2);
+	__activate_fgt(hctxt, vcpu, ICH_HFGWTR_EL2);
+	__activate_fgt(hctxt, vcpu, ICH_HFGITR_EL2);
+}
+
 #define __deactivate_fgt(htcxt, vcpu, reg)				\
 	do {								\
 		write_sysreg_s(ctxt_sys_reg(hctxt, reg),		\
@@ -267,6 +279,19 @@ static inline void __deactivate_traps_hfgxtr(struct kvm_vcpu *vcpu)
 	__deactivate_fgt(hctxt, vcpu, HDFGWTR2_EL2);
 }
 
+static inline void __deactivate_traps_ich_hfgxtr(struct kvm_vcpu *vcpu)
+{
+	struct kvm_cpu_context *hctxt = host_data_ptr(host_ctxt);
+
+	if (!cpus_have_final_cap(ARM64_HAS_GICV5_CPUIF))
+		return;
+
+	__deactivate_fgt(hctxt, vcpu, ICH_HFGRTR_EL2);
+	__deactivate_fgt(hctxt, vcpu, ICH_HFGWTR_EL2);
+	__deactivate_fgt(hctxt, vcpu, ICH_HFGITR_EL2);
+
+}
+
 static inline void  __activate_traps_mpam(struct kvm_vcpu *vcpu)
 {
 	u64 r = MPAM2_EL2_TRAPMPAM0EL1 | MPAM2_EL2_TRAPMPAM1EL1;
@@ -330,6 +355,7 @@ static inline void __activate_traps_common(struct kvm_vcpu *vcpu)
 	}
 
 	__activate_traps_hfgxtr(vcpu);
+	__activate_traps_ich_hfgxtr(vcpu);
 	__activate_traps_mpam(vcpu);
 }
 
@@ -347,6 +373,7 @@ static inline void __deactivate_traps_common(struct kvm_vcpu *vcpu)
 		write_sysreg_s(ctxt_sys_reg(hctxt, HCRX_EL2), SYS_HCRX_EL2);
 
 	__deactivate_traps_hfgxtr(vcpu);
+	__deactivate_traps_ich_hfgxtr(vcpu);
 	__deactivate_traps_mpam();
 }
 
diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c
index d3b9ec8a7c283..c23e22ffac080 100644
--- a/arch/arm64/kvm/hyp/nvhe/switch.c
+++ b/arch/arm64/kvm/hyp/nvhe/switch.c
@@ -44,6 +44,9 @@ struct fgt_masks hfgwtr2_masks;
 struct fgt_masks hfgitr2_masks;
 struct fgt_masks hdfgrtr2_masks;
 struct fgt_masks hdfgwtr2_masks;
+struct fgt_masks ich_hfgrtr_masks;
+struct fgt_masks ich_hfgwtr_masks;
+struct fgt_masks ich_hfgitr_masks;
 
 extern void kvm_nvhe_prepare_backtrace(unsigned long fp, unsigned long pc);
 
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index a065f8939bc8f..fbbd7b6ff6507 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -5630,6 +5630,8 @@ void kvm_calculate_traps(struct kvm_vcpu *vcpu)
 	compute_fgu(kvm, HFGRTR2_GROUP);
 	compute_fgu(kvm, HFGITR2_GROUP);
 	compute_fgu(kvm, HDFGRTR2_GROUP);
+	compute_fgu(kvm, ICH_HFGRTR_GROUP);
+	compute_fgu(kvm, ICH_HFGITR_GROUP);
 
 	set_bit(KVM_ARCH_FLAG_FGU_INITIALIZED, &kvm->arch.flags);
 out:
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:41 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:41 +0000
Subject: [PATCH 17/32] KVM: arm64: gic-v5: Implement PPI interrupt injection
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-18-sascha.bischoff@arm.com>

This change introduces interrupt injection for PPIs for GICv5-based
guests.

The lifecycle of PPIs is largely managed by the hardware for a GICv5
system. The hypervisor injects pending state into the guest by using
the ICH_PPI_PENDRx_EL2 registers. These are used by the hardware to
pick a Highest Priority Pending Interrupt (HPPI) for the guest based
on the enable state of each individual interrupt. The enable state and
priority for each interrupt are provided by the guest itself (through
writes to the PPI registers).

When Direct Virtual Interrupt (DVI) is set for a particular PPI, the
hypervisor is even able to skip the injection of the pending state
altogether - it all happens in hardware.

The result of the above is that no AP lists are required for GICv5,
unlike for older GICs. Instead, for PPIs the ICH_PPI_* registers
fulfil the same purpose for all 128 PPIs. Hence, as long as the
ICH_PPI_* registers are populated prior to guest entry, and merged
back into the KVM shadow state on exit, the PPI state is preserved,
and interrupts can be injected.

When injecting the state of a PPI the state is merged into the KVM's
shadow state using the set_pending_state irq_op. The directly sets the
relevant bit in the shadow ICH_PPI_PENDRx_EL2, which is presented to
the guest (and GICv5 hardware) on next guest entry. The
queue_irq_unlock irq_op is required to kick the vCPU to ensure that it
seems the new state. The result is that no AP lists are used for
private interrupts on GICv5.

Prior to entering the guest, vgic_v5_flush_ppi_state is called from
kvm_vgic_flush_hwstate. The effectively snapshots the shadow PPI
pending state (twice - an entry and an exit copy) in order to track
any changes. These changes can come from a guest consuming an
interrupt or from a guest making an Edge-triggered interrupt pending.

When returning from running a guest, the guest's PPI state is merged
back into KVM's shadow state in vgic_v5_merge_ppi_state from
kvm_vgic_sync_hwstate. The Enable and Active state is synced back for
all PPIs, and the pending state is synced back for Edge PPIs (Level is
driven directly by the devices generating said levels). The incoming
pending state from the guest is merged with KVM's shadow state to
avoid losing any incoming interrupts.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/vgic/vgic-v5.c | 157 ++++++++++++++++++++++++++++++++++
 arch/arm64/kvm/vgic/vgic.c    |  35 ++++++--
 arch/arm64/kvm/vgic/vgic.h    |  49 ++++++++---
 include/kvm/arm_vgic.h        |   3 +
 4 files changed, 226 insertions(+), 18 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index 22558080711eb..d54595fbf4586 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -54,6 +54,163 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
 	return 0;
 }
 
+static bool vgic_v5_ppi_set_pending_state(struct kvm_vcpu *vcpu,
+					  struct vgic_irq *irq)
+{
+	struct vgic_v5_cpu_if *cpu_if;
+	const u32 id_bit = BIT_ULL(irq->intid % 64);
+	const u32 reg = FIELD_GET(GICV5_HWIRQ_ID, irq->intid) / 64;
+
+	if (!vcpu || !irq)
+		return false;
+
+	/* Skip injecting the state altogether */
+	if (irq->directly_injected)
+		return true;
+
+	cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+
+	if (irq_is_pending(irq))
+		cpu_if->vgic_ppi_pendr[reg] |= id_bit;
+	else
+		cpu_if->vgic_ppi_pendr[reg] &= ~id_bit;
+
+	return true;
+}
+
+/*
+ * For GICv5, the PPIs are mostly directly managed by the hardware. We
+ * (the hypervisor) handle the pending, active, enable state
+ * save/restore, but don't need the PPIs to be queued on a per-VCPU AP
+ * list. Therefore, sanity check the state, unlock, and return.
+ */
+static bool vgic_v5_ppi_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq,
+					 unsigned long flags)
+	__releases(&irq->irq_lock)
+{
+	struct kvm_vcpu *vcpu;
+
+	lockdep_assert_held(&irq->irq_lock);
+
+	if (WARN_ON_ONCE(!irq_is_ppi_v5(irq->intid)))
+		return false;
+
+	vcpu = irq->target_vcpu;
+	if (WARN_ON_ONCE(!vcpu))
+		return false;
+
+	raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
+
+	/* Directly kick the target VCPU to make sure it sees the IRQ */
+	kvm_make_request(KVM_REQ_IRQ_PENDING, vcpu);
+	kvm_vcpu_kick(vcpu);
+
+	return true;
+}
+
+static struct irq_ops vgic_v5_ppi_irq_ops = {
+	.set_pending_state = vgic_v5_ppi_set_pending_state,
+	.queue_irq_unlock = vgic_v5_ppi_queue_irq_unlock,
+};
+
+void vgic_v5_set_ppi_ops(struct vgic_irq *irq)
+{
+	if (WARN_ON(!irq) || WARN_ON(irq->ops))
+		return;
+
+	irq->ops = &vgic_v5_ppi_irq_ops;
+}
+
+/*
+ * Detect any PPIs state changes, and propagate the state with KVM's
+ * shadow structures.
+ */
+static void vgic_v5_merge_ppi_state(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+	unsigned long flags;
+	int i, reg;
+
+	for (reg = 0; reg < 2; reg++) {
+		unsigned long changed_bits;
+		const unsigned long enabler = cpu_if->vgic_ich_ppi_enabler_exit[reg];
+		const unsigned long activer = cpu_if->vgic_ppi_activer_exit[reg];
+		const unsigned long pendr = cpu_if->vgic_ppi_pendr_exit[reg];
+
+		/*
+		 * Track what changed across enabler, activer, pendr, but mask
+		 * with ~DVI.
+		 */
+		changed_bits = cpu_if->vgic_ich_ppi_enabler_entry[reg] ^ enabler;
+		changed_bits |= cpu_if->vgic_ppi_activer_entry[reg] ^ activer;
+		changed_bits |= cpu_if->vgic_ppi_pendr_entry[reg] ^ pendr;
+		changed_bits &= ~cpu_if->vgic_ppi_dvir[reg];
+
+		for_each_set_bit(i, &changed_bits, 64) {
+			struct vgic_irq *irq;
+			u32 intid;
+
+			intid = FIELD_PREP(GICV5_HWIRQ_TYPE, GICV5_HWIRQ_TYPE_PPI);
+			intid |= FIELD_PREP(GICV5_HWIRQ_ID, reg * 64 + i);
+
+			irq = vgic_get_vcpu_irq(vcpu, intid);
+
+			raw_spin_lock_irqsave(&irq->irq_lock, flags);
+			irq->enabled = !!(enabler & BIT(i));
+			irq->active = !!(activer & BIT(i));
+			/* This is an OR to avoid losing incoming edges! */
+			if (irq->config == VGIC_CONFIG_EDGE)
+				irq->pending_latch |= !!(pendr & BIT(i));
+			raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
+
+			vgic_put_irq(vcpu->kvm, irq);
+		}
+
+		/* Re-inject the exit state as entry state next time! */
+		cpu_if->vgic_ich_ppi_enabler_entry[reg] = enabler;
+		cpu_if->vgic_ppi_activer_entry[reg] = activer;
+
+		/*
+		 * Pending state is a bit different. We only propagate back
+		 * pending state for Edge interrupts. Moreover, this is OR'd
+		 * with the incoming state to make sure we don't lose incoming
+		 * edges. Use the (inverse) HMR to mask off all Level bits, and
+		 * OR.
+		 */
+		cpu_if->vgic_ppi_pendr[reg] |= pendr & ~cpu_if->vgic_ppi_hmr[reg];
+	}
+}
+
+void vgic_v5_flush_ppi_state(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+
+	/*
+	 * We're about to enter the guest. Copy the shadow state to the pending
+	 * reg that will be written to the ICH_PPI_PENDRx_EL2 regs. While the
+	 * guest is running we track any incoming changes to the pending state in
+	 * vgic_ppi_pendr. The incoming changes are merged with the outgoing
+	 * changes on the return path.
+	 */
+	cpu_if->vgic_ppi_pendr_entry[0] = cpu_if->vgic_ppi_pendr[0];
+	cpu_if->vgic_ppi_pendr_entry[1] = cpu_if->vgic_ppi_pendr[1];
+
+	/*
+	 * Make sure that we can correctly detect "edges" in the PPI
+	 * state. There's a path where we never actually enter the guest, and
+	 * failure to do this risks losing pending state
+	 */
+	cpu_if->vgic_ppi_pendr_exit[0] = cpu_if->vgic_ppi_pendr[0];
+	cpu_if->vgic_ppi_pendr_exit[1] = cpu_if->vgic_ppi_pendr[1];
+
+}
+
+void vgic_v5_fold_irq_state(struct kvm_vcpu *vcpu)
+{
+	/* Sync back the guest PPI state to the KVM shadow state */
+	vgic_v5_merge_ppi_state(vcpu);
+}
+
 /*
  * Sets/clears the corresponding bit in the ICH_PPI_DVIR register.
  */
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index fc01c6d07fe62..e534876656ca7 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -105,6 +105,15 @@ struct vgic_irq *vgic_get_vcpu_irq(struct kvm_vcpu *vcpu, u32 intid)
 	if (WARN_ON(!vcpu))
 		return NULL;
 
+	if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5) {
+		u32 int_num = FIELD_GET(GICV5_HWIRQ_ID, intid);
+
+		if (irq_is_ppi_v5(intid)) {
+			int_num = array_index_nospec(int_num, VGIC_V5_NR_PRIVATE_IRQS);
+			return &vcpu->arch.vgic_cpu.private_irqs[int_num];
+		}
+	}
+
 	/* SGIs and PPIs */
 	if (intid < VGIC_NR_PRIVATE_IRQS) {
 		intid = array_index_nospec(intid, VGIC_NR_PRIVATE_IRQS);
@@ -258,10 +267,12 @@ struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
 	 * If the distributor is disabled, pending interrupts shouldn't be
 	 * forwarded.
 	 */
-	if (irq->enabled && irq_is_pending(irq)) {
-		if (unlikely(irq->target_vcpu &&
-			     !irq->target_vcpu->kvm->arch.vgic.enabled))
-			return NULL;
+	if (irq_is_enabled(irq) && irq_is_pending(irq)) {
+		if (irq->target_vcpu) {
+			if (!vgic_is_v5(irq->target_vcpu->kvm) &&
+			    unlikely(!irq->target_vcpu->kvm->arch.vgic.enabled))
+				return NULL;
+		}
 
 		return irq->target_vcpu;
 	}
@@ -1044,7 +1055,11 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 	if (can_access_vgic_from_kernel())
 		vgic_save_state(vcpu);
 
-	vgic_fold_lr_state(vcpu);
+	if (!vgic_is_v5(vcpu->kvm))
+		vgic_fold_lr_state(vcpu);
+	else
+		vgic_v5_fold_irq_state(vcpu);
+
 	vgic_prune_ap_list(vcpu);
 }
 
@@ -1105,13 +1120,17 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 
 	DEBUG_SPINLOCK_BUG_ON(!irqs_disabled());
 
-	scoped_guard(raw_spinlock, &vcpu->arch.vgic_cpu.ap_list_lock)
-		vgic_flush_lr_state(vcpu);
+	if (!vgic_is_v5(vcpu->kvm)) {
+		scoped_guard(raw_spinlock, &vcpu->arch.vgic_cpu.ap_list_lock)
+			vgic_flush_lr_state(vcpu);
+	} else {
+		vgic_v5_flush_ppi_state(vcpu);
+	}
 
 	if (can_access_vgic_from_kernel())
 		vgic_restore_state(vcpu);
 
-	if (vgic_supports_direct_irqs(vcpu->kvm))
+	if (vgic_supports_direct_irqs(vcpu->kvm) && !vgic_is_v5(vcpu->kvm))
 		vgic_v4_commit(vcpu);
 }
 
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index b6e3f5e3aba18..5a77318ddb87a 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -132,6 +132,28 @@ static inline bool irq_is_pending(struct vgic_irq *irq)
 		return irq->pending_latch || irq->line_level;
 }
 
+/* Requires the irq_lock to be held by the caller. */
+static inline bool irq_is_enabled(struct vgic_irq *irq)
+{
+	if (irq->enabled)
+		return true;
+
+	/*
+	 * We always consider GICv5 interrupts as enabled as we can
+	 * always inject them. The state is handled by the hardware,
+	 * and the hardware will only signal the interrupt to the
+	 * guest once the guest enables it.
+	 */
+	if (irq->target_vcpu) {
+		u32 vgic_model = irq->target_vcpu->kvm->arch.vgic.vgic_model;
+
+		if (vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5)
+			return true;
+	}
+
+	return false;
+}
+
 static inline bool vgic_irq_is_mapped_level(struct vgic_irq *irq)
 {
 	return irq->config == VGIC_CONFIG_LEVEL && irq->hw;
@@ -306,7 +328,7 @@ static inline bool vgic_try_get_irq_ref(struct vgic_irq *irq)
 	if (!irq)
 		return false;
 
-	if (irq->intid < VGIC_MIN_LPI)
+	if (irq->target_vcpu && !irq_is_lpi(irq->target_vcpu->kvm, irq->intid))
 		return true;
 
 	return refcount_inc_not_zero(&irq->refcount);
@@ -363,7 +385,10 @@ void vgic_debug_init(struct kvm *kvm);
 void vgic_debug_destroy(struct kvm *kvm);
 
 int vgic_v5_probe(const struct gic_kvm_info *info);
+void vgic_v5_set_ppi_ops(struct vgic_irq *irq);
 int vgic_v5_set_ppi_dvi(struct kvm_vcpu *vcpu, u32 irq, bool dvi);
+void vgic_v5_flush_ppi_state(struct kvm_vcpu *vcpu);
+void vgic_v5_fold_irq_state(struct kvm_vcpu *vcpu);
 void vgic_v5_load(struct kvm_vcpu *vcpu);
 void vgic_v5_put(struct kvm_vcpu *vcpu);
 void vgic_v5_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
@@ -432,15 +457,6 @@ void vgic_its_invalidate_all_caches(struct kvm *kvm);
 int vgic_its_inv_lpi(struct kvm *kvm, struct vgic_irq *irq);
 int vgic_its_invall(struct kvm_vcpu *vcpu);
 
-bool system_supports_direct_sgis(void);
-bool vgic_supports_direct_msis(struct kvm *kvm);
-bool vgic_supports_direct_sgis(struct kvm *kvm);
-
-static inline bool vgic_supports_direct_irqs(struct kvm *kvm)
-{
-	return vgic_supports_direct_msis(kvm) || vgic_supports_direct_sgis(kvm);
-}
-
 int vgic_v4_init(struct kvm *kvm);
 void vgic_v4_teardown(struct kvm *kvm);
 void vgic_v4_configure_vsgis(struct kvm *kvm);
@@ -485,6 +501,19 @@ static inline bool vgic_is_v5(struct kvm *kvm)
 	return kvm_vgic_global_state.type == VGIC_V5 && !vgic_is_v3_compat(kvm);
 }
 
+bool system_supports_direct_sgis(void);
+bool vgic_supports_direct_msis(struct kvm *kvm);
+bool vgic_supports_direct_sgis(struct kvm *kvm);
+
+static inline bool vgic_supports_direct_irqs(struct kvm *kvm)
+{
+	/* GICv5 always supports direct IRQs */
+	if (vgic_is_v5(kvm))
+		return true;
+
+	return vgic_supports_direct_msis(kvm) || vgic_supports_direct_sgis(kvm);
+}
+
 int vgic_its_debug_init(struct kvm_device *dev);
 void vgic_its_debug_destroy(struct kvm_device *dev);
 
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 20c908730fa00..5a46fe3c35b5c 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -32,6 +32,9 @@
 #define VGIC_MIN_LPI		8192
 #define KVM_IRQCHIP_NUM_PINS	(1020 - 32)
 
+/* GICv5 constants */
+#define VGIC_V5_NR_PRIVATE_IRQS	128
+
 #define irq_is_ppi_legacy(irq) ((irq) >= VGIC_NR_SGIS && (irq) < VGIC_NR_PRIVATE_IRQS)
 #define irq_is_spi_legacy(irq) ((irq) >= VGIC_NR_PRIVATE_IRQS && \
 					(irq) <= VGIC_MAX_SPI)
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:41 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:41 +0000
Subject: [PATCH 19/32] KVM: arm64: gic-v5: Init Private IRQs (PPIs) for GICv5
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-20-sascha.bischoff@arm.com>

Initialise the private interrupts (PPIs, only) for GICv5. This means
that a GICv5-style intid is generated (which encodes the PPI type in
the top bits) instead of the 0-based index that is used for older
GICs.

Additionally, set all of the GICv5 PPIs to use Level for the handling
mode, with the exception of the SW_PPI which uses Edge. This matches
the architecturally-defined set in the GICv5 specification (the CTIIRQ
handling mode is IMPDEF, so pick Level has been picked for that).

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/vgic/vgic-init.c    | 41 +++++++++++++++++++++++-------
 include/linux/irqchip/arm-gic-v5.h |  2 ++
 2 files changed, 34 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index b246cb6eae71b..51f4443cebcef 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -263,13 +263,19 @@ static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu, u32 type)
 {
 	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
 	int i;
+	u32 num_private_irqs;
+
+	if (vgic_is_v5(vcpu->kvm))
+		num_private_irqs = VGIC_V5_NR_PRIVATE_IRQS;
+	else
+		num_private_irqs = VGIC_NR_PRIVATE_IRQS;
 
 	lockdep_assert_held(&vcpu->kvm->arch.config_lock);
 
 	if (vgic_cpu->private_irqs)
 		return 0;
 
-	vgic_cpu->private_irqs = kcalloc(VGIC_NR_PRIVATE_IRQS,
+	vgic_cpu->private_irqs = kcalloc(num_private_irqs,
 					 sizeof(struct vgic_irq),
 					 GFP_KERNEL_ACCOUNT);
 
@@ -280,22 +286,39 @@ static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu, u32 type)
 	 * Enable and configure all SGIs to be edge-triggered and
 	 * configure all PPIs as level-triggered.
 	 */
-	for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) {
+	for (i = 0; i < num_private_irqs; i++) {
 		struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
 
 		INIT_LIST_HEAD(&irq->ap_list);
 		raw_spin_lock_init(&irq->irq_lock);
-		irq->intid = i;
 		irq->vcpu = NULL;
 		irq->target_vcpu = vcpu;
 		refcount_set(&irq->refcount, 0);
-		if (vgic_irq_is_sgi(i)) {
-			/* SGIs */
-			irq->enabled = 1;
-			irq->config = VGIC_CONFIG_EDGE;
+		if (!vgic_is_v5(vcpu->kvm)) {
+			irq->intid = i;
+			if (vgic_irq_is_sgi(i)) {
+				/* SGIs */
+				irq->enabled = 1;
+				irq->config = VGIC_CONFIG_EDGE;
+			} else {
+				/* PPIs */
+				irq->config = VGIC_CONFIG_LEVEL;
+			}
 		} else {
-			/* PPIs */
-			irq->config = VGIC_CONFIG_LEVEL;
+			irq->intid = i | FIELD_PREP(GICV5_HWIRQ_TYPE,
+						    GICV5_HWIRQ_TYPE_PPI);
+
+			/*
+			 * The only architected PPI that is Edge is
+			 * the SW PPI.
+			 */
+			if (irq->intid == GICV5_SW_PPI)
+				irq->config = VGIC_CONFIG_EDGE;
+			else
+				irq->config = VGIC_CONFIG_LEVEL;
+
+			/* Register the GICv5-specific PPI ops */
+			vgic_v5_set_ppi_ops(irq);
 		}
 
 		switch (type) {
diff --git a/include/linux/irqchip/arm-gic-v5.h b/include/linux/irqchip/arm-gic-v5.h
index ff10d6c7be2ae..9607b36f021ee 100644
--- a/include/linux/irqchip/arm-gic-v5.h
+++ b/include/linux/irqchip/arm-gic-v5.h
@@ -13,6 +13,8 @@
 
 #define GICV5_IPIS_PER_CPU		MAX_IPI
 
+#define GICV5_SW_PPI			0x20000003
+
 /*
  * INTID handling
  */
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:34 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:34 +0000
Subject: [PATCH 00/32] KVM: arm64: Introduce vGIC-v5 with PPI support
Message-ID: <20251212152215.675767-1-sascha.bischoff@arm.com>

This patch series adds the virtual GICv5 [1] device (vgic_v5). Only
PPIs are supported by this initial series, and the vgic_v5
implementation is restricted to the CPU interface, only. Further patch
series are to follow in due course, and will add support for SPIs,
LPIs, the GICv5 IRS, and the GICv5 ITS.

The main changes in this series are the following:

* Bump vgic_v3 to use generated ICH_VMCR_EL2 definitions
* Introduction of the vgic_v5 device, which can be created using the
  KVM_DEV_TYPE_ARM_VGIC_V5 device type
* GICv5 FGT handling, and trapping for guest accesses to
  ICC_IAFFIDR_EL1 and ICC_PPI_HMRx_EL1
* Introduction of queue_irq_unlock and set_pending_state to struct
  irq_ops
* Management of GICv5 PPI state & injection of PPIs
* Direct injection of PPIs using the GICv5 PPI DVI mechanism (used by
  the Arch Timer for mapped IRQs)
* Userspace injection of GICv5 interrupts via KVM_IRQ_LINE
* Addition of a simple GICv5 PPI selftest

As mentioned above, this series introduces two new irq_ops. The
reasoning for this is the following: GIGv5 doesn't have LRs, but
instead has the ICH_PPI_* registers which are able to manage the state
for all implemented vPPIs concurrently. Therefore, by carefully
managing the state of these, there is no need for per-VCPU AP lists
for GICv5. By using these new irq_ops, it becomes possible to directly
set vPPI pending state and to skip the enqueuing on AP lists.

One small, but noteworthy change is to KVM_IRQ_LINE. Previously,
KVM_IRQ_LINE has limited PPI injection to 16-31, inclusive, and SPI
injection to 32-1019, inclusive. When running with a vgic_v5, these
limits are now 0-127 and 0-65535, respectively. Note that technically
a GICv5 system could use up to 2^24 bits for the SPI ID space, but it
is expected that 65k should be sufficient for the foreseeable
future. If more are desired, it will require more significant changes
to KVM_IRQ_LINE.

One final thing to mention is the change to vgic_is_v3_compat(struct
kvm *kvm), which has now been extended to explicitly check that the
vgic_model is not v5. This was previously not required as native GICv5
guests didn't exist. This has a drawback: if called prior to
vgic_create, this check will return true on a GICv5 host with
FEAT_GCIE_LEGACY. This affects the initial state of the sanitized
system registers.

These changes have been tested on an Arm FVP with GICv5 support. A
guide on how to obtain this model and use it can be found at [2]. Note
that the 11.30 release is required as it adds the virtualisation
support.

Note: The first change in this series ("KVM: arm64: Account for RES1
bits in DECLARE_FEAT_MAP() and co") has been cherry-picked from Marc
Zyngier's VTCR sanitisation series [3], and adds support for RES1 FGT
bits. The reason for pulling in this change is that GICv5 adds a RES1
FGT bit, which needs to be correctly handled. Thanks for this change,
Marc!

The initial GICv5 KVM support was prototyped by myself and Timothy
Hayes. Timothy and I therefore have co-authorship on some of the
changes. Thanks for all of your efforts, Timothy!

These changes are based on torvalds/linux:master at 187d0801404f4. Any
future revisions of this series will be posted against the relevant
stable tags, but as we are close to 6.19-rc1 that didn't quite make
sense for this revision.

Thanks all for taking a look, and I look forward to your feedback!

Sascha

[1] https://developer.arm.com/documentation/aes0070/latest
[2] https://linaro.atlassian.net/wiki/x/CQAF-wY
[3] https://lore.kernel.org/all/20251210173024.561160-1-maz at kernel.org/

Marc Zyngier (1):
  KVM: arm64: Account for RES1 bits in DECLARE_FEAT_MAP() and co

Sascha Bischoff (31):
  KVM: arm64: gic-v3: Switch vGIC-v3 to use generated ICH_VMCR_EL2
  arm64/sysreg: Drop ICH_HFGRTR_EL2.ICC_HAPR_EL1 and make RES1
  arm64/sysreg: Add remaining GICv5 ICC_ & ICH_ sysregs for KVM support
  arm64/sysreg: Add GICR CDNMIA encoding
  KVM: arm64: gic-v5: Add ARM_VGIC_V5 device to KVM headers
  KVM: arm64: gic: Introduce interrupt type helpers
  KVM: arm64: gic-v5: Sanitize ID_AA64PFR2_EL1.GCIE
  KVM: arm64: gic-v5: Compute GICv5 FGTs on vcpu load
  KVM: arm64: gic-v5: Add emulation for ICC_IAFFID_EL1 accesses
  KVM: arm64: gic-v5: Trap and emulate ICH_PPI_HMRx_EL1 accesses
  KVM: arm64: gic: Set vgic_model before initing private IRQs
  KVM: arm64: gic-v5: Add vgic-v5 save/restore hyp interface
  KVM: arm64: gic-v5: Implement GICv5 load/put and save/restore
  KVM: arm64: gic-v5: Implement direct injection of PPIs
  KVM: arm64: gic: Introduce irq_queue and set_pending_state to irq_ops
  KVM: arm64: gic-v5: Implement PPI interrupt injection
  KVM: arm64: gic-v5: Check for pending PPIs
  KVM: arm64: gic-v5: Init Private IRQs (PPIs) for GICv5
  KVM: arm64: gic-v5: Support GICv5 interrupts with KVM_IRQ_LINE
  KVM: arm64: gic-v5: Create, init vgic_v5
  KVM: arm64: gic-v5: Reset vcpu state
  KVM: arm64: gic-v5: Bump arch timer for GICv5
  KVM: arm64: gic-v5: Mandate architected PPI for PMU emulation on GICv5
  KVM: arm64: gic: Hide GICv5 for protected guests
  KVM: arm64: gic-v5: Hide FEAT_GCIE from NV GICv5 guests
  KVM: arm64: gic-v5: Introduce kvm_arm_vgic_v5_ops and register them
  KVM: arm64: gic-v5: Set ICH_VCTLR_EL2.En on boot
  irqchip/gic-v5: Check if impl is virt capable
  KVM: arm64: gic-v5: Probe for GICv5 device
  Documentation: KVM: Introduce documentation for VGICv5
  KVM: arm64: selftests: Introduce a minimal GICv5 PPI selftest

 Documentation/virt/kvm/api.rst                |   6 +-
 .../virt/kvm/devices/arm-vgic-v5.rst          |  18 +
 arch/arm64/include/asm/el2_setup.h            |   3 +-
 arch/arm64/include/asm/kvm_asm.h              |   4 +
 arch/arm64/include/asm/kvm_host.h             |  20 +
 arch/arm64/include/asm/kvm_hyp.h              |   9 +
 arch/arm64/include/asm/sysreg.h               |  28 +-
 arch/arm64/include/asm/vncr_mapping.h         |   3 +
 arch/arm64/kvm/arch_timer.c                   | 116 +++-
 arch/arm64/kvm/arm.c                          |  25 +-
 arch/arm64/kvm/config.c                       | 133 ++++-
 arch/arm64/kvm/emulate-nested.c               | 123 ++++-
 arch/arm64/kvm/hyp/include/hyp/switch.h       |  27 +
 arch/arm64/kvm/hyp/nvhe/Makefile              |   2 +-
 arch/arm64/kvm/hyp/nvhe/hyp-main.c            |  32 ++
 arch/arm64/kvm/hyp/nvhe/switch.c              |  13 +
 arch/arm64/kvm/hyp/nvhe/sys_regs.c            |   8 +
 arch/arm64/kvm/hyp/vgic-v3-sr.c               |  64 +--
 arch/arm64/kvm/hyp/vgic-v5.c                  | 155 ++++++
 arch/arm64/kvm/hyp/vhe/Makefile               |   2 +-
 arch/arm64/kvm/nested.c                       |   5 +
 arch/arm64/kvm/pmu-emul.c                     |  20 +-
 arch/arm64/kvm/sys_regs.c                     |  86 ++-
 arch/arm64/kvm/vgic/vgic-init.c               | 119 +++--
 arch/arm64/kvm/vgic/vgic-kvm-device.c         |  74 ++-
 arch/arm64/kvm/vgic/vgic-mmio.c               |  28 +-
 arch/arm64/kvm/vgic/vgic-v3-nested.c          |   8 +-
 arch/arm64/kvm/vgic/vgic-v3.c                 |  48 +-
 arch/arm64/kvm/vgic/vgic-v5.c                 | 505 +++++++++++++++++-
 arch/arm64/kvm/vgic/vgic.c                    | 120 +++--
 arch/arm64/kvm/vgic/vgic.h                    |  76 ++-
 arch/arm64/tools/sysreg                       | 482 ++++++++++++++++-
 drivers/irqchip/irq-gic-v5-irs.c              |   4 +
 drivers/irqchip/irq-gic-v5.c                  |   5 +
 include/kvm/arm_arch_timer.h                  |   7 +-
 include/kvm/arm_pmu.h                         |   5 +-
 include/kvm/arm_vgic.h                        |  87 ++-
 include/linux/irqchip/arm-gic-v5.h            |  15 +
 include/linux/kvm_host.h                      |   1 +
 include/uapi/linux/kvm.h                      |   2 +
 tools/include/uapi/linux/kvm.h                |   2 +
 tools/testing/selftests/kvm/Makefile.kvm      |   1 +
 tools/testing/selftests/kvm/arm64/vgic_v5.c   | 248 +++++++++
 .../selftests/kvm/include/arm64/gic_v5.h      | 148 +++++
 44 files changed, 2623 insertions(+), 264 deletions(-)
 create mode 100644 Documentation/virt/kvm/devices/arm-vgic-v5.rst
 create mode 100644 arch/arm64/kvm/hyp/vgic-v5.c
 create mode 100644 tools/testing/selftests/kvm/arm64/vgic_v5.c
 create mode 100644 tools/testing/selftests/kvm/include/arm64/gic_v5.h

-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:42 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:42 +0000
Subject: [PATCH 21/32] KVM: arm64: gic-v5: Create, init vgic_v5
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-22-sascha.bischoff@arm.com>

Update kvm_vgic_create to create a vgic_v5 device. When creating a
vgic, FEAT_GCIE in the ID_AA64PFR2 is only exposed to vgic_v5-based
guests, and is hidden otherwise. GIC in ~ID_AA64PFR0_EL1 is never
exposed for a vgic_v5 guest.

When initialising a vgic_v5, skip kvm_vgic_dist_init as GICv5 doesn't
support one. The current vgic_v5 implementation only supports PPIs, so
no SPIs are initialised either.

The current vgic_v5 support doesn't extend to nested
guests. Therefore, the init of vgic_v5 for a nested guest is failed in
vgic_v5_init.

As the current vgic_v5 doesn't require any resources to be mapped,
vgic_v5_map_resources is simply used to check that the vgic has indeed
been initialised. Again, this will change as more GICv5 support is
merged in.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/vgic/vgic-init.c | 51 ++++++++++++++++++++++-----------
 arch/arm64/kvm/vgic/vgic-v5.c   | 26 +++++++++++++++++
 arch/arm64/kvm/vgic/vgic.h      |  2 ++
 include/kvm/arm_vgic.h          |  1 +
 4 files changed, 63 insertions(+), 17 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index 51f4443cebcef..69e8746516799 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -66,12 +66,12 @@ static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu, u32 type);
  * or through the generic KVM_CREATE_DEVICE API ioctl.
  * irqchip_in_kernel() tells you if this function succeeded or not.
  * @kvm: kvm struct pointer
- * @type: KVM_DEV_TYPE_ARM_VGIC_V[23]
+ * @type: KVM_DEV_TYPE_ARM_VGIC_V[235]
  */
 int kvm_vgic_create(struct kvm *kvm, u32 type)
 {
 	struct kvm_vcpu *vcpu;
-	u64 aa64pfr0, pfr1;
+	u64 aa64pfr0, aa64pfr2, pfr1;
 	unsigned long i;
 	int ret;
 
@@ -132,8 +132,11 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
 
 	if (type == KVM_DEV_TYPE_ARM_VGIC_V2)
 		kvm->max_vcpus = VGIC_V2_MAX_CPUS;
-	else
+	else if (type == KVM_DEV_TYPE_ARM_VGIC_V3)
 		kvm->max_vcpus = VGIC_V3_MAX_CPUS;
+	else if (type == KVM_DEV_TYPE_ARM_VGIC_V5)
+		kvm->max_vcpus = min(VGIC_V5_MAX_CPUS,
+				     kvm_vgic_global_state.max_gic_vcpus);
 
 	if (atomic_read(&kvm->online_vcpus) > kvm->max_vcpus) {
 		ret = -E2BIG;
@@ -163,17 +166,21 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
 	}
 
 	aa64pfr0 = kvm_read_vm_id_reg(kvm, SYS_ID_AA64PFR0_EL1) & ~ID_AA64PFR0_EL1_GIC;
+	aa64pfr2 = kvm_read_vm_id_reg(kvm, SYS_ID_AA64PFR2_EL1) & ~ID_AA64PFR2_EL1_GCIE;
 	pfr1 = kvm_read_vm_id_reg(kvm, SYS_ID_PFR1_EL1) & ~ID_PFR1_EL1_GIC;
 
 	if (type == KVM_DEV_TYPE_ARM_VGIC_V2) {
 		kvm->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
-	} else {
+	} else if (type == KVM_DEV_TYPE_ARM_VGIC_V3) {
 		INIT_LIST_HEAD(&kvm->arch.vgic.rd_regions);
 		aa64pfr0 |= SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, GIC, IMP);
 		pfr1 |= SYS_FIELD_PREP_ENUM(ID_PFR1_EL1, GIC, GICv3);
+	} else {
+		aa64pfr2 |= SYS_FIELD_PREP_ENUM(ID_AA64PFR2_EL1, GCIE, IMP);
 	}
 
 	kvm_set_vm_id_reg(kvm, SYS_ID_AA64PFR0_EL1, aa64pfr0);
+	kvm_set_vm_id_reg(kvm, SYS_ID_AA64PFR2_EL1, aa64pfr2);
 	kvm_set_vm_id_reg(kvm, SYS_ID_PFR1_EL1, pfr1);
 
 	if (type == KVM_DEV_TYPE_ARM_VGIC_V3)
@@ -420,20 +427,26 @@ int vgic_init(struct kvm *kvm)
 	if (kvm->created_vcpus != atomic_read(&kvm->online_vcpus))
 		return -EBUSY;
 
-	/* freeze the number of spis */
-	if (!dist->nr_spis)
-		dist->nr_spis = VGIC_NR_IRQS_LEGACY - VGIC_NR_PRIVATE_IRQS;
+	if (!vgic_is_v5(kvm)) {
+		/* freeze the number of spis */
+		if (!dist->nr_spis)
+			dist->nr_spis = VGIC_NR_IRQS_LEGACY - VGIC_NR_PRIVATE_IRQS;
 
-	ret = kvm_vgic_dist_init(kvm, dist->nr_spis);
-	if (ret)
-		goto out;
+		ret = kvm_vgic_dist_init(kvm, dist->nr_spis);
+		if (ret)
+			goto out;
 
-	/*
-	 * Ensure vPEs are allocated if direct IRQ injection (e.g. vSGIs,
-	 * vLPIs) is supported.
-	 */
-	if (vgic_supports_direct_irqs(kvm)) {
-		ret = vgic_v4_init(kvm);
+		/*
+		 * Ensure vPEs are allocated if direct IRQ injection (e.g. vSGIs,
+		 * vLPIs) is supported.
+		 */
+		if (vgic_supports_direct_irqs(kvm)) {
+			ret = vgic_v4_init(kvm);
+			if (ret)
+				goto out;
+		}
+	} else {
+		ret = vgic_v5_init(kvm);
 		if (ret)
 			goto out;
 	}
@@ -610,9 +623,13 @@ int kvm_vgic_map_resources(struct kvm *kvm)
 	if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2) {
 		ret = vgic_v2_map_resources(kvm);
 		type = VGIC_V2;
-	} else {
+	} else if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) {
 		ret = vgic_v3_map_resources(kvm);
 		type = VGIC_V3;
+	} else {
+		ret = vgic_v5_map_resources(kvm);
+		type = VGIC_V5;
+		goto out;
 	}
 
 	if (ret)
diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index 35740e88b3591..3567754ae1459 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -54,6 +54,32 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
 	return 0;
 }
 
+int vgic_v5_init(struct kvm *kvm)
+{
+	struct kvm_vcpu *vcpu;
+	unsigned long idx;
+
+	if (vgic_initialized(kvm))
+		return 0;
+
+	kvm_for_each_vcpu(idx, vcpu, kvm) {
+		if (vcpu_has_nv(vcpu)) {
+			kvm_err("Nested GICv5 VMs are currently unsupported\n");
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+int vgic_v5_map_resources(struct kvm *kvm)
+{
+	if (!vgic_initialized(kvm))
+		return -EBUSY;
+
+	return 0;
+}
+
 static u32 vgic_v5_get_effective_priority_mask(struct kvm_vcpu *vcpu)
 {
 	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index 4b3a1e7ca3fb4..66698973b2872 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -385,6 +385,8 @@ void vgic_debug_init(struct kvm *kvm);
 void vgic_debug_destroy(struct kvm *kvm);
 
 int vgic_v5_probe(const struct gic_kvm_info *info);
+int vgic_v5_init(struct kvm *kvm);
+int vgic_v5_map_resources(struct kvm *kvm);
 void vgic_v5_set_ppi_ops(struct vgic_irq *irq);
 int vgic_v5_set_ppi_dvi(struct kvm_vcpu *vcpu, u32 irq, bool dvi);
 bool vgic_v5_has_pending_ppi(struct kvm_vcpu *vcpu);
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 5a46fe3c35b5c..099b8ac02999e 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -21,6 +21,7 @@
 #include <linux/irqchip/arm-gic-v4.h>
 #include <linux/irqchip/arm-gic-v5.h>
 
+#define VGIC_V5_MAX_CPUS	512
 #define VGIC_V3_MAX_CPUS	512
 #define VGIC_V2_MAX_CPUS	8
 #define VGIC_NR_IRQS_LEGACY     256
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:42 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:42 +0000
Subject: [PATCH 20/32] KVM: arm64: gic-v5: Support GICv5 interrupts with
 KVM_IRQ_LINE
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-21-sascha.bischoff@arm.com>

Interrupts under GICv5 look quite different to those from older Arm
GICs. Specifically, the type is encoded in the top bits of the
interrupt ID.

Extend KVM_IRQ_LINE to cope with GICv5 PPIs and SPIs. The requires
subtly changing the KVM_IRQ_LINE API for GICv5 guests. For older Arm
GICs, PPIs had to be in the range of 16-31, and SPIs had to be
32-1019, but this no longer holds true for GICv5. Instead, for a GICv5
guest support PPIs in the range of 0-127, and SPIs in the range
0-65535. The documentation is updated accordingly.

The SPI range doesn't cover the full SPI range that a GICv5 system can
potentially cope with (GICv5 provides up to 24-bits of SPI ID space,
and we only have 16 bits to work with in KVM_IRQ_LINE). However, 65k
SPIs is more than would be reasonably expected on systems for years to
come.

Note: As the GICv5 KVM implementation currently doesn't support
injecting SPIs attempts to do so will fail. This restruction will
lifted as the GICv5 KVM support evolves.

Co-authored-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 Documentation/virt/kvm/api.rst |  6 ++++--
 arch/arm64/kvm/arm.c           | 21 ++++++++++++++++++---
 arch/arm64/kvm/vgic/vgic.c     |  4 ++++
 3 files changed, 26 insertions(+), 5 deletions(-)

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 01a3abef8abb9..460a5511ebcec 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -907,10 +907,12 @@ The irq_type field has the following values:
 - KVM_ARM_IRQ_TYPE_CPU:
 	       out-of-kernel GIC: irq_id 0 is IRQ, irq_id 1 is FIQ
 - KVM_ARM_IRQ_TYPE_SPI:
-	       in-kernel GIC: SPI, irq_id between 32 and 1019 (incl.)
+	       in-kernel GICv2/GICv3: SPI, irq_id between 32 and 1019 (incl.)
                (the vcpu_index field is ignored)
+	       in-kernel GICv5: SPI, irq_id between 0 and 65535 (incl.)
 - KVM_ARM_IRQ_TYPE_PPI:
-	       in-kernel GIC: PPI, irq_id between 16 and 31 (incl.)
+	       in-kernel GICv2/GICv3: PPI, irq_id between 16 and 31 (incl.)
+	       in-kernel GICv5: PPI, irq_id between 0 and 127 (incl.)
 
 (The irq_id field thus corresponds nicely to the IRQ ID in the ARM GIC specs)
 
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index b7cf9d86aabb7..22f618384b199 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -45,6 +45,8 @@
 #include <kvm/arm_pmu.h>
 #include <kvm/arm_psci.h>
 
+#include <linux/irqchip/arm-gic-v5.h>
+
 #include "sys_regs.h"
 
 static enum kvm_mode kvm_mode = KVM_MODE_DEFAULT;
@@ -1426,16 +1428,29 @@ int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level,
 		if (!vcpu)
 			return -EINVAL;
 
-		if (irq_num < VGIC_NR_SGIS || irq_num >= VGIC_NR_PRIVATE_IRQS)
+		if (kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5) {
+			if (irq_num >= VGIC_V5_NR_PRIVATE_IRQS)
+				return -EINVAL;
+
+			/* Build a GICv5-style IntID here */
+			irq_num |= FIELD_PREP(GICV5_HWIRQ_TYPE, GICV5_HWIRQ_TYPE_PPI);
+		} else if (irq_num < VGIC_NR_SGIS ||
+			   irq_num >= VGIC_NR_PRIVATE_IRQS) {
 			return -EINVAL;
+		}
 
 		return kvm_vgic_inject_irq(kvm, vcpu, irq_num, level, NULL);
 	case KVM_ARM_IRQ_TYPE_SPI:
 		if (!irqchip_in_kernel(kvm))
 			return -ENXIO;
 
-		if (irq_num < VGIC_NR_PRIVATE_IRQS)
-			return -EINVAL;
+		if (kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5) {
+			/* Build a GICv5-style IntID here */
+			irq_num |= FIELD_PREP(GICV5_HWIRQ_TYPE, GICV5_HWIRQ_TYPE_SPI);
+		} else {
+			if (irq_num < VGIC_NR_PRIVATE_IRQS)
+				return -EINVAL;
+		}
 
 		return kvm_vgic_inject_irq(kvm, NULL, irq_num, level, NULL);
 	}
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index 5d18a03cc11d5..62d7d4c5650e4 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -86,6 +86,10 @@ static struct vgic_irq *vgic_get_lpi(struct kvm *kvm, u32 intid)
  */
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, u32 intid)
 {
+	/* Non-private IRQs are not yet implemented for GICv5 */
+	if (vgic_is_v5(kvm))
+		return NULL;
+
 	/* SPIs */
 	if (intid >= VGIC_NR_PRIVATE_IRQS &&
 	    intid < (kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS)) {
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:44 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:44 +0000
Subject: [PATCH 25/32] KVM: arm64: gic: Hide GICv5 for protected guests
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-26-sascha.bischoff@arm.com>

We don't support running protected guest with GICv5 at the
moment. Therefore, be sure that we don't expose it to the guest at all
by actively hiding it when running a protected guest.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/include/asm/kvm_hyp.h   | 1 +
 arch/arm64/kvm/arm.c               | 1 +
 arch/arm64/kvm/hyp/nvhe/sys_regs.c | 8 ++++++++
 3 files changed, 10 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index f6cf59a719ac6..824c00c3e32c8 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -144,6 +144,7 @@ void __noreturn __host_enter(struct kvm_cpu_context *host_ctxt);
 
 extern u64 kvm_nvhe_sym(id_aa64pfr0_el1_sys_val);
 extern u64 kvm_nvhe_sym(id_aa64pfr1_el1_sys_val);
+extern u64 kvm_nvhe_sym(id_aa64pfr2_el1_sys_val);
 extern u64 kvm_nvhe_sym(id_aa64isar0_el1_sys_val);
 extern u64 kvm_nvhe_sym(id_aa64isar1_el1_sys_val);
 extern u64 kvm_nvhe_sym(id_aa64isar2_el1_sys_val);
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 22f618384b199..ac4e6c4d06b0e 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -2467,6 +2467,7 @@ static void kvm_hyp_init_symbols(void)
 {
 	kvm_nvhe_sym(id_aa64pfr0_el1_sys_val) = get_hyp_id_aa64pfr0_el1();
 	kvm_nvhe_sym(id_aa64pfr1_el1_sys_val) = read_sanitised_ftr_reg(SYS_ID_AA64PFR1_EL1);
+	kvm_nvhe_sym(id_aa64pfr2_el1_sys_val) = read_sanitised_ftr_reg(SYS_ID_AA64PFR2_EL1);
 	kvm_nvhe_sym(id_aa64isar0_el1_sys_val) = read_sanitised_ftr_reg(SYS_ID_AA64ISAR0_EL1);
 	kvm_nvhe_sym(id_aa64isar1_el1_sys_val) = read_sanitised_ftr_reg(SYS_ID_AA64ISAR1_EL1);
 	kvm_nvhe_sym(id_aa64isar2_el1_sys_val) = read_sanitised_ftr_reg(SYS_ID_AA64ISAR2_EL1);
diff --git a/arch/arm64/kvm/hyp/nvhe/sys_regs.c b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
index 3108b5185c204..9652935a6ebdd 100644
--- a/arch/arm64/kvm/hyp/nvhe/sys_regs.c
+++ b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
@@ -20,6 +20,7 @@
  */
 u64 id_aa64pfr0_el1_sys_val;
 u64 id_aa64pfr1_el1_sys_val;
+u64 id_aa64pfr2_el1_sys_val;
 u64 id_aa64isar0_el1_sys_val;
 u64 id_aa64isar1_el1_sys_val;
 u64 id_aa64isar2_el1_sys_val;
@@ -108,6 +109,11 @@ static const struct pvm_ftr_bits pvmid_aa64pfr1[] = {
 	FEAT_END
 };
 
+static const struct pvm_ftr_bits pvmid_aa64pfr2[] = {
+	MAX_FEAT(ID_AA64PFR2_EL1, GCIE, NI),
+	FEAT_END
+};
+
 static const struct pvm_ftr_bits pvmid_aa64mmfr0[] = {
 	MAX_FEAT_ENUM(ID_AA64MMFR0_EL1, PARANGE, 40),
 	MAX_FEAT_ENUM(ID_AA64MMFR0_EL1, ASIDBITS, 16),
@@ -221,6 +227,8 @@ static u64 pvm_calc_id_reg(const struct kvm_vcpu *vcpu, u32 id)
 		return get_restricted_features(vcpu, id_aa64pfr0_el1_sys_val, pvmid_aa64pfr0);
 	case SYS_ID_AA64PFR1_EL1:
 		return get_restricted_features(vcpu, id_aa64pfr1_el1_sys_val, pvmid_aa64pfr1);
+	case SYS_ID_AA64PFR2_EL1:
+		return get_restricted_features(vcpu, id_aa64pfr2_el1_sys_val, pvmid_aa64pfr2);
 	case SYS_ID_AA64ISAR0_EL1:
 		return id_aa64isar0_el1_sys_val;
 	case SYS_ID_AA64ISAR1_EL1:
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:44 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:44 +0000
Subject: [PATCH 28/32] KVM: arm64: gic-v5: Set ICH_VCTLR_EL2.En on boot
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-29-sascha.bischoff@arm.com>

This control enables virtual HPPI selection, i.e., selection and
delivery of interrupts for a guest (assuming that the guest itself has
opted to receive interrupts). This is set to enabled on boot as there
is no reason for disabling it in normal operation as virtual interrupt
signalling itself is still controlled via the HCR_EL2.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/include/asm/el2_setup.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h
index 07c12f4a69b41..e7e39117c79e5 100644
--- a/arch/arm64/include/asm/el2_setup.h
+++ b/arch/arm64/include/asm/el2_setup.h
@@ -238,6 +238,8 @@
 		     ICH_HFGWTR_EL2_ICC_CR0_EL1			| \
 		     ICH_HFGWTR_EL2_ICC_APR_EL1)
 	msr_s	SYS_ICH_HFGWTR_EL2, x0		// Disable reg write traps
+	mov	x0, #(ICH_VCTLR_EL2_En)
+	msr_s	SYS_ICH_VCTLR_EL2, x0		// Enable vHPPI selection
 .Lskip_gicv5_\@:
 .endm
 
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:42 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:42 +0000
Subject: [PATCH 22/32] KVM: arm64: gic-v5: Reset vcpu state
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-23-sascha.bischoff@arm.com>

Limit the number of ID and priority bits supported based on the
hardware capabilities when resetting the vcpu state. Additionally,
calculate the PPI HMR representation for the vcpu. This is presented
to the guest when it accesses the ICC_PPI_HMRx_EL1 register (by
trapping and emulating the access).

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/vgic/vgic-init.c |  6 +++-
 arch/arm64/kvm/vgic/vgic-v5.c   | 63 ++++++++++++++++++++++++++++++++-
 arch/arm64/kvm/vgic/vgic.h      |  1 +
 3 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index 69e8746516799..120f28b329738 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -396,7 +396,11 @@ int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
 
 static void kvm_vgic_vcpu_reset(struct kvm_vcpu *vcpu)
 {
-	if (kvm_vgic_global_state.type == VGIC_V2)
+	const struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+
+	if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5)
+		vgic_v5_reset(vcpu);
+	else if (kvm_vgic_global_state.type == VGIC_V2)
 		vgic_v2_reset(vcpu);
 	else
 		vgic_v3_reset(vcpu);
diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index 3567754ae1459..a3d52ce066869 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -54,6 +54,45 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
 	return 0;
 }
 
+static void vgic_v5_construct_hmrs(struct kvm_vcpu *vcpu);
+
+void vgic_v5_reset(struct kvm_vcpu *vcpu)
+{
+	u64 idr0;
+
+	idr0 = read_sysreg_s(SYS_ICC_IDR0_EL1);
+	switch (FIELD_GET(ICC_IDR0_EL1_ID_BITS, idr0)) {
+	case ICC_IDR0_EL1_ID_BITS_16BITS:
+		vcpu->arch.vgic_cpu.num_id_bits = 16;
+		break;
+	case ICC_IDR0_EL1_ID_BITS_24BITS:
+		vcpu->arch.vgic_cpu.num_id_bits = 24;
+		break;
+	default:
+		pr_warn("unknown value for id_bits");
+		vcpu->arch.vgic_cpu.num_id_bits = 16;
+	}
+
+	switch (FIELD_GET(ICC_IDR0_EL1_PRI_BITS, idr0)) {
+	case ICC_IDR0_EL1_PRI_BITS_4BITS:
+		vcpu->arch.vgic_cpu.num_pri_bits = 4;
+		break;
+	case ICC_IDR0_EL1_PRI_BITS_5BITS:
+		vcpu->arch.vgic_cpu.num_pri_bits = 5;
+		break;
+	default:
+		pr_warn("unknown value for priority_bits");
+		vcpu->arch.vgic_cpu.num_pri_bits = 4;
+	}
+
+	/*
+	 * We're now ready to run this VCPU so no more changes to the
+	 * PPI config are expected.
+	 */
+	vgic_v5_construct_hmrs(vcpu);
+
+}
+
 int vgic_v5_init(struct kvm *kvm)
 {
 	struct kvm_vcpu *vcpu;
@@ -105,8 +144,30 @@ static u32 vgic_v5_get_effective_priority_mask(struct kvm_vcpu *vcpu)
 	return priority_mask;
 }
 
+static void vgic_v5_construct_hmrs(struct kvm_vcpu *vcpu)
+{
+	/*
+	 * Calculate the PPI HMR to present to the guest (and for
+	 * internal interrupt masking).
+	 */
+	vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_hmr[0] = 0;
+	vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_hmr[1] = 0;
+	for (int i = 0; i < VGIC_V5_NR_PRIVATE_IRQS; ++i) {
+		int reg = i / 64;
+		u64 bit = BIT_ULL(i % 64);
+		struct vgic_irq *irq = &vcpu->arch.vgic_cpu.private_irqs[i];
+
+		raw_spin_lock(&irq->irq_lock);
+
+		if (irq->config == VGIC_CONFIG_LEVEL)
+			vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_hmr[reg] |= bit;
+
+		raw_spin_unlock(&irq->irq_lock);
+	}
+}
+
 static bool vgic_v5_ppi_set_pending_state(struct kvm_vcpu *vcpu,
-					  struct vgic_irq *irq)
+				   struct vgic_irq *irq)
 {
 	struct vgic_v5_cpu_if *cpu_if;
 	const u32 id_bit = BIT_ULL(irq->intid % 64);
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index 66698973b2872..91969b3b80d04 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -385,6 +385,7 @@ void vgic_debug_init(struct kvm *kvm);
 void vgic_debug_destroy(struct kvm *kvm);
 
 int vgic_v5_probe(const struct gic_kvm_info *info);
+void vgic_v5_reset(struct kvm_vcpu *vcpu);
 int vgic_v5_init(struct kvm *kvm);
 int vgic_v5_map_resources(struct kvm *kvm);
 void vgic_v5_set_ppi_ops(struct vgic_irq *irq);
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:43 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:43 +0000
Subject: [PATCH 24/32] KVM: arm64: gic-v5: Mandate architected PPI for PMU
 emulation on GICv5
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-25-sascha.bischoff@arm.com>

Make it mandatory to use the architected PPI when running a GICv5
guest. Attempts to set anything other than the architected PPI (23)
are rejected.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/pmu-emul.c | 14 ++++++++++++--
 include/kvm/arm_pmu.h     |  5 ++++-
 2 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c
index 0baf8e0fe23bd..9925f10aa4fce 100644
--- a/arch/arm64/kvm/pmu-emul.c
+++ b/arch/arm64/kvm/pmu-emul.c
@@ -961,8 +961,13 @@ static int kvm_arm_pmu_v3_init(struct kvm_vcpu *vcpu)
 		if (!vgic_initialized(vcpu->kvm))
 			return -ENODEV;
 
-		if (!kvm_arm_pmu_irq_initialized(vcpu))
-			return -ENXIO;
+		if (!kvm_arm_pmu_irq_initialized(vcpu)) {
+			/* Use the architected irq number for GICv5. */
+			if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5)
+				vcpu->arch.pmu.irq_num = KVM_ARMV8_PMU_GICV5_IRQ;
+			else
+				return -ENXIO;
+		}
 
 		ret = kvm_vgic_set_owner(vcpu, vcpu->arch.pmu.irq_num,
 					 &vcpu->arch.pmu);
@@ -987,6 +992,11 @@ static bool pmu_irq_is_valid(struct kvm *kvm, int irq)
 	unsigned long i;
 	struct kvm_vcpu *vcpu;
 
+	/* On GICv5, the PMUIRQ is architecturally mandated to be PPI 23 */
+	if (kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5 &&
+	    irq != KVM_ARMV8_PMU_GICV5_IRQ)
+		return false;
+
 	kvm_for_each_vcpu(i, vcpu, kvm) {
 		if (!kvm_arm_pmu_irq_initialized(vcpu))
 			continue;
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 96754b51b4116..0a36a3d5c8944 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -12,6 +12,9 @@
 
 #define KVM_ARMV8_PMU_MAX_COUNTERS	32
 
+/* PPI #23 - architecturally specified for GICv5 */
+#define KVM_ARMV8_PMU_GICV5_IRQ		0x20000017
+
 #if IS_ENABLED(CONFIG_HW_PERF_EVENTS) && IS_ENABLED(CONFIG_KVM)
 struct kvm_pmc {
 	u8 idx;	/* index into the pmu->pmc array */
@@ -38,7 +41,7 @@ struct arm_pmu_entry {
 };
 
 bool kvm_supports_guest_pmuv3(void);
-#define kvm_arm_pmu_irq_initialized(v)	((v)->arch.pmu.irq_num >= VGIC_NR_SGIS)
+#define kvm_arm_pmu_irq_initialized(v)	((v)->arch.pmu.irq_num != 0)
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
 void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu, u64 select_idx, u64 val);
 void kvm_pmu_set_counter_value_user(struct kvm_vcpu *vcpu, u64 select_idx, u64 val);
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:43 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:43 +0000
Subject: [PATCH 23/32] KVM: arm64: gic-v5: Bump arch timer for GICv5
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-24-sascha.bischoff@arm.com>

Now that GICv5 has arrived, the arch timer requires some TLC to
address some of the key differences introduced with GICv5.

For PPIs on GICv5, the set_pending_state and queue_irq_unlock irq_ops
are used as AP lists are not required at all for GICv5. The arch timer
also introduces an irq_op - get_input_level. Extend the
arch-timer-provided irq_ops to include the two PPI ops for vgic_v5
guests.

When possible, DVI (Direct Virtual Interrupt) is set for PPIs when
using a vgic_v5, which directly inject the pending state in to the
guest. This means that the host never sees the interrupt for the guest
for these interrupts. This has two impacts.

* First of all, the kvm_cpu_has_pending_timer check is updated to
  explicitly check if the timers are expected to fire.

* Secondly, for mapped timers (which use DVI) they must be masked on
  the host prior to entering a GICv5 guest, and unmasked on the return
  path. This is handled in set_timer_irq_phys_masked.

The final, but rather important, change is that the architected PPIs
for the timers are made mandatory for a GICv5 guest. Attempts to set
them to anything else are actively rejected. Once a vgic_v5 is
initialised, the arch timer PPIs are also explicitly reinitialised to
ensure the correct GICv5-compatible PPIs are used - this also adds in
the GICv5 PPI type to the intid.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/arch_timer.c     | 114 +++++++++++++++++++++++++++-----
 arch/arm64/kvm/vgic/vgic-init.c |   9 +++
 arch/arm64/kvm/vgic/vgic-v5.c   |   6 +-
 include/kvm/arm_arch_timer.h    |   7 +-
 include/kvm/arm_vgic.h          |   5 ++
 5 files changed, 119 insertions(+), 22 deletions(-)

diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c
index 6f033f6644219..b0a5a6c6bf8da 100644
--- a/arch/arm64/kvm/arch_timer.c
+++ b/arch/arm64/kvm/arch_timer.c
@@ -56,6 +56,17 @@ static struct irq_ops arch_timer_irq_ops = {
 	.get_input_level = kvm_arch_timer_get_input_level,
 };
 
+static struct irq_ops arch_timer_irq_ops_vgic_v5 = {
+	.get_input_level = kvm_arch_timer_get_input_level,
+	.set_pending_state = vgic_v5_ppi_set_pending_state,
+	.queue_irq_unlock = vgic_v5_ppi_queue_irq_unlock,
+};
+
+static bool vgic_is_v5(struct kvm_vcpu *vcpu)
+{
+	return vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5;
+}
+
 static int nr_timers(struct kvm_vcpu *vcpu)
 {
 	if (!vcpu_has_nv(vcpu))
@@ -396,7 +407,11 @@ static bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx)
 
 int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
 {
-	return vcpu_has_wfit_active(vcpu) && wfit_delay_ns(vcpu) == 0;
+	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
+	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
+
+	return kvm_timer_should_fire(vtimer) || kvm_timer_should_fire(ptimer) ||
+	       (vcpu_has_wfit_active(vcpu) && wfit_delay_ns(vcpu) == 0);
 }
 
 /*
@@ -657,6 +672,24 @@ static inline void set_timer_irq_phys_active(struct arch_timer_context *ctx, boo
 	WARN_ON(r);
 }
 
+/*
+ * On GICv5 we use DVI for the arch timer PPIs. This is restored later
+ * on as part of vgic_load. Therefore, in order to avoid the guest's
+ * interrupt making it to the host we mask it before entering the
+ * guest and unmask it again when we return.
+ */
+static inline void set_timer_irq_phys_masked(struct arch_timer_context *ctx, bool masked)
+{
+	if (masked) {
+		disable_percpu_irq(ctx->host_timer_irq);
+	} else {
+		if (ctx->host_timer_irq == host_vtimer_irq)
+			enable_percpu_irq(ctx->host_timer_irq, host_vtimer_irq_flags);
+		else
+			enable_percpu_irq(ctx->host_timer_irq, host_ptimer_irq_flags);
+	}
+}
+
 static void kvm_timer_vcpu_load_gic(struct arch_timer_context *ctx)
 {
 	struct kvm_vcpu *vcpu = timer_context_to_vcpu(ctx);
@@ -675,7 +708,10 @@ static void kvm_timer_vcpu_load_gic(struct arch_timer_context *ctx)
 
 	phys_active |= ctx->irq.level;
 
-	set_timer_irq_phys_active(ctx, phys_active);
+	if (!vgic_is_v5(vcpu))
+		set_timer_irq_phys_active(ctx, phys_active);
+	else
+		set_timer_irq_phys_masked(ctx, true);
 }
 
 static void kvm_timer_vcpu_load_nogic(struct kvm_vcpu *vcpu)
@@ -719,10 +755,14 @@ static void kvm_timer_vcpu_load_nested_switch(struct kvm_vcpu *vcpu,
 					      struct timer_map *map)
 {
 	int hw, ret;
+	struct irq_ops *ops;
 
 	if (!irqchip_in_kernel(vcpu->kvm))
 		return;
 
+	ops = vgic_is_v5(vcpu) ? &arch_timer_irq_ops_vgic_v5 :
+				 &arch_timer_irq_ops;
+
 	/*
 	 * We only ever unmap the vtimer irq on a VHE system that runs nested
 	 * virtualization, in which case we have both a valid emul_vtimer,
@@ -741,12 +781,12 @@ static void kvm_timer_vcpu_load_nested_switch(struct kvm_vcpu *vcpu,
 		ret = kvm_vgic_map_phys_irq(vcpu,
 					    map->direct_vtimer->host_timer_irq,
 					    timer_irq(map->direct_vtimer),
-					    &arch_timer_irq_ops);
+					    ops);
 		WARN_ON_ONCE(ret);
 		ret = kvm_vgic_map_phys_irq(vcpu,
 					    map->direct_ptimer->host_timer_irq,
 					    timer_irq(map->direct_ptimer),
-					    &arch_timer_irq_ops);
+					    ops);
 		WARN_ON_ONCE(ret);
 	}
 }
@@ -864,7 +904,8 @@ void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)
 	get_timer_map(vcpu, &map);
 
 	if (static_branch_likely(&has_gic_active_state)) {
-		if (vcpu_has_nv(vcpu))
+		/* We don't do NV on GICv5, yet */
+		if (vcpu_has_nv(vcpu) && !vgic_is_v5(vcpu))
 			kvm_timer_vcpu_load_nested_switch(vcpu, &map);
 
 		kvm_timer_vcpu_load_gic(map.direct_vtimer);
@@ -934,6 +975,15 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
 
 	if (kvm_vcpu_is_blocking(vcpu))
 		kvm_timer_blocking(vcpu);
+
+	/* Unmask again on GICV5 */
+	if (vgic_is_v5(vcpu)) {
+		set_timer_irq_phys_masked(map.direct_vtimer, false);
+
+		if (map.direct_ptimer)
+			set_timer_irq_phys_masked(map.direct_ptimer, false);
+
+	}
 }
 
 void kvm_timer_sync_nested(struct kvm_vcpu *vcpu)
@@ -1034,12 +1084,15 @@ void kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu)
 	if (timer->enabled) {
 		for (int i = 0; i < nr_timers(vcpu); i++)
 			kvm_timer_update_irq(vcpu, false,
-					     vcpu_get_timer(vcpu, i));
+					vcpu_get_timer(vcpu, i));
 
 		if (irqchip_in_kernel(vcpu->kvm)) {
-			kvm_vgic_reset_mapped_irq(vcpu, timer_irq(map.direct_vtimer));
+			kvm_vgic_reset_mapped_irq(
+				vcpu, timer_irq(map.direct_vtimer));
 			if (map.direct_ptimer)
-				kvm_vgic_reset_mapped_irq(vcpu, timer_irq(map.direct_ptimer));
+				kvm_vgic_reset_mapped_irq(
+					vcpu,
+					timer_irq(map.direct_ptimer));
 		}
 	}
 
@@ -1092,10 +1145,19 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
 		      HRTIMER_MODE_ABS_HARD);
 }
 
+/*
+ * This is always called during kvm_arch_init_vm, but will also be
+ * called from kvm_vgic_create if we have a vGICv5.
+ */
 void kvm_timer_init_vm(struct kvm *kvm)
 {
+	/*
+	 * Set up the default PPIs - note that we adjust them based on
+	 * the model of the GIC as GICv5 uses a different way to
+	 * describing interrupts.
+	 */
 	for (int i = 0; i < NR_KVM_TIMERS; i++)
-		kvm->arch.timer_data.ppi[i] = default_ppi[i];
+		kvm->arch.timer_data.ppi[i] = get_vgic_ppi(kvm, default_ppi[i]);
 }
 
 void kvm_timer_cpu_up(void)
@@ -1347,6 +1409,7 @@ static int kvm_irq_init(struct arch_timer_kvm_info *info)
 		}
 
 		arch_timer_irq_ops.flags |= VGIC_IRQ_SW_RESAMPLE;
+		arch_timer_irq_ops_vgic_v5.flags |= VGIC_IRQ_SW_RESAMPLE;
 		WARN_ON(irq_domain_push_irq(domain, host_vtimer_irq,
 					    (void *)TIMER_VTIMER));
 	}
@@ -1497,10 +1560,12 @@ static bool timer_irqs_are_valid(struct kvm_vcpu *vcpu)
 			break;
 
 		/*
-		 * We know by construction that we only have PPIs, so
-		 * all values are less than 32.
+		 * We know by construction that we only have PPIs, so all values
+		 * are less than 32. However, we mask off most of the bits as we
+		 * might be presented with a GICv5 style PPI where the type is
+		 * encoded in the top-bits.
 		 */
-		ppis |= BIT(irq);
+		ppis |= BIT(irq & 0x1f);
 	}
 
 	valid = hweight32(ppis) == nr_timers(vcpu);
@@ -1538,7 +1603,9 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
 {
 	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
 	struct timer_map map;
+	struct irq_ops *ops;
 	int ret;
+	int irq;
 
 	if (timer->enabled)
 		return 0;
@@ -1556,20 +1623,22 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
 		return -EINVAL;
 	}
 
+	ops = vgic_is_v5(vcpu) ? &arch_timer_irq_ops_vgic_v5 :
+				 &arch_timer_irq_ops;
+
 	get_timer_map(vcpu, &map);
 
-	ret = kvm_vgic_map_phys_irq(vcpu,
-				    map.direct_vtimer->host_timer_irq,
-				    timer_irq(map.direct_vtimer),
-				    &arch_timer_irq_ops);
+	irq = timer_irq(map.direct_vtimer);
+	ret = kvm_vgic_map_phys_irq(vcpu, map.direct_vtimer->host_timer_irq,
+				    irq, ops);
 	if (ret)
 		return ret;
 
 	if (map.direct_ptimer) {
+		irq = timer_irq(map.direct_ptimer);
 		ret = kvm_vgic_map_phys_irq(vcpu,
 					    map.direct_ptimer->host_timer_irq,
-					    timer_irq(map.direct_ptimer),
-					    &arch_timer_irq_ops);
+					    irq, ops);
 	}
 
 	if (ret)
@@ -1627,6 +1696,15 @@ int kvm_arm_timer_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
 		goto out;
 	}
 
+	/*
+	 * The PPIs for the Arch Timers arch architecturally defined for
+	 * GICv5. Reject anything that changes them from the specified value.
+	 */
+	if (vgic_is_v5(vcpu) && vcpu->kvm->arch.timer_data.ppi[idx] != irq) {
+		ret = -EINVAL;
+		goto out;
+	}
+
 	/*
 	 * We cannot validate the IRQ unicity before we run, so take it at
 	 * face value. The verdict will be given on first vcpu run, for each
diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index 120f28b329738..5955dcbfd051f 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -177,6 +177,15 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
 		pfr1 |= SYS_FIELD_PREP_ENUM(ID_PFR1_EL1, GIC, GICv3);
 	} else {
 		aa64pfr2 |= SYS_FIELD_PREP_ENUM(ID_AA64PFR2_EL1, GCIE, IMP);
+
+		/*
+		 * We now know that we have a GICv5. The Arch Timer PPI
+		 * interrupts may have been initialised at this stage, but will
+		 * have done so assuming that we have an older GIC, meaning that
+		 * the IntIDs won't be correct. We init them again, and this
+		 * time they will be correct.
+		 */
+		kvm_timer_init_vm(kvm);
 	}
 
 	kvm_set_vm_id_reg(kvm, SYS_ID_AA64PFR0_EL1, aa64pfr0);
diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index a3d52ce066869..1a6c9fc86ed07 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -166,7 +166,7 @@ static void vgic_v5_construct_hmrs(struct kvm_vcpu *vcpu)
 	}
 }
 
-static bool vgic_v5_ppi_set_pending_state(struct kvm_vcpu *vcpu,
+bool vgic_v5_ppi_set_pending_state(struct kvm_vcpu *vcpu,
 				   struct vgic_irq *irq)
 {
 	struct vgic_v5_cpu_if *cpu_if;
@@ -196,8 +196,8 @@ static bool vgic_v5_ppi_set_pending_state(struct kvm_vcpu *vcpu,
  * save/restore, but don't need the PPIs to be queued on a per-VCPU AP
  * list. Therefore, sanity check the state, unlock, and return.
  */
-static bool vgic_v5_ppi_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq,
-					 unsigned long flags)
+bool vgic_v5_ppi_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq,
+				  unsigned long flags)
 	__releases(&irq->irq_lock)
 {
 	struct kvm_vcpu *vcpu;
diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index 7310841f45121..6cb9c20f9db65 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -10,6 +10,8 @@
 #include <linux/clocksource.h>
 #include <linux/hrtimer.h>
 
+#include <linux/irqchip/arm-gic-v5.h>
+
 enum kvm_arch_timers {
 	TIMER_PTIMER,
 	TIMER_VTIMER,
@@ -47,7 +49,7 @@ struct arch_timer_vm_data {
 	u64	poffset;
 
 	/* The PPI for each timer, global to the VM */
-	u8	ppi[NR_KVM_TIMERS];
+	u32	ppi[NR_KVM_TIMERS];
 };
 
 struct arch_timer_context {
@@ -130,6 +132,9 @@ void kvm_timer_init_vhe(void);
 #define timer_vm_data(ctx)		(&(timer_context_to_vcpu(ctx)->kvm->arch.timer_data))
 #define timer_irq(ctx)			(timer_vm_data(ctx)->ppi[arch_timer_ctx_index(ctx)])
 
+#define get_vgic_ppi(k, i) (((k)->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V5) ? \
+				(i) : ((i) | FIELD_PREP(GICV5_HWIRQ_TYPE, GICV5_HWIRQ_TYPE_PPI)))
+
 u64 kvm_arm_timer_read_sysreg(struct kvm_vcpu *vcpu,
 			      enum kvm_arch_timers tmr,
 			      enum kvm_arch_timer_regs treg);
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 099b8ac02999e..6863e19d6eeb7 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -533,6 +533,11 @@ int vgic_v4_load(struct kvm_vcpu *vcpu);
 void vgic_v4_commit(struct kvm_vcpu *vcpu);
 int vgic_v4_put(struct kvm_vcpu *vcpu);
 
+bool vgic_v5_ppi_set_pending_state(struct kvm_vcpu *vcpu,
+				   struct vgic_irq *irq);
+bool vgic_v5_ppi_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq,
+				  unsigned long flags);
+
 bool vgic_state_is_nested(struct kvm_vcpu *vcpu);
 
 /* CPU HP callbacks */
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:44 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:44 +0000
Subject: [PATCH 27/32] KVM: arm64: gic-v5: Introduce kvm_arm_vgic_v5_ops and
 register them
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-28-sascha.bischoff@arm.com>

Only the KVM_DEV_ARM_VGIC_GRP_CTRL->KVM_DEV_ARM_VGIC_CTRL_INIT op is
currently supported. All other ops are stubbed out.

Co-authored-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/vgic/vgic-kvm-device.c | 72 +++++++++++++++++++++++++++
 include/linux/kvm_host.h              |  1 +
 2 files changed, 73 insertions(+)

diff --git a/arch/arm64/kvm/vgic/vgic-kvm-device.c b/arch/arm64/kvm/vgic/vgic-kvm-device.c
index b12ba99a423e5..78903182bba08 100644
--- a/arch/arm64/kvm/vgic/vgic-kvm-device.c
+++ b/arch/arm64/kvm/vgic/vgic-kvm-device.c
@@ -336,6 +336,9 @@ int kvm_register_vgic_device(unsigned long type)
 			break;
 		ret = kvm_vgic_register_its_device();
 		break;
+	case KVM_DEV_TYPE_ARM_VGIC_V5:
+		ret = kvm_register_device_ops(&kvm_arm_vgic_v5_ops,
+					      KVM_DEV_TYPE_ARM_VGIC_V5);
 	}
 
 	return ret;
@@ -715,3 +718,72 @@ struct kvm_device_ops kvm_arm_vgic_v3_ops = {
 	.get_attr = vgic_v3_get_attr,
 	.has_attr = vgic_v3_has_attr,
 };
+
+static int vgic_v5_set_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_ADDR:
+	case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS:
+	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
+		break;
+	case KVM_DEV_ARM_VGIC_GRP_CTRL:
+		switch (attr->attr) {
+		case KVM_DEV_ARM_VGIC_CTRL_INIT:
+			return  vgic_set_common_attr(dev, attr);
+		default:
+			break;
+		}
+	}
+
+	return -ENXIO;
+}
+
+static int vgic_v5_get_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_ADDR:
+	case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS:
+	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
+		break;
+	case KVM_DEV_ARM_VGIC_GRP_CTRL:
+		switch (attr->attr) {
+		case KVM_DEV_ARM_VGIC_CTRL_INIT:
+			return vgic_get_common_attr(dev, attr);
+		default:
+			break;
+		}
+	}
+
+	return -ENXIO;
+}
+
+static int vgic_v5_has_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_ADDR:
+	case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS:
+	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
+		break;
+	case KVM_DEV_ARM_VGIC_GRP_CTRL:
+		switch (attr->attr) {
+		case KVM_DEV_ARM_VGIC_CTRL_INIT:
+			return 0;
+		default:
+			break;
+		}
+	}
+
+	return -ENXIO;
+}
+
+struct kvm_device_ops kvm_arm_vgic_v5_ops = {
+	.name = "kvm-arm-vgic-v5",
+	.create = vgic_create,
+	.destroy = vgic_destroy,
+	.set_attr = vgic_v5_set_attr,
+	.get_attr = vgic_v5_get_attr,
+	.has_attr = vgic_v5_has_attr,
+};
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index d93f75b05ae22..d6082f06ccae3 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -2368,6 +2368,7 @@ void kvm_unregister_device_ops(u32 type);
 extern struct kvm_device_ops kvm_mpic_ops;
 extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
 extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
+extern struct kvm_device_ops kvm_arm_vgic_v5_ops;
 
 #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
 
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:45 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:45 +0000
Subject: [PATCH 29/32] irqchip/gic-v5: Check if impl is virt capable
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-30-sascha.bischoff@arm.com>

Now that there is support for creating a GICv5-based guest with KVM,
check that the hardware itself supports virtualisation, skipping the
setting of struct gic_kvm_info if not.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 drivers/irqchip/irq-gic-v5-irs.c   | 4 ++++
 drivers/irqchip/irq-gic-v5.c       | 5 +++++
 include/linux/irqchip/arm-gic-v5.h | 4 ++++
 3 files changed, 13 insertions(+)

diff --git a/drivers/irqchip/irq-gic-v5-irs.c b/drivers/irqchip/irq-gic-v5-irs.c
index ce2732d649a3e..eebf9f219ac8c 100644
--- a/drivers/irqchip/irq-gic-v5-irs.c
+++ b/drivers/irqchip/irq-gic-v5-irs.c
@@ -744,6 +744,10 @@ static int __init gicv5_irs_init(struct device_node *node)
 	 */
 	if (list_empty(&irs_nodes)) {
 
+		idr = irs_readl_relaxed(irs_data, GICV5_IRS_IDR0);
+		gicv5_global_data.virt_capable =
+			!!FIELD_GET(GICV5_IRS_IDR0_VIRT, idr);
+
 		idr = irs_readl_relaxed(irs_data, GICV5_IRS_IDR1);
 		irs_setup_pri_bits(idr);
 
diff --git a/drivers/irqchip/irq-gic-v5.c b/drivers/irqchip/irq-gic-v5.c
index 41ef286c4d781..f5b17a2557aa1 100644
--- a/drivers/irqchip/irq-gic-v5.c
+++ b/drivers/irqchip/irq-gic-v5.c
@@ -1064,6 +1064,11 @@ static struct gic_kvm_info gic_v5_kvm_info __initdata;
 
 static void __init gic_of_setup_kvm_info(struct device_node *node)
 {
+	if (!gicv5_global_data.virt_capable) {
+		pr_info("GIC implementation is not virtualization capable\n");
+		return;
+	}
+
 	gic_v5_kvm_info.type = GIC_V5;
 
 	/* GIC Virtual CPU interface maintenance interrupt */
diff --git a/include/linux/irqchip/arm-gic-v5.h b/include/linux/irqchip/arm-gic-v5.h
index 9607b36f021ee..36f4c0e8ef8e9 100644
--- a/include/linux/irqchip/arm-gic-v5.h
+++ b/include/linux/irqchip/arm-gic-v5.h
@@ -45,6 +45,7 @@
 /*
  * IRS registers and tables structures
  */
+#define GICV5_IRS_IDR0			0x0000
 #define GICV5_IRS_IDR1			0x0004
 #define GICV5_IRS_IDR2			0x0008
 #define GICV5_IRS_IDR5			0x0014
@@ -65,6 +66,8 @@
 #define GICV5_IRS_IST_STATUSR		0x0194
 #define GICV5_IRS_MAP_L2_ISTR		0x01c0
 
+#define GICV5_IRS_IDR0_VIRT		BIT(6)
+
 #define GICV5_IRS_IDR1_PRIORITY_BITS	GENMASK(22, 20)
 #define GICV5_IRS_IDR1_IAFFID_BITS	GENMASK(19, 16)
 
@@ -280,6 +283,7 @@ struct gicv5_chip_data {
 	u8			cpuif_pri_bits;
 	u8			cpuif_id_bits;
 	u8			irs_pri_bits;
+	bool			virt_capable;
 	struct {
 		__le64 *l1ist_addr;
 		u32 l2_size;
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:44 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:44 +0000
Subject: [PATCH 26/32] KVM: arm64: gic-v5: Hide FEAT_GCIE from NV GICv5 guests
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-27-sascha.bischoff@arm.com>

Currently, NV guests are not supported with GICv5. Therefore, make
sure that FEAT_GCIE is always hidden from such guests.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/nested.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
index cdeeb8f09e722..66404d48405e7 100644
--- a/arch/arm64/kvm/nested.c
+++ b/arch/arm64/kvm/nested.c
@@ -1547,6 +1547,11 @@ u64 limit_nv_id_reg(struct kvm *kvm, u32 reg, u64 val)
 			 ID_AA64PFR1_EL1_MTE);
 		break;
 
+	case SYS_ID_AA64PFR2_EL1:
+		/* GICv5 is not yet supported for NV */
+		val &= ~ID_AA64PFR2_EL1_GCIE;
+		break;
+
 	case SYS_ID_AA64MMFR0_EL1:
 		/* Hide ExS, Secure Memory */
 		val &= ~(ID_AA64MMFR0_EL1_EXS		|
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:46 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:46 +0000
Subject: [PATCH 31/32] Documentation: KVM: Introduce documentation for VGICv5
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-32-sascha.bischoff@arm.com>

Now that it is possible to create a VGICv5 device, provide initial
documentation for it. At this stage, there is little to document.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 Documentation/virt/kvm/devices/arm-vgic-v5.rst | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
 create mode 100644 Documentation/virt/kvm/devices/arm-vgic-v5.rst

diff --git a/Documentation/virt/kvm/devices/arm-vgic-v5.rst b/Documentation/virt/kvm/devices/arm-vgic-v5.rst
new file mode 100644
index 0000000000000..f6591603887bc
--- /dev/null
+++ b/Documentation/virt/kvm/devices/arm-vgic-v5.rst
@@ -0,0 +1,18 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+====================================================
+ARM Virtual Generic Interrupt Controller v5 (VGICv5)
+====================================================
+
+
+Device types supported:
+  - KVM_DEV_TYPE_ARM_VGIC_V5     ARM Generic Interrupt Controller v5.0
+
+Only one VGIC instance may be instantiated through this API.  The created VGIC
+will act as the VM interrupt controller, requiring emulated user-space devices
+to inject interrupts to the VGIC instead of directly to CPUs.
+
+Creating a guest GICv5 device requires a host GICv5 host.  The current VGICv5
+device only supports PPI interrupts.  These can either be injected from emulated
+in-kernel devices (such as the Arch Timer, or PMU), or via the KVM_IRQ_LINE
+ioctl.
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:46 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:46 +0000
Subject: [PATCH 32/32] KVM: arm64: selftests: Introduce a minimal GICv5 PPI
 selftest
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-33-sascha.bischoff@arm.com>

This basic selftest creates a vgic_v5 device (if supported), and tests
that one of the PPI interrupts works as expected with a basic
single-vCPU guest.

Upon starting, the guest enables interrupts. That means that it is
initialising all PPIs to have reasonable priorities, but marking them
as disabled. Then the priority mask in the ICC_PCR_EL1 is set, and
interrupts are enable in ICC_CR0_EL1. At this stage the guest is able
to recieve interrupts. The first IMPDEF PPI (64) is enabled and
kvm_irq_line is used to inject the state into the guest.

The guest's interrupt handler has an explicit WFI in order to ensure
that the guest skips WFI when there are pending and enabled PPI
interrupts.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 tools/testing/selftests/kvm/Makefile.kvm      |   1 +
 tools/testing/selftests/kvm/arm64/vgic_v5.c   | 248 ++++++++++++++++++
 .../selftests/kvm/include/arm64/gic_v5.h      | 148 +++++++++++
 3 files changed, 397 insertions(+)
 create mode 100644 tools/testing/selftests/kvm/arm64/vgic_v5.c
 create mode 100644 tools/testing/selftests/kvm/include/arm64/gic_v5.h

diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index ba5c2b643efaa..5c325b8a0766d 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -173,6 +173,7 @@ TEST_GEN_PROGS_arm64 += arm64/vcpu_width_config
 TEST_GEN_PROGS_arm64 += arm64/vgic_init
 TEST_GEN_PROGS_arm64 += arm64/vgic_irq
 TEST_GEN_PROGS_arm64 += arm64/vgic_lpi_stress
+TEST_GEN_PROGS_arm64 += arm64/vgic_v5
 TEST_GEN_PROGS_arm64 += arm64/vpmu_counter_access
 TEST_GEN_PROGS_arm64 += arm64/no-vgic-v3
 TEST_GEN_PROGS_arm64 += arm64/kvm-uuid
diff --git a/tools/testing/selftests/kvm/arm64/vgic_v5.c b/tools/testing/selftests/kvm/arm64/vgic_v5.c
new file mode 100644
index 0000000000000..5879fbd71042d
--- /dev/null
+++ b/tools/testing/selftests/kvm/arm64/vgic_v5.c
@@ -0,0 +1,248 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/kernel.h>
+#include <sys/syscall.h>
+#include <asm/kvm.h>
+#include <asm/kvm_para.h>
+
+#include <arm64/gic_v5.h>
+
+#include "test_util.h"
+#include "kvm_util.h"
+#include "processor.h"
+#include "vgic.h"
+
+#define NR_VCPUS		1
+
+struct vm_gic {
+	struct kvm_vm *vm;
+	int gic_fd;
+	uint32_t gic_dev_type;
+};
+
+static uint64_t max_phys_size;
+
+#define GUEST_CMD_IRQ_CDIA	10
+#define GUEST_CMD_IRQ_DIEOI	11
+#define GUEST_CMD_IS_AWAKE	12
+#define GUEST_CMD_IS_READY	13
+
+static void guest_irq_handler(struct ex_regs *regs)
+{
+	bool valid;
+	u32 hwirq;
+	u64 ia;
+	static int count;
+
+	/*
+	 * We have pending interrupts. Should never actually enter WFI
+	 * here!
+	 */
+	wfi();
+	GUEST_SYNC(GUEST_CMD_IS_AWAKE);
+
+	ia = gicr_insn(CDIA);
+	valid = GICV5_GICR_CDIA_VALID(ia);
+
+	GUEST_SYNC(GUEST_CMD_IRQ_CDIA);
+
+	if (!valid)
+		return;
+
+	gsb_ack();
+	isb();
+
+	hwirq = FIELD_GET(GICV5_GIC_CDIA_INTID, ia);
+
+	gic_insn(hwirq, CDDI);
+	gic_insn(0, CDEOI);
+
+	++count;
+	GUEST_SYNC(GUEST_CMD_IRQ_DIEOI);
+
+	if (count >= 2)
+		GUEST_DONE();
+
+	/* Ask for the next interrupt to be injected */
+	GUEST_SYNC(GUEST_CMD_IS_READY);
+}
+
+static void guest_code(void)
+{
+	local_irq_disable();
+
+	gicv5_cpu_enable_interrupts();
+	local_irq_enable();
+
+	/* Enable PPI 64 */
+	write_sysreg_s(1UL, SYS_ICC_PPI_ENABLER1_EL1);
+
+	/* Ask for the first interrupt to be injected */
+	GUEST_SYNC(GUEST_CMD_IS_READY);
+
+	/* Loop forever waiting for interrupts */
+	while (1);
+}
+
+
+/* we don't want to assert on run execution, hence that helper */
+static int run_vcpu(struct kvm_vcpu *vcpu)
+{
+	return __vcpu_run(vcpu) ? -errno : 0;
+}
+
+static void vm_gic_destroy(struct vm_gic *v)
+{
+	close(v->gic_fd);
+	kvm_vm_free(v->vm);
+}
+
+static void test_vgic_v5_ppis(uint32_t gic_dev_type)
+{
+	struct ucall uc;
+	struct kvm_vcpu *vcpus[NR_VCPUS];
+	struct vm_gic v;
+	int ret, i;
+
+	v.gic_dev_type = gic_dev_type;
+	v.vm = __vm_create(VM_SHAPE_DEFAULT, NR_VCPUS, 0);
+
+	v.gic_fd = kvm_create_device(v.vm, gic_dev_type);
+
+	for (i = 0; i < NR_VCPUS; ++i)
+		vcpus[i] = vm_vcpu_add(v.vm, i, guest_code);
+
+	vm_init_descriptor_tables(v.vm);
+	vm_install_exception_handler(v.vm, VECTOR_IRQ_CURRENT, guest_irq_handler);
+
+	for (i = 0; i < NR_VCPUS; i++)
+		vcpu_init_descriptor_tables(vcpus[i]);
+
+	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
+			    KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
+
+	while (1) {
+		ret = run_vcpu(vcpus[0]);
+
+		switch (get_ucall(vcpus[0], &uc)) {
+		case UCALL_SYNC:
+			/*
+			 * The guest is ready for the next level
+			 * change. Set high if ready, and lower if it
+			 * has been consumed.
+			 */
+			if (uc.args[1] == GUEST_CMD_IS_READY ||
+			    uc.args[1] == GUEST_CMD_IRQ_DIEOI) {
+				u64 irq = 64;
+				bool level = uc.args[1] == GUEST_CMD_IRQ_DIEOI ? 0 : 1;
+
+				irq &= KVM_ARM_IRQ_NUM_MASK;
+				irq |= KVM_ARM_IRQ_TYPE_PPI << KVM_ARM_IRQ_TYPE_SHIFT;
+
+				_kvm_irq_line(v.vm, irq, level);
+			} else if (uc.args[1] == GUEST_CMD_IS_AWAKE) {
+				pr_info("Guest skipping WFI due to pending IRQ\n");
+			} else if (uc.args[1] == GUEST_CMD_IRQ_CDIA) {
+				pr_info("Guest acknowledged IRQ\n");
+			}
+
+			continue;
+		case UCALL_ABORT:
+			REPORT_GUEST_ASSERT(uc);
+			break;
+		case UCALL_DONE:
+			goto done;
+		default:
+			TEST_FAIL("Unknown ucall %lu", uc.cmd);
+		}
+	}
+
+done:
+	TEST_ASSERT(ret == 0, "Failed to test GICv5 PPIs");
+
+	vm_gic_destroy(&v);
+}
+
+/*
+ * Returns 0 if it's possible to create GIC device of a given type (V2 or V3).
+ */
+int test_kvm_device(uint32_t gic_dev_type)
+{
+	struct kvm_vcpu *vcpus[NR_VCPUS];
+	struct vm_gic v;
+	uint32_t other;
+	int ret;
+
+	v.vm = vm_create_with_vcpus(NR_VCPUS, guest_code, vcpus);
+
+	/* try to create a non existing KVM device */
+	ret = __kvm_test_create_device(v.vm, 0);
+	TEST_ASSERT(ret && errno == ENODEV, "unsupported device");
+
+	/* trial mode */
+	ret = __kvm_test_create_device(v.vm, gic_dev_type);
+	if (ret)
+		return ret;
+	v.gic_fd = kvm_create_device(v.vm, gic_dev_type);
+
+	ret = __kvm_create_device(v.vm, gic_dev_type);
+	TEST_ASSERT(ret < 0 && errno == EEXIST, "create GIC device twice");
+
+	/* try to create the other gic_dev_types */
+	other = KVM_DEV_TYPE_ARM_VGIC_V2;
+	if (!__kvm_test_create_device(v.vm, other)) {
+		ret = __kvm_create_device(v.vm, other);
+		TEST_ASSERT(ret < 0 && (errno == EINVAL || errno == EEXIST),
+				"create GIC device while other version exists");
+	}
+
+	other = KVM_DEV_TYPE_ARM_VGIC_V3;
+	if (!__kvm_test_create_device(v.vm, other)) {
+		ret = __kvm_create_device(v.vm, other);
+		TEST_ASSERT(ret < 0 && (errno == EINVAL || errno == EEXIST),
+				"create GIC device while other version exists");
+	}
+
+	other = KVM_DEV_TYPE_ARM_VGIC_V5;
+	if (!__kvm_test_create_device(v.vm, other)) {
+		ret = __kvm_create_device(v.vm, other);
+		TEST_ASSERT(ret < 0 && (errno == EINVAL || errno == EEXIST),
+				"create GIC device while other version exists");
+	}
+
+	vm_gic_destroy(&v);
+
+	return 0;
+}
+
+void run_tests(uint32_t gic_dev_type)
+{
+	pr_info("Test VGICv5 PPIs\n");
+	test_vgic_v5_ppis(gic_dev_type);
+}
+
+int main(int ac, char **av)
+{
+	int ret;
+	int pa_bits;
+	int cnt_impl = 0;
+
+	test_disable_default_vgic();
+
+	pa_bits = vm_guest_mode_params[VM_MODE_DEFAULT].pa_bits;
+	max_phys_size = 1ULL << pa_bits;
+
+	ret = test_kvm_device(KVM_DEV_TYPE_ARM_VGIC_V5);
+	if (!ret) {
+		pr_info("Running VGIC_V5 tests.\n");
+		run_tests(KVM_DEV_TYPE_ARM_VGIC_V5);
+		cnt_impl++;
+	} else {
+		pr_info("No GICv5 support; Not running GIC_v5 tests.\n");
+		exit(KSFT_SKIP);
+	}
+
+	return 0;
+}
+
+
diff --git a/tools/testing/selftests/kvm/include/arm64/gic_v5.h b/tools/testing/selftests/kvm/include/arm64/gic_v5.h
new file mode 100644
index 0000000000000..5daaa84318bb1
--- /dev/null
+++ b/tools/testing/selftests/kvm/include/arm64/gic_v5.h
@@ -0,0 +1,148 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SELFTESTS_GIC_V5_H
+#define __SELFTESTS_GIC_V5_H
+
+#include <asm/barrier.h>
+#include <asm/sysreg.h>
+
+#include <linux/bitfield.h>
+
+#include "processor.h"
+
+/*
+ * Definitions for GICv5 instructions for the Current Domain
+ */
+#define GICV5_OP_GIC_CDAFF		sys_insn(1, 0, 12, 1, 3)
+#define GICV5_OP_GIC_CDDI		sys_insn(1, 0, 12, 2, 0)
+#define GICV5_OP_GIC_CDDIS		sys_insn(1, 0, 12, 1, 0)
+#define GICV5_OP_GIC_CDHM		sys_insn(1, 0, 12, 2, 1)
+#define GICV5_OP_GIC_CDEN		sys_insn(1, 0, 12, 1, 1)
+#define GICV5_OP_GIC_CDEOI		sys_insn(1, 0, 12, 1, 7)
+#define GICV5_OP_GIC_CDPEND		sys_insn(1, 0, 12, 1, 4)
+#define GICV5_OP_GIC_CDPRI		sys_insn(1, 0, 12, 1, 2)
+#define GICV5_OP_GIC_CDRCFG		sys_insn(1, 0, 12, 1, 5)
+#define GICV5_OP_GICR_CDIA		sys_insn(1, 0, 12, 3, 0)
+#define GICV5_OP_GICR_CDNMIA		sys_insn(1, 0, 12, 3, 1)
+
+/* Definitions for GIC CDAFF */
+#define GICV5_GIC_CDAFF_IAFFID_MASK	GENMASK_ULL(47, 32)
+#define GICV5_GIC_CDAFF_TYPE_MASK	GENMASK_ULL(31, 29)
+#define GICV5_GIC_CDAFF_IRM_MASK	BIT_ULL(28)
+#define GICV5_GIC_CDAFF_ID_MASK		GENMASK_ULL(23, 0)
+
+/* Definitions for GIC CDDI */
+#define GICV5_GIC_CDDI_TYPE_MASK	GENMASK_ULL(31, 29)
+#define GICV5_GIC_CDDI_ID_MASK		GENMASK_ULL(23, 0)
+
+/* Definitions for GIC CDDIS */
+#define GICV5_GIC_CDDIS_TYPE_MASK	GENMASK_ULL(31, 29)
+#define GICV5_GIC_CDDIS_TYPE(r)		FIELD_GET(GICV5_GIC_CDDIS_TYPE_MASK, r)
+#define GICV5_GIC_CDDIS_ID_MASK		GENMASK_ULL(23, 0)
+#define GICV5_GIC_CDDIS_ID(r)		FIELD_GET(GICV5_GIC_CDDIS_ID_MASK, r)
+
+/* Definitions for GIC CDEN */
+#define GICV5_GIC_CDEN_TYPE_MASK	GENMASK_ULL(31, 29)
+#define GICV5_GIC_CDEN_ID_MASK		GENMASK_ULL(23, 0)
+
+/* Definitions for GIC CDHM */
+#define GICV5_GIC_CDHM_HM_MASK		BIT_ULL(32)
+#define GICV5_GIC_CDHM_TYPE_MASK	GENMASK_ULL(31, 29)
+#define GICV5_GIC_CDHM_ID_MASK		GENMASK_ULL(23, 0)
+
+/* Definitions for GIC CDPEND */
+#define GICV5_GIC_CDPEND_PENDING_MASK	BIT_ULL(32)
+#define GICV5_GIC_CDPEND_TYPE_MASK	GENMASK_ULL(31, 29)
+#define GICV5_GIC_CDPEND_ID_MASK	GENMASK_ULL(23, 0)
+
+/* Definitions for GIC CDPRI */
+#define GICV5_GIC_CDPRI_PRIORITY_MASK	GENMASK_ULL(39, 35)
+#define GICV5_GIC_CDPRI_TYPE_MASK	GENMASK_ULL(31, 29)
+#define GICV5_GIC_CDPRI_ID_MASK		GENMASK_ULL(23, 0)
+
+/* Definitions for GIC CDRCFG */
+#define GICV5_GIC_CDRCFG_TYPE_MASK	GENMASK_ULL(31, 29)
+#define GICV5_GIC_CDRCFG_ID_MASK	GENMASK_ULL(23, 0)
+
+/* Definitions for GICR CDIA */
+#define GICV5_GIC_CDIA_VALID_MASK	BIT_ULL(32)
+#define GICV5_GICR_CDIA_VALID(r)	FIELD_GET(GICV5_GIC_CDIA_VALID_MASK, r)
+#define GICV5_GIC_CDIA_TYPE_MASK	GENMASK_ULL(31, 29)
+#define GICV5_GIC_CDIA_ID_MASK		GENMASK_ULL(23, 0)
+#define GICV5_GIC_CDIA_INTID		GENMASK_ULL(31, 0)
+
+/* Definitions for GICR CDNMIA */
+#define GICV5_GIC_CDNMIA_VALID_MASK	BIT_ULL(32)
+#define GICV5_GICR_CDNMIA_VALID(r)	FIELD_GET(GICV5_GIC_CDNMIA_VALID_MASK, r)
+#define GICV5_GIC_CDNMIA_TYPE_MASK	GENMASK_ULL(31, 29)
+#define GICV5_GIC_CDNMIA_ID_MASK	GENMASK_ULL(23, 0)
+
+#define gicr_insn(insn)			read_sysreg_s(GICV5_OP_GICR_##insn)
+#define gic_insn(v, insn)		write_sysreg_s(v, GICV5_OP_GIC_##insn)
+
+#define __GIC_BARRIER_INSN(op0, op1, CRn, CRm, op2, Rt)			\
+	__emit_inst(0xd5000000					|	\
+		    sys_insn((op0), (op1), (CRn), (CRm), (op2))	|	\
+		    ((Rt) & 0x1f))
+
+#define GSB_SYS_BARRIER_INSN		__GIC_BARRIER_INSN(1, 0, 12, 0, 0, 31)
+#define GSB_ACK_BARRIER_INSN		__GIC_BARRIER_INSN(1, 0, 12, 0, 1, 31)
+
+#define gsb_ack()	asm volatile(GSB_ACK_BARRIER_INSN : : : "memory")
+#define gsb_sys()	asm volatile(GSB_SYS_BARRIER_INSN : : : "memory")
+
+#define REPEAT_BYTE(x)	((~0ul / 0xff) * (x))
+
+#define GICV5_IRQ_DEFAULT_PRI 0b10000
+
+void gicv5_ppi_priority_init(void)
+{
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR0_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR1_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR2_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR3_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR4_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR5_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR6_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR7_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR8_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR9_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR10_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR11_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR12_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR13_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR14_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR15_EL1);
+
+	/*
+	 * Context syncronization required to make sure system register writes
+	 * effects are synchronised.
+	 */
+	isb();
+}
+
+void gicv5_cpu_disable_interrupts(void)
+{
+	u64 cr0;
+
+	cr0 = FIELD_PREP(ICC_CR0_EL1_EN, 0);
+	write_sysreg_s(cr0, SYS_ICC_CR0_EL1);
+}
+
+void gicv5_cpu_enable_interrupts(void)
+{
+	u64 cr0, pcr;
+
+	write_sysreg_s(0, SYS_ICC_PPI_ENABLER0_EL1);
+	write_sysreg_s(0, SYS_ICC_PPI_ENABLER1_EL1);
+
+	gicv5_ppi_priority_init();
+
+	pcr = FIELD_PREP(ICC_PCR_EL1_PRIORITY, GICV5_IRQ_DEFAULT_PRI);
+	write_sysreg_s(pcr, SYS_ICC_PCR_EL1);
+
+	cr0 = FIELD_PREP(ICC_CR0_EL1_EN, 1);
+	write_sysreg_s(cr0, SYS_ICC_CR0_EL1);
+}
+
+#endif
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 12 07:22:45 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 12 Dec 2025 15:22:45 +0000
Subject: [PATCH 30/32] KVM: arm64: gic-v5: Probe for GICv5 device
In-Reply-To: <20251212152215.675767-1-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
Message-ID: <20251212152215.675767-31-sascha.bischoff@arm.com>

The basic GICv5 PPI support is now complete. Allow probing for a
native GICv5 rather than just the legacy support.

The implementation doesn't support protected VMs with GICv5 at this
time. Therefore, if KVM has protected mode enabled the native GICv5
init is skipped, but legacy VMs are allowed if the hardware supports
it.

At this stage the GICv5 KVM implementation only supports PPIs, and
doesn't interact with the host IRS at all. This means that there is no
need to check how many concurrent VMs or vCPUs per VM are supported by
the IRS - the PPI support only requires the CPUIF. The support is
artificially limited to VGIC_V5_MAX_CPUS, i.e. 512, vCPUs per VM.

With this change it becomes possible to run basic GICv5-based VMs,
provided that they only use PPIs.

Co-authored-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/vgic/vgic-v5.c | 39 +++++++++++++++++++++++++++--------
 1 file changed, 30 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index 1a6c9fc86ed07..d74cc3543b9a4 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -10,22 +10,13 @@
 
 /*
  * Probe for a vGICv5 compatible interrupt controller, returning 0 on success.
- * Currently only supports GICv3-based VMs on a GICv5 host, and hence only
- * registers a VGIC_V3 device.
  */
 int vgic_v5_probe(const struct gic_kvm_info *info)
 {
 	u64 ich_vtr_el2;
 	int ret;
 
-	if (!cpus_have_final_cap(ARM64_HAS_GICV5_LEGACY))
-		return -ENODEV;
-
 	kvm_vgic_global_state.type = VGIC_V5;
-	kvm_vgic_global_state.has_gcie_v3_compat = true;
-
-	/* We only support v3 compat mode - use vGICv3 limits */
-	kvm_vgic_global_state.max_gic_vcpus = VGIC_V3_MAX_CPUS;
 
 	kvm_vgic_global_state.vcpu_base = 0;
 	kvm_vgic_global_state.vctrl_base = NULL;
@@ -33,6 +24,32 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
 	kvm_vgic_global_state.has_gicv4 = false;
 	kvm_vgic_global_state.has_gicv4_1 = false;
 
+	/*
+	 * GICv5 is currently not supported in Protected mode. Skip the
+	 * registration of GICv5 completely to make sure no guests can create a
+	 * GICv5-based guest.
+	 */
+	if (is_protected_kvm_enabled()) {
+		kvm_info("GICv5-based guests are not supported with pKVM\n");
+		goto skip_v5;
+	}
+
+	kvm_vgic_global_state.max_gic_vcpus = VGIC_V5_MAX_CPUS;
+
+	ret = kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V5);
+	if (ret) {
+		kvm_err("Cannot register GICv5 KVM device.\n");
+		goto skip_v5;
+	}
+
+	kvm_info("GCIE system register CPU interface\n");
+
+skip_v5:
+	/* If we don't support the GICv3 compat mode we're done. */
+	if (!cpus_have_final_cap(ARM64_HAS_GICV5_LEGACY))
+		return 0;
+
+	kvm_vgic_global_state.has_gcie_v3_compat = true;
 	ich_vtr_el2 =  kvm_call_hyp_ret(__vgic_v3_get_gic_config);
 	kvm_vgic_global_state.ich_vtr_el2 = (u32)ich_vtr_el2;
 
@@ -48,6 +65,10 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
 		return ret;
 	}
 
+	/* We potentially limit the max VCPUs further than we need to here */
+	kvm_vgic_global_state.max_gic_vcpus = min(VGIC_V3_MAX_CPUS,
+						  VGIC_V5_MAX_CPUS);
+
 	static_branch_enable(&kvm_vgic_global_state.gicv3_cpuif);
 	kvm_info("GCIE legacy system register CPU interface\n");
 
-- 
2.34.1


From leo.yan at arm.com  Fri Dec 12 07:27:38 2025
From: leo.yan at arm.com (Leo Yan)
Date: Fri, 12 Dec 2025 15:27:38 +0000
Subject: [PATCH 07/19] coresight: trbe: Refactor AUX flag setting
In-Reply-To: <27417fd5-902e-4474-8d60-356a94ac9590@linaro.org>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-7-7da32b076b28@arm.com>
 <a638f74f-94bc-4052-b8e1-e940aca2d4ce@linaro.org>
 <20251210154308.GZ724103@e132581.arm.com>
 <27417fd5-902e-4474-8d60-356a94ac9590@linaro.org>
Message-ID: <20251212152738.GA181228@e132581.arm.com>

On Fri, Dec 12, 2025 at 04:50:52PM +0200, James Clark wrote:

[...]

> > The trace can be stopped on Fill mode (stop on wrap) or Stop on trigger, so
> > it is not (only) about buffer error.  In these cases, even though the trace
> > unit is stopped, the buffer may still have space available, tracing can be
> > directly re-enabled in interrupt handler, thus the COLLISION/PARTIAL flags
> > are better choices.
> 
> I suppose this is the bit that I don't understand. If there is space left
> then why is the stop hit at all?

For instance, the buffer becomes empty in the middle:

   +----------------------------+
   |$$$$$$$|            |$$$$$$$|
   +----------------------------+
   ` base  `wptr        `limit

In this case, the trace unit stops when it reaches the limit.
Meanwhile, the tool might have already read out the old trace data so
we will get some free space, thus no need to set TRUNCATED flag.


From mochs at nvidia.com  Fri Dec 12 07:31:01 2025
From: mochs at nvidia.com (Matt Ochs)
Date: Fri, 12 Dec 2025 15:31:01 +0000
Subject: [RFC PATCH 4/5] firmware: smccc: register as platform driver
In-Reply-To: <20251208221319.1524888-5-vvidwans@nvidia.com>
References: <20251208221319.1524888-1-vvidwans@nvidia.com>
 <20251208221319.1524888-5-vvidwans@nvidia.com>
Message-ID: <7E7A2433-67DC-4AED-94E0-E096DA9CF3EB@nvidia.com>

> On Dec 8, 2025, at 16:13, Vedashree Vidwans <vvidwans at nvidia.com> wrote:
> 
> diff --git a/drivers/firmware/smccc/lfa_fw.c b/drivers/firmware/smccc/lfa_fw.c
> index 0e420cefa260..24916fc53420 100644
> --- a/drivers/firmware/smccc/lfa_fw.c
> +++ b/drivers/firmware/smccc/lfa_fw.c
...
> +
> +static int __init lfa_probe(struct platform_device *pdev)
> +{

WARNING: modpost: vmlinux: section mismatch in reference: lfa_driver+0x0 (section: .data) -> lfa_probe (section: .init.text)

__init is not needed here, please remove.

From james.clark at linaro.org  Fri Dec 12 07:32:17 2025
From: james.clark at linaro.org (James Clark)
Date: Fri, 12 Dec 2025 17:32:17 +0200
Subject: [PATCH v3 00/12] perf cs-etm/arm-spe: Remove hard coded config
 fields
Message-ID: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>

The specific config field that an event format attribute is in is
consistently hard coded, even though the API is supposed to be that the
driver publishes the config field name. To stop this pattern from being
copy pasted and causing problems in the future, replace them all with
calls to a new helper that returns the value that a user set.

This reveals some issues in evsel__set_config_if_unset(). It doesn't
work with sparse bitfields, which are an unused but documented feature.
And it also only writes to the attr.config field. To fix it we need to
start tracking user changes for all config fields and then use existing
helper functions that support sparse bitfields. Some other refactoring
was also required and a test was added.

Signed-off-by: James Clark <james.clark at linaro.org>
---
Changes in v3:
- Fix uninitialized variable warning on GCC
- Fix leak of evlist in test
- Confirm no type punning issues with ubsan (Ian)
- Link to v2: https://lore.kernel.org/r/20251208-james-perf-config-bits-v2-0-4ac0281993b0 at linaro.org

Changes in v2:
- Remove macros in get_config_chgs() and some other refactoring.
- Support sparse bitfields in evsel__set_config_if_unset().
- Always track user changes instead of only when
  'pmu->perf_event_attr_init_default' is set.
- Add a test.
- Don't bail out in cs-etm.c if any format fields are missing (Leo).
- Rename 'guess' to 'synth' (Mike).
- Link to v1: https://lore.kernel.org/r/20251201-james-perf-config-bits-v1-0-22ecbbf8007c at linaro.org

---
James Clark (12):
      perf parse-events: Refactor get_config_terms() to remove macros
      perf evsel: Support sparse fields in evsel__set_config_if_unset()
      perf parse-events: Track all user changed config bits
      perf evsel: apply evsel__set_config_if_unset() to all config fields
      perf evsel: Add a helper to get the value of a config field
      perf parse-events: Always track user config changes
      perf tests: Test evsel__set_config_if_unset() and config change tracking
      perf cs-etm: Make a helper to find the Coresight evsel
      perf cs-etm: Don't use hard coded config bits when setting up ETMCR
      perf cs-etm: Don't use hard coded config bits when setting up TRCCONFIGR
      perf cs-etm: Don't hard code config attribute when configuring the event
      perf arm-spe: Don't hard code config attribute

 tools/perf/arch/arm/util/cs-etm.c    | 193 +++++++++++++++------------
 tools/perf/arch/arm64/util/arm-spe.c |  15 ++-
 tools/perf/tests/pmu.c               |  91 +++++++++++++
 tools/perf/util/evsel.c              |   6 +-
 tools/perf/util/evsel.h              |   2 +
 tools/perf/util/evsel_config.h       |   7 +-
 tools/perf/util/parse-events.c       | 248 ++++++++++++++++++++---------------
 tools/perf/util/pmu.c                | 112 ++++++++++++++--
 8 files changed, 460 insertions(+), 214 deletions(-)
---
base-commit: 2eeb09fe1c5173b659929f92fee4461796ca8c14
change-id: 20251112-james-perf-config-bits-bee7106f0f00

Best regards,
-- 
James Clark <james.clark at linaro.org>



From james.clark at linaro.org  Fri Dec 12 07:32:18 2025
From: james.clark at linaro.org (James Clark)
Date: Fri, 12 Dec 2025 17:32:18 +0200
Subject: [PATCH v3 01/12] perf parse-events: Refactor get_config_terms() to
 remove macros
In-Reply-To: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
References: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
Message-ID: <20251212-james-perf-config-bits-v3-1-aa36a4846776@linaro.org>

The ADD_CONFIG_TERM() macros build the __type argument out of a partial
EVSEL__CONFIG_TERM_x enum name. This means that they can't be called
from a function where __type is a variable and it's also impossible to
grep the codebase to find usages of these enums as they're never typed
in full.

Fix this by removing the macros and replacing them with an
add_config_term() function. It seems the main reason these existed in
the first place was to avoid type punning and to write to a specific
field in the union, but the same thing can be achieved with a single
write to a u64 'val' field.

Running the Perf tests with "-fsanitize=undefined -fno-sanitize-recover"
results in no new issues as a result of this change.

Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/util/evsel_config.h |   1 +
 tools/perf/util/parse-events.c | 146 ++++++++++++++++++++++++-----------------
 2 files changed, 86 insertions(+), 61 deletions(-)

diff --git a/tools/perf/util/evsel_config.h b/tools/perf/util/evsel_config.h
index bcd3a978f0c415a8829d3fa37e9dd6bf664b39f2..685fd8d5c4a88fb8ae601ded60c1fc36dde73403 100644
--- a/tools/perf/util/evsel_config.h
+++ b/tools/perf/util/evsel_config.h
@@ -50,6 +50,7 @@ struct evsel_config_term {
 		u64	      cfg_chg;
 		char	      *str;
 		int	      cpu;
+		u64	      val;
 	} val;
 	bool weak;
 };
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 17c1c36a7bf9a3ec08812c4de700e3a3b3e547cc..46422286380f33a48087e7079a45bb21beb2d573 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1116,105 +1116,107 @@ static int config_attr(struct perf_event_attr *attr,
 	return 0;
 }
 
-static int get_config_terms(const struct parse_events_terms *head_config,
-			    struct list_head *head_terms)
+static struct evsel_config_term *add_config_term(enum evsel_term_type type,
+						 struct list_head *head_terms,
+						 bool weak)
 {
-#define ADD_CONFIG_TERM(__type, __weak)				\
-	struct evsel_config_term *__t;			\
-								\
-	__t = zalloc(sizeof(*__t));				\
-	if (!__t)						\
-		return -ENOMEM;					\
-								\
-	INIT_LIST_HEAD(&__t->list);				\
-	__t->type       = EVSEL__CONFIG_TERM_ ## __type;	\
-	__t->weak	= __weak;				\
-	list_add_tail(&__t->list, head_terms)
-
-#define ADD_CONFIG_TERM_VAL(__type, __name, __val, __weak)	\
-do {								\
-	ADD_CONFIG_TERM(__type, __weak);			\
-	__t->val.__name = __val;				\
-} while (0)
+	struct evsel_config_term *t;
 
-#define ADD_CONFIG_TERM_STR(__type, __val, __weak)		\
-do {								\
-	ADD_CONFIG_TERM(__type, __weak);			\
-	__t->val.str = strdup(__val);				\
-	if (!__t->val.str) {					\
-		zfree(&__t);					\
-		return -ENOMEM;					\
-	}							\
-	__t->free_str = true;					\
-} while (0)
+	t = zalloc(sizeof(*t));
+	if (!t)
+		return NULL;
+
+	INIT_LIST_HEAD(&t->list);
+	t->type = type;
+	t->weak	= weak;
+	list_add_tail(&t->list, head_terms);
 
+	return t;
+}
+
+static int get_config_terms(const struct parse_events_terms *head_config,
+			    struct list_head *head_terms)
+{
 	struct parse_events_term *term;
 
 	list_for_each_entry(term, &head_config->terms, list) {
+		struct evsel_config_term *new_term;
+		enum evsel_term_type new_type;
+		bool str_type = false;
+		u64 val;
+
 		switch (term->type_term) {
 		case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
-			ADD_CONFIG_TERM_VAL(PERIOD, period, term->val.num, term->weak);
+			new_type = EVSEL__CONFIG_TERM_PERIOD;
+			val = term->val.num;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ:
-			ADD_CONFIG_TERM_VAL(FREQ, freq, term->val.num, term->weak);
+			new_type = EVSEL__CONFIG_TERM_FREQ;
+			val = term->val.num;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_TIME:
-			ADD_CONFIG_TERM_VAL(TIME, time, term->val.num, term->weak);
+			new_type = EVSEL__CONFIG_TERM_TIME;
+			val = term->val.num;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_CALLGRAPH:
-			ADD_CONFIG_TERM_STR(CALLGRAPH, term->val.str, term->weak);
+			new_type = EVSEL__CONFIG_TERM_CALLGRAPH;
+			str_type = true;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
-			ADD_CONFIG_TERM_STR(BRANCH, term->val.str, term->weak);
+			new_type = EVSEL__CONFIG_TERM_BRANCH;
+			str_type = true;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
-			ADD_CONFIG_TERM_VAL(STACK_USER, stack_user,
-					    term->val.num, term->weak);
+			new_type = EVSEL__CONFIG_TERM_STACK_USER;
+			val = term->val.num;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_INHERIT:
-			ADD_CONFIG_TERM_VAL(INHERIT, inherit,
-					    term->val.num ? 1 : 0, term->weak);
+			new_type = EVSEL__CONFIG_TERM_INHERIT;
+			val = term->val.num ? 1 : 0;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_NOINHERIT:
-			ADD_CONFIG_TERM_VAL(INHERIT, inherit,
-					    term->val.num ? 0 : 1, term->weak);
+			new_type = EVSEL__CONFIG_TERM_INHERIT;
+			val = term->val.num ? 0 : 1;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_MAX_STACK:
-			ADD_CONFIG_TERM_VAL(MAX_STACK, max_stack,
-					    term->val.num, term->weak);
+			new_type = EVSEL__CONFIG_TERM_MAX_STACK;
+			val = term->val.num;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS:
-			ADD_CONFIG_TERM_VAL(MAX_EVENTS, max_events,
-					    term->val.num, term->weak);
+			new_type = EVSEL__CONFIG_TERM_MAX_EVENTS;
+			val = term->val.num;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_OVERWRITE:
-			ADD_CONFIG_TERM_VAL(OVERWRITE, overwrite,
-					    term->val.num ? 1 : 0, term->weak);
+			new_type = EVSEL__CONFIG_TERM_OVERWRITE;
+			val = term->val.num ? 1 : 0;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE:
-			ADD_CONFIG_TERM_VAL(OVERWRITE, overwrite,
-					    term->val.num ? 0 : 1, term->weak);
+			new_type = EVSEL__CONFIG_TERM_OVERWRITE;
+			val = term->val.num ? 0 : 1;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_DRV_CFG:
-			ADD_CONFIG_TERM_STR(DRV_CFG, term->val.str, term->weak);
+			new_type = EVSEL__CONFIG_TERM_DRV_CFG;
+			str_type = true;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_PERCORE:
-			ADD_CONFIG_TERM_VAL(PERCORE, percore,
-					    term->val.num ? true : false, term->weak);
+			new_type = EVSEL__CONFIG_TERM_PERCORE;
+			val = term->val.num ? true : false;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT:
-			ADD_CONFIG_TERM_VAL(AUX_OUTPUT, aux_output,
-					    term->val.num ? 1 : 0, term->weak);
+			new_type = EVSEL__CONFIG_TERM_AUX_OUTPUT;
+			val = term->val.num ? 1 : 0;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_AUX_ACTION:
-			ADD_CONFIG_TERM_STR(AUX_ACTION, term->val.str, term->weak);
+			new_type = EVSEL__CONFIG_TERM_AUX_ACTION;
+			str_type = true;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE:
-			ADD_CONFIG_TERM_VAL(AUX_SAMPLE_SIZE, aux_sample_size,
-					    term->val.num, term->weak);
+			new_type = EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE;
+			val = term->val.num;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV:
-			ADD_CONFIG_TERM_STR(RATIO_TO_PREV, term->val.str, term->weak);
+			new_type = EVSEL__CONFIG_TERM_RATIO_TO_PREV;
+			str_type = true;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_USER:
 		case PARSE_EVENTS__TERM_TYPE_CONFIG:
@@ -1229,7 +1231,23 @@ do {								\
 		case PARSE_EVENTS__TERM_TYPE_RAW:
 		case PARSE_EVENTS__TERM_TYPE_CPU:
 		default:
-			break;
+			/* Don't add a new term for these ones */
+			continue;
+		}
+
+		new_term = add_config_term(new_type, head_terms, term->weak);
+		if (!new_term)
+			return -ENOMEM;
+
+		if (str_type) {
+			new_term->val.str = strdup(term->val.str);
+			if (!new_term->val.str) {
+				zfree(&new_term);
+				return -ENOMEM;
+			}
+			new_term->free_str = true;
+		} else {
+			new_term->val.val = val;
 		}
 	}
 	return 0;
@@ -1290,10 +1308,16 @@ static int get_config_chgs(struct perf_pmu *pmu, struct parse_events_terms *head
 		}
 	}
 
-	if (bits)
-		ADD_CONFIG_TERM_VAL(CFG_CHG, cfg_chg, bits, false);
+	if (bits) {
+		struct evsel_config_term *new_term;
+
+		new_term = add_config_term(EVSEL__CONFIG_TERM_CFG_CHG,
+					   head_terms, false);
+		if (!new_term)
+			return -ENOMEM;
+		new_term->val.cfg_chg = bits;
+	}
 
-#undef ADD_CONFIG_TERM
 	return 0;
 }
 

-- 
2.34.1



From james.clark at linaro.org  Fri Dec 12 07:32:19 2025
From: james.clark at linaro.org (James Clark)
Date: Fri, 12 Dec 2025 17:32:19 +0200
Subject: [PATCH v3 02/12] perf evsel: Support sparse fields in
 evsel__set_config_if_unset()
In-Reply-To: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
References: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
Message-ID: <20251212-james-perf-config-bits-v3-2-aa36a4846776@linaro.org>

Sparse config fields are technically supported although currently
unused. field_prep() only works for contiguous bitfields so replace it
with pmu_format_value().

Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/util/pmu.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 956ea273c2c7805c0cb504fb7dcf996f79f5588d..2c26c8d76bed920c7b5b43beb867e4d1bcaa2970 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -144,6 +144,8 @@ struct perf_pmu_format {
 };
 
 static int pmu_aliases_parse(struct perf_pmu *pmu);
+static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
+			     bool zero);
 
 static struct perf_pmu_format *perf_pmu__new_format(struct list_head *list, char *name)
 {
@@ -1381,7 +1383,6 @@ bool evsel__is_aux_event(const struct evsel *evsel)
  * the bit pattern. It is shifted into position by this function, so to set
  * something to true, pass 1 for val rather than a pre shifted value.
  */
-#define field_prep(_mask, _val) (((_val) << (ffsll(_mask) - 1)) & (_mask))
 void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
 				const char *config_name, u64 val)
 {
@@ -1398,8 +1399,7 @@ void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
 		return;
 
 	/* Otherwise replace it */
-	evsel->core.attr.config &= ~bits;
-	evsel->core.attr.config |= field_prep(bits, val);
+	pmu_format_value(&bits, val, &evsel->core.attr.config, /*zero=*/true);
 }
 
 static struct perf_pmu_format *

-- 
2.34.1



From james.clark at linaro.org  Fri Dec 12 07:32:20 2025
From: james.clark at linaro.org (James Clark)
Date: Fri, 12 Dec 2025 17:32:20 +0200
Subject: [PATCH v3 03/12] perf parse-events: Track all user changed config
 bits
In-Reply-To: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
References: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
Message-ID: <20251212-james-perf-config-bits-v3-3-aa36a4846776@linaro.org>

Currently we only track which bits were set by the user in attr->config.
But all configN fields should be treated equally as they can all have
default and user overridden values.

Track them all by making get_config_chgs() generic and calling it once
for each config value.

Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/util/evsel.c        |  6 ++-
 tools/perf/util/evsel_config.h |  6 ++-
 tools/perf/util/parse-events.c | 98 +++++++++++++++++++++++-------------------
 tools/perf/util/pmu.c          |  2 +-
 4 files changed, 65 insertions(+), 47 deletions(-)

diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 9cd706f6279313c2cc53eba1adbd45f352090f75..dcadf022405d398bf394b3da7f0db5c81a3ec268 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1242,7 +1242,11 @@ static void evsel__apply_config_terms(struct evsel *evsel,
 		case EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE:
 			/* Already applied by auxtrace */
 			break;
-		case EVSEL__CONFIG_TERM_CFG_CHG:
+		case EVSEL__CONFIG_TERM_USR_CHG_CONFIG:
+		case EVSEL__CONFIG_TERM_USR_CHG_CONFIG1:
+		case EVSEL__CONFIG_TERM_USR_CHG_CONFIG2:
+		case EVSEL__CONFIG_TERM_USR_CHG_CONFIG3:
+		case EVSEL__CONFIG_TERM_USR_CHG_CONFIG4:
 			break;
 		case EVSEL__CONFIG_TERM_RATIO_TO_PREV:
 			rtp_buf = term->val.str;
diff --git a/tools/perf/util/evsel_config.h b/tools/perf/util/evsel_config.h
index 685fd8d5c4a88fb8ae601ded60c1fc36dde73403..7b565d76c0bc4277effbbf950110986b423f571c 100644
--- a/tools/perf/util/evsel_config.h
+++ b/tools/perf/util/evsel_config.h
@@ -27,7 +27,11 @@ enum evsel_term_type {
 	EVSEL__CONFIG_TERM_AUX_OUTPUT,
 	EVSEL__CONFIG_TERM_AUX_ACTION,
 	EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE,
-	EVSEL__CONFIG_TERM_CFG_CHG,
+	EVSEL__CONFIG_TERM_USR_CHG_CONFIG,
+	EVSEL__CONFIG_TERM_USR_CHG_CONFIG1,
+	EVSEL__CONFIG_TERM_USR_CHG_CONFIG2,
+	EVSEL__CONFIG_TERM_USR_CHG_CONFIG3,
+	EVSEL__CONFIG_TERM_USR_CHG_CONFIG4,
 	EVSEL__CONFIG_TERM_RATIO_TO_PREV,
 };
 
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 46422286380f33a48087e7079a45bb21beb2d573..7ef63b808d0542999fd1303b9f94cae68e38030f 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1253,66 +1253,32 @@ static int get_config_terms(const struct parse_events_terms *head_config,
 	return 0;
 }
 
-/*
- * Add EVSEL__CONFIG_TERM_CFG_CHG where cfg_chg will have a bit set for
- * each bit of attr->config that the user has changed.
- */
-static int get_config_chgs(struct perf_pmu *pmu, struct parse_events_terms *head_config,
-			   struct list_head *head_terms)
+static int add_cfg_chg(struct perf_pmu *pmu,
+		       struct parse_events_terms *head_config,
+		       struct list_head *head_terms,
+		       int format_type,
+		       enum parse_events__term_type term_type,
+		       enum evsel_term_type new_term_type)
 {
 	struct parse_events_term *term;
 	u64 bits = 0;
 	int type;
 
 	list_for_each_entry(term, &head_config->terms, list) {
-		switch (term->type_term) {
-		case PARSE_EVENTS__TERM_TYPE_USER:
+		if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER) {
 			type = perf_pmu__format_type(pmu, term->config);
-			if (type != PERF_PMU_FORMAT_VALUE_CONFIG)
+			if (type != format_type)
 				continue;
 			bits |= perf_pmu__format_bits(pmu, term->config);
-			break;
-		case PARSE_EVENTS__TERM_TYPE_CONFIG:
+		} else if (term->type_term == term_type) {
 			bits = ~(u64)0;
-			break;
-		case PARSE_EVENTS__TERM_TYPE_CONFIG1:
-		case PARSE_EVENTS__TERM_TYPE_CONFIG2:
-		case PARSE_EVENTS__TERM_TYPE_CONFIG3:
-		case PARSE_EVENTS__TERM_TYPE_CONFIG4:
-		case PARSE_EVENTS__TERM_TYPE_LEGACY_HARDWARE_CONFIG:
-		case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE_CONFIG:
-		case PARSE_EVENTS__TERM_TYPE_NAME:
-		case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
-		case PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ:
-		case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
-		case PARSE_EVENTS__TERM_TYPE_TIME:
-		case PARSE_EVENTS__TERM_TYPE_CALLGRAPH:
-		case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
-		case PARSE_EVENTS__TERM_TYPE_NOINHERIT:
-		case PARSE_EVENTS__TERM_TYPE_INHERIT:
-		case PARSE_EVENTS__TERM_TYPE_MAX_STACK:
-		case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS:
-		case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE:
-		case PARSE_EVENTS__TERM_TYPE_OVERWRITE:
-		case PARSE_EVENTS__TERM_TYPE_DRV_CFG:
-		case PARSE_EVENTS__TERM_TYPE_PERCORE:
-		case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT:
-		case PARSE_EVENTS__TERM_TYPE_AUX_ACTION:
-		case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE:
-		case PARSE_EVENTS__TERM_TYPE_METRIC_ID:
-		case PARSE_EVENTS__TERM_TYPE_RAW:
-		case PARSE_EVENTS__TERM_TYPE_CPU:
-		case PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV:
-		default:
-			break;
 		}
 	}
 
 	if (bits) {
 		struct evsel_config_term *new_term;
 
-		new_term = add_config_term(EVSEL__CONFIG_TERM_CFG_CHG,
-					   head_terms, false);
+		new_term = add_config_term(new_term_type, head_terms, false);
 		if (!new_term)
 			return -ENOMEM;
 		new_term->val.cfg_chg = bits;
@@ -1321,6 +1287,50 @@ static int get_config_chgs(struct perf_pmu *pmu, struct parse_events_terms *head
 	return 0;
 }
 
+/*
+ * Add EVSEL__CONFIG_TERM_USR_CFG_CONFIGn where cfg_chg will have a bit set for
+ * each bit of attr->configN that the user has changed.
+ */
+static int get_config_chgs(struct perf_pmu *pmu,
+			   struct parse_events_terms *head_config,
+			   struct list_head *head_terms)
+{
+	int ret;
+
+	ret = add_cfg_chg(pmu, head_config, head_terms,
+			  PERF_PMU_FORMAT_VALUE_CONFIG,
+			  PARSE_EVENTS__TERM_TYPE_CONFIG,
+			  EVSEL__CONFIG_TERM_USR_CHG_CONFIG);
+	if (ret)
+		return ret;
+
+	ret = add_cfg_chg(pmu, head_config, head_terms,
+			  PERF_PMU_FORMAT_VALUE_CONFIG1,
+			  PARSE_EVENTS__TERM_TYPE_CONFIG1,
+			  EVSEL__CONFIG_TERM_USR_CHG_CONFIG1);
+	if (ret)
+		return ret;
+
+	ret = add_cfg_chg(pmu, head_config, head_terms,
+			  PERF_PMU_FORMAT_VALUE_CONFIG2,
+			  PARSE_EVENTS__TERM_TYPE_CONFIG2,
+			  EVSEL__CONFIG_TERM_USR_CHG_CONFIG2);
+	if (ret)
+		return ret;
+
+	ret = add_cfg_chg(pmu, head_config, head_terms,
+			  PERF_PMU_FORMAT_VALUE_CONFIG3,
+			  PARSE_EVENTS__TERM_TYPE_CONFIG3,
+			  EVSEL__CONFIG_TERM_USR_CHG_CONFIG3);
+	if (ret)
+		return ret;
+
+	return add_cfg_chg(pmu, head_config, head_terms,
+			   PERF_PMU_FORMAT_VALUE_CONFIG4,
+			   PARSE_EVENTS__TERM_TYPE_CONFIG4,
+			   EVSEL__CONFIG_TERM_USR_CHG_CONFIG4);
+}
+
 int parse_events_add_tracepoint(struct parse_events_state *parse_state,
 				struct list_head *list,
 				const char *sys, const char *event,
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 2c26c8d76bed920c7b5b43beb867e4d1bcaa2970..e02f74d4020c151082ecc434c29c0ec4c2c9b2c8 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -1387,7 +1387,7 @@ void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
 				const char *config_name, u64 val)
 {
 	u64 user_bits = 0, bits;
-	struct evsel_config_term *term = evsel__get_config_term(evsel, CFG_CHG);
+	struct evsel_config_term *term = evsel__get_config_term(evsel, USR_CHG_CONFIG);
 
 	if (term)
 		user_bits = term->val.cfg_chg;

-- 
2.34.1



From james.clark at linaro.org  Fri Dec 12 07:32:21 2025
From: james.clark at linaro.org (James Clark)
Date: Fri, 12 Dec 2025 17:32:21 +0200
Subject: [PATCH v3 04/12] perf evsel: apply evsel__set_config_if_unset() to
 all config fields
In-Reply-To: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
References: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
Message-ID: <20251212-james-perf-config-bits-v3-4-aa36a4846776@linaro.org>

Misleadingly, evsel__set_config_if_unset() only works with the config
field and not config1, config2, etc. This is fine at the moment because
all users of it happen to operate on bits that are in that config field.
Fix it before there are any new users of the function which operate on
bits in different config fields.

In theory it's also possible for a driver to move an existing bit to
another config field and this fixes that scenario too, although this
hasn't happened yet either.

Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/util/pmu.c | 37 +++++++++++++++++++++++++++++++++++--
 1 file changed, 35 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index e02f74d4020c151082ecc434c29c0ec4c2c9b2c8..514cba91f5d99b399d2d6a1e350971660c54a9fc 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -146,6 +146,8 @@ struct perf_pmu_format {
 static int pmu_aliases_parse(struct perf_pmu *pmu);
 static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
 			     bool zero);
+static struct perf_pmu_format *pmu_find_format(const struct list_head *formats,
+					       const char *name);
 
 static struct perf_pmu_format *perf_pmu__new_format(struct list_head *list, char *name)
 {
@@ -1387,7 +1389,38 @@ void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
 				const char *config_name, u64 val)
 {
 	u64 user_bits = 0, bits;
-	struct evsel_config_term *term = evsel__get_config_term(evsel, USR_CHG_CONFIG);
+	struct evsel_config_term *term;
+	struct perf_pmu_format *format = pmu_find_format(&pmu->format, config_name);
+	__u64 *vp;
+
+	if (!format)
+		return;
+
+	switch (format->value) {
+	case PERF_PMU_FORMAT_VALUE_CONFIG:
+		term = evsel__get_config_term(evsel, USR_CHG_CONFIG);
+		vp = &evsel->core.attr.config;
+		break;
+	case PERF_PMU_FORMAT_VALUE_CONFIG1:
+		term = evsel__get_config_term(evsel, USR_CHG_CONFIG1);
+		vp = &evsel->core.attr.config1;
+		break;
+	case PERF_PMU_FORMAT_VALUE_CONFIG2:
+		term = evsel__get_config_term(evsel, USR_CHG_CONFIG2);
+		vp = &evsel->core.attr.config2;
+		break;
+	case PERF_PMU_FORMAT_VALUE_CONFIG3:
+		term = evsel__get_config_term(evsel, USR_CHG_CONFIG3);
+		vp = &evsel->core.attr.config3;
+		break;
+	case PERF_PMU_FORMAT_VALUE_CONFIG4:
+		term = evsel__get_config_term(evsel, USR_CHG_CONFIG4);
+		vp = &evsel->core.attr.config4;
+		break;
+	default:
+		pr_err("Unknown format value: %d\n", format->value);
+		return;
+	}
 
 	if (term)
 		user_bits = term->val.cfg_chg;
@@ -1399,7 +1432,7 @@ void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
 		return;
 
 	/* Otherwise replace it */
-	pmu_format_value(&bits, val, &evsel->core.attr.config, /*zero=*/true);
+	pmu_format_value(&bits, val, vp, /*zero=*/true);
 }
 
 static struct perf_pmu_format *

-- 
2.34.1



From james.clark at linaro.org  Fri Dec 12 07:32:22 2025
From: james.clark at linaro.org (James Clark)
Date: Fri, 12 Dec 2025 17:32:22 +0200
Subject: [PATCH v3 05/12] perf evsel: Add a helper to get the value of a
 config field
In-Reply-To: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
References: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
Message-ID: <20251212-james-perf-config-bits-v3-5-aa36a4846776@linaro.org>

This will be used by aux PMUs to read an already written value for
configuring their events and for also testing.

Its helper pmu_format_unpack() does the opposite of the existing
pmu_format_value() so rename that one to pmu_format_pack() so it's clear
how they are related.

Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/util/evsel.h |  2 ++
 tools/perf/util/pmu.c   | 77 ++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 68 insertions(+), 11 deletions(-)

diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index a08130ff2e47a887b19f6c47bfa9f51e0c40d226..092904a61ec7afdc59253f9b78a9fe8b7cb5bfa7 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -575,6 +575,8 @@ void evsel__uniquify_counter(struct evsel *counter);
 	((((src) >> (pos)) & ((1ull << (size)) - 1)) << (63 - ((pos) + (size) - 1)))
 
 u64 evsel__bitfield_swap_branch_flags(u64 value);
+int evsel__get_config_val(struct perf_pmu *pmu, struct evsel *evsel,
+			  const char *config_name, u64 *val);
 void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
 				const char *config_name, u64 val);
 
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 514cba91f5d99b399d2d6a1e350971660c54a9fc..ef7358ad1fb955f29f2e68b3d0ce711754e4d67c 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -144,8 +144,8 @@ struct perf_pmu_format {
 };
 
 static int pmu_aliases_parse(struct perf_pmu *pmu);
-static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
-			     bool zero);
+static void pmu_format_pack(unsigned long *format, __u64 value, __u64 *v,
+			    bool zero);
 static struct perf_pmu_format *pmu_find_format(const struct list_head *formats,
 					       const char *name);
 
@@ -1377,6 +1377,61 @@ bool evsel__is_aux_event(const struct evsel *evsel)
 	return pmu && pmu->auxtrace;
 }
 
+/*
+ * Unpacks a raw config[n] value using the sparse bitfield that defines a
+ * format attr. For example "config1:1,6-7,44" defines a 4 bit value across non
+ * contiguous bits and this function returns those 4 bits as a value.
+ */
+static u64 pmu_format_unpack(u64 format, u64 config_val)
+{
+	int val_bit = 0;
+	u64 res = 0;
+	int fmt_bit;
+
+	for_each_set_bit(fmt_bit, &format, PERF_PMU_FORMAT_BITS) {
+		if (test_bit(fmt_bit, &config_val))
+			res |= BIT_ULL(val_bit);
+
+		val_bit++;
+	}
+	return res;
+}
+
+int evsel__get_config_val(struct perf_pmu *pmu, struct evsel *evsel,
+			  const char *config_name, u64 *val)
+{
+	struct perf_pmu_format *format = pmu_find_format(&pmu->format, config_name);
+	u64 bits = perf_pmu__format_bits(pmu, config_name);
+
+	if (!format || !bits) {
+		pr_err("Unknown/empty format name: %s\n", config_name);
+		*val = 0;
+		return -EINVAL;
+	}
+
+	switch (format->value) {
+	case PERF_PMU_FORMAT_VALUE_CONFIG:
+		*val = pmu_format_unpack(bits, evsel->core.attr.config);
+		return 0;
+	case PERF_PMU_FORMAT_VALUE_CONFIG1:
+		*val = pmu_format_unpack(bits, evsel->core.attr.config1);
+		return 0;
+	case PERF_PMU_FORMAT_VALUE_CONFIG2:
+		*val = pmu_format_unpack(bits, evsel->core.attr.config2);
+		return 0;
+	case PERF_PMU_FORMAT_VALUE_CONFIG3:
+		*val = pmu_format_unpack(bits, evsel->core.attr.config3);
+		return 0;
+	case PERF_PMU_FORMAT_VALUE_CONFIG4:
+		*val = pmu_format_unpack(bits, evsel->core.attr.config4);
+		return 0;
+	default:
+		pr_err("Unknown format value: %d\n", format->value);
+		*val = 0;
+		return -EINVAL;
+	}
+}
+
 /*
  * Set @config_name to @val as long as the user hasn't already set or cleared it
  * by passing a config term on the command line.
@@ -1432,7 +1487,7 @@ void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
 		return;
 
 	/* Otherwise replace it */
-	pmu_format_value(&bits, val, vp, /*zero=*/true);
+	pmu_format_pack(&bits, val, vp, /*zero=*/true);
 }
 
 static struct perf_pmu_format *
@@ -1477,8 +1532,8 @@ int perf_pmu__format_type(struct perf_pmu *pmu, const char *name)
  * Sets value based on the format definition (format parameter)
  * and unformatted value (value parameter).
  */
-static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
-			     bool zero)
+static void pmu_format_pack(unsigned long *format, __u64 value, __u64 *v,
+			    bool zero)
 {
 	unsigned long fbit, vbit;
 
@@ -1595,23 +1650,23 @@ static int pmu_config_term(const struct perf_pmu *pmu,
 		switch (term->type_term) {
 		case PARSE_EVENTS__TERM_TYPE_CONFIG:
 			assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
-			pmu_format_value(bits, term->val.num, &attr->config, zero);
+			pmu_format_pack(bits, term->val.num, &attr->config, zero);
 			break;
 		case PARSE_EVENTS__TERM_TYPE_CONFIG1:
 			assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
-			pmu_format_value(bits, term->val.num, &attr->config1, zero);
+			pmu_format_pack(bits, term->val.num, &attr->config1, zero);
 			break;
 		case PARSE_EVENTS__TERM_TYPE_CONFIG2:
 			assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
-			pmu_format_value(bits, term->val.num, &attr->config2, zero);
+			pmu_format_pack(bits, term->val.num, &attr->config2, zero);
 			break;
 		case PARSE_EVENTS__TERM_TYPE_CONFIG3:
 			assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
-			pmu_format_value(bits, term->val.num, &attr->config3, zero);
+			pmu_format_pack(bits, term->val.num, &attr->config3, zero);
 			break;
 		case PARSE_EVENTS__TERM_TYPE_CONFIG4:
 			assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
-			pmu_format_value(bits, term->val.num, &attr->config4, zero);
+			pmu_format_pack(bits, term->val.num, &attr->config4, zero);
 			break;
 		case PARSE_EVENTS__TERM_TYPE_LEGACY_HARDWARE_CONFIG:
 			assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
@@ -1749,7 +1804,7 @@ static int pmu_config_term(const struct perf_pmu *pmu,
 		 */
 	}
 
-	pmu_format_value(format->bits, val, vp, zero);
+	pmu_format_pack(format->bits, val, vp, zero);
 	return 0;
 }
 

-- 
2.34.1



From james.clark at linaro.org  Fri Dec 12 07:32:23 2025
From: james.clark at linaro.org (James Clark)
Date: Fri, 12 Dec 2025 17:32:23 +0200
Subject: [PATCH v3 06/12] perf parse-events: Always track user config
 changes
In-Reply-To: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
References: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
Message-ID: <20251212-james-perf-config-bits-v3-6-aa36a4846776@linaro.org>

Requiring the 'pmu->perf_event_attr_init_default' callback to be set to
track user changes is a bit of a trap to fall in. It's hard to see that
this is required when depending on the user change tracking.

It's possible to want all 0 defaults so not set it, but at the same time
still do some programmatic setting of configs with
evsel__set_config_if_unset(). Also if a PMU reverts to 0 defaults and
deletes its existing callback, it will silently break existing uses of
evsel__set_config_if_unset().

One way to fix this would be to assert in evsel__set_config_if_unset()
if the changes weren't tracked, but that would be a possibly untested
runtime failure. Instead, always track it as it's harmless and
simplifies testing too.

Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/util/parse-events.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 7ef63b808d0542999fd1303b9f94cae68e38030f..bee9233437753ff706d6b149503a5e660c3972d8 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1528,12 +1528,8 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state,
 		return -ENOMEM;
 	}
 
-	/*
-	 * When using default config, record which bits of attr->config were
-	 * changed by the user.
-	 */
-	if (pmu->perf_event_attr_init_default &&
-	    get_config_chgs(pmu, &parsed_terms, &config_terms)) {
+	/* Record which bits of attr->config were changed by the user. */
+	if (get_config_chgs(pmu, &parsed_terms, &config_terms)) {
 		parse_events_terms__exit(&parsed_terms);
 		return -ENOMEM;
 	}

-- 
2.34.1



From james.clark at linaro.org  Fri Dec 12 07:32:24 2025
From: james.clark at linaro.org (James Clark)
Date: Fri, 12 Dec 2025 17:32:24 +0200
Subject: [PATCH v3 07/12] perf tests: Test evsel__set_config_if_unset() and
 config change tracking
In-Reply-To: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
References: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
Message-ID: <20251212-james-perf-config-bits-v3-7-aa36a4846776@linaro.org>

Test that evsel__set_config_if_unset() behaves as expected. This also
tests the user config change tracking mechanism as it depends on it.

Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/tests/pmu.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 91 insertions(+)

diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c
index cbded2c6faa4d5b422936e81bde83bc328fcdfe7..9e313a9a44fdebd0d417c7558b15e5db89241867 100644
--- a/tools/perf/tests/pmu.c
+++ b/tools/perf/tests/pmu.c
@@ -192,12 +192,102 @@ static int test__pmu_format(struct test_suite *test __maybe_unused, int subtest
 	}
 	if (attr.config2 != 0x0400000020041d07) {
 		pr_err("Unexpected config2 value %llx\n", attr.config2);
+	}
+
+	ret = TEST_OK;
+err_out:
+	parse_events_terms__exit(&terms);
+	test_pmu_put(dir, pmu);
+	return ret;
+}
+
+static int test__pmu_usr_chgs(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
+{
+	const char *event = "perf-pmu-test/config=15,config1=4,krava02=170,"
+			    "krava03=1,krava11=27,krava12=1/";
+	struct parse_events_terms terms;
+	struct parse_events_error err;
+	LIST_HEAD(config_terms);
+	struct evlist *evlist;
+	struct perf_pmu *pmu;
+	struct evsel *evsel;
+	int ret = TEST_FAIL;
+	char dir[PATH_MAX];
+	u64 val;
+
+	pmu = test_pmu_get(dir, sizeof(dir));
+	if (!pmu)
+		return TEST_FAIL;
+
+	evlist = evlist__new();
+	if (evlist == NULL) {
+		pr_err("Failed allocation");
+		goto err_out;
+	}
+
+	parse_events_terms__init(&terms);
+	ret = parse_events(evlist, event, &err);
+	if (ret) {
+		pr_debug("failed to parse event '%s', err %d\n", event, ret);
+		parse_events_error__print(&err, event);
+		if (parse_events_error__contains(&err, "can't access trace events"))
+			ret = TEST_SKIP;
 		goto err_out;
 	}
+	evsel = evlist__first(evlist);
+
+	/*
+	 * Set via config=15, krava01 bits 0-1
+	 * Set via config1=4, krava11 bit 1
+	 * Set values: krava02=170, krava03=1, krava11=27, krava12=1
+	 *
+	 * Test that already set values aren't overwritten.
+	 */
+	evsel__set_config_if_unset(pmu, evsel, "krava01", 16);
+	evsel__get_config_val(pmu, evsel, "krava01", &val);
+	TEST_ASSERT_EQUAL("krava01 overwritten", (int) val, (15 & 0b11));
+
+	evsel__set_config_if_unset(pmu, evsel, "krava11", 45);
+	evsel__get_config_val(pmu, evsel, "krava11", &val);
+	TEST_ASSERT_EQUAL("krava11 overwritten", (int) val, (27 | (4 << 1)));
+
+	evsel__set_config_if_unset(pmu, evsel, "krava02", 32);
+	evsel__get_config_val(pmu, evsel, "krava02", &val);
+	TEST_ASSERT_EQUAL("krava02 overwritten", (int) val, 170);
+
+	evsel__set_config_if_unset(pmu, evsel, "krava03", 0);
+	evsel__get_config_val(pmu, evsel, "krava03", &val);
+	TEST_ASSERT_EQUAL("krava03 overwritten", (int) val, 1);
+
+	/*
+	 * krava13 doesn't have any bits set by either krava13= or config1=
+	 * but setting _any_ raw value for config1 implies that krava13
+	 * shouldn't be overwritten. So it's value should remain as 0.
+	 */
+	evsel__set_config_if_unset(pmu, evsel, "krava13", 5);
+	evsel__get_config_val(pmu, evsel, "krava13", &val);
+	TEST_ASSERT_EQUAL("krava13 overwritten", (int) val, 0);
+
+	/*
+	 * Unset values: krava21, krava22, krava23
+	 *
+	 * Test that unset values are overwritten.
+	 */
+	evsel__set_config_if_unset(pmu, evsel, "krava21", 13905);
+	evsel__get_config_val(pmu, evsel, "krava21", &val);
+	TEST_ASSERT_EQUAL("krava21 not overwritten", (int) val, 13905);
+
+	evsel__set_config_if_unset(pmu, evsel, "krava22", 11);
+	evsel__get_config_val(pmu, evsel, "krava22", &val);
+	TEST_ASSERT_EQUAL("krava22 not overwritten", (int) val, 11);
 
+	evsel__set_config_if_unset(pmu, evsel, "krava23", 0);
+	evsel__get_config_val(pmu, evsel, "krava23", &val);
+	TEST_ASSERT_EQUAL("krava23 not overwritten", (int) val, 0);
 	ret = TEST_OK;
 err_out:
 	parse_events_terms__exit(&terms);
+	evlist__delete(evlist);
 	test_pmu_put(dir, pmu);
 	return ret;
 }
@@ -539,6 +629,7 @@ static struct test_case tests__pmu[] = {
 	TEST_CASE("PMU name combining", name_len),
 	TEST_CASE("PMU name comparison", name_cmp),
 	TEST_CASE("PMU cmdline match", pmu_match),
+	TEST_CASE("PMU user config changes", pmu_usr_chgs),
 	{	.name = NULL, }
 };
 

-- 
2.34.1



From james.clark at linaro.org  Fri Dec 12 07:32:25 2025
From: james.clark at linaro.org (James Clark)
Date: Fri, 12 Dec 2025 17:32:25 +0200
Subject: [PATCH v3 08/12] perf cs-etm: Make a helper to find the Coresight
 evsel
In-Reply-To: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
References: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
Message-ID: <20251212-james-perf-config-bits-v3-8-aa36a4846776@linaro.org>

This pattern occurs a few times and we'll add another one later, so add
a helper function for it.

Reviewed-by: Leo Yan <leo.yan at arm.com>
Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/arch/arm/util/cs-etm.c | 50 +++++++++++++++++++++------------------
 1 file changed, 27 insertions(+), 23 deletions(-)

diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
index ea891d12f8f40beebf8dee1d3db71cad701f5666..22c6272e8c367e5671809771b841c5babe2d5282 100644
--- a/tools/perf/arch/arm/util/cs-etm.c
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -302,6 +302,19 @@ static int cs_etm_set_sink_attr(struct perf_pmu *pmu,
 	return 0;
 }
 
+static struct evsel *cs_etm_get_evsel(struct evlist *evlist,
+				      struct perf_pmu *cs_etm_pmu)
+{
+	struct evsel *evsel;
+
+	evlist__for_each_entry(evlist, evsel) {
+		if (evsel->core.attr.type == cs_etm_pmu->type)
+			return evsel;
+	}
+
+	return NULL;
+}
+
 static int cs_etm_recording_options(struct auxtrace_record *itr,
 				    struct evlist *evlist,
 				    struct record_opts *opts)
@@ -476,29 +489,21 @@ static int cs_etm_recording_options(struct auxtrace_record *itr,
 
 static u64 cs_etm_get_config(struct auxtrace_record *itr)
 {
-	u64 config = 0;
 	struct cs_etm_recording *ptr =
 			container_of(itr, struct cs_etm_recording, itr);
 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
 	struct evlist *evlist = ptr->evlist;
-	struct evsel *evsel;
+	struct evsel *evsel = cs_etm_get_evsel(evlist, cs_etm_pmu);
 
-	evlist__for_each_entry(evlist, evsel) {
-		if (evsel->core.attr.type == cs_etm_pmu->type) {
-			/*
-			 * Variable perf_event_attr::config is assigned to
-			 * ETMv3/PTM.  The bit fields have been made to match
-			 * the ETMv3.5 ETRMCR register specification.  See the
-			 * PMU_FORMAT_ATTR() declarations in
-			 * drivers/hwtracing/coresight/coresight-perf.c for
-			 * details.
-			 */
-			config = evsel->core.attr.config;
-			break;
-		}
-	}
-
-	return config;
+	/*
+	 * Variable perf_event_attr::config is assigned to
+	 * ETMv3/PTM.  The bit fields have been made to match
+	 * the ETMv3.5 ETRMCR register specification.  See the
+	 * PMU_FORMAT_ATTR() declarations in
+	 * drivers/hwtracing/coresight/coresight-perf.c for
+	 * details.
+	 */
+	return evsel ? evsel->core.attr.config : 0;
 }
 
 #ifndef BIT
@@ -832,12 +837,11 @@ static int cs_etm_snapshot_start(struct auxtrace_record *itr)
 {
 	struct cs_etm_recording *ptr =
 			container_of(itr, struct cs_etm_recording, itr);
-	struct evsel *evsel;
+	struct evsel *evsel = cs_etm_get_evsel(ptr->evlist, ptr->cs_etm_pmu);
+
+	if (evsel)
+		return evsel__disable(evsel);
 
-	evlist__for_each_entry(ptr->evlist, evsel) {
-		if (evsel->core.attr.type == ptr->cs_etm_pmu->type)
-			return evsel__disable(evsel);
-	}
 	return -EINVAL;
 }
 

-- 
2.34.1



From james.clark at linaro.org  Fri Dec 12 07:32:26 2025
From: james.clark at linaro.org (James Clark)
Date: Fri, 12 Dec 2025 17:32:26 +0200
Subject: [PATCH v3 09/12] perf cs-etm: Don't use hard coded config bits
 when setting up ETMCR
In-Reply-To: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
References: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
Message-ID: <20251212-james-perf-config-bits-v3-9-aa36a4846776@linaro.org>

Perf only looks at attr.config when determining what was programmed into
ETMCR. These bits could theoretically be in any of the config fields.
Add a generic helper to find the value of any named format field in any
config field and then use it to get the attributes relevant to ETMCR.

The kernel will also stop publishing the ETMCR register bits in a header
[1] so preempt that by defining them here.

Move field_prep() to util.h so we can define it along side field_get().
Unfortunately FIELD_PREP() and FIELD_GET() from the kernel can't be used
as they require the mask to be a compile time constant.

[1]: https://lore.kernel.org/linux-arm-kernel/20251128-james-cs-syncfreq-v8-10-4d319764cc58 at linaro.org/
Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/arch/arm/util/cs-etm.c | 35 ++++++++++++++++++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)

diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
index 22c6272e8c367e5671809771b841c5babe2d5282..a5135b743e6f18789026323ea75b2a78d6495d73 100644
--- a/tools/perf/arch/arm/util/cs-etm.c
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -68,6 +68,12 @@ static const char * const metadata_ete_ro[] = {
 
 enum cs_etm_version { CS_NOT_PRESENT, CS_ETMV3, CS_ETMV4, CS_ETE };
 
+
+/* ETMv3 ETMCR register bits */
+#define ETMCR_CYC_ACC		BIT(12)
+#define ETMCR_TIMESTAMP_EN	BIT(28)
+#define ETMCR_RETURN_STACK	BIT(29)
+
 static bool cs_etm_is_ete(struct perf_pmu *cs_etm_pmu, struct perf_cpu cpu);
 static int cs_etm_get_ro(struct perf_pmu *pmu, struct perf_cpu cpu, const char *path, __u64 *val);
 static bool cs_etm_pmu_path_exists(struct perf_pmu *pmu, struct perf_cpu cpu, const char *path);
@@ -487,6 +493,33 @@ static int cs_etm_recording_options(struct auxtrace_record *itr,
 	return err;
 }
 
+static u64 cs_etm_synth_etmcr(struct auxtrace_record *itr)
+{
+	struct cs_etm_recording *ptr =
+		container_of(itr, struct cs_etm_recording, itr);
+	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
+	struct evsel *evsel = cs_etm_get_evsel(ptr->evlist, cs_etm_pmu);
+	u64 etmcr = 0;
+	u64 val;
+
+	if (!evsel)
+		return 0;
+
+	/*
+	 * Synthesize what the kernel programmed into ETMCR based on
+	 * what options the event was opened with. This doesn't have to be
+	 * complete or 100% accurate, not all bits used by OpenCSD anyway.
+	 */
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "cycacc", &val) && val)
+		etmcr |= ETMCR_CYC_ACC;
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "timestamp", &val) && val)
+		etmcr |= ETMCR_TIMESTAMP_EN;
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "retstack", &val) && val)
+		etmcr |= ETMCR_RETURN_STACK;
+
+	return etmcr;
+}
+
 static u64 cs_etm_get_config(struct auxtrace_record *itr)
 {
 	struct cs_etm_recording *ptr =
@@ -746,7 +779,7 @@ static void cs_etm_get_metadata(struct perf_cpu cpu, u32 *offset,
 	case CS_ETMV3:
 		magic = __perf_cs_etmv3_magic;
 		/* Get configuration register */
-		info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr);
+		info->priv[*offset + CS_ETM_ETMCR] = cs_etm_synth_etmcr(itr);
 		/* traceID set to legacy value in case new perf running on old system */
 		info->priv[*offset + CS_ETM_ETMTRACEIDR] = cs_etm_get_legacy_trace_id(cpu);
 		/* Get read-only information from sysFS */

-- 
2.34.1



From james.clark at linaro.org  Fri Dec 12 07:32:27 2025
From: james.clark at linaro.org (James Clark)
Date: Fri, 12 Dec 2025 17:32:27 +0200
Subject: [PATCH v3 10/12] perf cs-etm: Don't use hard coded config bits
 when setting up TRCCONFIGR
In-Reply-To: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
References: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
Message-ID: <20251212-james-perf-config-bits-v3-10-aa36a4846776@linaro.org>

Perf only looks at attr.config when determining what was programmed into
TRCCONFIGR. These bits could theoretically be in any of the config
fields. Use the evsel__get_config_val() helper so it's agnostic to
which config field they are in.

The kernel will also stop publishing the TRCCONFIGR register bits in a
header [1] so preempt that by defining them here.

[1]: https://lore.kernel.org/linux-arm-kernel/20251128-james-cs-syncfreq-v8-10-4d319764cc58 at linaro.org/
Reviewed-by: Leo Yan <leo.yan at arm.com>
Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/arch/arm/util/cs-etm.c | 79 +++++++++++++++++----------------------
 1 file changed, 34 insertions(+), 45 deletions(-)

diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
index a5135b743e6f18789026323ea75b2a78d6495d73..4a606b1e90f227aef9915e90439b2a024eeabcfe 100644
--- a/tools/perf/arch/arm/util/cs-etm.c
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -68,6 +68,14 @@ static const char * const metadata_ete_ro[] = {
 
 enum cs_etm_version { CS_NOT_PRESENT, CS_ETMV3, CS_ETMV4, CS_ETE };
 
+/* ETMv4 CONFIGR register bits */
+#define TRCCONFIGR_BB		BIT(3)
+#define TRCCONFIGR_CCI		BIT(4)
+#define TRCCONFIGR_CID		BIT(6)
+#define TRCCONFIGR_VMID		BIT(7)
+#define TRCCONFIGR_TS		BIT(11)
+#define TRCCONFIGR_RS		BIT(12)
+#define TRCCONFIGR_VMIDOPT	BIT(15)
 
 /* ETMv3 ETMCR register bits */
 #define ETMCR_CYC_ACC		BIT(12)
@@ -520,56 +528,37 @@ static u64 cs_etm_synth_etmcr(struct auxtrace_record *itr)
 	return etmcr;
 }
 
-static u64 cs_etm_get_config(struct auxtrace_record *itr)
+static u64 cs_etmv4_synth_trcconfigr(struct auxtrace_record *itr)
 {
+	u64 trcconfigr = 0;
 	struct cs_etm_recording *ptr =
-			container_of(itr, struct cs_etm_recording, itr);
+		container_of(itr, struct cs_etm_recording, itr);
 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
-	struct evlist *evlist = ptr->evlist;
-	struct evsel *evsel = cs_etm_get_evsel(evlist, cs_etm_pmu);
-
-	/*
-	 * Variable perf_event_attr::config is assigned to
-	 * ETMv3/PTM.  The bit fields have been made to match
-	 * the ETMv3.5 ETRMCR register specification.  See the
-	 * PMU_FORMAT_ATTR() declarations in
-	 * drivers/hwtracing/coresight/coresight-perf.c for
-	 * details.
-	 */
-	return evsel ? evsel->core.attr.config : 0;
-}
-
-#ifndef BIT
-#define BIT(N) (1UL << (N))
-#endif
+	struct evsel *evsel = cs_etm_get_evsel(ptr->evlist, cs_etm_pmu);
+	u64 val;
 
-static u64 cs_etmv4_get_config(struct auxtrace_record *itr)
-{
-	u64 config = 0;
-	u64 config_opts = 0;
+	if (!evsel)
+		return 0;
 
 	/*
-	 * The perf event variable config bits represent both
-	 * the command line options and register programming
-	 * bits in ETMv3/PTM. For ETMv4 we must remap options
-	 * to real bits
+	 * Synthesize what the kernel programmed into TRCCONFIGR based on
+	 * what options the event was opened with. This doesn't have to be
+	 * complete or 100% accurate, not all bits used by OpenCSD anyway.
 	 */
-	config_opts = cs_etm_get_config(itr);
-	if (config_opts & BIT(ETM_OPT_CYCACC))
-		config |= BIT(ETM4_CFG_BIT_CYCACC);
-	if (config_opts & BIT(ETM_OPT_CTXTID))
-		config |= BIT(ETM4_CFG_BIT_CTXTID);
-	if (config_opts & BIT(ETM_OPT_TS))
-		config |= BIT(ETM4_CFG_BIT_TS);
-	if (config_opts & BIT(ETM_OPT_RETSTK))
-		config |= BIT(ETM4_CFG_BIT_RETSTK);
-	if (config_opts & BIT(ETM_OPT_CTXTID2))
-		config |= BIT(ETM4_CFG_BIT_VMID) |
-			  BIT(ETM4_CFG_BIT_VMID_OPT);
-	if (config_opts & BIT(ETM_OPT_BRANCH_BROADCAST))
-		config |= BIT(ETM4_CFG_BIT_BB);
-
-	return config;
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "cycacc", &val) && val)
+		trcconfigr |= TRCCONFIGR_CCI;
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "contextid1", &val) && val)
+		trcconfigr |= TRCCONFIGR_CID;
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "timestamp", &val) && val)
+		trcconfigr |= TRCCONFIGR_TS;
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "retstack", &val) && val)
+		trcconfigr |= TRCCONFIGR_RS;
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "contextid2", &val) && val)
+		trcconfigr |= TRCCONFIGR_VMID | TRCCONFIGR_VMIDOPT;
+	if (!evsel__get_config_val(cs_etm_pmu, evsel, "branch_broadcast", &val) && val)
+		trcconfigr |= TRCCONFIGR_BB;
+
+	return trcconfigr;
 }
 
 static size_t
@@ -691,7 +680,7 @@ static void cs_etm_save_etmv4_header(__u64 data[], struct auxtrace_record *itr,
 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
 
 	/* Get trace configuration register */
-	data[CS_ETMV4_TRCCONFIGR] = cs_etmv4_get_config(itr);
+	data[CS_ETMV4_TRCCONFIGR] = cs_etmv4_synth_trcconfigr(itr);
 	/* traceID set to legacy version, in case new perf running on older system */
 	data[CS_ETMV4_TRCTRACEIDR] = cs_etm_get_legacy_trace_id(cpu);
 
@@ -723,7 +712,7 @@ static void cs_etm_save_ete_header(__u64 data[], struct auxtrace_record *itr, st
 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
 
 	/* Get trace configuration register */
-	data[CS_ETE_TRCCONFIGR] = cs_etmv4_get_config(itr);
+	data[CS_ETE_TRCCONFIGR] = cs_etmv4_synth_trcconfigr(itr);
 	/* traceID set to legacy version, in case new perf running on older system */
 	data[CS_ETE_TRCTRACEIDR] = cs_etm_get_legacy_trace_id(cpu);
 

-- 
2.34.1



From james.clark at linaro.org  Fri Dec 12 07:32:28 2025
From: james.clark at linaro.org (James Clark)
Date: Fri, 12 Dec 2025 17:32:28 +0200
Subject: [PATCH v3 11/12] perf cs-etm: Don't hard code config attribute
 when configuring the event
In-Reply-To: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
References: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
Message-ID: <20251212-james-perf-config-bits-v3-11-aa36a4846776@linaro.org>

These instances of hard coded config attributes are used for configuring
and validating the event options. Use the config attribute that's
published by the driver by replacing the open coded operations with
evsel__get_config_val() and evsel__set_config_if_unset().

Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/arch/arm/util/cs-etm.c | 57 +++++++++++++++++++--------------------
 1 file changed, 28 insertions(+), 29 deletions(-)

diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
index 4a606b1e90f227aef9915e90439b2a024eeabcfe..bfb573cb587893b7d91b92fed4c61f421392fbcf 100644
--- a/tools/perf/arch/arm/util/cs-etm.c
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -103,13 +103,14 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
 				      struct perf_cpu cpu)
 {
 	int err;
-	__u64 val;
-	u64 contextid = evsel->core.attr.config &
-		(perf_pmu__format_bits(cs_etm_pmu, "contextid") |
-		 perf_pmu__format_bits(cs_etm_pmu, "contextid1") |
-		 perf_pmu__format_bits(cs_etm_pmu, "contextid2"));
+	u64 ctxt, ctxt1, ctxt2;
+	__u64 trcidr2;
 
-	if (!contextid)
+	evsel__get_config_val(cs_etm_pmu, evsel, "contextid", &ctxt);
+	evsel__get_config_val(cs_etm_pmu, evsel, "contextid1", &ctxt1);
+	evsel__get_config_val(cs_etm_pmu, evsel, "contextid2", &ctxt2);
+
+	if (!ctxt && !ctxt1 && !ctxt2)
 		return 0;
 
 	/* Not supported in etmv3 */
@@ -120,12 +121,11 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
 	}
 
 	/* Get a handle on TRCIDR2 */
-	err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2], &val);
+	err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2], &trcidr2);
 	if (err)
 		return err;
 
-	if (contextid &
-	    perf_pmu__format_bits(cs_etm_pmu, "contextid1")) {
+	if (ctxt1) {
 		/*
 		 * TRCIDR2.CIDSIZE, bit [9-5], indicates whether contextID
 		 * tracing is supported:
@@ -133,15 +133,14 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
 		 *  0b00100 Maximum of 32-bit Context ID size.
 		 *  All other values are reserved.
 		 */
-		if (BMVAL(val, 5, 9) != 0x4) {
+		if (BMVAL(trcidr2, 5, 9) != 0x4) {
 			pr_err("%s: CONTEXTIDR_EL1 isn't supported, disable with %s/contextid1=0/\n",
 			       CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME);
 			return -EINVAL;
 		}
 	}
 
-	if (contextid &
-	    perf_pmu__format_bits(cs_etm_pmu, "contextid2")) {
+	if (ctxt2) {
 		/*
 		 * TRCIDR2.VMIDOPT[30:29] != 0 and
 		 * TRCIDR2.VMIDSIZE[14:10] == 0b00100 (32bit virtual contextid)
@@ -149,7 +148,7 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
 		 * virtual context id is < 32bit.
 		 * Any value of VMIDSIZE >= 4 (i.e, > 32bit) is fine for us.
 		 */
-		if (!BMVAL(val, 29, 30) || BMVAL(val, 10, 14) < 4) {
+		if (!BMVAL(trcidr2, 29, 30) || BMVAL(trcidr2, 10, 14) < 4) {
 			pr_err("%s: CONTEXTIDR_EL2 isn't supported, disable with %s/contextid2=0/\n",
 			       CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME);
 			return -EINVAL;
@@ -163,10 +162,11 @@ static int cs_etm_validate_timestamp(struct perf_pmu *cs_etm_pmu, struct evsel *
 				     struct perf_cpu cpu)
 {
 	int err;
-	__u64 val;
+	u64 val;
+	__u64 trcidr0;
 
-	if (!(evsel->core.attr.config &
-	      perf_pmu__format_bits(cs_etm_pmu, "timestamp")))
+	evsel__get_config_val(cs_etm_pmu, evsel, "timestamp", &val);
+	if (!val)
 		return 0;
 
 	if (cs_etm_get_version(cs_etm_pmu, cpu) == CS_ETMV3) {
@@ -176,7 +176,7 @@ static int cs_etm_validate_timestamp(struct perf_pmu *cs_etm_pmu, struct evsel *
 	}
 
 	/* Get a handle on TRCIRD0 */
-	err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0], &val);
+	err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0], &trcidr0);
 	if (err)
 		return err;
 
@@ -187,10 +187,9 @@ static int cs_etm_validate_timestamp(struct perf_pmu *cs_etm_pmu, struct evsel *
 	 *  0b00110 Implementation supports a maximum timestamp of 48bits.
 	 *  0b01000 Implementation supports a maximum timestamp of 64bits.
 	 */
-	val &= GENMASK(28, 24);
-	if (!val) {
+	trcidr0 &= GENMASK(28, 24);
+	if (!trcidr0)
 		return -EINVAL;
-	}
 
 	return 0;
 }
@@ -273,16 +272,20 @@ static int cs_etm_parse_snapshot_options(struct auxtrace_record *itr,
 	return 0;
 }
 
+/*
+ * The sink name format "@sink_name" is used, lookup the sink by name to convert
+ * to "sinkid=sink_hash" format.
+ *
+ * If the user has already manually provided a hash then "sinkid" isn't
+ * overwritten. If neither are provided then the driver will pick the best sink.
+ */
 static int cs_etm_set_sink_attr(struct perf_pmu *pmu,
 				struct evsel *evsel)
 {
 	char msg[BUFSIZ], path[PATH_MAX], *sink;
 	struct evsel_config_term *term;
-	int ret = -EINVAL;
 	u32 hash;
-
-	if (evsel->core.attr.config2 & GENMASK(31, 0))
-		return 0;
+	int ret;
 
 	list_for_each_entry(term, &evsel->config_terms, list) {
 		if (term->type != EVSEL__CONFIG_TERM_DRV_CFG)
@@ -305,14 +308,10 @@ static int cs_etm_set_sink_attr(struct perf_pmu *pmu,
 			return ret;
 		}
 
-		evsel->core.attr.config2 |= hash;
+		evsel__set_config_if_unset(pmu, evsel, "sinkid", hash);
 		return 0;
 	}
 
-	/*
-	 * No sink was provided on the command line - allow the CoreSight
-	 * system to look for a default
-	 */
 	return 0;
 }
 

-- 
2.34.1



From james.clark at linaro.org  Fri Dec 12 07:32:29 2025
From: james.clark at linaro.org (James Clark)
Date: Fri, 12 Dec 2025 17:32:29 +0200
Subject: [PATCH v3 12/12] perf arm-spe: Don't hard code config attribute
In-Reply-To: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
References: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
Message-ID: <20251212-james-perf-config-bits-v3-12-aa36a4846776@linaro.org>

Use the config attribute that's published by the driver instead of
hard coding "attr.config".

Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/arch/arm64/util/arm-spe.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c
index d5ec1408d0aec7e0d39a2cae7ad73694950ab67b..6c3dc97fde308cf4a1f289fab5101ead2765b140 100644
--- a/tools/perf/arch/arm64/util/arm-spe.c
+++ b/tools/perf/arch/arm64/util/arm-spe.c
@@ -256,7 +256,7 @@ static __u64 arm_spe_pmu__sample_period(const struct perf_pmu *arm_spe_pmu)
 
 static void arm_spe_setup_evsel(struct evsel *evsel, struct perf_cpu_map *cpus)
 {
-	u64 bit;
+	u64 pa_enable_bit;
 
 	evsel->core.attr.freq = 0;
 	evsel->core.attr.sample_period = arm_spe_pmu__sample_period(evsel->pmu);
@@ -288,9 +288,10 @@ static void arm_spe_setup_evsel(struct evsel *evsel, struct perf_cpu_map *cpus)
 	 * inform that the resulting output's SPE samples contain physical addresses
 	 * where applicable.
 	 */
-	bit = perf_pmu__format_bits(evsel->pmu, "pa_enable");
-	if (evsel->core.attr.config & bit)
-		evsel__set_sample_bit(evsel, PHYS_ADDR);
+
+	if (!evsel__get_config_val(evsel->pmu, evsel, "pa_enable", &pa_enable_bit))
+		if (pa_enable_bit)
+			evsel__set_sample_bit(evsel, PHYS_ADDR);
 }
 
 static int arm_spe_setup_aux_buffer(struct record_opts *opts)
@@ -397,6 +398,7 @@ static int arm_spe_recording_options(struct auxtrace_record *itr,
 	struct perf_cpu_map *cpus = evlist->core.user_requested_cpus;
 	bool discard = false;
 	int err;
+	u64 discard_bit;
 
 	sper->evlist = evlist;
 
@@ -425,9 +427,8 @@ static int arm_spe_recording_options(struct auxtrace_record *itr,
 	evlist__for_each_entry_safe(evlist, tmp, evsel) {
 		if (evsel__is_aux_event(evsel)) {
 			arm_spe_setup_evsel(evsel, cpus);
-			if (evsel->core.attr.config &
-			    perf_pmu__format_bits(evsel->pmu, "discard"))
-				discard = true;
+			if (!evsel__get_config_val(evsel->pmu, evsel, "discard", &discard_bit))
+				discard = !!discard_bit;
 		}
 	}
 

-- 
2.34.1



From mochs at nvidia.com  Fri Dec 12 07:37:00 2025
From: mochs at nvidia.com (Matt Ochs)
Date: Fri, 12 Dec 2025 15:37:00 +0000
Subject: [RFC PATCH 5/5] firmware: smccc: lfa: refresh fw details
In-Reply-To: <20251208221319.1524888-6-vvidwans@nvidia.com>
References: <20251208221319.1524888-1-vvidwans@nvidia.com>
 <20251208221319.1524888-6-vvidwans@nvidia.com>
Message-ID: <44635975-326C-4DD2-BCEC-EB04188E954A@nvidia.com>

> On Dec 8, 2025, at 16:13, Vedashree Vidwans <vvidwans at nvidia.com> wrote:
> 
> diff --git a/drivers/firmware/smccc/lfa_fw.c b/drivers/firmware/smccc/lfa_fw.c
> index 24916fc53420..334090708405 100644
> --- a/drivers/firmware/smccc/lfa_fw.c
> +++ b/drivers/firmware/smccc/lfa_fw.c
...
> + /*
> + * Pass 2:
> + *    If current FW components number is more than previous list, add new component nodes.
> + */
> + for (node_idx; node_idx < num_of_components; node_idx++) {

drivers/firmware/smccc/lfa_fw.c: In function ?update_fw_images_tree?:
drivers/firmware/smccc/lfa_fw.c:554:9: warning: statement with no effect [-Wunused-value]
  554 |         for (node_idx; node_idx < num_of_components; node_idx++) {
      |         ^~~

Please drop ?node_idx? from the initializer statement.


From smostafa at google.com  Fri Dec 12 07:37:43 2025
From: smostafa at google.com (Mostafa Saleh)
Date: Fri, 12 Dec 2025 15:37:43 +0000
Subject: [PATCH v5 04/27] iommu/io-pgtable-arm: Factor kernel specific
 code out
In-Reply-To: <20251128164541.GA812105@ziepe.ca>
References: <20251117184815.1027271-1-smostafa@google.com>
 <20251117184815.1027271-5-smostafa@google.com>
 <20251128164541.GA812105@ziepe.ca>
Message-ID: <aTw2x1UlldJGVA4Y@google.com>

On Fri, Nov 28, 2025 at 12:45:41PM -0400, Jason Gunthorpe wrote:
> On Mon, Nov 17, 2025 at 06:47:51PM +0000, Mostafa Saleh wrote:
> > Some of the used APIs are only part of the kernel and are not
> > available in the hypervisor, factor those out:
> > - alloc/free memory
> 
> Why not provide the iommu-pages API for the hypervisor environment?
> 
> Same for virt_to_phys, that could be moved into an iommu-pages wrapper
> too..

I guess that's possible, but then we would have to stub dma_map/unmap,
which might a bit ugly. I will look more into it.

> 
> I want to change other parts of the driver to use iommu-pages in the
> long run as well, so putting the abstraction there is probably more
> valuable than this.
> 
> Also the genericpt stuff is merged, should you (eventually?) be making
> a pKVM hypervisor specific set of page table functions? Eg if all you
> are doing is mirroring the host stage 2 I think you can build
> something much more efficient...

Most of the code is re-used from the io-pgtable-arm, so when that is
converted to genericpt, it should get to the hypervisor also.
The only hypervisor specific logic is the memory allocation, virt/phys
conversion and CMOs, I can look more into painting those, we don?t have
to change much.

I have some plans to add support for sharing the CPU stage-2 page table,
which is going to be complicated as it requires changes to the core
hypervisor hyp/pgtable.c code, which will be in a subsequent series.
However, I reckon that we would keep the shadowing logic as not all
SMMUv3/platforms are capable of sharing page tables.

Thanks,
Mostafa

> 
> Jason
> 


From smostafa at google.com  Fri Dec 12 07:41:33 2025
From: smostafa at google.com (Mostafa Saleh)
Date: Fri, 12 Dec 2025 15:41:33 +0000
Subject: [PATCH v5 05/27] iommu/arm-smmu-v3: Split code with hyp
In-Reply-To: <20251128164655.GB812105@ziepe.ca>
References: <20251117184815.1027271-1-smostafa@google.com>
 <20251117184815.1027271-6-smostafa@google.com>
 <20251128164655.GB812105@ziepe.ca>
Message-ID: <aTw3rS1Pp-Iqq7yU@google.com>

On Fri, Nov 28, 2025 at 12:46:55PM -0400, Jason Gunthorpe wrote:
> On Mon, Nov 17, 2025 at 06:47:52PM +0000, Mostafa Saleh wrote:
> > The KVM SMMUv3 driver would re-use some of the cmdq code inside
> > the hypervisor, move these functions to a new common c file that
> > is shared between the host kernel and the hypervisor.
> > 
> > Signed-off-by: Mostafa Saleh <smostafa at google.com>
> > ---
> >  drivers/iommu/arm/arm-smmu-v3/Makefile        |   2 +-
> >  .../arm/arm-smmu-v3/arm-smmu-v3-common-lib.c  | 114 +++++++++++++
> >  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 161 ------------------
> >  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  61 +++++++
> 
> I would think these inlines should go in some -common.h instead of
> arm-smmu-v3.h for better clarity, and ideally pkvm stuff does not
> include arm-smmu-v3.h at all?

My thought was that we use ?arm-smmu-v3.h? to avoid moving a lot of
code and messing up the git history, but I have no strong opinion,
splitting is fine also.

Thanks,
Mostafa

> 
> Jason


From liujianfeng1994 at gmail.com  Fri Dec 12 07:41:32 2025
From: liujianfeng1994 at gmail.com (Jianfeng Liu)
Date: Fri, 12 Dec 2025 23:41:32 +0800
Subject: [PATCH] media: rkvdec: set ctx->image_fmt in rkvdec_s_capture_fmt
Message-ID: <20251212154138.3042300-1-liujianfeng1994@gmail.com>

ctx->image_fmt is initialized as RKVDEC_IMG_FMT_ANY at
rkvdec_s_output_fmt, and get set at rkvdec_s_ctrl when userspace sends
SPS info via VIDIOC_S_EXT_CTRLS. This works fine with gstreamer because
it sends SPS info to kernel driver before requesting capture queue bufs.

But chromium requests capture queue bufs first and then sends SPS info
to kernel, then rkvdec_s_ctrl will return -EBUSY, and the video is
displayed green.

Chromium calls VIDIOC_S_FMT to capture queue instead before requesting
capture queue bufs, so setting ctx->image_fmt in rkvdec_s_capture_fmt
will make rkvdec_s_ctrl return 0 when the first SPS info sent to driver.

Signed-off-by: Jianfeng Liu <liujianfeng1994 at gmail.com>
Fixes: d35c64eccf3b1 ("media: rkvdec: Add get_image_fmt ops")
---

 drivers/media/platform/rockchip/rkvdec/rkvdec.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index 5af9aa5ab353..e7939d604f64 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -537,6 +537,18 @@ static int rkvdec_s_capture_fmt(struct file *file, void *priv,
 		return ret;
 
 	ctx->decoded_fmt = *f;
+
+	u32 fourcc = f->fmt.pix_mp.pixelformat;
+
+	if (fourcc == V4L2_PIX_FMT_NV12)
+		ctx->image_fmt = RKVDEC_IMG_FMT_420_8BIT;
+	else if (fourcc == V4L2_PIX_FMT_NV15)
+		ctx->image_fmt = RKVDEC_IMG_FMT_420_10BIT;
+	else if (fourcc == V4L2_PIX_FMT_NV16)
+		ctx->image_fmt = RKVDEC_IMG_FMT_422_8BIT;
+	else if (fourcc == V4L2_PIX_FMT_NV20)
+		ctx->image_fmt = RKVDEC_IMG_FMT_422_10BIT;
+
 	return 0;
 }
 
-- 
2.43.0



From smostafa at google.com  Fri Dec 12 07:42:15 2025
From: smostafa at google.com (Mostafa Saleh)
Date: Fri, 12 Dec 2025 15:42:15 +0000
Subject: [PATCH v5 07/27] iommu/arm-smmu-v3: Move IDR parsing to common
 functions
In-Reply-To: <20251128164816.GC812105@ziepe.ca>
References: <20251117184815.1027271-1-smostafa@google.com>
 <20251117184815.1027271-8-smostafa@google.com>
 <20251128164816.GC812105@ziepe.ca>
Message-ID: <aTw31-mh8z81yi4Y@google.com>

On Fri, Nov 28, 2025 at 12:48:16PM -0400, Jason Gunthorpe wrote:
> On Mon, Nov 17, 2025 at 06:47:54PM +0000, Mostafa Saleh wrote:
> > Move parsing of IDRs to functions so that it can be re-used
> > from the hypervisor.
> > 
> > Signed-off-by: Mostafa Saleh <smostafa at google.com>
> > ---
> >  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 112 +++-----------------
> >  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 111 +++++++++++++++++++
> >  2 files changed, 126 insertions(+), 97 deletions(-)
> 
> I don't see that this slow path stuff needs to be inlined?
> 
> +10 to my prior remark to not dump all the huge inlines in the main
> header.

They are inline as they are defined in the header file, otherwise they
get defined multiple times.

I am ok with adding a new common file.

Thanks,
Mostafa

> 
> Jason


From james.clark at linaro.org  Fri Dec 12 07:52:07 2025
From: james.clark at linaro.org (James Clark)
Date: Fri, 12 Dec 2025 17:52:07 +0200
Subject: [PATCH 07/19] coresight: trbe: Refactor AUX flag setting
In-Reply-To: <20251212152738.GA181228@e132581.arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-7-7da32b076b28@arm.com>
 <a638f74f-94bc-4052-b8e1-e940aca2d4ce@linaro.org>
 <20251210154308.GZ724103@e132581.arm.com>
 <27417fd5-902e-4474-8d60-356a94ac9590@linaro.org>
 <20251212152738.GA181228@e132581.arm.com>
Message-ID: <26b61e11-1dfa-4be1-8d58-06e35fb04d64@linaro.org>



On 12/12/2025 17:27, Leo Yan wrote:
> On Fri, Dec 12, 2025 at 04:50:52PM +0200, James Clark wrote:
> 
> [...]
> 
>>> The trace can be stopped on Fill mode (stop on wrap) or Stop on trigger, so
>>> it is not (only) about buffer error.  In these cases, even though the trace
>>> unit is stopped, the buffer may still have space available, tracing can be
>>> directly re-enabled in interrupt handler, thus the COLLISION/PARTIAL flags
>>> are better choices.
>>
>> I suppose this is the bit that I don't understand. If there is space left
>> then why is the stop hit at all?
> 
> For instance, the buffer becomes empty in the middle:
> 
>     +----------------------------+
>     |$$$$$$$|            |$$$$$$$|
>     +----------------------------+
>     ` base  `wptr        `limit
> 
> In this case, the trace unit stops when it reaches the limit.
> Meanwhile, the tool might have already read out the old trace data so
> we will get some free space, thus no need to set TRUNCATED flag.

Hmmm I see, I still think that means that Perf is being too slow and 
disabling the event wouldn't be that bad.

Also isn't there a very small chance to hit this? I'm wondering if you 
ever saw PARTIAL flags in practice?

I think the following all have to be true:

  * 3 out of 4 sections were full on the last interrupt
  * Perf hadn't managed to finish reading even 1 section in that time
  * The last section fills up
  * Perf had managed to finish reading 1 section between the time of
    the previous interrupt and the hard stop

There would have to be quite a high variability in read speed to make 
that possible. Maybe it happens and it's worthwhile optimizing for. The 
comments could explain it better if we do decide to keep it.



From smostafa at google.com  Fri Dec 12 07:53:13 2025
From: smostafa at google.com (Mostafa Saleh)
Date: Fri, 12 Dec 2025 15:53:13 +0000
Subject: [PATCH v5 14/27] iommu/arm-smmu-v3: Support probing KVM emulated
 devices
In-Reply-To: <20251128165616.GD812105@ziepe.ca>
References: <20251117184815.1027271-1-smostafa@google.com>
 <20251117184815.1027271-15-smostafa@google.com>
 <20251128165616.GD812105@ziepe.ca>
Message-ID: <aTw6afum4eqr5_e7@google.com>

On Fri, Nov 28, 2025 at 12:56:16PM -0400, Jason Gunthorpe wrote:
> On Mon, Nov 17, 2025 at 06:48:01PM +0000, Mostafa Saleh wrote:
> > When KVM runs in protected mode, and CONFIG_ARM_SMMU_V3_PKVM
> > is enabled, it will manage the SMMUv3 HW using trap and emulate
> > and present emulated SMMUs to the host kernel.
> > 
> > In that case, those SMMUs will be on the aux bus, so make it
> > possibly to the driver to probe those devices.
> > Otherwise, everything else is the same as the KVM emulation
> > complies with the architecutre, so the driver doesn't need
> > to be modified.
> > 
> > Suggested-by: Jason Gunthorpe <jgg at ziepe.ca>
> > Signed-off-by: Mostafa Saleh <smostafa at google.com>
> > ---
> >  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 58 +++++++++++++++++++++
> >  1 file changed, 58 insertions(+)
> > 
> > diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> > index 7b1bd0658910..851d47bedae6 100644
> > --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> > +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> > @@ -11,6 +11,7 @@
> >  
> >  #include <linux/acpi.h>
> >  #include <linux/acpi_iort.h>
> > +#include <linux/auxiliary_bus.h>
> >  #include <linux/bitops.h>
> >  #include <linux/crash_dump.h>
> >  #include <linux/delay.h>
> > @@ -4604,6 +4605,63 @@ static struct platform_driver arm_smmu_driver = {
> >  module_driver(arm_smmu_driver, platform_driver_register,
> >  	      arm_smmu_driver_unregister);
> >  
> > +#ifdef CONFIG_ARM_SMMU_V3_PKVM
> > +/*
> > + * Now we have 2 devices, the aux device bound to this driver, and pdev
> > + * which is the physical platform device.
> > + * This part is a bit hairy but it works due to the fact that
> > + * CONFIG_ARM_SMMU_V3_PKVM forces both drivers to be built in.
> > + * The struct device for the SMMU is used in the following cases:
> > + * 1) Printing using dev_*()
> > + * 2) DMA memory alloc (dmam_alloc_coherent, devm_*)
> > + * 3) Requesting resources (iomem, sysfs)
> > + * 4) Probing firmware info (of_node, fwnode...)
> > + * 5) Dealing with abstracted HW resources (irqs, MSIs, RPM)
> > + * 6) Saving/reading driver data
> > + * For point 4) and 5) we must use the platform device.
> > + * For, 1) pdev is better for debuggability.
> > + * For 2), 3), 6) it's better to use the bound device.
> > + * However that doesn't really work:
> > + * For 2) The DMA allocation using the aux device will fail, as
> > + * we need to setup some device DMA attrs (mask), to match the
> > + * platform.
> > + * For 6) Some contexts from the pdev as MSI, it needs to use the
> > + * drvdata.
> > + * Based on the following:
> > + * 1- Both drivers must be built-in to enable this (enforced by Kconfig),
> > + *    which means that none of them can be removed.
> > + * 2- The KVM driver doesn't do anythng at runtime and doesn't use drvdata.
> > + * We can keep the driver simple and to claim the platform device in all cases.
> > + */
> 
> It is OK I guess, I wouldn't insist you change it, but I think it is
> kind of gross. Registering the iommu driver against the platform
> device instead of the aux is pretty ugly and denies userspace the
> ability to see that the hypervisor is sitting in there through the
> sysfs topology.

Yes, that?s why I was wondering if it?s better to keep this as a platform
driver and create the aux devices for the parent(KVM) but that was really
complicated to handle the probe ordering.

I will give this another though before v6.

> 
> Not sure why the commentary about built-in though, what does that have
> to do with anything? If the aux driver is not built in then it will
> just module load later and everything should be fine?

As at the moment the KVM driver doesn?t use drvdata(nor any device
resources) and the main driver(aux) does, but if that was a module, we
can?t know which version does what (if that changes in the future,
although unlikely).

Thanks,
Mostafa

> 
> Jason


From joey.gouly at arm.com  Fri Dec 12 08:00:42 2025
From: joey.gouly at arm.com (Joey Gouly)
Date: Fri, 12 Dec 2025 16:00:42 +0000
Subject: [PATCH v2 6/6] KVM: arm64: Honor UX/PX attributes for EL2 S1
 mappings
In-Reply-To: <86tsxxng5b.wl-maz@kernel.org>
References: <20251210173024.561160-1-maz@kernel.org>
 <20251210173024.561160-7-maz@kernel.org>
 <20251211151810.GA867614@e124191.cambridge.arm.com>
 <86tsxxng5b.wl-maz@kernel.org>
Message-ID: <20251212160042.GA978851@e124191.cambridge.arm.com>

On Thu, Dec 11, 2025 at 04:21:20PM +0000, Marc Zyngier wrote:
> On Thu, 11 Dec 2025 15:18:51 +0000,
> Joey Gouly <joey.gouly at arm.com> wrote:
> > 
> > Question,
> > 
> > On Wed, Dec 10, 2025 at 05:30:24PM +0000, Marc Zyngier wrote:
> > > Now that we potentially have two bits to deal with when setting
> > > execution permissions, make sure we correctly handle them when both
> > > when building the page tables and when reading back from them.
> > > 
> > > Reported-by: Alexandru Elisei <alexandru.elisei at arm.com>
> > > Signed-off-by: Marc Zyngier <maz at kernel.org>
> > > ---
> > >  arch/arm64/include/asm/kvm_pgtable.h | 12 +++---------
> > >  arch/arm64/kvm/hyp/pgtable.c         | 24 +++++++++++++++++++++---
> > >  2 files changed, 24 insertions(+), 12 deletions(-)
> > > 
> > > diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h
> > > index be68b89692065..095e6b73740a6 100644
> > > --- a/arch/arm64/include/asm/kvm_pgtable.h
> > > +++ b/arch/arm64/include/asm/kvm_pgtable.h
> > > @@ -87,15 +87,9 @@ typedef u64 kvm_pte_t;
> > >  
> > >  #define KVM_PTE_LEAF_ATTR_HI_SW		GENMASK(58, 55)
> > >  
> > > -#define __KVM_PTE_LEAF_ATTR_HI_S1_XN	BIT(54)
> > > -#define __KVM_PTE_LEAF_ATTR_HI_S1_UXN	BIT(54)
> > > -#define __KVM_PTE_LEAF_ATTR_HI_S1_PXN	BIT(53)
> > > -
> > > -#define KVM_PTE_LEAF_ATTR_HI_S1_XN					\
> > > -	({ cpus_have_final_cap(ARM64_KVM_HVHE) ?			\
> > > -			(__KVM_PTE_LEAF_ATTR_HI_S1_UXN |		\
> > > -			 __KVM_PTE_LEAF_ATTR_HI_S1_PXN) :		\
> > > -			__KVM_PTE_LEAF_ATTR_HI_S1_XN; })
> > > +#define KVM_PTE_LEAF_ATTR_HI_S1_XN	BIT(54)
> > > +#define KVM_PTE_LEAF_ATTR_HI_S1_UXN	BIT(54)
> > > +#define KVM_PTE_LEAF_ATTR_HI_S1_PXN	BIT(53)
> > >  
> > >  #define KVM_PTE_LEAF_ATTR_HI_S2_XN	GENMASK(54, 53)
> > >  
> > > diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
> > > index e0bd6a0172729..97c0835d25590 100644
> > > --- a/arch/arm64/kvm/hyp/pgtable.c
> > > +++ b/arch/arm64/kvm/hyp/pgtable.c
> > > @@ -342,6 +342,9 @@ static int hyp_set_prot_attr(enum kvm_pgtable_prot prot, kvm_pte_t *ptep)
> > >  	if (!(prot & KVM_PGTABLE_PROT_R))
> > >  		return -EINVAL;
> > >  
> > > +	if (!cpus_have_final_cap(ARM64_KVM_HVHE))
> > > +		prot &= ~KVM_PGTABLE_PROT_UX;
> > 
> > Trying to understand this part. We don't consider KVM_PGTABLE_PROT_UX below
> > when !HVHE, and we don't set it in kvm_pgtable_hyp_pte_prot() when !HVHE
> > either, so can it ever actually be set?
> 
> Because KVM_PGTABLE_PROT_X, which is directly passed by the high-level
> code, is defined as such:
> 
> 	KVM_PGTABLE_PROT_X			= KVM_PGTABLE_PROT_PX	|
> 						  KVM_PGTABLE_PROT_UX,
> 

This was the main missing part!

> We *could* make that value dependent on HVHE, but since that's in an
> enum, it is pretty ugly to do (not impossible though).
> 
> But it is in the following code that this becomes useful...
> 
> >
> > Otherwise LGTM!
> > 
> > Thanks,
> > Joey
> > 
> > > +
> > >  	if (prot & KVM_PGTABLE_PROT_X) {
> > >  		if (prot & KVM_PGTABLE_PROT_W)
> > >  			return -EINVAL;
> 
> ... here. If you were passed UX (and only that), and that you're
> !HVHE, you won't have execution at all, and can allow writes.
> 
> Does that make sense?

Yes, thanks!

Reviewed-by: Joey Gouly <joey.gouly at arm.com>

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


From detlev.casanova at collabora.com  Fri Dec 12 08:01:01 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Fri, 12 Dec 2025 11:01:01 -0500
Subject: [PATCH] media: rkvdec: vp9: Fix probs struct alignment
Message-ID: <20251212160101.146684-1-detlev.casanova@collabora.com>

When building for arm 32 bits, the struct alignment changes and the compiler
adds 3 padding bits to the anonymous mv struct in
rkvdec_vp9_inter_frame_probs.

Therefore, the BUILD_BUG_ON used to check that the struct size is aligned
to 128 bits (hardware requirement) fails.

As that mv struct is at the end of the global rkvdec_vp9_probs struct
and is followed by 11 padding bits, the 3 padding bits can be explicitely
set in the mv struct and removed from the 11 following it.

This makes sure that the mv struct is 32 bits aligned.

Reported-by: kernel test robot <lkp at intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202512110229.R6YCf1Le-lkp at intel.com/
Fixes: d968e50b5c26 ("media: rkvdec: Unstage the driver")
Suggested-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
index b4bf01e839ef..23c733ca2e8e 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
@@ -66,6 +66,8 @@ struct rkvdec_vp9_inter_frame_probs {
 		u8 fr[2][3];
 		u8 class0_hp[2];
 		u8 hp[2];
+		/* 32 bit alignment */
+		u8 padding6[3];
 	} mv;
 };
 
@@ -85,7 +87,7 @@ struct rkvdec_vp9_probs {
 		struct rkvdec_vp9_intra_only_frame_probs intra_only;
 	};
 	/* 128 bit alignment */
-	u8 padding1[11];
+	u8 padding1[8];
 };
 
 /* Data structure describing auxiliary buffer format. */
-- 
2.52.0



From smostafa at google.com  Fri Dec 12 08:07:11 2025
From: smostafa at google.com (Mostafa Saleh)
Date: Fri, 12 Dec 2025 16:07:11 +0000
Subject: [PATCH v5 17/27] iommu/arm-smmu-v3-kvm: Probe SMMU HW
In-Reply-To: <20251128170748.GE812105@ziepe.ca>
References: <20251117184815.1027271-1-smostafa@google.com>
 <20251117184815.1027271-18-smostafa@google.com>
 <20251128170748.GE812105@ziepe.ca>
Message-ID: <aTw9r9syCwJH7hgz@google.com>

On Fri, Nov 28, 2025 at 01:07:48PM -0400, Jason Gunthorpe wrote:
> On Mon, Nov 17, 2025 at 06:48:04PM +0000, Mostafa Saleh wrote:
> 
> > +/*
> > + * Mini-probe and validation for the hypervisor.
> > + */
> > +static int smmu_probe(struct hyp_arm_smmu_v3_device *smmu)
> > +{
> > +	u32 reg;
> > +
> > +	/* IDR0 */
> > +	reg = readl_relaxed(smmu->base + ARM_SMMU_IDR0);
> > +	smmu->features = smmu_idr0_features(reg);
> > +
> > +	/*
> > +	 * Some MMU600 and MMU700 have errata that prevent them from using nesting,
> > +	 * not sure how can we identify those, so it's recommended not to enable this
> > +	 * drivers on such systems.
> > +	 * And preventing any of those will be too restrictive
> > +	 */
> 
> This driver is doing nesting though ??
> 
> Shouldn't you detect those IPs and not support a S1 at all so there is
> no nesting? Identity only?

I can see that the errarta are fixed in r1p1, and from the MMU-700 TRM,
we can extract this information from IIDR[1], I guess we can allow
nesting for all SMMUs except the one affected. Actually we can do that
at the moment from the main driver too, I can prepare a patch for that.

However nesting is still mandatroy, the fallback path for the KVM driver
if nesting is not supported (just S2 for example) is to fail and let the
upstream driver probe the platform devices with KVM out of the picture.

The main reason for this is that the KVM driver relies on CFGI to know
which SIDs to configure, for s2 only cases there won?t be trap and emulate
as the hypervisor would be take control of all the SMMUs (as v3 of this
series which requires HVCs)

It might be useful to support only S2 SMMUs, but I?d like to keep this
series simple and then we can build on top of it.

[1] https://developer.arm.com/documentation/101542/0001/Functional-description/Constraints-and-limitations-of-use/SMMUv3-implementation

Thanks,
Mostafa

> 
> Jason


From smostafa at google.com  Fri Dec 12 08:15:33 2025
From: smostafa at google.com (Mostafa Saleh)
Date: Fri, 12 Dec 2025 16:15:33 +0000
Subject: [PATCH v5 27/27] iommu/arm-smmu-v3-kvm: Enable nesting
In-Reply-To: <20251128171252.GF812105@ziepe.ca>
References: <20251117184815.1027271-1-smostafa@google.com>
 <20251117184815.1027271-28-smostafa@google.com>
 <20251128171252.GF812105@ziepe.ca>
Message-ID: <aTw_pZ7ZyhwFW7-3@google.com>

On Fri, Nov 28, 2025 at 01:12:52PM -0400, Jason Gunthorpe wrote:
> On Mon, Nov 17, 2025 at 06:48:14PM +0000, Mostafa Saleh wrote:
> > @@ -441,8 +490,32 @@ static void smmu_reshadow_ste(struct hyp_arm_smmu_v3_device *smmu, u32 sid, bool
> >  		hyp_ste_ptr = smmu_get_ste_ptr(smmu, sid, hyp_ste_base);
> >  	}
> >  
> > -	smmu_copy_from_host(smmu, hyp_ste_ptr->data, host_ste_ptr->data,
> > +	smmu_copy_from_host(smmu, target.data, host_ste_ptr->data,
> >  			    STRTAB_STE_DWORDS << 3);
> > +	/*
> > +	 * Typically, STE update is done as the following
> > +	 * 1- Write last 7 dwords, while STE is invalid
> > +	 * 2- CFGI
> > +	 * 3- Write first dword, making STE valid
> > +	 * 4- CFGI
> > +	 * As the SMMU MUST at least load 64 bits atomically
> > +	 * that gurantees that there is no race between writing
> > +	 * the STE and the CFGI where the SMMU observes parts
> > +	 * of the STE.
> > +	 * In the shadow we update the STE to enable nested translation,
> > +	 * which requires updating first 4 dwords.
> > +	 * That is only done if the STE is valid and not in abort.
> > +	 * Which means it happens at step 4)
> > +	 * So we need to also write the last 7 dwords and send CFGI
> > +	 * before writing the first dword.
> > +	 * There is no need for last CFGI as it's done next.
> > +	 */
> 
> This really should share the main driver logic to do STE writes in the
> right order and try to avoid making it non-valid if not necessary.
> 
> This will not properly support all the real-world kernel flows around
> PASID with such a simplistic implementation.
> 
>

I see, would it be OK to keep it as this simple now and add this later,
as this is still early support? as I want to keep this series minimal.

I plan to have another seires with some improvements and optimizations,
mostly about page tables (using block mappings) and I can include such
optimization, specially that the new hitless STE stuff is relatively
recent in the main driver.

Thanks,
Mostafa

> Json


From yeoreum.yun at arm.com  Fri Dec 12 08:18:30 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Fri, 12 Dec 2025 16:18:30 +0000
Subject: [PATCH 0/2] introduce pagetable_alloc_nolock()
Message-ID: <20251212161832.2067134-1-yeoreum.yun@arm.com>

Some architectures invoke pagetable_alloc() or __get_free_pages()
with preemption disabled.
For example, in arm64, linear_map_split_to_ptes() calls pagetable_alloc()
while spliting block entry to ptes and __kpti_install_ng_mappings()
calls __get_free_pages() to create kpti pagetable.

Under PREEMPT_RT, calling pagetable_alloc() with
preemption disabled is not allowed, because it may acquire
a spin lock that becomes sleepable on RT, potentially
causing a sleep during page allocation.

Since above two functions is called as callback of stop_machine()
where its callback is called in preemption disabled,
They could make a potential problem. (sleeping in preemption disabled).

To address this, introduce pagetable_alloc_nolock() API.

Yeoreum Yun (2):
  mm: introduce pagetable_alloc_nolock()
  arm64: mmu: use pagetable_alloc_nolock() while stop_machine()

 arch/arm64/mm/mmu.c  | 23 ++++++++++++++++++-----
 include/linux/mm.h   | 18 ++++++++++++++++++
 kernel/bpf/stream.c  |  2 +-
 kernel/bpf/syscall.c |  2 +-
 mm/page_alloc.c      | 10 +++-------
 5 files changed, 41 insertions(+), 14 deletions(-)

--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



From yeoreum.yun at arm.com  Fri Dec 12 08:18:31 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Fri, 12 Dec 2025 16:18:31 +0000
Subject: [PATCH 1/2] mm: introduce pagetable_alloc_nolock()
In-Reply-To: <20251212161832.2067134-1-yeoreum.yun@arm.com>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com>
Message-ID: <20251212161832.2067134-2-yeoreum.yun@arm.com>

Some architectures invoke pagetable_alloc() with preemption disabled
(e.g., arm64?s linear_map_split_to_ptes()).

Under PREEMPT_RT, calling pagetable_alloc() with
preemption disabled is not allowed, because it may acquire
a spin lock that becomes sleepable on RT, potentially
causing a sleep during page allocation.

To address this, introduce a pagetable_alloc_nolock() API and
permit two additional GFP flags for alloc_pages_nolock() ? __GFP_HIGH and __GFP_ZERO.

Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
---
 include/linux/mm.h   | 18 ++++++++++++++++++
 kernel/bpf/stream.c  |  2 +-
 kernel/bpf/syscall.c |  2 +-
 mm/page_alloc.c      | 10 +++-------
 4 files changed, 23 insertions(+), 9 deletions(-)

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 7c79b3369b82..11a27f60838b 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2990,6 +2990,24 @@ static inline struct ptdesc *pagetable_alloc_noprof(gfp_t gfp, unsigned int orde
 }
 #define pagetable_alloc(...)	alloc_hooks(pagetable_alloc_noprof(__VA_ARGS__))
 
+/**
+ * pagetable_alloc_nolock - opportunistic reetentrant pagetables allocation
+ *                          from any context
+ * @gfp:    GFP flags. Only __GFP_ZERO, __GFP_HIGH, __GFP_ACCOUNT allowed.
+ * @order:  desired pagetable order
+ *
+ * opportunistic reetentrant version of pagetable_alloc().
+ *
+ * Return: The ptdesc describing the allocated page tables.
+ */
+static inline struct ptdesc *pagetable_alloc_nolock_noprof(gfp_t gfp, unsigned int order)
+{
+	struct page *page = alloc_pages_nolock_noprof(gfp, NUMA_NO_NODE, order);
+
+	return page_ptdesc(page);
+}
+#define pagetable_alloc_nolock(...)	alloc_hooks(pagetable_alloc_nolock_noprof(__VA_ARGS__))
+
 /**
  * pagetable_free - Free pagetables
  * @pt:	The page table descriptor
diff --git a/kernel/bpf/stream.c b/kernel/bpf/stream.c
index ff16c631951b..3c80c8007d91 100644
--- a/kernel/bpf/stream.c
+++ b/kernel/bpf/stream.c
@@ -83,7 +83,7 @@ static struct bpf_stream_page *bpf_stream_page_replace(void)
 	struct bpf_stream_page *stream_page, *old_stream_page;
 	struct page *page;
 
-	page = alloc_pages_nolock(/* Don't account */ 0, NUMA_NO_NODE, 0);
+	page = alloc_pages_nolock(/* Don't account */ __GFP_ZERO, NUMA_NO_NODE, 0);
 	if (!page)
 		return NULL;
 	stream_page = page_address(page);
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 8a129746bd6c..cbc0f8d0c18b 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -598,7 +598,7 @@ static bool can_alloc_pages(void)
 static struct page *__bpf_alloc_page(int nid)
 {
 	if (!can_alloc_pages())
-		return alloc_pages_nolock(__GFP_ACCOUNT, nid, 0);
+		return alloc_pages_nolock(__GFP_ZERO | __GFP_ACCOUNT, nid, 0);
 
 	return alloc_pages_node(nid,
 				GFP_KERNEL | __GFP_ZERO | __GFP_ACCOUNT
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index ed82ee55e66a..88a920dc1e9a 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -7542,21 +7542,17 @@ struct page *alloc_frozen_pages_nolock_noprof(gfp_t gfp_flags, int nid, unsigned
 	 * various contexts. We cannot use printk_deferred_enter() to mitigate,
 	 * since the running context is unknown.
 	 *
-	 * Specify __GFP_ZERO to make sure that call to kmsan_alloc_page() below
-	 * is safe in any context. Also zeroing the page is mandatory for
-	 * BPF use cases.
-	 *
 	 * Though __GFP_NOMEMALLOC is not checked in the code path below,
 	 * specify it here to highlight that alloc_pages_nolock()
 	 * doesn't want to deplete reserves.
 	 */
-	gfp_t alloc_gfp = __GFP_NOWARN | __GFP_ZERO | __GFP_NOMEMALLOC | __GFP_COMP
+	gfp_t alloc_gfp = __GFP_NOWARN | __GFP_NOMEMALLOC | __GFP_COMP
 			| gfp_flags;
 	unsigned int alloc_flags = ALLOC_TRYLOCK;
 	struct alloc_context ac = { };
 	struct page *page;
 
-	VM_WARN_ON_ONCE(gfp_flags & ~__GFP_ACCOUNT);
+	VM_WARN_ON_ONCE(gfp_flags & ~(__GFP_HIGH | __GFP_ZERO | __GFP_ACCOUNT));
 	/*
 	 * In PREEMPT_RT spin_trylock() will call raw_spin_lock() which is
 	 * unsafe in NMI. If spin_trylock() is called from hard IRQ the current
@@ -7602,7 +7598,7 @@ struct page *alloc_frozen_pages_nolock_noprof(gfp_t gfp_flags, int nid, unsigned
 }
 /**
  * alloc_pages_nolock - opportunistic reentrant allocation from any context
- * @gfp_flags: GFP flags. Only __GFP_ACCOUNT allowed.
+ * @gfp_flags: GFP flags. Only __GFP_ZERO, __GFP_HIGH, __GFP_ACCOUNT allowed.
  * @nid: node to allocate from
  * @order: allocation order size
  *
-- 
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



From yeoreum.yun at arm.com  Fri Dec 12 08:18:32 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Fri, 12 Dec 2025 16:18:32 +0000
Subject: [PATCH 2/2] arm64: mmu: use pagetable_alloc_nolock() while stop_machine()
In-Reply-To: <20251212161832.2067134-1-yeoreum.yun@arm.com>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com>
Message-ID: <20251212161832.2067134-3-yeoreum.yun@arm.com>

linear_map_split_to_ptes() and __kpti_install_ng_mappings()
are called as callback of stop_machine().
That means these functions context are preemption disabled.

Unfortunately, under PREEMPT_RT, the pagetable_alloc() or
__get_free_pages() couldn't be called in this context
since spin lock that becomes sleepable on RT,
potentially causing a sleep during page allocation.

To address this, pagetable_alloc_nolock().

Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
---
 arch/arm64/mm/mmu.c | 23 ++++++++++++++++++-----
 1 file changed, 18 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 2ba01dc8ef82..0e98606d8c4c 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -475,10 +475,15 @@ static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys,
 static phys_addr_t __pgd_pgtable_alloc(struct mm_struct *mm, gfp_t gfp,
 				       enum pgtable_type pgtable_type)
 {
-	/* Page is zeroed by init_clear_pgtable() so don't duplicate effort. */
-	struct ptdesc *ptdesc = pagetable_alloc(gfp & ~__GFP_ZERO, 0);
+	struct ptdesc *ptdesc;
 	phys_addr_t pa;
 
+	/* Page is zeroed by init_clear_pgtable() so don't duplicate effort. */
+	if (gfpflags_allow_spinning(gfp))
+		ptdesc  = pagetable_alloc(gfp & ~__GFP_ZERO, 0);
+	else
+		ptdesc  = pagetable_alloc_nolock(gfp & ~__GFP_ZERO, 0);
+
 	if (!ptdesc)
 		return INVALID_PHYS_ADDR;
 
@@ -869,6 +874,7 @@ static int __init linear_map_split_to_ptes(void *__unused)
 		unsigned long kstart = (unsigned long)lm_alias(_stext);
 		unsigned long kend = (unsigned long)lm_alias(__init_begin);
 		int ret;
+		gfp_t gfp = IS_ENABLED(CONFIG_PREEMPT_RT) ? __GFP_HIGH : GFP_ATOMIC;
 
 		/*
 		 * Wait for all secondary CPUs to be put into the waiting area.
@@ -881,9 +887,9 @@ static int __init linear_map_split_to_ptes(void *__unused)
 		 * PTE. The kernel alias remains static throughout runtime so
 		 * can continue to be safely mapped with large mappings.
 		 */
-		ret = range_split_to_ptes(lstart, kstart, GFP_ATOMIC);
+		ret = range_split_to_ptes(lstart, kstart, gfp);
 		if (!ret)
-			ret = range_split_to_ptes(kend, lend, GFP_ATOMIC);
+			ret = range_split_to_ptes(kend, lend, gfp);
 		if (ret)
 			panic("Failed to split linear map\n");
 		flush_tlb_kernel_range(lstart, lend);
@@ -1207,7 +1213,14 @@ static int __init __kpti_install_ng_mappings(void *__unused)
 	remap_fn = (void *)__pa_symbol(idmap_kpti_install_ng_mappings);
 
 	if (!cpu) {
-		alloc = __get_free_pages(GFP_ATOMIC | __GFP_ZERO, order);
+		if (IS_ENABLED(CONFIG_PREEMPT_RT))
+			alloc = (u64) pagetable_alloc_nolock(__GFP_HIGH | __GFP_ZERO, order);
+		else
+			alloc = __get_free_pages(GFP_ATOMIC | __GFP_ZERO, order);
+
+		if (!alloc)
+			panic("Failed to alloc kpti_ng_pgd\n");
+
 		kpti_ng_temp_pgd = (pgd_t *)(alloc + (levels - 1) * PAGE_SIZE);
 		kpti_ng_temp_alloc = kpti_ng_temp_pgd_pa = __pa(kpti_ng_temp_pgd);
 
-- 
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



From mh at probably.group  Fri Dec 12 08:23:35 2025
From: mh at probably.group (=?utf-8?B?Ik1hcnRpbiBIb2xvdnNrw70gKFByb2JhYmx5IE5vdGhpbmcgcy5yLm8u?= =?utf-8?B?KSI=?=)
Date: Fri, 12 Dec 2025 17:23:35 +0100
Subject: [PATCH] arm64: dts: rockchip: enable dual 2.5GbE on Rock 5T
Message-ID: <96516D1F-9787-47FE-A67E-4745D11D9207@probably.group>

The Radxa Rock 5T board features two RTL8125B 2.5GbE Ethernet controllers
connected via PCIe lanes pcie2x1l0 (fe170000) and pcie2x1l2 (fe190000).
Currently only one interface is functional because the PCIe controller
nodes lack the necessary reset GPIO configuration.

Without the reset-gpios property, the RTL8125B PHYs remain in reset state
and are not enumerated by the PCIe bus. This results in only one Ethernet
interface being detected, or none at all depending on U-Boot initialization.

This patch adds the missing configuration for both PCIe controllers:
- Enables both pcie2x1l0 and pcie2x1l2 nodes (status = "okay")
- Configures reset GPIOs (GPIO4_PA5 and GPIO3_PB0 respectively)
- Adds corresponding pinctrl definitions

With this change, both 2.5GbE interfaces are properly detected and
functional on the Rock 5T.

Tested on Radxa Rock 5T v1.2 running Linux 6.12.


---
 .../boot/dts/rockchip/rk3588-rock-5t.dts      | 23 +++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts
index 0dd90c744380..aeb8e0d42f09 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts
@@ -68,6 +68,20 @@ &pcie2x1l1 {
 	status = "okay";
 };
 
+&pcie2x1l0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_0_rst>;
+	reset-gpios = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+&pcie2x1l2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_2_rst>;
+	reset-gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
 &pcie30phy {
 	data-lanes = <1 1 2 2>;
 };
@@ -101,6 +115,15 @@ pcie2 {
 		pcie2_1_rst: pcie2-1-rst {
 			rockchip,pins = <4 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
 		};
+
+		pcie2_0_rst: pcie2-0-rst {
+			rockchip,pins = <4 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		pcie2_2_rst: pcie2-2-rst {
+			rockchip,pins = <3 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
 		pcie2_0_vcc3v3_en: pcie2-0-vcc-en {
 			rockchip,pins = <2 RK_PC0 RK_FUNC_GPIO &pcfg_pull_none>;
 		};
-- 
2.52.0



From maz at kernel.org  Fri Dec 12 08:24:06 2025
From: maz at kernel.org (Marc Zyngier)
Date: Fri, 12 Dec 2025 16:24:06 +0000
Subject: [PATCH 09/32] KVM: arm64: gic-v5: Compute GICv5 FGTs on vcpu load
In-Reply-To: <20251212152215.675767-10-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	<20251212152215.675767-10-sascha.bischoff@arm.com>
Message-ID: <86o6o3oehl.wl-maz@kernel.org>

On Fri, 12 Dec 2025 15:22:38 +0000,
Sascha Bischoff <Sascha.Bischoff at arm.com> wrote:
> 
> Extend the existing FGT infrastructure to calculate and activate any
> required GICv5 traps (ICH_HFGRTR_EL2, ICH_HFGWTR_EL2, ICH_HFGITR_EL2)
> before entering the guest, and restore the original ICH_HFGxTR_EL2
> contents on the return path. This ensures that the host and guest
> behaviour remains independent.
> 
> As of this change, none of the GICv5 instructions or register accesses
> are being trapped, but this will change in subsequent commits as some
> GICv5 system registers must always be trapped (ICC_IAFFIDR_EL1,
> ICH_PPI_HMRx_EL1).

nit: 90% of this patch has nothing to do with computing the FGTs at
load time. The gist of it is actually setting up the FGT
infrastructure, and activate/deactivate aspect is actually very
minor. You may want to reformulate the commit message to make that
clearer (I don't think this needs splitting though).

[...]

> @@ -1501,7 +1585,7 @@ static void __compute_hdfgwtr(struct kvm_vcpu *vcpu)
>  void kvm_vcpu_load_fgt(struct kvm_vcpu *vcpu)
>  {
>  	if (!cpus_have_final_cap(ARM64_HAS_FGT))
> -		return;
> +		goto skip_feat_fgt;

How can you have GICv5, but not FGTs? I don't think this is a valid
construct as per the architecture:

	(FEAT_GCIE ==> v9Ap3)
	(FEAT_FGT ==> v8Ap5)
	(v9Ap3 ==> (v9Ap2 && v8Ap8))

>  
>  	__compute_fgt(vcpu, HFGRTR_EL2);
>  	__compute_hfgwtr(vcpu);
> @@ -1511,11 +1595,19 @@ void kvm_vcpu_load_fgt(struct kvm_vcpu *vcpu)
>  	__compute_fgt(vcpu, HAFGRTR_EL2);
>  
>  	if (!cpus_have_final_cap(ARM64_HAS_FGT2))
> -		return;
> +		goto skip_feat_fgt;

Even FGT2 is expected, since v9.3 is congruent to v8.8:

	(FEAT_FGT2 ==> v8Ap8)

>  
>  	__compute_fgt(vcpu, HFGRTR2_EL2);
>  	__compute_fgt(vcpu, HFGWTR2_EL2);
>  	__compute_fgt(vcpu, HFGITR2_EL2);
>  	__compute_fgt(vcpu, HDFGRTR2_EL2);
>  	__compute_fgt(vcpu, HDFGWTR2_EL2);
> +
> +skip_feat_fgt:
> +	if (!cpus_have_final_cap(ARM64_HAS_GICV5_CPUIF))
> +		return;
> +
> +	__compute_fgt(vcpu, ICH_HFGRTR_EL2);
> +	__compute_fgt(vcpu, ICH_HFGWTR_EL2);
> +	__compute_fgt(vcpu, ICH_HFGITR_EL2);
>  }

Thanks,

	M.

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


From mark.rutland at arm.com  Fri Dec 12 08:33:06 2025
From: mark.rutland at arm.com (Mark Rutland)
Date: Sat, 13 Dec 2025 01:33:06 +0900
Subject: Withdraw [PATCH] tracing: Enable kprobe tracing for Arm64 asm
 functions
In-Reply-To: <aTnVEdv2j5ur48aF@meta.com>
References: <20251027181749.240466-1-benniu@meta.com>
 <aQIltqoIVDwh4A6p@J2N7QTR9R3>
 <aQKpDIYwO9VTP7qM@meta.com>
 <aQNbjap69C6inZwb@J2N7QTR9R3>
 <aQOpd14RXnyQLOWR@meta.com>
 <aRr6Ll7h29dpt7zz@J2N7QTR9R3>
 <aTnVEdv2j5ur48aF@meta.com>
Message-ID: <aTxDwiqIhGG1NkUl@J2N7QTR9R3>

On Wed, Dec 10, 2025 at 12:16:17PM -0800, Ben Niu wrote:
> On Mon, Nov 17, 2025 at 10:34:22AM +0000, Mark Rutland wrote:
> > On Thu, Oct 30, 2025 at 11:07:51AM -0700, Ben Niu wrote:
> > > On Thu, Oct 30, 2025 at 12:35:25PM +0000, Mark Rutland wrote:
> > > > Is there something specific you want to trace, but cannot currently
> > > > trace (on arm64)?
> > > 
> > > For some reason, we only saw Arm64 Linux asm functions __arch_copy_to_user and
> > > __arch_copy_from_user being hot in our workloads, not those counterpart asm
> > > functions on x86, so we are trying to understand and improve performance of
> > > those Arm64 asm functions.
> > 
> > Are you sure that's not an artifact of those being out-of-line on arm64,
> > but inline on x86? On x86, the out-of-line forms are only used when the
> > CPU doesn't have FSRM, and when the CPU *does* have FSRM, the logic gets
> > inlined. See raw_copy_from_user(), raw_copy_to_user(), and
> > copy_user_generic() in arch/x86/include/asm/uaccess_64.h.
> 
> On x86, INLINE_COPY_TO_USER is not defined in the latest linux kernel and our
> internal branch, so _copy_to_user is always defined as an extern function
> (no-inline), which ends up inlining copy_user_generic. copy_user_generic
> executes FSRM rep movs if CPU supports it (our case), otherwise, it calls
> rep_movs_alternative, which issues plain movs to copy memory.

> > Have you checked that inlining is not skewing your results, and
> > artificially making those look hotter on am64 by virtue of centralizing
> > samples to the same IP/PC range?
> 
> As mentioned above, _copy_to_user is not inlined on x86.

Thanks for confirming!

> > Can you share any information on those workloads? e.g. which callchains
> > were hot?
> 
> Please reach out to James Greenhalgh and Chris Goodyer at Arm for more details
> about those workloads, which I can't share in a public channel.

If you can't share this info publicly, that's fair enough.

Please note that upstream it's hard to justify changing things based on
confidential information. Sharing information with me in private isn't
all that helpful as it would not be clear what I could subsequently
share in public.

The reason that I've asked is that it would be very interesting to know
whether there's a specific subsystem, driver, or code path that's
hitting this hard, because a better option might be "don't do that", and
attempt to avoid the uaccesses entirely (e.g. accessing a kernel alias
with get_user_pages()).

If there's anything that you can share about that, it'd be very helpful.

Mark.


From Frank.li at nxp.com  Fri Dec 12 08:43:17 2025
From: Frank.li at nxp.com (Frank Li)
Date: Fri, 12 Dec 2025 11:43:17 -0500
Subject: [PATCH 1/4] arm64: dts: imx91: Add tempsensor node
In-Reply-To: <20251212-imx91-dts-v1-1-2bb3c13762dd@nxp.com>
References: <20251212-imx91-dts-v1-0-2bb3c13762dd@nxp.com>
 <20251212-imx91-dts-v1-1-2bb3c13762dd@nxp.com>
Message-ID: <aTxGJfQDQVXb+Nd9@lizhi-Precision-Tower-5810>

On Fri, Dec 12, 2025 at 05:16:07PM +0800, Peng Fan (OSS) wrote:
> From: Peng Fan <peng.fan at nxp.com>
>
> Add tempsensor node and trim sub-nodes in ocotp.
>
> Signed-off-by: Peng Fan <peng.fan at nxp.com>
> ---

I posted it when upstream tmu driver

https://lore.kernel.org/imx/20251020-imx91tmu-v7-3-48d7d9f25055 at nxp.com/

Frank
>  arch/arm64/boot/dts/freescale/imx91.dtsi | 25 +++++++++++++++++++++++++
>  1 file changed, 25 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/freescale/imx91.dtsi b/arch/arm64/boot/dts/freescale/imx91.dtsi
> index 4d8300b2a7bca33bd0613db9e79d2fba6b40c052..c08db08ca9607b9780a77e215cdb5997e4daae4e 100644
> --- a/arch/arm64/boot/dts/freescale/imx91.dtsi
> +++ b/arch/arm64/boot/dts/freescale/imx91.dtsi
> @@ -6,6 +6,21 @@
>  #include "imx91-pinfunc.h"
>  #include "imx91_93_common.dtsi"
>
> +&aips1 {
> +	tempsense0: thermal-sensor at 44482000 {
> +		compatible = "fsl,imx91-tmu";
> +		reg = <0x44482000 0x1000>;
> +		clocks = <&clk IMX93_CLK_TMC_GATE>;
> +		interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
> +			     <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
> +			     <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
> +		interrupt-names = "thr1", "thr2", "ready";
> +		#thermal-sensor-cells = <0>;
> +		nvmem-cells = <&tmu_trim1>, <&tmu_trim2>;
> +		nvmem-cell-names = "trim1", "trim2";
> +	};
> +};
> +
>  &clk {
>  	compatible = "fsl,imx91-ccm";
>  };
> @@ -69,3 +84,13 @@ &media_blk_ctrl {
>  	clock-names = "apb", "axi", "nic", "disp", "cam",
>  		      "lcdif", "isi", "csi";
>  };
> +
> +&ocotp {
> +	tmu_trim1: tmu-trim at a0 {
> +		reg = <0xa0 0x4>;
> +	};
> +
> +	tmu_trim2: tmu-trim at a4 {
> +		reg = <0xa4 0x4>;
> +	};
> +};
>
> --
> 2.37.1
>


From jonas at kwiboo.se  Fri Dec 12 08:43:35 2025
From: jonas at kwiboo.se (Jonas Karlman)
Date: Fri, 12 Dec 2025 17:43:35 +0100
Subject: [PATCH] media: rkvdec: set ctx->image_fmt in rkvdec_s_capture_fmt
In-Reply-To: <20251212154138.3042300-1-liujianfeng1994@gmail.com>
References: <20251212154138.3042300-1-liujianfeng1994@gmail.com>
Message-ID: <5c2dec91-667f-48f6-b958-e0cf81cab569@kwiboo.se>

Hi,

On 12/12/2025 4:41 PM, Jianfeng Liu wrote:
> ctx->image_fmt is initialized as RKVDEC_IMG_FMT_ANY at
> rkvdec_s_output_fmt, and get set at rkvdec_s_ctrl when userspace sends
> SPS info via VIDIOC_S_EXT_CTRLS. This works fine with gstreamer because
> it sends SPS info to kernel driver before requesting capture queue bufs.
> 
> But chromium requests capture queue bufs first and then sends SPS info
> to kernel, then rkvdec_s_ctrl will return -EBUSY, and the video is
> displayed green.
> 
> Chromium calls VIDIOC_S_FMT to capture queue instead before requesting
> capture queue bufs, so setting ctx->image_fmt in rkvdec_s_capture_fmt
> will make rkvdec_s_ctrl return 0 when the first SPS info sent to driver.
> 
> Signed-off-by: Jianfeng Liu <liujianfeng1994 at gmail.com>
> Fixes: d35c64eccf3b1 ("media: rkvdec: Add get_image_fmt ops")
> ---
> 
>  drivers/media/platform/rockchip/rkvdec/rkvdec.c | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> index 5af9aa5ab353..e7939d604f64 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> @@ -537,6 +537,18 @@ static int rkvdec_s_capture_fmt(struct file *file, void *priv,
>  		return ret;
>  
>  	ctx->decoded_fmt = *f;
> +
> +	u32 fourcc = f->fmt.pix_mp.pixelformat;
> +
> +	if (fourcc == V4L2_PIX_FMT_NV12)
> +		ctx->image_fmt = RKVDEC_IMG_FMT_420_8BIT;
> +	else if (fourcc == V4L2_PIX_FMT_NV15)
> +		ctx->image_fmt = RKVDEC_IMG_FMT_420_10BIT;
> +	else if (fourcc == V4L2_PIX_FMT_NV16)
> +		ctx->image_fmt = RKVDEC_IMG_FMT_422_8BIT;
> +	else if (fourcc == V4L2_PIX_FMT_NV20)
> +		ctx->image_fmt = RKVDEC_IMG_FMT_422_10BIT;

ctx->image_fmt is used to limit what CAPTURE pixel format can be set and
forcing it here violates this.

Chromium should be fixed to follow spec at 4.5.3.2. Initialization [1]:

  1. Set the coded format on the OUTPUT queue via VIDIOC_S_FMT().
  2. Call VIDIOC_S_EXT_CTRLS() to set all the controls (parsed headers,
     etc.) required by the OUTPUT format to enumerate the CAPTURE formats.
  ...
  5. [optional] Choose a different CAPTURE format than suggested via
     VIDIOC_S_FMT() on CAPTURE queue.

Regards,
Jonas

[1] https://docs.kernel.org/userspace-api/media/v4l/dev-stateless-decoder.html

> +
>  	return 0;
>  }
>  



From detlev.casanova at collabora.com  Fri Dec 12 08:45:50 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Fri, 12 Dec 2025 11:45:50 -0500
Subject: [PATCH v3 02/15] media: v4l2-ctrls: Add hevc_ext_sps_[ls]t_rps
 controls
In-Reply-To: <3ff3c7f76e24fdc92d86be3f92b6947ef86abc25.camel@collabora.com>
References: <20251022162459.271603-1-detlev.casanova@collabora.com>
 <20251022162459.271603-3-detlev.casanova@collabora.com>
 <3ff3c7f76e24fdc92d86be3f92b6947ef86abc25.camel@collabora.com>
Message-ID: <511b524a-b573-42f6-8a11-7f0992f8f418@collabora.com>

Hi Nicolas,

On 12/10/25 15:07, Nicolas Dufresne wrote:
> Hi,
>
> Le mercredi 22 octobre 2025 ? 12:22 -0400, Detlev Casanova a ?crit?:
>> The vdpu381 decoder found on newer Rockchip SoC need the information
>> from the long term and short term ref pic sets from the SPS.
>>
>> So far, it wasn't included in the v4l2 API, so add it with new dynamic
>> sized controls.
>>
>> Each element of the hevc_ext_sps_lt_rps array contains the long term ref
>> pic set at that index.
>> Each element of the hevc_ext_sps_st_rps contains the short term ref pic
>> set at that index, as the raw data.
>> It is the role of the drivers to calculate the reference sets values.
>>
>> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
>> ---
>>  ?drivers/media/v4l2-core/v4l2-ctrls-core.c | 18 +++++++
>>  ?drivers/media/v4l2-core/v4l2-ctrls-defs.c | 10 ++++
>>  ?include/uapi/linux/v4l2-controls.h??????? | 61 +++++++++++++++++++++++
>>  ?include/uapi/linux/videodev2.h??????????? |? 2 +
>>  ?4 files changed, 91 insertions(+)
>>
>> diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c
>> index 85d07ef44f62..779936727505 100644
>> --- a/drivers/media/v4l2-core/v4l2-ctrls-core.c
>> +++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c
>> @@ -418,6 +418,12 @@ void v4l2_ctrl_type_op_log(const struct v4l2_ctrl *ctrl)
>>  ?	case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
>>  ?		pr_cont("HEVC_SLICE_PARAMS");
>>  ?		break;
>> +	case V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS:
>> +		pr_cont("HEVC_EXT_SPS_ST_RPS");
>> +		break;
>> +	case V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS:
>> +		pr_cont("HEVC_EXT_SPS_LT_RPS");
>> +		break;
>>  ?	case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX:
>>  ?		pr_cont("HEVC_SCALING_MATRIX");
>>  ?		break;
>> @@ -1173,6 +1179,12 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
>>  ?	case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
>>  ?		break;
>>   
>> +	case V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS:
>> +		break;
>> +
>> +	case V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS:
>> +		break;
>> +
>>  ?	case V4L2_CTRL_TYPE_HDR10_CLL_INFO:
>>  ?		break;
>>   
>> @@ -1925,6 +1937,12 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
>>  ?	case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
>>  ?		elem_size = sizeof(struct v4l2_ctrl_hevc_slice_params);
>>  ?		break;
>> +	case V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS:
>> +		elem_size = sizeof(struct v4l2_ctrl_hevc_ext_sps_st_rps);
>> +		break;
>> +	case V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS:
>> +		elem_size = sizeof(struct v4l2_ctrl_hevc_ext_sps_lt_rps);
>> +		break;
>>  ?	case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX:
>>  ?		elem_size = sizeof(struct v4l2_ctrl_hevc_scaling_matrix);
>>  ?		break;
>> diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
>> index ad41f65374e2..167286c9e424 100644
>> --- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c
>> +++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
>> @@ -1233,6 +1233,8 @@ const char *v4l2_ctrl_get_name(u32 id)
>>  ?	case V4L2_CID_STATELESS_HEVC_DECODE_MODE:		return "HEVC Decode Mode";
>>  ?	case V4L2_CID_STATELESS_HEVC_START_CODE:		return "HEVC Start Code";
>>  ?	case V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS:	return "HEVC Entry Point Offsets";
>> +	case V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS:		return "HEVC Short Term Ref Sets";
>> +	case V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS:		return "HEVC Long Term Ref Sets";
>>  ?	case V4L2_CID_STATELESS_AV1_SEQUENCE:			return "AV1 Sequence Parameters";
>>  ?	case V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY:		return "AV1 Tile Group Entry";
>>  ?	case V4L2_CID_STATELESS_AV1_FRAME:			return "AV1 Frame Parameters";
>> @@ -1578,6 +1580,14 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
>>  ?		*type = V4L2_CTRL_TYPE_U32;
>>  ?		*flags |= V4L2_CTRL_FLAG_DYNAMIC_ARRAY;
>>  ?		break;
>> +	case V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS:
>> +		*type = V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS;
>> +		*flags |= V4L2_CTRL_FLAG_DYNAMIC_ARRAY;
>> +		break;
>> +	case V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS:
>> +		*type = V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS;
>> +		*flags |= V4L2_CTRL_FLAG_DYNAMIC_ARRAY;
>> +		break;
>>  ?	case V4L2_CID_STATELESS_VP9_COMPRESSED_HDR:
>>  ?		*type = V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR;
>>  ?		break;
>> diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
>> index 2d30107e047e..dd9e29afa155 100644
>> --- a/include/uapi/linux/v4l2-controls.h
>> +++ b/include/uapi/linux/v4l2-controls.h
>> @@ -2093,6 +2093,8 @@ struct v4l2_ctrl_mpeg2_quantisation {
>>  ?#define V4L2_CID_STATELESS_HEVC_DECODE_MODE	(V4L2_CID_CODEC_STATELESS_BASE + 405)
>>  ?#define V4L2_CID_STATELESS_HEVC_START_CODE	(V4L2_CID_CODEC_STATELESS_BASE + 406)
>>  ?#define V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS (V4L2_CID_CODEC_STATELESS_BASE + 407)
>> +#define V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS? (V4L2_CID_CODEC_STATELESS_BASE + 408)
>> +#define V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS? (V4L2_CID_CODEC_STATELESS_BASE + 409)
>>   
>>  ?enum v4l2_stateless_hevc_decode_mode {
>>  ?	V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED,
>> @@ -2548,6 +2550,65 @@ struct v4l2_ctrl_hevc_scaling_matrix {
>>  ?	__u8	scaling_list_dc_coef_32x32[2];
>>  ?};
>>   
>> +#define V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED	0x1
>> +
>> +/*
>> + * struct v4l2_ctrl_hevc_ext_sps_st_rps - HEVC short term RPS parameters
>> + *
>> + * Dynamic size 1-dimension array for short term RPS. The number of elements
>> + * is v4l2_ctrl_hevc_sps::num_short_term_ref_pic_sets. It can contain up to 65 elements.
>> + *
>> + * @delta_idx_minus1: Specifies the delta compare to the index. See details in section 7.4.8
>> + *??????????????????? "Short-term reference picture set semantics" of the specification.
>> + * @delta_rps_sign: Sign of the delta as specified in section 7.4.8 "Short-term reference picture
>> + *????????????????? set semantics" of the specification.
>> + * @abs_delta_rps_minus1: Absolute delta RPS as specified in section 7.4.8 "Short-term reference
>> + *??????????????????????? picture set semantics" of the specification.
>> + * @num_negative_pics: Number of short-term RPS entries that have picture order count values less
>> + *???????????????????? than the picture order count value of the current picture.
>> + * @num_positive_pics: Number of short-term RPS entries that have picture order count values
>> + *???????????????????? greater than the picture order count value of the current picture.
>> + * @used_by_curr_pic: Bit j specifies if short-term RPS j is used by the current picture.
>> + * @use_delta_flag: Bit j equals to 1 specifies that the j-th entry in the source candidate
>> + *????????????????? short-term RPS is included in this candidate short-term RPS.
>> + * @delta_poc_s0_minus1: Specifies the negative picture order count delta for the i-th entry in
>> + *?????????????????????? the short-term RPS. See details in section 7.4.8 "Short-term reference
>> + *?????????????????????? picture set semantics" of the specification.
>> + * @delta_poc_s1_minus1: Specifies the positive picture order count delta for the i-th entry in
>> + *?????????????????????? the short-term RPS. See details in section 7.4.8 "Short-term reference
>> + *?????????????????????? picture set semantics" of the specification.
>> + * @flags: See V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_{}
>> + */
>> +struct v4l2_ctrl_hevc_ext_sps_st_rps {
>> +	__u8	delta_idx_minus1;
>> +	__u8	delta_rps_sign;
>> +	__u16	abs_delta_rps_minus1;
>> +	__u8	num_negative_pics;
>> +	__u8	num_positive_pics;
>> +	__u32	used_by_curr_pic;
> Did you run pahole ? This one does not seem to align, it starts with 16bit
> offset. The remark is because 32bit and 64bit platform, and all compiler should
> have the same binary representation, otherwise it will break in some ways.

That's a good point. I moved abs_delta_rps_minus1 with the other __u16 
fields and changed flags to be 16 bits too.

Also changed flags to 16 bits in v4l2_ctrl_hevc_ext_sps_lt_rps.

> regards,
> Nicolas
>
>> +	__u32	use_delta_flag;
>> +	__u16	delta_poc_s0_minus1[16];
>> +	__u16	delta_poc_s1_minus1[16];
>> +	__u8	flags;
>> +};
>> +
>> +#define V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_USED_LT		0x1
>> +
>> +/*
>> + * struct v4l2_ctrl_hevc_ext_sps_lt_rps - HEVC long term RPS parameters
>> + *
>> + * Dynamic size 1-dimension array for long term RPS. The number of elements
>> + * is v4l2_ctrl_hevc_sps::num_long_term_ref_pics_sps. It can contain up to 65 elements.
>> + *
>> + * @lt_ref_pic_poc_lsb_sps: picture order count modulo MaxPicOrderCntLsb of the i-th candidate
>> + *????????????????????????? long-term reference picture.
>> + * @flags: See V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_{}
>> + */
>> +struct v4l2_ctrl_hevc_ext_sps_lt_rps {
>> +	__u16	lt_ref_pic_poc_lsb_sps;
>> +	__u8	flags;
>> +};
>> +
>>  ?/* Stateless VP9 controls */
>>   
>>  ?#define V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED	0x1
>> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
>> index becd08fdbddb..ae1d33fd37b7 100644
>> --- a/include/uapi/linux/videodev2.h
>> +++ b/include/uapi/linux/videodev2.h
>> @@ -1981,6 +1981,8 @@ enum v4l2_ctrl_type {
>>  ?	V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS	= 0x0272,
>>  ?	V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX	= 0x0273,
>>  ?	V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS	= 0x0274,
>> +	V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS	= 0x0275,
>> +	V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS	= 0x0276,
>>   
>>  ?	V4L2_CTRL_TYPE_AV1_SEQUENCE	??? = 0x280,
>>  ?	V4L2_CTRL_TYPE_AV1_TILE_GROUP_ENTRY = 0x281,


From Frank.li at nxp.com  Fri Dec 12 08:46:38 2025
From: Frank.li at nxp.com (Frank Li)
Date: Fri, 12 Dec 2025 11:46:38 -0500
Subject: [PATCH 0/3] arm64: dts: freescale: Use phys to replace
 xceiver-supply
In-Reply-To: <20251212-imx9-can-phy-v1-0-a421d7023e13@nxp.com>
References: <20251212-imx9-can-phy-v1-0-a421d7023e13@nxp.com>
Message-ID: <aTxG7i44To0bYpdI@lizhi-Precision-Tower-5810>

On Fri, Dec 12, 2025 at 05:57:18PM +0800, Peng Fan (OSS) wrote:
> This is a pick up of patch 6-8 from [1].
>
> The drivers changes have been picked in 6.18, just resend the dts changes.
>
> [1]https://lore.kernel.org/linux-phy/20251001-can-v7-0-fad29efc3884 at nxp.com/

Please add 'resend' at subject next time.

Frank

>
> There are still some other device trees not converted to use phys,
> those will be converted later.
>
> Signed-off-by: Peng Fan <peng.fan at nxp.com>
> ---
> Peng Fan (3):
>       arm64: dts: imx95-15x15-evk: Use phys to replace xceiver-supply
>       arm64: dts: imx8mp-evk: Use phys to replace xceiver-supply
>       arm64: dts: imx93-11x11-evk: Use phys to replace xceiver-supply
>
>  arch/arm64/boot/dts/freescale/imx8mp-evk.dts      | 43 +++++++----------------
>  arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts | 17 +++++----
>  arch/arm64/boot/dts/freescale/imx95-15x15-evk.dts | 13 ++++---
>  3 files changed, 27 insertions(+), 46 deletions(-)
> ---
> base-commit: 008d3547aae5bc86fac3eda317489169c3fda112
> change-id: 20251212-imx9-can-phy-328c2085afc7
>
> Best regards,
> --
> Peng Fan <peng.fan at nxp.com>
>


From Frank.li at nxp.com  Fri Dec 12 08:54:08 2025
From: Frank.li at nxp.com (Frank Li)
Date: Fri, 12 Dec 2025 11:54:08 -0500
Subject: [PATCH v21 5/7] firmware: drivers: imx: adds miscdev
In-Reply-To: <20251212-imx-se-if-v21-5-ee7d6052d848@nxp.com>
References: <20251212-imx-se-if-v21-0-ee7d6052d848@nxp.com>
 <20251212-imx-se-if-v21-5-ee7d6052d848@nxp.com>
Message-ID: <aTxIsAQMe3sbxXQ4@lizhi-Precision-Tower-5810>

On Fri, Dec 12, 2025 at 02:44:16PM +0530, Pankaj Gupta wrote:
> Adds the driver for communication interface to secure-enclave, that
> enables exchanging messages with NXP secure enclave HW IP(s)
> like EdgeLock Enclave, from:
> - User-Space Applications via character driver.
>
> ABI documentation for the NXP secure-enclave driver.
>
> User-space library using this driver:
> - i.MX Secure Enclave library:
>   -- URL: https://github.com/nxp-imx/imx-secure-enclave.git,
> - i.MX Secure Middle-Ware:
>   -- URL: https://github.com/nxp-imx/imx-smw.git
>
> Following checks are performed on the incoming msg-header,
> to block exchanging invalid arbitrary commands:
> - maximum allowed words,
> - check if command-tag & response-tag are valid
> - version,
> - command id validation check, to allow limited base-line API(s)
>   and restrict following:
>   - exchanging power management commands.
>   - reset requests.
>   - BBSM configuration requests.
>   - re-initializing the FW.
>   - RNG init
>   - CAAM resource release management
>   - SE's internal memory management.
> from user-space.
>
> Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
> Reviewed-by: Frank Li <Frank.Li at nxp.com>
> ---
> changes from v20 to v21
> - removed "__free(kfree)" & added kfree();

KK's means is that correctly use __free according to cleanup.h.

fun()
{
	...
	some code logic
	...

	struct .... __free(kfree) rx_msg = kzalloc(cmd_snd_rcv_rsp_info.rx_buf_sz, GFP_KERNEL);
	...
}

Frank

> ---
>  Documentation/ABI/testing/se-cdev   |  43 +++
>  drivers/firmware/imx/ele_base_msg.c |  28 ++
>  drivers/firmware/imx/ele_base_msg.h |  20 +
>  drivers/firmware/imx/ele_common.c   |  37 +-
>  drivers/firmware/imx/ele_common.h   |   6 +
>  drivers/firmware/imx/se_ctrl.c      | 744 +++++++++++++++++++++++++++++++++++-
>  drivers/firmware/imx/se_ctrl.h      |  33 ++
>  include/uapi/linux/se_ioctl.h       |  97 +++++
>  8 files changed, 996 insertions(+), 12 deletions(-)
>
> diff --git a/Documentation/ABI/testing/se-cdev b/Documentation/ABI/testing/se-cdev
> new file mode 100644
> index 000000000000..dad39ffd245a
> --- /dev/null
> +++ b/Documentation/ABI/testing/se-cdev
> @@ -0,0 +1,43 @@
> +What:		/dev/<se>_mu[0-9]+_ch[0-9]+
> +Date:		Mar 2025
> +KernelVersion:	6.8
> +Contact:	linux-imx at nxp.com, pankaj.gupta at nxp.com
> +Description:
> +		NXP offers multiple hardware IP(s) for secure enclaves like EdgeLock-
> +		Enclave(ELE), SECO. The character device file descriptors
> +		/dev/<se>_mu*_ch* are the interface between userspace NXP's secure-
> +		enclave shared library and the kernel driver.
> +
> +		The ioctl(2)-based ABI is defined and documented in
> +		[include]<linux/firmware/imx/ele_mu_ioctl.h>.
> +		ioctl(s) are used primarily for:
> +			- shared memory management
> +			- allocation of I/O buffers
> +			- getting mu info
> +			- setting a dev-ctx as receiver to receive all the commands from FW
> +			- getting SoC info
> +			- send command and receive command response
> +
> +		The following file operations are supported:
> +
> +		open(2)
> +		  Currently the only useful flags are O_RDWR.
> +
> +		read(2)
> +		  Every read() from the opened character device context is waiting on
> +		  wait_event_interruptible, that gets set by the registered mailbox callback
> +		  function, indicating a message received from the firmware on message-
> +		  unit.
> +
> +		write(2)
> +		  Every write() to the opened character device context needs to acquire
> +		  mailbox_lock before sending message on to the message unit.
> +
> +		close(2)
> +		  Stops and frees up the I/O contexts that were associated
> +		  with the file descriptor.
> +
> +Users:		https://github.com/nxp-imx/imx-secure-enclave.git,
> +		https://github.com/nxp-imx/imx-smw.git
> +		crypto/skcipher,
> +		drivers/nvmem/imx-ocotp-ele.c
> diff --git a/drivers/firmware/imx/ele_base_msg.c b/drivers/firmware/imx/ele_base_msg.c
> index 4d1f0d43963e..185ba890765c 100644
> --- a/drivers/firmware/imx/ele_base_msg.c
> +++ b/drivers/firmware/imx/ele_base_msg.c
> @@ -14,6 +14,34 @@
>
>  #define FW_DBG_DUMP_FIXED_STR		"ELE"
>
> +int ele_uapi_allowed_base_cmd(struct se_if_priv *priv,
> +			      struct se_msg_hdr *header)
> +{
> +	switch (header->command) {
> +	case ELE_PING_REQ: return 0;
> +	case ELE_DEBUG_DUMP_REQ: return 0;
> +	case ELE_OEM_AUTH_CONTAINER_REQ: return 0;
> +	case ELE_OEM_VERIFY_IMAGE_REQ: return 0;
> +	case ELE_OEM_REL_CONTAINER_REQ: return 0;
> +	case ELE_FW_LIFE_CYCLE_REQ: return 0;
> +	case ELE_READ_FUSE_REQ: return 0;
> +	case ELE_GET_FW_VERS_REQ: return 0;
> +	case ELE_RETURN_LIFE_CYCLE_REQ: return 0;
> +	case ELE_GET_EVENT_REQ: return 0;
> +	case ELE_COMMIT_REQ: return 0;
> +	case ELE_GEN_KEY_BLOB_REQ: return 0;
> +	case ELE_GET_FW_STATUS_REQ: return 0;
> +	case ELE_XIP_DECRYPT_REQ: return 0;
> +	case ELE_WRITE_FUSE: return 0;
> +	case ELE_GET_INFO_REQ: return 0;
> +	case ELE_DEV_ATTEST_REQ: return 0;
> +	case ELE_WRITE_SHADOW_FUSE_REQ: return 0;
> +	case ELE_READ_SHADOW_FUSE_REQ: return 0;
> +	default:
> +		return -EACCES;
> +	}
> +}
> +
>  int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info)
>  {
>  	struct se_api_msg *tx_msg = NULL;
> diff --git a/drivers/firmware/imx/ele_base_msg.h b/drivers/firmware/imx/ele_base_msg.h
> index 8e5b015e99a2..f8fabac331fd 100644
> --- a/drivers/firmware/imx/ele_base_msg.h
> +++ b/drivers/firmware/imx/ele_base_msg.h
> @@ -15,6 +15,24 @@
>
>  #define ELE_NONE_VAL			0x0
>
> +
> +#define ELE_OEM_AUTH_CONTAINER_REQ	0x87
> +#define ELE_OEM_VERIFY_IMAGE_REQ	0x88
> +#define ELE_OEM_REL_CONTAINER_REQ	0x89
> +#define ELE_FW_LIFE_CYCLE_REQ		0x95
> +#define ELE_READ_FUSE_REQ		0x97
> +#define ELE_GET_FW_VERS_REQ		0x9d
> +#define ELE_RETURN_LIFE_CYCLE_REQ	0xa0
> +#define ELE_GET_EVENT_REQ		0xa2
> +#define ELE_COMMIT_REQ			0xa8
> +#define ELE_GEN_KEY_BLOB_REQ		0xaf
> +#define ELE_GET_FW_STATUS_REQ		0xc5
> +#define ELE_XIP_DECRYPT_REQ		0xc6
> +#define ELE_WRITE_FUSE                  0xd6
> +#define ELE_DEV_ATTEST_REQ              0xdb
> +#define ELE_WRITE_SHADOW_FUSE_REQ       0xf2
> +#define ELE_READ_SHADOW_FUSE_REQ        0xf3
> +
>  #define ELE_GET_INFO_REQ		0xda
>  #define ELE_GET_INFO_REQ_MSG_SZ		0x10
>  #define ELE_GET_INFO_RSP_MSG_SZ		0x08
> @@ -92,4 +110,6 @@ int ele_service_swap(struct se_if_priv *priv, phys_addr_t addr,
>  int ele_fw_authenticate(struct se_if_priv *priv, phys_addr_t contnr_addr,
>  			phys_addr_t img_addr);
>  int ele_debug_dump(struct se_if_priv *priv);
> +int ele_uapi_allowed_base_cmd(struct se_if_priv *priv,
> +			      struct se_msg_hdr *header);
>  #endif
> diff --git a/drivers/firmware/imx/ele_common.c b/drivers/firmware/imx/ele_common.c
> index fcd0f561d72d..78440f62bf92 100644
> --- a/drivers/firmware/imx/ele_common.c
> +++ b/drivers/firmware/imx/ele_common.c
> @@ -6,6 +6,23 @@
>  #include "ele_base_msg.h"
>  #include "ele_common.h"
>
> +int se_chk_tx_msg_hdr(struct se_if_priv *priv, struct se_msg_hdr *header)
> +{
> +	if (!header->size || header->size > MAX_WORD_SIZE)
> +		return -EINVAL;
> +
> +	if (header->tag != priv->if_defs->cmd_tag &&
> +	    header->tag != priv->if_defs->rsp_tag)
> +		return -EINVAL;
> +
> +	if (header->ver == priv->if_defs->base_api_ver)
> +		return ele_uapi_allowed_base_cmd(priv, header);
> +	else if (header->ver == priv->if_defs->fw_api_ver)
> +		return 0;
> +
> +	return -EINVAL;
> +}
> +
>  /*
>   * se_get_msg_chksum() - to calculate checksum word by word.
>   *
> @@ -42,15 +59,22 @@ u32 se_get_msg_chksum(u32 *msg, u32 msg_len)
>  	return chksum;
>  }
>
> +void set_se_rcv_msg_timeout(struct se_if_priv *priv, u32 timeout_ms)
> +{
> +	priv->se_rcv_msg_timeout_ms = timeout_ms;
> +}
> +
>  int ele_msg_rcv(struct se_if_device_ctx *dev_ctx, struct se_clbk_handle *se_clbk_hdl)
>  {
> -	unsigned long timeout;
> +	unsigned long timeout_ms;
>  	int ret;
>
>  	do {
> -		timeout = MAX_SCHEDULE_TIMEOUT;
> +		timeout_ms = MAX_SCHEDULE_TIMEOUT;
> +		if (dev_ctx->priv->cmd_receiver_clbk_hdl.dev_ctx != dev_ctx)
> +			timeout_ms = msecs_to_jiffies(dev_ctx->priv->se_rcv_msg_timeout_ms);
>
> -		ret = wait_for_completion_interruptible_timeout(&se_clbk_hdl->done, timeout);
> +		ret = wait_for_completion_interruptible_timeout(&se_clbk_hdl->done, timeout_ms);
>  		if (ret == -ERESTARTSYS) {
>  			if (dev_ctx->priv->waiting_rsp_clbk_hdl.dev_ctx) {
>  				dev_ctx->priv->waiting_rsp_clbk_hdl.signal_rcvd = true;
> @@ -59,6 +83,13 @@ int ele_msg_rcv(struct se_if_device_ctx *dev_ctx, struct se_clbk_handle *se_clbk
>  			ret = -EINTR;
>  			break;
>  		}
> +		if (ret == 0) {
> +			ret = -ETIMEDOUT;
> +			dev_err(dev_ctx->priv->dev,
> +				"Fatal Error: SE interface: %s0, hangs indefinitely.\n",
> +				get_se_if_name(dev_ctx->priv->if_defs->se_if_type));
> +			break;
> +		}
>  		ret = se_clbk_hdl->rx_msg_sz;
>  		break;
>  	} while (ret < 0);
> diff --git a/drivers/firmware/imx/ele_common.h b/drivers/firmware/imx/ele_common.h
> index 5bac14439d7d..bdc13d1b715d 100644
> --- a/drivers/firmware/imx/ele_common.h
> +++ b/drivers/firmware/imx/ele_common.h
> @@ -12,6 +12,11 @@
>
>  #define IMX_ELE_FW_DIR                 "imx/ele/"
>
> +#define MAX_WORD_SIZE			0x20
> +#define SE_RCV_MSG_DEFAULT_TIMEOUT	5000
> +#define SE_RCV_MSG_LONG_TIMEOUT		5000000
> +
> +void set_se_rcv_msg_timeout(struct se_if_priv *priv, u32 val);
>  u32 se_get_msg_chksum(u32 *msg, u32 msg_len);
>
>  int ele_msg_rcv(struct se_if_device_ctx *dev_ctx, struct se_clbk_handle *se_clbk_hdl);
> @@ -42,4 +47,5 @@ int se_save_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem);
>
>  int se_restore_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem);
>
> +int se_chk_tx_msg_hdr(struct se_if_priv *priv, struct se_msg_hdr *header);
>  #endif /*__ELE_COMMON_H__ */
> diff --git a/drivers/firmware/imx/se_ctrl.c b/drivers/firmware/imx/se_ctrl.c
> index 63562a4d9a3e..33afbdc752da 100644
> --- a/drivers/firmware/imx/se_ctrl.c
> +++ b/drivers/firmware/imx/se_ctrl.c
> @@ -23,6 +23,7 @@
>  #include <linux/slab.h>
>  #include <linux/string.h>
>  #include <linux/sys_soc.h>
> +#include <uapi/linux/se_ioctl.h>
>
>  #include "ele_base_msg.h"
>  #include "ele_common.h"
> @@ -32,12 +33,6 @@
>  #define MBOX_TX_NAME			"tx"
>  #define MBOX_RX_NAME			"rx"
>
> -#define SE_TYPE_STR_DBG			"dbg"
> -#define SE_TYPE_STR_HSM			"hsm"
> -
> -#define SE_TYPE_ID_DBG			0x1
> -#define SE_TYPE_ID_HSM			0x2
> -
>  struct se_fw_img_name {
>  	const u8 *prim_fw_nm_in_rfs;
>  	const u8 *seco_fw_nm_in_rfs;
> @@ -130,6 +125,13 @@ char *get_se_if_name(u8 se_if_id)
>  	return NULL;
>  }
>
> +static u32 get_se_soc_id(struct se_if_priv *priv)
> +{
> +	const struct se_soc_info *se_info = device_get_match_data(priv->dev);
> +
> +	return se_info->soc_id;
> +}
> +
>  static struct se_fw_load_info *get_load_fw_instance(struct se_if_priv *priv)
>  {
>  	return &var_se_info.load_fw;
> @@ -203,8 +205,213 @@ static int get_se_soc_info(struct se_if_priv *priv, const struct se_soc_info *se
>  	return 0;
>  }
>
> +static int load_firmware(struct se_if_priv *priv, const u8 *se_img_file_to_load)
> +{
> +	const struct firmware *fw = NULL;
> +	phys_addr_t se_fw_phyaddr;
> +	u8 *se_fw_buf;
> +	int ret;
> +
> +	if (!se_img_file_to_load) {
> +		dev_err(priv->dev, "FW image is not provided.");
> +		return -EINVAL;
> +	}
> +	ret = request_firmware(&fw, se_img_file_to_load, priv->dev);
> +	if (ret)
> +		return ret;
> +
> +	dev_info(priv->dev, "loading firmware %s.", se_img_file_to_load);
> +
> +	/* allocate buffer to store the SE FW */
> +	se_fw_buf = dma_alloc_coherent(priv->dev, fw->size, &se_fw_phyaddr, GFP_KERNEL);
> +	if (!se_fw_buf) {
> +		ret = -ENOMEM;
> +		goto exit;
> +	}
> +
> +	memcpy(se_fw_buf, fw->data, fw->size);
> +	ret = ele_fw_authenticate(priv, se_fw_phyaddr, se_fw_phyaddr);
> +	if (ret < 0) {
> +		dev_err(priv->dev,
> +			"Error %pe: Authenticate & load SE firmware %s.",
> +			ERR_PTR(ret), se_img_file_to_load);
> +		ret = -EPERM;
> +	}
> +	dma_free_coherent(priv->dev, fw->size, se_fw_buf, se_fw_phyaddr);
> +exit:
> +	release_firmware(fw);
> +
> +	return ret;
> +}
> +
> +static int se_load_firmware(struct se_if_priv *priv)
> +{
> +	struct se_fw_load_info *load_fw = get_load_fw_instance(priv);
> +	int ret = 0;
> +
> +	if (!load_fw->is_fw_tobe_loaded)
> +		return 0;
> +
> +	if (load_fw->imem.state == ELE_IMEM_STATE_BAD) {
> +		ret = load_firmware(priv, load_fw->se_fw_img_nm->prim_fw_nm_in_rfs);
> +		if (ret) {
> +			dev_err(priv->dev, "Failed to load boot firmware.");
> +			return -EPERM;
> +		}
> +	}
> +
> +	ret = load_firmware(priv, load_fw->se_fw_img_nm->seco_fw_nm_in_rfs);
> +	if (ret) {
> +		dev_err(priv->dev, "Failed to load runtime firmware.");
> +		return -EPERM;
> +	}
> +
> +	load_fw->is_fw_tobe_loaded = false;
> +
> +	return ret;
> +}
> +
> +static int init_se_shared_mem(struct se_if_device_ctx *dev_ctx)
> +{
> +	struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
> +	struct se_if_priv *priv = dev_ctx->priv;
> +
> +	INIT_LIST_HEAD(&se_shared_mem_mgmt->pending_out);
> +	INIT_LIST_HEAD(&se_shared_mem_mgmt->pending_in);
> +
> +	/*
> +	 * Allocate some memory for data exchanges with S40x.
> +	 * This will be used for data not requiring secure memory.
> +	 */
> +	se_shared_mem_mgmt->non_secure_mem.ptr =
> +			dma_alloc_coherent(priv->dev, MAX_DATA_SIZE_PER_USER,
> +					   &se_shared_mem_mgmt->non_secure_mem.dma_addr,
> +					   GFP_KERNEL);
> +	if (!se_shared_mem_mgmt->non_secure_mem.ptr)
> +		return -ENOMEM;
> +
> +	se_shared_mem_mgmt->non_secure_mem.size = MAX_DATA_SIZE_PER_USER;
> +	se_shared_mem_mgmt->non_secure_mem.pos = 0;
> +
> +	return 0;
> +}
> +
> +static void cleanup_se_shared_mem(struct se_if_device_ctx *dev_ctx)
> +{
> +	struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
> +	struct se_if_priv *priv = dev_ctx->priv;
> +
> +	/* Free non-secure shared buffer. */
> +	dma_free_coherent(priv->dev, MAX_DATA_SIZE_PER_USER,
> +			  se_shared_mem_mgmt->non_secure_mem.ptr,
> +			  se_shared_mem_mgmt->non_secure_mem.dma_addr);
> +
> +	se_shared_mem_mgmt->non_secure_mem.ptr = NULL;
> +	se_shared_mem_mgmt->non_secure_mem.dma_addr = 0;
> +	se_shared_mem_mgmt->non_secure_mem.size = 0;
> +	se_shared_mem_mgmt->non_secure_mem.pos = 0;
> +}
> +
> +/* Need to copy the output data to user-device context.
> + */
> +static int se_dev_ctx_cpy_out_data(struct se_if_device_ctx *dev_ctx)
> +{
> +	struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
> +	struct se_if_priv *priv = dev_ctx->priv;
> +	struct se_buf_desc *b_desc, *temp;
> +	bool do_cpy = true;
> +
> +	list_for_each_entry_safe(b_desc, temp, &se_shared_mem_mgmt->pending_out, link) {
> +		if (b_desc->usr_buf_ptr && b_desc->shared_buf_ptr && do_cpy) {
> +			dev_dbg(priv->dev, "Copying output data to user.");
> +			if (do_cpy && copy_to_user(b_desc->usr_buf_ptr,
> +						   b_desc->shared_buf_ptr,
> +						   b_desc->size)) {
> +				dev_err(priv->dev, "Failure copying output data to user.");
> +				do_cpy = false;
> +			}
> +		}
> +
> +		if (b_desc->shared_buf_ptr)
> +			memset(b_desc->shared_buf_ptr, 0, b_desc->size);
> +
> +		list_del(&b_desc->link);
> +		kfree(b_desc);
> +	}
> +
> +	return do_cpy ? 0 : -EFAULT;
> +}
> +
> +/*
> + * Clean the used Shared Memory space,
> + * whether its Input Data copied from user buffers, or
> + * Data received from FW.
> + */
> +static void se_dev_ctx_shared_mem_cleanup(struct se_if_device_ctx *dev_ctx)
> +{
> +	struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
> +	struct list_head *pending_lists[] = {&se_shared_mem_mgmt->pending_in,
> +						&se_shared_mem_mgmt->pending_out};
> +	struct se_buf_desc *b_desc, *temp;
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(pending_lists); i++) {
> +		list_for_each_entry_safe(b_desc, temp, pending_lists[i], link) {
> +			if (b_desc->shared_buf_ptr)
> +				memset(b_desc->shared_buf_ptr, 0, b_desc->size);
> +
> +			list_del(&b_desc->link);
> +			kfree(b_desc);
> +		}
> +	}
> +	se_shared_mem_mgmt->non_secure_mem.pos = 0;
> +}
> +
> +static int add_b_desc_to_pending_list(void *shared_ptr_with_pos,
> +				      struct se_ioctl_setup_iobuf *io,
> +				      struct se_if_device_ctx *dev_ctx)
> +{
> +	struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
> +	struct se_buf_desc *b_desc;
> +
> +	b_desc = kzalloc(sizeof(*b_desc), GFP_KERNEL);
> +	if (!b_desc)
> +		return -ENOMEM;
> +
> +	b_desc->shared_buf_ptr = shared_ptr_with_pos;
> +	b_desc->usr_buf_ptr = io->user_buf;
> +	b_desc->size = io->length;
> +
> +	if (io->flags & SE_IO_BUF_FLAGS_IS_INPUT) {
> +		/*
> +		 * buffer is input:
> +		 * add an entry in the "pending input buffers" list so
> +		 * that copied data can be cleaned from shared memory
> +		 * later.
> +		 */
> +		list_add_tail(&b_desc->link, &se_shared_mem_mgmt->pending_in);
> +	} else {
> +		/*
> +		 * buffer is output:
> +		 * add an entry in the "pending out buffers" list so data
> +		 * can be copied to user space when receiving Secure-Enclave
> +		 * response.
> +		 */
> +		list_add_tail(&b_desc->link, &se_shared_mem_mgmt->pending_out);
> +	}
> +
> +	return 0;
> +}
> +
> +/* interface for managed res to unregister a character device */
> +static void if_misc_deregister(void *miscdevice)
> +{
> +	misc_deregister(miscdevice);
> +}
> +
>  static int init_misc_device_context(struct se_if_priv *priv, int ch_id,
> -				    struct se_if_device_ctx **new_dev_ctx)
> +				    struct se_if_device_ctx **new_dev_ctx,
> +				    const struct file_operations *se_if_fops)
>  {
>  	struct se_if_device_ctx *dev_ctx;
>  	int ret = 0;
> @@ -220,12 +427,520 @@ static int init_misc_device_context(struct se_if_priv *priv, int ch_id,
>  	if (!dev_ctx->devname)
>  		return -ENOMEM;
>
> +	mutex_init(&dev_ctx->fops_lock);
> +
>  	dev_ctx->priv = priv;
>  	*new_dev_ctx = dev_ctx;
>
> +	dev_ctx->miscdev = devm_kzalloc(priv->dev, sizeof(*dev_ctx->miscdev), GFP_KERNEL);
> +	if (!dev_ctx->miscdev) {
> +		*new_dev_ctx = NULL;
> +		return -ENOMEM;
> +	}
> +
> +	dev_ctx->miscdev->name = dev_ctx->devname;
> +	dev_ctx->miscdev->minor = MISC_DYNAMIC_MINOR;
> +	dev_ctx->miscdev->fops = se_if_fops;
> +	dev_ctx->miscdev->parent = priv->dev;
> +	ret = misc_register(dev_ctx->miscdev);
> +	if (ret)
> +		return dev_err_probe(priv->dev, ret, "Failed to register misc device.");
> +
> +	ret = devm_add_action_or_reset(priv->dev, if_misc_deregister, dev_ctx->miscdev);
> +	if (ret)
> +		return dev_err_probe(priv->dev, ret,
> +				     "Failed to add action to the misc-dev.");
>  	return ret;
>  }
>
> +static int init_device_context(struct se_if_priv *priv, int ch_id,
> +			       struct se_if_device_ctx **new_dev_ctx)
> +{
> +	struct se_if_device_ctx *dev_ctx;
> +	int ret = 0;
> +
> +	dev_ctx = kzalloc(sizeof(*dev_ctx), GFP_KERNEL);
> +
> +	if (!dev_ctx)
> +		return -ENOMEM;
> +
> +	dev_ctx->devname = kasprintf(GFP_KERNEL, "%s0_ch%d",
> +				     get_se_if_name(priv->if_defs->se_if_type),
> +				     ch_id);
> +	if (!dev_ctx->devname) {
> +		kfree(dev_ctx);
> +		return -ENOMEM;
> +	}
> +
> +	mutex_init(&dev_ctx->fops_lock);
> +	dev_ctx->priv = priv;
> +	*new_dev_ctx = dev_ctx;
> +
> +	list_add_tail(&dev_ctx->link, &priv->dev_ctx_list);
> +	priv->active_devctx_count++;
> +
> +	ret = init_se_shared_mem(dev_ctx);
> +	if (ret < 0) {
> +		kfree(dev_ctx->devname);
> +		kfree(dev_ctx);
> +		*new_dev_ctx = NULL;
> +	}
> +
> +	return ret;
> +}
> +
> +static int se_ioctl_cmd_snd_rcv_rsp_handler(struct se_if_device_ctx *dev_ctx,
> +					    u64 arg)
> +{
> +	struct se_ioctl_cmd_snd_rcv_rsp_info cmd_snd_rcv_rsp_info = {0};
> +	struct se_api_msg *tx_msg = NULL;
> +	struct se_api_msg *rx_msg = NULL;
> +	struct se_if_priv *priv = dev_ctx->priv;
> +	int err = 0;
> +
> +	if (copy_from_user(&cmd_snd_rcv_rsp_info, (u8 __user *)arg,
> +			   sizeof(cmd_snd_rcv_rsp_info))) {
> +		dev_err(priv->dev,
> +			"%s: Failed to copy cmd_snd_rcv_rsp_info from user.",
> +			dev_ctx->devname);
> +		err = -EFAULT;
> +		goto exit;
> +	}
> +
> +	if (cmd_snd_rcv_rsp_info.tx_buf_sz < SE_MU_HDR_SZ) {
> +		dev_err(priv->dev, "%s: User buffer too small(%d < %d)",
> +			dev_ctx->devname, cmd_snd_rcv_rsp_info.tx_buf_sz, SE_MU_HDR_SZ);
> +		err = -ENOSPC;
> +		goto exit;
> +	}
> +
> +	err = se_chk_tx_msg_hdr(priv, (struct se_msg_hdr *)cmd_snd_rcv_rsp_info.tx_buf);
> +	if (err)
> +		goto exit;
> +
> +	rx_msg = kzalloc(cmd_snd_rcv_rsp_info.rx_buf_sz, GFP_KERNEL);
> +	if (!rx_msg) {
> +		err = -ENOMEM;
> +		goto exit;
> +	}
> +
> +	tx_msg = memdup_user(cmd_snd_rcv_rsp_info.tx_buf,
> +			     cmd_snd_rcv_rsp_info.tx_buf_sz);
> +	if (IS_ERR(tx_msg)) {
> +		err = PTR_ERR(tx_msg);
> +		goto exit;
> +	}
> +
> +	if (tx_msg->header.tag != priv->if_defs->cmd_tag) {
> +		err = -EINVAL;
> +		goto exit;
> +	}
> +
> +	if (tx_msg->header.ver == priv->if_defs->fw_api_ver &&
> +	    get_load_fw_instance(priv)->is_fw_tobe_loaded) {
> +		err = se_load_firmware(priv);
> +		if (err) {
> +			dev_err(priv->dev, "Could not send msg as FW is not loaded.");
> +			err = -EPERM;
> +			goto exit;
> +		}
> +	}
> +	set_se_rcv_msg_timeout(priv, SE_RCV_MSG_LONG_TIMEOUT);
> +
> +	err = ele_msg_send_rcv(dev_ctx, tx_msg, cmd_snd_rcv_rsp_info.tx_buf_sz,
> +			       rx_msg, cmd_snd_rcv_rsp_info.rx_buf_sz);
> +	if (err < 0)
> +		goto exit;
> +
> +	dev_dbg(priv->dev, "%s: %s %s.", dev_ctx->devname, __func__,
> +		"message received, start transmit to user");
> +
> +	/* We may need to copy the output data to user before
> +	 * delivering the completion message.
> +	 */
> +	err = se_dev_ctx_cpy_out_data(dev_ctx);
> +	if (err < 0)
> +		goto exit;
> +
> +	/* Copy data from the buffer */
> +	print_hex_dump_debug("to user ", DUMP_PREFIX_OFFSET, 4, 4, rx_msg,
> +			     cmd_snd_rcv_rsp_info.rx_buf_sz, false);
> +
> +	if (copy_to_user(cmd_snd_rcv_rsp_info.rx_buf, rx_msg,
> +			 cmd_snd_rcv_rsp_info.rx_buf_sz)) {
> +		dev_err(priv->dev, "%s: Failed to copy to user.", dev_ctx->devname);
> +		err = -EFAULT;
> +	}
> +
> +exit:
> +
> +	/* shared memory is allocated before this IOCTL */
> +	se_dev_ctx_shared_mem_cleanup(dev_ctx);
> +
> +	if (copy_to_user((void __user *)arg, &cmd_snd_rcv_rsp_info,
> +			 sizeof(cmd_snd_rcv_rsp_info))) {
> +		dev_err(priv->dev, "%s: Failed to copy cmd_snd_rcv_rsp_info from user.",
> +			dev_ctx->devname);
> +		err = -EFAULT;
> +	}
> +
> +	kfree(tx_msg);
> +	kfree(rx_msg);
> +	return err;
> +}
> +
> +static int se_ioctl_get_mu_info(struct se_if_device_ctx *dev_ctx,
> +				u64 arg)
> +{
> +	struct se_if_priv *priv = dev_ctx->priv;
> +	struct se_ioctl_get_if_info if_info;
> +	struct se_if_node *if_node;
> +	int err = 0;
> +
> +	if_node = container_of(priv->if_defs, typeof(*if_node), if_defs);
> +
> +	if_info.se_if_id = 0;
> +	if_info.interrupt_idx = 0;
> +	if_info.tz = 0;
> +	if_info.did = 0;
> +	if_info.cmd_tag = priv->if_defs->cmd_tag;
> +	if_info.rsp_tag = priv->if_defs->rsp_tag;
> +	if_info.success_tag = priv->if_defs->success_tag;
> +	if_info.base_api_ver = priv->if_defs->base_api_ver;
> +	if_info.fw_api_ver = priv->if_defs->fw_api_ver;
> +
> +	dev_dbg(priv->dev, "%s: info [se_if_id: %d, irq_idx: %d, tz: 0x%x, did: 0x%x].",
> +		dev_ctx->devname, if_info.se_if_id, if_info.interrupt_idx, if_info.tz,
> +		if_info.did);
> +
> +	if (copy_to_user((u8 __user *)arg, &if_info, sizeof(if_info))) {
> +		dev_err(priv->dev, "%s: Failed to copy mu info to user.",
> +			dev_ctx->devname);
> +		err = -EFAULT;
> +	}
> +
> +	return err;
> +}
> +
> +/*
> + * Copy a buffer of data to/from the user and return the address to use in
> + * messages
> + */
> +static int se_ioctl_setup_iobuf_handler(struct se_if_device_ctx *dev_ctx,
> +					u64 arg)
> +{
> +	struct se_shared_mem *shared_mem = NULL;
> +	struct se_ioctl_setup_iobuf io = {0};
> +	int err = 0;
> +	u32 pos;
> +
> +	if (copy_from_user(&io, (u8 __user *)arg, sizeof(io))) {
> +		dev_err(dev_ctx->priv->dev, "%s: Failed copy iobuf config from user.",
> +			dev_ctx->devname);
> +		return -EFAULT;
> +	}
> +
> +	dev_dbg(dev_ctx->priv->dev, "%s: io [buf: %p(%d) flag: %x].", dev_ctx->devname,
> +		io.user_buf, io.length, io.flags);
> +
> +	if (io.length == 0 || !io.user_buf) {
> +		/*
> +		 * Accept NULL pointers since some buffers are optional
> +		 * in FW commands. In this case we should return 0 as
> +		 * pointer to be embedded into the message.
> +		 * Skip all data copy part of code below.
> +		 */
> +		io.ele_addr = 0;
> +		goto copy;
> +	}
> +
> +	/* No specific requirement for this buffer. */
> +	shared_mem = &dev_ctx->se_shared_mem_mgmt.non_secure_mem;
> +
> +	/* Check there is enough space in the shared memory. */
> +	dev_dbg(dev_ctx->priv->dev, "%s: req_size = %d, max_size= %d, curr_pos = %d",
> +		dev_ctx->devname, round_up(io.length, 8u), shared_mem->size,
> +		shared_mem->pos);
> +
> +	if (shared_mem->size < shared_mem->pos ||
> +	    round_up(io.length, 8u) > (shared_mem->size - shared_mem->pos)) {
> +		dev_err(dev_ctx->priv->dev, "%s: Not enough space in shared memory.",
> +			dev_ctx->devname);
> +		return -ENOMEM;
> +	}
> +
> +	/* Allocate space in shared memory. 8 bytes aligned. */
> +	pos = shared_mem->pos;
> +	shared_mem->pos += round_up(io.length, 8u);
> +	io.ele_addr = (u64)shared_mem->dma_addr + pos;
> +
> +	memset(shared_mem->ptr + pos, 0, io.length);
> +	if ((io.flags & SE_IO_BUF_FLAGS_IS_INPUT) ||
> +	    (io.flags & SE_IO_BUF_FLAGS_IS_IN_OUT)) {
> +		/*
> +		 * buffer is input:
> +		 * copy data from user space to this allocated buffer.
> +		 */
> +		if (copy_from_user(shared_mem->ptr + pos, io.user_buf, io.length)) {
> +			dev_err(dev_ctx->priv->dev,
> +				"%s: Failed copy data to shared memory.",
> +				dev_ctx->devname);
> +			return -EFAULT;
> +		}
> +	}
> +
> +	err = add_b_desc_to_pending_list(shared_mem->ptr + pos, &io, dev_ctx);
> +	if (err < 0)
> +		dev_err(dev_ctx->priv->dev, "%s: Failed to allocate/link b_desc.",
> +			dev_ctx->devname);
> +
> +copy:
> +	/* Provide the EdgeLock Enclave address to user space only if success.*/
> +	if (copy_to_user((u8 __user *)arg, &io, sizeof(io))) {
> +		dev_err(dev_ctx->priv->dev, "%s: Failed to copy iobuff setup to user.",
> +			dev_ctx->devname);
> +		err = -EFAULT;
> +	}
> +
> +	return err;
> +}
> +
> +/* IOCTL to provide SoC information */
> +static int se_ioctl_get_se_soc_info_handler(struct se_if_device_ctx *dev_ctx, u64 arg)
> +{
> +	struct se_ioctl_get_soc_info soc_info;
> +	int err = -EINVAL;
> +
> +	soc_info.soc_id = get_se_soc_id(dev_ctx->priv);
> +	soc_info.soc_rev = var_se_info.soc_rev;
> +
> +	err = copy_to_user((u8 __user *)arg, (u8 *)(&soc_info), sizeof(soc_info));
> +	if (err) {
> +		dev_err(dev_ctx->priv->dev, "%s: Failed to copy soc info to user.",
> +			dev_ctx->devname);
> +		err = -EFAULT;
> +	}
> +
> +	return err;
> +}
> +
> +/*
> + * File operations for user-space
> + */
> +
> +/* Write a message to the MU. */
> +static ssize_t se_if_fops_write(struct file *fp, const char __user *buf,
> +				size_t size, loff_t *ppos)
> +{
> +	struct se_if_device_ctx *dev_ctx = fp->private_data;
> +	struct se_api_msg *tx_msg = NULL;
> +	struct se_if_priv *priv = dev_ctx->priv;
> +	int err;
> +
> +	dev_dbg(priv->dev, "%s: write from buf (%p)%zu, ppos=%lld.", dev_ctx->devname,
> +		buf, size, ((ppos) ? *ppos : 0));
> +
> +	scoped_cond_guard(mutex_intr, return -EBUSY, &dev_ctx->fops_lock) {
> +		if (dev_ctx != priv->cmd_receiver_clbk_hdl.dev_ctx)
> +			return -EINVAL;
> +
> +		err = se_chk_tx_msg_hdr(priv, (struct se_msg_hdr *)buf);
> +		if (err)
> +			return err;
> +
> +		if (size < SE_MU_HDR_SZ) {
> +			dev_err(priv->dev, "%s: User buffer too small(%zu < %d).",
> +				dev_ctx->devname, size, SE_MU_HDR_SZ);
> +			return -ENOSPC;
> +		}
> +
> +		tx_msg = memdup_user(buf, size);
> +		if (IS_ERR(tx_msg))
> +			return PTR_ERR(tx_msg);
> +
> +		print_hex_dump_debug("from user ", DUMP_PREFIX_OFFSET, 4, 4,
> +				     tx_msg, size, false);
> +
> +		err = ele_msg_send(dev_ctx, tx_msg, size);
> +
> +		kfree(tx_msg);
> +		return err;
> +	}
> +}
> +
> +/*
> + * Read a message from the MU.
> + * Blocking until a message is available.
> + */
> +static ssize_t se_if_fops_read(struct file *fp, char __user *buf, size_t size,
> +			       loff_t *ppos)
> +{
> +	struct se_if_device_ctx *dev_ctx = fp->private_data;
> +	struct se_if_priv *priv = dev_ctx->priv;
> +	int err;
> +
> +	dev_dbg(priv->dev, "%s: read to buf %p(%zu), ppos=%lld.", dev_ctx->devname,
> +		buf, size, ((ppos) ? *ppos : 0));
> +
> +	scoped_cond_guard(mutex_intr, return -EBUSY, &dev_ctx->fops_lock) {
> +		if (dev_ctx != priv->cmd_receiver_clbk_hdl.dev_ctx) {
> +			err = -EINVAL;
> +			goto exit;
> +		}
> +
> +		err = ele_msg_rcv(dev_ctx, &priv->cmd_receiver_clbk_hdl);
> +		if (err < 0) {
> +			dev_err(priv->dev, "%s: Err[0x%x]:Interrupted by signal."
> +				"Current active dev-ctx count = %d.",
> +				dev_ctx->devname, err, dev_ctx->priv->active_devctx_count);
> +			goto exit;
> +		}
> +
> +		/* We may need to copy the output data to user before
> +		 * delivering the completion message.
> +		 */
> +		err = se_dev_ctx_cpy_out_data(dev_ctx);
> +		if (err < 0)
> +			goto exit;
> +
> +		/* Copy data from the buffer */
> +		print_hex_dump_debug("to user ", DUMP_PREFIX_OFFSET, 4, 4,
> +				     priv->cmd_receiver_clbk_hdl.rx_msg,
> +				     priv->cmd_receiver_clbk_hdl.rx_msg_sz,
> +				     false);
> +
> +		if (copy_to_user(buf, priv->cmd_receiver_clbk_hdl.rx_msg,
> +				 priv->cmd_receiver_clbk_hdl.rx_msg_sz)) {
> +			dev_err(priv->dev, "%s: Failed to copy to user.",
> +				dev_ctx->devname);
> +			err = -EFAULT;
> +		} else {
> +			err = priv->cmd_receiver_clbk_hdl.rx_msg_sz;
> +		}
> +exit:
> +		priv->cmd_receiver_clbk_hdl.rx_msg_sz = 0;
> +
> +		se_dev_ctx_shared_mem_cleanup(dev_ctx);
> +
> +		return err;
> +	}
> +}
> +
> +/* Open a character device. */
> +static int se_if_fops_open(struct inode *nd, struct file *fp)
> +{
> +	struct miscdevice *miscdev = fp->private_data;
> +	struct se_if_device_ctx *misc_dev_ctx;
> +	struct se_if_device_ctx *dev_ctx;
> +	struct se_if_priv *priv;
> +	int err = 0;
> +
> +	priv = dev_get_drvdata(miscdev->parent);
> +	misc_dev_ctx = priv->priv_dev_ctx;
> +
> +	scoped_cond_guard(mutex_intr, return -EBUSY, &misc_dev_ctx->fops_lock) {
> +		priv->dev_ctx_mono_count++;
> +		err = init_device_context(priv,
> +					  priv->dev_ctx_mono_count ?
> +					  priv->dev_ctx_mono_count
> +					  : priv->dev_ctx_mono_count++,
> +					  &dev_ctx);
> +		if (err)
> +			dev_err(priv->dev, "Failed[0x%x] to create dev-ctx.", err);
> +		else
> +			fp->private_data = dev_ctx;
> +
> +		return err;
> +	}
> +}
> +
> +/* Close a character device. */
> +static int se_if_fops_close(struct inode *nd, struct file *fp)
> +{
> +	struct se_if_device_ctx *dev_ctx = fp->private_data;
> +	struct se_if_priv *priv = dev_ctx->priv;
> +
> +	scoped_cond_guard(mutex_intr, return -EBUSY, &dev_ctx->fops_lock) {
> +		/* check if this device was registered as command receiver. */
> +		if (priv->cmd_receiver_clbk_hdl.dev_ctx == dev_ctx) {
> +			priv->cmd_receiver_clbk_hdl.dev_ctx = NULL;
> +			kfree(priv->cmd_receiver_clbk_hdl.rx_msg);
> +			priv->cmd_receiver_clbk_hdl.rx_msg = NULL;
> +		}
> +
> +		se_dev_ctx_shared_mem_cleanup(dev_ctx);
> +		cleanup_se_shared_mem(dev_ctx);
> +
> +		priv->active_devctx_count--;
> +		list_del(&dev_ctx->link);
> +
> +		kfree(dev_ctx->devname);
> +		kfree(dev_ctx);
> +	}
> +
> +	return 0;
> +}
> +
> +/* IOCTL entry point of a character device */
> +static long se_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
> +{
> +	struct se_if_device_ctx *dev_ctx = fp->private_data;
> +	struct se_if_priv *priv = dev_ctx->priv;
> +	long err;
> +
> +	/* Prevent race during change of device context */
> +	scoped_cond_guard(mutex_intr, return -EBUSY, &dev_ctx->fops_lock) {
> +		switch (cmd) {
> +		case SE_IOCTL_ENABLE_CMD_RCV:
> +			if (!priv->cmd_receiver_clbk_hdl.dev_ctx) {
> +				if (!priv->cmd_receiver_clbk_hdl.rx_msg) {
> +					priv->cmd_receiver_clbk_hdl.rx_msg =
> +						kzalloc(MAX_NVM_MSG_LEN,
> +							GFP_KERNEL);
> +					if (!priv->cmd_receiver_clbk_hdl.rx_msg) {
> +						err = -ENOMEM;
> +						break;
> +					}
> +				}
> +				priv->cmd_receiver_clbk_hdl.rx_msg_sz = MAX_NVM_MSG_LEN;
> +				priv->cmd_receiver_clbk_hdl.dev_ctx = dev_ctx;
> +				err = 0;
> +			} else {
> +				err = -EBUSY;
> +			}
> +			break;
> +		case SE_IOCTL_GET_MU_INFO:
> +			err = se_ioctl_get_mu_info(dev_ctx, arg);
> +			break;
> +		case SE_IOCTL_SETUP_IOBUF:
> +			err = se_ioctl_setup_iobuf_handler(dev_ctx, arg);
> +			break;
> +		case SE_IOCTL_GET_SOC_INFO:
> +			err = se_ioctl_get_se_soc_info_handler(dev_ctx, arg);
> +			break;
> +		case SE_IOCTL_CMD_SEND_RCV_RSP:
> +			err = se_ioctl_cmd_snd_rcv_rsp_handler(dev_ctx, arg);
> +			break;
> +		default:
> +			err = -EINVAL;
> +			dev_dbg(priv->dev, "%s: IOCTL %.8x not supported.",
> +				dev_ctx->devname, cmd);
> +		}
> +	}
> +
> +	return err;
> +}
> +
> +/* Char driver setup */
> +static const struct file_operations se_if_fops = {
> +	.open		= se_if_fops_open,
> +	.owner		= THIS_MODULE,
> +	.release	= se_if_fops_close,
> +	.unlocked_ioctl = se_ioctl,
> +	.read		= se_if_fops_read,
> +	.write		= se_if_fops_write,
> +};
> +
>  /* interface for managed res to free a mailbox channel */
>  static void if_mbox_free_channel(void *mbox_chan)
>  {
> @@ -246,7 +961,7 @@ static int se_if_request_channel(struct device *dev, struct mbox_chan **chan,
>  	ret = devm_add_action_or_reset(dev, if_mbox_free_channel, t_chan);
>  	if (ret)
>  		return dev_err_probe(dev, -EPERM,
> -				     "Failed to add-action for removal of mbox: %s\n",
> +				     "Failed to add-action for removal of mbox: %s.",
>  				     name);
>  	*chan = t_chan;
>
> @@ -255,6 +970,7 @@ static int se_if_request_channel(struct device *dev, struct mbox_chan **chan,
>
>  static void se_if_probe_cleanup(void *plat_dev)
>  {
> +	struct se_if_device_ctx *dev_ctx, *t_dev_ctx;
>  	struct platform_device *pdev = plat_dev;
>  	struct se_fw_load_info *load_fw;
>  	struct device *dev = &pdev->dev;
> @@ -279,6 +995,13 @@ static void se_if_probe_cleanup(void *plat_dev)
>  		load_fw->imem.buf = NULL;
>  	}
>
> +	if (priv->dev_ctx_mono_count) {
> +		list_for_each_entry_safe(dev_ctx, t_dev_ctx, &priv->dev_ctx_list, link) {
> +			list_del(&dev_ctx->link);
> +			priv->active_devctx_count--;
> +		}
> +	}
> +
>  	/*
>  	 * No need to check, if reserved memory is allocated
>  	 * before calling for its release. Or clearing the
> @@ -319,6 +1042,7 @@ static int se_if_probe(struct platform_device *pdev)
>  	priv->se_mb_cl.tx_block		= false;
>  	priv->se_mb_cl.knows_txdone	= true;
>  	priv->se_mb_cl.rx_callback	= se_if_rx_callback;
> +	set_se_rcv_msg_timeout(priv, SE_RCV_MSG_DEFAULT_TIMEOUT);
>
>  	ret = se_if_request_channel(dev, &priv->tx_chan, &priv->se_mb_cl, MBOX_TX_NAME);
>  	if (ret)
> @@ -340,6 +1064,7 @@ static int se_if_probe(struct platform_device *pdev)
>  					     "Unable to get sram pool = %s.",
>  					     if_node->pool_name);
>  	}
> +	INIT_LIST_HEAD(&priv->dev_ctx_list);
>
>  	if (if_node->reserved_dma_ranges) {
>  		ret = of_reserved_mem_device_init(dev);
> @@ -348,7 +1073,7 @@ static int se_if_probe(struct platform_device *pdev)
>  					    "Failed to init reserved memory region.");
>  	}
>
> -	ret = init_misc_device_context(priv, 0, &priv->priv_dev_ctx);
> +	ret = init_misc_device_context(priv, 0, &priv->priv_dev_ctx, &se_if_fops);
>  	if (ret)
>  		return dev_err_probe(dev, ret,
>  				     "Failed[0x%x] to create device contexts.",
> @@ -389,6 +1114,7 @@ static int se_suspend(struct device *dev)
>  	struct se_fw_load_info *load_fw;
>  	int ret = 0;
>
> +	set_se_rcv_msg_timeout(priv, SE_RCV_MSG_DEFAULT_TIMEOUT);
>  	load_fw = get_load_fw_instance(priv);
>
>  	if (load_fw->imem_mgmt) {
> diff --git a/drivers/firmware/imx/se_ctrl.h b/drivers/firmware/imx/se_ctrl.h
> index b5e7705e2f26..5fcdcfe3e8e5 100644
> --- a/drivers/firmware/imx/se_ctrl.h
> +++ b/drivers/firmware/imx/se_ctrl.h
> @@ -14,6 +14,7 @@
>  #define SE_MSG_WORD_SZ			0x4
>
>  #define RES_STATUS(x)			FIELD_GET(0x000000ff, x)
> +#define MAX_DATA_SIZE_PER_USER		(65 * 1024)
>  #define MAX_NVM_MSG_LEN			(256)
>  #define MESSAGING_VERSION_6		0x6
>  #define MESSAGING_VERSION_7		0x7
> @@ -37,10 +38,38 @@ struct se_imem_buf {
>  	u32 state;
>  };
>
> +struct se_buf_desc {
> +	u8 *shared_buf_ptr;
> +	void __user *usr_buf_ptr;
> +	u32 size;
> +	struct list_head link;
> +};
> +
> +struct se_shared_mem {
> +	dma_addr_t dma_addr;
> +	u32 size;
> +	u32 pos;
> +	u8 *ptr;
> +};
> +
> +struct se_shared_mem_mgmt_info {
> +	struct list_head pending_in;
> +	struct list_head pending_out;
> +
> +	struct se_shared_mem non_secure_mem;
> +};
> +
>  /* Private struct for each char device instance. */
>  struct se_if_device_ctx {
>  	struct se_if_priv *priv;
> +	struct miscdevice *miscdev;
>  	const char *devname;
> +
> +	/* process one file operation at a time. */
> +	struct mutex fops_lock;
> +
> +	struct se_shared_mem_mgmt_info se_shared_mem_mgmt;
> +	struct list_head link;
>  };
>
>  /* Header of the messages exchange with the EdgeLock Enclave */
> @@ -89,6 +118,10 @@ struct se_if_priv {
>  	const struct se_if_defines *if_defs;
>
>  	struct se_if_device_ctx *priv_dev_ctx;
> +	struct list_head dev_ctx_list;
> +	u32 active_devctx_count;
> +	u32 dev_ctx_mono_count;
> +	u32 se_rcv_msg_timeout_ms;
>  };
>
>  char *get_se_if_name(u8 se_if_id);
> diff --git a/include/uapi/linux/se_ioctl.h b/include/uapi/linux/se_ioctl.h
> new file mode 100644
> index 000000000000..0c948bdc8c26
> --- /dev/null
> +++ b/include/uapi/linux/se_ioctl.h
> @@ -0,0 +1,97 @@
> +/* SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause*/
> +/*
> + * Copyright 2025 NXP
> + */
> +
> +#ifndef SE_IOCTL_H
> +#define SE_IOCTL_H
> +
> +#include <linux/types.h>
> +
> +#define SE_TYPE_STR_DBG			"dbg"
> +#define SE_TYPE_STR_HSM			"hsm"
> +#define SE_TYPE_ID_UNKWN		0x0
> +#define SE_TYPE_ID_DBG			0x1
> +#define SE_TYPE_ID_HSM			0x2
> +/* IOCTL definitions. */
> +
> +struct se_ioctl_setup_iobuf {
> +	void __user *user_buf;
> +	__u32 length;
> +	__u32 flags;
> +	__u64 ele_addr;
> +};
> +
> +struct se_ioctl_shared_mem_cfg {
> +	__u32 base_offset;
> +	__u32 size;
> +};
> +
> +struct se_ioctl_get_if_info {
> +	__u8 se_if_id;
> +	__u8 interrupt_idx;
> +	__u8 tz;
> +	__u8 did;
> +	__u8 cmd_tag;
> +	__u8 rsp_tag;
> +	__u8 success_tag;
> +	__u8 base_api_ver;
> +	__u8 fw_api_ver;
> +};
> +
> +struct se_ioctl_cmd_snd_rcv_rsp_info {
> +	__u32 __user *tx_buf;
> +	int tx_buf_sz;
> +	__u32 __user *rx_buf;
> +	int rx_buf_sz;
> +};
> +
> +struct se_ioctl_get_soc_info {
> +	__u16 soc_id;
> +	__u16 soc_rev;
> +};
> +
> +/* IO Buffer Flags */
> +#define SE_IO_BUF_FLAGS_IS_OUTPUT	(0x00u)
> +#define SE_IO_BUF_FLAGS_IS_INPUT	(0x01u)
> +#define SE_IO_BUF_FLAGS_USE_SEC_MEM	(0x02u)
> +#define SE_IO_BUF_FLAGS_USE_SHORT_ADDR	(0x04u)
> +#define SE_IO_BUF_FLAGS_IS_IN_OUT	(0x10u)
> +
> +/* IOCTLS */
> +#define SE_IOCTL			0x0A /* like MISC_MAJOR. */
> +
> +/*
> + * ioctl to designated the current fd as logical-reciever.
> + * This is ioctl is send when the nvm-daemon, a slave to the
> + * firmware is started by the user.
> + */
> +#define SE_IOCTL_ENABLE_CMD_RCV	_IO(SE_IOCTL, 0x01)
> +
> +/*
> + * ioctl to get the buffer allocated from the memory, which is shared
> + * between kernel and FW.
> + * Post allocation, the kernel tagged the allocated memory with:
> + *  Output
> + *  Input
> + *  Input-Output
> + *  Short address
> + *  Secure-memory
> + */
> +#define SE_IOCTL_SETUP_IOBUF	_IOWR(SE_IOCTL, 0x03, struct se_ioctl_setup_iobuf)
> +
> +/*
> + * ioctl to get the mu information, that is used to exchange message
> + * with FW, from user-spaced.
> + */
> +#define SE_IOCTL_GET_MU_INFO	_IOR(SE_IOCTL, 0x04, struct se_ioctl_get_if_info)
> +/*
> + * ioctl to get SoC Info from user-space.
> + */
> +#define SE_IOCTL_GET_SOC_INFO      _IOR(SE_IOCTL, 0x06, struct se_ioctl_get_soc_info)
> +
> +/*
> + * ioctl to send command and receive response from user-space.
> + */
> +#define SE_IOCTL_CMD_SEND_RCV_RSP _IOWR(SE_IOCTL, 0x07, struct se_ioctl_cmd_snd_rcv_rsp_info)
> +#endif
>
> --
> 2.43.0
>


From Frank.li at nxp.com  Fri Dec 12 09:02:32 2025
From: Frank.li at nxp.com (Frank Li)
Date: Fri, 12 Dec 2025 12:02:32 -0500
Subject: [PATCH 1/2] dt-bindings: power: fsl,imx-gpc: Document
 address-cells
In-Reply-To: <20251212085902.103507-1-alexander.stein@ew.tq-group.com>
References: <20251212085902.103507-1-alexander.stein@ew.tq-group.com>
Message-ID: <aTxKqPqGdiHllLo6@lizhi-Precision-Tower-5810>

On Fri, Dec 12, 2025 at 09:58:59AM +0100, Alexander Stein wrote:
> The GPC power controller is an interrupt controllers and can be referenced
> in interrupt-map properties, e.g. PCIe controller, thus the node should
> have address-cells property.
>
> Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>

Strange, there are not #address-cells property for gic if there are not
ITS node. gic is widely used.

Does gic node also missed #address-cells?

Frank

> ---
>  Documentation/devicetree/bindings/power/fsl,imx-gpc.yaml | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/power/fsl,imx-gpc.yaml b/Documentation/devicetree/bindings/power/fsl,imx-gpc.yaml
> index 9de3fe73c1eb6..d49a5130b87c7 100644
> --- a/Documentation/devicetree/bindings/power/fsl,imx-gpc.yaml
> +++ b/Documentation/devicetree/bindings/power/fsl,imx-gpc.yaml
> @@ -38,6 +38,9 @@ properties:
>    reg:
>      maxItems: 1
>
> +  "#address-cells":
> +    const: 0
> +
>    interrupts:
>      maxItems: 1
>
> --
> 2.43.0
>


From leo.yan at arm.com  Fri Dec 12 09:24:58 2025
From: leo.yan at arm.com (Leo Yan)
Date: Fri, 12 Dec 2025 17:24:58 +0000
Subject: [PATCH v2 0/2] perf arm_spe: Minor event configs housekeeping
Message-ID: <20251212-perf_c2c_update_event-v2-0-27df9a6cb1d4@arm.com>

This series is to clean up event configs and update the doc for the
memory events and related options on different archs.

A quick verifying on Orion6 board with commands:

  perf c2c record -e spe-load -- test
  perf c2c record -e spe-store -- test

Signed-off-by: Leo Yan <leo.yan at arm.com>
---
Changes in v2:
- Updated document with using table for memory events (James).
- Link to v1: https://lore.kernel.org/r/20251212-perf_c2c_update_event-v1-0-29a26c7a949b at arm.com

---
Leo Yan (2):
      perf mem: Simplify Arm SPE event config
      perf c2c: Update documentation for adding memory event table

 tools/perf/Documentation/perf-c2c.txt   | 51 ++++++++++++++++++++++++---------
 tools/perf/arch/arm64/util/mem-events.c |  4 +--
 2 files changed, 39 insertions(+), 16 deletions(-)
---
base-commit: cb015814f8b6eebcbb8e46e111d108892c5e6821
change-id: 20251212-perf_c2c_update_event-76d4eddebd23

Best regards,
-- 
Leo Yan <leo.yan at arm.com>



From leo.yan at arm.com  Fri Dec 12 09:24:59 2025
From: leo.yan at arm.com (Leo Yan)
Date: Fri, 12 Dec 2025 17:24:59 +0000
Subject: [PATCH v2 1/2] perf mem: Simplify Arm SPE event config
In-Reply-To: <20251212-perf_c2c_update_event-v2-0-27df9a6cb1d4@arm.com>
References: <20251212-perf_c2c_update_event-v2-0-27df9a6cb1d4@arm.com>
Message-ID: <20251212-perf_c2c_update_event-v2-1-27df9a6cb1d4@arm.com>

Since configuration fields default to zero, the zero assignments are
redundant, remove them.

Reviewed-by: James Clark <james.clark at linaro.org>
Signed-off-by: Leo Yan <leo.yan at arm.com>
---
 tools/perf/arch/arm64/util/mem-events.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/perf/arch/arm64/util/mem-events.c b/tools/perf/arch/arm64/util/mem-events.c
index 9f8da7937255cc9b14c3c58a1119b40bd0c76f6b..eaf00e0609c6c1b7d939a02fe3794471d1ed119b 100644
--- a/tools/perf/arch/arm64/util/mem-events.c
+++ b/tools/perf/arch/arm64/util/mem-events.c
@@ -6,7 +6,7 @@
 #define E(t, n, s, l, a) { .tag = t, .name = n, .event_name = s, .ldlat = l, .aux_event = a }
 
 struct perf_mem_event perf_mem_events_arm[PERF_MEM_EVENTS__MAX] = {
-	E("spe-load",	"%s/ts_enable=1,pa_enable=1,load_filter=1,store_filter=0,min_latency=%u/",	NULL,	true,	0),
-	E("spe-store",	"%s/ts_enable=1,pa_enable=1,load_filter=0,store_filter=1/",			NULL,	false,	0),
+	E("spe-load",	"%s/ts_enable=1,pa_enable=1,load_filter=1,min_latency=%u/",	NULL,	true,	0),
+	E("spe-store",	"%s/ts_enable=1,pa_enable=1,store_filter=1/",			NULL,	false,	0),
 	E("spe-ldst",	"%s/ts_enable=1,pa_enable=1,load_filter=1,store_filter=1,min_latency=%u/",	NULL,	true,	0),
 };

-- 
2.34.1



From leo.yan at arm.com  Fri Dec 12 09:25:00 2025
From: leo.yan at arm.com (Leo Yan)
Date: Fri, 12 Dec 2025 17:25:00 +0000
Subject: [PATCH v2 2/2] perf c2c: Update documentation for adding memory
 event table
In-Reply-To: <20251212-perf_c2c_update_event-v2-0-27df9a6cb1d4@arm.com>
References: <20251212-perf_c2c_update_event-v2-0-27df9a6cb1d4@arm.com>
Message-ID: <20251212-perf_c2c_update_event-v2-2-27df9a6cb1d4@arm.com>

Users may occasionally need to see which options are applied to memory
events.  This helps to understand the behavior of "perf c2c" and
"perf mem", and provides guidance for configuring memory event options
directly.

Add a table to track memory events and their corresponding options, and
include the Arm SPE events in it.

Suggested-by: Al Grant <al.grant at arm.com>
Signed-off-by: Leo Yan <leo.yan at arm.com>
---
 tools/perf/Documentation/perf-c2c.txt | 51 +++++++++++++++++++++++++----------
 1 file changed, 37 insertions(+), 14 deletions(-)

diff --git a/tools/perf/Documentation/perf-c2c.txt b/tools/perf/Documentation/perf-c2c.txt
index 40b0f71a2c44eb642ff3bb234631a614b7c4fc9d..e57a122b8719f1b2e20dd509959fc1563a6c20fd 100644
--- a/tools/perf/Documentation/perf-c2c.txt
+++ b/tools/perf/Documentation/perf-c2c.txt
@@ -160,20 +160,43 @@ Following perf record options are configured by default:
 
   -W,-d,--phys-data,--sample-cpu
 
-Unless specified otherwise with '-e' option, following events are monitored by
-default on Intel:
-
-  cpu/mem-loads,ldlat=30/P
-  cpu/mem-stores/P
-
-following on AMD:
-
-  ibs_op//
-
-and following on PowerPC:
-
-  cpu/mem-loads/
-  cpu/mem-stores/
+The following table lists the events monitored on different architectures.
+Unless specified otherwise with the -e option, the tool will select the
+default events.
+
+  +--------+---------------+-----------------+--------------------------------------------------------------------------------+
+  | Arch   | Configuration | Options         | Events                                                                         |
+  +--------+---------------+-----------------+--------------------------------------------------------------------------------+
+  | Intel  | Default       | -e ldlat-loads  | cpu/mem-loads,ldlat=30/P                                                       |
+  |        |               | -e ldlat-stores | cpu/mem-stores/P                                                               |
+  |        |---------------+-----------------+--------------------------------------------------------------------------------+
+  |        | Load only     | -e ldlat-loads  | cpu/mem-loads,ldlat=30/P                                                       |
+  |        |---------------+-----------------+--------------------------------------------------------------------------------+
+  |        | Store only    | -e ldlat-stores | cpu/mem-stores/P                                                               |
+  +--------+---------------+-----------------+--------------------------------------------------------------------------------+
+  | Intel  | Default       | -e ldlat-loads  | {cpu/mem-loads-aux/,cpu/mem-loads,ldlat=30/}:P                                 |
+  | with   |               | -e ldlat-stores | cpu/mem-stores/P                                                               |
+  | AUX    |--------------+------------------+--------------------------------------------------------------------------------+
+  |        | Load only     | -e ldlat-loads  | {cpu/mem-loads-aux/,cpu/mem-loads,ldlat=30/}:P                                 |
+  |        |---------------+-----------------+--------------------------------------------------------------------------------+
+  |        | Store only    | -e ldlat-stores | cpu/mem-stores/P                                                               |
+  +--------+---------------+-----------------+--------------------------------------------------------------------------------+
+  | AMD    | Default       | -e mem-ldst     | ibs_op// (without latency support)                                             |
+  |        |               |                 | ibs_op/ldlat=30/ (with latency support)                                        |
+  +--------+---------------+-----------------+--------------------------------------------------------------------------------+
+  | PowerPC| Default       | -e ldlat-loads  | cpu/mem-loads/                                                                 |
+  |        |               | -e ldlat-stores | cpu/mem-stores/                                                                |
+  |        |---------------+-----------------+--------------------------------------------------------------------------------+
+  |        | Load only     | -e ldlat-loads  | cpu/mem-loads/                                                                 |
+  |        |---------------+-----------------+--------------------------------------------------------------------------------+
+  |        | Store only    | -e ldlat-stores | cpu/mem-stores/                                                                |
+  +--------+---------------+-----------------+--------------------------------------------------------------------------------+
+  | Arm    | Default       | -e spe-ldst     | arm_spe_0/ts_enable=1,pa_enable=1,load_filter=1,store_filter=1,min_latency=30/ |
+  | SPE    |---------------+-----------------+--------------------------------------------------------------------------------+
+  |        | Load only     | -e spe-load     | arm_spe_0/ts_enable=1,pa_enable=1,load_filter=1,min_latency=30/                |
+  |        |---------------+-----------------+--------------------------------------------------------------------------------+
+  |        | Store only    | -e spe-store    | arm_spe_0/ts_enable=1,pa_enable=1,store_filter=1/                              |
+  +--------+---------------+-----------------+--------------------------------------------------------------------------------+
 
 User can pass any 'perf record' option behind '--' mark, like (to enable
 callchains and system wide monitoring):

-- 
2.34.1



From Frank.li at nxp.com  Fri Dec 12 09:25:48 2025
From: Frank.li at nxp.com (Frank Li)
Date: Fri, 12 Dec 2025 12:25:48 -0500
Subject: [PATCH 1/3] thermal/drivers/imx91: Check status before reading
 data
In-Reply-To: <20251212-imx91-thermal-v1-1-c208545b44cb@nxp.com>
References: <20251212-imx91-thermal-v1-0-c208545b44cb@nxp.com>
 <20251212-imx91-thermal-v1-1-c208545b44cb@nxp.com>
Message-ID: <aTxQHLh0OD89oc/g@lizhi-Precision-Tower-5810>

On Fri, Dec 12, 2025 at 03:51:14PM +0800, Peng Fan (OSS) wrote:
> From: Peng Fan <peng.fan at nxp.com>
>
> Per periodic mode from reference mannual:
> Write 1b to CTRL1[START]. Wait until STATm[DRDYn] becomes 1.
> Read DATAn[DATA_VAL]. It clears the corresponding STATm[DRDYn].
> DATAn[DATA_VAL] and STATm[DRDYn_IF] keep refreshing at a periodic interval
> of time, corresponding to PERIOD_CTRL[MEAS_FREQ].

It should get last time sample value without check DRDYn_IF bit. it should
only be a PERIOD_CTRL[MEAS_FREQ] delay.

worst case get value at previous's PERIOD_CTRL[MEAS_FREQ] sample.

PERIOD_CTRL[MEAS_FREQ] is quite short compare to call get_temp frequency.

Do you get invalidate data?

>
> Need to check STAT[DRDY] before reading the DATA register.
>
> And check the returned temperature to make sure it fits into the supported
> range (-40?C to +125?C).

https://lore.kernel.org/imx/aAIkAF_AHta8_vuS at mai.linaro.org/

Do you answer Daniel Lezcano's question
  ""When the measured temperature can be out of limits ?"  at v6 resend
patch.

Frank
>
> Signed-off-by: Peng Fan <peng.fan at nxp.com>
> ---
>  drivers/thermal/imx91_thermal.c | 10 ++++++++++
>  1 file changed, 10 insertions(+)
>
> diff --git a/drivers/thermal/imx91_thermal.c b/drivers/thermal/imx91_thermal.c
> index 9b20be03d6dec18553967548d0ca31d1c1fb387c..77e8e6a921c6af308b830c36721293c007256ca6 100644
> --- a/drivers/thermal/imx91_thermal.c
> +++ b/drivers/thermal/imx91_thermal.c
> @@ -108,10 +108,20 @@ static int imx91_tmu_get_temp(struct thermal_zone_device *tz, int *temp)
>  {
>  	struct imx91_tmu *tmu = thermal_zone_device_priv(tz);
>  	s16 data;
> +	int ret;
> +	u32 val;
> +
> +	ret = readl_relaxed_poll_timeout(tmu->base + IMX91_TMU_STAT0, val,
> +					 val & IMX91_TMU_STAT0_DRDY0_IF_MASK, 1000,
> +					 40000);
> +	if (ret)
> +		return -EAGAIN;
>
>  	/* DATA0 is 16bit signed number */
>  	data = readw_relaxed(tmu->base + IMX91_TMU_DATA0);
>  	*temp = imx91_tmu_to_mcelsius(data);
> +	if (*temp < IMX91_TMU_TEMP_LOW_LIMIT || *temp > IMX91_TMU_TEMP_HIGH_LIMIT)
> +		return -EAGAIN;
>
>  	return 0;
>  }
>
> --
> 2.37.1
>


From Frank.li at nxp.com  Fri Dec 12 09:29:41 2025
From: Frank.li at nxp.com (Frank Li)
Date: Fri, 12 Dec 2025 12:29:41 -0500
Subject: [PATCH 2/3] thermal/drivers/imx91: Drop extra spaces
In-Reply-To: <20251212-imx91-thermal-v1-2-c208545b44cb@nxp.com>
References: <20251212-imx91-thermal-v1-0-c208545b44cb@nxp.com>
 <20251212-imx91-thermal-v1-2-c208545b44cb@nxp.com>
Message-ID: <aTxRBVKuRAs6fCoZ@lizhi-Precision-Tower-5810>

On Fri, Dec 12, 2025 at 03:51:15PM +0800, Peng Fan (OSS) wrote:
> From: Peng Fan <peng.fan at nxp.com>
>
> Unify the code style, drop extra spaces for the macros.
>
> Signed-off-by: Peng Fan <peng.fan at nxp.com>
> ---
>  drivers/thermal/imx91_thermal.c | 22 +++++++++++-----------
>  1 file changed, 11 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/thermal/imx91_thermal.c b/drivers/thermal/imx91_thermal.c
> index 77e8e6a921c6af308b830c36721293c007256ca6..768c5acc384eca1c2203098bd4749628d9ffb8e6 100644
> --- a/drivers/thermal/imx91_thermal.c
> +++ b/drivers/thermal/imx91_thermal.c
> @@ -22,17 +22,17 @@
>  #define REG_TOG					0xc
>
>  #define IMX91_TMU_CTRL0				0x0
> -#define   IMX91_TMU_CTRL0_THR1_IE		BIT(9)
> -#define   IMX91_TMU_CTRL0_THR1_MASK		GENMASK(3, 2)
> -#define   IMX91_TMU_CTRL0_CLR_FLT1		BIT(21)
> +#define IMX91_TMU_CTRL0_THR1_IE			BIT(9)
> +#define IMX91_TMU_CTRL0_THR1_MASK		GENMASK(3, 2)
> +#define IMX91_TMU_CTRL0_CLR_FLT1		BIT(21)

It is used for register field. Many new driver use this style.

#define REGISTER_NAME
#define   REGISTER_FIELD

So register defination looks like tree. Reader can quick search field and
register name.

Frank


>
>  #define IMX91_TMU_THR_MODE_LE			0
>  #define IMX91_TMU_THR_MODE_GE			1
>
>  #define IMX91_TMU_STAT0				0x10
> -#define   IMX91_TMU_STAT0_THR1_IF		BIT(9)
> -#define   IMX91_TMU_STAT0_THR1_STAT		BIT(13)
> -#define   IMX91_TMU_STAT0_DRDY0_IF_MASK		BIT(16)
> +#define IMX91_TMU_STAT0_THR1_IF			BIT(9)
> +#define IMX91_TMU_STAT0_THR1_STAT		BIT(13)
> +#define IMX91_TMU_STAT0_DRDY0_IF_MASK		BIT(16)
>
>  #define IMX91_TMU_DATA0				0x20
>
> @@ -42,12 +42,12 @@
>  #define IMX91_TMU_CTRL1_STOP			BIT(29)
>  #define IMX91_TMU_CTRL1_RES_MASK		GENMASK(19, 18)
>  #define IMX91_TMU_CTRL1_MEAS_MODE_MASK		GENMASK(25, 24)
> -#define   IMX91_TMU_CTRL1_MEAS_MODE_SINGLE	0
> -#define   IMX91_TMU_CTRL1_MEAS_MODE_CONTINUES	1
> -#define   IMX91_TMU_CTRL1_MEAS_MODE_PERIODIC	2
> +#define IMX91_TMU_CTRL1_MEAS_MODE_SINGLE	0
> +#define IMX91_TMU_CTRL1_MEAS_MODE_CONTINUES	1
> +#define IMX91_TMU_CTRL1_MEAS_MODE_PERIODIC	2
>
>  #define IMX91_TMU_THR_CTRL01			0x30
> -#define   IMX91_TMU_THR_CTRL01_THR1_MASK	GENMASK(31, 16)
> +#define IMX91_TMU_THR_CTRL01_THR1_MASK		GENMASK(31, 16)
>
>  #define IMX91_TMU_REF_DIV			0x280
>  #define IMX91_TMU_DIV_EN			BIT(31)
> @@ -67,7 +67,7 @@
>  #define IMX91_TMU_DEFAULT_TRIM2_CONFIG		0x65d4
>
>  #define IMX91_TMU_PERIOD_CTRL			0x270
> -#define   IMX91_TMU_PERIOD_CTRL_MEAS_MASK	GENMASK(23, 0)
> +#define IMX91_TMU_PERIOD_CTRL_MEAS_MASK		GENMASK(23, 0)
>
>  #define IMX91_TMP_FRAC				64
>
>
> --
> 2.37.1
>


From alexandre.belloni at bootlin.com  Fri Dec 12 09:37:44 2025
From: alexandre.belloni at bootlin.com (Alexandre Belloni)
Date: Fri, 12 Dec 2025 18:37:44 +0100
Subject: [PATCH v2 0/3] at91: Remove of_platform_default_populate() calls
In-Reply-To: <20251120-at91-probe-v2-0-8c8592f02e8e@kernel.org>
References: <20251120-at91-probe-v2-0-8c8592f02e8e@kernel.org>
Message-ID: <202512121737447cdf2224@mail.local>

On 20/11/2025 15:37:49-0600, Rob Herring (Arm) wrote:
> This is another attempt at removing of_platform_default_populate() calls 
> on at91 platforms. The last attempts were in 2018[1] and 2023[2]. The 
> problems reported are PM and NAND failures. Both of these depend on SRAM 
> pool which doesn't have any fw_devlink tracking. Also, the PM code is 
> not a driver, so fw_devlink wouldn't help. For the NAND driver, we can 
> simply defer probe. For the PM init, we can move it to the .late_init 
> hook.
> 
> Rob
> 
> [1] https://lore.kernel.org/all/20180712192222.32481-1-robh at kernel.org/
> [2] https://lore.kernel.org/all/3908fa6f-dc33-4aac-c21f-4a676a3a6b23 at microchip.com/
> 
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>

For the whole series:

Acked-by: Alexandre Belloni <alexandre.belloni at bootlin.com>
Tested-by: Alexandre Belloni <alexandre.belloni at bootlin.com>

I tested on at91rm9200, at91sam9m10 and sama5d3 which is a
representative sample of the older platforms.

I tested suspend/resume successfully on at91sam9m10 and sama5d3.
at91rm9200 is not waking up but this is not caused by the series.


> ---
> Rob Herring (1):
>       ARM: at91: Move PM init functions to .init_late hook
> 
> Rob Herring (Arm) (2):
>       mtd: nand: atmel: Defer probe if SRAM is missing
>       ARM: at91: remove unnecessary of_platform_default_populate calls
> 
>  arch/arm/mach-at91/at91rm9200.c              | 12 +-----------
>  arch/arm/mach-at91/at91sam9.c                | 12 +-----------
>  arch/arm/mach-at91/sam9x60.c                 | 12 +-----------
>  arch/arm/mach-at91/sam9x7.c                  | 12 +-----------
>  arch/arm/mach-at91/sama5.c                   | 21 +++------------------
>  arch/arm/mach-at91/sama7.c                   | 11 +----------
>  drivers/mtd/nand/raw/atmel/nand-controller.c |  2 +-
>  7 files changed, 9 insertions(+), 73 deletions(-)
> ---
> base-commit: 3a8660878839faadb4f1a6dd72c3179c1df56787
> change-id: 20251120-at91-probe-20fbce9a6d1b
> 
> Best regards,
> --  
> Rob Herring (Arm) <robh at kernel.org>
> 

-- 
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From nicolas.dufresne at collabora.com  Fri Dec 12 09:53:53 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Fri, 12 Dec 2025 12:53:53 -0500
Subject: [PATCH] media: rkvdec: set ctx->image_fmt in
 rkvdec_s_capture_fmt
In-Reply-To: <20251212154138.3042300-1-liujianfeng1994@gmail.com>
References: <20251212154138.3042300-1-liujianfeng1994@gmail.com>
Message-ID: <8f24c8204984a46bad7d0bb24b78c8115906f748.camel@collabora.com>

Hi,

Le vendredi 12 d?cembre 2025 ? 23:41 +0800, Jianfeng Liu a ?crit?:
> ctx->image_fmt is initialized as RKVDEC_IMG_FMT_ANY at
> rkvdec_s_output_fmt, and get set at rkvdec_s_ctrl when userspace sends
> SPS info via VIDIOC_S_EXT_CTRLS. This works fine with gstreamer because
> it sends SPS info to kernel driver before requesting capture queue bufs.
> 
> But chromium requests capture queue bufs first and then sends SPS info
> to kernel, then rkvdec_s_ctrl will return -EBUSY, and the video is
> displayed green.
> 
> Chromium calls VIDIOC_S_FMT to capture queue instead before requesting
> capture queue bufs, so setting ctx->image_fmt in rkvdec_s_capture_fmt
> will make rkvdec_s_ctrl return 0 when the first SPS info sent to driver.

I'm reading you here, and reading the spec again [0], and you are saying the
Chromium isn't following the initialization process. That means, it should be
impossible to allocate 10bit capture buffer, since the SPS in place specify the
color depth. Other parameters in other codec can influence the reference buffer
size, so you could endup with the wrong allocation.


[0] https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/dev-stateless-decoder.html#initialization


> 
> Signed-off-by: Jianfeng Liu <liujianfeng1994 at gmail.com>
> Fixes: d35c64eccf3b1 ("media: rkvdec: Add get_image_fmt ops")
> ---
> 
> ?drivers/media/platform/rockchip/rkvdec/rkvdec.c | 12 ++++++++++++
> ?1 file changed, 12 insertions(+)
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> index 5af9aa5ab353..e7939d604f64 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> @@ -537,6 +537,18 @@ static int rkvdec_s_capture_fmt(struct file *file, void
> *priv,
> ?		return ret;
> ?
> ?	ctx->decoded_fmt = *f;
> +
> +	u32 fourcc = f->fmt.pix_mp.pixelformat;
> +
> +	if (fourcc == V4L2_PIX_FMT_NV12)
> +		ctx->image_fmt = RKVDEC_IMG_FMT_420_8BIT;
> +	else if (fourcc == V4L2_PIX_FMT_NV15)
> +		ctx->image_fmt = RKVDEC_IMG_FMT_420_10BIT;
> +	else if (fourcc == V4L2_PIX_FMT_NV16)
> +		ctx->image_fmt = RKVDEC_IMG_FMT_422_8BIT;
> +	else if (fourcc == V4L2_PIX_FMT_NV20)
> +		ctx->image_fmt = RKVDEC_IMG_FMT_422_10BIT;

You cannot accept a format that falls against the color depth in the SPS
control, and rkvdec does not do color conversion implicitly. This can otherwise
lead to letting the HW overrun the buffer (forcing 8bit with 10bit content). Can
you check with Chromium dev if they can perhaps adhere to the spec instead ?
This is all news to me, but I probably never had to test 10bit playback in
Chromium outside of MTK (which might not be less strict, hopefully done the
right way).

regards,
Nicolas

> +
> ?	return 0;
> ?}
> ?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251212/95750c3e/attachment.sig>

From conor at kernel.org  Fri Dec 12 09:55:26 2025
From: conor at kernel.org (Conor Dooley)
Date: Fri, 12 Dec 2025 17:55:26 +0000
Subject: [PATCH 2/4] dt-bindings: arm: Document Microchip LAN969x
In-Reply-To: <CA+HBbNHuYCq9oV4ZjWGjwnJM=oz-O85p_tqB+UnTBmivzDoowg@mail.gmail.com>
References: <20251203122313.1287950-1-robert.marko@sartura.hr>
 <20251203122313.1287950-2-robert.marko@sartura.hr>
 <20251203-duly-leotard-86b83bd840c6@spud>
 <CA+HBbNH6wO2VWOp1Dn52ArrYg6z89FgYnT3x-jsHsTVJ5xSBSA@mail.gmail.com>
 <20251208-absolute-diploma-6575729ab43f@spud>
 <CA+HBbNHuYCq9oV4ZjWGjwnJM=oz-O85p_tqB+UnTBmivzDoowg@mail.gmail.com>
Message-ID: <20251212-dazzler-agility-d45940bd27d2@spud>

On Fri, Dec 12, 2025 at 11:09:01AM +0100, Robert Marko wrote:
> On Mon, Dec 8, 2025 at 6:10?PM Conor Dooley <conor at kernel.org> wrote:
> >
> > On Mon, Dec 08, 2025 at 11:30:28AM +0100, Robert Marko wrote:
> > > On Wed, Dec 3, 2025 at 8:19?PM Conor Dooley <conor at kernel.org> wrote:
> > > >
> > > > On Wed, Dec 03, 2025 at 01:21:30PM +0100, Robert Marko wrote:
> > > > > Microchip LAN969x is a series of multi-port, multi-gigabit switches based
> > > > > on ARMv8 Cortex-A53 CPU.
> > > > >
> > > > > Signed-off-by: Robert Marko <robert.marko at sartura.hr>
> > > > > ---
> > > > >  .../bindings/arm/microchip,lan969x.yaml       | 32 +++++++++++++++++++
> > > >
> > > > This should not be in a unique file, put it in with the other microchip
> > > > arm devices please. Also, the wildcard in the compatible is not
> > > > permitted, only way it'd make sense is if these are different binnings
> > > > of the same silicon. If that's the case, you need to explain why,
> > > > because compatibles are meant to be soc-specific.
> > >
> > > Hi Conor,
> > > The issue is that there is no unique place for Microchip SoC-s,
> > > LAN966x series is in the AT91 bindings
> > > while SparX-5 has its own bindings file.
> > >
> > > What would you suggest in this case?
> >
> > Ideally, arm/atmel-at91.yaml and arm/microchip,sparx5.yaml would just
> > become arm/microchip.yaml. The axi at 600000000 thing in the sparx5 file
> > looks pointless and can be deleted IMO.
> 
> Ok, I merged them all in one generic microchip.yaml binding, but I noticed that
> arm/atmel-at91.yaml is licensed under GPL-2.0 while arm/microchip,sparx5.yaml
> is dual-licensed as its preferred for bindings.
> 
> Is that going to be an issue?

I *think* everyone that contributed, other than maybe Wolfram has
already okayed any binding going to dual license. Just do it as a
standalone commit in the patchset and make sure you CC Michael Walle
and Wolfram Sang.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251212/efe38ae1/attachment.sig>

From nicolas.dufresne at collabora.com  Fri Dec 12 10:39:13 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Fri, 12 Dec 2025 13:39:13 -0500
Subject: [PATCH] media: rkvdec: vp9: Fix probs struct alignment
In-Reply-To: <20251212160101.146684-1-detlev.casanova@collabora.com>
References: <20251212160101.146684-1-detlev.casanova@collabora.com>
Message-ID: <687cc16deaeb93e696952e563663478ed889834c.camel@collabora.com>

Le vendredi 12 d?cembre 2025 ? 11:01 -0500, Detlev Casanova a ?crit?:
> When building for arm 32 bits, the struct alignment changes and the compiler
> adds 3 padding bits to the anonymous mv struct in
> rkvdec_vp9_inter_frame_probs.
> 
> Therefore, the BUILD_BUG_ON used to check that the struct size is aligned
> to 128 bits (hardware requirement) fails.
> 
> As that mv struct is at the end of the global rkvdec_vp9_probs struct
> and is followed by 11 padding bits, the 3 padding bits can be explicitely
> set in the mv struct and removed from the 11 following it.
> 
> This makes sure that the mv struct is 32 bits aligned.
> 
> Reported-by: kernel test robot <lkp at intel.com>
> Closes:
> https://lore.kernel.org/oe-kbuild-all/202512110229.R6YCf1Le-lkp at intel.com/
> Fixes: d968e50b5c26 ("media: rkvdec: Unstage the driver")
> Suggested-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c | 4 +++-
> ?1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
> b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
> index b4bf01e839ef..23c733ca2e8e 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
> @@ -66,6 +66,8 @@ struct rkvdec_vp9_inter_frame_probs {
> ?		u8 fr[2][3];
> ?		u8 class0_hp[2];
> ?		u8 hp[2];
> +		/* 32 bit alignment */
> +		u8 padding6[3];
> ?	} mv;
> ?};
> ?
> @@ -85,7 +87,7 @@ struct rkvdec_vp9_probs {
> ?		struct rkvdec_vp9_intra_only_frame_probs intra_only;
> ?	};
> ?	/* 128 bit alignment */
> -	u8 padding1[11];
> +	u8 padding1[8];
> ?};
> ?
> ?/* Data structure describing auxiliary buffer format. */
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251212/bf3dfe9f/attachment.sig>

From nicolas.dufresne at collabora.com  Fri Dec 12 10:45:49 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Fri, 12 Dec 2025 13:45:49 -0500
Subject: [PATCH] media: rkvdec: vp9: Fix probs struct alignment
In-Reply-To: <20251212160101.146684-1-detlev.casanova@collabora.com>
References: <20251212160101.146684-1-detlev.casanova@collabora.com>
Message-ID: <0f697c71f73e54a5a9e1306a06ed883e56d8bc89.camel@collabora.com>

Hi,

Le vendredi 12 d?cembre 2025 ? 11:01 -0500, Detlev Casanova a ?crit?:
> When building for arm 32 bits, the struct alignment changes and the compiler

Reported by checkpatch [0], this needs a reflow, it exceeds 75 chars.

> adds 3 padding bits to the anonymous mv struct in
> rkvdec_vp9_inter_frame_probs.
> 
> Therefore, the BUILD_BUG_ON used to check that the struct size is aligned
> to 128 bits (hardware requirement) fails.
> 
> As that mv struct is at the end of the global rkvdec_vp9_probs struct
> and is followed by 11 padding bits, the 3 padding bits can be explicitely

Also from checkpatch:

explicitely -> explicitly


> set in the mv struct and removed from the 11 following it.
> 
> This makes sure that the mv struct is 32 bits aligned.

Unless someone request a change, I will be able to apply these fixes while
picking it up.

cheers,
Nicolas


[0]https://linux-media.pages.freedesktop.org/-/users/patchwork/-/jobs/89677987/artifacts/junit/0001-media-rkvdec-vp9-Fix-probs-struct-alignment.patch%20checkpatch.err.txt

> 
> Reported-by: kernel test robot <lkp at intel.com>
> Closes: https://lore.kernel.org/oe-kbuild-all/202512110229.R6YCf1Le-lkp at intel.com/
> Fixes: d968e50b5c26 ("media: rkvdec: Unstage the driver")
> Suggested-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
> ---
> ?drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c | 4 +++-
> ?1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
> index b4bf01e839ef..23c733ca2e8e 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
> @@ -66,6 +66,8 @@ struct rkvdec_vp9_inter_frame_probs {
> ?		u8 fr[2][3];
> ?		u8 class0_hp[2];
> ?		u8 hp[2];
> +		/* 32 bit alignment */
> +		u8 padding6[3];
> ?	} mv;
> ?};
> ?
> @@ -85,7 +87,7 @@ struct rkvdec_vp9_probs {
> ?		struct rkvdec_vp9_intra_only_frame_probs intra_only;
> ?	};
> ?	/* 128 bit alignment */
> -	u8 padding1[11];
> +	u8 padding1[8];
> ?};
> ?
> ?/* Data structure describing auxiliary buffer format. */
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251212/49475d08/attachment-0001.sig>

From yeoreum.yun at arm.com  Fri Dec 12 10:58:18 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Fri, 12 Dec 2025 18:58:18 +0000
Subject: [PATCH] smc91x: fix broken irq-context in PREEMPT_RT
Message-ID: <20251212185818.2209573-1-yeoreum.yun@arm.com>

When smc91x.c is built with PREEMPT_RT, the following splat occurs
in arm FVP_RevC:

[   13.055000] smc91x LNRO0003:00 eth0: link up, 10Mbps, half-duplex, lpa 0x0000
[   13.062137] BUG: workqueue leaked atomic, lock or RCU: kworker/2:1[106]
[   13.062137]      preempt=0x00000000 lock=0->0 RCU=0->1 workfn=mld_ifc_work
[   13.062266] C
** replaying previous printk message **
[   13.062266] CPU: 2 UID: 0 PID: 106 Comm: kworker/2:1 Not tainted 6.18.0-dirty #179 PREEMPT_{RT,(full)}
[   13.062353] Hardware name:  , BIOS
[   13.062382] Workqueue: mld mld_ifc_work
[   13.062469] Call trace:
[   13.062494]  show_stack+0x24/0x40 (C)
[   13.062602]  __dump_stack+0x28/0x48
[   13.062710]  dump_stack_lvl+0x7c/0xb0
[   13.062818]  dump_stack+0x18/0x34
[   13.062926]  process_scheduled_works+0x294/0x450
[   13.063043]  worker_thread+0x260/0x3d8
[   13.063124]  kthread+0x1c4/0x228
[   13.063235]  ret_from_fork+0x10/0x20

This happens because smc_special_trylock() disables IRQs even on PREEMPT_RT,
but smc_special_unlock() does not restore IRQs on PREEMPT_RT.
The reason is that smc_special_unlock() calls spin_unlock_irqrestore(),
and rcu_read_unlock_bh() in __dev_queue_xmit() cannot invoke
rcu_read_unlock() through __local_bh_enable_ip() when current->softirq_disable_cnt becomes zero.

To address this issue, replace smc_special_trylock() with spin_trylock_irqsave().

Fixes: 8ff499e43c53 ("smc91x: let smc91x work well under netpoll")
Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
---
This patch based on v6.18
---
 drivers/net/ethernet/smsc/smc91x.c | 11 ++---------
 1 file changed, 2 insertions(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c
index 9d1a83a5fa7e..b7fef6ce8615 100644
--- a/drivers/net/ethernet/smsc/smc91x.c
+++ b/drivers/net/ethernet/smsc/smc91x.c
@@ -516,15 +516,7 @@ static inline void  smc_rcv(struct net_device *dev)
  * any other concurrent access and C would always interrupt B. But life
  * isn't that easy in a SMP world...
  */
-#define smc_special_trylock(lock, flags)				\
-({									\
-	int __ret;							\
-	local_irq_save(flags);						\
-	__ret = spin_trylock(lock);					\
-	if (!__ret)							\
-		local_irq_restore(flags);				\
-	__ret;								\
-})
+#define smc_special_trylock(lock, flags)	spin_trylock_irqsave(lock, flags)
 #define smc_special_lock(lock, flags)		spin_lock_irqsave(lock, flags)
 #define smc_special_unlock(lock, flags) 	spin_unlock_irqrestore(lock, flags)
 #else
@@ -658,6 +650,7 @@ smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 		return NETDEV_TX_OK;
 	}

+	pr_err("[LEVI:%s:%d] before xmit_one %d\n", __func__, __LINE__, irqs_disabled());
 	smc_special_lock(&lp->lock, flags);

 	/* now, try to allocate the memory */
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



From yeoreum.yun at arm.com  Fri Dec 12 11:00:41 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Fri, 12 Dec 2025 19:00:41 +0000
Subject: [PATCH] smc91x: fix broken irq-context in PREEMPT_RT
In-Reply-To: <20251212185818.2209573-1-yeoreum.yun@arm.com>
References: <20251212185818.2209573-1-yeoreum.yun@arm.com>
Message-ID: <aTxmWSejm6yH3C7h@e129823.arm.com>

> When smc91x.c is built with PREEMPT_RT, the following splat occurs
> in arm FVP_RevC:
>
> [   13.055000] smc91x LNRO0003:00 eth0: link up, 10Mbps, half-duplex, lpa 0x0000
> [   13.062137] BUG: workqueue leaked atomic, lock or RCU: kworker/2:1[106]
> [   13.062137]      preempt=0x00000000 lock=0->0 RCU=0->1 workfn=mld_ifc_work
> [   13.062266] C
> ** replaying previous printk message **
> [   13.062266] CPU: 2 UID: 0 PID: 106 Comm: kworker/2:1 Not tainted 6.18.0-dirty #179 PREEMPT_{RT,(full)}
> [   13.062353] Hardware name:  , BIOS
> [   13.062382] Workqueue: mld mld_ifc_work
> [   13.062469] Call trace:
> [   13.062494]  show_stack+0x24/0x40 (C)
> [   13.062602]  __dump_stack+0x28/0x48
> [   13.062710]  dump_stack_lvl+0x7c/0xb0
> [   13.062818]  dump_stack+0x18/0x34
> [   13.062926]  process_scheduled_works+0x294/0x450
> [   13.063043]  worker_thread+0x260/0x3d8
> [   13.063124]  kthread+0x1c4/0x228
> [   13.063235]  ret_from_fork+0x10/0x20
>
> This happens because smc_special_trylock() disables IRQs even on PREEMPT_RT,
> but smc_special_unlock() does not restore IRQs on PREEMPT_RT.
> The reason is that smc_special_unlock() calls spin_unlock_irqrestore(),
> and rcu_read_unlock_bh() in __dev_queue_xmit() cannot invoke
> rcu_read_unlock() through __local_bh_enable_ip() when current->softirq_disable_cnt becomes zero.
>
> To address this issue, replace smc_special_trylock() with spin_trylock_irqsave().
>
> Fixes: 8ff499e43c53 ("smc91x: let smc91x work well under netpoll")
> Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
> ---
> This patch based on v6.18
> ---
>  drivers/net/ethernet/smsc/smc91x.c | 11 ++---------
>  1 file changed, 2 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c
> index 9d1a83a5fa7e..b7fef6ce8615 100644
> --- a/drivers/net/ethernet/smsc/smc91x.c
> +++ b/drivers/net/ethernet/smsc/smc91x.c
> @@ -516,15 +516,7 @@ static inline void  smc_rcv(struct net_device *dev)
>   * any other concurrent access and C would always interrupt B. But life
>   * isn't that easy in a SMP world...
>   */
> -#define smc_special_trylock(lock, flags)				\
> -({									\
> -	int __ret;							\
> -	local_irq_save(flags);						\
> -	__ret = spin_trylock(lock);					\
> -	if (!__ret)							\
> -		local_irq_restore(flags);				\
> -	__ret;								\
> -})
> +#define smc_special_trylock(lock, flags)	spin_trylock_irqsave(lock, flags)
>  #define smc_special_lock(lock, flags)		spin_lock_irqsave(lock, flags)
>  #define smc_special_unlock(lock, flags) 	spin_unlock_irqrestore(lock, flags)
>  #else
> @@ -658,6 +650,7 @@ smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
>  		return NETDEV_TX_OK;
>  	}
>
> +	pr_err("[LEVI:%s:%d] before xmit_one %d\n", __func__, __LINE__, irqs_disabled());
>  	smc_special_lock(&lp->lock, flags);

Ah sorry. I'll send again with removing debug log...

>
>  	/* now, try to allocate the memory */
> --
> LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
>

--
Sincerely,
Yeoreum Yun


From yeoreum.yun at arm.com  Fri Dec 12 11:03:38 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Fri, 12 Dec 2025 19:03:38 +0000
Subject: [PATCH v2] smc91x: fix broken irq-context in PREEMPT_RT
Message-ID: <20251212190338.2318843-1-yeoreum.yun@arm.com>

When smc91x.c is built with PREEMPT_RT, the following splat occurs
in FVP_RevC:

[   13.055000] smc91x LNRO0003:00 eth0: link up, 10Mbps, half-duplex, lpa 0x0000
[   13.062137] BUG: workqueue leaked atomic, lock or RCU: kworker/2:1[106]
[   13.062137]      preempt=0x00000000 lock=0->0 RCU=0->1 workfn=mld_ifc_work
[   13.062266] C
** replaying previous printk message **
[   13.062266] CPU: 2 UID: 0 PID: 106 Comm: kworker/2:1 Not tainted 6.18.0-dirty #179 PREEMPT_{RT,(full)}
[   13.062353] Hardware name:  , BIOS
[   13.062382] Workqueue: mld mld_ifc_work
[   13.062469] Call trace:
[   13.062494]  show_stack+0x24/0x40 (C)
[   13.062602]  __dump_stack+0x28/0x48
[   13.062710]  dump_stack_lvl+0x7c/0xb0
[   13.062818]  dump_stack+0x18/0x34
[   13.062926]  process_scheduled_works+0x294/0x450
[   13.063043]  worker_thread+0x260/0x3d8
[   13.063124]  kthread+0x1c4/0x228
[   13.063235]  ret_from_fork+0x10/0x20

This happens because smc_special_trylock() disables IRQs even on PREEMPT_RT,
but smc_special_unlock() does not restore IRQs on PREEMPT_RT.
The reason is that smc_special_unlock() calls spin_unlock_irqrestore(),
and rcu_read_unlock_bh() in __dev_queue_xmit() cannot invoke
rcu_read_unlock() through __local_bh_enable_ip() when current->softirq_disable_cnt becomes zero.

To address this issue, replace smc_special_trylock() with spin_trylock_irqsave().

Fixes: 8ff499e43c53 ("smc91x: let smc91x work well under netpoll")
Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
---
This patch based on v6.18.

History
========

>From v1 to v2:
  - remove debug log.
  - https://lore.kernel.org/all/20251212185818.2209573-1-yeoreum.yun at arm.com/

---
 drivers/net/ethernet/smsc/smc91x.c | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c
index 9d1a83a5fa7e..d16c178d1034 100644
--- a/drivers/net/ethernet/smsc/smc91x.c
+++ b/drivers/net/ethernet/smsc/smc91x.c
@@ -516,15 +516,7 @@ static inline void  smc_rcv(struct net_device *dev)
  * any other concurrent access and C would always interrupt B. But life
  * isn't that easy in a SMP world...
  */
-#define smc_special_trylock(lock, flags)				\
-({									\
-	int __ret;							\
-	local_irq_save(flags);						\
-	__ret = spin_trylock(lock);					\
-	if (!__ret)							\
-		local_irq_restore(flags);				\
-	__ret;								\
-})
+#define smc_special_trylock(lock, flags)	spin_trylock_irqsave(lock, flags)
 #define smc_special_lock(lock, flags)		spin_lock_irqsave(lock, flags)
 #define smc_special_unlock(lock, flags) 	spin_unlock_irqrestore(lock, flags)
 #else
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



From festevam at gmail.com  Fri Dec 12 11:07:03 2025
From: festevam at gmail.com (Fabio Estevam)
Date: Fri, 12 Dec 2025 16:07:03 -0300
Subject: imx8mp SPDIF TX does not produce a lockable signal
Message-ID: <CAOMZO5DtBFTe26P2x2ca5Vv1sRtpCh0HVrH+9qXrFDVOPD7qGw@mail.gmail.com>

Hi,

I?m working on a custom i.MX8MP-based board, and I am trying to get
SPDIF output working on kernel 6.12.60.

The XCVR node in the device tree is essentially identical to the one
in imx8mp-evk.dts, with the only differences being the SPDIF TX/RX pin
definitions.

The audio card is registered correctly:

# aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: imxaudioxcvr [imx-audio-xcvr], device 0: XCVR PCM snd-soc-dummy-dai-0
  Subdevices: 1/1
  Subdevice #0: subdevice #0

When I play audio:

aplay -D hw:0,0 -t raw -f IEC958_SUBFRAME_LE -c 2 -r 96000 96-24.wav

I do see activity on the SPDIF TX pin on a scope.

However, no SPDIF receiver (a DSP and a standalone consumer receiver)
is able to detect or lock onto the stream. Both devices report ?no
lock? even though there is signal activity. The waveform does not
appear to be interpreted as valid SPDIF.

I also tested by taking the XCVR driver from NXP?s downstream tree
(lf-6.12.y) and applying it to mainline, but the behavior is
unchanged.

Has anyone seen similar issues with the i.MX8MP SPDIF TX path, or is
there anything known to be missing from the mainline XCVR
implementation (clock configuration, channel status bits, preamble
handling, etc.) that might result in a non-lockable SPDIF output?

Any suggestions for debugging or fixing this would be appreciated.

Thanks,

Fabio Estevam


From festevam at gmail.com  Fri Dec 12 11:08:44 2025
From: festevam at gmail.com (Fabio Estevam)
Date: Fri, 12 Dec 2025 16:08:44 -0300
Subject: imx8mp SPDIF TX does not produce a lockable signal
In-Reply-To: <CAOMZO5DtBFTe26P2x2ca5Vv1sRtpCh0HVrH+9qXrFDVOPD7qGw@mail.gmail.com>
References: <CAOMZO5DtBFTe26P2x2ca5Vv1sRtpCh0HVrH+9qXrFDVOPD7qGw@mail.gmail.com>
Message-ID: <CAOMZO5DvEA9PXc2W7tK4ocVASK59FoKH5n2PmsGYfyUbTfH_=A@mail.gmail.com>

Made a typo on the linux-imx address, resending it.

On Fri, Dec 12, 2025 at 4:07?PM Fabio Estevam <festevam at gmail.com> wrote:
>
> Hi,
>
> I?m working on a custom i.MX8MP-based board, and I am trying to get
> SPDIF output working on kernel 6.12.60.
>
> The XCVR node in the device tree is essentially identical to the one
> in imx8mp-evk.dts, with the only differences being the SPDIF TX/RX pin
> definitions.
>
> The audio card is registered correctly:
>
> # aplay -l
> **** List of PLAYBACK Hardware Devices ****
> card 0: imxaudioxcvr [imx-audio-xcvr], device 0: XCVR PCM snd-soc-dummy-dai-0
>   Subdevices: 1/1
>   Subdevice #0: subdevice #0
>
> When I play audio:
>
> aplay -D hw:0,0 -t raw -f IEC958_SUBFRAME_LE -c 2 -r 96000 96-24.wav
>
> I do see activity on the SPDIF TX pin on a scope.
>
> However, no SPDIF receiver (a DSP and a standalone consumer receiver)
> is able to detect or lock onto the stream. Both devices report ?no
> lock? even though there is signal activity. The waveform does not
> appear to be interpreted as valid SPDIF.
>
> I also tested by taking the XCVR driver from NXP?s downstream tree
> (lf-6.12.y) and applying it to mainline, but the behavior is
> unchanged.
>
> Has anyone seen similar issues with the i.MX8MP SPDIF TX path, or is
> there anything known to be missing from the mainline XCVR
> implementation (clock configuration, channel status bits, preamble
> handling, etc.) that might result in a non-lockable SPDIF output?
>
> Any suggestions for debugging or fixing this would be appreciated.
>
> Thanks,
>
> Fabio Estevam


From festevam at gmail.com  Fri Dec 12 11:11:57 2025
From: festevam at gmail.com (Fabio Estevam)
Date: Fri, 12 Dec 2025 16:11:57 -0300
Subject: imx8mp SPDIF TX does not produce a lockable signal
Message-ID: <CAOMZO5BuMLhMyMkfE1xhOwEs2U=+pZnVq+FP+_bp5W_Qg6oMxQ@mail.gmail.com>

Hi,

I?m working on a custom i.MX8MP-based board, and I am trying to get
SPDIF output working on kernel 6.12.60.

The XCVR node in the device tree is essentially identical to the one
in imx8mp-evk.dts, with the only differences being the SPDIF TX/RX pin
definitions.

The audio card is registered correctly:

# aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: imxaudioxcvr [imx-audio-xcvr], device 0: XCVR PCM snd-soc-dummy-dai-0
  Subdevices: 1/1
  Subdevice #0: subdevice #0

When I play audio:

aplay -D hw:0,0 -t raw -f IEC958_SUBFRAME_LE -c 2 -r 96000 96-24.wav

I do see activity on the SPDIF TX pin on a scope.

However, no SPDIF receiver (a DSP and a standalone consumer receiver)
is able to detect or lock onto the stream. Both devices report ?no
lock? even though there is signal activity. The waveform does not
appear to be interpreted as valid SPDIF.

I also tested by taking the XCVR driver from NXP?s downstream tree
(lf-6.12.y) and applying it to mainline, but the behavior is
unchanged.

Has anyone seen similar issues with the i.MX8MP SPDIF TX path, or is
there anything known to be missing from the mainline XCVR
implementation (clock configuration, channel status bits, preamble
handling, etc.) that might result in a non-lockable SPDIF output?

Any suggestions for debugging or fixing this would be appreciated.

Thanks,

Fabio Estevam


From detlev.casanova at collabora.com  Fri Dec 12 11:17:33 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Fri, 12 Dec 2025 14:17:33 -0500
Subject: [PATCH] media: rkvdec: vp9: Fix probs struct alignment
In-Reply-To: <20251212160101.146684-1-detlev.casanova@collabora.com>
References: <20251212160101.146684-1-detlev.casanova@collabora.com>
Message-ID: <912e62f7-210d-4e25-9119-7dea61b856c5@collabora.com>

Hi all,

Sorry, I need to rewrite the commit message with some s/bit/byte...

Will do a v2 soon.

Regards,

Detlev.

On 12/12/25 11:01, Detlev Casanova wrote:
> When building for arm 32 bits, the struct alignment changes and the compiler
> adds 3 padding bits to the anonymous mv struct in
> rkvdec_vp9_inter_frame_probs.
>
> Therefore, the BUILD_BUG_ON used to check that the struct size is aligned
> to 128 bits (hardware requirement) fails.
>
> As that mv struct is at the end of the global rkvdec_vp9_probs struct
> and is followed by 11 padding bits, the 3 padding bits can be explicitely
> set in the mv struct and removed from the 11 following it.
>
> This makes sure that the mv struct is 32 bits aligned.
>
> Reported-by: kernel test robot <lkp at intel.com>
> Closes: https://lore.kernel.org/oe-kbuild-all/202512110229.R6YCf1Le-lkp at intel.com/
> Fixes: d968e50b5c26 ("media: rkvdec: Unstage the driver")
> Suggested-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
> ---
>   drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c | 4 +++-
>   1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
> index b4bf01e839ef..23c733ca2e8e 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
> @@ -66,6 +66,8 @@ struct rkvdec_vp9_inter_frame_probs {
>   		u8 fr[2][3];
>   		u8 class0_hp[2];
>   		u8 hp[2];
> +		/* 32 bit alignment */
> +		u8 padding6[3];
>   	} mv;
>   };
>   
> @@ -85,7 +87,7 @@ struct rkvdec_vp9_probs {
>   		struct rkvdec_vp9_intra_only_frame_probs intra_only;
>   	};
>   	/* 128 bit alignment */
> -	u8 padding1[11];
> +	u8 padding1[8];
>   };
>   
>   /* Data structure describing auxiliary buffer format. */


From coltonlewis at google.com  Fri Dec 12 11:22:02 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Fri, 12 Dec 2025 19:22:02 +0000
Subject: [PATCH v5 01/24] arm64: cpufeature: Add cpucap for HPMN0
In-Reply-To: <d3e946ec-787a-424a-9a7a-f04aeb490ba6@arm.com> (message from
 Suzuki K Poulose on Wed, 10 Dec 2025 10:54:10 +0000)
Message-ID: <gsnt7bur4iat.fsf@coltonlewis-kvm.c.googlers.com>

Suzuki K Poulose <suzuki.poulose at arm.com> writes:

> On 09/12/2025 20:50, Colton Lewis wrote:
>> Add a capability for FEAT_HPMN0, whether MDCR_EL2.HPMN can specify 0
>> counters reserved for the guest.

>> This required changing HPMN0 to an UnsignedEnum in tools/sysreg
>> because otherwise not all the appropriate macros are generated to add
>> it to arm64_cpu_capabilities_arm64_features.

>> Acked-by: Mark Rutland <mark.rutland at arm.com>
>> Signed-off-by: Colton Lewis <coltonlewis at google.com>

> Reviewed-by: Suzuki K Poulose <suzuki.poulose at arm.com>

Thanks Suzuki!


From shenwei.wang at nxp.com  Fri Dec 12 11:43:36 2025
From: shenwei.wang at nxp.com (Shenwei Wang)
Date: Fri, 12 Dec 2025 13:43:36 -0600
Subject: [PATCH v6 0/5] Enable Remote GPIO over RPMSG on i.MX Platform
Message-ID: <20251212194341.966387-1-shenwei.wang@nxp.com>

Support the remote devices on the remote processor via the RPMSG bus on
i.MX platform.

Changes in v6:
 - make the driver more generic with the actions below:
     rename the driver file to gpio-rpmsg.c
     remove the imx related info in the function and variable names
     rename the imx_rpmsg.h to rpdev_info.h
     create a gpio-rpmsg.yaml and refer it in imx_rproc.yaml
 - update the gpio-rpmsg.rst according to the feedback from Andrew and
   move the source file to driver-api/gpio
 - fix the bug reported by Zhongqiu Han
 - remove the I2C related info

Changes in v5:
 - move the gpio-rpmsg.rst from admin-guide to staging directory after
   discussion with Randy Dunlap.
 - add include files with some code improvements per Bartosz's comments.

Changes in v4:
 - add a documentation to describe the transport protocol per Andrew's
   comments.
 - add a new handler to get the gpio direction.

Changes in v3:
 - fix various format issue and return value check per Peng 's review
   comments.
 - add the logic to also populate the subnodes which are not in the
   device map per Arnaud's request. (in imx_rproc.c)
 - update the yaml per Frank's review comments.

Changes in v2:
 - re-implemented the gpio driver per Linus Walleij's feedback by using
   GPIOLIB_IRQCHIP helper library.
 - fix various format issue per Mathieu/Peng 's review comments.
 - update the yaml doc per Rob's feedback

Shenwei Wang (5):
  dt-bindings: remoteproc: imx_rproc: Add "rpmsg" subnode support
  remoteproc: imx_rproc: Populate devices under "rpmsg" subnode
  docs: driver-api: gpio: generic gpio driver over rpmsg bus
  gpio: rpmsg: add generic rpmsg GPIO driver
  arm64: dts: imx8ulp: Add rpmsg node under imx_rproc

 .../devicetree/bindings/gpio/gpio-rpmsg.yaml  |  49 ++
 .../bindings/remoteproc/fsl,imx-rproc.yaml    |  54 ++
 Documentation/driver-api/gpio/gpio-rpmsg.rst  | 232 +++++++++
 Documentation/driver-api/gpio/index.rst       |   1 +
 arch/arm64/boot/dts/freescale/imx8ulp.dtsi    |  27 +
 drivers/gpio/Kconfig                          |  16 +
 drivers/gpio/Makefile                         |   1 +
 drivers/gpio/gpio-rpmsg.c                     | 490 ++++++++++++++++++
 drivers/remoteproc/imx_rproc.c                | 143 +++++
 include/linux/rpmsg/rpdev_info.h              |  33 ++
 10 files changed, 1046 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/gpio/gpio-rpmsg.yaml
 create mode 100644 Documentation/driver-api/gpio/gpio-rpmsg.rst
 create mode 100644 drivers/gpio/gpio-rpmsg.c
 create mode 100644 include/linux/rpmsg/rpdev_info.h

--
2.43.0



From shenwei.wang at nxp.com  Fri Dec 12 11:43:37 2025
From: shenwei.wang at nxp.com (Shenwei Wang)
Date: Fri, 12 Dec 2025 13:43:37 -0600
Subject: [PATCH v6 1/5] dt-bindings: remoteproc: imx_rproc: Add "rpmsg" subnode support
In-Reply-To: <20251212194341.966387-1-shenwei.wang@nxp.com>
References: <20251212194341.966387-1-shenwei.wang@nxp.com>
Message-ID: <20251212194341.966387-2-shenwei.wang@nxp.com>

Remote processors may announce multiple devices (e.g., I2C, GPIO) over
an RPMSG channel. These devices may require corresponding device tree
nodes, especially when acting as providers, to supply phandles for their
consumers.

Define an RPMSG node to work as a container for a group of RPMSG channels
under the imx_rproc node.

Each subnode within "rpmsg" represents an individual RPMSG channel. The
name of each subnode corresponds to the channel name as defined by the
remote processor.

All remote devices associated with a given channel are defined as child
nodes under the corresponding channel node.

Signed-off-by: Shenwei Wang <shenwei.wang at nxp.com>
---
 .../devicetree/bindings/gpio/gpio-rpmsg.yaml  | 49 +++++++++++++++++
 .../bindings/remoteproc/fsl,imx-rproc.yaml    | 54 +++++++++++++++++++
 2 files changed, 103 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/gpio/gpio-rpmsg.yaml

diff --git a/Documentation/devicetree/bindings/gpio/gpio-rpmsg.yaml b/Documentation/devicetree/bindings/gpio/gpio-rpmsg.yaml
new file mode 100644
index 000000000000..b3e1a5dbf731
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-rpmsg.yaml
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/gpio/gpio-rpmsg.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Generic GPIO driver over RPMSG
+
+maintainers:
+  - Shenwei Wang <shenwei.wang at nxp.com>
+
+description:
+  On an AMP platform, some GPIO controllers are exposed by the remote processor
+  through the RPMSG bus. The RPMSG GPIO transport protocol defines the packet
+  structure and communication flow between Linux and the remote firmware. Those
+  controllers are managed via this transport protocol.
+
+properties:
+  compatible:
+    oneOf:
+      - items:
+          - enum:
+              - fsl,rpmsg-gpio
+          - const: rpmsg-gpio
+      - const: rpmsg-gpio
+
+  reg:
+    maxItems: 1
+
+  "#gpio-cells":
+    const: 2
+
+  gpio-controller: true
+
+  interrupt-controller: true
+
+  "#interrupt-cells":
+    const: 2
+
+required:
+  - compatible
+  - reg
+  - "#gpio-cells"
+  - "#interrupt-cells"
+
+allOf:
+  - $ref: /schemas/gpio/gpio.yaml#
+
+unevaluatedProperties: false
diff --git a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
index 57d75acb0b5e..fd8e5a61a459 100644
--- a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
+++ b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
@@ -84,6 +84,33 @@ properties:
       This property is to specify the resource id of the remote processor in SoC
       which supports SCFW
 
+  rpmsg:
+    type: object
+    additionalProperties: false
+    description:
+      Present a group of RPMSG channel devices.
+
+    properties:
+      rpmsg-io-channel:
+        type: object
+        additionalProperties: false
+        properties:
+          '#address-cells':
+            const: 1
+
+          '#size-cells':
+            const: 0
+
+        patternProperties:
+          "gpio@[0-9a-f]+$":
+            type: object
+            $ref: /schemas/gpio/gpio-rpmsg.yaml#
+            unevaluatedProperties: false
+
+        required:
+          - '#address-cells'
+          - '#size-cells'
+
 required:
   - compatible
 
@@ -146,5 +173,32 @@ examples:
                 &mu 3 1>;
       memory-region = <&vdev0buffer>, <&vdev0vring0>, <&vdev0vring1>, <&rsc_table>;
       syscon = <&src>;
+
+      rpmsg {
+        rpmsg-io-channel {
+          #address-cells = <1>;
+          #size-cells = <0>;
+
+          gpio at 0 {
+            compatible = "rpmsg-gpio";
+            reg = <0>;
+            gpio-controller;
+            #gpio-cells = <2>;
+            #interrupt-cells = <2>;
+            interrupt-controller;
+            interrupt-parent = <&rpmsg_gpioa>;
+          };
+
+          gpio at 1 {
+            compatible = "rpmsg-gpio";
+            reg = <1>;
+            gpio-controller;
+            #gpio-cells = <2>;
+            #interrupt-cells = <2>;
+            interrupt-controller;
+            interrupt-parent = <&rpmsg_gpiob>;
+          };
+        };
+      };
     };
 ...
-- 
2.43.0



From shenwei.wang at nxp.com  Fri Dec 12 11:43:38 2025
From: shenwei.wang at nxp.com (Shenwei Wang)
Date: Fri, 12 Dec 2025 13:43:38 -0600
Subject: [PATCH v6 2/5] remoteproc: imx_rproc: Populate devices under "rpmsg" subnode
In-Reply-To: <20251212194341.966387-1-shenwei.wang@nxp.com>
References: <20251212194341.966387-1-shenwei.wang@nxp.com>
Message-ID: <20251212194341.966387-3-shenwei.wang@nxp.com>

Register the RPMsg channel driver and populate remote devices defined
under the "rpmsg" subnode upon receiving their notification messages.

The following illustrates the expected DTS layout structure:

	cm33: remoteproc-cm33 {
		compatible = "fsl,imx8ulp-cm33";

		rpmsg {
			rpmsg-io-channel {
				gpio at 0 {
					compatible = "fsl,imx-rpmsg-gpio";
					reg = <0>;
				};

				gpio at 1 {
					compatible = "fsl,imx-rpmsg-gpio";
					reg = <1>;
				};

				...
			};

			...
		};
	};

Signed-off-by: Shenwei Wang <shenwei.wang at nxp.com>
---
 drivers/remoteproc/imx_rproc.c   | 143 +++++++++++++++++++++++++++++++
 include/linux/rpmsg/rpdev_info.h |  33 +++++++
 2 files changed, 176 insertions(+)
 create mode 100644 include/linux/rpmsg/rpdev_info.h

diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index 33f21ab24c92..65ee16fd66d1 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -15,6 +15,8 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
 #include <linux/of_reserved_mem.h>
 #include <linux/platform_device.h>
 #include <linux/pm_domain.h>
@@ -22,6 +24,8 @@
 #include <linux/reboot.h>
 #include <linux/regmap.h>
 #include <linux/remoteproc.h>
+#include <linux/rpmsg.h>
+#include <linux/rpmsg/rpdev_info.h>
 #include <linux/workqueue.h>
 
 #include "imx_rproc.h"
@@ -1016,6 +1020,141 @@ static void imx_rproc_destroy_workqueue(void *data)
 	destroy_workqueue(workqueue);
 }
 
+struct imx_rpmsg_driver {
+	struct rpmsg_driver rpdrv;
+	const char *compat;
+	void *driver_data;
+};
+
+static const char *channel_device_map[][2] = {
+	{"rpmsg-io-channel", "rpmsg-gpio"},
+};
+
+static int imx_rpmsg_endpoint_cb(struct rpmsg_device *rpdev, void *data,
+				 int len, void *priv, u32 src)
+{
+	struct rpdev_platform_info *drvdata;
+
+	drvdata = dev_get_drvdata(&rpdev->dev);
+	if (drvdata && drvdata->rx_callback)
+		return drvdata->rx_callback(rpdev, data, len, priv, src);
+
+	return 0;
+}
+
+static void imx_rpmsg_endpoint_remove(struct rpmsg_device *rpdev)
+{
+	of_platform_depopulate(&rpdev->dev);
+}
+
+static int imx_rpmsg_endpoint_probe(struct rpmsg_device *rpdev)
+{
+	struct rpdev_platform_info *drvdata;
+	struct imx_rpmsg_driver *imx_rpdrv;
+	struct device *dev = &rpdev->dev;
+	struct of_dev_auxdata *auxdata;
+	struct rpmsg_driver *rpdrv;
+
+	rpdrv = container_of(dev->driver, struct rpmsg_driver, drv);
+	imx_rpdrv = container_of(rpdrv, struct imx_rpmsg_driver, rpdrv);
+
+	if (!imx_rpdrv->driver_data)
+		return -EINVAL;
+
+	drvdata = devm_kmemdup(dev, imx_rpdrv->driver_data, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+
+	auxdata = devm_kzalloc(dev, sizeof(*auxdata) * 2, GFP_KERNEL);
+	if (!auxdata)
+		return -ENOMEM;
+
+	drvdata->rpdev = rpdev;
+	auxdata[0].compatible = devm_kstrdup(dev, imx_rpdrv->compat, GFP_KERNEL);
+	auxdata[0].platform_data = drvdata;
+	dev_set_drvdata(dev, drvdata);
+
+	of_platform_populate(drvdata->channel_node, NULL, auxdata, dev);
+
+	return 0;
+}
+
+static const char *imx_of_rpmsg_is_in_map(const char *name)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(channel_device_map); i++) {
+		if (strcmp(name, channel_device_map[i][0]) == 0)
+			return channel_device_map[i][1];
+	}
+
+	return NULL;
+}
+
+static int imx_of_rpmsg_register_rpdriver(struct device_node *channel,
+					  struct device *dev,
+					  const char *name,
+					  const char *compat)
+{
+	struct rpdev_platform_info *driver_data;
+	struct imx_rpmsg_driver *rp_driver;
+	struct rpmsg_device_id *rpdev_id;
+
+	/* rpmsg_device_id is a NULL terminated array */
+	rpdev_id = devm_kzalloc(dev, sizeof(*rpdev_id) * 2, GFP_KERNEL);
+	if (!rpdev_id)
+		return -ENOMEM;
+
+	strscpy(rpdev_id[0].name, name, RPMSG_NAME_SIZE);
+
+	rp_driver = devm_kzalloc(dev, sizeof(*rp_driver), GFP_KERNEL);
+	if (!rp_driver)
+		return -ENOMEM;
+
+	driver_data = devm_kzalloc(dev, sizeof(*driver_data), GFP_KERNEL);
+	if (!driver_data)
+		return -ENOMEM;
+
+	driver_data->rproc_name = dev->of_node->name;
+	driver_data->channel_node = channel;
+
+	rp_driver->rpdrv.drv.name = name;
+	rp_driver->rpdrv.id_table = rpdev_id;
+	rp_driver->rpdrv.probe = imx_rpmsg_endpoint_probe;
+	rp_driver->rpdrv.remove = imx_rpmsg_endpoint_remove;
+	rp_driver->rpdrv.callback = imx_rpmsg_endpoint_cb;
+	rp_driver->driver_data = driver_data;
+	rp_driver->compat = compat;
+
+	register_rpmsg_driver(&rp_driver->rpdrv);
+
+	return 0;
+}
+
+static int rproc_of_rpmsg_node_init(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	const char *compat;
+	int ret;
+
+	struct device_node *np __free(device_node) = of_get_child_by_name(dev->of_node, "rpmsg");
+	if (!np)
+		return 0;
+
+	for_each_child_of_node_scoped(np, child) {
+		compat = imx_of_rpmsg_is_in_map(child->name);
+		if (!compat)
+			ret = of_platform_default_populate(child, NULL, dev);
+		else
+			ret = imx_of_rpmsg_register_rpdriver(child, dev, child->name, compat);
+
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
 static int imx_rproc_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -1114,6 +1253,10 @@ static int imx_rproc_probe(struct platform_device *pdev)
 		goto err_put_pm;
 	}
 
+	ret = rproc_of_rpmsg_node_init(pdev);
+	if (ret < 0)
+		dev_info(dev, "populating 'rpmsg' node failed\n");
+
 	return 0;
 
 err_put_pm:
diff --git a/include/linux/rpmsg/rpdev_info.h b/include/linux/rpmsg/rpdev_info.h
new file mode 100644
index 000000000000..13e020cd028b
--- /dev/null
+++ b/include/linux/rpmsg/rpdev_info.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright 2025 NXP */
+
+/*
+ * @file linux/rpdev_info.h
+ *
+ * @brief Global header file for RPDEV Info
+ *
+ * @ingroup RPMSG
+ */
+#ifndef __LINUX_RPDEV_INFO_H__
+#define __LINUX_RPDEV_INFO_H__
+
+#define MAX_DEV_PER_CHANNEL    10
+
+/**
+ * rpdev_platform_info - store the platform information of rpdev
+ * @rproc_name: the name of the remote proc.
+ * @rpdev: rpmsg channel device
+ * @device_node: pointer to the device node of the rpdev.
+ * @rx_callback: rx callback handler of the rpdev.
+ * @channel_devices: an array of the devices related to the rpdev.
+ */
+struct rpdev_platform_info {
+	const char *rproc_name;
+	struct rpmsg_device *rpdev;
+	struct device_node *channel_node;
+	int (*rx_callback)(struct rpmsg_device *rpdev, void *data,
+			   int len, void *priv, u32 src);
+	void *channel_devices[MAX_DEV_PER_CHANNEL];
+};
+
+#endif /* __LINUX_RPDEV_INFO_H__ */
-- 
2.43.0



From shenwei.wang at nxp.com  Fri Dec 12 11:43:39 2025
From: shenwei.wang at nxp.com (Shenwei Wang)
Date: Fri, 12 Dec 2025 13:43:39 -0600
Subject: [PATCH v6 3/5] docs: driver-api: gpio: generic gpio driver over rpmsg bus
In-Reply-To: <20251212194341.966387-1-shenwei.wang@nxp.com>
References: <20251212194341.966387-1-shenwei.wang@nxp.com>
Message-ID: <20251212194341.966387-4-shenwei.wang@nxp.com>

Describes the gpio rpmsg transport protocol over the rpmsg bus between
the cores.

Signed-off-by: Shenwei Wang <shenwei.wang at nxp.com>
---
 Documentation/driver-api/gpio/gpio-rpmsg.rst | 232 +++++++++++++++++++
 Documentation/driver-api/gpio/index.rst      |   1 +
 2 files changed, 233 insertions(+)
 create mode 100644 Documentation/driver-api/gpio/gpio-rpmsg.rst

diff --git a/Documentation/driver-api/gpio/gpio-rpmsg.rst b/Documentation/driver-api/gpio/gpio-rpmsg.rst
new file mode 100644
index 000000000000..c78d10a9a85c
--- /dev/null
+++ b/Documentation/driver-api/gpio/gpio-rpmsg.rst
@@ -0,0 +1,232 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+GPIO RPMSG Protocol
+===================
+
+The GPIO RPMSG transport protocol is used for communication and interaction
+with GPIO controllers located on remote cores on the RPMSG bus.
+
+Message Format
+--------------
+
+The RPMSG message consists of a 14-byte packet with the following layout:
+
+.. code-block:: none
+
+   +-----+-------+--------+-----+-----+------------+-----+-----+-----+----+
+   |0x00 |0x01   |0x02    |0x03 |0x04 |0x05..0x09  |0x0A |0x0B |0x0C |0x0D|
+   | ID  |vendor |version |type |cmd  |reserved[5] |line |port |  data    |
+   +-----+-------+--------+-----+-----+------------+-----+-----+-----+----+
+
+- **ID (Message Identification Code)**: Always be 0x5. Indicates the GPIO message.
+
+- **Vendor**: Vendor ID number.
+  - 0: Reserved
+  - 1: NXP
+
+- **Version**: Vendor-specific version number (such as software release).
+
+- **Type (Message Type)**: The message type can be one of:
+
+  - 0: GPIO_RPMSG_SETUP
+  - 1: GPIO_RPMSG_REPLY
+  - 2: GPIO_RPMSG_NOTIFY
+
+- **Cmd**: Command code, used for GPIO_RPMSG_SETUP messages.
+
+- **reserved[5]**: Reserved bytes. Should always be 0.
+
+- **line**: The GPIO line index.
+
+- **port**: The GPIO controller index.
+
+- **data**: See details in the command description below.
+
+GPIO Commands
+-------------
+
+Commands are specified in the **Cmd** field for **GPIO_RPMSG_SETUP** (Type=0) messages.
+
+The SETUP message is always sent from Linux to the remote firmware. Each
+SETUP corresponds to a single REPLY message. The GPIO driver should
+serialize messages and determine whether a REPLY message is required. If a
+REPLY message is expected but not received within the specified timeout
+period (currently 1 second in the Linux driver), the driver should return
+-ETIMEOUT.
+
+GPIO_RPMSG_INPUT_INIT (Cmd=0)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+**Request:**
+
+.. code-block:: none
+
+   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
+   | 5   | 1   | 0   | 0   | 0   |  0        |line |port | val | wk |
+   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+
+- **val**: Interrupt trigger type.
+
+  - 0: Interrupt disabled
+  - 1: Rising edge trigger
+  - 2: Falling edge trigger
+  - 3: Both edge trigger
+  - 4: Low level trigger
+  - 5: High level trigger
+
+- **wk**: Wakeup enable.
+
+  The remote system should always aim to stay in a power-efficient state by
+  shutting down or clock-gating the GPIO blocks that aren't in use. Since
+  the remoteproc driver is responsibe for managing the power states of the
+  remote firmware, the GPIO driver does not require to konow the firmware's
+  running states.
+
+  When the wakeup bit is set, the remote firmware should configure the line
+  as a wakeup source. The firmware should send the notification message to
+  Linux after it is woken from the GPIO line.
+
+  - 0: Disable wakeup from GPIO
+  - 1: Enable wakeup from GPIO
+
+**Reply:**
+
+.. code-block:: none
+
+   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
+   | 5   | 1   | 0   | 1   | 1   |  0        |line |port | err | 0  |
+   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+
+- **err**: Error code from the remote core.
+
+  - 0: Success
+  - 1: General error (early remote software only returns this unclassified error)
+  - 2: Not supported (A command is not supported by the remote firmware)
+  - 3: Resource not available (The resource is not allocated to the Linux)
+  - 4: Resource busy (The resource is already used)
+  - 5: Parameter error
+
+GPIO_RPMSG_OUTPUT_INIT (Cmd=1)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+**Request:**
+
+.. code-block:: none
+
+   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
+   | 5   | 1   | 0   | 0   | 1   |  0        |line |port | val | 0  |
+   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+
+- **val**: Output level.
+
+  - 0: Low
+  - 1: High
+
+**Reply:**
+
+.. code-block:: none
+
+   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
+   | 5   | 1   | 0   | 1   | 1   |  0        |line |port | err | 0  |
+   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+
+- **err**: See above for definitions.
+
+GPIO_RPMSG_INPUT_GET (Cmd=2)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+**Request:**
+
+.. code-block:: none
+
+   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
+   | 5   | 1   | 0   | 0   | 2   |  0        |line |port | 0   | 0  |
+   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+
+**Reply:**
+
+.. code-block:: none
+
+   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+-----+
+   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D |
+   | 5   | 1   | 0   | 1   | 2   |  0        |line |port | err |level|
+   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+-----+
+
+- **err**: See above for definitions.
+
+- **level**: Input level.
+
+  - 0: Low
+  - 1: High
+
+GPIO_RPMSG_GET_DIRECTION (Cmd=3)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+**Request:**
+
+.. code-block:: none
+
+   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
+   | 5   | 1   | 0   | 0   | 3   |  0        |line |port | 0   | 0  |
+   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+
+**Reply:**
+
+.. code-block:: none
+
+   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+-----+
+   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D |
+   | 5   | 1   | 0   | 1   | 3   |  0        |line |port | err | dir |
+   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+-----+
+
+- **err**: See above for definitions.
+
+- **dir**: Direction.
+
+  - 0: Output
+  - 1: Input
+
+Notification Message
+--------------------
+
+Notifications are sent with **Type=2 (GPIO_RPMSG_NOTIFY)**:
+
+When a GPIO line asserts an interrupt on the remote processor, the firmware
+should immediately mask the corresponding interrupt source and send a
+notification message to the Linux. Upon completion of the interrupt
+handling on the Linux side, the driver should issue a
+**GPIO_RPMSG_INPUT_INIT** command to the firmware to unmask the interrupt.
+
+A Notification message can arrive between a SETUP and its REPLY message,
+and the driver is expected to handle this scenario.
+
+.. code-block:: none
+
+   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
+   | 5   | 1   | 0   | 2   | 0   |  0        |line |port | 0   | 0  |
+   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+
+- **line**: The GPIO line index.
+- **port**: The GPIO controller index.
+
+The reply message for the notification is optional. The remote firmware can
+implement it to simulate the interrupt acknowledgment behavior.
+
+The notification reply is sent with the byte index 0x4=1.
+
+.. code-block:: none
+
+   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
+   | 5   | 1   | 0   | 2   | 1   |  0        |line |port | 0   | 0  |
+   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
+
+- **line**: The GPIO line index.
+- **port**: The GPIO controller index.
diff --git a/Documentation/driver-api/gpio/index.rst b/Documentation/driver-api/gpio/index.rst
index bee58f709b9a..e5eb1f82f01f 100644
--- a/Documentation/driver-api/gpio/index.rst
+++ b/Documentation/driver-api/gpio/index.rst
@@ -16,6 +16,7 @@ Contents:
    drivers-on-gpio
    bt8xxgpio
    pca953x
+   gpio-rpmsg
 
 Core
 ====
-- 
2.43.0



From shenwei.wang at nxp.com  Fri Dec 12 11:43:40 2025
From: shenwei.wang at nxp.com (Shenwei Wang)
Date: Fri, 12 Dec 2025 13:43:40 -0600
Subject: [PATCH v6 4/5] gpio: rpmsg: add generic rpmsg GPIO driver
In-Reply-To: <20251212194341.966387-1-shenwei.wang@nxp.com>
References: <20251212194341.966387-1-shenwei.wang@nxp.com>
Message-ID: <20251212194341.966387-5-shenwei.wang@nxp.com>

On an AMP platform, the system may include two processors:
	- An MCU running an RTOS
	- An MPU running Linux

These processors communicate via the RPMSG protocol.
The driver implements the standard GPIO interface, allowing
the Linux side to control GPIO controllers which reside in
the remote processor via RPMSG protocol.

Cc: Bartosz Golaszewski <brgl at bgdev.pl>
Cc: Andrew Lunn <andrew at lunn.ch>
Signed-off-by: Shenwei Wang <shenwei.wang at nxp.com>
---
 drivers/gpio/Kconfig      |  16 ++
 drivers/gpio/Makefile     |   1 +
 drivers/gpio/gpio-rpmsg.c | 490 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 507 insertions(+)
 create mode 100644 drivers/gpio/gpio-rpmsg.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index bd185482a7fd..7a72b5dbd4a9 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -1883,6 +1883,22 @@ config GPIO_SODAVILLE
 
 endmenu
 
+menu "RPMSG GPIO drivers"
+	depends on RPMSG
+
+config GPIO_RPMSG
+	tristate "Generic RPMSG GPIO support"
+	select GPIOLIB_IRQCHIP
+	default REMOTEPROC
+	help
+	  Say yes here to support the generic GPIO functions over the RPMSG
+	  bus. Currently supported devices: i.MX7ULP, i.MX8ULP, i.MX8x,and
+	  i.MX9x.
+
+	  If unsure, say N.
+
+endmenu
+
 menu "SPI GPIO expanders"
 	depends on SPI_MASTER
 
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 2421a8fd3733..b1373ec274c8 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -156,6 +156,7 @@ obj-$(CONFIG_GPIO_RDC321X)		+= gpio-rdc321x.o
 obj-$(CONFIG_GPIO_REALTEK_OTTO)		+= gpio-realtek-otto.o
 obj-$(CONFIG_GPIO_REG)			+= gpio-reg.o
 obj-$(CONFIG_GPIO_ROCKCHIP)	+= gpio-rockchip.o
+obj-$(CONFIG_GPIO_RPMSG)		+= gpio-rpmsg.o
 obj-$(CONFIG_GPIO_RTD)			+= gpio-rtd.o
 obj-$(CONFIG_ARCH_SA1100)		+= gpio-sa1100.o
 obj-$(CONFIG_GPIO_SAMA5D2_PIOBU)	+= gpio-sama5d2-piobu.o
diff --git a/drivers/gpio/gpio-rpmsg.c b/drivers/gpio/gpio-rpmsg.c
new file mode 100644
index 000000000000..cf10e2958374
--- /dev/null
+++ b/drivers/gpio/gpio-rpmsg.c
@@ -0,0 +1,490 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2025 NXP
+ *
+ * The driver exports a standard gpiochip interface to control
+ * the GPIO controllers via RPMSG on a remote processor.
+ */
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/driver.h>
+#include <linux/init.h>
+#include <linux/irqdomain.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/rpmsg.h>
+#include <linux/rpmsg/rpdev_info.h>
+
+#define RPMSG_GPIO_ID		5
+#define RPMSG_VENDOR		1
+#define RPMSG_VERSION		0
+
+#define GPIOS_PER_PORT		32
+#define RPMSG_TIMEOUT		1000
+
+enum gpio_input_trigger_type {
+	GPIO_RPMSG_TRI_IGNORE,
+	GPIO_RPMSG_TRI_RISING,
+	GPIO_RPMSG_TRI_FALLING,
+	GPIO_RPMSG_TRI_BOTH_EDGE,
+	GPIO_RPMSG_TRI_LOW_LEVEL,
+	GPIO_RPMSG_TRI_HIGH_LEVEL,
+};
+
+enum gpio_rpmsg_header_type {
+	GPIO_RPMSG_SETUP,
+	GPIO_RPMSG_REPLY,
+	GPIO_RPMSG_NOTIFY,
+};
+
+enum gpio_rpmsg_header_cmd {
+	GPIO_RPMSG_INPUT_INIT,
+	GPIO_RPMSG_OUTPUT_INIT,
+	GPIO_RPMSG_INPUT_GET,
+	GPIO_RPMSG_DIRECTION_GET,
+};
+
+struct gpio_rpmsg_head {
+	u8 id;		/* Message ID Code */
+	u8 vendor;	/* Vendor ID number */
+	u8 version;	/* Vendor-specific version number */
+	u8 type;	/* Message type */
+	u8 cmd;		/* Command code */
+	u8 reserved[5];
+} __packed;
+
+struct gpio_rpmsg_packet {
+	struct gpio_rpmsg_head header;
+	u8 pin_idx;
+	u8 port_idx;
+	union {
+		u8 event;
+		u8 retcode;
+		u8 value;
+	} out;
+	union {
+		u8 wakeup;
+		u8 value;
+	} in;
+} __packed __aligned(8);
+
+struct gpio_rpmsg_pin {
+	u8 irq_shutdown;
+	u8 irq_unmask;
+	u8 irq_mask;
+	u32 irq_wake_enable;
+	u32 irq_type;
+	struct gpio_rpmsg_packet msg;
+};
+
+struct gpio_rpmsg_info {
+	struct rpmsg_device *rpdev;
+	struct gpio_rpmsg_packet *notify_msg;
+	struct gpio_rpmsg_packet *reply_msg;
+	struct completion cmd_complete;
+	struct mutex lock;
+	void **port_store;
+};
+
+struct rpmsg_gpio_port {
+	struct gpio_chip gc;
+	struct gpio_rpmsg_pin gpio_pins[GPIOS_PER_PORT];
+	struct gpio_rpmsg_info info;
+	int idx;
+};
+
+static int gpio_send_message(struct rpmsg_gpio_port *port,
+			     struct gpio_rpmsg_packet *msg,
+			     bool sync)
+{
+	struct gpio_rpmsg_info *info = &port->info;
+	int err;
+
+	if (!info->rpdev) {
+		pr_err("rpmsg channel doesn't exist, is remote core ready?\n");
+		return -EINVAL;
+	}
+
+	reinit_completion(&info->cmd_complete);
+	err = rpmsg_send(info->rpdev->ept, (void *)msg,
+			 sizeof(struct gpio_rpmsg_packet));
+	if (err) {
+		dev_err(&info->rpdev->dev, "rpmsg_send failed: %d\n", err);
+		return err;
+	}
+
+	if (sync) {
+		err = wait_for_completion_timeout(&info->cmd_complete,
+						  msecs_to_jiffies(RPMSG_TIMEOUT));
+		if (!err) {
+			dev_err(&info->rpdev->dev, "rpmsg_send timeout!\n");
+			return -ETIMEDOUT;
+		}
+
+		if (info->reply_msg->out.retcode != 0) {
+			dev_err(&info->rpdev->dev, "remote core replies an error: %d!\n",
+				info->reply_msg->out.retcode);
+			return -EINVAL;
+		}
+
+		/* copy the reply message */
+		memcpy(&port->gpio_pins[info->reply_msg->pin_idx].msg,
+		       info->reply_msg, sizeof(*info->reply_msg));
+	}
+
+	return 0;
+}
+
+static struct gpio_rpmsg_packet *gpio_setup_msg_header(struct rpmsg_gpio_port *port,
+						       unsigned int offset,
+						       u8 cmd)
+{
+	struct gpio_rpmsg_packet *msg = &port->gpio_pins[offset].msg;
+
+	memset(msg, 0, sizeof(struct gpio_rpmsg_packet));
+	msg->header.id = RPMSG_GPIO_ID;
+	msg->header.vendor = RPMSG_VENDOR;
+	msg->header.version = RPMSG_VERSION;
+	msg->header.type = GPIO_RPMSG_SETUP;
+	msg->header.cmd = cmd;
+	msg->pin_idx = offset;
+	msg->port_idx = port->idx;
+
+	return msg;
+};
+
+static int rpmsg_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+	struct rpmsg_gpio_port *port = gpiochip_get_data(gc);
+	struct gpio_rpmsg_packet *msg = NULL;
+	int ret;
+
+	guard(mutex)(&port->info.lock);
+
+	msg = gpio_setup_msg_header(port, gpio, GPIO_RPMSG_INPUT_GET);
+
+	ret = gpio_send_message(port, msg, true);
+	if (!ret)
+		ret = !!port->gpio_pins[gpio].msg.in.value;
+
+	return ret;
+}
+
+static int rpmsg_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio)
+{
+	struct rpmsg_gpio_port *port = gpiochip_get_data(gc);
+	struct gpio_rpmsg_packet *msg = NULL;
+	int ret;
+
+	guard(mutex)(&port->info.lock);
+
+	msg = gpio_setup_msg_header(port, gpio, GPIO_RPMSG_DIRECTION_GET);
+
+	ret = gpio_send_message(port, msg, true);
+	if (!ret)
+		ret = !!port->gpio_pins[gpio].msg.in.value;
+
+	return ret;
+}
+
+static int rpmsg_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio)
+{
+	struct rpmsg_gpio_port *port = gpiochip_get_data(gc);
+	struct gpio_rpmsg_packet *msg = NULL;
+
+	guard(mutex)(&port->info.lock);
+
+	msg = gpio_setup_msg_header(port, gpio, GPIO_RPMSG_INPUT_INIT);
+
+	return gpio_send_message(port, msg, true);
+}
+
+static int rpmsg_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+	struct rpmsg_gpio_port *port = gpiochip_get_data(gc);
+	struct gpio_rpmsg_packet *msg = NULL;
+
+	guard(mutex)(&port->info.lock);
+
+	msg = gpio_setup_msg_header(port, gpio, GPIO_RPMSG_OUTPUT_INIT);
+	msg->out.value = val;
+
+	return gpio_send_message(port, msg, true);
+}
+
+static int rpmsg_gpio_direction_output(struct gpio_chip *gc,
+				       unsigned int gpio,
+				       int val)
+{
+
+	return rpmsg_gpio_set(gc, gpio, val);
+}
+
+static int gpio_rpmsg_irq_set_type(struct irq_data *d, u32 type)
+{
+	struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
+	u32 gpio_idx = d->hwirq;
+	int edge = 0;
+	int ret = 0;
+
+	switch (type) {
+	case IRQ_TYPE_EDGE_RISING:
+		edge = GPIO_RPMSG_TRI_RISING;
+		irq_set_handler_locked(d, handle_simple_irq);
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		edge = GPIO_RPMSG_TRI_FALLING;
+		irq_set_handler_locked(d, handle_simple_irq);
+		break;
+	case IRQ_TYPE_EDGE_BOTH:
+		edge = GPIO_RPMSG_TRI_BOTH_EDGE;
+		irq_set_handler_locked(d, handle_simple_irq);
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+		edge = GPIO_RPMSG_TRI_LOW_LEVEL;
+		irq_set_handler_locked(d, handle_level_irq);
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+		edge = GPIO_RPMSG_TRI_HIGH_LEVEL;
+		irq_set_handler_locked(d, handle_level_irq);
+		break;
+	default:
+		ret = -EINVAL;
+		irq_set_handler_locked(d, handle_bad_irq);
+		break;
+	}
+
+	port->gpio_pins[gpio_idx].irq_type = edge;
+
+	return ret;
+}
+
+static int gpio_rpmsg_irq_set_wake(struct irq_data *d, u32 enable)
+{
+	struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
+	u32 gpio_idx = d->hwirq;
+
+	port->gpio_pins[gpio_idx].irq_wake_enable = enable;
+
+	return 0;
+}
+
+/*
+ * This function will be called at:
+ *  - one interrupt setup.
+ *  - the end of one interrupt happened
+ * The gpio over rpmsg driver will not write the real register, so save
+ * all infos before this function and then send all infos to M core in this
+ * step.
+ */
+static void gpio_rpmsg_unmask_irq(struct irq_data *d)
+{
+	struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
+	u32 gpio_idx = d->hwirq;
+
+	port->gpio_pins[gpio_idx].irq_unmask = 1;
+}
+
+static void gpio_rpmsg_mask_irq(struct irq_data *d)
+{
+	struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
+	u32 gpio_idx = d->hwirq;
+	/*
+	 * No need to implement the callback at A core side.
+	 * M core will mask interrupt after a interrupt occurred, and then
+	 * sends a notify to A core.
+	 * After A core dealt with the notify, A core will send a rpmsg to
+	 * M core to unmask this interrupt again.
+	 */
+	port->gpio_pins[gpio_idx].irq_mask = 1;
+}
+
+static void gpio_rpmsg_irq_shutdown(struct irq_data *d)
+{
+	struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
+	u32 gpio_idx = d->hwirq;
+
+	port->gpio_pins[gpio_idx].irq_shutdown = 1;
+}
+
+static void gpio_rpmsg_irq_bus_lock(struct irq_data *d)
+{
+	struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
+
+	mutex_lock(&port->info.lock);
+}
+
+static void gpio_rpmsg_irq_bus_sync_unlock(struct irq_data *d)
+{
+	struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
+	struct gpio_rpmsg_packet *msg = NULL;
+	u32 gpio_idx = d->hwirq;
+
+	if (!port)
+		return;
+
+	/*
+	 * For mask irq, do nothing here.
+	 * M core will mask interrupt after a interrupt occurred, and then
+	 * sends a notify to A core.
+	 * After A core dealt with the notify, A core will send a rpmsg to
+	 * M core to unmask this interrupt again.
+	 */
+
+	if (port->gpio_pins[gpio_idx].irq_mask && !port->gpio_pins[gpio_idx].irq_unmask) {
+		port->gpio_pins[gpio_idx].irq_mask = 0;
+		mutex_unlock(&port->info.lock);
+		return;
+	}
+
+	msg = gpio_setup_msg_header(port, gpio_idx, GPIO_RPMSG_INPUT_INIT);
+
+	if (port->gpio_pins[gpio_idx].irq_shutdown) {
+		msg->out.event = GPIO_RPMSG_TRI_IGNORE;
+		msg->in.wakeup = 0;
+		port->gpio_pins[gpio_idx].irq_shutdown = 0;
+	} else {
+		 /* if not set irq type, then use low level as trigger type */
+		msg->out.event = port->gpio_pins[gpio_idx].irq_type;
+		if (!msg->out.event)
+			msg->out.event = GPIO_RPMSG_TRI_LOW_LEVEL;
+		if (port->gpio_pins[gpio_idx].irq_unmask) {
+			msg->in.wakeup = 0;
+			port->gpio_pins[gpio_idx].irq_unmask = 0;
+		} else /* irq set wake */
+			msg->in.wakeup = port->gpio_pins[gpio_idx].irq_wake_enable;
+	}
+
+	gpio_send_message(port, msg, false);
+	mutex_unlock(&port->info.lock);
+}
+
+static const struct irq_chip gpio_rpmsg_irq_chip = {
+	.irq_mask = gpio_rpmsg_mask_irq,
+	.irq_unmask = gpio_rpmsg_unmask_irq,
+	.irq_set_wake = gpio_rpmsg_irq_set_wake,
+	.irq_set_type = gpio_rpmsg_irq_set_type,
+	.irq_shutdown = gpio_rpmsg_irq_shutdown,
+	.irq_bus_lock = gpio_rpmsg_irq_bus_lock,
+	.irq_bus_sync_unlock = gpio_rpmsg_irq_bus_sync_unlock,
+	.flags = IRQCHIP_IMMUTABLE,
+};
+
+static int rpmsg_gpio_callback(struct rpmsg_device *rpdev,
+			       void *data, int len, void *priv, u32 src)
+{
+	struct gpio_rpmsg_packet *msg = (struct gpio_rpmsg_packet *)data;
+	struct rpmsg_gpio_port *port = NULL;
+	struct rpdev_platform_info *drvdata;
+
+	drvdata = dev_get_drvdata(&rpdev->dev);
+	if (msg)
+		port = drvdata->channel_devices[msg->port_idx];
+
+	if (!port)
+		return -ENODEV;
+
+	if (msg->header.type == GPIO_RPMSG_REPLY) {
+		port->info.reply_msg = msg;
+		complete(&port->info.cmd_complete);
+	} else if (msg->header.type == GPIO_RPMSG_NOTIFY) {
+		port->info.notify_msg = msg;
+		generic_handle_domain_irq_safe(port->gc.irq.domain, msg->pin_idx);
+	} else
+		dev_err(&rpdev->dev, "wrong command type!\n");
+
+	return 0;
+}
+
+static void rpmsg_gpio_remove_action(void *data)
+{
+	struct rpmsg_gpio_port *port = data;
+
+	port->info.port_store[port->idx] = NULL;
+}
+
+static int rpmsg_gpio_probe(struct platform_device *pdev)
+{
+	struct rpdev_platform_info *pltdata = pdev->dev.platform_data;
+	struct rpmsg_gpio_port *port;
+	struct gpio_irq_chip *girq;
+	struct gpio_chip *gc;
+	int ret;
+
+	if (!pltdata)
+		return -EPROBE_DEFER;
+
+	port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
+	if (!port)
+		return -ENOMEM;
+
+	ret = device_property_read_u32(&pdev->dev, "reg", &port->idx);
+	if (ret)
+		return ret;
+
+	if (port->idx > MAX_DEV_PER_CHANNEL)
+		return -EINVAL;
+
+	ret = devm_mutex_init(&pdev->dev, &port->info.lock);
+	if (ret)
+		return ret;
+
+	init_completion(&port->info.cmd_complete);
+	port->info.rpdev = pltdata->rpdev;
+	port->info.port_store = pltdata->channel_devices;
+	port->info.port_store[port->idx] = port;
+	if (!pltdata->rx_callback)
+		pltdata->rx_callback = rpmsg_gpio_callback;
+
+	gc = &port->gc;
+	gc->owner = THIS_MODULE;
+	gc->parent = &pdev->dev;
+	gc->label = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s-gpio%d",
+				   pltdata->rproc_name, port->idx);
+	gc->ngpio = GPIOS_PER_PORT;
+	gc->base = -1;
+
+	gc->direction_input = rpmsg_gpio_direction_input;
+	gc->direction_output = rpmsg_gpio_direction_output;
+	gc->get_direction = rpmsg_gpio_get_direction;
+	gc->get = rpmsg_gpio_get;
+	gc->set = rpmsg_gpio_set;
+
+	platform_set_drvdata(pdev, port);
+	girq = &gc->irq;
+	gpio_irq_chip_set_chip(girq, &gpio_rpmsg_irq_chip);
+	girq->parent_handler = NULL;
+	girq->num_parents = 0;
+	girq->parents = NULL;
+	girq->chip->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s-gpio%d",
+					  pltdata->rproc_name, port->idx);
+
+	ret = devm_add_action_or_reset(&pdev->dev, rpmsg_gpio_remove_action, port);
+	if (ret)
+		return ret;
+
+	return devm_gpiochip_add_data(&pdev->dev, gc, port);
+}
+
+static const struct of_device_id rpmsg_gpio_dt_ids[] = {
+	{ .compatible = "rpmsg-gpio" },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver rpmsg_gpio_driver = {
+	.driver	= {
+		.name = "gpio-rpmsg",
+		.of_match_table = rpmsg_gpio_dt_ids,
+	},
+	.probe = rpmsg_gpio_probe,
+};
+
+module_platform_driver(rpmsg_gpio_driver);
+
+MODULE_AUTHOR("Shenwei Wang <shenwei.wang at nxp.com>");
+MODULE_DESCRIPTION("generic rpmsg gpio driver");
+MODULE_LICENSE("GPL");
-- 
2.43.0



From shenwei.wang at nxp.com  Fri Dec 12 11:43:41 2025
From: shenwei.wang at nxp.com (Shenwei Wang)
Date: Fri, 12 Dec 2025 13:43:41 -0600
Subject: [PATCH v6 5/5] arm64: dts: imx8ulp: Add rpmsg node under imx_rproc
In-Reply-To: <20251212194341.966387-1-shenwei.wang@nxp.com>
References: <20251212194341.966387-1-shenwei.wang@nxp.com>
Message-ID: <20251212194341.966387-6-shenwei.wang@nxp.com>

Add the RPMSG bus node along with its GPIO subnodes to the device
tree.

Enable remote device communication and GPIO control via RPMSG on
the i.MX platform.

Signed-off-by: Shenwei Wang <shenwei.wang at nxp.com>
---
 arch/arm64/boot/dts/freescale/imx8ulp.dtsi | 27 ++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8ulp.dtsi b/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
index 13b01f3aa2a4..93846435c6c1 100644
--- a/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
@@ -191,6 +191,33 @@ scmi_sensor: protocol at 15 {
 	cm33: remoteproc-cm33 {
 		compatible = "fsl,imx8ulp-cm33";
 		status = "disabled";
+
+		rpmsg {
+			rpmsg-io-channel {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				rpmsg_gpioa: gpio at 0 {
+					compatible = "rpmsg-gpio";
+					reg = <0>;
+					gpio-controller;
+					#gpio-cells = <2>;
+					#interrupt-cells = <2>;
+					interrupt-controller;
+					interrupt-parent = <&rpmsg_gpioa>;
+				};
+
+				rpmsg_gpiob: gpio at 1 {
+					compatible = "rpmsg-gpio";
+					reg = <1>;
+					gpio-controller;
+					#gpio-cells = <2>;
+					#interrupt-cells = <2>;
+					interrupt-controller;
+					interrupt-parent = <&rpmsg_gpiob>;
+				};
+			};
+		};
 	};
 
 	soc: soc at 0 {
-- 
2.43.0



From nicolinc at nvidia.com  Fri Dec 12 11:46:13 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Fri, 12 Dec 2025 11:46:13 -0800
Subject: [PATCH V6 1/4] iommu/tegra241-cmdqv: Decouple driver from ACPI
In-Reply-To: <54fce1f8-7675-4351-b292-0009b2e8c599@arm.com>
References: <20251212060803.1712637-1-amhetre@nvidia.com>
 <20251212060803.1712637-2-amhetre@nvidia.com>
 <54fce1f8-7675-4351-b292-0009b2e8c599@arm.com>
Message-ID: <aTxxBdcY4hODXcdu@nvidia.com>

On Fri, Dec 12, 2025 at 12:01:41PM +0000, Robin Murphy wrote:
> > @@ -4542,7 +4542,7 @@ static void acpi_smmu_dsdt_probe_tegra241_cmdqv(struct acpi_iort_node *node,
> >   	adev = acpi_dev_get_first_match_dev("NVDA200C", uid, -1);
> >   	if (adev) {
> >   		/* Tegra241 CMDQV driver is responsible for put_device() */
> 
> Don't we need to bring the put_device(adev) out to this level, since
> impl_dev is now something else that AFAICS we are *not* taking a new
> reference on (and thus should not be putting either)?

Ah, right! We are using the platform device now.

> > -		smmu->impl_dev = &adev->dev;
> > +		smmu->impl_dev = acpi_get_first_physical_node(adev);
> >   		smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
> >   		dev_info(smmu->dev, "found companion CMDQV device: %s\n",
> >   			 dev_name(smmu->impl_dev));

I think we should squash this:

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 0c98be3135c63..88625e3c27a65 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -5280,10 +5280,11 @@ static void acpi_smmu_dsdt_probe_tegra241_cmdqv(struct acpi_iort_node *node,
 	adev = acpi_dev_get_first_match_dev("NVDA200C", uid, -1);
 	if (adev) {
 		/* Tegra241 CMDQV driver is responsible for put_device() */
-		smmu->impl_dev = acpi_get_first_physical_node(adev);
+		smmu->impl_dev = get_device(acpi_get_first_physical_node(adev));
 		smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
 		dev_info(smmu->dev, "found companion CMDQV device: %s\n",
 			 dev_name(smmu->impl_dev));
+		acpi_dev_put(adev);
 	}
 	kfree(uid);
 }

Thanks
Nicolin


From will at kernel.org  Fri Dec 12 12:08:55 2025
From: will at kernel.org (Will Deacon)
Date: Sat, 13 Dec 2025 05:08:55 +0900
Subject: [PATCH v6 0/3] arm64: topology: Handle AMU FIE setup on CPU
 hotplug
In-Reply-To: <29253319-ced9-4ab6-a58e-28afdf235cde@huawei.com>
References: <20251119081356.2495290-1-zhenglifeng1@huawei.com>
 <aS2z0EURwHbbGZab@arm.com>
 <9b6882dc-a91a-42d6-bf76-347338930d71@huawei.com>
 <aS8GZOuaS1-j14MD@arm.com>
 <29253319-ced9-4ab6-a58e-28afdf235cde@huawei.com>
Message-ID: <aTx2V4am0FNHm03R@google.com>

On Fri, Dec 12, 2025 at 05:27:09PM +0800, zhenglifeng (A) wrote:
> On 2025/12/2 23:31, Beata Michalska wrote:
> > On Tue, Dec 02, 2025 at 11:05:25AM +0800, zhenglifeng (A) wrote:
> >> On 2025/12/1 23:27, Beata Michalska wrote:
> >>> Hi,
> >>>
> >>> Apologies for the delay in reviewing this - currently in progress....
> >>> Out of curiosity: what's the cpufreq driver used for testing this series ?
> >>
> >> I used cppc_cpufreq for testing this. But with some modifications in
> >> processor_driver.c, or you'll find that the driver will fail to load with
> >> maxcpus set. The modification below is only a temporary solution. I'm still
> >> working on that.
> >>
> > Right, so overall the implementation looks good - thanks for that.
> > There are two issues though with the cppc cpufreq driver.
> > 
> > One: as you have already noticed - it fails to register when
> > cpumask_present != cpumask_online.
> > 
> > Second: it will mix the sources of the freq scale if not all CPUs within the
> > policy have AMUs enabled/valid. This is due to the fact that at the time of
> > registering the driver and initializing the FIE support policy->cpus ==
> > policy->related_cpus. Assuming scenario when there are two CPUs within the
> > policy, one being offline and missing valid AMU counters,
> > the topology_set_scale_freq_source from cppc cpufreq driver will register
> > the tick handler for both CPUs, whereas AMU support will (rightly so) register
> > only for the firs one. When the second CPU comes online, the mismatch will be
> > detected and the arch callback will get cleared for the first CPU, but the
> > second one will remain unchanged.
> > 
> > That said, I do not think any of those issues is a blocker for this series.
> > But both would need fixing.
> 
> I believe Beata is OK with this series. So I think we can move ahead with it
> now.

Please repost at -rc1. It would be nice to have an Ack from Beata...

Will


From will at kernel.org  Fri Dec 12 12:13:40 2025
From: will at kernel.org (Will Deacon)
Date: Sat, 13 Dec 2025 05:13:40 +0900
Subject: [PATCH 00/10] arm64: Replace TLB invalidation preprocessor
 macros with C functions
In-Reply-To: <b40ee164-f533-43da-a4e2-068c9ae1e771@arm.com>
References: <20250711161732.384-1-will@kernel.org>
 <eb583fda-cbd1-4ef2-900a-a86e08a0b5d3@arm.com>
 <b40ee164-f533-43da-a4e2-068c9ae1e771@arm.com>
Message-ID: <aTx3dM8XUMQMOf2-@google.com>

On Fri, Dec 12, 2025 at 12:12:05PM +0000, Ryan Roberts wrote:
> On 10/12/2025 12:29, Ryan Roberts wrote:
> > On 11/07/2025 17:17, Will Deacon wrote:
> >> I cooked this series following a complaint from Linus back in March
> >> about our range-based TLB invalidation macro after we fixed an
> >> over-invalidation bug thanks to incorrect handling of its arguments:
> >>
> >>   https://lore.kernel.org/all/CAHk-=wgiX0q0WCL+SFwVCYtG7JR3=2Rshse-5J3AO2Y4AgT7Jw at mail.gmail.com/
> >>
> >> Once I started trying to rework the range macro into a C function, I
> >> spotted a few other opportunities for cleanup and so I've ended up with
> >> this series.
> >>
> >> Testing and feedback welcome.
> > 
> > Hi Will,
> > 
> > Did this go anywhere/are you planning to post a new version? There are a couple
> > of other cleanups I'd like to do in this area, and also I'd like to add tlbip
> > support. But I don't want to spend time on it if the baseline is going to
> > drastically change.
> > 
> > If you're not planning a v2, perhaps I could have a go then extend for the
> > extras I want to do?
> 
> Since I didn't hear back, I've reworked the series to include Linus's suggestion
> and am currently testing. Plan to post against -rc1.

Sorry, at LPC atm and have fallen behind. I was still planning to rework
this but I'm aware of other folks at Arm making changes here as well so
you should be wary of that too.

Regardless of macros or indirect branches, I was relatively happy with
some of the cleanup that fell out of this series so I'd be keen to land
it either way.

Will


From adrian.kossmann at posteo.de  Fri Dec 12 12:25:11 2025
From: adrian.kossmann at posteo.de (Adrian Kossmann)
Date: Fri, 12 Dec 2025 20:25:11 +0000
Subject: [PATCH] arm64: dts: rockchip: Add compatible for Ethernet PHY
In-Reply-To: <8e4607b7-8045-413d-aa3e-c2c1a74f52a6@lunn.ch>
References: <8e4607b7-8045-413d-aa3e-c2c1a74f52a6@lunn.ch>
Message-ID: <20251212202451.556449-1-adrian.kossmann@posteo.de>

Hi Andrew,

> It is a bit unusual for phylib to get the wrong driver, so i would
like to understand this a bit more.

after double-checking my setup I found that the PHY is in fact always 
bound to the RTL8211F driver, even without the compatible string, and 
this was rather an issue with my setup. 

The link instability I observed was caused by inappropriate RGMII RX/TX 
delay settings in the mainline DTS. With the current values for 
rx_delay and tx_delay in the mainline DTS the link collapsed under load. 
I've troubleshooted this with a known-good DTB and using its rx_delay 
and tx_delay values fixes the issue. 
I will send a v2 patch adjusting the delays instead of adding a compatible.

      Adrian



From coltonlewis at google.com  Fri Dec 12 12:27:47 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Fri, 12 Dec 2025 20:27:47 +0000
Subject: [PATCH v5 11/24] KVM: arm64: Writethrough trapped PMEVTYPER register
In-Reply-To: <202512110209.GjVZa9ti-lkp@intel.com> (message from kernel test
 robot on Thu, 11 Dec 2025 02:31:00 +0800)
Message-ID: <gsnt4ipv4f98.fsf@coltonlewis-kvm.c.googlers.com>

kernel test robot <lkp at intel.com> writes:

> Hi Colton,

> kernel test robot noticed the following build errors:

> [auto build test ERROR on ac3fd01e4c1efce8f2c054cdeb2ddd2fc0fb150d]

> url:     
> https://github.com/intel-lab-lkp/linux/commits/Colton-Lewis/arm64-cpufeature-Add-cpucap-for-HPMN0/20251210-055309
> base:   ac3fd01e4c1efce8f2c054cdeb2ddd2fc0fb150d
> patch link:     
> https://lore.kernel.org/r/20251209205121.1871534-12-coltonlewis%40google.com
> patch subject: [PATCH v5 11/24] KVM: arm64: Writethrough trapped  
> PMEVTYPER register
> config: arm64-randconfig-001-20251210  
> (https://download.01.org/0day-ci/archive/20251211/202512110209.GjVZa9ti-lkp at intel.com/config)
> compiler: aarch64-linux-gcc (GCC) 14.3.0
> reproduce (this is a W=1 build):  
> (https://download.01.org/0day-ci/archive/20251211/202512110209.GjVZa9ti-lkp at intel.com/reproduce)

> If you fix the issue in a separate patch/commit (i.e. not just a new  
> version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp at intel.com>
> | Closes:  
> https://lore.kernel.org/oe-kbuild-all/202512110209.GjVZa9ti-lkp at intel.com/

> All errors (new ones prefixed by >>):

>     arch/arm64/kvm/sys_regs.c: In function 'writethrough_pmevtyper':
>>> arch/arm64/kvm/sys_regs.c:1183:34: error: implicit declaration of  
>>> function 'kvm_pmu_event_mask'; did you mean 'kvm_pmu_evtyper_mask'?  
>>> [-Wimplicit-function-declaration]
>      1183 |                 eventsel = val & kvm_pmu_event_mask(vcpu->kvm);
>           |                                  ^~~~~~~~~~~~~~~~~~
>           |                                  kvm_pmu_evtyper_mask


Caused by missing a stub definition for kvm_pmu_event_mask when
reorganizing headers in patch 6: Reorganize PMU functions

Fixed

> vim +1183 arch/arm64/kvm/sys_regs.c

>    1168
>    1169	static bool writethrough_pmevtyper(struct kvm_vcpu *vcpu, struct  
> sys_reg_params *p,
>    1170					   u64 reg, u64 idx)
>    1171	{
>    1172		u64 eventsel;
>    1173		u64 val = p->regval;
>    1174		u64 evtyper_set = ARMV8_PMU_EXCLUDE_EL0 |
>    1175			ARMV8_PMU_EXCLUDE_EL1;
>    1176		u64 evtyper_clr = ARMV8_PMU_INCLUDE_EL2;
>    1177
>    1178		__vcpu_assign_sys_reg(vcpu, reg, val);
>    1179
>    1180		if (idx == ARMV8_PMU_CYCLE_IDX)
>    1181			eventsel = ARMV8_PMUV3_PERFCTR_CPU_CYCLES;
>    1182		else
>> 1183			eventsel = val & kvm_pmu_event_mask(vcpu->kvm);
>    1184
>    1185		if (vcpu->kvm->arch.pmu_filter &&
>    1186		    !test_bit(eventsel, vcpu->kvm->arch.pmu_filter))
>    1187			val |= evtyper_set;
>    1188
>    1189		val &= ~evtyper_clr;
>    1190
>    1191		if (idx == ARMV8_PMU_CYCLE_IDX)
>    1192			write_pmccfiltr(val);
>    1193		else
>    1194			write_pmevtypern(idx, val);
>    1195
>    1196		return true;
>    1197	}
>    1198

> --
> 0-DAY CI Kernel Test Service
> https://github.com/intel/lkp-tests/wiki


From nicolas.frattaroli at collabora.com  Fri Dec 12 12:28:03 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Fri, 12 Dec 2025 21:28:03 +0100
Subject: [PATCH v5 17/17] drm/tests: hdmi: Add tests for the color_format property
In-Reply-To: <20251212-discreet-wisteria-perch-edccad@penduick>
References: <20251128-color-format-v5-0-63e82f1db1e1@collabora.com>
 <20251128-color-format-v5-17-63e82f1db1e1@collabora.com>
 <20251212-discreet-wisteria-perch-edccad@penduick>
Message-ID: <2819485.tdWV9SEqCh@workhorse>

On Friday, 12 December 2025 10:19:13 Central European Standard Time Maxime Ripard wrote:
> On Fri, Nov 28, 2025 at 10:05:53PM +0100, Nicolas Frattaroli wrote:
> > Add some KUnit tests to check the color_format property is working as
> > expected with the HDMI state helper.
> > 
> > The added tests check that AUTO results in RGB, and the YCBCR modes
> > result in the corresponding YUV modes. An additional test ensures that
> > only DRM_COLOR_FORMAT_AUTO falls back to YUV420 with a YUV420-only mode,
> > and RGB errors out instead, while explicitly asking for YUV420 still
> > works.
> > 
> > This requires exporting hdmi_compute_config, so that it is accessible
> > from the tests.
> > 
> > Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
> > ---
> >  drivers/gpu/drm/display/drm_hdmi_state_helper.c    |   3 +-
> >  drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 109 +++++++++++++++++++++
> >  include/drm/display/drm_hdmi_state_helper.h        |   4 +
> >  3 files changed, 115 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> > index 1800e00b30c5..e86fb837ceaf 100644
> > --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> > +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> > @@ -641,7 +641,7 @@ hdmi_compute_format_bpc(const struct drm_connector *connector,
> >  	return -EINVAL;
> >  }
> >  
> > -static int
> > +int
> >  hdmi_compute_config(const struct drm_connector *connector,
> >  		    struct drm_connector_state *conn_state,
> >  		    const struct drm_display_mode *mode)
> > @@ -680,6 +680,7 @@ hdmi_compute_config(const struct drm_connector *connector,
> >  
> >  	return ret;
> >  }
> > +EXPORT_SYMBOL(hdmi_compute_config);
> 
> I don't think we need to export hdmi_compute_config directly, and if we
> do, it shouldn't be named that way.
> 
> The rest of the tests in the suite manage to test everything fine
> without exporting it. Is there any reason you can't do it for these
> tests?

The only function that calls hdmi_compute_config is the exported
drm_atomic_helper_connector_hdmi_check. While I can write tests around
drm_atomic_helper_connector_hdmi_check, it'll mean I'll have structure
the tests differently, and will accidentally test a lot of other things
as well, because it derives other state from the config and has a lot
more error paths. So checking that hdmi_compute_config fails as expected
won't be possible anymore, just that "_connector_hdmi_check fails.

I will rewrite the tests to do this since that appears to be the way
to do this, but I'll need to read up on the atomic state APIs and the
helper functions I've been using so far a bit to make sure I'm not
writing something broken here.

I do share your concerns about exporting this function though, I didn't
like doing it either. It is a side effect of unit testing not being a
first-class citizen of the C language I guess, but maybe it is better
to do this as an end-to-end test of the exported function rather than
just part of the implementation anyway.

> [...]

For everything I didn't directly reply to, assume I'll address it in
the next revision with no further sobbing to convey from my side.

Kind regards,
Nicolas Frattaroli




From coltonlewis at google.com  Fri Dec 12 12:29:59 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Fri, 12 Dec 2025 20:29:59 +0000
Subject: [PATCH v5 09/24] perf: arm_pmuv3: Keep out of guest counter partition
In-Reply-To: <202512110439.UXwb1Qh4-lkp@intel.com> (message from kernel test
 robot on Thu, 11 Dec 2025 04:21:58 +0800)
Message-ID: <gsnt1pkz4f5k.fsf@coltonlewis-kvm.c.googlers.com>

kernel test robot <lkp at intel.com> writes:

> Hi Colton,

> kernel test robot noticed the following build warnings:

> [auto build test WARNING on ac3fd01e4c1efce8f2c054cdeb2ddd2fc0fb150d]

> url:     
> https://github.com/intel-lab-lkp/linux/commits/Colton-Lewis/arm64-cpufeature-Add-cpucap-for-HPMN0/20251210-055309
> base:   ac3fd01e4c1efce8f2c054cdeb2ddd2fc0fb150d
> patch link:     
> https://lore.kernel.org/r/20251209205121.1871534-10-coltonlewis%40google.com
> patch subject: [PATCH v5 09/24] perf: arm_pmuv3: Keep out of guest  
> counter partition
> config: arm64-defconfig  
> (https://download.01.org/0day-ci/archive/20251211/202512110439.UXwb1Qh4-lkp at intel.com/config)
> compiler: aarch64-linux-gcc (GCC) 15.1.0
> reproduce (this is a W=1 build):  
> (https://download.01.org/0day-ci/archive/20251211/202512110439.UXwb1Qh4-lkp at intel.com/reproduce)

> If you fix the issue in a separate patch/commit (i.e. not just a new  
> version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp at intel.com>
> | Closes:  
> https://lore.kernel.org/oe-kbuild-all/202512110439.UXwb1Qh4-lkp at intel.com/

> All warnings (new ones prefixed by >>):

>>> Warning: arch/arm64/kvm/pmu-direct.c:75 function parameter 'pmu' not  
>>> described in 'kvm_pmu_guest_counter_mask'

Just a missing argument description in the comment. Fixed


> --
> 0-DAY CI Kernel Test Service
> https://github.com/intel/lkp-tests/wiki


From robh at kernel.org  Fri Dec 12 12:32:09 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Fri, 12 Dec 2025 14:32:09 -0600
Subject: [PATCH] arm/arm64: dts: st: Drop unused .dtsi
Message-ID: <20251212203226.458694-3-robh@kernel.org>

These .dtsi files are not included anywhere in the tree and can't be
tested.

Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
---
 arch/arm/boot/dts/st/spear320s.dtsi           | 24 -------
 .../boot/dts/st/stm32mp15xxab-pinctrl.dtsi    | 57 ---------------
 arch/arm64/boot/dts/qcom/msm8996-v3.0.dtsi    | 63 ----------------
 arch/arm64/boot/dts/st/stm32mp21xc.dtsi       |  8 ---
 arch/arm64/boot/dts/st/stm32mp23xc.dtsi       |  8 ---
 arch/arm64/boot/dts/st/stm32mp25xc.dtsi       |  8 ---
 .../boot/dts/st/stm32mp25xxal-pinctrl.dtsi    | 71 -------------------
 7 files changed, 239 deletions(-)
 delete mode 100644 arch/arm/boot/dts/st/spear320s.dtsi
 delete mode 100644 arch/arm/boot/dts/st/stm32mp15xxab-pinctrl.dtsi
 delete mode 100644 arch/arm64/boot/dts/qcom/msm8996-v3.0.dtsi
 delete mode 100644 arch/arm64/boot/dts/st/stm32mp21xc.dtsi
 delete mode 100644 arch/arm64/boot/dts/st/stm32mp23xc.dtsi
 delete mode 100644 arch/arm64/boot/dts/st/stm32mp25xc.dtsi
 delete mode 100644 arch/arm64/boot/dts/st/stm32mp25xxal-pinctrl.dtsi

diff --git a/arch/arm/boot/dts/st/spear320s.dtsi b/arch/arm/boot/dts/st/spear320s.dtsi
deleted file mode 100644
index 133236dc190d..000000000000
--- a/arch/arm/boot/dts/st/spear320s.dtsi
+++ /dev/null
@@ -1,24 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * DTS file for SPEAr320s SoC
- *
- * Copyright 2021 Herve Codina <herve.codina at bootlin.com>
- */
-
-/include/ "spear320.dtsi"
-
-/ {
-	ahb {
-		apb {
-			gpiopinctrl: gpio at b3000000 {
-				/*
-				 * The "RM0321 SPEAr320s address and map
-				 * registers" document mentions interrupt 6
-				 * (NPGIO_INTR) for the PL_GPIO interrupt.
-				 */
-				interrupts = <6>;
-				interrupt-parent = <&shirq>;
-			};
-		};
-	};
-};
diff --git a/arch/arm/boot/dts/st/stm32mp15xxab-pinctrl.dtsi b/arch/arm/boot/dts/st/stm32mp15xxab-pinctrl.dtsi
deleted file mode 100644
index 328dad140e9b..000000000000
--- a/arch/arm/boot/dts/st/stm32mp15xxab-pinctrl.dtsi
+++ /dev/null
@@ -1,57 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: Alexandre Torgue <alexandre.torgue at st.com> for STMicroelectronics.
- */
-
-&pinctrl {
-	st,package = <STM32MP_PKG_AB>;
-
-	gpioa: gpio at 50002000 {
-		status = "okay";
-		ngpios = <16>;
-		gpio-ranges = <&pinctrl 0 0 16>;
-	};
-
-	gpiob: gpio at 50003000 {
-		status = "okay";
-		ngpios = <16>;
-		gpio-ranges = <&pinctrl 0 16 16>;
-	};
-
-	gpioc: gpio at 50004000 {
-		status = "okay";
-		ngpios = <16>;
-		gpio-ranges = <&pinctrl 0 32 16>;
-	};
-
-	gpiod: gpio at 50005000 {
-		status = "okay";
-		ngpios = <16>;
-		gpio-ranges = <&pinctrl 0 48 16>;
-	};
-
-	gpioe: gpio at 50006000 {
-		status = "okay";
-		ngpios = <16>;
-		gpio-ranges = <&pinctrl 0 64 16>;
-	};
-
-	gpiof: gpio at 50007000 {
-		status = "okay";
-		ngpios = <6>;
-		gpio-ranges = <&pinctrl 6 86 6>;
-	};
-
-	gpiog: gpio at 50008000 {
-		status = "okay";
-		ngpios = <10>;
-		gpio-ranges = <&pinctrl 6 102 10>;
-	};
-
-	gpioh: gpio at 50009000 {
-		status = "okay";
-		ngpios = <2>;
-		gpio-ranges = <&pinctrl 0 112 2>;
-	};
-};
diff --git a/arch/arm64/boot/dts/qcom/msm8996-v3.0.dtsi b/arch/arm64/boot/dts/qcom/msm8996-v3.0.dtsi
deleted file mode 100644
index 929bdcd45d02..000000000000
--- a/arch/arm64/boot/dts/qcom/msm8996-v3.0.dtsi
+++ /dev/null
@@ -1,63 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-/*
- * Copyright (c) 2021, Konrad Dybcio <konrad.dybcio at somainline.org>
- */
-
-#include "msm8996.dtsi"
-
-/ {
-	qcom,msm-id = <246 0x30000>;
-};
-
- /*
-  * This revision seems to have differ GPU CPR
-  * parameters, GPU frequencies and some differences
-  * when it comes to voltage delivery to.. once again
-  * the GPU. Funnily enough, it's simpler to make it an
-  * overlay on top of 3.1 (the final one) than vice versa.
-  * The differences will show here as more and more
-  * features get enabled upstream.
-  */
-
-gpu_opp_table_3_0: opp-table-gpu30 {
-	compatible = "operating-points-v2";
-
-	opp-624000000 {
-		opp-hz = /bits/ 64 <624000000>;
-		opp-level = <7>;
-	};
-
-	opp-560000000 {
-		opp-hz = /bits/ 64 <560000000>;
-		opp-level = <6>;
-	};
-
-	opp-510000000 {
-		opp-hz = /bits/ 64 <510000000>;
-		opp-level = <5>;
-	};
-
-	opp-401800000 {
-		opp-hz = /bits/ 64 <401800000>;
-		opp-level = <4>;
-	};
-
-	opp-315000000 {
-		opp-hz = /bits/ 64 <315000000>;
-		opp-level = <3>;
-	};
-
-	opp-214000000 {
-		opp-hz = /bits/ 64 <214000000>;
-		opp-level = <3>;
-	};
-
-	opp-133000000 {
-		opp-hz = /bits/ 64 <133000000>;
-		opp-level = <3>;
-	};
-};
-
-&gpu {
-	operating-points-v2 = <&gpu_opp_table_3_0>;
-};
diff --git a/arch/arm64/boot/dts/st/stm32mp21xc.dtsi b/arch/arm64/boot/dts/st/stm32mp21xc.dtsi
deleted file mode 100644
index e33b00b424e1..000000000000
--- a/arch/arm64/boot/dts/st/stm32mp21xc.dtsi
+++ /dev/null
@@ -1,8 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
-/*
- * Copyright (C) STMicroelectronics 2025 - All Rights Reserved
- * Author: Alexandre Torgue <alexandre.torgue at foss.st.com> for STMicroelectronics.
- */
-
-/ {
-};
diff --git a/arch/arm64/boot/dts/st/stm32mp23xc.dtsi b/arch/arm64/boot/dts/st/stm32mp23xc.dtsi
deleted file mode 100644
index e33b00b424e1..000000000000
--- a/arch/arm64/boot/dts/st/stm32mp23xc.dtsi
+++ /dev/null
@@ -1,8 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
-/*
- * Copyright (C) STMicroelectronics 2025 - All Rights Reserved
- * Author: Alexandre Torgue <alexandre.torgue at foss.st.com> for STMicroelectronics.
- */
-
-/ {
-};
diff --git a/arch/arm64/boot/dts/st/stm32mp25xc.dtsi b/arch/arm64/boot/dts/st/stm32mp25xc.dtsi
deleted file mode 100644
index 5e83a6926485..000000000000
--- a/arch/arm64/boot/dts/st/stm32mp25xc.dtsi
+++ /dev/null
@@ -1,8 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-3-Clause)
-/*
- * Copyright (C) STMicroelectronics 2023 - All Rights Reserved
- * Author: Alexandre Torgue <alexandre.torgue at foss.st.com> for STMicroelectronics.
- */
-
-/ {
-};
diff --git a/arch/arm64/boot/dts/st/stm32mp25xxal-pinctrl.dtsi b/arch/arm64/boot/dts/st/stm32mp25xxal-pinctrl.dtsi
deleted file mode 100644
index 2406e972554c..000000000000
--- a/arch/arm64/boot/dts/st/stm32mp25xxal-pinctrl.dtsi
+++ /dev/null
@@ -1,71 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-3-Clause)
-/*
- * Copyright (C) STMicroelectronics 2023 - All Rights Reserved
- * Author: Alexandre Torgue <alexandre.torgue at foss.st.com> for STMicroelectronics.
- */
-
-&pinctrl {
-	st,package = <STM32MP_PKG_AL>;
-
-	gpioa: gpio at 44240000 {
-		status = "okay";
-		ngpios = <16>;
-		gpio-ranges = <&pinctrl 0 0 16>;
-	};
-
-	gpiob: gpio at 44250000 {
-		status = "okay";
-		ngpios = <16>;
-		gpio-ranges = <&pinctrl 0 16 16>;
-	};
-
-	gpioc: gpio at 44260000 {
-		status = "okay";
-		ngpios = <14>;
-		gpio-ranges = <&pinctrl 0 32 14>;
-	};
-
-	gpiod: gpio at 44270000 {
-		status = "okay";
-		ngpios = <16>;
-		gpio-ranges = <&pinctrl 0 48 16>;
-	};
-
-	gpioe: gpio at 44280000 {
-		status = "okay";
-		ngpios = <16>;
-		gpio-ranges = <&pinctrl 0 64 16>;
-	};
-
-	gpiof: gpio at 44290000 {
-		status = "okay";
-		ngpios = <16>;
-		gpio-ranges = <&pinctrl 0 80 16>;
-	};
-
-	gpiog: gpio at 442a0000 {
-		status = "okay";
-		ngpios = <16>;
-		gpio-ranges = <&pinctrl 0 96 16>;
-	};
-
-	gpioh: gpio at 442b0000 {
-		status = "okay";
-		ngpios = <12>;
-		gpio-ranges = <&pinctrl 2 114 12>;
-	};
-
-	gpioi: gpio at 442c0000 {
-		status = "okay";
-		ngpios = <12>;
-		gpio-ranges = <&pinctrl 0 128 12>;
-	};
-};
-
-&pinctrl_z {
-	gpioz: gpio at 46200000 {
-		status = "okay";
-		ngpios = <10>;
-		gpio-ranges = <&pinctrl_z 0 400 10>;
-	};
-};
-- 
2.51.0



From robh at kernel.org  Fri Dec 12 12:32:10 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Fri, 12 Dec 2025 14:32:10 -0600
Subject: [PATCH] ARM: dts: intel: Drop pxa2xx
Message-ID: <20251212203226.458694-4-robh@kernel.org>

These .dtsi files are not included anywhere in the tree and can't be
tested. They have not been touched since 2018 other than clean-ups.

Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
---
 arch/arm/boot/dts/intel/pxa/pxa25x.dtsi       | 118 -----------
 arch/arm/boot/dts/intel/pxa/pxa27x.dtsi       | 188 ------------------
 arch/arm/boot/dts/marvell/armada-380.dtsi     | 148 --------------
 arch/arm64/boot/dts/marvell/armada-7020.dtsi  |  10 -
 arch/arm64/boot/dts/marvell/armada-8020.dtsi  |  20 --
 .../boot/dts/marvell/armada-ap806-dual.dtsi   |  60 ------
 .../dts/marvell/cn9130-db-comexpress.dtsi     |  96 ---------
 7 files changed, 640 deletions(-)
 delete mode 100644 arch/arm/boot/dts/intel/pxa/pxa25x.dtsi
 delete mode 100644 arch/arm/boot/dts/intel/pxa/pxa27x.dtsi
 delete mode 100644 arch/arm/boot/dts/marvell/armada-380.dtsi
 delete mode 100644 arch/arm64/boot/dts/marvell/armada-7020.dtsi
 delete mode 100644 arch/arm64/boot/dts/marvell/armada-8020.dtsi
 delete mode 100644 arch/arm64/boot/dts/marvell/armada-ap806-dual.dtsi
 delete mode 100644 arch/arm64/boot/dts/marvell/cn9130-db-comexpress.dtsi

diff --git a/arch/arm/boot/dts/intel/pxa/pxa25x.dtsi b/arch/arm/boot/dts/intel/pxa/pxa25x.dtsi
deleted file mode 100644
index 5f8300e356ad..000000000000
--- a/arch/arm/boot/dts/intel/pxa/pxa25x.dtsi
+++ /dev/null
@@ -1,118 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2016 Robert Jarzmik <robert.jarzmik at free.fr>
- */
-#include "pxa2xx.dtsi"
-#include "dt-bindings/clock/pxa-clock.h"
-
-/ {
-	model = "Marvell PXA25x family SoC";
-	compatible = "marvell,pxa250";
-
-	clocks {
-	       /*
-		* The muxing of external clocks/internal dividers for osc* clock
-		* sources has been hidden under the carpet by now.
-		*/
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		clks: pxa2xx_clks at 41300004 {
-			compatible = "marvell,pxa250-core-clocks";
-			#clock-cells = <1>;
-			status = "okay";
-		};
-
-		/* timer oscillator */
-		clktimer: oscillator {
-			compatible = "fixed-clock";
-			#clock-cells = <0>;
-			clock-frequency  = <3686400>;
-			clock-output-names = "ostimer";
-		};
-	};
-
-	pxabus {
-		pdma: dma-controller at 40000000 {
-			compatible = "marvell,pdma-1.0";
-			reg = <0x40000000 0x10000>;
-			interrupts = <25>;
-			#dma-cells = <2>;
-			/* For backwards compatibility: */
-			#dma-channels = <16>;
-			dma-channels = <16>;
-			#dma-requests = <40>;
-			dma-requests = <40>;
-			status = "okay";
-		};
-
-		pxairq: interrupt-controller at 40d00000 {
-			marvell,intc-priority;
-			marvell,intc-nr-irqs = <32>;
-		};
-
-		pinctrl: pinctrl at 40e00000 {
-			reg = <0x40e00054 0x20 0x40e0000c 0xc 0x40e0010c 4
-			       0x40f00020 0x10>;
-			compatible = "marvell,pxa25x-pinctrl";
-		};
-
-		gpio: gpio at 40e00000 {
-			compatible = "intel,pxa25x-gpio";
-			gpio-ranges = <&pinctrl 0 0 84>;
-			clocks = <&clks CLK_NONE>;
-		};
-
-		pwm0: pwm at 40b00000 {
-			compatible = "marvell,pxa250-pwm";
-			reg = <0x40b00000 0x10>;
-			#pwm-cells = <1>;
-			clocks = <&clks CLK_PWM0>;
-		};
-
-		pwm1: pwm at 40b00010 {
-			compatible = "marvell,pxa250-pwm";
-			reg = <0x40b00010 0x10>;
-			#pwm-cells = <1>;
-			clocks = <&clks CLK_PWM1>;
-		};
-
-		rtc at 40900000 {
-			clocks = <&clks CLK_OSC32k768>;
-		};
-	};
-
-	timer at 40a00000 {
-		compatible = "marvell,pxa-timer";
-		reg = <0x40a00000 0x20>;
-		interrupts = <26>;
-		clocks = <&clktimer>;
-		status = "okay";
-	};
-
-	pxa250_opp_table: opp_table0 {
-		compatible = "operating-points-v2";
-
-		opp-99532800 {
-			opp-hz = /bits/ 64 <99532800>;
-			opp-microvolt = <1000000 950000 1650000>;
-			clock-latency-ns = <20>;
-		};
-		opp-199065600 {
-			opp-hz = /bits/ 64 <199065600>;
-			opp-microvolt = <1000000 950000 1650000>;
-			clock-latency-ns = <20>;
-		};
-		opp-298598400 {
-			opp-hz = /bits/ 64 <298598400>;
-			opp-microvolt = <1100000 1045000 1650000>;
-			clock-latency-ns = <20>;
-		};
-		opp-398131200 {
-			opp-hz = /bits/ 64 <398131200>;
-			opp-microvolt = <1300000 1235000 1650000>;
-			clock-latency-ns = <20>;
-		};
-	};
-};
diff --git a/arch/arm/boot/dts/intel/pxa/pxa27x.dtsi b/arch/arm/boot/dts/intel/pxa/pxa27x.dtsi
deleted file mode 100644
index a2cbfb3be609..000000000000
--- a/arch/arm/boot/dts/intel/pxa/pxa27x.dtsi
+++ /dev/null
@@ -1,188 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* The pxa3xx skeleton simply augments the 2xx version */
-#include "pxa2xx.dtsi"
-#include "dt-bindings/clock/pxa-clock.h"
-
-/ {
-	model = "Marvell PXA27x familiy SoC";
-	compatible = "marvell,pxa27x";
-
-	pxabus {
-		pdma: dma-controller at 40000000 {
-			compatible = "marvell,pdma-1.0";
-			reg = <0x40000000 0x10000>;
-			interrupts = <25>;
-			#dma-cells = <2>;
-			/* For backwards compatibility: */
-			#dma-channels = <32>;
-			dma-channels = <32>;
-			#dma-requests = <75>;
-			dma-requests = <75>;
-			status = "okay";
-		};
-
-		pxairq: interrupt-controller at 40d00000 {
-			marvell,intc-priority;
-			marvell,intc-nr-irqs = <34>;
-		};
-
-		pinctrl: pinctrl at 40e00000 {
-			reg = <0x40e00054 0x20 0x40e0000c 0xc 0x40e0010c 4
-			       0x40f00020 0x10>;
-			compatible = "marvell,pxa27x-pinctrl";
-		};
-
-		gpio: gpio at 40e00000 {
-			compatible = "intel,pxa27x-gpio";
-			gpio-ranges = <&pinctrl 0 0 128>;
-			clocks = <&clks CLK_NONE>;
-		};
-
-		usb0: usb at 4c000000 {
-			compatible = "marvell,pxa-ohci";
-			reg = <0x4c000000 0x10000>;
-			interrupts = <3>;
-			clocks = <&clks CLK_USBHOST>;
-			status = "disabled";
-		};
-
-		pwm0: pwm at 40b00000 {
-			compatible = "marvell,pxa270-pwm", "marvell,pxa250-pwm";
-			reg = <0x40b00000 0x10>;
-			#pwm-cells = <1>;
-			clocks = <&clks CLK_PWM0>;
-		};
-
-		pwm1: pwm at 40b00010 {
-			compatible = "marvell,pxa270-pwm", "marvell,pxa250-pwm";
-			reg = <0x40b00010 0x10>;
-			#pwm-cells = <1>;
-			clocks = <&clks CLK_PWM1>;
-		};
-
-		pwm2: pwm at 40c00000 {
-			compatible = "marvell,pxa270-pwm", "marvell,pxa250-pwm";
-			reg = <0x40c00000 0x10>;
-			#pwm-cells = <1>;
-			clocks = <&clks CLK_PWM0>;
-		};
-
-		pwm3: pwm at 40c00010 {
-			compatible = "marvell,pxa270-pwm", "marvell,pxa250-pwm";
-			reg = <0x40c00010 0x10>;
-			#pwm-cells = <1>;
-			clocks = <&clks CLK_PWM1>;
-		};
-
-		pwri2c: i2c at 40f00180 {
-			compatible = "mrvl,pxa-i2c";
-			reg = <0x40f00180 0x24>;
-			interrupts = <6>;
-			clocks = <&clks CLK_PWRI2C>;
-			#address-cells = <0x1>;
-			#size-cells = <0>;
-			status = "disabled";
-		};
-
-		pxa27x_udc: udc at 40600000 {
-			compatible = "marvell,pxa270-udc";
-			reg = <0x40600000 0x10000>;
-			interrupts = <11>;
-			clocks = <&clks CLK_USB>;
-			status = "disabled";
-		};
-
-		keypad: keypad at 41500000 {
-			compatible = "marvell,pxa27x-keypad";
-			reg = <0x41500000 0x4c>;
-			interrupts = <4>;
-			clocks = <&clks CLK_KEYPAD>;
-			status = "disabled";
-		};
-
-		pxa_camera: imaging at 50000000 {
-			compatible = "marvell,pxa270-qci";
-			reg = <0x50000000 0x1000>;
-			interrupts = <33>;
-			dmas = <&pdma 68 0	/* Y channel */
-				&pdma 69 0	/* U channel */
-				&pdma 70 0>;	/* V channel */
-			dma-names = "CI_Y", "CI_U", "CI_V";
-
-			clocks = <&clks CLK_CAMERA>;
-			clock-names = "ciclk";
-			clock-frequency = <5000000>;
-			clock-output-names = "qci_mclk";
-
-			status = "disabled";
-		};
-
-		rtc at 40900000 {
-			clocks = <&clks CLK_OSC32k768>;
-		};
-	};
-
-	clocks {
-	       /*
-		* The muxing of external clocks/internal dividers for osc* clock
-		* sources has been hidden under the carpet by now.
-		*/
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		clks: pxa2xx_clks at 41300004 {
-			compatible = "marvell,pxa270-clocks";
-			#clock-cells = <1>;
-			status = "okay";
-		};
-	};
-
-	timer at 40a00000 {
-		compatible = "marvell,pxa-timer";
-		reg = <0x40a00000 0x20>;
-		interrupts = <26>;
-		clocks = <&clks CLK_OSTIMER>;
-		status = "okay";
-	};
-
-	pxa270_opp_table: opp_table0 {
-		compatible = "operating-points-v2";
-
-		opp-104000000 {
-			opp-hz = /bits/ 64 <104000000>;
-			opp-microvolt = <900000 900000 1705000>;
-			clock-latency-ns = <20>;
-		};
-		opp-156000000 {
-			opp-hz = /bits/ 64 <156000000>;
-			opp-microvolt = <1000000 1000000 1705000>;
-			clock-latency-ns = <20>;
-		};
-		opp-208000000 {
-			opp-hz = /bits/ 64 <208000000>;
-			opp-microvolt = <1180000 1180000 1705000>;
-			clock-latency-ns = <20>;
-		};
-		opp-312000000 {
-			opp-hz = /bits/ 64 <312000000>;
-			opp-microvolt = <1250000 1250000 1705000>;
-			clock-latency-ns = <20>;
-		};
-		opp-416000000 {
-			opp-hz = /bits/ 64 <416000000>;
-			opp-microvolt = <1350000 1350000 1705000>;
-			clock-latency-ns = <20>;
-		};
-		opp-520000000 {
-			opp-hz = /bits/ 64 <520000000>;
-			opp-microvolt = <1450000 1450000 1705000>;
-			clock-latency-ns = <20>;
-		};
-		opp-624000000 {
-			opp-hz = /bits/ 64 <624000000>;
-			opp-microvolt = <1550000 1550000 1705000>;
-			clock-latency-ns = <20>;
-		};
-	};
-};
diff --git a/arch/arm/boot/dts/marvell/armada-380.dtsi b/arch/arm/boot/dts/marvell/armada-380.dtsi
deleted file mode 100644
index e94f22b0e9b5..000000000000
--- a/arch/arm/boot/dts/marvell/armada-380.dtsi
+++ /dev/null
@@ -1,148 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
-/*
- * Device Tree Include file for Marvell Armada 380 SoC.
- *
- * Copyright (C) 2014 Marvell
- *
- * Lior Amsalem <alior at marvell.com>
- * Gregory CLEMENT <gregory.clement at free-electrons.com>
- * Thomas Petazzoni <thomas.petazzoni at free-electrons.com>
- */
-
-#include "armada-38x.dtsi"
-
-/ {
-	model = "Marvell Armada 380 family SoC";
-	compatible = "marvell,armada380";
-
-	cpus {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		enable-method = "marvell,armada-380-smp";
-
-		cpu at 0 {
-			device_type = "cpu";
-			compatible = "arm,cortex-a9";
-			reg = <0>;
-		};
-	};
-
-	soc {
-		internal-regs {
-			pinctrl at 18000 {
-				compatible = "marvell,mv88f6810-pinctrl";
-			};
-		};
-
-		pcie {
-			compatible = "marvell,armada-370-pcie";
-			status = "disabled";
-			device_type = "pci";
-
-			#address-cells = <3>;
-			#size-cells = <2>;
-
-			msi-parent = <&mpic>;
-			bus-range = <0x00 0xff>;
-
-			ranges =
-			       <0x82000000 0 0x80000 MBUS_ID(0xf0, 0x01) 0x80000 0 0x00002000
-				0x82000000 0 0x40000 MBUS_ID(0xf0, 0x01) 0x40000 0 0x00002000
-				0x82000000 0 0x44000 MBUS_ID(0xf0, 0x01) 0x44000 0 0x00002000
-				0x82000000 0 0x48000 MBUS_ID(0xf0, 0x01) 0x48000 0 0x00002000
-				0x82000000 0x1 0     MBUS_ID(0x08, 0xe8) 0 1 0 /* Port 0 MEM */
-				0x81000000 0x1 0     MBUS_ID(0x08, 0xe0) 0 1 0 /* Port 0 IO  */
-				0x82000000 0x2 0     MBUS_ID(0x04, 0xe8) 0 1 0 /* Port 1 MEM */
-				0x81000000 0x2 0     MBUS_ID(0x04, 0xe0) 0 1 0 /* Port 1 IO  */
-				0x82000000 0x3 0     MBUS_ID(0x04, 0xd8) 0 1 0 /* Port 2 MEM */
-				0x81000000 0x3 0     MBUS_ID(0x04, 0xd0) 0 1 0 /* Port 2 IO  */>;
-
-			/* x1 port */
-			pcie at 1,0 {
-				device_type = "pci";
-				assigned-addresses = <0x82000800 0 0x80000 0 0x2000>;
-				reg = <0x0800 0 0 0 0>;
-				#address-cells = <3>;
-				#size-cells = <2>;
-				interrupt-names = "intx";
-				interrupts-extended = <&gic GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
-				#interrupt-cells = <1>;
-				ranges = <0x82000000 0 0 0x82000000 0x1 0 1 0
-					  0x81000000 0 0 0x81000000 0x1 0 1 0>;
-				bus-range = <0x00 0xff>;
-				interrupt-map-mask = <0 0 0 7>;
-				interrupt-map = <0 0 0 1 &pcie1_intc 0>,
-						<0 0 0 2 &pcie1_intc 1>,
-						<0 0 0 3 &pcie1_intc 2>,
-						<0 0 0 4 &pcie1_intc 3>;
-				marvell,pcie-port = <0>;
-				marvell,pcie-lane = <0>;
-				clocks = <&gateclk 8>;
-				status = "disabled";
-
-				pcie1_intc: interrupt-controller {
-					interrupt-controller;
-					#interrupt-cells = <1>;
-				};
-			};
-
-			/* x1 port */
-			pcie at 2,0 {
-				device_type = "pci";
-				assigned-addresses = <0x82001000 0 0x40000 0 0x2000>;
-				reg = <0x1000 0 0 0 0>;
-				#address-cells = <3>;
-				#size-cells = <2>;
-				interrupt-names = "intx";
-				interrupts-extended = <&gic GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
-				#interrupt-cells = <1>;
-				ranges = <0x82000000 0 0 0x82000000 0x2 0 1 0
-					  0x81000000 0 0 0x81000000 0x2 0 1 0>;
-				bus-range = <0x00 0xff>;
-				interrupt-map-mask = <0 0 0 7>;
-				interrupt-map = <0 0 0 1 &pcie2_intc 0>,
-						<0 0 0 2 &pcie2_intc 1>,
-						<0 0 0 3 &pcie2_intc 2>,
-						<0 0 0 4 &pcie2_intc 3>;
-				marvell,pcie-port = <1>;
-				marvell,pcie-lane = <0>;
-				clocks = <&gateclk 5>;
-				status = "disabled";
-
-				pcie2_intc: interrupt-controller {
-					interrupt-controller;
-					#interrupt-cells = <1>;
-				};
-			};
-
-			/* x1 port */
-			pcie at 3,0 {
-				device_type = "pci";
-				assigned-addresses = <0x82001800 0 0x44000 0 0x2000>;
-				reg = <0x1800 0 0 0 0>;
-				#address-cells = <3>;
-				#size-cells = <2>;
-				interrupt-names = "intx";
-				interrupts-extended = <&gic GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
-				#interrupt-cells = <1>;
-				ranges = <0x82000000 0 0 0x82000000 0x3 0 1 0
-					  0x81000000 0 0 0x81000000 0x3 0 1 0>;
-				bus-range = <0x00 0xff>;
-				interrupt-map-mask = <0 0 0 7>;
-				interrupt-map = <0 0 0 1 &pcie3_intc 0>,
-						<0 0 0 2 &pcie3_intc 1>,
-						<0 0 0 3 &pcie3_intc 2>,
-						<0 0 0 4 &pcie3_intc 3>;
-				marvell,pcie-port = <2>;
-				marvell,pcie-lane = <0>;
-				clocks = <&gateclk 6>;
-				status = "disabled";
-
-				pcie3_intc: interrupt-controller {
-					interrupt-controller;
-					#interrupt-cells = <1>;
-				};
-			};
-		};
-	};
-};
diff --git a/arch/arm64/boot/dts/marvell/armada-7020.dtsi b/arch/arm64/boot/dts/marvell/armada-7020.dtsi
deleted file mode 100644
index 570f901b4f4a..000000000000
--- a/arch/arm64/boot/dts/marvell/armada-7020.dtsi
+++ /dev/null
@@ -1,10 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
-/*
- * Copyright (C) 2016 Marvell Technology Group Ltd.
- *
- * Device Tree file for the Armada 7020 SoC, made of an AP806 Dual and
- * one CP110.
- */
-
-#include "armada-ap806-dual.dtsi"
-#include "armada-70x0.dtsi"
diff --git a/arch/arm64/boot/dts/marvell/armada-8020.dtsi b/arch/arm64/boot/dts/marvell/armada-8020.dtsi
deleted file mode 100644
index b6fc18876093..000000000000
--- a/arch/arm64/boot/dts/marvell/armada-8020.dtsi
+++ /dev/null
@@ -1,20 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
-/*
- * Copyright (C) 2016 Marvell Technology Group Ltd.
- *
- * Device Tree file for the Armada 8020 SoC, made of an AP806 Dual and
- * two CP110.
- */
-
-#include "armada-ap806-dual.dtsi"
-#include "armada-80x0.dtsi"
-
-/* The RTC requires external oscillator. But on Aramda 80x0, the RTC clock
- * in CP master is not connected (by package) to the oscillator. So
- * disable it. However, the RTC clock in CP slave is connected to the
- * oscillator so this one is let enabled.
- */
-
-&cp0_rtc {
-	status = "disabled";
-};
diff --git a/arch/arm64/boot/dts/marvell/armada-ap806-dual.dtsi b/arch/arm64/boot/dts/marvell/armada-ap806-dual.dtsi
deleted file mode 100644
index 82f4dedfc25e..000000000000
--- a/arch/arm64/boot/dts/marvell/armada-ap806-dual.dtsi
+++ /dev/null
@@ -1,60 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
-/*
- * Copyright (C) 2016 Marvell Technology Group Ltd.
- *
- * Device Tree file for Marvell Armada AP806.
- */
-
-#include "armada-ap806.dtsi"
-
-/ {
-	cpus {
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		cpu0: cpu at 0 {
-			device_type = "cpu";
-			compatible = "arm,cortex-a72";
-			reg = <0x000>;
-			enable-method = "psci";
-			#cooling-cells = <2>;
-			clocks = <&cpu_clk 0>;
-			i-cache-size = <0xc000>;
-			i-cache-line-size = <64>;
-			i-cache-sets = <256>;
-			d-cache-size = <0x8000>;
-			d-cache-line-size = <64>;
-			d-cache-sets = <256>;
-			next-level-cache = <&l2>;
-		};
-		cpu1: cpu at 1 {
-			device_type = "cpu";
-			compatible = "arm,cortex-a72";
-			reg = <0x001>;
-			enable-method = "psci";
-			#cooling-cells = <2>;
-			clocks = <&cpu_clk 0>;
-			i-cache-size = <0xc000>;
-			i-cache-line-size = <64>;
-			i-cache-sets = <256>;
-			d-cache-size = <0x8000>;
-			d-cache-line-size = <64>;
-			d-cache-sets = <256>;
-			next-level-cache = <&l2>;
-		};
-
-		l2: l2-cache {
-			compatible = "cache";
-			cache-size = <0x80000>;
-			cache-line-size = <64>;
-			cache-sets = <512>;
-			cache-level = <2>;
-			cache-unified;
-		};
-	};
-
-	thermal-zones {
-		/delete-node/ ap-thermal-cpu2;
-		/delete-node/ ap-thermal-cpu3;
-	};
-};
diff --git a/arch/arm64/boot/dts/marvell/cn9130-db-comexpress.dtsi b/arch/arm64/boot/dts/marvell/cn9130-db-comexpress.dtsi
deleted file mode 100644
index 028496ebc473..000000000000
--- a/arch/arm64/boot/dts/marvell/cn9130-db-comexpress.dtsi
+++ /dev/null
@@ -1,96 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
-/*
- * Copyright (C) 2023 Marvell International Ltd.
- *
- * Device tree for the CN9130-DB Com Express CPU module board.
- */
-
-#include "cn9130-db.dtsi"
-
-/ {
-	model = "Marvell Armada CN9130-DB COM EXPRESS type 7 CPU module board";
-	compatible = "marvell,cn9130-cpu-module", "marvell,cn9130",
-		     "marvell,armada-ap807-quad", "marvell,armada-ap807";
-
-};
-
-&ap0_reg_sd_vccq {
-	regulator-max-microvolt = <1800000>;
-	states = <1800000 0x1 1800000 0x0>;
-	/delete-property/ gpios;
-};
-
-&cp0_reg_usb3_vbus0 {
-	/delete-property/ gpio;
-};
-
-&cp0_reg_usb3_vbus1 {
-	/delete-property/ gpio;
-};
-
-&cp0_reg_sd_vcc {
-	status = "disabled";
-};
-
-&cp0_reg_sd_vccq {
-	status = "disabled";
-};
-
-&cp0_sdhci0 {
-	status = "disabled";
-};
-
-&cp0_eth0 {
-	status = "disabled";
-};
-
-&cp0_eth1 {
-	status = "okay";
-	phy = <&phy0>;
-	phy-mode = "rgmii-id";
-};
-
-&cp0_eth2 {
-	status = "disabled";
-};
-
-&cp0_mdio {
-	status = "okay";
-	pinctrl-0 = <&cp0_ge_mdio_pins>;
-	phy0: ethernet-phy at 0 {
-		status = "okay";
-	};
-};
-
-&cp0_syscon0 {
-	cp0_pinctrl: pinctrl {
-		compatible = "marvell,cp115-standalone-pinctrl";
-
-		cp0_ge_mdio_pins: ge-mdio-pins {
-			marvell,pins = "mpp40", "mpp41";
-			marvell,function = "ge";
-		};
-	};
-};
-
-&cp0_sdhci0 {
-	status = "disabled";
-};
-
-&cp0_spi1 {
-	status = "okay";
-};
-
-&cp0_usb3_0 {
-	status = "okay";
-	usb-phy = <&cp0_usb3_0_phy0>;
-	phy-names = "usb";
-	/delete-property/ phys;
-};
-
-&cp0_usb3_1 {
-	status = "okay";
-	usb-phy = <&cp0_usb3_0_phy1>;
-	phy-names = "usb";
-	/delete-property/ phys;
-};
-- 
2.51.0



From robh at kernel.org  Fri Dec 12 12:32:11 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Fri, 12 Dec 2025 14:32:11 -0600
Subject: [PATCH] ARM: dts: nxp/imx6: Drop unused .dtsi
Message-ID: <20251212203226.458694-5-robh@kernel.org>

These .dtsi files are not included anywhere in the tree and can't be
tested.

Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
---
 .../dts/nxp/imx/imx6dl-kontron-samx6i.dtsi    | 12 -----
 .../dts/nxp/imx/imx6q-kontron-samx6i.dtsi     | 12 -----
 .../boot/dts/nxp/imx/imx6qdl-pico-dwarf.dtsi  | 45 ----------------
 .../boot/dts/nxp/imx/imx6qdl-pico-nymph.dtsi  | 54 -------------------
 4 files changed, 123 deletions(-)
 delete mode 100644 arch/arm/boot/dts/nxp/imx/imx6dl-kontron-samx6i.dtsi
 delete mode 100644 arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi
 delete mode 100644 arch/arm/boot/dts/nxp/imx/imx6qdl-pico-dwarf.dtsi
 delete mode 100644 arch/arm/boot/dts/nxp/imx/imx6qdl-pico-nymph.dtsi

diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-kontron-samx6i.dtsi b/arch/arm/boot/dts/nxp/imx/imx6dl-kontron-samx6i.dtsi
deleted file mode 100644
index 5a9b819d7ee8..000000000000
--- a/arch/arm/boot/dts/nxp/imx/imx6dl-kontron-samx6i.dtsi
+++ /dev/null
@@ -1,12 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0 OR X11
-/*
- * Copyright 2019 (C) Pengutronix, Marco Felsch <kernel at pengutronix.de>
- */
-
-#include "imx6dl.dtsi"
-#include "imx6qdl-kontron-samx6i.dtsi"
-
-/ {
-	model = "Kontron SMARC-sAMX6i Dual-Lite/Solo";
-	compatible = "kontron,imx6dl-samx6i", "fsl,imx6dl";
-};
diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi b/arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi
deleted file mode 100644
index e76963436079..000000000000
--- a/arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi
+++ /dev/null
@@ -1,12 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0 OR X11
-/*
- * Copyright 2019 (C) Pengutronix, Marco Felsch <kernel at pengutronix.de>
- */
-
-#include "imx6q.dtsi"
-#include "imx6qdl-kontron-samx6i.dtsi"
-
-/ {
-	model = "Kontron SMARC-sAMX6i Quad/Dual";
-	compatible = "kontron,imx6q-samx6i", "fsl,imx6q";
-};
diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-pico-dwarf.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-pico-dwarf.dtsi
deleted file mode 100644
index 3a968782e854..000000000000
--- a/arch/arm/boot/dts/nxp/imx/imx6qdl-pico-dwarf.dtsi
+++ /dev/null
@@ -1,45 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+ OR MIT
-//
-// Copyright 2017 NXP
-
-#include "imx6qdl-pico.dtsi"
-
-/ {
-	leds {
-		compatible = "gpio-leds";
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_gpio_leds>;
-
-		led {
-			label = "gpio-led";
-			gpios = <&gpio5 31 GPIO_ACTIVE_HIGH>;
-		};
-	};
-
-};
-
-&i2c1 {
-	mpl3115 at 60 {
-		compatible = "fsl,mpl3115";
-		reg = <0x60>;
-	};
-};
-
-&i2c2 {
-	io-expander at 25 {
-		compatible = "nxp,pca9554";
-		reg = <0x25>;
-		gpio-controller;
-		#gpio-cells = <2>;
-		#interrupt-cells = <2>;
-	};
-
-};
-
-&iomuxc {
-	pinctrl_gpio_leds: gpioledsgrp {
-		fsl,pins = <
-			MX6QDL_PAD_CSI0_DAT13__GPIO5_IO31	0x1b0b0
-		>;
-	};
-};
diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-pico-nymph.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-pico-nymph.dtsi
deleted file mode 100644
index 3d56a4216448..000000000000
--- a/arch/arm/boot/dts/nxp/imx/imx6qdl-pico-nymph.dtsi
+++ /dev/null
@@ -1,54 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+ OR MIT
-
-#include "imx6qdl-pico.dtsi"
-
-/ {
-	leds {
-		compatible = "gpio-leds";
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_gpio_leds>;
-
-		led {
-			label = "gpio-led";
-			gpios = <&gpio5 31 GPIO_ACTIVE_HIGH>;
-		};
-	};
-
-};
-
-&i2c1 {
-	adc at 52 {
-		compatible = "ti,adc081c";
-		reg = <0x52>;
-		vref-supply = <&reg_2p5v>;
-	};
-};
-
-&i2c2 {
-	io-expander at 25 {
-		compatible = "nxp,pca9554";
-		reg = <0x25>;
-		gpio-controller;
-		#gpio-cells = <2>;
-		#interrupt-cells = <2>;
-	};
-};
-
-&i2c3 {
-	rtc at 68 {
-		compatible = "dallas,ds1337";
-		reg = <0x68>;
-	};
-};
-
-&pcie {
-	status = "okay";
-};
-
-&iomuxc {
-	pinctrl_gpio_leds: gpioledsgrp {
-		fsl,pins = <
-			MX6QDL_PAD_CSI0_DAT13__GPIO5_IO31	0x1b0b0
-		>;
-	};
-};
-- 
2.51.0



From robh at kernel.org  Fri Dec 12 12:32:13 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Fri, 12 Dec 2025 14:32:13 -0600
Subject: [PATCH] ARM: dts: samsung: Drop s3c6400.dtsi
Message-ID: <20251212203226.458694-7-robh@kernel.org>

This .dtsi file is not included anywhere in the tree and can't be
tested.

Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
---
 arch/arm/boot/dts/samsung/s3c6400.dtsi | 38 --------------------------
 1 file changed, 38 deletions(-)
 delete mode 100644 arch/arm/boot/dts/samsung/s3c6400.dtsi

diff --git a/arch/arm/boot/dts/samsung/s3c6400.dtsi b/arch/arm/boot/dts/samsung/s3c6400.dtsi
deleted file mode 100644
index 7cc785a63866..000000000000
--- a/arch/arm/boot/dts/samsung/s3c6400.dtsi
+++ /dev/null
@@ -1,38 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Samsung's S3C6400 SoC device tree source
- *
- * Copyright (c) 2013 Tomasz Figa <tomasz.figa at gmail.com>
- *
- * Samsung's S3C6400 SoC device nodes are listed in this file. S3C6400
- * based board files can include this file and provide values for board specific
- * bindings.
- *
- * Note: This file does not include device nodes for all the controllers in
- * S3C6400 SoC. As device tree coverage for S3C6400 increases, additional
- * nodes can be added to this file.
- */
-
-#include "s3c64xx.dtsi"
-
-/ {
-	compatible = "samsung,s3c6400";
-};
-
-&vic0 {
-	valid-mask = <0xfffffe1f>;
-	valid-wakeup-mask = <0x00200004>;
-};
-
-&vic1 {
-	valid-mask = <0xffffffff>;
-	valid-wakeup-mask = <0x53020000>;
-};
-
-&soc {
-	clocks: clock-controller at 7e00f000 {
-		compatible = "samsung,s3c6400-clock";
-		reg = <0x7e00f000 0x1000>;
-		#clock-cells = <1>;
-	};
-};
-- 
2.51.0



From robh at kernel.org  Fri Dec 12 12:32:14 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Fri, 12 Dec 2025 14:32:14 -0600
Subject: [PATCH] ARM: dts: microchip: Drop usb_a9g20-dab-mmx.dtsi
Message-ID: <20251212203226.458694-8-robh@kernel.org>

This .dtsi file is not included anywhere in the tree and can't be
tested.

Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
---
 .../boot/dts/microchip/usb_a9g20-dab-mmx.dtsi | 93 -------------------
 1 file changed, 93 deletions(-)
 delete mode 100644 arch/arm/boot/dts/microchip/usb_a9g20-dab-mmx.dtsi

diff --git a/arch/arm/boot/dts/microchip/usb_a9g20-dab-mmx.dtsi b/arch/arm/boot/dts/microchip/usb_a9g20-dab-mmx.dtsi
deleted file mode 100644
index 5b1d80c0ab26..000000000000
--- a/arch/arm/boot/dts/microchip/usb_a9g20-dab-mmx.dtsi
+++ /dev/null
@@ -1,93 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * calao-dab-mmx.dtsi - Device Tree Include file for Calao DAB-MMX Daughter Board
- *
- * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.com>
- */
-
-/ {
-	ahb {
-		apb {
-			usart1: serial at fffb4000 {
-				status = "okay";
-			};
-
-			usart3: serial at fffd0000 {
-				status = "okay";
-			};
-		};
-	};
-
-	i2c-gpio at 0 {
-		status = "okay";
-	};
-
-	leds {
-		compatible = "gpio-leds";
-
-		user_led1 {
-			label = "user_led1";
-			gpios = <&pioB 20 GPIO_ACTIVE_LOW>;
-		};
-
-/*
-* led already used by mother board but active as high
-*		user_led2 {
-*			label = "user_led2";
-*			gpios = <&pioB 21 GPIO_ACTIVE_LOW>;
-*		};
-*/
-		user_led3 {
-			label = "user_led3";
-			gpios = <&pioB 22 GPIO_ACTIVE_LOW>;
-		};
-
-		user_led4 {
-			label = "user_led4";
-			gpios = <&pioB 23 GPIO_ACTIVE_LOW>;
-		};
-
-		red {
-			label = "red";
-			gpios = <&pioB 24 GPIO_ACTIVE_LOW>;
-		};
-
-		orange {
-			label = "orange";
-			gpios = <&pioB 30 GPIO_ACTIVE_LOW>;
-		};
-
-		green {
-			label = "green";
-			gpios = <&pioB 31 GPIO_ACTIVE_LOW>;
-		};
-	};
-
-	gpio_keys {
-		compatible = "gpio-keys";
-
-		button-user-pb1 {
-			label = "user_pb1";
-			gpios = <&pioB 25 GPIO_ACTIVE_LOW>;
-			linux,code = <0x100>;
-		};
-
-		button-user-pb2 {
-			label = "user_pb2";
-			gpios = <&pioB 13 GPIO_ACTIVE_LOW>;
-			linux,code = <0x101>;
-		};
-
-		button-user-pb3 {
-			label = "user_pb3";
-			gpios = <&pioA 26 GPIO_ACTIVE_LOW>;
-			linux,code = <0x102>;
-		};
-
-		button-user-pb4 {
-			label = "user_pb4";
-			gpios = <&pioC 9 GPIO_ACTIVE_LOW>;
-			linux,code = <0x103>;
-		};
-	};
-};
-- 
2.51.0



From robin.murphy at arm.com  Fri Dec 12 12:36:25 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Fri, 12 Dec 2025 20:36:25 +0000
Subject: [PATCH V6 1/4] iommu/tegra241-cmdqv: Decouple driver from ACPI
In-Reply-To: <aTxxBdcY4hODXcdu@nvidia.com>
References: <20251212060803.1712637-1-amhetre@nvidia.com>
 <20251212060803.1712637-2-amhetre@nvidia.com>
 <54fce1f8-7675-4351-b292-0009b2e8c599@arm.com> <aTxxBdcY4hODXcdu@nvidia.com>
Message-ID: <104441bd-1284-4147-873a-f94c91788609@arm.com>

On 12/12/2025 7:46 pm, Nicolin Chen wrote:
> On Fri, Dec 12, 2025 at 12:01:41PM +0000, Robin Murphy wrote:
>>> @@ -4542,7 +4542,7 @@ static void acpi_smmu_dsdt_probe_tegra241_cmdqv(struct acpi_iort_node *node,
>>>    	adev = acpi_dev_get_first_match_dev("NVDA200C", uid, -1);
>>>    	if (adev) {
>>>    		/* Tegra241 CMDQV driver is responsible for put_device() */
>>
>> Don't we need to bring the put_device(adev) out to this level, since
>> impl_dev is now something else that AFAICS we are *not* taking a new
>> reference on (and thus should not be putting either)?
> 
> Ah, right! We are using the platform device now.
> 
>>> -		smmu->impl_dev = &adev->dev;
>>> +		smmu->impl_dev = acpi_get_first_physical_node(adev);
>>>    		smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
>>>    		dev_info(smmu->dev, "found companion CMDQV device: %s\n",
>>>    			 dev_name(smmu->impl_dev));
> 
> I think we should squash this:

Ack, it occurred to me shortly after sending that in fact it's good to 
still hold our own reference on impl_dev itself, as we're not relying on 
a bound driver to hold one for us.

Cheers,
Robin.

> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index 0c98be3135c63..88625e3c27a65 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -5280,10 +5280,11 @@ static void acpi_smmu_dsdt_probe_tegra241_cmdqv(struct acpi_iort_node *node,
>   	adev = acpi_dev_get_first_match_dev("NVDA200C", uid, -1);
>   	if (adev) {
>   		/* Tegra241 CMDQV driver is responsible for put_device() */
> -		smmu->impl_dev = acpi_get_first_physical_node(adev);
> +		smmu->impl_dev = get_device(acpi_get_first_physical_node(adev));
>   		smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
>   		dev_info(smmu->dev, "found companion CMDQV device: %s\n",
>   			 dev_name(smmu->impl_dev));
> +		acpi_dev_put(adev);
>   	}
>   	kfree(uid);
>   }
> 
> Thanks
> Nicolin



From detlev.casanova at collabora.com  Fri Dec 12 12:49:14 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Fri, 12 Dec 2025 15:49:14 -0500
Subject: [PATCH v3 01/15] media: uapi: HEVC: Add
 v4l2_ctrl_hevc_ext_sps_[ls]t_rps controls
In-Reply-To: <a46d28aab764afcf3feab29df0fd1793bfe27c52.camel@collabora.com>
References: <20251022162459.271603-1-detlev.casanova@collabora.com>
 <20251022162459.271603-2-detlev.casanova@collabora.com>
 <a46d28aab764afcf3feab29df0fd1793bfe27c52.camel@collabora.com>
Message-ID: <34a5dade-cef1-4c2b-a031-c1bccdf5c134@collabora.com>

Hi Nicolas,

On 12/10/25 15:03, Nicolas Dufresne wrote:
> Hi,
>
> Le mercredi 22 octobre 2025 ? 12:22 -0400, Detlev Casanova a ?crit?:
>> Some hardware (e.g.: Rockchip's rk3588 hevc decoder) need the
>> long and short term reference information for HEVC decoding.
> That's seems a bit short and incomplete. My understanding is that the decoder on
> this hardware needs to full parse the slice headers, and cannot be passed with
> the slice information. It also does not implement a a skip method similar to
> Hantro.
>
> So in short, I think the justification for this API is that these parameters are
> needed to fully parse HEVC slice headers. You should perhaps say that similar
> paramters ares passed in Vulkan Video API ?
Yes, I will clarify
>> Add controls to provide it as the raw data form the stream.
>>
>> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
>> ---
>>  ?.../media/v4l/ext-ctrls-codec-stateless.rst?? | 114 ++++++++++++++++++
>>  ?.../media/v4l/videodev2.h.rst.exceptions????? |?? 2 +
>>  ?.../media/v4l/vidioc-queryctrl.rst??????????? |? 12 ++
>>  ?3 files changed, 128 insertions(+)
>>
>> diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst
>> index 0da635691fdc..bb6772cf3cee 100644
>> --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst
>> +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst
>> @@ -2958,6 +2958,120 @@ This structure contains all loop filter related parameters. See sections
>>  ?????? - 0x00000004
>>  ?????? -
>>   
>> +``V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS (struct)``
>> +??? Specifies the list of Long-Term reference sets parameters from the SPS.
>> +??? These parameters are defined according to :ref:`hevc`.
>> +??? They are described in section 7.4.3.2.1 "General sequence parameter set
>> +??? RBSP semantics" of the specification.
>> +??? This control is a dynamically sized 1-dimensional array,
>> +??? V4L2_CTRL_FLAG_DYNAMIC_ARRAY flag must be set when using it.
> Can we making a bit clearer that this is a subset of the SPS (perhaps use the
> term subset). And this is user to extend another control (mention this other
> control) ?
>
>> +
>> +.. c:type:: v4l2_ctrl_hevc_ext_sps_lt_rps
>> +
>> +.. cssclass:: longtable
>> +
>> +.. flat-table:: struct v4l2_ctrl_hevc_ext_sps_lt_rps
>> +??? :header-rows:? 0
>> +??? :stub-columns: 0
>> +??? :widths:?????? 1 1 2
>> +
>> +??? * - __u16
>> +????? - ``lt_ref_pic_poc_lsb_sps``
>> +????? - Long term reference picture order count as described in section 7.4.3.2.1
>> +??????? "General sequence parameter set RBSP semantics" of the specification.
>> +??? * - __u8
>> +????? - ``flags``
>> +????? - See :ref:`Extended Long-Term RPS Flags <hevc_ext_sps_lt_rps_flags>`
>> +
>> +.. _hevc_ext_sps_lt_rps_flags:
>> +
>> +``Extended SPS Long-Term RPS Flags``
>> +
>> +.. cssclass:: longtable
>> +
>> +.. flat-table::
>> +??? :header-rows:? 0
>> +??? :stub-columns: 0
>> +??? :widths:?????? 1 1 2
>> +
>> +??? * - ``V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_USED_LT``
>> +????? - 0x00000001
>> +????? - Specifies if the long-term reference picture is used 7.4.3.2.1 "General sequence parameter
>> +??????? set RBSP semantics" of the specification.
>> +
>> +``V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS (struct)``
>> +??? Specifies the list of Short-Term reference sets parameters from the SPS.
>> +??? These parameters are defined according to :ref:`hevc`.
>> +??? They are described in section 7.4.8 "Short-term reference picture set
>> +??? semantics" of the specification.
>> +??? This control is a dynamically sized 1-dimensional array,
>> +??? V4L2_CTRL_FLAG_DYNAMIC_ARRAY flag must be set when using it.
> D?j? vue, this is a duplicate right ?

Almost, you saw the description of the Long term sets before, this is 
for the Short term.

Only the name and specification section have changed in the description.

>> +
>> +.. c:type:: v4l2_ctrl_hevc_ext_sps_st_rps
>> +
>> +.. cssclass:: longtable
>> +
>> +.. flat-table:: struct v4l2_ctrl_hevc_ext_sps_st_rps
>> +??? :header-rows:? 0
>> +??? :stub-columns: 0
>> +??? :widths:?????? 1 1 2
>> +
>> +??? * - __u8
>> +????? - ``delta_idx_minus1``
>> +????? - Specifies the delta compare to the index. See details in section 7.4.8 "Short-term
>> +??????? reference picture set semantics" of the specification.
>> +??? * - __u8
>> +????? - ``delta_rps_sign``
>> +????? - Sign of the delta as specified in section 7.4.8 "Short-term reference picture set
>> +??????? semantics" of the specification.
>> +??? * - __u16
>> +????? - ``abs_delta_rps_minus1``
>> +????? - Absolute delta RPS as specified in section 7.4.8 "Short-term reference picture set
>> +??????? semantics" of the specification.
>> +??? * - __u8
>> +????? - ``num_negative_pics``
>> +????? - Number of short-term RPS entries that have picture order count values less than the
>> +??????? picture order count value of the current picture.
>> +??? * - __u8
>> +????? - ``num_positive_pics``
>> +????? - Number of short-term RPS entries that have picture order count values greater than the
>> +??????? picture order count value of the current picture.
>> +??? * - __u32
>> +????? - ``used_by_curr_pic``
>> +????? - Bit i specifies if short-term RPS i is used by the current picture.
>> +??? * - __u32
>> +????? - ``use_delta_flag``
>> +????? - Bit i specifies if short-term RPS i is included in the short-term RPS entries.
>> +??? * - __u16
>> +????? - ``delta_poc_s0_minus1[16]``
>> +????? - Specifies the negative picture order count delta for the i-th entry in the short-term RPS.
>> +??????? See details in section 7.4.8 "Short-term reference picture set semantics" of the
>> +??????? specification.
>> +??? * - __u16
>> +????? - ``delta_poc_s1_minus1[16]``
>> +????? - Specifies the positive picture order count delta for the i-th entry in the short-term RPS.
>> +??????? See details in section 7.4.8 "Short-term reference picture set semantics" of the
>> +??????? specification.
>> +??? * - __u8
>> +????? - ``flags``
>> +????? - See :ref:`Extended Short-Term RPS Flags <hevc_ext_sps_st_rps_flags>`
>> +
>> +.. _hevc_ext_sps_st_rps_flags:
>> +
>> +``Extended SPS Short-Term RPS Flags``
>> +
>> +.. cssclass:: longtable
>> +
>> +.. flat-table::
>> +??? :header-rows:? 0
>> +??? :stub-columns: 0
>> +??? :widths:?????? 1 1 2
>> +
>> +??? * - ``V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED``
>> +????? - 0x00000001
>> +????? - Specifies if the short-term RPS is predicted from another short term RPS. See details in
>> +??????? section 7.4.8 "Short-term reference picture set semantics" of the specification.
>> +
>>  ?.. _v4l2-codec-stateless-av1:
>>   
>>  ?``V4L2_CID_STATELESS_AV1_SEQUENCE (struct)``
>> diff --git a/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions b/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions
>> index 35d3456cc812..1663fdf8444c 100644
>> --- a/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions
>> +++ b/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions
>> @@ -149,6 +149,8 @@ replace symbol V4L2_CTRL_TYPE_H264_DECODE_PARAMS :c:type:`v4l2_ctrl_type`
>>  ?replace symbol V4L2_CTRL_TYPE_HEVC_SPS :c:type:`v4l2_ctrl_type`
>>  ?replace symbol V4L2_CTRL_TYPE_HEVC_PPS :c:type:`v4l2_ctrl_type`
>>  ?replace symbol V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS :c:type:`v4l2_ctrl_type`
>> +replace symbol V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS :c:type:`v4l2_ctrl_type`
>> +replace symbol V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS :c:type:`v4l2_ctrl_type`
>>  ?replace symbol V4L2_CTRL_TYPE_AREA :c:type:`v4l2_ctrl_type`
>>  ?replace symbol V4L2_CTRL_TYPE_RECT :c:type:`v4l2_ctrl_type`
>>  ?replace symbol V4L2_CTRL_TYPE_FWHT_PARAMS :c:type:`v4l2_ctrl_type`
>> diff --git a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
>> index 3549417c7feb..128c044d2e3c 100644
>> --- a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
>> +++ b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
>> @@ -523,6 +523,18 @@ See also the examples in :ref:`control`.
>>  ?????? - n/a
>>  ?????? - A struct :c:type:`v4l2_ctrl_hevc_decode_params`, containing HEVC
>>  ?	decoding parameters for stateless video decoders.
>> +??? * - ``V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS``
>> +????? - n/a
>> +????? - n/a
>> +????? - n/a
>> +????? - A struct :c:type:`v4l2_ctrl_hevc_ext_sps_lt_rps`, containing HEVC
>> +	extended Long-Term RPS for stateless video decoders.
>> +??? * - ``V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS``
>> +????? - n/a
>> +????? - n/a
>> +????? - n/a
>> +????? - A struct :c:type:`v4l2_ctrl_hevc_ext_sps_st_rps`, containing HEVC
>> +	extended Short-Term RPS for stateless video decoders.
>>  ???? * - ``V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR``
>>  ?????? - n/a
>>  ?????? - n/a
> cheers,
> Nicolas


From osama.abdelkader at gmail.com  Fri Dec 12 12:50:22 2025
From: osama.abdelkader at gmail.com (Osama Abdelkader)
Date: Fri, 12 Dec 2025 21:50:22 +0100
Subject: [PATCH] dmaengine: sun4i: fix resource leak on promise allocation failure
Message-ID: <20251212205022.83482-1-osama.abdelkader@gmail.com>

When promise allocation fails in sun4i_dma_prep_dma_cyclic() or
sun4i_dma_prep_slave_sg(), the contract and already-allocated promises
are not freed, causing a resource leak.

Fix this by calling sun4i_dma_free_contract() to properly clean up
all resources before returning NULL on allocation failure.

This addresses the TODO comments that asked whether we should free
everything on error.

Signed-off-by: Osama Abdelkader <osama.abdelkader at gmail.com>
---
 drivers/dma/sun4i-dma.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/dma/sun4i-dma.c b/drivers/dma/sun4i-dma.c
index 00d2fd38d17f..d81e705ae91f 100644
--- a/drivers/dma/sun4i-dma.c
+++ b/drivers/dma/sun4i-dma.c
@@ -861,7 +861,7 @@ sun4i_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf, size_t len,
 							plength, sconfig, dir);
 
 		if (!promise) {
-			/* TODO: should we free everything? */
+			sun4i_dma_free_contract(&contract->vd);
 			return NULL;
 		}
 		promise->cfg |= endpoints;
@@ -954,8 +954,10 @@ sun4i_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 							sg_dma_len(sg),
 							sconfig, dir);
 
-		if (!promise)
-			return NULL; /* TODO: should we free everything? */
+		if (!promise) {
+			sun4i_dma_free_contract(&contract->vd);
+			return NULL;
+		}
 
 		promise->cfg |= endpoints;
 		promise->para = para;
-- 
2.43.0



From coltonlewis at google.com  Fri Dec 12 12:51:34 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Fri, 12 Dec 2025 20:51:34 +0000
Subject: [PATCH v5 10/24] KVM: arm64: Set up FGT for Partitioned PMU
In-Reply-To: <aTiPvS49uMOJEBrf@kernel.org> (message from Oliver Upton on Tue,
 9 Dec 2025 13:08:13 -0800)
Message-ID: <gsnty0n72zl5.fsf@coltonlewis-kvm.c.googlers.com>


Hi Oliver. Thanks for the speedy review.

Oliver Upton <oupton at kernel.org> writes:

> Hi Colton,

> On Tue, Dec 09, 2025 at 08:51:07PM +0000, Colton Lewis wrote:
>> In order to gain the best performance benefit from partitioning the
>> PMU, utilize fine grain traps (FEAT_FGT and FEAT_FGT2) to avoid
>> trapping common PMU register accesses by the guest to remove that
>> overhead.

>> Untrapped:
>> * PMCR_EL0
>> * PMUSERENR_EL0
>> * PMSELR_EL0
>> * PMCCNTR_EL0
>> * PMCNTEN_EL0
>> * PMINTEN_EL1
>> * PMEVCNTRn_EL0

>> These are safe to untrap because writing MDCR_EL2.HPMN as this series
>> will do limits the effect of writes to any of these registers to the
>> partition of counters 0..HPMN-1. Reads from these registers will not
>> leak information from between guests as all these registers are
>> context swapped by a later patch in this series. Reads from these
>> registers also do not leak any information about the host's hardware
>> beyond what is promised by PMUv3.

>> Trapped:
>> * PMOVS_EL0
>> * PMEVTYPERn_EL0
>> * PMCCFILTR_EL0
>> * PMICNTR_EL0
>> * PMICFILTR_EL0
>> * PMCEIDn_EL0
>> * PMMIR_EL1

>> PMOVS remains trapped so KVM can track overflow IRQs that will need to
>> be injected into the guest.

>> PMICNTR and PMIFILTR remain trapped because KVM is not handling them
>> yet.

>> PMEVTYPERn remains trapped so KVM can limit which events guests can
>> count, such as disallowing counting at EL2. PMCCFILTR and PMCIFILTR
>> are special cases of the same.

>> PMCEIDn and PMMIR remain trapped because they can leak information
>> specific to the host hardware implementation.

>> NOTE: This patch temporarily forces kvm_vcpu_pmu_is_partitioned() to
>> be false to prevent partial feature activation for easier debugging.

>> Signed-off-by: Colton Lewis <coltonlewis at google.com>
>> ---
>>   arch/arm64/include/asm/kvm_pmu.h | 33 ++++++++++++++++++++++
>>   arch/arm64/kvm/config.c          | 34 ++++++++++++++++++++--
>>   arch/arm64/kvm/pmu-direct.c      | 48 ++++++++++++++++++++++++++++++++
>>   3 files changed, 112 insertions(+), 3 deletions(-)

>> diff --git a/arch/arm64/include/asm/kvm_pmu.h  
>> b/arch/arm64/include/asm/kvm_pmu.h
>> index 8887f39c25e60..7297a697a4a62 100644
>> --- a/arch/arm64/include/asm/kvm_pmu.h
>> +++ b/arch/arm64/include/asm/kvm_pmu.h
>> @@ -96,6 +96,23 @@ u64 kvm_pmu_guest_counter_mask(struct arm_pmu *pmu);
>>   void kvm_pmu_host_counters_enable(void);
>>   void kvm_pmu_host_counters_disable(void);

>> +#if !defined(__KVM_NVHE_HYPERVISOR__)
>> +bool kvm_vcpu_pmu_is_partitioned(struct kvm_vcpu *vcpu);
>> +bool kvm_vcpu_pmu_use_fgt(struct kvm_vcpu *vcpu);
>> +#else
>> +static inline bool kvm_vcpu_pmu_is_partitioned(struct kvm_vcpu *vcpu)
>> +{
>> +	return false;
>> +}
>> +
>> +static inline bool kvm_vcpu_pmu_use_fgt(struct kvm_vcpu *vcpu)
>> +{
>> +	return false;
>> +}
>> +#endif
>> +u64 kvm_pmu_fgt_bits(void);
>> +u64 kvm_pmu_fgt2_bits(void);
>> +
>>   /*
>>    * Updates the vcpu's view of the pmu events for this cpu.
>>    * Must be called before every vcpu run after disabling interrupts, to  
>> ensure
>> @@ -135,6 +152,22 @@ static inline u64 kvm_pmu_get_counter_value(struct  
>> kvm_vcpu *vcpu,
>>   {
>>   	return 0;
>>   }
>> +static inline bool kvm_vcpu_pmu_is_partitioned(struct kvm_vcpu *vcpu)
>> +{
>> +	return false;
>> +}
>> +static inline bool kvm_vcpu_pmu_use_fgt(struct kvm_vcpu *vcpu)
>> +{
>> +	return false;
>> +}
>> +static inline u64 kvm_pmu_fgt_bits(void)
>> +{
>> +	return 0;
>> +}
>> +static inline u64 kvm_pmu_fgt2_bits(void)
>> +{
>> +	return 0;
>> +}
>>   static inline void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu,
>>   					     u64 select_idx, u64 val) {}
>>   static inline void kvm_pmu_set_counter_value_user(struct kvm_vcpu *vcpu,
>> diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
>> index 24bb3f36e9d59..064dc6aa06f76 100644
>> --- a/arch/arm64/kvm/config.c
>> +++ b/arch/arm64/kvm/config.c
>> @@ -6,6 +6,7 @@

>>   #include <linux/kvm_host.h>
>>   #include <asm/kvm_emulate.h>
>> +#include <asm/kvm_pmu.h>
>>   #include <asm/kvm_nested.h>
>>   #include <asm/sysreg.h>

>> @@ -1489,12 +1490,39 @@ static void __compute_hfgwtr(struct kvm_vcpu  
>> *vcpu)
>>   		*vcpu_fgt(vcpu, HFGWTR_EL2) |= HFGWTR_EL2_TCR_EL1;
>>   }

>> +static void __compute_hdfgrtr(struct kvm_vcpu *vcpu)
>> +{
>> +	__compute_fgt(vcpu, HDFGRTR_EL2);
>> +
>> +	if (kvm_vcpu_pmu_use_fgt(vcpu))
>> +		*vcpu_fgt(vcpu, HDFGRTR_EL2) |= kvm_pmu_fgt_bits();

> Couple of suggestions. I'd rather see this conditioned on
> kvm_vcpu_pmu_is_partitioned() and get rid of the FGT predicate. After
> all, kvm_vcpu_load_fgt() already checks for the presence of FEAT_FGT
> first.

I can use that here. I'll still need the use_fgt predicate when
programming MDCR_EL2 so I'll introduce in the later patch.

> Additionally, I'd prefer that the trap configuration is inline instead
> of done in a helper in some other file. Centralizing the FGT
> configuration here was very much intentional.

Sure I can centralize it.

> The other reason for doing this is kvm_pmu_fgt_bits() assumes a
> 'positive' trap polarity, even though there are several cases where FGTs
> have a 'negative' priority (i.e. 0 => trap).

For the bits I was concerned with they all had positive polarity, except
for the dedicated instruction counter. (Side note: Why would ARM do
this?)

IIRC the FGT setup I plugged into in previous versions of the patch had
some icky macros that accounted for polarity. They were confusing and I
didn't like the effort to understand them.

Is there a good reason not to adopt a convetion that 1 => trap for
kernel code? Reversing the negative polarities immediately before write
could be easy: Have a bitmap of the negative polarity bits to xor with
the traps we actually want.

A^0 = A (positive polarity bits)
A^1 = ~A (negative polarity bits)

> Thanks,
> Oliver


From osama.abdelkader at gmail.com  Fri Dec 12 12:52:30 2025
From: osama.abdelkader at gmail.com (Osama Abdelkader)
Date: Fri, 12 Dec 2025 21:52:30 +0100
Subject: [PATCH] arm64: hw_breakpoint: warn on invalid breakpoint length
Message-ID: <20251212205230.84606-1-osama.abdelkader@gmail.com>

Some tools (e.g. perf) incorrectly assume that breakpoints should be
sizeof(long), but this is wrong for AArch64 where breakpoints must be
4 bytes. Add a warning when we silently fix up the parameter so tool
developers can get notified.

This addresses the FIXME comment by adding diagnostic output rather
than breaking existing tools by returning -EINVAL.

Signed-off-by: Osama Abdelkader <osama.abdelkader at gmail.com>
---
 arch/arm64/kernel/hw_breakpoint.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
index ab76b36dce82..4d31842e5d91 100644
--- a/arch/arm64/kernel/hw_breakpoint.c
+++ b/arch/arm64/kernel/hw_breakpoint.c
@@ -475,11 +475,13 @@ static int arch_build_bp_info(struct perf_event *bp,
 				return -EINVAL;
 		} else if (hw->ctrl.len != ARM_BREAKPOINT_LEN_4) {
 			/*
-			 * FIXME: Some tools (I'm looking at you perf) assume
-			 *	  that breakpoints should be sizeof(long). This
-			 *	  is nonsense. For now, we fix up the parameter
-			 *	  but we should probably return -EINVAL instead.
+			 * Some tools (e.g. perf) incorrectly assume that
+			 * breakpoints should be sizeof(long). This is wrong
+			 * for AArch64 where breakpoints must be 4 bytes.
+			 * Warn the user and fix up the parameter.
 			 */
+			pr_warn_once("hw_breakpoint: invalid AArch64 breakpoint length %d,
+				fixing to 4 bytes\n", hw->ctrl.len);
 			hw->ctrl.len = ARM_BREAKPOINT_LEN_4;
 		}
 	}
-- 
2.43.0



From coltonlewis at google.com  Fri Dec 12 12:54:38 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Fri, 12 Dec 2025 20:54:38 +0000
Subject: [PATCH v5 12/24] KVM: arm64: Use physical PMSELR for PMXEVTYPER
 if partitioned
In-Reply-To: <aTiRG0I1FZzntHtH@kernel.org> (message from Oliver Upton on Tue,
 9 Dec 2025 13:14:03 -0800)
Message-ID: <gsntv7ib2zg1.fsf@coltonlewis-kvm.c.googlers.com>

Oliver Upton <oupton at kernel.org> writes:

> On Tue, Dec 09, 2025 at 08:51:09PM +0000, Colton Lewis wrote:
>> Because PMXEVTYPER is trapped and PMSELR is not, it is not appropriate
>> to use the virtual PMSELR register when it could be outdated and lead
>> to an invalid write. Use the physical register when partitioned.

>> Signed-off-by: Colton Lewis <coltonlewis at google.com>
>> ---
>>   arch/arm64/include/asm/arm_pmuv3.h | 7 ++++++-
>>   arch/arm64/kvm/sys_regs.c          | 9 +++++++--
>>   2 files changed, 13 insertions(+), 3 deletions(-)

>> diff --git a/arch/arm64/include/asm/arm_pmuv3.h  
>> b/arch/arm64/include/asm/arm_pmuv3.h
>> index 27c4d6d47da31..60600f04b5902 100644
>> --- a/arch/arm64/include/asm/arm_pmuv3.h
>> +++ b/arch/arm64/include/asm/arm_pmuv3.h
>> @@ -70,11 +70,16 @@ static inline u64 read_pmcr(void)
>>   	return read_sysreg(pmcr_el0);
>>   }

>> -static inline void write_pmselr(u32 val)
>> +static inline void write_pmselr(u64 val)
>>   {
>>   	write_sysreg(val, pmselr_el0);
>>   }

>> +static inline u64 read_pmselr(void)
>> +{
>> +	return read_sysreg(pmselr_el0);
>> +}
>> +
>>   static inline void write_pmccntr(u64 val)
>>   {
>>   	write_sysreg(val, pmccntr_el0);
>> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
>> index 0c9596325519b..2e6d907fa8af2 100644
>> --- a/arch/arm64/kvm/sys_regs.c
>> +++ b/arch/arm64/kvm/sys_regs.c
>> @@ -1199,14 +1199,19 @@ static bool writethrough_pmevtyper(struct  
>> kvm_vcpu *vcpu, struct sys_reg_params
>>   static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct  
>> sys_reg_params *p,
>>   			       const struct sys_reg_desc *r)
>>   {
>> -	u64 idx, reg;
>> +	u64 idx, reg, pmselr;

>>   	if (pmu_access_el0_disabled(vcpu))
>>   		return false;

>>   	if (r->CRn == 9 && r->CRm == 13 && r->Op2 == 1) {
>>   		/* PMXEVTYPER_EL0 */
>> -		idx = SYS_FIELD_GET(PMSELR_EL0, SEL, __vcpu_sys_reg(vcpu,  
>> PMSELR_EL0));
>> +		if (kvm_vcpu_pmu_is_partitioned(vcpu))
>> +			pmselr = read_pmselr();
>> +		else
>> +			pmselr = __vcpu_sys_reg(vcpu, PMSELR_EL0);

> This isn't preemption safe. Nor should the "if (partitioned) do X else do  
> Y" get
> open-coded throughout the shop.

Okay. I had not known the register access stuff wasn't. I'll fix that.


> I would rather this be handled with a prepatory patch that provides
> generic PMU register accessors to the rest of KVM (e.g.
> vcpu_read_pmu_reg() / vcpu_write_pmu_reg()). Internally those helpers
> can locate the vCPU's PMU registers (emulated, partitioned in-memory,
> partitioned in-CPU).

That seems like a good idea.

> Thanks,
> Oliver


From coltonlewis at google.com  Fri Dec 12 13:06:53 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Fri, 12 Dec 2025 21:06:53 +0000
Subject: [PATCH v5 13/24] KVM: arm64: Writethrough trapped PMOVS register
In-Reply-To: <aTiSTODjzaLzwAPN@kernel.org> (message from Oliver Upton on Tue,
 9 Dec 2025 13:19:08 -0800)
Message-ID: <gsntsedf2yvm.fsf@coltonlewis-kvm.c.googlers.com>

Oliver Upton <oupton at kernel.org> writes:

> On Tue, Dec 09, 2025 at 08:51:10PM +0000, Colton Lewis wrote:
>> Because PMOVS remains trapped, it needs to be written through when
>> partitioned to affect PMU hardware when expected.

>> Signed-off-by: Colton Lewis <coltonlewis at google.com>
>> ---
>>   arch/arm64/include/asm/arm_pmuv3.h | 10 ++++++++++
>>   arch/arm64/kvm/sys_regs.c          | 17 ++++++++++++++++-
>>   2 files changed, 26 insertions(+), 1 deletion(-)

>> diff --git a/arch/arm64/include/asm/arm_pmuv3.h  
>> b/arch/arm64/include/asm/arm_pmuv3.h
>> index 60600f04b5902..3e25c0313263c 100644
>> --- a/arch/arm64/include/asm/arm_pmuv3.h
>> +++ b/arch/arm64/include/asm/arm_pmuv3.h
>> @@ -140,6 +140,16 @@ static inline u64 read_pmicfiltr(void)
>>   	return read_sysreg_s(SYS_PMICFILTR_EL0);
>>   }

>> +static inline void write_pmovsset(u64 val)
>> +{
>> +	write_sysreg(val, pmovsset_el0);
>> +}
>> +
>> +static inline u64 read_pmovsset(void)
>> +{
>> +	return read_sysreg(pmovsset_el0);
>> +}
>> +
>>   static inline void write_pmovsclr(u64 val)
>>   {
>>   	write_sysreg(val, pmovsclr_el0);
>> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
>> index 2e6d907fa8af2..bee892db9ca8b 100644
>> --- a/arch/arm64/kvm/sys_regs.c
>> +++ b/arch/arm64/kvm/sys_regs.c
>> @@ -1307,6 +1307,19 @@ static bool access_pminten(struct kvm_vcpu *vcpu,  
>> struct sys_reg_params *p,
>>   	return true;
>>   }

>> +static void writethrough_pmovs(struct kvm_vcpu *vcpu, struct  
>> sys_reg_params *p, bool set)
>> +{
>> +	u64 mask = kvm_pmu_accessible_counter_mask(vcpu);
>> +
>> +	if (set) {
>> +		__vcpu_rmw_sys_reg(vcpu, PMOVSSET_EL0, |=, (p->regval & mask));
>> +		write_pmovsset(p->regval & mask);
>> +	} else {
>> +		__vcpu_rmw_sys_reg(vcpu, PMOVSSET_EL0, &=, ~(p->regval & mask));
>> +		write_pmovsclr(p->regval & mask);
>> +	}

> There's only ever a single canonical guest view of a register. Either it  
> has
> been loaded onto the CPU or it is in memory, writing the value to two
> different locations is odd. What guarantees the guest context is on the
> CPU currently? And what about preemption?

My thinking here was pmovs is trapped so the "canonical" view is in
memory, but the guest still expects it to have an effect immediately.

Otherwise we would have to wait until the next load before the value
makes it to hardware. Are you okay with that latency? I'm not sure
how well that's going to work. Consider PMEVTYPER as an example. If I
don't write it to hardware immediately, a guest may expect a counter to
start counting as soon as it is written, but if it's only in memory the
counter won't start until the next load.

Echoing discussion on the previous patch, I wasn't aware preemption was
possible while servicing these register writes. I'll figure out how to
account for that.


From balejk at matfyz.cz  Fri Dec 12 13:17:12 2025
From: balejk at matfyz.cz (Karel Balej)
Date: Fri, 12 Dec 2025 22:17:12 +0100
Subject: [DONOTAPPLY RFC PATCH v2 4/4] arm64: dts:
 samsung,coreprimevelte: add wifi node
In-Reply-To: <b92172f3-10f4-470f-b90a-121ff7fea988@dujemihanovic.xyz>
References: <20251026182602.26464-1-balejk@matfyz.cz>
 <20251026182602.26464-5-balejk@matfyz.cz> <aTCv75hjdX5XvgCh@google.com>
 <DEW3NQVZ84JU.22G38WMULFZJG@matfyz.cz>
 <b92172f3-10f4-470f-b90a-121ff7fea988@dujemihanovic.xyz>
Message-ID: <DEWJTWZ6Q51B.13HQYMDJZRFWA@matfyz.cz>

Duje Mihanovi?, 2025-12-12T15:55:48+01:00:
> On 12/12/25 09:36, Karel Balej wrote:
>>>> +			};
>>>>   		};
>>>>   	};
>>>>   };
>>>> @@ -523,6 +531,13 @@ &sdh1 {
>>>>   	pinctrl-1 = <&sdh1_fast_pins_0 &sdh1_fast_pins_1 &sdh1_pins_2>;
>>>>   	bus-width = <4>;
>>>>   	non-removable;
>>>> +	#address-cells = <1>;
>>>> +	#size-cells = <0>;
>>>
>>> I wonder if this should have:
>>>
>>> 	vmmc-supply = <&ldo16>;
>>>
>>> rather than regulator-always-on above.
>> 
>> You mean ldo15 right?
>> 
>> Not having any board schematics, I don't really know what exactly the
>> regulator's purpose is. As I mentioned in the commit message, the
>> communication with the chipset seems to work even if this is disabled
>> (e. g. FW loads, networks can be scanned for,...) which doesn't seem
>> like it should be the case if this was a main power supply for the bus,
>> only actual connecting to networks doesn't work (gives
>> CONNECT_ERR_ASSOC_ERR_TIMEOUT errors).
>
> To me, this strongly suggests that the regulator powers the WiFi 
> transmitter or at least a part of it (such as the RF amp).

Something like this occurred to me too but would the chip even see the
networks if this was the case? Although you are right that it could only
power some specific part of the radio.

>> So this didn't seem too fitting for either vmmc nor vqmmc as far as I
>> understand their semantics, so I went with the regulator-always-on
>> approach to be safe.
>
> Considering the above, I'd reckon it'd be good to have the option to 
> toggle it for rfkill if anything. I'm however not sure what would be the 
> right way to do so, nor how rfkill even works, if at all, with mwifiex 
> (from what I see, the driver does not use the API).

I have experimented with rfkill here before. The chip has a specific pin
for this so I don't think handling the regulator alone would suffice.
But yes, it should certainly be associated with the rfkill if possible
so that it could be turned off to save power when the radio is disabled.

Brian, is it possible to attach the rfkill pin (and ideally this
regulator) to the wireless device solely through the device tree in some
generic way or must this be implemented in the driver? I have
experimented with the rfkill-gpio driver in the past but it appeared as
a separate rfkill device with its own controls independent of the
mwifiex device and I could only soft block both (soft blocking the
rfkill-gpio device of course had effect on the wifi though).

Regards,
K. B.


From alexandre.belloni at bootlin.com  Fri Dec 12 13:18:12 2025
From: alexandre.belloni at bootlin.com (Alexandre Belloni)
Date: Fri, 12 Dec 2025 22:18:12 +0100
Subject: [PATCH] ARM: dts: microchip: Drop usb_a9g20-dab-mmx.dtsi
In-Reply-To: <20251212203226.458694-8-robh@kernel.org>
References: <20251212203226.458694-8-robh@kernel.org>
Message-ID: <20251212211812768361f3@mail.local>

On 12/12/2025 14:32:14-0600, Rob Herring (Arm) wrote:
> This .dtsi file is not included anywhere in the tree and can't be
> tested.
> 
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>

Acked-by: Alexandre Belloni <alexandre.belloni at bootlin.com>

> ---
>  .../boot/dts/microchip/usb_a9g20-dab-mmx.dtsi | 93 -------------------
>  1 file changed, 93 deletions(-)
>  delete mode 100644 arch/arm/boot/dts/microchip/usb_a9g20-dab-mmx.dtsi
> 
> diff --git a/arch/arm/boot/dts/microchip/usb_a9g20-dab-mmx.dtsi b/arch/arm/boot/dts/microchip/usb_a9g20-dab-mmx.dtsi
> deleted file mode 100644
> index 5b1d80c0ab26..000000000000
> --- a/arch/arm/boot/dts/microchip/usb_a9g20-dab-mmx.dtsi
> +++ /dev/null
> @@ -1,93 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0-only
> -/*
> - * calao-dab-mmx.dtsi - Device Tree Include file for Calao DAB-MMX Daughter Board
> - *
> - * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.com>
> - */
> -
> -/ {
> -	ahb {
> -		apb {
> -			usart1: serial at fffb4000 {
> -				status = "okay";
> -			};
> -
> -			usart3: serial at fffd0000 {
> -				status = "okay";
> -			};
> -		};
> -	};
> -
> -	i2c-gpio at 0 {
> -		status = "okay";
> -	};
> -
> -	leds {
> -		compatible = "gpio-leds";
> -
> -		user_led1 {
> -			label = "user_led1";
> -			gpios = <&pioB 20 GPIO_ACTIVE_LOW>;
> -		};
> -
> -/*
> -* led already used by mother board but active as high
> -*		user_led2 {
> -*			label = "user_led2";
> -*			gpios = <&pioB 21 GPIO_ACTIVE_LOW>;
> -*		};
> -*/
> -		user_led3 {
> -			label = "user_led3";
> -			gpios = <&pioB 22 GPIO_ACTIVE_LOW>;
> -		};
> -
> -		user_led4 {
> -			label = "user_led4";
> -			gpios = <&pioB 23 GPIO_ACTIVE_LOW>;
> -		};
> -
> -		red {
> -			label = "red";
> -			gpios = <&pioB 24 GPIO_ACTIVE_LOW>;
> -		};
> -
> -		orange {
> -			label = "orange";
> -			gpios = <&pioB 30 GPIO_ACTIVE_LOW>;
> -		};
> -
> -		green {
> -			label = "green";
> -			gpios = <&pioB 31 GPIO_ACTIVE_LOW>;
> -		};
> -	};
> -
> -	gpio_keys {
> -		compatible = "gpio-keys";
> -
> -		button-user-pb1 {
> -			label = "user_pb1";
> -			gpios = <&pioB 25 GPIO_ACTIVE_LOW>;
> -			linux,code = <0x100>;
> -		};
> -
> -		button-user-pb2 {
> -			label = "user_pb2";
> -			gpios = <&pioB 13 GPIO_ACTIVE_LOW>;
> -			linux,code = <0x101>;
> -		};
> -
> -		button-user-pb3 {
> -			label = "user_pb3";
> -			gpios = <&pioA 26 GPIO_ACTIVE_LOW>;
> -			linux,code = <0x102>;
> -		};
> -
> -		button-user-pb4 {
> -			label = "user_pb4";
> -			gpios = <&pioC 9 GPIO_ACTIVE_LOW>;
> -			linux,code = <0x103>;
> -		};
> -	};
> -};
> -- 
> 2.51.0
> 

-- 
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From coltonlewis at google.com  Fri Dec 12 13:22:23 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Fri, 12 Dec 2025 21:22:23 +0000
Subject: [PATCH v5 15/24] KVM: arm64: Setup MDCR_EL2 to handle a
 partitioned PMU
In-Reply-To: <aTiVnI5ewoEVRztD@kernel.org> (message from Oliver Upton on Tue,
 9 Dec 2025 13:33:16 -0800)
Message-ID: <gsntpl8j2y5s.fsf@coltonlewis-kvm.c.googlers.com>

Oliver Upton <oupton at kernel.org> writes:

> On Tue, Dec 09, 2025 at 08:51:12PM +0000, Colton Lewis wrote:
>> Setup MDCR_EL2 to handle a partitioned PMU. That means calculate an
>> appropriate value for HPMN instead of the default maximum setting the
>> host allows (which implies no partition) so hardware enforces that a
>> guest will only see the counters in the guest partition.

>> Setting HPMN to a non default value means the global enable bit for
>> the host counters is now MDCR_EL2.HPME instead of the usual
>> PMCR_EL0.E. Enable the HPME bit to allow the host to count guest
>> events. Since HPME only has an effect when HPMN is set which we only
>> do for the guest, it is correct to enable it unconditionally here.

>> Unset the TPM and TPMCR bits, which trap all PMU accesses, if
>> FGT (fine grain trapping) is being used.

>> If available, set the filtering bits HPMD and HCCD to be extra sure
>> nothing in the guest counts at EL2.

>> Signed-off-by: Colton Lewis <coltonlewis at google.com>
>> ---
>>   arch/arm64/include/asm/kvm_pmu.h | 11 ++++++
>>   arch/arm64/kvm/debug.c           | 29 ++++++++++++--
>>   arch/arm64/kvm/pmu-direct.c      | 65 ++++++++++++++++++++++++++++++++
>>   3 files changed, 102 insertions(+), 3 deletions(-)

>> diff --git a/arch/arm64/include/asm/kvm_pmu.h  
>> b/arch/arm64/include/asm/kvm_pmu.h
>> index 60b8a48cad456..8b634112eded2 100644
>> --- a/arch/arm64/include/asm/kvm_pmu.h
>> +++ b/arch/arm64/include/asm/kvm_pmu.h
>> @@ -101,6 +101,9 @@ u64 kvm_pmu_guest_counter_mask(struct arm_pmu *pmu);
>>   void kvm_pmu_host_counters_enable(void);
>>   void kvm_pmu_host_counters_disable(void);

>> +u8 kvm_pmu_guest_num_counters(struct kvm_vcpu *vcpu);
>> +u8 kvm_pmu_hpmn(struct kvm_vcpu *vcpu);
>> +
>>   #if !defined(__KVM_NVHE_HYPERVISOR__)
>>   bool kvm_vcpu_pmu_is_partitioned(struct kvm_vcpu *vcpu);
>>   bool kvm_vcpu_pmu_use_fgt(struct kvm_vcpu *vcpu);
>> @@ -173,6 +176,14 @@ static inline u64 kvm_pmu_fgt2_bits(void)
>>   {
>>   	return 0;
>>   }
>> +static inline u8 kvm_pmu_guest_num_counters(struct kvm_vcpu *vcpu)
>> +{
>> +	return 0;
>> +}
>> +static inline u8 kvm_pmu_hpmn(struct kvm_vcpu *vcpu)
>> +{
>> +	return 0;
>> +}
>>   static inline void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu,
>>   					     u64 select_idx, u64 val) {}
>>   static inline void kvm_pmu_set_counter_value_user(struct kvm_vcpu *vcpu,
>> diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
>> index 3ad6b7c6e4ba7..0ab89c91e19cb 100644
>> --- a/arch/arm64/kvm/debug.c
>> +++ b/arch/arm64/kvm/debug.c
>> @@ -36,20 +36,43 @@ static int cpu_has_spe(u64 dfr0)
>>    */
>>   static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu)
>>   {
>> +	int hpmn = kvm_pmu_hpmn(vcpu);
>> +
>>   	preempt_disable();

>>   	/*
>>   	 * This also clears MDCR_EL2_E2PB_MASK and MDCR_EL2_E2TB_MASK
>>   	 * to disable guest access to the profiling and trace buffers
>>   	 */
>> -	vcpu->arch.mdcr_el2 = FIELD_PREP(MDCR_EL2_HPMN,
>> -					 *host_data_ptr(nr_event_counters));
>> +
>> +	vcpu->arch.mdcr_el2 = FIELD_PREP(MDCR_EL2_HPMN, hpmn);
>>   	vcpu->arch.mdcr_el2 |= (MDCR_EL2_TPM |
>>   				MDCR_EL2_TPMS |
>>   				MDCR_EL2_TTRF |
>>   				MDCR_EL2_TPMCR |
>>   				MDCR_EL2_TDRA |
>> -				MDCR_EL2_TDOSA);
>> +				MDCR_EL2_TDOSA |
>> +				MDCR_EL2_HPME);
>> +
>> +	if (kvm_vcpu_pmu_is_partitioned(vcpu)) {
>> +		/*
>> +		 * Filtering these should be redundant because we trap
>> +		 * all the TYPER and FILTR registers anyway and ensure
>> +		 * they filter EL2, but set the bits if they are here.
>> +		 */
>> +		if (is_pmuv3p1(read_pmuver()))
>> +			vcpu->arch.mdcr_el2 |= MDCR_EL2_HPMD;
>> +		if (is_pmuv3p5(read_pmuver()))
>> +			vcpu->arch.mdcr_el2 |= MDCR_EL2_HCCD;
>> +
>> +		/*
>> +		 * Take out the coarse grain traps if we are using
>> +		 * fine grain traps.
>> +		 */
>> +		if (kvm_vcpu_pmu_use_fgt(vcpu))
>> +			vcpu->arch.mdcr_el2 &= ~(MDCR_EL2_TPM | MDCR_EL2_TPMCR);
>> +
>> +	}

>>   	/* Is the VM being debugged by userspace? */
>>   	if (vcpu->guest_debug)
>> diff --git a/arch/arm64/kvm/pmu-direct.c b/arch/arm64/kvm/pmu-direct.c
>> index 4dd160c878862..7fb4fb5c22e2a 100644
>> --- a/arch/arm64/kvm/pmu-direct.c
>> +++ b/arch/arm64/kvm/pmu-direct.c
>> @@ -154,3 +154,68 @@ void kvm_pmu_host_counters_disable(void)
>>   	mdcr &= ~MDCR_EL2_HPME;
>>   	write_sysreg(mdcr, mdcr_el2);
>>   }

> <snip>

>> +/**
>> + * kvm_pmu_guest_num_counters() - Number of counters to show to guest
>> + * @vcpu: Pointer to struct kvm_vcpu
>> + *
>> + * Calculate the number of counters to show to the guest via
>> + * PMCR_EL0.N, making sure to respect the maximum the host allows,
>> + * which is hpmn_max if partitioned and host_max otherwise.
>> + *
>> + * Return: Valid value for PMCR_EL0.N
>> + */
>> +u8 kvm_pmu_guest_num_counters(struct kvm_vcpu *vcpu)
>> +{
>> +	u8 nr_cnt = vcpu->kvm->arch.nr_pmu_counters;
>> +	int hpmn_max = armv8pmu_hpmn_max;
>> +	u8 host_max = *host_data_ptr(nr_event_counters);
>> +
>> +	if (vcpu->kvm->arch.arm_pmu)
>> +		hpmn_max = vcpu->kvm->arch.arm_pmu->hpmn_max;
>> +
>> +	if (kvm_vcpu_pmu_is_partitioned(vcpu)) {
>> +		if (nr_cnt <= hpmn_max && nr_cnt <= host_max)
>> +			return nr_cnt;
>> +		if (hpmn_max <= host_max)
>> +			return hpmn_max;
>> +	}
>> +
>> +	if (nr_cnt <= host_max)
>> +		return nr_cnt;
>> +
>> +	return host_max;
>> +}
>> +
>> +/**
>> + * kvm_pmu_hpmn() - Calculate HPMN field value
>> + * @vcpu: Pointer to struct kvm_vcpu
>> + *
>> + * Calculate the appropriate value to set for MDCR_EL2.HPMN. If
>> + * partitioned, this is the number of counters set for the guest if
>> + * supported, falling back to hpmn_max if needed. If we are not
>> + * partitioned or can't set the implied HPMN value, fall back to the
>> + * host value.
>> + *
>> + * Return: A valid HPMN value
>> + */
>> +u8 kvm_pmu_hpmn(struct kvm_vcpu *vcpu)
>> +{
>> +	u8 nr_guest_cnt = kvm_pmu_guest_num_counters(vcpu);
>> +	int nr_guest_cnt_max = armv8pmu_hpmn_max;
>> +	u8 nr_host_cnt_max = *host_data_ptr(nr_event_counters);
>> +
>> +	if (vcpu->kvm->arch.arm_pmu)
>> +		nr_guest_cnt_max = vcpu->kvm->arch.arm_pmu->hpmn_max;
>> +
>> +	if (kvm_vcpu_pmu_is_partitioned(vcpu)) {
>> +		if (cpus_have_final_cap(ARM64_HAS_HPMN0))
>> +			return nr_guest_cnt;
>> +		else if (nr_guest_cnt > 0)
>> +			return nr_guest_cnt;
>> +		else if (nr_guest_cnt_max > 0)
>> +			return nr_guest_cnt_max;
>> +	}
>> +
>> +	return nr_host_cnt_max;
>> +}

> </snip>

> I find all of this rather confusing. It seems like you're dealing with
> sanitizing kvm->arch.nr_pmu_counters vs. the underlying implementation.
> I'm not sure why you need to do that, I would expect that we reject
> unsupported values at the time of the ioctl.

I agree it makes more sense to do the validating at the ioctl. I'll do that.

> The only thing you do need to handle is if the vCPU has migrated to an
> "unsupported" CPU, for which we already have supporting helpers. I'm too
> lazy to fetch the Arm ARM and cite architecture but I'm pretty sure an
> out-of-range HPMN has UNPREDICTABLE behavior.

It does.

> I think you just need to move the vcpu_set_unsupported_cpu() call earlier  
> in
> kvm_arch_vcpu_load().

> Taking all that into consideration:

> u8 kvm_mdcr_hpmn(struct kvm_vcpu *vcpu)
> {
> 	u8 nr_counters = *host_data_ptr(nr_event_counters);

> 	if (!kvm_vcpu_pmu_is_partitioned(vcpu) || vcpu_on_unsupported_cpu(vcpu))
> 		return nr_counters;

> 	return vcpu->kvm->arch.nr_pmu_counters;
> }

Something like that will probably work. But I also need to account for
if arch.nr_pmu_counters is 0 and we don't have HPMN0, which is also
unpredictable. I don't think I can reject that at the ioctl because we
still want to support that case. Is there any way to handle that through
vcpu_on_unsupported_cpu()?

> Thanks,
> Oliver


From coltonlewis at google.com  Fri Dec 12 13:31:46 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Fri, 12 Dec 2025 21:31:46 +0000
Subject: [PATCH v5 16/24] KVM: arm64: Account for partitioning in PMCR_EL0 access
In-Reply-To: <aTiWsAvK9krnEw7V@kernel.org> (message from Oliver Upton on Tue,
 9 Dec 2025 13:37:52 -0800)
Message-ID: <gsntms3n2xq5.fsf@coltonlewis-kvm.c.googlers.com>

Oliver Upton <oupton at kernel.org> writes:

> On Tue, Dec 09, 2025 at 08:51:13PM +0000, Colton Lewis wrote:
>> Make sure reads and writes to PMCR_EL0 conform to additional
>> constraints imposed when the PMU is partitioned.

>> Signed-off-by: Colton Lewis <coltonlewis at google.com>
>> ---
>>   arch/arm64/kvm/pmu.c      | 2 +-
>>   arch/arm64/kvm/sys_regs.c | 2 +-
>>   2 files changed, 2 insertions(+), 2 deletions(-)

>> diff --git a/arch/arm64/kvm/pmu.c b/arch/arm64/kvm/pmu.c
>> index 1fd012f8ff4a9..48b39f096fa12 100644
>> --- a/arch/arm64/kvm/pmu.c
>> +++ b/arch/arm64/kvm/pmu.c
>> @@ -877,7 +877,7 @@ u64 kvm_pmu_accessible_counter_mask(struct kvm_vcpu  
>> *vcpu)
>>   u64 kvm_vcpu_read_pmcr(struct kvm_vcpu *vcpu)
>>   {
>>   	u64 pmcr = __vcpu_sys_reg(vcpu, PMCR_EL0);
>> -	u64 n = vcpu->kvm->arch.nr_pmu_counters;
>> +	u64 n = kvm_pmu_guest_num_counters(vcpu);

> Why can't the value of vcpu->kvm->arch.nr_pmu_counters be trusted?

Similar to discussion on a previous patch, I need to move some
validation to the ioctl where it's set.

>> @@ -1360,7 +1360,7 @@ static int set_pmcr(struct kvm_vcpu *vcpu, const  
>> struct sys_reg_desc *r,
>>   	 */
>>   	if (!kvm_vm_has_ran_once(kvm) &&
>>   	    !vcpu_has_nv(vcpu)	      &&
>> -	    new_n <= kvm_arm_pmu_get_max_counters(kvm))
>> +	    new_n <= kvm_pmu_hpmn(vcpu))
>>   		kvm->arch.nr_pmu_counters = new_n;

> This is the legacy UAPI for setting the number of PMU counters by
> writing to PMCR_EL0.N.

> The 'partitioned' implementation should take a dependency on the
> SET_NR_COUNTERS attribute and reject attempts to change the value of
> PMCR_EL0.N. Just like nested.

Good! I hated making writes to PMCR_EL0.N work and only did it because
of selftests assuming it did.


> Thanks,
> Oliver


From coltonlewis at google.com  Fri Dec 12 13:57:29 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Fri, 12 Dec 2025 21:57:29 +0000
Subject: [PATCH v5 17/24] KVM: arm64: Context swap Partitioned PMU guest registers
In-Reply-To: <aTia74R74upcsMEA@kernel.org> (message from Oliver Upton on Tue,
 9 Dec 2025 13:55:59 -0800)
Message-ID: <gsntjyyr2wja.fsf@coltonlewis-kvm.c.googlers.com>

Oliver Upton <oupton at kernel.org> writes:

> On Tue, Dec 09, 2025 at 08:51:14PM +0000, Colton Lewis wrote:
>> +/**
>> + * kvm_pmu_load() - Load untrapped PMU registers
>> + * @vcpu: Pointer to struct kvm_vcpu
>> + *
>> + * Load all untrapped PMU registers from the VCPU into the PCPU. Mask
>> + * to only bits belonging to guest-reserved counters and leave
>> + * host-reserved counters alone in bitmask registers.
>> + */
>> +void kvm_pmu_load(struct kvm_vcpu *vcpu)
>> +{
>> +	struct arm_pmu *pmu;
>> +	u64 mask;
>> +	u8 i;
>> +	u64 val;
>> +

> Assert that preemption is disabled.

Will do.

>> +	/*
>> +	 * If we aren't using FGT then we are trapping everything
>> +	 * anyway, so no need to bother with the swap.
>> +	 */
>> +	if (!kvm_vcpu_pmu_use_fgt(vcpu))
>> +		return;

> Uhh... Then how do events count in this case?

> The absence of FEAT_FGT shouldn't affect the residence of the guest PMU
> context. We just need to handle the extra traps, ideally by reading the
> PMU registers directly as a fast path exit handler.

Agreed. Yeah I fixed this in my internal backports but looks like I
skipped incorperating the fix here.

>> +	pmu = vcpu->kvm->arch.arm_pmu;
>> +
>> +	for (i = 0; i < pmu->hpmn_max; i++) {
>> +		val = __vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i);
>> +		write_pmevcntrn(i, val);
>> +	}
>> +
>> +	val = __vcpu_sys_reg(vcpu, PMCCNTR_EL0);
>> +	write_pmccntr(val);
>> +
>> +	val = __vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>> +	write_pmuserenr(val);

> What about the host's value for PMUSERENR?
>> +	val = __vcpu_sys_reg(vcpu, PMSELR_EL0);
>> +	write_pmselr(val);

> PMSELR_EL0 needs to be switched late, e.g. at  
> sysreg_restore_guest_state_vhe().
> Even though the host doesn't currently use the selector-based accessor,
> I'd prefer we not load things that'd affect the host context until we're
> about to enter the guest.


There's a spot in __activate_traps_common() where the host value for
PMUSERENR is saved and PMSELR is zeroed. I stopped that branch when
partitioning because it was clobbering my loaded values, but I can
modify instead to handle these things as they should be handled.

>> +	/* Save only the stateful writable bits. */
>> +	val = __vcpu_sys_reg(vcpu, PMCR_EL0);
>> +	mask = ARMV8_PMU_PMCR_MASK &
>> +		~(ARMV8_PMU_PMCR_P | ARMV8_PMU_PMCR_C);
>> +	write_pmcr(val & mask);
>> +
>> +	/*
>> +	 * When handling these:
>> +	 * 1. Apply only the bits for guest counters (indicated by mask)
>> +	 * 2. Use the different registers for set and clear
>> +	 */
>> +	mask = kvm_pmu_guest_counter_mask(pmu);
>> +
>> +	val = __vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
>> +	write_pmcntenset(val & mask);
>> +	write_pmcntenclr(~val & mask);
>> +
>> +	val = __vcpu_sys_reg(vcpu, PMINTENSET_EL1);
>> +	write_pmintenset(val & mask);
>> +	write_pmintenclr(~val & mask);

> Is this safe? What happens if we put the PMU into an overflow condition?

It gets handled by the host same as any other PMU interrupt. Though I
remember from our conversation you don't want the latency of an
additional interrupt so I can handle that here.

>> +}
>> +
>> +/**
>> + * kvm_pmu_put() - Put untrapped PMU registers
>> + * @vcpu: Pointer to struct kvm_vcpu
>> + *
>> + * Put all untrapped PMU registers from the VCPU into the PCPU. Mask
>> + * to only bits belonging to guest-reserved counters and leave
>> + * host-reserved counters alone in bitmask registers.
>> + */
>> +void kvm_pmu_put(struct kvm_vcpu *vcpu)
>> +{
>> +	struct arm_pmu *pmu;
>> +	u64 mask;
>> +	u8 i;
>> +	u64 val;
>> +
>> +	/*
>> +	 * If we aren't using FGT then we are trapping everything
>> +	 * anyway, so no need to bother with the swap.
>> +	 */
>> +	if (!kvm_vcpu_pmu_use_fgt(vcpu))
>> +		return;
>> +
>> +	pmu = vcpu->kvm->arch.arm_pmu;
>> +
>> +	for (i = 0; i < pmu->hpmn_max; i++) {
>> +		val = read_pmevcntrn(i);
>> +		__vcpu_assign_sys_reg(vcpu, PMEVCNTR0_EL0 + i, val);
>> +	}
>> +
>> +	val = read_pmccntr();
>> +	__vcpu_assign_sys_reg(vcpu, PMCCNTR_EL0, val);
>> +
>> +	val = read_pmuserenr();
>> +	__vcpu_assign_sys_reg(vcpu, PMUSERENR_EL0, val);
>> +
>> +	val = read_pmselr();
>> +	__vcpu_assign_sys_reg(vcpu, PMSELR_EL0, val);
>> +
>> +	val = read_pmcr();
>> +	__vcpu_assign_sys_reg(vcpu, PMCR_EL0, val);
>> +
>> +	/* Mask these to only save the guest relevant bits. */
>> +	mask = kvm_pmu_guest_counter_mask(pmu);
>> +
>> +	val = read_pmcntenset();
>> +	__vcpu_assign_sys_reg(vcpu, PMCNTENSET_EL0, val & mask);
>> +
>> +	val = read_pmintenset();
>> +	__vcpu_assign_sys_reg(vcpu, PMINTENSET_EL1, val & mask);

> What if the PMU is in an overflow state at this point?

Is this a separate concern from the point above? It gets loaded back
that way and the normal interrupt machinery handles it.


From robert.jarzmik at free.fr  Fri Dec 12 13:58:16 2025
From: robert.jarzmik at free.fr (Robert Jarzmik)
Date: Fri, 12 Dec 2025 22:58:16 +0100
Subject: [PATCH] ARM: dts: intel: Drop pxa2xx
In-Reply-To: <20251212203226.458694-4-robh@kernel.org> (Rob Herring's message
	of "Fri, 12 Dec 2025 14:32:10 -0600")
References: <20251212203226.458694-4-robh@kernel.org>
Message-ID: <m2345fmkg7.fsf@free.fr>

"Rob Herring (Arm)" <robh at kernel.org> writes:

> These .dtsi files are not included anywhere in the tree and 
> can't be
> tested. They have not been touched since 2018 other than 
> clean-ups.
>
And yet, there are used by people using pxa2xx board with an DT 
support
(like the mioa701 for which a board file was never merged).

If you remove pxa25x.dtsi and pxa27x.dtsi, you might as well 
remove all
support for this architecture from the kernel, as these are the 
building
blocks needed to make it work.

That might be what should be done, I'll let Arnd and Daniel 
comment on
the future of PXA in the kernel.

Cheers.

--
Robert

-- 
Formal Signature
Emacs 25, org-mode 9, mu4e 1.0


From coltonlewis at google.com  Fri Dec 12 13:59:30 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Fri, 12 Dec 2025 21:59:30 +0000
Subject: [PATCH v5 18/24] KVM: arm64: Enforce PMU event filter at vcpu_load()
In-Reply-To: <aTicD5hlKhZ3rkIn@kernel.org> (message from Oliver Upton on Tue,
 9 Dec 2025 14:00:47 -0800)
Message-ID: <gsnth5tv2wfx.fsf@coltonlewis-kvm.c.googlers.com>

Oliver Upton <oupton at kernel.org> writes:

> On Tue, Dec 09, 2025 at 08:51:15PM +0000, Colton Lewis wrote:
>> The KVM API for event filtering says that counters do not count when
>> blocked by the event filter. To enforce that, the event filter must be
>> rechecked on every load since it might have changed since the last
>> time the guest wrote a value. If the event is filtered, exclude
>> counting at all exception levels before writing the hardware.

>> Signed-off-by: Colton Lewis <coltonlewis at google.com>
>> ---
>>   arch/arm64/kvm/pmu-direct.c | 44 +++++++++++++++++++++++++++++++++++++
>>   1 file changed, 44 insertions(+)

>> diff --git a/arch/arm64/kvm/pmu-direct.c b/arch/arm64/kvm/pmu-direct.c
>> index 71977d24f489a..8d0d6d1a0d851 100644
>> --- a/arch/arm64/kvm/pmu-direct.c
>> +++ b/arch/arm64/kvm/pmu-direct.c
>> @@ -221,6 +221,49 @@ u8 kvm_pmu_hpmn(struct kvm_vcpu *vcpu)
>>   	return nr_host_cnt_max;
>>   }

>> +/**
>> + * kvm_pmu_apply_event_filter()
>> + * @vcpu: Pointer to vcpu struct
>> + *
>> + * To uphold the guarantee of the KVM PMU event filter, we must ensure
>> + * no counter counts if the event is filtered. Accomplish this by
>> + * filtering all exception levels if the event is filtered.
>> + */
>> +static void kvm_pmu_apply_event_filter(struct kvm_vcpu *vcpu)
>> +{
>> +	struct arm_pmu *pmu = vcpu->kvm->arch.arm_pmu;
>> +	u64 evtyper_set = ARMV8_PMU_EXCLUDE_EL0 |
>> +		ARMV8_PMU_EXCLUDE_EL1;
>> +	u64 evtyper_clr = ARMV8_PMU_INCLUDE_EL2;
>> +	u8 i;
>> +	u64 val;
>> +	u64 evsel;
>> +
>> +	if (!pmu)
>> +		return;
>> +
>> +	for (i = 0; i < pmu->hpmn_max; i++) {
>> +		val = __vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i);
>> +		evsel = val & kvm_pmu_event_mask(vcpu->kvm);
>> +
>> +		if (vcpu->kvm->arch.pmu_filter &&
>> +		    !test_bit(evsel, vcpu->kvm->arch.pmu_filter))
>> +			val |= evtyper_set;
>> +
>> +		val &= ~evtyper_clr;
>> +		write_pmevtypern(i, val);
>> +	}
>> +
>> +	val = __vcpu_sys_reg(vcpu, PMCCFILTR_EL0);
>> +
>> +	if (vcpu->kvm->arch.pmu_filter &&
>> +	    !test_bit(ARMV8_PMUV3_PERFCTR_CPU_CYCLES,  
>> vcpu->kvm->arch.pmu_filter))
>> +		val |= evtyper_set;
>> +
>> +	val &= ~evtyper_clr;
>> +	write_pmccfiltr(val);
>> +}

> This doesn't work for nested. I agree that the hardware value of
> PMEVTYPERn_EL0 needs to be under KVM control, but depending on whether
> or not we're in a hyp context the meaning of the EL1 filtering bit
> changes. Have a look at kvm_pmu_create_perf_event().

That's where I got the ideas for this code. I'll look at the handling
for hyp context too.


> Thanks,
> Oliver


From adrian.kossmann at posteo.de  Fri Dec 12 14:02:24 2025
From: adrian.kossmann at posteo.de (Adrian Kossmann)
Date: Fri, 12 Dec 2025 22:02:24 +0000
Subject: [PATCH v2] arm64: dts: rockchip: Adjust RGMII TXD/RXD delays for the Rock Pi E
Message-ID: <20251212220151.574860-1-adrian.kossmann@posteo.de>

Current RGMII TXD/RXD delay results in link instability
under load, with throughput eventually dropping to zero.
Adjust the RGMII TXD/RXD delay values for stable link
under load and stable Gigabit throughput

Signed-off-by: Adrian Kossmann <adrian.kossmann at posteo.de>
---
Changes in v2:
- Changed the patch subject as the last one contained
  incorrect changes
- Drop incorrect PHY compatible string change from v1
- Adjustments to RGMII RX/TX delay values
- Link to v1: https://lore.kernel.org/linux-rockchip/20251209210658.458506-2-adrian.kossmann at posteo.de/

 arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts b/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts
index a4bdd87d0729..29ff0b8b8f18 100644
--- a/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts
@@ -153,8 +153,8 @@ &gmac2io {
 	phy-supply = <&vcc_io>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&rgmiim1_pins>;
-	tx_delay = <0x26>;
-	rx_delay = <0x11>;
+	tx_delay = <0x1a>;
+	rx_delay = <0x14>;
 	status = "okay";
 
 	mdio {
-- 
2.52.0



From festevam at gmail.com  Fri Dec 12 14:11:59 2025
From: festevam at gmail.com (Fabio Estevam)
Date: Fri, 12 Dec 2025 19:11:59 -0300
Subject: imx8mp SPDIF TX does not produce a lockable signal
In-Reply-To: <CAOMZO5BuMLhMyMkfE1xhOwEs2U=+pZnVq+FP+_bp5W_Qg6oMxQ@mail.gmail.com>
References: <CAOMZO5BuMLhMyMkfE1xhOwEs2U=+pZnVq+FP+_bp5W_Qg6oMxQ@mail.gmail.com>
Message-ID: <CAOMZO5BhmvC1_AhcKTerd1p6PdJ7+YLonU59CcHfmpTVavgqdA@mail.gmail.com>

On Fri, Dec 12, 2025 at 4:11?PM Fabio Estevam <festevam at gmail.com> wrote:

> Any suggestions for debugging or fixing this would be appreciated.

The SPDIF TX audio locks and operation now works.

The key thing was to pass AES1 information.

In /etc/asound.conf:

pcm.spdif_out {
    type iec958
    slave {
        format IEC958_SUBFRAME_LE
        pcm {
            type hw
            card imxaudioxcvr
        }
    }
    status [ 0x00 0x0A 0x00 0x00 ]
    preamble.z 0x0
    preamble.x 0x1
    preamble.y 0x3
}

Play the wav file:
aplay -D plug:spdif_out  96-24.wav

or a 440 Hz tone via speaker test:

speaker-test -D plug:spdif_out -c 2 -t sine

Thanks


From andrew at lunn.ch  Fri Dec 12 14:25:35 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Fri, 12 Dec 2025 23:25:35 +0100
Subject: [PATCH v2] arm64: dts: rockchip: Adjust RGMII TXD/RXD delays for
 the Rock Pi E
In-Reply-To: <20251212220151.574860-1-adrian.kossmann@posteo.de>
References: <20251212220151.574860-1-adrian.kossmann@posteo.de>
Message-ID: <57e99fa1-0e59-4129-bcae-b94df46447e7@lunn.ch>

On Fri, Dec 12, 2025 at 10:02:24PM +0000, Adrian Kossmann wrote:
> Current RGMII TXD/RXD delay results in link instability
> under load, with throughput eventually dropping to zero.
> Adjust the RGMII TXD/RXD delay values for stable link
> under load and stable Gigabit throughput
> 
> Signed-off-by: Adrian Kossmann <adrian.kossmann at posteo.de>
> ---
> Changes in v2:
> - Changed the patch subject as the last one contained
>   incorrect changes
> - Drop incorrect PHY compatible string change from v1
> - Adjustments to RGMII RX/TX delay values
> - Link to v1: https://lore.kernel.org/linux-rockchip/20251209210658.458506-2-adrian.kossmann at posteo.de/
> 
>  arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts b/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts
> index a4bdd87d0729..29ff0b8b8f18 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts
> +++ b/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts
> @@ -153,8 +153,8 @@ &gmac2io {
>  	phy-supply = <&vcc_io>;
>  	pinctrl-names = "default";
>  	pinctrl-0 = <&rgmiim1_pins>;
> -	tx_delay = <0x26>;
> -	rx_delay = <0x11>;
> +	tx_delay = <0x1a>;
> +	rx_delay = <0x14>;
>  	status = "okay";

You cannot see it here, it appears before this context:

&gmac2io {
        assigned-clocks = <&cru SCLK_MAC2IO>, <&cru SCLK_MAC2IO_EXT>;
        assigned-clock-parents = <&gmac_clkin>, <&gmac_clkin>;
        clock_in_out = "input";
        phy-handle = <&rtl8211>;
        phy-mode = "rgmii";

rgmii means the PCB provides the delay. I doubt that is the
case. Please try changing this to rgmii-id, as recommended here:

https://elixir.bootlin.com/linux/v6.15/source/Documentation/devicetree/bindings/net/ethernet-controller.yaml#L287

and then try out different rx_delay and tx_delay values.

    Andrew


From coltonlewis at google.com  Fri Dec 12 14:25:44 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Fri, 12 Dec 2025 22:25:44 +0000
Subject: [PATCH v5 19/24] KVM: arm64: Implement lazy PMU context swaps
In-Reply-To: <aTidfRwYLYwTfmK_@kernel.org> (message from Oliver Upton on Tue,
 9 Dec 2025 14:06:53 -0800)
Message-ID: <gsntecoz2v87.fsf@coltonlewis-kvm.c.googlers.com>

Oliver Upton <oupton at kernel.org> writes:

> On Tue, Dec 09, 2025 at 08:51:16PM +0000, Colton Lewis wrote:
>> +enum vcpu_pmu_register_access {
>> +	VCPU_PMU_ACCESS_UNSET,
>> +	VCPU_PMU_ACCESS_VIRTUAL,
>> +	VCPU_PMU_ACCESS_PHYSICAL,
>> +};

> This is confusing. Even when the guest is accessing registers directly
> on the CPU I'd still call that "hardware assisted virtualization" and
> not "physical".

It was what I thought described the access pattern. Do you have another
naming suggestion?

>> +#endif /* _ASM_ARM64_KVM_TYPES_H */
>> diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
>> index 0ab89c91e19cb..c2cf6b308ec60 100644
>> --- a/arch/arm64/kvm/debug.c
>> +++ b/arch/arm64/kvm/debug.c
>> @@ -34,7 +34,7 @@ static int cpu_has_spe(u64 dfr0)
>>    *  - Self-hosted Trace Filter controls (MDCR_EL2_TTRF)
>>    *  - Self-hosted Trace (MDCR_EL2_TTRF/MDCR_EL2_E2TB)
>>    */
>> -static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu)
>> +void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu)
>>   {
>>   	int hpmn = kvm_pmu_hpmn(vcpu);

>> diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h  
>> b/arch/arm64/kvm/hyp/include/hyp/switch.h
>> index bde79ec1a1836..ea288a712bb5d 100644
>> --- a/arch/arm64/kvm/hyp/include/hyp/switch.h
>> +++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
>> @@ -963,6 +963,8 @@ static bool kvm_hyp_handle_pmu_regs(struct kvm_vcpu  
>> *vcpu)
>>   	if (ret)
>>   		__kvm_skip_instr(vcpu);

>> +	kvm_pmu_set_physical_access(vcpu);
>> +
>>   	return ret;
>>   }

>> diff --git a/arch/arm64/kvm/pmu-direct.c b/arch/arm64/kvm/pmu-direct.c
>> index 8d0d6d1a0d851..c5767e2ebc651 100644
>> --- a/arch/arm64/kvm/pmu-direct.c
>> +++ b/arch/arm64/kvm/pmu-direct.c
>> @@ -73,6 +73,7 @@ bool kvm_vcpu_pmu_use_fgt(struct kvm_vcpu *vcpu)
>>   	u8 hpmn = vcpu->kvm->arch.nr_pmu_counters;

>>   	return kvm_vcpu_pmu_is_partitioned(vcpu) &&
>> +		vcpu->arch.pmu.access == VCPU_PMU_ACCESS_PHYSICAL &&
>>   		cpus_have_final_cap(ARM64_HAS_FGT) &&
>>   		(hpmn != 0 || cpus_have_final_cap(ARM64_HAS_HPMN0));
>>   }
>> @@ -92,6 +93,26 @@ u64 kvm_pmu_fgt2_bits(void)
>>   		| HDFGRTR2_EL2_nPMICNTR_EL0;
>>   }

>> +/**
>> + * kvm_pmu_set_physical_access()
>> + * @vcpu: Pointer to vcpu struct
>> + *
>> + * Reconfigure the guest for physical access of PMU hardware if
>> + * allowed. This means reconfiguring mdcr_el2 and loading the vCPU
>> + * state onto hardware.
>> + *
>> + */
>> +
>> +void kvm_pmu_set_physical_access(struct kvm_vcpu *vcpu)
>> +{
>> +	if (kvm_vcpu_pmu_is_partitioned(vcpu)
>> +	    && vcpu->arch.pmu.access == VCPU_PMU_ACCESS_VIRTUAL) {
>> +		vcpu->arch.pmu.access = VCPU_PMU_ACCESS_PHYSICAL;
>> +		kvm_arm_setup_mdcr_el2(vcpu);
>> +		kvm_pmu_load(vcpu);
>> +	}

> It isn't immediately obvious how this guards against preemption.

> Also, the general approach for these context-loading situations is to do
> a full load/put on the vCPU rather than a directed load.

Understood. Will fix.

>> +static void kvm_pmu_register_init(struct kvm_vcpu *vcpu)
>> +{
>> +	if (vcpu->arch.pmu.access == VCPU_PMU_ACCESS_UNSET)
>> +		vcpu->arch.pmu.access = VCPU_PMU_ACCESS_VIRTUAL;

> This is confusing. The zero value of the enum should be consistent with
> the "unloaded" state.

That's the way I initially wrote it but it had a problem on a different
kernel. I forget the exact issue, but I never saw the problem on
upstream so I'm happy to go back to it.

>> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
>> index f2ae761625a66..d73218706b834 100644
>> --- a/arch/arm64/kvm/sys_regs.c
>> +++ b/arch/arm64/kvm/sys_regs.c
>> @@ -1197,6 +1197,8 @@ static bool access_pmu_evtyper(struct kvm_vcpu  
>> *vcpu, struct sys_reg_params *p,
>>   		p->regval = __vcpu_sys_reg(vcpu, reg);
>>   	}

>> +	kvm_pmu_set_physical_access(vcpu);
>> +
>>   	return true;
>>   }

>> @@ -1302,6 +1304,8 @@ static bool access_pmovs(struct kvm_vcpu *vcpu,  
>> struct sys_reg_params *p,
>>   		p->regval = __vcpu_sys_reg(vcpu, PMOVSSET_EL0);
>>   	}

>> +	kvm_pmu_set_physical_access(vcpu);
>> +
>>   	return true;
>>   }

> Aren't there a ton of other registers the guest may access before
> these two? Having generic PMU register accessors would allow you to
> manage residence of PMU registers from a single spot.

Yes but these are the only two that use the old trap handlers. I also
call set_physical_access from my fast path handler that handles all the
other registers when partitioned.

Agree on having some generic accessors which you mention in an earlier
patch.


From coltonlewis at google.com  Fri Dec 12 14:36:41 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Fri, 12 Dec 2025 22:36:41 +0000
Subject: [PATCH v5 20/24] perf: arm_pmuv3: Handle IRQs for Partitioned PMU
 guest counters
In-Reply-To: <aTimpRFfr9wI9Hw5@kernel.org> (message from Oliver Upton on Tue,
 9 Dec 2025 14:45:57 -0800)
Message-ID: <gsntbjk32upy.fsf@coltonlewis-kvm.c.googlers.com>

Oliver Upton <oupton at kernel.org> writes:

> On Tue, Dec 09, 2025 at 08:51:17PM +0000, Colton Lewis wrote:
>> Because ARM hardware is not yet capable of direct interrupt injection

> PPI injection, it can do LPIs just fine.

Clarification noted. I will update the message.

>> @@ -961,6 +964,12 @@ static irqreturn_t armv8pmu_handle_irq(struct  
>> arm_pmu *cpu_pmu)
>>   		 */
>>   		perf_event_overflow(event, &data, regs);
>>   	}
>> +
>> +	govf = pmovsr & kvm_pmu_guest_counter_mask(cpu_pmu);
>> +
>> +	if (kvm_pmu_is_partitioned(cpu_pmu) && govf)
>> +		kvm_pmu_handle_guest_irq(govf);
>> +

> The state ownership of this whole interaction is very odd. I would much
> rather that KVM have full ownership of the range of counters while the
> guest is loaded. By that I mean the PMUv3 driver only clears overflows
> on PMCs that it owns and KVM will do the same on the back of the IRQ.

If I'm understanding correctly this is a code location concern, because
the host driver has to handle the interrupt in this function or a callee
of this function.

I will do it that way. It would be duplicating a small amount of logic
in kvm_pmu_handle_guest_irq() but I see your reasoning.

> Similarly, KVM should be leaving the "guest" range of counters in a
> non-overflow condition at vcpu_put().

Noted from your comments on kvm_pmu_put()


> Thanks,
> Oliver


From jiaqiyan at google.com  Fri Dec 12 14:42:37 2025
From: jiaqiyan at google.com (Jiaqi Yan)
Date: Fri, 12 Dec 2025 14:42:37 -0800
Subject: [PATCH v4 2/3] KVM: selftests: Test for KVM_EXIT_ARM_SEA
In-Reply-To: <dbcfb853-5853-5967-1bf9-76c6b3839717@huawei.com>
References: <20251013185903.1372553-1-jiaqiyan@google.com> <20251013185903.1372553-3-jiaqiyan@google.com>
 <3061f5f8-cef0-b7b1-c4de-f2ceea29af9a@huawei.com> <CACw3F51mRXCDz7Hd4Vve98NoskhB2cSc88zAGfd6Hwr4uCBxPA@mail.gmail.com>
 <dbcfb853-5853-5967-1bf9-76c6b3839717@huawei.com>
Message-ID: <CACw3F51FQwCLe17E4VC5wtpnCyuBOMrchvoBYCcwTxPkuxD+fg@mail.gmail.com>

On Fri, Dec 12, 2025 at 1:22?AM Zenghui Yu <yuzenghui at huawei.com> wrote:
>
> On 2025/12/12 9:53, Jiaqi Yan wrote:
> > On Thu, Dec 11, 2025 at 5:02?AM Zenghui Yu <yuzenghui at huawei.com> wrote:
> > >
> > > I can also hit this ASSERT with:
> > >
> > > Random seed: 0x6b8b4567
> > > # Mapped 0x40000 pages: gva=0x80000000 to gpa=0xff80000000
> > > # Before EINJect: data=0xbaadcafe
> > > # EINJ_GVA=0x81234bad, einj_gpa=0xff81234bad, einj_hva=0xffff41234bad,
> > > einj_hpa=0x2841234bad
> > > # echo 0x10 > /sys/kernel/debug/apei/einj/error_type - done
> > > # echo 0x2 > /sys/kernel/debug/apei/einj/flags - done
> > > # echo 0x2841234bad > /sys/kernel/debug/apei/einj/param1 - done
> > > # echo 0xffffffffffffffff > /sys/kernel/debug/apei/einj/param2 - done
> > > # echo 0x1 > /sys/kernel/debug/apei/einj/notrigger - done
> > > # echo 0x1 > /sys/kernel/debug/apei/einj/error_inject - done
> > > # Memory UER EINJected
> > > # Dump kvm_run info about KVM_EXIT_MMIO
> > > # kvm_run.arm_sea: esr=0xffff90ba0040, flags=0x691000
> > > # kvm_run.arm_sea: gva=0x100000008, gpa=0
> > > ==== Test Assertion Failure ====
> > >   arm64/sea_to_user.c:207: exit_reason == (41)
> > >   pid=38023 tid=38023 errno=4 - Interrupted system call
> > >      1  0x0000000000402d1b: run_vm at sea_to_user.c:207
> > >      2  0x0000000000402467: main at sea_to_user.c:330
> > >      3  0x0000ffff9122b03f: ?? ??:0
> > >      4  0x0000ffff9122b117: ?? ??:0
> > >      5  0x00000000004026ef: _start at ??:?
> > >   Wanted KVM exit reason: 41 (ARM_SEA), got: 6 (MMIO)
> > >
> > > Not sure what's wrong it..
> >
> > Does your test machine have SDEI or SCI enabled for host APEI? Do you
> > see any kernel log from "Memory failure:" saying hugetlb page
> > recovered, and recovered significant earlier than the KVM exit here.
> > It maybe the kernel has already unmapped hugepage in response to SDEI
> > or SCI before this test actually consumes memory error, so no SEA is
> > actually triggered.
>
> No kernel log was printed when I saw this failure.

Hmm, and even no CPER logged by APEI/GHES? That makes me suspect the
error wasn't injected successfully.

In that case, I found a bug in sea_to_user.c: GUEST_FAIL is not
handled by run_vm and results in unhandled MMIO.

Here is a fix I tested on my side, with some other minor fixes. Do you
mind trying it?

commit b96a92d1006fbe2752ba133eb76b0c45c9c54265
Author: Jiaqi Yan <jiaqiyan at google.com>
Date:   Fri Dec 12 22:27:53 2025 +0000

    KVM: selftests: Improve sea_to_user test

    Several improvments to the test for KVM_EXIT_ARM_SEA:
    - refactor run_vm to catch GUEST_FAIL, instead of causing confusing
    kvm exit with unhandled MMIO
    - sync far_invalid to guest
    - exit with KSFT_SKIP or KSFT_FAIL when should

    Change-Id: I8b735de3b669297f0638bea2d32a0b36211f7f5c

diff --git a/tools/testing/selftests/kvm/arm64/sea_to_user.c
b/tools/testing/selftests/kvm/arm64/sea_to_user.c
index 573dd790aeb8e..6fd3cd881b415 100644
--- a/tools/testing/selftests/kvm/arm64/sea_to_user.c
+++ b/tools/testing/selftests/kvm/arm64/sea_to_user.c
@@ -98,11 +98,15 @@ static void write_einj_entry(const char
*einj_path, uint64_t val)

 static void inject_uer(uint64_t paddr)
 {
-       if (access("/sys/firmware/acpi/tables/EINJ", R_OK) == -1)
-               ksft_test_result_skip("EINJ table no available in firmware");
+       if (access("/sys/firmware/acpi/tables/EINJ", R_OK) == -1) {
+               ksft_test_result_skip("EINJ table not available in firmware\n");
+               exit(KSFT_SKIP);
+       }

-       if (access(EINJ_ETYPE, R_OK | W_OK) == -1)
+       if (access(EINJ_ETYPE, R_OK | W_OK) == -1) {
                ksft_test_result_skip("EINJ module probably not loaded?\n");
+               exit(KSFT_SKIP);
+       }

        write_einj_entry(EINJ_ETYPE, ERROR_TYPE_MEMORY_UER);
        write_einj_entry(EINJ_FLAGS, MASK_MEMORY_UER);
@@ -123,12 +127,13 @@ static void sigbus_signal_handler(int sig,
siginfo_t *si, void *v)
        ksft_print_msg("SIGBUS (%d) received, dumping siginfo...\n", sig);
        ksft_print_msg("si_signo=%d, si_errno=%d, si_code=%d, si_addr=%p\n",
                       si->si_signo, si->si_errno, si->si_code, si->si_addr);
-       if (si->si_code == BUS_MCEERR_AR)
+       if (si->si_code == BUS_MCEERR_AR) {
                ksft_test_result_skip("SEA is claimed by host APEI\n");
-       else
+               exit(KSFT_SKIP);
+       } else {
                ksft_test_result_fail("Exit with signal unhandled\n");
-
-       exit(0);
+               exit(KSFT_FAIL);
+       }
 }

 static void setup_sigbus_handler(void)
@@ -158,7 +163,6 @@ static void expect_sea_handler(struct ex_regs *regs)
 {
        u64 esr = read_sysreg(esr_el1);
        u64 far = read_sysreg(far_el1);
-       bool expect_far_invalid = far_invalid;

        GUEST_PRINTF("Handling Guest SEA\n");
        GUEST_PRINTF("ESR_EL1=%#lx, FAR_EL1=%#lx\n", esr, far);
@@ -166,7 +170,7 @@ static void expect_sea_handler(struct ex_regs *regs)
        GUEST_ASSERT_EQ(ESR_ELx_EC(esr), ESR_ELx_EC_DABT_CUR);
        GUEST_ASSERT_EQ(esr & ESR_ELx_FSC_TYPE, ESR_ELx_FSC_EXTABT);

-       if (expect_far_invalid) {
+       if (far_invalid) {
                GUEST_ASSERT_EQ(esr & ESR_ELx_FnV, ESR_ELx_FnV);
                GUEST_PRINTF("Guest observed garbage value in FAR\n");
        } else {
@@ -185,25 +189,19 @@ static void vcpu_inject_sea(struct kvm_vcpu *vcpu)
        vcpu_events_set(vcpu, &events);
 }

-static void run_vm(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
+static void validate_kvm_exit_arm_sea(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
 {
-       struct ucall uc;
-       bool guest_done = false;
        struct kvm_run *run = vcpu->run;
        u64 esr;

-       /* Resume the vCPU after error injection to consume the error. */
-       vcpu_run(vcpu);
+       TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_ARM_SEA);

-       ksft_print_msg("Dump kvm_run info about KVM_EXIT_%s\n",
-                      exit_reason_str(run->exit_reason));
+       ksft_print_msg("Dumping kvm_run as arm_sea:\n");
        ksft_print_msg("kvm_run.arm_sea: esr=%#llx, flags=%#llx\n",
                       run->arm_sea.esr, run->arm_sea.flags);
        ksft_print_msg("kvm_run.arm_sea: gva=%#llx, gpa=%#llx\n",
                       run->arm_sea.gva, run->arm_sea.gpa);

-       TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_ARM_SEA);
-
        esr = run->arm_sea.esr;
        TEST_ASSERT_EQ(ESR_ELx_EC(esr), ESR_ELx_EC_DABT_LOW);
        TEST_ASSERT_EQ(esr & ESR_ELx_FSC_TYPE, ESR_ELx_FSC_EXTABT);
@@ -211,39 +209,48 @@ static void run_vm(struct kvm_vm *vm, struct
kvm_vcpu *vcpu)
        TEST_ASSERT_EQ((esr & ESR_ELx_INST_SYNDROME), 0);
        TEST_ASSERT_EQ(esr & ESR_ELx_VNCR, 0);

-       if (!(esr & ESR_ELx_FnV)) {
-               ksft_print_msg("Expect gva to match given FnV bit is 0\n");
+       far_invalid = esr & ESR_ELx_FnV;
+       sync_global_to_guest(vm, far_invalid);
+
+       if (!far_invalid) {
+               ksft_print_msg("Expect gva to match\n");
                TEST_ASSERT_EQ(run->arm_sea.gva, EINJ_GVA);
        }

        if (run->arm_sea.flags & KVM_EXIT_ARM_SEA_FLAG_GPA_VALID) {
-               ksft_print_msg("Expect gpa to match given
KVM_EXIT_ARM_SEA_FLAG_GPA_VALID is set\n");
+               ksft_print_msg("Expect gpa to match\n");
                TEST_ASSERT_EQ(run->arm_sea.gpa, einj_gpa & PAGE_ADDR_MASK);
        }
+}

-       far_invalid = esr & ESR_ELx_FnV;
-
-       /* Inject a SEA into guest and expect handled in SEA handler. */
-       vcpu_inject_sea(vcpu);
+static void run_vm(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
+{
+       struct ucall uc;
+       bool guest_done = false;

        /* Expect the guest to reach GUEST_DONE gracefully. */
        do {
                vcpu_run(vcpu);
-               switch (get_ucall(vcpu, &uc)) {
-               case UCALL_PRINTF:
-                       ksft_print_msg("From guest: %s", uc.buffer);
-                       break;
-               case UCALL_DONE:
-                       ksft_print_msg("Guest done gracefully!\n");
-                       guest_done = 1;
-                       break;
-               case UCALL_ABORT:
-                       ksft_print_msg("Guest aborted!\n");
-                       guest_done = 1;
-                       REPORT_GUEST_ASSERT(uc);
-                       break;
-               default:
-                       TEST_FAIL("Unexpected ucall: %lu\n", uc.cmd);
+               if (vcpu->run->exit_reason == KVM_EXIT_ARM_SEA) {
+                       validate_kvm_exit_arm_sea(vm, vcpu);
+                       vcpu_inject_sea(vcpu);
+               } else {
+                       switch (get_ucall(vcpu, &uc)) {
+                       case UCALL_PRINTF:
+                               ksft_print_msg("From guest: %s", uc.buffer);
+                               break;
+                       case UCALL_DONE:
+                               ksft_print_msg("Guest done gracefully!\n");
+                               guest_done = 1;
+                               break;
+                       case UCALL_ABORT:
+                               ksft_print_msg("Guest aborted!\n");
+                               guest_done = 1;
+                               REPORT_GUEST_ASSERT(uc);
+                               break;
+                       default:
+                               TEST_FAIL("Unexpected ucall: %lu\n", uc.cmd);
+                       }
                }
        } while (!guest_done);
 }

>
> Thanks,
> Zenghui


From duje at dujemihanovic.xyz  Fri Dec 12 14:44:33 2025
From: duje at dujemihanovic.xyz (Duje =?UTF-8?B?TWloYW5vdmnEhw==?=)
Date: Fri, 12 Dec 2025 23:44:33 +0100
Subject: [DONOTAPPLY RFC PATCH v2 4/4] arm64: dts: samsung,coreprimevelte: add
 wifi node
In-Reply-To: <DEWJTWZ6Q51B.13HQYMDJZRFWA@matfyz.cz>
References: <20251026182602.26464-1-balejk@matfyz.cz>
 <b92172f3-10f4-470f-b90a-121ff7fea988@dujemihanovic.xyz>
 <DEWJTWZ6Q51B.13HQYMDJZRFWA@matfyz.cz>
Message-ID: <5962754.DvuYhMxLoT@radijator>

On Friday, 12 December 2025 22:17:12 Central European Standard Time Karel 
Balej wrote:
> Duje Mihanovi?, 2025-12-12T15:55:48+01:00:
> > On 12/12/25 09:36, Karel Balej wrote:
> >> Not having any board schematics, I don't really know what exactly the
> >> regulator's purpose is. As I mentioned in the commit message, the
> >> communication with the chipset seems to work even if this is disabled
> >> (e. g. FW loads, networks can be scanned for,...) which doesn't seem
> >> like it should be the case if this was a main power supply for the bus,
> >> only actual connecting to networks doesn't work (gives
> >> CONNECT_ERR_ASSOC_ERR_TIMEOUT errors).
> > 
> > To me, this strongly suggests that the regulator powers the WiFi
> > transmitter or at least a part of it (such as the RF amp).
> 
> Something like this occurred to me too but would the chip even see the
> networks if this was the case? Although you are right that it could only
> power some specific part of the radio.

AFAIK you don't need the transmitter to capture and parse beacon frames. Of 
course, connecting to networks is a completely different story.

Regards,
--
Duje





From coltonlewis at google.com  Fri Dec 12 14:55:06 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Fri, 12 Dec 2025 22:55:06 +0000
Subject: [PATCH v5 21/24] KVM: arm64: Inject recorded guest interrupts
In-Reply-To: <aTioEWHu0ZbFCjR6@kernel.org> (message from Oliver Upton on Tue,
 9 Dec 2025 14:52:01 -0800)
Message-ID: <gsnt8qf72tv9.fsf@coltonlewis-kvm.c.googlers.com>

Oliver Upton <oupton at kernel.org> writes:

> In no situation should KVM be injecting a "recorded" IRQ. The overflow
> condition of the PMU is well defined in the architecture and we should
> implement *exactly* that.

When I say "record" I just meant "updating the virtual overflow register
to reflect an overflow".

Do you think I'm not implementing the condition correctly in
kvm_pmu_part_overflow_status()?

> On Tue, Dec 09, 2025 at 08:51:18PM +0000, Colton Lewis wrote:
>> +/**
>> + * kvm_pmu_part_overflow_status() - Determine if any guest counters  
>> have overflowed
>> + * @vcpu: Ponter to struct kvm_vcpu
>> + *
>> + * Determine if any guest counters have overflowed and therefore an
>> + * IRQ needs to be injected into the guest.
>> + *
>> + * Return: True if there was an overflow, false otherwise
>> + */
>> +bool kvm_pmu_part_overflow_status(struct kvm_vcpu *vcpu)
>> +{
>> +	struct arm_pmu *pmu = vcpu->kvm->arch.arm_pmu;
>> +	u64 mask = kvm_pmu_guest_counter_mask(pmu);
>> +	u64 pmovs = __vcpu_sys_reg(vcpu, PMOVSSET_EL0);
>> +	u64 pmint = read_pmintenset();
>> +	u64 pmcr = read_pmcr();

> How do we know that the vPMU has been loaded on the CPU at this point?

Because this is only called by kvm_pmu_update_state which is only called
by kvm_pmu_update_state <- kvm_pmu_{flush,sync}_hwstate <-
kvm_arch_vcpu_ioctl_run after a vcpu_load.

>> +
>> +	return (pmcr & ARMV8_PMU_PMCR_E) && (mask & pmovs & pmint);
>> +}

> I'd rather reuse kvm_pmu_overflow_status(), relying on the accessors to
> abstract away the implementation / location of the guest PMU context.

Agreed on making some generic accessors.

> Thanks,
> Oliver


From coltonlewis at google.com  Fri Dec 12 14:59:01 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Fri, 12 Dec 2025 22:59:01 +0000
Subject: [PATCH v5 22/24] KVM: arm64: Add KVM_CAP to partition the PMU
In-Reply-To: <aTipeb2fAmUtSzzX@kernel.org> (message from Oliver Upton on Tue,
 9 Dec 2025 14:58:01 -0800)
Message-ID: <gsnt5xab2toq.fsf@coltonlewis-kvm.c.googlers.com>

Oliver Upton <oupton at kernel.org> writes:

> On Tue, Dec 09, 2025 at 08:51:19PM +0000, Colton Lewis wrote:
>> +
>> +7.245 KVM_CAP_ARM_PARTITION_PMU
>> +-------------------------------------
>> +

> Why can't this be a vCPU attribute similar to the other vPMU controls?
> Making the UAPI consistent will make it easier for userspace to reason
> about it.

I'm confused by the inconsistency of using a vCPU attribute for
something we want to affect the whole VM.

But I'll do a vCPU attribute if you want.

> Better yet, we could make the UAPI such that userspace selects a PMU
> implementation and the partitioned-ness of the PMU at the same time.

Sounds good.

>> @@ -132,6 +134,16 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
>>   		}
>>   		mutex_unlock(&kvm->lock);
>>   		break;
>> +	case KVM_CAP_ARM_PARTITION_PMU:
>> +		if (kvm->created_vcpus) {
>> +			r = -EBUSY;
>> +		} else if (!kvm_pmu_partition_ready()) {
>> +			r = -EPERM;
>> +		} else {
>> +			r = 0;
>> +			kvm_pmu_partition_enable(kvm, cap->args[0]);
>> +		}
>> +		break;
>>   	default:
>>   		break;
>>   	}
>> @@ -388,6 +400,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm,  
>> long ext)
>>   	case KVM_CAP_ARM_PMU_V3:
>>   		r = kvm_supports_guest_pmuv3();
>>   		break;
>> +	case KVM_CAP_ARM_PARTITION_PMU:
>> +		r = kvm_pmu_partition_ready();

> "ready" is very confusing in this context, as KVM will never be ready to
> support the feature on a system w/o the prerequisites.

That was a last minute addition. I'll change the name to something
better.

> Thanks,
> Oliver


From andrew at codeconstruct.com.au  Fri Dec 12 15:05:43 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Sat, 13 Dec 2025 08:05:43 +0900
Subject: [PATCH RFC 00/16] Eliminate warnings for AST2500 and AST2600
 EVB devicetrees
In-Reply-To: <20251212150631.GA3997751-robh@kernel.org>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
	 <20251212150631.GA3997751-robh@kernel.org>
Message-ID: <35ec28a70d360b2139742e9f04ff77e4a907cd2b.camel@codeconstruct.com.au>

Hi Rob,

On Fri, 2025-12-12 at 09:06 -0600, Rob Herring wrote:
> 
> Don't you see warnings for at25:
> 
> ???? 89 (atmel,at25): 'size' is a required property
> ???? 89 (atmel,at25): 'pagesize' is a required property
> ???? 89 (atmel,at25): 'address-width' is a required property
> 
> These are due to using the deprecated (since 2012) at25,byte-len, 
> at25,addr-mode, and at25,page-size properties. I think it has been long 
> enough you can just replace them with the new ones.

I don't see them, no. The series targets only the aspeed/aspeed-
ast2{5,6}00-evb.dts files, and neither of them contain at25 nodes. grep
suggests its only IBM platforms:

   > git grep -l at2 ../arch/arm/boot/dts/aspeed/*.dts*
   ../arch/arm/boot/dts/aspeed/aspeed-bmc-ibm-everest.dts
   ../arch/arm/boot/dts/aspeed/aspeed-bmc-ibm-fuji.dts
   ../arch/arm/boot/dts/aspeed/ibm-power10-dual.dtsi
   ../arch/arm/boot/dts/aspeed/ibm-power10-quad.dtsi
   ../arch/arm/boot/dts/aspeed/ibm-power11-dual.dtsi
   ../arch/arm/boot/dts/aspeed/ibm-power11-quad.dtsi
   >

Once I've got the pieces of this series merged I'll encourage platform
owners to start cleaning up their own devicetrees on the basis that
there are no longer warnings that aren't their problem.

Thanks for your feedback so far!

Andrew


From robh at kernel.org  Fri Dec 12 15:11:52 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Fri, 12 Dec 2025 17:11:52 -0600
Subject: [PATCH] dt-bindings: Remove unused includes
Message-ID: <20251212231203.727227-1-robh@kernel.org>

Remove includes which are not referenced by either DTS files or drivers.

There's a few more which are new, so they are excluded for now.

Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
---
 include/dt-bindings/clock/oxsemi,ox810se.h    |  19 --
 include/dt-bindings/clock/oxsemi,ox820.h      |  29 --
 include/dt-bindings/clock/qcom,mss-sc7180.h   |  12 -
 include/dt-bindings/clock/xlnx-versal-clk.h   | 123 ---------
 include/dt-bindings/clock/xlnx-zynqmp-clk.h   | 133 ---------
 include/dt-bindings/dma/jz4775-dma.h          |  44 ---
 include/dt-bindings/dma/x2000-dma.h           |  54 ----
 include/dt-bindings/gce/mt6779-gce.h          | 222 ---------------
 .../dt-bindings/iio/qcom,spmi-adc7-pmr735b.h  |  30 --
 .../dt-bindings/iio/qcom,spmi-adc7-smb139x.h  |  19 --
 include/dt-bindings/memory/mt6779-larb-port.h | 206 --------------
 include/dt-bindings/mux/ti-serdes.h           | 190 -------------
 include/dt-bindings/pinctrl/mt6397-pinfunc.h  | 257 ------------------
 .../power/allwinner,sun20i-d1-ppu.h           |  10 -
 include/dt-bindings/reset/bcm6318-reset.h     |  20 --
 include/dt-bindings/reset/imx8ulp-pcc-reset.h |  59 ----
 include/dt-bindings/reset/oxsemi,ox810se.h    |  42 ---
 include/dt-bindings/reset/oxsemi,ox820.h      |  42 ---
 include/dt-bindings/sound/audio-jack-events.h |  10 -
 19 files changed, 1521 deletions(-)
 delete mode 100644 include/dt-bindings/clock/oxsemi,ox810se.h
 delete mode 100644 include/dt-bindings/clock/oxsemi,ox820.h
 delete mode 100644 include/dt-bindings/clock/qcom,mss-sc7180.h
 delete mode 100644 include/dt-bindings/clock/xlnx-versal-clk.h
 delete mode 100644 include/dt-bindings/clock/xlnx-zynqmp-clk.h
 delete mode 100644 include/dt-bindings/dma/jz4775-dma.h
 delete mode 100644 include/dt-bindings/dma/x2000-dma.h
 delete mode 100644 include/dt-bindings/gce/mt6779-gce.h
 delete mode 100644 include/dt-bindings/iio/qcom,spmi-adc7-pmr735b.h
 delete mode 100644 include/dt-bindings/iio/qcom,spmi-adc7-smb139x.h
 delete mode 100644 include/dt-bindings/memory/mt6779-larb-port.h
 delete mode 100644 include/dt-bindings/mux/ti-serdes.h
 delete mode 100644 include/dt-bindings/pinctrl/mt6397-pinfunc.h
 delete mode 100644 include/dt-bindings/power/allwinner,sun20i-d1-ppu.h
 delete mode 100644 include/dt-bindings/reset/bcm6318-reset.h
 delete mode 100644 include/dt-bindings/reset/imx8ulp-pcc-reset.h
 delete mode 100644 include/dt-bindings/reset/oxsemi,ox810se.h
 delete mode 100644 include/dt-bindings/reset/oxsemi,ox820.h
 delete mode 100644 include/dt-bindings/sound/audio-jack-events.h

diff --git a/include/dt-bindings/clock/oxsemi,ox810se.h b/include/dt-bindings/clock/oxsemi,ox810se.h
deleted file mode 100644
index 7256365160f8..000000000000
--- a/include/dt-bindings/clock/oxsemi,ox810se.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) 2016 Neil Armstrong <narmstrong at baylibre.com>
- */
-
-#ifndef DT_CLOCK_OXSEMI_OX810SE_H
-#define DT_CLOCK_OXSEMI_OX810SE_H
-
-#define CLK_810_LEON		0
-#define CLK_810_DMA_SGDMA	1
-#define CLK_810_CIPHER		2
-#define CLK_810_SATA		3
-#define CLK_810_AUDIO		4
-#define CLK_810_USBMPH		5
-#define CLK_810_ETHA		6
-#define CLK_810_PCIEA		7
-#define CLK_810_NAND		8
-
-#endif /* DT_CLOCK_OXSEMI_OX810SE_H */
diff --git a/include/dt-bindings/clock/oxsemi,ox820.h b/include/dt-bindings/clock/oxsemi,ox820.h
deleted file mode 100644
index 55f4226e2f3f..000000000000
--- a/include/dt-bindings/clock/oxsemi,ox820.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) 2016 Neil Armstrong <narmstrong at baylibre.com>
- */
-
-#ifndef DT_CLOCK_OXSEMI_OX820_H
-#define DT_CLOCK_OXSEMI_OX820_H
-
-/* PLLs */
-#define CLK_820_PLLA		0
-#define CLK_820_PLLB		1
-
-/* Gate Clocks */
-#define CLK_820_LEON		2
-#define CLK_820_DMA_SGDMA	3
-#define CLK_820_CIPHER		4
-#define CLK_820_SD		5
-#define CLK_820_SATA		6
-#define CLK_820_AUDIO		7
-#define CLK_820_USBMPH		8
-#define CLK_820_ETHA		9
-#define CLK_820_PCIEA		10
-#define CLK_820_NAND		11
-#define CLK_820_PCIEB		12
-#define CLK_820_ETHB		13
-#define CLK_820_REF600		14
-#define CLK_820_USBDEV		15
-
-#endif /* DT_CLOCK_OXSEMI_OX820_H */
diff --git a/include/dt-bindings/clock/qcom,mss-sc7180.h b/include/dt-bindings/clock/qcom,mss-sc7180.h
deleted file mode 100644
index f15a9ded2961..000000000000
--- a/include/dt-bindings/clock/qcom,mss-sc7180.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (c) 2020, The Linux Foundation. All rights reserved.
- */
-
-#ifndef _DT_BINDINGS_CLK_QCOM_MSS_SC7180_H
-#define _DT_BINDINGS_CLK_QCOM_MSS_SC7180_H
-
-#define MSS_AXI_CRYPTO_CLK	0
-#define MSS_AXI_NAV_CLK		1
-
-#endif
diff --git a/include/dt-bindings/clock/xlnx-versal-clk.h b/include/dt-bindings/clock/xlnx-versal-clk.h
deleted file mode 100644
index 264d634d226e..000000000000
--- a/include/dt-bindings/clock/xlnx-versal-clk.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- *  Copyright (C) 2019 Xilinx Inc.
- *
- */
-
-#ifndef _DT_BINDINGS_CLK_VERSAL_H
-#define _DT_BINDINGS_CLK_VERSAL_H
-
-#define PMC_PLL					1
-#define APU_PLL					2
-#define RPU_PLL					3
-#define CPM_PLL					4
-#define NOC_PLL					5
-#define PLL_MAX					6
-#define PMC_PRESRC				7
-#define PMC_POSTCLK				8
-#define PMC_PLL_OUT				9
-#define PPLL					10
-#define NOC_PRESRC				11
-#define NOC_POSTCLK				12
-#define NOC_PLL_OUT				13
-#define NPLL					14
-#define APU_PRESRC				15
-#define APU_POSTCLK				16
-#define APU_PLL_OUT				17
-#define APLL					18
-#define RPU_PRESRC				19
-#define RPU_POSTCLK				20
-#define RPU_PLL_OUT				21
-#define RPLL					22
-#define CPM_PRESRC				23
-#define CPM_POSTCLK				24
-#define CPM_PLL_OUT				25
-#define CPLL					26
-#define PPLL_TO_XPD				27
-#define NPLL_TO_XPD				28
-#define APLL_TO_XPD				29
-#define RPLL_TO_XPD				30
-#define EFUSE_REF				31
-#define SYSMON_REF				32
-#define IRO_SUSPEND_REF				33
-#define USB_SUSPEND				34
-#define SWITCH_TIMEOUT				35
-#define RCLK_PMC				36
-#define RCLK_LPD				37
-#define WDT					38
-#define TTC0					39
-#define TTC1					40
-#define TTC2					41
-#define TTC3					42
-#define GEM_TSU					43
-#define GEM_TSU_LB				44
-#define MUXED_IRO_DIV2				45
-#define MUXED_IRO_DIV4				46
-#define PSM_REF					47
-#define GEM0_RX					48
-#define GEM0_TX					49
-#define GEM1_RX					50
-#define GEM1_TX					51
-#define CPM_CORE_REF				52
-#define CPM_LSBUS_REF				53
-#define CPM_DBG_REF				54
-#define CPM_AUX0_REF				55
-#define CPM_AUX1_REF				56
-#define QSPI_REF				57
-#define OSPI_REF				58
-#define SDIO0_REF				59
-#define SDIO1_REF				60
-#define PMC_LSBUS_REF				61
-#define I2C_REF					62
-#define TEST_PATTERN_REF			63
-#define DFT_OSC_REF				64
-#define PMC_PL0_REF				65
-#define PMC_PL1_REF				66
-#define PMC_PL2_REF				67
-#define PMC_PL3_REF				68
-#define CFU_REF					69
-#define SPARE_REF				70
-#define NPI_REF					71
-#define HSM0_REF				72
-#define HSM1_REF				73
-#define SD_DLL_REF				74
-#define FPD_TOP_SWITCH				75
-#define FPD_LSBUS				76
-#define ACPU					77
-#define DBG_TRACE				78
-#define DBG_FPD					79
-#define LPD_TOP_SWITCH				80
-#define ADMA					81
-#define LPD_LSBUS				82
-#define CPU_R5					83
-#define CPU_R5_CORE				84
-#define CPU_R5_OCM				85
-#define CPU_R5_OCM2				86
-#define IOU_SWITCH				87
-#define GEM0_REF				88
-#define GEM1_REF				89
-#define GEM_TSU_REF				90
-#define USB0_BUS_REF				91
-#define UART0_REF				92
-#define UART1_REF				93
-#define SPI0_REF				94
-#define SPI1_REF				95
-#define CAN0_REF				96
-#define CAN1_REF				97
-#define I2C0_REF				98
-#define I2C1_REF				99
-#define DBG_LPD					100
-#define TIMESTAMP_REF				101
-#define DBG_TSTMP				102
-#define CPM_TOPSW_REF				103
-#define USB3_DUAL_REF				104
-#define OUTCLK_MAX				105
-#define REF_CLK					106
-#define PL_ALT_REF_CLK				107
-#define MUXED_IRO				108
-#define PL_EXT					109
-#define PL_LB					110
-#define MIO_50_OR_51				111
-#define MIO_24_OR_25				112
-
-#endif
diff --git a/include/dt-bindings/clock/xlnx-zynqmp-clk.h b/include/dt-bindings/clock/xlnx-zynqmp-clk.h
deleted file mode 100644
index f0f7ddd3dcbd..000000000000
--- a/include/dt-bindings/clock/xlnx-zynqmp-clk.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Xilinx Zynq MPSoC Firmware layer
- *
- *  Copyright (C) 2014-2018 Xilinx, Inc.
- *
- */
-
-#ifndef _DT_BINDINGS_CLK_ZYNQMP_H
-#define _DT_BINDINGS_CLK_ZYNQMP_H
-
-/*
- * These bindings are deprecated, because they do not match the actual
- * concept of bindings but rather contain pure firmware values.
- * Instead include the header in the DTS source directory.
- */
-#warning "These bindings are deprecated. Instead use the header in the DTS source directory."
-
-#define IOPLL			0
-#define RPLL			1
-#define APLL			2
-#define DPLL			3
-#define VPLL			4
-#define IOPLL_TO_FPD		5
-#define RPLL_TO_FPD		6
-#define APLL_TO_LPD		7
-#define DPLL_TO_LPD		8
-#define VPLL_TO_LPD		9
-#define ACPU			10
-#define ACPU_HALF		11
-#define DBF_FPD			12
-#define DBF_LPD			13
-#define DBG_TRACE		14
-#define DBG_TSTMP		15
-#define DP_VIDEO_REF		16
-#define DP_AUDIO_REF		17
-#define DP_STC_REF		18
-#define GDMA_REF		19
-#define DPDMA_REF		20
-#define DDR_REF			21
-#define SATA_REF		22
-#define PCIE_REF		23
-#define GPU_REF			24
-#define GPU_PP0_REF		25
-#define GPU_PP1_REF		26
-#define TOPSW_MAIN		27
-#define TOPSW_LSBUS		28
-#define GTGREF0_REF		29
-#define LPD_SWITCH		30
-#define LPD_LSBUS		31
-#define USB0_BUS_REF		32
-#define USB1_BUS_REF		33
-#define USB3_DUAL_REF		34
-#define USB0			35
-#define USB1			36
-#define CPU_R5			37
-#define CPU_R5_CORE		38
-#define CSU_SPB			39
-#define CSU_PLL			40
-#define PCAP			41
-#define IOU_SWITCH		42
-#define GEM_TSU_REF		43
-#define GEM_TSU			44
-#define GEM0_TX			45
-#define GEM1_TX			46
-#define GEM2_TX			47
-#define GEM3_TX			48
-#define GEM0_RX			49
-#define GEM1_RX			50
-#define GEM2_RX			51
-#define GEM3_RX			52
-#define QSPI_REF		53
-#define SDIO0_REF		54
-#define SDIO1_REF		55
-#define UART0_REF		56
-#define UART1_REF		57
-#define SPI0_REF		58
-#define SPI1_REF		59
-#define NAND_REF		60
-#define I2C0_REF		61
-#define I2C1_REF		62
-#define CAN0_REF		63
-#define CAN1_REF		64
-#define CAN0			65
-#define CAN1			66
-#define DLL_REF			67
-#define ADMA_REF		68
-#define TIMESTAMP_REF		69
-#define AMS_REF			70
-#define PL0_REF			71
-#define PL1_REF			72
-#define PL2_REF			73
-#define PL3_REF			74
-#define WDT			75
-#define IOPLL_INT		76
-#define IOPLL_PRE_SRC		77
-#define IOPLL_HALF		78
-#define IOPLL_INT_MUX		79
-#define IOPLL_POST_SRC		80
-#define RPLL_INT		81
-#define RPLL_PRE_SRC		82
-#define RPLL_HALF		83
-#define RPLL_INT_MUX		84
-#define RPLL_POST_SRC		85
-#define APLL_INT		86
-#define APLL_PRE_SRC		87
-#define APLL_HALF		88
-#define APLL_INT_MUX		89
-#define APLL_POST_SRC		90
-#define DPLL_INT		91
-#define DPLL_PRE_SRC		92
-#define DPLL_HALF		93
-#define DPLL_INT_MUX		94
-#define DPLL_POST_SRC		95
-#define VPLL_INT		96
-#define VPLL_PRE_SRC		97
-#define VPLL_HALF		98
-#define VPLL_INT_MUX		99
-#define VPLL_POST_SRC		100
-#define CAN0_MIO		101
-#define CAN1_MIO		102
-#define ACPU_FULL		103
-#define GEM0_REF		104
-#define GEM1_REF		105
-#define GEM2_REF		106
-#define GEM3_REF		107
-#define GEM0_REF_UNG		108
-#define GEM1_REF_UNG		109
-#define GEM2_REF_UNG		110
-#define GEM3_REF_UNG		111
-#define LPD_WDT			112
-
-#endif
diff --git a/include/dt-bindings/dma/jz4775-dma.h b/include/dt-bindings/dma/jz4775-dma.h
deleted file mode 100644
index 8d27e2c69dca..000000000000
--- a/include/dt-bindings/dma/jz4775-dma.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * This header provides macros for JZ4775 DMA bindings.
- *
- * Copyright (c) 2020 ??? (Zhou Yanjie) <zhouyanjie at wanyeetech.com>
- */
-
-#ifndef __DT_BINDINGS_DMA_JZ4775_DMA_H__
-#define __DT_BINDINGS_DMA_JZ4775_DMA_H__
-
-/*
- * Request type numbers for the JZ4775 DMA controller (written to the DRTn
- * register for the channel).
- */
-#define JZ4775_DMA_I2S0_TX	0x6
-#define JZ4775_DMA_I2S0_RX	0x7
-#define JZ4775_DMA_AUTO		0x8
-#define JZ4775_DMA_SADC_RX	0x9
-#define JZ4775_DMA_UART3_TX	0x0e
-#define JZ4775_DMA_UART3_RX	0x0f
-#define JZ4775_DMA_UART2_TX	0x10
-#define JZ4775_DMA_UART2_RX	0x11
-#define JZ4775_DMA_UART1_TX	0x12
-#define JZ4775_DMA_UART1_RX	0x13
-#define JZ4775_DMA_UART0_TX	0x14
-#define JZ4775_DMA_UART0_RX	0x15
-#define JZ4775_DMA_SSI0_TX	0x16
-#define JZ4775_DMA_SSI0_RX	0x17
-#define JZ4775_DMA_MSC0_TX	0x1a
-#define JZ4775_DMA_MSC0_RX	0x1b
-#define JZ4775_DMA_MSC1_TX	0x1c
-#define JZ4775_DMA_MSC1_RX	0x1d
-#define JZ4775_DMA_MSC2_TX	0x1e
-#define JZ4775_DMA_MSC2_RX	0x1f
-#define JZ4775_DMA_PCM0_TX	0x20
-#define JZ4775_DMA_PCM0_RX	0x21
-#define JZ4775_DMA_SMB0_TX	0x24
-#define JZ4775_DMA_SMB0_RX	0x25
-#define JZ4775_DMA_SMB1_TX	0x26
-#define JZ4775_DMA_SMB1_RX	0x27
-#define JZ4775_DMA_SMB2_TX	0x28
-#define JZ4775_DMA_SMB2_RX	0x29
-
-#endif /* __DT_BINDINGS_DMA_JZ4775_DMA_H__ */
diff --git a/include/dt-bindings/dma/x2000-dma.h b/include/dt-bindings/dma/x2000-dma.h
deleted file mode 100644
index db2cd4830b00..000000000000
--- a/include/dt-bindings/dma/x2000-dma.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * This header provides macros for X2000 DMA bindings.
- *
- * Copyright (c) 2020 ??? (Zhou Yanjie) <zhouyanjie at wanyeetech.com>
- */
-
-#ifndef __DT_BINDINGS_DMA_X2000_DMA_H__
-#define __DT_BINDINGS_DMA_X2000_DMA_H__
-
-/*
- * Request type numbers for the X2000 DMA controller (written to the DRTn
- * register for the channel).
- */
-#define X2000_DMA_AUTO		0x8
-#define X2000_DMA_UART5_TX	0xa
-#define X2000_DMA_UART5_RX	0xb
-#define X2000_DMA_UART4_TX	0xc
-#define X2000_DMA_UART4_RX	0xd
-#define X2000_DMA_UART3_TX	0xe
-#define X2000_DMA_UART3_RX	0xf
-#define X2000_DMA_UART2_TX	0x10
-#define X2000_DMA_UART2_RX	0x11
-#define X2000_DMA_UART1_TX	0x12
-#define X2000_DMA_UART1_RX	0x13
-#define X2000_DMA_UART0_TX	0x14
-#define X2000_DMA_UART0_RX	0x15
-#define X2000_DMA_SSI0_TX	0x16
-#define X2000_DMA_SSI0_RX	0x17
-#define X2000_DMA_SSI1_TX	0x18
-#define X2000_DMA_SSI1_RX	0x19
-#define X2000_DMA_I2C0_TX	0x24
-#define X2000_DMA_I2C0_RX	0x25
-#define X2000_DMA_I2C1_TX	0x26
-#define X2000_DMA_I2C1_RX	0x27
-#define X2000_DMA_I2C2_TX	0x28
-#define X2000_DMA_I2C2_RX	0x29
-#define X2000_DMA_I2C3_TX	0x2a
-#define X2000_DMA_I2C3_RX	0x2b
-#define X2000_DMA_I2C4_TX	0x2c
-#define X2000_DMA_I2C4_RX	0x2d
-#define X2000_DMA_I2C5_TX	0x2e
-#define X2000_DMA_I2C5_RX	0x2f
-#define X2000_DMA_UART6_TX	0x30
-#define X2000_DMA_UART6_RX	0x31
-#define X2000_DMA_UART7_TX	0x32
-#define X2000_DMA_UART7_RX	0x33
-#define X2000_DMA_UART8_TX	0x34
-#define X2000_DMA_UART8_RX	0x35
-#define X2000_DMA_UART9_TX	0x36
-#define X2000_DMA_UART9_RX	0x37
-#define X2000_DMA_SADC_RX	0x38
-
-#endif /* __DT_BINDINGS_DMA_X2000_DMA_H__ */
diff --git a/include/dt-bindings/gce/mt6779-gce.h b/include/dt-bindings/gce/mt6779-gce.h
deleted file mode 100644
index 06101316ace4..000000000000
--- a/include/dt-bindings/gce/mt6779-gce.h
+++ /dev/null
@@ -1,222 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2019 MediaTek Inc.
- * Author: Dennis-YC Hsieh <dennis-yc.hsieh at mediatek.com>
- */
-
-#ifndef _DT_BINDINGS_GCE_MT6779_H
-#define _DT_BINDINGS_GCE_MT6779_H
-
-#define CMDQ_NO_TIMEOUT		0xffffffff
-
-/* GCE HW thread priority */
-#define CMDQ_THR_PRIO_LOWEST	0
-#define CMDQ_THR_PRIO_1		1
-#define CMDQ_THR_PRIO_2		2
-#define CMDQ_THR_PRIO_3		3
-#define CMDQ_THR_PRIO_4		4
-#define CMDQ_THR_PRIO_5		5
-#define CMDQ_THR_PRIO_6		6
-#define CMDQ_THR_PRIO_HIGHEST	7
-
-/* GCE subsys table */
-#define SUBSYS_1300XXXX		0
-#define SUBSYS_1400XXXX		1
-#define SUBSYS_1401XXXX		2
-#define SUBSYS_1402XXXX		3
-#define SUBSYS_1502XXXX		4
-#define SUBSYS_1880XXXX		5
-#define SUBSYS_1881XXXX		6
-#define SUBSYS_1882XXXX		7
-#define SUBSYS_1883XXXX		8
-#define SUBSYS_1884XXXX		9
-#define SUBSYS_1000XXXX		10
-#define SUBSYS_1001XXXX		11
-#define SUBSYS_1002XXXX		12
-#define SUBSYS_1003XXXX		13
-#define SUBSYS_1004XXXX		14
-#define SUBSYS_1005XXXX		15
-#define SUBSYS_1020XXXX		16
-#define SUBSYS_1028XXXX		17
-#define SUBSYS_1700XXXX		18
-#define SUBSYS_1701XXXX		19
-#define SUBSYS_1702XXXX		20
-#define SUBSYS_1703XXXX		21
-#define SUBSYS_1800XXXX		22
-#define SUBSYS_1801XXXX		23
-#define SUBSYS_1802XXXX		24
-#define SUBSYS_1804XXXX		25
-#define SUBSYS_1805XXXX		26
-#define SUBSYS_1808XXXX		27
-#define SUBSYS_180aXXXX		28
-#define SUBSYS_180bXXXX		29
-#define CMDQ_SUBSYS_OFF		32
-
-/* GCE hardware events */
-#define CMDQ_EVENT_DISP_RDMA0_SOF		0
-#define CMDQ_EVENT_DISP_RDMA1_SOF		1
-#define CMDQ_EVENT_MDP_RDMA0_SOF		2
-#define CMDQ_EVENT_MDP_RDMA1_SOF		3
-#define CMDQ_EVENT_MDP_RSZ0_SOF			4
-#define CMDQ_EVENT_MDP_RSZ1_SOF			5
-#define CMDQ_EVENT_MDP_TDSHP_SOF		6
-#define CMDQ_EVENT_MDP_WROT0_SOF		7
-#define CMDQ_EVENT_MDP_WROT1_SOF		8
-#define CMDQ_EVENT_DISP_OVL0_SOF		9
-#define CMDQ_EVENT_DISP_2L_OVL0_SOF		10
-#define CMDQ_EVENT_DISP_2L_OVL1_SOF		11
-#define CMDQ_EVENT_DISP_WDMA0_SOF		12
-#define CMDQ_EVENT_DISP_COLOR0_SOF		13
-#define CMDQ_EVENT_DISP_CCORR0_SOF		14
-#define CMDQ_EVENT_DISP_AAL0_SOF		15
-#define CMDQ_EVENT_DISP_GAMMA0_SOF		16
-#define CMDQ_EVENT_DISP_DITHER0_SOF		17
-#define CMDQ_EVENT_DISP_PWM0_SOF		18
-#define CMDQ_EVENT_DISP_DSI0_SOF		19
-#define CMDQ_EVENT_DISP_DPI0_SOF		20
-#define CMDQ_EVENT_DISP_POSTMASK0_SOF		21
-#define CMDQ_EVENT_DISP_RSZ0_SOF		22
-#define CMDQ_EVENT_MDP_AAL_SOF			23
-#define CMDQ_EVENT_MDP_CCORR_SOF		24
-#define CMDQ_EVENT_DISP_DBI0_SOF		25
-#define CMDQ_EVENT_ISP_RELAY_SOF		26
-#define CMDQ_EVENT_IPU_RELAY_SOF		27
-#define CMDQ_EVENT_DISP_RDMA0_EOF		28
-#define CMDQ_EVENT_DISP_RDMA1_EOF		29
-#define CMDQ_EVENT_MDP_RDMA0_EOF		30
-#define CMDQ_EVENT_MDP_RDMA1_EOF		31
-#define CMDQ_EVENT_MDP_RSZ0_EOF			32
-#define CMDQ_EVENT_MDP_RSZ1_EOF			33
-#define CMDQ_EVENT_MDP_TDSHP_EOF		34
-#define CMDQ_EVENT_MDP_WROT0_W_EOF		35
-#define CMDQ_EVENT_MDP_WROT1_W_EOF		36
-#define CMDQ_EVENT_DISP_OVL0_EOF		37
-#define CMDQ_EVENT_DISP_2L_OVL0_EOF		38
-#define CMDQ_EVENT_DISP_2L_OVL1_EOF		39
-#define CMDQ_EVENT_DISP_WDMA0_EOF		40
-#define CMDQ_EVENT_DISP_COLOR0_EOF		41
-#define CMDQ_EVENT_DISP_CCORR0_EOF		42
-#define CMDQ_EVENT_DISP_AAL0_EOF		43
-#define CMDQ_EVENT_DISP_GAMMA0_EOF		44
-#define CMDQ_EVENT_DISP_DITHER0_EOF		45
-#define CMDQ_EVENT_DISP_DSI0_EOF		46
-#define CMDQ_EVENT_DISP_DPI0_EOF		47
-#define CMDQ_EVENT_DISP_RSZ0_EOF		49
-#define CMDQ_EVENT_MDP_AAL_FRAME_DONE		50
-#define CMDQ_EVENT_MDP_CCORR_FRAME_DONE		51
-#define CMDQ_EVENT_DISP_POSTMASK0_FRAME_DONE	52
-#define CMDQ_EVENT_MUTEX0_STREAM_EOF		130
-#define CMDQ_EVENT_MUTEX1_STREAM_EOF		131
-#define CMDQ_EVENT_MUTEX2_STREAM_EOF		132
-#define CMDQ_EVENT_MUTEX3_STREAM_EOF		133
-#define CMDQ_EVENT_MUTEX4_STREAM_EOF		134
-#define CMDQ_EVENT_MUTEX5_STREAM_EOF		135
-#define CMDQ_EVENT_MUTEX6_STREAM_EOF		136
-#define CMDQ_EVENT_MUTEX7_STREAM_EOF		137
-#define CMDQ_EVENT_MUTEX8_STREAM_EOF		138
-#define CMDQ_EVENT_MUTEX9_STREAM_EOF		139
-#define CMDQ_EVENT_MUTEX10_STREAM_EOF		140
-#define CMDQ_EVENT_MUTEX11_STREAM_EOF		141
-#define CMDQ_EVENT_DISP_RDMA0_UNDERRUN		142
-#define CMDQ_EVENT_DISP_RDMA1_UNDERRUN		143
-#define CMDQ_EVENT_DISP_RDMA2_UNDERRUN		144
-#define CMDQ_EVENT_DISP_RDMA3_UNDERRUN		145
-#define CMDQ_EVENT_DSI0_TE			146
-#define CMDQ_EVENT_DSI0_IRQ_EVENT		147
-#define CMDQ_EVENT_DSI0_DONE_EVENT		148
-#define CMDQ_EVENT_DISP_POSTMASK0_RST_DONE	150
-#define CMDQ_EVENT_DISP_WDMA0_RST_DONE		151
-#define CMDQ_EVENT_MDP_WROT0_RST_DONE		153
-#define CMDQ_EVENT_MDP_RDMA0_RST_DONE		154
-#define CMDQ_EVENT_DISP_OVL0_RST_DONE		155
-#define CMDQ_EVENT_DISP_OVL0_2L_RST_DONE	156
-#define CMDQ_EVENT_DISP_OVL1_2L_RST_DONE	157
-#define CMDQ_EVENT_DIP_CQ_THREAD0_EOF		257
-#define CMDQ_EVENT_DIP_CQ_THREAD1_EOF		258
-#define CMDQ_EVENT_DIP_CQ_THREAD2_EOF		259
-#define CMDQ_EVENT_DIP_CQ_THREAD3_EOF		260
-#define CMDQ_EVENT_DIP_CQ_THREAD4_EOF		261
-#define CMDQ_EVENT_DIP_CQ_THREAD5_EOF		262
-#define CMDQ_EVENT_DIP_CQ_THREAD6_EOF		263
-#define CMDQ_EVENT_DIP_CQ_THREAD7_EOF		264
-#define CMDQ_EVENT_DIP_CQ_THREAD8_EOF		265
-#define CMDQ_EVENT_DIP_CQ_THREAD9_EOF		266
-#define CMDQ_EVENT_DIP_CQ_THREAD10_EOF		267
-#define CMDQ_EVENT_DIP_CQ_THREAD11_EOF		268
-#define CMDQ_EVENT_DIP_CQ_THREAD12_EOF		269
-#define CMDQ_EVENT_DIP_CQ_THREAD13_EOF		270
-#define CMDQ_EVENT_DIP_CQ_THREAD14_EOF		271
-#define CMDQ_EVENT_DIP_CQ_THREAD15_EOF		272
-#define CMDQ_EVENT_DIP_CQ_THREAD16_EOF		273
-#define CMDQ_EVENT_DIP_CQ_THREAD17_EOF		274
-#define CMDQ_EVENT_DIP_CQ_THREAD18_EOF		275
-#define CMDQ_EVENT_DIP_DMA_ERR_EVENT		276
-#define CMDQ_EVENT_AMD_FRAME_DONE		277
-#define CMDQ_EVENT_MFB_DONE			278
-#define CMDQ_EVENT_WPE_A_EOF			279
-#define CMDQ_EVENT_VENC_EOF			289
-#define CMDQ_EVENT_VENC_CMDQ_PAUSE_DONE		290
-#define CMDQ_EVENT_JPEG_ENC_EOF			291
-#define CMDQ_EVENT_VENC_MB_DONE			292
-#define CMDQ_EVENT_VENC_128BYTE_CNT_DONE	293
-#define CMDQ_EVENT_ISP_FRAME_DONE_A		321
-#define CMDQ_EVENT_ISP_FRAME_DONE_B		322
-#define CMDQ_EVENT_ISP_FRAME_DONE_C		323
-#define CMDQ_EVENT_ISP_CAMSV_0_PASS1_DONE	324
-#define CMDQ_EVENT_ISP_CAMSV_0_2_PASS1_DONE	325
-#define CMDQ_EVENT_ISP_CAMSV_1_PASS1_DONE	326
-#define CMDQ_EVENT_ISP_CAMSV_2_PASS1_DONE	327
-#define CMDQ_EVENT_ISP_CAMSV_3_PASS1_DONE	328
-#define CMDQ_EVENT_ISP_TSF_DONE			329
-#define CMDQ_EVENT_SENINF_0_FIFO_FULL		330
-#define CMDQ_EVENT_SENINF_1_FIFO_FULL		331
-#define CMDQ_EVENT_SENINF_2_FIFO_FULL		332
-#define CMDQ_EVENT_SENINF_3_FIFO_FULL		333
-#define CMDQ_EVENT_SENINF_4_FIFO_FULL		334
-#define CMDQ_EVENT_SENINF_5_FIFO_FULL		335
-#define CMDQ_EVENT_SENINF_6_FIFO_FULL		336
-#define CMDQ_EVENT_SENINF_7_FIFO_FULL		337
-#define CMDQ_EVENT_TG_OVRUN_A_INT_DLY		338
-#define CMDQ_EVENT_TG_OVRUN_B_INT_DLY		339
-#define CMDQ_EVENT_TG_OVRUN_C_INT		340
-#define CMDQ_EVENT_TG_GRABERR_A_INT_DLY		341
-#define CMDQ_EVENT_TG_GRABERR_B_INT_DLY		342
-#define CMDQ_EVENT_TG_GRABERR_C_INT		343
-#define CMDQ_EVENT_CQ_VR_SNAP_A_INT_DLY		344
-#define CMDQ_EVENT_CQ_VR_SNAP_B_INT_DLY		345
-#define CMDQ_EVENT_CQ_VR_SNAP_C_INT		346
-#define CMDQ_EVENT_DMA_R1_ERROR_A_INT_DLY	347
-#define CMDQ_EVENT_DMA_R1_ERROR_B_INT_DLY	348
-#define CMDQ_EVENT_DMA_R1_ERROR_C_INT		349
-#define CMDQ_EVENT_APU_GCE_CORE0_EVENT_0	353
-#define CMDQ_EVENT_APU_GCE_CORE0_EVENT_1	354
-#define CMDQ_EVENT_APU_GCE_CORE0_EVENT_2	355
-#define CMDQ_EVENT_APU_GCE_CORE0_EVENT_3	356
-#define CMDQ_EVENT_APU_GCE_CORE1_EVENT_0	385
-#define CMDQ_EVENT_APU_GCE_CORE1_EVENT_1	386
-#define CMDQ_EVENT_APU_GCE_CORE1_EVENT_2	387
-#define CMDQ_EVENT_APU_GCE_CORE1_EVENT_3	388
-#define CMDQ_EVENT_VDEC_EVENT_0			416
-#define CMDQ_EVENT_VDEC_EVENT_1			417
-#define CMDQ_EVENT_VDEC_EVENT_2			418
-#define CMDQ_EVENT_VDEC_EVENT_3			419
-#define CMDQ_EVENT_VDEC_EVENT_4			420
-#define CMDQ_EVENT_VDEC_EVENT_5			421
-#define CMDQ_EVENT_VDEC_EVENT_6			422
-#define CMDQ_EVENT_VDEC_EVENT_7			423
-#define CMDQ_EVENT_VDEC_EVENT_8			424
-#define CMDQ_EVENT_VDEC_EVENT_9			425
-#define CMDQ_EVENT_VDEC_EVENT_10		426
-#define CMDQ_EVENT_VDEC_EVENT_11		427
-#define CMDQ_EVENT_VDEC_EVENT_12		428
-#define CMDQ_EVENT_VDEC_EVENT_13		429
-#define CMDQ_EVENT_VDEC_EVENT_14		430
-#define CMDQ_EVENT_VDEC_EVENT_15		431
-#define CMDQ_EVENT_FDVT_DONE			449
-#define CMDQ_EVENT_FE_DONE			450
-#define CMDQ_EVENT_RSC_EOF			451
-#define CMDQ_EVENT_DVS_DONE_ASYNC_SHOT		452
-#define CMDQ_EVENT_DVP_DONE_ASYNC_SHOT		453
-#define CMDQ_EVENT_DSI0_TE_INFRA		898
-
-#endif
diff --git a/include/dt-bindings/iio/qcom,spmi-adc7-pmr735b.h b/include/dt-bindings/iio/qcom,spmi-adc7-pmr735b.h
deleted file mode 100644
index fdb8dd9ae541..000000000000
--- a/include/dt-bindings/iio/qcom,spmi-adc7-pmr735b.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (c) 2020 The Linux Foundation. All rights reserved.
- */
-
-#ifndef _DT_BINDINGS_QCOM_SPMI_VADC_PMR735B_H
-#define _DT_BINDINGS_QCOM_SPMI_VADC_PMR735B_H
-
-#ifndef PMR735B_SID
-#define PMR735B_SID					5
-#endif
-
-#include <dt-bindings/iio/qcom,spmi-vadc.h>
-
-/* ADC channels for PMR735B_ADC for PMIC7 */
-#define PMR735B_ADC7_REF_GND			(PMR735B_SID << 8 | ADC7_REF_GND)
-#define PMR735B_ADC7_1P25VREF			(PMR735B_SID << 8 | ADC7_1P25VREF)
-#define PMR735B_ADC7_VREF_VADC			(PMR735B_SID << 8 | ADC7_VREF_VADC)
-#define PMR735B_ADC7_DIE_TEMP			(PMR735B_SID << 8 | ADC7_DIE_TEMP)
-
-#define PMR735B_ADC7_GPIO1			(PMR735B_SID << 8 | ADC7_GPIO1)
-#define PMR735B_ADC7_GPIO2			(PMR735B_SID << 8 | ADC7_GPIO2)
-#define PMR735B_ADC7_GPIO3			(PMR735B_SID << 8 | ADC7_GPIO3)
-
-/* 100k pull-up2 */
-#define PMR735B_ADC7_GPIO1_100K_PU		(PMR735B_SID << 8 | ADC7_GPIO1_100K_PU)
-#define PMR735B_ADC7_GPIO2_100K_PU		(PMR735B_SID << 8 | ADC7_GPIO2_100K_PU)
-#define PMR735B_ADC7_GPIO3_100K_PU		(PMR735B_SID << 8 | ADC7_GPIO3_100K_PU)
-
-#endif /* _DT_BINDINGS_QCOM_SPMI_VADC_PMR735B_H */
diff --git a/include/dt-bindings/iio/qcom,spmi-adc7-smb139x.h b/include/dt-bindings/iio/qcom,spmi-adc7-smb139x.h
deleted file mode 100644
index c0680d1285cf..000000000000
--- a/include/dt-bindings/iio/qcom,spmi-adc7-smb139x.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */
-/*
- * Copyright (c) 2020 The Linux Foundation. All rights reserved.
- */
-
-#ifndef _DT_BINDINGS_QCOM_SPMI_VADC_SMB139X_H
-#define _DT_BINDINGS_QCOM_SPMI_VADC_SMB139X_H
-
-#include <dt-bindings/iio/qcom,spmi-vadc.h>
-
-#define SMB139x_1_ADC7_SMB_TEMP			(SMB139x_1_SID << 8 | ADC7_SMB_TEMP)
-#define SMB139x_1_ADC7_ICHG_SMB			(SMB139x_1_SID << 8 | ADC7_ICHG_SMB)
-#define SMB139x_1_ADC7_IIN_SMB			(SMB139x_1_SID << 8 | ADC7_IIN_SMB)
-
-#define SMB139x_2_ADC7_SMB_TEMP			(SMB139x_2_SID << 8 | ADC7_SMB_TEMP)
-#define SMB139x_2_ADC7_ICHG_SMB			(SMB139x_2_SID << 8 | ADC7_ICHG_SMB)
-#define SMB139x_2_ADC7_IIN_SMB			(SMB139x_2_SID << 8 | ADC7_IIN_SMB)
-
-#endif
diff --git a/include/dt-bindings/memory/mt6779-larb-port.h b/include/dt-bindings/memory/mt6779-larb-port.h
deleted file mode 100644
index 3fb438a96e35..000000000000
--- a/include/dt-bindings/memory/mt6779-larb-port.h
+++ /dev/null
@@ -1,206 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2019 MediaTek Inc.
- * Author: Chao Hao <chao.hao at mediatek.com>
- */
-
-#ifndef _DT_BINDINGS_MEMORY_MT6779_LARB_PORT_H_
-#define _DT_BINDINGS_MEMORY_MT6779_LARB_PORT_H_
-
-#include <dt-bindings/memory/mtk-memory-port.h>
-
-#define M4U_LARB0_ID			 0
-#define M4U_LARB1_ID			 1
-#define M4U_LARB2_ID			 2
-#define M4U_LARB3_ID			 3
-#define M4U_LARB4_ID			 4
-#define M4U_LARB5_ID			 5
-#define M4U_LARB6_ID			 6
-#define M4U_LARB7_ID			 7
-#define M4U_LARB8_ID			 8
-#define M4U_LARB9_ID			 9
-#define M4U_LARB10_ID			 10
-#define M4U_LARB11_ID			 11
-
-/* larb0 */
-#define M4U_PORT_DISP_POSTMASK0		 MTK_M4U_ID(M4U_LARB0_ID, 0)
-#define M4U_PORT_DISP_OVL0_HDR		 MTK_M4U_ID(M4U_LARB0_ID, 1)
-#define M4U_PORT_DISP_OVL1_HDR		 MTK_M4U_ID(M4U_LARB0_ID, 2)
-#define M4U_PORT_DISP_OVL0		 MTK_M4U_ID(M4U_LARB0_ID, 3)
-#define M4U_PORT_DISP_OVL1		 MTK_M4U_ID(M4U_LARB0_ID, 4)
-#define M4U_PORT_DISP_PVRIC0		 MTK_M4U_ID(M4U_LARB0_ID, 5)
-#define M4U_PORT_DISP_RDMA0		 MTK_M4U_ID(M4U_LARB0_ID, 6)
-#define M4U_PORT_DISP_WDMA0		 MTK_M4U_ID(M4U_LARB0_ID, 7)
-#define M4U_PORT_DISP_FAKE0		 MTK_M4U_ID(M4U_LARB0_ID, 8)
-
-/* larb1 */
-#define M4U_PORT_DISP_OVL0_2L_HDR	 MTK_M4U_ID(M4U_LARB1_ID, 0)
-#define M4U_PORT_DISP_OVL1_2L_HDR	 MTK_M4U_ID(M4U_LARB1_ID, 1)
-#define M4U_PORT_DISP_OVL0_2L		 MTK_M4U_ID(M4U_LARB1_ID, 2)
-#define M4U_PORT_DISP_OVL1_2L		 MTK_M4U_ID(M4U_LARB1_ID, 3)
-#define M4U_PORT_DISP_RDMA1		 MTK_M4U_ID(M4U_LARB1_ID, 4)
-#define M4U_PORT_MDP_PVRIC0		 MTK_M4U_ID(M4U_LARB1_ID, 5)
-#define M4U_PORT_MDP_PVRIC1		 MTK_M4U_ID(M4U_LARB1_ID, 6)
-#define M4U_PORT_MDP_RDMA0		 MTK_M4U_ID(M4U_LARB1_ID, 7)
-#define M4U_PORT_MDP_RDMA1		 MTK_M4U_ID(M4U_LARB1_ID, 8)
-#define M4U_PORT_MDP_WROT0_R		 MTK_M4U_ID(M4U_LARB1_ID, 9)
-#define M4U_PORT_MDP_WROT0_W		 MTK_M4U_ID(M4U_LARB1_ID, 10)
-#define M4U_PORT_MDP_WROT1_R		 MTK_M4U_ID(M4U_LARB1_ID, 11)
-#define M4U_PORT_MDP_WROT1_W		 MTK_M4U_ID(M4U_LARB1_ID, 12)
-#define M4U_PORT_DISP_FAKE1		 MTK_M4U_ID(M4U_LARB1_ID, 13)
-
-/* larb2-VDEC */
-#define M4U_PORT_HW_VDEC_MC_EXT          MTK_M4U_ID(M4U_LARB2_ID, 0)
-#define M4U_PORT_HW_VDEC_UFO_EXT         MTK_M4U_ID(M4U_LARB2_ID, 1)
-#define M4U_PORT_HW_VDEC_PP_EXT          MTK_M4U_ID(M4U_LARB2_ID, 2)
-#define M4U_PORT_HW_VDEC_PRED_RD_EXT     MTK_M4U_ID(M4U_LARB2_ID, 3)
-#define M4U_PORT_HW_VDEC_PRED_WR_EXT     MTK_M4U_ID(M4U_LARB2_ID, 4)
-#define M4U_PORT_HW_VDEC_PPWRAP_EXT      MTK_M4U_ID(M4U_LARB2_ID, 5)
-#define M4U_PORT_HW_VDEC_TILE_EXT        MTK_M4U_ID(M4U_LARB2_ID, 6)
-#define M4U_PORT_HW_VDEC_VLD_EXT         MTK_M4U_ID(M4U_LARB2_ID, 7)
-#define M4U_PORT_HW_VDEC_VLD2_EXT        MTK_M4U_ID(M4U_LARB2_ID, 8)
-#define M4U_PORT_HW_VDEC_AVC_MV_EXT      MTK_M4U_ID(M4U_LARB2_ID, 9)
-#define M4U_PORT_HW_VDEC_UFO_ENC_EXT     MTK_M4U_ID(M4U_LARB2_ID, 10)
-#define M4U_PORT_HW_VDEC_RG_CTRL_DMA_EXT MTK_M4U_ID(M4U_LARB2_ID, 11)
-
-/* larb3-VENC */
-#define M4U_PORT_VENC_RCPU		 MTK_M4U_ID(M4U_LARB3_ID, 0)
-#define M4U_PORT_VENC_REC		 MTK_M4U_ID(M4U_LARB3_ID, 1)
-#define M4U_PORT_VENC_BSDMA		 MTK_M4U_ID(M4U_LARB3_ID, 2)
-#define M4U_PORT_VENC_SV_COMV		 MTK_M4U_ID(M4U_LARB3_ID, 3)
-#define M4U_PORT_VENC_RD_COMV		 MTK_M4U_ID(M4U_LARB3_ID, 4)
-#define M4U_PORT_VENC_NBM_RDMA		 MTK_M4U_ID(M4U_LARB3_ID, 5)
-#define M4U_PORT_VENC_NBM_RDMA_LITE	 MTK_M4U_ID(M4U_LARB3_ID, 6)
-#define M4U_PORT_JPGENC_Y_RDMA		 MTK_M4U_ID(M4U_LARB3_ID, 7)
-#define M4U_PORT_JPGENC_C_RDMA		 MTK_M4U_ID(M4U_LARB3_ID, 8)
-#define M4U_PORT_JPGENC_Q_TABLE		 MTK_M4U_ID(M4U_LARB3_ID, 9)
-#define M4U_PORT_JPGENC_BSDMA		 MTK_M4U_ID(M4U_LARB3_ID, 10)
-#define M4U_PORT_JPGDEC_WDMA		 MTK_M4U_ID(M4U_LARB3_ID, 11)
-#define M4U_PORT_JPGDEC_BSDMA		 MTK_M4U_ID(M4U_LARB3_ID, 12)
-#define M4U_PORT_VENC_NBM_WDMA		 MTK_M4U_ID(M4U_LARB3_ID, 13)
-#define M4U_PORT_VENC_NBM_WDMA_LITE	 MTK_M4U_ID(M4U_LARB3_ID, 14)
-#define M4U_PORT_VENC_CUR_LUMA		 MTK_M4U_ID(M4U_LARB3_ID, 15)
-#define M4U_PORT_VENC_CUR_CHROMA	 MTK_M4U_ID(M4U_LARB3_ID, 16)
-#define M4U_PORT_VENC_REF_LUMA		 MTK_M4U_ID(M4U_LARB3_ID, 17)
-#define M4U_PORT_VENC_REF_CHROMA	 MTK_M4U_ID(M4U_LARB3_ID, 18)
-
-/* larb4-dummy */
-
-/* larb5-IMG */
-#define M4U_PORT_IMGI_D1		 MTK_M4U_ID(M4U_LARB5_ID, 0)
-#define M4U_PORT_IMGBI_D1		 MTK_M4U_ID(M4U_LARB5_ID, 1)
-#define M4U_PORT_DMGI_D1		 MTK_M4U_ID(M4U_LARB5_ID, 2)
-#define M4U_PORT_DEPI_D1		 MTK_M4U_ID(M4U_LARB5_ID, 3)
-#define M4U_PORT_LCEI_D1		 MTK_M4U_ID(M4U_LARB5_ID, 4)
-#define M4U_PORT_SMTI_D1		 MTK_M4U_ID(M4U_LARB5_ID, 5)
-#define M4U_PORT_SMTO_D2		 MTK_M4U_ID(M4U_LARB5_ID, 6)
-#define M4U_PORT_SMTO_D1		 MTK_M4U_ID(M4U_LARB5_ID, 7)
-#define M4U_PORT_CRZO_D1		 MTK_M4U_ID(M4U_LARB5_ID, 8)
-#define M4U_PORT_IMG3O_D1		 MTK_M4U_ID(M4U_LARB5_ID, 9)
-#define M4U_PORT_VIPI_D1		 MTK_M4U_ID(M4U_LARB5_ID, 10)
-#define M4U_PORT_WPE_RDMA1		 MTK_M4U_ID(M4U_LARB5_ID, 11)
-#define M4U_PORT_WPE_RDMA0		 MTK_M4U_ID(M4U_LARB5_ID, 12)
-#define M4U_PORT_WPE_WDMA		 MTK_M4U_ID(M4U_LARB5_ID, 13)
-#define M4U_PORT_TIMGO_D1		 MTK_M4U_ID(M4U_LARB5_ID, 14)
-#define M4U_PORT_MFB_RDMA0		 MTK_M4U_ID(M4U_LARB5_ID, 15)
-#define M4U_PORT_MFB_RDMA1		 MTK_M4U_ID(M4U_LARB5_ID, 16)
-#define M4U_PORT_MFB_RDMA2		 MTK_M4U_ID(M4U_LARB5_ID, 17)
-#define M4U_PORT_MFB_RDMA3		 MTK_M4U_ID(M4U_LARB5_ID, 18)
-#define M4U_PORT_MFB_WDMA		 MTK_M4U_ID(M4U_LARB5_ID, 19)
-#define M4U_PORT_RESERVE1		 MTK_M4U_ID(M4U_LARB5_ID, 20)
-#define M4U_PORT_RESERVE2		 MTK_M4U_ID(M4U_LARB5_ID, 21)
-#define M4U_PORT_RESERVE3		 MTK_M4U_ID(M4U_LARB5_ID, 22)
-#define M4U_PORT_RESERVE4		 MTK_M4U_ID(M4U_LARB5_ID, 23)
-#define M4U_PORT_RESERVE5		 MTK_M4U_ID(M4U_LARB5_ID, 24)
-#define M4U_PORT_RESERVE6		 MTK_M4U_ID(M4U_LARB5_ID, 25)
-
-/* larb6-IMG-VPU */
-#define M4U_PORT_IMG_IPUO		 MTK_M4U_ID(M4U_LARB6_ID, 0)
-#define M4U_PORT_IMG_IPU3O		 MTK_M4U_ID(M4U_LARB6_ID, 1)
-#define M4U_PORT_IMG_IPUI		 MTK_M4U_ID(M4U_LARB6_ID, 2)
-
-/* larb7-DVS */
-#define M4U_PORT_DVS_RDMA		 MTK_M4U_ID(M4U_LARB7_ID, 0)
-#define M4U_PORT_DVS_WDMA		 MTK_M4U_ID(M4U_LARB7_ID, 1)
-#define M4U_PORT_DVP_RDMA		 MTK_M4U_ID(M4U_LARB7_ID, 2)
-#define M4U_PORT_DVP_WDMA		 MTK_M4U_ID(M4U_LARB7_ID, 3)
-
-/* larb8-IPESYS */
-#define M4U_PORT_FDVT_RDA		 MTK_M4U_ID(M4U_LARB8_ID, 0)
-#define M4U_PORT_FDVT_RDB		 MTK_M4U_ID(M4U_LARB8_ID, 1)
-#define M4U_PORT_FDVT_WRA		 MTK_M4U_ID(M4U_LARB8_ID, 2)
-#define M4U_PORT_FDVT_WRB		 MTK_M4U_ID(M4U_LARB8_ID, 3)
-#define M4U_PORT_FE_RD0			 MTK_M4U_ID(M4U_LARB8_ID, 4)
-#define M4U_PORT_FE_RD1			 MTK_M4U_ID(M4U_LARB8_ID, 5)
-#define M4U_PORT_FE_WR0			 MTK_M4U_ID(M4U_LARB8_ID, 6)
-#define M4U_PORT_FE_WR1			 MTK_M4U_ID(M4U_LARB8_ID, 7)
-#define M4U_PORT_RSC_RDMA0		 MTK_M4U_ID(M4U_LARB8_ID, 8)
-#define M4U_PORT_RSC_WDMA		 MTK_M4U_ID(M4U_LARB8_ID, 9)
-
-/* larb9-CAM */
-#define M4U_PORT_CAM_IMGO_R1_C		 MTK_M4U_ID(M4U_LARB9_ID, 0)
-#define M4U_PORT_CAM_RRZO_R1_C		 MTK_M4U_ID(M4U_LARB9_ID, 1)
-#define M4U_PORT_CAM_LSCI_R1_C		 MTK_M4U_ID(M4U_LARB9_ID, 2)
-#define M4U_PORT_CAM_BPCI_R1_C		 MTK_M4U_ID(M4U_LARB9_ID, 3)
-#define M4U_PORT_CAM_YUVO_R1_C		 MTK_M4U_ID(M4U_LARB9_ID, 4)
-#define M4U_PORT_CAM_UFDI_R2_C		 MTK_M4U_ID(M4U_LARB9_ID, 5)
-#define M4U_PORT_CAM_RAWI_R2_C		 MTK_M4U_ID(M4U_LARB9_ID, 6)
-#define M4U_PORT_CAM_RAWI_R5_C		 MTK_M4U_ID(M4U_LARB9_ID, 7)
-#define M4U_PORT_CAM_CAMSV_1		 MTK_M4U_ID(M4U_LARB9_ID, 8)
-#define M4U_PORT_CAM_CAMSV_2		 MTK_M4U_ID(M4U_LARB9_ID, 9)
-#define M4U_PORT_CAM_CAMSV_3		 MTK_M4U_ID(M4U_LARB9_ID, 10)
-#define M4U_PORT_CAM_CAMSV_4		 MTK_M4U_ID(M4U_LARB9_ID, 11)
-#define M4U_PORT_CAM_CAMSV_5		 MTK_M4U_ID(M4U_LARB9_ID, 12)
-#define M4U_PORT_CAM_CAMSV_6		 MTK_M4U_ID(M4U_LARB9_ID, 13)
-#define M4U_PORT_CAM_AAO_R1_C		 MTK_M4U_ID(M4U_LARB9_ID, 14)
-#define M4U_PORT_CAM_AFO_R1_C		 MTK_M4U_ID(M4U_LARB9_ID, 15)
-#define M4U_PORT_CAM_FLKO_R1_C		 MTK_M4U_ID(M4U_LARB9_ID, 16)
-#define M4U_PORT_CAM_LCESO_R1_C		 MTK_M4U_ID(M4U_LARB9_ID, 17)
-#define M4U_PORT_CAM_CRZO_R1_C		 MTK_M4U_ID(M4U_LARB9_ID, 18)
-#define M4U_PORT_CAM_LTMSO_R1_C		 MTK_M4U_ID(M4U_LARB9_ID, 19)
-#define M4U_PORT_CAM_RSSO_R1_C		 MTK_M4U_ID(M4U_LARB9_ID, 20)
-#define M4U_PORT_CAM_CCUI		 MTK_M4U_ID(M4U_LARB9_ID, 21)
-#define M4U_PORT_CAM_CCUO		 MTK_M4U_ID(M4U_LARB9_ID, 22)
-#define M4U_PORT_CAM_FAKE		 MTK_M4U_ID(M4U_LARB9_ID, 23)
-
-/* larb10-CAM_A */
-#define M4U_PORT_CAM_IMGO_R1_A		 MTK_M4U_ID(M4U_LARB10_ID, 0)
-#define M4U_PORT_CAM_RRZO_R1_A		 MTK_M4U_ID(M4U_LARB10_ID, 1)
-#define M4U_PORT_CAM_LSCI_R1_A		 MTK_M4U_ID(M4U_LARB10_ID, 2)
-#define M4U_PORT_CAM_BPCI_R1_A		 MTK_M4U_ID(M4U_LARB10_ID, 3)
-#define M4U_PORT_CAM_YUVO_R1_A		 MTK_M4U_ID(M4U_LARB10_ID, 4)
-#define M4U_PORT_CAM_UFDI_R2_A		 MTK_M4U_ID(M4U_LARB10_ID, 5)
-#define M4U_PORT_CAM_RAWI_R2_A		 MTK_M4U_ID(M4U_LARB10_ID, 6)
-#define M4U_PORT_CAM_RAWI_R5_A		 MTK_M4U_ID(M4U_LARB10_ID, 7)
-#define M4U_PORT_CAM_IMGO_R1_B		 MTK_M4U_ID(M4U_LARB10_ID, 8)
-#define M4U_PORT_CAM_RRZO_R1_B		 MTK_M4U_ID(M4U_LARB10_ID, 9)
-#define M4U_PORT_CAM_LSCI_R1_B		 MTK_M4U_ID(M4U_LARB10_ID, 10)
-#define M4U_PORT_CAM_BPCI_R1_B		 MTK_M4U_ID(M4U_LARB10_ID, 11)
-#define M4U_PORT_CAM_YUVO_R1_B		 MTK_M4U_ID(M4U_LARB10_ID, 12)
-#define M4U_PORT_CAM_UFDI_R2_B		 MTK_M4U_ID(M4U_LARB10_ID, 13)
-#define M4U_PORT_CAM_RAWI_R2_B		 MTK_M4U_ID(M4U_LARB10_ID, 14)
-#define M4U_PORT_CAM_RAWI_R5_B		 MTK_M4U_ID(M4U_LARB10_ID, 15)
-#define M4U_PORT_CAM_CAMSV_0		 MTK_M4U_ID(M4U_LARB10_ID, 16)
-#define M4U_PORT_CAM_AAO_R1_A		 MTK_M4U_ID(M4U_LARB10_ID, 17)
-#define M4U_PORT_CAM_AFO_R1_A		 MTK_M4U_ID(M4U_LARB10_ID, 18)
-#define M4U_PORT_CAM_FLKO_R1_A		 MTK_M4U_ID(M4U_LARB10_ID, 19)
-#define M4U_PORT_CAM_LCESO_R1_A		 MTK_M4U_ID(M4U_LARB10_ID, 20)
-#define M4U_PORT_CAM_CRZO_R1_A		 MTK_M4U_ID(M4U_LARB10_ID, 21)
-#define M4U_PORT_CAM_AAO_R1_B		 MTK_M4U_ID(M4U_LARB10_ID, 22)
-#define M4U_PORT_CAM_AFO_R1_B		 MTK_M4U_ID(M4U_LARB10_ID, 23)
-#define M4U_PORT_CAM_FLKO_R1_B		 MTK_M4U_ID(M4U_LARB10_ID, 24)
-#define M4U_PORT_CAM_LCESO_R1_B		 MTK_M4U_ID(M4U_LARB10_ID, 25)
-#define M4U_PORT_CAM_CRZO_R1_B		 MTK_M4U_ID(M4U_LARB10_ID, 26)
-#define M4U_PORT_CAM_LTMSO_R1_A		 MTK_M4U_ID(M4U_LARB10_ID, 27)
-#define M4U_PORT_CAM_RSSO_R1_A		 MTK_M4U_ID(M4U_LARB10_ID, 28)
-#define M4U_PORT_CAM_LTMSO_R1_B		 MTK_M4U_ID(M4U_LARB10_ID, 29)
-#define M4U_PORT_CAM_RSSO_R1_B		 MTK_M4U_ID(M4U_LARB10_ID, 30)
-
-/* larb11-CAM-VPU */
-#define M4U_PORT_CAM_IPUO		 MTK_M4U_ID(M4U_LARB11_ID, 0)
-#define M4U_PORT_CAM_IPU2O		 MTK_M4U_ID(M4U_LARB11_ID, 1)
-#define M4U_PORT_CAM_IPU3O		 MTK_M4U_ID(M4U_LARB11_ID, 2)
-#define M4U_PORT_CAM_IPUI		 MTK_M4U_ID(M4U_LARB11_ID, 3)
-#define M4U_PORT_CAM_IPU2I		 MTK_M4U_ID(M4U_LARB11_ID, 4)
-
-#endif
diff --git a/include/dt-bindings/mux/ti-serdes.h b/include/dt-bindings/mux/ti-serdes.h
deleted file mode 100644
index b0b1091aad6d..000000000000
--- a/include/dt-bindings/mux/ti-serdes.h
+++ /dev/null
@@ -1,190 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * This header provides constants for SERDES MUX for TI SoCs
- */
-
-#ifndef _DT_BINDINGS_MUX_TI_SERDES
-#define _DT_BINDINGS_MUX_TI_SERDES
-
-/*
- * These bindings are deprecated, because they do not match the actual
- * concept of bindings but rather contain pure constants values used only
- * in DTS board files.
- * Instead include the header in the DTS source directory.
- */
-#warning "These bindings are deprecated. Instead, use the header in the DTS source directory."
-
-/* J721E */
-
-#define J721E_SERDES0_LANE0_QSGMII_LANE1	0x0
-#define J721E_SERDES0_LANE0_PCIE0_LANE0		0x1
-#define J721E_SERDES0_LANE0_USB3_0_SWAP		0x2
-#define J721E_SERDES0_LANE0_IP4_UNUSED		0x3
-
-#define J721E_SERDES0_LANE1_QSGMII_LANE2	0x0
-#define J721E_SERDES0_LANE1_PCIE0_LANE1		0x1
-#define J721E_SERDES0_LANE1_USB3_0		0x2
-#define J721E_SERDES0_LANE1_IP4_UNUSED		0x3
-
-#define J721E_SERDES1_LANE0_QSGMII_LANE3	0x0
-#define J721E_SERDES1_LANE0_PCIE1_LANE0		0x1
-#define J721E_SERDES1_LANE0_USB3_1_SWAP		0x2
-#define J721E_SERDES1_LANE0_SGMII_LANE0		0x3
-
-#define J721E_SERDES1_LANE1_QSGMII_LANE4	0x0
-#define J721E_SERDES1_LANE1_PCIE1_LANE1		0x1
-#define J721E_SERDES1_LANE1_USB3_1		0x2
-#define J721E_SERDES1_LANE1_SGMII_LANE1		0x3
-
-#define J721E_SERDES2_LANE0_IP1_UNUSED		0x0
-#define J721E_SERDES2_LANE0_PCIE2_LANE0		0x1
-#define J721E_SERDES2_LANE0_USB3_1_SWAP		0x2
-#define J721E_SERDES2_LANE0_SGMII_LANE0		0x3
-
-#define J721E_SERDES2_LANE1_IP1_UNUSED		0x0
-#define J721E_SERDES2_LANE1_PCIE2_LANE1		0x1
-#define J721E_SERDES2_LANE1_USB3_1		0x2
-#define J721E_SERDES2_LANE1_SGMII_LANE1		0x3
-
-#define J721E_SERDES3_LANE0_IP1_UNUSED		0x0
-#define J721E_SERDES3_LANE0_PCIE3_LANE0		0x1
-#define J721E_SERDES3_LANE0_USB3_0_SWAP		0x2
-#define J721E_SERDES3_LANE0_IP4_UNUSED		0x3
-
-#define J721E_SERDES3_LANE1_IP1_UNUSED		0x0
-#define J721E_SERDES3_LANE1_PCIE3_LANE1		0x1
-#define J721E_SERDES3_LANE1_USB3_0		0x2
-#define J721E_SERDES3_LANE1_IP4_UNUSED		0x3
-
-#define J721E_SERDES4_LANE0_EDP_LANE0		0x0
-#define J721E_SERDES4_LANE0_IP2_UNUSED		0x1
-#define J721E_SERDES4_LANE0_QSGMII_LANE5	0x2
-#define J721E_SERDES4_LANE0_IP4_UNUSED		0x3
-
-#define J721E_SERDES4_LANE1_EDP_LANE1		0x0
-#define J721E_SERDES4_LANE1_IP2_UNUSED		0x1
-#define J721E_SERDES4_LANE1_QSGMII_LANE6	0x2
-#define J721E_SERDES4_LANE1_IP4_UNUSED		0x3
-
-#define J721E_SERDES4_LANE2_EDP_LANE2		0x0
-#define J721E_SERDES4_LANE2_IP2_UNUSED		0x1
-#define J721E_SERDES4_LANE2_QSGMII_LANE7	0x2
-#define J721E_SERDES4_LANE2_IP4_UNUSED		0x3
-
-#define J721E_SERDES4_LANE3_EDP_LANE3		0x0
-#define J721E_SERDES4_LANE3_IP2_UNUSED		0x1
-#define J721E_SERDES4_LANE3_QSGMII_LANE8	0x2
-#define J721E_SERDES4_LANE3_IP4_UNUSED		0x3
-
-/* J7200 */
-
-#define J7200_SERDES0_LANE0_QSGMII_LANE3	0x0
-#define J7200_SERDES0_LANE0_PCIE1_LANE0		0x1
-#define J7200_SERDES0_LANE0_IP3_UNUSED		0x2
-#define J7200_SERDES0_LANE0_IP4_UNUSED		0x3
-
-#define J7200_SERDES0_LANE1_QSGMII_LANE4	0x0
-#define J7200_SERDES0_LANE1_PCIE1_LANE1		0x1
-#define J7200_SERDES0_LANE1_IP3_UNUSED		0x2
-#define J7200_SERDES0_LANE1_IP4_UNUSED		0x3
-
-#define J7200_SERDES0_LANE2_QSGMII_LANE1	0x0
-#define J7200_SERDES0_LANE2_PCIE1_LANE2		0x1
-#define J7200_SERDES0_LANE2_IP3_UNUSED		0x2
-#define J7200_SERDES0_LANE2_IP4_UNUSED		0x3
-
-#define J7200_SERDES0_LANE3_QSGMII_LANE2	0x0
-#define J7200_SERDES0_LANE3_PCIE1_LANE3		0x1
-#define J7200_SERDES0_LANE3_USB			0x2
-#define J7200_SERDES0_LANE3_IP4_UNUSED		0x3
-
-/* AM64 */
-
-#define AM64_SERDES0_LANE0_PCIE0		0x0
-#define AM64_SERDES0_LANE0_USB			0x1
-
-/* J721S2 */
-
-#define J721S2_SERDES0_LANE0_EDP_LANE0		0x0
-#define J721S2_SERDES0_LANE0_PCIE1_LANE0	0x1
-#define J721S2_SERDES0_LANE0_IP3_UNUSED		0x2
-#define J721S2_SERDES0_LANE0_IP4_UNUSED		0x3
-
-#define J721S2_SERDES0_LANE1_EDP_LANE1		0x0
-#define J721S2_SERDES0_LANE1_PCIE1_LANE1	0x1
-#define J721S2_SERDES0_LANE1_USB		0x2
-#define J721S2_SERDES0_LANE1_IP4_UNUSED		0x3
-
-#define J721S2_SERDES0_LANE2_EDP_LANE2		0x0
-#define J721S2_SERDES0_LANE2_PCIE1_LANE2	0x1
-#define J721S2_SERDES0_LANE2_IP3_UNUSED		0x2
-#define J721S2_SERDES0_LANE2_IP4_UNUSED		0x3
-
-#define J721S2_SERDES0_LANE3_EDP_LANE3		0x0
-#define J721S2_SERDES0_LANE3_PCIE1_LANE3	0x1
-#define J721S2_SERDES0_LANE3_USB		0x2
-#define J721S2_SERDES0_LANE3_IP4_UNUSED		0x3
-
-/* J784S4 */
-
-#define J784S4_SERDES0_LANE0_IP1_UNUSED		0x0
-#define J784S4_SERDES0_LANE0_PCIE1_LANE0	0x1
-#define J784S4_SERDES0_LANE0_IP3_UNUSED		0x2
-#define J784S4_SERDES0_LANE0_IP4_UNUSED		0x3
-
-#define J784S4_SERDES0_LANE1_IP1_UNUSED		0x0
-#define J784S4_SERDES0_LANE1_PCIE1_LANE1	0x1
-#define J784S4_SERDES0_LANE1_IP3_UNUSED		0x2
-#define J784S4_SERDES0_LANE1_IP4_UNUSED		0x3
-
-#define J784S4_SERDES0_LANE2_PCIE3_LANE0	0x0
-#define J784S4_SERDES0_LANE2_PCIE1_LANE2	0x1
-#define J784S4_SERDES0_LANE2_IP3_UNUSED		0x2
-#define J784S4_SERDES0_LANE2_IP4_UNUSED		0x3
-
-#define J784S4_SERDES0_LANE3_PCIE3_LANE1	0x0
-#define J784S4_SERDES0_LANE3_PCIE1_LANE3	0x1
-#define J784S4_SERDES0_LANE3_USB		0x2
-#define J784S4_SERDES0_LANE3_IP4_UNUSED		0x3
-
-#define J784S4_SERDES1_LANE0_QSGMII_LANE3	0x0
-#define J784S4_SERDES1_LANE0_PCIE0_LANE0	0x1
-#define J784S4_SERDES1_LANE0_IP3_UNUSED		0x2
-#define J784S4_SERDES1_LANE0_IP4_UNUSED		0x3
-
-#define J784S4_SERDES1_LANE1_QSGMII_LANE4	0x0
-#define J784S4_SERDES1_LANE1_PCIE0_LANE1	0x1
-#define J784S4_SERDES1_LANE1_IP3_UNUSED		0x2
-#define J784S4_SERDES1_LANE1_IP4_UNUSED		0x3
-
-#define J784S4_SERDES1_LANE2_QSGMII_LANE1	0x0
-#define J784S4_SERDES1_LANE2_PCIE0_LANE2	0x1
-#define J784S4_SERDES1_LANE2_PCIE2_LANE0	0x2
-#define J784S4_SERDES1_LANE2_IP4_UNUSED		0x3
-
-#define J784S4_SERDES1_LANE3_QSGMII_LANE2	0x0
-#define J784S4_SERDES1_LANE3_PCIE0_LANE3	0x1
-#define J784S4_SERDES1_LANE3_PCIE2_LANE1	0x2
-#define J784S4_SERDES1_LANE3_IP4_UNUSED		0x3
-
-#define J784S4_SERDES2_LANE0_QSGMII_LANE5	0x0
-#define J784S4_SERDES2_LANE0_IP2_UNUSED		0x1
-#define J784S4_SERDES2_LANE0_IP3_UNUSED		0x2
-#define J784S4_SERDES2_LANE0_IP4_UNUSED		0x3
-
-#define J784S4_SERDES2_LANE1_QSGMII_LANE6	0x0
-#define J784S4_SERDES2_LANE1_IP2_UNUSED		0x1
-#define J784S4_SERDES2_LANE1_IP3_UNUSED		0x2
-#define J784S4_SERDES2_LANE1_IP4_UNUSED		0x3
-
-#define J784S4_SERDES2_LANE2_QSGMII_LANE7	0x0
-#define J784S4_SERDES2_LANE2_QSGMII_LANE1	0x1
-#define J784S4_SERDES2_LANE2_IP3_UNUSED		0x2
-#define J784S4_SERDES2_LANE2_IP4_UNUSED		0x3
-
-#define J784S4_SERDES2_LANE3_QSGMII_LANE8	0x0
-#define J784S4_SERDES2_LANE3_QSGMII_LANE2	0x1
-#define J784S4_SERDES2_LANE3_IP3_UNUSED		0x2
-#define J784S4_SERDES2_LANE3_IP4_UNUSED		0x3
-
-#endif /* _DT_BINDINGS_MUX_TI_SERDES */
diff --git a/include/dt-bindings/pinctrl/mt6397-pinfunc.h b/include/dt-bindings/pinctrl/mt6397-pinfunc.h
deleted file mode 100644
index f393fbd68905..000000000000
--- a/include/dt-bindings/pinctrl/mt6397-pinfunc.h
+++ /dev/null
@@ -1,257 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __DTS_MT6397_PINFUNC_H
-#define __DTS_MT6397_PINFUNC_H
-
-#include <dt-bindings/pinctrl/mt65xx.h>
-
-#define MT6397_PIN_0_INT__FUNC_GPIO0 (MTK_PIN_NO(0) | 0)
-#define MT6397_PIN_0_INT__FUNC_INT (MTK_PIN_NO(0) | 1)
-
-#define MT6397_PIN_1_SRCVOLTEN__FUNC_GPIO1 (MTK_PIN_NO(1) | 0)
-#define MT6397_PIN_1_SRCVOLTEN__FUNC_SRCVOLTEN (MTK_PIN_NO(1) | 1)
-#define MT6397_PIN_1_SRCVOLTEN__FUNC_TEST_CK1 (MTK_PIN_NO(1) | 6)
-
-#define MT6397_PIN_2_SRCLKEN_PERI__FUNC_GPIO2 (MTK_PIN_NO(2) | 0)
-#define MT6397_PIN_2_SRCLKEN_PERI__FUNC_SRCLKEN_PERI (MTK_PIN_NO(2) | 1)
-#define MT6397_PIN_2_SRCLKEN_PERI__FUNC_TEST_CK2 (MTK_PIN_NO(2) | 6)
-
-#define MT6397_PIN_3_RTC_32K1V8__FUNC_GPIO3 (MTK_PIN_NO(3) | 0)
-#define MT6397_PIN_3_RTC_32K1V8__FUNC_RTC_32K1V8 (MTK_PIN_NO(3) | 1)
-#define MT6397_PIN_3_RTC_32K1V8__FUNC_TEST_CK3 (MTK_PIN_NO(3) | 6)
-
-#define MT6397_PIN_4_WRAP_EVENT__FUNC_GPIO4 (MTK_PIN_NO(4) | 0)
-#define MT6397_PIN_4_WRAP_EVENT__FUNC_WRAP_EVENT (MTK_PIN_NO(4) | 1)
-
-#define MT6397_PIN_5_SPI_CLK__FUNC_GPIO5 (MTK_PIN_NO(5) | 0)
-#define MT6397_PIN_5_SPI_CLK__FUNC_SPI_CLK (MTK_PIN_NO(5) | 1)
-
-#define MT6397_PIN_6_SPI_CSN__FUNC_GPIO6 (MTK_PIN_NO(6) | 0)
-#define MT6397_PIN_6_SPI_CSN__FUNC_SPI_CSN (MTK_PIN_NO(6) | 1)
-
-#define MT6397_PIN_7_SPI_MOSI__FUNC_GPIO7 (MTK_PIN_NO(7) | 0)
-#define MT6397_PIN_7_SPI_MOSI__FUNC_SPI_MOSI (MTK_PIN_NO(7) | 1)
-
-#define MT6397_PIN_8_SPI_MISO__FUNC_GPIO8 (MTK_PIN_NO(8) | 0)
-#define MT6397_PIN_8_SPI_MISO__FUNC_SPI_MISO (MTK_PIN_NO(8) | 1)
-
-#define MT6397_PIN_9_AUD_CLK_MOSI__FUNC_GPIO9 (MTK_PIN_NO(9) | 0)
-#define MT6397_PIN_9_AUD_CLK_MOSI__FUNC_AUD_CLK (MTK_PIN_NO(9) | 1)
-#define MT6397_PIN_9_AUD_CLK_MOSI__FUNC_TEST_IN0 (MTK_PIN_NO(9) | 6)
-#define MT6397_PIN_9_AUD_CLK_MOSI__FUNC_TEST_OUT0 (MTK_PIN_NO(9) | 7)
-
-#define MT6397_PIN_10_AUD_DAT_MISO__FUNC_GPIO10 (MTK_PIN_NO(10) | 0)
-#define MT6397_PIN_10_AUD_DAT_MISO__FUNC_AUD_MISO (MTK_PIN_NO(10) | 1)
-#define MT6397_PIN_10_AUD_DAT_MISO__FUNC_TEST_IN1 (MTK_PIN_NO(10) | 6)
-#define MT6397_PIN_10_AUD_DAT_MISO__FUNC_TEST_OUT1 (MTK_PIN_NO(10) | 7)
-
-#define MT6397_PIN_11_AUD_DAT_MOSI__FUNC_GPIO11 (MTK_PIN_NO(11) | 0)
-#define MT6397_PIN_11_AUD_DAT_MOSI__FUNC_AUD_MOSI (MTK_PIN_NO(11) | 1)
-#define MT6397_PIN_11_AUD_DAT_MOSI__FUNC_TEST_IN2 (MTK_PIN_NO(11) | 6)
-#define MT6397_PIN_11_AUD_DAT_MOSI__FUNC_TEST_OUT2 (MTK_PIN_NO(11) | 7)
-
-#define MT6397_PIN_12_COL0__FUNC_GPIO12 (MTK_PIN_NO(12) | 0)
-#define MT6397_PIN_12_COL0__FUNC_COL0_USBDL (MTK_PIN_NO(12) | 1)
-#define MT6397_PIN_12_COL0__FUNC_EINT10_1X (MTK_PIN_NO(12) | 2)
-#define MT6397_PIN_12_COL0__FUNC_PWM1_3X (MTK_PIN_NO(12) | 3)
-#define MT6397_PIN_12_COL0__FUNC_TEST_IN3 (MTK_PIN_NO(12) | 6)
-#define MT6397_PIN_12_COL0__FUNC_TEST_OUT3 (MTK_PIN_NO(12) | 7)
-
-#define MT6397_PIN_13_COL1__FUNC_GPIO13 (MTK_PIN_NO(13) | 0)
-#define MT6397_PIN_13_COL1__FUNC_COL1 (MTK_PIN_NO(13) | 1)
-#define MT6397_PIN_13_COL1__FUNC_EINT11_1X (MTK_PIN_NO(13) | 2)
-#define MT6397_PIN_13_COL1__FUNC_SCL0_2X (MTK_PIN_NO(13) | 3)
-#define MT6397_PIN_13_COL1__FUNC_TEST_IN4 (MTK_PIN_NO(13) | 6)
-#define MT6397_PIN_13_COL1__FUNC_TEST_OUT4 (MTK_PIN_NO(13) | 7)
-
-#define MT6397_PIN_14_COL2__FUNC_GPIO14 (MTK_PIN_NO(14) | 0)
-#define MT6397_PIN_14_COL2__FUNC_COL2 (MTK_PIN_NO(14) | 1)
-#define MT6397_PIN_14_COL2__FUNC_EINT12_1X (MTK_PIN_NO(14) | 2)
-#define MT6397_PIN_14_COL2__FUNC_SDA0_2X (MTK_PIN_NO(14) | 3)
-#define MT6397_PIN_14_COL2__FUNC_TEST_IN5 (MTK_PIN_NO(14) | 6)
-#define MT6397_PIN_14_COL2__FUNC_TEST_OUT5 (MTK_PIN_NO(14) | 7)
-
-#define MT6397_PIN_15_COL3__FUNC_GPIO15 (MTK_PIN_NO(15) | 0)
-#define MT6397_PIN_15_COL3__FUNC_COL3 (MTK_PIN_NO(15) | 1)
-#define MT6397_PIN_15_COL3__FUNC_EINT13_1X (MTK_PIN_NO(15) | 2)
-#define MT6397_PIN_15_COL3__FUNC_SCL1_2X (MTK_PIN_NO(15) | 3)
-#define MT6397_PIN_15_COL3__FUNC_TEST_IN6 (MTK_PIN_NO(15) | 6)
-#define MT6397_PIN_15_COL3__FUNC_TEST_OUT6 (MTK_PIN_NO(15) | 7)
-
-#define MT6397_PIN_16_COL4__FUNC_GPIO16 (MTK_PIN_NO(16) | 0)
-#define MT6397_PIN_16_COL4__FUNC_COL4 (MTK_PIN_NO(16) | 1)
-#define MT6397_PIN_16_COL4__FUNC_EINT14_1X (MTK_PIN_NO(16) | 2)
-#define MT6397_PIN_16_COL4__FUNC_SDA1_2X (MTK_PIN_NO(16) | 3)
-#define MT6397_PIN_16_COL4__FUNC_TEST_IN7 (MTK_PIN_NO(16) | 6)
-#define MT6397_PIN_16_COL4__FUNC_TEST_OUT7 (MTK_PIN_NO(16) | 7)
-
-#define MT6397_PIN_17_COL5__FUNC_GPIO17 (MTK_PIN_NO(17) | 0)
-#define MT6397_PIN_17_COL5__FUNC_COL5 (MTK_PIN_NO(17) | 1)
-#define MT6397_PIN_17_COL5__FUNC_EINT15_1X (MTK_PIN_NO(17) | 2)
-#define MT6397_PIN_17_COL5__FUNC_SCL2_2X (MTK_PIN_NO(17) | 3)
-#define MT6397_PIN_17_COL5__FUNC_TEST_IN8 (MTK_PIN_NO(17) | 6)
-#define MT6397_PIN_17_COL5__FUNC_TEST_OUT8 (MTK_PIN_NO(17) | 7)
-
-#define MT6397_PIN_18_COL6__FUNC_GPIO18 (MTK_PIN_NO(18) | 0)
-#define MT6397_PIN_18_COL6__FUNC_COL6 (MTK_PIN_NO(18) | 1)
-#define MT6397_PIN_18_COL6__FUNC_EINT16_1X (MTK_PIN_NO(18) | 2)
-#define MT6397_PIN_18_COL6__FUNC_SDA2_2X (MTK_PIN_NO(18) | 3)
-#define MT6397_PIN_18_COL6__FUNC_GPIO32K_0 (MTK_PIN_NO(18) | 4)
-#define MT6397_PIN_18_COL6__FUNC_GPIO26M_0 (MTK_PIN_NO(18) | 5)
-#define MT6397_PIN_18_COL6__FUNC_TEST_IN9 (MTK_PIN_NO(18) | 6)
-#define MT6397_PIN_18_COL6__FUNC_TEST_OUT9 (MTK_PIN_NO(18) | 7)
-
-#define MT6397_PIN_19_COL7__FUNC_GPIO19 (MTK_PIN_NO(19) | 0)
-#define MT6397_PIN_19_COL7__FUNC_COL7 (MTK_PIN_NO(19) | 1)
-#define MT6397_PIN_19_COL7__FUNC_EINT17_1X (MTK_PIN_NO(19) | 2)
-#define MT6397_PIN_19_COL7__FUNC_PWM2_3X (MTK_PIN_NO(19) | 3)
-#define MT6397_PIN_19_COL7__FUNC_GPIO32K_1 (MTK_PIN_NO(19) | 4)
-#define MT6397_PIN_19_COL7__FUNC_GPIO26M_1 (MTK_PIN_NO(19) | 5)
-#define MT6397_PIN_19_COL7__FUNC_TEST_IN10 (MTK_PIN_NO(19) | 6)
-#define MT6397_PIN_19_COL7__FUNC_TEST_OUT10 (MTK_PIN_NO(19) | 7)
-
-#define MT6397_PIN_20_ROW0__FUNC_GPIO20 (MTK_PIN_NO(20) | 0)
-#define MT6397_PIN_20_ROW0__FUNC_ROW0 (MTK_PIN_NO(20) | 1)
-#define MT6397_PIN_20_ROW0__FUNC_EINT18_1X (MTK_PIN_NO(20) | 2)
-#define MT6397_PIN_20_ROW0__FUNC_SCL0_3X (MTK_PIN_NO(20) | 3)
-#define MT6397_PIN_20_ROW0__FUNC_TEST_IN11 (MTK_PIN_NO(20) | 6)
-#define MT6397_PIN_20_ROW0__FUNC_TEST_OUT11 (MTK_PIN_NO(20) | 7)
-
-#define MT6397_PIN_21_ROW1__FUNC_GPIO21 (MTK_PIN_NO(21) | 0)
-#define MT6397_PIN_21_ROW1__FUNC_ROW1 (MTK_PIN_NO(21) | 1)
-#define MT6397_PIN_21_ROW1__FUNC_EINT19_1X (MTK_PIN_NO(21) | 2)
-#define MT6397_PIN_21_ROW1__FUNC_SDA0_3X (MTK_PIN_NO(21) | 3)
-#define MT6397_PIN_21_ROW1__FUNC_AUD_TSTCK (MTK_PIN_NO(21) | 4)
-#define MT6397_PIN_21_ROW1__FUNC_TEST_IN12 (MTK_PIN_NO(21) | 6)
-#define MT6397_PIN_21_ROW1__FUNC_TEST_OUT12 (MTK_PIN_NO(21) | 7)
-
-#define MT6397_PIN_22_ROW2__FUNC_GPIO22 (MTK_PIN_NO(22) | 0)
-#define MT6397_PIN_22_ROW2__FUNC_ROW2 (MTK_PIN_NO(22) | 1)
-#define MT6397_PIN_22_ROW2__FUNC_EINT20_1X (MTK_PIN_NO(22) | 2)
-#define MT6397_PIN_22_ROW2__FUNC_SCL1_3X (MTK_PIN_NO(22) | 3)
-#define MT6397_PIN_22_ROW2__FUNC_TEST_IN13 (MTK_PIN_NO(22) | 6)
-#define MT6397_PIN_22_ROW2__FUNC_TEST_OUT13 (MTK_PIN_NO(22) | 7)
-
-#define MT6397_PIN_23_ROW3__FUNC_GPIO23 (MTK_PIN_NO(23) | 0)
-#define MT6397_PIN_23_ROW3__FUNC_ROW3 (MTK_PIN_NO(23) | 1)
-#define MT6397_PIN_23_ROW3__FUNC_EINT21_1X (MTK_PIN_NO(23) | 2)
-#define MT6397_PIN_23_ROW3__FUNC_SDA1_3X (MTK_PIN_NO(23) | 3)
-#define MT6397_PIN_23_ROW3__FUNC_TEST_IN14 (MTK_PIN_NO(23) | 6)
-#define MT6397_PIN_23_ROW3__FUNC_TEST_OUT14 (MTK_PIN_NO(23) | 7)
-
-#define MT6397_PIN_24_ROW4__FUNC_GPIO24 (MTK_PIN_NO(24) | 0)
-#define MT6397_PIN_24_ROW4__FUNC_ROW4 (MTK_PIN_NO(24) | 1)
-#define MT6397_PIN_24_ROW4__FUNC_EINT22_1X (MTK_PIN_NO(24) | 2)
-#define MT6397_PIN_24_ROW4__FUNC_SCL2_3X (MTK_PIN_NO(24) | 3)
-#define MT6397_PIN_24_ROW4__FUNC_TEST_IN15 (MTK_PIN_NO(24) | 6)
-#define MT6397_PIN_24_ROW4__FUNC_TEST_OUT15 (MTK_PIN_NO(24) | 7)
-
-#define MT6397_PIN_25_ROW5__FUNC_GPIO25 (MTK_PIN_NO(25) | 0)
-#define MT6397_PIN_25_ROW5__FUNC_ROW5 (MTK_PIN_NO(25) | 1)
-#define MT6397_PIN_25_ROW5__FUNC_EINT23_1X (MTK_PIN_NO(25) | 2)
-#define MT6397_PIN_25_ROW5__FUNC_SDA2_3X (MTK_PIN_NO(25) | 3)
-#define MT6397_PIN_25_ROW5__FUNC_TEST_IN16 (MTK_PIN_NO(25) | 6)
-#define MT6397_PIN_25_ROW5__FUNC_TEST_OUT16 (MTK_PIN_NO(25) | 7)
-
-#define MT6397_PIN_26_ROW6__FUNC_GPIO26 (MTK_PIN_NO(26) | 0)
-#define MT6397_PIN_26_ROW6__FUNC_ROW6 (MTK_PIN_NO(26) | 1)
-#define MT6397_PIN_26_ROW6__FUNC_EINT24_1X (MTK_PIN_NO(26) | 2)
-#define MT6397_PIN_26_ROW6__FUNC_PWM3_3X (MTK_PIN_NO(26) | 3)
-#define MT6397_PIN_26_ROW6__FUNC_GPIO32K_2 (MTK_PIN_NO(26) | 4)
-#define MT6397_PIN_26_ROW6__FUNC_GPIO26M_2 (MTK_PIN_NO(26) | 5)
-#define MT6397_PIN_26_ROW6__FUNC_TEST_IN17 (MTK_PIN_NO(26) | 6)
-#define MT6397_PIN_26_ROW6__FUNC_TEST_OUT17 (MTK_PIN_NO(26) | 7)
-
-#define MT6397_PIN_27_ROW7__FUNC_GPIO27 (MTK_PIN_NO(27) | 0)
-#define MT6397_PIN_27_ROW7__FUNC_ROW7 (MTK_PIN_NO(27) | 1)
-#define MT6397_PIN_27_ROW7__FUNC_EINT3_1X (MTK_PIN_NO(27) | 2)
-#define MT6397_PIN_27_ROW7__FUNC_CBUS (MTK_PIN_NO(27) | 3)
-#define MT6397_PIN_27_ROW7__FUNC_GPIO32K_3 (MTK_PIN_NO(27) | 4)
-#define MT6397_PIN_27_ROW7__FUNC_GPIO26M_3 (MTK_PIN_NO(27) | 5)
-#define MT6397_PIN_27_ROW7__FUNC_TEST_IN18 (MTK_PIN_NO(27) | 6)
-#define MT6397_PIN_27_ROW7__FUNC_TEST_OUT18 (MTK_PIN_NO(27) | 7)
-
-#define MT6397_PIN_28_PWM1__FUNC_GPIO28 (MTK_PIN_NO(28) | 0)
-#define MT6397_PIN_28_PWM1__FUNC_PWM1 (MTK_PIN_NO(28) | 1)
-#define MT6397_PIN_28_PWM1__FUNC_EINT4_1X (MTK_PIN_NO(28) | 2)
-#define MT6397_PIN_28_PWM1__FUNC_GPIO32K_4 (MTK_PIN_NO(28) | 4)
-#define MT6397_PIN_28_PWM1__FUNC_GPIO26M_4 (MTK_PIN_NO(28) | 5)
-#define MT6397_PIN_28_PWM1__FUNC_TEST_IN19 (MTK_PIN_NO(28) | 6)
-#define MT6397_PIN_28_PWM1__FUNC_TEST_OUT19 (MTK_PIN_NO(28) | 7)
-
-#define MT6397_PIN_29_PWM2__FUNC_GPIO29 (MTK_PIN_NO(29) | 0)
-#define MT6397_PIN_29_PWM2__FUNC_PWM2 (MTK_PIN_NO(29) | 1)
-#define MT6397_PIN_29_PWM2__FUNC_EINT5_1X (MTK_PIN_NO(29) | 2)
-#define MT6397_PIN_29_PWM2__FUNC_GPIO32K_5 (MTK_PIN_NO(29) | 4)
-#define MT6397_PIN_29_PWM2__FUNC_GPIO26M_5 (MTK_PIN_NO(29) | 5)
-#define MT6397_PIN_29_PWM2__FUNC_TEST_IN20 (MTK_PIN_NO(29) | 6)
-#define MT6397_PIN_29_PWM2__FUNC_TEST_OUT20 (MTK_PIN_NO(29) | 7)
-
-#define MT6397_PIN_30_PWM3__FUNC_GPIO30 (MTK_PIN_NO(30) | 0)
-#define MT6397_PIN_30_PWM3__FUNC_PWM3 (MTK_PIN_NO(30) | 1)
-#define MT6397_PIN_30_PWM3__FUNC_EINT6_1X (MTK_PIN_NO(30) | 2)
-#define MT6397_PIN_30_PWM3__FUNC_COL0 (MTK_PIN_NO(30) | 3)
-#define MT6397_PIN_30_PWM3__FUNC_GPIO32K_6 (MTK_PIN_NO(30) | 4)
-#define MT6397_PIN_30_PWM3__FUNC_GPIO26M_6 (MTK_PIN_NO(30) | 5)
-#define MT6397_PIN_30_PWM3__FUNC_TEST_IN21 (MTK_PIN_NO(30) | 6)
-#define MT6397_PIN_30_PWM3__FUNC_TEST_OUT21 (MTK_PIN_NO(30) | 7)
-
-#define MT6397_PIN_31_SCL0__FUNC_GPIO31 (MTK_PIN_NO(31) | 0)
-#define MT6397_PIN_31_SCL0__FUNC_SCL0 (MTK_PIN_NO(31) | 1)
-#define MT6397_PIN_31_SCL0__FUNC_EINT7_1X (MTK_PIN_NO(31) | 2)
-#define MT6397_PIN_31_SCL0__FUNC_PWM1_2X (MTK_PIN_NO(31) | 3)
-#define MT6397_PIN_31_SCL0__FUNC_TEST_IN22 (MTK_PIN_NO(31) | 6)
-#define MT6397_PIN_31_SCL0__FUNC_TEST_OUT22 (MTK_PIN_NO(31) | 7)
-
-#define MT6397_PIN_32_SDA0__FUNC_GPIO32 (MTK_PIN_NO(32) | 0)
-#define MT6397_PIN_32_SDA0__FUNC_SDA0 (MTK_PIN_NO(32) | 1)
-#define MT6397_PIN_32_SDA0__FUNC_EINT8_1X (MTK_PIN_NO(32) | 2)
-#define MT6397_PIN_32_SDA0__FUNC_TEST_IN23 (MTK_PIN_NO(32) | 6)
-#define MT6397_PIN_32_SDA0__FUNC_TEST_OUT23 (MTK_PIN_NO(32) | 7)
-
-#define MT6397_PIN_33_SCL1__FUNC_GPIO33 (MTK_PIN_NO(33) | 0)
-#define MT6397_PIN_33_SCL1__FUNC_SCL1 (MTK_PIN_NO(33) | 1)
-#define MT6397_PIN_33_SCL1__FUNC_EINT9_1X (MTK_PIN_NO(33) | 2)
-#define MT6397_PIN_33_SCL1__FUNC_PWM2_2X (MTK_PIN_NO(33) | 3)
-#define MT6397_PIN_33_SCL1__FUNC_TEST_IN24 (MTK_PIN_NO(33) | 6)
-#define MT6397_PIN_33_SCL1__FUNC_TEST_OUT24 (MTK_PIN_NO(33) | 7)
-
-#define MT6397_PIN_34_SDA1__FUNC_GPIO34 (MTK_PIN_NO(34) | 0)
-#define MT6397_PIN_34_SDA1__FUNC_SDA1 (MTK_PIN_NO(34) | 1)
-#define MT6397_PIN_34_SDA1__FUNC_EINT0_1X (MTK_PIN_NO(34) | 2)
-#define MT6397_PIN_34_SDA1__FUNC_TEST_IN25 (MTK_PIN_NO(34) | 6)
-#define MT6397_PIN_34_SDA1__FUNC_TEST_OUT25 (MTK_PIN_NO(34) | 7)
-
-#define MT6397_PIN_35_SCL2__FUNC_GPIO35 (MTK_PIN_NO(35) | 0)
-#define MT6397_PIN_35_SCL2__FUNC_SCL2 (MTK_PIN_NO(35) | 1)
-#define MT6397_PIN_35_SCL2__FUNC_EINT1_1X (MTK_PIN_NO(35) | 2)
-#define MT6397_PIN_35_SCL2__FUNC_PWM3_2X (MTK_PIN_NO(35) | 3)
-#define MT6397_PIN_35_SCL2__FUNC_TEST_IN26 (MTK_PIN_NO(35) | 6)
-#define MT6397_PIN_35_SCL2__FUNC_TEST_OUT26 (MTK_PIN_NO(35) | 7)
-
-#define MT6397_PIN_36_SDA2__FUNC_GPIO36 (MTK_PIN_NO(36) | 0)
-#define MT6397_PIN_36_SDA2__FUNC_SDA2 (MTK_PIN_NO(36) | 1)
-#define MT6397_PIN_36_SDA2__FUNC_EINT2_1X (MTK_PIN_NO(36) | 2)
-#define MT6397_PIN_36_SDA2__FUNC_TEST_IN27 (MTK_PIN_NO(36) | 6)
-#define MT6397_PIN_36_SDA2__FUNC_TEST_OUT27 (MTK_PIN_NO(36) | 7)
-
-#define MT6397_PIN_37_HDMISD__FUNC_GPIO37 (MTK_PIN_NO(37) | 0)
-#define MT6397_PIN_37_HDMISD__FUNC_HDMISD (MTK_PIN_NO(37) | 1)
-#define MT6397_PIN_37_HDMISD__FUNC_TEST_IN28 (MTK_PIN_NO(37) | 6)
-#define MT6397_PIN_37_HDMISD__FUNC_TEST_OUT28 (MTK_PIN_NO(37) | 7)
-
-#define MT6397_PIN_38_HDMISCK__FUNC_GPIO38 (MTK_PIN_NO(38) | 0)
-#define MT6397_PIN_38_HDMISCK__FUNC_HDMISCK (MTK_PIN_NO(38) | 1)
-#define MT6397_PIN_38_HDMISCK__FUNC_TEST_IN29 (MTK_PIN_NO(38) | 6)
-#define MT6397_PIN_38_HDMISCK__FUNC_TEST_OUT29 (MTK_PIN_NO(38) | 7)
-
-#define MT6397_PIN_39_HTPLG__FUNC_GPIO39 (MTK_PIN_NO(39) | 0)
-#define MT6397_PIN_39_HTPLG__FUNC_HTPLG (MTK_PIN_NO(39) | 1)
-#define MT6397_PIN_39_HTPLG__FUNC_TEST_IN30 (MTK_PIN_NO(39) | 6)
-#define MT6397_PIN_39_HTPLG__FUNC_TEST_OUT30 (MTK_PIN_NO(39) | 7)
-
-#define MT6397_PIN_40_CEC__FUNC_GPIO40 (MTK_PIN_NO(40) | 0)
-#define MT6397_PIN_40_CEC__FUNC_CEC (MTK_PIN_NO(40) | 1)
-#define MT6397_PIN_40_CEC__FUNC_TEST_IN31 (MTK_PIN_NO(40) | 6)
-#define MT6397_PIN_40_CEC__FUNC_TEST_OUT31 (MTK_PIN_NO(40) | 7)
-
-#endif /* __DTS_MT6397_PINFUNC_H */
diff --git a/include/dt-bindings/power/allwinner,sun20i-d1-ppu.h b/include/dt-bindings/power/allwinner,sun20i-d1-ppu.h
deleted file mode 100644
index 23cfb57256d6..000000000000
--- a/include/dt-bindings/power/allwinner,sun20i-d1-ppu.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
-
-#ifndef _DT_BINDINGS_POWER_SUN20I_D1_PPU_H_
-#define _DT_BINDINGS_POWER_SUN20I_D1_PPU_H_
-
-#define PD_CPU			0
-#define PD_VE			1
-#define PD_DSP			2
-
-#endif /* _DT_BINDINGS_POWER_SUN20I_D1_PPU_H_ */
diff --git a/include/dt-bindings/reset/bcm6318-reset.h b/include/dt-bindings/reset/bcm6318-reset.h
deleted file mode 100644
index f882662505ea..000000000000
--- a/include/dt-bindings/reset/bcm6318-reset.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-
-#ifndef __DT_BINDINGS_RESET_BCM6318_H
-#define __DT_BINDINGS_RESET_BCM6318_H
-
-#define BCM6318_RST_SPI		0
-#define BCM6318_RST_EPHY	1
-#define BCM6318_RST_SAR		2
-#define BCM6318_RST_ENETSW	3
-#define BCM6318_RST_USBD	4
-#define BCM6318_RST_USBH	5
-#define BCM6318_RST_PCIE_CORE	6
-#define BCM6318_RST_PCIE	7
-#define BCM6318_RST_PCIE_EXT	8
-#define BCM6318_RST_PCIE_HARD	9
-#define BCM6318_RST_ADSL	10
-#define BCM6318_RST_PHYMIPS	11
-#define BCM6318_RST_HOSTMIPS	12
-
-#endif /* __DT_BINDINGS_RESET_BCM6318_H */
diff --git a/include/dt-bindings/reset/imx8ulp-pcc-reset.h b/include/dt-bindings/reset/imx8ulp-pcc-reset.h
deleted file mode 100644
index e99a4735c3c4..000000000000
--- a/include/dt-bindings/reset/imx8ulp-pcc-reset.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright 2021 NXP
- */
-
-#ifndef DT_BINDING_PCC_RESET_IMX8ULP_H
-#define DT_BINDING_PCC_RESET_IMX8ULP_H
-
-/* PCC3 */
-#define PCC3_WDOG3_SWRST	0
-#define PCC3_WDOG4_SWRST	1
-#define PCC3_LPIT1_SWRST	2
-#define PCC3_TPM4_SWRST		3
-#define PCC3_TPM5_SWRST		4
-#define PCC3_FLEXIO1_SWRST	5
-#define PCC3_I3C2_SWRST		6
-#define PCC3_LPI2C4_SWRST	7
-#define PCC3_LPI2C5_SWRST	8
-#define PCC3_LPUART4_SWRST	9
-#define PCC3_LPUART5_SWRST	10
-#define PCC3_LPSPI4_SWRST	11
-#define PCC3_LPSPI5_SWRST	12
-
-/* PCC4 */
-#define PCC4_FLEXSPI2_SWRST	0
-#define PCC4_TPM6_SWRST		1
-#define PCC4_TPM7_SWRST		2
-#define PCC4_LPI2C6_SWRST	3
-#define PCC4_LPI2C7_SWRST	4
-#define PCC4_LPUART6_SWRST	5
-#define PCC4_LPUART7_SWRST	6
-#define PCC4_SAI4_SWRST		7
-#define PCC4_SAI5_SWRST		8
-#define PCC4_USDHC0_SWRST	9
-#define PCC4_USDHC1_SWRST	10
-#define PCC4_USDHC2_SWRST	11
-#define PCC4_USB0_SWRST		12
-#define PCC4_USB0_PHY_SWRST	13
-#define PCC4_USB1_SWRST		14
-#define PCC4_USB1_PHY_SWRST	15
-#define PCC4_ENET_SWRST		16
-
-/* PCC5 */
-#define PCC5_TPM8_SWRST		0
-#define PCC5_SAI6_SWRST		1
-#define PCC5_SAI7_SWRST		2
-#define PCC5_SPDIF_SWRST	3
-#define PCC5_ISI_SWRST		4
-#define PCC5_CSI_REGS_SWRST	5
-#define PCC5_CSI_SWRST		6
-#define PCC5_DSI_SWRST		7
-#define PCC5_WDOG5_SWRST	8
-#define PCC5_EPDC_SWRST		9
-#define PCC5_PXP_SWRST		10
-#define PCC5_GPU2D_SWRST	11
-#define PCC5_GPU3D_SWRST	12
-#define PCC5_DC_NANO_SWRST	13
-
-#endif /*DT_BINDING_RESET_IMX8ULP_H */
diff --git a/include/dt-bindings/reset/oxsemi,ox810se.h b/include/dt-bindings/reset/oxsemi,ox810se.h
deleted file mode 100644
index e943187e6527..000000000000
--- a/include/dt-bindings/reset/oxsemi,ox810se.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) 2016 Neil Armstrong <narmstrong at baylibre.com>
- */
-
-#ifndef DT_RESET_OXSEMI_OX810SE_H
-#define DT_RESET_OXSEMI_OX810SE_H
-
-#define RESET_ARM	0
-#define RESET_COPRO	1
-/* Reserved		2 */
-/* Reserved		3 */
-#define RESET_USBHS	4
-#define RESET_USBHSPHY	5
-#define RESET_MAC	6
-#define RESET_PCI	7
-#define RESET_DMA	8
-#define RESET_DPE	9
-#define RESET_DDR	10
-#define RESET_SATA	11
-#define RESET_SATA_LINK	12
-#define RESET_SATA_PHY	13
- /* Reserved		14 */
-#define RESET_NAND	15
-#define RESET_GPIO	16
-#define RESET_UART1	17
-#define RESET_UART2	18
-#define RESET_MISC	19
-#define RESET_I2S	20
-#define RESET_AHB_MON	21
-#define RESET_UART3	22
-#define RESET_UART4	23
-#define RESET_SGDMA	24
-/* Reserved		25 */
-/* Reserved		26 */
-/* Reserved		27 */
-/* Reserved		28 */
-/* Reserved		29 */
-/* Reserved		30 */
-#define RESET_BUS	31
-
-#endif /* DT_RESET_OXSEMI_OX810SE_H */
diff --git a/include/dt-bindings/reset/oxsemi,ox820.h b/include/dt-bindings/reset/oxsemi,ox820.h
deleted file mode 100644
index 54b58e09c1c0..000000000000
--- a/include/dt-bindings/reset/oxsemi,ox820.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) 2016 Neil Armstrong <narmstrong at baylibre.com>
- */
-
-#ifndef DT_RESET_OXSEMI_OX820_H
-#define DT_RESET_OXSEMI_OX820_H
-
-#define RESET_SCU	0
-#define RESET_LEON	1
-#define RESET_ARM0	2
-#define RESET_ARM1	3
-#define RESET_USBHS	4
-#define RESET_USBPHYA	5
-#define RESET_MAC	6
-#define RESET_PCIEA	7
-#define RESET_SGDMA	8
-#define RESET_CIPHER	9
-#define RESET_DDR	10
-#define RESET_SATA	11
-#define RESET_SATA_LINK	12
-#define RESET_SATA_PHY	13
-#define RESET_PCIEPHY	14
-#define RESET_NAND	15
-#define RESET_GPIO	16
-#define RESET_UART1	17
-#define RESET_UART2	18
-#define RESET_MISC	19
-#define RESET_I2S	20
-#define RESET_SD	21
-#define RESET_MAC_2	22
-#define RESET_PCIEB	23
-#define RESET_VIDEO	24
-#define RESET_DDR_PHY	25
-#define RESET_USBPHYB	26
-#define RESET_USBDEV	27
-/* Reserved		29 */
-#define RESET_ARMDBG	29
-#define RESET_PLLA	30
-#define RESET_PLLB	31
-
-#endif /* DT_RESET_OXSEMI_OX820_H */
diff --git a/include/dt-bindings/sound/audio-jack-events.h b/include/dt-bindings/sound/audio-jack-events.h
deleted file mode 100644
index 1b29b295126a..000000000000
--- a/include/dt-bindings/sound/audio-jack-events.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __AUDIO_JACK_EVENTS_H
-#define __AUDIO_JACK_EVENTS_H
-
-#define JACK_HEADPHONE		1
-#define JACK_MICROPHONE		2
-#define JACK_LINEOUT		3
-#define JACK_LINEIN		4
-
-#endif /* __AUDIO_JACK_EVENTS_H */
-- 
2.51.0



From adrian.kossmann at posteo.de  Fri Dec 12 15:50:13 2025
From: adrian.kossmann at posteo.de (Adrian Kossmann)
Date: Fri, 12 Dec 2025 23:50:13 +0000
Subject: [PATCH v2] arm64: dts: rockchip: Adjust RGMII TXD/RXD delays for the Rock Pi E
In-Reply-To: <57e99fa1-0e59-4129-bcae-b94df46447e7@lunn.ch>
References: <57e99fa1-0e59-4129-bcae-b94df46447e7@lunn.ch>
Message-ID: <20251212234957.591812-1-adrian.kossmann@posteo.de>

Hi Andrew,

> rgmii means the PCB provides the delay. I doubt that is the
> case.

Yes, however, to my understanding, there are two kinds of delays that
influence RGMII timing: Delays that are added onto the clock signal 
(TXC/RXC) and delays added to the data signal (TXD/RXD) by the GMAC.
The link provided by you describes delays that are either introduced by 
longer clock traces  on the PCB (rgmii phy-mode) or by programmable clock delays 
(rgmii-id phy-mode). Delays for TXD timing and RXD timing are described in [1] 
and are implemented by the Rockchip Ethernet driver which is bound to node 
gmac2io according to [2]. The example DT binding in [1] as well as other 
mainline DTS of devices that use the RK3328 seem to adjust RGMII timing 
via TXD and RXD delays and setting phy-mode to rgmii, despite having 
programmable TXC/RXC delays, at least according to the technical 
manual of the RK3328. So, in this case this may be an exception
from the usual convention that any RGMII phy mode other than 
'rgmii-id' is probably wrong.

Of course, I may have overlooked something or misunderstood, and I 
would appreciate further guidance in this case.

[1] https://www.kernel.org/doc/Documentation/devicetree/bindings/net/rockchip-dwmac.txt
[2] https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git/tree/arch/arm64/boot/dts/rockchip/rk3328.dtsi#n982


      Adrian



From wsa+renesas at sang-engineering.com  Fri Dec 12 16:03:39 2025
From: wsa+renesas at sang-engineering.com (Wolfram Sang)
Date: Sat, 13 Dec 2025 09:03:39 +0900
Subject: [PATCH] ARM: dts: microchip: Drop usb_a9g20-dab-mmx.dtsi
In-Reply-To: <20251212203226.458694-8-robh@kernel.org>
References: <20251212203226.458694-8-robh@kernel.org>
Message-ID: <aTytWyyZiYFnyauo@shikoro>

On Fri, Dec 12, 2025 at 02:32:14PM -0600, Rob Herring (Arm) wrote:
> This .dtsi file is not included anywhere in the tree and can't be
> tested.
> 
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>

Nowadays, this should be a dtso which did not exist back then. Is it
okay to convert it? Yes, I can do this.



From lkp at intel.com  Fri Dec 12 16:45:34 2025
From: lkp at intel.com (kernel test robot)
Date: Sat, 13 Dec 2025 08:45:34 +0800
Subject: [PATCH v21 3/7] firmware: imx: add driver for NXP EdgeLock
 Enclave
In-Reply-To: <20251212-imx-se-if-v21-3-ee7d6052d848@nxp.com>
References: <20251212-imx-se-if-v21-3-ee7d6052d848@nxp.com>
Message-ID: <202512130804.vObtjguS-lkp@intel.com>

Hi Pankaj,

kernel test robot noticed the following build errors:

[auto build test ERROR on 4a26e7032d7d57c998598c08a034872d6f0d3945]

url:    https://github.com/intel-lab-lkp/linux/commits/Pankaj-Gupta/Documentation-firmware-add-imx-se-to-other_interfaces/20251212-172535
base:   4a26e7032d7d57c998598c08a034872d6f0d3945
patch link:    https://lore.kernel.org/r/20251212-imx-se-if-v21-3-ee7d6052d848%40nxp.com
patch subject: [PATCH v21 3/7] firmware: imx: add driver for NXP EdgeLock Enclave
config: sparc64-allmodconfig (https://download.01.org/0day-ci/archive/20251213/202512130804.vObtjguS-lkp at intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 1335a05ab8bc8339ce24be3a9da89d8c3f4e0571)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251213/202512130804.vObtjguS-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512130804.vObtjguS-lkp at intel.com/

All errors (new ones prefixed by >>):

>> drivers/firmware/imx/se_ctrl.c:168:6: error: call to undeclared function 'FIELD_GET'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     168 |         if (FIELD_GET(DEV_GETINFO_MIN_VER_MASK, var_se_info.soc_rev))
         |             ^
   1 error generated.
--
>> drivers/firmware/imx/ele_common.c:241:11: error: call to undeclared function 'FIELD_GET'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     241 |         status = RES_STATUS(msg->data[0]);
         |                  ^
   drivers/firmware/imx/se_ctrl.h:16:25: note: expanded from macro 'RES_STATUS'
      16 | #define RES_STATUS(x)                   FIELD_GET(0x000000ff, x)
         |                                         ^
   1 error generated.


vim +/FIELD_GET +168 drivers/firmware/imx/se_ctrl.c

   137	
   138	static int get_se_soc_info(struct se_if_priv *priv, const struct se_soc_info *se_info)
   139	{
   140		struct se_fw_load_info *load_fw = get_load_fw_instance(priv);
   141		struct soc_device_attribute *attr;
   142		u8 data[MAX_SOC_INFO_DATA_SZ];
   143		struct ele_dev_info *s_info;
   144		struct soc_device *sdev;
   145		int err = 0;
   146	
   147		/*
   148		 * This function should be called once.
   149		 * Check if the se_soc_rev is zero to continue.
   150		 */
   151		if (var_se_info.soc_rev)
   152			return err;
   153	
   154		err = ele_fetch_soc_info(priv, &data);
   155		if (err < 0)
   156			return dev_err_probe(priv->dev, err, "Failed to fetch SoC Info.");
   157		s_info = (void *)data;
   158		var_se_info.soc_rev = s_info->d_info.soc_rev;
   159		load_fw->imem.state = s_info->d_addn_info.imem_state;
   160	
   161		if (!se_info->soc_register)
   162			return 0;
   163	
   164		attr = devm_kzalloc(priv->dev, sizeof(*attr), GFP_KERNEL);
   165		if (!attr)
   166			return -ENOMEM;
   167	
 > 168		if (FIELD_GET(DEV_GETINFO_MIN_VER_MASK, var_se_info.soc_rev))
   169			attr->revision = devm_kasprintf(priv->dev, GFP_KERNEL, "%x.%x",
   170							FIELD_GET(DEV_GETINFO_MIN_VER_MASK,
   171								  var_se_info.soc_rev),
   172							FIELD_GET(DEV_GETINFO_MAJ_VER_MASK,
   173								  var_se_info.soc_rev));
   174		else
   175			attr->revision = devm_kasprintf(priv->dev, GFP_KERNEL, "%x",
   176							FIELD_GET(DEV_GETINFO_MAJ_VER_MASK,
   177								  var_se_info.soc_rev));
   178	
   179		switch (se_info->soc_id) {
   180		case SOC_ID_OF_IMX8ULP:
   181			attr->soc_id = "i.MX8ULP";
   182			break;
   183		case SOC_ID_OF_IMX93:
   184			attr->soc_id = "i.MX93";
   185			break;
   186		}
   187	
   188		err = of_property_read_string(of_root, "model", &attr->machine);
   189		if (err)
   190			return -EINVAL;
   191	
   192		attr->family = "Freescale i.MX";
   193	
   194		attr->serial_number = devm_kasprintf(priv->dev,
   195						     GFP_KERNEL, "%016llX",
   196						     GET_SERIAL_NUM_FROM_UID(s_info->d_info.uid,
   197									     MAX_UID_SIZE >> 2));
   198	
   199		sdev = soc_device_register(attr);
   200		if (IS_ERR(sdev))
   201			return PTR_ERR(sdev);
   202	
   203		return 0;
   204	}
   205	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From lkp at intel.com  Fri Dec 12 16:45:52 2025
From: lkp at intel.com (kernel test robot)
Date: Sat, 13 Dec 2025 08:45:52 +0800
Subject: [PATCH v21 3/7] firmware: imx: add driver for NXP EdgeLock
 Enclave
In-Reply-To: <20251212-imx-se-if-v21-3-ee7d6052d848@nxp.com>
References: <20251212-imx-se-if-v21-3-ee7d6052d848@nxp.com>
Message-ID: <202512130836.yv66kq5e-lkp@intel.com>

Hi Pankaj,

kernel test robot noticed the following build errors:

[auto build test ERROR on 4a26e7032d7d57c998598c08a034872d6f0d3945]

url:    https://github.com/intel-lab-lkp/linux/commits/Pankaj-Gupta/Documentation-firmware-add-imx-se-to-other_interfaces/20251212-172535
base:   4a26e7032d7d57c998598c08a034872d6f0d3945
patch link:    https://lore.kernel.org/r/20251212-imx-se-if-v21-3-ee7d6052d848%40nxp.com
patch subject: [PATCH v21 3/7] firmware: imx: add driver for NXP EdgeLock Enclave
config: m68k-allmodconfig (https://download.01.org/0day-ci/archive/20251213/202512130836.yv66kq5e-lkp at intel.com/config)
compiler: m68k-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251213/202512130836.yv66kq5e-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512130836.yv66kq5e-lkp at intel.com/

All error/warnings (new ones prefixed by >>):

   drivers/firmware/imx/se_ctrl.c: In function 'get_se_soc_info':
>> drivers/firmware/imx/se_ctrl.c:168:13: error: implicit declaration of function 'FIELD_GET' [-Wimplicit-function-declaration]
     168 |         if (FIELD_GET(DEV_GETINFO_MIN_VER_MASK, var_se_info.soc_rev))
         |             ^~~~~~~~~
   drivers/firmware/imx/se_ctrl.c: At top level:
   drivers/firmware/imx/se_ctrl.c:374:12: warning: 'se_resume' defined but not used [-Wunused-function]
     374 | static int se_resume(struct device *dev)
         |            ^~~~~~~~~
>> drivers/firmware/imx/se_ctrl.c:357:12: warning: 'se_suspend' defined but not used [-Wunused-function]
     357 | static int se_suspend(struct device *dev)
         |            ^~~~~~~~~~
--
   In file included from drivers/firmware/imx/ele_base_msg.h:14,
                    from drivers/firmware/imx/ele_common.c:6:
   drivers/firmware/imx/ele_common.c: In function 'se_val_rsp_hdr_n_status':
>> drivers/firmware/imx/se_ctrl.h:16:41: error: implicit declaration of function 'FIELD_GET' [-Wimplicit-function-declaration]
      16 | #define RES_STATUS(x)                   FIELD_GET(0x000000ff, x)
         |                                         ^~~~~~~~~
   drivers/firmware/imx/ele_common.c:241:18: note: in expansion of macro 'RES_STATUS'
     241 |         status = RES_STATUS(msg->data[0]);
         |                  ^~~~~~~~~~
--
   drivers/firmware/imx/ele_base_msg.c: In function 'ele_get_info':
>> drivers/firmware/imx/ele_base_msg.c:77:47: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
      77 |                 gen_pool_free(priv->mem_pool, (u64)get_info_data,
         |                                               ^


vim +/FIELD_GET +168 drivers/firmware/imx/se_ctrl.c

   137	
   138	static int get_se_soc_info(struct se_if_priv *priv, const struct se_soc_info *se_info)
   139	{
   140		struct se_fw_load_info *load_fw = get_load_fw_instance(priv);
   141		struct soc_device_attribute *attr;
   142		u8 data[MAX_SOC_INFO_DATA_SZ];
   143		struct ele_dev_info *s_info;
   144		struct soc_device *sdev;
   145		int err = 0;
   146	
   147		/*
   148		 * This function should be called once.
   149		 * Check if the se_soc_rev is zero to continue.
   150		 */
   151		if (var_se_info.soc_rev)
   152			return err;
   153	
   154		err = ele_fetch_soc_info(priv, &data);
   155		if (err < 0)
   156			return dev_err_probe(priv->dev, err, "Failed to fetch SoC Info.");
   157		s_info = (void *)data;
   158		var_se_info.soc_rev = s_info->d_info.soc_rev;
   159		load_fw->imem.state = s_info->d_addn_info.imem_state;
   160	
   161		if (!se_info->soc_register)
   162			return 0;
   163	
   164		attr = devm_kzalloc(priv->dev, sizeof(*attr), GFP_KERNEL);
   165		if (!attr)
   166			return -ENOMEM;
   167	
 > 168		if (FIELD_GET(DEV_GETINFO_MIN_VER_MASK, var_se_info.soc_rev))
   169			attr->revision = devm_kasprintf(priv->dev, GFP_KERNEL, "%x.%x",
   170							FIELD_GET(DEV_GETINFO_MIN_VER_MASK,
   171								  var_se_info.soc_rev),
   172							FIELD_GET(DEV_GETINFO_MAJ_VER_MASK,
   173								  var_se_info.soc_rev));
   174		else
   175			attr->revision = devm_kasprintf(priv->dev, GFP_KERNEL, "%x",
   176							FIELD_GET(DEV_GETINFO_MAJ_VER_MASK,
   177								  var_se_info.soc_rev));
   178	
   179		switch (se_info->soc_id) {
   180		case SOC_ID_OF_IMX8ULP:
   181			attr->soc_id = "i.MX8ULP";
   182			break;
   183		case SOC_ID_OF_IMX93:
   184			attr->soc_id = "i.MX93";
   185			break;
   186		}
   187	
   188		err = of_property_read_string(of_root, "model", &attr->machine);
   189		if (err)
   190			return -EINVAL;
   191	
   192		attr->family = "Freescale i.MX";
   193	
   194		attr->serial_number = devm_kasprintf(priv->dev,
   195						     GFP_KERNEL, "%016llX",
   196						     GET_SERIAL_NUM_FROM_UID(s_info->d_info.uid,
   197									     MAX_UID_SIZE >> 2));
   198	
   199		sdev = soc_device_register(attr);
   200		if (IS_ERR(sdev))
   201			return PTR_ERR(sdev);
   202	
   203		return 0;
   204	}
   205	
   206	/* interface for managed res to free a mailbox channel */
   207	static void if_mbox_free_channel(void *mbox_chan)
   208	{
   209		mbox_free_channel(mbox_chan);
   210	}
   211	
   212	static int se_if_request_channel(struct device *dev, struct mbox_chan **chan,
   213					 struct mbox_client *cl, const char *name)
   214	{
   215		struct mbox_chan *t_chan;
   216		int ret = 0;
   217	
   218		t_chan = mbox_request_channel_byname(cl, name);
   219		if (IS_ERR(t_chan))
   220			return dev_err_probe(dev, PTR_ERR(t_chan),
   221					     "Failed to request %s channel.", name);
   222	
   223		ret = devm_add_action_or_reset(dev, if_mbox_free_channel, t_chan);
   224		if (ret)
   225			return dev_err_probe(dev, -EPERM,
   226					     "Failed to add-action for removal of mbox: %s\n",
   227					     name);
   228		*chan = t_chan;
   229	
   230		return ret;
   231	}
   232	
   233	static void se_if_probe_cleanup(void *plat_dev)
   234	{
   235		struct platform_device *pdev = plat_dev;
   236		struct se_fw_load_info *load_fw;
   237		struct device *dev = &pdev->dev;
   238		struct se_if_priv *priv;
   239	
   240		priv = dev_get_drvdata(dev);
   241		load_fw = get_load_fw_instance(priv);
   242	
   243		/*
   244		 * In se_if_request_channel(), passed the clean-up functional
   245		 * pointer reference as action to devm_add_action_or_reset().
   246		 * No need to free the mbox channels here.
   247		 */
   248	
   249		/*
   250		 * free the buffer in se remove, previously allocated
   251		 * in se probe to store encrypted IMEM
   252		 */
   253		if (load_fw && load_fw->imem.buf) {
   254			dmam_free_coherent(dev, ELE_IMEM_SIZE, load_fw->imem.buf,
   255					   load_fw->imem.phyaddr);
   256			load_fw->imem.buf = NULL;
   257		}
   258	
   259		/*
   260		 * No need to check, if reserved memory is allocated
   261		 * before calling for its release. Or clearing the
   262		 * un-set bit.
   263		 */
   264		of_reserved_mem_device_release(dev);
   265	}
   266	
   267	static int se_if_probe(struct platform_device *pdev)
   268	{
   269		const struct se_soc_info *se_info;
   270		const struct se_if_node *if_node;
   271		struct se_fw_load_info *load_fw;
   272		struct device *dev = &pdev->dev;
   273		struct se_if_priv *priv;
   274		int ret;
   275	
   276		if_node = device_get_match_data(dev);
   277		if (!if_node)
   278			return -EINVAL;
   279	
   280		se_info = if_node->se_info;
   281	
   282		priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
   283		if (!priv)
   284			return -ENOMEM;
   285	
   286		priv->dev = dev;
   287		priv->if_defs = &if_node->if_defs;
   288		dev_set_drvdata(dev, priv);
   289	
   290		ret = devm_add_action_or_reset(dev, se_if_probe_cleanup, pdev);
   291		if (ret)
   292			return ret;
   293	
   294		/* Mailbox client configuration */
   295		priv->se_mb_cl.dev		= dev;
   296		priv->se_mb_cl.tx_block		= false;
   297		priv->se_mb_cl.knows_txdone	= true;
   298		priv->se_mb_cl.rx_callback	= se_if_rx_callback;
   299	
   300		ret = se_if_request_channel(dev, &priv->tx_chan, &priv->se_mb_cl, MBOX_TX_NAME);
   301		if (ret)
   302			return ret;
   303	
   304		ret = se_if_request_channel(dev, &priv->rx_chan, &priv->se_mb_cl, MBOX_RX_NAME);
   305		if (ret)
   306			return ret;
   307	
   308		mutex_init(&priv->se_if_cmd_lock);
   309	
   310		init_completion(&priv->waiting_rsp_clbk_hdl.done);
   311		init_completion(&priv->cmd_receiver_clbk_hdl.done);
   312	
   313		if (if_node->pool_name) {
   314			priv->mem_pool = of_gen_pool_get(dev->of_node, if_node->pool_name, 0);
   315			if (!priv->mem_pool)
   316				return dev_err_probe(dev, -ENOMEM,
   317						     "Unable to get sram pool = %s.",
   318						     if_node->pool_name);
   319		}
   320	
   321		if (if_node->reserved_dma_ranges) {
   322			ret = of_reserved_mem_device_init(dev);
   323			if (ret)
   324				return dev_err_probe(dev, ret,
   325						    "Failed to init reserved memory region.");
   326		}
   327	
   328		if (if_node->if_defs.se_if_type == SE_TYPE_ID_HSM) {
   329			ret = get_se_soc_info(priv, se_info);
   330			if (ret)
   331				return dev_err_probe(dev, ret, "Failed to fetch SoC Info.");
   332		}
   333	
   334		/* By default, there is no pending FW to be loaded.*/
   335		if (se_info->se_fw_img_nm.seco_fw_nm_in_rfs) {
   336			load_fw = get_load_fw_instance(priv);
   337			load_fw->se_fw_img_nm = &se_info->se_fw_img_nm;
   338			load_fw->is_fw_tobe_loaded = true;
   339	
   340			if (load_fw->se_fw_img_nm->prim_fw_nm_in_rfs) {
   341				/* allocate buffer where SE store encrypted IMEM */
   342				load_fw->imem.buf = dmam_alloc_coherent(priv->dev, ELE_IMEM_SIZE,
   343									&load_fw->imem.phyaddr,
   344									GFP_KERNEL);
   345				if (!load_fw->imem.buf)
   346					return dev_err_probe(dev, -ENOMEM,
   347							     "dmam-alloc-failed: To store encr-IMEM.");
   348				load_fw->imem_mgmt = true;
   349			}
   350		}
   351		dev_info(dev, "i.MX secure-enclave: %s0 interface to firmware, configured.",
   352			 get_se_if_name(priv->if_defs->se_if_type));
   353	
   354		return ret;
   355	}
   356	
 > 357	static int se_suspend(struct device *dev)
   358	{
   359		struct se_if_priv *priv = dev_get_drvdata(dev);
   360		struct se_fw_load_info *load_fw;
   361		int ret = 0;
   362	
   363		load_fw = get_load_fw_instance(priv);
   364	
   365		if (load_fw->imem_mgmt) {
   366			ret = se_save_imem_state(priv, &load_fw->imem);
   367			if (ret)
   368				dev_err(dev, "Failure saving IMEM state[0x%x]", ret);
   369		}
   370	
   371		return 0;
   372	}
   373	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From alexandre.belloni at bootlin.com  Fri Dec 12 17:09:34 2025
From: alexandre.belloni at bootlin.com (Alexandre Belloni)
Date: Sat, 13 Dec 2025 02:09:34 +0100
Subject: [PATCH] ARM: dts: microchip: Drop usb_a9g20-dab-mmx.dtsi
In-Reply-To: <aTytWyyZiYFnyauo@shikoro>
References: <20251212203226.458694-8-robh@kernel.org>
 <aTytWyyZiYFnyauo@shikoro>
Message-ID: <20251213010934353f1efe@mail.local>

On 13/12/2025 09:03:39+0900, Wolfram Sang wrote:
> On Fri, Dec 12, 2025 at 02:32:14PM -0600, Rob Herring (Arm) wrote:
> > This .dtsi file is not included anywhere in the tree and can't be
> > tested.
> > 
> > Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> 
> Nowadays, this should be a dtso which did not exist back then. Is it
> okay to convert it? Yes, I can do this.
> 

I don't think this will be missed by anyone. Unless you actually have
one of the boards, I would simply drop this.


-- 
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From ebiggers at kernel.org  Fri Dec 12 18:29:29 2025
From: ebiggers at kernel.org (Eric Biggers)
Date: Fri, 12 Dec 2025 18:29:29 -0800
Subject: [PATCH v2] arm64/simd: Avoid pointless clearing of FP/SIMD buffer
In-Reply-To: <20251209054848.998878-2-ardb@kernel.org>
References: <20251209054848.998878-2-ardb@kernel.org>
Message-ID: <20251213022929.GA71695@sol>

On Tue, Dec 09, 2025 at 06:48:49AM +0100, Ard Biesheuvel wrote:
> The buffer provided to kernel_neon_begin() is only used if the task is
> scheduled out while the FP/SIMD is in use by the kernel, or when such a
> section is interrupted by a softirq that also uses the FP/SIMD.
> 
> IOW, this happens rarely, and even if it happened often, there is still
> no reason for this buffer to be cleared beforehand, which happens
> unconditionally, due to the use of a compound literal expression.
> 
> So define that buffer variable explicitly, and mark it as
> __uninitialized so that it will not get cleared, even when
> -ftrivial-auto-var-init is in effect.
> 
> This requires some preprocessor gymnastics, due to the fact that the
> variable must be defined throughout the entire guarded scope, and the
> expression
> 
>   ({ struct user_fpsimd_state __uninitialized st; &st; })
> 
> is problematic in that regard, even though the compilers seem to
> permit it. So instead, repeat for 'for ()' trick that is also used in
> the implementation of the guarded scope helpers.
> 
> Cc: Will Deacon <will at kernel.org>,
> Cc: Catalin Marinas <catalin.marinas at arm.com>,
> Cc: Kees Cook <keescook at chromium.org>
> Cc: Eric Biggers <ebiggers at kernel.org>
> Signed-off-by: Ard Biesheuvel <ardb at kernel.org>
> ---
>  arch/arm64/include/asm/simd.h | 9 ++++++++-
>  1 file changed, 8 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/include/asm/simd.h b/arch/arm64/include/asm/simd.h
> index 0941f6f58a14..69ecbd69ca8c 100644
> --- a/arch/arm64/include/asm/simd.h
> +++ b/arch/arm64/include/asm/simd.h
> @@ -48,6 +48,13 @@ DEFINE_LOCK_GUARD_1(ksimd,
>  		    kernel_neon_begin(_T->lock),
>  		    kernel_neon_end(_T->lock))
>  
> -#define scoped_ksimd()	scoped_guard(ksimd, &(struct user_fpsimd_state){})
> +#define __scoped_ksimd(_label)					\
> +	for (struct user_fpsimd_state __uninitialized __st;	\
> +	     true; ({ goto _label; }))				\
> +		if (0) {					\
> +_label:			break;					\
> +		} else scoped_guard(ksimd, &__st)
> +
> +#define scoped_ksimd()	__scoped_ksimd(__UNIQUE_ID(label))
>  
>  #endif
> 

Applied to https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git/log/?h=libcrypto-fixes

I added:

    Fixes: 4fa617cc6851 ("arm64/fpsimd: Allocate kernel mode FP/SIMD buffers on the stack")

- Eric


From eleanor.lin at realtek.com  Fri Dec 12 18:57:15 2025
From: eleanor.lin at realtek.com (=?utf-8?B?WXUtQ2h1biBMaW4gW+ael+elkOWQm10=?=)
Date: Sat, 13 Dec 2025 02:57:15 -0000
Subject: [PATCH v2 3/3] arm64: dts: realtek: Add Kent SoC and EVB device
 trees
In-Reply-To: <3add6c9f-1bcd-4ec7-ae5e-ba1e67c5087d@kernel.org>
References: <20251113123009.26568-1-eleanor.lin@realtek.com>
 <20251113123009.26568-4-eleanor.lin@realtek.com>
 <3add6c9f-1bcd-4ec7-ae5e-ba1e67c5087d@kernel.org>
Message-ID: <1e4c91ab20564680b497d996bc2a4db3@realtek.com>

> On 13/11/2025 13:30, Yu-Chun Lin wrote:
>> diff --git a/arch/arm64/boot/dts/realtek/rtd1920s-smallville.dtsi b/arch/arm64/boot/dts/realtek/rtd1920s-smallville.dtsi
>> new file mode 100644
>> index 000000000000..0989afcbde67
>> --- /dev/null
>> +++ b/arch/arm64/boot/dts/realtek/rtd1920s-smallville.dtsi
>> @@ -0,0 +1,129 @@
>> +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
>
> Odd, why do you want GPLv3 or GPLv4? GPLv3 has quite strict
> requirements, so I hope you know what you are doing and your legal
> understand this.

Thank you for the kind reminder.

I simply copied the header from an existing Realtek upstream dtsi file.
I will change it to 'SPDX-License-Identifier: GPL-2.0'

>> +/*
>> + * Realtek RTD1920S Smallville EVB
>> + *
>> + * Copyright (c) 2024 Realtek Semiconductor Corp.
>> + */
>> +
>> +/dts-v1/;
>> +
>> +#include <dt-bindings/thermal/thermal.h>
>> +#include "rtd1920.dtsi"
>> +
>> +/ {
>> +	chosen {
>> +		bootargs = "earlycon=uart8250,mmio32,0x98007800";
>
> Drop bootargs, I asked for this last time. That's debugging.
>

Sorry. I will drop it. Set boot args in bootloader.

>> +		stdout-path = "serial0:460800n8";
>> +	};
>
>
>
> Best regards,
> Krzysztof

From eleanor.lin at realtek.com  Fri Dec 12 18:57:16 2025
From: eleanor.lin at realtek.com (=?utf-8?B?WXUtQ2h1biBMaW4gW+ael+elkOWQm10=?=)
Date: Sat, 13 Dec 2025 02:57:16 -0000
Subject: [PATCH v2 2/3] dt-bindings: mfd: Add Realtek MISC system
 controller
In-Reply-To: <38d7aacd-1c05-4040-8575-bdec0587e08f@kernel.org>
References: <20251113123009.26568-1-eleanor.lin@realtek.com>
 <20251113123009.26568-3-eleanor.lin@realtek.com>
 <e799389ce8b4449baba83a893361bdd4@realtek.com>
 <94198d5f-e49f-4b38-8288-3be29efd142b@kernel.org>
 <15951264289d44f797ebd4e05238b380@realtek.com>
 <38d7aacd-1c05-4040-8575-bdec0587e08f@kernel.org>
Message-ID: <d2dbb700ce684ee4a4c4ca120ac5e4e4@realtek.com>

> On 17/11/2025 13:41, Yu-Chun Lin [???] wrote:
> >>>
> >>
> >> None of them. You need SoC specific compatibles which can be used as
> >> fallbacks for SoC specific compatibles. There is plenty of examples
> >> for this already, but anyway this does not solve the problem that you
> >> still did not properly describe the hardware but instead use your
> >> downstream as arguments.
> >>
> >> This will get you nowhere.
> >
> > To implement this fallback structure, my understanding is that the
> > SoC-level DTSI should override the node and prepend its SoC-specific
> > Compatible, while the common DTSI only provides the family-level
> > compatible.
> >
> > /* common DTSI */
> > misc: syscon at ... {
> >     compatible = "realtek,kent-misc", "syscon", "simple-mfd";
> 
> No. You changed nothing. How does this differ from options I disagreed with?
> 
> Anyway, there is no such SoC as "kent" and I was clear - you need SoC
> compatibles.
> 
> Define what is your SoC first.
> 
> Best regards,
> Krzysztof

Hi Krzysztof,

Thank you for your response.

The original intention was to add a basic Kent device tree, but since the
'misc' node is currently empty. I will remove both this device node and
its corresponding YAML binding in v3.

After further consideration within our team, we have decided to add
power-domain and reboot-mode functionalities to the 'misc' node in the
future. And we will adhere to the SoC-specific compatible string binding
pattern, following this structure:

/* schema binding */
compatible:
  items:
    - enum:
        - realtek,rtd1501-misc
        - realtek,rtd1861-misc
        - realtek,rtd1920-misc
    - const: syscon
    - const: simple-mfd

/* SoC-specific Device Tree Source (e.g. rtd1920s.dtsi) */

&rbus {
  misc: syscon at 7000 {
    compatible = "realtek,rtd1920-misc", "syscon", "simple-mfd";
    reg = <0x7000 0x1000>;
    ranges = <0x0 0x7000 0x1000>;
    #address-cells = <1>;
    #size-cells = <1>;
  };
};

Best regards,
Yu-Chun

From eleanor.lin at realtek.com  Fri Dec 12 18:57:18 2025
From: eleanor.lin at realtek.com (=?big5?B?WXUtQ2h1biBMaW4gW6pMr6enZ10=?=)
Date: Sat, 13 Dec 2025 02:57:18 -0000
Subject: [PATCH v2 2/3] dt-bindings: mfd: Add Realtek MISC system
 controller
In-Reply-To: <20251113123009.26568-3-eleanor.lin@realtek.com>
References: <20251113123009.26568-1-eleanor.lin@realtek.com>
 <20251113123009.26568-3-eleanor.lin@realtek.com>
Message-ID: <e799389ce8b4449baba83a893361bdd4@realtek.com>

Hi Conor and Krzysztof,

> Documentation/devicetree/bindings/mfd/realtek,misc.yaml
> 
> diff --git a/Documentation/devicetree/bindings/mfd/realtek,misc.yaml
> b/Documentation/devicetree/bindings/mfd/realtek,misc.yaml
> new file mode 100644
> index 000000000000..4f4a9ae250be
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/realtek,misc.yaml
> @@ -0,0 +1,72 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/mfd/realtek,misc.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Realtek MISC System Controller
> +
> +description:
> +  The Realtek MISC System Controller is a register area that contains
> +  miscellaneous system registers for the SoC and serves as a parent
> +node
> +  for other functions.
> +
> +maintainers:
> +  - James Tai <james.tai at realtek.com>
> +  - Yu-Chun Lin <eleanor.lin at realtek.com>
> +
> +properties:
> +  compatible:
> +    items:
> +      - enum:
> +          - realtek,misc

I apologize for the current compatible string, which was initially named
by referencing existing patterns like 'brcm,misc' and thus violates the
naming guidance against "wildcards" and general non-SoC specific names.

Let me explain the purpose of the device node (Realtek system controller).

This MISC area contains several peripheral sub-modules such as uart,
watchdog, rtc or i2c ..... These blocks share a unified register region
implemented as a single hardware module, which remains powered during
system suspend states (e.g., S3). These blocks share the same MMIO region
and appear as child nodes under the MISC syscon node. Currently, it
includes uart.

Regarding the current structure, the device node is defined in a kent.dtsi
and is included by each SoC's DTSI.

I've considered two ways to write compatible string naming.

Option 1: Use a single SoC-specific compatible string

Rename "realtek,misc" to "realtek,rtd1861-misc"

/* kent.dtsi */
misc: syscon at ... {
    compatible = "realtek,rtd1861-misc", "syscon", "simple-mfd";
};

Pros: Only one compatible string is needed, simplifying maintenance across
the driver and DTS.

Cons: Violates the "SoC-specific compatible" rule for other SoCs
(RTD1501, RTD1920).

Option 2: SoC-specific + fallback (Compliant but Verbose)

Define the full list in the schema, and override the compatible string in each SoC DTSI.

/* schema binding */

compatible:
  items:
    - enum:
        - realtek,rtd1501-misc
        - realtek,rtd1861-misc
        - realtek,rtd1920-misc
        # ... add new SoCs here
    - const: realtek,kent-misc
    - const: syscon
    - const: simple-mfd


/* kent.dtsi */

misc: syscon at ... {
    compatible = "realtek,kent-misc", "syscon", "simple-mfd";
};

SoC-specific override (e.g. rtd1920s-smallville.dtsi):

&misc {
    compatible = "realtek,rtd1920-misc", "realtek,kent-misc", "syscon",
                 "simple-mfd";
};

Pros: Fully compliant with DT rules

Cons: Requires override in every SoC file; slight duplication.

Is Option 2 the expected pattern?
Thanks for your guidance!

Best regards,
Yu-Chun

> +      - const: syscon
> +      - const: simple-mfd
> +
> +  reg:
> +    maxItems: 1
> +
> +  ranges:
> +    maxItems: 1
> +
> +  '#address-cells':
> +    const: 1
> +
> +  '#size-cells':
> +    const: 1
> +
> +patternProperties:
> +  "^serial@[0-9a-f]+$":
> +    type: object
> +    description: UART controllers inside MISC area
> +
> +required:
> +  - compatible
> +  - reg
> +  - ranges
> +  - '#address-cells'
> +  - '#size-cells'
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +
> +    syscon at 7000 {
> +        compatible = "realtek,misc", "syscon", "simple-mfd";
> +        reg = <0x7000 0x1000>;
> +        ranges = <0x0 0x7000 0x1000>;
> +        #address-cells = <1>;
> +        #size-cells = <1>;
> +
> +        uart0: serial at 800 {
> +            compatible = "snps,dw-apb-uart";
> +            reg = <0x800 0x100>;
> +            clock-frequency = <432000000>;
> +            interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
> +            reg-io-width = <4>;
> +            reg-shift = <2>;
> +            status = "disabled";
> +        };
> +    };
> --
> 2.34.1


From pkshih at realtek.com  Fri Dec 12 18:57:19 2025
From: pkshih at realtek.com (Ping-Ke Shih)
Date: Sat, 13 Dec 2025 02:57:19 -0000
Subject: [PATCH] wifi: mt76: Strip whitespace from build ddate
In-Reply-To: <20251120155829.3494747-1-superm1@kernel.org>
References: <20251120155829.3494747-1-superm1@kernel.org>
Message-ID: <a29d737be885490586c30be6262835c8@realtek.com>

Mario Limonciello (AMD) <superm1 at kernel.org> wrote:
> @@ -3124,8 +3125,11 @@ int mt76_connac2_load_patch(struct mt76_dev *dev, const char *fw_name)
>         }
> 
>         hdr = (const void *)fw->data;
> +       strscpy(build_date, hdr->build_date, sizeof(build_date));
> +       build_date[16] = '\0';

As comment of strscpy(), NULL terminator always presents.

 * Copy the source string @src, or as much of it as fits, into the
 * destination @dst buffer. The behavior is undefined if the string
 * buffers overlap. The destination @dst buffer is always NUL terminated,
 * unless it's zero-sized.

> +       strim(build_date);
>         dev_info(dev->dev, "HW/SW Version: 0x%x, Build Time: %.16s\n",
> -                be32_to_cpu(hdr->hw_sw_ver), hdr->build_date);
> +                be32_to_cpu(hdr->hw_sw_ver), build_date);
> 
>         for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) {
>                 struct mt76_connac2_patch_sec *sec;
> --
> 2.43.0
> 



From eleanor.lin at realtek.com  Fri Dec 12 18:57:21 2025
From: eleanor.lin at realtek.com (Yu-Chun Lin)
Date: Sat, 13 Dec 2025 02:57:21 -0000
Subject: [PATCH v2 1/3] dt-bindings: arm: realtek: Add Kent Soc family compatibles
In-Reply-To: <20251113-preorder-task-4e5ba09580d8@spud>
References: <20251113-preorder-task-4e5ba09580d8@spud>
Message-ID: <20251117105542.14789-1-eleanor.lin@realtek.com>

On Thu, Nov 13, 2025 at 08:30:07PM +0800, Yu-Chun Lin wrote:
> > Define compatible strings for Realtek RTD1501s, RTD1861b and RTD1920s.
> > 
> > Additionally, convert legacy DTS-style comments to YAML description 
> > properties, following the pattern from the ARM bindings conversion 
> > series [1].
>
> "Additionally" is often a sign that it should be in a different patch.
> Acked-by: Conor Dooley <conor.dooley at microchip.com>
> pw-bot: not-applicable

Hi Conor,

I'm planning to split the changes into two separate patches:

1. One patch to convert realtek.yaml to match the DTS-style comments,
following the pattern from the ARM bindings conversion series.
2. Another patch to define the compatible strings for Realtek RTD1501s,
RTD1861b, and RTD1920s.

Could you confirm if both patches should include your Acked-by tag, or is
it only applicable to one of them?

Best regards 
Yu-Chun

> > 
> > [1] 
> > https://lore.kernel.org/lkml/20200622125527.24207-2-afaerber at suse.de/
> > 
> > Signed-off-by: Yu-Chun Lin <eleanor.lin at realtek.com>
> > ---
> >  .../devicetree/bindings/arm/realtek.yaml      | 42 +++++++++++++------
> >  1 file changed, 30 insertions(+), 12 deletions(-)
> > 
> > diff --git a/Documentation/devicetree/bindings/arm/realtek.yaml 
> > b/Documentation/devicetree/bindings/arm/realtek.yaml
> > index ddd9a85099e9..be529490640c 100644
> > --- a/Documentation/devicetree/bindings/arm/realtek.yaml
> > +++ b/Documentation/devicetree/bindings/arm/realtek.yaml
> > @@ -14,21 +14,21 @@ properties:
> >      const: '/'
> >    compatible:
> >      oneOf:
> > -      # RTD1195 SoC based boards
> > -      - items:
> > +      - description: RTD1195 SoC based boards
> > +        items:
> >            - enum:
> >                - mele,x1000 # MeLE X1000
> >                - realtek,horseradish # Realtek Horseradish EVB
> >            - const: realtek,rtd1195
> >  
> > -      # RTD1293 SoC based boards
> > -      - items:
> > +      - description: RTD1293 SoC based boards
> > +        items:
> >            - enum:
> >                - synology,ds418j # Synology DiskStation DS418j
> >            - const: realtek,rtd1293
> >  
> > -      # RTD1295 SoC based boards
> > -      - items:
> > +      - description: RTD1295 SoC based boards
> > +        items:
> >            - enum:
> >                - mele,v9 # MeLE V9
> >                - probox2,ava # ProBox2 AVA @@ -36,25 +36,43 @@ 
> > properties:
> >                - zidoo,x9s # Zidoo X9S
> >            - const: realtek,rtd1295
> >  
> > -      # RTD1296 SoC based boards
> > -      - items:
> > +      - description: RTD1296 SoC based boards
> > +        items:
> >            - enum:
> >                - synology,ds418 # Synology DiskStation DS418
> >            - const: realtek,rtd1296
> >  
> > -      # RTD1395 SoC based boards
> > -      - items:
> > +      - description: RTD1395 SoC based boards
> > +        items:
> >            - enum:
> >                - bananapi,bpi-m4 # Banana Pi BPI-M4
> >                - realtek,lion-skin # Realtek Lion Skin EVB
> >            - const: realtek,rtd1395
> >  
> > -      # RTD1619 SoC based boards
> > -      - items:
> > +      - description: RTD1501s SoC based boards
> > +        items:
> > +          - enum:
> > +              - realtek,phantom # Realtek Phantom EVB (8GB)
> > +          - const: realtek,rtd1501s
> > +
> > +      - description: RTD1619 SoC based boards
> > +        items:
> >            - enum:
> >                - realtek,mjolnir # Realtek Mjolnir EVB
> >            - const: realtek,rtd1619
> >  
> > +      - description: RTD1861b SoC based boards
> > +        items:
> > +          - enum:
> > +              - realtek,krypton # Realtek Krypton EVB (8GB)
> > +          - const: realtek,rtd1861b
> > +
> > +      - description: RTD1920s SoC based boards
> > +        items:
> > +          - enum:
> > +              - realtek,smallville # Realtek Smallville EVB (4GB)
> > +          - const: realtek,rtd1920s
> > +
> >  additionalProperties: true
> >  
> >  ...
> > --
> > 2.34.1
> > 



From eleanor.lin at realtek.com  Fri Dec 12 18:57:30 2025
From: eleanor.lin at realtek.com (Yu-Chun Lin)
Date: Sat, 13 Dec 2025 02:57:30 -0000
Subject: [PATCH v2 1/3] dt-bindings: arm: realtek: Add Kent Soc family compatibles
In-Reply-To: <20251113123009.26568-1-eleanor.lin@realtek.com>
References: <20251113123009.26568-1-eleanor.lin@realtek.com>
Message-ID: <20251113123009.26568-2-eleanor.lin@realtek.com>

Define compatible strings for Realtek RTD1501s, RTD1861b and RTD1920s.

Additionally, convert legacy DTS-style comments to YAML description
properties, following the pattern from the ARM bindings conversion series
[1].

[1] https://lore.kernel.org/lkml/20200622125527.24207-2-afaerber at suse.de/

Signed-off-by: Yu-Chun Lin <eleanor.lin at realtek.com>
---
 .../devicetree/bindings/arm/realtek.yaml      | 42 +++++++++++++------
 1 file changed, 30 insertions(+), 12 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/realtek.yaml b/Documentation/devicetree/bindings/arm/realtek.yaml
index ddd9a85099e9..be529490640c 100644
--- a/Documentation/devicetree/bindings/arm/realtek.yaml
+++ b/Documentation/devicetree/bindings/arm/realtek.yaml
@@ -14,21 +14,21 @@ properties:
     const: '/'
   compatible:
     oneOf:
-      # RTD1195 SoC based boards
-      - items:
+      - description: RTD1195 SoC based boards
+        items:
           - enum:
               - mele,x1000 # MeLE X1000
               - realtek,horseradish # Realtek Horseradish EVB
           - const: realtek,rtd1195
 
-      # RTD1293 SoC based boards
-      - items:
+      - description: RTD1293 SoC based boards
+        items:
           - enum:
               - synology,ds418j # Synology DiskStation DS418j
           - const: realtek,rtd1293
 
-      # RTD1295 SoC based boards
-      - items:
+      - description: RTD1295 SoC based boards
+        items:
           - enum:
               - mele,v9 # MeLE V9
               - probox2,ava # ProBox2 AVA
@@ -36,25 +36,43 @@ properties:
               - zidoo,x9s # Zidoo X9S
           - const: realtek,rtd1295
 
-      # RTD1296 SoC based boards
-      - items:
+      - description: RTD1296 SoC based boards
+        items:
           - enum:
               - synology,ds418 # Synology DiskStation DS418
           - const: realtek,rtd1296
 
-      # RTD1395 SoC based boards
-      - items:
+      - description: RTD1395 SoC based boards
+        items:
           - enum:
               - bananapi,bpi-m4 # Banana Pi BPI-M4
               - realtek,lion-skin # Realtek Lion Skin EVB
           - const: realtek,rtd1395
 
-      # RTD1619 SoC based boards
-      - items:
+      - description: RTD1501s SoC based boards
+        items:
+          - enum:
+              - realtek,phantom # Realtek Phantom EVB (8GB)
+          - const: realtek,rtd1501s
+
+      - description: RTD1619 SoC based boards
+        items:
           - enum:
               - realtek,mjolnir # Realtek Mjolnir EVB
           - const: realtek,rtd1619
 
+      - description: RTD1861b SoC based boards
+        items:
+          - enum:
+              - realtek,krypton # Realtek Krypton EVB (8GB)
+          - const: realtek,rtd1861b
+
+      - description: RTD1920s SoC based boards
+        items:
+          - enum:
+              - realtek,smallville # Realtek Smallville EVB (4GB)
+          - const: realtek,rtd1920s
+
 additionalProperties: true
 
 ...
-- 
2.34.1



From eleanor.lin at realtek.com  Fri Dec 12 18:57:32 2025
From: eleanor.lin at realtek.com (Yu-Chun Lin)
Date: Sat, 13 Dec 2025 02:57:32 -0000
Subject: [PATCH v2 3/3] arm64: dts: realtek: Add Kent SoC and EVB device trees
In-Reply-To: <20251113123009.26568-1-eleanor.lin@realtek.com>
References: <20251113123009.26568-1-eleanor.lin@realtek.com>
Message-ID: <20251113123009.26568-4-eleanor.lin@realtek.com>

Add Device Tree hierarchy for Realtek Kent SoC family:

- kent.dtsi: base SoC layer
- rtd<variant>.dtsi: SoC variant layer
- rtd<variant>-<board>.dtsi: board layer
- rtd<variant>-<board>-<config>.dts: board configuration layer

Include RTD1501s Phantom EVB (8GB), RTD1861B Krypton EVB (8GB), and
RTD1920s Smallville EVB (4GB).

Signed-off-by: Yu-Chun Lin <eleanor.lin at realtek.com>
---
 arch/arm64/boot/dts/realtek/Makefile          |   7 +-
 arch/arm64/boot/dts/realtek/kent.dtsi         | 174 ++++++++++++++++++
 arch/arm64/boot/dts/realtek/rtd1501.dtsi      |  13 ++
 .../boot/dts/realtek/rtd1501s-phantom-8gb.dts |  25 +++
 .../boot/dts/realtek/rtd1501s-phantom.dtsi    | 119 ++++++++++++
 arch/arm64/boot/dts/realtek/rtd1861.dtsi      |  13 ++
 .../boot/dts/realtek/rtd1861b-krypton-8gb.dts |  25 +++
 .../boot/dts/realtek/rtd1861b-krypton.dtsi    |  73 ++++++++
 arch/arm64/boot/dts/realtek/rtd1920.dtsi      |  13 ++
 .../dts/realtek/rtd1920s-smallville-4gb.dts   |  23 +++
 .../boot/dts/realtek/rtd1920s-smallville.dtsi | 129 +++++++++++++
 11 files changed, 610 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm64/boot/dts/realtek/kent.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1501.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1501s-phantom-8gb.dts
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1501s-phantom.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1861.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1861b-krypton-8gb.dts
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1861b-krypton.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1920.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1920s-smallville-4gb.dts
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1920s-smallville.dtsi

diff --git a/arch/arm64/boot/dts/realtek/Makefile b/arch/arm64/boot/dts/realtek/Makefile
index ef8d8fcbaa05..8a8e143182b9 100644
--- a/arch/arm64/boot/dts/realtek/Makefile
+++ b/arch/arm64/boot/dts/realtek/Makefile
@@ -1,15 +1,14 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1293-ds418j.dtb
-
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1295-mele-v9.dtb
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1295-probox2-ava.dtb
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1295-xnano-x5.dtb
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1295-zidoo-x9s.dtb
-
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1296-ds418.dtb
-
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1395-bpi-m4.dtb
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1395-lionskin.dtb
-
+dtb-$(CONFIG_ARCH_REALTEK) += rtd1501s-phantom-8gb.dtb
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1619-mjolnir.dtb
+dtb-$(CONFIG_ARCH_REALTEK) += rtd1861b-krypton-8gb.dtb
+dtb-$(CONFIG_ARCH_REALTEK) += rtd1920s-smallville-4gb.dtb
+
diff --git a/arch/arm64/boot/dts/realtek/kent.dtsi b/arch/arm64/boot/dts/realtek/kent.dtsi
new file mode 100644
index 000000000000..8d1b082c6ec8
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/kent.dtsi
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Realtek Kent SoC family
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	aliases {
+		serial0 = &uart0;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI  9 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu0: cpu at 0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a78";
+			reg = <0x0>;
+			enable-method = "psci";
+			next-level-cache = <&l2_0>;
+			dynamic-power-coefficient = <454>;
+			#cooling-cells = <2>;
+
+			l2_0: l2-cache {
+				compatible = "cache";
+				cache-level = <2>;
+				cache-line-size = <64>;
+				cache-sets = <256>;
+				cache-size = <0x40000>;
+				cache-unified;
+				next-level-cache = <&l3>;
+			};
+		};
+
+		cpu1: cpu at 100 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a78";
+			reg = <0x100>;
+			enable-method = "psci";
+			next-level-cache = <&l2_1>;
+			dynamic-power-coefficient = <454>;
+			#cooling-cells = <2>;
+
+			l2_1: l2-cache {
+				compatible = "cache";
+				cache-level = <2>;
+				cache-line-size = <64>;
+				cache-sets = <256>;
+				cache-size = <0x40000>;
+				cache-unified;
+				next-level-cache = <&l3>;
+			};
+		};
+
+		cpu2: cpu at 200 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a78";
+			reg = <0x200>;
+			enable-method = "psci";
+			next-level-cache = <&l2_2>;
+			dynamic-power-coefficient = <454>;
+			#cooling-cells = <2>;
+
+			l2_2: l2-cache {
+				compatible = "cache";
+				cache-level = <2>;
+				cache-line-size = <64>;
+				cache-sets = <256>;
+				cache-size = <0x40000>;
+				cache-unified;
+				next-level-cache = <&l3>;
+			};
+		};
+
+		cpu3: cpu at 300 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a78";
+			reg = <0x300>;
+			enable-method = "psci";
+			next-level-cache = <&l2_3>;
+			dynamic-power-coefficient = <454>;
+			#cooling-cells = <2>;
+
+			l2_3: l2-cache {
+				compatible = "cache";
+				cache-level = <2>;
+				cache-line-size = <64>;
+				cache-sets = <256>;
+				cache-size = <0x40000>;
+				cache-unified;
+				next-level-cache = <&l3>;
+			};
+		};
+
+		l3: l3-cache {
+			compatible = "cache";
+			cache-level = <3>;
+			cache-line-size = <64>;
+			cache-sets = <512>;
+			cache-size = <0x200000>;
+			cache-unified;
+		};
+	};
+
+	psci: psci {
+		compatible = "arm,psci-1.0";
+		method = "smc";
+	};
+
+	soc at 0 {
+		compatible = "simple-bus";
+		ranges = <0x0 0x0 0x0 0x40000>, /* boot code */
+			 <0x98000000 0x0 0x98000000 0xef0000>, /* rbus */
+			 <0xa0000000 0x0 0xa0000000 0x10000000>, /* PCIE */
+			 <0xff000000 0x0 0xff000000 0x200000>; /* GIC */
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		rbus: bus at 98000000 {
+			compatible = "simple-bus";
+			ranges = <0x0 0x98000000 0xef0000>,
+				 <0xa0000000 0xa0000000 0x10000000>; /* PCIE */
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			iso: syscon at 7000 {
+				compatible = "realtek,misc", "syscon", "simple-mfd";
+				reg = <0x7000 0x1000>;
+				ranges = <0x0 0x7000 0x1000>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+
+				uart0: serial at 800 {
+					compatible = "snps,dw-apb-uart";
+					reg = <0x800 0x100>;
+					clock-frequency = <432000000>;
+					interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
+					reg-io-width = <4>;
+					reg-shift = <2>;
+					status = "disabled";
+				};
+			};
+		};
+
+		gic: interrupt-controller at ff100000 {
+			compatible = "arm,gic-v3";
+			reg = <0xff100000 0x10000>,
+			      <0xff140000 0x80000>;
+			interrupt-controller;
+			interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#interrupt-cells = <3>;
+			#size-cells = <1>;
+		};
+	};
+};
+
diff --git a/arch/arm64/boot/dts/realtek/rtd1501.dtsi b/arch/arm64/boot/dts/realtek/rtd1501.dtsi
new file mode 100644
index 000000000000..1df5d9843505
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1501.dtsi
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Realtek RTD1501 SoC
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+#include "kent.dtsi"
+
+&uart0 {
+	status = "okay";
+};
+
diff --git a/arch/arm64/boot/dts/realtek/rtd1501s-phantom-8gb.dts b/arch/arm64/boot/dts/realtek/rtd1501s-phantom-8gb.dts
new file mode 100644
index 000000000000..c708a713fc4d
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1501s-phantom-8gb.dts
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Realtek RTD1501S Phantom EVB
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+/dts-v1/;
+
+#include "rtd1501s-phantom.dtsi"
+
+/ {
+	compatible = "realtek,phantom", "realtek,rtd1501s";
+	model = "Realtek Phantom EVB Chromium (8GB)";
+
+	memory at 40000 {
+		device_type = "memory";
+		reg = <0x0 0x50000 0x0 0x7ffb0000>,
+		      <0x0 0x8a100000 0x0 0xdef0000>,
+		      <0x0 0x98700000 0x0 0x7900000>,
+		      <0x0 0xa0600000 0x0 0x5ea00000>,
+		      <0x1 0x0 0x0 0xa0000000>,
+		      <0x1 0xa0600000 0x0 0x5fa00000>;
+	};
+};
+
diff --git a/arch/arm64/boot/dts/realtek/rtd1501s-phantom.dtsi b/arch/arm64/boot/dts/realtek/rtd1501s-phantom.dtsi
new file mode 100644
index 000000000000..a3639bd6a75b
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1501s-phantom.dtsi
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Realtek RTD1501S Phantom EVB
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/thermal/thermal.h>
+#include "rtd1501.dtsi"
+
+/ {
+	chosen {
+		bootargs = "earlycon=uart8250,mmio32,0x98007800";
+		stdout-path = "serial0:460800n8";
+	};
+
+	reserved_memory: reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		linux,cma {
+			compatible = "shared-dma-pool";
+			alignment = <0x0 0x400000>;
+			alloc-ranges = <0x0 0x0 0x0 0x20000000>;
+			size = <0x0 0x2000000>;
+			reusable;
+			linux,cma-default;
+		};
+	};
+
+	cpu_opps: opp-table-cpu {
+		compatible = "operating-points-v2";
+		opp-shared;
+
+		opp800: opp-800000000 {
+			opp-hz = /bits/ 64 <800000000>;
+			opp-microvolt = <830000 830000 1100000>;
+		};
+
+		opp900: opp-900000000 {
+			opp-hz = /bits/ 64 <900000000>;
+			opp-microvolt = <850000 850000 1100000>;
+		};
+
+		opp1000: opp-1000000000 {
+			opp-hz = /bits/ 64 <1000000000>;
+			opp-microvolt = <870000 870000 1100000>;
+		};
+
+		opp1100: opp-1100000000 {
+			opp-hz = /bits/ 64 <1100000000>;
+			opp-microvolt = <890000 890000 1100000>;
+		};
+
+		opp1200: opp-1200000000 {
+			opp-hz = /bits/ 64 <1200000000>;
+			opp-microvolt = <910000 910000 1100000>;
+		};
+
+		opp1300: opp-1300000000 {
+			opp-hz = /bits/ 64 <1300000000>;
+			opp-microvolt = <930000 930000 1100000>;
+		};
+
+		opp1400: opp-1400000000 {
+			opp-hz = /bits/ 64 <1400000000>;
+			opp-microvolt = <950000 950000 1100000>;
+		};
+
+		opp1500: opp-1500000000 {
+			opp-hz = /bits/ 64 <1500000000>;
+			opp-microvolt = <970000 970000 1100000>;
+		};
+
+		opp1600: opp-1600000000 {
+			opp-hz = /bits/ 64 <1600000000>;
+			opp-microvolt = <990000 990000 1100000>;
+			opp-suspend;
+		};
+
+		opp1700: opp-1700000000 {
+			opp-hz = /bits/ 64 <1700000000>;
+			opp-microvolt = <1010000 1010000 1100000>;
+		};
+
+		opp1800: opp-1800000000 {
+			opp-hz = /bits/ 64 <1800000000>;
+			opp-microvolt = <1030000 1030000 1100000>;
+		};
+
+		opp1900: opp-1900000000 {
+			opp-hz = /bits/ 64 <1900000000>;
+			opp-microvolt = <1050000 1050000 1100000>;
+		};
+	};
+};
+
+&cpu0 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu1 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu2 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu3 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
diff --git a/arch/arm64/boot/dts/realtek/rtd1861.dtsi b/arch/arm64/boot/dts/realtek/rtd1861.dtsi
new file mode 100644
index 000000000000..e9b1b85c7a63
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1861.dtsi
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Realtek RTD1861 SoC
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+#include "kent.dtsi"
+
+&uart0 {
+	status = "okay";
+};
+
diff --git a/arch/arm64/boot/dts/realtek/rtd1861b-krypton-8gb.dts b/arch/arm64/boot/dts/realtek/rtd1861b-krypton-8gb.dts
new file mode 100644
index 000000000000..38feec66d4e9
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1861b-krypton-8gb.dts
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Realtek RTD1861B Krypton EVB
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+/dts-v1/;
+
+#include "rtd1861b-krypton.dtsi"
+
+/ {
+	compatible = "realtek,krypton", "realtek,rtd1861b";
+	model = "Realtek Krypton EVB (8GB)";
+
+	memory at 40000 {
+		device_type = "memory";
+		reg = <0x0 0x50000 0x0 0x7ffb0000>,
+		      <0x0 0x8a100000 0x0 0xdef0000>,
+		      <0x0 0x98700000 0x0 0x7900000>,
+		      <0x0 0xa0600000 0x0 0x5ea00000>,
+		      <0x1 0x0 0x0 0xa0000000>,
+		      <0x1 0xa0600000 0x0 0x5fa00000>;
+	};
+};
+
diff --git a/arch/arm64/boot/dts/realtek/rtd1861b-krypton.dtsi b/arch/arm64/boot/dts/realtek/rtd1861b-krypton.dtsi
new file mode 100644
index 000000000000..3773284ce95b
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1861b-krypton.dtsi
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Realtek RTD1861B Krypton EVB
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+/dts-v1/;
+
+#include "rtd1861.dtsi"
+
+/ {
+	chosen {
+		bootargs = "earlycon=uart8250,mmio32,0x98007800";
+		stdout-path = "serial0:460800n8";
+	};
+
+	reserved_memory: reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		linux,cma {
+			compatible = "shared-dma-pool";
+			alignment = <0x0 0x400000>;
+			alloc-ranges = <0x0 0x0 0x0 0x20000000>;
+			size = <0x0 0x2000000>;
+			reusable;
+			linux,cma-default;
+		};
+	};
+
+	cpu_opps: opp-table-cpu {
+		compatible = "operating-points-v2";
+		opp-shared;
+
+		opp1200: opp-1200000000 {
+			opp-hz = /bits/ 64 <1200000000>;
+			opp-microvolt = <900000>;
+		};
+
+		opp1600: opp-1600000000 {
+			opp-hz = /bits/ 64 <1600000000>;
+			opp-microvolt = <1000000>;
+			opp-suspend;
+		};
+
+		opp1800: opp-1800000000 {
+			opp-hz = /bits/ 64 <1800000000>;
+			opp-microvolt = <1050000>;
+		};
+	};
+};
+
+&cpu0 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu1 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu2 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu3 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
diff --git a/arch/arm64/boot/dts/realtek/rtd1920.dtsi b/arch/arm64/boot/dts/realtek/rtd1920.dtsi
new file mode 100644
index 000000000000..ffefde9749a1
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1920.dtsi
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Realtek RTD1920 SoC
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+#include "kent.dtsi"
+
+&uart0 {
+	status = "okay";
+};
+
diff --git a/arch/arm64/boot/dts/realtek/rtd1920s-smallville-4gb.dts b/arch/arm64/boot/dts/realtek/rtd1920s-smallville-4gb.dts
new file mode 100644
index 000000000000..b6900b11f34d
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1920s-smallville-4gb.dts
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Realtek RTD1920S Smallville EVB
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+/dts-v1/;
+
+#include "rtd1920s-smallville.dtsi"
+
+/ {
+	compatible = "realtek,smallville", "realtek,rtd1920s";
+	model = "Realtek Smallville EVB (4GB)";
+
+	memory at 40000 {
+		device_type = "memory";
+		reg = <0x0 0x50000 0x0 0x7ffb0000>,
+		      <0x0 0x8a100000 0x0 0xdef0000>,
+		      <0x0 0x98700000 0x0 0x7900000>,
+		      <0x0 0xa1000000 0x0 0x5e000000>;
+	};
+};
+
diff --git a/arch/arm64/boot/dts/realtek/rtd1920s-smallville.dtsi b/arch/arm64/boot/dts/realtek/rtd1920s-smallville.dtsi
new file mode 100644
index 000000000000..0989afcbde67
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1920s-smallville.dtsi
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * Realtek RTD1920S Smallville EVB
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/thermal/thermal.h>
+#include "rtd1920.dtsi"
+
+/ {
+	chosen {
+		bootargs = "earlycon=uart8250,mmio32,0x98007800";
+		stdout-path = "serial0:460800n8";
+	};
+
+	reserved_memory: reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		protected_mem: protected-mem at 50000 {
+			reg = <0x0 0x50000 0x0 0xbf0000>;
+			no-map;
+		};
+
+		metadata: metadata at c40000 {
+			reg = <0x0 0xc40000 0x0 0x3c4000>;
+			no-map;
+		};
+
+		linux,cma {
+			compatible = "shared-dma-pool";
+			alignment = <0x0 0x400000>;
+			alloc-ranges = <0x0 0x0 0x0 0x20000000>;
+			size = <0x0 0x2000000>;
+			reusable;
+			linux,cma-default;
+		};
+	};
+
+	cpu_opps: opp-table-cpu {
+		compatible = "operating-points-v2";
+		opp-shared;
+
+		opp800: opp-800000000 {
+			opp-hz = /bits/ 64 <800000000>;
+			opp-microvolt = <830000 830000 1100000>;
+		};
+
+		opp900: opp-900000000 {
+			opp-hz = /bits/ 64 <900000000>;
+			opp-microvolt = <850000 850000 1100000>;
+		};
+
+		opp1000: opp-1000000000 {
+			opp-hz = /bits/ 64 <1000000000>;
+			opp-microvolt = <870000 870000 1100000>;
+		};
+
+		opp1100: opp-1100000000 {
+			opp-hz = /bits/ 64 <1100000000>;
+			opp-microvolt = <890000 890000 1100000>;
+		};
+
+		opp1200: opp-1200000000 {
+			opp-hz = /bits/ 64 <1200000000>;
+			opp-microvolt = <910000 910000 1100000>;
+		};
+
+		opp1300: opp-1300000000 {
+			opp-hz = /bits/ 64 <1300000000>;
+			opp-microvolt = <930000 930000 1100000>;
+		};
+
+		opp1400: opp-1400000000 {
+			opp-hz = /bits/ 64 <1400000000>;
+			opp-microvolt = <950000 950000 1100000>;
+		};
+
+		opp1500: opp-1500000000 {
+			opp-hz = /bits/ 64 <1500000000>;
+			opp-microvolt = <970000 970000 1100000>;
+		};
+
+		opp1600: opp-1600000000 {
+			opp-hz = /bits/ 64 <1600000000>;
+			opp-microvolt = <990000 990000 1100000>;
+			opp-suspend;
+		};
+
+		opp1700: opp-1700000000 {
+			opp-hz = /bits/ 64 <1700000000>;
+			opp-microvolt = <1010000 1010000 1100000>;
+		};
+
+		opp1800: opp-1800000000 {
+			opp-hz = /bits/ 64 <1800000000>;
+			opp-microvolt = <1030000 1030000 1100000>;
+		};
+
+		opp1900: opp-1900000000 {
+			opp-hz = /bits/ 64 <1900000000>;
+			opp-microvolt = <1050000 1050000 1100000>;
+		};
+	};
+};
+
+&cpu0 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu1 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu2 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu3 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
-- 
2.34.1



From eleanor.lin at realtek.com  Fri Dec 12 18:57:33 2025
From: eleanor.lin at realtek.com (Yu-Chun Lin)
Date: Sat, 13 Dec 2025 02:57:33 -0000
Subject: [PATCH v2 2/3] dt-bindings: mfd: Add Realtek MISC system controller
In-Reply-To: <20251113123009.26568-1-eleanor.lin@realtek.com>
References: <20251113123009.26568-1-eleanor.lin@realtek.com>
Message-ID: <20251113123009.26568-3-eleanor.lin@realtek.com>

Add DT binding schema for Realtek system controller.

Signed-off-by: Yu-Chun Lin <eleanor.lin at realtek.com>
---
 .../devicetree/bindings/mfd/realtek,misc.yaml | 72 +++++++++++++++++++
 1 file changed, 72 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/realtek,misc.yaml

diff --git a/Documentation/devicetree/bindings/mfd/realtek,misc.yaml b/Documentation/devicetree/bindings/mfd/realtek,misc.yaml
new file mode 100644
index 000000000000..4f4a9ae250be
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/realtek,misc.yaml
@@ -0,0 +1,72 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/realtek,misc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Realtek MISC System Controller
+
+description:
+  The Realtek MISC System Controller is a register area that contains
+  miscellaneous system registers for the SoC and serves as a parent node
+  for other functions.
+
+maintainers:
+  - James Tai <james.tai at realtek.com>
+  - Yu-Chun Lin <eleanor.lin at realtek.com>
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - realtek,misc
+      - const: syscon
+      - const: simple-mfd
+
+  reg:
+    maxItems: 1
+
+  ranges:
+    maxItems: 1
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 1
+
+patternProperties:
+  "^serial@[0-9a-f]+$":
+    type: object
+    description: UART controllers inside MISC area
+
+required:
+  - compatible
+  - reg
+  - ranges
+  - '#address-cells'
+  - '#size-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    syscon at 7000 {
+        compatible = "realtek,misc", "syscon", "simple-mfd";
+        reg = <0x7000 0x1000>;
+        ranges = <0x0 0x7000 0x1000>;
+        #address-cells = <1>;
+        #size-cells = <1>;
+
+        uart0: serial at 800 {
+            compatible = "snps,dw-apb-uart";
+            reg = <0x800 0x100>;
+            clock-frequency = <432000000>;
+            interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
+            reg-io-width = <4>;
+            reg-shift = <2>;
+            status = "disabled";
+        };
+    };
-- 
2.34.1



From eleanor.lin at realtek.com  Fri Dec 12 18:57:35 2025
From: eleanor.lin at realtek.com (Yu-Chun Lin)
Date: Sat, 13 Dec 2025 02:57:35 -0000
Subject: [PATCH v2 0/3] arm64: dts: Add support for Kent SoC family
Message-ID: <20251113123009.26568-1-eleanor.lin@realtek.com>

Hello,

This patch series adds initial Device Tree support for Realtek's Kent SoC
family, including the RTD1501S, RTD1861B, and RTD1920S variants with their
respective evaluation boards.

The series includes:

1. Adds compatible strings for the Kent family.
2. Add new DT bindings for the Realtek ISO system controller.
3. Add Device Tree files for the Kent SoC, TD1501S Phantom EVB (8GB),
RTD1861B Krypton EVB (8GB), and RTD1920S Smallville EVB (4GB).

The patches have been validated with 'make dtbs_check' and
'dt_binding_check' to ensure compliance with DT schema and successful
compilation.

Cheers,
Yu-Chun

Signed-off-by: Yu-Chun Lin <eleanor.lin at realtek.com>
---
Changes in v2:

[PATCH v2 1/3]
- Fix YAML syntax: remove duplicate blank lines
- Validated with 'make dt_binding_check'

[PATCH v2 2/3]
- Rename: realtek,iso-system.yaml -> realtek,misc.yaml
- Improve description and example: show child node (UART)

[PATCH v2 3/3]
- Reorder Makefile targets to alphabetical order.
- Rename node: use generic names ('arch_timer' -> 'timer', 'reg-bus' -> 'bus')
- Fix node naming and hex format (remove leading zeros)
- Inline overlay nodes directly into .dtsi
- Reorder properties: ranges after reg
- Remove unnecessary status and custom bootargs

V1: https://lore.kernel.org/lkml/20251105104452.6336-1-eleanor.lin at realtek.com/

Yu-Chun Lin (3):
  dt-bindings: arm: realtek: Add Kent Soc family compatibles
  dt-bindings: mfd: Add Realtek MISC system controller
  arm64: dts: realtek: Add Kent SoC and EVB device trees

 .../devicetree/bindings/arm/realtek.yaml      |  42 +++--
 .../devicetree/bindings/mfd/realtek,misc.yaml |  72 ++++++++
 arch/arm64/boot/dts/realtek/Makefile          |   7 +-
 arch/arm64/boot/dts/realtek/kent.dtsi         | 174 ++++++++++++++++++
 arch/arm64/boot/dts/realtek/rtd1501.dtsi      |  13 ++
 .../boot/dts/realtek/rtd1501s-phantom-8gb.dts |  25 +++
 .../boot/dts/realtek/rtd1501s-phantom.dtsi    | 119 ++++++++++++
 arch/arm64/boot/dts/realtek/rtd1861.dtsi      |  13 ++
 .../boot/dts/realtek/rtd1861b-krypton-8gb.dts |  25 +++
 .../boot/dts/realtek/rtd1861b-krypton.dtsi    |  73 ++++++++
 arch/arm64/boot/dts/realtek/rtd1920.dtsi      |  13 ++
 .../dts/realtek/rtd1920s-smallville-4gb.dts   |  23 +++
 .../boot/dts/realtek/rtd1920s-smallville.dtsi | 129 +++++++++++++
 13 files changed, 712 insertions(+), 16 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mfd/realtek,misc.yaml
 create mode 100644 arch/arm64/boot/dts/realtek/kent.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1501.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1501s-phantom-8gb.dts
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1501s-phantom.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1861.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1861b-krypton-8gb.dts
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1861b-krypton.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1920.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1920s-smallville-4gb.dts
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1920s-smallville.dtsi

-- 
2.34.1



From eleanor.lin at realtek.com  Fri Dec 12 18:57:38 2025
From: eleanor.lin at realtek.com (=?utf-8?B?WXUtQ2h1biBMaW4gW+ael+elkOWQm10=?=)
Date: Sat, 13 Dec 2025 02:57:38 -0000
Subject: [PATCH v2 2/3] dt-bindings: mfd: Add Realtek MISC system
 controller
In-Reply-To: <94198d5f-e49f-4b38-8288-3be29efd142b@kernel.org>
References: <20251113123009.26568-1-eleanor.lin@realtek.com>
 <20251113123009.26568-3-eleanor.lin@realtek.com>
 <e799389ce8b4449baba83a893361bdd4@realtek.com>
 <94198d5f-e49f-4b38-8288-3be29efd142b@kernel.org>
Message-ID: <15951264289d44f797ebd4e05238b380@realtek.com>

> 
> On 17/11/2025 12:03, Yu-Chun Lin [???] wrote:
> > Hi Conor and Krzysztof,
> >
> >> Documentation/devicetree/bindings/mfd/realtek,misc.yaml
> >>
> >> diff --git a/Documentation/devicetree/bindings/mfd/realtek,misc.yaml
> >> b/Documentation/devicetree/bindings/mfd/realtek,misc.yaml
> >> new file mode 100644
> >> index 000000000000..4f4a9ae250be
> >> --- /dev/null
> >> +++ b/Documentation/devicetree/bindings/mfd/realtek,misc.yaml
> >> @@ -0,0 +1,72 @@
> >> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
> >> +---
> >> +$id: http://devicetree.org/schemas/mfd/realtek,misc.yaml#
> >> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> >> +
> >> +title: Realtek MISC System Controller
> >> +
> >> +description:
> >> +  The Realtek MISC System Controller is a register area that
> >> +contains
> >> +  miscellaneous system registers for the SoC and serves as a parent
> >> +node
> >> +  for other functions.
> >> +
> >> +maintainers:
> >> +  - James Tai <james.tai at realtek.com>
> >> +  - Yu-Chun Lin <eleanor.lin at realtek.com>
> >> +
> >> +properties:
> >> +  compatible:
> >> +    items:
> >> +      - enum:
> >> +          - realtek,misc
> >
> > I apologize for the current compatible string, which was initially
> > named by referencing existing patterns like 'brcm,misc' and thus
> > violates the naming guidance against "wildcards" and general non-SoC
> specific names.
> >
> > Let me explain the purpose of the device node (Realtek system controller).
> >
> > This MISC area contains several peripheral sub-modules such as uart,
> > watchdog, rtc or i2c ..... These blocks share a unified register
> > region implemented as a single hardware module, which remains powered
> > during system suspend states (e.g., S3). These blocks share the same
> > MMIO region and appear as child nodes under the MISC syscon node.
> > Currently, it
> 
> No, you are mixing hardware with DT representation. This device cannot
> appear as child node, because there is no such concept in hardware as child
> node. You cannot use argument of DT representation when you justify how this
> is represented in DT. It is invalid.
> 
> You need to start argumentation in terms of hardware.
> 

You are right that there is no hardware parent-child relationship between the MISC
controller and the UART block. The MISC registers at 0x98007000 are a system control
(syscon) module, while the UART controller is a separate IP mapped at 0x98007800
on the same RBUS.
In v3, I will moved the UART node to be a direct child of the RBUS bus node.

> 
> > includes uart.
> >
> > Regarding the current structure, the device node is defined in a
> > kent.dtsi and is included by each SoC's DTSI.
> >
> > I've considered two ways to write compatible string naming.
> >
> > Option 1: Use a single SoC-specific compatible string
> >
> > Rename "realtek,misc" to "realtek,rtd1861-misc"
> >
> > /* kent.dtsi */
> > misc: syscon at ... {
> >     compatible = "realtek,rtd1861-misc", "syscon", "simple-mfd"; };
> >
> > Pros: Only one compatible string is needed, simplifying maintenance
> > across the driver and DTS.
> >
> > Cons: Violates the "SoC-specific compatible" rule for other SoCs
> > (RTD1501, RTD1920).
> >
> > Option 2: SoC-specific + fallback (Compliant but Verbose)
> >
> > Define the full list in the schema, and override the compatible string in each
> SoC DTSI.
> >
> > /* schema binding */
> >
> > compatible:
> >   items:
> >     - enum:
> >         - realtek,rtd1501-misc
> >         - realtek,rtd1861-misc
> >         - realtek,rtd1920-misc
> >         # ... add new SoCs here
> >     - const: realtek,kent-misc
> >     - const: syscon
> >     - const: simple-mfd
> >
> >
> > /* kent.dtsi */
> >
> > misc: syscon at ... {
> >     compatible = "realtek,kent-misc", "syscon", "simple-mfd"; };
> >
> > SoC-specific override (e.g. rtd1920s-smallville.dtsi):
> >
> > &misc {
> >     compatible = "realtek,rtd1920-misc", "realtek,kent-misc", "syscon",
> >                  "simple-mfd";
> > };
> >
> > Pros: Fully compliant with DT rules
> >
> > Cons: Requires override in every SoC file; slight duplication.
> >
> > Is Option 2 the expected pattern?
> > Thanks for your guidance!
> >
> 
> None of them. You need SoC specific compatibles which can be used as
> fallbacks for SoC specific compatibles. There is plenty of examples for this
> already, but anyway this does not solve the problem that you still did not
> properly describe the hardware but instead use your downstream as
> arguments.
> 
> This will get you nowhere.

To implement this fallback structure, my understanding is that the
SoC-level DTSI should override the node and prepend its SoC-specific
Compatible, while the common DTSI only provides the family-level
compatible.

/* common DTSI */
misc: syscon at ... {
    compatible = "realtek,kent-misc", "syscon", "simple-mfd";
};

/* SoC-specific DTSI */
&misc {
    compatible = "realtek,rtd1920-misc",
                 "realtek,kent-misc",
                 "syscon", "simple-mfd";
};
Please let me know if this is the intended usage.
> 
> Best regards,
> Krzysztof

From eleanor.lin at realtek.com  Fri Dec 12 18:57:40 2025
From: eleanor.lin at realtek.com (Yu-Chun Lin)
Date: Sat, 13 Dec 2025 02:57:40 -0000
Subject: [PATCH v3 1/2] dt-bindings: arm: realtek: Add Kent Soc family compatibles
In-Reply-To: <20251121084505.3200-1-eleanor.lin@realtek.com>
References: <20251121084505.3200-1-eleanor.lin@realtek.com>
Message-ID: <20251121084505.3200-2-eleanor.lin@realtek.com>

Define compatible strings for Realtek RTD1501s, RTD1861b and RTD1920s.

Additionally, convert legacy DTS-style comments to YAML description
properties, following the pattern from the ARM bindings conversion series
[1].

[1] https://lore.kernel.org/lkml/20200622125527.24207-2-afaerber at suse.de/

Acked-by: Conor Dooley <conor.dooley at microchip.com>
Signed-off-by: Yu-Chun Lin <eleanor.lin at realtek.com>
---
 .../devicetree/bindings/arm/realtek.yaml      | 42 +++++++++++++------
 1 file changed, 30 insertions(+), 12 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/realtek.yaml b/Documentation/devicetree/bindings/arm/realtek.yaml
index ddd9a85099e9..be529490640c 100644
--- a/Documentation/devicetree/bindings/arm/realtek.yaml
+++ b/Documentation/devicetree/bindings/arm/realtek.yaml
@@ -14,21 +14,21 @@ properties:
     const: '/'
   compatible:
     oneOf:
-      # RTD1195 SoC based boards
-      - items:
+      - description: RTD1195 SoC based boards
+        items:
           - enum:
               - mele,x1000 # MeLE X1000
               - realtek,horseradish # Realtek Horseradish EVB
           - const: realtek,rtd1195
 
-      # RTD1293 SoC based boards
-      - items:
+      - description: RTD1293 SoC based boards
+        items:
           - enum:
               - synology,ds418j # Synology DiskStation DS418j
           - const: realtek,rtd1293
 
-      # RTD1295 SoC based boards
-      - items:
+      - description: RTD1295 SoC based boards
+        items:
           - enum:
               - mele,v9 # MeLE V9
               - probox2,ava # ProBox2 AVA
@@ -36,25 +36,43 @@ properties:
               - zidoo,x9s # Zidoo X9S
           - const: realtek,rtd1295
 
-      # RTD1296 SoC based boards
-      - items:
+      - description: RTD1296 SoC based boards
+        items:
           - enum:
               - synology,ds418 # Synology DiskStation DS418
           - const: realtek,rtd1296
 
-      # RTD1395 SoC based boards
-      - items:
+      - description: RTD1395 SoC based boards
+        items:
           - enum:
               - bananapi,bpi-m4 # Banana Pi BPI-M4
               - realtek,lion-skin # Realtek Lion Skin EVB
           - const: realtek,rtd1395
 
-      # RTD1619 SoC based boards
-      - items:
+      - description: RTD1501s SoC based boards
+        items:
+          - enum:
+              - realtek,phantom # Realtek Phantom EVB (8GB)
+          - const: realtek,rtd1501s
+
+      - description: RTD1619 SoC based boards
+        items:
           - enum:
               - realtek,mjolnir # Realtek Mjolnir EVB
           - const: realtek,rtd1619
 
+      - description: RTD1861b SoC based boards
+        items:
+          - enum:
+              - realtek,krypton # Realtek Krypton EVB (8GB)
+          - const: realtek,rtd1861b
+
+      - description: RTD1920s SoC based boards
+        items:
+          - enum:
+              - realtek,smallville # Realtek Smallville EVB (4GB)
+          - const: realtek,rtd1920s
+
 additionalProperties: true
 
 ...
-- 
2.34.1



From eleanor.lin at realtek.com  Fri Dec 12 18:57:45 2025
From: eleanor.lin at realtek.com (Yu-Chun Lin)
Date: Sat, 13 Dec 2025 02:57:45 -0000
Subject: [PATCH v3 2/2] arm64: dts: realtek: Add Kent SoC and EVB device trees
In-Reply-To: <20251121084505.3200-1-eleanor.lin@realtek.com>
References: <20251121084505.3200-1-eleanor.lin@realtek.com>
Message-ID: <20251121084505.3200-3-eleanor.lin@realtek.com>

Add Device Tree hierarchy for Realtek Kent SoC family:

- kent.dtsi: base SoC layer
- rtd<variant>.dtsi: SoC variant layer
- rtd<variant>-<board>.dtsi: board layer
- rtd<variant>-<board>-<config>.dts: board configuration layer

Include RTD1501s Phantom EVB (8GB), RTD1861B Krypton EVB (8GB), and
RTD1920s Smallville EVB (4GB).

Signed-off-by: Yu-Chun Lin <eleanor.lin at realtek.com>
---
 arch/arm64/boot/dts/realtek/Makefile          |   7 +-
 arch/arm64/boot/dts/realtek/kent.dtsi         | 166 ++++++++++++++++++
 arch/arm64/boot/dts/realtek/rtd1501.dtsi      |  12 ++
 .../boot/dts/realtek/rtd1501s-phantom-8gb.dts |  25 +++
 .../boot/dts/realtek/rtd1501s-phantom.dtsi    | 118 +++++++++++++
 arch/arm64/boot/dts/realtek/rtd1861.dtsi      |  12 ++
 .../boot/dts/realtek/rtd1861b-krypton-8gb.dts |  25 +++
 .../boot/dts/realtek/rtd1861b-krypton.dtsi    |  72 ++++++++
 arch/arm64/boot/dts/realtek/rtd1920.dtsi      |  12 ++
 .../dts/realtek/rtd1920s-smallville-4gb.dts   |  23 +++
 .../boot/dts/realtek/rtd1920s-smallville.dtsi | 128 ++++++++++++++
 11 files changed, 596 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm64/boot/dts/realtek/kent.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1501.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1501s-phantom-8gb.dts
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1501s-phantom.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1861.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1861b-krypton-8gb.dts
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1861b-krypton.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1920.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1920s-smallville-4gb.dts
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1920s-smallville.dtsi

diff --git a/arch/arm64/boot/dts/realtek/Makefile b/arch/arm64/boot/dts/realtek/Makefile
index ef8d8fcbaa05..60a37d5a948c 100644
--- a/arch/arm64/boot/dts/realtek/Makefile
+++ b/arch/arm64/boot/dts/realtek/Makefile
@@ -1,15 +1,14 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1293-ds418j.dtb
-
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1295-mele-v9.dtb
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1295-probox2-ava.dtb
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1295-xnano-x5.dtb
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1295-zidoo-x9s.dtb
-
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1296-ds418.dtb
-
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1395-bpi-m4.dtb
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1395-lionskin.dtb
-
+dtb-$(CONFIG_ARCH_REALTEK) += rtd1501s-phantom-8gb.dtb
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1619-mjolnir.dtb
+dtb-$(CONFIG_ARCH_REALTEK) += rtd1861b-krypton-8gb.dtb
+dtb-$(CONFIG_ARCH_REALTEK) += rtd1920s-smallville-4gb.dtb
diff --git a/arch/arm64/boot/dts/realtek/kent.dtsi b/arch/arm64/boot/dts/realtek/kent.dtsi
new file mode 100644
index 000000000000..ae006ce24420
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/kent.dtsi
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Realtek Kent SoC family
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	aliases {
+		serial0 = &uart0;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI  9 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu0: cpu at 0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a78";
+			reg = <0x0>;
+			enable-method = "psci";
+			next-level-cache = <&l2_0>;
+			dynamic-power-coefficient = <454>;
+			#cooling-cells = <2>;
+
+			l2_0: l2-cache {
+				compatible = "cache";
+				cache-level = <2>;
+				cache-line-size = <64>;
+				cache-sets = <256>;
+				cache-size = <0x40000>;
+				cache-unified;
+				next-level-cache = <&l3>;
+			};
+		};
+
+		cpu1: cpu at 100 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a78";
+			reg = <0x100>;
+			enable-method = "psci";
+			next-level-cache = <&l2_1>;
+			dynamic-power-coefficient = <454>;
+			#cooling-cells = <2>;
+
+			l2_1: l2-cache {
+				compatible = "cache";
+				cache-level = <2>;
+				cache-line-size = <64>;
+				cache-sets = <256>;
+				cache-size = <0x40000>;
+				cache-unified;
+				next-level-cache = <&l3>;
+			};
+		};
+
+		cpu2: cpu at 200 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a78";
+			reg = <0x200>;
+			enable-method = "psci";
+			next-level-cache = <&l2_2>;
+			dynamic-power-coefficient = <454>;
+			#cooling-cells = <2>;
+
+			l2_2: l2-cache {
+				compatible = "cache";
+				cache-level = <2>;
+				cache-line-size = <64>;
+				cache-sets = <256>;
+				cache-size = <0x40000>;
+				cache-unified;
+				next-level-cache = <&l3>;
+			};
+		};
+
+		cpu3: cpu at 300 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a78";
+			reg = <0x300>;
+			enable-method = "psci";
+			next-level-cache = <&l2_3>;
+			dynamic-power-coefficient = <454>;
+			#cooling-cells = <2>;
+
+			l2_3: l2-cache {
+				compatible = "cache";
+				cache-level = <2>;
+				cache-line-size = <64>;
+				cache-sets = <256>;
+				cache-size = <0x40000>;
+				cache-unified;
+				next-level-cache = <&l3>;
+			};
+		};
+
+		l3: l3-cache {
+			compatible = "cache";
+			cache-level = <3>;
+			cache-line-size = <64>;
+			cache-sets = <512>;
+			cache-size = <0x200000>;
+			cache-unified;
+		};
+	};
+
+	psci: psci {
+		compatible = "arm,psci-1.0";
+		method = "smc";
+	};
+
+	soc at 0 {
+		compatible = "simple-bus";
+		ranges = <0x0 0x0 0x0 0x40000>, /* boot code */
+			 <0x98000000 0x0 0x98000000 0xef0000>, /* rbus */
+			 <0xa0000000 0x0 0xa0000000 0x10000000>, /* PCIE */
+			 <0xff000000 0x0 0xff000000 0x200000>; /* GIC */
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		rbus: bus at 98000000 {
+			compatible = "simple-bus";
+			ranges = <0x0 0x98000000 0xef0000>,
+				 <0xa0000000 0xa0000000 0x10000000>; /* PCIE */
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			uart0: serial at 7800 {
+				compatible = "snps,dw-apb-uart";
+				reg = <0x7800 0x100>;
+				clock-frequency = <432000000>;
+				interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
+				reg-io-width = <4>;
+				reg-shift = <2>;
+				status = "disabled";
+			};
+		};
+
+		gic: interrupt-controller at ff100000 {
+			compatible = "arm,gic-v3";
+			reg = <0xff100000 0x10000>,
+			      <0xff140000 0x80000>;
+			interrupt-controller;
+			interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#interrupt-cells = <3>;
+			#size-cells = <1>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/realtek/rtd1501.dtsi b/arch/arm64/boot/dts/realtek/rtd1501.dtsi
new file mode 100644
index 000000000000..65f7ede3df73
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1501.dtsi
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Realtek RTD1501 SoC
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+#include "kent.dtsi"
+
+&uart0 {
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/realtek/rtd1501s-phantom-8gb.dts b/arch/arm64/boot/dts/realtek/rtd1501s-phantom-8gb.dts
new file mode 100644
index 000000000000..09e544acfd34
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1501s-phantom-8gb.dts
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Realtek RTD1501S Phantom EVB
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+/dts-v1/;
+
+#include "rtd1501s-phantom.dtsi"
+
+/ {
+	compatible = "realtek,phantom", "realtek,rtd1501s";
+	model = "Realtek Phantom EVB Chromium (8GB)";
+
+	memory at 40000 {
+		device_type = "memory";
+		reg = <0x0 0x50000 0x0 0x7ffb0000>,
+		      <0x0 0x8a100000 0x0 0xdef0000>,
+		      <0x0 0x98700000 0x0 0x7900000>,
+		      <0x0 0xa0600000 0x0 0x5ea00000>,
+		      <0x1 0x0 0x0 0xa0000000>,
+		      <0x1 0xa0600000 0x0 0x5fa00000>;
+	};
+};
diff --git a/arch/arm64/boot/dts/realtek/rtd1501s-phantom.dtsi b/arch/arm64/boot/dts/realtek/rtd1501s-phantom.dtsi
new file mode 100644
index 000000000000..bcfb96799671
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1501s-phantom.dtsi
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Realtek RTD1501S Phantom EVB
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/thermal/thermal.h>
+#include "rtd1501.dtsi"
+
+/ {
+	chosen {
+		stdout-path = "serial0:460800n8";
+	};
+
+	reserved_memory: reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		linux,cma {
+			compatible = "shared-dma-pool";
+			alignment = <0x0 0x400000>;
+			alloc-ranges = <0x0 0x0 0x0 0x20000000>;
+			size = <0x0 0x2000000>;
+			reusable;
+			linux,cma-default;
+		};
+	};
+
+	cpu_opps: opp-table-cpu {
+		compatible = "operating-points-v2";
+		opp-shared;
+
+		opp800: opp-800000000 {
+			opp-hz = /bits/ 64 <800000000>;
+			opp-microvolt = <830000 830000 1100000>;
+		};
+
+		opp900: opp-900000000 {
+			opp-hz = /bits/ 64 <900000000>;
+			opp-microvolt = <850000 850000 1100000>;
+		};
+
+		opp1000: opp-1000000000 {
+			opp-hz = /bits/ 64 <1000000000>;
+			opp-microvolt = <870000 870000 1100000>;
+		};
+
+		opp1100: opp-1100000000 {
+			opp-hz = /bits/ 64 <1100000000>;
+			opp-microvolt = <890000 890000 1100000>;
+		};
+
+		opp1200: opp-1200000000 {
+			opp-hz = /bits/ 64 <1200000000>;
+			opp-microvolt = <910000 910000 1100000>;
+		};
+
+		opp1300: opp-1300000000 {
+			opp-hz = /bits/ 64 <1300000000>;
+			opp-microvolt = <930000 930000 1100000>;
+		};
+
+		opp1400: opp-1400000000 {
+			opp-hz = /bits/ 64 <1400000000>;
+			opp-microvolt = <950000 950000 1100000>;
+		};
+
+		opp1500: opp-1500000000 {
+			opp-hz = /bits/ 64 <1500000000>;
+			opp-microvolt = <970000 970000 1100000>;
+		};
+
+		opp1600: opp-1600000000 {
+			opp-hz = /bits/ 64 <1600000000>;
+			opp-microvolt = <990000 990000 1100000>;
+			opp-suspend;
+		};
+
+		opp1700: opp-1700000000 {
+			opp-hz = /bits/ 64 <1700000000>;
+			opp-microvolt = <1010000 1010000 1100000>;
+		};
+
+		opp1800: opp-1800000000 {
+			opp-hz = /bits/ 64 <1800000000>;
+			opp-microvolt = <1030000 1030000 1100000>;
+		};
+
+		opp1900: opp-1900000000 {
+			opp-hz = /bits/ 64 <1900000000>;
+			opp-microvolt = <1050000 1050000 1100000>;
+		};
+	};
+};
+
+&cpu0 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu1 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu2 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu3 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
diff --git a/arch/arm64/boot/dts/realtek/rtd1861.dtsi b/arch/arm64/boot/dts/realtek/rtd1861.dtsi
new file mode 100644
index 000000000000..44c3de8f1f48
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1861.dtsi
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Realtek RTD1861 SoC
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+#include "kent.dtsi"
+
+&uart0 {
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/realtek/rtd1861b-krypton-8gb.dts b/arch/arm64/boot/dts/realtek/rtd1861b-krypton-8gb.dts
new file mode 100644
index 000000000000..9c23d901c49c
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1861b-krypton-8gb.dts
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Realtek RTD1861B Krypton EVB
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+/dts-v1/;
+
+#include "rtd1861b-krypton.dtsi"
+
+/ {
+	compatible = "realtek,krypton", "realtek,rtd1861b";
+	model = "Realtek Krypton EVB (8GB)";
+
+	memory at 40000 {
+		device_type = "memory";
+		reg = <0x0 0x50000 0x0 0x7ffb0000>,
+		      <0x0 0x8a100000 0x0 0xdef0000>,
+		      <0x0 0x98700000 0x0 0x7900000>,
+		      <0x0 0xa0600000 0x0 0x5ea00000>,
+		      <0x1 0x0 0x0 0xa0000000>,
+		      <0x1 0xa0600000 0x0 0x5fa00000>;
+	};
+};
diff --git a/arch/arm64/boot/dts/realtek/rtd1861b-krypton.dtsi b/arch/arm64/boot/dts/realtek/rtd1861b-krypton.dtsi
new file mode 100644
index 000000000000..b500f4d2c502
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1861b-krypton.dtsi
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Realtek RTD1861B Krypton EVB
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+/dts-v1/;
+
+#include "rtd1861.dtsi"
+
+/ {
+	chosen {
+		stdout-path = "serial0:460800n8";
+	};
+
+	reserved_memory: reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		linux,cma {
+			compatible = "shared-dma-pool";
+			alignment = <0x0 0x400000>;
+			alloc-ranges = <0x0 0x0 0x0 0x20000000>;
+			size = <0x0 0x2000000>;
+			reusable;
+			linux,cma-default;
+		};
+	};
+
+	cpu_opps: opp-table-cpu {
+		compatible = "operating-points-v2";
+		opp-shared;
+
+		opp1200: opp-1200000000 {
+			opp-hz = /bits/ 64 <1200000000>;
+			opp-microvolt = <900000>;
+		};
+
+		opp1600: opp-1600000000 {
+			opp-hz = /bits/ 64 <1600000000>;
+			opp-microvolt = <1000000>;
+			opp-suspend;
+		};
+
+		opp1800: opp-1800000000 {
+			opp-hz = /bits/ 64 <1800000000>;
+			opp-microvolt = <1050000>;
+		};
+	};
+};
+
+&cpu0 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu1 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu2 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu3 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
diff --git a/arch/arm64/boot/dts/realtek/rtd1920.dtsi b/arch/arm64/boot/dts/realtek/rtd1920.dtsi
new file mode 100644
index 000000000000..becf546216e9
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1920.dtsi
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Realtek RTD1920 SoC
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+#include "kent.dtsi"
+
+&uart0 {
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/realtek/rtd1920s-smallville-4gb.dts b/arch/arm64/boot/dts/realtek/rtd1920s-smallville-4gb.dts
new file mode 100644
index 000000000000..9fd6976e0d9b
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1920s-smallville-4gb.dts
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Realtek RTD1920S Smallville EVB
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+/dts-v1/;
+
+#include "rtd1920s-smallville.dtsi"
+
+/ {
+	compatible = "realtek,smallville", "realtek,rtd1920s";
+	model = "Realtek Smallville EVB (4GB)";
+
+	memory at 40000 {
+		device_type = "memory";
+		reg = <0x0 0x50000 0x0 0x7ffb0000>,
+		      <0x0 0x8a100000 0x0 0xdef0000>,
+		      <0x0 0x98700000 0x0 0x7900000>,
+		      <0x0 0xa1000000 0x0 0x5e000000>;
+	};
+};
diff --git a/arch/arm64/boot/dts/realtek/rtd1920s-smallville.dtsi b/arch/arm64/boot/dts/realtek/rtd1920s-smallville.dtsi
new file mode 100644
index 000000000000..3db8fcea6447
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1920s-smallville.dtsi
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Realtek RTD1920S Smallville EVB
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/thermal/thermal.h>
+#include "rtd1920.dtsi"
+
+/ {
+	chosen {
+		stdout-path = "serial0:460800n8";
+	};
+
+	reserved_memory: reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		protected_mem: protected-mem at 50000 {
+			reg = <0x0 0x50000 0x0 0xbf0000>;
+			no-map;
+		};
+
+		metadata: metadata at c40000 {
+			reg = <0x0 0xc40000 0x0 0x3c4000>;
+			no-map;
+		};
+
+		linux,cma {
+			compatible = "shared-dma-pool";
+			alignment = <0x0 0x400000>;
+			alloc-ranges = <0x0 0x0 0x0 0x20000000>;
+			size = <0x0 0x2000000>;
+			reusable;
+			linux,cma-default;
+		};
+	};
+
+	cpu_opps: opp-table-cpu {
+		compatible = "operating-points-v2";
+		opp-shared;
+
+		opp800: opp-800000000 {
+			opp-hz = /bits/ 64 <800000000>;
+			opp-microvolt = <830000 830000 1100000>;
+		};
+
+		opp900: opp-900000000 {
+			opp-hz = /bits/ 64 <900000000>;
+			opp-microvolt = <850000 850000 1100000>;
+		};
+
+		opp1000: opp-1000000000 {
+			opp-hz = /bits/ 64 <1000000000>;
+			opp-microvolt = <870000 870000 1100000>;
+		};
+
+		opp1100: opp-1100000000 {
+			opp-hz = /bits/ 64 <1100000000>;
+			opp-microvolt = <890000 890000 1100000>;
+		};
+
+		opp1200: opp-1200000000 {
+			opp-hz = /bits/ 64 <1200000000>;
+			opp-microvolt = <910000 910000 1100000>;
+		};
+
+		opp1300: opp-1300000000 {
+			opp-hz = /bits/ 64 <1300000000>;
+			opp-microvolt = <930000 930000 1100000>;
+		};
+
+		opp1400: opp-1400000000 {
+			opp-hz = /bits/ 64 <1400000000>;
+			opp-microvolt = <950000 950000 1100000>;
+		};
+
+		opp1500: opp-1500000000 {
+			opp-hz = /bits/ 64 <1500000000>;
+			opp-microvolt = <970000 970000 1100000>;
+		};
+
+		opp1600: opp-1600000000 {
+			opp-hz = /bits/ 64 <1600000000>;
+			opp-microvolt = <990000 990000 1100000>;
+			opp-suspend;
+		};
+
+		opp1700: opp-1700000000 {
+			opp-hz = /bits/ 64 <1700000000>;
+			opp-microvolt = <1010000 1010000 1100000>;
+		};
+
+		opp1800: opp-1800000000 {
+			opp-hz = /bits/ 64 <1800000000>;
+			opp-microvolt = <1030000 1030000 1100000>;
+		};
+
+		opp1900: opp-1900000000 {
+			opp-hz = /bits/ 64 <1900000000>;
+			opp-microvolt = <1050000 1050000 1100000>;
+		};
+	};
+};
+
+&cpu0 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu1 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu2 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu3 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
-- 
2.34.1



From eleanor.lin at realtek.com  Fri Dec 12 18:57:47 2025
From: eleanor.lin at realtek.com (Yu-Chun Lin)
Date: Sat, 13 Dec 2025 02:57:47 -0000
Subject: [PATCH v3 0/2] arm64: dts: Add support for Kent SoC family
Message-ID: <20251121084505.3200-1-eleanor.lin@realtek.com>

Hello,

This patch series adds initial Device Tree support for Realtek's Kent SoC
family, including the RTD1501S, RTD1861B, and RTD1920S variants with their
respective evaluation boards.

The series includes:

1. Adds compatible strings for the Kent family.
2. Add Device Tree files for the Kent SoC, TD1501S Phantom EVB (8GB),
RTD1861B Krypton EVB (8GB), and RTD1920S Smallville EVB (4GB).

The patches have been validated with 'make dtbs_check' and
'dt_binding_check' to ensure compliance with DT schema and successful
compilation.

Cheers,
Yu-Chun

Signed-off-by: Yu-Chun Lin <eleanor.lin at realtek.com>
---
Changes in v3:

- Drop the dt-bindings patch (realtek,misc.yaml)
- Drop 'iso: syscon at 7000' node and and re-parent the UART directly to rbus
- Change all dts/dtsi to license: GPL-2.0
- Drop all custom bootargs

V2: https://lore.kernel.org/lkml/20251113123009.26568-1-eleanor.lin at realtek.com/

Changes in v2:

[PATCH v2 1/3]
- Fix YAML syntax: remove duplicate blank lines
- Validated with 'make dt_binding_check'

[PATCH v2 2/3]
- Rename: realtek,iso-system.yaml -> realtek,misc.yaml
- Improve description and example: show child node (UART)

[PATCH v2 3/3]
- Reorder Makefile targets to alphabetical order.
- Rename node: use generic names ('arch_timer' -> 'timer', 'reg-bus' -> 'bus')
- Fix node naming and hex format (remove leading zeros)
- Inline overlay nodes directly into .dtsi
- Reorder properties: ranges after reg
- Remove unnecessary status and custom bootargs

V1: https://lore.kernel.org/lkml/20251105104452.6336-1-eleanor.lin at realtek.com/

Yu-Chun Lin (2):
  dt-bindings: arm: realtek: Add Kent Soc family compatibles
  arm64: dts: realtek: Add Kent SoC and EVB device trees

 .../devicetree/bindings/arm/realtek.yaml      |  42 +++--
 arch/arm64/boot/dts/realtek/Makefile          |   7 +-
 arch/arm64/boot/dts/realtek/kent.dtsi         | 166 ++++++++++++++++++
 arch/arm64/boot/dts/realtek/rtd1501.dtsi      |  12 ++
 .../boot/dts/realtek/rtd1501s-phantom-8gb.dts |  25 +++
 .../boot/dts/realtek/rtd1501s-phantom.dtsi    | 118 +++++++++++++
 arch/arm64/boot/dts/realtek/rtd1861.dtsi      |  12 ++
 .../boot/dts/realtek/rtd1861b-krypton-8gb.dts |  25 +++
 .../boot/dts/realtek/rtd1861b-krypton.dtsi    |  72 ++++++++
 arch/arm64/boot/dts/realtek/rtd1920.dtsi      |  12 ++
 .../dts/realtek/rtd1920s-smallville-4gb.dts   |  23 +++
 .../boot/dts/realtek/rtd1920s-smallville.dtsi | 128 ++++++++++++++
 12 files changed, 626 insertions(+), 16 deletions(-)
 create mode 100644 arch/arm64/boot/dts/realtek/kent.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1501.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1501s-phantom-8gb.dts
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1501s-phantom.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1861.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1861b-krypton-8gb.dts
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1861b-krypton.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1920.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1920s-smallville-4gb.dts
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1920s-smallville.dtsi

-- 
2.34.1



From krzk at kernel.org  Fri Dec 12 18:58:52 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sat, 13 Dec 2025 03:58:52 +0100
Subject: [PATCH] dt-bindings: Remove unused includes
In-Reply-To: <20251212231203.727227-1-robh@kernel.org>
References: <20251212231203.727227-1-robh@kernel.org>
Message-ID: <02201ae8-d705-4896-a3ff-9b2d5cf833f8@kernel.org>

On 13/12/2025 00:11, Rob Herring (Arm) wrote:
> Remove includes which are not referenced by either DTS files or drivers.
> 
> There's a few more which are new, so they are excluded for now.
> 
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>


Oh yes!

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof


From krzk at kernel.org  Fri Dec 12 19:01:17 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sat, 13 Dec 2025 04:01:17 +0100
Subject: [PATCH] arm/arm64: dts: st: Drop unused .dtsi
In-Reply-To: <20251212203226.458694-3-robh@kernel.org>
References: <20251212203226.458694-3-robh@kernel.org>
Message-ID: <eb752290-0eb3-4817-b3ca-91a4f423dac4@kernel.org>

On 12/12/2025 21:32, Rob Herring (Arm) wrote:
> These .dtsi files are not included anywhere in the tree and can't be
> tested.
> 
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> ---
>  arch/arm/boot/dts/st/spear320s.dtsi           | 24 -------
>  .../boot/dts/st/stm32mp15xxab-pinctrl.dtsi    | 57 ---------------
>  arch/arm64/boot/dts/qcom/msm8996-v3.0.dtsi    | 63 ----------------


This should go to the qcom one.

Best regards,
Krzysztof


From krzk at kernel.org  Fri Dec 12 19:05:39 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sat, 13 Dec 2025 04:05:39 +0100
Subject: [PATCH 3/8] dt-bindings: watchdog: Add AAEON embedded controller
 watchdog binding
In-Reply-To: <cb8031bb-9213-49b7-a85a-5ca9091aee5c@roeck-us.net>
References: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com>
 <20251212-dev-b4-aaeon-mcu-driver-v1-3-6bd65bc8ef12@bootlin.com>
 <019aa49f-fe59-488d-aff8-f07cf07ee68d@kernel.org>
 <cb8031bb-9213-49b7-a85a-5ca9091aee5c@roeck-us.net>
Message-ID: <176bd9cf-688a-480e-93b7-8f1710563c56@kernel.org>

On 12/12/2025 12:46, Guenter Roeck wrote:
> On 12/12/25 00:20, Krzysztof Kozlowski wrote:
>> On 12/12/2025 08:41, Thomas Perrot (Schneider Electric) wrote:
>>> +
>>> +additionalProperties: false
>>> +
>>> +examples:
>>> +  - |
>>> +    watchdog {
>>> +      compatible = "aaeon,srg-imx8pl-wdt";
>>
>> No, that was discussed many times on the mailing list already. Fold the
>> child into the parent. Your driver model really do not matter for DT.
>>
> 
> Theoretically there could be a 'timeout' property since this is
> a watchdog driver, but that isn't supported by the driver, so
> I agree.
> 

Timeout can be added to the parent node. The most differentiating factor
are dedicated resources and none are here.

Best regards,
Krzysztof


From broonie at kernel.org  Fri Dec 12 19:16:03 2025
From: broonie at kernel.org (Mark Brown)
Date: Sat, 13 Dec 2025 12:16:03 +0900
Subject: [PATCH] dt-bindings: Remove unused includes
In-Reply-To: <20251212231203.727227-1-robh@kernel.org>
References: <20251212231203.727227-1-robh@kernel.org>
Message-ID: <aTzaczBfsrH2nY5w@sirena.co.uk>

On Fri, Dec 12, 2025 at 05:11:52PM -0600, Rob Herring (Arm) wrote:
> Remove includes which are not referenced by either DTS files or drivers.
> 
> There's a few more which are new, so they are excluded for now.

Acked-by: Mark Brown <broonie at kernel.org>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251213/346ce135/attachment.sig>

From liujianfeng1994 at gmail.com  Fri Dec 12 21:50:52 2025
From: liujianfeng1994 at gmail.com (Jianfeng Liu)
Date: Sat, 13 Dec 2025 13:50:52 +0800
Subject: [PATCH] media: rkvdec: set ctx->image_fmt in rkvdec_s_capture_fmt
In-Reply-To: <5c2dec91-667f-48f6-b958-e0cf81cab569@kwiboo.se>
References: <5c2dec91-667f-48f6-b958-e0cf81cab569@kwiboo.se>
Message-ID: <20251213055052.3046554-1-liujianfeng1994@gmail.com>

On Fri, 12 Dec 2025 17:43:35 +0100, Jonas Karlman wrote:
>Chromium should be fixed to follow spec at 4.5.3.2. Initialization [1]:

Hi Jonas,

Thank you for guiding me to the spec, I will look into chromium and try
to fix it.

Best regards,
Jianfeng


From liujianfeng1994 at gmail.com  Fri Dec 12 21:59:42 2025
From: liujianfeng1994 at gmail.com (Jianfeng Liu)
Date: Sat, 13 Dec 2025 13:59:42 +0800
Subject: [PATCH] media: rkvdec: set ctx->image_fmt in rkvdec_s_capture_fmt
In-Reply-To: <8f24c8204984a46bad7d0bb24b78c8115906f748.camel@collabora.com>
References: <8f24c8204984a46bad7d0bb24b78c8115906f748.camel@collabora.com>
Message-ID: <20251213055942.3046647-1-liujianfeng1994@gmail.com>

Hi,

On Fri, 12 Dec 2025 12:53:53 -0500, Nicolas Dufresne wrote:
>I'm reading you here, and reading the spec again [0], and you are saying the
>Chromium isn't following the initialization process. That means, it should be
>impossible to allocate 10bit capture buffer, since the SPS in place specify the
>color depth. Other parameters in other codec can influence the reference buffer
>size, so you could endup with the wrong allocation.

Chromium does follow the spec when decoding 10bit videos[1], but that is
still limited to hevc and vp9. For h264 and 8bit video chromium thinks
this is unnecessary.

>You cannot accept a format that falls against the color depth in the SPS
>control, and rkvdec does not do color conversion implicitly. This can otherwise
>lead to letting the HW overrun the buffer (forcing 8bit with 10bit content). Can
>you check with Chromium dev if they can perhaps adhere to the spec instead ?
>This is all news to me, but I probably never had to test 10bit playback in
>Chromium outside of MTK (which might not be less strict, hopefully done the
>right way).

I will try to fix chromium to follow the spec. Since rkvdec driver is the
only driver related, I didn't check the stateless spec.

[1]https://github.com/chromium/chromium/blob/145.0.7577.2/media/gpu/v4l2/v4l2_video_decoder.cc#L648-L650

Best regards,
Jianfeng


From lkp at intel.com  Fri Dec 12 21:59:37 2025
From: lkp at intel.com (kernel test robot)
Date: Sat, 13 Dec 2025 13:59:37 +0800
Subject: [PATCH 14/32] KVM: arm64: gic-v5: Implement GICv5 load/put and
 save/restore
In-Reply-To: <20251212152215.675767-15-sascha.bischoff@arm.com>
References: <20251212152215.675767-15-sascha.bischoff@arm.com>
Message-ID: <202512131338.pYhd9ptc-lkp@intel.com>

Hi Sascha,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on next-20251212]
[cannot apply to kvmarm/next arm64/for-next/core kvm/queue kvm/next kvm/linux-next v6.18]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Sascha-Bischoff/KVM-arm64-Account-for-RES1-bits-in-DECLARE_FEAT_MAP-and-co/20251212-233140
base:   linus/master
patch link:    https://lore.kernel.org/r/20251212152215.675767-15-sascha.bischoff%40arm.com
patch subject: [PATCH 14/32] KVM: arm64: gic-v5: Implement GICv5 load/put and save/restore
config: arm64-allnoconfig (https://download.01.org/0day-ci/archive/20251213/202512131338.pYhd9ptc-lkp at intel.com/config)
compiler: aarch64-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251213/202512131338.pYhd9ptc-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512131338.pYhd9ptc-lkp at intel.com/

All errors (new ones prefixed by >>):

   In file included from arch/arm64/include/asm/kvm_host.h:36,
                    from include/linux/kvm_host.h:45,
                    from arch/arm64/kernel/asm-offsets.c:16:
>> include/kvm/arm_vgic.h:392:26: error: field 'gicv5_vpe' has incomplete type
     392 |         struct gicv5_vpe gicv5_vpe;
         |                          ^~~~~~~~~
   make[3]: *** [scripts/Makefile.build:182: arch/arm64/kernel/asm-offsets.s] Error 1
   make[3]: Target 'prepare' not remade because of errors.
   make[2]: *** [Makefile:1314: prepare0] Error 2
   make[2]: Target 'prepare' not remade because of errors.
   make[1]: *** [Makefile:248: __sub-make] Error 2
   make[1]: Target 'prepare' not remade because of errors.
   make: *** [Makefile:248: __sub-make] Error 2
   make: Target 'prepare' not remade because of errors.


vim +/gicv5_vpe +392 include/kvm/arm_vgic.h

   360	
   361	struct vgic_v5_cpu_if {
   362		u64	vgic_apr;
   363		u64	vgic_vmcr;
   364	
   365		/* PPI register state */
   366		u64	vgic_ppi_hmr[2];
   367		u64	vgic_ppi_dvir[2];
   368		u64	vgic_ppi_priorityr[16];
   369	
   370		/* The pending state of the guest. This is merged with the exit state */
   371		u64	vgic_ppi_pendr[2];
   372	
   373		/* The state flushed to the regs when entering the guest */
   374		u64	vgic_ppi_activer_entry[2];
   375		u64	vgic_ich_ppi_enabler_entry[2];
   376		u64	vgic_ppi_pendr_entry[2];
   377	
   378		/* The saved state of the regs when leaving the guest */
   379		u64	vgic_ppi_activer_exit[2];
   380		u64	vgic_ich_ppi_enabler_exit[2];
   381		u64	vgic_ppi_pendr_exit[2];
   382	
   383		/*
   384		 * The ICSR is re-used across host and guest, and hence it needs to be
   385		 * saved/restored. Only one copy is required as the host should block
   386		 * preemption between executing GIC CDRCFG and acccessing the
   387		 * ICC_ICSR_EL1. A guest, of course, can never guarantee this, and hence
   388		 * it is the hyp's responsibility to keep the state constistent.
   389		 */
   390		u64	vgic_icsr;
   391	
 > 392		struct gicv5_vpe gicv5_vpe;
   393	};
   394	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From lkp at intel.com  Fri Dec 12 22:22:24 2025
From: lkp at intel.com (kernel test robot)
Date: Sat, 13 Dec 2025 14:22:24 +0800
Subject: [PATCH 6/8] gpio: aaeon: Add GPIO driver for SRG-IMX8PL MCU
In-Reply-To: <20251212-dev-b4-aaeon-mcu-driver-v1-6-6bd65bc8ef12@bootlin.com>
References: <20251212-dev-b4-aaeon-mcu-driver-v1-6-6bd65bc8ef12@bootlin.com>
Message-ID: <202512131342.1nkKkryD-lkp@intel.com>

Hi Thomas,

kernel test robot noticed the following build errors:

[auto build test ERROR on d358e5254674b70f34c847715ca509e46eb81e6f]

url:    https://github.com/intel-lab-lkp/linux/commits/Thomas-Perrot-Schneider-Electric/dt-bindings-vendor-prefixes-Add-AAEON-vendor-prefix/20251212-154458
base:   d358e5254674b70f34c847715ca509e46eb81e6f
patch link:    https://lore.kernel.org/r/20251212-dev-b4-aaeon-mcu-driver-v1-6-6bd65bc8ef12%40bootlin.com
patch subject: [PATCH 6/8] gpio: aaeon: Add GPIO driver for SRG-IMX8PL MCU
config: arc-randconfig-r132-20251213 (https://download.01.org/0day-ci/archive/20251213/202512131342.1nkKkryD-lkp at intel.com/config)
compiler: arc-linux-gcc (GCC) 14.3.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251213/202512131342.1nkKkryD-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512131342.1nkKkryD-lkp at intel.com/

All errors (new ones prefixed by >>):

   `.exit.text' referenced in section `__jump_table' of lib/test_dynamic_debug.o: defined in discarded section `.exit.text' of lib/test_dynamic_debug.o
   `.exit.text' referenced in section `__jump_table' of lib/test_dynamic_debug.o: defined in discarded section `.exit.text' of lib/test_dynamic_debug.o
   arc-linux-ld: drivers/gpio/gpio-aaeon-mcu.o: in function `aaeon_mcu_gpio_get':
>> drivers/gpio/gpio-aaeon-mcu.c:124:(.text+0x4c): undefined reference to `aaeon_mcu_i2c_xfer'
>> arc-linux-ld: drivers/gpio/gpio-aaeon-mcu.c:124:(.text+0x4c): undefined reference to `aaeon_mcu_i2c_xfer'
   arc-linux-ld: drivers/gpio/gpio-aaeon-mcu.o: in function `aaeon_mcu_gpio_set':
   drivers/gpio/gpio-aaeon-mcu.c:139:(.text+0x100): undefined reference to `aaeon_mcu_i2c_xfer'
   arc-linux-ld: drivers/gpio/gpio-aaeon-mcu.c:139:(.text+0x100): undefined reference to `aaeon_mcu_i2c_xfer'
   arc-linux-ld: drivers/gpio/gpio-aaeon-mcu.c:150:(.text+0x172): undefined reference to `aaeon_mcu_i2c_xfer'
   arc-linux-ld: drivers/gpio/gpio-aaeon-mcu.o:drivers/gpio/gpio-aaeon-mcu.c:150: more undefined references to `aaeon_mcu_i2c_xfer' follow
   `.exit.text' referenced in section `__jump_table' of drivers/target/target_core_configfs.o: defined in discarded section `.exit.text' of drivers/target/target_core_configfs.o
   `.exit.text' referenced in section `__jump_table' of drivers/target/target_core_configfs.o: defined in discarded section `.exit.text' of drivers/target/target_core_configfs.o

sparse warnings: (new ones prefixed by >>)
>> drivers/gpio/gpio-aaeon-mcu.c:246:1: sparse: sparse: bad integer constant expression
   drivers/gpio/gpio-aaeon-mcu.c:246:1: sparse: sparse: static assertion failed: "MODULE_INFO(description, ...) contains embedded NUL byte"
   drivers/gpio/gpio-aaeon-mcu.c:247:1: sparse: sparse: bad integer constant expression
   drivers/gpio/gpio-aaeon-mcu.c:247:1: sparse: sparse: static assertion failed: "MODULE_INFO(author, ...) contains embedded NUL byte"
   drivers/gpio/gpio-aaeon-mcu.c:248:1: sparse: sparse: bad integer constant expression
   drivers/gpio/gpio-aaeon-mcu.c:248:1: sparse: sparse: static assertion failed: "MODULE_INFO(file, ...) contains embedded NUL byte"
   drivers/gpio/gpio-aaeon-mcu.c:248:1: sparse: sparse: bad integer constant expression
   drivers/gpio/gpio-aaeon-mcu.c:248:1: sparse: sparse: static assertion failed: "MODULE_INFO(license, ...) contains embedded NUL byte"

vim +124 drivers/gpio/gpio-aaeon-mcu.c

   110	
   111	static int aaeon_mcu_gpio_get(struct gpio_chip *gc, unsigned int offset)
   112	{
   113		struct aaeon_mcu_gpio *data = gpiochip_get_data(gc);
   114		u8 cmd[3], rsp;
   115		int ret;
   116	
   117		if (offset < MAX_GPOS)
   118			return test_bit(offset, data->gpo_state);
   119	
   120		cmd[0] = AAEON_MCU_READ_GPIO;
   121		cmd[1] = offset - 7;
   122		cmd[2] = 0x00;
   123	
 > 124		ret = aaeon_mcu_i2c_xfer(data->mfd->i2c_client, cmd, 3, &rsp, 1);
   125		if (ret < 0)
   126			return ret;
   127	
   128		return rsp;
   129	}
   130	
   131	static int aaeon_mcu_gpo_set_cmd(struct aaeon_mcu_gpio *data, unsigned int offset, int value)
   132	{
   133		u8 cmd[3], rsp;
   134	
   135		cmd[0] = AAEON_MCU_CONTROL_GPO;
   136		cmd[1] = offset + 1;
   137		cmd[2] = !!value;
   138	
   139		return aaeon_mcu_i2c_xfer(data->mfd->i2c_client, cmd, 3, &rsp, 1);
   140	}
   141	
   142	static int aaeon_mcu_gpio_set_cmd(struct aaeon_mcu_gpio *data, unsigned int offset, int value)
   143	{
   144		u8 cmd[3], rsp;
   145	
   146		cmd[0] = AAEON_MCU_WRITE_GPIO;
   147		cmd[1] = offset - 7;
   148		cmd[2] = !!value;
   149	
   150		return aaeon_mcu_i2c_xfer(data->mfd->i2c_client, cmd, 3, &rsp, 1);
   151	}
   152	
   153	static int aaeon_mcu_gpio_set(struct gpio_chip *gc, unsigned int offset,
   154				      int value)
   155	{
   156		struct aaeon_mcu_gpio *data = gpiochip_get_data(gc);
   157	
   158		if (offset < MAX_GPOS) {
   159			if (aaeon_mcu_gpo_set_cmd(data, offset, value) == 0)
   160				assign_bit(offset, data->gpo_state, value);
   161		} else {
   162			return aaeon_mcu_gpio_set_cmd(data, offset, value);
   163		}
   164		return 0;
   165	}
   166	
   167	static const struct gpio_chip aaeon_mcu_chip = {
   168		.label			= "gpio-aaeon-mcu",
   169		.owner			= THIS_MODULE,
   170		.get_direction		= aaeon_mcu_gpio_get_direction,
   171		.direction_input	= aaeon_mcu_gpio_direction_input,
   172		.direction_output	= aaeon_mcu_gpio_direction_output,
   173		.get			= aaeon_mcu_gpio_get,
   174		.set			= aaeon_mcu_gpio_set,
   175		.base			= -1,
   176		.ngpio			= MAX_GPOS + MAX_GPIOS,
   177		.can_sleep		= true,
   178	};
   179	
   180	static void aaeon_mcu_gpio_reset(struct aaeon_mcu_gpio *data, struct device *dev)
   181	{
   182		unsigned int i;
   183		int ret;
   184	
   185		/* Reset all GPOs */
   186		for (i = 0; i < MAX_GPOS; i++) {
   187			ret = aaeon_mcu_gpo_set_cmd(data, i, 0);
   188			if (ret < 0)
   189				dev_warn(dev, "Failed to reset GPO %u state: %d\n", i, ret);
   190			clear_bit(i, data->dir_in);
   191		}
   192	
   193		/* Reset all GPIOs */
   194		for (i = MAX_GPOS; i < MAX_GPOS + MAX_GPIOS; i++) {
   195			ret = aaeon_mcu_gpio_config_input_cmd(data, i);
   196			if (ret < 0)
   197				dev_warn(dev, "Failed to reset GPIO %u state: %d\n", i, ret);
   198			set_bit(i, data->dir_in);
   199		}
   200	}
   201	
   202	static int aaeon_mcu_gpio_probe(struct platform_device *pdev)
   203	{
   204		struct aaeon_mcu_dev *mfd = dev_get_drvdata(pdev->dev.parent);
   205		struct aaeon_mcu_gpio *data;
   206	
   207		data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
   208		if (!data)
   209			return -ENOMEM;
   210	
   211		data->mfd = mfd;
   212		data->gc = aaeon_mcu_chip;
   213		data->gc.parent = &pdev->dev;
   214	
   215		/*
   216		 * Reset all GPIO states to a known configuration. The MCU does not
   217		 * reset GPIO state on soft reboot, only on power cycle (hard reboot).
   218		 * Without this reset, GPIOs would retain their previous state across
   219		 * reboots, which could lead to unexpected behavior.
   220		 */
   221		aaeon_mcu_gpio_reset(data, &pdev->dev);
   222	
   223		platform_set_drvdata(pdev, data);
   224	
   225		return devm_gpiochip_add_data(&pdev->dev, &data->gc,
   226					      data);
   227	}
   228	
   229	static const struct of_device_id aaeon_mcu_gpio_of_match[] = {
   230		{ .compatible = "aaeon,srg-imx8pl-gpio" },
   231		{},
   232	};
   233	
   234	MODULE_DEVICE_TABLE(of, aaeon_mcu_gpio_of_match);
   235	
   236	static struct platform_driver aaeon_mcu_gpio_driver = {
   237		.driver = {
   238			.name = "aaeon-mcu-gpio",
   239			.of_match_table = aaeon_mcu_gpio_of_match,
   240		},
   241		.probe = aaeon_mcu_gpio_probe,
   242	};
   243	
   244	module_platform_driver(aaeon_mcu_gpio_driver);
   245	
 > 246	MODULE_DESCRIPTION("GPIO interface for Aaeon MCU");

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From eugen.hristev at linaro.org  Fri Dec 12 22:48:33 2025
From: eugen.hristev at linaro.org (Eugen Hristev)
Date: Sat, 13 Dec 2025 08:48:33 +0200
Subject: [PATCH 00/26] Introduce meminspect
In-Reply-To: <20251119154427.1033475-1-eugen.hristev@linaro.org>
References: <20251119154427.1033475-1-eugen.hristev@linaro.org>
Message-ID: <bf00eec5-e9fe-41df-b758-7601815b24a0@linaro.org>



On 11/19/25 17:44, Eugen Hristev wrote:
> meminspect is a mechanism which allows the kernel to mark specific memory
> areas for memory dumping or specific inspection, statistics, usage.
> Once regions are marked, meminspect keeps an internal list with the regions
> in a dedicated table.

[...]


> I will present this version at Plumbers conference in Tokyo on December 13th:
> https://lpc.events/event/19/contributions/2080/
> I am eager to discuss it there face to face.

Summary of the discussions at LPC talk on Dec 13th:

One main idea on the static variables annotation was to do some linker
magic, to create a list of variables in the tree, that would be parsed
by some script, the addresses and sizes would be then stored into the
dedicated section at the script level, without having any C code change.
Pros: no C code change, Cons: it would be hidden/masked from the code,
easy to miss out, which might lead to people's variables being annotated
without them knowing

Another idea was to have variables directly stored in a dedicated
section which would be added to the table.
e.g. static int __attribute(section (...)) nr_irqs;
Pros: no more meminspect section Cons: have to keep all interesting
variables in a separate section, which might not be okay for everyone.

On dynamic memory, the memblock flag marking did not receive any obvious
NAKs.

On dynamic memory that is bigger in size than one page, as the table
entries are registered by virtual address, this would be non-contiguous
in physical memory. How is this solved?
-> At the moment it's left for the consumer drivers to handle this
situation. If the region is a VA and the size > PAGE_SIZE, then the
driver needs to handle the way it handles it. Maybe the driver that
parses the entry needs to convert it into multiple contiguous entries,
or just have virtual address is enough. The inspection table does not
enforce or limit the entries to contiguous entries only.

On the traverse/notifier system, the implementation did not receive any
obvious NAKs

General comments:

Trilok Soni from Qualcomm mentioned they will be using this into their
software deliveries in production.

Someone suggested to have some mechanism to block specific data from
being added to the inspection table as being sensitive non-inspectable
data.
[Eugen]: Still have to figure out how that could be done. Stuff is not
being added to the table by default.

Another comment was about what use case there is in mind, is this for
servers, or for confidential computing, because each different use case
might have different requirements, like ignoring some regions is an
option in one case, but bloating the table in another case might not be
fine.
[Eugen]: The meminspect scenario should cover all cases and not be too
specific. If it is generic enough and customizable enough to care for
everyone's needs then I consider it being a success. It should not
specialize in neither of these two different cases, but rather be
tailored by each use case to provide the mandatory requirements for that
case.

Another comment mentioned that this usecase does not apply to many
people due to firmware or specific hardware needed.
[Eugen]: one interesting proposed usecase is to have a pstore
driver/implementation that would traverse the inspection table at panic
handler time, then gather data from there to store in the pstore
(ramoops, mtdoops or whatever backend) and have it available to the
userspace after reboot. This would be a nice use case that does not
require firmware nor specific hardware, just pstore backend support.

Ending note was whether this implementation is going in a good direction
and what would be the way to having it moving upstream.

Thanks everyone who attended and came up with ideas and comments.
There are a few comments which I may have missed, so please feel free to
reply to this email to start a discussion thread on the topic you are
interested in.

Eugen


From rdunlap at infradead.org  Fri Dec 12 22:57:02 2025
From: rdunlap at infradead.org (Randy Dunlap)
Date: Fri, 12 Dec 2025 22:57:02 -0800
Subject: [PATCH 00/26] Introduce meminspect
In-Reply-To: <bf00eec5-e9fe-41df-b758-7601815b24a0@linaro.org>
References: <20251119154427.1033475-1-eugen.hristev@linaro.org>
 <bf00eec5-e9fe-41df-b758-7601815b24a0@linaro.org>
Message-ID: <5903a8e1-71c6-4546-ac50-35effa078dda@infradead.org>

Hi,

On 12/12/25 10:48 PM, Eugen Hristev wrote:
> 
> 
> On 11/19/25 17:44, Eugen Hristev wrote:
>> meminspect is a mechanism which allows the kernel to mark specific memory
>> areas for memory dumping or specific inspection, statistics, usage.
>> Once regions are marked, meminspect keeps an internal list with the regions
>> in a dedicated table.
> 
> [...]
> 
> 
>> I will present this version at Plumbers conference in Tokyo on December 13th:
>> https://lpc.events/event/19/contributions/2080/
>> I am eager to discuss it there face to face.
> 
> Summary of the discussions at LPC talk on Dec 13th:
> 
> One main idea on the static variables annotation was to do some linker
> magic, to create a list of variables in the tree, that would be parsed
> by some script, the addresses and sizes would be then stored into the
> dedicated section at the script level, without having any C code change.
> Pros: no C code change, Cons: it would be hidden/masked from the code,
> easy to miss out, which might lead to people's variables being annotated
> without them knowing
> 
> Another idea was to have variables directly stored in a dedicated
> section which would be added to the table.
> e.g. static int __attribute(section (...)) nr_irqs;
> Pros: no more meminspect section Cons: have to keep all interesting
> variables in a separate section, which might not be okay for everyone.
> 
> On dynamic memory, the memblock flag marking did not receive any obvious
> NAKs.
> 
> On dynamic memory that is bigger in size than one page, as the table
> entries are registered by virtual address, this would be non-contiguous
> in physical memory. How is this solved?
> -> At the moment it's left for the consumer drivers to handle this
> situation. If the region is a VA and the size > PAGE_SIZE, then the
> driver needs to handle the way it handles it. Maybe the driver that
> parses the entry needs to convert it into multiple contiguous entries,
> or just have virtual address is enough. The inspection table does not
> enforce or limit the entries to contiguous entries only.
> 
> On the traverse/notifier system, the implementation did not receive any
> obvious NAKs
> 
> General comments:
> 
> Trilok Soni from Qualcomm mentioned they will be using this into their
> software deliveries in production.
> 
> Someone suggested to have some mechanism to block specific data from
> being added to the inspection table as being sensitive non-inspectable
> data.
> [Eugen]: Still have to figure out how that could be done. Stuff is not
> being added to the table by default.
> 
> Another comment was about what use case there is in mind, is this for
> servers, or for confidential computing, because each different use case
> might have different requirements, like ignoring some regions is an
> option in one case, but bloating the table in another case might not be
> fine.
> [Eugen]: The meminspect scenario should cover all cases and not be too
> specific. If it is generic enough and customizable enough to care for
> everyone's needs then I consider it being a success. It should not
> specialize in neither of these two different cases, but rather be
> tailored by each use case to provide the mandatory requirements for that
> case.
> 
> Another comment mentioned that this usecase does not apply to many
> people due to firmware or specific hardware needed.
> [Eugen]: one interesting proposed usecase is to have a pstore
> driver/implementation that would traverse the inspection table at panic
> handler time, then gather data from there to store in the pstore
> (ramoops, mtdoops or whatever backend) and have it available to the
> userspace after reboot. This would be a nice use case that does not
> require firmware nor specific hardware, just pstore backend support.
> 
> Ending note was whether this implementation is going in a good direction
> and what would be the way to having it moving upstream.
> 
> Thanks everyone who attended and came up with ideas and comments.
> There are a few comments which I may have missed, so please feel free to
> reply to this email to start a discussion thread on the topic you are
> interested in.
> 
> Eugen
> 

Maybe you or someone else has already mentioned this. If so, sorry I missed it.

How does this compare or contrast to VMCOREINFO?

thanks.
-- 
~Randy



From jackmanb at google.com  Fri Dec 12 23:05:20 2025
From: jackmanb at google.com (Brendan Jackman)
Date: Sat, 13 Dec 2025 16:05:20 +0900
Subject: [PATCH 2/2] arm64: mmu: use pagetable_alloc_nolock() while stop_machine()
In-Reply-To: <20251212161832.2067134-3-yeoreum.yun@arm.com>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com> <20251212161832.2067134-3-yeoreum.yun@arm.com>
Message-ID: <CA+i-1C2e7QNTy5u=HF7tLsLXLq4xYbMTCbNjWGAxHz4uwgR05g@mail.gmail.com>

On Sat, 13 Dec 2025 at 01:18, Yeoreum Yun <yeoreum.yun at arm.com> wrote:
>
> linear_map_split_to_ptes() and __kpti_install_ng_mappings()
> are called as callback of stop_machine().
> That means these functions context are preemption disabled.
>
> Unfortunately, under PREEMPT_RT, the pagetable_alloc() or
> __get_free_pages() couldn't be called in this context
> since spin lock that becomes sleepable on RT,
> potentially causing a sleep during page allocation.
>
> To address this, pagetable_alloc_nolock().
>
> Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
> ---
>  arch/arm64/mm/mmu.c | 23 ++++++++++++++++++-----
>  1 file changed, 18 insertions(+), 5 deletions(-)
>
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index 2ba01dc8ef82..0e98606d8c4c 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -475,10 +475,15 @@ static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys,
>  static phys_addr_t __pgd_pgtable_alloc(struct mm_struct *mm, gfp_t gfp,
>                                        enum pgtable_type pgtable_type)
>  {
> -       /* Page is zeroed by init_clear_pgtable() so don't duplicate effort. */
> -       struct ptdesc *ptdesc = pagetable_alloc(gfp & ~__GFP_ZERO, 0);
> +       struct ptdesc *ptdesc;
>         phys_addr_t pa;
>
> +       /* Page is zeroed by init_clear_pgtable() so don't duplicate effort. */
> +       if (gfpflags_allow_spinning(gfp))
> +               ptdesc  = pagetable_alloc(gfp & ~__GFP_ZERO, 0);
> +       else
> +               ptdesc  = pagetable_alloc_nolock(gfp & ~__GFP_ZERO, 0);
> +
>         if (!ptdesc)
>                 return INVALID_PHYS_ADDR;
>
> @@ -869,6 +874,7 @@ static int __init linear_map_split_to_ptes(void *__unused)
>                 unsigned long kstart = (unsigned long)lm_alias(_stext);
>                 unsigned long kend = (unsigned long)lm_alias(__init_begin);
>                 int ret;
> +               gfp_t gfp = IS_ENABLED(CONFIG_PREEMPT_RT) ? __GFP_HIGH : GFP_ATOMIC;
>
>                 /*
>                  * Wait for all secondary CPUs to be put into the waiting area.
> @@ -881,9 +887,9 @@ static int __init linear_map_split_to_ptes(void *__unused)
>                  * PTE. The kernel alias remains static throughout runtime so
>                  * can continue to be safely mapped with large mappings.
>                  */
> -               ret = range_split_to_ptes(lstart, kstart, GFP_ATOMIC);
> +               ret = range_split_to_ptes(lstart, kstart, gfp);
>                 if (!ret)
> -                       ret = range_split_to_ptes(kend, lend, GFP_ATOMIC);
> +                       ret = range_split_to_ptes(kend, lend, gfp);
>                 if (ret)
>                         panic("Failed to split linear map\n");
>                 flush_tlb_kernel_range(lstart, lend);
> @@ -1207,7 +1213,14 @@ static int __init __kpti_install_ng_mappings(void *__unused)
>         remap_fn = (void *)__pa_symbol(idmap_kpti_install_ng_mappings);
>
>         if (!cpu) {
> -               alloc = __get_free_pages(GFP_ATOMIC | __GFP_ZERO, order);
> +               if (IS_ENABLED(CONFIG_PREEMPT_RT))
> +                       alloc = (u64) pagetable_alloc_nolock(__GFP_HIGH | __GFP_ZERO, order);
> +               else
> +                       alloc = __get_free_pages(GFP_ATOMIC | __GFP_ZERO, order);
> +
> +               if (!alloc)
> +                       panic("Failed to alloc kpti_ng_pgd\n");
> +

I don't have the context on what this code is doing so take this with
a grain of salt, but...

The point of the _nolock alloc is to give the allocator an excuse to
fail. Panicking on that failure doesn't seem like a great idea to me?


From eugen.hristev at linaro.org  Fri Dec 12 23:22:56 2025
From: eugen.hristev at linaro.org (Eugen Hristev)
Date: Sat, 13 Dec 2025 09:22:56 +0200
Subject: [PATCH 00/26] Introduce meminspect
In-Reply-To: <5903a8e1-71c6-4546-ac50-35effa078dda@infradead.org>
References: <20251119154427.1033475-1-eugen.hristev@linaro.org>
 <bf00eec5-e9fe-41df-b758-7601815b24a0@linaro.org>
 <5903a8e1-71c6-4546-ac50-35effa078dda@infradead.org>
Message-ID: <c3db6ccd-dfc7-4a6a-82b7-3d615f8cab4f@linaro.org>



On 12/13/25 08:57, Randy Dunlap wrote:
> Hi,
> 
> On 12/12/25 10:48 PM, Eugen Hristev wrote:
>>
>>
>> On 11/19/25 17:44, Eugen Hristev wrote:
>>> meminspect is a mechanism which allows the kernel to mark specific memory
>>> areas for memory dumping or specific inspection, statistics, usage.
>>> Once regions are marked, meminspect keeps an internal list with the regions
>>> in a dedicated table.
>>
>> [...]
>>
>>
>>> I will present this version at Plumbers conference in Tokyo on December 13th:
>>> https://lpc.events/event/19/contributions/2080/
>>> I am eager to discuss it there face to face.
>>
>> Summary of the discussions at LPC talk on Dec 13th:
>>
>> One main idea on the static variables annotation was to do some linker
>> magic, to create a list of variables in the tree, that would be parsed
>> by some script, the addresses and sizes would be then stored into the
>> dedicated section at the script level, without having any C code change.
>> Pros: no C code change, Cons: it would be hidden/masked from the code,
>> easy to miss out, which might lead to people's variables being annotated
>> without them knowing
>>
>> Another idea was to have variables directly stored in a dedicated
>> section which would be added to the table.
>> e.g. static int __attribute(section (...)) nr_irqs;
>> Pros: no more meminspect section Cons: have to keep all interesting
>> variables in a separate section, which might not be okay for everyone.
>>
>> On dynamic memory, the memblock flag marking did not receive any obvious
>> NAKs.
>>
>> On dynamic memory that is bigger in size than one page, as the table
>> entries are registered by virtual address, this would be non-contiguous
>> in physical memory. How is this solved?
>> -> At the moment it's left for the consumer drivers to handle this
>> situation. If the region is a VA and the size > PAGE_SIZE, then the
>> driver needs to handle the way it handles it. Maybe the driver that
>> parses the entry needs to convert it into multiple contiguous entries,
>> or just have virtual address is enough. The inspection table does not
>> enforce or limit the entries to contiguous entries only.
>>
>> On the traverse/notifier system, the implementation did not receive any
>> obvious NAKs
>>
>> General comments:
>>
>> Trilok Soni from Qualcomm mentioned they will be using this into their
>> software deliveries in production.
>>
>> Someone suggested to have some mechanism to block specific data from
>> being added to the inspection table as being sensitive non-inspectable
>> data.
>> [Eugen]: Still have to figure out how that could be done. Stuff is not
>> being added to the table by default.
>>
>> Another comment was about what use case there is in mind, is this for
>> servers, or for confidential computing, because each different use case
>> might have different requirements, like ignoring some regions is an
>> option in one case, but bloating the table in another case might not be
>> fine.
>> [Eugen]: The meminspect scenario should cover all cases and not be too
>> specific. If it is generic enough and customizable enough to care for
>> everyone's needs then I consider it being a success. It should not
>> specialize in neither of these two different cases, but rather be
>> tailored by each use case to provide the mandatory requirements for that
>> case.
>>
>> Another comment mentioned that this usecase does not apply to many
>> people due to firmware or specific hardware needed.
>> [Eugen]: one interesting proposed usecase is to have a pstore
>> driver/implementation that would traverse the inspection table at panic
>> handler time, then gather data from there to store in the pstore
>> (ramoops, mtdoops or whatever backend) and have it available to the
>> userspace after reboot. This would be a nice use case that does not
>> require firmware nor specific hardware, just pstore backend support.
>>
>> Ending note was whether this implementation is going in a good direction
>> and what would be the way to having it moving upstream.
>>
>> Thanks everyone who attended and came up with ideas and comments.
>> There are a few comments which I may have missed, so please feel free to
>> reply to this email to start a discussion thread on the topic you are
>> interested in.
>>
>> Eugen
>>
> 
> Maybe you or someone else has already mentioned this. If so, sorry I missed it.
> 
> How does this compare or contrast to VMCOREINFO?
> 
> thanks.

This inspection table could be created in an VMCOREINFO way, the patch
series here[1] is something that would fit it best .

The drawbacks are :
some static variables have to be registered to VMCOREINFO in their file
of residence. This means including vmcoreinfo header and adding
functions/code there, and everywhere that would be needed , or , the
variables have to be un-static'ed , which is a no-go.
This received more negative opinions on that particular patch series.
The annotation idea seemed cleaner and simpler, and more generic.

We could add more and more entries to the vmcoreinfo table, but that
would mean expanding it a lot, which it would maybe defy its purpose,
and be getting too big, especially for the cases where custom drivers
would like to register data.

How I see it, is that maybe the vmcoreinfo init function, could also
parse the inspection table and create more entries if that is needed.
So somehow memory inspection is a superset or generalization , while
VMCOREINFO is a more particular use case that would fit here.

Do you think of some better way to integrate the meminspect table into
VMCOREINFO ?

[1]
https://lore.kernel.org/all/20250912150855.2901211-1-eugen.hristev at linaro.org/


From lkp at intel.com  Sat Dec 13 00:05:00 2025
From: lkp at intel.com (kernel test robot)
Date: Sat, 13 Dec 2025 16:05:00 +0800
Subject: [PATCH 14/32] KVM: arm64: gic-v5: Implement GICv5 load/put and
 save/restore
In-Reply-To: <20251212152215.675767-15-sascha.bischoff@arm.com>
References: <20251212152215.675767-15-sascha.bischoff@arm.com>
Message-ID: <202512131539.zPrweF7e-lkp@intel.com>

Hi Sascha,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on next-20251212]
[cannot apply to kvmarm/next arm64/for-next/core kvm/queue kvm/next kvm/linux-next v6.18]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Sascha-Bischoff/KVM-arm64-Account-for-RES1-bits-in-DECLARE_FEAT_MAP-and-co/20251212-233140
base:   linus/master
patch link:    https://lore.kernel.org/r/20251212152215.675767-15-sascha.bischoff%40arm.com
patch subject: [PATCH 14/32] KVM: arm64: gic-v5: Implement GICv5 load/put and save/restore
config: arm64-randconfig-002-20251213 (https://download.01.org/0day-ci/archive/20251213/202512131539.zPrweF7e-lkp at intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 1335a05ab8bc8339ce24be3a9da89d8c3f4e0571)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251213/202512131539.zPrweF7e-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512131539.zPrweF7e-lkp at intel.com/

All errors (new ones prefixed by >>):

   In file included from arch/arm64/kernel/asm-offsets.c:16:
   In file included from include/linux/kvm_host.h:45:
   In file included from arch/arm64/include/asm/kvm_host.h:36:
>> include/kvm/arm_vgic.h:392:19: error: field has incomplete type 'struct gicv5_vpe'
     392 |         struct gicv5_vpe gicv5_vpe;
         |                          ^
   include/kvm/arm_vgic.h:392:9: note: forward declaration of 'struct gicv5_vpe'
     392 |         struct gicv5_vpe gicv5_vpe;
         |                ^
   1 error generated.
   make[3]: *** [scripts/Makefile.build:182: arch/arm64/kernel/asm-offsets.s] Error 1 shuffle=1891526797
   make[3]: Target 'prepare' not remade because of errors.
   make[2]: *** [Makefile:1314: prepare0] Error 2 shuffle=1891526797
   make[2]: Target 'prepare' not remade because of errors.
   make[1]: *** [Makefile:248: __sub-make] Error 2 shuffle=1891526797
   make[1]: Target 'prepare' not remade because of errors.
   make: *** [Makefile:248: __sub-make] Error 2 shuffle=1891526797
   make: Target 'prepare' not remade because of errors.

Kconfig warnings: (for reference only)
   WARNING: unmet direct dependencies detected for CAN_DEV
   Depends on [n]: NETDEVICES [=n] && CAN [=y]
   Selected by [y]:
   - CAN [=y] && NET [=y]


vim +392 include/kvm/arm_vgic.h

   360	
   361	struct vgic_v5_cpu_if {
   362		u64	vgic_apr;
   363		u64	vgic_vmcr;
   364	
   365		/* PPI register state */
   366		u64	vgic_ppi_hmr[2];
   367		u64	vgic_ppi_dvir[2];
   368		u64	vgic_ppi_priorityr[16];
   369	
   370		/* The pending state of the guest. This is merged with the exit state */
   371		u64	vgic_ppi_pendr[2];
   372	
   373		/* The state flushed to the regs when entering the guest */
   374		u64	vgic_ppi_activer_entry[2];
   375		u64	vgic_ich_ppi_enabler_entry[2];
   376		u64	vgic_ppi_pendr_entry[2];
   377	
   378		/* The saved state of the regs when leaving the guest */
   379		u64	vgic_ppi_activer_exit[2];
   380		u64	vgic_ich_ppi_enabler_exit[2];
   381		u64	vgic_ppi_pendr_exit[2];
   382	
   383		/*
   384		 * The ICSR is re-used across host and guest, and hence it needs to be
   385		 * saved/restored. Only one copy is required as the host should block
   386		 * preemption between executing GIC CDRCFG and acccessing the
   387		 * ICC_ICSR_EL1. A guest, of course, can never guarantee this, and hence
   388		 * it is the hyp's responsibility to keep the state constistent.
   389		 */
   390		u64	vgic_icsr;
   391	
 > 392		struct gicv5_vpe gicv5_vpe;
   393	};
   394	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From balejk at matfyz.cz  Sat Dec 13 00:48:13 2025
From: balejk at matfyz.cz (Karel Balej)
Date: Sat, 13 Dec 2025 09:48:13 +0100
Subject: [PATCH v2 2/2] pmdomain: add audio power island for Marvell PXA1908 SoC
In-Reply-To: <20251213084843.7491-1-balejk@matfyz.cz>
References: <20251213084843.7491-1-balejk@matfyz.cz>
Message-ID: <20251213084843.7491-2-balejk@matfyz.cz>

Define power domain which needs to be enabled in order for audio to work
on the PXA1908-based samsung,coreprimevelte smartphone. In the
downstream code, this power-on method is marked as specific to the ULCx
series which is allegedly a codename of sorts with ULC1 corresponding to
the PXA1908.

No other audio components needed for sound to work on this phone are
currently available mainline but some successful testing was performed
with the vendor variants of the respective drivers and with the domain
forced always-on.

Signed-off-by: Karel Balej <balejk at matfyz.cz>
---

Notes:
    v2:
    - APMU_AUD_CLK -> APMU_AUDIO_CLK and group it with other register
      definitions. (Duje)
    - Move default function exit path inside the switch. (Duje)
    - Modify the commit message with information provided by Duje (thanks!).

 .../marvell/pxa1908-power-controller.c        | 39 +++++++++++++++++--
 1 file changed, 35 insertions(+), 4 deletions(-)

diff --git a/drivers/pmdomain/marvell/pxa1908-power-controller.c b/drivers/pmdomain/marvell/pxa1908-power-controller.c
index ff5e6e82d3f8..543e8d33ac0c 100644
--- a/drivers/pmdomain/marvell/pxa1908-power-controller.c
+++ b/drivers/pmdomain/marvell/pxa1908-power-controller.c
@@ -24,12 +24,15 @@
 #define APMU_DEBUG		0x88
 #define DSI_PHY_DVM_MASK	BIT(31)
 
+#define APMU_AUDIO_CLK		0x80
+#define AUDIO_ULCX_ENABLE	0x0d
+
 #define POWER_ON_LATENCY_US	300
 #define POWER_OFF_LATENCY_US	20
 #define POWER_POLL_TIMEOUT_US	(25 * USEC_PER_MSEC)
 #define POWER_POLL_SLEEP_US	6
 
-#define NR_DOMAINS	5
+#define NR_DOMAINS	6
 
 #define to_pxa1908_pd(_genpd) container_of(_genpd, struct pxa1908_pd, genpd)
 
@@ -59,9 +62,14 @@ static inline bool pxa1908_pd_is_on(struct pxa1908_pd *pd)
 {
 	struct pxa1908_pd_ctrl *ctrl = pd->ctrl;
 
-	return pd->data.id != PXA1908_POWER_DOMAIN_DSI
-		? regmap_test_bits(ctrl->base, APMU_PWR_STATUS_REG, pd->data.pwr_state)
-		: regmap_test_bits(ctrl->base, APMU_DEBUG, DSI_PHY_DVM_MASK);
+	switch (pd->data.id) {
+	case PXA1908_POWER_DOMAIN_AUDIO:
+		return regmap_test_bits(ctrl->base, APMU_AUDIO_CLK, AUDIO_ULCX_ENABLE);
+	case PXA1908_POWER_DOMAIN_DSI:
+		return regmap_test_bits(ctrl->base, APMU_DEBUG, DSI_PHY_DVM_MASK);
+	default:
+		return regmap_test_bits(ctrl->base, APMU_PWR_STATUS_REG, pd->data.pwr_state);
+	}
 }
 
 static int pxa1908_pd_power_on(struct generic_pm_domain *genpd)
@@ -123,6 +131,22 @@ static inline int pxa1908_dsi_power_off(struct generic_pm_domain *genpd)
 	return regmap_clear_bits(ctrl->base, APMU_DEBUG, DSI_PHY_DVM_MASK);
 }
 
+static inline int pxa1908_audio_power_on(struct generic_pm_domain *genpd)
+{
+	struct pxa1908_pd *pd = to_pxa1908_pd(genpd);
+	struct pxa1908_pd_ctrl *ctrl = pd->ctrl;
+
+	return regmap_set_bits(ctrl->base, APMU_AUDIO_CLK, AUDIO_ULCX_ENABLE);
+}
+
+static inline int pxa1908_audio_power_off(struct generic_pm_domain *genpd)
+{
+	struct pxa1908_pd *pd = to_pxa1908_pd(genpd);
+	struct pxa1908_pd_ctrl *ctrl = pd->ctrl;
+
+	return regmap_clear_bits(ctrl->base, APMU_AUDIO_CLK, AUDIO_ULCX_ENABLE);
+}
+
 #define DOMAIN(_id, _name, ctrl, mode, state) \
 	[_id] = { \
 		.data = { \
@@ -159,6 +183,13 @@ static struct pxa1908_pd domains[NR_DOMAINS] = {
 			.keep_on = true,
 		},
 	},
+	[PXA1908_POWER_DOMAIN_AUDIO] = {
+		.genpd = {
+			.name = "audio",
+			.power_on = pxa1908_audio_power_on,
+			.power_off = pxa1908_audio_power_off,
+		},
+	},
 };
 
 static void pxa1908_pd_remove(struct auxiliary_device *auxdev)
-- 
2.51.2



From balejk at matfyz.cz  Sat Dec 13 00:48:12 2025
From: balejk at matfyz.cz (Karel Balej)
Date: Sat, 13 Dec 2025 09:48:12 +0100
Subject: [PATCH v2 1/2] dt-bindings: power: define ID for Marvell PXA1908 audio domain
Message-ID: <20251213084843.7491-1-balejk@matfyz.cz>

Define an identifier for the SoC's audio power island so that it can be
referenced through device tree.

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
Reviewed-by: Duje Mihanovi? <duje at dujemihanovic.xyz>
Signed-off-by: Karel Balej <balejk at matfyz.cz>
---

Notes:
    v2:
    - Add received trailers (thanks!).
    - v1: https://lore.kernel.org/r/20251127190237.745-1-balejk at matfyz.cz/

 include/dt-bindings/power/marvell,pxa1908-power.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/dt-bindings/power/marvell,pxa1908-power.h b/include/dt-bindings/power/marvell,pxa1908-power.h
index 19b088351af1..173f47e0e69d 100644
--- a/include/dt-bindings/power/marvell,pxa1908-power.h
+++ b/include/dt-bindings/power/marvell,pxa1908-power.h
@@ -13,5 +13,6 @@
 #define PXA1908_POWER_DOMAIN_GPU2D	2
 #define PXA1908_POWER_DOMAIN_DSI	3
 #define PXA1908_POWER_DOMAIN_ISP	4
+#define PXA1908_POWER_DOMAIN_AUDIO	5
 
 #endif
-- 
2.51.2



From lkp at intel.com  Sat Dec 13 02:10:43 2025
From: lkp at intel.com (kernel test robot)
Date: Sat, 13 Dec 2025 18:10:43 +0800
Subject: [PATCH] arm64: hw_breakpoint: warn on invalid breakpoint length
In-Reply-To: <20251212205230.84606-1-osama.abdelkader@gmail.com>
References: <20251212205230.84606-1-osama.abdelkader@gmail.com>
Message-ID: <202512131730.89TvJc2D-lkp@intel.com>

Hi Osama,

kernel test robot noticed the following build errors:

[auto build test ERROR on arm64/for-next/core]
[also build test ERROR on arm-perf/for-next/perf linus/master v6.18 next-20251212]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Osama-Abdelkader/arm64-hw_breakpoint-warn-on-invalid-breakpoint-length/20251213-045501
base:   https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-next/core
patch link:    https://lore.kernel.org/r/20251212205230.84606-1-osama.abdelkader%40gmail.com
patch subject: [PATCH] arm64: hw_breakpoint: warn on invalid breakpoint length
config: arm64-allmodconfig (https://download.01.org/0day-ci/archive/20251213/202512131730.89TvJc2D-lkp at intel.com/config)
compiler: clang version 19.1.7 (https://github.com/llvm/llvm-project cd708029e0b2869e80abe31ddb175f7c35361f90)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251213/202512131730.89TvJc2D-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512131730.89TvJc2D-lkp at intel.com/

All errors (new ones prefixed by >>):

   arch/arm64/kernel/hw_breakpoint.c:483:17: warning: missing terminating '"' character [-Winvalid-pp-token]
     483 |                         pr_warn_once("hw_breakpoint: invalid AArch64 breakpoint length %d,
         |                                      ^
   arch/arm64/kernel/hw_breakpoint.c:484:24: warning: missing terminating '"' character [-Winvalid-pp-token]
     484 |                                 fixing to 4 bytes\n", hw->ctrl.len);
         |                                                    ^
>> arch/arm64/kernel/hw_breakpoint.c:483:4: error: unterminated function-like macro invocation
     483 |                         pr_warn_once("hw_breakpoint: invalid AArch64 breakpoint length %d,
         |                         ^
   include/linux/printk.h:669:9: note: macro 'pr_warn_once' defined here
     669 | #define pr_warn_once(fmt, ...)                                  \
         |         ^
>> arch/arm64/kernel/hw_breakpoint.c:1014:2: error: expected '}'
    1014 | }
         |  ^
   arch/arm64/kernel/hw_breakpoint.c:476:52: note: to match this '{'
     476 |                 } else if (hw->ctrl.len != ARM_BREAKPOINT_LEN_4) {
         |                                                                  ^
>> arch/arm64/kernel/hw_breakpoint.c:1014:2: error: expected '}'
    1014 | }
         |  ^
   arch/arm64/kernel/hw_breakpoint.c:471:47: note: to match this '{'
     471 |         if (hw->ctrl.type == ARM_BREAKPOINT_EXECUTE) {
         |                                                      ^
>> arch/arm64/kernel/hw_breakpoint.c:1014:2: error: expected '}'
    1014 | }
         |  ^
   arch/arm64/kernel/hw_breakpoint.c:417:1: note: to match this '{'
     417 | {
         | ^
   2 warnings and 4 errors generated.


vim +483 arch/arm64/kernel/hw_breakpoint.c

   410	
   411	/*
   412	 * Construct an arch_hw_breakpoint from a perf_event.
   413	 */
   414	static int arch_build_bp_info(struct perf_event *bp,
   415				      const struct perf_event_attr *attr,
   416				      struct arch_hw_breakpoint *hw)
   417	{
   418		/* Type */
   419		switch (attr->bp_type) {
   420		case HW_BREAKPOINT_X:
   421			hw->ctrl.type = ARM_BREAKPOINT_EXECUTE;
   422			break;
   423		case HW_BREAKPOINT_R:
   424			hw->ctrl.type = ARM_BREAKPOINT_LOAD;
   425			break;
   426		case HW_BREAKPOINT_W:
   427			hw->ctrl.type = ARM_BREAKPOINT_STORE;
   428			break;
   429		case HW_BREAKPOINT_RW:
   430			hw->ctrl.type = ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE;
   431			break;
   432		default:
   433			return -EINVAL;
   434		}
   435	
   436		/* Len */
   437		switch (attr->bp_len) {
   438		case HW_BREAKPOINT_LEN_1:
   439			hw->ctrl.len = ARM_BREAKPOINT_LEN_1;
   440			break;
   441		case HW_BREAKPOINT_LEN_2:
   442			hw->ctrl.len = ARM_BREAKPOINT_LEN_2;
   443			break;
   444		case HW_BREAKPOINT_LEN_3:
   445			hw->ctrl.len = ARM_BREAKPOINT_LEN_3;
   446			break;
   447		case HW_BREAKPOINT_LEN_4:
   448			hw->ctrl.len = ARM_BREAKPOINT_LEN_4;
   449			break;
   450		case HW_BREAKPOINT_LEN_5:
   451			hw->ctrl.len = ARM_BREAKPOINT_LEN_5;
   452			break;
   453		case HW_BREAKPOINT_LEN_6:
   454			hw->ctrl.len = ARM_BREAKPOINT_LEN_6;
   455			break;
   456		case HW_BREAKPOINT_LEN_7:
   457			hw->ctrl.len = ARM_BREAKPOINT_LEN_7;
   458			break;
   459		case HW_BREAKPOINT_LEN_8:
   460			hw->ctrl.len = ARM_BREAKPOINT_LEN_8;
   461			break;
   462		default:
   463			return -EINVAL;
   464		}
   465	
   466		/*
   467		 * On AArch64, we only permit breakpoints of length 4, whereas
   468		 * AArch32 also requires breakpoints of length 2 for Thumb.
   469		 * Watchpoints can be of length 1, 2, 4 or 8 bytes.
   470		 */
   471		if (hw->ctrl.type == ARM_BREAKPOINT_EXECUTE) {
   472			if (is_compat_bp(bp)) {
   473				if (hw->ctrl.len != ARM_BREAKPOINT_LEN_2 &&
   474				    hw->ctrl.len != ARM_BREAKPOINT_LEN_4)
   475					return -EINVAL;
   476			} else if (hw->ctrl.len != ARM_BREAKPOINT_LEN_4) {
   477				/*
   478				 * Some tools (e.g. perf) incorrectly assume that
   479				 * breakpoints should be sizeof(long). This is wrong
   480				 * for AArch64 where breakpoints must be 4 bytes.
   481				 * Warn the user and fix up the parameter.
   482				 */
 > 483				pr_warn_once("hw_breakpoint: invalid AArch64 breakpoint length %d,
 > 484					fixing to 4 bytes\n", hw->ctrl.len);
   485				hw->ctrl.len = ARM_BREAKPOINT_LEN_4;
   486			}
   487		}
   488	
   489		/* Address */
   490		hw->address = attr->bp_addr;
   491	
   492		/*
   493		 * Privilege
   494		 * Note that we disallow combined EL0/EL1 breakpoints because
   495		 * that would complicate the stepping code.
   496		 */
   497		if (arch_check_bp_in_kernelspace(hw))
   498			hw->ctrl.privilege = AARCH64_BREAKPOINT_EL1;
   499		else
   500			hw->ctrl.privilege = AARCH64_BREAKPOINT_EL0;
   501	
   502		/* Enabled? */
   503		hw->ctrl.enabled = !attr->disabled;
   504	
   505		return 0;
   506	}
   507	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From osama.abdelkader at gmail.com  Sat Dec 13 03:23:35 2025
From: osama.abdelkader at gmail.com (Osama Abdelkader)
Date: Sat, 13 Dec 2025 12:23:35 +0100
Subject: [PATCH v2] arm64: hw_breakpoint: warn on invalid breakpoint length
Message-ID: <20251213112336.26503-1-osama.abdelkader@gmail.com>

Some tools (e.g. perf) incorrectly assume that breakpoints should be
sizeof(long), but this is wrong for AArch64 where breakpoints must be
4 bytes. Add a warning when we silently fix up the parameter so tool
developers can get notified.

This addresses the FIXME comment by adding diagnostic output rather
than breaking existing tools by returning -EINVAL.

Signed-off-by: Osama Abdelkader <osama.abdelkader at gmail.com>
---
v2: fix warning messageline splitting
---
 arch/arm64/kernel/hw_breakpoint.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
index ab76b36dce82..cce306145d78 100644
--- a/arch/arm64/kernel/hw_breakpoint.c
+++ b/arch/arm64/kernel/hw_breakpoint.c
@@ -475,11 +475,13 @@ static int arch_build_bp_info(struct perf_event *bp,
 				return -EINVAL;
 		} else if (hw->ctrl.len != ARM_BREAKPOINT_LEN_4) {
 			/*
-			 * FIXME: Some tools (I'm looking at you perf) assume
-			 *	  that breakpoints should be sizeof(long). This
-			 *	  is nonsense. For now, we fix up the parameter
-			 *	  but we should probably return -EINVAL instead.
+			 * Some tools (e.g. perf) incorrectly assume that
+			 * breakpoints should be sizeof(long). This is wrong
+			 * for AArch64 where breakpoints must be 4 bytes.
+			 * Warn the user and fix up the parameter.
 			 */
+			pr_warn_once("hw_breakpoint: invalid AArch64 breakpoint length %d, fixing to 4 bytes\n",
+				     hw->ctrl.len);
 			hw->ctrl.len = ARM_BREAKPOINT_LEN_4;
 		}
 	}
-- 
2.43.0



From lkp at intel.com  Sat Dec 13 04:38:29 2025
From: lkp at intel.com (kernel test robot)
Date: Sat, 13 Dec 2025 20:38:29 +0800
Subject: [PATCH v8 2/8] coresight: core: add a new API to retrieve the
 helper device
In-Reply-To: <20251211-enable-byte-cntr-for-ctcu-v8-2-3e12ff313191@oss.qualcomm.com>
References: <20251211-enable-byte-cntr-for-ctcu-v8-2-3e12ff313191@oss.qualcomm.com>
Message-ID: <202512132024.rsZaNtbp-lkp@intel.com>

Hi Jie,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 47b7b5e32bb7264b51b89186043e1ada4090b558]

url:    https://github.com/intel-lab-lkp/linux/commits/Jie-Gan/coresight-core-Refactoring-ctcu_get_active_port-and-make-it-generic/20251211-142430
base:   47b7b5e32bb7264b51b89186043e1ada4090b558
patch link:    https://lore.kernel.org/r/20251211-enable-byte-cntr-for-ctcu-v8-2-3e12ff313191%40oss.qualcomm.com
patch subject: [PATCH v8 2/8] coresight: core: add a new API to retrieve the helper device
config: arm64-randconfig-001-20251213 (https://download.01.org/0day-ci/archive/20251213/202512132024.rsZaNtbp-lkp at intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 1335a05ab8bc8339ce24be3a9da89d8c3f4e0571)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251213/202512132024.rsZaNtbp-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512132024.rsZaNtbp-lkp at intel.com/

All warnings (new ones prefixed by >>):

>> Warning: drivers/hwtracing/coresight/coresight-core.c:600 function parameter 'subtype' not described in 'coresight_get_helper'
>> Warning: drivers/hwtracing/coresight/coresight-core.c:600 function parameter 'subtype' not described in 'coresight_get_helper'

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From nicolas.dufresne at collabora.com  Sat Dec 13 06:27:20 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Sat, 13 Dec 2025 09:27:20 -0500
Subject: [PATCH] media: rkvdec: set ctx->image_fmt in
 rkvdec_s_capture_fmt
In-Reply-To: <20251213055942.3046647-1-liujianfeng1994@gmail.com>
References: <8f24c8204984a46bad7d0bb24b78c8115906f748.camel@collabora.com>
	 <20251213055942.3046647-1-liujianfeng1994@gmail.com>
Message-ID: <6810b2c54369a7941d4f01d1013a641412743b62.camel@collabora.com>

Hi,

Le samedi 13 d?cembre 2025 ? 13:59 +0800, Jianfeng Liu a ?crit?:
> Chromium does follow the spec when decoding 10bit videos[1], but that is
> still limited to hevc and vp9. For h264 and 8bit video chromium thinks
> this is unnecessary.

thanks for the pointer, that explains a lot my surprise and slight confusion.
Now that you mention, on relevant chromebooks, 10bit is only supported with
HEVC/VP9 (perhaps AV1 too, not sure).

Nicolas
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251213/68846657/attachment.sig>

From francesco at valla.it  Sat Dec 13 06:48:42 2025
From: francesco at valla.it (Francesco Valla)
Date: Sat, 13 Dec 2025 15:48:42 +0100
Subject: [PATCH v2 0/2] Add FRDM i.MX 91 Development board support
In-Reply-To: <20251212-imx91_frdm-v2-0-4dd6d289e81d@nxp.com>
References: <20251212-imx91_frdm-v2-0-4dd6d289e81d@nxp.com>
Message-ID: <aT18yj7c27_buJSe@bywater>

On Fri, Dec 12, 2025 at 11:31:32AM +0900, Joseph Guo wrote:
> FRDM-IMX91 board is a low cost development platform based on i.MX91 SoC:
> https://www.nxp.com/design/design-center/development-boards-and-designs/FRDM-IMX91
> 
> Add device tree and dt-binding for FRDM-IMX91.
> 
> Signed-off-by: Joseph Guo <qijian.guo at nxp.com>
> ---
> Changes in v2:
> - rename compatible 'frdm-imx91' to 'imx91-11x11-frdm'
> - rename 'sw-keys' to 'gpio-keys'
> - rename 'user_btn' to 'button-k'
> - drop lpspi3 node
> - rename iomuxc 'grpsleep' to 'sleepgrp'
> - move dt-binding patch before the dts patch
> - add board page link in cover letter
> - use CAN PHY to manage the stby gpio of flexcan2
> - drop realtek property
> - add pcf2131 aliase
> - add bootph- property for nodes should be kept in bootloader phase
> - add reset-gpio and assert for eqos and fec
> - delete unused alias
> - Link to v1: https://lore.kernel.org/r/20251114-imx91_frdm-v1-0-e5763bdf9336 at nxp.com
> 
> ---
> Joseph Guo (2):
>       dt-bindings: arm: imx Add FRDM-IMX91 board
>       arm64: dts: freescale: Add FRDM-IMX91 basic support
> 
>  Documentation/devicetree/bindings/arm/fsl.yaml     |   1 +
>  arch/arm64/boot/dts/freescale/Makefile             |   1 +
>  arch/arm64/boot/dts/freescale/imx91-11x11-frdm.dts | 904 +++++++++++++++++++++
>  3 files changed, 906 insertions(+)
> ---
> base-commit: 73f1e611b076de705c2f1c26cfdfc5b8e96f4733
> change-id: 20251114-imx91_frdm-add2b2c07e78
> 
> Best regards,
> -- 
> Joseph Guo <qijian.guo at nxp.com>
> 
>

Everything is in good shape, the only non-working thing is button-k3 
(but that was expected, as a small hardware modification is required
to reroute the phisical button from system reset to user function).
Not a real issue, at least from my point of view.

Reviewed-by: Francesco Valla <francesco at valla.it>
Tested-by: Francesco Valla <francesco at valla.it>


Regards,
Francesco



From nicolas at ndufresne.ca  Sat Dec 13 08:06:06 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Sat, 13 Dec 2025 11:06:06 -0500
Subject: [PATCH RESEND v6 2/4] dt-bindings: media: allegro: Add al300
 decoder IPs
In-Reply-To: <20251208-allegro_dvt_al300_dec_driver-v6-2-128956555677@allegrodvt.com>
References: <20251208-allegro_dvt_al300_dec_driver-v6-0-128956555677@allegrodvt.com>
	 <20251208-allegro_dvt_al300_dec_driver-v6-2-128956555677@allegrodvt.com>
Message-ID: <99ff7a97287988b8e74f84e1fa55cd6e1524323b.camel@ndufresne.ca>

Hi,

Le lundi 08 d?cembre 2025 ? 16:49 +0100, Yassine Ouaissa via B4 Relay a ?crit?:
> From: Yassine Ouaissa <yassine.ouaissa at allegrodvt.com>
> 
> Add a schema for the allegro gen3 video decoder.
> 
> Acked-by: Conor Dooley <conor.dooley at microchip.com>
> Signed-off-by: Yassine Ouaissa <yassine.ouaissa at allegrodvt.com>

You didn't apply any changes following Micheal review in this oen either. Couple
of reminder below.

> ---
> ?.../bindings/media/allegro,al300-vdec.yaml???????? | 76 ++++++++++++++++++++++
> ?MAINTAINERS??????????????????????????????????????? |? 2 +
> ?2 files changed, 78 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/media/allegro,al300-vdec.yaml b/Documentation/devicetree/bindings/media/allegro,al300-vdec.yaml
> new file mode 100644
> index 000000000000..12e86c306d55
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/allegro,al300-vdec.yaml
> @@ -0,0 +1,76 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/media/allegro,al300-vdec.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Allegro DVT Video IP Decoder Gen 3
> +
> +maintainers:
> +? - Yassine OUAISSA <yassine.ouaissa at allegrodvt.com>
> +
> +description:
> +? The al300-vdec represents the gen 3 of Allegro DVT IP video
> +? decoding technology, offering significant advancements over its
> +? predecessors. This new decoder features enhanced processing capabilities
> +? with improved throughput and reduced latency.
> +
> +? Communication between the host driver software and the MCU is implemented
> +? through a specialized mailbox interface mechanism. This mailbox system
> +? provides a structured channel for exchanging commands, parameters, and
> +? status information between the host CPU and the MCU controlling the codec
> +? engines.

Need to drop the marketing. In 10y from now, this won't be new anymore.

> +
> +properties:
> +? compatible:
> +??? const: allegro,al300-vdec
> +
> +? reg:
> +??? maxItems: 2
> +
> +? reg-names:
> +??? items:
> +????? - const: top
> +????? - const: apb
> +
> +? interrupts:
> +??? maxItems: 1
> +
> +? clocks:
> +??? description: MCU core clock
> +??? maxItems: 1
> +
> +? memory-region:
> +??? maxItems: 1
> +
> +? firmware-name:
> +??? maxItems: 1
> +
> +required:
> +? - compatible
> +? - reg
> +? - reg-names
> +? - interrupts
> +? - clocks
> +
> +additionalProperties: False
> +
> +examples:
> +? - |
> +??? #include <dt-bindings/interrupt-controller/arm-gic.h>
> +
> +??? axi {
> +??????? #address-cells = <2>;
> +??????? #size-cells = <2>;
> +
> +??????? video-decoder at a0120000 {
> +??????????? compatible = "allegro,al300-vdec";
> +??????????? reg = <0x00 0xa0120000 0x00 0x10000>, /*VDEC_TOP*/
> +????????????????? <0x01 0x80000000 0x00 0x8000>;? /*MCU_APB*/
> +??????????? reg-names = "top", "apb";
> +??????????? interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
> +??????????? clocks = <&mcu_core_clk>;
> +??????????? memory-region = <&vdec_mem>;
> +??????????? firmware-name = "al300_vdec.fw";
> +??????? };
> +??? };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index dc56841fa5e5..67dfc2ee1725 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -837,7 +837,9 @@ M:	Michael Tretter <m.tretter at pengutronix.de>
> ?R:	Pengutronix Kernel Team <kernel at pengutronix.de>
> ?L:	linux-media at vger.kernel.org
> ?S:	Maintained
> +F:	Documentation/devicetree/bindings/media/allegro,al300-vdec.yaml
> ?F:	Documentation/devicetree/bindings/media/allegro,al5e.yaml
> +F:	drivers/media/platform/allegro-dvt/al300
> ?F:	drivers/media/platform/allegro-dvt/zynqmp

As I said earlier, I'd like to see Micheal/PTX as maintainer for
drivers/media/platform/allegro-dvt for now, and you with only the AL300. They
have a lot more experience.

Nicolas

> ?
> ?ALLIED VISION ALVIUM CAMERA DRIVER
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251213/42fe9e64/attachment-0001.sig>

From jic23 at kernel.org  Sat Dec 13 08:59:49 2025
From: jic23 at kernel.org (Jonathan Cameron)
Date: Sat, 13 Dec 2025 16:59:49 +0000
Subject: [PATCH] dt-bindings: Remove unused includes
In-Reply-To: <20251212231203.727227-1-robh@kernel.org>
References: <20251212231203.727227-1-robh@kernel.org>
Message-ID: <20251213165949.4b51f7cb@jic23-huawei>

On Fri, 12 Dec 2025 17:11:52 -0600
"Rob Herring (Arm)" <robh at kernel.org> wrote:

> Remove includes which are not referenced by either DTS files or drivers.
> 
> There's a few more which are new, so they are excluded for now.
> 
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>

Acked-by: Jonathan Cameron <jonathan.cameron at huawei.com> #for-iio

Ideally we'll get a QC ack on those as well.

Jonathan
>  .../dt-bindings/iio/qcom,spmi-adc7-pmr735b.h  |  30 --
>  .../dt-bindings/iio/qcom,spmi-adc7-smb139x.h  |  19 --


From jic23 at kernel.org  Sat Dec 13 09:02:51 2025
From: jic23 at kernel.org (Jonathan Cameron)
Date: Sat, 13 Dec 2025 17:02:51 +0000
Subject: [PATCH RFC 14/16] dt-bindings: iio: adc: Allow interrupts
 property for AST2600
In-Reply-To: <176548307744.1801669.10354753289483698774.robh@kernel.org>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
	<20251211-dev-dt-warnings-all-v1-14-21b18b9ada77@codeconstruct.com.au>
	<176548307744.1801669.10354753289483698774.robh@kernel.org>
Message-ID: <20251213170251.4d3b1690@jic23-huawei>

On Thu, 11 Dec 2025 13:57:57 -0600
"Rob Herring (Arm)" <robh at kernel.org> wrote:

> On Thu, 11 Dec 2025 17:45:56 +0900, Andrew Jeffery wrote:
> > The device has interrupts allocated according to the datasheet, and
> > the devicetree already defines the interrupt property. Address existing
> > warnings by allowing the property.
> > 
> > Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
> > ---
> >  Documentation/devicetree/bindings/iio/adc/aspeed,ast2600-adc.yaml | 3 +++
> >  1 file changed, 3 insertions(+)
> >   
> 
> Acked-by: Rob Herring (Arm) <robh at kernel.org>
> 
> 

Doesn't seem to be a reason for me not picking this up immediately. Hence
I've done so.  Currently on the testing branch of iio.git as I'll be rebasing
on rc1 once available

Thanks,

Jonathan


From m.felsch at pengutronix.de  Sat Dec 13 10:13:24 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Sat, 13 Dec 2025 19:13:24 +0100
Subject: [PATCH] ARM: dts: nxp/imx6: Drop unused .dtsi
In-Reply-To: <20251212203226.458694-5-robh@kernel.org>
References: <20251212203226.458694-5-robh@kernel.org>
Message-ID: <20251213181324.u32ztfblkknfpz44@pengutronix.de>

Hi Rob,

On 25-12-12, Rob Herring (Arm) wrote:
> These .dtsi files are not included anywhere in the tree and can't be
> tested.

not in the tree but by other projects, please see below.

> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> ---
>  .../dts/nxp/imx/imx6dl-kontron-samx6i.dtsi    | 12 -----
>  .../dts/nxp/imx/imx6q-kontron-samx6i.dtsi     | 12 -----
>  .../boot/dts/nxp/imx/imx6qdl-pico-dwarf.dtsi  | 45 ----------------
>  .../boot/dts/nxp/imx/imx6qdl-pico-nymph.dtsi  | 54 -------------------
>  4 files changed, 123 deletions(-)
>  delete mode 100644 arch/arm/boot/dts/nxp/imx/imx6dl-kontron-samx6i.dtsi
>  delete mode 100644 arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi
>  delete mode 100644 arch/arm/boot/dts/nxp/imx/imx6qdl-pico-dwarf.dtsi
>  delete mode 100644 arch/arm/boot/dts/nxp/imx/imx6qdl-pico-nymph.dtsi
> 
> diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-kontron-samx6i.dtsi b/arch/arm/boot/dts/nxp/imx/imx6dl-kontron-samx6i.dtsi
> deleted file mode 100644
> index 5a9b819d7ee8..000000000000
> --- a/arch/arm/boot/dts/nxp/imx/imx6dl-kontron-samx6i.dtsi
> +++ /dev/null
> @@ -1,12 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0 OR X11
> -/*
> - * Copyright 2019 (C) Pengutronix, Marco Felsch <kernel at pengutronix.de>
> - */
> -
> -#include "imx6dl.dtsi"
> -#include "imx6qdl-kontron-samx6i.dtsi"
> -
> -/ {
> -	model = "Kontron SMARC-sAMX6i Dual-Lite/Solo";
> -	compatible = "kontron,imx6dl-samx6i", "fsl,imx6dl";
> -};
> diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi b/arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi
> deleted file mode 100644
> index e76963436079..000000000000
> --- a/arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi
> +++ /dev/null
> @@ -1,12 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0 OR X11
> -/*
> - * Copyright 2019 (C) Pengutronix, Marco Felsch <kernel at pengutronix.de>
> - */
> -
> -#include "imx6q.dtsi"
> -#include "imx6qdl-kontron-samx6i.dtsi"
> -
> -/ {
> -	model = "Kontron SMARC-sAMX6i Quad/Dual";
> -	compatible = "kontron,imx6q-samx6i", "fsl,imx6q";
> -};

I can't speak for the other two .dtsi files but both kontron .dtsi files
are used by barebox:

 - https://elixir.bootlin.com/barebox/v2025.11.0/source/arch/arm/dts/imx6dl-samx6i.dts#L8
 - https://elixir.bootlin.com/barebox/v2025.11.0/source/arch/arm/dts/imx6q-samx6i.dts#L8

Removing them here will cause a regression for barebox.

Regards,
  Marco


> diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-pico-dwarf.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-pico-dwarf.dtsi
> deleted file mode 100644
> index 3a968782e854..000000000000
> --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-pico-dwarf.dtsi
> +++ /dev/null
> @@ -1,45 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0+ OR MIT
> -//
> -// Copyright 2017 NXP
> -
> -#include "imx6qdl-pico.dtsi"
> -
> -/ {
> -	leds {
> -		compatible = "gpio-leds";
> -		pinctrl-names = "default";
> -		pinctrl-0 = <&pinctrl_gpio_leds>;
> -
> -		led {
> -			label = "gpio-led";
> -			gpios = <&gpio5 31 GPIO_ACTIVE_HIGH>;
> -		};
> -	};
> -
> -};
> -
> -&i2c1 {
> -	mpl3115 at 60 {
> -		compatible = "fsl,mpl3115";
> -		reg = <0x60>;
> -	};
> -};
> -
> -&i2c2 {
> -	io-expander at 25 {
> -		compatible = "nxp,pca9554";
> -		reg = <0x25>;
> -		gpio-controller;
> -		#gpio-cells = <2>;
> -		#interrupt-cells = <2>;
> -	};
> -
> -};
> -
> -&iomuxc {
> -	pinctrl_gpio_leds: gpioledsgrp {
> -		fsl,pins = <
> -			MX6QDL_PAD_CSI0_DAT13__GPIO5_IO31	0x1b0b0
> -		>;
> -	};
> -};
> diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-pico-nymph.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-pico-nymph.dtsi
> deleted file mode 100644
> index 3d56a4216448..000000000000
> --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-pico-nymph.dtsi
> +++ /dev/null
> @@ -1,54 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0+ OR MIT
> -
> -#include "imx6qdl-pico.dtsi"
> -
> -/ {
> -	leds {
> -		compatible = "gpio-leds";
> -		pinctrl-names = "default";
> -		pinctrl-0 = <&pinctrl_gpio_leds>;
> -
> -		led {
> -			label = "gpio-led";
> -			gpios = <&gpio5 31 GPIO_ACTIVE_HIGH>;
> -		};
> -	};
> -
> -};
> -
> -&i2c1 {
> -	adc at 52 {
> -		compatible = "ti,adc081c";
> -		reg = <0x52>;
> -		vref-supply = <&reg_2p5v>;
> -	};
> -};
> -
> -&i2c2 {
> -	io-expander at 25 {
> -		compatible = "nxp,pca9554";
> -		reg = <0x25>;
> -		gpio-controller;
> -		#gpio-cells = <2>;
> -		#interrupt-cells = <2>;
> -	};
> -};
> -
> -&i2c3 {
> -	rtc at 68 {
> -		compatible = "dallas,ds1337";
> -		reg = <0x68>;
> -	};
> -};
> -
> -&pcie {
> -	status = "okay";
> -};
> -
> -&iomuxc {
> -	pinctrl_gpio_leds: gpioledsgrp {
> -		fsl,pins = <
> -			MX6QDL_PAD_CSI0_DAT13__GPIO5_IO31	0x1b0b0
> -		>;
> -	};
> -};
> -- 
> 2.51.0
> 
> 
> 

-- 
#gernperDu 
#CallMeByMyFirstName

Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | https://www.pengutronix.de/ |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-9    |


From lkp at intel.com  Sat Dec 13 12:27:15 2025
From: lkp at intel.com (kernel test robot)
Date: Sun, 14 Dec 2025 04:27:15 +0800
Subject: [PATCH RESEND v6 4/4] media: allegro-dvt: Add Gen 3 IP stateful
 decoder driver
In-Reply-To: <20251208-allegro_dvt_al300_dec_driver-v6-4-128956555677@allegrodvt.com>
References: <20251208-allegro_dvt_al300_dec_driver-v6-4-128956555677@allegrodvt.com>
Message-ID: <202512140429.FIDK3ebu-lkp@intel.com>

Hi Yassine,

kernel test robot noticed the following build warnings:

[auto build test WARNING on c2f2b01b74be8b40a2173372bcd770723f87e7b2]

url:    https://github.com/intel-lab-lkp/linux/commits/Yassine-Ouaissa-via-B4-Relay/media-allegro-dvt-Move-the-current-driver-to-a-subdirectory/20251208-235310
base:   c2f2b01b74be8b40a2173372bcd770723f87e7b2
patch link:    https://lore.kernel.org/r/20251208-allegro_dvt_al300_dec_driver-v6-4-128956555677%40allegrodvt.com
patch subject: [PATCH RESEND v6 4/4] media: allegro-dvt: Add Gen 3 IP stateful decoder driver
config: parisc-allmodconfig (https://download.01.org/0day-ci/archive/20251214/202512140429.FIDK3ebu-lkp at intel.com/config)
compiler: hppa-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251214/202512140429.FIDK3ebu-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512140429.FIDK3ebu-lkp at intel.com/

All warnings (new ones prefixed by >>):

   In file included from include/uapi/linux/errno.h:1,
                    from include/linux/errno.h:5,
                    from drivers/media/platform/allegro-dvt/al300/al_codec_util.c:11:
   arch/parisc/include/uapi/asm/errno.h:7:9: warning: 'ENOMSG' redefined
       7 | #define ENOMSG          35      /* No message of desired type */
         |         ^~~~~~
   In file included from drivers/media/platform/allegro-dvt/al300/al_codec_util.c:10:
   include/uapi/asm-generic/errno.h:23:9: note: this is the location of the previous definition
      23 | #define ENOMSG          42      /* No message of desired type */
         |         ^~~~~~
>> arch/parisc/include/uapi/asm/errno.h:8:9: warning: 'EIDRM' redefined
       8 | #define EIDRM           36      /* Identifier removed */
         |         ^~~~~
   include/uapi/asm-generic/errno.h:24:9: note: this is the location of the previous definition
      24 | #define EIDRM           43      /* Identifier removed */
         |         ^~~~~
   arch/parisc/include/uapi/asm/errno.h:9:9: warning: 'ECHRNG' redefined
       9 | #define ECHRNG          37      /* Channel number out of range */
         |         ^~~~~~
   include/uapi/asm-generic/errno.h:25:9: note: this is the location of the previous definition
      25 | #define ECHRNG          44      /* Channel number out of range */
         |         ^~~~~~
>> arch/parisc/include/uapi/asm/errno.h:10:9: warning: 'EL2NSYNC' redefined
      10 | #define EL2NSYNC        38      /* Level 2 not synchronized */
         |         ^~~~~~~~
   include/uapi/asm-generic/errno.h:26:9: note: this is the location of the previous definition
      26 | #define EL2NSYNC        45      /* Level 2 not synchronized */
         |         ^~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:11:9: warning: 'EL3HLT' redefined
      11 | #define EL3HLT          39      /* Level 3 halted */
         |         ^~~~~~
   include/uapi/asm-generic/errno.h:27:9: note: this is the location of the previous definition
      27 | #define EL3HLT          46      /* Level 3 halted */
         |         ^~~~~~
   arch/parisc/include/uapi/asm/errno.h:12:9: warning: 'EL3RST' redefined
      12 | #define EL3RST          40      /* Level 3 reset */
         |         ^~~~~~
   include/uapi/asm-generic/errno.h:28:9: note: this is the location of the previous definition
      28 | #define EL3RST          47      /* Level 3 reset */
         |         ^~~~~~
   arch/parisc/include/uapi/asm/errno.h:13:9: warning: 'ELNRNG' redefined
      13 | #define ELNRNG          41      /* Link number out of range */
         |         ^~~~~~
   include/uapi/asm-generic/errno.h:29:9: note: this is the location of the previous definition
      29 | #define ELNRNG          48      /* Link number out of range */
         |         ^~~~~~
   arch/parisc/include/uapi/asm/errno.h:14:9: warning: 'EUNATCH' redefined
      14 | #define EUNATCH         42      /* Protocol driver not attached */
         |         ^~~~~~~
   include/uapi/asm-generic/errno.h:30:9: note: this is the location of the previous definition
      30 | #define EUNATCH         49      /* Protocol driver not attached */
         |         ^~~~~~~
   arch/parisc/include/uapi/asm/errno.h:15:9: warning: 'ENOCSI' redefined
      15 | #define ENOCSI          43      /* No CSI structure available */
         |         ^~~~~~
   include/uapi/asm-generic/errno.h:31:9: note: this is the location of the previous definition
      31 | #define ENOCSI          50      /* No CSI structure available */
         |         ^~~~~~
   arch/parisc/include/uapi/asm/errno.h:16:9: warning: 'EL2HLT' redefined
      16 | #define EL2HLT          44      /* Level 2 halted */
         |         ^~~~~~
   include/uapi/asm-generic/errno.h:32:9: note: this is the location of the previous definition
      32 | #define EL2HLT          51      /* Level 2 halted */
         |         ^~~~~~
>> arch/parisc/include/uapi/asm/errno.h:17:9: warning: 'EDEADLK' redefined
      17 | #define EDEADLK         45      /* Resource deadlock would occur */
         |         ^~~~~~~
   include/uapi/asm-generic/errno.h:7:9: note: this is the location of the previous definition
       7 | #define EDEADLK         35      /* Resource deadlock would occur */
         |         ^~~~~~~
   arch/parisc/include/uapi/asm/errno.h:19:9: warning: 'ENOLCK' redefined
      19 | #define ENOLCK          46      /* No record locks available */
         |         ^~~~~~
   include/uapi/asm-generic/errno.h:9:9: note: this is the location of the previous definition
       9 | #define ENOLCK          37      /* No record locks available */
         |         ^~~~~~
>> arch/parisc/include/uapi/asm/errno.h:20:9: warning: 'EILSEQ' redefined
      20 | #define EILSEQ          47      /* Illegal byte sequence */
         |         ^~~~~~
   include/uapi/asm-generic/errno.h:67:9: note: this is the location of the previous definition
      67 | #define EILSEQ          84      /* Illegal byte sequence */
         |         ^~~~~~
   arch/parisc/include/uapi/asm/errno.h:22:9: warning: 'ENONET' redefined
      22 | #define ENONET          50      /* Machine is not on the network */
         |         ^~~~~~
   include/uapi/asm-generic/errno.h:47:9: note: this is the location of the previous definition
      47 | #define ENONET          64      /* Machine is not on the network */
         |         ^~~~~~
   arch/parisc/include/uapi/asm/errno.h:23:9: warning: 'ENODATA' redefined
      23 | #define ENODATA         51      /* No data available */
         |         ^~~~~~~
   include/uapi/asm-generic/errno.h:44:9: note: this is the location of the previous definition
      44 | #define ENODATA         61      /* No data available */
         |         ^~~~~~~
   arch/parisc/include/uapi/asm/errno.h:24:9: warning: 'ETIME' redefined
      24 | #define ETIME           52      /* Timer expired */
         |         ^~~~~
   include/uapi/asm-generic/errno.h:45:9: note: this is the location of the previous definition
      45 | #define ETIME           62      /* Timer expired */
         |         ^~~~~
   arch/parisc/include/uapi/asm/errno.h:25:9: warning: 'ENOSR' redefined
      25 | #define ENOSR           53      /* Out of streams resources */
         |         ^~~~~
   include/uapi/asm-generic/errno.h:46:9: note: this is the location of the previous definition
      46 | #define ENOSR           63      /* Out of streams resources */
         |         ^~~~~
   arch/parisc/include/uapi/asm/errno.h:26:9: warning: 'ENOSTR' redefined
      26 | #define ENOSTR          54      /* Device not a stream */
         |         ^~~~~~
   include/uapi/asm-generic/errno.h:43:9: note: this is the location of the previous definition
      43 | #define ENOSTR          60      /* Device not a stream */
         |         ^~~~~~
   arch/parisc/include/uapi/asm/errno.h:27:9: warning: 'ENOPKG' redefined
      27 | #define ENOPKG          55      /* Package not installed */
         |         ^~~~~~
   include/uapi/asm-generic/errno.h:48:9: note: this is the location of the previous definition
      48 | #define ENOPKG          65      /* Package not installed */
         |         ^~~~~~
   arch/parisc/include/uapi/asm/errno.h:29:9: warning: 'ENOLINK' redefined
      29 | #define ENOLINK         57      /* Link has been severed */
         |         ^~~~~~~
   include/uapi/asm-generic/errno.h:50:9: note: this is the location of the previous definition
      50 | #define ENOLINK         67      /* Link has been severed */
         |         ^~~~~~~
   arch/parisc/include/uapi/asm/errno.h:30:9: warning: 'EADV' redefined
      30 | #define EADV            58      /* Advertise error */
         |         ^~~~
   include/uapi/asm-generic/errno.h:51:9: note: this is the location of the previous definition
      51 | #define EADV            68      /* Advertise error */
         |         ^~~~
   arch/parisc/include/uapi/asm/errno.h:31:9: warning: 'ESRMNT' redefined
      31 | #define ESRMNT          59      /* Srmount error */
         |         ^~~~~~
   include/uapi/asm-generic/errno.h:52:9: note: this is the location of the previous definition
      52 | #define ESRMNT          69      /* Srmount error */
         |         ^~~~~~
   arch/parisc/include/uapi/asm/errno.h:32:9: warning: 'ECOMM' redefined
      32 | #define ECOMM           60      /* Communication error on send */
         |         ^~~~~
   include/uapi/asm-generic/errno.h:53:9: note: this is the location of the previous definition
      53 | #define ECOMM           70      /* Communication error on send */
         |         ^~~~~
   arch/parisc/include/uapi/asm/errno.h:33:9: warning: 'EPROTO' redefined
      33 | #define EPROTO          61      /* Protocol error */
         |         ^~~~~~
   include/uapi/asm-generic/errno.h:54:9: note: this is the location of the previous definition
      54 | #define EPROTO          71      /* Protocol error */
         |         ^~~~~~
>> arch/parisc/include/uapi/asm/errno.h:35:9: warning: 'EMULTIHOP' redefined
      35 | #define EMULTIHOP       64      /* Multihop attempted */
         |         ^~~~~~~~~
   include/uapi/asm-generic/errno.h:55:9: note: this is the location of the previous definition
      55 | #define EMULTIHOP       72      /* Multihop attempted */
         |         ^~~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:37:9: warning: 'EDOTDOT' redefined
      37 | #define EDOTDOT         66      /* RFS specific error */
         |         ^~~~~~~
   include/uapi/asm-generic/errno.h:56:9: note: this is the location of the previous definition
      56 | #define EDOTDOT         73      /* RFS specific error */
         |         ^~~~~~~
>> arch/parisc/include/uapi/asm/errno.h:38:9: warning: 'EBADMSG' redefined
      38 | #define EBADMSG         67      /* Not a data message */
         |         ^~~~~~~
   include/uapi/asm-generic/errno.h:57:9: note: this is the location of the previous definition
      57 | #define EBADMSG         74      /* Not a data message */
         |         ^~~~~~~
>> arch/parisc/include/uapi/asm/errno.h:39:9: warning: 'EUSERS' redefined
      39 | #define EUSERS          68      /* Too many users */
         |         ^~~~~~
   include/uapi/asm-generic/errno.h:70:9: note: this is the location of the previous definition
      70 | #define EUSERS          87      /* Too many users */
         |         ^~~~~~
   arch/parisc/include/uapi/asm/errno.h:40:9: warning: 'EDQUOT' redefined
      40 | #define EDQUOT          69      /* Quota exceeded */
         |         ^~~~~~
   include/uapi/asm-generic/errno.h:105:9: note: this is the location of the previous definition
     105 | #define EDQUOT          122     /* Quota exceeded */
         |         ^~~~~~
   arch/parisc/include/uapi/asm/errno.h:41:9: warning: 'ESTALE' redefined
      41 | #define ESTALE          70      /* Stale file handle */
         |         ^~~~~~
   include/uapi/asm-generic/errno.h:99:9: note: this is the location of the previous definition
      99 | #define ESTALE          116     /* Stale file handle */
         |         ^~~~~~
   arch/parisc/include/uapi/asm/errno.h:42:9: warning: 'EREMOTE' redefined
      42 | #define EREMOTE         71      /* Object is remote */
         |         ^~~~~~~
   include/uapi/asm-generic/errno.h:49:9: note: this is the location of the previous definition
      49 | #define EREMOTE         66      /* Object is remote */
         |         ^~~~~~~
   arch/parisc/include/uapi/asm/errno.h:43:9: warning: 'EOVERFLOW' redefined
      43 | #define EOVERFLOW       72      /* Value too large for defined data type */
         |         ^~~~~~~~~
   include/uapi/asm-generic/errno.h:58:9: note: this is the location of the previous definition
      58 | #define EOVERFLOW       75      /* Value too large for defined data type */
         |         ^~~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:47:9: warning: 'EBADE' redefined
      47 | #define EBADE           160     /* Invalid exchange */
         |         ^~~~~
   include/uapi/asm-generic/errno.h:33:9: note: this is the location of the previous definition
      33 | #define EBADE           52      /* Invalid exchange */
         |         ^~~~~
   arch/parisc/include/uapi/asm/errno.h:48:9: warning: 'EBADR' redefined
      48 | #define EBADR           161     /* Invalid request descriptor */
         |         ^~~~~
   include/uapi/asm-generic/errno.h:34:9: note: this is the location of the previous definition
      34 | #define EBADR           53      /* Invalid request descriptor */
         |         ^~~~~
>> arch/parisc/include/uapi/asm/errno.h:49:9: warning: 'EXFULL' redefined
      49 | #define EXFULL          162     /* Exchange full */
         |         ^~~~~~
   include/uapi/asm-generic/errno.h:35:9: note: this is the location of the previous definition
      35 | #define EXFULL          54      /* Exchange full */
         |         ^~~~~~
   arch/parisc/include/uapi/asm/errno.h:50:9: warning: 'ENOANO' redefined
      50 | #define ENOANO          163     /* No anode */
         |         ^~~~~~
   include/uapi/asm-generic/errno.h:36:9: note: this is the location of the previous definition
      36 | #define ENOANO          55      /* No anode */
         |         ^~~~~~
>> arch/parisc/include/uapi/asm/errno.h:51:9: warning: 'EBADRQC' redefined
      51 | #define EBADRQC         164     /* Invalid request code */
         |         ^~~~~~~
   include/uapi/asm-generic/errno.h:37:9: note: this is the location of the previous definition
      37 | #define EBADRQC         56      /* Invalid request code */
         |         ^~~~~~~
   arch/parisc/include/uapi/asm/errno.h:52:9: warning: 'EBADSLT' redefined
      52 | #define EBADSLT         165     /* Invalid slot */
         |         ^~~~~~~
   include/uapi/asm-generic/errno.h:38:9: note: this is the location of the previous definition
      38 | #define EBADSLT         57      /* Invalid slot */
         |         ^~~~~~~
   arch/parisc/include/uapi/asm/errno.h:53:9: warning: 'EBFONT' redefined
      53 | #define EBFONT          166     /* Bad font file format */
         |         ^~~~~~
   include/uapi/asm-generic/errno.h:42:9: note: this is the location of the previous definition
      42 | #define EBFONT          59      /* Bad font file format */
         |         ^~~~~~
   arch/parisc/include/uapi/asm/errno.h:54:9: warning: 'ENOTUNIQ' redefined
      54 | #define ENOTUNIQ        167     /* Name not unique on network */
         |         ^~~~~~~~
   include/uapi/asm-generic/errno.h:59:9: note: this is the location of the previous definition
      59 | #define ENOTUNIQ        76      /* Name not unique on network */
         |         ^~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:55:9: warning: 'EBADFD' redefined
      55 | #define EBADFD          168     /* File descriptor in bad state */
         |         ^~~~~~
   include/uapi/asm-generic/errno.h:60:9: note: this is the location of the previous definition
      60 | #define EBADFD          77      /* File descriptor in bad state */
         |         ^~~~~~
>> arch/parisc/include/uapi/asm/errno.h:56:9: warning: 'EREMCHG' redefined
      56 | #define EREMCHG         169     /* Remote address changed */
         |         ^~~~~~~
   include/uapi/asm-generic/errno.h:61:9: note: this is the location of the previous definition
      61 | #define EREMCHG         78      /* Remote address changed */
         |         ^~~~~~~
   arch/parisc/include/uapi/asm/errno.h:57:9: warning: 'ELIBACC' redefined
      57 | #define ELIBACC         170     /* Can not access a needed shared library */
         |         ^~~~~~~
   include/uapi/asm-generic/errno.h:62:9: note: this is the location of the previous definition
      62 | #define ELIBACC         79      /* Can not access a needed shared library */
         |         ^~~~~~~
>> arch/parisc/include/uapi/asm/errno.h:58:9: warning: 'ELIBBAD' redefined
      58 | #define ELIBBAD         171     /* Accessing a corrupted shared library */
         |         ^~~~~~~
   include/uapi/asm-generic/errno.h:63:9: note: this is the location of the previous definition
      63 | #define ELIBBAD         80      /* Accessing a corrupted shared library */
         |         ^~~~~~~
>> arch/parisc/include/uapi/asm/errno.h:59:9: warning: 'ELIBSCN' redefined
      59 | #define ELIBSCN         172     /* .lib section in a.out corrupted */
         |         ^~~~~~~
   include/uapi/asm-generic/errno.h:64:9: note: this is the location of the previous definition
      64 | #define ELIBSCN         81      /* .lib section in a.out corrupted */
         |         ^~~~~~~
   arch/parisc/include/uapi/asm/errno.h:60:9: warning: 'ELIBMAX' redefined
      60 | #define ELIBMAX         173     /* Attempting to link in too many shared libraries */
         |         ^~~~~~~
   include/uapi/asm-generic/errno.h:65:9: note: this is the location of the previous definition
      65 | #define ELIBMAX         82      /* Attempting to link in too many shared libraries */
         |         ^~~~~~~
>> arch/parisc/include/uapi/asm/errno.h:61:9: warning: 'ELIBEXEC' redefined
      61 | #define ELIBEXEC        174     /* Cannot exec a shared library directly */
         |         ^~~~~~~~
   include/uapi/asm-generic/errno.h:66:9: note: this is the location of the previous definition
      66 | #define ELIBEXEC        83      /* Cannot exec a shared library directly */
         |         ^~~~~~~~
>> arch/parisc/include/uapi/asm/errno.h:62:9: warning: 'ERESTART' redefined
      62 | #define ERESTART        175     /* Interrupted system call should be restarted */
         |         ^~~~~~~~
   include/uapi/asm-generic/errno.h:68:9: note: this is the location of the previous definition
      68 | #define ERESTART        85      /* Interrupted system call should be restarted */
         |         ^~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:63:9: warning: 'ESTRPIPE' redefined
      63 | #define ESTRPIPE        176     /* Streams pipe error */
         |         ^~~~~~~~
   include/uapi/asm-generic/errno.h:69:9: note: this is the location of the previous definition
      69 | #define ESTRPIPE        86      /* Streams pipe error */
         |         ^~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:64:9: warning: 'EUCLEAN' redefined
      64 | #define EUCLEAN         177     /* Structure needs cleaning */
         |         ^~~~~~~
   include/uapi/asm-generic/errno.h:100:9: note: this is the location of the previous definition
     100 | #define EUCLEAN         117     /* Structure needs cleaning */
         |         ^~~~~~~
   arch/parisc/include/uapi/asm/errno.h:65:9: warning: 'ENOTNAM' redefined
      65 | #define ENOTNAM         178     /* Not a XENIX named type file */
         |         ^~~~~~~
   include/uapi/asm-generic/errno.h:101:9: note: this is the location of the previous definition
     101 | #define ENOTNAM         118     /* Not a XENIX named type file */
         |         ^~~~~~~
   arch/parisc/include/uapi/asm/errno.h:66:9: warning: 'ENAVAIL' redefined
      66 | #define ENAVAIL         179     /* No XENIX semaphores available */
         |         ^~~~~~~
   include/uapi/asm-generic/errno.h:102:9: note: this is the location of the previous definition
     102 | #define ENAVAIL         119     /* No XENIX semaphores available */
         |         ^~~~~~~
   arch/parisc/include/uapi/asm/errno.h:67:9: warning: 'EISNAM' redefined
      67 | #define EISNAM          180     /* Is a named type file */
         |         ^~~~~~
   include/uapi/asm-generic/errno.h:103:9: note: this is the location of the previous definition
     103 | #define EISNAM          120     /* Is a named type file */
         |         ^~~~~~
>> arch/parisc/include/uapi/asm/errno.h:68:9: warning: 'EREMOTEIO' redefined
      68 | #define EREMOTEIO       181     /* Remote I/O error */
         |         ^~~~~~~~~
   include/uapi/asm-generic/errno.h:104:9: note: this is the location of the previous definition
     104 | #define EREMOTEIO       121     /* Remote I/O error */
         |         ^~~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:69:9: warning: 'ENOMEDIUM' redefined
      69 | #define ENOMEDIUM       182     /* No medium found */
         |         ^~~~~~~~~
   include/uapi/asm-generic/errno.h:107:9: note: this is the location of the previous definition
     107 | #define ENOMEDIUM       123     /* No medium found */
         |         ^~~~~~~~~
>> arch/parisc/include/uapi/asm/errno.h:70:9: warning: 'EMEDIUMTYPE' redefined
      70 | #define EMEDIUMTYPE     183     /* Wrong medium type */
         |         ^~~~~~~~~~~
   include/uapi/asm-generic/errno.h:108:9: note: this is the location of the previous definition
     108 | #define EMEDIUMTYPE     124     /* Wrong medium type */
         |         ^~~~~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:71:9: warning: 'ENOKEY' redefined
      71 | #define ENOKEY          184     /* Required key not available */
         |         ^~~~~~
   include/uapi/asm-generic/errno.h:110:9: note: this is the location of the previous definition
     110 | #define ENOKEY          126     /* Required key not available */
         |         ^~~~~~
>> arch/parisc/include/uapi/asm/errno.h:72:9: warning: 'EKEYEXPIRED' redefined
      72 | #define EKEYEXPIRED     185     /* Key has expired */
         |         ^~~~~~~~~~~
   include/uapi/asm-generic/errno.h:111:9: note: this is the location of the previous definition
     111 | #define EKEYEXPIRED     127     /* Key has expired */
         |         ^~~~~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:73:9: warning: 'EKEYREVOKED' redefined
      73 | #define EKEYREVOKED     186     /* Key has been revoked */
         |         ^~~~~~~~~~~
   include/uapi/asm-generic/errno.h:112:9: note: this is the location of the previous definition
     112 | #define EKEYREVOKED     128     /* Key has been revoked */
         |         ^~~~~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:74:9: warning: 'EKEYREJECTED' redefined
      74 | #define EKEYREJECTED    187     /* Key was rejected by service */
         |         ^~~~~~~~~~~~
   include/uapi/asm-generic/errno.h:113:9: note: this is the location of the previous definition
     113 | #define EKEYREJECTED    129     /* Key was rejected by service */
         |         ^~~~~~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:78:9: warning: 'ENOTSOCK' redefined
      78 | #define ENOTSOCK        216     /* Socket operation on non-socket */
         |         ^~~~~~~~
   include/uapi/asm-generic/errno.h:71:9: note: this is the location of the previous definition
      71 | #define ENOTSOCK        88      /* Socket operation on non-socket */
         |         ^~~~~~~~
>> arch/parisc/include/uapi/asm/errno.h:79:9: warning: 'EDESTADDRREQ' redefined
      79 | #define EDESTADDRREQ    217     /* Destination address required */
         |         ^~~~~~~~~~~~
   include/uapi/asm-generic/errno.h:72:9: note: this is the location of the previous definition
      72 | #define EDESTADDRREQ    89      /* Destination address required */
         |         ^~~~~~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:80:9: warning: 'EMSGSIZE' redefined
      80 | #define EMSGSIZE        218     /* Message too long */
         |         ^~~~~~~~
   include/uapi/asm-generic/errno.h:73:9: note: this is the location of the previous definition
      73 | #define EMSGSIZE        90      /* Message too long */
         |         ^~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:81:9: warning: 'EPROTOTYPE' redefined
      81 | #define EPROTOTYPE      219     /* Protocol wrong type for socket */
         |         ^~~~~~~~~~
   include/uapi/asm-generic/errno.h:74:9: note: this is the location of the previous definition
      74 | #define EPROTOTYPE      91      /* Protocol wrong type for socket */
         |         ^~~~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:82:9: warning: 'ENOPROTOOPT' redefined
      82 | #define ENOPROTOOPT     220     /* Protocol not available */
         |         ^~~~~~~~~~~
   include/uapi/asm-generic/errno.h:75:9: note: this is the location of the previous definition
      75 | #define ENOPROTOOPT     92      /* Protocol not available */
         |         ^~~~~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:83:9: warning: 'EPROTONOSUPPORT' redefined
      83 | #define EPROTONOSUPPORT 221     /* Protocol not supported */
         |         ^~~~~~~~~~~~~~~
   include/uapi/asm-generic/errno.h:76:9: note: this is the location of the previous definition
      76 | #define EPROTONOSUPPORT 93      /* Protocol not supported */
         |         ^~~~~~~~~~~~~~~
>> arch/parisc/include/uapi/asm/errno.h:84:9: warning: 'ESOCKTNOSUPPORT' redefined
      84 | #define ESOCKTNOSUPPORT 222     /* Socket type not supported */
         |         ^~~~~~~~~~~~~~~
   include/uapi/asm-generic/errno.h:77:9: note: this is the location of the previous definition
      77 | #define ESOCKTNOSUPPORT 94      /* Socket type not supported */
         |         ^~~~~~~~~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:85:9: warning: 'EOPNOTSUPP' redefined
      85 | #define EOPNOTSUPP      223     /* Operation not supported on transport endpoint */
         |         ^~~~~~~~~~
   include/uapi/asm-generic/errno.h:78:9: note: this is the location of the previous definition
      78 | #define EOPNOTSUPP      95      /* Operation not supported on transport endpoint */
         |         ^~~~~~~~~~
>> arch/parisc/include/uapi/asm/errno.h:86:9: warning: 'EPFNOSUPPORT' redefined
      86 | #define EPFNOSUPPORT    224     /* Protocol family not supported */
         |         ^~~~~~~~~~~~
   include/uapi/asm-generic/errno.h:79:9: note: this is the location of the previous definition
      79 | #define EPFNOSUPPORT    96      /* Protocol family not supported */
         |         ^~~~~~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:87:9: warning: 'EAFNOSUPPORT' redefined
      87 | #define EAFNOSUPPORT    225     /* Address family not supported by protocol */
         |         ^~~~~~~~~~~~
   include/uapi/asm-generic/errno.h:80:9: note: this is the location of the previous definition
      80 | #define EAFNOSUPPORT    97      /* Address family not supported by protocol */
         |         ^~~~~~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:88:9: warning: 'EADDRINUSE' redefined
      88 | #define EADDRINUSE      226     /* Address already in use */
         |         ^~~~~~~~~~
   include/uapi/asm-generic/errno.h:81:9: note: this is the location of the previous definition
      81 | #define EADDRINUSE      98      /* Address already in use */
         |         ^~~~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:89:9: warning: 'EADDRNOTAVAIL' redefined
      89 | #define EADDRNOTAVAIL   227     /* Cannot assign requested address */
         |         ^~~~~~~~~~~~~
   include/uapi/asm-generic/errno.h:82:9: note: this is the location of the previous definition
      82 | #define EADDRNOTAVAIL   99      /* Cannot assign requested address */
         |         ^~~~~~~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:90:9: warning: 'ENETDOWN' redefined
      90 | #define ENETDOWN        228     /* Network is down */
         |         ^~~~~~~~
   include/uapi/asm-generic/errno.h:83:9: note: this is the location of the previous definition
      83 | #define ENETDOWN        100     /* Network is down */
         |         ^~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:91:9: warning: 'ENETUNREACH' redefined
      91 | #define ENETUNREACH     229     /* Network is unreachable */
         |         ^~~~~~~~~~~
   include/uapi/asm-generic/errno.h:84:9: note: this is the location of the previous definition
      84 | #define ENETUNREACH     101     /* Network is unreachable */
         |         ^~~~~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:92:9: warning: 'ENETRESET' redefined
      92 | #define ENETRESET       230     /* Network dropped connection because of reset */
         |         ^~~~~~~~~
   include/uapi/asm-generic/errno.h:85:9: note: this is the location of the previous definition
      85 | #define ENETRESET       102     /* Network dropped connection because of reset */
         |         ^~~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:93:9: warning: 'ECONNABORTED' redefined
      93 | #define ECONNABORTED    231     /* Software caused connection abort */
         |         ^~~~~~~~~~~~
   include/uapi/asm-generic/errno.h:86:9: note: this is the location of the previous definition
      86 | #define ECONNABORTED    103     /* Software caused connection abort */
         |         ^~~~~~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:94:9: warning: 'ECONNRESET' redefined
      94 | #define ECONNRESET      232     /* Connection reset by peer */
         |         ^~~~~~~~~~
   include/uapi/asm-generic/errno.h:87:9: note: this is the location of the previous definition
      87 | #define ECONNRESET      104     /* Connection reset by peer */
         |         ^~~~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:95:9: warning: 'ENOBUFS' redefined
      95 | #define ENOBUFS         233     /* No buffer space available */
         |         ^~~~~~~
   include/uapi/asm-generic/errno.h:88:9: note: this is the location of the previous definition
      88 | #define ENOBUFS         105     /* No buffer space available */
         |         ^~~~~~~
   arch/parisc/include/uapi/asm/errno.h:96:9: warning: 'EISCONN' redefined
      96 | #define EISCONN         234     /* Transport endpoint is already connected */
         |         ^~~~~~~
   include/uapi/asm-generic/errno.h:89:9: note: this is the location of the previous definition
      89 | #define EISCONN         106     /* Transport endpoint is already connected */
         |         ^~~~~~~
   arch/parisc/include/uapi/asm/errno.h:97:9: warning: 'ENOTCONN' redefined
      97 | #define ENOTCONN        235     /* Transport endpoint is not connected */
         |         ^~~~~~~~
   include/uapi/asm-generic/errno.h:90:9: note: this is the location of the previous definition
      90 | #define ENOTCONN        107     /* Transport endpoint is not connected */
         |         ^~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:98:9: warning: 'ESHUTDOWN' redefined
      98 | #define ESHUTDOWN       236     /* Cannot send after transport endpoint shutdown */
         |         ^~~~~~~~~
   include/uapi/asm-generic/errno.h:91:9: note: this is the location of the previous definition
      91 | #define ESHUTDOWN       108     /* Cannot send after transport endpoint shutdown */
         |         ^~~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:99:9: warning: 'ETOOMANYREFS' redefined
      99 | #define ETOOMANYREFS    237     /* Too many references: cannot splice */
         |         ^~~~~~~~~~~~
   include/uapi/asm-generic/errno.h:92:9: note: this is the location of the previous definition
      92 | #define ETOOMANYREFS    109     /* Too many references: cannot splice */
         |         ^~~~~~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:100:9: warning: 'ETIMEDOUT' redefined
     100 | #define ETIMEDOUT       238     /* Connection timed out */
         |         ^~~~~~~~~
   include/uapi/asm-generic/errno.h:93:9: note: this is the location of the previous definition
      93 | #define ETIMEDOUT       110     /* Connection timed out */
         |         ^~~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:101:9: warning: 'ECONNREFUSED' redefined
     101 | #define ECONNREFUSED    239     /* Connection refused */
         |         ^~~~~~~~~~~~
   include/uapi/asm-generic/errno.h:94:9: note: this is the location of the previous definition
      94 | #define ECONNREFUSED    111     /* Connection refused */
         |         ^~~~~~~~~~~~
   arch/parisc/include/uapi/asm/errno.h:103:9: warning: 'EHOSTDOWN' redefined
     103 | #define EHOSTDOWN       241     /* Host is down */
         |         ^~~~~~~~~
   include/uapi/asm-generic/errno.h:95:9: note: this is the location of the previous definition
      95 | #define EHOSTDOWN       112     /* Host is down */


vim +/EIDRM +8 arch/parisc/include/uapi/asm/errno.h

^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16    6  
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16    7  #define	ENOMSG		35	/* No message of desired type */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   @8  #define	EIDRM		36	/* Identifier removed */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16    9  #define	ECHRNG		37	/* Channel number out of range */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @10  #define	EL2NSYNC	38	/* Level 2 not synchronized */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   11  #define	EL3HLT		39	/* Level 3 halted */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   12  #define	EL3RST		40	/* Level 3 reset */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   13  #define	ELNRNG		41	/* Link number out of range */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   14  #define	EUNATCH		42	/* Protocol driver not attached */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   15  #define	ENOCSI		43	/* No CSI structure available */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   16  #define	EL2HLT		44	/* Level 2 halted */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @17  #define	EDEADLK		45	/* Resource deadlock would occur */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   18  #define	EDEADLOCK	EDEADLK
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   19  #define	ENOLCK		46	/* No record locks available */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @20  #define	EILSEQ		47	/* Illegal byte sequence */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   21  
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   22  #define	ENONET		50	/* Machine is not on the network */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   23  #define	ENODATA		51	/* No data available */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   24  #define	ETIME		52	/* Timer expired */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   25  #define	ENOSR		53	/* Out of streams resources */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   26  #define	ENOSTR		54	/* Device not a stream */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   27  #define	ENOPKG		55	/* Package not installed */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   28  
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   29  #define	ENOLINK		57	/* Link has been severed */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   30  #define	EADV		58	/* Advertise error */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   31  #define	ESRMNT		59	/* Srmount error */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   32  #define	ECOMM		60	/* Communication error on send */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   33  #define	EPROTO		61	/* Protocol error */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   34  
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @35  #define	EMULTIHOP	64	/* Multihop attempted */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   36  
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   37  #define	EDOTDOT		66	/* RFS specific error */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @38  #define	EBADMSG		67	/* Not a data message */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @39  #define	EUSERS		68	/* Too many users */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   40  #define	EDQUOT		69	/* Quota exceeded */
0ca43435188b9f9 arch/parisc/include/uapi/asm/errno.h Eric Sandeen        2013-11-12   41  #define	ESTALE		70	/* Stale file handle */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   42  #define	EREMOTE		71	/* Object is remote */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   43  #define	EOVERFLOW	72	/* Value too large for defined data type */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   44  
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   45  /* these errnos are defined by Linux but not HPUX. */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   46  
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   47  #define	EBADE		160	/* Invalid exchange */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   48  #define	EBADR		161	/* Invalid request descriptor */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @49  #define	EXFULL		162	/* Exchange full */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   50  #define	ENOANO		163	/* No anode */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @51  #define	EBADRQC		164	/* Invalid request code */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   52  #define	EBADSLT		165	/* Invalid slot */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   53  #define	EBFONT		166	/* Bad font file format */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   54  #define	ENOTUNIQ	167	/* Name not unique on network */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   55  #define	EBADFD		168	/* File descriptor in bad state */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @56  #define	EREMCHG		169	/* Remote address changed */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   57  #define	ELIBACC		170	/* Can not access a needed shared library */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @58  #define	ELIBBAD		171	/* Accessing a corrupted shared library */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @59  #define	ELIBSCN		172	/* .lib section in a.out corrupted */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   60  #define	ELIBMAX		173	/* Attempting to link in too many shared libraries */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @61  #define	ELIBEXEC	174	/* Cannot exec a shared library directly */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @62  #define	ERESTART	175	/* Interrupted system call should be restarted */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   63  #define	ESTRPIPE	176	/* Streams pipe error */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   64  #define	EUCLEAN		177	/* Structure needs cleaning */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   65  #define	ENOTNAM		178	/* Not a XENIX named type file */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   66  #define	ENAVAIL		179	/* No XENIX semaphores available */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   67  #define	EISNAM		180	/* Is a named type file */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @68  #define	EREMOTEIO	181	/* Remote I/O error */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   69  #define	ENOMEDIUM	182	/* No medium found */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @70  #define	EMEDIUMTYPE	183	/* Wrong medium type */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   71  #define	ENOKEY		184	/* Required key not available */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @72  #define	EKEYEXPIRED	185	/* Key has expired */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   73  #define	EKEYREVOKED	186	/* Key has been revoked */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   74  #define	EKEYREJECTED	187	/* Key was rejected by service */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   75  
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   76  /* We now return you to your regularly scheduled HPUX. */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   77  
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   78  #define	ENOTSOCK	216	/* Socket operation on non-socket */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @79  #define	EDESTADDRREQ	217	/* Destination address required */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   80  #define	EMSGSIZE	218	/* Message too long */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   81  #define	EPROTOTYPE	219	/* Protocol wrong type for socket */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   82  #define	ENOPROTOOPT	220	/* Protocol not available */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   83  #define	EPROTONOSUPPORT	221	/* Protocol not supported */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @84  #define	ESOCKTNOSUPPORT	222	/* Socket type not supported */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   85  #define	EOPNOTSUPP	223	/* Operation not supported on transport endpoint */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @86  #define	EPFNOSUPPORT	224	/* Protocol family not supported */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @87  #define	EAFNOSUPPORT	225	/* Address family not supported by protocol */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @88  #define	EADDRINUSE	226	/* Address already in use */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   89  #define	EADDRNOTAVAIL	227	/* Cannot assign requested address */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @90  #define	ENETDOWN	228	/* Network is down */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @91  #define	ENETUNREACH	229	/* Network is unreachable */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   92  #define	ENETRESET	230	/* Network dropped connection because of reset */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @93  #define	ECONNABORTED	231	/* Software caused connection abort */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   94  #define	ECONNRESET	232	/* Connection reset by peer */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @95  #define	ENOBUFS		233	/* No buffer space available */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @96  #define	EISCONN		234	/* Transport endpoint is already connected */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   97  #define	ENOTCONN	235	/* Transport endpoint is not connected */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16   98  #define	ESHUTDOWN	236	/* Cannot send after transport endpoint shutdown */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  @99  #define	ETOOMANYREFS	237	/* Too many references: cannot splice */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16 @100  #define	ETIMEDOUT	238	/* Connection timed out */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  101  #define	ECONNREFUSED	239	/* Connection refused */
3eb53b20d7bd137 arch/parisc/include/uapi/asm/errno.h Helge Deller        2016-08-20  102  #define	EREFUSED	ECONNREFUSED	/* for HP's NFS apparently */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  103  #define	EHOSTDOWN	241	/* Host is down */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  104  #define	EHOSTUNREACH	242	/* No route to host */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  105  
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16 @106  #define	EALREADY	244	/* Operation already in progress */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16 @107  #define	EINPROGRESS	245	/* Operation now in progress */
f5a408d53edef3a arch/parisc/include/uapi/asm/errno.h Guy Martin          2014-01-16  108  #define	EWOULDBLOCK	EAGAIN	/* Operation would block (Not HPUX compliant) */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  109  #define	ENOTEMPTY	247	/* Directory not empty */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  110  #define	ENAMETOOLONG	248	/* File name too long */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  111  #define	ELOOP		249	/* Too many symbolic links encountered */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  112  #define	ENOSYS		251	/* Function not implemented */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  113  
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  114  #define ECANCELLED	253	/* aio request was canceled before complete (POSIX.4 / HPUX) */
05aa10de701409b include/asm-parisc/errno.h           Grant Grundler      2005-10-21  115  #define ECANCELED	ECANCELLED	/* SuSv3 and Solaris wants one 'L' */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  116  
4750e2c0c59e0c8 include/asm-parisc/errno.h           Joe Korty           2005-05-01  117  /* for robust mutexes */
4750e2c0c59e0c8 include/asm-parisc/errno.h           Joe Korty           2005-05-01  118  #define EOWNERDEAD	254	/* Owner died */
4750e2c0c59e0c8 include/asm-parisc/errno.h           Joe Korty           2005-05-01 @119  #define ENOTRECOVERABLE	255	/* State not recoverable */
4750e2c0c59e0c8 include/asm-parisc/errno.h           Joe Korty           2005-05-01  120  
7d217d7ffc3433d arch/parisc/include/asm/errno.h      Alexander Beregalov 2009-06-07 @121  #define	ERFKILL		256	/* Operation not possible due to RF-kill */
^1da177e4c3f415 include/asm-parisc/errno.h           Linus Torvalds      2005-04-16  122  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From nsc at kernel.org  Fri Dec 12 11:09:31 2025
From: nsc at kernel.org (Nicolas Schier)
Date: Fri, 12 Dec 2025 20:09:31 +0100
Subject: [PATCH v7 6/6] scripts/make_fit: Compress dtbs in parallel
In-Reply-To: <20251211140309.1910613-7-sjg@chromium.org>
References: <20251211140309.1910613-1-sjg@chromium.org>
 <20251211140309.1910613-7-sjg@chromium.org>
Message-ID: <aTxoa9ghRIMqAMrO@levanger>

On Thu, Dec 11, 2025 at 07:03:03AM -0700, Simon Glass wrote:
> When there are 1500 device tree files it takes quite a while to compress
> them. Do it in parallel.
> 

> kbuild: Allow adding modules into the FIT ramdisk

This line sneaked in somehow?

Kind regards,
Nicolas


From lkp at intel.com  Sat Dec 13 14:38:13 2025
From: lkp at intel.com (kernel test robot)
Date: Sun, 14 Dec 2025 06:38:13 +0800
Subject: [PATCH 6/8] gpio: aaeon: Add GPIO driver for SRG-IMX8PL MCU
In-Reply-To: <20251212-dev-b4-aaeon-mcu-driver-v1-6-6bd65bc8ef12@bootlin.com>
References: <20251212-dev-b4-aaeon-mcu-driver-v1-6-6bd65bc8ef12@bootlin.com>
Message-ID: <202512140637.VrfgC1Tj-lkp@intel.com>

Hi Thomas,

kernel test robot noticed the following build errors:

[auto build test ERROR on d358e5254674b70f34c847715ca509e46eb81e6f]

url:    https://github.com/intel-lab-lkp/linux/commits/Thomas-Perrot-Schneider-Electric/dt-bindings-vendor-prefixes-Add-AAEON-vendor-prefix/20251212-154458
base:   d358e5254674b70f34c847715ca509e46eb81e6f
patch link:    https://lore.kernel.org/r/20251212-dev-b4-aaeon-mcu-driver-v1-6-6bd65bc8ef12%40bootlin.com
patch subject: [PATCH 6/8] gpio: aaeon: Add GPIO driver for SRG-IMX8PL MCU
config: mips-randconfig-r051-20251213 (https://download.01.org/0day-ci/archive/20251214/202512140637.VrfgC1Tj-lkp at intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 1335a05ab8bc8339ce24be3a9da89d8c3f4e0571)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251214/202512140637.VrfgC1Tj-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512140637.VrfgC1Tj-lkp at intel.com/

All errors (new ones prefixed by >>, old ones prefixed by <<):

>> ERROR: modpost: "aaeon_mcu_i2c_xfer" [drivers/gpio/gpio-aaeon-mcu.ko] undefined!

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From stefano.radaelli21 at gmail.com  Sat Dec 13 15:09:00 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Sun, 14 Dec 2025 00:09:00 +0100
Subject: [PATCH v2 0/6] arm64: dts: imx8mp-var-som: align DTS with hardware revision
Message-ID: <20251213230909.16810-1-stefano.r@variscite.com>

This patch series aligns the VAR-SOM-MX8MP device tree with the actual
hardware populated on the System-on-Module, and separates SOM-specific
descriptions from carrier-board-specific ones.

The first three patches move the USDHC2 interface, the PCA9534 GPIO
expander, and the UART2 debug console out of the SOM dtsi, as these
components are not present on the VAR-SOM-MX8MP module itself and are
instead routed on the Symphony carrier board. Their descriptions are
therefore provided in the carrier board DTS, keeping the SOM device
tree limited to on-module hardware.

The remaining patches add support for peripherals that are populated
on the SOM and commonly used across designs, including WiFi/Bluetooth
connectivity, the WM8904 audio codec, and the ADS7846 touchscreen
controller.

Overall, this series ensures a clear separation between SOM and carrier
board responsibilities in the device tree, avoids describing
non-existent hardware on the module, and enables key on-module
features.

v2:
 - Move deleted nodes from SOM dts to Symphony carrier board

Stefano Radaelli (6):
  arm64: dts: imx8mp-var-som: Move USDHC2 support to Symphony carrier
  arm64: dts: imx8mp-var-som: Move PCA9534 GPIO expander to Symphony
    carrier
  arm64: dts: imx8mp-var-som: Move UART2 description to Symphony carrier
  arm64: dts: imx8mp-var-som: Add WiFi and Bluetooth support
  arm64: dts: imx8mp-var-som: Add support for WM8904 audio codec
  arm64: dts: imx8mp-var-som: Add support for ADS7846 touchscreen

 .../dts/freescale/imx8mp-var-som-symphony.dts | 145 ++++++++
 .../boot/dts/freescale/imx8mp-var-som.dtsi    | 332 +++++++++++-------
 2 files changed, 356 insertions(+), 121 deletions(-)


base-commit: cb015814f8b6eebcbb8e46e111d108892c5e6821
-- 
2.47.3



From stefano.radaelli21 at gmail.com  Sat Dec 13 15:09:01 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Sun, 14 Dec 2025 00:09:01 +0100
Subject: [PATCH v2 1/6] arm64: dts: imx8mp-var-som: Move USDHC2 support to Symphony carrier
In-Reply-To: <20251213230909.16810-1-stefano.r@variscite.com>
References: <20251213230909.16810-1-stefano.r@variscite.com>
Message-ID: <20251213230909.16810-2-stefano.r@variscite.com>

The VAR-SOM-MX8MP module does not include a microSD slot connected to
USDHC2. The USDHC2 interface is routed only on the Symphony carrier
board, and it may optionally be used or omitted depending on the
customer's carrier design.

Move the USDHC2 node, its regulators, pinctrl groups and related GPIOs
from the SOM device tree to the Symphony carrier DTS, keeping the SOM
description limited to hardware populated on the module.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../dts/freescale/imx8mp-var-som-symphony.dts | 77 +++++++++++++++++++
 .../boot/dts/freescale/imx8mp-var-som.dtsi    | 75 ------------------
 2 files changed, 77 insertions(+), 75 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts b/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
index 36d3eb865202..ea3c193bb684 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
@@ -8,4 +8,81 @@
 / {
 	model = "Variscite VAR-SOM-MX8M-PLUS on Symphony-Board";
 	compatible = "variscite,var-som-mx8mp-symphony", "variscite,var-som-mx8mp", "fsl,imx8mp";
+
+	reg_usdhc2_vmmc: regulator-usdhc2-vmmc {
+		compatible = "regulator-fixed";
+		regulator-name = "VSD_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpios = <&gpio4 22 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		startup-delay-us = <100>;
+		off-on-delay-us = <12000>;
+	};
+
+	reg_usdhc2_vqmmc: regulator-usdhc2-vqmmc {
+		compatible = "regulator-gpio";
+		regulator-name = "VSD_VSEL";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <3300000>;
+		gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>;
+		states = <3300000 0x0 1800000 0x1>;
+		vin-supply = <&ldo5>;
+	};
+};
+
+/* SD-card */
+&usdhc2 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+	cd-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	vqmmc-supply = <&reg_usdhc2_vqmmc>;
+	bus-width = <4>;
+	status = "okay";
+};
+
+&iomuxc {
+	pinctrl_usdhc2_gpio: usdhc2-gpiogrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14                             0x1c4
+			MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22                               0x10
+			MX8MP_IOMUXC_SD2_CD_B__GPIO2_IO12                               0xc0
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK                                0x190
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD                                0x1d0
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0                            0x1d0
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1                            0x1d0
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2                            0x1d0
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3                            0x1d0
+		>;
+	};
+
+	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK                                0x194
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD                                0x1d4
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0                            0x1d4
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1                            0x1d4
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2                            0x1d4
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3                            0x1d4
+		>;
+	};
+
+	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK                                0x196
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD                                0x1d6
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0                            0x1d6
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1                            0x1d6
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2                            0x1d6
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3                            0x1d6
+		>;
+	};
 };
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
index 29f080904482..949d9878f395 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
@@ -35,27 +35,6 @@ memory at 40000000 {
 		      <0x1 0x00000000 0 0xc0000000>;
 	};
 
-	reg_usdhc2_vmmc: regulator-usdhc2-vmmc {
-	        compatible = "regulator-fixed";
-	        regulator-name = "VSD_3V3";
-	        regulator-min-microvolt = <3300000>;
-	        regulator-max-microvolt = <3300000>;
-	        gpios = <&gpio4 22 GPIO_ACTIVE_HIGH>;
-	        enable-active-high;
-	        startup-delay-us = <100>;
-	        off-on-delay-us = <12000>;
-	};
-
-	reg_usdhc2_vqmmc: regulator-usdhc2-vqmmc {
-		compatible = "regulator-gpio";
-		regulator-name = "VSD_VSEL";
-		regulator-min-microvolt = <1800000>;
-		regulator-max-microvolt = <3300000>;
-		gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>;
-		states = <3300000 0x0 1800000 0x1>;
-		vin-supply = <&ldo5>;
-	};
-
 	reg_phy_supply: regulator-phy-supply {
 		compatible = "regulator-fixed";
 		regulator-name = "phy-supply";
@@ -271,19 +250,6 @@ &uart2 {
         status = "okay";
 };
 
-/* SD-card */
-&usdhc2 {
-        pinctrl-names = "default", "state_100mhz", "state_200mhz";
-        pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
-        pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
-        pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
-        cd-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;
-        vmmc-supply = <&reg_usdhc2_vmmc>;
-	vqmmc-supply = <&reg_usdhc2_vqmmc>;
-        bus-width = <4>;
-        status = "okay";
-};
-
 /* eMMC */
 &usdhc3 {
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
@@ -358,47 +324,6 @@ MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX                            0x40
 		>;
 	};
 
-	pinctrl_usdhc2_gpio: usdhc2-gpiogrp {
-	        fsl,pins = <
-	                MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14                             0x1c4
-	                MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22                               0x10
-	                MX8MP_IOMUXC_SD2_CD_B__GPIO2_IO12                               0xc0
-	        >;
-	};
-
-	pinctrl_usdhc2: usdhc2grp {
-	        fsl,pins = <
-	                MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK                                0x190
-	                MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD                                0x1d0
-	                MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0                            0x1d0
-	                MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1                            0x1d0
-	                MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2                            0x1d0
-	                MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3                            0x1d0
-	        >;
-	};
-
-	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
-	        fsl,pins = <
-	                MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK                                0x194
-	                MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD                                0x1d4
-	                MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0                            0x1d4
-	                MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1                            0x1d4
-	                MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2                            0x1d4
-	                MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3                            0x1d4
-	        >;
-	};
-
-	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
-	        fsl,pins = <
-	                MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK                                0x196
-	                MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD                                0x1d6
-	                MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0                            0x1d6
-	                MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1                            0x1d6
-	                MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2                            0x1d6
-	                MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3                            0x1d6
-	        >;
-	};
-
 	pinctrl_usdhc3: usdhc3grp {
 		fsl,pins = <
 			MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK				0x190
-- 
2.47.3



From stefano.radaelli21 at gmail.com  Sat Dec 13 15:09:02 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Sun, 14 Dec 2025 00:09:02 +0100
Subject: [PATCH v2 2/6] arm64: dts: imx8mp-var-som: Move PCA9534 GPIO expander to Symphony carrier
In-Reply-To: <20251213230909.16810-1-stefano.r@variscite.com>
References: <20251213230909.16810-1-stefano.r@variscite.com>
Message-ID: <20251213230909.16810-3-stefano.r@variscite.com>

The VAR-SOM-MX8MP module does not include the PCA9534 GPIO expander nor
the LED connected to it. These components are present only on the
Symphony carrier board and may vary across custom carrier designs.

Move the PCA9534 GPIO expander node and the associated LED definition
from the SOM device tree to the Symphony carrier DTS, ensuring the SOM
dtsi describes only hardware present on the module.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../dts/freescale/imx8mp-var-som-symphony.dts | 50 +++++++++++++++++++
 .../boot/dts/freescale/imx8mp-var-som.dtsi    | 50 -------------------
 2 files changed, 50 insertions(+), 50 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts b/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
index ea3c193bb684..361e6122bdc3 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
@@ -9,6 +9,16 @@ / {
 	model = "Variscite VAR-SOM-MX8M-PLUS on Symphony-Board";
 	compatible = "variscite,var-som-mx8mp-symphony", "variscite,var-som-mx8mp", "fsl,imx8mp";
 
+	gpio-leds {
+		compatible = "gpio-leds";
+
+		led-0 {
+			function = LED_FUNCTION_POWER;
+			gpios = <&pca9534 0 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+	};
+
 	reg_usdhc2_vmmc: regulator-usdhc2-vmmc {
 		compatible = "regulator-fixed";
 		regulator-name = "VSD_3V3";
@@ -31,6 +41,33 @@ reg_usdhc2_vqmmc: regulator-usdhc2-vqmmc {
 	};
 };
 
+&i2c3 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	status = "okay";
+
+	/* GPIO expander */
+	pca9534: gpio at 20 {
+		compatible = "nxp,pca9534";
+		reg = <0x20>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_pca9534>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <15 IRQ_TYPE_EDGE_FALLING>;
+		wakeup-source;
+
+		usb3-sata-sel-hog {
+			gpio-hog;
+			gpios = <4 0>;
+			output-low;
+			line-name = "usb3_sata_sel";
+		};
+	};
+};
+
 /* SD-card */
 &usdhc2 {
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
@@ -45,6 +82,19 @@ &usdhc2 {
 };
 
 &iomuxc {
+	pinctrl_i2c3: i2c3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL                                 0x400001c2
+			MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA                                 0x400001c2
+		>;
+	};
+
+	pinctrl_pca9534: pca9534grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO15__GPIO1_IO15                             0xc0
+		>;
+	};
+
 	pinctrl_usdhc2_gpio: usdhc2-gpiogrp {
 		fsl,pins = <
 			MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14                             0x1c4
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
index 949d9878f395..158a78ec9656 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
@@ -19,16 +19,6 @@ chosen {
 		stdout-path = &uart2;
 	};
 
-	gpio-leds {
-	        compatible = "gpio-leds";
-
-	        led-0 {
-	                function = LED_FUNCTION_POWER;
-	                gpios = <&pca9534 0 GPIO_ACTIVE_HIGH>;
-	                linux,default-trigger = "heartbeat";
-	        };
-	};
-
 	memory at 40000000 {
 		device_type = "memory";
 		reg = <0x0 0x40000000 0 0xc0000000>,
@@ -216,33 +206,6 @@ ldo5: LDO5 {
 	};
 };
 
-&i2c3 {
-        clock-frequency = <400000>;
-        pinctrl-names = "default";
-        pinctrl-0 = <&pinctrl_i2c3>;
-        status = "okay";
-
-	/* GPIO expander */
-	pca9534: gpio at 20 {
-	        compatible = "nxp,pca9534";
-	        reg = <0x20>;
-	        pinctrl-names = "default";
-	        pinctrl-0 = <&pinctrl_pca9534>;
-	        gpio-controller;
-	        #gpio-cells = <2>;
-	        interrupt-parent = <&gpio1>;
-	        interrupts = <15 IRQ_TYPE_EDGE_FALLING>;
-	        wakeup-source;
-
-	        usb3-sata-sel-hog {
-	                gpio-hog;
-	                gpios = <4 0>;
-	                output-low;
-	                line-name = "usb3_sata_sel";
-	        };
-	};
-};
-
 /* Console */
 &uart2 {
         pinctrl-names = "default";
@@ -298,19 +261,6 @@ MX8MP_IOMUXC_SD1_DATA5__I2C1_SDA				0x400001c2
 		>;
 	};
 
-	pinctrl_i2c3: i2c3grp {
-	        fsl,pins = <
-	                MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL                                 0x400001c2
-	                MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA                                 0x400001c2
-	        >;
-	};
-
-	pinctrl_pca9534: pca9534grp {
-	        fsl,pins = <
-	                MX8MP_IOMUXC_GPIO1_IO15__GPIO1_IO15                             0xc0
-	        >;
-	};
-
 	pinctrl_pmic: pmicgrp {
 		fsl,pins = <
 			MX8MP_IOMUXC_SPDIF_RX__GPIO5_IO04				0x1c0
-- 
2.47.3



From stefano.radaelli21 at gmail.com  Sat Dec 13 15:09:03 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Sun, 14 Dec 2025 00:09:03 +0100
Subject: [PATCH v2 3/6] arm64: dts: imx8mp-var-som: Move UART2 description to Symphony carrier
In-Reply-To: <20251213230909.16810-1-stefano.r@variscite.com>
References: <20251213230909.16810-1-stefano.r@variscite.com>
Message-ID: <20251213230909.16810-4-stefano.r@variscite.com>

The VAR-SOM-MX8MP module does not provide an onboard debug console.
UART2 is routed and exposed only on the Symphony carrier board, while
custom carrier designs may choose to expose a different UART.

Move the UART2 node from the SOM device tree to the
imx8mp-var-som-symphony.dts, keeping the SOM dtsi limited to hardware
present on the module itself.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../dts/freescale/imx8mp-var-som-symphony.dts  | 18 ++++++++++++++++++
 .../boot/dts/freescale/imx8mp-var-som.dtsi     | 18 ------------------
 2 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts b/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
index 361e6122bdc3..291f65e36865 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
@@ -9,6 +9,10 @@ / {
 	model = "Variscite VAR-SOM-MX8M-PLUS on Symphony-Board";
 	compatible = "variscite,var-som-mx8mp-symphony", "variscite,var-som-mx8mp", "fsl,imx8mp";
 
+	chosen {
+		stdout-path = &uart2;
+	};
+
 	gpio-leds {
 		compatible = "gpio-leds";
 
@@ -68,6 +72,13 @@ usb3-sata-sel-hog {
 	};
 };
 
+/* Console */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2>;
+	status = "okay";
+};
+
 /* SD-card */
 &usdhc2 {
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
@@ -95,6 +106,13 @@ MX8MP_IOMUXC_GPIO1_IO15__GPIO1_IO15                             0xc0
 		>;
 	};
 
+	pinctrl_uart2: uart2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX                            0x40
+			MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX                            0x40
+		>;
+	};
+
 	pinctrl_usdhc2_gpio: usdhc2-gpiogrp {
 		fsl,pins = <
 			MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14                             0x1c4
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
index 158a78ec9656..5bba91dcef17 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
@@ -15,10 +15,6 @@
 / {
 	model = "Variscite VAR-SOM-MX8M Plus module";
 
-	chosen {
-		stdout-path = &uart2;
-	};
-
 	memory at 40000000 {
 		device_type = "memory";
 		reg = <0x0 0x40000000 0 0xc0000000>,
@@ -206,13 +202,6 @@ ldo5: LDO5 {
 	};
 };
 
-/* Console */
-&uart2 {
-        pinctrl-names = "default";
-        pinctrl-0 = <&pinctrl_uart2>;
-        status = "okay";
-};
-
 /* eMMC */
 &usdhc3 {
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
@@ -267,13 +256,6 @@ MX8MP_IOMUXC_SPDIF_RX__GPIO5_IO04				0x1c0
 		>;
 	};
 
-	pinctrl_uart2: uart2grp {
-	        fsl,pins = <
-		        MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX                            0x40
-			MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX                            0x40
-		>;
-	};
-
 	pinctrl_usdhc3: usdhc3grp {
 		fsl,pins = <
 			MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK				0x190
-- 
2.47.3



From stefano.radaelli21 at gmail.com  Sat Dec 13 15:09:04 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Sun, 14 Dec 2025 00:09:04 +0100
Subject: [PATCH v2 4/6] arm64: dts: imx8mp-var-som: Add WiFi and Bluetooth support
In-Reply-To: <20251213230909.16810-1-stefano.r@variscite.com>
References: <20251213230909.16810-1-stefano.r@variscite.com>
Message-ID: <20251213230909.16810-5-stefano.r@variscite.com>

Add device tree nodes for the WiFi and Bluetooth module mounted on the
VAR-SOM-MX8MP. The module can be based on either the NXP IW612 or IW611
chipset, depending on the configuration chosen by the customer.

Regardless of the chipset used, WiFi communicates over SDIO and Bluetooth
over UART.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../boot/dts/freescale/imx8mp-var-som.dtsi    | 93 +++++++++++++++++++
 1 file changed, 93 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
index 5bba91dcef17..e7f5ec10cbac 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
@@ -21,6 +21,15 @@ memory at 40000000 {
 		      <0x1 0x00000000 0 0xc0000000>;
 	};
 
+	iw61x_pwrseq: wifi-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		post-power-on-delay-ms = <100>;
+		power-off-delay-us = <10000>;
+		reset-gpios = <&gpio2 8 GPIO_ACTIVE_LOW>, /* WIFI_RESET */
+			      <&gpio2 19 GPIO_ACTIVE_LOW>; /* WIFI_PWR_EN */
+		status = "okay";
+	};
+
 	reg_phy_supply: regulator-phy-supply {
 		compatible = "regulator-fixed";
 		regulator-name = "phy-supply";
@@ -202,6 +211,33 @@ ldo5: LDO5 {
 	};
 };
 
+/* BT */
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart3>, <&pinctrl_bluetooth>;
+	assigned-clocks = <&clk IMX8MP_CLK_UART3>;
+	assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_80M>;
+	uart-has-rtscts;
+	status = "okay";
+
+	bluetooth {
+		compatible = "nxp,88w8987-bt";
+	};
+};
+
+/* WIFI */
+&usdhc1 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc1>, <&pinctrl_wifi>;
+	pinctrl-1 = <&pinctrl_usdhc1_100mhz>, <&pinctrl_wifi>;
+	pinctrl-2 = <&pinctrl_usdhc1_200mhz>, <&pinctrl_wifi>;
+	bus-width = <4>;
+	non-removable;
+	keep-power-in-suspend;
+	mmc-pwrseq = <&iw61x_pwrseq>;
+	status = "okay";
+};
+
 /* eMMC */
 &usdhc3 {
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
@@ -222,6 +258,14 @@ &wdog1 {
 
 &iomuxc {
 
+	pinctrl_bluetooth: bluetoothgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_DATA7__GPIO2_IO09                              0xc0
+			MX8MP_IOMUXC_GPIO1_IO04__GPIO1_IO04                             0xc0
+			MX8MP_IOMUXC_SD1_RESET_B__GPIO2_IO10                            0xc0
+		>;
+	};
+
 	pinctrl_eqos: eqosgrp {
 		fsl,pins = <
 			MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC				0x2
@@ -256,6 +300,48 @@ MX8MP_IOMUXC_SPDIF_RX__GPIO5_IO04				0x1c0
 		>;
 	};
 
+	pinctrl_uart3: uart3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_ECSPI1_SCLK__UART3_DCE_RX                          0x140
+			MX8MP_IOMUXC_ECSPI1_MOSI__UART3_DCE_TX                          0x140
+			MX8MP_IOMUXC_ECSPI1_MISO__UART3_DCE_CTS                         0x140
+			MX8MP_IOMUXC_ECSPI1_SS0__UART3_DCE_RTS                          0x140
+		>;
+	};
+
+	pinctrl_usdhc1: usdhc1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK                                0x190
+			MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD                                0x1d0
+			MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0                            0x1d0
+			MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1                            0x1d0
+			MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2                            0x1d0
+			MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3                            0x1d0
+		>;
+	};
+
+	pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK                                0x194
+			MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD                                0x1d4
+			MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0                            0x1d4
+			MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1                            0x1d4
+			MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2                            0x1d4
+			MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3                            0x1d4
+		>;
+	};
+
+	pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK                                0x196
+			MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD                                0x1d6
+			MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0                            0x1d6
+			MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1                            0x1d6
+			MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2                            0x1d6
+			MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3                            0x1d6
+		>;
+	};
+
 	pinctrl_usdhc3: usdhc3grp {
 		fsl,pins = <
 			MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK				0x190
@@ -309,4 +395,11 @@ pinctrl_wdog: wdoggrp {
 			MX8MP_IOMUXC_GPIO1_IO02__WDOG1_WDOG_B				0xc6
 		>;
 	};
+
+	pinctrl_wifi: wifigrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_DATA6__GPIO2_IO08                              0xc0
+			MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19                            0xc0
+		>;
+	};
 };
-- 
2.47.3



From stefano.radaelli21 at gmail.com  Sat Dec 13 15:09:05 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Sun, 14 Dec 2025 00:09:05 +0100
Subject: [PATCH v2 5/6] arm64: dts: imx8mp-var-som: Add support for WM8904 audio codec
In-Reply-To: <20251213230909.16810-1-stefano.r@variscite.com>
References: <20251213230909.16810-1-stefano.r@variscite.com>
Message-ID: <20251213230909.16810-6-stefano.r@variscite.com>

The VAR-SOM-MX8MP can integrate the WM8904, a high-performance
ultra-low-power stereo codec optimized for portable audio applications.

This patch adds the WM8904 device to the appropriate I2C bus, enables
the SAI peripheral, and introduces the sound node to expose the
sound card to the system.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../boot/dts/freescale/imx8mp-var-som.dtsi    | 94 +++++++++++++++++++
 1 file changed, 94 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
index e7f5ec10cbac..169fc6a9c8cb 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
@@ -30,6 +30,14 @@ iw61x_pwrseq: wifi-pwrseq {
 		status = "okay";
 	};
 
+	reg_audio_supply: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "wm8904-supply";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
 	reg_phy_supply: regulator-phy-supply {
 		compatible = "regulator-fixed";
 		regulator-name = "phy-supply";
@@ -47,6 +55,34 @@ reg_phy_vddio: regulator-phy-vddio {
 		regulator-min-microvolt = <1800000>;
 		regulator-max-microvolt = <1800000>;
 	};
+
+	sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,bitclock-master = <&codec_dai>;
+		simple-audio-card,format = "i2s";
+		simple-audio-card,frame-master = <&codec_dai>;
+		simple-audio-card,mclk-fs = <256>;
+		simple-audio-card,name = "wm8904-audio";
+		simple-audio-card,routing =
+			"Headphone Jack", "HPOUTL",
+			"Headphone Jack", "HPOUTR",
+			"IN2L", "Line In Jack",
+			"IN2R", "Line In Jack",
+			"IN1L", "Microphone Jack",
+			"IN1R", "Microphone Jack";
+		simple-audio-card,widgets =
+			"Microphone", "Microphone Jack",
+			"Headphone", "Headphone Jack",
+			"Line", "Line In Jack";
+
+		codec_dai: simple-audio-card,codec {
+			sound-dai = <&wm8904>;
+		};
+
+		simple-audio-card,cpu {
+			sound-dai = <&sai3>;
+		};
+	};
 };
 
 &A53_0 {
@@ -209,6 +245,52 @@ ldo5: LDO5 {
 			};
 		};
 	};
+
+	wm8904: audio-codec at 1a {
+		compatible = "wlf,wm8904";
+		reg = <0x1a>;
+		#sound-dai-cells = <0>;
+		clocks = <&audio_blk_ctrl IMX8MP_CLK_AUDIOMIX_SAI3_MCLK1>;
+		clock-names = "mclk";
+		AVDD-supply = <&reg_audio_supply>;
+		CPVDD-supply = <&reg_audio_supply>;
+		DBVDD-supply = <&reg_audio_supply>;
+		DCVDD-supply = <&reg_audio_supply>;
+		MICVDD-supply = <&reg_audio_supply>;
+		wlf,drc-cfg-names = "default", "peaklimiter", "tradition",
+				    "soft", "music";
+		/*
+		 * Config registers per name, respectively:
+		 * KNEE_IP = 0,   KNEE_OP = 0,     HI_COMP = 1,   LO_COMP = 1
+		 * KNEE_IP = -24, KNEE_OP = -6,    HI_COMP = 1/4, LO_COMP = 1
+		 * KNEE_IP = -42, KNEE_OP = -3,    HI_COMP = 0,   LO_COMP = 1
+		 * KNEE_IP = -45, KNEE_OP = -9,    HI_COMP = 1/8, LO_COMP = 1
+		 * KNEE_IP = -30, KNEE_OP = -10.5, HI_COMP = 1/4, LO_COMP = 1
+		 */
+		wlf,drc-cfg-regs = /bits/ 16 <0x01af 0x3248 0x0000 0x0000>,
+				   /bits/ 16 <0x04af 0x324b 0x0010 0x0408>,
+				   /bits/ 16 <0x04af 0x324b 0x0028 0x0704>,
+				   /bits/ 16 <0x04af 0x324b 0x0018 0x078c>,
+				   /bits/ 16 <0x04af 0x324b 0x0010 0x050e>;
+		/* GPIO1 = DMIC_CLK, don't touch others */
+		wlf,gpio-cfg = <0x0018>, <0xffff>, <0xffff>, <0xffff>;
+	};
+};
+
+&sai3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_sai3>;
+	assigned-clocks = <&clk IMX8MP_CLK_SAI3>;
+	assigned-clock-parents = <&clk IMX8MP_AUDIO_PLL1_OUT>;
+	assigned-clock-rates = <11536000>;
+	clocks = <&audio_blk_ctrl IMX8MP_CLK_AUDIOMIX_SAI3_IPG>,
+		 <&clk IMX8MP_CLK_DUMMY>,
+		 <&audio_blk_ctrl IMX8MP_CLK_AUDIOMIX_SAI3_MCLK1>,
+		 <&clk IMX8MP_CLK_DUMMY>,
+		 <&clk IMX8MP_CLK_DUMMY>;
+	clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
+	fsl,sai-mclk-direction-output;
+	status = "okay";
 };
 
 /* BT */
@@ -300,6 +382,18 @@ MX8MP_IOMUXC_SPDIF_RX__GPIO5_IO04				0x1c0
 		>;
 	};
 
+	pinctrl_sai3: sai3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI3_TXFS__AUDIOMIX_SAI3_TX_SYNC                   0xd6
+			MX8MP_IOMUXC_SAI3_TXC__AUDIOMIX_SAI3_TX_BCLK                    0xd6
+			MX8MP_IOMUXC_SAI3_RXD__AUDIOMIX_SAI3_RX_DATA00                  0xd6
+			MX8MP_IOMUXC_SAI3_TXD__AUDIOMIX_SAI3_TX_DATA00                  0xd6
+			MX8MP_IOMUXC_SAI3_MCLK__AUDIOMIX_SAI3_MCLK                      0xd6
+			MX8MP_IOMUXC_SAI3_RXFS__AUDIOMIX_SAI3_RX_SYNC                   0xd6
+			MX8MP_IOMUXC_SAI3_RXC__AUDIOMIX_SAI3_RX_BCLK                    0xd6
+		>;
+	};
+
 	pinctrl_uart3: uart3grp {
 		fsl,pins = <
 			MX8MP_IOMUXC_ECSPI1_SCLK__UART3_DCE_RX                          0x140
-- 
2.47.3



From stefano.radaelli21 at gmail.com  Sat Dec 13 15:09:06 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Sun, 14 Dec 2025 00:09:06 +0100
Subject: [PATCH v2 6/6] arm64: dts: imx8mp-var-som: Add support for ADS7846 touchscreen
In-Reply-To: <20251213230909.16810-1-stefano.r@variscite.com>
References: <20251213230909.16810-1-stefano.r@variscite.com>
Message-ID: <20251213230909.16810-7-stefano.r@variscite.com>

The VAR-SOM-MX8MP integrates an ADS7846 resistive touchscreen controller.
The controller is physically located on the SOM, and its signals are
routed to the SOM pins, allowing carrier boards to make use of it.

This patch adds the ADS7846 node and the appropriate SPI controller.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../boot/dts/freescale/imx8mp-var-som.dtsi    | 46 +++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
index 169fc6a9c8cb..ebe615a84150 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
@@ -101,6 +101,37 @@ &A53_3 {
 	cpu-supply = <&buck2>;
 };
 
+&ecspi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi1>;
+	cs-gpios = <&gpio5 17 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	/* Resistive touch controller */
+	ads7846: touchscreen at 0 {
+		compatible = "ti,ads7846";
+		reg = <0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_restouch>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <12 IRQ_TYPE_EDGE_FALLING>;
+		spi-max-frequency = <1500000>;
+		pendown-gpio = <&gpio1 12 GPIO_ACTIVE_LOW>;
+		ti,x-min = /bits/ 16 <125>;
+		ti,x-max = /bits/ 16 <4008>;
+		ti,y-min = /bits/ 16 <282>;
+		ti,y-max = /bits/ 16 <3864>;
+		ti,x-plate-ohms = /bits/ 16 <180>;
+		ti,pressure-max = /bits/ 16 <255>;
+		ti,debounce-max = /bits/ 16 <10>;
+		ti,debounce-tol = /bits/ 16 <3>;
+		ti,debounce-rep = /bits/ 16 <1>;
+		ti,settle-delay-usec = /bits/ 16 <150>;
+		ti,keep-vref-on;
+		wakeup-source;
+	};
+};
+
 &eqos {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_eqos>;
@@ -348,6 +379,15 @@ MX8MP_IOMUXC_SD1_RESET_B__GPIO2_IO10                            0xc0
 		>;
 	};
 
+	pinctrl_ecspi1: ecspi1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C1_SCL__ECSPI1_SCLK                              0x12
+			MX8MP_IOMUXC_I2C1_SDA__ECSPI1_MOSI                              0x12
+			MX8MP_IOMUXC_I2C2_SCL__ECSPI1_MISO                              0x12
+			MX8MP_IOMUXC_I2C2_SDA__GPIO5_IO17                               0x12
+		>;
+	};
+
 	pinctrl_eqos: eqosgrp {
 		fsl,pins = <
 			MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC				0x2
@@ -382,6 +422,12 @@ MX8MP_IOMUXC_SPDIF_RX__GPIO5_IO04				0x1c0
 		>;
 	};
 
+	pinctrl_restouch: restouchgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO12__GPIO1_IO12                             0xc0
+		>;
+	};
+
 	pinctrl_sai3: sai3grp {
 		fsl,pins = <
 			MX8MP_IOMUXC_SAI3_TXFS__AUDIOMIX_SAI3_TX_SYNC                   0xd6
-- 
2.47.3



From krzk at kernel.org  Sat Dec 13 17:23:32 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sun, 14 Dec 2025 02:23:32 +0100
Subject: [PATCH v2 4/6] arm64: dts: imx8mp-var-som: Add WiFi and Bluetooth
 support
In-Reply-To: <20251213230909.16810-5-stefano.r@variscite.com>
References: <20251213230909.16810-1-stefano.r@variscite.com>
 <20251213230909.16810-5-stefano.r@variscite.com>
Message-ID: <d58e3cae-e303-4e1f-ab43-c800cf0ab2aa@kernel.org>

On 14/12/2025 00:09, Stefano Radaelli wrote:
> Add device tree nodes for the WiFi and Bluetooth module mounted on the
> VAR-SOM-MX8MP. The module can be based on either the NXP IW612 or IW611
> chipset, depending on the configuration chosen by the customer.
> 
> Regardless of the chipset used, WiFi communicates over SDIO and Bluetooth
> over UART.
> 
> Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
> ---
>  .../boot/dts/freescale/imx8mp-var-som.dtsi    | 93 +++++++++++++++++++
>  1 file changed, 93 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
> index 5bba91dcef17..e7f5ec10cbac 100644
> --- a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
> +++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
> @@ -21,6 +21,15 @@ memory at 40000000 {
>  		      <0x1 0x00000000 0 0xc0000000>;
>  	};
>  
> +	iw61x_pwrseq: wifi-pwrseq {
> +		compatible = "mmc-pwrseq-simple";
> +		post-power-on-delay-ms = <100>;
> +		power-off-delay-us = <10000>;
> +		reset-gpios = <&gpio2 8 GPIO_ACTIVE_LOW>, /* WIFI_RESET */
> +			      <&gpio2 19 GPIO_ACTIVE_LOW>; /* WIFI_PWR_EN */
> +		status = "okay";

Did you disable it anywhere before?


Best regards,
Krzysztof


From lkp at intel.com  Sat Dec 13 18:44:22 2025
From: lkp at intel.com (kernel test robot)
Date: Sun, 14 Dec 2025 10:44:22 +0800
Subject: [PATCH v21 3/7] firmware: imx: add driver for NXP EdgeLock
 Enclave
In-Reply-To: <20251212-imx-se-if-v21-3-ee7d6052d848@nxp.com>
References: <20251212-imx-se-if-v21-3-ee7d6052d848@nxp.com>
Message-ID: <202512141039.nVscnjzl-lkp@intel.com>

Hi Pankaj,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 4a26e7032d7d57c998598c08a034872d6f0d3945]

url:    https://github.com/intel-lab-lkp/linux/commits/Pankaj-Gupta/Documentation-firmware-add-imx-se-to-other_interfaces/20251212-172535
base:   4a26e7032d7d57c998598c08a034872d6f0d3945
patch link:    https://lore.kernel.org/r/20251212-imx-se-if-v21-3-ee7d6052d848%40nxp.com
patch subject: [PATCH v21 3/7] firmware: imx: add driver for NXP EdgeLock Enclave
config: powerpc-randconfig-r131-20251213 (https://download.01.org/0day-ci/archive/20251214/202512141039.nVscnjzl-lkp at intel.com/config)
compiler: powerpc-linux-gcc (GCC) 13.4.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251214/202512141039.nVscnjzl-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512141039.nVscnjzl-lkp at intel.com/

sparse warnings: (new ones prefixed by >>)
>> drivers/firmware/imx/ele_base_msg.c:77:52: sparse: sparse: non size-preserving pointer to integer cast

vim +77 drivers/firmware/imx/ele_base_msg.c

    16	
    17	int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info)
    18	{
    19		struct se_api_msg *tx_msg = NULL;
    20		struct se_api_msg *rx_msg = NULL;
    21		dma_addr_t get_info_addr = 0;
    22		u32 *get_info_data = NULL;
    23		int ret = 0;
    24	
    25		if (!priv)
    26			return -EINVAL;
    27	
    28		memset(s_info, 0x0, sizeof(*s_info));
    29	
    30		tx_msg = kzalloc(ELE_GET_INFO_REQ_MSG_SZ, GFP_KERNEL);
    31		if (!tx_msg)
    32			return -ENOMEM;
    33	
    34		rx_msg = kzalloc(ELE_GET_INFO_RSP_MSG_SZ, GFP_KERNEL);
    35		if (!rx_msg) {
    36			ret = -ENOMEM;
    37			goto exit;
    38		}
    39	
    40		if (priv->mem_pool)
    41			get_info_data = gen_pool_dma_alloc(priv->mem_pool,
    42							   ELE_GET_INFO_BUFF_SZ,
    43							   &get_info_addr);
    44		else
    45			get_info_data = dma_alloc_coherent(priv->dev,
    46							   ELE_GET_INFO_BUFF_SZ,
    47							   &get_info_addr,
    48							   GFP_KERNEL);
    49		if (!get_info_data) {
    50			dev_dbg(priv->dev,
    51				"%s: Failed to allocate get_info_addr.", __func__);
    52			ret = -ENOMEM;
    53			goto exit;
    54		}
    55	
    56		ret = se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
    57					  ELE_GET_INFO_REQ, ELE_GET_INFO_REQ_MSG_SZ,
    58					  true);
    59		if (ret)
    60			goto exit;
    61	
    62		tx_msg->data[0] = upper_32_bits(get_info_addr);
    63		tx_msg->data[1] = lower_32_bits(get_info_addr);
    64		tx_msg->data[2] = sizeof(*s_info);
    65		ret = ele_msg_send_rcv(priv, tx_msg, ELE_GET_INFO_REQ_MSG_SZ, rx_msg,
    66				       ELE_GET_INFO_RSP_MSG_SZ);
    67		if (ret < 0)
    68			goto exit;
    69	
    70		ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_GET_INFO_REQ,
    71					      ELE_GET_INFO_RSP_MSG_SZ, true);
    72	
    73		memcpy(s_info, get_info_data, sizeof(*s_info));
    74	
    75	exit:
    76		if (priv->mem_pool)
  > 77			gen_pool_free(priv->mem_pool, (u64)get_info_data,
    78				      ELE_GET_INFO_BUFF_SZ);
    79		else
    80			dma_free_coherent(priv->dev, ELE_GET_INFO_BUFF_SZ,
    81					  get_info_data, get_info_addr);
    82	
    83		kfree(tx_msg);
    84		kfree(rx_msg);
    85		return ret;
    86	}
    87	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From yeoreum.yun at arm.com  Sun Dec 14 01:13:47 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Sun, 14 Dec 2025 09:13:47 +0000
Subject: [PATCH 2/2] arm64: mmu: use pagetable_alloc_nolock() while
 stop_machine()
In-Reply-To: <CA+i-1C2e7QNTy5u=HF7tLsLXLq4xYbMTCbNjWGAxHz4uwgR05g@mail.gmail.com>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com>
 <20251212161832.2067134-3-yeoreum.yun@arm.com>
 <CA+i-1C2e7QNTy5u=HF7tLsLXLq4xYbMTCbNjWGAxHz4uwgR05g@mail.gmail.com>
Message-ID: <aT5/y3cSGIzi2K+m@e129823.arm.com>

Hi Brendan,

> On Sat, 13 Dec 2025 at 01:18, Yeoreum Yun <yeoreum.yun at arm.com> wrote:
> >
> > linear_map_split_to_ptes() and __kpti_install_ng_mappings()
> > are called as callback of stop_machine().
> > That means these functions context are preemption disabled.
> >
> > Unfortunately, under PREEMPT_RT, the pagetable_alloc() or
> > __get_free_pages() couldn't be called in this context
> > since spin lock that becomes sleepable on RT,
> > potentially causing a sleep during page allocation.
> >
> > To address this, pagetable_alloc_nolock().
> >
> > Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
> > ---
> >  arch/arm64/mm/mmu.c | 23 ++++++++++++++++++-----
> >  1 file changed, 18 insertions(+), 5 deletions(-)
> >
> > diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> > index 2ba01dc8ef82..0e98606d8c4c 100644
> > --- a/arch/arm64/mm/mmu.c
> > +++ b/arch/arm64/mm/mmu.c
> > @@ -475,10 +475,15 @@ static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys,
> >  static phys_addr_t __pgd_pgtable_alloc(struct mm_struct *mm, gfp_t gfp,
> >                                        enum pgtable_type pgtable_type)
> >  {
> > -       /* Page is zeroed by init_clear_pgtable() so don't duplicate effort. */
> > -       struct ptdesc *ptdesc = pagetable_alloc(gfp & ~__GFP_ZERO, 0);
> > +       struct ptdesc *ptdesc;
> >         phys_addr_t pa;
> >
> > +       /* Page is zeroed by init_clear_pgtable() so don't duplicate effort. */
> > +       if (gfpflags_allow_spinning(gfp))
> > +               ptdesc  = pagetable_alloc(gfp & ~__GFP_ZERO, 0);
> > +       else
> > +               ptdesc  = pagetable_alloc_nolock(gfp & ~__GFP_ZERO, 0);
> > +
> >         if (!ptdesc)
> >                 return INVALID_PHYS_ADDR;
> >
> > @@ -869,6 +874,7 @@ static int __init linear_map_split_to_ptes(void *__unused)
> >                 unsigned long kstart = (unsigned long)lm_alias(_stext);
> >                 unsigned long kend = (unsigned long)lm_alias(__init_begin);
> >                 int ret;
> > +               gfp_t gfp = IS_ENABLED(CONFIG_PREEMPT_RT) ? __GFP_HIGH : GFP_ATOMIC;
> >
> >                 /*
> >                  * Wait for all secondary CPUs to be put into the waiting area.
> > @@ -881,9 +887,9 @@ static int __init linear_map_split_to_ptes(void *__unused)
> >                  * PTE. The kernel alias remains static throughout runtime so
> >                  * can continue to be safely mapped with large mappings.
> >                  */
> > -               ret = range_split_to_ptes(lstart, kstart, GFP_ATOMIC);
> > +               ret = range_split_to_ptes(lstart, kstart, gfp);
> >                 if (!ret)
> > -                       ret = range_split_to_ptes(kend, lend, GFP_ATOMIC);
> > +                       ret = range_split_to_ptes(kend, lend, gfp);
> >                 if (ret)
> >                         panic("Failed to split linear map\n");
> >                 flush_tlb_kernel_range(lstart, lend);
> > @@ -1207,7 +1213,14 @@ static int __init __kpti_install_ng_mappings(void *__unused)
> >         remap_fn = (void *)__pa_symbol(idmap_kpti_install_ng_mappings);
> >
> >         if (!cpu) {
> > -               alloc = __get_free_pages(GFP_ATOMIC | __GFP_ZERO, order);
> > +               if (IS_ENABLED(CONFIG_PREEMPT_RT))
> > +                       alloc = (u64) pagetable_alloc_nolock(__GFP_HIGH | __GFP_ZERO, order);
> > +               else
> > +                       alloc = __get_free_pages(GFP_ATOMIC | __GFP_ZERO, order);
> > +
> > +               if (!alloc)
> > +                       panic("Failed to alloc kpti_ng_pgd\n");
> > +
>
> I don't have the context on what this code is doing so take this with
> a grain of salt, but...
>
> The point of the _nolock alloc is to give the allocator an excuse to
> fail. Panicking on that failure doesn't seem like a great idea to me?

I thought first whether it changes to "static" memory area to handle
this in PREEMPT_RT.
But since this function is called while smp_cpus_done().
So, I think it's fine since there wouldn't be a contention for
memory allocation in this phase.

Thanks.

--
Sincerely,
Yeoreum Yun


From lorenzo at kernel.org  Sun Dec 14 01:30:07 2025
From: lorenzo at kernel.org (Lorenzo Bianconi)
Date: Sun, 14 Dec 2025 10:30:07 +0100
Subject: [PATCH net] net: airoha: Move net_devs registration in a dedicated
 routine
Message-ID: <20251214-airoha-fix-dev-registration-v1-1-860e027ad4c6@kernel.org>

Since airoha_probe() is not executed under rtnl lock, there is small race
where a given device is configured by user-space while the remaining ones
are not completely loaded from the dts yet. This condition will allow a
hw device misconfiguration since there are some conditions (e.g. GDM2 check
in airoha_dev_init()) that require all device are properly loaded from the
device tree. Fix the issue moving net_devices registration at the end of
the airoha_probe routine.

Fixes: 9cd451d414f6e ("net: airoha: Add loopback support for GDM2")
Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
---
 drivers/net/ethernet/airoha/airoha_eth.c | 39 +++++++++++++++++++++-----------
 1 file changed, 26 insertions(+), 13 deletions(-)

diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 75893c90a0a17c528c27fc0e986de194e7736637..315d97036ac1d611cc786020cbf2c6df810995a9 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -2924,19 +2924,26 @@ static int airoha_alloc_gdm_port(struct airoha_eth *eth,
 	port->id = id;
 	eth->ports[p] = port;
 
-	err = airoha_metadata_dst_alloc(port);
-	if (err)
-		return err;
+	return airoha_metadata_dst_alloc(port);
+}
 
-	err = register_netdev(dev);
-	if (err)
-		goto free_metadata_dst;
+static int airoha_register_gdm_devices(struct airoha_eth *eth)
+{
+	int i;
 
-	return 0;
+	for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
+		struct airoha_gdm_port *port = eth->ports[i];
+		int err;
 
-free_metadata_dst:
-	airoha_metadata_dst_free(port);
-	return err;
+		if (!port)
+			continue;
+
+		err = register_netdev(port->dev);
+		if (err)
+			return err;
+	}
+
+	return 0;
 }
 
 static int airoha_probe(struct platform_device *pdev)
@@ -3027,6 +3034,10 @@ static int airoha_probe(struct platform_device *pdev)
 		}
 	}
 
+	err = airoha_register_gdm_devices(eth);
+	if (err)
+		goto error_napi_stop;
+
 	return 0;
 
 error_napi_stop:
@@ -3040,10 +3051,12 @@ static int airoha_probe(struct platform_device *pdev)
 	for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
 		struct airoha_gdm_port *port = eth->ports[i];
 
-		if (port && port->dev->reg_state == NETREG_REGISTERED) {
+		if (!port)
+			continue;
+
+		if (port->dev->reg_state == NETREG_REGISTERED)
 			unregister_netdev(port->dev);
-			airoha_metadata_dst_free(port);
-		}
+		airoha_metadata_dst_free(port);
 	}
 	free_netdev(eth->napi_dev);
 	platform_set_drvdata(pdev, NULL);

---
base-commit: 8f7aa3d3c7323f4ca2768a9e74ebbe359c4f8f88
change-id: 20251214-airoha-fix-dev-registration-c3a114d58416

Best regards,
-- 
Lorenzo Bianconi <lorenzo at kernel.org>



From lorenzo at kernel.org  Sun Dec 14 01:55:30 2025
From: lorenzo at kernel.org (Lorenzo Bianconi)
Date: Sun, 14 Dec 2025 10:55:30 +0100
Subject: [PATCH mt76] wifi: mt76: mt7996: Reset ampdu_state state in case
 of failure in mt7996_tx_check_aggr()
Message-ID: <20251214-mt7996-aggr-check-fix-v1-1-33a8b62ec0fc@kernel.org>

Reset the ampdu_state configured state if ieee80211_start_tx_ba_session
routine fails in mt7996_tx_check_aggr()

Fixes: 98686cd21624c ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices")
Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
---
 drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
index 2560e2f46e89a4bc46e21d796fca80b7decefa5c..b265a96c3e925233d1c410a26315efe56bde73b1 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
@@ -1269,8 +1269,9 @@ mt7996_tx_check_aggr(struct ieee80211_link_sta *link_sta,
 	if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)))
 		return;
 
-	if (!test_and_set_bit(tid, &wcid->ampdu_state))
-		ieee80211_start_tx_ba_session(link_sta->sta, tid, 0);
+	if (!test_and_set_bit(tid, &wcid->ampdu_state) &&
+	    ieee80211_start_tx_ba_session(link_sta->sta, tid, 0))
+		clear_bit(tid, &wcid->ampdu_state);
 }
 
 static void

---
base-commit: 53d1548612670aa8b5d89745116cc33d9d172863
change-id: 20251214-mt7996-aggr-check-fix-8379634f9b54

Best regards,
-- 
Lorenzo Bianconi <lorenzo at kernel.org>



From broonie at kernel.org  Sun Dec 14 02:34:24 2025
From: broonie at kernel.org (Mark Brown)
Date: Sun, 14 Dec 2025 19:34:24 +0900
Subject: [PATCH v7 07/10] ASoC: mediatek: mt8196: add platform driver
In-Reply-To: <20250822125301.12333-8-darren.ye@mediatek.com>
References: <20250822125301.12333-1-darren.ye@mediatek.com>
 <20250822125301.12333-8-darren.ye@mediatek.com>
Message-ID: <aT6SsKEGK553Xg5i@sirena.co.uk>

On Fri, Aug 22, 2025 at 08:52:36PM +0800, Darren.Ye wrote:
> From: Darren Ye <darren.ye at mediatek.com>
> 
> Add mt8196 platform driver.

This doesn't apply against current code, please check and resend.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251214/1f0b25ee/attachment.sig>

From linux at fw-web.de  Sun Dec 14 03:03:02 2025
From: linux at fw-web.de (Frank Wunderlich)
Date: Sun, 14 Dec 2025 12:03:02 +0100
Subject: [RFC net-next v3 1/3] net: ethernet: mtk_eth_soc: Add register definitions for RSS and LRO
In-Reply-To: <20251214110310.7009-1-linux@fw-web.de>
References: <20251214110310.7009-1-linux@fw-web.de>
Message-ID: <20251214110310.7009-2-linux@fw-web.de>

From: Mason Chang <mason-cw.chang at mediatek.com>

Add definitions for Receive Side Scaling and Large Receive Offload support.

Signed-off-by: Mason Chang <mason-cw.chang at mediatek.com>
Signed-off-by: Frank Wunderlich <frank-w at public-files.de>
---
 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 23 +++++++++++++++
 drivers/net/ethernet/mediatek/mtk_eth_soc.h | 32 +++++++++++++++------
 2 files changed, 46 insertions(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index e68997a29191..243ff16fd15e 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -50,13 +50,18 @@ static const struct mtk_reg_map mtk_reg_map = {
 		.rx_ptr		= 0x0900,
 		.rx_cnt_cfg	= 0x0904,
 		.pcrx_ptr	= 0x0908,
+		.lro_ctrl_dw0   = 0x0980,
 		.glo_cfg	= 0x0a04,
 		.rst_idx	= 0x0a08,
 		.delay_irq	= 0x0a0c,
 		.irq_status	= 0x0a20,
 		.irq_mask	= 0x0a28,
 		.adma_rx_dbg0	= 0x0a38,
+		.lro_alt_score_delta	= 0x0a4c,
 		.int_grp	= 0x0a50,
+		.lro_rx1_dly_int	= 0x0a70,
+		.lro_ring_dip_dw0	= 0x0b04,
+		.lro_ring_ctrl_dw1	= 0x0b28,
 	},
 	.qdma = {
 		.qtx_cfg	= 0x1800,
@@ -113,6 +118,7 @@ static const struct mtk_reg_map mt7986_reg_map = {
 	.tx_irq_mask		= 0x461c,
 	.tx_irq_status		= 0x4618,
 	.pdma = {
+		.rss_glo_cfg    = 0x2800,
 		.rx_ptr		= 0x4100,
 		.rx_cnt_cfg	= 0x4104,
 		.pcrx_ptr	= 0x4108,
@@ -123,6 +129,12 @@ static const struct mtk_reg_map mt7986_reg_map = {
 		.irq_mask	= 0x4228,
 		.adma_rx_dbg0	= 0x4238,
 		.int_grp	= 0x4250,
+		.int_grp3	= 0x422c,
+		.lro_ctrl_dw0	= 0x4180,
+		.lro_alt_score_delta	= 0x424c,
+		.lro_rx1_dly_int	= 0x4270,
+		.lro_ring_dip_dw0	= 0x4304,
+		.lro_ring_ctrl_dw1	= 0x4328,
 	},
 	.qdma = {
 		.qtx_cfg	= 0x4400,
@@ -170,10 +182,21 @@ static const struct mtk_reg_map mt7988_reg_map = {
 		.glo_cfg	= 0x6a04,
 		.rst_idx	= 0x6a08,
 		.delay_irq	= 0x6a0c,
+		.rx_cfg		= 0x6a10,
 		.irq_status	= 0x6a20,
 		.irq_mask	= 0x6a28,
 		.adma_rx_dbg0	= 0x6a38,
 		.int_grp	= 0x6a50,
+		.int_grp3	= 0x6a58,
+		.tx_delay_irq	= 0x6ab0,
+		.rx_delay_irq	= 0x6ac0,
+		.lro_ctrl_dw0	= 0x6c08,
+		.lro_alt_score_delta	= 0x6c1c,
+		.lro_ring_dip_dw0	= 0x6c14,
+		.lro_ring_ctrl_dw1	= 0x6c38,
+		.lro_alt_dbg	= 0x6c40,
+		.lro_alt_dbg_data	= 0x6c44,
+		.rss_glo_cfg	= 0x7000,
 	},
 	.qdma = {
 		.qtx_cfg	= 0x4400,
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index 0168e2fbc619..334625814b97 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -1143,16 +1143,30 @@ struct mtk_reg_map {
 	u32	tx_irq_mask;
 	u32	tx_irq_status;
 	struct {
-		u32	rx_ptr;		/* rx base pointer */
-		u32	rx_cnt_cfg;	/* rx max count configuration */
-		u32	pcrx_ptr;	/* rx cpu pointer */
-		u32	glo_cfg;	/* global configuration */
-		u32	rst_idx;	/* reset index */
-		u32	delay_irq;	/* delay interrupt */
-		u32	irq_status;	/* interrupt status */
-		u32	irq_mask;	/* interrupt mask */
+		u32	rx_ptr;			/* rx base pointer */
+		u32	rx_cnt_cfg;		/* rx max count configuration */
+		u32	pcrx_ptr;		/* rx cpu pointer */
+		u32	pdrx_ptr;		/* rx dma pointer */
+		u32	glo_cfg;		/* global configuration */
+		u32	rst_idx;		/* reset index */
+		u32	rx_cfg;			/* rx dma configuration */
+		u32	delay_irq;		/* delay interrupt */
+		u32	irq_status;		/* interrupt status */
+		u32	irq_mask;		/* interrupt mask */
 		u32	adma_rx_dbg0;
-		u32	int_grp;
+		u32	int_grp;		/* interrupt group1 */
+		u32	int_grp3;		/* interrupt group3 */
+		u32	tx_delay_irq;		/* tx delay interrupt */
+		u32	rx_delay_irq;		/* rx delay interrupt */
+		u32	lro_ctrl_dw0;		/* lro ctrl dword0 */
+		u32	lro_alt_score_delta;	/* lro auto-learn score delta */
+		u32	lro_rx1_dly_int;	/* lro rx ring1 delay interrupt */
+		u32	lro_ring_dip_dw0;	/* lro ring dip dword0 */
+		u32	lro_ring_ctrl_dw1;	/* lro ring ctrl dword1 */
+		u32	lro_alt_dbg;		/* lro auto-learn debug */
+		u32	lro_alt_dbg_data;	/* lro auto-learn debug data */
+		u32	rss_glo_cfg;		/* rss global configuration */
+
 	} pdma;
 	struct {
 		u32	qtx_cfg;	/* tx queue configuration */
-- 
2.43.0



From linux at fw-web.de  Sun Dec 14 03:03:01 2025
From: linux at fw-web.de (Frank Wunderlich)
Date: Sun, 14 Dec 2025 12:03:01 +0100
Subject: [RFC net-next v3 0/3] Add RSS and LRO support
Message-ID: <20251214110310.7009-1-linux@fw-web.de>

From: Frank Wunderlich <frank-w at public-files.de>

This series add RSS and LRO hardware acceleration for terminating
traffic on MT798x.

It is currently only for discussion to get the upported SDK driver
changes in a good shape.

patches are upported from mtk SDK:
- https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/refs/heads/master/master/files/target/linux/mediatek/patches-6.12/999-eth-08-mtk_eth_soc-add-register-definitions-for-rss-lro-reg.patch
- https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/refs/heads/master/master/files/target/linux/mediatek/patches-6.12/999-eth-09-mtk_eth_soc-add-rss-support.patch
- https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/refs/heads/master/master/files/target/linux/mediatek/patches-6.12/999-eth-10-mtk_eth_soc-add-hw-lro-support.patch
with additional fixes

changes:
v3:
- readded the change dropped in v2 because it was a fix
  for getting RSS working on mt7986
- changes requested by jakub
- reworked coverletter (dropped instructions for configuration)
- name all PDMA-IRQ the same way
- retested on
  - BPI-R3/mt7986 (RSS needs to be enabled)
  - BPI-R4/mt7988
  - BPI-R64/mt7622 and BPI-R2/mt7623 for not breaking network functionality

v2:
- drop wrong change (MTK_CDMP_IG_CTRL is only netsys v1)
- Fix immutable string IRQ setup (thx to Emilia Schotte)
- drop links to 6.6 patches/commits in sdk in comments

Mason Chang (3):
  net: ethernet: mtk_eth_soc: Add register definitions for RSS and LRO
  net: ethernet: mtk_eth_soc: Add RSS support
  net: ethernet: mtk_eth_soc: Add LRO support

 bpi-r4.its                                  |  16 +-
 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 762 ++++++++++++++++----
 drivers/net/ethernet/mediatek/mtk_eth_soc.h | 171 +++--
 3 files changed, 757 insertions(+), 192 deletions(-)

-- 
2.43.0



From linux at fw-web.de  Sun Dec 14 03:03:03 2025
From: linux at fw-web.de (Frank Wunderlich)
Date: Sun, 14 Dec 2025 12:03:03 +0100
Subject: [RFC net-next v3 2/3] net: ethernet: mtk_eth_soc: Add RSS support
In-Reply-To: <20251214110310.7009-1-linux@fw-web.de>
References: <20251214110310.7009-1-linux@fw-web.de>
Message-ID: <20251214110310.7009-3-linux@fw-web.de>

From: Mason Chang <mason-cw.chang at mediatek.com>

Add support for Receive Side Scaling.

We can adjust SMP affinity with the following command:
echo [CPU bitmap num] > /proc/irq/[virtual IRQ ID]/smp_affinity,
with interrupts evenly assigned to 4 CPUs, we were able to measure
an RX throughput of 7.3Gbps using iperf3 on the MT7988. Further
optimizations will be carried out in the future.

The experimental command is as follows:
PC: iperf3 -c [IP] -P 10
DUT: iperf3 -s

The entire indirection table can be imagined as 128 buckets, we
can use the ethtool command to mark which RX ring we want to send
the packets in these buckets to.

Show RSS RX ring parameters in indirection table and RSS hash key:
ethtool -x [interface]
Change RSS RX rings weight under uniform distribution:
ethtool --set-rxfh-indir [interface] equal [ring num]
Change RSS RX rings weight under non-uniform distribution:
ethtool --set-rxfh-indir [interface] weight [ring0 weight]
[ring1 weight] [ring2 weight] [ring3 weight]

Signed-off-by: Mason Chang <mason-cw.chang at mediatek.com>
Signed-off-by: Frank Wunderlich <frank-w at public-files.de>
---
v3:
- changes requested by jakub
- readded rss fix for mt7986
- name all PDMA-IRQ the same way

v2:
- drop wrong change (MTK_CDMP_IG_CTRL is only netsys v1)
- Fix immutable string IRQ setup (thx to Emilia Schotte)
- drop link to no more existent 6.6 patch in comment
---
 bpi-r4.its                                  |  16 +-
 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 526 +++++++++++++++-----
 drivers/net/ethernet/mediatek/mtk_eth_soc.h |  95 +++-
 3 files changed, 492 insertions(+), 145 deletions(-)

diff --git a/bpi-r4.its b/bpi-r4.its
index d5d9c494373e..d3b666e0a46f 100644
--- a/bpi-r4.its
+++ b/bpi-r4.its
@@ -40,7 +40,7 @@
 				algo = "sha1";
 			};
 		};
-		fdt-base-r4pro-4e {
+		/*fdt-base-r4pro-4e {
 			description = "Flattened Device Tree blob BPI-R4 Pro 4E";
 			data = /incbin/("./arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-4e.dtb");
 			type = "flat_dt";
@@ -72,7 +72,7 @@
 			hash-1 {
 				algo = "sha1";
 			};
-		};
+		};*/
 		fdt-ov-sd {
 			description = "Flattened Device Tree blob";
 			data = /incbin/("./arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-sd.dtbo");
@@ -83,7 +83,7 @@
 			data = /incbin/("./arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-emmc.dtbo");
 			type = "flat_dt";
 		};
-		fdt-ov-lite-sd {
+		/*fdt-ov-lite-sd {
 			description = "Flattened Device Tree blob";
 			data = /incbin/("./arch/arm64/boot/dts/mediatek/mt7987a-bananapi-bpi-r4-lite-sd.dtbo");
 			type = "flat_dt";
@@ -132,7 +132,7 @@
 			description = "DT overlay for R4Pro EMMC";
 			data = /incbin/("./arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-emmc.dtbo");
 			type = "flat_dt";
-		};
+		};*/
 /*		ramdisk-1 {
 			description = "ramdisk";
 			data = /incbin/("./rootfs_arm64.cpio.gz");
@@ -165,7 +165,7 @@
 				algo = "sha1";
 			};
 		};
-		conf-base-r4pro {
+		/*conf-base-r4pro {
 			description = "Boot Linux kernel with base FDT blob for BPI-R4 Pro";
 			kernel = "kernel-1";
 			fdt = "fdt-base-r4pro-8x";
@@ -200,7 +200,7 @@
 			hash-1 {
 				algo = "sha1";
 			};
-		};
+		};*/
 		conf-sd {
 			description = "Boot Linux kernel with SD FDT blob";
 			kernel = "kernel-1";
@@ -227,7 +227,7 @@
 			description = "EMMC FDT overlay blob for R4";
 			fdt = "fdt-ov-emmc";
 		};
-		ov-lite-sd {
+		/*ov-lite-sd {
 			description = "SD FDT overlay blob for R4 Lite";
 			fdt = "fdt-ov-lite-sd";
 		};
@@ -266,6 +266,6 @@
 		ov-pro-cn18 {
 			description = "CN18 FDT overlay blob for R4 Pro";
 			fdt = "fdt-ov-pro-cn18";
-		};
+		};*/
 	};
 };
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 243ff16fd15e..b27b8b8b05f6 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -1275,6 +1275,7 @@ static bool mtk_rx_get_desc(struct mtk_eth *eth, struct mtk_rx_dma_v2 *rxd,
 	if (mtk_is_netsys_v3_or_greater(eth)) {
 		rxd->rxd5 = READ_ONCE(dma_rxd->rxd5);
 		rxd->rxd6 = READ_ONCE(dma_rxd->rxd6);
+		rxd->rxd7 = READ_ONCE(dma_rxd->rxd7);
 	}
 
 	return true;
@@ -1842,47 +1843,9 @@ static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	return NETDEV_TX_OK;
 }
 
-static struct mtk_rx_ring *mtk_get_rx_ring(struct mtk_eth *eth)
+static void mtk_update_rx_cpu_idx(struct mtk_eth *eth, struct mtk_rx_ring *ring)
 {
-	int i;
-	struct mtk_rx_ring *ring;
-	int idx;
-
-	if (!eth->hwlro)
-		return &eth->rx_ring[0];
-
-	for (i = 0; i < MTK_MAX_RX_RING_NUM; i++) {
-		struct mtk_rx_dma *rxd;
-
-		ring = &eth->rx_ring[i];
-		idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size);
-		rxd = ring->dma + idx * eth->soc->rx.desc_size;
-		if (rxd->rxd2 & RX_DMA_DONE) {
-			ring->calc_idx_update = true;
-			return ring;
-		}
-	}
-
-	return NULL;
-}
-
-static void mtk_update_rx_cpu_idx(struct mtk_eth *eth)
-{
-	struct mtk_rx_ring *ring;
-	int i;
-
-	if (!eth->hwlro) {
-		ring = &eth->rx_ring[0];
-		mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg);
-	} else {
-		for (i = 0; i < MTK_MAX_RX_RING_NUM; i++) {
-			ring = &eth->rx_ring[i];
-			if (ring->calc_idx_update) {
-				ring->calc_idx_update = false;
-				mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg);
-			}
-		}
-	}
+	mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg);
 }
 
 static bool mtk_page_pool_enabled(struct mtk_eth *eth)
@@ -1913,7 +1876,7 @@ static struct page_pool *mtk_create_page_pool(struct mtk_eth *eth,
 		return pp;
 
 	err = __xdp_rxq_info_reg(xdp_q, eth->dummy_dev, id,
-				 eth->rx_napi.napi_id, PAGE_SIZE);
+				 eth->rx_napi[id].napi.napi_id, PAGE_SIZE);
 	if (err < 0)
 		goto err_free_pp;
 
@@ -2202,7 +2165,8 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
 		       struct mtk_eth *eth)
 {
 	struct dim_sample dim_sample = {};
-	struct mtk_rx_ring *ring;
+	struct mtk_napi *rx_napi = container_of(napi, struct mtk_napi, napi);
+	struct mtk_rx_ring *ring = rx_napi->rx_ring;
 	bool xdp_flush = false;
 	int idx;
 	struct sk_buff *skb;
@@ -2213,16 +2177,15 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
 	dma_addr_t dma_addr = DMA_MAPPING_ERROR;
 	int ppe_idx = 0;
 
+	if (unlikely(!ring))
+		goto rx_done;
+
 	while (done < budget) {
 		unsigned int pktlen, *rxdcsum;
 		struct net_device *netdev;
 		u32 hash, reason;
 		int mac = 0;
 
-		ring = mtk_get_rx_ring(eth);
-		if (unlikely(!ring))
-			goto rx_done;
-
 		idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size);
 		rxd = ring->dma + idx * eth->soc->rx.desc_size;
 		data = ring->data[idx];
@@ -2414,7 +2377,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
 		 * we continue
 		 */
 		wmb();
-		mtk_update_rx_cpu_idx(eth);
+		mtk_update_rx_cpu_idx(eth, ring);
 	}
 
 	eth->rx_packets += done;
@@ -2623,7 +2586,9 @@ static int mtk_napi_tx(struct napi_struct *napi, int budget)
 
 static int mtk_napi_rx(struct napi_struct *napi, int budget)
 {
-	struct mtk_eth *eth = container_of(napi, struct mtk_eth, rx_napi);
+	struct mtk_napi *rx_napi = container_of(napi, struct mtk_napi, napi);
+	struct mtk_eth *eth = rx_napi->eth;
+	struct mtk_rx_ring *ring = rx_napi->rx_ring;
 	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
 	int rx_done_total = 0;
 
@@ -2632,7 +2597,7 @@ static int mtk_napi_rx(struct napi_struct *napi, int budget)
 	do {
 		int rx_done;
 
-		mtk_w32(eth, eth->soc->rx.irq_done_mask,
+		mtk_w32(eth, MTK_RX_DONE_INT(ring->ring_no),
 			reg_map->pdma.irq_status);
 		rx_done = mtk_poll_rx(napi, budget - rx_done_total, eth);
 		rx_done_total += rx_done;
@@ -2648,10 +2613,10 @@ static int mtk_napi_rx(struct napi_struct *napi, int budget)
 			return budget;
 
 	} while (mtk_r32(eth, reg_map->pdma.irq_status) &
-		 eth->soc->rx.irq_done_mask);
+		 MTK_RX_DONE_INT(ring->ring_no));
 
 	if (napi_complete_done(napi, rx_done_total))
-		mtk_rx_irq_enable(eth, eth->soc->rx.irq_done_mask);
+		mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(ring->ring_no));
 
 	return rx_done_total;
 }
@@ -2897,6 +2862,7 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag)
 	else
 		ring->crx_idx_reg = reg_map->pdma.pcrx_ptr +
 				    ring_no * MTK_QRX_OFFSET;
+	ring->ring_no = ring_no;
 	/* make sure that all changes to the dma ring are flushed before we
 	 * continue
 	 */
@@ -2965,6 +2931,7 @@ static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring, bool in_
 
 static int mtk_hwlro_rx_init(struct mtk_eth *eth)
 {
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
 	int i;
 	u32 ring_ctrl_dw1 = 0, ring_ctrl_dw2 = 0, ring_ctrl_dw3 = 0;
 	u32 lro_ctrl_dw0 = 0, lro_ctrl_dw3 = 0;
@@ -3025,6 +2992,7 @@ static int mtk_hwlro_rx_init(struct mtk_eth *eth)
 
 static void mtk_hwlro_rx_uninit(struct mtk_eth *eth)
 {
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
 	int i;
 	u32 val;
 
@@ -3051,6 +3019,7 @@ static void mtk_hwlro_rx_uninit(struct mtk_eth *eth)
 
 static void mtk_hwlro_val_ipaddr(struct mtk_eth *eth, int idx, __be32 ip)
 {
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
 	u32 reg_val;
 
 	reg_val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(idx));
@@ -3066,6 +3035,7 @@ static void mtk_hwlro_val_ipaddr(struct mtk_eth *eth, int idx, __be32 ip)
 
 static void mtk_hwlro_inval_ipaddr(struct mtk_eth *eth, int idx)
 {
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
 	u32 reg_val;
 
 	reg_val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(idx));
@@ -3201,6 +3171,105 @@ static int mtk_hwlro_get_fdir_all(struct net_device *dev,
 	return 0;
 }
 
+static u32 mtk_rss_indr_table(struct mtk_rss_params *rss_params, int index)
+{
+	u32 val = 0;
+	int i;
+
+	for (i = 16 * index; i < 16 * index + 16; i++)
+		val |= (rss_params->indirection_table[i] << (2 * (i % 16)));
+
+	return val;
+}
+
+static int mtk_rss_init(struct mtk_eth *eth)
+{
+	const struct mtk_soc_data *soc = eth->soc;
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
+	struct mtk_rss_params *rss_params = &eth->rss_params;
+	u32 val;
+	int i;
+
+	netdev_rss_key_fill(rss_params->hash_key, MTK_RSS_HASH_KEYSIZE);
+
+	for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE; i++)
+		rss_params->indirection_table[i] = ethtool_rxfh_indir_default(i, eth->soc->rss_num);
+
+	if (soc->rx.desc_size == sizeof(struct mtk_rx_dma)) {
+		/* Set RSS rings to PSE modes */
+		for (i = 1; i <= MTK_HW_LRO_RING_NUM; i++) {
+			val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(i));
+			val |= MTK_RING_PSE_MODE;
+			mtk_w32(eth, val, MTK_LRO_CTRL_DW2_CFG(i));
+		}
+
+		/* Enable non-lro multiple rx */
+		val = mtk_r32(eth, reg_map->pdma.lro_ctrl_dw0);
+		val |= MTK_NON_LRO_MULTI_EN;
+		mtk_w32(eth, val, reg_map->pdma.lro_ctrl_dw0);
+
+		/* Enable RSS dly int supoort */
+		val |= MTK_LRO_DLY_INT_EN;
+		mtk_w32(eth, val, reg_map->pdma.lro_ctrl_dw0);
+	}
+
+	/* Hash Type */
+	val = mtk_r32(eth, reg_map->pdma.rss_glo_cfg);
+	val |= MTK_RSS_IPV4_STATIC_HASH;
+	val |= MTK_RSS_IPV6_STATIC_HASH;
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+	/* Hash Key */
+	for (i = 0; i < MTK_RSS_HASH_KEYSIZE / sizeof(u32); i++)
+		mtk_w32(eth, rss_params->hash_key[i], MTK_RSS_HASH_KEY_DW(i));
+
+	/* Select the size of indirection table */
+	for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE / 16; i++)
+		mtk_w32(eth, mtk_rss_indr_table(rss_params, i),
+			MTK_RSS_INDR_TABLE_DW(i));
+
+	/* Pause */
+	val |= MTK_RSS_CFG_REQ;
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+	/* Enable RSS */
+	val |= MTK_RSS_EN;
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+	/* Release pause */
+	val &= ~(MTK_RSS_CFG_REQ);
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+	/* Set perRSS GRP INT */
+	mtk_m32(eth, MTK_RX_DONE_INT(MTK_RSS_RING(1)),
+		MTK_RX_DONE_INT(MTK_RSS_RING(1)), reg_map->pdma.int_grp);
+	mtk_m32(eth, MTK_RX_DONE_INT(MTK_RSS_RING(2)),
+		MTK_RX_DONE_INT(MTK_RSS_RING(2)), reg_map->pdma.int_grp + 0x4);
+	mtk_m32(eth, MTK_RX_DONE_INT(MTK_RSS_RING(3)),
+		MTK_RX_DONE_INT(MTK_RSS_RING(3)), reg_map->pdma.int_grp3);
+
+	return 0;
+}
+
+static void mtk_rss_uninit(struct mtk_eth *eth)
+{
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
+	u32 val;
+
+	/* Pause */
+	val = mtk_r32(eth, reg_map->pdma.rss_glo_cfg);
+	val |= MTK_RSS_CFG_REQ;
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+	/* Disable RSS */
+	val &= ~(MTK_RSS_EN);
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+	/* Release pause */
+	val &= ~(MTK_RSS_CFG_REQ);
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+}
+
 static netdev_features_t mtk_fix_features(struct net_device *dev,
 					  netdev_features_t features)
 {
@@ -3291,6 +3360,17 @@ static int mtk_dma_init(struct mtk_eth *eth)
 			return err;
 	}
 
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		for (i = 1; i < MTK_RX_RSS_NUM; i++) {
+			err = mtk_rx_alloc(eth, MTK_RSS_RING(i), MTK_RX_FLAGS_NORMAL);
+			if (err)
+				return err;
+		}
+		err = mtk_rss_init(eth);
+		if (err)
+			return err;
+	}
+
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {
 		/* Enable random early drop and set drop threshold
 		 * automatically
@@ -3337,6 +3417,12 @@ static void mtk_dma_free(struct mtk_eth *eth)
 			mtk_rx_clean(eth, &eth->rx_ring[i], false);
 	}
 
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		mtk_rss_uninit(eth);
+		for (i = 1; i < MTK_RX_RSS_NUM; i++)
+			mtk_rx_clean(eth, &eth->rx_ring[MTK_RSS_RING(i)], true);
+	}
+
 	for (i = 0; i < DIV_ROUND_UP(soc->tx.fq_dma_size, MTK_FQ_DMA_LENGTH); i++) {
 		kfree(eth->scratch_head[i]);
 		eth->scratch_head[i] = NULL;
@@ -3369,23 +3455,23 @@ static void mtk_tx_timeout(struct net_device *dev, unsigned int txqueue)
 	schedule_work(&eth->pending_work);
 }
 
-static int mtk_get_irqs(struct platform_device *pdev, struct mtk_eth *eth)
+static int mtk_get_irqs_fe(struct platform_device *pdev, struct mtk_eth *eth)
 {
 	int i;
 
 	/* future SoCs beginning with MT7988 should use named IRQs in dts */
-	eth->irq[MTK_FE_IRQ_TX] = platform_get_irq_byname_optional(pdev, "fe1");
-	eth->irq[MTK_FE_IRQ_RX] = platform_get_irq_byname_optional(pdev, "fe2");
-	if (eth->irq[MTK_FE_IRQ_TX] >= 0 && eth->irq[MTK_FE_IRQ_RX] >= 0)
+	eth->irq_fe[MTK_FE_IRQ_TX] = platform_get_irq_byname_optional(pdev, "fe1");
+	eth->irq_fe[MTK_FE_IRQ_RX] = platform_get_irq_byname_optional(pdev, "fe2");
+	if (eth->irq_fe[MTK_FE_IRQ_TX] >= 0 && eth->irq_fe[MTK_FE_IRQ_RX] >= 0)
 		return 0;
 
 	/* only use legacy mode if platform_get_irq_byname_optional returned -ENXIO */
-	if (eth->irq[MTK_FE_IRQ_TX] != -ENXIO)
-		return dev_err_probe(&pdev->dev, eth->irq[MTK_FE_IRQ_TX],
+	if (eth->irq_fe[MTK_FE_IRQ_TX] != -ENXIO)
+		return dev_err_probe(&pdev->dev, eth->irq_fe[MTK_FE_IRQ_TX],
 				     "Error requesting FE TX IRQ\n");
 
-	if (eth->irq[MTK_FE_IRQ_RX] != -ENXIO)
-		return dev_err_probe(&pdev->dev, eth->irq[MTK_FE_IRQ_RX],
+	if (eth->irq_fe[MTK_FE_IRQ_RX] != -ENXIO)
+		return dev_err_probe(&pdev->dev, eth->irq_fe[MTK_FE_IRQ_RX],
 				     "Error requesting FE RX IRQ\n");
 
 	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT))
@@ -3400,14 +3486,14 @@ static int mtk_get_irqs(struct platform_device *pdev, struct mtk_eth *eth)
 	for (i = 0; i < MTK_FE_IRQ_NUM; i++) {
 		if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT)) {
 			if (i == MTK_FE_IRQ_SHARED)
-				eth->irq[MTK_FE_IRQ_SHARED] = platform_get_irq(pdev, i);
+				eth->irq_fe[MTK_FE_IRQ_SHARED] = platform_get_irq(pdev, i);
 			else
-				eth->irq[i] = eth->irq[MTK_FE_IRQ_SHARED];
+				eth->irq_fe[i] = eth->irq_fe[MTK_FE_IRQ_SHARED];
 		} else {
-			eth->irq[i] = platform_get_irq(pdev, i + 1);
+			eth->irq_fe[i] = platform_get_irq(pdev, i + 1);
 		}
 
-		if (eth->irq[i] < 0) {
+		if (eth->irq_fe[i] < 0) {
 			dev_err(&pdev->dev, "no IRQ%d resource found\n", i);
 			return -ENXIO;
 		}
@@ -3416,14 +3502,36 @@ static int mtk_get_irqs(struct platform_device *pdev, struct mtk_eth *eth)
 	return 0;
 }
 
-static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth)
+static int mtk_get_irqs_pdma(struct platform_device *pdev, struct mtk_eth *eth)
 {
-	struct mtk_eth *eth = _eth;
+	char rxring[] = "pdma0";
+	int i;
+
+	for (i = 0; i < MTK_PDMA_IRQ_NUM; i++) {
+		rxring[4] = '0' + i;
+		eth->irq_pdma[i] = platform_get_irq_byname(pdev, rxring);
+		if (eth->irq_pdma[i] < 0)
+			return eth->irq_pdma[i];
+	}
+
+	return 0;
+}
+
+static irqreturn_t mtk_handle_irq_rx(int irq, void *priv)
+{
+	struct mtk_napi *rx_napi = priv;
+	struct mtk_eth *eth = rx_napi->eth;
+	struct mtk_rx_ring *ring = rx_napi->rx_ring;
 
 	eth->rx_events++;
-	if (likely(napi_schedule_prep(&eth->rx_napi))) {
-		mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask);
-		__napi_schedule(&eth->rx_napi);
+	if (unlikely(!(mtk_r32(eth, eth->soc->reg_map->pdma.irq_status) &
+		       mtk_r32(eth, eth->soc->reg_map->pdma.irq_mask) &
+		       MTK_RX_DONE_INT(ring->ring_no))))
+		return IRQ_NONE;
+
+	if (likely(napi_schedule_prep(&rx_napi->napi))) {
+		mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(ring->ring_no));
+		__napi_schedule(&rx_napi->napi);
 	}
 
 	return IRQ_HANDLED;
@@ -3448,10 +3556,10 @@ static irqreturn_t mtk_handle_irq(int irq, void *_eth)
 	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
 
 	if (mtk_r32(eth, reg_map->pdma.irq_mask) &
-	    eth->soc->rx.irq_done_mask) {
+	    MTK_RX_DONE_INT(0)) {
 		if (mtk_r32(eth, reg_map->pdma.irq_status) &
-		    eth->soc->rx.irq_done_mask)
-			mtk_handle_irq_rx(irq, _eth);
+		    MTK_RX_DONE_INT(0))
+			mtk_handle_irq_rx(irq, &eth->rx_napi[0]);
 	}
 	if (mtk_r32(eth, reg_map->tx_irq_mask) & MTK_TX_DONE_INT) {
 		if (mtk_r32(eth, reg_map->tx_irq_status) & MTK_TX_DONE_INT)
@@ -3468,10 +3576,10 @@ static void mtk_poll_controller(struct net_device *dev)
 	struct mtk_eth *eth = mac->hw;
 
 	mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
-	mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask);
-	mtk_handle_irq_rx(eth->irq[MTK_FE_IRQ_RX], dev);
+	mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(0));
+	mtk_handle_irq_rx(eth->irq_fe[MTK_FE_IRQ_RX], &eth->rx_napi[0]);
 	mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
-	mtk_rx_irq_enable(eth, eth->soc->rx.irq_done_mask);
+	mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(0));
 }
 #endif
 
@@ -3643,9 +3751,17 @@ static int mtk_open(struct net_device *dev)
 		}
 
 		napi_enable(&eth->tx_napi);
-		napi_enable(&eth->rx_napi);
+		napi_enable(&eth->rx_napi[0].napi);
 		mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
-		mtk_rx_irq_enable(eth, soc->rx.irq_done_mask);
+		mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(0));
+
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+			for (i = 1; i < MTK_RX_RSS_NUM; i++) {
+				napi_enable(&eth->rx_napi[MTK_RSS_RING(i)].napi);
+				mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(MTK_RSS_RING(i)));
+			}
+		}
+
 		refcount_set(&eth->dma_refcnt, 1);
 	} else {
 		refcount_inc(&eth->dma_refcnt);
@@ -3730,9 +3846,16 @@ static int mtk_stop(struct net_device *dev)
 		mtk_gdm_config(eth, i, MTK_GDMA_DROP_ALL);
 
 	mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
-	mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask);
+	mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(0));
 	napi_disable(&eth->tx_napi);
-	napi_disable(&eth->rx_napi);
+	napi_disable(&eth->rx_napi[0].napi);
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		for (i = 1; i < MTK_RX_RSS_NUM; i++) {
+			mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(MTK_RSS_RING(i)));
+			napi_disable(&eth->rx_napi[MTK_RSS_RING(i)].napi);
+		}
+	}
 
 	cancel_work_sync(&eth->rx_dim.work);
 	cancel_work_sync(&eth->tx_dim.work);
@@ -3843,9 +3966,7 @@ static void mtk_dim_rx(struct work_struct *work)
 						dim->profile_ix);
 	spin_lock_bh(&eth->dim_lock);
 
-	val = mtk_r32(eth, reg_map->pdma.delay_irq);
-	val &= MTK_PDMA_DELAY_TX_MASK;
-	val |= MTK_PDMA_DELAY_RX_EN;
+	val = MTK_PDMA_DELAY_RX_EN;
 
 	cur = min_t(u32, DIV_ROUND_UP(cur_profile.usec, 20), MTK_PDMA_DELAY_PTIME_MASK);
 	val |= cur << MTK_PDMA_DELAY_RX_PTIME_SHIFT;
@@ -3853,9 +3974,19 @@ static void mtk_dim_rx(struct work_struct *work)
 	cur = min_t(u32, cur_profile.pkts, MTK_PDMA_DELAY_PINT_MASK);
 	val |= cur << MTK_PDMA_DELAY_RX_PINT_SHIFT;
 
-	mtk_w32(eth, val, reg_map->pdma.delay_irq);
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
-		mtk_w32(eth, val, reg_map->qdma.delay_irq);
+		mtk_m32(eth, MTK_PDMA_DELAY_TX_MASK,
+			val << MTK_PDMA_DELAY_TX_PTIME_SHIFT, reg_map->qdma.delay_irq);
+
+	if (eth->soc->rx.desc_size == sizeof(struct mtk_rx_dma)) {
+		mtk_m32(eth, MTK_PDMA_DELAY_RX_MASK, val, reg_map->pdma.delay_irq);
+		mtk_w32(eth, val, reg_map->pdma.lro_rx1_dly_int);
+		mtk_w32(eth, val, reg_map->pdma.lro_rx1_dly_int + 0x4);
+		mtk_w32(eth, val, reg_map->pdma.lro_rx1_dly_int + 0x8);
+	} else {
+		val = val | (val << MTK_PDMA_DELAY_RX_RING_SHIFT);
+		mtk_w32(eth, val, reg_map->pdma.rx_delay_irq);
+	}
 
 	spin_unlock_bh(&eth->dim_lock);
 
@@ -3874,9 +4005,7 @@ static void mtk_dim_tx(struct work_struct *work)
 						dim->profile_ix);
 	spin_lock_bh(&eth->dim_lock);
 
-	val = mtk_r32(eth, reg_map->pdma.delay_irq);
-	val &= MTK_PDMA_DELAY_RX_MASK;
-	val |= MTK_PDMA_DELAY_TX_EN;
+	val = MTK_PDMA_DELAY_TX_EN;
 
 	cur = min_t(u32, DIV_ROUND_UP(cur_profile.usec, 20), MTK_PDMA_DELAY_PTIME_MASK);
 	val |= cur << MTK_PDMA_DELAY_TX_PTIME_SHIFT;
@@ -3884,9 +4013,16 @@ static void mtk_dim_tx(struct work_struct *work)
 	cur = min_t(u32, cur_profile.pkts, MTK_PDMA_DELAY_PINT_MASK);
 	val |= cur << MTK_PDMA_DELAY_TX_PINT_SHIFT;
 
-	mtk_w32(eth, val, reg_map->pdma.delay_irq);
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
-		mtk_w32(eth, val, reg_map->qdma.delay_irq);
+		mtk_m32(eth, MTK_PDMA_DELAY_RX_MASK,
+			val >> MTK_PDMA_DELAY_TX_PTIME_SHIFT, reg_map->qdma.delay_irq);
+
+	if (eth->soc->rx.desc_size == sizeof(struct mtk_rx_dma)) {
+		mtk_m32(eth, MTK_PDMA_DELAY_TX_MASK, val, reg_map->pdma.delay_irq);
+	} else {
+		mtk_w32(eth, val >> MTK_PDMA_DELAY_TX_PTIME_SHIFT,
+			reg_map->pdma.tx_delay_irq);
+	}
 
 	spin_unlock_bh(&eth->dim_lock);
 
@@ -4104,6 +4240,25 @@ static void mtk_hw_reset_monitor_work(struct work_struct *work)
 			      MTK_DMA_MONITOR_TIMEOUT);
 }
 
+static int mtk_napi_init(struct mtk_eth *eth)
+{
+	struct mtk_napi *rx_napi = &eth->rx_napi[0];
+	int i;
+
+	rx_napi->eth = eth;
+	rx_napi->rx_ring = &eth->rx_ring[0];
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		for (i = 1; i < MTK_RX_RSS_NUM; i++) {
+			rx_napi = &eth->rx_napi[MTK_RSS_RING(i)];
+			rx_napi->eth = eth;
+			rx_napi->rx_ring = &eth->rx_ring[MTK_RSS_RING(i)];
+		}
+	}
+
+	return 0;
+}
+
 static int mtk_hw_init(struct mtk_eth *eth, bool reset)
 {
 	u32 dma_mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA |
@@ -4193,12 +4348,11 @@ static int mtk_hw_init(struct mtk_eth *eth, bool reset)
 	 */
 	val = mtk_r32(eth, MTK_CDMQ_IG_CTRL);
 	mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL);
-	if (mtk_is_netsys_v1(eth)) {
-		val = mtk_r32(eth, MTK_CDMP_IG_CTRL);
-		mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL);
+	val = mtk_r32(eth, MTK_CDMP_IG_CTRL);
+	mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL);
 
+	if (mtk_is_netsys_v1(eth))
 		mtk_w32(eth, 1, MTK_CDMP_EG_CTRL);
-	}
 
 	/* set interrupt delays based on current Net DIM sample */
 	mtk_dim_rx(&eth->rx_dim.work);
@@ -4209,11 +4363,17 @@ static int mtk_hw_init(struct mtk_eth *eth, bool reset)
 	mtk_rx_irq_disable(eth, ~0);
 
 	/* FE int grouping */
-	mtk_w32(eth, MTK_TX_DONE_INT, reg_map->pdma.int_grp);
-	mtk_w32(eth, eth->soc->rx.irq_done_mask, reg_map->pdma.int_grp + 4);
+
 	mtk_w32(eth, MTK_TX_DONE_INT, reg_map->qdma.int_grp);
-	mtk_w32(eth, eth->soc->rx.irq_done_mask, reg_map->qdma.int_grp + 4);
-	mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP);
+	mtk_w32(eth, MTK_RX_DONE_INT(0), reg_map->qdma.int_grp + 4);
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_PDMA_INT)) {
+		mtk_w32(eth, 0x210FFFF2, MTK_FE_INT_GRP);
+	} else {
+		mtk_w32(eth, MTK_TX_DONE_INT, reg_map->pdma.int_grp);
+		mtk_w32(eth, MTK_RX_DONE_INT(0), reg_map->pdma.int_grp + 4);
+		mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP);
+	}
 
 	if (mtk_is_netsys_v3_or_greater(eth)) {
 		/* PSE dummy page mechanism */
@@ -4651,6 +4811,8 @@ static void mtk_get_ethtool_stats(struct net_device *dev,
 static int mtk_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
 			 u32 *rule_locs)
 {
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
 	int ret = -EOPNOTSUPP;
 
 	switch (cmd->cmd) {
@@ -4658,6 +4820,9 @@ static int mtk_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
 		if (dev->hw_features & NETIF_F_LRO) {
 			cmd->data = MTK_MAX_RX_RING_NUM;
 			ret = 0;
+		} else if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+			cmd->data = MTK_RX_RSS_NUM;
+			ret = 0;
 		}
 		break;
 	case ETHTOOL_GRXCLSRLCNT:
@@ -4732,6 +4897,70 @@ static int mtk_set_eee(struct net_device *dev, struct ethtool_keee *eee)
 	return phylink_ethtool_set_eee(mac->phylink, eee);
 }
 
+static u32 mtk_get_rxfh_key_size(struct net_device *dev)
+{
+	return MTK_RSS_HASH_KEYSIZE;
+}
+
+static u32 mtk_get_rxfh_indir_size(struct net_device *dev)
+{
+	return MTK_RSS_MAX_INDIRECTION_TABLE;
+}
+
+static int mtk_get_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	struct mtk_rss_params *rss_params = &eth->rss_params;
+	int i;
+
+	rxfh->hfunc = ETH_RSS_HASH_TOP;	/* Toeplitz */
+
+	if (rxfh->key) {
+		memcpy(rxfh->key, rss_params->hash_key,
+		       sizeof(rss_params->hash_key));
+	}
+
+	if (rxfh->indir) {
+		for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE; i++)
+			rxfh->indir[i] = rss_params->indirection_table[i];
+	}
+
+	return 0;
+}
+
+static int mtk_set_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh,
+			struct netlink_ext_ack *extack)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	struct mtk_rss_params *rss_params = &eth->rss_params;
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
+	int i;
+
+	if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+	    rxfh->hfunc != ETH_RSS_HASH_TOP)
+		return -EOPNOTSUPP;
+
+	if (rxfh->key) {
+		memcpy(rss_params->hash_key, rxfh->key,
+		       sizeof(rss_params->hash_key));
+		for (i = 0; i < MTK_RSS_HASH_KEYSIZE / sizeof(u32); i++)
+			mtk_w32(eth, rss_params->hash_key[i],
+				MTK_RSS_HASH_KEY_DW(i));
+	}
+
+	if (rxfh->indir) {
+		for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE; i++)
+			rss_params->indirection_table[i] = rxfh->indir[i];
+		for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE / 16; i++)
+			mtk_w32(eth, mtk_rss_indr_table(rss_params, i),
+				MTK_RSS_INDR_TABLE_DW(i));
+	}
+
+	return 0;
+}
+
 static u16 mtk_select_queue(struct net_device *dev, struct sk_buff *skb,
 			    struct net_device *sb_dev)
 {
@@ -4766,6 +4995,10 @@ static const struct ethtool_ops mtk_ethtool_ops = {
 	.set_rxnfc		= mtk_set_rxnfc,
 	.get_eee		= mtk_get_eee,
 	.set_eee		= mtk_set_eee,
+	.get_rxfh_key_size	= mtk_get_rxfh_key_size,
+	.get_rxfh_indir_size	= mtk_get_rxfh_indir_size,
+	.get_rxfh		= mtk_get_rxfh,
+	.set_rxfh		= mtk_set_rxfh,
 };
 
 static const struct net_device_ops mtk_netdev_ops = {
@@ -4955,7 +5188,7 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
 	eth->netdev[id]->features |= eth->soc->hw_features;
 	eth->netdev[id]->ethtool_ops = &mtk_ethtool_ops;
 
-	eth->netdev[id]->irq = eth->irq[MTK_FE_IRQ_SHARED];
+	eth->netdev[id]->irq = eth->irq_fe[MTK_FE_IRQ_SHARED];
 	eth->netdev[id]->dev.of_node = np;
 
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628))
@@ -5066,6 +5299,7 @@ static int mtk_probe(struct platform_device *pdev)
 	struct resource *res = NULL;
 	struct device_node *mac_np;
 	struct mtk_eth *eth;
+	char *irqname;
 	int err, i;
 
 	eth = devm_kzalloc(&pdev->dev, sizeof(*eth), GFP_KERNEL);
@@ -5197,10 +5431,16 @@ static int mtk_probe(struct platform_device *pdev)
 		}
 	}
 
-	err = mtk_get_irqs(pdev, eth);
+	err = mtk_get_irqs_fe(pdev, eth);
 	if (err)
 		goto err_wed_exit;
 
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_PDMA_INT)) {
+		err = mtk_get_irqs_pdma(pdev, eth);
+		if (err)
+			goto err_wed_exit;
+	}
+
 	for (i = 0; i < ARRAY_SIZE(eth->clks); i++) {
 		eth->clks[i] = devm_clk_get(eth->dev,
 					    mtk_clks_source_name[i]);
@@ -5243,23 +5483,56 @@ static int mtk_probe(struct platform_device *pdev)
 		}
 	}
 
+	err = mtk_napi_init(eth);
+	if (err)
+		goto err_free_dev;
+
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT)) {
-		err = devm_request_irq(eth->dev, eth->irq[MTK_FE_IRQ_SHARED],
+		err = devm_request_irq(eth->dev, eth->irq_fe[MTK_FE_IRQ_SHARED],
 				       mtk_handle_irq, 0,
 				       dev_name(eth->dev), eth);
 	} else {
-		err = devm_request_irq(eth->dev, eth->irq[MTK_FE_IRQ_TX],
+		irqname = devm_kasprintf(eth->dev, GFP_KERNEL, "%s TX",
+					 dev_name(eth->dev));
+		err = devm_request_irq(eth->dev, eth->irq_fe[MTK_FE_IRQ_TX],
 				       mtk_handle_irq_tx, 0,
-				       dev_name(eth->dev), eth);
+				       irqname, eth);
 		if (err)
 			goto err_free_dev;
 
-		err = devm_request_irq(eth->dev, eth->irq[MTK_FE_IRQ_RX],
-				       mtk_handle_irq_rx, 0,
-				       dev_name(eth->dev), eth);
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_PDMA_INT)) {
+			irqname = devm_kasprintf(eth->dev, GFP_KERNEL, "%s PDMA RX %d",
+						 dev_name(eth->dev), 0);
+			err = devm_request_irq(eth->dev, eth->irq_pdma[0],
+					       mtk_handle_irq_rx, IRQF_SHARED,
+					       irqname, &eth->rx_napi[0]);
+			if (err)
+				goto err_free_dev;
+
+			if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+				for (i = 1; i < MTK_RX_RSS_NUM; i++) {
+					irqname = devm_kasprintf(eth->dev, GFP_KERNEL,
+								 "%s PDMA RX %d",
+								 dev_name(eth->dev), i);
+					err = devm_request_irq(eth->dev,
+							       eth->irq_pdma[MTK_RSS_RING(i)],
+							       mtk_handle_irq_rx, IRQF_SHARED,
+							       irqname,
+							       &eth->rx_napi[MTK_RSS_RING(i)]);
+					if (err)
+						goto err_free_dev;
+				}
+			}
+		} else {
+			irqname = devm_kasprintf(eth->dev, GFP_KERNEL, "%s RX",
+						 dev_name(eth->dev));
+			err = devm_request_irq(eth->dev, eth->irq_fe[MTK_FE_IRQ_RX],
+					       mtk_handle_irq_rx, 0,
+					       irqname, &eth->rx_napi[0]);
+			if (err)
+				goto err_free_dev;
+		}
 	}
-	if (err)
-		goto err_free_dev;
 
 	/* No MT7628/88 support yet */
 	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) {
@@ -5300,7 +5573,7 @@ static int mtk_probe(struct platform_device *pdev)
 		} else
 			netif_info(eth, probe, eth->netdev[i],
 				   "mediatek frame engine at 0x%08lx, irq %d\n",
-				   eth->netdev[i]->base_addr, eth->irq[MTK_FE_IRQ_SHARED]);
+				   eth->netdev[i]->base_addr, eth->irq_fe[MTK_FE_IRQ_SHARED]);
 	}
 
 	/* we run 2 devices on the same DMA ring so we need a dummy device
@@ -5313,7 +5586,13 @@ static int mtk_probe(struct platform_device *pdev)
 		goto err_unreg_netdev;
 	}
 	netif_napi_add(eth->dummy_dev, &eth->tx_napi, mtk_napi_tx);
-	netif_napi_add(eth->dummy_dev, &eth->rx_napi, mtk_napi_rx);
+	netif_napi_add(eth->dummy_dev, &eth->rx_napi[0].napi, mtk_napi_rx);
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		for (i = 1; i < MTK_RX_RSS_NUM; i++)
+			netif_napi_add(eth->dummy_dev, &eth->rx_napi[MTK_RSS_RING(i)].napi,
+				       mtk_napi_rx);
+	}
 
 	platform_set_drvdata(pdev, eth);
 	schedule_delayed_work(&eth->reset.monitor_work,
@@ -5357,7 +5636,12 @@ static void mtk_remove(struct platform_device *pdev)
 	mtk_hw_deinit(eth);
 
 	netif_napi_del(&eth->tx_napi);
-	netif_napi_del(&eth->rx_napi);
+	netif_napi_del(&eth->rx_napi[0].napi);
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		for (i = 1; i < MTK_RX_RSS_NUM; i++)
+			netif_napi_del(&eth->rx_napi[MTK_RSS_RING(i)].napi);
+	}
 	mtk_cleanup(eth);
 	free_netdev(eth->dummy_dev);
 	mtk_mdio_cleanup(eth);
@@ -5370,6 +5654,7 @@ static const struct mtk_soc_data mt2701_data = {
 	.required_clks = MT7623_CLKS_BITMAP,
 	.required_pctl = true,
 	.version = 1,
+	.rss_num = 0,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5379,7 +5664,6 @@ static const struct mtk_soc_data mt2701_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID,
 		.dma_size = MTK_DMA_SIZE(2K),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5398,6 +5682,7 @@ static const struct mtk_soc_data mt7621_data = {
 	.ppe_num = 1,
 	.hash_offset = 2,
 	.foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
+	.rss_num = 0,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5407,7 +5692,6 @@ static const struct mtk_soc_data mt7621_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID,
 		.dma_size = MTK_DMA_SIZE(2K),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5428,6 +5712,7 @@ static const struct mtk_soc_data mt7622_data = {
 	.hash_offset = 2,
 	.has_accounting = true,
 	.foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
+	.rss_num = 0,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5437,7 +5722,6 @@ static const struct mtk_soc_data mt7622_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID,
 		.dma_size = MTK_DMA_SIZE(2K),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5457,6 +5741,7 @@ static const struct mtk_soc_data mt7623_data = {
 	.hash_offset = 2,
 	.foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
 	.disable_pll_modes = true,
+	.rss_num = 0,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5466,7 +5751,6 @@ static const struct mtk_soc_data mt7623_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID,
 		.dma_size = MTK_DMA_SIZE(2K),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5483,6 +5767,7 @@ static const struct mtk_soc_data mt7629_data = {
 	.required_pctl = false,
 	.has_accounting = true,
 	.version = 1,
+	.rss_num = 0,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5492,7 +5777,6 @@ static const struct mtk_soc_data mt7629_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID,
 		.dma_size = MTK_DMA_SIZE(2K),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5513,16 +5797,16 @@ static const struct mtk_soc_data mt7981_data = {
 	.hash_offset = 4,
 	.has_accounting = true,
 	.foe_entry_size = MTK_FOE_ENTRY_V2_SIZE,
+	.rss_num = 4,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma_v2),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
 		.dma_len_offset = 8,
-		.dma_size = MTK_DMA_SIZE(2K),
+		.dma_size = MTK_DMA_SIZE(4K),
 		.fq_dma_size = MTK_DMA_SIZE(2K),
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID_V2,
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
 		.dma_len_offset = 16,
@@ -5543,6 +5827,7 @@ static const struct mtk_soc_data mt7986_data = {
 	.hash_offset = 4,
 	.has_accounting = true,
 	.foe_entry_size = MTK_FOE_ENTRY_V2_SIZE,
+	.rss_num = 4,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma_v2),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
@@ -5552,7 +5837,6 @@ static const struct mtk_soc_data mt7986_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID_V2,
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
 		.dma_len_offset = 16,
@@ -5573,20 +5857,20 @@ static const struct mtk_soc_data mt7988_data = {
 	.hash_offset = 4,
 	.has_accounting = true,
 	.foe_entry_size = MTK_FOE_ENTRY_V3_SIZE,
+	.rss_num = 4,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma_v2),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
 		.dma_len_offset = 8,
-		.dma_size = MTK_DMA_SIZE(2K),
+		.dma_size = MTK_DMA_SIZE(4K),
 		.fq_dma_size = MTK_DMA_SIZE(4K),
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma_v2),
-		.irq_done_mask = MTK_RX_DONE_INT_V2,
 		.dma_l4_valid = RX_DMA_L4_VALID_V2,
 		.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
 		.dma_len_offset = 8,
-		.dma_size = MTK_DMA_SIZE(2K),
+		.dma_size = MTK_DMA_SIZE(1K),
 	},
 };
 
@@ -5597,6 +5881,7 @@ static const struct mtk_soc_data rt5350_data = {
 	.required_clks = MT7628_CLKS_BITMAP,
 	.required_pctl = false,
 	.version = 1,
+	.rss_num = 0,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5605,7 +5890,6 @@ static const struct mtk_soc_data rt5350_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID_PDMA,
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
 		.dma_len_offset = 16,
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index 334625814b97..db72337e9fd4 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -76,6 +76,8 @@
 #define	MTK_HW_LRO_BW_THRE		3000
 #define	MTK_HW_LRO_REPLACE_DELTA	1000
 #define	MTK_HW_LRO_SDL_REMAIN_ROOM	1522
+#define MTK_RSS_HASH_KEYSIZE		40
+#define MTK_RSS_MAX_INDIRECTION_TABLE	128
 
 /* Frame Engine Global Configuration */
 #define MTK_FE_GLO_CFG(x)	(((x) == MTK_GMAC3_ID) ? 0x24 : 0x00)
@@ -97,6 +99,8 @@
 #define MTK_GDM1_AF		BIT(28)
 #define MTK_GDM2_AF		BIT(29)
 
+#define MTK_PDMA_IRQ_NUM	(4)
+
 /* PDMA HW LRO Alter Flow Timer Register */
 #define MTK_PDMA_LRO_ALT_REFRESH_TIMER	0x1c
 
@@ -179,7 +183,10 @@
 
 /* PDMA HW LRO Control Registers */
 #define MTK_PDMA_LRO_CTRL_DW0	0x980
+#define MTK_HW_LRO_RING_NUM		(mtk_is_netsys_v3_or_greater(eth) ? 4 : 3)
 #define MTK_LRO_EN			BIT(0)
+#define MTK_NON_LRO_MULTI_EN		BIT(2)
+#define MTK_LRO_DLY_INT_EN		BIT(5)
 #define MTK_L3_CKS_UPD_EN		BIT(7)
 #define MTK_L3_CKS_UPD_EN_V2		BIT(19)
 #define MTK_LRO_ALT_PKT_CNT_MODE	BIT(21)
@@ -198,6 +205,19 @@
 #define MTK_MULTI_EN		BIT(10)
 #define MTK_PDMA_SIZE_8DWORDS	(1 << 4)
 
+/* PDMA RSS Control Registers */
+#define MTK_RX_NAPI_NUM			(4)
+#define MTK_RX_RSS_NUM			(eth->soc->rss_num)
+#define MTK_RSS_RING(x)			(x)
+#define MTK_RSS_EN			BIT(0)
+#define MTK_RSS_CFG_REQ			BIT(2)
+#define MTK_RSS_IPV6_STATIC_HASH	(0x7 << 8)
+#define MTK_RSS_IPV4_STATIC_HASH	(0x7 << 12)
+#define MTK_RSS_HASH_KEY_DW(x)		(reg_map->pdma.rss_glo_cfg + 0x20 +	\
+					 ((x) * 0x4))
+#define MTK_RSS_INDR_TABLE_DW(x)	(reg_map->pdma.rss_glo_cfg + 0x50 +	\
+					 ((x) * 0x4))
+
 /* PDMA Global Configuration Register */
 #define MTK_PDMA_LRO_SDL	0x3000
 #define MTK_RX_CFG_SDL_OFFSET	16
@@ -209,6 +229,7 @@
 /* PDMA Delay Interrupt Register */
 #define MTK_PDMA_DELAY_RX_MASK		GENMASK(15, 0)
 #define MTK_PDMA_DELAY_RX_EN		BIT(15)
+#define MTK_PDMA_DELAY_RX_RING_SHIFT	16
 #define MTK_PDMA_DELAY_RX_PINT_SHIFT	8
 #define MTK_PDMA_DELAY_RX_PTIME_SHIFT	0
 
@@ -229,14 +250,12 @@
 #define MTK_RING_MYIP_VLD		BIT(9)
 
 /* PDMA HW LRO Ring Control Registers */
-#define MTK_LRO_RX_RING0_CTRL_DW1	0xb28
-#define MTK_LRO_RX_RING0_CTRL_DW2	0xb2c
-#define MTK_LRO_RX_RING0_CTRL_DW3	0xb30
-#define MTK_LRO_CTRL_DW1_CFG(x)		(MTK_LRO_RX_RING0_CTRL_DW1 + (x * 0x40))
-#define MTK_LRO_CTRL_DW2_CFG(x)		(MTK_LRO_RX_RING0_CTRL_DW2 + (x * 0x40))
-#define MTK_LRO_CTRL_DW3_CFG(x)		(MTK_LRO_RX_RING0_CTRL_DW3 + (x * 0x40))
+#define MTK_LRO_CTRL_DW1_CFG(x)		(reg_map->pdma.lro_ring_ctrl_dw1 + ((x) * 0x40))
+#define MTK_LRO_CTRL_DW2_CFG(x)		(reg_map->pdma.lro_ring_ctrl_dw1 + 0x4 + ((x) * 0x40))
+#define MTK_LRO_CTRL_DW3_CFG(x)		(reg_map->pdma.lro_ring_ctrl_dw1 + 0x8 + ((x) * 0x40))
 #define MTK_RING_AGE_TIME_L		((MTK_HW_LRO_AGE_TIME & 0x3ff) << 22)
 #define MTK_RING_AGE_TIME_H		((MTK_HW_LRO_AGE_TIME >> 10) & 0x3f)
+#define MTK_RING_PSE_MODE		BIT(6)
 #define MTK_RING_AUTO_LERAN_MODE	(3 << 6)
 #define MTK_RING_VLD			BIT(8)
 #define MTK_RING_MAX_AGG_TIME		((MTK_HW_LRO_AGG_TIME & 0xffff) << 10)
@@ -290,7 +309,20 @@
 #define FC_THRES_MIN		0x4444
 
 /* QDMA Interrupt Status Register */
-#define MTK_RX_DONE_DLY		BIT(30)
+#define MTK_RX_DONE_INT_V1(ring_no) \
+	( \
+		(ring_no) ? \
+		BIT(24 + (ring_no)) : \
+		BIT(30) \
+	)
+
+#define MTK_RX_DONE_INT_V2(ring_no)	BIT(24 + (ring_no))
+
+#define MTK_RX_DONE_INT(ring_no)		\
+	(mtk_is_netsys_v3_or_greater(eth) ?  \
+	 MTK_RX_DONE_INT_V2(ring_no) : \
+	 MTK_RX_DONE_INT_V1(ring_no))
+
 #define MTK_TX_DONE_DLY		BIT(28)
 #define MTK_RX_DONE_INT3	BIT(19)
 #define MTK_RX_DONE_INT2	BIT(18)
@@ -300,11 +332,8 @@
 #define MTK_TX_DONE_INT2	BIT(2)
 #define MTK_TX_DONE_INT1	BIT(1)
 #define MTK_TX_DONE_INT0	BIT(0)
-#define MTK_RX_DONE_INT		MTK_RX_DONE_DLY
 #define MTK_TX_DONE_INT		MTK_TX_DONE_DLY
 
-#define MTK_RX_DONE_INT_V2	BIT(14)
-
 #define MTK_CDM_TXFIFO_RDY	BIT(7)
 
 /* QDMA Interrupt grouping registers */
@@ -942,6 +971,7 @@ struct mtk_tx_ring {
 	struct mtk_tx_dma *dma_pdma;	/* For MT7628/88 PDMA handling */
 	dma_addr_t phys_pdma;
 	int cpu_idx;
+	bool in_sram;
 };
 
 /* PDMA rx ring mode */
@@ -967,13 +997,38 @@ struct mtk_rx_ring {
 	u16 buf_size;
 	u16 dma_size;
 	bool calc_idx_update;
+	bool in_sram;
 	u16 calc_idx;
 	u32 crx_idx_reg;
+	u32 ring_no;
 	/* page_pool */
 	struct page_pool *page_pool;
 	struct xdp_rxq_info xdp_q;
 };
 
+/* struct mtk_rss_params -	This is the structure holding parameters
+ *				for the RSS ring
+ * @hash_key			The element is used to record the
+ *				secret key for the RSS ring
+ * indirection_table		The element is used to record the
+ *				indirection table for the RSS ring
+ */
+struct mtk_rss_params {
+	u32		hash_key[MTK_RSS_HASH_KEYSIZE / sizeof(u32)];
+	u8		indirection_table[MTK_RSS_MAX_INDIRECTION_TABLE];
+};
+
+/* struct mtk_napi -	This is the structure holding NAPI-related information,
+ *			and a mtk_napi struct is binding to one interrupt group
+ * @napi:		The NAPI struct
+ * @rx_ring:		Pointer to the memory holding info about the RX ring
+ */
+struct mtk_napi {
+	struct napi_struct	napi;
+	struct mtk_eth		*eth;
+	struct mtk_rx_ring	*rx_ring;
+};
+
 enum mkt_eth_capabilities {
 	MTK_RGMII_BIT = 0,
 	MTK_TRGMII_BIT,
@@ -985,7 +1040,9 @@ enum mkt_eth_capabilities {
 	MTK_INFRA_BIT,
 	MTK_SHARED_SGMII_BIT,
 	MTK_HWLRO_BIT,
+	MTK_RSS_BIT,
 	MTK_SHARED_INT_BIT,
+	MTK_PDMA_INT_BIT,
 	MTK_TRGMII_MT7621_CLK_BIT,
 	MTK_QDMA_BIT,
 	MTK_SOC_MT7628_BIT,
@@ -1025,7 +1082,9 @@ enum mkt_eth_capabilities {
 #define MTK_INFRA		BIT_ULL(MTK_INFRA_BIT)
 #define MTK_SHARED_SGMII	BIT_ULL(MTK_SHARED_SGMII_BIT)
 #define MTK_HWLRO		BIT_ULL(MTK_HWLRO_BIT)
+#define MTK_RSS			BIT_ULL(MTK_RSS_BIT)
 #define MTK_SHARED_INT		BIT_ULL(MTK_SHARED_INT_BIT)
+#define MTK_PDMA_INT		BIT_ULL(MTK_PDMA_INT_BIT)
 #define MTK_TRGMII_MT7621_CLK	BIT_ULL(MTK_TRGMII_MT7621_CLK_BIT)
 #define MTK_QDMA		BIT_ULL(MTK_QDMA_BIT)
 #define MTK_SOC_MT7628		BIT_ULL(MTK_SOC_MT7628_BIT)
@@ -1117,15 +1176,15 @@ enum mkt_eth_capabilities {
 #define MT7981_CAPS  (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC2_GEPHY | \
 		      MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \
 		      MTK_MUX_U3_GMAC2_TO_QPHY | MTK_U3_COPHY_V2 | \
-		      MTK_RSTCTRL_PPE1 | MTK_SRAM)
+		      MTK_RSTCTRL_PPE1 | MTK_SRAM | MTK_PDMA_INT)
 
 #define MT7986_CAPS  (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \
 		      MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \
-		      MTK_RSTCTRL_PPE1 | MTK_SRAM)
+		      MTK_RSTCTRL_PPE1 | MTK_SRAM | MTK_PDMA_INT)
 
 #define MT7988_CAPS  (MTK_36BIT_DMA | MTK_GDM1_ESW | MTK_GMAC2_2P5GPHY | \
 		      MTK_MUX_GMAC2_TO_2P5GPHY | MTK_QDMA | MTK_RSTCTRL_PPE1 | \
-		      MTK_RSTCTRL_PPE2 | MTK_SRAM)
+		      MTK_RSTCTRL_PPE2 | MTK_SRAM | MTK_PDMA_INT | MTK_RSS)
 
 struct mtk_tx_dma_desc_info {
 	dma_addr_t	addr;
@@ -1223,6 +1282,7 @@ struct mtk_reg_map {
 struct mtk_soc_data {
 	const struct mtk_reg_map *reg_map;
 	u32             ana_rgc3;
+	u32		rss_num;
 	u64		caps;
 	u64		required_clks;
 	bool		required_pctl;
@@ -1270,7 +1330,8 @@ struct mtk_soc_data {
  *			dummy for NAPI to work
  * @netdev:		The netdev instances
  * @mac:		Each netdev is linked to a physical MAC
- * @irq:		The IRQ that we are using
+ * @irq_fe:		Array of IRQs of the frame engine
+ * @irq_pdma:		Array of IRQs of the PDMA used for RSS
  * @msg_enable:		Ethtool msg level
  * @ethsys:		The register map pointing at the range used to setup
  *			MII modes
@@ -1314,7 +1375,8 @@ struct mtk_eth {
 	struct net_device		*dummy_dev;
 	struct net_device		*netdev[MTK_MAX_DEVS];
 	struct mtk_mac			*mac[MTK_MAX_DEVS];
-	int				irq[MTK_FE_IRQ_NUM];
+	int				irq_fe[MTK_FE_IRQ_NUM];
+	int				irq_pdma[MTK_PDMA_IRQ_NUM];
 	u32				msg_enable;
 	unsigned long			sysclk;
 	struct regmap			*ethsys;
@@ -1327,7 +1389,8 @@ struct mtk_eth {
 	struct mtk_rx_ring		rx_ring[MTK_MAX_RX_RING_NUM];
 	struct mtk_rx_ring		rx_ring_qdma;
 	struct napi_struct		tx_napi;
-	struct napi_struct		rx_napi;
+	struct mtk_napi			rx_napi[MTK_RX_NAPI_NUM];
+	struct mtk_rss_params		rss_params;
 	void				*scratch_ring;
 	dma_addr_t			phy_scratch_ring;
 	void				*scratch_head[MTK_FQ_DMA_HEAD];
-- 
2.43.0



From linux at fw-web.de  Sun Dec 14 03:03:04 2025
From: linux at fw-web.de (Frank Wunderlich)
Date: Sun, 14 Dec 2025 12:03:04 +0100
Subject: [RFC net-next v3 3/3] net: ethernet: mtk_eth_soc: Add LRO support
In-Reply-To: <20251214110310.7009-1-linux@fw-web.de>
References: <20251214110310.7009-1-linux@fw-web.de>
Message-ID: <20251214110310.7009-4-linux@fw-web.de>

From: Mason Chang <mason-cw.chang at mediatek.com>

Add Large Receive Offload support to mediatek ethernet driver and
activate it for MT7988.

Signed-off-by: Mason Chang <mason-cw.chang at mediatek.com>
Signed-off-by: Frank Wunderlich <frank-w at public-files.de>
---
v2:
- drop link to commit for 6.6 patch
---
 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 213 ++++++++++++++++++--
 drivers/net/ethernet/mediatek/mtk_eth_soc.h |  48 +++--
 2 files changed, 221 insertions(+), 40 deletions(-)

diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index b27b8b8b05f6..7521d8888221 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -2785,7 +2785,7 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag)
 	if (!ring->data)
 		return -ENOMEM;
 
-	if (mtk_page_pool_enabled(eth)) {
+	if (mtk_page_pool_enabled(eth) && rcu_access_pointer(eth->prog))  {
 		struct page_pool *pp;
 
 		pp = mtk_create_page_pool(eth, &ring->xdp_q, ring_no,
@@ -2932,7 +2932,8 @@ static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring, bool in_
 static int mtk_hwlro_rx_init(struct mtk_eth *eth)
 {
 	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
-	int i;
+	const struct mtk_soc_data *soc = eth->soc;
+	int i, val;
 	u32 ring_ctrl_dw1 = 0, ring_ctrl_dw2 = 0, ring_ctrl_dw3 = 0;
 	u32 lro_ctrl_dw0 = 0, lro_ctrl_dw3 = 0;
 
@@ -2953,7 +2954,7 @@ static int mtk_hwlro_rx_init(struct mtk_eth *eth)
 	ring_ctrl_dw2 |= MTK_RING_MAX_AGG_CNT_L;
 	ring_ctrl_dw3 |= MTK_RING_MAX_AGG_CNT_H;
 
-	for (i = 1; i < MTK_MAX_RX_RING_NUM; i++) {
+	for (i = 1; i <= MTK_HW_LRO_RING_NUM; i++) {
 		mtk_w32(eth, ring_ctrl_dw1, MTK_LRO_CTRL_DW1_CFG(i));
 		mtk_w32(eth, ring_ctrl_dw2, MTK_LRO_CTRL_DW2_CFG(i));
 		mtk_w32(eth, ring_ctrl_dw3, MTK_LRO_CTRL_DW3_CFG(i));
@@ -2975,8 +2976,22 @@ static int mtk_hwlro_rx_init(struct mtk_eth *eth)
 	mtk_w32(eth, (MTK_HW_LRO_TIMER_UNIT << 16) | MTK_HW_LRO_REFRESH_TIME,
 		MTK_PDMA_LRO_ALT_REFRESH_TIMER);
 
-	/* set HW LRO mode & the max aggregation count for rx packets */
-	lro_ctrl_dw3 |= MTK_ADMA_MODE | (MTK_HW_LRO_MAX_AGG_CNT & 0xff);
+	if (mtk_is_netsys_v3_or_greater(eth)) {
+		val = mtk_r32(eth, reg_map->pdma.rx_cfg);
+		mtk_w32(eth, val | ((MTK_PDMA_LRO_SDL + MTK_MAX_RX_LENGTH) <<
+			MTK_RX_CFG_SDL_OFFSET), reg_map->pdma.rx_cfg);
+
+		lro_ctrl_dw0 |= MTK_PDMA_LRO_SDL << MTK_CTRL_DW0_SDL_OFFSET;
+
+		/* enable cpu reason black list */
+		lro_ctrl_dw0 |= MTK_LRO_CRSN_BNW;
+
+		/* no use PPE cpu reason */
+		mtk_w32(eth, 0xffffffff, MTK_PDMA_LRO_CTRL_DW1);
+	} else {
+		/* set HW LRO mode & the max aggregation count for rx packets */
+		lro_ctrl_dw3 |= MTK_ADMA_MODE | (MTK_HW_LRO_MAX_AGG_CNT & 0xff);
+	}
 
 	/* the minimal remaining room of SDL0 in RXD for lro aggregation */
 	lro_ctrl_dw3 |= MTK_LRO_MIN_RXD_SDL;
@@ -2987,6 +3002,16 @@ static int mtk_hwlro_rx_init(struct mtk_eth *eth)
 	mtk_w32(eth, lro_ctrl_dw3, MTK_PDMA_LRO_CTRL_DW3);
 	mtk_w32(eth, lro_ctrl_dw0, MTK_PDMA_LRO_CTRL_DW0);
 
+	if (mtk_is_netsys_v2_or_greater(eth)) {
+		i = (soc->rx.desc_size == sizeof(struct mtk_rx_dma_v2)) ? 1 : 0;
+		mtk_m32(eth, MTK_RX_DONE_INT(MTK_HW_LRO_RING(i)),
+			MTK_RX_DONE_INT(MTK_HW_LRO_RING(i)), reg_map->pdma.int_grp);
+		mtk_m32(eth, MTK_RX_DONE_INT(MTK_HW_LRO_RING(i + 1)),
+			MTK_RX_DONE_INT(MTK_HW_LRO_RING(i + 1)), reg_map->pdma.int_grp + 0x4);
+		mtk_m32(eth, MTK_RX_DONE_INT(MTK_HW_LRO_RING(i + 2)),
+			MTK_RX_DONE_INT(MTK_HW_LRO_RING(i + 2)), reg_map->pdma.int_grp3);
+	}
+
 	return 0;
 }
 
@@ -3010,7 +3035,7 @@ static void mtk_hwlro_rx_uninit(struct mtk_eth *eth)
 	}
 
 	/* invalidate lro rings */
-	for (i = 1; i < MTK_MAX_RX_RING_NUM; i++)
+	for (i = 1; i <= MTK_HW_LRO_RING_NUM; i++)
 		mtk_w32(eth, 0, MTK_LRO_CTRL_DW2_CFG(i));
 
 	/* disable HW LRO */
@@ -3059,6 +3084,64 @@ static int mtk_hwlro_get_ip_cnt(struct mtk_mac *mac)
 	return cnt;
 }
 
+static int mtk_hwlro_add_ipaddr_idx(struct net_device *dev, u32 ip4dst)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
+	u32 reg_val;
+	int i;
+
+	/* check for duplicate IP address in the current DIP list */
+	for (i = 1; i <= MTK_HW_LRO_DIP_NUM; i++) {
+		reg_val = mtk_r32(eth, MTK_LRO_DIP_DW0_CFG(i));
+		if (reg_val == ip4dst)
+			break;
+	}
+
+	if (i < MTK_HW_LRO_DIP_NUM + 1) {
+		netdev_warn(dev, "Duplicate IP address at DIP(%d)!\n", i);
+		return -EEXIST;
+	}
+
+	/* find out available DIP index */
+	for (i = 1; i <= MTK_HW_LRO_DIP_NUM; i++) {
+		reg_val = mtk_r32(eth, MTK_LRO_DIP_DW0_CFG(i));
+		if (reg_val == 0UL)
+			break;
+	}
+
+	if (i >= MTK_HW_LRO_DIP_NUM + 1) {
+		netdev_warn(dev, "DIP index is currently out of resource!\n");
+		return -EBUSY;
+	}
+
+	return i;
+}
+
+static int mtk_hwlro_get_ipaddr_idx(struct net_device *dev, u32 ip4dst)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
+	u32 reg_val;
+	int i;
+
+	/* find out DIP index that matches the given IP address */
+	for (i = 1; i <= MTK_HW_LRO_DIP_NUM; i++) {
+		reg_val = mtk_r32(eth, MTK_LRO_DIP_DW0_CFG(i));
+		if (reg_val == ip4dst)
+			break;
+	}
+
+	if (i >= MTK_HW_LRO_DIP_NUM + 1) {
+		netdev_warn(dev, "DIP address is not exist!\n");
+		return -ENOENT;
+	}
+
+	return i;
+}
+
 static int mtk_hwlro_add_ipaddr(struct net_device *dev,
 				struct ethtool_rxnfc *cmd)
 {
@@ -3067,15 +3150,19 @@ static int mtk_hwlro_add_ipaddr(struct net_device *dev,
 	struct mtk_mac *mac = netdev_priv(dev);
 	struct mtk_eth *eth = mac->hw;
 	int hwlro_idx;
+	u32 ip4dst;
 
 	if ((fsp->flow_type != TCP_V4_FLOW) ||
 	    (!fsp->h_u.tcp_ip4_spec.ip4dst) ||
 	    (fsp->location > 1))
 		return -EINVAL;
 
-	mac->hwlro_ip[fsp->location] = htonl(fsp->h_u.tcp_ip4_spec.ip4dst);
-	hwlro_idx = (mac->id * MTK_MAX_LRO_IP_CNT) + fsp->location;
+	ip4dst = htonl(fsp->h_u.tcp_ip4_spec.ip4dst);
+	hwlro_idx = mtk_hwlro_add_ipaddr_idx(dev, ip4dst);
+	if (hwlro_idx < 0)
+		return hwlro_idx;
 
+	mac->hwlro_ip[fsp->location] = ip4dst;
 	mac->hwlro_ip_cnt = mtk_hwlro_get_ip_cnt(mac);
 
 	mtk_hwlro_val_ipaddr(eth, hwlro_idx, mac->hwlro_ip[fsp->location]);
@@ -3091,13 +3178,17 @@ static int mtk_hwlro_del_ipaddr(struct net_device *dev,
 	struct mtk_mac *mac = netdev_priv(dev);
 	struct mtk_eth *eth = mac->hw;
 	int hwlro_idx;
+	u32 ip4dst;
 
 	if (fsp->location > 1)
 		return -EINVAL;
 
-	mac->hwlro_ip[fsp->location] = 0;
-	hwlro_idx = (mac->id * MTK_MAX_LRO_IP_CNT) + fsp->location;
+	ip4dst = mac->hwlro_ip[fsp->location];
+	hwlro_idx = mtk_hwlro_get_ipaddr_idx(dev, ip4dst);
+	if (hwlro_idx < 0)
+		return hwlro_idx;
 
+	mac->hwlro_ip[fsp->location] = 0;
 	mac->hwlro_ip_cnt = mtk_hwlro_get_ip_cnt(mac);
 
 	mtk_hwlro_inval_ipaddr(eth, hwlro_idx);
@@ -3105,6 +3196,24 @@ static int mtk_hwlro_del_ipaddr(struct net_device *dev,
 	return 0;
 }
 
+static void mtk_hwlro_netdev_enable(struct net_device *dev)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	int i, hwlro_idx;
+
+	for (i = 0; i < MTK_MAX_LRO_IP_CNT; i++) {
+		if (mac->hwlro_ip[i] == 0)
+			continue;
+
+		hwlro_idx = mtk_hwlro_get_ipaddr_idx(dev, mac->hwlro_ip[i]);
+		if (hwlro_idx < 0)
+			continue;
+
+		mtk_hwlro_val_ipaddr(eth, hwlro_idx, mac->hwlro_ip[i]);
+	}
+}
+
 static void mtk_hwlro_netdev_disable(struct net_device *dev)
 {
 	struct mtk_mac *mac = netdev_priv(dev);
@@ -3112,8 +3221,14 @@ static void mtk_hwlro_netdev_disable(struct net_device *dev)
 	int i, hwlro_idx;
 
 	for (i = 0; i < MTK_MAX_LRO_IP_CNT; i++) {
+		if (mac->hwlro_ip[i] == 0)
+			continue;
+
+		hwlro_idx = mtk_hwlro_get_ipaddr_idx(dev, mac->hwlro_ip[i]);
+		if (hwlro_idx < 0)
+			continue;
+
 		mac->hwlro_ip[i] = 0;
-		hwlro_idx = (mac->id * MTK_MAX_LRO_IP_CNT) + i;
 
 		mtk_hwlro_inval_ipaddr(eth, hwlro_idx);
 	}
@@ -3293,6 +3408,8 @@ static int mtk_set_features(struct net_device *dev, netdev_features_t features)
 
 	if ((diff & NETIF_F_LRO) && !(features & NETIF_F_LRO))
 		mtk_hwlro_netdev_disable(dev);
+	else if ((diff & NETIF_F_LRO) && (features & NETIF_F_LRO))
+		mtk_hwlro_netdev_enable(dev);
 
 	return 0;
 }
@@ -3350,8 +3467,8 @@ static int mtk_dma_init(struct mtk_eth *eth)
 		return err;
 
 	if (eth->hwlro) {
-		for (i = 1; i < MTK_MAX_RX_RING_NUM; i++) {
-			err = mtk_rx_alloc(eth, i, MTK_RX_FLAGS_HWLRO);
+		for (i = 0; i < MTK_HW_LRO_RING_NUM; i++) {
+			err = mtk_rx_alloc(eth, MTK_HW_LRO_RING(i), MTK_RX_FLAGS_HWLRO);
 			if (err)
 				return err;
 		}
@@ -3413,8 +3530,8 @@ static void mtk_dma_free(struct mtk_eth *eth)
 
 	if (eth->hwlro) {
 		mtk_hwlro_rx_uninit(eth);
-		for (i = 1; i < MTK_MAX_RX_RING_NUM; i++)
-			mtk_rx_clean(eth, &eth->rx_ring[i], false);
+		for (i = 0; i < MTK_HW_LRO_RING_NUM; i++)
+			mtk_rx_clean(eth, &eth->rx_ring[MTK_HW_LRO_RING(i)], false);
 	}
 
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
@@ -3609,16 +3726,21 @@ static int mtk_start_dma(struct mtk_eth *eth)
 			val |= MTK_RX_BT_32DWORDS;
 		mtk_w32(eth, val, reg_map->qdma.glo_cfg);
 
-		mtk_w32(eth,
-			MTK_RX_DMA_EN | rx_2b_offset |
-			MTK_RX_BT_32DWORDS | MTK_MULTI_EN,
-			reg_map->pdma.glo_cfg);
+		val = mtk_r32(eth, reg_map->pdma.glo_cfg);
+		val |= MTK_RX_DMA_EN | rx_2b_offset |
+		       MTK_RX_BT_32DWORDS | MTK_MULTI_EN;
+		mtk_w32(eth, val, reg_map->pdma.glo_cfg);
 	} else {
 		mtk_w32(eth, MTK_TX_WB_DDONE | MTK_TX_DMA_EN | MTK_RX_DMA_EN |
 			MTK_MULTI_EN | MTK_PDMA_SIZE_8DWORDS,
 			reg_map->pdma.glo_cfg);
 	}
 
+	if (eth->hwlro && mtk_is_netsys_v3_or_greater(eth)) {
+		val = mtk_r32(eth, reg_map->pdma.glo_cfg);
+		mtk_w32(eth, val | MTK_RX_DMA_LRO_EN, reg_map->pdma.glo_cfg);
+	}
+
 	return 0;
 }
 
@@ -3762,6 +3884,13 @@ static int mtk_open(struct net_device *dev)
 			}
 		}
 
+		if (eth->hwlro) {
+			for (i = 0; i < MTK_HW_LRO_RING_NUM; i++) {
+				napi_enable(&eth->rx_napi[MTK_HW_LRO_RING(i)].napi);
+				mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(MTK_HW_LRO_RING(i)));
+			}
+		}
+
 		refcount_set(&eth->dma_refcnt, 1);
 	} else {
 		refcount_inc(&eth->dma_refcnt);
@@ -3857,6 +3986,14 @@ static int mtk_stop(struct net_device *dev)
 		}
 	}
 
+	if (eth->hwlro) {
+		for (i = 0; i < MTK_HW_LRO_RING_NUM; i++) {
+			mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(MTK_HW_LRO_RING(i)));
+			napi_synchronize(&eth->rx_napi[MTK_HW_LRO_RING(i)].napi);
+			napi_disable(&eth->rx_napi[MTK_HW_LRO_RING(i)].napi);
+		}
+	}
+
 	cancel_work_sync(&eth->rx_dim.work);
 	cancel_work_sync(&eth->tx_dim.work);
 
@@ -4256,6 +4393,14 @@ static int mtk_napi_init(struct mtk_eth *eth)
 		}
 	}
 
+	if (eth->hwlro) {
+		for (i = 0; i < MTK_HW_LRO_RING_NUM; i++) {
+			rx_napi = &eth->rx_napi[MTK_HW_LRO_RING(i)];
+			rx_napi->eth = eth;
+			rx_napi->rx_ring = &eth->rx_ring[MTK_HW_LRO_RING(i)];
+		}
+	}
+
 	return 0;
 }
 
@@ -4818,7 +4963,7 @@ static int mtk_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
 	switch (cmd->cmd) {
 	case ETHTOOL_GRXRINGS:
 		if (dev->hw_features & NETIF_F_LRO) {
-			cmd->data = MTK_MAX_RX_RING_NUM;
+			cmd->data = MTK_HW_LRO_RING_NUM;
 			ret = 0;
 		} else if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
 			cmd->data = MTK_RX_RSS_NUM;
@@ -5523,6 +5668,21 @@ static int mtk_probe(struct platform_device *pdev)
 						goto err_free_dev;
 				}
 			}
+
+			if (eth->hwlro) {
+				for (i = 0; i < MTK_HW_LRO_RING_NUM; i++) {
+					irqname = devm_kasprintf(eth->dev, GFP_KERNEL,
+								 "%s LRO RX %d",
+								 dev_name(eth->dev), i);
+					err = devm_request_irq(eth->dev,
+							       eth->irq_pdma[MTK_HW_LRO_IRQ(i)],
+							       mtk_handle_irq_rx, IRQF_SHARED,
+							       irqname,
+							       &eth->rx_napi[MTK_HW_LRO_RING(i)]);
+					if (err)
+						goto err_free_dev;
+				}
+			}
 		} else {
 			irqname = devm_kasprintf(eth->dev, GFP_KERNEL, "%s RX",
 						 dev_name(eth->dev));
@@ -5594,6 +5754,13 @@ static int mtk_probe(struct platform_device *pdev)
 				       mtk_napi_rx);
 	}
 
+	if (eth->hwlro) {
+		for (i = 0; i < MTK_HW_LRO_RING_NUM; i++) {
+			netif_napi_add(eth->dummy_dev, &eth->rx_napi[MTK_HW_LRO_RING(i)].napi,
+				       mtk_napi_rx);
+		}
+	}
+
 	platform_set_drvdata(pdev, eth);
 	schedule_delayed_work(&eth->reset.monitor_work,
 			      MTK_DMA_MONITOR_TIMEOUT);
@@ -5642,6 +5809,12 @@ static void mtk_remove(struct platform_device *pdev)
 		for (i = 1; i < MTK_RX_RSS_NUM; i++)
 			netif_napi_del(&eth->rx_napi[MTK_RSS_RING(i)].napi);
 	}
+
+	if (eth->hwlro) {
+		for (i = 0; i < MTK_HW_LRO_RING_NUM; i++)
+			netif_napi_del(&eth->rx_napi[MTK_HW_LRO_RING(i)].napi);
+	}
+
 	mtk_cleanup(eth);
 	free_netdev(eth->dummy_dev);
 	mtk_mdio_cleanup(eth);
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index db72337e9fd4..a8f54ea17f1c 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -35,7 +35,7 @@
 #define MTK_DMA_SIZE(x)		(SZ_##x)
 #define MTK_FQ_DMA_HEAD		32
 #define MTK_FQ_DMA_LENGTH	2048
-#define MTK_RX_ETH_HLEN		(ETH_HLEN + ETH_FCS_LEN)
+#define MTK_RX_ETH_HLEN		(VLAN_ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN)
 #define MTK_RX_HLEN		(NET_SKB_PAD + MTK_RX_ETH_HLEN + NET_IP_ALIGN)
 #define MTK_DMA_DUMMY_DESC	0xffffffff
 #define MTK_DEFAULT_MSG_ENABLE	(NETIF_MSG_DRV | \
@@ -63,10 +63,13 @@
 
 #define MTK_QRX_OFFSET		0x10
 
-#define MTK_MAX_RX_RING_NUM	4
-#define MTK_HW_LRO_DMA_SIZE	8
+#define MTK_MAX_RX_RING_NUM	(8)
+#define MTK_HW_LRO_DMA_SIZE	(mtk_is_netsys_v3_or_greater(eth) ? 64 : 8)
+#define IS_HW_LRO_RING(ring_no)	(mtk_is_netsys_v3_or_greater(eth) ?		\
+				 (((ring_no) > 3) && ((ring_no) < 8)) :		\
+				 (((ring_no) > 0) && ((ring_no) < 4)))
 
-#define	MTK_MAX_LRO_RX_LENGTH		(4096 * 3)
+#define	MTK_MAX_LRO_RX_LENGTH		(4096 * 3 + MTK_MAX_RX_LENGTH)
 #define	MTK_MAX_LRO_IP_CNT		2
 #define	MTK_HW_LRO_TIMER_UNIT		1	/* 20 us */
 #define	MTK_HW_LRO_REFRESH_TIME		50000	/* 1 sec. */
@@ -182,31 +185,35 @@
 #define MTK_CDMM_THRES		0x165c
 
 /* PDMA HW LRO Control Registers */
-#define MTK_PDMA_LRO_CTRL_DW0	0x980
+#define MTK_HW_LRO_DIP_NUM		(mtk_is_netsys_v3_or_greater(eth) ? 4 : 3)
 #define MTK_HW_LRO_RING_NUM		(mtk_is_netsys_v3_or_greater(eth) ? 4 : 3)
+#define MTK_HW_LRO_RING(x)		((x) + (mtk_is_netsys_v3_or_greater(eth) ? 4 : 1))
+#define MTK_HW_LRO_IRQ(x)		((x) + (mtk_is_netsys_v3_or_greater(eth) ? 0 : 1))
+#define MTK_LRO_CRSN_BNW		BIT((mtk_is_netsys_v3_or_greater(eth) ? 22 : 6))
 #define MTK_LRO_EN			BIT(0)
 #define MTK_NON_LRO_MULTI_EN		BIT(2)
 #define MTK_LRO_DLY_INT_EN		BIT(5)
-#define MTK_L3_CKS_UPD_EN		BIT(7)
-#define MTK_L3_CKS_UPD_EN_V2		BIT(19)
+#define MTK_L3_CKS_UPD_EN		BIT(mtk_is_netsys_v3_or_greater(eth) ? 19 : 7)
 #define MTK_LRO_ALT_PKT_CNT_MODE	BIT(21)
-#define MTK_LRO_RING_RELINQUISH_REQ	(0x7 << 26)
-#define MTK_LRO_RING_RELINQUISH_REQ_V2	(0xf << 24)
-#define MTK_LRO_RING_RELINQUISH_DONE	(0x7 << 29)
-#define MTK_LRO_RING_RELINQUISH_DONE_V2	(0xf << 28)
-
-#define MTK_PDMA_LRO_CTRL_DW1	0x984
-#define MTK_PDMA_LRO_CTRL_DW2	0x988
-#define MTK_PDMA_LRO_CTRL_DW3	0x98c
+#define MTK_LRO_RING_RELINQUISH_REQ	(mtk_is_netsys_v3_or_greater(eth) ? 0xf << 24 : 0x7 << 26)
+#define MTK_LRO_RING_RELINQUISH_DONE	(mtk_is_netsys_v3_or_greater(eth) ? 0xf << 28 : 0x7 << 29)
+
+#define MTK_PDMA_LRO_CTRL_DW0	(reg_map->pdma.lro_ctrl_dw0)
+#define MTK_PDMA_LRO_CTRL_DW1	(reg_map->pdma.lro_ctrl_dw0 + 0x04)
+#define MTK_PDMA_LRO_CTRL_DW2	(reg_map->pdma.lro_ctrl_dw0 + 0x08)
+#define MTK_PDMA_LRO_CTRL_DW3	(reg_map->pdma.lro_ctrl_dw0 + 0x0c)
 #define MTK_ADMA_MODE		BIT(15)
 #define MTK_LRO_MIN_RXD_SDL	(MTK_HW_LRO_SDL_REMAIN_ROOM << 16)
 
+#define MTK_CTRL_DW0_SDL_OFFSET	(3)
+#define MTK_CTRL_DW0_SDL_MASK	BITS(3, 18)
+
 #define MTK_RX_DMA_LRO_EN	BIT(8)
 #define MTK_MULTI_EN		BIT(10)
 #define MTK_PDMA_SIZE_8DWORDS	(1 << 4)
 
 /* PDMA RSS Control Registers */
-#define MTK_RX_NAPI_NUM			(4)
+#define MTK_RX_NAPI_NUM			(8)
 #define MTK_RX_RSS_NUM			(eth->soc->rss_num)
 #define MTK_RSS_RING(x)			(x)
 #define MTK_RSS_EN			BIT(0)
@@ -242,11 +249,10 @@
 #define MTK_PDMA_DELAY_PTIME_MASK	0xff
 
 /* PDMA HW LRO Alter Flow Delta Register */
-#define MTK_PDMA_LRO_ALT_SCORE_DELTA	0xa4c
+#define MTK_PDMA_LRO_ALT_SCORE_DELTA	(reg_map->pdma.lro_alt_score_delta)
 
 /* PDMA HW LRO IP Setting Registers */
-#define MTK_LRO_RX_RING0_DIP_DW0	0xb04
-#define MTK_LRO_DIP_DW0_CFG(x)		(MTK_LRO_RX_RING0_DIP_DW0 + (x * 0x40))
+#define MTK_LRO_DIP_DW0_CFG(x)		(reg_map->pdma.lro_ring_dip_dw0 + ((x) * 0x40))
 #define MTK_RING_MYIP_VLD		BIT(9)
 
 /* PDMA HW LRO Ring Control Registers */
@@ -1184,7 +1190,8 @@ enum mkt_eth_capabilities {
 
 #define MT7988_CAPS  (MTK_36BIT_DMA | MTK_GDM1_ESW | MTK_GMAC2_2P5GPHY | \
 		      MTK_MUX_GMAC2_TO_2P5GPHY | MTK_QDMA | MTK_RSTCTRL_PPE1 | \
-		      MTK_RSTCTRL_PPE2 | MTK_SRAM | MTK_PDMA_INT | MTK_RSS)
+		      MTK_RSTCTRL_PPE2 | MTK_SRAM | MTK_PDMA_INT | MTK_RSS | \
+		      MTK_HWLRO)
 
 struct mtk_tx_dma_desc_info {
 	dma_addr_t	addr;
@@ -1459,6 +1466,7 @@ struct mtk_mac {
 
 /* the struct describing the SoC. these are declared in the soc_xyz.c files */
 extern const struct of_device_id of_mtk_match[];
+extern u32 mtk_hwlro_stats_ebl;
 
 static inline bool mtk_is_netsys_v1(struct mtk_eth *eth)
 {
-- 
2.43.0



From stefano.radaelli21 at gmail.com  Sun Dec 14 03:05:23 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Sun, 14 Dec 2025 12:05:23 +0100
Subject: [PATCH v3 0/6] arm64: dts: imx8mp-var-som: align DTS with hardware revision
Message-ID: <20251214110531.9475-1-stefano.r@variscite.com>

This patch series aligns the VAR-SOM-MX8MP device tree with the actual
hardware populated on the System-on-Module, and separates SOM-specific
descriptions from carrier-board-specific ones.

The first three patches move the USDHC2 interface, the PCA9534 GPIO
expander, and the UART2 debug console out of the SOM dtsi, as these
components are not present on the VAR-SOM-MX8MP module itself and are
instead routed on the Symphony carrier board. Their descriptions are
therefore provided in the carrier board DTS, keeping the SOM device
tree limited to on-module hardware.

The remaining patches add support for peripherals that are populated
on the SOM and commonly used across designs, including WiFi/Bluetooth
connectivity, the WM8904 audio codec, and the ADS7846 touchscreen
controller.

Overall, this series ensures a clear separation between SOM and carrier
board responsibilities in the device tree, avoids describing
non-existent hardware on the module, and enables key on-module
features.
v3:
 - Remove unnecessary status property
v2:
 - Move deleted nodes from SOM dts to Symphony carrier board

Stefano Radaelli (6):
  arm64: dts: imx8mp-var-som: Move USDHC2 support to Symphony carrier
  arm64: dts: imx8mp-var-som: Move PCA9534 GPIO expander to Symphony
    carrier
  arm64: dts: imx8mp-var-som: Move UART2 description to Symphony carrier
  arm64: dts: imx8mp-var-som: Add WiFi and Bluetooth support
  arm64: dts: imx8mp-var-som: Add support for WM8904 audio codec
  arm64: dts: imx8mp-var-som: Add support for ADS7846 touchscreen

 .../dts/freescale/imx8mp-var-som-symphony.dts | 145 ++++++++
 .../boot/dts/freescale/imx8mp-var-som.dtsi    | 331 +++++++++++-------
 2 files changed, 355 insertions(+), 121 deletions(-)


base-commit: cb015814f8b6eebcbb8e46e111d108892c5e6821
-- 
2.47.3



From stefano.radaelli21 at gmail.com  Sun Dec 14 03:05:24 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Sun, 14 Dec 2025 12:05:24 +0100
Subject: [PATCH v3 1/6] arm64: dts: imx8mp-var-som: Move USDHC2 support to Symphony carrier
In-Reply-To: <20251214110531.9475-1-stefano.r@variscite.com>
References: <20251214110531.9475-1-stefano.r@variscite.com>
Message-ID: <20251214110531.9475-2-stefano.r@variscite.com>

The VAR-SOM-MX8MP module does not include a microSD slot connected to
USDHC2. The USDHC2 interface is routed only on the Symphony carrier
board, and it may optionally be used or omitted depending on the
customer's carrier design.

Move the USDHC2 node, its regulators, pinctrl groups and related GPIOs
from the SOM device tree to the Symphony carrier DTS, keeping the SOM
description limited to hardware populated on the module.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../dts/freescale/imx8mp-var-som-symphony.dts | 77 +++++++++++++++++++
 .../boot/dts/freescale/imx8mp-var-som.dtsi    | 75 ------------------
 2 files changed, 77 insertions(+), 75 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts b/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
index 36d3eb865202..ea3c193bb684 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
@@ -8,4 +8,81 @@
 / {
 	model = "Variscite VAR-SOM-MX8M-PLUS on Symphony-Board";
 	compatible = "variscite,var-som-mx8mp-symphony", "variscite,var-som-mx8mp", "fsl,imx8mp";
+
+	reg_usdhc2_vmmc: regulator-usdhc2-vmmc {
+		compatible = "regulator-fixed";
+		regulator-name = "VSD_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpios = <&gpio4 22 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		startup-delay-us = <100>;
+		off-on-delay-us = <12000>;
+	};
+
+	reg_usdhc2_vqmmc: regulator-usdhc2-vqmmc {
+		compatible = "regulator-gpio";
+		regulator-name = "VSD_VSEL";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <3300000>;
+		gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>;
+		states = <3300000 0x0 1800000 0x1>;
+		vin-supply = <&ldo5>;
+	};
+};
+
+/* SD-card */
+&usdhc2 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+	cd-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	vqmmc-supply = <&reg_usdhc2_vqmmc>;
+	bus-width = <4>;
+	status = "okay";
+};
+
+&iomuxc {
+	pinctrl_usdhc2_gpio: usdhc2-gpiogrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14                             0x1c4
+			MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22                               0x10
+			MX8MP_IOMUXC_SD2_CD_B__GPIO2_IO12                               0xc0
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK                                0x190
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD                                0x1d0
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0                            0x1d0
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1                            0x1d0
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2                            0x1d0
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3                            0x1d0
+		>;
+	};
+
+	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK                                0x194
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD                                0x1d4
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0                            0x1d4
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1                            0x1d4
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2                            0x1d4
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3                            0x1d4
+		>;
+	};
+
+	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK                                0x196
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD                                0x1d6
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0                            0x1d6
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1                            0x1d6
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2                            0x1d6
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3                            0x1d6
+		>;
+	};
 };
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
index 29f080904482..949d9878f395 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
@@ -35,27 +35,6 @@ memory at 40000000 {
 		      <0x1 0x00000000 0 0xc0000000>;
 	};
 
-	reg_usdhc2_vmmc: regulator-usdhc2-vmmc {
-	        compatible = "regulator-fixed";
-	        regulator-name = "VSD_3V3";
-	        regulator-min-microvolt = <3300000>;
-	        regulator-max-microvolt = <3300000>;
-	        gpios = <&gpio4 22 GPIO_ACTIVE_HIGH>;
-	        enable-active-high;
-	        startup-delay-us = <100>;
-	        off-on-delay-us = <12000>;
-	};
-
-	reg_usdhc2_vqmmc: regulator-usdhc2-vqmmc {
-		compatible = "regulator-gpio";
-		regulator-name = "VSD_VSEL";
-		regulator-min-microvolt = <1800000>;
-		regulator-max-microvolt = <3300000>;
-		gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>;
-		states = <3300000 0x0 1800000 0x1>;
-		vin-supply = <&ldo5>;
-	};
-
 	reg_phy_supply: regulator-phy-supply {
 		compatible = "regulator-fixed";
 		regulator-name = "phy-supply";
@@ -271,19 +250,6 @@ &uart2 {
         status = "okay";
 };
 
-/* SD-card */
-&usdhc2 {
-        pinctrl-names = "default", "state_100mhz", "state_200mhz";
-        pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
-        pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
-        pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
-        cd-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;
-        vmmc-supply = <&reg_usdhc2_vmmc>;
-	vqmmc-supply = <&reg_usdhc2_vqmmc>;
-        bus-width = <4>;
-        status = "okay";
-};
-
 /* eMMC */
 &usdhc3 {
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
@@ -358,47 +324,6 @@ MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX                            0x40
 		>;
 	};
 
-	pinctrl_usdhc2_gpio: usdhc2-gpiogrp {
-	        fsl,pins = <
-	                MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14                             0x1c4
-	                MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22                               0x10
-	                MX8MP_IOMUXC_SD2_CD_B__GPIO2_IO12                               0xc0
-	        >;
-	};
-
-	pinctrl_usdhc2: usdhc2grp {
-	        fsl,pins = <
-	                MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK                                0x190
-	                MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD                                0x1d0
-	                MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0                            0x1d0
-	                MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1                            0x1d0
-	                MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2                            0x1d0
-	                MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3                            0x1d0
-	        >;
-	};
-
-	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
-	        fsl,pins = <
-	                MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK                                0x194
-	                MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD                                0x1d4
-	                MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0                            0x1d4
-	                MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1                            0x1d4
-	                MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2                            0x1d4
-	                MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3                            0x1d4
-	        >;
-	};
-
-	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
-	        fsl,pins = <
-	                MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK                                0x196
-	                MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD                                0x1d6
-	                MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0                            0x1d6
-	                MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1                            0x1d6
-	                MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2                            0x1d6
-	                MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3                            0x1d6
-	        >;
-	};
-
 	pinctrl_usdhc3: usdhc3grp {
 		fsl,pins = <
 			MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK				0x190
-- 
2.47.3



From stefano.radaelli21 at gmail.com  Sun Dec 14 03:05:25 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Sun, 14 Dec 2025 12:05:25 +0100
Subject: [PATCH v3 2/6] arm64: dts: imx8mp-var-som: Move PCA9534 GPIO expander to Symphony carrier
In-Reply-To: <20251214110531.9475-1-stefano.r@variscite.com>
References: <20251214110531.9475-1-stefano.r@variscite.com>
Message-ID: <20251214110531.9475-3-stefano.r@variscite.com>

The VAR-SOM-MX8MP module does not include the PCA9534 GPIO expander nor
the LED connected to it. These components are present only on the
Symphony carrier board and may vary across custom carrier designs.

Move the PCA9534 GPIO expander node and the associated LED definition
from the SOM device tree to the Symphony carrier DTS, ensuring the SOM
dtsi describes only hardware present on the module.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../dts/freescale/imx8mp-var-som-symphony.dts | 50 +++++++++++++++++++
 .../boot/dts/freescale/imx8mp-var-som.dtsi    | 50 -------------------
 2 files changed, 50 insertions(+), 50 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts b/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
index ea3c193bb684..361e6122bdc3 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
@@ -9,6 +9,16 @@ / {
 	model = "Variscite VAR-SOM-MX8M-PLUS on Symphony-Board";
 	compatible = "variscite,var-som-mx8mp-symphony", "variscite,var-som-mx8mp", "fsl,imx8mp";
 
+	gpio-leds {
+		compatible = "gpio-leds";
+
+		led-0 {
+			function = LED_FUNCTION_POWER;
+			gpios = <&pca9534 0 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+	};
+
 	reg_usdhc2_vmmc: regulator-usdhc2-vmmc {
 		compatible = "regulator-fixed";
 		regulator-name = "VSD_3V3";
@@ -31,6 +41,33 @@ reg_usdhc2_vqmmc: regulator-usdhc2-vqmmc {
 	};
 };
 
+&i2c3 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	status = "okay";
+
+	/* GPIO expander */
+	pca9534: gpio at 20 {
+		compatible = "nxp,pca9534";
+		reg = <0x20>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_pca9534>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <15 IRQ_TYPE_EDGE_FALLING>;
+		wakeup-source;
+
+		usb3-sata-sel-hog {
+			gpio-hog;
+			gpios = <4 0>;
+			output-low;
+			line-name = "usb3_sata_sel";
+		};
+	};
+};
+
 /* SD-card */
 &usdhc2 {
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
@@ -45,6 +82,19 @@ &usdhc2 {
 };
 
 &iomuxc {
+	pinctrl_i2c3: i2c3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL                                 0x400001c2
+			MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA                                 0x400001c2
+		>;
+	};
+
+	pinctrl_pca9534: pca9534grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO15__GPIO1_IO15                             0xc0
+		>;
+	};
+
 	pinctrl_usdhc2_gpio: usdhc2-gpiogrp {
 		fsl,pins = <
 			MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14                             0x1c4
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
index 949d9878f395..158a78ec9656 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
@@ -19,16 +19,6 @@ chosen {
 		stdout-path = &uart2;
 	};
 
-	gpio-leds {
-	        compatible = "gpio-leds";
-
-	        led-0 {
-	                function = LED_FUNCTION_POWER;
-	                gpios = <&pca9534 0 GPIO_ACTIVE_HIGH>;
-	                linux,default-trigger = "heartbeat";
-	        };
-	};
-
 	memory at 40000000 {
 		device_type = "memory";
 		reg = <0x0 0x40000000 0 0xc0000000>,
@@ -216,33 +206,6 @@ ldo5: LDO5 {
 	};
 };
 
-&i2c3 {
-        clock-frequency = <400000>;
-        pinctrl-names = "default";
-        pinctrl-0 = <&pinctrl_i2c3>;
-        status = "okay";
-
-	/* GPIO expander */
-	pca9534: gpio at 20 {
-	        compatible = "nxp,pca9534";
-	        reg = <0x20>;
-	        pinctrl-names = "default";
-	        pinctrl-0 = <&pinctrl_pca9534>;
-	        gpio-controller;
-	        #gpio-cells = <2>;
-	        interrupt-parent = <&gpio1>;
-	        interrupts = <15 IRQ_TYPE_EDGE_FALLING>;
-	        wakeup-source;
-
-	        usb3-sata-sel-hog {
-	                gpio-hog;
-	                gpios = <4 0>;
-	                output-low;
-	                line-name = "usb3_sata_sel";
-	        };
-	};
-};
-
 /* Console */
 &uart2 {
         pinctrl-names = "default";
@@ -298,19 +261,6 @@ MX8MP_IOMUXC_SD1_DATA5__I2C1_SDA				0x400001c2
 		>;
 	};
 
-	pinctrl_i2c3: i2c3grp {
-	        fsl,pins = <
-	                MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL                                 0x400001c2
-	                MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA                                 0x400001c2
-	        >;
-	};
-
-	pinctrl_pca9534: pca9534grp {
-	        fsl,pins = <
-	                MX8MP_IOMUXC_GPIO1_IO15__GPIO1_IO15                             0xc0
-	        >;
-	};
-
 	pinctrl_pmic: pmicgrp {
 		fsl,pins = <
 			MX8MP_IOMUXC_SPDIF_RX__GPIO5_IO04				0x1c0
-- 
2.47.3



From stefano.radaelli21 at gmail.com  Sun Dec 14 03:05:26 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Sun, 14 Dec 2025 12:05:26 +0100
Subject: [PATCH v3 3/6] arm64: dts: imx8mp-var-som: Move UART2 description to Symphony carrier
In-Reply-To: <20251214110531.9475-1-stefano.r@variscite.com>
References: <20251214110531.9475-1-stefano.r@variscite.com>
Message-ID: <20251214110531.9475-4-stefano.r@variscite.com>

The VAR-SOM-MX8MP module does not provide an onboard debug console.
UART2 is routed and exposed only on the Symphony carrier board, while
custom carrier designs may choose to expose a different UART.

Move the UART2 node from the SOM device tree to the
imx8mp-var-som-symphony.dts, keeping the SOM dtsi limited to hardware
present on the module itself.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../dts/freescale/imx8mp-var-som-symphony.dts  | 18 ++++++++++++++++++
 .../boot/dts/freescale/imx8mp-var-som.dtsi     | 18 ------------------
 2 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts b/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
index 361e6122bdc3..291f65e36865 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
@@ -9,6 +9,10 @@ / {
 	model = "Variscite VAR-SOM-MX8M-PLUS on Symphony-Board";
 	compatible = "variscite,var-som-mx8mp-symphony", "variscite,var-som-mx8mp", "fsl,imx8mp";
 
+	chosen {
+		stdout-path = &uart2;
+	};
+
 	gpio-leds {
 		compatible = "gpio-leds";
 
@@ -68,6 +72,13 @@ usb3-sata-sel-hog {
 	};
 };
 
+/* Console */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2>;
+	status = "okay";
+};
+
 /* SD-card */
 &usdhc2 {
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
@@ -95,6 +106,13 @@ MX8MP_IOMUXC_GPIO1_IO15__GPIO1_IO15                             0xc0
 		>;
 	};
 
+	pinctrl_uart2: uart2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX                            0x40
+			MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX                            0x40
+		>;
+	};
+
 	pinctrl_usdhc2_gpio: usdhc2-gpiogrp {
 		fsl,pins = <
 			MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14                             0x1c4
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
index 158a78ec9656..5bba91dcef17 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
@@ -15,10 +15,6 @@
 / {
 	model = "Variscite VAR-SOM-MX8M Plus module";
 
-	chosen {
-		stdout-path = &uart2;
-	};
-
 	memory at 40000000 {
 		device_type = "memory";
 		reg = <0x0 0x40000000 0 0xc0000000>,
@@ -206,13 +202,6 @@ ldo5: LDO5 {
 	};
 };
 
-/* Console */
-&uart2 {
-        pinctrl-names = "default";
-        pinctrl-0 = <&pinctrl_uart2>;
-        status = "okay";
-};
-
 /* eMMC */
 &usdhc3 {
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
@@ -267,13 +256,6 @@ MX8MP_IOMUXC_SPDIF_RX__GPIO5_IO04				0x1c0
 		>;
 	};
 
-	pinctrl_uart2: uart2grp {
-	        fsl,pins = <
-		        MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX                            0x40
-			MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX                            0x40
-		>;
-	};
-
 	pinctrl_usdhc3: usdhc3grp {
 		fsl,pins = <
 			MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK				0x190
-- 
2.47.3



From stefano.radaelli21 at gmail.com  Sun Dec 14 03:05:27 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Sun, 14 Dec 2025 12:05:27 +0100
Subject: [PATCH v3 4/6] arm64: dts: imx8mp-var-som: Add WiFi and Bluetooth support
In-Reply-To: <20251214110531.9475-1-stefano.r@variscite.com>
References: <20251214110531.9475-1-stefano.r@variscite.com>
Message-ID: <20251214110531.9475-5-stefano.r@variscite.com>

Add device tree nodes for the WiFi and Bluetooth module mounted on the
VAR-SOM-MX8MP. The module can be based on either the NXP IW612 or IW611
chipset, depending on the configuration chosen by the customer.

Regardless of the chipset used, WiFi communicates over SDIO and Bluetooth
over UART.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../boot/dts/freescale/imx8mp-var-som.dtsi    | 92 +++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
index 5bba91dcef17..2c49d53e30c3 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
@@ -21,6 +21,14 @@ memory at 40000000 {
 		      <0x1 0x00000000 0 0xc0000000>;
 	};
 
+	iw61x_pwrseq: wifi-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		post-power-on-delay-ms = <100>;
+		power-off-delay-us = <10000>;
+		reset-gpios = <&gpio2 8 GPIO_ACTIVE_LOW>, /* WIFI_RESET */
+			      <&gpio2 19 GPIO_ACTIVE_LOW>; /* WIFI_PWR_EN */
+	};
+
 	reg_phy_supply: regulator-phy-supply {
 		compatible = "regulator-fixed";
 		regulator-name = "phy-supply";
@@ -202,6 +210,33 @@ ldo5: LDO5 {
 	};
 };
 
+/* BT */
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart3>, <&pinctrl_bluetooth>;
+	assigned-clocks = <&clk IMX8MP_CLK_UART3>;
+	assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_80M>;
+	uart-has-rtscts;
+	status = "okay";
+
+	bluetooth {
+		compatible = "nxp,88w8987-bt";
+	};
+};
+
+/* WIFI */
+&usdhc1 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc1>, <&pinctrl_wifi>;
+	pinctrl-1 = <&pinctrl_usdhc1_100mhz>, <&pinctrl_wifi>;
+	pinctrl-2 = <&pinctrl_usdhc1_200mhz>, <&pinctrl_wifi>;
+	bus-width = <4>;
+	non-removable;
+	keep-power-in-suspend;
+	mmc-pwrseq = <&iw61x_pwrseq>;
+	status = "okay";
+};
+
 /* eMMC */
 &usdhc3 {
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
@@ -222,6 +257,14 @@ &wdog1 {
 
 &iomuxc {
 
+	pinctrl_bluetooth: bluetoothgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_DATA7__GPIO2_IO09                              0xc0
+			MX8MP_IOMUXC_GPIO1_IO04__GPIO1_IO04                             0xc0
+			MX8MP_IOMUXC_SD1_RESET_B__GPIO2_IO10                            0xc0
+		>;
+	};
+
 	pinctrl_eqos: eqosgrp {
 		fsl,pins = <
 			MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC				0x2
@@ -256,6 +299,48 @@ MX8MP_IOMUXC_SPDIF_RX__GPIO5_IO04				0x1c0
 		>;
 	};
 
+	pinctrl_uart3: uart3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_ECSPI1_SCLK__UART3_DCE_RX                          0x140
+			MX8MP_IOMUXC_ECSPI1_MOSI__UART3_DCE_TX                          0x140
+			MX8MP_IOMUXC_ECSPI1_MISO__UART3_DCE_CTS                         0x140
+			MX8MP_IOMUXC_ECSPI1_SS0__UART3_DCE_RTS                          0x140
+		>;
+	};
+
+	pinctrl_usdhc1: usdhc1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK                                0x190
+			MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD                                0x1d0
+			MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0                            0x1d0
+			MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1                            0x1d0
+			MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2                            0x1d0
+			MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3                            0x1d0
+		>;
+	};
+
+	pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK                                0x194
+			MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD                                0x1d4
+			MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0                            0x1d4
+			MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1                            0x1d4
+			MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2                            0x1d4
+			MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3                            0x1d4
+		>;
+	};
+
+	pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK                                0x196
+			MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD                                0x1d6
+			MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0                            0x1d6
+			MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1                            0x1d6
+			MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2                            0x1d6
+			MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3                            0x1d6
+		>;
+	};
+
 	pinctrl_usdhc3: usdhc3grp {
 		fsl,pins = <
 			MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK				0x190
@@ -309,4 +394,11 @@ pinctrl_wdog: wdoggrp {
 			MX8MP_IOMUXC_GPIO1_IO02__WDOG1_WDOG_B				0xc6
 		>;
 	};
+
+	pinctrl_wifi: wifigrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_DATA6__GPIO2_IO08                              0xc0
+			MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19                            0xc0
+		>;
+	};
 };
-- 
2.47.3



From stefano.radaelli21 at gmail.com  Sun Dec 14 03:05:28 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Sun, 14 Dec 2025 12:05:28 +0100
Subject: [PATCH v3 5/6] arm64: dts: imx8mp-var-som: Add support for WM8904 audio codec
In-Reply-To: <20251214110531.9475-1-stefano.r@variscite.com>
References: <20251214110531.9475-1-stefano.r@variscite.com>
Message-ID: <20251214110531.9475-6-stefano.r@variscite.com>

The VAR-SOM-MX8MP can integrate the WM8904, a high-performance
ultra-low-power stereo codec optimized for portable audio applications.

This patch adds the WM8904 device to the appropriate I2C bus, enables
the SAI peripheral, and introduces the sound node to expose the
sound card to the system.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../boot/dts/freescale/imx8mp-var-som.dtsi    | 94 +++++++++++++++++++
 1 file changed, 94 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
index 2c49d53e30c3..6da5df11c44a 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
@@ -29,6 +29,14 @@ iw61x_pwrseq: wifi-pwrseq {
 			      <&gpio2 19 GPIO_ACTIVE_LOW>; /* WIFI_PWR_EN */
 	};
 
+	reg_audio_supply: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "wm8904-supply";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
 	reg_phy_supply: regulator-phy-supply {
 		compatible = "regulator-fixed";
 		regulator-name = "phy-supply";
@@ -46,6 +54,34 @@ reg_phy_vddio: regulator-phy-vddio {
 		regulator-min-microvolt = <1800000>;
 		regulator-max-microvolt = <1800000>;
 	};
+
+	sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,bitclock-master = <&codec_dai>;
+		simple-audio-card,format = "i2s";
+		simple-audio-card,frame-master = <&codec_dai>;
+		simple-audio-card,mclk-fs = <256>;
+		simple-audio-card,name = "wm8904-audio";
+		simple-audio-card,routing =
+			"Headphone Jack", "HPOUTL",
+			"Headphone Jack", "HPOUTR",
+			"IN2L", "Line In Jack",
+			"IN2R", "Line In Jack",
+			"IN1L", "Microphone Jack",
+			"IN1R", "Microphone Jack";
+		simple-audio-card,widgets =
+			"Microphone", "Microphone Jack",
+			"Headphone", "Headphone Jack",
+			"Line", "Line In Jack";
+
+		codec_dai: simple-audio-card,codec {
+			sound-dai = <&wm8904>;
+		};
+
+		simple-audio-card,cpu {
+			sound-dai = <&sai3>;
+		};
+	};
 };
 
 &A53_0 {
@@ -208,6 +244,52 @@ ldo5: LDO5 {
 			};
 		};
 	};
+
+	wm8904: audio-codec at 1a {
+		compatible = "wlf,wm8904";
+		reg = <0x1a>;
+		#sound-dai-cells = <0>;
+		clocks = <&audio_blk_ctrl IMX8MP_CLK_AUDIOMIX_SAI3_MCLK1>;
+		clock-names = "mclk";
+		AVDD-supply = <&reg_audio_supply>;
+		CPVDD-supply = <&reg_audio_supply>;
+		DBVDD-supply = <&reg_audio_supply>;
+		DCVDD-supply = <&reg_audio_supply>;
+		MICVDD-supply = <&reg_audio_supply>;
+		wlf,drc-cfg-names = "default", "peaklimiter", "tradition",
+				    "soft", "music";
+		/*
+		 * Config registers per name, respectively:
+		 * KNEE_IP = 0,   KNEE_OP = 0,     HI_COMP = 1,   LO_COMP = 1
+		 * KNEE_IP = -24, KNEE_OP = -6,    HI_COMP = 1/4, LO_COMP = 1
+		 * KNEE_IP = -42, KNEE_OP = -3,    HI_COMP = 0,   LO_COMP = 1
+		 * KNEE_IP = -45, KNEE_OP = -9,    HI_COMP = 1/8, LO_COMP = 1
+		 * KNEE_IP = -30, KNEE_OP = -10.5, HI_COMP = 1/4, LO_COMP = 1
+		 */
+		wlf,drc-cfg-regs = /bits/ 16 <0x01af 0x3248 0x0000 0x0000>,
+				   /bits/ 16 <0x04af 0x324b 0x0010 0x0408>,
+				   /bits/ 16 <0x04af 0x324b 0x0028 0x0704>,
+				   /bits/ 16 <0x04af 0x324b 0x0018 0x078c>,
+				   /bits/ 16 <0x04af 0x324b 0x0010 0x050e>;
+		/* GPIO1 = DMIC_CLK, don't touch others */
+		wlf,gpio-cfg = <0x0018>, <0xffff>, <0xffff>, <0xffff>;
+	};
+};
+
+&sai3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_sai3>;
+	assigned-clocks = <&clk IMX8MP_CLK_SAI3>;
+	assigned-clock-parents = <&clk IMX8MP_AUDIO_PLL1_OUT>;
+	assigned-clock-rates = <11536000>;
+	clocks = <&audio_blk_ctrl IMX8MP_CLK_AUDIOMIX_SAI3_IPG>,
+		<&clk IMX8MP_CLK_DUMMY>,
+		<&audio_blk_ctrl IMX8MP_CLK_AUDIOMIX_SAI3_MCLK1>,
+		<&clk IMX8MP_CLK_DUMMY>,
+		<&clk IMX8MP_CLK_DUMMY>;
+	clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
+	fsl,sai-mclk-direction-output;
+	status = "okay";
 };
 
 /* BT */
@@ -299,6 +381,18 @@ MX8MP_IOMUXC_SPDIF_RX__GPIO5_IO04				0x1c0
 		>;
 	};
 
+	pinctrl_sai3: sai3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI3_TXFS__AUDIOMIX_SAI3_TX_SYNC                   0xd6
+			MX8MP_IOMUXC_SAI3_TXC__AUDIOMIX_SAI3_TX_BCLK                    0xd6
+			MX8MP_IOMUXC_SAI3_RXD__AUDIOMIX_SAI3_RX_DATA00                  0xd6
+			MX8MP_IOMUXC_SAI3_TXD__AUDIOMIX_SAI3_TX_DATA00                  0xd6
+			MX8MP_IOMUXC_SAI3_MCLK__AUDIOMIX_SAI3_MCLK                      0xd6
+			MX8MP_IOMUXC_SAI3_RXFS__AUDIOMIX_SAI3_RX_SYNC                   0xd6
+			MX8MP_IOMUXC_SAI3_RXC__AUDIOMIX_SAI3_RX_BCLK                    0xd6
+		>;
+	};
+
 	pinctrl_uart3: uart3grp {
 		fsl,pins = <
 			MX8MP_IOMUXC_ECSPI1_SCLK__UART3_DCE_RX                          0x140
-- 
2.47.3



From stefano.radaelli21 at gmail.com  Sun Dec 14 03:05:29 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Sun, 14 Dec 2025 12:05:29 +0100
Subject: [PATCH v3 6/6] arm64: dts: imx8mp-var-som: Add support for ADS7846 touchscreen
In-Reply-To: <20251214110531.9475-1-stefano.r@variscite.com>
References: <20251214110531.9475-1-stefano.r@variscite.com>
Message-ID: <20251214110531.9475-7-stefano.r@variscite.com>

The VAR-SOM-MX8MP integrates an ADS7846 resistive touchscreen controller.
The controller is physically located on the SOM, and its signals are
routed to the SOM pins, allowing carrier boards to make use of it.

This patch adds the ADS7846 node and the appropriate SPI controller.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../boot/dts/freescale/imx8mp-var-som.dtsi    | 46 +++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
index 6da5df11c44a..8ab0e32879cc 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
@@ -100,6 +100,37 @@ &A53_3 {
 	cpu-supply = <&buck2>;
 };
 
+&ecspi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi1>;
+	cs-gpios = <&gpio5 17 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	/* Resistive touch controller */
+	ads7846: touchscreen at 0 {
+		compatible = "ti,ads7846";
+		reg = <0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_restouch>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <12 IRQ_TYPE_EDGE_FALLING>;
+		spi-max-frequency = <1500000>;
+		pendown-gpio = <&gpio1 12 GPIO_ACTIVE_LOW>;
+		ti,x-min = /bits/ 16 <125>;
+		ti,x-max = /bits/ 16 <4008>;
+		ti,y-min = /bits/ 16 <282>;
+		ti,y-max = /bits/ 16 <3864>;
+		ti,x-plate-ohms = /bits/ 16 <180>;
+		ti,pressure-max = /bits/ 16 <255>;
+		ti,debounce-max = /bits/ 16 <10>;
+		ti,debounce-tol = /bits/ 16 <3>;
+		ti,debounce-rep = /bits/ 16 <1>;
+		ti,settle-delay-usec = /bits/ 16 <150>;
+		ti,keep-vref-on;
+		wakeup-source;
+	};
+};
+
 &eqos {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_eqos>;
@@ -347,6 +378,15 @@ MX8MP_IOMUXC_SD1_RESET_B__GPIO2_IO10                            0xc0
 		>;
 	};
 
+	pinctrl_ecspi1: ecspi1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C1_SCL__ECSPI1_SCLK                              0x12
+			MX8MP_IOMUXC_I2C1_SDA__ECSPI1_MOSI                              0x12
+			MX8MP_IOMUXC_I2C2_SCL__ECSPI1_MISO                              0x12
+			MX8MP_IOMUXC_I2C2_SDA__GPIO5_IO17                               0x12
+		>;
+	};
+
 	pinctrl_eqos: eqosgrp {
 		fsl,pins = <
 			MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC				0x2
@@ -381,6 +421,12 @@ MX8MP_IOMUXC_SPDIF_RX__GPIO5_IO04				0x1c0
 		>;
 	};
 
+	pinctrl_restouch: restouchgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO12__GPIO1_IO12                             0xc0
+		>;
+	};
+
 	pinctrl_sai3: sai3grp {
 		fsl,pins = <
 			MX8MP_IOMUXC_SAI3_TXFS__AUDIOMIX_SAI3_TX_SYNC                   0xd6
-- 
2.47.3



From linusw at kernel.org  Sun Dec 14 03:14:12 2025
From: linusw at kernel.org (Linus Walleij)
Date: Sun, 14 Dec 2025 12:14:12 +0100
Subject: [PATCH 0/4] drm: Revert and fix enable/disable sequence
In-Reply-To: <3b13c7a2-f7e6-49fd-b3bb-3e0a1fe9acf3@ideasonboard.com>
References: <20251205-drm-seq-fix-v1-0-fda68fa1b3de@ideasonboard.com> <3b13c7a2-f7e6-49fd-b3bb-3e0a1fe9acf3@ideasonboard.com>
Message-ID: <CAD++jLk8-0Rkh16T+R1dh6=e_f9U1i=AKOk1Y8dLGV4bxzRtFg@mail.gmail.com>

On Fri, Dec 12, 2025 at 3:21?PM Tomi Valkeinen
<tomi.valkeinen at ideasonboard.com> wrote:
> On 05/12/2025 11:51, Tomi Valkeinen wrote:
> > Changing the enable/disable sequence in commit c9b1150a68d9
> > ("drm/atomic-helper: Re-order bridge chain pre-enable and post-disable")
> > has caused regressions on multiple platforms: R-Car, MCDE, Rockchip.
> >
> > This is an alternate series to Linus' series:
> >
> > https://lore.kernel.org/all/20251202-mcde-drm-regression-thirdfix-v6-0-f1bffd4ec0fa%40kernel.org/
> >
> > This series first reverts the original commit and reverts a fix for
> > mediatek which is no longer needed. It then exposes helper functions
> > from DRM core, and finally implements the new sequence only in the tidss
> > driver.
> >
> > There is one more fix in upstream for the original commit, commit
> > 5d91394f2361 ("drm/exynos: fimd: Guard display clock control with
> > runtime PM calls"), but I have not reverted that one as it looks like a
> > valid patch in its own.
> >
> > I added Cc stable v6.17+ to all patches, but I didn't add Fixes tags, as
> > I wasn't sure what should they point to. But I could perhaps add Fixes:
> > <original commit> to all of these.

> There has been no comments, so I assume this is the way to go.
>
> Should we merge this series as a fix for 6.18 rcs?

Too late now, so let's merge it as a fix for v6.19 rcs!

Yours,
Linus Walleij


From yeoreum.yun at arm.com  Sun Dec 14 03:22:39 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Sun, 14 Dec 2025 11:22:39 +0000
Subject: [PATCH v11 RESEND 0/9] support FEAT_LSUI
Message-ID: <20251214112248.901769-1-yeoreum.yun@arm.com>

Since Armv9.6, FEAT_LSUI supplies the load/store instructions for
previleged level to access to access user memory without clearing
PSTATE.PAN bit.

This patchset support FEAT_LSUI and applies in futex atomic operation
and user_swpX emulation where can replace from ldxr/st{l}xr
pair implmentation with clearing PSTATE.PAN bit to correspondant
load/store unprevileged atomic operation without clearing PSTATE.PAN bit.

This patch based on v6.19-rc1


Patch Sequences
================

Patch #1 adds cpufeature for FEAT_LSUI

Patch #2-#3 expose FEAT_LSUI to guest

Patch #4 adds Kconfig for FEAT_LSUI

Patch #5-#6 support futex atomic-op with FEAT_LSUI

Patch #7-#9 support user_swpX emulation with FEAT_LSUI


Patch History
==============
from v10 to v11:
  - rebase to v6.19-rc1
  - use cast instruction to emulate deprecated swpb instruction
  - https://lore.kernel.org/all/20251103163224.818353-1-yeoreum.yun at arm.com/

from v9 to v10:
  - apply FEAT_LSUI to user_swpX emulation.
  - add test coverage for LSUI bit in ID_AA64ISAR3_EL1
  - rebase to v6.18-rc4
  - https://lore.kernel.org/all/20250922102244.2068414-1-yeoreum.yun at arm.com/

from v8 to v9:
  - refotoring __lsui_cmpxchg64()
  - rebase to v6.17-rc7
  - https://lore.kernel.org/all/20250917110838.917281-1-yeoreum.yun at arm.com/

from v7 to v8:
  - implements futex_atomic_eor() and futex_atomic_cmpxchg() with casalt
    with C helper.
  - Drop the small optimisation on ll/sc futex_atomic_set operation.
  - modify some commit message.
  - https://lore.kernel.org/all/20250816151929.197589-1-yeoreum.yun at arm.com/

from v6 to v7:
  - wrap FEAT_LSUI with CONFIG_AS_HAS_LSUI in cpufeature
  - remove unnecessary addition of indentation.
  - remove unnecessary mte_tco_enable()/disable() on LSUI operation.
  - https://lore.kernel.org/all/20250811163635.1562145-1-yeoreum.yun at arm.com/

from v5 to v6:
  - rebase to v6.17-rc1
  - https://lore.kernel.org/all/20250722121956.1509403-1-yeoreum.yun at arm.com/

from v4 to v5:
  - remove futex_ll_sc.h futext_lsui and lsui.h and move them to futex.h
  - reorganize the patches.
  - https://lore.kernel.org/all/20250721083618.2743569-1-yeoreum.yun at arm.com/

from v3 to v4:
  - rebase to v6.16-rc7
  - modify some patch's title.
  - https://lore.kernel.org/all/20250617183635.1266015-1-yeoreum.yun at arm.com/

from v2 to v3:
  - expose FEAT_LUSI to guest
  - add help section for LUSI Kconfig
  - https://lore.kernel.org/all/20250611151154.46362-1-yeoreum.yun at arm.com/

from v1 to v2:
  - remove empty v9.6 menu entry
  - locate HAS_LUSI in cpucaps in order
  - https://lore.kernel.org/all/20250611104916.10636-1-yeoreum.yun at arm.com/


Yeoreum Yun (9):
  arm64: cpufeature: add FEAT_LSUI
  KVM: arm64: expose FEAT_LSUI to guest
  KVM: arm64: kselftest: set_id_regs: add test for FEAT_LSUI
  arm64: Kconfig: Detect toolchain support for LSUI
  arm64: futex: refactor futex atomic operation
  arm64: futex: support futex with FEAT_LSUI
  arm64: separate common LSUI definitions into lsui.h
  arm64: armv8_deprecated: convert user_swpX to inline function
  arm64: armv8_deprecated: apply FEAT_LSUI for swpX emulation.

 arch/arm64/Kconfig                            |   5 +
 arch/arm64/include/asm/futex.h                | 291 +++++++++++++++---
 arch/arm64/include/asm/lsui.h                 |  25 ++
 arch/arm64/kernel/armv8_deprecated.c          | 111 +++++--
 arch/arm64/kernel/cpufeature.c                |  10 +
 arch/arm64/kvm/sys_regs.c                     |   3 +-
 arch/arm64/tools/cpucaps                      |   1 +
 .../testing/selftests/kvm/arm64/set_id_regs.c |   1 +
 8 files changed, 381 insertions(+), 66 deletions(-)
 create mode 100644 arch/arm64/include/asm/lsui.h


base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



From yeoreum.yun at arm.com  Sun Dec 14 03:22:40 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Sun, 14 Dec 2025 11:22:40 +0000
Subject: [PATCH v11 RESEND 1/9] arm64: cpufeature: add FEAT_LSUI
In-Reply-To: <20251214112248.901769-1-yeoreum.yun@arm.com>
References: <20251214112248.901769-1-yeoreum.yun@arm.com>
Message-ID: <20251214112248.901769-2-yeoreum.yun@arm.com>

Since Armv9.6, FEAT_LSUI provides load/store instructions
that allow privileged code to access user memory without
clearing the PSTATE.PAN bit.

Add CPU feature detection for FEAT_LSUI.

Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
Reviewed-by: Catalin Marinas <catalin.marinas at arm.com>
---
 arch/arm64/kernel/cpufeature.c | 10 ++++++++++
 arch/arm64/tools/cpucaps       |  1 +
 2 files changed, 11 insertions(+)

diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index c840a93b9ef9..4c75220e53a1 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -280,6 +280,7 @@ static const struct arm64_ftr_bits ftr_id_aa64isar2[] = {

 static const struct arm64_ftr_bits ftr_id_aa64isar3[] = {
 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64ISAR3_EL1_FPRCVT_SHIFT, 4, 0),
+	ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64ISAR3_EL1_LSUI_SHIFT, 4, ID_AA64ISAR3_EL1_LSUI_NI),
 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64ISAR3_EL1_LSFE_SHIFT, 4, 0),
 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64ISAR3_EL1_FAMINMAX_SHIFT, 4, 0),
 	ARM64_FTR_END,
@@ -3148,6 +3149,15 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
 		.matches = has_cpuid_feature,
 		ARM64_CPUID_FIELDS(ID_AA64MMFR1_EL1, XNX, IMP)
 	},
+#ifdef CONFIG_AS_HAS_LSUI
+	{
+		.desc = "Unprivileged Load Store Instructions (LSUI)",
+		.capability = ARM64_HAS_LSUI,
+		.type = ARM64_CPUCAP_SYSTEM_FEATURE,
+		.matches = has_cpuid_feature,
+		ARM64_CPUID_FIELDS(ID_AA64ISAR3_EL1, LSUI, IMP)
+	},
+#endif
 	{},
 };

diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps
index 0fac75f01534..4b2f7f3f2b80 100644
--- a/arch/arm64/tools/cpucaps
+++ b/arch/arm64/tools/cpucaps
@@ -46,6 +46,7 @@ HAS_HCX
 HAS_LDAPR
 HAS_LPA2
 HAS_LSE_ATOMICS
+HAS_LSUI
 HAS_MOPS
 HAS_NESTED_VIRT
 HAS_BBML2_NOABORT
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



From yeoreum.yun at arm.com  Sun Dec 14 03:22:41 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Sun, 14 Dec 2025 11:22:41 +0000
Subject: [PATCH v11 RESEND 2/9] KVM: arm64: expose FEAT_LSUI to guest
In-Reply-To: <20251214112248.901769-1-yeoreum.yun@arm.com>
References: <20251214112248.901769-1-yeoreum.yun@arm.com>
Message-ID: <20251214112248.901769-3-yeoreum.yun@arm.com>

expose FEAT_LSUI to guest.

Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
Acked-by: Marc Zyngier <maz at kernel.org>
Reviewed-by: Catalin Marinas <catalin.marinas at arm.com>
---
 arch/arm64/kvm/sys_regs.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index c8fd7c6a12a1..fa34910b22ae 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1805,7 +1805,7 @@ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu,
 		break;
 	case SYS_ID_AA64ISAR3_EL1:
 		val &= ID_AA64ISAR3_EL1_FPRCVT | ID_AA64ISAR3_EL1_LSFE |
-			ID_AA64ISAR3_EL1_FAMINMAX;
+			ID_AA64ISAR3_EL1_FAMINMAX | ID_AA64ISAR3_EL1_LSUI;
 		break;
 	case SYS_ID_AA64MMFR2_EL1:
 		val &= ~ID_AA64MMFR2_EL1_CCIDX_MASK;
@@ -3249,6 +3249,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 					ID_AA64ISAR2_EL1_GPA3)),
 	ID_WRITABLE(ID_AA64ISAR3_EL1, (ID_AA64ISAR3_EL1_FPRCVT |
 				       ID_AA64ISAR3_EL1_LSFE |
+				       ID_AA64ISAR3_EL1_LSUI |
 				       ID_AA64ISAR3_EL1_FAMINMAX)),
 	ID_UNALLOCATED(6,4),
 	ID_UNALLOCATED(6,5),
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



From yeoreum.yun at arm.com  Sun Dec 14 03:22:42 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Sun, 14 Dec 2025 11:22:42 +0000
Subject: [PATCH v11 RESEND 3/9] KVM: arm64: kselftest: set_id_regs: add test for FEAT_LSUI
In-Reply-To: <20251214112248.901769-1-yeoreum.yun@arm.com>
References: <20251214112248.901769-1-yeoreum.yun@arm.com>
Message-ID: <20251214112248.901769-4-yeoreum.yun@arm.com>

Add test coverage for FEAT_LSUI.

Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
Reviewed-by: Mark Brown <broonie at kernel.org>
---
 tools/testing/selftests/kvm/arm64/set_id_regs.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tools/testing/selftests/kvm/arm64/set_id_regs.c b/tools/testing/selftests/kvm/arm64/set_id_regs.c
index c4815d365816..0b1714aa127c 100644
--- a/tools/testing/selftests/kvm/arm64/set_id_regs.c
+++ b/tools/testing/selftests/kvm/arm64/set_id_regs.c
@@ -125,6 +125,7 @@ static const struct reg_ftr_bits ftr_id_aa64isar2_el1[] = {

 static const struct reg_ftr_bits ftr_id_aa64isar3_el1[] = {
 	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR3_EL1, FPRCVT, 0),
+	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR3_EL1, LSUI, 0),
 	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR3_EL1, LSFE, 0),
 	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR3_EL1, FAMINMAX, 0),
 	REG_FTR_END,
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



From yeoreum.yun at arm.com  Sun Dec 14 03:22:43 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Sun, 14 Dec 2025 11:22:43 +0000
Subject: [PATCH v11 RESEND 4/9] arm64: Kconfig: Detect toolchain support for LSUI
In-Reply-To: <20251214112248.901769-1-yeoreum.yun@arm.com>
References: <20251214112248.901769-1-yeoreum.yun@arm.com>
Message-ID: <20251214112248.901769-5-yeoreum.yun@arm.com>

Since Armv9.6, FEAT_LSUI supplies the load/store instructions for
previleged level to access to access user memory without clearing
PSTATE.PAN bit.
It's enough to add CONFIG_AS_HAS_LSUI only because the code for LSUI uses
individual `.arch_extension` entries.

Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
Reviewed-by: Catalin Marinas <catalin.marinas at arm.com>
---
 arch/arm64/Kconfig | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 93173f0a09c7..36e87a1a1b5c 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -2227,6 +2227,11 @@ config ARM64_GCS

 endmenu # "ARMv9.4 architectural features"

+config AS_HAS_LSUI
+	def_bool $(as-instr,.arch_extension lsui)
+	help
+	  Supported by LLVM 20+ and binutils 2.45+.
+
 config ARM64_SVE
 	bool "ARM Scalable Vector Extension support"
 	default y
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



From yeoreum.yun at arm.com  Sun Dec 14 03:22:44 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Sun, 14 Dec 2025 11:22:44 +0000
Subject: [PATCH v11 RESEND 5/9] arm64: futex: refactor futex atomic operation
In-Reply-To: <20251214112248.901769-1-yeoreum.yun@arm.com>
References: <20251214112248.901769-1-yeoreum.yun@arm.com>
Message-ID: <20251214112248.901769-6-yeoreum.yun@arm.com>

Refactor futex atomic operations using ll/sc method with
clearing PSTATE.PAN to prepare to apply FEAT_LSUI on them.

Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
Reviewed-by: Catalin Marinas <catalin.marinas at arm.com>
---
 arch/arm64/include/asm/futex.h | 128 +++++++++++++++++++++------------
 1 file changed, 82 insertions(+), 46 deletions(-)

diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h
index bc06691d2062..f8cb674bdb3f 100644
--- a/arch/arm64/include/asm/futex.h
+++ b/arch/arm64/include/asm/futex.h
@@ -7,17 +7,21 @@

 #include <linux/futex.h>
 #include <linux/uaccess.h>
+#include <linux/stringify.h>

 #include <asm/errno.h>

 #define FUTEX_MAX_LOOPS	128 /* What's the largest number you can think of? */

-#define __futex_atomic_op(insn, ret, oldval, uaddr, tmp, oparg)		\
-do {									\
+#define LLSC_FUTEX_ATOMIC_OP(op, insn)					\
+static __always_inline int						\
+__llsc_futex_atomic_##op(int oparg, u32 __user *uaddr, int *oval)	\
+{									\
 	unsigned int loops = FUTEX_MAX_LOOPS;				\
+	int ret, oldval, tmp;						\
 									\
 	uaccess_enable_privileged();					\
-	asm volatile(							\
+	asm volatile("// __llsc_futex_atomic_" #op "\n"			\
 "	prfm	pstl1strm, %2\n"					\
 "1:	ldxr	%w1, %2\n"						\
 	insn "\n"							\
@@ -35,45 +39,103 @@ do {									\
 	: "r" (oparg), "Ir" (-EAGAIN)					\
 	: "memory");							\
 	uaccess_disable_privileged();					\
-} while (0)
+									\
+	if (!ret)							\
+		*oval = oldval;						\
+									\
+	return ret;							\
+}
+
+LLSC_FUTEX_ATOMIC_OP(add, "add	%w3, %w1, %w5")
+LLSC_FUTEX_ATOMIC_OP(or,  "orr	%w3, %w1, %w5")
+LLSC_FUTEX_ATOMIC_OP(and, "and	%w3, %w1, %w5")
+LLSC_FUTEX_ATOMIC_OP(eor, "eor	%w3, %w1, %w5")
+LLSC_FUTEX_ATOMIC_OP(set, "mov	%w3, %w5")
+
+static __always_inline int
+__llsc_futex_cmpxchg(u32 __user *uaddr, u32 oldval, u32 newval, u32 *oval)
+{
+	int ret = 0;
+	unsigned int loops = FUTEX_MAX_LOOPS;
+	u32 val, tmp;
+
+	uaccess_enable_privileged();
+	asm volatile("//__llsc_futex_cmpxchg\n"
+"	prfm	pstl1strm, %2\n"
+"1:	ldxr	%w1, %2\n"
+"	eor	%w3, %w1, %w5\n"
+"	cbnz	%w3, 4f\n"
+"2:	stlxr	%w3, %w6, %2\n"
+"	cbz	%w3, 3f\n"
+"	sub	%w4, %w4, %w3\n"
+"	cbnz	%w4, 1b\n"
+"	mov	%w0, %w7\n"
+"3:\n"
+"	dmb	ish\n"
+"4:\n"
+	_ASM_EXTABLE_UACCESS_ERR(1b, 4b, %w0)
+	_ASM_EXTABLE_UACCESS_ERR(2b, 4b, %w0)
+	: "+r" (ret), "=&r" (val), "+Q" (*uaddr), "=&r" (tmp), "+r" (loops)
+	: "r" (oldval), "r" (newval), "Ir" (-EAGAIN)
+	: "memory");
+	uaccess_disable_privileged();
+
+	if (!ret)
+		*oval = val;
+
+	return ret;
+}
+
+#define FUTEX_ATOMIC_OP(op)						\
+static __always_inline int						\
+__futex_atomic_##op(int oparg, u32 __user *uaddr, int *oval)		\
+{									\
+	return __llsc_futex_atomic_##op(oparg, uaddr, oval);		\
+}
+
+FUTEX_ATOMIC_OP(add)
+FUTEX_ATOMIC_OP(or)
+FUTEX_ATOMIC_OP(and)
+FUTEX_ATOMIC_OP(eor)
+FUTEX_ATOMIC_OP(set)
+
+static __always_inline int
+__futex_cmpxchg(u32 __user *uaddr, u32 oldval, u32 newval, u32 *oval)
+{
+	return __llsc_futex_cmpxchg(uaddr, oldval, newval, oval);
+}

 static inline int
 arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *_uaddr)
 {
-	int oldval = 0, ret, tmp;
-	u32 __user *uaddr = __uaccess_mask_ptr(_uaddr);
+	int ret;
+	u32 __user *uaddr;

 	if (!access_ok(_uaddr, sizeof(u32)))
 		return -EFAULT;

+	uaddr = __uaccess_mask_ptr(_uaddr);
+
 	switch (op) {
 	case FUTEX_OP_SET:
-		__futex_atomic_op("mov	%w3, %w5",
-				  ret, oldval, uaddr, tmp, oparg);
+		ret = __futex_atomic_set(oparg, uaddr, oval);
 		break;
 	case FUTEX_OP_ADD:
-		__futex_atomic_op("add	%w3, %w1, %w5",
-				  ret, oldval, uaddr, tmp, oparg);
+		ret = __futex_atomic_add(oparg, uaddr, oval);
 		break;
 	case FUTEX_OP_OR:
-		__futex_atomic_op("orr	%w3, %w1, %w5",
-				  ret, oldval, uaddr, tmp, oparg);
+		ret = __futex_atomic_or(oparg, uaddr, oval);
 		break;
 	case FUTEX_OP_ANDN:
-		__futex_atomic_op("and	%w3, %w1, %w5",
-				  ret, oldval, uaddr, tmp, ~oparg);
+		ret = __futex_atomic_and(~oparg, uaddr, oval);
 		break;
 	case FUTEX_OP_XOR:
-		__futex_atomic_op("eor	%w3, %w1, %w5",
-				  ret, oldval, uaddr, tmp, oparg);
+		ret = __futex_atomic_eor(oparg, uaddr, oval);
 		break;
 	default:
 		ret = -ENOSYS;
 	}

-	if (!ret)
-		*oval = oldval;
-
 	return ret;
 }

@@ -81,40 +143,14 @@ static inline int
 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *_uaddr,
 			      u32 oldval, u32 newval)
 {
-	int ret = 0;
-	unsigned int loops = FUTEX_MAX_LOOPS;
-	u32 val, tmp;
 	u32 __user *uaddr;

 	if (!access_ok(_uaddr, sizeof(u32)))
 		return -EFAULT;

 	uaddr = __uaccess_mask_ptr(_uaddr);
-	uaccess_enable_privileged();
-	asm volatile("// futex_atomic_cmpxchg_inatomic\n"
-"	prfm	pstl1strm, %2\n"
-"1:	ldxr	%w1, %2\n"
-"	sub	%w3, %w1, %w5\n"
-"	cbnz	%w3, 4f\n"
-"2:	stlxr	%w3, %w6, %2\n"
-"	cbz	%w3, 3f\n"
-"	sub	%w4, %w4, %w3\n"
-"	cbnz	%w4, 1b\n"
-"	mov	%w0, %w7\n"
-"3:\n"
-"	dmb	ish\n"
-"4:\n"
-	_ASM_EXTABLE_UACCESS_ERR(1b, 4b, %w0)
-	_ASM_EXTABLE_UACCESS_ERR(2b, 4b, %w0)
-	: "+r" (ret), "=&r" (val), "+Q" (*uaddr), "=&r" (tmp), "+r" (loops)
-	: "r" (oldval), "r" (newval), "Ir" (-EAGAIN)
-	: "memory");
-	uaccess_disable_privileged();
-
-	if (!ret)
-		*uval = val;

-	return ret;
+	return __futex_cmpxchg(uaddr, oldval, newval, uval);
 }

 #endif /* __ASM_FUTEX_H */
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



From yeoreum.yun at arm.com  Sun Dec 14 03:22:45 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Sun, 14 Dec 2025 11:22:45 +0000
Subject: [PATCH v11 RESEND 6/9] arm64: futex: support futex with FEAT_LSUI
In-Reply-To: <20251214112248.901769-1-yeoreum.yun@arm.com>
References: <20251214112248.901769-1-yeoreum.yun@arm.com>
Message-ID: <20251214112248.901769-7-yeoreum.yun@arm.com>

Current futex atomic operations are implemented with ll/sc instructions
and clearing PSTATE.PAN.

Since Armv9.6, FEAT_LSUI supplies not only load/store instructions but
also atomic operation for user memory access in kernel it doesn't need
to clear PSTATE.PAN bit anymore.

With theses instructions some of futex atomic operations don't need to
be implmented with ldxr/stlxr pair instead can be implmented with
one atomic operation supplied by FEAT_LSUI.

However, some of futex atomic operation don't have matched
instructuion i.e) eor or cmpxchg with word size.
For those operation, uses cas{al}t to implement them.

Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
---
 arch/arm64/include/asm/futex.h | 180 ++++++++++++++++++++++++++++++++-
 1 file changed, 178 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h
index f8cb674bdb3f..6778ff7e1c0e 100644
--- a/arch/arm64/include/asm/futex.h
+++ b/arch/arm64/include/asm/futex.h
@@ -9,6 +9,8 @@
 #include <linux/uaccess.h>
 #include <linux/stringify.h>

+#include <asm/alternative.h>
+#include <asm/alternative-macros.h>
 #include <asm/errno.h>

 #define FUTEX_MAX_LOOPS	128 /* What's the largest number you can think of? */
@@ -86,11 +88,185 @@ __llsc_futex_cmpxchg(u32 __user *uaddr, u32 oldval, u32 newval, u32 *oval)
 	return ret;
 }

+#ifdef CONFIG_AS_HAS_LSUI
+
+/*
+ * When the LSUI feature is present, the CPU also implements PAN, because
+ * FEAT_PAN has been mandatory since Armv8.1. Therefore, there is no need to
+ * call uaccess_ttbr0_enable()/uaccess_ttbr0_disable() around each LSUI
+ * operation.
+ */
+
+#define __LSUI_PREAMBLE	".arch_extension lsui\n"
+
+#define LSUI_FUTEX_ATOMIC_OP(op, asm_op, mb)				\
+static __always_inline int						\
+__lsui_futex_atomic_##op(int oparg, u32 __user *uaddr, int *oval)	\
+{									\
+	int ret = 0;							\
+	int oldval;							\
+									\
+	asm volatile("// __lsui_futex_atomic_" #op "\n"			\
+	__LSUI_PREAMBLE							\
+"1:	" #asm_op #mb "	%w3, %w2, %1\n"					\
+"2:\n"									\
+	_ASM_EXTABLE_UACCESS_ERR(1b, 2b, %w0)				\
+	: "+r" (ret), "+Q" (*uaddr), "=r" (oldval)			\
+	: "r" (oparg)							\
+	: "memory");							\
+									\
+	if (!ret)							\
+		*oval = oldval;						\
+									\
+	return ret;							\
+}
+
+LSUI_FUTEX_ATOMIC_OP(add, ldtadd, al)
+LSUI_FUTEX_ATOMIC_OP(or, ldtset, al)
+LSUI_FUTEX_ATOMIC_OP(andnot, ldtclr, al)
+LSUI_FUTEX_ATOMIC_OP(set, swpt, al)
+
+static __always_inline int
+__lsui_cmpxchg64(u64 __user *uaddr, u64 *oldval, u64 newval)
+{
+	int ret = 0;
+
+	asm volatile("// __lsui_cmpxchg64\n"
+	__LSUI_PREAMBLE
+"1:	casalt	%x2, %x3, %1\n"
+"2:\n"
+	_ASM_EXTABLE_UACCESS_ERR(1b, 2b, %w0)
+	: "+r" (ret), "+Q" (*uaddr), "+r" (*oldval)
+	: "r" (newval)
+	: "memory");
+
+	return ret;
+}
+
+static __always_inline int
+__lsui_cmpxchg32(u32 __user *uaddr, u32 oldval, u32 newval, u32 *oval)
+{
+	u64 __user *uaddr64;
+	bool futex_on_lo;
+	int ret = -EAGAIN, i;
+	u32 other, orig_other;
+	union {
+		struct futex_on_lo {
+			u32 val;
+			u32 other;
+		} lo_futex;
+
+		struct futex_on_hi {
+			u32 other;
+			u32 val;
+		} hi_futex;
+
+		u64 raw;
+	} oval64, orig64, nval64;
+
+	uaddr64 = (u64 __user *) PTR_ALIGN_DOWN(uaddr, sizeof(u64));
+	futex_on_lo = (IS_ALIGNED((unsigned long)uaddr, sizeof(u64)) ==
+			IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN));
+
+	for (i = 0; i < FUTEX_MAX_LOOPS; i++) {
+		if (get_user(oval64.raw, uaddr64))
+			return -EFAULT;
+
+		nval64.raw = oval64.raw;
+
+		if (futex_on_lo) {
+			oval64.lo_futex.val = oldval;
+			nval64.lo_futex.val = newval;
+		} else {
+			oval64.hi_futex.val = oldval;
+			nval64.hi_futex.val = newval;
+		}
+
+		orig64.raw = oval64.raw;
+
+		if (__lsui_cmpxchg64(uaddr64, &oval64.raw, nval64.raw))
+			return -EFAULT;
+
+		if (futex_on_lo) {
+			oldval = oval64.lo_futex.val;
+			other = oval64.lo_futex.other;
+			orig_other = orig64.lo_futex.other;
+		} else {
+			oldval = oval64.hi_futex.val;
+			other = oval64.hi_futex.other;
+			orig_other = orig64.hi_futex.other;
+		}
+
+		if (other == orig_other) {
+			ret = 0;
+			break;
+		}
+	}
+
+	if (!ret)
+		*oval = oldval;
+
+	return ret;
+}
+
+static __always_inline int
+__lsui_futex_atomic_and(int oparg, u32 __user *uaddr, int *oval)
+{
+	return __lsui_futex_atomic_andnot(~oparg, uaddr, oval);
+}
+
+static __always_inline int
+__lsui_futex_atomic_eor(int oparg, u32 __user *uaddr, int *oval)
+{
+	u32 oldval, newval, val;
+	int ret, i;
+
+	/*
+	 * there are no ldteor/stteor instructions...
+	 */
+	for (i = 0; i < FUTEX_MAX_LOOPS; i++) {
+		if (get_user(oldval, uaddr))
+			return -EFAULT;
+
+		newval = oldval ^ oparg;
+
+		ret = __lsui_cmpxchg32(uaddr, oldval, newval, &val);
+		if (ret)
+			return ret;
+
+		if (val == oldval) {
+			*oval = val;
+			return 0;
+		}
+	}
+
+	return -EAGAIN;
+}
+
+static __always_inline int
+__lsui_futex_cmpxchg(u32 __user *uaddr, u32 oldval, u32 newval, u32 *oval)
+{
+	return __lsui_cmpxchg32(uaddr, oldval, newval, oval);
+}
+
+#define __lsui_llsc_body(op, ...)					\
+({									\
+	alternative_has_cap_likely(ARM64_HAS_LSUI) ?			\
+		__lsui_##op(__VA_ARGS__) : __llsc_##op(__VA_ARGS__);	\
+})
+
+#else	/* CONFIG_AS_HAS_LSUI */
+
+#define __lsui_llsc_body(op, ...)	__llsc_##op(__VA_ARGS__)
+
+#endif	/* CONFIG_AS_HAS_LSUI */
+
+
 #define FUTEX_ATOMIC_OP(op)						\
 static __always_inline int						\
 __futex_atomic_##op(int oparg, u32 __user *uaddr, int *oval)		\
 {									\
-	return __llsc_futex_atomic_##op(oparg, uaddr, oval);		\
+	return __lsui_llsc_body(futex_atomic_##op, oparg, uaddr, oval);	\
 }

 FUTEX_ATOMIC_OP(add)
@@ -102,7 +278,7 @@ FUTEX_ATOMIC_OP(set)
 static __always_inline int
 __futex_cmpxchg(u32 __user *uaddr, u32 oldval, u32 newval, u32 *oval)
 {
-	return __llsc_futex_cmpxchg(uaddr, oldval, newval, oval);
+	return __lsui_llsc_body(futex_cmpxchg, uaddr, oldval, newval, oval);
 }

 static inline int
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



From yeoreum.yun at arm.com  Sun Dec 14 03:22:46 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Sun, 14 Dec 2025 11:22:46 +0000
Subject: [PATCH v11 RESEND 7/9] arm64: separate common LSUI definitions into lsui.h
In-Reply-To: <20251214112248.901769-1-yeoreum.yun@arm.com>
References: <20251214112248.901769-1-yeoreum.yun@arm.com>
Message-ID: <20251214112248.901769-8-yeoreum.yun@arm.com>

This patch prepares for applying LSUI to the armv8_deprecated
SWP instruction.
Some LSUI-related definitions can be reused by armv8_deprecated.c,
so move the common definitions into a separate header file, lsui.h.

Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
---
 arch/arm64/include/asm/futex.h | 15 +--------------
 arch/arm64/include/asm/lsui.h  | 25 +++++++++++++++++++++++++
 2 files changed, 26 insertions(+), 14 deletions(-)
 create mode 100644 arch/arm64/include/asm/lsui.h

diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h
index 6778ff7e1c0e..ca9487219102 100644
--- a/arch/arm64/include/asm/futex.h
+++ b/arch/arm64/include/asm/futex.h
@@ -9,9 +9,8 @@
 #include <linux/uaccess.h>
 #include <linux/stringify.h>

-#include <asm/alternative.h>
-#include <asm/alternative-macros.h>
 #include <asm/errno.h>
+#include <asm/lsui.h>

 #define FUTEX_MAX_LOOPS	128 /* What's the largest number you can think of? */

@@ -97,8 +96,6 @@ __llsc_futex_cmpxchg(u32 __user *uaddr, u32 oldval, u32 newval, u32 *oval)
  * operation.
  */

-#define __LSUI_PREAMBLE	".arch_extension lsui\n"
-
 #define LSUI_FUTEX_ATOMIC_OP(op, asm_op, mb)				\
 static __always_inline int						\
 __lsui_futex_atomic_##op(int oparg, u32 __user *uaddr, int *oval)	\
@@ -249,16 +246,6 @@ __lsui_futex_cmpxchg(u32 __user *uaddr, u32 oldval, u32 newval, u32 *oval)
 	return __lsui_cmpxchg32(uaddr, oldval, newval, oval);
 }

-#define __lsui_llsc_body(op, ...)					\
-({									\
-	alternative_has_cap_likely(ARM64_HAS_LSUI) ?			\
-		__lsui_##op(__VA_ARGS__) : __llsc_##op(__VA_ARGS__);	\
-})
-
-#else	/* CONFIG_AS_HAS_LSUI */
-
-#define __lsui_llsc_body(op, ...)	__llsc_##op(__VA_ARGS__)
-
 #endif	/* CONFIG_AS_HAS_LSUI */


diff --git a/arch/arm64/include/asm/lsui.h b/arch/arm64/include/asm/lsui.h
new file mode 100644
index 000000000000..1a2ad408a47b
--- /dev/null
+++ b/arch/arm64/include/asm/lsui.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_LSUI_H
+#define __ASM_LSUI_H
+
+#ifdef CONFIG_AS_HAS_LSUI
+
+#define __LSUI_PREAMBLE	".arch_extension lsui\n"
+
+#include <linux/stringify.h>
+#include <asm/alternative.h>
+#include <asm/alternative-macros.h>
+#include <asm/cpucaps.h>
+
+#define __lsui_llsc_body(op, ...)					\
+({									\
+	alternative_has_cap_likely(ARM64_HAS_LSUI) ?			\
+		__lsui_##op(__VA_ARGS__) : __llsc_##op(__VA_ARGS__);	\
+})
+
+#else	/* CONFIG_AS_HAS_LSUI */
+
+#define __lsui_llsc_body(op, ...)	__llsc_##op(__VA_ARGS__)
+
+#endif	/* CONFIG_AS_HAS_LSUI */
+#endif	/* __ASM_LSUI_H */
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



From yeoreum.yun at arm.com  Sun Dec 14 03:22:47 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Sun, 14 Dec 2025 11:22:47 +0000
Subject: [PATCH v11 RESEND 8/9] arm64: armv8_deprecated: convert user_swpX to inline function
In-Reply-To: <20251214112248.901769-1-yeoreum.yun@arm.com>
References: <20251214112248.901769-1-yeoreum.yun@arm.com>
Message-ID: <20251214112248.901769-9-yeoreum.yun@arm.com>

This is preparation patch to apply FEAT_LSUI in
user_swpX operation.
For this, convert user_swpX macro into inline function.
No functional change.

Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
---
 arch/arm64/kernel/armv8_deprecated.c | 38 +++++++++++++++++-----------
 1 file changed, 23 insertions(+), 15 deletions(-)

diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
index e737c6295ec7..d15e35f1075c 100644
--- a/arch/arm64/kernel/armv8_deprecated.c
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -93,13 +93,18 @@ static unsigned int __maybe_unused aarch32_check_condition(u32 opcode, u32 psr)
 /* Arbitrary constant to ensure forward-progress of the LL/SC loop */
 #define __SWP_LL_SC_LOOPS	4

-#define __user_swpX_asm(data, addr, res, temp, temp2, B)	\
-do {								\
+#define LLSC_USER_SWPX(B)					\
+static __always_inline int					\
+__llsc_user_swp##B##_asm(unsigned int *data, unsigned int addr)	\
+{								\
+	int err = 0;						\
+	unsigned int temp, temp2;				\
+								\
 	uaccess_enable_privileged();				\
 	__asm__ __volatile__(					\
 	"	mov		%w3, %w6\n"			\
-	"0:	ldxr"B"		%w2, [%4]\n"			\
-	"1:	stxr"B"		%w0, %w1, [%4]\n"		\
+	"0:	ldxr"#B"	%w2, [%4]\n"			\
+	"1:	stxr"#B"	%w0, %w1, [%4]\n"		\
 	"	cbz		%w0, 2f\n"			\
 	"	sub		%w3, %w3, #1\n"			\
 	"	cbnz		%w3, 0b\n"			\
@@ -110,17 +115,22 @@ do {								\
 	"3:\n"							\
 	_ASM_EXTABLE_UACCESS_ERR(0b, 3b, %w0)			\
 	_ASM_EXTABLE_UACCESS_ERR(1b, 3b, %w0)			\
-	: "=&r" (res), "+r" (data), "=&r" (temp), "=&r" (temp2)	\
+	: "=&r" (err), "+r" (*data), "=&r" (temp), "=&r" (temp2)\
 	: "r" ((unsigned long)addr), "i" (-EAGAIN),		\
 	  "i" (__SWP_LL_SC_LOOPS)				\
 	: "memory");						\
 	uaccess_disable_privileged();				\
-} while (0)
+								\
+	return err;						\
+}
+
+LLSC_USER_SWPX()
+LLSC_USER_SWPX(b)

-#define __user_swp_asm(data, addr, res, temp, temp2) \
-	__user_swpX_asm(data, addr, res, temp, temp2, "")
-#define __user_swpb_asm(data, addr, res, temp, temp2) \
-	__user_swpX_asm(data, addr, res, temp, temp2, "b")
+#define __user_swp_asm(data, addr) \
+	__llsc_user_swp_asm(data, addr)
+#define __user_swpb_asm(data, addr) \
+	__llsc_user_swpb_asm(data, addr)

 /*
  * Bit 22 of the instruction encoding distinguishes between
@@ -131,7 +141,7 @@ do {								\
 static int emulate_swpX(unsigned int address, unsigned int *data,
 			unsigned int type)
 {
-	unsigned int res = 0;
+	unsigned int res;

 	if ((type != TYPE_SWPB) && (address & 0x3)) {
 		/* SWP to unaligned address not permitted */
@@ -140,12 +150,10 @@ static int emulate_swpX(unsigned int address, unsigned int *data,
 	}

 	while (1) {
-		unsigned long temp, temp2;
-
 		if (type == TYPE_SWPB)
-			__user_swpb_asm(*data, address, res, temp, temp2);
+			res = __user_swpb_asm(data, address);
 		else
-			__user_swp_asm(*data, address, res, temp, temp2);
+			res = __user_swp_asm(data, address);

 		if (likely(res != -EAGAIN) || signal_pending(current))
 			break;
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



From yeoreum.yun at arm.com  Sun Dec 14 03:22:48 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Sun, 14 Dec 2025 11:22:48 +0000
Subject: [PATCH v11 RESEND 9/9] arm64: armv8_deprecated: apply FEAT_LSUI for swpX emulation.
In-Reply-To: <20251214112248.901769-1-yeoreum.yun@arm.com>
References: <20251214112248.901769-1-yeoreum.yun@arm.com>
Message-ID: <20251214112248.901769-10-yeoreum.yun@arm.com>

Apply the FEAT_LSUI instruction to emulate the deprecated swpX
instruction, so that toggling of the PSTATE.PAN bit can be removed when
LSUI-related instructions are used.

Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
---
 arch/arm64/kernel/armv8_deprecated.c | 77 +++++++++++++++++++++++++---
 1 file changed, 71 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
index d15e35f1075c..b8e6d71f766d 100644
--- a/arch/arm64/kernel/armv8_deprecated.c
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -13,6 +13,7 @@
 #include <linux/uaccess.h>

 #include <asm/cpufeature.h>
+#include <asm/lsui.h>
 #include <asm/insn.h>
 #include <asm/sysreg.h>
 #include <asm/system_misc.h>
@@ -86,13 +87,77 @@ static unsigned int __maybe_unused aarch32_check_condition(u32 opcode, u32 psr)
  *	   Rn  = address
  */

+/* Arbitrary constant to ensure forward-progress of the loop */
+#define __SWP_LOOPS	4
+
+#ifdef CONFIG_AS_HAS_LSUI
+static __always_inline int
+__lsui_user_swp_asm(unsigned int *data, unsigned int addr)
+{
+	int err = 0;
+	unsigned int temp;
+
+	asm volatile("// __lsui_user_swp_asm\n"
+	__LSUI_PREAMBLE
+	"1:	swpt		%w1, %w2, [%3]\n"
+	"	mov		%w1, %w2\n"
+	"2:\n"
+	_ASM_EXTABLE_UACCESS_ERR(1b, 2b, %w0)
+	: "+r" (err), "+r" (*data), "=&r" (temp)
+	: "r" ((unsigned long)addr)
+	: "memory");
+
+	return err;
+}
+
+static __always_inline int
+__lsui_user_swpb_asm(unsigned int *data, unsigned int addr)
+{
+	u8 i, idx;
+	int err = -EAGAIN;
+	u64 __user *addr_al;
+	u64 oldval;
+	union {
+		u64 var;
+		u8 raw[sizeof(u64)];
+	} newval, curval;
+
+	idx = addr & (sizeof(u64) - 1);
+	addr_al = (u64 __user *)ALIGN_DOWN(addr, sizeof(u64));
+
+	for (i = 0; i < __SWP_LOOPS; i++) {
+		if (get_user(oldval, addr_al))
+			return -EFAULT;
+
+		curval.var = newval.var = oldval;
+		newval.raw[idx] = *data;
+
+		asm volatile("// __lsui_user_swpb_asm\n"
+		__LSUI_PREAMBLE
+		"1: cast	%x2, %x3, %1\n"
+		"2:\n"
+		_ASM_EXTABLE_UACCESS_ERR(1b, 2b, %w0)
+		: "+r" (err), "+Q" (*addr_al), "+r" (curval.var)
+		: "r" (newval.var)
+		: "memory");
+
+		if (curval.var == oldval) {
+			err = 0;
+			break;
+		}
+	}
+
+	if (!err)
+		*data = curval.raw[idx];
+
+	return err;
+}
+#endif /* CONFIG_AS_HAS_LSUI */
+
 /*
  * Error-checking SWP macros implemented using ldxr{b}/stxr{b}
  */

-/* Arbitrary constant to ensure forward-progress of the LL/SC loop */
-#define __SWP_LL_SC_LOOPS	4
-
 #define LLSC_USER_SWPX(B)					\
 static __always_inline int					\
 __llsc_user_swp##B##_asm(unsigned int *data, unsigned int addr)	\
@@ -117,7 +182,7 @@ __llsc_user_swp##B##_asm(unsigned int *data, unsigned int addr)	\
 	_ASM_EXTABLE_UACCESS_ERR(1b, 3b, %w0)			\
 	: "=&r" (err), "+r" (*data), "=&r" (temp), "=&r" (temp2)\
 	: "r" ((unsigned long)addr), "i" (-EAGAIN),		\
-	  "i" (__SWP_LL_SC_LOOPS)				\
+	  "i" (__SWP_LOOPS)					\
 	: "memory");						\
 	uaccess_disable_privileged();				\
 								\
@@ -128,9 +193,9 @@ LLSC_USER_SWPX()
 LLSC_USER_SWPX(b)

 #define __user_swp_asm(data, addr) \
-	__llsc_user_swp_asm(data, addr)
+	__lsui_llsc_body(user_swp_asm, data, addr)
 #define __user_swpb_asm(data, addr) \
-	__llsc_user_swpb_asm(data, addr)
+	__lsui_llsc_body(user_swpb_asm, data, addr)

 /*
  * Bit 22 of the instruction encoding distinguishes between
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



From sven at kernel.org  Sun Dec 14 03:51:33 2025
From: sven at kernel.org (Sven Peter)
Date: Sun, 14 Dec 2025 11:51:33 +0000
Subject: [PATCH v3 0/3] Apple Silicon Type-C PHY
Message-ID: <20251214-b4-atcphy-v3-0-ba82b20e9459@kernel.org>

Hi,

This series adds support for the combined Type-C PHY found in Apple
Silicon machines and required for USB3, DP-AltMode, and Thunderbolt/USB4
support. As in the previous versions, this is limited to USB3 support so
far since the other modes need further work in different subsystems.
With the dwc3 glue driver being upstream this is however the last part
required for upstream USB3 support.

The generic tunable support inside driver/soc/apple will also be re-used
for Thunderbolt later but it's fine to take it through the PHY tree
since thunderbolt will depend on that anyway.

Changes in v3:
- Link to v2: https://patch.msgid.link/20251123-b4-atcphy-v2-0-34cc7092b22a at kernel.org
- Rebased on 6.19-rc1

Changes in v2:
- Link to v1: https://patch.msgid.link/20251026-b4-atcphy-v1-0-f81b1225f9c6 at kernel.org
- Picked up tags from Rob and Janne, thanks!
- Added additional sanity checks for the tunables to guard against bugs
  in our bootloader (Janne)
- Used struct_size from overflow.h instead of open-coding it inside
  tunables.c (Janne)
- Fixed a bunch of typos in atc.c pointed out by Mark Kettenis via IRC

Changes since v2 of the combined series:
- Link to v2: https://lore.kernel.org/asahi/20250906-atcphy-6-17-v2-0-52c348623ef6 at kernel.org/
- atc.c:
  - Removed a bunch of outdated safety checks from atc.c that were only
    required in a previous version that did not rely on the dwc3-glue
    driver
  - Addressed Philipp's review comments:
    - Added documentation for struct apple_atcphy (and a bunch of other
      things while I was at it)
    - Moved the mutex guard from atcphy_dpphy_configure to atcphy_dp_configure
      since the first one doesn't touch any shared structures or MMIO
- apple,atcphy.yaml:
  - Added a generic apple,tunable definition that uses uint32-matrix
    and refer to that one from the individual tunable properties
  - Adjust the tunable description to make it easier to understand
  - Limited all lines to 80 chars
  - Used > for longer descriptions
  - Fixed some typos
- Picked up r-b tags (thanks!)

Best,

Sven

Signed-off-by: Sven Peter <sven at kernel.org>
---
Sven Peter (3):
      soc: apple: Add hardware tunable support
      dt-bindings: phy: Add Apple Type-C PHY
      phy: apple: Add Apple Type-C PHY

 .../devicetree/bindings/phy/apple,atcphy.yaml      |  222 ++
 MAINTAINERS                                        |    2 +
 drivers/phy/Kconfig                                |    1 +
 drivers/phy/Makefile                               |    1 +
 drivers/phy/apple/Kconfig                          |   14 +
 drivers/phy/apple/Makefile                         |    4 +
 drivers/phy/apple/atc.c                            | 2294 ++++++++++++++++++++
 drivers/soc/apple/Kconfig                          |    4 +
 drivers/soc/apple/Makefile                         |    3 +
 drivers/soc/apple/tunable.c                        |   80 +
 include/linux/soc/apple/tunable.h                  |   62 +
 11 files changed, 2687 insertions(+)
---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20251013-b4-atcphy-d6a7c939d417

Best regards,
-- 
Sven Peter <sven at kernel.org>




From sven at kernel.org  Sun Dec 14 03:51:34 2025
From: sven at kernel.org (Sven Peter)
Date: Sun, 14 Dec 2025 11:51:34 +0000
Subject: [PATCH v3 1/3] soc: apple: Add hardware tunable support
In-Reply-To: <20251214-b4-atcphy-v3-0-ba82b20e9459@kernel.org>
References: <20251214-b4-atcphy-v3-0-ba82b20e9459@kernel.org>
Message-ID: <20251214-b4-atcphy-v3-1-ba82b20e9459@kernel.org>

Various hardware, like the Type-C PHY or the Thunderbolt/USB4 NHI,
present on Apple SoCs need machine-specific tunables passed from our
bootloader m1n1 to the device tree. Add generic helpers so that we
don't have to duplicate this across multiple drivers.

Reviewed-by: Alyssa Rosenzweig <alyssa at rosenzweig.io>
Reviewed-by: Neal Gompa <neal at gompa.dev>
Reviewed-by: Janne Grunau <j at jannau.net>
Signed-off-by: Sven Peter <sven at kernel.org>
---
 drivers/soc/apple/Kconfig         |  4 ++
 drivers/soc/apple/Makefile        |  3 ++
 drivers/soc/apple/tunable.c       | 80 +++++++++++++++++++++++++++++++++++++++
 include/linux/soc/apple/tunable.h | 62 ++++++++++++++++++++++++++++++
 4 files changed, 149 insertions(+)

diff --git a/drivers/soc/apple/Kconfig b/drivers/soc/apple/Kconfig
index ad67368892311bed5a94d358288390a6fb8b3b4a..d0ff32182a2b4a10c98cb96c70a03bea8c650f84 100644
--- a/drivers/soc/apple/Kconfig
+++ b/drivers/soc/apple/Kconfig
@@ -38,6 +38,10 @@ config APPLE_SART
 
 	  Say 'y' here if you have an Apple SoC.
 
+config APPLE_TUNABLE
+	tristate
+	depends on ARCH_APPLE || COMPILE_TEST
+
 endmenu
 
 endif
diff --git a/drivers/soc/apple/Makefile b/drivers/soc/apple/Makefile
index 4d9ab8f3037b7159771d8817fa507ba29f99ae10..0b85ab61aefe131349a67d0aa80204edd8e89925 100644
--- a/drivers/soc/apple/Makefile
+++ b/drivers/soc/apple/Makefile
@@ -8,3 +8,6 @@ apple-rtkit-y = rtkit.o rtkit-crashlog.o
 
 obj-$(CONFIG_APPLE_SART) += apple-sart.o
 apple-sart-y = sart.o
+
+obj-$(CONFIG_APPLE_TUNABLE) += apple-tunable.o
+apple-tunable-y = tunable.o
diff --git a/drivers/soc/apple/tunable.c b/drivers/soc/apple/tunable.c
new file mode 100644
index 0000000000000000000000000000000000000000..6593238391715be07cdfec0c1b116d6946f53fb5
--- /dev/null
+++ b/drivers/soc/apple/tunable.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Apple Silicon hardware tunable support
+ *
+ * Each tunable is a list with each entry containing a offset into the MMIO
+ * region, a mask of bits to be cleared and a set of bits to be set. These
+ * tunables are passed along by the previous boot stages and vary from device
+ * to device such that they cannot be hardcoded in the individual drivers.
+ *
+ * Copyright (C) The Asahi Linux Contributors
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/overflow.h>
+#include <linux/soc/apple/tunable.h>
+
+struct apple_tunable *devm_apple_tunable_parse(struct device *dev,
+					       struct device_node *np,
+					       const char *name,
+					       struct resource *res)
+{
+	struct apple_tunable *tunable;
+	struct property *prop;
+	const __be32 *p;
+	size_t sz;
+	int i;
+
+	if (resource_size(res) < 4)
+		return ERR_PTR(-EINVAL);
+
+	prop = of_find_property(np, name, NULL);
+	if (!prop)
+		return ERR_PTR(-ENOENT);
+
+	if (prop->length % (3 * sizeof(u32)))
+		return ERR_PTR(-EINVAL);
+	sz = prop->length / (3 * sizeof(u32));
+
+	tunable = devm_kzalloc(dev, struct_size(tunable, values, sz), GFP_KERNEL);
+	if (!tunable)
+		return ERR_PTR(-ENOMEM);
+	tunable->sz = sz;
+
+	for (i = 0, p = NULL; i < tunable->sz; ++i) {
+		p = of_prop_next_u32(prop, p, &tunable->values[i].offset);
+		p = of_prop_next_u32(prop, p, &tunable->values[i].mask);
+		p = of_prop_next_u32(prop, p, &tunable->values[i].value);
+
+		/* Sanity checks to catch bugs in our bootloader */
+		if (tunable->values[i].offset % 4)
+			return ERR_PTR(-EINVAL);
+		if (tunable->values[i].offset > (resource_size(res) - 4))
+			return ERR_PTR(-EINVAL);
+	}
+
+	return tunable;
+}
+EXPORT_SYMBOL(devm_apple_tunable_parse);
+
+void apple_tunable_apply(void __iomem *regs, struct apple_tunable *tunable)
+{
+	size_t i;
+
+	for (i = 0; i < tunable->sz; ++i) {
+		u32 val, old_val;
+
+		old_val = readl(regs + tunable->values[i].offset);
+		val = old_val & ~tunable->values[i].mask;
+		val |= tunable->values[i].value;
+		if (val != old_val)
+			writel(val, regs + tunable->values[i].offset);
+	}
+}
+EXPORT_SYMBOL(apple_tunable_apply);
+
+MODULE_LICENSE("Dual MIT/GPL");
+MODULE_AUTHOR("Sven Peter <sven at kernel.org>");
+MODULE_DESCRIPTION("Apple Silicon hardware tunable support");
diff --git a/include/linux/soc/apple/tunable.h b/include/linux/soc/apple/tunable.h
new file mode 100644
index 0000000000000000000000000000000000000000..531ca814cd02357a0c5de6f3acde805294c13d4a
--- /dev/null
+++ b/include/linux/soc/apple/tunable.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
+/*
+ * Apple Silicon hardware tunable support
+ *
+ * Each tunable is a list with each entry containing a offset into the MMIO
+ * region, a mask of bits to be cleared and a set of bits to be set. These
+ * tunables are passed along by the previous boot stages and vary from device
+ * to device such that they cannot be hardcoded in the individual drivers.
+ *
+ * Copyright (C) The Asahi Linux Contributors
+ */
+
+#ifndef _LINUX_SOC_APPLE_TUNABLE_H_
+#define _LINUX_SOC_APPLE_TUNABLE_H_
+
+#include <linux/device.h>
+#include <linux/types.h>
+
+/**
+ * Struct to store an Apple Silicon hardware tunable.
+ *
+ * Each tunable is a list with each entry containing a offset into the MMIO
+ * region, a mask of bits to be cleared and a set of bits to be set. These
+ * tunables are passed along by the previous boot stages and vary from device
+ * to device such that they cannot be hardcoded in the individual drivers.
+ *
+ * @param sz Number of [offset, mask, value] tuples stored in values.
+ * @param values [offset, mask, value] array.
+ */
+struct apple_tunable {
+	size_t sz;
+	struct {
+		u32 offset;
+		u32 mask;
+		u32 value;
+	} values[] __counted_by(sz);
+};
+
+/**
+ * Parse an array of hardware tunables from the device tree.
+ *
+ * @dev: Device node used for devm_kzalloc internally.
+ * @np: Device node which contains the tunable array.
+ * @name: Name of the device tree property which contains the tunables.
+ * @res: Resource to which the tunables will be applied, used for bound checking
+ *
+ * @return: devres allocated struct on success or PTR_ERR on failure.
+ */
+struct apple_tunable *devm_apple_tunable_parse(struct device *dev,
+					       struct device_node *np,
+					       const char *name,
+					       struct resource *res);
+
+/**
+ * Apply a previously loaded hardware tunable.
+ *
+ * @param regs: MMIO to which the tunable will be applied.
+ * @param tunable: Pointer to the tunable.
+ */
+void apple_tunable_apply(void __iomem *regs, struct apple_tunable *tunable);
+
+#endif

-- 
2.34.1




From sven at kernel.org  Sun Dec 14 03:51:35 2025
From: sven at kernel.org (Sven Peter)
Date: Sun, 14 Dec 2025 11:51:35 +0000
Subject: [PATCH v3 2/3] dt-bindings: phy: Add Apple Type-C PHY
In-Reply-To: <20251214-b4-atcphy-v3-0-ba82b20e9459@kernel.org>
References: <20251214-b4-atcphy-v3-0-ba82b20e9459@kernel.org>
Message-ID: <20251214-b4-atcphy-v3-2-ba82b20e9459@kernel.org>

Apple's Type-C PHY (ATCPHY) is a PHY for USB 2.0, USB 3.x,
USB4/Thunderbolt, and DisplayPort connectivity found in Apple Silicon
SoCs.

The PHY handles muxing between these different protocols and also provides
the reset controller for the attached dwc3 USB controller.

Reviewed-by: Neal Gompa <neal at gompa.dev>
Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Sven Peter <sven at kernel.org>
---
 .../devicetree/bindings/phy/apple,atcphy.yaml      | 222 +++++++++++++++++++++
 MAINTAINERS                                        |   1 +
 2 files changed, 223 insertions(+)

diff --git a/Documentation/devicetree/bindings/phy/apple,atcphy.yaml b/Documentation/devicetree/bindings/phy/apple,atcphy.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..0acac7e3ee67ef2f03ffe1e04b0ac0fb414af362
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/apple,atcphy.yaml
@@ -0,0 +1,222 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/apple,atcphy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Apple Type-C PHY (ATCPHY)
+
+maintainers:
+  - Sven Peter <sven at kernel.org>
+
+description: >
+  The Apple Type-C PHY (ATCPHY) is a combined PHY for USB 2.0, USB 3.x,
+  USB4/Thunderbolt, and DisplayPort connectivity via Type-C ports found in
+  Apple Silicon SoCs.
+
+  The PHY handles muxing between these different protocols and also provides the
+  reset controller for the attached DWC3 USB controller.
+
+  It is designed for USB4 operation and does not handle individual differential
+  pairs as distinct DisplayPort lanes. Any reference to lane in this binding
+  hence refers to two differential pairs (RX and TX) as used in USB terminology.
+
+  In order to correctly setup these lanes for the various modes calibration
+  values copied from Apple's firmware and converted to the format described
+  below by our bootloader m1n1 are required. Without these only USB2 operation
+  is possible.
+
+allOf:
+  - $ref: /schemas/usb/usb-switch.yaml#
+
+$defs:
+  apple,tunable:
+    $ref: /schemas/types.yaml#/definitions/uint32-matrix
+    items:
+      items:
+        - description: Register offset
+        - description: Mask to be applied to the register value
+        - description: Bits to be set after applying the mask
+    description: >
+      List of (register offset, mask, value) tuples copied from Apple's Device
+      Tree by our bootloader m1n1 and used to configure the PHY. These values
+      even vary for a single product/device and likely contain calibration
+      values determined by Apple at manufacturing time.
+      Unless otherwise noted these tunables are always applied to the core
+      register region.
+
+properties:
+  compatible:
+    oneOf:
+      - items:
+          - enum:
+              - apple,t6000-atcphy
+              - apple,t6020-atcphy
+              - apple,t8112-atcphy
+          - const: apple,t8103-atcphy
+      - const: apple,t8103-atcphy
+
+  reg:
+    items:
+      - description: Common controls for all PHYs (USB2/3/4, DisplayPort, TBT)
+      - description: DisplayPort Alternate Mode PHY specific controls
+      - description: Type-C PHY AXI to Apple Fabric interconnect controls
+      - description: USB2 PHY specific controls
+      - description: USB3 PIPE interface controls
+
+  reg-names:
+    items:
+      - const: core
+      - const: lpdptx
+      - const: axi2af
+      - const: usb2phy
+      - const: pipehandler
+
+  "#phy-cells":
+    const: 1
+
+  "#reset-cells":
+    const: 0
+
+  mode-switch: true
+  orientation-switch: true
+
+  power-domains:
+    maxItems: 1
+
+  ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+    properties:
+      port at 0:
+        $ref: /schemas/graph.yaml#/properties/port
+        description: Outgoing connection to the SS port of the Type-C connector.
+
+      port at 1:
+        $ref: /schemas/graph.yaml#/properties/port
+        description: Incoming endpoint from the USB3 controller.
+
+      port at 2:
+        $ref: /schemas/graph.yaml#/properties/port
+        description: Incoming endpoint from the DisplayPort controller.
+
+      port at 3:
+        $ref: /schemas/graph.yaml#/properties/port
+        description: Incoming endpoint from the USB4/Thunderbolt controller.
+
+  apple,tunable-common-a:
+    $ref: "#/$defs/apple,tunable"
+    description: >
+      Common tunables required for all modes, applied before tunable-axi2af.
+
+  apple,tunable-axi2af:
+    $ref: "#/$defs/apple,tunable"
+    description: >
+      AXI to Apple Fabric tunables, required for all modes. Unlike all other
+      tunables these are applied to the axi2af region.
+
+  apple,tunable-common-b:
+    $ref: "#/$defs/apple,tunable"
+    description: >
+      Common tunables required for all modes, applied after tunable-axi2af.
+
+  apple,tunable-lane0-usb:
+    $ref: "#/$defs/apple,tunable"
+    description: USB3 tunables for lane 0.
+
+  apple,tunable-lane1-usb:
+    $ref: "#/$defs/apple,tunable"
+    description: USB3 tunables for lane 1.
+
+  apple,tunable-lane0-cio:
+    $ref: "#/$defs/apple,tunable"
+    description: USB4/Thunderbolt ("Converged IO") tunables for lane 0.
+
+  apple,tunable-lane1-cio:
+    $ref: "#/$defs/apple,tunable"
+    description: USB4/Thunderbolt ("Converged IO") tunables for lane 1.
+
+  apple,tunable-lane0-dp:
+    $ref: "#/$defs/apple,tunable"
+    description: >
+      DisplayPort tunables for lane 0.
+
+      Note that lane here refers to a USB RX and TX pair re-used for DisplayPort
+      and not to an individual DisplayPort differential lane.
+
+  apple,tunable-lane1-dp:
+    $ref: "#/$defs/apple,tunable"
+    description: >
+      DisplayPort tunables for lane 1.
+
+      Note that lane here refers to a USB RX and TX pair re-used for DisplayPort
+      and not to an individual DisplayPort differential lane.
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - "#phy-cells"
+  - "#reset-cells"
+  - orientation-switch
+  - mode-switch
+  - power-domains
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    phy at 83000000 {
+      compatible = "apple,t8103-atcphy";
+      reg = <0x83000000 0x4c000>,
+            <0x83050000 0x8000>,
+            <0x80000000 0x4000>,
+            <0x82a90000 0x4000>,
+            <0x82a84000 0x4000>;
+      reg-names = "core", "lpdptx", "axi2af", "usb2phy",
+                  "pipehandler";
+
+      #phy-cells = <1>;
+      #reset-cells = <0>;
+
+      orientation-switch;
+      mode-switch;
+      power-domains = <&ps_atc0_usb>;
+
+      ports {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        port at 0 {
+          reg = <0>;
+
+          endpoint {
+            remote-endpoint = <&typec_connector_ss>;
+          };
+        };
+
+        port at 1 {
+          reg = <1>;
+
+          endpoint {
+            remote-endpoint = <&dwc3_ss_out>;
+          };
+        };
+
+        port at 2 {
+          reg = <2>;
+
+          endpoint {
+            remote-endpoint = <&dcp_dp_out>;
+          };
+        };
+
+        port at 3 {
+          reg = <3>;
+
+          endpoint {
+            remote-endpoint = <&acio_tbt_out>;
+          };
+        };
+      };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index 5b11839cba9de1e9e43f63787578edd8c429ca39..5c68ab187d406d5fd6d042672848197c1b6957a1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2471,6 +2471,7 @@ F:	Documentation/devicetree/bindings/nvme/apple,nvme-ans.yaml
 F:	Documentation/devicetree/bindings/nvmem/apple,efuses.yaml
 F:	Documentation/devicetree/bindings/nvmem/apple,spmi-nvmem.yaml
 F:	Documentation/devicetree/bindings/pci/apple,pcie.yaml
+F:	Documentation/devicetree/bindings/phy/apple,atcphy.yaml
 F:	Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml
 F:	Documentation/devicetree/bindings/power/apple*
 F:	Documentation/devicetree/bindings/power/reset/apple,smc-reboot.yaml

-- 
2.34.1




From sven at kernel.org  Sun Dec 14 03:51:36 2025
From: sven at kernel.org (Sven Peter)
Date: Sun, 14 Dec 2025 11:51:36 +0000
Subject: [PATCH v3 3/3] phy: apple: Add Apple Type-C PHY
In-Reply-To: <20251214-b4-atcphy-v3-0-ba82b20e9459@kernel.org>
References: <20251214-b4-atcphy-v3-0-ba82b20e9459@kernel.org>
Message-ID: <20251214-b4-atcphy-v3-3-ba82b20e9459@kernel.org>

The Apple Type-C PHY (ATCPHY) is a PHY for USB 2.0, USB 3.x,
USB4/Thunderbolt, and DisplayPort connectivity found in Apple Silicon SoCs.
The PHY handles muxing between these different protocols and also provides
the reset controller for the attached dwc3 USB controller.

There is no documentation available for this PHY and the entire sequence
of MMIO pokes has been figured out by tracing all MMIO access of Apple's
driver under a thin hypervisor and correlating the register reads/writes
to their kernel's debug output to find their names. Deviations from this
sequence generally results in the port not working or, especially when
the mode is switched to USB4 or Thunderbolt, to some watchdog resetting
the entire SoC.

This initial commit already introduces support for Display Port and
USB4/Thunderbolt but the drivers for these are not ready. We cannot
control the alternate mode negotiation and are stuck with whatever Apple's
firmware decides such that any DisplayPort or USB4/Thunderbolt device will
result in a correctly setup PHY but not be usable until the other drivers
are upstreamed as well.

Co-developed-by: Janne Grunau <j at jannau.net>
Signed-off-by: Janne Grunau <j at jannau.net>
Co-developed-by: Hector Martin <marcan at marcan.st>
Signed-off-by: Hector Martin <marcan at marcan.st>
Reviewed-by: Philipp Zabel <p.zabel at pengutronix.de> # for reset controller
Reviewed-by: Neal Gompa <neal at gompa.dev>
Signed-off-by: Sven Peter <sven at kernel.org>
---
 MAINTAINERS                |    1 +
 drivers/phy/Kconfig        |    1 +
 drivers/phy/Makefile       |    1 +
 drivers/phy/apple/Kconfig  |   14 +
 drivers/phy/apple/Makefile |    4 +
 drivers/phy/apple/atc.c    | 2294 ++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 2315 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 5c68ab187d406d5fd6d042672848197c1b6957a1..4685224949fed08ec8764215e7e5cda99b9ad8ab 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2500,6 +2500,7 @@ F:	drivers/mfd/macsmc.c
 F:	drivers/nvme/host/apple.c
 F:	drivers/nvmem/apple-efuses.c
 F:	drivers/nvmem/apple-spmi-nvmem.c
+F:	drivers/phy/apple/
 F:	drivers/pinctrl/pinctrl-apple-gpio.c
 F:	drivers/power/reset/macsmc-reboot.c
 F:	drivers/pwm/pwm-apple.c
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 678dd0452f0aa0597773433f04d2a9ba77474d2a..2fb5e3b313effc1dd658264c0d9110c9c291520c 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -103,6 +103,7 @@ config PHY_NXP_PTN3222
 
 source "drivers/phy/allwinner/Kconfig"
 source "drivers/phy/amlogic/Kconfig"
+source "drivers/phy/apple/Kconfig"
 source "drivers/phy/broadcom/Kconfig"
 source "drivers/phy/cadence/Kconfig"
 source "drivers/phy/freescale/Kconfig"
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index bfb27fb5a494283d7fd05dd670ebd1b12df8b1a1..eb84c3328d10620dfc460ff06b2c488ba2741067 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_PHY_AIROHA_PCIE)		+= phy-airoha-pcie.o
 obj-$(CONFIG_PHY_NXP_PTN3222)		+= phy-nxp-ptn3222.o
 obj-y					+= allwinner/	\
 					   amlogic/	\
+					   apple/	\
 					   broadcom/	\
 					   cadence/	\
 					   freescale/	\
diff --git a/drivers/phy/apple/Kconfig b/drivers/phy/apple/Kconfig
new file mode 100644
index 0000000000000000000000000000000000000000..67f460512592602ae60b2245b1562f5f667488c9
--- /dev/null
+++ b/drivers/phy/apple/Kconfig
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+config PHY_APPLE_ATC
+	tristate "Apple Type-C PHY"
+	depends on (ARM64 && ARCH_APPLE) || (COMPILE_TEST && !GENERIC_ATOMIC64)
+	depends on TYPEC
+	select GENERIC_PHY
+	select APPLE_TUNABLE
+	help
+	  Enable this to add support for the Apple Type-C PHY found in
+	  Apple Silicon M-series SoCs. This PHY supports USB2,
+	  USB3, USB4, Thunderbolt, and DisplayPort.
+
+	  If M is selected the module will be called 'phy-apple-atc'.
+
diff --git a/drivers/phy/apple/Makefile b/drivers/phy/apple/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..e02836a63df3b5324c5ac102b379b12a24494301
--- /dev/null
+++ b/drivers/phy/apple/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+
+obj-$(CONFIG_PHY_APPLE_ATC)		+= phy-apple-atc.o
+phy-apple-atc-y			:= atc.o
diff --git a/drivers/phy/apple/atc.c b/drivers/phy/apple/atc.c
new file mode 100644
index 0000000000000000000000000000000000000000..c8a58ee64b7aad3205df51cf16ae778471ad2c5d
--- /dev/null
+++ b/drivers/phy/apple/atc.c
@@ -0,0 +1,2294 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/*
+ * Apple Type-C PHY driver
+ *
+ * The Apple Type-C PHY (ATCPHY) is a combined PHY for USB 2.0, USB 3.x,
+ * USB4/Thunderbolt, and DisplayPort connectivity via Type-C ports found in
+ * Apple Silicon SoCs.
+ *
+ * The PHY handles muxing between these different protocols and also provides the
+ * reset controller for the attached DWC3 USB controller.
+ *
+ * No documentation for this PHY is available and its operation has been
+ * reverse engineered by observing the XNU's MMIO access using a thin hypervisor
+ * and correlating register access to XNU's very verbose debug output. Most
+ * register names comes from this debug output as well.
+ *
+ * In order to correctly setup the high speed lanes for the various modes
+ * calibration values copied from Apple's firmware by our bootloader m1n1 are
+ * required. Without these only USB2 operation is possible.
+ *
+ * Copyright (C) The Asahi Linux Contributors
+ * Author: Sven Peter <sven at kernel.org>
+ */
+
+#include <dt-bindings/phy/phy.h>
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include <linux/lockdep.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/soc/apple/tunable.h>
+#include <linux/types.h>
+#include <linux/usb/pd.h>
+#include <linux/usb/typec.h>
+#include <linux/usb/typec_altmode.h>
+#include <linux/usb/typec_dp.h>
+#include <linux/usb/typec_mux.h>
+#include <linux/usb/typec_tbt.h>
+
+#define AUSPLL_FSM_CTRL 0x1014
+
+#define AUSPLL_APB_CMD_OVERRIDE 0x2000
+#define AUSPLL_APB_CMD_OVERRIDE_REQ BIT(0)
+#define AUSPLL_APB_CMD_OVERRIDE_ACK BIT(1)
+#define AUSPLL_APB_CMD_OVERRIDE_UNK28 BIT(28)
+#define AUSPLL_APB_CMD_OVERRIDE_CMD GENMASK(27, 3)
+
+#define AUSPLL_FREQ_DESC_A 0x2080
+#define AUSPLL_FD_FREQ_COUNT_TARGET GENMASK(9, 0)
+#define AUSPLL_FD_FBDIVN_HALF BIT(10)
+#define AUSPLL_FD_REV_DIVN GENMASK(13, 11)
+#define AUSPLL_FD_KI_MAN GENMASK(17, 14)
+#define AUSPLL_FD_KI_EXP GENMASK(21, 18)
+#define AUSPLL_FD_KP_MAN GENMASK(25, 22)
+#define AUSPLL_FD_KP_EXP GENMASK(29, 26)
+#define AUSPLL_FD_KPKI_SCALE_HBW GENMASK(31, 30)
+
+#define AUSPLL_FREQ_DESC_B 0x2084
+#define AUSPLL_FD_FBDIVN_FRAC_DEN GENMASK(13, 0)
+#define AUSPLL_FD_FBDIVN_FRAC_NUM GENMASK(27, 14)
+
+#define AUSPLL_FREQ_DESC_C 0x2088
+#define AUSPLL_FD_SDM_SSC_STEP GENMASK(7, 0)
+#define AUSPLL_FD_SDM_SSC_EN BIT(8)
+#define AUSPLL_FD_PCLK_DIV_SEL GENMASK(13, 9)
+#define AUSPLL_FD_LFSDM_DIV GENMASK(15, 14)
+#define AUSPLL_FD_LFCLK_CTRL GENMASK(19, 16)
+#define AUSPLL_FD_VCLK_OP_DIVN GENMASK(21, 20)
+#define AUSPLL_FD_VCLK_PRE_DIVN BIT(22)
+
+#define AUSPLL_DCO_EFUSE_SPARE 0x222c
+#define AUSPLL_RODCO_ENCAP_EFUSE GENMASK(10, 9)
+#define AUSPLL_RODCO_BIAS_ADJUST_EFUSE GENMASK(14, 12)
+
+#define AUSPLL_FRACN_CAN 0x22a4
+#define AUSPLL_DLL_START_CAPCODE GENMASK(18, 17)
+
+#define AUSPLL_CLKOUT_MASTER 0x2200
+#define AUSPLL_CLKOUT_MASTER_PCLK_DRVR_EN BIT(2)
+#define AUSPLL_CLKOUT_MASTER_PCLK2_DRVR_EN BIT(4)
+#define AUSPLL_CLKOUT_MASTER_REFBUFCLK_DRVR_EN BIT(6)
+
+#define AUSPLL_CLKOUT_DIV 0x2208
+#define AUSPLL_CLKOUT_PLLA_REFBUFCLK_DI GENMASK(20, 16)
+
+#define AUSPLL_BGR 0x2214
+#define AUSPLL_BGR_CTRL_AVAIL BIT(0)
+
+#define AUSPLL_CLKOUT_DTC_VREG 0x2220
+#define AUSPLL_DTC_VREG_ADJUST GENMASK(16, 14)
+#define AUSPLL_DTC_VREG_BYPASS BIT(7)
+
+#define AUSPLL_FREQ_CFG 0x2224
+#define AUSPLL_FREQ_REFCLK GENMASK(1, 0)
+
+#define AUS_COMMON_SHIM_BLK_VREG 0x0a04
+#define AUS_VREG_TRIM GENMASK(6, 2)
+
+#define AUS_UNK_A20 0x0a20
+#define AUS_UNK_A20_TX_CAL_CODE GENMASK(23, 20)
+
+#define ACIOPHY_CMN_SHM_STS_REG0 0x0a74
+#define ACIOPHY_CMN_SHM_STS_REG0_CMD_READY BIT(0)
+
+#define CIO3PLL_CLK_CTRL 0x2a00
+#define CIO3PLL_CLK_PCLK_EN BIT(1)
+#define CIO3PLL_CLK_REFCLK_EN BIT(5)
+
+#define CIO3PLL_DCO_NCTRL 0x2a38
+#define CIO3PLL_DCO_COARSEBIN_EFUSE0 GENMASK(6, 0)
+#define CIO3PLL_DCO_COARSEBIN_EFUSE1 GENMASK(23, 17)
+
+#define CIO3PLL_FRACN_CAN 0x2aa4
+#define CIO3PLL_DLL_CAL_START_CAPCODE GENMASK(18, 17)
+
+#define CIO3PLL_DTC_VREG 0x2a20
+#define CIO3PLL_DTC_VREG_ADJUST GENMASK(16, 14)
+
+#define ACIOPHY_CFG0 0x08
+#define ACIOPHY_CFG0_COMMON_BIG_OV BIT(1)
+#define ACIOPHY_CFG0_COMMON_SMALL_OV BIT(3)
+#define ACIOPHY_CFG0_COMMON_CLAMP_OV BIT(5)
+#define ACIOPHY_CFG0_RX_SMALL_OV GENMASK(9, 8)
+#define ACIOPHY_CFG0_RX_BIG_OV GENMASK(13, 12)
+#define ACIOPHY_CFG0_RX_CLAMP_OV GENMASK(17, 16)
+
+#define ACIOPHY_CROSSBAR 0x4c
+#define ACIOPHY_CROSSBAR_PROTOCOL GENMASK(4, 0)
+#define ACIOPHY_CROSSBAR_PROTOCOL_USB4 0x0
+#define ACIOPHY_CROSSBAR_PROTOCOL_USB4_SWAPPED 0x1
+#define ACIOPHY_CROSSBAR_PROTOCOL_USB3 0xa
+#define ACIOPHY_CROSSBAR_PROTOCOL_USB3_SWAPPED 0xb
+#define ACIOPHY_CROSSBAR_PROTOCOL_USB3_DP 0x10
+#define ACIOPHY_CROSSBAR_PROTOCOL_USB3_DP_SWAPPED 0x11
+#define ACIOPHY_CROSSBAR_PROTOCOL_DP 0x14
+#define ACIOPHY_CROSSBAR_DP_SINGLE_PMA GENMASK(16, 5)
+#define ACIOPHY_CROSSBAR_DP_SINGLE_PMA_NONE 0x0000
+#define ACIOPHY_CROSSBAR_DP_SINGLE_PMA_UNK100 0x100
+#define ACIOPHY_CROSSBAR_DP_SINGLE_PMA_UNK008 0x008
+#define ACIOPHY_CROSSBAR_DP_BOTH_PMA BIT(17)
+
+#define ACIOPHY_LANE_MODE 0x48
+#define ACIOPHY_LANE_MODE_RX0 GENMASK(2, 0)
+#define ACIOPHY_LANE_MODE_TX0 GENMASK(5, 3)
+#define ACIOPHY_LANE_MODE_RX1 GENMASK(8, 6)
+#define ACIOPHY_LANE_MODE_TX1 GENMASK(11, 9)
+
+enum atcphy_lane_mode {
+	ACIOPHY_LANE_MODE_USB4 = 0,
+	ACIOPHY_LANE_MODE_USB3 = 1,
+	ACIOPHY_LANE_MODE_DP = 2,
+	ACIOPHY_LANE_MODE_OFF = 3,
+};
+
+#define ACIOPHY_TOP_BIST_CIOPHY_CFG1 0x84
+#define ACIOPHY_TOP_BIST_CIOPHY_CFG1_CLK_EN BIT(27)
+#define ACIOPHY_TOP_BIST_CIOPHY_CFG1_BIST_EN BIT(28)
+
+#define ACIOPHY_TOP_BIST_OV_CFG 0x8c
+#define ACIOPHY_TOP_BIST_OV_CFG_LN0_RESET_N_OV BIT(13)
+#define ACIOPHY_TOP_BIST_OV_CFG_LN0_PWR_DOWN_OV BIT(25)
+
+#define ACIOPHY_TOP_BIST_READ_CTRL 0x90
+#define ACIOPHY_TOP_BIST_READ_CTRL_LN0_PHY_STATUS_RE BIT(2)
+
+#define ACIOPHY_TOP_PHY_STAT 0x9c
+#define ACIOPHY_TOP_PHY_STAT_LN0_UNK0 BIT(0)
+#define ACIOPHY_TOP_PHY_STAT_LN0_UNK23 BIT(23)
+
+#define ACIOPHY_TOP_BIST_PHY_CFG0 0xa8
+#define ACIOPHY_TOP_BIST_PHY_CFG0_LN0_RESET_N BIT(0)
+
+#define ACIOPHY_TOP_BIST_PHY_CFG1 0xac
+#define ACIOPHY_TOP_BIST_PHY_CFG1_LN0_PWR_DOWN GENMASK(13, 10)
+
+#define ACIOPHY_SLEEP_CTRL 0x1b0
+#define ACIOPHY_SLEEP_CTRL_TX_BIG_OV GENMASK(3, 2)
+#define ACIOPHY_SLEEP_CTRL_TX_SMALL_OV GENMASK(7, 6)
+#define ACIOPHY_SLEEP_CTRL_TX_CLAMP_OV GENMASK(11, 10)
+
+#define ACIOPHY_PLL_PCTL_FSM_CTRL1 0x1014
+#define ACIOPHY_PLL_APB_REQ_OV_SEL GENMASK(21, 13)
+#define ACIOPHY_PLL_COMMON_CTRL 0x1028
+#define ACIOPHY_PLL_WAIT_FOR_CMN_READY_BEFORE_RESET_EXIT BIT(24)
+
+#define ATCPHY_POWER_CTRL 0x20000
+#define ATCPHY_POWER_STAT 0x20004
+#define ATCPHY_POWER_SLEEP_SMALL BIT(0)
+#define ATCPHY_POWER_SLEEP_BIG BIT(1)
+#define ATCPHY_POWER_CLAMP_EN BIT(2)
+#define ATCPHY_POWER_APB_RESET_N BIT(3)
+#define ATCPHY_POWER_PHY_RESET_N BIT(4)
+
+#define ATCPHY_MISC 0x20008
+#define ATCPHY_MISC_RESET_N BIT(0)
+#define ATCPHY_MISC_LANE_SWAP BIT(2)
+
+#define ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0 0x7000
+#define DP_PMA_BYTECLK_RESET BIT(0)
+#define DP_MAC_DIV20_CLK_SEL BIT(1)
+#define DPTXPHY_PMA_LANE_RESET_N BIT(2)
+#define DPTXPHY_PMA_LANE_RESET_N_OV BIT(3)
+#define DPTX_PCLK1_SELECT GENMASK(6, 4)
+#define DPTX_PCLK2_SELECT GENMASK(9, 7)
+#define DPRX_PCLK_SELECT GENMASK(12, 10)
+#define DPTX_PCLK1_ENABLE BIT(13)
+#define DPTX_PCLK2_ENABLE BIT(14)
+#define DPRX_PCLK_ENABLE BIT(15)
+
+#define ACIOPHY_DP_PCLK_STAT 0x7044
+#define ACIOPHY_AUSPLL_LOCK BIT(3)
+
+#define LN0_AUSPMA_RX_TOP 0x9000
+#define LN0_AUSPMA_RX_EQ 0xA000
+#define LN0_AUSPMA_RX_SHM 0xB000
+#define LN0_AUSPMA_TX_TOP 0xC000
+#define LN0_AUSPMA_TX_SHM 0xD000
+
+#define LN1_AUSPMA_RX_TOP 0x10000
+#define LN1_AUSPMA_RX_EQ 0x11000
+#define LN1_AUSPMA_RX_SHM 0x12000
+#define LN1_AUSPMA_TX_TOP 0x13000
+#define LN1_AUSPMA_TX_SHM 0x14000
+
+#define LN_AUSPMA_RX_TOP_PMAFSM 0x0010
+#define LN_AUSPMA_RX_TOP_PMAFSM_PCS_OV BIT(0)
+#define LN_AUSPMA_RX_TOP_PMAFSM_PCS_REQ BIT(9)
+
+#define LN_AUSPMA_RX_TOP_TJ_CFG_RX_TXMODE 0x00F0
+#define LN_RX_TXMODE BIT(0)
+
+#define LN_AUSPMA_RX_SHM_TJ_RXA_CTLE_CTRL0 0x00
+#define LN_TX_CLK_EN BIT(20)
+#define LN_TX_CLK_EN_OV BIT(21)
+
+#define LN_AUSPMA_RX_SHM_TJ_RXA_AFE_CTRL1 0x04
+#define LN_RX_DIV20_RESET_N_OV BIT(29)
+#define LN_RX_DIV20_RESET_N BIT(30)
+
+#define LN_AUSPMA_RX_SHM_TJ_RXA_UNK_CTRL2 0x08
+#define LN_AUSPMA_RX_SHM_TJ_RXA_UNK_CTRL3 0x0C
+#define LN_AUSPMA_RX_SHM_TJ_RXA_UNK_CTRL4 0x10
+#define LN_AUSPMA_RX_SHM_TJ_RXA_UNK_CTRL5 0x14
+#define LN_AUSPMA_RX_SHM_TJ_RXA_UNK_CTRL6 0x18
+#define LN_AUSPMA_RX_SHM_TJ_RXA_UNK_CTRL7 0x1C
+#define LN_AUSPMA_RX_SHM_TJ_RXA_UNK_CTRL8 0x20
+#define LN_AUSPMA_RX_SHM_TJ_RXA_UNK_CTRL9 0x24
+#define LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL10 0x28
+#define LN_DTVREG_ADJUST GENMASK(31, 27)
+
+#define LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL11 0x2C
+#define LN_DTVREG_BIG_EN BIT(23)
+#define LN_DTVREG_BIG_EN_OV BIT(24)
+#define LN_DTVREG_SML_EN BIT(25)
+#define LN_DTVREG_SML_EN_OV BIT(26)
+
+#define LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL12 0x30
+#define LN_TX_BYTECLK_RESET_SYNC_CLR BIT(22)
+#define LN_TX_BYTECLK_RESET_SYNC_CLR_OV BIT(23)
+#define LN_TX_BYTECLK_RESET_SYNC_EN BIT(24)
+#define LN_TX_BYTECLK_RESET_SYNC_EN_OV BIT(25)
+#define LN_TX_HRCLK_SEL BIT(28)
+#define LN_TX_HRCLK_SEL_OV BIT(29)
+#define LN_TX_PBIAS_EN BIT(30)
+#define LN_TX_PBIAS_EN_OV BIT(31)
+
+#define LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL13 0x34
+#define LN_TX_PRE_EN BIT(0)
+#define LN_TX_PRE_EN_OV BIT(1)
+#define LN_TX_PST1_EN BIT(2)
+#define LN_TX_PST1_EN_OV BIT(3)
+#define LN_DTVREG_ADJUST_OV BIT(15)
+
+#define LN_AUSPMA_RX_SHM_TJ_UNK_CTRL14A 0x38
+#define LN_AUSPMA_RX_SHM_TJ_UNK_CTRL14B 0x3C
+#define LN_AUSPMA_RX_SHM_TJ_UNK_CTRL15A 0x40
+#define LN_AUSPMA_RX_SHM_TJ_UNK_CTRL15B 0x44
+#define LN_AUSPMA_RX_SHM_TJ_RXA_SAVOS_CTRL16 0x48
+#define LN_RXTERM_EN BIT(21)
+#define LN_RXTERM_EN_OV BIT(22)
+#define LN_RXTERM_PULLUP_LEAK_EN BIT(23)
+#define LN_RXTERM_PULLUP_LEAK_EN_OV BIT(24)
+#define LN_TX_CAL_CODE GENMASK(29, 25)
+#define LN_TX_CAL_CODE_OV BIT(30)
+
+#define LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL17 0x4C
+#define LN_TX_MARGIN GENMASK(19, 15)
+#define LN_TX_MARGIN_OV BIT(20)
+#define LN_TX_MARGIN_LSB BIT(21)
+#define LN_TX_MARGIN_LSB_OV BIT(22)
+#define LN_TX_MARGIN_P1 GENMASK(26, 23)
+#define LN_TX_MARGIN_P1_OV BIT(27)
+#define LN_TX_MARGIN_P1_LSB GENMASK(29, 28)
+#define LN_TX_MARGIN_P1_LSB_OV BIT(30)
+
+#define LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL18 0x50
+#define LN_TX_P1_CODE GENMASK(3, 0)
+#define LN_TX_P1_CODE_OV BIT(4)
+#define LN_TX_P1_LSB_CODE GENMASK(6, 5)
+#define LN_TX_P1_LSB_CODE_OV BIT(7)
+#define LN_TX_MARGIN_PRE GENMASK(10, 8)
+#define LN_TX_MARGIN_PRE_OV BIT(11)
+#define LN_TX_MARGIN_PRE_LSB GENMASK(13, 12)
+#define LN_TX_MARGIN_PRE_LSB_OV BIT(14)
+#define LN_TX_PRE_LSB_CODE GENMASK(16, 15)
+#define LN_TX_PRE_LSB_CODE_OV BIT(17)
+#define LN_TX_PRE_CODE GENMASK(21, 18)
+#define LN_TX_PRE_CODE_OV BIT(22)
+
+#define LN_AUSPMA_RX_SHM_TJ_RXA_TERM_CTRL19 0x54
+#define LN_TX_TEST_EN BIT(21)
+#define LN_TX_TEST_EN_OV BIT(22)
+#define LN_TX_EN BIT(23)
+#define LN_TX_EN_OV BIT(24)
+#define LN_TX_CLK_DLY_CTRL_TAPGEN GENMASK(27, 25)
+#define LN_TX_CLK_DIV2_EN BIT(28)
+#define LN_TX_CLK_DIV2_EN_OV BIT(29)
+#define LN_TX_CLK_DIV2_RST BIT(30)
+#define LN_TX_CLK_DIV2_RST_OV BIT(31)
+
+#define LN_AUSPMA_RX_SHM_TJ_RXA_UNK_CTRL20 0x58
+#define LN_AUSPMA_RX_SHM_TJ_RXA_UNK_CTRL21 0x5C
+#define LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22 0x60
+#define LN_VREF_ADJUST_GRAY GENMASK(11, 7)
+#define LN_VREF_ADJUST_GRAY_OV BIT(12)
+#define LN_VREF_BIAS_SEL GENMASK(14, 13)
+#define LN_VREF_BIAS_SEL_OV BIT(15)
+#define LN_VREF_BOOST_EN BIT(16)
+#define LN_VREF_BOOST_EN_OV BIT(17)
+#define LN_VREF_EN BIT(18)
+#define LN_VREF_EN_OV BIT(19)
+#define LN_VREF_LPBKIN_DATA GENMASK(29, 28)
+#define LN_VREF_TEST_RXLPBKDT_EN BIT(30)
+#define LN_VREF_TEST_RXLPBKDT_EN_OV BIT(31)
+
+#define LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG0 0x00
+#define LN_BYTECLK_RESET_SYNC_EN_OV BIT(2)
+#define LN_BYTECLK_RESET_SYNC_EN BIT(3)
+#define LN_BYTECLK_RESET_SYNC_CLR_OV BIT(4)
+#define LN_BYTECLK_RESET_SYNC_CLR BIT(5)
+#define LN_BYTECLK_RESET_SYNC_SEL_OV BIT(6)
+
+#define LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG1 0x04
+#define LN_TXA_DIV2_EN_OV BIT(8)
+#define LN_TXA_DIV2_EN BIT(9)
+#define LN_TXA_DIV2_RESET_OV BIT(10)
+#define LN_TXA_DIV2_RESET BIT(11)
+#define LN_TXA_CLK_EN_OV BIT(22)
+#define LN_TXA_CLK_EN BIT(23)
+
+#define LN_AUSPMA_TX_SHM_TXA_IMP_REG0 0x08
+#define LN_TXA_CAL_CTRL_OV BIT(0)
+#define LN_TXA_CAL_CTRL GENMASK(18, 1)
+#define LN_TXA_CAL_CTRL_BASE_OV BIT(19)
+#define LN_TXA_CAL_CTRL_BASE GENMASK(23, 20)
+#define LN_TXA_HIZ_OV BIT(29)
+#define LN_TXA_HIZ BIT(30)
+
+#define LN_AUSPMA_TX_SHM_TXA_IMP_REG1 0x0C
+#define LN_AUSPMA_TX_SHM_TXA_IMP_REG2 0x10
+#define LN_TXA_MARGIN_OV BIT(0)
+#define LN_TXA_MARGIN GENMASK(18, 1)
+#define LN_TXA_MARGIN_2R_OV BIT(19)
+#define LN_TXA_MARGIN_2R BIT(20)
+
+#define LN_AUSPMA_TX_SHM_TXA_IMP_REG3 0x14
+#define LN_TXA_MARGIN_POST_OV BIT(0)
+#define LN_TXA_MARGIN_POST GENMASK(10, 1)
+#define LN_TXA_MARGIN_POST_2R_OV BIT(11)
+#define LN_TXA_MARGIN_POST_2R BIT(12)
+#define LN_TXA_MARGIN_POST_4R_OV BIT(13)
+#define LN_TXA_MARGIN_POST_4R BIT(14)
+#define LN_TXA_MARGIN_PRE_OV BIT(15)
+#define LN_TXA_MARGIN_PRE GENMASK(21, 16)
+#define LN_TXA_MARGIN_PRE_2R_OV BIT(22)
+#define LN_TXA_MARGIN_PRE_2R BIT(23)
+#define LN_TXA_MARGIN_PRE_4R_OV BIT(24)
+#define LN_TXA_MARGIN_PRE_4R BIT(25)
+
+#define LN_AUSPMA_TX_SHM_TXA_UNK_REG0 0x18
+#define LN_AUSPMA_TX_SHM_TXA_UNK_REG1 0x1C
+#define LN_AUSPMA_TX_SHM_TXA_UNK_REG2 0x20
+
+#define LN_AUSPMA_TX_SHM_TXA_LDOCLK 0x24
+#define LN_LDOCLK_BYPASS_SML_OV BIT(8)
+#define LN_LDOCLK_BYPASS_SML BIT(9)
+#define LN_LDOCLK_BYPASS_BIG_OV BIT(10)
+#define LN_LDOCLK_BYPASS_BIG BIT(11)
+#define LN_LDOCLK_EN_SML_OV BIT(12)
+#define LN_LDOCLK_EN_SML BIT(13)
+#define LN_LDOCLK_EN_BIG_OV BIT(14)
+#define LN_LDOCLK_EN_BIG BIT(15)
+
+/* LPDPTX registers */
+#define LPDPTX_AUX_CFG_BLK_AUX_CTRL 0x0000
+#define LPDPTX_BLK_AUX_CTRL_PWRDN BIT(4)
+#define LPDPTX_BLK_AUX_RXOFFSET GENMASK(25, 22)
+
+#define LPDPTX_AUX_CFG_BLK_AUX_LDO_CTRL 0x0008
+
+#define LPDPTX_AUX_CFG_BLK_AUX_MARGIN 0x000c
+#define LPDPTX_MARGIN_RCAL_RXOFFSET_EN BIT(5)
+#define LPDPTX_AUX_MARGIN_RCAL_TXSWING GENMASK(10, 6)
+
+#define LPDPTX_AUX_SHM_CFG_BLK_AUX_CTRL_REG0 0x0204
+#define LPDPTX_CFG_PMA_AUX_SEL_LF_DATA BIT(15)
+
+#define LPDPTX_AUX_SHM_CFG_BLK_AUX_CTRL_REG1 0x0208
+#define LPDPTX_CFG_PMA_PHYS_ADJ GENMASK(22, 20)
+#define LPDPTX_CFG_PMA_PHYS_ADJ_OV BIT(19)
+
+#define LPDPTX_AUX_CONTROL 0x4000
+#define LPDPTX_AUX_PWN_DOWN 0x10
+#define LPDPTX_AUX_CLAMP_EN 0x04
+#define LPDPTX_SLEEP_B_BIG_IN 0x02
+#define LPDPTX_SLEEP_B_SML_IN 0x01
+#define LPDPTX_TXTERM_CODEMSB 0x400
+#define LPDPTX_TXTERM_CODE GENMASK(9, 5)
+
+/* pipehandler registers */
+#define PIPEHANDLER_OVERRIDE 0x00
+#define PIPEHANDLER_OVERRIDE_RXVALID BIT(0)
+#define PIPEHANDLER_OVERRIDE_RXDETECT BIT(2)
+
+#define PIPEHANDLER_OVERRIDE_VALUES 0x04
+#define PIPEHANDLER_OVERRIDE_VAL_RXDETECT0 BIT(1)
+#define PIPEHANDLER_OVERRIDE_VAL_RXDETECT1 BIT(2)
+#define PIPEHANDLER_OVERRIDE_VAL_PHY_STATUS BIT(4)
+
+#define PIPEHANDLER_MUX_CTRL 0x0c
+#define PIPEHANDLER_MUX_CTRL_CLK GENMASK(5, 3)
+#define PIPEHANDLER_MUX_CTRL_DATA GENMASK(2, 0)
+#define PIPEHANDLER_MUX_CTRL_CLK_OFF 0
+#define PIPEHANDLER_MUX_CTRL_CLK_USB3 1
+#define PIPEHANDLER_MUX_CTRL_CLK_USB4 2
+#define PIPEHANDLER_MUX_CTRL_CLK_DUMMY 4
+
+#define PIPEHANDLER_MUX_CTRL_DATA_USB3 0
+#define PIPEHANDLER_MUX_CTRL_DATA_USB4 1
+#define PIPEHANDLER_MUX_CTRL_DATA_DUMMY 2
+
+#define PIPEHANDLER_LOCK_REQ 0x10
+#define PIPEHANDLER_LOCK_ACK 0x14
+#define PIPEHANDLER_LOCK_EN BIT(0)
+
+#define PIPEHANDLER_AON_GEN 0x1C
+#define PIPEHANDLER_AON_GEN_DWC3_FORCE_CLAMP_EN BIT(4)
+#define PIPEHANDLER_AON_GEN_DWC3_RESET_N BIT(0)
+
+#define PIPEHANDLER_NONSELECTED_OVERRIDE 0x20
+#define PIPEHANDLER_NATIVE_RESET BIT(12)
+#define PIPEHANDLER_DUMMY_PHY_EN BIT(15)
+#define PIPEHANDLER_NATIVE_POWER_DOWN GENMASK(3, 0)
+
+#define PIPEHANDLER_LOCK_ACK_TIMEOUT_US 1000
+
+/* USB2 PHY regs */
+#define USB2PHY_USBCTL 0x00
+#define USB2PHY_USBCTL_RUN 2
+#define USB2PHY_USBCTL_ISOLATION 4
+
+#define USB2PHY_CTL 0x04
+#define USB2PHY_CTL_RESET BIT(0)
+#define USB2PHY_CTL_PORT_RESET BIT(1)
+#define USB2PHY_CTL_APB_RESET_N BIT(2)
+#define USB2PHY_CTL_SIDDQ BIT(3)
+
+#define USB2PHY_SIG 0x08
+#define USB2PHY_SIG_VBUSDET_FORCE_VAL BIT(0)
+#define USB2PHY_SIG_VBUSDET_FORCE_EN BIT(1)
+#define USB2PHY_SIG_VBUSVLDEXT_FORCE_VAL BIT(2)
+#define USB2PHY_SIG_VBUSVLDEXT_FORCE_EN BIT(3)
+#define USB2PHY_SIG_HOST (7 << 12)
+
+#define USB2PHY_MISCTUNE 0x1c
+#define USB2PHY_MISCTUNE_APBCLK_GATE_OFF BIT(29)
+#define USB2PHY_MISCTUNE_REFCLK_GATE_OFF BIT(30)
+
+enum atcphy_dp_link_rate {
+	ATCPHY_DP_LINK_RATE_RBR,
+	ATCPHY_DP_LINK_RATE_HBR,
+	ATCPHY_DP_LINK_RATE_HBR2,
+	ATCPHY_DP_LINK_RATE_HBR3,
+};
+
+/**
+ * enum atcphy_pipehandler_state - States of the PIPE mux interface ("pipehandler")
+ * @ATCPHY_PIPEHANDLER_STATE_DUMMY: "Dummy PHY" (disables USB3, USB2 only)
+ * @ATCPHY_PIPEHANDLER_STATE_USB3: USB3 directly connected to the Type-C port
+ * @ATCPHY_PIPEHANDLER_STATE_USB4: USB3 tunneled via USB4/Thunderbolt
+ *
+ * DWC3's USB3 PIPE interface is connected to a multiplexer inside this PHY
+ * which can switch between a dummy state (which effectively disables any USB3
+ * support and falls back to USB2 only operation via the separate ULPI interface),
+ * a USB3 state (for regular USB3 or USB3+DisplayPort operation) and a USB4 state
+ * (for USB3 tunneled via USB4/Thunderbolt).
+ */
+enum atcphy_pipehandler_state {
+	ATCPHY_PIPEHANDLER_STATE_DUMMY,
+	ATCPHY_PIPEHANDLER_STATE_USB3,
+	ATCPHY_PIPEHANDLER_STATE_USB4,
+};
+
+/**
+ * enum atcphy_mode - Operating modes of the PHY
+ * @APPLE_ATCPHY_MODE_OFF: all PHYs powered off
+ * @APPLE_ATCPHY_MODE_USB2: Nothing on the four SS lanes (i.e. USB2 only on D-/+)
+ * @APPLE_ATCPHY_MODE_USB3: USB3 on two lanes, nothing on the other two
+ * @APPLE_ATCPHY_MODE_USB3_DP: USB3 on two lanes and DisplayPort on the other two
+ * @APPLE_ATCPHY_MODE_TBT: Thunderbolt on all lanes
+ * @APPLE_ATCPHY_MODE_USB4: USB4 on all lanes
+ * @APPLE_ATCPHY_MODE_DP: DisplayPort on all lanes
+ */
+enum atcphy_mode {
+	APPLE_ATCPHY_MODE_OFF,
+	APPLE_ATCPHY_MODE_USB2,
+	APPLE_ATCPHY_MODE_USB3,
+	APPLE_ATCPHY_MODE_USB3_DP,
+	APPLE_ATCPHY_MODE_TBT,
+	APPLE_ATCPHY_MODE_USB4,
+	APPLE_ATCPHY_MODE_DP,
+};
+
+enum atcphy_lane {
+	APPLE_ATCPHY_LANE_0,
+	APPLE_ATCPHY_LANE_1,
+};
+
+/* Link rate configuration, field names are taken from XNU debug output or register names */
+struct atcphy_dp_link_rate_configuration {
+	u16 freqinit_count_target;
+	u16 fbdivn_frac_den;
+	u16 fbdivn_frac_num;
+	u16 pclk_div_sel;
+	u8 lfclk_ctrl;
+	u8 vclk_op_divn;
+	bool plla_clkout_vreg_bypass;
+	bool txa_ldoclk_bypass;
+	bool txa_div2_en;
+};
+
+/* Crossbar and lane configuration */
+struct atcphy_mode_configuration {
+	u32 crossbar;
+	u32 crossbar_dp_single_pma;
+	bool crossbar_dp_both_pma;
+	enum atcphy_lane_mode lane_mode[2];
+	bool dp_lane[2];
+	bool set_swap;
+};
+
+/**
+ * struct apple_atcphy - Apple Type-C PHY device struct
+ * @np: Device node pointer
+ * @dev: Device pointer
+ * @tunables: Firmware-provided tunable parameters
+ * @tunables.axi2af: AXI to AF interface tunables
+ * @tunables.common: Common tunables for all lanes
+ * @tunables.lane_usb3: USB3 lane-specific tunables
+ * @tunables.lane_dp: DisplayPort lane-specific tunables
+ * @tunables.lane_usb4: USB4 lane-specific tunables
+ * @mode: Current PHY operating mode
+ * @swap_lanes: True if lanes must be swapped due to cable orientation
+ * @dp_link_rate: DisplayPort link rate
+ * @pipehandler_up: True if the PIPE mux ("pipehandler") is set to USB3 or USB4 mode
+ * @regs: Memory-mapped registers
+ * @regs.core: Core registers
+ * @regs.axi2af: AXI to Apple Fabric interface registers
+ * @regs.usb2phy: USB2 PHY registers
+ * @regs.pipehandler: USB3 PIPE interface ("pipehandler") registers
+ * @regs.lpdptx: DisplayPort registers
+ * @res: Resources for memory-mapped registers, used to verify that tunables aren't out of bounds
+ * @res.core: Core register resource
+ * @res.axi2af: AXI to Apple Fabric interface resource
+ * @phys: PHY instances
+ * @phys.usb2: USB2 PHY instance
+ * @phys.usb3: USB3 PHY instance
+ * @phys.dp: DisplayPort PHY instance
+ * @phy_provider: PHY provider instance
+ * @rcdev: Reset controller device
+ * @sw: Type-C switch instance
+ * @mux: Type-C mux instance
+ * @lock: Mutex for synchronizing register access across PHY, Type-C switch/mux and reset controller
+ */
+struct apple_atcphy {
+	struct device_node *np;
+	struct device *dev;
+
+	struct {
+		struct apple_tunable *axi2af;
+		struct apple_tunable *common[2];
+		struct apple_tunable *lane_usb3[2];
+		struct apple_tunable *lane_dp[2];
+		struct apple_tunable *lane_usb4[2];
+	} tunables;
+
+	enum atcphy_mode mode;
+	bool swap_lanes;
+	int dp_link_rate;
+	bool pipehandler_up;
+
+	struct {
+		void __iomem *core;
+		void __iomem *axi2af;
+		void __iomem *usb2phy;
+		void __iomem *pipehandler;
+		void __iomem *lpdptx;
+	} regs;
+
+	struct {
+		struct resource *core;
+		struct resource *axi2af;
+	} res;
+
+	struct {
+		struct phy *usb2;
+		struct phy *usb3;
+		struct phy *dp;
+	} phys;
+	struct phy_provider *phy_provider;
+
+	struct reset_controller_dev rcdev;
+
+	struct typec_switch *sw;
+	struct typec_mux *mux;
+
+	struct mutex lock;
+};
+
+static const struct {
+	const struct atcphy_mode_configuration normal;
+	const struct atcphy_mode_configuration swapped;
+	bool enable_dp_aux;
+	enum atcphy_pipehandler_state pipehandler_state;
+} atcphy_modes[] = {
+	[APPLE_ATCPHY_MODE_OFF] = {
+		.normal = {
+			.crossbar = ACIOPHY_CROSSBAR_PROTOCOL_USB3,
+			.crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_NONE,
+			.crossbar_dp_both_pma = false,
+			.lane_mode = {ACIOPHY_LANE_MODE_OFF, ACIOPHY_LANE_MODE_OFF},
+			.dp_lane = {false, false},
+			.set_swap = false,
+		},
+		.swapped = {
+			.crossbar = ACIOPHY_CROSSBAR_PROTOCOL_USB3_SWAPPED,
+			.crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_NONE,
+			.crossbar_dp_both_pma = false,
+			.lane_mode = {ACIOPHY_LANE_MODE_OFF, ACIOPHY_LANE_MODE_OFF},
+			.dp_lane = {false, false},
+			.set_swap = false, /* doesn't matter since the SS lanes are off */
+		},
+		.enable_dp_aux = false,
+		.pipehandler_state = ATCPHY_PIPEHANDLER_STATE_DUMMY,
+	},
+	[APPLE_ATCPHY_MODE_USB2] = {
+		.normal = {
+			.crossbar = ACIOPHY_CROSSBAR_PROTOCOL_USB3,
+			.crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_NONE,
+			.crossbar_dp_both_pma = false,
+			.lane_mode = {ACIOPHY_LANE_MODE_OFF, ACIOPHY_LANE_MODE_OFF},
+			.dp_lane = {false, false},
+			.set_swap = false,
+		},
+		.swapped = {
+			.crossbar = ACIOPHY_CROSSBAR_PROTOCOL_USB3_SWAPPED,
+			.crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_NONE,
+			.crossbar_dp_both_pma = false,
+			.lane_mode = {ACIOPHY_LANE_MODE_OFF, ACIOPHY_LANE_MODE_OFF},
+			.dp_lane = {false, false},
+			.set_swap = false, /* doesn't matter since the SS lanes are off */
+		},
+		.enable_dp_aux = false,
+		.pipehandler_state = ATCPHY_PIPEHANDLER_STATE_DUMMY,
+	},
+	[APPLE_ATCPHY_MODE_USB3] = {
+		/*
+		 * Setting up the lanes as DP/USB3 is intentional here, USB3/USB3 does not work
+		 * and isn't required since this PHY does not support 20GBps mode anyway.
+		 * The only difference to APPLE_ATCPHY_MODE_USB3_DP is that DP Aux is not enabled.
+		 */
+		.normal = {
+			.crossbar = ACIOPHY_CROSSBAR_PROTOCOL_USB3_DP,
+			.crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_UNK008,
+			.crossbar_dp_both_pma = false,
+			.lane_mode = {ACIOPHY_LANE_MODE_USB3, ACIOPHY_LANE_MODE_DP},
+			.dp_lane = {false, true},
+			.set_swap = false,
+		},
+		.swapped = {
+			.crossbar = ACIOPHY_CROSSBAR_PROTOCOL_USB3_DP_SWAPPED,
+			.crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_UNK008,
+			.crossbar_dp_both_pma = false,
+			.lane_mode = {ACIOPHY_LANE_MODE_DP, ACIOPHY_LANE_MODE_USB3},
+			.dp_lane = {true, false},
+			.set_swap = true,
+		},
+		.enable_dp_aux = false,
+		.pipehandler_state = ATCPHY_PIPEHANDLER_STATE_USB3,
+	},
+	[APPLE_ATCPHY_MODE_USB3_DP] = {
+		.normal = {
+			.crossbar = ACIOPHY_CROSSBAR_PROTOCOL_USB3_DP,
+			.crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_UNK008,
+			.crossbar_dp_both_pma = false,
+			.lane_mode = {ACIOPHY_LANE_MODE_USB3, ACIOPHY_LANE_MODE_DP},
+			.dp_lane = {false, true},
+			.set_swap = false,
+		},
+		.swapped = {
+			.crossbar = ACIOPHY_CROSSBAR_PROTOCOL_USB3_DP_SWAPPED,
+			.crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_UNK008,
+			.crossbar_dp_both_pma = false,
+			.lane_mode = {ACIOPHY_LANE_MODE_DP, ACIOPHY_LANE_MODE_USB3},
+			.dp_lane = {true, false},
+			.set_swap = true,
+		},
+		.enable_dp_aux = true,
+		.pipehandler_state = ATCPHY_PIPEHANDLER_STATE_USB3,
+	},
+	[APPLE_ATCPHY_MODE_TBT] = {
+		.normal = {
+			.crossbar = ACIOPHY_CROSSBAR_PROTOCOL_USB4,
+			.crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_NONE,
+			.crossbar_dp_both_pma = false,
+			.lane_mode = {ACIOPHY_LANE_MODE_USB4, ACIOPHY_LANE_MODE_USB4},
+			.dp_lane = {false, false},
+			.set_swap = false,
+		},
+		.swapped = {
+			.crossbar = ACIOPHY_CROSSBAR_PROTOCOL_USB4_SWAPPED,
+			.crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_NONE,
+			.crossbar_dp_both_pma = false,
+			.lane_mode = {ACIOPHY_LANE_MODE_USB4, ACIOPHY_LANE_MODE_USB4},
+			.dp_lane = {false, false},
+			.set_swap = false, /* intentionally false */
+		},
+		.enable_dp_aux = false,
+		.pipehandler_state = ATCPHY_PIPEHANDLER_STATE_DUMMY,
+	},
+	[APPLE_ATCPHY_MODE_USB4] = {
+		.normal = {
+			.crossbar = ACIOPHY_CROSSBAR_PROTOCOL_USB4,
+			.crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_NONE,
+			.crossbar_dp_both_pma = false,
+			.lane_mode = {ACIOPHY_LANE_MODE_USB4, ACIOPHY_LANE_MODE_USB4},
+			.dp_lane = {false, false},
+			.set_swap = false,
+		},
+		.swapped = {
+			.crossbar = ACIOPHY_CROSSBAR_PROTOCOL_USB4_SWAPPED,
+			.crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_NONE,
+			.crossbar_dp_both_pma = false,
+			.lane_mode = {ACIOPHY_LANE_MODE_USB4, ACIOPHY_LANE_MODE_USB4},
+			.dp_lane = {false, false},
+			.set_swap = false, /* intentionally false */
+		},
+		.enable_dp_aux = false,
+		.pipehandler_state = ATCPHY_PIPEHANDLER_STATE_USB4,
+	},
+	[APPLE_ATCPHY_MODE_DP] = {
+		.normal = {
+			.crossbar = ACIOPHY_CROSSBAR_PROTOCOL_DP,
+			.crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_UNK100,
+			.crossbar_dp_both_pma = true,
+			.lane_mode = {ACIOPHY_LANE_MODE_DP, ACIOPHY_LANE_MODE_DP},
+			.dp_lane = {true, true},
+			.set_swap = false,
+		},
+		.swapped = {
+			.crossbar = ACIOPHY_CROSSBAR_PROTOCOL_DP,
+			.crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_UNK008,
+			.crossbar_dp_both_pma = false, /* intentionally false */
+			.lane_mode = {ACIOPHY_LANE_MODE_DP, ACIOPHY_LANE_MODE_DP},
+			.dp_lane = {true, true},
+			.set_swap = false, /* intentionally false */
+		},
+		.enable_dp_aux = true,
+		.pipehandler_state = ATCPHY_PIPEHANDLER_STATE_DUMMY,
+	},
+};
+
+static const struct atcphy_dp_link_rate_configuration dp_lr_config[] = {
+	[ATCPHY_DP_LINK_RATE_RBR] = {
+		.freqinit_count_target = 0x21c,
+		.fbdivn_frac_den = 0x0,
+		.fbdivn_frac_num = 0x0,
+		.pclk_div_sel = 0x13,
+		.lfclk_ctrl = 0x5,
+		.vclk_op_divn = 0x2,
+		.plla_clkout_vreg_bypass = true,
+		.txa_ldoclk_bypass = true,
+		.txa_div2_en = true,
+	},
+	[ATCPHY_DP_LINK_RATE_HBR] = {
+		.freqinit_count_target = 0x1c2,
+		.fbdivn_frac_den = 0x3ffe,
+		.fbdivn_frac_num = 0x1fff,
+		.pclk_div_sel = 0x9,
+		.lfclk_ctrl = 0x5,
+		.vclk_op_divn = 0x2,
+		.plla_clkout_vreg_bypass = true,
+		.txa_ldoclk_bypass = true,
+		.txa_div2_en = false,
+	},
+	[ATCPHY_DP_LINK_RATE_HBR2] = {
+		.freqinit_count_target = 0x1c2,
+		.fbdivn_frac_den = 0x3ffe,
+		.fbdivn_frac_num = 0x1fff,
+		.pclk_div_sel = 0x4,
+		.lfclk_ctrl = 0x5,
+		.vclk_op_divn = 0x0,
+		.plla_clkout_vreg_bypass = true,
+		.txa_ldoclk_bypass = true,
+		.txa_div2_en = false,
+	},
+	[ATCPHY_DP_LINK_RATE_HBR3] = {
+		.freqinit_count_target = 0x2a3,
+		.fbdivn_frac_den = 0x3ffc,
+		.fbdivn_frac_num = 0x2ffd,
+		.pclk_div_sel = 0x4,
+		.lfclk_ctrl = 0x6,
+		.vclk_op_divn = 0x0,
+		.plla_clkout_vreg_bypass = false,
+		.txa_ldoclk_bypass = false,
+		.txa_div2_en = false,
+	},
+};
+
+static inline void mask32(void __iomem *reg, u32 mask, u32 set)
+{
+	u32 value = readl(reg);
+
+	value &= ~mask;
+	value |= set;
+	writel(value, reg);
+}
+
+static inline void core_mask32(struct apple_atcphy *atcphy, u32 reg, u32 mask, u32 set)
+{
+	mask32(atcphy->regs.core + reg, mask, set);
+}
+
+static inline void set32(void __iomem *reg, u32 set)
+{
+	mask32(reg, 0, set);
+}
+
+static inline void core_set32(struct apple_atcphy *atcphy, u32 reg, u32 set)
+{
+	core_mask32(atcphy, reg, 0, set);
+}
+
+static inline void clear32(void __iomem *reg, u32 clear)
+{
+	mask32(reg, clear, 0);
+}
+
+static inline void core_clear32(struct apple_atcphy *atcphy, u32 reg, u32 clear)
+{
+	core_mask32(atcphy, reg, clear, 0);
+}
+
+static const struct atcphy_mode_configuration *atcphy_get_mode_config(struct apple_atcphy *atcphy,
+								      enum atcphy_mode mode)
+{
+	if (atcphy->swap_lanes)
+		return &atcphy_modes[mode].swapped;
+	else
+		return &atcphy_modes[mode].normal;
+}
+
+static void atcphy_apply_tunables(struct apple_atcphy *atcphy, enum atcphy_mode mode)
+{
+	const int lane0 = atcphy->swap_lanes ? 1 : 0;
+	const int lane1 = atcphy->swap_lanes ? 0 : 1;
+
+	apple_tunable_apply(atcphy->regs.core, atcphy->tunables.common[0]);
+	apple_tunable_apply(atcphy->regs.axi2af, atcphy->tunables.axi2af);
+	apple_tunable_apply(atcphy->regs.core, atcphy->tunables.common[1]);
+
+	switch (mode) {
+	/*
+	 * USB 3.2 Gen 2x2 / SuperSpeed 20Gbps is not supported by this hardware and applying USB3
+	 * tunables to both lanes does not result in a working PHY configuration. Thus, both
+	 * USB3-only and USB3/DP get the same tunable setup here.
+	 */
+	case APPLE_ATCPHY_MODE_USB3:
+	case APPLE_ATCPHY_MODE_USB3_DP:
+		apple_tunable_apply(atcphy->regs.core, atcphy->tunables.lane_usb3[lane0]);
+		apple_tunable_apply(atcphy->regs.core, atcphy->tunables.lane_dp[lane1]);
+		break;
+
+	case APPLE_ATCPHY_MODE_DP:
+		apple_tunable_apply(atcphy->regs.core, atcphy->tunables.lane_dp[lane0]);
+		apple_tunable_apply(atcphy->regs.core, atcphy->tunables.lane_dp[lane1]);
+		break;
+
+	/*
+	 * Even though the various Thunderbolt versions and USB4 are different protocols they need
+	 * the same tunables. The actual protocol-specific setup happens inside the Thunderbolt/USB4
+	 * native host interface.
+	 */
+	case APPLE_ATCPHY_MODE_TBT:
+	case APPLE_ATCPHY_MODE_USB4:
+		apple_tunable_apply(atcphy->regs.core, atcphy->tunables.lane_usb4[lane0]);
+		apple_tunable_apply(atcphy->regs.core, atcphy->tunables.lane_usb4[lane1]);
+		break;
+
+	case APPLE_ATCPHY_MODE_OFF:
+	case APPLE_ATCPHY_MODE_USB2:
+		break;
+	}
+}
+
+static int atcphy_pipehandler_lock(struct apple_atcphy *atcphy)
+{
+	int ret;
+	u32 reg;
+
+	if (readl(atcphy->regs.pipehandler + PIPEHANDLER_LOCK_REQ) & PIPEHANDLER_LOCK_EN) {
+		dev_warn(atcphy->dev, "Pipehandler already locked\n");
+		return 0;
+	}
+
+	set32(atcphy->regs.pipehandler + PIPEHANDLER_LOCK_REQ, PIPEHANDLER_LOCK_EN);
+
+	ret = readl_poll_timeout(atcphy->regs.pipehandler + PIPEHANDLER_LOCK_ACK, reg,
+				 reg & PIPEHANDLER_LOCK_EN, 10, PIPEHANDLER_LOCK_ACK_TIMEOUT_US);
+	if (ret) {
+		clear32(atcphy->regs.pipehandler + PIPEHANDLER_LOCK_REQ, 1);
+		dev_warn(atcphy->dev, "Pipehandler lock not acked.\n");
+	}
+
+	return ret;
+}
+
+static int atcphy_pipehandler_unlock(struct apple_atcphy *atcphy)
+{
+	int ret;
+	u32 reg;
+
+	clear32(atcphy->regs.pipehandler + PIPEHANDLER_LOCK_REQ, PIPEHANDLER_LOCK_EN);
+	ret = readl_poll_timeout(atcphy->regs.pipehandler + PIPEHANDLER_LOCK_ACK, reg,
+				 !(reg & PIPEHANDLER_LOCK_EN), 10, PIPEHANDLER_LOCK_ACK_TIMEOUT_US);
+	if (ret)
+		dev_warn(atcphy->dev, "Pipehandler lock release not acked.\n");
+
+	return ret;
+}
+
+static int atcphy_pipehandler_check(struct apple_atcphy *atcphy)
+{
+	int ret;
+
+	lockdep_assert_held(&atcphy->lock);
+
+	if (readl(atcphy->regs.pipehandler + PIPEHANDLER_LOCK_ACK) & PIPEHANDLER_LOCK_EN) {
+		dev_warn(atcphy->dev, "Pipehandler already locked\n");
+
+		ret = atcphy_pipehandler_unlock(atcphy);
+		if (ret) {
+			dev_err(atcphy->dev, "Failed to unlock pipehandler\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int atcphy_configure_pipehandler_usb3(struct apple_atcphy *atcphy, bool host)
+{
+	int ret;
+	u32 reg;
+
+	ret = atcphy_pipehandler_check(atcphy);
+	if (ret)
+		return ret;
+
+	/*
+	 * Only host mode requires this unknown BIST sequence to work correctly, possibly due to
+	 * some hardware quirk. Guest mode breaks if we try to apply this sequence.
+	 */
+	if (host) {
+		/* Force disable link detection */
+		clear32(atcphy->regs.pipehandler + PIPEHANDLER_OVERRIDE_VALUES,
+			PIPEHANDLER_OVERRIDE_VAL_RXDETECT0 | PIPEHANDLER_OVERRIDE_VAL_RXDETECT1);
+		set32(atcphy->regs.pipehandler + PIPEHANDLER_OVERRIDE,
+		      PIPEHANDLER_OVERRIDE_RXVALID);
+		set32(atcphy->regs.pipehandler + PIPEHANDLER_OVERRIDE,
+		      PIPEHANDLER_OVERRIDE_RXDETECT);
+
+		ret = atcphy_pipehandler_lock(atcphy);
+		if (ret) {
+			dev_err(atcphy->dev, "Failed to lock pipehandler");
+			return ret;
+		}
+
+		/* BIST dance */
+		core_set32(atcphy, ACIOPHY_TOP_BIST_PHY_CFG0,
+			   ACIOPHY_TOP_BIST_PHY_CFG0_LN0_RESET_N);
+		core_set32(atcphy, ACIOPHY_TOP_BIST_OV_CFG, ACIOPHY_TOP_BIST_OV_CFG_LN0_RESET_N_OV);
+		ret = readl_poll_timeout(atcphy->regs.core + ACIOPHY_TOP_PHY_STAT, reg,
+					 !(reg & ACIOPHY_TOP_PHY_STAT_LN0_UNK23), 10, 10000);
+		if (ret)
+			dev_warn(atcphy->dev,
+				 "Timed out waiting for ACIOPHY_TOP_PHY_STAT_LN0_UNK23\n");
+
+		core_set32(atcphy, ACIOPHY_TOP_BIST_READ_CTRL,
+			   ACIOPHY_TOP_BIST_READ_CTRL_LN0_PHY_STATUS_RE);
+		core_clear32(atcphy, ACIOPHY_TOP_BIST_READ_CTRL,
+			     ACIOPHY_TOP_BIST_READ_CTRL_LN0_PHY_STATUS_RE);
+
+		core_mask32(atcphy, ACIOPHY_TOP_BIST_PHY_CFG1,
+			    ACIOPHY_TOP_BIST_PHY_CFG1_LN0_PWR_DOWN,
+			    FIELD_PREP(ACIOPHY_TOP_BIST_PHY_CFG1_LN0_PWR_DOWN, 3));
+
+		core_set32(atcphy, ACIOPHY_TOP_BIST_OV_CFG,
+			   ACIOPHY_TOP_BIST_OV_CFG_LN0_PWR_DOWN_OV);
+		core_set32(atcphy, ACIOPHY_TOP_BIST_CIOPHY_CFG1,
+			   ACIOPHY_TOP_BIST_CIOPHY_CFG1_CLK_EN);
+		core_set32(atcphy, ACIOPHY_TOP_BIST_CIOPHY_CFG1,
+			   ACIOPHY_TOP_BIST_CIOPHY_CFG1_BIST_EN);
+		writel(0, atcphy->regs.core + ACIOPHY_TOP_BIST_CIOPHY_CFG1);
+
+		ret = readl_poll_timeout(atcphy->regs.core + ACIOPHY_TOP_PHY_STAT, reg,
+					 (reg & ACIOPHY_TOP_PHY_STAT_LN0_UNK0), 10, 10000);
+		if (ret)
+			dev_warn(atcphy->dev,
+				 "timed out waiting for ACIOPHY_TOP_PHY_STAT_LN0_UNK0\n");
+
+		ret = readl_poll_timeout(atcphy->regs.core + ACIOPHY_TOP_PHY_STAT, reg,
+					 !(reg & ACIOPHY_TOP_PHY_STAT_LN0_UNK23), 10, 10000);
+		if (ret)
+			dev_warn(atcphy->dev,
+				 "timed out waiting for ACIOPHY_TOP_PHY_STAT_LN0_UNK23\n");
+
+		/* Clear reset for non-selected USB3 PHY (?) */
+		mask32(atcphy->regs.pipehandler + PIPEHANDLER_NONSELECTED_OVERRIDE,
+		       PIPEHANDLER_NATIVE_POWER_DOWN, FIELD_PREP(PIPEHANDLER_NATIVE_POWER_DOWN, 3));
+		clear32(atcphy->regs.pipehandler + PIPEHANDLER_NONSELECTED_OVERRIDE,
+			PIPEHANDLER_NATIVE_RESET);
+
+		/* More BIST stuff (?) */
+		writel(0, atcphy->regs.core + ACIOPHY_TOP_BIST_OV_CFG);
+		core_set32(atcphy, ACIOPHY_TOP_BIST_CIOPHY_CFG1,
+			   ACIOPHY_TOP_BIST_CIOPHY_CFG1_CLK_EN);
+		core_set32(atcphy, ACIOPHY_TOP_BIST_CIOPHY_CFG1,
+			   ACIOPHY_TOP_BIST_CIOPHY_CFG1_BIST_EN);
+	}
+
+	/* Configure PIPE mux to USB3 PHY */
+	mask32(atcphy->regs.pipehandler + PIPEHANDLER_MUX_CTRL, PIPEHANDLER_MUX_CTRL_CLK,
+	       FIELD_PREP(PIPEHANDLER_MUX_CTRL_CLK, PIPEHANDLER_MUX_CTRL_CLK_OFF));
+	udelay(10);
+	mask32(atcphy->regs.pipehandler + PIPEHANDLER_MUX_CTRL, PIPEHANDLER_MUX_CTRL_DATA,
+	       FIELD_PREP(PIPEHANDLER_MUX_CTRL_DATA, PIPEHANDLER_MUX_CTRL_DATA_USB3));
+	udelay(10);
+	mask32(atcphy->regs.pipehandler + PIPEHANDLER_MUX_CTRL, PIPEHANDLER_MUX_CTRL_CLK,
+	       FIELD_PREP(PIPEHANDLER_MUX_CTRL_CLK, PIPEHANDLER_MUX_CTRL_CLK_USB3));
+	udelay(10);
+
+	/* Remove link detection override */
+	clear32(atcphy->regs.pipehandler + PIPEHANDLER_OVERRIDE, PIPEHANDLER_OVERRIDE_RXVALID);
+	clear32(atcphy->regs.pipehandler + PIPEHANDLER_OVERRIDE, PIPEHANDLER_OVERRIDE_RXDETECT);
+
+	/* Pipehandler was only locked when the BIST sequence was applied for host mode */
+	if (host) {
+		ret = atcphy_pipehandler_unlock(atcphy);
+		if (ret)
+			dev_warn(atcphy->dev, "Failed to unlock pipehandler");
+	}
+
+	return 0;
+}
+
+static int atcphy_configure_pipehandler_dummy(struct apple_atcphy *atcphy)
+{
+	int ret;
+
+	ret = atcphy_pipehandler_check(atcphy);
+	if (ret)
+		return ret;
+
+	/* Force disable link detection */
+	clear32(atcphy->regs.pipehandler + PIPEHANDLER_OVERRIDE_VALUES,
+		PIPEHANDLER_OVERRIDE_VAL_RXDETECT0 | PIPEHANDLER_OVERRIDE_VAL_RXDETECT1);
+	set32(atcphy->regs.pipehandler + PIPEHANDLER_OVERRIDE, PIPEHANDLER_OVERRIDE_RXVALID);
+	set32(atcphy->regs.pipehandler + PIPEHANDLER_OVERRIDE, PIPEHANDLER_OVERRIDE_RXDETECT);
+
+	ret = atcphy_pipehandler_lock(atcphy);
+	if (ret)
+		dev_warn(atcphy->dev, "Failed to lock pipehandler");
+
+	/* Switch to dummy PHY */
+	mask32(atcphy->regs.pipehandler + PIPEHANDLER_MUX_CTRL, PIPEHANDLER_MUX_CTRL_CLK,
+	       FIELD_PREP(PIPEHANDLER_MUX_CTRL_CLK, PIPEHANDLER_MUX_CTRL_CLK_OFF));
+	udelay(10);
+	mask32(atcphy->regs.pipehandler + PIPEHANDLER_MUX_CTRL, PIPEHANDLER_MUX_CTRL_DATA,
+	       FIELD_PREP(PIPEHANDLER_MUX_CTRL_DATA, PIPEHANDLER_MUX_CTRL_DATA_DUMMY));
+	udelay(10);
+	mask32(atcphy->regs.pipehandler + PIPEHANDLER_MUX_CTRL, PIPEHANDLER_MUX_CTRL_CLK,
+	       FIELD_PREP(PIPEHANDLER_MUX_CTRL_CLK, PIPEHANDLER_MUX_CTRL_CLK_DUMMY));
+	udelay(10);
+
+	ret = atcphy_pipehandler_unlock(atcphy);
+	if (ret)
+		dev_warn(atcphy->dev, "Failed to unlock pipehandler");
+
+	mask32(atcphy->regs.pipehandler + PIPEHANDLER_NONSELECTED_OVERRIDE,
+	       PIPEHANDLER_NATIVE_POWER_DOWN, FIELD_PREP(PIPEHANDLER_NATIVE_POWER_DOWN, 2));
+	set32(atcphy->regs.pipehandler + PIPEHANDLER_NONSELECTED_OVERRIDE,
+	      PIPEHANDLER_NATIVE_RESET);
+
+	return 0;
+}
+
+static int atcphy_configure_pipehandler(struct apple_atcphy *atcphy, bool host)
+{
+	int ret;
+
+	lockdep_assert_held(&atcphy->lock);
+
+	switch (atcphy_modes[atcphy->mode].pipehandler_state) {
+	case ATCPHY_PIPEHANDLER_STATE_USB3:
+		ret = atcphy_configure_pipehandler_usb3(atcphy, host);
+		atcphy->pipehandler_up = true;
+		break;
+	case ATCPHY_PIPEHANDLER_STATE_USB4:
+		dev_warn(atcphy->dev,
+			 "ATCPHY_PIPEHANDLER_STATE_USB4 not implemented; falling back to USB2\n");
+		ret = atcphy_configure_pipehandler_dummy(atcphy);
+		atcphy->pipehandler_up = false;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static void atcphy_setup_pipehandler(struct apple_atcphy *atcphy)
+{
+	lockdep_assert_held(&atcphy->lock);
+
+	mask32(atcphy->regs.pipehandler + PIPEHANDLER_MUX_CTRL, PIPEHANDLER_MUX_CTRL_CLK,
+	       FIELD_PREP(PIPEHANDLER_MUX_CTRL_CLK, PIPEHANDLER_MUX_CTRL_CLK_OFF));
+	udelay(10);
+	mask32(atcphy->regs.pipehandler + PIPEHANDLER_MUX_CTRL, PIPEHANDLER_MUX_CTRL_DATA,
+	       FIELD_PREP(PIPEHANDLER_MUX_CTRL_DATA, PIPEHANDLER_MUX_CTRL_DATA_DUMMY));
+	udelay(10);
+	mask32(atcphy->regs.pipehandler + PIPEHANDLER_MUX_CTRL, PIPEHANDLER_MUX_CTRL_CLK,
+	       FIELD_PREP(PIPEHANDLER_MUX_CTRL_CLK, PIPEHANDLER_MUX_CTRL_CLK_DUMMY));
+	udelay(10);
+}
+
+static void atcphy_configure_lanes(struct apple_atcphy *atcphy, enum atcphy_mode mode)
+{
+	const struct atcphy_mode_configuration *mode_cfg = atcphy_get_mode_config(atcphy, mode);
+
+	core_mask32(atcphy, ACIOPHY_LANE_MODE, ACIOPHY_LANE_MODE_RX0,
+		    FIELD_PREP(ACIOPHY_LANE_MODE_RX0, mode_cfg->lane_mode[0]));
+	core_mask32(atcphy, ACIOPHY_LANE_MODE, ACIOPHY_LANE_MODE_TX0,
+		    FIELD_PREP(ACIOPHY_LANE_MODE_TX0, mode_cfg->lane_mode[0]));
+	core_mask32(atcphy, ACIOPHY_LANE_MODE, ACIOPHY_LANE_MODE_RX1,
+		    FIELD_PREP(ACIOPHY_LANE_MODE_RX1, mode_cfg->lane_mode[1]));
+	core_mask32(atcphy, ACIOPHY_LANE_MODE, ACIOPHY_LANE_MODE_TX1,
+		    FIELD_PREP(ACIOPHY_LANE_MODE_TX1, mode_cfg->lane_mode[1]));
+	core_mask32(atcphy, ACIOPHY_CROSSBAR, ACIOPHY_CROSSBAR_PROTOCOL,
+		    FIELD_PREP(ACIOPHY_CROSSBAR_PROTOCOL, mode_cfg->crossbar));
+
+	if (mode_cfg->set_swap)
+		core_set32(atcphy, ATCPHY_MISC, ATCPHY_MISC_LANE_SWAP);
+	else
+		core_clear32(atcphy, ATCPHY_MISC, ATCPHY_MISC_LANE_SWAP);
+
+	core_mask32(atcphy, ACIOPHY_CROSSBAR, ACIOPHY_CROSSBAR_DP_SINGLE_PMA,
+		    FIELD_PREP(ACIOPHY_CROSSBAR_DP_SINGLE_PMA, mode_cfg->crossbar_dp_single_pma));
+	if (mode_cfg->crossbar_dp_both_pma)
+		core_set32(atcphy, ACIOPHY_CROSSBAR, ACIOPHY_CROSSBAR_DP_BOTH_PMA);
+	else
+		core_clear32(atcphy, ACIOPHY_CROSSBAR, ACIOPHY_CROSSBAR_DP_BOTH_PMA);
+
+	if (mode_cfg->dp_lane[0]) {
+		core_set32(atcphy, LN0_AUSPMA_RX_TOP + LN_AUSPMA_RX_TOP_PMAFSM,
+			   LN_AUSPMA_RX_TOP_PMAFSM_PCS_OV);
+		udelay(10);
+		core_clear32(atcphy, LN0_AUSPMA_RX_TOP + LN_AUSPMA_RX_TOP_PMAFSM,
+			     LN_AUSPMA_RX_TOP_PMAFSM_PCS_REQ);
+	} else {
+		core_clear32(atcphy, LN0_AUSPMA_RX_TOP + LN_AUSPMA_RX_TOP_PMAFSM,
+			     LN_AUSPMA_RX_TOP_PMAFSM_PCS_OV);
+		udelay(10);
+	}
+
+	if (mode_cfg->dp_lane[1]) {
+		core_set32(atcphy, LN1_AUSPMA_RX_TOP + LN_AUSPMA_RX_TOP_PMAFSM,
+			   LN_AUSPMA_RX_TOP_PMAFSM_PCS_OV);
+		udelay(10);
+		core_clear32(atcphy, LN1_AUSPMA_RX_TOP + LN_AUSPMA_RX_TOP_PMAFSM,
+			     LN_AUSPMA_RX_TOP_PMAFSM_PCS_REQ);
+	} else {
+		core_clear32(atcphy, LN1_AUSPMA_RX_TOP + LN_AUSPMA_RX_TOP_PMAFSM,
+			     LN_AUSPMA_RX_TOP_PMAFSM_PCS_OV);
+		udelay(10);
+	}
+}
+
+static void atcphy_enable_dp_aux(struct apple_atcphy *atcphy)
+{
+	core_set32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DPTXPHY_PMA_LANE_RESET_N);
+	core_set32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DPTXPHY_PMA_LANE_RESET_N_OV);
+
+	core_mask32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DPRX_PCLK_SELECT,
+		    FIELD_PREP(DPRX_PCLK_SELECT, 1));
+	core_set32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DPRX_PCLK_ENABLE);
+
+	core_mask32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DPTX_PCLK1_SELECT,
+		    FIELD_PREP(DPTX_PCLK1_SELECT, 1));
+	core_set32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DPTX_PCLK1_ENABLE);
+
+	core_mask32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DPTX_PCLK2_SELECT,
+		    FIELD_PREP(DPTX_PCLK2_SELECT, 1));
+	core_set32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DPTX_PCLK2_ENABLE);
+
+	core_set32(atcphy, ACIOPHY_PLL_COMMON_CTRL,
+		   ACIOPHY_PLL_WAIT_FOR_CMN_READY_BEFORE_RESET_EXIT);
+
+	set32(atcphy->regs.lpdptx + LPDPTX_AUX_CONTROL, LPDPTX_AUX_CLAMP_EN);
+	set32(atcphy->regs.lpdptx + LPDPTX_AUX_CONTROL, LPDPTX_SLEEP_B_SML_IN);
+	udelay(10);
+	set32(atcphy->regs.lpdptx + LPDPTX_AUX_CONTROL, LPDPTX_SLEEP_B_BIG_IN);
+	udelay(10);
+	clear32(atcphy->regs.lpdptx + LPDPTX_AUX_CONTROL, LPDPTX_AUX_CLAMP_EN);
+	clear32(atcphy->regs.lpdptx + LPDPTX_AUX_CONTROL, LPDPTX_AUX_PWN_DOWN);
+	clear32(atcphy->regs.lpdptx + LPDPTX_AUX_CONTROL, LPDPTX_TXTERM_CODEMSB);
+	mask32(atcphy->regs.lpdptx + LPDPTX_AUX_CONTROL, LPDPTX_TXTERM_CODE,
+	       FIELD_PREP(LPDPTX_TXTERM_CODE, 0x16));
+
+	set32(atcphy->regs.lpdptx + LPDPTX_AUX_CFG_BLK_AUX_LDO_CTRL, 0x1c00);
+	mask32(atcphy->regs.lpdptx + LPDPTX_AUX_SHM_CFG_BLK_AUX_CTRL_REG1, LPDPTX_CFG_PMA_PHYS_ADJ,
+	       FIELD_PREP(LPDPTX_CFG_PMA_PHYS_ADJ, 5));
+	set32(atcphy->regs.lpdptx + LPDPTX_AUX_SHM_CFG_BLK_AUX_CTRL_REG1,
+	      LPDPTX_CFG_PMA_PHYS_ADJ_OV);
+
+	clear32(atcphy->regs.lpdptx + LPDPTX_AUX_CFG_BLK_AUX_MARGIN,
+		LPDPTX_MARGIN_RCAL_RXOFFSET_EN);
+
+	clear32(atcphy->regs.lpdptx + LPDPTX_AUX_CFG_BLK_AUX_CTRL, LPDPTX_BLK_AUX_CTRL_PWRDN);
+	set32(atcphy->regs.lpdptx + LPDPTX_AUX_SHM_CFG_BLK_AUX_CTRL_REG0,
+	      LPDPTX_CFG_PMA_AUX_SEL_LF_DATA);
+	mask32(atcphy->regs.lpdptx + LPDPTX_AUX_CFG_BLK_AUX_CTRL, LPDPTX_BLK_AUX_RXOFFSET,
+	       FIELD_PREP(LPDPTX_BLK_AUX_RXOFFSET, 3));
+
+	mask32(atcphy->regs.lpdptx + LPDPTX_AUX_CFG_BLK_AUX_MARGIN, LPDPTX_AUX_MARGIN_RCAL_TXSWING,
+	       FIELD_PREP(LPDPTX_AUX_MARGIN_RCAL_TXSWING, 12));
+
+	atcphy->dp_link_rate = -1;
+}
+
+static void atcphy_disable_dp_aux(struct apple_atcphy *atcphy)
+{
+	set32(atcphy->regs.lpdptx + LPDPTX_AUX_CONTROL, LPDPTX_AUX_PWN_DOWN);
+	set32(atcphy->regs.lpdptx + LPDPTX_AUX_CFG_BLK_AUX_CTRL, LPDPTX_BLK_AUX_CTRL_PWRDN);
+	set32(atcphy->regs.lpdptx + LPDPTX_AUX_CONTROL, LPDPTX_AUX_CLAMP_EN);
+	clear32(atcphy->regs.lpdptx + LPDPTX_AUX_CONTROL, LPDPTX_SLEEP_B_SML_IN);
+	udelay(10);
+	clear32(atcphy->regs.lpdptx + LPDPTX_AUX_CONTROL, LPDPTX_SLEEP_B_BIG_IN);
+	udelay(10);
+
+	core_clear32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DPTXPHY_PMA_LANE_RESET_N);
+	core_clear32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DPRX_PCLK_ENABLE);
+	core_clear32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DPTX_PCLK1_ENABLE);
+	core_clear32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DPTX_PCLK2_ENABLE);
+}
+
+static int atcphy_dp_configure_lane(struct apple_atcphy *atcphy, enum atcphy_lane lane,
+				    const struct atcphy_dp_link_rate_configuration *cfg)
+{
+	void __iomem *tx_shm, *rx_shm, *rx_top;
+	unsigned int tx_cal_code;
+
+	lockdep_assert_held(&atcphy->lock);
+
+	switch (lane) {
+	case APPLE_ATCPHY_LANE_0:
+		tx_shm = atcphy->regs.core + LN0_AUSPMA_TX_SHM;
+		rx_shm = atcphy->regs.core + LN0_AUSPMA_RX_SHM;
+		rx_top = atcphy->regs.core + LN0_AUSPMA_RX_TOP;
+		break;
+	case APPLE_ATCPHY_LANE_1:
+		tx_shm = atcphy->regs.core + LN1_AUSPMA_TX_SHM;
+		rx_shm = atcphy->regs.core + LN1_AUSPMA_RX_SHM;
+		rx_top = atcphy->regs.core + LN1_AUSPMA_RX_TOP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_LDOCLK, LN_LDOCLK_EN_SML);
+	set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_LDOCLK, LN_LDOCLK_EN_SML_OV);
+	udelay(10);
+
+	set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_LDOCLK, LN_LDOCLK_EN_BIG);
+	set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_LDOCLK, LN_LDOCLK_EN_BIG_OV);
+	udelay(10);
+
+	if (cfg->txa_ldoclk_bypass) {
+		set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_LDOCLK, LN_LDOCLK_BYPASS_SML);
+		set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_LDOCLK, LN_LDOCLK_BYPASS_SML_OV);
+		udelay(10);
+
+		set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_LDOCLK, LN_LDOCLK_BYPASS_BIG);
+		set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_LDOCLK, LN_LDOCLK_BYPASS_BIG_OV);
+		udelay(10);
+	} else {
+		clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_LDOCLK, LN_LDOCLK_BYPASS_SML);
+		clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_LDOCLK, LN_LDOCLK_BYPASS_SML_OV);
+		udelay(10);
+
+		clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_LDOCLK, LN_LDOCLK_BYPASS_BIG);
+		clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_LDOCLK, LN_LDOCLK_BYPASS_BIG_OV);
+		udelay(10);
+	}
+
+	set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG0, LN_BYTECLK_RESET_SYNC_SEL_OV);
+	set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG0, LN_BYTECLK_RESET_SYNC_EN);
+	set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG0, LN_BYTECLK_RESET_SYNC_EN_OV);
+	clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG0, LN_BYTECLK_RESET_SYNC_CLR);
+	set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG0, LN_BYTECLK_RESET_SYNC_CLR_OV);
+
+	if (cfg->txa_div2_en)
+		set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG1, LN_TXA_DIV2_EN);
+	else
+		clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG1, LN_TXA_DIV2_EN);
+	set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG1, LN_TXA_DIV2_EN_OV);
+	set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG1, LN_TXA_CLK_EN);
+	set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG1, LN_TXA_CLK_EN_OV);
+	clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG1, LN_TXA_DIV2_RESET);
+	set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG1, LN_TXA_DIV2_RESET_OV);
+
+	mask32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG0, LN_TXA_CAL_CTRL_BASE,
+	       FIELD_PREP(LN_TXA_CAL_CTRL_BASE, 0xf));
+	set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG0, LN_TXA_CAL_CTRL_BASE_OV);
+
+	tx_cal_code = FIELD_GET(AUS_UNK_A20_TX_CAL_CODE, readl(atcphy->regs.core + AUS_UNK_A20));
+	mask32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG0, LN_TXA_CAL_CTRL,
+	       FIELD_PREP(LN_TXA_CAL_CTRL, (1 << tx_cal_code) - 1));
+	set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG0, LN_TXA_CAL_CTRL_OV);
+
+	clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG2, LN_TXA_MARGIN);
+	set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG2, LN_TXA_MARGIN_OV);
+	clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG2, LN_TXA_MARGIN_2R);
+	set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG2, LN_TXA_MARGIN_2R_OV);
+
+	clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG3, LN_TXA_MARGIN_POST);
+	set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG3, LN_TXA_MARGIN_POST_OV);
+	clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG3, LN_TXA_MARGIN_POST_2R);
+	set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG3, LN_TXA_MARGIN_POST_2R_OV);
+	clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG3, LN_TXA_MARGIN_POST_4R);
+	set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG3, LN_TXA_MARGIN_POST_4R_OV);
+	clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG3, LN_TXA_MARGIN_PRE);
+	set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG3, LN_TXA_MARGIN_PRE_OV);
+	clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG3, LN_TXA_MARGIN_PRE_2R);
+	set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG3, LN_TXA_MARGIN_PRE_2R_OV);
+	clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG3, LN_TXA_MARGIN_PRE_4R);
+	set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG3, LN_TXA_MARGIN_PRE_4R_OV);
+
+	clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG0, LN_TXA_HIZ);
+	set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG0, LN_TXA_HIZ_OV);
+
+	clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_AFE_CTRL1, LN_RX_DIV20_RESET_N);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_AFE_CTRL1, LN_RX_DIV20_RESET_N_OV);
+	udelay(10);
+
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_AFE_CTRL1, LN_RX_DIV20_RESET_N);
+
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL12, LN_TX_BYTECLK_RESET_SYNC_EN);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL12, LN_TX_BYTECLK_RESET_SYNC_EN_OV);
+
+	mask32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_SAVOS_CTRL16, LN_TX_CAL_CODE,
+	       FIELD_PREP(LN_TX_CAL_CODE, tx_cal_code));
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_SAVOS_CTRL16, LN_TX_CAL_CODE_OV);
+
+	mask32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TERM_CTRL19, LN_TX_CLK_DLY_CTRL_TAPGEN,
+	       FIELD_PREP(LN_TX_CLK_DLY_CTRL_TAPGEN, 3));
+
+	clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL10, LN_DTVREG_ADJUST);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL13, LN_DTVREG_ADJUST_OV);
+
+	clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_SAVOS_CTRL16, LN_RXTERM_EN);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_SAVOS_CTRL16, LN_RXTERM_EN_OV);
+
+	clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TERM_CTRL19, LN_TX_TEST_EN);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TERM_CTRL19, LN_TX_TEST_EN_OV);
+
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22, LN_VREF_TEST_RXLPBKDT_EN);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22, LN_VREF_TEST_RXLPBKDT_EN_OV);
+	mask32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22, LN_VREF_LPBKIN_DATA,
+	       FIELD_PREP(LN_VREF_LPBKIN_DATA, 3));
+	mask32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22, LN_VREF_BIAS_SEL,
+	       FIELD_PREP(LN_VREF_BIAS_SEL, 2));
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22, LN_VREF_BIAS_SEL_OV);
+	mask32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22, LN_VREF_ADJUST_GRAY,
+	       FIELD_PREP(LN_VREF_ADJUST_GRAY, 0x18));
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22, LN_VREF_ADJUST_GRAY_OV);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22, LN_VREF_EN);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22, LN_VREF_EN_OV);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22, LN_VREF_BOOST_EN);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22, LN_VREF_BOOST_EN_OV);
+	udelay(10);
+
+	clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22, LN_VREF_BOOST_EN);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22, LN_VREF_BOOST_EN_OV);
+	udelay(10);
+
+	clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL13, LN_TX_PRE_EN);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL13, LN_TX_PRE_EN_OV);
+	clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL13, LN_TX_PST1_EN);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL13, LN_TX_PST1_EN_OV);
+
+	clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL12, LN_TX_PBIAS_EN);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL12, LN_TX_PBIAS_EN_OV);
+
+	clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_SAVOS_CTRL16, LN_RXTERM_PULLUP_LEAK_EN);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_SAVOS_CTRL16, LN_RXTERM_PULLUP_LEAK_EN_OV);
+
+	set32(rx_top + LN_AUSPMA_RX_TOP_TJ_CFG_RX_TXMODE, LN_RX_TXMODE);
+
+	if (cfg->txa_div2_en)
+		set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TERM_CTRL19, LN_TX_CLK_DIV2_EN);
+	else
+		clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TERM_CTRL19, LN_TX_CLK_DIV2_EN);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TERM_CTRL19, LN_TX_CLK_DIV2_EN_OV);
+
+	clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TERM_CTRL19, LN_TX_CLK_DIV2_RST);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TERM_CTRL19, LN_TX_CLK_DIV2_RST_OV);
+
+	clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL12, LN_TX_HRCLK_SEL);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL12, LN_TX_HRCLK_SEL_OV);
+
+	clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL17, LN_TX_MARGIN);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL17, LN_TX_MARGIN_OV);
+	clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL17, LN_TX_MARGIN_LSB);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL17, LN_TX_MARGIN_LSB_OV);
+	clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL17, LN_TX_MARGIN_P1);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL17, LN_TX_MARGIN_P1_OV);
+	clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL17, LN_TX_MARGIN_P1_LSB);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL17, LN_TX_MARGIN_P1_LSB_OV);
+
+	clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL18, LN_TX_P1_CODE);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL18, LN_TX_P1_CODE_OV);
+	clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL18, LN_TX_P1_LSB_CODE);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL18, LN_TX_P1_LSB_CODE_OV);
+	clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL18, LN_TX_MARGIN_PRE);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL18, LN_TX_MARGIN_PRE_OV);
+	clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL18, LN_TX_MARGIN_PRE_LSB);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL18, LN_TX_MARGIN_PRE_LSB_OV);
+	clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL18, LN_TX_PRE_LSB_CODE);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL18, LN_TX_PRE_LSB_CODE_OV);
+	clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL18, LN_TX_PRE_CODE);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL18, LN_TX_PRE_CODE_OV);
+
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL11, LN_DTVREG_SML_EN);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL11, LN_DTVREG_SML_EN_OV);
+	udelay(10);
+
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL11, LN_DTVREG_BIG_EN);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL11, LN_DTVREG_BIG_EN_OV);
+	udelay(10);
+
+	mask32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL10, LN_DTVREG_ADJUST,
+	       FIELD_PREP(LN_DTVREG_ADJUST, 0xa));
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL13, LN_DTVREG_ADJUST_OV);
+	udelay(10);
+
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TERM_CTRL19, LN_TX_EN);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TERM_CTRL19, LN_TX_EN_OV);
+	udelay(10);
+
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_CTLE_CTRL0, LN_TX_CLK_EN);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_CTLE_CTRL0, LN_TX_CLK_EN_OV);
+
+	clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL12, LN_TX_BYTECLK_RESET_SYNC_CLR);
+	set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL12, LN_TX_BYTECLK_RESET_SYNC_CLR_OV);
+
+	return 0;
+}
+
+static int atcphy_auspll_apb_command(struct apple_atcphy *atcphy, u32 command)
+{
+	int ret;
+	u32 reg;
+
+	reg = readl(atcphy->regs.core + AUSPLL_APB_CMD_OVERRIDE);
+	reg &= ~AUSPLL_APB_CMD_OVERRIDE_CMD;
+	reg |= FIELD_PREP(AUSPLL_APB_CMD_OVERRIDE_CMD, command);
+	reg |= AUSPLL_APB_CMD_OVERRIDE_REQ;
+	reg |= AUSPLL_APB_CMD_OVERRIDE_UNK28;
+	writel(reg, atcphy->regs.core + AUSPLL_APB_CMD_OVERRIDE);
+
+	ret = readl_poll_timeout(atcphy->regs.core + AUSPLL_APB_CMD_OVERRIDE, reg,
+				 (reg & AUSPLL_APB_CMD_OVERRIDE_ACK), 10, 10000);
+	if (ret)
+		dev_warn(atcphy->dev, "AUSPLL APB command was not acked\n");
+
+	core_clear32(atcphy, AUSPLL_APB_CMD_OVERRIDE, AUSPLL_APB_CMD_OVERRIDE_REQ);
+
+	return 0;
+}
+
+static int atcphy_dp_configure(struct apple_atcphy *atcphy, enum atcphy_dp_link_rate lr)
+{
+	const struct atcphy_dp_link_rate_configuration *cfg;
+	const struct atcphy_mode_configuration *mode_cfg;
+	int ret;
+	u32 reg;
+
+	guard(mutex)(&atcphy->lock);
+	mode_cfg = atcphy_get_mode_config(atcphy, atcphy->mode);
+	cfg = &dp_lr_config[lr];
+
+	if (atcphy->dp_link_rate == lr)
+		return 0;
+
+	ret = readl_poll_timeout(atcphy->regs.core + ACIOPHY_CMN_SHM_STS_REG0, reg,
+				 (reg & ACIOPHY_CMN_SHM_STS_REG0_CMD_READY), 10, 10000);
+	if (ret) {
+		dev_err(atcphy->dev, "ACIOPHY_CMN_SHM_STS_REG0_CMD_READY not set.\n");
+		return ret;
+	}
+
+	core_clear32(atcphy, AUSPLL_FREQ_CFG, AUSPLL_FREQ_REFCLK);
+
+	core_mask32(atcphy, AUSPLL_FREQ_DESC_A, AUSPLL_FD_FREQ_COUNT_TARGET,
+		    FIELD_PREP(AUSPLL_FD_FREQ_COUNT_TARGET, cfg->freqinit_count_target));
+	core_clear32(atcphy, AUSPLL_FREQ_DESC_A, AUSPLL_FD_FBDIVN_HALF);
+	core_clear32(atcphy, AUSPLL_FREQ_DESC_A, AUSPLL_FD_REV_DIVN);
+	core_mask32(atcphy, AUSPLL_FREQ_DESC_A, AUSPLL_FD_KI_MAN, FIELD_PREP(AUSPLL_FD_KI_MAN, 8));
+	core_mask32(atcphy, AUSPLL_FREQ_DESC_A, AUSPLL_FD_KI_EXP, FIELD_PREP(AUSPLL_FD_KI_EXP, 3));
+	core_mask32(atcphy, AUSPLL_FREQ_DESC_A, AUSPLL_FD_KP_MAN, FIELD_PREP(AUSPLL_FD_KP_MAN, 8));
+	core_mask32(atcphy, AUSPLL_FREQ_DESC_A, AUSPLL_FD_KP_EXP, FIELD_PREP(AUSPLL_FD_KP_EXP, 7));
+	core_clear32(atcphy, AUSPLL_FREQ_DESC_A, AUSPLL_FD_KPKI_SCALE_HBW);
+
+	core_mask32(atcphy, AUSPLL_FREQ_DESC_B, AUSPLL_FD_FBDIVN_FRAC_DEN,
+		    FIELD_PREP(AUSPLL_FD_FBDIVN_FRAC_DEN, cfg->fbdivn_frac_den));
+	core_mask32(atcphy, AUSPLL_FREQ_DESC_B, AUSPLL_FD_FBDIVN_FRAC_NUM,
+		    FIELD_PREP(AUSPLL_FD_FBDIVN_FRAC_NUM, cfg->fbdivn_frac_num));
+
+	core_clear32(atcphy, AUSPLL_FREQ_DESC_C, AUSPLL_FD_SDM_SSC_STEP);
+	core_clear32(atcphy, AUSPLL_FREQ_DESC_C, AUSPLL_FD_SDM_SSC_EN);
+	core_mask32(atcphy, AUSPLL_FREQ_DESC_C, AUSPLL_FD_PCLK_DIV_SEL,
+		    FIELD_PREP(AUSPLL_FD_PCLK_DIV_SEL, cfg->pclk_div_sel));
+	core_mask32(atcphy, AUSPLL_FREQ_DESC_C, AUSPLL_FD_LFSDM_DIV,
+		    FIELD_PREP(AUSPLL_FD_LFSDM_DIV, 1));
+	core_mask32(atcphy, AUSPLL_FREQ_DESC_C, AUSPLL_FD_LFCLK_CTRL,
+		    FIELD_PREP(AUSPLL_FD_LFCLK_CTRL, cfg->lfclk_ctrl));
+	core_mask32(atcphy, AUSPLL_FREQ_DESC_C, AUSPLL_FD_VCLK_OP_DIVN,
+		    FIELD_PREP(AUSPLL_FD_VCLK_OP_DIVN, cfg->vclk_op_divn));
+	core_set32(atcphy, AUSPLL_FREQ_DESC_C, AUSPLL_FD_VCLK_PRE_DIVN);
+
+	core_mask32(atcphy, AUSPLL_CLKOUT_DIV, AUSPLL_CLKOUT_PLLA_REFBUFCLK_DI,
+		    FIELD_PREP(AUSPLL_CLKOUT_PLLA_REFBUFCLK_DI, 7));
+
+	if (cfg->plla_clkout_vreg_bypass)
+		core_set32(atcphy, AUSPLL_CLKOUT_DTC_VREG, AUSPLL_DTC_VREG_BYPASS);
+	else
+		core_clear32(atcphy, AUSPLL_CLKOUT_DTC_VREG, AUSPLL_DTC_VREG_BYPASS);
+
+	core_set32(atcphy, AUSPLL_BGR, AUSPLL_BGR_CTRL_AVAIL);
+
+	core_set32(atcphy, AUSPLL_CLKOUT_MASTER, AUSPLL_CLKOUT_MASTER_PCLK_DRVR_EN);
+	core_set32(atcphy, AUSPLL_CLKOUT_MASTER, AUSPLL_CLKOUT_MASTER_PCLK2_DRVR_EN);
+	core_set32(atcphy, AUSPLL_CLKOUT_MASTER, AUSPLL_CLKOUT_MASTER_REFBUFCLK_DRVR_EN);
+
+	ret = atcphy_auspll_apb_command(atcphy, 0);
+	if (ret)
+		return ret;
+
+	ret = readl_poll_timeout(atcphy->regs.core + ACIOPHY_DP_PCLK_STAT, reg,
+				 (reg & ACIOPHY_AUSPLL_LOCK), 10, 10000);
+	if (ret) {
+		dev_err(atcphy->dev, "ACIOPHY_DP_PCLK did not lock.\n");
+		return ret;
+	}
+
+	ret = atcphy_auspll_apb_command(atcphy, 0x2800);
+	if (ret)
+		return ret;
+
+	if (mode_cfg->dp_lane[0]) {
+		ret = atcphy_dp_configure_lane(atcphy, APPLE_ATCPHY_LANE_0, cfg);
+		if (ret)
+			return ret;
+	}
+
+	if (mode_cfg->dp_lane[1]) {
+		ret = atcphy_dp_configure_lane(atcphy, APPLE_ATCPHY_LANE_1, cfg);
+		if (ret)
+			return ret;
+	}
+
+	core_clear32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DP_PMA_BYTECLK_RESET);
+	core_clear32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DP_MAC_DIV20_CLK_SEL);
+
+	atcphy->dp_link_rate = lr;
+	return 0;
+}
+
+static void atcphy_usb2_power_off(struct apple_atcphy *atcphy)
+{
+	/* Disable the PHY, this clears USB2PHY_USBCTL_RUN */
+	writel(USB2PHY_USBCTL_ISOLATION, atcphy->regs.usb2phy + USB2PHY_USBCTL);
+	udelay(10);
+
+	/* Switch the PHY to low power mode */
+	set32(atcphy->regs.usb2phy + USB2PHY_CTL, USB2PHY_CTL_SIDDQ);
+	udelay(10);
+
+	/* Enable all resets */
+	set32(atcphy->regs.usb2phy + USB2PHY_CTL, USB2PHY_CTL_PORT_RESET);
+	udelay(10);
+	set32(atcphy->regs.usb2phy + USB2PHY_CTL, USB2PHY_CTL_RESET);
+	udelay(10);
+	clear32(atcphy->regs.usb2phy + USB2PHY_CTL, USB2PHY_CTL_APB_RESET_N);
+	udelay(10);
+	set32(atcphy->regs.usb2phy + USB2PHY_MISCTUNE, USB2PHY_MISCTUNE_APBCLK_GATE_OFF);
+	set32(atcphy->regs.usb2phy + USB2PHY_MISCTUNE, USB2PHY_MISCTUNE_REFCLK_GATE_OFF);
+}
+
+static int atcphy_power_off(struct apple_atcphy *atcphy)
+{
+	u32 reg;
+	int ret;
+
+	atcphy_disable_dp_aux(atcphy);
+
+	/* Enable all reset lines */
+	core_clear32(atcphy, ATCPHY_POWER_CTRL, ATCPHY_POWER_PHY_RESET_N);
+	core_set32(atcphy, ATCPHY_POWER_CTRL, ATCPHY_POWER_CLAMP_EN);
+	core_clear32(atcphy, ATCPHY_MISC, ATCPHY_MISC_RESET_N | ATCPHY_MISC_LANE_SWAP);
+	core_clear32(atcphy, ATCPHY_POWER_CTRL, ATCPHY_POWER_APB_RESET_N);
+
+	core_clear32(atcphy, ATCPHY_POWER_CTRL, ATCPHY_POWER_SLEEP_BIG);
+	ret = readl_poll_timeout(atcphy->regs.core + ATCPHY_POWER_STAT, reg,
+				 !(reg & ATCPHY_POWER_SLEEP_BIG), 10, 1000);
+	if (ret) {
+		dev_err(atcphy->dev, "Failed to sleep atcphy \"big\"\n");
+		return ret;
+	}
+
+	core_clear32(atcphy, ATCPHY_POWER_CTRL, ATCPHY_POWER_SLEEP_SMALL);
+	ret = readl_poll_timeout(atcphy->regs.core + ATCPHY_POWER_STAT, reg,
+				 !(reg & ATCPHY_POWER_SLEEP_SMALL), 10, 1000);
+	if (ret) {
+		dev_err(atcphy->dev, "Failed to sleep atcphy \"small\"\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static void atcphy_usb2_power_on(struct apple_atcphy *atcphy)
+{
+	set32(atcphy->regs.usb2phy + USB2PHY_SIG,
+	      USB2PHY_SIG_VBUSDET_FORCE_VAL | USB2PHY_SIG_VBUSDET_FORCE_EN |
+		      USB2PHY_SIG_VBUSVLDEXT_FORCE_VAL | USB2PHY_SIG_VBUSVLDEXT_FORCE_EN);
+	udelay(10);
+
+	/* Take the PHY out of its low power state */
+	clear32(atcphy->regs.usb2phy + USB2PHY_CTL, USB2PHY_CTL_SIDDQ);
+	udelay(10);
+
+	/* Release reset */
+	clear32(atcphy->regs.usb2phy + USB2PHY_CTL, USB2PHY_CTL_RESET);
+	udelay(10);
+	clear32(atcphy->regs.usb2phy + USB2PHY_CTL, USB2PHY_CTL_PORT_RESET);
+	udelay(10);
+	set32(atcphy->regs.usb2phy + USB2PHY_CTL, USB2PHY_CTL_APB_RESET_N);
+	udelay(10);
+	clear32(atcphy->regs.usb2phy + USB2PHY_MISCTUNE, USB2PHY_MISCTUNE_APBCLK_GATE_OFF);
+	clear32(atcphy->regs.usb2phy + USB2PHY_MISCTUNE, USB2PHY_MISCTUNE_REFCLK_GATE_OFF);
+
+	/* Enable the PHY */
+	writel(USB2PHY_USBCTL_RUN, atcphy->regs.usb2phy + USB2PHY_USBCTL);
+}
+
+static int atcphy_power_on(struct apple_atcphy *atcphy)
+{
+	u32 reg;
+	int ret;
+
+	atcphy_usb2_power_on(atcphy);
+
+	core_set32(atcphy, ATCPHY_MISC, ATCPHY_MISC_RESET_N);
+
+	core_set32(atcphy, ATCPHY_POWER_CTRL, ATCPHY_POWER_SLEEP_SMALL);
+	ret = readl_poll_timeout(atcphy->regs.core + ATCPHY_POWER_STAT, reg,
+				 reg & ATCPHY_POWER_SLEEP_SMALL, 100, 100000);
+	if (ret) {
+		dev_err(atcphy->dev, "failed to wakeup atcphy \"small\"\n");
+		return ret;
+	}
+
+	core_set32(atcphy, ATCPHY_POWER_CTRL, ATCPHY_POWER_SLEEP_BIG);
+	ret = readl_poll_timeout(atcphy->regs.core + ATCPHY_POWER_STAT, reg,
+				 reg & ATCPHY_POWER_SLEEP_BIG, 100, 100000);
+	if (ret) {
+		dev_err(atcphy->dev, "failed to wakeup atcphy \"big\"\n");
+		return ret;
+	}
+
+	core_clear32(atcphy, ATCPHY_POWER_CTRL, ATCPHY_POWER_CLAMP_EN);
+	core_set32(atcphy, ATCPHY_POWER_CTRL, ATCPHY_POWER_APB_RESET_N);
+
+	return 0;
+}
+
+static int atcphy_configure(struct apple_atcphy *atcphy, enum atcphy_mode mode)
+{
+	int ret = 0;
+
+	lockdep_assert_held(&atcphy->lock);
+
+	if (mode == APPLE_ATCPHY_MODE_OFF) {
+		ret = atcphy_power_off(atcphy);
+		atcphy->mode = mode;
+		return ret;
+	}
+
+	ret = atcphy_power_on(atcphy);
+	if (ret)
+		return ret;
+
+	atcphy_apply_tunables(atcphy, mode);
+
+	core_set32(atcphy, AUSPLL_FSM_CTRL, 0x1fe000);
+	core_set32(atcphy, AUSPLL_APB_CMD_OVERRIDE, AUSPLL_APB_CMD_OVERRIDE_UNK28);
+
+	set32(atcphy->regs.core + ACIOPHY_CFG0, ACIOPHY_CFG0_COMMON_SMALL_OV);
+	udelay(10);
+	set32(atcphy->regs.core + ACIOPHY_CFG0, ACIOPHY_CFG0_COMMON_BIG_OV);
+	udelay(10);
+	set32(atcphy->regs.core + ACIOPHY_CFG0, ACIOPHY_CFG0_COMMON_CLAMP_OV);
+	udelay(10);
+
+	mask32(atcphy->regs.core + ACIOPHY_SLEEP_CTRL, ACIOPHY_SLEEP_CTRL_TX_SMALL_OV,
+	       FIELD_PREP(ACIOPHY_SLEEP_CTRL_TX_SMALL_OV, 3));
+	udelay(10);
+	mask32(atcphy->regs.core + ACIOPHY_SLEEP_CTRL, ACIOPHY_SLEEP_CTRL_TX_BIG_OV,
+	       FIELD_PREP(ACIOPHY_SLEEP_CTRL_TX_BIG_OV, 3));
+	udelay(10);
+	mask32(atcphy->regs.core + ACIOPHY_SLEEP_CTRL, ACIOPHY_SLEEP_CTRL_TX_CLAMP_OV,
+	       FIELD_PREP(ACIOPHY_SLEEP_CTRL_TX_CLAMP_OV, 3));
+	udelay(10);
+
+	mask32(atcphy->regs.core + ACIOPHY_CFG0, ACIOPHY_CFG0_RX_BIG_OV,
+	       FIELD_PREP(ACIOPHY_CFG0_RX_BIG_OV, 3));
+	udelay(10);
+	mask32(atcphy->regs.core + ACIOPHY_CFG0, ACIOPHY_CFG0_RX_SMALL_OV,
+	       FIELD_PREP(ACIOPHY_CFG0_RX_SMALL_OV, 3));
+	udelay(10);
+	mask32(atcphy->regs.core + ACIOPHY_CFG0, ACIOPHY_CFG0_RX_CLAMP_OV,
+	       FIELD_PREP(ACIOPHY_CFG0_RX_CLAMP_OV, 3));
+	udelay(10);
+
+	/* Setup AUX channel if DP altmode is requested */
+	if (atcphy_modes[mode].enable_dp_aux)
+		atcphy_enable_dp_aux(atcphy);
+
+	/* Enable clocks and configure lanes */
+	core_set32(atcphy, CIO3PLL_CLK_CTRL, CIO3PLL_CLK_PCLK_EN);
+	core_set32(atcphy, CIO3PLL_CLK_CTRL, CIO3PLL_CLK_REFCLK_EN);
+	atcphy_configure_lanes(atcphy, mode);
+
+	/* Take the USB3 PHY out of reset */
+	core_set32(atcphy, ATCPHY_POWER_CTRL, ATCPHY_POWER_PHY_RESET_N);
+
+	atcphy->mode = mode;
+
+	return 0;
+}
+
+static int atcphy_usb2_set_mode(struct phy *phy, enum phy_mode mode, int submode)
+{
+	struct apple_atcphy *atcphy = phy_get_drvdata(phy);
+
+	guard(mutex)(&atcphy->lock);
+
+	switch (mode) {
+	case PHY_MODE_USB_HOST:
+		set32(atcphy->regs.usb2phy + USB2PHY_SIG, USB2PHY_SIG_HOST);
+		break;
+	case PHY_MODE_USB_DEVICE:
+		clear32(atcphy->regs.usb2phy + USB2PHY_SIG, USB2PHY_SIG_HOST);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct phy_ops apple_atc_usb2_phy_ops = {
+	.owner = THIS_MODULE,
+	.set_mode = atcphy_usb2_set_mode,
+};
+
+static int atcphy_usb3_power_off(struct phy *phy)
+{
+	struct apple_atcphy *atcphy = phy_get_drvdata(phy);
+	int ret;
+
+	guard(mutex)(&atcphy->lock);
+
+	ret = atcphy_configure_pipehandler_dummy(atcphy);
+	if (ret)
+		dev_warn(atcphy->dev, "Failed to switch pipe to dummy: %d", ret);
+
+	atcphy->pipehandler_up = false;
+
+	if (atcphy->mode != APPLE_ATCPHY_MODE_OFF)
+		atcphy_configure(atcphy, APPLE_ATCPHY_MODE_OFF);
+
+	return 0;
+}
+
+static int atcphy_usb3_set_mode(struct phy *phy, enum phy_mode mode, int submode)
+{
+	struct apple_atcphy *atcphy = phy_get_drvdata(phy);
+
+	guard(mutex)(&atcphy->lock);
+
+	/*
+	 * We may get multiple calls to set_mode (for host mode e.g. at least one from the dwc3 glue
+	 * driver and then another one from the generic xhci code) but must only configure the
+	 * PIPE handler once.
+	 */
+	if (atcphy->pipehandler_up)
+		return 0;
+
+	switch (mode) {
+	case PHY_MODE_USB_HOST:
+		return atcphy_configure_pipehandler(atcphy, true);
+	case PHY_MODE_USB_DEVICE:
+		return atcphy_configure_pipehandler(atcphy, false);
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct phy_ops apple_atc_usb3_phy_ops = {
+	.owner = THIS_MODULE,
+	.power_off = atcphy_usb3_power_off,
+	.set_mode = atcphy_usb3_set_mode,
+};
+
+static int atcphy_dpphy_set_mode(struct phy *phy, enum phy_mode mode, int submode)
+{
+	/* Nothing to do here since the setup already happened in mux_set */
+	if (mode == PHY_MODE_DP && submode == 0)
+		return 0;
+	return -EINVAL;
+}
+
+static int atcphy_dpphy_validate(struct phy *phy, enum phy_mode mode, int submode,
+				 union phy_configure_opts *opts_)
+{
+	struct phy_configure_opts_dp *opts = &opts_->dp;
+	struct apple_atcphy *atcphy = phy_get_drvdata(phy);
+
+	if (mode != PHY_MODE_DP)
+		return -EINVAL;
+	if (submode != 0)
+		return -EINVAL;
+
+	switch (atcphy->mode) {
+	case APPLE_ATCPHY_MODE_USB3_DP:
+		opts->lanes = 2;
+		break;
+	case APPLE_ATCPHY_MODE_DP:
+		opts->lanes = 4;
+		break;
+	default:
+		opts->lanes = 0;
+	}
+
+	return 0;
+}
+
+static int atcphy_dpphy_configure(struct phy *phy, union phy_configure_opts *opts_)
+{
+	struct phy_configure_opts_dp *opts = &opts_->dp;
+	struct apple_atcphy *atcphy = phy_get_drvdata(phy);
+	enum atcphy_dp_link_rate link_rate;
+
+	if (opts->set_voltages)
+		return -EINVAL;
+	if (opts->set_lanes)
+		return -EINVAL;
+
+	if (opts->set_rate) {
+		switch (opts->link_rate) {
+		case 1620:
+			link_rate = ATCPHY_DP_LINK_RATE_RBR;
+			break;
+		case 2700:
+			link_rate = ATCPHY_DP_LINK_RATE_HBR;
+			break;
+		case 5400:
+			link_rate = ATCPHY_DP_LINK_RATE_HBR2;
+			break;
+		case 8100:
+			link_rate = ATCPHY_DP_LINK_RATE_HBR3;
+			break;
+		case 0:
+			return 0;
+		default:
+			dev_err(atcphy->dev, "Unsupported link rate: %d\n", opts->link_rate);
+			return -EINVAL;
+		}
+
+		return atcphy_dp_configure(atcphy, link_rate);
+	}
+
+	return 0;
+}
+
+static const struct phy_ops apple_atc_dp_phy_ops = {
+	.owner = THIS_MODULE,
+	.configure = atcphy_dpphy_configure,
+	.validate = atcphy_dpphy_validate,
+	.set_mode = atcphy_dpphy_set_mode,
+};
+
+static struct phy *atcphy_xlate(struct device *dev, const struct of_phandle_args *args)
+{
+	struct apple_atcphy *atcphy = dev_get_drvdata(dev);
+
+	switch (args->args[0]) {
+	case PHY_TYPE_USB2:
+		return atcphy->phys.usb2;
+	case PHY_TYPE_USB3:
+		return atcphy->phys.usb3;
+	case PHY_TYPE_DP:
+		return atcphy->phys.dp;
+	}
+	return ERR_PTR(-ENODEV);
+}
+
+static int atcphy_probe_phy(struct apple_atcphy *atcphy)
+{
+	struct {
+		struct phy **phy;
+		const struct phy_ops *ops;
+	} phys[] = {
+		{ &atcphy->phys.usb2, &apple_atc_usb2_phy_ops },
+		{ &atcphy->phys.usb3, &apple_atc_usb3_phy_ops },
+		{ &atcphy->phys.dp, &apple_atc_dp_phy_ops },
+	};
+
+	for (int i = 0; i < ARRAY_SIZE(phys); i++) {
+		*phys[i].phy = devm_phy_create(atcphy->dev, NULL, phys[i].ops);
+		if (IS_ERR(*phys[i].phy))
+			return PTR_ERR(*phys[i].phy);
+		phy_set_drvdata(*phys[i].phy, atcphy);
+	}
+
+	atcphy->phy_provider = devm_of_phy_provider_register(atcphy->dev, atcphy_xlate);
+	if (IS_ERR(atcphy->phy_provider))
+		return PTR_ERR(atcphy->phy_provider);
+	return 0;
+}
+
+static void _atcphy_dwc3_reset_assert(struct apple_atcphy *atcphy)
+{
+	lockdep_assert_held(&atcphy->lock);
+
+	clear32(atcphy->regs.pipehandler + PIPEHANDLER_AON_GEN, PIPEHANDLER_AON_GEN_DWC3_RESET_N);
+	set32(atcphy->regs.pipehandler + PIPEHANDLER_AON_GEN,
+	      PIPEHANDLER_AON_GEN_DWC3_FORCE_CLAMP_EN);
+}
+
+static int atcphy_dwc3_reset_assert(struct reset_controller_dev *rcdev, unsigned long id)
+{
+	struct apple_atcphy *atcphy = container_of(rcdev, struct apple_atcphy, rcdev);
+	int ret;
+
+	guard(mutex)(&atcphy->lock);
+
+	_atcphy_dwc3_reset_assert(atcphy);
+
+	if (atcphy->pipehandler_up) {
+		ret = atcphy_configure_pipehandler_dummy(atcphy);
+		if (ret)
+			dev_warn(atcphy->dev, "Failed to switch PIPE to dummy: %d\n", ret);
+		else
+			atcphy->pipehandler_up = false;
+	}
+
+	atcphy_usb2_power_off(atcphy);
+
+	return 0;
+}
+
+static int atcphy_dwc3_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id)
+{
+	struct apple_atcphy *atcphy = container_of(rcdev, struct apple_atcphy, rcdev);
+
+	guard(mutex)(&atcphy->lock);
+
+	clear32(atcphy->regs.pipehandler + PIPEHANDLER_AON_GEN,
+		PIPEHANDLER_AON_GEN_DWC3_FORCE_CLAMP_EN);
+	set32(atcphy->regs.pipehandler + PIPEHANDLER_AON_GEN, PIPEHANDLER_AON_GEN_DWC3_RESET_N);
+
+	return 0;
+}
+
+const struct reset_control_ops atcphy_dwc3_reset_ops = {
+	.assert = atcphy_dwc3_reset_assert,
+	.deassert = atcphy_dwc3_reset_deassert,
+};
+
+static int atcphy_reset_xlate(struct reset_controller_dev *rcdev,
+			      const struct of_phandle_args *reset_spec)
+{
+	return 0;
+}
+
+static int atcphy_probe_rcdev(struct apple_atcphy *atcphy)
+{
+	atcphy->rcdev.owner = THIS_MODULE;
+	atcphy->rcdev.nr_resets = 1;
+	atcphy->rcdev.ops = &atcphy_dwc3_reset_ops;
+	atcphy->rcdev.of_node = atcphy->dev->of_node;
+	atcphy->rcdev.of_reset_n_cells = 0;
+	atcphy->rcdev.of_xlate = atcphy_reset_xlate;
+
+	return devm_reset_controller_register(atcphy->dev, &atcphy->rcdev);
+}
+
+static int atcphy_sw_set(struct typec_switch_dev *sw, enum typec_orientation orientation)
+{
+	struct apple_atcphy *atcphy = typec_switch_get_drvdata(sw);
+
+	guard(mutex)(&atcphy->lock);
+
+	switch (orientation) {
+	case TYPEC_ORIENTATION_NONE:
+		break;
+	case TYPEC_ORIENTATION_NORMAL:
+		atcphy->swap_lanes = false;
+		break;
+	case TYPEC_ORIENTATION_REVERSE:
+		atcphy->swap_lanes = true;
+		break;
+	}
+
+	return 0;
+}
+
+static int atcphy_probe_switch(struct apple_atcphy *atcphy)
+{
+	struct typec_switch_desc sw_desc = {
+		.drvdata = atcphy,
+		.fwnode = atcphy->dev->fwnode,
+		.set = atcphy_sw_set,
+	};
+
+	return PTR_ERR_OR_ZERO(typec_switch_register(atcphy->dev, &sw_desc));
+}
+
+static int atcphy_mux_set(struct typec_mux_dev *mux, struct typec_mux_state *state)
+{
+	struct apple_atcphy *atcphy = typec_mux_get_drvdata(mux);
+	enum atcphy_mode target_mode;
+
+	guard(mutex)(&atcphy->lock);
+
+	if (state->mode == TYPEC_STATE_SAFE) {
+		target_mode = APPLE_ATCPHY_MODE_OFF;
+	} else if (state->mode == TYPEC_STATE_USB) {
+		target_mode = APPLE_ATCPHY_MODE_USB3;
+	} else if (!state->alt && state->mode == TYPEC_MODE_USB4) {
+		struct enter_usb_data *data = state->data;
+		u32 eudo_usb_mode = FIELD_GET(EUDO_USB_MODE_MASK, data->eudo);
+
+		switch (eudo_usb_mode) {
+		case EUDO_USB_MODE_USB2:
+			target_mode = APPLE_ATCPHY_MODE_USB2;
+			break;
+		case EUDO_USB_MODE_USB3:
+			target_mode = APPLE_ATCPHY_MODE_USB3;
+			break;
+		case EUDO_USB_MODE_USB4:
+			target_mode = APPLE_ATCPHY_MODE_USB4;
+			break;
+		default:
+			dev_warn(atcphy->dev, "Unsupported EUDO USB mode: 0x%x.\n", eudo_usb_mode);
+			target_mode = APPLE_ATCPHY_MODE_OFF;
+		}
+	} else if (state->alt && state->alt->svid == USB_TYPEC_TBT_SID) {
+		target_mode = APPLE_ATCPHY_MODE_TBT;
+	} else if (state->alt && state->alt->svid == USB_TYPEC_DP_SID) {
+		switch (state->mode) {
+		case TYPEC_DP_STATE_C:
+		case TYPEC_DP_STATE_E:
+			target_mode = APPLE_ATCPHY_MODE_DP;
+			break;
+		case TYPEC_DP_STATE_D:
+			target_mode = APPLE_ATCPHY_MODE_USB3_DP;
+			break;
+		default:
+			dev_err(atcphy->dev,
+				"Unsupported DP pin assignment: 0x%lx, your connected device will not work.\n",
+				state->mode);
+			target_mode = APPLE_ATCPHY_MODE_OFF;
+		}
+	} else if (state->alt) {
+		dev_err(atcphy->dev,
+			"Unknown alternate mode SVID: 0x%x, your connected device will not work.\n",
+			state->alt->svid);
+		target_mode = APPLE_ATCPHY_MODE_OFF;
+	} else {
+		dev_err(atcphy->dev, "Unknown mode: 0x%lx, your connected device will not work.\n",
+			state->mode);
+		target_mode = APPLE_ATCPHY_MODE_OFF;
+	}
+
+	if (atcphy->mode == target_mode)
+		return 0;
+
+	/*
+	 * If the pipehandler is still/already up here there's a bug somewhere so make sure to
+	 * complain loudly. We can still try to switch modes and hope for the best though,
+	 * in the worst case the hardware will fall back to USB2-only.
+	 */
+	WARN_ON_ONCE(atcphy->pipehandler_up);
+	return atcphy_configure(atcphy, target_mode);
+}
+
+static int atcphy_probe_mux(struct apple_atcphy *atcphy)
+{
+	struct typec_mux_desc mux_desc = {
+		.drvdata = atcphy,
+		.fwnode = atcphy->dev->fwnode,
+		.set = atcphy_mux_set,
+	};
+
+	return PTR_ERR_OR_ZERO(typec_mux_register(atcphy->dev, &mux_desc));
+}
+
+static int atcphy_load_tunables(struct apple_atcphy *atcphy)
+{
+	struct {
+		const char *dt_name;
+		struct apple_tunable **tunable;
+		struct resource *res;
+	} tunables[] = {
+		{ "apple,tunable-axi2af", &atcphy->tunables.axi2af, atcphy->res.axi2af },
+		{ "apple,tunable-common-a", &atcphy->tunables.common[0], atcphy->res.core },
+		{ "apple,tunable-common-b", &atcphy->tunables.common[1], atcphy->res.core },
+		{ "apple,tunable-lane0-usb", &atcphy->tunables.lane_usb3[0], atcphy->res.core },
+		{ "apple,tunable-lane1-usb", &atcphy->tunables.lane_usb3[1], atcphy->res.core },
+		{ "apple,tunable-lane0-cio", &atcphy->tunables.lane_usb4[0], atcphy->res.core },
+		{ "apple,tunable-lane1-cio", &atcphy->tunables.lane_usb4[1], atcphy->res.core },
+		{ "apple,tunable-lane0-dp", &atcphy->tunables.lane_dp[0], atcphy->res.core },
+		{ "apple,tunable-lane1-dp", &atcphy->tunables.lane_dp[1], atcphy->res.core },
+	};
+
+	for (int i = 0; i < ARRAY_SIZE(tunables); i++) {
+		*tunables[i].tunable = devm_apple_tunable_parse(
+			atcphy->dev, atcphy->np, tunables[i].dt_name, tunables[i].res);
+		if (IS_ERR(tunables[i].tunable)) {
+			dev_err(atcphy->dev, "Failed to read tunable %s: %ld\n",
+				tunables[i].dt_name, PTR_ERR(tunables[i].tunable));
+			return PTR_ERR(tunables[i].tunable);
+		}
+	}
+
+	return 0;
+}
+
+static int atcphy_map_resources(struct platform_device *pdev, struct apple_atcphy *atcphy)
+{
+	struct {
+		const char *name;
+		void __iomem **addr;
+		struct resource **res;
+	} resources[] = {
+		{ "core", &atcphy->regs.core, &atcphy->res.core },
+		{ "lpdptx", &atcphy->regs.lpdptx, NULL },
+		{ "axi2af", &atcphy->regs.axi2af, &atcphy->res.axi2af },
+		{ "usb2phy", &atcphy->regs.usb2phy, NULL },
+		{ "pipehandler", &atcphy->regs.pipehandler, NULL },
+	};
+	struct resource *res;
+
+	for (int i = 0; i < ARRAY_SIZE(resources); i++) {
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, resources[i].name);
+		*resources[i].addr = devm_ioremap_resource(&pdev->dev, res);
+		if (IS_ERR(resources[i].addr))
+			return dev_err_probe(atcphy->dev, PTR_ERR(resources[i].addr),
+					     "Unable to map %s regs", resources[i].name);
+
+		if (resources[i].res)
+			*resources[i].res = res;
+	}
+
+	return 0;
+}
+
+static int atcphy_probe_finalize(struct apple_atcphy *atcphy)
+{
+	int ret;
+
+	guard(mutex)(&atcphy->lock);
+
+	/* Reset dwc3 on probe, let dwc3 (consumer) deassert it */
+	_atcphy_dwc3_reset_assert(atcphy);
+
+	/* Reset atcphy to clear any state potentially left by the bootloader */
+	atcphy_power_off(atcphy);
+	atcphy_setup_pipehandler(atcphy);
+
+	ret = atcphy_probe_rcdev(atcphy);
+	if (ret)
+		return dev_err_probe(atcphy->dev, ret, "Probing rcdev failed");
+	ret = atcphy_probe_mux(atcphy);
+	if (ret)
+		return dev_err_probe(atcphy->dev, ret, "Probing mux failed");
+	ret = atcphy_probe_switch(atcphy);
+	if (ret)
+		return dev_err_probe(atcphy->dev, ret, "Probing switch failed");
+	ret = atcphy_probe_phy(atcphy);
+	if (ret)
+		return dev_err_probe(atcphy->dev, ret, "Probing phy failed");
+
+	return 0;
+}
+
+static int atcphy_probe(struct platform_device *pdev)
+{
+	struct apple_atcphy *atcphy;
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	atcphy = devm_kzalloc(&pdev->dev, sizeof(*atcphy), GFP_KERNEL);
+	if (!atcphy)
+		return -ENOMEM;
+
+	atcphy->dev = dev;
+	atcphy->np = dev->of_node;
+	mutex_init(&atcphy->lock);
+	platform_set_drvdata(pdev, atcphy);
+
+	ret = atcphy_map_resources(pdev, atcphy);
+	if (ret)
+		return ret;
+	ret = atcphy_load_tunables(atcphy);
+	if (ret)
+		return ret;
+
+	atcphy->mode = APPLE_ATCPHY_MODE_OFF;
+	atcphy->pipehandler_up = false;
+
+	return atcphy_probe_finalize(atcphy);
+}
+
+static const struct of_device_id atcphy_match[] = {
+	{ .compatible = "apple,t8103-atcphy" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, atcphy_match);
+
+static struct platform_driver atcphy_driver = {
+	.driver = {
+		.name = "phy-apple-atc",
+		.of_match_table = atcphy_match,
+	},
+	.probe = atcphy_probe,
+};
+module_platform_driver(atcphy_driver);
+
+MODULE_AUTHOR("Sven Peter <sven at kernel.org>");
+MODULE_DESCRIPTION("Apple Type-C PHY driver");
+MODULE_LICENSE("GPL");

-- 
2.34.1




From festevam at gmail.com  Sun Dec 14 04:04:38 2025
From: festevam at gmail.com (Fabio Estevam)
Date: Sun, 14 Dec 2025 09:04:38 -0300
Subject: [PATCH v3 6/6] arm64: dts: imx8mp-var-som: Add support for
 ADS7846 touchscreen
In-Reply-To: <20251214110531.9475-7-stefano.r@variscite.com>
References: <20251214110531.9475-1-stefano.r@variscite.com> <20251214110531.9475-7-stefano.r@variscite.com>
Message-ID: <CAOMZO5AzuZVkD3rTLEDGFpCx0ovtKfzjZtNgGG0uLDXbPkiqRg@mail.gmail.com>

Hi Stefano,

On Sun, Dec 14, 2025 at 8:05?AM Stefano Radaelli
<stefano.radaelli21 at gmail.com> wrote:

> +       /* Resistive touch controller */
> +       ads7846: touchscreen at 0 {
> +               compatible = "ti,ads7846";

The public datasheet states that the touchscreen is a TSC2046:

https://variscite.com/wp-content/uploads/2024/05/VAR-SOM-MX8M-PLUS_V2_Datasheet.pdf

I understand they are both from the same family of touchscreen
controllers, but shouldn't you use the ti,tsc2046 compatible string
instead?


From leo.yan at linux.dev  Sun Dec 14 04:18:42 2025
From: leo.yan at linux.dev (Leo Yan)
Date: Sun, 14 Dec 2025 20:18:42 +0800
Subject: [RFC PATCH v6 05/35] KVM: arm64: Add KVM_CAP_ARM_SPE capability
In-Reply-To: <20251114160717.163230-6-alexandru.elisei@arm.com>
References: <20251114160717.163230-1-alexandru.elisei@arm.com>
 <20251114160717.163230-6-alexandru.elisei@arm.com>
Message-ID: <20251214121842.GA16796@debian-dev>

On Fri, Nov 14, 2025 at 04:06:46PM +0000, Alexandru Elisei wrote:

[...]

> +void kvm_host_spe_init(struct arm_spe_pmu *arm_spu)
> +{
> +	struct arm_spu_entry *entry;
> +
> +	guard(mutex)(&arm_spus_lock);
> +
> +	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
> +	if (!entry)
> +		return;
> +
> +	entry->arm_spu = arm_spu;
> +	list_add_tail(&entry->link, &arm_spus);
> +
> +	if (list_is_singular(&arm_spus))
> +		static_branch_enable(&kvm_spe_available);

We can simply check if list_empty(&arm_spus) in kvm_supports_spe(), thus
the static key kvm_spe_available is not needed.  Another benefit is this
is consistent with CPU PMU's virt implementation.

Thanks,
Leo


From tomi.valkeinen at ideasonboard.com  Sun Dec 14 04:42:03 2025
From: tomi.valkeinen at ideasonboard.com (Tomi Valkeinen)
Date: Sun, 14 Dec 2025 14:42:03 +0200
Subject: [PATCH 0/4] drm: Revert and fix enable/disable sequence
In-Reply-To: <CAD++jLk8-0Rkh16T+R1dh6=e_f9U1i=AKOk1Y8dLGV4bxzRtFg@mail.gmail.com>
References: <20251205-drm-seq-fix-v1-0-fda68fa1b3de@ideasonboard.com>
 <3b13c7a2-f7e6-49fd-b3bb-3e0a1fe9acf3@ideasonboard.com>
 <CAD++jLk8-0Rkh16T+R1dh6=e_f9U1i=AKOk1Y8dLGV4bxzRtFg@mail.gmail.com>
Message-ID: <817b2358-0920-4b7a-abb1-133103d0f9fe@ideasonboard.com>

Hi,

On 14/12/2025 13:14, Linus Walleij wrote:
> On Fri, Dec 12, 2025 at 3:21?PM Tomi Valkeinen
> <tomi.valkeinen at ideasonboard.com> wrote:
>> On 05/12/2025 11:51, Tomi Valkeinen wrote:
>>> Changing the enable/disable sequence in commit c9b1150a68d9
>>> ("drm/atomic-helper: Re-order bridge chain pre-enable and post-disable")
>>> has caused regressions on multiple platforms: R-Car, MCDE, Rockchip.
>>>
>>> This is an alternate series to Linus' series:
>>>
>>> https://lore.kernel.org/all/20251202-mcde-drm-regression-thirdfix-v6-0-f1bffd4ec0fa%40kernel.org/
>>>
>>> This series first reverts the original commit and reverts a fix for
>>> mediatek which is no longer needed. It then exposes helper functions
>>> from DRM core, and finally implements the new sequence only in the tidss
>>> driver.
>>>
>>> There is one more fix in upstream for the original commit, commit
>>> 5d91394f2361 ("drm/exynos: fimd: Guard display clock control with
>>> runtime PM calls"), but I have not reverted that one as it looks like a
>>> valid patch in its own.
>>>
>>> I added Cc stable v6.17+ to all patches, but I didn't add Fixes tags, as
>>> I wasn't sure what should they point to. But I could perhaps add Fixes:
>>> <original commit> to all of these.
> 
>> There has been no comments, so I assume this is the way to go.
>>
>> Should we merge this series as a fix for 6.18 rcs?
> 
> Too late now, so let's merge it as a fix for v6.19 rcs!
Ah, right. Indeed, I meant v6.19 rcs.

 Tomi



From robh at kernel.org  Sun Dec 14 06:41:56 2025
From: robh at kernel.org (Rob Herring)
Date: Sun, 14 Dec 2025 08:41:56 -0600
Subject: [PATCH] ARM: dts: nxp/imx6: Drop unused .dtsi
In-Reply-To: <20251213181324.u32ztfblkknfpz44@pengutronix.de>
References: <20251212203226.458694-5-robh@kernel.org> <20251213181324.u32ztfblkknfpz44@pengutronix.de>
Message-ID: <CAL_JsqK9OREenZjBHrDh7AqsyUXYOzTOhY4e0qHGzYkX8tacWQ@mail.gmail.com>

On Sat, Dec 13, 2025 at 12:13?PM Marco Felsch <m.felsch at pengutronix.de> wrote:
>
> Hi Rob,
>
> On 25-12-12, Rob Herring (Arm) wrote:
> > These .dtsi files are not included anywhere in the tree and can't be
> > tested.
>
> not in the tree but by other projects, please see below.
>
> > Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> > ---
> >  .../dts/nxp/imx/imx6dl-kontron-samx6i.dtsi    | 12 -----
> >  .../dts/nxp/imx/imx6q-kontron-samx6i.dtsi     | 12 -----
> >  .../boot/dts/nxp/imx/imx6qdl-pico-dwarf.dtsi  | 45 ----------------
> >  .../boot/dts/nxp/imx/imx6qdl-pico-nymph.dtsi  | 54 -------------------
> >  4 files changed, 123 deletions(-)
> >  delete mode 100644 arch/arm/boot/dts/nxp/imx/imx6dl-kontron-samx6i.dtsi
> >  delete mode 100644 arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi
> >  delete mode 100644 arch/arm/boot/dts/nxp/imx/imx6qdl-pico-dwarf.dtsi
> >  delete mode 100644 arch/arm/boot/dts/nxp/imx/imx6qdl-pico-nymph.dtsi
> >
> > diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-kontron-samx6i.dtsi b/arch/arm/boot/dts/nxp/imx/imx6dl-kontron-samx6i.dtsi
> > deleted file mode 100644
> > index 5a9b819d7ee8..000000000000
> > --- a/arch/arm/boot/dts/nxp/imx/imx6dl-kontron-samx6i.dtsi
> > +++ /dev/null
> > @@ -1,12 +0,0 @@
> > -// SPDX-License-Identifier: GPL-2.0 OR X11
> > -/*
> > - * Copyright 2019 (C) Pengutronix, Marco Felsch <kernel at pengutronix.de>
> > - */
> > -
> > -#include "imx6dl.dtsi"
> > -#include "imx6qdl-kontron-samx6i.dtsi"
> > -
> > -/ {
> > -     model = "Kontron SMARC-sAMX6i Dual-Lite/Solo";
> > -     compatible = "kontron,imx6dl-samx6i", "fsl,imx6dl";
> > -};
> > diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi b/arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi
> > deleted file mode 100644
> > index e76963436079..000000000000
> > --- a/arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi
> > +++ /dev/null
> > @@ -1,12 +0,0 @@
> > -// SPDX-License-Identifier: GPL-2.0 OR X11
> > -/*
> > - * Copyright 2019 (C) Pengutronix, Marco Felsch <kernel at pengutronix.de>
> > - */
> > -
> > -#include "imx6q.dtsi"
> > -#include "imx6qdl-kontron-samx6i.dtsi"
> > -
> > -/ {
> > -     model = "Kontron SMARC-sAMX6i Quad/Dual";
> > -     compatible = "kontron,imx6q-samx6i", "fsl,imx6q";
> > -};
>
> I can't speak for the other two .dtsi files but both kontron .dtsi files
> are used by barebox:
>
>  - https://elixir.bootlin.com/barebox/v2025.11.0/source/arch/arm/dts/imx6dl-samx6i.dts#L8
>  - https://elixir.bootlin.com/barebox/v2025.11.0/source/arch/arm/dts/imx6q-samx6i.dts#L8
>
> Removing them here will cause a regression for barebox.

Please upstream something that uses the .dtsi. Other than the
undocumented barebox property, no reason these can't be.

Rob


From andrew at lunn.ch  Sun Dec 14 08:43:12 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Sun, 14 Dec 2025 17:43:12 +0100
Subject: [RFC net-next v3 2/3] net: ethernet: mtk_eth_soc: Add RSS support
In-Reply-To: <20251214110310.7009-3-linux@fw-web.de>
References: <20251214110310.7009-1-linux@fw-web.de>
 <20251214110310.7009-3-linux@fw-web.de>
Message-ID: <cbe399db-11b9-4176-b842-a50956df7d26@lunn.ch>

>  bpi-r4.its                                  |  16 +-

I don't think this file belongs in this patch?

> +#define MTK_RX_RSS_NUM			(eth->soc->rss_num)
> +#define MTK_RSS_HASH_KEY_DW(x)		(reg_map->pdma.rss_glo_cfg + 0x20 +	\
> +					 ((x) * 0x4))
> +#define MTK_RSS_INDR_TABLE_DW(x)	(reg_map->pdma.rss_glo_cfg + 0x50 +	\
> +					 ((x) * 0x4))

It is bad practice for a macro to access things not passed to it. At
minimum, pass eth & reg_map to the macro.

    Andrew

---
pw-bot: cr


From andrew at lunn.ch  Sun Dec 14 08:49:43 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Sun, 14 Dec 2025 17:49:43 +0100
Subject: [RFC net-next v3 3/3] net: ethernet: mtk_eth_soc: Add LRO support
In-Reply-To: <20251214110310.7009-4-linux@fw-web.de>
References: <20251214110310.7009-1-linux@fw-web.de>
 <20251214110310.7009-4-linux@fw-web.de>
Message-ID: <2e00738e-6d17-4ba6-8af4-7e02783b17da@lunn.ch>

>  static int mtk_hwlro_rx_init(struct mtk_eth *eth)
>  {
>  	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
> -	int i;
> +	const struct mtk_soc_data *soc = eth->soc;
> +	int i, val;
>  	u32 ring_ctrl_dw1 = 0, ring_ctrl_dw2 = 0, ring_ctrl_dw3 = 0;
>  	u32 lro_ctrl_dw0 = 0, lro_ctrl_dw3 = 0;

Reverse Christmas tree. It looks like it was already broken, but you
should not make it worse, and i think you can even fix it here.

> +static int mtk_hwlro_add_ipaddr_idx(struct net_device *dev, u32 ip4dst)
> +{
> +	struct mtk_mac *mac = netdev_priv(dev);
> +	struct mtk_eth *eth = mac->hw;
> +	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
> +	u32 reg_val;
> +	int i;

More Reverse Christmas tree probes. You will need to move the
assignment to reg_map into the body of the function.

> +#define MTK_PDMA_LRO_CTRL_DW0	(reg_map->pdma.lro_ctrl_dw0)
> +#define MTK_PDMA_LRO_CTRL_DW1	(reg_map->pdma.lro_ctrl_dw0 + 0x04)
> +#define MTK_PDMA_LRO_CTRL_DW2	(reg_map->pdma.lro_ctrl_dw0 + 0x08)
> +#define MTK_PDMA_LRO_CTRL_DW3	(reg_map->pdma.lro_ctrl_dw0 + 0x0c)

Same comment as the previous patch.

	Andrew


From christophe.jaillet at wanadoo.fr  Sun Dec 14 09:49:09 2025
From: christophe.jaillet at wanadoo.fr (Christophe JAILLET)
Date: Sun, 14 Dec 2025 18:49:09 +0100
Subject: [PATCH] stm class: Constify struct configfs_item_operations and configfs_group_operations
Message-ID: <b5811c1c5efdc6e9c8eb4886b8046b50b09c37f0.1765734533.git.christophe.jaillet@wanadoo.fr>

'struct configfs_item_operations' and 'configfs_group_operations' are not
modified in this driver.

Constifying these structures moves some data to a read-only section, so
increases overall security, especially when the structure holds some
function pointers.

On a x86_64, with allmodconfig, as an example:
Before:
======
   text	   data	    bss	    dec	    hex	filename
  11786	   4216	     64	  16066	   3ec2	drivers/hwtracing/stm/policy.o

After:
=====
   text	   data	    bss	    dec	    hex	filename
  12202	   3800	     64	  16066	   3ec2	drivers/hwtracing/stm/policy.o

Signed-off-by: Christophe JAILLET <christophe.jaillet at wanadoo.fr>
---
Compile tested only.

This change is possible since commits f2f36500a63b and f7f78098690d.
---
 drivers/hwtracing/stm/policy.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/hwtracing/stm/policy.c b/drivers/hwtracing/stm/policy.c
index 42103c3a177f..a1af8d585fc9 100644
--- a/drivers/hwtracing/stm/policy.c
+++ b/drivers/hwtracing/stm/policy.c
@@ -181,7 +181,7 @@ static void stp_policy_node_release(struct config_item *item)
 	kfree(node);
 }
 
-static struct configfs_item_operations stp_policy_node_item_ops = {
+static const struct configfs_item_operations stp_policy_node_item_ops = {
 	.release		= stp_policy_node_release,
 };
 
@@ -270,7 +270,7 @@ stp_policy_node_drop(struct config_group *group, struct config_item *item)
 	config_item_put(item);
 }
 
-static struct configfs_group_operations stp_policy_node_group_ops = {
+static const struct configfs_group_operations stp_policy_node_group_ops = {
 	.make_group	= stp_policy_node_make,
 	.drop_item	= stp_policy_node_drop,
 };
@@ -364,11 +364,11 @@ static void stp_policy_release(struct config_item *item)
 	kfree(policy);
 }
 
-static struct configfs_item_operations stp_policy_item_ops = {
+static const struct configfs_item_operations stp_policy_item_ops = {
 	.release		= stp_policy_release,
 };
 
-static struct configfs_group_operations stp_policy_group_ops = {
+static const struct configfs_group_operations stp_policy_group_ops = {
 	.make_group	= stp_policy_node_make,
 };
 
@@ -466,7 +466,7 @@ stp_policy_make(struct config_group *group, const char *name)
 	return ret;
 }
 
-static struct configfs_group_operations stp_policy_root_group_ops = {
+static const struct configfs_group_operations stp_policy_root_group_ops = {
 	.make_group	= stp_policy_make,
 };
 
-- 
2.52.0



From m.felsch at pengutronix.de  Sun Dec 14 10:57:50 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Sun, 14 Dec 2025 19:57:50 +0100
Subject: [PATCH] ARM: dts: nxp/imx6: Drop unused .dtsi
In-Reply-To: <CAL_JsqK9OREenZjBHrDh7AqsyUXYOzTOhY4e0qHGzYkX8tacWQ@mail.gmail.com>
References: <20251212203226.458694-5-robh@kernel.org>
 <20251213181324.u32ztfblkknfpz44@pengutronix.de>
 <CAL_JsqK9OREenZjBHrDh7AqsyUXYOzTOhY4e0qHGzYkX8tacWQ@mail.gmail.com>
Message-ID: <20251214185750.tzt6jf4zg5gtex63@pengutronix.de>

On 25-12-14, Rob Herring wrote:
> On Sat, Dec 13, 2025 at 12:13?PM Marco Felsch <m.felsch at pengutronix.de> wrote:
> >
> > Hi Rob,
> >
> > On 25-12-12, Rob Herring (Arm) wrote:
> > > These .dtsi files are not included anywhere in the tree and can't be
> > > tested.
> >
> > not in the tree but by other projects, please see below.
> >
> > > Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> > > ---
> > >  .../dts/nxp/imx/imx6dl-kontron-samx6i.dtsi    | 12 -----
> > >  .../dts/nxp/imx/imx6q-kontron-samx6i.dtsi     | 12 -----
> > >  .../boot/dts/nxp/imx/imx6qdl-pico-dwarf.dtsi  | 45 ----------------
> > >  .../boot/dts/nxp/imx/imx6qdl-pico-nymph.dtsi  | 54 -------------------
> > >  4 files changed, 123 deletions(-)
> > >  delete mode 100644 arch/arm/boot/dts/nxp/imx/imx6dl-kontron-samx6i.dtsi
> > >  delete mode 100644 arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi
> > >  delete mode 100644 arch/arm/boot/dts/nxp/imx/imx6qdl-pico-dwarf.dtsi
> > >  delete mode 100644 arch/arm/boot/dts/nxp/imx/imx6qdl-pico-nymph.dtsi
> > >
> > > diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-kontron-samx6i.dtsi b/arch/arm/boot/dts/nxp/imx/imx6dl-kontron-samx6i.dtsi
> > > deleted file mode 100644
> > > index 5a9b819d7ee8..000000000000
> > > --- a/arch/arm/boot/dts/nxp/imx/imx6dl-kontron-samx6i.dtsi
> > > +++ /dev/null
> > > @@ -1,12 +0,0 @@
> > > -// SPDX-License-Identifier: GPL-2.0 OR X11
> > > -/*
> > > - * Copyright 2019 (C) Pengutronix, Marco Felsch <kernel at pengutronix.de>
> > > - */
> > > -
> > > -#include "imx6dl.dtsi"
> > > -#include "imx6qdl-kontron-samx6i.dtsi"
> > > -
> > > -/ {
> > > -     model = "Kontron SMARC-sAMX6i Dual-Lite/Solo";
> > > -     compatible = "kontron,imx6dl-samx6i", "fsl,imx6dl";
> > > -};
> > > diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi b/arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi
> > > deleted file mode 100644
> > > index e76963436079..000000000000
> > > --- a/arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi
> > > +++ /dev/null
> > > @@ -1,12 +0,0 @@
> > > -// SPDX-License-Identifier: GPL-2.0 OR X11
> > > -/*
> > > - * Copyright 2019 (C) Pengutronix, Marco Felsch <kernel at pengutronix.de>
> > > - */
> > > -
> > > -#include "imx6q.dtsi"
> > > -#include "imx6qdl-kontron-samx6i.dtsi"
> > > -
> > > -/ {
> > > -     model = "Kontron SMARC-sAMX6i Quad/Dual";
> > > -     compatible = "kontron,imx6q-samx6i", "fsl,imx6q";
> > > -};
> >
> > I can't speak for the other two .dtsi files but both kontron .dtsi files
> > are used by barebox:
> >
> >  - https://elixir.bootlin.com/barebox/v2025.11.0/source/arch/arm/dts/imx6dl-samx6i.dts#L8
> >  - https://elixir.bootlin.com/barebox/v2025.11.0/source/arch/arm/dts/imx6q-samx6i.dts#L8
> >
> > Removing them here will cause a regression for barebox.
> 
> Please upstream something that uses the .dtsi. Other than the
> undocumented barebox property, no reason these can't be.

My intention wasn't to point to the barebox-only
"barebox,disable-deep-probe" property. I was refering to the include
line.

The two .dtsi files we're talking about are SoM .dtsi files. We don't
have access to the Kontron EVK baseboard which uses this SoM.

I've added a few Kontron devs which may can add the missing baseboard
support.

+Cc: frieder.schrempf at kontron.de
+Cc: annette.kobou at kontron.de
+Cc: oualid.derouiche at kontron.de
+Cc: eberhard.stoll at kontron.de

I could also add the imx6dl-samx6i.dts and imx6q-samx6i.dts like we do
in barebox. But as said, this would be a devicetree for a SoM which
makes sense for the bootloader but not for the kernel.

Regards,
  Marco


> 
> Rob
> 

-- 
#gernperDu 
#CallMeByMyFirstName

Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | https://www.pengutronix.de/ |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-9    |


From rdunlap at infradead.org  Sun Dec 14 11:17:50 2025
From: rdunlap at infradead.org (Randy Dunlap)
Date: Sun, 14 Dec 2025 11:17:50 -0800
Subject: [PATCH] xilinx_hwicap: fifo_icap.c: fix all kernel-doc warnings
Message-ID: <20251214191750.2173225-1-rdunlap@infradead.org>

Modify comments in fifo_icap.c to prevent all kernel-doc warnings:

Warning: fifo_icap.c:51 This comment starts with '/**', but isn't a
 kernel-doc comment.
 * HwIcap Device Interrupt Status/Enable Registers
Warning: fifo_icap.c:106 No description found for return value
 of 'fifo_icap_fifo_read'
Warning: fifo_icap.c:160 No description found for return value
 of 'fifo_icap_get_status'
Warning: fifo_icap.c:171 No description found for return value
 of 'fifo_icap_busy'
Warning: fifo_icap.c:184 No description found for return value
 of 'fifo_icap_write_fifo_vacancy'
Warning: fifo_icap.c:196 No description found for return value
 of 'fifo_icap_read_fifo_occupancy'
Warning: fifo_icap.c:207 bad line:
Warning: fifo_icap.c:214 No description found for return value
 of 'fifo_icap_set_configuration'
Warning: fifo_icap.c:290 function parameter 'frame_buffer' not described
 in 'fifo_icap_get_configuration'
Warning: fifo_icap.c:290 function parameter 'num_words' not described
 in 'fifo_icap_get_configuration'
Warning: fifo_icap.c:290 No description found for return value
 of 'fifo_icap_get_configuration'
Warning: fifo_icap.c:357 expecting prototype for buffer_icap_reset().
 Prototype was for fifo_icap_reset() instead

Signed-off-by: Randy Dunlap <rdunlap at infradead.org>
---
Cc: Arnd Bergmann <arnd at arndb.de>
Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
Cc: Michal Simek <michal.simek at amd.com>
Cc: linux-arm-kernel at lists.infradead.org
---
 drivers/char/xilinx_hwicap/fifo_icap.c |   27 ++++++++++++++++-------
 1 file changed, 19 insertions(+), 8 deletions(-)

--- linux-next-20251128.orig/drivers/char/xilinx_hwicap/fifo_icap.c
+++ linux-next-20251128/drivers/char/xilinx_hwicap/fifo_icap.c
@@ -48,7 +48,7 @@
 
 #define XHI_GIER_GIE_MASK 0x80000000 /* Global Interrupt enable Mask */
 
-/**
+/*
  * HwIcap Device Interrupt Status/Enable Registers
  *
  * Interrupt Status Register (IPISR) : This register holds the
@@ -102,6 +102,8 @@ static inline void fifo_icap_fifo_write(
  * @drvdata: a pointer to the drvdata.
  *
  * This function will silently fail if the fifo is empty.
+ *
+ * Returns: 32-bit data from the Read FIFO
  **/
 static inline u32 fifo_icap_fifo_read(struct hwicap_drvdata *drvdata)
 {
@@ -156,6 +158,8 @@ static inline void fifo_icap_start_readb
  * D2 - Always 1
  * D1 - Always 1
  * D0 - Done bit
+ *
+ * Returns: the 32-bit ICAP status register
  **/
 u32 fifo_icap_get_status(struct hwicap_drvdata *drvdata)
 {
@@ -165,8 +169,11 @@ u32 fifo_icap_get_status(struct hwicap_d
 }
 
 /**
- * fifo_icap_busy - Return true if the ICAP is still processing a transaction.
+ * fifo_icap_busy - Check the ICAP busy status.
  * @drvdata: a pointer to the drvdata.
+ *
+ * Returns: %true if the ICAP is still processing a transaction,
+ *	otherwise %false
  **/
 static inline u32 fifo_icap_busy(struct hwicap_drvdata *drvdata)
 {
@@ -178,7 +185,7 @@ static inline u32 fifo_icap_busy(struct
  * fifo_icap_write_fifo_vacancy - Query the write fifo available space.
  * @drvdata: a pointer to the drvdata.
  *
- * Return the number of words that can be safely pushed into the write fifo.
+ * Returns: the number of words that can be safely pushed into the write fifo.
  **/
 static inline u32 fifo_icap_write_fifo_vacancy(
 		struct hwicap_drvdata *drvdata)
@@ -190,7 +197,7 @@ static inline u32 fifo_icap_write_fifo_v
  * fifo_icap_read_fifo_occupancy - Query the read fifo available data.
  * @drvdata: a pointer to the drvdata.
  *
- * Return the number of words that can be safely read from the read fifo.
+ * Returns: the number of words that can be safely read from the read fifo.
  **/
 static inline u32 fifo_icap_read_fifo_occupancy(
 		struct hwicap_drvdata *drvdata)
@@ -205,10 +212,12 @@ static inline u32 fifo_icap_read_fifo_oc
  *		ICAP device.
  * @num_words: the number of words (32 bit) to write to the ICAP
  *		device.
-
+ *
  * This function writes the given user data to the Write FIFO in
  * polled mode and starts the transfer of the data to
  * the ICAP device.
+ *
+ * Returns: %0 on success or %-errno on failure.
  **/
 int fifo_icap_set_configuration(struct hwicap_drvdata *drvdata,
 		u32 *frame_buffer, u32 num_words)
@@ -280,11 +289,13 @@ int fifo_icap_set_configuration(struct h
 /**
  * fifo_icap_get_configuration - Read configuration data from the device.
  * @drvdata: a pointer to the drvdata.
- * @data: Address of the data representing the partial bitstream
- * @size: the size of the partial bitstream in 32 bit words.
+ * @frame_buffer: Address of the data representing the partial bitstream
+ * @num_words: the size of the partial bitstream in 32 bit words.
  *
  * This function reads the specified number of words from the ICAP device in
  * the polled mode.
+ *
+ * Returns: %0 on success or %-errno on failure.
  */
 int fifo_icap_get_configuration(struct hwicap_drvdata *drvdata,
 		u32 *frame_buffer, u32 num_words)
@@ -347,7 +358,7 @@ int fifo_icap_get_configuration(struct h
 }
 
 /**
- * buffer_icap_reset - Reset the logic of the icap device.
+ * fifo_icap_reset - Reset the logic of the icap device.
  * @drvdata: a pointer to the drvdata.
  *
  * This function forces the software reset of the complete HWICAP device.


From rdunlap at infradead.org  Sun Dec 14 11:17:58 2025
From: rdunlap at infradead.org (Randy Dunlap)
Date: Sun, 14 Dec 2025 11:17:58 -0800
Subject: [PATCH] xilinx_hwicap: fifo_icap.c: fix all kernel-doc warnings
Message-ID: <20251214191758.2173409-1-rdunlap@infradead.org>

Modify comments in fifo_icap.c to prevent all kernel-doc warnings:

Warning: fifo_icap.c:51 This comment starts with '/**', but isn't a
 kernel-doc comment.
 * HwIcap Device Interrupt Status/Enable Registers
Warning: fifo_icap.c:106 No description found for return value
 of 'fifo_icap_fifo_read'
Warning: fifo_icap.c:160 No description found for return value
 of 'fifo_icap_get_status'
Warning: fifo_icap.c:171 No description found for return value
 of 'fifo_icap_busy'
Warning: fifo_icap.c:184 No description found for return value
 of 'fifo_icap_write_fifo_vacancy'
Warning: fifo_icap.c:196 No description found for return value
 of 'fifo_icap_read_fifo_occupancy'
Warning: fifo_icap.c:207 bad line:
Warning: fifo_icap.c:214 No description found for return value
 of 'fifo_icap_set_configuration'
Warning: fifo_icap.c:290 function parameter 'frame_buffer' not described
 in 'fifo_icap_get_configuration'
Warning: fifo_icap.c:290 function parameter 'num_words' not described
 in 'fifo_icap_get_configuration'
Warning: fifo_icap.c:290 No description found for return value
 of 'fifo_icap_get_configuration'
Warning: fifo_icap.c:357 expecting prototype for buffer_icap_reset().
 Prototype was for fifo_icap_reset() instead

Signed-off-by: Randy Dunlap <rdunlap at infradead.org>
---
Cc: Arnd Bergmann <arnd at arndb.de>
Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
Cc: Michal Simek <michal.simek at amd.com>
Cc: linux-arm-kernel at lists.infradead.org
---
 drivers/char/xilinx_hwicap/fifo_icap.c |   27 ++++++++++++++++-------
 1 file changed, 19 insertions(+), 8 deletions(-)

--- linux-next-20251128.orig/drivers/char/xilinx_hwicap/fifo_icap.c
+++ linux-next-20251128/drivers/char/xilinx_hwicap/fifo_icap.c
@@ -48,7 +48,7 @@
 
 #define XHI_GIER_GIE_MASK 0x80000000 /* Global Interrupt enable Mask */
 
-/**
+/*
  * HwIcap Device Interrupt Status/Enable Registers
  *
  * Interrupt Status Register (IPISR) : This register holds the
@@ -102,6 +102,8 @@ static inline void fifo_icap_fifo_write(
  * @drvdata: a pointer to the drvdata.
  *
  * This function will silently fail if the fifo is empty.
+ *
+ * Returns: 32-bit data from the Read FIFO
  **/
 static inline u32 fifo_icap_fifo_read(struct hwicap_drvdata *drvdata)
 {
@@ -156,6 +158,8 @@ static inline void fifo_icap_start_readb
  * D2 - Always 1
  * D1 - Always 1
  * D0 - Done bit
+ *
+ * Returns: the 32-bit ICAP status register
  **/
 u32 fifo_icap_get_status(struct hwicap_drvdata *drvdata)
 {
@@ -165,8 +169,11 @@ u32 fifo_icap_get_status(struct hwicap_d
 }
 
 /**
- * fifo_icap_busy - Return true if the ICAP is still processing a transaction.
+ * fifo_icap_busy - Check the ICAP busy status.
  * @drvdata: a pointer to the drvdata.
+ *
+ * Returns: %true if the ICAP is still processing a transaction,
+ *	otherwise %false
  **/
 static inline u32 fifo_icap_busy(struct hwicap_drvdata *drvdata)
 {
@@ -178,7 +185,7 @@ static inline u32 fifo_icap_busy(struct
  * fifo_icap_write_fifo_vacancy - Query the write fifo available space.
  * @drvdata: a pointer to the drvdata.
  *
- * Return the number of words that can be safely pushed into the write fifo.
+ * Returns: the number of words that can be safely pushed into the write fifo.
  **/
 static inline u32 fifo_icap_write_fifo_vacancy(
 		struct hwicap_drvdata *drvdata)
@@ -190,7 +197,7 @@ static inline u32 fifo_icap_write_fifo_v
  * fifo_icap_read_fifo_occupancy - Query the read fifo available data.
  * @drvdata: a pointer to the drvdata.
  *
- * Return the number of words that can be safely read from the read fifo.
+ * Returns: the number of words that can be safely read from the read fifo.
  **/
 static inline u32 fifo_icap_read_fifo_occupancy(
 		struct hwicap_drvdata *drvdata)
@@ -205,10 +212,12 @@ static inline u32 fifo_icap_read_fifo_oc
  *		ICAP device.
  * @num_words: the number of words (32 bit) to write to the ICAP
  *		device.
-
+ *
  * This function writes the given user data to the Write FIFO in
  * polled mode and starts the transfer of the data to
  * the ICAP device.
+ *
+ * Returns: %0 on success or %-errno on failure.
  **/
 int fifo_icap_set_configuration(struct hwicap_drvdata *drvdata,
 		u32 *frame_buffer, u32 num_words)
@@ -280,11 +289,13 @@ int fifo_icap_set_configuration(struct h
 /**
  * fifo_icap_get_configuration - Read configuration data from the device.
  * @drvdata: a pointer to the drvdata.
- * @data: Address of the data representing the partial bitstream
- * @size: the size of the partial bitstream in 32 bit words.
+ * @frame_buffer: Address of the data representing the partial bitstream
+ * @num_words: the size of the partial bitstream in 32 bit words.
  *
  * This function reads the specified number of words from the ICAP device in
  * the polled mode.
+ *
+ * Returns: %0 on success or %-errno on failure.
  */
 int fifo_icap_get_configuration(struct hwicap_drvdata *drvdata,
 		u32 *frame_buffer, u32 num_words)
@@ -347,7 +358,7 @@ int fifo_icap_get_configuration(struct h
 }
 
 /**
- * buffer_icap_reset - Reset the logic of the icap device.
+ * fifo_icap_reset - Reset the logic of the icap device.
  * @drvdata: a pointer to the drvdata.
  *
  * This function forces the software reset of the complete HWICAP device.


From rdunlap at infradead.org  Sun Dec 14 11:18:44 2025
From: rdunlap at infradead.org (Randy Dunlap)
Date: Sun, 14 Dec 2025 11:18:44 -0800
Subject: [PATCH] xilinx_hwicap: fifo_icap.c: fix all kernel-doc warnings
In-Reply-To: <20251214191758.2173409-1-rdunlap@infradead.org>
References: <20251214191758.2173409-1-rdunlap@infradead.org>
Message-ID: <ffdc9133-49d2-4694-8706-55e924ba5f1f@infradead.org>

ugh. Sorry about the accidental resend.



From stefano.radaelli21 at gmail.com  Sun Dec 14 13:42:47 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Sun, 14 Dec 2025 22:42:47 +0100
Subject: [PATCH v3 6/6] arm64: dts: imx8mp-var-som: Add support for
 ADS7846 touchscreen
In-Reply-To: <CAOMZO5AzuZVkD3rTLEDGFpCx0ovtKfzjZtNgGG0uLDXbPkiqRg@mail.gmail.com>
References: <20251214110531.9475-1-stefano.r@variscite.com>
 <20251214110531.9475-7-stefano.r@variscite.com>
 <CAOMZO5AzuZVkD3rTLEDGFpCx0ovtKfzjZtNgGG0uLDXbPkiqRg@mail.gmail.com>
Message-ID: <aT8vV_5cZW99YIB-@Lord-Beerus.station>

Hi Fabio,

> 
> I understand they are both from the same family of touchscreen
> controllers, but shouldn't you use the ti,tsc2046 compatible string
> instead?

thank you very much for the hint, I hadn't noticed that compatible string.
Even though it belongs to the same family and uses the same driver, I will
use the ti,tsc2046 compatible as you suggest, so that it matches the
hardware more accurately.

Best regards,
Stefano



From stefano.radaelli21 at gmail.com  Sun Dec 14 13:52:47 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Sun, 14 Dec 2025 22:52:47 +0100
Subject: [PATCH v4 0/6] arm64: dts: imx8mp-var-som: align DTS with hardware revision
Message-ID: <20251214215256.5812-1-stefano.r@variscite.com>

This patch series aligns the VAR-SOM-MX8MP device tree with the actual
hardware populated on the System-on-Module, and separates SOM-specific
descriptions from carrier-board-specific ones.

The first three patches move the USDHC2 interface, the PCA9534 GPIO
expander, and the UART2 debug console out of the SOM dtsi, as these
components are not present on the VAR-SOM-MX8MP module itself and are
instead routed on the Symphony carrier board. Their descriptions are
therefore provided in the carrier board DTS, keeping the SOM device
tree limited to on-module hardware.

The remaining patches add support for peripherals that are populated
on the SOM and commonly used across designs, including WiFi/Bluetooth
connectivity, the WM8904 audio codec, and the ADS7846 touchscreen
controller.

Overall, this series ensures a clear separation between SOM and carrier
board responsibilities in the device tree, avoids describing
non-existent hardware on the module, and enables key on-module
features.

v4:
 - Change touchscreen label and compatible string to "ti,tsc2046" to
   better match hardware revision
v3:
 - Remove unnecessary status property
v2:
 - Move deleted nodes from SOM dts to Symphony carrier board

Stefano Radaelli (6):
  arm64: dts: imx8mp-var-som: Move USDHC2 support to Symphony carrier
  arm64: dts: imx8mp-var-som: Move PCA9534 GPIO expander to Symphony
    carrier
  arm64: dts: imx8mp-var-som: Move UART2 description to Symphony carrier
  arm64: dts: imx8mp-var-som: Add WiFi and Bluetooth support
  arm64: dts: imx8mp-var-som: Add support for WM8904 audio codec
  arm64: dts: imx8mp-var-som: Add support for TSC2046 touchscreen

 .../dts/freescale/imx8mp-var-som-symphony.dts | 145 ++++++++
 .../boot/dts/freescale/imx8mp-var-som.dtsi    | 331 +++++++++++-------
 2 files changed, 355 insertions(+), 121 deletions(-)


base-commit: cb015814f8b6eebcbb8e46e111d108892c5e6821
-- 
2.47.3



From stefano.radaelli21 at gmail.com  Sun Dec 14 13:52:48 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Sun, 14 Dec 2025 22:52:48 +0100
Subject: [PATCH v4 1/6] arm64: dts: imx8mp-var-som: Move USDHC2 support to Symphony carrier
In-Reply-To: <20251214215256.5812-1-stefano.r@variscite.com>
References: <20251214215256.5812-1-stefano.r@variscite.com>
Message-ID: <20251214215256.5812-2-stefano.r@variscite.com>

The VAR-SOM-MX8MP module does not include a microSD slot connected to
USDHC2. The USDHC2 interface is routed only on the Symphony carrier
board, and it may optionally be used or omitted depending on the
customer's carrier design.

Move the USDHC2 node, its regulators, pinctrl groups and related GPIOs
from the SOM device tree to the Symphony carrier DTS, keeping the SOM
description limited to hardware populated on the module.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../dts/freescale/imx8mp-var-som-symphony.dts | 77 +++++++++++++++++++
 .../boot/dts/freescale/imx8mp-var-som.dtsi    | 75 ------------------
 2 files changed, 77 insertions(+), 75 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts b/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
index 36d3eb865202..ea3c193bb684 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
@@ -8,4 +8,81 @@
 / {
 	model = "Variscite VAR-SOM-MX8M-PLUS on Symphony-Board";
 	compatible = "variscite,var-som-mx8mp-symphony", "variscite,var-som-mx8mp", "fsl,imx8mp";
+
+	reg_usdhc2_vmmc: regulator-usdhc2-vmmc {
+		compatible = "regulator-fixed";
+		regulator-name = "VSD_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpios = <&gpio4 22 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		startup-delay-us = <100>;
+		off-on-delay-us = <12000>;
+	};
+
+	reg_usdhc2_vqmmc: regulator-usdhc2-vqmmc {
+		compatible = "regulator-gpio";
+		regulator-name = "VSD_VSEL";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <3300000>;
+		gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>;
+		states = <3300000 0x0 1800000 0x1>;
+		vin-supply = <&ldo5>;
+	};
+};
+
+/* SD-card */
+&usdhc2 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+	cd-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	vqmmc-supply = <&reg_usdhc2_vqmmc>;
+	bus-width = <4>;
+	status = "okay";
+};
+
+&iomuxc {
+	pinctrl_usdhc2_gpio: usdhc2-gpiogrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14                             0x1c4
+			MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22                               0x10
+			MX8MP_IOMUXC_SD2_CD_B__GPIO2_IO12                               0xc0
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK                                0x190
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD                                0x1d0
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0                            0x1d0
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1                            0x1d0
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2                            0x1d0
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3                            0x1d0
+		>;
+	};
+
+	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK                                0x194
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD                                0x1d4
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0                            0x1d4
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1                            0x1d4
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2                            0x1d4
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3                            0x1d4
+		>;
+	};
+
+	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK                                0x196
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD                                0x1d6
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0                            0x1d6
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1                            0x1d6
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2                            0x1d6
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3                            0x1d6
+		>;
+	};
 };
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
index 29f080904482..949d9878f395 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
@@ -35,27 +35,6 @@ memory at 40000000 {
 		      <0x1 0x00000000 0 0xc0000000>;
 	};
 
-	reg_usdhc2_vmmc: regulator-usdhc2-vmmc {
-	        compatible = "regulator-fixed";
-	        regulator-name = "VSD_3V3";
-	        regulator-min-microvolt = <3300000>;
-	        regulator-max-microvolt = <3300000>;
-	        gpios = <&gpio4 22 GPIO_ACTIVE_HIGH>;
-	        enable-active-high;
-	        startup-delay-us = <100>;
-	        off-on-delay-us = <12000>;
-	};
-
-	reg_usdhc2_vqmmc: regulator-usdhc2-vqmmc {
-		compatible = "regulator-gpio";
-		regulator-name = "VSD_VSEL";
-		regulator-min-microvolt = <1800000>;
-		regulator-max-microvolt = <3300000>;
-		gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>;
-		states = <3300000 0x0 1800000 0x1>;
-		vin-supply = <&ldo5>;
-	};
-
 	reg_phy_supply: regulator-phy-supply {
 		compatible = "regulator-fixed";
 		regulator-name = "phy-supply";
@@ -271,19 +250,6 @@ &uart2 {
         status = "okay";
 };
 
-/* SD-card */
-&usdhc2 {
-        pinctrl-names = "default", "state_100mhz", "state_200mhz";
-        pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
-        pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
-        pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
-        cd-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;
-        vmmc-supply = <&reg_usdhc2_vmmc>;
-	vqmmc-supply = <&reg_usdhc2_vqmmc>;
-        bus-width = <4>;
-        status = "okay";
-};
-
 /* eMMC */
 &usdhc3 {
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
@@ -358,47 +324,6 @@ MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX                            0x40
 		>;
 	};
 
-	pinctrl_usdhc2_gpio: usdhc2-gpiogrp {
-	        fsl,pins = <
-	                MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14                             0x1c4
-	                MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22                               0x10
-	                MX8MP_IOMUXC_SD2_CD_B__GPIO2_IO12                               0xc0
-	        >;
-	};
-
-	pinctrl_usdhc2: usdhc2grp {
-	        fsl,pins = <
-	                MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK                                0x190
-	                MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD                                0x1d0
-	                MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0                            0x1d0
-	                MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1                            0x1d0
-	                MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2                            0x1d0
-	                MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3                            0x1d0
-	        >;
-	};
-
-	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
-	        fsl,pins = <
-	                MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK                                0x194
-	                MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD                                0x1d4
-	                MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0                            0x1d4
-	                MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1                            0x1d4
-	                MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2                            0x1d4
-	                MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3                            0x1d4
-	        >;
-	};
-
-	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
-	        fsl,pins = <
-	                MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK                                0x196
-	                MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD                                0x1d6
-	                MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0                            0x1d6
-	                MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1                            0x1d6
-	                MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2                            0x1d6
-	                MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3                            0x1d6
-	        >;
-	};
-
 	pinctrl_usdhc3: usdhc3grp {
 		fsl,pins = <
 			MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK				0x190
-- 
2.47.3



From stefano.radaelli21 at gmail.com  Sun Dec 14 13:52:49 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Sun, 14 Dec 2025 22:52:49 +0100
Subject: [PATCH v4 2/6] arm64: dts: imx8mp-var-som: Move PCA9534 GPIO expander to Symphony carrier
In-Reply-To: <20251214215256.5812-1-stefano.r@variscite.com>
References: <20251214215256.5812-1-stefano.r@variscite.com>
Message-ID: <20251214215256.5812-3-stefano.r@variscite.com>

The VAR-SOM-MX8MP module does not include the PCA9534 GPIO expander nor
the LED connected to it. These components are present only on the
Symphony carrier board and may vary across custom carrier designs.

Move the PCA9534 GPIO expander node and the associated LED definition
from the SOM device tree to the Symphony carrier DTS, ensuring the SOM
dtsi describes only hardware present on the module.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../dts/freescale/imx8mp-var-som-symphony.dts | 50 +++++++++++++++++++
 .../boot/dts/freescale/imx8mp-var-som.dtsi    | 50 -------------------
 2 files changed, 50 insertions(+), 50 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts b/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
index ea3c193bb684..361e6122bdc3 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
@@ -9,6 +9,16 @@ / {
 	model = "Variscite VAR-SOM-MX8M-PLUS on Symphony-Board";
 	compatible = "variscite,var-som-mx8mp-symphony", "variscite,var-som-mx8mp", "fsl,imx8mp";
 
+	gpio-leds {
+		compatible = "gpio-leds";
+
+		led-0 {
+			function = LED_FUNCTION_POWER;
+			gpios = <&pca9534 0 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+	};
+
 	reg_usdhc2_vmmc: regulator-usdhc2-vmmc {
 		compatible = "regulator-fixed";
 		regulator-name = "VSD_3V3";
@@ -31,6 +41,33 @@ reg_usdhc2_vqmmc: regulator-usdhc2-vqmmc {
 	};
 };
 
+&i2c3 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	status = "okay";
+
+	/* GPIO expander */
+	pca9534: gpio at 20 {
+		compatible = "nxp,pca9534";
+		reg = <0x20>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_pca9534>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <15 IRQ_TYPE_EDGE_FALLING>;
+		wakeup-source;
+
+		usb3-sata-sel-hog {
+			gpio-hog;
+			gpios = <4 0>;
+			output-low;
+			line-name = "usb3_sata_sel";
+		};
+	};
+};
+
 /* SD-card */
 &usdhc2 {
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
@@ -45,6 +82,19 @@ &usdhc2 {
 };
 
 &iomuxc {
+	pinctrl_i2c3: i2c3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL                                 0x400001c2
+			MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA                                 0x400001c2
+		>;
+	};
+
+	pinctrl_pca9534: pca9534grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO15__GPIO1_IO15                             0xc0
+		>;
+	};
+
 	pinctrl_usdhc2_gpio: usdhc2-gpiogrp {
 		fsl,pins = <
 			MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14                             0x1c4
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
index 949d9878f395..158a78ec9656 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
@@ -19,16 +19,6 @@ chosen {
 		stdout-path = &uart2;
 	};
 
-	gpio-leds {
-	        compatible = "gpio-leds";
-
-	        led-0 {
-	                function = LED_FUNCTION_POWER;
-	                gpios = <&pca9534 0 GPIO_ACTIVE_HIGH>;
-	                linux,default-trigger = "heartbeat";
-	        };
-	};
-
 	memory at 40000000 {
 		device_type = "memory";
 		reg = <0x0 0x40000000 0 0xc0000000>,
@@ -216,33 +206,6 @@ ldo5: LDO5 {
 	};
 };
 
-&i2c3 {
-        clock-frequency = <400000>;
-        pinctrl-names = "default";
-        pinctrl-0 = <&pinctrl_i2c3>;
-        status = "okay";
-
-	/* GPIO expander */
-	pca9534: gpio at 20 {
-	        compatible = "nxp,pca9534";
-	        reg = <0x20>;
-	        pinctrl-names = "default";
-	        pinctrl-0 = <&pinctrl_pca9534>;
-	        gpio-controller;
-	        #gpio-cells = <2>;
-	        interrupt-parent = <&gpio1>;
-	        interrupts = <15 IRQ_TYPE_EDGE_FALLING>;
-	        wakeup-source;
-
-	        usb3-sata-sel-hog {
-	                gpio-hog;
-	                gpios = <4 0>;
-	                output-low;
-	                line-name = "usb3_sata_sel";
-	        };
-	};
-};
-
 /* Console */
 &uart2 {
         pinctrl-names = "default";
@@ -298,19 +261,6 @@ MX8MP_IOMUXC_SD1_DATA5__I2C1_SDA				0x400001c2
 		>;
 	};
 
-	pinctrl_i2c3: i2c3grp {
-	        fsl,pins = <
-	                MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL                                 0x400001c2
-	                MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA                                 0x400001c2
-	        >;
-	};
-
-	pinctrl_pca9534: pca9534grp {
-	        fsl,pins = <
-	                MX8MP_IOMUXC_GPIO1_IO15__GPIO1_IO15                             0xc0
-	        >;
-	};
-
 	pinctrl_pmic: pmicgrp {
 		fsl,pins = <
 			MX8MP_IOMUXC_SPDIF_RX__GPIO5_IO04				0x1c0
-- 
2.47.3



From stefano.radaelli21 at gmail.com  Sun Dec 14 13:52:50 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Sun, 14 Dec 2025 22:52:50 +0100
Subject: [PATCH v4 3/6] arm64: dts: imx8mp-var-som: Move UART2 description to Symphony carrier
In-Reply-To: <20251214215256.5812-1-stefano.r@variscite.com>
References: <20251214215256.5812-1-stefano.r@variscite.com>
Message-ID: <20251214215256.5812-4-stefano.r@variscite.com>

The VAR-SOM-MX8MP module does not provide an onboard debug console.
UART2 is routed and exposed only on the Symphony carrier board, while
custom carrier designs may choose to expose a different UART.

Move the UART2 node from the SOM device tree to the
imx8mp-var-som-symphony.dts, keeping the SOM dtsi limited to hardware
present on the module itself.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../dts/freescale/imx8mp-var-som-symphony.dts  | 18 ++++++++++++++++++
 .../boot/dts/freescale/imx8mp-var-som.dtsi     | 18 ------------------
 2 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts b/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
index 361e6122bdc3..291f65e36865 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som-symphony.dts
@@ -9,6 +9,10 @@ / {
 	model = "Variscite VAR-SOM-MX8M-PLUS on Symphony-Board";
 	compatible = "variscite,var-som-mx8mp-symphony", "variscite,var-som-mx8mp", "fsl,imx8mp";
 
+	chosen {
+		stdout-path = &uart2;
+	};
+
 	gpio-leds {
 		compatible = "gpio-leds";
 
@@ -68,6 +72,13 @@ usb3-sata-sel-hog {
 	};
 };
 
+/* Console */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2>;
+	status = "okay";
+};
+
 /* SD-card */
 &usdhc2 {
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
@@ -95,6 +106,13 @@ MX8MP_IOMUXC_GPIO1_IO15__GPIO1_IO15                             0xc0
 		>;
 	};
 
+	pinctrl_uart2: uart2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX                            0x40
+			MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX                            0x40
+		>;
+	};
+
 	pinctrl_usdhc2_gpio: usdhc2-gpiogrp {
 		fsl,pins = <
 			MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14                             0x1c4
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
index 158a78ec9656..5bba91dcef17 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
@@ -15,10 +15,6 @@
 / {
 	model = "Variscite VAR-SOM-MX8M Plus module";
 
-	chosen {
-		stdout-path = &uart2;
-	};
-
 	memory at 40000000 {
 		device_type = "memory";
 		reg = <0x0 0x40000000 0 0xc0000000>,
@@ -206,13 +202,6 @@ ldo5: LDO5 {
 	};
 };
 
-/* Console */
-&uart2 {
-        pinctrl-names = "default";
-        pinctrl-0 = <&pinctrl_uart2>;
-        status = "okay";
-};
-
 /* eMMC */
 &usdhc3 {
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
@@ -267,13 +256,6 @@ MX8MP_IOMUXC_SPDIF_RX__GPIO5_IO04				0x1c0
 		>;
 	};
 
-	pinctrl_uart2: uart2grp {
-	        fsl,pins = <
-		        MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX                            0x40
-			MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX                            0x40
-		>;
-	};
-
 	pinctrl_usdhc3: usdhc3grp {
 		fsl,pins = <
 			MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK				0x190
-- 
2.47.3



From stefano.radaelli21 at gmail.com  Sun Dec 14 13:52:51 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Sun, 14 Dec 2025 22:52:51 +0100
Subject: [PATCH v4 4/6] arm64: dts: imx8mp-var-som: Add WiFi and Bluetooth support
In-Reply-To: <20251214215256.5812-1-stefano.r@variscite.com>
References: <20251214215256.5812-1-stefano.r@variscite.com>
Message-ID: <20251214215256.5812-5-stefano.r@variscite.com>

Add device tree nodes for the WiFi and Bluetooth module mounted on the
VAR-SOM-MX8MP. The module can be based on either the NXP IW612 or IW611
chipset, depending on the configuration chosen by the customer.

Regardless of the chipset used, WiFi communicates over SDIO and Bluetooth
over UART.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../boot/dts/freescale/imx8mp-var-som.dtsi    | 92 +++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
index 5bba91dcef17..2c49d53e30c3 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
@@ -21,6 +21,14 @@ memory at 40000000 {
 		      <0x1 0x00000000 0 0xc0000000>;
 	};
 
+	iw61x_pwrseq: wifi-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		post-power-on-delay-ms = <100>;
+		power-off-delay-us = <10000>;
+		reset-gpios = <&gpio2 8 GPIO_ACTIVE_LOW>, /* WIFI_RESET */
+			      <&gpio2 19 GPIO_ACTIVE_LOW>; /* WIFI_PWR_EN */
+	};
+
 	reg_phy_supply: regulator-phy-supply {
 		compatible = "regulator-fixed";
 		regulator-name = "phy-supply";
@@ -202,6 +210,33 @@ ldo5: LDO5 {
 	};
 };
 
+/* BT */
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart3>, <&pinctrl_bluetooth>;
+	assigned-clocks = <&clk IMX8MP_CLK_UART3>;
+	assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_80M>;
+	uart-has-rtscts;
+	status = "okay";
+
+	bluetooth {
+		compatible = "nxp,88w8987-bt";
+	};
+};
+
+/* WIFI */
+&usdhc1 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc1>, <&pinctrl_wifi>;
+	pinctrl-1 = <&pinctrl_usdhc1_100mhz>, <&pinctrl_wifi>;
+	pinctrl-2 = <&pinctrl_usdhc1_200mhz>, <&pinctrl_wifi>;
+	bus-width = <4>;
+	non-removable;
+	keep-power-in-suspend;
+	mmc-pwrseq = <&iw61x_pwrseq>;
+	status = "okay";
+};
+
 /* eMMC */
 &usdhc3 {
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
@@ -222,6 +257,14 @@ &wdog1 {
 
 &iomuxc {
 
+	pinctrl_bluetooth: bluetoothgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_DATA7__GPIO2_IO09                              0xc0
+			MX8MP_IOMUXC_GPIO1_IO04__GPIO1_IO04                             0xc0
+			MX8MP_IOMUXC_SD1_RESET_B__GPIO2_IO10                            0xc0
+		>;
+	};
+
 	pinctrl_eqos: eqosgrp {
 		fsl,pins = <
 			MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC				0x2
@@ -256,6 +299,48 @@ MX8MP_IOMUXC_SPDIF_RX__GPIO5_IO04				0x1c0
 		>;
 	};
 
+	pinctrl_uart3: uart3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_ECSPI1_SCLK__UART3_DCE_RX                          0x140
+			MX8MP_IOMUXC_ECSPI1_MOSI__UART3_DCE_TX                          0x140
+			MX8MP_IOMUXC_ECSPI1_MISO__UART3_DCE_CTS                         0x140
+			MX8MP_IOMUXC_ECSPI1_SS0__UART3_DCE_RTS                          0x140
+		>;
+	};
+
+	pinctrl_usdhc1: usdhc1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK                                0x190
+			MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD                                0x1d0
+			MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0                            0x1d0
+			MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1                            0x1d0
+			MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2                            0x1d0
+			MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3                            0x1d0
+		>;
+	};
+
+	pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK                                0x194
+			MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD                                0x1d4
+			MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0                            0x1d4
+			MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1                            0x1d4
+			MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2                            0x1d4
+			MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3                            0x1d4
+		>;
+	};
+
+	pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK                                0x196
+			MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD                                0x1d6
+			MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0                            0x1d6
+			MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1                            0x1d6
+			MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2                            0x1d6
+			MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3                            0x1d6
+		>;
+	};
+
 	pinctrl_usdhc3: usdhc3grp {
 		fsl,pins = <
 			MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK				0x190
@@ -309,4 +394,11 @@ pinctrl_wdog: wdoggrp {
 			MX8MP_IOMUXC_GPIO1_IO02__WDOG1_WDOG_B				0xc6
 		>;
 	};
+
+	pinctrl_wifi: wifigrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_DATA6__GPIO2_IO08                              0xc0
+			MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19                            0xc0
+		>;
+	};
 };
-- 
2.47.3



From stefano.radaelli21 at gmail.com  Sun Dec 14 13:52:52 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Sun, 14 Dec 2025 22:52:52 +0100
Subject: [PATCH v4 5/6] arm64: dts: imx8mp-var-som: Add support for WM8904 audio codec
In-Reply-To: <20251214215256.5812-1-stefano.r@variscite.com>
References: <20251214215256.5812-1-stefano.r@variscite.com>
Message-ID: <20251214215256.5812-6-stefano.r@variscite.com>

The VAR-SOM-MX8MP can integrate the WM8904, a high-performance
ultra-low-power stereo codec optimized for portable audio applications.

This patch adds the WM8904 device to the appropriate I2C bus, enables
the SAI peripheral, and introduces the sound node to expose the
sound card to the system.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../boot/dts/freescale/imx8mp-var-som.dtsi    | 94 +++++++++++++++++++
 1 file changed, 94 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
index 2c49d53e30c3..6da5df11c44a 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
@@ -29,6 +29,14 @@ iw61x_pwrseq: wifi-pwrseq {
 			      <&gpio2 19 GPIO_ACTIVE_LOW>; /* WIFI_PWR_EN */
 	};
 
+	reg_audio_supply: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "wm8904-supply";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
 	reg_phy_supply: regulator-phy-supply {
 		compatible = "regulator-fixed";
 		regulator-name = "phy-supply";
@@ -46,6 +54,34 @@ reg_phy_vddio: regulator-phy-vddio {
 		regulator-min-microvolt = <1800000>;
 		regulator-max-microvolt = <1800000>;
 	};
+
+	sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,bitclock-master = <&codec_dai>;
+		simple-audio-card,format = "i2s";
+		simple-audio-card,frame-master = <&codec_dai>;
+		simple-audio-card,mclk-fs = <256>;
+		simple-audio-card,name = "wm8904-audio";
+		simple-audio-card,routing =
+			"Headphone Jack", "HPOUTL",
+			"Headphone Jack", "HPOUTR",
+			"IN2L", "Line In Jack",
+			"IN2R", "Line In Jack",
+			"IN1L", "Microphone Jack",
+			"IN1R", "Microphone Jack";
+		simple-audio-card,widgets =
+			"Microphone", "Microphone Jack",
+			"Headphone", "Headphone Jack",
+			"Line", "Line In Jack";
+
+		codec_dai: simple-audio-card,codec {
+			sound-dai = <&wm8904>;
+		};
+
+		simple-audio-card,cpu {
+			sound-dai = <&sai3>;
+		};
+	};
 };
 
 &A53_0 {
@@ -208,6 +244,52 @@ ldo5: LDO5 {
 			};
 		};
 	};
+
+	wm8904: audio-codec at 1a {
+		compatible = "wlf,wm8904";
+		reg = <0x1a>;
+		#sound-dai-cells = <0>;
+		clocks = <&audio_blk_ctrl IMX8MP_CLK_AUDIOMIX_SAI3_MCLK1>;
+		clock-names = "mclk";
+		AVDD-supply = <&reg_audio_supply>;
+		CPVDD-supply = <&reg_audio_supply>;
+		DBVDD-supply = <&reg_audio_supply>;
+		DCVDD-supply = <&reg_audio_supply>;
+		MICVDD-supply = <&reg_audio_supply>;
+		wlf,drc-cfg-names = "default", "peaklimiter", "tradition",
+				    "soft", "music";
+		/*
+		 * Config registers per name, respectively:
+		 * KNEE_IP = 0,   KNEE_OP = 0,     HI_COMP = 1,   LO_COMP = 1
+		 * KNEE_IP = -24, KNEE_OP = -6,    HI_COMP = 1/4, LO_COMP = 1
+		 * KNEE_IP = -42, KNEE_OP = -3,    HI_COMP = 0,   LO_COMP = 1
+		 * KNEE_IP = -45, KNEE_OP = -9,    HI_COMP = 1/8, LO_COMP = 1
+		 * KNEE_IP = -30, KNEE_OP = -10.5, HI_COMP = 1/4, LO_COMP = 1
+		 */
+		wlf,drc-cfg-regs = /bits/ 16 <0x01af 0x3248 0x0000 0x0000>,
+				   /bits/ 16 <0x04af 0x324b 0x0010 0x0408>,
+				   /bits/ 16 <0x04af 0x324b 0x0028 0x0704>,
+				   /bits/ 16 <0x04af 0x324b 0x0018 0x078c>,
+				   /bits/ 16 <0x04af 0x324b 0x0010 0x050e>;
+		/* GPIO1 = DMIC_CLK, don't touch others */
+		wlf,gpio-cfg = <0x0018>, <0xffff>, <0xffff>, <0xffff>;
+	};
+};
+
+&sai3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_sai3>;
+	assigned-clocks = <&clk IMX8MP_CLK_SAI3>;
+	assigned-clock-parents = <&clk IMX8MP_AUDIO_PLL1_OUT>;
+	assigned-clock-rates = <11536000>;
+	clocks = <&audio_blk_ctrl IMX8MP_CLK_AUDIOMIX_SAI3_IPG>,
+		<&clk IMX8MP_CLK_DUMMY>,
+		<&audio_blk_ctrl IMX8MP_CLK_AUDIOMIX_SAI3_MCLK1>,
+		<&clk IMX8MP_CLK_DUMMY>,
+		<&clk IMX8MP_CLK_DUMMY>;
+	clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
+	fsl,sai-mclk-direction-output;
+	status = "okay";
 };
 
 /* BT */
@@ -299,6 +381,18 @@ MX8MP_IOMUXC_SPDIF_RX__GPIO5_IO04				0x1c0
 		>;
 	};
 
+	pinctrl_sai3: sai3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI3_TXFS__AUDIOMIX_SAI3_TX_SYNC                   0xd6
+			MX8MP_IOMUXC_SAI3_TXC__AUDIOMIX_SAI3_TX_BCLK                    0xd6
+			MX8MP_IOMUXC_SAI3_RXD__AUDIOMIX_SAI3_RX_DATA00                  0xd6
+			MX8MP_IOMUXC_SAI3_TXD__AUDIOMIX_SAI3_TX_DATA00                  0xd6
+			MX8MP_IOMUXC_SAI3_MCLK__AUDIOMIX_SAI3_MCLK                      0xd6
+			MX8MP_IOMUXC_SAI3_RXFS__AUDIOMIX_SAI3_RX_SYNC                   0xd6
+			MX8MP_IOMUXC_SAI3_RXC__AUDIOMIX_SAI3_RX_BCLK                    0xd6
+		>;
+	};
+
 	pinctrl_uart3: uart3grp {
 		fsl,pins = <
 			MX8MP_IOMUXC_ECSPI1_SCLK__UART3_DCE_RX                          0x140
-- 
2.47.3



From stefano.radaelli21 at gmail.com  Sun Dec 14 13:52:53 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Sun, 14 Dec 2025 22:52:53 +0100
Subject: [PATCH v4 6/6] arm64: dts: imx8mp-var-som: Add support for TSC2046 touchscreen
In-Reply-To: <20251214215256.5812-1-stefano.r@variscite.com>
References: <20251214215256.5812-1-stefano.r@variscite.com>
Message-ID: <20251214215256.5812-7-stefano.r@variscite.com>

The VAR-SOM-MX8MP integrates a TSC2046 resistive touchscreen controller.
The controller is physically located on the SOM, and its signals are
routed to the SOM pins, allowing carrier boards to make use of it.

This patch adds the TSC2046 node and the appropriate SPI controller.

Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../boot/dts/freescale/imx8mp-var-som.dtsi    | 46 +++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
index 6da5df11c44a..49467b48d0b0 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi
@@ -100,6 +100,37 @@ &A53_3 {
 	cpu-supply = <&buck2>;
 };
 
+&ecspi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi1>;
+	cs-gpios = <&gpio5 17 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	/* Resistive touch controller */
+	tsc2046: touchscreen at 0 {
+		compatible = "ti,tsc2046";
+		reg = <0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_restouch>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <12 IRQ_TYPE_EDGE_FALLING>;
+		spi-max-frequency = <1500000>;
+		pendown-gpio = <&gpio1 12 GPIO_ACTIVE_LOW>;
+		ti,x-min = /bits/ 16 <125>;
+		ti,x-max = /bits/ 16 <4008>;
+		ti,y-min = /bits/ 16 <282>;
+		ti,y-max = /bits/ 16 <3864>;
+		ti,x-plate-ohms = /bits/ 16 <180>;
+		ti,pressure-max = /bits/ 16 <255>;
+		ti,debounce-max = /bits/ 16 <10>;
+		ti,debounce-tol = /bits/ 16 <3>;
+		ti,debounce-rep = /bits/ 16 <1>;
+		ti,settle-delay-usec = /bits/ 16 <150>;
+		ti,keep-vref-on;
+		wakeup-source;
+	};
+};
+
 &eqos {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_eqos>;
@@ -347,6 +378,15 @@ MX8MP_IOMUXC_SD1_RESET_B__GPIO2_IO10                            0xc0
 		>;
 	};
 
+	pinctrl_ecspi1: ecspi1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C1_SCL__ECSPI1_SCLK                              0x12
+			MX8MP_IOMUXC_I2C1_SDA__ECSPI1_MOSI                              0x12
+			MX8MP_IOMUXC_I2C2_SCL__ECSPI1_MISO                              0x12
+			MX8MP_IOMUXC_I2C2_SDA__GPIO5_IO17                               0x12
+		>;
+	};
+
 	pinctrl_eqos: eqosgrp {
 		fsl,pins = <
 			MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC				0x2
@@ -381,6 +421,12 @@ MX8MP_IOMUXC_SPDIF_RX__GPIO5_IO04				0x1c0
 		>;
 	};
 
+	pinctrl_restouch: restouchgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO12__GPIO1_IO12                             0xc0
+		>;
+	};
+
 	pinctrl_sai3: sai3grp {
 		fsl,pins = <
 			MX8MP_IOMUXC_SAI3_TXFS__AUDIOMIX_SAI3_TX_SYNC                   0xd6
-- 
2.47.3



From francesco at valla.it  Sun Dec 14 14:02:58 2025
From: francesco at valla.it (Francesco Valla)
Date: Sun, 14 Dec 2025 23:02:58 +0100
Subject: [PATCH 3/4] arm64: dts: imx91: Update file name with dash
In-Reply-To: <20251212-imx91-dts-v1-3-2bb3c13762dd@nxp.com>
References: <20251212-imx91-dts-v1-0-2bb3c13762dd@nxp.com>
 <20251212-imx91-dts-v1-3-2bb3c13762dd@nxp.com>
Message-ID: <aT80EhkC41d7BSZs@bywater>

Hi Peng,

On Fri, Dec 12, 2025 at 05:16:09PM +0800, Peng Fan (OSS) wrote:
> From: Peng Fan <peng.fan at nxp.com>
> 
> Update "imx91_93_common.dtsi" to "imx91-93-common.dtsi" to align with
> others.
> 
> Signed-off-by: Peng Fan <peng.fan at nxp.com>
> ---
>  arch/arm64/boot/dts/freescale/imx91.dtsi           |    2 +-
>  arch/arm64/boot/dts/freescale/imx91_93_common.dtsi | 1187 --------------------
>  arch/arm64/boot/dts/freescale/imx93.dtsi           |    2 +-
>  3 files changed, 2 insertions(+), 1189 deletions(-)
>

The new (i.e., renamed) file is not there, so this is not working.

Francesco



From joel-linux at jmay.us  Sun Dec 14 14:12:49 2025
From: joel-linux at jmay.us (Joel May)
Date: Sun, 14 Dec 2025 14:12:49 -0800
Subject: [PATCH] arm64: perf: fix syscalltbl path base
Message-ID: <b2651f20-6f3a-49f5-9cd8-3fb028b2cab5@app.fastmail.com>

From: Joel May <joel-linux at jmay.us>

A fix for the Perf build process was introduced in commit bfb713ea53c74
("perf tools: Fix arm64 build by generating unistd_64.h"), which generates
the unistd_64.h header as necessary.  This fix works fine in some
scenarios.

My problem is when building Perf from tools/perf with SRCARCH=arm64, the
path used in scripts/Makefile.asm-headers is relative to tools/perf
instead of root directory.  This results in the build failing like so.
This snippet is a simplified repro of the problem, see the link to the
TrueNAS SCALE build script to see the problem in context.

  jmay at debian13-aarch64:/mnt/linux/linux-vanilla/tools/perf$ ARCH=arm64 SRCARCH=arm64 make -j1
  ...
  make[4]: *** No rule to make target '/mnt/linux/linux-vanilla/tools/perf/libperf/arch/arm64/include/generated/uapi/asm/unistd_64.h'.  Stop.
  make[3]: *** [Makefile:108: uapi-asm-generic] Error 2
  make[2]: *** [Makefile.perf:972: /mnt/linux/linux-vanilla/tools/perf/libperf/libperf.a] Error 2

The problem is that scripts/Makefile.asm-headers is including a relative
syscalltbl path from arch/arm64/kernel/Makefile.syscalls.  The syscalltbl
path needs to be based on the srctree root.

Fixes: 7fe33e9f662c0 ("arm64: convert unistd_32.h to syscall.tbl format")
Fixes: bfb713ea53c74 ("perf tools: Fix arm64 build by generating unistd_64.h")
Link: https://github.com/truenas/linux/commit/91377b555a57dfa75364d7da85b5e21e41e81625#diff-831a0e8e3eaa7a5ca92599e58771b8a6b2c4bd7533f627e33138873995aac61eR147
Signed-off-by: Joel May <joel-linux at jmay.us>
---
 arch/arm64/kernel/Makefile.syscalls | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/Makefile.syscalls b/arch/arm64/kernel/Makefile.syscalls
index 0542a718871a..958f2335ec1b 100644
--- a/arch/arm64/kernel/Makefile.syscalls
+++ b/arch/arm64/kernel/Makefile.syscalls
@@ -3,4 +3,4 @@
 syscall_abis_32 +=
 syscall_abis_64 += renameat rlimit memfd_secret
 
-syscalltbl = arch/arm64/tools/syscall_%.tbl
+syscalltbl = $(srctree)/arch/arm64/tools/syscall_%.tbl

base-commit: edde060637b92607f3522252c03d64ad06369933
-- 
2.34.1



From devnull+jan.petrous.oss.nxp.com at kernel.org  Sun Dec 14 14:15:40 2025
From: devnull+jan.petrous.oss.nxp.com at kernel.org (Jan Petrous via B4 Relay)
Date: Sun, 14 Dec 2025 23:15:40 +0100
Subject: [PATCH RFC 4/4] stmmac: s32: enable multi irqs mode
In-Reply-To: <20251214-dwmac_multi_irq-v1-0-36562ab0e9f7@oss.nxp.com>
References: <20251214-dwmac_multi_irq-v1-0-36562ab0e9f7@oss.nxp.com>
Message-ID: <20251214-dwmac_multi_irq-v1-4-36562ab0e9f7@oss.nxp.com>

From: "Jan Petrous (OSS)" <jan.petrous at oss.nxp.com>

Signalize support for multi irq mode.

>From now, if yoused old DT node, without channel IRQs set,
the driver fails to init with the following error:

[4.925420] s32-dwmac 4033c000.ethernet eth0: stmmac_request_irq_multi_msi: alloc rx-0  MSI -6 (error: -22)

Signed-off-by: Jan Petrous (OSS) <jan.petrous at oss.nxp.com>
---
 drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c
index 5a485ee98fa7..284e2067a00b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c
@@ -2,7 +2,7 @@
 /*
  * NXP S32G/R GMAC glue layer
  *
- * Copyright 2019-2024 NXP
+ * Copyright 2019-2025 NXP
  *
  */
 
@@ -149,6 +149,7 @@ static int s32_dwmac_probe(struct platform_device *pdev)
 	plat->core_type = DWMAC_CORE_GMAC4;
 	plat->pmt = 1;
 	plat->flags |= STMMAC_FLAG_SPH_DISABLE;
+	plat->flags |= STMMAC_FLAG_MULTI_MSI_EN;
 	plat->rx_fifo_size = 20480;
 	plat->tx_fifo_size = 20480;
 

-- 
2.47.0




From devnull+jan.petrous.oss.nxp.com at kernel.org  Sun Dec 14 14:15:39 2025
From: devnull+jan.petrous.oss.nxp.com at kernel.org (Jan Petrous via B4 Relay)
Date: Sun, 14 Dec 2025 23:15:39 +0100
Subject: [PATCH RFC 3/4] arm64: dts: s32: set Ethernet channel irqs
In-Reply-To: <20251214-dwmac_multi_irq-v1-0-36562ab0e9f7@oss.nxp.com>
References: <20251214-dwmac_multi_irq-v1-0-36562ab0e9f7@oss.nxp.com>
Message-ID: <20251214-dwmac_multi_irq-v1-3-36562ab0e9f7@oss.nxp.com>

From: "Jan Petrous (OSS)" <jan.petrous at oss.nxp.com>

The GMAC Ethernet controller found on S32G2/S32G3 and S32R45
contains up to 5 RX and 5 TX channels.
It can operate in two interrupt modes:

  1) Sharing irq mode: only one irq line is used
     for all channels.

  2) Multiple irq mode: every channel uses two irq lines,
     one for RX and second for TX.

Specify all irq twins for all channels.

Signed-off-by: Jan Petrous (OSS) <jan.petrous at oss.nxp.com>
---
 arch/arm64/boot/dts/freescale/s32g2.dtsi | 24 ++++++++++++++++++++++--
 arch/arm64/boot/dts/freescale/s32g3.dtsi | 24 ++++++++++++++++++++++--
 2 files changed, 44 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/s32g2.dtsi b/arch/arm64/boot/dts/freescale/s32g2.dtsi
index 51d00dac12de..ea615fc5ccd9 100644
--- a/arch/arm64/boot/dts/freescale/s32g2.dtsi
+++ b/arch/arm64/boot/dts/freescale/s32g2.dtsi
@@ -732,8 +732,28 @@ gmac0: ethernet at 4033c000 {
 			reg = <0x4033c000 0x2000>, /* gmac IP */
 			      <0x4007c004 0x4>;    /* GMAC_0_CTRL_STS */
 			interrupt-parent = <&gic>;
-			interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
-			interrupt-names = "macirq";
+			interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
+				     /* CHN 0: tx, rx */
+				     <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>,
+				     /* CHN 1: tx, rx */
+				     <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>,
+				     /* CHN 2: tx, rx */
+				     <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>,
+				     /* CHN 3: tx, rx */
+				     <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
+				     /* CHN 4: tx, rx */
+				     <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "macirq",
+					  "tx-queue-0", "rx-queue-0",
+					  "tx-queue-1", "rx-queue-1",
+					  "tx-queue-2", "rx-queue-2",
+					  "tx-queue-3", "rx-queue-3",
+					  "tx-queue-4", "rx-queue-4";
 			snps,mtl-rx-config = <&mtl_rx_setup>;
 			snps,mtl-tx-config = <&mtl_tx_setup>;
 			status = "disabled";
diff --git a/arch/arm64/boot/dts/freescale/s32g3.dtsi b/arch/arm64/boot/dts/freescale/s32g3.dtsi
index eff7673e7f34..ecbec49c7344 100644
--- a/arch/arm64/boot/dts/freescale/s32g3.dtsi
+++ b/arch/arm64/boot/dts/freescale/s32g3.dtsi
@@ -809,8 +809,28 @@ gmac0: ethernet at 4033c000 {
 			reg = <0x4033c000 0x2000>, /* gmac IP */
 			      <0x4007c004 0x4>;    /* GMAC_0_CTRL_STS */
 			interrupt-parent = <&gic>;
-			interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
-			interrupt-names = "macirq";
+			interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
+				     /* CHN 0: tx, rx */
+				     <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>,
+				     /* CHN 1: tx, rx */
+				     <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>,
+				     /* CHN 2: tx, rx */
+				     <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>,
+				     /* CHN 3: tx, rx */
+				     <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
+				     /* CHN 4: tx, rx */
+				     <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "macirq",
+					  "tx-queue-0", "rx-queue-0",
+					  "tx-queue-1", "rx-queue-1",
+					  "tx-queue-2", "rx-queue-2",
+					  "tx-queue-3", "rx-queue-3",
+					  "tx-queue-4", "rx-queue-4";
 			snps,mtl-rx-config = <&mtl_rx_setup>;
 			snps,mtl-tx-config = <&mtl_tx_setup>;
 			status = "disabled";

-- 
2.47.0




From devnull+jan.petrous.oss.nxp.com at kernel.org  Sun Dec 14 14:15:37 2025
From: devnull+jan.petrous.oss.nxp.com at kernel.org (Jan Petrous via B4 Relay)
Date: Sun, 14 Dec 2025 23:15:37 +0100
Subject: [PATCH RFC 1/4] net: stmmac: platform: read channels irq
In-Reply-To: <20251214-dwmac_multi_irq-v1-0-36562ab0e9f7@oss.nxp.com>
References: <20251214-dwmac_multi_irq-v1-0-36562ab0e9f7@oss.nxp.com>
Message-ID: <20251214-dwmac_multi_irq-v1-1-36562ab0e9f7@oss.nxp.com>

From: "Jan Petrous (OSS)" <jan.petrous at oss.nxp.com>

Read IRQ resources for all channels, to allow multi IRQ mode
for platform glue drivers.

Signed-off-by: Jan Petrous (OSS) <jan.petrous at oss.nxp.com>
---
 .../net/ethernet/stmicro/stmmac/stmmac_platform.c  | 38 +++++++++++++++++++++-
 1 file changed, 37 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 8979a50b5507..29e40253bdfe 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -700,6 +700,9 @@ EXPORT_SYMBOL_GPL(stmmac_pltfr_find_clk);
 int stmmac_get_platform_resources(struct platform_device *pdev,
 				  struct stmmac_resources *stmmac_res)
 {
+	int i;
+	char name[8];
+
 	memset(stmmac_res, 0, sizeof(*stmmac_res));
 
 	/* Get IRQ information early to have an ability to ask for deferred
@@ -743,7 +746,40 @@ int stmmac_get_platform_resources(struct platform_device *pdev,
 
 	stmmac_res->addr = devm_platform_ioremap_resource(pdev, 0);
 
-	return PTR_ERR_OR_ZERO(stmmac_res->addr);
+	if (IS_ERR(stmmac_res->addr))
+		return PTR_ERR(stmmac_res->addr);
+
+	/* RX channels irq */
+	for (i = 0; i < MTL_MAX_RX_QUEUES; i++) {
+		scnprintf(name, 8, "rx-queue-%d", i);
+		stmmac_res->rx_irq[i] = platform_get_irq_byname_optional(pdev,
+									 name);
+		if (stmmac_res->rx_irq[i] < 0) {
+			if (stmmac_res->rx_irq[i] == -EPROBE_DEFER)
+				return -EPROBE_DEFER;
+			dev_dbg(&pdev->dev, "IRQ rx-queue-%d not found\n", i);
+
+			/* Stop on first unset rx-queue-%i property member */
+			break;
+		}
+	}
+
+	/* TX channels irq */
+	for (i = 0; i < MTL_MAX_TX_QUEUES; i++) {
+		scnprintf(name, 8, "tx-queue-%d", i);
+		stmmac_res->tx_irq[i] = platform_get_irq_byname_optional(pdev,
+									 name);
+		if (stmmac_res->tx_irq[i] < 0) {
+			if (stmmac_res->tx_irq[i] == -EPROBE_DEFER)
+				return -EPROBE_DEFER;
+			dev_dbg(&pdev->dev, "IRQ tx-queue-%d not found\n", i);
+
+			/* Stop on first unset tx-queue-%i property member */
+			break;
+		}
+	}
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(stmmac_get_platform_resources);
 

-- 
2.47.0




From devnull+jan.petrous.oss.nxp.com at kernel.org  Sun Dec 14 14:15:36 2025
From: devnull+jan.petrous.oss.nxp.com at kernel.org (Jan Petrous via B4 Relay)
Date: Sun, 14 Dec 2025 23:15:36 +0100
Subject: [PATCH RFC 0/4] Support multi-channel IRQs in stmmac platform
 drivers
Message-ID: <20251214-dwmac_multi_irq-v1-0-36562ab0e9f7@oss.nxp.com>

The stmmac core supports two interrupt modes, controlled by the
flag STMMAC_FLAG_MULTI_MSI_EN.
- When the flag is set, the driver uses multi-channel IRQ mode (multi-IRQ).
- Otherwise, a single IRQ line is requested:

static int stmmac_request_irq(struct net_device *dev)
{
        /* Request the IRQ lines */
        if (priv->plat->flags & STMMAC_FLAG_MULTI_MSI_EN)
                ret = stmmac_request_irq_multi_msi(dev);
        else
                ret = stmmac_request_irq_single(dev);
}

At present, only PCI drivers (Intel and Loongson) make use of the multi-IRQ
mode. This concept can be extended to DT-based embedded glue drivers
(dwmac-xxx.c).

This series adds support for reading per-channel IRQs from the DT node and
reuses the existing STMMAC_FLAG_MULTI_MSI_EN flag to enable multi-IRQ
operation in platform drivers.

NXP S32G2/S32G3/S32R SoCs integrate the DWMAC IP with multi-channel
interrupt support. The dwmac-s32.c driver change is provided as an example of
enabling multi-IRQ mode for non-PCI drivers.

An open question remains: should platform drivers support both single-IRQ
and multi-IRQ modes, or should multi-IRQ be required with the DT node
specifying all channel interrupts? The current RFC implementation follows
the latter approach ? dwmac-s32 requires IRQs to be defined for all
channels.

So, when the glue driver has set the flag, but the corresponding DT node
has not expanded 'interrupts' property accordingly, the driver init
fails with the following error:

[4.925420] s32-dwmac 4033c000.ethernet eth0: stmmac_request_irq_multi_msi: alloc rx-0  MSI -6 (error: -22)

When correctly set, the assigned IRQs can be visible
in /proc/interrupts:

root at s32g399aevb3:~# grep eth /proc/interrupts
 29:          0          0          0          0          0          0          0          0    GICv3  89 Level     eth0:mac
 30:          0          0          0          0          0          0          0          0    GICv3  91 Level     eth0:rx-0
 31:          0          0          0          0          0          0          0          0    GICv3  93 Level     eth0:rx-1
 32:          0          0          0          0          0          0          0          0    GICv3  95 Level     eth0:rx-2
 33:          0          0          0          0          0          0          0          0    GICv3  97 Level     eth0:rx-3
 34:          0          0          0          0          0          0          0          0    GICv3  99 Level     eth0:rx-4
 35:          0          0          0          0          0          0          0          0    GICv3  90 Level     eth0:tx-0
 36:          0          0          0          0          0          0          0          0    GICv3  92 Level     eth0:tx-1
 37:          0          0          0          0          0          0          0          0    GICv3  94 Level     eth0:tx-2
 38:          0          0          0          0          0          0          0          0    GICv3  96 Level     eth0:tx-3
 39:          0          0          0          0          0          0          0          0    GICv3  98 Level     eth0:tx-4

Signed-off-by: Jan Petrous (OSS) <jan.petrous at oss.nxp.com>
---
Jan Petrous (OSS) (4):
      net: stmmac: platform: read channels irq
      dt-bindings: net: nxp,s32-dwmac: Declare per-queue interrupts
      arm64: dts: s32: set Ethernet channel irqs
      stmmac: s32: enable multi irqs mode

 .../devicetree/bindings/net/nxp,s32-dwmac.yaml     | 40 +++++++++++++++++++---
 arch/arm64/boot/dts/freescale/s32g2.dtsi           | 24 +++++++++++--
 arch/arm64/boot/dts/freescale/s32g3.dtsi           | 24 +++++++++++--
 drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c    |  3 +-
 .../net/ethernet/stmicro/stmmac/stmmac_platform.c  | 38 +++++++++++++++++++-
 5 files changed, 119 insertions(+), 10 deletions(-)
---
base-commit: cb015814f8b6eebcbb8e46e111d108892c5e6821
change-id: 20251209-dwmac_multi_irq-9d8f60462cc1

Best regards,
-- 
Jan Petrous (OSS) <jan.petrous at oss.nxp.com>




From devnull+jan.petrous.oss.nxp.com at kernel.org  Sun Dec 14 14:15:38 2025
From: devnull+jan.petrous.oss.nxp.com at kernel.org (Jan Petrous via B4 Relay)
Date: Sun, 14 Dec 2025 23:15:38 +0100
Subject: [PATCH RFC 2/4] dt-bindings: net: nxp,s32-dwmac: Declare per-queue
 interrupts
In-Reply-To: <20251214-dwmac_multi_irq-v1-0-36562ab0e9f7@oss.nxp.com>
References: <20251214-dwmac_multi_irq-v1-0-36562ab0e9f7@oss.nxp.com>
Message-ID: <20251214-dwmac_multi_irq-v1-2-36562ab0e9f7@oss.nxp.com>

From: "Jan Petrous (OSS)" <jan.petrous at oss.nxp.com>

The DWMAC IP on supported SoCs has connected queue-based IRQ lines.

Signed-off-by: Jan Petrous (OSS) <jan.petrous at oss.nxp.com>
---
 .../devicetree/bindings/net/nxp,s32-dwmac.yaml     | 40 +++++++++++++++++++---
 1 file changed, 36 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/nxp,s32-dwmac.yaml b/Documentation/devicetree/bindings/net/nxp,s32-dwmac.yaml
index 2b8b74c5feec..b5e42fa49110 100644
--- a/Documentation/devicetree/bindings/net/nxp,s32-dwmac.yaml
+++ b/Documentation/devicetree/bindings/net/nxp,s32-dwmac.yaml
@@ -33,10 +33,22 @@ properties:
       - description: GMAC PHY mode control register
 
   interrupts:
-    maxItems: 1
+    minItems: 11
+    maxItems: 11
 
   interrupt-names:
-    const: macirq
+    - items:
+        - const: macirq
+        - const: rx-queue-0
+        - const: tx-queue-0
+        - const: rx-queue-1
+        - const: tx-queue-1
+        - const: rx-queue-2
+        - const: tx-queue-2
+        - const: rx-queue-3
+        - const: tx-queue-3
+        - const: rx-queue-4
+        - const: tx-queue-4
 
   clocks:
     items:
@@ -75,8 +87,28 @@ examples:
         reg = <0x0 0x4033c000 0x0 0x2000>, /* gmac IP */
               <0x0 0x4007c004 0x0 0x4>;    /* GMAC_0_CTRL_STS */
         interrupt-parent = <&gic>;
-        interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
-        interrupt-names = "macirq";
+        interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
+                     /* CHN 0: tx, rx */
+                     <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>,
+                     /* CHN 1: tx, rx */
+                     <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>,
+                     /* CHN 2: tx, rx */
+                     <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>,
+                     /* CHN 3: tx, rx */
+                     <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
+                     /* CHN 4: tx, rx */
+                     <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
+        interrupt-names = "macirq",
+                          "tx-queue-0", "rx-queue-0",
+                          "tx-queue-1", "rx-queue-1",
+                          "tx-queue-2", "rx-queue-2",
+                          "tx-queue-3", "rx-queue-3",
+                          "tx-queue-4", "rx-queue-4",
         snps,mtl-rx-config = <&mtl_rx_setup>;
         snps,mtl-tx-config = <&mtl_tx_setup>;
         clocks = <&clks 24>, <&clks 17>, <&clks 16>, <&clks 15>;

-- 
2.47.0




From andrew at lunn.ch  Sun Dec 14 14:30:43 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Sun, 14 Dec 2025 23:30:43 +0100
Subject: [PATCH RFC 1/4] net: stmmac: platform: read channels irq
In-Reply-To: <20251214-dwmac_multi_irq-v1-1-36562ab0e9f7@oss.nxp.com>
References: <20251214-dwmac_multi_irq-v1-0-36562ab0e9f7@oss.nxp.com>
 <20251214-dwmac_multi_irq-v1-1-36562ab0e9f7@oss.nxp.com>
Message-ID: <b9c8580f-e615-4eaa-8878-2fb8d888c0aa@lunn.ch>

On Sun, Dec 14, 2025 at 11:15:37PM +0100, Jan Petrous via B4 Relay wrote:
> From: "Jan Petrous (OSS)" <jan.petrous at oss.nxp.com>
> 
> Read IRQ resources for all channels, to allow multi IRQ mode
> for platform glue drivers.
> 
> Signed-off-by: Jan Petrous (OSS) <jan.petrous at oss.nxp.com>
> ---
>  .../net/ethernet/stmicro/stmmac/stmmac_platform.c  | 38 +++++++++++++++++++++-
>  1 file changed, 37 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
> index 8979a50b5507..29e40253bdfe 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
> @@ -700,6 +700,9 @@ EXPORT_SYMBOL_GPL(stmmac_pltfr_find_clk);
>  int stmmac_get_platform_resources(struct platform_device *pdev,
>  				  struct stmmac_resources *stmmac_res)
>  {
> +	int i;
> +	char name[8];

Reverse Christmas tree please.

>  	memset(stmmac_res, 0, sizeof(*stmmac_res));
>  
>  	/* Get IRQ information early to have an ability to ask for deferred
> @@ -743,7 +746,40 @@ int stmmac_get_platform_resources(struct platform_device *pdev,
>  
>  	stmmac_res->addr = devm_platform_ioremap_resource(pdev, 0);
>  
> -	return PTR_ERR_OR_ZERO(stmmac_res->addr);
> +	if (IS_ERR(stmmac_res->addr))
> +		return PTR_ERR(stmmac_res->addr);
> +
> +	/* RX channels irq */
> +	for (i = 0; i < MTL_MAX_RX_QUEUES; i++) {
> +		scnprintf(name, 8, "rx-queue-%d", i);

It would be better to use sizeof(name), not 8.

Also, 'rx-queue-' is 9 characters. So i don't see how this can
actually work?

	Andrew


From smostafa at google.com  Sun Dec 14 14:32:35 2025
From: smostafa at google.com (Mostafa Saleh)
Date: Sun, 14 Dec 2025 22:32:35 +0000
Subject: [PATCH rc v3 1/4] iommu/arm-smmu-v3: Add ignored bits to fix STE
 update sequence
In-Reply-To: <cc0d4ab571e2e789ee1cddfa035379dc54f0601b.1765334526.git.nicolinc@nvidia.com>
References: <cover.1765334526.git.nicolinc@nvidia.com>
 <cc0d4ab571e2e789ee1cddfa035379dc54f0601b.1765334526.git.nicolinc@nvidia.com>
Message-ID: <aT87A1ur4htPjM5T@google.com>

Hi Nicolin,

On Tue, Dec 09, 2025 at 06:45:16PM -0800, Nicolin Chen wrote:
> From: Jason Gunthorpe <jgg at nvidia.com>
> 
> C_BAD_STE was observed when updating nested STE from an S1-bypass mode to
> an S1DSS-bypass mode. As both modes enabled S2, the used bit is slightly
> different than the normal S1-bypass and S1DSS-bypass modes. As a result,
> fields like MEV and EATS in S2's used list marked the word1 as a critical
> word that requested a STE.V=0. This breaks a hitless update.
> 
> However, both MEV and EATS aren't critical in terms of STE update. One
> controls the merge of the events and the other controls the ATS that is
> managed by the driver at the same time via pci_enable_ats().
> 
> Add an arm_smmu_get_ste_ignored() to allow STE update algorithm to ignore
> those fields, avoiding the STE update breakages.
> 
> Note that this change is required by both MEV and EATS fields, which were
> introduced in different kernel versions. So add this get_ignored() first.
> The MEV and EATS will be added in arm_smmu_get_ste_ignored() separately.
> 
> Fixes: 1e8be08d1c91 ("iommu/arm-smmu-v3: Support IOMMU_DOMAIN_NESTED")
> Cc: stable at vger.kernel.org
> Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
> Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
> Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
> ---
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  2 ++
>  .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  | 19 ++++++++++++---
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 24 +++++++++++++++----
>  3 files changed, 37 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> index ae23aacc3840..d5f0e5407b9f 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> @@ -900,6 +900,7 @@ struct arm_smmu_entry_writer {
>  
>  struct arm_smmu_entry_writer_ops {
>  	void (*get_used)(const __le64 *entry, __le64 *used);
> +	void (*get_ignored)(__le64 *ignored_bits);
>  	void (*sync)(struct arm_smmu_entry_writer *writer);
>  };
>  
> @@ -911,6 +912,7 @@ void arm_smmu_make_s2_domain_ste(struct arm_smmu_ste *target,
>  
>  #if IS_ENABLED(CONFIG_KUNIT)
>  void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits);
> +void arm_smmu_get_ste_ignored(__le64 *ignored_bits);
>  void arm_smmu_write_entry(struct arm_smmu_entry_writer *writer, __le64 *cur,
>  			  const __le64 *target);
>  void arm_smmu_get_cd_used(const __le64 *ent, __le64 *used_bits);
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> index d2671bfd3798..3556e65cf9ac 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> @@ -38,13 +38,16 @@ enum arm_smmu_test_master_feat {
>  static bool arm_smmu_entry_differs_in_used_bits(const __le64 *entry,
>  						const __le64 *used_bits,
>  						const __le64 *target,
> +						const __le64 *ignored,
>  						unsigned int length)
>  {
>  	bool differs = false;
>  	unsigned int i;
>  
>  	for (i = 0; i < length; i++) {
> -		if ((entry[i] & used_bits[i]) != target[i])
> +		__le64 used = used_bits[i] & ~ignored[i];
> +
> +		if ((entry[i] & used) != (target[i] & used))
>  			differs = true;
>  	}
>  	return differs;
> @@ -56,12 +59,18 @@ arm_smmu_test_writer_record_syncs(struct arm_smmu_entry_writer *writer)
>  	struct arm_smmu_test_writer *test_writer =
>  		container_of(writer, struct arm_smmu_test_writer, writer);
>  	__le64 *entry_used_bits;
> +	__le64 *ignored;
>  
>  	entry_used_bits = kunit_kzalloc(
>  		test_writer->test, sizeof(*entry_used_bits) * NUM_ENTRY_QWORDS,
>  		GFP_KERNEL);
>  	KUNIT_ASSERT_NOT_NULL(test_writer->test, entry_used_bits);
>  
> +	ignored = kunit_kzalloc(test_writer->test,
> +				sizeof(*ignored) * NUM_ENTRY_QWORDS,
> +				GFP_KERNEL);
> +	KUNIT_ASSERT_NOT_NULL(test_writer->test, ignored);
> +
>  	pr_debug("STE value is now set to: ");
>  	print_hex_dump_debug("    ", DUMP_PREFIX_NONE, 16, 8,
>  			     test_writer->entry,
> @@ -79,14 +88,17 @@ arm_smmu_test_writer_record_syncs(struct arm_smmu_entry_writer *writer)
>  		 * configuration.
>  		 */
>  		writer->ops->get_used(test_writer->entry, entry_used_bits);
> +		if (writer->ops->get_ignored)
> +			writer->ops->get_ignored(ignored);
>  		KUNIT_EXPECT_FALSE(
>  			test_writer->test,
>  			arm_smmu_entry_differs_in_used_bits(
>  				test_writer->entry, entry_used_bits,
> -				test_writer->init_entry, NUM_ENTRY_QWORDS) &&
> +				test_writer->init_entry, ignored,
> +				NUM_ENTRY_QWORDS) &&
>  				arm_smmu_entry_differs_in_used_bits(
>  					test_writer->entry, entry_used_bits,
> -					test_writer->target_entry,
> +					test_writer->target_entry, ignored,
>  					NUM_ENTRY_QWORDS));
>  	}
>  }
> @@ -106,6 +118,7 @@ arm_smmu_v3_test_debug_print_used_bits(struct arm_smmu_entry_writer *writer,
>  static const struct arm_smmu_entry_writer_ops test_ste_ops = {
>  	.sync = arm_smmu_test_writer_record_syncs,
>  	.get_used = arm_smmu_get_ste_used,
> +	.get_ignored = arm_smmu_get_ste_ignored,
>  };
>  
>  static const struct arm_smmu_entry_writer_ops test_cd_ops = {
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index d16d35c78c06..e22c0890041b 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -1082,6 +1082,12 @@ void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits)
>  }
>  EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_used);
>  
> +VISIBLE_IF_KUNIT
> +void arm_smmu_get_ste_ignored(__le64 *ignored_bits)
> +{
> +}
> +EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_ignored);
> +
>  /*
>   * Figure out if we can do a hitless update of entry to become target. Returns a
>   * bit mask where 1 indicates that qword needs to be set disruptively.
> @@ -1094,13 +1100,22 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
>  {
>  	__le64 target_used[NUM_ENTRY_QWORDS] = {};
>  	__le64 cur_used[NUM_ENTRY_QWORDS] = {};
> +	__le64 ignored[NUM_ENTRY_QWORDS] = {};

I think we can avoid extra stack allocation for another STE, if we make
the function update cur_used directly, but no strong opinion.

>  	u8 used_qword_diff = 0;
>  	unsigned int i;
>  
>  	writer->ops->get_used(entry, cur_used);
>  	writer->ops->get_used(target, target_used);
> +	if (writer->ops->get_ignored)
> +		writer->ops->get_ignored(ignored);
>  
>  	for (i = 0; i != NUM_ENTRY_QWORDS; i++) {
> +		/*
> +		 * Ignored is only used for bits that are used by both entries,
> +		 * otherwise it is sequenced according to the unused entry.
> +		 */
> +		ignored[i] &= target_used[i] & cur_used[i];
> +
>  		/*
>  		 * Check that masks are up to date, the make functions are not
>  		 * allowed to set a bit to 1 if the used function doesn't say it
> @@ -1109,6 +1124,7 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
>  		WARN_ON_ONCE(target[i] & ~target_used[i]);
>  
>  		/* Bits can change because they are not currently being used */
> +		cur_used[i] &= ~ignored[i];
>  		unused_update[i] = (entry[i] & cur_used[i]) |
>  				   (target[i] & ~cur_used[i]);
>  		/*
> @@ -1207,12 +1223,9 @@ void arm_smmu_write_entry(struct arm_smmu_entry_writer *writer, __le64 *entry,
>  		entry_set(writer, entry, target, 0, 1);
>  	} else {
>  		/*
> -		 * No inuse bit changed. Sanity check that all unused bits are 0
> -		 * in the entry. The target was already sanity checked by
> -		 * compute_qword_diff().
> +		 * No inuse bit changed, though ignored bits may have changed.
>  		 */
> -		WARN_ON_ONCE(
> -			entry_set(writer, entry, target, 0, NUM_ENTRY_QWORDS));
> +		entry_set(writer, entry, target, 0, NUM_ENTRY_QWORDS);

After this change, no other caller uses the entry_set() return value, so it
can be changed to return void.

>  	}
>  }
>  EXPORT_SYMBOL_IF_KUNIT(arm_smmu_write_entry);
> @@ -1543,6 +1556,7 @@ static void arm_smmu_ste_writer_sync_entry(struct arm_smmu_entry_writer *writer)
>  static const struct arm_smmu_entry_writer_ops arm_smmu_ste_writer_ops = {
>  	.sync = arm_smmu_ste_writer_sync_entry,
>  	.get_used = arm_smmu_get_ste_used,
> +	.get_ignored = arm_smmu_get_ste_ignored,
>  };
>  

I have some mixed feelings about this, having get_used(), then get_ignored()
with the same bits set seems confusing to me, specially the get_ignored()
loops back to update cur_used, which is set from get_used()

My initial though was just to remove this bit from get_used() + some changes
to checks setting bits that are not used would be enough, and the semantics
of get_used() can be something as:
?Return bits used by the updated translation regime that MUST be observed
atomically? and in that case we can ignore things as MEV as it doesn?t
impact the translation.

However, this approach makes it a bit explicit which bits are ignored, if we
keep this logic, I think changing the name of get_ignored() might help, to
something as "get_allowed_break()" or "get_update_safe()"?

Thanks,
Mostafa

>  static void arm_smmu_write_ste(struct arm_smmu_master *master, u32 sid,
> -- 
> 2.43.0
> 


From andrew at lunn.ch  Sun Dec 14 14:33:29 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Sun, 14 Dec 2025 23:33:29 +0100
Subject: [PATCH RFC 0/4] Support multi-channel IRQs in stmmac platform
 drivers
In-Reply-To: <20251214-dwmac_multi_irq-v1-0-36562ab0e9f7@oss.nxp.com>
References: <20251214-dwmac_multi_irq-v1-0-36562ab0e9f7@oss.nxp.com>
Message-ID: <39430c2b-9430-46c3-8087-5381782a5b01@lunn.ch>

On Sun, Dec 14, 2025 at 11:15:36PM +0100, Jan Petrous via B4 Relay wrote:
> The stmmac core supports two interrupt modes, controlled by the
> flag STMMAC_FLAG_MULTI_MSI_EN.
> - When the flag is set, the driver uses multi-channel IRQ mode (multi-IRQ).
> - Otherwise, a single IRQ line is requested:
> 
> static int stmmac_request_irq(struct net_device *dev)
> {
>         /* Request the IRQ lines */
>         if (priv->plat->flags & STMMAC_FLAG_MULTI_MSI_EN)
>                 ret = stmmac_request_irq_multi_msi(dev);
>         else
>                 ret = stmmac_request_irq_single(dev);
> }
> 
> At present, only PCI drivers (Intel and Loongson) make use of the multi-IRQ
> mode. This concept can be extended to DT-based embedded glue drivers
> (dwmac-xxx.c).
> 
> This series adds support for reading per-channel IRQs from the DT node and
> reuses the existing STMMAC_FLAG_MULTI_MSI_EN flag to enable multi-IRQ
> operation in platform drivers.
> 
> NXP S32G2/S32G3/S32R SoCs integrate the DWMAC IP with multi-channel
> interrupt support. The dwmac-s32.c driver change is provided as an example of
> enabling multi-IRQ mode for non-PCI drivers.
> 
> An open question remains: should platform drivers support both single-IRQ
> and multi-IRQ modes, or should multi-IRQ be required with the DT node
> specifying all channel interrupts? The current RFC implementation follows
> the latter approach ? dwmac-s32 requires IRQs to be defined for all
> channels.

You need to consider backwards compatibility. Will an old DT blob
continue to work after this change?

	Andrew


From andrew at lunn.ch  Sun Dec 14 14:37:51 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Sun, 14 Dec 2025 23:37:51 +0100
Subject: [PATCH RFC 4/4] stmmac: s32: enable multi irqs mode
In-Reply-To: <20251214-dwmac_multi_irq-v1-4-36562ab0e9f7@oss.nxp.com>
References: <20251214-dwmac_multi_irq-v1-0-36562ab0e9f7@oss.nxp.com>
 <20251214-dwmac_multi_irq-v1-4-36562ab0e9f7@oss.nxp.com>
Message-ID: <d1eba807-c45d-434f-b272-ed0841c728bf@lunn.ch>

On Sun, Dec 14, 2025 at 11:15:40PM +0100, Jan Petrous via B4 Relay wrote:
> From: "Jan Petrous (OSS)" <jan.petrous at oss.nxp.com>
> 
> Signalize support for multi irq mode.
> 
> >From now, if yoused old DT node, without channel IRQs set,
> the driver fails to init with the following error:
> 
> [4.925420] s32-dwmac 4033c000.ethernet eth0: stmmac_request_irq_multi_msi: alloc rx-0  MSI -6 (error: -22)

Sorry, but that is not acceptable. You cannot break old DT blobs.

Please reverse the logic. If you find all the needed properties in DT
enable STMMAC_FLAG_MULTI_MSI_EN. If none of the properties are there,
continue using one interrupt, and if only some of the needed
properties are there but some are missing, then you can error out with
EINVAL, because the DT blob is invalid.

	Andrew


From lkp at intel.com  Sun Dec 14 16:15:42 2025
From: lkp at intel.com (kernel test robot)
Date: Mon, 15 Dec 2025 01:15:42 +0100
Subject: [PATCH 31/32] Documentation: KVM: Introduce documentation for
 VGICv5
In-Reply-To: <20251212152215.675767-32-sascha.bischoff@arm.com>
References: <20251212152215.675767-32-sascha.bischoff@arm.com>
Message-ID: <202512150153.QbgdGdcn-lkp@intel.com>

Hi Sascha,

kernel test robot noticed the following build warnings:

[auto build test WARNING on linus/master]
[also build test WARNING on v6.19-rc1 next-20251212]
[cannot apply to kvmarm/next arm64/for-next/core kvm/queue kvm/next kvm/linux-next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Sascha-Bischoff/KVM-arm64-Account-for-RES1-bits-in-DECLARE_FEAT_MAP-and-co/20251212-233140
base:   linus/master
patch link:    https://lore.kernel.org/r/20251212152215.675767-32-sascha.bischoff%40arm.com
patch subject: [PATCH 31/32] Documentation: KVM: Introduce documentation for VGICv5
reproduce: (https://download.01.org/0day-ci/archive/20251215/202512150153.QbgdGdcn-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512150153.QbgdGdcn-lkp at intel.com/

All warnings (new ones prefixed by >>):

   ERROR: Cannot find file ./include/linux/mutex.h
   ERROR: Cannot find file ./include/linux/mutex.h
   WARNING: No kernel-doc for file ./include/linux/mutex.h
   ERROR: Cannot find file ./include/linux/fwctl.h
   WARNING: No kernel-doc for file ./include/linux/fwctl.h
>> Documentation/virt/kvm/devices/arm-vgic-v5.rst: WARNING: document isn't included in any toctree [toc.not_included]

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From akpm at linux-foundation.org  Sun Dec 14 16:32:14 2025
From: akpm at linux-foundation.org (Andrew Morton)
Date: Sun, 14 Dec 2025 16:32:14 -0800
Subject: [PATCH v1 2/3] kexec: print out debugging message if required
 for kexec_load
In-Reply-To: <20251212095649.857796-3-maqianga@uniontech.com>
References: <20251212095649.857796-1-maqianga@uniontech.com>
	<20251212095649.857796-3-maqianga@uniontech.com>
Message-ID: <20251214163214.5018b9c083f11c7ecc081a5d@linux-foundation.org>

On Fri, 12 Dec 2025 17:56:48 +0800 Qiang Ma <maqianga at uniontech.com> wrote:

> The commit a85ee18c7900 ("kexec_file: print out debugging message
> if required") has added general code printing in kexec_file_load(),
> but not in kexec_load().
> 
> As a result, when using '-d' for the kexec_load interface,
> print nothing in the kernel space.

That doesn't sound like a thing which "kernel test robot" would detect
and report.

> Since the segments debugging message has already been printed by the
> user-space tool kexec-tools, it will not be printed here in the
> kernel space.
> 
> And print out type/start/head of kimage and flags to help debug.
> 
> Signed-off-by: Qiang Ma <maqianga at uniontech.com>
> Reported-by: kernel test robot <lkp at intel.com>
> Closes: https://lore.kernel.org/oe-kbuild-all/202510310332.6XrLe70K-lkp at intel.com/

Oh I see, that's a warning against an earlier version of this patch. 
But this is labelled "v1"!

I suggest we remove this Reported-by record.

> --- a/kernel/kexec.c
> +++ b/kernel/kexec.c
> @@ -166,6 +166,9 @@ static int do_kexec_load(unsigned long entry, unsigned long nr_segments,
>  	if (ret)
>  		goto out;
>  
> +	kexec_dprintk("kexec_load: type:%u, start:0x%lx head:0x%lx flags:0x%lx\n",
> +		      image->type, image->start, image->head, flags);
> +
>  	/* Install the new kernel and uninstall the old */
>  	image = xchg(dest_image, image);

Thanks, I'll await reviewer input before proceeding with this series.


From sashal at kernel.org  Sun Dec 14 16:41:21 2025
From: sashal at kernel.org (Sasha Levin)
Date: Sun, 14 Dec 2025 19:41:21 -0500
Subject: [PATCH AUTOSEL 6.18-6.12] ASoC: rockchip: Fix Wvoid-pointer-to-enum-cast warning (again)
In-Reply-To: <20251215004145.2760442-1-sashal@kernel.org>
References: <20251215004145.2760442-1-sashal@kernel.org>
Message-ID: <20251215004145.2760442-4-sashal@kernel.org>

From: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

[ Upstream commit 57d508b5f718730f74b11e0dc9609ac7976802d1 ]

'version' is an enum, thus cast of pointer on 64-bit compile test with
clang W=1 causes:

  rockchip_pdm.c:583:17: error: cast to smaller integer type 'enum rk_pdm_version' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast]

This was already fixed in commit 49a4a8d12612 ("ASoC: rockchip: Fix
Wvoid-pointer-to-enum-cast warning") but then got bad in
commit 9958d85968ed ("ASoC: Use device_get_match_data()").

Discussion on LKML also pointed out that 'uintptr_t' is not the correct
type and either 'kernel_ulong_t' or 'unsigned long' should be used,
with several arguments towards the latter [1].

Link: https://lore.kernel.org/r/CAMuHMdX7t=mabqFE5O-Cii3REMuyaePHmqX+j_mqyrn6XXzsoA at mail.gmail.com/ [1]
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
Link: https://patch.msgid.link/20251203141644.106459-2-krzysztof.kozlowski at oss.qualcomm.com
Signed-off-by: Mark Brown <broonie at kernel.org>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---

LLM Generated explanations, may be completely bogus:

## Summary Analysis

### What the commit fixes
This is a **build fix** that prevents a compilation error when building
with clang and W=1:
```
error: cast to smaller integer type 'enum rk_pdm_version' from 'const
void *' [-Werror,-Wvoid-pointer-to-enum-cast]
```

The issue is that on 64-bit systems, casting directly from `const void
*` (64 bits) to an enum (typically 32 bits) triggers a truncation
warning. Using `(unsigned long)` as an intermediate cast avoids this
because `unsigned long` matches the pointer size.

### Classification
This falls clearly into the **BUILD FIX** exception category which is
explicitly allowed for stable trees. Build fixes that prevent
compilation are critical for users who need to build the kernel.

### Scope and Risk
- **Change**: Single line - only changing the cast type
- **Files touched**: 1 file
- **Risk**: Extremely low - the runtime behavior is identical; only the
  compile-time representation differs
- **Functional equivalence**: The value stored in `pdm->version` is the
  same either way

### Applicability to Stable Trees
The regressing commit 9958d85968ed went into v6.7-rc1. Therefore:
- Stable trees **v6.6.y and earlier**: NOT affected (don't have the
  regression)
- Stable trees **v6.7.y and later**: Affected and would benefit from
  this fix

### Stable Criteria Assessment
| Criterion | Assessment |
|-----------|------------|
| Obviously correct | ? Yes - standard pattern for void pointer to enum
cast |
| Fixes real bug | ? Yes - compilation failure |
| Small scope | ? Yes - 1 line change |
| No new features | ? Correct - pure bug fix |
| Tested | ? Accepted by maintainer |

### Additional Factors
- This is a **regression fix** - the same issue was previously fixed in
  commit 49a4a8d12612 but regressed
- LKML discussion confirms `unsigned long` as the appropriate fix
- Signed off by both author and subsystem maintainer (Mark Brown)

### Risk vs Benefit
- **Risk**: Near zero - compile-time only change, no runtime behavior
  modification
- **Benefit**: Enables compilation with clang W=1 on 64-bit platforms

This is an excellent stable backport candidate. It's a minimal, low-risk
build fix that allows users to compile the kernel in a common
configuration. Build fixes are explicitly mentioned as appropriate for
stable trees, and this one is as safe as they come - a single-line cast
change with no runtime impact.

**YES**

 sound/soc/rockchip/rockchip_pdm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c
index c1ee470ec6079..c69cdd6f24994 100644
--- a/sound/soc/rockchip/rockchip_pdm.c
+++ b/sound/soc/rockchip/rockchip_pdm.c
@@ -580,7 +580,7 @@ static int rockchip_pdm_probe(struct platform_device *pdev)
 	if (!pdm)
 		return -ENOMEM;
 
-	pdm->version = (enum rk_pdm_version)device_get_match_data(&pdev->dev);
+	pdm->version = (unsigned long)device_get_match_data(&pdev->dev);
 	if (pdm->version == RK_PDM_RK3308) {
 		pdm->reset = devm_reset_control_get(&pdev->dev, "pdm-m");
 		if (IS_ERR(pdm->reset))
-- 
2.51.0



From peng.fan at oss.nxp.com  Sun Dec 14 16:50:47 2025
From: peng.fan at oss.nxp.com (Peng Fan)
Date: Mon, 15 Dec 2025 08:50:47 +0800
Subject: [PATCH 1/4] arm64: dts: imx91: Add tempsensor node
In-Reply-To: <aTxGJfQDQVXb+Nd9@lizhi-Precision-Tower-5810>
References: <20251212-imx91-dts-v1-0-2bb3c13762dd@nxp.com>
 <20251212-imx91-dts-v1-1-2bb3c13762dd@nxp.com>
 <aTxGJfQDQVXb+Nd9@lizhi-Precision-Tower-5810>
Message-ID: <aT9bZ0hiOf0dldz5@shlinux89>

On Fri, Dec 12, 2025 at 11:43:17AM -0500, Frank Li wrote:
>On Fri, Dec 12, 2025 at 05:16:07PM +0800, Peng Fan (OSS) wrote:
>> From: Peng Fan <peng.fan at nxp.com>
>>
>> Add tempsensor node and trim sub-nodes in ocotp.
>>
>> Signed-off-by: Peng Fan <peng.fan at nxp.com>
>> ---
>
>I posted it when upstream tmu driver
>
>https://lore.kernel.org/imx/20251020-imx91tmu-v7-3-48d7d9f25055 at nxp.com/

ok, drop this patch.

Thanks,
Peng



From peng.fan at oss.nxp.com  Sun Dec 14 17:36:19 2025
From: peng.fan at oss.nxp.com (Peng Fan)
Date: Mon, 15 Dec 2025 09:36:19 +0800
Subject: [PATCH 1/3] thermal/drivers/imx91: Check status before reading
 data
In-Reply-To: <aTxQHLh0OD89oc/g@lizhi-Precision-Tower-5810>
References: <20251212-imx91-thermal-v1-0-c208545b44cb@nxp.com>
 <20251212-imx91-thermal-v1-1-c208545b44cb@nxp.com>
 <aTxQHLh0OD89oc/g@lizhi-Precision-Tower-5810>
Message-ID: <aT9mE63WtVqCxIPC@shlinux89>

On Fri, Dec 12, 2025 at 12:25:48PM -0500, Frank Li wrote:
>On Fri, Dec 12, 2025 at 03:51:14PM +0800, Peng Fan (OSS) wrote:
>> From: Peng Fan <peng.fan at nxp.com>
>>
>> Per periodic mode from reference mannual:
>> Write 1b to CTRL1[START]. Wait until STATm[DRDYn] becomes 1.
>> Read DATAn[DATA_VAL]. It clears the corresponding STATm[DRDYn].
>> DATAn[DATA_VAL] and STATm[DRDYn_IF] keep refreshing at a periodic interval
>> of time, corresponding to PERIOD_CTRL[MEAS_FREQ].
>
>It should get last time sample value without check DRDYn_IF bit. it should
>only be a PERIOD_CTRL[MEAS_FREQ] delay.
>
>worst case get value at previous's PERIOD_CTRL[MEAS_FREQ] sample.
>
>PERIOD_CTRL[MEAS_FREQ] is quite short compare to call get_temp frequency.
>
>Do you get invalidate data?

No, this is just to align what we tested in LTS tree.
It should be fine to use last value, so drop this patch.

Thanks,
Peng

>
>>
>> Need to check STAT[DRDY] before reading the DATA register.
>>
>> And check the returned temperature to make sure it fits into the supported
>> range (-40?C to +125?C).
>
>https://lore.kernel.org/imx/aAIkAF_AHta8_vuS at mai.linaro.org/
>
>Do you answer Daniel Lezcano's question
>  ""When the measured temperature can be out of limits ?"  at v6 resend
>patch.
>
>Frank
>>
>> Signed-off-by: Peng Fan <peng.fan at nxp.com>
>> ---
>>  drivers/thermal/imx91_thermal.c | 10 ++++++++++
>>  1 file changed, 10 insertions(+)
>>
>> diff --git a/drivers/thermal/imx91_thermal.c b/drivers/thermal/imx91_thermal.c
>> index 9b20be03d6dec18553967548d0ca31d1c1fb387c..77e8e6a921c6af308b830c36721293c007256ca6 100644
>> --- a/drivers/thermal/imx91_thermal.c
>> +++ b/drivers/thermal/imx91_thermal.c
>> @@ -108,10 +108,20 @@ static int imx91_tmu_get_temp(struct thermal_zone_device *tz, int *temp)
>>  {
>>  	struct imx91_tmu *tmu = thermal_zone_device_priv(tz);
>>  	s16 data;
>> +	int ret;
>> +	u32 val;
>> +
>> +	ret = readl_relaxed_poll_timeout(tmu->base + IMX91_TMU_STAT0, val,
>> +					 val & IMX91_TMU_STAT0_DRDY0_IF_MASK, 1000,
>> +					 40000);
>> +	if (ret)
>> +		return -EAGAIN;
>>
>>  	/* DATA0 is 16bit signed number */
>>  	data = readw_relaxed(tmu->base + IMX91_TMU_DATA0);
>>  	*temp = imx91_tmu_to_mcelsius(data);
>> +	if (*temp < IMX91_TMU_TEMP_LOW_LIMIT || *temp > IMX91_TMU_TEMP_HIGH_LIMIT)
>> +		return -EAGAIN;
>>
>>  	return 0;
>>  }
>>
>> --
>> 2.37.1
>>


From haibo.chen at nxp.com  Sun Dec 14 18:05:49 2025
From: haibo.chen at nxp.com (Bough Chen)
Date: Mon, 15 Dec 2025 02:05:49 +0000
Subject: [PATCH] mmc: sdhci-esdhc-imx: add alternate ARCH_S32 dependency
 to Kconfig
In-Reply-To: <20251212-s32g-sdhci-kconfig-v1-1-8e278c8d7f78@redhat.com>
References: <20251212-s32g-sdhci-kconfig-v1-1-8e278c8d7f78@redhat.com>
Message-ID: <DU0PR04MB94963E37EF077E5A3FF7359D90ADA@DU0PR04MB9496.eurprd04.prod.outlook.com>

> -----Original Message-----
> From: Jared Kangas <jkangas at redhat.com>
> Sent: 2025?12?12? 23:03
> To: Ulf Hansson <ulf.hansson at linaro.org>; Bough Chen <haibo.chen at nxp.com>;
> Adrian Hunter <adrian.hunter at intel.com>; Shawn Guo
> <shawnguo at kernel.org>; Sascha Hauer <s.hauer at pengutronix.de>;
> Pengutronix Kernel Team <kernel at pengutronix.de>; Fabio Estevam
> <festevam at gmail.com>; Chester Lin <chester62515 at gmail.com>
> Cc: linux-mmc at vger.kernel.org; linux-kernel at vger.kernel.org;
> imx at lists.linux.dev; dl-S32 <S32 at nxp.com>;
> linux-arm-kernel at lists.infradead.org; Jared Kangas <jkangas at redhat.com>
> Subject: [PATCH] mmc: sdhci-esdhc-imx: add alternate ARCH_S32 dependency to
> Kconfig
> 
> [You don't often get email from jkangas at redhat.com. Learn why this is
> important at https://aka.ms/LearnAboutSenderIdentification ]
> 
> MMC_SDHCI_ESDHC_IMX requires ARCH_MXC despite also being used on
> ARCH_S32, which results in unmet dependencies when compiling strictly for
> ARCH_S32. Resolve this by adding ARCH_S32 as an alternative to ARCH_MXC in
> the driver's dependencies.

Reviewed-by: Haibo Chen <haibo.chen at nxp.com>

Thanks
Haibo
> 
> Fixes: 5c4f00627c9a ("mmc: sdhci-esdhc-imx: add NXP S32G2 support")
> Signed-off-by: Jared Kangas <jkangas at redhat.com>
> ---
>  drivers/mmc/host/Kconfig | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index
> 10d0ef58ef493102d3586d7a31d755543297999a..c94ae4794545de1c818ad50b
> e7f91331862b6acf 100644
> --- a/drivers/mmc/host/Kconfig
> +++ b/drivers/mmc/host/Kconfig
> @@ -315,14 +315,14 @@ config MMC_SDHCI_ESDHC_MCF
> 
>  config MMC_SDHCI_ESDHC_IMX
>         tristate "SDHCI support for the Freescale eSDHC/uSDHC i.MX
> controller"
> -       depends on ARCH_MXC || COMPILE_TEST
> +       depends on ARCH_MXC || ARCH_S32 || COMPILE_TEST
>         depends on MMC_SDHCI_PLTFM
>         depends on OF
>         select MMC_SDHCI_IO_ACCESSORS
>         select MMC_CQHCI
>         help
>           This selects the Freescale eSDHC/uSDHC controller support
> -         found on i.MX25, i.MX35 i.MX5x and i.MX6x.
> +         found on i.MX25, i.MX35, i.MX5x, i.MX6x, and S32G.
> 
>           If you have a controller with this interface, say Y or M here.
> 
> 
> ---
> base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
> change-id: 20251211-s32g-sdhci-kconfig-585b6909f7b4
> 
> Best regards,
> --
> Jared Kangas <jkangas at redhat.com>


From make24 at iscas.ac.cn  Sun Dec 14 18:09:31 2025
From: make24 at iscas.ac.cn (Ma Ke)
Date: Mon, 15 Dec 2025 10:09:31 +0800
Subject: [PATCH v2] USB: Fix error handling in gadget driver
Message-ID: <20251215020931.15324-1-make24@iscas.ac.cn>

lpc32xx_udc_probe() acquires an i2c_client reference through
isp1301_get_client() but fails to release it in both error handling
paths and the normal removal path. This could result in a reference
count leak for the I2C device, preventing proper cleanup and
potentially leading to resource exhaustion. Add put_device() to
release the reference in the probe failure path and in the remove
function.

Calling path: isp1301_get_client() -> of_find_i2c_device_by_node() ->
i2c_find_device_by_fwnode(). As comments of
i2c_find_device_by_fwnode() says, 'The user must call
put_device(&client->dev) once done with the i2c client.'

Found by code review.

Cc: stable at vger.kernel.org
Fixes: 24a28e428351 ("USB: gadget driver for LPC32xx")
Signed-off-by: Ma Ke <make24 at iscas.ac.cn>
---
Changes in v2:
- simplified the patch as suggestions.
---
 drivers/usb/gadget/udc/lpc32xx_udc.c | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c
index 1a7d3c4f652f..73c0f28a8585 100644
--- a/drivers/usb/gadget/udc/lpc32xx_udc.c
+++ b/drivers/usb/gadget/udc/lpc32xx_udc.c
@@ -3020,7 +3020,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev)
 	pdev->dev.dma_mask = &lpc32xx_usbd_dmamask;
 	retval = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
 	if (retval)
-		return retval;
+		goto i2c_fail;
 
 	udc->board = &lpc32xx_usbddata;
 
@@ -3038,28 +3038,32 @@ static int lpc32xx_udc_probe(struct platform_device *pdev)
 	/* Get IRQs */
 	for (i = 0; i < 4; i++) {
 		udc->udp_irq[i] = platform_get_irq(pdev, i);
-		if (udc->udp_irq[i] < 0)
-			return udc->udp_irq[i];
+		if (udc->udp_irq[i] < 0) {
+			retval = udc->udp_irq[i];
+			goto i2c_fail;
+		}
 	}
 
 	udc->udp_baseaddr = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(udc->udp_baseaddr)) {
 		dev_err(udc->dev, "IO map failure\n");
-		return PTR_ERR(udc->udp_baseaddr);
+		retval = PTR_ERR(udc->udp_baseaddr);
+		goto i2c_fail;
 	}
 
 	/* Get USB device clock */
 	udc->usb_slv_clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(udc->usb_slv_clk)) {
 		dev_err(udc->dev, "failed to acquire USB device clock\n");
-		return PTR_ERR(udc->usb_slv_clk);
+		retval = PTR_ERR(udc->usb_slv_clk);
+		goto i2c_fail;
 	}
 
 	/* Enable USB device clock */
 	retval = clk_prepare_enable(udc->usb_slv_clk);
 	if (retval < 0) {
 		dev_err(udc->dev, "failed to start USB device clock\n");
-		return retval;
+		goto i2c_fail;
 	}
 
 	/* Setup deferred workqueue data */
@@ -3161,6 +3165,8 @@ static int lpc32xx_udc_probe(struct platform_device *pdev)
 	dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE,
 			  udc->udca_v_base, udc->udca_p_base);
 i2c_fail:
+	if (udc->isp1301_i2c_client)
+		put_device(&udc->isp1301_i2c_client->dev);
 	clk_disable_unprepare(udc->usb_slv_clk);
 	dev_err(udc->dev, "%s probe failed, %d\n", driver_name, retval);
 
@@ -3189,6 +3195,9 @@ static void lpc32xx_udc_remove(struct platform_device *pdev)
 	dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE,
 			  udc->udca_v_base, udc->udca_p_base);
 
+	if (udc->isp1301_i2c_client)
+		put_device(&udc->isp1301_i2c_client->dev);
+
 	clk_disable_unprepare(udc->usb_slv_clk);
 }
 
-- 
2.17.1



From mathieu.poirier at linaro.org  Sun Dec 14 18:11:01 2025
From: mathieu.poirier at linaro.org (Mathieu Poirier)
Date: Sun, 14 Dec 2025 19:11:01 -0700
Subject: [PATCH v2 1/3] remoteproc: imx_dsp_rproc: Skip
 RP_MBOX_SUSPEND_SYSTEM when mailbox TX channel is uninitialized
In-Reply-To: <20251204122825.756106-1-iuliana.prodan@oss.nxp.com>
References: <20251204122825.756106-1-iuliana.prodan@oss.nxp.com>
Message-ID: <aT9uNSboYCGK1DYL@p14s>

On Thu, Dec 04, 2025 at 02:28:23PM +0200, Iuliana Prodan (OSS) wrote:
> From: Iuliana Prodan <iuliana.prodan at nxp.com>
> 
> Firmwares that do not use mailbox communication (e.g., the hello_world
> sample) leave priv->tx_ch as NULL. The current suspend logic
> unconditionally sends RP_MBOX_SUSPEND_SYSTEM, which is invalid without
> an initialized TX channel.
> 
> Detect the no_mailboxes case early and skip sending the suspend
> message. Instead, proceed directly to the runtime PM suspend path,
> which is the correct behavior for firmwares that cannot respond to
> mailbox requests.
> 
> Signed-off-by: Iuliana Prodan <iuliana.prodan at nxp.com>
> ---
> Changes since v1:
> - Wrapped commit message to 75 characters
> - Changed dev_err to dev_dbg since this case is normal behavior
> ---
>  drivers/remoteproc/imx_dsp_rproc.c | 9 +++++++++
>  1 file changed, 9 insertions(+)
>

I have applied all 3 patches in this set.  Next time, please consider adding a
cover letter.

Thanks,
Mathieu
 
> diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c
> index 5130a35214c9..f51deaacc700 100644
> --- a/drivers/remoteproc/imx_dsp_rproc.c
> +++ b/drivers/remoteproc/imx_dsp_rproc.c
> @@ -1242,6 +1242,15 @@ static int imx_dsp_suspend(struct device *dev)
>  	if (rproc->state != RPROC_RUNNING)
>  		goto out;
>  
> +	/*
> +	 * No channel available for sending messages;
> +	 * indicates no mailboxes present, so trigger PM runtime suspend
> +	 */
> +	if (!priv->tx_ch) {
> +		dev_dbg(dev, "No initialized mbox tx channel, suspend directly.\n");
> +		goto out;
> +	}
> +
>  	reinit_completion(&priv->pm_comp);
>  
>  	/* Tell DSP that suspend is happening */
> -- 
> 2.25.1
> 


From zhentao.guo at amlogic.com  Sun Dec 14 18:15:59 2025
From: zhentao.guo at amlogic.com (Zhentao Guo)
Date: Mon, 15 Dec 2025 10:15:59 +0800
Subject: [PATCH RFC v2 2/3] decoder: Add V4L2 stateless H.264 decoder
 driver
In-Reply-To: <f9c113914290a0701614c64b5e2167d4b3e21646.camel@ndufresne.ca>
References: <20251124-b4-s4-vdec-upstream-v2-0-bdbbce3f11a6@amlogic.com>
 <20251124-b4-s4-vdec-upstream-v2-2-bdbbce3f11a6@amlogic.com>
 <9b74086ac938475328904960add2c284b81efd4a.camel@ndufresne.ca>
 <12f26bf8-409b-4206-a39b-4bb2a14edec0@amlogic.com>
 <f9c113914290a0701614c64b5e2167d4b3e21646.camel@ndufresne.ca>
Message-ID: <9ab31529-8146-4ca7-8389-04c69f7d1b49@amlogic.com>


? 2025/12/12 21:51, Nicolas Dufresne ??:
> Hi,
>
> Le vendredi 12 d?cembre 2025 ? 12:11 +0800, Zhentao Guo a ?crit?:
>>> strcpy() would be the preferred helper for this, no need to fill the leading
>>> zero liek this, see include/linux/string.h
>> Ok, it should be more suitable to use strcpy.
> I have to correct myself, I meant to suggest strscpy(dst, src, size). Passing
> the size for safety seems important, and unlike strncpy() it takes care of the
> leading zero.
Yes, we use strscpy() for copying all the strings.
>
> Nicolas

Thanks

Zhentao



From mathieu.poirier at linaro.org  Sun Dec 14 18:19:43 2025
From: mathieu.poirier at linaro.org (Mathieu Poirier)
Date: Sun, 14 Dec 2025 19:19:43 -0700
Subject: [PATCH] remoteproc: imx_rproc: Use strstarts for "rsc-table"
 check
In-Reply-To: <20251208233302.684139-1-shenwei.wang@nxp.com>
References: <20251208233302.684139-1-shenwei.wang@nxp.com>
Message-ID: <aT9wP_3olsf7WbPL@p14s>

On Mon, Dec 08, 2025 at 05:33:02PM -0600, Shenwei Wang wrote:
> The resource name may include an address suffix, for example:
> rsc-table at 1fff8000.
> 
> To handle such cases, use strstarts() instead of strcmp() when checking
> for "rsc-table".
> 
> Signed-off-by: Shenwei Wang <shenwei.wang at nxp.com>
> ---
>  drivers/remoteproc/imx_rproc.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
> index 3be8790c14a2..33f21ab24c92 100644
> --- a/drivers/remoteproc/imx_rproc.c
> +++ b/drivers/remoteproc/imx_rproc.c
> @@ -694,7 +694,7 @@ static int imx_rproc_addr_init(struct imx_rproc *priv,
>  		}
>  		priv->mem[b].sys_addr = res.start;
>  		priv->mem[b].size = resource_size(&res);
> -		if (!strcmp(res.name, "rsc-table"))
> +		if (strstarts(res.name, "rsc-table"))
>  			priv->rsc_table = priv->mem[b].cpu_addr;

Before applying this patch, I want to know how it ever worked before.  How
did DT with a suffix tested?

>  		b++;
>  	}
> -- 
> 2.43.0
> 


From make24 at iscas.ac.cn  Sun Dec 14 18:27:09 2025
From: make24 at iscas.ac.cn (Ma Ke)
Date: Mon, 15 Dec 2025 10:27:09 +0800
Subject: [PATCH v2 RESEND] coresight: etm-perf: Fix reference count leak in etm_setup_aux
Message-ID: <20251215022709.17220-1-make24@iscas.ac.cn>

In etm_setup_aux(), when a user sink is obtained via
coresight_get_sink_by_id(), it increments the reference count of the
sink device. However, if the sink is used in path building, the path
holds a reference, but the initial reference from
coresight_get_sink_by_id() is not released, causing a reference count
leak. We should release the initial reference after the path is built.

Found by code review.

Cc: stable at vger.kernel.org
Fixes: 0e6c20517596 ("coresight: etm-perf: Allow an event to use different sinks")
Signed-off-by: Ma Ke <make24 at iscas.ac.cn>
---
Changes in v2:
- modified the patch as suggestions.
---
 drivers/hwtracing/coresight/coresight-etm-perf.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c
index 17afa0f4cdee..56d012ab6d3a 100644
--- a/drivers/hwtracing/coresight/coresight-etm-perf.c
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.c
@@ -454,6 +454,11 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
 		goto err;
 
 out:
+	if (user_sink) {
+		put_device(&user_sink->dev);
+		user_sink = NULL;
+	}
+
 	return event_data;
 
 err:
-- 
2.17.1



From qijian.guo at oss.nxp.com  Sun Dec 14 18:36:40 2025
From: qijian.guo at oss.nxp.com (Joseph Guo (OSS))
Date: Mon, 15 Dec 2025 10:36:40 +0800
Subject: [PATCH v2 0/2] Add FRDM i.MX 91 Development board support
In-Reply-To: <aT18yj7c27_buJSe@bywater>
References: <20251212-imx91_frdm-v2-0-4dd6d289e81d@nxp.com>
 <aT18yj7c27_buJSe@bywater>
Message-ID: <6cd03c93-1a6d-4766-86e2-1a74d49c4789@oss.nxp.com>



On 12/13/2025 10:48 PM, Francesco Valla wrote:
> On Fri, Dec 12, 2025 at 11:31:32AM +0900, Joseph Guo wrote:
>> FRDM-IMX91 board is a low cost development platform based on i.MX91 SoC:
>> https://www.nxp.com/design/design-center/development-boards-and-designs/FRDM-IMX91
>>
>> Add device tree and dt-binding for FRDM-IMX91.
>>
>> Signed-off-by: Joseph Guo <qijian.guo at nxp.com>
>> ---
>> Changes in v2:
>> - rename compatible 'frdm-imx91' to 'imx91-11x11-frdm'
>> - rename 'sw-keys' to 'gpio-keys'
>> - rename 'user_btn' to 'button-k'
>> - drop lpspi3 node
>> - rename iomuxc 'grpsleep' to 'sleepgrp'
>> - move dt-binding patch before the dts patch
>> - add board page link in cover letter
>> - use CAN PHY to manage the stby gpio of flexcan2
>> - drop realtek property
>> - add pcf2131 aliase
>> - add bootph- property for nodes should be kept in bootloader phase
>> - add reset-gpio and assert for eqos and fec
>> - delete unused alias
>> - Link to v1: https://lore.kernel.org/r/20251114-imx91_frdm-v1-0-e5763bdf9336 at nxp.com
>>
>> ---
>> Joseph Guo (2):
>>        dt-bindings: arm: imx Add FRDM-IMX91 board
>>        arm64: dts: freescale: Add FRDM-IMX91 basic support
>>
>>   Documentation/devicetree/bindings/arm/fsl.yaml     |   1 +
>>   arch/arm64/boot/dts/freescale/Makefile             |   1 +
>>   arch/arm64/boot/dts/freescale/imx91-11x11-frdm.dts | 904 +++++++++++++++++++++
>>   3 files changed, 906 insertions(+)
>> ---
>> base-commit: 73f1e611b076de705c2f1c26cfdfc5b8e96f4733
>> change-id: 20251114-imx91_frdm-add2b2c07e78
>>
>> Best regards,
>> -- 
>> Joseph Guo <qijian.guo at nxp.com>
>>
>>
> 
> Everything is in good shape, the only non-working thing is button-k3
> (but that was expected, as a small hardware modification is required
> to reroute the phisical button from system reset to user function).
> Not a real issue, at least from my point of view.
> 
> Reviewed-by: Francesco Valla <francesco at valla.it>
> Tested-by: Francesco Valla <francesco at valla.it>
> 

Hi Francesco,

Thank you for your review and test.

Regards,
Joseph

> 
> Regards,
> Francesco
> 



From irving-ch.lin at mediatek.com  Sun Dec 14 19:49:23 2025
From: irving-ch.lin at mediatek.com (irving.ch.lin)
Date: Mon, 15 Dec 2025 11:49:23 +0800
Subject: [PATCH v4 14/21] clk: mediatek: Add MT8189 mdp clock support
In-Reply-To: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
References: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
Message-ID: <20251215034944.2973003-15-irving-ch.lin@mediatek.com>

From: Irving-CH Lin <irving-ch.lin at mediatek.com>

Add support for the MT8189 mdp clock controller,
which provides clock gate control for display system.

Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
---
 drivers/clk/mediatek/Kconfig             | 12 ++++
 drivers/clk/mediatek/Makefile            |  1 +
 drivers/clk/mediatek/clk-mt8189-mdpsys.c | 91 ++++++++++++++++++++++++
 3 files changed, 104 insertions(+)
 create mode 100644 drivers/clk/mediatek/clk-mt8189-mdpsys.c

diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
index c0fe1aa49993..ef962f5816a8 100644
--- a/drivers/clk/mediatek/Kconfig
+++ b/drivers/clk/mediatek/Kconfig
@@ -894,6 +894,18 @@ config COMMON_CLK_MT8189_IMG
 	  are building a kernel for a device that uses the MT8189 SoC and requires
 	  image processing capabilities, say Y or M to include this driver.
 
+config COMMON_CLK_MT8189_MDPSYS
+	tristate "Clock driver for MediaTek MT8189 mdpsys"
+	depends on COMMON_CLK_MT8189
+	default COMMON_CLK_MT8189
+	help
+	  This driver supports the display system clocks on the MediaTek MT8189
+	  SoC. By enabling this option, it allows for the control of the clocks
+	  related to the display subsystem. This is crucial for the proper
+	  functionality of the display features on devices powered by the MT8189
+	  chipset, ensuring that the display system operates efficiently and
+	  effectively.
+
 config COMMON_CLK_MT8192
 	tristate "Clock driver for MediaTek MT8192"
 	depends on ARM64 || COMPILE_TEST
diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
index a1eaf123f2f0..9b23e4c5e019 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -131,6 +131,7 @@ obj-$(CONFIG_COMMON_CLK_MT8189_DBGAO) += clk-mt8189-dbgao.o
 obj-$(CONFIG_COMMON_CLK_MT8189_DVFSRC) += clk-mt8189-dvfsrc.o
 obj-$(CONFIG_COMMON_CLK_MT8189_IIC) += clk-mt8189-iic.o
 obj-$(CONFIG_COMMON_CLK_MT8189_IMG) += clk-mt8189-img.o
+obj-$(CONFIG_COMMON_CLK_MT8189_MDPSYS) += clk-mt8189-mdpsys.o
 obj-$(CONFIG_COMMON_CLK_MT8192) += clk-mt8192-apmixedsys.o clk-mt8192.o
 obj-$(CONFIG_COMMON_CLK_MT8192_AUDSYS) += clk-mt8192-aud.o
 obj-$(CONFIG_COMMON_CLK_MT8192_CAMSYS) += clk-mt8192-cam.o
diff --git a/drivers/clk/mediatek/clk-mt8189-mdpsys.c b/drivers/clk/mediatek/clk-mt8189-mdpsys.c
new file mode 100644
index 000000000000..282bfb77b47d
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8189-mdpsys.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Qiqi Wang <qiqi.wang at mediatek.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include "clk-mtk.h"
+#include "clk-gate.h"
+
+#include <dt-bindings/clock/mediatek,mt8189-clk.h>
+
+static const struct mtk_gate_regs mdp0_cg_regs = {
+	.set_ofs = 0x04,
+	.clr_ofs = 0x08,
+	.sta_ofs = 0x00,
+};
+
+static const struct mtk_gate_regs mdp1_cg_regs = {
+	.set_ofs = 0x14,
+	.clr_ofs = 0x18,
+	.sta_ofs = 0x10,
+};
+
+#define GATE_MDP0(_id, _name, _parent, _shift)				\
+	GATE_MTK_FLAGS(_id, _name, _parent, &mdp0_cg_regs, _shift,	\
+		       &mtk_clk_gate_ops_setclr, CLK_IGNORE_UNUSED)
+
+#define GATE_MDP1(_id, _name, _parent, _shift)				\
+	GATE_MTK_FLAGS(_id, _name, _parent, &mdp1_cg_regs, _shift,	\
+		       &mtk_clk_gate_ops_setclr, CLK_IGNORE_UNUSED)
+
+static const struct mtk_gate mdp_clks[] = {
+	/* MDP0 */
+	GATE_MDP0(CLK_MDP_MUTEX0, "mdp_mutex0", "mdp0_sel", 0),
+	GATE_MDP0(CLK_MDP_APB_BUS, "mdp_apb_bus", "mdp0_sel", 1),
+	GATE_MDP0(CLK_MDP_SMI0, "mdp_smi0", "mdp0_sel", 2),
+	GATE_MDP0(CLK_MDP_RDMA0, "mdp_rdma0", "mdp0_sel", 3),
+	GATE_MDP0(CLK_MDP_RDMA2, "mdp_rdma2", "mdp0_sel", 4),
+	GATE_MDP0(CLK_MDP_HDR0, "mdp_hdr0", "mdp0_sel", 5),
+	GATE_MDP0(CLK_MDP_AAL0, "mdp_aal0", "mdp0_sel", 6),
+	GATE_MDP0(CLK_MDP_RSZ0, "mdp_rsz0", "mdp0_sel", 7),
+	GATE_MDP0(CLK_MDP_TDSHP0, "mdp_tdshp0", "mdp0_sel", 8),
+	GATE_MDP0(CLK_MDP_COLOR0, "mdp_color0", "mdp0_sel", 9),
+	GATE_MDP0(CLK_MDP_WROT0, "mdp_wrot0", "mdp0_sel", 10),
+	GATE_MDP0(CLK_MDP_FAKE_ENG0, "mdp_fake_eng0", "mdp0_sel", 11),
+	GATE_MDP0(CLK_MDPSYS_CONFIG, "mdpsys_config", "mdp0_sel", 14),
+	GATE_MDP0(CLK_MDP_RDMA1, "mdp_rdma1", "mdp0_sel", 15),
+	GATE_MDP0(CLK_MDP_RDMA3, "mdp_rdma3", "mdp0_sel", 16),
+	GATE_MDP0(CLK_MDP_HDR1, "mdp_hdr1", "mdp0_sel", 17),
+	GATE_MDP0(CLK_MDP_AAL1, "mdp_aal1", "mdp0_sel", 18),
+	GATE_MDP0(CLK_MDP_RSZ1, "mdp_rsz1", "mdp0_sel", 19),
+	GATE_MDP0(CLK_MDP_TDSHP1, "mdp_tdshp1", "mdp0_sel", 20),
+	GATE_MDP0(CLK_MDP_COLOR1, "mdp_color1", "mdp0_sel", 21),
+	GATE_MDP0(CLK_MDP_WROT1, "mdp_wrot1", "mdp0_sel", 22),
+	GATE_MDP0(CLK_MDP_RSZ2, "mdp_rsz2", "mdp0_sel", 24),
+	GATE_MDP0(CLK_MDP_WROT2, "mdp_wrot2", "mdp0_sel", 25),
+	GATE_MDP0(CLK_MDP_RSZ3, "mdp_rsz3", "mdp0_sel", 28),
+	GATE_MDP0(CLK_MDP_WROT3, "mdp_wrot3", "mdp0_sel", 29),
+	/* MDP1 */
+	GATE_MDP1(CLK_MDP_BIRSZ0, "mdp_birsz0", "mdp0_sel", 3),
+	GATE_MDP1(CLK_MDP_BIRSZ1, "mdp_birsz1", "mdp0_sel", 4),
+};
+
+static const struct mtk_clk_desc mdp_mcd = {
+	.clks = mdp_clks,
+	.num_clks = ARRAY_SIZE(mdp_clks),
+};
+
+static const struct of_device_id of_match_clk_mt8189_mdpsys[] = {
+	{ .compatible = "mediatek,mt8189-mdpsys", .data = &mdp_mcd },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_match_clk_mt8189_mdpsys);
+
+static struct platform_driver clk_mt8189_mdpsys_drv = {
+	.probe = mtk_clk_simple_probe,
+	.remove = mtk_clk_simple_remove,
+	.driver = {
+		.name = "clk-mt8189-mdpsys",
+		.of_match_table = of_match_clk_mt8189_mdpsys,
+	},
+};
+
+module_platform_driver(clk_mt8189_mdpsys_drv);
+MODULE_DESCRIPTION("MediaTek MT8189 mdpsys clocks driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



From irving-ch.lin at mediatek.com  Sun Dec 14 19:49:09 2025
From: irving-ch.lin at mediatek.com (irving.ch.lin)
Date: Mon, 15 Dec 2025 11:49:09 +0800
Subject: [PATCH v4 00/21] Add support for MT8189 clock/power controller
Message-ID: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>

From: Irving-CH Lin <irving-ch.lin at mediatek.com>

Changes since v4:
- Fix dt_binding_check warning.
- Check prepare_enable before set_parent to ensure our reference clock is ready.
- Enable fhctl in apmixed driver.
- Refine clock drivers: 
  - Change subsys name, regs base/size (clock related part, instead of whole subsys).
  - Simply code with GATE_MTK macro.
  - Add MODULE_DEVICE_TABLE, MODULE_DESCRIPTION
  - Register remove callback mtk_clk_simple_remove.
  - Remove most of CLK_OPS_PARENT_ENABLE and CLK_IGNORE_UNUSED which may block bringup,
      but some subsys will power off before we disable unused clocks, so still need here.  

changes since v3:
- Add power-controller dt-schema to mediatek,power-controller.yaml.
- Separates clock commit to small parts (by sub-system).
- Change to mtk-pm-domains for new MTK pm framework.

changes since v2:
- Fix dt-schema checking fails
- Merge dt-binding files and dt-schema files into one patch.
- Add vendor information to dt-binding file name.
- Remove NR define in dt-binding header.
- Add struct member description.

  This series add support for the clock and power controllers
of MediaTek's new SoC, MT8189. With these changes,
other modules can easily manage clock and power resources
using standard Linux APIs, such as the Common Clock Framework (CCF)
and pm_runtime on MT8189 platform.

Irving-CH Lin (21):
  dt-bindings: clock: mediatek: Add MT8189 clock definitions
  dt-bindings: power: mediatek: Add MT8189 power domain definitions
  clk: mediatek: clk-mux: Make sure bypass clk enabled while setting MFG
    rate
  clk: mediatek: Add MT8189 apmixedsys clock support
  clk: mediatek: Add MT8189 topckgen clock support
  clk: mediatek: Add MT8189 vlpckgen clock support
  clk: mediatek: Add MT8189 vlpcfg clock support
  clk: mediatek: Add MT8189 bus clock support
  clk: mediatek: Add MT8189 cam clock support
  clk: mediatek: Add MT8189 dbgao clock support
  clk: mediatek: Add MT8189 dvfsrc clock support
  clk: mediatek: Add MT8189 i2c clock support
  clk: mediatek: Add MT8189 img clock support
  clk: mediatek: Add MT8189 mdp clock support
  clk: mediatek: Add MT8189 mfg clock support
  clk: mediatek: Add MT8189 dispsys clock support
  clk: mediatek: Add MT8189 scp clock support
  clk: mediatek: Add MT8189 ufs clock support
  clk: mediatek: Add MT8189 vcodec clock support
  pmdomain: mediatek: Add bus protect control flow for MT8189
  pmdomain: mediatek: Add power domain driver for MT8189 SoC

 .../bindings/clock/mediatek,mt8189-clock.yaml |   90 ++
 .../clock/mediatek,mt8189-sys-clock.yaml      |   58 +
 .../power/mediatek,power-controller.yaml      |    1 +
 drivers/clk/mediatek/Kconfig                  |  146 +++
 drivers/clk/mediatek/Makefile                 |   14 +
 drivers/clk/mediatek/clk-mt8189-apmixedsys.c  |  192 ++++
 drivers/clk/mediatek/clk-mt8189-bus.c         |  196 ++++
 drivers/clk/mediatek/clk-mt8189-cam.c         |  108 ++
 drivers/clk/mediatek/clk-mt8189-dbgao.c       |   94 ++
 drivers/clk/mediatek/clk-mt8189-dispsys.c     |  172 +++
 drivers/clk/mediatek/clk-mt8189-dvfsrc.c      |   54 +
 drivers/clk/mediatek/clk-mt8189-iic.c         |  118 ++
 drivers/clk/mediatek/clk-mt8189-img.c         |  107 ++
 drivers/clk/mediatek/clk-mt8189-mdpsys.c      |   91 ++
 drivers/clk/mediatek/clk-mt8189-mfg.c         |   53 +
 drivers/clk/mediatek/clk-mt8189-scp.c         |   73 ++
 drivers/clk/mediatek/clk-mt8189-topckgen.c    | 1020 +++++++++++++++++
 drivers/clk/mediatek/clk-mt8189-ufs.c         |   89 ++
 drivers/clk/mediatek/clk-mt8189-vcodec.c      |   93 ++
 drivers/clk/mediatek/clk-mt8189-vlpcfg.c      |  111 ++
 drivers/clk/mediatek/clk-mt8189-vlpckgen.c    |  280 +++++
 drivers/clk/mediatek/clk-mux.c                |    9 +-
 drivers/pmdomain/mediatek/mt8189-pm-domains.h |  485 ++++++++
 drivers/pmdomain/mediatek/mtk-pm-domains.c    |   36 +-
 drivers/pmdomain/mediatek/mtk-pm-domains.h    |    5 +
 .../dt-bindings/clock/mediatek,mt8189-clk.h   |  580 ++++++++++
 .../dt-bindings/power/mediatek,mt8189-power.h |   38 +
 27 files changed, 4306 insertions(+), 7 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt8189-clock.yaml
 create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt8189-sys-clock.yaml
 create mode 100644 drivers/clk/mediatek/clk-mt8189-apmixedsys.c
 create mode 100644 drivers/clk/mediatek/clk-mt8189-bus.c
 create mode 100644 drivers/clk/mediatek/clk-mt8189-cam.c
 create mode 100644 drivers/clk/mediatek/clk-mt8189-dbgao.c
 create mode 100644 drivers/clk/mediatek/clk-mt8189-dispsys.c
 create mode 100644 drivers/clk/mediatek/clk-mt8189-dvfsrc.c
 create mode 100644 drivers/clk/mediatek/clk-mt8189-iic.c
 create mode 100644 drivers/clk/mediatek/clk-mt8189-img.c
 create mode 100644 drivers/clk/mediatek/clk-mt8189-mdpsys.c
 create mode 100644 drivers/clk/mediatek/clk-mt8189-mfg.c
 create mode 100644 drivers/clk/mediatek/clk-mt8189-scp.c
 create mode 100644 drivers/clk/mediatek/clk-mt8189-topckgen.c
 create mode 100644 drivers/clk/mediatek/clk-mt8189-ufs.c
 create mode 100644 drivers/clk/mediatek/clk-mt8189-vcodec.c
 create mode 100644 drivers/clk/mediatek/clk-mt8189-vlpcfg.c
 create mode 100644 drivers/clk/mediatek/clk-mt8189-vlpckgen.c
 create mode 100644 drivers/pmdomain/mediatek/mt8189-pm-domains.h
 create mode 100644 include/dt-bindings/clock/mediatek,mt8189-clk.h
 create mode 100644 include/dt-bindings/power/mediatek,mt8189-power.h

-- 
2.45.2



From irving-ch.lin at mediatek.com  Sun Dec 14 19:49:10 2025
From: irving-ch.lin at mediatek.com (irving.ch.lin)
Date: Mon, 15 Dec 2025 11:49:10 +0800
Subject: [PATCH v4 01/21] dt-bindings: clock: mediatek: Add MT8189 clock definitions
In-Reply-To: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
References: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
Message-ID: <20251215034944.2973003-2-irving-ch.lin@mediatek.com>

From: Irving-CH Lin <irving-ch.lin at mediatek.com>

Add device tree bindings for the clock of MediaTek MT8189 SoC.

Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
---
 .../bindings/clock/mediatek,mt8189-clock.yaml |  90 +++
 .../clock/mediatek,mt8189-sys-clock.yaml      |  58 ++
 .../dt-bindings/clock/mediatek,mt8189-clk.h   | 580 ++++++++++++++++++
 3 files changed, 728 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt8189-clock.yaml
 create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt8189-sys-clock.yaml
 create mode 100644 include/dt-bindings/clock/mediatek,mt8189-clk.h

diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8189-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8189-clock.yaml
new file mode 100644
index 000000000000..d21e02df36a1
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/mediatek,mt8189-clock.yaml
@@ -0,0 +1,90 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/mediatek,mt8189-clock.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek Functional Clock Controller for MT8189
+
+maintainers:
+  - Qiqi Wang <qiqi.wang at mediatek.com>
+
+description: |
+  The clock architecture in MediaTek like below
+  PLLs -->
+          dividers -->
+                      muxes -->
+                               clock gate
+
+  The devices provide clock gate control in different IP blocks.
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - mediatek,mt8189-camsys-main
+          - mediatek,mt8189-camsys-rawa
+          - mediatek,mt8189-camsys-rawb
+          - mediatek,mt8189-dbg-ao
+          - mediatek,mt8189-dem
+          - mediatek,mt8189-dispsys
+          - mediatek,mt8189-dvfsrc-top
+          - mediatek,mt8189-gce-d
+          - mediatek,mt8189-gce-m
+          - mediatek,mt8189-iic-wrap-e
+          - mediatek,mt8189-iic-wrap-en
+          - mediatek,mt8189-iic-wrap-s
+          - mediatek,mt8189-iic-wrap-ws
+          - mediatek,mt8189-imgsys1
+          - mediatek,mt8189-imgsys2
+          - mediatek,mt8189-infra-ao
+          - mediatek,mt8189-ipesys
+          - mediatek,mt8189-mdpsys
+          - mediatek,mt8189-mfgcfg
+          - mediatek,mt8189-mm-infra
+          - mediatek,mt8189-peri-ao
+          - mediatek,mt8189-scp-clk
+          - mediatek,mt8189-scp-i2c-clk
+          - mediatek,mt8189-ufscfg-ao
+          - mediatek,mt8189-ufscfg-pdn
+          - mediatek,mt8189-vdec-core
+          - mediatek,mt8189-venc
+      - const: syscon
+
+  reg:
+    maxItems: 1
+
+  '#clock-cells':
+    const: 1
+
+  '#reset-cells':
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - '#clock-cells'
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - mediatek,mt8189-peri-ao
+              - mediatek,mt8189-ufscfg-ao
+              - mediatek,mt8189-ufscfg-pdn
+
+    then:
+      required:
+        - '#reset-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    clock-controller at 11b21000 {
+        compatible = "mediatek,mt8189-iic-wrap-ws", "syscon";
+        reg = <0x11b21000 0x1000>;
+        #clock-cells = <1>;
+    };
diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8189-sys-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8189-sys-clock.yaml
new file mode 100644
index 000000000000..c94de207e289
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/mediatek,mt8189-sys-clock.yaml
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/mediatek,mt8189-sys-clock.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek System Clock Controller for MT8189
+
+maintainers:
+  - Qiqi Wang <qiqi.wang at mediatek.com>
+
+description: |
+  The clock architecture in MediaTek like below
+  PLLs -->
+          dividers -->
+                      muxes -->
+                               clock gate
+
+  The apmixedsys provides most of PLLs which generated from SoC 26m.
+  The topckgen provides dividers and muxes which provide the clock source to other IP blocks.
+  The infracfg_ao provides clock gate in peripheral and infrastructure IP blocks.
+  The mcusys provides mux control to select the clock source in AP MCU.
+  The device nodes also provide the system control capacity for configuration.
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - mediatek,mt8189-apmixedsys
+          - mediatek,mt8189-topckgen
+          - mediatek,mt8189-vlpckgen
+          - mediatek,mt8189-vlp-ao
+          - mediatek,mt8189-vlpcfg-ao
+      - const: syscon
+
+  reg:
+    maxItems: 1
+
+  '#clock-cells':
+    const: 1
+
+  '#reset-cells':
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - '#clock-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    clock-controller at 10000000 {
+        compatible = "mediatek,mt8189-topckgen", "syscon";
+        reg = <0x10000000 0x1000>;
+        #clock-cells = <1>;
+    };
diff --git a/include/dt-bindings/clock/mediatek,mt8189-clk.h b/include/dt-bindings/clock/mediatek,mt8189-clk.h
new file mode 100644
index 000000000000..139db869a3ec
--- /dev/null
+++ b/include/dt-bindings/clock/mediatek,mt8189-clk.h
@@ -0,0 +1,580 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)  */
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Qiqi Wang <qiqi.wang at mediatek.com>
+ */
+
+#ifndef _DT_BINDINGS_CLK_MT8189_H
+#define _DT_BINDINGS_CLK_MT8189_H
+
+/* TOPCKGEN */
+#define CLK_TOP_AXI_SEL					0
+#define CLK_TOP_AXI_PERI_SEL				1
+#define CLK_TOP_AXI_U_SEL				2
+#define CLK_TOP_BUS_AXIMEM_SEL				3
+#define CLK_TOP_DISP0_SEL				4
+#define CLK_TOP_MMINFRA_SEL				5
+#define CLK_TOP_UART_SEL				6
+#define CLK_TOP_SPI0_SEL				7
+#define CLK_TOP_SPI1_SEL				8
+#define CLK_TOP_SPI2_SEL				9
+#define CLK_TOP_SPI3_SEL				10
+#define CLK_TOP_SPI4_SEL				11
+#define CLK_TOP_SPI5_SEL				12
+#define CLK_TOP_MSDC_MACRO_0P_SEL			13
+#define CLK_TOP_MSDC50_0_HCLK_SEL			14
+#define CLK_TOP_MSDC50_0_SEL				15
+#define CLK_TOP_AES_MSDCFDE_SEL				16
+#define CLK_TOP_MSDC_MACRO_1P_SEL			17
+#define CLK_TOP_MSDC30_1_SEL				18
+#define CLK_TOP_MSDC30_1_HCLK_SEL			19
+#define CLK_TOP_MSDC_MACRO_2P_SEL			20
+#define CLK_TOP_MSDC30_2_SEL				21
+#define CLK_TOP_MSDC30_2_HCLK_SEL			22
+#define CLK_TOP_AUD_INTBUS_SEL				23
+#define CLK_TOP_ATB_SEL					24
+#define CLK_TOP_DISP_PWM_SEL				25
+#define CLK_TOP_USB_TOP_P0_SEL				26
+#define CLK_TOP_USB_XHCI_P0_SEL				27
+#define CLK_TOP_USB_TOP_P1_SEL				28
+#define CLK_TOP_USB_XHCI_P1_SEL				29
+#define CLK_TOP_USB_TOP_P2_SEL				30
+#define CLK_TOP_USB_XHCI_P2_SEL				31
+#define CLK_TOP_USB_TOP_P3_SEL				32
+#define CLK_TOP_USB_XHCI_P3_SEL				33
+#define CLK_TOP_USB_TOP_P4_SEL				34
+#define CLK_TOP_USB_XHCI_P4_SEL				35
+#define CLK_TOP_I2C_SEL					36
+#define CLK_TOP_SENINF_SEL				37
+#define CLK_TOP_SENINF1_SEL				38
+#define CLK_TOP_AUD_ENGEN1_SEL				39
+#define CLK_TOP_AUD_ENGEN2_SEL				40
+#define CLK_TOP_AES_UFSFDE_SEL				41
+#define CLK_TOP_U_SEL					42
+#define CLK_TOP_U_MBIST_SEL				43
+#define CLK_TOP_AUD_1_SEL				44
+#define CLK_TOP_AUD_2_SEL				45
+#define CLK_TOP_VENC_SEL				46
+#define CLK_TOP_VDEC_SEL				47
+#define CLK_TOP_PWM_SEL					48
+#define CLK_TOP_AUDIO_H_SEL				49
+#define CLK_TOP_MCUPM_SEL				50
+#define CLK_TOP_MEM_SUB_SEL				51
+#define CLK_TOP_MEM_SUB_PERI_SEL			52
+#define CLK_TOP_MEM_SUB_U_SEL				53
+#define CLK_TOP_EMI_N_SEL				54
+#define CLK_TOP_DSI_OCC_SEL				55
+#define CLK_TOP_AP2CONN_HOST_SEL			56
+#define CLK_TOP_IMG1_SEL				57
+#define CLK_TOP_IPE_SEL					58
+#define CLK_TOP_CAM_SEL					59
+#define CLK_TOP_CAMTM_SEL				60
+#define CLK_TOP_DSP_SEL					61
+#define CLK_TOP_SR_PKA_SEL				62
+#define CLK_TOP_DXCC_SEL				63
+#define CLK_TOP_MFG_REF_SEL				64
+#define CLK_TOP_MDP0_SEL				65
+#define CLK_TOP_DP_SEL					66
+#define CLK_TOP_EDP_SEL					67
+#define CLK_TOP_EDP_FAVT_SEL				68
+#define CLK_TOP_ETH_250M_SEL				69
+#define CLK_TOP_ETH_62P4M_PTP_SEL			70
+#define CLK_TOP_ETH_50M_RMII_SEL			71
+#define CLK_TOP_SFLASH_SEL				72
+#define CLK_TOP_GCPU_SEL				73
+#define CLK_TOP_MAC_TL_SEL				74
+#define CLK_TOP_VDSTX_DG_CTS_SEL			75
+#define CLK_TOP_PLL_DPIX_SEL				76
+#define CLK_TOP_ECC_SEL					77
+#define CLK_TOP_APLL_I2SIN0_MCK_SEL			78
+#define CLK_TOP_APLL_I2SIN1_MCK_SEL			79
+#define CLK_TOP_APLL_I2SIN2_MCK_SEL			80
+#define CLK_TOP_APLL_I2SIN3_MCK_SEL			81
+#define CLK_TOP_APLL_I2SIN4_MCK_SEL			82
+#define CLK_TOP_APLL_I2SIN6_MCK_SEL			83
+#define CLK_TOP_APLL_I2SOUT0_MCK_SEL			84
+#define CLK_TOP_APLL_I2SOUT1_MCK_SEL			85
+#define CLK_TOP_APLL_I2SOUT2_MCK_SEL			86
+#define CLK_TOP_APLL_I2SOUT3_MCK_SEL			87
+#define CLK_TOP_APLL_I2SOUT4_MCK_SEL			88
+#define CLK_TOP_APLL_I2SOUT6_MCK_SEL			89
+#define CLK_TOP_APLL_FMI2S_MCK_SEL			90
+#define CLK_TOP_APLL_TDMOUT_MCK_SEL			91
+#define CLK_TOP_MFG_SEL_MFGPLL				92
+#define CLK_TOP_APLL12_CK_DIV_I2SIN0			93
+#define CLK_TOP_APLL12_CK_DIV_I2SIN1			94
+#define CLK_TOP_APLL12_CK_DIV_I2SOUT0			95
+#define CLK_TOP_APLL12_CK_DIV_I2SOUT1			96
+#define CLK_TOP_APLL12_CK_DIV_FMI2S			97
+#define CLK_TOP_APLL12_CK_DIV_TDMOUT_M			98
+#define CLK_TOP_APLL12_CK_DIV_TDMOUT_B			99
+#define CLK_TOP_MAINPLL_D3				100
+#define CLK_TOP_MAINPLL_D4				101
+#define CLK_TOP_MAINPLL_D4_D2				102
+#define CLK_TOP_MAINPLL_D4_D4				103
+#define CLK_TOP_MAINPLL_D4_D8				104
+#define CLK_TOP_MAINPLL_D5				105
+#define CLK_TOP_MAINPLL_D5_D2				106
+#define CLK_TOP_MAINPLL_D5_D4				107
+#define CLK_TOP_MAINPLL_D5_D8				108
+#define CLK_TOP_MAINPLL_D6				109
+#define CLK_TOP_MAINPLL_D6_D2				110
+#define CLK_TOP_MAINPLL_D6_D4				111
+#define CLK_TOP_MAINPLL_D6_D8				112
+#define CLK_TOP_MAINPLL_D7				113
+#define CLK_TOP_MAINPLL_D7_D2				114
+#define CLK_TOP_MAINPLL_D7_D4				115
+#define CLK_TOP_MAINPLL_D7_D8				116
+#define CLK_TOP_MAINPLL_D9				117
+#define CLK_TOP_UNIVPLL_D2				118
+#define CLK_TOP_UNIVPLL_D3				119
+#define CLK_TOP_UNIVPLL_D4				120
+#define CLK_TOP_UNIVPLL_D4_D2				121
+#define CLK_TOP_UNIVPLL_D4_D4				122
+#define CLK_TOP_UNIVPLL_D4_D8				123
+#define CLK_TOP_UNIVPLL_D5				124
+#define CLK_TOP_UNIVPLL_D5_D2				125
+#define CLK_TOP_UNIVPLL_D5_D4				126
+#define CLK_TOP_UNIVPLL_D6				127
+#define CLK_TOP_UNIVPLL_D6_D2				128
+#define CLK_TOP_UNIVPLL_D6_D4				129
+#define CLK_TOP_UNIVPLL_D6_D8				130
+#define CLK_TOP_UNIVPLL_D6_D16				131
+#define CLK_TOP_UNIVPLL_D7				132
+#define CLK_TOP_UNIVPLL_D7_D2				133
+#define CLK_TOP_UNIVPLL_D7_D3				134
+#define CLK_TOP_LVDSTX_DG_CTS				135
+#define CLK_TOP_UNIVPLL_192M				136
+#define CLK_TOP_UNIVPLL_192M_D2				137
+#define CLK_TOP_UNIVPLL_192M_D4				138
+#define CLK_TOP_UNIVPLL_192M_D8				139
+#define CLK_TOP_UNIVPLL_192M_D10			140
+#define CLK_TOP_UNIVPLL_192M_D16			141
+#define CLK_TOP_UNIVPLL_192M_D32			142
+#define CLK_TOP_APLL1_D2				143
+#define CLK_TOP_APLL1_D4				144
+#define CLK_TOP_APLL1_D8				145
+#define CLK_TOP_APLL1_D3				146
+#define CLK_TOP_APLL2_D2				147
+#define CLK_TOP_APLL2_D4				148
+#define CLK_TOP_APLL2_D8				149
+#define CLK_TOP_APLL2_D3				150
+#define CLK_TOP_MMPLL_D4				151
+#define CLK_TOP_MMPLL_D4_D2				152
+#define CLK_TOP_MMPLL_D4_D4				153
+#define CLK_TOP_VPLL_DPIX				154
+#define CLK_TOP_MMPLL_D5				155
+#define CLK_TOP_MMPLL_D5_D2				156
+#define CLK_TOP_MMPLL_D5_D4				157
+#define CLK_TOP_MMPLL_D6				158
+#define CLK_TOP_MMPLL_D6_D2				159
+#define CLK_TOP_MMPLL_D7				160
+#define CLK_TOP_MMPLL_D9				161
+#define CLK_TOP_TVDPLL1_D2				162
+#define CLK_TOP_TVDPLL1_D4				163
+#define CLK_TOP_TVDPLL1_D8				164
+#define CLK_TOP_TVDPLL1_D16				165
+#define CLK_TOP_TVDPLL2_D2				166
+#define CLK_TOP_TVDPLL2_D4				167
+#define CLK_TOP_TVDPLL2_D8				168
+#define CLK_TOP_TVDPLL2_D16				169
+#define CLK_TOP_ETHPLL_D2				170
+#define CLK_TOP_ETHPLL_D8				171
+#define CLK_TOP_ETHPLL_D10				172
+#define CLK_TOP_MSDCPLL_D2				173
+#define CLK_TOP_VOWPLL                                  174
+#define CLK_TOP_UFSPLL_D2				175
+#define CLK_TOP_F26M_CK_D2				176
+#define CLK_TOP_OSC_D2					177
+#define CLK_TOP_OSC_D4					178
+#define CLK_TOP_OSC_D8					179
+#define CLK_TOP_OSC_D16					180
+#define CLK_TOP_OSC_D3					181
+#define CLK_TOP_OSC_D7					182
+#define CLK_TOP_OSC_D10					183
+#define CLK_TOP_OSC_D20					184
+#define CLK_TOP_FMCNT_P0_EN				185
+#define CLK_TOP_FMCNT_P1_EN				186
+#define CLK_TOP_FMCNT_P2_EN				187
+#define CLK_TOP_FMCNT_P3_EN				188
+#define CLK_TOP_FMCNT_P4_EN				189
+#define CLK_TOP_USB_F26M_CK_EN				190
+#define CLK_TOP_SSPXTP_F26M_CK_EN			191
+#define CLK_TOP_USB2_PHY_RF_P0_EN			192
+#define CLK_TOP_USB2_PHY_RF_P1_EN			193
+#define CLK_TOP_USB2_PHY_RF_P2_EN			194
+#define CLK_TOP_USB2_PHY_RF_P3_EN			195
+#define CLK_TOP_USB2_PHY_RF_P4_EN			196
+#define CLK_TOP_USB2_26M_CK_P0_EN			197
+#define CLK_TOP_USB2_26M_CK_P1_EN			198
+#define CLK_TOP_USB2_26M_CK_P2_EN			199
+#define CLK_TOP_USB2_26M_CK_P3_EN			200
+#define CLK_TOP_USB2_26M_CK_P4_EN			201
+#define CLK_TOP_F26M_CK_EN				202
+#define CLK_TOP_AP2CON_EN				203
+#define CLK_TOP_EINT_N_EN				204
+#define CLK_TOP_TOPCKGEN_FMIPI_CSI_UP26M_CK_EN		205
+#define CLK_TOP_DRAMULP_CK_EN				206
+#define CLK_TOP_EINT_E_EN				207
+#define CLK_TOP_EINT_W_EN				208
+#define CLK_TOP_EINT_S_EN				209
+
+/* INFRACFG_AO */
+#define CLK_IFRAO_CQ_DMA_FPC				0
+#define CLK_IFRAO_DEBUGSYS				1
+#define CLK_IFRAO_DBG_TRACE				2
+#define CLK_IFRAO_CQ_DMA				3
+
+/* APMIXEDSYS */
+#define CLK_APMIXED_ARMPLL_LL				0
+#define CLK_APMIXED_ARMPLL_BL				1
+#define CLK_APMIXED_CCIPLL				2
+#define CLK_APMIXED_MAINPLL				3
+#define CLK_APMIXED_UNIVPLL				4
+#define CLK_APMIXED_MMPLL				5
+#define CLK_APMIXED_MFGPLL				6
+#define CLK_APMIXED_APLL1				7
+#define CLK_APMIXED_APLL2				8
+#define CLK_APMIXED_EMIPLL				9
+#define CLK_APMIXED_APUPLL2				10
+#define CLK_APMIXED_APUPLL				11
+#define CLK_APMIXED_TVDPLL1				12
+#define CLK_APMIXED_TVDPLL2				13
+#define CLK_APMIXED_ETHPLL				14
+#define CLK_APMIXED_MSDCPLL				15
+#define CLK_APMIXED_UFSPLL				16
+
+/* PERICFG_AO */
+#define CLK_PERAO_UART0					0
+#define CLK_PERAO_UART1					1
+#define CLK_PERAO_UART2					2
+#define CLK_PERAO_UART3					3
+#define CLK_PERAO_PWM_H					4
+#define CLK_PERAO_PWM_B					5
+#define CLK_PERAO_PWM_FB1				6
+#define CLK_PERAO_PWM_FB2				7
+#define CLK_PERAO_PWM_FB3				8
+#define CLK_PERAO_PWM_FB4				9
+#define CLK_PERAO_DISP_PWM0				10
+#define CLK_PERAO_DISP_PWM1				11
+#define CLK_PERAO_SPI0_B				12
+#define CLK_PERAO_SPI1_B				13
+#define CLK_PERAO_SPI2_B				14
+#define CLK_PERAO_SPI3_B				15
+#define CLK_PERAO_SPI4_B				16
+#define CLK_PERAO_SPI5_B				17
+#define CLK_PERAO_SPI0_H				18
+#define CLK_PERAO_SPI1_H				19
+#define CLK_PERAO_SPI2_H				20
+#define CLK_PERAO_SPI3_H				21
+#define CLK_PERAO_SPI4_H				22
+#define CLK_PERAO_SPI5_H				23
+#define CLK_PERAO_AXI					24
+#define CLK_PERAO_AHB_APB				25
+#define CLK_PERAO_TL					26
+#define CLK_PERAO_REF					27
+#define CLK_PERAO_I2C					28
+#define CLK_PERAO_DMA_B					29
+#define CLK_PERAO_SSUSB0_REF				30
+#define CLK_PERAO_SSUSB0_FRMCNT				31
+#define CLK_PERAO_SSUSB0_SYS				32
+#define CLK_PERAO_SSUSB0_XHCI				33
+#define CLK_PERAO_SSUSB0_F				34
+#define CLK_PERAO_SSUSB0_H				35
+#define CLK_PERAO_SSUSB1_REF				36
+#define CLK_PERAO_SSUSB1_FRMCNT				37
+#define CLK_PERAO_SSUSB1_SYS				38
+#define CLK_PERAO_SSUSB1_XHCI				39
+#define CLK_PERAO_SSUSB1_F				40
+#define CLK_PERAO_SSUSB1_H				41
+#define CLK_PERAO_SSUSB2_REF				42
+#define CLK_PERAO_SSUSB2_FRMCNT				43
+#define CLK_PERAO_SSUSB2_SYS				44
+#define CLK_PERAO_SSUSB2_XHCI				45
+#define CLK_PERAO_SSUSB2_F				46
+#define CLK_PERAO_SSUSB2_H				47
+#define CLK_PERAO_SSUSB3_REF				48
+#define CLK_PERAO_SSUSB3_FRMCNT				49
+#define CLK_PERAO_SSUSB3_SYS				50
+#define CLK_PERAO_SSUSB3_XHCI				51
+#define CLK_PERAO_SSUSB3_F				52
+#define CLK_PERAO_SSUSB3_H				53
+#define CLK_PERAO_SSUSB4_REF				54
+#define CLK_PERAO_SSUSB4_FRMCNT				55
+#define CLK_PERAO_SSUSB4_SYS				56
+#define CLK_PERAO_SSUSB4_XHCI				57
+#define CLK_PERAO_SSUSB4_F				58
+#define CLK_PERAO_SSUSB4_H				59
+#define CLK_PERAO_MSDC0					60
+#define CLK_PERAO_MSDC0_H				61
+#define CLK_PERAO_MSDC0_FAES				62
+#define CLK_PERAO_MSDC0_MST_F				63
+#define CLK_PERAO_MSDC0_SLV_H				64
+#define CLK_PERAO_MSDC1					65
+#define CLK_PERAO_MSDC1_H				66
+#define CLK_PERAO_MSDC1_MST_F				67
+#define CLK_PERAO_MSDC1_SLV_H				68
+#define CLK_PERAO_MSDC2					69
+#define CLK_PERAO_MSDC2_H				70
+#define CLK_PERAO_MSDC2_MST_F				71
+#define CLK_PERAO_MSDC2_SLV_H				72
+#define CLK_PERAO_SFLASH				73
+#define CLK_PERAO_SFLASH_F				74
+#define CLK_PERAO_SFLASH_H				75
+#define CLK_PERAO_SFLASH_P				76
+#define CLK_PERAO_AUDIO0				77
+#define CLK_PERAO_AUDIO1				78
+#define CLK_PERAO_AUDIO2				79
+#define CLK_PERAO_AUXADC_26M				80
+
+/* UFSCFG_AO_REG */
+#define CLK_UFSCFG_AO_REG_UNIPRO_TX_SYM			0
+#define CLK_UFSCFG_AO_REG_UNIPRO_RX_SYM0		1
+#define CLK_UFSCFG_AO_REG_UNIPRO_RX_SYM1		2
+#define CLK_UFSCFG_AO_REG_UNIPRO_SYS			3
+#define CLK_UFSCFG_AO_REG_U_SAP_CFG			4
+#define CLK_UFSCFG_AO_REG_U_PHY_TOP_AHB_S_BUS		5
+
+/* UFSCFG_PDN_REG */
+#define CLK_UFSCFG_REG_UFSHCI_UFS			0
+#define CLK_UFSCFG_REG_UFSHCI_AES			1
+#define CLK_UFSCFG_REG_UFSHCI_U_AHB			2
+#define CLK_UFSCFG_REG_UFSHCI_U_AXI			3
+
+/* IMP_IIC_WRAP_WS */
+#define CLK_IMPWS_I2C2					0
+
+/* IMP_IIC_WRAP_E */
+#define CLK_IMPE_I2C0					0
+#define CLK_IMPE_I2C1					1
+
+/* IMP_IIC_WRAP_S */
+#define CLK_IMPS_I2C3					0
+#define CLK_IMPS_I2C4					1
+#define CLK_IMPS_I2C5					2
+#define CLK_IMPS_I2C6					3
+
+/* IMP_IIC_WRAP_EN */
+#define CLK_IMPEN_I2C7					0
+#define CLK_IMPEN_I2C8					1
+
+/* MFG */
+#define CLK_MFG_BG3D					0
+
+/* DISPSYS_CONFIG */
+#define CLK_MM_DISP_OVL0_4L				0
+#define CLK_MM_DISP_OVL1_4L				1
+#define CLK_MM_VPP_RSZ0					2
+#define CLK_MM_VPP_RSZ1					3
+#define CLK_MM_DISP_RDMA0				4
+#define CLK_MM_DISP_RDMA1				5
+#define CLK_MM_DISP_COLOR0				6
+#define CLK_MM_DISP_COLOR1				7
+#define CLK_MM_DISP_CCORR0				8
+#define CLK_MM_DISP_CCORR1				9
+#define CLK_MM_DISP_CCORR2				10
+#define CLK_MM_DISP_CCORR3				11
+#define CLK_MM_DISP_AAL0				12
+#define CLK_MM_DISP_AAL1				13
+#define CLK_MM_DISP_GAMMA0				14
+#define CLK_MM_DISP_GAMMA1				15
+#define CLK_MM_DISP_DITHER0				16
+#define CLK_MM_DISP_DITHER1				17
+#define CLK_MM_DISP_DSC_WRAP0				18
+#define CLK_MM_VPP_MERGE0				19
+#define CLK_MMSYS_0_DISP_DVO				20
+#define CLK_MMSYS_0_DISP_DSI0				21
+#define CLK_MM_DP_INTF0					22
+#define CLK_MM_DPI0					23
+#define CLK_MM_DISP_WDMA0				24
+#define CLK_MM_DISP_WDMA1				25
+#define CLK_MM_DISP_FAKE_ENG0				26
+#define CLK_MM_DISP_FAKE_ENG1				27
+#define CLK_MM_SMI_LARB					28
+#define CLK_MM_DISP_MUTEX0				29
+#define CLK_MM_DIPSYS_CONFIG				30
+#define CLK_MM_DUMMY					31
+#define CLK_MMSYS_1_DISP_DSI0				32
+#define CLK_MMSYS_1_LVDS_ENCODER			33
+#define CLK_MMSYS_1_DPI0				34
+#define CLK_MMSYS_1_DISP_DVO				35
+#define CLK_MM_DP_INTF					36
+#define CLK_MMSYS_1_LVDS_ENCODER_CTS			37
+#define CLK_MMSYS_1_DISP_DVO_AVT			38
+
+/* IMGSYS1 */
+#define CLK_IMGSYS1_LARB9				0
+#define CLK_IMGSYS1_LARB11				1
+#define CLK_IMGSYS1_DIP					2
+#define CLK_IMGSYS1_GALS				3
+
+/* IMGSYS2 */
+#define CLK_IMGSYS2_LARB9				0
+#define CLK_IMGSYS2_LARB11				1
+#define CLK_IMGSYS2_MFB					2
+#define CLK_IMGSYS2_WPE					3
+#define CLK_IMGSYS2_MSS					4
+#define CLK_IMGSYS2_GALS				5
+
+/* VDEC_CORE */
+#define CLK_VDEC_CORE_LARB_CKEN				0
+#define CLK_VDEC_CORE_VDEC_CKEN				1
+#define CLK_VDEC_CORE_VDEC_ACTIVE			2
+
+/* VENC_GCON */
+#define CLK_VEN1_CKE0_LARB				0
+#define CLK_VEN1_CKE1_VENC				1
+#define CLK_VEN1_CKE2_JPGENC				2
+#define CLK_VEN1_CKE3_JPGDEC				3
+#define CLK_VEN1_CKE4_JPGDEC_C1				4
+#define CLK_VEN1_CKE5_GALS				5
+#define CLK_VEN1_CKE6_GALS_SRAM				6
+
+/* VLPCFG_REG */
+#define CLK_VLPCFG_REG_SCP				0
+#define CLK_VLPCFG_REG_RG_R_APXGPT_26M			1
+#define CLK_VLPCFG_REG_DPMSRCK_TEST			2
+#define CLK_VLPCFG_REG_RG_DPMSRRTC_TEST			3
+#define CLK_VLPCFG_REG_DPMSRULP_TEST			4
+#define CLK_VLPCFG_REG_SPMI_P_MST			5
+#define CLK_VLPCFG_REG_SPMI_P_MST_32K			6
+#define CLK_VLPCFG_REG_PMIF_SPMI_P_SYS			7
+#define CLK_VLPCFG_REG_PMIF_SPMI_P_TMR			8
+#define CLK_VLPCFG_REG_PMIF_SPMI_M_SYS			9
+#define CLK_VLPCFG_REG_PMIF_SPMI_M_TMR			10
+#define CLK_VLPCFG_REG_DVFSRC				11
+#define CLK_VLPCFG_REG_PWM_VLP				12
+#define CLK_VLPCFG_REG_SRCK				13
+#define CLK_VLPCFG_REG_SSPM_F26M			14
+#define CLK_VLPCFG_REG_SSPM_F32K			15
+#define CLK_VLPCFG_REG_SSPM_ULPOSC			16
+#define CLK_VLPCFG_REG_VLP_32K_COM			17
+#define CLK_VLPCFG_REG_VLP_26M_COM			18
+
+/* VLP_CKSYS */
+#define CLK_VLP_CK_SCP_SEL				0
+#define CLK_VLP_CK_PWRAP_ULPOSC_SEL			1
+#define CLK_VLP_CK_SPMI_P_MST_SEL			2
+#define CLK_VLP_CK_DVFSRC_SEL				3
+#define CLK_VLP_CK_PWM_VLP_SEL				4
+#define CLK_VLP_CK_AXI_VLP_SEL				5
+#define CLK_VLP_CK_SYSTIMER_26M_SEL			6
+#define CLK_VLP_CK_SSPM_SEL				7
+#define CLK_VLP_CK_SSPM_F26M_SEL			8
+#define CLK_VLP_CK_SRCK_SEL				9
+#define CLK_VLP_CK_SCP_SPI_SEL				10
+#define CLK_VLP_CK_SCP_IIC_SEL				11
+#define CLK_VLP_CK_SCP_SPI_HIGH_SPD_SEL			12
+#define CLK_VLP_CK_SCP_IIC_HIGH_SPD_SEL			13
+#define CLK_VLP_CK_SSPM_ULPOSC_SEL			14
+#define CLK_VLP_CK_APXGPT_26M_SEL			15
+#define CLK_VLP_CK_VADSP_SEL				16
+#define CLK_VLP_CK_VADSP_VOWPLL_SEL			17
+#define CLK_VLP_CK_VADSP_UARTHUB_BCLK_SEL		18
+#define CLK_VLP_CK_CAMTG0_SEL				19
+#define CLK_VLP_CK_CAMTG1_SEL				20
+#define CLK_VLP_CK_CAMTG2_SEL				21
+#define CLK_VLP_CK_AUD_ADC_SEL				22
+#define CLK_VLP_CK_KP_IRQ_GEN_SEL			23
+#define CLK_VLP_CK_VADSYS_VLP_26M_EN			24
+#define CLK_VLP_CK_SEJ_13M_EN				25
+#define CLK_VLP_CK_SEJ_26M_EN				26
+#define CLK_VLP_CK_FMIPI_CSI_UP26M_CK_EN		27
+
+/* SCP_IIC */
+#define CLK_SCP_IIC_I2C0_W1S				0
+#define CLK_SCP_IIC_I2C1_W1S				1
+
+/* SCP */
+#define CLK_SCP_SET_SPI0				0
+#define CLK_SCP_SET_SPI1				1
+
+/* CAMSYS_MAIN */
+#define CLK_CAM_M_LARB13				0
+#define CLK_CAM_M_LARB14				1
+#define CLK_CAM_M_CAMSYS_MAIN_CAM			2
+#define CLK_CAM_M_CAMSYS_MAIN_CAMTG			3
+#define CLK_CAM_M_SENINF				4
+#define CLK_CAM_M_CAMSV1				5
+#define CLK_CAM_M_CAMSV2				6
+#define CLK_CAM_M_CAMSV3				7
+#define CLK_CAM_M_FAKE_ENG				8
+#define CLK_CAM_M_CAM2MM_GALS				9
+#define CLK_CAM_M_CAMSV4				10
+#define CLK_CAM_M_PDA					11
+
+/* CAMSYS_RAWA */
+#define CLK_CAM_RA_CAMSYS_RAWA_LARBX			0
+#define CLK_CAM_RA_CAMSYS_RAWA_CAM			1
+#define CLK_CAM_RA_CAMSYS_RAWA_CAMTG			2
+
+/* CAMSYS_RAWB */
+#define CLK_CAM_RB_CAMSYS_RAWB_LARBX			0
+#define CLK_CAM_RB_CAMSYS_RAWB_CAM			1
+#define CLK_CAM_RB_CAMSYS_RAWB_CAMTG			2
+
+/* IPESYS */
+#define CLK_IPE_LARB19					0
+#define CLK_IPE_LARB20					1
+#define CLK_IPE_SMI_SUBCOM				2
+#define CLK_IPE_FD					3
+#define CLK_IPE_FE					4
+#define CLK_IPE_RSC					5
+#define CLK_IPESYS_GALS					6
+
+/* VLPCFG_AO_REG */
+#define CLK_VLPCFG_AO_APEINT_RX				0
+
+/* DVFSRC_TOP */
+#define CLK_DVFSRC_TOP_DVFSRC_EN			0
+
+/* MMINFRA_CONFIG */
+#define CLK_MMINFRA_GCE_D				0
+#define CLK_MMINFRA_GCE_M				1
+#define CLK_MMINFRA_SMI					2
+#define CLK_MMINFRA_GCE_26M				3
+
+/* GCE_D */
+#define CLK_GCE_D_TOP					0
+
+/* GCE_M */
+#define CLK_GCE_M_TOP					0
+
+/* MDPSYS_CONFIG */
+#define CLK_MDP_MUTEX0					0
+#define CLK_MDP_APB_BUS					1
+#define CLK_MDP_SMI0					2
+#define CLK_MDP_RDMA0					3
+#define CLK_MDP_RDMA2					4
+#define CLK_MDP_HDR0					5
+#define CLK_MDP_AAL0					6
+#define CLK_MDP_RSZ0					7
+#define CLK_MDP_TDSHP0					8
+#define CLK_MDP_COLOR0					9
+#define CLK_MDP_WROT0					10
+#define CLK_MDP_FAKE_ENG0				11
+#define CLK_MDPSYS_CONFIG				12
+#define CLK_MDP_RDMA1					13
+#define CLK_MDP_RDMA3					14
+#define CLK_MDP_HDR1					15
+#define CLK_MDP_AAL1					16
+#define CLK_MDP_RSZ1					17
+#define CLK_MDP_TDSHP1					18
+#define CLK_MDP_COLOR1					19
+#define CLK_MDP_WROT1					20
+#define CLK_MDP_RSZ2					21
+#define CLK_MDP_WROT2					22
+#define CLK_MDP_RSZ3					23
+#define CLK_MDP_WROT3					24
+#define CLK_MDP_BIRSZ0					25
+#define CLK_MDP_BIRSZ1					26
+
+/* DBGAO */
+#define CLK_DBGAO_ATB_EN				0
+
+/* DEM */
+#define CLK_DEM_ATB_EN					0
+#define CLK_DEM_BUSCLK_EN				1
+#define CLK_DEM_SYSCLK_EN				2
+
+#endif /* _DT_BINDINGS_CLK_MT8189_H */
-- 
2.45.2



From irving-ch.lin at mediatek.com  Sun Dec 14 19:49:13 2025
From: irving-ch.lin at mediatek.com (irving.ch.lin)
Date: Mon, 15 Dec 2025 11:49:13 +0800
Subject: [PATCH v4 04/21] clk: mediatek: Add MT8189 apmixedsys clock support
In-Reply-To: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
References: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
Message-ID: <20251215034944.2973003-5-irving-ch.lin@mediatek.com>

From: Irving-CH Lin <irving-ch.lin at mediatek.com>

Add support for the MT8189 apmixedsys clock controller, which provides
PLLs generated from SoC 26m.

Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
---
 drivers/clk/mediatek/Kconfig                 |  13 ++
 drivers/clk/mediatek/Makefile                |   1 +
 drivers/clk/mediatek/clk-mt8189-apmixedsys.c | 192 +++++++++++++++++++
 3 files changed, 206 insertions(+)
 create mode 100644 drivers/clk/mediatek/clk-mt8189-apmixedsys.c

diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
index 0e8dd82aa84e..2c898fd8a34c 100644
--- a/drivers/clk/mediatek/Kconfig
+++ b/drivers/clk/mediatek/Kconfig
@@ -815,6 +815,19 @@ config COMMON_CLK_MT8188_WPESYS
 	help
 	  This driver supports MediaTek MT8188 Warp Engine clocks.
 
+config COMMON_CLK_MT8189
+	bool "Clock driver for MediaTek MT8189"
+	depends on ARM64 || COMPILE_TEST
+	select COMMON_CLK_MEDIATEK
+	select COMMON_CLK_MEDIATEK_FHCTL
+	default ARCH_MEDIATEK
+	help
+	  Enable this option to support the clock management for MediaTek MT8189 SoC. This
+	  includes handling of all primary clock functions and features specific to the MT8189
+	  platform. Enabling this driver ensures that the system's clock functionality aligns
+	  with the MediaTek MT8189 hardware capabilities, providing efficient management of
+	  clock speeds and power consumption.
+
 config COMMON_CLK_MT8192
 	tristate "Clock driver for MediaTek MT8192"
 	depends on ARM64 || COMPILE_TEST
diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
index d8736a060dbd..66577ccb9b93 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -123,6 +123,7 @@ obj-$(CONFIG_COMMON_CLK_MT8188_VDOSYS) += clk-mt8188-vdo0.o clk-mt8188-vdo1.o
 obj-$(CONFIG_COMMON_CLK_MT8188_VENCSYS) += clk-mt8188-venc.o
 obj-$(CONFIG_COMMON_CLK_MT8188_VPPSYS) += clk-mt8188-vpp0.o clk-mt8188-vpp1.o
 obj-$(CONFIG_COMMON_CLK_MT8188_WPESYS) += clk-mt8188-wpe.o
+obj-$(CONFIG_COMMON_CLK_MT8189) += clk-mt8189-apmixedsys.o
 obj-$(CONFIG_COMMON_CLK_MT8192) += clk-mt8192-apmixedsys.o clk-mt8192.o
 obj-$(CONFIG_COMMON_CLK_MT8192_AUDSYS) += clk-mt8192-aud.o
 obj-$(CONFIG_COMMON_CLK_MT8192_CAMSYS) += clk-mt8192-cam.o
diff --git a/drivers/clk/mediatek/clk-mt8189-apmixedsys.c b/drivers/clk/mediatek/clk-mt8189-apmixedsys.c
new file mode 100644
index 000000000000..1299765e4f14
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8189-apmixedsys.c
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Qiqi Wang <qiqi.wang at mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "clk-fhctl.h"
+#include "clk-mtk.h"
+#include "clk-pll.h"
+
+#include <dt-bindings/clock/mediatek,mt8189-clk.h>
+
+#define MT8189_PLL_FMAX		(3800UL * MHZ)
+#define MT8189_PLL_FMIN		(1500UL * MHZ)
+#define MT8189_PLLEN_OFS	0x70
+#define MT8189_INTEGER_BITS	8
+
+#define PLL_SETCLR(_id, _name, _reg, _en_setclr_bit,		\
+			_rstb_setclr_bit, _flags, _pd_reg,	\
+			_pd_shift, _tuner_reg, _tuner_en_reg,	\
+			_tuner_en_bit, _pcw_reg, _pcw_shift,	\
+			_pcwbits) {				\
+		.id = _id,					\
+		.name = _name,					\
+		.en_reg = MT8189_PLLEN_OFS,			\
+		.reg = _reg,					\
+		.pll_en_bit = _en_setclr_bit,			\
+		.rst_bar_mask = BIT(_rstb_setclr_bit),		\
+		.flags = _flags,				\
+		.fmax = MT8189_PLL_FMAX,			\
+		.fmin = MT8189_PLL_FMIN,			\
+		.pd_reg = _pd_reg,				\
+		.pd_shift = _pd_shift,				\
+		.tuner_reg = _tuner_reg,			\
+		.tuner_en_reg = _tuner_en_reg,			\
+		.tuner_en_bit = _tuner_en_bit,			\
+		.pcw_reg = _pcw_reg,				\
+		.pcw_shift = _pcw_shift,			\
+		.pcwbits = _pcwbits,				\
+		.pcwibits = MT8189_INTEGER_BITS,		\
+	}
+
+static const struct mtk_pll_data apmixed_plls[] = {
+	PLL_SETCLR(CLK_APMIXED_ARMPLL_LL, "armpll-ll", 0x204, 18,
+		   0, PLL_AO, 0x208, 24, 0, 0, 0, 0x208, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_ARMPLL_BL, "armpll-bl", 0x214, 17,
+		   0, PLL_AO, 0x218, 24, 0, 0, 0, 0x218, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_CCIPLL, "ccipll", 0x224, 16,
+		   0, PLL_AO, 0x228, 24, 0, 0, 0, 0x228, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_MAINPLL, "mainpll", 0x304, 15,
+		   23, HAVE_RST_BAR | PLL_AO,
+		   0x308, 24, 0, 0, 0, 0x308, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_UNIVPLL, "univpll", 0x314, 14,
+		   23, HAVE_RST_BAR, 0x318, 24, 0, 0, 0, 0x318, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_MMPLL, "mmpll", 0x324, 13,
+		   23, HAVE_RST_BAR, 0x328, 24, 0, 0, 0, 0x328, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_MFGPLL, "mfgpll", 0x504, 7,
+		   0, 0, 0x508, 24, 0, 0, 0, 0x508, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_APLL1, "apll1", 0x404, 11,
+		   0, 0, 0x408, 24, 0x040, 0x00c, 0, 0x40c, 0, 32),
+	PLL_SETCLR(CLK_APMIXED_APLL2, "apll2", 0x418, 10,
+		   0, 0, 0x41c, 24, 0x044, 0x00c, 1, 0x420, 0, 32),
+	PLL_SETCLR(CLK_APMIXED_EMIPLL, "emipll", 0x334, 12,
+		   0, PLL_AO, 0x338, 24, 0, 0, 0, 0x338, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_APUPLL2, "apupll2", 0x614, 2,
+		   0, 0, 0x618, 24, 0, 0, 0, 0x618, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_APUPLL, "apupll", 0x604, 3,
+		   0, 0, 0x608, 24, 0, 0, 0, 0x608, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_TVDPLL1, "tvdpll1", 0x42c, 9,
+		   0, 0, 0x430, 24, 0, 0, 0, 0x430, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_TVDPLL2, "tvdpll2", 0x43c, 8,
+		   0, 0, 0x440, 24, 0, 0, 0, 0x440, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_ETHPLL, "ethpll", 0x514, 6,
+		   0, 0, 0x518, 24, 0, 0, 0, 0x518, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_MSDCPLL, "msdcpll", 0x524, 5,
+		   0, 0, 0x528, 24, 0, 0, 0, 0x528, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_UFSPLL, "ufspll", 0x534, 4,
+		   0, 0, 0x538, 24, 0, 0, 0, 0x538, 0, 22),
+};
+
+#define FH(_pllid, _fhid, _offset) {				\
+		.data = {					\
+			.pll_id = _pllid,			\
+			.fh_id = _fhid,				\
+			.fh_ver = FHCTL_PLLFH_V2,		\
+			.fhx_offset = _offset,			\
+			.dds_mask = GENMASK(21, 0),		\
+			.slope0_value = 0x6003c97,		\
+			.slope1_value = 0x6003c97,		\
+			.sfstrx_en = BIT(2),			\
+			.frddsx_en = BIT(1),			\
+			.fhctlx_en = BIT(0),			\
+			.tgl_org = BIT(31),			\
+			.dvfs_tri = BIT(31),			\
+			.pcwchg = BIT(31),			\
+			.dt_val = 0x0,				\
+			.df_val = 0x9,				\
+			.updnlmt_shft = 16,			\
+			.msk_frddsx_dys = GENMASK(23, 20),	\
+			.msk_frddsx_dts = GENMASK(19, 16),	\
+		},						\
+	}
+
+static struct mtk_pllfh_data pllfhs[] = {
+	FH(CLK_APMIXED_ARMPLL_LL, 0, 0x003C),
+	FH(CLK_APMIXED_ARMPLL_BL, 1, 0x0050),
+	FH(CLK_APMIXED_CCIPLL, 2, 0x0064),
+	FH(CLK_APMIXED_MAINPLL, 3, 0x0078),
+	FH(CLK_APMIXED_MMPLL, 4, 0x008C),
+	FH(CLK_APMIXED_MFGPLL, 5, 0x00A0),
+	FH(CLK_APMIXED_EMIPLL, 6, 0x00B4),
+	FH(CLK_APMIXED_TVDPLL1, 7, 0x00C8),
+	FH(CLK_APMIXED_TVDPLL2, 8, 0x00DC),
+	FH(CLK_APMIXED_MSDCPLL, 9, 0x00F0),
+	FH(CLK_APMIXED_UFSPLL, 10, 0x0104),
+	FH(CLK_APMIXED_APUPLL, 11, 0x0118),
+	FH(CLK_APMIXED_APUPLL2, 12, 0x012c),
+};
+
+static const struct of_device_id of_match_clk_mt8189_apmixed[] = {
+	{ .compatible = "mediatek,mt8189-apmixedsys" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_match_clk_mt8189_apmixed);
+
+static int clk_mt8189_apmixed_probe(struct platform_device *pdev)
+{
+	int r;
+	struct clk_hw_onecell_data *clk_data;
+	struct device_node *node = pdev->dev.of_node;
+	const u8 *fhctl_node = "mediatek,mt8189-fhctl";
+
+	clk_data = mtk_alloc_clk_data(ARRAY_SIZE(apmixed_plls));
+	if (!clk_data)
+		return -ENOMEM;
+
+	fhctl_parse_dt(fhctl_node, pllfhs, ARRAY_SIZE(pllfhs));
+
+	r = mtk_clk_register_pllfhs(node, apmixed_plls, ARRAY_SIZE(apmixed_plls),
+				    pllfhs, ARRAY_SIZE(pllfhs), clk_data);
+	if (r)
+		goto free_apmixed_data;
+
+	r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+	if (r)
+		goto unregister_plls;
+
+	platform_set_drvdata(pdev, clk_data);
+
+	return 0;
+
+unregister_plls:
+	mtk_clk_unregister_plls(apmixed_plls, ARRAY_SIZE(apmixed_plls),
+				clk_data);
+free_apmixed_data:
+	mtk_free_clk_data(clk_data);
+	return r;
+}
+
+static void clk_mt8189_apmixed_remove(struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev);
+
+	of_clk_del_provider(node);
+	mtk_clk_unregister_pllfhs(apmixed_plls, ARRAY_SIZE(apmixed_plls), pllfhs,
+				  ARRAY_SIZE(pllfhs), clk_data);
+	mtk_free_clk_data(clk_data);
+}
+
+static struct platform_driver clk_mt8189_apmixed_drv = {
+	.probe = clk_mt8189_apmixed_probe,
+	.remove = clk_mt8189_apmixed_remove,
+	.driver = {
+		.name = "clk-mt8189-apmixed",
+		.of_match_table = of_match_clk_mt8189_apmixed,
+	},
+};
+
+module_platform_driver(clk_mt8189_apmixed_drv);
+MODULE_DESCRIPTION("MediaTek MT8189 apmixed clocks driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



From irving-ch.lin at mediatek.com  Sun Dec 14 19:49:26 2025
From: irving-ch.lin at mediatek.com (irving.ch.lin)
Date: Mon, 15 Dec 2025 11:49:26 +0800
Subject: [PATCH v4 17/21] clk: mediatek: Add MT8189 scp clock support
In-Reply-To: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
References: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
Message-ID: <20251215034944.2973003-18-irving-ch.lin@mediatek.com>

From: Irving-CH Lin <irving-ch.lin at mediatek.com>

Add support for the MT8189 scp clock controller,
which provides clock gate control for System Control Processor.

Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
---
 drivers/clk/mediatek/Kconfig          | 10 ++++
 drivers/clk/mediatek/Makefile         |  1 +
 drivers/clk/mediatek/clk-mt8189-scp.c | 73 +++++++++++++++++++++++++++
 3 files changed, 84 insertions(+)
 create mode 100644 drivers/clk/mediatek/clk-mt8189-scp.c

diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
index 8b1f358457d8..2cc1a28436f1 100644
--- a/drivers/clk/mediatek/Kconfig
+++ b/drivers/clk/mediatek/Kconfig
@@ -929,6 +929,16 @@ config COMMON_CLK_MT8189_MMSYS
 	  ensure that these components receive the correct clock frequencies
 	  for proper operation.
 
+config COMMON_CLK_MT8189_SCP
+	tristate "Clock driver for MediaTek MT8189 scp"
+	depends on COMMON_CLK_MT8189
+	default COMMON_CLK_MT8189
+	help
+	  Enable this to support the clock framework for the System Control
+	  Processor (SCP) in the MediaTek MT8189 SoC. This includes clock
+	  management for SCP-related features, ensuring proper clock
+	  distribution and gating for power efficiency and functionality.
+
 config COMMON_CLK_MT8192
 	tristate "Clock driver for MediaTek MT8192"
 	depends on ARM64 || COMPILE_TEST
diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
index 21a9e6264b84..819c67395e1b 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -134,6 +134,7 @@ obj-$(CONFIG_COMMON_CLK_MT8189_IMG) += clk-mt8189-img.o
 obj-$(CONFIG_COMMON_CLK_MT8189_MDPSYS) += clk-mt8189-mdpsys.o
 obj-$(CONFIG_COMMON_CLK_MT8189_MFG) += clk-mt8189-mfg.o
 obj-$(CONFIG_COMMON_CLK_MT8189_MMSYS) += clk-mt8189-dispsys.o
+obj-$(CONFIG_COMMON_CLK_MT8189_SCP) += clk-mt8189-scp.o
 obj-$(CONFIG_COMMON_CLK_MT8192) += clk-mt8192-apmixedsys.o clk-mt8192.o
 obj-$(CONFIG_COMMON_CLK_MT8192_AUDSYS) += clk-mt8192-aud.o
 obj-$(CONFIG_COMMON_CLK_MT8192_CAMSYS) += clk-mt8192-cam.o
diff --git a/drivers/clk/mediatek/clk-mt8189-scp.c b/drivers/clk/mediatek/clk-mt8189-scp.c
new file mode 100644
index 000000000000..efa00de90215
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8189-scp.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Qiqi Wang <qiqi.wang at mediatek.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include "clk-mtk.h"
+#include "clk-gate.h"
+
+#include <dt-bindings/clock/mediatek,mt8189-clk.h>
+
+static const struct mtk_gate_regs scp_cg_regs = {
+	.set_ofs = 0x4,
+	.clr_ofs = 0x8,
+	.sta_ofs = 0x4,
+};
+
+#define GATE_SCP(_id, _name, _parent, _shift)		\
+	GATE_MTK(_id, _name, _parent, &scp_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv)
+
+static const struct mtk_gate scp_clks[] = {
+	GATE_SCP(CLK_SCP_SET_SPI0, "scp_set_spi0", "clk26m", 0),
+	GATE_SCP(CLK_SCP_SET_SPI1, "scp_set_spi1", "clk26m", 1),
+};
+
+static const struct mtk_clk_desc scp_mcd = {
+	.clks = scp_clks,
+	.num_clks = ARRAY_SIZE(scp_clks),
+};
+
+static const struct mtk_gate_regs scp_iic_cg_regs = {
+	.set_ofs = 0x8,
+	.clr_ofs = 0x4,
+	.sta_ofs = 0x0,
+};
+
+#define GATE_SCP_IIC(_id, _name, _parent, _shift)	\
+	GATE_MTK(_id, _name, _parent, &scp_iic_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv)
+
+static const struct mtk_gate scp_iic_clks[] = {
+	GATE_SCP_IIC(CLK_SCP_IIC_I2C0_W1S, "scp_iic_i2c0_w1s", "vlp_scp_iic_sel", 0),
+	GATE_SCP_IIC(CLK_SCP_IIC_I2C1_W1S, "scp_iic_i2c1_w1s", "vlp_scp_iic_sel", 1),
+};
+
+static const struct mtk_clk_desc scp_iic_mcd = {
+	.clks = scp_iic_clks,
+	.num_clks = ARRAY_SIZE(scp_iic_clks),
+};
+
+static const struct of_device_id of_match_clk_mt8189_scp[] = {
+	{ .compatible = "mediatek,mt8189-scp-clk", .data = &scp_mcd },
+	{ .compatible = "mediatek,mt8189-scp-i2c-clk", .data = &scp_iic_mcd },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_match_clk_mt8189_scp);
+
+static struct platform_driver clk_mt8189_scp_drv = {
+	.probe = mtk_clk_simple_probe,
+	.remove = mtk_clk_simple_remove,
+	.driver = {
+		.name = "clk-mt8189-scp",
+		.of_match_table = of_match_clk_mt8189_scp,
+	},
+};
+
+module_platform_driver(clk_mt8189_scp_drv);
+MODULE_DESCRIPTION("MediaTek MT8189 scp clocks driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



From irving-ch.lin at mediatek.com  Sun Dec 14 19:49:29 2025
From: irving-ch.lin at mediatek.com (irving.ch.lin)
Date: Mon, 15 Dec 2025 11:49:29 +0800
Subject: [PATCH v4 20/21] pmdomain: mediatek: Add bus protect control flow for MT8189
In-Reply-To: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
References: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
Message-ID: <20251215034944.2973003-21-irving-ch.lin@mediatek.com>

From: Irving-CH Lin <irving-ch.lin at mediatek.com>

In MT8189 mminfra power domain, the bus protect policy separates
into two parts, one is set before subsys clocks enabled, and another
need to enable after subsys clocks enable.

Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
---
 drivers/pmdomain/mediatek/mtk-pm-domains.c | 31 ++++++++++++++++++----
 drivers/pmdomain/mediatek/mtk-pm-domains.h |  5 ++++
 2 files changed, 31 insertions(+), 5 deletions(-)

diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c
index 80561d27f2b2..bfa3ae55e8fd 100644
--- a/drivers/pmdomain/mediatek/mtk-pm-domains.c
+++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c
@@ -250,7 +250,7 @@ static int scpsys_bus_protect_set(struct scpsys_domain *pd,
 					MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
 }
 
-static int scpsys_bus_protect_enable(struct scpsys_domain *pd)
+static int scpsys_bus_protect_enable(struct scpsys_domain *pd, u8 flags)
 {
 	for (int i = 0; i < SPM_MAX_BUS_PROT_DATA; i++) {
 		const struct scpsys_bus_prot_data *bpd = &pd->data->bp_cfg[i];
@@ -259,6 +259,10 @@ static int scpsys_bus_protect_enable(struct scpsys_domain *pd)
 		if (!bpd->bus_prot_set_clr_mask)
 			break;
 
+		if ((bpd->flags & BUS_PROT_IGNORE_SUBCLK) !=
+		    (flags & BUS_PROT_IGNORE_SUBCLK))
+			continue;
+
 		if (bpd->flags & BUS_PROT_INVERTED)
 			ret = scpsys_bus_protect_clear(pd, bpd);
 		else
@@ -270,7 +274,7 @@ static int scpsys_bus_protect_enable(struct scpsys_domain *pd)
 	return 0;
 }
 
-static int scpsys_bus_protect_disable(struct scpsys_domain *pd)
+static int scpsys_bus_protect_disable(struct scpsys_domain *pd, u8 flags)
 {
 	for (int i = SPM_MAX_BUS_PROT_DATA - 1; i >= 0; i--) {
 		const struct scpsys_bus_prot_data *bpd = &pd->data->bp_cfg[i];
@@ -279,6 +283,10 @@ static int scpsys_bus_protect_disable(struct scpsys_domain *pd)
 		if (!bpd->bus_prot_set_clr_mask)
 			continue;
 
+		if ((bpd->flags & BUS_PROT_IGNORE_SUBCLK) !=
+		    (flags & BUS_PROT_IGNORE_SUBCLK))
+			continue;
+
 		if (bpd->flags & BUS_PROT_INVERTED)
 			ret = scpsys_bus_protect_set(pd, bpd);
 		else
@@ -632,6 +640,15 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
 	if (ret)
 		goto err_pwr_ack;
 
+	/*
+	 * In MT8189 mminfra power domain, the bus protect policy separates
+	 * into two parts, one is set before subsys clocks enabled, and another
+	 * need to enable after subsys clocks enable.
+	 */
+	ret = scpsys_bus_protect_disable(pd, BUS_PROT_IGNORE_SUBCLK);
+	if (ret < 0)
+		goto err_pwr_ack;
+
 	/*
 	 * In few Mediatek platforms(e.g. MT6779), the bus protect policy is
 	 * stricter, which leads to bus protect release must be prior to bus
@@ -648,7 +665,7 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
 	if (ret < 0)
 		goto err_disable_subsys_clks;
 
-	ret = scpsys_bus_protect_disable(pd);
+	ret = scpsys_bus_protect_disable(pd, 0);
 	if (ret < 0)
 		goto err_disable_sram;
 
@@ -662,7 +679,7 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
 	return 0;
 
 err_enable_bus_protect:
-	scpsys_bus_protect_enable(pd);
+	scpsys_bus_protect_enable(pd, 0);
 err_disable_sram:
 	scpsys_sram_disable(pd);
 err_disable_subsys_clks:
@@ -683,7 +700,7 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
 	bool tmp;
 	int ret;
 
-	ret = scpsys_bus_protect_enable(pd);
+	ret = scpsys_bus_protect_enable(pd, 0);
 	if (ret < 0)
 		return ret;
 
@@ -697,6 +714,10 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
 
 	clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks);
 
+	ret = scpsys_bus_protect_enable(pd, BUS_PROT_IGNORE_SUBCLK);
+	if (ret < 0)
+		return ret;
+
 	if (MTK_SCPD_CAPS(pd, MTK_SCPD_MODEM_PWRSEQ))
 		scpsys_modem_pwrseq_off(pd);
 	else
diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.h b/drivers/pmdomain/mediatek/mtk-pm-domains.h
index f608e6ec4744..a5dca24cbc2f 100644
--- a/drivers/pmdomain/mediatek/mtk-pm-domains.h
+++ b/drivers/pmdomain/mediatek/mtk-pm-domains.h
@@ -56,6 +56,7 @@ enum scpsys_bus_prot_flags {
 	BUS_PROT_REG_UPDATE = BIT(1),
 	BUS_PROT_IGNORE_CLR_ACK = BIT(2),
 	BUS_PROT_INVERTED = BIT(3),
+	BUS_PROT_IGNORE_SUBCLK = BIT(4),
 };
 
 enum scpsys_bus_prot_block {
@@ -95,6 +96,10 @@ enum scpsys_bus_prot_block {
 		_BUS_PROT(_hwip, _mask, _set, _clr, _mask, _sta,	\
 			  BUS_PROT_REG_UPDATE)
 
+#define BUS_PROT_WR_IGN_SUBCLK(_hwip, _mask, _set, _clr, _sta)		\
+		_BUS_PROT(_hwip, _mask, _set, _clr, _mask, _sta,	\
+			  BUS_PROT_IGNORE_CLR_ACK | BUS_PROT_IGNORE_SUBCLK)
+
 #define BUS_PROT_INFRA_UPDATE_TOPAXI(_mask)			\
 		BUS_PROT_UPDATE(INFRA, _mask,			\
 				INFRA_TOPAXI_PROTECTEN,		\
-- 
2.45.2



From irving-ch.lin at mediatek.com  Sun Dec 14 19:49:20 2025
From: irving-ch.lin at mediatek.com (irving.ch.lin)
Date: Mon, 15 Dec 2025 11:49:20 +0800
Subject: [PATCH v4 11/21] clk: mediatek: Add MT8189 dvfsrc clock support
In-Reply-To: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
References: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
Message-ID: <20251215034944.2973003-12-irving-ch.lin@mediatek.com>

From: Irving-CH Lin <irving-ch.lin at mediatek.com>

Add support for the MT8189 dvfsrc clock controller,
which provides clock gate control for dram dvfs.

Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
---
 drivers/clk/mediatek/Kconfig             | 10 +++++
 drivers/clk/mediatek/Makefile            |  1 +
 drivers/clk/mediatek/clk-mt8189-dvfsrc.c | 54 ++++++++++++++++++++++++
 3 files changed, 65 insertions(+)
 create mode 100644 drivers/clk/mediatek/clk-mt8189-dvfsrc.c

diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
index c707b224dccd..76c9391bee69 100644
--- a/drivers/clk/mediatek/Kconfig
+++ b/drivers/clk/mediatek/Kconfig
@@ -860,6 +860,16 @@ config COMMON_CLK_MT8189_DBGAO
 	  vcore debug system clocks. If you want to control its clocks, say Y or M
 	  to include this driver in your kernel build.
 
+config COMMON_CLK_MT8189_DVFSRC
+	tristate "Clock driver for MediaTek MT8189 dvfsrc"
+	depends on COMMON_CLK_MT8189
+	default COMMON_CLK_MT8189
+	help
+	  Enable this to support the clock management for the dvfsrc
+	  on MediaTek MT8189 SoCs. This includes enabling and disabling
+	  vcore dvfs clocks. If you want to control its clocks, say Y or M
+	  to include this driver in your kernel build.
+
 config COMMON_CLK_MT8192
 	tristate "Clock driver for MediaTek MT8192"
 	depends on ARM64 || COMPILE_TEST
diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
index eabe2cab4b8d..3a8dad865c97 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -128,6 +128,7 @@ obj-$(CONFIG_COMMON_CLK_MT8189) += clk-mt8189-apmixedsys.o clk-mt8189-topckgen.o
 obj-$(CONFIG_COMMON_CLK_MT8189_BUS) += clk-mt8189-bus.o
 obj-$(CONFIG_COMMON_CLK_MT8189_CAM) += clk-mt8189-cam.o
 obj-$(CONFIG_COMMON_CLK_MT8189_DBGAO) += clk-mt8189-dbgao.o
+obj-$(CONFIG_COMMON_CLK_MT8189_DVFSRC) += clk-mt8189-dvfsrc.o
 obj-$(CONFIG_COMMON_CLK_MT8192) += clk-mt8192-apmixedsys.o clk-mt8192.o
 obj-$(CONFIG_COMMON_CLK_MT8192_AUDSYS) += clk-mt8192-aud.o
 obj-$(CONFIG_COMMON_CLK_MT8192_CAMSYS) += clk-mt8192-cam.o
diff --git a/drivers/clk/mediatek/clk-mt8189-dvfsrc.c b/drivers/clk/mediatek/clk-mt8189-dvfsrc.c
new file mode 100644
index 000000000000..f8ab656af6e6
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8189-dvfsrc.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Qiqi Wang <qiqi.wang at mediatek.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include "clk-mtk.h"
+#include "clk-gate.h"
+
+#include <dt-bindings/clock/mediatek,mt8189-clk.h>
+
+static const struct mtk_gate_regs dvfsrc_top_cg_regs = {
+	.set_ofs = 0x0,
+	.clr_ofs = 0x0,
+	.sta_ofs = 0x0,
+};
+
+#define GATE_DVFSRC_TOP_FLAGS(_id, _name, _parent, _shift, _flags)		\
+	GATE_MTK_FLAGS(_id, _name, _parent, &dvfsrc_top_cg_regs, _shift,	\
+		       &mtk_clk_gate_ops_no_setclr_inv, _flags)
+
+static const struct mtk_gate dvfsrc_top_clks[] = {
+	GATE_DVFSRC_TOP_FLAGS(CLK_DVFSRC_TOP_DVFSRC_EN, "dvfsrc_dvfsrc_en",
+			      "clk26m", 0, CLK_IS_CRITICAL),
+};
+
+static const struct mtk_clk_desc dvfsrc_top_mcd = {
+	.clks = dvfsrc_top_clks,
+	.num_clks = ARRAY_SIZE(dvfsrc_top_clks),
+};
+
+static const struct of_device_id of_match_clk_mt8189_dvfsrc[] = {
+	{ .compatible = "mediatek,mt8189-dvfsrc-top", .data = &dvfsrc_top_mcd },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_match_clk_mt8189_dvfsrc);
+
+static struct platform_driver clk_mt8189_dvfsrc_drv = {
+	.probe = mtk_clk_simple_probe,
+	.remove = mtk_clk_simple_remove,
+	.driver = {
+		.name = "clk-mt8189-dvfsrc",
+		.of_match_table = of_match_clk_mt8189_dvfsrc,
+	},
+};
+
+module_platform_driver(clk_mt8189_dvfsrc_drv);
+MODULE_DESCRIPTION("MediaTek MT8189 dvfsrc clocks driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



From irving-ch.lin at mediatek.com  Sun Dec 14 19:49:28 2025
From: irving-ch.lin at mediatek.com (irving.ch.lin)
Date: Mon, 15 Dec 2025 11:49:28 +0800
Subject: [PATCH v4 19/21] clk: mediatek: Add MT8189 vcodec clock support
In-Reply-To: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
References: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
Message-ID: <20251215034944.2973003-20-irving-ch.lin@mediatek.com>

From: Irving-CH Lin <irving-ch.lin at mediatek.com>

Add support for the MT8189 vcodec clock controller,
which provides clock gate control for video encoder/decoder.

Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
---
 drivers/clk/mediatek/Kconfig             | 10 +++
 drivers/clk/mediatek/Makefile            |  1 +
 drivers/clk/mediatek/clk-mt8189-vcodec.c | 93 ++++++++++++++++++++++++
 3 files changed, 104 insertions(+)
 create mode 100644 drivers/clk/mediatek/clk-mt8189-vcodec.c

diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
index 3ef964b19d97..2ae5966d4c56 100644
--- a/drivers/clk/mediatek/Kconfig
+++ b/drivers/clk/mediatek/Kconfig
@@ -951,6 +951,16 @@ config COMMON_CLK_MT8189_UFS
 	  option if the system includes a UFS device that relies on the MT8189
 	  SoC for clock management.
 
+config COMMON_CLK_MT8189_VCODEC
+	tristate "Clock driver for MediaTek MT8189 vcodec"
+	depends on COMMON_CLK_MT8189
+	default COMMON_CLK_MT8189
+	help
+	  This driver supports the video codec (VCODEC) clocks on the MediaTek
+	  MT8189 SoCs. Enabling this option will allow the system to manage
+	  clocks required for the operation of hardware video encoding and
+	  decoding features provided by the VCODEC unit of the MT8189 platform.
+
 config COMMON_CLK_MT8192
 	tristate "Clock driver for MediaTek MT8192"
 	depends on ARM64 || COMPILE_TEST
diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
index 4179808dba7b..614371c92e81 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -136,6 +136,7 @@ obj-$(CONFIG_COMMON_CLK_MT8189_MFG) += clk-mt8189-mfg.o
 obj-$(CONFIG_COMMON_CLK_MT8189_MMSYS) += clk-mt8189-dispsys.o
 obj-$(CONFIG_COMMON_CLK_MT8189_SCP) += clk-mt8189-scp.o
 obj-$(CONFIG_COMMON_CLK_MT8189_UFS) += clk-mt8189-ufs.o
+obj-$(CONFIG_COMMON_CLK_MT8189_VCODEC) += clk-mt8189-vcodec.o
 obj-$(CONFIG_COMMON_CLK_MT8192) += clk-mt8192-apmixedsys.o clk-mt8192.o
 obj-$(CONFIG_COMMON_CLK_MT8192_AUDSYS) += clk-mt8192-aud.o
 obj-$(CONFIG_COMMON_CLK_MT8192_CAMSYS) += clk-mt8192-cam.o
diff --git a/drivers/clk/mediatek/clk-mt8189-vcodec.c b/drivers/clk/mediatek/clk-mt8189-vcodec.c
new file mode 100644
index 000000000000..87b01e432474
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8189-vcodec.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Qiqi Wang <qiqi.wang at mediatek.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include "clk-mtk.h"
+#include "clk-gate.h"
+
+#include <dt-bindings/clock/mediatek,mt8189-clk.h>
+
+static const struct mtk_gate_regs vdec_core0_cg_regs = {
+	.set_ofs = 0x0,
+	.clr_ofs = 0x4,
+	.sta_ofs = 0x0,
+};
+
+static const struct mtk_gate_regs vdec_core1_cg_regs = {
+	.set_ofs = 0x8,
+	.clr_ofs = 0xc,
+	.sta_ofs = 0x8,
+};
+
+#define GATE_VDEC_CORE0(_id, _name, _parent, _shift)				\
+	GATE_MTK_FLAGS(_id, _name, _parent, &vdec_core0_cg_regs, _shift,	\
+		       &mtk_clk_gate_ops_setclr_inv, CLK_IGNORE_UNUSED)
+
+#define GATE_VDEC_CORE1(_id, _name, _parent, _shift)				\
+	GATE_MTK_FLAGS(_id, _name, _parent, &vdec_core1_cg_regs, _shift,	\
+		       &mtk_clk_gate_ops_setclr_inv, CLK_IGNORE_UNUSED)
+
+static const struct mtk_gate vdec_core_clks[] = {
+	/* VDEC_CORE0 */
+	GATE_VDEC_CORE0(CLK_VDEC_CORE_VDEC_CKEN, "vdec_core_vdec_cken", "vdec_sel", 0),
+	GATE_VDEC_CORE0(CLK_VDEC_CORE_VDEC_ACTIVE, "vdec_core_vdec_active", "vdec_sel", 4),
+	/* VDEC_CORE1 */
+	GATE_VDEC_CORE1(CLK_VDEC_CORE_LARB_CKEN, "vdec_core_larb_cken", "vdec_sel", 0),
+};
+
+static const struct mtk_clk_desc vdec_core_mcd = {
+	.clks = vdec_core_clks,
+	.num_clks = ARRAY_SIZE(vdec_core_clks),
+};
+
+static const struct mtk_gate_regs ven1_cg_regs = {
+	.set_ofs = 0x4,
+	.clr_ofs = 0x8,
+	.sta_ofs = 0x0,
+};
+
+#define GATE_VEN1(_id, _name, _parent, _shift)				\
+	GATE_MTK_FLAGS(_id, _name, _parent, &ven1_cg_regs, _shift,	\
+		       &mtk_clk_gate_ops_setclr_inv, CLK_IGNORE_UNUSED)
+
+static const struct mtk_gate ven1_clks[] = {
+	GATE_VEN1(CLK_VEN1_CKE0_LARB, "ven1_larb", "venc_sel", 0),
+	GATE_VEN1(CLK_VEN1_CKE1_VENC, "ven1_venc", "venc_sel", 4),
+	GATE_VEN1(CLK_VEN1_CKE2_JPGENC, "ven1_jpgenc", "venc_sel", 8),
+	GATE_VEN1(CLK_VEN1_CKE3_JPGDEC, "ven1_jpgdec", "venc_sel", 12),
+	GATE_VEN1(CLK_VEN1_CKE4_JPGDEC_C1, "ven1_jpgdec_c1", "venc_sel", 16),
+	GATE_VEN1(CLK_VEN1_CKE5_GALS, "ven1_gals", "venc_sel", 28),
+	GATE_VEN1(CLK_VEN1_CKE6_GALS_SRAM, "ven1_gals_sram", "venc_sel", 31),
+};
+
+static const struct mtk_clk_desc ven1_mcd = {
+	.clks = ven1_clks,
+	.num_clks = ARRAY_SIZE(ven1_clks),
+};
+
+static const struct of_device_id of_match_clk_mt8189_vcodec[] = {
+	{ .compatible = "mediatek,mt8189-vdec-core", .data = &vdec_core_mcd },
+	{ .compatible = "mediatek,mt8189-venc", .data = &ven1_mcd },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_match_clk_mt8189_vcodec);
+
+static struct platform_driver clk_mt8189_vcodec_drv = {
+	.probe = mtk_clk_simple_probe,
+	.remove = mtk_clk_simple_remove,
+	.driver = {
+		.name = "clk-mt8189-vcodec",
+		.of_match_table = of_match_clk_mt8189_vcodec,
+	},
+};
+
+module_platform_driver(clk_mt8189_vcodec_drv);
+MODULE_DESCRIPTION("MediaTek MT8189 video encoder/decoder clocks driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



From irving-ch.lin at mediatek.com  Sun Dec 14 19:49:11 2025
From: irving-ch.lin at mediatek.com (irving.ch.lin)
Date: Mon, 15 Dec 2025 11:49:11 +0800
Subject: [PATCH v4 02/21] dt-bindings: power: mediatek: Add MT8189 power domain definitions
In-Reply-To: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
References: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
Message-ID: <20251215034944.2973003-3-irving-ch.lin@mediatek.com>

From: Irving-CH Lin <irving-ch.lin at mediatek.com>

Add device tree bindings for the power domains of MediaTek MT8189 SoC.

Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
---
 .../power/mediatek,power-controller.yaml      |  1 +
 .../dt-bindings/power/mediatek,mt8189-power.h | 38 +++++++++++++++++++
 2 files changed, 39 insertions(+)
 create mode 100644 include/dt-bindings/power/mediatek,mt8189-power.h

diff --git a/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml b/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml
index f8a13928f615..443c227c0e51 100644
--- a/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml
+++ b/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml
@@ -31,6 +31,7 @@ properties:
       - mediatek,mt8183-power-controller
       - mediatek,mt8186-power-controller
       - mediatek,mt8188-power-controller
+      - mediatek,mt8189-power-controller
       - mediatek,mt8192-power-controller
       - mediatek,mt8195-power-controller
       - mediatek,mt8196-hwv-hfrp-power-controller
diff --git a/include/dt-bindings/power/mediatek,mt8189-power.h b/include/dt-bindings/power/mediatek,mt8189-power.h
new file mode 100644
index 000000000000..70a8c2113457
--- /dev/null
+++ b/include/dt-bindings/power/mediatek,mt8189-power.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Qiqi Wang <qiqi.wang at mediatek.com>
+ */
+
+#ifndef _DT_BINDINGS_POWER_MT8189_POWER_H
+#define _DT_BINDINGS_POWER_MT8189_POWER_H
+
+/* SPM */
+#define MT8189_POWER_DOMAIN_CONN			0
+#define MT8189_POWER_DOMAIN_AUDIO			1
+#define MT8189_POWER_DOMAIN_ADSP_TOP_DORMANT		2
+#define MT8189_POWER_DOMAIN_ADSP_INFRA			3
+#define MT8189_POWER_DOMAIN_ADSP_AO			4
+#define MT8189_POWER_DOMAIN_MM_INFRA			5
+#define MT8189_POWER_DOMAIN_ISP_IMG1			6
+#define MT8189_POWER_DOMAIN_ISP_IMG2			7
+#define MT8189_POWER_DOMAIN_ISP_IPE			8
+#define MT8189_POWER_DOMAIN_VDE0			9
+#define MT8189_POWER_DOMAIN_VEN0			10
+#define MT8189_POWER_DOMAIN_CAM_MAIN			11
+#define MT8189_POWER_DOMAIN_CAM_SUBA			12
+#define MT8189_POWER_DOMAIN_CAM_SUBB			13
+#define MT8189_POWER_DOMAIN_MDP0			14
+#define MT8189_POWER_DOMAIN_DISP			15
+#define MT8189_POWER_DOMAIN_DP_TX			16
+#define MT8189_POWER_DOMAIN_CSI_RX			17
+#define MT8189_POWER_DOMAIN_SSUSB			18
+#define MT8189_POWER_DOMAIN_MFG0			19
+#define MT8189_POWER_DOMAIN_MFG1			20
+#define MT8189_POWER_DOMAIN_MFG2			21
+#define MT8189_POWER_DOMAIN_MFG3			22
+#define MT8189_POWER_DOMAIN_EDP_TX_DORMANT		23
+#define MT8189_POWER_DOMAIN_PCIE			24
+#define MT8189_POWER_DOMAIN_PCIE_PHY			25
+
+#endif /* _DT_BINDINGS_POWER_MT8189_POWER_H */
-- 
2.45.2



From irving-ch.lin at mediatek.com  Sun Dec 14 19:49:25 2025
From: irving-ch.lin at mediatek.com (irving.ch.lin)
Date: Mon, 15 Dec 2025 11:49:25 +0800
Subject: [PATCH v4 16/21] clk: mediatek: Add MT8189 dispsys clock support
In-Reply-To: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
References: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
Message-ID: <20251215034944.2973003-17-irving-ch.lin@mediatek.com>

From: Irving-CH Lin <irving-ch.lin at mediatek.com>

Add support for the MT8189 dispsys clock controller,
which provides clock gate control for display system.

Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
---
 drivers/clk/mediatek/Kconfig              |  12 ++
 drivers/clk/mediatek/Makefile             |   1 +
 drivers/clk/mediatek/clk-mt8189-dispsys.c | 172 ++++++++++++++++++++++
 3 files changed, 185 insertions(+)
 create mode 100644 drivers/clk/mediatek/clk-mt8189-dispsys.c

diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
index 316d010b503a..8b1f358457d8 100644
--- a/drivers/clk/mediatek/Kconfig
+++ b/drivers/clk/mediatek/Kconfig
@@ -917,6 +917,18 @@ config COMMON_CLK_MT8189_MFG
 	  the MT8189 chipset. Enabling this will allow the manufacturing mode of
 	  the chipset to function correctly with the appropriate clock settings.
 
+config COMMON_CLK_MT8189_MMSYS
+	tristate "Clock driver for MediaTek MT8189 mmsys"
+	depends on COMMON_CLK_MT8189
+	default COMMON_CLK_MT8189
+	help
+	  Enable this to support the clock framework for MediaTek MT8189
+	  multimedia systems (mmsys). This driver is responsible for managing
+	  the clocks for various multimedia components within the SoC, such as
+	  video, audio, and image processing units. Enabling this option will
+	  ensure that these components receive the correct clock frequencies
+	  for proper operation.
+
 config COMMON_CLK_MT8192
 	tristate "Clock driver for MediaTek MT8192"
 	depends on ARM64 || COMPILE_TEST
diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
index 07f11760cf68..21a9e6264b84 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -133,6 +133,7 @@ obj-$(CONFIG_COMMON_CLK_MT8189_IIC) += clk-mt8189-iic.o
 obj-$(CONFIG_COMMON_CLK_MT8189_IMG) += clk-mt8189-img.o
 obj-$(CONFIG_COMMON_CLK_MT8189_MDPSYS) += clk-mt8189-mdpsys.o
 obj-$(CONFIG_COMMON_CLK_MT8189_MFG) += clk-mt8189-mfg.o
+obj-$(CONFIG_COMMON_CLK_MT8189_MMSYS) += clk-mt8189-dispsys.o
 obj-$(CONFIG_COMMON_CLK_MT8192) += clk-mt8192-apmixedsys.o clk-mt8192.o
 obj-$(CONFIG_COMMON_CLK_MT8192_AUDSYS) += clk-mt8192-aud.o
 obj-$(CONFIG_COMMON_CLK_MT8192_CAMSYS) += clk-mt8192-cam.o
diff --git a/drivers/clk/mediatek/clk-mt8189-dispsys.c b/drivers/clk/mediatek/clk-mt8189-dispsys.c
new file mode 100644
index 000000000000..4c101cf66f91
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8189-dispsys.c
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Qiqi Wang <qiqi.wang at mediatek.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include "clk-mtk.h"
+#include "clk-gate.h"
+
+#include <dt-bindings/clock/mediatek,mt8189-clk.h>
+
+static const struct mtk_gate_regs mm0_cg_regs = {
+	.set_ofs = 0x04,
+	.clr_ofs = 0x08,
+	.sta_ofs = 0x00,
+};
+
+static const struct mtk_gate_regs mm1_cg_regs = {
+	.set_ofs = 0x14,
+	.clr_ofs = 0x18,
+	.sta_ofs = 0x10,
+};
+
+#define GATE_MM0(_id, _name, _parent, _shift)		\
+	GATE_MTK(_id, _name, _parent, &mm0_cg_regs, _shift, &mtk_clk_gate_ops_setclr)
+
+#define GATE_MM1(_id, _name, _parent, _shift)		\
+	GATE_MTK(_id, _name, _parent, &mm1_cg_regs, _shift, &mtk_clk_gate_ops_setclr)
+
+static const struct mtk_gate mm_clks[] = {
+	/* MM0 */
+	GATE_MM0(CLK_MM_DISP_OVL0_4L, "mm_disp_ovl0_4l", "disp0_sel", 0),
+	GATE_MM0(CLK_MM_DISP_OVL1_4L, "mm_disp_ovl1_4l", "disp0_sel", 1),
+	GATE_MM0(CLK_MM_VPP_RSZ0, "mm_vpp_rsz0", "disp0_sel", 2),
+	GATE_MM0(CLK_MM_VPP_RSZ1, "mm_vpp_rsz1", "disp0_sel", 3),
+	GATE_MM0(CLK_MM_DISP_RDMA0, "mm_disp_rdma0", "disp0_sel", 4),
+	GATE_MM0(CLK_MM_DISP_RDMA1, "mm_disp_rdma1", "disp0_sel", 5),
+	GATE_MM0(CLK_MM_DISP_COLOR0, "mm_disp_color0", "disp0_sel", 6),
+	GATE_MM0(CLK_MM_DISP_COLOR1, "mm_disp_color1", "disp0_sel", 7),
+	GATE_MM0(CLK_MM_DISP_CCORR0, "mm_disp_ccorr0", "disp0_sel", 8),
+	GATE_MM0(CLK_MM_DISP_CCORR1, "mm_disp_ccorr1", "disp0_sel", 9),
+	GATE_MM0(CLK_MM_DISP_CCORR2, "mm_disp_ccorr2", "disp0_sel", 10),
+	GATE_MM0(CLK_MM_DISP_CCORR3, "mm_disp_ccorr3", "disp0_sel", 11),
+	GATE_MM0(CLK_MM_DISP_AAL0, "mm_disp_aal0", "disp0_sel", 12),
+	GATE_MM0(CLK_MM_DISP_AAL1, "mm_disp_aal1", "disp0_sel", 13),
+	GATE_MM0(CLK_MM_DISP_GAMMA0, "mm_disp_gamma0", "disp0_sel", 14),
+	GATE_MM0(CLK_MM_DISP_GAMMA1, "mm_disp_gamma1", "disp0_sel", 15),
+	GATE_MM0(CLK_MM_DISP_DITHER0, "mm_disp_dither0", "disp0_sel", 16),
+	GATE_MM0(CLK_MM_DISP_DITHER1, "mm_disp_dither1", "disp0_sel", 17),
+	GATE_MM0(CLK_MM_DISP_DSC_WRAP0, "mm_disp_dsc_wrap0", "disp0_sel", 18),
+	GATE_MM0(CLK_MM_VPP_MERGE0, "mm_vpp_merge0", "disp0_sel", 19),
+	GATE_MM0(CLK_MMSYS_0_DISP_DVO, "mmsys_0_disp_dvo", "disp0_sel", 20),
+	GATE_MM0(CLK_MMSYS_0_DISP_DSI0, "mmsys_0_CLK0", "disp0_sel", 21),
+	GATE_MM0(CLK_MM_DP_INTF0, "mm_dp_intf0", "disp0_sel", 22),
+	GATE_MM0(CLK_MM_DPI0, "mm_dpi0", "disp0_sel", 23),
+	GATE_MM0(CLK_MM_DISP_WDMA0, "mm_disp_wdma0", "disp0_sel", 24),
+	GATE_MM0(CLK_MM_DISP_WDMA1, "mm_disp_wdma1", "disp0_sel", 25),
+	GATE_MM0(CLK_MM_DISP_FAKE_ENG0, "mm_disp_fake_eng0", "disp0_sel", 26),
+	GATE_MM0(CLK_MM_DISP_FAKE_ENG1, "mm_disp_fake_eng1", "disp0_sel", 27),
+	GATE_MM0(CLK_MM_SMI_LARB, "mm_smi_larb", "disp0_sel", 28),
+	GATE_MM0(CLK_MM_DISP_MUTEX0, "mm_disp_mutex0", "disp0_sel", 29),
+	GATE_MM0(CLK_MM_DIPSYS_CONFIG, "mm_dipsys_config", "disp0_sel", 30),
+	GATE_MM0(CLK_MM_DUMMY, "mm_dummy", "disp0_sel", 31),
+	/* MM1 */
+	GATE_MM1(CLK_MMSYS_1_DISP_DSI0, "mmsys_1_CLK0", "dsi_occ_sel", 0),
+	GATE_MM1(CLK_MMSYS_1_LVDS_ENCODER, "mmsys_1_lvds_encoder", "pll_dpix_sel", 1),
+	GATE_MM1(CLK_MMSYS_1_DPI0, "mmsys_1_dpi0", "pll_dpix_sel", 2),
+	GATE_MM1(CLK_MMSYS_1_DISP_DVO, "mmsys_1_disp_dvo", "edp_sel", 3),
+	GATE_MM1(CLK_MM_DP_INTF, "mm_dp_intf", "dp_sel", 4),
+	GATE_MM1(CLK_MMSYS_1_LVDS_ENCODER_CTS, "mmsys_1_lvds_encoder_cts", "vdstx_dg_cts_sel", 5),
+	GATE_MM1(CLK_MMSYS_1_DISP_DVO_AVT, "mmsys_1_disp_dvo_avt", "edp_favt_sel", 6),
+};
+
+static const struct mtk_clk_desc mm_mcd = {
+	.clks = mm_clks,
+	.num_clks = ARRAY_SIZE(mm_clks),
+};
+
+static const struct mtk_gate_regs gce_d_cg_regs = {
+	.set_ofs = 0x0,
+	.clr_ofs = 0x0,
+	.sta_ofs = 0x0,
+};
+
+#define GATE_GCE_D(_id, _name, _parent, _shift)		\
+	GATE_MTK(_id, _name, _parent, &gce_d_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr)
+
+static const struct mtk_gate gce_d_clks[] = {
+	GATE_GCE_D(CLK_GCE_D_TOP, "gce_d_top", "mminfra_gce_d", 16),
+};
+
+static const struct mtk_clk_desc gce_d_mcd = {
+	.clks = gce_d_clks,
+	.num_clks = ARRAY_SIZE(gce_d_clks),
+};
+
+static const struct mtk_gate_regs gce_m_cg_regs = {
+	.set_ofs = 0x0,
+	.clr_ofs = 0x0,
+	.sta_ofs = 0x0,
+};
+
+#define GATE_GCE_M(_id, _name, _parent, _shift)		\
+	GATE_MTK(_id, _name, _parent, &gce_m_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr)
+
+static const struct mtk_gate gce_m_clks[] = {
+	GATE_GCE_M(CLK_GCE_M_TOP, "gce_m_top", "mminfra_gce_m", 16),
+};
+
+static const struct mtk_clk_desc gce_m_mcd = {
+	.clks = gce_m_clks,
+	.num_clks = ARRAY_SIZE(gce_m_clks),
+};
+
+static const struct mtk_gate_regs mminfra_config0_cg_regs = {
+	.set_ofs = 0x104,
+	.clr_ofs = 0x108,
+	.sta_ofs = 0x100,
+};
+
+static const struct mtk_gate_regs mminfra_config1_cg_regs = {
+	.set_ofs = 0x114,
+	.clr_ofs = 0x118,
+	.sta_ofs = 0x110,
+};
+
+#define GATE_MMINFRA_CONFIG0(_id, _name, _parent, _shift)	\
+	GATE_MTK(_id, _name, _parent, &mminfra_config0_cg_regs, _shift, &mtk_clk_gate_ops_setclr)
+
+#define GATE_MMINFRA_CONFIG1(_id, _name, _parent, _shift)	\
+	GATE_MTK(_id, _name, _parent, &mminfra_config1_cg_regs, _shift, &mtk_clk_gate_ops_setclr)
+
+static const struct mtk_gate mminfra_config_clks[] = {
+	/* MMINFRA_CONFIG0 */
+	GATE_MMINFRA_CONFIG0(CLK_MMINFRA_GCE_D, "mminfra_gce_d", "mminfra_sel", 0),
+	GATE_MMINFRA_CONFIG0(CLK_MMINFRA_GCE_M, "mminfra_gce_m", "mminfra_sel", 1),
+	GATE_MMINFRA_CONFIG0(CLK_MMINFRA_SMI, "mminfra_smi", "mminfra_sel", 2),
+	/* MMINFRA_CONFIG1 */
+	GATE_MMINFRA_CONFIG1(CLK_MMINFRA_GCE_26M, "mminfra_gce_26m", "mminfra_sel", 17),
+};
+
+static const struct mtk_clk_desc mminfra_config_mcd = {
+	.clks = mminfra_config_clks,
+	.num_clks = ARRAY_SIZE(mminfra_config_clks),
+};
+
+static const struct of_device_id of_match_clk_mt8189_dispsys[] = {
+	{ .compatible = "mediatek,mt8189-dispsys", .data = &mm_mcd },
+	{ .compatible = "mediatek,mt8189-gce-d", .data = &gce_d_mcd },
+	{ .compatible = "mediatek,mt8189-gce-m", .data = &gce_m_mcd },
+	{ .compatible = "mediatek,mt8189-mm-infra", .data = &mminfra_config_mcd },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_match_clk_mt8189_dispsys);
+
+static struct platform_driver clk_mt8189_dispsys_drv = {
+	.probe = mtk_clk_simple_probe,
+	.remove = mtk_clk_simple_remove,
+	.driver = {
+		.name = "clk-mt8189-dispsys",
+		.of_match_table = of_match_clk_mt8189_dispsys,
+	},
+};
+
+module_platform_driver(clk_mt8189_dispsys_drv);
+MODULE_DESCRIPTION("MediaTek MT8189 display clocks driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



From irving-ch.lin at mediatek.com  Sun Dec 14 19:49:15 2025
From: irving-ch.lin at mediatek.com (irving.ch.lin)
Date: Mon, 15 Dec 2025 11:49:15 +0800
Subject: [PATCH v4 06/21] clk: mediatek: Add MT8189 vlpckgen clock support
In-Reply-To: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
References: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
Message-ID: <20251215034944.2973003-7-irving-ch.lin@mediatek.com>

From: Irving-CH Lin <irving-ch.lin at mediatek.com>

Add support for the MT8189 vlpckgen clock controller, which provides
muxes and dividers for clock selection in vlp domain for other IP blocks.

Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
---
 drivers/clk/mediatek/Makefile              |   3 +-
 drivers/clk/mediatek/clk-mt8189-vlpckgen.c | 280 +++++++++++++++++++++
 2 files changed, 282 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/mediatek/clk-mt8189-vlpckgen.c

diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
index 9d3d2983bfb2..3b25df9e7b50 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -123,7 +123,8 @@ obj-$(CONFIG_COMMON_CLK_MT8188_VDOSYS) += clk-mt8188-vdo0.o clk-mt8188-vdo1.o
 obj-$(CONFIG_COMMON_CLK_MT8188_VENCSYS) += clk-mt8188-venc.o
 obj-$(CONFIG_COMMON_CLK_MT8188_VPPSYS) += clk-mt8188-vpp0.o clk-mt8188-vpp1.o
 obj-$(CONFIG_COMMON_CLK_MT8188_WPESYS) += clk-mt8188-wpe.o
-obj-$(CONFIG_COMMON_CLK_MT8189) += clk-mt8189-apmixedsys.o clk-mt8189-topckgen.o
+obj-$(CONFIG_COMMON_CLK_MT8189) += clk-mt8189-apmixedsys.o clk-mt8189-topckgen.o \
+				   clk-mt8189-vlpckgen.o
 obj-$(CONFIG_COMMON_CLK_MT8192) += clk-mt8192-apmixedsys.o clk-mt8192.o
 obj-$(CONFIG_COMMON_CLK_MT8192_AUDSYS) += clk-mt8192-aud.o
 obj-$(CONFIG_COMMON_CLK_MT8192_CAMSYS) += clk-mt8192-cam.o
diff --git a/drivers/clk/mediatek/clk-mt8189-vlpckgen.c b/drivers/clk/mediatek/clk-mt8189-vlpckgen.c
new file mode 100644
index 000000000000..950cc1fb73a1
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8189-vlpckgen.c
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Qiqi Wang <qiqi.wang at mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "clk-mtk.h"
+#include "clk-mux.h"
+#include "clk-gate.h"
+
+#include <dt-bindings/clock/mediatek,mt8189-clk.h>
+
+static DEFINE_SPINLOCK(mt8189_vlpclk_lock);
+
+static const char * const vlp_26m_oscd10_parents[] = {
+	"clk26m",
+	"osc_d10"
+};
+
+static const char * const vlp_vadsp_vowpll_parents[] = {
+	"clk26m",
+	"vowpll"
+};
+
+static const char * const vlp_sspm_ulposc_parents[] = {
+	"ulposc",
+	"univpll_d5_d2",
+	"osc_d10"
+};
+
+static const char * const vlp_aud_adc_parents[] = {
+	"clk26m",
+	"vowpll",
+	"aud_adc_ext",
+	"osc_d10"
+};
+
+static const char * const vlp_scp_iic_spi_parents[] = {
+	"clk26m",
+	"mainpll_d5_d4",
+	"mainpll_d7_d2",
+	"osc_d10"
+};
+
+static const char * const vlp_vadsp_uarthub_b_parents[] = {
+	"clk26m",
+	"osc_d10",
+	"univpll_d6_d4",
+	"univpll_d6_d2"
+};
+
+static const char * const vlp_axi_kp_parents[] = {
+	"clk26m",
+	"osc_d10",
+	"osc_d2",
+	"mainpll_d7_d4",
+	"mainpll_d7_d2"
+};
+
+static const char * const vlp_sspm_parents[] = {
+	"clk26m",
+	"osc_d10",
+	"mainpll_d5_d2",
+	"ulposc",
+	"mainpll_d6"
+};
+
+static const char * const vlp_pwm_vlp_parents[] = {
+	"clk26m",
+	"osc_d4",
+	"clk32k",
+	"osc_d10",
+	"mainpll_d4_d8"
+};
+
+static const char * const vlp_pwrap_ulposc_parents[] = {
+	"clk26m",
+	"osc_d10",
+	"osc_d7",
+	"osc_d8",
+	"osc_d16",
+	"mainpll_d7_d8"
+};
+
+static const char * const vlp_vadsp_parents[] = {
+	"clk26m",
+	"osc_d20",
+	"osc_d10",
+	"osc_d2",
+	"ulposc",
+	"mainpll_d4_d2"
+};
+
+static const char * const vlp_scp_parents[] = {
+	"clk26m",
+	"univpll_d4",
+	"univpll_d3",
+	"mainpll_d3",
+	"univpll_d6",
+	"apll1",
+	"mainpll_d4",
+	"mainpll_d6",
+	"mainpll_d7",
+	"osc_d10"
+};
+
+static const char * const vlp_spmi_p_parents[] = {
+	"clk26m",
+	"f26m_d2",
+	"osc_d8",
+	"osc_d10",
+	"osc_d16",
+	"osc_d7",
+	"clk32k",
+	"mainpll_d7_d8",
+	"mainpll_d6_d8",
+	"mainpll_d5_d8"
+};
+
+static const char * const vlp_camtg_parents[] = {
+	"clk26m",
+	"univpll_192m_d8",
+	"univpll_d6_d8",
+	"univpll_192m_d4",
+	"osc_d16",
+	"osc_d20",
+	"osc_d10",
+	"univpll_d6_d16",
+	"tvdpll1_d16",
+	"f26m_d2",
+	"univpll_192m_d10",
+	"univpll_192m_d16",
+	"univpll_192m_d32"
+};
+
+static const struct mtk_mux vlp_ck_muxes[] = {
+	/* VLP_CLK_CFG_0 */
+	MUX_GATE_CLR_SET_UPD(CLK_VLP_CK_SCP_SEL, "vlp_scp_sel",
+			     vlp_scp_parents, 0x008, 0x00c, 0x010,
+			     0, 4, 7, 0x04, 0),
+	MUX_CLR_SET_UPD(CLK_VLP_CK_PWRAP_ULPOSC_SEL, "vlp_pwrap_osc_sel",
+			vlp_pwrap_ulposc_parents, 0x008, 0x00c, 0x010,
+			8, 3, 0x04, 1),
+	MUX_CLR_SET_UPD(CLK_VLP_CK_SPMI_P_MST_SEL, "vlp_spmi_p_sel",
+			vlp_spmi_p_parents, 0x008, 0x00c, 0x010,
+			16, 4, 0x04, 2),
+	MUX_CLR_SET_UPD(CLK_VLP_CK_DVFSRC_SEL, "vlp_dvfsrc_sel",
+			vlp_26m_oscd10_parents, 0x008, 0x00c, 0x010,
+			24, 1, 0x04, 3),
+	/* VLP_CLK_CFG_1 */
+	MUX_CLR_SET_UPD(CLK_VLP_CK_PWM_VLP_SEL, "vlp_pwm_vlp_sel",
+			vlp_pwm_vlp_parents, 0x014, 0x018, 0x01c,
+			0, 3, 0x04, 4),
+	MUX_CLR_SET_UPD(CLK_VLP_CK_AXI_VLP_SEL, "vlp_axi_vlp_sel",
+			vlp_axi_kp_parents, 0x014, 0x018, 0x01c,
+			8, 3, 0x04, 5),
+	MUX_CLR_SET_UPD(CLK_VLP_CK_SYSTIMER_26M_SEL, "vlp_timer_26m_sel",
+			vlp_26m_oscd10_parents, 0x014, 0x018, 0x01c,
+			16, 1, 0x04, 6),
+	MUX_CLR_SET_UPD(CLK_VLP_CK_SSPM_SEL, "vlp_sspm_sel",
+			vlp_sspm_parents, 0x014, 0x018, 0x01c,
+			24, 3, 0x04, 7),
+	/* VLP_CLK_CFG_2 */
+	MUX_CLR_SET_UPD(CLK_VLP_CK_SSPM_F26M_SEL, "vlp_sspm_f26m_sel",
+			vlp_26m_oscd10_parents, 0x020, 0x024, 0x028,
+			0, 1, 0x04, 8),
+	MUX_CLR_SET_UPD(CLK_VLP_CK_SRCK_SEL, "vlp_srck_sel",
+			vlp_26m_oscd10_parents, 0x020, 0x024, 0x028,
+			8, 1, 0x04, 9),
+	MUX_CLR_SET_UPD(CLK_VLP_CK_SCP_SPI_SEL, "vlp_scp_spi_sel",
+			vlp_scp_iic_spi_parents, 0x020, 0x024, 0x028,
+			16, 2, 0x04, 10),
+	MUX_CLR_SET_UPD(CLK_VLP_CK_SCP_IIC_SEL, "vlp_scp_iic_sel",
+			vlp_scp_iic_spi_parents, 0x020, 0x024, 0x028,
+			24, 2, 0x04, 11),
+	/* VLP_CLK_CFG_3 */
+	MUX_CLR_SET_UPD(CLK_VLP_CK_SCP_SPI_HIGH_SPD_SEL,
+			"vlp_scp_spi_hs_sel",
+			vlp_scp_iic_spi_parents, 0x02c, 0x030, 0x034,
+			0, 2, 0x04, 12),
+	MUX_CLR_SET_UPD(CLK_VLP_CK_SCP_IIC_HIGH_SPD_SEL,
+			"vlp_scp_iic_hs_sel",
+			vlp_scp_iic_spi_parents, 0x02c, 0x030, 0x034,
+			8, 2, 0x04, 13),
+	MUX_CLR_SET_UPD(CLK_VLP_CK_SSPM_ULPOSC_SEL, "vlp_sspm_ulposc_sel",
+			vlp_sspm_ulposc_parents, 0x02c, 0x030, 0x034,
+			16, 2, 0x04, 14),
+	MUX_CLR_SET_UPD(CLK_VLP_CK_APXGPT_26M_SEL, "vlp_apxgpt_26m_sel",
+			vlp_26m_oscd10_parents, 0x02c, 0x030, 0x034,
+			24, 1, 0x04, 15),
+	/* VLP_CLK_CFG_4 */
+	MUX_GATE_CLR_SET_UPD(CLK_VLP_CK_VADSP_SEL, "vlp_vadsp_sel",
+			     vlp_vadsp_parents, 0x038, 0x03c, 0x040,
+			     0, 3, 7, 0x04, 16),
+	MUX_GATE_CLR_SET_UPD(CLK_VLP_CK_VADSP_VOWPLL_SEL,
+			     "vlp_vadsp_vowpll_sel",
+			     vlp_vadsp_vowpll_parents, 0x038, 0x03c, 0x040,
+			     8, 1, 15, 0x04, 17),
+	MUX_GATE_CLR_SET_UPD(CLK_VLP_CK_VADSP_UARTHUB_BCLK_SEL,
+			     "vlp_vadsp_uarthub_b_sel",
+			     vlp_vadsp_uarthub_b_parents,
+			     0x038, 0x03c, 0x040, 16, 2, 23, 0x04, 18),
+	MUX_GATE_CLR_SET_UPD(CLK_VLP_CK_CAMTG0_SEL, "vlp_camtg0_sel",
+			     vlp_camtg_parents, 0x038, 0x03c, 0x040,
+			     24, 4, 31, 0x04, 19),
+	/* VLP_CLK_CFG_5 */
+	MUX_GATE_CLR_SET_UPD(CLK_VLP_CK_CAMTG1_SEL, "vlp_camtg1_sel",
+			     vlp_camtg_parents, 0x044, 0x048, 0x04c,
+			     0, 4, 7, 0x04, 20),
+	MUX_GATE_CLR_SET_UPD(CLK_VLP_CK_CAMTG2_SEL, "vlp_camtg2_sel",
+			     vlp_camtg_parents, 0x044, 0x048, 0x04c,
+			     8, 4, 15, 0x04, 21),
+	MUX_GATE_CLR_SET_UPD(CLK_VLP_CK_AUD_ADC_SEL, "vlp_aud_adc_sel",
+			     vlp_aud_adc_parents, 0x044, 0x048, 0x04c,
+			     16, 2, 23, 0x04, 22),
+	MUX_GATE_CLR_SET_UPD(CLK_VLP_CK_KP_IRQ_GEN_SEL, "vlp_kp_irq_sel",
+			     vlp_axi_kp_parents, 0x044, 0x048, 0x04c,
+			     24, 3, 31, 0x04, 23),
+};
+
+static const struct mtk_gate_regs vlp_ck_cg_regs = {
+	.set_ofs = 0x1f4,
+	.clr_ofs = 0x1f8,
+	.sta_ofs = 0x1f0,
+};
+
+#define GATE_VLP_CK_FLAGS(_id, _name, _parent, _shift, _flag) {	\
+		.id = _id,				\
+		.name = _name,				\
+		.parent_name = _parent,			\
+		.regs = &vlp_ck_cg_regs,		\
+		.shift = _shift,			\
+		.flags = _flag,				\
+		.ops = &mtk_clk_gate_ops_setclr_inv,	\
+	}
+
+#define GATE_VLP_CK(_id, _name, _parent, _shift)	\
+	GATE_VLP_CK_FLAGS(_id, _name, _parent, _shift, 0)
+
+static const struct mtk_gate vlp_ck_clks[] = {
+	GATE_VLP_CK(CLK_VLP_CK_VADSYS_VLP_26M_EN, "vlp_vadsys_vlp_26m", "clk26m", 1),
+	GATE_VLP_CK_FLAGS(CLK_VLP_CK_FMIPI_CSI_UP26M_CK_EN, "VLP_fmipi_csi_up26m",
+			  "osc_d10", 11, CLK_IS_CRITICAL),
+};
+
+static const struct mtk_clk_desc vlpck_desc = {
+	.mux_clks = vlp_ck_muxes,
+	.num_mux_clks = ARRAY_SIZE(vlp_ck_muxes),
+	.clks = vlp_ck_clks,
+	.num_clks = ARRAY_SIZE(vlp_ck_clks),
+	.clk_lock = &mt8189_vlpclk_lock,
+};
+
+static const struct of_device_id of_match_clk_mt8189_vlpck[] = {
+	{ .compatible = "mediatek,mt8189-vlpckgen", .data = &vlpck_desc },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver clk_mt8189_vlpck_drv = {
+	.probe = mtk_clk_simple_probe,
+	.remove = mtk_clk_simple_remove,
+	.driver = {
+		.name = "clk-mt8189-vlpck",
+		.of_match_table = of_match_clk_mt8189_vlpck,
+	},
+};
+
+module_platform_driver(clk_mt8189_vlpck_drv);
+MODULE_DESCRIPTION("MediaTek MT8189 vlpckgen clocks driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



From irving-ch.lin at mediatek.com  Sun Dec 14 19:49:12 2025
From: irving-ch.lin at mediatek.com (irving.ch.lin)
Date: Mon, 15 Dec 2025 11:49:12 +0800
Subject: [PATCH v4 03/21] clk: mediatek: clk-mux: Make sure bypass clk enabled while setting MFG rate
In-Reply-To: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
References: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
Message-ID: <20251215034944.2973003-4-irving-ch.lin@mediatek.com>

From: Irving-CH Lin <irving-ch.lin at mediatek.com>

Enable bypass clock before MFG changing rate, to make sure
MFG reference clock available during transient.

Fixes: b66add7a74e8 ("clk: mediatek: mux: add clk notifier functions")
Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
---
 drivers/clk/mediatek/clk-mux.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/mediatek/clk-mux.c b/drivers/clk/mediatek/clk-mux.c
index c5af6dc078a3..07f1f18b38bc 100644
--- a/drivers/clk/mediatek/clk-mux.c
+++ b/drivers/clk/mediatek/clk-mux.c
@@ -414,16 +414,21 @@ static int mtk_clk_mux_notifier_cb(struct notifier_block *nb,
 	struct clk_notifier_data *data = _data;
 	struct clk_hw *hw = __clk_get_hw(data->clk);
 	struct mtk_mux_nb *mux_nb = to_mtk_mux_nb(nb);
+	struct clk_hw *p_hw = clk_hw_get_parent_by_index(hw, mux_nb->bypass_index);
 	int ret = 0;
 
 	switch (event) {
 	case PRE_RATE_CHANGE:
-		mux_nb->original_index = mux_nb->ops->get_parent(hw);
-		ret = mux_nb->ops->set_parent(hw, mux_nb->bypass_index);
+		ret = clk_prepare_enable(p_hw->clk);
+		if (ret == 0) {
+			mux_nb->original_index = mux_nb->ops->get_parent(hw);
+			ret = mux_nb->ops->set_parent(hw, mux_nb->bypass_index);
+		}
 		break;
 	case POST_RATE_CHANGE:
 	case ABORT_RATE_CHANGE:
 		ret = mux_nb->ops->set_parent(hw, mux_nb->original_index);
+		clk_disable_unprepare(p_hw->clk);
 		break;
 	}
 
-- 
2.45.2



From irving-ch.lin at mediatek.com  Sun Dec 14 19:49:27 2025
From: irving-ch.lin at mediatek.com (irving.ch.lin)
Date: Mon, 15 Dec 2025 11:49:27 +0800
Subject: [PATCH v4 18/21] clk: mediatek: Add MT8189 ufs clock support
In-Reply-To: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
References: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
Message-ID: <20251215034944.2973003-19-irving-ch.lin@mediatek.com>

From: Irving-CH Lin <irving-ch.lin at mediatek.com>

Add support for the MT8189 ufs clock controller,
which provides clock gate control for Universal Flash Storage.

Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
---
 drivers/clk/mediatek/Kconfig          | 12 ++++
 drivers/clk/mediatek/Makefile         |  1 +
 drivers/clk/mediatek/clk-mt8189-ufs.c | 89 +++++++++++++++++++++++++++
 3 files changed, 102 insertions(+)
 create mode 100644 drivers/clk/mediatek/clk-mt8189-ufs.c

diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
index 2cc1a28436f1..3ef964b19d97 100644
--- a/drivers/clk/mediatek/Kconfig
+++ b/drivers/clk/mediatek/Kconfig
@@ -939,6 +939,18 @@ config COMMON_CLK_MT8189_SCP
 	  management for SCP-related features, ensuring proper clock
 	  distribution and gating for power efficiency and functionality.
 
+config COMMON_CLK_MT8189_UFS
+	tristate "Clock driver for MediaTek MT8189 ufs"
+	depends on COMMON_CLK_MT8189
+	default COMMON_CLK_MT8189
+	help
+	  Enable this to support the clock management for the Universal Flash
+	  Storage (UFS) interface on MediaTek MT8189 SoCs. This includes
+	  clock sources, dividers, and gates that are specific to the UFS
+	  feature of the MT8189 platform. It is recommended to enable this
+	  option if the system includes a UFS device that relies on the MT8189
+	  SoC for clock management.
+
 config COMMON_CLK_MT8192
 	tristate "Clock driver for MediaTek MT8192"
 	depends on ARM64 || COMPILE_TEST
diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
index 819c67395e1b..4179808dba7b 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -135,6 +135,7 @@ obj-$(CONFIG_COMMON_CLK_MT8189_MDPSYS) += clk-mt8189-mdpsys.o
 obj-$(CONFIG_COMMON_CLK_MT8189_MFG) += clk-mt8189-mfg.o
 obj-$(CONFIG_COMMON_CLK_MT8189_MMSYS) += clk-mt8189-dispsys.o
 obj-$(CONFIG_COMMON_CLK_MT8189_SCP) += clk-mt8189-scp.o
+obj-$(CONFIG_COMMON_CLK_MT8189_UFS) += clk-mt8189-ufs.o
 obj-$(CONFIG_COMMON_CLK_MT8192) += clk-mt8192-apmixedsys.o clk-mt8192.o
 obj-$(CONFIG_COMMON_CLK_MT8192_AUDSYS) += clk-mt8192-aud.o
 obj-$(CONFIG_COMMON_CLK_MT8192_CAMSYS) += clk-mt8192-cam.o
diff --git a/drivers/clk/mediatek/clk-mt8189-ufs.c b/drivers/clk/mediatek/clk-mt8189-ufs.c
new file mode 100644
index 000000000000..541f9e05d567
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8189-ufs.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Qiqi Wang <qiqi.wang at mediatek.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include "clk-mtk.h"
+#include "clk-gate.h"
+
+#include <dt-bindings/clock/mediatek,mt8189-clk.h>
+
+static const struct mtk_gate_regs ufscfg_ao_reg_cg_regs = {
+	.set_ofs = 0x8,
+	.clr_ofs = 0xc,
+	.sta_ofs = 0x4,
+};
+
+#define GATE_UFSCFG_AO_REG(_id, _name, _parent, _shift)		\
+	GATE_MTK(_id, _name, _parent, &ufscfg_ao_reg_cg_regs, _shift, &mtk_clk_gate_ops_setclr)
+
+static const struct mtk_gate ufscfg_ao_reg_clks[] = {
+	GATE_UFSCFG_AO_REG(CLK_UFSCFG_AO_REG_UNIPRO_TX_SYM,
+			   "ufscfg_ao_unipro_tx_sym", "clk26m", 1),
+	GATE_UFSCFG_AO_REG(CLK_UFSCFG_AO_REG_UNIPRO_RX_SYM0,
+			   "ufscfg_ao_unipro_rx_sym0", "clk26m", 2),
+	GATE_UFSCFG_AO_REG(CLK_UFSCFG_AO_REG_UNIPRO_RX_SYM1,
+			   "ufscfg_ao_unipro_rx_sym1", "clk26m", 3),
+	GATE_UFSCFG_AO_REG(CLK_UFSCFG_AO_REG_UNIPRO_SYS,
+			   "ufscfg_ao_unipro_sys", "ufs_sel", 4),
+	GATE_UFSCFG_AO_REG(CLK_UFSCFG_AO_REG_U_SAP_CFG,
+			   "ufscfg_ao_u_sap_cfg", "clk26m", 5),
+	GATE_UFSCFG_AO_REG(CLK_UFSCFG_AO_REG_U_PHY_TOP_AHB_S_BUS,
+			   "ufscfg_ao_u_phy_ahb_s_bus", "axi_u_sel", 6),
+};
+
+static const struct mtk_clk_desc ufscfg_ao_reg_mcd = {
+	.clks = ufscfg_ao_reg_clks,
+	.num_clks = ARRAY_SIZE(ufscfg_ao_reg_clks),
+};
+
+static const struct mtk_gate_regs ufscfg_pdn_reg_cg_regs = {
+	.set_ofs = 0x8,
+	.clr_ofs = 0xc,
+	.sta_ofs = 0x4,
+};
+
+#define GATE_UFSCFG_PDN_REG(_id, _name, _parent, _shift)	\
+	GATE_MTK(_id, _name, _parent, &ufscfg_pdn_reg_cg_regs, _shift, &mtk_clk_gate_ops_setclr)
+
+static const struct mtk_gate ufscfg_pdn_reg_clks[] = {
+	GATE_UFSCFG_PDN_REG(CLK_UFSCFG_REG_UFSHCI_UFS,
+			    "ufscfg_ufshci_ufs", "ufs_sel", 0),
+	GATE_UFSCFG_PDN_REG(CLK_UFSCFG_REG_UFSHCI_AES,
+			    "ufscfg_ufshci_aes", "aes_ufsfde_sel", 1),
+	GATE_UFSCFG_PDN_REG(CLK_UFSCFG_REG_UFSHCI_U_AHB,
+			    "ufscfg_ufshci_u_ahb", "axi_u_sel", 3),
+	GATE_UFSCFG_PDN_REG(CLK_UFSCFG_REG_UFSHCI_U_AXI,
+			    "ufscfg_ufshci_u_axi", "mem_sub_u_sel", 5),
+};
+
+static const struct mtk_clk_desc ufscfg_pdn_reg_mcd = {
+	.clks = ufscfg_pdn_reg_clks,
+	.num_clks = ARRAY_SIZE(ufscfg_pdn_reg_clks),
+};
+
+static const struct of_device_id of_match_clk_mt8189_ufs[] = {
+	{ .compatible = "mediatek,mt8189-ufscfg-ao", .data = &ufscfg_ao_reg_mcd },
+	{ .compatible = "mediatek,mt8189-ufscfg-pdn", .data = &ufscfg_pdn_reg_mcd },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_match_clk_mt8189_ufs);
+
+static struct platform_driver clk_mt8189_ufs_drv = {
+	.probe = mtk_clk_simple_probe,
+	.remove = mtk_clk_simple_remove,
+	.driver = {
+		.name = "clk-mt8189-ufs",
+		.of_match_table = of_match_clk_mt8189_ufs,
+	},
+};
+
+module_platform_driver(clk_mt8189_ufs_drv);
+MODULE_DESCRIPTION("MediaTek MT8189 ufs clocks driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



From irving-ch.lin at mediatek.com  Sun Dec 14 19:49:18 2025
From: irving-ch.lin at mediatek.com (irving.ch.lin)
Date: Mon, 15 Dec 2025 11:49:18 +0800
Subject: [PATCH v4 09/21] clk: mediatek: Add MT8189 cam clock support
In-Reply-To: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
References: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
Message-ID: <20251215034944.2973003-10-irving-ch.lin@mediatek.com>

From: Irving-CH Lin <irving-ch.lin at mediatek.com>

Add support for the MT8189 cam clock controller,
which provides clock gate control for camera.

Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
---
 drivers/clk/mediatek/Kconfig          |  11 +++
 drivers/clk/mediatek/Makefile         |   1 +
 drivers/clk/mediatek/clk-mt8189-cam.c | 108 ++++++++++++++++++++++++++
 3 files changed, 120 insertions(+)
 create mode 100644 drivers/clk/mediatek/clk-mt8189-cam.c

diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
index 0e7fdb5421e6..82a26d952bff 100644
--- a/drivers/clk/mediatek/Kconfig
+++ b/drivers/clk/mediatek/Kconfig
@@ -839,6 +839,17 @@ config COMMON_CLK_MT8189_BUS
 	  MT8189 chipset, ensuring that all bus-related components receive the
 	  correct clock signals for optimal performance.
 
+config COMMON_CLK_MT8189_CAM
+	tristate "Clock driver for MediaTek MT8189 cam"
+	depends on COMMON_CLK_MT8189
+	default COMMON_CLK_MT8189
+	help
+	  Enable this to support the clock management for the camera interface
+	  on MediaTek MT8189 SoCs. This includes enabling, disabling, and
+	  setting the rate for camera-related clocks. If you have a camera
+	  that relies on this SoC and you want to control its clocks, say Y or M
+	  to include this driver in your kernel build.
+
 config COMMON_CLK_MT8192
 	tristate "Clock driver for MediaTek MT8192"
 	depends on ARM64 || COMPILE_TEST
diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
index aabfb42cb1b2..95a8f4ae05ee 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -126,6 +126,7 @@ obj-$(CONFIG_COMMON_CLK_MT8188_WPESYS) += clk-mt8188-wpe.o
 obj-$(CONFIG_COMMON_CLK_MT8189) += clk-mt8189-apmixedsys.o clk-mt8189-topckgen.o \
 				   clk-mt8189-vlpckgen.o clk-mt8189-vlpcfg.o
 obj-$(CONFIG_COMMON_CLK_MT8189_BUS) += clk-mt8189-bus.o
+obj-$(CONFIG_COMMON_CLK_MT8189_CAM) += clk-mt8189-cam.o
 obj-$(CONFIG_COMMON_CLK_MT8192) += clk-mt8192-apmixedsys.o clk-mt8192.o
 obj-$(CONFIG_COMMON_CLK_MT8192_AUDSYS) += clk-mt8192-aud.o
 obj-$(CONFIG_COMMON_CLK_MT8192_CAMSYS) += clk-mt8192-cam.o
diff --git a/drivers/clk/mediatek/clk-mt8189-cam.c b/drivers/clk/mediatek/clk-mt8189-cam.c
new file mode 100644
index 000000000000..d65ac08cedd6
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8189-cam.c
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Qiqi Wang <qiqi.wang at mediatek.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include "clk-mtk.h"
+#include "clk-gate.h"
+
+#include <dt-bindings/clock/mediatek,mt8189-clk.h>
+
+static const struct mtk_gate_regs cam_m_cg_regs = {
+	.set_ofs = 0x4,
+	.clr_ofs = 0x8,
+	.sta_ofs = 0x0,
+};
+
+#define GATE_CAM_M(_id, _name, _parent, _shift)				\
+	GATE_MTK_FLAGS(_id, _name, _parent, &cam_m_cg_regs, _shift,	\
+		       &mtk_clk_gate_ops_setclr, CLK_IGNORE_UNUSED)
+
+static const struct mtk_gate cam_m_clks[] = {
+	GATE_CAM_M(CLK_CAM_M_LARB13, "cam_m_larb13", "cam_sel", 0),
+	GATE_CAM_M(CLK_CAM_M_LARB14, "cam_m_larb14", "cam_sel", 2),
+	GATE_CAM_M(CLK_CAM_M_CAMSYS_MAIN_CAM, "cam_m_camsys_main_cam", "cam_sel", 6),
+	GATE_CAM_M(CLK_CAM_M_CAMSYS_MAIN_CAMTG, "cam_m_camsys_main_camtg", "cam_sel", 7),
+	GATE_CAM_M(CLK_CAM_M_SENINF, "cam_m_seninf", "cam_sel", 8),
+	GATE_CAM_M(CLK_CAM_M_CAMSV1, "cam_m_camsv1", "cam_sel", 10),
+	GATE_CAM_M(CLK_CAM_M_CAMSV2, "cam_m_camsv2", "cam_sel", 11),
+	GATE_CAM_M(CLK_CAM_M_CAMSV3, "cam_m_camsv3", "cam_sel", 12),
+	GATE_CAM_M(CLK_CAM_M_FAKE_ENG, "cam_m_fake_eng", "cam_sel", 17),
+	GATE_CAM_M(CLK_CAM_M_CAM2MM_GALS, "cam_m_cam2mm_gals", "cam_sel", 19),
+	GATE_CAM_M(CLK_CAM_M_CAMSV4, "cam_m_camsv4", "cam_sel", 20),
+	GATE_CAM_M(CLK_CAM_M_PDA, "cam_m_pda", "cam_sel", 21),
+};
+
+static const struct mtk_clk_desc cam_m_mcd = {
+	.clks = cam_m_clks,
+	.num_clks = ARRAY_SIZE(cam_m_clks),
+};
+
+static const struct mtk_gate_regs cam_ra_cg_regs = {
+	.set_ofs = 0x4,
+	.clr_ofs = 0x8,
+	.sta_ofs = 0x0,
+};
+
+#define GATE_CAM_RA(_id, _name, _parent, _shift)			\
+	GATE_MTK_FLAGS(_id, _name, _parent, &cam_ra_cg_regs, _shift,	\
+		       &mtk_clk_gate_ops_setclr, CLK_IGNORE_UNUSED)
+
+static const struct mtk_gate cam_ra_clks[] = {
+	GATE_CAM_RA(CLK_CAM_RA_CAMSYS_RAWA_LARBX, "cam_ra_camsys_rawa_larbx", "cam_sel", 0),
+	GATE_CAM_RA(CLK_CAM_RA_CAMSYS_RAWA_CAM, "cam_ra_camsys_rawa_cam", "cam_sel", 1),
+	GATE_CAM_RA(CLK_CAM_RA_CAMSYS_RAWA_CAMTG, "cam_ra_camsys_rawa_camtg", "cam_sel", 2),
+};
+
+static const struct mtk_clk_desc cam_ra_mcd = {
+	.clks = cam_ra_clks,
+	.num_clks = ARRAY_SIZE(cam_ra_clks),
+};
+
+static const struct mtk_gate_regs cam_rb_cg_regs = {
+	.set_ofs = 0x4,
+	.clr_ofs = 0x8,
+	.sta_ofs = 0x0,
+};
+
+#define GATE_CAM_RB(_id, _name, _parent, _shift)			\
+	GATE_MTK_FLAGS(_id, _name, _parent, &cam_rb_cg_regs, _shift,	\
+		       &mtk_clk_gate_ops_setclr, CLK_IGNORE_UNUSED)
+
+static const struct mtk_gate cam_rb_clks[] = {
+	GATE_CAM_RB(CLK_CAM_RB_CAMSYS_RAWB_LARBX, "cam_rb_camsys_rawb_larbx", "cam_sel", 0),
+	GATE_CAM_RB(CLK_CAM_RB_CAMSYS_RAWB_CAM, "cam_rb_camsys_rawb_cam", "cam_sel", 1),
+	GATE_CAM_RB(CLK_CAM_RB_CAMSYS_RAWB_CAMTG, "cam_rb_camsys_rawb_camtg", "cam_sel", 2),
+};
+
+static const struct mtk_clk_desc cam_rb_mcd = {
+	.clks = cam_rb_clks,
+	.num_clks = ARRAY_SIZE(cam_rb_clks),
+};
+
+static const struct of_device_id of_match_clk_mt8189_cam[] = {
+	{ .compatible = "mediatek,mt8189-camsys-main", .data = &cam_m_mcd },
+	{ .compatible = "mediatek,mt8189-camsys-rawa", .data = &cam_ra_mcd },
+	{ .compatible = "mediatek,mt8189-camsys-rawb", .data = &cam_rb_mcd },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_match_clk_mt8189_cam);
+
+static struct platform_driver clk_mt8189_cam_drv = {
+	.probe = mtk_clk_simple_probe,
+	.remove = mtk_clk_simple_remove,
+	.driver = {
+		.name = "clk-mt8189-cam",
+		.of_match_table = of_match_clk_mt8189_cam,
+	},
+};
+
+module_platform_driver(clk_mt8189_cam_drv);
+MODULE_DESCRIPTION("MediaTek MT8189 cam clocks driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



From irving-ch.lin at mediatek.com  Sun Dec 14 19:49:16 2025
From: irving-ch.lin at mediatek.com (irving.ch.lin)
Date: Mon, 15 Dec 2025 11:49:16 +0800
Subject: [PATCH v4 07/21] clk: mediatek: Add MT8189 vlpcfg clock support
In-Reply-To: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
References: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
Message-ID: <20251215034944.2973003-8-irving-ch.lin@mediatek.com>

From: Irving-CH Lin <irving-ch.lin at mediatek.com>

Add support for the MT8189 vlpcfg clock controller,
which provides clock gate control for vlp domain IPs.

Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
---
 drivers/clk/mediatek/Makefile            |   2 +-
 drivers/clk/mediatek/clk-mt8189-vlpcfg.c | 111 +++++++++++++++++++++++
 2 files changed, 112 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/mediatek/clk-mt8189-vlpcfg.c

diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
index 3b25df9e7b50..d9279b237b7b 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -124,7 +124,7 @@ obj-$(CONFIG_COMMON_CLK_MT8188_VENCSYS) += clk-mt8188-venc.o
 obj-$(CONFIG_COMMON_CLK_MT8188_VPPSYS) += clk-mt8188-vpp0.o clk-mt8188-vpp1.o
 obj-$(CONFIG_COMMON_CLK_MT8188_WPESYS) += clk-mt8188-wpe.o
 obj-$(CONFIG_COMMON_CLK_MT8189) += clk-mt8189-apmixedsys.o clk-mt8189-topckgen.o \
-				   clk-mt8189-vlpckgen.o
+				   clk-mt8189-vlpckgen.o clk-mt8189-vlpcfg.o
 obj-$(CONFIG_COMMON_CLK_MT8192) += clk-mt8192-apmixedsys.o clk-mt8192.o
 obj-$(CONFIG_COMMON_CLK_MT8192_AUDSYS) += clk-mt8192-aud.o
 obj-$(CONFIG_COMMON_CLK_MT8192_CAMSYS) += clk-mt8192-cam.o
diff --git a/drivers/clk/mediatek/clk-mt8189-vlpcfg.c b/drivers/clk/mediatek/clk-mt8189-vlpcfg.c
new file mode 100644
index 000000000000..2b9c3101f2b4
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8189-vlpcfg.c
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Qiqi Wang <qiqi.wang at mediatek.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include "clk-mtk.h"
+#include "clk-gate.h"
+
+#include <dt-bindings/clock/mediatek,mt8189-clk.h>
+
+static const struct mtk_gate_regs vlpcfg_ao_reg_cg_regs = {
+	.set_ofs = 0x0,
+	.clr_ofs = 0x0,
+	.sta_ofs = 0x0,
+};
+
+#define GATE_VLPCFG_AO_REG(_id, _name, _parent, _shift)		\
+	GATE_MTK(_id, _name, _parent, &vlpcfg_ao_reg_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr)
+
+static const struct mtk_gate vlpcfg_ao_reg_clks[] = {
+	GATE_VLPCFG_AO_REG(CLK_VLPCFG_AO_APEINT_RX, "vlpcfg_ao_apeint_rx", "clk26m", 8),
+};
+
+static const struct mtk_clk_desc vlpcfg_ao_reg_mcd = {
+	.clks = vlpcfg_ao_reg_clks,
+	.num_clks = ARRAY_SIZE(vlpcfg_ao_reg_clks),
+};
+
+static const struct mtk_gate_regs vlpcfg_reg_cg_regs = {
+	.set_ofs = 0x4,
+	.clr_ofs = 0x4,
+	.sta_ofs = 0x4,
+};
+
+#define GATE_VLPCFG_REG_FLAGS(_id, _name, _parent, _shift, _flags)		\
+	GATE_MTK_FLAGS(_id, _name, _parent, &vlpcfg_reg_cg_regs, _shift,	\
+		       &mtk_clk_gate_ops_no_setclr_inv, _flags)
+
+#define GATE_VLPCFG_REG(_id, _name, _parent, _shift)		\
+	GATE_VLPCFG_REG_FLAGS(_id, _name, _parent, _shift, 0)
+
+static const struct mtk_gate vlpcfg_reg_clks[] = {
+	GATE_VLPCFG_REG_FLAGS(CLK_VLPCFG_REG_SCP, "vlpcfg_scp",
+			      "vlp_scp_sel", 28, CLK_IS_CRITICAL),
+	GATE_VLPCFG_REG_FLAGS(CLK_VLPCFG_REG_RG_R_APXGPT_26M, "vlpcfg_r_apxgpt_26m",
+			      "clk26m", 24, CLK_IS_CRITICAL),
+	GATE_VLPCFG_REG_FLAGS(CLK_VLPCFG_REG_DPMSRCK_TEST, "vlpcfg_dpmsrck_test",
+			      "clk26m", 23, CLK_IS_CRITICAL),
+	GATE_VLPCFG_REG_FLAGS(CLK_VLPCFG_REG_RG_DPMSRRTC_TEST, "vlpcfg_dpmsrrtc_test",
+			      "clk32k", 22, CLK_IS_CRITICAL),
+	GATE_VLPCFG_REG_FLAGS(CLK_VLPCFG_REG_DPMSRULP_TEST, "vlpcfg_dpmsrulp_test",
+			      "osc_d10", 21, CLK_IS_CRITICAL),
+	GATE_VLPCFG_REG_FLAGS(CLK_VLPCFG_REG_SPMI_P_MST, "vlpcfg_spmi_p",
+			      "vlp_spmi_p_sel", 20, CLK_IS_CRITICAL),
+	GATE_VLPCFG_REG_FLAGS(CLK_VLPCFG_REG_SPMI_P_MST_32K, "vlpcfg_spmi_p_32k",
+			      "clk32k", 18, CLK_IS_CRITICAL),
+	GATE_VLPCFG_REG_FLAGS(CLK_VLPCFG_REG_PMIF_SPMI_P_SYS, "vlpcfg_pmif_spmi_p_sys",
+			      "vlp_pwrap_ulposc_sel", 13, CLK_IS_CRITICAL),
+	GATE_VLPCFG_REG_FLAGS(CLK_VLPCFG_REG_PMIF_SPMI_P_TMR, "vlpcfg_pmif_spmi_p_tmr",
+			      "vlp_pwrap_ulposc_sel", 12, CLK_IS_CRITICAL),
+	GATE_VLPCFG_REG(CLK_VLPCFG_REG_PMIF_SPMI_M_SYS, "vlpcfg_pmif_spmi_m_sys",
+			"vlp_pwrap_ulposc_sel", 11),
+	GATE_VLPCFG_REG(CLK_VLPCFG_REG_PMIF_SPMI_M_TMR, "vlpcfg_pmif_spmi_m_tmr",
+			"vlp_pwrap_ulposc_sel", 10),
+	GATE_VLPCFG_REG_FLAGS(CLK_VLPCFG_REG_DVFSRC, "vlpcfg_dvfsrc",
+			      "vlp_dvfsrc_sel", 9, CLK_IS_CRITICAL),
+	GATE_VLPCFG_REG_FLAGS(CLK_VLPCFG_REG_PWM_VLP, "vlpcfg_pwm_vlp",
+			      "vlp_pwm_vlp_sel", 8, CLK_IS_CRITICAL),
+	GATE_VLPCFG_REG_FLAGS(CLK_VLPCFG_REG_SRCK, "vlpcfg_srck",
+			      "vlp_srck_sel", 7, CLK_IS_CRITICAL),
+	GATE_VLPCFG_REG_FLAGS(CLK_VLPCFG_REG_SSPM_F26M, "vlpcfg_sspm_f26m",
+			      "vlp_sspm_f26m_sel", 4, CLK_IS_CRITICAL),
+	GATE_VLPCFG_REG_FLAGS(CLK_VLPCFG_REG_SSPM_F32K, "vlpcfg_sspm_f32k",
+			      "clk32k", 3, CLK_IS_CRITICAL),
+	GATE_VLPCFG_REG_FLAGS(CLK_VLPCFG_REG_SSPM_ULPOSC, "vlpcfg_sspm_ulposc",
+			      "vlp_sspm_ulposc_sel", 2, CLK_IS_CRITICAL),
+	GATE_VLPCFG_REG_FLAGS(CLK_VLPCFG_REG_VLP_32K_COM, "vlpcfg_vlp_32k_com",
+			      "clk32k", 1, CLK_IS_CRITICAL),
+	GATE_VLPCFG_REG_FLAGS(CLK_VLPCFG_REG_VLP_26M_COM, "vlpcfg_vlp_26m_com",
+			      "clk26m", 0, CLK_IS_CRITICAL),
+};
+
+static const struct mtk_clk_desc vlpcfg_reg_mcd = {
+	.clks = vlpcfg_reg_clks,
+	.num_clks = ARRAY_SIZE(vlpcfg_reg_clks),
+};
+
+static const struct of_device_id of_match_clk_mt8189_vlpcfg[] = {
+	{ .compatible = "mediatek,mt8189-vlp-ao", .data = &vlpcfg_ao_reg_mcd },
+	{ .compatible = "mediatek,mt8189-vlpcfg-ao", .data = &vlpcfg_reg_mcd },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver clk_mt8189_vlpcfg_drv = {
+	.probe = mtk_clk_simple_probe,
+	.remove = mtk_clk_simple_remove,
+	.driver = {
+		.name = "clk-mt8189-vlpcfg",
+		.of_match_table = of_match_clk_mt8189_vlpcfg,
+	},
+};
+
+module_platform_driver(clk_mt8189_vlpcfg_drv);
+MODULE_DESCRIPTION("MediaTek MT8189 vlpcfg clocks driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



From irving-ch.lin at mediatek.com  Sun Dec 14 19:49:24 2025
From: irving-ch.lin at mediatek.com (irving.ch.lin)
Date: Mon, 15 Dec 2025 11:49:24 +0800
Subject: [PATCH v4 15/21] clk: mediatek: Add MT8189 mfg clock support
In-Reply-To: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
References: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
Message-ID: <20251215034944.2973003-16-irving-ch.lin@mediatek.com>

From: Irving-CH Lin <irving-ch.lin at mediatek.com>

Add support for the MT8189 mfg clock controller,
which provides clock gate control for the GPU.

Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
---
 drivers/clk/mediatek/Kconfig          | 11 ++++++
 drivers/clk/mediatek/Makefile         |  1 +
 drivers/clk/mediatek/clk-mt8189-mfg.c | 53 +++++++++++++++++++++++++++
 3 files changed, 65 insertions(+)
 create mode 100644 drivers/clk/mediatek/clk-mt8189-mfg.c

diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
index ef962f5816a8..316d010b503a 100644
--- a/drivers/clk/mediatek/Kconfig
+++ b/drivers/clk/mediatek/Kconfig
@@ -906,6 +906,17 @@ config COMMON_CLK_MT8189_MDPSYS
 	  chipset, ensuring that the display system operates efficiently and
 	  effectively.
 
+config COMMON_CLK_MT8189_MFG
+	tristate "Clock driver for MediaTek MT8189 mfg"
+	depends on COMMON_CLK_MT8189
+	default COMMON_CLK_MT8189
+	help
+	  Enable this option to support the manufacturing clocks for the MediaTek
+	  MT8189 chipset. This driver provides the necessary clock framework
+	  integration for manufacturing tests and operations that are specific to
+	  the MT8189 chipset. Enabling this will allow the manufacturing mode of
+	  the chipset to function correctly with the appropriate clock settings.
+
 config COMMON_CLK_MT8192
 	tristate "Clock driver for MediaTek MT8192"
 	depends on ARM64 || COMPILE_TEST
diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
index 9b23e4c5e019..07f11760cf68 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -132,6 +132,7 @@ obj-$(CONFIG_COMMON_CLK_MT8189_DVFSRC) += clk-mt8189-dvfsrc.o
 obj-$(CONFIG_COMMON_CLK_MT8189_IIC) += clk-mt8189-iic.o
 obj-$(CONFIG_COMMON_CLK_MT8189_IMG) += clk-mt8189-img.o
 obj-$(CONFIG_COMMON_CLK_MT8189_MDPSYS) += clk-mt8189-mdpsys.o
+obj-$(CONFIG_COMMON_CLK_MT8189_MFG) += clk-mt8189-mfg.o
 obj-$(CONFIG_COMMON_CLK_MT8192) += clk-mt8192-apmixedsys.o clk-mt8192.o
 obj-$(CONFIG_COMMON_CLK_MT8192_AUDSYS) += clk-mt8192-aud.o
 obj-$(CONFIG_COMMON_CLK_MT8192_CAMSYS) += clk-mt8192-cam.o
diff --git a/drivers/clk/mediatek/clk-mt8189-mfg.c b/drivers/clk/mediatek/clk-mt8189-mfg.c
new file mode 100644
index 000000000000..a09bf8f2e017
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8189-mfg.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Qiqi Wang <qiqi.wang at mediatek.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include "clk-mtk.h"
+#include "clk-gate.h"
+
+#include <dt-bindings/clock/mediatek,mt8189-clk.h>
+
+static const struct mtk_gate_regs mfg_cg_regs = {
+	.set_ofs = 0x4,
+	.clr_ofs = 0x8,
+	.sta_ofs = 0x0,
+};
+
+#define GATE_MFG(_id, _name, _parent, _shift)				\
+	GATE_MTK_FLAGS(_id, _name, _parent, &mfg_cg_regs, _shift,	\
+		       &mtk_clk_gate_ops_setclr, CLK_IGNORE_UNUSED)
+
+static const struct mtk_gate mfg_clks[] = {
+	GATE_MFG(CLK_MFG_BG3D, "mfg_bg3d", "mfg_sel_mfgpll", 0),
+};
+
+static const struct mtk_clk_desc mfg_mcd = {
+	.clks = mfg_clks,
+	.num_clks = ARRAY_SIZE(mfg_clks),
+};
+
+static const struct of_device_id of_match_clk_mt8189_mfg[] = {
+	{ .compatible = "mediatek,mt8189-mfgcfg", .data = &mfg_mcd },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_match_clk_mt8189_mfg);
+
+static struct platform_driver clk_mt8189_mfg_drv = {
+	.probe = mtk_clk_simple_probe,
+	.remove = mtk_clk_simple_remove,
+	.driver = {
+		.name = "clk-mt8189-mfg",
+		.of_match_table = of_match_clk_mt8189_mfg,
+	},
+};
+
+module_platform_driver(clk_mt8189_mfg_drv);
+MODULE_DESCRIPTION("MediaTek MT8189 mfg clocks driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



From irving-ch.lin at mediatek.com  Sun Dec 14 19:49:22 2025
From: irving-ch.lin at mediatek.com (irving.ch.lin)
Date: Mon, 15 Dec 2025 11:49:22 +0800
Subject: [PATCH v4 13/21] clk: mediatek: Add MT8189 img clock support
In-Reply-To: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
References: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
Message-ID: <20251215034944.2973003-14-irving-ch.lin@mediatek.com>

From: Irving-CH Lin <irving-ch.lin at mediatek.com>

Add support for the MT8189 img clock controller,
which provides clock gate control for image processing module.

Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
---
 drivers/clk/mediatek/Kconfig          |  11 +++
 drivers/clk/mediatek/Makefile         |   1 +
 drivers/clk/mediatek/clk-mt8189-img.c | 107 ++++++++++++++++++++++++++
 3 files changed, 119 insertions(+)
 create mode 100644 drivers/clk/mediatek/clk-mt8189-img.c

diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
index 71603fba2ea8..c0fe1aa49993 100644
--- a/drivers/clk/mediatek/Kconfig
+++ b/drivers/clk/mediatek/Kconfig
@@ -883,6 +883,17 @@ config COMMON_CLK_MT8189_IIC
 	  the MT8189 chipset, improving the overall performance and power
 	  efficiency of the device.
 
+config COMMON_CLK_MT8189_IMG
+	tristate "Clock driver for MediaTek MT8189 img"
+	depends on COMMON_CLK_MT8189
+	default COMMON_CLK_MT8189
+	help
+	  Enable this to support the clock framework for MediaTek MT8189 SoC's
+	  image processing units. This includes clocks necessary for the operation
+	  of image-related hardware blocks such as ISP, VENC, and VDEC. If you
+	  are building a kernel for a device that uses the MT8189 SoC and requires
+	  image processing capabilities, say Y or M to include this driver.
+
 config COMMON_CLK_MT8192
 	tristate "Clock driver for MediaTek MT8192"
 	depends on ARM64 || COMPILE_TEST
diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
index 0eed1edf7c63..a1eaf123f2f0 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -130,6 +130,7 @@ obj-$(CONFIG_COMMON_CLK_MT8189_CAM) += clk-mt8189-cam.o
 obj-$(CONFIG_COMMON_CLK_MT8189_DBGAO) += clk-mt8189-dbgao.o
 obj-$(CONFIG_COMMON_CLK_MT8189_DVFSRC) += clk-mt8189-dvfsrc.o
 obj-$(CONFIG_COMMON_CLK_MT8189_IIC) += clk-mt8189-iic.o
+obj-$(CONFIG_COMMON_CLK_MT8189_IMG) += clk-mt8189-img.o
 obj-$(CONFIG_COMMON_CLK_MT8192) += clk-mt8192-apmixedsys.o clk-mt8192.o
 obj-$(CONFIG_COMMON_CLK_MT8192_AUDSYS) += clk-mt8192-aud.o
 obj-$(CONFIG_COMMON_CLK_MT8192_CAMSYS) += clk-mt8192-cam.o
diff --git a/drivers/clk/mediatek/clk-mt8189-img.c b/drivers/clk/mediatek/clk-mt8189-img.c
new file mode 100644
index 000000000000..d79f48dbe3e1
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8189-img.c
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Qiqi Wang <qiqi.wang at mediatek.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include "clk-mtk.h"
+#include "clk-gate.h"
+
+#include <dt-bindings/clock/mediatek,mt8189-clk.h>
+
+static const struct mtk_gate_regs imgsys1_cg_regs = {
+	.set_ofs = 0x4,
+	.clr_ofs = 0x8,
+	.sta_ofs = 0x0,
+};
+
+#define GATE_IMGSYS1(_id, _name, _parent, _shift)			\
+	GATE_MTK_FLAGS(_id, _name, _parent, &imgsys1_cg_regs, _shift,	\
+		       &mtk_clk_gate_ops_setclr, CLK_IGNORE_UNUSED)
+
+static const struct mtk_gate imgsys1_clks[] = {
+	GATE_IMGSYS1(CLK_IMGSYS1_LARB9, "imgsys1_larb9", "img1_sel", 0),
+	GATE_IMGSYS1(CLK_IMGSYS1_LARB11, "imgsys1_larb11", "img1_sel", 1),
+	GATE_IMGSYS1(CLK_IMGSYS1_DIP, "imgsys1_dip", "img1_sel", 2),
+	GATE_IMGSYS1(CLK_IMGSYS1_GALS, "imgsys1_gals", "img1_sel", 12),
+};
+
+static const struct mtk_clk_desc imgsys1_mcd = {
+	.clks = imgsys1_clks,
+	.num_clks = ARRAY_SIZE(imgsys1_clks),
+};
+
+static const struct mtk_gate_regs imgsys2_cg_regs = {
+	.set_ofs = 0x4,
+	.clr_ofs = 0x8,
+	.sta_ofs = 0x0,
+};
+
+#define GATE_IMGSYS2(_id, _name, _parent, _shift)			\
+	GATE_MTK_FLAGS(_id, _name, _parent, &imgsys2_cg_regs, _shift,	\
+		       &mtk_clk_gate_ops_setclr, CLK_IGNORE_UNUSED)
+
+static const struct mtk_gate imgsys2_clks[] = {
+	GATE_IMGSYS2(CLK_IMGSYS2_LARB9, "imgsys2_larb9", "img1_sel", 0),
+	GATE_IMGSYS2(CLK_IMGSYS2_LARB11, "imgsys2_larb11", "img1_sel", 1),
+	GATE_IMGSYS2(CLK_IMGSYS2_MFB, "imgsys2_mfb", "img1_sel", 6),
+	GATE_IMGSYS2(CLK_IMGSYS2_WPE, "imgsys2_wpe", "img1_sel", 7),
+	GATE_IMGSYS2(CLK_IMGSYS2_MSS, "imgsys2_mss", "img1_sel", 8),
+	GATE_IMGSYS2(CLK_IMGSYS2_GALS, "imgsys2_gals", "img1_sel", 12),
+};
+
+static const struct mtk_clk_desc imgsys2_mcd = {
+	.clks = imgsys2_clks,
+	.num_clks = ARRAY_SIZE(imgsys2_clks),
+};
+
+static const struct mtk_gate_regs ipe_cg_regs = {
+	.set_ofs = 0x4,
+	.clr_ofs = 0x8,
+	.sta_ofs = 0x0,
+};
+
+#define GATE_IPE(_id, _name, _parent, _shift)				\
+	GATE_MTK_FLAGS(_id, _name, _parent, &ipe_cg_regs, _shift,	\
+		       &mtk_clk_gate_ops_setclr, CLK_IGNORE_UNUSED)
+
+static const struct mtk_gate ipe_clks[] = {
+	GATE_IPE(CLK_IPE_LARB19, "ipe_larb19", "ipe_sel", 0),
+	GATE_IPE(CLK_IPE_LARB20, "ipe_larb20", "ipe_sel", 1),
+	GATE_IPE(CLK_IPE_SMI_SUBCOM, "ipe_smi_subcom", "ipe_sel", 2),
+	GATE_IPE(CLK_IPE_FD, "ipe_fd", "ipe_sel", 3),
+	GATE_IPE(CLK_IPE_FE, "ipe_fe", "ipe_sel", 4),
+	GATE_IPE(CLK_IPE_RSC, "ipe_rsc", "ipe_sel", 5),
+	GATE_IPE(CLK_IPESYS_GALS, "ipesys_gals", "ipe_sel", 8),
+};
+
+static const struct mtk_clk_desc ipe_mcd = {
+	.clks = ipe_clks,
+	.num_clks = ARRAY_SIZE(ipe_clks),
+};
+
+static const struct of_device_id of_match_clk_mt8189_img[] = {
+	{ .compatible = "mediatek,mt8189-imgsys1", .data = &imgsys1_mcd },
+	{ .compatible = "mediatek,mt8189-imgsys2", .data = &imgsys2_mcd },
+	{ .compatible = "mediatek,mt8189-ipesys", .data = &ipe_mcd },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_match_clk_mt8189_img);
+
+static struct platform_driver clk_mt8189_img_drv = {
+	.probe = mtk_clk_simple_probe,
+	.remove = mtk_clk_simple_remove,
+	.driver = {
+		.name = "clk-mt8189-img",
+		.of_match_table = of_match_clk_mt8189_img,
+	},
+};
+
+module_platform_driver(clk_mt8189_img_drv);
+MODULE_DESCRIPTION("MediaTek MT8189 img clocks driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



From irving-ch.lin at mediatek.com  Sun Dec 14 19:49:14 2025
From: irving-ch.lin at mediatek.com (irving.ch.lin)
Date: Mon, 15 Dec 2025 11:49:14 +0800
Subject: [PATCH v4 05/21] clk: mediatek: Add MT8189 topckgen clock support
In-Reply-To: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
References: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
Message-ID: <20251215034944.2973003-6-irving-ch.lin@mediatek.com>

From: Irving-CH Lin <irving-ch.lin at mediatek.com>

Add support for the MT8189 topckgen clock controller, which provides
muxes and dividers for clock selection in other IP blocks.

Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
---
 drivers/clk/mediatek/Makefile              |    2 +-
 drivers/clk/mediatek/clk-mt8189-topckgen.c | 1020 ++++++++++++++++++++
 2 files changed, 1021 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/mediatek/clk-mt8189-topckgen.c

diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
index 66577ccb9b93..9d3d2983bfb2 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -123,7 +123,7 @@ obj-$(CONFIG_COMMON_CLK_MT8188_VDOSYS) += clk-mt8188-vdo0.o clk-mt8188-vdo1.o
 obj-$(CONFIG_COMMON_CLK_MT8188_VENCSYS) += clk-mt8188-venc.o
 obj-$(CONFIG_COMMON_CLK_MT8188_VPPSYS) += clk-mt8188-vpp0.o clk-mt8188-vpp1.o
 obj-$(CONFIG_COMMON_CLK_MT8188_WPESYS) += clk-mt8188-wpe.o
-obj-$(CONFIG_COMMON_CLK_MT8189) += clk-mt8189-apmixedsys.o
+obj-$(CONFIG_COMMON_CLK_MT8189) += clk-mt8189-apmixedsys.o clk-mt8189-topckgen.o
 obj-$(CONFIG_COMMON_CLK_MT8192) += clk-mt8192-apmixedsys.o clk-mt8192.o
 obj-$(CONFIG_COMMON_CLK_MT8192_AUDSYS) += clk-mt8192-aud.o
 obj-$(CONFIG_COMMON_CLK_MT8192_CAMSYS) += clk-mt8192-cam.o
diff --git a/drivers/clk/mediatek/clk-mt8189-topckgen.c b/drivers/clk/mediatek/clk-mt8189-topckgen.c
new file mode 100644
index 000000000000..dcc3c21bf3a4
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8189-topckgen.c
@@ -0,0 +1,1020 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Qiqi Wang <qiqi.wang at mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "clk-mtk.h"
+#include "clk-mux.h"
+#include "clk-gate.h"
+
+#include <dt-bindings/clock/mediatek,mt8189-clk.h>
+
+static DEFINE_SPINLOCK(mt8189_clk_lock);
+
+static const struct mtk_fixed_factor top_divs[] = {
+	FACTOR(CLK_TOP_MAINPLL_D3, "mainpll_d3", "mainpll", 1, 3),
+	FACTOR(CLK_TOP_MAINPLL_D4, "mainpll_d4", "mainpll", 1, 4),
+	FACTOR(CLK_TOP_MAINPLL_D4_D2, "mainpll_d4_d2", "mainpll", 1, 8),
+	FACTOR(CLK_TOP_MAINPLL_D4_D4, "mainpll_d4_d4", "mainpll", 1, 16),
+	FACTOR(CLK_TOP_MAINPLL_D4_D8, "mainpll_d4_d8", "mainpll", 43, 1375),
+	FACTOR(CLK_TOP_MAINPLL_D5, "mainpll_d5", "mainpll", 1, 5),
+	FACTOR(CLK_TOP_MAINPLL_D5_D2, "mainpll_d5_d2", "mainpll", 1, 10),
+	FACTOR(CLK_TOP_MAINPLL_D5_D4, "mainpll_d5_d4", "mainpll", 1, 20),
+	FACTOR(CLK_TOP_MAINPLL_D5_D8, "mainpll_d5_d8", "mainpll", 1, 40),
+	FACTOR(CLK_TOP_MAINPLL_D6, "mainpll_d6", "mainpll", 1, 6),
+	FACTOR(CLK_TOP_MAINPLL_D6_D2, "mainpll_d6_d2", "mainpll", 1, 12),
+	FACTOR(CLK_TOP_MAINPLL_D6_D4, "mainpll_d6_d4", "mainpll", 1, 24),
+	FACTOR(CLK_TOP_MAINPLL_D6_D8, "mainpll_d6_d8", "mainpll", 1, 48),
+	FACTOR(CLK_TOP_MAINPLL_D7, "mainpll_d7", "mainpll", 1, 7),
+	FACTOR(CLK_TOP_MAINPLL_D7_D2, "mainpll_d7_d2", "mainpll", 1, 14),
+	FACTOR(CLK_TOP_MAINPLL_D7_D4, "mainpll_d7_d4", "mainpll", 1, 28),
+	FACTOR(CLK_TOP_MAINPLL_D7_D8, "mainpll_d7_d8", "mainpll", 1, 56),
+	FACTOR(CLK_TOP_MAINPLL_D9, "mainpll_d9", "mainpll", 1, 9),
+	FACTOR(CLK_TOP_UNIVPLL_D2, "univpll_d2", "univpll", 1, 2),
+	FACTOR(CLK_TOP_UNIVPLL_D3, "univpll_d3", "univpll", 1, 3),
+	FACTOR(CLK_TOP_UNIVPLL_D4, "univpll_d4", "univpll", 1, 4),
+	FACTOR(CLK_TOP_UNIVPLL_D4_D2, "univpll_d4_d2", "univpll", 1, 8),
+	FACTOR(CLK_TOP_UNIVPLL_D4_D4, "univpll_d4_d4", "univpll", 1, 16),
+	FACTOR(CLK_TOP_UNIVPLL_D4_D8, "univpll_d4_d8", "univpll", 1, 32),
+	FACTOR(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univpll", 1, 5),
+	FACTOR(CLK_TOP_UNIVPLL_D5_D2, "univpll_d5_d2", "univpll", 1, 10),
+	FACTOR(CLK_TOP_UNIVPLL_D5_D4, "univpll_d5_d4", "univpll", 1, 20),
+	FACTOR(CLK_TOP_UNIVPLL_D6, "univpll_d6", "univpll", 1, 6),
+	FACTOR(CLK_TOP_UNIVPLL_D6_D2, "univpll_d6_d2", "univpll", 1, 12),
+	FACTOR(CLK_TOP_UNIVPLL_D6_D4, "univpll_d6_d4", "univpll", 1, 24),
+	FACTOR(CLK_TOP_UNIVPLL_D6_D8, "univpll_d6_d8", "univpll", 1, 48),
+	FACTOR(CLK_TOP_UNIVPLL_D6_D16, "univpll_d6_d16", "univpll", 1, 96),
+	FACTOR(CLK_TOP_UNIVPLL_D7, "univpll_d7", "univpll", 1, 7),
+	FACTOR(CLK_TOP_UNIVPLL_D7_D2, "univpll_d7_d2", "univpll", 1, 14),
+	FACTOR(CLK_TOP_UNIVPLL_D7_D3, "univpll_d7_d3", "univpll", 1, 21),
+	FACTOR(CLK_TOP_LVDSTX_DG_CTS, "lvdstx_dg_cts", "univpll", 1, 21),
+	FACTOR(CLK_TOP_UNIVPLL_192M, "univpll_192m", "univpll", 1, 13),
+	FACTOR(CLK_TOP_UNIVPLL_192M_D2, "univpll_192m_d2", "univpll", 1, 26),
+	FACTOR(CLK_TOP_UNIVPLL_192M_D4, "univpll_192m_d4", "univpll", 1, 52),
+	FACTOR(CLK_TOP_UNIVPLL_192M_D8, "univpll_192m_d8", "univpll", 1, 104),
+	FACTOR(CLK_TOP_UNIVPLL_192M_D10, "univpll_192m_d10", "univpll", 1, 130),
+	FACTOR(CLK_TOP_UNIVPLL_192M_D16, "univpll_192m_d16", "univpll", 1, 208),
+	FACTOR(CLK_TOP_UNIVPLL_192M_D32, "univpll_192m_d32", "univpll", 1, 416),
+	FACTOR(CLK_TOP_APLL1_D2, "apll1_d2", "apll1", 1, 2),
+	FACTOR(CLK_TOP_APLL1_D4, "apll1_d4", "apll1", 1, 4),
+	FACTOR(CLK_TOP_APLL1_D8, "apll1_d8", "apll1", 1, 8),
+	FACTOR(CLK_TOP_APLL1_D3, "apll1_d3", "apll1", 1, 3),
+	FACTOR(CLK_TOP_APLL2_D2, "apll2_d2", "apll2", 1, 2),
+	FACTOR(CLK_TOP_APLL2_D4, "apll2_d4", "apll2", 1, 4),
+	FACTOR(CLK_TOP_APLL2_D8, "apll2_d8", "apll2", 1, 8),
+	FACTOR(CLK_TOP_APLL2_D3, "apll2_d3", "apll2", 1, 3),
+	FACTOR(CLK_TOP_MMPLL_D4, "mmpll_d4", "mmpll", 1, 4),
+	FACTOR(CLK_TOP_MMPLL_D4_D2, "mmpll_d4_d2", "mmpll", 1, 8),
+	FACTOR(CLK_TOP_MMPLL_D4_D4, "mmpll_d4_d4", "mmpll", 1, 16),
+	FACTOR(CLK_TOP_VPLL_DPIX, "vpll_dpix", "mmpll", 1, 16),
+	FACTOR(CLK_TOP_MMPLL_D5, "mmpll_d5", "mmpll", 1, 5),
+	FACTOR(CLK_TOP_MMPLL_D5_D2, "mmpll_d5_d2", "mmpll", 1, 10),
+	FACTOR(CLK_TOP_MMPLL_D5_D4, "mmpll_d5_d4", "mmpll", 1, 20),
+	FACTOR(CLK_TOP_MMPLL_D6, "mmpll_d6", "mmpll", 1, 6),
+	FACTOR(CLK_TOP_MMPLL_D6_D2, "mmpll_d6_d2", "mmpll", 1, 12),
+	FACTOR(CLK_TOP_MMPLL_D7, "mmpll_d7", "mmpll", 1, 7),
+	FACTOR(CLK_TOP_MMPLL_D9, "mmpll_d9", "mmpll", 1, 9),
+	FACTOR(CLK_TOP_TVDPLL1_D2, "tvdpll1_d2", "tvdpll1", 1, 2),
+	FACTOR(CLK_TOP_TVDPLL1_D4, "tvdpll1_d4", "tvdpll1", 1, 4),
+	FACTOR(CLK_TOP_TVDPLL1_D8, "tvdpll1_d8", "tvdpll1", 1, 8),
+	FACTOR(CLK_TOP_TVDPLL1_D16, "tvdpll1_d16", "tvdpll1", 92, 1473),
+	FACTOR(CLK_TOP_TVDPLL2_D2, "tvdpll2_d2", "tvdpll2", 1, 2),
+	FACTOR(CLK_TOP_TVDPLL2_D4, "tvdpll2_d4", "tvdpll2", 1, 4),
+	FACTOR(CLK_TOP_TVDPLL2_D8, "tvdpll2_d8", "tvdpll2", 1, 8),
+	FACTOR(CLK_TOP_TVDPLL2_D16, "tvdpll2_d16", "tvdpll2", 92, 1473),
+	FACTOR(CLK_TOP_ETHPLL_D2, "ethpll_d2", "ethpll", 1, 2),
+	FACTOR(CLK_TOP_ETHPLL_D8, "ethpll_d8", "ethpll", 1, 8),
+	FACTOR(CLK_TOP_ETHPLL_D10, "ethpll_d10", "ethpll", 1, 10),
+	FACTOR(CLK_TOP_MSDCPLL_D2, "msdcpll_d2", "msdcpll", 1, 2),
+	FACTOR(CLK_TOP_UFSPLL_D2, "ufspll_d2", "ufspll", 1, 2),
+	FACTOR(CLK_TOP_F26M_CK_D2, "f26m_d2", "clk26m", 1, 2),
+	FACTOR(CLK_TOP_OSC_D2, "osc_d2", "ulposc", 1, 2),
+	FACTOR(CLK_TOP_OSC_D4, "osc_d4", "ulposc", 1, 4),
+	FACTOR(CLK_TOP_OSC_D8, "osc_d8", "ulposc", 1, 8),
+	FACTOR(CLK_TOP_OSC_D16, "osc_d16", "ulposc", 61, 973),
+	FACTOR(CLK_TOP_OSC_D3, "osc_d3", "ulposc", 1, 3),
+	FACTOR(CLK_TOP_OSC_D7, "osc_d7", "ulposc", 1, 7),
+	FACTOR(CLK_TOP_OSC_D10, "osc_d10", "ulposc", 1, 10),
+	FACTOR(CLK_TOP_OSC_D20, "osc_d20", "ulposc", 1, 20),
+};
+
+static const char * const ap2conn_host_parents[] = {
+	"clk26m",
+	"mainpll_d7_d4"
+};
+
+static const char * const apll_m_parents[] = {
+	"aud_1_sel",
+	"aud_2_sel"
+};
+
+static const char * const aud_1_parents[] = {
+	"clk26m",
+	"apll1"
+};
+
+static const char * const aud_2_parents[] = {
+	"clk26m",
+	"apll2"
+};
+
+static const char * const mfg_sel_mfgpll_parents[] = {
+	"mfg_ref_sel",
+	"mfgpll"
+};
+
+static const char * const pwm_parents[] = {
+	"clk26m",
+	"univpll_d4_d8"
+};
+
+static const char * const snps_eth_250m_parents[] = {
+	"clk26m",
+	"ethpll_d2"
+};
+
+static const char * const snps_eth_50m_rmii_parents[] = {
+	"clk26m",
+	"ethpll_d10"
+};
+
+static const char * const uart_parents[] = {
+	"clk26m",
+	"univpll_d6_d8"
+};
+
+static const char * const atb_parents[] = {
+	"clk26m",
+	"mainpll_d4_d2",
+	"mainpll_d5_d2"
+};
+
+static const char * const aud_intbus_parents[] = {
+	"clk26m",
+	"mainpll_d4_d4",
+	"mainpll_d7_d4"
+};
+
+static const char * const msdc5hclk_parents[] = {
+	"clk26m",
+	"mainpll_d4_d2",
+	"mainpll_d6_d2"
+};
+
+static const char * const pcie_mac_tl_parents[] = {
+	"clk26m",
+	"mainpll_d4_d4",
+	"univpll_d5_d4"
+};
+
+static const char * const pll_dpix_parents[] = {
+	"clk26m",
+	"vpll_dpix",
+	"mmpll_d4_d4"
+};
+
+static const char * const usb_parents[] = {
+	"clk26m",
+	"univpll_d5_d4",
+	"univpll_d6_d4"
+};
+
+static const char * const vdstx_dg_cts_parents[] = {
+	"clk26m",
+	"lvdstx_dg_cts",
+	"univpll_d7_d3"
+};
+
+static const char * const audio_h_parents[] = {
+	"clk26m",
+	"univpll_d7_d2",
+	"apll1",
+	"apll2"
+};
+
+static const char * const aud_engen1_parents[] = {
+	"clk26m",
+	"apll1_d2",
+	"apll1_d4",
+	"apll1_d8"
+};
+
+static const char * const aud_engen2_parents[] = {
+	"clk26m",
+	"apll2_d2",
+	"apll2_d4",
+	"apll2_d8"
+};
+
+static const char * const axi_peri_parents[] = {
+	"clk26m",
+	"mainpll_d4_d4",
+	"mainpll_d7_d2",
+	"osc_d4"
+};
+
+static const char * const axi_u_parents[] = {
+	"clk26m",
+	"mainpll_d4_d8",
+	"mainpll_d7_d4",
+	"osc_d8"
+};
+
+static const char * const camtm_parents[] = {
+	"clk26m",
+	"osc_d2",
+	"univpll_d6_d2",
+	"univpll_d6_d4"
+};
+
+static const char * const dsi_occ_parents[] = {
+	"clk26m",
+	"univpll_d6_d2",
+	"univpll_d5_d2",
+	"univpll_d4_d2"
+};
+
+static const char * const dxcc_parents[] = {
+	"clk26m",
+	"mainpll_d4_d8",
+	"mainpll_d4_d4",
+	"mainpll_d4_d2"
+};
+
+static const char * const i2c_parents[] = {
+	"clk26m",
+	"mainpll_d4_d8",
+	"univpll_d5_d4",
+	"mainpll_d4_d4"
+};
+
+static const char * const mcupm_parents[] = {
+	"clk26m",
+	"univpll_d6_d2",
+	"mainpll_d5_d2",
+	"mainpll_d6_d2"
+};
+
+static const char * const mfg_ref_parents[] = {
+	"clk26m",
+	"mainpll_d6_d2",
+	"mainpll_d6",
+	"mainpll_d5_d2"
+};
+
+static const char * const msdc30_h_parents[] = {
+	"clk26m",
+	"msdcpll_d2",
+	"mainpll_d4_d4",
+	"mainpll_d6_d4"
+};
+
+static const char * const msdc_macro_p_parents[] = {
+	"clk26m",
+	"msdcpll",
+	"mmpll_d5_d4",
+	"univpll_d4_d2"
+};
+
+static const char * const snps_eth_62p4m_ptp_parents[] = {
+	"clk26m",
+	"ethpll_d8",
+	"apll1_d3",
+	"apll2_d3"
+};
+
+static const char * const ufs_mbist_parents[] = {
+	"clk26m",
+	"mainpll_d4_d2",
+	"univpll_d4_d2",
+	"ufspll_d2"
+};
+
+static const char * const aes_msdcfde_parents[] = {
+	"clk26m",
+	"mainpll_d4_d2",
+	"mainpll_d6",
+	"mainpll_d4_d4",
+	"msdcpll"
+};
+
+static const char * const bus_aximem_parents[] = {
+	"clk26m",
+	"mainpll_d7_d2",
+	"mainpll_d5_d2",
+	"mainpll_d4_d2",
+	"mainpll_d6"
+};
+
+static const char * const dp_parents[] = {
+	"clk26m",
+	"tvdpll1_d16",
+	"tvdpll1_d8",
+	"tvdpll1_d4",
+	"tvdpll1_d2"
+};
+
+static const char * const msdc30_parents[] = {
+	"clk26m",
+	"univpll_d6_d2",
+	"mainpll_d6_d2",
+	"mainpll_d7_d2",
+	"msdcpll_d2"
+};
+
+static const char * const ecc_parents[] = {
+	"clk26m",
+	"univpll_d6_d2",
+	"univpll_d4_d2",
+	"univpll_d6",
+	"mainpll_d4",
+	"univpll_d4"
+};
+
+static const char * const emi_n_parents[] = {
+	"clk26m",
+	"osc_d2",
+	"mainpll_d9",
+	"mainpll_d6",
+	"mainpll_d5",
+	"emipll"
+};
+
+static const char * const sr_pka_parents[] = {
+	"clk26m",
+	"mainpll_d4_d4",
+	"mainpll_d4_d2",
+	"mainpll_d7",
+	"mainpll_d6",
+	"mainpll_d5"
+};
+
+static const char * const aes_ufsfde_parents[] = {
+	"clk26m",
+	"mainpll_d4",
+	"mainpll_d4_d2",
+	"mainpll_d6",
+	"mainpll_d4_d4",
+	"univpll_d4_d2",
+	"univpll_d6"
+};
+
+static const char * const axi_parents[] = {
+	"clk26m",
+	"mainpll_d4_d4",
+	"mainpll_d7_d2",
+	"mainpll_d4_d2",
+	"mainpll_d5_d2",
+	"mainpll_d6_d2",
+	"osc_d4"
+};
+
+static const char * const disp_pwm_parents[] = {
+	"clk26m",
+	"univpll_d6_d4",
+	"osc_d2",
+	"osc_d4",
+	"osc_d16",
+	"univpll_d5_d4",
+	"mainpll_d4_d4"
+};
+
+static const char * const edp_parents[] = {
+	"clk26m",
+	"tvdpll2_d16",
+	"tvdpll2_d8",
+	"tvdpll2_d4",
+	"tvdpll2_d2"
+};
+
+static const char * const gcpu_parents[] = {
+	"clk26m",
+	"mainpll_d6",
+	"mainpll_d4_d2",
+	"univpll_d4_d2",
+	"univpll_d5_d2",
+	"univpll_d5_d4",
+	"univpll_d6"
+};
+
+static const char * const msdc50_0_parents[] = {
+	"clk26m",
+	"msdcpll",
+	"msdcpll_d2",
+	"mainpll_d6_d2",
+	"mainpll_d4_d4",
+	"mainpll_d6",
+	"univpll_d4_d4"
+};
+
+static const char * const ufs_parents[] = {
+	"clk26m",
+	"mainpll_d4_d8",
+	"mainpll_d4_d4",
+	"mainpll_d5_d2",
+	"mainpll_d6_d2",
+	"univpll_d6_d2",
+	"msdcpll_d2"
+};
+
+static const char * const dsp_parents[] = {
+	"clk26m",
+	"osc_d4",
+	"osc_d3",
+	"osc_d2",
+	"univpll_d7_d2",
+	"univpll_d6_d2",
+	"mainpll_d6",
+	"univpll_d5"
+};
+
+static const char * const mem_sub_peri_u_parents[] = {
+	"clk26m",
+	"univpll_d4_d4",
+	"mainpll_d5_d2",
+	"mainpll_d4_d2",
+	"mainpll_d6",
+	"mainpll_d5",
+	"univpll_d5",
+	"mainpll_d4"
+};
+
+static const char * const seninf_parents[] = {
+	"clk26m",
+	"osc_d2",
+	"univpll_d6_d2",
+	"mainpll_d4_d2",
+	"univpll_d4_d2",
+	"mmpll_d7",
+	"univpll_d6",
+	"univpll_d5"
+};
+
+static const char * const sflash_parents[] = {
+	"clk26m",
+	"mainpll_d7_d8",
+	"univpll_d6_d8",
+	"mainpll_d7_d4",
+	"mainpll_d6_d4",
+	"univpll_d6_d4",
+	"univpll_d7_d3",
+	"univpll_d5_d4"
+};
+
+static const char * const spi_parents[] = {
+	"clk26m",
+	"univpll_d6_d2",
+	"univpll_192m",
+	"mainpll_d6_d2",
+	"univpll_d4_d4",
+	"mainpll_d4_d4",
+	"univpll_d5_d4",
+	"univpll_d6_d4"
+};
+
+static const char * const img1_parents[] = {
+	"clk26m",
+	"univpll_d4",
+	"mmpll_d5",
+	"mmpll_d6",
+	"univpll_d6",
+	"mmpll_d7",
+	"mmpll_d4_d2",
+	"univpll_d4_d2",
+	"mainpll_d4_d2",
+	"mmpll_d6_d2",
+	"mmpll_d5_d2"
+};
+
+static const char * const ipe_parents[] = {
+	"clk26m",
+	"univpll_d4",
+	"mainpll_d4",
+	"mmpll_d6",
+	"univpll_d6",
+	"mainpll_d6",
+	"mmpll_d4_d2",
+	"univpll_d4_d2",
+	"mainpll_d4_d2",
+	"mmpll_d6_d2",
+	"mmpll_d5_d2"
+};
+
+static const char * const mem_sub_parents[] = {
+	"clk26m",
+	"univpll_d4_d4",
+	"mainpll_d6_d2",
+	"mainpll_d5_d2",
+	"mainpll_d4_d2",
+	"mainpll_d6",
+	"mmpll_d7",
+	"mainpll_d5",
+	"univpll_d5",
+	"mainpll_d4",
+	"univpll_d4"
+};
+
+static const char * const cam_parents[] = {
+	"clk26m",
+	"mainpll_d4",
+	"mmpll_d4",
+	"univpll_d4",
+	"univpll_d5",
+	"mmpll_d7",
+	"mmpll_d6",
+	"univpll_d6",
+	"univpll_d4_d2",
+	"mmpll_d9",
+	"mainpll_d4_d2",
+	"osc_d2"
+};
+
+static const char * const mmsys_parents[] = {
+	"clk26m",
+	"mainpll_d5_d2",
+	"univpll_d5_d2",
+	"mainpll_d4_d2",
+	"univpll_d4_d2",
+	"mainpll_d6",
+	"univpll_d6",
+	"mmpll_d6",
+	"tvdpll1",
+	"tvdpll2",
+	"univpll_d4",
+	"mmpll_d4"
+};
+
+static const char * const mminfra_parents[] = {
+	"clk26m",
+	"osc_d2",
+	"mainpll_d5_d2",
+	"mmpll_d6_d2",
+	"mainpll_d4_d2",
+	"mmpll_d4_d2",
+	"mainpll_d6",
+	"mmpll_d7",
+	"univpll_d6",
+	"mainpll_d5",
+	"mmpll_d6",
+	"univpll_d5",
+	"mainpll_d4",
+	"univpll_d4",
+	"mmpll_d4",
+	"emipll"
+};
+
+static const char * const vdec_parents[] = {
+	"clk26m",
+	"univpll_192m_d2",
+	"univpll_d5_d4",
+	"mainpll_d5",
+	"mainpll_d5_d2",
+	"mmpll_d6_d2",
+	"univpll_d5_d2",
+	"mainpll_d4_d2",
+	"univpll_d4_d2",
+	"univpll_d7",
+	"mmpll_d7",
+	"mmpll_d6",
+	"univpll_d6",
+	"mainpll_d4",
+	"univpll_d4",
+	"mmpll_d5_d2"
+};
+
+static const char * const venc_parents[] = {
+	"clk26m",
+	"mmpll_d4_d2",
+	"mainpll_d6",
+	"univpll_d4_d2",
+	"mainpll_d4_d2",
+	"univpll_d6",
+	"mmpll_d6",
+	"mainpll_d5_d2",
+	"mainpll_d6_d2",
+	"mmpll_d9",
+	"mmpll_d4",
+	"mainpll_d4",
+	"univpll_d4",
+	"univpll_d5",
+	"univpll_d5_d2",
+	"mainpll_d5"
+};
+
+static const struct mtk_mux top_muxes[] = {
+	/* CLK_CFG_0 */
+	MUX_CLR_SET_UPD(CLK_TOP_AXI_SEL, "axi_sel",
+			axi_parents, 0x010, 0x014, 0x018, 0, 3, 0x04, 0),
+	MUX_CLR_SET_UPD(CLK_TOP_AXI_PERI_SEL, "axi_peri_sel",
+			axi_peri_parents, 0x010, 0x014, 0x018,
+			8, 2, 0x04, 1),
+	MUX_CLR_SET_UPD(CLK_TOP_AXI_U_SEL, "axi_u_sel",
+			axi_u_parents, 0x010, 0x014, 0x018,
+			16, 2, 0x04, 2),
+	MUX_CLR_SET_UPD(CLK_TOP_BUS_AXIMEM_SEL, "bus_aximem_sel",
+			bus_aximem_parents, 0x010, 0x014, 0x018,
+			24, 3, 0x04, 3),
+	/* CLK_CFG_1 */
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_DISP0_SEL, "disp0_sel",
+			     mmsys_parents, 0x020, 0x024, 0x028,
+			     0, 4, 7, 0x04, 4),
+	MUX_CLR_SET_UPD(CLK_TOP_MMINFRA_SEL, "mminfra_sel",
+			mminfra_parents, 0x020, 0x024, 0x028,
+			8, 4, 0x04, 5),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_UART_SEL, "uart_sel",
+			     uart_parents, 0x020, 0x024, 0x028,
+			     16, 1, 23, 0x04, 6),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_SPI0_SEL, "spi0_sel",
+			     spi_parents, 0x020, 0x024, 0x028,
+			     24, 3, 31, 0x04, 7),
+	/* CLK_CFG_2 */
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_SPI1_SEL, "spi1_sel",
+			     spi_parents, 0x030, 0x034, 0x038,
+			     0, 3, 7, 0x04, 8),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_SPI2_SEL, "spi2_sel",
+			     spi_parents, 0x030, 0x034, 0x038,
+			     8, 3, 15, 0x04, 9),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_SPI3_SEL, "spi3_sel",
+			     spi_parents, 0x030, 0x034, 0x038,
+			     16, 3, 23, 0x04, 10),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_SPI4_SEL, "spi4_sel",
+			     spi_parents, 0x030, 0x034, 0x038,
+			     24, 3, 31, 0x04, 11),
+	/* CLK_CFG_3 */
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_SPI5_SEL, "spi5_sel",
+			     spi_parents, 0x040, 0x044, 0x048,
+			     0, 3, 7, 0x04, 12),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC_MACRO_0P_SEL, "msdc_macro_0p_sel",
+			     msdc_macro_p_parents, 0x040, 0x044, 0x048,
+			     8, 2, 15, 0x04, 13),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC50_0_HCLK_SEL, "msdc5hclk_sel",
+			     msdc5hclk_parents, 0x040, 0x044, 0x048,
+			     16, 2, 23, 0x04, 14),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC50_0_SEL, "msdc50_0_sel",
+			     msdc50_0_parents, 0x040, 0x044, 0x048,
+			     24, 3, 31, 0x04, 15),
+	/* CLK_CFG_4 */
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_AES_MSDCFDE_SEL, "aes_msdcfde_sel",
+			     aes_msdcfde_parents, 0x050, 0x054, 0x058,
+			     0, 3, 7, 0x04, 16),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC_MACRO_1P_SEL, "msdc_macro_1p_sel",
+			     msdc_macro_p_parents, 0x050, 0x054, 0x058,
+			     8, 2, 15, 0x04, 17),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC30_1_SEL, "msdc30_1_sel",
+			     msdc30_parents, 0x050, 0x054, 0x058,
+			     16, 3, 23, 0x04, 18),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC30_1_HCLK_SEL, "msdc30_1_h_sel",
+			     msdc30_h_parents, 0x050, 0x054, 0x058,
+			     24, 2, 31, 0x04, 19),
+	/* CLK_CFG_5 */
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC_MACRO_2P_SEL, "msdc_macro_2p_sel",
+			     msdc_macro_p_parents, 0x060, 0x064, 0x068,
+			     0, 2, 7, 0x04, 20),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC30_2_SEL, "msdc30_2_sel",
+			     msdc30_parents, 0x060, 0x064, 0x068,
+			     8, 3, 15, 0x04, 21),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC30_2_HCLK_SEL, "msdc30_2_h_sel",
+			     msdc30_h_parents, 0x060, 0x064, 0x068,
+			     16, 2, 23, 0x04, 22),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_INTBUS_SEL, "aud_intbus_sel",
+			     aud_intbus_parents, 0x060, 0x064, 0x068,
+			     24, 2, 31, 0x04, 23),
+	/* CLK_CFG_6 */
+	MUX_CLR_SET_UPD(CLK_TOP_ATB_SEL, "atb_sel",
+			atb_parents, 0x070, 0x074, 0x078, 0, 2, 0x04, 24),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_DISP_PWM_SEL, "disp_pwm_sel",
+			     disp_pwm_parents, 0x070, 0x074, 0x078,
+			     8, 3, 15, 0x04, 25),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_TOP_P0_SEL, "usb_p0_sel",
+			     usb_parents, 0x070, 0x074, 0x078,
+			     16, 2, 23, 0x04, 26),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_XHCI_P0_SEL, "ssusb_xhci_p0_sel",
+			     usb_parents, 0x070, 0x074, 0x078,
+			     24, 2, 31, 0x04, 27),
+	/* CLK_CFG_7 */
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_TOP_P1_SEL, "usb_p1_sel",
+			     usb_parents, 0x080, 0x084, 0x088,
+			     0, 2, 7, 0x04, 28),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_XHCI_P1_SEL, "ssusb_xhci_p1_sel",
+			     usb_parents, 0x080, 0x084, 0x088,
+			     8, 2, 15, 0x04, 29),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_TOP_P2_SEL, "usb_p2_sel",
+			     usb_parents, 0x080, 0x084, 0x088,
+			     16, 2, 23, 0x04, 30),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_XHCI_P2_SEL, "ssusb_xhci_p2_sel",
+			     usb_parents, 0x080, 0x084, 0x088,
+			     24, 2, 31, 0x08, 0),
+	/* CLK_CFG_8 */
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_TOP_P3_SEL, "usb_p3_sel",
+			     usb_parents, 0x090, 0x094, 0x098,
+			     0, 2, 7, 0x08, 1),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_XHCI_P3_SEL, "ssusb_xhci_p3_sel",
+			     usb_parents, 0x090, 0x094, 0x098,
+			     8, 2, 15, 0x08, 2),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_TOP_P4_SEL, "usb_p4_sel",
+			     usb_parents, 0x090, 0x094, 0x098,
+			     16, 2, 23, 0x08, 3),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_XHCI_P4_SEL, "ssusb_xhci_p4_sel",
+			     usb_parents, 0x090, 0x094, 0x098,
+			     24, 2, 31, 0x08, 4),
+	/* CLK_CFG_9 */
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_I2C_SEL, "i2c_sel",
+			     i2c_parents, 0x0a0, 0x0a4, 0x0a8,
+			     0, 2, 7, 0x08, 5),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_SENINF_SEL, "seninf_sel",
+			     seninf_parents, 0x0a0, 0x0a4, 0x0a8,
+			     8, 3, 15, 0x08, 6),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_SENINF1_SEL, "seninf1_sel",
+			     seninf_parents, 0x0a0, 0x0a4, 0x0a8,
+			     16, 3, 23, 0x08, 7),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_ENGEN1_SEL, "aud_engen1_sel",
+			     aud_engen1_parents, 0x0a0, 0x0a4, 0x0a8,
+			     24, 2, 31, 0x08, 8),
+	/* CLK_CFG_10 */
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_ENGEN2_SEL, "aud_engen2_sel",
+			     aud_engen2_parents, 0x0b0, 0x0b4, 0x0b8,
+			     0, 2, 7, 0x08, 9),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_AES_UFSFDE_SEL, "aes_ufsfde_sel",
+			     aes_ufsfde_parents, 0x0b0, 0x0b4, 0x0b8,
+			     8, 3, 15, 0x08, 10),
+	MUX_CLR_SET_UPD(CLK_TOP_U_SEL, "ufs_sel",
+			ufs_parents, 0x0b0, 0x0b4, 0x0b8,
+			16, 3, 0x08, 11),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_U_MBIST_SEL, "ufs_mbist_sel",
+			     ufs_mbist_parents, 0x0b0, 0x0b4, 0x0b8,
+			     24, 2, 31, 0x08, 12),
+	/* CLK_CFG_11 */
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_1_SEL, "aud_1_sel",
+			     aud_1_parents, 0x0c0, 0x0c4, 0x0c8,
+			     0, 1, 7, 0x08, 13),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_2_SEL, "aud_2_sel",
+			     aud_2_parents, 0x0c0, 0x0c4, 0x0c8,
+			     8, 1, 15, 0x08, 14),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_VENC_SEL, "venc_sel",
+			     venc_parents, 0x0c0, 0x0c4, 0x0c8,
+			     16, 4, 23, 0x08, 15),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_VDEC_SEL, "vdec_sel",
+			     vdec_parents, 0x0c0, 0x0c4, 0x0c8,
+			     24, 4, 31, 0x08, 16),
+	/* CLK_CFG_12 */
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_PWM_SEL, "pwm_sel",
+			     pwm_parents, 0x0d0, 0x0d4, 0x0d8,
+			     0, 1, 7, 0x08, 17),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_AUDIO_H_SEL, "audio_h_sel",
+			     audio_h_parents, 0x0d0, 0x0d4, 0x0d8,
+			     8, 2, 15, 0x08, 18),
+	MUX_CLR_SET_UPD(CLK_TOP_MCUPM_SEL, "mcupm_sel",
+			mcupm_parents, 0x0d0, 0x0d4, 0x0d8,
+			16, 2, 0x08, 19),
+	MUX_CLR_SET_UPD(CLK_TOP_MEM_SUB_SEL, "mem_sub_sel",
+			mem_sub_parents, 0x0d0, 0x0d4, 0x0d8,
+			24, 4, 0x08, 20),
+	/* CLK_CFG_13 */
+	MUX_CLR_SET_UPD(CLK_TOP_MEM_SUB_PERI_SEL, "mem_sub_peri_sel",
+			mem_sub_peri_u_parents, 0x0e0, 0x0e4, 0x0e8,
+			0, 3, 0x08, 21),
+	MUX_CLR_SET_UPD(CLK_TOP_MEM_SUB_U_SEL, "mem_sub_u_sel",
+			mem_sub_peri_u_parents, 0x0e0, 0x0e4, 0x0e8,
+			8, 3, 0x08, 22),
+	MUX_CLR_SET_UPD(CLK_TOP_EMI_N_SEL, "emi_n_sel",
+			emi_n_parents, 0x0e0, 0x0e4, 0x0e8,
+			16, 3, 0x08, 23),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_DSI_OCC_SEL, "dsi_occ_sel",
+			     dsi_occ_parents, 0x0e0, 0x0e4, 0x0e8,
+			     24, 2, 31, 0x08, 24),
+	/* CLK_CFG_14 */
+	MUX_CLR_SET_UPD(CLK_TOP_AP2CONN_HOST_SEL, "ap2conn_host_sel",
+			ap2conn_host_parents, 0x0f0, 0x0f4, 0x0f8,
+			0, 1, 0x08, 25),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_IMG1_SEL, "img1_sel",
+			     img1_parents, 0x0f0, 0x0f4, 0x0f8,
+			     8, 4, 15, 0x08, 26),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_IPE_SEL, "ipe_sel",
+			     ipe_parents, 0x0f0, 0x0f4, 0x0f8,
+			     16, 4, 23, 0x08, 27),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_CAM_SEL, "cam_sel",
+			     cam_parents, 0x0f0, 0x0f4, 0x0f8,
+			     24, 4, 31, 0x08, 28),
+	/* CLK_CFG_15 */
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_CAMTM_SEL, "camtm_sel",
+			     camtm_parents, 0x100, 0x104, 0x108,
+			     0, 2, 7, 0x08, 29),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_DSP_SEL, "dsp_sel",
+			     dsp_parents, 0x100, 0x104, 0x108,
+			     8, 3, 15, 0x08, 30),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_SR_PKA_SEL, "sr_pka_sel",
+			     sr_pka_parents, 0x100, 0x104, 0x108,
+			     16, 3, 23, 0x0c, 0),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_DXCC_SEL, "dxcc_sel",
+			     dxcc_parents, 0x100, 0x104, 0x108,
+			     24, 2, 31, 0x0c, 1),
+	/* CLK_CFG_16 */
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_MFG_REF_SEL, "mfg_ref_sel",
+			     mfg_ref_parents, 0x110, 0x114, 0x118,
+			     0, 2, 7, 0x0c, 2),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_MDP0_SEL, "mdp0_sel",
+			     mmsys_parents, 0x110, 0x114, 0x118,
+			     8, 4, 15, 0x0c, 3),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_DP_SEL, "dp_sel",
+			     dp_parents, 0x110, 0x114, 0x118,
+			     16, 3, 23, 0x0c, 4),
+	MUX_CLR_SET_UPD(CLK_TOP_EDP_SEL, "edp_sel",
+			edp_parents, 0x110, 0x114, 0x118,
+			24, 3, 0x0c, 5),
+	/* CLK_CFG_17 */
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_EDP_FAVT_SEL, "edp_favt_sel",
+			     edp_parents, 0x180, 0x184, 0x188,
+			     0, 3, 7, 0x0c, 6),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_250M_SEL, "snps_eth_250m_sel",
+			     snps_eth_250m_parents, 0x180, 0x184, 0x188,
+			     8, 1, 15, 0x0c, 7),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_62P4M_PTP_SEL,
+			     "snps_eth_62p4m_ptp_sel",
+			     snps_eth_62p4m_ptp_parents,
+			     0x180, 0x184, 0x188, 16, 2, 23, 0x0c, 8),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_50M_RMII_SEL,
+			     "snps_eth_50m_rmii_sel",
+			     snps_eth_50m_rmii_parents,
+			     0x180, 0x184, 0x188, 24, 1, 31, 0x0c, 9),
+	/* CLK_CFG_18 */
+	MUX_CLR_SET_UPD(CLK_TOP_SFLASH_SEL, "sflash_sel",
+			sflash_parents, 0x190, 0x194, 0x198,
+			0, 3, 0x0c, 10),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_GCPU_SEL, "gcpu_sel",
+			     gcpu_parents, 0x190, 0x194, 0x198,
+			     8, 3, 15, 0x0c, 11),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_MAC_TL_SEL, "pcie_mac_tl_sel",
+			     pcie_mac_tl_parents, 0x190, 0x194, 0x198,
+			     16, 2, 23, 0x0c, 12),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_VDSTX_DG_CTS_SEL, "vdstx_dg_cts_sel",
+			     vdstx_dg_cts_parents, 0x190, 0x194, 0x198,
+			     24, 2, 31, 0x0c, 13),
+	/* CLK_CFG_19 */
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_PLL_DPIX_SEL, "pll_dpix_sel",
+			     pll_dpix_parents, 0x240, 0x244, 0x248,
+			     0, 2, 7, 0x0c, 14),
+	MUX_GATE_CLR_SET_UPD(CLK_TOP_ECC_SEL, "ecc_sel",
+			     ecc_parents, 0x240, 0x244, 0x248,
+			     8, 3, 15, 0x0c, 15),
+	/* CLK_MISC_CFG_3 */
+	GATE_CLR_SET_UPD_FLAGS(CLK_TOP_MFG_SEL_MFGPLL, "mfg_sel_mfgpll",
+			       mfg_sel_mfgpll_parents,
+			       0x510, 0x514, 0x0518, 16, 1, 0, -1, -1,
+			       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+			       mtk_mux_clr_set_upd_ops)
+};
+
+static const struct mtk_composite top_composites[] = {
+	/* CLK_AUDDIV_0 */
+	MUX(CLK_TOP_APLL_I2SIN0_MCK_SEL, "apll_i2sin0_m_sel",
+	    apll_m_parents, 0x0320, 16, 1),
+	MUX(CLK_TOP_APLL_I2SIN1_MCK_SEL, "apll_i2sin1_m_sel",
+	    apll_m_parents, 0x0320, 17, 1),
+	MUX(CLK_TOP_APLL_I2SIN2_MCK_SEL, "apll_i2sin2_m_sel",
+	    apll_m_parents, 0x0320, 18, 1),
+	MUX(CLK_TOP_APLL_I2SIN3_MCK_SEL, "apll_i2sin3_m_sel",
+	    apll_m_parents, 0x0320, 19, 1),
+	MUX(CLK_TOP_APLL_I2SIN4_MCK_SEL, "apll_i2sin4_m_sel",
+	    apll_m_parents, 0x0320, 20, 1),
+	MUX(CLK_TOP_APLL_I2SIN6_MCK_SEL, "apll_i2sin6_m_sel",
+	    apll_m_parents, 0x0320, 21, 1),
+	MUX(CLK_TOP_APLL_I2SOUT0_MCK_SEL, "apll_i2sout0_m_sel",
+	    apll_m_parents, 0x0320, 22, 1),
+	MUX(CLK_TOP_APLL_I2SOUT1_MCK_SEL, "apll_i2sout1_m_sel",
+	    apll_m_parents, 0x0320, 23, 1),
+	MUX(CLK_TOP_APLL_I2SOUT2_MCK_SEL, "apll_i2sout2_m_sel",
+	    apll_m_parents, 0x0320, 24, 1),
+	MUX(CLK_TOP_APLL_I2SOUT3_MCK_SEL, "apll_i2sout3_m_sel",
+	    apll_m_parents, 0x0320, 25, 1),
+	MUX(CLK_TOP_APLL_I2SOUT4_MCK_SEL, "apll_i2sout4_m_sel",
+	    apll_m_parents, 0x0320, 26, 1),
+	MUX(CLK_TOP_APLL_I2SOUT6_MCK_SEL, "apll_i2sout6_m_sel",
+	    apll_m_parents, 0x0320, 27, 1),
+	MUX(CLK_TOP_APLL_FMI2S_MCK_SEL, "apll_fmi2s_m_sel",
+	    apll_m_parents, 0x0320, 28, 1),
+	MUX(CLK_TOP_APLL_TDMOUT_MCK_SEL, "apll_tdmout_m_sel",
+	    apll_m_parents, 0x0320, 29, 1),
+	/* CLK_AUDDIV_2 */
+	DIV_GATE(CLK_TOP_APLL12_CK_DIV_I2SIN0, "apll12_div_i2sin0",
+		 "apll_i2sin0_m_sel", 0x0320, 0, 0x0328, 8, 0),
+	DIV_GATE(CLK_TOP_APLL12_CK_DIV_I2SIN1, "apll12_div_i2sin1",
+		 "apll_i2sin1_m_sel", 0x0320, 1, 0x0328, 8, 8),
+	/* CLK_AUDDIV_3 */
+	DIV_GATE(CLK_TOP_APLL12_CK_DIV_I2SOUT0, "apll12_div_i2sout0",
+		 "apll_i2sout0_m_sel", 0x0320, 6, 0x0334, 8, 16),
+	DIV_GATE(CLK_TOP_APLL12_CK_DIV_I2SOUT1, "apll12_div_i2sout1",
+		 "apll_i2sout1_m_sel", 0x0320, 7, 0x0334, 8, 24),
+	/* CLK_AUDDIV_5 */
+	DIV_GATE(CLK_TOP_APLL12_CK_DIV_FMI2S, "apll12_div_fmi2s",
+		 "apll_fmi2s_m_sel", 0x0320, 12, 0x033c, 8, 0),
+	DIV_GATE(CLK_TOP_APLL12_CK_DIV_TDMOUT_M, "apll12_div_tdmout_m",
+		 "apll_tdmout_m_sel", 0x0320, 13, 0x033c, 8, 8),
+	DIV_GATE(CLK_TOP_APLL12_CK_DIV_TDMOUT_B, "apll12_div_tdmout_b",
+		 "apll12_div_tdmout_m", 0x0320, 14, 0x033c, 8, 16),
+};
+
+static const struct mtk_gate_regs top_cg_regs = {
+	.set_ofs = 0x514,
+	.clr_ofs = 0x518,
+	.sta_ofs = 0x510,
+};
+
+#define GATE_TOP_FLAGS(_id, _name, _parent, _shift, _flag) {	\
+		.id = _id,				\
+		.name = _name,				\
+		.parent_name = _parent,			\
+		.regs = &top_cg_regs,			\
+		.shift = _shift,			\
+		.flags = _flag,				\
+		.ops = &mtk_clk_gate_ops_setclr_inv,	\
+	}
+
+#define GATE_TOP(_id, _name, _parent, _shift)		\
+	GATE_TOP_FLAGS(_id, _name, _parent, _shift, 0)
+
+static const struct mtk_gate top_clks[] = {
+	GATE_TOP_FLAGS(CLK_TOP_FMCNT_P0_EN, "fmcnt_p0_en", "univpll_192m_d4", 0, CLK_IS_CRITICAL),
+	GATE_TOP_FLAGS(CLK_TOP_FMCNT_P1_EN, "fmcnt_p1_en", "univpll_192m_d4", 1, CLK_IS_CRITICAL),
+	GATE_TOP_FLAGS(CLK_TOP_FMCNT_P2_EN, "fmcnt_p2_en", "univpll_192m_d4", 2, CLK_IS_CRITICAL),
+	GATE_TOP_FLAGS(CLK_TOP_FMCNT_P3_EN, "fmcnt_p3_en", "univpll_192m_d4", 3, CLK_IS_CRITICAL),
+	GATE_TOP_FLAGS(CLK_TOP_FMCNT_P4_EN, "fmcnt_p4_en", "univpll_192m_d4", 4, CLK_IS_CRITICAL),
+	GATE_TOP_FLAGS(CLK_TOP_USB_F26M_CK_EN, "ssusb_f26m", "clk26m", 5, CLK_IS_CRITICAL),
+	GATE_TOP_FLAGS(CLK_TOP_SSPXTP_F26M_CK_EN, "sspxtp_f26m", "clk26m", 6, CLK_IS_CRITICAL),
+	GATE_TOP(CLK_TOP_USB2_PHY_RF_P0_EN, "usb2_phy_rf_p0_en", "clk26m", 7),
+	GATE_TOP(CLK_TOP_USB2_PHY_RF_P1_EN, "usb2_phy_rf_p1_en", "clk26m", 10),
+	GATE_TOP(CLK_TOP_USB2_PHY_RF_P2_EN, "usb2_phy_rf_p2_en", "clk26m", 11),
+	GATE_TOP(CLK_TOP_USB2_PHY_RF_P3_EN, "usb2_phy_rf_p3_en", "clk26m", 12),
+	GATE_TOP(CLK_TOP_USB2_PHY_RF_P4_EN, "usb2_phy_rf_p4_en", "clk26m", 13),
+	GATE_TOP_FLAGS(CLK_TOP_USB2_26M_CK_P0_EN, "usb2_26m_p0_en", "clk26m", 14, CLK_IS_CRITICAL),
+	GATE_TOP_FLAGS(CLK_TOP_USB2_26M_CK_P1_EN, "usb2_26m_p1_en", "clk26m", 15, CLK_IS_CRITICAL),
+	GATE_TOP_FLAGS(CLK_TOP_USB2_26M_CK_P2_EN, "usb2_26m_p2_en", "clk26m", 18, CLK_IS_CRITICAL),
+	GATE_TOP_FLAGS(CLK_TOP_USB2_26M_CK_P3_EN, "usb2_26m_p3_en", "clk26m", 19, CLK_IS_CRITICAL),
+	GATE_TOP_FLAGS(CLK_TOP_USB2_26M_CK_P4_EN, "usb2_26m_p4_en", "clk26m", 20, CLK_IS_CRITICAL),
+	GATE_TOP(CLK_TOP_F26M_CK_EN, "pcie_f26m", "clk26m", 21),
+	GATE_TOP_FLAGS(CLK_TOP_AP2CON_EN, "ap2con", "clk26m", 24, CLK_IS_CRITICAL),
+	GATE_TOP_FLAGS(CLK_TOP_EINT_N_EN, "eint_n", "clk26m", 25, CLK_IS_CRITICAL),
+	GATE_TOP_FLAGS(CLK_TOP_TOPCKGEN_FMIPI_CSI_UP26M_CK_EN,
+		       "TOPCKGEN_fmipi_csi_up26m", "osc_d10", 26, CLK_IS_CRITICAL),
+	GATE_TOP_FLAGS(CLK_TOP_EINT_E_EN, "eint_e", "clk26m", 28, CLK_IS_CRITICAL),
+	GATE_TOP_FLAGS(CLK_TOP_EINT_W_EN, "eint_w", "clk26m", 30, CLK_IS_CRITICAL),
+	GATE_TOP_FLAGS(CLK_TOP_EINT_S_EN, "eint_s", "clk26m", 31, CLK_IS_CRITICAL),
+};
+
+/* Register mux notifier for MFG mux */
+static int clk_mt8189_reg_mfg_mux_notifier(struct device *dev,
+					   struct clk *clk)
+{
+	struct mtk_mux_nb *mfg_mux_nb;
+
+	mfg_mux_nb = devm_kzalloc(dev, sizeof(*mfg_mux_nb), GFP_KERNEL);
+	if (!mfg_mux_nb)
+		return -ENOMEM;
+
+	mfg_mux_nb->ops = &mtk_mux_clr_set_upd_ops;
+	mfg_mux_nb->bypass_index = 0; /* Bypass to CLK_TOP_MFG_REF_SEL */
+
+	return devm_mtk_clk_mux_notifier_register(dev, clk, mfg_mux_nb);
+}
+
+static const struct mtk_clk_desc topck_desc = {
+	.factor_clks = top_divs,
+	.num_factor_clks = ARRAY_SIZE(top_divs),
+	.mux_clks = top_muxes,
+	.num_mux_clks = ARRAY_SIZE(top_muxes),
+	.composite_clks = top_composites,
+	.num_composite_clks = ARRAY_SIZE(top_composites),
+	.clks = top_clks,
+	.num_clks = ARRAY_SIZE(top_clks),
+	.clk_notifier_func = clk_mt8189_reg_mfg_mux_notifier,
+	.mfg_clk_idx = CLK_TOP_MFG_SEL_MFGPLL,
+	.clk_lock = &mt8189_clk_lock,
+};
+
+static const struct of_device_id of_match_clk_mt8189_topck[] = {
+	{ .compatible = "mediatek,mt8189-topckgen", .data = &topck_desc },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver clk_mt8189_topck_drv = {
+	.probe = mtk_clk_simple_probe,
+	.remove = mtk_clk_simple_remove,
+	.driver = {
+		.name = "clk-mt8189-topck",
+		.of_match_table = of_match_clk_mt8189_topck,
+	},
+};
+
+module_platform_driver(clk_mt8189_topck_drv);
+MODULE_DESCRIPTION("MediaTek MT8189 topckgen clocks driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



From irving-ch.lin at mediatek.com  Sun Dec 14 19:49:17 2025
From: irving-ch.lin at mediatek.com (irving.ch.lin)
Date: Mon, 15 Dec 2025 11:49:17 +0800
Subject: [PATCH v4 08/21] clk: mediatek: Add MT8189 bus clock support
In-Reply-To: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
References: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
Message-ID: <20251215034944.2973003-9-irving-ch.lin@mediatek.com>

From: Irving-CH Lin <irving-ch.lin at mediatek.com>

Add support for the MT8189 bus clock controller,
which provides clock gate control for infra/peri IPs
(such as spi, uart, msdc, flashif ...).

Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
---
 drivers/clk/mediatek/Kconfig          |  11 ++
 drivers/clk/mediatek/Makefile         |   1 +
 drivers/clk/mediatek/clk-mt8189-bus.c | 196 ++++++++++++++++++++++++++
 3 files changed, 208 insertions(+)
 create mode 100644 drivers/clk/mediatek/clk-mt8189-bus.c

diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
index 2c898fd8a34c..0e7fdb5421e6 100644
--- a/drivers/clk/mediatek/Kconfig
+++ b/drivers/clk/mediatek/Kconfig
@@ -828,6 +828,17 @@ config COMMON_CLK_MT8189
 	  with the MediaTek MT8189 hardware capabilities, providing efficient management of
 	  clock speeds and power consumption.
 
+config COMMON_CLK_MT8189_BUS
+	tristate "Clock driver for MediaTek MT8189 bus"
+	depends on COMMON_CLK_MT8189
+	default COMMON_CLK_MT8189
+	help
+	  Enable this configuration option to support the clock framework for
+	  MediaTek MT8189 SoC bus clocks. It includes the necessary clock
+	  management for bus-related peripherals and interconnects within the
+	  MT8189 chipset, ensuring that all bus-related components receive the
+	  correct clock signals for optimal performance.
+
 config COMMON_CLK_MT8192
 	tristate "Clock driver for MediaTek MT8192"
 	depends on ARM64 || COMPILE_TEST
diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
index d9279b237b7b..aabfb42cb1b2 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -125,6 +125,7 @@ obj-$(CONFIG_COMMON_CLK_MT8188_VPPSYS) += clk-mt8188-vpp0.o clk-mt8188-vpp1.o
 obj-$(CONFIG_COMMON_CLK_MT8188_WPESYS) += clk-mt8188-wpe.o
 obj-$(CONFIG_COMMON_CLK_MT8189) += clk-mt8189-apmixedsys.o clk-mt8189-topckgen.o \
 				   clk-mt8189-vlpckgen.o clk-mt8189-vlpcfg.o
+obj-$(CONFIG_COMMON_CLK_MT8189_BUS) += clk-mt8189-bus.o
 obj-$(CONFIG_COMMON_CLK_MT8192) += clk-mt8192-apmixedsys.o clk-mt8192.o
 obj-$(CONFIG_COMMON_CLK_MT8192_AUDSYS) += clk-mt8192-aud.o
 obj-$(CONFIG_COMMON_CLK_MT8192_CAMSYS) += clk-mt8192-cam.o
diff --git a/drivers/clk/mediatek/clk-mt8189-bus.c b/drivers/clk/mediatek/clk-mt8189-bus.c
new file mode 100644
index 000000000000..c9b83fa98590
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8189-bus.c
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Qiqi Wang <qiqi.wang at mediatek.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include "clk-mtk.h"
+#include "clk-gate.h"
+
+#include <dt-bindings/clock/mediatek,mt8189-clk.h>
+
+static const struct mtk_gate_regs ifrao0_cg_regs = {
+	.set_ofs = 0x80,
+	.clr_ofs = 0x84,
+	.sta_ofs = 0x90,
+};
+
+static const struct mtk_gate_regs ifrao1_cg_regs = {
+	.set_ofs = 0x88,
+	.clr_ofs = 0x8c,
+	.sta_ofs = 0x94,
+};
+
+static const struct mtk_gate_regs ifrao2_cg_regs = {
+	.set_ofs = 0xa4,
+	.clr_ofs = 0xa8,
+	.sta_ofs = 0xac,
+};
+
+#define GATE_IFRAO0(_id, _name, _parent, _shift)	\
+	GATE_MTK(_id, _name, _parent, &ifrao0_cg_regs, _shift, &mtk_clk_gate_ops_setclr)
+
+#define GATE_IFRAO1(_id, _name, _parent, _shift)	\
+	GATE_MTK(_id, _name, _parent, &ifrao1_cg_regs, _shift, &mtk_clk_gate_ops_setclr)
+
+#define GATE_IFRAO2(_id, _name, _parent, _shift)	\
+	GATE_MTK(_id, _name, _parent, &ifrao2_cg_regs, _shift, &mtk_clk_gate_ops_setclr)
+
+static const struct mtk_gate ifrao_clks[] = {
+	/* IFRAO0 */
+	GATE_IFRAO0(CLK_IFRAO_CQ_DMA_FPC, "ifrao_dma", "clk26m", 28),
+	/* IFRAO1 */
+	GATE_IFRAO1(CLK_IFRAO_DEBUGSYS, "ifrao_debugsys", "axi_sel", 24),
+	GATE_IFRAO1(CLK_IFRAO_DBG_TRACE, "ifrao_dbg_trace", "axi_sel", 29),
+	/* IFRAO2 */
+	GATE_IFRAO2(CLK_IFRAO_CQ_DMA, "ifrao_cq_dma", "axi_sel", 27),
+};
+
+static const struct mtk_clk_desc ifrao_mcd = {
+	.clks = ifrao_clks,
+	.num_clks = ARRAY_SIZE(ifrao_clks),
+};
+
+static const struct mtk_gate_regs perao0_cg_regs = {
+	.set_ofs = 0x24,
+	.clr_ofs = 0x28,
+	.sta_ofs = 0x10,
+};
+
+static const struct mtk_gate_regs perao1_cg_regs = {
+	.set_ofs = 0x2c,
+	.clr_ofs = 0x30,
+	.sta_ofs = 0x14,
+};
+
+static const struct mtk_gate_regs perao2_cg_regs = {
+	.set_ofs = 0x34,
+	.clr_ofs = 0x38,
+	.sta_ofs = 0x18,
+};
+
+#define GATE_PERAO0(_id, _name, _parent, _shift)	\
+	GATE_MTK(_id, _name, _parent, &perao0_cg_regs, _shift, &mtk_clk_gate_ops_setclr)
+
+#define GATE_PERAO1(_id, _name, _parent, _shift)	\
+	GATE_MTK(_id, _name, _parent, &perao1_cg_regs, _shift, &mtk_clk_gate_ops_setclr)
+
+#define GATE_PERAO2(_id, _name, _parent, _shift)	\
+	GATE_MTK(_id, _name, _parent, &perao2_cg_regs, _shift, &mtk_clk_gate_ops_setclr)
+
+static const struct mtk_gate perao_clks[] = {
+	/* PERAO0 */
+	GATE_PERAO0(CLK_PERAO_UART0, "perao_uart0", "uart_sel", 0),
+	GATE_PERAO0(CLK_PERAO_UART1, "perao_uart1", "uart_sel", 1),
+	GATE_PERAO0(CLK_PERAO_UART2, "perao_uart2", "uart_sel", 2),
+	GATE_PERAO0(CLK_PERAO_UART3, "perao_uart3", "uart_sel", 3),
+	GATE_PERAO0(CLK_PERAO_PWM_H, "perao_pwm_h", "axi_peri_sel", 4),
+	GATE_PERAO0(CLK_PERAO_PWM_B, "perao_pwm_b", "pwm_sel", 5),
+	GATE_PERAO0(CLK_PERAO_PWM_FB1, "perao_pwm_fb1", "pwm_sel", 6),
+	GATE_PERAO0(CLK_PERAO_PWM_FB2, "perao_pwm_fb2", "pwm_sel", 7),
+	GATE_PERAO0(CLK_PERAO_PWM_FB3, "perao_pwm_fb3", "pwm_sel", 8),
+	GATE_PERAO0(CLK_PERAO_PWM_FB4, "perao_pwm_fb4", "pwm_sel", 9),
+	GATE_PERAO0(CLK_PERAO_DISP_PWM0, "perao_disp_pwm0", "disp_pwm_sel", 10),
+	GATE_PERAO0(CLK_PERAO_DISP_PWM1, "perao_disp_pwm1", "disp_pwm_sel", 11),
+	GATE_PERAO0(CLK_PERAO_SPI0_B, "perao_spi0_b", "spi0_sel", 12),
+	GATE_PERAO0(CLK_PERAO_SPI1_B, "perao_spi1_b", "spi1_sel", 13),
+	GATE_PERAO0(CLK_PERAO_SPI2_B, "perao_spi2_b", "spi2_sel", 14),
+	GATE_PERAO0(CLK_PERAO_SPI3_B, "perao_spi3_b", "spi3_sel", 15),
+	GATE_PERAO0(CLK_PERAO_SPI4_B, "perao_spi4_b", "spi4_sel", 16),
+	GATE_PERAO0(CLK_PERAO_SPI5_B, "perao_spi5_b", "spi5_sel", 17),
+	GATE_PERAO0(CLK_PERAO_SPI0_H, "perao_spi0_h", "axi_peri_sel", 18),
+	GATE_PERAO0(CLK_PERAO_SPI1_H, "perao_spi1_h", "axi_peri_sel", 19),
+	GATE_PERAO0(CLK_PERAO_SPI2_H, "perao_spi2_h", "axi_peri_sel", 20),
+	GATE_PERAO0(CLK_PERAO_SPI3_H, "perao_spi3_h", "axi_peri_sel", 21),
+	GATE_PERAO0(CLK_PERAO_SPI4_H, "perao_spi4_h", "axi_peri_sel", 22),
+	GATE_PERAO0(CLK_PERAO_SPI5_H, "perao_spi5_h", "axi_peri_sel", 23),
+	GATE_PERAO0(CLK_PERAO_AXI, "perao_axi", "mem_sub_peri_sel", 24),
+	GATE_PERAO0(CLK_PERAO_AHB_APB, "perao_ahb_apb", "axi_peri_sel", 25),
+	GATE_PERAO0(CLK_PERAO_TL, "perao_tl", "pcie_mac_tl_sel", 26),
+	GATE_PERAO0(CLK_PERAO_REF, "perao_ref", "clk26m", 27),
+	GATE_PERAO0(CLK_PERAO_I2C, "perao_i2c", "axi_peri_sel", 28),
+	GATE_PERAO0(CLK_PERAO_DMA_B, "perao_dma_b", "axi_peri_sel", 29),
+	/* PERAO1 */
+	GATE_PERAO1(CLK_PERAO_SSUSB0_REF, "perao_ssusb0_ref", "clk26m", 1),
+	GATE_PERAO1(CLK_PERAO_SSUSB0_FRMCNT, "perao_ssusb0_frmcnt", "univpll_192m_d4", 2),
+	GATE_PERAO1(CLK_PERAO_SSUSB0_SYS, "perao_ssusb0_sys", "usb_p0_sel", 4),
+	GATE_PERAO1(CLK_PERAO_SSUSB0_XHCI, "perao_ssusb0_xhci", "ssusb_xhci_p0_sel", 5),
+	GATE_PERAO1(CLK_PERAO_SSUSB0_F, "perao_ssusb0_f", "axi_peri_sel", 6),
+	GATE_PERAO1(CLK_PERAO_SSUSB0_H, "perao_ssusb0_h", "axi_peri_sel", 7),
+	GATE_PERAO1(CLK_PERAO_SSUSB1_REF, "perao_ssusb1_ref", "clk26m", 8),
+	GATE_PERAO1(CLK_PERAO_SSUSB1_FRMCNT, "perao_ssusb1_frmcnt", "univpll_192m_d4", 9),
+	GATE_PERAO1(CLK_PERAO_SSUSB1_SYS, "perao_ssusb1_sys", "usb_p1_sel", 11),
+	GATE_PERAO1(CLK_PERAO_SSUSB1_XHCI, "perao_ssusb1_xhci", "ssusb_xhci_p1_sel", 12),
+	GATE_PERAO1(CLK_PERAO_SSUSB1_F, "perao_ssusb1_f", "axi_peri_sel", 13),
+	GATE_PERAO1(CLK_PERAO_SSUSB1_H, "perao_ssusb1_h", "axi_peri_sel", 14),
+	GATE_PERAO1(CLK_PERAO_SSUSB2_REF, "perao_ssusb2_ref", "clk26m", 15),
+	GATE_PERAO1(CLK_PERAO_SSUSB2_FRMCNT, "perao_ssusb2_frmcnt", "univpll_192m_d4", 16),
+	GATE_PERAO1(CLK_PERAO_SSUSB2_SYS, "perao_ssusb2_sys", "usb_p2_sel", 18),
+	GATE_PERAO1(CLK_PERAO_SSUSB2_XHCI, "perao_ssusb2_xhci", "ssusb_xhci_p2_sel", 19),
+	GATE_PERAO1(CLK_PERAO_SSUSB2_F, "perao_ssusb2_f", "axi_peri_sel", 20),
+	GATE_PERAO1(CLK_PERAO_SSUSB2_H, "perao_ssusb2_h", "axi_peri_sel", 21),
+	GATE_PERAO1(CLK_PERAO_SSUSB3_REF, "perao_ssusb3_ref", "clk26m", 23),
+	GATE_PERAO1(CLK_PERAO_SSUSB3_FRMCNT, "perao_ssusb3_frmcnt", "univpll_192m_d4", 24),
+	GATE_PERAO1(CLK_PERAO_SSUSB3_SYS, "perao_ssusb3_sys", "usb_p3_sel", 26),
+	GATE_PERAO1(CLK_PERAO_SSUSB3_XHCI, "perao_ssusb3_xhci", "ssusb_xhci_p3_sel", 27),
+	GATE_PERAO1(CLK_PERAO_SSUSB3_F, "perao_ssusb3_f", "axi_peri_sel", 28),
+	GATE_PERAO1(CLK_PERAO_SSUSB3_H, "perao_ssusb3_h", "axi_peri_sel", 29),
+	/* PERAO2 */
+	GATE_PERAO2(CLK_PERAO_SSUSB4_REF, "perao_ssusb4_ref", "clk26m", 0),
+	GATE_PERAO2(CLK_PERAO_SSUSB4_FRMCNT, "perao_ssusb4_frmcnt", "univpll_192m_d4", 1),
+	GATE_PERAO2(CLK_PERAO_SSUSB4_SYS, "perao_ssusb4_sys", "usb_p4_sel", 3),
+	GATE_PERAO2(CLK_PERAO_SSUSB4_XHCI, "perao_ssusb4_xhci", "ssusb_xhci_p4_sel", 4),
+	GATE_PERAO2(CLK_PERAO_SSUSB4_F, "perao_ssusb4_f", "axi_peri_sel", 5),
+	GATE_PERAO2(CLK_PERAO_SSUSB4_H, "perao_ssusb4_h", "axi_peri_sel", 6),
+	GATE_PERAO2(CLK_PERAO_MSDC0, "perao_msdc0", "msdc50_0_sel", 7),
+	GATE_PERAO2(CLK_PERAO_MSDC0_H, "perao_msdc0_h", "msdc5hclk_sel", 8),
+	GATE_PERAO2(CLK_PERAO_MSDC0_FAES, "perao_msdc0_faes", "aes_msdcfde_sel", 9),
+	GATE_PERAO2(CLK_PERAO_MSDC0_MST_F, "perao_msdc0_mst_f", "axi_peri_sel", 10),
+	GATE_PERAO2(CLK_PERAO_MSDC0_SLV_H, "perao_msdc0_slv_h", "axi_peri_sel", 11),
+	GATE_PERAO2(CLK_PERAO_MSDC1, "perao_msdc1", "msdc30_1_sel", 12),
+	GATE_PERAO2(CLK_PERAO_MSDC1_H, "perao_msdc1_h", "msdc30_1_h_sel", 13),
+	GATE_PERAO2(CLK_PERAO_MSDC1_MST_F, "perao_msdc1_mst_f", "axi_peri_sel", 14),
+	GATE_PERAO2(CLK_PERAO_MSDC1_SLV_H, "perao_msdc1_slv_h", "axi_peri_sel", 15),
+	GATE_PERAO2(CLK_PERAO_MSDC2, "perao_msdc2", "msdc30_2_sel", 16),
+	GATE_PERAO2(CLK_PERAO_MSDC2_H, "perao_msdc2_h", "msdc30_2_h_sel", 17),
+	GATE_PERAO2(CLK_PERAO_MSDC2_MST_F, "perao_msdc2_mst_f", "axi_peri_sel", 18),
+	GATE_PERAO2(CLK_PERAO_MSDC2_SLV_H, "perao_msdc2_slv_h", "axi_peri_sel", 19),
+	GATE_PERAO2(CLK_PERAO_SFLASH, "perao_sflash", "sflash_sel", 20),
+	GATE_PERAO2(CLK_PERAO_SFLASH_F, "perao_sflash_f", "axi_peri_sel", 21),
+	GATE_PERAO2(CLK_PERAO_SFLASH_H, "perao_sflash_h", "axi_peri_sel", 22),
+	GATE_PERAO2(CLK_PERAO_SFLASH_P, "perao_sflash_p", "axi_peri_sel", 23),
+	GATE_PERAO2(CLK_PERAO_AUDIO0, "perao_audio0", "axi_peri_sel", 24),
+	GATE_PERAO2(CLK_PERAO_AUDIO1, "perao_audio1", "axi_peri_sel", 25),
+	GATE_PERAO2(CLK_PERAO_AUDIO2, "perao_audio2", "aud_intbus_sel", 26),
+	GATE_PERAO2(CLK_PERAO_AUXADC_26M, "perao_auxadc_26m", "clk26m", 27),
+};
+
+static const struct mtk_clk_desc perao_mcd = {
+	.clks = perao_clks,
+	.num_clks = ARRAY_SIZE(perao_clks),
+};
+
+static const struct of_device_id of_match_clk_mt8189_bus[] = {
+	{ .compatible = "mediatek,mt8189-infra-ao", .data = &ifrao_mcd },
+	{ .compatible = "mediatek,mt8189-peri-ao", .data = &perao_mcd },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_match_clk_mt8189_bus);
+
+static struct platform_driver clk_mt8189_bus_drv = {
+	.probe = mtk_clk_simple_probe,
+	.remove = mtk_clk_simple_remove,
+	.driver = {
+		.name = "clk-mt8189-bus",
+		.of_match_table = of_match_clk_mt8189_bus,
+	},
+};
+
+module_platform_driver(clk_mt8189_bus_drv);
+MODULE_DESCRIPTION("MediaTek MT8189 bus/peripheral clocks driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



From irving-ch.lin at mediatek.com  Sun Dec 14 19:49:21 2025
From: irving-ch.lin at mediatek.com (irving.ch.lin)
Date: Mon, 15 Dec 2025 11:49:21 +0800
Subject: [PATCH v4 12/21] clk: mediatek: Add MT8189 i2c clock support
In-Reply-To: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
References: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
Message-ID: <20251215034944.2973003-13-irving-ch.lin@mediatek.com>

From: Irving-CH Lin <irving-ch.lin at mediatek.com>

Add support for the MT8189 i2c clock controller,
which provides clock gate control for i2c.

Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
---
 drivers/clk/mediatek/Kconfig          |  13 +++
 drivers/clk/mediatek/Makefile         |   1 +
 drivers/clk/mediatek/clk-mt8189-iic.c | 118 ++++++++++++++++++++++++++
 3 files changed, 132 insertions(+)
 create mode 100644 drivers/clk/mediatek/clk-mt8189-iic.c

diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
index 76c9391bee69..71603fba2ea8 100644
--- a/drivers/clk/mediatek/Kconfig
+++ b/drivers/clk/mediatek/Kconfig
@@ -870,6 +870,19 @@ config COMMON_CLK_MT8189_DVFSRC
 	  vcore dvfs clocks. If you want to control its clocks, say Y or M
 	  to include this driver in your kernel build.
 
+config COMMON_CLK_MT8189_IIC
+	tristate "Clock driver for MediaTek MT8189 iic"
+	depends on COMMON_CLK_MT8189
+	default COMMON_CLK_MT8189
+	help
+	  Enable this option to support the clock framework for MediaTek MT8189
+	  integrated circuits (iic). This driver is responsible for managing
+	  clock sources, dividers, and gates specifically designed for MT8189
+	  SoCs. Enabling this driver ensures that the system can correctly
+	  manage clock frequencies and power for various components within
+	  the MT8189 chipset, improving the overall performance and power
+	  efficiency of the device.
+
 config COMMON_CLK_MT8192
 	tristate "Clock driver for MediaTek MT8192"
 	depends on ARM64 || COMPILE_TEST
diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
index 3a8dad865c97..0eed1edf7c63 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -129,6 +129,7 @@ obj-$(CONFIG_COMMON_CLK_MT8189_BUS) += clk-mt8189-bus.o
 obj-$(CONFIG_COMMON_CLK_MT8189_CAM) += clk-mt8189-cam.o
 obj-$(CONFIG_COMMON_CLK_MT8189_DBGAO) += clk-mt8189-dbgao.o
 obj-$(CONFIG_COMMON_CLK_MT8189_DVFSRC) += clk-mt8189-dvfsrc.o
+obj-$(CONFIG_COMMON_CLK_MT8189_IIC) += clk-mt8189-iic.o
 obj-$(CONFIG_COMMON_CLK_MT8192) += clk-mt8192-apmixedsys.o clk-mt8192.o
 obj-$(CONFIG_COMMON_CLK_MT8192_AUDSYS) += clk-mt8192-aud.o
 obj-$(CONFIG_COMMON_CLK_MT8192_CAMSYS) += clk-mt8192-cam.o
diff --git a/drivers/clk/mediatek/clk-mt8189-iic.c b/drivers/clk/mediatek/clk-mt8189-iic.c
new file mode 100644
index 000000000000..5feeb6cd83cf
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8189-iic.c
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Qiqi Wang <qiqi.wang at mediatek.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include "clk-mtk.h"
+#include "clk-gate.h"
+
+#include <dt-bindings/clock/mediatek,mt8189-clk.h>
+
+static const struct mtk_gate_regs impe_cg_regs = {
+	.set_ofs = 0x8,
+	.clr_ofs = 0x4,
+	.sta_ofs = 0x0,
+};
+
+#define GATE_IMPE(_id, _name, _parent, _shift)				\
+	GATE_MTK_FLAGS(_id, _name, _parent, &impe_cg_regs, _shift,	\
+		&mtk_clk_gate_ops_setclr, CLK_OPS_PARENT_ENABLE)
+
+static const struct mtk_gate impe_clks[] = {
+	GATE_IMPE(CLK_IMPE_I2C0, "impe_i2c0", "i2c_sel", 0),
+	GATE_IMPE(CLK_IMPE_I2C1, "impe_i2c1", "i2c_sel", 1),
+};
+
+static const struct mtk_clk_desc impe_mcd = {
+	.clks = impe_clks,
+	.num_clks = ARRAY_SIZE(impe_clks),
+};
+
+static const struct mtk_gate_regs impen_cg_regs = {
+	.set_ofs = 0x8,
+	.clr_ofs = 0x4,
+	.sta_ofs = 0x0,
+};
+
+#define GATE_IMPEN(_id, _name, _parent, _shift)				\
+	GATE_MTK_FLAGS(_id, _name, _parent, &impen_cg_regs, _shift,	\
+		&mtk_clk_gate_ops_setclr, CLK_OPS_PARENT_ENABLE)
+
+static const struct mtk_gate impen_clks[] = {
+	GATE_IMPEN(CLK_IMPEN_I2C7, "impen_i2c7", "i2c_sel", 0),
+	GATE_IMPEN(CLK_IMPEN_I2C8, "impen_i2c8", "i2c_sel", 1),
+};
+
+static const struct mtk_clk_desc impen_mcd = {
+	.clks = impen_clks,
+	.num_clks = ARRAY_SIZE(impen_clks),
+};
+
+static const struct mtk_gate_regs imps_cg_regs = {
+	.set_ofs = 0x8,
+	.clr_ofs = 0x4,
+	.sta_ofs = 0x0,
+};
+
+#define GATE_IMPS(_id, _name, _parent, _shift)				\
+	GATE_MTK_FLAGS(_id, _name, _parent, &imps_cg_regs, _shift,	\
+		&mtk_clk_gate_ops_setclr, CLK_OPS_PARENT_ENABLE)
+
+static const struct mtk_gate imps_clks[] = {
+	GATE_IMPS(CLK_IMPS_I2C3, "imps_i2c3", "i2c_sel", 0),
+	GATE_IMPS(CLK_IMPS_I2C4, "imps_i2c4", "i2c_sel", 1),
+	GATE_IMPS(CLK_IMPS_I2C5, "imps_i2c5", "i2c_sel", 2),
+	GATE_IMPS(CLK_IMPS_I2C6, "imps_i2c6", "i2c_sel", 3),
+};
+
+static const struct mtk_clk_desc imps_mcd = {
+	.clks = imps_clks,
+	.num_clks = ARRAY_SIZE(imps_clks),
+};
+
+static const struct mtk_gate_regs impws_cg_regs = {
+	.set_ofs = 0x8,
+	.clr_ofs = 0x4,
+	.sta_ofs = 0x0,
+};
+
+#define GATE_IMPWS(_id, _name, _parent, _shift)				\
+	GATE_MTK_FLAGS(_id, _name, _parent, &impws_cg_regs, _shift,	\
+		&mtk_clk_gate_ops_setclr, CLK_OPS_PARENT_ENABLE)
+
+static const struct mtk_gate impws_clks[] = {
+	GATE_IMPWS(CLK_IMPWS_I2C2, "impws_i2c2", "i2c_sel", 0),
+};
+
+static const struct mtk_clk_desc impws_mcd = {
+	.clks = impws_clks,
+	.num_clks = ARRAY_SIZE(impws_clks),
+};
+
+static const struct of_device_id of_match_clk_mt8189_iic[] = {
+	{ .compatible = "mediatek,mt8189-iic-wrap-e", .data = &impe_mcd },
+	{ .compatible = "mediatek,mt8189-iic-wrap-en", .data = &impen_mcd },
+	{ .compatible = "mediatek,mt8189-iic-wrap-s", .data = &imps_mcd },
+	{ .compatible = "mediatek,mt8189-iic-wrap-ws", .data = &impws_mcd },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_match_clk_mt8189_iic);
+
+static struct platform_driver clk_mt8189_iic_drv = {
+	.probe = mtk_clk_simple_probe,
+	.remove = mtk_clk_simple_remove,
+	.driver = {
+		.name = "clk-mt8189-iic",
+		.of_match_table = of_match_clk_mt8189_iic,
+	},
+};
+
+module_platform_driver(clk_mt8189_iic_drv);
+MODULE_DESCRIPTION("MediaTek MT8189 iic clocks driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



From irving-ch.lin at mediatek.com  Sun Dec 14 19:49:30 2025
From: irving-ch.lin at mediatek.com (irving.ch.lin)
Date: Mon, 15 Dec 2025 11:49:30 +0800
Subject: [PATCH v4 21/21] pmdomain: mediatek: Add power domain driver for MT8189 SoC
In-Reply-To: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
References: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
Message-ID: <20251215034944.2973003-22-irving-ch.lin@mediatek.com>

From: Irving-CH Lin <irving-ch.lin at mediatek.com>

Introduce a new power domain (pmd) driver for the MediaTek mt8189 SoC.
This driver ports and refines the power domain framework, dividing
hardware blocks (CPU, GPU, peripherals, etc.) into independent power
domains for precise and energy-efficient power management.

Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
---
 drivers/pmdomain/mediatek/mt8189-pm-domains.h | 485 ++++++++++++++++++
 drivers/pmdomain/mediatek/mtk-pm-domains.c    |   5 +
 2 files changed, 490 insertions(+)
 create mode 100644 drivers/pmdomain/mediatek/mt8189-pm-domains.h

diff --git a/drivers/pmdomain/mediatek/mt8189-pm-domains.h b/drivers/pmdomain/mediatek/mt8189-pm-domains.h
new file mode 100644
index 000000000000..c28b9460c074
--- /dev/null
+++ b/drivers/pmdomain/mediatek/mt8189-pm-domains.h
@@ -0,0 +1,485 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Qiqi Wang <qiqi.wang at mediatek.com>
+ */
+
+#ifndef __SOC_MEDIATEK_MT8189_PM_DOMAINS_H
+#define __SOC_MEDIATEK_MT8189_PM_DOMAINS_H
+
+#include "mtk-pm-domains.h"
+#include <dt-bindings/power/mediatek,mt8189-power.h>
+
+/*
+ * MT8189 power domain support
+ */
+
+#define MT8189_SPM_PWR_STATUS				0x0f40
+#define MT8189_SPM_PWR_STATUS_2ND			0x0f44
+#define MT8189_SPM_PWR_STATUS_MSB			0x0f48
+#define MT8189_SPM_PWR_STATUS_MSB_2ND			0x0f4c
+#define MT8189_SPM_XPU_PWR_STATUS			0x0f50
+#define MT8189_SPM_XPU_PWR_STATUS_2ND			0x0f54
+
+#define MT8189_PROT_EN_EMICFG_GALS_SLP_SET		0x0084
+#define MT8189_PROT_EN_EMICFG_GALS_SLP_CLR		0x0088
+#define MT8189_PROT_EN_EMICFG_GALS_SLP_RDY		0x008c
+#define MT8189_PROT_EN_MMSYS_STA_0_SET			0x0c14
+#define MT8189_PROT_EN_MMSYS_STA_0_CLR			0x0c18
+#define MT8189_PROT_EN_MMSYS_STA_0_RDY			0x0c1c
+#define MT8189_PROT_EN_MMSYS_STA_1_SET			0x0c24
+#define MT8189_PROT_EN_MMSYS_STA_1_CLR			0x0c28
+#define MT8189_PROT_EN_MMSYS_STA_1_RDY			0x0c2c
+#define MT8189_PROT_EN_INFRASYS_STA_0_SET		0x0c44
+#define MT8189_PROT_EN_INFRASYS_STA_0_CLR		0x0c48
+#define MT8189_PROT_EN_INFRASYS_STA_0_RDY		0x0c4c
+#define MT8189_PROT_EN_INFRASYS_STA_1_SET		0x0c54
+#define MT8189_PROT_EN_INFRASYS_STA_1_CLR		0x0c58
+#define MT8189_PROT_EN_INFRASYS_STA_1_RDY		0x0c5c
+#define MT8189_PROT_EN_PERISYS_STA_0_SET		0x0c84
+#define MT8189_PROT_EN_PERISYS_STA_0_CLR		0x0c88
+#define MT8189_PROT_EN_PERISYS_STA_0_RDY		0x0c8c
+#define MT8189_PROT_EN_MCU_STA_0_SET			0x0c94
+#define MT8189_PROT_EN_MCU_STA_0_CLR			0x0c98
+#define MT8189_PROT_EN_MCU_STA_0_RDY			0x0c9c
+#define MT8189_PROT_EN_MD_STA_0_SET			0x0ca4
+#define MT8189_PROT_EN_MD_STA_0_CLR			0x0ca8
+#define MT8189_PROT_EN_MD_STA_0_RDY			0x0cac
+
+#define MT8189_PROT_EN_EMISYS_STA_0_MM_INFRA		(GENMASK(21, 20))
+#define MT8189_PROT_EN_INFRASYS_STA_0_CONN		(BIT(8))
+#define MT8189_PROT_EN_INFRASYS_STA_1_CONN		(BIT(12))
+#define MT8189_PROT_EN_INFRASYS_STA_0_MM_INFRA		(BIT(16))
+#define MT8189_PROT_EN_INFRASYS_STA_1_MM_INFRA		(BIT(11))
+#define MT8189_PROT_EN_INFRASYS_STA_1_MFG1		(BIT(20))
+#define MT8189_PROT_EN_MCU_STA_0_CONN			(BIT(1))
+#define MT8189_PROT_EN_MCU_STA_0_CONN_2ND		(BIT(0))
+#define MT8189_PROT_EN_MD_STA_0_MFG1			(BIT(0) | BIT(2))
+#define MT8189_PROT_EN_MD_STA_0_MFG1_2ND		(BIT(4))
+#define MT8189_PROT_EN_MM_INFRA_IGN			(BIT(1))
+#define MT8189_PROT_EN_MM_INFRA_2_IGN			(BIT(0))
+#define MT8189_PROT_EN_MMSYS_STA_0_CAM_MAIN		(GENMASK(31, 30))
+#define MT8189_PROT_EN_MMSYS_STA_1_CAM_MAIN		(GENMASK(10, 9))
+#define MT8189_PROT_EN_MMSYS_STA_0_DISP			(GENMASK(1, 0))
+#define MT8189_PROT_EN_MMSYS_STA_0_ISP_IMG1		(BIT(3))
+#define MT8189_PROT_EN_MMSYS_STA_1_ISP_IMG1		(BIT(7))
+#define MT8189_PROT_EN_MMSYS_STA_0_ISP_IPE		(BIT(2))
+#define MT8189_PROT_EN_MMSYS_STA_1_ISP_IPE		(BIT(8))
+#define MT8189_PROT_EN_MMSYS_STA_0_MDP0			(BIT(18))
+#define MT8189_PROT_EN_MMSYS_STA_1_MM_INFRA		(GENMASK(3, 2))
+#define MT8189_PROT_EN_MMSYS_STA_1_MM_INFRA_2ND		(GENMASK(15, 7))
+#define MT8189_PROT_EN_MMSYS_STA_0_VDE0			(BIT(20))
+#define MT8189_PROT_EN_MMSYS_STA_1_VDE0			(BIT(13))
+#define MT8189_PROT_EN_MMSYS_STA_0_VEN0			(BIT(12))
+#define MT8189_PROT_EN_MMSYS_STA_1_VEN0			(BIT(12))
+#define MT8189_PROT_EN_PERISYS_STA_0_AUDIO		(BIT(6))
+#define MT8189_PROT_EN_PERISYS_STA_0_SSUSB		(BIT(7))
+#define MT8189_PROT_EN_EMICFG_GALS_SLP_MFG1		(GENMASK(5, 4))
+
+static enum scpsys_bus_prot_block scpsys_bus_prot_blocks_mt8189[] = {
+	BUS_PROT_BLOCK_INFRA, BUS_PROT_BLOCK_SMI
+};
+
+static const struct scpsys_domain_data scpsys_domain_data_mt8189[] = {
+	[MT8189_POWER_DOMAIN_CONN] = {
+		.name = "conn",
+		.sta_mask = BIT(1),
+		.ctl_offs = 0xe04,
+		.pwr_sta_offs = MT8189_SPM_PWR_STATUS,
+		.pwr_sta2nd_offs = MT8189_SPM_PWR_STATUS_2ND,
+		.bp_cfg = {
+			BUS_PROT_WR_IGN(INFRA,
+					MT8189_PROT_EN_MCU_STA_0_CONN,
+					MT8189_PROT_EN_MCU_STA_0_SET,
+					MT8189_PROT_EN_MCU_STA_0_CLR,
+					MT8189_PROT_EN_MCU_STA_0_RDY),
+			BUS_PROT_WR_IGN(INFRA,
+					MT8189_PROT_EN_INFRASYS_STA_1_CONN,
+					MT8189_PROT_EN_INFRASYS_STA_1_SET,
+					MT8189_PROT_EN_INFRASYS_STA_1_CLR,
+					MT8189_PROT_EN_INFRASYS_STA_1_RDY),
+			BUS_PROT_WR_IGN(INFRA,
+					MT8189_PROT_EN_MCU_STA_0_CONN_2ND,
+					MT8189_PROT_EN_MCU_STA_0_SET,
+					MT8189_PROT_EN_MCU_STA_0_CLR,
+					MT8189_PROT_EN_MCU_STA_0_RDY),
+			BUS_PROT_WR_IGN(INFRA,
+					MT8189_PROT_EN_INFRASYS_STA_0_CONN,
+					MT8189_PROT_EN_INFRASYS_STA_0_SET,
+					MT8189_PROT_EN_INFRASYS_STA_0_CLR,
+					MT8189_PROT_EN_INFRASYS_STA_0_RDY),
+		},
+		.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+	},
+	[MT8189_POWER_DOMAIN_AUDIO] = {
+		.name = "audio",
+		.sta_mask = BIT(6),
+		.ctl_offs = 0xe18,
+		.pwr_sta_offs = MT8189_SPM_PWR_STATUS,
+		.pwr_sta2nd_offs = MT8189_SPM_PWR_STATUS_2ND,
+		.sram_pdn_bits = BIT(8),
+		.sram_pdn_ack_bits = BIT(12),
+		.bp_cfg = {
+			BUS_PROT_WR_IGN(INFRA,
+					MT8189_PROT_EN_PERISYS_STA_0_AUDIO,
+					MT8189_PROT_EN_PERISYS_STA_0_SET,
+					MT8189_PROT_EN_PERISYS_STA_0_CLR,
+					MT8189_PROT_EN_PERISYS_STA_0_RDY),
+		},
+	},
+	[MT8189_POWER_DOMAIN_ADSP_TOP_DORMANT] = {
+		.name = "adsp-top-dormant",
+		.sta_mask = BIT(7),
+		.ctl_offs = 0xe1c,
+		.pwr_sta_offs = MT8189_SPM_PWR_STATUS,
+		.pwr_sta2nd_offs = MT8189_SPM_PWR_STATUS_2ND,
+		.sram_pdn_bits = BIT(9),
+		.sram_pdn_ack_bits = BIT(13),
+		.caps = MTK_SCPD_SRAM_ISO | MTK_SCPD_SRAM_PDN_INVERTED |
+			MTK_SCPD_ACTIVE_WAKEUP | MTK_SCPD_KEEP_DEFAULT_OFF,
+	},
+	[MT8189_POWER_DOMAIN_ADSP_INFRA] = {
+		.name = "adsp-infra",
+		.sta_mask = BIT(8),
+		.pwr_sta_offs = MT8189_SPM_PWR_STATUS,
+		.pwr_sta2nd_offs = MT8189_SPM_PWR_STATUS_2ND,
+		.ctl_offs = 0xe20,
+		.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+	},
+	[MT8189_POWER_DOMAIN_ADSP_AO] = {
+		.name = "adsp-ao",
+		.sta_mask = BIT(9),
+		.ctl_offs = 0xe24,
+		.pwr_sta_offs = MT8189_SPM_PWR_STATUS,
+		.pwr_sta2nd_offs = MT8189_SPM_PWR_STATUS_2ND,
+	},
+	[MT8189_POWER_DOMAIN_ISP_IMG1] = {
+		.name = "isp-img1",
+		.sta_mask = BIT(10),
+		.ctl_offs = 0xe28,
+		.pwr_sta_offs = MT8189_SPM_PWR_STATUS,
+		.pwr_sta2nd_offs = MT8189_SPM_PWR_STATUS_2ND,
+		.sram_pdn_bits = BIT(8),
+		.sram_pdn_ack_bits = BIT(12),
+		.bp_cfg = {
+			BUS_PROT_WR_IGN(INFRA,
+					MT8189_PROT_EN_MMSYS_STA_0_ISP_IMG1,
+					MT8189_PROT_EN_MMSYS_STA_0_SET,
+					MT8189_PROT_EN_MMSYS_STA_0_CLR,
+					MT8189_PROT_EN_MMSYS_STA_0_RDY),
+			BUS_PROT_WR_IGN(INFRA,
+					MT8189_PROT_EN_MMSYS_STA_1_ISP_IMG1,
+					MT8189_PROT_EN_MMSYS_STA_1_SET,
+					MT8189_PROT_EN_MMSYS_STA_1_CLR,
+					MT8189_PROT_EN_MMSYS_STA_1_RDY),
+		},
+		.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+	},
+	[MT8189_POWER_DOMAIN_ISP_IMG2] = {
+		.name = "isp-img2",
+		.sta_mask = BIT(11),
+		.ctl_offs = 0xe2c,
+		.pwr_sta_offs = MT8189_SPM_PWR_STATUS,
+		.pwr_sta2nd_offs = MT8189_SPM_PWR_STATUS_2ND,
+		.sram_pdn_bits = BIT(8),
+		.sram_pdn_ack_bits = BIT(12),
+		.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+	},
+	[MT8189_POWER_DOMAIN_ISP_IPE] = {
+		.name = "isp-ipe",
+		.sta_mask = BIT(12),
+		.ctl_offs = 0xe30,
+		.pwr_sta_offs = MT8189_SPM_PWR_STATUS,
+		.pwr_sta2nd_offs = MT8189_SPM_PWR_STATUS_2ND,
+		.sram_pdn_bits = BIT(8),
+		.sram_pdn_ack_bits = BIT(12),
+		.bp_cfg = {
+			BUS_PROT_WR_IGN(INFRA,
+					MT8189_PROT_EN_MMSYS_STA_0_ISP_IPE,
+					MT8189_PROT_EN_MMSYS_STA_0_SET,
+					MT8189_PROT_EN_MMSYS_STA_0_CLR,
+					MT8189_PROT_EN_MMSYS_STA_0_RDY),
+			BUS_PROT_WR_IGN(INFRA,
+					MT8189_PROT_EN_MMSYS_STA_1_ISP_IPE,
+					MT8189_PROT_EN_MMSYS_STA_1_SET,
+					MT8189_PROT_EN_MMSYS_STA_1_CLR,
+					MT8189_PROT_EN_MMSYS_STA_1_RDY),
+		},
+		.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+	},
+	[MT8189_POWER_DOMAIN_VDE0] = {
+		.name = "vde0",
+		.sta_mask = BIT(14),
+		.ctl_offs = 0xe38,
+		.pwr_sta_offs = MT8189_SPM_PWR_STATUS,
+		.pwr_sta2nd_offs = MT8189_SPM_PWR_STATUS_2ND,
+		.sram_pdn_bits = BIT(8),
+		.sram_pdn_ack_bits = BIT(12),
+		.bp_cfg = {
+			BUS_PROT_WR_IGN(INFRA,
+					MT8189_PROT_EN_MMSYS_STA_0_VDE0,
+					MT8189_PROT_EN_MMSYS_STA_0_SET,
+					MT8189_PROT_EN_MMSYS_STA_0_CLR,
+					MT8189_PROT_EN_MMSYS_STA_0_RDY),
+			BUS_PROT_WR_IGN(INFRA,
+					MT8189_PROT_EN_MMSYS_STA_1_VDE0,
+					MT8189_PROT_EN_MMSYS_STA_1_SET,
+					MT8189_PROT_EN_MMSYS_STA_1_CLR,
+					MT8189_PROT_EN_MMSYS_STA_1_RDY),
+		},
+	},
+	[MT8189_POWER_DOMAIN_VEN0] = {
+		.name = "ven0",
+		.sta_mask = BIT(16),
+		.ctl_offs = 0xe40,
+		.pwr_sta_offs = MT8189_SPM_PWR_STATUS,
+		.pwr_sta2nd_offs = MT8189_SPM_PWR_STATUS_2ND,
+		.sram_pdn_bits = BIT(8),
+		.sram_pdn_ack_bits = BIT(12),
+		.bp_cfg = {
+			BUS_PROT_WR_IGN(INFRA,
+					MT8189_PROT_EN_MMSYS_STA_0_VEN0,
+					MT8189_PROT_EN_MMSYS_STA_0_SET,
+					MT8189_PROT_EN_MMSYS_STA_0_CLR,
+					MT8189_PROT_EN_MMSYS_STA_0_RDY),
+			BUS_PROT_WR_IGN(INFRA,
+					MT8189_PROT_EN_MMSYS_STA_1_VEN0,
+					MT8189_PROT_EN_MMSYS_STA_1_SET,
+					MT8189_PROT_EN_MMSYS_STA_1_CLR,
+					MT8189_PROT_EN_MMSYS_STA_1_RDY),
+		},
+	},
+	[MT8189_POWER_DOMAIN_CAM_MAIN] = {
+		.name = "cam-main",
+		.sta_mask = BIT(18),
+		.ctl_offs = 0xe48,
+		.pwr_sta_offs = MT8189_SPM_PWR_STATUS,
+		.pwr_sta2nd_offs = MT8189_SPM_PWR_STATUS_2ND,
+		.sram_pdn_bits = BIT(8),
+		.sram_pdn_ack_bits = BIT(12),
+		.bp_cfg = {
+			BUS_PROT_WR_IGN(INFRA,
+					MT8189_PROT_EN_MMSYS_STA_0_CAM_MAIN,
+					MT8189_PROT_EN_MMSYS_STA_0_SET,
+					MT8189_PROT_EN_MMSYS_STA_0_CLR,
+					MT8189_PROT_EN_MMSYS_STA_0_RDY),
+			BUS_PROT_WR_IGN(INFRA,
+					MT8189_PROT_EN_MMSYS_STA_1_CAM_MAIN,
+					MT8189_PROT_EN_MMSYS_STA_1_SET,
+					MT8189_PROT_EN_MMSYS_STA_1_CLR,
+					MT8189_PROT_EN_MMSYS_STA_1_RDY),
+		},
+		.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+	},
+	[MT8189_POWER_DOMAIN_CAM_SUBA] = {
+		.name = "cam-suba",
+		.sta_mask = BIT(20),
+		.ctl_offs = 0xe50,
+		.pwr_sta_offs = MT8189_SPM_PWR_STATUS,
+		.pwr_sta2nd_offs = MT8189_SPM_PWR_STATUS_2ND,
+		.sram_pdn_bits = BIT(8),
+		.sram_pdn_ack_bits = BIT(12),
+		.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+	},
+	[MT8189_POWER_DOMAIN_CAM_SUBB] = {
+		.name = "cam-subb",
+		.sta_mask = BIT(21),
+		.ctl_offs = 0xe54,
+		.pwr_sta_offs = MT8189_SPM_PWR_STATUS,
+		.pwr_sta2nd_offs = MT8189_SPM_PWR_STATUS_2ND,
+		.sram_pdn_bits = BIT(8),
+		.sram_pdn_ack_bits = BIT(12),
+		.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+	},
+	[MT8189_POWER_DOMAIN_MDP0] = {
+		.name = "mdp0",
+		.sta_mask = BIT(26),
+		.ctl_offs = 0xe68,
+		.pwr_sta_offs = MT8189_SPM_PWR_STATUS,
+		.pwr_sta2nd_offs = MT8189_SPM_PWR_STATUS_2ND,
+		.sram_pdn_bits = BIT(8),
+		.sram_pdn_ack_bits = BIT(12),
+		.bp_cfg = {
+			BUS_PROT_WR_IGN(INFRA,
+					MT8189_PROT_EN_MMSYS_STA_0_MDP0,
+					MT8189_PROT_EN_MMSYS_STA_0_SET,
+					MT8189_PROT_EN_MMSYS_STA_0_CLR,
+					MT8189_PROT_EN_MMSYS_STA_0_RDY),
+		},
+	},
+	[MT8189_POWER_DOMAIN_DISP] = {
+		.name = "disp",
+		.sta_mask = BIT(28),
+		.ctl_offs = 0xe70,
+		.pwr_sta_offs = MT8189_SPM_PWR_STATUS,
+		.pwr_sta2nd_offs = MT8189_SPM_PWR_STATUS_2ND,
+		.sram_pdn_bits = BIT(8),
+		.sram_pdn_ack_bits = BIT(12),
+		.bp_cfg = {
+			BUS_PROT_WR_IGN(INFRA,
+					MT8189_PROT_EN_MMSYS_STA_0_DISP,
+					MT8189_PROT_EN_MMSYS_STA_0_SET,
+					MT8189_PROT_EN_MMSYS_STA_0_CLR,
+					MT8189_PROT_EN_MMSYS_STA_0_RDY),
+		},
+	},
+	[MT8189_POWER_DOMAIN_MM_INFRA] = {
+		.name = "mm-infra",
+		.sta_mask = BIT(30),
+		.ctl_offs = 0xe78,
+		.pwr_sta_offs = MT8189_SPM_PWR_STATUS,
+		.pwr_sta2nd_offs = MT8189_SPM_PWR_STATUS_2ND,
+		.sram_pdn_bits = BIT(8),
+		.sram_pdn_ack_bits = BIT(12),
+		.bp_cfg = {
+			BUS_PROT_WR_IGN(INFRA,
+					MT8189_PROT_EN_MMSYS_STA_1_MM_INFRA,
+					MT8189_PROT_EN_MMSYS_STA_1_SET,
+					MT8189_PROT_EN_MMSYS_STA_1_CLR,
+					MT8189_PROT_EN_MMSYS_STA_1_RDY),
+			BUS_PROT_WR_IGN(INFRA,
+					MT8189_PROT_EN_MMSYS_STA_1_MM_INFRA_2ND,
+					MT8189_PROT_EN_MMSYS_STA_1_SET,
+					MT8189_PROT_EN_MMSYS_STA_1_CLR,
+					MT8189_PROT_EN_MMSYS_STA_1_RDY),
+			BUS_PROT_WR_IGN_SUBCLK(INFRA,
+					       MT8189_PROT_EN_MM_INFRA_IGN,
+					       MT8189_PROT_EN_MMSYS_STA_1_SET,
+					       MT8189_PROT_EN_MMSYS_STA_1_CLR,
+					       MT8189_PROT_EN_MMSYS_STA_1_RDY),
+			BUS_PROT_WR_IGN_SUBCLK(INFRA,
+					       MT8189_PROT_EN_MM_INFRA_2_IGN,
+					       MT8189_PROT_EN_MMSYS_STA_1_SET,
+					       MT8189_PROT_EN_MMSYS_STA_1_CLR,
+					       MT8189_PROT_EN_MMSYS_STA_1_RDY),
+		},
+	},
+	[MT8189_POWER_DOMAIN_DP_TX] = {
+		.name = "dp-tx",
+		.sta_mask = BIT(0),
+		.ctl_offs = 0xe80,
+		.pwr_sta_offs = MT8189_SPM_PWR_STATUS_MSB,
+		.pwr_sta2nd_offs = MT8189_SPM_PWR_STATUS_MSB_2ND,
+		.sram_pdn_bits = BIT(8),
+		.sram_pdn_ack_bits = BIT(12),
+	},
+	[MT8189_POWER_DOMAIN_CSI_RX] = {
+		.name = "csi-rx",
+		.sta_mask = BIT(7),
+		.ctl_offs = 0xe9c,
+		.pwr_sta_offs = MT8189_SPM_PWR_STATUS_MSB,
+		.pwr_sta2nd_offs = MT8189_SPM_PWR_STATUS_MSB_2ND,
+		.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+	},
+	[MT8189_POWER_DOMAIN_SSUSB] = {
+		.name = "ssusb",
+		.sta_mask = BIT(10),
+		.ctl_offs = 0xea8,
+		.pwr_sta_offs = MT8189_SPM_PWR_STATUS_MSB,
+		.pwr_sta2nd_offs = MT8189_SPM_PWR_STATUS_MSB_2ND,
+		.sram_pdn_bits = BIT(8),
+		.sram_pdn_ack_bits = BIT(12),
+		.bp_cfg = {
+			BUS_PROT_WR_IGN(INFRA,
+					MT8189_PROT_EN_PERISYS_STA_0_SSUSB,
+					MT8189_PROT_EN_PERISYS_STA_0_SET,
+					MT8189_PROT_EN_PERISYS_STA_0_CLR,
+					MT8189_PROT_EN_PERISYS_STA_0_RDY),
+		},
+		.caps = MTK_SCPD_ACTIVE_WAKEUP,
+	},
+	[MT8189_POWER_DOMAIN_MFG0] = {
+		.name = "mfg0",
+		.sta_mask = BIT(1),
+		.ctl_offs = 0xeb4,
+		.pwr_sta_offs = MT8189_SPM_XPU_PWR_STATUS,
+		.pwr_sta2nd_offs = MT8189_SPM_XPU_PWR_STATUS_2ND,
+		.caps = MTK_SCPD_DOMAIN_SUPPLY,
+	},
+	[MT8189_POWER_DOMAIN_MFG1] = {
+		.name = "mfg1",
+		.sta_mask = BIT(2),
+		.ctl_offs = 0xeb8,
+		.pwr_sta_offs = MT8189_SPM_XPU_PWR_STATUS,
+		.pwr_sta2nd_offs = MT8189_SPM_XPU_PWR_STATUS_2ND,
+		.sram_pdn_bits = BIT(8),
+		.sram_pdn_ack_bits = BIT(12),
+		.bp_cfg = {
+			BUS_PROT_WR_IGN(INFRA,
+					MT8189_PROT_EN_INFRASYS_STA_1_MFG1,
+					MT8189_PROT_EN_INFRASYS_STA_1_SET,
+					MT8189_PROT_EN_INFRASYS_STA_1_CLR,
+					MT8189_PROT_EN_INFRASYS_STA_1_RDY),
+			BUS_PROT_WR_IGN(INFRA,
+					MT8189_PROT_EN_MD_STA_0_MFG1,
+					MT8189_PROT_EN_MD_STA_0_SET,
+					MT8189_PROT_EN_MD_STA_0_CLR,
+					MT8189_PROT_EN_MD_STA_0_RDY),
+			BUS_PROT_WR_IGN(INFRA,
+					MT8189_PROT_EN_MD_STA_0_MFG1_2ND,
+					MT8189_PROT_EN_MD_STA_0_SET,
+					MT8189_PROT_EN_MD_STA_0_CLR,
+					MT8189_PROT_EN_MD_STA_0_RDY),
+			BUS_PROT_WR_IGN(SMI,
+					MT8189_PROT_EN_EMICFG_GALS_SLP_MFG1,
+					MT8189_PROT_EN_EMICFG_GALS_SLP_SET,
+					MT8189_PROT_EN_EMICFG_GALS_SLP_CLR,
+					MT8189_PROT_EN_EMICFG_GALS_SLP_RDY),
+		},
+		.caps = MTK_SCPD_DOMAIN_SUPPLY,
+	},
+	[MT8189_POWER_DOMAIN_MFG2] = {
+		.name = "mfg2",
+		.sta_mask = BIT(3),
+		.ctl_offs = 0xebc,
+		.pwr_sta_offs = MT8189_SPM_XPU_PWR_STATUS,
+		.pwr_sta2nd_offs = MT8189_SPM_XPU_PWR_STATUS_2ND,
+		.sram_pdn_bits = BIT(8),
+		.sram_pdn_ack_bits = BIT(12),
+	},
+	[MT8189_POWER_DOMAIN_MFG3] = {
+		.name = "mfg3",
+		.sta_mask = BIT(4),
+		.ctl_offs = 0xec0,
+		.pwr_sta_offs = MT8189_SPM_XPU_PWR_STATUS,
+		.pwr_sta2nd_offs = MT8189_SPM_XPU_PWR_STATUS_2ND,
+		.sram_pdn_bits = BIT(8),
+		.sram_pdn_ack_bits = BIT(12),
+	},
+	[MT8189_POWER_DOMAIN_EDP_TX_DORMANT] = {
+		.name = "edp-tx-dormant",
+		.sta_mask = BIT(12),
+		.ctl_offs = 0xf70,
+		.pwr_sta_offs = MT8189_SPM_PWR_STATUS_MSB,
+		.pwr_sta2nd_offs = MT8189_SPM_PWR_STATUS_MSB_2ND,
+		.sram_pdn_bits = BIT(9),
+		.sram_pdn_ack_bits = 0,
+		.caps = MTK_SCPD_SRAM_ISO | MTK_SCPD_SRAM_PDN_INVERTED,
+	},
+	[MT8189_POWER_DOMAIN_PCIE] = {
+		.name = "pcie",
+		.sta_mask = BIT(13),
+		.ctl_offs = 0xf74,
+		.pwr_sta_offs = MT8189_SPM_PWR_STATUS_MSB,
+		.pwr_sta2nd_offs = MT8189_SPM_PWR_STATUS_MSB_2ND,
+		.sram_pdn_bits = BIT(8),
+		.sram_pdn_ack_bits = BIT(12),
+		.caps = MTK_SCPD_ACTIVE_WAKEUP,
+	},
+	[MT8189_POWER_DOMAIN_PCIE_PHY] = {
+		.name = "pcie-phy",
+		.sta_mask = BIT(14),
+		.ctl_offs = 0xf78,
+		.pwr_sta_offs = MT8189_SPM_PWR_STATUS_MSB,
+		.pwr_sta2nd_offs = MT8189_SPM_PWR_STATUS_MSB_2ND,
+	},
+};
+
+static const struct scpsys_soc_data mt8189_scpsys_data = {
+	.domains_data = scpsys_domain_data_mt8189,
+	.num_domains = ARRAY_SIZE(scpsys_domain_data_mt8189),
+	.bus_prot_blocks = scpsys_bus_prot_blocks_mt8189,
+	.num_bus_prot_blocks = ARRAY_SIZE(scpsys_bus_prot_blocks_mt8189),
+};
+
+#endif /* __SOC_MEDIATEK_MT8189_PM_DOMAINS_H */
diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c
index bfa3ae55e8fd..721224c89865 100644
--- a/drivers/pmdomain/mediatek/mtk-pm-domains.c
+++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c
@@ -26,6 +26,7 @@
 #include "mt8183-pm-domains.h"
 #include "mt8186-pm-domains.h"
 #include "mt8188-pm-domains.h"
+#include "mt8189-pm-domains.h"
 #include "mt8192-pm-domains.h"
 #include "mt8195-pm-domains.h"
 #include "mt8196-pm-domains.h"
@@ -1180,6 +1181,10 @@ static const struct of_device_id scpsys_of_match[] = {
 		.compatible = "mediatek,mt8188-power-controller",
 		.data = &mt8188_scpsys_data,
 	},
+	{
+		.compatible = "mediatek,mt8189-power-controller",
+		.data = &mt8189_scpsys_data,
+	},
 	{
 		.compatible = "mediatek,mt8192-power-controller",
 		.data = &mt8192_scpsys_data,
-- 
2.45.2



From irving-ch.lin at mediatek.com  Sun Dec 14 19:49:19 2025
From: irving-ch.lin at mediatek.com (irving.ch.lin)
Date: Mon, 15 Dec 2025 11:49:19 +0800
Subject: [PATCH v4 10/21] clk: mediatek: Add MT8189 dbgao clock support
In-Reply-To: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
References: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
Message-ID: <20251215034944.2973003-11-irving-ch.lin@mediatek.com>

From: Irving-CH Lin <irving-ch.lin at mediatek.com>

Add support for the MT8189 dbgao clock controller,
which provides clock gate control for debug-system.

Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
---
 drivers/clk/mediatek/Kconfig            | 10 +++
 drivers/clk/mediatek/Makefile           |  1 +
 drivers/clk/mediatek/clk-mt8189-dbgao.c | 94 +++++++++++++++++++++++++
 3 files changed, 105 insertions(+)
 create mode 100644 drivers/clk/mediatek/clk-mt8189-dbgao.c

diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
index 82a26d952bff..c707b224dccd 100644
--- a/drivers/clk/mediatek/Kconfig
+++ b/drivers/clk/mediatek/Kconfig
@@ -850,6 +850,16 @@ config COMMON_CLK_MT8189_CAM
 	  that relies on this SoC and you want to control its clocks, say Y or M
 	  to include this driver in your kernel build.
 
+config COMMON_CLK_MT8189_DBGAO
+	tristate "Clock driver for MediaTek MT8189 debug ao"
+	depends on COMMON_CLK_MT8189
+	default COMMON_CLK_MT8189
+	help
+	  Enable this to support the clock management for the debug function
+	  on MediaTek MT8189 SoCs. This includes enabling and disabling
+	  vcore debug system clocks. If you want to control its clocks, say Y or M
+	  to include this driver in your kernel build.
+
 config COMMON_CLK_MT8192
 	tristate "Clock driver for MediaTek MT8192"
 	depends on ARM64 || COMPILE_TEST
diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
index 95a8f4ae05ee..eabe2cab4b8d 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -127,6 +127,7 @@ obj-$(CONFIG_COMMON_CLK_MT8189) += clk-mt8189-apmixedsys.o clk-mt8189-topckgen.o
 				   clk-mt8189-vlpckgen.o clk-mt8189-vlpcfg.o
 obj-$(CONFIG_COMMON_CLK_MT8189_BUS) += clk-mt8189-bus.o
 obj-$(CONFIG_COMMON_CLK_MT8189_CAM) += clk-mt8189-cam.o
+obj-$(CONFIG_COMMON_CLK_MT8189_DBGAO) += clk-mt8189-dbgao.o
 obj-$(CONFIG_COMMON_CLK_MT8192) += clk-mt8192-apmixedsys.o clk-mt8192.o
 obj-$(CONFIG_COMMON_CLK_MT8192_AUDSYS) += clk-mt8192-aud.o
 obj-$(CONFIG_COMMON_CLK_MT8192_CAMSYS) += clk-mt8192-cam.o
diff --git a/drivers/clk/mediatek/clk-mt8189-dbgao.c b/drivers/clk/mediatek/clk-mt8189-dbgao.c
new file mode 100644
index 000000000000..543321ae5e65
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8189-dbgao.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Qiqi Wang <qiqi.wang at mediatek.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include "clk-mtk.h"
+#include "clk-gate.h"
+
+#include <dt-bindings/clock/mediatek,mt8189-clk.h>
+
+static const struct mtk_gate_regs dbgao_cg_regs = {
+	.set_ofs = 0x70,
+	.clr_ofs = 0x70,
+	.sta_ofs = 0x70,
+};
+
+#define GATE_DBGAO(_id, _name, _parent, _shift)		\
+	GATE_MTK(_id, _name, _parent, &dbgao_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv)
+
+static const struct mtk_gate dbgao_clks[] = {
+	GATE_DBGAO(CLK_DBGAO_ATB_EN, "dbgao_atb_en", "atb_sel", 0),
+};
+
+static const struct mtk_clk_desc dbgao_mcd = {
+	.clks = dbgao_clks,
+	.num_clks = ARRAY_SIZE(dbgao_clks),
+};
+
+static const struct mtk_gate_regs dem0_cg_regs = {
+	.set_ofs = 0x2c,
+	.clr_ofs = 0x2c,
+	.sta_ofs = 0x2c,
+};
+
+static const struct mtk_gate_regs dem1_cg_regs = {
+	.set_ofs = 0x30,
+	.clr_ofs = 0x30,
+	.sta_ofs = 0x30,
+};
+
+static const struct mtk_gate_regs dem2_cg_regs = {
+	.set_ofs = 0x70,
+	.clr_ofs = 0x70,
+	.sta_ofs = 0x70,
+};
+
+#define GATE_DEM0(_id, _name, _parent, _shift)		\
+	GATE_MTK(_id, _name, _parent, &dem0_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv)
+
+#define GATE_DEM1(_id, _name, _parent, _shift)		\
+	GATE_MTK(_id, _name, _parent, &dem1_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv)
+
+#define GATE_DEM2(_id, _name, _parent, _shift)		\
+	GATE_MTK(_id, _name, _parent, &dem2_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv)
+
+static const struct mtk_gate dem_clks[] = {
+	/* DEM0 */
+	GATE_DEM0(CLK_DEM_BUSCLK_EN, "dem_busclk_en", "axi_sel", 0),
+	/* DEM1 */
+	GATE_DEM1(CLK_DEM_SYSCLK_EN, "dem_sysclk_en", "axi_sel", 0),
+	/* DEM2 */
+	GATE_DEM2(CLK_DEM_ATB_EN, "dem_atb_en", "atb_sel", 0),
+};
+
+static const struct mtk_clk_desc dem_mcd = {
+	.clks = dem_clks,
+	.num_clks = ARRAY_SIZE(dem_clks),
+};
+
+static const struct of_device_id of_match_clk_mt8189_dbgao[] = {
+	{ .compatible = "mediatek,mt8189-dbg-ao", .data = &dbgao_mcd },
+	{ .compatible = "mediatek,mt8189-dem", .data = &dem_mcd },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_match_clk_mt8189_dbgao);
+
+static struct platform_driver clk_mt8189_dbgao_drv = {
+	.probe = mtk_clk_simple_probe,
+	.remove = mtk_clk_simple_remove,
+	.driver = {
+		.name = "clk-mt8189-dbgao",
+		.of_match_table = of_match_clk_mt8189_dbgao,
+	},
+};
+
+module_platform_driver(clk_mt8189_dbgao_drv);
+MODULE_DESCRIPTION("MediaTek MT8189 dbgao system clocks driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



From lkp at intel.com  Sun Dec 14 19:51:39 2025
From: lkp at intel.com (kernel test robot)
Date: Mon, 15 Dec 2025 04:51:39 +0100
Subject: [PATCH v21 1/7] Documentation/firmware: add imx/se to
 other_interfaces
In-Reply-To: <20251212-imx-se-if-v21-1-ee7d6052d848@nxp.com>
References: <20251212-imx-se-if-v21-1-ee7d6052d848@nxp.com>
Message-ID: <202512150427.Kc14BEvI-lkp@intel.com>

Hi Pankaj,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 4a26e7032d7d57c998598c08a034872d6f0d3945]

url:    https://github.com/intel-lab-lkp/linux/commits/Pankaj-Gupta/Documentation-firmware-add-imx-se-to-other_interfaces/20251212-172535
base:   4a26e7032d7d57c998598c08a034872d6f0d3945
patch link:    https://lore.kernel.org/r/20251212-imx-se-if-v21-1-ee7d6052d848%40nxp.com
patch subject: [PATCH v21 1/7] Documentation/firmware: add imx/se to other_interfaces
reproduce: (https://download.01.org/0day-ci/archive/20251215/202512150427.Kc14BEvI-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512150427.Kc14BEvI-lkp at intel.com/

All warnings (new ones prefixed by >>):

   ERROR: Cannot find file ./include/linux/firmware/intel/stratix10-svc-client.h
   WARNING: No kernel-doc for file ./include/linux/firmware/intel/stratix10-svc-client.h
   Documentation/driver-api/firmware/other_interfaces.rst:60: ERROR: Unexpected indentation. [docutils]
   Documentation/driver-api/firmware/other_interfaces.rst:103: ERROR: Unexpected indentation. [docutils]
   Documentation/driver-api/firmware/other_interfaces.rst:115: ERROR: Unexpected indentation. [docutils]
>> Documentation/driver-api/firmware/other_interfaces.rst:116: WARNING: Blank line required after table. [docutils]
>> Documentation/driver-api/firmware/other_interfaces.rst:140: WARNING: Bullet list ends without a blank line; unexpected unindent. [docutils]
   ERROR: Cannot find file ./drivers/firmware/imx/se_fw.c
   ERROR: Cannot find file ./drivers/firmware/imx/se_fw.c
   WARNING: No kernel-doc for file ./drivers/firmware/imx/se_fw.c
   ERROR: Cannot find file ./include/linux/fpga/fpga-bridge.h
   WARNING: No kernel-doc for file ./include/linux/fpga/fpga-bridge.h


vim +116 Documentation/driver-api/firmware/other_interfaces.rst

    94	
    95	::
    96	   +--------------------------------------------+
    97	   |            Character Device(C_DEV)         |
    98	   |                                            |
    99	   |   +---------+ +---------+     +---------+  |
   100	   |   | misc #1 | | misc #2 | ... | misc #n |  |
   101	   |   |  dev    | |  dev    |     | dev     |  |
   102	   |   +---------+ +---------+     +---------+  |
   103	   |        +-------------------------+         |
   104	   |        | Misc. Dev Synchr. Logic |         |
   105	   |        +-------------------------+         |
   106	   |                                            |
   107	   +--------------------------------------------+
   108	
   109	   +--------------------------------------------+
   110	   |               Service Layer                |
   111	   |                                            |
   112	   |      +-----------------------------+       |
   113	   |      | Message Serialization Logic |       |
   114	   |      +-----------------------------+       |
   115	   |          +---------------+                 |
 > 116	   |          |  imx-mailbox  |                 |
   117	   |          |   mailbox.c   |                 |
   118	   |          +---------------+                 |
   119	   |                                            |
   120	   +--------------------------------------------+
   121	
   122	- service layer:
   123	  This layer is responsible for ensuring the communication protocol that is defined
   124	  for communication with firmware.
   125	
   126	  FW Communication protocol ensures two things:
   127	  - Serializing the messages to be sent over an MU.
   128	
   129	  - FW can handle one command message at a time.
   130	
   131	- c_dev:
   132	  This layer offers character device contexts, created as '/dev/<se>_mux_chx'.
   133	  Using these multiple device contexts that are getting multiplexed over a single MU,
   134	  userspace application(s) can call fops like write/read to send the command message,
   135	  and read back the command response message to/from Firmware.
   136	  fops like read & write use the above defined service layer API(s) to communicate with
   137	  Firmware.
   138	
   139	  Misc-device(/dev/<se>_mux_chn) synchronization protocol:
 > 140	::
   141	
   142	                                Non-Secure               +   Secure
   143	                                                         |
   144	                                                         |
   145	                  +---------+      +-------------+       |
   146	                  | se_fw.c +<---->+imx-mailbox.c|       |
   147	                  |         |      |  mailbox.c  +<-->+------+    +------+
   148	                  +---+-----+      +-------------+    | MU X +<-->+ ELE |
   149	                      |                               +------+    +------+
   150	                      +----------------+                 |
   151	                      |                |                 |
   152	                      v                v                 |
   153	                  logical           logical              |
   154	                  receiver          waiter               |
   155	                     +                 +                 |
   156	                     |                 |                 |
   157	                     |                 |                 |
   158	                     |            +----+------+          |
   159	                     |            |           |          |
   160	                     |            |           |          |
   161	              device_ctx     device_ctx     device_ctx   |
   162	                                                         |
   163	                User 0        User 1       User Y        |
   164	                +------+      +------+     +------+      |
   165	                |misc.c|      |misc.c|     |misc.c|      |
   166	 kernel space   +------+      +------+     +------+      |
   167	                                                         |
   168	 +------------------------------------------------------ |
   169	                    |             |           |          |
   170	 userspace     /dev/ele_muXch0    |           |          |
   171	                          /dev/ele_muXch1     |          |
   172	                                        /dev/ele_muXchY  |
   173	                                                         |
   174	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From shengjiu.wang at gmail.com  Sun Dec 14 19:53:49 2025
From: shengjiu.wang at gmail.com (Shengjiu Wang)
Date: Mon, 15 Dec 2025 11:53:49 +0800
Subject: imx8mp SPDIF TX does not produce a lockable signal
In-Reply-To: <CAOMZO5BhmvC1_AhcKTerd1p6PdJ7+YLonU59CcHfmpTVavgqdA@mail.gmail.com>
References: <CAOMZO5BuMLhMyMkfE1xhOwEs2U=+pZnVq+FP+_bp5W_Qg6oMxQ@mail.gmail.com>
 <CAOMZO5BhmvC1_AhcKTerd1p6PdJ7+YLonU59CcHfmpTVavgqdA@mail.gmail.com>
Message-ID: <CAA+D8AMMDuakAXSUizUmxdbPZiD_kzTEC_gSS5FVCRJ1nxDHgQ@mail.gmail.com>

On Sat, Dec 13, 2025 at 6:12?AM Fabio Estevam <festevam at gmail.com> wrote:
>
> On Fri, Dec 12, 2025 at 4:11?PM Fabio Estevam <festevam at gmail.com> wrote:
>
> > Any suggestions for debugging or fixing this would be appreciated.
>
> The SPDIF TX audio locks and operation now works.
>
> The key thing was to pass AES1 information.

Yes,  the only supported format is IEC958 in driver,  so need to convert to this
format from alsa-lib.

Best regards
Shengjiu Wang
>
> In /etc/asound.conf:
>
> pcm.spdif_out {
>     type iec958
>     slave {
>         format IEC958_SUBFRAME_LE
>         pcm {
>             type hw
>             card imxaudioxcvr
>         }
>     }
>     status [ 0x00 0x0A 0x00 0x00 ]
>     preamble.z 0x0
>     preamble.x 0x1
>     preamble.y 0x3
> }
>
> Play the wav file:
> aplay -D plug:spdif_out  96-24.wav
>
> or a 440 Hz tone via speaker test:
>
> speaker-test -D plug:spdif_out -c 2 -t sine
>
> Thanks


From maqianga at uniontech.com  Sun Dec 14 20:41:36 2025
From: maqianga at uniontech.com (Qiang Ma)
Date: Mon, 15 Dec 2025 12:41:36 +0800
Subject: [PATCH v1 2/3] kexec: print out debugging message if required for
 kexec_load
In-Reply-To: <20251214163214.5018b9c083f11c7ecc081a5d@linux-foundation.org>
References: <20251212095649.857796-1-maqianga@uniontech.com>
 <20251212095649.857796-3-maqianga@uniontech.com>
 <20251214163214.5018b9c083f11c7ecc081a5d@linux-foundation.org>
Message-ID: <B86C6BDD7F4F1AC4+1b245d22-60ed-48d4-829e-aadfa145098f@uniontech.com>


? 2025/12/15 08:32, Andrew Morton ??:
> On Fri, 12 Dec 2025 17:56:48 +0800 Qiang Ma <maqianga at uniontech.com> wrote:
>
>> The commit a85ee18c7900 ("kexec_file: print out debugging message
>> if required") has added general code printing in kexec_file_load(),
>> but not in kexec_load().
>>
>> As a result, when using '-d' for the kexec_load interface,
>> print nothing in the kernel space.
> That doesn't sound like a thing which "kernel test robot" would detect
> and report.
>
>> Since the segments debugging message has already been printed by the
>> user-space tool kexec-tools, it will not be printed here in the
>> kernel space.
>>
>> And print out type/start/head of kimage and flags to help debug.
>>
>> Signed-off-by: Qiang Ma <maqianga at uniontech.com>
>> Reported-by: kernel test robot <lkp at intel.com>
>> Closes: https://lore.kernel.org/oe-kbuild-all/202510310332.6XrLe70K-lkp at intel.com/
> Oh I see, that's a warning against an earlier version of this patch.
> But this is labelled "v1"!
yes.
>
> I suggest we remove this Reported-by record.
ok, I'll collect some other suggestions and fix it together in the next 
version.
>> --- a/kernel/kexec.c
>> +++ b/kernel/kexec.c
>> @@ -166,6 +166,9 @@ static int do_kexec_load(unsigned long entry, unsigned long nr_segments,
>>   	if (ret)
>>   		goto out;
>>   
>> +	kexec_dprintk("kexec_load: type:%u, start:0x%lx head:0x%lx flags:0x%lx\n",
>> +		      image->type, image->start, image->head, flags);
>> +
>>   	/* Install the new kernel and uninstall the old */
>>   	image = xchg(dest_image, image);
> Thanks, I'll await reviewer input before proceeding with this series.
>



From ankur.a.arora at oracle.com  Sun Dec 14 20:49:15 2025
From: ankur.a.arora at oracle.com (Ankur Arora)
Date: Sun, 14 Dec 2025 20:49:15 -0800
Subject: [PATCH v8 08/12] locking/atomic: scripts: build atomic_long_cond_read_*_timeout()
In-Reply-To: <20251215044919.460086-1-ankur.a.arora@oracle.com>
References: <20251215044919.460086-1-ankur.a.arora@oracle.com>
Message-ID: <20251215044919.460086-9-ankur.a.arora@oracle.com>

Add the atomic long wrappers for the cond-load timeout interfaces.

Cc: Will Deacon <will at kernel.org>
Cc: Peter Zijlstra <peterz at infradead.org>
Cc: Boqun Feng <boqun.feng at gmail.com>
Signed-off-by: Ankur Arora <ankur.a.arora at oracle.com>
---
 include/linux/atomic/atomic-long.h | 18 +++++++++++-------
 scripts/atomic/gen-atomic-long.sh  | 16 ++++++++++------
 2 files changed, 21 insertions(+), 13 deletions(-)

diff --git a/include/linux/atomic/atomic-long.h b/include/linux/atomic/atomic-long.h
index f86b29d90877..e6da0189cbe6 100644
--- a/include/linux/atomic/atomic-long.h
+++ b/include/linux/atomic/atomic-long.h
@@ -11,14 +11,18 @@
 
 #ifdef CONFIG_64BIT
 typedef atomic64_t atomic_long_t;
-#define ATOMIC_LONG_INIT(i)		ATOMIC64_INIT(i)
-#define atomic_long_cond_read_acquire	atomic64_cond_read_acquire
-#define atomic_long_cond_read_relaxed	atomic64_cond_read_relaxed
+#define ATOMIC_LONG_INIT(i)			ATOMIC64_INIT(i)
+#define atomic_long_cond_read_acquire		atomic64_cond_read_acquire
+#define atomic_long_cond_read_relaxed		atomic64_cond_read_relaxed
+#define atomic_long_cond_read_acquire_timeout	atomic64_cond_read_acquire_timeout
+#define atomic_long_cond_read_relaxed_timeout	atomic64_cond_read_relaxed_timeout
 #else
 typedef atomic_t atomic_long_t;
-#define ATOMIC_LONG_INIT(i)		ATOMIC_INIT(i)
-#define atomic_long_cond_read_acquire	atomic_cond_read_acquire
-#define atomic_long_cond_read_relaxed	atomic_cond_read_relaxed
+#define ATOMIC_LONG_INIT(i)			ATOMIC_INIT(i)
+#define atomic_long_cond_read_acquire		atomic_cond_read_acquire
+#define atomic_long_cond_read_relaxed		atomic_cond_read_relaxed
+#define atomic_long_cond_read_acquire_timeout	atomic_cond_read_acquire_timeout
+#define atomic_long_cond_read_relaxed_timeout	atomic_cond_read_relaxed_timeout
 #endif
 
 /**
@@ -1809,4 +1813,4 @@ raw_atomic_long_dec_if_positive(atomic_long_t *v)
 }
 
 #endif /* _LINUX_ATOMIC_LONG_H */
-// eadf183c3600b8b92b91839dd3be6bcc560c752d
+// 475f45a880d1625faa5116dcfd6e943e4dbe1cd5
diff --git a/scripts/atomic/gen-atomic-long.sh b/scripts/atomic/gen-atomic-long.sh
index 9826be3ba986..874643dc74bd 100755
--- a/scripts/atomic/gen-atomic-long.sh
+++ b/scripts/atomic/gen-atomic-long.sh
@@ -79,14 +79,18 @@ cat << EOF
 
 #ifdef CONFIG_64BIT
 typedef atomic64_t atomic_long_t;
-#define ATOMIC_LONG_INIT(i)		ATOMIC64_INIT(i)
-#define atomic_long_cond_read_acquire	atomic64_cond_read_acquire
-#define atomic_long_cond_read_relaxed	atomic64_cond_read_relaxed
+#define ATOMIC_LONG_INIT(i)			ATOMIC64_INIT(i)
+#define atomic_long_cond_read_acquire		atomic64_cond_read_acquire
+#define atomic_long_cond_read_relaxed		atomic64_cond_read_relaxed
+#define atomic_long_cond_read_acquire_timeout	atomic64_cond_read_acquire_timeout
+#define atomic_long_cond_read_relaxed_timeout	atomic64_cond_read_relaxed_timeout
 #else
 typedef atomic_t atomic_long_t;
-#define ATOMIC_LONG_INIT(i)		ATOMIC_INIT(i)
-#define atomic_long_cond_read_acquire	atomic_cond_read_acquire
-#define atomic_long_cond_read_relaxed	atomic_cond_read_relaxed
+#define ATOMIC_LONG_INIT(i)			ATOMIC_INIT(i)
+#define atomic_long_cond_read_acquire		atomic_cond_read_acquire
+#define atomic_long_cond_read_relaxed		atomic_cond_read_relaxed
+#define atomic_long_cond_read_acquire_timeout	atomic_cond_read_acquire_timeout
+#define atomic_long_cond_read_relaxed_timeout	atomic_cond_read_relaxed_timeout
 #endif
 
 EOF
-- 
2.31.1



From ankur.a.arora at oracle.com  Sun Dec 14 20:49:13 2025
From: ankur.a.arora at oracle.com (Ankur Arora)
Date: Sun, 14 Dec 2025 20:49:13 -0800
Subject: [PATCH v8 06/12] asm-generic: barrier: Add smp_cond_load_acquire_timeout()
In-Reply-To: <20251215044919.460086-1-ankur.a.arora@oracle.com>
References: <20251215044919.460086-1-ankur.a.arora@oracle.com>
Message-ID: <20251215044919.460086-7-ankur.a.arora@oracle.com>

Add the acquire variant of smp_cond_load_relaxed_timeout(). This
reuses the relaxed variant, with additional LOAD->LOAD ordering.

Cc: Arnd Bergmann <arnd at arndb.de>
Cc: Will Deacon <will at kernel.org>
Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Peter Zijlstra <peterz at infradead.org>
Cc: linux-arch at vger.kernel.org
Reviewed-by: Catalin Marinas <catalin.marinas at arm.com>
Reviewed-by: Haris Okanovic <harisokn at amazon.com>
Tested-by: Haris Okanovic <harisokn at amazon.com>
Signed-off-by: Ankur Arora <ankur.a.arora at oracle.com>
---
 include/asm-generic/barrier.h | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/include/asm-generic/barrier.h b/include/asm-generic/barrier.h
index e25592f9fcbf..d05d34bece0d 100644
--- a/include/asm-generic/barrier.h
+++ b/include/asm-generic/barrier.h
@@ -331,6 +331,32 @@ __done:								\
 })
 #endif
 
+/**
+ * smp_cond_load_acquire_timeout() - (Spin) wait for cond with ACQUIRE ordering
+ * until a timeout expires.
+ * @ptr: pointer to the variable to wait on
+ * @cond: boolean expression to wait for
+ * @time_expr_ns: monotonic expression that evaluates to time in ns or,
+ *  on failure, returns a negative value.
+ * @timeout_ns: timeout value in ns
+ * (Both of the above are assumed to be compatible with s64.)
+ *
+ * Equivalent to using smp_cond_load_acquire() on the condition variable with
+ * a timeout.
+ */
+#ifndef smp_cond_load_acquire_timeout
+#define smp_cond_load_acquire_timeout(ptr, cond_expr,			\
+				      time_expr_ns, timeout_ns)		\
+({									\
+	__unqual_scalar_typeof(*ptr) _val;				\
+	_val = smp_cond_load_relaxed_timeout(ptr, cond_expr,		\
+					     time_expr_ns,		\
+					     timeout_ns);		\
+	smp_acquire__after_ctrl_dep();					\
+	(typeof(*ptr))_val;						\
+})
+#endif
+
 /*
  * pmem_wmb() ensures that all stores for which the modification
  * are written to persistent storage by preceding instructions have
-- 
2.31.1



From ankur.a.arora at oracle.com  Sun Dec 14 20:49:11 2025
From: ankur.a.arora at oracle.com (Ankur Arora)
Date: Sun, 14 Dec 2025 20:49:11 -0800
Subject: [PATCH v8 04/12] arm64: support WFET in smp_cond_relaxed_timeout()
In-Reply-To: <20251215044919.460086-1-ankur.a.arora@oracle.com>
References: <20251215044919.460086-1-ankur.a.arora@oracle.com>
Message-ID: <20251215044919.460086-5-ankur.a.arora@oracle.com>

Extend __cmpwait_relaxed() to __cmpwait_relaxed_timeout() which takes
an additional timeout value in ns.

Lacking WFET, or with zero or negative value of timeout we fallback
to WFE.

Cc: Arnd Bergmann <arnd at arndb.de>
Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Will Deacon <will at kernel.org>
Cc: linux-arm-kernel at lists.infradead.org
Signed-off-by: Ankur Arora <ankur.a.arora at oracle.com>
---
 arch/arm64/include/asm/barrier.h |  8 ++--
 arch/arm64/include/asm/cmpxchg.h | 72 ++++++++++++++++++++++----------
 2 files changed, 55 insertions(+), 25 deletions(-)

diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h
index 6190e178db51..fbd71cd4ef4e 100644
--- a/arch/arm64/include/asm/barrier.h
+++ b/arch/arm64/include/asm/barrier.h
@@ -224,8 +224,8 @@ do {									\
 extern bool arch_timer_evtstrm_available(void);
 
 /*
- * In the common case, cpu_poll_relax() sits waiting in __cmpwait_relaxed()
- * for the ptr value to change.
+ * In the common case, cpu_poll_relax() sits waiting in __cmpwait_relaxed()/
+ * __cmpwait_relaxed_timeout() for the ptr value to change.
  *
  * Since this period is reasonably long, choose SMP_TIMEOUT_POLL_COUNT
  * to be 1, so smp_cond_load_{relaxed,acquire}_timeout() does a
@@ -234,7 +234,9 @@ extern bool arch_timer_evtstrm_available(void);
 #define SMP_TIMEOUT_POLL_COUNT	1
 
 #define cpu_poll_relax(ptr, val, timeout_ns) do {			\
-	if (arch_timer_evtstrm_available())				\
+	if (alternative_has_cap_unlikely(ARM64_HAS_WFXT))		\
+		__cmpwait_relaxed_timeout(ptr, val, timeout_ns);	\
+	else if (arch_timer_evtstrm_available())			\
 		__cmpwait_relaxed(ptr, val);				\
 	else								\
 		cpu_relax();						\
diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h
index d7a540736741..acd01a203b62 100644
--- a/arch/arm64/include/asm/cmpxchg.h
+++ b/arch/arm64/include/asm/cmpxchg.h
@@ -12,6 +12,7 @@
 
 #include <asm/barrier.h>
 #include <asm/lse.h>
+#include <asm/delay-const.h>
 
 /*
  * We need separate acquire parameters for ll/sc and lse, since the full
@@ -208,22 +209,41 @@ __CMPXCHG_GEN(_mb)
 	__cmpxchg128((ptr), (o), (n));						\
 })
 
-#define __CMPWAIT_CASE(w, sfx, sz)					\
-static inline void __cmpwait_case_##sz(volatile void *ptr,		\
-				       unsigned long val)		\
-{									\
-	unsigned long tmp;						\
-									\
-	asm volatile(							\
-	"	sevl\n"							\
-	"	wfe\n"							\
-	"	ldxr" #sfx "\t%" #w "[tmp], %[v]\n"			\
-	"	eor	%" #w "[tmp], %" #w "[tmp], %" #w "[val]\n"	\
-	"	cbnz	%" #w "[tmp], 1f\n"				\
-	"	wfe\n"							\
-	"1:"								\
-	: [tmp] "=&r" (tmp), [v] "+Q" (*(u##sz *)ptr)			\
-	: [val] "r" (val));						\
+/* Re-declared here to avoid include dependency. */
+extern u64 (*arch_timer_read_counter)(void);
+
+#define __CMPWAIT_CASE(w, sfx, sz)						\
+static inline void __cmpwait_case_##sz(volatile void *ptr,			\
+				       unsigned long val,			\
+				       s64 timeout_ns)				\
+{										\
+	unsigned long tmp;							\
+										\
+	if (!alternative_has_cap_unlikely(ARM64_HAS_WFXT) || timeout_ns <= 0) {	\
+		asm volatile(							\
+		"	sevl\n"							\
+		"	wfe\n"							\
+		"	ldxr" #sfx "\t%" #w "[tmp], %[v]\n"			\
+		"	eor	%" #w "[tmp], %" #w "[tmp], %" #w "[val]\n"	\
+		"	cbnz	%" #w "[tmp], 1f\n"				\
+		"	wfe\n"							\
+		"1:"								\
+		: [tmp] "=&r" (tmp), [v] "+Q" (*(u##sz *)ptr)			\
+		: [val] "r" (val));						\
+	} else {								\
+		u64 ecycles = arch_timer_read_counter() +			\
+				NSECS_TO_CYCLES(timeout_ns);			\
+		asm volatile(							\
+		"	sevl\n"							\
+		"	wfe\n"							\
+		"	ldxr" #sfx "\t%" #w "[tmp], %[v]\n"			\
+		"	eor	%" #w "[tmp], %" #w "[tmp], %" #w "[val]\n"	\
+		"	cbnz	%" #w "[tmp], 2f\n"				\
+		"	msr s0_3_c1_c0_0, %[ecycles]\n"				\
+		"2:"								\
+		: [tmp] "=&r" (tmp), [v] "+Q" (*(u##sz *)ptr)			\
+		: [val] "r" (val), [ecycles] "r" (ecycles));			\
+	}									\
 }
 
 __CMPWAIT_CASE(w, b, 8);
@@ -236,17 +256,22 @@ __CMPWAIT_CASE( ,  , 64);
 #define __CMPWAIT_GEN(sfx)						\
 static __always_inline void __cmpwait##sfx(volatile void *ptr,		\
 				  unsigned long val,			\
+				  s64 timeout_ns,			\
 				  int size)				\
 {									\
 	switch (size) {							\
 	case 1:								\
-		return __cmpwait_case##sfx##_8(ptr, (u8)val);		\
+		return __cmpwait_case##sfx##_8(ptr, (u8)val,		\
+					       timeout_ns);		\
 	case 2:								\
-		return __cmpwait_case##sfx##_16(ptr, (u16)val);		\
+		return __cmpwait_case##sfx##_16(ptr, (u16)val,		\
+					       timeout_ns);		\
 	case 4:								\
-		return __cmpwait_case##sfx##_32(ptr, val);		\
+		return __cmpwait_case##sfx##_32(ptr, val,		\
+					       timeout_ns);		\
 	case 8:								\
-		return __cmpwait_case##sfx##_64(ptr, val);		\
+		return __cmpwait_case##sfx##_64(ptr, val,		\
+					       timeout_ns);		\
 	default:							\
 		BUILD_BUG();						\
 	}								\
@@ -258,7 +283,10 @@ __CMPWAIT_GEN()
 
 #undef __CMPWAIT_GEN
 
-#define __cmpwait_relaxed(ptr, val) \
-	__cmpwait((ptr), (unsigned long)(val), sizeof(*(ptr)))
+#define __cmpwait_relaxed_timeout(ptr, val, timeout_ns)			\
+	__cmpwait((ptr), (unsigned long)(val), timeout_ns, sizeof(*(ptr)))
+
+#define __cmpwait_relaxed(ptr, val)					\
+	__cmpwait_relaxed_timeout(ptr, val, 0)
 
 #endif	/* __ASM_CMPXCHG_H */
-- 
2.31.1



From ankur.a.arora at oracle.com  Sun Dec 14 20:49:08 2025
From: ankur.a.arora at oracle.com (Ankur Arora)
Date: Sun, 14 Dec 2025 20:49:08 -0800
Subject: [PATCH v8 01/12] asm-generic: barrier: Add smp_cond_load_relaxed_timeout()
In-Reply-To: <20251215044919.460086-1-ankur.a.arora@oracle.com>
References: <20251215044919.460086-1-ankur.a.arora@oracle.com>
Message-ID: <20251215044919.460086-2-ankur.a.arora@oracle.com>

Add smp_cond_load_relaxed_timeout(), which extends
smp_cond_load_relaxed() to allow waiting for a duration.

We loop around waiting for the condition variable to change while
peridically doing a time-check. The loop uses cpu_poll_relax()
to slow down the busy-waiting, which, unless overridden by the
architecture code, amounts to a cpu_relax().

Note that there are two ways for the time-check to fail: once we have
timed out or, if the time_expr_ns returns an invalid value (negative
or zero).

The number of times we spin before doing the time-check is specified
by SMP_TIMEOUT_POLL_COUNT (chosen to be 200 by default) which,
assuming each cpu_poll_relax() iteration takes ~20-30 cycles (measured
on a variety of x86 platforms), for a total of ~4000-6000 cycles.

That is also the outer limit of the overshoot when working with the
parameters above. This might be higher or lesser depending on the
implementation of cpu_poll_relax() across architectures.

Cc: Arnd Bergmann <arnd at arndb.de>
Cc: Will Deacon <will at kernel.org>
Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Peter Zijlstra <peterz at infradead.org>
Cc: linux-arch at vger.kernel.org
Signed-off-by: Ankur Arora <ankur.a.arora at oracle.com>
---

Notes:

   - the interface now breaks the time_check_expr into two parts:
     time_expr_ns (evaluates to current time) and remaining_ns. The main
     reason for doing this was to support WFET and similar primitives
     which can do timed waiting.

   - cpu_poll_relax() now takes an additional paramater to handle that.

   - time_expr_ns can now return failure which needs a little more change
     in organization. This was needed because rqspinlock check_timeout()
     logic mapped naturally to the unified check in time_check_expr.
     Breaking up the time_check_expr, however needed check_timeout() to
     separate a clock interface (which could fail on deadlock or its
     internal timeout check) and the timeout duration.

   - given the changes in logic I've removed Catalin and Haris' R-by and
     Tested-by.

 include/asm-generic/barrier.h | 58 +++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/include/asm-generic/barrier.h b/include/asm-generic/barrier.h
index d4f581c1e21d..e25592f9fcbf 100644
--- a/include/asm-generic/barrier.h
+++ b/include/asm-generic/barrier.h
@@ -273,6 +273,64 @@ do {									\
 })
 #endif
 
+/*
+ * Number of times we iterate in the loop before doing the time check.
+ */
+#ifndef SMP_TIMEOUT_POLL_COUNT
+#define SMP_TIMEOUT_POLL_COUNT		200
+#endif
+
+#ifndef cpu_poll_relax
+#define cpu_poll_relax(ptr, val, timeout_ns)	cpu_relax()
+#endif
+
+/**
+ * smp_cond_load_relaxed_timeout() - (Spin) wait for cond with no ordering
+ * guarantees until a timeout expires.
+ * @ptr: pointer to the variable to wait on
+ * @cond: boolean expression to wait for
+ * @time_expr_ns: expression that evaluates to monotonic time (in ns) or,
+ *  on failure, returns a negative value.
+ * @timeout_ns: timeout value in ns
+ * (Both of the above are assumed to be compatible with s64.)
+ *
+ * Equivalent to using READ_ONCE() on the condition variable.
+ */
+#ifndef smp_cond_load_relaxed_timeout
+#define smp_cond_load_relaxed_timeout(ptr, cond_expr,			\
+				      time_expr_ns, timeout_ns)		\
+({									\
+	__label__ __out, __done;					\
+	typeof(ptr) __PTR = (ptr);					\
+	__unqual_scalar_typeof(*ptr) VAL;				\
+	u32 __n = 0, __spin = SMP_TIMEOUT_POLL_COUNT;			\
+	s64 __time_now = (s64)(time_expr_ns);				\
+	s64 __timeout = (s64)timeout_ns;				\
+	s64 __time_end = __time_now + __timeout;			\
+									\
+	if (__time_now <= 0)						\
+		goto __out;						\
+									\
+	for (;;) {							\
+		VAL = READ_ONCE(*__PTR);				\
+		if (cond_expr)						\
+			goto __done;					\
+		cpu_poll_relax(__PTR, VAL, __timeout);			\
+		if (++__n < __spin)					\
+			continue;					\
+		__time_now = (s64)(time_expr_ns);			\
+		__timeout = __time_end - __time_now;			\
+		if (__time_now <= 0 || __timeout <= 0)			\
+			goto __out;					\
+		__n = 0;						\
+	}								\
+__out:									\
+	VAL = READ_ONCE(*__PTR);					\
+__done:								\
+	(typeof(*ptr))VAL;						\
+})
+#endif
+
 /*
  * pmem_wmb() ensures that all stores for which the modification
  * are written to persistent storage by preceding instructions have
-- 
2.31.1



From ankur.a.arora at oracle.com  Sun Dec 14 20:49:09 2025
From: ankur.a.arora at oracle.com (Ankur Arora)
Date: Sun, 14 Dec 2025 20:49:09 -0800
Subject: [PATCH v8 02/12] arm64: barrier: Support smp_cond_load_relaxed_timeout()
In-Reply-To: <20251215044919.460086-1-ankur.a.arora@oracle.com>
References: <20251215044919.460086-1-ankur.a.arora@oracle.com>
Message-ID: <20251215044919.460086-3-ankur.a.arora@oracle.com>

Support waiting in smp_cond_load_relaxed_timeout() via
__cmpwait_relaxed(). To ensure that we wake from waiting in
WFE periodically and don't block forever if there are no stores
to ptr, this path is only used when the event-stream is enabled.

Note that when using __cmpwait_relaxed() we ignore the timeout
value, allowing an overshoot by upto the event-stream period.
And, in the unlikely event that the event-stream is unavailable,
fallback to spin-waiting.

Also set SMP_TIMEOUT_POLL_COUNT to 1 so we do the time-check in
each iteration of smp_cond_load_relaxed_timeout().

Cc: Arnd Bergmann <arnd at arndb.de>
Cc: Will Deacon <will at kernel.org>
Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: linux-arm-kernel at lists.infradead.org
Suggested-by: Will Deacon <will at kernel.org>
Signed-off-by: Ankur Arora <ankur.a.arora at oracle.com>
---

Notes:
   - cpu_poll_relax() now takes an additional parameter.

   - added a comment detailing why we define SMP_TIMEOUT_POLL_COUNT=1 and
     how it ties up with smp_cond_load_relaxed_timeout().

   - explicitly include <asm/vdso/processor.h> for cpu_relax().

 arch/arm64/include/asm/barrier.h | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h
index 9495c4441a46..6190e178db51 100644
--- a/arch/arm64/include/asm/barrier.h
+++ b/arch/arm64/include/asm/barrier.h
@@ -12,6 +12,7 @@
 #include <linux/kasan-checks.h>
 
 #include <asm/alternative-macros.h>
+#include <asm/vdso/processor.h>
 
 #define __nops(n)	".rept	" #n "\nnop\n.endr\n"
 #define nops(n)		asm volatile(__nops(n))
@@ -219,6 +220,26 @@ do {									\
 	(typeof(*ptr))VAL;						\
 })
 
+/* Re-declared here to avoid include dependency. */
+extern bool arch_timer_evtstrm_available(void);
+
+/*
+ * In the common case, cpu_poll_relax() sits waiting in __cmpwait_relaxed()
+ * for the ptr value to change.
+ *
+ * Since this period is reasonably long, choose SMP_TIMEOUT_POLL_COUNT
+ * to be 1, so smp_cond_load_{relaxed,acquire}_timeout() does a
+ * time-check in each iteration.
+ */
+#define SMP_TIMEOUT_POLL_COUNT	1
+
+#define cpu_poll_relax(ptr, val, timeout_ns) do {			\
+	if (arch_timer_evtstrm_available())				\
+		__cmpwait_relaxed(ptr, val);				\
+	else								\
+		cpu_relax();						\
+} while (0)
+
 #include <asm-generic/barrier.h>
 
 #endif	/* __ASSEMBLER__ */
-- 
2.31.1



From ankur.a.arora at oracle.com  Sun Dec 14 20:49:16 2025
From: ankur.a.arora at oracle.com (Ankur Arora)
Date: Sun, 14 Dec 2025 20:49:16 -0800
Subject: [PATCH v8 09/12] bpf/rqspinlock: switch check_timeout() to a clock interface
In-Reply-To: <20251215044919.460086-1-ankur.a.arora@oracle.com>
References: <20251215044919.460086-1-ankur.a.arora@oracle.com>
Message-ID: <20251215044919.460086-10-ankur.a.arora@oracle.com>

check_timeout() gets the current time value and depending on how
much time has passed, checks for deadlock or times out, returning 0
or -errno on deadlock or timeout.

Switch this out to a clock style interface, where it functions as a
clock in the "lock-domain", returning the current time until a
deadlock or timeout occurs. Once a deadlock or timeout has occurred,
it stops functioning as a clock and returns error.

Cc: Kumar Kartikeya Dwivedi <memxor at gmail.com>
Cc: Alexei Starovoitov <ast at kernel.org>
Cc: bpf at vger.kernel.org
Signed-off-by: Ankur Arora <ankur.a.arora at oracle.com>
---
 kernel/bpf/rqspinlock.c | 41 +++++++++++++++++++++++++++--------------
 1 file changed, 27 insertions(+), 14 deletions(-)

diff --git a/kernel/bpf/rqspinlock.c b/kernel/bpf/rqspinlock.c
index f7d0c8d4644e..ac9b3572e42f 100644
--- a/kernel/bpf/rqspinlock.c
+++ b/kernel/bpf/rqspinlock.c
@@ -196,8 +196,12 @@ static noinline int check_deadlock_ABBA(rqspinlock_t *lock, u32 mask)
 	return 0;
 }
 
-static noinline int check_timeout(rqspinlock_t *lock, u32 mask,
-				  struct rqspinlock_timeout *ts)
+/*
+ * Returns current monotonic time in ns on success or, negative errno
+ * value on failure due to timeout expiration or detection of deadlock.
+ */
+static noinline s64 clock_deadlock(rqspinlock_t *lock, u32 mask,
+				   struct rqspinlock_timeout *ts)
 {
 	u64 prev = ts->cur;
 	u64 time;
@@ -207,7 +211,7 @@ static noinline int check_timeout(rqspinlock_t *lock, u32 mask,
 			return -EDEADLK;
 		ts->cur = ktime_get_mono_fast_ns();
 		ts->timeout_end = ts->cur + ts->duration;
-		return 0;
+		return (s64)ts->cur;
 	}
 
 	time = ktime_get_mono_fast_ns();
@@ -219,11 +223,15 @@ static noinline int check_timeout(rqspinlock_t *lock, u32 mask,
 	 * checks.
 	 */
 	if (prev + NSEC_PER_MSEC < time) {
+		int ret;
 		ts->cur = time;
-		return check_deadlock_ABBA(lock, mask);
+		ret = check_deadlock_ABBA(lock, mask);
+		if (ret)
+			return ret;
+
 	}
 
-	return 0;
+	return (s64)time;
 }
 
 /*
@@ -234,12 +242,12 @@ static noinline int check_timeout(rqspinlock_t *lock, u32 mask,
 #define RES_CHECK_TIMEOUT(ts, ret, mask)                              \
 	({                                                            \
 		if (!(ts).spin++)                                     \
-			(ret) = check_timeout((lock), (mask), &(ts)); \
+			(ret) = clock_deadlock((lock), (mask), &(ts));\
 		(ret);                                                \
 	})
 #else
 #define RES_CHECK_TIMEOUT(ts, ret, mask)			      \
-	({ (ret) = check_timeout((lock), (mask), &(ts)); })
+	({ (ret) = clock_deadlock((lock), (mask), &(ts)); })
 #endif
 
 /*
@@ -261,7 +269,8 @@ static noinline int check_timeout(rqspinlock_t *lock, u32 mask,
 int __lockfunc resilient_tas_spin_lock(rqspinlock_t *lock)
 {
 	struct rqspinlock_timeout ts;
-	int val, ret = 0;
+	s64 ret = 0;
+	int val;
 
 	RES_INIT_TIMEOUT(ts);
 	/*
@@ -280,7 +289,7 @@ int __lockfunc resilient_tas_spin_lock(rqspinlock_t *lock)
 	val = atomic_read(&lock->val);
 
 	if (val || !atomic_try_cmpxchg(&lock->val, &val, 1)) {
-		if (RES_CHECK_TIMEOUT(ts, ret, ~0u))
+		if (RES_CHECK_TIMEOUT(ts, ret, ~0u) < 0)
 			goto out;
 		cpu_relax();
 		goto retry;
@@ -339,6 +348,7 @@ int __lockfunc resilient_queued_spin_lock_slowpath(rqspinlock_t *lock, u32 val)
 {
 	struct mcs_spinlock *prev, *next, *node;
 	struct rqspinlock_timeout ts;
+	s64 timeout_err = 0;
 	int idx, ret = 0;
 	u32 old, tail;
 
@@ -405,10 +415,10 @@ int __lockfunc resilient_queued_spin_lock_slowpath(rqspinlock_t *lock, u32 val)
 	 */
 	if (val & _Q_LOCKED_MASK) {
 		RES_RESET_TIMEOUT(ts, RES_DEF_TIMEOUT);
-		res_smp_cond_load_acquire(&lock->locked, !VAL || RES_CHECK_TIMEOUT(ts, ret, _Q_LOCKED_MASK));
+		res_smp_cond_load_acquire(&lock->locked, !VAL || RES_CHECK_TIMEOUT(ts, timeout_err, _Q_LOCKED_MASK) < 0);
 	}
 
-	if (ret) {
+	if (timeout_err < 0) {
 		/*
 		 * We waited for the locked bit to go back to 0, as the pending
 		 * waiter, but timed out. We need to clear the pending bit since
@@ -420,6 +430,7 @@ int __lockfunc resilient_queued_spin_lock_slowpath(rqspinlock_t *lock, u32 val)
 		 */
 		clear_pending(lock);
 		lockevent_inc(rqspinlock_lock_timeout);
+		ret = timeout_err;
 		goto err_release_entry;
 	}
 
@@ -567,18 +578,19 @@ int __lockfunc resilient_queued_spin_lock_slowpath(rqspinlock_t *lock, u32 val)
 	 */
 	RES_RESET_TIMEOUT(ts, RES_DEF_TIMEOUT * 2);
 	val = res_atomic_cond_read_acquire(&lock->val, !(VAL & _Q_LOCKED_PENDING_MASK) ||
-					   RES_CHECK_TIMEOUT(ts, ret, _Q_LOCKED_PENDING_MASK));
+					   RES_CHECK_TIMEOUT(ts, timeout_err, _Q_LOCKED_PENDING_MASK) < 0);
 
 	/* Disable queue destruction when we detect deadlocks. */
-	if (ret == -EDEADLK) {
+	if (timeout_err == -EDEADLK) {
 		if (!next)
 			next = smp_cond_load_relaxed(&node->next, (VAL));
 		arch_mcs_spin_unlock_contended(&next->locked);
+		ret = timeout_err;
 		goto err_release_node;
 	}
 
 waitq_timeout:
-	if (ret) {
+	if (timeout_err < 0) {
 		/*
 		 * If the tail is still pointing to us, then we are the final waiter,
 		 * and are responsible for resetting the tail back to 0. Otherwise, if
@@ -608,6 +620,7 @@ int __lockfunc resilient_queued_spin_lock_slowpath(rqspinlock_t *lock, u32 val)
 			WRITE_ONCE(next->locked, RES_TIMEOUT_VAL);
 		}
 		lockevent_inc(rqspinlock_lock_timeout);
+		ret = timeout_err;
 		goto err_release_node;
 	}
 
-- 
2.31.1



From ankur.a.arora at oracle.com  Sun Dec 14 20:49:17 2025
From: ankur.a.arora at oracle.com (Ankur Arora)
Date: Sun, 14 Dec 2025 20:49:17 -0800
Subject: [PATCH v8 10/12] bpf/rqspinlock: Use smp_cond_load_acquire_timeout()
In-Reply-To: <20251215044919.460086-1-ankur.a.arora@oracle.com>
References: <20251215044919.460086-1-ankur.a.arora@oracle.com>
Message-ID: <20251215044919.460086-11-ankur.a.arora@oracle.com>

Switch out the conditional load interfaces used by rqspinlock
to smp_cond_read_acquire_timeout() and its wrapper,
atomic_cond_read_acquire_timeout().

Both these handle the timeout and amortize as needed, so use
clock_deadlock() directly instead of going through RES_CHECK_TIMEOUT().

For correctness, however, we need to ensure that the timeout case in
smp_cond_read_acquire_timeout() always agrees with that in
clock_deadlock(), which returns with -ETIMEDOUT.

For the most part, this is fine because smp_cond_load_acquire_timeout()
does not have an independent clock and does not do double reads from
clock_deadlock() which could cause its internal state to go out of
sync from that of clock_deadlock().

There is, however, an edge case where clock_deadlock() checks for:

        if (time > ts->timeout_end)
                return -ETIMEDOUT;

while smp_cond_load_acquire_timeout() checks for:

        __time_now = (time_expr_ns);
        if (__time_now <= 0 || __time_now >= __time_end) {
                VAL = READ_ONCE(*__PTR);
                break;
        }

This runs into a problem when (__time_now == __time_end) since
clock_deadlock() does not treat it as a timeout condition but
the second clause in the conditional above does.
So, add an equality check in clock_deadlock().

Finally, redefine SMP_TIMEOUT_POLL_COUNT to be 16k to be similar to the
spin-count used in RES_CHECK_TIMEOUT(). We only do this for non-arm64
as that uses a waiting implementation.

Cc: Kumar Kartikeya Dwivedi <memxor at gmail.com>
Cc: Alexei Starovoitov <ast at kernel.org>
Cc: bpf at vger.kernel.org
Signed-off-by: Ankur Arora <ankur.a.arora at oracle.com>
---
Notes:
  - change the check in clock_deadlock()

 kernel/bpf/rqspinlock.c | 37 ++++++++++++++++++++-----------------
 1 file changed, 20 insertions(+), 17 deletions(-)

diff --git a/kernel/bpf/rqspinlock.c b/kernel/bpf/rqspinlock.c
index ac9b3572e42f..2a361c4c7393 100644
--- a/kernel/bpf/rqspinlock.c
+++ b/kernel/bpf/rqspinlock.c
@@ -215,7 +215,7 @@ static noinline s64 clock_deadlock(rqspinlock_t *lock, u32 mask,
 	}
 
 	time = ktime_get_mono_fast_ns();
-	if (time > ts->timeout_end)
+	if (time >= ts->timeout_end)
 		return -ETIMEDOUT;
 
 	/*
@@ -235,20 +235,14 @@ static noinline s64 clock_deadlock(rqspinlock_t *lock, u32 mask,
 }
 
 /*
- * Do not amortize with spins when res_smp_cond_load_acquire is defined,
- * as the macro does internal amortization for us.
+ * Amortize timeout check for busy-wait loops.
  */
-#ifndef res_smp_cond_load_acquire
 #define RES_CHECK_TIMEOUT(ts, ret, mask)                              \
 	({                                                            \
 		if (!(ts).spin++)                                     \
 			(ret) = clock_deadlock((lock), (mask), &(ts));\
 		(ret);                                                \
 	})
-#else
-#define RES_CHECK_TIMEOUT(ts, ret, mask)			      \
-	({ (ret) = clock_deadlock((lock), (mask), &(ts)); })
-#endif
 
 /*
  * Initialize the 'spin' member.
@@ -262,6 +256,18 @@ static noinline s64 clock_deadlock(rqspinlock_t *lock, u32 mask,
  */
 #define RES_RESET_TIMEOUT(ts, _duration) ({ (ts).timeout_end = 0; (ts).duration = _duration; })
 
+/*
+ * Limit how often we invoke clock_deadlock() while spin-waiting in
+ * smp_cond_load_acquire_timeout() or atomic_cond_read_acquire_timeout().
+ *
+ * (ARM64 generally uses a waited implementation so we use the default
+ * value there.)
+ */
+#ifndef CONFIG_ARM64
+#undef SMP_TIMEOUT_POLL_COUNT
+#define SMP_TIMEOUT_POLL_COUNT	(16*1024)
+#endif
+
 /*
  * Provide a test-and-set fallback for cases when queued spin lock support is
  * absent from the architecture.
@@ -312,12 +318,6 @@ EXPORT_SYMBOL_GPL(resilient_tas_spin_lock);
  */
 static DEFINE_PER_CPU_ALIGNED(struct qnode, rqnodes[_Q_MAX_NODES]);
 
-#ifndef res_smp_cond_load_acquire
-#define res_smp_cond_load_acquire(v, c) smp_cond_load_acquire(v, c)
-#endif
-
-#define res_atomic_cond_read_acquire(v, c) res_smp_cond_load_acquire(&(v)->counter, (c))
-
 /**
  * resilient_queued_spin_lock_slowpath - acquire the queued spinlock
  * @lock: Pointer to queued spinlock structure
@@ -415,7 +415,9 @@ int __lockfunc resilient_queued_spin_lock_slowpath(rqspinlock_t *lock, u32 val)
 	 */
 	if (val & _Q_LOCKED_MASK) {
 		RES_RESET_TIMEOUT(ts, RES_DEF_TIMEOUT);
-		res_smp_cond_load_acquire(&lock->locked, !VAL || RES_CHECK_TIMEOUT(ts, timeout_err, _Q_LOCKED_MASK) < 0);
+		smp_cond_load_acquire_timeout(&lock->locked, !VAL,
+					      (timeout_err = clock_deadlock(lock, _Q_LOCKED_MASK, &ts)),
+					      ts.duration);
 	}
 
 	if (timeout_err < 0) {
@@ -577,8 +579,9 @@ int __lockfunc resilient_queued_spin_lock_slowpath(rqspinlock_t *lock, u32 val)
 	 * us.
 	 */
 	RES_RESET_TIMEOUT(ts, RES_DEF_TIMEOUT * 2);
-	val = res_atomic_cond_read_acquire(&lock->val, !(VAL & _Q_LOCKED_PENDING_MASK) ||
-					   RES_CHECK_TIMEOUT(ts, timeout_err, _Q_LOCKED_PENDING_MASK) < 0);
+	val = atomic_cond_read_acquire_timeout(&lock->val, !(VAL & _Q_LOCKED_PENDING_MASK),
+					       (timeout_err = clock_deadlock(lock, _Q_LOCKED_PENDING_MASK, &ts)),
+					       ts.duration);
 
 	/* Disable queue destruction when we detect deadlocks. */
 	if (timeout_err == -EDEADLK) {
-- 
2.31.1



From ankur.a.arora at oracle.com  Sun Dec 14 20:49:07 2025
From: ankur.a.arora at oracle.com (Ankur Arora)
Date: Sun, 14 Dec 2025 20:49:07 -0800
Subject: [PATCH v8 00/12] barrier: Add smp_cond_load_{relaxed,acquire}_timeout()
Message-ID: <20251215044919.460086-1-ankur.a.arora@oracle.com>

This series adds waited variants of the smp_cond_load() primitives:
smp_cond_load_relaxed_timeout(), and smp_cond_load_acquire_timeout().

As the name suggests, the new interfaces are meant for contexts where
you want to wait on a condition variable for a finite duration. This is
easy enough to do with a loop around cpu_relax(). There are, however,
architectures (ex. arm64) that allow waiting on a cacheline instead.

So, these interfaces handle a mixture of spin/wait with a
smp_cond_load() thrown in. The interfaces are:

   smp_cond_load_relaxed_timeout(ptr, cond_expr, time_expr, timeout)
   smp_cond_load_acquire_timeout(ptr, cond_expr, time_expr, timeout)

The parameters, time_expr, timeout determine when to bail out.

Also add tif_need_resched_relaxed_wait() which wraps the pattern used
in poll_idle() and abstracts out details of the interface and those
of the scheduler.

In addition add atomic_cond_read_*_timeout(), atomic64_cond_read_*_timeout(),
and atomic_long wrappers to the interfaces.

Finally update poll_idle() and resilient queued spinlocks to use them.

Changelog:

  v7 [0]:
   - change the interface to separately provide the timeout. This is
     useful for supporting WFET and similar primitives which can do
     timed waiting (suggested by Arnd Bergmann).

   - Adapting rqspinlock code to this changed interface also
     necessitated allowing time_expr to fail.
   - rqspinlock changes to adapt to the new smp_cond_load_acquire_timeout().

   - add WFET support (suggested by Arnd Bergmann).
   - add support for atomic-long wrappers.
   - add a new scheduler interface tif_need_resched_relaxed_wait() which
     encapsulates the polling logic used by poll_idle().
     - interface suggested by (Rafael J. Wysocki).

  v6 [1]:
   - fixup missing timeout parameters in atomic64_cond_read_*_timeout()
   - remove a race between setting of TIF_NEED_RESCHED and the call to
     smp_cond_load_relaxed_timeout(). This would mean that dev->poll_time_limit
     would be set even if we hadn't spent any time waiting.
     (The original check compared against local_clock(), which would have been
     fine, but I was instead using a cheaper check against _TIF_NEED_RESCHED.)
   (Both from meta-CI bot)

  v5 [2]:
   - use cpu_poll_relax() instead of cpu_relax().
   - instead of defining an arm64 specific
     smp_cond_load_relaxed_timeout(), just define the appropriate
     cpu_poll_relax().
   - re-read the target pointer when we exit due to the time-check.
   - s/SMP_TIMEOUT_SPIN_COUNT/SMP_TIMEOUT_POLL_COUNT/
   (Suggested by Will Deacon)

   - add atomic_cond_read_*_timeout() and atomic64_cond_read_*_timeout()
     interfaces.
   - rqspinlock: use atomic_cond_read_acquire_timeout().
   - cpuidle: use smp_cond_load_relaxed_tiemout() for polling.
   (Suggested by Catalin Marinas)

   - rqspinlock: define SMP_TIMEOUT_POLL_COUNT to be 16k for non arm64

  v4 [3]:
    - naming change 's/timewait/timeout/'
    - resilient spinlocks: get rid of res_smp_cond_load_acquire_waiting()
      and fixup use of RES_CHECK_TIMEOUT().
    (Both suggested by Catalin Marinas)

  v3 [4]:
    - further interface simplifications (suggested by Catalin Marinas)

  v2 [5]:
    - simplified the interface (suggested by Catalin Marinas)
       - get rid of wait_policy, and a multitude of constants
       - adds a slack parameter
      This helped remove a fair amount of duplicated code duplication and in
      hindsight unnecessary constants.

  v1 [6]:
     - add wait_policy (coarse and fine)
     - derive spin-count etc at runtime instead of using arbitrary
       constants.

Haris Okanovic tested v4 of this series with poll_idle()/haltpoll patches. [7]

Comments appreciated!

Thanks
Ankur

 [0] https://lore.kernel.org/lkml/20251028053136.692462-1-ankur.a.arora at oracle.com/
 [1] https://lore.kernel.org/lkml/20250911034655.3916002-1-ankur.a.arora at oracle.com/
 [2] https://lore.kernel.org/lkml/20250911034655.3916002-1-ankur.a.arora at oracle.com/
 [3] https://lore.kernel.org/lkml/20250829080735.3598416-1-ankur.a.arora at oracle.com/
 [4] https://lore.kernel.org/lkml/20250627044805.945491-1-ankur.a.arora at oracle.com/
 [5] https://lore.kernel.org/lkml/20250502085223.1316925-1-ankur.a.arora at oracle.com/
 [6] https://lore.kernel.org/lkml/20250203214911.898276-1-ankur.a.arora at oracle.com/
 [7] https://lore.kernel.org/lkml/2cecbf7fb23ee83a4ce027e1be3f46f97efd585c.camel at amazon.com/

Cc: Arnd Bergmann <arnd at arndb.de>
Cc: Will Deacon <will at kernel.org>
Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Peter Zijlstra <peterz at infradead.org>
Cc: "Rafael J. Wysocki" <rafael at kernel.org>
Cc: Daniel Lezcano <daniel.lezcano at linaro.org>
Cc: Kumar Kartikeya Dwivedi <memxor at gmail.com>
Cc: Alexei Starovoitov <ast at kernel.org>
Cc: bpf at vger.kernel.org
Cc: linux-arch at vger.kernel.org
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-pm at vger.kernel.org

Ankur Arora (12):
  asm-generic: barrier: Add smp_cond_load_relaxed_timeout()
  arm64: barrier: Support smp_cond_load_relaxed_timeout()
  arm64/delay: move some constants out to a separate header
  arm64: support WFET in smp_cond_relaxed_timeout()
  arm64: rqspinlock: Remove private copy of
    smp_cond_load_acquire_timewait()
  asm-generic: barrier: Add smp_cond_load_acquire_timeout()
  atomic: Add atomic_cond_read_*_timeout()
  locking/atomic: scripts: build atomic_long_cond_read_*_timeout()
  bpf/rqspinlock: switch check_timeout() to a clock interface
  bpf/rqspinlock: Use smp_cond_load_acquire_timeout()
  sched: add need-resched timed wait interface
  cpuidle/poll_state: Wait for need-resched via
    tif_need_resched_relaxed_wait()

 arch/arm64/include/asm/barrier.h     | 23 ++++++++
 arch/arm64/include/asm/cmpxchg.h     | 72 ++++++++++++++++-------
 arch/arm64/include/asm/delay-const.h | 25 ++++++++
 arch/arm64/include/asm/rqspinlock.h  | 85 ----------------------------
 arch/arm64/lib/delay.c               | 13 +----
 drivers/cpuidle/poll_state.c         | 27 ++-------
 drivers/soc/qcom/rpmh-rsc.c          |  9 +--
 include/asm-generic/barrier.h        | 84 +++++++++++++++++++++++++++
 include/linux/atomic.h               | 10 ++++
 include/linux/atomic/atomic-long.h   | 18 +++---
 include/linux/sched/idle.h           | 29 ++++++++++
 kernel/bpf/rqspinlock.c              | 72 ++++++++++++++---------
 scripts/atomic/gen-atomic-long.sh    | 16 ++++--
 13 files changed, 295 insertions(+), 188 deletions(-)
 create mode 100644 arch/arm64/include/asm/delay-const.h

-- 
2.31.1



From ankur.a.arora at oracle.com  Sun Dec 14 20:49:14 2025
From: ankur.a.arora at oracle.com (Ankur Arora)
Date: Sun, 14 Dec 2025 20:49:14 -0800
Subject: [PATCH v8 07/12] atomic: Add atomic_cond_read_*_timeout()
In-Reply-To: <20251215044919.460086-1-ankur.a.arora@oracle.com>
References: <20251215044919.460086-1-ankur.a.arora@oracle.com>
Message-ID: <20251215044919.460086-8-ankur.a.arora@oracle.com>

Add atomic load wrappers, atomic_cond_read_*_timeout() and
atomic64_cond_read_*_timeout() for the cond-load timeout interfaces.

Cc: Will Deacon <will at kernel.org>
Cc: Peter Zijlstra <peterz at infradead.org>
Cc: Boqun Feng <boqun.feng at gmail.com>
Signed-off-by: Ankur Arora <ankur.a.arora at oracle.com>
---
 include/linux/atomic.h | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/include/linux/atomic.h b/include/linux/atomic.h
index 8dd57c3a99e9..5bcb86e07784 100644
--- a/include/linux/atomic.h
+++ b/include/linux/atomic.h
@@ -31,6 +31,16 @@
 #define atomic64_cond_read_acquire(v, c) smp_cond_load_acquire(&(v)->counter, (c))
 #define atomic64_cond_read_relaxed(v, c) smp_cond_load_relaxed(&(v)->counter, (c))
 
+#define atomic_cond_read_acquire_timeout(v, c, e, t) \
+	smp_cond_load_acquire_timeout(&(v)->counter, (c), (e), (t))
+#define atomic_cond_read_relaxed_timeout(v, c, e, t) \
+	smp_cond_load_relaxed_timeout(&(v)->counter, (c), (e), (t))
+
+#define atomic64_cond_read_acquire_timeout(v, c, e, t) \
+	smp_cond_load_acquire_timeout(&(v)->counter, (c), (e), (t))
+#define atomic64_cond_read_relaxed_timeout(v, c, e, t) \
+	smp_cond_load_relaxed_timeout(&(v)->counter, (c), (e), (t))
+
 /*
  * The idea here is to build acquire/release variants by adding explicit
  * barriers on top of the relaxed variant. In the case where the relaxed
-- 
2.31.1



From ankur.a.arora at oracle.com  Sun Dec 14 20:49:12 2025
From: ankur.a.arora at oracle.com (Ankur Arora)
Date: Sun, 14 Dec 2025 20:49:12 -0800
Subject: [PATCH v8 05/12] arm64: rqspinlock: Remove private copy of smp_cond_load_acquire_timewait()
In-Reply-To: <20251215044919.460086-1-ankur.a.arora@oracle.com>
References: <20251215044919.460086-1-ankur.a.arora@oracle.com>
Message-ID: <20251215044919.460086-6-ankur.a.arora@oracle.com>

In preparation for defining smp_cond_load_acquire_timeout(), remove
the private copy. Lacking this, the rqspinlock code falls back to using
smp_cond_load_acquire().

Cc: Kumar Kartikeya Dwivedi <memxor at gmail.com>
Cc: Alexei Starovoitov <ast at kernel.org>
Cc: bpf at vger.kernel.org
Reviewed-by: Catalin Marinas <catalin.marinas at arm.com>
Reviewed-by: Haris Okanovic <harisokn at amazon.com>
Signed-off-by: Ankur Arora <ankur.a.arora at oracle.com>
---
 arch/arm64/include/asm/rqspinlock.h | 85 -----------------------------
 1 file changed, 85 deletions(-)

diff --git a/arch/arm64/include/asm/rqspinlock.h b/arch/arm64/include/asm/rqspinlock.h
index 9ea0a74e5892..a385603436e9 100644
--- a/arch/arm64/include/asm/rqspinlock.h
+++ b/arch/arm64/include/asm/rqspinlock.h
@@ -3,91 +3,6 @@
 #define _ASM_RQSPINLOCK_H
 
 #include <asm/barrier.h>
-
-/*
- * Hardcode res_smp_cond_load_acquire implementations for arm64 to a custom
- * version based on [0]. In rqspinlock code, our conditional expression involves
- * checking the value _and_ additionally a timeout. However, on arm64, the
- * WFE-based implementation may never spin again if no stores occur to the
- * locked byte in the lock word. As such, we may be stuck forever if
- * event-stream based unblocking is not available on the platform for WFE spin
- * loops (arch_timer_evtstrm_available).
- *
- * Once support for smp_cond_load_acquire_timewait [0] lands, we can drop this
- * copy-paste.
- *
- * While we rely on the implementation to amortize the cost of sampling
- * cond_expr for us, it will not happen when event stream support is
- * unavailable, time_expr check is amortized. This is not the common case, and
- * it would be difficult to fit our logic in the time_expr_ns >= time_limit_ns
- * comparison, hence just let it be. In case of event-stream, the loop is woken
- * up at microsecond granularity.
- *
- * [0]: https://lore.kernel.org/lkml/20250203214911.898276-1-ankur.a.arora at oracle.com
- */
-
-#ifndef smp_cond_load_acquire_timewait
-
-#define smp_cond_time_check_count	200
-
-#define __smp_cond_load_relaxed_spinwait(ptr, cond_expr, time_expr_ns,	\
-					 time_limit_ns) ({		\
-	typeof(ptr) __PTR = (ptr);					\
-	__unqual_scalar_typeof(*ptr) VAL;				\
-	unsigned int __count = 0;					\
-	for (;;) {							\
-		VAL = READ_ONCE(*__PTR);				\
-		if (cond_expr)						\
-			break;						\
-		cpu_relax();						\
-		if (__count++ < smp_cond_time_check_count)		\
-			continue;					\
-		if ((time_expr_ns) >= (time_limit_ns))			\
-			break;						\
-		__count = 0;						\
-	}								\
-	(typeof(*ptr))VAL;						\
-})
-
-#define __smp_cond_load_acquire_timewait(ptr, cond_expr,		\
-					 time_expr_ns, time_limit_ns)	\
-({									\
-	typeof(ptr) __PTR = (ptr);					\
-	__unqual_scalar_typeof(*ptr) VAL;				\
-	for (;;) {							\
-		VAL = smp_load_acquire(__PTR);				\
-		if (cond_expr)						\
-			break;						\
-		__cmpwait_relaxed(__PTR, VAL);				\
-		if ((time_expr_ns) >= (time_limit_ns))			\
-			break;						\
-	}								\
-	(typeof(*ptr))VAL;						\
-})
-
-#define smp_cond_load_acquire_timewait(ptr, cond_expr,			\
-				      time_expr_ns, time_limit_ns)	\
-({									\
-	__unqual_scalar_typeof(*ptr) _val;				\
-	int __wfe = arch_timer_evtstrm_available();			\
-									\
-	if (likely(__wfe)) {						\
-		_val = __smp_cond_load_acquire_timewait(ptr, cond_expr,	\
-							time_expr_ns,	\
-							time_limit_ns);	\
-	} else {							\
-		_val = __smp_cond_load_relaxed_spinwait(ptr, cond_expr,	\
-							time_expr_ns,	\
-							time_limit_ns);	\
-		smp_acquire__after_ctrl_dep();				\
-	}								\
-	(typeof(*ptr))_val;						\
-})
-
-#endif
-
-#define res_smp_cond_load_acquire(v, c) smp_cond_load_acquire_timewait(v, c, 0, 1)
-
 #include <asm-generic/rqspinlock.h>
 
 #endif /* _ASM_RQSPINLOCK_H */
-- 
2.31.1



From ankur.a.arora at oracle.com  Sun Dec 14 20:49:10 2025
From: ankur.a.arora at oracle.com (Ankur Arora)
Date: Sun, 14 Dec 2025 20:49:10 -0800
Subject: [PATCH v8 03/12] arm64/delay: move some constants out to a separate header
In-Reply-To: <20251215044919.460086-1-ankur.a.arora@oracle.com>
References: <20251215044919.460086-1-ankur.a.arora@oracle.com>
Message-ID: <20251215044919.460086-4-ankur.a.arora@oracle.com>

Moves some constants and functions related to xloops, cycles computation
out to a new header.

No functional change.

Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Will Deacon <will at kernel.org>
Cc: Bjorn Andersson <andersson at kernel.org>
Cc: Konrad Dybcio <konradybcio at kernel.org>
Cc: linux-arm-kernel at lists.infradead.org
Signed-off-by: Ankur Arora <ankur.a.arora at oracle.com>
Reviewed-by: Christoph Lameter <cl at linux.com>
---
 arch/arm64/include/asm/delay-const.h | 25 +++++++++++++++++++++++++
 arch/arm64/lib/delay.c               | 13 +++----------
 drivers/soc/qcom/rpmh-rsc.c          |  9 +--------
 3 files changed, 29 insertions(+), 18 deletions(-)
 create mode 100644 arch/arm64/include/asm/delay-const.h

diff --git a/arch/arm64/include/asm/delay-const.h b/arch/arm64/include/asm/delay-const.h
new file mode 100644
index 000000000000..63fb5fc24a90
--- /dev/null
+++ b/arch/arm64/include/asm/delay-const.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _ASM_DELAY_CONST_H
+#define _ASM_DELAY_CONST_H
+
+#include <asm/param.h>	/* For HZ */
+
+/* 2**32 / 1000000 (rounded up) */
+#define __usecs_to_xloops_mult	0x10C7UL
+
+/* 2**32 / 1000000000 (rounded up) */
+#define __nsecs_to_xloops_mult	0x5UL
+
+extern unsigned long loops_per_jiffy;
+static inline unsigned long xloops_to_cycles(unsigned long xloops)
+{
+	return (xloops * loops_per_jiffy * HZ) >> 32;
+}
+
+#define USECS_TO_CYCLES(time_usecs) \
+	xloops_to_cycles((time_usecs) * __usecs_to_xloops_mult)
+
+#define NSECS_TO_CYCLES(time_nsecs) \
+	xloops_to_cycles((time_nsecs) * __nsecs_to_xloops_mult)
+
+#endif	/* _ASM_DELAY_CONST_H */
diff --git a/arch/arm64/lib/delay.c b/arch/arm64/lib/delay.c
index cb2062e7e234..511b5597e2a5 100644
--- a/arch/arm64/lib/delay.c
+++ b/arch/arm64/lib/delay.c
@@ -12,17 +12,10 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/timex.h>
+#include <asm/delay-const.h>
 
 #include <clocksource/arm_arch_timer.h>
 
-#define USECS_TO_CYCLES(time_usecs)			\
-	xloops_to_cycles((time_usecs) * 0x10C7UL)
-
-static inline unsigned long xloops_to_cycles(unsigned long xloops)
-{
-	return (xloops * loops_per_jiffy * HZ) >> 32;
-}
-
 void __delay(unsigned long cycles)
 {
 	cycles_t start = get_cycles();
@@ -58,12 +51,12 @@ EXPORT_SYMBOL(__const_udelay);
 
 void __udelay(unsigned long usecs)
 {
-	__const_udelay(usecs * 0x10C7UL); /* 2**32 / 1000000 (rounded up) */
+	__const_udelay(usecs * __usecs_to_xloops_mult);
 }
 EXPORT_SYMBOL(__udelay);
 
 void __ndelay(unsigned long nsecs)
 {
-	__const_udelay(nsecs * 0x5UL); /* 2**32 / 1000000000 (rounded up) */
+	__const_udelay(nsecs * __nsecs_to_xloops_mult);
 }
 EXPORT_SYMBOL(__ndelay);
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index c6f7d5c9c493..95962fc37295 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -26,6 +26,7 @@
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/wait.h>
+#include <asm/delay-const.h>
 
 #include <clocksource/arm_arch_timer.h>
 #include <soc/qcom/cmd-db.h>
@@ -146,14 +147,6 @@ enum {
  *  +---------------------------------------------------+
  */
 
-#define USECS_TO_CYCLES(time_usecs)			\
-	xloops_to_cycles((time_usecs) * 0x10C7UL)
-
-static inline unsigned long xloops_to_cycles(u64 xloops)
-{
-	return (xloops * loops_per_jiffy * HZ) >> 32;
-}
-
 static u32 rpmh_rsc_reg_offset_ver_2_7[] = {
 	[RSC_DRV_TCS_OFFSET]		= 672,
 	[RSC_DRV_CMD_OFFSET]		= 20,
-- 
2.31.1



From ankur.a.arora at oracle.com  Sun Dec 14 20:49:18 2025
From: ankur.a.arora at oracle.com (Ankur Arora)
Date: Sun, 14 Dec 2025 20:49:18 -0800
Subject: [PATCH v8 11/12] sched: add need-resched timed wait interface
In-Reply-To: <20251215044919.460086-1-ankur.a.arora@oracle.com>
References: <20251215044919.460086-1-ankur.a.arora@oracle.com>
Message-ID: <20251215044919.460086-12-ankur.a.arora@oracle.com>

Add tif_bitset_relaxed_wait() (and tif_need_resched_relaxed_wait()
which wraps it) which takes the thread_info bit and timeout duration
as parameters and waits until the bit is set or for the expiration
of the timeout.

The wait is implemented via smp_cond_load_relaxed_timeout().

smp_cond_load_acquire_timeout() essentially provides the pattern used
in poll_idle() where we spin in a loop waiting for the flag to change
until a timeout occurs.

tif_need_resched_relaxed_wait() allows us to abstract out the internals
of waiting, scheduler specific details etc.

Placed in linux/sched/idle.h instead of linux/thread_info.h to work
around recursive include hell.

Cc: Ingo Molnar <mingo at kernel.org>
Cc: Peter Zijlstra <peterz at infradead.org>
Cc: "Rafael J. Wysocki" <rafael at kernel.org>
Cc: Daniel Lezcano <daniel.lezcano at linaro.org>
Cc: linux-pm at vger.kernel.org
Signed-off-by: Ankur Arora <ankur.a.arora at oracle.com>
---
 include/linux/sched/idle.h | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/include/linux/sched/idle.h b/include/linux/sched/idle.h
index 8465ff1f20d1..6780ad760abb 100644
--- a/include/linux/sched/idle.h
+++ b/include/linux/sched/idle.h
@@ -3,6 +3,7 @@
 #define _LINUX_SCHED_IDLE_H
 
 #include <linux/sched.h>
+#include <linux/sched/clock.h>
 
 enum cpu_idle_type {
 	__CPU_NOT_IDLE = 0,
@@ -113,4 +114,32 @@ static __always_inline void current_clr_polling(void)
 }
 #endif
 
+/*
+ * Caller needs to make sure that the thread context cannot be preempted
+ * or migrated, so current_thread_info() cannot change from under us.
+ *
+ * This also allows us to safely stay in the local_clock domain.
+ */
+static inline bool tif_bitset_relaxed_wait(int bit, s64 timeout_ns)
+{
+	unsigned int flags;
+
+	flags = smp_cond_load_relaxed_timeout(&current_thread_info()->flags,
+					      (VAL & bit),
+					      (s64)local_clock_noinstr(),
+					      timeout_ns);
+	return flags & bit;
+}
+
+/**
+ * tif_need_resched_relaxed_wait() - Wait for need-resched being set with
+ * no ordering guarantees until a timeout expires.
+ *
+ * @timeout_ns: timeout value.
+ */
+static inline bool tif_need_resched_relaxed_wait(s64 timeout_ns)
+{
+	return tif_bitset_relaxed_wait(TIF_NEED_RESCHED, timeout_ns);
+}
+
 #endif /* _LINUX_SCHED_IDLE_H */
-- 
2.31.1



From ankur.a.arora at oracle.com  Sun Dec 14 20:49:19 2025
From: ankur.a.arora at oracle.com (Ankur Arora)
Date: Sun, 14 Dec 2025 20:49:19 -0800
Subject: [PATCH v8 12/12] cpuidle/poll_state: Wait for need-resched via tif_need_resched_relaxed_wait()
In-Reply-To: <20251215044919.460086-1-ankur.a.arora@oracle.com>
References: <20251215044919.460086-1-ankur.a.arora@oracle.com>
Message-ID: <20251215044919.460086-13-ankur.a.arora@oracle.com>

The inner loop in poll_idle() polls over the thread_info flags,
waiting to see if the thread has TIF_NEED_RESCHED set. The loop
exits once the condition is met, or if the poll time limit has
been exceeded.

To minimize the number of instructions executed in each iteration,
the time check is rate-limited. In addition, each loop iteration
executes cpu_relax() which on certain platforms provides a hint to
the pipeline that the loop busy-waits, allowing the processor to
reduce power consumption.

Switch over to tif_need_resched_relaxed_wait() instead, since that
provides exactly that.

However, given that when running in idle we want to minimize our power
consumption, continue to depend on CONFIG_ARCH_HAS_CPU_RELAX as that
serves as an indicator that the platform supports an optimized version
of tif_need_resched_relaxed_wait() (via
smp_cond_load_acquire_timeout()).

Cc: "Rafael J. Wysocki" <rafael at kernel.org>
Cc: Daniel Lezcano <daniel.lezcano at linaro.org>
Cc: linux-pm at vger.kernel.org
Suggested-by: "Rafael J. Wysocki" <rafael at kernel.org>
Signed-off-by: Ankur Arora <ankur.a.arora at oracle.com>
---

Notes:
  - use tif_need_resched_relaxed_wait() instead of
    smp_cond_load_relaxed_timeout()

 drivers/cpuidle/poll_state.c | 27 +++++----------------------
 1 file changed, 5 insertions(+), 22 deletions(-)

diff --git a/drivers/cpuidle/poll_state.c b/drivers/cpuidle/poll_state.c
index c7524e4c522a..20136b3a08c2 100644
--- a/drivers/cpuidle/poll_state.c
+++ b/drivers/cpuidle/poll_state.c
@@ -6,41 +6,24 @@
 #include <linux/cpuidle.h>
 #include <linux/export.h>
 #include <linux/irqflags.h>
-#include <linux/sched.h>
-#include <linux/sched/clock.h>
 #include <linux/sched/idle.h>
 #include <linux/sprintf.h>
 #include <linux/types.h>
 
-#define POLL_IDLE_RELAX_COUNT	200
-
 static int __cpuidle poll_idle(struct cpuidle_device *dev,
 			       struct cpuidle_driver *drv, int index)
 {
-	u64 time_start;
-
-	time_start = local_clock_noinstr();
-
 	dev->poll_time_limit = false;
 
 	raw_local_irq_enable();
 	if (!current_set_polling_and_test()) {
-		unsigned int loop_count = 0;
-		u64 limit;
+		s64 limit;
+		bool nr_set;
 
-		limit = cpuidle_poll_time(drv, dev);
+		limit = (s64)cpuidle_poll_time(drv, dev);
 
-		while (!need_resched()) {
-			cpu_relax();
-			if (loop_count++ < POLL_IDLE_RELAX_COUNT)
-				continue;
-
-			loop_count = 0;
-			if (local_clock_noinstr() - time_start > limit) {
-				dev->poll_time_limit = true;
-				break;
-			}
-		}
+		nr_set = tif_need_resched_relaxed_wait(limit);
+		dev->poll_time_limit = !nr_set;
 	}
 	raw_local_irq_disable();
 
-- 
2.31.1



From bot+bpf-ci at kernel.org  Sun Dec 14 21:14:26 2025
From: bot+bpf-ci at kernel.org (bot+bpf-ci at kernel.org)
Date: Mon, 15 Dec 2025 05:14:26 +0000 (UTC)
Subject: [PATCH v8 05/12] arm64: rqspinlock: Remove private copy of smp_cond_load_acquire_timewait()
In-Reply-To: <20251215044919.460086-6-ankur.a.arora@oracle.com>
References: <20251215044919.460086-6-ankur.a.arora@oracle.com>
Message-ID: <5dfe5e4c186bcc18bf8fb935b4ba81c7e0a2ce3c13a49fe91aac51b07975a1a4@mail.kernel.org>

> diff --git a/arch/arm64/include/asm/rqspinlock.h b/arch/arm64/include/asm/rqspinlock.h
> index 9ea0a74e5892..a385603436e9 100644
> --- a/arch/arm64/include/asm/rqspinlock.h
> +++ b/arch/arm64/include/asm/rqspinlock.h
> @@ -3,91 +3,6 @@
>  #define _ASM_RQSPINLOCK_H
>
>  #include <asm/barrier.h>
> -
> -/*
> - * Hardcode res_smp_cond_load_acquire implementations for arm64 to a custom
> - * version based on [0]. In rqspinlock code, our conditional expression involves
> - * checking the value _and_ additionally a timeout. However, on arm64, the
> - * WFE-based implementation may never spin again if no stores occur to the
> - * locked byte in the lock word. As such, we may be stuck forever if
> - * event-stream based unblocking is not available on the platform for WFE spin
> - * loops (arch_timer_evtstrm_available).
                                               ^^^^

Can lock acquisition hang indefinitely on platforms without event-stream
support? The deleted implementation provided special handling for the
arch_timer_evtstrm_available() == false case using
__smp_cond_load_relaxed_spinwait(), which checked the timeout condition
every 200 iterations via cpu_relax().

After this removal, resilient_queued_spin_lock_slowpath() at line 408
calls:

    res_smp_cond_load_acquire(&lock->locked,
                              !VAL || RES_CHECK_TIMEOUT(ts, ret, _Q_LOCKED_MASK));

This now falls back to the generic smp_cond_load_acquire() (defined in
kernel/bpf/rqspinlock.c:307), which uses __cmpwait_relaxed(). On
platforms without event-stream, __cmpwait_relaxed() becomes just
cpu_relax() (a yield instruction), and the WFE instruction may never wake
up if no stores occur to the lock word.

Even if WFE does wake up periodically, the RES_CHECK_TIMEOUT macro is
defined with amortization (checking timeout every ~256 iterations when
!(ts.spin++) wraps), which may be too sparse compared to the deleted
implementation's explicit check every 200 iterations.

This means the timeout and deadlock detection logic may not function
correctly, potentially causing lock acquisition to hang instead of
returning -ETIMEDOUT or -EDEADLK after the intended 250ms timeout
(RES_DEF_TIMEOUT).

Note: The next commit in the series (f150b57ec7c8 "bpf/rqspinlock: Use
smp_cond_load_acquire_timeout()") switches to proper timeout-aware
primitives, which resolves this issue.

> - *
> - * Once support for smp_cond_load_acquire_timewait [0] lands, we can drop this
> - * copy-paste.

[ ... ]

> -#define res_smp_cond_load_acquire(v, c) smp_cond_load_acquire_timewait(v, c, 0, 1)
> -
>  #include <asm-generic/rqspinlock.h>
>
>  #endif /* _ASM_RQSPINLOCK_H */


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/20221060323

From amhetre at nvidia.com  Sun Dec 14 22:09:08 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Mon, 15 Dec 2025 11:39:08 +0530
Subject: [PATCH V6 1/4] iommu/tegra241-cmdqv: Decouple driver from ACPI
In-Reply-To: <104441bd-1284-4147-873a-f94c91788609@arm.com>
References: <20251212060803.1712637-1-amhetre@nvidia.com>
 <20251212060803.1712637-2-amhetre@nvidia.com>
 <54fce1f8-7675-4351-b292-0009b2e8c599@arm.com> <aTxxBdcY4hODXcdu@nvidia.com>
 <104441bd-1284-4147-873a-f94c91788609@arm.com>
Message-ID: <d4e942de-296c-409b-915a-cb7ad23c53e0@nvidia.com>


On 12/13/2025 2:06 AM, Robin Murphy wrote:
> External email: Use caution opening links or attachments
>
>
> On 12/12/2025 7:46 pm, Nicolin Chen wrote:
>> On Fri, Dec 12, 2025 at 12:01:41PM +0000, Robin Murphy wrote:
>>>> @@ -4542,7 +4542,7 @@ static void 
>>>> acpi_smmu_dsdt_probe_tegra241_cmdqv(struct acpi_iort_node *node,
>>>> ??? adev = acpi_dev_get_first_match_dev("NVDA200C", uid, -1);
>>>> ??? if (adev) {
>>>> ??????????? /* Tegra241 CMDQV driver is responsible for 
>>>> put_device() */
>>>
>>> Don't we need to bring the put_device(adev) out to this level, since
>>> impl_dev is now something else that AFAICS we are *not* taking a new
>>> reference on (and thus should not be putting either)?
>>
>> Ah, right! We are using the platform device now.
>>
>>>> -?????????? smmu->impl_dev = &adev->dev;
>>>> +?????????? smmu->impl_dev = acpi_get_first_physical_node(adev);
>>>> ??????????? smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
>>>> ??????????? dev_info(smmu->dev, "found companion CMDQV device: %s\n",
>>>> ???????????????????? dev_name(smmu->impl_dev));
>>
>> I think we should squash this:
>
> Ack, it occurred to me shortly after sending that in fact it's good to
> still hold our own reference on impl_dev itself, as we're not relying on
> a bound driver to hold one for us.
>
> Cheers,
> Robin.
>

Ack, thanks Nic and Robin. I will include this and send
new version.

>> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c 
>> b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> index 0c98be3135c63..88625e3c27a65 100644
>> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> @@ -5280,10 +5280,11 @@ static void 
>> acpi_smmu_dsdt_probe_tegra241_cmdqv(struct acpi_iort_node *node,
>> ????? adev = acpi_dev_get_first_match_dev("NVDA200C", uid, -1);
>> ????? if (adev) {
>> ????????????? /* Tegra241 CMDQV driver is responsible for 
>> put_device() */
>> -???????????? smmu->impl_dev = acpi_get_first_physical_node(adev);
>> +???????????? smmu->impl_dev = 
>> get_device(acpi_get_first_physical_node(adev));
>> ????????????? smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
>> ????????????? dev_info(smmu->dev, "found companion CMDQV device: %s\n",
>> ?????????????????????? dev_name(smmu->impl_dev));
>> +???????????? acpi_dev_put(adev);
>> ????? }
>> ????? kfree(uid);
>> ? }
>>
>> Thanks
>> Nicolin
>


From anshuld at ti.com  Sun Dec 14 22:08:58 2025
From: anshuld at ti.com (Anshul Dalal)
Date: Mon, 15 Dec 2025 11:38:58 +0530
Subject: [PATCH v5] dt-bindings: arm: keystone: add boot_* mboxes to ti,sci
Message-ID: <20251215-k3_syscon_add_boot_mailboxes-v5-1-5a8fe567fd31@ti.com>

The bootloader on K3 devices makes use of mailboxes as per the ROM spec
which might be different than one's available to the kernel (firmware
spec).

Therefore, this patch adds the missing mailbox entries to the DT binding
if the matching compatible is ti,am654-sci to represent the mailboxes
exposed by the hardware during boot for the purpose of loading the
firmware. The newly added mboxes are made optional by keeping minItems
as 2 to remain compliant with existing device-trees.

Signed-off-by: Anshul Dalal <anshuld at ti.com>
---
Changes in v5:
- Added commit description for the optional mailboxes
- Link to v4: https://lore.kernel.org/r/20251205-k3_syscon_add_boot_mailboxes-v4-1-8e216fb88941 at ti.com

Changes in v4:
- Make new boot_* mboxes conditional on ti,am654-sci compatible
- Link to v3: https://lore.kernel.org/r/20251112-k3_syscon_add_boot_mailboxes-v3-1-66155a4236dc at ti.com

Changes in v3:
- Drop [1/2] of the last patch series
- Update existing example with boot_* mailboxes instead of adding a new one
- Link to v2: https://lore.kernel.org/r/20251112-k3_syscon_add_boot_mailboxes-v2-0-aebc1e47b391 at ti.com

Changes in v2:
- Remove maxItems entry
- Remove RFC tag from patch (added by mistake in v1)
- Document the new mailboxes in mboxes instead of mbox-names
- Provide example with all the mailboxes set
- Update commit title to have "ti,sci"
- Split into two patches
- Link to v1: https://lore.kernel.org/r/20251111-k3_syscon_add_boot_mailboxes-v1-1-529a27f21076 at ti.com
---
 .../devicetree/bindings/arm/keystone/ti,sci.yaml   | 50 +++++++++++++++++++---
 1 file changed, 43 insertions(+), 7 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
index 25a2b42105e5..d9eb2a81e539 100644
--- a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
+++ b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
@@ -51,15 +51,15 @@ properties:
     minItems: 1
 
   mbox-names:
+    minItems: 2
+    maxItems: 6
     description: |
       Specifies the mailboxes used to communicate with TI-SCI Controller
       made available from TI-SCI controller.
-    items:
-      - const: rx
-      - const: tx
 
   mboxes:
     minItems: 2
+    maxItems: 6
 
   ti,host-id:
     $ref: /schemas/types.yaml#/definitions/uint32
@@ -79,6 +79,42 @@ properties:
     type: object
     $ref: /schemas/reset/ti,sci-reset.yaml#
 
+if:
+  properties:
+    compatible:
+      contains:
+        const: ti,am654-sci
+then:
+  properties:
+    mbox-names:
+      minItems: 2
+      items:
+        - const: rx
+        - const: tx
+        - const: notify
+        - const: boot_rx
+        - const: boot_tx
+        - const: boot_notify
+    mboxes:
+      minItems: 2
+      items:
+        - description: RX thread
+        - description: TX thread
+        - description: Notify thread
+        - description: boot stage RX thread
+        - description: boot stage TX thread
+        - description: boot stage Notify thread
+else:
+  properties:
+    mbox-names:
+      items:
+        - const: rx
+        - const: tx
+    mboxes:
+      items:
+        - description: RX thread
+        - description: TX thread
+
 required:
   - compatible
   - mbox-names
@@ -99,11 +135,11 @@ examples:
 
   - |
     dmsc: system-controller at 44083000 {
-      compatible = "ti,k2g-sci";
+      compatible = "ti,am654-sci";
       ti,host-id = <12>;
-      mbox-names = "rx", "tx";
-      mboxes = <&secure_proxy_main 11>,
-               <&secure_proxy_main 13>;
+      mbox-names = "rx", "tx", "notify", "boot_rx", "boot_tx";
+      mboxes= <&secure_proxy_mcu 6>, <&secure_proxy_mcu 8>,
+        <&secure_proxy_mcu 5>, <&secure_proxy_mcu 5>, <&secure_proxy_mcu 4>;
       reg-names = "debug_messages";
       reg = <0x44083000 0x1000>;
 

---
base-commit: 4427259cc7f7571a157fbc9b5011e1ef6fe0a4a8
change-id: 20251105-k3_syscon_add_boot_mailboxes-8452bdd98962

Best regards,
-- 
Anshul Dalal <anshuld at ti.com>



From amhetre at nvidia.com  Sun Dec 14 22:48:16 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Mon, 15 Dec 2025 06:48:16 +0000
Subject: [PATCH V7 1/4] iommu/tegra241-cmdqv: Decouple driver from ACPI
In-Reply-To: <20251215064819.3345361-1-amhetre@nvidia.com>
References: <20251215064819.3345361-1-amhetre@nvidia.com>
Message-ID: <20251215064819.3345361-2-amhetre@nvidia.com>

From: Nicolin Chen <nicolinc at nvidia.com>

A platform device is created by acpi_create_platform_device() per CMDQV's
adev. That means there is no point in going through _CRS of ACPI.

Replace all the ACPI functions with standard platform functions. And drop
all ACPI dependencies. This will make the driver compatible with DT also.

Suggested-by: Robin Murphy <robin.murphy at arm.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/Kconfig                     |  1 -
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   |  3 +-
 .../iommu/arm/arm-smmu-v3/tegra241-cmdqv.c    | 84 +++----------------
 3 files changed, 14 insertions(+), 74 deletions(-)

diff --git a/drivers/iommu/arm/Kconfig b/drivers/iommu/arm/Kconfig
index ef42bbe07dbe..5fac08b89dee 100644
--- a/drivers/iommu/arm/Kconfig
+++ b/drivers/iommu/arm/Kconfig
@@ -121,7 +121,6 @@ config ARM_SMMU_V3_KUNIT_TEST
 
 config TEGRA241_CMDQV
 	bool "NVIDIA Tegra241 CMDQ-V extension support for ARM SMMUv3"
-	depends on ACPI
 	help
 	  Support for NVIDIA CMDQ-Virtualization extension for ARM SMMUv3. The
 	  CMDQ-V extension is similar to v3.3 ECMDQ for multi command queues
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index d16d35c78c06..dad3c0cb800b 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -4542,10 +4542,11 @@ static void acpi_smmu_dsdt_probe_tegra241_cmdqv(struct acpi_iort_node *node,
 	adev = acpi_dev_get_first_match_dev("NVDA200C", uid, -1);
 	if (adev) {
 		/* Tegra241 CMDQV driver is responsible for put_device() */
-		smmu->impl_dev = &adev->dev;
+		smmu->impl_dev = get_device(acpi_get_first_physical_node(adev));
 		smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
 		dev_info(smmu->dev, "found companion CMDQV device: %s\n",
 			 dev_name(smmu->impl_dev));
+		acpi_dev_put(adev);
 	}
 	kfree(uid);
 }
diff --git a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
index 378104cd395e..1fc03b72beb8 100644
--- a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
+++ b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
@@ -3,17 +3,15 @@
 
 #define dev_fmt(fmt) "tegra241_cmdqv: " fmt
 
-#include <linux/acpi.h>
 #include <linux/debugfs.h>
 #include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
 #include <linux/iommu.h>
 #include <linux/iommufd.h>
 #include <linux/iopoll.h>
+#include <linux/platform_device.h>
 #include <uapi/linux/iommufd.h>
 
-#include <acpi/acpixf.h>
-
 #include "arm-smmu-v3.h"
 
 /* CMDQV register page base and size defines */
@@ -854,69 +852,6 @@ static struct arm_smmu_impl_ops tegra241_cmdqv_impl_ops = {
 
 /* Probe Functions */
 
-static int tegra241_cmdqv_acpi_is_memory(struct acpi_resource *res, void *data)
-{
-	struct resource_win win;
-
-	return !acpi_dev_resource_address_space(res, &win);
-}
-
-static int tegra241_cmdqv_acpi_get_irqs(struct acpi_resource *ares, void *data)
-{
-	struct resource r;
-	int *irq = data;
-
-	if (*irq <= 0 && acpi_dev_resource_interrupt(ares, 0, &r))
-		*irq = r.start;
-	return 1; /* No need to add resource to the list */
-}
-
-static struct resource *
-tegra241_cmdqv_find_acpi_resource(struct device *dev, int *irq)
-{
-	struct acpi_device *adev = to_acpi_device(dev);
-	struct list_head resource_list;
-	struct resource_entry *rentry;
-	struct resource *res = NULL;
-	int ret;
-
-	INIT_LIST_HEAD(&resource_list);
-	ret = acpi_dev_get_resources(adev, &resource_list,
-				     tegra241_cmdqv_acpi_is_memory, NULL);
-	if (ret < 0) {
-		dev_err(dev, "failed to get memory resource: %d\n", ret);
-		return NULL;
-	}
-
-	rentry = list_first_entry_or_null(&resource_list,
-					  struct resource_entry, node);
-	if (!rentry) {
-		dev_err(dev, "failed to get memory resource entry\n");
-		goto free_list;
-	}
-
-	/* Caller must free the res */
-	res = kzalloc(sizeof(*res), GFP_KERNEL);
-	if (!res)
-		goto free_list;
-
-	*res = *rentry->res;
-
-	acpi_dev_free_resource_list(&resource_list);
-
-	INIT_LIST_HEAD(&resource_list);
-
-	if (irq)
-		ret = acpi_dev_get_resources(adev, &resource_list,
-					     tegra241_cmdqv_acpi_get_irqs, irq);
-	if (ret < 0 || !irq || *irq <= 0)
-		dev_warn(dev, "no interrupt. errors will not be reported\n");
-
-free_list:
-	acpi_dev_free_resource_list(&resource_list);
-	return res;
-}
-
 static int tegra241_cmdqv_init_structures(struct arm_smmu_device *smmu)
 {
 	struct tegra241_cmdqv *cmdqv =
@@ -1042,18 +977,23 @@ __tegra241_cmdqv_probe(struct arm_smmu_device *smmu, struct resource *res,
 
 struct arm_smmu_device *tegra241_cmdqv_probe(struct arm_smmu_device *smmu)
 {
+	struct platform_device *pdev = to_platform_device(smmu->impl_dev);
 	struct arm_smmu_device *new_smmu;
-	struct resource *res = NULL;
+	struct resource *res;
 	int irq;
 
-	if (!smmu->dev->of_node)
-		res = tegra241_cmdqv_find_acpi_resource(smmu->impl_dev, &irq);
-	if (!res)
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "no memory resource found for CMDQV\n");
 		goto out_fallback;
+	}
 
-	new_smmu = __tegra241_cmdqv_probe(smmu, res, irq);
-	kfree(res);
+	irq = platform_get_irq_optional(pdev, 0);
+	if (irq <= 0)
+		dev_warn(&pdev->dev,
+			 "no interrupt. errors will not be reported\n");
 
+	new_smmu = __tegra241_cmdqv_probe(smmu, res, irq);
 	if (new_smmu)
 		return new_smmu;
 
-- 
2.25.1



From amhetre at nvidia.com  Sun Dec 14 22:48:15 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Mon, 15 Dec 2025 06:48:15 +0000
Subject: [PATCH V7 0/4] Add device tree support for NVIDIA Tegra CMDQV
Message-ID: <20251215064819.3345361-1-amhetre@nvidia.com>

This series adds device tree support for the CMDQ-Virtualization (CMDQV)
hardware on NVIDIA Tegra264 SoCs.

CMDQV is a hardware block that works alongside the ARM SMMUv3 to assist in
virtualizing the command queue. It was previously only supported through
ACPI on Tegra241. This series extends the existing driver to support device
tree based initialization, which is required for Tegra264 platforms.

The series is structured as follows:

Patch 1: Decouple tegra241-cmdqv driver from ACPI by replacing all the
         ACPI functions with standard platform functions.

Patch 2: Extends the tegra241-cmdqv driver to support device tree probing
         alongside the existing ACPI support. The SMMU driver now parses
         the nvidia,cmdqv phandle to associate each SMMU with its
         corresponding CMDQV instance.

Patch 3: Adds device tree binding documentation for nvidia,tegra264-cmdqv
         and extends the arm,smmu-v3 binding with an optional nvidia,cmdqv
         property.

Patch 4: Adds CMDQV device nodes to the Tegra264 device tree and enables
         them on the tegra264-p3834 platform.

The implementation follows the existing ACPI probe path to minimize code
divergence and maintain consistency with Tegra241 support.

Changes in V7:
- Hold reference on platform device (impl_dev) and drop ref on ACPI
  device (adev).

Changes in V6:
- Added Nicolin's patch for decoupling tegra241-cmdqv from ACPI and
  rebased other patches on top of it.
- Removed put_device() from DT path as tegra241-cmdqv driver takes care
  of dropping reference in remove callback.

Changes in V5:
- Guard ACPI functions with CONFIG_ACPI to fix build without ACPI.

Changes in V4:
- Removed platform driver registration from tegra241-cmdqv.c to avoid
  duplicate module init/cleanup symbols
- Fixed the ordering of properties in CMDQV device tree nodes
- Added "Reviewed-by: Rob Herring" for binding documentation patch(2/3)
  carry-forwarding from V3.

Changes in V3:
- Remove the Kconfig dependency for CONFIG_TEGRA241_CMDQV
- Drop the reference on the platform device after getting it from
  of_find_device_by_node()
- Remove the unnecessary "nvidia,tegra264-smmu" compatible string from
  arm-smmu-v3 match table
- Order CMDQV nodes in device tree files according to its address

Changes in V2:
- Updated dependency for CONFIG_TEGRA241_CMDQV on OF || ACPI
- Changed maintainer to Nicolin Chen
- Removed interrupt-names property

Ashish Mhetre (3):
  iommu/arm-smmu-v3: Add device-tree support for CMDQV driver
  dt-bindings: iommu: Add NVIDIA Tegra CMDQV support
  arm64: dts: nvidia: Add nodes for CMDQV

Nicolin Chen (1):
  iommu/tegra241-cmdqv: Decouple driver from ACPI

 .../bindings/iommu/arm,smmu-v3.yaml           | 30 ++++++-
 .../bindings/iommu/nvidia,tegra264-cmdqv.yaml | 42 ++++++++++
 .../arm64/boot/dts/nvidia/tegra264-p3834.dtsi |  8 ++
 arch/arm64/boot/dts/nvidia/tegra264.dtsi      | 50 +++++++++--
 drivers/iommu/arm/Kconfig                     |  1 -
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 35 +++++++-
 .../iommu/arm/arm-smmu-v3/tegra241-cmdqv.c    | 84 +++----------------
 7 files changed, 169 insertions(+), 81 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/iommu/nvidia,tegra264-cmdqv.yaml

-- 
2.25.1



From amhetre at nvidia.com  Sun Dec 14 22:48:19 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Mon, 15 Dec 2025 06:48:19 +0000
Subject: [PATCH V7 4/4] arm64: dts: nvidia: Add nodes for CMDQV
In-Reply-To: <20251215064819.3345361-1-amhetre@nvidia.com>
References: <20251215064819.3345361-1-amhetre@nvidia.com>
Message-ID: <20251215064819.3345361-5-amhetre@nvidia.com>

The Command Queue Virtualization (CMDQV) hardware is part of the
SMMUv3 implementation on NVIDIA Tegra SoCs. It assists in
virtualizing the command queue for the SMMU.

Update SMMU compatible strings to use nvidia,tegra264-smmu to enable
CMDQV support. Add device tree nodes for the CMDQV hardware and enable
them on the tegra264-p3834 platform where SMMUs are enabled. Each SMMU
instance is paired with its corresponding CMDQV instance via the
nvidia,cmdqv property.

Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
---
 .../arm64/boot/dts/nvidia/tegra264-p3834.dtsi |  8 +++
 arch/arm64/boot/dts/nvidia/tegra264.dtsi      | 50 +++++++++++++++++--
 2 files changed, 53 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi b/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
index 06795c82427a..7e2c3e66c2ab 100644
--- a/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
@@ -23,8 +23,16 @@ iommu at 5000000 {
 			status = "okay";
 		};
 
+		cmdqv at 5200000 {
+			status = "okay";
+		};
+
 		iommu at 6000000 {
 			status = "okay";
 		};
+
+		cmdqv at 6200000 {
+			status = "okay";
+		};
 	};
 };
diff --git a/arch/arm64/boot/dts/nvidia/tegra264.dtsi b/arch/arm64/boot/dts/nvidia/tegra264.dtsi
index f137565da804..9eb7058e3149 100644
--- a/arch/arm64/boot/dts/nvidia/tegra264.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra264.dtsi
@@ -3361,7 +3361,7 @@ bus at 8100000000 {
 			 <0x02 0x00000000 0xd0 0x00000000 0x08 0x80000000>; /* ECAM, prefetchable memory, I/O */
 
 		smmu1: iommu at 5000000 {
-			compatible = "arm,smmu-v3";
+			compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
 			reg = <0x00 0x5000000 0x0 0x200000>;
 			interrupts = <GIC_SPI 12 IRQ_TYPE_EDGE_RISING>,
 				     <GIC_SPI 13 IRQ_TYPE_EDGE_RISING>;
@@ -3370,10 +3370,18 @@ smmu1: iommu at 5000000 {
 
 			#iommu-cells = <1>;
 			dma-coherent;
+			nvidia,cmdqv = <&cmdqv1>;
+		};
+
+		cmdqv1: cmdqv at 5200000 {
+			compatible = "nvidia,tegra264-cmdqv";
+			reg = <0x00 0x5200000 0x0 0x830000>;
+			interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
 		};
 
 		smmu2: iommu at 6000000 {
-			compatible = "arm,smmu-v3";
+			compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
 			reg = <0x00 0x6000000 0x0 0x200000>;
 			interrupts = <GIC_SPI 1 IRQ_TYPE_EDGE_RISING>,
 				     <GIC_SPI 2 IRQ_TYPE_EDGE_RISING>;
@@ -3382,6 +3390,14 @@ smmu2: iommu at 6000000 {
 
 			#iommu-cells = <1>;
 			dma-coherent;
+			nvidia,cmdqv = <&cmdqv2>;
+		};
+
+		cmdqv2: cmdqv at 6200000 {
+			compatible = "nvidia,tegra264-cmdqv";
+			reg = <0x00 0x6200000 0x0 0x830000>;
+			interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
 		};
 
 		mc: memory-controller at 8020000 {
@@ -3437,7 +3453,7 @@ emc: external-memory-controller at 8800000 {
 		};
 
 		smmu0: iommu at a000000 {
-			compatible = "arm,smmu-v3";
+			compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
 			reg = <0x00 0xa000000 0x0 0x200000>;
 			interrupts = <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>,
 				     <GIC_SPI 22 IRQ_TYPE_EDGE_RISING>;
@@ -3446,10 +3462,18 @@ smmu0: iommu at a000000 {
 
 			#iommu-cells = <1>;
 			dma-coherent;
+			nvidia,cmdqv = <&cmdqv0>;
+		};
+
+		cmdqv0: cmdqv at a200000 {
+			compatible = "nvidia,tegra264-cmdqv";
+			reg = <0x00 0xa200000 0x0 0x830000>;
+			interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
 		};
 
 		smmu4: iommu at b000000 {
-			compatible = "arm,smmu-v3";
+			compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
 			reg = <0x00 0xb000000 0x0 0x200000>;
 			interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
 				     <GIC_SPI 31 IRQ_TYPE_EDGE_RISING>;
@@ -3458,6 +3482,14 @@ smmu4: iommu at b000000 {
 
 			#iommu-cells = <1>;
 			dma-coherent;
+			nvidia,cmdqv = <&cmdqv4>;
+		};
+
+		cmdqv4: cmdqv at b200000 {
+			compatible = "nvidia,tegra264-cmdqv";
+			reg = <0x00 0xb200000 0x0 0x830000>;
+			interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
 		};
 
 		i2c14: i2c at c410000 {
@@ -3690,7 +3722,7 @@ bus at 8800000000 {
 		ranges = <0x00 0x00000000 0x88 0x00000000 0x01 0x00000000>;
 
 		smmu3: iommu at 6000000 {
-			compatible = "arm,smmu-v3";
+			compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
 			reg = <0x00 0x6000000 0x0 0x200000>;
 			interrupts = <GIC_SPI 225 IRQ_TYPE_EDGE_RISING>,
 				     <GIC_SPI 226 IRQ_TYPE_EDGE_RISING>;
@@ -3699,6 +3731,14 @@ smmu3: iommu at 6000000 {
 
 			#iommu-cells = <1>;
 			dma-coherent;
+			nvidia,cmdqv = <&cmdqv3>;
+		};
+
+		cmdqv3: cmdqv at 6200000 {
+			compatible = "nvidia,tegra264-cmdqv";
+			reg = <0x00 0x6200000 0x0 0x830000>;
+			interrupts = <GIC_SPI 232 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
 		};
 
 		hda at 90b0000 {
-- 
2.25.1



From amhetre at nvidia.com  Sun Dec 14 22:48:17 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Mon, 15 Dec 2025 06:48:17 +0000
Subject: [PATCH V7 2/4] iommu/arm-smmu-v3: Add device-tree support for CMDQV driver
In-Reply-To: <20251215064819.3345361-1-amhetre@nvidia.com>
References: <20251215064819.3345361-1-amhetre@nvidia.com>
Message-ID: <20251215064819.3345361-3-amhetre@nvidia.com>

Add device tree support to the CMDQV driver to enable usage on Tegra264
SoCs. The implementation parses the nvidia,cmdqv phandle from the SMMU
device tree node to associate each SMMU with its corresponding CMDQV
instance based on compatible string.

Reviewed-by: Nicolin Chen <nicolinc at nvidia.com>
Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 32 +++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index dad3c0cb800b..0cd0013200f3 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -4530,6 +4530,35 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
 	return 0;
 }
 
+#ifdef CONFIG_TEGRA241_CMDQV
+static void tegra_cmdqv_dt_probe(struct device_node *smmu_node,
+				 struct arm_smmu_device *smmu)
+{
+	struct platform_device *pdev;
+	struct device_node *np;
+
+	np = of_parse_phandle(smmu_node, "nvidia,cmdqv", 0);
+	if (!np)
+		return;
+
+	/* Tegra241 CMDQV driver is responsible for put_device() */
+	pdev = of_find_device_by_node(np);
+	of_node_put(np);
+	if (!pdev)
+		return;
+
+	smmu->impl_dev = &pdev->dev;
+	smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
+	dev_info(smmu->dev, "found companion CMDQV device: %s\n",
+		 dev_name(smmu->impl_dev));
+}
+#else
+static void tegra_cmdqv_dt_probe(struct device_node *smmu_node,
+				 struct arm_smmu_device *smmu)
+{
+}
+#endif
+
 #ifdef CONFIG_ACPI
 #ifdef CONFIG_TEGRA241_CMDQV
 static void acpi_smmu_dsdt_probe_tegra241_cmdqv(struct acpi_iort_node *node,
@@ -4635,6 +4664,9 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev,
 	if (of_dma_is_coherent(dev->of_node))
 		smmu->features |= ARM_SMMU_FEAT_COHERENCY;
 
+	if (of_device_is_compatible(dev->of_node, "nvidia,tegra264-smmu"))
+		tegra_cmdqv_dt_probe(dev->of_node, smmu);
+
 	return ret;
 }
 
-- 
2.25.1



From amhetre at nvidia.com  Sun Dec 14 22:48:18 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Mon, 15 Dec 2025 06:48:18 +0000
Subject: [PATCH V7 3/4] dt-bindings: iommu: Add NVIDIA Tegra CMDQV support
In-Reply-To: <20251215064819.3345361-1-amhetre@nvidia.com>
References: <20251215064819.3345361-1-amhetre@nvidia.com>
Message-ID: <20251215064819.3345361-4-amhetre@nvidia.com>

The Command Queue Virtualization (CMDQV) hardware is part of the
SMMUv3 implementation on NVIDIA Tegra SoCs. It assists in
virtualizing the command queue for the SMMU.

Add a new device tree binding document for nvidia,tegra264-cmdqv.

Also update the arm,smmu-v3 binding to include an optional nvidia,cmdqv
property. This property is a phandle to the CMDQV device node, allowing
the SMMU driver to associate with its corresponding CMDQV instance.
Restrict this property usage to Nvidia Tegra264 only.

Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
---
 .../bindings/iommu/arm,smmu-v3.yaml           | 30 ++++++++++++-
 .../bindings/iommu/nvidia,tegra264-cmdqv.yaml | 42 +++++++++++++++++++
 2 files changed, 70 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/iommu/nvidia,tegra264-cmdqv.yaml

diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
index 75fcf4cb52d9..1c03482e4c61 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
@@ -20,7 +20,12 @@ properties:
   $nodename:
     pattern: "^iommu@[0-9a-f]*"
   compatible:
-    const: arm,smmu-v3
+    oneOf:
+      - const: arm,smmu-v3
+      - items:
+          - enum:
+              - nvidia,tegra264-smmu
+          - const: arm,smmu-v3
 
   reg:
     maxItems: 1
@@ -58,6 +63,15 @@ properties:
 
   msi-parent: true
 
+  nvidia,cmdqv:
+    description: |
+      A phandle to its pairing CMDQV extension for an implementation on NVIDIA
+      Tegra SoC.
+
+      If this property is absent, CMDQ-Virtualization won't be used and SMMU
+      will only use its own CMDQ.
+    $ref: /schemas/types.yaml#/definitions/phandle
+
   hisilicon,broken-prefetch-cmd:
     type: boolean
     description: Avoid sending CMD_PREFETCH_* commands to the SMMU.
@@ -69,6 +83,17 @@ properties:
       register access with page 0 offsets. Set for Cavium ThunderX2 silicon that
       doesn't support SMMU page1 register space.
 
+allOf:
+  - if:
+      not:
+        properties:
+          compatible:
+            contains:
+              const: nvidia,tegra264-smmu
+    then:
+      properties:
+        nvidia,cmdqv: false
+
 required:
   - compatible
   - reg
@@ -82,7 +107,7 @@ examples:
     #include <dt-bindings/interrupt-controller/irq.h>
 
     iommu at 2b400000 {
-            compatible = "arm,smmu-v3";
+            compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
             reg = <0x2b400000 0x20000>;
             interrupts = <GIC_SPI 74 IRQ_TYPE_EDGE_RISING>,
                          <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>,
@@ -92,4 +117,5 @@ examples:
             dma-coherent;
             #iommu-cells = <1>;
             msi-parent = <&its 0xff0000>;
+            nvidia,cmdqv = <&cmdqv>;
     };
diff --git a/Documentation/devicetree/bindings/iommu/nvidia,tegra264-cmdqv.yaml b/Documentation/devicetree/bindings/iommu/nvidia,tegra264-cmdqv.yaml
new file mode 100644
index 000000000000..3f5006a59805
--- /dev/null
+++ b/Documentation/devicetree/bindings/iommu/nvidia,tegra264-cmdqv.yaml
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iommu/nvidia,tegra264-cmdqv.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra264 CMDQV
+
+description:
+  The CMDQ-Virtualization hardware block is part of the SMMUv3 implementation
+  on Tegra264 SoCs. It assists in virtualizing the command queue for the SMMU.
+
+maintainers:
+  - Nicolin Chen <nicolinc at nvidia.com>
+
+properties:
+  compatible:
+    const: nvidia,tegra264-cmdqv
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    cmdqv at 5200000 {
+            compatible = "nvidia,tegra264-cmdqv";
+            reg = <0x5200000 0x830000>;
+            interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+    };
-- 
2.25.1



From ping.bai at nxp.com  Sun Dec 14 23:26:05 2025
From: ping.bai at nxp.com (Jacky Bai)
Date: Mon, 15 Dec 2025 15:26:05 +0800
Subject: [PATCH] remoteproc: imx_rproc: Ues sync handling in rx_callback
 for i.MX7ULP suspend
Message-ID: <20251215-imx7ulp_rproc-v1-1-4e96cebc4bc6@nxp.com>

On i.MX7ULP platform, certain drivers that depend on rpmsg may need
to send an rpmsg request and receive an acknowledgment from the
remote core during the late_suspend stage. In the current imx_rproc
implementation, rx_callback defers message handling to a workqueue.
However, this deferred work may not execute before the system enters
the noirq_suspend stage. When that happens, pending mailbox IRQs
will cause the suspend sequence to abort.

To address this, handle incoming messages synchronously within
rx_callback when running on i.MX7ULP. This ensures the message is
processed immediately, allows the mailbox IRQ to be cleared in time,
and prevents suspend failures.

Signed-off-by: Jacky Bai <ping.bai at nxp.com>
---
 drivers/remoteproc/imx_rproc.c | 49 ++++++++++++++++++++++++++++++++++++++++--
 drivers/remoteproc/imx_rproc.h |  1 +
 2 files changed, 48 insertions(+), 2 deletions(-)

diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index 3be8790c14a2ccc789dd40508ec274000ec09978..1127c56388fd94f296c80db5c01a5d431d669c4d 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -22,6 +22,7 @@
 #include <linux/reboot.h>
 #include <linux/regmap.h>
 #include <linux/remoteproc.h>
+#include <linux/suspend.h>
 #include <linux/workqueue.h>
 
 #include "imx_rproc.h"
@@ -111,11 +112,13 @@ struct imx_rproc {
 	void __iomem			*rsc_table;
 	struct imx_sc_ipc		*ipc_handle;
 	struct notifier_block		rproc_nb;
+	struct notifier_block		pm_nb;
 	u32				rproc_pt;	/* partition id */
 	u32				rsrc_id;	/* resource id */
 	u32				entry;		/* cpu start address */
 	u32				core_index;
 	struct dev_pm_domain_list	*pd_list;
+	bool				use_sync_rx;
 };
 
 static const struct imx_rproc_att imx_rproc_att_imx93[] = {
@@ -725,7 +728,10 @@ static void imx_rproc_rx_callback(struct mbox_client *cl, void *msg)
 	struct rproc *rproc = dev_get_drvdata(cl->dev);
 	struct imx_rproc *priv = rproc->priv;
 
-	queue_work(priv->workqueue, &priv->rproc_work);
+	if (priv->use_sync_rx)
+		idr_for_each(&rproc->notifyids, imx_rproc_notified_idr_cb, rproc);
+	else
+		queue_work(priv->workqueue, &priv->rproc_work);
 }
 
 static int imx_rproc_xtr_mbox_init(struct rproc *rproc, bool tx_block)
@@ -1009,6 +1015,38 @@ static int imx_rproc_sys_off_handler(struct sys_off_data *data)
 	return NOTIFY_DONE;
 }
 
+static int imx_rproc_pm_notify(struct notifier_block *nb,
+	unsigned long action, void *data)
+{
+	int ret;
+	struct imx_rproc *priv = container_of(nb, struct imx_rproc, pm_nb);
+
+	imx_rproc_free_mbox(priv->rproc);
+
+	switch (action) {
+	case PM_SUSPEND_PREPARE:
+		ret = imx_rproc_xtr_mbox_init(priv->rproc, false);
+		if (ret) {
+			dev_err(&priv->rproc->dev, "Failed to request non-blocking mbox\n");
+			return NOTIFY_BAD;
+		}
+		priv->use_sync_rx = true;
+		break;
+	case PM_POST_SUSPEND:
+		ret = imx_rproc_xtr_mbox_init(priv->rproc, true);
+		if (ret) {
+			dev_err(&priv->rproc->dev, "Failed to request blocking mbox\n");
+			return NOTIFY_BAD;
+		}
+		priv->use_sync_rx = false;
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
 static void imx_rproc_destroy_workqueue(void *data)
 {
 	struct workqueue_struct *workqueue = data;
@@ -1103,6 +1141,13 @@ static int imx_rproc_probe(struct platform_device *pdev)
 			return dev_err_probe(dev, ret, "register restart handler failure\n");
 	}
 
+	if (dcfg->flags & IMX_RPROC_NEED_PM_SYNC) {
+		priv->pm_nb.notifier_call = imx_rproc_pm_notify;
+		ret = register_pm_notifier(&priv->pm_nb);
+		if (ret)
+			return dev_err_probe(dev, ret, "register pm notifier failure\n");
+	}
+
 	pm_runtime_enable(dev);
 	ret = pm_runtime_resume_and_get(dev);
 	if (ret)
@@ -1202,7 +1247,7 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx8ulp = {
 static const struct imx_rproc_dcfg imx_rproc_cfg_imx7ulp = {
 	.att		= imx_rproc_att_imx7ulp,
 	.att_size	= ARRAY_SIZE(imx_rproc_att_imx7ulp),
-	.flags		= IMX_RPROC_NEED_SYSTEM_OFF,
+	.flags		= IMX_RPROC_NEED_SYSTEM_OFF | IMX_RPROC_NEED_PM_SYNC,
 };
 
 static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = {
diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h
index 1b2d9f4d6d19dcdc215be97f7e2ab3488281916a..0e3e460cef4ed9340fb4977183e03143c84764af 100644
--- a/drivers/remoteproc/imx_rproc.h
+++ b/drivers/remoteproc/imx_rproc.h
@@ -18,6 +18,7 @@ struct imx_rproc_att {
 /* dcfg flags */
 #define IMX_RPROC_NEED_SYSTEM_OFF	BIT(0)
 #define IMX_RPROC_NEED_CLKS		BIT(1)
+#define IMX_RPROC_NEED_PM_SYNC		BIT(2)
 
 struct imx_rproc_plat_ops {
 	int (*start)(struct rproc *rproc);

---
base-commit: 5ce74bc1b7cb2732b22f9c93082545bc655d6547
change-id: 20251211-imx7ulp_rproc-57999329239b

Best regards,
-- 
Jacky Bai <ping.bai at nxp.com>



From sumit.garg at kernel.org  Sun Dec 14 23:30:54 2025
From: sumit.garg at kernel.org (Sumit Garg)
Date: Mon, 15 Dec 2025 16:30:54 +0900
Subject: [PATCH v1 10/17] firmware: arm_scmi: optee: Make use of
 module_tee_client_driver()
In-Reply-To: <537c48e3db243b5c68c3192179a948efb3a180c7.1765472125.git.u.kleine-koenig@baylibre.com>
References: <cover.1765472125.git.u.kleine-koenig@baylibre.com>
 <537c48e3db243b5c68c3192179a948efb3a180c7.1765472125.git.u.kleine-koenig@baylibre.com>
Message-ID: <aT-5LtYnLSF_MwW4@sumit-X1>

On Thu, Dec 11, 2025 at 06:15:04PM +0100, Uwe Kleine-K?nig wrote:
> Reduce boilerplate by using the newly introduced module_tee_client_driver().
> That takes care of assigning the driver's bus, so the explicit assigning
> in this driver can be dropped.
> 
> Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig at baylibre.com>
> ---
>  drivers/firmware/arm_scmi/transports/optee.c | 13 +------------
>  1 file changed, 1 insertion(+), 12 deletions(-)

Reviewed-by: Sumit Garg <sumit.garg at oss.qualcomm.com>

-Sumit

> 
> diff --git a/drivers/firmware/arm_scmi/transports/optee.c b/drivers/firmware/arm_scmi/transports/optee.c
> index dc0f46340153..8fdb80d3fabd 100644
> --- a/drivers/firmware/arm_scmi/transports/optee.c
> +++ b/drivers/firmware/arm_scmi/transports/optee.c
> @@ -612,23 +612,12 @@ static struct tee_client_driver scmi_optee_service_driver = {
>  	.id_table	= scmi_optee_service_id,
>  	.driver		= {
>  		.name = "scmi-optee",
> -		.bus = &tee_bus_type,
>  		.probe = scmi_optee_service_probe,
>  		.remove = scmi_optee_service_remove,
>  	},
>  };
>  
> -static int __init scmi_transport_optee_init(void)
> -{
> -	return driver_register(&scmi_optee_service_driver.driver);
> -}
> -module_init(scmi_transport_optee_init);
> -
> -static void __exit scmi_transport_optee_exit(void)
> -{
> -	driver_unregister(&scmi_optee_service_driver.driver);
> -}
> -module_exit(scmi_transport_optee_exit);
> +module_tee_client_driver(scmi_optee_service_driver);
>  
>  MODULE_AUTHOR("Etienne Carriere <etienne.carriere at foss.st.com>");
>  MODULE_DESCRIPTION("SCMI OPTEE Transport driver");
> -- 
> 2.47.3
> 


From alexander.stein at ew.tq-group.com  Sun Dec 14 23:31:47 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Mon, 15 Dec 2025 08:31:47 +0100
Subject: [PATCH 1/2] dt-bindings: power: fsl,imx-gpc: Document address-cells
In-Reply-To: <aTxKqPqGdiHllLo6@lizhi-Precision-Tower-5810>
References: <20251212085902.103507-1-alexander.stein@ew.tq-group.com>
 <aTxKqPqGdiHllLo6@lizhi-Precision-Tower-5810>
Message-ID: <12807757.O9o76ZdvQC@steina-w>

Hi,

Am Freitag, 12. Dezember 2025, 18:02:32 CET schrieb Frank Li:
> On Fri, Dec 12, 2025 at 09:58:59AM +0100, Alexander Stein wrote:
> > The GPC power controller is an interrupt controllers and can be referenced
> > in interrupt-map properties, e.g. PCIe controller, thus the node should
> > have address-cells property.
> >
> > Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
> 
> Strange, there are not #address-cells property for gic if there are not
> ITS node. gic is widely used.
> 
> Does gic node also missed #address-cells?

Yes and no.
Yes: see commit faf183a02ed6b ("arm64: dts: imx8mp: Add default GIC address cells")
No: AFAICS this is only necessary if an interrupt-controller is referenced
from within interrupt-map. But on imx6qdl.dtsi 'intc' (GIC) is not used that way.

Best regards,
Alexander

> 
> Frank
> 
> > ---
> >  Documentation/devicetree/bindings/power/fsl,imx-gpc.yaml | 3 +++
> >  1 file changed, 3 insertions(+)
> >
> > diff --git a/Documentation/devicetree/bindings/power/fsl,imx-gpc.yaml b/Documentation/devicetree/bindings/power/fsl,imx-gpc.yaml
> > index 9de3fe73c1eb6..d49a5130b87c7 100644
> > --- a/Documentation/devicetree/bindings/power/fsl,imx-gpc.yaml
> > +++ b/Documentation/devicetree/bindings/power/fsl,imx-gpc.yaml
> > @@ -38,6 +38,9 @@ properties:
> >    reg:
> >      maxItems: 1
> >
> > +  "#address-cells":
> > +    const: 0
> > +
> >    interrupts:
> >      maxItems: 1
> >
> > --
> > 2.43.0
> >
> 


-- 
TQ-Systems GmbH | M?hlstra?e 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht M?nchen, HRB 105018
Gesch?ftsf?hrer: Detlef Schneider, R?diger Stahl, Stefan Schneider
http://www.tq-group.com/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251215/5112fd8e/attachment-0001.sig>

From sumit.garg at kernel.org  Sun Dec 14 23:32:55 2025
From: sumit.garg at kernel.org (Sumit Garg)
Date: Mon, 15 Dec 2025 16:32:55 +0900
Subject: [PATCH v1 11/17] firmware: arm_scmi: Make use of tee bus methods
In-Reply-To: <46dae3cada663b3a5ae1989881d9e74ef40acce5.1765472125.git.u.kleine-koenig@baylibre.com>
References: <cover.1765472125.git.u.kleine-koenig@baylibre.com>
 <46dae3cada663b3a5ae1989881d9e74ef40acce5.1765472125.git.u.kleine-koenig@baylibre.com>
Message-ID: <aT-5p7FTvNU8jcLU@sumit-X1>

On Thu, Dec 11, 2025 at 06:15:05PM +0100, Uwe Kleine-K?nig wrote:
> The tee bus got dedicated callbacks for probe and remove.
> Make use of these. This fixes a runtime warning about the driver needing
> to be converted to the bus methods. Note that the return value of .remove()
> was already ignored before, so there is no problem introduced by dropping
> the error returns.
> 
> Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig at baylibre.com>
> ---
>  drivers/firmware/arm_scmi/transports/optee.c | 19 +++++++++----------
>  1 file changed, 9 insertions(+), 10 deletions(-)

Reviewed-by: Sumit Garg <sumit.garg at oss.qualcomm.com>

-Sumit

> 
> diff --git a/drivers/firmware/arm_scmi/transports/optee.c b/drivers/firmware/arm_scmi/transports/optee.c
> index 8fdb80d3fabd..07ae18d5279d 100644
> --- a/drivers/firmware/arm_scmi/transports/optee.c
> +++ b/drivers/firmware/arm_scmi/transports/optee.c
> @@ -529,8 +529,9 @@ static const struct of_device_id scmi_of_match[] = {
>  DEFINE_SCMI_TRANSPORT_DRIVER(scmi_optee, scmi_optee_driver, scmi_optee_desc,
>  			     scmi_of_match, core);
>  
> -static int scmi_optee_service_probe(struct device *dev)
> +static int scmi_optee_service_probe(struct tee_client_device *scmi_pta)
>  {
> +	struct device *dev = &scmi_pta->dev;
>  	struct scmi_optee_agent *agent;
>  	struct tee_context *tee_ctx;
>  	int ret;
> @@ -578,24 +579,22 @@ static int scmi_optee_service_probe(struct device *dev)
>  	return ret;
>  }
>  
> -static int scmi_optee_service_remove(struct device *dev)
> +static void scmi_optee_service_remove(struct tee_client_device *scmi_pta)
>  {
>  	struct scmi_optee_agent *agent = scmi_optee_private;
>  
>  	if (!scmi_optee_private)
> -		return -EINVAL;
> +		return;
>  
>  	platform_driver_unregister(&scmi_optee_driver);
>  
>  	if (!list_empty(&scmi_optee_private->channel_list))
> -		return -EBUSY;
> +		return;
>  
>  	/* Ensure cleared reference is visible before resources are released */
>  	smp_store_mb(scmi_optee_private, NULL);
>  
>  	tee_client_close_context(agent->tee_ctx);
> -
> -	return 0;
>  }
>  
>  static const struct tee_client_device_id scmi_optee_service_id[] = {
> @@ -609,11 +608,11 @@ static const struct tee_client_device_id scmi_optee_service_id[] = {
>  MODULE_DEVICE_TABLE(tee, scmi_optee_service_id);
>  
>  static struct tee_client_driver scmi_optee_service_driver = {
> -	.id_table	= scmi_optee_service_id,
> -	.driver		= {
> +	.probe = scmi_optee_service_probe,
> +	.remove = scmi_optee_service_remove,
> +	.id_table = scmi_optee_service_id,
> +	.driver = {
>  		.name = "scmi-optee",
> -		.probe = scmi_optee_service_probe,
> -		.remove = scmi_optee_service_remove,
>  	},
>  };
>  
> -- 
> 2.47.3
> 
> 


From linux at fw-web.de  Sun Dec 14 23:46:08 2025
From: linux at fw-web.de (Frank Wunderlich)
Date: Mon, 15 Dec 2025 08:46:08 +0100
Subject: [PATCH] arm64: dts: mediatek: mt7988a-bpi-r4pro: fix model string
Message-ID: <20251215074609.4100-1-linux@fw-web.de>

From: Frank Wunderlich <frank-w at public-files.de>

Fix incorrect model string in Devicetree for BPI-R4-Pro.

Fixes: f397471a6a8c ("arm64: dts: mediatek: mt7988: Add devicetree for BananaPi R4 Pro")
Signed-off-by: Frank Wunderlich <frank-w at public-files.de>
---
 arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-4e.dts | 2 +-
 arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-8x.dts | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-4e.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-4e.dts
index c7ea6e88c4f4..621d01e3cd89 100644
--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-4e.dts
+++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-4e.dts
@@ -9,7 +9,7 @@
 #include "mt7988a-bananapi-bpi-r4-pro.dtsi"
 
 / {
-	model = "Bananapi BPI-R4";
+	model = "Bananapi BPI-R4 Pro 4E";
 	compatible = "bananapi,bpi-r4-pro-4e",
 		     "bananapi,bpi-r4-pro",
 		     "mediatek,mt7988a";
diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-8x.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-8x.dts
index c9a0e69e9dd5..bb15bfa5e6ae 100644
--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-8x.dts
+++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-8x.dts
@@ -9,7 +9,7 @@
 #include "mt7988a-bananapi-bpi-r4-pro.dtsi"
 
 / {
-	model = "Bananapi BPI-R4";
+	model = "Bananapi BPI-R4 Pro 8X";
 	compatible = "bananapi,bpi-r4-pro-8x",
 		     "bananapi,bpi-r4-pro",
 		     "mediatek,mt7988a";
-- 
2.43.0



From michal.simek at amd.com  Sun Dec 14 23:47:11 2025
From: michal.simek at amd.com (Michal Simek)
Date: Mon, 15 Dec 2025 08:47:11 +0100
Subject: [PATCH] soc/xilinx: replace use of system_unbound_wq with
 system_dfl_wq
In-Reply-To: <20251104103942.96647-1-marco.crivellari@suse.com>
References: <20251104103942.96647-1-marco.crivellari@suse.com>
Message-ID: <7e44d434-faf2-4f14-9427-9e6173912d15@amd.com>



On 11/4/25 11:39, Marco Crivellari wrote:
> Currently if a user enqueue a work item using schedule_delayed_work() the
> used wq is "system_wq" (per-cpu wq) while queue_delayed_work() use
> WORK_CPU_UNBOUND (used when a cpu is not specified). The same applies to
> schedule_work() that is using system_wq and queue_work(), that makes use
> again of WORK_CPU_UNBOUND.
> 
> This lack of consistentcy cannot be addressed without refactoring the API.
> 
> This patch continues the effort to refactor worqueue APIs, which has begun
> with the change introducing new workqueues and a new alloc_workqueue flag:
> 
> commit 128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq")
> commit 930c2ea566af ("workqueue: Add new WQ_PERCPU flag")
> 
> system_dfl_wq should be the default workqueue so as not to enforce
> locality constraints for random work whenever it's not required.
> 
> The old system_unbound_wq will be kept for a few release cycles.
> 
> Suggested-by: Tejun Heo <tj at kernel.org>
> Signed-off-by: Marco Crivellari <marco.crivellari at suse.com>
> ---
>   drivers/soc/xilinx/zynqmp_power.c | 6 +++---
>   1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/soc/xilinx/zynqmp_power.c b/drivers/soc/xilinx/zynqmp_power.c
> index ae59bf16659a..6145c4fe192e 100644
> --- a/drivers/soc/xilinx/zynqmp_power.c
> +++ b/drivers/soc/xilinx/zynqmp_power.c
> @@ -82,7 +82,7 @@ static void subsystem_restart_event_callback(const u32 *payload, void *data)
>   	memcpy(zynqmp_pm_init_restart_work->args, &payload[0],
>   	       sizeof(zynqmp_pm_init_restart_work->args));
>   
> -	queue_work(system_unbound_wq, &zynqmp_pm_init_restart_work->callback_work);
> +	queue_work(system_dfl_wq, &zynqmp_pm_init_restart_work->callback_work);
>   }
>   
>   static void suspend_event_callback(const u32 *payload, void *data)
> @@ -95,7 +95,7 @@ static void suspend_event_callback(const u32 *payload, void *data)
>   	memcpy(zynqmp_pm_init_suspend_work->args, &payload[1],
>   	       sizeof(zynqmp_pm_init_suspend_work->args));
>   
> -	queue_work(system_unbound_wq, &zynqmp_pm_init_suspend_work->callback_work);
> +	queue_work(system_dfl_wq, &zynqmp_pm_init_suspend_work->callback_work);
>   }
>   
>   static irqreturn_t zynqmp_pm_isr(int irq, void *data)
> @@ -140,7 +140,7 @@ static void ipi_receive_callback(struct mbox_client *cl, void *data)
>   		memcpy(zynqmp_pm_init_suspend_work->args, &payload[1],
>   		       sizeof(zynqmp_pm_init_suspend_work->args));
>   
> -		queue_work(system_unbound_wq,
> +		queue_work(system_dfl_wq,
>   			   &zynqmp_pm_init_suspend_work->callback_work);
>   
>   		/* Send NULL message to mbox controller to ack the message */

Applied.
M


From sumit.garg at kernel.org  Sun Dec 14 23:54:11 2025
From: sumit.garg at kernel.org (Sumit Garg)
Date: Mon, 15 Dec 2025 16:54:11 +0900
Subject: [PATCH v1 00/17] tee: Use bus callbacks instead of driver
 callbacks
In-Reply-To: <cover.1765472125.git.u.kleine-koenig@baylibre.com>
References: <cover.1765472125.git.u.kleine-koenig@baylibre.com>
Message-ID: <aT--ox375kg2Mzh-@sumit-X1>

On Thu, Dec 11, 2025 at 06:14:54PM +0100, Uwe Kleine-K?nig wrote:
> Hello,
> 
> the objective of this series is to make tee driver stop using callbacks
> in struct device_driver. These were superseded by bus methods in 2006
> (commit 594c8281f905 ("[PATCH] Add bus_type probe, remove, shutdown
> methods.")) but nobody cared to convert all subsystems accordingly.
> 
> Here the tee drivers are converted. The first commit is somewhat
> unrelated, but simplifies the conversion (and the drivers). It
> introduces driver registration helpers that care about setting the bus
> and owner. (The latter is missing in all drivers, so by using these
> helpers the drivers become more correct.)
> 
> The patches #4 - #17 depend on the first two, so if they should be
> applied to their respective subsystem trees these must contain the first
> two patches first.

Thanks Uwe for your efforts to clean up the boilerplate code for TEE bus
drivers.

> 
> Note that after patch #2 is applied, unconverted drivers provoke a
> warning in driver_register(), so it would be good for the user
> experience if the whole series goes in during a single merge window.

+1

I suggest the whole series goes via the Jens tree since there shouldn't
be any chances for conflict here.

> So
> I guess an immutable branch containing the frist three patches that can
> be merged into the other subsystem trees would be sensible.
> 
> After all patches are applied, tee_bus_type can be made private to
> drivers/tee as it's not used in other places any more.
> 

Feel free to make the tee_bus_type private as the last patch in the series
such that any followup driver follows this clean approach.

-Sumit

> Best regards
> Uwe
> 
> Uwe Kleine-K?nig (17):
>   tee: Add some helpers to reduce boilerplate for tee client drivers
>   tee: Add probe, remove and shutdown bus callbacks to tee_client_driver
>   tee: Adapt documentation to cover recent additions
>   hwrng: optee - Make use of module_tee_client_driver()
>   hwrng: optee - Make use of tee bus methods
>   rtc: optee: Migrate to use tee specific driver registration function
>   rtc: optee: Make use of tee bus methods
>   efi: stmm: Make use of module_tee_client_driver()
>   efi: stmm: Make use of tee bus methods
>   firmware: arm_scmi: optee: Make use of module_tee_client_driver()
>   firmware: arm_scmi: Make use of tee bus methods
>   firmware: tee_bnxt: Make use of module_tee_client_driver()
>   firmware: tee_bnxt: Make use of tee bus methods
>   KEYS: trusted: Migrate to use tee specific driver registration
>     function
>   KEYS: trusted: Make use of tee bus methods
>   tpm/tpm_ftpm_tee: Make use of tee specific driver registration
>   tpm/tpm_ftpm_tee: Make use of tee bus methods
> 
>  Documentation/driver-api/tee.rst             | 18 +----
>  drivers/char/hw_random/optee-rng.c           | 26 ++----
>  drivers/char/tpm/tpm_ftpm_tee.c              | 31 +++++---
>  drivers/firmware/arm_scmi/transports/optee.c | 32 +++-----
>  drivers/firmware/broadcom/tee_bnxt_fw.c      | 30 ++-----
>  drivers/firmware/efi/stmm/tee_stmm_efi.c     | 25 ++----
>  drivers/rtc/rtc-optee.c                      | 27 ++-----
>  drivers/tee/tee_core.c                       | 84 ++++++++++++++++++++
>  include/linux/tee_drv.h                      | 12 +++
>  security/keys/trusted-keys/trusted_tee.c     | 17 ++--
>  10 files changed, 164 insertions(+), 138 deletions(-)
> 
> 
> base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
> -- 
> 2.47.3
> 


From ardb at kernel.org  Sun Dec 14 23:54:34 2025
From: ardb at kernel.org (Ard Biesheuvel)
Date: Mon, 15 Dec 2025 16:54:34 +0900
Subject: [PATCH] crypto: arm64/ghash - Fix incorrect output from ghash-neon
In-Reply-To: <20251212054020.GB4838@sol>
References: <DETXT7QI62KE.F3CGH2VWX1SC@cknow-tech.com> <20251209223417.112294-1-ebiggers@kernel.org>
 <DEUFDH7FJURL.3J0FN5I19VV8F@cknow-tech.com> <CAMj1kXEQkB9MWB+PAi4XE_MuBt0ScitxTsKMDo1-7Cp-=xXOpw@mail.gmail.com>
 <20251212054020.GB4838@sol>
Message-ID: <CAMj1kXHVq1NWA28jKxBrHHi1JOPoGXEamC7uMgTOmFwzmcYxRA@mail.gmail.com>

On Fri, 12 Dec 2025 at 06:40, Eric Biggers <ebiggers at kernel.org> wrote:
>
> On Wed, Dec 10, 2025 at 06:31:44PM +0900, Ard Biesheuvel wrote:
> > On Wed, 10 Dec 2025 at 18:22, Diederik de Haas <diederik at cknow-tech.com> wrote:
> > >
> > > On Tue Dec 9, 2025 at 11:34 PM CET, Eric Biggers wrote:
> > > > Commit 9a7c987fb92b ("crypto: arm64/ghash - Use API partial block
> > > > handling") made ghash_finup() pass the wrong buffer to
> > > > ghash_do_simd_update().  As a result, ghash-neon now produces incorrect
> > > > outputs when the message length isn't divisible by 16 bytes.  Fix this.
> > >
> > > I was hoping to not have to do a 'git bisect', but this is much better
> > > :-D I can confirm that this patch fixes the error I was seeing, so
> > >
> > > Tested-by: Diederik de Haas <diederik at cknow-tech.com>
> > >
> > > > (I didn't notice this earlier because this code is reached only on CPUs
> > > > that support NEON but not PMULL.  I haven't yet found a way to get
> > > > qemu-system-aarch64 to emulate that configuration.)
> > >
> > > https://www.qemu.org/docs/master/system/arm/raspi.html indicates it can
> > > emulate various Raspberry Pi models. I've only tested it with RPi 3B+
> > > (bc of its wifi+bt chip), but I wouldn't be surprised if all RPi models
> > > would have this problem? Dunno if QEMU emulates that though.
> > >
> >
> > All 64-bit RPi models except the RPi5 are affected by this, as those
> > do not implement the crypto extensions. So I would expect QEMU to do
> > the same.
> >
> > It would be nice, though, if we could emulate this on the mach-virt
> > machine model too. It should be fairly trivial to do, so if there is
> > demand for this I can look into it.
>
> I'm definitely interested in it.  I'm already testing multiple "-cpu"
> options, and it's easy to add more.
>
> With qemu-system-aarch64 I'm currently only using "-M virt", since the
> other machine models I've tried don't boot with arm64 defconfig,
> including "-M raspi3b" and "-M raspi4b".
>
> There may be some tricks I'm missing.  Regardless, expanding the
> selection of available CPUs for "-M virt" would be helpful.  Either by
> adding "real" CPUs that have "interesting" combinations of features, or
> by just allowing turning features off like
> "-cpu max,aes=off,pmull=off,sha256=off".  (Certain features like sve can
> already be turned off in that way, but not the ones relevant to us.)
>

There are some architectural rules around which combinations of crypto
extensions are permitted:
- PMULL implies AES, and there is no way for the ID registers to
describe a CPU that has PMULL but not AES
- SHA256 implies SHA1 (but the ID register fields are independent)
- SHA3 and SHA512 both imply SHA256+SHA1
- SVE versions are not allowed to be implemented unless the plain NEON
version is implemented as well
-  FEAT_Crypto has different meanings for v8.0, v8.2 and v9.x

So it would be much easier, also in terms of future maintenance, to
have a simple 'crypto=off' setting that applies to all emulated CPU
models, given that disabling all crypto on any given compliant CPU
will never result in something that the architecture does not permit.

Would that work for you?


From sumit.garg at kernel.org  Sun Dec 14 23:55:19 2025
From: sumit.garg at kernel.org (Sumit Garg)
Date: Mon, 15 Dec 2025 16:55:19 +0900
Subject: [PATCH v1 08/17] efi: stmm: Make use of
 module_tee_client_driver()
In-Reply-To: <0896270bc530d1e3b7fbcf5f7e168172dcc05d1e.1765472125.git.u.kleine-koenig@baylibre.com>
References: <cover.1765472125.git.u.kleine-koenig@baylibre.com>
 <0896270bc530d1e3b7fbcf5f7e168172dcc05d1e.1765472125.git.u.kleine-koenig@baylibre.com>
Message-ID: <aT--5-bIY8S2PiZa@sumit-X1>

On Thu, Dec 11, 2025 at 06:15:02PM +0100, Uwe Kleine-K?nig wrote:
> Reduce boilerplate by using the newly introduced module_tee_client_driver().
> That takes care of assigning the driver's bus, so the explicit assigning
> in this driver can be dropped.
> 
> Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig at baylibre.com>
> ---
>  drivers/firmware/efi/stmm/tee_stmm_efi.c | 14 +-------------
>  1 file changed, 1 insertion(+), 13 deletions(-)

Reviewed-by: Sumit Garg <sumit.garg at oss.qualcomm.com>

-Sumit

> 
> diff --git a/drivers/firmware/efi/stmm/tee_stmm_efi.c b/drivers/firmware/efi/stmm/tee_stmm_efi.c
> index 65c0fe1ba275..5903811858b6 100644
> --- a/drivers/firmware/efi/stmm/tee_stmm_efi.c
> +++ b/drivers/firmware/efi/stmm/tee_stmm_efi.c
> @@ -584,24 +584,12 @@ static struct tee_client_driver tee_stmm_efi_driver = {
>  	.id_table	= tee_stmm_efi_id_table,
>  	.driver		= {
>  		.name		= "tee-stmm-efi",
> -		.bus		= &tee_bus_type,
>  		.probe		= tee_stmm_efi_probe,
>  		.remove		= tee_stmm_efi_remove,
>  	},
>  };
>  
> -static int __init tee_stmm_efi_mod_init(void)
> -{
> -	return driver_register(&tee_stmm_efi_driver.driver);
> -}
> -
> -static void __exit tee_stmm_efi_mod_exit(void)
> -{
> -	driver_unregister(&tee_stmm_efi_driver.driver);
> -}
> -
> -module_init(tee_stmm_efi_mod_init);
> -module_exit(tee_stmm_efi_mod_exit);
> +module_tee_client_driver(tee_stmm_efi_driver);
>  
>  MODULE_LICENSE("GPL");
>  MODULE_AUTHOR("Ilias Apalodimas <ilias.apalodimas at linaro.org>");
> -- 
> 2.47.3
> 
> 


From sumit.garg at kernel.org  Sun Dec 14 23:55:57 2025
From: sumit.garg at kernel.org (Sumit Garg)
Date: Mon, 15 Dec 2025 16:55:57 +0900
Subject: [PATCH v1 09/17] efi: stmm: Make use of tee bus methods
In-Reply-To: <9e3d9ab0f7987f313237b51911865f0cccae8eb5.1765472125.git.u.kleine-koenig@baylibre.com>
References: <cover.1765472125.git.u.kleine-koenig@baylibre.com>
 <9e3d9ab0f7987f313237b51911865f0cccae8eb5.1765472125.git.u.kleine-koenig@baylibre.com>
Message-ID: <aT-_DbMYPN0p2CrK@sumit-X1>

On Thu, Dec 11, 2025 at 06:15:03PM +0100, Uwe Kleine-K?nig wrote:
> The tee bus got dedicated callbacks for probe and remove.
> Make use of these. This fixes a runtime warning about the driver needing
> to be converted to the bus methods.
> 
> Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig at baylibre.com>
> ---
>  drivers/firmware/efi/stmm/tee_stmm_efi.c | 11 +++++------
>  1 file changed, 5 insertions(+), 6 deletions(-)

Reviewed-by: Sumit Garg <sumit.garg at oss.qualcomm.com>

-Sumit

> 
> diff --git a/drivers/firmware/efi/stmm/tee_stmm_efi.c b/drivers/firmware/efi/stmm/tee_stmm_efi.c
> index 5903811858b6..7b04dd649629 100644
> --- a/drivers/firmware/efi/stmm/tee_stmm_efi.c
> +++ b/drivers/firmware/efi/stmm/tee_stmm_efi.c
> @@ -520,8 +520,9 @@ static void tee_stmm_restore_efivars_generic_ops(void)
>  	efivars_generic_ops_register();
>  }
>  
> -static int tee_stmm_efi_probe(struct device *dev)
> +static int tee_stmm_efi_probe(struct tee_client_device *tee_dev)
>  {
> +	struct device *dev = &tee_dev->dev;
>  	struct tee_ioctl_open_session_arg sess_arg;
>  	efi_status_t ret;
>  	int rc;
> @@ -571,21 +572,19 @@ static int tee_stmm_efi_probe(struct device *dev)
>  	return 0;
>  }
>  
> -static int tee_stmm_efi_remove(struct device *dev)
> +static void tee_stmm_efi_remove(struct tee_client_device *dev)
>  {
>  	tee_stmm_restore_efivars_generic_ops();
> -
> -	return 0;
>  }
>  
>  MODULE_DEVICE_TABLE(tee, tee_stmm_efi_id_table);
>  
>  static struct tee_client_driver tee_stmm_efi_driver = {
>  	.id_table	= tee_stmm_efi_id_table,
> +	.probe		= tee_stmm_efi_probe,
> +	.remove		= tee_stmm_efi_remove,
>  	.driver		= {
>  		.name		= "tee-stmm-efi",
> -		.probe		= tee_stmm_efi_probe,
> -		.remove		= tee_stmm_efi_remove,
>  	},
>  };
>  
> -- 
> 2.47.3
> 
> 


From michal.simek at amd.com  Mon Dec 15 00:02:53 2025
From: michal.simek at amd.com (Michal Simek)
Date: Mon, 15 Dec 2025 09:02:53 +0100
Subject: [PATCH v3 1/1] arm64: dts: xilinx: fix zynqmp opp-table-cpu
In-Reply-To: <20251111070555.1169130-1-neal.frager@amd.com>
References: <20251111070555.1169130-1-neal.frager@amd.com>
Message-ID: <27c2e287-949e-4ae5-a818-49f6d61cba5c@amd.com>



On 11/11/25 08:05, Neal Frager wrote:
> Since the following commit, the zynqmp clk driver uses the common
> divider_round_rate() when determining the appropriate clock divider for a
> requested clock frequency:
> https://github.com/torvalds/linux/commit/1fe15be1fb613534ecbac5f8c3f8744f757d237d
> 
> This means that all the calculations will be in kHz when determining the
> appropriate clock divider for a given cpufreq request. The problem with this
> is that the zynqmp.dtsi and zynqmp-clk-ccf.dtsi files have frequency
> definitions in Hz, so when dividing requested values in kHz, errors can occur
> with the rounding.
> 
> For example, the current pss_ref_clk frequency is 33333333 Hz which generates
> a cpufreq parent clock frequency of 1199999988 Hz which is the same as the
> highest opp-table-cpu frequency in the zynqmp.dtsi.
> 
> But if a user requests the value 1199999 kHz as recommended in the available
> frequencies:
> 
> root at zynqmp:/sys/kernel/tracing# cat /sys/devices/system/cpu/cpufreq/policy0/scaling_available_frequencies
> 299999 399999 599999 1199999
> root at zynqmp:/ # echo 1199999 > /sys/devices/system/cpu/cpufreq/policy0/scaling_setspeed
> 
> The calculation will be:
> 1199999988 / 1199999000 = 1.000001
> 
> This will get rounded up to a divider value of 2 giving the following result.
> 
> root at zynqmp:/ # cat /sys/devices/system/cpu/cpufreq/policy0/cpuinfo_cur_freq
> 599999
> 
> Also, if a user tries to work around this calculation by using any larger
> values, it still will not fix the problem because the driver will use the
> largest opp in kHz which leads to the same calculation error.
> 
> User requests 1200000
> root at zynqmp:/ # echo 1200000 > /sys/devices/system/cpu/cpufreq/policy0/scaling_setspeed
> 
> Driver converts any value greater than 1199999 to the largest opp which is
> 1199999 and then calculates the divider value with the same calculation.
> 
> The calculation will still be:
> 1199999988 / 1199999000 = 1.000001
> 
> This will get rounded up to a divider value of 2 giving the following result.
> 
> root at zynqmp:/ # cat /sys/devices/system/cpu/cpufreq/policy0/cpuinfo_cur_freq
> 599999
> 
> This means there is no way to configure the zynqmp for the fastest opp using
> the current dtsi files.
> 
> To fix this issue, this patch updates the zynqmp opp-table-cpu and
> pss_ref_clk, so the clock rates are calculated correctly.
> 
> root at zynqmp:/sys/kernel/tracing# cat /sys/devices/system/cpu/cpufreq/policy0/scaling_available_frequencies
> 300000 400000 600000 1200000
> root at zynqmp:/ # echo 1200000 > /sys/devices/system/cpu/cpufreq/policy0/scaling_setspeed
> root at zynqmp:/ # cat /sys/devices/system/cpu/cpufreq/policy0/cpuinfo_cur_freq
> 1200000
> 
> Signed-off-by: Neal Frager <neal.frager at amd.com>
> ---
> V1->V2:
> - The clock-latency-ns and opp-microvolt values did not change, so simplify
>    the patch by only changing the opp-hz values in decimal format.
> V2->V3:
> - Improved commit explanation
> - Added pss_ref_clk frequency change to the patch
> ---
>   arch/arm64/boot/dts/xilinx/zynqmp-clk-ccf.dtsi |  2 +-
>   arch/arm64/boot/dts/xilinx/zynqmp.dtsi         | 16 ++++++++--------
>   2 files changed, 9 insertions(+), 9 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-clk-ccf.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp-clk-ccf.dtsi
> index 52e122fc7c9e..482f432ba7f3 100644
> --- a/arch/arm64/boot/dts/xilinx/zynqmp-clk-ccf.dtsi
> +++ b/arch/arm64/boot/dts/xilinx/zynqmp-clk-ccf.dtsi
> @@ -14,7 +14,7 @@ pss_ref_clk: pss-ref-clk {
>   		bootph-all;
>   		compatible = "fixed-clock";
>   		#clock-cells = <0>;
> -		clock-frequency = <33333333>;
> +		clock-frequency = <33333000>;
>   		clock-output-names = "pss_ref_clk";
>   	};
>   
> diff --git a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi
> index 938b014ca923..dd9bd39f61e8 100644
> --- a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi
> +++ b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi
> @@ -103,23 +103,23 @@ CPU_SLEEP_0: cpu-sleep-0 {
>   	cpu_opp_table: opp-table-cpu {
>   		compatible = "operating-points-v2";
>   		opp-shared;
> -		opp00 {
> -			opp-hz = /bits/ 64 <1199999988>;
> +		opp-1200000000 {
> +			opp-hz = /bits/ 64 <1200000000>;
>   			opp-microvolt = <1000000>;
>   			clock-latency-ns = <500000>;
>   		};
> -		opp01 {
> -			opp-hz = /bits/ 64 <599999994>;
> +		opp-600000000 {
> +			opp-hz = /bits/ 64 <600000000>;
>   			opp-microvolt = <1000000>;
>   			clock-latency-ns = <500000>;
>   		};
> -		opp02 {
> -			opp-hz = /bits/ 64 <399999996>;
> +		opp-400000000 {
> +			opp-hz = /bits/ 64 <400000000>;
>   			opp-microvolt = <1000000>;
>   			clock-latency-ns = <500000>;
>   		};
> -		opp03 {
> -			opp-hz = /bits/ 64 <299999997>;
> +		opp-300000000 {
> +			opp-hz = /bits/ 64 <300000000>;
>   			opp-microvolt = <1000000>;
>   			clock-latency-ns = <500000>;
>   		};

Applied.
M


From michal.simek at amd.com  Mon Dec 15 00:02:05 2025
From: michal.simek at amd.com (Michal Simek)
Date: Mon, 15 Dec 2025 09:02:05 +0100
Subject: [PATCH] arm64: zynqmp: Remove ina260 IIO description
Message-ID: <7e57f76deca9e73be3fcb914aed119f567c9bf8a.1765785722.git.michal.simek@amd.com>

Kernel has only hwmon driver that's why there is no reason to wire iio to
hwmon converter which was describing out of tree ina260 IIO.

Signed-off-by: Michal Simek <michal.simek at amd.com>
---

Upstreaming of ina260 IIO driver was tried here.
https://lore.kernel.org/all/20210322105056.30571-1-raviteja.narayanam at xilinx.com/
---
 arch/arm64/boot/dts/xilinx/zynqmp-sck-kd-g-revA.dtso | 6 ------
 arch/arm64/boot/dts/xilinx/zynqmp-sck-kr-g-revA.dtso | 6 ------
 arch/arm64/boot/dts/xilinx/zynqmp-sck-kr-g-revB.dtso | 6 ------
 arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revA.dtso | 6 ------
 arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revB.dtso | 6 ------
 5 files changed, 30 deletions(-)

diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kd-g-revA.dtso b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kd-g-revA.dtso
index 02be5e1e8686..832dc5ab2458 100644
--- a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kd-g-revA.dtso
+++ b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kd-g-revA.dtso
@@ -26,11 +26,6 @@ aliases {
 		ethernet0 = "/axi/ethernet at ff0c0000"; /* &gem1 */
 	};
 
-	ina260-u3 {
-		compatible = "iio-hwmon";
-		io-channels = <&u3 0>, <&u3 1>, <&u3 2>;
-	};
-
 	clk_26: clock2 { /* u17 - USB */
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
@@ -67,7 +62,6 @@ &i2c1 { /* I2C_SCK C26/C27 - MIO from SOM */
 
 	u3: ina260 at 40 { /* u3 */
 		compatible = "ti,ina260";
-		#io-channel-cells = <1>;
 		label = "ina260-u14";
 		reg = <0x40>;
 	};
diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kr-g-revA.dtso b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kr-g-revA.dtso
index b92dcb86e87e..b88efcce0162 100644
--- a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kr-g-revA.dtso
+++ b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kr-g-revA.dtso
@@ -25,11 +25,6 @@ aliases {
 		ethernet1 = "/axi/ethernet at ff0c0000"; /* &gem1 */
 	};
 
-	ina260-u14 {
-		compatible = "iio-hwmon";
-		io-channels = <&u14 0>, <&u14 1>, <&u14 2>;
-	};
-
 	clk_27: clock0 { /* u86 - DP */
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
@@ -95,7 +90,6 @@ &i2c1 { /* I2C_SCK C26/C27 - MIO from SOM */
 
 	u14: ina260 at 40 { /* u14 */
 		compatible = "ti,ina260";
-		#io-channel-cells = <1>;
 		label = "ina260-u14";
 		reg = <0x40>;
 	};
diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kr-g-revB.dtso b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kr-g-revB.dtso
index 99ad220d13d6..817797b21679 100644
--- a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kr-g-revB.dtso
+++ b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kr-g-revB.dtso
@@ -25,11 +25,6 @@ aliases {
 		ethernet1 = "/axi/ethernet at ff0c0000"; /* &gem1 */
 	};
 
-	ina260-u14 {
-		compatible = "iio-hwmon";
-		io-channels = <&u14 0>, <&u14 1>, <&u14 2>;
-	};
-
 	clk_125: clock0 { /* u87 - GEM0/1 */
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
@@ -96,7 +91,6 @@ &i2c1 { /* I2C_SCK C26/C27 - MIO from SOM */
 
 	u14: ina260 at 40 { /* u14 */
 		compatible = "ti,ina260";
-		#io-channel-cells = <1>;
 		label = "ina260-u14";
 		reg = <0x40>;
 	};
diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revA.dtso b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revA.dtso
index d7351a17d3e8..923a70d750bf 100644
--- a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revA.dtso
+++ b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revA.dtso
@@ -32,11 +32,6 @@ aliases {
 		ethernet0 = "/axi/ethernet at ff0e0000"; /* &gem3 */
 	};
 
-	ina260-u14 {
-		compatible = "iio-hwmon";
-		io-channels = <&u14 0>, <&u14 1>, <&u14 2>;
-	};
-
 	si5332_0: si5332-0 { /* u17 */
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
@@ -96,7 +91,6 @@ &i2c1 { /* I2C_SCK C23/C24 - MIO from SOM */
 
 	u14: ina260 at 40 { /* u14 */
 		compatible = "ti,ina260";
-		#io-channel-cells = <1>;
 		label = "ina260-u14";
 		reg = <0x40>;
 	};
diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revB.dtso b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revB.dtso
index a4ae37ebaccf..563e750b0e08 100644
--- a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revB.dtso
+++ b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revB.dtso
@@ -27,11 +27,6 @@ aliases {
 		ethernet0 = "/axi/ethernet at ff0e0000"; /* &gem3 */
 	};
 
-	ina260-u14 {
-		compatible = "iio-hwmon";
-		io-channels = <&u14 0>, <&u14 1>, <&u14 2>;
-	};
-
 	si5332_0: si5332-0 { /* u17 */
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
@@ -92,7 +87,6 @@ &i2c1 { /* I2C_SCK C23/C24 - MIO from SOM */
 
 	u14: ina260 at 40 { /* u14 */
 		compatible = "ti,ina260";
-		#io-channel-cells = <1>;
 		label = "ina260-u14";
 		reg = <0x40>;
 	};
-- 
2.43.0

base-commit: 138cb5c1bc67058542ea83109dd6e2d0d2451528


From michal.simek at amd.com  Mon Dec 15 00:04:56 2025
From: michal.simek at amd.com (Michal Simek)
Date: Mon, 15 Dec 2025 09:04:56 +0100
Subject: [PATCH] xilinx_hwicap: fifo_icap.c: fix all kernel-doc warnings
In-Reply-To: <20251214191750.2173225-1-rdunlap@infradead.org>
References: <20251214191750.2173225-1-rdunlap@infradead.org>
Message-ID: <efb1de24-059d-4bd0-8578-d3f47ef8e432@amd.com>



On 12/14/25 20:17, Randy Dunlap wrote:
> Modify comments in fifo_icap.c to prevent all kernel-doc warnings:
> 
> Warning: fifo_icap.c:51 This comment starts with '/**', but isn't a
>   kernel-doc comment.
>   * HwIcap Device Interrupt Status/Enable Registers
> Warning: fifo_icap.c:106 No description found for return value
>   of 'fifo_icap_fifo_read'
> Warning: fifo_icap.c:160 No description found for return value
>   of 'fifo_icap_get_status'
> Warning: fifo_icap.c:171 No description found for return value
>   of 'fifo_icap_busy'
> Warning: fifo_icap.c:184 No description found for return value
>   of 'fifo_icap_write_fifo_vacancy'
> Warning: fifo_icap.c:196 No description found for return value
>   of 'fifo_icap_read_fifo_occupancy'
> Warning: fifo_icap.c:207 bad line:
> Warning: fifo_icap.c:214 No description found for return value
>   of 'fifo_icap_set_configuration'
> Warning: fifo_icap.c:290 function parameter 'frame_buffer' not described
>   in 'fifo_icap_get_configuration'
> Warning: fifo_icap.c:290 function parameter 'num_words' not described
>   in 'fifo_icap_get_configuration'
> Warning: fifo_icap.c:290 No description found for return value
>   of 'fifo_icap_get_configuration'
> Warning: fifo_icap.c:357 expecting prototype for buffer_icap_reset().
>   Prototype was for fifo_icap_reset() instead
> 
> Signed-off-by: Randy Dunlap <rdunlap at infradead.org>
> ---
> Cc: Arnd Bergmann <arnd at arndb.de>
> Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
> Cc: Michal Simek <michal.simek at amd.com>
> Cc: linux-arm-kernel at lists.infradead.org
> ---
>   drivers/char/xilinx_hwicap/fifo_icap.c |   27 ++++++++++++++++-------
>   1 file changed, 19 insertions(+), 8 deletions(-)
> 
> --- linux-next-20251128.orig/drivers/char/xilinx_hwicap/fifo_icap.c
> +++ linux-next-20251128/drivers/char/xilinx_hwicap/fifo_icap.c
> @@ -48,7 +48,7 @@
>   
>   #define XHI_GIER_GIE_MASK 0x80000000 /* Global Interrupt enable Mask */
>   
> -/**
> +/*
>    * HwIcap Device Interrupt Status/Enable Registers
>    *
>    * Interrupt Status Register (IPISR) : This register holds the
> @@ -102,6 +102,8 @@ static inline void fifo_icap_fifo_write(
>    * @drvdata: a pointer to the drvdata.
>    *
>    * This function will silently fail if the fifo is empty.
> + *
> + * Returns: 32-bit data from the Read FIFO
>    **/
>   static inline u32 fifo_icap_fifo_read(struct hwicap_drvdata *drvdata)
>   {
> @@ -156,6 +158,8 @@ static inline void fifo_icap_start_readb
>    * D2 - Always 1
>    * D1 - Always 1
>    * D0 - Done bit
> + *
> + * Returns: the 32-bit ICAP status register
>    **/
>   u32 fifo_icap_get_status(struct hwicap_drvdata *drvdata)
>   {
> @@ -165,8 +169,11 @@ u32 fifo_icap_get_status(struct hwicap_d
>   }
>   
>   /**
> - * fifo_icap_busy - Return true if the ICAP is still processing a transaction.
> + * fifo_icap_busy - Check the ICAP busy status.
>    * @drvdata: a pointer to the drvdata.
> + *
> + * Returns: %true if the ICAP is still processing a transaction,
> + *	otherwise %false
>    **/
>   static inline u32 fifo_icap_busy(struct hwicap_drvdata *drvdata)
>   {
> @@ -178,7 +185,7 @@ static inline u32 fifo_icap_busy(struct
>    * fifo_icap_write_fifo_vacancy - Query the write fifo available space.
>    * @drvdata: a pointer to the drvdata.
>    *
> - * Return the number of words that can be safely pushed into the write fifo.
> + * Returns: the number of words that can be safely pushed into the write fifo.
>    **/
>   static inline u32 fifo_icap_write_fifo_vacancy(
>   		struct hwicap_drvdata *drvdata)
> @@ -190,7 +197,7 @@ static inline u32 fifo_icap_write_fifo_v
>    * fifo_icap_read_fifo_occupancy - Query the read fifo available data.
>    * @drvdata: a pointer to the drvdata.
>    *
> - * Return the number of words that can be safely read from the read fifo.
> + * Returns: the number of words that can be safely read from the read fifo.
>    **/
>   static inline u32 fifo_icap_read_fifo_occupancy(
>   		struct hwicap_drvdata *drvdata)
> @@ -205,10 +212,12 @@ static inline u32 fifo_icap_read_fifo_oc
>    *		ICAP device.
>    * @num_words: the number of words (32 bit) to write to the ICAP
>    *		device.
> -
> + *
>    * This function writes the given user data to the Write FIFO in
>    * polled mode and starts the transfer of the data to
>    * the ICAP device.
> + *
> + * Returns: %0 on success or %-errno on failure.
>    **/
>   int fifo_icap_set_configuration(struct hwicap_drvdata *drvdata,
>   		u32 *frame_buffer, u32 num_words)
> @@ -280,11 +289,13 @@ int fifo_icap_set_configuration(struct h
>   /**
>    * fifo_icap_get_configuration - Read configuration data from the device.
>    * @drvdata: a pointer to the drvdata.
> - * @data: Address of the data representing the partial bitstream
> - * @size: the size of the partial bitstream in 32 bit words.
> + * @frame_buffer: Address of the data representing the partial bitstream
> + * @num_words: the size of the partial bitstream in 32 bit words.
>    *
>    * This function reads the specified number of words from the ICAP device in
>    * the polled mode.
> + *
> + * Returns: %0 on success or %-errno on failure.
>    */
>   int fifo_icap_get_configuration(struct hwicap_drvdata *drvdata,
>   		u32 *frame_buffer, u32 num_words)
> @@ -347,7 +358,7 @@ int fifo_icap_get_configuration(struct h
>   }
>   
>   /**
> - * buffer_icap_reset - Reset the logic of the icap device.
> + * fifo_icap_reset - Reset the logic of the icap device.
>    * @drvdata: a pointer to the drvdata.
>    *
>    * This function forces the software reset of the complete HWICAP device.

Reviewed-by: Michal Simek <michal.simek at amd.com>

Thanks,
Michal


From michal.simek at amd.com  Mon Dec 15 00:28:00 2025
From: michal.simek at amd.com (Michal Simek)
Date: Mon, 15 Dec 2025 09:28:00 +0100
Subject: [PATCH] cpuidle: zynq: Switch Michal Simek's email to new one
Message-ID: <ebfbf945d90b0efff3ce0dc17fb7f1f0db5b6628.1765787278.git.michal.simek@amd.com>

@xilinx.com is still working but better to switch to new amd.com after
AMD/Xilinx acquisition.

Signed-off-by: Michal Simek <michal.simek at amd.com>
---

 drivers/cpuidle/cpuidle-zynq.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/cpuidle/cpuidle-zynq.c b/drivers/cpuidle/cpuidle-zynq.c
index a79610e723b3..89448ae4845c 100644
--- a/drivers/cpuidle/cpuidle-zynq.c
+++ b/drivers/cpuidle/cpuidle-zynq.c
@@ -11,7 +11,7 @@
  * #1 wait-for-interrupt
  * #2 wait-for-interrupt and RAM self refresh
  *
- * Maintainer: Michal Simek <michal.simek at xilinx.com>
+ * Maintainer: Michal Simek <michal.simek at amd.com>
  */
 
 #include <linux/init.h>
-- 
2.43.0

base-commit: dc5aef63c037562500723d0041e863a092997124
branch: zynqmp/soc


From michal.simek at amd.com  Mon Dec 15 00:28:29 2025
From: michal.simek at amd.com (Michal Simek)
Date: Mon, 15 Dec 2025 09:28:29 +0100
Subject: [PATCH] fpga: xilinx: Switch Michal Simek's email to new one
Message-ID: <49de9536c9952a3a36bb996f2fb0a1f0efb1ba6f.1765787307.git.michal.simek@amd.com>

@xilinx.com is still working but better to switch to new amd.com after
AMD/Xilinx acquisition.

Signed-off-by: Michal Simek <michal.simek at amd.com>
---

 drivers/fpga/xilinx-pr-decoupler.c | 2 +-
 drivers/fpga/zynq-fpga.c           | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/fpga/xilinx-pr-decoupler.c b/drivers/fpga/xilinx-pr-decoupler.c
index 822751fad18a..6994d68e9036 100644
--- a/drivers/fpga/xilinx-pr-decoupler.c
+++ b/drivers/fpga/xilinx-pr-decoupler.c
@@ -173,5 +173,5 @@ module_platform_driver(xlnx_pr_decoupler_driver);
 
 MODULE_DESCRIPTION("Xilinx Partial Reconfiguration Decoupler");
 MODULE_AUTHOR("Moritz Fischer <mdf at kernel.org>");
-MODULE_AUTHOR("Michal Simek <michal.simek at xilinx.com>");
+MODULE_AUTHOR("Michal Simek <michal.simek at amd.com>");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/fpga/zynq-fpga.c b/drivers/fpga/zynq-fpga.c
index b7629a0e4813..9d1d599ef718 100644
--- a/drivers/fpga/zynq-fpga.c
+++ b/drivers/fpga/zynq-fpga.c
@@ -652,6 +652,6 @@ static struct platform_driver zynq_fpga_driver = {
 module_platform_driver(zynq_fpga_driver);
 
 MODULE_AUTHOR("Moritz Fischer <moritz.fischer at ettus.com>");
-MODULE_AUTHOR("Michal Simek <michal.simek at xilinx.com>");
+MODULE_AUTHOR("Michal Simek <michal.simek at amd.com>");
 MODULE_DESCRIPTION("Xilinx Zynq FPGA Manager");
 MODULE_LICENSE("GPL v2");
-- 
2.43.0

base-commit: ebfbf945d90b0efff3ce0dc17fb7f1f0db5b6628
branch: zynqmp/soc


From marco.crivellari at suse.com  Mon Dec 15 00:38:49 2025
From: marco.crivellari at suse.com (Marco Crivellari)
Date: Mon, 15 Dec 2025 09:38:49 +0100
Subject: [PATCH] soc/xilinx: replace use of system_unbound_wq with system_dfl_wq
In-Reply-To: <7e44d434-faf2-4f14-9427-9e6173912d15@amd.com>
References: <20251104103942.96647-1-marco.crivellari@suse.com> <7e44d434-faf2-4f14-9427-9e6173912d15@amd.com>
Message-ID: <CAAofZF6X8HSkJnK3UEoP9M1yN52XRy+U=Dh7YWGvbtxYqvsD5A@mail.gmail.com>

On Mon, Dec 15, 2025 at 8:47?AM Michal Simek <michal.simek at amd.com> wrote:
> Applied.

Many thanks!



-- 

Marco Crivellari

L3 Support Engineer


From james.clark at linaro.org  Mon Dec 15 00:40:04 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 15 Dec 2025 10:40:04 +0200
Subject: [PATCH v2 2/2] perf c2c: Update documentation for adding memory
 event table
In-Reply-To: <20251212-perf_c2c_update_event-v2-2-27df9a6cb1d4@arm.com>
References: <20251212-perf_c2c_update_event-v2-0-27df9a6cb1d4@arm.com>
 <20251212-perf_c2c_update_event-v2-2-27df9a6cb1d4@arm.com>
Message-ID: <651e1a79-356f-4f86-a6c3-8119f1c6c98f@linaro.org>



On 12/12/2025 19:25, Leo Yan wrote:
> Users may occasionally need to see which options are applied to memory
> events.  This helps to understand the behavior of "perf c2c" and
> "perf mem", and provides guidance for configuring memory event options
> directly.
> 
> Add a table to track memory events and their corresponding options, and
> include the Arm SPE events in it.
> 
> Suggested-by: Al Grant <al.grant at arm.com>
> Signed-off-by: Leo Yan <leo.yan at arm.com>

Reviewed-by: James Clark <james.clark at linaro.org>

> ---
>   tools/perf/Documentation/perf-c2c.txt | 51 +++++++++++++++++++++++++----------
>   1 file changed, 37 insertions(+), 14 deletions(-)
> 
> diff --git a/tools/perf/Documentation/perf-c2c.txt b/tools/perf/Documentation/perf-c2c.txt
> index 40b0f71a2c44eb642ff3bb234631a614b7c4fc9d..e57a122b8719f1b2e20dd509959fc1563a6c20fd 100644
> --- a/tools/perf/Documentation/perf-c2c.txt
> +++ b/tools/perf/Documentation/perf-c2c.txt
> @@ -160,20 +160,43 @@ Following perf record options are configured by default:
>   
>     -W,-d,--phys-data,--sample-cpu
>   
> -Unless specified otherwise with '-e' option, following events are monitored by
> -default on Intel:
> -
> -  cpu/mem-loads,ldlat=30/P
> -  cpu/mem-stores/P
> -
> -following on AMD:
> -
> -  ibs_op//
> -
> -and following on PowerPC:
> -
> -  cpu/mem-loads/
> -  cpu/mem-stores/
> +The following table lists the events monitored on different architectures.
> +Unless specified otherwise with the -e option, the tool will select the
> +default events.
> +
> +  +--------+---------------+-----------------+--------------------------------------------------------------------------------+
> +  | Arch   | Configuration | Options         | Events                                                                         |
> +  +--------+---------------+-----------------+--------------------------------------------------------------------------------+
> +  | Intel  | Default       | -e ldlat-loads  | cpu/mem-loads,ldlat=30/P                                                       |
> +  |        |               | -e ldlat-stores | cpu/mem-stores/P                                                               |
> +  |        |---------------+-----------------+--------------------------------------------------------------------------------+
> +  |        | Load only     | -e ldlat-loads  | cpu/mem-loads,ldlat=30/P                                                       |
> +  |        |---------------+-----------------+--------------------------------------------------------------------------------+
> +  |        | Store only    | -e ldlat-stores | cpu/mem-stores/P                                                               |
> +  +--------+---------------+-----------------+--------------------------------------------------------------------------------+
> +  | Intel  | Default       | -e ldlat-loads  | {cpu/mem-loads-aux/,cpu/mem-loads,ldlat=30/}:P                                 |
> +  | with   |               | -e ldlat-stores | cpu/mem-stores/P                                                               |
> +  | AUX    |--------------+------------------+--------------------------------------------------------------------------------+
> +  |        | Load only     | -e ldlat-loads  | {cpu/mem-loads-aux/,cpu/mem-loads,ldlat=30/}:P                                 |
> +  |        |---------------+-----------------+--------------------------------------------------------------------------------+
> +  |        | Store only    | -e ldlat-stores | cpu/mem-stores/P                                                               |
> +  +--------+---------------+-----------------+--------------------------------------------------------------------------------+
> +  | AMD    | Default       | -e mem-ldst     | ibs_op// (without latency support)                                             |
> +  |        |               |                 | ibs_op/ldlat=30/ (with latency support)                                        |
> +  +--------+---------------+-----------------+--------------------------------------------------------------------------------+
> +  | PowerPC| Default       | -e ldlat-loads  | cpu/mem-loads/                                                                 |
> +  |        |               | -e ldlat-stores | cpu/mem-stores/                                                                |
> +  |        |---------------+-----------------+--------------------------------------------------------------------------------+
> +  |        | Load only     | -e ldlat-loads  | cpu/mem-loads/                                                                 |
> +  |        |---------------+-----------------+--------------------------------------------------------------------------------+
> +  |        | Store only    | -e ldlat-stores | cpu/mem-stores/                                                                |
> +  +--------+---------------+-----------------+--------------------------------------------------------------------------------+
> +  | Arm    | Default       | -e spe-ldst     | arm_spe_0/ts_enable=1,pa_enable=1,load_filter=1,store_filter=1,min_latency=30/ |
> +  | SPE    |---------------+-----------------+--------------------------------------------------------------------------------+
> +  |        | Load only     | -e spe-load     | arm_spe_0/ts_enable=1,pa_enable=1,load_filter=1,min_latency=30/                |
> +  |        |---------------+-----------------+--------------------------------------------------------------------------------+
> +  |        | Store only    | -e spe-store    | arm_spe_0/ts_enable=1,pa_enable=1,store_filter=1/                              |
> +  +--------+---------------+-----------------+--------------------------------------------------------------------------------+
>   
>   User can pass any 'perf record' option behind '--' mark, like (to enable
>   callchains and system wide monitoring):
> 



From arnd at arndb.de  Mon Dec 15 00:40:10 2025
From: arnd at arndb.de (Arnd Bergmann)
Date: Mon, 15 Dec 2025 09:40:10 +0100
Subject: [PATCH] arm64: perf: fix syscalltbl path base
In-Reply-To: <b2651f20-6f3a-49f5-9cd8-3fb028b2cab5@app.fastmail.com>
References: <b2651f20-6f3a-49f5-9cd8-3fb028b2cab5@app.fastmail.com>
Message-ID: <fcc6ada2-8a4d-4989-b257-e4ba17d5d14b@app.fastmail.com>

On Sun, Dec 14, 2025, at 23:12, Joel May wrote:
>
> The problem is that scripts/Makefile.asm-headers is including a relative
> syscalltbl path from arch/arm64/kernel/Makefile.syscalls.  The syscalltbl
> path needs to be based on the srctree root.
>
> Fixes: 7fe33e9f662c0 ("arm64: convert unistd_32.h to syscall.tbl 
> format")
> Fixes: bfb713ea53c74 ("perf tools: Fix arm64 build by generating 
> unistd_64.h")
> Link: 
> https://github.com/truenas/linux/commit/91377b555a57dfa75364d7da85b5e21e41e81625#diff-831a0e8e3eaa7a5ca92599e58771b8a6b2c4bd7533f627e33138873995aac61eR147
> Signed-off-by: Joel May <joel-linux at jmay.us>

Reviewed-by: Arnd Bergmann <arnd at arndb.de>


From yanan.yang at nxp.com  Mon Dec 15 00:42:51 2025
From: yanan.yang at nxp.com (Yanan Yang)
Date: Mon, 15 Dec 2025 17:42:51 +0900
Subject: [PATCH v2 1/2] dt-bindings: arm: fsl: Add FRDM-IMX91S board
In-Reply-To: <20251215-imx91s-frdm-v2-0-87996bdaa59c@nxp.com>
References: <20251215-imx91s-frdm-v2-0-87996bdaa59c@nxp.com>
Message-ID: <20251215-imx91s-frdm-v2-1-87996bdaa59c@nxp.com>

Add DT compatible string for NXP FRDM-IMX91S board

The FRDM-IMX91S is a low-cost, compact development board based on the
i.MX91 applications processor. It is a cost-optimized variant of the
FRDM-IMX91 board, with notable hardware differences requiring a separate
DTS:
- 512MB LPDDR4 (FRDM-IMX91 uses 1GB)
- 256MB FlexSPI-NAND (FRDM-IMX91 uses 8GB eMMC)
- Single GbE port (FRDM-IMX91 has dual GbE)
- PMIC PF9453 (FRDM-IMX91 uses PCA9451A)

Signed-off-by: Yanan Yang <yanan.yang at nxp.com>

---
Changes in v2:
- Correct author name: removed extra period in "Yanan.Yang"
- Refined commit message to clarify board differences
---
 Documentation/devicetree/bindings/arm/fsl.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
index 68a2d5fecc43..82f28be401b8 100644
--- a/Documentation/devicetree/bindings/arm/fsl.yaml
+++ b/Documentation/devicetree/bindings/arm/fsl.yaml
@@ -1412,6 +1412,7 @@ properties:
         items:
           - enum:
               - fsl,imx91-11x11-evk       # i.MX91 11x11 EVK Board
+              - fsl,imx91-11x11-frdm-s    # FRDM-IMX91S Board
           - const: fsl,imx91
 
       - description: i.MX93 based Boards

-- 
2.43.0



From yanan.yang at nxp.com  Mon Dec 15 00:42:50 2025
From: yanan.yang at nxp.com (Yanan Yang)
Date: Mon, 15 Dec 2025 17:42:50 +0900
Subject: [PATCH v2 0/2] Add NXP FRDM-IMX91S board support
Message-ID: <20251215-imx91s-frdm-v2-0-87996bdaa59c@nxp.com>

This patch set introduces DeviceTree support for the NXP FRDM-IMX91S
development board based on the i.MX91 SoC. FRDM-IMX91S is a cost-optimized
variant of FRDM-IMX91 and differs in several hardware aspects:

- 512MB LPDDR4 (FRDM-IMX91 uses 1GB)
- 256MB FlexSPI-NAND (FRDM-IMX91 uses 8GB eMMC)
- Single GbE port (FRDM-IMX91 has dual GbE)
- PMIC PF9453 (FRDM-IMX91 uses PCA9451A)

This patch has been tested on FRDM-IMX91S board and verified for basic
functionality.

For more details about the FRDM-IMX91S board, see:
https://www.nxp.com/design/design-center/development-boards-and-designs/FRDM-IMX91S

Signed-off-by: Yanan Yang <yanan.yang at nxp.com>
---
Changes in v2:
- Correct author name: removed extra period in "Yanan.Yang"
- Removed aliases pointing to disabled nodes from DTS
- Add "rtc0 = &pcf2131;" in aliases to make external RTC the primary device
- Fix DT node name: change
  "usdhc1_pwrseq: usdhc1_pwrseq" to "usdhc1_pwrseq: usdhc1-pwrseq"
- Renamed LED node from 'status' to 'led-0' to comply with gpio-leds binding
- Replace regulator-based transceiver (reg_can_stby) with CAN PHY (nxp,tja1051)
- Replaced 'xceiver-supply' property with 'phys' in flexcan1 node
- Adjusted alignment in fsl,pins property: used spaces between pin names and values for proper DTS style.
- Refined commit message in dt binding patch to clarify board differences
- Link to v1: https://lore.kernel.org/r/20251205-imx91s-frdm-v1-0-afd6cd01c299 at nxp.com

---
Yanan Yang (2):
      dt-bindings: arm: fsl: Add FRDM-IMX91S board
      arm64: dts: freescale: add NXP FRDM-IMX91S board support

 Documentation/devicetree/bindings/arm/fsl.yaml     |   1 +
 arch/arm64/boot/dts/freescale/Makefile             |   1 +
 .../boot/dts/freescale/imx91-11x11-frdm-s.dts      | 677 +++++++++++++++++++++
 3 files changed, 679 insertions(+)
---
base-commit: bc04acf4aeca588496124a6cf54bfce3db327039
change-id: 20251205-imx91s-frdm-2c339bcc2f6f

Best regards,
-- 
Yanan Yang <yanan.yang at nxp.com>



From yanan.yang at nxp.com  Mon Dec 15 00:42:52 2025
From: yanan.yang at nxp.com (Yanan Yang)
Date: Mon, 15 Dec 2025 17:42:52 +0900
Subject: [PATCH v2 2/2] arm64: dts: freescale: add NXP FRDM-IMX91S board
 support
In-Reply-To: <20251215-imx91s-frdm-v2-0-87996bdaa59c@nxp.com>
References: <20251215-imx91s-frdm-v2-0-87996bdaa59c@nxp.com>
Message-ID: <20251215-imx91s-frdm-v2-2-87996bdaa59c@nxp.com>

Add DeviceTree support for the NXP FRDM-IMX91S development board based
on the i.MX91 SoC. FRDM-IMX91S is a cost-optimized variant of FRDM-IMX91
and differs in memory, storage, Ethernet, and PMIC configuration:

- 512MB LPDDR4 (FRDM-IMX91 uses 1GB)
- 256MB FlexSPI-NAND (FRDM-IMX91 uses 8GB eMMC)
- Single GbE port (FRDM-IMX91 has dual GbE)
- PMIC PF9453 (FRDM-IMX91 uses PCA9451A)

This DT enables:
- ADC1
- UART1 and UART5
- I2C bus and children nodes
- USB and related nodes
- uSDHC1 and uSDHC2
- FlexSPI NAND flash
- Watchdog3
- Ethernet (eqos)
- FlexCAN
- MQS

Link: https://www.nxp.com/design/design-center/development-boards-and-designs/FRDM-IMX91S
(FRDM-IMX91S board page)
Link: https://www.nxp.com/design/design-center/development-boards-and-designs/FRDM-IMX91
(FRDM-IMX91 board page)

Co-developed-by: Lei Xu <lei.xu at nxp.com>
Signed-off-by: Lei Xu <lei.xu at nxp.com>
Co-developed-by: Xiaofeng Wei <xiaofeng.wei at nxp.com>
Signed-off-by: Xiaofeng Wei <xiaofeng.wei at nxp.com>
Signed-off-by: Yanan Yang <yanan.yang at nxp.com>

---
Changes in v2:
- Correct author name: removed extra period in "Yanan.Yang"
- Removed aliases pointing to disabled nodes from DTS
- Add "rtc0 = &pcf2131;" in aliases to make external RTC the primary device
- Fix DT node name: change
  "usdhc1_pwrseq: usdhc1_pwrseq" to "usdhc1_pwrseq: usdhc1-pwrseq"
- Renamed LED node from 'status' to 'led-0' to comply with gpio-leds binding
- Replace regulator-based transceiver (reg_can_stby) with CAN PHY (nxp,tja1051)
- Replaced 'xceiver-supply' property with 'phys' in flexcan1 node
- Adjusted alignment in fsl,pins property: used spaces between pin names and values for proper DTS style.
---
 arch/arm64/boot/dts/freescale/Makefile             |   1 +
 .../boot/dts/freescale/imx91-11x11-frdm-s.dts      | 677 +++++++++++++++++++++
 2 files changed, 678 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index f30d3fd724d0..927bf76a05f3 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -368,6 +368,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8qxp-tqma8xqps-mb-smarc-2.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8ulp-9x9-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8ulp-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx91-11x11-evk.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx91-11x11-frdm-s.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx91-phyboard-segin.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx91-tqma9131-mba91xxca.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx93-9x9-qsb.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx91-11x11-frdm-s.dts b/arch/arm64/boot/dts/freescale/imx91-11x11-frdm-s.dts
new file mode 100644
index 000000000000..9ab29d1b979e
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx91-11x11-frdm-s.dts
@@ -0,0 +1,677 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2025 NXP
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/usb/pd.h>
+#include "imx91.dtsi"
+
+/ {
+	compatible = "fsl,imx91-11x11-frdm-s", "fsl,imx91";
+	model = "NXP FRDM-IMX91S board";
+
+	aliases {
+		ethernet0 = &eqos;
+		gpio0 = &gpio1;
+		gpio1 = &gpio2;
+		gpio2 = &gpio3;
+		i2c0 = &lpi2c1;
+		i2c1 = &lpi2c2;
+		mmc0 = &usdhc1;
+		mmc1 = &usdhc2;
+		rtc0 = &pcf2131;
+		rtc1 = &bbnsm_rtc;
+		serial0 = &lpuart1;
+		serial4 = &lpuart5;
+	};
+
+	chosen {
+		stdout-path = &lpuart1;
+	};
+
+	flexcan1_phy: can-phy {
+		compatible = "nxp,tja1051";
+		#phy-cells = <0>;
+		max-bitrate = <5000000>;
+		silent-gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>;
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+		pinctrl-0 = <&pinctrl_gpio_key>;
+		pinctrl-names = "default";
+
+		button {
+			interrupt-parent = <&gpio3>;
+			interrupts = <26 IRQ_TYPE_EDGE_FALLING>;
+			gpios = <&gpio3 26 GPIO_PULL_UP>;
+			label = "User Button";
+			linux,code = <BTN_1>;
+		};
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+
+		led-0 {
+			default-state = "on";
+			gpios = <&pcal6524 7 GPIO_ACTIVE_LOW>;
+			label = "green:status";
+		};
+	};
+
+	reg_vref_1v8: regulator-adc-vref {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <1800000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-name = "vref_1v8";
+	};
+
+	reg_usdhc1_vmmc: regulator-usdhc1 {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "WLAN_EN";
+		startup-delay-us = <20000>;
+		gpio = <&pcal6524 3 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_usdhc2_vmmc: regulator-usdhc2 {
+		compatible = "regulator-fixed";
+		off-on-delay-us = <12000>;
+		pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
+		pinctrl-names = "default";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "VSD_3V3";
+		gpio = <&gpio3 7 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_usb_vbus: regulator-vbus {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <5000000>;
+		regulator-min-microvolt = <5000000>;
+		regulator-name = "USB_VBUS";
+		gpio = <&pcal6524 15 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		linux,cma {
+			compatible = "shared-dma-pool";
+			alloc-ranges = <0 0x80000000 0 0x20000000>;
+			reusable;
+			size = <0 0x2000000>;
+			linux,cma-default;
+		};
+	};
+
+	sound-mqs {
+		compatible = "fsl,imx6sx-sdb-mqs", "fsl,imx-audio-mqs";
+		audio-codec = <&mqs1>;
+		audio-cpu = <&sai1>;
+		model = "mqs-audio";
+	};
+
+	usdhc1_pwrseq: usdhc1-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&pcal6524 18 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&adc1 {
+	vref-supply = <&reg_vref_1v8>;
+	status = "okay";
+};
+
+&eqos {
+	phy-handle = <&ethphy1>;
+	phy-mode = "rgmii-id";
+	pinctrl-0 = <&pinctrl_eqos>;
+	pinctrl-1 = <&pinctrl_eqos_sleep>;
+	pinctrl-names = "default", "sleep";
+	status = "okay";
+
+	mdio {
+		compatible = "snps,dwmac-mdio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-frequency = <5000000>;
+
+		ethphy1: ethernet-phy at 4 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <4>;
+		};
+	};
+};
+
+&flexcan1 {
+	phys = <&flexcan1_phy>;
+	pinctrl-0 = <&pinctrl_flexcan1>;
+	pinctrl-1 = <&pinctrl_flexcan1_sleep>;
+	pinctrl-names = "default", "sleep";
+	status = "okay";
+};
+
+&flexspi1 {
+	pinctrl-0 = <&pinctrl_flexspi1>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	flash at 0 {
+		compatible = "spi-nand";
+		reg = <0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		spi-max-frequency = <104000000>;
+		spi-rx-bus-width = <4>;
+		spi-tx-bus-width = <4>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition at 0 {
+				reg = <0x000000 0x800000>;
+				label = "bootloader";
+			};
+
+			partition at 1 {
+				reg = <0x800000 0x800000>;
+				label = "env";
+			};
+
+			partition at 2 {
+				reg = <0x1000000 0x2800000>;
+				label = "kernel";
+			};
+
+			partition at 3 {
+				reg = <0x3800000 0x20000>;
+				label = "dtb";
+			};
+
+			partition at 4 {
+				reg = <0x3820000 0xc7e0000>;
+				label = "rootfs";
+				linux,rootfs;
+			};
+		};
+	};
+};
+
+&iomuxc {
+	pinctrl_eqos: eqosgrp {
+		fsl,pins = <
+			MX91_PAD_ENET1_MDC__ENET1_MDC                           0x57e
+			MX91_PAD_ENET1_MDIO__ENET_QOS_MDIO                      0x57e
+			MX91_PAD_ENET1_RD0__ENET_QOS_RGMII_RD0                  0x57e
+			MX91_PAD_ENET1_RD1__ENET_QOS_RGMII_RD1                  0x57e
+			MX91_PAD_ENET1_RD2__ENET_QOS_RGMII_RD2                  0x57e
+			MX91_PAD_ENET1_RD3__ENET_QOS_RGMII_RD3                  0x57e
+			MX91_PAD_ENET1_RXC__ENET_QOS_RGMII_RXC                  0x5fe
+			MX91_PAD_ENET1_RX_CTL__ENET_QOS_RGMII_RX_CTL            0x57e
+			MX91_PAD_ENET1_TD0__ENET_QOS_RGMII_TD0                  0x57e
+			MX91_PAD_ENET1_TD1__ENET1_RGMII_TD1                     0x57e
+			MX91_PAD_ENET1_TD2__ENET_QOS_RGMII_TD2                  0x57e
+			MX91_PAD_ENET1_TD3__ENET_QOS_RGMII_TD3                  0x57e
+			MX91_PAD_ENET1_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK  0x5fe
+			MX91_PAD_ENET1_TX_CTL__ENET_QOS_RGMII_TX_CTL            0x57e
+		>;
+	};
+
+	pinctrl_eqos_sleep: eqossleepgrp {
+		fsl,pins = <
+			MX91_PAD_ENET1_MDC__GPIO4_IO0                           0x31e
+			MX91_PAD_ENET1_MDIO__GPIO4_IO1                          0x31e
+			MX91_PAD_ENET1_RD0__GPIO4_IO10                          0x31e
+			MX91_PAD_ENET1_RD1__GPIO4_IO11                          0x31e
+			MX91_PAD_ENET1_RD2__GPIO4_IO12                          0x31e
+			MX91_PAD_ENET1_RD3__GPIO4_IO13                          0x31e
+			MX91_PAD_ENET1_RXC__GPIO4_IO9                           0x31e
+			MX91_PAD_ENET1_RX_CTL__GPIO4_IO8                        0x31e
+			MX91_PAD_ENET1_TD0__GPIO4_IO5                           0x31e
+			MX91_PAD_ENET1_TD1__GPIO4_IO4                           0x31e
+			MX91_PAD_ENET1_TD2__GPIO4_IO3                           0x31e
+			MX91_PAD_ENET1_TD3__GPIO4_IO2                           0x31e
+			MX91_PAD_ENET1_TXC__GPIO4_IO7                           0x31e
+			MX91_PAD_ENET1_TX_CTL__GPIO4_IO6                        0x31e
+		>;
+	};
+
+	pinctrl_flexcan1: flexcan1grp {
+		fsl,pins = <
+			MX91_PAD_GPIO_IO28__CAN1_TX                             0x139e
+			MX91_PAD_GPIO_IO29__CAN1_RX                             0x139e
+			MX91_PAD_PDM_BIT_STREAM1__GPIO1_IO10                    0x31e
+		>;
+	};
+
+	pinctrl_flexcan1_sleep: flexcan1sleepgrp {
+		fsl,pins = <
+			MX91_PAD_GPIO_IO28__GPIO2_IO28                          0x31e
+			MX91_PAD_GPIO_IO29__GPIO2_IO29                          0x31e
+			MX91_PAD_PDM_BIT_STREAM1__GPIO1_IO10                    0x31e
+		>;
+	};
+
+	pinctrl_flexspi1: flexspi1grp {
+		fsl,pins = <
+			MX91_PAD_SD3_CLK__FLEXSPI1_A_SCLK                       0x3fe
+			MX91_PAD_SD3_CMD__FLEXSPI1_A_SS0_B                      0x3fe
+			MX91_PAD_SD3_DATA0__FLEXSPI1_A_DATA0                    0x3fe
+			MX91_PAD_SD3_DATA1__FLEXSPI1_A_DATA1                    0x3fe
+			MX91_PAD_SD3_DATA2__FLEXSPI1_A_DATA2                    0x3fe
+			MX91_PAD_SD3_DATA3__FLEXSPI1_A_DATA3                    0x3fe
+		>;
+	};
+
+	pinctrl_gpio_key: gpiokeysgrp {
+		fsl,pins = <
+			MX91_PAD_CCM_CLKO1__GPIO3_IO26                          0x31e
+		>;
+	};
+
+	pinctrl_lpi2c1: lpi2c1grp {
+		fsl,pins = <
+			MX91_PAD_I2C1_SCL__LPI2C1_SCL                           0x40000b9e
+			MX91_PAD_I2C1_SDA__LPI2C1_SDA                           0x40000b9e
+		>;
+	};
+
+	pinctrl_lpi2c2: lpi2c2grp {
+		fsl,pins = <
+			MX91_PAD_I2C2_SCL__LPI2C2_SCL                           0x40000b9e
+			MX91_PAD_I2C2_SDA__LPI2C2_SDA                           0x40000b9e
+		>;
+	};
+
+	pinctrl_mqs1: mqs1grp {
+		fsl,pins = <
+			MX91_PAD_PDM_CLK__MQS1_LEFT                             0x31e
+			MX91_PAD_PDM_BIT_STREAM0__MQS1_RIGHT                    0x31e
+		>;
+	};
+
+	pinctrl_pcal6524: pcal6524grp {
+		fsl,pins = <
+			MX91_PAD_CCM_CLKO2__GPIO3_IO27                          0x31e
+			MX91_PAD_SD1_DATA5__GPIO3_IO15                          0x31e
+		>;
+	};
+
+	pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
+		fsl,pins = <
+			MX91_PAD_SD2_RESET_B__GPIO3_IO7                         0x31e
+		>;
+	};
+
+	pinctrl_uart1: uart1grp {
+		fsl,pins = <
+			MX91_PAD_UART1_RXD__LPUART1_RX                          0x31e
+			MX91_PAD_UART1_TXD__LPUART1_TX                          0x31e
+		>;
+	};
+
+	pinctrl_uart5: uart5grp {
+		fsl,pins = <
+			MX91_PAD_DAP_TDO_TRACESWO__LPUART5_TX                   0x31e
+			MX91_PAD_DAP_TDI__LPUART5_RX                            0x31e
+			MX91_PAD_DAP_TMS_SWDIO__LPUART5_RTS_B                   0x31e
+			MX91_PAD_DAP_TCLK_SWCLK__LPUART5_CTS_B                  0x31e
+		>;
+	};
+
+	pinctrl_usdhc1: usdhc1grp {
+		fsl,pins = <
+			MX91_PAD_SD1_CLK__USDHC1_CLK                            0x1582
+			MX91_PAD_SD1_CMD__USDHC1_CMD                            0x1382
+			MX91_PAD_SD1_DATA0__USDHC1_DATA0                        0x1382
+			MX91_PAD_SD1_DATA1__USDHC1_DATA1                        0x1382
+			MX91_PAD_SD1_DATA2__USDHC1_DATA2                        0x1382
+			MX91_PAD_SD1_DATA3__USDHC1_DATA3                        0x1382
+			MX91_PAD_SD1_DATA4__GPIO3_IO14                          0x31e
+			MX91_PAD_SD1_STROBE__GPIO3_IO18                         0x31e
+		>;
+	};
+
+	pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp {
+		fsl,pins = <
+			MX91_PAD_SD1_CLK__USDHC1_CLK                            0x158e
+			MX91_PAD_SD1_CMD__USDHC1_CMD                            0x138e
+			MX91_PAD_SD1_DATA0__USDHC1_DATA0                        0x138e
+			MX91_PAD_SD1_DATA1__USDHC1_DATA1                        0x138e
+			MX91_PAD_SD1_DATA2__USDHC1_DATA2                        0x138e
+			MX91_PAD_SD1_DATA3__USDHC1_DATA3                        0x138e
+			MX91_PAD_SD1_DATA4__GPIO3_IO14                          0x31e
+			MX91_PAD_SD1_STROBE__GPIO3_IO18                         0x31e
+		>;
+	};
+
+	pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp {
+		fsl,pins = <
+			MX91_PAD_SD1_CLK__USDHC1_CLK                            0x15fe
+			MX91_PAD_SD1_CMD__USDHC1_CMD                            0x13fe
+			MX91_PAD_SD1_DATA0__USDHC1_DATA0                        0x13fe
+			MX91_PAD_SD1_DATA1__USDHC1_DATA1                        0x13fe
+			MX91_PAD_SD1_DATA2__USDHC1_DATA2                        0x13fe
+			MX91_PAD_SD1_DATA3__USDHC1_DATA3                        0x13fe
+			MX91_PAD_SD1_DATA4__GPIO3_IO14                          0x31e
+			MX91_PAD_SD1_STROBE__GPIO3_IO18                         0x31e
+		>;
+	};
+
+	pinctrl_usdhc2_gpio: usdhc2gpiogrp {
+		fsl,pins = <
+			MX91_PAD_SD2_CD_B__GPIO3_IO0                            0x31e
+		>;
+	};
+
+	pinctrl_usdhc2_gpio_sleep: usdhc2gpiosleepgrp {
+		fsl,pins = <
+			MX91_PAD_SD2_CD_B__GPIO3_IO0                            0x51e
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			MX91_PAD_SD2_CLK__USDHC2_CLK                            0x1582
+			MX91_PAD_SD2_CMD__USDHC2_CMD                            0x1382
+			MX91_PAD_SD2_DATA0__USDHC2_DATA0                        0x1382
+			MX91_PAD_SD2_DATA1__USDHC2_DATA1                        0x1382
+			MX91_PAD_SD2_DATA2__USDHC2_DATA2                        0x1382
+			MX91_PAD_SD2_DATA3__USDHC2_DATA3                        0x1382
+			MX91_PAD_SD2_VSELECT__USDHC2_VSELECT                    0x51e
+		>;
+	};
+
+	pinctrl_usdhc2_sleep: usdhc2sleepgrp {
+		fsl,pins = <
+			MX91_PAD_SD2_CLK__GPIO3_IO1                             0x51e
+			MX91_PAD_SD2_CMD__GPIO3_IO2                             0x51e
+			MX91_PAD_SD2_DATA0__GPIO3_IO3                           0x51e
+			MX91_PAD_SD2_DATA1__GPIO3_IO4                           0x51e
+			MX91_PAD_SD2_DATA2__GPIO3_IO5                           0x51e
+			MX91_PAD_SD2_DATA3__GPIO3_IO6                           0x51e
+			MX91_PAD_SD2_VSELECT__GPIO3_IO19                        0x51e
+		>;
+	};
+
+	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+		fsl,pins = <
+			MX91_PAD_SD2_CLK__USDHC2_CLK                            0x158e
+			MX91_PAD_SD2_CMD__USDHC2_CMD                            0x138e
+			MX91_PAD_SD2_DATA0__USDHC2_DATA0                        0x138e
+			MX91_PAD_SD2_DATA1__USDHC2_DATA1                        0x138e
+			MX91_PAD_SD2_DATA2__USDHC2_DATA2                        0x138e
+			MX91_PAD_SD2_DATA3__USDHC2_DATA3                        0x138e
+			MX91_PAD_SD2_VSELECT__USDHC2_VSELECT                    0x51e
+		>;
+	};
+
+	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+		fsl,pins = <
+			MX91_PAD_SD2_CLK__USDHC2_CLK                            0x15fe
+			MX91_PAD_SD2_CMD__USDHC2_CMD                            0x13fe
+			MX91_PAD_SD2_DATA0__USDHC2_DATA0                        0x13fe
+			MX91_PAD_SD2_DATA1__USDHC2_DATA1                        0x13fe
+			MX91_PAD_SD2_DATA2__USDHC2_DATA2                        0x13fe
+			MX91_PAD_SD2_DATA3__USDHC2_DATA3                        0x13fe
+			MX91_PAD_SD2_VSELECT__USDHC2_VSELECT                    0x51e
+		>;
+	};
+
+	pinctrl_wdog: wdoggrp {
+		fsl,pins = <
+			MX91_PAD_WDOG_ANY__WDOG1_WDOG_ANY                       0x31e
+		>;
+	};
+};
+
+&lpi2c1 {
+	clock-frequency = <400000>;
+	pinctrl-0 = <&pinctrl_lpi2c1>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	pcf2131: rtc at 53 {
+		compatible = "nxp,pcf2131";
+		reg = <0x53>;
+		interrupt-parent = <&pcal6524>;
+		interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
+	};
+};
+
+&lpi2c2 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	clock-frequency = <400000>;
+	pinctrl-0 = <&pinctrl_lpi2c2>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	pcal6524: gpio at 22 {
+		compatible = "nxp,pcal6524";
+		reg = <0x22>;
+		#interrupt-cells = <2>;
+		interrupt-controller;
+		interrupt-parent = <&gpio3>;
+		interrupts = <27 IRQ_TYPE_LEVEL_LOW>;
+		#gpio-cells = <2>;
+		gpio-controller;
+		pinctrl-0 = <&pinctrl_pcal6524>;
+		pinctrl-names = "default";
+		reset-gpios = <&gpio3 15 GPIO_ACTIVE_LOW>;
+	};
+
+	pmic at 32 {
+		compatible = "nxp,pf9453";
+		reg = <0x32>;
+		interrupt-parent = <&pcal6524>;
+		interrupts = <10 IRQ_TYPE_EDGE_FALLING>;
+
+		regulators {
+			buck1: BUCK1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <3775000>;
+				regulator-min-microvolt = <600000>;
+				regulator-name = "BUCK1";
+			};
+
+			buck2: BUCK2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <2187500>;
+				regulator-min-microvolt = <600000>;
+				regulator-name = "BUCK2";
+				regulator-ramp-delay = <12500>;
+			};
+
+			buck3: BUCK3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <3775000>;
+				regulator-min-microvolt = <600000>;
+				regulator-name = "BUCK3";
+			};
+
+			buck4: BUCK4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <3775000>;
+				regulator-min-microvolt = <600000>;
+				regulator-name = "BUCK4";
+			};
+
+			ldo1: LDO1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <3300000>;
+				regulator-min-microvolt = <800000>;
+				regulator-name = "LDO1";
+			};
+
+			ldo2: LDO2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <1950000>;
+				regulator-min-microvolt = <500000>;
+				regulator-name = "LDO2";
+			};
+
+			ldo_snvs: LDO-SNVS {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <3400000>;
+				regulator-min-microvolt = <1200000>;
+				regulator-name = "LDO-SNVS";
+			};
+		};
+	};
+
+	ptn5110: tcpc at 52 {
+		compatible = "nxp,ptn5110", "tcpci";
+		reg = <0x52>;
+		interrupt-parent = <&gpio3>;
+		interrupts = <27 IRQ_TYPE_LEVEL_LOW>;
+
+		typec1_con: connector {
+			compatible = "usb-c-connector";
+			data-role = "dual";
+			label = "USB-C";
+			op-sink-microwatt = <15000000>;
+			power-role = "dual";
+			self-powered;
+			sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)
+				     PDO_VAR(5000, 20000, 3000)>;
+			source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
+			try-power-role = "sink";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+
+					typec1_dr_sw: endpoint {
+						remote-endpoint = <&usb1_drd_sw>;
+					};
+				};
+			};
+		};
+	};
+};
+
+&lpuart1 {
+	pinctrl-0 = <&pinctrl_uart1>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&lpuart5 {
+	pinctrl-0 = <&pinctrl_uart5>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	bluetooth {
+		compatible = "nxp,88w8987-bt";
+	};
+};
+
+&media_blk_ctrl {
+	status = "okay";
+};
+
+&mqs1 {
+	clocks = <&clk IMX93_CLK_MQS1_GATE>;
+	clock-names = "mclk";
+	pinctrl-0 = <&pinctrl_mqs1>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&sai1 {
+	clocks = <&clk IMX93_CLK_SAI1_IPG>, <&clk IMX93_CLK_DUMMY>,
+		 <&clk IMX93_CLK_SAI1_GATE>, <&clk IMX93_CLK_DUMMY>,
+		 <&clk IMX93_CLK_DUMMY>, <&clk IMX93_CLK_AUDIO_PLL>;
+	clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3", "pll8k";
+	assigned-clocks = <&clk IMX93_CLK_SAI1>;
+	assigned-clock-parents = <&clk IMX93_CLK_AUDIO_PLL>;
+	assigned-clock-rates = <24576000>;
+	#sound-dai-cells = <0>;
+	fsl,sai-mclk-direction-output;
+	status = "okay";
+};
+
+&usbotg1 {
+	adp-disable;
+	disable-over-current;
+	dr_mode = "otg";
+	hnp-disable;
+	srp-disable;
+	usb-role-switch;
+	samsung,picophy-dc-vol-level-adjust = <7>;
+	samsung,picophy-pre-emp-curr-control = <3>;
+	status = "okay";
+
+	port {
+		usb1_drd_sw: endpoint {
+			remote-endpoint = <&typec1_dr_sw>;
+		};
+	};
+};
+
+&usbotg2 {
+	disable-over-current;
+	dr_mode = "host";
+	vbus-supply = <&reg_usb_vbus>;
+	samsung,picophy-dc-vol-level-adjust = <7>;
+	samsung,picophy-pre-emp-curr-control = <3>;
+	status = "okay";
+};
+
+&usdhc1 {
+	bus-width = <8>;
+	keep-power-in-suspend;
+	mmc-pwrseq = <&usdhc1_pwrseq>;
+	non-removable;
+	pinctrl-0 = <&pinctrl_usdhc1>;
+	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	vmmc-supply = <&reg_usdhc1_vmmc>;
+	wakeup-source;
+	status = "okay";
+};
+
+&usdhc2 {
+	bus-width = <4>;
+	cd-gpios = <&gpio3 0 GPIO_ACTIVE_LOW>;
+	no-mmc;
+	no-sdio;
+	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-3 = <&pinctrl_usdhc2_sleep>, <&pinctrl_usdhc2_gpio_sleep>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	status = "okay";
+};
+
+&wdog3 {
+	pinctrl-0 = <&pinctrl_wdog>;
+	pinctrl-names = "default";
+	fsl,ext-reset-output;
+	status = "okay";
+};

-- 
2.43.0



From james.clark at linaro.org  Mon Dec 15 00:47:05 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 15 Dec 2025 10:47:05 +0200
Subject: [PATCH] arm64: perf: fix syscalltbl path base
In-Reply-To: <b2651f20-6f3a-49f5-9cd8-3fb028b2cab5@app.fastmail.com>
References: <b2651f20-6f3a-49f5-9cd8-3fb028b2cab5@app.fastmail.com>
Message-ID: <fcefc3c0-541d-40cc-84e3-9c2460308bdb@linaro.org>



On 15/12/2025 00:12, Joel May wrote:
> From: Joel May <joel-linux at jmay.us>
> 
> A fix for the Perf build process was introduced in commit bfb713ea53c74
> ("perf tools: Fix arm64 build by generating unistd_64.h"), which generates
> the unistd_64.h header as necessary.  This fix works fine in some
> scenarios.
> 
> My problem is when building Perf from tools/perf with SRCARCH=arm64, the
> path used in scripts/Makefile.asm-headers is relative to tools/perf
> instead of root directory.  This results in the build failing like so.
> This snippet is a simplified repro of the problem, see the link to the
> TrueNAS SCALE build script to see the problem in context.
> 
>    jmay at debian13-aarch64:/mnt/linux/linux-vanilla/tools/perf$ ARCH=arm64 SRCARCH=arm64 make -j1
>    ...
>    make[4]: *** No rule to make target '/mnt/linux/linux-vanilla/tools/perf/libperf/arch/arm64/include/generated/uapi/asm/unistd_64.h'.  Stop.
>    make[3]: *** [Makefile:108: uapi-asm-generic] Error 2
>    make[2]: *** [Makefile.perf:972: /mnt/linux/linux-vanilla/tools/perf/libperf/libperf.a] Error 2
> 
> The problem is that scripts/Makefile.asm-headers is including a relative
> syscalltbl path from arch/arm64/kernel/Makefile.syscalls.  The syscalltbl
> path needs to be based on the srctree root.
> 
> Fixes: 7fe33e9f662c0 ("arm64: convert unistd_32.h to syscall.tbl format")
> Fixes: bfb713ea53c74 ("perf tools: Fix arm64 build by generating unistd_64.h")

Hi Joel,

There is a similar fix on the list here:

https://lore.kernel.org/linux-perf-users/20251204-perf_fix_syscall_header-v1-1-b8e27f74ed6a at arm.com/

I'm not sure if commit 1 alone will also fix your issue, or we'd need to 
collapse both of the commits in that set.

The first commit has an older fixes: tag and also fixes some other 
issues so it might be better to take that one rather than this one.

Thanks
James

> Link: https://github.com/truenas/linux/commit/91377b555a57dfa75364d7da85b5e21e41e81625#diff-831a0e8e3eaa7a5ca92599e58771b8a6b2c4bd7533f627e33138873995aac61eR147
> Signed-off-by: Joel May <joel-linux at jmay.us>
> ---
>   arch/arm64/kernel/Makefile.syscalls | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kernel/Makefile.syscalls b/arch/arm64/kernel/Makefile.syscalls
> index 0542a718871a..958f2335ec1b 100644
> --- a/arch/arm64/kernel/Makefile.syscalls
> +++ b/arch/arm64/kernel/Makefile.syscalls
> @@ -3,4 +3,4 @@
>   syscall_abis_32 +=
>   syscall_abis_64 += renameat rlimit memfd_secret
>   
> -syscalltbl = arch/arm64/tools/syscall_%.tbl
> +syscalltbl = $(srctree)/arch/arm64/tools/syscall_%.tbl
> 
> base-commit: edde060637b92607f3522252c03d64ad06369933



From benjamin.gaignard at collabora.com  Mon Dec 15 00:53:37 2025
From: benjamin.gaignard at collabora.com (Benjamin Gaignard)
Date: Mon, 15 Dec 2025 09:53:37 +0100
Subject: [PATCH v10 0/7] Add support for Verisilicon IOMMU used by media
Message-ID: <20251215085349.10155-1-benjamin.gaignard@collabora.com>

Hi all,

This patch series adds support for the Verisilicon IOMMU, which is found
in front
of hardware encoder and decoder blocks in several SoCs using Verisilicon
IP. 
A first implementation of this IOMMU is available on the Rockchip RK3588
SoC.

Rockchip provides a driver for this hardware in their 6.1 kernel branch:
https://github.com/rockchip-linux/kernel/blob/develop-6.1/drivers/iommu/rockchip-iommu-av1d.c

This series includes:
- a new binding for the Verisilicon IOMMU
- a driver implementation
- DT updates for RK3588

The driver was forward-ported from Rockchip???s 6.1 implementation, 
the prefix was renamed to vsi for generality, and several fixes were
applied.

AV1 decoding was tested using the stateless VPU driver and Fluster.
The test results show a score of 205/239, which confirms that no
regressions
were introduced by this series.

Feedback and testing welcome.

changes in version 10:
- Update vsi_iommu_identity_attach() and vsi_iommu_attach_device()
  prototypes.
- Fix build as module issue when Verisilicon video decoder is built-in.
- Rebase on master branch.

changes in version 9:
- removing blanks lines.

changes in version 8:
- Add myself in MAINTAINERS file.
- Add API to restore VSI iommu context from decoder driver
- Fix reported checkpatch issues: add comment in pinlock_t declaration
  and remove blank line.
- Include board name in defconfig patch commit message

changes in version 7:
- fix locking issues.
- add a patch in AV1 video decoder to manage per context iommu domain.
- fix compilation issues when build as module.
- remove useless "rockchip,rk3588-av1-iommu" compatible in driver code.

changes in version 6:
- rework lock schema in vsi_iommu_attach_device() so
  it protected against concurrent invalidation.
- flush the cache after changing of domain.

changes in version 5:
- change locking schema to use 2 spin_locks: one to protect vsi_domain
  data and one to protect vsi_iommu structure.
- make suspend/resume more robust by calling disable/enable function.
- rebased on top of v6.16-rc5

changes in version 4:
- rename and reorder compatibles fields.
- Kconfig dependencies
- Fix the remarks done by Jason and Robin: locking, clocks, macros
  probing, pm_runtime, atomic allocation.

changes in version 3:
- Change compatible to "rockchip,rk3588-iommu-1.2"
- Fix compatible in .yaml
- Update DT and driver to use "rockchip,rk3588-iommu-1.2" compatible
- Set CONFIG_VSI_IOMMU as module in defconfig
- Create an identity domain for the driver
- Fix double flush issue
- Rework attach/detach logic
- Simplify xlate function
- Discover iommu device like done in ARM driver
- Remove ARM_DMA_USE_IOMMU from Kconfig

changes in version 2:
- Add a compatible "rockchip,rk3588-av1-iommu"
- Fix clock-names in binding 
- Remove "vsi_mmu" label in binding example.
- Rework driver probe function
- Remove double flush
- Rework driver internal structures and avoid allocate
  in xlate function.
- Do not touch to VPU driver anymore (path removed)
- Add a patch to enable the driver in arm64 defconfig

Benjamin Gaignard (7):
  dt-bindings: vendor-prefixes: Add Verisilicon
  dt-bindings: iommu: verisilicon: Add binding for VSI IOMMU
  iommu: Add verisilicon IOMMU driver
  MAINTAINERS: Add entry for Verisilicon IOMMU driver
  media: verisilicon: AV1: Restore IOMMU context before decoding a frame
  arm64: dts: rockchip: Add verisilicon IOMMU node on RK3588
  arm64: defconfig: enable Verisilicon IOMMU for Rockchip RK3588

 .../bindings/iommu/verisilicon,iommu.yaml     |  71 ++
 .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
 MAINTAINERS                                   |   8 +
 arch/arm64/boot/dts/rockchip/rk3588-base.dtsi |  11 +
 arch/arm64/configs/defconfig                  |   1 +
 drivers/iommu/Kconfig                         |  11 +
 drivers/iommu/Makefile                        |   1 +
 drivers/iommu/vsi-iommu.c                     | 808 ++++++++++++++++++
 drivers/media/platform/verisilicon/Kconfig    |   1 +
 .../verisilicon/rockchip_vpu981_hw_av1_dec.c  |  15 +
 include/linux/vsi-iommu.h                     |  21 +
 11 files changed, 950 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iommu/verisilicon,iommu.yaml
 create mode 100644 drivers/iommu/vsi-iommu.c
 create mode 100644 include/linux/vsi-iommu.h

-- 
2.43.0



From benjamin.gaignard at collabora.com  Mon Dec 15 00:53:38 2025
From: benjamin.gaignard at collabora.com (Benjamin Gaignard)
Date: Mon, 15 Dec 2025 09:53:38 +0100
Subject: [PATCH v10 1/7] dt-bindings: vendor-prefixes: Add Verisilicon
In-Reply-To: <20251215085349.10155-1-benjamin.gaignard@collabora.com>
References: <20251215085349.10155-1-benjamin.gaignard@collabora.com>
Message-ID: <20251215085349.10155-2-benjamin.gaignard@collabora.com>

Verisilicon Microelectronics is a company based in Shanghai, China,
developping hardware blocks for SoC.

https://verisilicon.com/

Add their name to the list of vendors.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard at collabora.com>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index c7591b2aec2a..ce5c413948b1 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -1745,6 +1745,8 @@ patternProperties:
     description: Variscite Ltd.
   "^vdl,.*":
     description: Van der Laan b.v.
+  "^verisilicon,.*":
+    description: VeriSilicon Microelectronics
   "^vertexcom,.*":
     description: Vertexcom Technologies, Inc.
   "^via,.*":
-- 
2.43.0



From benjamin.gaignard at collabora.com  Mon Dec 15 00:53:41 2025
From: benjamin.gaignard at collabora.com (Benjamin Gaignard)
Date: Mon, 15 Dec 2025 09:53:41 +0100
Subject: [PATCH v10 4/7] MAINTAINERS: Add entry for Verisilicon IOMMU driver
In-Reply-To: <20251215085349.10155-1-benjamin.gaignard@collabora.com>
References: <20251215085349.10155-1-benjamin.gaignard@collabora.com>
Message-ID: <20251215085349.10155-5-benjamin.gaignard@collabora.com>

Add maintainer for Verisilicon iommu driver.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard at collabora.com>
---
 MAINTAINERS | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index c9e416ba74c6..ca67e5333134 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -27296,6 +27296,14 @@ F:	drivers/media/v4l2-core/v4l2-isp.c
 F:	include/media/v4l2-isp.h
 F:	include/uapi/linux/media/v4l2-isp.h
 
+VERISILICON IOMMU DRIVER
+M:	Benjamin Gaignard <benjamin.gaignard at collabora.com>
+L:	iommu at lists.linux.dev
+S:	Maintained
+F:	Documentation/devicetree/bindings/iommu/verisilicon,iommu.yaml
+F:	drivers/iommu/vsi-iommu.c
+F:	include/linux/vsi-iommu.h
+
 VF610 NAND DRIVER
 M:	Stefan Agner <stefan at agner.ch>
 L:	linux-mtd at lists.infradead.org
-- 
2.43.0



From benjamin.gaignard at collabora.com  Mon Dec 15 00:53:40 2025
From: benjamin.gaignard at collabora.com (Benjamin Gaignard)
Date: Mon, 15 Dec 2025 09:53:40 +0100
Subject: [PATCH v10 3/7] iommu: Add verisilicon IOMMU driver
In-Reply-To: <20251215085349.10155-1-benjamin.gaignard@collabora.com>
References: <20251215085349.10155-1-benjamin.gaignard@collabora.com>
Message-ID: <20251215085349.10155-4-benjamin.gaignard@collabora.com>

The Verisilicon IOMMU hardware block can be found in combination
with Verisilicon hardware video codecs (encoders or decoders) on
different SoCs.
Enable it will allow us to use non contiguous memory allocators
for Verisilicon video codecs.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard at collabora.com>
---
changes in version 10:
- Update vsi_iommu_identity_attach() and vsi_iommu_attach_device()
  prototypes.

 drivers/iommu/Kconfig     |  11 +
 drivers/iommu/Makefile    |   1 +
 drivers/iommu/vsi-iommu.c | 808 ++++++++++++++++++++++++++++++++++++++
 include/linux/vsi-iommu.h |  21 +
 4 files changed, 841 insertions(+)
 create mode 100644 drivers/iommu/vsi-iommu.c
 create mode 100644 include/linux/vsi-iommu.h

diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 99095645134f..60468014f39f 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -384,6 +384,17 @@ config SPRD_IOMMU
 
 	  Say Y here if you want to use the multimedia devices listed above.
 
+config VSI_IOMMU
+	tristate "Verisilicon IOMMU Support"
+	depends on (ARCH_ROCKCHIP && ARM64) || COMPILE_TEST
+	select IOMMU_API
+	help
+	  Support for IOMMUs used by Verisilicon sub-systems like video
+	  decoders or encoder hardware blocks.
+
+	  Say Y here if you want to use this IOMMU in front of these
+	  hardware blocks.
+
 endif # IOMMU_SUPPORT
 
 source "drivers/iommu/generic_pt/Kconfig"
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 8e8843316c4b..f4043350d023 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -36,3 +36,4 @@ obj-$(CONFIG_IOMMU_SVA) += iommu-sva.o
 obj-$(CONFIG_IOMMU_IOPF) += io-pgfault.o
 obj-$(CONFIG_SPRD_IOMMU) += sprd-iommu.o
 obj-$(CONFIG_APPLE_DART) += apple-dart.o
+obj-$(CONFIG_VSI_IOMMU) += vsi-iommu.o
diff --git a/drivers/iommu/vsi-iommu.c b/drivers/iommu/vsi-iommu.c
new file mode 100644
index 000000000000..ea961adf5eb9
--- /dev/null
+++ b/drivers/iommu/vsi-iommu.c
@@ -0,0 +1,808 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2025 Collabora Ltd.
+ *
+ * IOMMU API for Verisilicon
+ *
+ * Module Authors:	Yandong Lin <yandong.lin at rock-chips.com>
+ *			Simon Xue <xxm at rock-chips.com>
+ *			Benjamin Gaignard <benjamin.gaignard at collabora.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/compiler.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iommu.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_iommu.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/vsi-iommu.h>
+
+#include "iommu-pages.h"
+
+struct vsi_iommu {
+	struct device *dev;
+	void __iomem *regs;
+	struct clk_bulk_data *clocks;
+	int num_clocks;
+	struct iommu_device iommu;
+	struct list_head node; /* entry in vsi_iommu_domain.iommus */
+	struct iommu_domain *domain; /* domain to which iommu is attached */
+	spinlock_t lock; /* lock to protect vsi_iommu fields */
+	int irq;
+};
+
+struct vsi_iommu_domain {
+	struct list_head iommus;
+	struct device *dev;
+	u32 *dt;
+	dma_addr_t dt_dma;
+	struct iommu_domain domain;
+	u64 *pta;
+	dma_addr_t pta_dma;
+	spinlock_t lock; /* lock to protect vsi_iommu_domain fields */
+};
+
+static struct iommu_domain vsi_identity_domain;
+
+#define NUM_DT_ENTRIES	1024
+#define NUM_PT_ENTRIES	1024
+#define PT_SIZE		(NUM_PT_ENTRIES * sizeof(u32))
+
+#define SPAGE_SIZE	BIT(12)
+
+/* vsi iommu regs address */
+#define VSI_MMU_CONFIG1_BASE			0x1ac
+#define VSI_MMU_AHB_EXCEPTION_BASE		0x380
+#define VSI_MMU_AHB_CONTROL_BASE		0x388
+#define VSI_MMU_AHB_TLB_ARRAY_BASE_L_BASE	0x38C
+
+/* MMU register offsets */
+#define VSI_MMU_FLUSH_BASE		0x184
+#define VSI_MMU_BIT_FLUSH		BIT(4)
+
+#define VSI_MMU_PAGE_FAULT_ADDR		0x380
+#define VSI_MMU_STATUS_BASE		0x384	/* IRQ status */
+
+#define VSI_MMU_BIT_ENABLE		BIT(0)
+
+#define VSI_MMU_OUT_OF_BOUND		BIT(28)
+/* Irq mask */
+#define VSI_MMU_IRQ_MASK		0x7
+
+#define VSI_DTE_PT_ADDRESS_MASK		0xffffffc0
+#define VSI_DTE_PT_VALID		BIT(0)
+
+#define VSI_PAGE_DESC_LO_MASK		0xfffff000
+#define VSI_PAGE_DESC_HI_MASK		GENMASK_ULL(39, 32)
+#define VSI_PAGE_DESC_HI_SHIFT		(32 - 4)
+
+static inline phys_addr_t vsi_dte_pt_address(u32 dte)
+{
+	return (phys_addr_t)dte & VSI_DTE_PT_ADDRESS_MASK;
+}
+
+static inline u32 vsi_mk_dte(u32 dte)
+{
+	return (phys_addr_t)dte | VSI_DTE_PT_VALID;
+}
+
+#define VSI_PTE_PAGE_WRITABLE		BIT(2)
+#define VSI_PTE_PAGE_VALID		BIT(0)
+
+static inline phys_addr_t vsi_pte_page_address(u64 pte)
+{
+	return ((pte << VSI_PAGE_DESC_HI_SHIFT) & VSI_PAGE_DESC_HI_MASK) |
+	       (pte & VSI_PAGE_DESC_LO_MASK);
+}
+
+static u32 vsi_mk_pte(phys_addr_t page, int prot)
+{
+	u32 flags = 0;
+
+	flags |= (prot & IOMMU_WRITE) ? VSI_PTE_PAGE_WRITABLE : 0;
+
+	page = (page & VSI_PAGE_DESC_LO_MASK) |
+	       ((page & VSI_PAGE_DESC_HI_MASK) >> VSI_PAGE_DESC_HI_SHIFT);
+
+	return page | flags | VSI_PTE_PAGE_VALID;
+}
+
+#define VSI_DTE_PT_VALID	BIT(0)
+
+static inline bool vsi_dte_is_pt_valid(u32 dte)
+{
+	return dte & VSI_DTE_PT_VALID;
+}
+
+static inline bool vsi_pte_is_page_valid(u32 pte)
+{
+	return pte & VSI_PTE_PAGE_VALID;
+}
+
+static u32 vsi_mk_pte_invalid(u32 pte)
+{
+	return pte & ~VSI_PTE_PAGE_VALID;
+}
+
+#define VSI_MASTER_TLB_MASK	GENMASK_ULL(31, 10)
+/* mode 0 : 4k */
+#define VSI_PTA_4K_MODE	0
+
+static u64 vsi_mk_pta(dma_addr_t dt_dma)
+{
+	u64 val = (dt_dma & VSI_MASTER_TLB_MASK) | VSI_PTA_4K_MODE;
+
+	return val;
+}
+
+static struct vsi_iommu_domain *to_vsi_domain(struct iommu_domain *dom)
+{
+	return container_of(dom, struct vsi_iommu_domain, domain);
+}
+
+static inline void vsi_table_flush(struct vsi_iommu_domain *vsi_domain, dma_addr_t dma,
+				   unsigned int count)
+{
+	size_t size = count * sizeof(u32); /* count of u32 entry */
+
+	dma_sync_single_for_device(vsi_domain->dev, dma, size, DMA_TO_DEVICE);
+}
+
+#define VSI_IOVA_DTE_MASK	0xffc00000
+#define VSI_IOVA_DTE_SHIFT	22
+#define VSI_IOVA_PTE_MASK	0x003ff000
+#define VSI_IOVA_PTE_SHIFT	12
+#define VSI_IOVA_PAGE_MASK	0x00000fff
+#define VSI_IOVA_PAGE_SHIFT	0
+
+static u32 vsi_iova_dte_index(u32 iova)
+{
+	return (iova & VSI_IOVA_DTE_MASK) >> VSI_IOVA_DTE_SHIFT;
+}
+
+static u32 vsi_iova_pte_index(u32 iova)
+{
+	return (iova & VSI_IOVA_PTE_MASK) >> VSI_IOVA_PTE_SHIFT;
+}
+
+static u32 vsi_iova_page_offset(u32 iova)
+{
+	return (iova & VSI_IOVA_PAGE_MASK) >> VSI_IOVA_PAGE_SHIFT;
+}
+
+static void vsi_iommu_flush_tlb_all(struct iommu_domain *domain)
+{
+	struct vsi_iommu_domain *vsi_domain = to_vsi_domain(domain);
+	struct list_head *pos;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vsi_domain->lock, flags);
+
+	list_for_each(pos, &vsi_domain->iommus) {
+		struct vsi_iommu *iommu;
+		int ret;
+
+		iommu = list_entry(pos, struct vsi_iommu, node);
+		ret = pm_runtime_resume_and_get(iommu->dev);
+		if (ret < 0)
+			continue;
+
+		spin_lock(&iommu->lock);
+
+		writel(VSI_MMU_BIT_FLUSH, iommu->regs + VSI_MMU_FLUSH_BASE);
+		writel(0, iommu->regs + VSI_MMU_FLUSH_BASE);
+
+		spin_unlock(&iommu->lock);
+		pm_runtime_put_autosuspend(iommu->dev);
+	}
+
+	spin_unlock_irqrestore(&vsi_domain->lock, flags);
+}
+
+static irqreturn_t vsi_iommu_irq(int irq, void *dev_id)
+{
+	struct vsi_iommu *iommu = dev_id;
+	unsigned long flags;
+	dma_addr_t iova;
+	u32 status;
+
+	if (pm_runtime_resume_and_get(iommu->dev) < 0)
+		return IRQ_NONE;
+
+	spin_lock_irqsave(&iommu->lock, flags);
+
+	status = readl(iommu->regs + VSI_MMU_STATUS_BASE);
+	if (status & VSI_MMU_IRQ_MASK) {
+		dev_err(iommu->dev, "unexpected int_status=%08x\n", status);
+		iova = readl(iommu->regs + VSI_MMU_PAGE_FAULT_ADDR);
+		report_iommu_fault(iommu->domain, iommu->dev, iova, status);
+	}
+	writel(0, iommu->regs + VSI_MMU_STATUS_BASE);
+
+	spin_unlock_irqrestore(&iommu->lock, flags);
+	pm_runtime_put_autosuspend(iommu->dev);
+
+	return IRQ_HANDLED;
+}
+
+static struct vsi_iommu *vsi_iommu_get_from_dev(struct device *dev)
+{
+	struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+	struct device *iommu_dev = bus_find_device_by_fwnode(&platform_bus_type,
+							     fwspec->iommu_fwnode);
+
+	put_device(iommu_dev);
+
+	return iommu_dev ? dev_get_drvdata(iommu_dev) : NULL;
+}
+
+static struct iommu_domain *vsi_iommu_domain_alloc_paging(struct device *dev)
+{
+	struct vsi_iommu *iommu = dev_iommu_priv_get(dev);
+	struct vsi_iommu_domain *vsi_domain;
+
+	vsi_domain = kzalloc(sizeof(*vsi_domain), GFP_KERNEL);
+	if (!vsi_domain)
+		return NULL;
+
+	vsi_domain->dev = iommu->dev;
+	spin_lock_init(&vsi_domain->lock);
+
+	/*
+	 * iommu use a 2 level pagetable.
+	 * Each level1 (dt) and level2 (pt) table has 1024 4-byte entries.
+	 * Allocate one 4 KiB page for each table.
+	 */
+	vsi_domain->dt = iommu_alloc_pages_sz(GFP_KERNEL | GFP_DMA32,
+					      SPAGE_SIZE);
+	if (!vsi_domain->dt)
+		goto err_free_domain;
+
+	vsi_domain->dt_dma = dma_map_single(vsi_domain->dev, vsi_domain->dt,
+					    SPAGE_SIZE, DMA_TO_DEVICE);
+	if (dma_mapping_error(vsi_domain->dev, vsi_domain->dt_dma)) {
+		dev_err(dev, "DMA map error for DT\n");
+		goto err_free_dt;
+	}
+
+	vsi_domain->pta = iommu_alloc_pages_sz(GFP_KERNEL | GFP_DMA32,
+					       SPAGE_SIZE);
+	if (!vsi_domain->pta)
+		goto err_unmap_dt;
+
+	vsi_domain->pta[0] = vsi_mk_pta(vsi_domain->dt_dma);
+	vsi_domain->pta_dma = dma_map_single(vsi_domain->dev, vsi_domain->pta,
+					     SPAGE_SIZE, DMA_TO_DEVICE);
+	if (dma_mapping_error(vsi_domain->dev, vsi_domain->pta_dma)) {
+		dev_err(dev, "DMA map error for PTA\n");
+		goto err_free_pta;
+	}
+
+	INIT_LIST_HEAD(&vsi_domain->iommus);
+
+	vsi_domain->domain.geometry.aperture_start = 0;
+	vsi_domain->domain.geometry.aperture_end   = DMA_BIT_MASK(32);
+	vsi_domain->domain.geometry.force_aperture = true;
+	vsi_domain->domain.pgsize_bitmap	   = SZ_4K;
+
+	return &vsi_domain->domain;
+
+err_free_pta:
+	iommu_free_pages(vsi_domain->pta);
+err_unmap_dt:
+	dma_unmap_single(vsi_domain->dev, vsi_domain->dt_dma,
+			 SPAGE_SIZE, DMA_TO_DEVICE);
+err_free_dt:
+	iommu_free_pages(vsi_domain->dt);
+err_free_domain:
+	kfree(vsi_domain);
+
+	return NULL;
+}
+
+static phys_addr_t vsi_iommu_iova_to_phys(struct iommu_domain *domain,
+					  dma_addr_t iova)
+{
+	struct vsi_iommu_domain *vsi_domain = to_vsi_domain(domain);
+	phys_addr_t pt_phys, phys = 0;
+	unsigned long flags;
+	u32 dte, pte;
+	u32 *page_table;
+
+	spin_lock_irqsave(&vsi_domain->lock, flags);
+	dte = vsi_domain->dt[vsi_iova_dte_index(iova)];
+	if (!vsi_dte_is_pt_valid(dte))
+		goto unlock;
+
+	pt_phys = vsi_dte_pt_address(dte);
+	page_table = (u32 *)phys_to_virt(pt_phys);
+	pte = page_table[vsi_iova_pte_index(iova)];
+	if (!vsi_pte_is_page_valid(pte))
+		goto unlock;
+
+	phys = vsi_pte_page_address(pte) + vsi_iova_page_offset(iova);
+
+unlock:
+	spin_unlock_irqrestore(&vsi_domain->lock, flags);
+	return phys;
+}
+
+static size_t vsi_iommu_unmap_iova(struct vsi_iommu_domain *vsi_domain,
+				   u32 *pte_addr, dma_addr_t pte_dma,
+				   size_t size)
+{
+	unsigned int pte_count;
+	unsigned int pte_total = size / SPAGE_SIZE;
+
+	for (pte_count = 0;
+	     pte_count < pte_total && pte_count < NUM_PT_ENTRIES; pte_count++) {
+		u32 pte = pte_addr[pte_count];
+
+		if (!vsi_pte_is_page_valid(pte))
+			break;
+
+		pte_addr[pte_count] = vsi_mk_pte_invalid(pte);
+	}
+
+	vsi_table_flush(vsi_domain, pte_dma, pte_total);
+
+	return pte_count * SPAGE_SIZE;
+}
+
+static int vsi_iommu_map_iova(struct vsi_iommu_domain *vsi_domain, u32 *pte_addr,
+			      dma_addr_t pte_dma, dma_addr_t iova,
+			      phys_addr_t paddr, size_t size, int prot)
+{
+	unsigned int pte_count;
+	unsigned int pte_total = size / SPAGE_SIZE;
+
+	for (pte_count = 0;
+	     pte_count < pte_total && pte_count < NUM_PT_ENTRIES; pte_count++) {
+		u32 pte = pte_addr[pte_count];
+
+		if (vsi_pte_is_page_valid(pte))
+			return (pte_count - 1) * SPAGE_SIZE;
+
+		pte_addr[pte_count] = vsi_mk_pte(paddr, prot);
+
+		paddr += SPAGE_SIZE;
+	}
+
+	vsi_table_flush(vsi_domain, pte_dma, pte_total);
+
+	return 0;
+}
+
+static size_t vsi_iommu_unmap(struct iommu_domain *domain, unsigned long _iova,
+			      size_t size, size_t count, struct iommu_iotlb_gather *gather)
+{
+	struct vsi_iommu_domain *vsi_domain = to_vsi_domain(domain);
+	dma_addr_t pte_dma, iova = (dma_addr_t)_iova;
+	unsigned long flags;
+	phys_addr_t pt_phys;
+	u32 dte;
+	u32 *pte_addr;
+	size_t unmap_size = 0;
+
+	spin_lock_irqsave(&vsi_domain->lock, flags);
+
+	dte = vsi_domain->dt[vsi_iova_dte_index(iova)];
+	/* Just return 0 if iova is unmapped */
+	if (!vsi_dte_is_pt_valid(dte))
+		goto unlock;
+
+	pt_phys = vsi_dte_pt_address(dte);
+	pte_addr = (u32 *)phys_to_virt(pt_phys) + vsi_iova_pte_index(iova);
+	pte_dma = pt_phys + vsi_iova_pte_index(iova) * sizeof(u32);
+	unmap_size = vsi_iommu_unmap_iova(vsi_domain, pte_addr, pte_dma, size);
+
+unlock:
+	spin_unlock_irqrestore(&vsi_domain->lock, flags);
+
+	return unmap_size;
+}
+
+static u32 *vsi_dte_get_page_table(struct vsi_iommu_domain *vsi_domain,
+				   dma_addr_t iova, gfp_t gfp)
+{
+	u32 *page_table, *dte_addr;
+	u32 dte_index, dte;
+	phys_addr_t pt_phys;
+	dma_addr_t pt_dma;
+	gfp_t flags;
+
+	dte_index = vsi_iova_dte_index(iova);
+	dte_addr = &vsi_domain->dt[dte_index];
+	dte = *dte_addr;
+	if (vsi_dte_is_pt_valid(dte))
+		goto done;
+
+	/* Do not allow to sleep while allocating the buffer */
+	flags = (gfp & ~GFP_KERNEL) | GFP_ATOMIC | GFP_DMA32;
+	page_table = iommu_alloc_pages_sz(flags, PAGE_SIZE);
+	if (!page_table)
+		return ERR_PTR(-ENOMEM);
+
+	pt_dma = dma_map_single(vsi_domain->dev, page_table, PAGE_SIZE, DMA_TO_DEVICE);
+	if (dma_mapping_error(vsi_domain->dev, pt_dma)) {
+		dev_err(vsi_domain->dev, "DMA mapping error while allocating page table\n");
+		iommu_free_pages(page_table);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	dte = vsi_mk_dte(pt_dma);
+	*dte_addr = dte;
+
+	vsi_table_flush(vsi_domain,
+			vsi_domain->dt_dma + dte_index * sizeof(u32), 1);
+done:
+	pt_phys = vsi_dte_pt_address(dte);
+	return (u32 *)phys_to_virt(pt_phys);
+}
+
+static int vsi_iommu_map(struct iommu_domain *domain, unsigned long _iova,
+			 phys_addr_t paddr, size_t size, size_t count,
+			 int prot, gfp_t gfp, size_t *mapped)
+{
+	struct vsi_iommu_domain *vsi_domain = to_vsi_domain(domain);
+	dma_addr_t pte_dma, iova = (dma_addr_t)_iova;
+	u32 *page_table, *pte_addr;
+	u32 dte, pte_index;
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&vsi_domain->lock, flags);
+
+	page_table = vsi_dte_get_page_table(vsi_domain, iova, gfp);
+	if (IS_ERR(page_table)) {
+		spin_unlock_irqrestore(&vsi_domain->lock, flags);
+		return PTR_ERR(page_table);
+	}
+
+	dte = vsi_domain->dt[vsi_iova_dte_index(iova)];
+	pte_index = vsi_iova_pte_index(iova);
+	pte_addr = &page_table[pte_index];
+	pte_dma = vsi_dte_pt_address(dte) + pte_index * sizeof(u32);
+	ret = vsi_iommu_map_iova(vsi_domain, pte_addr, pte_dma, iova,
+				 paddr, size, prot);
+	if (!ret)
+		*mapped = size;
+	spin_unlock_irqrestore(&vsi_domain->lock, flags);
+
+	return ret;
+}
+
+static void vsi_iommu_disable(struct vsi_iommu *iommu)
+{
+	writel(0, iommu->regs + VSI_MMU_AHB_CONTROL_BASE);
+}
+
+static int vsi_iommu_identity_attach(struct iommu_domain *domain,
+				     struct device *dev, struct iommu_domain *old)
+{
+	struct vsi_iommu *iommu = dev_iommu_priv_get(dev);
+	unsigned long flags;
+	int ret;
+
+	ret = pm_runtime_resume_and_get(iommu->dev);
+	if (ret < 0)
+		return ret;
+
+	spin_lock_irqsave(&iommu->lock, flags);
+	if (iommu->domain == domain)
+		goto unlock;
+
+	vsi_iommu_disable(iommu);
+	list_del_init(&iommu->node);
+
+	iommu->domain = domain;
+
+unlock:
+	spin_unlock_irqrestore(&iommu->lock, flags);
+	pm_runtime_put_autosuspend(iommu->dev);
+	return 0;
+}
+
+static const struct iommu_domain_ops vsi_identity_ops = {
+	.attach_dev = vsi_iommu_identity_attach,
+};
+
+static struct iommu_domain vsi_identity_domain = {
+	.type = IOMMU_DOMAIN_IDENTITY,
+	.ops = &vsi_identity_ops,
+};
+
+static void vsi_iommu_enable(struct vsi_iommu *iommu, struct iommu_domain *domain)
+{
+	struct vsi_iommu_domain *vsi_domain = to_vsi_domain(domain);
+
+	if (domain == &vsi_identity_domain)
+		return;
+
+	writel(vsi_domain->pta_dma, iommu->regs + VSI_MMU_AHB_TLB_ARRAY_BASE_L_BASE);
+	writel(VSI_MMU_OUT_OF_BOUND, iommu->regs + VSI_MMU_CONFIG1_BASE);
+	writel(VSI_MMU_BIT_ENABLE, iommu->regs + VSI_MMU_AHB_EXCEPTION_BASE);
+	writel(VSI_MMU_BIT_ENABLE, iommu->regs + VSI_MMU_AHB_CONTROL_BASE);
+}
+
+void vsi_iommu_restore_ctx(struct iommu_domain *domain)
+{
+	struct vsi_iommu_domain *vsi_domain = to_vsi_domain(domain);
+	struct list_head *pos;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vsi_domain->lock, flags);
+
+	list_for_each(pos, &vsi_domain->iommus) {
+		struct vsi_iommu *iommu;
+
+		iommu = list_entry(pos, struct vsi_iommu, node);
+		if (!iommu)
+			continue;
+
+		spin_lock(&iommu->lock);
+
+		writel(VSI_MMU_BIT_FLUSH, iommu->regs + VSI_MMU_FLUSH_BASE);
+		writel(0, iommu->regs + VSI_MMU_FLUSH_BASE);
+
+		spin_unlock(&iommu->lock);
+	}
+
+	spin_unlock_irqrestore(&vsi_domain->lock, flags);
+}
+EXPORT_SYMBOL_GPL(vsi_iommu_restore_ctx);
+
+static int vsi_iommu_attach_device(struct iommu_domain *domain,
+				   struct device *dev, struct iommu_domain *old)
+{
+	struct vsi_iommu *iommu = dev_iommu_priv_get(dev);
+	struct vsi_iommu_domain *vsi_domain = to_vsi_domain(domain);
+	unsigned long flags, flags2;
+	int ret = 0;
+
+	ret = pm_runtime_resume_and_get(iommu->dev);
+	if (ret < 0)
+		return ret;
+
+	spin_lock_irqsave(&vsi_domain->lock, flags);
+	spin_lock_irqsave(&iommu->lock, flags2);
+
+	vsi_iommu_enable(iommu, domain);
+	writel(VSI_MMU_BIT_FLUSH, iommu->regs + VSI_MMU_FLUSH_BASE);
+	writel(0, iommu->regs + VSI_MMU_FLUSH_BASE);
+
+	list_del_init(&iommu->node);
+	list_add_tail(&iommu->node, &vsi_domain->iommus);
+
+	iommu->domain = domain;
+
+	spin_unlock_irqrestore(&iommu->lock, flags2);
+	spin_unlock_irqrestore(&vsi_domain->lock, flags);
+	pm_runtime_put_autosuspend(iommu->dev);
+	return ret;
+}
+
+static void vsi_iommu_domain_free(struct iommu_domain *domain)
+{
+	struct vsi_iommu_domain *vsi_domain = to_vsi_domain(domain);
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&vsi_domain->lock, flags);
+
+	WARN_ON(!list_empty(&vsi_domain->iommus));
+
+	for (i = 0; i < NUM_DT_ENTRIES; i++) {
+		u32 dte = vsi_domain->dt[i];
+
+		if (vsi_dte_is_pt_valid(dte)) {
+			phys_addr_t pt_phys = vsi_dte_pt_address(dte);
+			u32 *page_table = phys_to_virt(pt_phys);
+
+			dma_unmap_single(vsi_domain->dev, pt_phys,
+					 SPAGE_SIZE, DMA_TO_DEVICE);
+			iommu_free_pages(page_table);
+		}
+	}
+
+	dma_unmap_single(vsi_domain->dev, vsi_domain->dt_dma,
+			 SPAGE_SIZE, DMA_TO_DEVICE);
+	iommu_free_pages(vsi_domain->dt);
+
+	dma_unmap_single(vsi_domain->dev, vsi_domain->pta_dma,
+			 SPAGE_SIZE, DMA_TO_DEVICE);
+	iommu_free_pages(vsi_domain->pta);
+
+	spin_unlock_irqrestore(&vsi_domain->lock, flags);
+
+	kfree(vsi_domain);
+}
+
+static struct iommu_device *vsi_iommu_probe_device(struct device *dev)
+{
+	struct vsi_iommu *iommu = vsi_iommu_get_from_dev(dev);
+	struct device_link *link;
+
+	link = device_link_add(dev, iommu->dev,
+			       DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME);
+	if (!link)
+		dev_err(dev, "Unable to link %s\n", dev_name(iommu->dev));
+
+	dev_iommu_priv_set(dev, iommu);
+	return &iommu->iommu;
+}
+
+static void vsi_iommu_release_device(struct device *dev)
+{
+	struct vsi_iommu *iommu = dev_iommu_priv_get(dev);
+
+	device_link_remove(dev, iommu->dev);
+}
+
+static int vsi_iommu_of_xlate(struct device *dev, const struct of_phandle_args *args)
+{
+	return iommu_fwspec_add_ids(dev, args->args, 1);
+}
+
+static const struct iommu_ops vsi_iommu_ops = {
+	.identity_domain = &vsi_identity_domain,
+	.release_domain = &vsi_identity_domain,
+	.domain_alloc_paging = vsi_iommu_domain_alloc_paging,
+	.of_xlate = vsi_iommu_of_xlate,
+	.probe_device = vsi_iommu_probe_device,
+	.release_device = vsi_iommu_release_device,
+	.device_group = generic_single_device_group,
+	.owner = THIS_MODULE,
+	.default_domain_ops = &(const struct iommu_domain_ops) {
+		.attach_dev		= vsi_iommu_attach_device,
+		.map_pages		= vsi_iommu_map,
+		.unmap_pages		= vsi_iommu_unmap,
+		.flush_iotlb_all	= vsi_iommu_flush_tlb_all,
+		.iova_to_phys		= vsi_iommu_iova_to_phys,
+		.free			= vsi_iommu_domain_free,
+	}
+};
+
+static const struct of_device_id vsi_iommu_dt_ids[] = {
+	{
+		.compatible = "verisilicon,iommu-1.2",
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, vsi_iommu_dt_ids);
+
+static int vsi_iommu_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct vsi_iommu *iommu;
+	int err;
+
+	iommu = devm_kzalloc(dev, sizeof(*iommu), GFP_KERNEL);
+	if (!iommu)
+		return -ENOMEM;
+
+	iommu->dev = dev;
+	spin_lock_init(&iommu->lock);
+	INIT_LIST_HEAD(&iommu->node);
+
+	iommu->regs = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(iommu->regs))
+		return -ENOMEM;
+
+	iommu->num_clocks = devm_clk_bulk_get_all(dev, &iommu->clocks);
+	if  (iommu->num_clocks < 0)
+		return iommu->num_clocks;
+
+	err = clk_bulk_prepare(iommu->num_clocks, iommu->clocks);
+	if (err)
+		return err;
+
+	iommu->irq = platform_get_irq(pdev, 0);
+	if (iommu->irq < 0)
+		return iommu->irq;
+
+	err = devm_request_irq(iommu->dev, iommu->irq, vsi_iommu_irq,
+			       IRQF_SHARED, dev_name(dev), iommu);
+	if (err)
+		goto err_unprepare_clocks;
+
+	dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+	platform_set_drvdata(pdev, iommu);
+
+	pm_runtime_set_autosuspend_delay(dev, 100);
+	pm_runtime_use_autosuspend(dev);
+	pm_runtime_enable(dev);
+
+	err = iommu_device_sysfs_add(&iommu->iommu, dev, NULL, dev_name(dev));
+	if (err)
+		goto err_runtime_disable;
+
+	err = iommu_device_register(&iommu->iommu, &vsi_iommu_ops, dev);
+	if (err)
+		goto err_remove_sysfs;
+
+	return 0;
+
+err_remove_sysfs:
+	iommu_device_sysfs_remove(&iommu->iommu);
+err_runtime_disable:
+	pm_runtime_disable(dev);
+err_unprepare_clocks:
+	clk_bulk_unprepare(iommu->num_clocks, iommu->clocks);
+	return err;
+}
+
+static void vsi_iommu_shutdown(struct platform_device *pdev)
+{
+	struct vsi_iommu *iommu = platform_get_drvdata(pdev);
+
+	disable_irq(iommu->irq);
+	pm_runtime_force_suspend(&pdev->dev);
+}
+
+static int __maybe_unused vsi_iommu_suspend(struct device *dev)
+{
+	struct vsi_iommu *iommu = dev_get_drvdata(dev);
+
+	vsi_iommu_disable(iommu);
+
+	clk_bulk_disable(iommu->num_clocks, iommu->clocks);
+
+	return 0;
+}
+
+static int __maybe_unused vsi_iommu_resume(struct device *dev)
+{
+	struct vsi_iommu *iommu = dev_get_drvdata(dev);
+	unsigned long flags, flags2;
+	int ret;
+
+	ret = clk_bulk_enable(iommu->num_clocks, iommu->clocks);
+	if (ret)
+		return ret;
+
+	if (iommu->domain) {
+		struct vsi_iommu_domain *vsi_domain = to_vsi_domain(iommu->domain);
+
+		spin_lock_irqsave(&vsi_domain->lock, flags);
+		spin_lock_irqsave(&iommu->lock, flags2);
+		vsi_iommu_enable(iommu, iommu->domain);
+		spin_unlock_irqrestore(&iommu->lock, flags2);
+		spin_unlock_irqrestore(&vsi_domain->lock, flags);
+	}
+
+	return 0;
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(vsi_iommu_pm_ops,
+				 vsi_iommu_suspend, vsi_iommu_resume,
+				 NULL);
+
+static struct platform_driver rockchip_vsi_iommu_driver = {
+	.probe = vsi_iommu_probe,
+	.shutdown = vsi_iommu_shutdown,
+	.driver = {
+		   .name = "vsi_iommu",
+		   .of_match_table = vsi_iommu_dt_ids,
+		   .pm = pm_sleep_ptr(&vsi_iommu_pm_ops),
+		   .suppress_bind_attrs = true,
+	},
+};
+module_platform_driver(rockchip_vsi_iommu_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard at collabora.com>");
+MODULE_DESCRIPTION("Verisilicon IOMMU driver");
diff --git a/include/linux/vsi-iommu.h b/include/linux/vsi-iommu.h
new file mode 100644
index 000000000000..81a80f9219f4
--- /dev/null
+++ b/include/linux/vsi-iommu.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * verisilicon iommu: simple virtual address space management
+ *
+ * Copyright (c) 2025, Collabora
+ *
+ * Written by Benjamin Gaignard <benjamin.gaignard at collabora.com>
+ */
+
+#ifndef _VSI_IOMMU_H_
+#define _VSI_IOMMU_H_
+
+struct iommu_domain;
+
+#if IS_ENABLED(CONFIG_VSI_IOMMU)
+void vsi_iommu_restore_ctx(struct iommu_domain *domain);
+#else
+static inline void vsi_iommu_restore_ctx(struct iommu_domain *domain) {}
+#endif
+
+#endif
-- 
2.43.0



From benjamin.gaignard at collabora.com  Mon Dec 15 00:53:39 2025
From: benjamin.gaignard at collabora.com (Benjamin Gaignard)
Date: Mon, 15 Dec 2025 09:53:39 +0100
Subject: [PATCH v10 2/7] dt-bindings: iommu: verisilicon: Add binding for VSI IOMMU
In-Reply-To: <20251215085349.10155-1-benjamin.gaignard@collabora.com>
References: <20251215085349.10155-1-benjamin.gaignard@collabora.com>
Message-ID: <20251215085349.10155-3-benjamin.gaignard@collabora.com>

Add a device tree binding for the Verisilicon (VSI) IOMMU.
This IOMMU sits in front of hardware encoder and decoder
blocks on SoCs using Verisilicon IP, such as the Rockchip RK3588.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard at collabora.com>
Reviewed-by: Conor Dooley <conor.dooley at microchip.com>
---
 .../bindings/iommu/verisilicon,iommu.yaml     | 71 +++++++++++++++++++
 1 file changed, 71 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iommu/verisilicon,iommu.yaml

diff --git a/Documentation/devicetree/bindings/iommu/verisilicon,iommu.yaml b/Documentation/devicetree/bindings/iommu/verisilicon,iommu.yaml
new file mode 100644
index 000000000000..d3ce9e603b61
--- /dev/null
+++ b/Documentation/devicetree/bindings/iommu/verisilicon,iommu.yaml
@@ -0,0 +1,71 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iommu/verisilicon,iommu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Verisilicon IOMMU
+
+maintainers:
+  - Benjamin Gaignard <benjamin.gaignard at collabora.com>
+
+description: |+
+  A Versilicon iommu translates io virtual addresses to physical addresses for
+  its associated video decoder.
+
+properties:
+  compatible:
+    items:
+      - const: rockchip,rk3588-av1-iommu
+      - const: verisilicon,iommu-1.2
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: Core clock
+      - description: Interface clock
+
+  clock-names:
+    items:
+      - const: core
+      - const: iface
+
+  "#iommu-cells":
+    const: 0
+
+  power-domains:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - "#iommu-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/rockchip,rk3588-cru.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    bus {
+      #address-cells = <2>;
+      #size-cells = <2>;
+
+      iommu at fdca0000 {
+        compatible = "rockchip,rk3588-av1-iommu","verisilicon,iommu-1.2";
+        reg = <0x0 0xfdca0000 0x0 0x600>;
+        interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH 0>;
+        clocks = <&cru ACLK_AV1>, <&cru PCLK_AV1>;
+        clock-names = "core", "iface";
+        #iommu-cells = <0>;
+      };
+    };
-- 
2.43.0



From benjamin.gaignard at collabora.com  Mon Dec 15 00:53:44 2025
From: benjamin.gaignard at collabora.com (Benjamin Gaignard)
Date: Mon, 15 Dec 2025 09:53:44 +0100
Subject: [PATCH v10 7/7] arm64: defconfig: enable Verisilicon IOMMU for Rockchip RK3588
In-Reply-To: <20251215085349.10155-1-benjamin.gaignard@collabora.com>
References: <20251215085349.10155-1-benjamin.gaignard@collabora.com>
Message-ID: <20251215085349.10155-8-benjamin.gaignard@collabora.com>

Enable Verisilicon IOMMU used by Rockchip RK3588 AV1 hardware codec.
This hardware block could be found in Radxa Rock 5B board.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard at collabora.com>
---
 arch/arm64/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 45288ec9eaf7..0106bf1935f8 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -1525,6 +1525,7 @@ CONFIG_ARM_SMMU=y
 CONFIG_ARM_SMMU_V3=y
 CONFIG_MTK_IOMMU=y
 CONFIG_QCOM_IOMMU=y
+CONFIG_VSI_IOMMU=m
 CONFIG_REMOTEPROC=y
 CONFIG_IMX_REMOTEPROC=y
 CONFIG_MTK_SCP=m
-- 
2.43.0



From benjamin.gaignard at collabora.com  Mon Dec 15 00:53:43 2025
From: benjamin.gaignard at collabora.com (Benjamin Gaignard)
Date: Mon, 15 Dec 2025 09:53:43 +0100
Subject: [PATCH v10 6/7] arm64: dts: rockchip: Add verisilicon IOMMU node on RK3588
In-Reply-To: <20251215085349.10155-1-benjamin.gaignard@collabora.com>
References: <20251215085349.10155-1-benjamin.gaignard@collabora.com>
Message-ID: <20251215085349.10155-7-benjamin.gaignard@collabora.com>

Add the device tree node for the Verisilicon IOMMU present
in the RK3588 SoC.
This IOMMU handles address translation for the VPU hardware blocks.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard at collabora.com>
---
 arch/arm64/boot/dts/rockchip/rk3588-base.dtsi | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
index 2a7921793020..acff8bb3a612 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
@@ -1364,6 +1364,17 @@ av1d: video-codec at fdc70000 {
 		clock-names = "aclk", "hclk";
 		power-domains = <&power RK3588_PD_AV1>;
 		resets = <&cru SRST_A_AV1>, <&cru SRST_P_AV1>, <&cru SRST_A_AV1_BIU>, <&cru SRST_P_AV1_BIU>;
+		iommus = <&av1d_mmu>;
+	};
+
+	av1d_mmu: iommu at fdca0000 {
+		compatible = "rockchip,rk3588-av1-iommu", "verisilicon,iommu-1.2";
+		reg = <0x0 0xfdca0000 0x0 0x600>;
+		interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH 0>;
+		clocks = <&cru ACLK_AV1>, <&cru PCLK_AV1>;
+		clock-names = "core", "iface";
+		#iommu-cells = <0>;
+		power-domains = <&power RK3588_PD_AV1>;
 	};
 
 	vop: vop at fdd90000 {
-- 
2.43.0



From benjamin.gaignard at collabora.com  Mon Dec 15 00:53:42 2025
From: benjamin.gaignard at collabora.com (Benjamin Gaignard)
Date: Mon, 15 Dec 2025 09:53:42 +0100
Subject: [PATCH v10 5/7] media: verisilicon: AV1: Restore IOMMU context before decoding a frame
In-Reply-To: <20251215085349.10155-1-benjamin.gaignard@collabora.com>
References: <20251215085349.10155-1-benjamin.gaignard@collabora.com>
Message-ID: <20251215085349.10155-6-benjamin.gaignard@collabora.com>

AV1 is a stateless decoder which means multiple AV1 bitstreams could be
decoded at the same time using the same hardware block. Before decoding
a frame it is needed to restore the iommu tables to avoid mixing decode
contexts.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard at collabora.com>
---
changes in version 10:
- Fix build as module issue when Verisilicon video decoder is built-in.

 drivers/media/platform/verisilicon/Kconfig        |  1 +
 .../verisilicon/rockchip_vpu981_hw_av1_dec.c      | 15 +++++++++++++++
 2 files changed, 16 insertions(+)

diff --git a/drivers/media/platform/verisilicon/Kconfig b/drivers/media/platform/verisilicon/Kconfig
index 3272a24db71d..e64bc8b55235 100644
--- a/drivers/media/platform/verisilicon/Kconfig
+++ b/drivers/media/platform/verisilicon/Kconfig
@@ -49,6 +49,7 @@ config VIDEO_HANTRO_ROCKCHIP
 	bool "Hantro VPU Rockchip support"
 	depends on VIDEO_HANTRO
 	depends on ARCH_ROCKCHIP || COMPILE_TEST
+	select VSI_IOMMU
 	default y
 	help
 	  Enable support for RK3288, RK3328, and RK3399 SoCs.
diff --git a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
index e4703bb6be7c..d9e68e0ded68 100644
--- a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
+++ b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
@@ -5,6 +5,9 @@
  * Author: Benjamin Gaignard <benjamin.gaignard at collabora.com>
  */
 
+#include <linux/iommu.h>
+#include <linux/vsi-iommu.h>
+
 #include <media/v4l2-mem2mem.h>
 #include "hantro.h"
 #include "hantro_v4l2.h"
@@ -2095,12 +2098,24 @@ rockchip_vpu981_av1_dec_set_output_buffer(struct hantro_ctx *ctx)
 	hantro_write_addr(vpu, AV1_TILE_OUT_MV, mv_addr);
 }
 
+static void rockchip_vpu981_av1_restore_iommu(struct hantro_ctx *ctx)
+{
+	struct iommu_domain *domain;
+
+	/* Before decoding any frame iommu context need to be restored */
+	domain = iommu_get_domain_for_dev(ctx->dev->v4l2_dev.dev);
+	if (domain)
+		vsi_iommu_restore_ctx(domain);
+}
+
 int rockchip_vpu981_av1_dec_run(struct hantro_ctx *ctx)
 {
 	struct hantro_dev *vpu = ctx->dev;
 	struct vb2_v4l2_buffer *vb2_src;
 	int ret;
 
+	rockchip_vpu981_av1_restore_iommu(ctx);
+
 	hantro_start_prepare_run(ctx);
 
 	ret = rockchip_vpu981_av1_dec_prepare_run(ctx);
-- 
2.43.0



From james.clark at linaro.org  Mon Dec 15 01:02:08 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 15 Dec 2025 11:02:08 +0200
Subject: [PATCH v2 RESEND] coresight: etm-perf: Fix reference count leak
 in etm_setup_aux
In-Reply-To: <20251215022709.17220-1-make24@iscas.ac.cn>
References: <20251215022709.17220-1-make24@iscas.ac.cn>
Message-ID: <c698d581-da15-42bf-9612-62f1bad66615@linaro.org>



On 15/12/2025 04:27, Ma Ke wrote:
> In etm_setup_aux(), when a user sink is obtained via
> coresight_get_sink_by_id(), it increments the reference count of the
> sink device. However, if the sink is used in path building, the path
> holds a reference, but the initial reference from
> coresight_get_sink_by_id() is not released, causing a reference count
> leak. We should release the initial reference after the path is built.
> 
> Found by code review.
> 
> Cc: stable at vger.kernel.org
> Fixes: 0e6c20517596 ("coresight: etm-perf: Allow an event to use different sinks")
> Signed-off-by: Ma Ke <make24 at iscas.ac.cn>
> ---
> Changes in v2:
> - modified the patch as suggestions.

I think Leo's comment on the previous v2 is still unaddressed. But 
releasing it in coresight_get_sink_by_id() would make it consistent with 
coresight_find_csdev_by_fwnode() and prevent further mistakes.

It also leads me to see that users of coresight_find_device_by_fwnode() 
should also release it, but only one out of two appears to.

James

> ---
>   drivers/hwtracing/coresight/coresight-etm-perf.c | 5 +++++
>   1 file changed, 5 insertions(+)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c
> index 17afa0f4cdee..56d012ab6d3a 100644
> --- a/drivers/hwtracing/coresight/coresight-etm-perf.c
> +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c
> @@ -454,6 +454,11 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
>   		goto err;
>   
>   out:
> +	if (user_sink) {
> +		put_device(&user_sink->dev);
> +		user_sink = NULL;
> +	}
> +
>   	return event_data;
>   
>   err:



From nicolas.ferre at microchip.com  Mon Dec 15 01:02:56 2025
From: nicolas.ferre at microchip.com (Nicolas Ferre)
Date: Mon, 15 Dec 2025 10:02:56 +0100
Subject: [PATCH] ARM: dts: microchip: Drop usb_a9g20-dab-mmx.dtsi
In-Reply-To: <20251213010934353f1efe@mail.local>
References: <20251212203226.458694-8-robh@kernel.org>
 <aTytWyyZiYFnyauo@shikoro> <20251213010934353f1efe@mail.local>
Message-ID: <0ec01064-2755-401a-b2c8-76ad6ce686af@microchip.com>

On 13/12/2025 at 02:09, Alexandre Belloni wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
> On 13/12/2025 09:03:39+0900, Wolfram Sang wrote:
>> On Fri, Dec 12, 2025 at 02:32:14PM -0600, Rob Herring (Arm) wrote:
>>> This .dtsi file is not included anywhere in the tree and can't be
>>> tested.
>>>
>>> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
>>
>> Nowadays, this should be a dtso which did not exist back then. Is it
>> okay to convert it? Yes, I can do this.
>>
> 
> I don't think this will be missed by anyone. Unless you actually have
> one of the boards, I would simply drop this.

+1

Regards,
   Nicolas


From manikandan.m at microchip.com  Mon Dec 15 01:06:38 2025
From: manikandan.m at microchip.com (Manikandan Muralidharan)
Date: Mon, 15 Dec 2025 14:36:38 +0530
Subject: [PATCH 1/2] dt-bindings: mfd: atmel,hlcdc: Add sama7d65 compatible string
Message-ID: <20251215090639.346288-1-manikandan.m@microchip.com>

Add LCD compatible string for sama7d65.

Signed-off-by: Manikandan Muralidharan <manikandan.m at microchip.com>
---
 Documentation/devicetree/bindings/mfd/atmel,hlcdc.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/mfd/atmel,hlcdc.yaml b/Documentation/devicetree/bindings/mfd/atmel,hlcdc.yaml
index 4aa36903e755..dfee8707bac2 100644
--- a/Documentation/devicetree/bindings/mfd/atmel,hlcdc.yaml
+++ b/Documentation/devicetree/bindings/mfd/atmel,hlcdc.yaml
@@ -25,6 +25,7 @@ properties:
       - atmel,sama5d4-hlcdc
       - microchip,sam9x60-hlcdc
       - microchip,sam9x75-xlcdc
+      - microchip,sama7d65-xlcdc
 
   reg:
     maxItems: 1

base-commit: 7f790dd21a931c61167f7bdc327aecf2cebad327
-- 
2.25.1



From manikandan.m at microchip.com  Mon Dec 15 01:06:39 2025
From: manikandan.m at microchip.com (Manikandan Muralidharan)
Date: Mon, 15 Dec 2025 14:36:39 +0530
Subject: [PATCH 2/2] drm: atmel-hlcdc: add LCD controller layer definition for sama7d65
In-Reply-To: <20251215090639.346288-1-manikandan.m@microchip.com>
References: <20251215090639.346288-1-manikandan.m@microchip.com>
Message-ID: <20251215090639.346288-2-manikandan.m@microchip.com>

From: Ryan Wanner <Ryan.Wanner at microchip.com>

Add the LCD controller layer definition and atmel_hlcdc_of_match
entry for sama7d65.

Signed-off-by: Ryan Wanner <Ryan.Wanner at microchip.com>
Signed-off-by: Manikandan Muralidharan <manikandan.m at microchip.com>
---
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | 81 ++++++++++++++++++++
 drivers/mfd/atmel-hlcdc.c                    |  1 +
 2 files changed, 82 insertions(+)

diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
index dd70894c8f38..9c18c6841e2a 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
@@ -566,6 +566,83 @@ static const struct atmel_hlcdc_dc_desc atmel_xlcdc_dc_sam9x75 = {
 	.ops = &atmel_xlcdc_ops,
 };
 
+static const struct atmel_hlcdc_layer_desc atmel_xlcdc_sama7d65_layers[] = {
+	{
+		.name = "base",
+		.formats = &atmel_hlcdc_plane_rgb_formats,
+		.regs_offset = 0x60,
+		.id = 0,
+		.type = ATMEL_HLCDC_BASE_LAYER,
+		.cfgs_offset = 0x1c,
+		.layout = {
+			.xstride = { 2 },
+			.default_color = 3,
+			.general_config = 4,
+			.disc_pos = 5,
+			.disc_size = 6,
+		},
+		.clut_offset = 0x700,
+	},
+	{
+		.name = "overlay1",
+		.formats = &atmel_hlcdc_plane_rgb_formats,
+		.regs_offset = 0x160,
+		.id = 1,
+		.type = ATMEL_HLCDC_OVERLAY_LAYER,
+		.cfgs_offset = 0x1c,
+		.layout = {
+			.pos = 2,
+			.size = 3,
+			.xstride = { 4 },
+			.pstride = { 5 },
+			.default_color = 6,
+			.chroma_key = 7,
+			.chroma_key_mask = 8,
+			.general_config = 9,
+		},
+		.clut_offset = 0xb00,
+	},
+	{
+		.name = "high-end-overlay",
+		.formats = &atmel_hlcdc_plane_rgb_and_yuv_formats,
+		.regs_offset = 0x360,
+		.id = 2,
+		.type = ATMEL_HLCDC_OVERLAY_LAYER,
+		.cfgs_offset = 0x30,
+		.layout = {
+			.pos = 2,
+			.size = 3,
+			.memsize = 4,
+			.xstride = { 5, 7 },
+			.pstride = { 6, 8 },
+			.default_color = 9,
+			.chroma_key = 10,
+			.chroma_key_mask = 11,
+			.general_config = 12,
+			.csc = 16,
+			.scaler_config = 23,
+			.vxs_config = 30,
+			.hxs_config = 31,
+		},
+		.clut_offset = 0x1300,
+	},
+};
+
+static const struct atmel_hlcdc_dc_desc atmel_xlcdc_dc_sama7d65 = {
+	.min_width = 0,
+	.min_height = 0,
+	.max_width = 2048,
+	.max_height = 2048,
+	.max_spw = 0x3ff,
+	.max_vpw = 0x3ff,
+	.max_hpw = 0x3ff,
+	.fixed_clksrc = false,
+	.is_xlcdc = true,
+	.nlayers = ARRAY_SIZE(atmel_xlcdc_sama7d65_layers),
+	.layers = atmel_xlcdc_sama7d65_layers,
+	.ops = &atmel_xlcdc_ops,
+};
+
 static const struct of_device_id atmel_hlcdc_of_match[] = {
 	{
 		.compatible = "atmel,at91sam9n12-hlcdc",
@@ -595,6 +672,10 @@ static const struct of_device_id atmel_hlcdc_of_match[] = {
 		.compatible = "microchip,sam9x75-xlcdc",
 		.data = &atmel_xlcdc_dc_sam9x75,
 	},
+	{
+		.compatible = "microchip,sama7d65-xlcdc",
+		.data = &atmel_xlcdc_dc_sama7d65,
+	},
 	{ /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, atmel_hlcdc_of_match);
diff --git a/drivers/mfd/atmel-hlcdc.c b/drivers/mfd/atmel-hlcdc.c
index 4c4e35d404f3..c3f3d39bf584 100644
--- a/drivers/mfd/atmel-hlcdc.c
+++ b/drivers/mfd/atmel-hlcdc.c
@@ -140,6 +140,7 @@ static const struct of_device_id atmel_hlcdc_match[] = {
 	{ .compatible = "atmel,sama5d4-hlcdc" },
 	{ .compatible = "microchip,sam9x60-hlcdc" },
 	{ .compatible = "microchip,sam9x75-xlcdc" },
+	{ .compatible = "microchip,sama7d65-xlcdc" },
 	{ /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, atmel_hlcdc_match);
-- 
2.25.1



From jackmanb at google.com  Mon Dec 15 01:22:22 2025
From: jackmanb at google.com (Brendan Jackman)
Date: Mon, 15 Dec 2025 09:22:22 +0000
Subject: [PATCH 2/2] arm64: mmu: use pagetable_alloc_nolock() while stop_machine()
In-Reply-To: <aT5/y3cSGIzi2K+m@e129823.arm.com>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com> <20251212161832.2067134-3-yeoreum.yun@arm.com>
 <CA+i-1C2e7QNTy5u=HF7tLsLXLq4xYbMTCbNjWGAxHz4uwgR05g@mail.gmail.com> <aT5/y3cSGIzi2K+m@e129823.arm.com>
Message-ID: <DEYOI8H2OESD.1H56D3H8HKILB@google.com>

On Sun Dec 14, 2025 at 9:13 AM UTC, Yeoreum Yun wrote:
>> I don't have the context on what this code is doing so take this with
>> a grain of salt, but...
>>
>> The point of the _nolock alloc is to give the allocator an excuse to
>> fail. Panicking on that failure doesn't seem like a great idea to me?
>
> I thought first whether it changes to "static" memory area to handle
> this in PREEMPT_RT.
> But since this function is called while smp_cpus_done().
> So, I think it's fine since there wouldn't be a contention for
> memory allocation in this phase.

Then shouldn't it use _nolock unconditionally?


From alexandre.torgue at foss.st.com  Mon Dec 15 01:26:26 2025
From: alexandre.torgue at foss.st.com (Alexandre TORGUE)
Date: Mon, 15 Dec 2025 10:26:26 +0100
Subject: [PATCH] arm/arm64: dts: st: Drop unused .dtsi
In-Reply-To: <20251212203226.458694-3-robh@kernel.org>
References: <20251212203226.458694-3-robh@kernel.org>
Message-ID: <73678ca9-0943-4daa-a2f4-05219db2384e@foss.st.com>

Hi Rob

On 12/12/25 21:32, Rob Herring (Arm) wrote:
> These .dtsi files are not included anywhere in the tree and can't be
> tested.
> 
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> ---
>   arch/arm/boot/dts/st/spear320s.dtsi           | 24 -------
>   .../boot/dts/st/stm32mp15xxab-pinctrl.dtsi    | 57 ---------------
>   arch/arm64/boot/dts/qcom/msm8996-v3.0.dtsi    | 63 ----------------
>   arch/arm64/boot/dts/st/stm32mp21xc.dtsi       |  8 ---
>   arch/arm64/boot/dts/st/stm32mp23xc.dtsi       |  8 ---
>   arch/arm64/boot/dts/st/stm32mp25xc.dtsi       |  8 ---
>   .../boot/dts/st/stm32mp25xxal-pinctrl.dtsi    | 71 -------------------
>   7 files changed, 239 deletions(-)
>   delete mode 100644 arch/arm/boot/dts/st/spear320s.dtsi
>   delete mode 100644 arch/arm/boot/dts/st/stm32mp15xxab-pinctrl.dtsi
>   delete mode 100644 arch/arm64/boot/dts/qcom/msm8996-v3.0.dtsi
>   delete mode 100644 arch/arm64/boot/dts/st/stm32mp21xc.dtsi
>   delete mode 100644 arch/arm64/boot/dts/st/stm32mp23xc.dtsi
>   delete mode 100644 arch/arm64/boot/dts/st/stm32mp25xc.dtsi
>   delete mode 100644 arch/arm64/boot/dts/st/stm32mp25xxal-pinctrl.dtsi
>

...

Ok with this patch. We'll re introduce files when we'll have really a 
usage of those files by a board.

Reviewed-by: Alexandre Torgue <alexandre.torgue at foss.st.com>


From u.kleine-koenig at baylibre.com  Mon Dec 15 01:32:18 2025
From: u.kleine-koenig at baylibre.com (Uwe =?utf-8?Q?Kleine-K=C3=B6nig?=)
Date: Mon, 15 Dec 2025 10:32:18 +0100
Subject: [PATCH v1 00/17] tee: Use bus callbacks instead of driver
 callbacks
In-Reply-To: <aT--ox375kg2Mzh-@sumit-X1>
References: <cover.1765472125.git.u.kleine-koenig@baylibre.com>
 <aT--ox375kg2Mzh-@sumit-X1>
Message-ID: <dhunzydod4d7vj73llpuqemxb5er2ja4emxusr66irwf77jhhb@es4yd2axzl25>

Hello Sumit,

On Mon, Dec 15, 2025 at 04:54:11PM +0900, Sumit Garg wrote:
> On Thu, Dec 11, 2025 at 06:14:54PM +0100, Uwe Kleine-K?nig wrote:
> > Hello,
> > 
> > the objective of this series is to make tee driver stop using callbacks
> > in struct device_driver. These were superseded by bus methods in 2006
> > (commit 594c8281f905 ("[PATCH] Add bus_type probe, remove, shutdown
> > methods.")) but nobody cared to convert all subsystems accordingly.
> > 
> > Here the tee drivers are converted. The first commit is somewhat
> > unrelated, but simplifies the conversion (and the drivers). It
> > introduces driver registration helpers that care about setting the bus
> > and owner. (The latter is missing in all drivers, so by using these
> > helpers the drivers become more correct.)
> > 
> > The patches #4 - #17 depend on the first two, so if they should be
> > applied to their respective subsystem trees these must contain the first
> > two patches first.
> 
> Thanks Uwe for your efforts to clean up the boilerplate code for TEE bus
> drivers.

Thanks for your feedback. I will prepare a v2 and address your comments
(whitespace issues and wrong callback in the shutdown method).

> > Note that after patch #2 is applied, unconverted drivers provoke a
> > warning in driver_register(), so it would be good for the user
> > experience if the whole series goes in during a single merge window.
> 
> +1
> 
> I suggest the whole series goes via the Jens tree since there shouldn't
> be any chances for conflict here.
> 
> > So
> > I guess an immutable branch containing the frist three patches that can
> > be merged into the other subsystem trees would be sensible.
> > 
> > After all patches are applied, tee_bus_type can be made private to
> > drivers/tee as it's not used in other places any more.
> > 
> 
> Feel free to make the tee_bus_type private as the last patch in the series
> such that any followup driver follows this clean approach.

There is a bit more to do for that than I'm willing to invest. With my
patch series applied `tee_bus_type` is still used in
drivers/tee/optee/device.c and drivers/tee/tee_core.c. Maybe it's
sensible to merge these two files into a single one.

The things I wonder about additionally are:

 - if CONFIG_OPTEE=n and CONFIG_TEE=y|m the tee bus is only used for
   drivers but not devices.

 - optee_register_device() calls device_create_file() on
   &optee_device->dev after device_register(&optee_device->dev).
   (Attention half-knowledge!) I think device_create_file() should not
   be called on an already registered device (or you have to send a
   uevent afterwards). This should probably use type attribute groups.
   (Or the need_supplicant attribute should be dropped as it isn't very
   useful. This would maybe be considered an ABI change however.)

 - Why does optee_probe() in drivers/tee/optee/smc_abi.c unregister all
   optee devices in its error path (optee_unregister_devices())?

Best regards
Uwe
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251215/21e1df16/attachment.sig>

From arnd at arndb.de  Mon Dec 15 01:33:00 2025
From: arnd at arndb.de (Arnd Bergmann)
Date: Mon, 15 Dec 2025 10:33:00 +0100
Subject: [PATCH] arm64: perf: fix syscalltbl path base
In-Reply-To: <fcefc3c0-541d-40cc-84e3-9c2460308bdb@linaro.org>
References: <b2651f20-6f3a-49f5-9cd8-3fb028b2cab5@app.fastmail.com>
 <fcefc3c0-541d-40cc-84e3-9c2460308bdb@linaro.org>
Message-ID: <23c07ac4-ff13-47a5-824a-e7af1d1847a3@app.fastmail.com>

On Mon, Dec 15, 2025, at 09:47, James Clark wrote:
> On 15/12/2025 00:12, Joel May wrote:
>
> Hi Joel,
>
> There is a similar fix on the list here:
>
> https://lore.kernel.org/linux-perf-users/20251204-perf_fix_syscall_header-v1-1-b8e27f74ed6a at arm.com/
>
> I'm not sure if commit 1 alone will also fix your issue, or we'd need to 
> collapse both of the commits in that set.
>
> The first commit has an older fixes: tag and also fixes some other 
> issues so it might be better to take that one rather than this one.

I don't understand that other "fix", doesn't that just work around
the arm64 build issue by adding another special case for arm64?

If we want the tools directory to have a copy of the generated unistd.h
files instead of generating them, it should at the minimum be done
the same across all architectures.

    Arnd


From maz at kernel.org  Mon Dec 15 01:33:47 2025
From: maz at kernel.org (Marc Zyngier)
Date: Mon, 15 Dec 2025 09:33:47 +0000
Subject: [PATCH v11 RESEND 9/9] arm64: armv8_deprecated: apply FEAT_LSUI for swpX emulation.
In-Reply-To: <20251214112248.901769-10-yeoreum.yun@arm.com>
References: <20251214112248.901769-1-yeoreum.yun@arm.com>
	<20251214112248.901769-10-yeoreum.yun@arm.com>
Message-ID: <86ms3knl6s.wl-maz@kernel.org>

On Sun, 14 Dec 2025 11:22:48 +0000,
Yeoreum Yun <yeoreum.yun at arm.com> wrote:
> 
> Apply the FEAT_LSUI instruction to emulate the deprecated swpX
> instruction, so that toggling of the PSTATE.PAN bit can be removed when
> LSUI-related instructions are used.
> 
> Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>

It really begs the question: what are the odds of ever seeing a CPU
that implements both LSUI and AArch32?

This seems extremely unlikely to me.

	M.

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


From yeoreum.yun at arm.com  Mon Dec 15 01:34:48 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Mon, 15 Dec 2025 09:34:48 +0000
Subject: [PATCH 2/2] arm64: mmu: use pagetable_alloc_nolock() while
 stop_machine()
In-Reply-To: <DEYOI8H2OESD.1H56D3H8HKILB@google.com>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com>
 <20251212161832.2067134-3-yeoreum.yun@arm.com>
 <CA+i-1C2e7QNTy5u=HF7tLsLXLq4xYbMTCbNjWGAxHz4uwgR05g@mail.gmail.com>
 <aT5/y3cSGIzi2K+m@e129823.arm.com>
 <DEYOI8H2OESD.1H56D3H8HKILB@google.com>
Message-ID: <aT/WOAr4osoJWaMS@e129823.arm.com>

Hi Brendan,
> On Sun Dec 14, 2025 at 9:13 AM UTC, Yeoreum Yun wrote:
> >> I don't have the context on what this code is doing so take this with
> >> a grain of salt, but...
> >>
> >> The point of the _nolock alloc is to give the allocator an excuse to
> >> fail. Panicking on that failure doesn't seem like a great idea to me?
> >
> > I thought first whether it changes to "static" memory area to handle
> > this in PREEMPT_RT.
> > But since this function is called while smp_cpus_done().
> > So, I think it's fine since there wouldn't be a contention for
> > memory allocation in this phase.
>
> Then shouldn't it use _nolock unconditionally?

As you pointed out, I think it should be fine even in the !PREEMPT_RT case.
However, in case I missed something or if my understanding is incorrect,
I applied it only to the PREEMPT_RT case for now.

--
Sincerely,
Yeoreum Yun


From jcalligeros99 at gmail.com  Mon Dec 15 01:37:44 2025
From: jcalligeros99 at gmail.com (James Calligeros)
Date: Mon, 15 Dec 2025 19:37:44 +1000
Subject: [PATCH v6 0/7] mfd: macsmc: add rtc, hwmon and hid subdevices
Message-ID: <20251215-macsmc-subdevs-v6-0-0518cb5f28ae@gmail.com>

Hi all,

This series adds support for the remaining SMC subdevices. These are the
RTC, hwmon, and HID devices. They are being submitted together as the RTC
and hwmon drivers both require changes to the SMC DT schema.

The RTC driver is responsible for getting and setting the system clock,
and requires an NVMEM cell. This series replaces Sven's original RTC driver
submission [1].

The hwmon function is an interesting one. While each Apple Silicon device
exposes pretty similar sets of sensors, these all seem to be paired to
different SMC keys in the firmware interface. This is true even when the
sensors are on the SoC. For example, an M1 MacBook Pro will use different
keys to access the LITTLE core temperature sensors to an M1 Mac mini. This
necessitates describing which keys correspond to which sensors for each
device individually, and populating the hwmon structs at runtime. We do
this with a node in the device tree. This series includes only the keys
for sensors which we know to be common to all devices. The SMC is also
responsible for monitoring and controlling fan speeds on systems with fans,
which we expose via the hwmon driver.

The SMC also handles the hardware power button and lid switch. Power
button presses and lid opening/closing are emitted as HID events, so we
add an input subdevice to handle them.

Since there are no real dependencies between the components of this series,
it should be fine for each subsystem to take the relevant patches through
their trees. The mfd one-liners should be taken in order to avoid trivial
conflicts.

Regards,

James

[1] https://lore.kernel.org/asahi/CAEg-Je84XxLWH7vznQmPRfjf6GxWOu75ZetwN7AdseAwfMLLrQ at mail.gmail.com/T/#t
[2] https://lore.kernel.org/asahi/20251106140050.GQ8064 at google.com/

---
Changes in v6:
- Rebase onto 6.19-rc1, dropping already merged commits
- Link to v5: https://lore.kernel.org/r/20251112-macsmc-subdevs-v5-0-728e4b91fe81 at gmail.com

Changes in v5:
- Drop inadvertent mfd core includes in rtc and input drivers
- Link to v4: https://lore.kernel.org/r/20251025-macsmc-subdevs-v4-0-374d5c9eba0e at gmail.com

Changes in v4:
- Added Rob's R-b to hwmon Devicetree schema
- Added missing include to hwmon driver
- Dropped superfluous dev_info() from hwmon probe
- Added Guenter's A-b to hwmon driver
- Renamed INPUT_MACSMC_INPUT to INPUT_MACSMC
- Dropped leftover mention of HID in input driver
- Reinstated input driver MODULE_ALIAS
- Trigger a hard wakeup on power button/lid switch when coming out of
  s2idle
- Suppress KEY_POWER event on wakeup to prevent an immediate shutdown
  when waking up
- Squashed hwmon Devicetree commits into one
- Link to v3: https://lore.kernel.org/r/20251007-macsmc-subdevs-v3-0-d7d3bfd7ae02 at gmail.com

Changes in v3:
- Renamed macsmc-hid to macsmc-input
- Switched to pm_wakeup_event in macsmc-input
- macsmc-input now configures its capabilities before registering the device
- Renamed macsmc_hwmon to macsmc-hwmon
- Dropped module aliases in macsmc-input and macsmc_hwmon
- Introduced new SMC FourCC macro to silence GCC errors
- Condensed hwmon binding using $defs
- Made label property optional for hwmon sensors
- Fixed incorrect hwmon is_visible implementation
- Dropped 64-bit math from SMC float ops
- Fixed incorrect use of error numbers in hwmon driver
- Replaced a number of non-fatal dev_errs with dev_dbgs in hwmon driver
- Added hwmon driver documentation
- Added hwmon subdevice directly to the DT SMC node
- Included "common" hwmon sensors in SoC .dtsi files
- Fixed typo in hwmon-common.dtsi
- Added Neal's R-b to series
- Added required nodes to t602x Devicetrees
- Link to v2: https://lore.kernel.org/r/20250827-macsmc-subdevs-v2-0-ce5e99d54c28 at gmail.com

Changes in v2:
- Added Rob's R-b tag to RTC DT binding
- Removed redundant nesting from hwmon DT binding
- Dedpulicated property definitions in hwmon DT schema
- Made label a required property for hwmon DT nodes
- Clarified semantics in hwmon DT schema definitions
- Split mfd tree changes into separate commits
- Fixed numerous style errors in hwmon driver
- Removed log messages sysfs read/write functions in hwmon driver
- Removed ignored errors from hwmon driver
- Removed uses of dev_err for non-errors in hwmon driver
- Made it more obvious that a number of hwmon fan properties are optional
- Modified hwmon driver to reflect DT schema changes
- Added compatible property to hwmon node
- Link to v1: https://lore.kernel.org/r/20250819-macsmc-subdevs-v1-0-57df6c3e5f19 at gmail.com

---
Hector Martin (1):
      input: macsmc-input: New driver to handle the Apple Mac SMC buttons/lid

James Calligeros (5):
      dt-bindings: hwmon: Add Apple System Management Controller hwmon schema
      mfd: macsmc: Wire up Apple SMC RTC subdevice
      mfd: macsmc: Wire up Apple SMC hwmon subdevice
      mfd: macsmc: Wire up Apple SMC input subdevice
      arm64: dts: apple: t8103, t8112, t60xx: Add hwmon SMC subdevice

Sven Peter (1):
      arm64: dts: apple: t8103,t60xx,t8112: Add SMC RTC node

 .../bindings/hwmon/apple,smc-hwmon.yaml  |  86 ++++++++++
 .../bindings/mfd/apple,smc.yaml          |  36 +++++
 MAINTAINERS                              |   2 +
 .../boot/dts/apple/hwmon-common.dtsi     |  33 ++++
 .../boot/dts/apple/hwmon-fan-dual.dtsi   |  22 +++
 arch/arm64/boot/dts/apple/hwmon-fan.dtsi |  17 ++
 .../boot/dts/apple/hwmon-laptop.dtsi     |  33 ++++
 .../boot/dts/apple/hwmon-mac-mini.dtsi   |  15 ++
 .../arm64/boot/dts/apple/t6001-j375c.dts |   2 +
 arch/arm64/boot/dts/apple/t6001.dtsi     |   2 +
 .../arm64/boot/dts/apple/t6002-j375d.dts |   2 +
 .../arm64/boot/dts/apple/t600x-die0.dtsi |  10 ++
 .../boot/dts/apple/t600x-j314-j316.dtsi  |   3 +
 .../arm64/boot/dts/apple/t602x-die0.dtsi |  10 ++
 arch/arm64/boot/dts/apple/t8103-j274.dts |   2 +
 arch/arm64/boot/dts/apple/t8103-j293.dts |   3 +
 arch/arm64/boot/dts/apple/t8103-j313.dts |   2 +
 arch/arm64/boot/dts/apple/t8103-j456.dts |   2 +
 arch/arm64/boot/dts/apple/t8103-j457.dts |   2 +
 arch/arm64/boot/dts/apple/t8103.dtsi     |  11 ++
 arch/arm64/boot/dts/apple/t8112-j413.dts |   2 +
 arch/arm64/boot/dts/apple/t8112-j473.dts |   2 +
 arch/arm64/boot/dts/apple/t8112-j493.dts |   3 +
 arch/arm64/boot/dts/apple/t8112.dtsi     |  11 ++
 drivers/input/misc/Kconfig               |  11 ++
 drivers/input/misc/Makefile              |   1 +
 drivers/input/misc/macsmc-input.c        | 207 +++++++++++++++++++++++++
 drivers/mfd/macsmc.c                     |   3 +
 28 files changed, 535 insertions(+)
---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20250816-macsmc-subdevs-87032c017d0c

Best regards,
-- 
James Calligeros <jcalligeros99 at gmail.com>



From jcalligeros99 at gmail.com  Mon Dec 15 01:37:45 2025
From: jcalligeros99 at gmail.com (James Calligeros)
Date: Mon, 15 Dec 2025 19:37:45 +1000
Subject: [PATCH v6 1/7] dt-bindings: hwmon: Add Apple System Management
 Controller hwmon schema
In-Reply-To: <20251215-macsmc-subdevs-v6-0-0518cb5f28ae@gmail.com>
References: <20251215-macsmc-subdevs-v6-0-0518cb5f28ae@gmail.com>
Message-ID: <20251215-macsmc-subdevs-v6-1-0518cb5f28ae@gmail.com>

Apple Silicon devices integrate a vast array of sensors, monitoring
current, power, temperature, and voltage across almost every part of
the system. The sensors themselves are all connected to the System
Management Controller (SMC). The SMC firmware exposes the data
reported by these sensors via its standard FourCC-based key-value
API. The SMC is also responsible for monitoring and controlling any
fans connected to the system, exposing them in the same way.

For reasons known only to Apple, each device exposes its sensors with
an almost totally unique set of keys. This is true even for devices
which share an SoC. An M1 Mac mini, for example, will report its core
temperatures on different keys to an M1 MacBook Pro. Worse still, the
SMC does not provide a way to enumerate the available keys at runtime,
nor do the keys follow any sort of reasonable or consistent naming
rules that could be used to deduce their purpose. We must therefore
know which keys are present on any given device, and which function
they serve, ahead of time.

Add a schema so that we can describe the available sensors for a given
Apple Silicon device in the Devicetree.

Reviewed-by: Neal Gompa <neal at gompa.dev>
Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
---
 .../bindings/hwmon/apple,smc-hwmon.yaml  | 86 +++++++++++++++++++++++++
 .../bindings/mfd/apple,smc.yaml          | 36 +++++++++++
 MAINTAINERS                              |  1 +
 3 files changed, 123 insertions(+)

diff --git a/Documentation/devicetree/bindings/hwmon/apple,smc-hwmon.yaml b/Documentation/devicetree/bindings/hwmon/apple,smc-hwmon.yaml
new file mode 100644
index 000000000000..2eec317bc4b3
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwmon/apple,smc-hwmon.yaml
@@ -0,0 +1,86 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/hwmon/apple,smc-hwmon.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Apple SMC Hardware Monitoring
+
+description:
+  Apple's System Management Controller (SMC) exposes a vast array of
+  hardware monitoring sensors, including temperature probes, current and
+  voltage sense, power meters, and fan speeds. It also provides endpoints
+  to manually control the speed of each fan individually. Each Apple
+  Silicon device exposes a different set of endpoints via SMC keys. This
+  is true even when two machines share an SoC. The CPU core temperature
+  sensor keys on an M1 Mac mini are different to those on an M1 MacBook
+  Pro, for example.
+
+maintainers:
+  - James Calligeros <jcalligeros99 at gmail.com>
+
+$defs:
+  sensor:
+    type: object
+
+    properties:
+      apple,key-id:
+        $ref: /schemas/types.yaml#/definitions/string
+        pattern: "^[A-Za-z0-9]{4}$"
+        description: The SMC FourCC key of the desired sensor.
+          Must match the node's suffix.
+
+      label:
+        description: Human-readable name for the sensor
+
+    required:
+      - apple,key-id
+
+properties:
+  compatible:
+    const: apple,smc-hwmon
+
+patternProperties:
+  "^current-[A-Za-z0-9]{4}$":
+    $ref: "#/$defs/sensor"
+    unevaluatedProperties: false
+
+  "^fan-[A-Za-z0-9]{4}$":
+    $ref: "#/$defs/sensor"
+    unevaluatedProperties: false
+
+    properties:
+      apple,fan-minimum:
+        $ref: /schemas/types.yaml#/definitions/string
+        pattern: "^[A-Za-z0-9]{4}$"
+        description: SMC key containing the fan's minimum speed
+
+      apple,fan-maximum:
+        $ref: /schemas/types.yaml#/definitions/string
+        pattern: "^[A-Za-z0-9]{4}$"
+        description: SMC key containing the fan's maximum speed
+
+      apple,fan-target:
+        $ref: /schemas/types.yaml#/definitions/string
+        pattern: "^[A-Za-z0-9]{4}$"
+        description: Writeable endpoint for setting desired fan speed
+
+      apple,fan-mode:
+        $ref: /schemas/types.yaml#/definitions/string
+        pattern: "^[A-Za-z0-9]{4}$"
+        description: Writeable key to enable/disable manual fan control
+
+
+  "^power-[A-Za-z0-9]{4}$":
+    $ref: "#/$defs/sensor"
+    unevaluatedProperties: false
+
+  "^temperature-[A-Za-z0-9]{4}$":
+    $ref: "#/$defs/sensor"
+    unevaluatedProperties: false
+
+  "^voltage-[A-Za-z0-9]{4}$":
+    $ref: "#/$defs/sensor"
+    unevaluatedProperties: false
+
+additionalProperties: false
diff --git a/Documentation/devicetree/bindings/mfd/apple,smc.yaml b/Documentation/devicetree/bindings/mfd/apple,smc.yaml
index 0410e712c900..34ce048619f5 100644
--- a/Documentation/devicetree/bindings/mfd/apple,smc.yaml
+++ b/Documentation/devicetree/bindings/mfd/apple,smc.yaml
@@ -49,6 +49,9 @@ properties:
   rtc:
     $ref: /schemas/rtc/apple,smc-rtc.yaml
 
+  hwmon:
+    $ref: /schemas/hwmon/apple,smc-hwmon.yaml
+
 additionalProperties: false
 
 required:
@@ -89,5 +92,38 @@ examples:
           nvmem-cells = <&rtc_offset>;
           nvmem-cell-names = "rtc_offset";
        };
+
+        hwmon {
+          compatible = "apple,smc-hwmon";
+
+          current-ID0R {
+            apple,key-id = "ID0R";
+            label = "AC Input Current";
+          };
+
+          fan-F0Ac {
+            apple,key-id = "F0Ac";
+            apple,fan-minimum = "F0Mn";
+            apple,fan-maximum = "F0Mx";
+            apple,fan-target = "F0Tg";
+            apple,fan-mode = "F0Md";
+            label = "Fan 1";
+          };
+
+          power-PSTR {
+            apple,key-id = "PSTR";
+            label = "Total System Power";
+          };
+
+          temperature-TW0P {
+            apple,key-id = "TW0P";
+            label = "WiFi/BT Module Temperature";
+          };
+
+          voltage-VD0R {
+            apple,key-id = "VD0R";
+            label = "AC Input Voltage";
+          };
+        };
       };
     };
diff --git a/MAINTAINERS b/MAINTAINERS
index 5b11839cba9d..5f160eb6762e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2458,6 +2458,7 @@ F:	Documentation/devicetree/bindings/cpufreq/apple,cluster-cpufreq.yaml
 F:	Documentation/devicetree/bindings/dma/apple,admac.yaml
 F:	Documentation/devicetree/bindings/gpio/apple,smc-gpio.yaml
 F:	Documentation/devicetree/bindings/gpu/apple,agx.yaml
+F:	Documentation/devicetree/bindings/hwmon/apple,smc-hwmon.yaml
 F:	Documentation/devicetree/bindings/i2c/apple,i2c.yaml
 F:	Documentation/devicetree/bindings/input/touchscreen/apple,z2-multitouch.yaml
 F:	Documentation/devicetree/bindings/interrupt-controller/apple,*

-- 
2.52.0



From jcalligeros99 at gmail.com  Mon Dec 15 01:37:46 2025
From: jcalligeros99 at gmail.com (James Calligeros)
Date: Mon, 15 Dec 2025 19:37:46 +1000
Subject: [PATCH v6 2/7] mfd: macsmc: Wire up Apple SMC RTC subdevice
In-Reply-To: <20251215-macsmc-subdevs-v6-0-0518cb5f28ae@gmail.com>
References: <20251215-macsmc-subdevs-v6-0-0518cb5f28ae@gmail.com>
Message-ID: <20251215-macsmc-subdevs-v6-2-0518cb5f28ae@gmail.com>

Add the new SMC RTC function to the mfd device

Reviewed-by: Neal Gompa <neal at gompa.dev>
Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
---
 drivers/mfd/macsmc.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mfd/macsmc.c b/drivers/mfd/macsmc.c
index e3893e255ce5..9099a7a22f1f 100644
--- a/drivers/mfd/macsmc.c
+++ b/drivers/mfd/macsmc.c
@@ -47,6 +47,7 @@
 static const struct mfd_cell apple_smc_devs[] = {
 	MFD_CELL_OF("macsmc-gpio", NULL, NULL, 0, 0, "apple,smc-gpio"),
 	MFD_CELL_OF("macsmc-reboot", NULL, NULL, 0, 0, "apple,smc-reboot"),
+	MFD_CELL_OF("macsmc-rtc", NULL, NULL, 0, 0, "apple,smc-rtc"),
 };
 
 static int apple_smc_cmd_locked(struct apple_smc *smc, u64 cmd, u64 arg,

-- 
2.52.0



From jcalligeros99 at gmail.com  Mon Dec 15 01:37:47 2025
From: jcalligeros99 at gmail.com (James Calligeros)
Date: Mon, 15 Dec 2025 19:37:47 +1000
Subject: [PATCH v6 3/7] mfd: macsmc: Wire up Apple SMC hwmon subdevice
In-Reply-To: <20251215-macsmc-subdevs-v6-0-0518cb5f28ae@gmail.com>
References: <20251215-macsmc-subdevs-v6-0-0518cb5f28ae@gmail.com>
Message-ID: <20251215-macsmc-subdevs-v6-3-0518cb5f28ae@gmail.com>

Add the SMC hwmon functionality to the mfd device

Reviewed-by: Neal Gompa <neal at gompa.dev>
Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
---
 drivers/mfd/macsmc.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mfd/macsmc.c b/drivers/mfd/macsmc.c
index 9099a7a22f1f..fa7b822d55bd 100644
--- a/drivers/mfd/macsmc.c
+++ b/drivers/mfd/macsmc.c
@@ -46,6 +46,7 @@
 
 static const struct mfd_cell apple_smc_devs[] = {
 	MFD_CELL_OF("macsmc-gpio", NULL, NULL, 0, 0, "apple,smc-gpio"),
+	MFD_CELL_OF("macsmc-hwmon", NULL, NULL, 0, 0, "apple,smc-hwmon"),
 	MFD_CELL_OF("macsmc-reboot", NULL, NULL, 0, 0, "apple,smc-reboot"),
 	MFD_CELL_OF("macsmc-rtc", NULL, NULL, 0, 0, "apple,smc-rtc"),
 };

-- 
2.52.0



From jcalligeros99 at gmail.com  Mon Dec 15 01:37:48 2025
From: jcalligeros99 at gmail.com (James Calligeros)
Date: Mon, 15 Dec 2025 19:37:48 +1000
Subject: [PATCH v6 4/7] input: macsmc-input: New driver to handle the Apple
 Mac SMC buttons/lid
In-Reply-To: <20251215-macsmc-subdevs-v6-0-0518cb5f28ae@gmail.com>
References: <20251215-macsmc-subdevs-v6-0-0518cb5f28ae@gmail.com>
Message-ID: <20251215-macsmc-subdevs-v6-4-0518cb5f28ae@gmail.com>

From: Hector Martin <marcan at marcan.st>

This driver implements power button and lid switch support for Apple Mac
devices using SMC controllers driven by the macsmc driver.

In addition to basic input support, this also responds to the final
shutdown warning (when the power button is held down long enough) by
doing an emergency kernel poweroff. This allows the NVMe controller to
be cleanly shut down, which prevents data loss for in-cache data.

Reviewed-by: Neal Gompa <neal at gompa.dev>
Signed-off-by: Hector Martin <marcan at marcan.st>
Co-developed-by: Sven Peter <sven at kernel.org>
Signed-off-by: Sven Peter <sven at kernel.org>
Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
---
 MAINTAINERS                       |   1 +
 drivers/input/misc/Kconfig        |  11 ++
 drivers/input/misc/Makefile       |   1 +
 drivers/input/misc/macsmc-input.c | 207 +++++++++++++++++++++++++
 4 files changed, 220 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 5f160eb6762e..7f2160a18da2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2492,6 +2492,7 @@ F:	drivers/hwmon/macsmc-hwmon.c
 F:	drivers/pmdomain/apple/
 F:	drivers/i2c/busses/i2c-pasemi-core.c
 F:	drivers/i2c/busses/i2c-pasemi-platform.c
+F:	drivers/input/misc/macsmc-input.c
 F:	drivers/input/touchscreen/apple_z2.c
 F:	drivers/iommu/apple-dart.c
 F:	drivers/iommu/io-pgtable-dart.c
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 94a753fcb64f..0e805c870e29 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -1003,4 +1003,15 @@ config INPUT_STPMIC1_ONKEY
 	  To compile this driver as a module, choose M here: the
 	  module will be called stpmic1_onkey.
 
+config INPUT_MACSMC
+	tristate "Apple Mac SMC lid/buttons"
+	depends on MFD_MACSMC
+	help
+	  Say Y here if you want to use the input events delivered via the
+	  SMC controller on Apple Mac machines using the macsmc driver.
+	  This includes lid open/close and the power button.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called macsmc-input.
+
 endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 415fc4e2918b..174031304975 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_INPUT_IQS7222)		+= iqs7222.o
 obj-$(CONFIG_INPUT_KEYSPAN_REMOTE)	+= keyspan_remote.o
 obj-$(CONFIG_INPUT_KXTJ9)		+= kxtj9.o
 obj-$(CONFIG_INPUT_M68K_BEEP)		+= m68kspkr.o
+obj-$(CONFIG_INPUT_MACSMC_INPUT)	+= macsmc-input.o
 obj-$(CONFIG_INPUT_MAX7360_ROTARY)	+= max7360-rotary.o
 obj-$(CONFIG_INPUT_MAX77650_ONKEY)	+= max77650-onkey.o
 obj-$(CONFIG_INPUT_MAX77693_HAPTIC)	+= max77693-haptic.o
diff --git a/drivers/input/misc/macsmc-input.c b/drivers/input/misc/macsmc-input.c
new file mode 100644
index 000000000000..f4598e65fc80
--- /dev/null
+++ b/drivers/input/misc/macsmc-input.c
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Apple SMC input event driver
+ * Copyright The Asahi Linux Contributors
+ *
+ * This driver exposes certain events from the SMC as an input device.
+ * This includes the lid open/close and power button notifications.
+ */
+
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/mfd/macsmc.h>
+#include <linux/module.h>
+#include <linux/reboot.h>
+
+/**
+ * struct macsmc_input
+ * @dev: Underlying struct device for the input sub-device
+ * @smc: Pointer to apple_smc struct of the mfd parent
+ * @input: Allocated input_dev; devres managed
+ * @nb: Notifier block used for incoming events from SMC (e.g. button pressed down)
+ * @wakeup_mode: Set to true when system is suspended and power button events should wake it
+ */
+struct macsmc_input {
+	struct device *dev;
+	struct apple_smc *smc;
+	struct input_dev *input;
+	struct notifier_block nb;
+	bool wakeup_mode;
+};
+
+#define SMC_EV_BTN 0x7201
+#define SMC_EV_LID 0x7203
+
+#define BTN_POWER		0x01 /* power button on e.g. Mac Mini chasis pressed */
+#define BTN_TOUCHID		0x06 /* combined TouchID / power button on MacBooks pressed */
+#define BTN_POWER_HELD_SHORT	0xfe /* power button briefly held down */
+#define BTN_POWER_HELD_LONG	0x00 /* power button held down; sent just before forced poweroff */
+
+static void macsmc_input_event_button(struct macsmc_input *smcin, unsigned long event)
+{
+	u8 button = (event >> 8) & 0xff;
+	u8 state = !!(event & 0xff);
+
+	switch (button) {
+	case BTN_POWER:
+	case BTN_TOUCHID:
+		pm_wakeup_dev_event(smcin->dev, 0, (smcin->wakeup_mode && state));
+
+		/* Suppress KEY_POWER event to prevent immediate shutdown on wake */
+		if (smcin->wakeup_mode)
+			return;
+
+		input_report_key(smcin->input, KEY_POWER, state);
+		input_sync(smcin->input);
+		break;
+	case BTN_POWER_HELD_SHORT: /* power button held down; ignore */
+		break;
+	case BTN_POWER_HELD_LONG:
+		/*
+		 * If we get here the power button has been held down for a while and
+		 * we have about 4 seconds before forced power-off is triggered by SMC.
+		 * Try to do an emergency shutdown to make sure the NVMe cache is
+		 * flushed. macOS actually does this by panicing (!)...
+		 */
+		if (state) {
+			dev_crit(smcin->dev, "Triggering forced shutdown!\n");
+			if (kernel_can_power_off())
+				kernel_power_off();
+			else /* Missing macsmc-reboot driver? */
+				kernel_restart("SMC power button triggered restart");
+		}
+		break;
+	default:
+		dev_warn(smcin->dev, "Unknown SMC button event: %04lx\n", event & 0xffff);
+	}
+}
+
+static void macsmc_input_event_lid(struct macsmc_input *smcin, unsigned long event)
+{
+	u8 lid_state = !!((event >> 8) & 0xff);
+
+	pm_wakeup_dev_event(smcin->dev, 0, (smcin->wakeup_mode && !lid_state));
+	input_report_switch(smcin->input, SW_LID, lid_state);
+	input_sync(smcin->input);
+}
+
+static int macsmc_input_event(struct notifier_block *nb, unsigned long event, void *data)
+{
+	struct macsmc_input *smcin = container_of(nb, struct macsmc_input, nb);
+	u16 type = event >> 16;
+
+	switch (type) {
+	case SMC_EV_BTN:
+		macsmc_input_event_button(smcin, event);
+		return NOTIFY_OK;
+	case SMC_EV_LID:
+		macsmc_input_event_lid(smcin, event);
+		return NOTIFY_OK;
+	default:
+		/* SMC event meant for another driver */
+		return NOTIFY_DONE;
+	}
+}
+
+static int macsmc_input_probe(struct platform_device *pdev)
+{
+	struct apple_smc *smc = dev_get_drvdata(pdev->dev.parent);
+	struct macsmc_input *smcin;
+	bool have_lid, have_power;
+	int error;
+
+	/* Bail early if this SMC neither supports power button nor lid events */
+	have_lid = apple_smc_key_exists(smc, SMC_KEY(MSLD));
+	have_power = apple_smc_key_exists(smc, SMC_KEY(bHLD));
+	if (!have_lid && !have_power)
+		return -ENODEV;
+
+	smcin = devm_kzalloc(&pdev->dev, sizeof(*smcin), GFP_KERNEL);
+	if (!smcin)
+		return -ENOMEM;
+
+	smcin->dev = &pdev->dev;
+	smcin->smc = smc;
+	platform_set_drvdata(pdev, smcin);
+
+	smcin->input = devm_input_allocate_device(&pdev->dev);
+	if (!smcin->input)
+		return -ENOMEM;
+
+	smcin->input->phys = "macsmc-input (0)";
+	smcin->input->name = "Apple SMC power/lid events";
+
+	if (have_lid)
+		input_set_capability(smcin->input, EV_SW, SW_LID);
+	if (have_power)
+		input_set_capability(smcin->input, EV_KEY, KEY_POWER);
+
+	if (have_lid) {
+		u8 val;
+
+		error = apple_smc_read_u8(smc, SMC_KEY(MSLD), &val);
+		if (error < 0)
+			dev_warn(&pdev->dev, "Failed to read initial lid state\n");
+		else
+			input_report_switch(smcin->input, SW_LID, val);
+	}
+
+	if (have_power) {
+		u32 val;
+
+		error = apple_smc_read_u32(smc, SMC_KEY(bHLD), &val);
+		if (error < 0)
+			dev_warn(&pdev->dev, "Failed to read initial power button state\n");
+		else
+			input_report_key(smcin->input, KEY_POWER, val & 1);
+	}
+
+	error = input_register_device(smcin->input);
+	if (error) {
+		dev_err(&pdev->dev, "Failed to register input device: %d\n", error);
+		return error;
+	}
+
+	input_sync(smcin->input);
+
+	smcin->nb.notifier_call = macsmc_input_event;
+	blocking_notifier_chain_register(&smc->event_handlers, &smcin->nb);
+
+	device_init_wakeup(&pdev->dev, true);
+
+	return 0;
+}
+
+static int macsmc_input_pm_prepare(struct device *dev)
+{
+	struct macsmc_input *smcin = dev_get_drvdata(dev);
+
+	smcin->wakeup_mode = true;
+	return 0;
+}
+
+static void macsmc_input_pm_complete(struct device *dev)
+{
+	struct macsmc_input *smcin = dev_get_drvdata(dev);
+
+	smcin->wakeup_mode = false;
+}
+
+static const struct dev_pm_ops macsmc_input_pm_ops = {
+	.prepare = macsmc_input_pm_prepare,
+	.complete = macsmc_input_pm_complete,
+};
+
+static struct platform_driver macsmc_input_driver = {
+	.driver = {
+		.name = "macsmc-input",
+		.pm = &macsmc_input_pm_ops,
+	},
+	.probe = macsmc_input_probe,
+};
+module_platform_driver(macsmc_input_driver);
+
+MODULE_AUTHOR("Hector Martin <marcan at marcan.st>");
+MODULE_LICENSE("Dual MIT/GPL");
+MODULE_DESCRIPTION("Apple SMC input driver");
+MODULE_ALIAS("platform:macsmc-input");

-- 
2.52.0



From jcalligeros99 at gmail.com  Mon Dec 15 01:37:49 2025
From: jcalligeros99 at gmail.com (James Calligeros)
Date: Mon, 15 Dec 2025 19:37:49 +1000
Subject: [PATCH v6 5/7] mfd: macsmc: Wire up Apple SMC input subdevice
In-Reply-To: <20251215-macsmc-subdevs-v6-0-0518cb5f28ae@gmail.com>
References: <20251215-macsmc-subdevs-v6-0-0518cb5f28ae@gmail.com>
Message-ID: <20251215-macsmc-subdevs-v6-5-0518cb5f28ae@gmail.com>

Add the new SMC input function to the mfd device

Reviewed-by: Neal Gompa <neal at gompa.dev>
Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
---
 drivers/mfd/macsmc.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mfd/macsmc.c b/drivers/mfd/macsmc.c
index fa7b822d55bd..85410f357603 100644
--- a/drivers/mfd/macsmc.c
+++ b/drivers/mfd/macsmc.c
@@ -45,6 +45,7 @@
 #define SMC_TIMEOUT_MS		500
 
 static const struct mfd_cell apple_smc_devs[] = {
+	MFD_CELL_NAME("macsmc-input"),
 	MFD_CELL_OF("macsmc-gpio", NULL, NULL, 0, 0, "apple,smc-gpio"),
 	MFD_CELL_OF("macsmc-hwmon", NULL, NULL, 0, 0, "apple,smc-hwmon"),
 	MFD_CELL_OF("macsmc-reboot", NULL, NULL, 0, 0, "apple,smc-reboot"),

-- 
2.52.0



From jcalligeros99 at gmail.com  Mon Dec 15 01:37:50 2025
From: jcalligeros99 at gmail.com (James Calligeros)
Date: Mon, 15 Dec 2025 19:37:50 +1000
Subject: [PATCH v6 6/7] arm64: dts: apple: t8103,t60xx,t8112: Add SMC RTC
 node
In-Reply-To: <20251215-macsmc-subdevs-v6-0-0518cb5f28ae@gmail.com>
References: <20251215-macsmc-subdevs-v6-0-0518cb5f28ae@gmail.com>
Message-ID: <20251215-macsmc-subdevs-v6-6-0518cb5f28ae@gmail.com>

From: Sven Peter <sven at kernel.org>

The System Manager Controller of all M1/M2 SoCs supports the RTC
sub-device.

Reviewed-by: Neal Gompa <neal at gompa.dev>
Signed-off-by: Sven Peter <sven at kernel.org>
Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
---
 .../arm64/boot/dts/apple/t600x-die0.dtsi | 6 ++++++
 .../arm64/boot/dts/apple/t602x-die0.dtsi | 6 ++++++
 arch/arm64/boot/dts/apple/t8103.dtsi     | 6 ++++++
 arch/arm64/boot/dts/apple/t8112.dtsi     | 6 ++++++
 4 files changed, 24 insertions(+)

diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi
index 3603b276a2ab..f715b19efd16 100644
--- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi
+++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi
@@ -44,6 +44,12 @@ smc_reboot: reboot {
 			nvmem-cell-names = "shutdown_flag", "boot_stage",
 				"boot_error_count", "panic_count";
 		};
+
+		rtc {
+			compatible = "apple,smc-rtc";
+			nvmem-cells = <&rtc_offset>;
+			nvmem-cell-names = "rtc_offset";
+		};
 	};
 
 	smc_mbox: mbox at 290408000 {
diff --git a/arch/arm64/boot/dts/apple/t602x-die0.dtsi b/arch/arm64/boot/dts/apple/t602x-die0.dtsi
index 2e7d2bf08ddc..8622ddea7b44 100644
--- a/arch/arm64/boot/dts/apple/t602x-die0.dtsi
+++ b/arch/arm64/boot/dts/apple/t602x-die0.dtsi
@@ -121,6 +121,12 @@ smc_reboot: reboot {
 			nvmem-cell-names = "shutdown_flag", "boot_stage",
 				"boot_error_count", "panic_count";
 		};
+
+		rtc {
+			compatible = "apple,smc-rtc";
+			nvmem-cells = <&rtc_offset>;
+			nvmem-cell-names = "rtc_offset";
+		};
 	};
 
 	pinctrl_smc: pinctrl at 2a2820000 {
diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi
index 8b7b27887968..59f2678639cf 100644
--- a/arch/arm64/boot/dts/apple/t8103.dtsi
+++ b/arch/arm64/boot/dts/apple/t8103.dtsi
@@ -916,6 +916,12 @@ smc_reboot: reboot {
 				nvmem-cell-names = "shutdown_flag", "boot_stage",
 					"boot_error_count", "panic_count";
 			};
+
+			rtc {
+				compatible = "apple,smc-rtc";
+				nvmem-cells = <&rtc_offset>;
+				nvmem-cell-names = "rtc_offset";
+			};
 		};
 
 		smc_mbox: mbox at 23e408000 {
diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi
index 3f79878b25af..6bc3f58b06f7 100644
--- a/arch/arm64/boot/dts/apple/t8112.dtsi
+++ b/arch/arm64/boot/dts/apple/t8112.dtsi
@@ -919,6 +919,12 @@ smc_reboot: reboot {
 				nvmem-cell-names = "shutdown_flag", "boot_stage",
 					"boot_error_count", "panic_count";
 			};
+
+			rtc {
+				compatible = "apple,smc-rtc";
+				nvmem-cells = <&rtc_offset>;
+				nvmem-cell-names = "rtc_offset";
+			};
 		};
 
 		smc_mbox: mbox at 23e408000 {

-- 
2.52.0



From jcalligeros99 at gmail.com  Mon Dec 15 01:37:51 2025
From: jcalligeros99 at gmail.com (James Calligeros)
Date: Mon, 15 Dec 2025 19:37:51 +1000
Subject: [PATCH v6 7/7] arm64: dts: apple: t8103, t8112, t60xx: Add hwmon
 SMC subdevice
In-Reply-To: <20251215-macsmc-subdevs-v6-0-0518cb5f28ae@gmail.com>
References: <20251215-macsmc-subdevs-v6-0-0518cb5f28ae@gmail.com>
Message-ID: <20251215-macsmc-subdevs-v6-7-0518cb5f28ae@gmail.com>

Apple's System Management Controller integrates numerous sensors
that can be exposed via hwmon. Add the subdevice, compatible,
and some common sensors that are exposed on every currently
supported device as a starting point.

Reviewed-by: Neal Gompa <neal at gompa.dev>
Co-developed-by: Janne Grunau <j at jannau.net>
Signed-off-by: Janne Grunau <j at jannau.net>
Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
---
 .../boot/dts/apple/hwmon-common.dtsi     | 33 +++++++++++++++++++++++++
 .../boot/dts/apple/hwmon-fan-dual.dtsi   | 22 +++++++++++++++++
 arch/arm64/boot/dts/apple/hwmon-fan.dtsi | 17 +++++++++++++
 .../boot/dts/apple/hwmon-laptop.dtsi     | 33 +++++++++++++++++++++++++
 .../boot/dts/apple/hwmon-mac-mini.dtsi   | 15 +++++++++++
 .../arm64/boot/dts/apple/t6001-j375c.dts |  2 ++
 arch/arm64/boot/dts/apple/t6001.dtsi     |  2 ++
 .../arm64/boot/dts/apple/t6002-j375d.dts |  2 ++
 .../arm64/boot/dts/apple/t600x-die0.dtsi |  4 +++
 .../boot/dts/apple/t600x-j314-j316.dtsi  |  3 +++
 .../arm64/boot/dts/apple/t602x-die0.dtsi |  4 +++
 arch/arm64/boot/dts/apple/t8103-j274.dts |  2 ++
 arch/arm64/boot/dts/apple/t8103-j293.dts |  3 +++
 arch/arm64/boot/dts/apple/t8103-j313.dts |  2 ++
 arch/arm64/boot/dts/apple/t8103-j456.dts |  2 ++
 arch/arm64/boot/dts/apple/t8103-j457.dts |  2 ++
 arch/arm64/boot/dts/apple/t8103.dtsi     |  5 ++++
 arch/arm64/boot/dts/apple/t8112-j413.dts |  2 ++
 arch/arm64/boot/dts/apple/t8112-j473.dts |  2 ++
 arch/arm64/boot/dts/apple/t8112-j493.dts |  3 +++
 arch/arm64/boot/dts/apple/t8112.dtsi     |  5 ++++
 21 files changed, 165 insertions(+)

diff --git a/arch/arm64/boot/dts/apple/hwmon-common.dtsi b/arch/arm64/boot/dts/apple/hwmon-common.dtsi
new file mode 100644
index 000000000000..b87021855fdf
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/hwmon-common.dtsi
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Hardware monitoring sensors expected to be found on all Apple Silicon devices
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+&smc_hwmon {
+	current-ID0R {
+		apple,key-id = "ID0R";
+		label = "AC Input Current";
+	};
+	power-PSTR {
+		apple,key-id = "PSTR";
+		label = "Total System Power";
+	};
+	power-PDTR {
+		apple,key-id = "PDTR";
+		label = "AC Input Power";
+	};
+	power-PMVR {
+		apple,key-id = "PMVR";
+		label = "3.8 V Rail Power";
+	};
+	temperature-TH0x {
+		apple,key-id = "TH0x";
+		label = "NAND Flash Temperature";
+	};
+	voltage-VD0R {
+		apple,key-id = "VD0R";
+		label = "AC Input Voltage";
+	};
+};
diff --git a/arch/arm64/boot/dts/apple/hwmon-fan-dual.dtsi b/arch/arm64/boot/dts/apple/hwmon-fan-dual.dtsi
new file mode 100644
index 000000000000..3eef0721bcca
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/hwmon-fan-dual.dtsi
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * SMC hwmon fan keys for Apple Silicon desktops/laptops with two fans
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+#include "hwmon-fan.dtsi"
+
+&smc_hwmon {
+	fan-F0Ac {
+		label = "Fan 1";
+	};
+	fan-F1Ac {
+		apple,key-id = "F1Ac";
+		label = "Fan 2";
+		apple,fan-minimum = "F1Mn";
+		apple,fan-maximum = "F1Mx";
+		apple,fan-target = "F1Tg";
+		apple,fan-mode = "F1Md";
+	};
+};
diff --git a/arch/arm64/boot/dts/apple/hwmon-fan.dtsi b/arch/arm64/boot/dts/apple/hwmon-fan.dtsi
new file mode 100644
index 000000000000..fba9faf38f4b
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/hwmon-fan.dtsi
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * hwmon fan keys for Apple Silicon desktops/laptops with a single fan.
+ *
+ *  Copyright The Asahi Linux Contributors
+ */
+
+&smc_hwmon {
+	fan-F0Ac {
+		apple,key-id = "F0Ac";
+		label = "Fan";
+		apple,fan-minimum = "F0Mn";
+		apple,fan-maximum = "F0Mx";
+		apple,fan-target = "F0Tg";
+		apple,fan-mode = "F0Md";
+	};
+};
diff --git a/arch/arm64/boot/dts/apple/hwmon-laptop.dtsi b/arch/arm64/boot/dts/apple/hwmon-laptop.dtsi
new file mode 100644
index 000000000000..0c4666282a5c
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/hwmon-laptop.dtsi
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Hardware monitoring sensors expected on all Apple Silicon laptops
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+&smc_hwmon {
+	power-PHPC {
+		apple,key-id = "PHPC";
+		label = "Heatpipe Power";
+	};
+	temperature-TB0T {
+		apple,key-id = "TB0T";
+		label = "Battery Hotspot Temperature";
+	};
+	temperature-TCHP {
+		apple,key-id = "TCHP";
+		label = "Charge Regulator Temperature";
+	};
+	temperature-TW0P {
+		apple,key-id = "TW0P";
+		label = "WiFi/BT Module Temperature";
+	};
+	voltage-SBAV {
+		apple,key-id = "SBAV";
+		label = "Battery Voltage";
+	};
+	voltage-VD0R {
+		apple,key-id = "VD0R";
+		label = "Charger Input Voltage";
+	};
+};
diff --git a/arch/arm64/boot/dts/apple/hwmon-mac-mini.dtsi b/arch/arm64/boot/dts/apple/hwmon-mac-mini.dtsi
new file mode 100644
index 000000000000..f32627336ae7
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/hwmon-mac-mini.dtsi
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * hwmon sensors expected on all Mac mini models
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+#include "hwmon-fan.dtsi"
+
+&smc_hwmon {
+	temperature-TW0P {
+		apple,key-id = "TW0P";
+		label = "WiFi/BT Module Temperature";
+	};
+};
diff --git a/arch/arm64/boot/dts/apple/t6001-j375c.dts b/arch/arm64/boot/dts/apple/t6001-j375c.dts
index 2e7c23714d4d..08276114c1d8 100644
--- a/arch/arm64/boot/dts/apple/t6001-j375c.dts
+++ b/arch/arm64/boot/dts/apple/t6001-j375c.dts
@@ -24,3 +24,5 @@ &wifi0 {
 &bluetooth0 {
 	brcm,board-type = "apple,okinawa";
 };
+
+#include "hwmon-fan-dual.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t6001.dtsi b/arch/arm64/boot/dts/apple/t6001.dtsi
index ffbe823b71bc..264df90f07d8 100644
--- a/arch/arm64/boot/dts/apple/t6001.dtsi
+++ b/arch/arm64/boot/dts/apple/t6001.dtsi
@@ -66,3 +66,5 @@ p-core-pmu-affinity {
 &gpu {
 	compatible = "apple,agx-g13c", "apple,agx-g13s";
 };
+
+#include "hwmon-common.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t6002-j375d.dts b/arch/arm64/boot/dts/apple/t6002-j375d.dts
index 2b7f80119618..d12c0ae418f7 100644
--- a/arch/arm64/boot/dts/apple/t6002-j375d.dts
+++ b/arch/arm64/boot/dts/apple/t6002-j375d.dts
@@ -56,3 +56,5 @@ &bluetooth0 {
 
 /delete-node/ &ps_disp0_cpu0_die1;
 /delete-node/ &ps_disp0_fe_die1;
+
+#include "hwmon-fan-dual.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi
index f715b19efd16..e6647c1a9173 100644
--- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi
+++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi
@@ -37,6 +37,10 @@ smc_gpio: gpio {
 			#gpio-cells = <2>;
 		};
 
+		smc_hwmon: hwmon {
+			compatible = "apple,smc-hwmon";
+		};
+
 		smc_reboot: reboot {
 			compatible = "apple,smc-reboot";
 			nvmem-cells = <&shutdown_flag>, <&boot_stage>,
diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi
index c0aac59a6fae..127814a9dfa4 100644
--- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi
+++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi
@@ -131,3 +131,6 @@ &fpwm0 {
 };
 
 #include "spi1-nvram.dtsi"
+
+#include "hwmon-laptop.dtsi"
+#include "hwmon-fan-dual.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t602x-die0.dtsi b/arch/arm64/boot/dts/apple/t602x-die0.dtsi
index 8622ddea7b44..680c103c1c0f 100644
--- a/arch/arm64/boot/dts/apple/t602x-die0.dtsi
+++ b/arch/arm64/boot/dts/apple/t602x-die0.dtsi
@@ -114,6 +114,10 @@ smc_gpio: gpio {
 			#gpio-cells = <2>;
 		};
 
+		smc_hwmon: hwmon {
+			compatible = "apple,smc-hwmon";
+		};
+
 		smc_reboot: reboot {
 			compatible = "apple,smc-reboot";
 			nvmem-cells = <&shutdown_flag>, <&boot_stage>,
diff --git a/arch/arm64/boot/dts/apple/t8103-j274.dts b/arch/arm64/boot/dts/apple/t8103-j274.dts
index 1c3e37f86d46..f5b8cc087882 100644
--- a/arch/arm64/boot/dts/apple/t8103-j274.dts
+++ b/arch/arm64/boot/dts/apple/t8103-j274.dts
@@ -61,3 +61,5 @@ &pcie0_dart_2 {
 &i2c2 {
 	status = "okay";
 };
+
+#include "hwmon-mac-mini.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t8103-j293.dts b/arch/arm64/boot/dts/apple/t8103-j293.dts
index 5b3c42e9f0e6..abb88391635f 100644
--- a/arch/arm64/boot/dts/apple/t8103-j293.dts
+++ b/arch/arm64/boot/dts/apple/t8103-j293.dts
@@ -119,3 +119,6 @@ dfr_panel_in: endpoint {
 &displaydfr_dart {
 	status = "okay";
 };
+
+#include "hwmon-laptop.dtsi"
+#include "hwmon-fan.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t8103-j313.dts b/arch/arm64/boot/dts/apple/t8103-j313.dts
index 97a4344d8dca..491ead016b21 100644
--- a/arch/arm64/boot/dts/apple/t8103-j313.dts
+++ b/arch/arm64/boot/dts/apple/t8103-j313.dts
@@ -41,3 +41,5 @@ &wifi0 {
 &fpwm1 {
 	status = "okay";
 };
+
+#include "hwmon-laptop.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t8103-j456.dts b/arch/arm64/boot/dts/apple/t8103-j456.dts
index 58c8e43789b4..c2ec6fbb633c 100644
--- a/arch/arm64/boot/dts/apple/t8103-j456.dts
+++ b/arch/arm64/boot/dts/apple/t8103-j456.dts
@@ -75,3 +75,5 @@ &pcie0_dart_1 {
 &pcie0_dart_2 {
 	status = "okay";
 };
+
+#include "hwmon-fan-dual.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t8103-j457.dts b/arch/arm64/boot/dts/apple/t8103-j457.dts
index 7089ccf3ce55..aeaab2482d54 100644
--- a/arch/arm64/boot/dts/apple/t8103-j457.dts
+++ b/arch/arm64/boot/dts/apple/t8103-j457.dts
@@ -56,3 +56,5 @@ ethernet0: ethernet at 0,0 {
 &pcie0_dart_2 {
 	status = "okay";
 };
+
+#include "hwmon-fan.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi
index 59f2678639cf..f1820bdc0910 100644
--- a/arch/arm64/boot/dts/apple/t8103.dtsi
+++ b/arch/arm64/boot/dts/apple/t8103.dtsi
@@ -909,6 +909,10 @@ smc_gpio: gpio {
 				#gpio-cells = <2>;
 			};
 
+			smc_hwmon: hwmon {
+				compatible = "apple,smc-hwmon";
+			};
+
 			smc_reboot: reboot {
 				compatible = "apple,smc-reboot";
 				nvmem-cells = <&shutdown_flag>, <&boot_stage>,
@@ -1141,3 +1145,4 @@ port02: pci at 2,0 {
 };
 
 #include "t8103-pmgr.dtsi"
+#include "hwmon-common.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t8112-j413.dts b/arch/arm64/boot/dts/apple/t8112-j413.dts
index 6f69658623bf..500dcdf2d4b5 100644
--- a/arch/arm64/boot/dts/apple/t8112-j413.dts
+++ b/arch/arm64/boot/dts/apple/t8112-j413.dts
@@ -78,3 +78,5 @@ &i2c4 {
 &fpwm1 {
 	status = "okay";
 };
+
+#include "hwmon-laptop.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t8112-j473.dts b/arch/arm64/boot/dts/apple/t8112-j473.dts
index 06fe257f08be..11db6a92493f 100644
--- a/arch/arm64/boot/dts/apple/t8112-j473.dts
+++ b/arch/arm64/boot/dts/apple/t8112-j473.dts
@@ -52,3 +52,5 @@ &pcie1_dart {
 &pcie2_dart {
 	status = "okay";
 };
+
+#include "hwmon-mac-mini.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t8112-j493.dts b/arch/arm64/boot/dts/apple/t8112-j493.dts
index fb8ad7d4c65a..a0da02c00f15 100644
--- a/arch/arm64/boot/dts/apple/t8112-j493.dts
+++ b/arch/arm64/boot/dts/apple/t8112-j493.dts
@@ -133,3 +133,6 @@ touchbar0: touchbar at 0 {
 		touchscreen-inverted-y;
 	};
 };
+
+#include "hwmon-laptop.dtsi"
+#include "hwmon-fan.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi
index 6bc3f58b06f7..c4d1e5ffaee9 100644
--- a/arch/arm64/boot/dts/apple/t8112.dtsi
+++ b/arch/arm64/boot/dts/apple/t8112.dtsi
@@ -912,6 +912,10 @@ smc_gpio: gpio {
 				#gpio-cells = <2>;
 			};
 
+			smc_hwmon: hwmon {
+				compatible = "apple,smc-hwmon";
+			};
+
 			smc_reboot: reboot {
 				compatible = "apple,smc-reboot";
 				nvmem-cells = <&shutdown_flag>, <&boot_stage>,
@@ -1180,3 +1184,4 @@ port03: pci at 3,0 {
 };
 
 #include "t8112-pmgr.dtsi"
+#include "hwmon-common.dtsi"

-- 
2.52.0



From leo.yan at arm.com  Mon Dec 15 01:51:03 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 15 Dec 2025 09:51:03 +0000
Subject: [PATCH v2 RESEND] coresight: etm-perf: Fix reference count leak
 in etm_setup_aux
In-Reply-To: <c698d581-da15-42bf-9612-62f1bad66615@linaro.org>
References: <20251215022709.17220-1-make24@iscas.ac.cn>
 <c698d581-da15-42bf-9612-62f1bad66615@linaro.org>
Message-ID: <20251215095103.GA681384@e132581.arm.com>

On Mon, Dec 15, 2025 at 11:02:08AM +0200, James Clark wrote:
> 
> 
> On 15/12/2025 04:27, Ma Ke wrote:
> > In etm_setup_aux(), when a user sink is obtained via
> > coresight_get_sink_by_id(), it increments the reference count of the
> > sink device. However, if the sink is used in path building, the path
> > holds a reference, but the initial reference from
> > coresight_get_sink_by_id() is not released, causing a reference count
> > leak. We should release the initial reference after the path is built.
> > 
> > Found by code review.
> > 
> > Cc: stable at vger.kernel.org
> > Fixes: 0e6c20517596 ("coresight: etm-perf: Allow an event to use different sinks")
> > Signed-off-by: Ma Ke <make24 at iscas.ac.cn>
> > ---
> > Changes in v2:
> > - modified the patch as suggestions.
> 
> I think Leo's comment on the previous v2 is still unaddressed. But releasing
> it in coresight_get_sink_by_id() would make it consistent with
> coresight_find_csdev_by_fwnode() and prevent further mistakes.

The point is the coresight core layer uses coresight_grab_device() to
increase the device's refcnt.  This is why we don't need to grab a
device when setup AUX.

> It also leads me to see that users of coresight_find_device_by_fwnode()
> should also release it, but only one out of two appears to.

Good finding!

Thanks,
Leo


From laurent.pinchart at ideasonboard.com  Mon Dec 15 01:52:48 2025
From: laurent.pinchart at ideasonboard.com (Laurent Pinchart)
Date: Mon, 15 Dec 2025 18:52:48 +0900
Subject: [PATCH 06/26] drm/bridge: add devm_drm_of_find_bridge
In-Reply-To: <20251215-magnetic-stoic-okapi-d40cc1@penduick>
References: <20251119-drm-bridge-alloc-getput-drm_of_find_bridge-v1-0-0db98a7fe474@bootlin.com>
 <20251119-drm-bridge-alloc-getput-drm_of_find_bridge-v1-6-0db98a7fe474@bootlin.com>
 <hs44z4b2dgisemuewgtvl4epjcqqilg6cy36po25pubaog4hmq@33qgl4o3hwoa>
 <DEH2CVQV21Z2.25PJBAQAKFJSG@bootlin.com>
 <20251201-thick-jasmine-oarfish-1eceb0@houat>
 <DEVKQWH8GU0D.2NWQ1U7IOIEHI@bootlin.com>
 <20251215-magnetic-stoic-okapi-d40cc1@penduick>
Message-ID: <20251215095248.GB11477@pendragon.ideasonboard.com>

On Mon, Dec 15, 2025 at 10:41:32AM +0100, Maxime Ripard wrote:
> On Thu, Dec 11, 2025 at 06:47:37PM +0100, Luca Ceresoli wrote:
> > Hi Maxime,
> > 
> > On Mon Dec 1, 2025 at 5:51 PM CET, Maxime Ripard wrote:
> > > On Mon, Nov 24, 2025 at 05:25:39PM +0100, Luca Ceresoli wrote:
> > >> Hi Maxime,
> > >>
> > >> On Mon Nov 24, 2025 at 11:39 AM CET, Maxime Ripard wrote:
> > >> > On Wed, Nov 19, 2025 at 02:05:37PM +0100, Luca Ceresoli wrote:
> > >> >> Several drivers (about 20) follow the same pattern:
> > >> >>
> > >> >>  1. get a pointer to a bridge (typically the next bridge in the chain) by
> > >> >>     calling of_drm_find_bridge()
> > >> >>  2. store the returned pointer in the private driver data, keep it until
> > >> >>     driver .remove
> > >> >>  3. dereference the pointer at attach time and possibly at other times
> > >> >>
> > >> >> of_drm_find_bridge() is now deprecated because it does not increment the
> > >> >> refcount and should be replaced with drm_of_find_bridge() +
> > >> >> drm_bridge_put().
> > >> >>
> > >> >> However some of those drivers have a complex code flow and adding a
> > >> >> drm_bridge_put() call in all the appropriate locations is error-prone,
> > >> >> leads to ugly and more complex code, and can lead to errors over time with
> > >> >> code flow changes.
> > >> >>
> > >> >> To handle all those drivers in a straightforward way, add a devm variant of
> > >> >> drm_of_find_bridge() that adds a devm action to invoke drm_bridge_put()
> > >> >> when the said driver is removed. This allows all those drivers to put the
> > >> >> reference automatically and safely with a one line change:
> > >> >>
> > >> >>   - priv->next_bridge = of_drm_find_bridge(remote_np);
> > >> >>   + priv->next_bridge = devm_drm_of_find_bridge(dev, remote_np);
> > >> >>
> > >> >> Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
> > >> >>
> > >> >> ---
> > >> >>  drivers/gpu/drm/drm_bridge.c | 30 ++++++++++++++++++++++++++++++
> > >> >>  include/drm/drm_bridge.h     |  5 +++++
> > >> >>  2 files changed, 35 insertions(+)
> > >> >>
> > >> >> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> > >> >> index 09ad825f9cb8..c7baafbe5695 100644
> > >> >> --- a/drivers/gpu/drm/drm_bridge.c
> > >> >> +++ b/drivers/gpu/drm/drm_bridge.c
> > >> >> @@ -1446,6 +1446,36 @@ struct drm_bridge *drm_of_find_bridge(struct device_node *np)
> > >> >>  }
> > >> >>  EXPORT_SYMBOL(drm_of_find_bridge);
> > >> >>
> > >> >> +/**
> > >> >> + * devm_drm_of_find_bridge - find the bridge corresponding to the device
> > >> >> + *			     node in the global bridge list and add a devm
> > >> >> + *			     action to put it
> > >> >> + *
> > >> >> + * @dev: device requesting the bridge
> > >> >> + * @np: device node
> > >> >> + *
> > >> >> + * On success the returned bridge refcount is incremented, and a devm
> > >> >> + * action is added to call drm_bridge_put() when @dev is removed. So the
> > >> >> + * caller does not have to put the returned bridge explicitly.
> > >> >> + *
> > >> >> + * RETURNS:
> > >> >> + * drm_bridge control struct on success, NULL on failure
> > >> >> + */
> > >> >> +struct drm_bridge *devm_drm_of_find_bridge(struct device *dev, struct device_node *np)
> > >> >> +{
> > >> >> +	struct drm_bridge *bridge = drm_of_find_bridge(np);
> > >> >> +
> > >> >> +	if (bridge) {
> > >> >> +		int err = devm_add_action_or_reset(dev, drm_bridge_put_void, bridge);
> > >> >> +
> > >> >> +		if (err)
> > >> >> +			return ERR_PTR(err);
> > >> >> +	}
> > >> >> +
> > >> >> +	return bridge;
> > >> >> +}
> > >> >> +EXPORT_SYMBOL(devm_drm_of_find_bridge);
> > >> >
> > >> > That's inherently unsafe though, because even if the bridge is removed
> > >> > other parts of DRM might still have a reference to it and could call
> > >> > into it.
> > >> >
> > >> > We'd then have dropped our reference to the next bridge, which could
> > >> > have been freed, and it's a use-after-free.
> > >>
> > >> I think you refer to this scenario:
> > >>
> > >>   1. pipeline: encoder --> bridge A --> bridge B --> bridge C
> > >>   2. encoder takes a reference to bridge B
> > >>      using devm_drm_of_find_bridge() or other means
> > >>   3. bridge B takes a next_bridge reference to bridge C
> > >>      using devm_drm_of_find_bridge()
> > >>   4. encoder calls (bridge B)->foo(), which in turns references
> > >>      next_bridge, e.g.:
> > >>
> > >>        b_foo() {
> > >>            bar(b->next_bridge);
> > >>        }
> > >>
> > >> If bridges B and C are removed, bridge C can be freed but B is still
> > >> allocated because the encoder holds a ref. So when step 4 happens, 'b->c'
> > >> would be a use-after-free (or NULL deref if b.remove cleared it, which is
> > >> just as bad).
> > >
> > > Yep.
> > >
> > >> If I got you correctly, then I'm a bit surprised by your comment. This
> > >> series is part of the first chapter of the hotplug work, which does not aim
> > >> at fixing everything but rather at fixing one part: handle dynamic
> > >> _allocation_ lifetime of drm_bridges by adding a refcount and
> > >> drm_bridge_get/put().
> > >>
> > >> Chapter 2 of the work is adding drm_bridge_enter/exit/unplug() [1] and
> > >> other changes in order to avoid code of drivers of removed bridges to
> > >> access fields they shouldn't. So the above example at point 4 would become:
> > >>
> > >>        b_foo() {
> > >>            if (!drm_bridge_enter())
> > >>                return;
> > >>            bar(b->c);
> > >>            drm_bridge_exit();
> > >>        }
> > >>
> > >> And that avoids 'b->c' after bridge B is removed.
> > >>
> > >> Does that answer your remark?
> > >
> > > Not really. I wasn't really questionning your current focus, or the way
> > > you laid out the current agenda or whatever.
> > >
> > > What I am questionning though is whether or not we want to introduce
> > > something we will have to untangle soon, and even more so when we're not
> > > mentioning it anywhere.
> > >
> > >> > It's more complicated than it sounds, because we only have access to the
> > >> > drm_device when the bridge is attached, so later than probe.
> > >> >
> > >> > I wonder if we shouldn't tie the lifetime of that reference to the
> > >> > lifetime of the bridge itself, and we would give up the next_bridge
> > >> > reference only when we're destroyed ourselves.
> > >>
> > >> I'm afraid I'm not following you, sorry. Do you refer to the time between
> > >> the bridge removal (driver .remove) and the last bridge put (when
> > >> deallocation happens)?
> > >>
> > >> In that time frame the struct drm_bridge is still allocated along with any
> > >> next_bridge pointer it may contain, but the following bridge could have
> > >> been deallocated.
> > >>
> > >> What do you mean by "give up the next_bridge"?
> > >
> > > What I was trying to say was that if we want to fix the problem you
> > > illustrated about, we need to give up the reference at __drm_bridge_free
> > > time. So each bridge having a reference to a bridge would need to do so
> > > in its destroy hook.
> > >
> > > Since it's quite a common pattern, it would make sense to add a
> > > next_bridge field to drm_bridge itself, so the core can do it
> > > automatically in __drm_bridge_free if that pointer is !NULL.
> > >
> > > But...
> > >
> > >> > Storing a list of all the references we need to drop is going to be
> > >> > intrusive though, so maybe the easiest way to do it would be to create a
> > >> > next_bridge field in drm_bridge, and only drop the reference stored
> > >> > there?
> > >> >
> > >> > And possibly tie the whole thing together using a helper?
> > >> >
> > >> > Anyway, I'm not sure it should be a prerequisite to this series. I we do
> > >> > want to go the devm_drm_of_find_bridge route however, we should at least
> > >> > document that it's unsafe, and add a TODO entry to clean up the mess
> > >> > later on.
> > >
> > > ... I *really* don't consider it something you need to work on right now.
> > >
> > >> Do you mean the drm variant is unsafe while the original
> > >> (drm_of_find_bridge() in this series, might be renamed) is not? I
> > >> don't see how that can happen. If the driver for bridge B were to use
> > >> drm_of_find_bridge(), that driver would be responsible to
> > >> drm_bridge_put(b->next_bridge) in its .remove() function or earlier.
> > >> So the next_bridge pointing to bridge C would equally become subject
> > >> to use-after-free.
> > >
> > > No, I was saying that both are equally unsafe. But we're adding a new,
> > > broken, helper, and we don't mention anywhere that it is. So what I was
> > > saying is mostly do we really want to introduce some more broken code
> > > when we know it is. And if we do, we should be really clear about it.
> > >
> > >> devm does not make it worse, on the opposite it postpones the
> > >> drm_bridge_put(next_bridge) as late as possible: just after
> > >> b.remove().
> > >
> > > Which doesn't really change anything, does it? I'd expect the window
> > > between the remove and final drm_bridge_put to be much wider than the
> > > execution time of remove itself.
> > >
> > >> One final, high-level thought about the various 'next_bridge' pointers that
> > >> many bridge drivers have. Most of them do:
> > >>
> > >>  0. have a 'struct drm_bridge next_bridge *' in their private struct
> > >>  1. take the next_bridge reference during probe or another startup phase
> > >>  2. store it in their private driver struct
> > >>  3. use it to call drm_bridge_attach
> > >>  4. (pending) put the reference to it in their .remove or earlier
> > >>
> > >> I'm wondering whether we could let the DRM bridge core do it all, by
> > >> removing items 0, 1, 2 and 4, and change 3 as:
> > >>
> > >> -     drm_bridge_attach(encoder, me->next_bridge, &me->bridge, flags);
> > >> +  drm_of_bridge_attach(encoder, &me->bridge, dev->of_node, 1, -1, flags);
> > >>
> > >> where dev->of_node and the following integers are the same flags passed to
> > >> devm_drm_of_get_bridge() and the like, i.e. the endpoint info needed to
> > >> walk the DT graph and reach the next bridge.
> > >>
> > >> This would allow the core to take care of all locking and lifetime of the
> > >> next bridge, and most (all?) bridges would never access any pointers to the
> > >> next bridge. The idea is to let the core do the right thing in a single
> > >> place instead of trying to make all drivers do the right thing (and
> > >> touching dozen files when needing to touch the logic).
> > >>
> > >> That is more a long-term ideal than something I'd do right now, but having
> > >> opinions would be very interesting.
> > >
> > > That was pretty much my point, yeah.
> > >
> > > Maxime
> > 
> > Let me recap this discussion, because there are various aspects and I need
> > to clarify by view on it.
> > 
> > First: the problem you discuss is about drm_of_find_bridge() introduced in
> > patch 1. The devm variant is just equally affected.
> > 
> > You proposed adding a next_bridge field in struct drm_bridge so there is an
> > automated, common call to drm_bridge_put() (and setting it to NULL). It
> > would remove some burden on individual drivers of course, but I don't think
> > it would solve the problem. In the same scenario we are discussing
> > (i.e. encoder --> bridge A --> bridge B --> bridge C, then B+C get removed)
> > B's next_bridge would be automatically put, but the encoder could still
> > call B->foo(), which could still do B->next_bridge.
> 
> I mean, yes, that's what we have drm_bridge_enter and _exit for.
> B->next_bridge would still be valid, but we also still would have a
> reference to C so I'm not sure what the big deal is?
> 
> > Additionally, as a matter of fact there are currently drivers storing
> > bridge pointers. The next_bridge is the most common case. Code using
> > drm_bridge_connector_init() for example can store up to eight of them, but
> > individual drivers are the hardest to hunt for.
> 
> That's fine, we can have a custom destroy hook for those.
> 
> > I can see these (potential) tools to handle this (not mutually exclusive):
> > 
> >  1. remove drm_bridge pointers pointing to other bridges
> >  2. check whether a bridge (say B) still exists before any dereference
> >     to B->another_bridge: that's drm_bridge_enter/exit()
> >  3. let owners of bridge pointers be notified when a bridge is unplugged,
> >     so they can actively put their reference and clear their pointer
> > 
> > For item 1, I think the drm_of_bridge_attach() idea quoted above would
> > work, at least for the simple cases where bridge drivers use the
> > next_bridge only for attach. A next_bridge pointer in struct drm_bridge is
> > not even needed in that case, the pointer would be computed from OF when
> > needed and not stored. I can do an experiment and send a first series, do
> > you think it would be useful?
> > 
> > For item 2, I still think it would just work for cases not (or not yet)
> > covered by item 1. Given the same example as above:
> > 
> >         b_foo() {
> >             if (!drm_bridge_enter())
> >                 return;
> >             bar(b->c);
> >             drm_bridge_exit();
> >         }
> > 
> > drm_bridge_enter() will prevent doing anything on b->whatever, including
> > any stale pointers. The idea is "I, bridge B, have been unplugged, my
> > resources are not reliably usable, keep out!". No?
> 
> Yes.
> 
> > However item 2 won't prevent the caller from keeping the pointer for a long
> > time, especially if b_foo() is a void function so it cannot return anything
> > saying "I was unplugged, I'm no longer theree".
> 
> Indeed.
> 
> > And that's where item 3 (notifiers) might come in useful: upon
> > receiving a bridge removal notification any driver or other code is in
> > a position to actively put its reference to the bridge and clear its
> > pointer. I had proposed something in [0], which can likely be
> > improved, but it is useful in my current draft solution.
> > 
> > I'd like to know your opinions about the above points, so we can
> > progressively clarify the path forward.
> 
> I largely agree with everything you said, but that wasn't my point at
> the beginning of the discussion though. My point was that you're giving
> away the reference too soon with devm_drm_of_find_bridge (or by doing it
> in remove).
> 
> > PS: I just realized about a fourth option: a revocable [1] (thanks Laurent
> > who pointed me to it). That's basically a wrapper around a pointer that
> > allows to guard from accessing it when the pointed object is gone. To me it
> > looks somewhat equivalent to drm_bridge_enter/exit() but with very
> > different APIs. I still haven't looked at the details.
> 
> Yeah, a revocable pointer would work too. It will be a pain to implement
> in C though.

I discussed this with Tzung-Bi at LPC, which gave me a more detailed
view of the particular issue he was trying to solve. I believe that
reference-counting is a better solution than the new revocable API for
the cros-ec drivers. The revocable API may still have its place in the
kernel, but I increasingly think that it may be a workaround for cases
where introducing reference counting would be very difficult due to
historical reasons.

-- 
Regards,

Laurent Pinchart


From jackmanb at google.com  Mon Dec 15 01:55:26 2025
From: jackmanb at google.com (Brendan Jackman)
Date: Mon, 15 Dec 2025 09:55:26 +0000
Subject: [PATCH 2/2] arm64: mmu: use pagetable_alloc_nolock() while stop_machine()
In-Reply-To: <aT/WOAr4osoJWaMS@e129823.arm.com>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com> <20251212161832.2067134-3-yeoreum.yun@arm.com>
 <CA+i-1C2e7QNTy5u=HF7tLsLXLq4xYbMTCbNjWGAxHz4uwgR05g@mail.gmail.com>
 <aT5/y3cSGIzi2K+m@e129823.arm.com> <DEYOI8H2OESD.1H56D3H8HKILB@google.com> <aT/WOAr4osoJWaMS@e129823.arm.com>
Message-ID: <DEYP7JSVTB9D.3EFN2KEHH3O79@google.com>

On Mon Dec 15, 2025 at 9:34 AM UTC, Yeoreum Yun wrote:
> Hi Brendan,
>> On Sun Dec 14, 2025 at 9:13 AM UTC, Yeoreum Yun wrote:
>> >> I don't have the context on what this code is doing so take this with
>> >> a grain of salt, but...
>> >>
>> >> The point of the _nolock alloc is to give the allocator an excuse to
>> >> fail. Panicking on that failure doesn't seem like a great idea to me?
>> >
>> > I thought first whether it changes to "static" memory area to handle
>> > this in PREEMPT_RT.
>> > But since this function is called while smp_cpus_done().
>> > So, I think it's fine since there wouldn't be a contention for
>> > memory allocation in this phase.
>>
>> Then shouldn't it use _nolock unconditionally?
>
> As you pointed out, I think it should be fine even in the !PREEMPT_RT case.
> However, in case I missed something or if my understanding is incorrect,
> I applied it only to the PREEMPT_RT case for now.

Hmm, I don't think "this code might be broken so let's cage it behind a
conditional" is a good strategy.

1. It bloats the codebase.

2. It's confusing to readers, now you have to try an understand why this
   conditional is here, which is a doomed effort. This could be
   mitigated with comments but, see point 1.

3. It expands the testing matrix. So now we have code that we aren't
   really sure is correct, AND it gets less test coverage.

Overall I am feeling a bit uncomfortable about this use of _nolock, but
I am also feeling pretty ignorant about PREEMPT_RT and also about this
arm64 code, so I am hesitant to suggest alternatives, I hope someone
else can offer some input here...


From peter.maydell at linaro.org  Mon Dec 15 01:56:45 2025
From: peter.maydell at linaro.org (Peter Maydell)
Date: Mon, 15 Dec 2025 09:56:45 +0000
Subject: [PATCH 31/32] Documentation: KVM: Introduce documentation for VGICv5
In-Reply-To: <20251212152215.675767-32-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com> <20251212152215.675767-32-sascha.bischoff@arm.com>
Message-ID: <CAFEAcA-fgWOUu7yWfGNGyy0BwTPxH1ht+E5SQ4tjJf3U=w7e6w@mail.gmail.com>

On Fri, 12 Dec 2025 at 15:24, Sascha Bischoff <Sascha.Bischoff at arm.com> wrote:
>
> Now that it is possible to create a VGICv5 device, provide initial
> documentation for it. At this stage, there is little to document.

Is userspace access to read/write the GICv5 register state also
in the "will be added a in future patchseries" category ?

thanks
-- PMM


From yeoreum.yun at arm.com  Mon Dec 15 01:56:04 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Mon, 15 Dec 2025 09:56:04 +0000
Subject: [PATCH v11 RESEND 9/9] arm64: armv8_deprecated: apply FEAT_LSUI
 for swpX emulation.
In-Reply-To: <86ms3knl6s.wl-maz@kernel.org>
References: <20251214112248.901769-1-yeoreum.yun@arm.com>
 <20251214112248.901769-10-yeoreum.yun@arm.com>
 <86ms3knl6s.wl-maz@kernel.org>
Message-ID: <aT/bNLQyKcrAZ6Fb@e129823.arm.com>

Hi,

> On Sun, 14 Dec 2025 11:22:48 +0000,
> Yeoreum Yun <yeoreum.yun at arm.com> wrote:
> >
> > Apply the FEAT_LSUI instruction to emulate the deprecated swpX
> > instruction, so that toggling of the PSTATE.PAN bit can be removed when
> > LSUI-related instructions are used.
> >
> > Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
>
> It really begs the question: what are the odds of ever seeing a CPU
> that implements both LSUI and AArch32?
>
> This seems extremely unlikely to me.

Well, I'm not sure how many CPU will have
both ID_AA64PFR0_EL1.EL0 bit as 0b0010 and FEAT_LSUI
(except FVP currently) -- at least the CPU what I saw,
most of them set ID_AA64PFR0_EL1.EL0 as 0b0010.

If you this seems useless, I don't have any strong comments
whether drop patches related to deprecated swp instruction parts
(patch 8-9 only) or not.
(But, I hope to pass this decision to maintaining perspective...)

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

--
Sincerely,
Yeoreum Yun


From yeoreum.yun at arm.com  Mon Dec 15 02:06:38 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Mon, 15 Dec 2025 10:06:38 +0000
Subject: [PATCH 2/2] arm64: mmu: use pagetable_alloc_nolock() while
 stop_machine()
In-Reply-To: <DEYP7JSVTB9D.3EFN2KEHH3O79@google.com>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com>
 <20251212161832.2067134-3-yeoreum.yun@arm.com>
 <CA+i-1C2e7QNTy5u=HF7tLsLXLq4xYbMTCbNjWGAxHz4uwgR05g@mail.gmail.com>
 <aT5/y3cSGIzi2K+m@e129823.arm.com>
 <DEYOI8H2OESD.1H56D3H8HKILB@google.com>
 <aT/WOAr4osoJWaMS@e129823.arm.com>
 <DEYP7JSVTB9D.3EFN2KEHH3O79@google.com>
Message-ID: <aT/drjN1BkvyAGoi@e129823.arm.com>

> On Mon Dec 15, 2025 at 9:34 AM UTC, Yeoreum Yun wrote:
> > Hi Brendan,
> >> On Sun Dec 14, 2025 at 9:13 AM UTC, Yeoreum Yun wrote:
> >> >> I don't have the context on what this code is doing so take this with
> >> >> a grain of salt, but...
> >> >>
> >> >> The point of the _nolock alloc is to give the allocator an excuse to
> >> >> fail. Panicking on that failure doesn't seem like a great idea to me?
> >> >
> >> > I thought first whether it changes to "static" memory area to handle
> >> > this in PREEMPT_RT.
> >> > But since this function is called while smp_cpus_done().
> >> > So, I think it's fine since there wouldn't be a contention for
> >> > memory allocation in this phase.
> >>
> >> Then shouldn't it use _nolock unconditionally?
> >
> > As you pointed out, I think it should be fine even in the !PREEMPT_RT case.
> > However, in case I missed something or if my understanding is incorrect,
> > I applied it only to the PREEMPT_RT case for now.
>
> Hmm, I don't think "this code might be broken so let's cage it behind a
> conditional" is a good strategy.
>
> 1. It bloats the codebase.
>
> 2. It's confusing to readers, now you have to try an understand why this
>    conditional is here, which is a doomed effort. This could be
>    mitigated with comments but, see point 1.
>
> 3. It expands the testing matrix. So now we have code that we aren't
>    really sure is correct, AND it gets less test coverage.
>
> Overall I am feeling a bit uncomfortable about this use of _nolock, but
> I am also feeling pretty ignorant about PREEMPT_RT and also about this
> arm64 code, so I am hesitant to suggest alternatives, I hope someone
> else can offer some input here...

I understand. However, as I mentioned earlier,
my main intention was to hear opinions specifically about memory contention.

That said, if there is no memory contention,
I don?t think using the _nolock API is necessarily a bad approach.
In fact, I believe a bigger issue is that, under PREEMPT_RT,
code that uses the regular memory allocation APIs may give users the false impression
that those APIs are ?safe to use,? even though they are not.

--
Sincerely,
Yeoreum Yun


From jie.gan at oss.qualcomm.com  Mon Dec 15 02:09:45 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Mon, 15 Dec 2025 18:09:45 +0800
Subject: [PATCH v2 RESEND] coresight: etm-perf: Fix reference count leak
 in etm_setup_aux
In-Reply-To: <20251215095103.GA681384@e132581.arm.com>
References: <20251215022709.17220-1-make24@iscas.ac.cn>
 <c698d581-da15-42bf-9612-62f1bad66615@linaro.org>
 <20251215095103.GA681384@e132581.arm.com>
Message-ID: <f85c7d37-4980-46f0-9136-353a35a8f0ed@oss.qualcomm.com>



On 12/15/2025 5:51 PM, Leo Yan wrote:
> On Mon, Dec 15, 2025 at 11:02:08AM +0200, James Clark wrote:
>>
>>
>> On 15/12/2025 04:27, Ma Ke wrote:
>>> In etm_setup_aux(), when a user sink is obtained via
>>> coresight_get_sink_by_id(), it increments the reference count of the
>>> sink device. However, if the sink is used in path building, the path
>>> holds a reference, but the initial reference from
>>> coresight_get_sink_by_id() is not released, causing a reference count
>>> leak. We should release the initial reference after the path is built.
>>>
>>> Found by code review.
>>>
>>> Cc: stable at vger.kernel.org
>>> Fixes: 0e6c20517596 ("coresight: etm-perf: Allow an event to use different sinks")
>>> Signed-off-by: Ma Ke <make24 at iscas.ac.cn>
>>> ---
>>> Changes in v2:
>>> - modified the patch as suggestions.
>>
>> I think Leo's comment on the previous v2 is still unaddressed. But releasing
>> it in coresight_get_sink_by_id() would make it consistent with
>> coresight_find_csdev_by_fwnode() and prevent further mistakes.
> 
> The point is the coresight core layer uses coresight_grab_device() to
> increase the device's refcnt.  This is why we don't need to grab a
> device when setup AUX.

That make sense. We dont need to hold the refcnt for a while and it 
should be released immediately after locating the required device.

Thanks,
Jie

> 
>> It also leads me to see that users of coresight_find_device_by_fwnode()
>> should also release it, but only one out of two appears to.
> 
> Good finding!
> 
> Thanks,
> Leo
> 



From peng.fan at nxp.com  Mon Dec 15 02:15:36 2025
From: peng.fan at nxp.com (Peng Fan)
Date: Mon, 15 Dec 2025 10:15:36 +0000
Subject: [PATCH] remoteproc: imx_rproc: Use strstarts for "rsc-table"
 check
In-Reply-To: <20251208233302.684139-1-shenwei.wang@nxp.com>
References: <20251208233302.684139-1-shenwei.wang@nxp.com>
Message-ID: <PAXPR04MB84599C141E28B6B83BD62C2388ADA@PAXPR04MB8459.eurprd04.prod.outlook.com>

Hi Shenwei,

> Subject: [PATCH] remoteproc: imx_rproc: Use strstarts for "rsc-table"
> check
> 
> The resource name may include an address suffix, for example:
> rsc-table at 1fff8000.

device_node->name does not contain the suffix "@xyz".
device_node->full_name contains the name and "@xyz"

Do you see the device_node->name is rsc-table at 1fff8000 in your test? 

Regards
Peng.

> 
> To handle such cases, use strstarts() instead of strcmp() when checking
> for "rsc-table".
> 
> Signed-off-by: Shenwei Wang <shenwei.wang at nxp.com>
> ---
>  drivers/remoteproc/imx_rproc.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/remoteproc/imx_rproc.c
> b/drivers/remoteproc/imx_rproc.c index
> 3be8790c14a2..33f21ab24c92 100644
> --- a/drivers/remoteproc/imx_rproc.c
> +++ b/drivers/remoteproc/imx_rproc.c
> @@ -694,7 +694,7 @@ static int imx_rproc_addr_init(struct imx_rproc
> *priv,
>  		}
>  		priv->mem[b].sys_addr = res.start;
>  		priv->mem[b].size = resource_size(&res);
> -		if (!strcmp(res.name, "rsc-table"))
> +		if (strstarts(res.name, "rsc-table"))
>  			priv->rsc_table = priv->mem[b].cpu_addr;
>  		b++;
>  	}
> --
> 2.43.0



From peng.fan at nxp.com  Mon Dec 15 02:20:42 2025
From: peng.fan at nxp.com (Peng Fan)
Date: Mon, 15 Dec 2025 10:20:42 +0000
Subject: [PATCH] remoteproc: imx_rproc: Use strstarts for "rsc-table"
 check
In-Reply-To: <PAXPR04MB84599C141E28B6B83BD62C2388ADA@PAXPR04MB8459.eurprd04.prod.outlook.com>
References: <20251208233302.684139-1-shenwei.wang@nxp.com>
 <PAXPR04MB84599C141E28B6B83BD62C2388ADA@PAXPR04MB8459.eurprd04.prod.outlook.com>
Message-ID: <PAXPR04MB8459D21BF666688CBBE92AE188ADA@PAXPR04MB8459.eurprd04.prod.outlook.com>

> Subject: RE: [PATCH] remoteproc: imx_rproc: Use strstarts for "rsc-
> table" check
> 
> Hi Shenwei,
> 
> > Subject: [PATCH] remoteproc: imx_rproc: Use strstarts for "rsc-table"
> > check
> >
> > The resource name may include an address suffix, for example:
> > rsc-table at 1fff8000.
> 
> device_node->name does not contain the suffix "@xyz".
> device_node->full_name contains the name and "@xyz"
> 
> Do you see the device_node->name is rsc-table at 1fff8000 in your test?

Ignore above. I use an old tree, just see this change
"remoteproc: Use of_reserved_mem_region_* functions for "memory-region"
use res to replace device_node.

Regards
Peng.

> 
> Regards
> Peng.
> 
> >
> > To handle such cases, use strstarts() instead of strcmp() when
> > checking for "rsc-table".
> >
> > Signed-off-by: Shenwei Wang <shenwei.wang at nxp.com>
> > ---
> >  drivers/remoteproc/imx_rproc.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/remoteproc/imx_rproc.c
> > b/drivers/remoteproc/imx_rproc.c index
> > 3be8790c14a2..33f21ab24c92 100644
> > --- a/drivers/remoteproc/imx_rproc.c
> > +++ b/drivers/remoteproc/imx_rproc.c
> > @@ -694,7 +694,7 @@ static int imx_rproc_addr_init(struct
> imx_rproc
> > *priv,
> >  		}
> >  		priv->mem[b].sys_addr = res.start;
> >  		priv->mem[b].size = resource_size(&res);
> > -		if (!strcmp(res.name, "rsc-table"))
> > +		if (strstarts(res.name, "rsc-table"))
> >  			priv->rsc_table = priv->mem[b].cpu_addr;
> >  		b++;
> >  	}
> > --
> > 2.43.0



From nicolas.frattaroli at collabora.com  Mon Dec 15 02:23:57 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Mon, 15 Dec 2025 11:23:57 +0100
Subject: [PATCH RESEND v3 0/5] MediaTek PLL Refactors and Fixes
Message-ID: <20251215-mtk-pll-rpm-v3-0-5afb3191e869@collabora.com>

This series refactors all users of mtk-pll, just so we can enable
runtime power management for the clock controllers that want it. It's
also generally more useful to have the struct device in the pll code,
rather than the device node.

Also fix up MT8196 mfgpll to declare its parent-child relationship with
mfg_eb, and fix the common clock framework core to take
CLK_OPS_PARENT_ENABLE into account for the recalc_rate op as well.

The reason why this is all in the same series is that it grew out of me
first modelling this as an RPM clock for mfgpll, which Angelo disagreed
with, so I did some investigation and it seems MFG_EB indeed is a parent
clock. However, the earlier refactoring to pass the device pointer down
is still useful.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
Changes in v3:
- Make device_node forward declaration a device forward declaration
- Remove forward declarations of struct clk_ops and struct
  clk_hw_onecell_data. (clk-provider.h include remains as it's needed
  for a complete type of clk_hw)
- Move PLL_PARENT_EN flag to individual mfgpll definitions.
- Link to v2: https://lore.kernel.org/r/20251008-mtk-pll-rpm-v2-0-170ed0698560 at collabora.com

Changes in v2:
- Drop bindings patch
- Drop mfgpll RPM patch
- Add patch to also transition pllfh to passing device
- Add fixes patch to make CLK_OPS_PARENT_ENABLE also apply to the
  recalc_rate operation
- Remodel mfgpll's mfg_eb dependency as parent-child with
  CLK_OPS_PARENT_ENABLE
- Link to v1: https://lore.kernel.org/r/20250929-mtk-pll-rpm-v1-0-49541777878d at collabora.com

---
Nicolas Frattaroli (5):
      clk: Respect CLK_OPS_PARENT_ENABLE during recalc
      clk: mediatek: Refactor pll registration to pass device
      clk: mediatek: Pass device to clk_hw_register for PLLs
      clk: mediatek: Refactor pllfh registration to pass device
      clk: mediatek: Add mfg_eb as parent to mt8196 mfgpll clocks

 drivers/clk/clk.c                            | 13 +++++++++++++
 drivers/clk/mediatek/clk-mt2701.c            |  2 +-
 drivers/clk/mediatek/clk-mt2712-apmixedsys.c |  2 +-
 drivers/clk/mediatek/clk-mt6735-apmixedsys.c |  4 ++--
 drivers/clk/mediatek/clk-mt6765.c            |  2 +-
 drivers/clk/mediatek/clk-mt6779.c            |  2 +-
 drivers/clk/mediatek/clk-mt6795-apmixedsys.c |  2 +-
 drivers/clk/mediatek/clk-mt6797.c            |  2 +-
 drivers/clk/mediatek/clk-mt7622-apmixedsys.c |  2 +-
 drivers/clk/mediatek/clk-mt7629.c            |  2 +-
 drivers/clk/mediatek/clk-mt7981-apmixed.c    |  2 +-
 drivers/clk/mediatek/clk-mt7986-apmixed.c    |  2 +-
 drivers/clk/mediatek/clk-mt7988-apmixed.c    |  2 +-
 drivers/clk/mediatek/clk-mt8135-apmixedsys.c |  3 ++-
 drivers/clk/mediatek/clk-mt8167-apmixedsys.c |  2 +-
 drivers/clk/mediatek/clk-mt8173-apmixedsys.c | 14 +++++++-------
 drivers/clk/mediatek/clk-mt8183-apmixedsys.c |  2 +-
 drivers/clk/mediatek/clk-mt8186-apmixedsys.c |  2 +-
 drivers/clk/mediatek/clk-mt8188-apmixedsys.c |  2 +-
 drivers/clk/mediatek/clk-mt8192-apmixedsys.c |  2 +-
 drivers/clk/mediatek/clk-mt8195-apmixedsys.c |  2 +-
 drivers/clk/mediatek/clk-mt8195-apusys_pll.c |  3 ++-
 drivers/clk/mediatek/clk-mt8196-apmixedsys.c |  3 ++-
 drivers/clk/mediatek/clk-mt8196-mcu.c        |  2 +-
 drivers/clk/mediatek/clk-mt8196-mfg.c        | 15 ++++++++-------
 drivers/clk/mediatek/clk-mt8196-vlpckgen.c   |  2 +-
 drivers/clk/mediatek/clk-mt8365-apmixedsys.c |  2 +-
 drivers/clk/mediatek/clk-mt8516-apmixedsys.c |  2 +-
 drivers/clk/mediatek/clk-pll.c               | 19 +++++++++++++------
 drivers/clk/mediatek/clk-pll.h               | 15 ++++++++-------
 drivers/clk/mediatek/clk-pllfh.c             | 13 ++++++++-----
 drivers/clk/mediatek/clk-pllfh.h             |  2 +-
 32 files changed, 87 insertions(+), 59 deletions(-)
---
base-commit: adff43957b0d8b9f6ad0e1b1f6daa7136f9ffbef
change-id: 20250929-mtk-pll-rpm-bf28192dd016

Best regards,
-- 
Nicolas Frattaroli <nicolas.frattaroli at collabora.com>



From nicolas.frattaroli at collabora.com  Mon Dec 15 02:23:58 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Mon, 15 Dec 2025 11:23:58 +0100
Subject: [PATCH RESEND v3 1/5] clk: Respect CLK_OPS_PARENT_ENABLE during
 recalc
In-Reply-To: <20251215-mtk-pll-rpm-v3-0-5afb3191e869@collabora.com>
References: <20251215-mtk-pll-rpm-v3-0-5afb3191e869@collabora.com>
Message-ID: <20251215-mtk-pll-rpm-v3-1-5afb3191e869@collabora.com>

When CLK_OPS_PARENT_ENABLE was introduced, it guarded various clock
operations, such as setting the rate or switching parents. However,
another operation that can and often does touch actual hardware state is
recalc_rate, which may also be affected by such a dependency.

Add parent enables/disables where the recalc_rate op is called directly.

Fixes: fc8726a2c021 ("clk: core: support clocks which requires parents enable (part 2)")
Fixes: a4b3518d146f ("clk: core: support clocks which requires parents enable (part 1)")
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
Reviewed-by: Chen-Yu Tsai <wenst at chromium.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/clk/clk.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 85d2f2481acf..1b0f9d567f48 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -1921,7 +1921,14 @@ static unsigned long clk_recalc(struct clk_core *core,
 	unsigned long rate = parent_rate;
 
 	if (core->ops->recalc_rate && !clk_pm_runtime_get(core)) {
+		if (core->flags & CLK_OPS_PARENT_ENABLE)
+			clk_core_prepare_enable(core->parent);
+
 		rate = core->ops->recalc_rate(core->hw, parent_rate);
+
+		if (core->flags & CLK_OPS_PARENT_ENABLE)
+			clk_core_disable_unprepare(core->parent);
+
 		clk_pm_runtime_put(core);
 	}
 	return rate;
@@ -4031,6 +4038,9 @@ static int __clk_core_init(struct clk_core *core)
 	 */
 	clk_core_update_duty_cycle_nolock(core);
 
+	if (core->flags & CLK_OPS_PARENT_ENABLE)
+		clk_core_prepare_enable(core->parent);
+
 	/*
 	 * Set clk's rate.  The preferred method is to use .recalc_rate.  For
 	 * simple clocks and lazy developers the default fallback is to use the
@@ -4046,6 +4056,9 @@ static int __clk_core_init(struct clk_core *core)
 		rate = 0;
 	core->rate = core->req_rate = rate;
 
+	if (core->flags & CLK_OPS_PARENT_ENABLE)
+		clk_core_disable_unprepare(core->parent);
+
 	/*
 	 * Enable CLK_IS_CRITICAL clocks so newly added critical clocks
 	 * don't get accidentally disabled when walking the orphan tree and

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Mon Dec 15 02:23:59 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Mon, 15 Dec 2025 11:23:59 +0100
Subject: [PATCH RESEND v3 2/5] clk: mediatek: Refactor pll registration to
 pass device
In-Reply-To: <20251215-mtk-pll-rpm-v3-0-5afb3191e869@collabora.com>
References: <20251215-mtk-pll-rpm-v3-0-5afb3191e869@collabora.com>
Message-ID: <20251215-mtk-pll-rpm-v3-2-5afb3191e869@collabora.com>

As it stands, mtk_clk_register_plls takes a struct device_node pointer
as its first argument. This is a tragic happenstance, as it's trivial to
get the device_node from a struct device, but the opposite not so much.
The struct device is a much more useful thing to have passed down.

Refactor mtk_clk_register_plls to take a struct device pointer instead
of a struct device_node pointer, and fix up all users of this function.

Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
Reviewed-by: Chen-Yu Tsai <wenst at chromium.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/clk/mediatek/clk-mt2701.c            |  2 +-
 drivers/clk/mediatek/clk-mt2712-apmixedsys.c |  2 +-
 drivers/clk/mediatek/clk-mt6735-apmixedsys.c |  4 ++--
 drivers/clk/mediatek/clk-mt6765.c            |  2 +-
 drivers/clk/mediatek/clk-mt6779.c            |  2 +-
 drivers/clk/mediatek/clk-mt6797.c            |  2 +-
 drivers/clk/mediatek/clk-mt7622-apmixedsys.c |  2 +-
 drivers/clk/mediatek/clk-mt7629.c            |  2 +-
 drivers/clk/mediatek/clk-mt7981-apmixed.c    |  2 +-
 drivers/clk/mediatek/clk-mt7986-apmixed.c    |  2 +-
 drivers/clk/mediatek/clk-mt7988-apmixed.c    |  2 +-
 drivers/clk/mediatek/clk-mt8135-apmixedsys.c |  3 ++-
 drivers/clk/mediatek/clk-mt8167-apmixedsys.c |  2 +-
 drivers/clk/mediatek/clk-mt8183-apmixedsys.c |  2 +-
 drivers/clk/mediatek/clk-mt8188-apmixedsys.c |  2 +-
 drivers/clk/mediatek/clk-mt8195-apusys_pll.c |  3 ++-
 drivers/clk/mediatek/clk-mt8196-apmixedsys.c |  3 ++-
 drivers/clk/mediatek/clk-mt8196-mcu.c        |  2 +-
 drivers/clk/mediatek/clk-mt8196-mfg.c        |  2 +-
 drivers/clk/mediatek/clk-mt8196-vlpckgen.c   |  2 +-
 drivers/clk/mediatek/clk-mt8365-apmixedsys.c |  2 +-
 drivers/clk/mediatek/clk-mt8516-apmixedsys.c |  2 +-
 drivers/clk/mediatek/clk-pll.c               |  7 ++++---
 drivers/clk/mediatek/clk-pll.h               | 10 ++++------
 24 files changed, 34 insertions(+), 32 deletions(-)

diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c
index 1e88ad8b93f4..d9f40fda73d1 100644
--- a/drivers/clk/mediatek/clk-mt2701.c
+++ b/drivers/clk/mediatek/clk-mt2701.c
@@ -978,7 +978,7 @@ static int mtk_apmixedsys_init(struct platform_device *pdev)
 	if (!clk_data)
 		return -ENOMEM;
 
-	mtk_clk_register_plls(node, apmixed_plls, ARRAY_SIZE(apmixed_plls),
+	mtk_clk_register_plls(&pdev->dev, apmixed_plls, ARRAY_SIZE(apmixed_plls),
 								clk_data);
 	mtk_clk_register_factors(apmixed_fixed_divs, ARRAY_SIZE(apmixed_fixed_divs),
 								clk_data);
diff --git a/drivers/clk/mediatek/clk-mt2712-apmixedsys.c b/drivers/clk/mediatek/clk-mt2712-apmixedsys.c
index a60622d251ff..54b18e9f83f8 100644
--- a/drivers/clk/mediatek/clk-mt2712-apmixedsys.c
+++ b/drivers/clk/mediatek/clk-mt2712-apmixedsys.c
@@ -119,7 +119,7 @@ static int clk_mt2712_apmixed_probe(struct platform_device *pdev)
 	if (!clk_data)
 		return -ENOMEM;
 
-	r = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
+	r = mtk_clk_register_plls(&pdev->dev, plls, ARRAY_SIZE(plls), clk_data);
 	if (r)
 		goto free_clk_data;
 
diff --git a/drivers/clk/mediatek/clk-mt6735-apmixedsys.c b/drivers/clk/mediatek/clk-mt6735-apmixedsys.c
index e0949911e8f7..9e30c089a209 100644
--- a/drivers/clk/mediatek/clk-mt6735-apmixedsys.c
+++ b/drivers/clk/mediatek/clk-mt6735-apmixedsys.c
@@ -93,8 +93,8 @@ static int clk_mt6735_apmixed_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	platform_set_drvdata(pdev, clk_data);
 
-	ret = mtk_clk_register_plls(pdev->dev.of_node, apmixedsys_plls,
-				   ARRAY_SIZE(apmixedsys_plls), clk_data);
+	ret = mtk_clk_register_plls(&pdev->dev, apmixedsys_plls,
+				    ARRAY_SIZE(apmixedsys_plls), clk_data);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to register PLLs: %d\n", ret);
 		return ret;
diff --git a/drivers/clk/mediatek/clk-mt6765.c b/drivers/clk/mediatek/clk-mt6765.c
index d53731e7933f..60f6f9fa7dcf 100644
--- a/drivers/clk/mediatek/clk-mt6765.c
+++ b/drivers/clk/mediatek/clk-mt6765.c
@@ -740,7 +740,7 @@ static int clk_mt6765_apmixed_probe(struct platform_device *pdev)
 	if (!clk_data)
 		return -ENOMEM;
 
-	mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
+	mtk_clk_register_plls(&pdev->dev, plls, ARRAY_SIZE(plls), clk_data);
 
 	mtk_clk_register_gates(&pdev->dev, node, apmixed_clks,
 			       ARRAY_SIZE(apmixed_clks), clk_data);
diff --git a/drivers/clk/mediatek/clk-mt6779.c b/drivers/clk/mediatek/clk-mt6779.c
index 86732f5acf93..4b9dcb910b03 100644
--- a/drivers/clk/mediatek/clk-mt6779.c
+++ b/drivers/clk/mediatek/clk-mt6779.c
@@ -1220,7 +1220,7 @@ static int clk_mt6779_apmixed_probe(struct platform_device *pdev)
 	if (!clk_data)
 		return -ENOMEM;
 
-	mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
+	mtk_clk_register_plls(&pdev->dev, plls, ARRAY_SIZE(plls), clk_data);
 
 	mtk_clk_register_gates(&pdev->dev, node, apmixed_clks,
 			       ARRAY_SIZE(apmixed_clks), clk_data);
diff --git a/drivers/clk/mediatek/clk-mt6797.c b/drivers/clk/mediatek/clk-mt6797.c
index fb59e71af58e..ebf850ac57f5 100644
--- a/drivers/clk/mediatek/clk-mt6797.c
+++ b/drivers/clk/mediatek/clk-mt6797.c
@@ -655,7 +655,7 @@ static int mtk_apmixedsys_init(struct platform_device *pdev)
 	if (!clk_data)
 		return -ENOMEM;
 
-	mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
+	mtk_clk_register_plls(&pdev->dev, plls, ARRAY_SIZE(plls), clk_data);
 
 	return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
 }
diff --git a/drivers/clk/mediatek/clk-mt7622-apmixedsys.c b/drivers/clk/mediatek/clk-mt7622-apmixedsys.c
index 2350592d9a93..8a29eaab0cfc 100644
--- a/drivers/clk/mediatek/clk-mt7622-apmixedsys.c
+++ b/drivers/clk/mediatek/clk-mt7622-apmixedsys.c
@@ -96,7 +96,7 @@ static int clk_mt7622_apmixed_probe(struct platform_device *pdev)
 	if (!clk_data)
 		return -ENOMEM;
 
-	ret = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
+	ret = mtk_clk_register_plls(dev, plls, ARRAY_SIZE(plls), clk_data);
 	if (ret)
 		return ret;
 
diff --git a/drivers/clk/mediatek/clk-mt7629.c b/drivers/clk/mediatek/clk-mt7629.c
index baf94e7bea37..e154771b1b8b 100644
--- a/drivers/clk/mediatek/clk-mt7629.c
+++ b/drivers/clk/mediatek/clk-mt7629.c
@@ -634,7 +634,7 @@ static int mtk_apmixedsys_init(struct platform_device *pdev)
 	if (!clk_data)
 		return -ENOMEM;
 
-	mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls),
+	mtk_clk_register_plls(&pdev->dev, plls, ARRAY_SIZE(plls),
 			      clk_data);
 
 	mtk_clk_register_gates(&pdev->dev, node, apmixed_clks,
diff --git a/drivers/clk/mediatek/clk-mt7981-apmixed.c b/drivers/clk/mediatek/clk-mt7981-apmixed.c
index e8211eb4e09e..6606b54fb376 100644
--- a/drivers/clk/mediatek/clk-mt7981-apmixed.c
+++ b/drivers/clk/mediatek/clk-mt7981-apmixed.c
@@ -76,7 +76,7 @@ static int clk_mt7981_apmixed_probe(struct platform_device *pdev)
 	if (!clk_data)
 		return -ENOMEM;
 
-	mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
+	mtk_clk_register_plls(&pdev->dev, plls, ARRAY_SIZE(plls), clk_data);
 
 	r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
 	if (r) {
diff --git a/drivers/clk/mediatek/clk-mt7986-apmixed.c b/drivers/clk/mediatek/clk-mt7986-apmixed.c
index 93751abe6be8..1c79418d08a7 100644
--- a/drivers/clk/mediatek/clk-mt7986-apmixed.c
+++ b/drivers/clk/mediatek/clk-mt7986-apmixed.c
@@ -74,7 +74,7 @@ static int clk_mt7986_apmixed_probe(struct platform_device *pdev)
 	if (!clk_data)
 		return -ENOMEM;
 
-	mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
+	mtk_clk_register_plls(&pdev->dev, plls, ARRAY_SIZE(plls), clk_data);
 
 	r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
 	if (r) {
diff --git a/drivers/clk/mediatek/clk-mt7988-apmixed.c b/drivers/clk/mediatek/clk-mt7988-apmixed.c
index 63d33a78cb48..416a4b88d100 100644
--- a/drivers/clk/mediatek/clk-mt7988-apmixed.c
+++ b/drivers/clk/mediatek/clk-mt7988-apmixed.c
@@ -86,7 +86,7 @@ static int clk_mt7988_apmixed_probe(struct platform_device *pdev)
 	if (!clk_data)
 		return -ENOMEM;
 
-	r = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
+	r = mtk_clk_register_plls(&pdev->dev, plls, ARRAY_SIZE(plls), clk_data);
 	if (r)
 		goto free_apmixed_data;
 
diff --git a/drivers/clk/mediatek/clk-mt8135-apmixedsys.c b/drivers/clk/mediatek/clk-mt8135-apmixedsys.c
index bdadc35c64cb..19e4ee489ec3 100644
--- a/drivers/clk/mediatek/clk-mt8135-apmixedsys.c
+++ b/drivers/clk/mediatek/clk-mt8135-apmixedsys.c
@@ -57,7 +57,8 @@ static int clk_mt8135_apmixed_probe(struct platform_device *pdev)
 	if (!clk_data)
 		return -ENOMEM;
 
-	ret = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
+	ret = mtk_clk_register_plls(&pdev->dev, plls, ARRAY_SIZE(plls),
+				    clk_data);
 	if (ret)
 		goto free_clk_data;
 
diff --git a/drivers/clk/mediatek/clk-mt8167-apmixedsys.c b/drivers/clk/mediatek/clk-mt8167-apmixedsys.c
index adf576786696..fb6c21bbeef8 100644
--- a/drivers/clk/mediatek/clk-mt8167-apmixedsys.c
+++ b/drivers/clk/mediatek/clk-mt8167-apmixedsys.c
@@ -105,7 +105,7 @@ static int clk_mt8167_apmixed_probe(struct platform_device *pdev)
 	if (!clk_data)
 		return -ENOMEM;
 
-	ret = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
+	ret = mtk_clk_register_plls(dev, plls, ARRAY_SIZE(plls), clk_data);
 	if (ret)
 		return ret;
 
diff --git a/drivers/clk/mediatek/clk-mt8183-apmixedsys.c b/drivers/clk/mediatek/clk-mt8183-apmixedsys.c
index 551adbfd7ac9..6242d4f5376e 100644
--- a/drivers/clk/mediatek/clk-mt8183-apmixedsys.c
+++ b/drivers/clk/mediatek/clk-mt8183-apmixedsys.c
@@ -155,7 +155,7 @@ static int clk_mt8183_apmixed_probe(struct platform_device *pdev)
 	if (!clk_data)
 		return -ENOMEM;
 
-	ret = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
+	ret = mtk_clk_register_plls(dev, plls, ARRAY_SIZE(plls), clk_data);
 	if (ret)
 		return ret;
 
diff --git a/drivers/clk/mediatek/clk-mt8188-apmixedsys.c b/drivers/clk/mediatek/clk-mt8188-apmixedsys.c
index 21d7a9a2ab1a..a1de596bff99 100644
--- a/drivers/clk/mediatek/clk-mt8188-apmixedsys.c
+++ b/drivers/clk/mediatek/clk-mt8188-apmixedsys.c
@@ -106,7 +106,7 @@ static int clk_mt8188_apmixed_probe(struct platform_device *pdev)
 	if (!clk_data)
 		return -ENOMEM;
 
-	r = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
+	r = mtk_clk_register_plls(&pdev->dev, plls, ARRAY_SIZE(plls), clk_data);
 	if (r)
 		goto free_apmixed_data;
 
diff --git a/drivers/clk/mediatek/clk-mt8195-apusys_pll.c b/drivers/clk/mediatek/clk-mt8195-apusys_pll.c
index 8b45a3fad02f..a2d98ed58e34 100644
--- a/drivers/clk/mediatek/clk-mt8195-apusys_pll.c
+++ b/drivers/clk/mediatek/clk-mt8195-apusys_pll.c
@@ -66,7 +66,8 @@ static int clk_mt8195_apusys_pll_probe(struct platform_device *pdev)
 	if (!clk_data)
 		return -ENOMEM;
 
-	r = mtk_clk_register_plls(node, apusys_plls, ARRAY_SIZE(apusys_plls), clk_data);
+	r = mtk_clk_register_plls(&pdev->dev, apusys_plls,
+				  ARRAY_SIZE(apusys_plls), clk_data);
 	if (r)
 		goto free_apusys_pll_data;
 
diff --git a/drivers/clk/mediatek/clk-mt8196-apmixedsys.c b/drivers/clk/mediatek/clk-mt8196-apmixedsys.c
index 617f5449b88b..c4ebb0170b82 100644
--- a/drivers/clk/mediatek/clk-mt8196-apmixedsys.c
+++ b/drivers/clk/mediatek/clk-mt8196-apmixedsys.c
@@ -152,7 +152,8 @@ static int clk_mt8196_apmixed_probe(struct platform_device *pdev)
 	if (!clk_data)
 		return -ENOMEM;
 
-	r = mtk_clk_register_plls(node, mcd->clks, mcd->num_clks, clk_data);
+	r = mtk_clk_register_plls(&pdev->dev, mcd->clks, mcd->num_clks,
+				  clk_data);
 	if (r)
 		goto free_apmixed_data;
 
diff --git a/drivers/clk/mediatek/clk-mt8196-mcu.c b/drivers/clk/mediatek/clk-mt8196-mcu.c
index 5cbcc411ae73..13642fc673c2 100644
--- a/drivers/clk/mediatek/clk-mt8196-mcu.c
+++ b/drivers/clk/mediatek/clk-mt8196-mcu.c
@@ -122,7 +122,7 @@ static int clk_mt8196_mcu_probe(struct platform_device *pdev)
 	if (!clk_data)
 		return -ENOMEM;
 
-	r = mtk_clk_register_plls(node, plls, num_plls, clk_data);
+	r = mtk_clk_register_plls(&pdev->dev, plls, num_plls, clk_data);
 	if (r)
 		goto free_clk_data;
 
diff --git a/drivers/clk/mediatek/clk-mt8196-mfg.c b/drivers/clk/mediatek/clk-mt8196-mfg.c
index ae1eb9de79ae..8e09c0f7b754 100644
--- a/drivers/clk/mediatek/clk-mt8196-mfg.c
+++ b/drivers/clk/mediatek/clk-mt8196-mfg.c
@@ -105,7 +105,7 @@ static int clk_mt8196_mfg_probe(struct platform_device *pdev)
 	if (!clk_data)
 		return -ENOMEM;
 
-	r = mtk_clk_register_plls(node, plls, num_plls, clk_data);
+	r = mtk_clk_register_plls(&pdev->dev, plls, num_plls, clk_data);
 	if (r)
 		goto free_clk_data;
 
diff --git a/drivers/clk/mediatek/clk-mt8196-vlpckgen.c b/drivers/clk/mediatek/clk-mt8196-vlpckgen.c
index d59a8a9d9855..7dcc164627c5 100644
--- a/drivers/clk/mediatek/clk-mt8196-vlpckgen.c
+++ b/drivers/clk/mediatek/clk-mt8196-vlpckgen.c
@@ -664,7 +664,7 @@ static int clk_mt8196_vlp_probe(struct platform_device *pdev)
 	if (r)
 		goto unregister_factors;
 
-	r = mtk_clk_register_plls(node, vlp_plls, ARRAY_SIZE(vlp_plls),
+	r = mtk_clk_register_plls(dev, vlp_plls, ARRAY_SIZE(vlp_plls),
 				  clk_data);
 	if (r)
 		goto unregister_muxes;
diff --git a/drivers/clk/mediatek/clk-mt8365-apmixedsys.c b/drivers/clk/mediatek/clk-mt8365-apmixedsys.c
index f41b991a0178..e331aa28a4bd 100644
--- a/drivers/clk/mediatek/clk-mt8365-apmixedsys.c
+++ b/drivers/clk/mediatek/clk-mt8365-apmixedsys.c
@@ -133,7 +133,7 @@ static int clk_mt8365_apmixed_probe(struct platform_device *pdev)
 		return PTR_ERR(hw);
 	clk_data->hws[CLK_APMIXED_USB20_EN] = hw;
 
-	ret = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
+	ret = mtk_clk_register_plls(dev, plls, ARRAY_SIZE(plls), clk_data);
 	if (ret)
 		return ret;
 
diff --git a/drivers/clk/mediatek/clk-mt8516-apmixedsys.c b/drivers/clk/mediatek/clk-mt8516-apmixedsys.c
index edd9174d2f2f..2a6206cae2f0 100644
--- a/drivers/clk/mediatek/clk-mt8516-apmixedsys.c
+++ b/drivers/clk/mediatek/clk-mt8516-apmixedsys.c
@@ -87,7 +87,7 @@ static int clk_mt8516_apmixed_probe(struct platform_device *pdev)
 	if (!clk_data)
 		return -ENOMEM;
 
-	ret = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
+	ret = mtk_clk_register_plls(dev, plls, ARRAY_SIZE(plls), clk_data);
 	if (ret)
 		return ret;
 
diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c
index cd2b6ce551c6..5caf91ae9ddb 100644
--- a/drivers/clk/mediatek/clk-pll.c
+++ b/drivers/clk/mediatek/clk-pll.c
@@ -11,6 +11,7 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of_address.h>
+#include <linux/platform_device.h>
 #include <linux/slab.h>
 
 #include "clk-pll.h"
@@ -404,7 +405,7 @@ void mtk_clk_unregister_pll(struct clk_hw *hw)
 	kfree(pll);
 }
 
-int mtk_clk_register_plls(struct device_node *node,
+int mtk_clk_register_plls(struct device *dev,
 			  const struct mtk_pll_data *plls, int num_plls,
 			  struct clk_hw_onecell_data *clk_data)
 {
@@ -412,7 +413,7 @@ int mtk_clk_register_plls(struct device_node *node,
 	int i;
 	struct clk_hw *hw;
 
-	base = of_iomap(node, 0);
+	base = of_iomap(dev->of_node, 0);
 	if (!base) {
 		pr_err("%s(): ioremap failed\n", __func__);
 		return -EINVAL;
@@ -423,7 +424,7 @@ int mtk_clk_register_plls(struct device_node *node,
 
 		if (!IS_ERR_OR_NULL(clk_data->hws[pll->id])) {
 			pr_warn("%pOF: Trying to register duplicate clock ID: %d\n",
-				node, pll->id);
+				dev->of_node, pll->id);
 			continue;
 		}
 
diff --git a/drivers/clk/mediatek/clk-pll.h b/drivers/clk/mediatek/clk-pll.h
index d71c150ce83e..38fde1a273bf 100644
--- a/drivers/clk/mediatek/clk-pll.h
+++ b/drivers/clk/mediatek/clk-pll.h
@@ -10,9 +10,7 @@
 #include <linux/clk-provider.h>
 #include <linux/types.h>
 
-struct clk_ops;
-struct clk_hw_onecell_data;
-struct device_node;
+struct device;
 
 struct mtk_pll_div_table {
 	u32 div;
@@ -78,9 +76,9 @@ struct mtk_clk_pll {
 	const struct mtk_pll_data *data;
 };
 
-int mtk_clk_register_plls(struct device_node *node,
-			  const struct mtk_pll_data *plls, int num_plls,
-			  struct clk_hw_onecell_data *clk_data);
+int mtk_clk_register_plls(struct device *dev, const struct mtk_pll_data *plls,
+			  int num_plls, struct clk_hw_onecell_data *clk_data);
+
 void mtk_clk_unregister_plls(const struct mtk_pll_data *plls, int num_plls,
 			     struct clk_hw_onecell_data *clk_data);
 

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Mon Dec 15 02:24:00 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Mon, 15 Dec 2025 11:24:00 +0100
Subject: [PATCH RESEND v3 3/5] clk: mediatek: Pass device to
 clk_hw_register for PLLs
In-Reply-To: <20251215-mtk-pll-rpm-v3-0-5afb3191e869@collabora.com>
References: <20251215-mtk-pll-rpm-v3-0-5afb3191e869@collabora.com>
Message-ID: <20251215-mtk-pll-rpm-v3-3-5afb3191e869@collabora.com>

Passing the struct device pointer to clk_hw_register allows for runtime
power management to work for the registered clock controllers. However,
the mediatek PLL clocks do not do this.

Change this by adding a struct device pointer argument to
mtk_clk_register_pll, and fix up the only other user of it. Also add a
new member to the struct mtk_clk_pll for the struct device pointer,
which is set by mtk_clk_register_pll and is used by
mtk_clk_register_pll_ops.

If mtk_clk_register_pll is called with a NULL struct device pointer,
then everything still works as expected; the clock core will simply
treat them as previously, i.e. without runtime power management.

Reviewed-by: Chen-Yu Tsai <wenst at chromium.org>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/clk/mediatek/clk-pll.c   | 9 ++++++---
 drivers/clk/mediatek/clk-pll.h   | 4 +++-
 drivers/clk/mediatek/clk-pllfh.c | 2 +-
 3 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c
index 5caf91ae9ddb..c4f9c06e5133 100644
--- a/drivers/clk/mediatek/clk-pll.c
+++ b/drivers/clk/mediatek/clk-pll.c
@@ -366,7 +366,7 @@ struct clk_hw *mtk_clk_register_pll_ops(struct mtk_clk_pll *pll,
 		init.parent_names = &parent_name;
 	init.num_parents = 1;
 
-	ret = clk_hw_register(NULL, &pll->hw);
+	ret = clk_hw_register(pll->dev, &pll->hw);
 
 	if (ret)
 		return ERR_PTR(ret);
@@ -374,7 +374,8 @@ struct clk_hw *mtk_clk_register_pll_ops(struct mtk_clk_pll *pll,
 	return &pll->hw;
 }
 
-struct clk_hw *mtk_clk_register_pll(const struct mtk_pll_data *data,
+struct clk_hw *mtk_clk_register_pll(struct device *dev,
+				    const struct mtk_pll_data *data,
 				    void __iomem *base)
 {
 	struct mtk_clk_pll *pll;
@@ -385,6 +386,8 @@ struct clk_hw *mtk_clk_register_pll(const struct mtk_pll_data *data,
 	if (!pll)
 		return ERR_PTR(-ENOMEM);
 
+	pll->dev = dev;
+
 	hw = mtk_clk_register_pll_ops(pll, data, base, pll_ops);
 	if (IS_ERR(hw))
 		kfree(pll);
@@ -428,7 +431,7 @@ int mtk_clk_register_plls(struct device *dev,
 			continue;
 		}
 
-		hw = mtk_clk_register_pll(pll, base);
+		hw = mtk_clk_register_pll(dev, pll, base);
 
 		if (IS_ERR(hw)) {
 			pr_err("Failed to register clk %s: %pe\n", pll->name,
diff --git a/drivers/clk/mediatek/clk-pll.h b/drivers/clk/mediatek/clk-pll.h
index 38fde1a273bf..f6493699c4e3 100644
--- a/drivers/clk/mediatek/clk-pll.h
+++ b/drivers/clk/mediatek/clk-pll.h
@@ -61,6 +61,7 @@ struct mtk_pll_data {
  */
 
 struct mtk_clk_pll {
+	struct device *dev;
 	struct clk_hw	hw;
 	void __iomem	*base_addr;
 	void __iomem	*pd_addr;
@@ -108,7 +109,8 @@ struct clk_hw *mtk_clk_register_pll_ops(struct mtk_clk_pll *pll,
 					const struct mtk_pll_data *data,
 					void __iomem *base,
 					const struct clk_ops *pll_ops);
-struct clk_hw *mtk_clk_register_pll(const struct mtk_pll_data *data,
+struct clk_hw *mtk_clk_register_pll(struct device *dev,
+				    const struct mtk_pll_data *data,
 				    void __iomem *base);
 void mtk_clk_unregister_pll(struct clk_hw *hw);
 
diff --git a/drivers/clk/mediatek/clk-pllfh.c b/drivers/clk/mediatek/clk-pllfh.c
index 83630ee07ee9..62bfe4a480f1 100644
--- a/drivers/clk/mediatek/clk-pllfh.c
+++ b/drivers/clk/mediatek/clk-pllfh.c
@@ -220,7 +220,7 @@ int mtk_clk_register_pllfhs(struct device_node *node,
 		if (use_fhctl)
 			hw = mtk_clk_register_pllfh(pll, pllfh, base);
 		else
-			hw = mtk_clk_register_pll(pll, base);
+			hw = mtk_clk_register_pll(NULL, pll, base);
 
 		if (IS_ERR(hw)) {
 			pr_err("Failed to register %s clk %s: %ld\n",

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Mon Dec 15 02:24:01 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Mon, 15 Dec 2025 11:24:01 +0100
Subject: [PATCH RESEND v3 4/5] clk: mediatek: Refactor pllfh registration
 to pass device
In-Reply-To: <20251215-mtk-pll-rpm-v3-0-5afb3191e869@collabora.com>
References: <20251215-mtk-pll-rpm-v3-0-5afb3191e869@collabora.com>
Message-ID: <20251215-mtk-pll-rpm-v3-4-5afb3191e869@collabora.com>

After refactoring all of PLL to pass the device, it's now fairly easy to
refactor pllfh and its users, as pllfh registration wraps PLL
registration.

Do this refactor and move all of the pllfh users to pass the device as
well.

Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/clk/mediatek/clk-mt6795-apmixedsys.c |  2 +-
 drivers/clk/mediatek/clk-mt8173-apmixedsys.c | 14 +++++++-------
 drivers/clk/mediatek/clk-mt8186-apmixedsys.c |  2 +-
 drivers/clk/mediatek/clk-mt8192-apmixedsys.c |  2 +-
 drivers/clk/mediatek/clk-mt8195-apmixedsys.c |  2 +-
 drivers/clk/mediatek/clk-pllfh.c             | 13 ++++++++-----
 drivers/clk/mediatek/clk-pllfh.h             |  2 +-
 7 files changed, 20 insertions(+), 17 deletions(-)

diff --git a/drivers/clk/mediatek/clk-mt6795-apmixedsys.c b/drivers/clk/mediatek/clk-mt6795-apmixedsys.c
index 91665d7f125e..123d5d7fea85 100644
--- a/drivers/clk/mediatek/clk-mt6795-apmixedsys.c
+++ b/drivers/clk/mediatek/clk-mt6795-apmixedsys.c
@@ -152,7 +152,7 @@ static int clk_mt6795_apmixed_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	fhctl_parse_dt(fhctl_node, pllfhs, ARRAY_SIZE(pllfhs));
-	ret = mtk_clk_register_pllfhs(node, plls, ARRAY_SIZE(plls),
+	ret = mtk_clk_register_pllfhs(dev, plls, ARRAY_SIZE(plls),
 				      pllfhs, ARRAY_SIZE(pllfhs), clk_data);
 	if (ret)
 		goto free_clk_data;
diff --git a/drivers/clk/mediatek/clk-mt8173-apmixedsys.c b/drivers/clk/mediatek/clk-mt8173-apmixedsys.c
index 95385bb67d55..d7d416172ab3 100644
--- a/drivers/clk/mediatek/clk-mt8173-apmixedsys.c
+++ b/drivers/clk/mediatek/clk-mt8173-apmixedsys.c
@@ -140,13 +140,13 @@ MODULE_DEVICE_TABLE(of, of_match_clk_mt8173_apmixed);
 static int clk_mt8173_apmixed_probe(struct platform_device *pdev)
 {
 	const u8 *fhctl_node = "mediatek,mt8173-fhctl";
-	struct device_node *node = pdev->dev.of_node;
 	struct clk_hw_onecell_data *clk_data;
+	struct device *dev = &pdev->dev;
 	void __iomem *base;
 	struct clk_hw *hw;
 	int r;
 
-	base = of_iomap(node, 0);
+	base = of_iomap(dev->of_node, 0);
 	if (!base)
 		return -ENOMEM;
 
@@ -157,25 +157,25 @@ static int clk_mt8173_apmixed_probe(struct platform_device *pdev)
 	}
 
 	fhctl_parse_dt(fhctl_node, pllfhs, ARRAY_SIZE(pllfhs));
-	r = mtk_clk_register_pllfhs(node, plls, ARRAY_SIZE(plls),
-				    pllfhs, ARRAY_SIZE(pllfhs), clk_data);
+	r = mtk_clk_register_pllfhs(dev, plls, ARRAY_SIZE(plls), pllfhs,
+				    ARRAY_SIZE(pllfhs), clk_data);
 	if (r)
 		goto free_clk_data;
 
 	hw = mtk_clk_register_ref2usb_tx("ref2usb_tx", "clk26m", base + REGOFF_REF2USB);
 	if (IS_ERR(hw)) {
 		r = PTR_ERR(hw);
-		dev_err(&pdev->dev, "Failed to register ref2usb_tx: %d\n", r);
+		dev_err(dev, "Failed to register ref2usb_tx: %d\n", r);
 		goto unregister_plls;
 	}
 	clk_data->hws[CLK_APMIXED_REF2USB_TX] = hw;
 
-	hw = devm_clk_hw_register_divider(&pdev->dev, "hdmi_ref", "tvdpll_594m", 0,
+	hw = devm_clk_hw_register_divider(dev, "hdmi_ref", "tvdpll_594m", 0,
 					  base + REGOFF_HDMI_REF, 16, 3,
 					  CLK_DIVIDER_POWER_OF_TWO, NULL);
 	clk_data->hws[CLK_APMIXED_HDMI_REF] = hw;
 
-	r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+	r = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, clk_data);
 	if (r)
 		goto unregister_ref2usb;
 
diff --git a/drivers/clk/mediatek/clk-mt8186-apmixedsys.c b/drivers/clk/mediatek/clk-mt8186-apmixedsys.c
index 4b2b16578232..d35dd2632e43 100644
--- a/drivers/clk/mediatek/clk-mt8186-apmixedsys.c
+++ b/drivers/clk/mediatek/clk-mt8186-apmixedsys.c
@@ -151,7 +151,7 @@ static int clk_mt8186_apmixed_probe(struct platform_device *pdev)
 
 	fhctl_parse_dt(fhctl_node, pllfhs, ARRAY_SIZE(pllfhs));
 
-	r = mtk_clk_register_pllfhs(node, plls, ARRAY_SIZE(plls),
+	r = mtk_clk_register_pllfhs(&pdev->dev, plls, ARRAY_SIZE(plls),
 				    pllfhs, ARRAY_SIZE(pllfhs), clk_data);
 	if (r)
 		goto free_apmixed_data;
diff --git a/drivers/clk/mediatek/clk-mt8192-apmixedsys.c b/drivers/clk/mediatek/clk-mt8192-apmixedsys.c
index 0b66a27e4d5a..b0563a285bd6 100644
--- a/drivers/clk/mediatek/clk-mt8192-apmixedsys.c
+++ b/drivers/clk/mediatek/clk-mt8192-apmixedsys.c
@@ -162,7 +162,7 @@ static int clk_mt8192_apmixed_probe(struct platform_device *pdev)
 
 	fhctl_parse_dt(fhctl_node, pllfhs, ARRAY_SIZE(pllfhs));
 
-	r = mtk_clk_register_pllfhs(node, plls, ARRAY_SIZE(plls),
+	r = mtk_clk_register_pllfhs(&pdev->dev, plls, ARRAY_SIZE(plls),
 				    pllfhs, ARRAY_SIZE(pllfhs), clk_data);
 	if (r)
 		goto free_clk_data;
diff --git a/drivers/clk/mediatek/clk-mt8195-apmixedsys.c b/drivers/clk/mediatek/clk-mt8195-apmixedsys.c
index 282a3137dc89..44917ab034c5 100644
--- a/drivers/clk/mediatek/clk-mt8195-apmixedsys.c
+++ b/drivers/clk/mediatek/clk-mt8195-apmixedsys.c
@@ -181,7 +181,7 @@ static int clk_mt8195_apmixed_probe(struct platform_device *pdev)
 
 	fhctl_parse_dt(fhctl_node, pllfhs, ARRAY_SIZE(pllfhs));
 
-	r = mtk_clk_register_pllfhs(node, plls, ARRAY_SIZE(plls),
+	r = mtk_clk_register_pllfhs(&pdev->dev, plls, ARRAY_SIZE(plls),
 				    pllfhs, ARRAY_SIZE(pllfhs), clk_data);
 	if (r)
 		goto free_apmixed_data;
diff --git a/drivers/clk/mediatek/clk-pllfh.c b/drivers/clk/mediatek/clk-pllfh.c
index 62bfe4a480f1..8ad11023d911 100644
--- a/drivers/clk/mediatek/clk-pllfh.c
+++ b/drivers/clk/mediatek/clk-pllfh.c
@@ -10,6 +10,7 @@
 #include <linux/slab.h>
 #include <linux/clkdev.h>
 #include <linux/delay.h>
+#include <linux/device.h>
 
 #include "clk-mtk.h"
 #include "clk-pllfh.h"
@@ -149,7 +150,7 @@ static bool fhctl_is_supported_and_enabled(const struct mtk_pllfh_data *pllfh)
 }
 
 static struct clk_hw *
-mtk_clk_register_pllfh(const struct mtk_pll_data *pll_data,
+mtk_clk_register_pllfh(struct device *dev, const struct mtk_pll_data *pll_data,
 		       struct mtk_pllfh_data *pllfh_data, void __iomem *base)
 {
 	struct clk_hw *hw;
@@ -166,6 +167,8 @@ mtk_clk_register_pllfh(const struct mtk_pll_data *pll_data,
 		goto out;
 	}
 
+	fh->clk_pll.dev = dev;
+
 	hw = mtk_clk_register_pll_ops(&fh->clk_pll, pll_data, base,
 				      &mtk_pllfh_ops);
 
@@ -194,7 +197,7 @@ static void mtk_clk_unregister_pllfh(struct clk_hw *hw)
 	kfree(fh);
 }
 
-int mtk_clk_register_pllfhs(struct device_node *node,
+int mtk_clk_register_pllfhs(struct device *dev,
 			    const struct mtk_pll_data *plls, int num_plls,
 			    struct mtk_pllfh_data *pllfhs, int num_fhs,
 			    struct clk_hw_onecell_data *clk_data)
@@ -203,7 +206,7 @@ int mtk_clk_register_pllfhs(struct device_node *node,
 	int i;
 	struct clk_hw *hw;
 
-	base = of_iomap(node, 0);
+	base = of_iomap(dev->of_node, 0);
 	if (!base) {
 		pr_err("%s(): ioremap failed\n", __func__);
 		return -EINVAL;
@@ -218,9 +221,9 @@ int mtk_clk_register_pllfhs(struct device_node *node,
 		use_fhctl = fhctl_is_supported_and_enabled(pllfh);
 
 		if (use_fhctl)
-			hw = mtk_clk_register_pllfh(pll, pllfh, base);
+			hw = mtk_clk_register_pllfh(dev, pll, pllfh, base);
 		else
-			hw = mtk_clk_register_pll(NULL, pll, base);
+			hw = mtk_clk_register_pll(dev, pll, base);
 
 		if (IS_ERR(hw)) {
 			pr_err("Failed to register %s clk %s: %ld\n",
diff --git a/drivers/clk/mediatek/clk-pllfh.h b/drivers/clk/mediatek/clk-pllfh.h
index 5f419c2ec01f..a4f337acad71 100644
--- a/drivers/clk/mediatek/clk-pllfh.h
+++ b/drivers/clk/mediatek/clk-pllfh.h
@@ -68,7 +68,7 @@ struct fh_operation {
 	int (*ssc_enable)(struct mtk_fh *fh, u32 rate);
 };
 
-int mtk_clk_register_pllfhs(struct device_node *node,
+int mtk_clk_register_pllfhs(struct device *dev,
 			    const struct mtk_pll_data *plls, int num_plls,
 			    struct mtk_pllfh_data *pllfhs, int num_pllfhs,
 			    struct clk_hw_onecell_data *clk_data);

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Mon Dec 15 02:24:02 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Mon, 15 Dec 2025 11:24:02 +0100
Subject: [PATCH RESEND v3 5/5] clk: mediatek: Add mfg_eb as parent to
 mt8196 mfgpll clocks
In-Reply-To: <20251215-mtk-pll-rpm-v3-0-5afb3191e869@collabora.com>
References: <20251215-mtk-pll-rpm-v3-0-5afb3191e869@collabora.com>
Message-ID: <20251215-mtk-pll-rpm-v3-5-5afb3191e869@collabora.com>

All the MFGPLL require MFG_EB to be on for any operation on them, and
they only tick when MFG_EB is on as well, therefore making this a
parent-child relationship.

This dependency wasn't clear during the initial upstreaming of these
clock controllers, as it only made itself known when I could observe
the effects of the clock by bringing up a different piece of hardware.

Add a new PLL_PARENT_EN flag to mediatek's clk-pll.h, and check for it
when initialising the pll to then translate it into the actual
CLK_OPS_PARENT_ENABLE flag.

Then add the mfg_eb parent to the mfgpll clocks, and set the new
PLL_PARENT_EN flag.

Fixes: 03dc02f8c7dc ("clk: mediatek: Add MT8196 mfg clock support")
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/clk/mediatek/clk-mt8196-mfg.c | 13 +++++++------
 drivers/clk/mediatek/clk-pll.c        |  3 +++
 drivers/clk/mediatek/clk-pll.h        |  1 +
 3 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/clk/mediatek/clk-mt8196-mfg.c b/drivers/clk/mediatek/clk-mt8196-mfg.c
index 8e09c0f7b754..a317183f1681 100644
--- a/drivers/clk/mediatek/clk-mt8196-mfg.c
+++ b/drivers/clk/mediatek/clk-mt8196-mfg.c
@@ -58,24 +58,25 @@
 		.pcw_shift = _pcw_shift,			\
 		.pcwbits = _pcwbits,				\
 		.pcwibits = MT8196_INTEGER_BITS,		\
+		.parent_name = "mfg_eb",			\
 	}
 
 static const struct mtk_pll_data mfg_ao_plls[] = {
-	PLL(CLK_MFG_AO_MFGPLL, "mfgpll", MFGPLL_CON0, MFGPLL_CON0, 0, 0, 0,
-	    BIT(0), MFGPLL_CON1, 24, 0, 0, 0,
+	PLL(CLK_MFG_AO_MFGPLL, "mfgpll", MFGPLL_CON0, MFGPLL_CON0, 0, 0,
+	    PLL_PARENT_EN, BIT(0), MFGPLL_CON1, 24, 0, 0, 0,
 	    MFGPLL_CON1, 0, 22),
 };
 
 static const struct mtk_pll_data mfgsc0_ao_plls[] = {
 	PLL(CLK_MFGSC0_AO_MFGPLL_SC0, "mfgpll-sc0", MFGPLL_SC0_CON0,
-	    MFGPLL_SC0_CON0, 0, 0, 0, BIT(0), MFGPLL_SC0_CON1, 24, 0, 0, 0,
-	    MFGPLL_SC0_CON1, 0, 22),
+	    MFGPLL_SC0_CON0, 0, 0, PLL_PARENT_EN, BIT(0), MFGPLL_SC0_CON1, 24,
+	    0, 0, 0, MFGPLL_SC0_CON1, 0, 22),
 };
 
 static const struct mtk_pll_data mfgsc1_ao_plls[] = {
 	PLL(CLK_MFGSC1_AO_MFGPLL_SC1, "mfgpll-sc1", MFGPLL_SC1_CON0,
-	    MFGPLL_SC1_CON0, 0, 0, 0, BIT(0), MFGPLL_SC1_CON1, 24, 0, 0, 0,
-	    MFGPLL_SC1_CON1, 0, 22),
+	    MFGPLL_SC1_CON0, 0, 0, PLL_PARENT_EN, BIT(0), MFGPLL_SC1_CON1, 24,
+	    0, 0, 0, MFGPLL_SC1_CON1, 0, 22),
 };
 
 static const struct of_device_id of_match_clk_mt8196_mfg[] = {
diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c
index c4f9c06e5133..0f3759fcd9d0 100644
--- a/drivers/clk/mediatek/clk-pll.c
+++ b/drivers/clk/mediatek/clk-pll.c
@@ -359,6 +359,9 @@ struct clk_hw *mtk_clk_register_pll_ops(struct mtk_clk_pll *pll,
 
 	init.name = data->name;
 	init.flags = (data->flags & PLL_AO) ? CLK_IS_CRITICAL : 0;
+	if (data->flags & PLL_PARENT_EN)
+		init.flags |= CLK_OPS_PARENT_ENABLE;
+
 	init.ops = pll_ops;
 	if (data->parent_name)
 		init.parent_names = &data->parent_name;
diff --git a/drivers/clk/mediatek/clk-pll.h b/drivers/clk/mediatek/clk-pll.h
index f6493699c4e3..f49dc2732ffe 100644
--- a/drivers/clk/mediatek/clk-pll.h
+++ b/drivers/clk/mediatek/clk-pll.h
@@ -19,6 +19,7 @@ struct mtk_pll_div_table {
 
 #define HAVE_RST_BAR	BIT(0)
 #define PLL_AO		BIT(1)
+#define PLL_PARENT_EN	BIT(2)
 #define POSTDIV_MASK	GENMASK(2, 0)
 
 struct mtk_pll_data {

-- 
2.52.0



From eleanor.lin at realtek.com  Mon Dec 15 02:31:56 2025
From: eleanor.lin at realtek.com (Yu-Chun Lin)
Date: Mon, 15 Dec 2025 18:31:56 +0800
Subject: [PATCH v3 1/2 RESEND] dt-bindings: arm: realtek: Add Kent Soc family compatibles
In-Reply-To: <20251215103157.27039-1-eleanor.lin@realtek.com>
References: <20251215103157.27039-1-eleanor.lin@realtek.com>
Message-ID: <20251215103157.27039-2-eleanor.lin@realtek.com>

Define compatible strings for Realtek RTD1501s, RTD1861b and RTD1920s.

Additionally, convert legacy DTS-style comments to YAML description
properties, following the pattern from the ARM bindings conversion series
[1].

[1] https://lore.kernel.org/lkml/20200622125527.24207-2-afaerber at suse.de/

Acked-by: Conor Dooley <conor.dooley at microchip.com>
Signed-off-by: Yu-Chun Lin <eleanor.lin at realtek.com>
---
 .../devicetree/bindings/arm/realtek.yaml      | 42 +++++++++++++------
 1 file changed, 30 insertions(+), 12 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/realtek.yaml b/Documentation/devicetree/bindings/arm/realtek.yaml
index ddd9a85099e9..be529490640c 100644
--- a/Documentation/devicetree/bindings/arm/realtek.yaml
+++ b/Documentation/devicetree/bindings/arm/realtek.yaml
@@ -14,21 +14,21 @@ properties:
     const: '/'
   compatible:
     oneOf:
-      # RTD1195 SoC based boards
-      - items:
+      - description: RTD1195 SoC based boards
+        items:
           - enum:
               - mele,x1000 # MeLE X1000
               - realtek,horseradish # Realtek Horseradish EVB
           - const: realtek,rtd1195
 
-      # RTD1293 SoC based boards
-      - items:
+      - description: RTD1293 SoC based boards
+        items:
           - enum:
               - synology,ds418j # Synology DiskStation DS418j
           - const: realtek,rtd1293
 
-      # RTD1295 SoC based boards
-      - items:
+      - description: RTD1295 SoC based boards
+        items:
           - enum:
               - mele,v9 # MeLE V9
               - probox2,ava # ProBox2 AVA
@@ -36,25 +36,43 @@ properties:
               - zidoo,x9s # Zidoo X9S
           - const: realtek,rtd1295
 
-      # RTD1296 SoC based boards
-      - items:
+      - description: RTD1296 SoC based boards
+        items:
           - enum:
               - synology,ds418 # Synology DiskStation DS418
           - const: realtek,rtd1296
 
-      # RTD1395 SoC based boards
-      - items:
+      - description: RTD1395 SoC based boards
+        items:
           - enum:
               - bananapi,bpi-m4 # Banana Pi BPI-M4
               - realtek,lion-skin # Realtek Lion Skin EVB
           - const: realtek,rtd1395
 
-      # RTD1619 SoC based boards
-      - items:
+      - description: RTD1501s SoC based boards
+        items:
+          - enum:
+              - realtek,phantom # Realtek Phantom EVB (8GB)
+          - const: realtek,rtd1501s
+
+      - description: RTD1619 SoC based boards
+        items:
           - enum:
               - realtek,mjolnir # Realtek Mjolnir EVB
           - const: realtek,rtd1619
 
+      - description: RTD1861b SoC based boards
+        items:
+          - enum:
+              - realtek,krypton # Realtek Krypton EVB (8GB)
+          - const: realtek,rtd1861b
+
+      - description: RTD1920s SoC based boards
+        items:
+          - enum:
+              - realtek,smallville # Realtek Smallville EVB (4GB)
+          - const: realtek,rtd1920s
+
 additionalProperties: true
 
 ...
-- 
2.34.1



From eleanor.lin at realtek.com  Mon Dec 15 02:31:57 2025
From: eleanor.lin at realtek.com (Yu-Chun Lin)
Date: Mon, 15 Dec 2025 18:31:57 +0800
Subject: [PATCH v3 2/2 RESEND] arm64: dts: realtek: Add Kent SoC and EVB device trees
In-Reply-To: <20251215103157.27039-1-eleanor.lin@realtek.com>
References: <20251215103157.27039-1-eleanor.lin@realtek.com>
Message-ID: <20251215103157.27039-3-eleanor.lin@realtek.com>

Add Device Tree hierarchy for Realtek Kent SoC family:

- kent.dtsi: base SoC layer
- rtd<variant>.dtsi: SoC variant layer
- rtd<variant>-<board>.dtsi: board layer
- rtd<variant>-<board>-<config>.dts: board configuration layer

Include RTD1501s Phantom EVB (8GB), RTD1861B Krypton EVB (8GB), and
RTD1920s Smallville EVB (4GB).

Signed-off-by: Yu-Chun Lin <eleanor.lin at realtek.com>
---
 arch/arm64/boot/dts/realtek/Makefile          |   7 +-
 arch/arm64/boot/dts/realtek/kent.dtsi         | 166 ++++++++++++++++++
 arch/arm64/boot/dts/realtek/rtd1501.dtsi      |  12 ++
 .../boot/dts/realtek/rtd1501s-phantom-8gb.dts |  25 +++
 .../boot/dts/realtek/rtd1501s-phantom.dtsi    | 118 +++++++++++++
 arch/arm64/boot/dts/realtek/rtd1861.dtsi      |  12 ++
 .../boot/dts/realtek/rtd1861b-krypton-8gb.dts |  25 +++
 .../boot/dts/realtek/rtd1861b-krypton.dtsi    |  72 ++++++++
 arch/arm64/boot/dts/realtek/rtd1920.dtsi      |  12 ++
 .../dts/realtek/rtd1920s-smallville-4gb.dts   |  23 +++
 .../boot/dts/realtek/rtd1920s-smallville.dtsi | 128 ++++++++++++++
 11 files changed, 596 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm64/boot/dts/realtek/kent.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1501.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1501s-phantom-8gb.dts
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1501s-phantom.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1861.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1861b-krypton-8gb.dts
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1861b-krypton.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1920.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1920s-smallville-4gb.dts
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1920s-smallville.dtsi

diff --git a/arch/arm64/boot/dts/realtek/Makefile b/arch/arm64/boot/dts/realtek/Makefile
index ef8d8fcbaa05..60a37d5a948c 100644
--- a/arch/arm64/boot/dts/realtek/Makefile
+++ b/arch/arm64/boot/dts/realtek/Makefile
@@ -1,15 +1,14 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1293-ds418j.dtb
-
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1295-mele-v9.dtb
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1295-probox2-ava.dtb
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1295-xnano-x5.dtb
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1295-zidoo-x9s.dtb
-
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1296-ds418.dtb
-
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1395-bpi-m4.dtb
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1395-lionskin.dtb
-
+dtb-$(CONFIG_ARCH_REALTEK) += rtd1501s-phantom-8gb.dtb
 dtb-$(CONFIG_ARCH_REALTEK) += rtd1619-mjolnir.dtb
+dtb-$(CONFIG_ARCH_REALTEK) += rtd1861b-krypton-8gb.dtb
+dtb-$(CONFIG_ARCH_REALTEK) += rtd1920s-smallville-4gb.dtb
diff --git a/arch/arm64/boot/dts/realtek/kent.dtsi b/arch/arm64/boot/dts/realtek/kent.dtsi
new file mode 100644
index 000000000000..ae006ce24420
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/kent.dtsi
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Realtek Kent SoC family
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	aliases {
+		serial0 = &uart0;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI  9 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu0: cpu at 0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a78";
+			reg = <0x0>;
+			enable-method = "psci";
+			next-level-cache = <&l2_0>;
+			dynamic-power-coefficient = <454>;
+			#cooling-cells = <2>;
+
+			l2_0: l2-cache {
+				compatible = "cache";
+				cache-level = <2>;
+				cache-line-size = <64>;
+				cache-sets = <256>;
+				cache-size = <0x40000>;
+				cache-unified;
+				next-level-cache = <&l3>;
+			};
+		};
+
+		cpu1: cpu at 100 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a78";
+			reg = <0x100>;
+			enable-method = "psci";
+			next-level-cache = <&l2_1>;
+			dynamic-power-coefficient = <454>;
+			#cooling-cells = <2>;
+
+			l2_1: l2-cache {
+				compatible = "cache";
+				cache-level = <2>;
+				cache-line-size = <64>;
+				cache-sets = <256>;
+				cache-size = <0x40000>;
+				cache-unified;
+				next-level-cache = <&l3>;
+			};
+		};
+
+		cpu2: cpu at 200 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a78";
+			reg = <0x200>;
+			enable-method = "psci";
+			next-level-cache = <&l2_2>;
+			dynamic-power-coefficient = <454>;
+			#cooling-cells = <2>;
+
+			l2_2: l2-cache {
+				compatible = "cache";
+				cache-level = <2>;
+				cache-line-size = <64>;
+				cache-sets = <256>;
+				cache-size = <0x40000>;
+				cache-unified;
+				next-level-cache = <&l3>;
+			};
+		};
+
+		cpu3: cpu at 300 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a78";
+			reg = <0x300>;
+			enable-method = "psci";
+			next-level-cache = <&l2_3>;
+			dynamic-power-coefficient = <454>;
+			#cooling-cells = <2>;
+
+			l2_3: l2-cache {
+				compatible = "cache";
+				cache-level = <2>;
+				cache-line-size = <64>;
+				cache-sets = <256>;
+				cache-size = <0x40000>;
+				cache-unified;
+				next-level-cache = <&l3>;
+			};
+		};
+
+		l3: l3-cache {
+			compatible = "cache";
+			cache-level = <3>;
+			cache-line-size = <64>;
+			cache-sets = <512>;
+			cache-size = <0x200000>;
+			cache-unified;
+		};
+	};
+
+	psci: psci {
+		compatible = "arm,psci-1.0";
+		method = "smc";
+	};
+
+	soc at 0 {
+		compatible = "simple-bus";
+		ranges = <0x0 0x0 0x0 0x40000>, /* boot code */
+			 <0x98000000 0x0 0x98000000 0xef0000>, /* rbus */
+			 <0xa0000000 0x0 0xa0000000 0x10000000>, /* PCIE */
+			 <0xff000000 0x0 0xff000000 0x200000>; /* GIC */
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		rbus: bus at 98000000 {
+			compatible = "simple-bus";
+			ranges = <0x0 0x98000000 0xef0000>,
+				 <0xa0000000 0xa0000000 0x10000000>; /* PCIE */
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			uart0: serial at 7800 {
+				compatible = "snps,dw-apb-uart";
+				reg = <0x7800 0x100>;
+				clock-frequency = <432000000>;
+				interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
+				reg-io-width = <4>;
+				reg-shift = <2>;
+				status = "disabled";
+			};
+		};
+
+		gic: interrupt-controller at ff100000 {
+			compatible = "arm,gic-v3";
+			reg = <0xff100000 0x10000>,
+			      <0xff140000 0x80000>;
+			interrupt-controller;
+			interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#interrupt-cells = <3>;
+			#size-cells = <1>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/realtek/rtd1501.dtsi b/arch/arm64/boot/dts/realtek/rtd1501.dtsi
new file mode 100644
index 000000000000..65f7ede3df73
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1501.dtsi
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Realtek RTD1501 SoC
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+#include "kent.dtsi"
+
+&uart0 {
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/realtek/rtd1501s-phantom-8gb.dts b/arch/arm64/boot/dts/realtek/rtd1501s-phantom-8gb.dts
new file mode 100644
index 000000000000..09e544acfd34
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1501s-phantom-8gb.dts
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Realtek RTD1501S Phantom EVB
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+/dts-v1/;
+
+#include "rtd1501s-phantom.dtsi"
+
+/ {
+	compatible = "realtek,phantom", "realtek,rtd1501s";
+	model = "Realtek Phantom EVB Chromium (8GB)";
+
+	memory at 40000 {
+		device_type = "memory";
+		reg = <0x0 0x50000 0x0 0x7ffb0000>,
+		      <0x0 0x8a100000 0x0 0xdef0000>,
+		      <0x0 0x98700000 0x0 0x7900000>,
+		      <0x0 0xa0600000 0x0 0x5ea00000>,
+		      <0x1 0x0 0x0 0xa0000000>,
+		      <0x1 0xa0600000 0x0 0x5fa00000>;
+	};
+};
diff --git a/arch/arm64/boot/dts/realtek/rtd1501s-phantom.dtsi b/arch/arm64/boot/dts/realtek/rtd1501s-phantom.dtsi
new file mode 100644
index 000000000000..bcfb96799671
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1501s-phantom.dtsi
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Realtek RTD1501S Phantom EVB
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/thermal/thermal.h>
+#include "rtd1501.dtsi"
+
+/ {
+	chosen {
+		stdout-path = "serial0:460800n8";
+	};
+
+	reserved_memory: reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		linux,cma {
+			compatible = "shared-dma-pool";
+			alignment = <0x0 0x400000>;
+			alloc-ranges = <0x0 0x0 0x0 0x20000000>;
+			size = <0x0 0x2000000>;
+			reusable;
+			linux,cma-default;
+		};
+	};
+
+	cpu_opps: opp-table-cpu {
+		compatible = "operating-points-v2";
+		opp-shared;
+
+		opp800: opp-800000000 {
+			opp-hz = /bits/ 64 <800000000>;
+			opp-microvolt = <830000 830000 1100000>;
+		};
+
+		opp900: opp-900000000 {
+			opp-hz = /bits/ 64 <900000000>;
+			opp-microvolt = <850000 850000 1100000>;
+		};
+
+		opp1000: opp-1000000000 {
+			opp-hz = /bits/ 64 <1000000000>;
+			opp-microvolt = <870000 870000 1100000>;
+		};
+
+		opp1100: opp-1100000000 {
+			opp-hz = /bits/ 64 <1100000000>;
+			opp-microvolt = <890000 890000 1100000>;
+		};
+
+		opp1200: opp-1200000000 {
+			opp-hz = /bits/ 64 <1200000000>;
+			opp-microvolt = <910000 910000 1100000>;
+		};
+
+		opp1300: opp-1300000000 {
+			opp-hz = /bits/ 64 <1300000000>;
+			opp-microvolt = <930000 930000 1100000>;
+		};
+
+		opp1400: opp-1400000000 {
+			opp-hz = /bits/ 64 <1400000000>;
+			opp-microvolt = <950000 950000 1100000>;
+		};
+
+		opp1500: opp-1500000000 {
+			opp-hz = /bits/ 64 <1500000000>;
+			opp-microvolt = <970000 970000 1100000>;
+		};
+
+		opp1600: opp-1600000000 {
+			opp-hz = /bits/ 64 <1600000000>;
+			opp-microvolt = <990000 990000 1100000>;
+			opp-suspend;
+		};
+
+		opp1700: opp-1700000000 {
+			opp-hz = /bits/ 64 <1700000000>;
+			opp-microvolt = <1010000 1010000 1100000>;
+		};
+
+		opp1800: opp-1800000000 {
+			opp-hz = /bits/ 64 <1800000000>;
+			opp-microvolt = <1030000 1030000 1100000>;
+		};
+
+		opp1900: opp-1900000000 {
+			opp-hz = /bits/ 64 <1900000000>;
+			opp-microvolt = <1050000 1050000 1100000>;
+		};
+	};
+};
+
+&cpu0 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu1 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu2 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu3 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
diff --git a/arch/arm64/boot/dts/realtek/rtd1861.dtsi b/arch/arm64/boot/dts/realtek/rtd1861.dtsi
new file mode 100644
index 000000000000..44c3de8f1f48
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1861.dtsi
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Realtek RTD1861 SoC
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+#include "kent.dtsi"
+
+&uart0 {
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/realtek/rtd1861b-krypton-8gb.dts b/arch/arm64/boot/dts/realtek/rtd1861b-krypton-8gb.dts
new file mode 100644
index 000000000000..9c23d901c49c
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1861b-krypton-8gb.dts
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Realtek RTD1861B Krypton EVB
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+/dts-v1/;
+
+#include "rtd1861b-krypton.dtsi"
+
+/ {
+	compatible = "realtek,krypton", "realtek,rtd1861b";
+	model = "Realtek Krypton EVB (8GB)";
+
+	memory at 40000 {
+		device_type = "memory";
+		reg = <0x0 0x50000 0x0 0x7ffb0000>,
+		      <0x0 0x8a100000 0x0 0xdef0000>,
+		      <0x0 0x98700000 0x0 0x7900000>,
+		      <0x0 0xa0600000 0x0 0x5ea00000>,
+		      <0x1 0x0 0x0 0xa0000000>,
+		      <0x1 0xa0600000 0x0 0x5fa00000>;
+	};
+};
diff --git a/arch/arm64/boot/dts/realtek/rtd1861b-krypton.dtsi b/arch/arm64/boot/dts/realtek/rtd1861b-krypton.dtsi
new file mode 100644
index 000000000000..b500f4d2c502
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1861b-krypton.dtsi
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Realtek RTD1861B Krypton EVB
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+/dts-v1/;
+
+#include "rtd1861.dtsi"
+
+/ {
+	chosen {
+		stdout-path = "serial0:460800n8";
+	};
+
+	reserved_memory: reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		linux,cma {
+			compatible = "shared-dma-pool";
+			alignment = <0x0 0x400000>;
+			alloc-ranges = <0x0 0x0 0x0 0x20000000>;
+			size = <0x0 0x2000000>;
+			reusable;
+			linux,cma-default;
+		};
+	};
+
+	cpu_opps: opp-table-cpu {
+		compatible = "operating-points-v2";
+		opp-shared;
+
+		opp1200: opp-1200000000 {
+			opp-hz = /bits/ 64 <1200000000>;
+			opp-microvolt = <900000>;
+		};
+
+		opp1600: opp-1600000000 {
+			opp-hz = /bits/ 64 <1600000000>;
+			opp-microvolt = <1000000>;
+			opp-suspend;
+		};
+
+		opp1800: opp-1800000000 {
+			opp-hz = /bits/ 64 <1800000000>;
+			opp-microvolt = <1050000>;
+		};
+	};
+};
+
+&cpu0 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu1 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu2 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu3 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
diff --git a/arch/arm64/boot/dts/realtek/rtd1920.dtsi b/arch/arm64/boot/dts/realtek/rtd1920.dtsi
new file mode 100644
index 000000000000..becf546216e9
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1920.dtsi
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Realtek RTD1920 SoC
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+#include "kent.dtsi"
+
+&uart0 {
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/realtek/rtd1920s-smallville-4gb.dts b/arch/arm64/boot/dts/realtek/rtd1920s-smallville-4gb.dts
new file mode 100644
index 000000000000..9fd6976e0d9b
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1920s-smallville-4gb.dts
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Realtek RTD1920S Smallville EVB
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+/dts-v1/;
+
+#include "rtd1920s-smallville.dtsi"
+
+/ {
+	compatible = "realtek,smallville", "realtek,rtd1920s";
+	model = "Realtek Smallville EVB (4GB)";
+
+	memory at 40000 {
+		device_type = "memory";
+		reg = <0x0 0x50000 0x0 0x7ffb0000>,
+		      <0x0 0x8a100000 0x0 0xdef0000>,
+		      <0x0 0x98700000 0x0 0x7900000>,
+		      <0x0 0xa1000000 0x0 0x5e000000>;
+	};
+};
diff --git a/arch/arm64/boot/dts/realtek/rtd1920s-smallville.dtsi b/arch/arm64/boot/dts/realtek/rtd1920s-smallville.dtsi
new file mode 100644
index 000000000000..3db8fcea6447
--- /dev/null
+++ b/arch/arm64/boot/dts/realtek/rtd1920s-smallville.dtsi
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Realtek RTD1920S Smallville EVB
+ *
+ * Copyright (c) 2024 Realtek Semiconductor Corp.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/thermal/thermal.h>
+#include "rtd1920.dtsi"
+
+/ {
+	chosen {
+		stdout-path = "serial0:460800n8";
+	};
+
+	reserved_memory: reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		protected_mem: protected-mem at 50000 {
+			reg = <0x0 0x50000 0x0 0xbf0000>;
+			no-map;
+		};
+
+		metadata: metadata at c40000 {
+			reg = <0x0 0xc40000 0x0 0x3c4000>;
+			no-map;
+		};
+
+		linux,cma {
+			compatible = "shared-dma-pool";
+			alignment = <0x0 0x400000>;
+			alloc-ranges = <0x0 0x0 0x0 0x20000000>;
+			size = <0x0 0x2000000>;
+			reusable;
+			linux,cma-default;
+		};
+	};
+
+	cpu_opps: opp-table-cpu {
+		compatible = "operating-points-v2";
+		opp-shared;
+
+		opp800: opp-800000000 {
+			opp-hz = /bits/ 64 <800000000>;
+			opp-microvolt = <830000 830000 1100000>;
+		};
+
+		opp900: opp-900000000 {
+			opp-hz = /bits/ 64 <900000000>;
+			opp-microvolt = <850000 850000 1100000>;
+		};
+
+		opp1000: opp-1000000000 {
+			opp-hz = /bits/ 64 <1000000000>;
+			opp-microvolt = <870000 870000 1100000>;
+		};
+
+		opp1100: opp-1100000000 {
+			opp-hz = /bits/ 64 <1100000000>;
+			opp-microvolt = <890000 890000 1100000>;
+		};
+
+		opp1200: opp-1200000000 {
+			opp-hz = /bits/ 64 <1200000000>;
+			opp-microvolt = <910000 910000 1100000>;
+		};
+
+		opp1300: opp-1300000000 {
+			opp-hz = /bits/ 64 <1300000000>;
+			opp-microvolt = <930000 930000 1100000>;
+		};
+
+		opp1400: opp-1400000000 {
+			opp-hz = /bits/ 64 <1400000000>;
+			opp-microvolt = <950000 950000 1100000>;
+		};
+
+		opp1500: opp-1500000000 {
+			opp-hz = /bits/ 64 <1500000000>;
+			opp-microvolt = <970000 970000 1100000>;
+		};
+
+		opp1600: opp-1600000000 {
+			opp-hz = /bits/ 64 <1600000000>;
+			opp-microvolt = <990000 990000 1100000>;
+			opp-suspend;
+		};
+
+		opp1700: opp-1700000000 {
+			opp-hz = /bits/ 64 <1700000000>;
+			opp-microvolt = <1010000 1010000 1100000>;
+		};
+
+		opp1800: opp-1800000000 {
+			opp-hz = /bits/ 64 <1800000000>;
+			opp-microvolt = <1030000 1030000 1100000>;
+		};
+
+		opp1900: opp-1900000000 {
+			opp-hz = /bits/ 64 <1900000000>;
+			opp-microvolt = <1050000 1050000 1100000>;
+		};
+	};
+};
+
+&cpu0 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu1 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu2 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
+
+&cpu3 {
+	operating-points-v2 = <&cpu_opps>;
+	#cooling-cells = <2>;
+};
-- 
2.34.1



From eleanor.lin at realtek.com  Mon Dec 15 02:31:55 2025
From: eleanor.lin at realtek.com (Yu-Chun Lin)
Date: Mon, 15 Dec 2025 18:31:55 +0800
Subject: [PATCH v3 0/2 RESEND] arm64: dts: Add support for Kent SoC family
Message-ID: <20251215103157.27039-1-eleanor.lin@realtek.com>

Hello,

This patch series adds initial Device Tree support for Realtek's Kent SoC
family, including the RTD1501S, RTD1861B, and RTD1920S variants with their
respective evaluation boards.

The series includes:

1. Adds compatible strings for the Kent family.
2. Add Device Tree files for the Kent SoC, TD1501S Phantom EVB (8GB),
RTD1861B Krypton EVB (8GB), and RTD1920S Smallville EVB (4GB).

The patches have been validated with 'make dtbs_check' and
'dt_binding_check' to ensure compliance with DT schema and successful
compilation.

Cheers,
Yu-Chun

Signed-off-by: Yu-Chun Lin <eleanor.lin at realtek.com>
---
Changes in v3:

- Drop the dt-bindings patch (realtek,misc.yaml)
- Drop 'iso: syscon at 7000' node and and re-parent the UART directly to rbus
- Change all dts/dtsi to license: GPL-2.0
- Drop all custom bootargs

V2: https://lore.kernel.org/lkml/20251113123009.26568-1-eleanor.lin at realtek.com/

Changes in v2:

[PATCH v2 1/3]
- Fix YAML syntax: remove duplicate blank lines
- Validated with 'make dt_binding_check'

[PATCH v2 2/3]
- Rename: realtek,iso-system.yaml -> realtek,misc.yaml
- Improve description and example: show child node (UART)

[PATCH v2 3/3]
- Reorder Makefile targets to alphabetical order.
- Rename node: use generic names ('arch_timer' -> 'timer', 'reg-bus' -> 'bus')
- Fix node naming and hex format (remove leading zeros)
- Inline overlay nodes directly into .dtsi
- Reorder properties: ranges after reg
- Remove unnecessary status and custom bootargs

V1: https://lore.kernel.org/lkml/20251105104452.6336-1-eleanor.lin at realtek.com/

Yu-Chun Lin (2):
  dt-bindings: arm: realtek: Add Kent Soc family compatibles
  arm64: dts: realtek: Add Kent SoC and EVB device trees

 .../devicetree/bindings/arm/realtek.yaml      |  42 +++--
 arch/arm64/boot/dts/realtek/Makefile          |   7 +-
 arch/arm64/boot/dts/realtek/kent.dtsi         | 166 ++++++++++++++++++
 arch/arm64/boot/dts/realtek/rtd1501.dtsi      |  12 ++
 .../boot/dts/realtek/rtd1501s-phantom-8gb.dts |  25 +++
 .../boot/dts/realtek/rtd1501s-phantom.dtsi    | 118 +++++++++++++
 arch/arm64/boot/dts/realtek/rtd1861.dtsi      |  12 ++
 .../boot/dts/realtek/rtd1861b-krypton-8gb.dts |  25 +++
 .../boot/dts/realtek/rtd1861b-krypton.dtsi    |  72 ++++++++
 arch/arm64/boot/dts/realtek/rtd1920.dtsi      |  12 ++
 .../dts/realtek/rtd1920s-smallville-4gb.dts   |  23 +++
 .../boot/dts/realtek/rtd1920s-smallville.dtsi | 128 ++++++++++++++
 12 files changed, 626 insertions(+), 16 deletions(-)
 create mode 100644 arch/arm64/boot/dts/realtek/kent.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1501.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1501s-phantom-8gb.dts
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1501s-phantom.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1861.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1861b-krypton-8gb.dts
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1861b-krypton.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1920.dtsi
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1920s-smallville-4gb.dts
 create mode 100644 arch/arm64/boot/dts/realtek/rtd1920s-smallville.dtsi

-- 
2.34.1



From robh at kernel.org  Mon Dec 15 02:36:26 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Mon, 15 Dec 2025 04:36:26 -0600
Subject: [PATCH v6 1/7] dt-bindings: hwmon: Add Apple System Management
 Controller hwmon schema
In-Reply-To: <20251215-macsmc-subdevs-v6-1-0518cb5f28ae@gmail.com>
References: <20251215-macsmc-subdevs-v6-0-0518cb5f28ae@gmail.com>
 <20251215-macsmc-subdevs-v6-1-0518cb5f28ae@gmail.com>
Message-ID: <176579498664.1749225.5193965875803198793.robh@kernel.org>


On Mon, 15 Dec 2025 19:37:45 +1000, James Calligeros wrote:
> Apple Silicon devices integrate a vast array of sensors, monitoring
> current, power, temperature, and voltage across almost every part of
> the system. The sensors themselves are all connected to the System
> Management Controller (SMC). The SMC firmware exposes the data
> reported by these sensors via its standard FourCC-based key-value
> API. The SMC is also responsible for monitoring and controlling any
> fans connected to the system, exposing them in the same way.
> 
> For reasons known only to Apple, each device exposes its sensors with
> an almost totally unique set of keys. This is true even for devices
> which share an SoC. An M1 Mac mini, for example, will report its core
> temperatures on different keys to an M1 MacBook Pro. Worse still, the
> SMC does not provide a way to enumerate the available keys at runtime,
> nor do the keys follow any sort of reasonable or consistent naming
> rules that could be used to deduce their purpose. We must therefore
> know which keys are present on any given device, and which function
> they serve, ahead of time.
> 
> Add a schema so that we can describe the available sensors for a given
> Apple Silicon device in the Devicetree.
> 
> Reviewed-by: Neal Gompa <neal at gompa.dev>
> Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
> Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
> ---
>  .../bindings/hwmon/apple,smc-hwmon.yaml  | 86 +++++++++++++++++++++++++
>  .../bindings/mfd/apple,smc.yaml          | 36 +++++++++++
>  MAINTAINERS                              |  1 +
>  3 files changed, 123 insertions(+)
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:
./Documentation/devicetree/bindings/hwmon/apple,smc-hwmon.yaml:73:1: [warning] too many blank lines (2 > 1) (empty-lines)

dtschema/dtc warnings/errors:

doc reference errors (make refcheckdocs):

See https://patchwork.kernel.org/project/devicetree/patch/20251215-macsmc-subdevs-v6-1-0518cb5f28ae at gmail.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.



From payne.lin at mediatek.com  Mon Dec 15 02:38:47 2025
From: payne.lin at mediatek.com (20190311120055 created)
Date: Mon, 15 Dec 2025 18:38:47 +0800
Subject: [PATCH] pwm: mediatek: Add error handling for zero rate in PWM state
Message-ID: <20251215103855.3099184-1-payne.lin@mediatek.com>

From: Payne Lin <payne.lin at mediatek.com>

Added a check to handle cases where the rate is zero in the
mtk_disp_pwm_get_state function. This prevents division by zero errors
when calculating the period.
- Added error message for zero rate scenario

Signed-off-by: Payne Lin <payne.lin at mediatek.com>
---
 drivers/pwm/pwm-mtk-disp.c | 31 +++++++++++++++++++------------
 1 file changed, 19 insertions(+), 12 deletions(-)

diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c
index bafd6b6195f6..dd0ae041af70 100644
--- a/drivers/pwm/pwm-mtk-disp.c
+++ b/drivers/pwm/pwm-mtk-disp.c
@@ -176,19 +176,18 @@ static int mtk_disp_pwm_get_state(struct pwm_chip *chip,
 	struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
 	u64 rate, period, high_width;
 	u32 clk_div, pwm_en, con0, con1;
-	int err;
+	int ret;
 
-	err = clk_prepare_enable(mdp->clk_main);
-	if (err < 0) {
-		dev_err(pwmchip_parent(chip), "Can't enable mdp->clk_main: %pe\n", ERR_PTR(err));
-		return err;
+	ret = clk_prepare_enable(mdp->clk_main);
+	if (ret < 0) {
+		dev_err(pwmchip_parent(chip), "Can't enable mdp->clk_main: %pe\n", ERR_PTR(ret));
+		goto err_handle;
 	}
 
-	err = clk_prepare_enable(mdp->clk_mm);
-	if (err < 0) {
-		dev_err(pwmchip_parent(chip), "Can't enable mdp->clk_mm: %pe\n", ERR_PTR(err));
-		clk_disable_unprepare(mdp->clk_main);
-		return err;
+	ret = clk_prepare_enable(mdp->clk_mm);
+	if (ret < 0) {
+		dev_err(pwmchip_parent(chip), "Can't enable mdp->clk_mm: %pe\n", ERR_PTR(ret));
+		goto err_disable_clk_main;
 	}
 
 	/*
@@ -212,15 +211,23 @@ static int mtk_disp_pwm_get_state(struct pwm_chip *chip,
 	 * period has 12 bits, clk_div 11 and NSEC_PER_SEC has 30,
 	 * so period * (clk_div + 1) * NSEC_PER_SEC doesn't overflow.
 	 */
+	if (rate == 0) {
+		dev_err(pwmchip_parent(chip), "rate is zero, cannot calculate period\n");
+		ret = -EINVAL;
+		goto err_disable_clk_mm;
+	}
 	state->period = DIV64_U64_ROUND_UP(period * (clk_div + 1) * NSEC_PER_SEC, rate);
 	high_width = FIELD_GET(PWM_HIGH_WIDTH_MASK, con1);
 	state->duty_cycle = DIV64_U64_ROUND_UP(high_width * (clk_div + 1) * NSEC_PER_SEC,
 					       rate);
 	state->polarity = PWM_POLARITY_NORMAL;
+
+err_disable_clk_mm:
 	clk_disable_unprepare(mdp->clk_mm);
+err_disable_clk_main:
 	clk_disable_unprepare(mdp->clk_main);
-
-	return 0;
+err_handle:
+	return ret;
 }
 
 static const struct pwm_ops mtk_disp_pwm_ops = {
-- 
2.45.2



From payne.lin at mediatek.com  Mon Dec 15 02:40:32 2025
From: payne.lin at mediatek.com (20190311120055 created)
Date: Mon, 15 Dec 2025 18:40:32 +0800
Subject: [PATCH] pwm: mediatek: Add error handling for zero rate in PWM state
Message-ID: <20251215104037.3100485-1-payne.lin@mediatek.com>

From: Payne Lin <payne.lin at mediatek.com>

Added a check to handle cases where the rate is zero in the
mtk_disp_pwm_get_state function. This prevents division by zero errors
when calculating the period.
- Added error message for zero rate scenario

Signed-off-by: Payne Lin <payne.lin at mediatek.com>
---
 drivers/pwm/pwm-mtk-disp.c | 31 +++++++++++++++++++------------
 1 file changed, 19 insertions(+), 12 deletions(-)

diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c
index bafd6b6195f6..dd0ae041af70 100644
--- a/drivers/pwm/pwm-mtk-disp.c
+++ b/drivers/pwm/pwm-mtk-disp.c
@@ -176,19 +176,18 @@ static int mtk_disp_pwm_get_state(struct pwm_chip *chip,
 	struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
 	u64 rate, period, high_width;
 	u32 clk_div, pwm_en, con0, con1;
-	int err;
+	int ret;
 
-	err = clk_prepare_enable(mdp->clk_main);
-	if (err < 0) {
-		dev_err(pwmchip_parent(chip), "Can't enable mdp->clk_main: %pe\n", ERR_PTR(err));
-		return err;
+	ret = clk_prepare_enable(mdp->clk_main);
+	if (ret < 0) {
+		dev_err(pwmchip_parent(chip), "Can't enable mdp->clk_main: %pe\n", ERR_PTR(ret));
+		goto err_handle;
 	}
 
-	err = clk_prepare_enable(mdp->clk_mm);
-	if (err < 0) {
-		dev_err(pwmchip_parent(chip), "Can't enable mdp->clk_mm: %pe\n", ERR_PTR(err));
-		clk_disable_unprepare(mdp->clk_main);
-		return err;
+	ret = clk_prepare_enable(mdp->clk_mm);
+	if (ret < 0) {
+		dev_err(pwmchip_parent(chip), "Can't enable mdp->clk_mm: %pe\n", ERR_PTR(ret));
+		goto err_disable_clk_main;
 	}
 
 	/*
@@ -212,15 +211,23 @@ static int mtk_disp_pwm_get_state(struct pwm_chip *chip,
 	 * period has 12 bits, clk_div 11 and NSEC_PER_SEC has 30,
 	 * so period * (clk_div + 1) * NSEC_PER_SEC doesn't overflow.
 	 */
+	if (rate == 0) {
+		dev_err(pwmchip_parent(chip), "rate is zero, cannot calculate period\n");
+		ret = -EINVAL;
+		goto err_disable_clk_mm;
+	}
 	state->period = DIV64_U64_ROUND_UP(period * (clk_div + 1) * NSEC_PER_SEC, rate);
 	high_width = FIELD_GET(PWM_HIGH_WIDTH_MASK, con1);
 	state->duty_cycle = DIV64_U64_ROUND_UP(high_width * (clk_div + 1) * NSEC_PER_SEC,
 					       rate);
 	state->polarity = PWM_POLARITY_NORMAL;
+
+err_disable_clk_mm:
 	clk_disable_unprepare(mdp->clk_mm);
+err_disable_clk_main:
 	clk_disable_unprepare(mdp->clk_main);
-
-	return 0;
+err_handle:
+	return ret;
 }
 
 static const struct pwm_ops mtk_disp_pwm_ops = {
-- 
2.45.2



From jbrunet at baylibre.com  Mon Dec 15 02:51:04 2025
From: jbrunet at baylibre.com (Jerome Brunet)
Date: Mon, 15 Dec 2025 11:51:04 +0100
Subject: [PATCH v7 0/5] add support for T7 family clock controller
In-Reply-To: <20251212022619.3072132-1-jian.hu@amlogic.com>
References: <20251212022619.3072132-1-jian.hu@amlogic.com>
Message-ID: <176579586493.1510096.5256519771615298068.b4-ty@baylibre.com>

Applied to clk-meson (clk-meson-next), thanks!

[1/5] dt-bindings: clock: add Amlogic T7 PLL clock controller
      https://github.com/BayLibre/clk-meson/commit/5437753728ac
[2/5] dt-bindings: clock: add Amlogic T7 SCMI clock controller
      https://github.com/BayLibre/clk-meson/commit/f5d473e96fe0
[3/5] dt-bindings: clock: add Amlogic T7 peripherals clock controller
      https://github.com/BayLibre/clk-meson/commit/b4156204e0f5
[4/5] clk: meson: t7: add support for the T7 SoC PLL clock
      https://github.com/BayLibre/clk-meson/commit/140f074c3127
[5/5] clk: meson: t7: add t7 clock peripherals controller driver
      https://github.com/BayLibre/clk-meson/commit/fab4d651b592

Best regards,
--
Jerome



From jbrunet at baylibre.com  Mon Dec 15 02:51:06 2025
From: jbrunet at baylibre.com (Jerome Brunet)
Date: Mon, 15 Dec 2025 11:51:06 +0100
Subject: [PATCH v6 0/3] clk: amlogic: add video-related clocks for S4
 SoC
In-Reply-To: <20250919-add_video_clk-v6-0-fe223161fb3f@amlogic.com>
References: <20250919-add_video_clk-v6-0-fe223161fb3f@amlogic.com>
Message-ID: <176579586619.1510096.14461375977036233686.b4-ty@baylibre.com>

Applied to clk-meson (clk-meson-next), thanks!

[1/3] dt-bindings: clock: add video clock indices for Amlogic S4 SoC
      https://github.com/BayLibre/clk-meson/commit/29c4f32095d0
[2/3] clk: amlogic: add video-related clocks for S4 SoC
      https://github.com/BayLibre/clk-meson/commit/c78c9dbe2bb9
[3/3] clk: amlogic: remove potentially unsafe flags from S4 video clocks
      https://github.com/BayLibre/clk-meson/commit/4aca7e92023c

Best regards,
--
Jerome



From james.clark at linaro.org  Mon Dec 15 02:52:24 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 15 Dec 2025 12:52:24 +0200
Subject: [PATCH] arm64: perf: fix syscalltbl path base
In-Reply-To: <23c07ac4-ff13-47a5-824a-e7af1d1847a3@app.fastmail.com>
References: <b2651f20-6f3a-49f5-9cd8-3fb028b2cab5@app.fastmail.com>
 <fcefc3c0-541d-40cc-84e3-9c2460308bdb@linaro.org>
 <23c07ac4-ff13-47a5-824a-e7af1d1847a3@app.fastmail.com>
Message-ID: <bda366b4-fa53-4feb-a7ce-ee47cfc404b5@linaro.org>



On 15/12/2025 11:33, Arnd Bergmann wrote:
> On Mon, Dec 15, 2025, at 09:47, James Clark wrote:
>> On 15/12/2025 00:12, Joel May wrote:
>>
>> Hi Joel,
>>
>> There is a similar fix on the list here:
>>
>> https://lore.kernel.org/linux-perf-users/20251204-perf_fix_syscall_header-v1-1-b8e27f74ed6a at arm.com/
>>
>> I'm not sure if commit 1 alone will also fix your issue, or we'd need to
>> collapse both of the commits in that set.
>>
>> The first commit has an older fixes: tag and also fixes some other
>> issues so it might be better to take that one rather than this one.
> 
> I don't understand that other "fix", doesn't that just work around
> the arm64 build issue by adding another special case for arm64?
> 
> If we want the tools directory to have a copy of the generated unistd.h
> files instead of generating them, it should at the minimum be done
> the same across all architectures.
> 
>      Arnd

I don't think it's a special case, the other architectures already have 
a copy of their syscall headers in tools/ don't they?

My original commit that is reverted by Leo's patches is more of a "fix" 
than his fix. It turned out that running the generator script for the 
Perf build wasn't the best idea after all. Now it's obvious that we'd 
have to keep injecting that build rule into every tool that needs it. 
And it doesn't even respect this rule described here that tools headers 
should be decoupled from the kernel sources:

  linux/tools/include/uapi/README

I don't see the benefit of manually copying over the generator script 
and its input file and then updating every build rule to invoke it when 
we can manually copy over the output of that script and not have to do 
anything else.

Ian makes the point that we can run the generator for doing 
check_headers.sh. But at least that only needs to be done for one tool 
and can be in addition to the manual copy.

James



From zajec5 at gmail.com  Mon Dec 15 02:53:02 2025
From: zajec5 at gmail.com (=?UTF-8?B?UmFmYcWCIE1pxYJlY2tp?=)
Date: Mon, 15 Dec 2025 11:53:02 +0100
Subject: [PATCH 2/2] ARM: dts: mediatek: mt7623: fix efuse fallback
 compatible
In-Reply-To: <20240617094634.23173-2-zajec5@gmail.com>
References: <20240617094634.23173-1-zajec5@gmail.com>
 <20240617094634.23173-2-zajec5@gmail.com>
Message-ID: <424704d3-eb9a-4af3-828c-96645e347907@gmail.com>

W dniu 17.06.2024 o?11:46, Rafa? Mi?ecki pisze:
> From: Rafa? Mi?ecki <rafal at milecki.pl>
> 
> Fix following validation error:
> arch/arm/boot/dts/mediatek/mt7623a-rfb-emmc.dtb: efuse at 10206000: compatible: 'oneOf' conditional failed, one must be fixed:
>          ['mediatek,mt7623-efuse', 'mediatek,mt8173-efuse'] is too long
>          'mediatek,mt8173-efuse' was expected
>          'mediatek,efuse' was expected
>          from schema $id: http://devicetree.org/schemas/nvmem/mediatek,efuse.yaml#
> arch/arm/boot/dts/mediatek/mt7623a-rfb-emmc.dtb: efuse at 10206000: Unevaluated properties are not allowed ('compatible' was unexpected)
>          from schema $id: http://devicetree.org/schemas/nvmem/mediatek,efuse.yaml#
> 
> Fixes: 43c7a91b4b3a ("arm: dts: mt7623: add efuse nodes to the mt7623.dtsi file")
> Signed-off-by: Rafa? Mi?ecki <rafal at milecki.pl>

I noticed this patch got missed.

With AngeloGioacchino's review, can we have it accepted now?


> ---
>   arch/arm/boot/dts/mediatek/mt7623.dtsi | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/arch/arm/boot/dts/mediatek/mt7623.dtsi b/arch/arm/boot/dts/mediatek/mt7623.dtsi
> index 9c5a52ce9351..748f9b366897 100644
> --- a/arch/arm/boot/dts/mediatek/mt7623.dtsi
> +++ b/arch/arm/boot/dts/mediatek/mt7623.dtsi
> @@ -328,7 +328,7 @@ sysirq: interrupt-controller at 10200100 {
>   
>   	efuse: efuse at 10206000 {
>   		compatible = "mediatek,mt7623-efuse",
> -			     "mediatek,mt8173-efuse";
> +			     "mediatek,efuse";
>   		reg = <0 0x10206000 0 0x1000>;
>   		#address-cells = <1>;
>   		#size-cells = <1>;



From Sascha.Bischoff at arm.com  Mon Dec 15 02:54:19 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Mon, 15 Dec 2025 10:54:19 +0000
Subject: [PATCH 14/32] KVM: arm64: gic-v5: Implement GICv5 load/put and
 save/restore
In-Reply-To: <202512131338.pYhd9ptc-lkp@intel.com>
References: <20251212152215.675767-15-sascha.bischoff@arm.com>
	 <202512131338.pYhd9ptc-lkp@intel.com>
Message-ID: <fd72d2f3cee71081d6abca6bdefd20c2962708b0.camel@arm.com>

On Sat, 2025-12-13 at 13:59 +0800, kernel test robot wrote:
> All errors (new ones prefixed by >>):
> 
> ?? In file included from arch/arm64/include/asm/kvm_host.h:36,
> ??????????????????? from include/linux/kvm_host.h:45,
> ??????????????????? from arch/arm64/kernel/asm-offsets.c:16:
> > > include/kvm/arm_vgic.h:392:26: error: field 'gicv5_vpe' has
> > > incomplete type
> ???? 392 |???????? struct gicv5_vpe gicv5_vpe;
> ???????? |????????????????????????? ^~~~~~~~~
> ?? make[3]: *** [scripts/Makefile.build:182: arch/arm64/kernel/asm-
> offsets.s] Error 1
> ?? make[3]: Target 'prepare' not remade because of errors.
> ?? make[2]: *** [Makefile:1314: prepare0] Error 2
> ?? make[2]: Target 'prepare' not remade because of errors.
> ?? make[1]: *** [Makefile:248: __sub-make] Error 2
> ?? make[1]: Target 'prepare' not remade because of errors.
> ?? make: *** [Makefile:248: __sub-make] Error 2
> ?? make: Target 'prepare' not remade because of errors.
> 

I've located the underlying issue - the definition of struct gicv5_vpe
was wrapped in an #ifdef CONFIG_KVM block, and the two failing builds
have KVM disabled.

I've fixed the issue locally (dropped the #ifdef), and will post a
fixed commit as part of v2 of this series.

Sascha

From nicolas.frattaroli at collabora.com  Mon Dec 15 03:10:21 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Mon, 15 Dec 2025 12:10:21 +0100
Subject: [PATCH 2/4] Input: adc-keys - support types that aren't just keyboard
 keys
In-Reply-To: <20251028213209.2646838-1-dsimic@manjaro.org>
References: <20250630-rock4d-audio-v1-2-0b3c8e8fda9c@collabora.com>
 <20251028213209.2646838-1-dsimic@manjaro.org>
Message-ID: <2411362.ElGaqSPkdT@workhorse>

On Tuesday, 28 October 2025 22:32:09 Central European Standard Time Dragan Simic wrote:
> Hello Nicolas,
> 
> On Monday, June 30, 2025, 12:19:24 Nicolas Frattaroli wrote:
> > Instead of doing something like what gpio-keys is doing, adc-keys
> > hardcodes that all keycodes must be of type EV_KEY.
> > 
> > This limits the usefulness of adc-keys, and overcomplicates the code
> > with manual bit-setting logic.
> > 
> > Instead, refactor the code to read the linux,input-type fwnode property,
> > and get rid of the custom bit setting logic, replacing it with
> > input_set_capability instead. input_report_key is replaced with
> > input_event, which allows us to explicitly pass the type.
> 
> Thanks for this patch, it's indeed very useful!  Please see some
> comments below.
> 
> > Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
> > ---
> >  drivers/input/keyboard/adc-keys.c | 16 ++++++++++++----
> >  1 file changed, 12 insertions(+), 4 deletions(-)
> > 
> > diff --git a/drivers/input/keyboard/adc-keys.c b/drivers/input/keyboard/adc-keys.c
> > index f1753207429db02ce6510e5ec0da9b24d9edb61d..339dd4d4a0842108da2c6136b1e0098cd1f6a3cd 100644
> > --- a/drivers/input/keyboard/adc-keys.c
> > +++ b/drivers/input/keyboard/adc-keys.c
> > @@ -19,12 +19,14 @@
> >  struct adc_keys_button {
> >  	u32 voltage;
> >  	u32 keycode;
> > +	u32 type;
> >  };
> >  
> >  struct adc_keys_state {
> >  	struct iio_channel *channel;
> >  	u32 num_keys;
> >  	u32 last_key;
> > +	u32 last_type;
> >  	u32 keyup_voltage;
> >  	const struct adc_keys_button *map;
> >  };
> > @@ -35,6 +37,7 @@ static void adc_keys_poll(struct input_dev *input)
> >  	int i, value, ret;
> >  	u32 diff, closest = 0xffffffff;
> >  	int keycode = 0;
> > +	u32 type = EV_KEY;
> >  
> >  	ret = iio_read_channel_processed(st->channel, &value);
> >  	if (unlikely(ret < 0)) {
> > @@ -46,6 +49,7 @@ static void adc_keys_poll(struct input_dev *input)
> >  			if (diff < closest) {
> >  				closest = diff;
> >  				keycode = st->map[i].keycode;
> > +				type = st->map[i].type;
> >  			}
> >  		}
> >  	}
> > @@ -54,13 +58,14 @@ static void adc_keys_poll(struct input_dev *input)
> >  		keycode = 0;
> >  
> >  	if (st->last_key && st->last_key != keycode)
> > -		input_report_key(input, st->last_key, 0);
> > +		input_event(input, st->last_type, st->last_key, 0);
> >  
> >  	if (keycode)
> > -		input_report_key(input, keycode, 1);
> > +		input_event(input, type, keycode, 1);
> 
> When EV_ABS is defined in the DT as the key type, which happens with
> joysticks and whatnot, separate handling is needed, by requiring the
> actual associated button values to be reported in the input_event()
> invocations, more specifically on the keypresses only.

Analogue control devices like joysticks are handled in adc-joystick.c.
adc-keys is specifically for resistor-ladder key devices. A driver or
binding for some absolute/relative positioning device that is not a
joystick should get its own binding first. Overloading the meaning
of the adc-keys binding and then adding functionality to the driver
is not the way to go.

I'll instead add code to only allow EV_KEY and EV_SW. Switches
function like keys for all intents and purposes, so they fit here.

> 
> That's also visible in the gpio_keys_gpio_report_event() function in
> drivers/input/keyboard/gpio_keys.c.
> 
> >  	input_sync(input);
> >  	st->last_key = keycode;
> > +	st->last_type = type;
> >  }
> >  
> >  static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st)
> > @@ -93,6 +98,10 @@ static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st)
> >  			return -EINVAL;
> >  		}
> >  
> > +		if (fwnode_property_read_u32(child, "linux,input-type",
> > +					     &map[i].type))
> > +			map[i].type = EV_KEY;
> 
> Going along with the remarks above, it will also be needed to read
> and record the values of "linux,input-value" DT properties here, and
> to extend the associated binding to define their presence.
> 
> >  		i++;
> >  	}
> >  
> > @@ -156,9 +165,8 @@ static int adc_keys_probe(struct platform_device *pdev)
> >  	input->id.product = 0x0001;
> >  	input->id.version = 0x0100;
> >  
> > -	__set_bit(EV_KEY, input->evbit);
> >  	for (i = 0; i < st->num_keys; i++)
> > -		__set_bit(st->map[i].keycode, input->keybit);
> > +		input_set_capability(input, st->map[i].type, st->map[i].keycode);
> >  
> >  	if (device_property_read_bool(dev, "autorepeat"))
> >  		__set_bit(EV_REP, input->evbit);
> 






From peng.fan at nxp.com  Mon Dec 15 03:11:47 2025
From: peng.fan at nxp.com (Peng Fan)
Date: Mon, 15 Dec 2025 11:11:47 +0000
Subject: [PATCH] remoteproc: imx_rproc: Use strstarts for "rsc-table"
 check
In-Reply-To: <aT9wP_3olsf7WbPL@p14s>
References: <20251208233302.684139-1-shenwei.wang@nxp.com>
 <aT9wP_3olsf7WbPL@p14s>
Message-ID: <PAXPR04MB8459542CF892C802061E162688ADA@PAXPR04MB8459.eurprd04.prod.outlook.com>

> Subject: Re: [PATCH] remoteproc: imx_rproc: Use strstarts for "rsc-
> table" check
> 
> On Mon, Dec 08, 2025 at 05:33:02PM -0600, Shenwei Wang wrote:
> > The resource name may include an address suffix, for example:
> > rsc-table at 1fff8000.
> >
> > To handle such cases, use strstarts() instead of strcmp() when
> > checking for "rsc-table".
> >
> > Signed-off-by: Shenwei Wang <shenwei.wang at nxp.com>
> > ---
> >  drivers/remoteproc/imx_rproc.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/remoteproc/imx_rproc.c
> > b/drivers/remoteproc/imx_rproc.c index
> 3be8790c14a2..33f21ab24c92
> > 100644
> > --- a/drivers/remoteproc/imx_rproc.c
> > +++ b/drivers/remoteproc/imx_rproc.c
> > @@ -694,7 +694,7 @@ static int imx_rproc_addr_init(struct
> imx_rproc *priv,
> >  		}
> >  		priv->mem[b].sys_addr = res.start;
> >  		priv->mem[b].size = resource_size(&res);
> > -		if (!strcmp(res.name, "rsc-table"))
> > +		if (strstarts(res.name, "rsc-table"))
> >  			priv->rsc_table = priv->mem[b].cpu_addr;
> 
> Before applying this patch, I want to know how it ever worked before.
> How did DT with a suffix tested?

In Rob's v2 version[1], I gave my T-b in 2025-5-7, but I could not recall
whether I did rpmsg test, seems I only did start/stop test from the issue
Shenwei spotted.

[1] https://lore.kernel.org/linux-remoteproc/20250423-dt-memory-region-v2-v2-4-2fbd6ebd3c88 at kernel.org/

Regards
Peng.

> 
> >  		b++;
> >  	}
> > --
> > 2.43.0
> >


From rafael at kernel.org  Mon Dec 15 03:11:59 2025
From: rafael at kernel.org (Rafael J. Wysocki)
Date: Mon, 15 Dec 2025 12:11:59 +0100
Subject: [PATCH v8 12/12] cpuidle/poll_state: Wait for need-resched via tif_need_resched_relaxed_wait()
In-Reply-To: <20251215044919.460086-13-ankur.a.arora@oracle.com>
References: <20251215044919.460086-1-ankur.a.arora@oracle.com> <20251215044919.460086-13-ankur.a.arora@oracle.com>
Message-ID: <CAJZ5v0imk5kdqunNGvK+6_BPh2_k89RPPC8B4MDDF1GLZrUhLQ@mail.gmail.com>

On Mon, Dec 15, 2025 at 5:55?AM Ankur Arora <ankur.a.arora at oracle.com> wrote:
>
> The inner loop in poll_idle() polls over the thread_info flags,
> waiting to see if the thread has TIF_NEED_RESCHED set. The loop
> exits once the condition is met, or if the poll time limit has
> been exceeded.
>
> To minimize the number of instructions executed in each iteration,
> the time check is rate-limited. In addition, each loop iteration
> executes cpu_relax() which on certain platforms provides a hint to
> the pipeline that the loop busy-waits, allowing the processor to
> reduce power consumption.
>
> Switch over to tif_need_resched_relaxed_wait() instead, since that
> provides exactly that.
>
> However, given that when running in idle we want to minimize our power
> consumption, continue to depend on CONFIG_ARCH_HAS_CPU_RELAX as that
> serves as an indicator that the platform supports an optimized version
> of tif_need_resched_relaxed_wait() (via
> smp_cond_load_acquire_timeout()).
>
> Cc: "Rafael J. Wysocki" <rafael at kernel.org>
> Cc: Daniel Lezcano <daniel.lezcano at linaro.org>
> Cc: linux-pm at vger.kernel.org
> Suggested-by: "Rafael J. Wysocki" <rafael at kernel.org>
> Signed-off-by: Ankur Arora <ankur.a.arora at oracle.com>
> ---
>
> Notes:
>   - use tif_need_resched_relaxed_wait() instead of
>     smp_cond_load_relaxed_timeout()
>
>  drivers/cpuidle/poll_state.c | 27 +++++----------------------
>  1 file changed, 5 insertions(+), 22 deletions(-)
>
> diff --git a/drivers/cpuidle/poll_state.c b/drivers/cpuidle/poll_state.c
> index c7524e4c522a..20136b3a08c2 100644
> --- a/drivers/cpuidle/poll_state.c
> +++ b/drivers/cpuidle/poll_state.c
> @@ -6,41 +6,24 @@
>  #include <linux/cpuidle.h>
>  #include <linux/export.h>
>  #include <linux/irqflags.h>
> -#include <linux/sched.h>
> -#include <linux/sched/clock.h>
>  #include <linux/sched/idle.h>
>  #include <linux/sprintf.h>
>  #include <linux/types.h>
>
> -#define POLL_IDLE_RELAX_COUNT  200
> -
>  static int __cpuidle poll_idle(struct cpuidle_device *dev,
>                                struct cpuidle_driver *drv, int index)
>  {
> -       u64 time_start;
> -
> -       time_start = local_clock_noinstr();
> -
>         dev->poll_time_limit = false;
>
>         raw_local_irq_enable();
>         if (!current_set_polling_and_test()) {
> -               unsigned int loop_count = 0;
> -               u64 limit;
> +               s64 limit;
> +               bool nr_set;

It doesn't look like the nr_set variable is really needed.

>
> -               limit = cpuidle_poll_time(drv, dev);
> +               limit = (s64)cpuidle_poll_time(drv, dev);

Is the explicit cast needed to suppress a warning?  If not, I'd drop it.

>
> -               while (!need_resched()) {
> -                       cpu_relax();
> -                       if (loop_count++ < POLL_IDLE_RELAX_COUNT)
> -                               continue;
> -
> -                       loop_count = 0;
> -                       if (local_clock_noinstr() - time_start > limit) {
> -                               dev->poll_time_limit = true;
> -                               break;
> -                       }
> -               }
> +               nr_set = tif_need_resched_relaxed_wait(limit);
> +               dev->poll_time_limit = !nr_set;

This can be

dev->poll_time_limit = !tif_need_resched_relaxed_wait(limit);

>         }
>         raw_local_irq_disable();
>
> --


From peng.fan at nxp.com  Mon Dec 15 03:13:41 2025
From: peng.fan at nxp.com (Peng Fan)
Date: Mon, 15 Dec 2025 11:13:41 +0000
Subject: [PATCH] remoteproc: imx_rproc: Use strstarts for "rsc-table"
 check
In-Reply-To: <20251208233302.684139-1-shenwei.wang@nxp.com>
References: <20251208233302.684139-1-shenwei.wang@nxp.com>
Message-ID: <PAXPR04MB8459148338CF7EBB38C699EA88ADA@PAXPR04MB8459.eurprd04.prod.outlook.com>

> Subject: [PATCH] remoteproc: imx_rproc: Use strstarts for "rsc-table"
> check
> 
> The resource name may include an address suffix, for example:
> rsc-table at 1fff8000.
> 
> To handle such cases, use strstarts() instead of strcmp() when checking
> for "rsc-table".
> 
> Signed-off-by: Shenwei Wang <shenwei.wang at nxp.com>

With fixes tag added:
Reviewed-by: Peng Fan <peng.fan at nxp.com>


From leo.yan at arm.com  Mon Dec 15 03:28:18 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 15 Dec 2025 11:28:18 +0000
Subject: [PATCH] arm64: perf: fix syscalltbl path base
In-Reply-To: <bda366b4-fa53-4feb-a7ce-ee47cfc404b5@linaro.org>
References: <b2651f20-6f3a-49f5-9cd8-3fb028b2cab5@app.fastmail.com>
 <fcefc3c0-541d-40cc-84e3-9c2460308bdb@linaro.org>
 <23c07ac4-ff13-47a5-824a-e7af1d1847a3@app.fastmail.com>
 <bda366b4-fa53-4feb-a7ce-ee47cfc404b5@linaro.org>
Message-ID: <20251215112818.GB681384@e132581.arm.com>

On Mon, Dec 15, 2025 at 12:52:24PM +0200, James Clark wrote:

[...]

> On 15/12/2025 11:33, Arnd Bergmann wrote:
> > On Mon, Dec 15, 2025, at 09:47, James Clark wrote:
> > > On 15/12/2025 00:12, Joel May wrote:
> > > 
> > > Hi Joel,
> > > 
> > > There is a similar fix on the list here:
> > > 
> > > https://lore.kernel.org/linux-perf-users/20251204-perf_fix_syscall_header-v1-1-b8e27f74ed6a at arm.com/
> > > 
> > > I'm not sure if commit 1 alone will also fix your issue, or we'd need to
> > > collapse both of the commits in that set.

We need to apply both patches in the share link - we need to apply the
second patch to revert generating unistd_64.h in libperf.

> > > The first commit has an older fixes: tag and also fixes some other
> > > issues so it might be better to take that one rather than this one.
> > 
> > I don't understand that other "fix", doesn't that just work around
> > the arm64 build issue by adding another special case for arm64?
> > 
> > If we want the tools directory to have a copy of the generated unistd.h
> > files instead of generating them, it should at the minimum be done
> > the same across all architectures.
> 
> I don't think it's a special case, the other architectures already have a
> copy of their syscall headers in tools/ don't they?

Correct.  Most of architectures simply include

    tools/include/uapi/asm-generic/unistd.h

x86 includes their own unistd_32/64.h; only arm64 attempted to generate
unistd_64.h dynamically, but this is problem for build dependency - when
build perf, feature tests in tools/build/feature/ run before libperf and
fail if unistd_64.h has not yet been generated by libperf Makefile.

> My original commit that is reverted by Leo's patches is more of a "fix" than
> his fix. It turned out that running the generator script for the Perf build
> wasn't the best idea after all. Now it's obvious that we'd have to keep
> injecting that build rule into every tool that needs it. And it doesn't even
> respect this rule described here that tools headers should be decoupled from
> the kernel sources:
> 
>  linux/tools/include/uapi/README
> 
> I don't see the benefit of manually copying over the generator script and
> its input file and then updating every build rule to invoke it when we can
> manually copy over the output of that script and not have to do anything
> else.
> 
> Ian makes the point that we can run the generator for doing
> check_headers.sh. But at least that only needs to be done for one tool and
> can be in addition to the manual copy.
> 
> James


From ukleinek at kernel.org  Mon Dec 15 03:29:56 2025
From: ukleinek at kernel.org (Uwe =?utf-8?Q?Kleine-K=C3=B6nig?=)
Date: Mon, 15 Dec 2025 12:29:56 +0100
Subject: [PATCH] pwm: mediatek: Add error handling for zero rate in PWM
 state
In-Reply-To: <20251215104037.3100485-1-payne.lin@mediatek.com>
References: <20251215104037.3100485-1-payne.lin@mediatek.com>
Message-ID: <s5ieu7cciqgw3x5rnpcn43fm3nkinm4guz33nhwwi45apdz2ot@4zsbi7tckuwz>

Hello,

the From: line of your patch is strange.

On Mon, Dec 15, 2025 at 06:40:32PM +0800, 20190311120055 created wrote:
> From: Payne Lin <payne.lin at mediatek.com>
> 
> Added a check to handle cases where the rate is zero in the
> mtk_disp_pwm_get_state function. This prevents division by zero errors
> when calculating the period.
> - Added error message for zero rate scenario
> 
> Signed-off-by: Payne Lin <payne.lin at mediatek.com>
> ---
>  drivers/pwm/pwm-mtk-disp.c | 31 +++++++++++++++++++------------
>  1 file changed, 19 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c
> index bafd6b6195f6..dd0ae041af70 100644
> --- a/drivers/pwm/pwm-mtk-disp.c
> +++ b/drivers/pwm/pwm-mtk-disp.c
> @@ -176,19 +176,18 @@ static int mtk_disp_pwm_get_state(struct pwm_chip *chip,
>  	struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
>  	u64 rate, period, high_width;
>  	u32 clk_div, pwm_en, con0, con1;
> -	int err;
> +	int ret;

If you keep the variable name, the patch gets quite a bit more obivious.

> -	err = clk_prepare_enable(mdp->clk_main);
> -	if (err < 0) {
> -		dev_err(pwmchip_parent(chip), "Can't enable mdp->clk_main: %pe\n", ERR_PTR(err));
> -		return err;
> +	ret = clk_prepare_enable(mdp->clk_main);
> +	if (ret < 0) {
> +		dev_err(pwmchip_parent(chip), "Can't enable mdp->clk_main: %pe\n", ERR_PTR(ret));
> +		goto err_handle;
>  	}

Fixing error handling should go into a separate patch please.

> -	err = clk_prepare_enable(mdp->clk_mm);
> -	if (err < 0) {
> -		dev_err(pwmchip_parent(chip), "Can't enable mdp->clk_mm: %pe\n", ERR_PTR(err));
> -		clk_disable_unprepare(mdp->clk_main);
> -		return err;
> +	ret = clk_prepare_enable(mdp->clk_mm);
> +	if (ret < 0) {
> +		dev_err(pwmchip_parent(chip), "Can't enable mdp->clk_mm: %pe\n", ERR_PTR(ret));
> +		goto err_disable_clk_main;
>  	}
>  
>  	/*
> @@ -212,15 +211,23 @@ static int mtk_disp_pwm_get_state(struct pwm_chip *chip,
>  	 * period has 12 bits, clk_div 11 and NSEC_PER_SEC has 30,
>  	 * so period * (clk_div + 1) * NSEC_PER_SEC doesn't overflow.
>  	 */
That comment belongs to the assignment to state->period. Don't separate
them with your addition.

> +	if (rate == 0) {
> +		dev_err(pwmchip_parent(chip), "rate is zero, cannot calculate period\n");

All the other messages (at least those in the context above) start with
a capital letter.

> +		ret = -EINVAL;
> +		goto err_disable_clk_mm;
> +	}
>  	state->period = DIV64_U64_ROUND_UP(period * (clk_div + 1) * NSEC_PER_SEC, rate);
>  	high_width = FIELD_GET(PWM_HIGH_WIDTH_MASK, con1);
>  	state->duty_cycle = DIV64_U64_ROUND_UP(high_width * (clk_div + 1) * NSEC_PER_SEC,
>  					       rate);
>  	state->polarity = PWM_POLARITY_NORMAL;
> +
> +err_disable_clk_mm:
>  	clk_disable_unprepare(mdp->clk_mm);
> +err_disable_clk_main:
>  	clk_disable_unprepare(mdp->clk_main);
> -
> -	return 0;
> +err_handle:
> +	return ret;
>  }

Best regards
Uwe
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251215/d95dfd66/attachment-0001.sig>

From heiko at sntech.de  Mon Dec 15 03:36:26 2025
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 15 Dec 2025 12:36:26 +0100
Subject: [PATCH v5 1/4] arm64: dts: rockchip: Add light/proximity sensor to
 Pinephone Pro
In-Reply-To: <20251124-ppp_light_accel_mag_vol-down-v5-1-f9a10a0a50eb@gmail.com>
References: <20251124-ppp_light_accel_mag_vol-down-v5-0-f9a10a0a50eb@gmail.com>
 <20251124-ppp_light_accel_mag_vol-down-v5-1-f9a10a0a50eb@gmail.com>
Message-ID: <10855349.CDJkKcVGEf@phil>

Hi,

Am Dienstag, 25. November 2025, 04:47:00 Mitteleurop?ische Normalzeit schrieb Rudraksha Gupta via B4 Relay:

> diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
> index 6f97e57f36f5..2d2858ee149e 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
> +++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
> @@ -520,6 +520,16 @@ touchscreen at 14 {
>  		touchscreen-size-x = <720>;
>  		touchscreen-size-y = <1440>;
>  	};
> +
> +	light-sensor at 48 {
> +		compatible = "sensortek,stk3311";
> +		proximity-near-level = <300>;

proximity-next-... belongs below pinctrl-*


> +		reg = <0x48>;
> +		interrupt-parent = <&gpio4>;
> +		interrupts = <RK_PD3 IRQ_TYPE_EDGE_FALLING>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&light_int_l>;
> +	};
>  };
>  
>  &i2c4 {
> @@ -689,6 +699,12 @@ vcc1v8_codec_en: vcc1v8-codec-en {
>  		};
>  	};
>  
> +	stk3311 {

please sort nodes alphabetically
(stk3311 after vcc1v8-codec-en is incorrect)


> +		light_int_l: light-int-l {
> +			rockchip,pins = <4 RK_PD3 RK_FUNC_GPIO &pcfg_input_pull_up>;
> +		};
> +	};
> +
>  	wireless-bluetooth {
>  		bt_wake_pin: bt-wake-pin {
>  			rockchip,pins = <2 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;
> 
> 


Heiko





From lorenzo.stoakes at oracle.com  Mon Dec 15 03:36:01 2025
From: lorenzo.stoakes at oracle.com (Lorenzo Stoakes)
Date: Mon, 15 Dec 2025 11:36:01 +0000
Subject: [PATCH v2 1/3] arm64: mm: support batch clearing of the young
 flag for large folios
In-Reply-To: <e10f876ce130134fa089befe83f30561b48b9889.1765439380.git.baolin.wang@linux.alibaba.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <e10f876ce130134fa089befe83f30561b48b9889.1765439380.git.baolin.wang@linux.alibaba.com>
Message-ID: <5039c6a2-09b6-4c9b-accb-26583ba120db@lucifer.local>

On Thu, Dec 11, 2025 at 04:16:54PM +0800, Baolin Wang wrote:
> Currently, contpte_ptep_test_and_clear_young() and contpte_ptep_clear_flush_young()
> only clear the young flag and flush TLBs for PTEs within the contiguous range.
> To support batch PTE operations for other sized large folios in the following
> patches, adding a new parameter to specify the number of PTEs.
>
> While we are at it, rename the functions to maintain consistency with other
> contpte_*() functions.
>
> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
> ---
>  arch/arm64/include/asm/pgtable.h | 12 ++++-----
>  arch/arm64/mm/contpte.c          | 44 ++++++++++++++++++++++----------
>  2 files changed, 37 insertions(+), 19 deletions(-)
>
> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
> index 0944e296dd4a..e03034683156 100644
> --- a/arch/arm64/include/asm/pgtable.h
> +++ b/arch/arm64/include/asm/pgtable.h
> @@ -1679,10 +1679,10 @@ extern void contpte_clear_full_ptes(struct mm_struct *mm, unsigned long addr,
>  extern pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
>  				unsigned long addr, pte_t *ptep,
>  				unsigned int nr, int full);
> -extern int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
> -				unsigned long addr, pte_t *ptep);
> -extern int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
> -				unsigned long addr, pte_t *ptep);
> +extern int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
> +				unsigned long addr, pte_t *ptep, unsigned int nr);
> +extern int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
> +				unsigned long addr, pte_t *ptep, unsigned int nr);

In core mm at least, as a convention, we strip 'extern' from header declarations
as we go as they're not necessary.

I wonder about this naming convention also. The contpte_xxx_() prefix
obviously implies we are operating upon PTEs in the contiguous range, now
we are doing something... different and 'nr' is a bit vague.

Is it the nr of contiguous ranges? Well in reality it's nr_pages right? But
now we're not saying they're necessarily contiguous in the sense of contpte...

I wonder whether we'd be better off introducing a new function that
explicitly has 'batch' or 'batched' in the name, and have the usual
contpte_***() stuff and callers that need batching using a new underlying helper?

Obviously I defer to Ryan on all this, just my thoughts...

>  extern void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
>  				pte_t *ptep, unsigned int nr);
>  extern int contpte_ptep_set_access_flags(struct vm_area_struct *vma,
> @@ -1854,7 +1854,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
>  	if (likely(!pte_valid_cont(orig_pte)))
>  		return __ptep_test_and_clear_young(vma, addr, ptep);
>
> -	return contpte_ptep_test_and_clear_young(vma, addr, ptep);
> +	return contpte_test_and_clear_young_ptes(vma, addr, ptep, CONT_PTES);
>  }
>
>  #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
> @@ -1866,7 +1866,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
>  	if (likely(!pte_valid_cont(orig_pte)))
>  		return __ptep_clear_flush_young(vma, addr, ptep);
>
> -	return contpte_ptep_clear_flush_young(vma, addr, ptep);
> +	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
>  }
>
>  #define wrprotect_ptes wrprotect_ptes
> diff --git a/arch/arm64/mm/contpte.c b/arch/arm64/mm/contpte.c
> index c0557945939c..19b122441be3 100644
> --- a/arch/arm64/mm/contpte.c
> +++ b/arch/arm64/mm/contpte.c
> @@ -488,8 +488,9 @@ pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
>  }
>  EXPORT_SYMBOL_GPL(contpte_get_and_clear_full_ptes);
>
> -int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
> -					unsigned long addr, pte_t *ptep)
> +int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
> +					unsigned long addr, pte_t *ptep,
> +					unsigned int nr)
>  {
>  	/*
>  	 * ptep_clear_flush_young() technically requires us to clear the access
> @@ -500,39 +501,56 @@ int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
>  	 * having to unfold.
>  	 */

Hmm shouldn't you need to update this comment now 'nr' is a thing? E.g.:

"And since we only create a contig range when the range is covered by a single
folio, we can get away with clearing young for the whole contig range here, so
we avoid having to unfold."

However now you're allowing for large folios that are not contpte?

Overall feeling pretty iffy about implementing this this way.

>
> +	unsigned long start = addr;
> +	unsigned long end = start + nr * PAGE_SIZE;

So now [addr, addr + nr * PAGE_SIZE) must for sure be within a single PTE
table?

>  	int young = 0;
>  	int i;
>
> -	ptep = contpte_align_down(ptep);
> -	addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
> +	if (pte_cont(__ptep_get(ptep + nr - 1)))
> +		end = ALIGN(end, CONT_PTE_SIZE);

OK so I guess for PTE_CONT to be set, it must be aligned to CONT_PTE_SIZE,
with other PTE entries present there not having PTE_CONT set (Ryan - do
correct me if I'm wrong!)

I guess then no worry about running off the end of the PTE table here.

I wonder about using pte_cont_addr_end() here, but I guess you are not
intending to limit to a range here but rather capture the entire contpte
range of the end.

I don't love that now a function prefixed with contpte_... can have a
condition where part of the input range is _not_ a contpte entry, or is
specified partially...


>
> -	for (i = 0; i < CONT_PTES; i++, ptep++, addr += PAGE_SIZE)
> -		young |= __ptep_test_and_clear_young(vma, addr, ptep);
> +	if (pte_cont(__ptep_get(ptep))) {
> +		start = ALIGN_DOWN(start, CONT_PTE_SIZE);
> +		ptep = contpte_align_down(ptep);
> +	}
> +
> +	nr = (end - start) / PAGE_SIZE;

Hm don't love this reuse of input param.

> +	for (i = 0; i < nr; i++, ptep++, start += PAGE_SIZE)
> +		young |= __ptep_test_and_clear_young(vma, start, ptep);

Again, overall find it a bit iffy that we are essentially overloading the
code with non-contpte behaviour.

>
>  	return young;
>  }
> -EXPORT_SYMBOL_GPL(contpte_ptep_test_and_clear_young);
> +EXPORT_SYMBOL_GPL(contpte_test_and_clear_young_ptes);
>
> -int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
> -					unsigned long addr, pte_t *ptep)
> +int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
> +				unsigned long addr, pte_t *ptep,
> +				unsigned int nr)
>  {
>  	int young;
>
> -	young = contpte_ptep_test_and_clear_young(vma, addr, ptep);
> +	young = contpte_test_and_clear_young_ptes(vma, addr, ptep, nr);
>
>  	if (young) {
> +		unsigned long start = addr;
> +		unsigned long end = start + nr * PAGE_SIZE;
> +
> +		if (pte_cont(__ptep_get(ptep + nr - 1)))
> +			end = ALIGN(end, CONT_PTE_SIZE);
> +
> +		if (pte_cont(__ptep_get(ptep)))
> +			start = ALIGN_DOWN(start, CONT_PTE_SIZE);
> +
>  		/*
>  		 * See comment in __ptep_clear_flush_young(); same rationale for
>  		 * eliding the trailing DSB applies here.
>  		 */
> -		addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
> -		__flush_tlb_range_nosync(vma->vm_mm, addr, addr + CONT_PTE_SIZE,
> +		__flush_tlb_range_nosync(vma->vm_mm, start, end,
>  					 PAGE_SIZE, true, 3);

Similar comments to above.

Am curious as to Ryan's opinion.

>  	}
>
>  	return young;
>  }
> -EXPORT_SYMBOL_GPL(contpte_ptep_clear_flush_young);
> +EXPORT_SYMBOL_GPL(contpte_clear_flush_young_ptes);
>
>  void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
>  					pte_t *ptep, unsigned int nr)
> --
> 2.47.3
>


From robert.marko at sartura.hr  Mon Dec 15 03:36:25 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Mon, 15 Dec 2025 12:36:25 +0100
Subject: [PATCH 4/4] arm64: dts: microchip: add LAN969x support
In-Reply-To: <20251203-splendor-cubbyhole-eda2d6982b46@spud>
References: <20251203122313.1287950-1-robert.marko@sartura.hr>
 <20251203122313.1287950-4-robert.marko@sartura.hr> <20251203-splendor-cubbyhole-eda2d6982b46@spud>
Message-ID: <CA+HBbNGdd-u=4PtXZtirqRkFBhKwraa5gV-32QChDDjfVARPRg@mail.gmail.com>

On Wed, Dec 3, 2025 at 8:21?PM Conor Dooley <conor at kernel.org> wrote:
>
> On Wed, Dec 03, 2025 at 01:21:32PM +0100, Robert Marko wrote:
> > Add support for Microchip LAN969x switch SoC, including the EV23X71A
> > EVB board.
> >
> > Signed-off-by: Robert Marko <robert.marko at sartura.hr>
> > ---
> >  arch/arm64/boot/dts/microchip/Makefile        |   2 +
> >  .../boot/dts/microchip/lan9696-ev23x71a.dts   | 761 ++++++++++++++++++
>
> >  arch/arm64/boot/dts/microchip/lan969x.dtsi    | 482 +++++++++++
>
> The majority of devices in this file are missing soc-specific
> compatibles.

Hi,
I missed this before.

The majority of the devices are simply reused from the AT91 series, so
I thought it was not required to
update all of the bindings to add the LAN9691 compatible.

If that is required, I will do so in v2.

Regards,
Robert
-- 
Robert Marko
Staff Embedded Linux Engineer
Sartura d.d.
Lendavska ulica 16a
10000 Zagreb, Croatia
Email: robert.marko at sartura.hr
Web: www.sartura.hr


From heiko at sntech.de  Mon Dec 15 03:38:17 2025
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 15 Dec 2025 12:38:17 +0100
Subject: [PATCH v5 3/4] arm64: dts: rockchip: Add magnetometer sensor to Pinephone
 Pro
In-Reply-To: <20251124-ppp_light_accel_mag_vol-down-v5-3-f9a10a0a50eb@gmail.com>
References: <20251124-ppp_light_accel_mag_vol-down-v5-0-f9a10a0a50eb@gmail.com>
 <20251124-ppp_light_accel_mag_vol-down-v5-3-f9a10a0a50eb@gmail.com>
Message-ID: <7420522.MhkbZ0Pkbq@phil>

Am Dienstag, 25. November 2025, 04:47:02 Mitteleurop?ische Normalzeit schrieb Rudraksha Gupta via B4 Relay:

>  arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 15 +++++++++++++++
>  1 file changed, 15 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
> index f8c74b43ae9f..03721d71766c 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
> +++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
> @@ -553,6 +553,21 @@ mpu6500 at 68 {
>  	};
>  };
>  
> +&i2c4 {
> +	af8133j: compass at 1c {
> +		compatible = "voltafield,af8133j";
> +		reg = <0x1c>;
> +		reset-gpios = <&gpio1 RK_PA1 GPIO_ACTIVE_LOW>;

reset-gpios below dvdd-*

And for completeness sake, you probably want to also add a simple
pinctrl entry

> +		avdd-supply = <&vcc_3v0>;
> +		dvdd-supply = <&vcc_1v8>;
> +
> +		mount-matrix =
> +			"0", "1", "0",
> +			"-1", "0", "0",
> +			"0", "0", "1";
> +	};
> +};
> +

Thanks
Heiko




From jackabt.amazon at gmail.com  Mon Dec 15 03:43:06 2025
From: jackabt.amazon at gmail.com (Thomson, Jack)
Date: Mon, 15 Dec 2025 11:43:06 +0000
Subject: [PATCH v3 1/3] KVM: arm64: Add pre_fault_memory implementation
In-Reply-To: <86see3r7e9.wl-maz@kernel.org>
References: <20251119154910.97716-1-jackabt.amazon@gmail.com>
 <20251119154910.97716-2-jackabt.amazon@gmail.com>
 <86see3r7e9.wl-maz@kernel.org>
Message-ID: <bc93c396-78b1-491c-8857-41114aa585d7@gmail.com>



On 24/11/2025 11:34 am, Marc Zyngier wrote:
> On Wed, 19 Nov 2025 15:49:08 +0000,
> Jack Thomson <jackabt.amazon at gmail.com> wrote:
>>
>> From: Jack Thomson <jackabt at amazon.com>
>>
>> Add kvm_arch_vcpu_pre_fault_memory() for arm64. The implementation hands
>> off the stage-2 faulting logic to either gmem_abort() or
>> user_mem_abort().
>>
>> Add an optional page_size output parameter to user_mem_abort() to
>> return the VMA page size, which is needed when pre-faulting.
>>
>> Update the documentation to clarify x86 specific behaviour.
>>
>> Signed-off-by: Jack Thomson <jackabt at amazon.com>
>> ---
>>   Documentation/virt/kvm/api.rst |  3 +-
>>   arch/arm64/kvm/Kconfig         |  1 +
>>   arch/arm64/kvm/arm.c           |  1 +
>>   arch/arm64/kvm/mmu.c           | 73 ++++++++++++++++++++++++++++++++--
>>   4 files changed, 73 insertions(+), 5 deletions(-)
>>
>> diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
>> index 57061fa29e6a..30872d080511 100644
>> --- a/Documentation/virt/kvm/api.rst
>> +++ b/Documentation/virt/kvm/api.rst
>> @@ -6493,7 +6493,8 @@ Errors:
>>   KVM_PRE_FAULT_MEMORY populates KVM's stage-2 page tables used to map memory
>>   for the current vCPU state.  KVM maps memory as if the vCPU generated a
>>   stage-2 read page fault, e.g. faults in memory as needed, but doesn't break
>> -CoW.  However, KVM does not mark any newly created stage-2 PTE as Accessed.
>> +CoW.  However, on x86, KVM does not mark any newly created stage-2 PTE as
>> +Accessed.
>>   
>>   In the case of confidential VM types where there is an initial set up of
>>   private guest memory before the guest is 'finalized'/measured, this ioctl
>> diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
>> index 4f803fd1c99a..6872aaabe16c 100644
>> --- a/arch/arm64/kvm/Kconfig
>> +++ b/arch/arm64/kvm/Kconfig
>> @@ -25,6 +25,7 @@ menuconfig KVM
>>   	select HAVE_KVM_CPU_RELAX_INTERCEPT
>>   	select KVM_MMIO
>>   	select KVM_GENERIC_DIRTYLOG_READ_PROTECT
>> +	select KVM_GENERIC_PRE_FAULT_MEMORY
>>   	select VIRT_XFER_TO_GUEST_WORK
>>   	select KVM_VFIO
>>   	select HAVE_KVM_DIRTY_RING_ACQ_REL
>> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
>> index 870953b4a8a7..88c5dc2b4ee8 100644
>> --- a/arch/arm64/kvm/arm.c
>> +++ b/arch/arm64/kvm/arm.c
>> @@ -327,6 +327,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
>>   	case KVM_CAP_IRQFD_RESAMPLE:
>>   	case KVM_CAP_COUNTER_OFFSET:
>>   	case KVM_CAP_ARM_WRITABLE_IMP_ID_REGS:
>> +	case KVM_CAP_PRE_FAULT_MEMORY:
>>   		r = 1;
> 
> How does with pKVM, where the host is not in charge of dealing with
> stage-2?
For the pKVM case would
     if (vcpu_is_protected(vcpu))
         return -EPERM;
be the appropriate way to handle this?
>>   		break;
>>   	case KVM_CAP_SET_GUEST_DEBUG2:
>> diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
>> index 7cc964af8d30..cba09168fc6d 100644
>> --- a/arch/arm64/kvm/mmu.c
>> +++ b/arch/arm64/kvm/mmu.c
>> @@ -1599,8 +1599,8 @@ static int gmem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
>>   
>>   static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
>>   			  struct kvm_s2_trans *nested,
>> -			  struct kvm_memory_slot *memslot, unsigned long hva,
>> -			  bool fault_is_perm)
>> +			  struct kvm_memory_slot *memslot, long *page_size,
> 
> Why is page_size a signed type? A page size is never negative.
> 
>> +			  unsigned long hva, bool fault_is_perm)
> 
> I really wish we'd stop adding parameters to this function, as it has
> long stopped being readable. It would make a lot more sense if we
> passed a descriptor for the fault, containing the ipa, hva, memslot
> and fault type.
I found a patch series which looks to address this [1]. Would you like
this fixed for this series?

[1] 
https://lore.kernel.org/linux-arm-kernel/20250821210042.3451147-1-seanjc at google.com/
>>   {
>>   	int ret = 0;
>>   	bool topup_memcache;
>> @@ -1878,6 +1878,9 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
>>   	kvm_release_faultin_page(kvm, page, !!ret, writable);
>>   	kvm_fault_unlock(kvm);
>>   
>> +	if (page_size)
>> +		*page_size = vma_pagesize;
>> +
>>   	/* Mark the page dirty only if the fault is handled successfully */
>>   	if (writable && !ret)
>>   		mark_page_dirty_in_slot(kvm, memslot, gfn);
>> @@ -2080,8 +2083,8 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
>>   		ret = gmem_abort(vcpu, fault_ipa, nested, memslot,
>>   				 esr_fsc_is_permission_fault(esr));
>>   	else
>> -		ret = user_mem_abort(vcpu, fault_ipa, nested, memslot, hva,
>> -				     esr_fsc_is_permission_fault(esr));
>> +		ret = user_mem_abort(vcpu, fault_ipa, nested, memslot, NULL,
>> +				     hva, esr_fsc_is_permission_fault(esr));
>>   	if (ret == 0)
>>   		ret = 1;
>>   out:
>> @@ -2457,3 +2460,65 @@ void kvm_toggle_cache(struct kvm_vcpu *vcpu, bool was_enabled)
>>   
>>   	trace_kvm_toggle_cache(*vcpu_pc(vcpu), was_enabled, now_enabled);
>>   }
>> +
>> +long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,
>> +				    struct kvm_pre_fault_memory *range)
>> +{
>> +	int ret, idx;
>> +	hva_t hva;
>> +	phys_addr_t end;
>> +	struct kvm_memory_slot *memslot;
>> +	struct kvm_vcpu_fault_info stored_fault, *fault_info;
>> +
>> +	long page_size = PAGE_SIZE;
>> +	phys_addr_t ipa = range->gpa;
>> +	gfn_t gfn = gpa_to_gfn(range->gpa);
> 
> nit: Please order this in a more readable way, preferably with long
> line first.
> 
>> +
>> +	idx = srcu_read_lock(&vcpu->kvm->srcu);
> 
> ??? Aren't we already guaranteed to be under the SRCU read lock?
> 
>> +
>> +	if (ipa >= kvm_phys_size(vcpu->arch.hw_mmu)) {
>> +		ret = -ENOENT;
>> +		goto out_unlock;
>> +	}
>> +
>> +	memslot = gfn_to_memslot(vcpu->kvm, gfn);
>> +	if (!memslot) {
>> +		ret = -ENOENT;
>> +		goto out_unlock;
>> +	}
>> +
>> +	fault_info = &vcpu->arch.fault;
>> +	stored_fault = *fault_info;
> 
> If this is a vcpu ioctl, can the fault information be actually valid
> while userspace is issuing an ioctl? Wouldn't that mean that we are
> exiting to userspace in the middle of handling an exception?
> 
>> +
>> +	/* Generate a synthetic abort for the pre-fault address */
>> +	fault_info->esr_el2 = ESR_ELx_EC_DABT_LOW;
>> +	fault_info->esr_el2 &= ~ESR_ELx_ISV;
> 
> You are constructing this from scratch. How can ISV be set?
> 
>> +	fault_info->esr_el2 |= ESR_ELx_FSC_FAULT_L(KVM_PGTABLE_LAST_LEVEL);
>> +
>> +	fault_info->hpfar_el2 = HPFAR_EL2_NS |
>> +		FIELD_PREP(HPFAR_EL2_FIPA, ipa >> 12);
>> +
>> +	if (kvm_slot_has_gmem(memslot)) {
>> +		ret = gmem_abort(vcpu, ipa, NULL, memslot, false);
>> +	} else {
>> +		hva = gfn_to_hva_memslot_prot(memslot, gfn, NULL);
>> +		if (kvm_is_error_hva(hva)) {
>> +			ret = -EFAULT;
>> +			goto out;
>> +		}
>> +		ret = user_mem_abort(vcpu, ipa, NULL, memslot, &page_size, hva,
>> +				     false);
>> +	}
>> +
>> +	if (ret < 0)
>> +		goto out;
>> +
>> +	end = (range->gpa & ~(page_size - 1)) + page_size;
> 
> This suspiciously looks like one of the __ALIGN_KERNEL* macros.
> 
>> +	ret = min(range->size, end - range->gpa);
>> +
>> +out:
>> +	*fault_info = stored_fault;
>> +out_unlock:
>> +	srcu_read_unlock(&vcpu->kvm->srcu, idx);
>> +	return ret;
>> +}
> 
> Thanks,
> 
> 	M.
> 

-- 
Thanks,
Jack


From alexandru.elisei at arm.com  Mon Dec 15 03:44:05 2025
From: alexandru.elisei at arm.com (Alexandru Elisei)
Date: Mon, 15 Dec 2025 11:44:05 +0000
Subject: [PATCH v2 0/4] KVM: arm64: pKVM fixes
Message-ID: <20251215114409.212512-1-alexandru.elisei@arm.com>

v1 can be found at [1].

Similar to [2], when trying to run an unprotected VM on FVP with S1PIE enabled
and kvm-arm.mode=protected, writes to PIRE0_EL1 made by the guest in
__cpu_setup() are trapped by KVM and the BUG_ON(!r->access) is hit. That's
because HFGWTR_EL2.nPIRE0_EL1 is an inverse polarity trap and the FGT values for
the unprotected pKVM VCPU weren't being propagated from kvm_arch_vcpu_load().

Couldn't figure out how to run a protected pKVM VM, so that's untested.

New in this iteration is #2 ("KVM: arm64: Print register encoding if there's no
accessor") because I realized that the first thing I did when I hit the
BUG_ON(!r->access) (for this series and for the fix at [2]) was to print the
encoding for the register.  Thought that it might be more useful in the future
to do this by default.

Patch #4 ("KVM: arm64: Remove unused parameter in synchronize_vcpu_pstate()") is
also new - found it by code inspection while debugging something unrelated.

Changelog
=========

v1->v2:
* Rebased on top of v6.19-rc1.
* Added tags to patch #1 ("KVM: arm64: Copy FGT traps to unprotected pKVM
  VCPU on VCPU load") - thanks!
* Removed local variables 'hyp_kvm_vcpu' and 'host_vcpu' in patch #1.
* Patch #2 and #4 are new.
* Patch #3 ("KVM: arm64: Remove extra argument for
  __pvkm_host_{share,unshare}_hyp()") now properly fixes
  __pkvm_host_unshare_hyp().

[1] https://lore.kernel.org/kvmarm/20251210132102.137631-1-alexandru.elisei at arm.com/
[2] https://lore.kernel.org/all/20251112102853.47759-1-alexandru.elisei at arm.com/

Alexandru Elisei (4):
  KVM: arm64: Copy FGT traps to unprotected pKVM VCPU on VCPU load
  KVM: arm64: Print register encoding if there's no accessor
  KVM: arm64: Remove extra argument for __pvkm_host_{share,unshare}_hyp()
  KVM: arm64: Remove unused parameter in synchronize_vcpu_pstate()

 arch/arm64/kvm/hyp/include/hyp/switch.h | 2 +-
 arch/arm64/kvm/hyp/nvhe/hyp-main.c      | 3 +++
 arch/arm64/kvm/hyp/nvhe/pkvm.c          | 1 -
 arch/arm64/kvm/hyp/nvhe/switch.c        | 2 +-
 arch/arm64/kvm/hyp/vhe/switch.c         | 2 +-
 arch/arm64/kvm/mmu.c                    | 4 ++--
 arch/arm64/kvm/sys_regs.c               | 8 +++++++-
 7 files changed, 15 insertions(+), 7 deletions(-)


base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
-- 
2.52.0



From alexandru.elisei at arm.com  Mon Dec 15 03:44:07 2025
From: alexandru.elisei at arm.com (Alexandru Elisei)
Date: Mon, 15 Dec 2025 11:44:07 +0000
Subject: [PATCH v2 2/4] KVM: arm64: Print register encoding if there's no accessor
In-Reply-To: <20251215114409.212512-1-alexandru.elisei@arm.com>
References: <20251215114409.212512-1-alexandru.elisei@arm.com>
Message-ID: <20251215114409.212512-3-alexandru.elisei@arm.com>

Configuring a register trap without specifying an accessor function is
abviously a bug. Instead of calling die() when that happens, let's be a bit
more helpful and print the register encoding and kill the virtual machine
instead.

Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
---
 arch/arm64/kvm/sys_regs.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index c8fd7c6a12a1..d669f6fef177 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -4668,7 +4668,13 @@ static void perform_access(struct kvm_vcpu *vcpu,
 	 * that we don't know how to handle. This certainly qualifies
 	 * as a gross bug that should be fixed right away.
 	 */
-	BUG_ON(!r->access);
+	if (!r->access) {
+		KVM_BUG(1, vcpu->kvm,
+			"Unexpected access to register: { Op0(%2u), Op1(%2u), CRn(%2u), CRm(%2u), Op2(%2u) } (%s)",
+			params->Op0, params->Op1, params->CRn, params->CRm, params->Op2,
+			str_write_read(params->is_write));
+		return;
+	}
 
 	/* Skip instruction if instructed so */
 	if (likely(r->access(vcpu, params, r)))
-- 
2.52.0



From alexandru.elisei at arm.com  Mon Dec 15 03:44:06 2025
From: alexandru.elisei at arm.com (Alexandru Elisei)
Date: Mon, 15 Dec 2025 11:44:06 +0000
Subject: [PATCH v2 1/4] KVM: arm64: Copy FGT traps to unprotected pKVM VCPU on VCPU load
In-Reply-To: <20251215114409.212512-1-alexandru.elisei@arm.com>
References: <20251215114409.212512-1-alexandru.elisei@arm.com>
Message-ID: <20251215114409.212512-2-alexandru.elisei@arm.com>

Commit fb10ddf35c1c ("KVM: arm64: Compute per-vCPU FGTs at vcpu_load()")
introduced per-VCPU FGT traps. For an unprotected pKVM VCPU, the untrusted
host FGT configuration is copied in pkvm_vcpu_init_traps(), which is called
from __pkvm_init_vcpu(). __pkvm_init_vcpu() is called once per VCPU (when
the VCPU is first run) which means that the uninitialized, zero, values for
the FGT registers end up being used for the entire lifetime of the VCPU.
This causes both unwanted traps (for the inverse polarity trap bits) and
the guest being allowed to access registers it shouldn't.

Fix it by copying the FGT traps for unprotected pKVM VCPUs when the
untrusted host loads the VCPU.

Fixes: fb10ddf35c1c ("KVM: arm64: Compute per-vCPU FGTs at vcpu_load()")
Acked-by: Will Deacon <will at kernel.org>
Tested-by: Fuad Tabba <tabba at google.com>
Reviewed-by: Fuad Tabba <tabba at google.com>
Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
---
 arch/arm64/kvm/hyp/nvhe/hyp-main.c | 3 +++
 arch/arm64/kvm/hyp/nvhe/pkvm.c     | 1 -
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index a7c689152f68..8ffbbce5e2ed 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -180,6 +180,9 @@ static void handle___pkvm_vcpu_load(struct kvm_cpu_context *host_ctxt)
 		/* Propagate WFx trapping flags */
 		hyp_vcpu->vcpu.arch.hcr_el2 &= ~(HCR_TWE | HCR_TWI);
 		hyp_vcpu->vcpu.arch.hcr_el2 |= hcr_el2 & (HCR_TWE | HCR_TWI);
+	} else {
+		memcpy(&hyp_vcpu->vcpu.arch.fgt, hyp_vcpu->host_vcpu->arch.fgt,
+		       sizeof(hyp_vcpu->vcpu.arch.fgt));
 	}
 }
 
diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index 8911338961c5..12b2acfbcfd1 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -172,7 +172,6 @@ static int pkvm_vcpu_init_traps(struct pkvm_hyp_vcpu *hyp_vcpu)
 
 		/* Trust the host for non-protected vcpu features. */
 		vcpu->arch.hcrx_el2 = host_vcpu->arch.hcrx_el2;
-		memcpy(vcpu->arch.fgt, host_vcpu->arch.fgt, sizeof(vcpu->arch.fgt));
 		return 0;
 	}
 
-- 
2.52.0



From alexandru.elisei at arm.com  Mon Dec 15 03:44:08 2025
From: alexandru.elisei at arm.com (Alexandru Elisei)
Date: Mon, 15 Dec 2025 11:44:08 +0000
Subject: [PATCH v2 3/4] KVM: arm64: Remove extra argument for __pvkm_host_{share,unshare}_hyp()
In-Reply-To: <20251215114409.212512-1-alexandru.elisei@arm.com>
References: <20251215114409.212512-1-alexandru.elisei@arm.com>
Message-ID: <20251215114409.212512-4-alexandru.elisei@arm.com>

__pvkm_host_share_hyp() and __pkvm_host_unshare_hyp() both have one
parameter, the pfn, not two. Even though correctness isn't impacted because
the SMCCC handlers pass the first argument and ignore the second one, let's
call the functions with the proper number of arguments.

Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
---
 arch/arm64/kvm/mmu.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index 48d7c372a4cd..124404eb208d 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -497,7 +497,7 @@ static int share_pfn_hyp(u64 pfn)
 	this->count = 1;
 	rb_link_node(&this->node, parent, node);
 	rb_insert_color(&this->node, &hyp_shared_pfns);
-	ret = kvm_call_hyp_nvhe(__pkvm_host_share_hyp, pfn, 1);
+	ret = kvm_call_hyp_nvhe(__pkvm_host_share_hyp, pfn);
 unlock:
 	mutex_unlock(&hyp_shared_pfns_lock);
 
@@ -523,7 +523,7 @@ static int unshare_pfn_hyp(u64 pfn)
 
 	rb_erase(&this->node, &hyp_shared_pfns);
 	kfree(this);
-	ret = kvm_call_hyp_nvhe(__pkvm_host_unshare_hyp, pfn, 1);
+	ret = kvm_call_hyp_nvhe(__pkvm_host_unshare_hyp, pfn);
 unlock:
 	mutex_unlock(&hyp_shared_pfns_lock);
 
-- 
2.52.0



From alexandru.elisei at arm.com  Mon Dec 15 03:44:09 2025
From: alexandru.elisei at arm.com (Alexandru Elisei)
Date: Mon, 15 Dec 2025 11:44:09 +0000
Subject: [PATCH v2 4/4] KVM: arm64: Remove unused parameter in synchronize_vcpu_pstate()
In-Reply-To: <20251215114409.212512-1-alexandru.elisei@arm.com>
References: <20251215114409.212512-1-alexandru.elisei@arm.com>
Message-ID: <20251215114409.212512-5-alexandru.elisei@arm.com>

synchronize_vcpu_pstate() doesn't make use of the reference to exit_code,
remove the parameter.

Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
---
 arch/arm64/kvm/hyp/include/hyp/switch.h | 2 +-
 arch/arm64/kvm/hyp/nvhe/switch.c        | 2 +-
 arch/arm64/kvm/hyp/vhe/switch.c         | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index c5d5e5b86eaf..afecbdd3c1e9 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -854,7 +854,7 @@ static inline bool kvm_hyp_handle_exit(struct kvm_vcpu *vcpu, u64 *exit_code,
 	return false;
 }
 
-static inline void synchronize_vcpu_pstate(struct kvm_vcpu *vcpu, u64 *exit_code)
+static inline void synchronize_vcpu_pstate(struct kvm_vcpu *vcpu)
 {
 	/*
 	 * Check for the conditions of Cortex-A510's #2077057. When these occur
diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c
index d3b9ec8a7c28..779089e42681 100644
--- a/arch/arm64/kvm/hyp/nvhe/switch.c
+++ b/arch/arm64/kvm/hyp/nvhe/switch.c
@@ -211,7 +211,7 @@ static inline bool fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
 {
 	const exit_handler_fn *handlers = kvm_get_exit_handler_array(vcpu);
 
-	synchronize_vcpu_pstate(vcpu, exit_code);
+	synchronize_vcpu_pstate(vcpu);
 
 	/*
 	 * Some guests (e.g., protected VMs) are not be allowed to run in
diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c
index 9984c492305a..9db3f11a4754 100644
--- a/arch/arm64/kvm/hyp/vhe/switch.c
+++ b/arch/arm64/kvm/hyp/vhe/switch.c
@@ -536,7 +536,7 @@ static const exit_handler_fn hyp_exit_handlers[] = {
 
 static inline bool fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
 {
-	synchronize_vcpu_pstate(vcpu, exit_code);
+	synchronize_vcpu_pstate(vcpu);
 
 	/*
 	 * If we were in HYP context on entry, adjust the PSTATE view
-- 
2.52.0



From alexandru.elisei at arm.com  Mon Dec 15 03:46:38 2025
From: alexandru.elisei at arm.com (Alexandru Elisei)
Date: Mon, 15 Dec 2025 11:46:38 +0000
Subject: [RFC PATCH v6 05/35] KVM: arm64: Add KVM_CAP_ARM_SPE capability
In-Reply-To: <20251214121842.GA16796@debian-dev>
References: <20251114160717.163230-1-alexandru.elisei@arm.com>
 <20251114160717.163230-6-alexandru.elisei@arm.com>
 <20251214121842.GA16796@debian-dev>
Message-ID: <aT_1HimOyJk6H1ko@raptor>

Hi Leo,

On Sun, Dec 14, 2025 at 08:18:42PM +0800, Leo Yan wrote:
> On Fri, Nov 14, 2025 at 04:06:46PM +0000, Alexandru Elisei wrote:
> 
> [...]
> 
> > +void kvm_host_spe_init(struct arm_spe_pmu *arm_spu)
> > +{
> > +	struct arm_spu_entry *entry;
> > +
> > +	guard(mutex)(&arm_spus_lock);
> > +
> > +	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
> > +	if (!entry)
> > +		return;
> > +
> > +	entry->arm_spu = arm_spu;
> > +	list_add_tail(&entry->link, &arm_spus);
> > +
> > +	if (list_is_singular(&arm_spus))
> > +		static_branch_enable(&kvm_spe_available);
> 
> We can simply check if list_empty(&arm_spus) in kvm_supports_spe(), thus
> the static key kvm_spe_available is not needed.  Another benefit is this
> is consistent with CPU PMU's virt implementation.

Sure, that makes sense. I think I added a static key because I was thinking
about performance on hot paths, but looking at the series I forgot to actually
make use of it.

Thanks,
Alex


From heiko at sntech.de  Mon Dec 15 03:47:30 2025
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 15 Dec 2025 12:47:30 +0100
Subject: [PATCH v2] arm64: dts: rockchip: Add overlay for the PCIe slot on RK3576 EVB1
In-Reply-To: <20251202-evb1-pcie1-v2-1-810693b1b72f@gmail.com>
References: <20251202-evb1-pcie1-v2-1-810693b1b72f@gmail.com>
Message-ID: <176579924021.1404176.5086927047208846310.b4-ty@sntech.de>


On Tue, 02 Dec 2025 13:54:31 +0400, Alexey Charkov wrote:
> Rockchip RK3576 EVB1 has an onboard PCIe slot (PCIe 2.1, x4 mechanically,
> x1 electrically), but it shares pins and PHY with the only USB3 Type-A
> port.
> 
> There is a physical switch next to the slot to transfer respective pins
> connection from the USB3 port to the PCIe slot, but apart from flipping
> the switch one must also disable the USB3 host controller to prevent it
> from claiming the PHY before the PCIe slot can become usable.
> 
> [...]

Applied, thanks!

[1/1] arm64: dts: rockchip: Add overlay for the PCIe slot on RK3576 EVB1
      commit: 47b5d3697f6b9f53a0db30a99656a2f8f919e246

Best regards,
-- 
Heiko Stuebner <heiko at sntech.de>


From heiko at sntech.de  Mon Dec 15 03:47:32 2025
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 15 Dec 2025 12:47:32 +0100
Subject: (subset) [PATCH v5 0/4] Upstreaming Pinephone Pro Patches
In-Reply-To: <20251124-ppp_light_accel_mag_vol-down-v5-0-f9a10a0a50eb@gmail.com>
References: <20251124-ppp_light_accel_mag_vol-down-v5-0-f9a10a0a50eb@gmail.com>
Message-ID: <176579924023.1404176.12391640220645132527.b4-ty@sntech.de>


On Mon, 24 Nov 2025 19:46:59 -0800, Rudraksha Gupta wrote:
> Throughout the years, many have contributed to the Pinephone Pro (ppp)
> development. Unfortunately, these patches are scattered around various
> repositories in different states.
> 
> I will be attempting to upstream these patches. I will start off with the
> following small series:
> - Add light/proximity sensor support
>   - Link: https://codeberg.org/megi/linux/commit/f171bc7013bc7ad3de9af817bfbcbfa548ebe01c
> - Add accelerometer sensor support
>   - Link: https://codeberg.org/megi/linux/commit/b0bb7633e073a6760fa213b8c4a78ea2e73c7bf1
> - Add magnetometer sensor support
>   - Link: https://codeberg.org/megi/linux/commit/2f7e67f451f16eaf15b81aa1dbdf126d54927d35
> - Add mount-matrix for magnetometer
>   - Link: https://codeberg.org/megi/linux/commit/d7cd2eab931e32fa94408a96d73b4e6c0616107a
> - Fix voltage threshold for volume down key
>   - Link: https://codeberg.org/megi/linux/commit/7c496a5cc27ed4e38b740f36c2d8b2c62f80ae54
> 
> [...]

Applied, thanks!

[2/4] arm64: dts: rockchip: Add accelerometer sensor to Pinephone Pro
      commit: abd9bb7ad5bdbbf76316013cda3812c2719a0210
[4/4] arm64: dts: rockchip: Fix voltage threshold for volume keys for Pinephone Pro
      commit: 5497ffe305b2ea31ae62d4a311d7cabfb671f54a

Best regards,
-- 
Heiko Stuebner <heiko at sntech.de>


From heiko at sntech.de  Mon Dec 15 03:47:33 2025
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 15 Dec 2025 12:47:33 +0100
Subject: (subset) [PATCH v3 0/7] media: rkvdec: Add HEVC backend
In-Reply-To: <20250905161942.3759717-1-jonas@kwiboo.se>
References: <20250905161942.3759717-1-jonas@kwiboo.se>
Message-ID: <176579924020.1404176.16613704782665436214.b4-ty@sntech.de>


On Fri, 05 Sep 2025 16:19:18 +0000, Jonas Karlman wrote:
> This series add a HEVC backend to the Rockchip Video Decoder driver.
> 
> With the dependent H.264 High 10 and 4:2:2 profile support series
> finally merged there is finally time to send a v2 with minor changes and
> a suggested code style fix of this series. v1 of this series has been
> fully functional up until recent unstaging of the rkvdec driver.
> 
> [...]

Applied, thanks!

[7/7] ARM: dts: rockchip: Add vdec node for RK3288
      commit: e74470cf3101da79666f20186c9406192223e9a8

Best regards,
-- 
Heiko Stuebner <heiko at sntech.de>


From heiko at sntech.de  Mon Dec 15 03:47:31 2025
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 15 Dec 2025 12:47:31 +0100
Subject: [PATCH] arm64: dts: rockchip: enable SPDIF audio on Rock 5 ITX
In-Reply-To: <20251124183056.B853068C4E@verein.lst.de>
References: <20251124183056.B853068C4E@verein.lst.de>
Message-ID: <176579924017.1404176.3512598682044953071.b4-ty@sntech.de>


On Mon, 24 Nov 2025 19:30:56 +0100, Torsten Duwe wrote:
> The Rock5 ITX has an S/PDIF (TOSLINK) socket in its I/O-shield, whose
> TX signal is wired to GPIO4 C1. Activate SPDIF TX unit 1 and select
> the proper pinmux (M2).
> 
> 

Applied, thanks!

[1/1] arm64: dts: rockchip: enable SPDIF audio on Rock 5 ITX
      commit: 2cc30da80a28a8a5d1337230c3586eb2f9580120

Best regards,
-- 
Heiko Stuebner <heiko at sntech.de>


From maz at kernel.org  Mon Dec 15 03:52:00 2025
From: maz at kernel.org (Marc Zyngier)
Date: Mon, 15 Dec 2025 11:52:00 +0000
Subject: [PATCH 02/32] KVM: arm64: gic-v3: Switch vGIC-v3 to use generated ICH_VMCR_EL2
In-Reply-To: <20251212152215.675767-3-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	<20251212152215.675767-3-sascha.bischoff@arm.com>
Message-ID: <86ldj4nesf.wl-maz@kernel.org>

On Fri, 12 Dec 2025 15:22:35 +0000,
Sascha Bischoff <Sascha.Bischoff at arm.com> wrote:
> 
> From: Sascha Bischoff <Sascha.Bischoff at arm.com>
> 
> The VGIC-v3 code relied on hand-written definitions for the
> ICH_VMCR_EL2 register. This register, and the associated fields, is
> now generated as part of the sysreg framework. Move to using the
> generated definitions instead of the hand-written ones.
> 
> There are no functional changes as part of this change.
> 
> Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
> ---
>  arch/arm64/include/asm/sysreg.h      | 21 ---------
>  arch/arm64/kvm/hyp/vgic-v3-sr.c      | 64 ++++++++++++----------------
>  arch/arm64/kvm/vgic/vgic-v3-nested.c |  8 ++--
>  arch/arm64/kvm/vgic/vgic-v3.c        | 48 ++++++++++-----------
>  4 files changed, 54 insertions(+), 87 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index 9df51accbb025..b3b8b8cd7bf1e 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -560,7 +560,6 @@
>  #define SYS_ICC_SRE_EL2			sys_reg(3, 4, 12, 9, 5)
>  #define SYS_ICH_EISR_EL2		sys_reg(3, 4, 12, 11, 3)
>  #define SYS_ICH_ELRSR_EL2		sys_reg(3, 4, 12, 11, 5)
> -#define SYS_ICH_VMCR_EL2		sys_reg(3, 4, 12, 11, 7)
>  
>  #define __SYS__LR0_EL2(x)		sys_reg(3, 4, 12, 12, x)
>  #define SYS_ICH_LR0_EL2			__SYS__LR0_EL2(0)
> @@ -988,26 +987,6 @@
>  #define ICH_LR_PRIORITY_SHIFT	48
>  #define ICH_LR_PRIORITY_MASK	(0xffULL << ICH_LR_PRIORITY_SHIFT)
>  
> -/* ICH_VMCR_EL2 bit definitions */
> -#define ICH_VMCR_ACK_CTL_SHIFT	2
> -#define ICH_VMCR_ACK_CTL_MASK	(1 << ICH_VMCR_ACK_CTL_SHIFT)
> -#define ICH_VMCR_FIQ_EN_SHIFT	3
> -#define ICH_VMCR_FIQ_EN_MASK	(1 << ICH_VMCR_FIQ_EN_SHIFT)
> -#define ICH_VMCR_CBPR_SHIFT	4
> -#define ICH_VMCR_CBPR_MASK	(1 << ICH_VMCR_CBPR_SHIFT)
> -#define ICH_VMCR_EOIM_SHIFT	9
> -#define ICH_VMCR_EOIM_MASK	(1 << ICH_VMCR_EOIM_SHIFT)
> -#define ICH_VMCR_BPR1_SHIFT	18
> -#define ICH_VMCR_BPR1_MASK	(7 << ICH_VMCR_BPR1_SHIFT)
> -#define ICH_VMCR_BPR0_SHIFT	21
> -#define ICH_VMCR_BPR0_MASK	(7 << ICH_VMCR_BPR0_SHIFT)
> -#define ICH_VMCR_PMR_SHIFT	24
> -#define ICH_VMCR_PMR_MASK	(0xffUL << ICH_VMCR_PMR_SHIFT)
> -#define ICH_VMCR_ENG0_SHIFT	0
> -#define ICH_VMCR_ENG0_MASK	(1 << ICH_VMCR_ENG0_SHIFT)
> -#define ICH_VMCR_ENG1_SHIFT	1
> -#define ICH_VMCR_ENG1_MASK	(1 << ICH_VMCR_ENG1_SHIFT)
> -
>  /*
>   * Permission Indirection Extension (PIE) permission encodings.
>   * Encodings with the _O suffix, have overlays applied (Permission Overlay Extension).
> diff --git a/arch/arm64/kvm/hyp/vgic-v3-sr.c b/arch/arm64/kvm/hyp/vgic-v3-sr.c
> index 0b670a033fd87..24a2074f3a8cf 100644
> --- a/arch/arm64/kvm/hyp/vgic-v3-sr.c
> +++ b/arch/arm64/kvm/hyp/vgic-v3-sr.c
> @@ -569,11 +569,11 @@ static int __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu, u32 vmcr,
>  			continue;
>  
>  		/* Group-0 interrupt, but Group-0 disabled? */
> -		if (!(val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG0_MASK))
> +		if (!(val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_EL2_VENG0_MASK))
>  			continue;
>  
>  		/* Group-1 interrupt, but Group-1 disabled? */
> -		if ((val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG1_MASK))
> +		if ((val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_EL2_VENG1_MASK))
>  			continue;
>  
>  		/* Not the highest priority? */
> @@ -646,19 +646,19 @@ static int __vgic_v3_get_highest_active_priority(void)
>  
>  static unsigned int __vgic_v3_get_bpr0(u32 vmcr)
>  {
> -	return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
> +	return FIELD_GET(ICH_VMCR_EL2_VBPR0, vmcr);
>  }
>  
>  static unsigned int __vgic_v3_get_bpr1(u32 vmcr)
>  {
>  	unsigned int bpr;
>  
> -	if (vmcr & ICH_VMCR_CBPR_MASK) {
> +	if (vmcr & ICH_VMCR_EL2_VCBPR_MASK) {
>  		bpr = __vgic_v3_get_bpr0(vmcr);
>  		if (bpr < 7)
>  			bpr++;
>  	} else {
> -		bpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
> +		bpr = FIELD_GET(ICH_VMCR_EL2_VBPR1, vmcr);
>  	}
>  
>  	return bpr;
> @@ -758,7 +758,7 @@ static void __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>  	if (grp != !!(lr_val & ICH_LR_GROUP))
>  		goto spurious;
>  
> -	pmr = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
> +	pmr = FIELD_GET(ICH_VMCR_EL2_VPMR, vmcr);
>  	lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
>  	if (pmr <= lr_prio)
>  		goto spurious;
> @@ -806,7 +806,7 @@ static int ___vgic_v3_write_dir(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>  	int lr;
>  
>  	/* EOImode == 0, nothing to be done here */
> -	if (!(vmcr & ICH_VMCR_EOIM_MASK))
> +	if (!FIELD_GET(ICH_VMCR_EL2_VEOIM_MASK, vmcr))

nit: FIELD_GET() doesn't bring anything here. Similar comment applies
to most 'if (val & MASK)' constructs that get changed here.

>  		return 1;
>  
>  	/* No deactivate to be performed on an LPI */
> @@ -849,7 +849,7 @@ static void __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>  	}
>  
>  	/* EOImode == 1 and not an LPI, nothing to be done here */
> -	if ((vmcr & ICH_VMCR_EOIM_MASK) && !(vid >= VGIC_MIN_LPI))
> +	if (FIELD_GET(ICH_VMCR_EL2_VEOIM_MASK, vmcr) && !(vid >= VGIC_MIN_LPI))
>  		return;
>  
>  	lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
> @@ -865,12 +865,12 @@ static void __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>  
>  static void __vgic_v3_read_igrpen0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>  {
> -	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG0_MASK));
> +	vcpu_set_reg(vcpu, rt, !!FIELD_GET(ICH_VMCR_EL2_VENG0_MASK, vmcr));

Here, !! is actually really superfluous and makes it harder to
understand what is being done. Similar thing for IRGPEN1.

Apart from these two points, this looks OK to me.

Thanks,

	M.

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


From krzk at kernel.org  Mon Dec 15 03:59:49 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 15 Dec 2025 12:59:49 +0100
Subject: [PATCH v2 1/2] dt-bindings: arm: fsl: Add FRDM-IMX91S board
In-Reply-To: <20251215-imx91s-frdm-v2-1-87996bdaa59c@nxp.com>
References: <20251215-imx91s-frdm-v2-0-87996bdaa59c@nxp.com>
 <20251215-imx91s-frdm-v2-1-87996bdaa59c@nxp.com>
Message-ID: <31617f79-4cdb-4c8f-89f5-8ca1a3b3d054@kernel.org>

On 15/12/2025 09:42, Yanan Yang wrote:
> Add DT compatible string for NXP FRDM-IMX91S board
> 
> The FRDM-IMX91S is a low-cost, compact development board based on the
> i.MX91 applications processor. It is a cost-optimized variant of the
> FRDM-IMX91 board, with notable hardware differences requiring a separate
> DTS:
> - 512MB LPDDR4 (FRDM-IMX91 uses 1GB)
> - 256MB FlexSPI-NAND (FRDM-IMX91 uses 8GB eMMC)
> - Single GbE port (FRDM-IMX91 has dual GbE)
> - PMIC PF9453 (FRDM-IMX91 uses PCA9451A)
> 
> Signed-off-by: Yanan Yang <yanan.yang at nxp.com>
> 


Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>


Best regards,
Krzysztof


From alain.volmat at foss.st.com  Mon Dec 15 04:10:19 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Mon, 15 Dec 2025 13:10:19 +0100
Subject: [PATCH] media: stm32: dcmipp: avoid naming clock if only one is
 needed
Message-ID: <20251215-stm32-dcmipp-mp13-kclk-fix-v1-1-544a3b0cfc00@foss.st.com>

When DCMIPP requires only a single clock (kclk), avoid relying on its
name to obtain it. The introduction of MP25 support added the mclk,
which necessitated naming the first clock kclk. However, this breaks
backward compatibility with existing MP13 device trees that do not
specify clock names.

Fixes: 686f27f7ea37 ("media: stm32: dcmipp: add core support for the stm32mp25")
Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
Cc: Stable at vger.kernel.org # 6.14.x: 7f487562af49 media: stm32: dcmipp: correct ret type in dcmipp_graph_notify_bound
Cc: Stable at vger.kernel.org # 6.14.x: c715dd62da30 media: stm32: dcmipp: add has_csi2 & needs_mclk in match data
Cc: Stable at vger.kernel.org # 6.14.x:
---
 drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c
index 1b7bae3266c8..49398d077764 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c
@@ -526,7 +526,12 @@ static int dcmipp_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	kclk = devm_clk_get(&pdev->dev, "kclk");
+	/*
+	 * In case of the DCMIPP has only 1 clock (such as on MP13), the
+	 * clock might not be named.
+	 */
+	kclk = devm_clk_get(&pdev->dev,
+			    dcmipp->pipe_cfg->needs_mclk ? "kclk" : NULL);
 	if (IS_ERR(kclk))
 		return dev_err_probe(&pdev->dev, PTR_ERR(kclk),
 				     "Unable to get kclk\n");

---
base-commit: f7231cff1f3ff8259bef02dc4999bc132abf29cf
change-id: 20251215-stm32-dcmipp-mp13-kclk-fix-b36b1bf22be1

Best regards,
-- 
Alain Volmat <alain.volmat at foss.st.com>



From alain.volmat at foss.st.com  Mon Dec 15 04:19:42 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Mon, 15 Dec 2025 13:19:42 +0100
Subject: [PATCH 3/5] arm64: dts: st: add power-domains in all i2c of
 stm32mp231.dtsi
In-Reply-To: <20251215-stm32-i2c-mp2x-dt-updates-v1-0-2738a05a7af8@foss.st.com>
References: <20251215-stm32-i2c-mp2x-dt-updates-v1-0-2738a05a7af8@foss.st.com>
Message-ID: <20251215-stm32-i2c-mp2x-dt-updates-v1-3-2738a05a7af8@foss.st.com>

Add the power-domains property in all i2c instances available
on the stm32mp231.dtsi

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 arch/arm64/boot/dts/st/stm32mp231.dtsi | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm64/boot/dts/st/stm32mp231.dtsi b/arch/arm64/boot/dts/st/stm32mp231.dtsi
index 88e214d395ab..3d2a71e0341f 100644
--- a/arch/arm64/boot/dts/st/stm32mp231.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp231.dtsi
@@ -359,6 +359,7 @@ i2c1: i2c at 40120000 {
 				       <&hpdma 28 0x20 0x3021>;
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 41>;
+				power-domains = <&cluster_pd>;
 				status = "disabled";
 			};
 
@@ -375,6 +376,7 @@ i2c2: i2c at 40130000 {
 				       <&hpdma 31 0x20 0x3021>;
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 42>;
+				power-domains = <&cluster_pd>;
 				status = "disabled";
 			};
 
@@ -391,6 +393,7 @@ i2c7: i2c at 40180000 {
 				       <&hpdma 46 0x20 0x3021>;
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 47>;
+				power-domains = <&cluster_pd>;
 				status = "disabled";
 			};
 
@@ -664,6 +667,7 @@ i2c8: i2c at 46040000 {
 				       <&hpdma 169 0x20 0x3021>;
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 48>;
+				power-domains = <&cluster_pd>;
 				status = "disabled";
 			};
 

-- 
2.34.1



From alain.volmat at foss.st.com  Mon Dec 15 04:19:39 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Mon, 15 Dec 2025 13:19:39 +0100
Subject: [PATCH 0/5] i2c: st: add power-domains on stm32mp2x and enable
 i2c-analog-filter
Message-ID: <20251215-stm32-i2c-mp2x-dt-updates-v1-0-2738a05a7af8@foss.st.com>

This series add the possibility to indicate a power-domains for an i2c
instance and set the related property for all i2c instances on
stm32mp2x.
It also enables by default the i2c-analog-filter on all instances on
stm32mp2x.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
Alain Volmat (5):
      dt-bindings: i2c: st,stm32-i2c: add 'power-domains' property
      arm64: dts: st: add power-domains in all i2c of stm32mp251.dtsi
      arm64: dts: st: add power-domains in all i2c of stm32mp231.dtsi
      arm64: dts: st: enable i2c analog-filter in stm32mp251.dtsi
      arm64: dts: st: enable i2c analog-filter in stm32mp231.dtsi

 Documentation/devicetree/bindings/i2c/st,stm32-i2c.yaml |  3 +++
 arch/arm64/boot/dts/st/stm32mp231.dtsi                  |  8 ++++++++
 arch/arm64/boot/dts/st/stm32mp251.dtsi                  | 16 ++++++++++++++++
 3 files changed, 27 insertions(+)
---
base-commit: a6961e2ced5190c68acd78a7e372de07f565fcd6
change-id: 20251214-stm32-i2c-mp2x-dt-updates-e3747a0ab68c

Best regards,
-- 
Alain Volmat <alain.volmat at foss.st.com>



From alain.volmat at foss.st.com  Mon Dec 15 04:19:44 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Mon, 15 Dec 2025 13:19:44 +0100
Subject: [PATCH 5/5] arm64: dts: st: enable i2c analog-filter in
 stm32mp231.dtsi
In-Reply-To: <20251215-stm32-i2c-mp2x-dt-updates-v1-0-2738a05a7af8@foss.st.com>
References: <20251215-stm32-i2c-mp2x-dt-updates-v1-0-2738a05a7af8@foss.st.com>
Message-ID: <20251215-stm32-i2c-mp2x-dt-updates-v1-5-2738a05a7af8@foss.st.com>

By default enable the analog filter on all i2c instances on
the stm32mp23x series.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 arch/arm64/boot/dts/st/stm32mp231.dtsi | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm64/boot/dts/st/stm32mp231.dtsi b/arch/arm64/boot/dts/st/stm32mp231.dtsi
index 3d2a71e0341f..65c0a0de4141 100644
--- a/arch/arm64/boot/dts/st/stm32mp231.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp231.dtsi
@@ -360,6 +360,7 @@ i2c1: i2c at 40120000 {
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 41>;
 				power-domains = <&cluster_pd>;
+				i2c-analog-filter;
 				status = "disabled";
 			};
 
@@ -377,6 +378,7 @@ i2c2: i2c at 40130000 {
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 42>;
 				power-domains = <&cluster_pd>;
+				i2c-analog-filter;
 				status = "disabled";
 			};
 
@@ -394,6 +396,7 @@ i2c7: i2c at 40180000 {
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 47>;
 				power-domains = <&cluster_pd>;
+				i2c-analog-filter;
 				status = "disabled";
 			};
 
@@ -668,6 +671,7 @@ i2c8: i2c at 46040000 {
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 48>;
 				power-domains = <&cluster_pd>;
+				i2c-analog-filter;
 				status = "disabled";
 			};
 

-- 
2.34.1



From alain.volmat at foss.st.com  Mon Dec 15 04:19:41 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Mon, 15 Dec 2025 13:19:41 +0100
Subject: [PATCH 2/5] arm64: dts: st: add power-domains in all i2c of
 stm32mp251.dtsi
In-Reply-To: <20251215-stm32-i2c-mp2x-dt-updates-v1-0-2738a05a7af8@foss.st.com>
References: <20251215-stm32-i2c-mp2x-dt-updates-v1-0-2738a05a7af8@foss.st.com>
Message-ID: <20251215-stm32-i2c-mp2x-dt-updates-v1-2-2738a05a7af8@foss.st.com>

Add the power-domains property in all i2c instances available
on the stm32mp251.dtsi

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 arch/arm64/boot/dts/st/stm32mp251.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/boot/dts/st/stm32mp251.dtsi b/arch/arm64/boot/dts/st/stm32mp251.dtsi
index a8e6e0f77b83..4d5222698a16 100644
--- a/arch/arm64/boot/dts/st/stm32mp251.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp251.dtsi
@@ -780,6 +780,7 @@ i2c1: i2c at 40120000 {
 				       <&hpdma 28 0x20 0x3021>;
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 41>;
+				power-domains = <&CLUSTER_PD>;
 				status = "disabled";
 			};
 
@@ -796,6 +797,7 @@ i2c2: i2c at 40130000 {
 				       <&hpdma 31 0x20 0x3021>;
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 42>;
+				power-domains = <&CLUSTER_PD>;
 				status = "disabled";
 			};
 
@@ -812,6 +814,7 @@ i2c3: i2c at 40140000 {
 				       <&hpdma 34 0x20 0x3021>;
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 43>;
+				power-domains = <&CLUSTER_PD>;
 				status = "disabled";
 			};
 
@@ -828,6 +831,7 @@ i2c4: i2c at 40150000 {
 				       <&hpdma 37 0x20 0x3021>;
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 44>;
+				power-domains = <&CLUSTER_PD>;
 				status = "disabled";
 			};
 
@@ -844,6 +848,7 @@ i2c5: i2c at 40160000 {
 				       <&hpdma 40 0x20 0x3021>;
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 45>;
+				power-domains = <&CLUSTER_PD>;
 				status = "disabled";
 			};
 
@@ -860,6 +865,7 @@ i2c6: i2c at 40170000 {
 				       <&hpdma 43 0x20 0x3021>;
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 46>;
+				power-domains = <&CLUSTER_PD>;
 				status = "disabled";
 			};
 
@@ -876,6 +882,7 @@ i2c7: i2c at 40180000 {
 				       <&hpdma 46 0x20 0x3021>;
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 47>;
+				power-domains = <&CLUSTER_PD>;
 				status = "disabled";
 			};
 
@@ -1460,6 +1467,7 @@ i2c8: i2c at 46040000 {
 				       <&hpdma 169 0x20 0x3021>;
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 48>;
+				power-domains = <&CLUSTER_PD>;
 				status = "disabled";
 			};
 

-- 
2.34.1



From alain.volmat at foss.st.com  Mon Dec 15 04:19:40 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Mon, 15 Dec 2025 13:19:40 +0100
Subject: [PATCH 1/5] dt-bindings: i2c: st,stm32-i2c: add 'power-domains'
 property
In-Reply-To: <20251215-stm32-i2c-mp2x-dt-updates-v1-0-2738a05a7af8@foss.st.com>
References: <20251215-stm32-i2c-mp2x-dt-updates-v1-0-2738a05a7af8@foss.st.com>
Message-ID: <20251215-stm32-i2c-mp2x-dt-updates-v1-1-2738a05a7af8@foss.st.com>

STM32 I2C may be in a power domain which is the case for the STM32MP2x
based boards. Allow a single 'power-domains' entry for STM32 I2C.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 Documentation/devicetree/bindings/i2c/st,stm32-i2c.yaml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/i2c/st,stm32-i2c.yaml b/Documentation/devicetree/bindings/i2c/st,stm32-i2c.yaml
index 457bb0702ed9..64aaa0dfa8fa 100644
--- a/Documentation/devicetree/bindings/i2c/st,stm32-i2c.yaml
+++ b/Documentation/devicetree/bindings/i2c/st,stm32-i2c.yaml
@@ -127,6 +127,9 @@ properties:
 
   wakeup-source: true
 
+  power-domains:
+    maxItems: 1
+
   access-controllers:
     minItems: 1
     maxItems: 2

-- 
2.34.1



From alain.volmat at foss.st.com  Mon Dec 15 04:19:43 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Mon, 15 Dec 2025 13:19:43 +0100
Subject: [PATCH 4/5] arm64: dts: st: enable i2c analog-filter in
 stm32mp251.dtsi
In-Reply-To: <20251215-stm32-i2c-mp2x-dt-updates-v1-0-2738a05a7af8@foss.st.com>
References: <20251215-stm32-i2c-mp2x-dt-updates-v1-0-2738a05a7af8@foss.st.com>
Message-ID: <20251215-stm32-i2c-mp2x-dt-updates-v1-4-2738a05a7af8@foss.st.com>

By default enable the analog filter on all i2c instances on
the stm32mp25x series.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 arch/arm64/boot/dts/st/stm32mp251.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/boot/dts/st/stm32mp251.dtsi b/arch/arm64/boot/dts/st/stm32mp251.dtsi
index 4d5222698a16..a334e92cac4a 100644
--- a/arch/arm64/boot/dts/st/stm32mp251.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp251.dtsi
@@ -781,6 +781,7 @@ i2c1: i2c at 40120000 {
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 41>;
 				power-domains = <&CLUSTER_PD>;
+				i2c-analog-filter;
 				status = "disabled";
 			};
 
@@ -798,6 +799,7 @@ i2c2: i2c at 40130000 {
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 42>;
 				power-domains = <&CLUSTER_PD>;
+				i2c-analog-filter;
 				status = "disabled";
 			};
 
@@ -815,6 +817,7 @@ i2c3: i2c at 40140000 {
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 43>;
 				power-domains = <&CLUSTER_PD>;
+				i2c-analog-filter;
 				status = "disabled";
 			};
 
@@ -832,6 +835,7 @@ i2c4: i2c at 40150000 {
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 44>;
 				power-domains = <&CLUSTER_PD>;
+				i2c-analog-filter;
 				status = "disabled";
 			};
 
@@ -849,6 +853,7 @@ i2c5: i2c at 40160000 {
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 45>;
 				power-domains = <&CLUSTER_PD>;
+				i2c-analog-filter;
 				status = "disabled";
 			};
 
@@ -866,6 +871,7 @@ i2c6: i2c at 40170000 {
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 46>;
 				power-domains = <&CLUSTER_PD>;
+				i2c-analog-filter;
 				status = "disabled";
 			};
 
@@ -883,6 +889,7 @@ i2c7: i2c at 40180000 {
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 47>;
 				power-domains = <&CLUSTER_PD>;
+				i2c-analog-filter;
 				status = "disabled";
 			};
 
@@ -1468,6 +1475,7 @@ i2c8: i2c at 46040000 {
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 48>;
 				power-domains = <&CLUSTER_PD>;
+				i2c-analog-filter;
 				status = "disabled";
 			};
 

-- 
2.34.1



From ed.tsai at mediatek.com  Mon Dec 15 04:21:42 2025
From: ed.tsai at mediatek.com (ed.tsai at mediatek.com)
Date: Mon, 15 Dec 2025 20:21:42 +0800
Subject: [PATCH 1/1] PM: runtime: fix bitfield race of needs_force_resume
Message-ID: <20251215122154.3180001-1-ed.tsai@mediatek.com>

From: Ed Tsai <ed.tsai at mediatek.com>

needs_force_resume is a bitfield member in struct dev_pm_info and must
be accessed under the same lock as its bitfield group.

A real concurrent write was observed between needs_force_resume and
idle_notification; stacks below:

write needs_force_resume:
  pm_runtime_reinit+0x110/0x360
  really_probe+0xe0/0x464
  __driver_probe_device+0x9c/0x104
  driver_probe_device+0x3c/0x1a8
  __device_attach_driver+0x100/0x17c
  bus_for_each_drv+0x10c/0x168
  __device_attach_async_helper+0x7c/0xf4
  async_run_entry_fn+0x4c/0x1b4
  process_scheduled_works+0x1dc/0x498
  worker_thread+0x220/0x320
  kthread+0x150/0x27c
  ret_from_fork+0x10/0x20

write idle_notification:
  rpm_idle+0x464/0x5f8
  __pm_runtime_idle+0x7c/0x170
  scsi_autopm_put_device+0x18/0x28
  scsi_sysfs_add_sdev+0x1a0/0x1d8
  scsi_probe_and_add_lun+0xbd8/0xcd0
  __scsi_add_device+0xb8/0x11c
  ufshcd_async_scan+0xb4/0x3a4
  async_run_entry_fn+0x4c/0x1b4
  process_scheduled_works+0x1dc/0x498
  worker_thread+0x220/0x320
  kthread+0x150/0x27c
  ret_from_fork+0x10/0x20

Fixes: 89d9cec3b1e9 ("PM: runtime: Clear power.needs_force_resume in pm_runtime_reinit()")
Signed-off-by: Ed Tsai <ed.tsai at mediatek.com>
---
 drivers/base/power/runtime.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 84676cc24221..3328543b1ed8 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -1879,11 +1879,22 @@ void pm_runtime_reinit(struct device *dev)
 				pm_runtime_put(dev->parent);
 		}
 	}
+
 	/*
 	 * Clear power.needs_force_resume in case it has been set by
 	 * pm_runtime_force_suspend() invoked from a driver remove callback.
 	 */
+	if (dev->power.irq_safe)
+		spin_lock(&dev->power.lock);
+	else
+		spin_lock_irq(&dev->power.lock);
+
 	dev->power.needs_force_resume = false;
+
+	if (dev->power.irq_safe)
+		spin_unlock(&dev->power.lock);
+	else
+		spin_unlock_irq(&dev->power.lock);
 }
 
 /**
-- 
2.45.2



From arnd at arndb.de  Mon Dec 15 04:22:04 2025
From: arnd at arndb.de (Arnd Bergmann)
Date: Mon, 15 Dec 2025 13:22:04 +0100
Subject: [PATCH] arm64: perf: fix syscalltbl path base
In-Reply-To: <20251215112818.GB681384@e132581.arm.com>
References: <b2651f20-6f3a-49f5-9cd8-3fb028b2cab5@app.fastmail.com>
 <fcefc3c0-541d-40cc-84e3-9c2460308bdb@linaro.org>
 <23c07ac4-ff13-47a5-824a-e7af1d1847a3@app.fastmail.com>
 <bda366b4-fa53-4feb-a7ce-ee47cfc404b5@linaro.org>
 <20251215112818.GB681384@e132581.arm.com>
Message-ID: <0076b248-9b23-408d-9448-701df3c8d952@app.fastmail.com>

On Mon, Dec 15, 2025, at 12:28, Leo Yan wrote:
> On Mon, Dec 15, 2025 at 12:52:24PM +0200, James Clark wrote:
>> On 15/12/2025 11:33, Arnd Bergmann wrote:
>> > On Mon, Dec 15, 2025, at 09:47, James Clark wrote:
>> > > The first commit has an older fixes: tag and also fixes some other
>> > > issues so it might be better to take that one rather than this one.
>> > 
>> > I don't understand that other "fix", doesn't that just work around
>> > the arm64 build issue by adding another special case for arm64?
>> > 
>> > If we want the tools directory to have a copy of the generated unistd.h
>> > files instead of generating them, it should at the minimum be done
>> > the same across all architectures.
>> 
>> I don't think it's a special case, the other architectures already have a
>> copy of their syscall headers in tools/ don't they?
>
> Correct.  Most of architectures simply include
>
>     tools/include/uapi/asm-generic/unistd.h
>
> x86 includes their own unistd_32/64.h; only arm64 attempted to generate
> unistd_64.h dynamically, but this is problem for build dependency - when
> build perf, feature tests in tools/build/feature/ run before libperf and
> fail if unistd_64.h has not yet been generated by libperf Makefile.

Ah, I see now that arc/hexagon/loongarch/riscv just use an old
copy of the header based on the and no longer update them. I only
saw that they have the stub version but hadn't realized that they
never updated past the point where we started generating the
ones for the uapi.

Still, I would suggest using the same method across all architectures:
either we figure out how to use the generated headers on all of them
(including x86, which uses yet another method), or we just stick with
the old asm-generic/unistd.h copy and use that on arm64 as well.

     Arnd


From lorenzo.stoakes at oracle.com  Mon Dec 15 04:22:58 2025
From: lorenzo.stoakes at oracle.com (Lorenzo Stoakes)
Date: Mon, 15 Dec 2025 12:22:58 +0000
Subject: [PATCH v2 2/3] mm: rmap: support batched checks of the
 references for large folios
In-Reply-To: <545dba5e899634bc6c8ca782417d16fef3bd049f.1765439381.git.baolin.wang@linux.alibaba.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <545dba5e899634bc6c8ca782417d16fef3bd049f.1765439381.git.baolin.wang@linux.alibaba.com>
Message-ID: <4413d7f4-7734-4715-a450-2ba09db5ed22@lucifer.local>

On Thu, Dec 11, 2025 at 04:16:55PM +0800, Baolin Wang wrote:
> Currently, folio_referenced_one() always checks the young flag for each PTE
> sequentially, which is inefficient for large folios. This inefficiency is
> especially noticeable when reclaiming clean file-backed large folios, where
> folio_referenced() is observed as a significant performance hotspot.
>
> Moreover, on Arm architecture, which supports contiguous PTEs, there is already

arm64 you mean :)

> an optimization to clear the young flags for PTEs within a contiguous range.
> However, this is not sufficient. We can extend this to perform batched operations
> for the entire large folio (which might exceed the contiguous range: CONT_PTE_SIZE).
>
> Introduce a new API: clear_flush_young_ptes() to facilitate batched checking
> of the young flags and flushing TLB entries, thereby improving performance
> during large folio reclamation.
>
> Performance testing:
> Allocate 10G clean file-backed folios by mmap() in a memory cgroup, and try to
> reclaim 8G file-backed folios via the memory.reclaim interface. I can observe
> 33% performance improvement on my Arm64 32-core server (and 10%+ improvement
> on my X86 machine). Meanwhile, the hotspot folio_check_references() dropped
> from approximately 35% to around 5%.
>
> W/o patchset:
> real	0m1.518s
> user	0m0.000s
> sys	0m1.518s
>
> W/ patchset:
> real	0m1.018s
> user	0m0.000s
> sys	0m1.018s

That's nice!

Have you performed the same kind of performance testing on non-arm64? As in the
past we've had a batch optimisation go horribly wrong on non-arm64 even if it
was ok on arm64 :)

>
> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
> ---
>  arch/arm64/include/asm/pgtable.h | 11 +++++++++++
>  include/linux/mmu_notifier.h     |  9 +++++----
>  include/linux/pgtable.h          | 19 +++++++++++++++++++
>  mm/rmap.c                        | 22 ++++++++++++++++++++--
>  4 files changed, 55 insertions(+), 6 deletions(-)
>
> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
> index e03034683156..a865bd8c46a3 100644
> --- a/arch/arm64/include/asm/pgtable.h
> +++ b/arch/arm64/include/asm/pgtable.h
> @@ -1869,6 +1869,17 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
>  	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
>  }
>
> +#define clear_flush_young_ptes clear_flush_young_ptes
> +static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
> +					unsigned long addr, pte_t *ptep,
> +					unsigned int nr)
> +{
> +	if (likely(nr == 1))
> +		return __ptep_clear_flush_young(vma, addr, ptep);
> +
> +	return contpte_clear_flush_young_ptes(vma, addr, ptep, nr);
> +}

Hmm again this is a weird way of exposing a contepte-specific function, you
really need to rework that as discussed in patch 1/3.

It seems to me we can share code to avoid this.

> +
>  #define wrprotect_ptes wrprotect_ptes
>  static __always_inline void wrprotect_ptes(struct mm_struct *mm,
>  				unsigned long addr, pte_t *ptep, unsigned int nr)
> diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h
> index d1094c2d5fb6..be594b274729 100644
> --- a/include/linux/mmu_notifier.h
> +++ b/include/linux/mmu_notifier.h
> @@ -515,16 +515,17 @@ static inline void mmu_notifier_range_init_owner(
>  	range->owner = owner;
>  }
>
> -#define ptep_clear_flush_young_notify(__vma, __address, __ptep)		\
> +#define ptep_clear_flush_young_notify(__vma, __address, __ptep, __nr)	\
>  ({									\
>  	int __young;							\
>  	struct vm_area_struct *___vma = __vma;				\
>  	unsigned long ___address = __address;				\
> -	__young = ptep_clear_flush_young(___vma, ___address, __ptep);	\
> +	unsigned int ___nr = __nr;					\
> +	__young = clear_flush_young_ptes(___vma, ___address, __ptep, ___nr);	\
>  	__young |= mmu_notifier_clear_flush_young(___vma->vm_mm,	\
>  						  ___address,		\
>  						  ___address +		\
> -							PAGE_SIZE);	\
> +						nr * PAGE_SIZE);	\
>  	__young;							\
>  })

An aside, but I wonder why this needs to be a (pretty disgusting) macro?

>
> @@ -650,7 +651,7 @@ static inline void mmu_notifier_subscriptions_destroy(struct mm_struct *mm)
>
>  #define mmu_notifier_range_update_to_read_only(r) false
>
> -#define ptep_clear_flush_young_notify ptep_clear_flush_young
> +#define ptep_clear_flush_young_notify clear_flush_young_ptes
>  #define pmdp_clear_flush_young_notify pmdp_clear_flush_young
>  #define ptep_clear_young_notify ptep_test_and_clear_young
>  #define pmdp_clear_young_notify pmdp_test_and_clear_young
> diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
> index b13b6f42be3c..c7d0fd228cb7 100644
> --- a/include/linux/pgtable.h
> +++ b/include/linux/pgtable.h
> @@ -947,6 +947,25 @@ static inline void wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
>  }
>  #endif
>
> +#ifndef clear_flush_young_ptes
> +static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
> +					 unsigned long addr, pte_t *ptep,
> +					 unsigned int nr)
> +{
> +	int young = 0;
> +
> +	for (;;) {
> +		young |= ptep_clear_flush_young(vma, addr, ptep);
> +		if (--nr == 0)
> +			break;
> +		ptep++;
> +		addr += PAGE_SIZE;
> +	}
> +
> +	return young;
> +}
> +#endif
> +
>  /*
>   * On some architectures hardware does not set page access bit when accessing
>   * memory page, it is responsibility of software setting this bit. It brings
> diff --git a/mm/rmap.c b/mm/rmap.c
> index d6799afe1114..ec232165c47d 100644
> --- a/mm/rmap.c
> +++ b/mm/rmap.c
> @@ -827,9 +827,11 @@ static bool folio_referenced_one(struct folio *folio,
>  	struct folio_referenced_arg *pra = arg;
>  	DEFINE_FOLIO_VMA_WALK(pvmw, folio, vma, address, 0);
>  	int ptes = 0, referenced = 0;
> +	unsigned int nr;
>
>  	while (page_vma_mapped_walk(&pvmw)) {
>  		address = pvmw.address;
> +		nr = 1;
>
>  		if (vma->vm_flags & VM_LOCKED) {
>  			ptes++;
> @@ -874,9 +876,21 @@ static bool folio_referenced_one(struct folio *folio,
>  			if (lru_gen_look_around(&pvmw))
>  				referenced++;
>  		} else if (pvmw.pte) {
> +			if (folio_test_large(folio)) {
> +				unsigned long end_addr = pmd_addr_end(address, vma->vm_end);
> +				unsigned int max_nr = (end_addr - address) >> PAGE_SHIFT;
> +				pte_t pteval = ptep_get(pvmw.pte);
> +
> +				nr = folio_pte_batch(folio, pvmw.pte, pteval, max_nr);

I do wish we could put this fiddly logic into a helper for each place in
which we do similar kind 'end of the PTE table, maximum number we could
have' logic.

> +			}

NIT but we're running into pretty long lines here.

> +
> +			ptes += nr;
>  			if (ptep_clear_flush_young_notify(vma, address,
> -						pvmw.pte))
> +						pvmw.pte, nr))
>  				referenced++;

I find this referenced logic weird, it seems like it should be a boolean,
but this is outside the scope of your patch here :)

> +			/* Skip the batched PTEs */
> +			pvmw.pte += nr - 1;
> +			pvmw.address += (nr - 1) * PAGE_SIZE;
>  		} else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) {
>  			if (pmdp_clear_flush_young_notify(vma, address,
>  						pvmw.pmd))
> @@ -886,7 +900,11 @@ static bool folio_referenced_one(struct folio *folio,
>  			WARN_ON_ONCE(1);
>  		}
>
> -		pra->mapcount--;
> +		pra->mapcount -= nr;
> +		if (ptes == pvmw.nr_pages) {
> +			page_vma_mapped_walk_done(&pvmw);
> +			break;
> +		}
>  	}
>
>  	if (referenced)
> --
> 2.47.3
>


From alain.volmat at foss.st.com  Mon Dec 15 04:26:22 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Mon, 15 Dec 2025 13:26:22 +0100
Subject: [PATCH 3/3] arm64: dts: st: add power-domains in all spi of
 stm32mp231.dtsi
In-Reply-To: <20251215-stm32-spi-mp2x-dt-updates-v1-0-464a5fd20f13@foss.st.com>
References: <20251215-stm32-spi-mp2x-dt-updates-v1-0-464a5fd20f13@foss.st.com>
Message-ID: <20251215-stm32-spi-mp2x-dt-updates-v1-3-464a5fd20f13@foss.st.com>

Add the power-domains property in all spi instances available
on the stm32mp231.dtsi

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 arch/arm64/boot/dts/st/stm32mp231.dtsi | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/boot/dts/st/stm32mp231.dtsi b/arch/arm64/boot/dts/st/stm32mp231.dtsi
index 88e214d395ab..6b1cd5cd2cfb 100644
--- a/arch/arm64/boot/dts/st/stm32mp231.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp231.dtsi
@@ -251,6 +251,7 @@ spi2: spi at 400b0000 {
 				       <&hpdma 52 0x20 0x3021>;
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 23>;
+				power-domains = <&cluster_pd>;
 				status = "disabled";
 			};
 
@@ -281,6 +282,7 @@ spi3: spi at 400c0000 {
 				       <&hpdma 54 0x20 0x3021>;
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 24>;
+				power-domains = <&cluster_pd>;
 				status = "disabled";
 			};
 
@@ -433,6 +435,7 @@ spi1: spi at 40230000 {
 				       <&hpdma 50 0x20 0x3021>;
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 22>;
+				power-domains = <&cluster_pd>;
 				status = "disabled";
 			};
 
@@ -448,6 +451,7 @@ spi4: spi at 40240000 {
 				       <&hpdma 56 0x20 0x3021>;
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 25>;
+				power-domains = <&cluster_pd>;
 				status = "disabled";
 			};
 
@@ -463,6 +467,7 @@ spi5: spi at 40280000 {
 				       <&hpdma 58 0x20 0x3021>;
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 26>;
+				power-domains = <&cluster_pd>;
 				status = "disabled";
 			};
 

-- 
2.34.1



From alain.volmat at foss.st.com  Mon Dec 15 04:26:21 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Mon, 15 Dec 2025 13:26:21 +0100
Subject: [PATCH 2/3] arm64: dts: st: add power-domains in all spi of
 stm32mp251.dtsi
In-Reply-To: <20251215-stm32-spi-mp2x-dt-updates-v1-0-464a5fd20f13@foss.st.com>
References: <20251215-stm32-spi-mp2x-dt-updates-v1-0-464a5fd20f13@foss.st.com>
Message-ID: <20251215-stm32-spi-mp2x-dt-updates-v1-2-464a5fd20f13@foss.st.com>

Add the power-domains property in all spi instances available
on the stm32mp251.dtsi

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 arch/arm64/boot/dts/st/stm32mp251.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/boot/dts/st/stm32mp251.dtsi b/arch/arm64/boot/dts/st/stm32mp251.dtsi
index a8e6e0f77b83..64c3487b3cda 100644
--- a/arch/arm64/boot/dts/st/stm32mp251.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp251.dtsi
@@ -672,6 +672,7 @@ spi2: spi at 400b0000 {
 				       <&hpdma 52 0x20 0x3021>;
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 23>;
+				power-domains = <&CLUSTER_PD>;
 				status = "disabled";
 			};
 
@@ -702,6 +703,7 @@ spi3: spi at 400c0000 {
 				       <&hpdma 54 0x20 0x3021>;
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 24>;
+				power-domains = <&CLUSTER_PD>;
 				status = "disabled";
 			};
 
@@ -1048,6 +1050,7 @@ spi1: spi at 40230000 {
 				       <&hpdma 50 0x20 0x3021>;
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 22>;
+				power-domains = <&CLUSTER_PD>;
 				status = "disabled";
 			};
 
@@ -1063,6 +1066,7 @@ spi4: spi at 40240000 {
 				       <&hpdma 56 0x20 0x3021>;
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 25>;
+				power-domains = <&CLUSTER_PD>;
 				status = "disabled";
 			};
 
@@ -1171,6 +1175,7 @@ spi5: spi at 40280000 {
 				       <&hpdma 58 0x20 0x3021>;
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 26>;
+				power-domains = <&CLUSTER_PD>;
 				status = "disabled";
 			};
 
@@ -1380,6 +1385,7 @@ spi6: spi at 40350000 {
 				       <&hpdma 60 0x20 0x3021>;
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 27>;
+				power-domains = <&CLUSTER_PD>;
 				status = "disabled";
 			};
 
@@ -1395,6 +1401,7 @@ spi7: spi at 40360000 {
 				       <&hpdma 62 0x20 0x3021>;
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 28>;
+				power-domains = <&CLUSTER_PD>;
 				status = "disabled";
 			};
 
@@ -1444,6 +1451,7 @@ spi8: spi at 46020000 {
 				       <&hpdma 172 0x20 0x3021>;
 				dma-names = "rx", "tx";
 				access-controllers = <&rifsc 29>;
+				power-domains = <&CLUSTER_PD>;
 				status = "disabled";
 			};
 

-- 
2.34.1



From alain.volmat at foss.st.com  Mon Dec 15 04:26:19 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Mon, 15 Dec 2025 13:26:19 +0100
Subject: [PATCH 0/3] spi: st: add power-domains on stm32mp2x
Message-ID: <20251215-stm32-spi-mp2x-dt-updates-v1-0-464a5fd20f13@foss.st.com>

This series add the possibility to indicate a power-domains for an spi
instance and set the related property for all spi instances on
stm32mp2x.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
Alain Volmat (3):
      dt-bindings: spi: st,stm32-spi: add 'power-domains' property
      arm64: dts: st: add power-domains in all spi of stm32mp251.dtsi
      arm64: dts: st: add power-domains in all spi of stm32mp231.dtsi

 Documentation/devicetree/bindings/spi/st,stm32-spi.yaml | 3 +++
 arch/arm64/boot/dts/st/stm32mp231.dtsi                  | 5 +++++
 arch/arm64/boot/dts/st/stm32mp251.dtsi                  | 8 ++++++++
 3 files changed, 16 insertions(+)
---
base-commit: a6961e2ced5190c68acd78a7e372de07f565fcd6
change-id: 20251214-stm32-spi-mp2x-dt-updates-048068b7f05e

Best regards,
-- 
Alain Volmat <alain.volmat at foss.st.com>



From alain.volmat at foss.st.com  Mon Dec 15 04:26:20 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Mon, 15 Dec 2025 13:26:20 +0100
Subject: [PATCH 1/3] dt-bindings: spi: st,stm32-spi: add 'power-domains'
 property
In-Reply-To: <20251215-stm32-spi-mp2x-dt-updates-v1-0-464a5fd20f13@foss.st.com>
References: <20251215-stm32-spi-mp2x-dt-updates-v1-0-464a5fd20f13@foss.st.com>
Message-ID: <20251215-stm32-spi-mp2x-dt-updates-v1-1-464a5fd20f13@foss.st.com>

STM32 SPI may be in a power domain which is the case for the STM32MP2x
based boards. Allow a single 'power-domains' entry for STM32 SPI.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 Documentation/devicetree/bindings/spi/st,stm32-spi.yaml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/spi/st,stm32-spi.yaml b/Documentation/devicetree/bindings/spi/st,stm32-spi.yaml
index ca880a226afa..472e92974714 100644
--- a/Documentation/devicetree/bindings/spi/st,stm32-spi.yaml
+++ b/Documentation/devicetree/bindings/spi/st,stm32-spi.yaml
@@ -96,6 +96,9 @@ properties:
       The region should be defined as child node of the AHB SRAM node
       as per the generic bindings in Documentation/devicetree/bindings/sram/sram.yaml
 
+  power-domains:
+    maxItems: 1
+
   access-controllers:
     minItems: 1
     maxItems: 2

-- 
2.34.1



From nicolas.frattaroli at collabora.com  Mon Dec 15 04:29:28 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Mon, 15 Dec 2025 13:29:28 +0100
Subject: [PATCH v2 0/4] ROCK 4D audio enablement
Message-ID: <20251215-rock4d-audio-v2-0-82a61de39b4c@collabora.com>

The ROCK 4D uses an ADC input to distinguish between a headphone (i.e.,
no mic) and a headset (i.e., with mic). After some searching, it appears
that the closest we can get to modelling this is by sending a particular
switch input event.

So this series modifies the adc-keys bindings, extends the adc-keys
driver to allow sending other input types as well, and then adds the
analog audio nodes to ROCK 4D's device tree.

It should be noted that analog capture from the TRRS jack currently
results in completely digitally silent audio for me, i.e. no data other
than 0xFF. There's a few reasons why this could happen, chief among them
that my SAI driver is broken or that the ES8328 codec driver is once
again broken. The DAPM routes when graphed out look fine though. So the
DTS part is correct, and I can fix the broken capture in a separate
follow-up patch that doesn't have to include DT people.

Another possibility is that my phone headset, despite being 4 rings and
having a little pin hole at the back of the volume doodad, does not
actually have a microphone, but in that case I'd still expect some noise
in the PCM. Maybe it's just shy.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
Changes in v2:
- Drop HDMI audio patch, as it was already merged.
- adc-keys: rename "keycode" to "code".
- adc-keys: make the keycode (now "code") local a u32 instead of an int
- adc-keys: only allow EV_KEY and EV_SW for now. Rename patch
  accordingly.
- adc-keys: Add another patch to rework probe function error logging.
- Link to v1: https://lore.kernel.org/r/20250630-rock4d-audio-v1-0-0b3c8e8fda9c at collabora.com

---
Nicolas Frattaroli (4):
      dt-bindings: input: adc-keys: allow linux,input-type property
      Input: adc-keys - support EV_SW as well, not just EV_KEY.
      Input: adc-keys - Use dev_err_probe in probe function
      arm64: dts: rockchip: add analog audio to ROCK 4D

 .../devicetree/bindings/input/adc-keys.yaml        |  3 +
 arch/arm64/boot/dts/rockchip/rk3576-rock-4d.dts    | 90 ++++++++++++++++++++++
 drivers/input/keyboard/adc-keys.c                  | 88 ++++++++++-----------
 3 files changed, 138 insertions(+), 43 deletions(-)
---
base-commit: 3e7f562e20ee87a25e104ef4fce557d39d62fa85
change-id: 20250627-rock4d-audio-cfc07f168a08

Best regards,
-- 
Nicolas Frattaroli <nicolas.frattaroli at collabora.com>



From nicolas.frattaroli at collabora.com  Mon Dec 15 04:29:30 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Mon, 15 Dec 2025 13:29:30 +0100
Subject: [PATCH v2 2/4] Input: adc-keys - support EV_SW as well, not just
 EV_KEY.
In-Reply-To: <20251215-rock4d-audio-v2-0-82a61de39b4c@collabora.com>
References: <20251215-rock4d-audio-v2-0-82a61de39b4c@collabora.com>
Message-ID: <20251215-rock4d-audio-v2-2-82a61de39b4c@collabora.com>

Instead of doing something like what gpio-keys is doing, adc-keys
hardcodes that all keycodes must be of type EV_KEY.

This limits the usefulness of adc-keys, and overcomplicates the code
with manual bit-setting logic.

Instead, refactor the code to read the linux,input-type fwnode property,
and get rid of the custom bit setting logic, replacing it with
input_set_capability instead. input_report_key is replaced with
input_event, which allows us to explicitly pass the type.

Only EV_KEY and EV_SW is allowed at this stage.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/input/keyboard/adc-keys.c | 37 +++++++++++++++++++++++++------------
 1 file changed, 25 insertions(+), 12 deletions(-)

diff --git a/drivers/input/keyboard/adc-keys.c b/drivers/input/keyboard/adc-keys.c
index f1753207429d..62376f34f7d0 100644
--- a/drivers/input/keyboard/adc-keys.c
+++ b/drivers/input/keyboard/adc-keys.c
@@ -18,13 +18,15 @@
 
 struct adc_keys_button {
 	u32 voltage;
-	u32 keycode;
+	u32 code;
+	u32 type;
 };
 
 struct adc_keys_state {
 	struct iio_channel *channel;
 	u32 num_keys;
 	u32 last_key;
+	u32 last_type;
 	u32 keyup_voltage;
 	const struct adc_keys_button *map;
 };
@@ -34,7 +36,8 @@ static void adc_keys_poll(struct input_dev *input)
 	struct adc_keys_state *st = input_get_drvdata(input);
 	int i, value, ret;
 	u32 diff, closest = 0xffffffff;
-	int keycode = 0;
+	u32 code = 0;
+	u32 type = EV_KEY;
 
 	ret = iio_read_channel_processed(st->channel, &value);
 	if (unlikely(ret < 0)) {
@@ -45,22 +48,24 @@ static void adc_keys_poll(struct input_dev *input)
 			diff = abs(st->map[i].voltage - value);
 			if (diff < closest) {
 				closest = diff;
-				keycode = st->map[i].keycode;
+				code = st->map[i].code;
+				type = st->map[i].type;
 			}
 		}
 	}
 
 	if (abs(st->keyup_voltage - value) < closest)
-		keycode = 0;
+		code = 0;
 
-	if (st->last_key && st->last_key != keycode)
-		input_report_key(input, st->last_key, 0);
+	if (st->last_key && st->last_key != code)
+		input_event(input, st->last_type, st->last_key, 0);
 
-	if (keycode)
-		input_report_key(input, keycode, 1);
+	if (code)
+		input_event(input, type, code, 1);
 
 	input_sync(input);
-	st->last_key = keycode;
+	st->last_key = code;
+	st->last_type = type;
 }
 
 static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st)
@@ -88,11 +93,20 @@ static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st)
 		map[i].voltage /= 1000;
 
 		if (fwnode_property_read_u32(child, "linux,code",
-					     &map[i].keycode)) {
+					     &map[i].code)) {
 			dev_err(dev, "Key with invalid or missing linux,code\n");
 			return -EINVAL;
 		}
 
+		if (fwnode_property_read_u32(child, "linux,input-type",
+					     &map[i].type))
+			map[i].type = EV_KEY;
+
+		if (map[i].type != EV_KEY && map[i].type != EV_SW)
+			return dev_err_probe(dev, -EINVAL,
+					     "Invalid linux,input-type: 0x%x\n",
+					     map[i].type);
+
 		i++;
 	}
 
@@ -156,9 +170,8 @@ static int adc_keys_probe(struct platform_device *pdev)
 	input->id.product = 0x0001;
 	input->id.version = 0x0100;
 
-	__set_bit(EV_KEY, input->evbit);
 	for (i = 0; i < st->num_keys; i++)
-		__set_bit(st->map[i].keycode, input->keybit);
+		input_set_capability(input, st->map[i].type, st->map[i].code);
 
 	if (device_property_read_bool(dev, "autorepeat"))
 		__set_bit(EV_REP, input->evbit);

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Mon Dec 15 04:29:29 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Mon, 15 Dec 2025 13:29:29 +0100
Subject: [PATCH v2 1/4] dt-bindings: input: adc-keys: allow
 linux,input-type property
In-Reply-To: <20251215-rock4d-audio-v2-0-82a61de39b4c@collabora.com>
References: <20251215-rock4d-audio-v2-0-82a61de39b4c@collabora.com>
Message-ID: <20251215-rock4d-audio-v2-1-82a61de39b4c@collabora.com>

adc-keys, unlike gpio-keys, does not allow linux,input-type as a valid
property. This makes it impossible to model devices that have ADC inputs
that should generate switch events.

Add the property to the binding with the same default as gpio-keys.

Reviewed-by: Heiko Stuebner <heiko at sntech.de>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 Documentation/devicetree/bindings/input/adc-keys.yaml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/input/adc-keys.yaml b/Documentation/devicetree/bindings/input/adc-keys.yaml
index 7aa078dead37..e372ebc23d16 100644
--- a/Documentation/devicetree/bindings/input/adc-keys.yaml
+++ b/Documentation/devicetree/bindings/input/adc-keys.yaml
@@ -42,6 +42,9 @@ patternProperties:
 
       linux,code: true
 
+      linux,input-type:
+        default: 1  # EV_KEY
+
       press-threshold-microvolt:
         description:
           Voltage above or equal to which this key is considered pressed. No

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Mon Dec 15 04:29:31 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Mon, 15 Dec 2025 13:29:31 +0100
Subject: [PATCH v2 3/4] Input: adc-keys - Use dev_err_probe in probe
 function
In-Reply-To: <20251215-rock4d-audio-v2-0-82a61de39b4c@collabora.com>
References: <20251215-rock4d-audio-v2-0-82a61de39b4c@collabora.com>
Message-ID: <20251215-rock4d-audio-v2-3-82a61de39b4c@collabora.com>

Rework the probe function, and functions called by the probe function,
to use dev_err_probe for error logging.

While at it, also do some minor style cleanups, like not error logging
on -ENOMEM and using ! instead of == 0.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/input/keyboard/adc-keys.c | 53 ++++++++++++++++-----------------------
 1 file changed, 21 insertions(+), 32 deletions(-)

diff --git a/drivers/input/keyboard/adc-keys.c b/drivers/input/keyboard/adc-keys.c
index 62376f34f7d0..6f2ddcecea99 100644
--- a/drivers/input/keyboard/adc-keys.c
+++ b/drivers/input/keyboard/adc-keys.c
@@ -74,10 +74,8 @@ static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st)
 	int i;
 
 	st->num_keys = device_get_child_node_count(dev);
-	if (st->num_keys == 0) {
-		dev_err(dev, "keymap is missing\n");
-		return -EINVAL;
-	}
+	if (!st->num_keys)
+		return dev_err_probe(dev, -EINVAL, "keymap is missing\n");
 
 	map = devm_kmalloc_array(dev, st->num_keys, sizeof(*map), GFP_KERNEL);
 	if (!map)
@@ -86,17 +84,16 @@ static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st)
 	i = 0;
 	device_for_each_child_node_scoped(dev, child) {
 		if (fwnode_property_read_u32(child, "press-threshold-microvolt",
-					     &map[i].voltage)) {
-			dev_err(dev, "Key with invalid or missing voltage\n");
-			return -EINVAL;
-		}
+					     &map[i].voltage))
+			return dev_err_probe(dev, -EINVAL,
+					     "Key with invalid or missing voltage\n");
+
 		map[i].voltage /= 1000;
 
 		if (fwnode_property_read_u32(child, "linux,code",
-					     &map[i].code)) {
-			dev_err(dev, "Key with invalid or missing linux,code\n");
-			return -EINVAL;
-		}
+					     &map[i].code))
+			return dev_err_probe(dev, -EINVAL,
+					     "Key with invalid or missing linux,code\n");
 
 		if (fwnode_property_read_u32(child, "linux,input-type",
 					     &map[i].type))
@@ -129,7 +126,8 @@ static int adc_keys_probe(struct platform_device *pdev)
 
 	st->channel = devm_iio_channel_get(dev, "buttons");
 	if (IS_ERR(st->channel))
-		return PTR_ERR(st->channel);
+		return dev_err_probe(dev, PTR_ERR(st->channel),
+				     "Could not get iio channel\n");
 
 	if (!st->channel->indio_dev)
 		return -ENXIO;
@@ -138,16 +136,13 @@ static int adc_keys_probe(struct platform_device *pdev)
 	if (error < 0)
 		return error;
 
-	if (type != IIO_VOLTAGE) {
-		dev_err(dev, "Incompatible channel type %d\n", type);
-		return -EINVAL;
-	}
+	if (type != IIO_VOLTAGE)
+		return dev_err_probe(dev, -EINVAL, "Incompatible channel type %d\n", type);
 
 	if (device_property_read_u32(dev, "keyup-threshold-microvolt",
-				     &st->keyup_voltage)) {
-		dev_err(dev, "Invalid or missing keyup voltage\n");
-		return -EINVAL;
-	}
+				     &st->keyup_voltage))
+		return dev_err_probe(dev, -EINVAL, "Invalid or missing keyup voltage\n");
+
 	st->keyup_voltage /= 1000;
 
 	error = adc_keys_load_keymap(dev, st);
@@ -155,10 +150,8 @@ static int adc_keys_probe(struct platform_device *pdev)
 		return error;
 
 	input = devm_input_allocate_device(dev);
-	if (!input) {
-		dev_err(dev, "failed to allocate input device\n");
+	if (!input)
 		return -ENOMEM;
-	}
 
 	input_set_drvdata(input, st);
 
@@ -178,19 +171,15 @@ static int adc_keys_probe(struct platform_device *pdev)
 
 
 	error = input_setup_polling(input, adc_keys_poll);
-	if (error) {
-		dev_err(dev, "Unable to set up polling: %d\n", error);
-		return error;
-	}
+	if (error)
+		return dev_err_probe(dev, error, "Unable to set up polling\n");
 
 	if (!device_property_read_u32(dev, "poll-interval", &value))
 		input_set_poll_interval(input, value);
 
 	error = input_register_device(input);
-	if (error) {
-		dev_err(dev, "Unable to register input device: %d\n", error);
-		return error;
-	}
+	if (error)
+		return dev_err_probe(dev, error, "Unable to register input device\n");
 
 	return 0;
 }

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Mon Dec 15 04:29:32 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Mon, 15 Dec 2025 13:29:32 +0100
Subject: [PATCH v2 4/4] arm64: dts: rockchip: add analog audio to ROCK 4D
In-Reply-To: <20251215-rock4d-audio-v2-0-82a61de39b4c@collabora.com>
References: <20251215-rock4d-audio-v2-0-82a61de39b4c@collabora.com>
Message-ID: <20251215-rock4d-audio-v2-4-82a61de39b4c@collabora.com>

The RADXA ROCK 4D, like many other Rockchip-based boards, uses an ES8388
analog audio codec. On the production version of the board, the codec's
LOUT1 and ROUT1 pins are tied to the headphone jack, whereas pins LOUT2
and ROUT2 lead to a non-populated speaker amplifier that itself leads to
a non-populated speaker jack. The schematic is still haunted by the
ghosts of those symbols, but it clearly marks them as "NC".

The 3.5mm TRRS jack has its microphone ring (and ground ring) wired to
the codec's LINPUT1 and RINPUT1 pins for differential signalling.

Furthermore, it uses the SoCs ADC to detect whether the inserted cable
is of headphones (i.e., no microphone), or a headset (i.e., with
microphone). The way this is done is that the ADC input taps the output
of a 100K/100K resistor divider that divides the microphone ring pin
that's pulled up to 3.3V.

There is no ADC level difference between a completely empty jack and one
with a set of headphones (i.e., ones that don't have a microphone)
connected. Consequently headphone insertion detection isn't something
that can be done.

Add the necessary codec and audio card nodes. The non-populated parts,
i.e. LOUT2 and ROUT2, are not modeled at all, as they are not present on
the hardware.

Also, add an adc-keys node for the headset detection, which uses an
input type of EV_SW with the SW_MICROPHONE_INSERT keycode. Below the
220mV pressed voltage level of our SW_MICROPHONE_INSERT switch, we also
define a button that emits a KEY_RESERVED code, which is there to model
this part of the voltage range as not just being extra legroom for the
button above it, but actually a state that is encountered in the real
world, and should be recognised as a valid state for the ADC range to be
in so that no "closer" ADC button is chosen.

Tested-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 arch/arm64/boot/dts/rockchip/rk3576-rock-4d.dts | 90 +++++++++++++++++++++++++
 1 file changed, 90 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3576-rock-4d.dts b/arch/arm64/boot/dts/rockchip/rk3576-rock-4d.dts
index 7023dc326d0e..d86fe2951da6 100644
--- a/arch/arm64/boot/dts/rockchip/rk3576-rock-4d.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3576-rock-4d.dts
@@ -6,6 +6,7 @@
 /dts-v1/;
 
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
 #include <dt-bindings/leds/common.h>
 #include <dt-bindings/pinctrl/rockchip.h>
 #include <dt-bindings/pwm/pwm.h>
@@ -37,6 +38,31 @@ hdmi_con_in: endpoint {
 		};
 	};
 
+	es8388_sound: es8388-sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,format = "i2s";
+		simple-audio-card,mclk-fs = <256>;
+		simple-audio-card,name = "On-board Analog ES8388";
+		simple-audio-card,widgets = "Microphone", "Headphone Mic",
+					    "Headphone", "Headphone";
+		simple-audio-card,routing = "Headphone", "LOUT1",
+					    "Headphone", "ROUT1",
+					    "Left PGA Mux", "Differential Mux",
+					    "Differential Mux", "LINPUT1",
+					    "Differential Mux", "RINPUT1",
+					    "LINPUT1", "Headphone Mic",
+					    "RINPUT1", "Headphone Mic";
+
+		simple-audio-card,cpu {
+			sound-dai = <&sai1>;
+		};
+
+		simple-audio-card,codec {
+			sound-dai = <&es8388>;
+			system-clock-frequency = <12288000>;
+		};
+	};
+
 	rfkill {
 		compatible = "rfkill-gpio";
 		pinctrl-names = "default";
@@ -65,6 +91,37 @@ user-led {
 		};
 	};
 
+	saradc_keys: adc-keys {
+		compatible = "adc-keys";
+		io-channels = <&saradc 3>;
+		io-channel-names = "buttons";
+		keyup-threshold-microvolt = <3000000>;
+		poll-interval = <100>;
+
+		/*
+		 * During insertion and removal of a regular set of headphones,
+		 * i.e. one without a microphone, the voltage level briefly
+		 * dips below the 220mV of the headset connection switch.
+		 * By having a button definition with a KEY_RESERVED signal
+		 * between 0 to 220, we ensure no driver implementation thinks
+		 * that the closest thing to 0V is 220mV so clearly there must
+		 * be a headset connected.
+		 */
+
+		button-headset-disconnected {
+			label = "Headset Microphone Disconnected";
+			linux,code = <KEY_RESERVED>;
+			press-threshold-microvolt = <0>;
+		};
+
+		button-headset-connected {
+			label = "Headset Microphone Connected";
+			linux,code = <SW_MICROPHONE_INSERT>;
+			linux,input-type = <EV_SW>;
+			press-threshold-microvolt = <220000>;
+		};
+	};
+
 	vcc_5v0_dcin: regulator-vcc-5v0-dcin {
 		compatible = "regulator-fixed";
 		regulator-always-on;
@@ -682,6 +739,25 @@ hym8563: rtc at 51 {
 	};
 };
 
+&i2c3 {
+	status = "okay";
+
+	es8388: audio-codec at 10 {
+		compatible = "everest,es8388", "everest,es8328";
+		reg = <0x10>;
+		clocks = <&cru CLK_SAI1_MCLKOUT_TO_IO>;
+		AVDD-supply = <&vcca_3v3_s0>;
+		DVDD-supply = <&vcc_3v3_s0>;
+		HPVDD-supply = <&vcca_3v3_s0>;
+		PVDD-supply = <&vcc_3v3_s0>;
+		assigned-clocks = <&cru CLK_SAI1_MCLKOUT_TO_IO>;
+		assigned-clock-rates = <12288000>;
+		#sound-dai-cells = <0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&sai1m0_mclk>;
+	};
+};
+
 &mdio0 {
 	rgmii_phy0: ethernet-phy at 1 {
 		compatible = "ethernet-phy-id001c.c916";
@@ -756,10 +832,24 @@ wifi_en_h: wifi-en-h {
 	};
 };
 
+&sai1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&sai1m0_lrck
+		     &sai1m0_sclk
+		     &sai1m0_sdi0
+		     &sai1m0_sdo0>;
+	status = "okay";
+};
+
 &sai6 {
 	status = "okay";
 };
 
+&saradc {
+	vref-supply = <&vcca1v8_pldo2_s0>;
+	status = "okay";
+};
+
 &sdmmc {
 	bus-width = <4>;
 	cap-mmc-highspeed;

-- 
2.52.0



From nicolas.ferre at microchip.com  Mon Dec 15 04:32:03 2025
From: nicolas.ferre at microchip.com (Nicolas Ferre)
Date: Mon, 15 Dec 2025 13:32:03 +0100
Subject: [PATCH 4/4] arm64: dts: microchip: add LAN969x support
In-Reply-To: <CA+HBbNGdd-u=4PtXZtirqRkFBhKwraa5gV-32QChDDjfVARPRg@mail.gmail.com>
References: <20251203122313.1287950-1-robert.marko@sartura.hr>
 <20251203122313.1287950-4-robert.marko@sartura.hr>
 <20251203-splendor-cubbyhole-eda2d6982b46@spud>
 <CA+HBbNGdd-u=4PtXZtirqRkFBhKwraa5gV-32QChDDjfVARPRg@mail.gmail.com>
Message-ID: <173412c8-c2fb-4c38-8de7-5b1c2eebdbf9@microchip.com>

Robert,

On 15/12/2025 at 12:36, Robert Marko wrote:
> On Wed, Dec 3, 2025 at 8:21?PM Conor Dooley <conor at kernel.org> wrote:
>>
>> On Wed, Dec 03, 2025 at 01:21:32PM +0100, Robert Marko wrote:
>>> Add support for Microchip LAN969x switch SoC, including the EV23X71A
>>> EVB board.
>>>
>>> Signed-off-by: Robert Marko <robert.marko at sartura.hr>
>>> ---
>>>   arch/arm64/boot/dts/microchip/Makefile        |   2 +
>>>   .../boot/dts/microchip/lan9696-ev23x71a.dts   | 761 ++++++++++++++++++
>>
>>>   arch/arm64/boot/dts/microchip/lan969x.dtsi    | 482 +++++++++++
>>
>> The majority of devices in this file are missing soc-specific
>> compatibles.
> 
> Hi,
> I missed this before.
> 
> The majority of the devices are simply reused from the AT91 series, so
> I thought it was not required to
> update all of the bindings to add the LAN9691 compatible.
> 
> If that is required, I will do so in v2.
Well, history told us it was better (in addition to be required by DT 
best practices). Indeed, even if the same IP block is used, sometimes 
integration subtleties pay game with us and a dedicated compatible 
string saves us.

Regards,
   Nicolas


From lorenzo.stoakes at oracle.com  Mon Dec 15 04:38:30 2025
From: lorenzo.stoakes at oracle.com (Lorenzo Stoakes)
Date: Mon, 15 Dec 2025 12:38:30 +0000
Subject: [PATCH v2 3/3] mm: rmap: support batched unmapping for file
 large folios
In-Reply-To: <af330c9ea188bd0f28189b1e6e5803f6de9d2abe.1765439381.git.baolin.wang@linux.alibaba.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <af330c9ea188bd0f28189b1e6e5803f6de9d2abe.1765439381.git.baolin.wang@linux.alibaba.com>
Message-ID: <70d1dedc-b4fc-4eb6-baf6-9e54b6a62249@lucifer.local>

On Thu, Dec 11, 2025 at 04:16:56PM +0800, Baolin Wang wrote:
> Similar to folio_referenced_one(), we can apply batched unmapping for file
> large folios to optimize the performance of file folios reclamation.
>
> Performance testing:
> Allocate 10G clean file-backed folios by mmap() in a memory cgroup, and try to
> reclaim 8G file-backed folios via the memory.reclaim interface. I can observe
> 75% performance improvement on my Arm64 32-core server.

Again, you must test on non-arm64 architectures and report the numbers for this
also.

>
> W/o patch:
> real    0m1.018s
> user    0m0.000s
> sys     0m1.018s
>
> W/ patch:
> real	0m0.249s
> user	0m0.000s
> sys	0m0.249s
>
> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
> ---
>  mm/rmap.c | 7 ++++---
>  1 file changed, 4 insertions(+), 3 deletions(-)
>
> diff --git a/mm/rmap.c b/mm/rmap.c
> index ec232165c47d..4c9d5777c8da 100644
> --- a/mm/rmap.c
> +++ b/mm/rmap.c
> @@ -1855,9 +1855,10 @@ static inline unsigned int folio_unmap_pte_batch(struct folio *folio,
>  	end_addr = pmd_addr_end(addr, vma->vm_end);
>  	max_nr = (end_addr - addr) >> PAGE_SHIFT;
>
> -	/* We only support lazyfree batching for now ... */
> -	if (!folio_test_anon(folio) || folio_test_swapbacked(folio))
> +	/* We only support lazyfree or file folios batching for now ... */
> +	if (folio_test_anon(folio) && folio_test_swapbacked(folio))

Why is it now ok to support file-backed batched unmapping when it wasn't in
Barry's series (see [0])? You don't seem to be justifying this?

[0]:https://lore.kernel.org/all/20250214093015.51024-4-21cnbao at gmail.com/T/#u


>  		return 1;
> +
>  	if (pte_unused(pte))
>  		return 1;
>
> @@ -2223,7 +2224,7 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
>  			 *
>  			 * See Documentation/mm/mmu_notifier.rst
>  			 */
> -			dec_mm_counter(mm, mm_counter_file(folio));
> +			add_mm_counter(mm, mm_counter_file(folio), -nr_pages);

Was this just a bug before?

>  		}
>  discard:
>  		if (unlikely(folio_test_hugetlb(folio))) {
> --
> 2.47.3
>

Thanks, Lorenzo


From Sascha.Bischoff at arm.com  Mon Dec 15 05:01:59 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Mon, 15 Dec 2025 13:01:59 +0000
Subject: [PATCH 31/32] Documentation: KVM: Introduce documentation for
 VGICv5
In-Reply-To: <CAFEAcA-fgWOUu7yWfGNGyy0BwTPxH1ht+E5SQ4tjJf3U=w7e6w@mail.gmail.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	 <20251212152215.675767-32-sascha.bischoff@arm.com>
	 <CAFEAcA-fgWOUu7yWfGNGyy0BwTPxH1ht+E5SQ4tjJf3U=w7e6w@mail.gmail.com>
Message-ID: <44e57b5d9192569128aada07e27e5ca4005bc6a7.camel@arm.com>

On Mon, 2025-12-15 at 09:56 +0000, Peter Maydell wrote:
> On Fri, 12 Dec 2025 at 15:24, Sascha Bischoff
> <Sascha.Bischoff at arm.com> wrote:
> > 
> > Now that it is possible to create a VGICv5 device, provide initial
> > documentation for it. At this stage, there is little to document.
> 
> Is userspace access to read/write the GICv5 register state also
> in the "will be added a in future patchseries" category ?
> 
> thanks
> -- PMM

Hi Peter,

That was the intent for now. Given that the order in which state is
read/written as part of, e.g., saving or restoring a guest matters
greatly, I am reluctant to post the userspace access patches piecemeal
(sys regs, IRS MMIO region, IRS SPI IST, IRS LPI IST, ITS MMIO region).
Also, this series is already rather lengthy, so I don't particularly
want to drag more things in.

FWIW, the current design for userspace access to the GICv5 system
registers looks precisely like what currently exists for GICv3 using
KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS, and reuses this same ioctl.

Thanks,
Sascha

From robin.murphy at arm.com  Mon Dec 15 05:04:57 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Mon, 15 Dec 2025 13:04:57 +0000
Subject: [PATCH 0/3] perf/arm_dsu: Support newer DSUs
Message-ID: <cover.1765802897.git.robin.murphy@arm.com>

Hi all,

DSU-110 and 120 have been out for a while, and although they continue
to share the same basic system register interface, they have subtle
functional changes that require a little attention to support properly.
And while DSUs still aren't widely exposed in current systems, at least
some folks do apparently care.

Sanity-checked on DSU-120 in FPGA, and original DSU on Rockchip RK3566
with TF-A hacked to set ACTLR_EL3.CLUSTERPMUEN.

Cheers,
Robin.


Robin Murphy (3):
  perf/arm_dsu: Support DSU-110
  perf/arm_dsu: Support DSU-120
  perf/arm_dsu: Allow standard cycles events

 drivers/perf/arm_dsu_pmu.c | 37 +++++++++++++++++++++++--------------
 1 file changed, 23 insertions(+), 14 deletions(-)

-- 
2.39.2.101.g768bb238c484.dirty



From robin.murphy at arm.com  Mon Dec 15 05:04:58 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Mon, 15 Dec 2025 13:04:58 +0000
Subject: [PATCH 1/3] perf/arm_dsu: Support DSU-110
In-Reply-To: <cover.1765802897.git.robin.murphy@arm.com>
References: <cover.1765802897.git.robin.murphy@arm.com>
Message-ID: <5aa884a673f7a53f4793176662e64e4851e394d8.1765802897.git.robin.murphy@arm.com>

DSU-110 sneakily made all the event counters 64-bit, perhaps related
to no longer having AArch32 EL1 to worry about. While the DSU version
itself is not easily discoverable, the size of a counter certainly is.

Signed-off-by: Robin Murphy <robin.murphy at arm.com>
---
 drivers/perf/arm_dsu_pmu.c | 24 ++++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/drivers/perf/arm_dsu_pmu.c b/drivers/perf/arm_dsu_pmu.c
index cb4fb59fe04b..8663721ee018 100644
--- a/drivers/perf/arm_dsu_pmu.c
+++ b/drivers/perf/arm_dsu_pmu.c
@@ -66,13 +66,6 @@
  */
 #define DSU_PMU_IDX_CYCLE_COUNTER	31
 
-/* All event counters are 32bit, with a 64bit Cycle counter */
-#define DSU_PMU_COUNTER_WIDTH(idx)	\
-	(((idx) == DSU_PMU_IDX_CYCLE_COUNTER) ? 64 : 32)
-
-#define DSU_PMU_COUNTER_MASK(idx)	\
-	GENMASK_ULL((DSU_PMU_COUNTER_WIDTH((idx)) - 1), 0)
-
 #define DSU_EXT_ATTR(_name, _func, _config)		\
 	(&((struct dev_ext_attribute[]) {				\
 		{							\
@@ -107,6 +100,7 @@ struct dsu_hw_events {
  * @num_counters	: Number of event counters implemented by the PMU,
  *			  excluding the cycle counter.
  * @irq			: Interrupt line for counter overflow.
+ * @has_32b_pmevcntr	: Are the non-cycle counters only 32-bit?
  * @cpmceid_bitmap	: Bitmap for the availability of architected common
  *			  events (event_code < 0x40).
  */
@@ -120,6 +114,7 @@ struct dsu_pmu {
 	struct hlist_node		cpuhp_node;
 	s8				num_counters;
 	int				irq;
+	bool				has_32b_pmevcntr;
 	DECLARE_BITMAP(cpmceid_bitmap, DSU_PMU_MAX_COMMON_EVENTS);
 };
 
@@ -328,6 +323,11 @@ static inline void dsu_pmu_set_event(struct dsu_pmu *dsu_pmu,
 	raw_spin_unlock_irqrestore(&dsu_pmu->pmu_lock, flags);
 }
 
+static u64 dsu_pmu_counter_mask(struct hw_perf_event *hw)
+{
+	return (hw->flags && hw->idx != DSU_PMU_IDX_CYCLE_COUNTER) ? U32_MAX : U64_MAX;
+}
+
 static void dsu_pmu_event_update(struct perf_event *event)
 {
 	struct hw_perf_event *hwc = &event->hw;
@@ -339,7 +339,7 @@ static void dsu_pmu_event_update(struct perf_event *event)
 		new_count = dsu_pmu_read_counter(event);
 	} while (local64_cmpxchg(&hwc->prev_count, prev_count, new_count) !=
 			prev_count);
-	delta = (new_count - prev_count) & DSU_PMU_COUNTER_MASK(hwc->idx);
+	delta = (new_count - prev_count) & dsu_pmu_counter_mask(hwc);
 	local64_add(delta, &event->count);
 }
 
@@ -362,8 +362,7 @@ static inline u32 dsu_pmu_get_reset_overflow(void)
  */
 static void dsu_pmu_set_event_period(struct perf_event *event)
 {
-	int idx = event->hw.idx;
-	u64 val = DSU_PMU_COUNTER_MASK(idx) >> 1;
+	u64 val = dsu_pmu_counter_mask(&event->hw) >> 1;
 
 	local64_set(&event->hw.prev_count, val);
 	dsu_pmu_write_counter(event, val);
@@ -564,6 +563,7 @@ static int dsu_pmu_event_init(struct perf_event *event)
 		return -EINVAL;
 
 	event->hw.config_base = event->attr.config;
+	event->hw.flags = dsu_pmu->has_32b_pmevcntr;
 	return 0;
 }
 
@@ -664,6 +664,10 @@ static void dsu_pmu_probe_pmu(struct dsu_pmu *dsu_pmu)
 	cpmceid[1] = __dsu_pmu_read_pmceid(1);
 	bitmap_from_arr32(dsu_pmu->cpmceid_bitmap, cpmceid,
 			  DSU_PMU_MAX_COMMON_EVENTS);
+	/* Newer DSUs have 64-bit counters */
+	__dsu_pmu_write_counter(0, U64_MAX);
+	if (__dsu_pmu_read_counter(0) != U64_MAX)
+		dsu_pmu->has_32b_pmevcntr = true;
 }
 
 static void dsu_pmu_set_active_cpu(int cpu, struct dsu_pmu *dsu_pmu)
-- 
2.39.2.101.g768bb238c484.dirty



From robin.murphy at arm.com  Mon Dec 15 05:05:00 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Mon, 15 Dec 2025 13:05:00 +0000
Subject: [PATCH 3/3] perf/arm_dsu: Allow standard cycles events
In-Reply-To: <cover.1765802897.git.robin.murphy@arm.com>
References: <cover.1765802897.git.robin.murphy@arm.com>
Message-ID: <1a7d3708fec84fd292d6e8414e65984b020f99ad.1765802897.git.robin.murphy@arm.com>

Since we do not use the divide-by-64 option, there should be no
significant difference between the dedicated cycle counter and the
standard cycles event. Since using the latter on DSU-120 now has
the side-effect of allowing multiple cycles events to be scheduled
simultaneously (beneficial for multiple cycle-based metrics), there
seems little reason not to allow the same on older DSUs as well.

Signed-off-by: Robin Murphy <robin.murphy at arm.com>
---
 drivers/perf/arm_dsu_pmu.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/perf/arm_dsu_pmu.c b/drivers/perf/arm_dsu_pmu.c
index 56c592f0dae3..32b0dd7c693b 100644
--- a/drivers/perf/arm_dsu_pmu.c
+++ b/drivers/perf/arm_dsu_pmu.c
@@ -284,9 +284,8 @@ static int dsu_pmu_get_event_idx(struct dsu_hw_events *hw_events,
 	unsigned long *used_mask = hw_events->used_mask;
 
 	if (evtype == DSU_PMU_EVT_CYCLES && dsu_pmu->has_pmccntr) {
-		if (test_and_set_bit(DSU_PMU_IDX_CYCLE_COUNTER, used_mask))
-			return -EAGAIN;
-		return DSU_PMU_IDX_CYCLE_COUNTER;
+		if (!test_and_set_bit(DSU_PMU_IDX_CYCLE_COUNTER, used_mask))
+			return DSU_PMU_IDX_CYCLE_COUNTER;
 	}
 
 	idx = find_first_zero_bit(used_mask, dsu_pmu->num_counters);
-- 
2.39.2.101.g768bb238c484.dirty



From robin.murphy at arm.com  Mon Dec 15 05:04:59 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Mon, 15 Dec 2025 13:04:59 +0000
Subject: [PATCH 2/3] perf/arm_dsu: Support DSU-120
In-Reply-To: <cover.1765802897.git.robin.murphy@arm.com>
References: <cover.1765802897.git.robin.murphy@arm.com>
Message-ID: <346d4d9cda0e6c8dec44c28b8911e2bd944c389c.1765802897.git.robin.murphy@arm.com>

DSU-120 has the same system register interface as previous DSUs, but
no longer offers a dedicated cycle counter. While this is not directly
discoverable via PMCR, the PMCCNTR register is still defined to exist
with RAZ/WI behaviour, allowing for a straightforward heuristic.

Signed-off-by: Robin Murphy <robin.murphy at arm.com>
---
 drivers/perf/arm_dsu_pmu.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/perf/arm_dsu_pmu.c b/drivers/perf/arm_dsu_pmu.c
index 8663721ee018..56c592f0dae3 100644
--- a/drivers/perf/arm_dsu_pmu.c
+++ b/drivers/perf/arm_dsu_pmu.c
@@ -101,6 +101,7 @@ struct dsu_hw_events {
  *			  excluding the cycle counter.
  * @irq			: Interrupt line for counter overflow.
  * @has_32b_pmevcntr	: Are the non-cycle counters only 32-bit?
+ * @has_pmccntr		: Do we even have a dedicated cycle counter?
  * @cpmceid_bitmap	: Bitmap for the availability of architected common
  *			  events (event_code < 0x40).
  */
@@ -115,6 +116,7 @@ struct dsu_pmu {
 	s8				num_counters;
 	int				irq;
 	bool				has_32b_pmevcntr;
+	bool				has_pmccntr;
 	DECLARE_BITMAP(cpmceid_bitmap, DSU_PMU_MAX_COMMON_EVENTS);
 };
 
@@ -281,7 +283,7 @@ static int dsu_pmu_get_event_idx(struct dsu_hw_events *hw_events,
 	struct dsu_pmu *dsu_pmu = to_dsu_pmu(event->pmu);
 	unsigned long *used_mask = hw_events->used_mask;
 
-	if (evtype == DSU_PMU_EVT_CYCLES) {
+	if (evtype == DSU_PMU_EVT_CYCLES && dsu_pmu->has_pmccntr) {
 		if (test_and_set_bit(DSU_PMU_IDX_CYCLE_COUNTER, used_mask))
 			return -EAGAIN;
 		return DSU_PMU_IDX_CYCLE_COUNTER;
@@ -668,6 +670,10 @@ static void dsu_pmu_probe_pmu(struct dsu_pmu *dsu_pmu)
 	__dsu_pmu_write_counter(0, U64_MAX);
 	if (__dsu_pmu_read_counter(0) != U64_MAX)
 		dsu_pmu->has_32b_pmevcntr = true;
+	/* On even newer DSUs, PMCCNTR is RAZ/WI */
+	__dsu_pmu_write_pmccntr(U64_MAX);
+	if (__dsu_pmu_read_pmccntr() == U64_MAX)
+		dsu_pmu->has_pmccntr = true;
 }
 
 static void dsu_pmu_set_active_cpu(int cpu, struct dsu_pmu *dsu_pmu)
-- 
2.39.2.101.g768bb238c484.dirty



From nm at ti.com  Mon Dec 15 05:22:20 2025
From: nm at ti.com (Nishanth Menon)
Date: Mon, 15 Dec 2025 07:22:20 -0600
Subject: [PATCH] firmware: ti_sci.h: fix all kernel-doc warnings
In-Reply-To: <20251128055731.812460-1-rdunlap@infradead.org>
References: <20251128055731.812460-1-rdunlap@infradead.org>
Message-ID: <176580492714.1684742.10297688269442872704.b4-ty@ti.com>

Hi Randy Dunlap,

On Thu, 27 Nov 2025 21:57:31 -0800, Randy Dunlap wrote:
> Modify kernel-doc comments in ti_sci.h to eliminate all kernel-doc
> warnings:
> 
> * use correct/matching struct names in kdoc comments
> * use correct struct member names in kdoc comments
> * add a ':' after struct member names where needed
> * change a blank kdoc line to " *"
> * convert 3 structs to kernel-doc comments:
>   struct ti_sci_msg_rm_udmap_tx_ch_cfg_req
>   struct ti_sci_msg_rm_udmap_rx_ch_cfg_req
>   struct ti_sci_msg_rm_udmap_flow_cfg_req
> 
> [...]

I have applied the following to branch ti-drivers-soc-next on [1].
Thank you!

[1/1] firmware: ti_sci.h: fix all kernel-doc warnings
      commit: fdce161afe29b40e84853ec821cbd7bbd727bf58

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent up the chain during
the next merge window (or sooner if it is a relevant bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/ti/linux.git
-- 
Regards,
Nishanth Menon
Key (0xDDB5849D1736249D) / Fingerprint: F8A2 8693 54EB 8232 17A3  1A34 DDB5 849D 1736 249D
https://ti.com/opensource



From nm at ti.com  Mon Dec 15 05:22:49 2025
From: nm at ti.com (Nishanth Menon)
Date: Mon, 15 Dec 2025 07:22:49 -0600
Subject: [PATCH v2 1/3] arm64: dts: ti: k3-am642-phyboard-electra-peb-c-010: Fix icssg-prueth schema warning
In-Reply-To: <20251127122733.2523367-1-w.egorov@phytec.de>
References: <20251127122733.2523367-1-w.egorov@phytec.de>
Message-ID: <176580496018.1685064.13129316484547928618.b4-ty@ti.com>

Hi Wadim Egorov,

On Thu, 27 Nov 2025 13:27:31 +0100, Wadim Egorov wrote:
> Reduce length of dma-names and dmas properties for icssg1-ethernet
> node to comply with ti,icssg-prueth schema constraints. The previous
> entries exceeded the allowed count and triggered dtschema warnings
> during validation.
> 
> 

I have applied the following to branch ti-k3-dts-next on [1].
Thank you!

[1/3] arm64: dts: ti: k3-am642-phyboard-electra-peb-c-010: Fix icssg-prueth schema warning
      commit: 05bbe52d0be5637dcd3c880348e3688f7ec64eb7
[2/3] arm64: dts: ti: k3-am642-phyboard-electra-x27-gpio1-spi1-uart3: Fix schema warnings
      commit: d876bb9353d87dee0ae620300106e8def189c785
[3/3] arm64: dts: ti: k3-am62-lp-sk-nand: Rename pinctrls to fix schema warnings
      commit: cf5e8adebe77917a4cc95e43e461cdbd857591ce

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent up the chain during
the next merge window (or sooner if it is a relevant bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/ti/linux.git
-- 
Regards,
Nishanth Menon
Key (0xDDB5849D1736249D) / Fingerprint: F8A2 8693 54EB 8232 17A3  1A34 DDB5 849D 1736 249D
https://ti.com/opensource



From nm at ti.com  Mon Dec 15 05:28:45 2025
From: nm at ti.com (Nishanth Menon)
Date: Mon, 15 Dec 2025 07:28:45 -0600
Subject: [GIT PULL] arm64: dts: TI K3 fixes for v6.19
Message-ID: <20251215132845.faudhjh7ywxdx2nq@elongated>

Hi,

The following are minor fixups found on device tree overlay files post
PR for 6.19. These were identified after we enabled builds of all the
dt+overlay combinations.

The following changes since commit 8f0b4cce4481fb22653697cced8d0d04027cb1e8:

  Linux 6.19-rc1 (2025-12-14 16:05:07 +1200)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/ti/linux.git tags/ti-k3-dt-fixes-for-v6.19

for you to fetch changes up to cf5e8adebe77917a4cc95e43e461cdbd857591ce:

  arm64: dts: ti: k3-am62-lp-sk-nand: Rename pinctrls to fix schema warnings (2025-12-15 07:17:46 -0600)

----------------------------------------------------------------
TI K3 DT fixes for v6.19

- minor fixes for overlay files

----------------------------------------------------------------
Wadim Egorov (3):
      arm64: dts: ti: k3-am642-phyboard-electra-peb-c-010: Fix icssg-prueth schema warning
      arm64: dts: ti: k3-am642-phyboard-electra-x27-gpio1-spi1-uart3: Fix schema warnings
      arm64: dts: ti: k3-am62-lp-sk-nand: Rename pinctrls to fix schema warnings

 arch/arm64/boot/dts/ti/k3-am62-lp-sk-nand.dtso                    | 2 +-
 arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-peb-c-010.dtso   | 7 ++-----
 .../dts/ti/k3-am642-phyboard-electra-x27-gpio1-spi1-uart3.dtso    | 8 ++++----
 3 files changed, 7 insertions(+), 10 deletions(-)
-- 
Regards,
Nishanth Menon
Key (0xDDB5849D1736249D) / Fingerprint: F8A2 8693 54EB 8232 17A3  1A34 DDB5 849D 1736 249D
https://ti.com/opensource
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251215/89eebf6b/attachment.sig>

From robert.marko at sartura.hr  Mon Dec 15 05:31:00 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Mon, 15 Dec 2025 14:31:00 +0100
Subject: [PATCH 4/4] arm64: dts: microchip: add LAN969x support
In-Reply-To: <173412c8-c2fb-4c38-8de7-5b1c2eebdbf9@microchip.com>
References: <20251203122313.1287950-1-robert.marko@sartura.hr>
 <20251203122313.1287950-4-robert.marko@sartura.hr> <20251203-splendor-cubbyhole-eda2d6982b46@spud>
 <CA+HBbNGdd-u=4PtXZtirqRkFBhKwraa5gV-32QChDDjfVARPRg@mail.gmail.com> <173412c8-c2fb-4c38-8de7-5b1c2eebdbf9@microchip.com>
Message-ID: <CA+HBbNFzETiySdw-VuzMJx6vdhPU_3d_aU2v9eJ4-_OBaTn2mA@mail.gmail.com>

On Mon, Dec 15, 2025 at 1:32?PM Nicolas Ferre
<nicolas.ferre at microchip.com> wrote:
>
> Robert,
>
> On 15/12/2025 at 12:36, Robert Marko wrote:
> > On Wed, Dec 3, 2025 at 8:21?PM Conor Dooley <conor at kernel.org> wrote:
> >>
> >> On Wed, Dec 03, 2025 at 01:21:32PM +0100, Robert Marko wrote:
> >>> Add support for Microchip LAN969x switch SoC, including the EV23X71A
> >>> EVB board.
> >>>
> >>> Signed-off-by: Robert Marko <robert.marko at sartura.hr>
> >>> ---
> >>>   arch/arm64/boot/dts/microchip/Makefile        |   2 +
> >>>   .../boot/dts/microchip/lan9696-ev23x71a.dts   | 761 ++++++++++++++++++
> >>
> >>>   arch/arm64/boot/dts/microchip/lan969x.dtsi    | 482 +++++++++++
> >>
> >> The majority of devices in this file are missing soc-specific
> >> compatibles.
> >
> > Hi,
> > I missed this before.
> >
> > The majority of the devices are simply reused from the AT91 series, so
> > I thought it was not required to
> > update all of the bindings to add the LAN9691 compatible.
> >
> > If that is required, I will do so in v2.
> Well, history told us it was better (in addition to be required by DT
> best practices). Indeed, even if the same IP block is used, sometimes
> integration subtleties pay game with us and a dedicated compatible
> string saves us.

Ok, I will then update the required bindings and include them in the
series in v2.

Regards,
Robert
>
> Regards,
>    Nicolas



-- 
Robert Marko
Staff Embedded Linux Engineer
Sartura d.d.
Lendavska ulica 16a
10000 Zagreb, Croatia
Email: robert.marko at sartura.hr
Web: www.sartura.hr


From maz at kernel.org  Mon Dec 15 05:32:04 2025
From: maz at kernel.org (Marc Zyngier)
Date: Mon, 15 Dec 2025 13:32:04 +0000
Subject: [PATCH 07/32] KVM: arm64: gic: Introduce interrupt type helpers
In-Reply-To: <20251212152215.675767-8-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	<20251212152215.675767-8-sascha.bischoff@arm.com>
Message-ID: <86jyynooq3.wl-maz@kernel.org>

On Fri, 12 Dec 2025 15:22:37 +0000,
Sascha Bischoff <Sascha.Bischoff at arm.com> wrote:
> 
> GICv5 has moved from using interrupt ranges for different interrupt
> types to using some of the upper bits of the interrupt ID to denote
> the interrupt type. This is not compatible with older GICs (which rely
> on ranges of interrupts to determine the type), and hence a set of
> helpers is introduced. These helpers take a struct kvm*, and use the
> vgic model to determine how to interpret the interrupt ID.
> 
> Helpers are introduced for PPIs, SPIs, and LPIs. Additionally, a
> helper is introduced to determine if an interrupt is private - SGIs
> and PPIs for older GICs, and PPIs only for GICv5.
> 
> The helpers are plumbed into the core vgic code, as well as the Arch
> Timer and PMU code.
> 
> There should be no functional changes as part of this change.
> 
> Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
> ---
>  arch/arm64/kvm/arch_timer.c           |  2 +-
>  arch/arm64/kvm/pmu-emul.c             |  6 +++---
>  arch/arm64/kvm/vgic/vgic-kvm-device.c |  2 +-
>  arch/arm64/kvm/vgic/vgic.c            | 14 +++++++-------
>  include/kvm/arm_vgic.h                | 27 +++++++++++++++++++++++----
>  5 files changed, 35 insertions(+), 16 deletions(-)
> 
> diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c
> index 99a07972068d1..6f033f6644219 100644
> --- a/arch/arm64/kvm/arch_timer.c
> +++ b/arch/arm64/kvm/arch_timer.c
> @@ -1598,7 +1598,7 @@ int kvm_arm_timer_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
>  	if (get_user(irq, uaddr))
>  		return -EFAULT;
>  
> -	if (!(irq_is_ppi(irq)))
> +	if (!(irq_is_ppi(vcpu->kvm, irq)))

nit: From a high-level perspective, I'd find it mentally more
satisfying to pass a vcpu to the macro rather than a vm pointer when
dealing with PPIs. It would also keep the dereference hidden away. But
maybe i just need to go with the flow here.

>  		return -EINVAL;
>  
>  	mutex_lock(&vcpu->kvm->arch.config_lock);
> diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c
> index b03dbda7f1ab9..0baf8e0fe23bd 100644
> --- a/arch/arm64/kvm/pmu-emul.c
> +++ b/arch/arm64/kvm/pmu-emul.c
> @@ -939,7 +939,7 @@ int kvm_arm_pmu_v3_enable(struct kvm_vcpu *vcpu)
>  		 * number against the dimensions of the vgic and make sure
>  		 * it's valid.
>  		 */
> -		if (!irq_is_ppi(irq) && !vgic_valid_spi(vcpu->kvm, irq))
> +		if (!irq_is_ppi(vcpu->kvm, irq) && !vgic_valid_spi(vcpu->kvm, irq))
>  			return -EINVAL;
>  	} else if (kvm_arm_pmu_irq_initialized(vcpu)) {
>  		   return -EINVAL;
> @@ -991,7 +991,7 @@ static bool pmu_irq_is_valid(struct kvm *kvm, int irq)
>  		if (!kvm_arm_pmu_irq_initialized(vcpu))
>  			continue;
>  
> -		if (irq_is_ppi(irq)) {
> +		if (irq_is_ppi(kvm, irq)) {
>  			if (vcpu->arch.pmu.irq_num != irq)
>  				return false;
>  		} else {
> @@ -1142,7 +1142,7 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
>  			return -EFAULT;
>  
>  		/* The PMU overflow interrupt can be a PPI or a valid SPI. */
> -		if (!(irq_is_ppi(irq) || irq_is_spi(irq)))
> +		if (!(irq_is_ppi(vcpu->kvm, irq) || irq_is_spi(vcpu->kvm, irq)))
>  			return -EINVAL;
>  
>  		if (!pmu_irq_is_valid(kvm, irq))
> diff --git a/arch/arm64/kvm/vgic/vgic-kvm-device.c b/arch/arm64/kvm/vgic/vgic-kvm-device.c
> index 3d1a776b716d7..b12ba99a423e5 100644
> --- a/arch/arm64/kvm/vgic/vgic-kvm-device.c
> +++ b/arch/arm64/kvm/vgic/vgic-kvm-device.c
> @@ -639,7 +639,7 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
>  		if (vgic_initialized(dev->kvm))
>  			return -EBUSY;
>  
> -		if (!irq_is_ppi(val))
> +		if (!irq_is_ppi(dev->kvm, val))
>  			return -EINVAL;
>  
>  		dev->kvm->arch.vgic.mi_intid = val;
> diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
> index 430aa98888fda..2c0e8803342e2 100644
> --- a/arch/arm64/kvm/vgic/vgic.c
> +++ b/arch/arm64/kvm/vgic/vgic.c
> @@ -94,7 +94,7 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, u32 intid)
>  	}
>  
>  	/* LPIs */
> -	if (intid >= VGIC_MIN_LPI)
> +	if (irq_is_lpi(kvm, intid))
>  		return vgic_get_lpi(kvm, intid);
>  
>  	return NULL;
> @@ -123,7 +123,7 @@ static void vgic_release_lpi_locked(struct vgic_dist *dist, struct vgic_irq *irq
>  
>  static __must_check bool __vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
>  {
> -	if (irq->intid < VGIC_MIN_LPI)
> +	if (!irq_is_lpi(kvm, irq->intid))
>  		return false;
>  
>  	return refcount_dec_and_test(&irq->refcount);
> @@ -148,7 +148,7 @@ void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
>  	 * Acquire/release it early on lockdep kernels to make locking issues
>  	 * in rare release paths a bit more obvious.
>  	 */
> -	if (IS_ENABLED(CONFIG_LOCKDEP) && irq->intid >= VGIC_MIN_LPI) {
> +	if (IS_ENABLED(CONFIG_LOCKDEP) && irq_is_lpi(kvm, irq->intid)) {
>  		guard(spinlock_irqsave)(&dist->lpi_xa.xa_lock);
>  	}
>  
> @@ -186,7 +186,7 @@ void vgic_flush_pending_lpis(struct kvm_vcpu *vcpu)
>  	raw_spin_lock_irqsave(&vgic_cpu->ap_list_lock, flags);
>  
>  	list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
> -		if (irq->intid >= VGIC_MIN_LPI) {
> +		if (irq_is_lpi(vcpu->kvm, irq->intid)) {
>  			raw_spin_lock(&irq->irq_lock);
>  			list_del(&irq->ap_list);
>  			irq->vcpu = NULL;
> @@ -521,12 +521,12 @@ int kvm_vgic_inject_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  	if (ret)
>  		return ret;
>  
> -	if (!vcpu && intid < VGIC_NR_PRIVATE_IRQS)
> +	if (!vcpu && irq_is_private(kvm, intid))
>  		return -EINVAL;
>  
>  	trace_vgic_update_irq_pending(vcpu ? vcpu->vcpu_idx : 0, intid, level);
>  
> -	if (intid < VGIC_NR_PRIVATE_IRQS)
> +	if (irq_is_private(kvm, intid))
>  		irq = vgic_get_vcpu_irq(vcpu, intid);
>  	else
>  		irq = vgic_get_irq(kvm, intid);
> @@ -685,7 +685,7 @@ int kvm_vgic_set_owner(struct kvm_vcpu *vcpu, unsigned int intid, void *owner)
>  		return -EAGAIN;
>  
>  	/* SGIs and LPIs cannot be wired up to any device */
> -	if (!irq_is_ppi(intid) && !vgic_valid_spi(vcpu->kvm, intid))
> +	if (!irq_is_ppi(vcpu->kvm, intid) && !vgic_valid_spi(vcpu->kvm, intid))
>  		return -EINVAL;
>  
>  	irq = vgic_get_vcpu_irq(vcpu, intid);
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index b261fb3968d03..be1f45a494f78 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -19,6 +19,7 @@
>  #include <linux/jump_label.h>
>  
>  #include <linux/irqchip/arm-gic-v4.h>
> +#include <linux/irqchip/arm-gic-v5.h>
>  
>  #define VGIC_V3_MAX_CPUS	512
>  #define VGIC_V2_MAX_CPUS	8
> @@ -31,9 +32,22 @@
>  #define VGIC_MIN_LPI		8192
>  #define KVM_IRQCHIP_NUM_PINS	(1020 - 32)
>  
> -#define irq_is_ppi(irq) ((irq) >= VGIC_NR_SGIS && (irq) < VGIC_NR_PRIVATE_IRQS)
> -#define irq_is_spi(irq) ((irq) >= VGIC_NR_PRIVATE_IRQS && \
> -			 (irq) <= VGIC_MAX_SPI)
> +#define irq_is_ppi_legacy(irq) ((irq) >= VGIC_NR_SGIS && (irq) < VGIC_NR_PRIVATE_IRQS)
> +#define irq_is_spi_legacy(irq) ((irq) >= VGIC_NR_PRIVATE_IRQS && \
> +					(irq) <= VGIC_MAX_SPI)
> +#define irq_is_lpi_legacy(irq) ((irq) > VGIC_MAX_SPI)

This last line is wrong. v3 LPIs start at 8192, while VGIC_MAX_SPI is
1019. Also, "legacy" is remarkably ambiguous. v2 is legacy for v3, v3
for v4...  You see where this is going.

I'd rather you have something that denotes the non-GICv5-ness of the
implementation. irq_is_nv5_ppi()?

> +
> +#define irq_is_ppi_v5(irq) (FIELD_GET(GICV5_HWIRQ_TYPE, irq) == GICV5_HWIRQ_TYPE_PPI)
> +#define irq_is_spi_v5(irq) (FIELD_GET(GICV5_HWIRQ_TYPE, irq) == GICV5_HWIRQ_TYPE_SPI)
> +#define irq_is_lpi_v5(irq) (FIELD_GET(GICV5_HWIRQ_TYPE, irq) == GICV5_HWIRQ_TYPE_LPI)
> +
> +#define gic_is_v5(k) ((k)->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5)
> +
> +#define irq_is_ppi(k, i) (gic_is_v5(k) ? irq_is_ppi_v5(i) : irq_is_ppi_legacy(i))
> +#define irq_is_spi(k, i) (gic_is_v5(k) ? irq_is_spi_v5(i) : irq_is_spi_legacy(i))
> +#define irq_is_lpi(k, i) (gic_is_v5(k) ? irq_is_lpi_v5(i) : irq_is_lpi_legacy(i))
> +
> +#define irq_is_private(k, i) (gic_is_v5(k) ? irq_is_ppi_v5(i) : i < VGIC_NR_PRIVATE_IRQS)
>  
>  enum vgic_type {
>  	VGIC_V2,		/* Good ol' GICv2 */
> @@ -418,8 +432,13 @@ u64 vgic_v3_get_misr(struct kvm_vcpu *vcpu);
>  
>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>  #define vgic_initialized(k)	((k)->arch.vgic.initialized)
> -#define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
> +#define vgic_ready(k)		((k)->arch.vgic.ready)

What is this for? Nothing seem to be using it yet. How different is it
from the 'initialized' field?

> +#define vgic_valid_spi_legacy(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
> +#define vgic_valid_spi_v5(k, i)	(irq_is_spi(k, i) && \
> +				 (FIELD_GET(GICV5_HWIRQ_ID, i) < (k)->arch.vgic.nr_spis))
> +#define vgic_valid_spi(k, i) (((k)->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V5) ? \
> +				vgic_valid_spi_legacy(k, i) : vgic_valid_spi_v5(k, i))
>

This macro has its v5/nv5 statements in the opposite order of all the
others. Some consistency would be welcome.

Thanks,

	M.

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


From tabba at google.com  Mon Dec 15 05:42:44 2025
From: tabba at google.com (Fuad Tabba)
Date: Mon, 15 Dec 2025 13:42:44 +0000
Subject: [PATCH v2 4/4] KVM: arm64: Remove unused parameter in synchronize_vcpu_pstate()
In-Reply-To: <20251215114409.212512-5-alexandru.elisei@arm.com>
References: <20251215114409.212512-1-alexandru.elisei@arm.com> <20251215114409.212512-5-alexandru.elisei@arm.com>
Message-ID: <CA+EHjTyCTetJ+ieRNFG9QN6gQT_4b+G29i-w9AB745w4EtrwMA@mail.gmail.com>

On Mon, 15 Dec 2025 at 11:44, Alexandru Elisei <alexandru.elisei at arm.com> wrote:
>
> synchronize_vcpu_pstate() doesn't make use of the reference to exit_code,
> remove the parameter.
>
> Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
> ---

Reviewed-by: Fuad Tabba <tabba at google.com>

Cheers,
/fuad

>  arch/arm64/kvm/hyp/include/hyp/switch.h | 2 +-
>  arch/arm64/kvm/hyp/nvhe/switch.c        | 2 +-
>  arch/arm64/kvm/hyp/vhe/switch.c         | 2 +-
>  3 files changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
> index c5d5e5b86eaf..afecbdd3c1e9 100644
> --- a/arch/arm64/kvm/hyp/include/hyp/switch.h
> +++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
> @@ -854,7 +854,7 @@ static inline bool kvm_hyp_handle_exit(struct kvm_vcpu *vcpu, u64 *exit_code,
>         return false;
>  }
>
> -static inline void synchronize_vcpu_pstate(struct kvm_vcpu *vcpu, u64 *exit_code)
> +static inline void synchronize_vcpu_pstate(struct kvm_vcpu *vcpu)
>  {
>         /*
>          * Check for the conditions of Cortex-A510's #2077057. When these occur
> diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c
> index d3b9ec8a7c28..779089e42681 100644
> --- a/arch/arm64/kvm/hyp/nvhe/switch.c
> +++ b/arch/arm64/kvm/hyp/nvhe/switch.c
> @@ -211,7 +211,7 @@ static inline bool fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
>  {
>         const exit_handler_fn *handlers = kvm_get_exit_handler_array(vcpu);
>
> -       synchronize_vcpu_pstate(vcpu, exit_code);
> +       synchronize_vcpu_pstate(vcpu);
>
>         /*
>          * Some guests (e.g., protected VMs) are not be allowed to run in
> diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c
> index 9984c492305a..9db3f11a4754 100644
> --- a/arch/arm64/kvm/hyp/vhe/switch.c
> +++ b/arch/arm64/kvm/hyp/vhe/switch.c
> @@ -536,7 +536,7 @@ static const exit_handler_fn hyp_exit_handlers[] = {
>
>  static inline bool fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
>  {
> -       synchronize_vcpu_pstate(vcpu, exit_code);
> +       synchronize_vcpu_pstate(vcpu);
>
>         /*
>          * If we were in HYP context on entry, adjust the PSTATE view
> --
> 2.52.0
>


From tabba at google.com  Mon Dec 15 05:43:39 2025
From: tabba at google.com (Fuad Tabba)
Date: Mon, 15 Dec 2025 13:43:39 +0000
Subject: [PATCH v2 3/4] KVM: arm64: Remove extra argument for __pvkm_host_{share,unshare}_hyp()
In-Reply-To: <20251215114409.212512-4-alexandru.elisei@arm.com>
References: <20251215114409.212512-1-alexandru.elisei@arm.com> <20251215114409.212512-4-alexandru.elisei@arm.com>
Message-ID: <CA+EHjTz2rZ1ebh8PP_f8DkJ=zqF_yjHQPgtQXxFjCsvifGD1bw@mail.gmail.com>

On Mon, 15 Dec 2025 at 11:44, Alexandru Elisei <alexandru.elisei at arm.com> wrote:
>
> __pvkm_host_share_hyp() and __pkvm_host_unshare_hyp() both have one
> parameter, the pfn, not two. Even though correctness isn't impacted because
> the SMCCC handlers pass the first argument and ignore the second one, let's
> call the functions with the proper number of arguments.
>
> Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
> ---

Reviewed-by: Fuad Tabba <tabba at google.com>

Cheers,
/fuad

>  arch/arm64/kvm/mmu.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
> index 48d7c372a4cd..124404eb208d 100644
> --- a/arch/arm64/kvm/mmu.c
> +++ b/arch/arm64/kvm/mmu.c
> @@ -497,7 +497,7 @@ static int share_pfn_hyp(u64 pfn)
>         this->count = 1;
>         rb_link_node(&this->node, parent, node);
>         rb_insert_color(&this->node, &hyp_shared_pfns);
> -       ret = kvm_call_hyp_nvhe(__pkvm_host_share_hyp, pfn, 1);
> +       ret = kvm_call_hyp_nvhe(__pkvm_host_share_hyp, pfn);
>  unlock:
>         mutex_unlock(&hyp_shared_pfns_lock);
>
> @@ -523,7 +523,7 @@ static int unshare_pfn_hyp(u64 pfn)
>
>         rb_erase(&this->node, &hyp_shared_pfns);
>         kfree(this);
> -       ret = kvm_call_hyp_nvhe(__pkvm_host_unshare_hyp, pfn, 1);
> +       ret = kvm_call_hyp_nvhe(__pkvm_host_unshare_hyp, pfn);
>  unlock:
>         mutex_unlock(&hyp_shared_pfns_lock);
>
> --
> 2.52.0
>


From heiko at sntech.de  Mon Dec 15 05:51:03 2025
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 15 Dec 2025 14:51:03 +0100
Subject: [PATCH] arm64: dts: rockchip: enable dual 2.5GbE on Rock 5T
In-Reply-To: <96516D1F-9787-47FE-A67E-4745D11D9207@probably.group>
References: <96516D1F-9787-47FE-A67E-4745D11D9207@probably.group>
Message-ID: <176580661874.1441131.12947657582985645446.b4-ty@sntech.de>


On Fri, 12 Dec 2025 17:23:35 +0100, "Martin Holovsk? (Probably Nothing s.r.o. )" wrote:
> The Radxa Rock 5T board features two RTL8125B 2.5GbE Ethernet controllers
> connected via PCIe lanes pcie2x1l0 (fe170000) and pcie2x1l2 (fe190000).
> Currently only one interface is functional because the PCIe controller
> nodes lack the necessary reset GPIO configuration.
> 
> Without the reset-gpios property, the RTL8125B PHYs remain in reset state
> and are not enumerated by the PCIe bus. This results in only one Ethernet
> interface being detected, or none at all depending on U-Boot initialization.
> 
> [...]

Applied, thanks!

[1/1] arm64: dts: rockchip: enable dual 2.5GbE on Rock 5T
      commit: 96029ffeccf677b1e4baa98f30909a83a485b6d7

I've resorted both the pcie phandles as well as the pinctrl entries
pcie2-0 comes before pcie2-1 etc :-) .

Best regards,
-- 
Heiko Stuebner <heiko at sntech.de>


From nm at ti.com  Mon Dec 15 05:57:08 2025
From: nm at ti.com (Nishanth Menon)
Date: Mon, 15 Dec 2025 07:57:08 -0600
Subject: [PATCH v5] dt-bindings: arm: keystone: add boot_* mboxes to
 ti,sci
In-Reply-To: <20251215-k3_syscon_add_boot_mailboxes-v5-1-5a8fe567fd31@ti.com>
References: <20251215-k3_syscon_add_boot_mailboxes-v5-1-5a8fe567fd31@ti.com>
Message-ID: <20251215135708.ij5e7jr3binzmlbf@panda>

On 11:38-20251215, Anshul Dalal wrote:
> The bootloader on K3 devices makes use of mailboxes as per the ROM spec
> which might be different than one's available to the kernel (firmware
> spec).
> 
> Therefore, this patch adds the missing mailbox entries to the DT binding
> if the matching compatible is ti,am654-sci to represent the mailboxes
> exposed by the hardware during boot for the purpose of loading the
> firmware. The newly added mboxes are made optional by keeping minItems
> as 2 to remain compliant with existing device-trees.
> 
> Signed-off-by: Anshul Dalal <anshuld at ti.com>
> ---
> Changes in v5:
> - Added commit description for the optional mailboxes
> - Link to v4: https://lore.kernel.org/r/20251205-k3_syscon_add_boot_mailboxes-v4-1-8e216fb88941 at ti.com
> 
> Changes in v4:
> - Make new boot_* mboxes conditional on ti,am654-sci compatible
> - Link to v3: https://lore.kernel.org/r/20251112-k3_syscon_add_boot_mailboxes-v3-1-66155a4236dc at ti.com
> 
> Changes in v3:
> - Drop [1/2] of the last patch series
> - Update existing example with boot_* mailboxes instead of adding a new one
> - Link to v2: https://lore.kernel.org/r/20251112-k3_syscon_add_boot_mailboxes-v2-0-aebc1e47b391 at ti.com
> 
> Changes in v2:
> - Remove maxItems entry
> - Remove RFC tag from patch (added by mistake in v1)
> - Document the new mailboxes in mboxes instead of mbox-names
> - Provide example with all the mailboxes set
> - Update commit title to have "ti,sci"
> - Split into two patches
> - Link to v1: https://lore.kernel.org/r/20251111-k3_syscon_add_boot_mailboxes-v1-1-529a27f21076 at ti.com
> ---
>  .../devicetree/bindings/arm/keystone/ti,sci.yaml   | 50 +++++++++++++++++++---
>  1 file changed, 43 insertions(+), 7 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
> index 25a2b42105e5..d9eb2a81e539 100644
> --- a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
> +++ b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
> @@ -51,15 +51,15 @@ properties:
>      minItems: 1
>  
>    mbox-names:
> +    minItems: 2
> +    maxItems: 6
>      description: |
>        Specifies the mailboxes used to communicate with TI-SCI Controller
>        made available from TI-SCI controller.
> -    items:
> -      - const: rx
> -      - const: tx
>  
>    mboxes:
>      minItems: 2
> +    maxItems: 6
>  
>    ti,host-id:
>      $ref: /schemas/types.yaml#/definitions/uint32
> @@ -79,6 +79,42 @@ properties:
>      type: object
>      $ref: /schemas/reset/ti,sci-reset.yaml#
>  
> +if:
> +  properties:
> +    compatible:
> +      contains:
> +        const: ti,am654-sci
> +then:
> +  properties:
> +    mbox-names:
> +      minItems: 2
> +      items:
> +        - const: rx
> +        - const: tx
> +        - const: notify
> +        - const: boot_rx
> +        - const: boot_tx
> +        - const: boot_notify
> +    mboxes:
> +      minItems: 2
> +      items:
> +        - description: RX thread
> +        - description: TX thread
> +        - description: Notify thread
> +        - description: boot stage RX thread
> +        - description: boot stage TX thread
> +        - description: boot stage Notify thread
> +else:
> +  properties:
> +    mbox-names:
> +      items:
> +        - const: rx
> +        - const: tx
> +    mboxes:
> +      items:
> +        - description: RX thread
> +        - description: TX thread
> +
>  required:
>    - compatible
>    - mbox-names
> @@ -99,11 +135,11 @@ examples:
>  
>    - |
>      dmsc: system-controller at 44083000 {
> -      compatible = "ti,k2g-sci";
> +      compatible = "ti,am654-sci";
>        ti,host-id = <12>;
> -      mbox-names = "rx", "tx";
> -      mboxes = <&secure_proxy_main 11>,
> -               <&secure_proxy_main 13>;
> +      mbox-names = "rx", "tx", "notify", "boot_rx", "boot_tx";
> +      mboxes= <&secure_proxy_mcu 6>, <&secure_proxy_mcu 8>,
> +        <&secure_proxy_mcu 5>, <&secure_proxy_mcu 5>, <&secure_proxy_mcu 4>;
>        reg-names = "debug_messages";
>        reg = <0x44083000 0x1000>;

Please add a different example for am654, i want to make sure k2g still
continues to be checked.

That said, AM62 series of devices do not use notification pipe for
standard communication. So, the schema will break for those.

in summary:
k2g: rx, tx
am654, j721e, j721s2, j7200, j784s4, .. : rx, tx, notify, boot_rx,
boot_tx, boot_notify
am625, am62p ..: rx, tx, boot_rx, boot_tx, boot_notify

we will need three examples, and will need to add am62x series as one
additional compatible.

Though we could play a trick by reordering as follows to handle superset
of am62 and am65 series as follows, but I do prefer explicitly handling
them:

   - const: rx
   - const: tx
   - const: boot_rx
   - const: boot_tx
   - const: notify
   - const: boot_notify


-- 
Regards,
Nishanth Menon
Key (0xDDB5849D1736249D) / Fingerprint: F8A2 8693 54EB 8232 17A3  1A34 DDB5 849D 1736 249D
https://ti.com/opensource


From heiko at sntech.de  Mon Dec 15 05:57:15 2025
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 15 Dec 2025 14:57:15 +0100
Subject: (subset) [PATCH v2 0/9] General RK3368 HDMI support and 2 outputs for RK3368-Lion
In-Reply-To: <20251021074254.87065-1-heiko@sntech.de>
References: <20251021074254.87065-1-heiko@sntech.de>
Message-ID: <176580702585.1452104.11896620179705853130.b4-ty@sntech.de>


On Tue, 21 Oct 2025 09:42:45 +0200, Heiko Stuebner wrote:
> This series adds the necessary bits for HDMI output on RK3368 and enables
> this on RK3368-Lion. At the same time, use the recently added DSI support
> to enable the generic Video-Demo-adapter as an overlay on Lion as well.
> 
> 
> The reason I'm shaving this Yak is that the recently added DSI support
> created DTC warnings about a single endpoint with an address.
> 
> [...]

Applied, thanks!

[1/9] dt-bindings: display: rockchip: dw-hdmi: Add compatible for RK3368 HDMI
      commit: 0edbd43e0c149152b917c0cde61e4bd34a5bd118
[2/9] drm/rockchip: hdmi: add RK3368 controller variant
      commit: e7a943f0824b584e42847ad9642d7fb751022cf6

Best regards,
-- 
Heiko Stuebner <heiko at sntech.de>


From nicolas at ndufresne.ca  Mon Dec 15 05:58:31 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Mon, 15 Dec 2025 08:58:31 -0500
Subject: [PATCH RFC v2 2/3] decoder: Add V4L2 stateless H.264 decoder
 driver
In-Reply-To: <9ab31529-8146-4ca7-8389-04c69f7d1b49@amlogic.com>
References: <20251124-b4-s4-vdec-upstream-v2-0-bdbbce3f11a6@amlogic.com>
	 <20251124-b4-s4-vdec-upstream-v2-2-bdbbce3f11a6@amlogic.com>
	 <9b74086ac938475328904960add2c284b81efd4a.camel@ndufresne.ca>
	 <12f26bf8-409b-4206-a39b-4bb2a14edec0@amlogic.com>
	 <f9c113914290a0701614c64b5e2167d4b3e21646.camel@ndufresne.ca>
	 <9ab31529-8146-4ca7-8389-04c69f7d1b49@amlogic.com>
Message-ID: <04287d0b6207c98f24112b492b9ee52f0889da39.camel@ndufresne.ca>

Le lundi 15 d?cembre 2025 ? 10:15 +0800, Zhentao Guo a ?crit?:
> 
> ? 2025/12/12 21:51, Nicolas Dufresne ??:
> > Hi,
> > 
> > Le vendredi 12 d?cembre 2025 ? 12:11 +0800, Zhentao Guo a ?crit?:
> > > > strcpy() would be the preferred helper for this, no need to fill the
> > > > leading
> > > > zero liek this, see include/linux/string.h
> > > Ok, it should be more suitable to use strcpy.
> > I have to correct myself, I meant to suggest strscpy(dst, src, size).
> > Passing
> > the size for safety seems important, and unlike strncpy() it takes care of
> > the
> > leading zero.
> Yes, we use strscpy() for copying all the strings.

Indeed, I had miss-read, then you simply need to remove the code you added to
force the last byte to be 0, this is not needed with that function.

Nicolas

> > 
> > Nicolas
> 
> Thanks
> 
> Zhentao
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251215/7b101226/attachment-0001.sig>

From maz at kernel.org  Mon Dec 15 05:58:40 2025
From: maz at kernel.org (Marc Zyngier)
Date: Mon, 15 Dec 2025 13:58:40 +0000
Subject: [PATCH v2 2/4] KVM: arm64: Print register encoding if there's no accessor
In-Reply-To: <20251215114409.212512-3-alexandru.elisei@arm.com>
References: <20251215114409.212512-1-alexandru.elisei@arm.com>
	<20251215114409.212512-3-alexandru.elisei@arm.com>
Message-ID: <86ike7onhr.wl-maz@kernel.org>

On Mon, 15 Dec 2025 11:44:07 +0000,
Alexandru Elisei <alexandru.elisei at arm.com> wrote:
> 
> Configuring a register trap without specifying an accessor function is
> abviously a bug. Instead of calling die() when that happens, let's be a bit
> more helpful and print the register encoding and kill the virtual machine
> instead.
> 
> Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
> ---
>  arch/arm64/kvm/sys_regs.c | 8 +++++++-
>  1 file changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index c8fd7c6a12a1..d669f6fef177 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -4668,7 +4668,13 @@ static void perform_access(struct kvm_vcpu *vcpu,
>  	 * that we don't know how to handle. This certainly qualifies
>  	 * as a gross bug that should be fixed right away.
>  	 */
> -	BUG_ON(!r->access);
> +	if (!r->access) {
> +		KVM_BUG(1, vcpu->kvm,
> +			"Unexpected access to register: { Op0(%2u), Op1(%2u), CRn(%2u), CRm(%2u), Op2(%2u) } (%s)",
> +			params->Op0, params->Op1, params->CRn, params->CRm, params->Op2,
> +			str_write_read(params->is_write));
> +		return;
> +	}

Why not writing

	if (KVM_BUG(!r>access, ...))
		return;

instead? And you could reuse the format that's already defined in
print_sys_reg_msg().

You could instead consider injecting an UNDEF in the guest, which I
find more palatable than this "vm_bugged" stuff. It would at least be
consistent with the "register does not exist in the sysreg table"
approach that we already have.

Thanks,

	M.

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


From broonie at kernel.org  Mon Dec 15 05:58:47 2025
From: broonie at kernel.org (Mark Brown)
Date: Mon, 15 Dec 2025 22:58:47 +0900
Subject: [PATCH RESEND] ASoC: mediatek: mt8195: optimize property
 formatting error handling by using scnprintf()
In-Reply-To: <20251212044408.1286-2-hariconscious@gmail.com>
References: <20251212044408.1286-2-hariconscious@gmail.com>
Message-ID: <176580712756.161056.16246291831827319109.b4-ty@kernel.org>

On Fri, 12 Dec 2025 10:14:09 +0530, hariconscious at gmail.com wrote:
> Replace snprintf() with scnprintf() when constructing the property
> and remove negative return error handling as scnprintf() returns the
> actual number of bytes written to buffer.
> 
> snprintf() as defined by the C99 standard,returns the number of
> characters that *would have been* written if enough space were
> available.Use scnprintf() that returns the actual number of
> characters written.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next

Thanks!

[1/1] ASoC: mediatek: mt8195: optimize property formatting error handling by using scnprintf()
      commit: 180cdb96e821e30528b02708b927c93daa0ed40b

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark



From broonie at kernel.org  Mon Dec 15 05:59:22 2025
From: broonie at kernel.org (Mark Brown)
Date: Mon, 15 Dec 2025 22:59:22 +0900
Subject: [PATCH v2 0/6] Support ECSPI dynamic burst feature for DMA
 mode
In-Reply-To: <20251202075503.2448339-1-carlos.song@nxp.com>
References: <20251202075503.2448339-1-carlos.song@nxp.com>
Message-ID: <176580716285.161463.10166271924842509723.b4-ty@kernel.org>

On Tue, 02 Dec 2025 15:54:57 +0800, Carlos Song wrote:
> ECSPI has a low throughput because of no dynamic burst support, it
> transfers only one word per frame in DMA mode, causing SCLK stalls
> between words due to BURST_LENGTH updates.
> 
> This patch set is to support ECSPI dynamic burst feature to help improve
> the ECSPI DMA mode performance.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next

Thanks!

[1/6] spi: imx: group spi_imx_dma_configure() with spi_imx_dma_transfer()
      commit: c64f62b036aed30626cb30fa82d3ec4a13fa83df
[2/6] spi: imx: introduce helper to clear DMA mode logic
      commit: 5395bb7f7c361310d0f329c8169d2190809b05c1
[3/6] spi: imx: avoid dmaengine_terminate_all() on TX prep failure
      commit: a5f298581d454c5ea77c5fb6f4ee1bff61eb2b2c
[4/6] spi: imx: handle DMA submission errors with dma_submit_error()
      commit: a450c8b77f929f5f9f5236861761a8c5cab22023
[5/6] spi: imx: support dynamic burst length for ECSPI DMA mode
      commit: faa8e404ad8e686cb98c51dc507fdcacfb8020ce
[6/6] spi: imx: enable DMA mode for target operation
      commit: ba9b28652c75b07383e267328f1759195d5430f7

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark



From broonie at kernel.org  Mon Dec 15 05:59:25 2025
From: broonie at kernel.org (Mark Brown)
Date: Mon, 15 Dec 2025 22:59:25 +0900
Subject: [PATCH v3 0/6] Support ECSPI dynamic burst feature for DMA
 mode
In-Reply-To: <20251203085949.2922166-1-carlos.song@nxp.com>
References: <20251203085949.2922166-1-carlos.song@nxp.com>
Message-ID: <176580716540.161463.10558713364568567703.b4-ty@kernel.org>

On Wed, 03 Dec 2025 16:59:43 +0800, Carlos Song wrote:
> ECSPI has a low throughput because of no dynamic burst support, it
> transfers only one word per frame in DMA mode, causing SCLK stalls
> between words due to BURST_LENGTH updates.
> 
> This patch set is to support ECSPI dynamic burst feature to help improve
> the ECSPI DMA mode performance.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next

Thanks!

[1/6] spi: imx: group spi_imx_dma_configure() with spi_imx_dma_transfer()
      commit: c64f62b036aed30626cb30fa82d3ec4a13fa83df
[2/6] spi: imx: introduce helper to clear DMA mode logic
      commit: 5395bb7f7c361310d0f329c8169d2190809b05c1
[3/6] spi: imx: avoid dmaengine_terminate_all() on TX prep failure
      commit: a5f298581d454c5ea77c5fb6f4ee1bff61eb2b2c
[4/6] spi: imx: handle DMA submission errors with dma_submit_error()
      commit: a450c8b77f929f5f9f5236861761a8c5cab22023
[5/6] spi: imx: support dynamic burst length for ECSPI DMA mode
      commit: faa8e404ad8e686cb98c51dc507fdcacfb8020ce
[6/6] spi: imx: enable DMA mode for target operation
      commit: ba9b28652c75b07383e267328f1759195d5430f7

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark



From broonie at kernel.org  Mon Dec 15 05:59:30 2025
From: broonie at kernel.org (Mark Brown)
Date: Mon, 15 Dec 2025 22:59:30 +0900
Subject: [PATCH 0/8] spi: stm32: Update for OSPI and QSPI drivers
In-Reply-To: <20251205-upstream_qspi_ospi_updates-v1-0-7e6c8b9f5141@foss.st.com>
References: <20251205-upstream_qspi_ospi_updates-v1-0-7e6c8b9f5141@foss.st.com>
Message-ID: <176580717045.161463.13864912582865667097.b4-ty@kernel.org>

On Fri, 05 Dec 2025 10:04:50 +0100, Patrice Chotard wrote:
> This serie applies the following updates on the spi-stm32-ospi and
> spi-stm32-qspi dirvers :
> 
>   _ Update FIFO accesses using u16 and u32 when possible instead of u8
>     only to optimize throughput.
>   _ Replace Transmit Complete and Transmit Error interrupt management by
>     usage of read_poll_timeout_atomic() to optimize throughtput.
>   _ Simplify Status Match interrupt check.
>   _ Set DMA burst configuration dynamically.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next

Thanks!

[1/8] spi: stm32-ospi: Set DMA maxburst dynamically
      commit: e35a7607e05d59d35e937b80532ae93d1dd2493f
[2/8] spi: stm32-ospi: Optimize FIFO accesses using u16 or u32
      commit: cfe58ffc95a601988702df6f3462cb54dde467e9
[3/8] spi: stm32-ospi: Remove CR_TCIE and CR_TEIE irq usage
      commit: f6ed06926b510f54a0817567ffd458194ed90bd6
[4/8] spi: stm32-ospi: Simplify SMIE interrupt test
      commit: e2f0ea18e560e5fa6180f52dffe434525a0cf86b
[5/8] spi: stm32-qspi: Set DMA maxburst dynamically
      commit: 4ef80c71c62ab841db9b1a9d74ffe043c60f6222
[6/8] spi: stm32-qspi: Optimize FIFO accesses using u16 or u32
      commit: 1ca91281649547efa4be34584a304974c9601df1
[7/8] spi: stm32-qspi: Remove CR_TCIE and CR_TEIE irq usage
      commit: c5f76d888810bca2d46297a7b942e10bc8cc69dd
[8/8] spi: stm32-qspi: Simplify SMIE interrupt test
      commit: fee876b2ec75dcc18fdea154eae1f5bf14d82659

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark



From broonie at kernel.org  Mon Dec 15 05:59:35 2025
From: broonie at kernel.org (Mark Brown)
Date: Mon, 15 Dec 2025 22:59:35 +0900
Subject: [PATCH v2 0/8] spi: stm32: Update for OSPI and QSPI drivers
In-Reply-To: <20251208-upstream_qspi_ospi_updates-v2-0-62526c9467dc@foss.st.com>
References: <20251208-upstream_qspi_ospi_updates-v2-0-62526c9467dc@foss.st.com>
Message-ID: <176580717503.161463.8142752344614450653.b4-ty@kernel.org>

On Mon, 08 Dec 2025 08:29:07 +0100, Patrice Chotard wrote:
> This serie applies the following updates on the spi-stm32-ospi and
> spi-stm32-qspi dirvers :
> 
>   _ Update FIFO accesses using u16 and u32 when possible instead of u8
>     only to optimize throughput.
>   _ Replace Transmit Complete and Transmit Error interrupt management by
>     usage of read_poll_timeout_atomic() to optimize throughtput.
>   _ Simplify Status Match interrupt check.
>   _ Set DMA burst configuration dynamically.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next

Thanks!

[1/8] spi: stm32-ospi: Set DMA maxburst dynamically
      commit: e35a7607e05d59d35e937b80532ae93d1dd2493f
[2/8] spi: stm32-ospi: Optimize FIFO accesses using u16 or u32
      commit: cfe58ffc95a601988702df6f3462cb54dde467e9
[3/8] spi: stm32-ospi: Remove CR_TCIE and CR_TEIE irq usage
      commit: f6ed06926b510f54a0817567ffd458194ed90bd6
[4/8] spi: stm32-ospi: Simplify SMIE interrupt test
      commit: e2f0ea18e560e5fa6180f52dffe434525a0cf86b
[5/8] spi: stm32-qspi: Set DMA maxburst dynamically
      commit: 4ef80c71c62ab841db9b1a9d74ffe043c60f6222
[6/8] spi: stm32-qspi: Optimize FIFO accesses using u16 or u32
      commit: 1ca91281649547efa4be34584a304974c9601df1
[7/8] spi: stm32-qspi: Remove CR_TCIE and CR_TEIE irq usage
      commit: c5f76d888810bca2d46297a7b942e10bc8cc69dd
[8/8] spi: stm32-qspi: Simplify SMIE interrupt test
      commit: fee876b2ec75dcc18fdea154eae1f5bf14d82659

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark



From nicolas.frattaroli at collabora.com  Mon Dec 15 06:09:16 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Mon, 15 Dec 2025 15:09:16 +0100
Subject: [PATCH v5 0/8] drm/rockchip: No more post-atomic_check fixups
Message-ID: <20251215-vop2-atomic-fixups-v5-0-83463c075a8d@collabora.com>

I'm taking over this series to get it across the finish line. Original
cover letter from Daniel Stone on v1:

> Hi,
> This series is a pretty small and consistent one for VOP2. The atomic
> uAPI very clearly specifies that drivers should either do what userspace
> requested (on a successful commit), or fail atomic_check if it is not
> for any reason possible to do what userspace requested.
> 
> VOP2 is unfortunately littered with a bunch of cases where it will apply
> fixups after atomic_check - doing something different to what userspace
> requested, e.g. clipping or aligning regions - or throw error messages
> into the log when userspace does request a condition which can't be met.
> 
> Doing something different to what was requested is bad because it
> results in unexpected visual output which can look like artifacts.
> Throwing errors into the log is bad because generic userspace will
> reasonably attempt to try any configuration it can. For example,
> throwing an error message on a plane not being aligned to a 16 pixel
> boundary can result in 15 frames' worth of error output in the log when
> a window is being animated across a screen.
> 
> This series removes all post-check fixups - failing the check if the
> configuration cannot be applied - and also demotes all messages about
> unsupported configurations to DEBUG_KMS.
> 
> Cheers,
> Daniel

---
Changes in v5:
- Reword message in "Switch impossible format conditional to WARN_ON" to
  remove the reference to "staggering on", as it previously didn't do
  that either.
- Return from atomic_update if any of the WARN_ON conditionals came
  true.
- Link to v4: https://lore.kernel.org/r/20251211-vop2-atomic-fixups-v4-0-5d50eda26bf8 at collabora.com

Changes in v4:
- s/64-byte/64-pixel/
- Link to v3: https://lore.kernel.org/r/20251209-vop2-atomic-fixups-v3-0-07c48f0f1f0d at collabora.com

Changes in v3:
- Change the AFBC source rectangle debug message to talk about 4-pixel
  alignment instead of 4-byte alignment.
- Fix another eSmart->Esmart casing case in a debug message
- Link to v2: https://lore.kernel.org/r/20251206-vop2-atomic-fixups-v2-0-7fb45bbfbebd at collabora.com

Changes in v2:
- Dropped patches [1, 5] as they were already applied.
- Changed the patch subject to use prefix "drm/rockchip: vop2:" for the
  remaining ones.
- Fixed a checkpatch nag about commenting style in "Switch impossible
  pos conditional to WARN_ON".
- Reworded "eSmart" to "Esmart" for consistency, and to avoid drawing
  Tim Apple's ire.
- Make the hopefully impossible WARN_ON format conditional in
  vop2_plane_atomic_check still bubble the error up to userspace,
  instead of continuing on.
- Use dest_w instead of dsp_w in patch "Enforce scaling workaround
  in plane_check", to avoid a compiler error.
- Only reject non-multiple-of-4-pixel-wide framebuffers on
  RK3566/RK3568, as the other SoCs have no such limitation. (Thank you
  to Andy Yan for doing the research to confirm this!)
- Consequently also only WARN_ON if this condition is violated in
  atomic_update on those SoCs.
- Link to v1: https://lore.kernel.org/dri-devel/20251015110042.41273-1-daniels at collabora.com/

Signed-off-by: Daniel Stone <daniels at collabora.com>
Cc: Daniel Stone <daniels at collabora.com>
To: Chaoyi Chen <chaoyi.chen at rock-chips.com>
To: Sandy Huang <hjc at rock-chips.com>
To: Heiko St?bner <heiko at sntech.de>
To: Andy Yan <andy.yan at rock-chips.com>
To: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
To: Maxime Ripard <mripard at kernel.org>
To: Thomas Zimmermann <tzimmermann at suse.de>
To: David Airlie <airlied at gmail.com>
To: Simona Vetter <simona at ffwll.ch>
Cc: dri-devel at lists.freedesktop.org
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-rockchip at lists.infradead.org
Cc: linux-kernel at vger.kernel.org
Cc: kernel at collabora.com
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>

---
Daniel Stone (8):
      drm/rockchip: vop2: Switch impossible format conditional to WARN_ON
      drm/rockchip: vop2: Switch impossible pos conditional to WARN_ON
      drm/rockchip: vop2: Fix Esmart test condition
      drm/rockchip: vop2: Enforce scaling workaround in plane_check
      drm/rockchip: vop2: Enforce AFBC source alignment in plane_check
      drm/rockchip: vop2: Enforce AFBC transform stride align in plane_check
      drm/rockchip: vop2: Use drm_is_afbc helper function
      drm/rockchip: vop2: Simplify format_mod_supported

 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 137 ++++++++++++---------------
 1 file changed, 62 insertions(+), 75 deletions(-)
---
base-commit: 3e7f562e20ee87a25e104ef4fce557d39d62fa85
change-id: 20251206-vop2-atomic-fixups-0c30e0980f85

Best regards,
-- 
Nicolas Frattaroli <nicolas.frattaroli at collabora.com>



From nicolas.frattaroli at collabora.com  Mon Dec 15 06:09:17 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Mon, 15 Dec 2025 15:09:17 +0100
Subject: [PATCH v5 1/8] drm/rockchip: vop2: Switch impossible format
 conditional to WARN_ON
In-Reply-To: <20251215-vop2-atomic-fixups-v5-0-83463c075a8d@collabora.com>
References: <20251215-vop2-atomic-fixups-v5-0-83463c075a8d@collabora.com>
Message-ID: <20251215-vop2-atomic-fixups-v5-1-83463c075a8d@collabora.com>

From: Daniel Stone <daniels at collabora.com>

We should never be able to create a framebuffer with an unsupported
format, so throw a warning if this ever happens.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 498df0ce4680..20b49209ddcd 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1030,7 +1030,8 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
 		return 0;
 
 	format = vop2_convert_format(fb->format->format);
-	if (format < 0)
+	/* We shouldn't be able to create a fb for an unsupported format */
+	if (WARN_ON(format < 0))
 		return format;
 
 	/* Co-ordinates have now been clipped */

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Mon Dec 15 06:09:18 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Mon, 15 Dec 2025 15:09:18 +0100
Subject: [PATCH v5 2/8] drm/rockchip: vop2: Switch impossible pos
 conditional to WARN_ON
In-Reply-To: <20251215-vop2-atomic-fixups-v5-0-83463c075a8d@collabora.com>
References: <20251215-vop2-atomic-fixups-v5-0-83463c075a8d@collabora.com>
Message-ID: <20251215-vop2-atomic-fixups-v5-2-83463c075a8d@collabora.com>

From: Daniel Stone <daniels at collabora.com>

We already clip the plane to the display bounds in atomic_check, and
ensure that it is sufficiently sized. Instead of trying to catch this
and adjust for it in atomic_update, just assert that atomic_check has
done its job.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 28 ++++++++--------------------
 1 file changed, 8 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 20b49209ddcd..1cad5a8ece61 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1214,28 +1214,16 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
 	src_w = drm_rect_width(src) >> 16;
 	src_h = drm_rect_height(src) >> 16;
 	dsp_w = drm_rect_width(dest);
-
-	if (dest->x1 + dsp_w > adjusted_mode->hdisplay) {
-		drm_dbg_kms(vop2->drm,
-			    "vp%d %s dest->x1[%d] + dsp_w[%d] exceed mode hdisplay[%d]\n",
-			    vp->id, win->data->name, dest->x1, dsp_w, adjusted_mode->hdisplay);
-		dsp_w = adjusted_mode->hdisplay - dest->x1;
-		if (dsp_w < 4)
-			dsp_w = 4;
-		src_w = dsp_w * src_w / drm_rect_width(dest);
-	}
-
 	dsp_h = drm_rect_height(dest);
 
-	if (dest->y1 + dsp_h > adjusted_mode->vdisplay) {
-		drm_dbg_kms(vop2->drm,
-			    "vp%d %s dest->y1[%d] + dsp_h[%d] exceed mode vdisplay[%d]\n",
-			    vp->id, win->data->name, dest->y1, dsp_h, adjusted_mode->vdisplay);
-		dsp_h = adjusted_mode->vdisplay - dest->y1;
-		if (dsp_h < 4)
-			dsp_h = 4;
-		src_h = dsp_h * src_h / drm_rect_height(dest);
-	}
+	/* drm_atomic_helper_check_plane_state calls drm_rect_clip_scaled for
+	 * us, which keeps our planes bounded within the CRTC active area
+	 */
+	if (WARN_ON(dest->x1 + dsp_w > adjusted_mode->hdisplay) ||
+	    WARN_ON(dest->y1 + dsp_h > adjusted_mode->vdisplay) ||
+	    WARN_ON(dsp_w < 4) || WARN_ON(dsp_h < 4) ||
+	    WARN_ON(src_w < 4) || WARN_ON(src_h < 4))
+		return;
 
 	/*
 	 * This is workaround solution for IC design:

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Mon Dec 15 06:09:19 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Mon, 15 Dec 2025 15:09:19 +0100
Subject: [PATCH v5 3/8] drm/rockchip: vop2: Fix Esmart test condition
In-Reply-To: <20251215-vop2-atomic-fixups-v5-0-83463c075a8d@collabora.com>
References: <20251215-vop2-atomic-fixups-v5-0-83463c075a8d@collabora.com>
Message-ID: <20251215-vop2-atomic-fixups-v5-3-83463c075a8d@collabora.com>

From: Daniel Stone <daniels at collabora.com>

If we want to find out if a window is Esmart or not, test for not being
a cluster window, rather than AFBDC presence.

No functional effect as only cluster windows support AFBC decode.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 1cad5a8ece61..fbcc655cb583 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1229,12 +1229,10 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
 	 * This is workaround solution for IC design:
 	 * esmart can't support scale down when src_w % 16 == 1.
 	 */
-	if (!(win->data->feature & WIN_FEATURE_AFBDC)) {
-		if (src_w > dsp_w && (src_w & 0xf) == 1) {
-			drm_dbg_kms(vop2->drm, "vp%d %s act_w[%d] MODE 16 == 1\n",
-				    vp->id, win->data->name, src_w);
-			src_w -= 1;
-		}
+	if (!vop2_cluster_window(win) && src_w > dsp_w && (src_w & 1)) {
+		drm_dbg_kms(vop2->drm, "vp%d %s act_w[%d] MODE 16 == 1\n",
+			    vp->id, win->data->name, src_w);
+		src_w -= 1;
 	}
 
 	if (afbc_en && src_w % 4) {

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Mon Dec 15 06:09:20 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Mon, 15 Dec 2025 15:09:20 +0100
Subject: [PATCH v5 4/8] drm/rockchip: vop2: Enforce scaling workaround in
 plane_check
In-Reply-To: <20251215-vop2-atomic-fixups-v5-0-83463c075a8d@collabora.com>
References: <20251215-vop2-atomic-fixups-v5-0-83463c075a8d@collabora.com>
Message-ID: <20251215-vop2-atomic-fixups-v5-4-83463c075a8d@collabora.com>

From: Daniel Stone <daniels at collabora.com>

It seems only cluster windows are capable of applying downscaling when
the source region has an odd width. Instead of applying a workaround
inside atomic_update, fail the plane check if this is requested.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index fbcc655cb583..ded8b9952c6d 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -998,6 +998,7 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
 	struct drm_crtc *crtc = pstate->crtc;
 	struct drm_crtc_state *cstate;
 	struct vop2_video_port *vp;
+	struct vop2_win *win = to_vop2_win(plane);
 	struct vop2 *vop2;
 	const struct vop2_data *vop2_data;
 	struct drm_rect *dest = &pstate->dst;
@@ -1065,6 +1066,16 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
 		return -EINVAL;
 	}
 
+	/*
+	 * This is workaround solution for IC design:
+	 * esmart can't support scale down when src_w % 16 == 1.
+	 */
+	if (!vop2_cluster_window(win) && src_w > dest_w && (src_w & 1)) {
+		drm_dbg_kms(vop2->drm,
+			    "Esmart windows cannot downscale odd-width source regions\n");
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
@@ -1225,16 +1236,6 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
 	    WARN_ON(src_w < 4) || WARN_ON(src_h < 4))
 		return;
 
-	/*
-	 * This is workaround solution for IC design:
-	 * esmart can't support scale down when src_w % 16 == 1.
-	 */
-	if (!vop2_cluster_window(win) && src_w > dsp_w && (src_w & 1)) {
-		drm_dbg_kms(vop2->drm, "vp%d %s act_w[%d] MODE 16 == 1\n",
-			    vp->id, win->data->name, src_w);
-		src_w -= 1;
-	}
-
 	if (afbc_en && src_w % 4) {
 		drm_dbg_kms(vop2->drm, "vp%d %s src_w[%d] not 4 pixel aligned\n",
 			    vp->id, win->data->name, src_w);

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Mon Dec 15 06:09:21 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Mon, 15 Dec 2025 15:09:21 +0100
Subject: [PATCH v5 5/8] drm/rockchip: vop2: Enforce AFBC source alignment
 in plane_check
In-Reply-To: <20251215-vop2-atomic-fixups-v5-0-83463c075a8d@collabora.com>
References: <20251215-vop2-atomic-fixups-v5-0-83463c075a8d@collabora.com>
Message-ID: <20251215-vop2-atomic-fixups-v5-5-83463c075a8d@collabora.com>

From: Daniel Stone <daniels at collabora.com>

Planes can only source AFBC framebuffers at multiples of 4px wide on
RK3566/RK3568. Instead of clipping on all SoCs when the user asks for an
unaligned source rectangle, reject the configuration in the plane's
atomic check on RK3566/RK3568 only.

Signed-off-by: Daniel Stone <daniels at collabora.com>
[Make RK3566/RK3568 specific, reword message, s/byte/pixel/]
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index ded8b9952c6d..0eab3370f088 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1076,6 +1076,13 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
 		return -EINVAL;
 	}
 
+	if (vop2->version == VOP_VERSION_RK3568 && drm_is_afbc(fb->modifier) && src_w % 4) {
+		drm_dbg_kms(vop2->drm,
+			    "AFBC source rectangles must be 4-pixel aligned; is %d\n",
+			    src_w);
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
@@ -1236,11 +1243,9 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
 	    WARN_ON(src_w < 4) || WARN_ON(src_h < 4))
 		return;
 
-	if (afbc_en && src_w % 4) {
-		drm_dbg_kms(vop2->drm, "vp%d %s src_w[%d] not 4 pixel aligned\n",
-			    vp->id, win->data->name, src_w);
-		src_w = ALIGN_DOWN(src_w, 4);
-	}
+	if (vop2->version == VOP_VERSION_RK3568 && drm_is_afbc(fb->modifier))
+		if (WARN_ON(src_w % 4))
+			return;
 
 	act_info = (src_h - 1) << 16 | ((src_w - 1) & 0xffff);
 	dsp_info = (dsp_h - 1) << 16 | ((dsp_w - 1) & 0xffff);

-- 
2.52.0



From horms at kernel.org  Mon Dec 15 06:11:51 2025
From: horms at kernel.org (Simon Horman)
Date: Mon, 15 Dec 2025 14:11:51 +0000
Subject: [PATCH net] net: airoha: Move net_devs registration in a
 dedicated routine
In-Reply-To: <20251214-airoha-fix-dev-registration-v1-1-860e027ad4c6@kernel.org>
References: <20251214-airoha-fix-dev-registration-v1-1-860e027ad4c6@kernel.org>
Message-ID: <aUAXJ01iHnSJtItt@horms.kernel.org>

On Sun, Dec 14, 2025 at 10:30:07AM +0100, Lorenzo Bianconi wrote:
> Since airoha_probe() is not executed under rtnl lock, there is small race
> where a given device is configured by user-space while the remaining ones
> are not completely loaded from the dts yet. This condition will allow a
> hw device misconfiguration since there are some conditions (e.g. GDM2 check
> in airoha_dev_init()) that require all device are properly loaded from the
> device tree. Fix the issue moving net_devices registration at the end of
> the airoha_probe routine.
> 
> Fixes: 9cd451d414f6e ("net: airoha: Add loopback support for GDM2")
> Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>

Hi Lorenzo,

As a fix this patch looks good to me.

Reviewed-by: Simon Horman <horms at kernel.org>

But I am somewhat surprised that the netdev isn't unregistered earlier
both in airoha_remove() and the unwind ladder of airoha_probe().


From nicolas.frattaroli at collabora.com  Mon Dec 15 06:09:22 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Mon, 15 Dec 2025 15:09:22 +0100
Subject: [PATCH v5 6/8] drm/rockchip: vop2: Enforce AFBC transform stride
 align in plane_check
In-Reply-To: <20251215-vop2-atomic-fixups-v5-0-83463c075a8d@collabora.com>
References: <20251215-vop2-atomic-fixups-v5-0-83463c075a8d@collabora.com>
Message-ID: <20251215-vop2-atomic-fixups-v5-6-83463c075a8d@collabora.com>

From: Daniel Stone <daniels at collabora.com>

Make sure we can't break the hardware by requesting an unsupported
configuration.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 0eab3370f088..7591a34ba912 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1083,6 +1083,15 @@ static int vop2_plane_atomic_check(struct drm_plane *plane,
 		return -EINVAL;
 	}
 
+	if (drm_is_afbc(fb->modifier) &&
+	    pstate->rotation &
+		(DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270) &&
+	    (fb->pitches[0] << 3) / vop2_get_bpp(fb->format) % 64) {
+		drm_dbg_kms(vop2->drm,
+			    "AFBC buffers must be 64-pixel aligned for horizontal rotation or mirroring\n");
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
@@ -1290,9 +1299,6 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
 		 * with WIN_VIR_STRIDE.
 		 */
 		stride = (fb->pitches[0] << 3) / bpp;
-		if ((stride & 0x3f) && (xmirror || rotate_90 || rotate_270))
-			drm_dbg_kms(vop2->drm, "vp%d %s stride[%d] not 64 pixel aligned\n",
-				    vp->id, win->data->name, stride);
 
 		 /* It's for head stride, each head size is 16 byte */
 		stride = ALIGN(stride, block_w) / block_w * 16;

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Mon Dec 15 06:09:23 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Mon, 15 Dec 2025 15:09:23 +0100
Subject: [PATCH v5 7/8] drm/rockchip: vop2: Use drm_is_afbc helper function
In-Reply-To: <20251215-vop2-atomic-fixups-v5-0-83463c075a8d@collabora.com>
References: <20251215-vop2-atomic-fixups-v5-0-83463c075a8d@collabora.com>
Message-ID: <20251215-vop2-atomic-fixups-v5-7-83463c075a8d@collabora.com>

From: Daniel Stone <daniels at collabora.com>

We don't need to do a long open-coded walk here; we can simply check the
modifier value.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 7591a34ba912..707b48c7e9d8 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1207,7 +1207,7 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
 		return;
 	}
 
-	afbc_en = rockchip_afbc(plane, fb->modifier);
+	afbc_en = drm_is_afbc(fb->modifier);
 
 	offset = (src->x1 >> 16) * fb->format->cpp[0];
 

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Mon Dec 15 06:09:24 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Mon, 15 Dec 2025 15:09:24 +0100
Subject: [PATCH v5 8/8] drm/rockchip: vop2: Simplify format_mod_supported
In-Reply-To: <20251215-vop2-atomic-fixups-v5-0-83463c075a8d@collabora.com>
References: <20251215-vop2-atomic-fixups-v5-0-83463c075a8d@collabora.com>
Message-ID: <20251215-vop2-atomic-fixups-v5-8-83463c075a8d@collabora.com>

From: Daniel Stone <daniels at collabora.com>

Make it a little less convoluted, and just directly check if the
combination of plane + format + modifier is supported.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 56 +++++++++++-----------------
 1 file changed, 22 insertions(+), 34 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 707b48c7e9d8..a0099e4dd4ea 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -367,59 +367,47 @@ static bool is_yuv_output(u32 bus_format)
 	}
 }
 
-static bool rockchip_afbc(struct drm_plane *plane, u64 modifier)
-{
-	int i;
-
-	if (modifier == DRM_FORMAT_MOD_LINEAR)
-		return false;
-
-	for (i = 0 ; i < plane->modifier_count; i++)
-		if (plane->modifiers[i] == modifier)
-			return true;
-
-	return false;
-}
-
 static bool rockchip_vop2_mod_supported(struct drm_plane *plane, u32 format,
 					u64 modifier)
 {
 	struct vop2_win *win = to_vop2_win(plane);
 	struct vop2 *vop2 = win->vop2;
+	int i;
 
+	/* No support for implicit modifiers */
 	if (modifier == DRM_FORMAT_MOD_INVALID)
 		return false;
 
-	if (vop2->version == VOP_VERSION_RK3568) {
-		if (vop2_cluster_window(win)) {
-			if (modifier == DRM_FORMAT_MOD_LINEAR) {
-				drm_dbg_kms(vop2->drm,
-					    "Cluster window only supports format with afbc\n");
-				return false;
-			}
-		}
+	/* The cluster window on 3568 is AFBC-only */
+	if (vop2->version == VOP_VERSION_RK3568 && vop2_cluster_window(win) &&
+	    !drm_is_afbc(modifier)) {
+		drm_dbg_kms(vop2->drm,
+			    "Cluster window only supports format with afbc\n");
+		return false;
 	}
 
-	if (format == DRM_FORMAT_XRGB2101010 || format == DRM_FORMAT_XBGR2101010) {
-		if (vop2->version == VOP_VERSION_RK3588) {
-			if (!rockchip_afbc(plane, modifier)) {
-				drm_dbg_kms(vop2->drm, "Only support 32 bpp format with afbc\n");
-				return false;
-			}
-		}
+	/* 10bpc formats on 3588 are AFBC-only */
+	if (vop2->version == VOP_VERSION_RK3588 && !drm_is_afbc(modifier) &&
+	    (format == DRM_FORMAT_XRGB2101010 || format == DRM_FORMAT_XBGR2101010)) {
+		drm_dbg_kms(vop2->drm, "Only support 10bpc format with afbc\n");
+		return false;
 	}
 
+	/* Linear is otherwise supported everywhere */
 	if (modifier == DRM_FORMAT_MOD_LINEAR)
 		return true;
 
-	if (!rockchip_afbc(plane, modifier)) {
-		drm_dbg_kms(vop2->drm, "Unsupported format modifier 0x%llx\n",
-			    modifier);
-
+	/* Not all format+modifier combinations are allowable */
+	if (vop2_convert_afbc_format(format) == VOP2_AFBC_FMT_INVALID)
 		return false;
+
+	/* Different windows have different format/modifier support */
+	for (i = 0; i < plane->modifier_count; i++) {
+		if (plane->modifiers[i] == modifier)
+			return true;
 	}
 
-	return vop2_convert_afbc_format(format) >= 0;
+	return false;
 }
 
 /*

-- 
2.52.0



From Sascha.Bischoff at arm.com  Mon Dec 15 06:15:03 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Mon, 15 Dec 2025 14:15:03 +0000
Subject: [PATCH 02/32] KVM: arm64: gic-v3: Switch vGIC-v3 to use generated
 ICH_VMCR_EL2
In-Reply-To: <86ldj4nesf.wl-maz@kernel.org>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	 <20251212152215.675767-3-sascha.bischoff@arm.com>
	 <86ldj4nesf.wl-maz@kernel.org>
Message-ID: <ece413c8b70e30f39052fb29371e9a75c239ff9e.camel@arm.com>

On Mon, 2025-12-15 at 11:52 +0000, Marc Zyngier wrote:
> On Fri, 12 Dec 2025 15:22:35 +0000,
> Sascha Bischoff <Sascha.Bischoff at arm.com> wrote:
> > 
> > From: Sascha Bischoff <Sascha.Bischoff at arm.com>
> > 
> > ?	/* EOImode == 0, nothing to be done here */
> > -	if (!(vmcr & ICH_VMCR_EOIM_MASK))
> > +	if (!FIELD_GET(ICH_VMCR_EL2_VEOIM_MASK, vmcr))
> 
> nit: FIELD_GET() doesn't bring anything here. Similar comment applies
> to most 'if (val & MASK)' constructs that get changed here.

I've reverted all bare instances of `val & MASK` (without shifts) to
not use FIELD_GET(). Anything with an additional shift I've left as a
FIELD_GET().
?
> > ?static void __vgic_v3_read_igrpen0(struct kvm_vcpu *vcpu, u32
> > vmcr, int rt)
> > ?{
> > -	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG0_MASK));
> > +	vcpu_set_reg(vcpu, rt,
> > !!FIELD_GET(ICH_VMCR_EL2_VENG0_MASK, vmcr));
> 
> Here, !! is actually really superfluous and makes it harder to
> understand what is being done. Similar thing for IRGPEN1.

Dropped those !! as part of this change.

> Apart from these two points, this looks OK to me.
> 
> Thanks,
> 
> 	M.

Thanks,
Sascha


From u.kleine-koenig at baylibre.com  Mon Dec 15 06:16:30 2025
From: u.kleine-koenig at baylibre.com (=?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?=)
Date: Mon, 15 Dec 2025 15:16:30 +0100
Subject: [PATCH v2 00/17] tee: Use bus callbacks instead of driver callbacks
Message-ID: <cover.1765791463.git.u.kleine-koenig@baylibre.com>

Hello,

the objective of this series is to make tee driver stop using callbacks
in struct device_driver. These were superseded by bus methods in 2006
(commit 594c8281f905 ("[PATCH] Add bus_type probe, remove, shutdown
methods.")) but nobody cared to convert all subsystems accordingly.

Here the tee drivers are converted. The first commit is somewhat
unrelated, but simplifies the conversion (and the drivers). It
introduces driver registration helpers that care about setting the bus
and owner. (The latter is missing in all drivers, so by using these
helpers the drivers become more correct.)

v1 of this series is available at
https://lore.kernel.org/all/cover.1765472125.git.u.kleine-koenig at baylibre.com

Changes since v1:

 - rebase to v6.19-rc1 (no conflicts)
 - add tags received so far
 - fix whitespace issues pointed out by Sumit Garg
 - fix shutdown callback to shutdown and not remove

As already noted in v1's cover letter, this series should go in during a
single merge window as there are runtime warnings when the series is
only applied partially. Sumit Garg suggested to apply the whole series
via Jens Wiklander's tree.
If this is done the dependencies in this series are honored, in case the
plan changes: Patches #4 - #17 depend on the first two.

Note this series is only build tested.

Uwe Kleine-K?nig (17):
  tee: Add some helpers to reduce boilerplate for tee client drivers
  tee: Add probe, remove and shutdown bus callbacks to tee_client_driver
  tee: Adapt documentation to cover recent additions
  hwrng: optee - Make use of module_tee_client_driver()
  hwrng: optee - Make use of tee bus methods
  rtc: optee: Migrate to use tee specific driver registration function
  rtc: optee: Make use of tee bus methods
  efi: stmm: Make use of module_tee_client_driver()
  efi: stmm: Make use of tee bus methods
  firmware: arm_scmi: optee: Make use of module_tee_client_driver()
  firmware: arm_scmi: Make use of tee bus methods
  firmware: tee_bnxt: Make use of module_tee_client_driver()
  firmware: tee_bnxt: Make use of tee bus methods
  KEYS: trusted: Migrate to use tee specific driver registration
    function
  KEYS: trusted: Make use of tee bus methods
  tpm/tpm_ftpm_tee: Make use of tee specific driver registration
  tpm/tpm_ftpm_tee: Make use of tee bus methods

 Documentation/driver-api/tee.rst             | 18 +----
 drivers/char/hw_random/optee-rng.c           | 26 ++----
 drivers/char/tpm/tpm_ftpm_tee.c              | 31 +++++---
 drivers/firmware/arm_scmi/transports/optee.c | 32 +++-----
 drivers/firmware/broadcom/tee_bnxt_fw.c      | 30 ++-----
 drivers/firmware/efi/stmm/tee_stmm_efi.c     | 25 ++----
 drivers/rtc/rtc-optee.c                      | 27 ++-----
 drivers/tee/tee_core.c                       | 84 ++++++++++++++++++++
 include/linux/tee_drv.h                      | 12 +++
 security/keys/trusted-keys/trusted_tee.c     | 17 ++--
 10 files changed, 164 insertions(+), 138 deletions(-)

base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
-- 
2.47.3



From u.kleine-koenig at baylibre.com  Mon Dec 15 06:16:38 2025
From: u.kleine-koenig at baylibre.com (=?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?=)
Date: Mon, 15 Dec 2025 15:16:38 +0100
Subject: [PATCH v2 08/17] efi: stmm: Make use of module_tee_client_driver()
In-Reply-To: <cover.1765791463.git.u.kleine-koenig@baylibre.com>
References: <cover.1765791463.git.u.kleine-koenig@baylibre.com>
Message-ID: <6a56ee61e485703d548e9e44d53b2920b4e43ca6.1765791463.git.u.kleine-koenig@baylibre.com>

Reduce boilerplate by using the newly introduced module_tee_client_driver().
That takes care of assigning the driver's bus, so the explicit assigning
in this driver can be dropped.

Reviewed-by: Sumit Garg <sumit.garg at oss.qualcomm.com>
Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig at baylibre.com>
---
 drivers/firmware/efi/stmm/tee_stmm_efi.c | 14 +-------------
 1 file changed, 1 insertion(+), 13 deletions(-)

diff --git a/drivers/firmware/efi/stmm/tee_stmm_efi.c b/drivers/firmware/efi/stmm/tee_stmm_efi.c
index 65c0fe1ba275..5903811858b6 100644
--- a/drivers/firmware/efi/stmm/tee_stmm_efi.c
+++ b/drivers/firmware/efi/stmm/tee_stmm_efi.c
@@ -584,24 +584,12 @@ static struct tee_client_driver tee_stmm_efi_driver = {
 	.id_table	= tee_stmm_efi_id_table,
 	.driver		= {
 		.name		= "tee-stmm-efi",
-		.bus		= &tee_bus_type,
 		.probe		= tee_stmm_efi_probe,
 		.remove		= tee_stmm_efi_remove,
 	},
 };
 
-static int __init tee_stmm_efi_mod_init(void)
-{
-	return driver_register(&tee_stmm_efi_driver.driver);
-}
-
-static void __exit tee_stmm_efi_mod_exit(void)
-{
-	driver_unregister(&tee_stmm_efi_driver.driver);
-}
-
-module_init(tee_stmm_efi_mod_init);
-module_exit(tee_stmm_efi_mod_exit);
+module_tee_client_driver(tee_stmm_efi_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Ilias Apalodimas <ilias.apalodimas at linaro.org>");
-- 
2.47.3



From u.kleine-koenig at baylibre.com  Mon Dec 15 06:16:39 2025
From: u.kleine-koenig at baylibre.com (=?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?=)
Date: Mon, 15 Dec 2025 15:16:39 +0100
Subject: [PATCH v2 09/17] efi: stmm: Make use of tee bus methods
In-Reply-To: <cover.1765791463.git.u.kleine-koenig@baylibre.com>
References: <cover.1765791463.git.u.kleine-koenig@baylibre.com>
Message-ID: <b70ad65c88a82cf56c93cf17cf326213f8273e37.1765791463.git.u.kleine-koenig@baylibre.com>

The tee bus got dedicated callbacks for probe and remove.
Make use of these. This fixes a runtime warning about the driver needing
to be converted to the bus methods.

Reviewed-by: Sumit Garg <sumit.garg at oss.qualcomm.com>
Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig at baylibre.com>
---
 drivers/firmware/efi/stmm/tee_stmm_efi.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/firmware/efi/stmm/tee_stmm_efi.c b/drivers/firmware/efi/stmm/tee_stmm_efi.c
index 5903811858b6..7b04dd649629 100644
--- a/drivers/firmware/efi/stmm/tee_stmm_efi.c
+++ b/drivers/firmware/efi/stmm/tee_stmm_efi.c
@@ -520,8 +520,9 @@ static void tee_stmm_restore_efivars_generic_ops(void)
 	efivars_generic_ops_register();
 }
 
-static int tee_stmm_efi_probe(struct device *dev)
+static int tee_stmm_efi_probe(struct tee_client_device *tee_dev)
 {
+	struct device *dev = &tee_dev->dev;
 	struct tee_ioctl_open_session_arg sess_arg;
 	efi_status_t ret;
 	int rc;
@@ -571,21 +572,19 @@ static int tee_stmm_efi_probe(struct device *dev)
 	return 0;
 }
 
-static int tee_stmm_efi_remove(struct device *dev)
+static void tee_stmm_efi_remove(struct tee_client_device *dev)
 {
 	tee_stmm_restore_efivars_generic_ops();
-
-	return 0;
 }
 
 MODULE_DEVICE_TABLE(tee, tee_stmm_efi_id_table);
 
 static struct tee_client_driver tee_stmm_efi_driver = {
 	.id_table	= tee_stmm_efi_id_table,
+	.probe		= tee_stmm_efi_probe,
+	.remove		= tee_stmm_efi_remove,
 	.driver		= {
 		.name		= "tee-stmm-efi",
-		.probe		= tee_stmm_efi_probe,
-		.remove		= tee_stmm_efi_remove,
 	},
 };
 
-- 
2.47.3



From u.kleine-koenig at baylibre.com  Mon Dec 15 06:16:40 2025
From: u.kleine-koenig at baylibre.com (=?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?=)
Date: Mon, 15 Dec 2025 15:16:40 +0100
Subject: [PATCH v2 10/17] firmware: arm_scmi: optee: Make use of module_tee_client_driver()
In-Reply-To: <cover.1765791463.git.u.kleine-koenig@baylibre.com>
References: <cover.1765791463.git.u.kleine-koenig@baylibre.com>
Message-ID: <983988a9020a2829bbedfd599fb6a52f8867e37b.1765791463.git.u.kleine-koenig@baylibre.com>

Reduce boilerplate by using the newly introduced module_tee_client_driver().
That takes care of assigning the driver's bus, so the explicit assigning
in this driver can be dropped.

Reviewed-by: Sumit Garg <sumit.garg at oss.qualcomm.com>
Reviewed-by: Sudeep Holla <sudeep.holla at arm.com>
Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig at baylibre.com>
---
 drivers/firmware/arm_scmi/transports/optee.c | 13 +------------
 1 file changed, 1 insertion(+), 12 deletions(-)

diff --git a/drivers/firmware/arm_scmi/transports/optee.c b/drivers/firmware/arm_scmi/transports/optee.c
index dc0f46340153..8fdb80d3fabd 100644
--- a/drivers/firmware/arm_scmi/transports/optee.c
+++ b/drivers/firmware/arm_scmi/transports/optee.c
@@ -612,23 +612,12 @@ static struct tee_client_driver scmi_optee_service_driver = {
 	.id_table	= scmi_optee_service_id,
 	.driver		= {
 		.name = "scmi-optee",
-		.bus = &tee_bus_type,
 		.probe = scmi_optee_service_probe,
 		.remove = scmi_optee_service_remove,
 	},
 };
 
-static int __init scmi_transport_optee_init(void)
-{
-	return driver_register(&scmi_optee_service_driver.driver);
-}
-module_init(scmi_transport_optee_init);
-
-static void __exit scmi_transport_optee_exit(void)
-{
-	driver_unregister(&scmi_optee_service_driver.driver);
-}
-module_exit(scmi_transport_optee_exit);
+module_tee_client_driver(scmi_optee_service_driver);
 
 MODULE_AUTHOR("Etienne Carriere <etienne.carriere at foss.st.com>");
 MODULE_DESCRIPTION("SCMI OPTEE Transport driver");
-- 
2.47.3



From u.kleine-koenig at baylibre.com  Mon Dec 15 06:16:41 2025
From: u.kleine-koenig at baylibre.com (=?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?=)
Date: Mon, 15 Dec 2025 15:16:41 +0100
Subject: [PATCH v2 11/17] firmware: arm_scmi: Make use of tee bus methods
In-Reply-To: <cover.1765791463.git.u.kleine-koenig@baylibre.com>
References: <cover.1765791463.git.u.kleine-koenig@baylibre.com>
Message-ID: <859339714ce238c34fdc4832fa23d6d6abec6ba1.1765791463.git.u.kleine-koenig@baylibre.com>

The tee bus got dedicated callbacks for probe and remove.
Make use of these. This fixes a runtime warning about the driver needing
to be converted to the bus methods. Note that the return value of .remove()
was already ignored before, so there is no problem introduced by dropping
the error returns.

Reviewed-by: Sumit Garg <sumit.garg at oss.qualcomm.com>
Reviewed-by: Sudeep Holla <sudeep.holla at arm.com>
Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig at baylibre.com>
---
 drivers/firmware/arm_scmi/transports/optee.c | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/drivers/firmware/arm_scmi/transports/optee.c b/drivers/firmware/arm_scmi/transports/optee.c
index 8fdb80d3fabd..07ae18d5279d 100644
--- a/drivers/firmware/arm_scmi/transports/optee.c
+++ b/drivers/firmware/arm_scmi/transports/optee.c
@@ -529,8 +529,9 @@ static const struct of_device_id scmi_of_match[] = {
 DEFINE_SCMI_TRANSPORT_DRIVER(scmi_optee, scmi_optee_driver, scmi_optee_desc,
 			     scmi_of_match, core);
 
-static int scmi_optee_service_probe(struct device *dev)
+static int scmi_optee_service_probe(struct tee_client_device *scmi_pta)
 {
+	struct device *dev = &scmi_pta->dev;
 	struct scmi_optee_agent *agent;
 	struct tee_context *tee_ctx;
 	int ret;
@@ -578,24 +579,22 @@ static int scmi_optee_service_probe(struct device *dev)
 	return ret;
 }
 
-static int scmi_optee_service_remove(struct device *dev)
+static void scmi_optee_service_remove(struct tee_client_device *scmi_pta)
 {
 	struct scmi_optee_agent *agent = scmi_optee_private;
 
 	if (!scmi_optee_private)
-		return -EINVAL;
+		return;
 
 	platform_driver_unregister(&scmi_optee_driver);
 
 	if (!list_empty(&scmi_optee_private->channel_list))
-		return -EBUSY;
+		return;
 
 	/* Ensure cleared reference is visible before resources are released */
 	smp_store_mb(scmi_optee_private, NULL);
 
 	tee_client_close_context(agent->tee_ctx);
-
-	return 0;
 }
 
 static const struct tee_client_device_id scmi_optee_service_id[] = {
@@ -609,11 +608,11 @@ static const struct tee_client_device_id scmi_optee_service_id[] = {
 MODULE_DEVICE_TABLE(tee, scmi_optee_service_id);
 
 static struct tee_client_driver scmi_optee_service_driver = {
-	.id_table	= scmi_optee_service_id,
-	.driver		= {
+	.probe = scmi_optee_service_probe,
+	.remove = scmi_optee_service_remove,
+	.id_table = scmi_optee_service_id,
+	.driver = {
 		.name = "scmi-optee",
-		.probe = scmi_optee_service_probe,
-		.remove = scmi_optee_service_remove,
 	},
 };
 
-- 
2.47.3



From jan.petrous at oss.nxp.com  Mon Dec 15 06:21:49 2025
From: jan.petrous at oss.nxp.com (Jan Petrous)
Date: Mon, 15 Dec 2025 15:21:49 +0100
Subject: [PATCH RFC 4/4] stmmac: s32: enable multi irqs mode
In-Reply-To: <d1eba807-c45d-434f-b272-ed0841c728bf@lunn.ch>
References: <20251214-dwmac_multi_irq-v1-0-36562ab0e9f7@oss.nxp.com>
 <20251214-dwmac_multi_irq-v1-4-36562ab0e9f7@oss.nxp.com>
 <d1eba807-c45d-434f-b272-ed0841c728bf@lunn.ch>
Message-ID: <aUAZfcMbHD+BHNSi@lsv051416.swis.nl-cdc01.nxp.com>

On Sun, Dec 14, 2025 at 11:37:51PM +0100, Andrew Lunn wrote:
> On Sun, Dec 14, 2025 at 11:15:40PM +0100, Jan Petrous via B4 Relay wrote:
> > From: "Jan Petrous (OSS)" <jan.petrous at oss.nxp.com>
> > 
> > Signalize support for multi irq mode.
> > 
> > >From now, if yoused old DT node, without channel IRQs set,
> > the driver fails to init with the following error:
> > 
> > [4.925420] s32-dwmac 4033c000.ethernet eth0: stmmac_request_irq_multi_msi: alloc rx-0  MSI -6 (error: -22)
> 
> Sorry, but that is not acceptable. You cannot break old DT blobs.
> 
> Please reverse the logic. If you find all the needed properties in DT
> enable STMMAC_FLAG_MULTI_MSI_EN. If none of the properties are there,
> continue using one interrupt, and if only some of the needed
> properties are there but some are missing, then you can error out with
> EINVAL, because the DT blob is invalid.
> 

Yeh, that was the main reason of marking it as RFC, I was not sure
if I can break old DT blobs or not.

Thanks for answer. I will change the procedure to stay
backward compatible.

/Jan


From devnull+david.ixit.cz at kernel.org  Mon Dec 15 06:30:01 2025
From: devnull+david.ixit.cz at kernel.org (David Heidelberg via B4 Relay)
Date: Mon, 15 Dec 2025 15:30:01 +0100
Subject: [PATCH 1/4] Input: stmfts - correct wording for the warning
 message
In-Reply-To: <20251215-fts-fixes-v1-0-8c1e3a63ebf1@ixit.cz>
References: <20251215-fts-fixes-v1-0-8c1e3a63ebf1@ixit.cz>
Message-ID: <20251215-fts-fixes-v1-1-8c1e3a63ebf1@ixit.cz>

From: David Heidelberg <david at ixit.cz>

We're trying to enable regulator, not disable it.

Fixes: 78bcac7b2ae1 ("Input: add support for the STMicroelectronics FingerTip touchscreen")
Suggested-by: Petr Hodina <petr.hodina at protonmail.com>
Signed-off-by: David Heidelberg <david at ixit.cz>
---
 drivers/input/touchscreen/stmfts.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
index 119cd26851cf6..9f5609524fef6 100644
--- a/drivers/input/touchscreen/stmfts.c
+++ b/drivers/input/touchscreen/stmfts.c
@@ -120,7 +120,7 @@ static int stmfts_brightness_set(struct led_classdev *led_cdev,
 			err = regulator_enable(sdata->ledvdd);
 			if (err) {
 				dev_warn(&sdata->client->dev,
-					 "failed to disable ledvdd regulator: %d\n",
+					 "failed to enable ledvdd regulator: %d\n",
 					 err);
 				return err;
 			}

-- 
2.51.0




From devnull+david.ixit.cz at kernel.org  Mon Dec 15 06:30:02 2025
From: devnull+david.ixit.cz at kernel.org (David Heidelberg via B4 Relay)
Date: Mon, 15 Dec 2025 15:30:02 +0100
Subject: [PATCH 2/4] Input: stmfts - Make comments correct
In-Reply-To: <20251215-fts-fixes-v1-0-8c1e3a63ebf1@ixit.cz>
References: <20251215-fts-fixes-v1-0-8c1e3a63ebf1@ixit.cz>
Message-ID: <20251215-fts-fixes-v1-2-8c1e3a63ebf1@ixit.cz>

From: Petr Hodina <petr.hodina at protonmail.com>

No functional change.

Fixes: 78bcac7b2ae1 ("Input: add support for the STMicroelectronics FingerTip touchscreen")
Signed-off-by: Petr Hodina <petr.hodina at protonmail.com>
Signed-off-by: David Heidelberg <david at ixit.cz>
---
 drivers/input/touchscreen/stmfts.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
index 9f5609524fef6..ad363b3c344cd 100644
--- a/drivers/input/touchscreen/stmfts.c
+++ b/drivers/input/touchscreen/stmfts.c
@@ -141,7 +141,7 @@ static enum led_brightness stmfts_brightness_get(struct led_classdev *led_cdev)
 
 /*
  * We can't simply use i2c_smbus_read_i2c_block_data because we
- * need to read more than 255 bytes (
+ * need to read 256 bytes, which exceeds the 255-byte SMBus block limit.
  */
 static int stmfts_read_events(struct stmfts_data *sdata)
 {
@@ -594,9 +594,6 @@ static void stmfts_power_off(void *data)
 						sdata->regulators);
 }
 
-/* This function is void because I don't want to prevent using the touch key
- * only because the LEDs don't get registered
- */
 static int stmfts_enable_led(struct stmfts_data *sdata)
 {
 	int err;

-- 
2.51.0




From devnull+david.ixit.cz at kernel.org  Mon Dec 15 06:30:03 2025
From: devnull+david.ixit.cz at kernel.org (David Heidelberg via B4 Relay)
Date: Mon, 15 Dec 2025 15:30:03 +0100
Subject: [PATCH 3/4] Input: stmfts - use sysfs_emit() instead of sprintf()
In-Reply-To: <20251215-fts-fixes-v1-0-8c1e3a63ebf1@ixit.cz>
References: <20251215-fts-fixes-v1-0-8c1e3a63ebf1@ixit.cz>
Message-ID: <20251215-fts-fixes-v1-3-8c1e3a63ebf1@ixit.cz>

From: Petr Hodina <petr.hodina at protonmail.com>

Follow the advice in Documentation/filesystems/sysfs.rst:
show() should only use sysfs_emit() or sysfs_emit_at() when formatting
the value to be returned to user space.

Signed-off-by: Petr Hodina <petr.hodina at protonmail.com>
Signed-off-by: David Heidelberg <david at ixit.cz>
---
 drivers/input/touchscreen/stmfts.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
index ad363b3c344cd..4b166b0a9a5a6 100644
--- a/drivers/input/touchscreen/stmfts.c
+++ b/drivers/input/touchscreen/stmfts.c
@@ -410,7 +410,7 @@ static ssize_t stmfts_sysfs_chip_id(struct device *dev,
 {
 	struct stmfts_data *sdata = dev_get_drvdata(dev);
 
-	return sprintf(buf, "%#x\n", sdata->chip_id);
+	return sysfs_emit(buf, "%#x\n", sdata->chip_id);
 }
 
 static ssize_t stmfts_sysfs_chip_version(struct device *dev,
@@ -418,7 +418,7 @@ static ssize_t stmfts_sysfs_chip_version(struct device *dev,
 {
 	struct stmfts_data *sdata = dev_get_drvdata(dev);
 
-	return sprintf(buf, "%u\n", sdata->chip_ver);
+	return sysfs_emit(buf, "%u\n", sdata->chip_ver);
 }
 
 static ssize_t stmfts_sysfs_fw_ver(struct device *dev,
@@ -426,7 +426,7 @@ static ssize_t stmfts_sysfs_fw_ver(struct device *dev,
 {
 	struct stmfts_data *sdata = dev_get_drvdata(dev);
 
-	return sprintf(buf, "%u\n", sdata->fw_ver);
+	return sysfs_emit(buf, "%u\n", sdata->fw_ver);
 }
 
 static ssize_t stmfts_sysfs_config_id(struct device *dev,
@@ -434,7 +434,7 @@ static ssize_t stmfts_sysfs_config_id(struct device *dev,
 {
 	struct stmfts_data *sdata = dev_get_drvdata(dev);
 
-	return sprintf(buf, "%#x\n", sdata->config_id);
+	return sysfs_emit(buf, "%#x\n", sdata->config_id);
 }
 
 static ssize_t stmfts_sysfs_config_version(struct device *dev,
@@ -442,7 +442,7 @@ static ssize_t stmfts_sysfs_config_version(struct device *dev,
 {
 	struct stmfts_data *sdata = dev_get_drvdata(dev);
 
-	return sprintf(buf, "%u\n", sdata->config_ver);
+	return sysfs_emit(buf, "%u\n", sdata->config_ver);
 }
 
 static ssize_t stmfts_sysfs_read_status(struct device *dev,
@@ -457,7 +457,7 @@ static ssize_t stmfts_sysfs_read_status(struct device *dev,
 	if (err)
 		return err;
 
-	return sprintf(buf, "%#02x\n", status[0]);
+	return sysfs_emit(buf, "%#02x\n", status[0]);
 }
 
 static ssize_t stmfts_sysfs_hover_enable_read(struct device *dev,
@@ -465,7 +465,7 @@ static ssize_t stmfts_sysfs_hover_enable_read(struct device *dev,
 {
 	struct stmfts_data *sdata = dev_get_drvdata(dev);
 
-	return sprintf(buf, "%u\n", sdata->hover_enabled);
+	return sysfs_emit(buf, "%u\n", sdata->hover_enabled);
 }
 
 static ssize_t stmfts_sysfs_hover_enable_write(struct device *dev,

-- 
2.51.0




From devnull+david.ixit.cz at kernel.org  Mon Dec 15 06:30:00 2025
From: devnull+david.ixit.cz at kernel.org (David Heidelberg via B4 Relay)
Date: Mon, 15 Dec 2025 15:30:00 +0100
Subject: [PATCH 0/4] Input: small nitpick fixes
Message-ID: <20251215-fts-fixes-v1-0-8c1e3a63ebf1@ixit.cz>

Feel free to ignore the last patch, if you want to wait for FTS5
support.

Signed-off-by: David Heidelberg <david at ixit.cz>
---
David Heidelberg (1):
      Input: stmfts - correct wording for the warning message

Petr Hodina (3):
      Input: stmfts - Make comments correct
      Input: stmfts - use sysfs_emit() instead of sprintf()
      Input: stmfts - use client to make future code cleaner

 drivers/input/touchscreen/stmfts.c | 24 +++++++++++-------------
 1 file changed, 11 insertions(+), 13 deletions(-)
---
base-commit: 4a5663c04bb679631985a15efab774da58c37815
change-id: 20251212-fts-fixes-30253fde92d9

Best regards,
-- 
David Heidelberg <david at ixit.cz>




From devnull+david.ixit.cz at kernel.org  Mon Dec 15 06:30:04 2025
From: devnull+david.ixit.cz at kernel.org (David Heidelberg via B4 Relay)
Date: Mon, 15 Dec 2025 15:30:04 +0100
Subject: [PATCH 4/4] Input: stmfts - use client to make future code cleaner
In-Reply-To: <20251215-fts-fixes-v1-0-8c1e3a63ebf1@ixit.cz>
References: <20251215-fts-fixes-v1-0-8c1e3a63ebf1@ixit.cz>
Message-ID: <20251215-fts-fixes-v1-4-8c1e3a63ebf1@ixit.cz>

From: Petr Hodina <petr.hodina at protonmail.com>

Make code cleaner, compiler will optimize it away anyway.

Preparation for FTM5 support, where more steps are needed.

Signed-off-by: Petr Hodina <petr.hodina at protonmail.com>
Signed-off-by: David Heidelberg <david at ixit.cz>
---
 drivers/input/touchscreen/stmfts.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
index 4b166b0a9a5a6..06845a00348cc 100644
--- a/drivers/input/touchscreen/stmfts.c
+++ b/drivers/input/touchscreen/stmfts.c
@@ -747,9 +747,10 @@ static int stmfts_runtime_suspend(struct device *dev)
 static int stmfts_runtime_resume(struct device *dev)
 {
 	struct stmfts_data *sdata = dev_get_drvdata(dev);
+	struct i2c_client *client = sdata->client;
 	int ret;
 
-	ret = i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_OUT);
+	ret = i2c_smbus_write_byte(client, STMFTS_SLEEP_OUT);
 	if (ret)
 		dev_err(dev, "failed to resume device: %d\n", ret);
 

-- 
2.51.0




From lorenzo at kernel.org  Mon Dec 15 06:33:01 2025
From: lorenzo at kernel.org (Lorenzo Bianconi)
Date: Mon, 15 Dec 2025 15:33:01 +0100
Subject: [PATCH net] net: airoha: Move net_devs registration in a
 dedicated routine
In-Reply-To: <aUAXJ01iHnSJtItt@horms.kernel.org>
References: <20251214-airoha-fix-dev-registration-v1-1-860e027ad4c6@kernel.org>
 <aUAXJ01iHnSJtItt@horms.kernel.org>
Message-ID: <aUAcHVULgJTpdGzT@lore-desk>

> On Sun, Dec 14, 2025 at 10:30:07AM +0100, Lorenzo Bianconi wrote:
> > Since airoha_probe() is not executed under rtnl lock, there is small race
> > where a given device is configured by user-space while the remaining ones
> > are not completely loaded from the dts yet. This condition will allow a
> > hw device misconfiguration since there are some conditions (e.g. GDM2 check
> > in airoha_dev_init()) that require all device are properly loaded from the
> > device tree. Fix the issue moving net_devices registration at the end of
> > the airoha_probe routine.
> > 
> > Fixes: 9cd451d414f6e ("net: airoha: Add loopback support for GDM2")
> > Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
> 
> Hi Lorenzo,
> 
> As a fix this patch looks good to me.
> 
> Reviewed-by: Simon Horman <horms at kernel.org>

Hi Simon,

thx for the review.

> 
> But I am somewhat surprised that the netdev isn't unregistered earlier
> both in airoha_remove() and the unwind ladder of airoha_probe().

do you mean moving unregister_netdev() before
airoha_qdma_stop_napi()/airoha_hw_cleanup()? I was thinking about it to be
honest :)
Since it is not related to this fix, I will post a patch as soon as net-next is
open again.

Regards,
Lorenzo

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251215/f2095c0d/attachment.sig>

From horms at kernel.org  Mon Dec 15 06:39:19 2025
From: horms at kernel.org (Simon Horman)
Date: Mon, 15 Dec 2025 14:39:19 +0000
Subject: [PATCH net] net: airoha: Move net_devs registration in a
 dedicated routine
In-Reply-To: <aUAcHVULgJTpdGzT@lore-desk>
References: <20251214-airoha-fix-dev-registration-v1-1-860e027ad4c6@kernel.org>
 <aUAXJ01iHnSJtItt@horms.kernel.org>
 <aUAcHVULgJTpdGzT@lore-desk>
Message-ID: <aUAdlzPgf_lQKgLM@horms.kernel.org>

On Mon, Dec 15, 2025 at 03:33:01PM +0100, Lorenzo Bianconi wrote:
> > On Sun, Dec 14, 2025 at 10:30:07AM +0100, Lorenzo Bianconi wrote:
> > > Since airoha_probe() is not executed under rtnl lock, there is small race
> > > where a given device is configured by user-space while the remaining ones
> > > are not completely loaded from the dts yet. This condition will allow a
> > > hw device misconfiguration since there are some conditions (e.g. GDM2 check
> > > in airoha_dev_init()) that require all device are properly loaded from the
> > > device tree. Fix the issue moving net_devices registration at the end of
> > > the airoha_probe routine.
> > > 
> > > Fixes: 9cd451d414f6e ("net: airoha: Add loopback support for GDM2")
> > > Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
> > 
> > Hi Lorenzo,
> > 
> > As a fix this patch looks good to me.
> > 
> > Reviewed-by: Simon Horman <horms at kernel.org>
> 
> Hi Simon,
> 
> thx for the review.
> 
> > 
> > But I am somewhat surprised that the netdev isn't unregistered earlier
> > both in airoha_remove() and the unwind ladder of airoha_probe().
> 
> do you mean moving unregister_netdev() before
> airoha_qdma_stop_napi()/airoha_hw_cleanup()? I was thinking about it to be
> honest :)
> Since it is not related to this fix, I will post a patch as soon as net-next is
> open again.

Yes, that is what I was thinking.
And I agree that this is net-next material unrelated to this fix.

While you are there, I would look at making the unwind ladder
in probe follow the same pattern as remove, if possible.
I think that might mean moving airoha_ppe_deinit().

But perhaps you already thought of that too.
Or there is some good reason not to do so.




From dan.carpenter at linaro.org  Mon Dec 15 06:41:43 2025
From: dan.carpenter at linaro.org (Dan Carpenter)
Date: Mon, 15 Dec 2025 17:41:43 +0300
Subject: [PATCH v2 0/4] s32g: Use a syscon for GPR
Message-ID: <cover.1765806521.git.dan.carpenter@linaro.org>

The s32g devices have a GPR register region which holds a number of
miscellaneous registers.  Currently only the stmmac/dwmac-s32.c uses
anything from there and we just add a line to the device tree to
access that GMAC_0_CTRL_STS register:

                        reg = <0x4033c000 0x2000>, /* gmac IP */
                              <0x4007c004 0x4>;    /* GMAC_0_CTRL_STS */

We still have to maintain backwards compatibility to this format,
of course, but it would be better to access these through a syscon.
First of all, putting all the registers together is more organized
and shows how the hardware actually is implemented.  Secondly, in
some versions of this chipset those registers can only be accessed
via SCMI, if the registers aren't grouped together each driver will
have to create a whole lot of if then statements to access it via
IOMEM or via SCMI, where if we use a syscon interface we can write
a driver to handle that quite transparently without modifying each
individual driver which reads or writes to one of these registers.
That code is out of tree for now, but eventually we'll want to
support this.

Changed since v1:
* Add imx at lists.linux.dev to the CC list.
* Fix forward porting bug.  s/PHY_INTF_SEL_RGMII/S32_PHY_INTF_SEL_RGMII/
* Use the correct SoC names nxp,s32g2-gpr and nxp,s32g3-gpr instead of
  nxp,s32g-gpr which is the SoC family.
* Fix the phandle name by adding the vendor prefix
* Fix the documentation for the phandle
* Remove #address-cells and #size-cells from the syscon block

Here is the whole list of registers in the GPR region

Starting from 0x4007C000

0  Software-Triggered Faults (SW_NCF)
4  GMAC Control (GMAC_0_CTRL_STS)
28 CMU Status 1 (CMU_STATUS_REG1)
2C CMUs Status 2 (CMU_STATUS_REG2)
30 FCCU EOUT Override Clear (FCCU_EOUT_OVERRIDE_CLEAR_REG)
38 SRC POR Control (SRC_POR_CTRL_REG)
54 GPR21 (GPR21)
5C GPR23 (GPR23)
60 GPR24 Register (GPR24)
CC Debug Control (DEBUG_CONTROL)
F0 Timestamp Control (TIMESTAMP_CONTROL_REGISTER)
F4 FlexRay OS Tick Input Select (FLEXRAY_OS_TICK_INPUT_SELECT_REG)
FC GPR63 Register (GPR63)

Starting from 0x4007CA00

0  Coherency Enable for PFE Ports (PFE_COH_EN)
4  PFE EMAC Interface Mode (PFE_EMACX_INTF_SEL)
20 PFE EMACX Power Control (PFE_PWR_CTRL)
28 Error Injection on Cortex-M7 AHB and AXI Pipe (CM7_TCM_AHB_SLICE)
2C Error Injection AHBP Gasket Cortex-M7 (ERROR_INJECTION_AHBP_GASKET_CM7)
40 LLCE Subsystem Status (LLCE_STAT)
44 LLCE Power Control (LLCE_CTRL)
48 DDR Urgent Control (DDR_URGENT_CTRL)
4C FTM Global Load Control (FLXTIM_CTRL)
50 FTM LDOK Status (FLXTIM_STAT)
54 Top CMU Status (CMU_STAT)
58 Accelerator NoC No Pending Trans Status (NOC_NOPEND_TRANS)
90 SerDes RD/WD Toggle Control (PCIE_TOGGLE)
94 SerDes Toggle Done Status (PCIE_TOGGLEDONE_STAT)
E0 Generic Control 0 (GENCTRL0)
E4 Generic Control 1 (GENCTRL1)
F0 Generic Status 0 (GENSTAT0)
FC Cortex-M7 AXI Parity Error and AHBP Gasket Error Alarm (CM7_AXI_AHBP_GASKET_ERROR_ALARM)

Starting from 4007C800

4  GPR01 Register (GPR01)
30 GPR12 Register (GPR12)
58 GPR22 Register (GPR22)
70 GPR28 Register (GPR28)
74 GPR29 Register (GPR29)

Starting from 4007CB00

4 WKUP Pad Pullup/Pulldown Select (WKUP_PUS)

Dan Carpenter (4):
  net: stmmac: s32: use a syscon for S32_PHY_INTF_SEL_RGMII
  dt-bindings: mfd: syscon: Document the GPR syscon for the NXP S32 SoCs
  dt-bindings: net: nxp,s32-dwmac: Use the GPR syscon
  dts: s32g: Add GPR syscon region

 .../devicetree/bindings/mfd/syscon.yaml       |  4 ++++
 .../bindings/net/nxp,s32-dwmac.yaml           | 10 ++++++++
 arch/arm64/boot/dts/freescale/s32g2.dtsi      |  6 +++++
 arch/arm64/boot/dts/freescale/s32g3.dtsi      |  6 +++++
 .../net/ethernet/stmicro/stmmac/dwmac-s32.c   | 23 +++++++++++++++----
 5 files changed, 44 insertions(+), 5 deletions(-)

-- 
2.51.0



From dan.carpenter at linaro.org  Mon Dec 15 06:41:48 2025
From: dan.carpenter at linaro.org (Dan Carpenter)
Date: Mon, 15 Dec 2025 17:41:48 +0300
Subject: [PATCH v2 1/4] net: stmmac: s32: use a syscon for
 S32_PHY_INTF_SEL_RGMII
In-Reply-To: <cover.1765806521.git.dan.carpenter@linaro.org>
References: <cover.1765806521.git.dan.carpenter@linaro.org>
Message-ID: <f7ee93f0a8c6d6b9de3f2b37da9e038bfa7f290a.1765806521.git.dan.carpenter@linaro.org>

On the s32 chipsets the GMAC_0_CTRL_STS register is in GPR region.
Originally, accessing this register was done in a sort of ad-hoc way,
but we want to use the syscon interface to do it.

This is a little bit ugly because we have to maintain backwards
compatibility to the old device trees so we have to support both ways
to access this register.

Signed-off-by: Dan Carpenter <dan.carpenter at linaro.org>
---
Fix forward porting bug.  s/PHY_INTF_SEL_RGMII/S32_PHY_INTF_SEL_RGMII/

 .../net/ethernet/stmicro/stmmac/dwmac-s32.c   | 23 +++++++++++++++----
 1 file changed, 18 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c
index 5a485ee98fa7..2e6bb41f49e1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c
@@ -11,12 +11,14 @@
 #include <linux/device.h>
 #include <linux/ethtool.h>
 #include <linux/io.h>
+#include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of_mdio.h>
 #include <linux/of_address.h>
 #include <linux/phy.h>
 #include <linux/phylink.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/stmmac.h>
 
 #include "stmmac_platform.h"
@@ -32,6 +34,8 @@
 struct s32_priv_data {
 	void __iomem *ioaddr;
 	void __iomem *ctrl_sts;
+	struct regmap *sts_regmap;
+	unsigned int sts_offset;
 	struct device *dev;
 	phy_interface_t *intf_mode;
 	struct clk *tx_clk;
@@ -40,7 +44,10 @@ struct s32_priv_data {
 
 static int s32_gmac_write_phy_intf_select(struct s32_priv_data *gmac)
 {
-	writel(S32_PHY_INTF_SEL_RGMII, gmac->ctrl_sts);
+	if (gmac->ctrl_sts)
+		writel(S32_PHY_INTF_SEL_RGMII, gmac->ctrl_sts);
+	else
+		regmap_write(gmac->sts_regmap, gmac->sts_offset, S32_PHY_INTF_SEL_RGMII);
 
 	dev_dbg(gmac->dev, "PHY mode set to %s\n", phy_modes(*gmac->intf_mode));
 
@@ -125,10 +132,16 @@ static int s32_dwmac_probe(struct platform_device *pdev)
 				     "dt configuration failed\n");
 
 	/* PHY interface mode control reg */
-	gmac->ctrl_sts = devm_platform_get_and_ioremap_resource(pdev, 1, NULL);
-	if (IS_ERR(gmac->ctrl_sts))
-		return dev_err_probe(dev, PTR_ERR(gmac->ctrl_sts),
-				     "S32CC config region is missing\n");
+	gmac->sts_regmap = syscon_regmap_lookup_by_phandle_args(dev->of_node,
+					"nxp,phy-sel", 1, &gmac->sts_offset);
+	if (gmac->sts_regmap == ERR_PTR(-EPROBE_DEFER))
+		return PTR_ERR(gmac->sts_regmap);
+	if (IS_ERR(gmac->sts_regmap)) {
+		gmac->ctrl_sts = devm_platform_get_and_ioremap_resource(pdev, 1, NULL);
+		if (IS_ERR(gmac->ctrl_sts))
+			return dev_err_probe(dev, PTR_ERR(gmac->ctrl_sts),
+					     "S32CC config region is missing\n");
+	}
 
 	/* tx clock */
 	gmac->tx_clk = devm_clk_get(&pdev->dev, "tx");
-- 
2.51.0



From dan.carpenter at linaro.org  Mon Dec 15 06:42:02 2025
From: dan.carpenter at linaro.org (Dan Carpenter)
Date: Mon, 15 Dec 2025 17:42:02 +0300
Subject: [PATCH v2 4/4] dts: s32g: Add GPR syscon region
In-Reply-To: <cover.1765806521.git.dan.carpenter@linaro.org>
References: <cover.1765806521.git.dan.carpenter@linaro.org>
Message-ID: <990c6317baca68b1ec0391eba3b66f511d75710c.1765806521.git.dan.carpenter@linaro.org>

Add the GPR syscon region for the s32 chipset.

Signed-off-by: Dan Carpenter <dan.carpenter at linaro.org>
---
v2: Remove #address-cells and #size-cells

 arch/arm64/boot/dts/freescale/s32g2.dtsi | 6 ++++++
 arch/arm64/boot/dts/freescale/s32g3.dtsi | 6 ++++++
 2 files changed, 12 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/s32g2.dtsi b/arch/arm64/boot/dts/freescale/s32g2.dtsi
index 51d00dac12de..b954952d962b 100644
--- a/arch/arm64/boot/dts/freescale/s32g2.dtsi
+++ b/arch/arm64/boot/dts/freescale/s32g2.dtsi
@@ -325,6 +325,11 @@ usdhc0-200mhz-grp4 {
 			};
 		};
 
+		gpr: syscon at 4007c000 {
+			compatible = "nxp,s32g2-gpr", "syscon";
+			reg = <0x4007c000 0x3000>;
+		};
+
 		ocotp: nvmem at 400a4000 {
 			compatible = "nxp,s32g2-ocotp";
 			reg = <0x400a4000 0x400>;
@@ -731,6 +736,7 @@ gmac0: ethernet at 4033c000 {
 			compatible = "nxp,s32g2-dwmac";
 			reg = <0x4033c000 0x2000>, /* gmac IP */
 			      <0x4007c004 0x4>;    /* GMAC_0_CTRL_STS */
+			nxp,phy-sel = <&gpr 0x4>;
 			interrupt-parent = <&gic>;
 			interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
 			interrupt-names = "macirq";
diff --git a/arch/arm64/boot/dts/freescale/s32g3.dtsi b/arch/arm64/boot/dts/freescale/s32g3.dtsi
index eff7673e7f34..71ee1c043d03 100644
--- a/arch/arm64/boot/dts/freescale/s32g3.dtsi
+++ b/arch/arm64/boot/dts/freescale/s32g3.dtsi
@@ -383,6 +383,11 @@ usdhc0-200mhz-grp4 {
 			};
 		};
 
+		gpr: syscon at 4007c000 {
+			compatible = "nxp,s32g3-gpr", "syscon";
+			reg = <0x4007c000 0x3000>;
+		};
+
 		ocotp: nvmem at 400a4000 {
 			compatible = "nxp,s32g3-ocotp", "nxp,s32g2-ocotp";
 			reg = <0x400a4000 0x400>;
@@ -808,6 +813,7 @@ gmac0: ethernet at 4033c000 {
 			compatible = "nxp,s32g2-dwmac";
 			reg = <0x4033c000 0x2000>, /* gmac IP */
 			      <0x4007c004 0x4>;    /* GMAC_0_CTRL_STS */
+			nxp,phy-sel = <&gpr 0x4>;
 			interrupt-parent = <&gic>;
 			interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
 			interrupt-names = "macirq";
-- 
2.51.0



From leo.yan at arm.com  Mon Dec 15 06:59:09 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 15 Dec 2025 14:59:09 +0000
Subject: [PATCH v2] arm64: hw_breakpoint: warn on invalid breakpoint
 length
In-Reply-To: <20251213112336.26503-1-osama.abdelkader@gmail.com>
References: <20251213112336.26503-1-osama.abdelkader@gmail.com>
Message-ID: <20251215145909.GC681384@e132581.arm.com>

Hi,

On Sat, Dec 13, 2025 at 12:23:35PM +0100, Osama Abdelkader wrote:
> Some tools (e.g. perf) incorrectly assume that breakpoints should be
> sizeof(long), but this is wrong for AArch64 where breakpoints must be
> 4 bytes. Add a warning when we silently fix up the parameter so tool
> developers can get notified.

To be clear, the perf tool has fixed the issue since:

  fa6cc3f93258 ("perf parse-events: Vary default_breakpoint_len on i386 and arm64")

The latest perf can pass the correct length (4) for instruction
breakpoint.

> This addresses the FIXME comment by adding diagnostic output rather
> than breaking existing tools by returning -EINVAL.
> 
> Signed-off-by: Osama Abdelkader <osama.abdelkader at gmail.com>
> ---
> v2: fix warning messageline splitting
> ---
>  arch/arm64/kernel/hw_breakpoint.c | 10 ++++++----
>  1 file changed, 6 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
> index ab76b36dce82..cce306145d78 100644
> --- a/arch/arm64/kernel/hw_breakpoint.c
> +++ b/arch/arm64/kernel/hw_breakpoint.c
> @@ -475,11 +475,13 @@ static int arch_build_bp_info(struct perf_event *bp,
>  				return -EINVAL;
>  		} else if (hw->ctrl.len != ARM_BREAKPOINT_LEN_4) {
>  			/*
> -			 * FIXME: Some tools (I'm looking at you perf) assume
> -			 *	  that breakpoints should be sizeof(long). This
> -			 *	  is nonsense. For now, we fix up the parameter
> -			 *	  but we should probably return -EINVAL instead.

This FIXME is still valid for me.  IMO, if really want to remove the
comment, a reasonable solution is:

  1) Backport two patches (fa6cc3f93258 and 70b27c756f9) onto the
     stable kernel code base for fixing perf tool.

  2) Based on perf tool has fixed the issue on the mainline kernel and
     stable kernels, we can change to return -EINVAL instead.

> +			 * Some tools (e.g. perf) incorrectly assume that
> +			 * breakpoints should be sizeof(long). This is wrong
> +			 * for AArch64 where breakpoints must be 4 bytes.
> +			 * Warn the user and fix up the parameter.
>  			 */
> +			pr_warn_once("hw_breakpoint: invalid AArch64 breakpoint length %d, fixing to 4 bytes\n",
> +				     hw->ctrl.len);

AFAIK, since I started to use Armv5 CPUs, Arm instructions (not Thumb
ones) are always 4-byte length. Not sure if the log is useful or not,
I would leave this to maintainers.

Thanks,
Leo

>  			hw->ctrl.len = ARM_BREAKPOINT_LEN_4;
>  		}
>  	}
> -- 
> 2.43.0
> 
> 


From kevin.brodsky at arm.com  Mon Dec 15 07:03:09 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Mon, 15 Dec 2025 15:03:09 +0000
Subject: [PATCH v6 00/14] Nesting support for lazy MMU mode
Message-ID: <20251215150323.2218608-1-kevin.brodsky@arm.com>

When the lazy MMU mode was introduced eons ago, it wasn't made clear
whether such a sequence was legal:

	arch_enter_lazy_mmu_mode()
	...
		arch_enter_lazy_mmu_mode()
		...
		arch_leave_lazy_mmu_mode()
	...
	arch_leave_lazy_mmu_mode()

It seems fair to say that nested calls to
arch_{enter,leave}_lazy_mmu_mode() were not expected, and most
architectures never explicitly supported it.

Nesting does in fact occur in certain configurations, and avoiding it
has proved difficult. This series therefore enables lazy_mmu sections to
nest, on all architectures.

Nesting is handled using a counter in task_struct (patch 8), like other
stateless APIs such as pagefault_{disable,enable}(). This is fully
handled in a new generic layer in <linux/pgtable.h>; the arch_* API
remains unchanged. A new pair of calls, lazy_mmu_mode_{pause,resume}(),
is also introduced to allow functions that are called with the lazy MMU
mode enabled to temporarily pause it, regardless of nesting.

An arch now opts in to using the lazy MMU mode by selecting
CONFIG_ARCH_LAZY_MMU; this is more appropriate now that we have a
generic API, especially with state conditionally added to task_struct.

---

Background: Ryan Roberts' series from March [1] attempted to prevent
nesting from ever occurring, and mostly succeeded. Unfortunately, a
corner case (DEBUG_PAGEALLOC) may still cause nesting to occur on arm64.
Ryan proposed [2] to address that corner case at the generic level but
this approach received pushback; [3] then attempted to solve the issue
on arm64 only, but it was deemed too fragile.

It feels generally difficult to guarantee that lazy_mmu sections don't
nest, because callers of various standard mm functions do not know if
the function uses lazy_mmu itself.

The overall approach in v3/v4 is very close to what David Hildenbrand
proposed on v2 [4].

Unlike in v1/v2, no special provision is made for architectures to
save/restore extra state when entering/leaving the mode. Based on the
discussions so far, this does not seem to be required - an arch can
store any relevant state in thread_struct during arch_enter() and
restore it in arch_leave(). Nesting is not a concern as these functions
are only called at the top level, not in nested sections.

The introduction of a generic layer, and tracking of the lazy MMU state
in task_struct, also allows to streamline the arch callbacks - this
series removes 67 lines from arch/.

Patch overview:

* Patch 1: cleanup - avoids having to deal with the powerpc
  context-switching code

* Patch 2-4: prepare arch_flush_lazy_mmu_mode() to be called from the
  generic layer (patch 9)

* Patch 5: documentation clarification (not directly related to the
  changes in this series)

* Patch 6-7: new API + CONFIG_ARCH_LAZY_MMU

* Patch 8: ensure correctness in interrupt context

* Patch 9: nesting support

* Patch 10-13: replace arch-specific tracking of lazy MMU mode with
  generic API

* Patch 14: basic tests to ensure that the state added in patch 9 is
  tracked correctly

This series has been tested by running the mm kselftests on arm64 with
DEBUG_VM, DEBUG_PAGEALLOC, KFENCE and KASAN. Extensive testing on
powerpc was also kindly provided by Venkat Rao Bagalkote [5]. It was
build-tested on other architectures (with and without XEN_PV on x86).

- Kevin

[1] https://lore.kernel.org/all/20250303141542.3371656-1-ryan.roberts at arm.com/
[2] https://lore.kernel.org/all/20250530140446.2387131-1-ryan.roberts at arm.com/
[3] https://lore.kernel.org/all/20250606135654.178300-1-ryan.roberts at arm.com/
[4] https://lore.kernel.org/all/ef343405-c394-4763-a79f-21381f217b6c at redhat.com/
[5] https://lore.kernel.org/all/94889730-1AEF-458F-B623-04092C0D6819 at linux.ibm.com/
---
Changelog

v5..v6:

- Rebased on v6.19-rc1
- Overall: no functional change
- Patch 5: new patch clarifying that generic code may not sleep while in lazy
  MMU mode [Alexander Gordeev]
- Patch 6: added description for the ARCH_HAS_LAZY_MMU_MODE option
  [Anshuman Khandual]
- Patch 9: rename in_lazy_mmu_mode() to is_lazy_mmu_mode_active() [Alexander]
- Patch 14: new patch with basic KUnit tests [Anshuman]
- Collected R-b/A-b/T-b tags

v5: https://lore.kernel.org/all/20251124132228.622678-1-kevin.brodsky at arm.com/

v4..v5:

- Rebased on mm-unstable
- Patch 3: added missing radix_enabled() check in arch_flush()
  [Ritesh Harjani]
- Patch 6: declare arch_flush_lazy_mmu_mode() as static inline on x86
  [Ryan Roberts]
- Patch 7 (formerly 12): moved before patch 8 to ensure correctness in
  interrupt context [Ryan]. The diffs in in_lazy_mmu_mode() and
  queue_pte_barriers() are moved to patch 8 and 9 resp.
- Patch 8:
  * Removed all restrictions regarding lazy_mmu_mode_{pause,resume}().
    They may now be called even when lazy MMU isn't enabled, and
    any call to lazy_mmu_mode_* may be made while paused (such calls
    will be ignored). [David, Ryan]
  * lazy_mmu_state.{nesting_level,active} are replaced with
    {enable_count,pause_count} to track arbitrary nesting of both
    enable/disable and pause/resume [Ryan]
  * Added __task_lazy_mmu_mode_active() for use in patch 12 [David]
  * Added documentation for all the functions [Ryan]
- Patch 9: keep existing test + set TIF_LAZY_MMU_PENDING instead of
  atomic RMW [David, Ryan]
- Patch 12: use __task_lazy_mmu_mode_active() instead of accessing
  lazy_mmu_state directly [David]
- Collected R-b/A-b tags

v4: https://lore.kernel.org/all/20251029100909.3381140-1-kevin.brodsky at arm.com/

v3..v4:

- Patch 2: restored ordering of preempt_{disable,enable}() [Dave Hansen]
- Patch 5 onwards: s/ARCH_LAZY_MMU/ARCH_HAS_LAZY_MMU_MODE/ [Mike Rapoport]
- Patch 7: renamed lazy_mmu_state members, removed VM_BUG_ON(),
  reordered writes to lazy_mmu_state members [David Hildenbrand]
- Dropped patch 13 as it doesn't seem justified [David H]
- Various improvements to commit messages [David H]

v3: https://lore.kernel.org/all/20251015082727.2395128-1-kevin.brodsky at arm.com/

v2..v3:

- Full rewrite; dropped all Acked-by/Reviewed-by.
- Rebased on v6.18-rc1.

v2: https://lore.kernel.org/all/20250908073931.4159362-1-kevin.brodsky at arm.com/

v1..v2:
- Rebased on mm-unstable.
- Patch 2: handled new calls to enter()/leave(), clarified how the "flush"
  pattern (leave() followed by enter()) is handled.
- Patch 5,6: removed unnecessary local variable [Alexander Gordeev's
  suggestion].
- Added Mike Rapoport's Acked-by.

v1: https://lore.kernel.org/all/20250904125736.3918646-1-kevin.brodsky at arm.com/
---
Cc: Alexander Gordeev <agordeev at linux.ibm.com>
Cc: Andreas Larsson <andreas at gaisler.com>
Cc: Andrew Morton <akpm at linux-foundation.org>
Cc: Anshuman Khandual <anshuman.khandual at arm.com>
Cc: Boris Ostrovsky <boris.ostrovsky at oracle.com>
Cc: Borislav Petkov <bp at alien8.de>
Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Christophe Leroy <christophe.leroy at csgroup.eu>
Cc: Dave Hansen <dave.hansen at linux.intel.com>
Cc: David Hildenbrand <david at redhat.com>
Cc: "David S. Miller" <davem at davemloft.net>
Cc: David Woodhouse <dwmw2 at infradead.org>
Cc: "H. Peter Anvin" <hpa at zytor.com>
Cc: Ingo Molnar <mingo at redhat.com>
Cc: Jann Horn <jannh at google.com>
Cc: Juergen Gross <jgross at suse.com>
Cc: "Liam R. Howlett" <Liam.Howlett at oracle.com>
Cc: Lorenzo Stoakes <lorenzo.stoakes at oracle.com>
Cc: Madhavan Srinivasan <maddy at linux.ibm.com>
Cc: Michael Ellerman <mpe at ellerman.id.au>
Cc: Michal Hocko <mhocko at suse.com>
Cc: Mike Rapoport <rppt at kernel.org>
Cc: Nicholas Piggin <npiggin at gmail.com>
Cc: Peter Zijlstra <peterz at infradead.org>
Cc: Ritesh Harjani (IBM) <ritesh.list at gmail.com>
Cc: Ryan Roberts <ryan.roberts at arm.com>
Cc: Suren Baghdasaryan <surenb at google.com>
Cc: Thomas Gleixner <tglx at linutronix.de>
Cc: Venkat Rao Bagalkote <venkat88 at linux.ibm.com>
Cc: Vlastimil Babka <vbabka at suse.cz>
Cc: Will Deacon <will at kernel.org>
Cc: Yeoreum Yun <yeoreum.yun at arm.com>
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-kernel at vger.kernel.org
Cc: linuxppc-dev at lists.ozlabs.org
Cc: sparclinux at vger.kernel.org
Cc: xen-devel at lists.xenproject.org
Cc: x86 at kernel.org
---
Alexander Gordeev (1):
  powerpc/64s: Do not re-activate batched TLB flush

Kevin Brodsky (13):
  x86/xen: simplify flush_lazy_mmu()
  powerpc/mm: implement arch_flush_lazy_mmu_mode()
  sparc/mm: implement arch_flush_lazy_mmu_mode()
  mm: clarify lazy_mmu sleeping constraints
  mm: introduce CONFIG_ARCH_HAS_LAZY_MMU_MODE
  mm: introduce generic lazy_mmu helpers
  mm: bail out of lazy_mmu_mode_* in interrupt context
  mm: enable lazy_mmu sections to nest
  arm64: mm: replace TIF_LAZY_MMU with is_lazy_mmu_mode_active()
  powerpc/mm: replace batch->active with is_lazy_mmu_mode_active()
  sparc/mm: replace batch->active with is_lazy_mmu_mode_active()
  x86/xen: use lazy_mmu_state when context-switching
  mm: Add basic tests for lazy_mmu

 arch/arm64/Kconfig                            |   1 +
 arch/arm64/include/asm/pgtable.h              |  41 +----
 arch/arm64/include/asm/thread_info.h          |   3 +-
 arch/arm64/mm/mmu.c                           |   8 +-
 arch/arm64/mm/pageattr.c                      |   4 +-
 .../include/asm/book3s/64/tlbflush-hash.h     |  20 +--
 arch/powerpc/include/asm/thread_info.h        |   2 -
 arch/powerpc/kernel/process.c                 |  25 ---
 arch/powerpc/mm/book3s64/hash_tlb.c           |  10 +-
 arch/powerpc/mm/book3s64/subpage_prot.c       |   4 +-
 arch/powerpc/platforms/Kconfig.cputype        |   1 +
 arch/sparc/Kconfig                            |   1 +
 arch/sparc/include/asm/tlbflush_64.h          |   5 +-
 arch/sparc/mm/tlb.c                           |  14 +-
 arch/x86/Kconfig                              |   1 +
 arch/x86/boot/compressed/misc.h               |   1 +
 arch/x86/boot/startup/sme.c                   |   1 +
 arch/x86/include/asm/paravirt.h               |   1 -
 arch/x86/include/asm/pgtable.h                |   1 +
 arch/x86/include/asm/thread_info.h            |   4 +-
 arch/x86/xen/enlighten_pv.c                   |   3 +-
 arch/x86/xen/mmu_pv.c                         |   6 +-
 fs/proc/task_mmu.c                            |   4 +-
 include/linux/mm_types_task.h                 |   5 +
 include/linux/pgtable.h                       | 158 +++++++++++++++++-
 include/linux/sched.h                         |  45 +++++
 mm/Kconfig                                    |  19 +++
 mm/Makefile                                   |   1 +
 mm/kasan/shadow.c                             |   8 +-
 mm/madvise.c                                  |  18 +-
 mm/memory.c                                   |  16 +-
 mm/migrate_device.c                           |   8 +-
 mm/mprotect.c                                 |   4 +-
 mm/mremap.c                                   |   4 +-
 mm/tests/lazy_mmu_mode_kunit.c                |  71 ++++++++
 mm/userfaultfd.c                              |   4 +-
 mm/vmalloc.c                                  |  12 +-
 mm/vmscan.c                                   |  12 +-
 38 files changed, 380 insertions(+), 166 deletions(-)
 create mode 100644 mm/tests/lazy_mmu_mode_kunit.c


base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
-- 
2.51.2



From kevin.brodsky at arm.com  Mon Dec 15 07:03:10 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Mon, 15 Dec 2025 15:03:10 +0000
Subject: [PATCH v6 01/14] powerpc/64s: Do not re-activate batched TLB flush
In-Reply-To: <20251215150323.2218608-1-kevin.brodsky@arm.com>
References: <20251215150323.2218608-1-kevin.brodsky@arm.com>
Message-ID: <20251215150323.2218608-2-kevin.brodsky@arm.com>

From: Alexander Gordeev <agordeev at linux.ibm.com>

Since commit b9ef323ea168 ("powerpc/64s: Disable preemption in hash
lazy mmu mode") a task can not be preempted while in lazy MMU mode.
Therefore, the batch re-activation code is never called, so remove it.

Signed-off-by: Alexander Gordeev <agordeev at linux.ibm.com>
Reviewed-by: David Hildenbrand <david at redhat.com>
Reviewed-by: Ritesh Harjani (IBM) <ritesh.list at gmail.com>
Reviewed-by: Ryan Roberts <ryan.roberts at arm.com>
Tested-by: Venkat Rao Bagalkote <venkat88 at linux.ibm.com>
Signed-off-by: Kevin Brodsky <kevin.brodsky at arm.com>
---
 arch/powerpc/include/asm/thread_info.h |  2 --
 arch/powerpc/kernel/process.c          | 25 -------------------------
 2 files changed, 27 deletions(-)

diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h
index b0f200aba2b3..97f35f9b1a96 100644
--- a/arch/powerpc/include/asm/thread_info.h
+++ b/arch/powerpc/include/asm/thread_info.h
@@ -154,12 +154,10 @@ void arch_setup_new_exec(void);
 /* Don't move TLF_NAPPING without adjusting the code in entry_32.S */
 #define TLF_NAPPING		0	/* idle thread enabled NAP mode */
 #define TLF_SLEEPING		1	/* suspend code enabled SLEEP mode */
-#define TLF_LAZY_MMU		3	/* tlb_batch is active */
 #define TLF_RUNLATCH		4	/* Is the runlatch enabled? */
 
 #define _TLF_NAPPING		(1 << TLF_NAPPING)
 #define _TLF_SLEEPING		(1 << TLF_SLEEPING)
-#define _TLF_LAZY_MMU		(1 << TLF_LAZY_MMU)
 #define _TLF_RUNLATCH		(1 << TLF_RUNLATCH)
 
 #ifndef __ASSEMBLER__
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index a45fe147868b..a15d0b619b1f 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -1281,9 +1281,6 @@ struct task_struct *__switch_to(struct task_struct *prev,
 {
 	struct thread_struct *new_thread, *old_thread;
 	struct task_struct *last;
-#ifdef CONFIG_PPC_64S_HASH_MMU
-	struct ppc64_tlb_batch *batch;
-#endif
 
 	new_thread = &new->thread;
 	old_thread = &current->thread;
@@ -1291,14 +1288,6 @@ struct task_struct *__switch_to(struct task_struct *prev,
 	WARN_ON(!irqs_disabled());
 
 #ifdef CONFIG_PPC_64S_HASH_MMU
-	batch = this_cpu_ptr(&ppc64_tlb_batch);
-	if (batch->active) {
-		current_thread_info()->local_flags |= _TLF_LAZY_MMU;
-		if (batch->index)
-			__flush_tlb_pending(batch);
-		batch->active = 0;
-	}
-
 	/*
 	 * On POWER9 the copy-paste buffer can only paste into
 	 * foreign real addresses, so unprivileged processes can not
@@ -1369,20 +1358,6 @@ struct task_struct *__switch_to(struct task_struct *prev,
 	 */
 
 #ifdef CONFIG_PPC_BOOK3S_64
-#ifdef CONFIG_PPC_64S_HASH_MMU
-	/*
-	 * This applies to a process that was context switched while inside
-	 * arch_enter_lazy_mmu_mode(), to re-activate the batch that was
-	 * deactivated above, before _switch(). This will never be the case
-	 * for new tasks.
-	 */
-	if (current_thread_info()->local_flags & _TLF_LAZY_MMU) {
-		current_thread_info()->local_flags &= ~_TLF_LAZY_MMU;
-		batch = this_cpu_ptr(&ppc64_tlb_batch);
-		batch->active = 1;
-	}
-#endif
-
 	/*
 	 * Math facilities are masked out of the child MSR in copy_thread.
 	 * A new task does not need to restore_math because it will
-- 
2.51.2



From kevin.brodsky at arm.com  Mon Dec 15 07:03:11 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Mon, 15 Dec 2025 15:03:11 +0000
Subject: [PATCH v6 02/14] x86/xen: simplify flush_lazy_mmu()
In-Reply-To: <20251215150323.2218608-1-kevin.brodsky@arm.com>
References: <20251215150323.2218608-1-kevin.brodsky@arm.com>
Message-ID: <20251215150323.2218608-3-kevin.brodsky@arm.com>

arch_flush_lazy_mmu_mode() is called when outstanding batched
pgtable operations must be completed immediately. There should
however be no need to leave and re-enter lazy MMU completely. The
only part of that sequence that we really need is xen_mc_flush();
call it directly.

Reviewed-by: David Hildenbrand <david at redhat.com>
Reviewed-by: Ryan Roberts <ryan.roberts at arm.com>
Reviewed-by: Juergen Gross <jgross at suse.com>
Reviewed-by: Anshuman Khandual <anshuman.khandual at arm.com>
Signed-off-by: Kevin Brodsky <kevin.brodsky at arm.com>
---
 arch/x86/xen/mmu_pv.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/arch/x86/xen/mmu_pv.c b/arch/x86/xen/mmu_pv.c
index 2a4a8deaf612..7a35c3393df4 100644
--- a/arch/x86/xen/mmu_pv.c
+++ b/arch/x86/xen/mmu_pv.c
@@ -2139,10 +2139,8 @@ static void xen_flush_lazy_mmu(void)
 {
 	preempt_disable();
 
-	if (xen_get_lazy_mode() == XEN_LAZY_MMU) {
-		arch_leave_lazy_mmu_mode();
-		arch_enter_lazy_mmu_mode();
-	}
+	if (xen_get_lazy_mode() == XEN_LAZY_MMU)
+		xen_mc_flush();
 
 	preempt_enable();
 }
-- 
2.51.2



From kevin.brodsky at arm.com  Mon Dec 15 07:03:12 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Mon, 15 Dec 2025 15:03:12 +0000
Subject: [PATCH v6 03/14] powerpc/mm: implement arch_flush_lazy_mmu_mode()
In-Reply-To: <20251215150323.2218608-1-kevin.brodsky@arm.com>
References: <20251215150323.2218608-1-kevin.brodsky@arm.com>
Message-ID: <20251215150323.2218608-4-kevin.brodsky@arm.com>

Upcoming changes to the lazy_mmu API will cause
arch_flush_lazy_mmu_mode() to be called when leaving a nested
lazy_mmu section.

Move the relevant logic from arch_leave_lazy_mmu_mode() to
arch_flush_lazy_mmu_mode() and have the former call the latter. The
radix_enabled() check is required in both as
arch_flush_lazy_mmu_mode() will be called directly from the generic
layer in a subsequent patch.

Note: the additional this_cpu_ptr() and radix_enabled() calls on the
arch_leave_lazy_mmu_mode() path will be removed in a subsequent
patch.

Acked-by: David Hildenbrand <david at redhat.com>
Tested-by: Venkat Rao Bagalkote <venkat88 at linux.ibm.com>
Signed-off-by: Kevin Brodsky <kevin.brodsky at arm.com>
---
 .../powerpc/include/asm/book3s/64/tlbflush-hash.h | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/include/asm/book3s/64/tlbflush-hash.h b/arch/powerpc/include/asm/book3s/64/tlbflush-hash.h
index 146287d9580f..2d45f57df169 100644
--- a/arch/powerpc/include/asm/book3s/64/tlbflush-hash.h
+++ b/arch/powerpc/include/asm/book3s/64/tlbflush-hash.h
@@ -41,7 +41,7 @@ static inline void arch_enter_lazy_mmu_mode(void)
 	batch->active = 1;
 }
 
-static inline void arch_leave_lazy_mmu_mode(void)
+static inline void arch_flush_lazy_mmu_mode(void)
 {
 	struct ppc64_tlb_batch *batch;
 
@@ -51,12 +51,21 @@ static inline void arch_leave_lazy_mmu_mode(void)
 
 	if (batch->index)
 		__flush_tlb_pending(batch);
+}
+
+static inline void arch_leave_lazy_mmu_mode(void)
+{
+	struct ppc64_tlb_batch *batch;
+
+	if (radix_enabled())
+		return;
+	batch = this_cpu_ptr(&ppc64_tlb_batch);
+
+	arch_flush_lazy_mmu_mode();
 	batch->active = 0;
 	preempt_enable();
 }
 
-#define arch_flush_lazy_mmu_mode()      do {} while (0)
-
 extern void hash__tlbiel_all(unsigned int action);
 
 extern void flush_hash_page(unsigned long vpn, real_pte_t pte, int psize,
-- 
2.51.2



From kevin.brodsky at arm.com  Mon Dec 15 07:03:13 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Mon, 15 Dec 2025 15:03:13 +0000
Subject: [PATCH v6 04/14] sparc/mm: implement arch_flush_lazy_mmu_mode()
In-Reply-To: <20251215150323.2218608-1-kevin.brodsky@arm.com>
References: <20251215150323.2218608-1-kevin.brodsky@arm.com>
Message-ID: <20251215150323.2218608-5-kevin.brodsky@arm.com>

Upcoming changes to the lazy_mmu API will cause
arch_flush_lazy_mmu_mode() to be called when leaving a nested
lazy_mmu section.

Move the relevant logic from arch_leave_lazy_mmu_mode() to
arch_flush_lazy_mmu_mode() and have the former call the latter.

Note: the additional this_cpu_ptr() call on the
arch_leave_lazy_mmu_mode() path will be removed in a subsequent
patch.

Acked-by: David Hildenbrand <david at redhat.com>
Signed-off-by: Kevin Brodsky <kevin.brodsky at arm.com>
---
 arch/sparc/include/asm/tlbflush_64.h | 2 +-
 arch/sparc/mm/tlb.c                  | 9 ++++++++-
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/arch/sparc/include/asm/tlbflush_64.h b/arch/sparc/include/asm/tlbflush_64.h
index 8b8cdaa69272..925bb5d7a4e1 100644
--- a/arch/sparc/include/asm/tlbflush_64.h
+++ b/arch/sparc/include/asm/tlbflush_64.h
@@ -43,8 +43,8 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end);
 
 void flush_tlb_pending(void);
 void arch_enter_lazy_mmu_mode(void);
+void arch_flush_lazy_mmu_mode(void);
 void arch_leave_lazy_mmu_mode(void);
-#define arch_flush_lazy_mmu_mode()      do {} while (0)
 
 /* Local cpu only.  */
 void __flush_tlb_all(void);
diff --git a/arch/sparc/mm/tlb.c b/arch/sparc/mm/tlb.c
index a35ddcca5e76..7b5dfcdb1243 100644
--- a/arch/sparc/mm/tlb.c
+++ b/arch/sparc/mm/tlb.c
@@ -59,12 +59,19 @@ void arch_enter_lazy_mmu_mode(void)
 	tb->active = 1;
 }
 
-void arch_leave_lazy_mmu_mode(void)
+void arch_flush_lazy_mmu_mode(void)
 {
 	struct tlb_batch *tb = this_cpu_ptr(&tlb_batch);
 
 	if (tb->tlb_nr)
 		flush_tlb_pending();
+}
+
+void arch_leave_lazy_mmu_mode(void)
+{
+	struct tlb_batch *tb = this_cpu_ptr(&tlb_batch);
+
+	arch_flush_lazy_mmu_mode();
 	tb->active = 0;
 	preempt_enable();
 }
-- 
2.51.2



From kevin.brodsky at arm.com  Mon Dec 15 07:03:14 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Mon, 15 Dec 2025 15:03:14 +0000
Subject: [PATCH v6 05/14] mm: clarify lazy_mmu sleeping constraints
In-Reply-To: <20251215150323.2218608-1-kevin.brodsky@arm.com>
References: <20251215150323.2218608-1-kevin.brodsky@arm.com>
Message-ID: <20251215150323.2218608-6-kevin.brodsky@arm.com>

The lazy MMU mode documentation makes clear that an implementation
should not assume that preemption is disabled or any lock is held
upon entry to the mode; however it says nothing about what code
using the lazy MMU interface should expect.

In practice sleeping is forbidden (for generic code) while the lazy
MMU mode is active: say it explicitly.

Signed-off-by: Kevin Brodsky <kevin.brodsky at arm.com>
---
 include/linux/pgtable.h | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index 652f287c1ef6..1abc4a1c3d72 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -225,11 +225,15 @@ static inline int pmd_dirty(pmd_t pmd)
  * up to date.
  *
  * In the general case, no lock is guaranteed to be held between entry and exit
- * of the lazy mode. So the implementation must assume preemption may be enabled
- * and cpu migration is possible; it must take steps to be robust against this.
- * (In practice, for user PTE updates, the appropriate page table lock(s) are
- * held, but for kernel PTE updates, no lock is held). Nesting is not permitted
- * and the mode cannot be used in interrupt context.
+ * of the lazy mode. (In practice, for user PTE updates, the appropriate page
+ * table lock(s) are held, but for kernel PTE updates, no lock is held).
+ * The implementation must therefore assume preemption may be enabled upon
+ * entry to the mode and cpu migration is possible; it must take steps to be
+ * robust against this. An implementation may handle this by disabling
+ * preemption, as a consequence generic code may not sleep while the lazy MMU
+ * mode is active.
+ *
+ * Nesting is not permitted and the mode cannot be used in interrupt context.
  */
 #ifndef __HAVE_ARCH_ENTER_LAZY_MMU_MODE
 static inline void arch_enter_lazy_mmu_mode(void) {}
-- 
2.51.2



From kevin.brodsky at arm.com  Mon Dec 15 07:03:15 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Mon, 15 Dec 2025 15:03:15 +0000
Subject: [PATCH v6 06/14] mm: introduce CONFIG_ARCH_HAS_LAZY_MMU_MODE
In-Reply-To: <20251215150323.2218608-1-kevin.brodsky@arm.com>
References: <20251215150323.2218608-1-kevin.brodsky@arm.com>
Message-ID: <20251215150323.2218608-7-kevin.brodsky@arm.com>

Architectures currently opt in for implementing lazy_mmu helpers by
defining __HAVE_ARCH_ENTER_LAZY_MMU_MODE.

In preparation for introducing a generic lazy_mmu layer that will
require storage in task_struct, let's switch to a cleaner approach:
instead of defining a macro, select a CONFIG option.

This patch introduces CONFIG_ARCH_HAS_LAZY_MMU_MODE and has each
arch select it when it implements lazy_mmu helpers.
__HAVE_ARCH_ENTER_LAZY_MMU_MODE is removed and <linux/pgtable.h>
relies on the new CONFIG instead.

On x86, lazy_mmu helpers are only implemented if PARAVIRT_XXL is
selected. This creates some complications in arch/x86/boot/, because
a few files manually undefine PARAVIRT* options. As a result
<asm/paravirt.h> does not define the lazy_mmu helpers, but this
breaks the build as <linux/pgtable.h> only defines them if
!CONFIG_ARCH_HAS_LAZY_MMU_MODE. There does not seem to be a clean
way out of this - let's just undefine that new CONFIG too.

Acked-by: David Hildenbrand <david at redhat.com>
Reviewed-by: Ritesh Harjani (IBM) <ritesh.list at gmail.com>
Reviewed-by: Ryan Roberts <ryan.roberts at arm.com>
Signed-off-by: Kevin Brodsky <kevin.brodsky at arm.com>
---
 arch/arm64/Kconfig                                 | 1 +
 arch/arm64/include/asm/pgtable.h                   | 1 -
 arch/powerpc/include/asm/book3s/64/tlbflush-hash.h | 2 --
 arch/powerpc/platforms/Kconfig.cputype             | 1 +
 arch/sparc/Kconfig                                 | 1 +
 arch/sparc/include/asm/tlbflush_64.h               | 2 --
 arch/x86/Kconfig                                   | 1 +
 arch/x86/boot/compressed/misc.h                    | 1 +
 arch/x86/boot/startup/sme.c                        | 1 +
 arch/x86/include/asm/paravirt.h                    | 1 -
 include/linux/pgtable.h                            | 2 +-
 mm/Kconfig                                         | 7 +++++++
 12 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 93173f0a09c7..3fb4603c0e16 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -35,6 +35,7 @@ config ARM64
 	select ARCH_HAS_KCOV
 	select ARCH_HAS_KERNEL_FPU_SUPPORT if KERNEL_MODE_NEON
 	select ARCH_HAS_KEEPINITRD
+	select ARCH_HAS_LAZY_MMU_MODE
 	select ARCH_HAS_MEMBARRIER_SYNC_CORE
 	select ARCH_HAS_MEM_ENCRYPT
 	select ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 64d5f1d9cce9..f7d66c261347 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -80,7 +80,6 @@ static inline void queue_pte_barriers(void)
 	}
 }
 
-#define  __HAVE_ARCH_ENTER_LAZY_MMU_MODE
 static inline void arch_enter_lazy_mmu_mode(void)
 {
 	/*
diff --git a/arch/powerpc/include/asm/book3s/64/tlbflush-hash.h b/arch/powerpc/include/asm/book3s/64/tlbflush-hash.h
index 2d45f57df169..565c1b7c3eae 100644
--- a/arch/powerpc/include/asm/book3s/64/tlbflush-hash.h
+++ b/arch/powerpc/include/asm/book3s/64/tlbflush-hash.h
@@ -24,8 +24,6 @@ DECLARE_PER_CPU(struct ppc64_tlb_batch, ppc64_tlb_batch);
 
 extern void __flush_tlb_pending(struct ppc64_tlb_batch *batch);
 
-#define __HAVE_ARCH_ENTER_LAZY_MMU_MODE
-
 static inline void arch_enter_lazy_mmu_mode(void)
 {
 	struct ppc64_tlb_batch *batch;
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 4c321a8ea896..f399917c17bd 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -93,6 +93,7 @@ config PPC_BOOK3S_64
 	select IRQ_WORK
 	select PPC_64S_HASH_MMU if !PPC_RADIX_MMU
 	select KASAN_VMALLOC if KASAN
+	select ARCH_HAS_LAZY_MMU_MODE
 
 config PPC_BOOK3E_64
 	bool "Embedded processors"
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index a630d373e645..2bad14744ca4 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -112,6 +112,7 @@ config SPARC64
 	select NEED_PER_CPU_PAGE_FIRST_CHUNK
 	select ARCH_SUPPORTS_SCHED_SMT if SMP
 	select ARCH_SUPPORTS_SCHED_MC  if SMP
+	select ARCH_HAS_LAZY_MMU_MODE
 
 config ARCH_PROC_KCORE_TEXT
 	def_bool y
diff --git a/arch/sparc/include/asm/tlbflush_64.h b/arch/sparc/include/asm/tlbflush_64.h
index 925bb5d7a4e1..4e1036728e2f 100644
--- a/arch/sparc/include/asm/tlbflush_64.h
+++ b/arch/sparc/include/asm/tlbflush_64.h
@@ -39,8 +39,6 @@ static inline void flush_tlb_range(struct vm_area_struct *vma,
 
 void flush_tlb_kernel_range(unsigned long start, unsigned long end);
 
-#define __HAVE_ARCH_ENTER_LAZY_MMU_MODE
-
 void flush_tlb_pending(void);
 void arch_enter_lazy_mmu_mode(void);
 void arch_flush_lazy_mmu_mode(void);
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 80527299f859..2427a66cb0fe 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -808,6 +808,7 @@ config PARAVIRT
 config PARAVIRT_XXL
 	bool
 	depends on X86_64
+	select ARCH_HAS_LAZY_MMU_MODE
 
 config PARAVIRT_DEBUG
 	bool "paravirt-ops debugging"
diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h
index fd855e32c9b9..4f86c5903e03 100644
--- a/arch/x86/boot/compressed/misc.h
+++ b/arch/x86/boot/compressed/misc.h
@@ -11,6 +11,7 @@
 #undef CONFIG_PARAVIRT
 #undef CONFIG_PARAVIRT_XXL
 #undef CONFIG_PARAVIRT_SPINLOCKS
+#undef CONFIG_ARCH_HAS_LAZY_MMU_MODE
 #undef CONFIG_KASAN
 #undef CONFIG_KASAN_GENERIC
 
diff --git a/arch/x86/boot/startup/sme.c b/arch/x86/boot/startup/sme.c
index e7ea65f3f1d6..b76a7c95dfe1 100644
--- a/arch/x86/boot/startup/sme.c
+++ b/arch/x86/boot/startup/sme.c
@@ -24,6 +24,7 @@
 #undef CONFIG_PARAVIRT
 #undef CONFIG_PARAVIRT_XXL
 #undef CONFIG_PARAVIRT_SPINLOCKS
+#undef CONFIG_ARCH_HAS_LAZY_MMU_MODE
 
 /*
  * This code runs before CPU feature bits are set. By default, the
diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h
index b5e59a7ba0d0..13f9cd31c8f8 100644
--- a/arch/x86/include/asm/paravirt.h
+++ b/arch/x86/include/asm/paravirt.h
@@ -526,7 +526,6 @@ static inline void arch_end_context_switch(struct task_struct *next)
 	PVOP_VCALL1(cpu.end_context_switch, next);
 }
 
-#define  __HAVE_ARCH_ENTER_LAZY_MMU_MODE
 static inline void arch_enter_lazy_mmu_mode(void)
 {
 	PVOP_VCALL0(mmu.lazy_mode.enter);
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index 1abc4a1c3d72..d46d86959bd6 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -235,7 +235,7 @@ static inline int pmd_dirty(pmd_t pmd)
  *
  * Nesting is not permitted and the mode cannot be used in interrupt context.
  */
-#ifndef __HAVE_ARCH_ENTER_LAZY_MMU_MODE
+#ifndef CONFIG_ARCH_HAS_LAZY_MMU_MODE
 static inline void arch_enter_lazy_mmu_mode(void) {}
 static inline void arch_leave_lazy_mmu_mode(void) {}
 static inline void arch_flush_lazy_mmu_mode(void) {}
diff --git a/mm/Kconfig b/mm/Kconfig
index bd0ea5454af8..62073bd61544 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -1464,6 +1464,13 @@ config PT_RECLAIM
 config FIND_NORMAL_PAGE
 	def_bool n
 
+config ARCH_HAS_LAZY_MMU_MODE
+	bool
+	help
+	  The architecture uses the lazy MMU mode. This allows changes to
+	  MMU-related architectural state to be deferred until the mode is
+	  exited. See <linux/pgtable.h> for details.
+
 source "mm/damon/Kconfig"
 
 endmenu
-- 
2.51.2



From kevin.brodsky at arm.com  Mon Dec 15 07:03:16 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Mon, 15 Dec 2025 15:03:16 +0000
Subject: [PATCH v6 07/14] mm: introduce generic lazy_mmu helpers
In-Reply-To: <20251215150323.2218608-1-kevin.brodsky@arm.com>
References: <20251215150323.2218608-1-kevin.brodsky@arm.com>
Message-ID: <20251215150323.2218608-8-kevin.brodsky@arm.com>

The implementation of the lazy MMU mode is currently entirely
arch-specific; core code directly calls arch helpers:
arch_{enter,leave}_lazy_mmu_mode().

We are about to introduce support for nested lazy MMU sections.
As things stand we'd have to duplicate that logic in every arch
implementing lazy_mmu - adding to a fair amount of logic
already duplicated across lazy_mmu implementations.

This patch therefore introduces a new generic layer that calls the
existing arch_* helpers. Two pair of calls are introduced:

* lazy_mmu_mode_enable() ... lazy_mmu_mode_disable()
    This is the standard case where the mode is enabled for a given
    block of code by surrounding it with enable() and disable()
    calls.

* lazy_mmu_mode_pause() ... lazy_mmu_mode_resume()
    This is for situations where the mode is temporarily disabled
    by first calling pause() and then resume() (e.g. to prevent any
    batching from occurring in a critical section).

The documentation in <linux/pgtable.h> will be updated in a
subsequent patch.

No functional change should be introduced at this stage.
The implementation of enable()/resume() and disable()/pause() is
currently identical, but nesting support will change that.

Most of the call sites have been updated using the following
Coccinelle script:

@@
@@
{
...
- arch_enter_lazy_mmu_mode();
+ lazy_mmu_mode_enable();
...
- arch_leave_lazy_mmu_mode();
+ lazy_mmu_mode_disable();
...
}

@@
@@
{
...
- arch_leave_lazy_mmu_mode();
+ lazy_mmu_mode_pause();
...
- arch_enter_lazy_mmu_mode();
+ lazy_mmu_mode_resume();
...
}

A couple of notes regarding x86:

* Xen is currently the only case where explicit handling is required
  for lazy MMU when context-switching. This is purely an
  implementation detail and using the generic lazy_mmu_mode_*
  functions would cause trouble when nesting support is introduced,
  because the generic functions must be called from the current task.
  For that reason we still use arch_leave() and arch_enter() there.

* x86 calls arch_flush_lazy_mmu_mode() unconditionally in a few
  places, but only defines it if PARAVIRT_XXL is selected, and we
  are removing the fallback in <linux/pgtable.h>. Add a new fallback
  definition to <asm/pgtable.h> to keep things building.

Acked-by: David Hildenbrand <david at redhat.com>
Reviewed-by: Anshuman Khandual <anshuman.khandual at arm.com>
Signed-off-by: Kevin Brodsky <kevin.brodsky at arm.com>
---
 arch/arm64/mm/mmu.c                     |  8 +++----
 arch/arm64/mm/pageattr.c                |  4 ++--
 arch/powerpc/mm/book3s64/hash_tlb.c     |  8 +++----
 arch/powerpc/mm/book3s64/subpage_prot.c |  4 ++--
 arch/x86/include/asm/pgtable.h          |  1 +
 fs/proc/task_mmu.c                      |  4 ++--
 include/linux/pgtable.h                 | 29 +++++++++++++++++++++----
 mm/kasan/shadow.c                       |  8 +++----
 mm/madvise.c                            | 18 +++++++--------
 mm/memory.c                             | 16 +++++++-------
 mm/migrate_device.c                     |  8 +++----
 mm/mprotect.c                           |  4 ++--
 mm/mremap.c                             |  4 ++--
 mm/userfaultfd.c                        |  4 ++--
 mm/vmalloc.c                            | 12 +++++-----
 mm/vmscan.c                             | 12 +++++-----
 16 files changed, 83 insertions(+), 61 deletions(-)

diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 9ae7ce00a7ef..76d359f02982 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -801,7 +801,7 @@ int split_kernel_leaf_mapping(unsigned long start, unsigned long end)
 		return -EINVAL;
 
 	mutex_lock(&pgtable_split_lock);
-	arch_enter_lazy_mmu_mode();
+	lazy_mmu_mode_enable();
 
 	/*
 	 * The split_kernel_leaf_mapping_locked() may sleep, it is not a
@@ -823,7 +823,7 @@ int split_kernel_leaf_mapping(unsigned long start, unsigned long end)
 			ret = split_kernel_leaf_mapping_locked(end);
 	}
 
-	arch_leave_lazy_mmu_mode();
+	lazy_mmu_mode_disable();
 	mutex_unlock(&pgtable_split_lock);
 	return ret;
 }
@@ -884,10 +884,10 @@ static int range_split_to_ptes(unsigned long start, unsigned long end, gfp_t gfp
 {
 	int ret;
 
-	arch_enter_lazy_mmu_mode();
+	lazy_mmu_mode_enable();
 	ret = walk_kernel_page_table_range_lockless(start, end,
 					&split_to_ptes_ops, NULL, &gfp);
-	arch_leave_lazy_mmu_mode();
+	lazy_mmu_mode_disable();
 
 	return ret;
 }
diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c
index f0e784b963e6..508986608b49 100644
--- a/arch/arm64/mm/pageattr.c
+++ b/arch/arm64/mm/pageattr.c
@@ -110,7 +110,7 @@ static int update_range_prot(unsigned long start, unsigned long size,
 	if (WARN_ON_ONCE(ret))
 		return ret;
 
-	arch_enter_lazy_mmu_mode();
+	lazy_mmu_mode_enable();
 
 	/*
 	 * The caller must ensure that the range we are operating on does not
@@ -119,7 +119,7 @@ static int update_range_prot(unsigned long start, unsigned long size,
 	 */
 	ret = walk_kernel_page_table_range_lockless(start, start + size,
 						    &pageattr_ops, NULL, &data);
-	arch_leave_lazy_mmu_mode();
+	lazy_mmu_mode_disable();
 
 	return ret;
 }
diff --git a/arch/powerpc/mm/book3s64/hash_tlb.c b/arch/powerpc/mm/book3s64/hash_tlb.c
index 21fcad97ae80..787f7a0e27f0 100644
--- a/arch/powerpc/mm/book3s64/hash_tlb.c
+++ b/arch/powerpc/mm/book3s64/hash_tlb.c
@@ -205,7 +205,7 @@ void __flush_hash_table_range(unsigned long start, unsigned long end)
 	 * way to do things but is fine for our needs here.
 	 */
 	local_irq_save(flags);
-	arch_enter_lazy_mmu_mode();
+	lazy_mmu_mode_enable();
 	for (; start < end; start += PAGE_SIZE) {
 		pte_t *ptep = find_init_mm_pte(start, &hugepage_shift);
 		unsigned long pte;
@@ -217,7 +217,7 @@ void __flush_hash_table_range(unsigned long start, unsigned long end)
 			continue;
 		hpte_need_flush(&init_mm, start, ptep, pte, hugepage_shift);
 	}
-	arch_leave_lazy_mmu_mode();
+	lazy_mmu_mode_disable();
 	local_irq_restore(flags);
 }
 
@@ -237,7 +237,7 @@ void flush_hash_table_pmd_range(struct mm_struct *mm, pmd_t *pmd, unsigned long
 	 * way to do things but is fine for our needs here.
 	 */
 	local_irq_save(flags);
-	arch_enter_lazy_mmu_mode();
+	lazy_mmu_mode_enable();
 	start_pte = pte_offset_map(pmd, addr);
 	if (!start_pte)
 		goto out;
@@ -249,6 +249,6 @@ void flush_hash_table_pmd_range(struct mm_struct *mm, pmd_t *pmd, unsigned long
 	}
 	pte_unmap(start_pte);
 out:
-	arch_leave_lazy_mmu_mode();
+	lazy_mmu_mode_disable();
 	local_irq_restore(flags);
 }
diff --git a/arch/powerpc/mm/book3s64/subpage_prot.c b/arch/powerpc/mm/book3s64/subpage_prot.c
index ec98e526167e..07c47673bba2 100644
--- a/arch/powerpc/mm/book3s64/subpage_prot.c
+++ b/arch/powerpc/mm/book3s64/subpage_prot.c
@@ -73,13 +73,13 @@ static void hpte_flush_range(struct mm_struct *mm, unsigned long addr,
 	pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
 	if (!pte)
 		return;
-	arch_enter_lazy_mmu_mode();
+	lazy_mmu_mode_enable();
 	for (; npages > 0; --npages) {
 		pte_update(mm, addr, pte, 0, 0, 0);
 		addr += PAGE_SIZE;
 		++pte;
 	}
-	arch_leave_lazy_mmu_mode();
+	lazy_mmu_mode_disable();
 	pte_unmap_unlock(pte - 1, ptl);
 }
 
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index e33df3da6980..2842fa1f7a2c 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -118,6 +118,7 @@ extern pmdval_t early_pmd_flags;
 #define __pte(x)	native_make_pte(x)
 
 #define arch_end_context_switch(prev)	do {} while(0)
+static inline void arch_flush_lazy_mmu_mode(void) {}
 #endif	/* CONFIG_PARAVIRT_XXL */
 
 static inline pmd_t pmd_set_flags(pmd_t pmd, pmdval_t set)
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 81dfc26bfae8..480db575553e 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -2739,7 +2739,7 @@ static int pagemap_scan_pmd_entry(pmd_t *pmd, unsigned long start,
 		return 0;
 	}
 
-	arch_enter_lazy_mmu_mode();
+	lazy_mmu_mode_enable();
 
 	if ((p->arg.flags & PM_SCAN_WP_MATCHING) && !p->vec_out) {
 		/* Fast path for performing exclusive WP */
@@ -2809,7 +2809,7 @@ static int pagemap_scan_pmd_entry(pmd_t *pmd, unsigned long start,
 	if (flush_end)
 		flush_tlb_range(vma, start, addr);
 
-	arch_leave_lazy_mmu_mode();
+	lazy_mmu_mode_disable();
 	pte_unmap_unlock(start_pte, ptl);
 
 	cond_resched();
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index d46d86959bd6..116a18b7916c 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -235,10 +235,31 @@ static inline int pmd_dirty(pmd_t pmd)
  *
  * Nesting is not permitted and the mode cannot be used in interrupt context.
  */
-#ifndef CONFIG_ARCH_HAS_LAZY_MMU_MODE
-static inline void arch_enter_lazy_mmu_mode(void) {}
-static inline void arch_leave_lazy_mmu_mode(void) {}
-static inline void arch_flush_lazy_mmu_mode(void) {}
+#ifdef CONFIG_ARCH_HAS_LAZY_MMU_MODE
+static inline void lazy_mmu_mode_enable(void)
+{
+	arch_enter_lazy_mmu_mode();
+}
+
+static inline void lazy_mmu_mode_disable(void)
+{
+	arch_leave_lazy_mmu_mode();
+}
+
+static inline void lazy_mmu_mode_pause(void)
+{
+	arch_leave_lazy_mmu_mode();
+}
+
+static inline void lazy_mmu_mode_resume(void)
+{
+	arch_enter_lazy_mmu_mode();
+}
+#else
+static inline void lazy_mmu_mode_enable(void) {}
+static inline void lazy_mmu_mode_disable(void) {}
+static inline void lazy_mmu_mode_pause(void) {}
+static inline void lazy_mmu_mode_resume(void) {}
 #endif
 
 #ifndef pte_batch_hint
diff --git a/mm/kasan/shadow.c b/mm/kasan/shadow.c
index 29a751a8a08d..c1433d5cc5db 100644
--- a/mm/kasan/shadow.c
+++ b/mm/kasan/shadow.c
@@ -305,7 +305,7 @@ static int kasan_populate_vmalloc_pte(pte_t *ptep, unsigned long addr,
 	pte_t pte;
 	int index;
 
-	arch_leave_lazy_mmu_mode();
+	lazy_mmu_mode_pause();
 
 	index = PFN_DOWN(addr - data->start);
 	page = data->pages[index];
@@ -319,7 +319,7 @@ static int kasan_populate_vmalloc_pte(pte_t *ptep, unsigned long addr,
 	}
 	spin_unlock(&init_mm.page_table_lock);
 
-	arch_enter_lazy_mmu_mode();
+	lazy_mmu_mode_resume();
 
 	return 0;
 }
@@ -471,7 +471,7 @@ static int kasan_depopulate_vmalloc_pte(pte_t *ptep, unsigned long addr,
 	pte_t pte;
 	int none;
 
-	arch_leave_lazy_mmu_mode();
+	lazy_mmu_mode_pause();
 
 	spin_lock(&init_mm.page_table_lock);
 	pte = ptep_get(ptep);
@@ -483,7 +483,7 @@ static int kasan_depopulate_vmalloc_pte(pte_t *ptep, unsigned long addr,
 	if (likely(!none))
 		__free_page(pfn_to_page(pte_pfn(pte)));
 
-	arch_enter_lazy_mmu_mode();
+	lazy_mmu_mode_resume();
 
 	return 0;
 }
diff --git a/mm/madvise.c b/mm/madvise.c
index b617b1be0f53..6bf7009fa5ce 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -453,7 +453,7 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd,
 	if (!start_pte)
 		return 0;
 	flush_tlb_batched_pending(mm);
-	arch_enter_lazy_mmu_mode();
+	lazy_mmu_mode_enable();
 	for (; addr < end; pte += nr, addr += nr * PAGE_SIZE) {
 		nr = 1;
 		ptent = ptep_get(pte);
@@ -461,7 +461,7 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd,
 		if (++batch_count == SWAP_CLUSTER_MAX) {
 			batch_count = 0;
 			if (need_resched()) {
-				arch_leave_lazy_mmu_mode();
+				lazy_mmu_mode_disable();
 				pte_unmap_unlock(start_pte, ptl);
 				cond_resched();
 				goto restart;
@@ -497,7 +497,7 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd,
 				if (!folio_trylock(folio))
 					continue;
 				folio_get(folio);
-				arch_leave_lazy_mmu_mode();
+				lazy_mmu_mode_disable();
 				pte_unmap_unlock(start_pte, ptl);
 				start_pte = NULL;
 				err = split_folio(folio);
@@ -508,7 +508,7 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd,
 				if (!start_pte)
 					break;
 				flush_tlb_batched_pending(mm);
-				arch_enter_lazy_mmu_mode();
+				lazy_mmu_mode_enable();
 				if (!err)
 					nr = 0;
 				continue;
@@ -556,7 +556,7 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd,
 	}
 
 	if (start_pte) {
-		arch_leave_lazy_mmu_mode();
+		lazy_mmu_mode_disable();
 		pte_unmap_unlock(start_pte, ptl);
 	}
 	if (pageout)
@@ -675,7 +675,7 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,
 	if (!start_pte)
 		return 0;
 	flush_tlb_batched_pending(mm);
-	arch_enter_lazy_mmu_mode();
+	lazy_mmu_mode_enable();
 	for (; addr != end; pte += nr, addr += PAGE_SIZE * nr) {
 		nr = 1;
 		ptent = ptep_get(pte);
@@ -724,7 +724,7 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,
 				if (!folio_trylock(folio))
 					continue;
 				folio_get(folio);
-				arch_leave_lazy_mmu_mode();
+				lazy_mmu_mode_disable();
 				pte_unmap_unlock(start_pte, ptl);
 				start_pte = NULL;
 				err = split_folio(folio);
@@ -735,7 +735,7 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,
 				if (!start_pte)
 					break;
 				flush_tlb_batched_pending(mm);
-				arch_enter_lazy_mmu_mode();
+				lazy_mmu_mode_enable();
 				if (!err)
 					nr = 0;
 				continue;
@@ -775,7 +775,7 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,
 	if (nr_swap)
 		add_mm_counter(mm, MM_SWAPENTS, nr_swap);
 	if (start_pte) {
-		arch_leave_lazy_mmu_mode();
+		lazy_mmu_mode_disable();
 		pte_unmap_unlock(start_pte, ptl);
 	}
 	cond_resched();
diff --git a/mm/memory.c b/mm/memory.c
index 2a55edc48a65..ee15303c4041 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1256,7 +1256,7 @@ copy_pte_range(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma,
 	spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING);
 	orig_src_pte = src_pte;
 	orig_dst_pte = dst_pte;
-	arch_enter_lazy_mmu_mode();
+	lazy_mmu_mode_enable();
 
 	do {
 		nr = 1;
@@ -1325,7 +1325,7 @@ copy_pte_range(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma,
 	} while (dst_pte += nr, src_pte += nr, addr += PAGE_SIZE * nr,
 		 addr != end);
 
-	arch_leave_lazy_mmu_mode();
+	lazy_mmu_mode_disable();
 	pte_unmap_unlock(orig_src_pte, src_ptl);
 	add_mm_rss_vec(dst_mm, rss);
 	pte_unmap_unlock(orig_dst_pte, dst_ptl);
@@ -1842,7 +1842,7 @@ static unsigned long zap_pte_range(struct mmu_gather *tlb,
 		return addr;
 
 	flush_tlb_batched_pending(mm);
-	arch_enter_lazy_mmu_mode();
+	lazy_mmu_mode_enable();
 	do {
 		bool any_skipped = false;
 
@@ -1874,7 +1874,7 @@ static unsigned long zap_pte_range(struct mmu_gather *tlb,
 		direct_reclaim = try_get_and_clear_pmd(mm, pmd, &pmdval);
 
 	add_mm_rss_vec(mm, rss);
-	arch_leave_lazy_mmu_mode();
+	lazy_mmu_mode_disable();
 
 	/* Do the actual TLB flush before dropping ptl */
 	if (force_flush) {
@@ -2813,7 +2813,7 @@ static int remap_pte_range(struct mm_struct *mm, pmd_t *pmd,
 	mapped_pte = pte = pte_alloc_map_lock(mm, pmd, addr, &ptl);
 	if (!pte)
 		return -ENOMEM;
-	arch_enter_lazy_mmu_mode();
+	lazy_mmu_mode_enable();
 	do {
 		BUG_ON(!pte_none(ptep_get(pte)));
 		if (!pfn_modify_allowed(pfn, prot)) {
@@ -2823,7 +2823,7 @@ static int remap_pte_range(struct mm_struct *mm, pmd_t *pmd,
 		set_pte_at(mm, addr, pte, pte_mkspecial(pfn_pte(pfn, prot)));
 		pfn++;
 	} while (pte++, addr += PAGE_SIZE, addr != end);
-	arch_leave_lazy_mmu_mode();
+	lazy_mmu_mode_disable();
 	pte_unmap_unlock(mapped_pte, ptl);
 	return err;
 }
@@ -3174,7 +3174,7 @@ static int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd,
 			return -EINVAL;
 	}
 
-	arch_enter_lazy_mmu_mode();
+	lazy_mmu_mode_enable();
 
 	if (fn) {
 		do {
@@ -3187,7 +3187,7 @@ static int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd,
 	}
 	*mask |= PGTBL_PTE_MODIFIED;
 
-	arch_leave_lazy_mmu_mode();
+	lazy_mmu_mode_disable();
 
 	if (mm != &init_mm)
 		pte_unmap_unlock(mapped_pte, ptl);
diff --git a/mm/migrate_device.c b/mm/migrate_device.c
index 23379663b1e1..0346c2d7819f 100644
--- a/mm/migrate_device.c
+++ b/mm/migrate_device.c
@@ -271,7 +271,7 @@ static int migrate_vma_collect_pmd(pmd_t *pmdp,
 	ptep = pte_offset_map_lock(mm, pmdp, start, &ptl);
 	if (!ptep)
 		goto again;
-	arch_enter_lazy_mmu_mode();
+	lazy_mmu_mode_enable();
 	ptep += (addr - start) / PAGE_SIZE;
 
 	for (; addr < end; addr += PAGE_SIZE, ptep++) {
@@ -313,7 +313,7 @@ static int migrate_vma_collect_pmd(pmd_t *pmdp,
 			if (folio_test_large(folio)) {
 				int ret;
 
-				arch_leave_lazy_mmu_mode();
+				lazy_mmu_mode_disable();
 				pte_unmap_unlock(ptep, ptl);
 				ret = migrate_vma_split_folio(folio,
 							  migrate->fault_page);
@@ -356,7 +356,7 @@ static int migrate_vma_collect_pmd(pmd_t *pmdp,
 			if (folio && folio_test_large(folio)) {
 				int ret;
 
-				arch_leave_lazy_mmu_mode();
+				lazy_mmu_mode_disable();
 				pte_unmap_unlock(ptep, ptl);
 				ret = migrate_vma_split_folio(folio,
 							  migrate->fault_page);
@@ -485,7 +485,7 @@ static int migrate_vma_collect_pmd(pmd_t *pmdp,
 	if (unmapped)
 		flush_tlb_range(walk->vma, start, end);
 
-	arch_leave_lazy_mmu_mode();
+	lazy_mmu_mode_disable();
 	pte_unmap_unlock(ptep - 1, ptl);
 
 	return 0;
diff --git a/mm/mprotect.c b/mm/mprotect.c
index 283889e4f1ce..c0571445bef7 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -233,7 +233,7 @@ static long change_pte_range(struct mmu_gather *tlb,
 		is_private_single_threaded = vma_is_single_threaded_private(vma);
 
 	flush_tlb_batched_pending(vma->vm_mm);
-	arch_enter_lazy_mmu_mode();
+	lazy_mmu_mode_enable();
 	do {
 		nr_ptes = 1;
 		oldpte = ptep_get(pte);
@@ -379,7 +379,7 @@ static long change_pte_range(struct mmu_gather *tlb,
 			}
 		}
 	} while (pte += nr_ptes, addr += nr_ptes * PAGE_SIZE, addr != end);
-	arch_leave_lazy_mmu_mode();
+	lazy_mmu_mode_disable();
 	pte_unmap_unlock(pte - 1, ptl);
 
 	return pages;
diff --git a/mm/mremap.c b/mm/mremap.c
index 672264807db6..8275b9772ec1 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -260,7 +260,7 @@ static int move_ptes(struct pagetable_move_control *pmc,
 	if (new_ptl != old_ptl)
 		spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
 	flush_tlb_batched_pending(vma->vm_mm);
-	arch_enter_lazy_mmu_mode();
+	lazy_mmu_mode_enable();
 
 	for (; old_addr < old_end; old_ptep += nr_ptes, old_addr += nr_ptes * PAGE_SIZE,
 		new_ptep += nr_ptes, new_addr += nr_ptes * PAGE_SIZE) {
@@ -305,7 +305,7 @@ static int move_ptes(struct pagetable_move_control *pmc,
 		}
 	}
 
-	arch_leave_lazy_mmu_mode();
+	lazy_mmu_mode_disable();
 	if (force_flush)
 		flush_tlb_range(vma, old_end - len, old_end);
 	if (new_ptl != old_ptl)
diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index e6dfd5f28acd..b11f81095fa5 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -1103,7 +1103,7 @@ static long move_present_ptes(struct mm_struct *mm,
 	/* It's safe to drop the reference now as the page-table is holding one. */
 	folio_put(*first_src_folio);
 	*first_src_folio = NULL;
-	arch_enter_lazy_mmu_mode();
+	lazy_mmu_mode_enable();
 
 	while (true) {
 		orig_src_pte = ptep_get_and_clear(mm, src_addr, src_pte);
@@ -1140,7 +1140,7 @@ static long move_present_ptes(struct mm_struct *mm,
 			break;
 	}
 
-	arch_leave_lazy_mmu_mode();
+	lazy_mmu_mode_disable();
 	if (src_addr > src_start)
 		flush_tlb_range(src_vma, src_start, src_addr);
 
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index ecbac900c35f..1dea299fbb5a 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -108,7 +108,7 @@ static int vmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
 	if (!pte)
 		return -ENOMEM;
 
-	arch_enter_lazy_mmu_mode();
+	lazy_mmu_mode_enable();
 
 	do {
 		if (unlikely(!pte_none(ptep_get(pte)))) {
@@ -134,7 +134,7 @@ static int vmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
 		pfn++;
 	} while (pte += PFN_DOWN(size), addr += size, addr != end);
 
-	arch_leave_lazy_mmu_mode();
+	lazy_mmu_mode_disable();
 	*mask |= PGTBL_PTE_MODIFIED;
 	return 0;
 }
@@ -366,7 +366,7 @@ static void vunmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
 	unsigned long size = PAGE_SIZE;
 
 	pte = pte_offset_kernel(pmd, addr);
-	arch_enter_lazy_mmu_mode();
+	lazy_mmu_mode_enable();
 
 	do {
 #ifdef CONFIG_HUGETLB_PAGE
@@ -385,7 +385,7 @@ static void vunmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
 		WARN_ON(!pte_none(ptent) && !pte_present(ptent));
 	} while (pte += (size >> PAGE_SHIFT), addr += size, addr != end);
 
-	arch_leave_lazy_mmu_mode();
+	lazy_mmu_mode_disable();
 	*mask |= PGTBL_PTE_MODIFIED;
 }
 
@@ -533,7 +533,7 @@ static int vmap_pages_pte_range(pmd_t *pmd, unsigned long addr,
 	if (!pte)
 		return -ENOMEM;
 
-	arch_enter_lazy_mmu_mode();
+	lazy_mmu_mode_enable();
 
 	do {
 		struct page *page = pages[*nr];
@@ -555,7 +555,7 @@ static int vmap_pages_pte_range(pmd_t *pmd, unsigned long addr,
 		(*nr)++;
 	} while (pte++, addr += PAGE_SIZE, addr != end);
 
-	arch_leave_lazy_mmu_mode();
+	lazy_mmu_mode_disable();
 	*mask |= PGTBL_PTE_MODIFIED;
 
 	return err;
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 670fe9fae5ba..ab7ca55ca0f3 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -3516,7 +3516,7 @@ static bool walk_pte_range(pmd_t *pmd, unsigned long start, unsigned long end,
 		return false;
 	}
 
-	arch_enter_lazy_mmu_mode();
+	lazy_mmu_mode_enable();
 restart:
 	for (i = pte_index(start), addr = start; addr != end; i++, addr += PAGE_SIZE) {
 		unsigned long pfn;
@@ -3557,7 +3557,7 @@ static bool walk_pte_range(pmd_t *pmd, unsigned long start, unsigned long end,
 	if (i < PTRS_PER_PTE && get_next_vma(PMD_MASK, PAGE_SIZE, args, &start, &end))
 		goto restart;
 
-	arch_leave_lazy_mmu_mode();
+	lazy_mmu_mode_disable();
 	pte_unmap_unlock(pte, ptl);
 
 	return suitable_to_scan(total, young);
@@ -3598,7 +3598,7 @@ static void walk_pmd_range_locked(pud_t *pud, unsigned long addr, struct vm_area
 	if (!spin_trylock(ptl))
 		goto done;
 
-	arch_enter_lazy_mmu_mode();
+	lazy_mmu_mode_enable();
 
 	do {
 		unsigned long pfn;
@@ -3645,7 +3645,7 @@ static void walk_pmd_range_locked(pud_t *pud, unsigned long addr, struct vm_area
 
 	walk_update_folio(walk, last, gen, dirty);
 
-	arch_leave_lazy_mmu_mode();
+	lazy_mmu_mode_disable();
 	spin_unlock(ptl);
 done:
 	*first = -1;
@@ -4244,7 +4244,7 @@ bool lru_gen_look_around(struct page_vma_mapped_walk *pvmw)
 		}
 	}
 
-	arch_enter_lazy_mmu_mode();
+	lazy_mmu_mode_enable();
 
 	pte -= (addr - start) / PAGE_SIZE;
 
@@ -4278,7 +4278,7 @@ bool lru_gen_look_around(struct page_vma_mapped_walk *pvmw)
 
 	walk_update_folio(walk, last, gen, dirty);
 
-	arch_leave_lazy_mmu_mode();
+	lazy_mmu_mode_disable();
 
 	/* feedback from rmap walkers to page table walkers */
 	if (mm_state && suitable_to_scan(i, young))
-- 
2.51.2



From kevin.brodsky at arm.com  Mon Dec 15 07:03:17 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Mon, 15 Dec 2025 15:03:17 +0000
Subject: [PATCH v6 08/14] mm: bail out of lazy_mmu_mode_* in interrupt context
In-Reply-To: <20251215150323.2218608-1-kevin.brodsky@arm.com>
References: <20251215150323.2218608-1-kevin.brodsky@arm.com>
Message-ID: <20251215150323.2218608-9-kevin.brodsky@arm.com>

The lazy MMU mode cannot be used in interrupt context. This is
documented in <linux/pgtable.h>, but isn't consistently handled
across architectures.

arm64 ensures that calls to lazy_mmu_mode_* have no effect in
interrupt context, because such calls do occur in certain
configurations - see commit b81c688426a9 ("arm64/mm: Disable barrier
batching in interrupt contexts"). Other architectures do not check
this situation, most likely because it hasn't occurred so far.

Let's handle this in the new generic lazy_mmu layer, in the same
fashion as arm64: bail out of lazy_mmu_mode_* if in_interrupt().
Also remove the arm64 handling that is now redundant.

Both arm64 and x86/Xen also ensure that any lazy MMU optimisation is
disabled while in interrupt (see queue_pte_barriers() and
xen_get_lazy_mode() respectively). This will be handled in the
generic layer in a subsequent patch.

Acked-by: David Hildenbrand (Red Hat) <david at kernel.org>
Reviewed-by: Anshuman Khandual <anshuman.khandual at arm.com>
Signed-off-by: Kevin Brodsky <kevin.brodsky at arm.com>
---
 arch/arm64/include/asm/pgtable.h |  9 ---------
 include/linux/pgtable.h          | 17 ++++++++++++++++-
 2 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index f7d66c261347..bf9178902bdb 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -94,26 +94,17 @@ static inline void arch_enter_lazy_mmu_mode(void)
 	 * keeps tracking simple.
 	 */
 
-	if (in_interrupt())
-		return;
-
 	set_thread_flag(TIF_LAZY_MMU);
 }
 
 static inline void arch_flush_lazy_mmu_mode(void)
 {
-	if (in_interrupt())
-		return;
-
 	if (test_and_clear_thread_flag(TIF_LAZY_MMU_PENDING))
 		emit_pte_barriers();
 }
 
 static inline void arch_leave_lazy_mmu_mode(void)
 {
-	if (in_interrupt())
-		return;
-
 	arch_flush_lazy_mmu_mode();
 	clear_thread_flag(TIF_LAZY_MMU);
 }
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index 116a18b7916c..dddde6873d1e 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -233,26 +233,41 @@ static inline int pmd_dirty(pmd_t pmd)
  * preemption, as a consequence generic code may not sleep while the lazy MMU
  * mode is active.
  *
- * Nesting is not permitted and the mode cannot be used in interrupt context.
+ * The mode is disabled in interrupt context and calls to the lazy_mmu API have
+ * no effect.
+ *
+ * Nesting is not permitted.
  */
 #ifdef CONFIG_ARCH_HAS_LAZY_MMU_MODE
 static inline void lazy_mmu_mode_enable(void)
 {
+	if (in_interrupt())
+		return;
+
 	arch_enter_lazy_mmu_mode();
 }
 
 static inline void lazy_mmu_mode_disable(void)
 {
+	if (in_interrupt())
+		return;
+
 	arch_leave_lazy_mmu_mode();
 }
 
 static inline void lazy_mmu_mode_pause(void)
 {
+	if (in_interrupt())
+		return;
+
 	arch_leave_lazy_mmu_mode();
 }
 
 static inline void lazy_mmu_mode_resume(void)
 {
+	if (in_interrupt())
+		return;
+
 	arch_enter_lazy_mmu_mode();
 }
 #else
-- 
2.51.2



From kevin.brodsky at arm.com  Mon Dec 15 07:03:18 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Mon, 15 Dec 2025 15:03:18 +0000
Subject: [PATCH v6 09/14] mm: enable lazy_mmu sections to nest
In-Reply-To: <20251215150323.2218608-1-kevin.brodsky@arm.com>
References: <20251215150323.2218608-1-kevin.brodsky@arm.com>
Message-ID: <20251215150323.2218608-10-kevin.brodsky@arm.com>

Despite recent efforts to prevent lazy_mmu sections from nesting, it
remains difficult to ensure that it never occurs - and in fact it
does occur on arm64 in certain situations (CONFIG_DEBUG_PAGEALLOC).
Commit 1ef3095b1405 ("arm64/mm: Permit lazy_mmu_mode to be nested")
made nesting tolerable on arm64, but without truly supporting it:
the inner call to leave() disables the batching optimisation before
the outer section ends.

This patch actually enables lazy_mmu sections to nest by tracking
the nesting level in task_struct, in a similar fashion to e.g.
pagefault_{enable,disable}(). This is fully handled by the generic
lazy_mmu helpers that were recently introduced.

lazy_mmu sections were not initially intended to nest, so we need to
clarify the semantics w.r.t. the arch_*_lazy_mmu_mode() callbacks.
This patch takes the following approach:

* The outermost calls to lazy_mmu_mode_{enable,disable}() trigger
  calls to arch_{enter,leave}_lazy_mmu_mode() - this is unchanged.

* Nested calls to lazy_mmu_mode_{enable,disable}() are not forwarded
  to the arch via arch_{enter,leave} - lazy MMU remains enabled so
  the assumption is that these callbacks are not relevant. However,
  existing code may rely on a call to disable() to flush any batched
  state, regardless of nesting. arch_flush_lazy_mmu_mode() is
  therefore called in that situation.

A separate interface was recently introduced to temporarily pause
the lazy MMU mode: lazy_mmu_mode_{pause,resume}(). pause() fully
exits the mode *regardless of the nesting level*, and resume()
restores the mode at the same nesting level.

pause()/resume() are themselves allowed to nest, so we actually
store two nesting levels in task_struct: enable_count and
pause_count. A new helper is_lazy_mmu_mode_active() is introduced to
determine whether we are currently in lazy MMU mode; this will be
used in subsequent patches to replace the various ways arch's
currently track whether the mode is enabled.

In summary (enable/pause represent the values *after* the call):

lazy_mmu_mode_enable()		-> arch_enter()	    enable=1 pause=0
    lazy_mmu_mode_enable()	-> ?		    enable=2 pause=0
	lazy_mmu_mode_pause()	-> arch_leave()     enable=2 pause=1
	lazy_mmu_mode_resume()	-> arch_enter()     enable=2 pause=0
    lazy_mmu_mode_disable()	-> arch_flush()     enable=1 pause=0
lazy_mmu_mode_disable()		-> arch_leave()     enable=0 pause=0

Note: is_lazy_mmu_mode_active() is added to <linux/sched.h> to allow
arch headers included by <linux/pgtable.h> to use it.

Acked-by: David Hildenbrand (Red Hat) <david at kernel.org>
Signed-off-by: Kevin Brodsky <kevin.brodsky at arm.com>
---
 arch/arm64/include/asm/pgtable.h |  12 ----
 include/linux/mm_types_task.h    |   5 ++
 include/linux/pgtable.h          | 114 +++++++++++++++++++++++++++++--
 include/linux/sched.h            |  45 ++++++++++++
 4 files changed, 157 insertions(+), 19 deletions(-)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index bf9178902bdb..7f528c36d53c 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -82,18 +82,6 @@ static inline void queue_pte_barriers(void)
 
 static inline void arch_enter_lazy_mmu_mode(void)
 {
-	/*
-	 * lazy_mmu_mode is not supposed to permit nesting. But in practice this
-	 * does happen with CONFIG_DEBUG_PAGEALLOC, where a page allocation
-	 * inside a lazy_mmu_mode section (such as zap_pte_range()) will change
-	 * permissions on the linear map with apply_to_page_range(), which
-	 * re-enters lazy_mmu_mode. So we tolerate nesting in our
-	 * implementation. The first call to arch_leave_lazy_mmu_mode() will
-	 * flush and clear the flag such that the remainder of the work in the
-	 * outer nest behaves as if outside of lazy mmu mode. This is safe and
-	 * keeps tracking simple.
-	 */
-
 	set_thread_flag(TIF_LAZY_MMU);
 }
 
diff --git a/include/linux/mm_types_task.h b/include/linux/mm_types_task.h
index a82aa80c0ba4..11bf319d78ec 100644
--- a/include/linux/mm_types_task.h
+++ b/include/linux/mm_types_task.h
@@ -88,4 +88,9 @@ struct tlbflush_unmap_batch {
 #endif
 };
 
+struct lazy_mmu_state {
+	u8 enable_count;
+	u8 pause_count;
+};
+
 #endif /* _LINUX_MM_TYPES_TASK_H */
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index dddde6873d1e..2f0dd3a4ace1 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -236,39 +236,139 @@ static inline int pmd_dirty(pmd_t pmd)
  * The mode is disabled in interrupt context and calls to the lazy_mmu API have
  * no effect.
  *
- * Nesting is not permitted.
+ * The lazy MMU mode is enabled for a given block of code using:
+ *
+ *   lazy_mmu_mode_enable();
+ *   <code>
+ *   lazy_mmu_mode_disable();
+ *
+ * Nesting is permitted: <code> may itself use an enable()/disable() pair.
+ * A nested call to enable() has no functional effect; however disable() causes
+ * any batched architectural state to be flushed regardless of nesting. After a
+ * call to disable(), the caller can therefore rely on all previous page table
+ * modifications to have taken effect, but the lazy MMU mode may still be
+ * enabled.
+ *
+ * In certain cases, it may be desirable to temporarily pause the lazy MMU mode.
+ * This can be done using:
+ *
+ *   lazy_mmu_mode_pause();
+ *   <code>
+ *   lazy_mmu_mode_resume();
+ *
+ * pause() ensures that the mode is exited regardless of the nesting level;
+ * resume() re-enters the mode at the same nesting level. Any call to the
+ * lazy_mmu_mode_* API between those two calls has no effect. In particular,
+ * this means that pause()/resume() pairs may nest.
+ *
+ * is_lazy_mmu_mode_active() can be used to check whether the lazy MMU mode is
+ * currently enabled.
  */
 #ifdef CONFIG_ARCH_HAS_LAZY_MMU_MODE
+/**
+ * lazy_mmu_mode_enable() - Enable the lazy MMU mode.
+ *
+ * Enters a new lazy MMU mode section; if the mode was not already enabled,
+ * enables it and calls arch_enter_lazy_mmu_mode().
+ *
+ * Must be paired with a call to lazy_mmu_mode_disable().
+ *
+ * Has no effect if called:
+ * - While paused - see lazy_mmu_mode_pause()
+ * - In interrupt context
+ */
 static inline void lazy_mmu_mode_enable(void)
 {
-	if (in_interrupt())
+	struct lazy_mmu_state *state = &current->lazy_mmu_state;
+
+	if (in_interrupt() || state->pause_count > 0)
 		return;
 
-	arch_enter_lazy_mmu_mode();
+	VM_WARN_ON_ONCE(state->enable_count == U8_MAX);
+
+	if (state->enable_count++ == 0)
+		arch_enter_lazy_mmu_mode();
 }
 
+/**
+ * lazy_mmu_mode_disable() - Disable the lazy MMU mode.
+ *
+ * Exits the current lazy MMU mode section. If it is the outermost section,
+ * disables the mode and calls arch_leave_lazy_mmu_mode(). Otherwise (nested
+ * section), calls arch_flush_lazy_mmu_mode().
+ *
+ * Must match a call to lazy_mmu_mode_enable().
+ *
+ * Has no effect if called:
+ * - While paused - see lazy_mmu_mode_pause()
+ * - In interrupt context
+ */
 static inline void lazy_mmu_mode_disable(void)
 {
-	if (in_interrupt())
+	struct lazy_mmu_state *state = &current->lazy_mmu_state;
+
+	if (in_interrupt() || state->pause_count > 0)
 		return;
 
-	arch_leave_lazy_mmu_mode();
+	VM_WARN_ON_ONCE(state->enable_count == 0);
+
+	if (--state->enable_count == 0)
+		arch_leave_lazy_mmu_mode();
+	else /* Exiting a nested section */
+		arch_flush_lazy_mmu_mode();
+
 }
 
+/**
+ * lazy_mmu_mode_pause() - Pause the lazy MMU mode.
+ *
+ * Pauses the lazy MMU mode; if it is currently active, disables it and calls
+ * arch_leave_lazy_mmu_mode().
+ *
+ * Must be paired with a call to lazy_mmu_mode_resume(). Calls to the
+ * lazy_mmu_mode_* API have no effect until the matching resume() call.
+ *
+ * Has no effect if called:
+ * - While paused (inside another pause()/resume() pair)
+ * - In interrupt context
+ */
 static inline void lazy_mmu_mode_pause(void)
 {
+	struct lazy_mmu_state *state = &current->lazy_mmu_state;
+
 	if (in_interrupt())
 		return;
 
-	arch_leave_lazy_mmu_mode();
+	VM_WARN_ON_ONCE(state->pause_count == U8_MAX);
+
+	if (state->pause_count++ == 0 && state->enable_count > 0)
+		arch_leave_lazy_mmu_mode();
 }
 
+/**
+ * lazy_mmu_mode_resume() - Resume the lazy MMU mode.
+ *
+ * Resumes the lazy MMU mode; if it was active at the point where the matching
+ * call to lazy_mmu_mode_pause() was made, re-enables it and calls
+ * arch_enter_lazy_mmu_mode().
+ *
+ * Must match a call to lazy_mmu_mode_pause().
+ *
+ * Has no effect if called:
+ * - While paused (inside another pause()/resume() pair)
+ * - In interrupt context
+ */
 static inline void lazy_mmu_mode_resume(void)
 {
+	struct lazy_mmu_state *state = &current->lazy_mmu_state;
+
 	if (in_interrupt())
 		return;
 
-	arch_enter_lazy_mmu_mode();
+	VM_WARN_ON_ONCE(state->pause_count == 0);
+
+	if (--state->pause_count == 0 && state->enable_count > 0)
+		arch_enter_lazy_mmu_mode();
 }
 #else
 static inline void lazy_mmu_mode_enable(void) {}
diff --git a/include/linux/sched.h b/include/linux/sched.h
index d395f2810fac..f2fc6584c790 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1419,6 +1419,10 @@ struct task_struct {
 
 	struct page_frag		task_frag;
 
+#ifdef CONFIG_ARCH_HAS_LAZY_MMU_MODE
+	struct lazy_mmu_state		lazy_mmu_state;
+#endif
+
 #ifdef CONFIG_TASK_DELAY_ACCT
 	struct task_delay_info		*delays;
 #endif
@@ -1702,6 +1706,47 @@ static inline char task_state_to_char(struct task_struct *tsk)
 	return task_index_to_char(task_state_index(tsk));
 }
 
+#ifdef CONFIG_ARCH_HAS_LAZY_MMU_MODE
+/**
+ * __task_lazy_mmu_mode_active() - Test the lazy MMU mode state for a task.
+ * @tsk: The task to check.
+ *
+ * Test whether @tsk has its lazy MMU mode state set to active (i.e. enabled
+ * and not paused).
+ *
+ * This function only considers the state saved in task_struct; to test whether
+ * current actually is in lazy MMU mode, is_lazy_mmu_mode_active() should be
+ * used instead.
+ *
+ * This function is intended for architectures that implement the lazy MMU
+ * mode; it must not be called from generic code.
+ */
+static inline bool __task_lazy_mmu_mode_active(struct task_struct *tsk)
+{
+	struct lazy_mmu_state *state = &tsk->lazy_mmu_state;
+
+	return state->enable_count > 0 && state->pause_count == 0;
+}
+
+/**
+ * is_lazy_mmu_mode_active() - Test whether we are currently in lazy MMU mode.
+ *
+ * Test whether the current context is in lazy MMU mode. This is true if both:
+ * 1. We are not in interrupt context
+ * 2. Lazy MMU mode is active for the current task
+ *
+ * This function is intended for architectures that implement the lazy MMU
+ * mode; it must not be called from generic code.
+ */
+static inline bool is_lazy_mmu_mode_active(void)
+{
+	if (in_interrupt())
+		return false;
+
+	return __task_lazy_mmu_mode_active(current);
+}
+#endif
+
 extern struct pid *cad_pid;
 
 /*
-- 
2.51.2



From kevin.brodsky at arm.com  Mon Dec 15 07:03:19 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Mon, 15 Dec 2025 15:03:19 +0000
Subject: [PATCH v6 10/14] arm64: mm: replace TIF_LAZY_MMU with is_lazy_mmu_mode_active()
In-Reply-To: <20251215150323.2218608-1-kevin.brodsky@arm.com>
References: <20251215150323.2218608-1-kevin.brodsky@arm.com>
Message-ID: <20251215150323.2218608-11-kevin.brodsky@arm.com>

The generic lazy_mmu layer now tracks whether a task is in lazy MMU
mode. As a result we no longer need a TIF flag for that purpose -
let's use the new is_lazy_mmu_mode_active() helper instead.

The explicit check for in_interrupt() is no longer necessary either
as is_lazy_mmu_mode_active() always returns false in interrupt
context.

Acked-by: David Hildenbrand (Red Hat) <david at kernel.org>
Reviewed-by: Anshuman Khandual <anshuman.khandual at arm.com>
Signed-off-by: Kevin Brodsky <kevin.brodsky at arm.com>
---
 arch/arm64/include/asm/pgtable.h     | 19 +++----------------
 arch/arm64/include/asm/thread_info.h |  3 +--
 2 files changed, 4 insertions(+), 18 deletions(-)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 7f528c36d53c..445e18e92221 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -62,28 +62,16 @@ static inline void emit_pte_barriers(void)
 
 static inline void queue_pte_barriers(void)
 {
-	unsigned long flags;
-
-	if (in_interrupt()) {
-		emit_pte_barriers();
-		return;
-	}
-
-	flags = read_thread_flags();
-
-	if (flags & BIT(TIF_LAZY_MMU)) {
+	if (is_lazy_mmu_mode_active()) {
 		/* Avoid the atomic op if already set. */
-		if (!(flags & BIT(TIF_LAZY_MMU_PENDING)))
+		if (!test_thread_flag(TIF_LAZY_MMU_PENDING))
 			set_thread_flag(TIF_LAZY_MMU_PENDING);
 	} else {
 		emit_pte_barriers();
 	}
 }
 
-static inline void arch_enter_lazy_mmu_mode(void)
-{
-	set_thread_flag(TIF_LAZY_MMU);
-}
+static inline void arch_enter_lazy_mmu_mode(void) {}
 
 static inline void arch_flush_lazy_mmu_mode(void)
 {
@@ -94,7 +82,6 @@ static inline void arch_flush_lazy_mmu_mode(void)
 static inline void arch_leave_lazy_mmu_mode(void)
 {
 	arch_flush_lazy_mmu_mode();
-	clear_thread_flag(TIF_LAZY_MMU);
 }
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index a803b887b0b4..e7cd017b07c8 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -84,8 +84,7 @@ void arch_setup_new_exec(void);
 #define TIF_SME_VL_INHERIT	28	/* Inherit SME vl_onexec across exec */
 #define TIF_KERNEL_FPSTATE	29	/* Task is in a kernel mode FPSIMD section */
 #define TIF_TSC_SIGSEGV		30	/* SIGSEGV on counter-timer access */
-#define TIF_LAZY_MMU		31	/* Task in lazy mmu mode */
-#define TIF_LAZY_MMU_PENDING	32	/* Ops pending for lazy mmu mode exit */
+#define TIF_LAZY_MMU_PENDING	31	/* Ops pending for lazy mmu mode exit */
 
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
-- 
2.51.2



From kevin.brodsky at arm.com  Mon Dec 15 07:03:20 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Mon, 15 Dec 2025 15:03:20 +0000
Subject: [PATCH v6 11/14] powerpc/mm: replace batch->active with is_lazy_mmu_mode_active()
In-Reply-To: <20251215150323.2218608-1-kevin.brodsky@arm.com>
References: <20251215150323.2218608-1-kevin.brodsky@arm.com>
Message-ID: <20251215150323.2218608-12-kevin.brodsky@arm.com>

A per-CPU batch struct is activated when entering lazy MMU mode; its
lifetime is the same as the lazy MMU section (it is deactivated when
leaving the mode). Preemption is disabled in that interval to ensure
that the per-CPU reference remains valid.

The generic lazy_mmu layer now tracks whether a task is in lazy MMU
mode. We can therefore use the generic helper
is_lazy_mmu_mode_active() to tell whether a batch struct is active
instead of tracking it explicitly.

Acked-by: David Hildenbrand <david at redhat.com>
Reviewed-by: Ritesh Harjani (IBM) <ritesh.list at gmail.com>
Tested-by: Venkat Rao Bagalkote <venkat88 at linux.ibm.com>
Signed-off-by: Kevin Brodsky <kevin.brodsky at arm.com>
---
 arch/powerpc/include/asm/book3s/64/tlbflush-hash.h | 9 ---------
 arch/powerpc/mm/book3s64/hash_tlb.c                | 2 +-
 2 files changed, 1 insertion(+), 10 deletions(-)

diff --git a/arch/powerpc/include/asm/book3s/64/tlbflush-hash.h b/arch/powerpc/include/asm/book3s/64/tlbflush-hash.h
index 565c1b7c3eae..6cc9abcd7b3d 100644
--- a/arch/powerpc/include/asm/book3s/64/tlbflush-hash.h
+++ b/arch/powerpc/include/asm/book3s/64/tlbflush-hash.h
@@ -12,7 +12,6 @@
 #define PPC64_TLB_BATCH_NR 192
 
 struct ppc64_tlb_batch {
-	int			active;
 	unsigned long		index;
 	struct mm_struct	*mm;
 	real_pte_t		pte[PPC64_TLB_BATCH_NR];
@@ -26,8 +25,6 @@ extern void __flush_tlb_pending(struct ppc64_tlb_batch *batch);
 
 static inline void arch_enter_lazy_mmu_mode(void)
 {
-	struct ppc64_tlb_batch *batch;
-
 	if (radix_enabled())
 		return;
 	/*
@@ -35,8 +32,6 @@ static inline void arch_enter_lazy_mmu_mode(void)
 	 * operating on kernel page tables.
 	 */
 	preempt_disable();
-	batch = this_cpu_ptr(&ppc64_tlb_batch);
-	batch->active = 1;
 }
 
 static inline void arch_flush_lazy_mmu_mode(void)
@@ -53,14 +48,10 @@ static inline void arch_flush_lazy_mmu_mode(void)
 
 static inline void arch_leave_lazy_mmu_mode(void)
 {
-	struct ppc64_tlb_batch *batch;
-
 	if (radix_enabled())
 		return;
-	batch = this_cpu_ptr(&ppc64_tlb_batch);
 
 	arch_flush_lazy_mmu_mode();
-	batch->active = 0;
 	preempt_enable();
 }
 
diff --git a/arch/powerpc/mm/book3s64/hash_tlb.c b/arch/powerpc/mm/book3s64/hash_tlb.c
index 787f7a0e27f0..fbdeb8981ae7 100644
--- a/arch/powerpc/mm/book3s64/hash_tlb.c
+++ b/arch/powerpc/mm/book3s64/hash_tlb.c
@@ -100,7 +100,7 @@ void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
 	 * Check if we have an active batch on this CPU. If not, just
 	 * flush now and return.
 	 */
-	if (!batch->active) {
+	if (!is_lazy_mmu_mode_active()) {
 		flush_hash_page(vpn, rpte, psize, ssize, mm_is_thread_local(mm));
 		put_cpu_var(ppc64_tlb_batch);
 		return;
-- 
2.51.2



From kevin.brodsky at arm.com  Mon Dec 15 07:03:21 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Mon, 15 Dec 2025 15:03:21 +0000
Subject: [PATCH v6 12/14] sparc/mm: replace batch->active with is_lazy_mmu_mode_active()
In-Reply-To: <20251215150323.2218608-1-kevin.brodsky@arm.com>
References: <20251215150323.2218608-1-kevin.brodsky@arm.com>
Message-ID: <20251215150323.2218608-13-kevin.brodsky@arm.com>

A per-CPU batch struct is activated when entering lazy MMU mode; its
lifetime is the same as the lazy MMU section (it is deactivated when
leaving the mode). Preemption is disabled in that interval to ensure
that the per-CPU reference remains valid.

The generic lazy_mmu layer now tracks whether a task is in lazy MMU
mode. We can therefore use the generic helper
is_lazy_mmu_mode_active() to tell whether a batch struct is active
instead of tracking it explicitly.

Acked-by: David Hildenbrand (Red Hat) <david at kernel.org>
Signed-off-by: Kevin Brodsky <kevin.brodsky at arm.com>
---
 arch/sparc/include/asm/tlbflush_64.h | 1 -
 arch/sparc/mm/tlb.c                  | 9 +--------
 2 files changed, 1 insertion(+), 9 deletions(-)

diff --git a/arch/sparc/include/asm/tlbflush_64.h b/arch/sparc/include/asm/tlbflush_64.h
index 4e1036728e2f..6133306ba59a 100644
--- a/arch/sparc/include/asm/tlbflush_64.h
+++ b/arch/sparc/include/asm/tlbflush_64.h
@@ -12,7 +12,6 @@ struct tlb_batch {
 	unsigned int hugepage_shift;
 	struct mm_struct *mm;
 	unsigned long tlb_nr;
-	unsigned long active;
 	unsigned long vaddrs[TLB_BATCH_NR];
 };
 
diff --git a/arch/sparc/mm/tlb.c b/arch/sparc/mm/tlb.c
index 7b5dfcdb1243..3a852071d260 100644
--- a/arch/sparc/mm/tlb.c
+++ b/arch/sparc/mm/tlb.c
@@ -52,11 +52,7 @@ void flush_tlb_pending(void)
 
 void arch_enter_lazy_mmu_mode(void)
 {
-	struct tlb_batch *tb;
-
 	preempt_disable();
-	tb = this_cpu_ptr(&tlb_batch);
-	tb->active = 1;
 }
 
 void arch_flush_lazy_mmu_mode(void)
@@ -69,10 +65,7 @@ void arch_flush_lazy_mmu_mode(void)
 
 void arch_leave_lazy_mmu_mode(void)
 {
-	struct tlb_batch *tb = this_cpu_ptr(&tlb_batch);
-
 	arch_flush_lazy_mmu_mode();
-	tb->active = 0;
 	preempt_enable();
 }
 
@@ -93,7 +86,7 @@ static void tlb_batch_add_one(struct mm_struct *mm, unsigned long vaddr,
 		nr = 0;
 	}
 
-	if (!tb->active) {
+	if (!is_lazy_mmu_mode_active()) {
 		flush_tsb_user_page(mm, vaddr, hugepage_shift);
 		global_flush_tlb_page(mm, vaddr);
 		goto out;
-- 
2.51.2



From kevin.brodsky at arm.com  Mon Dec 15 07:03:22 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Mon, 15 Dec 2025 15:03:22 +0000
Subject: [PATCH v6 13/14] x86/xen: use lazy_mmu_state when context-switching
In-Reply-To: <20251215150323.2218608-1-kevin.brodsky@arm.com>
References: <20251215150323.2218608-1-kevin.brodsky@arm.com>
Message-ID: <20251215150323.2218608-14-kevin.brodsky@arm.com>

We currently set a TIF flag when scheduling out a task that is in
lazy MMU mode, in order to restore it when the task is scheduled
again.

The generic lazy_mmu layer now tracks whether a task is in lazy MMU
mode in task_struct::lazy_mmu_state. We can therefore check that
state when switching to the new task, instead of using a separate
TIF flag.

Acked-by: David Hildenbrand (Red Hat) <david at kernel.org>
Reviewed-by: Juergen Gross <jgross at suse.com>
Signed-off-by: Kevin Brodsky <kevin.brodsky at arm.com>
---
 arch/x86/include/asm/thread_info.h | 4 +---
 arch/x86/xen/enlighten_pv.c        | 3 +--
 2 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index e71e0e8362ed..0067684afb5b 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -100,8 +100,7 @@ struct thread_info {
 #define TIF_FORCED_TF		24	/* true if TF in eflags artificially */
 #define TIF_SINGLESTEP		25	/* reenable singlestep on user return*/
 #define TIF_BLOCKSTEP		26	/* set when we want DEBUGCTLMSR_BTF */
-#define TIF_LAZY_MMU_UPDATES	27	/* task is updating the mmu lazily */
-#define TIF_ADDR32		28	/* 32-bit address space on 64 bits */
+#define TIF_ADDR32		27	/* 32-bit address space on 64 bits */
 
 #define _TIF_SSBD		BIT(TIF_SSBD)
 #define _TIF_SPEC_IB		BIT(TIF_SPEC_IB)
@@ -114,7 +113,6 @@ struct thread_info {
 #define _TIF_FORCED_TF		BIT(TIF_FORCED_TF)
 #define _TIF_BLOCKSTEP		BIT(TIF_BLOCKSTEP)
 #define _TIF_SINGLESTEP		BIT(TIF_SINGLESTEP)
-#define _TIF_LAZY_MMU_UPDATES	BIT(TIF_LAZY_MMU_UPDATES)
 #define _TIF_ADDR32		BIT(TIF_ADDR32)
 
 /* flags to check in __switch_to() */
diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c
index 4806cc28d7ca..98dbb6a61087 100644
--- a/arch/x86/xen/enlighten_pv.c
+++ b/arch/x86/xen/enlighten_pv.c
@@ -426,7 +426,6 @@ static void xen_start_context_switch(struct task_struct *prev)
 
 	if (this_cpu_read(xen_lazy_mode) == XEN_LAZY_MMU) {
 		arch_leave_lazy_mmu_mode();
-		set_ti_thread_flag(task_thread_info(prev), TIF_LAZY_MMU_UPDATES);
 	}
 	enter_lazy(XEN_LAZY_CPU);
 }
@@ -437,7 +436,7 @@ static void xen_end_context_switch(struct task_struct *next)
 
 	xen_mc_flush();
 	leave_lazy(XEN_LAZY_CPU);
-	if (test_and_clear_ti_thread_flag(task_thread_info(next), TIF_LAZY_MMU_UPDATES))
+	if (__task_lazy_mmu_mode_active(next))
 		arch_enter_lazy_mmu_mode();
 }
 
-- 
2.51.2



From kevin.brodsky at arm.com  Mon Dec 15 07:03:23 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Mon, 15 Dec 2025 15:03:23 +0000
Subject: [PATCH v6 14/14] mm: Add basic tests for lazy_mmu
In-Reply-To: <20251215150323.2218608-1-kevin.brodsky@arm.com>
References: <20251215150323.2218608-1-kevin.brodsky@arm.com>
Message-ID: <20251215150323.2218608-15-kevin.brodsky@arm.com>

Add basic KUnit tests for the generic aspects of the lazy MMU mode:
ensure that it appears active when it should, depending on how
enable/disable and pause/resume pairs are nested.

Signed-off-by: Kevin Brodsky <kevin.brodsky at arm.com>
---
 mm/Kconfig                     | 12 ++++++
 mm/Makefile                    |  1 +
 mm/tests/lazy_mmu_mode_kunit.c | 71 ++++++++++++++++++++++++++++++++++
 3 files changed, 84 insertions(+)
 create mode 100644 mm/tests/lazy_mmu_mode_kunit.c

diff --git a/mm/Kconfig b/mm/Kconfig
index 62073bd61544..ac48deb44884 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -1471,6 +1471,18 @@ config ARCH_HAS_LAZY_MMU_MODE
 	  MMU-related architectural state to be deferred until the mode is
 	  exited. See <linux/pgtable.h> for details.
 
+config LAZY_MMU_MODE_KUNIT_TEST
+	tristate "KUnit tests for the lazy MMU mode" if !KUNIT_ALL_TESTS
+	depends on ARCH_HAS_LAZY_MMU_MODE
+	depends on KUNIT
+	default KUNIT_ALL_TESTS
+	help
+	  Enable this option to check that the lazy MMU mode interface behaves
+	  as expected. Only tests for the generic interface are included (not
+	  architecture-specific behaviours).
+
+	  If unsure, say N.
+
 source "mm/damon/Kconfig"
 
 endmenu
diff --git a/mm/Makefile b/mm/Makefile
index 2d0570a16e5b..9175f8cc6565 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -147,3 +147,4 @@ obj-$(CONFIG_SHRINKER_DEBUG) += shrinker_debug.o
 obj-$(CONFIG_EXECMEM) += execmem.o
 obj-$(CONFIG_TMPFS_QUOTA) += shmem_quota.o
 obj-$(CONFIG_PT_RECLAIM) += pt_reclaim.o
+obj-$(CONFIG_LAZY_MMU_MODE_KUNIT_TEST) += tests/lazy_mmu_mode_kunit.o
diff --git a/mm/tests/lazy_mmu_mode_kunit.c b/mm/tests/lazy_mmu_mode_kunit.c
new file mode 100644
index 000000000000..2720eb995714
--- /dev/null
+++ b/mm/tests/lazy_mmu_mode_kunit.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <kunit/test.h>
+#include <linux/pgtable.h>
+
+static void expect_not_active(struct kunit *test)
+{
+	KUNIT_EXPECT_FALSE(test, is_lazy_mmu_mode_active());
+}
+
+static void expect_active(struct kunit *test)
+{
+	KUNIT_EXPECT_TRUE(test, is_lazy_mmu_mode_active());
+}
+
+static void lazy_mmu_mode_active(struct kunit *test)
+{
+	expect_not_active(test);
+
+	lazy_mmu_mode_enable();
+	expect_active(test);
+
+	{
+		/* Nested section */
+		lazy_mmu_mode_enable();
+		expect_active(test);
+
+		lazy_mmu_mode_disable();
+		expect_active(test);
+	}
+
+	{
+		/* Paused section */
+		lazy_mmu_mode_pause();
+		expect_not_active(test);
+
+		{
+			/* No effect (paused) */
+			lazy_mmu_mode_enable();
+			expect_not_active(test);
+
+			lazy_mmu_mode_disable();
+			expect_not_active(test);
+
+			lazy_mmu_mode_pause();
+			expect_not_active(test);
+
+			lazy_mmu_mode_resume();
+			expect_not_active(test);
+		}
+
+		lazy_mmu_mode_resume();
+		expect_active(test);
+	}
+
+	lazy_mmu_mode_disable();
+	expect_not_active(test);
+}
+
+static struct kunit_case lazy_mmu_mode_test_cases[] = {
+	KUNIT_CASE(lazy_mmu_mode_active),
+	{}
+};
+
+static struct kunit_suite lazy_mmu_mode_test_suite = {
+	.name = "lazy_mmu_mode",
+	.test_cases = lazy_mmu_mode_test_cases,
+};
+kunit_test_suite(lazy_mmu_mode_test_suite);
+
+MODULE_DESCRIPTION("Tests for the lazy MMU mode");
+MODULE_LICENSE("GPL");
-- 
2.51.2



From linux at timmermann.space  Mon Dec 15 07:05:22 2025
From: linux at timmermann.space (Lukas Timmermann)
Date: Mon, 15 Dec 2025 16:05:22 +0100
Subject: [PATCH v3 1/3] dt-bindings: ARM: samsung: Add Google Manta (Nexus
 10)
In-Reply-To: <20251215-lat3st-staging-v3-0-2e4914b64dd8@timmermann.space>
References: <20251215-lat3st-staging-v3-0-2e4914b64dd8@timmermann.space>
Message-ID: <20251215-lat3st-staging-v3-1-2e4914b64dd8@timmermann.space>

From: Alexandre Marquet <tb at a-marquet.fr>

Add the Google Nexus 10 board to documentation.

Signed-off-by: Alexandre Marquet <tb at a-marquet.fr>
Signed-off-by: Lukas Timmermann <linux at timmermann.space>
---
 Documentation/devicetree/bindings/arm/samsung/samsung-boards.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/arm/samsung/samsung-boards.yaml b/Documentation/devicetree/bindings/arm/samsung/samsung-boards.yaml
index f8e20e602c20..13d97257f070 100644
--- a/Documentation/devicetree/bindings/arm/samsung/samsung-boards.yaml
+++ b/Documentation/devicetree/bindings/arm/samsung/samsung-boards.yaml
@@ -117,6 +117,7 @@ properties:
       - description: Exynos5250 based boards
         items:
           - enum:
+              - google,manta                    # Google Manta (Nexus 10)
               - google,snow-rev5                # Google Snow Rev 5+
               - google,spring                   # Google Spring
               - insignal,arndale                # Insignal Arndale

-- 
2.52.0



From linux at timmermann.space  Mon Dec 15 07:05:24 2025
From: linux at timmermann.space (Lukas Timmermann)
Date: Mon, 15 Dec 2025 16:05:24 +0100
Subject: [PATCH v3 3/3] ARM: samsung: exynos5250: Allow CPU1 to boot
In-Reply-To: <20251215-lat3st-staging-v3-0-2e4914b64dd8@timmermann.space>
References: <20251215-lat3st-staging-v3-0-2e4914b64dd8@timmermann.space>
Message-ID: <20251215-lat3st-staging-v3-3-2e4914b64dd8@timmermann.space>

From: Alexandre Marquet <tb at a-marquet.fr>

The firmware trustzone needs a special call to bring up the secondary
cpu core on the Manta board. This seems to be not needed on other
exynos5 boards and comes down to the available firmware on
a particular board.

Signed-off-by: Alexandre Marquet <tb at a-marquet.fr>
Signed-off-by: Lukas Timmermann <linux at timmermann.space>
---
 arch/arm/mach-exynos/firmware.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c
index a5e22678e27b..e9b0ed07bb90 100644
--- a/arch/arm/mach-exynos/firmware.c
+++ b/arch/arm/mach-exynos/firmware.c
@@ -61,10 +61,10 @@ static int exynos_cpu_boot(int cpu)
 	 * Exynos3250 doesn't need to send smc command for secondary CPU boot
 	 * because Exynos3250 removes WFE in secure mode.
 	 *
-	 * On Exynos5 devices the call is ignored by trustzone firmware.
+	 * On most Exynos5 devices the call is ignored by trustzone firmware.
 	 */
 	if (!soc_is_exynos4210() && !soc_is_exynos4212() &&
-	    !soc_is_exynos4412())
+	    !soc_is_exynos4412() && !of_machine_is_compatible("google,manta"))
 		return 0;
 
 	/*

-- 
2.52.0



From linux at timmermann.space  Mon Dec 15 07:05:21 2025
From: linux at timmermann.space (Lukas Timmermann)
Date: Mon, 15 Dec 2025 16:05:21 +0100
Subject: [PATCH v3 0/3] Add support for exynos5250-manta (Google Nexus 10)
Message-ID: <20251215-lat3st-staging-v3-0-2e4914b64dd8@timmermann.space>

This patch series adds initial support for the google-manta board, known
as Google Nexus 10 to users. The device is powered by
the Exynos 5250 SoC. The bindings for the notification led are already 
in the kernel mailing list, got recently applied and can be found here:
https://lore.kernel.org/linux-leds/20251125114015.355487-1-linux at timmermann.space/

The first two patches add the necessary device tree files and
bindings, while the last patch makes a small modification to
allow CPU1 to boot, as it requires a call to it's underlying firmware.

This first iteration only provides basic support to get the board
up and running and usable via UART and with WiFi support. We will upstream additional 
features in future patches. All patches have been tested on real hardware.

Changes in v3:
 - Added a better patch description for firmware patch. (@krzk)
 - Reorganized nodes in DT. (@krzk)
 - Fixed memory node to use separate entries. (@krzk)
 - Renamed pwrseq node. (@krzk)
 - Fixed firmware checking for old dt compatible string. (@pavel)
 - Link to v2: https://lore.kernel.org/all/20251125-google-manta-v2-0-0f097cfff39c at timmermann.space/
Changes in v2:
 - Renamed to google-manta (@krzk)
 - Link to v1: https://lore.kernel.org/all/20251120144018.961604-2-linux at timmermann.space/

Signed-off-by: Lukas Timmermann <linux at timmermann.space>
---
Alexandre Marquet (3):
      dt-bindings: ARM: samsung: Add Google Manta (Nexus 10)
      ARM: dts: exynos: Add Google Manta (Nexus 10)
      ARM: samsung: exynos5250: Allow CPU1 to boot

 .../bindings/arm/samsung/samsung-boards.yaml       |   1 +
 arch/arm/boot/dts/samsung/Makefile                 |   1 +
 arch/arm/boot/dts/samsung/exynos5250-manta.dts     | 511 +++++++++++++++++++++
 arch/arm/mach-exynos/firmware.c                    |   4 +-
 4 files changed, 515 insertions(+), 2 deletions(-)
---
base-commit: d5f0e9098499869354aacb5b080f602f0399d396
change-id: 20251215-lat3st-staging-d9c926d8a75f

Best regards,
-- 
Lukas Timmermann <linux at timmermann.space>



From linux at timmermann.space  Mon Dec 15 07:05:23 2025
From: linux at timmermann.space (Lukas Timmermann)
Date: Mon, 15 Dec 2025 16:05:23 +0100
Subject: [PATCH v3 2/3] ARM: dts: exynos: Add Google Manta (Nexus 10)
In-Reply-To: <20251215-lat3st-staging-v3-0-2e4914b64dd8@timmermann.space>
References: <20251215-lat3st-staging-v3-0-2e4914b64dd8@timmermann.space>
Message-ID: <20251215-lat3st-staging-v3-2-2e4914b64dd8@timmermann.space>

From: Alexandre Marquet <tb at a-marquet.fr>

Manta is the code name for Google Nexus 10, and was manufactured by
Samsung with their Exynos5250 SoC.
This patch adds initial device-tree file for this board.

Signed-off-by: Alexandre Marquet <tb at a-marquet.fr>
Co-developed-by: Lukas Timmermann <linux at timmermann.space>
Signed-off-by: Lukas Timmermann <linux at timmermann.space>
---
 arch/arm/boot/dts/samsung/Makefile             |   1 +
 arch/arm/boot/dts/samsung/exynos5250-manta.dts | 511 +++++++++++++++++++++++++
 2 files changed, 512 insertions(+)

diff --git a/arch/arm/boot/dts/samsung/Makefile b/arch/arm/boot/dts/samsung/Makefile
index 7becf36656b1..e0143ee8c82d 100644
--- a/arch/arm/boot/dts/samsung/Makefile
+++ b/arch/arm/boot/dts/samsung/Makefile
@@ -26,6 +26,7 @@ dtb-$(CONFIG_ARCH_EXYNOS4) += \
 	exynos4412-trats2.dtb
 dtb-$(CONFIG_ARCH_EXYNOS5) += \
 	exynos5250-arndale.dtb \
+	exynos5250-manta.dtb \
 	exynos5250-smdk5250.dtb \
 	exynos5250-snow.dtb \
 	exynos5250-snow-rev5.dtb \
diff --git a/arch/arm/boot/dts/samsung/exynos5250-manta.dts b/arch/arm/boot/dts/samsung/exynos5250-manta.dts
new file mode 100644
index 000000000000..0f006590576c
--- /dev/null
+++ b/arch/arm/boot/dts/samsung/exynos5250-manta.dts
@@ -0,0 +1,511 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Google Manta (Nexus 10) board device tree source
+ *
+ * Copyright (c) 2023-2025 Alexandre Marquet
+ * Copyright (c) 2025 Lukas Timmermann
+ */
+
+/dts-v1/;
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/clock/maxim,max77686.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include "exynos-pinctrl.h"
+#include "exynos5250.dtsi"
+#include "exynos-mfc-reserved-memory.dtsi"
+
+/ {
+	model = "Google Nexus 10";
+	compatible = "google,manta", "samsung,exynos5250", "samsung,exynos5";
+
+	aliases {
+		mmc0 = &mmc_0; /* eMMC */
+		mmc1 = &mmc_1; /* WiFi */
+	};
+
+	bmp180_vdda_reg: regulator-bmp180-vdda {
+		compatible = "regulator-fixed";
+		regulator-name = "BMP180_VDDA";
+	};
+
+	bmp180_vddd_reg: regulator-bmp180-vddd {
+		compatible = "regulator-fixed";
+		regulator-name = "BMP180_VDDD";
+	};
+
+	chosen {
+		stdout-path = &serial_2;
+	};
+
+	fixed-rate-clocks {
+		xxti {
+			compatible = "samsung,clock-xxti";
+			clock-frequency = <24000000>;
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+		pinctrl-names = "default";
+		pinctrl-0 = <&gpio_keys>;
+
+		key-down {
+			gpios = <&gpx2 1 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_VOLUMEDOWN>;
+			label = "volume down";
+			debounce-interval = <5>;
+		};
+
+		key-up {
+			gpios = <&gpx2 0 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_VOLUMEUP>;
+			label = "volume up";
+			debounce-interval = <5>;
+		};
+
+		key-power {
+			gpios = <&gpx2 7 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_POWER>;
+			label = "power";
+			debounce-interval = <5>;
+			wakeup-source;
+		};
+
+		lid-switch {
+			label = "Lid";
+			gpios = <&gpx1 3 GPIO_ACTIVE_LOW>;
+			linux,input-type = <5>; /* EV_SW */
+			linux,code = <0>; /* SW_LID */
+			debounce-interval = <10>;
+			wakeup-source;
+		};
+	};
+
+	multi-led {
+		compatible = "leds-group-multicolor";
+		color = <LED_COLOR_ID_RGB>;
+		function = LED_FUNCTION_STATUS;
+		leds = <&status_red>, <&status_green>, <&status_blue>, <&status_white>;
+	};
+
+	pwrseq: mmc1-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&gpv1 0 GPIO_ACTIVE_LOW>;
+		pinctrl-0 = <&wlan_pmena>;
+		pinctrl-names = "default";
+		clocks = <&max77686 MAX77686_CLK_PMIC>;
+		clock-names = "ext_clock";
+		post-power-on-delay-ms = <300>;
+		power-off-delay-us = <50>;
+	};
+
+	firmware at 203f000 {
+		compatible = "samsung,secure-firmware";
+		reg = <0x0204efff 0x1000>;
+	};
+
+	memory at 40000000 {
+		device_type = "memory";
+		reg = <0x40000000 0x20000000>,
+		      <0x60000000 0x20000000>,
+		      <0x80000000 0x20000000>,
+		      <0xa0000000 0x1ff00000>;
+	};
+};
+
+&clock {
+	assigned-clocks = <&clock CLK_FOUT_APLL>;
+	assigned-clock-rates = <1000000000>;
+};
+
+&cpu0 {
+	cpu0-supply = <&buck2_reg>;
+};
+
+&ehci {
+	status = "disabled";
+};
+
+&i2c_0 {
+	status = "okay";
+	samsung,i2c-sda-delay = <100>;
+	samsung,i2c-slave-addr = <0x10>;
+};
+
+&i2c_1 {
+	status = "okay";
+
+	pressure at 77 {
+		compatible = "bosch,bmp180";
+		reg = <0x77>;
+		vddd-supply = <&bmp180_vddd_reg>;
+		vdda-supply = <&bmp180_vdda_reg>;
+	};
+
+	imu at 68 {
+		compatible = "invensense,mpu6050";
+		reg = <0x68>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&acc_int>;
+		interrupt-parent = <&gpx1>;
+		interrupts = <4 IRQ_TYPE_EDGE_RISING>;
+		mount-matrix = "0",  "-1",  "0",
+				"-1",  "0",  "0",
+				"0",  "0", "-1";
+
+		i2c-gate {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			magnetometer at c {
+				compatible = "asahi-kasei,ak8963";
+				reg = <0x0c>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&msense_rst>;
+				mount-matrix = "-1",  "0",  "0",
+						"0",  "1",  "0",
+						"0",  "0", "-1";
+			};
+		};
+	};
+
+	led-controller at 42 {
+		compatible = "ams,as3668";
+		reg = <0x42>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		status_red: led at 0 {
+			reg = <0x0>;
+			function = LED_FUNCTION_STATUS;
+			color = <LED_COLOR_ID_RED>;
+		};
+
+		status_green: led at 1 {
+			reg = <0x1>;
+			function = LED_FUNCTION_STATUS;
+			color = <LED_COLOR_ID_GREEN>;
+		};
+
+		status_blue: led at 2 {
+			reg = <0x2>;
+			function = LED_FUNCTION_STATUS;
+			color = <LED_COLOR_ID_BLUE>;
+		};
+
+		status_white: led at 3 {
+			reg = <0x3>;
+			function = LED_FUNCTION_STATUS;
+			color = <LED_COLOR_ID_WHITE>;
+		};
+	};
+};
+
+&i2c_2 {
+	status = "okay";
+
+	light-sensor at 23 {
+		compatible = "rohm,bh1721";
+		reg = <0x23>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&bh1721fvc_reset>;
+		reset-gpios = <&gph1 2 GPIO_ACTIVE_LOW>;
+	};
+
+	onewire at 18 {
+		compatible = "maxim,ds2484";
+		reg = <0x18>;
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&onewire_sleep>;
+	};
+};
+
+&i2c_5 {
+	status = "okay";
+	samsung,i2c-sda-delay = <100>;
+
+	max77686: pmic at 9 {
+		compatible = "maxim,max77686";
+		reg = <0x09>;
+		interrupt-parent = <&gpx0>;
+		interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&max77686_irq>;
+		#clock-cells = <1>;
+		wakeup-source;
+
+		voltage-regulators {
+			ldo3_reg: LDO3 {
+				regulator-name = "VCC_1.8V_AP";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			ldo8_reg: LDO8 {
+				regulator-name = "VMIPI_1.0V";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			ldo9_reg: LDO9 {
+				regulator-name = "TOUCH_VDD_1.8V";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			ldo10_reg: LDO10 {
+				regulator-name = "VMIPI_1.8V";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			ldo12_reg: LDO12 {
+				regulator-name = "VUOTG_3.0V";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			ldo15_reg: LDO15 {
+				regulator-name = "VHSIC_1.0V";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			ldo16_reg: LDO16 {
+				regulator-name = "VHSIC_1.8V";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			ldo17_reg: LDO17 {
+				regulator-name = "5M_CORE_1.5V";
+				regulator-min-microvolt = <1500000>;
+				regulator-max-microvolt = <1500000>;
+			};
+			ldo18_reg: LDO18 {
+				regulator-name = "CAM_IO_1.8V";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			ldo19_reg: LDO19 {
+				regulator-name = "VT_CAM_1.8V";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			ldo20_reg: LDO20 {
+				regulator-name = "TA_CHECK_1.35V";
+				regulator-min-microvolt = <1350000>;
+				regulator-max-microvolt = <1350000>;
+			};
+			ldo23_reg: LDO23 {
+				regulator-name = "TSP_AVDD_2.8V";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+			};
+			ldo24_reg: LDO24 {
+				regulator-name = "CAM_AF_2.8V";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+			};
+			ldo25_reg: LDO25 {
+				regulator-name = "VADC_3.3V";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			buck1_reg: BUCK1 {
+				regulator-name = "vdd_mif";
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			buck2_reg: BUCK2 {
+				regulator-name = "vdd_arm";
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			buck3_reg: BUCK3 {
+				regulator-name = "vdd_int";
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			buck4_reg: BUCK4 {
+				regulator-name = "vdd_g3d";
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-boot-on;
+			};
+		};
+	};
+};
+
+&mali {
+	status = "okay";
+	mali-supply = <&buck4_reg>;
+};
+
+&mixer {
+	status = "okay";
+};
+
+/* eMMC */
+&mmc_0 {
+	status = "okay";
+	non-removable;
+	max-frequency = <200000000>;
+	sd-uhs-ddr50;
+	mmc-ddr-1_8v;
+	cap-mmc-hw-reset;
+	mmc-hs200-1_8v;
+	bus-width = <8>;
+	card-detect-delay = <200>;
+	samsung,dw-mshc-ciu-div = <3>;
+	samsung,dw-mshc-sdr-timing = <1 2>;
+	samsung,dw-mshc-ddr-timing = <2 3>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
+};
+
+/* WiFi */
+&mmc_1 {
+	status = "okay";
+	non-removable;
+	max-frequency = <100000000>;
+	sd-uhs-sdr50;
+	cap-sd-highspeed;
+	keep-power-in-suspend;
+	bus-width = <4>;
+	card-detect-delay = <0>;
+	samsung,dw-mshc-ciu-div = <3>;
+	samsung,dw-mshc-sdr-timing = <2 4>;
+	samsung,dw-mshc-ddr-timing = <2 3>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&sd1_clk &sd1_cmd &sd1_bus4>;
+	mmc-pwrseq = <&pwrseq>;
+
+	wifi at 1 {
+		compatible = "brcm,bcm4330-fmac", "brcm,bcm4329-fmac";
+		reg = <1>;
+		interrupt-parent = <&gpx2>;
+		interrupts = <5 IRQ_TYPE_NONE>;
+		interrupt-names = "host-wake";
+		pinctrl-names = "default";
+		pinctrl-0 = <&wlan_irq>;
+	};
+};
+
+&ohci {
+	status = "disabled";
+};
+
+&pinctrl_0 {
+	acc_int: acc-int-pins {
+		samsung,pins = "gpx1-4";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_EINT>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+	};
+
+	max77686_irq: max77686-irq-pins {
+		samsung,pins = "gpx0-2";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+	gpio_keys: gpio-keys-pins-pins {
+		samsung,pins = "gpx2-0", "gpx2-1", "gpx2-7", "gpx1-3";
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+	};
+	wlan_irq: wlan-irq-pins {
+		samsung,pins = "gpx2-5";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV3>;
+	};
+};
+
+&pinctrl_1 {
+	bh1721fvc_reset: bh1721fvc-reset-pins {
+		samsung,pins = "gph1-2";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+	};
+	msense_rst: msense-rst-pins {
+		samsung,pins = "gpg2-0";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+	};
+	onewire_sleep: onewire-sleep-pins {
+		samsung,pins = "gpg0-0";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-con-pdn = <EXYNOS_PIN_PDN_INPUT>;
+		samsung,pin-pud-pdn = <EXYNOS_PIN_PULL_NONE>;
+	};
+};
+
+&pinctrl_2 {
+	wlan_pmena: wlan-pmena-pins {
+		samsung,pins = "gpv1-0";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV3>;
+		samsung,pin-con-pdn = <EXYNOS_PIN_PDN_PREV>;
+		samsung,pin-val = <0>;
+	};
+};
+
+&pmu_system_controller {
+	assigned-clocks = <&pmu_system_controller 0>;
+	assigned-clock-parents = <&clock CLK_FIN_PLL>;
+};
+
+&sd1_bus4 {
+	samsung,pin-con-pdn = <EXYNOS_PIN_PDN_INPUT>;
+	samsung,pin-pud-pdn = <EXYNOS_PIN_PULL_NONE>;
+};
+
+&sd1_cmd {
+	samsung,pin-con-pdn = <EXYNOS_PIN_PDN_INPUT>;
+	samsung,pin-pud-pdn = <EXYNOS_PIN_PULL_NONE>;
+};
+
+/* Bluetooth */
+&serial_0 {
+	status = "disabled";
+};
+
+&serial_1 {
+	pinctrl-names = "default", "flow-control";
+	pinctrl-0 = <&uart1_data>;
+	pinctrl-1 = <&uart1_data>, <&uart1_fctl>;
+};
+
+&serial_2 {
+	pinctrl-names = "default", "flow-control";
+	pinctrl-0 = <&uart2_data>;
+	pinctrl-1 = <&uart2_data>, <&uart2_fctl>;
+};
+
+&usbdrd {
+	status = "disabled";
+};
+
+&usbdrd_dwc3 {
+	status = "disabled";
+};
+
+&usbdrd_phy {
+	status = "disabled";
+};

-- 
2.52.0



From alexandru.elisei at arm.com  Mon Dec 15 07:17:27 2025
From: alexandru.elisei at arm.com (Alexandru Elisei)
Date: Mon, 15 Dec 2025 15:17:27 +0000
Subject: [PATCH v2 2/4] KVM: arm64: Print register encoding if there's no
 accessor
In-Reply-To: <86ike7onhr.wl-maz@kernel.org>
References: <20251215114409.212512-1-alexandru.elisei@arm.com>
 <20251215114409.212512-3-alexandru.elisei@arm.com>
 <86ike7onhr.wl-maz@kernel.org>
Message-ID: <aUAmh32jCUOWMg8K@raptor>

Hi Marc,

On Mon, Dec 15, 2025 at 01:58:40PM +0000, Marc Zyngier wrote:
> On Mon, 15 Dec 2025 11:44:07 +0000,
> Alexandru Elisei <alexandru.elisei at arm.com> wrote:
> > 
> > Configuring a register trap without specifying an accessor function is
> > abviously a bug. Instead of calling die() when that happens, let's be a bit
> > more helpful and print the register encoding and kill the virtual machine
> > instead.
> > 
> > Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
> > ---
> >  arch/arm64/kvm/sys_regs.c | 8 +++++++-
> >  1 file changed, 7 insertions(+), 1 deletion(-)
> > 
> > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> > index c8fd7c6a12a1..d669f6fef177 100644
> > --- a/arch/arm64/kvm/sys_regs.c
> > +++ b/arch/arm64/kvm/sys_regs.c
> > @@ -4668,7 +4668,13 @@ static void perform_access(struct kvm_vcpu *vcpu,
> >  	 * that we don't know how to handle. This certainly qualifies
> >  	 * as a gross bug that should be fixed right away.
> >  	 */
> > -	BUG_ON(!r->access);
> > +	if (!r->access) {
> > +		KVM_BUG(1, vcpu->kvm,
> > +			"Unexpected access to register: { Op0(%2u), Op1(%2u), CRn(%2u), CRm(%2u), Op2(%2u) } (%s)",
> > +			params->Op0, params->Op1, params->CRn, params->CRm, params->Op2,
> > +			str_write_read(params->is_write));
> > +		return;
> > +	}
> 
> Why not writing
> 
> 	if (KVM_BUG(!r>access, ...))
> 		return;
> 
> instead? And you could reuse the format that's already defined in
> print_sys_reg_msg().
> 
> You could instead consider injecting an UNDEF in the guest, which I

Injecting an undefined instruction exception early in the boot process can lead
to an infinite loop of undefined instruction exceptions in the guest. This is
what happens for the unhandled PIRE0_EL1 trap that the previous patch fixes. The
guest access takes place in __cpu_setup(), when there are no vectors installed.

If you're ok with this, I can move forward with the below:

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index c8fd7c6a12a1..516072417649 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -4668,7 +4668,10 @@ static void perform_access(struct kvm_vcpu *vcpu,
         * that we don't know how to handle. This certainly qualifies
         * as a gross bug that should be fixed right away.
         */
-       BUG_ON(!r->access);
+       if (!r->access) {
+               bad_trap(vcpu, params, r, "Unexpected register access");
+               return;
+       }

        /* Skip instruction if instructed so */
        if (likely(r->access(vcpu, params, r)))

And this is what KVM prints (the register encoding is outside the trace snippet,
if you think that would make a difference to the end user):

[ 4926.964472] ------------[ cut here ]------------
[ 4926.964529] Unexpected Unexpected register access
[ 4926.964713] WARNING: arch/arm64/kvm/sys_regs.c:64 at bad_trap.isra.0+0x70/0x7c, CPU#5: kvm-vcpu-0/179
[ 4926.965014] Modules linked in:
[ 4926.965097] CPU: 5 UID: 0 PID: 179 Comm: kvm-vcpu-0 Not tainted 6.19.0-rc1-dirty #85 PREEMPT
[ 4926.965240] Hardware name: FVP Base RevC (DT)
[ 4926.965316] pstate: 63402005 (nZCv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
[ 4926.965442] pc : bad_trap.isra.0+0x70/0x7c
[ 4926.965564] lr : bad_trap.isra.0+0x70/0x7c
[ 4926.965687] sp : ffff800080be39f0
[ 4926.965760] x29: ffff800080be39f0 x28: ffff0008031e2dc0 x27: 0000000000000000
[ 4926.965943] x26: 0000000000000000 x25: 0000000000000000 x24: 000000000000ae80
[ 4926.966124] x23: ffff000800b78048 x22: ffff00080164c9c0 x21: ffff0008031e2dc0
[ 4926.966314] x20: ffff000800b78000 x19: ffff000800b78000 x18: ffffffffff00b468
[ 4926.966506] x17: 0000000000000000 x16: 0000000000000000 x15: ffffa991688ee120
[ 4926.966689] x14: fffffffffe00b467 x13: 0000000000001408 x12: 0000000000001470
[ 4926.966874] x11: 0000000000000058 x10: 0000000000000018 x9 : ffff000875334bc0
[ 4926.967058] x8 : 0000000002bfffa8 x7 : 0000000000000081 x6 : ffff000877f34bc0
[ 4926.967241] x5 : 0000000000000081 x4 : ffffa991674022a8 x3 : 0000000000000001
[ 4926.967423] x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff0008031e2dc0
[ 4926.967605] Call trace:
[ 4926.967664]  bad_trap.isra.0+0x70/0x7c (P)
[ 4926.967805]  perform_access+0xcc/0xd8
[ 4926.967943]  kvm_handle_sys_reg+0x100/0x170
[ 4926.968068]  handle_exit+0x58/0x168
[ 4926.968187]  kvm_arch_vcpu_ioctl_run+0x2f8/0x900
[ 4926.968336]  kvm_vcpu_ioctl+0x168/0xa18
[ 4926.968479]  __arm64_sys_ioctl+0x2ec/0xaf4
[ 4926.968599]  invoke_syscall.constprop.0+0x48/0xc8
[ 4926.968758]  do_el0_svc+0x3c/0xb8
[ 4926.968903]  el0_svc+0x3c/0x160
[ 4926.969014]  el0t_64_sync_handler+0xa0/0xe4
[ 4926.969137]  el0t_64_sync+0x198/0x19c
[ 4926.969255] ---[ end trace 0000000000000000 ]---
[ 4926.969427] kvm [166]:  { Op0( 3), Op1( 0), CRn(10), CRm( 2), Op2( 2), func_write },

Thanks,
Alex


From michal.simek at amd.com  Mon Dec 15 07:21:36 2025
From: michal.simek at amd.com (Michal Simek)
Date: Mon, 15 Dec 2025 16:21:36 +0100
Subject: [PATCH] Revert "arm64: zynqmp: Add an OP-TEE node to the device
 tree"
In-Reply-To: <3654c600-553f-429a-8bec-1add7f6eb5c6@vaisala.com>
References: <20251125-revert-zynqmp-optee-v1-1-d2ce4c0fcaf6@vaisala.com>
 <88b72343-e86f-4b13-adcc-ba09683eb898@amd.com>
 <199062ba-9a0d-40ae-ac8c-0fbed5615cf8@vaisala.com>
 <3654c600-553f-429a-8bec-1add7f6eb5c6@vaisala.com>
Message-ID: <db79cd4a-548d-46f1-b498-aac82ca53010@amd.com>

Hi,

On 12/12/25 13:09, Tomas Melin wrote:
> Hi,
> 
> Is there some more specific information I can provide regarding this patch?

I am trying to identify U-Boot code (2026.01-rc4) which does what you have 
described in the commit message but I can't find it out.
Can you please point me directly to file, line number where that described logic 
is skipped?

Thanks,
Michal


From kevin.brodsky at arm.com  Mon Dec 15 07:24:31 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Mon, 15 Dec 2025 16:24:31 +0100
Subject: [PATCH v9 03/16] arm64/ptrace: Return early for
 ptrace_report_syscall_entry() error
In-Reply-To: <051fe45b-f158-85be-3f8e-60c830fb47a2@huawei.com>
References: <20251204082123.2792067-1-ruanjinjie@huawei.com>
 <20251204082123.2792067-4-ruanjinjie@huawei.com>
 <52f63e40-541f-4ed8-9d05-626eab4b39cb@arm.com>
 <051fe45b-f158-85be-3f8e-60c830fb47a2@huawei.com>
Message-ID: <9f6fc1db-5579-4aef-8deb-808ae83f3266@arm.com>

On 12/12/2025 05:00, Jinjie Ruan wrote:
> On 2025/12/9 21:46, Kevin Brodsky wrote:
>> On 04/12/2025 09:21, Jinjie Ruan wrote:
>>> The generic entry abort the syscall_trace_enter() sequence if
>>> ptrace_report_syscall_entry() errors out, but arm64 not.
>>>
>>> As the ptrace_report_syscall_entry() comment said, the calling arch code
>>> should abort the system call and must prevent normal entry so no system
>>> call is made if ptrace_report_syscall_entry() return nonzero.
>> This patch is now in the right position, which means that arm64 does
>> abort the syscall already without this patch. What we're changing here
>> is that the tracing sequence is interrupted. The comment you're
>> referring to says nothing about tracing so I'm not sure it helps to
>> refer to it.
> I think ?must prevent normal entry ?means When ptrace requests
> interception, all subsequent processing, including audit and seccomp,
> should completely bypassed.

Fair enough, let's just make sure the commit message doesn't imply that
arm64 performs a syscall before this patch.

- Kevin


From maz at kernel.org  Mon Dec 15 07:39:56 2025
From: maz at kernel.org (Marc Zyngier)
Date: Mon, 15 Dec 2025 15:39:56 +0000
Subject: [PATCH v2 2/4] KVM: arm64: Print register encoding if there's no accessor
In-Reply-To: <aUAmh32jCUOWMg8K@raptor>
References: <20251215114409.212512-1-alexandru.elisei@arm.com>
	<20251215114409.212512-3-alexandru.elisei@arm.com>
	<86ike7onhr.wl-maz@kernel.org>
	<aUAmh32jCUOWMg8K@raptor>
Message-ID: <86h5troisz.wl-maz@kernel.org>

On Mon, 15 Dec 2025 15:17:27 +0000,
Alexandru Elisei <alexandru.elisei at arm.com> wrote:
> 
> Hi Marc,
> 
> On Mon, Dec 15, 2025 at 01:58:40PM +0000, Marc Zyngier wrote:
> > On Mon, 15 Dec 2025 11:44:07 +0000,
> > Alexandru Elisei <alexandru.elisei at arm.com> wrote:
> > > 
> > > Configuring a register trap without specifying an accessor function is
> > > abviously a bug. Instead of calling die() when that happens, let's be a bit
> > > more helpful and print the register encoding and kill the virtual machine
> > > instead.
> > > 
> > > Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
> > > ---
> > >  arch/arm64/kvm/sys_regs.c | 8 +++++++-
> > >  1 file changed, 7 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> > > index c8fd7c6a12a1..d669f6fef177 100644
> > > --- a/arch/arm64/kvm/sys_regs.c
> > > +++ b/arch/arm64/kvm/sys_regs.c
> > > @@ -4668,7 +4668,13 @@ static void perform_access(struct kvm_vcpu *vcpu,
> > >  	 * that we don't know how to handle. This certainly qualifies
> > >  	 * as a gross bug that should be fixed right away.
> > >  	 */
> > > -	BUG_ON(!r->access);
> > > +	if (!r->access) {
> > > +		KVM_BUG(1, vcpu->kvm,
> > > +			"Unexpected access to register: { Op0(%2u), Op1(%2u), CRn(%2u), CRm(%2u), Op2(%2u) } (%s)",
> > > +			params->Op0, params->Op1, params->CRn, params->CRm, params->Op2,
> > > +			str_write_read(params->is_write));
> > > +		return;
> > > +	}
> > 
> > Why not writing
> > 
> > 	if (KVM_BUG(!r>access, ...))
> > 		return;
> > 
> > instead? And you could reuse the format that's already defined in
> > print_sys_reg_msg().
> > 
> > You could instead consider injecting an UNDEF in the guest, which I
> 
> Injecting an undefined instruction exception early in the boot process can lead
> to an infinite loop of undefined instruction exceptions in the guest. This is
> what happens for the unhandled PIRE0_EL1 trap that the previous patch fixes. The
> guest access takes place in __cpu_setup(), when there are no vectors
> installed.

*Linux* crashes in this way. Who cares about Linux?

It's a matter of consistency. When KVM unexpectedly traps something,
we inject an UNDEF *today*. Why should the lack of an access callback
be treated any differently? What material difference does it make to
the guest?

Someone who wants to understand what is happening in their guest can
attach a debugger to it and find out.

>
> If you're ok with this, I can move forward with the below:
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index c8fd7c6a12a1..516072417649 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -4668,7 +4668,10 @@ static void perform_access(struct kvm_vcpu *vcpu,
>          * that we don't know how to handle. This certainly qualifies
>          * as a gross bug that should be fixed right away.
>          */
> -       BUG_ON(!r->access);
> +       if (!r->access) {
> +               bad_trap(vcpu, params, r, "Unexpected register access");
> +               return;
> +       }
> 
>         /* Skip instruction if instructed so */
>         if (likely(r->access(vcpu, params, r)))
> 
> And this is what KVM prints (the register encoding is outside the trace snippet,
> if you think that would make a difference to the end user):
> 
> [ 4926.964472] ------------[ cut here ]------------
> [ 4926.964529] Unexpected Unexpected register access
                 ^^^^^^^^^^^^^^^^^^^^^

You can clean-up the message...

> [ 4926.964713] WARNING: arch/arm64/kvm/sys_regs.c:64 at bad_trap.isra.0+0x70/0x7c, CPU#5: kvm-vcpu-0/179
> [ 4926.965014] Modules linked in:
> [ 4926.965097] CPU: 5 UID: 0 PID: 179 Comm: kvm-vcpu-0 Not tainted 6.19.0-rc1-dirty #85 PREEMPT
> [ 4926.965240] Hardware name: FVP Base RevC (DT)
> [ 4926.965316] pstate: 63402005 (nZCv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
> [ 4926.965442] pc : bad_trap.isra.0+0x70/0x7c
> [ 4926.965564] lr : bad_trap.isra.0+0x70/0x7c
> [ 4926.965687] sp : ffff800080be39f0
> [ 4926.965760] x29: ffff800080be39f0 x28: ffff0008031e2dc0 x27: 0000000000000000
> [ 4926.965943] x26: 0000000000000000 x25: 0000000000000000 x24: 000000000000ae80
> [ 4926.966124] x23: ffff000800b78048 x22: ffff00080164c9c0 x21: ffff0008031e2dc0
> [ 4926.966314] x20: ffff000800b78000 x19: ffff000800b78000 x18: ffffffffff00b468
> [ 4926.966506] x17: 0000000000000000 x16: 0000000000000000 x15: ffffa991688ee120
> [ 4926.966689] x14: fffffffffe00b467 x13: 0000000000001408 x12: 0000000000001470
> [ 4926.966874] x11: 0000000000000058 x10: 0000000000000018 x9 : ffff000875334bc0
> [ 4926.967058] x8 : 0000000002bfffa8 x7 : 0000000000000081 x6 : ffff000877f34bc0
> [ 4926.967241] x5 : 0000000000000081 x4 : ffffa991674022a8 x3 : 0000000000000001
> [ 4926.967423] x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff0008031e2dc0
> [ 4926.967605] Call trace:
> [ 4926.967664]  bad_trap.isra.0+0x70/0x7c (P)
> [ 4926.967805]  perform_access+0xcc/0xd8
> [ 4926.967943]  kvm_handle_sys_reg+0x100/0x170
> [ 4926.968068]  handle_exit+0x58/0x168
> [ 4926.968187]  kvm_arch_vcpu_ioctl_run+0x2f8/0x900
> [ 4926.968336]  kvm_vcpu_ioctl+0x168/0xa18
> [ 4926.968479]  __arm64_sys_ioctl+0x2ec/0xaf4
> [ 4926.968599]  invoke_syscall.constprop.0+0x48/0xc8
> [ 4926.968758]  do_el0_svc+0x3c/0xb8
> [ 4926.968903]  el0_svc+0x3c/0x160
> [ 4926.969014]  el0t_64_sync_handler+0xa0/0xe4
> [ 4926.969137]  el0t_64_sync+0x198/0x19c
> [ 4926.969255] ---[ end trace 0000000000000000 ]---
> [ 4926.969427] kvm [166]:  { Op0( 3), Op1( 0), CRn(10), CRm( 2), Op2( 2), func_write },

Works for me. The only small snag is that you only ever get one of
these, irrespective of the register. Not a big deal.

Thanks,

	M.

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


From ulf.hansson at linaro.org  Mon Dec 15 07:43:42 2025
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Mon, 15 Dec 2025 16:43:42 +0100
Subject: [PATCH 0/3] Add SD/MMC Card driver support for Mediatek MT8189 SoC
In-Reply-To: <20251203-mt8189-add-mmc-support-v1-0-f5ce43212fe9@collabora.com>
References: <20251203-mt8189-add-mmc-support-v1-0-f5ce43212fe9@collabora.com>
Message-ID: <CAPDyKFoXoO-rpEK4Y-FZyWhpOumiwir96-XfLOOR2U1h73ADhg@mail.gmail.com>

On Wed, 3 Dec 2025 at 12:45, Louis-Alexis Eyraud
<louisalexis.eyraud at collabora.com> wrote:
>
> This patch series adds in the Mediatek SD/MMC Card host driver (mtk-sd)
> the support of Mediatek MT8189 SoC and its variants (MT8371 and
> MT8391).
>
> It has been tested with a kernel based on next-20251203 tag on the
> Mediatek Genio 720-EVK board, based on MT8391 SoC, using both onboard
> eMMC storage and a micro-SD card.
>
> Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
> ---
> Louis-Alexis Eyraud (3):
>       dt-bindings: mmc: mtk-sd: Add support for MT8189 SoC
>       mmc: mtk-sd: add support for SPM resource release control
>       mmc: mtk-sd: add support for MT8189 SoC
>
>  Documentation/devicetree/bindings/mmc/mtk-sd.yaml |  3 +++
>  drivers/mmc/host/mtk-sd.c                         | 32 ++++++++++++++++++++---
>  2 files changed, 32 insertions(+), 3 deletions(-)
> ---
> base-commit: e47d97576181b31291cf58e77d737d21def0e160
> change-id: 20251128-mt8189-add-mmc-support-ff6df8f89e41
>
> Best regards,
> --
> Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
>

The series applied for next, thanks!

Kind regards
Uffe


From ulf.hansson at linaro.org  Mon Dec 15 07:43:51 2025
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Mon, 15 Dec 2025 16:43:51 +0100
Subject: [PATCH v3] mmc: sdhci-esdhc-imx: wait for data transfer
 completion before reset
In-Reply-To: <20251211075603.533033-1-ziniu.wang_1@nxp.com>
References: <20251211075603.533033-1-ziniu.wang_1@nxp.com>
Message-ID: <CAPDyKFo4o=V9H-U+HBGTtog58=0QkDzepBR2HFqU7Giede8xAg@mail.gmail.com>

On Thu, 11 Dec 2025 at 08:54, <ziniu.wang_1 at nxp.com> wrote:
>
> From: Luke Wang <ziniu.wang_1 at nxp.com>
>
> On IMX7ULP platforms, certain SD cards (e.g. Kingston Canvas Go! Plus)
> cause system hangs and reboots during manual tuning. These cards exhibit
> large gaps (~16us) between tuning command response and data transmission.
> When cmd CRC errors occur during tuning, the code assumes data errors even
> tuning data hasn't been fully received and then reset host data circuit.
>
> Per IMX7ULP reference manual, reset operations (RESET_DATA/ALL) need to
> make sure no active data transfers. Previously, resetting while data was
> in-flight would clear data circuit, including ADMA/SDMA address, causing
> data to be transmitted to incorrect memory address. This patch adds
> polling for data transfer completion before executing resets.
>
> Signed-off-by: Luke Wang <ziniu.wang_1 at nxp.com>
> Reviewed-by: Bough Chen <haibo.chen at nxp.com>

Applied for next, thanks!

Kind regards
Uffe


> ---
> v3: add define for timeout value
> v2: amend commit message
> ---
>  drivers/mmc/host/sdhci-esdhc-imx.c | 18 ++++++++++++++++++
>  1 file changed, 18 insertions(+)
>
> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
> index a7a5df673b0f..97461e20425d 100644
> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> @@ -216,6 +216,8 @@
>  #define ESDHC_FLAG_DUMMY_PAD           BIT(19)
>
>  #define ESDHC_AUTO_TUNING_WINDOW       3
> +/* 100ms timeout for data inhibit */
> +#define ESDHC_DATA_INHIBIT_WAIT_US     100000
>
>  enum wp_types {
>         ESDHC_WP_NONE,          /* no WP, neither controller nor gpio */
> @@ -1453,6 +1455,22 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
>
>  static void esdhc_reset(struct sdhci_host *host, u8 mask)
>  {
> +       u32 present_state;
> +       int ret;
> +
> +       /*
> +        * For data or full reset, ensure any active data transfer completes
> +        * before resetting to avoid system hang.
> +        */
> +       if (mask & (SDHCI_RESET_DATA | SDHCI_RESET_ALL)) {
> +               ret = readl_poll_timeout_atomic(host->ioaddr + ESDHC_PRSSTAT, present_state,
> +                                               !(present_state & SDHCI_DATA_INHIBIT), 2,
> +                                               ESDHC_DATA_INHIBIT_WAIT_US);
> +               if (ret == -ETIMEDOUT)
> +                       dev_warn(mmc_dev(host->mmc),
> +                                "timeout waiting for data transfer completion\n");
> +       }
> +
>         sdhci_and_cqhci_reset(host, mask);
>
>         sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
> --
> 2.34.1
>


From tomas.melin at vaisala.com  Mon Dec 15 07:43:52 2025
From: tomas.melin at vaisala.com (Tomas Melin)
Date: Mon, 15 Dec 2025 17:43:52 +0200
Subject: [PATCH] Revert "arm64: zynqmp: Add an OP-TEE node to the device
 tree"
In-Reply-To: <db79cd4a-548d-46f1-b498-aac82ca53010@amd.com>
References: <20251125-revert-zynqmp-optee-v1-1-d2ce4c0fcaf6@vaisala.com>
 <88b72343-e86f-4b13-adcc-ba09683eb898@amd.com>
 <199062ba-9a0d-40ae-ac8c-0fbed5615cf8@vaisala.com>
 <3654c600-553f-429a-8bec-1add7f6eb5c6@vaisala.com>
 <db79cd4a-548d-46f1-b498-aac82ca53010@amd.com>
Message-ID: <0435af95-a3bc-4ec7-b07b-bdec42f25c56@vaisala.com>

Hi,

On 15/12/2025 17:21, Michal Simek wrote:
> Hi,
> 
> On 12/12/25 13:09, Tomas Melin wrote:
>> Hi,
>>
>> Is there some more specific information I can provide regarding this patch?
> 
> I am trying to identify U-Boot code (2026.01-rc4) which does what you have 
> described in the commit message but I can't find it out.
> Can you please point me directly to file, line number where that described logic 
> is skipped?

Please check lib/optee/optee.c, in particular lines 128 ->
Target dt being linux kernel devicetree where the reserved-memory nodes
are automatically injected. When node is already there, it bails out early.

thanks,
Tomas


> 
> Thanks,
> Michal



From tabba at google.com  Mon Dec 15 07:45:28 2025
From: tabba at google.com (Fuad Tabba)
Date: Mon, 15 Dec 2025 15:45:28 +0000
Subject: [PATCH v1 0/5] KVM: selftests: Alignment fixes and arm64 MMU cleanup
Message-ID: <20251215154533.3154405-1-tabba@google.com>

This series tidies up a few things in the KVM selftests. It addresses an
error in memory alignment, hardens the arm64 MMU configuration for
selftests, and fixes minor documentation issues.

First, for arm64, the series explicitly disables translation table walks
for the unused upper virtual address range (TTBR1). Since selftests run
entirely in the lower range (TTBR0), leaving TTBR1 uninitialized but
active could lead to unpredictable behavior if guest code accesses high
addresses. We set EPD1 (and TBI1) to ensure such accesses
deterministically generate translation faults.

Second, the series fixes the `page_align()` implementation in both arm64
and riscv. The previous version incorrectly rounded up already-aligned
addresses to the *next* page, potentially wasting memory or causing
unexpected gaps. After fixing the logic in the arch-specific files, the
function is moved to the common `kvm_util.h` header to eliminate code
duplication.

Finally, a few comments and argument descriptions in `kvm_util` are
updated to match the actual code implementation.

Based on Linux 6.19-rc1.

Cheers,
/fuad

Fuad Tabba (5):
  KVM: arm64: selftests: Disable unused TTBR1_EL1 translations
  KVM: arm64: selftests: Fix incorrect rounding in page_align()
  KVM: riscv: selftests: Fix incorrect rounding in page_align()
  KVM: selftests: Move page_align() to shared header
  KVM: selftests: Fix typos and stale comments in kvm_util

 tools/testing/selftests/kvm/include/arm64/processor.h | 4 ++++
 tools/testing/selftests/kvm/include/kvm_util.h        | 9 +++++++--
 tools/testing/selftests/kvm/lib/arm64/processor.c     | 7 ++-----
 tools/testing/selftests/kvm/lib/kvm_util.c            | 2 +-
 tools/testing/selftests/kvm/lib/riscv/processor.c     | 5 -----
 5 files changed, 14 insertions(+), 13 deletions(-)


base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
-- 
2.52.0.239.gd5f0c6e74e-goog



From tabba at google.com  Mon Dec 15 07:45:29 2025
From: tabba at google.com (Fuad Tabba)
Date: Mon, 15 Dec 2025 15:45:29 +0000
Subject: [PATCH v1 1/5] KVM: arm64: selftests: Disable unused TTBR1_EL1 translations
In-Reply-To: <20251215154533.3154405-1-tabba@google.com>
References: <20251215154533.3154405-1-tabba@google.com>
Message-ID: <20251215154533.3154405-2-tabba@google.com>

KVM selftests map all guest code and data into the lower virtual address
range (0x0000...) managed by TTBR0_EL1. The upper range (0xFFFF...)
managed by TTBR1_EL1 is unused and uninitialized.

If a guest accesses the upper range, the MMU attempts a translation
table walk using uninitialized registers, leading to unpredictable
behavior.

Set `TCR_EL1.EPD1` to disable translation table walks for TTBR1_EL1,
ensuring that any access to the upper range generates an immediate
Translation Fault. Additionally, set `TCR_EL1.TBI1` (Top Byte Ignore) to
ensure that tagged pointers in the upper range also deterministically
trigger a Translation Fault via EPD1.

Define `TCR_EPD1_MASK`, `TCR_EPD1_SHIFT`, and `TCR_TBI1` in
`processor.h` to support this configuration. These are based on their
definitions in `arch/arm64/include/asm/pgtable-hwdef.h`.

Suggested-by: Will Deacon <will at kernel.org>
Signed-off-by: Fuad Tabba <tabba at google.com>
---
 tools/testing/selftests/kvm/include/arm64/processor.h | 4 ++++
 tools/testing/selftests/kvm/lib/arm64/processor.c     | 2 ++
 2 files changed, 6 insertions(+)

diff --git a/tools/testing/selftests/kvm/include/arm64/processor.h b/tools/testing/selftests/kvm/include/arm64/processor.h
index ff928716574d..ac97a1c436fc 100644
--- a/tools/testing/selftests/kvm/include/arm64/processor.h
+++ b/tools/testing/selftests/kvm/include/arm64/processor.h
@@ -90,6 +90,9 @@
 #define TCR_TG0_64K		(UL(1) << TCR_TG0_SHIFT)
 #define TCR_TG0_16K		(UL(2) << TCR_TG0_SHIFT)
 
+#define TCR_EPD1_SHIFT		23
+#define TCR_EPD1_MASK		(UL(1) << TCR_EPD1_SHIFT)
+
 #define TCR_IPS_SHIFT		32
 #define TCR_IPS_MASK		(UL(7) << TCR_IPS_SHIFT)
 #define TCR_IPS_52_BITS	(UL(6) << TCR_IPS_SHIFT)
@@ -97,6 +100,7 @@
 #define TCR_IPS_40_BITS	(UL(2) << TCR_IPS_SHIFT)
 #define TCR_IPS_36_BITS	(UL(1) << TCR_IPS_SHIFT)
 
+#define TCR_TBI1		(UL(1) << 38)
 #define TCR_HA			(UL(1) << 39)
 #define TCR_DS			(UL(1) << 59)
 
diff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/testing/selftests/kvm/lib/arm64/processor.c
index d46e4b13b92c..5b379da8cb90 100644
--- a/tools/testing/selftests/kvm/lib/arm64/processor.c
+++ b/tools/testing/selftests/kvm/lib/arm64/processor.c
@@ -384,6 +384,8 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
 
 	tcr_el1 |= TCR_IRGN0_WBWA | TCR_ORGN0_WBWA | TCR_SH0_INNER;
 	tcr_el1 |= TCR_T0SZ(vm->va_bits);
+	tcr_el1 |= TCR_TBI1;
+	tcr_el1 |= TCR_EPD1_MASK;
 	if (use_lpa2_pte_format(vm))
 		tcr_el1 |= TCR_DS;
 
-- 
2.52.0.239.gd5f0c6e74e-goog



From tabba at google.com  Mon Dec 15 07:45:30 2025
From: tabba at google.com (Fuad Tabba)
Date: Mon, 15 Dec 2025 15:45:30 +0000
Subject: [PATCH v1 2/5] KVM: arm64: selftests: Fix incorrect rounding in page_align()
In-Reply-To: <20251215154533.3154405-1-tabba@google.com>
References: <20251215154533.3154405-1-tabba@google.com>
Message-ID: <20251215154533.3154405-3-tabba@google.com>

The implementation of `page_align()` in `processor.c` calculates
alignment incorrectly for values that are already aligned. Specifically,
`(v + vm->page_size) & ~(vm->page_size - 1)` aligns to the *next* page
boundary even if `v` is already page-aligned, potentially wasting a page
of memory.

Fix the calculation to use standard alignment logic: `(v + vm->page_size
- 1) & ~(vm->page_size - 1)`.

Fixes: 7a6629ef746d ("kvm: selftests: add virt mem support for aarch64")
Signed-off-by: Fuad Tabba <tabba at google.com>
---
 tools/testing/selftests/kvm/lib/arm64/processor.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/testing/selftests/kvm/lib/arm64/processor.c
index 5b379da8cb90..607a4e462984 100644
--- a/tools/testing/selftests/kvm/lib/arm64/processor.c
+++ b/tools/testing/selftests/kvm/lib/arm64/processor.c
@@ -23,7 +23,7 @@ static vm_vaddr_t exception_handlers;
 
 static uint64_t page_align(struct kvm_vm *vm, uint64_t v)
 {
-	return (v + vm->page_size) & ~(vm->page_size - 1);
+	return (v + vm->page_size - 1) & ~(vm->page_size - 1);
 }
 
 static uint64_t pgd_index(struct kvm_vm *vm, vm_vaddr_t gva)
-- 
2.52.0.239.gd5f0c6e74e-goog



From tabba at google.com  Mon Dec 15 07:45:31 2025
From: tabba at google.com (Fuad Tabba)
Date: Mon, 15 Dec 2025 15:45:31 +0000
Subject: [PATCH v1 3/5] KVM: riscv: selftests: Fix incorrect rounding in page_align()
In-Reply-To: <20251215154533.3154405-1-tabba@google.com>
References: <20251215154533.3154405-1-tabba@google.com>
Message-ID: <20251215154533.3154405-4-tabba@google.com>

The implementation of `page_align()` in `processor.c` calculates
alignment incorrectly for values that are already aligned. Specifically,
`(v + vm->page_size) & ~(vm->page_size - 1)` aligns to the *next* page
boundary even if `v` is already page-aligned, potentially wasting a page
of memory.

Fix the calculation to use standard alignment logic: `(v + vm->page_size
- 1) & ~(vm->page_size - 1)`.

Fixes: 3e06cdf10520 ("KVM: selftests: Add initial support for RISC-V 64-bit")
Signed-off-by: Fuad Tabba <tabba at google.com>
---
 tools/testing/selftests/kvm/lib/riscv/processor.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c
index 2eac7d4b59e9..d5e8747b5e69 100644
--- a/tools/testing/selftests/kvm/lib/riscv/processor.c
+++ b/tools/testing/selftests/kvm/lib/riscv/processor.c
@@ -28,7 +28,7 @@ bool __vcpu_has_ext(struct kvm_vcpu *vcpu, uint64_t ext)
 
 static uint64_t page_align(struct kvm_vm *vm, uint64_t v)
 {
-	return (v + vm->page_size) & ~(vm->page_size - 1);
+	return (v + vm->page_size - 1) & ~(vm->page_size - 1);
 }
 
 static uint64_t pte_addr(struct kvm_vm *vm, uint64_t entry)
-- 
2.52.0.239.gd5f0c6e74e-goog



From tabba at google.com  Mon Dec 15 07:45:32 2025
From: tabba at google.com (Fuad Tabba)
Date: Mon, 15 Dec 2025 15:45:32 +0000
Subject: [PATCH v1 4/5] KVM: selftests: Move page_align() to shared header
In-Reply-To: <20251215154533.3154405-1-tabba@google.com>
References: <20251215154533.3154405-1-tabba@google.com>
Message-ID: <20251215154533.3154405-5-tabba@google.com>

To avoid code duplication, move page_align() to the shared `kvm_util.h`
header file.

No functional change intended.

Signed-off-by: Fuad Tabba <tabba at google.com>
---
 tools/testing/selftests/kvm/include/kvm_util.h    | 5 +++++
 tools/testing/selftests/kvm/lib/arm64/processor.c | 5 -----
 tools/testing/selftests/kvm/lib/riscv/processor.c | 5 -----
 3 files changed, 5 insertions(+), 10 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index 81f4355ff28a..dabbe4c3b93f 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -1258,6 +1258,11 @@ static inline int __vm_disable_nx_huge_pages(struct kvm_vm *vm)
 	return __vm_enable_cap(vm, KVM_CAP_VM_DISABLE_NX_HUGE_PAGES, 0);
 }
 
+static inline uint64_t page_align(struct kvm_vm *vm, uint64_t v)
+{
+	return (v + vm->page_size - 1) & ~(vm->page_size - 1);
+}
+
 /*
  * Arch hook that is invoked via a constructor, i.e. before exeucting main(),
  * to allow for arch-specific setup that is common to all tests, e.g. computing
diff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/testing/selftests/kvm/lib/arm64/processor.c
index 607a4e462984..143632917766 100644
--- a/tools/testing/selftests/kvm/lib/arm64/processor.c
+++ b/tools/testing/selftests/kvm/lib/arm64/processor.c
@@ -21,11 +21,6 @@
 
 static vm_vaddr_t exception_handlers;
 
-static uint64_t page_align(struct kvm_vm *vm, uint64_t v)
-{
-	return (v + vm->page_size - 1) & ~(vm->page_size - 1);
-}
-
 static uint64_t pgd_index(struct kvm_vm *vm, vm_vaddr_t gva)
 {
 	unsigned int shift = (vm->pgtable_levels - 1) * (vm->page_shift - 3) + vm->page_shift;
diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c
index d5e8747b5e69..f8ff4bf938d9 100644
--- a/tools/testing/selftests/kvm/lib/riscv/processor.c
+++ b/tools/testing/selftests/kvm/lib/riscv/processor.c
@@ -26,11 +26,6 @@ bool __vcpu_has_ext(struct kvm_vcpu *vcpu, uint64_t ext)
 	return !ret && !!value;
 }
 
-static uint64_t page_align(struct kvm_vm *vm, uint64_t v)
-{
-	return (v + vm->page_size - 1) & ~(vm->page_size - 1);
-}
-
 static uint64_t pte_addr(struct kvm_vm *vm, uint64_t entry)
 {
 	return ((entry & PGTBL_PTE_ADDR_MASK) >> PGTBL_PTE_ADDR_SHIFT) <<
-- 
2.52.0.239.gd5f0c6e74e-goog



From tabba at google.com  Mon Dec 15 07:45:33 2025
From: tabba at google.com (Fuad Tabba)
Date: Mon, 15 Dec 2025 15:45:33 +0000
Subject: [PATCH v1 5/5] KVM: selftests: Fix typos and stale comments in kvm_util
In-Reply-To: <20251215154533.3154405-1-tabba@google.com>
References: <20251215154533.3154405-1-tabba@google.com>
Message-ID: <20251215154533.3154405-6-tabba@google.com>

Fix minor documentation errors in `kvm_util.h` and `kvm_util.c`.

- Correct the argument description for `vcpu_args_set` in `kvm_util.h`,
  which incorrectly listed `vm` instead of `vcpu`.
- Fix a typo in the comment for `kvm_selftest_arch_init` ("exeucting" ->
  "executing").
- Correct the return value description for `vm_vaddr_unused_gap` in
  `kvm_util.c` to match the implementation, which returns an address "at
  or above" `vaddr_min`, not "at or below".

No functional change intended.

Signed-off-by: Fuad Tabba <tabba at google.com>
---
 tools/testing/selftests/kvm/include/kvm_util.h | 4 ++--
 tools/testing/selftests/kvm/lib/kvm_util.c     | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index dabbe4c3b93f..e29b2cbcb82b 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -939,7 +939,7 @@ void *vcpu_map_dirty_ring(struct kvm_vcpu *vcpu);
  * VM VCPU Args Set
  *
  * Input Args:
- *   vm - Virtual Machine
+ *   vcpu - vCPU
  *   num - number of arguments
  *   ... - arguments, each of type uint64_t
  *
@@ -1264,7 +1264,7 @@ static inline uint64_t page_align(struct kvm_vm *vm, uint64_t v)
 }
 
 /*
- * Arch hook that is invoked via a constructor, i.e. before exeucting main(),
+ * Arch hook that is invoked via a constructor, i.e. before executing main(),
  * to allow for arch-specific setup that is common to all tests, e.g. computing
  * the default guest "mode".
  */
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 8279b6ced8d2..fab6b62d7810 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -1351,7 +1351,7 @@ struct kvm_vcpu *__vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
  * Output Args: None
  *
  * Return:
- *   Lowest virtual address at or below vaddr_min, with at least
+ *   Lowest virtual address at or above vaddr_min, with at least
  *   sz unused bytes.  TEST_ASSERT failure if no area of at least
  *   size sz is available.
  *
-- 
2.52.0.239.gd5f0c6e74e-goog



From pmladek at suse.com  Mon Dec 15 07:45:57 2025
From: pmladek at suse.com (Petr Mladek)
Date: Mon, 15 Dec 2025 16:45:57 +0100
Subject: [PATCH v2] printk/nbcon: Restore IRQ in atomic flush after each
 emitted record
In-Reply-To: <20251212124520.244483-1-pmladek@suse.com>
References: <20251212124520.244483-1-pmladek@suse.com>
Message-ID: <aUAtNbAIsR9_8IUo@pathway>

On Fri 2025-12-12 13:45:20, Petr Mladek wrote:
> The commit d5d399efff6577 ("printk/nbcon: Release nbcon consoles ownership
> in atomic flush after each emitted record") prevented stall of a CPU
> which lost nbcon console ownership because another CPU entered
> an emergency flush.
> 
> But there is still the problem that the CPU doing the emergency flush
> might cause a stall on its own.
> 
> Let's go even further and restore IRQ in the atomic flush after
> each emitted record.
> 
> It is not a complete solution. The interrupts and/or scheduling might
> still be blocked when the emergency atomic flush was called with
> IRQs and/or scheduling disabled. But it should remove the following
> lockup:
> 
>   mlx5_core 0000:03:00.0: Shutdown was called
>   kvm: exiting hardware virtualization
>   arm-smmu-v3 arm-smmu-v3.10.auto: CMD_SYNC timeout at 0x00000103 [hwprod 0x00000104, hwcons 0x00000102]
>   smp: csd: Detected non-responsive CSD lock (#1) on CPU#4, waiting 5000000032 ns for CPU#00 do_nothing (kernel/smp.c:1057)
>   smp:     csd: CSD lock (#1) unresponsive.
>   [...]
>   Call trace:
>   pl011_console_write_atomic (./arch/arm64/include/asm/vdso/processor.h:12 drivers/tty/serial/amba-pl011.c:2540) (P)
>   nbcon_emit_next_record (kernel/printk/nbcon.c:1049)
>   __nbcon_atomic_flush_pending_con (kernel/printk/nbcon.c:1517)
>   __nbcon_atomic_flush_pending.llvm.15488114865160659019 (./arch/arm64/include/asm/alternative-macros.h:254 ./arch/arm64/include/asm/cpufeature.h:808 ./arch/arm64/include/asm/irqflags.h:192 kernel/printk/nbcon.c:1562 kernel/printk/nbcon.c:1612)
>   nbcon_atomic_flush_pending (kernel/printk/nbcon.c:1629)
>   printk_kthreads_shutdown (kernel/printk/printk.c:?)
>   syscore_shutdown (drivers/base/syscore.c:120)
>   kernel_kexec (kernel/kexec_core.c:1045)
>   __arm64_sys_reboot (kernel/reboot.c:794 kernel/reboot.c:722 kernel/reboot.c:722)
>   invoke_syscall (arch/arm64/kernel/syscall.c:50)
>   el0_svc_common.llvm.14158405452757855239 (arch/arm64/kernel/syscall.c:?)
>   do_el0_svc (arch/arm64/kernel/syscall.c:152)
>   el0_svc (./arch/arm64/include/asm/alternative-macros.h:254 ./arch/arm64/include/asm/cpufeature.h:808 ./arch/arm64/include/asm/irqflags.h:73 arch/arm64/kernel/entry-common.c:169 arch/arm64/kernel/entry-common.c:182 arch/arm64/kernel/entry-common.c:749)
>   el0t_64_sync_handler (arch/arm64/kernel/entry-common.c:820)
>   el0t_64_sync (arch/arm64/kernel/entry.S:600)
> 
> In this case, nbcon_atomic_flush_pending() is called from
> printk_kthreads_shutdown() with IRQs and scheduling enabled.
> 
> Note that __nbcon_atomic_flush_pending_con() is directly called also from
> nbcon_device_release() where the disabled IRQs might break PREEMPT_RT
> guarantees. But the atomic flush is called only in emergency or panic
> situations where the latencies are irrelevant anyway.
> 
> An ultimate solution would be a touching of watchdogs. But it would hide
> all problems. Let's do it later when anyone reports a stall which does
> not have a better solution.
> 
> Closes: https://lore.kernel.org/r/sqwajvt7utnt463tzxgwu2yctyn5m6bjwrslsnupfexeml6hkd at v6sqmpbu3vvu
> Tested-by: Breno Leitao <leitao at debian.org>
> Signed-off-by: Petr Mladek <pmladek at suse.com>

JFYI, the patch has been committed into printk/linux.git,
branch rework/atomic-flush-softlockup.

It is fixing a real-life problem. I am going to give it few days
in linux-next and crete pull request by the end of this week
or at Jan 2, 2026 (before or after my Christmass vacation).

Best Regards,
Petr


From lee at kernel.org  Mon Dec 15 07:46:07 2025
From: lee at kernel.org (Lee Jones)
Date: Mon, 15 Dec 2025 15:46:07 +0000
Subject: [PATCH 2/2] drm: atmel-hlcdc: add LCD controller layer
 definition for sama7d65
In-Reply-To: <20251215090639.346288-2-manikandan.m@microchip.com>
References: <20251215090639.346288-1-manikandan.m@microchip.com>
 <20251215090639.346288-2-manikandan.m@microchip.com>
Message-ID: <20251215154607.GE9275@google.com>

On Mon, 15 Dec 2025, Manikandan Muralidharan wrote:

> From: Ryan Wanner <Ryan.Wanner at microchip.com>
> 
> Add the LCD controller layer definition and atmel_hlcdc_of_match
> entry for sama7d65.
> 
> Signed-off-by: Ryan Wanner <Ryan.Wanner at microchip.com>
> Signed-off-by: Manikandan Muralidharan <manikandan.m at microchip.com>
> ---
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | 81 ++++++++++++++++++++

>  drivers/mfd/atmel-hlcdc.c                    |  1 +

Please separate this into its own patch.

>  2 files changed, 82 insertions(+)

-- 
Lee Jones [???]


From maz at kernel.org  Mon Dec 15 07:50:02 2025
From: maz at kernel.org (Marc Zyngier)
Date: Mon, 15 Dec 2025 15:50:02 +0000
Subject: [PATCH 23/32] KVM: arm64: gic-v5: Bump arch timer for GICv5
In-Reply-To: <20251212152215.675767-24-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	<20251212152215.675767-24-sascha.bischoff@arm.com>
Message-ID: <86fr9boic5.wl-maz@kernel.org>

On Fri, 12 Dec 2025 15:22:43 +0000,
Sascha Bischoff <Sascha.Bischoff at arm.com> wrote:
> 
> Now that GICv5 has arrived, the arch timer requires some TLC to
> address some of the key differences introduced with GICv5.
> 
> For PPIs on GICv5, the set_pending_state and queue_irq_unlock irq_ops
> are used as AP lists are not required at all for GICv5. The arch timer
> also introduces an irq_op - get_input_level. Extend the
> arch-timer-provided irq_ops to include the two PPI ops for vgic_v5
> guests.
> 
> When possible, DVI (Direct Virtual Interrupt) is set for PPIs when
> using a vgic_v5, which directly inject the pending state in to the
> guest. This means that the host never sees the interrupt for the guest
> for these interrupts. This has two impacts.
> 
> * First of all, the kvm_cpu_has_pending_timer check is updated to
>   explicitly check if the timers are expected to fire.
> 
> * Secondly, for mapped timers (which use DVI) they must be masked on
>   the host prior to entering a GICv5 guest, and unmasked on the return
>   path. This is handled in set_timer_irq_phys_masked.
> 
> The final, but rather important, change is that the architected PPIs
> for the timers are made mandatory for a GICv5 guest. Attempts to set
> them to anything else are actively rejected. Once a vgic_v5 is
> initialised, the arch timer PPIs are also explicitly reinitialised to
> ensure the correct GICv5-compatible PPIs are used - this also adds in
> the GICv5 PPI type to the intid.
> 
> Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
> ---
>  arch/arm64/kvm/arch_timer.c     | 114 +++++++++++++++++++++++++++-----
>  arch/arm64/kvm/vgic/vgic-init.c |   9 +++
>  arch/arm64/kvm/vgic/vgic-v5.c   |   6 +-
>  include/kvm/arm_arch_timer.h    |   7 +-
>  include/kvm/arm_vgic.h          |   5 ++
>  5 files changed, 119 insertions(+), 22 deletions(-)
> 
> diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c
> index 6f033f6644219..b0a5a6c6bf8da 100644
> --- a/arch/arm64/kvm/arch_timer.c
> +++ b/arch/arm64/kvm/arch_timer.c
> @@ -56,6 +56,17 @@ static struct irq_ops arch_timer_irq_ops = {
>  	.get_input_level = kvm_arch_timer_get_input_level,
>  };
>  
> +static struct irq_ops arch_timer_irq_ops_vgic_v5 = {
> +	.get_input_level = kvm_arch_timer_get_input_level,
> +	.set_pending_state = vgic_v5_ppi_set_pending_state,
> +	.queue_irq_unlock = vgic_v5_ppi_queue_irq_unlock,
> +};
> +
> +static bool vgic_is_v5(struct kvm_vcpu *vcpu)
> +{
> +	return vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5;
> +}
> +

Drive-by comment: you also have

arch/arm64/kvm/vgic/vgic.h:static inline bool vgic_is_v5(struct kvm *kvm)
include/kvm/arm_vgic.h:#define gic_is_v5(k) ((k)->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5)

At least two of them have to die.

	M.

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


From Frank.li at nxp.com  Mon Dec 15 07:56:49 2025
From: Frank.li at nxp.com (Frank Li)
Date: Mon, 15 Dec 2025 10:56:49 -0500
Subject: [PATCH v2 0/4] s32g: Use a syscon for GPR
In-Reply-To: <cover.1765806521.git.dan.carpenter@linaro.org>
References: <cover.1765806521.git.dan.carpenter@linaro.org>
Message-ID: <aUAvwRmIZBC0W6ql@lizhi-Precision-Tower-5810>

On Mon, Dec 15, 2025 at 05:41:43PM +0300, Dan Carpenter wrote:
> The s32g devices have a GPR register region which holds a number of
> miscellaneous registers.  Currently only the stmmac/dwmac-s32.c uses
> anything from there and we just add a line to the device tree to
> access that GMAC_0_CTRL_STS register:
>
>                         reg = <0x4033c000 0x2000>, /* gmac IP */
>                               <0x4007c004 0x4>;    /* GMAC_0_CTRL_STS */
>
> We still have to maintain backwards compatibility to this format,
> of course, but it would be better to access these through a syscon.
> First of all, putting all the registers together is more organized
> and shows how the hardware actually is implemented.  Secondly, in
> some versions of this chipset those registers can only be accessed
> via SCMI, if the registers aren't grouped together each driver will
> have to create a whole lot of if then statements to access it via
> IOMEM or via SCMI,

Does SCMI work as regmap? syscon look likes simple, but missed abstract
in overall.

You still use regmap by use MMIO. /* GMAC_0_CTRL_STS */

regmap = devm_regmap_init_mmio(dev, sts_offset, &regmap_config);

So all code can use regmap function without if-then statements if SCMI work
as regmap.

Frank


>where if we use a syscon interface we can write
> a driver to handle that quite transparently without modifying each
> individual driver which reads or writes to one of these registers.
> That code is out of tree for now, but eventually we'll want to
> support this.
>
> Changed since v1:
> * Add imx at lists.linux.dev to the CC list.
> * Fix forward porting bug.  s/PHY_INTF_SEL_RGMII/S32_PHY_INTF_SEL_RGMII/
> * Use the correct SoC names nxp,s32g2-gpr and nxp,s32g3-gpr instead of
>   nxp,s32g-gpr which is the SoC family.
> * Fix the phandle name by adding the vendor prefix
> * Fix the documentation for the phandle
> * Remove #address-cells and #size-cells from the syscon block
>
> Here is the whole list of registers in the GPR region
>
> Starting from 0x4007C000
>
> 0  Software-Triggered Faults (SW_NCF)
> 4  GMAC Control (GMAC_0_CTRL_STS)
> 28 CMU Status 1 (CMU_STATUS_REG1)
> 2C CMUs Status 2 (CMU_STATUS_REG2)
> 30 FCCU EOUT Override Clear (FCCU_EOUT_OVERRIDE_CLEAR_REG)
> 38 SRC POR Control (SRC_POR_CTRL_REG)
> 54 GPR21 (GPR21)
> 5C GPR23 (GPR23)
> 60 GPR24 Register (GPR24)
> CC Debug Control (DEBUG_CONTROL)
> F0 Timestamp Control (TIMESTAMP_CONTROL_REGISTER)
> F4 FlexRay OS Tick Input Select (FLEXRAY_OS_TICK_INPUT_SELECT_REG)
> FC GPR63 Register (GPR63)
>
> Starting from 0x4007CA00
>
> 0  Coherency Enable for PFE Ports (PFE_COH_EN)
> 4  PFE EMAC Interface Mode (PFE_EMACX_INTF_SEL)
> 20 PFE EMACX Power Control (PFE_PWR_CTRL)
> 28 Error Injection on Cortex-M7 AHB and AXI Pipe (CM7_TCM_AHB_SLICE)
> 2C Error Injection AHBP Gasket Cortex-M7 (ERROR_INJECTION_AHBP_GASKET_CM7)
> 40 LLCE Subsystem Status (LLCE_STAT)
> 44 LLCE Power Control (LLCE_CTRL)
> 48 DDR Urgent Control (DDR_URGENT_CTRL)
> 4C FTM Global Load Control (FLXTIM_CTRL)
> 50 FTM LDOK Status (FLXTIM_STAT)
> 54 Top CMU Status (CMU_STAT)
> 58 Accelerator NoC No Pending Trans Status (NOC_NOPEND_TRANS)
> 90 SerDes RD/WD Toggle Control (PCIE_TOGGLE)
> 94 SerDes Toggle Done Status (PCIE_TOGGLEDONE_STAT)
> E0 Generic Control 0 (GENCTRL0)
> E4 Generic Control 1 (GENCTRL1)
> F0 Generic Status 0 (GENSTAT0)
> FC Cortex-M7 AXI Parity Error and AHBP Gasket Error Alarm (CM7_AXI_AHBP_GASKET_ERROR_ALARM)
>
> Starting from 4007C800
>
> 4  GPR01 Register (GPR01)
> 30 GPR12 Register (GPR12)
> 58 GPR22 Register (GPR22)
> 70 GPR28 Register (GPR28)
> 74 GPR29 Register (GPR29)
>
> Starting from 4007CB00
>
> 4 WKUP Pad Pullup/Pulldown Select (WKUP_PUS)
>
> Dan Carpenter (4):
>   net: stmmac: s32: use a syscon for S32_PHY_INTF_SEL_RGMII
>   dt-bindings: mfd: syscon: Document the GPR syscon for the NXP S32 SoCs
>   dt-bindings: net: nxp,s32-dwmac: Use the GPR syscon
>   dts: s32g: Add GPR syscon region
>
>  .../devicetree/bindings/mfd/syscon.yaml       |  4 ++++
>  .../bindings/net/nxp,s32-dwmac.yaml           | 10 ++++++++
>  arch/arm64/boot/dts/freescale/s32g2.dtsi      |  6 +++++
>  arch/arm64/boot/dts/freescale/s32g3.dtsi      |  6 +++++
>  .../net/ethernet/stmicro/stmmac/dwmac-s32.c   | 23 +++++++++++++++----
>  5 files changed, 44 insertions(+), 5 deletions(-)
>
> --
> 2.51.0
>


From ulf.hansson at linaro.org  Mon Dec 15 07:57:03 2025
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Mon, 15 Dec 2025 16:57:03 +0100
Subject: [PATCH v4 00/21] Add support for MT8189 clock/power controller
In-Reply-To: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
References: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
Message-ID: <CAPDyKFrsRTmvc4JmFAT_mCEEaG9yGkZn_JJqqyqCnB-AmpZgsQ@mail.gmail.com>

On Mon, 15 Dec 2025 at 04:50, irving.ch.lin <irving-ch.lin at mediatek.com> wrote:
>
> From: Irving-CH Lin <irving-ch.lin at mediatek.com>
>
> Changes since v4:
> - Fix dt_binding_check warning.
> - Check prepare_enable before set_parent to ensure our reference clock is ready.
> - Enable fhctl in apmixed driver.
> - Refine clock drivers:
>   - Change subsys name, regs base/size (clock related part, instead of whole subsys).
>   - Simply code with GATE_MTK macro.
>   - Add MODULE_DEVICE_TABLE, MODULE_DESCRIPTION
>   - Register remove callback mtk_clk_simple_remove.
>   - Remove most of CLK_OPS_PARENT_ENABLE and CLK_IGNORE_UNUSED which may block bringup,
>       but some subsys will power off before we disable unused clocks, so still need here.

I assume I can pick the pmdomain related changes (patch2, patch20 and
patch21) from this series, as they are independent from the clock
changes, right?

Kind regards
Uffe


>
> changes since v3:
> - Add power-controller dt-schema to mediatek,power-controller.yaml.
> - Separates clock commit to small parts (by sub-system).
> - Change to mtk-pm-domains for new MTK pm framework.
>
> changes since v2:
> - Fix dt-schema checking fails
> - Merge dt-binding files and dt-schema files into one patch.
> - Add vendor information to dt-binding file name.
> - Remove NR define in dt-binding header.
> - Add struct member description.
>
>   This series add support for the clock and power controllers
> of MediaTek's new SoC, MT8189. With these changes,
> other modules can easily manage clock and power resources
> using standard Linux APIs, such as the Common Clock Framework (CCF)
> and pm_runtime on MT8189 platform.
>
> Irving-CH Lin (21):
>   dt-bindings: clock: mediatek: Add MT8189 clock definitions
>   dt-bindings: power: mediatek: Add MT8189 power domain definitions
>   clk: mediatek: clk-mux: Make sure bypass clk enabled while setting MFG
>     rate
>   clk: mediatek: Add MT8189 apmixedsys clock support
>   clk: mediatek: Add MT8189 topckgen clock support
>   clk: mediatek: Add MT8189 vlpckgen clock support
>   clk: mediatek: Add MT8189 vlpcfg clock support
>   clk: mediatek: Add MT8189 bus clock support
>   clk: mediatek: Add MT8189 cam clock support
>   clk: mediatek: Add MT8189 dbgao clock support
>   clk: mediatek: Add MT8189 dvfsrc clock support
>   clk: mediatek: Add MT8189 i2c clock support
>   clk: mediatek: Add MT8189 img clock support
>   clk: mediatek: Add MT8189 mdp clock support
>   clk: mediatek: Add MT8189 mfg clock support
>   clk: mediatek: Add MT8189 dispsys clock support
>   clk: mediatek: Add MT8189 scp clock support
>   clk: mediatek: Add MT8189 ufs clock support
>   clk: mediatek: Add MT8189 vcodec clock support
>   pmdomain: mediatek: Add bus protect control flow for MT8189
>   pmdomain: mediatek: Add power domain driver for MT8189 SoC
>
>  .../bindings/clock/mediatek,mt8189-clock.yaml |   90 ++
>  .../clock/mediatek,mt8189-sys-clock.yaml      |   58 +
>  .../power/mediatek,power-controller.yaml      |    1 +
>  drivers/clk/mediatek/Kconfig                  |  146 +++
>  drivers/clk/mediatek/Makefile                 |   14 +
>  drivers/clk/mediatek/clk-mt8189-apmixedsys.c  |  192 ++++
>  drivers/clk/mediatek/clk-mt8189-bus.c         |  196 ++++
>  drivers/clk/mediatek/clk-mt8189-cam.c         |  108 ++
>  drivers/clk/mediatek/clk-mt8189-dbgao.c       |   94 ++
>  drivers/clk/mediatek/clk-mt8189-dispsys.c     |  172 +++
>  drivers/clk/mediatek/clk-mt8189-dvfsrc.c      |   54 +
>  drivers/clk/mediatek/clk-mt8189-iic.c         |  118 ++
>  drivers/clk/mediatek/clk-mt8189-img.c         |  107 ++
>  drivers/clk/mediatek/clk-mt8189-mdpsys.c      |   91 ++
>  drivers/clk/mediatek/clk-mt8189-mfg.c         |   53 +
>  drivers/clk/mediatek/clk-mt8189-scp.c         |   73 ++
>  drivers/clk/mediatek/clk-mt8189-topckgen.c    | 1020 +++++++++++++++++
>  drivers/clk/mediatek/clk-mt8189-ufs.c         |   89 ++
>  drivers/clk/mediatek/clk-mt8189-vcodec.c      |   93 ++
>  drivers/clk/mediatek/clk-mt8189-vlpcfg.c      |  111 ++
>  drivers/clk/mediatek/clk-mt8189-vlpckgen.c    |  280 +++++
>  drivers/clk/mediatek/clk-mux.c                |    9 +-
>  drivers/pmdomain/mediatek/mt8189-pm-domains.h |  485 ++++++++
>  drivers/pmdomain/mediatek/mtk-pm-domains.c    |   36 +-
>  drivers/pmdomain/mediatek/mtk-pm-domains.h    |    5 +
>  .../dt-bindings/clock/mediatek,mt8189-clk.h   |  580 ++++++++++
>  .../dt-bindings/power/mediatek,mt8189-power.h |   38 +
>  27 files changed, 4306 insertions(+), 7 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt8189-clock.yaml
>  create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt8189-sys-clock.yaml
>  create mode 100644 drivers/clk/mediatek/clk-mt8189-apmixedsys.c
>  create mode 100644 drivers/clk/mediatek/clk-mt8189-bus.c
>  create mode 100644 drivers/clk/mediatek/clk-mt8189-cam.c
>  create mode 100644 drivers/clk/mediatek/clk-mt8189-dbgao.c
>  create mode 100644 drivers/clk/mediatek/clk-mt8189-dispsys.c
>  create mode 100644 drivers/clk/mediatek/clk-mt8189-dvfsrc.c
>  create mode 100644 drivers/clk/mediatek/clk-mt8189-iic.c
>  create mode 100644 drivers/clk/mediatek/clk-mt8189-img.c
>  create mode 100644 drivers/clk/mediatek/clk-mt8189-mdpsys.c
>  create mode 100644 drivers/clk/mediatek/clk-mt8189-mfg.c
>  create mode 100644 drivers/clk/mediatek/clk-mt8189-scp.c
>  create mode 100644 drivers/clk/mediatek/clk-mt8189-topckgen.c
>  create mode 100644 drivers/clk/mediatek/clk-mt8189-ufs.c
>  create mode 100644 drivers/clk/mediatek/clk-mt8189-vcodec.c
>  create mode 100644 drivers/clk/mediatek/clk-mt8189-vlpcfg.c
>  create mode 100644 drivers/clk/mediatek/clk-mt8189-vlpckgen.c
>  create mode 100644 drivers/pmdomain/mediatek/mt8189-pm-domains.h
>  create mode 100644 include/dt-bindings/clock/mediatek,mt8189-clk.h
>  create mode 100644 include/dt-bindings/power/mediatek,mt8189-power.h
>
> --
> 2.45.2
>


From Sascha.Bischoff at arm.com  Mon Dec 15 08:01:47 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Mon, 15 Dec 2025 16:01:47 +0000
Subject: [PATCH 07/32] KVM: arm64: gic: Introduce interrupt type helpers
In-Reply-To: <86jyynooq3.wl-maz@kernel.org>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	 <20251212152215.675767-8-sascha.bischoff@arm.com>
	 <86jyynooq3.wl-maz@kernel.org>
Message-ID: <38b8e14630a16d74ab7c0ce07ceda2e572d8a01f.camel@arm.com>

On Mon, 2025-12-15 at 13:32 +0000, Marc Zyngier wrote:
> On Fri, 12 Dec 2025 15:22:37 +0000,
> Sascha Bischoff <Sascha.Bischoff at arm.com> wrote:
> > ?
> > -	if (!(irq_is_ppi(irq)))
> > +	if (!(irq_is_ppi(vcpu->kvm, irq)))
> 
> nit: From a high-level perspective, I'd find it mentally more
> satisfying to pass a vcpu to the macro rather than a vm pointer when
> dealing with PPIs. It would also keep the dereference hidden away.
> But
> maybe i just need to go with the flow here.

No, I think you're right. It better aligns with the semantics
underlying private IRQs, and does make the code a bit neater. If we're
ever generically checking (e.g., not using the _v5 variant) and don't
have a vcpu pointer in that context then something is likely awry.

It does make irq_is_private(k, i) a bit strange though as that is used
for things like

	if (!vcpu && irq_is_private(kvm, intid))

in later commits. That needs to take struct kvm if we want to do the
same sort of check. Else, we might as well not have it.

> > +#define irq_is_lpi_legacy(irq) ((irq) > VGIC_MAX_SPI)
> 
> This last line is wrong. v3 LPIs start at 8192, while VGIC_MAX_SPI is
> 1019. Also, "legacy" is remarkably ambiguous. v2 is legacy for v3, v3
> for v4...? You see where this is going.
> 
> I'd rather you have something that denotes the non-GICv5-ness of the
> implementation. irq_is_nv5_ppi()?

You are absolutely correct; that last line is wrong. Fixed, thanks!

And yeah, naming is hard. From my (unique) point of view, everything
that isn't GICv5 is legacy, but that's not exactly helpful for anyone
else.

IMO, nv5 is a bit too close to NV & NV2. I'd prefer something more like
irq_is_non_v5_ppi for the naming, but definitely don't heel strongly.
Happy for suggestions here, but for the time being I've locally changed
to using nv5 in the place of legacy.

> > ?#define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
> > ?#define vgic_initialized(k)	((k)->arch.vgic.initialized)
> > -#define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) &&
> > \
> > +#define vgic_ready(k)		((k)->arch.vgic.ready)
> 
> What is this for? Nothing seem to be using it yet. How different is
> it
> from the 'initialized' field?

This is for nothing, and wasn't meant to be here at all. Seems it crept
in from the prototyping, and slipped through the cracks when preparing
this series. Have dropped it. Apologies!

> > +#define vgic_valid_spi_legacy(k, i)	(((i) >=
> > VGIC_NR_PRIVATE_IRQS) && \
> > ?			((i) < (k)->arch.vgic.nr_spis +
> > VGIC_NR_PRIVATE_IRQS))
> > +#define vgic_valid_spi_v5(k, i)	(irq_is_spi(k, i) && \
> > +				 (FIELD_GET(GICV5_HWIRQ_ID, i) <
> > (k)->arch.vgic.nr_spis))
> > +#define vgic_valid_spi(k, i) (((k)->arch.vgic.vgic_model !=
> > KVM_DEV_TYPE_ARM_VGIC_V5) ? \
> > +				vgic_valid_spi_legacy(k, i) :
> > vgic_valid_spi_v5(k, i))
> > 
> 
> This macro has its v5/nv5 statements in the opposite order of all the
> others. Some consistency would be welcome.

Have re-ordered to match the order above.

> 
> Thanks,
> 
> 	M.
> 

Thanks,
Sascha


From maz at kernel.org  Mon Dec 15 08:05:04 2025
From: maz at kernel.org (Marc Zyngier)
Date: Mon, 15 Dec 2025 16:05:04 +0000
Subject: [PATCH 07/32] KVM: arm64: gic: Introduce interrupt type helpers
In-Reply-To: <86jyynooq3.wl-maz@kernel.org>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	<20251212152215.675767-8-sascha.bischoff@arm.com>
	<86jyynooq3.wl-maz@kernel.org>
Message-ID: <86ecovohn3.wl-maz@kernel.org>

On Mon, 15 Dec 2025 13:32:04 +0000,
Marc Zyngier <maz at kernel.org> wrote:
> 
> I'd rather you have something that denotes the non-GICv5-ness of the
> implementation. irq_is_nv5_ppi()?

Actually, this is just as bad. I spent the past 30 minutes hacking on
this, and came up with this hack (which compiles, but probably doesn't
run). It is significantly more code, but I like that it treats all GIC
implementations more or less the same way.

It also clears the who [v]gic_is_v5() situation that made little
sense.

Let me know what you think.

	M.

diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c
index b0a5a6c6bf8da..c908d5ac4d678 100644
--- a/arch/arm64/kvm/arch_timer.c
+++ b/arch/arm64/kvm/arch_timer.c
@@ -62,11 +62,6 @@ static struct irq_ops arch_timer_irq_ops_vgic_v5 = {
 	.queue_irq_unlock = vgic_v5_ppi_queue_irq_unlock,
 };
 
-static bool vgic_is_v5(struct kvm_vcpu *vcpu)
-{
-	return vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5;
-}
-
 static int nr_timers(struct kvm_vcpu *vcpu)
 {
 	if (!vcpu_has_nv(vcpu))
@@ -708,7 +703,7 @@ static void kvm_timer_vcpu_load_gic(struct arch_timer_context *ctx)
 
 	phys_active |= ctx->irq.level;
 
-	if (!vgic_is_v5(vcpu))
+	if (!vgic_is_v5(vcpu->kvm))
 		set_timer_irq_phys_active(ctx, phys_active);
 	else
 		set_timer_irq_phys_masked(ctx, true);
@@ -760,7 +755,7 @@ static void kvm_timer_vcpu_load_nested_switch(struct kvm_vcpu *vcpu,
 	if (!irqchip_in_kernel(vcpu->kvm))
 		return;
 
-	ops = vgic_is_v5(vcpu) ? &arch_timer_irq_ops_vgic_v5 :
+	ops = vgic_is_v5(vcpu->kvm) ? &arch_timer_irq_ops_vgic_v5 :
 				 &arch_timer_irq_ops;
 
 	/*
@@ -905,7 +900,7 @@ void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)
 
 	if (static_branch_likely(&has_gic_active_state)) {
 		/* We don't do NV on GICv5, yet */
-		if (vcpu_has_nv(vcpu) && !vgic_is_v5(vcpu))
+		if (vcpu_has_nv(vcpu) && !vgic_is_v5(vcpu->kvm))
 			kvm_timer_vcpu_load_nested_switch(vcpu, &map);
 
 		kvm_timer_vcpu_load_gic(map.direct_vtimer);
@@ -977,7 +972,7 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
 		kvm_timer_blocking(vcpu);
 
 	/* Unmask again on GICV5 */
-	if (vgic_is_v5(vcpu)) {
+	if (vgic_is_v5(vcpu->kvm)) {
 		set_timer_irq_phys_masked(map.direct_vtimer, false);
 
 		if (map.direct_ptimer)
@@ -1623,7 +1618,7 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
 		return -EINVAL;
 	}
 
-	ops = vgic_is_v5(vcpu) ? &arch_timer_irq_ops_vgic_v5 :
+	ops = vgic_is_v5(vcpu->kvm) ? &arch_timer_irq_ops_vgic_v5 :
 				 &arch_timer_irq_ops;
 
 	get_timer_map(vcpu, &map);
@@ -1700,7 +1695,7 @@ int kvm_arm_timer_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
 	 * The PPIs for the Arch Timers arch architecturally defined for
 	 * GICv5. Reject anything that changes them from the specified value.
 	 */
-	if (vgic_is_v5(vcpu) && vcpu->kvm->arch.timer_data.ppi[idx] != irq) {
+	if (vgic_is_v5(vcpu->kvm) && vcpu->kvm->arch.timer_data.ppi[idx] != irq) {
 		ret = -EINVAL;
 		goto out;
 	}
diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index d74cc3543b9a4..19d8bf90f8f6c 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -225,7 +225,7 @@ bool vgic_v5_ppi_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq,
 
 	lockdep_assert_held(&irq->irq_lock);
 
-	if (WARN_ON_ONCE(!irq_is_ppi_v5(irq->intid)))
+	if (WARN_ON_ONCE(!__irq_is_ppi(KVM_DEV_TYPE_ARM_VGIC_V5, irq->intid)))
 		return false;
 
 	vcpu = irq->target_vcpu;
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index 62d7d4c5650e4..6d8e4cd661734 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -109,10 +109,10 @@ struct vgic_irq *vgic_get_vcpu_irq(struct kvm_vcpu *vcpu, u32 intid)
 	if (WARN_ON(!vcpu))
 		return NULL;
 
-	if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5) {
+	if (vgic_is_v5(vcpu->kvm)) {
 		u32 int_num = FIELD_GET(GICV5_HWIRQ_ID, intid);
 
-		if (irq_is_ppi_v5(intid)) {
+		if (__irq_is_ppi(KVM_DEV_TYPE_ARM_VGIC_V5, intid)) {
 			int_num = array_index_nospec(int_num, VGIC_V5_NR_PRIVATE_IRQS);
 			return &vcpu->arch.vgic_cpu.private_irqs[int_num];
 		}
@@ -600,15 +600,13 @@ static int kvm_vgic_map_irq(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
 	irq->hwintid = data->hwirq;
 	irq->ops = ops;
 
-	if (vgic_is_v5(vcpu->kvm)) {
-		/* Nothing for us to do */
-		if (!irq_is_ppi_v5(irq->intid))
-			return 0;
+	if (vgic_is_v5(vcpu->kvm) &&
+	    !__irq_is_ppi(KVM_DEV_TYPE_ARM_VGIC_V5, irq->intid))
+		return 0;
 
-		if (FIELD_GET(GICV5_HWIRQ_ID, irq->intid) == irq->hwintid) {
-			if (!vgic_v5_set_ppi_dvi(vcpu, irq->hwintid, true))
-				irq->directly_injected = true;
-		}
+	if (FIELD_GET(GICV5_HWIRQ_ID, irq->intid) == irq->hwintid) {
+		if (!vgic_v5_set_ppi_dvi(vcpu, irq->hwintid, true))
+			irq->directly_injected = true;
 	}
 
 	return 0;
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index 91969b3b80d04..d8a947a7eb941 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -500,11 +500,6 @@ static inline bool vgic_is_v3(struct kvm *kvm)
 	return kvm_vgic_global_state.type == VGIC_V3 || vgic_is_v3_compat(kvm);
 }
 
-static inline bool vgic_is_v5(struct kvm *kvm)
-{
-	return kvm_vgic_global_state.type == VGIC_V5 && !vgic_is_v3_compat(kvm);
-}
-
 bool system_supports_direct_sgis(void);
 bool vgic_supports_direct_msis(struct kvm *kvm);
 bool vgic_supports_direct_sgis(struct kvm *kvm);
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 6863e19d6eeb7..ae2897c539af7 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -36,22 +36,78 @@
 /* GICv5 constants */
 #define VGIC_V5_NR_PRIVATE_IRQS	128
 
-#define irq_is_ppi_legacy(irq) ((irq) >= VGIC_NR_SGIS && (irq) < VGIC_NR_PRIVATE_IRQS)
-#define irq_is_spi_legacy(irq) ((irq) >= VGIC_NR_PRIVATE_IRQS && \
-					(irq) <= VGIC_MAX_SPI)
-#define irq_is_lpi_legacy(irq) ((irq) > VGIC_MAX_SPI)
-
-#define irq_is_ppi_v5(irq) (FIELD_GET(GICV5_HWIRQ_TYPE, irq) == GICV5_HWIRQ_TYPE_PPI)
-#define irq_is_spi_v5(irq) (FIELD_GET(GICV5_HWIRQ_TYPE, irq) == GICV5_HWIRQ_TYPE_SPI)
-#define irq_is_lpi_v5(irq) (FIELD_GET(GICV5_HWIRQ_TYPE, irq) == GICV5_HWIRQ_TYPE_LPI)
-
-#define gic_is_v5(k) ((k)->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5)
-
-#define irq_is_ppi(k, i) (gic_is_v5(k) ? irq_is_ppi_v5(i) : irq_is_ppi_legacy(i))
-#define irq_is_spi(k, i) (gic_is_v5(k) ? irq_is_spi_v5(i) : irq_is_spi_legacy(i))
-#define irq_is_lpi(k, i) (gic_is_v5(k) ? irq_is_lpi_v5(i) : irq_is_lpi_legacy(i))
-
-#define irq_is_private(k, i) (gic_is_v5(k) ? irq_is_ppi_v5(i) : i < VGIC_NR_PRIVATE_IRQS)
+#define is_v5_type(t, i)	(FIELD_GET(GICV5_HWIRQ_TYPE, (i)) == (t))
+
+#define __irq_is_sgi(t, i)						\
+	({								\
+		bool __ret;						\
+									\
+		switch (t) {						\
+		case KVM_DEV_TYPE_ARM_VGIC_V5:				\
+			__ret = false;					\
+			break;						\
+		default:						\
+			__ret  = (i) < VGIC_NR_SGIS;			\
+		}							\
+									\
+		__ret;							\
+	})
+
+#define __irq_is_ppi(t, i)						\
+	({								\
+		bool __ret;						\
+									\
+		switch (t) {						\
+		case KVM_DEV_TYPE_ARM_VGIC_V5:				\
+			__ret = is_v5_type(GICV5_HWIRQ_TYPE_PPI, (i));	\
+			break;						\
+		default:						\
+			__ret  = (i) >= VGIC_NR_SGIS;			\
+			__ret &= (i) < VGIC_NR_PRIVATE_IRQS;		\
+		}							\
+									\
+		__ret;							\
+	})
+
+#define __irq_is_spi(t, i)						\
+	({								\
+		bool __ret;						\
+									\
+		switch (t) {						\
+		case KVM_DEV_TYPE_ARM_VGIC_V5:				\
+			__ret = is_v5_type(GICV5_HWIRQ_TYPE_SPI, (i));	\
+			break;						\
+		default:						\
+			__ret  = (i) <= VGIC_MAX_SPI;			\
+			__ret &= (i) >= VGIC_NR_PRIVATE_IRQS;		\
+		}							\
+									\
+		__ret;							\
+	})
+
+#define __irq_is_lpi(t, i)						\
+	({								\
+		bool __ret;						\
+									\
+		switch (t) {						\
+		case KVM_DEV_TYPE_ARM_VGIC_V5:				\
+			__ret = is_v5_type(GICV5_HWIRQ_TYPE_LPI, (i));	\
+			break;						\
+		default:						\
+			__ret  = (i) >= 8192;				\
+		}							\
+									\
+		__ret;							\
+	})
+
+#define irq_is_sgi(k, i) __irq_is_sgi((k)->arch.vgic.vgic_model, i)
+#define irq_is_ppi(k, i) __irq_is_ppi((k)->arch.vgic.vgic_model, i)
+#define irq_is_spi(k, i) __irq_is_spi((k)->arch.vgic.vgic_model, i)
+#define irq_is_lpi(k, i) __irq_is_lpi((k)->arch.vgic.vgic_model, i)
+
+#define irq_is_private(k, i) (irq_is_ppi(k, i) || irq_is_sgi(k, i))
+
+#define vgic_is_v5(k) ((k)->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5)
 
 enum vgic_type {
 	VGIC_V2,		/* Good ol' GICv2 */

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


From m.felsch at pengutronix.de  Mon Dec 15 08:05:10 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Mon, 15 Dec 2025 17:05:10 +0100
Subject: [PATCH v7 1/3] dt-bindings: soc: imx93-media-blk-ctrl: Add PDFC
 subnode to schema and example
In-Reply-To: <20251208012826.GA340359-robh@kernel.org>
References: <20251202-v6-18-topic-imx93-parallel-display-v7-0-2cce31d64608@pengutronix.de>
 <20251202-v6-18-topic-imx93-parallel-display-v7-1-2cce31d64608@pengutronix.de>
 <20251208012826.GA340359-robh@kernel.org>
Message-ID: <20251215160510.msuinr2dierrifit@pengutronix.de>

On 25-12-07, Rob Herring wrote:
> On Tue, Dec 02, 2025 at 02:32:58PM +0100, Marco Felsch wrote:
> > From: Liu Ying <victor.liu at nxp.com>
> > 
> > i.MX93 SoC mediamix blk-ctrl contains one DISPLAY_MUX register which
> > configures parallel display format by using the "PARALLEL_DISP_FORMAT"
> > field. Document the Parallel Display Format Configuration(PDFC) subnode
> > and add the subnode to example.
> > 
> > Signed-off-by: Liu Ying <victor.liu at nxp.com>
> > [m.felsch at pengutronix.de: port to v6.18-rc1]
> > [m.felsch at pengutronix.de: add bus-width]
> > Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
> > ---
> >  .../bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml | 92 ++++++++++++++++++++++
> >  1 file changed, 92 insertions(+)
> > 
> > diff --git a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> > index 34aea58094e55365a2f9c86092f637e533f954ff..6e2d86d9341c75108b492bcbabc8a560d8e707cd 100644
> > --- a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> > +++ b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> > @@ -26,6 +26,12 @@ properties:
> >    reg:
> >      maxItems: 1
> >  
> > +  '#address-cells':
> > +    const: 1
> > +
> > +  '#size-cells':
> > +    const: 1
> > +
> 
> And 'ranges' needed.

I dropped this due to the response from Krzysztof:

https://lore.kernel.org/linux-arm-kernel/c7129d8e-87de-444c-be52-b2eedf03585f at kernel.org/

Regards,
  Marco

> >    '#power-domain-cells':
> >      const: 1
> >  
> > @@ -40,6 +46,60 @@ properties:
> >      minItems: 8
> >      maxItems: 10
> >  
> > +  bridge at 60:
> > +    type: object
> > +    additionalProperties: false
> > +
> > +    properties:
> > +      compatible:
> > +        const: nxp,imx93-pdfc
> > +
> > +      reg:
> > +        maxItems: 1
> > +
> > +      ports:
> > +        $ref: /schemas/graph.yaml#/properties/ports
> > +
> > +        properties:
> > +          port at 0:
> > +            $ref: /schemas/graph.yaml#/properties/port
> > +            description: Input port node to receive pixel data.
> > +
> > +          port at 1:
> > +            $ref: /schemas/graph.yaml#/$defs/port-base
> > +            unevaluatedProperties: false
> > +            description: Output port node to downstream pixel data receivers.
> > +
> > +            properties:
> > +              endpoint:
> > +                $ref: /schemas/graph.yaml#/$defs/endpoint-base
> > +                unevaluatedProperties: false
> > +
> > +                properties:
> > +                  bus-width:
> > +                    enum: [ 16, 18, 24 ]
> > +                    description:
> > +                      Specify the physical parallel bus width.
> > +
> > +                      This property is optional if the display bus-width
> > +                      matches the SoC bus-width, e.g. a 18-bit RGB666 (display)
> > +                      is connected and all 18-bit data lanes are muxed to the
> > +                      parallel-output pads.
> > +
> > +                      This property must be set to 18 to cut only the LSBs
> > +                      instead of the MSBs in case a 24-bit RGB888 display is
> > +                      connected and only the lower 18-bit data lanes are muxed
> > +                      to the parallel-output pads.
> > +
> > +        required:
> > +          - port at 0
> > +          - port at 1
> > +
> > +    required:
> > +      - compatible
> > +      - reg
> > +      - ports
> > +
> >  allOf:
> >    - if:
> >        properties:
> > @@ -81,9 +141,12 @@ allOf:
> >              - const: isi
> >              - const: csi
> >              - const: dsi
> > +
> >  required:
> >    - compatible
> >    - reg
> > +  - '#address-cells'
> > +  - '#size-cells'
> >    - power-domains
> >    - clocks
> >    - clock-names
> > @@ -112,4 +175,33 @@ examples:
> >                 clock-names = "apb", "axi", "nic", "disp", "cam",
> >                               "pxp", "lcdif", "isi", "csi", "dsi";
> >        #power-domain-cells = <1>;
> > +      #address-cells = <1>;
> > +      #size-cells = <1>;
> > +
> > +      bridge at 60 {
> > +        compatible = "nxp,imx93-pdfc";
> > +        reg = <0x60 0x4>;
> > +
> > +        ports {
> > +          #address-cells = <1>;
> > +          #size-cells = <0>;
> > +
> > +          port at 0 {
> > +            reg = <0>;
> > +
> > +            pdfc_from_lcdif: endpoint {
> > +              remote-endpoint = <&lcdif_to_pdfc>;
> > +            };
> > +          };
> > +
> > +          port at 1 {
> > +            reg = <1>;
> > +
> > +            pdfc_to_panel: endpoint {
> > +              remote-endpoint = <&panel_from_pdfc>;
> > +              bus-width = <18>;
> > +            };
> > +          };
> > +        };
> > +      };
> >      };
> > 
> > -- 
> > 2.47.3
> > 
> 

-- 
#gernperDu 
#CallMeByMyFirstName

Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | https://www.pengutronix.de/ |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-9    |


From michal.simek at amd.com  Mon Dec 15 08:10:42 2025
From: michal.simek at amd.com (Michal Simek)
Date: Mon, 15 Dec 2025 17:10:42 +0100
Subject: [PATCH] Revert "arm64: zynqmp: Add an OP-TEE node to the device
 tree"
In-Reply-To: <0435af95-a3bc-4ec7-b07b-bdec42f25c56@vaisala.com>
References: <20251125-revert-zynqmp-optee-v1-1-d2ce4c0fcaf6@vaisala.com>
 <88b72343-e86f-4b13-adcc-ba09683eb898@amd.com>
 <199062ba-9a0d-40ae-ac8c-0fbed5615cf8@vaisala.com>
 <3654c600-553f-429a-8bec-1add7f6eb5c6@vaisala.com>
 <db79cd4a-548d-46f1-b498-aac82ca53010@amd.com>
 <0435af95-a3bc-4ec7-b07b-bdec42f25c56@vaisala.com>
Message-ID: <7e82a871-0234-409a-8fd3-a548cbb789e8@amd.com>



On 12/15/25 16:43, Tomas Melin wrote:
> Hi,
> 
> On 15/12/2025 17:21, Michal Simek wrote:
>> Hi,
>>
>> On 12/12/25 13:09, Tomas Melin wrote:
>>> Hi,
>>>
>>> Is there some more specific information I can provide regarding this patch?
>>
>> I am trying to identify U-Boot code (2026.01-rc4) which does what you have
>> described in the commit message but I can't find it out.
>> Can you please point me directly to file, line number where that described logic
>> is skipped?
> 
> Please check lib/optee/optee.c, in particular lines 128 ->
> Target dt being linux kernel devicetree where the reserved-memory nodes
> are automatically injected. When node is already there, it bails out early.

I don't really mind that's why applied.

Thanks,
Michal




From Frank.li at nxp.com  Mon Dec 15 08:12:25 2025
From: Frank.li at nxp.com (Frank Li)
Date: Mon, 15 Dec 2025 11:12:25 -0500
Subject: [PATCH] remoteproc: imx_rproc: Ues sync handling in rx_callback
 for i.MX7ULP suspend
In-Reply-To: <20251215-imx7ulp_rproc-v1-1-4e96cebc4bc6@nxp.com>
References: <20251215-imx7ulp_rproc-v1-1-4e96cebc4bc6@nxp.com>
Message-ID: <aUAzaXp1t+fTVfyT@lizhi-Precision-Tower-5810>

On Mon, Dec 15, 2025 at 03:26:05PM +0800, Jacky Bai wrote:
> On i.MX7ULP platform, certain drivers that depend on rpmsg may need
> to send an rpmsg request and receive an acknowledgment from the
> remote core during the late_suspend stage. In the current imx_rproc
> implementation, rx_callback defers message handling to a workqueue.
> However, this deferred work may not execute before the system enters
> the noirq_suspend stage. When that happens, pending mailbox IRQs
> will cause the suspend sequence to abort.
>
> To address this, handle incoming messages synchronously within
> rx_callback when running on i.MX7ULP. This ensures the message is
> processed immediately, allows the mailbox IRQ to be cleared in time,
> and prevents suspend failures.
>
> Signed-off-by: Jacky Bai <ping.bai at nxp.com>
> ---
>  drivers/remoteproc/imx_rproc.c | 49 ++++++++++++++++++++++++++++++++++++++++--
>  drivers/remoteproc/imx_rproc.h |  1 +
>  2 files changed, 48 insertions(+), 2 deletions(-)
>
...
>
> -	queue_work(priv->workqueue, &priv->rproc_work);
> +	if (priv->use_sync_rx)
> +		idr_for_each(&rproc->notifyids, imx_rproc_notified_idr_cb, rproc);
> +	else
> +		queue_work(priv->workqueue, &priv->rproc_work);
>  }
>
>  static int imx_rproc_xtr_mbox_init(struct rproc *rproc, bool tx_block)
> @@ -1009,6 +1015,38 @@ static int imx_rproc_sys_off_handler(struct sys_off_data *data)
>  	return NOTIFY_DONE;
>  }
>
> +static int imx_rproc_pm_notify(struct notifier_block *nb,
> +	unsigned long action, void *data)
> +{
> +	int ret;
> +	struct imx_rproc *priv = container_of(nb, struct imx_rproc, pm_nb);

	struct imx_rproc *priv = container_of(nb, struct imx_rproc, pm_nb);
	int ret;

> +
> +	imx_rproc_free_mbox(priv->rproc);
> +
> +	switch (action) {
> +	case PM_SUSPEND_PREPARE:
> +		ret = imx_rproc_xtr_mbox_init(priv->rproc, false);

Any risk condition if on going message during free() and _init()?

> +		if (ret) {
> +			dev_err(&priv->rproc->dev, "Failed to request non-blocking mbox\n");
> +			return NOTIFY_BAD;
> +		}
> +		priv->use_sync_rx = true;
> +		break;
> +	case PM_POST_SUSPEND:
> +		ret = imx_rproc_xtr_mbox_init(priv->rproc, true);
> +		if (ret) {
> +			dev_err(&priv->rproc->dev, "Failed to request blocking mbox\n");
> +			return NOTIFY_BAD;
> +		}
> +		priv->use_sync_rx = false;
> +		break;
> +	default:
> +		break;

imx_rproc_free_mbox() here? if other notify comming,  mbox is free() as
expected?

Frank
> +	}
> +
> +	return NOTIFY_OK;
> +}
> +
>  static void imx_rproc_destroy_workqueue(void *data)
>  {
>  	struct workqueue_struct *workqueue = data;
> @@ -1103,6 +1141,13 @@ static int imx_rproc_probe(struct platform_device *pdev)
>  			return dev_err_probe(dev, ret, "register restart handler failure\n");
>  	}
>
> +	if (dcfg->flags & IMX_RPROC_NEED_PM_SYNC) {
> +		priv->pm_nb.notifier_call = imx_rproc_pm_notify;
> +		ret = register_pm_notifier(&priv->pm_nb);
> +		if (ret)
> +			return dev_err_probe(dev, ret, "register pm notifier failure\n");
> +	}
> +
>  	pm_runtime_enable(dev);
>  	ret = pm_runtime_resume_and_get(dev);
>  	if (ret)
> @@ -1202,7 +1247,7 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx8ulp = {
>  static const struct imx_rproc_dcfg imx_rproc_cfg_imx7ulp = {
>  	.att		= imx_rproc_att_imx7ulp,
>  	.att_size	= ARRAY_SIZE(imx_rproc_att_imx7ulp),
> -	.flags		= IMX_RPROC_NEED_SYSTEM_OFF,
> +	.flags		= IMX_RPROC_NEED_SYSTEM_OFF | IMX_RPROC_NEED_PM_SYNC,
>  };
>
>  static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = {
> diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h
> index 1b2d9f4d6d19dcdc215be97f7e2ab3488281916a..0e3e460cef4ed9340fb4977183e03143c84764af 100644
> --- a/drivers/remoteproc/imx_rproc.h
> +++ b/drivers/remoteproc/imx_rproc.h
> @@ -18,6 +18,7 @@ struct imx_rproc_att {
>  /* dcfg flags */
>  #define IMX_RPROC_NEED_SYSTEM_OFF	BIT(0)
>  #define IMX_RPROC_NEED_CLKS		BIT(1)
> +#define IMX_RPROC_NEED_PM_SYNC		BIT(2)
>
>  struct imx_rproc_plat_ops {
>  	int (*start)(struct rproc *rproc);
>
> ---
> base-commit: 5ce74bc1b7cb2732b22f9c93082545bc655d6547
> change-id: 20251211-imx7ulp_rproc-57999329239b
>
> Best regards,
> --
> Jacky Bai <ping.bai at nxp.com>
>


From Frank.li at nxp.com  Mon Dec 15 08:16:35 2025
From: Frank.li at nxp.com (Frank Li)
Date: Mon, 15 Dec 2025 11:16:35 -0500
Subject: [PATCH 1/2] dt-bindings: power: fsl,imx-gpc: Document
 address-cells
In-Reply-To: <12807757.O9o76ZdvQC@steina-w>
References: <20251212085902.103507-1-alexander.stein@ew.tq-group.com>
 <aTxKqPqGdiHllLo6@lizhi-Precision-Tower-5810>
 <12807757.O9o76ZdvQC@steina-w>
Message-ID: <aUA0Y6mycZVX7cXD@lizhi-Precision-Tower-5810>

On Mon, Dec 15, 2025 at 08:31:47AM +0100, Alexander Stein wrote:
> Hi,
>
> Am Freitag, 12. Dezember 2025, 18:02:32 CET schrieb Frank Li:
> > On Fri, Dec 12, 2025 at 09:58:59AM +0100, Alexander Stein wrote:
> > > The GPC power controller is an interrupt controllers and can be referenced
> > > in interrupt-map properties, e.g. PCIe controller, thus the node should
> > > have address-cells property.
> > >
> > > Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
> >
> > Strange, there are not #address-cells property for gic if there are not
> > ITS node. gic is widely used.
> >
> > Does gic node also missed #address-cells?
>
> Yes and no.
> Yes: see commit faf183a02ed6b ("arm64: dts: imx8mp: Add default GIC address cells")
> No: AFAICS this is only necessary if an interrupt-controller is referenced
> from within interrupt-map. But on imx6qdl.dtsi 'intc' (GIC) is not used that way.

Thanks.

Frank

>
> Best regards,
> Alexander
>
> >
> > Frank
> >
> > > ---
> > >  Documentation/devicetree/bindings/power/fsl,imx-gpc.yaml | 3 +++
> > >  1 file changed, 3 insertions(+)
> > >
> > > diff --git a/Documentation/devicetree/bindings/power/fsl,imx-gpc.yaml b/Documentation/devicetree/bindings/power/fsl,imx-gpc.yaml
> > > index 9de3fe73c1eb6..d49a5130b87c7 100644
> > > --- a/Documentation/devicetree/bindings/power/fsl,imx-gpc.yaml
> > > +++ b/Documentation/devicetree/bindings/power/fsl,imx-gpc.yaml
> > > @@ -38,6 +38,9 @@ properties:
> > >    reg:
> > >      maxItems: 1
> > >
> > > +  "#address-cells":
> > > +    const: 0
> > > +
> > >    interrupts:
> > >      maxItems: 1
> > >
> > > --
> > > 2.43.0
> > >
> >
>
>
> --
> TQ-Systems GmbH | M?hlstra?e 2, Gut Delling | 82229 Seefeld, Germany
> Amtsgericht M?nchen, HRB 105018
> Gesch?ftsf?hrer: Detlef Schneider, R?diger Stahl, Stefan Schneider
> http://www.tq-group.com/




From m.felsch at pengutronix.de  Mon Dec 15 08:17:06 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Mon, 15 Dec 2025 17:17:06 +0100
Subject: [PATCH v7 1/3] dt-bindings: soc: imx93-media-blk-ctrl: Add PDFC
 subnode to schema and example
In-Reply-To: <705773fc-5aba-4bff-b05e-272e1cd0262c@nxp.com>
References: <20251202-v6-18-topic-imx93-parallel-display-v7-0-2cce31d64608@pengutronix.de>
 <20251202-v6-18-topic-imx93-parallel-display-v7-1-2cce31d64608@pengutronix.de>
 <705773fc-5aba-4bff-b05e-272e1cd0262c@nxp.com>
Message-ID: <20251215161706.2ea3wtu3xlwcxxar@pengutronix.de>

Hi Liu,

On 25-12-08, Liu Ying wrote:
> Hi Marco,
> 
> On 12/02/2025, Marco Felsch wrote:
> > From: Liu Ying <victor.liu at nxp.com>
> > 
> > i.MX93 SoC mediamix blk-ctrl contains one DISPLAY_MUX register which
> > configures parallel display format by using the "PARALLEL_DISP_FORMAT"
> > field. Document the Parallel Display Format Configuration(PDFC) subnode
> > and add the subnode to example.
> > 
> > Signed-off-by: Liu Ying <victor.liu at nxp.com>
> > [m.felsch at pengutronix.de: port to v6.18-rc1]
> > [m.felsch at pengutronix.de: add bus-width]
> > Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
> > ---
> >  .../bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml | 92 ++++++++++++++++++++++
> >  1 file changed, 92 insertions(+)
> > 
> > diff --git a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> > index 34aea58094e55365a2f9c86092f637e533f954ff..6e2d86d9341c75108b492bcbabc8a560d8e707cd 100644
> > --- a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> > +++ b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> > @@ -26,6 +26,12 @@ properties:
> >    reg:
> >      maxItems: 1
> >  
> > +  '#address-cells':
> > +    const: 1
> > +
> > +  '#size-cells':
> > +    const: 1
> > +
> >    '#power-domain-cells':
> >      const: 1
> >  
> > @@ -40,6 +46,60 @@ properties:
> >      minItems: 8
> >      maxItems: 10
> >  
> > +  bridge at 60:
> 
> The dependency patch series mentioned in cover letter has two links in it's
> cover letter.  Reading the patch sets pointed by the two links, we may find
> Krzysztof's comments - the child nodes of the blk-ctrl should be completely
> documented.

Thanks for pointing this out.

@Krzysztof
Requesting to add everything seems not feasible if everything added
should be tested too.
I don't see why everything should be added in one step, since the base
.dtsi isn't added in one step too.
The different devices (parallel-out bridge, DSI bridge, LVDS bridge,
CSI) logically don't belong together, ableit all device use the same
syscon as parent.

Regards,
  Marco

> > +    type: object
> > +    additionalProperties: false
> > +
> > +    properties:
> > +      compatible:
> > +        const: nxp,imx93-pdfc
> > +
> > +      reg:
> > +        maxItems: 1
> > +
> > +      ports:
> > +        $ref: /schemas/graph.yaml#/properties/ports
> > +
> > +        properties:
> > +          port at 0:
> > +            $ref: /schemas/graph.yaml#/properties/port
> > +            description: Input port node to receive pixel data.
> > +
> > +          port at 1:
> > +            $ref: /schemas/graph.yaml#/$defs/port-base
> > +            unevaluatedProperties: false
> > +            description: Output port node to downstream pixel data receivers.
> > +
> > +            properties:
> > +              endpoint:
> > +                $ref: /schemas/graph.yaml#/$defs/endpoint-base
> > +                unevaluatedProperties: false
> > +
> > +                properties:
> > +                  bus-width:
> 
> In v1-v5, I thought the output bus format can be determined by the sink
> device(a panel or a bridge) hence properties like bus-width were not needed.
> But, if this property is really needed, then reference video-interfaces.yaml
> since bus-width is documented there.  Should we reference bus-type defined
> in video-interfaces.yaml too?
> 
> > +                    enum: [ 16, 18, 24 ]
> 
> The PARALLEL_DISP_FORMAT field of DISPLAY_MUX register says this IP supports
> below formats.  It seems that the enum here may tell RGB888, RGB666 and RGB565.
> How can we tell RGB555, YCbCr 24 bits and YUV444 then?
> 
> 000b RGB888 -> RGB888
> 001b RGB888 -> RGB666
> 010b RGB565 -> RGB565
> 011b RGB555 -> RGB555
> 100b YUV -> YCbCr 24 bits
> 101b YUV -> YUV444
> 
> > +                    description:
> > +                      Specify the physical parallel bus width.
> > +
> > +                      This property is optional if the display bus-width
> > +                      matches the SoC bus-width, e.g. a 18-bit RGB666 (display)
> > +                      is connected and all 18-bit data lanes are muxed to the
> 
> Per video-interfaces.yaml, s/data lanes/data lines/.  "data lanes" is a
> value for MIPI DSI/CSI, afaik.
> 
> > +                      parallel-output pads.
> 
> How about just saying that this property is optional and by default it's 24?
> 
> > +
> > +                      This property must be set to 18 to cut only the LSBs
> > +                      instead of the MSBs in case a 24-bit RGB888 display is
> > +                      connected and only the lower 18-bit data lanes are muxed
> > +                      to the parallel-output pads.
> 
> The __lower__ 18-bit?  Isn't it the __MSB__ 6bit in each color component?
> 
> > +
> > +        required:
> > +          - port at 0
> > +          - port at 1
> > +
> > +    required:
> > +      - compatible
> > +      - reg
> > +      - ports
> > +
> >  allOf:
> >    - if:
> >        properties:
> > @@ -81,9 +141,12 @@ allOf:
> >              - const: isi
> >              - const: csi
> >              - const: dsi
> > +
> >  required:
> >    - compatible
> >    - reg
> > +  - '#address-cells'
> > +  - '#size-cells'
> >    - power-domains
> >    - clocks
> >    - clock-names
> > @@ -112,4 +175,33 @@ examples:
> >                 clock-names = "apb", "axi", "nic", "disp", "cam",
> >                               "pxp", "lcdif", "isi", "csi", "dsi";
> >        #power-domain-cells = <1>;
> > +      #address-cells = <1>;
> > +      #size-cells = <1>;
> > +
> > +      bridge at 60 {
> > +        compatible = "nxp,imx93-pdfc";
> > +        reg = <0x60 0x4>;
> > +
> > +        ports {
> > +          #address-cells = <1>;
> > +          #size-cells = <0>;
> > +
> > +          port at 0 {
> > +            reg = <0>;
> > +
> > +            pdfc_from_lcdif: endpoint {
> > +              remote-endpoint = <&lcdif_to_pdfc>;
> > +            };
> > +          };
> > +
> > +          port at 1 {
> > +            reg = <1>;
> > +
> > +            pdfc_to_panel: endpoint {
> > +              remote-endpoint = <&panel_from_pdfc>;
> > +              bus-width = <18>;
> > +            };
> > +          };
> > +        };
> > +      };
> >      };
> > 
> 
> 
> -- 
> Regards,
> Liu Ying
> 

-- 
#gernperDu 
#CallMeByMyFirstName

Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | https://www.pengutronix.de/ |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-9    |


From ryan.roberts at arm.com  Mon Dec 15 08:35:14 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Mon, 15 Dec 2025 16:35:14 +0000
Subject: [PATCH v2 0/3] Fix bugs and performance of kstack offset randomisation
Message-ID: <20251215163520.1144179-1-ryan.roberts@arm.com>

Hi All,

As I reported at [1], kstack offset randomisation suffers from a couple of bugs
and, on arm64 at least, the performance is poor. This series attempts to fix
both; patch 1 provides back-portable fixes for the functional bugs. Patches 2-3
propose a performance improvement approach.

I've looked at a few different options but ultimately decided that Jeremy's
original prng approach is the fastest. I made the argument that this approach is
secure "enough" in the RFC [2] and the responses indicated agreement.

More details in the commit logs.


Performance
===========

Mean and tail performance of 3 "small" syscalls was measured. syscall was made
10 million times and each individually measured and binned. These results have
low noise so I'm confident that they are trustworthy.

The baseline is v6.18-rc5 with stack randomization turned *off*. So I'm showing
performance cost of turning it on without any changes to the implementation,
then the reduced performance cost of turning it on with my changes applied.

**NOTE**: The below results were generated using the RFC patches but there is no
meaningful change, so the numbers are still valid.

arm64 (AWS Graviton3):
+-----------------+--------------+-------------+---------------+
| Benchmark       | Result Class |   v6.18-rc5 | per-task-prng |
|                 |              | rndstack-on |               |
|                 |              |             |               |
+=================+==============+=============+===============+
| syscall/getpid  | mean (ns)    |  (R) 15.62% |     (R) 3.43% |
|                 | p99 (ns)     | (R) 155.01% |     (R) 3.20% |
|                 | p99.9 (ns)   | (R) 156.71% |     (R) 2.93% |
+-----------------+--------------+-------------+---------------+
| syscall/getppid | mean (ns)    |  (R) 14.09% |     (R) 2.12% |
|                 | p99 (ns)     | (R) 152.81% |         1.55% |
|                 | p99.9 (ns)   | (R) 153.67% |         1.77% |
+-----------------+--------------+-------------+---------------+
| syscall/invalid | mean (ns)    |  (R) 13.89% |     (R) 3.32% |
|                 | p99 (ns)     | (R) 165.82% |     (R) 3.51% |
|                 | p99.9 (ns)   | (R) 168.83% |     (R) 3.77% |
+-----------------+--------------+-------------+---------------+

Because arm64 was previously using get_random_u16(), it was expensive when it
didn't have any buffered bits and had to call into the crng. That's what caused
the enormous tail latency.


x86 (AWS Sapphire Rapids):
+-----------------+--------------+-------------+---------------+
| Benchmark       | Result Class |   v6.18-rc5 | per-task-prng |
|                 |              | rndstack-on |               |
|                 |              |             |               |
+=================+==============+=============+===============+
| syscall/getpid  | mean (ns)    |  (R) 13.32% |     (R) 4.60% |
|                 | p99 (ns)     |  (R) 13.38% |    (R) 18.08% |
|                 | p99.9 (ns)   |      16.26% |    (R) 19.38% |
+-----------------+--------------+-------------+---------------+
| syscall/getppid | mean (ns)    |  (R) 11.96% |     (R) 5.26% |
|                 | p99 (ns)     |  (R) 11.83% |     (R) 8.35% |
|                 | p99.9 (ns)   |  (R) 11.42% |    (R) 22.37% |
+-----------------+--------------+-------------+---------------+
| syscall/invalid | mean (ns)    |  (R) 10.58% |     (R) 2.91% |
|                 | p99 (ns)     |  (R) 10.51% |     (R) 4.36% |
|                 | p99.9 (ns)   |  (R) 10.35% |    (R) 21.97% |
+-----------------+--------------+-------------+---------------+

I was surprised to see that the baseline cost on x86 is 10-12% since it is just
using rdtsc. But as I say, I believe the results are accurate.


Changes since v1 (RFC) [2]
==========================

- Introduced patch 2 to make prandom_u32_state() __always_inline (needed since
  its called from noinstr code)
- In patch 3, prng is now per-cpu instead of per-task (per Ard)


[1] https://lore.kernel.org/all/dd8c37bc-795f-4c7a-9086-69e584d8ab24 at arm.com/
[2] https://lore.kernel.org/all/20251127105958.2427758-1-ryan.roberts at arm.com/

Thanks,
Ryan


Ryan Roberts (3):
  randomize_kstack: Maintain kstack_offset per task
  prandom: Convert prandom_u32_state() to __always_inline
  randomize_kstack: Unify random source across arches

 arch/Kconfig                         |  5 +--
 arch/arm64/kernel/syscall.c          | 11 -----
 arch/loongarch/kernel/syscall.c      | 11 -----
 arch/powerpc/kernel/syscall.c        | 12 ------
 arch/riscv/kernel/traps.c            | 12 ------
 arch/s390/include/asm/entry-common.h |  8 ----
 arch/x86/include/asm/entry-common.h  | 12 ------
 include/linux/prandom.h              | 19 ++++++++-
 include/linux/randomize_kstack.h     | 61 ++++++++++++----------------
 init/main.c                          |  2 +-
 kernel/fork.c                        |  1 +
 lib/random32.c                       | 19 ---------
 12 files changed, 49 insertions(+), 124 deletions(-)

--
2.43.0



From ryan.roberts at arm.com  Mon Dec 15 08:35:15 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Mon, 15 Dec 2025 16:35:15 +0000
Subject: [PATCH v2 1/3] randomize_kstack: Maintain kstack_offset per task
In-Reply-To: <20251215163520.1144179-1-ryan.roberts@arm.com>
References: <20251215163520.1144179-1-ryan.roberts@arm.com>
Message-ID: <20251215163520.1144179-2-ryan.roberts@arm.com>

kstack_offset was previously maintained per-cpu, but this caused a
couple of issues. So let's instead make it per-task.

Issue 1: add_random_kstack_offset() and choose_random_kstack_offset()
expected and required to be called with interrupts and preemption
disabled so that it could manipulate per-cpu state. But arm64, loongarch
and risc-v are calling them with interrupts and preemption enabled. I
don't _think_ this causes any functional issues, but it's certainly
unexpected and could lead to manipulating the wrong cpu's state, which
could cause a minor performance degradation due to bouncing the cache
lines. By maintaining the state per-task those functions can safely be
called in preemptible context.

Issue 2: add_random_kstack_offset() is called before executing the
syscall and expands the stack using a previously chosen rnadom offset.
choose_random_kstack_offset() is called after executing the syscall and
chooses and stores a new random offset for the next syscall. With
per-cpu storage for this offset, an attacker could force cpu migration
during the execution of the syscall and prevent the offset from being
updated for the original cpu such that it is predictable for the next
syscall on that cpu. By maintaining the state per-task, this problem
goes away because the per-task random offset is updated after the
syscall regardless of which cpu it is executing on.

Fixes: 39218ff4c625 ("stack: Optionally randomize kernel stack offset each syscall")
Closes: https://lore.kernel.org/all/dd8c37bc-795f-4c7a-9086-69e584d8ab24 at arm.com/
Cc: stable at vger.kernel.org
Signed-off-by: Ryan Roberts <ryan.roberts at arm.com>
---
 include/linux/randomize_kstack.h | 26 +++++++++++++++-----------
 include/linux/sched.h            |  4 ++++
 init/main.c                      |  1 -
 kernel/fork.c                    |  2 ++
 4 files changed, 21 insertions(+), 12 deletions(-)

diff --git a/include/linux/randomize_kstack.h b/include/linux/randomize_kstack.h
index 1d982dbdd0d0..5d3916ca747c 100644
--- a/include/linux/randomize_kstack.h
+++ b/include/linux/randomize_kstack.h
@@ -9,7 +9,6 @@
 
 DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
 			 randomize_kstack_offset);
-DECLARE_PER_CPU(u32, kstack_offset);
 
 /*
  * Do not use this anywhere else in the kernel. This is used here because
@@ -50,15 +49,14 @@ DECLARE_PER_CPU(u32, kstack_offset);
  * add_random_kstack_offset - Increase stack utilization by previously
  *			      chosen random offset
  *
- * This should be used in the syscall entry path when interrupts and
- * preempt are disabled, and after user registers have been stored to
- * the stack. For testing the resulting entropy, please see:
- * tools/testing/selftests/lkdtm/stack-entropy.sh
+ * This should be used in the syscall entry path after user registers have been
+ * stored to the stack. Preemption may be enabled. For testing the resulting
+ * entropy, please see: tools/testing/selftests/lkdtm/stack-entropy.sh
  */
 #define add_random_kstack_offset() do {					\
 	if (static_branch_maybe(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,	\
 				&randomize_kstack_offset)) {		\
-		u32 offset = raw_cpu_read(kstack_offset);		\
+		u32 offset = current->kstack_offset;			\
 		u8 *ptr = __kstack_alloca(KSTACK_OFFSET_MAX(offset));	\
 		/* Keep allocation even after "ptr" loses scope. */	\
 		asm volatile("" :: "r"(ptr) : "memory");		\
@@ -69,9 +67,9 @@ DECLARE_PER_CPU(u32, kstack_offset);
  * choose_random_kstack_offset - Choose the random offset for the next
  *				 add_random_kstack_offset()
  *
- * This should only be used during syscall exit when interrupts and
- * preempt are disabled. This position in the syscall flow is done to
- * frustrate attacks from userspace attempting to learn the next offset:
+ * This should only be used during syscall exit. Preemption may be enabled. This
+ * position in the syscall flow is done to frustrate attacks from userspace
+ * attempting to learn the next offset:
  * - Maximize the timing uncertainty visible from userspace: if the
  *   offset is chosen at syscall entry, userspace has much more control
  *   over the timing between choosing offsets. "How long will we be in
@@ -85,14 +83,20 @@ DECLARE_PER_CPU(u32, kstack_offset);
 #define choose_random_kstack_offset(rand) do {				\
 	if (static_branch_maybe(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,	\
 				&randomize_kstack_offset)) {		\
-		u32 offset = raw_cpu_read(kstack_offset);		\
+		u32 offset = current->kstack_offset;			\
 		offset = ror32(offset, 5) ^ (rand);			\
-		raw_cpu_write(kstack_offset, offset);			\
+		current->kstack_offset = offset;			\
 	}								\
 } while (0)
+
+static inline void random_kstack_task_init(struct task_struct *tsk)
+{
+	tsk->kstack_offset = 0;
+}
 #else /* CONFIG_RANDOMIZE_KSTACK_OFFSET */
 #define add_random_kstack_offset()		do { } while (0)
 #define choose_random_kstack_offset(rand)	do { } while (0)
+#define random_kstack_task_init(tsk)		do { } while (0)
 #endif /* CONFIG_RANDOMIZE_KSTACK_OFFSET */
 
 #endif
diff --git a/include/linux/sched.h b/include/linux/sched.h
index d395f2810fac..9e0080ed1484 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1591,6 +1591,10 @@ struct task_struct {
 	unsigned long			prev_lowest_stack;
 #endif
 
+#ifdef CONFIG_RANDOMIZE_KSTACK_OFFSET
+	u32				kstack_offset;
+#endif
+
 #ifdef CONFIG_X86_MCE
 	void __user			*mce_vaddr;
 	__u64				mce_kflags;
diff --git a/init/main.c b/init/main.c
index b84818ad9685..27fcbbde933e 100644
--- a/init/main.c
+++ b/init/main.c
@@ -830,7 +830,6 @@ static inline void initcall_debug_enable(void)
 #ifdef CONFIG_RANDOMIZE_KSTACK_OFFSET
 DEFINE_STATIC_KEY_MAYBE_RO(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
 			   randomize_kstack_offset);
-DEFINE_PER_CPU(u32, kstack_offset);
 
 static int __init early_randomize_kstack_offset(char *buf)
 {
diff --git a/kernel/fork.c b/kernel/fork.c
index b1f3915d5f8e..b061e1edbc43 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -95,6 +95,7 @@
 #include <linux/thread_info.h>
 #include <linux/kstack_erase.h>
 #include <linux/kasan.h>
+#include <linux/randomize_kstack.h>
 #include <linux/scs.h>
 #include <linux/io_uring.h>
 #include <linux/bpf.h>
@@ -2231,6 +2232,7 @@ __latent_entropy struct task_struct *copy_process(
 	if (retval)
 		goto bad_fork_cleanup_io;
 
+	random_kstack_task_init(p);
 	stackleak_task_init(p);
 
 	if (pid != &init_struct_pid) {
-- 
2.43.0



From ryan.roberts at arm.com  Mon Dec 15 08:35:16 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Mon, 15 Dec 2025 16:35:16 +0000
Subject: [PATCH v2 2/3] prandom: Convert prandom_u32_state() to __always_inline
In-Reply-To: <20251215163520.1144179-1-ryan.roberts@arm.com>
References: <20251215163520.1144179-1-ryan.roberts@arm.com>
Message-ID: <20251215163520.1144179-3-ryan.roberts@arm.com>

We will shortly use prandom_u32_state() to implement kstack offset
randomization and some arches need to call it from non-instrumentable
context. Given the function is just a handful of operations and doesn't
call out to any other functions, let's take the easy path and make it
__always_inline.

Signed-off-by: Ryan Roberts <ryan.roberts at arm.com>
---
 include/linux/prandom.h | 19 ++++++++++++++++++-
 lib/random32.c          | 19 -------------------
 2 files changed, 18 insertions(+), 20 deletions(-)

diff --git a/include/linux/prandom.h b/include/linux/prandom.h
index ff7dcc3fa105..e797b3709f5c 100644
--- a/include/linux/prandom.h
+++ b/include/linux/prandom.h
@@ -17,7 +17,24 @@ struct rnd_state {
 	__u32 s1, s2, s3, s4;
 };
 
-u32 prandom_u32_state(struct rnd_state *state);
+/**
+ * prandom_u32_state - seeded pseudo-random number generator.
+ * @state: pointer to state structure holding seeded state.
+ *
+ * This is used for pseudo-randomness with no outside seeding.
+ * For more random results, use get_random_u32().
+ */
+static __always_inline u32 prandom_u32_state(struct rnd_state *state)
+{
+#define TAUSWORTHE(s, a, b, c, d) ((s & c) << d) ^ (((s << a) ^ s) >> b)
+	state->s1 = TAUSWORTHE(state->s1,  6U, 13U, 4294967294U, 18U);
+	state->s2 = TAUSWORTHE(state->s2,  2U, 27U, 4294967288U,  2U);
+	state->s3 = TAUSWORTHE(state->s3, 13U, 21U, 4294967280U,  7U);
+	state->s4 = TAUSWORTHE(state->s4,  3U, 12U, 4294967168U, 13U);
+
+	return (state->s1 ^ state->s2 ^ state->s3 ^ state->s4);
+}
+
 void prandom_bytes_state(struct rnd_state *state, void *buf, size_t nbytes);
 void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state);
 
diff --git a/lib/random32.c b/lib/random32.c
index 24e7acd9343f..d57baf489d4a 100644
--- a/lib/random32.c
+++ b/lib/random32.c
@@ -42,25 +42,6 @@
 #include <linux/slab.h>
 #include <linux/unaligned.h>
 
-/**
- *	prandom_u32_state - seeded pseudo-random number generator.
- *	@state: pointer to state structure holding seeded state.
- *
- *	This is used for pseudo-randomness with no outside seeding.
- *	For more random results, use get_random_u32().
- */
-u32 prandom_u32_state(struct rnd_state *state)
-{
-#define TAUSWORTHE(s, a, b, c, d) ((s & c) << d) ^ (((s << a) ^ s) >> b)
-	state->s1 = TAUSWORTHE(state->s1,  6U, 13U, 4294967294U, 18U);
-	state->s2 = TAUSWORTHE(state->s2,  2U, 27U, 4294967288U,  2U);
-	state->s3 = TAUSWORTHE(state->s3, 13U, 21U, 4294967280U,  7U);
-	state->s4 = TAUSWORTHE(state->s4,  3U, 12U, 4294967168U, 13U);
-
-	return (state->s1 ^ state->s2 ^ state->s3 ^ state->s4);
-}
-EXPORT_SYMBOL(prandom_u32_state);
-
 /**
  *	prandom_bytes_state - get the requested number of pseudo-random bytes
  *
-- 
2.43.0



From anshuld at ti.com  Mon Dec 15 08:35:39 2025
From: anshuld at ti.com (Anshul Dalal)
Date: Mon, 15 Dec 2025 22:05:39 +0530
Subject: [PATCH v5] dt-bindings: arm: keystone: add boot_* mboxes to
 ti,sci
In-Reply-To: <20251215135708.ij5e7jr3binzmlbf@panda>
References: <20251215-k3_syscon_add_boot_mailboxes-v5-1-5a8fe567fd31@ti.com>
 <20251215135708.ij5e7jr3binzmlbf@panda>
Message-ID: <DEYXPZH7UWOY.18YAJY8IA1M0Z@ti.com>


> On 11:38-20251215, Anshul Dalal wrote:
>> The bootloader on K3 devices makes use of mailboxes as per the ROM spec
>> which might be different than one's available to the kernel (firmware
>> spec).
>> 
>> Therefore, this patch adds the missing mailbox entries to the DT binding
>> if the matching compatible is ti,am654-sci to represent the mailboxes
>> exposed by the hardware during boot for the purpose of loading the
>> firmware. The newly added mboxes are made optional by keeping minItems
>> as 2 to remain compliant with existing device-trees.
>> 
>> Signed-off-by: Anshul Dalal <anshuld at ti.com>
>> ---
>> Changes in v5:
>> - Added commit description for the optional mailboxes
>> - Link to v4: https://lore.kernel.org/r/20251205-k3_syscon_add_boot_mailboxes-v4-1-8e216fb88941 at ti.com
>> 
>> Changes in v4:
>> - Make new boot_* mboxes conditional on ti,am654-sci compatible
>> - Link to v3: https://lore.kernel.org/r/20251112-k3_syscon_add_boot_mailboxes-v3-1-66155a4236dc at ti.com
>> 
>> Changes in v3:
>> - Drop [1/2] of the last patch series
>> - Update existing example with boot_* mailboxes instead of adding a new one
>> - Link to v2: https://lore.kernel.org/r/20251112-k3_syscon_add_boot_mailboxes-v2-0-aebc1e47b391 at ti.com
>> 
>> Changes in v2:
>> - Remove maxItems entry
>> - Remove RFC tag from patch (added by mistake in v1)
>> - Document the new mailboxes in mboxes instead of mbox-names
>> - Provide example with all the mailboxes set
>> - Update commit title to have "ti,sci"
>> - Split into two patches
>> - Link to v1: https://lore.kernel.org/r/20251111-k3_syscon_add_boot_mailboxes-v1-1-529a27f21076 at ti.com
>> ---
>>  .../devicetree/bindings/arm/keystone/ti,sci.yaml   | 50 +++++++++++++++++++---
>>  1 file changed, 43 insertions(+), 7 deletions(-)
>> 
>> diff --git a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
>> index 25a2b42105e5..d9eb2a81e539 100644
>> --- a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
>> +++ b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
>> @@ -51,15 +51,15 @@ properties:
>>      minItems: 1
>>  
>>    mbox-names:
>> +    minItems: 2
>> +    maxItems: 6
>>      description: |
>>        Specifies the mailboxes used to communicate with TI-SCI Controller
>>        made available from TI-SCI controller.
>> -    items:
>> -      - const: rx
>> -      - const: tx
>>  
>>    mboxes:
>>      minItems: 2
>> +    maxItems: 6
>>  
>>    ti,host-id:
>>      $ref: /schemas/types.yaml#/definitions/uint32
>> @@ -79,6 +79,42 @@ properties:
>>      type: object
>>      $ref: /schemas/reset/ti,sci-reset.yaml#
>>  
>> +if:
>> +  properties:
>> +    compatible:
>> +      contains:
>> +        const: ti,am654-sci
>> +then:
>> +  properties:
>> +    mbox-names:
>> +      minItems: 2
>> +      items:
>> +        - const: rx
>> +        - const: tx
>> +        - const: notify
>> +        - const: boot_rx
>> +        - const: boot_tx
>> +        - const: boot_notify
>> +    mboxes:
>> +      minItems: 2
>> +      items:
>> +        - description: RX thread
>> +        - description: TX thread
>> +        - description: Notify thread
>> +        - description: boot stage RX thread
>> +        - description: boot stage TX thread
>> +        - description: boot stage Notify thread
>> +else:
>> +  properties:
>> +    mbox-names:
>> +      items:
>> +        - const: rx
>> +        - const: tx
>> +    mboxes:
>> +      items:
>> +        - description: RX thread
>> +        - description: TX thread
>> +
>>  required:
>>    - compatible
>>    - mbox-names
>> @@ -99,11 +135,11 @@ examples:
>>  
>>    - |
>>      dmsc: system-controller at 44083000 {
>> -      compatible = "ti,k2g-sci";
>> +      compatible = "ti,am654-sci";
>>        ti,host-id = <12>;
>> -      mbox-names = "rx", "tx";
>> -      mboxes = <&secure_proxy_main 11>,
>> -               <&secure_proxy_main 13>;
>> +      mbox-names = "rx", "tx", "notify", "boot_rx", "boot_tx";
>> +      mboxes= <&secure_proxy_mcu 6>, <&secure_proxy_mcu 8>,
>> +        <&secure_proxy_mcu 5>, <&secure_proxy_mcu 5>, <&secure_proxy_mcu 4>;
>>        reg-names = "debug_messages";
>>        reg = <0x44083000 0x1000>;
>
> Please add a different example for am654, i want to make sure k2g still
> continues to be checked.
>
> That said, AM62 series of devices do not use notification pipe for
> standard communication. So, the schema will break for those.
>
> in summary:
> k2g: rx, tx
> am654, j721e, j721s2, j7200, j784s4, .. : rx, tx, notify, boot_rx,
> boot_tx, boot_notify
> am625, am62p ..: rx, tx, boot_rx, boot_tx, boot_notify
>
> we will need three examples, and will need to add am62x series as one
> additional compatible.
>
> Though we could play a trick by reordering as follows to handle superset
> of am62 and am65 series as follows, but I do prefer explicitly handling
> them:
>
>    - const: rx
>    - const: tx
>    - const: boot_rx
>    - const: boot_tx
>    - const: notify
>    - const: boot_notify

I'm in favour of adding the new compatible for the AM62 devices and
handling the mboxes properly, let's fix it properly this time :)

Will post a v6 shortly,
~ Anshul



From ryan.roberts at arm.com  Mon Dec 15 08:35:17 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Mon, 15 Dec 2025 16:35:17 +0000
Subject: [PATCH v2 3/3] randomize_kstack: Unify random source across arches
In-Reply-To: <20251215163520.1144179-1-ryan.roberts@arm.com>
References: <20251215163520.1144179-1-ryan.roberts@arm.com>
Message-ID: <20251215163520.1144179-4-ryan.roberts@arm.com>

Previously different architectures were using random sources of
differing strength and cost to decide the random kstack offset. A number
of architectures (loongarch, powerpc, s390, x86) were using their
timestamp counter, at whatever the frequency happened to be. Other
arches (arm64, riscv) were using entropy from the crng via
get_random_u16().

There have been concerns that in some cases the timestamp counters may
be too weak, because they can be easily guessed or influenced by user
space. And get_random_u16() has been shown to be too costly for the
level of protection kstack offset randomization provides.

So let's use a common, architecture-agnostic source of entropy; a
per-cpu prng, seeded at boot-time from the crng. This has a few
benefits:

  - We can remove choose_random_kstack_offset(); That was only there to
    try to make the timestamp counter value a bit harder to influence
    from user space.

  - The architecture code is simplified. All it has to do now is call
    add_random_kstack_offset() in the syscall path.

  - The strength of the randomness can be reasoned about independently
    of the architecture.

  - Arches previously using get_random_u16() now have much faster
    syscall paths, see below results.

There have been some claims that a prng may be less strong than the
timestamp counter if not regularly reseeded. But the prng has a period
of about 2^113. So as long as the prng state remains secret, it should
not be possible to guess. If the prng state can be accessed, we have
bigger problems.

Additionally, we are only consuming 6 bits to randomize the stack, so
there are only 64 possible random offsets. I assert that it would be
trivial for an attacker to brute force by repeating their attack and
waiting for the random stack offset to be the desired one. The prng
approach seems entirely proportional to this level of protection.

Performance data are provided below. The baseline is v6.18 with rndstack
on for each respective arch. (I)/(R) indicate statistically significant
improvement/regression. arm64 platform is AWS Graviton3 (m7g.metal).
x86_64 platform is AWS Sapphire Rapids (m7i.24xlarge):

+-----------------+--------------+---------------+---------------+
| Benchmark       | Result Class | per-task-prng | per-task-prng |
|                 |              | arm64 (metal) |   x86_64 (VM) |
+=================+==============+===============+===============+
| syscall/getpid  | mean (ns)    |    (I) -9.50% |   (I) -17.65% |
|                 | p99 (ns)     |   (I) -59.24% |   (I) -24.41% |
|                 | p99.9 (ns)   |   (I) -59.52% |   (I) -28.52% |
+-----------------+--------------+---------------+---------------+
| syscall/getppid | mean (ns)    |    (I) -9.52% |   (I) -19.24% |
|                 | p99 (ns)     |   (I) -59.25% |   (I) -25.03% |
|                 | p99.9 (ns)   |   (I) -59.50% |   (I) -28.17% |
+-----------------+--------------+---------------+---------------+
| syscall/invalid | mean (ns)    |   (I) -10.31% |   (I) -18.56% |
|                 | p99 (ns)     |   (I) -60.79% |   (I) -20.06% |
|                 | p99.9 (ns)   |   (I) -61.04% |   (I) -25.04% |
+-----------------+--------------+---------------+---------------+

I tested an earlier version of this change on x86 bare metal and it
showed a smaller but still significant improvement. The bare metal
system wasn't available this time around so testing was done in a VM
instance. I'm guessing the cost of rdtsc is higher for VMs.

Signed-off-by: Ryan Roberts <ryan.roberts at arm.com>
---
 arch/Kconfig                         |  5 +--
 arch/arm64/kernel/syscall.c          | 11 ------
 arch/loongarch/kernel/syscall.c      | 11 ------
 arch/powerpc/kernel/syscall.c        | 12 ------
 arch/riscv/kernel/traps.c            | 12 ------
 arch/s390/include/asm/entry-common.h |  8 ----
 arch/x86/include/asm/entry-common.h  | 12 ------
 include/linux/randomize_kstack.h     | 55 +++++++++++-----------------
 include/linux/sched.h                |  4 --
 init/main.c                          |  1 +
 kernel/fork.c                        |  1 -
 11 files changed, 25 insertions(+), 107 deletions(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index 31220f512b16..8591fe7b4ac1 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -1516,9 +1516,8 @@ config HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET
 	def_bool n
 	help
 	  An arch should select this symbol if it can support kernel stack
-	  offset randomization with calls to add_random_kstack_offset()
-	  during syscall entry and choose_random_kstack_offset() during
-	  syscall exit. Careful removal of -fstack-protector-strong and
+	  offset randomization with a call to add_random_kstack_offset()
+	  during syscall entry. Careful removal of -fstack-protector-strong and
 	  -fstack-protector should also be applied to the entry code and
 	  closely examined, as the artificial stack bump looks like an array
 	  to the compiler, so it will attempt to add canary checks regardless
diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index c062badd1a56..358ddfbf1401 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -52,17 +52,6 @@ static void invoke_syscall(struct pt_regs *regs, unsigned int scno,
 	}
 
 	syscall_set_return_value(current, regs, 0, ret);
-
-	/*
-	 * This value will get limited by KSTACK_OFFSET_MAX(), which is 10
-	 * bits. The actual entropy will be further reduced by the compiler
-	 * when applying stack alignment constraints: the AAPCS mandates a
-	 * 16-byte aligned SP at function boundaries, which will remove the
-	 * 4 low bits from any entropy chosen here.
-	 *
-	 * The resulting 6 bits of entropy is seen in SP[9:4].
-	 */
-	choose_random_kstack_offset(get_random_u16());
 }
 
 static inline bool has_syscall_work(unsigned long flags)
diff --git a/arch/loongarch/kernel/syscall.c b/arch/loongarch/kernel/syscall.c
index 1249d82c1cd0..85da7e050d97 100644
--- a/arch/loongarch/kernel/syscall.c
+++ b/arch/loongarch/kernel/syscall.c
@@ -79,16 +79,5 @@ void noinstr __no_stack_protector do_syscall(struct pt_regs *regs)
 					   regs->regs[7], regs->regs[8], regs->regs[9]);
 	}
 
-	/*
-	 * This value will get limited by KSTACK_OFFSET_MAX(), which is 10
-	 * bits. The actual entropy will be further reduced by the compiler
-	 * when applying stack alignment constraints: 16-bytes (i.e. 4-bits)
-	 * aligned, which will remove the 4 low bits from any entropy chosen
-	 * here.
-	 *
-	 * The resulting 6 bits of entropy is seen in SP[9:4].
-	 */
-	choose_random_kstack_offset(get_cycles());
-
 	syscall_exit_to_user_mode(regs);
 }
diff --git a/arch/powerpc/kernel/syscall.c b/arch/powerpc/kernel/syscall.c
index be159ad4b77b..b3d8b0f9823b 100644
--- a/arch/powerpc/kernel/syscall.c
+++ b/arch/powerpc/kernel/syscall.c
@@ -173,17 +173,5 @@ notrace long system_call_exception(struct pt_regs *regs, unsigned long r0)
 	}
 #endif
 
-	/*
-	 * Ultimately, this value will get limited by KSTACK_OFFSET_MAX(),
-	 * so the maximum stack offset is 1k bytes (10 bits).
-	 *
-	 * The actual entropy will be further reduced by the compiler when
-	 * applying stack alignment constraints: the powerpc architecture
-	 * may have two kinds of stack alignment (16-bytes and 8-bytes).
-	 *
-	 * So the resulting 6 or 7 bits of entropy is seen in SP[9:4] or SP[9:3].
-	 */
-	choose_random_kstack_offset(mftb());
-
 	return ret;
 }
diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c
index 80230de167de..79b285bdfd1a 100644
--- a/arch/riscv/kernel/traps.c
+++ b/arch/riscv/kernel/traps.c
@@ -342,18 +342,6 @@ void do_trap_ecall_u(struct pt_regs *regs)
 		if (syscall >= 0 && syscall < NR_syscalls)
 			syscall_handler(regs, syscall);
 
-		/*
-		 * Ultimately, this value will get limited by KSTACK_OFFSET_MAX(),
-		 * so the maximum stack offset is 1k bytes (10 bits).
-		 *
-		 * The actual entropy will be further reduced by the compiler when
-		 * applying stack alignment constraints: 16-byte (i.e. 4-bit) aligned
-		 * for RV32I or RV64I.
-		 *
-		 * The resulting 6 bits of entropy is seen in SP[9:4].
-		 */
-		choose_random_kstack_offset(get_random_u16());
-
 		syscall_exit_to_user_mode(regs);
 	} else {
 		irqentry_state_t state = irqentry_nmi_enter(regs);
diff --git a/arch/s390/include/asm/entry-common.h b/arch/s390/include/asm/entry-common.h
index 979af986a8fe..35450a485323 100644
--- a/arch/s390/include/asm/entry-common.h
+++ b/arch/s390/include/asm/entry-common.h
@@ -51,14 +51,6 @@ static __always_inline void arch_exit_to_user_mode(void)
 
 #define arch_exit_to_user_mode arch_exit_to_user_mode
 
-static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs,
-						  unsigned long ti_work)
-{
-	choose_random_kstack_offset(get_tod_clock_fast());
-}
-
-#define arch_exit_to_user_mode_prepare arch_exit_to_user_mode_prepare
-
 static __always_inline bool arch_in_rcu_eqs(void)
 {
 	if (IS_ENABLED(CONFIG_KVM))
diff --git a/arch/x86/include/asm/entry-common.h b/arch/x86/include/asm/entry-common.h
index ce3eb6d5fdf9..7535131c711b 100644
--- a/arch/x86/include/asm/entry-common.h
+++ b/arch/x86/include/asm/entry-common.h
@@ -82,18 +82,6 @@ static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs,
 	current_thread_info()->status &= ~(TS_COMPAT | TS_I386_REGS_POKED);
 #endif
 
-	/*
-	 * This value will get limited by KSTACK_OFFSET_MAX(), which is 10
-	 * bits. The actual entropy will be further reduced by the compiler
-	 * when applying stack alignment constraints (see cc_stack_align4/8 in
-	 * arch/x86/Makefile), which will remove the 3 (x86_64) or 2 (ia32)
-	 * low bits from any entropy chosen here.
-	 *
-	 * Therefore, final stack offset entropy will be 7 (x86_64) or
-	 * 8 (ia32) bits.
-	 */
-	choose_random_kstack_offset(rdtsc());
-
 	/* Avoid unnecessary reads of 'x86_ibpb_exit_to_user' */
 	if (cpu_feature_enabled(X86_FEATURE_IBPB_EXIT_TO_USER) &&
 	    this_cpu_read(x86_ibpb_exit_to_user)) {
diff --git a/include/linux/randomize_kstack.h b/include/linux/randomize_kstack.h
index 5d3916ca747c..92e6363adf25 100644
--- a/include/linux/randomize_kstack.h
+++ b/include/linux/randomize_kstack.h
@@ -6,6 +6,7 @@
 #include <linux/kernel.h>
 #include <linux/jump_label.h>
 #include <linux/percpu-defs.h>
+#include <linux/prandom.h>
 
 DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
 			 randomize_kstack_offset);
@@ -45,9 +46,22 @@ DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
 #define KSTACK_OFFSET_MAX(x)	((x) & 0b1111111100)
 #endif
 
+DECLARE_PER_CPU(struct rnd_state, kstack_rnd_state);
+
+static __always_inline u32 get_kstack_offset(void)
+{
+	struct rnd_state *state;
+	u32 rnd;
+
+	state = &get_cpu_var(kstack_rnd_state);
+	rnd = prandom_u32_state(state);
+	put_cpu_var(kstack_rnd_state);
+
+	return rnd;
+}
+
 /**
- * add_random_kstack_offset - Increase stack utilization by previously
- *			      chosen random offset
+ * add_random_kstack_offset - Increase stack utilization by a random offset.
  *
  * This should be used in the syscall entry path after user registers have been
  * stored to the stack. Preemption may be enabled. For testing the resulting
@@ -56,47 +70,22 @@ DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
 #define add_random_kstack_offset() do {					\
 	if (static_branch_maybe(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,	\
 				&randomize_kstack_offset)) {		\
-		u32 offset = current->kstack_offset;			\
+		u32 offset = get_kstack_offset();			\
 		u8 *ptr = __kstack_alloca(KSTACK_OFFSET_MAX(offset));	\
 		/* Keep allocation even after "ptr" loses scope. */	\
 		asm volatile("" :: "r"(ptr) : "memory");		\
 	}								\
 } while (0)
 
-/**
- * choose_random_kstack_offset - Choose the random offset for the next
- *				 add_random_kstack_offset()
- *
- * This should only be used during syscall exit. Preemption may be enabled. This
- * position in the syscall flow is done to frustrate attacks from userspace
- * attempting to learn the next offset:
- * - Maximize the timing uncertainty visible from userspace: if the
- *   offset is chosen at syscall entry, userspace has much more control
- *   over the timing between choosing offsets. "How long will we be in
- *   kernel mode?" tends to be more difficult to predict than "how long
- *   will we be in user mode?"
- * - Reduce the lifetime of the new offset sitting in memory during
- *   kernel mode execution. Exposure of "thread-local" memory content
- *   (e.g. current, percpu, etc) tends to be easier than arbitrary
- *   location memory exposure.
- */
-#define choose_random_kstack_offset(rand) do {				\
-	if (static_branch_maybe(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,	\
-				&randomize_kstack_offset)) {		\
-		u32 offset = current->kstack_offset;			\
-		offset = ror32(offset, 5) ^ (rand);			\
-		current->kstack_offset = offset;			\
-	}								\
-} while (0)
-
-static inline void random_kstack_task_init(struct task_struct *tsk)
+static int random_kstack_init(void)
 {
-	tsk->kstack_offset = 0;
+	prandom_seed_full_state(&kstack_rnd_state);
+	return 0;
 }
+
+late_initcall(random_kstack_init);
 #else /* CONFIG_RANDOMIZE_KSTACK_OFFSET */
 #define add_random_kstack_offset()		do { } while (0)
-#define choose_random_kstack_offset(rand)	do { } while (0)
-#define random_kstack_task_init(tsk)		do { } while (0)
 #endif /* CONFIG_RANDOMIZE_KSTACK_OFFSET */
 
 #endif
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 9e0080ed1484..d395f2810fac 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1591,10 +1591,6 @@ struct task_struct {
 	unsigned long			prev_lowest_stack;
 #endif
 
-#ifdef CONFIG_RANDOMIZE_KSTACK_OFFSET
-	u32				kstack_offset;
-#endif
-
 #ifdef CONFIG_X86_MCE
 	void __user			*mce_vaddr;
 	__u64				mce_kflags;
diff --git a/init/main.c b/init/main.c
index 27fcbbde933e..ad7674af6ab1 100644
--- a/init/main.c
+++ b/init/main.c
@@ -830,6 +830,7 @@ static inline void initcall_debug_enable(void)
 #ifdef CONFIG_RANDOMIZE_KSTACK_OFFSET
 DEFINE_STATIC_KEY_MAYBE_RO(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
 			   randomize_kstack_offset);
+DEFINE_PER_CPU(struct rnd_state, kstack_rnd_state);
 
 static int __init early_randomize_kstack_offset(char *buf)
 {
diff --git a/kernel/fork.c b/kernel/fork.c
index b061e1edbc43..68d9766288fd 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -2232,7 +2232,6 @@ __latent_entropy struct task_struct *copy_process(
 	if (retval)
 		goto bad_fork_cleanup_io;
 
-	random_kstack_task_init(p);
 	stackleak_task_init(p);
 
 	if (pid != &init_struct_pid) {
-- 
2.43.0



From foss+kernel at 0leil.net  Mon Dec 15 08:45:56 2025
From: foss+kernel at 0leil.net (Quentin Schulz)
Date: Mon, 15 Dec 2025 17:45:56 +0100
Subject: [PATCH] arm64: dts: rockchip: fix unit-address for RK3588 NPU's
 core1 and core2's IOMMU
Message-ID: <20251215-npu-dt-node-address-v1-1-840093e8a2bf@cherry.de>

From: Quentin Schulz <quentin.schulz at cherry.de>

The Device Tree specification specifies[1] that

"""
Each node in the devicetree is named according to the following
convention:
	node-name at unit-address
[...]
The unit-address must match the first address specified in the reg
property of the node.
"""

The first address in the reg property is fdaXa000 and not fdaX9000. This
is likely a copy-paste error as the IOMMU for core0 has two entries in
the reg property, the first one being fdab9000 and the second fdaba000.

Let's fix this oversight to match what the spec is expecting.

[1] https://github.com/devicetree-org/devicetree-specification/releases/download/v0.4/devicetree-specification-v0.4.pdf 2.2.1 Node Names

Fixes: a31dfc060a74 ("arm64: dts: rockchip: Add nodes for NPU and its MMU to rk3588-base")
Cc: stable at vger.kernel.org
Signed-off-by: Quentin Schulz <quentin.schulz at cherry.de>
---
 arch/arm64/boot/dts/rockchip/rk3588-base.dtsi | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
index 2a79217930206..7ab12d1054a73 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
@@ -1200,7 +1200,7 @@ rknn_core_1: npu at fdac0000 {
 		status = "disabled";
 	};
 
-	rknn_mmu_1: iommu at fdac9000 {
+	rknn_mmu_1: iommu at fdaca000 {
 		compatible = "rockchip,rk3588-iommu", "rockchip,rk3568-iommu";
 		reg = <0x0 0xfdaca000 0x0 0x100>;
 		interrupts = <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH 0>;
@@ -1230,7 +1230,7 @@ rknn_core_2: npu at fdad0000 {
 		status = "disabled";
 	};
 
-	rknn_mmu_2: iommu at fdad9000 {
+	rknn_mmu_2: iommu at fdada000 {
 		compatible = "rockchip,rk3588-iommu", "rockchip,rk3568-iommu";
 		reg = <0x0 0xfdada000 0x0 0x100>;
 		interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH 0>;

---
base-commit: a619746d25c8adafe294777cc98c47a09759b3ed
change-id: 20251215-npu-dt-node-address-7bfeab42dae9

Best regards,
-- 
Quentin Schulz <quentin.schulz at cherry.de>



From m.felsch at pengutronix.de  Mon Dec 15 08:47:54 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Mon, 15 Dec 2025 17:47:54 +0100
Subject: [PATCH v7 2/3] drm/bridge: imx: Add i.MX93 parallel display
 format configuration support
In-Reply-To: <f53be351-e059-4a71-bbbd-7a893e954169@nxp.com>
References: <20251202-v6-18-topic-imx93-parallel-display-v7-0-2cce31d64608@pengutronix.de>
 <20251202-v6-18-topic-imx93-parallel-display-v7-2-2cce31d64608@pengutronix.de>
 <f53be351-e059-4a71-bbbd-7a893e954169@nxp.com>
Message-ID: <20251215164754.5amfk7hasaol7tdt@pengutronix.de>

Hi,

On 25-12-08, Liu Ying wrote:
> Hi Marco,
> 
> On 12/02/2025, Marco Felsch wrote:
> > From: Liu Ying <victor.liu at nxp.com>
> > 
> > NXP i.MX93 mediamix blk-ctrl contains one DISPLAY_MUX register which
> > configures parallel display format by using the "PARALLEL_DISP_FORMAT"
> > field. Add a DRM bridge driver to support the display format configuration.
> > 
> > Signed-off-by: Liu Ying <victor.liu at nxp.com>
> > [m.felsch at pengutronix.de: port to v6.18-rc1]
> > [m.felsch at pengutronix.de: add review feedback (Alexander)]
> > [m.felsch at pengutronix.de: fix to short Kconfig description (checkpath)]
> > [m.felsch at pengutronix.de: use "GPL" instead of "GPL v2" (checkpatch)]
> > [m.felsch at pengutronix.de: make use of reg property]
> > [m.felsch at pengutronix.de: add bus-width support]
> > Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
> > ---
> >  drivers/gpu/drm/bridge/imx/Kconfig      |  11 ++
> >  drivers/gpu/drm/bridge/imx/Makefile     |   1 +
> >  drivers/gpu/drm/bridge/imx/imx93-pdfc.c | 227 ++++++++++++++++++++++++++++++++
> >  3 files changed, 239 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/bridge/imx/Kconfig b/drivers/gpu/drm/bridge/imx/Kconfig
> > index 9a480c6abb856276df9b71d23b39a43b3a9c542d..28fd7a00473a0ec50bf0ffb5d50972abc209ceec 100644
> > --- a/drivers/gpu/drm/bridge/imx/Kconfig
> > +++ b/drivers/gpu/drm/bridge/imx/Kconfig
> > @@ -88,4 +88,15 @@ config DRM_IMX93_MIPI_DSI
> >  	  Choose this to enable MIPI DSI controller found in Freescale i.MX93
> >  	  processor.
> >  
> > +config DRM_IMX93_PARALLEL_DISP_FMT_CONFIG
> > +	tristate "NXP i.MX91/i.MX93 parallel display format configuration"
> > +	depends on OF
> > +	select DRM_KMS_HELPER
> > +	help
> > +	  On i.MX93 and i.MX91 SoCs the parallel display format output is
> > +	  controlled via the MEDIAMIX BLK-CTRL DISPLAY_MUX.
> > +
> > +	  Say 'Y' or 'M' if you use the parallel display output path on a
> > +	  i.MX93 or i.MX91 SoC.
> > +
> >  endif # ARCH_MXC || COMPILE_TEST
> > diff --git a/drivers/gpu/drm/bridge/imx/Makefile b/drivers/gpu/drm/bridge/imx/Makefile
> > index dd5d4858480663bade98bd58039d1cb6f8aa18da..f4ccc5cbef72a576443d5fecf666b76dfba8aa94 100644
> > --- a/drivers/gpu/drm/bridge/imx/Makefile
> > +++ b/drivers/gpu/drm/bridge/imx/Makefile
> > @@ -8,3 +8,4 @@ obj-$(CONFIG_DRM_IMX8QXP_PIXEL_COMBINER) += imx8qxp-pixel-combiner.o
> >  obj-$(CONFIG_DRM_IMX8QXP_PIXEL_LINK) += imx8qxp-pixel-link.o
> >  obj-$(CONFIG_DRM_IMX8QXP_PIXEL_LINK_TO_DPI) += imx8qxp-pxl2dpi.o
> >  obj-$(CONFIG_DRM_IMX93_MIPI_DSI) += imx93-mipi-dsi.o
> > +obj-$(CONFIG_DRM_IMX93_PARALLEL_DISP_FMT_CONFIG) += imx93-pdfc.o
> > diff --git a/drivers/gpu/drm/bridge/imx/imx93-pdfc.c b/drivers/gpu/drm/bridge/imx/imx93-pdfc.c
> > new file mode 100644
> > index 0000000000000000000000000000000000000000..624389def0ac3f24158edc64a8913375a4cc2f12
> > --- /dev/null
> > +++ b/drivers/gpu/drm/bridge/imx/imx93-pdfc.c
> > @@ -0,0 +1,227 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +
> > +/*
> > + * Copyright 2022-2025 NXP
> > + */
> > +
> > +#include <linux/bitfield.h>
> > +#include <linux/bits.h>
> > +#include <linux/media-bus-format.h>
> > +#include <linux/mfd/syscon.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +#include <linux/of_graph.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/regmap.h>
> > +
> > +#include <drm/drm_atomic_state_helper.h>
> > +#include <drm/drm_bridge.h>
> > +#include <drm/drm_print.h>
> 
> Drop this header file if you won't use DRM_DEV_DEBUG_DRIVER() in v5.

Sure.

> > +#define PARALLEL_DISP_FORMAT		GENMASK(10, 8)
> > +#define FORMAT_RGB888_TO_RGB888		FIELD_PREP(PARALLEL_DISP_FORMAT, 0)
> > +#define FORMAT_RGB888_TO_RGB666		FIELD_PREP(PARALLEL_DISP_FORMAT, 1)
> > +#define FORMAT_RGB565_TO_RGB565		FIELD_PREP(PARALLEL_DISP_FORMAT, 2)
> > +
> > +struct imx93_pdfc {
> > +	struct drm_bridge bridge;
> > +	struct drm_bridge *next_bridge;
> > +	struct device *dev;
> > +	struct regmap *regmap;
> > +	u64 disp_mux_reg_off;
> > +	u32 phy_bus_width;
> > +};
> > +
> > +static int
> > +imx93_pdfc_bridge_attach(struct drm_bridge *bridge, struct drm_encoder *encoder,
> > +			 enum drm_bridge_attach_flags flags)
> > +{
> > +	struct imx93_pdfc *pdfc = bridge->driver_private;
> > +
> > +	return drm_bridge_attach(bridge->encoder, pdfc->next_bridge, bridge, flags);
> > +}
> > +
> > +static void imx93_pdfc_bridge_atomic_enable(struct drm_bridge *bridge,
> > +					    struct drm_atomic_state *state)
> > +{
> > +	struct imx93_pdfc *pdfc = bridge->driver_private;
> > +	const struct drm_bridge_state *bridge_state;
> > +	unsigned int mask = PARALLEL_DISP_FORMAT;
> > +	unsigned int val;
> > +
> > +	bridge_state = drm_atomic_get_new_bridge_state(state, bridge);
> > +
> > +	switch (bridge_state->output_bus_cfg.format) {
> > +	case MEDIA_BUS_FMT_RGB888_1X24:
> > +		val = FORMAT_RGB888_TO_RGB888;
> > +		if (pdfc->phy_bus_width == 18) {
> > +			/*
> > +			 * Can be valid if physical bus limitation exist,
> 
> s/exist/exists/

Thanks

> > +			 * therefore use dev_dbg().
> > +			 */
> > +			dev_dbg(pdfc->dev, "Truncate two LSBs from each color\n");
> > +			val = FORMAT_RGB888_TO_RGB666;
> > +		}
> > +		break;
> > +	case MEDIA_BUS_FMT_RGB666_1X18:
> > +		val = FORMAT_RGB888_TO_RGB666;
> > +		break;
> > +	case MEDIA_BUS_FMT_RGB565_1X16:
> > +		val = FORMAT_RGB565_TO_RGB565;
> > +		break;
> > +	}
> > +
> > +	regmap_update_bits(pdfc->regmap, pdfc->disp_mux_reg_off, mask, val);
> > +}
> > +
> > +static const u32 imx93_pdfc_bus_output_fmts[] = {
> > +	MEDIA_BUS_FMT_RGB888_1X24,
> > +	MEDIA_BUS_FMT_RGB666_1X18,
> > +	MEDIA_BUS_FMT_RGB565_1X16,
> > +	MEDIA_BUS_FMT_FIXED
> > +};
> > +
> > +static bool imx93_pdfc_bus_output_fmt_supported(u32 fmt)
> > +{
> > +	int i;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(imx93_pdfc_bus_output_fmts); i++) {
> > +		if (imx93_pdfc_bus_output_fmts[i] == fmt)
> > +			return true;
> > +	}
> > +
> > +	return false;
> > +}
> > +
> > +static u32 *
> > +imx93_pdfc_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
> > +					    struct drm_bridge_state *bridge_state,
> > +					    struct drm_crtc_state *crtc_state,
> > +					    struct drm_connector_state *conn_state,
> > +					    u32 output_fmt,
> > +					    unsigned int *num_input_fmts)
> > +{
> > +	u32 *input_fmts;
> > +
> > +	*num_input_fmts = 0;
> > +
> > +	if (!imx93_pdfc_bus_output_fmt_supported(output_fmt))
> > +		return NULL;
> > +
> > +	input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
> > +	if (!input_fmts)
> > +		return NULL;
> > +
> > +	switch (output_fmt) {
> > +	case MEDIA_BUS_FMT_RGB888_1X24:
> > +	case MEDIA_BUS_FMT_RGB565_1X16:
> > +		input_fmts[0] = output_fmt;
> > +		break;
> > +	case MEDIA_BUS_FMT_RGB666_1X18:
> > +	case MEDIA_BUS_FMT_FIXED:
> > +		input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24;
> > +		break;
> > +	}
> > +
> > +	*num_input_fmts = 1;
> > +
> > +	return input_fmts;
> > +}
> > +
> > +static int imx93_pdfc_bridge_atomic_check(struct drm_bridge *bridge,
> > +					  struct drm_bridge_state *bridge_state,
> > +					  struct drm_crtc_state *crtc_state,
> > +					  struct drm_connector_state *conn_state)
> > +{
> > +	struct imx93_pdfc *pdfc = bridge->driver_private;
> > +
> > +	switch (bridge_state->output_bus_cfg.format) {
> > +	case MEDIA_BUS_FMT_RGB888_1X24:
> > +	case MEDIA_BUS_FMT_RGB666_1X18:
> > +	case MEDIA_BUS_FMT_RGB565_1X16:
> 
> The case MEDIA_BUS_FMT_FIXED is also valid.

Good point, I think we should drop this from the
imx93_pdfc_bus_output_fmts completely since we know that only prallel panels
with an actual format can be attached to this bridge.

> > +		return 0;
> > +	default:
> > +		dev_warn(pdfc->dev, "Unsupported output bus format: 0x%x\n",
> > +			 bridge_state->output_bus_cfg.format);
> > +		return -EINVAL;
> > +	}
> > +}
> > +
> > +static const struct drm_bridge_funcs funcs = {
> > +	.attach			= imx93_pdfc_bridge_attach,
> > +	.atomic_enable		= imx93_pdfc_bridge_atomic_enable,
> > +	.atomic_duplicate_state	= drm_atomic_helper_bridge_duplicate_state,
> > +	.atomic_destroy_state	= drm_atomic_helper_bridge_destroy_state,
> > +	.atomic_get_input_bus_fmts	= imx93_pdfc_bridge_atomic_get_input_bus_fmts,
> > +	.atomic_check		= imx93_pdfc_bridge_atomic_check,
> > +	.atomic_reset		= drm_atomic_helper_bridge_reset,
> > +};
> > +
> > +static int imx93_pdfc_bridge_probe(struct platform_device *pdev)
> > +{
> > +	struct device *dev = &pdev->dev;
> > +	struct imx93_pdfc *pdfc;
> > +	struct device_node *ep;
> > +	int err;
> > +
> > +	pdfc = devm_drm_bridge_alloc(dev, struct imx93_pdfc, bridge, &funcs);
> > +	if (IS_ERR(pdfc))
> > +		return PTR_ERR(pdfc);
> > +
> > +	pdfc->regmap = syscon_node_to_regmap(dev->of_node->parent);
> > +	if (IS_ERR(pdfc->regmap))
> > +		return dev_err_probe(dev, PTR_ERR(pdfc->regmap),
> > +				     "failed to get regmap\n");
> > +
> > +	err = of_property_read_reg(dev->of_node, 0, &pdfc->disp_mux_reg_off, NULL);
> > +	if (err)
> > +		return dev_err_probe(dev, err,
> > +				     "failed to get display-mux reg\n");
> > +
> > +	/* No limits per default */
> > +	pdfc->phy_bus_width = 24;
> > +
> > +	/* Get output ep (port1/endpoint0) */
> > +	ep = of_graph_get_endpoint_by_regs(dev->of_node, 1, 0);
> 
> Nit: DT binding just defines endpoint not endpoint0, so set the reg parameter
> to -1.

Good point, thanks.

> > +	if (ep) {
> > +		err = of_property_read_u32(ep, "bus-width", &pdfc->phy_bus_width);
> > +		of_node_put(ep);
> > +
> > +		/* bus-width is optional but it must have valid data if present */
> > +		if (err && err != -EINVAL)
> > +			return dev_err_probe(dev, err,
> > +					     "failed to query bus-width\n");
> > +	}
> > +
> > +	pdfc->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
> > +	if (IS_ERR(pdfc->next_bridge))
> > +		return dev_err_probe(dev, PTR_ERR(pdfc->next_bridge),
> > +				     "failed to get next bridge\n");
> > +
> > +	pdfc->dev = dev;
> > +	pdfc->bridge.driver_private = pdfc;
> > +	pdfc->bridge.of_node = dev->of_node;
> > +	pdfc->bridge.type = DRM_MODE_CONNECTOR_DPI;
> > +
> > +	return devm_drm_bridge_add(dev, &pdfc->bridge);
> > +}
> > +
> > +static const struct of_device_id imx93_pdfc_dt_ids[] = {
> > +	{ .compatible = "nxp,imx93-pdfc", },
> 
> The cover letter and Kconfig say that both i.MX91 and i.MX93 are supported,
> so need an additional compatible string for i.MX91?

I don't think so, according the imx91_93_common.dtsi, there are a lot
IPs which are shared between the i.MX91 and the i.MX93, even the clock
defines.

Thanks for the review.

Regards,
  Marco


> 
> > +	{ /* sentinel */ }
> > +};
> > +MODULE_DEVICE_TABLE(of, imx93_pdfc_dt_ids);
> > +
> > +static struct platform_driver imx93_pdfc_bridge_driver = {
> > +	.probe	= imx93_pdfc_bridge_probe,
> > +	.driver	= {
> > +		.of_match_table = imx93_pdfc_dt_ids,
> > +		.name = "imx93_pdfc",
> > +	},
> > +};
> > +module_platform_driver(imx93_pdfc_bridge_driver);
> > +
> > +MODULE_DESCRIPTION("NXP i.MX93 parallel display format configuration driver");
> > +MODULE_AUTHOR("Liu Ying <victor.liu at nxp.com>");
> > +MODULE_LICENSE("GPL");
> > 
> 
> 
> -- 
> Regards,
> Liu Ying
> 

-- 
#gernperDu 
#CallMeByMyFirstName

Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | https://www.pengutronix.de/ |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-9    |


From leo.yan at arm.com  Mon Dec 15 08:49:20 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 15 Dec 2025 16:49:20 +0000
Subject: [PATCH] arm64: perf: fix syscalltbl path base
In-Reply-To: <0076b248-9b23-408d-9448-701df3c8d952@app.fastmail.com>
References: <b2651f20-6f3a-49f5-9cd8-3fb028b2cab5@app.fastmail.com>
 <fcefc3c0-541d-40cc-84e3-9c2460308bdb@linaro.org>
 <23c07ac4-ff13-47a5-824a-e7af1d1847a3@app.fastmail.com>
 <bda366b4-fa53-4feb-a7ce-ee47cfc404b5@linaro.org>
 <20251215112818.GB681384@e132581.arm.com>
 <0076b248-9b23-408d-9448-701df3c8d952@app.fastmail.com>
Message-ID: <20251215164920.GD681384@e132581.arm.com>

On Mon, Dec 15, 2025 at 01:22:04PM +0100, Arnd Bergmann wrote:

[...]

> Ah, I see now that arc/hexagon/loongarch/riscv just use an old
> copy of the header based on the and no longer update them. I only
> saw that they have the stub version but hadn't realized that they
> never updated past the point where we started generating the
> ones for the uapi.
> 
> Still, I would suggest using the same method across all architectures:
> either we figure out how to use the generated headers on all of them
> (including x86, which uses yet another method)

Switching to generated unistd.h headers would require removing
tools/include/uapi/asm-generic/unistd.h and generating unistd_64/32.h
on the fly, while still keeping arch's stub headers under
tools/arch/${arch}/include/uapi/asm/.

As discussed in [1], I would prefer to drop these headers, but Ian
noted that this could break builds with older toolchains.  We keep the
tools/ copies of unistd.h because tools need the latest syscall
numbers; relying on outdated toolchain headers can lead to build
failures or incorrect behavior (e.g., perf falling back to predefined
but wrong syscall numbers).

One idea is to install kernel headers first and then build tools, e,g.:

   cd linux
   export CROSS_COMPILE=aarch64-linux-gnu-
   make ARCH=arm64 headers_install O=$OUT
   make ARCH=arm64 O=$OUT -C tools/perf

Generating the headers dynamically would avoid maintaining duplicated
copies under tools/ and no need for periodic syncs.  However, this is a
quite big effort, not just perf, we need to update makefiles to the path
of the installed headers.  I'd like to hear opinions from tools
(perf/bpf/selftest) maintainers before proceeding.

> or we just stick with
> the old asm-generic/unistd.h copy and use that on arm64 as well.

I will proceed this way for now.  From a maintenance view, it is a
pragmatic solution that only requires reverting a few patches and does
not introduce any new code.

Thanks for your suggestion!

Leo

[1] https://lore.kernel.org/linux-perf-users/20251209104926.GS724103 at e132581.arm.com/


From tabba at google.com  Mon Dec 15 08:51:50 2025
From: tabba at google.com (Fuad Tabba)
Date: Mon, 15 Dec 2025 16:51:50 +0000
Subject: [PATCH v2 0/5] KVM: selftests: Alignment fixes and arm64 MMU cleanup
Message-ID: <20251215165155.3451819-1-tabba@google.com>

v2:
- Resend to correct partial To/Cc lists. The previous versions were
  inadvertently sent to disjoint subsets of the maintainers and lists
  (kvmarm vs kvm-riscv). Apologies for the noise and the duplicate
  threads.
- No code changes.

This series tidies up a few things in the KVM selftests. It addresses an
error in memory alignment, hardens the arm64 MMU configuration for
selftests, and fixes minor documentation issues.

First, for arm64, the series explicitly disables translation table walks
for the unused upper virtual address range (TTBR1). Since selftests run
entirely in the lower range (TTBR0), leaving TTBR1 uninitialized but
active could lead to unpredictable behavior if guest code accesses high
addresses. We set EPD1 (and TBI1) to ensure such accesses
deterministically generate translation faults.

Second, the series fixes the `page_align()` implementation in both arm64
and riscv. The previous version incorrectly rounded up already-aligned
addresses to the *next* page, potentially wasting memory or causing
unexpected gaps. After fixing the logic in the arch-specific files, the
function is moved to the common `kvm_util.h` header to eliminate code
duplication.

Finally, a few comments and argument descriptions in `kvm_util` are
updated to match the actual code implementation.

Based on Linux 6.19-rc1.

Cheers,
/fuad

Fuad Tabba (5):
  KVM: arm64: selftests: Disable unused TTBR1_EL1 translations
  KVM: arm64: selftests: Fix incorrect rounding in page_align()
  KVM: riscv: selftests: Fix incorrect rounding in page_align()
  KVM: selftests: Move page_align() to shared header
  KVM: selftests: Fix typos and stale comments in kvm_util

 tools/testing/selftests/kvm/include/arm64/processor.h | 4 ++++
 tools/testing/selftests/kvm/include/kvm_util.h        | 9 +++++++--
 tools/testing/selftests/kvm/lib/arm64/processor.c     | 7 ++-----
 tools/testing/selftests/kvm/lib/kvm_util.c            | 2 +-
 tools/testing/selftests/kvm/lib/riscv/processor.c     | 5 -----
 5 files changed, 14 insertions(+), 13 deletions(-)


base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
-- 
2.52.0.239.gd5f0c6e74e-goog



From tabba at google.com  Mon Dec 15 08:51:52 2025
From: tabba at google.com (Fuad Tabba)
Date: Mon, 15 Dec 2025 16:51:52 +0000
Subject: [PATCH v2 2/5] KVM: arm64: selftests: Fix incorrect rounding in page_align()
In-Reply-To: <20251215165155.3451819-1-tabba@google.com>
References: <20251215165155.3451819-1-tabba@google.com>
Message-ID: <20251215165155.3451819-3-tabba@google.com>

The implementation of `page_align()` in `processor.c` calculates
alignment incorrectly for values that are already aligned. Specifically,
`(v + vm->page_size) & ~(vm->page_size - 1)` aligns to the *next* page
boundary even if `v` is already page-aligned, potentially wasting a page
of memory.

Fix the calculation to use standard alignment logic: `(v + vm->page_size
- 1) & ~(vm->page_size - 1)`.

Fixes: 7a6629ef746d ("kvm: selftests: add virt mem support for aarch64")
Signed-off-by: Fuad Tabba <tabba at google.com>
---
 tools/testing/selftests/kvm/lib/arm64/processor.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/testing/selftests/kvm/lib/arm64/processor.c
index 5b379da8cb90..607a4e462984 100644
--- a/tools/testing/selftests/kvm/lib/arm64/processor.c
+++ b/tools/testing/selftests/kvm/lib/arm64/processor.c
@@ -23,7 +23,7 @@ static vm_vaddr_t exception_handlers;
 
 static uint64_t page_align(struct kvm_vm *vm, uint64_t v)
 {
-	return (v + vm->page_size) & ~(vm->page_size - 1);
+	return (v + vm->page_size - 1) & ~(vm->page_size - 1);
 }
 
 static uint64_t pgd_index(struct kvm_vm *vm, vm_vaddr_t gva)
-- 
2.52.0.239.gd5f0c6e74e-goog



From tabba at google.com  Mon Dec 15 08:51:51 2025
From: tabba at google.com (Fuad Tabba)
Date: Mon, 15 Dec 2025 16:51:51 +0000
Subject: [PATCH v2 1/5] KVM: arm64: selftests: Disable unused TTBR1_EL1 translations
In-Reply-To: <20251215165155.3451819-1-tabba@google.com>
References: <20251215165155.3451819-1-tabba@google.com>
Message-ID: <20251215165155.3451819-2-tabba@google.com>

KVM selftests map all guest code and data into the lower virtual address
range (0x0000...) managed by TTBR0_EL1. The upper range (0xFFFF...)
managed by TTBR1_EL1 is unused and uninitialized.

If a guest accesses the upper range, the MMU attempts a translation
table walk using uninitialized registers, leading to unpredictable
behavior.

Set `TCR_EL1.EPD1` to disable translation table walks for TTBR1_EL1,
ensuring that any access to the upper range generates an immediate
Translation Fault. Additionally, set `TCR_EL1.TBI1` (Top Byte Ignore) to
ensure that tagged pointers in the upper range also deterministically
trigger a Translation Fault via EPD1.

Define `TCR_EPD1_MASK`, `TCR_EPD1_SHIFT`, and `TCR_TBI1` in
`processor.h` to support this configuration. These are based on their
definitions in `arch/arm64/include/asm/pgtable-hwdef.h`.

Suggested-by: Will Deacon <will at kernel.org>
Signed-off-by: Fuad Tabba <tabba at google.com>
---
 tools/testing/selftests/kvm/include/arm64/processor.h | 4 ++++
 tools/testing/selftests/kvm/lib/arm64/processor.c     | 2 ++
 2 files changed, 6 insertions(+)

diff --git a/tools/testing/selftests/kvm/include/arm64/processor.h b/tools/testing/selftests/kvm/include/arm64/processor.h
index ff928716574d..ac97a1c436fc 100644
--- a/tools/testing/selftests/kvm/include/arm64/processor.h
+++ b/tools/testing/selftests/kvm/include/arm64/processor.h
@@ -90,6 +90,9 @@
 #define TCR_TG0_64K		(UL(1) << TCR_TG0_SHIFT)
 #define TCR_TG0_16K		(UL(2) << TCR_TG0_SHIFT)
 
+#define TCR_EPD1_SHIFT		23
+#define TCR_EPD1_MASK		(UL(1) << TCR_EPD1_SHIFT)
+
 #define TCR_IPS_SHIFT		32
 #define TCR_IPS_MASK		(UL(7) << TCR_IPS_SHIFT)
 #define TCR_IPS_52_BITS	(UL(6) << TCR_IPS_SHIFT)
@@ -97,6 +100,7 @@
 #define TCR_IPS_40_BITS	(UL(2) << TCR_IPS_SHIFT)
 #define TCR_IPS_36_BITS	(UL(1) << TCR_IPS_SHIFT)
 
+#define TCR_TBI1		(UL(1) << 38)
 #define TCR_HA			(UL(1) << 39)
 #define TCR_DS			(UL(1) << 59)
 
diff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/testing/selftests/kvm/lib/arm64/processor.c
index d46e4b13b92c..5b379da8cb90 100644
--- a/tools/testing/selftests/kvm/lib/arm64/processor.c
+++ b/tools/testing/selftests/kvm/lib/arm64/processor.c
@@ -384,6 +384,8 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
 
 	tcr_el1 |= TCR_IRGN0_WBWA | TCR_ORGN0_WBWA | TCR_SH0_INNER;
 	tcr_el1 |= TCR_T0SZ(vm->va_bits);
+	tcr_el1 |= TCR_TBI1;
+	tcr_el1 |= TCR_EPD1_MASK;
 	if (use_lpa2_pte_format(vm))
 		tcr_el1 |= TCR_DS;
 
-- 
2.52.0.239.gd5f0c6e74e-goog



From tabba at google.com  Mon Dec 15 08:51:53 2025
From: tabba at google.com (Fuad Tabba)
Date: Mon, 15 Dec 2025 16:51:53 +0000
Subject: [PATCH v2 3/5] KVM: riscv: selftests: Fix incorrect rounding in page_align()
In-Reply-To: <20251215165155.3451819-1-tabba@google.com>
References: <20251215165155.3451819-1-tabba@google.com>
Message-ID: <20251215165155.3451819-4-tabba@google.com>

The implementation of `page_align()` in `processor.c` calculates
alignment incorrectly for values that are already aligned. Specifically,
`(v + vm->page_size) & ~(vm->page_size - 1)` aligns to the *next* page
boundary even if `v` is already page-aligned, potentially wasting a page
of memory.

Fix the calculation to use standard alignment logic: `(v + vm->page_size
- 1) & ~(vm->page_size - 1)`.

Fixes: 3e06cdf10520 ("KVM: selftests: Add initial support for RISC-V 64-bit")
Signed-off-by: Fuad Tabba <tabba at google.com>
---
 tools/testing/selftests/kvm/lib/riscv/processor.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c
index 2eac7d4b59e9..d5e8747b5e69 100644
--- a/tools/testing/selftests/kvm/lib/riscv/processor.c
+++ b/tools/testing/selftests/kvm/lib/riscv/processor.c
@@ -28,7 +28,7 @@ bool __vcpu_has_ext(struct kvm_vcpu *vcpu, uint64_t ext)
 
 static uint64_t page_align(struct kvm_vm *vm, uint64_t v)
 {
-	return (v + vm->page_size) & ~(vm->page_size - 1);
+	return (v + vm->page_size - 1) & ~(vm->page_size - 1);
 }
 
 static uint64_t pte_addr(struct kvm_vm *vm, uint64_t entry)
-- 
2.52.0.239.gd5f0c6e74e-goog



From tabba at google.com  Mon Dec 15 08:51:54 2025
From: tabba at google.com (Fuad Tabba)
Date: Mon, 15 Dec 2025 16:51:54 +0000
Subject: [PATCH v2 4/5] KVM: selftests: Move page_align() to shared header
In-Reply-To: <20251215165155.3451819-1-tabba@google.com>
References: <20251215165155.3451819-1-tabba@google.com>
Message-ID: <20251215165155.3451819-5-tabba@google.com>

To avoid code duplication, move page_align() to the shared `kvm_util.h`
header file.

No functional change intended.

Signed-off-by: Fuad Tabba <tabba at google.com>
---
 tools/testing/selftests/kvm/include/kvm_util.h    | 5 +++++
 tools/testing/selftests/kvm/lib/arm64/processor.c | 5 -----
 tools/testing/selftests/kvm/lib/riscv/processor.c | 5 -----
 3 files changed, 5 insertions(+), 10 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index 81f4355ff28a..dabbe4c3b93f 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -1258,6 +1258,11 @@ static inline int __vm_disable_nx_huge_pages(struct kvm_vm *vm)
 	return __vm_enable_cap(vm, KVM_CAP_VM_DISABLE_NX_HUGE_PAGES, 0);
 }
 
+static inline uint64_t page_align(struct kvm_vm *vm, uint64_t v)
+{
+	return (v + vm->page_size - 1) & ~(vm->page_size - 1);
+}
+
 /*
  * Arch hook that is invoked via a constructor, i.e. before exeucting main(),
  * to allow for arch-specific setup that is common to all tests, e.g. computing
diff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/testing/selftests/kvm/lib/arm64/processor.c
index 607a4e462984..143632917766 100644
--- a/tools/testing/selftests/kvm/lib/arm64/processor.c
+++ b/tools/testing/selftests/kvm/lib/arm64/processor.c
@@ -21,11 +21,6 @@
 
 static vm_vaddr_t exception_handlers;
 
-static uint64_t page_align(struct kvm_vm *vm, uint64_t v)
-{
-	return (v + vm->page_size - 1) & ~(vm->page_size - 1);
-}
-
 static uint64_t pgd_index(struct kvm_vm *vm, vm_vaddr_t gva)
 {
 	unsigned int shift = (vm->pgtable_levels - 1) * (vm->page_shift - 3) + vm->page_shift;
diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c
index d5e8747b5e69..f8ff4bf938d9 100644
--- a/tools/testing/selftests/kvm/lib/riscv/processor.c
+++ b/tools/testing/selftests/kvm/lib/riscv/processor.c
@@ -26,11 +26,6 @@ bool __vcpu_has_ext(struct kvm_vcpu *vcpu, uint64_t ext)
 	return !ret && !!value;
 }
 
-static uint64_t page_align(struct kvm_vm *vm, uint64_t v)
-{
-	return (v + vm->page_size - 1) & ~(vm->page_size - 1);
-}
-
 static uint64_t pte_addr(struct kvm_vm *vm, uint64_t entry)
 {
 	return ((entry & PGTBL_PTE_ADDR_MASK) >> PGTBL_PTE_ADDR_SHIFT) <<
-- 
2.52.0.239.gd5f0c6e74e-goog



From tabba at google.com  Mon Dec 15 08:51:55 2025
From: tabba at google.com (Fuad Tabba)
Date: Mon, 15 Dec 2025 16:51:55 +0000
Subject: [PATCH v2 5/5] KVM: selftests: Fix typos and stale comments in kvm_util
In-Reply-To: <20251215165155.3451819-1-tabba@google.com>
References: <20251215165155.3451819-1-tabba@google.com>
Message-ID: <20251215165155.3451819-6-tabba@google.com>

Fix minor documentation errors in `kvm_util.h` and `kvm_util.c`.

- Correct the argument description for `vcpu_args_set` in `kvm_util.h`,
  which incorrectly listed `vm` instead of `vcpu`.
- Fix a typo in the comment for `kvm_selftest_arch_init` ("exeucting" ->
  "executing").
- Correct the return value description for `vm_vaddr_unused_gap` in
  `kvm_util.c` to match the implementation, which returns an address "at
  or above" `vaddr_min`, not "at or below".

No functional change intended.

Signed-off-by: Fuad Tabba <tabba at google.com>
---
 tools/testing/selftests/kvm/include/kvm_util.h | 4 ++--
 tools/testing/selftests/kvm/lib/kvm_util.c     | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index dabbe4c3b93f..e29b2cbcb82b 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -939,7 +939,7 @@ void *vcpu_map_dirty_ring(struct kvm_vcpu *vcpu);
  * VM VCPU Args Set
  *
  * Input Args:
- *   vm - Virtual Machine
+ *   vcpu - vCPU
  *   num - number of arguments
  *   ... - arguments, each of type uint64_t
  *
@@ -1264,7 +1264,7 @@ static inline uint64_t page_align(struct kvm_vm *vm, uint64_t v)
 }
 
 /*
- * Arch hook that is invoked via a constructor, i.e. before exeucting main(),
+ * Arch hook that is invoked via a constructor, i.e. before executing main(),
  * to allow for arch-specific setup that is common to all tests, e.g. computing
  * the default guest "mode".
  */
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 8279b6ced8d2..fab6b62d7810 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -1351,7 +1351,7 @@ struct kvm_vcpu *__vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
  * Output Args: None
  *
  * Return:
- *   Lowest virtual address at or below vaddr_min, with at least
+ *   Lowest virtual address at or above vaddr_min, with at least
  *   sz unused bytes.  TEST_ASSERT failure if no area of at least
  *   size sz is available.
  *
-- 
2.52.0.239.gd5f0c6e74e-goog



From yeoreum.yun at arm.com  Mon Dec 15 08:52:38 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Mon, 15 Dec 2025 16:52:38 +0000
Subject: [PATCH v6 00/14] Nesting support for lazy MMU mode
In-Reply-To: <20251215150323.2218608-1-kevin.brodsky@arm.com>
References: <20251215150323.2218608-1-kevin.brodsky@arm.com>
Message-ID: <aUA81joXQL0ZyIgm@e129823.arm.com>

> When the lazy MMU mode was introduced eons ago, it wasn't made clear
> whether such a sequence was legal:
>
> 	arch_enter_lazy_mmu_mode()
> 	...
> 		arch_enter_lazy_mmu_mode()
> 		...
> 		arch_leave_lazy_mmu_mode()
> 	...
> 	arch_leave_lazy_mmu_mode()
>
> It seems fair to say that nested calls to
> arch_{enter,leave}_lazy_mmu_mode() were not expected, and most
> architectures never explicitly supported it.
>
> Nesting does in fact occur in certain configurations, and avoiding it
> has proved difficult. This series therefore enables lazy_mmu sections to
> nest, on all architectures.
>
> Nesting is handled using a counter in task_struct (patch 8), like other
> stateless APIs such as pagefault_{disable,enable}(). This is fully
> handled in a new generic layer in <linux/pgtable.h>; the arch_* API
> remains unchanged. A new pair of calls, lazy_mmu_mode_{pause,resume}(),
> is also introduced to allow functions that are called with the lazy MMU
> mode enabled to temporarily pause it, regardless of nesting.
>
> An arch now opts in to using the lazy MMU mode by selecting
> CONFIG_ARCH_LAZY_MMU; this is more appropriate now that we have a
> generic API, especially with state conditionally added to task_struct.
>
> ---
>
> Background: Ryan Roberts' series from March [1] attempted to prevent
> nesting from ever occurring, and mostly succeeded. Unfortunately, a
> corner case (DEBUG_PAGEALLOC) may still cause nesting to occur on arm64.
> Ryan proposed [2] to address that corner case at the generic level but
> this approach received pushback; [3] then attempted to solve the issue
> on arm64 only, but it was deemed too fragile.
>
> It feels generally difficult to guarantee that lazy_mmu sections don't
> nest, because callers of various standard mm functions do not know if
> the function uses lazy_mmu itself.
>
> The overall approach in v3/v4 is very close to what David Hildenbrand
> proposed on v2 [4].
>
> Unlike in v1/v2, no special provision is made for architectures to
> save/restore extra state when entering/leaving the mode. Based on the
> discussions so far, this does not seem to be required - an arch can
> store any relevant state in thread_struct during arch_enter() and
> restore it in arch_leave(). Nesting is not a concern as these functions
> are only called at the top level, not in nested sections.
>
> The introduction of a generic layer, and tracking of the lazy MMU state
> in task_struct, also allows to streamline the arch callbacks - this
> series removes 67 lines from arch/.
>
> Patch overview:
>
> * Patch 1: cleanup - avoids having to deal with the powerpc
>   context-switching code
>
> * Patch 2-4: prepare arch_flush_lazy_mmu_mode() to be called from the
>   generic layer (patch 9)
>
> * Patch 5: documentation clarification (not directly related to the
>   changes in this series)
>
> * Patch 6-7: new API + CONFIG_ARCH_LAZY_MMU
>
> * Patch 8: ensure correctness in interrupt context
>
> * Patch 9: nesting support
>
> * Patch 10-13: replace arch-specific tracking of lazy MMU mode with
>   generic API
>
> * Patch 14: basic tests to ensure that the state added in patch 9 is
>   tracked correctly
>
> This series has been tested by running the mm kselftests on arm64 with
> DEBUG_VM, DEBUG_PAGEALLOC, KFENCE and KASAN. Extensive testing on
> powerpc was also kindly provided by Venkat Rao Bagalkote [5]. It was
> build-tested on other architectures (with and without XEN_PV on x86).
>
> - Kevin
>
> [1] https://lore.kernel.org/all/20250303141542.3371656-1-ryan.roberts at arm.com/
> [2] https://lore.kernel.org/all/20250530140446.2387131-1-ryan.roberts at arm.com/
> [3] https://lore.kernel.org/all/20250606135654.178300-1-ryan.roberts at arm.com/
> [4] https://lore.kernel.org/all/ef343405-c394-4763-a79f-21381f217b6c at redhat.com/
> [5] https://lore.kernel.org/all/94889730-1AEF-458F-B623-04092C0D6819 at linux.ibm.com/
> ---
> Changelog
>
> v5..v6:
>
> - Rebased on v6.19-rc1
> - Overall: no functional change
> - Patch 5: new patch clarifying that generic code may not sleep while in lazy
>   MMU mode [Alexander Gordeev]
> - Patch 6: added description for the ARCH_HAS_LAZY_MMU_MODE option
>   [Anshuman Khandual]
> - Patch 9: rename in_lazy_mmu_mode() to is_lazy_mmu_mode_active() [Alexander]
> - Patch 14: new patch with basic KUnit tests [Anshuman]
> - Collected R-b/A-b/T-b tags
>
> v5: https://lore.kernel.org/all/20251124132228.622678-1-kevin.brodsky at arm.com/
>
> v4..v5:
>
> - Rebased on mm-unstable
> - Patch 3: added missing radix_enabled() check in arch_flush()
>   [Ritesh Harjani]
> - Patch 6: declare arch_flush_lazy_mmu_mode() as static inline on x86
>   [Ryan Roberts]
> - Patch 7 (formerly 12): moved before patch 8 to ensure correctness in
>   interrupt context [Ryan]. The diffs in in_lazy_mmu_mode() and
>   queue_pte_barriers() are moved to patch 8 and 9 resp.
> - Patch 8:
>   * Removed all restrictions regarding lazy_mmu_mode_{pause,resume}().
>     They may now be called even when lazy MMU isn't enabled, and
>     any call to lazy_mmu_mode_* may be made while paused (such calls
>     will be ignored). [David, Ryan]
>   * lazy_mmu_state.{nesting_level,active} are replaced with
>     {enable_count,pause_count} to track arbitrary nesting of both
>     enable/disable and pause/resume [Ryan]
>   * Added __task_lazy_mmu_mode_active() for use in patch 12 [David]
>   * Added documentation for all the functions [Ryan]
> - Patch 9: keep existing test + set TIF_LAZY_MMU_PENDING instead of
>   atomic RMW [David, Ryan]
> - Patch 12: use __task_lazy_mmu_mode_active() instead of accessing
>   lazy_mmu_state directly [David]
> - Collected R-b/A-b tags
>
> v4: https://lore.kernel.org/all/20251029100909.3381140-1-kevin.brodsky at arm.com/
>
> v3..v4:
>
> - Patch 2: restored ordering of preempt_{disable,enable}() [Dave Hansen]
> - Patch 5 onwards: s/ARCH_LAZY_MMU/ARCH_HAS_LAZY_MMU_MODE/ [Mike Rapoport]
> - Patch 7: renamed lazy_mmu_state members, removed VM_BUG_ON(),
>   reordered writes to lazy_mmu_state members [David Hildenbrand]
> - Dropped patch 13 as it doesn't seem justified [David H]
> - Various improvements to commit messages [David H]
>
> v3: https://lore.kernel.org/all/20251015082727.2395128-1-kevin.brodsky at arm.com/
>
> v2..v3:
>
> - Full rewrite; dropped all Acked-by/Reviewed-by.
> - Rebased on v6.18-rc1.
>
> v2: https://lore.kernel.org/all/20250908073931.4159362-1-kevin.brodsky at arm.com/
>
> v1..v2:
> - Rebased on mm-unstable.
> - Patch 2: handled new calls to enter()/leave(), clarified how the "flush"
>   pattern (leave() followed by enter()) is handled.
> - Patch 5,6: removed unnecessary local variable [Alexander Gordeev's
>   suggestion].
> - Added Mike Rapoport's Acked-by.
>
> v1: https://lore.kernel.org/all/20250904125736.3918646-1-kevin.brodsky at arm.com/
> ---
> Cc: Alexander Gordeev <agordeev at linux.ibm.com>
> Cc: Andreas Larsson <andreas at gaisler.com>
> Cc: Andrew Morton <akpm at linux-foundation.org>
> Cc: Anshuman Khandual <anshuman.khandual at arm.com>
> Cc: Boris Ostrovsky <boris.ostrovsky at oracle.com>
> Cc: Borislav Petkov <bp at alien8.de>
> Cc: Catalin Marinas <catalin.marinas at arm.com>
> Cc: Christophe Leroy <christophe.leroy at csgroup.eu>
> Cc: Dave Hansen <dave.hansen at linux.intel.com>
> Cc: David Hildenbrand <david at redhat.com>
> Cc: "David S. Miller" <davem at davemloft.net>
> Cc: David Woodhouse <dwmw2 at infradead.org>
> Cc: "H. Peter Anvin" <hpa at zytor.com>
> Cc: Ingo Molnar <mingo at redhat.com>
> Cc: Jann Horn <jannh at google.com>
> Cc: Juergen Gross <jgross at suse.com>
> Cc: "Liam R. Howlett" <Liam.Howlett at oracle.com>
> Cc: Lorenzo Stoakes <lorenzo.stoakes at oracle.com>
> Cc: Madhavan Srinivasan <maddy at linux.ibm.com>
> Cc: Michael Ellerman <mpe at ellerman.id.au>
> Cc: Michal Hocko <mhocko at suse.com>
> Cc: Mike Rapoport <rppt at kernel.org>
> Cc: Nicholas Piggin <npiggin at gmail.com>
> Cc: Peter Zijlstra <peterz at infradead.org>
> Cc: Ritesh Harjani (IBM) <ritesh.list at gmail.com>
> Cc: Ryan Roberts <ryan.roberts at arm.com>
> Cc: Suren Baghdasaryan <surenb at google.com>
> Cc: Thomas Gleixner <tglx at linutronix.de>
> Cc: Venkat Rao Bagalkote <venkat88 at linux.ibm.com>
> Cc: Vlastimil Babka <vbabka at suse.cz>
> Cc: Will Deacon <will at kernel.org>
> Cc: Yeoreum Yun <yeoreum.yun at arm.com>
> Cc: linux-arm-kernel at lists.infradead.org
> Cc: linux-kernel at vger.kernel.org
> Cc: linuxppc-dev at lists.ozlabs.org
> Cc: sparclinux at vger.kernel.org
> Cc: xen-devel at lists.xenproject.org
> Cc: x86 at kernel.org
> ---
> Alexander Gordeev (1):
>   powerpc/64s: Do not re-activate batched TLB flush
>
> Kevin Brodsky (13):
>   x86/xen: simplify flush_lazy_mmu()
>   powerpc/mm: implement arch_flush_lazy_mmu_mode()
>   sparc/mm: implement arch_flush_lazy_mmu_mode()
>   mm: clarify lazy_mmu sleeping constraints
>   mm: introduce CONFIG_ARCH_HAS_LAZY_MMU_MODE
>   mm: introduce generic lazy_mmu helpers
>   mm: bail out of lazy_mmu_mode_* in interrupt context
>   mm: enable lazy_mmu sections to nest
>   arm64: mm: replace TIF_LAZY_MMU with is_lazy_mmu_mode_active()
>   powerpc/mm: replace batch->active with is_lazy_mmu_mode_active()
>   sparc/mm: replace batch->active with is_lazy_mmu_mode_active()
>   x86/xen: use lazy_mmu_state when context-switching
>   mm: Add basic tests for lazy_mmu
>
>  arch/arm64/Kconfig                            |   1 +
>  arch/arm64/include/asm/pgtable.h              |  41 +----
>  arch/arm64/include/asm/thread_info.h          |   3 +-
>  arch/arm64/mm/mmu.c                           |   8 +-
>  arch/arm64/mm/pageattr.c                      |   4 +-
>  .../include/asm/book3s/64/tlbflush-hash.h     |  20 +--
>  arch/powerpc/include/asm/thread_info.h        |   2 -
>  arch/powerpc/kernel/process.c                 |  25 ---
>  arch/powerpc/mm/book3s64/hash_tlb.c           |  10 +-
>  arch/powerpc/mm/book3s64/subpage_prot.c       |   4 +-
>  arch/powerpc/platforms/Kconfig.cputype        |   1 +
>  arch/sparc/Kconfig                            |   1 +
>  arch/sparc/include/asm/tlbflush_64.h          |   5 +-
>  arch/sparc/mm/tlb.c                           |  14 +-
>  arch/x86/Kconfig                              |   1 +
>  arch/x86/boot/compressed/misc.h               |   1 +
>  arch/x86/boot/startup/sme.c                   |   1 +
>  arch/x86/include/asm/paravirt.h               |   1 -
>  arch/x86/include/asm/pgtable.h                |   1 +
>  arch/x86/include/asm/thread_info.h            |   4 +-
>  arch/x86/xen/enlighten_pv.c                   |   3 +-
>  arch/x86/xen/mmu_pv.c                         |   6 +-
>  fs/proc/task_mmu.c                            |   4 +-
>  include/linux/mm_types_task.h                 |   5 +
>  include/linux/pgtable.h                       | 158 +++++++++++++++++-
>  include/linux/sched.h                         |  45 +++++
>  mm/Kconfig                                    |  19 +++
>  mm/Makefile                                   |   1 +
>  mm/kasan/shadow.c                             |   8 +-
>  mm/madvise.c                                  |  18 +-
>  mm/memory.c                                   |  16 +-
>  mm/migrate_device.c                           |   8 +-
>  mm/mprotect.c                                 |   4 +-
>  mm/mremap.c                                   |   4 +-
>  mm/tests/lazy_mmu_mode_kunit.c                |  71 ++++++++
>  mm/userfaultfd.c                              |   4 +-
>  mm/vmalloc.c                                  |  12 +-
>  mm/vmscan.c                                   |  12 +-
>  38 files changed, 380 insertions(+), 166 deletions(-)
>  create mode 100644 mm/tests/lazy_mmu_mode_kunit.c
>
>
> base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
> --
> 2.51.2

All of these look good to me.

Reviewed-by: Yeoreum Yun <yeoreum.yun at arm.com>

--
Sincerely,
Yeoreum Yun


From m.felsch at pengutronix.de  Mon Dec 15 09:07:50 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Mon, 15 Dec 2025 18:07:50 +0100
Subject: [PATCH 2/2] arm64: dts: imx93-phyboard-segin: Add peb-av-02
 overlay
In-Reply-To: <15bb2331-713a-4b6a-ae9a-4870066e84dc@norik.com>
References: <20251202-v6-18-topic-imx93-phyboard-segin-av-02-display-v1-0-9c14be6c7478@pengutronix.de>
 <20251202-v6-18-topic-imx93-phyboard-segin-av-02-display-v1-2-9c14be6c7478@pengutronix.de>
 <15bb2331-713a-4b6a-ae9a-4870066e84dc@norik.com>
Message-ID: <20251215170750.j2l6gnbocmhdloe6@pengutronix.de>

Hi Primoz,

On 25-12-03, Primoz Fiser wrote:
> Hi Marco,
> 
> On 2. 12. 25 14:44, Marco Felsch wrote:
> > From: Andrej Picej <andrej.picej at norik.com>
> > 
> > Add overlay for Audio-Video module PEB-AV-02. Add support for panel
> > display, capacitive touchscreen and backlight.
> > 
> > For now the backlight is configured as a GPIO, brightness of the display
> > can not be set. When the FLEXIO PWM driver is available this should be
> > switched to PWM backlight driver.
> > 
> > Signed-off-by: Andrej Picej <andrej.picej at norik.com>
> > [rework commit message, use local regulator, remove compatible]
> > Signed-off-by: Primoz Fiser <primoz.fiser at norik.com>
> > Signed-off-by: Christian Hemp <c.hemp at phytec.de>
> > [m.felsch at pengutronix.de: cleanup downstream commit]
> > Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
> > ---
> >  arch/arm64/boot/dts/freescale/Makefile             |   2 +
> >  .../freescale/imx93-phyboard-segin-peb-av-02.dtso  | 135 +++++++++++++++++++++
> >  2 files changed, 137 insertions(+)
> > 
> > diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
> > index 525ef180481d331e9c4decd092b7b831c497b67e..27e27ac29e82bc0692e86c2ba15c240dc9fbe1c6 100644
> > --- a/arch/arm64/boot/dts/freescale/Makefile
> > +++ b/arch/arm64/boot/dts/freescale/Makefile
> > @@ -357,10 +357,12 @@ dtb-$(CONFIG_ARCH_MXC) += imx93-phyboard-nash.dtb
> >  dtb-$(CONFIG_ARCH_MXC) += imx93-phyboard-segin.dtb
> >  
> >  imx93-phyboard-nash-peb-wlbt-07-dtbs += imx93-phyboard-nash.dtb imx93-phyboard-nash-peb-wlbt-07.dtbo
> > +imx93-phyboard-segin-peb-av-02-dtbs += imx93-phyboard-segin.dtb imx93-phyboard-segin-peb-av-02.dtbo
> >  imx93-phyboard-segin-peb-eval-01-dtbs += imx93-phyboard-segin.dtb imx93-phyboard-segin-peb-eval-01.dtbo
> >  imx93-phyboard-segin-peb-wlbt-05-dtbs += imx93-phyboard-segin.dtb imx93-phyboard-segin-peb-wlbt-05.dtbo
> >  imx93-phycore-rpmsg-dtbs += imx93-phyboard-nash.dtb imx93-phyboard-segin.dtb imx93-phycore-rpmsg.dtbo
> >  dtb-$(CONFIG_ARCH_MXC) += imx93-phyboard-nash-peb-wlbt-07.dtb
> > +dtb-$(CONFIG_ARCH_MXC) += imx93-phyboard-segin-peb-av-02.dtb
> 
> Here you need to rebase since new commits on linux-next.

Argh.. will do.

> >  dtb-$(CONFIG_ARCH_MXC) += imx93-phyboard-segin-peb-eval-01.dtb
> >  dtb-$(CONFIG_ARCH_MXC) += imx93-phyboard-segin-peb-wlbt-05.dtb
> >  dtb-$(CONFIG_ARCH_MXC) += imx93-phycore-rpmsg.dtb
> > diff --git a/arch/arm64/boot/dts/freescale/imx93-phyboard-segin-peb-av-02.dtso b/arch/arm64/boot/dts/freescale/imx93-phyboard-segin-peb-av-02.dtso
> > new file mode 100644
> > index 0000000000000000000000000000000000000000..2e7074e402dc8fdeb1568d4f2d4960431e972501
> > --- /dev/null
> > +++ b/arch/arm64/boot/dts/freescale/imx93-phyboard-segin-peb-av-02.dtso
> > @@ -0,0 +1,135 @@
> > +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> > +/*
> > + * Copyright (C) 2025 PHYTEC Messtechnik GmbH
> > + * Copyright (C) 2025 Pengutronix
> > + *
> > + * Author: Andrej Picej <andrej.picej at norik.com>
> > + * Author: Marco Felsch <kernel at pengutronix.de>
> > + */
> > +
> > +#include <dt-bindings/clock/imx93-clock.h>
> > +#include <dt-bindings/gpio/gpio.h>
> > +#include <dt-bindings/interrupt-controller/arm-gic.h>
> > +#include "imx93-pinfunc.h"
> > +
> > +/dts-v1/;
> > +/plugin/;
> > +
> > +&{/} {
> > +	/* TODO: Convert to PWM backlight once the FlexIO PWM is supported */
> > +	backlight: backlight {
> > +		compatible = "gpio-backlight";
> > +		pinctrl-names = "default";
> > +		pinctrl-0 = <&pinctrl_backlight>;
> > +		gpios = <&gpio4 28 GPIO_ACTIVE_HIGH>;
> > +	};
> > +
> > +	panel {
> > +		compatible = "edt,etm0700g0edh6";
> > +		pinctrl-names = "default";
> > +		pinctrl-0 = <&pinctrl_panel>;
> > +
> > +		backlight = <&backlight>;
> > +		enable-gpios = <&gpio4 29 GPIO_ACTIVE_HIGH>;
> > +		power-supply = <&reg_x71_vcc_3v3>;
> > +
> > +		port {
> > +			panel_in: endpoint {
> > +				remote-endpoint = <&dpi_to_panel>;
> > +			};
> > +		};
> > +	};
> > +
> > +	reg_x71_vcc_3v3: regulator-x71-vcc-3v3 {
> 
> I just checked the schematics.
> 
> Can we rename this to reg_vcc_3v3_con in v2 maybe?
> 
> > +		compatible = "regulator-fixed";
> > +		regulator-name = "X71-VCC3V3";
> 
> And this to "VCC3V3_CON"?
> 
> The reasoning behind is that "X71-VCC3V3" voltage doesn't exist on the
> schematics, while there is actually "VCC3V3_CON" voltage supplying the
> display panel.

I know that "X71-VCC3V3" doesn't exist, I also thought about
"X71:VCC3V3" to make it clear. Why I mentioned the X71 in the first
place was to not cause any naming conflict. I would like to keep the X71
naming since "VCC3V3_CON" really is the "X71-VCC3V3" with some filters
applied. Anyway, I can change this of course.

> > +		regulator-max-microvolt = <3300000>;
> > +		regulator-min-microvolt = <3300000>;
> > +	};
> > +};
> > +
> > +&dpi_bridge {
> > +	status = "okay";
> > +};
> > +
> > +&dpi_to_panel {
> > +	remote-endpoint = <&panel_in>;
> > +	bus-width = <18>;
> > +};
> > +
> > +&lcdif {
> > +	pinctrl-names = "default";
> > +	pinctrl-0 = <&pinctrl_lcdif>;
> > +	assigned-clocks = <&clk IMX93_CLK_VIDEO_PLL>;
> > +	assigned-clock-rates = <332600000>;
> > +	status = "okay";
> > +};
> > +
> > +&lpi2c2 {
> > +	#address-cells = <1>;
> > +	#size-cells = <0>;
> > +
> > +	touchscreen at 38 {
> > +		compatible = "edt,edt-ft5406";
> > +		reg = <0x38>;
> > +		pinctrl-names = "default";
> > +		pinctrl-0 = <&pinctrl_touchscreen>;
> > +		interrupt-parent = <&gpio4>;
> > +		interrupts = <12 IRQ_TYPE_EDGE_FALLING>;
> > +		reset-gpios = <&gpio4 1 GPIO_ACTIVE_LOW>;
> > +		touchscreen-size-x = <1792>;
> > +		touchscreen-size-y = <1024>;
> 
> Please add "wakeup-source" property here like in the downstream commit.
> 
> With this in place, panel touch can be used to wake up the board from sleep.

Is this a required feature? Touchscreens with no certain
low-power mode handlig (e.g. reduced scanning time) can draw much power
in suspend.

I can add it if Phytec is aware of this fact and still wants to have
thsi feature.

> Last but not least, can you add the vcc and iovcc supply regulators here
> like in the downstream commit:
> 
> vcc-supply = <&reg_vcc_3v3_con>;
> iovcc-supply = <&reg_vcc_3v3_con>;
> 
> to get rid of the following warnings:
> 
> edt_ft5x06 1-0038: supply vcc not found, using dummy regulator
> edt_ft5x06 1-0038: supply iovcc not found, using dummy regulator

Will do.

> Anyway, I tested the display on the segin board with latest linux-next
> and your patches. Can report display, touch and backlight work as expected.
> 
> Thank you!
> 
> Tested-by: Primoz Fiser <primoz.fiser at norik.com>

Regards,
  Marco

> 
> BR,
> Primoz
> 
> > +	};
> > +};
> > +
> > +&media_blk_ctrl {
> > +	status = "okay";
> > +};
> > +
> > +&iomuxc {
> > +	pinctrl_backlight: backlightgrp {
> > +		fsl,pins = <
> > +			MX93_PAD_CCM_CLKO3__GPIO4_IO28			0x1133e
> > +		>;
> > +	};
> > +
> > +	pinctrl_lcdif: lcdifgrp {
> > +		fsl,pins = <
> > +			MX93_PAD_GPIO_IO00__MEDIAMIX_DISP_CLK		0x50e
> > +			MX93_PAD_GPIO_IO01__MEDIAMIX_DISP_DE		0x50e
> > +			MX93_PAD_GPIO_IO02__MEDIAMIX_DISP_VSYNC		0x50e
> > +			MX93_PAD_GPIO_IO03__MEDIAMIX_DISP_HSYNC		0x50e
> > +			MX93_PAD_GPIO_IO04__MEDIAMIX_DISP_DATA00	0x50e
> > +			MX93_PAD_GPIO_IO05__MEDIAMIX_DISP_DATA01	0x50e
> > +			MX93_PAD_GPIO_IO06__MEDIAMIX_DISP_DATA02	0x50e
> > +			MX93_PAD_GPIO_IO07__MEDIAMIX_DISP_DATA03	0x50e
> > +			MX93_PAD_GPIO_IO08__MEDIAMIX_DISP_DATA04	0x50e
> > +			MX93_PAD_GPIO_IO09__MEDIAMIX_DISP_DATA05	0x51e
> > +			MX93_PAD_GPIO_IO10__MEDIAMIX_DISP_DATA06	0x50e
> > +			MX93_PAD_GPIO_IO11__MEDIAMIX_DISP_DATA07	0x50e
> > +			MX93_PAD_GPIO_IO12__MEDIAMIX_DISP_DATA08	0x50e
> > +			MX93_PAD_GPIO_IO13__MEDIAMIX_DISP_DATA09	0x50e
> > +			MX93_PAD_GPIO_IO14__MEDIAMIX_DISP_DATA10	0x50e
> > +			MX93_PAD_GPIO_IO15__MEDIAMIX_DISP_DATA11	0x50e
> > +			MX93_PAD_GPIO_IO16__MEDIAMIX_DISP_DATA12	0x506
> > +			MX93_PAD_GPIO_IO17__MEDIAMIX_DISP_DATA13	0x506
> > +			MX93_PAD_GPIO_IO18__MEDIAMIX_DISP_DATA14	0x506
> > +			MX93_PAD_GPIO_IO19__MEDIAMIX_DISP_DATA15	0x506
> > +			MX93_PAD_GPIO_IO20__MEDIAMIX_DISP_DATA16	0x506
> > +			MX93_PAD_GPIO_IO21__MEDIAMIX_DISP_DATA17	0x506
> > +		>;
> > +	};
> > +
> > +	pinctrl_panel: panelgrp {
> > +		fsl,pins = <
> > +			MX93_PAD_CCM_CLKO4__GPIO4_IO29			0x1133e
> > +		>;
> > +	};
> > +
> > +	pinctrl_touchscreen: touchscreengrp {
> > +		fsl,pins = <
> > +			MX93_PAD_ENET1_MDIO__GPIO4_IO01			0x11e
> > +			MX93_PAD_ENET1_RD2__GPIO4_IO12			0x1133e
> > +		>;
> > +	};
> > +};
> > 
> 
> -- 
> Primoz Fiser
> phone: +386-41-390-545
> email: primoz.fiser at norik.com
> --
> Norik systems d.o.o.
> Your embedded software partner
> Slovenia, EU
> phone: +386-41-540-545
> email: info at norik.com
> 
> 

-- 
#gernperDu 
#CallMeByMyFirstName

Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | https://www.pengutronix.de/ |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-9    |


From horms at kernel.org  Mon Dec 15 09:10:43 2025
From: horms at kernel.org (Simon Horman)
Date: Mon, 15 Dec 2025 17:10:43 +0000
Subject: [PATCH v2] smc91x: fix broken irq-context in PREEMPT_RT
In-Reply-To: <20251212190338.2318843-1-yeoreum.yun@arm.com>
References: <20251212190338.2318843-1-yeoreum.yun@arm.com>
Message-ID: <aUBBE-W4kwQbsp9t@horms.kernel.org>

On Fri, Dec 12, 2025 at 07:03:38PM +0000, Yeoreum Yun wrote:
> When smc91x.c is built with PREEMPT_RT, the following splat occurs
> in FVP_RevC:
> 
> [   13.055000] smc91x LNRO0003:00 eth0: link up, 10Mbps, half-duplex, lpa 0x0000
> [   13.062137] BUG: workqueue leaked atomic, lock or RCU: kworker/2:1[106]
> [   13.062137]      preempt=0x00000000 lock=0->0 RCU=0->1 workfn=mld_ifc_work
> [   13.062266] C
> ** replaying previous printk message **
> [   13.062266] CPU: 2 UID: 0 PID: 106 Comm: kworker/2:1 Not tainted 6.18.0-dirty #179 PREEMPT_{RT,(full)}
> [   13.062353] Hardware name:  , BIOS
> [   13.062382] Workqueue: mld mld_ifc_work
> [   13.062469] Call trace:
> [   13.062494]  show_stack+0x24/0x40 (C)
> [   13.062602]  __dump_stack+0x28/0x48
> [   13.062710]  dump_stack_lvl+0x7c/0xb0
> [   13.062818]  dump_stack+0x18/0x34
> [   13.062926]  process_scheduled_works+0x294/0x450
> [   13.063043]  worker_thread+0x260/0x3d8
> [   13.063124]  kthread+0x1c4/0x228
> [   13.063235]  ret_from_fork+0x10/0x20
> 
> This happens because smc_special_trylock() disables IRQs even on PREEMPT_RT,
> but smc_special_unlock() does not restore IRQs on PREEMPT_RT.
> The reason is that smc_special_unlock() calls spin_unlock_irqrestore(),
> and rcu_read_unlock_bh() in __dev_queue_xmit() cannot invoke
> rcu_read_unlock() through __local_bh_enable_ip() when current->softirq_disable_cnt becomes zero.
> 
> To address this issue, replace smc_special_trylock() with spin_trylock_irqsave().
> 
> Fixes: 8ff499e43c53 ("smc91x: let smc91x work well under netpoll")
> Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
> ---
> This patch based on v6.18.
> 
> History
> ========
> 
> >From v1 to v2:
>   - remove debug log.
>   - https://lore.kernel.org/all/20251212185818.2209573-1-yeoreum.yun at arm.com/
> 

Firstly, I'd like to note that it seems to me that the last
non-trivial update to this driver seems to have occurred back in 2016.
Do you know if it is still actively used?

I agree that this patch seems appropriate as a bug fix.
But I do wonder if, as a follow-up for net-next when it re-opens,
smc_special_*lock could be removed entirely.
Other than being the source of this bug (which I guess is special),
they don't seem very special anymore. Perhaps they were once,
but that time seems to have passed.

Regarding the Fixes tag. I wonder if this one, which post-dates the
currently cited commit is correct. It seems to be when RT variants of
these locks was introduced.

Fixes: 342a93247e08 ("locking/spinlock: Provide RT variant header: <linux/spinlock_rt.h>")

Lastly, for reference, when posting fixes for Networking code, please:

* Target the patches at net like this:

  [PATCH net] ...

* Allow at least 24h to pass before posting updated patch versions

More can be found here: https://docs.kernel.org/process/maintainer-netdev.html


Reviewed-by: Simon Horman <horms at kernel.org>


From maz at kernel.org  Mon Dec 15 09:31:03 2025
From: maz at kernel.org (Marc Zyngier)
Date: Mon, 15 Dec 2025 17:31:03 +0000
Subject: [PATCH 10/32] KVM: arm64: gic-v5: Add emulation for ICC_IAFFID_EL1 accesses
In-Reply-To: <20251212152215.675767-11-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	<20251212152215.675767-11-sascha.bischoff@arm.com>
Message-ID: <86cy4fodns.wl-maz@kernel.org>

On Fri, 12 Dec 2025 15:22:38 +0000,
Sascha Bischoff <Sascha.Bischoff at arm.com> wrote:
> 
> GICv5 doesn't include an ICV_IAFFIDR_EL1 or ICH_IAFFIDR_EL2 for
> providing the IAFFID to the guest. A guest access to the
> ICH_IAFFIDR_EL1 must therefore be trapped and emulated to avoid the

nit: ICC_IAFFIDR_EL1. There is no ICH_*_EL1 register.

> guest accessing the host's ICC_IAFFIDR_EL1.
> 
> For GICv5, the VPE ID corresponds to the virtual IAFFID for the
> purposes of specifying the affinity of virtual interrupts. The VPE ID
> is the index into the VPE Table, which will be the same as the
> vcpu->vcpu_id once the various GICv5 VM tables are introduced. At this
> stage, said VM tables have yet to be introduced as they are not
> required for PPI support. Moreover, the IAFFID should go largely
> unused by any guest using just PPIs as they are not routable to a
> different PE. That said, we still need to trap and emulate the guest's
> accesses to avoid leaking host state into the guest.

I think you can trim some of this. Just state that KVM makes the
IAFFIDR, VPEID and vcpu_id the same thing, and that'll be good enough.

> 
> The virtual IAFFID is provided to the guest when it reads
> ICC_IAFFID_EL1 (which always traps back to the hypervisor). Writes are
> rightly ignored.
> 
> The trapping for the ICC_IAFFIDR_EL2 is always enabled when in a guest
> context.

This register doesn't exist either.

> 
> Co-authored-by: Timothy Hayes <timothy.hayes at arm.com>
> Signed-off-by: Timothy Hayes <timothy.hayes at arm.com>
> Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
> ---
>  arch/arm64/kvm/config.c   | 10 +++++++++-
>  arch/arm64/kvm/sys_regs.c | 19 +++++++++++++++++++
>  2 files changed, 28 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
> index 57ef67f718113..cbdd8ac90f4d0 100644
> --- a/arch/arm64/kvm/config.c
> +++ b/arch/arm64/kvm/config.c
> @@ -1582,6 +1582,14 @@ static void __compute_hdfgwtr(struct kvm_vcpu *vcpu)
>  		*vcpu_fgt(vcpu, HDFGWTR_EL2) |= HDFGWTR_EL2_MDSCR_EL1;
>  }
>  
> +static void __compute_ich_hfgrtr(struct kvm_vcpu *vcpu)
> +{
> +	__compute_fgt(vcpu, ICH_HFGRTR_EL2);
> +
> +	/* ICC_IAFFIDR_EL1 *always* needs to be trapped when running a guest */
> +	*vcpu_fgt(vcpu, ICH_HFGRTR_EL2) &= ~ICH_HFGRTR_EL2_ICC_IAFFIDR_EL1;

Slightly redundant when !GICv5 in the guest, but that's not really a
problem.

> +}
> +
>  void kvm_vcpu_load_fgt(struct kvm_vcpu *vcpu)
>  {
>  	if (!cpus_have_final_cap(ARM64_HAS_FGT))
> @@ -1607,7 +1615,7 @@ void kvm_vcpu_load_fgt(struct kvm_vcpu *vcpu)
>  	if (!cpus_have_final_cap(ARM64_HAS_GICV5_CPUIF))
>  		return;
>  
> -	__compute_fgt(vcpu, ICH_HFGRTR_EL2);
> +	__compute_ich_hfgrtr(vcpu);
>  	__compute_fgt(vcpu, ICH_HFGWTR_EL2);
>  	__compute_fgt(vcpu, ICH_HFGITR_EL2);
>  }
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index fbbd7b6ff6507..31c08fd591d08 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -681,6 +681,24 @@ static bool access_gic_dir(struct kvm_vcpu *vcpu,
>  	return true;
>  }
>  
> +static bool access_gicv5_iaffid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +				const struct sys_reg_desc *r)
> +{
> +	if (!vgic_is_v5(vcpu->kvm))
> +		return undef_access(vcpu, p, r);

Shouldn't this be readily handled by the FGU configuration in the
absence of GICv5 in the guest?

> +
> +	if (p->is_write)
> +		return ignore_write(vcpu, p);
> +
> +	/*
> +	 * For GICv5 VMs, the IAFFID value is the same as the VPE ID. The VPE ID
> +	 * is the same as the VCPU's ID.
> +	 */
> +	p->regval = FIELD_PREP(ICC_IAFFIDR_EL1_IAFFID, vcpu->vcpu_id);
> +
> +	return true;
> +}
> +
>  static bool trap_raz_wi(struct kvm_vcpu *vcpu,
>  			struct sys_reg_params *p,
>  			const struct sys_reg_desc *r)
> @@ -3411,6 +3429,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>  	{ SYS_DESC(SYS_ICC_AP1R1_EL1), undef_access },
>  	{ SYS_DESC(SYS_ICC_AP1R2_EL1), undef_access },
>  	{ SYS_DESC(SYS_ICC_AP1R3_EL1), undef_access },
> +	{ SYS_DESC(SYS_ICC_IAFFIDR_EL1), access_gicv5_iaffid },
>  	{ SYS_DESC(SYS_ICC_DIR_EL1), access_gic_dir },
>  	{ SYS_DESC(SYS_ICC_RPR_EL1), undef_access },
>  	{ SYS_DESC(SYS_ICC_SGI1R_EL1), access_gic_sgi },

Thanks,

	M.

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


From Sascha.Bischoff at arm.com  Mon Dec 15 09:37:15 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Mon, 15 Dec 2025 17:37:15 +0000
Subject: [PATCH 09/32] KVM: arm64: gic-v5: Compute GICv5 FGTs on vcpu load
In-Reply-To: <86o6o3oehl.wl-maz@kernel.org>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	 <20251212152215.675767-10-sascha.bischoff@arm.com>
	 <86o6o3oehl.wl-maz@kernel.org>
Message-ID: <d858ab5e484032ddb903cd8c6d0031af798e41ba.camel@arm.com>

On Fri, 2025-12-12 at 16:24 +0000, Marc Zyngier wrote:
> On Fri, 12 Dec 2025 15:22:38 +0000,
> Sascha Bischoff <Sascha.Bischoff at arm.com> wrote:
> > 
> > Extend the existing FGT infrastructure to calculate and activate
> > any
> > required GICv5 traps (ICH_HFGRTR_EL2, ICH_HFGWTR_EL2,
> > ICH_HFGITR_EL2)
> > before entering the guest, and restore the original ICH_HFGxTR_EL2
> > contents on the return path. This ensures that the host and guest
> > behaviour remains independent.
> > 
> > As of this change, none of the GICv5 instructions or register
> > accesses
> > are being trapped, but this will change in subsequent commits as
> > some
> > GICv5 system registers must always be trapped (ICC_IAFFIDR_EL1,
> > ICH_PPI_HMRx_EL1).
> 
> nit: 90% of this patch has nothing to do with computing the FGTs at
> load time. The gist of it is actually setting up the FGT
> infrastructure, and activate/deactivate aspect is actually very
> minor. You may want to reformulate the commit message to make that
> clearer (I don't think this needs splitting though).

Good point. Have reworded the commit message accordingly.

> 
> [...]
> 
> > @@ -1501,7 +1585,7 @@ static void __compute_hdfgwtr(struct kvm_vcpu
> > *vcpu)
> > ?void kvm_vcpu_load_fgt(struct kvm_vcpu *vcpu)
> > ?{
> > ?	if (!cpus_have_final_cap(ARM64_HAS_FGT))
> > -		return;
> > +		goto skip_feat_fgt;
> 
> How can you have GICv5, but not FGTs? I don't think this is a valid
> construct as per the architecture:
> 
> 	(FEAT_GCIE ==> v9Ap3)
> 	(FEAT_FGT ==> v8Ap5)
> 	(v9Ap3 ==> (v9Ap2 && v8Ap8))

OK, agreed. FEAT_FGT is mandatory from v8.6. Have dropped this first
skip as we'll certainly have it if we have GICv5.

> 
> > ?
> > ?	__compute_fgt(vcpu, HFGRTR_EL2);
> > ?	__compute_hfgwtr(vcpu);
> > @@ -1511,11 +1595,19 @@ void kvm_vcpu_load_fgt(struct kvm_vcpu
> > *vcpu)
> > ?	__compute_fgt(vcpu, HAFGRTR_EL2);
> > ?
> > ?	if (!cpus_have_final_cap(ARM64_HAS_FGT2))
> > -		return;
> > +		goto skip_feat_fgt;
> 
> Even FGT2 is expected, since v9.3 is congruent to v8.8:
> 
> 	(FEAT_FGT2 ==> v8Ap8)

FEAT_FGT2 is optional from v8.8 (v9.3), and mandatory from v8.9 (v9.4).
This means we could have a GICv5 system without FEAT_FGT2; I'll leave
in the second skip.

Thanks,
Sascha

> 
> > ?
> > ?	__compute_fgt(vcpu, HFGRTR2_EL2);
> > ?	__compute_fgt(vcpu, HFGWTR2_EL2);
> > ?	__compute_fgt(vcpu, HFGITR2_EL2);
> > ?	__compute_fgt(vcpu, HDFGRTR2_EL2);
> > ?	__compute_fgt(vcpu, HDFGWTR2_EL2);
> > +
> > +skip_feat_fgt:
> > +	if (!cpus_have_final_cap(ARM64_HAS_GICV5_CPUIF))
> > +		return;
> > +
> > +	__compute_fgt(vcpu, ICH_HFGRTR_EL2);
> > +	__compute_fgt(vcpu, ICH_HFGWTR_EL2);
> > +	__compute_fgt(vcpu, ICH_HFGITR_EL2);
> > ?}
> 
> Thanks,
> 
> 	M.
> 


From cki-project at redhat.com  Mon Dec 15 09:43:02 2025
From: cki-project at redhat.com (cki-project at redhat.com)
Date: Mon, 15 Dec 2025 17:43:02 -0000
Subject: =?utf-8?b?4pyF?= PASS: Test report for for-kernelci (6.19.0-rc1,
 upstream-arm-next, 8f0b4cce)
Message-ID: <74421.125121512430402225@us-mta-217.us.mimecast.lan>

Hi, we tested your kernel and here are the results:

    Overall result: PASSED
             Merge: OK
           Compile: OK
              Test: OK

Tested-by: CKI Project <cki-project at redhat.com>

Kernel information:
    Commit message: Linux 6.19-rc1

You can find all the details about the test run at
    https://datawarehouse.cki-project.org/kcidb/checkouts/redhat:2215260160


If you find a failure unrelated to your changes, please ask the test maintainer to review it.
This will prevent the failures from being incorrectly reported in the future.

Please reply to this email if you have any questions about the tests that we
ran or if you have any suggestions on how to make future tests more effective.

        ,-.   ,-.
       ( C ) ( K )  Continuous
        `-',-.`-'   Kernel
          ( I )     Integration
           `-'
______________________________________________________________________________



From leo.yan at arm.com  Mon Dec 15 09:49:01 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 15 Dec 2025 17:49:01 +0000
Subject: [RFC PATCH v6 08/35] HACK! KVM: arm64: Enable SPE virtualization
 only in VHE mode
In-Reply-To: <20251114160717.163230-9-alexandru.elisei@arm.com>
References: <20251114160717.163230-1-alexandru.elisei@arm.com>
 <20251114160717.163230-9-alexandru.elisei@arm.com>
Message-ID: <20251215174901.GA779696@e132581.arm.com>

On Fri, Nov 14, 2025 at 04:06:49PM +0000, Alexandru Elisei wrote:
> For RFC only.
> 
> Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
> ---
>  arch/arm64/kvm/spe.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/kvm/spe.c b/arch/arm64/kvm/spe.c
> index 7e38f7d9075b..101258b55053 100644
> --- a/arch/arm64/kvm/spe.c
> +++ b/arch/arm64/kvm/spe.c
> @@ -24,8 +24,8 @@ void kvm_host_spe_init(struct arm_spe_pmu *arm_spu)
>  {
>  	struct arm_spu_entry *entry;
>  
> -	/* TODO: pKVM support */
> -	if (is_protected_kvm_enabled())
> +	/* TODO: pKVM and nVHE support */
> +	if (is_protected_kvm_enabled() || !has_vhe())

I totally agree we should focus on VHE mode first.  But it is worth
considering if we can unify solution across different virtualization
modes.

Aside from register access and IRQ handling, buffer management is the
most complex part of this series, it would be useful to know whether
the change can support different modes.

Thanks,
Leo

P.S. an interesting question is whether we can reuse virtio-iommu or
DMA buffer allocation for SPE.  My understanding is the IOMMU would be
simpler case, as the page table allocation and mapping occur entirely
on the host side.


From oupton at kernel.org  Mon Dec 15 09:50:23 2025
From: oupton at kernel.org (Oliver Upton)
Date: Mon, 15 Dec 2025 09:50:23 -0800
Subject: [PATCH v5 21/24] KVM: arm64: Inject recorded guest interrupts
In-Reply-To: <gsnt8qf72tv9.fsf@coltonlewis-kvm.c.googlers.com>
References: <aTioEWHu0ZbFCjR6@kernel.org>
 <gsnt8qf72tv9.fsf@coltonlewis-kvm.c.googlers.com>
Message-ID: <aUBKX8iqsptyTb4S@kernel.org>

On Fri, Dec 12, 2025 at 10:55:06PM +0000, Colton Lewis wrote:
> Oliver Upton <oupton at kernel.org> writes:
> 
> > In no situation should KVM be injecting a "recorded" IRQ. The overflow
> > condition of the PMU is well defined in the architecture and we should
> > implement *exactly* that.
> 
> When I say "record" I just meant "updating the virtual overflow register
> to reflect an overflow".

Right, consider changing the shortlog to read more along the lines of
"detect overflows for partitioned PMU" or similar.

> > On Tue, Dec 09, 2025 at 08:51:18PM +0000, Colton Lewis wrote:
> > > +/**
> > > + * kvm_pmu_part_overflow_status() - Determine if any guest counters
> > > have overflowed
> > > + * @vcpu: Ponter to struct kvm_vcpu
> > > + *
> > > + * Determine if any guest counters have overflowed and therefore an
> > > + * IRQ needs to be injected into the guest.
> > > + *
> > > + * Return: True if there was an overflow, false otherwise
> > > + */
> > > +bool kvm_pmu_part_overflow_status(struct kvm_vcpu *vcpu)
> > > +{
> > > +	struct arm_pmu *pmu = vcpu->kvm->arch.arm_pmu;
> > > +	u64 mask = kvm_pmu_guest_counter_mask(pmu);
> > > +	u64 pmovs = __vcpu_sys_reg(vcpu, PMOVSSET_EL0);
> > > +	u64 pmint = read_pmintenset();
> > > +	u64 pmcr = read_pmcr();
> 
> > How do we know that the vPMU has been loaded on the CPU at this point?
> 
> Because this is only called by kvm_pmu_update_state which is only called
> by kvm_pmu_update_state <- kvm_pmu_{flush,sync}_hwstate <-
> kvm_arch_vcpu_ioctl_run after a vcpu_load.

That's assuming the PMU is loaded eagerly which I thought we agreed it
would not be.

Thanks,
Oliver


From m.felsch at pengutronix.de  Mon Dec 15 09:54:36 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Mon, 15 Dec 2025 18:54:36 +0100
Subject: [PATCH v7 1/3] dt-bindings: soc: imx93-media-blk-ctrl: Add PDFC
 subnode to schema and example
In-Reply-To: <705773fc-5aba-4bff-b05e-272e1cd0262c@nxp.com>
References: <20251202-v6-18-topic-imx93-parallel-display-v7-0-2cce31d64608@pengutronix.de>
 <20251202-v6-18-topic-imx93-parallel-display-v7-1-2cce31d64608@pengutronix.de>
 <705773fc-5aba-4bff-b05e-272e1cd0262c@nxp.com>
Message-ID: <20251215175436.wwlgzxionq55zu27@pengutronix.de>

Hi Liu,

sorry I didn't fully answer you please see below.

On 25-12-08, Liu Ying wrote:
> Hi Marco,
> 
> On 12/02/2025, Marco Felsch wrote:
> > From: Liu Ying <victor.liu at nxp.com>
> > 
> > i.MX93 SoC mediamix blk-ctrl contains one DISPLAY_MUX register which
> > configures parallel display format by using the "PARALLEL_DISP_FORMAT"
> > field. Document the Parallel Display Format Configuration(PDFC) subnode
> > and add the subnode to example.
> > 
> > Signed-off-by: Liu Ying <victor.liu at nxp.com>
> > [m.felsch at pengutronix.de: port to v6.18-rc1]
> > [m.felsch at pengutronix.de: add bus-width]
> > Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
> > ---
> >  .../bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml | 92 ++++++++++++++++++++++
> >  1 file changed, 92 insertions(+)
> > 
> > diff --git a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> > index 34aea58094e55365a2f9c86092f637e533f954ff..6e2d86d9341c75108b492bcbabc8a560d8e707cd 100644
> > --- a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> > +++ b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> > @@ -26,6 +26,12 @@ properties:
> >    reg:
> >      maxItems: 1

...

> > +            properties:
> > +              endpoint:
> > +                $ref: /schemas/graph.yaml#/$defs/endpoint-base
> > +                unevaluatedProperties: false
> > +
> > +                properties:
> > +                  bus-width:
> 
> In v1-v5, I thought the output bus format can be determined by the sink
> device(a panel or a bridge) hence properties like bus-width were not needed.
> But, if this property is really needed, then reference video-interfaces.yaml
> since bus-width is documented there.  Should we reference bus-type defined
> in video-interfaces.yaml too?

You're right, the bus-width should be determined by the connected panel.
But there are cases where a 24-bit panel is connected but only the lower
18-bits are muxed. I added the bus-width property to handle this case.
In the end most users don't have to specify this since the correct
bus-width is coming from the panel bus-fmt.

> > +                    enum: [ 16, 18, 24 ]
> 
> The PARALLEL_DISP_FORMAT field of DISPLAY_MUX register says this IP supports
> below formats.  It seems that the enum here may tell RGB888, RGB666 and RGB565.
> How can we tell RGB555, YCbCr 24 bits and YUV444 then?
> 
> 000b RGB888 -> RGB888
> 001b RGB888 -> RGB666
> 010b RGB565 -> RGB565
> 011b RGB555 -> RGB555
> 100b YUV -> YCbCr 24 bits
> 101b YUV -> YUV444

This enum is about the physical bus width. RGB565 == 16-bit, YUV ==
24-bit.

That said, I don't think that you need to specify the bus-fmt since this
is coming from the panel. As said above, my itension with the bus-width
property is to provide integrators (dts-writers) a possibility to limit
the physical available bus width.

> > +                    description:
> > +                      Specify the physical parallel bus width.
> > +
> > +                      This property is optional if the display bus-width
> > +                      matches the SoC bus-width, e.g. a 18-bit RGB666 (display)
> > +                      is connected and all 18-bit data lanes are muxed to the
> 
> Per video-interfaces.yaml, s/data lanes/data lines/.  "data lanes" is a
> value for MIPI DSI/CSI, afaik.

I can go with "lines" if this is the preferred naming convention for
DRM.

> > +                      parallel-output pads.
> 
> How about just saying that this property is optional and by default it's 24?

I wanted to make it clear what this property does.

> > +                      This property must be set to 18 to cut only the LSBs
> > +                      instead of the MSBs in case a 24-bit RGB888 display is
> > +                      connected and only the lower 18-bit data lanes are muxed
> > +                      to the parallel-output pads.
> 
> The __lower__ 18-bit?  Isn't it the __MSB__ 6bit in each color component?

No, the LSB are cut, this is why it's so important to use this property
if you connected a external 24-bit display to the lower data
lines[17-0].

If you don't specify this property, the MSBs are cut/lost which is far
worse than using the LSB information.

Regards,
  Marco

> > +
> > +        required:
> > +          - port at 0
> > +          - port at 1
> > +
> > +    required:
> > +      - compatible
> > +      - reg
> > +      - ports
> > +
> >  allOf:
> >    - if:
> >        properties:
> > @@ -81,9 +141,12 @@ allOf:
> >              - const: isi
> >              - const: csi
> >              - const: dsi
> > +
> >  required:
> >    - compatible
> >    - reg
> > +  - '#address-cells'
> > +  - '#size-cells'
> >    - power-domains
> >    - clocks
> >    - clock-names
> > @@ -112,4 +175,33 @@ examples:
> >                 clock-names = "apb", "axi", "nic", "disp", "cam",
> >                               "pxp", "lcdif", "isi", "csi", "dsi";
> >        #power-domain-cells = <1>;
> > +      #address-cells = <1>;
> > +      #size-cells = <1>;
> > +
> > +      bridge at 60 {
> > +        compatible = "nxp,imx93-pdfc";
> > +        reg = <0x60 0x4>;
> > +
> > +        ports {
> > +          #address-cells = <1>;
> > +          #size-cells = <0>;
> > +
> > +          port at 0 {
> > +            reg = <0>;
> > +
> > +            pdfc_from_lcdif: endpoint {
> > +              remote-endpoint = <&lcdif_to_pdfc>;
> > +            };
> > +          };
> > +
> > +          port at 1 {
> > +            reg = <1>;
> > +
> > +            pdfc_to_panel: endpoint {
> > +              remote-endpoint = <&panel_from_pdfc>;
> > +              bus-width = <18>;
> > +            };
> > +          };
> > +        };
> > +      };
> >      };
> > 
> 
> 
> -- 
> Regards,
> Liu Ying
> 

-- 
#gernperDu 
#CallMeByMyFirstName

Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | https://www.pengutronix.de/ |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-9    |


From daniel at fooishbar.org  Mon Dec 15 09:55:13 2025
From: daniel at fooishbar.org (Daniel Stone)
Date: Mon, 15 Dec 2025 17:55:13 +0000
Subject: [PATCH v4 1/8] drm/rockchip: vop2: Switch impossible format
 conditional to WARN_ON
In-Reply-To: <14738785.uLZWGnKmhe@workhorse>
References: <20251211-vop2-atomic-fixups-v4-0-5d50eda26bf8@collabora.com>
 <20251211-vop2-atomic-fixups-v4-1-5d50eda26bf8@collabora.com>
 <20251211223822.6eeabb4d@pumpkin> <14738785.uLZWGnKmhe@workhorse>
Message-ID: <CAPj87rMeJWLm9J=7kMrEvbpzVOMiQc-TThSNE-Gfac7nhUB3bw@mail.gmail.com>

Hi,

On Fri, 12 Dec 2025 at 12:46, Nicolas Frattaroli
<nicolas.frattaroli at collabora.com> wrote:
> On Thursday, 11 December 2025 23:38:22 Central European Standard Time David Laight wrote:
> > Except that all the systems with PANIC_ON_WARN set will panic.
> > I believe that is somewhere over 90% of systems.
>
> I also like making up statistics. Warning here is the correct move
> in my opinion because this warning being triggered indicates a bug
> in the kernel code, and with PANIC_ON_WARN the user explicitly says
> they would rather panic in such a case than treat it as an abnormal
> condition that is recoverable.
>
> The reason why this condition ever occurring should be treated as an
> abnormal condition is because the DRM subsystem should guarantee we
> don't get a framebuffer of a format we didn't explicitly declare
> support for in the first place. So this condition being hit either
> means drm_universal_plane_init is broken, or the array of formats
> that's passed to it is out of sync with the conversion code, which
> is also a bug. Or someone managed to thoroughly hose DRM's internal
> kernel-side data structures, which is precisely the kind of thing
> PANIC_ON_WARN users want to abort for.

Yes, that's exactly it. We make all kinds of load-bearing assumptions
everywhere: that PM code won't pass in a NULL struct device pointer to
the resume handler, that our driver callbacks won't get called whilst
the device is runtime-suspended, etc. We could try to handle every
single one of those with if (clk == NULL) return 0; /* ??? */, or we
could not.

If you'd like, we could just delete every one of these checks and
replace them with comments, explaining what we assume the invariants
to be, and wait for an OOPS due to dereferencing invalid pointers. But
the MISRA style of 'handling' every possible impossible case is not
tractable.

Cheers,
Daniel


From daniel at fooishbar.org  Mon Dec 15 09:57:07 2025
From: daniel at fooishbar.org (Daniel Stone)
Date: Mon, 15 Dec 2025 17:57:07 +0000
Subject: [PATCH v4 2/8] drm/rockchip: vop2: Switch impossible pos
 conditional to WARN_ON
In-Reply-To: <20251211224102.5e079d70@pumpkin>
References: <20251211-vop2-atomic-fixups-v4-0-5d50eda26bf8@collabora.com>
 <20251211-vop2-atomic-fixups-v4-2-5d50eda26bf8@collabora.com> <20251211224102.5e079d70@pumpkin>
Message-ID: <CAPj87rO45oAihxRhshwvP=9N6oDtd+yRN-R4M3=TsFYmwjr1cA@mail.gmail.com>

Hi,

On Thu, 11 Dec 2025 at 22:41, David Laight <david.laight.linux at gmail.com> wrote:
> On Thu, 11 Dec 2025 21:40:32 +0100
> Nicolas Frattaroli <nicolas.frattaroli at collabora.com> wrote:
> > -     if (dest->y1 + dsp_h > adjusted_mode->vdisplay) {
> > -             drm_dbg_kms(vop2->drm,
> > -                         "vp%d %s dest->y1[%d] + dsp_h[%d] exceed mode vdisplay[%d]\n",
> > -                         vp->id, win->data->name, dest->y1, dsp_h, adjusted_mode->vdisplay);
> > -             dsp_h = adjusted_mode->vdisplay - dest->y1;
> > -             if (dsp_h < 4)
> > -                     dsp_h = 4;
> > -             src_h = dsp_h * src_h / drm_rect_height(dest);
> > -     }
> > +     /* drm_atomic_helper_check_plane_state calls drm_rect_clip_scaled for
> > +      * us, which keeps our planes bounded within the CRTC active area
> > +      */
> > +     WARN_ON(dest->x1 + dsp_w > adjusted_mode->hdisplay);
> > +     WARN_ON(dest->y1 + dsp_h > adjusted_mode->vdisplay);
> > +     WARN_ON(dsp_w < 4);
> > +     WARN_ON(dsp_h < 4);
> > +     WARN_ON(src_w < 4);
> > +     WARN_ON(src_h < 4);
>
> You need to do something when the tests fail.
> Carrying on regardless is never right.

When we arrive at this point, because the load-bearing assumption in
the comment has not been met, our options would be:
* display random incorrect content, and hope that we aren't reading
out of bounds from a buffer that's too small
* turn the display off
* there is no third option

Which are you suggesting?

Cheers,
Daniel


From lkp at intel.com  Mon Dec 15 09:59:37 2025
From: lkp at intel.com (kernel test robot)
Date: Tue, 16 Dec 2025 01:59:37 +0800
Subject: [PATCH v8 03/12] arm64/delay: move some constants out to a
 separate header
In-Reply-To: <20251215044919.460086-4-ankur.a.arora@oracle.com>
References: <20251215044919.460086-4-ankur.a.arora@oracle.com>
Message-ID: <202512160125.4rEePFm5-lkp@intel.com>

Hi Ankur,

kernel test robot noticed the following build errors:

[auto build test ERROR on bpf-next/master]
[also build test ERROR on bpf/master linus/master arnd-asm-generic/master v6.19-rc1 next-20251215]
[cannot apply to arm64/for-next/core bpf-next/net]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Ankur-Arora/asm-generic-barrier-Add-smp_cond_load_relaxed_timeout/20251215-130116
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master
patch link:    https://lore.kernel.org/r/20251215044919.460086-4-ankur.a.arora%40oracle.com
patch subject: [PATCH v8 03/12] arm64/delay: move some constants out to a separate header
config: sh-allmodconfig (https://download.01.org/0day-ci/archive/20251216/202512160125.4rEePFm5-lkp at intel.com/config)
compiler: sh4-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251216/202512160125.4rEePFm5-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512160125.4rEePFm5-lkp at intel.com/

All errors (new ones prefixed by >>):

>> drivers/soc/qcom/rpmh-rsc.c:29:10: fatal error: asm/delay-const.h: No such file or directory
      29 | #include <asm/delay-const.h>
         |          ^~~~~~~~~~~~~~~~~~~
   compilation terminated.


vim +29 drivers/soc/qcom/rpmh-rsc.c

     8	
     9	#include <linux/atomic.h>
    10	#include <linux/cpu_pm.h>
    11	#include <linux/delay.h>
    12	#include <linux/interrupt.h>
    13	#include <linux/io.h>
    14	#include <linux/iopoll.h>
    15	#include <linux/kernel.h>
    16	#include <linux/ktime.h>
    17	#include <linux/list.h>
    18	#include <linux/module.h>
    19	#include <linux/notifier.h>
    20	#include <linux/of.h>
    21	#include <linux/of_irq.h>
    22	#include <linux/of_platform.h>
    23	#include <linux/platform_device.h>
    24	#include <linux/pm_domain.h>
    25	#include <linux/pm_runtime.h>
    26	#include <linux/slab.h>
    27	#include <linux/spinlock.h>
    28	#include <linux/wait.h>
  > 29	#include <asm/delay-const.h>
    30	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From oupton at kernel.org  Mon Dec 15 10:06:22 2025
From: oupton at kernel.org (Oliver Upton)
Date: Mon, 15 Dec 2025 10:06:22 -0800
Subject: [PATCH v5 19/24] KVM: arm64: Implement lazy PMU context swaps
In-Reply-To: <gsntecoz2v87.fsf@coltonlewis-kvm.c.googlers.com>
References: <aTidfRwYLYwTfmK_@kernel.org>
 <gsntecoz2v87.fsf@coltonlewis-kvm.c.googlers.com>
Message-ID: <aUBOHnT1whwR3vbo@kernel.org>

On Fri, Dec 12, 2025 at 10:25:44PM +0000, Colton Lewis wrote:
> Oliver Upton <oupton at kernel.org> writes:
> 
> > On Tue, Dec 09, 2025 at 08:51:16PM +0000, Colton Lewis wrote:
> > > +enum vcpu_pmu_register_access {
> > > +	VCPU_PMU_ACCESS_UNSET,
> > > +	VCPU_PMU_ACCESS_VIRTUAL,
> > > +	VCPU_PMU_ACCESS_PHYSICAL,
> > > +};
> 
> > This is confusing. Even when the guest is accessing registers directly
> > on the CPU I'd still call that "hardware assisted virtualization" and
> > not "physical".
> 
> It was what I thought described the access pattern. Do you have another
> naming suggestion?

	PMU_STATE_FREE,
	PMU_STATE_GUEST_OWNED,

> > > +	kvm_pmu_set_physical_access(vcpu);
> > > +
> > >   	return true;
> > >   }
> 
> > Aren't there a ton of other registers the guest may access before
> > these two? Having generic PMU register accessors would allow you to
> > manage residence of PMU registers from a single spot.
> 
> Yes but these are the only two that use the old trap handlers. I also
> call set_physical_access from my fast path handler that handles all the
> other registers when partitioned.

The fast path accessors should only be accessing state already loaded
on the CPU. If the guest's PMU context isn't loaded on the CPU then it
should return to a kernel context and do a full put/load on the vCPU.

I'm not seeing how this all fits together but for lazy loading to work
correctly you need to evaluate the state of the vPMU at vcpu_load(). If
there exists an enabled PMC, set PMU_STATE_GUEST_OWNED and load it
upfront.

Otherwise, default to PMU_STATE_FREE until the next register access and
this whole thing resets when the vCPU is scheduled out. I had suggested
to you a while back that you should follow a similar model to the debug
registers, this is how they behave.

Thanks,
Oliver


From robh at kernel.org  Mon Dec 15 10:09:39 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Mon, 15 Dec 2025 12:09:39 -0600
Subject: [PATCH RFC 2/4] dt-bindings: net: nxp,s32-dwmac: Declare
 per-queue interrupts
In-Reply-To: <20251214-dwmac_multi_irq-v1-2-36562ab0e9f7@oss.nxp.com>
References: <20251214-dwmac_multi_irq-v1-0-36562ab0e9f7@oss.nxp.com>
 <20251214-dwmac_multi_irq-v1-2-36562ab0e9f7@oss.nxp.com>
Message-ID: <176582217911.3066791.4926710165988218857.robh@kernel.org>


On Sun, 14 Dec 2025 23:15:38 +0100, Jan Petrous (OSS) wrote:
> The DWMAC IP on supported SoCs has connected queue-based IRQ lines.
> 
> Signed-off-by: Jan Petrous (OSS) <jan.petrous at oss.nxp.com>
> ---
>  .../devicetree/bindings/net/nxp,s32-dwmac.yaml     | 40 +++++++++++++++++++---
>  1 file changed, 36 insertions(+), 4 deletions(-)
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/net/nxp,s32-dwmac.yaml: ignoring, error in schema: properties: interrupt-names
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/net/nxp,s32-dwmac.yaml: properties:interrupt-names: [{'items': [{'const': 'macirq'}, {'const': 'rx-queue-0'}, {'const': 'tx-queue-0'}, {'const': 'rx-queue-1'}, {'const': 'tx-queue-1'}, {'const': 'rx-queue-2'}, {'const': 'tx-queue-2'}, {'const': 'rx-queue-3'}, {'const': 'tx-queue-3'}, {'const': 'rx-queue-4'}, {'const': 'tx-queue-4'}]}] is not of type 'object', 'boolean'
	from schema $id: http://devicetree.org/meta-schemas/keywords.yaml
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/net/nxp,s32-dwmac.yaml: properties:interrupt-names: [{'items': [{'const': 'macirq'}, {'const': 'rx-queue-0'}, {'const': 'tx-queue-0'}, {'const': 'rx-queue-1'}, {'const': 'tx-queue-1'}, {'const': 'rx-queue-2'}, {'const': 'tx-queue-2'}, {'const': 'rx-queue-3'}, {'const': 'tx-queue-3'}, {'const': 'rx-queue-4'}, {'const': 'tx-queue-4'}]}] is not of type 'object', 'boolean'
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/net/nxp,s32-dwmac.yaml: properties:interrupt-names: [{'items': [{'const': 'macirq'}, {'const': 'rx-queue-0'}, {'const': 'tx-queue-0'}, {'const': 'rx-queue-1'}, {'const': 'tx-queue-1'}, {'const': 'rx-queue-2'}, {'const': 'tx-queue-2'}, {'const': 'rx-queue-3'}, {'const': 'tx-queue-3'}, {'const': 'rx-queue-4'}, {'const': 'tx-queue-4'}]}] is not of type 'object', 'boolean'
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/net/nxp,s32-dwmac.yaml: properties:interrupt-names: [{'items': [{'const': 'macirq'}, {'const': 'rx-queue-0'}, {'const': 'tx-queue-0'}, {'const': 'rx-queue-1'}, {'const': 'tx-queue-1'}, {'const': 'rx-queue-2'}, {'const': 'tx-queue-2'}, {'const': 'rx-queue-3'}, {'const': 'tx-queue-3'}, {'const': 'rx-queue-4'}, {'const': 'tx-queue-4'}]}] is not of type 'object', 'boolean'
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/net/nxp,s32-dwmac.yaml: properties:interrupt-names: [{'items': [{'const': 'macirq'}, {'const': 'rx-queue-0'}, {'const': 'tx-queue-0'}, {'const': 'rx-queue-1'}, {'const': 'tx-queue-1'}, {'const': 'rx-queue-2'}, {'const': 'tx-queue-2'}, {'const': 'rx-queue-3'}, {'const': 'tx-queue-3'}, {'const': 'rx-queue-4'}, {'const': 'tx-queue-4'}]}] is not of type 'object', 'boolean'
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/net/nxp,s32-dwmac.yaml: properties:interrupt-names: [{'items': [{'const': 'macirq'}, {'const': 'rx-queue-0'}, {'const': 'tx-queue-0'}, {'const': 'rx-queue-1'}, {'const': 'tx-queue-1'}, {'const': 'rx-queue-2'}, {'const': 'tx-queue-2'}, {'const': 'rx-queue-3'}, {'const': 'tx-queue-3'}, {'const': 'rx-queue-4'}, {'const': 'tx-queue-4'}]}] is not of type 'object', 'boolean'
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/net/nxp,s32-dwmac.yaml: properties:interrupt-names: [{'items': [{'const': 'macirq'}, {'const': 'rx-queue-0'}, {'const': 'tx-queue-0'}, {'const': 'rx-queue-1'}, {'const': 'tx-queue-1'}, {'const': 'rx-queue-2'}, {'const': 'tx-queue-2'}, {'const': 'rx-queue-3'}, {'const': 'tx-queue-3'}, {'const': 'rx-queue-4'}, {'const': 'tx-queue-4'}]}] is not of type 'object', 'boolean'
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/net/nxp,s32-dwmac.yaml: properties:interrupt-names: [{'items': [{'const': 'macirq'}, {'const': 'rx-queue-0'}, {'const': 'tx-queue-0'}, {'const': 'rx-queue-1'}, {'const': 'tx-queue-1'}, {'const': 'rx-queue-2'}, {'const': 'tx-queue-2'}, {'const': 'rx-queue-3'}, {'const': 'tx-queue-3'}, {'const': 'rx-queue-4'}, {'const': 'tx-queue-4'}]}] is not of type 'object', 'boolean'
Traceback (most recent call last):
  File "/usr/local/bin/dt-doc-validate", line 8, in <module>
    sys.exit(main())
             ~~~~^^
  File "/usr/local/lib/python3.13/dist-packages/dtschema/doc_validate.py", line 66, in main
    ret |= check_doc(f)
           ~~~~~~~~~^^^
  File "/usr/local/lib/python3.13/dist-packages/dtschema/doc_validate.py", line 37, in check_doc
    dtsch.check_schema_refs()
    ~~~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/local/lib/python3.13/dist-packages/dtschema/schema.py", line 241, in check_schema_refs
    self._check_schema_refs(resolver, self)
    ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/dtschema/schema.py", line 212, in _check_schema_refs
    self._check_schema_refs(resolver, v, parent=k, is_common=is_common,
    ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                            has_constraint=has_constraint)
                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/dtschema/schema.py", line 216, in _check_schema_refs
    self._check_schema_refs(resolver, schema[i], parent=parent, is_common=is_common,
    ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                            has_constraint=has_constraint)
                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/dtschema/schema.py", line 203, in _check_schema_refs
    ref_sch = resolver.lookup(schema['$ref']).contents
              ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 682, in lookup
    retrieved = self._registry.get_or_retrieve(uri)
  File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 422, in get_or_retrieve
    registry = self.crawl()
  File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 500, in crawl
    id = resource.id()
  File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 231, in id
    id = self._specification.id_of(self.contents)
  File "/usr/local/lib/python3.13/dist-packages/referencing/jsonschema.py", line 50, in _dollar_id
    return contents.get("$id")
           ^^^^^^^^^^^^
AttributeError: 'list' object has no attribute 'get'
Lexical error: Documentation/devicetree/bindings/net/nxp,s32-dwmac.example.dts:58.13-17 Unexpected 'snps'
Error: Documentation/devicetree/bindings/net/nxp,s32-dwmac.example.dts:58.13-17 syntax error
FATAL ERROR: Unable to parse input tree
make[2]: *** [scripts/Makefile.dtbs:141: Documentation/devicetree/bindings/net/nxp,s32-dwmac.example.dtb] Error 1
make[2]: *** Waiting for unfinished jobs....
make[1]: *** [/builds/robherring/dt-review-ci/linux/Makefile:1559: 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/20251214-dwmac_multi_irq-v1-2-36562ab0e9f7 at oss.nxp.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.



From david.laight.linux at gmail.com  Mon Dec 15 10:16:05 2025
From: david.laight.linux at gmail.com (David Laight)
Date: Mon, 15 Dec 2025 18:16:05 +0000
Subject: [PATCH v4 1/8] drm/rockchip: vop2: Switch impossible format
 conditional to WARN_ON
In-Reply-To: <CAPj87rMeJWLm9J=7kMrEvbpzVOMiQc-TThSNE-Gfac7nhUB3bw@mail.gmail.com>
References: <20251211-vop2-atomic-fixups-v4-0-5d50eda26bf8@collabora.com>
	<20251211-vop2-atomic-fixups-v4-1-5d50eda26bf8@collabora.com>
	<20251211223822.6eeabb4d@pumpkin>
	<14738785.uLZWGnKmhe@workhorse>
	<CAPj87rMeJWLm9J=7kMrEvbpzVOMiQc-TThSNE-Gfac7nhUB3bw@mail.gmail.com>
Message-ID: <20251215181605.29f6afcc@pumpkin>

On Mon, 15 Dec 2025 17:55:13 +0000
Daniel Stone <daniel at fooishbar.org> wrote:

> Hi,
> 
> On Fri, 12 Dec 2025 at 12:46, Nicolas Frattaroli
> <nicolas.frattaroli at collabora.com> wrote:
> > On Thursday, 11 December 2025 23:38:22 Central European Standard Time David Laight wrote:  
> > > Except that all the systems with PANIC_ON_WARN set will panic.
> > > I believe that is somewhere over 90% of systems.  
> >
> > I also like making up statistics. Warning here is the correct move
> > in my opinion because this warning being triggered indicates a bug
> > in the kernel code, and with PANIC_ON_WARN the user explicitly says
> > they would rather panic in such a case than treat it as an abnormal
> > condition that is recoverable.
> >
> > The reason why this condition ever occurring should be treated as an
> > abnormal condition is because the DRM subsystem should guarantee we
> > don't get a framebuffer of a format we didn't explicitly declare
> > support for in the first place. So this condition being hit either
> > means drm_universal_plane_init is broken, or the array of formats
> > that's passed to it is out of sync with the conversion code, which
> > is also a bug. Or someone managed to thoroughly hose DRM's internal
> > kernel-side data structures, which is precisely the kind of thing
> > PANIC_ON_WARN users want to abort for.  
> 
> Yes, that's exactly it. We make all kinds of load-bearing assumptions
> everywhere: that PM code won't pass in a NULL struct device pointer to
> the resume handler, that our driver callbacks won't get called whilst
> the device is runtime-suspended, etc. We could try to handle every
> single one of those with if (clk == NULL) return 0; /* ??? */, or we
> could not.
> 
> If you'd like, we could just delete every one of these checks and
> replace them with comments, explaining what we assume the invariants
> to be, and wait for an OOPS due to dereferencing invalid pointers. But
> the MISRA style of 'handling' every possible impossible case is not
> tractable.

Especially since it is often easier to debug the NULL pointer reference
that the work out why a BUG_ON(!ptr) happened.
(In the former case you should have the contents of all the registers
making it easier to backtrack to where the NULL came from.)

	David

> 
> Cheers,
> Daniel



From catalin.marinas at arm.com  Mon Dec 15 10:16:38 2025
From: catalin.marinas at arm.com (Catalin Marinas)
Date: Mon, 15 Dec 2025 18:16:38 +0000
Subject: [PATCH v2 0/2] efi/arm64: Simplify SVE/SME state preserve/restore
In-Reply-To: <20251206190114.892262-4-ardb@kernel.org>
References: <20251206190114.892262-4-ardb@kernel.org>
Message-ID: <176582226393.1756467.4367015850424872029.b4-ty@arm.com>

On Sat, 06 Dec 2025 20:01:15 +0100, Ard Biesheuvel wrote:
> The EFI specific SVE/SME state preserve/restore logic is unneeded, and
> can be removed. Patch #1 adds some lkdtm test cases to emulate the
> condition under which this code might be called.
> 
> v2:
> - Document that BUG_IN_HARDIRQ and PANIC_IN_HARDIRQ will crash the
>   system.
> - Add Kees's R-b
> - Rebase onto torvalds's tree of today so it is expected to apply
>   cleanly to -rc1
> 
> [...]

Applied to arm64 (for-next/fixes), thanks!

(not really a fix but postponed applying it for -rc1 due to conflicts)

[1/2] lkdtm/bugs: Add cases for BUG and PANIC occurring in hardirq context
      https://git.kernel.org/arm64/c/eb972eab0794
[2/2] arm64/efi: Remove unneeded SVE/SME fallback preserve/store handling
      https://git.kernel.org/arm64/c/63de2b3859ba

-- 
Catalin


From catalin.marinas at arm.com  Mon Dec 15 10:17:16 2025
From: catalin.marinas at arm.com (Catalin Marinas)
Date: Mon, 15 Dec 2025 18:17:16 +0000
Subject: [PATCH] arm64: mm: Simplify check in arch_kfence_init_pool()
In-Reply-To: <20251119130016.283216-1-kevin.brodsky@arm.com>
References: <20251119130016.283216-1-kevin.brodsky@arm.com>
Message-ID: <176582226392.1756467.15532050189041554427.b4-ty@arm.com>

On Wed, 19 Nov 2025 13:00:16 +0000, Kevin Brodsky wrote:
> TL;DR: checking force_pte_mapping() in arch_kfence_init_pool() is
> sufficient
> 
> Commit ce2b3a50ad92 ("arm64: mm: Don't sleep in
> split_kernel_leaf_mapping() when in atomic context") recently added
> an arm64 implementation of arch_kfence_init_pool() to ensure that
> the KFENCE pool is PTE-mapped. Assuming that the pool was not
> initialised early, block splitting is necessary if the linear
> mapping is not fully PTE-mapped, in other words if
> force_pte_mapping() is false.
> 
> [...]

Applied to arm64 (for-next/fixes), thanks!

[1/1] arm64: mm: Simplify check in arch_kfence_init_pool()
      https://git.kernel.org/arm64/c/b7737c38e7cb

-- 
Catalin


From catalin.marinas at arm.com  Mon Dec 15 10:17:37 2025
From: catalin.marinas at arm.com (Catalin Marinas)
Date: Mon, 15 Dec 2025 18:17:37 +0000
Subject: [PATCH] arm64/gcs: Flush the GCS locking state on exec
In-Reply-To: <20251129-arm64-gcs-flush-lock-v1-1-902b3ba6f39d@kernel.org>
References: <20251129-arm64-gcs-flush-lock-v1-1-902b3ba6f39d@kernel.org>
Message-ID: <176582226393.1756467.9855121048488078844.b4-ty@arm.com>

On Sat, 29 Nov 2025 00:48:45 +0000, Mark Brown wrote:
> When we exec a new task we forget to flush the set of locked GCS mode bits.
> Since we do flush the rest of the state this means that if GCS is locked
> the new task will be unable to enable GCS, it will be locked as being
> disabled. Add the expected flush.
> 
> 

Applied to arm64 (for-next/fixes), thanks!

[1/1] arm64/gcs: Flush the GCS locking state on exec
      https://git.kernel.org/arm64/c/98a97bf41528

-- 
Catalin


From iuliana.prodan at nxp.com  Mon Dec 15 10:32:27 2025
From: iuliana.prodan at nxp.com (Iuliana Prodan)
Date: Mon, 15 Dec 2025 20:32:27 +0200
Subject: [PATCH] remoteproc: imx_rproc: Ues sync handling in rx_callback
 for i.MX7ULP suspend
In-Reply-To: <20251215-imx7ulp_rproc-v1-1-4e96cebc4bc6@nxp.com>
References: <20251215-imx7ulp_rproc-v1-1-4e96cebc4bc6@nxp.com>
Message-ID: <8c00c09f-da9e-4630-a3d7-586ed29116f3@nxp.com>

On 12/15/2025 9:26 AM, Jacky Bai wrote:
> On i.MX7ULP platform, certain drivers that depend on rpmsg may need
> to send an rpmsg request and receive an acknowledgment from the
> remote core during the late_suspend stage. In the current imx_rproc
> implementation, rx_callback defers message handling to a workqueue.
> However, this deferred work may not execute before the system enters
> the noirq_suspend stage. When that happens, pending mailbox IRQs
> will cause the suspend sequence to abort.
> 
> To address this, handle incoming messages synchronously within
> rx_callback when running on i.MX7ULP. This ensures the message is
> processed immediately, allows the mailbox IRQ to be cleared in time,
> and prevents suspend failures.
> 
> Signed-off-by: Jacky Bai <ping.bai at nxp.com>
> ---
>   drivers/remoteproc/imx_rproc.c | 49 ++++++++++++++++++++++++++++++++++++++++--
>   drivers/remoteproc/imx_rproc.h |  1 +
>   2 files changed, 48 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
> index 3be8790c14a2ccc789dd40508ec274000ec09978..1127c56388fd94f296c80db5c01a5d431d669c4d 100644
> --- a/drivers/remoteproc/imx_rproc.c
> +++ b/drivers/remoteproc/imx_rproc.c
> @@ -22,6 +22,7 @@
>   #include <linux/reboot.h>
>   #include <linux/regmap.h>
>   #include <linux/remoteproc.h>
> +#include <linux/suspend.h>
>   #include <linux/workqueue.h>
>   
>   #include "imx_rproc.h"
> @@ -111,11 +112,13 @@ struct imx_rproc {
>   	void __iomem			*rsc_table;
>   	struct imx_sc_ipc		*ipc_handle;
>   	struct notifier_block		rproc_nb;
> +	struct notifier_block		pm_nb;
>   	u32				rproc_pt;	/* partition id */
>   	u32				rsrc_id;	/* resource id */
>   	u32				entry;		/* cpu start address */
>   	u32				core_index;
>   	struct dev_pm_domain_list	*pd_list;
> +	bool				use_sync_rx;
>   };
>   
>   static const struct imx_rproc_att imx_rproc_att_imx93[] = {
> @@ -725,7 +728,10 @@ static void imx_rproc_rx_callback(struct mbox_client *cl, void *msg)
>   	struct rproc *rproc = dev_get_drvdata(cl->dev);
>   	struct imx_rproc *priv = rproc->priv;
>   
> -	queue_work(priv->workqueue, &priv->rproc_work);
> +	if (priv->use_sync_rx)
> +		idr_for_each(&rproc->notifyids, imx_rproc_notified_idr_cb, rproc);
> +	else
> +		queue_work(priv->workqueue, &priv->rproc_work);
>   }
>   
>   static int imx_rproc_xtr_mbox_init(struct rproc *rproc, bool tx_block)
> @@ -1009,6 +1015,38 @@ static int imx_rproc_sys_off_handler(struct sys_off_data *data)
>   	return NOTIFY_DONE;
>   }
>   
> +static int imx_rproc_pm_notify(struct notifier_block *nb,
> +	unsigned long action, void *data)
> +{
> +	int ret;
> +	struct imx_rproc *priv = container_of(nb, struct imx_rproc, pm_nb);
> +
> +	imx_rproc_free_mbox(priv->rproc);

Here you free mailbox unconditinally.
> +
> +	switch (action) {
> +	case PM_SUSPEND_PREPARE:

When switching to sync mode, any pending work in the workqueue should be 
flushed to avoid processing messages twice.
> +		ret = imx_rproc_xtr_mbox_init(priv->rproc, false);
> +		if (ret) {
> +			dev_err(&priv->rproc->dev, "Failed to request non-blocking mbox\n");
> +			return NOTIFY_BAD;
> +		}
> +		priv->use_sync_rx = true;
> +		break;
> +	case PM_POST_SUSPEND:
> +		ret = imx_rproc_xtr_mbox_init(priv->rproc, true);
> +		if (ret) {
> +			dev_err(&priv->rproc->dev, "Failed to request blocking mbox\n");
> +			return NOTIFY_BAD;
> +		}

If imx_rproc_xtr_mbox_init() fails in either case, the mailbox channels 
remain freed but the function returns NOTIFY_BAD. The system may 
continue with freed mailbox channels.

Only free the mailbox if re-initialization succeeds, or ensure proper 
cleanup on failure.

> +		priv->use_sync_rx = false;
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	return NOTIFY_OK;
> +}
> +
>   static void imx_rproc_destroy_workqueue(void *data)
>   {
>   	struct workqueue_struct *workqueue = data;
> @@ -1103,6 +1141,13 @@ static int imx_rproc_probe(struct platform_device *pdev)
>   			return dev_err_probe(dev, ret, "register restart handler failure\n");
>   	}
>   
> +	if (dcfg->flags & IMX_RPROC_NEED_PM_SYNC) {
> +		priv->pm_nb.notifier_call = imx_rproc_pm_notify;
> +		ret = register_pm_notifier(&priv->pm_nb);
> +		if (ret)
> +			return dev_err_probe(dev, ret, "register pm notifier failure\n");
> +	}
> +

The PM notifier is registered in probe but never unregistered in remove 
or error paths.

Thanks,
Iulia

>   	pm_runtime_enable(dev);
>   	ret = pm_runtime_resume_and_get(dev);
>   	if (ret)
> @@ -1202,7 +1247,7 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx8ulp = {
>   static const struct imx_rproc_dcfg imx_rproc_cfg_imx7ulp = {
>   	.att		= imx_rproc_att_imx7ulp,
>   	.att_size	= ARRAY_SIZE(imx_rproc_att_imx7ulp),
> -	.flags		= IMX_RPROC_NEED_SYSTEM_OFF,
> +	.flags		= IMX_RPROC_NEED_SYSTEM_OFF | IMX_RPROC_NEED_PM_SYNC,
>   };
>   
>   static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = {
> diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h
> index 1b2d9f4d6d19dcdc215be97f7e2ab3488281916a..0e3e460cef4ed9340fb4977183e03143c84764af 100644
> --- a/drivers/remoteproc/imx_rproc.h
> +++ b/drivers/remoteproc/imx_rproc.h
> @@ -18,6 +18,7 @@ struct imx_rproc_att {
>   /* dcfg flags */
>   #define IMX_RPROC_NEED_SYSTEM_OFF	BIT(0)
>   #define IMX_RPROC_NEED_CLKS		BIT(1)
> +#define IMX_RPROC_NEED_PM_SYNC		BIT(2)
>   
>   struct imx_rproc_plat_ops {
>   	int (*start)(struct rproc *rproc);
> 
> ---
> base-commit: 5ce74bc1b7cb2732b22f9c93082545bc655d6547
> change-id: 20251211-imx7ulp_rproc-57999329239b
> 
> Best regards,



From dan.carpenter at linaro.org  Mon Dec 15 10:33:54 2025
From: dan.carpenter at linaro.org (Dan Carpenter)
Date: Mon, 15 Dec 2025 21:33:54 +0300
Subject: [PATCH v2 0/4] s32g: Use a syscon for GPR
In-Reply-To: <aUAvwRmIZBC0W6ql@lizhi-Precision-Tower-5810>
References: <cover.1765806521.git.dan.carpenter@linaro.org>
 <aUAvwRmIZBC0W6ql@lizhi-Precision-Tower-5810>
Message-ID: <aUBUkuLf7NHtLSl1@stanley.mountain>

On Mon, Dec 15, 2025 at 10:56:49AM -0500, Frank Li wrote:
> On Mon, Dec 15, 2025 at 05:41:43PM +0300, Dan Carpenter wrote:
> > The s32g devices have a GPR register region which holds a number of
> > miscellaneous registers.  Currently only the stmmac/dwmac-s32.c uses
> > anything from there and we just add a line to the device tree to
> > access that GMAC_0_CTRL_STS register:
> >
> >                         reg = <0x4033c000 0x2000>, /* gmac IP */
> >                               <0x4007c004 0x4>;    /* GMAC_0_CTRL_STS */
> >
> > We still have to maintain backwards compatibility to this format,
> > of course, but it would be better to access these through a syscon.
> > First of all, putting all the registers together is more organized
> > and shows how the hardware actually is implemented.  Secondly, in
> > some versions of this chipset those registers can only be accessed
> > via SCMI, if the registers aren't grouped together each driver will
> > have to create a whole lot of if then statements to access it via
> > IOMEM or via SCMI,
> 
> Does SCMI work as regmap? syscon look likes simple, but missed abstract
> in overall.
> 

The SCMI part of this is pretty complicated and needs discussion.  It
might be that it requires a vendor extension.  Right now, the out of
tree code uses a nvmem vendor extension but that probably won't get
merged upstream.

But in theory, it's fairly simple, you can write a regmap driver and
register it as a syscon and everything that was accessing nxp,phy-sel
accesses the same register but over SCMI.

> You still use regmap by use MMIO. /* GMAC_0_CTRL_STS */
> 
> regmap = devm_regmap_init_mmio(dev, sts_offset, &regmap_config);
> 

You can use have an MMIO syscon, or you can create a custom driver
and register it as a syscon using of_syscon_register_regmap().

> So all code can use regmap function without if-then statements if SCMI work
> as regmap.
> 

regards,
dan carpenter



From david at ixit.cz  Mon Dec 15 10:53:37 2025
From: david at ixit.cz (David Heidelberg)
Date: Mon, 15 Dec 2025 19:53:37 +0100
Subject: [PATCH v3 2/3] ARM: dts: exynos: Add Google Manta (Nexus 10)
In-Reply-To: <20251215-lat3st-staging-v3-2-2e4914b64dd8@timmermann.space>
References: <20251215-lat3st-staging-v3-0-2e4914b64dd8@timmermann.space>
 <20251215-lat3st-staging-v3-2-2e4914b64dd8@timmermann.space>
Message-ID: <c62d6c99-0c8d-40e5-95fc-ae73ecaca926@ixit.cz>

Hello Lucas,

thanks for the sending Nexus 10 upstream, see few nitpicks below:

On 15/12/2025 16:05, Lukas Timmermann wrote:
> From: Alexandre Marquet <tb at a-marquet.fr>
> 
> Manta is the code name for Google Nexus 10, and was manufactured by
> Samsung with their Exynos5250 SoC.
> This patch adds initial device-tree file for this board.
> 
> Signed-off-by: Alexandre Marquet <tb at a-marquet.fr>
> Co-developed-by: Lukas Timmermann <linux at timmermann.space>
> Signed-off-by: Lukas Timmermann <linux at timmermann.space>
> ---
>   arch/arm/boot/dts/samsung/Makefile             |   1 +
>   arch/arm/boot/dts/samsung/exynos5250-manta.dts | 511 +++++++++++++++++++++++++
>   2 files changed, 512 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/samsung/Makefile b/arch/arm/boot/dts/samsung/Makefile
> index 7becf36656b1..e0143ee8c82d 100644
> --- a/arch/arm/boot/dts/samsung/Makefile
> +++ b/arch/arm/boot/dts/samsung/Makefile
> @@ -26,6 +26,7 @@ dtb-$(CONFIG_ARCH_EXYNOS4) += \
>   	exynos4412-trats2.dtb
>   dtb-$(CONFIG_ARCH_EXYNOS5) += \
>   	exynos5250-arndale.dtb \
> +	exynos5250-manta.dtb \
>   	exynos5250-smdk5250.dtb \
>   	exynos5250-snow.dtb \
>   	exynos5250-snow-rev5.dtb \
> diff --git a/arch/arm/boot/dts/samsung/exynos5250-manta.dts b/arch/arm/boot/dts/samsung/exynos5250-manta.dts
> new file mode 100644
> index 000000000000..0f006590576c
> --- /dev/null
> +++ b/arch/arm/boot/dts/samsung/exynos5250-manta.dts
> @@ -0,0 +1,511 @@
> +// SPDX-License-Identifier: GPL-2.0

you could use here modern SPDX I guess (GPL-2.0-only)

> +/*
> + * Google Manta (Nexus 10) board device tree source
> + *
> + * Copyright (c) 2023-2025 Alexandre Marquet
> + * Copyright (c) 2025 Lukas Timmermann
> + */
> +
> +/dts-v1/;
> +#include <dt-bindings/leds/common.h>
> +#include <dt-bindings/gpio/gpio.h>
> +#include <dt-bindings/clock/maxim,max77686.h>
> +#include <dt-bindings/input/linux-event-codes.h>
> +#include "exynos-pinctrl.h"
> +#include "exynos5250.dtsi"
> +#include "exynos-mfc-reserved-memory.dtsi"
> +
> +/ {
> +	model = "Google Nexus 10";
> +	compatible = "google,manta", "samsung,exynos5250", "samsung,exynos5";
> +
> +	aliases {
> +		mmc0 = &mmc_0; /* eMMC */
> +		mmc1 = &mmc_1; /* WiFi */
> +	};
> +
> +	bmp180_vdda_reg: regulator-bmp180-vdda {
> +		compatible = "regulator-fixed";
> +		regulator-name = "BMP180_VDDA";
> +	};
something-something-regulator (all occurences within the DTS)

> +
> +	bmp180_vddd_reg: regulator-bmp180-vddd {
> +		compatible = "regulator-fixed";
> +		regulator-name = "BMP180_VDDD";
> +	};
> +
> +	chosen {
> +		stdout-path = &serial_2;
> +	};
> +
> +	fixed-rate-clocks {
> +		xxti {
> +			compatible = "samsung,clock-xxti";
> +			clock-frequency = <24000000>;
> +		};
> +	};
> +
> +	gpio-keys {
> +		compatible = "gpio-keys";
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&gpio_keys>;
> +
> +		key-down {
> +			gpios = <&gpx2 1 GPIO_ACTIVE_LOW>;
> +			linux,code = <KEY_VOLUMEDOWN>;
> +			label = "volume down";
> +			debounce-interval = <5>;
> +		};
> +
> +		key-up {
> +			gpios = <&gpx2 0 GPIO_ACTIVE_LOW>;
> +			linux,code = <KEY_VOLUMEUP>;
> +			label = "volume up";
> +			debounce-interval = <5>;
> +		};
> +
> +		key-power {
> +			gpios = <&gpx2 7 GPIO_ACTIVE_LOW>;
> +			linux,code = <KEY_POWER>;
> +			label = "power";
> +			debounce-interval = <5>;
> +			wakeup-source;
> +		};
> +
> +		lid-switch {
> +			label = "Lid";
> +			gpios = <&gpx1 3 GPIO_ACTIVE_LOW>;
> +			linux,input-type = <5>; /* EV_SW */
> +			linux,code = <0>; /* SW_LID */
> +			debounce-interval = <10>;
> +			wakeup-source;
> +		};
> +	};
> +
> +	multi-led {
> +		compatible = "leds-group-multicolor";
> +		color = <LED_COLOR_ID_RGB>;
> +		function = LED_FUNCTION_STATUS;
> +		leds = <&status_red>, <&status_green>, <&status_blue>, <&status_white>;
> +	};
> +
> +	pwrseq: mmc1-pwrseq {
> +		compatible = "mmc-pwrseq-simple";
> +		reset-gpios = <&gpv1 0 GPIO_ACTIVE_LOW>;
> +		pinctrl-0 = <&wlan_pmena>;
> +		pinctrl-names = "default";
> +		clocks = <&max77686 MAX77686_CLK_PMIC>;
> +		clock-names = "ext_clock";
> +		post-power-on-delay-ms = <300>;
> +		power-off-delay-us = <50>;
> +	};
> +
> +	firmware at 203f000 {
> +		compatible = "samsung,secure-firmware";
> +		reg = <0x0204efff 0x1000>;
> +	};
> +
> +	memory at 40000000 {
> +		device_type = "memory";
> +		reg = <0x40000000 0x20000000>,
> +		      <0x60000000 0x20000000>,
> +		      <0x80000000 0x20000000>,
> +		      <0xa0000000 0x1ff00000>;
> +	};
> +};
> +
> +&clock {
> +	assigned-clocks = <&clock CLK_FOUT_APLL>;
> +	assigned-clock-rates = <1000000000>;
> +};
> +
> +&cpu0 {
> +	cpu0-supply = <&buck2_reg>;
> +};
> +
> +&ehci {
> +	status = "disabled";
> +};
> +
> +&i2c_0 {
> +	status = "okay";

status should be before first sub-node (none in this case), with 
preceding newline, please change all occurences


> +	samsung,i2c-sda-delay = <100>;
> +	samsung,i2c-slave-addr = <0x10>;
> +};
> +
> +&i2c_1 {
> +	status = "okay";
> +
> +	pressure at 77 {
> +		compatible = "bosch,bmp180";
> +		reg = <0x77>;
> +		vddd-supply = <&bmp180_vddd_reg>;
> +		vdda-supply = <&bmp180_vdda_reg>;
> +	};
> +
> +	imu at 68 {
> +		compatible = "invensense,mpu6050";
> +		reg = <0x68>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&acc_int>;
> +		interrupt-parent = <&gpx1>;
> +		interrupts = <4 IRQ_TYPE_EDGE_RISING>;
> +		mount-matrix = "0",  "-1",  "0",
> +				"-1",  "0",  "0",
> +				"0",  "0", "-1";
> +
> +		i2c-gate {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +
> +			magnetometer at c {
> +				compatible = "asahi-kasei,ak8963";
> +				reg = <0x0c>;
> +				pinctrl-names = "default";
> +				pinctrl-0 = <&msense_rst>;
> +				mount-matrix = "-1",  "0",  "0",
> +						"0",  "1",  "0",
> +						"0",  "0", "-1";
> +			};
> +		};
> +	};
> +
> +	led-controller at 42 {
> +		compatible = "ams,as3668";
> +		reg = <0x42>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		status_red: led at 0 {
> +			reg = <0x0>;
> +			function = LED_FUNCTION_STATUS;
> +			color = <LED_COLOR_ID_RED>;
> +		};
> +
> +		status_green: led at 1 {
> +			reg = <0x1>;
> +			function = LED_FUNCTION_STATUS;
> +			color = <LED_COLOR_ID_GREEN>;
> +		};
> +
> +		status_blue: led at 2 {
> +			reg = <0x2>;
> +			function = LED_FUNCTION_STATUS;
> +			color = <LED_COLOR_ID_BLUE>;
> +		};
> +
> +		status_white: led at 3 {
> +			reg = <0x3>;
> +			function = LED_FUNCTION_STATUS;
> +			color = <LED_COLOR_ID_WHITE>;
> +		};
> +	};
> +};
> +
> +&i2c_2 {
> +	status = "okay";
> +
> +	light-sensor at 23 {
> +		compatible = "rohm,bh1721";
> +		reg = <0x23>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&bh1721fvc_reset>;
> +		reset-gpios = <&gph1 2 GPIO_ACTIVE_LOW>;
> +	};
> +
> +	onewire at 18 {
> +		compatible = "maxim,ds2484";
> +		reg = <0x18>;
> +
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&onewire_sleep>;
> +	};
> +};
> +
> +&i2c_5 {
> +	status = "okay";
> +	samsung,i2c-sda-delay = <100>;
> +
> +	max77686: pmic at 9 {
> +		compatible = "maxim,max77686";
> +		reg = <0x09>;
> +		interrupt-parent = <&gpx0>;
> +		interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&max77686_irq>;
> +		#clock-cells = <1>;
> +		wakeup-source;
> +
> +		voltage-regulators {
> +			ldo3_reg: LDO3 {
> +				regulator-name = "VCC_1.8V_AP";
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <1800000>;
> +				regulator-always-on;
> +				regulator-boot-on;
> +			};
> +			ldo8_reg: LDO8 {
> +				regulator-name = "VMIPI_1.0V";
> +				regulator-min-microvolt = <1000000>;
> +				regulator-max-microvolt = <1000000>;
> +				regulator-always-on;
> +				regulator-boot-on;
> +			};
> +			ldo9_reg: LDO9 {
> +				regulator-name = "TOUCH_VDD_1.8V";
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <1800000>;
> +			};
> +			ldo10_reg: LDO10 {
> +				regulator-name = "VMIPI_1.8V";
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <1800000>;
> +				regulator-always-on;
> +				regulator-boot-on;
> +			};
> +			ldo12_reg: LDO12 {
> +				regulator-name = "VUOTG_3.0V";
> +				regulator-min-microvolt = <3000000>;
> +				regulator-max-microvolt = <3000000>;
> +				regulator-always-on;
> +				regulator-boot-on;
> +			};
> +			ldo15_reg: LDO15 {
> +				regulator-name = "VHSIC_1.0V";
> +				regulator-min-microvolt = <1000000>;
> +				regulator-max-microvolt = <1000000>;
> +				regulator-always-on;
> +				regulator-boot-on;
> +			};
> +			ldo16_reg: LDO16 {
> +				regulator-name = "VHSIC_1.8V";
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <1800000>;
> +				regulator-always-on;
> +				regulator-boot-on;
> +			};
> +			ldo17_reg: LDO17 {
> +				regulator-name = "5M_CORE_1.5V";
> +				regulator-min-microvolt = <1500000>;
> +				regulator-max-microvolt = <1500000>;
> +			};
> +			ldo18_reg: LDO18 {
> +				regulator-name = "CAM_IO_1.8V";
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <1800000>;
> +			};
> +			ldo19_reg: LDO19 {
> +				regulator-name = "VT_CAM_1.8V";
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <1800000>;
> +			};
> +			ldo20_reg: LDO20 {
> +				regulator-name = "TA_CHECK_1.35V";
> +				regulator-min-microvolt = <1350000>;
> +				regulator-max-microvolt = <1350000>;
> +			};
> +			ldo23_reg: LDO23 {
> +				regulator-name = "TSP_AVDD_2.8V";
> +				regulator-min-microvolt = <2800000>;
> +				regulator-max-microvolt = <2800000>;
> +			};
> +			ldo24_reg: LDO24 {
> +				regulator-name = "CAM_AF_2.8V";
> +				regulator-min-microvolt = <2800000>;
> +				regulator-max-microvolt = <2800000>;
> +			};
> +			ldo25_reg: LDO25 {
> +				regulator-name = "VADC_3.3V";
> +				regulator-min-microvolt = <3300000>;
> +				regulator-max-microvolt = <3300000>;
> +				regulator-always-on;
> +				regulator-boot-on;
> +			};
> +			buck1_reg: BUCK1 {
> +				regulator-name = "vdd_mif";
> +				regulator-min-microvolt = <850000>;
> +				regulator-max-microvolt = <1200000>;
> +				regulator-always-on;
> +				regulator-boot-on;
> +			};
> +			buck2_reg: BUCK2 {
> +				regulator-name = "vdd_arm";
> +				regulator-min-microvolt = <850000>;
> +				regulator-max-microvolt = <1200000>;
> +				regulator-always-on;
> +				regulator-boot-on;
> +			};
> +			buck3_reg: BUCK3 {
> +				regulator-name = "vdd_int";
> +				regulator-min-microvolt = <850000>;
> +				regulator-max-microvolt = <1200000>;
> +				regulator-always-on;
> +				regulator-boot-on;
> +			};
> +			buck4_reg: BUCK4 {
> +				regulator-name = "vdd_g3d";
> +				regulator-min-microvolt = <850000>;
> +				regulator-max-microvolt = <1200000>;
> +				regulator-boot-on;
> +			};
> +		};
> +	};
> +};
> +
> +&mali {
> +	status = "okay";
> +	mali-supply = <&buck4_reg>;
> +};
> +
> +&mixer {
> +	status = "okay";
> +};
> +
> +/* eMMC */
> +&mmc_0 {
> +	status = "okay";
> +	non-removable;
> +	max-frequency = <200000000>;
> +	sd-uhs-ddr50;
> +	mmc-ddr-1_8v;
> +	cap-mmc-hw-reset;
> +	mmc-hs200-1_8v;
> +	bus-width = <8>;
> +	card-detect-delay = <200>;
> +	samsung,dw-mshc-ciu-div = <3>;
> +	samsung,dw-mshc-sdr-timing = <1 2>;
> +	samsung,dw-mshc-ddr-timing = <2 3>;
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
> +};
> +
> +/* WiFi */
> +&mmc_1 {
> +	status = "okay";
> +	non-removable;
> +	max-frequency = <100000000>;
> +	sd-uhs-sdr50;
> +	cap-sd-highspeed;
> +	keep-power-in-suspend;
> +	bus-width = <4>;
> +	card-detect-delay = <0>;
> +	samsung,dw-mshc-ciu-div = <3>;
> +	samsung,dw-mshc-sdr-timing = <2 4>;
> +	samsung,dw-mshc-ddr-timing = <2 3>;
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&sd1_clk &sd1_cmd &sd1_bus4>;
> +	mmc-pwrseq = <&pwrseq>;
> +
> +	wifi at 1 {
> +		compatible = "brcm,bcm4330-fmac", "brcm,bcm4329-fmac";
> +		reg = <1>;
> +		interrupt-parent = <&gpx2>;
> +		interrupts = <5 IRQ_TYPE_NONE>;
> +		interrupt-names = "host-wake";
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&wlan_irq>;
> +	};
> +};
> +
> +&ohci {
> +	status = "disabled";
> +};
> +
> +&pinctrl_0 {
> +	acc_int: acc-int-pins {
> +		samsung,pins = "gpx1-4";
> +		samsung,pin-function = <EXYNOS_PIN_FUNC_EINT>;
> +		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
> +	};
> +
> +	max77686_irq: max77686-irq-pins {
> +		samsung,pins = "gpx0-2";
> +		samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
> +		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
> +		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
> +	};

missing newlines (everywhere below)

> +	gpio_keys: gpio-keys-pins-pins {
> +		samsung,pins = "gpx2-0", "gpx2-1", "gpx2-7", "gpx1-3";
> +		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
> +	};
> +	wlan_irq: wlan-irq-pins {
> +		samsung,pins = "gpx2-5";
> +		samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
> +		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
> +		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV3>;
> +	};
> +};
> +
> +&pinctrl_1 {
> +	bh1721fvc_reset: bh1721fvc-reset-pins {
> +		samsung,pins = "gph1-2";
> +		samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
> +		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
> +	};
> +	msense_rst: msense-rst-pins {
> +		samsung,pins = "gpg2-0";
> +		samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
> +	};
> +	onewire_sleep: onewire-sleep-pins {
> +		samsung,pins = "gpg0-0";
> +		samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
> +		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
> +		samsung,pin-con-pdn = <EXYNOS_PIN_PDN_INPUT>;
> +		samsung,pin-pud-pdn = <EXYNOS_PIN_PULL_NONE>;
> +	};
> +};
> +
> +&pinctrl_2 {
> +	wlan_pmena: wlan-pmena-pins {
> +		samsung,pins = "gpv1-0";
> +		samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
> +		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
> +		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV3>;
> +		samsung,pin-con-pdn = <EXYNOS_PIN_PDN_PREV>;
> +		samsung,pin-val = <0>;
> +	};
> +};
> +
> +&pmu_system_controller {
> +	assigned-clocks = <&pmu_system_controller 0>;
> +	assigned-clock-parents = <&clock CLK_FIN_PLL>;
> +};
> +
> +&sd1_bus4 {
> +	samsung,pin-con-pdn = <EXYNOS_PIN_PDN_INPUT>;
> +	samsung,pin-pud-pdn = <EXYNOS_PIN_PULL_NONE>;
> +};
> +
> +&sd1_cmd {
> +	samsung,pin-con-pdn = <EXYNOS_PIN_PDN_INPUT>;
> +	samsung,pin-pud-pdn = <EXYNOS_PIN_PULL_NONE>;
> +};
> +
> +/* Bluetooth */
> +&serial_0 {
> +	status = "disabled";
> +};
> +
> +&serial_1 {
> +	pinctrl-names = "default", "flow-control";
> +	pinctrl-0 = <&uart1_data>;
> +	pinctrl-1 = <&uart1_data>, <&uart1_fctl>;

pinctrl-name follow after last pinctrl- entry.

> +};
> +
> +&serial_2 {
> +	pinctrl-names = "default", "flow-control";
> +	pinctrl-0 = <&uart2_data>;
> +	pinctrl-1 = <&uart2_data>, <&uart2_fctl>;

same

> +};
> +
> +&usbdrd {
> +	status = "disabled";
> +};
> +
> +&usbdrd_dwc3 {
> +	status = "disabled";
> +};
> +
> +&usbdrd_phy {
> +	status = "disabled";
> +};
> 

-- 
David Heidelberg



From m.felsch at pengutronix.de  Mon Dec 15 11:18:26 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Mon, 15 Dec 2025 20:18:26 +0100
Subject: [PATCH v3 2/3] pmdomain: imx93-blk-ctrl: convert to devm_* only
In-Reply-To: <20251215-v6-18-topic-imx93-blkctrl-v3-0-51dbd1333938@pengutronix.de>
References: <20251215-v6-18-topic-imx93-blkctrl-v3-0-51dbd1333938@pengutronix.de>
Message-ID: <20251215-v6-18-topic-imx93-blkctrl-v3-2-51dbd1333938@pengutronix.de>

Convert the driver to devm_ APIs only by making use of
devm_add_action_or_reset() and devm_pm_runtime_enable() to simplify the
probe error path and to drop the .remove() callback. This also ensures
that the device release order equals the device probe error path order.

Furthermore drop the dev_set_drvdata() usage since the only user was the
.remove() callback which is removed by this commit.

Reviewed-by: Frank Li <Frank.Li at nxp.com>
Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
---
 drivers/pmdomain/imx/imx93-blk-ctrl.c | 66 +++++++++++++++--------------------
 1 file changed, 29 insertions(+), 37 deletions(-)

diff --git a/drivers/pmdomain/imx/imx93-blk-ctrl.c b/drivers/pmdomain/imx/imx93-blk-ctrl.c
index 2aa163aef8de4ee901b9cde76ce2aad246c8c08a..49610f2389c3bbaf4de4133918fbcacb7924f672 100644
--- a/drivers/pmdomain/imx/imx93-blk-ctrl.c
+++ b/drivers/pmdomain/imx/imx93-blk-ctrl.c
@@ -188,6 +188,20 @@ static int imx93_blk_ctrl_power_off(struct generic_pm_domain *genpd)
 	return 0;
 }
 
+static void imx93_release_genpd_provider(void *data)
+{
+	struct device_node *of_node = data;
+
+	of_genpd_del_provider(of_node);
+}
+
+static void imx93_release_pm_genpd(void *data)
+{
+	struct generic_pm_domain *genpd = data;
+
+	pm_genpd_remove(genpd);
+}
+
 static struct lock_class_key blk_ctrl_genpd_lock_class;
 
 static int imx93_blk_ctrl_probe(struct platform_device *pdev)
@@ -256,10 +270,8 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
 			domain->clks[j].id = data->clk_names[j];
 
 		ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks);
-		if (ret) {
-			dev_err_probe(dev, ret, "failed to get clock\n");
-			goto cleanup_pds;
-		}
+		if (ret)
+			return dev_err_probe(dev, ret, "failed to get clock\n");
 
 		domain->genpd.name = data->name;
 		domain->genpd.power_on = imx93_blk_ctrl_power_on;
@@ -267,11 +279,12 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
 		domain->bc = bc;
 
 		ret = pm_genpd_init(&domain->genpd, NULL, true);
-		if (ret) {
-			dev_err_probe(dev, ret, "failed to init power domain\n");
-			goto cleanup_pds;
-		}
+		if (ret)
+			return dev_err_probe(dev, ret, "failed to init power domain\n");
 
+		ret = devm_add_action_or_reset(dev, imx93_release_pm_genpd, &domain->genpd);
+		if (ret)
+			return dev_err_probe(dev, ret, "failed to add pm_genpd release callback\n");
 		/*
 		 * We use runtime PM to trigger power on/off of the upstream GPC
 		 * domain, as a strict hierarchical parent/child power domain
@@ -288,39 +301,19 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
 		bc->onecell_data.domains[i] = &domain->genpd;
 	}
 
-	pm_runtime_enable(dev);
+	ret = devm_pm_runtime_enable(dev);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to enable pm-runtime\n");
 
 	ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data);
-	if (ret) {
-		dev_err_probe(dev, ret, "failed to add power domain provider\n");
-		goto cleanup_pds;
-	}
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to add power domain provider\n");
 
-	dev_set_drvdata(dev, bc);
+	ret = devm_add_action_or_reset(dev, imx93_release_genpd_provider, dev->of_node);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to add genpd_provider release callback\n");
 
 	return 0;
-
-cleanup_pds:
-	for (i--; i >= 0; i--)
-		pm_genpd_remove(&bc->domains[i].genpd);
-
-	return ret;
-}
-
-static void imx93_blk_ctrl_remove(struct platform_device *pdev)
-{
-	struct imx93_blk_ctrl *bc = dev_get_drvdata(&pdev->dev);
-	int i;
-
-	of_genpd_del_provider(pdev->dev.of_node);
-
-	pm_runtime_disable(&pdev->dev);
-
-	for (i = 0; i < bc->onecell_data.num_domains; i++) {
-		struct imx93_blk_ctrl_domain *domain = &bc->domains[i];
-
-		pm_genpd_remove(&domain->genpd);
-	}
 }
 
 static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] = {
@@ -455,7 +448,6 @@ MODULE_DEVICE_TABLE(of, imx93_blk_ctrl_of_match);
 
 static struct platform_driver imx93_blk_ctrl_driver = {
 	.probe = imx93_blk_ctrl_probe,
-	.remove = imx93_blk_ctrl_remove,
 	.driver = {
 		.name = "imx93-blk-ctrl",
 		.of_match_table = imx93_blk_ctrl_of_match,

-- 
2.47.3



From m.felsch at pengutronix.de  Mon Dec 15 11:18:24 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Mon, 15 Dec 2025 20:18:24 +0100
Subject: [PATCH v3 0/3] i.MX91/93 BLK-CTRL improvements
Message-ID: <20251215-v6-18-topic-imx93-blkctrl-v3-0-51dbd1333938@pengutronix.de>

Hi,

there were several approaches to bring the sub-devices population
mainline [1,2] but non of them made it upstream. Both approaches were
part of either the i.MX93 LVDS or MIPI-CSI enablement.

This small patchset decouples the blk-ctrl changes which allows the
MIPI-CSI and LVDS patchstack to be rebased ontop of this patchset.

Before adding the sub-device supprt, I converted the driver to devm_*
only API.

Regards,
  Marco

[1] https://lore.kernel.org/all/20250701-95_cam-v1-3-c5172bab387b at nxp.com/
[2] https://lore.kernel.org/all/20250304154929.1785200-4-alexander.stein at ew.tq-group.com/

---
Changes in v3:
- Link to v2: https://lore.kernel.org/r/20251202-v6-18-topic-imx93-blkctrl-v2-0-e73501034adc at pengutronix.de
- Add r-b (Frank)
- Rebase to v6.19-rc1

Changes in v2:
- Link to v1: https://lore.kernel.org/r/20251201-v6-18-topic-imx93-blkctrl-v1-0-b57a72e60105 at pengutronix.de
- Adapt patch2 commit message (Frank)
- Check devm_pm_runtime_enable() return (Frank)
- Add r-b tags (Frank, Alexander)

---
Marco Felsch (3):
      pmdomain: imx93-blk-ctrl: cleanup error path
      pmdomain: imx93-blk-ctrl: convert to devm_* only
      pmdomain: imx93-blk-ctrl: add support for optional subnodes

 drivers/pmdomain/imx/imx93-blk-ctrl.c | 77 ++++++++++++++++-------------------
 1 file changed, 36 insertions(+), 41 deletions(-)
---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20251201-v6-18-topic-imx93-blkctrl-341220f7084d

Best regards,
-- 
Marco Felsch <m.felsch at pengutronix.de>



From m.felsch at pengutronix.de  Mon Dec 15 11:18:27 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Mon, 15 Dec 2025 20:18:27 +0100
Subject: [PATCH v3 3/3] pmdomain: imx93-blk-ctrl: add support for optional
 subnodes
In-Reply-To: <20251215-v6-18-topic-imx93-blkctrl-v3-0-51dbd1333938@pengutronix.de>
References: <20251215-v6-18-topic-imx93-blkctrl-v3-0-51dbd1333938@pengutronix.de>
Message-ID: <20251215-v6-18-topic-imx93-blkctrl-v3-3-51dbd1333938@pengutronix.de>

This particular block can have DT subnodes describing the LVDS LDB, MIPI
DSI and parallel DPI bridge.

Scan for possible sub-devices within the driver, instead of misusing the
simple-bus to perform the scan.

Reviewed-by: Alexander Stein <alexander.stein at ew.tq-group.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
---
 drivers/pmdomain/imx/imx93-blk-ctrl.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/pmdomain/imx/imx93-blk-ctrl.c b/drivers/pmdomain/imx/imx93-blk-ctrl.c
index 49610f2389c3bbaf4de4133918fbcacb7924f672..1afc78b034fad8fa09a3e8527586387156fc2543 100644
--- a/drivers/pmdomain/imx/imx93-blk-ctrl.c
+++ b/drivers/pmdomain/imx/imx93-blk-ctrl.c
@@ -7,6 +7,7 @@
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/pm_domain.h>
 #include <linux/pm_runtime.h>
@@ -313,6 +314,10 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
 	if (ret)
 		return dev_err_probe(dev, ret, "failed to add genpd_provider release callback\n");
 
+	ret = devm_of_platform_populate(dev);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to populate blk-ctrl sub-devices\n");
+
 	return 0;
 }
 

-- 
2.47.3



From m.felsch at pengutronix.de  Mon Dec 15 11:18:25 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Mon, 15 Dec 2025 20:18:25 +0100
Subject: [PATCH v3 1/3] pmdomain: imx93-blk-ctrl: cleanup error path
In-Reply-To: <20251215-v6-18-topic-imx93-blkctrl-v3-0-51dbd1333938@pengutronix.de>
References: <20251215-v6-18-topic-imx93-blkctrl-v3-0-51dbd1333938@pengutronix.de>
Message-ID: <20251215-v6-18-topic-imx93-blkctrl-v3-1-51dbd1333938@pengutronix.de>

Call dev_err_probe() directly during return to make the code more
compact.

Reviewed-by: Alexander Stein <alexander.stein at ew.tq-group.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
---
 drivers/pmdomain/imx/imx93-blk-ctrl.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/pmdomain/imx/imx93-blk-ctrl.c b/drivers/pmdomain/imx/imx93-blk-ctrl.c
index e094fe5a42bf646c712f3eca4e66a313fa5a914c..2aa163aef8de4ee901b9cde76ce2aad246c8c08a 100644
--- a/drivers/pmdomain/imx/imx93-blk-ctrl.c
+++ b/drivers/pmdomain/imx/imx93-blk-ctrl.c
@@ -240,10 +240,8 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
 	bc->num_clks = bc_data->num_clks;
 
 	ret = devm_clk_bulk_get(dev, bc->num_clks, bc->clks);
-	if (ret) {
-		dev_err_probe(dev, ret, "failed to get bus clock\n");
-		return ret;
-	}
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to get bus clock\n");
 
 	for (i = 0; i < bc_data->num_domains; i++) {
 		const struct imx93_blk_ctrl_domain_data *data = &bc_data->domains[i];

-- 
2.47.3



From bcreeley at amd.com  Mon Dec 15 11:28:36 2025
From: bcreeley at amd.com (Creeley, Brett)
Date: Mon, 15 Dec 2025 11:28:36 -0800
Subject: [RFC net-next v3 1/3] net: ethernet: mtk_eth_soc: Add register
 definitions for RSS and LRO
In-Reply-To: <20251214110310.7009-2-linux@fw-web.de>
References: <20251214110310.7009-1-linux@fw-web.de>
 <20251214110310.7009-2-linux@fw-web.de>
Message-ID: <d101cf0e-bf7c-4aa7-a444-f6b61a1854ad@amd.com>



On 12/14/2025 3:03 AM, Frank Wunderlich wrote:
> Caution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
>
>
> From: Mason Chang <mason-cw.chang at mediatek.com>
>
> Add definitions for Receive Side Scaling and Large Receive Offload support.
>
> Signed-off-by: Mason Chang <mason-cw.chang at mediatek.com>
> Signed-off-by: Frank Wunderlich <frank-w at public-files.de>
> ---
>   drivers/net/ethernet/mediatek/mtk_eth_soc.c | 23 +++++++++++++++
>   drivers/net/ethernet/mediatek/mtk_eth_soc.h | 32 +++++++++++++++------
>   2 files changed, 46 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
> index e68997a29191..243ff16fd15e 100644
> --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
> +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
> @@ -50,13 +50,18 @@ static const struct mtk_reg_map mtk_reg_map = {
>                  .rx_ptr         = 0x0900,
>                  .rx_cnt_cfg     = 0x0904,
>                  .pcrx_ptr       = 0x0908,
> +               .lro_ctrl_dw0   = 0x0980,
>                  .glo_cfg        = 0x0a04,
>                  .rst_idx        = 0x0a08,
>                  .delay_irq      = 0x0a0c,
>                  .irq_status     = 0x0a20,
>                  .irq_mask       = 0x0a28,
>                  .adma_rx_dbg0   = 0x0a38,
> +               .lro_alt_score_delta    = 0x0a4c,
>                  .int_grp        = 0x0a50,
> +               .lro_rx1_dly_int        = 0x0a70,
> +               .lro_ring_dip_dw0       = 0x0b04,
> +               .lro_ring_ctrl_dw1      = 0x0b28,
>          },
>          .qdma = {
>                  .qtx_cfg        = 0x1800,
> @@ -113,6 +118,7 @@ static const struct mtk_reg_map mt7986_reg_map = {
>          .tx_irq_mask            = 0x461c,
>          .tx_irq_status          = 0x4618,
>          .pdma = {
> +               .rss_glo_cfg    = 0x2800,
>                  .rx_ptr         = 0x4100,
>                  .rx_cnt_cfg     = 0x4104,
>                  .pcrx_ptr       = 0x4108,
> @@ -123,6 +129,12 @@ static const struct mtk_reg_map mt7986_reg_map = {
>                  .irq_mask       = 0x4228,
>                  .adma_rx_dbg0   = 0x4238,
>                  .int_grp        = 0x4250,
> +               .int_grp3       = 0x422c,
> +               .lro_ctrl_dw0   = 0x4180,
> +               .lro_alt_score_delta    = 0x424c,
> +               .lro_rx1_dly_int        = 0x4270,
> +               .lro_ring_dip_dw0       = 0x4304,
> +               .lro_ring_ctrl_dw1      = 0x4328,
>          },
>          .qdma = {
>                  .qtx_cfg        = 0x4400,
> @@ -170,10 +182,21 @@ static const struct mtk_reg_map mt7988_reg_map = {
>                  .glo_cfg        = 0x6a04,
>                  .rst_idx        = 0x6a08,
>                  .delay_irq      = 0x6a0c,
> +               .rx_cfg         = 0x6a10,
>                  .irq_status     = 0x6a20,
>                  .irq_mask       = 0x6a28,
>                  .adma_rx_dbg0   = 0x6a38,
>                  .int_grp        = 0x6a50,
> +               .int_grp3       = 0x6a58,
> +               .tx_delay_irq   = 0x6ab0,
> +               .rx_delay_irq   = 0x6ac0,
> +               .lro_ctrl_dw0   = 0x6c08,
> +               .lro_alt_score_delta    = 0x6c1c,
> +               .lro_ring_dip_dw0       = 0x6c14,
> +               .lro_ring_ctrl_dw1      = 0x6c38,
> +               .lro_alt_dbg    = 0x6c40,
> +               .lro_alt_dbg_data       = 0x6c44,
> +               .rss_glo_cfg    = 0x7000,
>          },
>          .qdma = {
>                  .qtx_cfg        = 0x4400,
> diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
> index 0168e2fbc619..334625814b97 100644
> --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
> +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
> @@ -1143,16 +1143,30 @@ struct mtk_reg_map {
>          u32     tx_irq_mask;
>          u32     tx_irq_status;
>          struct {
> -               u32     rx_ptr;         /* rx base pointer */
> -               u32     rx_cnt_cfg;     /* rx max count configuration */
> -               u32     pcrx_ptr;       /* rx cpu pointer */
> -               u32     glo_cfg;        /* global configuration */
> -               u32     rst_idx;        /* reset index */
> -               u32     delay_irq;      /* delay interrupt */
> -               u32     irq_status;     /* interrupt status */
> -               u32     irq_mask;       /* interrupt mask */
> +               u32     rx_ptr;                 /* rx base pointer */
> +               u32     rx_cnt_cfg;             /* rx max count configuration */
> +               u32     pcrx_ptr;               /* rx cpu pointer */
> +               u32     pdrx_ptr;               /* rx dma pointer */
> +               u32     glo_cfg;                /* global configuration */
> +               u32     rst_idx;                /* reset index */
> +               u32     rx_cfg;                 /* rx dma configuration */
> +               u32     delay_irq;              /* delay interrupt */
> +               u32     irq_status;             /* interrupt status */
> +               u32     irq_mask;               /* interrupt mask */

Small nit - is the comment alignment really necessary?

Thanks,

Brett
>                  u32     adma_rx_dbg0;
> -               u32     int_grp;
> +               u32     int_grp;                /* interrupt group1 */
> +               u32     int_grp3;               /* interrupt group3 */
> +               u32     tx_delay_irq;           /* tx delay interrupt */
> +               u32     rx_delay_irq;           /* rx delay interrupt */
> +               u32     lro_ctrl_dw0;           /* lro ctrl dword0 */
> +               u32     lro_alt_score_delta;    /* lro auto-learn score delta */
> +               u32     lro_rx1_dly_int;        /* lro rx ring1 delay interrupt */
> +               u32     lro_ring_dip_dw0;       /* lro ring dip dword0 */
> +               u32     lro_ring_ctrl_dw1;      /* lro ring ctrl dword1 */
> +               u32     lro_alt_dbg;            /* lro auto-learn debug */
> +               u32     lro_alt_dbg_data;       /* lro auto-learn debug data */
> +               u32     rss_glo_cfg;            /* rss global configuration */
> +
>          } pdma;
>          struct {
>                  u32     qtx_cfg;        /* tx queue configuration */
> --
> 2.43.0
>
>



From Frank.li at nxp.com  Mon Dec 15 11:28:43 2025
From: Frank.li at nxp.com (Frank Li)
Date: Mon, 15 Dec 2025 14:28:43 -0500
Subject: [PATCH v2 0/4] s32g: Use a syscon for GPR
In-Reply-To: <aUBUkuLf7NHtLSl1@stanley.mountain>
References: <cover.1765806521.git.dan.carpenter@linaro.org>
 <aUAvwRmIZBC0W6ql@lizhi-Precision-Tower-5810>
 <aUBUkuLf7NHtLSl1@stanley.mountain>
Message-ID: <aUBha2/xiZsIF/o5@lizhi-Precision-Tower-5810>

On Mon, Dec 15, 2025 at 09:33:54PM +0300, Dan Carpenter wrote:
> On Mon, Dec 15, 2025 at 10:56:49AM -0500, Frank Li wrote:
> > On Mon, Dec 15, 2025 at 05:41:43PM +0300, Dan Carpenter wrote:
> > > The s32g devices have a GPR register region which holds a number of
> > > miscellaneous registers.  Currently only the stmmac/dwmac-s32.c uses
> > > anything from there and we just add a line to the device tree to
> > > access that GMAC_0_CTRL_STS register:
> > >
> > >                         reg = <0x4033c000 0x2000>, /* gmac IP */
> > >                               <0x4007c004 0x4>;    /* GMAC_0_CTRL_STS */
> > >
> > > We still have to maintain backwards compatibility to this format,
> > > of course, but it would be better to access these through a syscon.
> > > First of all, putting all the registers together is more organized
> > > and shows how the hardware actually is implemented.  Secondly, in
> > > some versions of this chipset those registers can only be accessed
> > > via SCMI, if the registers aren't grouped together each driver will
> > > have to create a whole lot of if then statements to access it via
> > > IOMEM or via SCMI,
> >
> > Does SCMI work as regmap? syscon look likes simple, but missed abstract
> > in overall.
> >
>
> The SCMI part of this is pretty complicated and needs discussion.  It
> might be that it requires a vendor extension.  Right now, the out of
> tree code uses a nvmem vendor extension but that probably won't get
> merged upstream.
>
> But in theory, it's fairly simple, you can write a regmap driver and
> register it as a syscon and everything that was accessing nxp,phy-sel
> accesses the same register but over SCMI.

nxp,phy-sel is not standard API. Driver access raw register value. such
as write 1 to offset 0x100.

After change to SCMI, which may mapped to difference command. Even change
to other SOC, value and offset also need be changed. It is not standilzed
as what you expected.

>
> > You still use regmap by use MMIO. /* GMAC_0_CTRL_STS */
> >
> > regmap = devm_regmap_init_mmio(dev, sts_offset, &regmap_config);
> >
>
> You can use have an MMIO syscon, or you can create a custom driver
> and register it as a syscon using of_syscon_register_regmap().

My means is that it is not necessary to create nxp,phy-sel, especially
there already have <0x4007c004 0x4>;    /* GMAC_0_CTRL_STS */

Frank

>
> > So all code can use regmap function without if-then statements if SCMI work
> > as regmap.
> >
>
> regards,
> dan carpenter
>


From krzk at kernel.org  Mon Dec 15 11:33:24 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 15 Dec 2025 20:33:24 +0100
Subject: [PATCH v3 2/3] ARM: dts: exynos: Add Google Manta (Nexus 10)
In-Reply-To: <c62d6c99-0c8d-40e5-95fc-ae73ecaca926@ixit.cz>
References: <20251215-lat3st-staging-v3-0-2e4914b64dd8@timmermann.space>
 <20251215-lat3st-staging-v3-2-2e4914b64dd8@timmermann.space>
 <c62d6c99-0c8d-40e5-95fc-ae73ecaca926@ixit.cz>
Message-ID: <546ff0cb-a3a2-4fa4-a78b-79c923ed7765@kernel.org>

On 15/12/2025 19:53, David Heidelberg wrote:
> Hello Lucas,
> 
> thanks for the sending Nexus 10 upstream, see few nitpicks below:
> 
> On 15/12/2025 16:05, Lukas Timmermann wrote:
>> From: Alexandre Marquet <tb at a-marquet.fr>
>>
>> Manta is the code name for Google Nexus 10, and was manufactured by
>> Samsung with their Exynos5250 SoC.
>> This patch adds initial device-tree file for this board.
>>
>> Signed-off-by: Alexandre Marquet <tb at a-marquet.fr>
>> Co-developed-by: Lukas Timmermann <linux at timmermann.space>
>> Signed-off-by: Lukas Timmermann <linux at timmermann.space>
>> ---
>>   arch/arm/boot/dts/samsung/Makefile             |   1 +
>>   arch/arm/boot/dts/samsung/exynos5250-manta.dts | 511 +++++++++++++++++++++++++
>>   2 files changed, 512 insertions(+)
>>
>> diff --git a/arch/arm/boot/dts/samsung/Makefile b/arch/arm/boot/dts/samsung/Makefile
>> index 7becf36656b1..e0143ee8c82d 100644
>> --- a/arch/arm/boot/dts/samsung/Makefile
>> +++ b/arch/arm/boot/dts/samsung/Makefile
>> @@ -26,6 +26,7 @@ dtb-$(CONFIG_ARCH_EXYNOS4) += \
>>   	exynos4412-trats2.dtb
>>   dtb-$(CONFIG_ARCH_EXYNOS5) += \
>>   	exynos5250-arndale.dtb \
>> +	exynos5250-manta.dtb \
>>   	exynos5250-smdk5250.dtb \
>>   	exynos5250-snow.dtb \
>>   	exynos5250-snow-rev5.dtb \
>> diff --git a/arch/arm/boot/dts/samsung/exynos5250-manta.dts b/arch/arm/boot/dts/samsung/exynos5250-manta.dts
>> new file mode 100644
>> index 000000000000..0f006590576c
>> --- /dev/null
>> +++ b/arch/arm/boot/dts/samsung/exynos5250-manta.dts
>> @@ -0,0 +1,511 @@
>> +// SPDX-License-Identifier: GPL-2.0
> 
> you could use here modern SPDX I guess (GPL-2.0-only)
> 
>> +/*
>> + * Google Manta (Nexus 10) board device tree source
>> + *
>> + * Copyright (c) 2023-2025 Alexandre Marquet
>> + * Copyright (c) 2025 Lukas Timmermann
>> + */
>> +
>> +/dts-v1/;
>> +#include <dt-bindings/leds/common.h>
>> +#include <dt-bindings/gpio/gpio.h>
>> +#include <dt-bindings/clock/maxim,max77686.h>
>> +#include <dt-bindings/input/linux-event-codes.h>
>> +#include "exynos-pinctrl.h"
>> +#include "exynos5250.dtsi"
>> +#include "exynos-mfc-reserved-memory.dtsi"
>> +
>> +/ {
>> +	model = "Google Nexus 10";
>> +	compatible = "google,manta", "samsung,exynos5250", "samsung,exynos5";
>> +
>> +	aliases {
>> +		mmc0 = &mmc_0; /* eMMC */
>> +		mmc1 = &mmc_1; /* WiFi */
>> +	};
>> +
>> +	bmp180_vdda_reg: regulator-bmp180-vdda {
>> +		compatible = "regulator-fixed";
>> +		regulator-name = "BMP180_VDDA";
>> +	};
> something-something-regulator (all occurences within the DTS)
> 

I don't understand this suggestion.

>> +
>> +	bmp180_vddd_reg: regulator-bmp180-vddd {
>> +		compatible = "regulator-fixed";
>> +		regulator-name = "BMP180_VDDD";
>> +	};



>> +};
>> +
>> +&clock {
>> +	assigned-clocks = <&clock CLK_FOUT_APLL>;
>> +	assigned-clock-rates = <1000000000>;
>> +};
>> +
>> +&cpu0 {
>> +	cpu0-supply = <&buck2_reg>;
>> +};
>> +
>> +&ehci {
>> +	status = "disabled";
>> +};
>> +
>> +&i2c_0 {
>> +	status = "okay";
> 
> status should be before first sub-node (none in this case), with 
> preceding newline, please change all occurences
> 

Well yeah, but do you have actually any comment pointing real issues?


Best regards,
Krzysztof


From dianders at chromium.org  Mon Dec 15 11:41:22 2025
From: dianders at chromium.org (Doug Anderson)
Date: Mon, 15 Dec 2025 11:41:22 -0800
Subject: Proposal: Officially allow "incomplete" trees as a base
In-Reply-To: <CAD=FV=Wfu4ddQdTeupN+Md5Tv+5P1Up+Zo5U2AjGpqayTuqFhw@mail.gmail.com>
References: <CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA@mail.gmail.com>
 <aS66WcLPm6e5rdyk@shell.armlinux.org.uk> <CAL_JsqLxLakt94ACgv8z5A-O4WGZPfiZ-7UFaBPaOa7W8L3Cxw@mail.gmail.com>
 <CAD=FV=Wfu4ddQdTeupN+Md5Tv+5P1Up+Zo5U2AjGpqayTuqFhw@mail.gmail.com>
Message-ID: <CAD=FV=USdk6FAcdHqXBqOu1EGZF4-7ywag--PneCNMxjbZDpAg@mail.gmail.com>

Hi,

On Wed, Dec 3, 2025 at 2:37?PM Doug Anderson <dianders at chromium.org> wrote:
>
> Hi,
>
> On Tue, Dec 2, 2025 at 3:16?PM Rob Herring <robh at kernel.org> wrote:
> >
> > > as a set of examples. I don't see a clear way to generate these from
> > > a fragmented scheme. There's a similar problem with the board-level
> > > compatible:
> > >
> > >         compatible = "solidrun,cubox-i/dl", "fsl,imx6dl";
> > >         compatible = "solidrun,hummingboard2/dl", "fsl,imx6dl";
> > >         compatible = "solidrun,hummingboard/dl", "fsl,imx6dl";
> > >         compatible = "solidrun,hummingboard2/q", "fsl,imx6q";
> > >
> > > These don't include the SoM information.
> >
> > So we're back to needing to merge compatible even though Doug was
> > willing to drop it. Or to put it another way, there's usecases for the
> > base to be different SoC revisions and variants. So I don't think we
> > should give up on solving that.
>
> I'm willing to take a crack at it. Before doing so, though, I think we
> need to agree upon a definition of what the top-level "compatible" is
> supposed to be. Otherwise, what exactly is our goal in trying to merge
> "compatible" strings? We should have a goal of updating the official
> documentation with whatever we decide.
>
>
> I guess first, we should see what the spec says. The Devicetree
> Specification v0.4 says this about the top-level compatible (which, it
> should be noted, is documented _separtely_ from section 2.3.1 since
> all of section 2.3 is only about device nodes):
>
> > Specifies a list of platform architectures with which this platform is compatible. This property can be used by operating systems in selecting platform specific code. The recommended form of the property value is: "manufacturer,model" For example: compatible = "fsl,mpc8572ds"
>
> That's not very detailed, but I guess we can start out looking at what
> it _doesn't_ say.
>
> a) The spec doesn't say anything about the top-level compatible
> uniquely identifying a specific hardware configuration. Nothing there
> says "look at one of the strings in the list and you can tell exactly
> what product you have in front of you".
>
> b) The spec doesn't specifically mention that one should include any
> strings for a SoC / SoM / reference board. Indeed, the example given
> shows an example "compatible" with just one string: "fsl,mpc8572ds".
> Searching the interwebs, I find that this example "compatible"
> probably refers to a Freescale "MPC8572 Development System", which is
> a dev board with a "MPC8572" chip. Notably, the example "compatible"
> didn't include the "MPC8572" chip.
>
> c) The spec doesn't seem to include a firm definition of what they
> mean by the word "platform". In my mind, one could interpret the SoC
> as a "platform". One could also interpret a SoM or a reference board
> as a "platform". It's not necessarily clear. Since AI is the answer to
> all things these days, I asked Gemini. I asked what "platform" meant
> in the context of the DT spec and it (confidently) told me that "the
> platform is the physical machine." ...but when I asked if one could
> also consider the SoC the "platform", it told me that was "an
> excellent clarifying question" and went on to say the SoC "is often
> referred to as the base platform or the SoC-level platform." :-P
>
>
> How does that help us? I guess I'd summarize that, from reading the
> spec and more loosely interpreting the word "platform":
>
> a) The compatible string doesn't _need_ to include strings
> representing the SoC, SoM, or baseboard, but it can.
>
> b) The compatible string is primarily there for use by the operating
> system to select platform (board, reference board, SoM, or SoC)
> specific code.
>
>
> That still doesn't really tell us when we should / shouldn't include a
> SoC / SoM / baseboard in the top-level "compatible". It also doesn't
> tell us if we should include even more detailed levels. ...and by
> "more detailed levels", I would perhaps say that each of these could
> also be considered a "platform":
> * google,trogdor-lazor-rev6-sku6 - An exact model of board.
> * google,trogdor-lazor-rev6 - A platform that has several SKUs.
> * google,trogdor-lazor - A platform that has several revisions and SKUs.
> * google,trogdor - A reference platform that has several boards.
>
>
> Perhaps we should lean into the statement "This property can be used
> by operating systems in selecting platform specific code" to give us
> guidance? The problem is that we somehow need to not just look at
> current operating systems but, if we want to strive towards the goal
> of shipping binary device trees, we need to consider future operating
> system code that hasn't yet been written. That sounds impossible and
> makes one think you should cram as much info into the compatible
> string as possible, but...
>
> ...actually, we only need to put information into the compatible
> string if there's not an easy way for the operating system to get the
> information elsewhere, right? If the information is found elsewhere in
> the device tree or if the operating system can probe the information
> itself, then there's really no _need_ to put it in the top-level
> "compatible" and we'll never end up painting ourselves into a corner.
> We could still put the information there just to make it convenient,
> but it's not really needed. Does this make sense?
>
> I would further argue that, in order to be useful, any given
> "platform" should document its expectations and we need to be
> consistent across anyone using that platform. To make it concrete, if
> the Qualcomm SC7180 platform documents that "qcom,sc7180" belongs in
> the top-level compatible string then all device trees including sc7180
> should have that string. This _doesn't_ mean that on some future
> platform (like qcom,sc9999) we couldn't make a different decision.
> Maybe on "qcom,sc9999" we've decided to put SoC details as some
> properties under the "soc at 0" node. Now the operating system can find
> the details about which SoC is present from the "soc at 0" node and
> therefore we don't need to represent it in the top-level compatible
> string.
>
>
> Assuming that all makes sense, maybe the way to document the top-level
> compatible string:
>
> --
>
> Specifies a list of "platform architectures" with which this platform
> is compatible. A "platform architecture" can be at any level, from the
> specific board to the class of board to the reference platform to the
> SoM to the SoC. A given "platform architecture" should always be
> consistently included or not-included by all final device trees using
> it. If the "qcom,sc7180" SoC platform is defined to be included, it
> should be consistently included by any device trees with this SoC. The
> criteria for whether to represent a "platform architecture" in the
> top-level compatible string is the difficulty of the operating system
> obtaining the information in some other way (including from other DT
> properties or from probing). In general, the top-level "compatible"
> used by operating systems in selecting platform specific code. The
> recommended form of the property value is: "manufacturer,model"
>
> Examples:
>
> compatible = "fsl,mpc8572ds";
> - Select code related to the Freescale MPC8572 Development System
>
> No platform is included for the CPU since ("fsl,mpc8572") isn't
> consistently listed as a platform.
>
> compatible = "google,snow-rev4", "google,snow", "samsung,exynos5250",
> "samsung,exynos5"
> - Select code related to google,snow-rev4.
> - Select code related to google,snow.
> - Select code related to samsung,exynos5250.
> - Select code related to samsung,exynos5.
>
> In this example, the idea is that all exynos5 boards would have
> "samsung,exynos5" so code that needed to run on "exynos5" could
> consistently test for that "compatible" string. Similarly, all
> exynos5250 boards would have "samsung,exynos5250" and all snow boards
> would have "google,snow"
>
> --
>
> What do folks think?
>
> Note that the current Chromebook stuff [1] we used on sc7180-trogdor
> boards doesn't fit amazingly well into that definition, but it can
> kinda squeeze in there. Essentially the sc7180-trogdor stuff is
> designed around making it easy for the bootloader to find the right
> device tree but doesn't provide anything terribly useful to the OS in
> the top-level "compatible" string. At this point, I don't think I
> would encourage others to adopt something similar.
>
>
> If folks agree with the above interpretation, I think I'd end up back
> to arguing _against_ the need to merge compatible strings. If we don't
> need to put detailed SoC information into the top-level compatible
> string then we don't need to merge. I think the most
> flexible/futureproof would be to just define that for the SoC inside
> Pixel 10 (and presumably all future Google Silicon) we'll put SoC
> information under the "soc at 0" node and thus there's no need to include
> it in the top-level "compatible". That leaves us without a
> "compatible" to put in the base "dtb", but maybe we can just put
> compatible = "incomplete" or something like that?
>
> I suspect that even for Russell's purposes the information can either
> be probed by the OS or put in places other than the top-level
> compatible string. We might not want to change his existing
> devicetrees in case some OS is relying on the existing compatible
> strings, but for work going forward it feels like it would be a
> solution...
>
>
> [1] https://docs.kernel.org/arch/arm/google/chromebook-boot-flow.html

It's me again. The pest.

Adding a few people who piped up when I mentioned this at Plumbers
(namely Bjorn and Geert)...


Bjorn mentioned that, in general, it's hard to know what device /
devicetree people are using when they report bugs. Presumably if we
made the top-level compatible less representative of the overall
system, this problem would be made worse?

While this is true, to me it isn't necessarily a blocker (though feel
free to object). Specifically:

* The device tree doesn't fully describe all hardware anyway. While we
might use a "SKU" variant to choose between one MIPI panel or another,
Chromebooks _don't_ use SKU variants to choose between one eDP panel
or another because eDP panels can be probed. We also might use a "SKU"
variant to choose between two MIPI webcams but not two USB webcams for
the same reason.

* We've already accepted the idea of "hardware probers" that can run
at boot anyway and those don't adjust SKU numbers. grep the source for
"fail-needs-probe".

Someone pointed out that if you really need the device tree it could
be captured in bug reports. This seems reasonable to me. I also really
liked the idea of keeping some sort of log somewhere in the device
tree every time an overlay is applied, though I tend to agree with
others that filenames of device tree files shouldn't be ABI.


Geert talked about the top-level compatible as being the "last resort"
to fix any issue. That matches my understanding above from reading the
docs and seeing how it was used. Geert: I would be curious what you
thought about my arguments above.


In general, I'm still hoping to figure out next steps. I believe this
problem is important enough that we shouldn't just drop it due to
silence, so I'll continue being my usual noisy self and keep
pestering.

-Doug


From robh at kernel.org  Mon Dec 15 11:43:25 2025
From: robh at kernel.org (Rob Herring)
Date: Mon, 15 Dec 2025 13:43:25 -0600
Subject: [PATCH] ARM: dts: nxp/imx6: Drop unused .dtsi
In-Reply-To: <20251214185750.tzt6jf4zg5gtex63@pengutronix.de>
References: <20251212203226.458694-5-robh@kernel.org> <20251213181324.u32ztfblkknfpz44@pengutronix.de>
 <CAL_JsqK9OREenZjBHrDh7AqsyUXYOzTOhY4e0qHGzYkX8tacWQ@mail.gmail.com> <20251214185750.tzt6jf4zg5gtex63@pengutronix.de>
Message-ID: <CAL_JsqLfVemq9k3x5J1pTz--Z+VYLeEQrFdbtdS7Pc-HkRui=w@mail.gmail.com>

On Sun, Dec 14, 2025 at 12:58?PM Marco Felsch <m.felsch at pengutronix.de> wrote:
>
> On 25-12-14, Rob Herring wrote:
> > On Sat, Dec 13, 2025 at 12:13?PM Marco Felsch <m.felsch at pengutronix.de> wrote:
> > >
> > > Hi Rob,
> > >
> > > On 25-12-12, Rob Herring (Arm) wrote:
> > > > These .dtsi files are not included anywhere in the tree and can't be
> > > > tested.
> > >
> > > not in the tree but by other projects, please see below.
> > >
> > > > Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> > > > ---
> > > >  .../dts/nxp/imx/imx6dl-kontron-samx6i.dtsi    | 12 -----
> > > >  .../dts/nxp/imx/imx6q-kontron-samx6i.dtsi     | 12 -----
> > > >  .../boot/dts/nxp/imx/imx6qdl-pico-dwarf.dtsi  | 45 ----------------
> > > >  .../boot/dts/nxp/imx/imx6qdl-pico-nymph.dtsi  | 54 -------------------
> > > >  4 files changed, 123 deletions(-)
> > > >  delete mode 100644 arch/arm/boot/dts/nxp/imx/imx6dl-kontron-samx6i.dtsi
> > > >  delete mode 100644 arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi
> > > >  delete mode 100644 arch/arm/boot/dts/nxp/imx/imx6qdl-pico-dwarf.dtsi
> > > >  delete mode 100644 arch/arm/boot/dts/nxp/imx/imx6qdl-pico-nymph.dtsi
> > > >
> > > > diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-kontron-samx6i.dtsi b/arch/arm/boot/dts/nxp/imx/imx6dl-kontron-samx6i.dtsi
> > > > deleted file mode 100644
> > > > index 5a9b819d7ee8..000000000000
> > > > --- a/arch/arm/boot/dts/nxp/imx/imx6dl-kontron-samx6i.dtsi
> > > > +++ /dev/null
> > > > @@ -1,12 +0,0 @@
> > > > -// SPDX-License-Identifier: GPL-2.0 OR X11
> > > > -/*
> > > > - * Copyright 2019 (C) Pengutronix, Marco Felsch <kernel at pengutronix.de>
> > > > - */
> > > > -
> > > > -#include "imx6dl.dtsi"
> > > > -#include "imx6qdl-kontron-samx6i.dtsi"
> > > > -
> > > > -/ {
> > > > -     model = "Kontron SMARC-sAMX6i Dual-Lite/Solo";
> > > > -     compatible = "kontron,imx6dl-samx6i", "fsl,imx6dl";
> > > > -};
> > > > diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi b/arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi
> > > > deleted file mode 100644
> > > > index e76963436079..000000000000
> > > > --- a/arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi
> > > > +++ /dev/null
> > > > @@ -1,12 +0,0 @@
> > > > -// SPDX-License-Identifier: GPL-2.0 OR X11
> > > > -/*
> > > > - * Copyright 2019 (C) Pengutronix, Marco Felsch <kernel at pengutronix.de>
> > > > - */
> > > > -
> > > > -#include "imx6q.dtsi"
> > > > -#include "imx6qdl-kontron-samx6i.dtsi"
> > > > -
> > > > -/ {
> > > > -     model = "Kontron SMARC-sAMX6i Quad/Dual";
> > > > -     compatible = "kontron,imx6q-samx6i", "fsl,imx6q";
> > > > -};
> > >
> > > I can't speak for the other two .dtsi files but both kontron .dtsi files
> > > are used by barebox:
> > >
> > >  - https://elixir.bootlin.com/barebox/v2025.11.0/source/arch/arm/dts/imx6dl-samx6i.dts#L8
> > >  - https://elixir.bootlin.com/barebox/v2025.11.0/source/arch/arm/dts/imx6q-samx6i.dts#L8
> > >
> > > Removing them here will cause a regression for barebox.
> >
> > Please upstream something that uses the .dtsi. Other than the
> > undocumented barebox property, no reason these can't be.
>
> My intention wasn't to point to the barebox-only
> "barebox,disable-deep-probe" property. I was refering to the include
> line.
>
> The two .dtsi files we're talking about are SoM .dtsi files. We don't
> have access to the Kontron EVK baseboard which uses this SoM.
>
> I've added a few Kontron devs which may can add the missing baseboard
> support.
>
> +Cc: frieder.schrempf at kontron.de
> +Cc: annette.kobou at kontron.de
> +Cc: oualid.derouiche at kontron.de
> +Cc: eberhard.stoll at kontron.de
>
> I could also add the imx6dl-samx6i.dts and imx6q-samx6i.dts like we do
> in barebox. But as said, this would be a devicetree for a SoM which
> makes sense for the bootloader but not for the kernel.

Why not? People use the kernel as a bootloader. There's also some
discussions about splitting SoMs and baseboards into overlays for
baseboards (and also even into SoC base DT plus overlay for boards).

Rob


From frank-w at public-files.de  Mon Dec 15 11:57:40 2025
From: frank-w at public-files.de (Frank Wunderlich)
Date: Mon, 15 Dec 2025 20:57:40 +0100
Subject: =?US-ASCII?Q?Re=3A_=5BRFC_net-next_v3_1/3=5D_net=3A_ethernet=3A_mtk=5Fet?=
 =?US-ASCII?Q?h=5Fsoc=3A_Add_register_definitions_for_RSS_and_LRO?=
In-Reply-To: <d101cf0e-bf7c-4aa7-a444-f6b61a1854ad@amd.com>
References: <20251214110310.7009-1-linux@fw-web.de> <20251214110310.7009-2-linux@fw-web.de> <d101cf0e-bf7c-4aa7-a444-f6b61a1854ad@amd.com>
Message-ID: <033E8AC9-21D6-4707-AE75-37556241CC52@public-files.de>

Am 15. Dezember 2025 20:28:36 MEZ schrieb "Creeley, Brett" <bcreeley at amd.com>:
>
>
>On 12/14/2025 3:03 AM, Frank Wunderlich wrote:
>> diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
>> index 0168e2fbc619..334625814b97 100644
>> --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
>> +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
>> @@ -1143,16 +1143,30 @@ struct mtk_reg_map {
>>          u32     tx_irq_mask;
>>          u32     tx_irq_status;
>>          struct {
>> -               u32     rx_ptr;         /* rx base pointer */
>> -               u32     rx_cnt_cfg;     /* rx max count configuration */
>> -               u32     pcrx_ptr;       /* rx cpu pointer */
>> -               u32     glo_cfg;        /* global configuration */
>> -               u32     rst_idx;        /* reset index */
>> -               u32     delay_irq;      /* delay interrupt */
>> -               u32     irq_status;     /* interrupt status */
>> -               u32     irq_mask;       /* interrupt mask */
>> +               u32     rx_ptr;                 /* rx base pointer */
>> +               u32     rx_cnt_cfg;             /* rx max count configuration */
>> +               u32     pcrx_ptr;               /* rx cpu pointer */
>> +               u32     pdrx_ptr;               /* rx dma pointer */
>> +               u32     glo_cfg;                /* global configuration */
>> +               u32     rst_idx;                /* reset index */
>> +               u32     rx_cfg;                 /* rx dma configuration */
>> +               u32     delay_irq;              /* delay interrupt */
>> +               u32     irq_status;             /* interrupt status */
>> +               u32     irq_mask;               /* interrupt mask */
>
>Small nit - is the comment alignment really necessary?

I could transform it to something like this:

<https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/net/ethernet/mediatek/mtk_eth_soc.h#n921>

>Thanks,
>
>Brett


regards Frank


From david at ixit.cz  Mon Dec 15 12:06:31 2025
From: david at ixit.cz (David Heidelberg)
Date: Mon, 15 Dec 2025 21:06:31 +0100
Subject: [PATCH v3 2/3] ARM: dts: exynos: Add Google Manta (Nexus 10)
In-Reply-To: <546ff0cb-a3a2-4fa4-a78b-79c923ed7765@kernel.org>
References: <20251215-lat3st-staging-v3-0-2e4914b64dd8@timmermann.space>
 <20251215-lat3st-staging-v3-2-2e4914b64dd8@timmermann.space>
 <c62d6c99-0c8d-40e5-95fc-ae73ecaca926@ixit.cz>
 <546ff0cb-a3a2-4fa4-a78b-79c923ed7765@kernel.org>
Message-ID: <eb898d21-5fda-474d-979e-18da33a85415@ixit.cz>



On 15/12/2025 20:33, Krzysztof Kozlowski wrote:
> On 15/12/2025 19:53, David Heidelberg wrote:
>> Hello Lucas,
>>
>> thanks for the sending Nexus 10 upstream, see few nitpicks below:
>>
>> On 15/12/2025 16:05, Lukas Timmermann wrote:
>>> From: Alexandre Marquet <tb at a-marquet.fr>
>>>
>>> Manta is the code name for Google Nexus 10, and was manufactured by
>>> Samsung with their Exynos5250 SoC.
>>> This patch adds initial device-tree file for this board.
>>>
>>> Signed-off-by: Alexandre Marquet <tb at a-marquet.fr>
>>> Co-developed-by: Lukas Timmermann <linux at timmermann.space>
>>> Signed-off-by: Lukas Timmermann <linux at timmermann.space>
>>> ---
>>>    arch/arm/boot/dts/samsung/Makefile             |   1 +
>>>    arch/arm/boot/dts/samsung/exynos5250-manta.dts | 511 +++++++++++++++++++++++++
>>>    2 files changed, 512 insertions(+)
>>>
>>> diff --git a/arch/arm/boot/dts/samsung/Makefile b/arch/arm/boot/dts/samsung/Makefile
>>> index 7becf36656b1..e0143ee8c82d 100644
>>> --- a/arch/arm/boot/dts/samsung/Makefile
>>> +++ b/arch/arm/boot/dts/samsung/Makefile
>>> @@ -26,6 +26,7 @@ dtb-$(CONFIG_ARCH_EXYNOS4) += \
>>>    	exynos4412-trats2.dtb
>>>    dtb-$(CONFIG_ARCH_EXYNOS5) += \
>>>    	exynos5250-arndale.dtb \
>>> +	exynos5250-manta.dtb \
>>>    	exynos5250-smdk5250.dtb \
>>>    	exynos5250-snow.dtb \
>>>    	exynos5250-snow-rev5.dtb \
>>> diff --git a/arch/arm/boot/dts/samsung/exynos5250-manta.dts b/arch/arm/boot/dts/samsung/exynos5250-manta.dts
>>> new file mode 100644
>>> index 000000000000..0f006590576c
>>> --- /dev/null
>>> +++ b/arch/arm/boot/dts/samsung/exynos5250-manta.dts
>>> @@ -0,0 +1,511 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>
>> you could use here modern SPDX I guess (GPL-2.0-only)
>>
>>> +/*
>>> + * Google Manta (Nexus 10) board device tree source
>>> + *
>>> + * Copyright (c) 2023-2025 Alexandre Marquet
>>> + * Copyright (c) 2025 Lukas Timmermann
>>> + */
>>> +
>>> +/dts-v1/;
>>> +#include <dt-bindings/leds/common.h>
>>> +#include <dt-bindings/gpio/gpio.h>
>>> +#include <dt-bindings/clock/maxim,max77686.h>
>>> +#include <dt-bindings/input/linux-event-codes.h>
>>> +#include "exynos-pinctrl.h"
>>> +#include "exynos5250.dtsi"
>>> +#include "exynos-mfc-reserved-memory.dtsi"
>>> +
>>> +/ {
>>> +	model = "Google Nexus 10";
>>> +	compatible = "google,manta", "samsung,exynos5250", "samsung,exynos5";
>>> +
>>> +	aliases {
>>> +		mmc0 = &mmc_0; /* eMMC */
>>> +		mmc1 = &mmc_1; /* WiFi */
>>> +	};
>>> +
>>> +	bmp180_vdda_reg: regulator-bmp180-vdda {
>>> +		compatible = "regulator-fixed";
>>> +		regulator-name = "BMP180_VDDA";
>>> +	};
>> something-something-regulator (all occurences within the DTS)
>>
> 
> I don't understand this suggestion.

oh right, let me clarify,

the regulator name should end with -regulator postfix.

> 
>>> +
>>> +	bmp180_vddd_reg: regulator-bmp180-vddd {
>>> +		compatible = "regulator-fixed";
>>> +		regulator-name = "BMP180_VDDD";
>>> +	};
> 
> 
> 
>>> +};
>>> +
>>> +&clock {
>>> +	assigned-clocks = <&clock CLK_FOUT_APLL>;
>>> +	assigned-clock-rates = <1000000000>;
>>> +};
>>> +
>>> +&cpu0 {
>>> +	cpu0-supply = <&buck2_reg>;
>>> +};
>>> +
>>> +&ehci {
>>> +	status = "disabled";
>>> +};
>>> +
>>> +&i2c_0 {
>>> +	status = "okay";
>>
>> status should be before first sub-node (none in this case), with
>> preceding newline, please change all occurences
>>
> 
> Well yeah, but do you have actually any comment pointing real issues?

No I don't, just generic device-tree nitpicks.

David

> 
> 
> Best regards,
> Krzysztof

-- 
David Heidelberg



From dan.carpenter at linaro.org  Mon Dec 15 12:11:03 2025
From: dan.carpenter at linaro.org (Dan Carpenter)
Date: Mon, 15 Dec 2025 23:11:03 +0300
Subject: [PATCH v2 0/4] s32g: Use a syscon for GPR
In-Reply-To: <aUBha2/xiZsIF/o5@lizhi-Precision-Tower-5810>
References: <cover.1765806521.git.dan.carpenter@linaro.org>
 <aUAvwRmIZBC0W6ql@lizhi-Precision-Tower-5810>
 <aUBUkuLf7NHtLSl1@stanley.mountain>
 <aUBha2/xiZsIF/o5@lizhi-Precision-Tower-5810>
Message-ID: <aUBrV2_Iv4oTPkC4@stanley.mountain>

On Mon, Dec 15, 2025 at 02:28:43PM -0500, Frank Li wrote:
> On Mon, Dec 15, 2025 at 09:33:54PM +0300, Dan Carpenter wrote:
> > On Mon, Dec 15, 2025 at 10:56:49AM -0500, Frank Li wrote:
> > > On Mon, Dec 15, 2025 at 05:41:43PM +0300, Dan Carpenter wrote:
> > > > The s32g devices have a GPR register region which holds a number of
> > > > miscellaneous registers.  Currently only the stmmac/dwmac-s32.c uses
> > > > anything from there and we just add a line to the device tree to
> > > > access that GMAC_0_CTRL_STS register:
> > > >
> > > >                         reg = <0x4033c000 0x2000>, /* gmac IP */
> > > >                               <0x4007c004 0x4>;    /* GMAC_0_CTRL_STS */
> > > >
> > > > We still have to maintain backwards compatibility to this format,
> > > > of course, but it would be better to access these through a syscon.
> > > > First of all, putting all the registers together is more organized
> > > > and shows how the hardware actually is implemented.  Secondly, in
> > > > some versions of this chipset those registers can only be accessed
> > > > via SCMI, if the registers aren't grouped together each driver will
> > > > have to create a whole lot of if then statements to access it via
> > > > IOMEM or via SCMI,
> > >
> > > Does SCMI work as regmap? syscon look likes simple, but missed abstract
> > > in overall.
> > >
> >
> > The SCMI part of this is pretty complicated and needs discussion.  It
> > might be that it requires a vendor extension.  Right now, the out of
> > tree code uses a nvmem vendor extension but that probably won't get
> > merged upstream.
> >
> > But in theory, it's fairly simple, you can write a regmap driver and
> > register it as a syscon and everything that was accessing nxp,phy-sel
> > accesses the same register but over SCMI.
> 
> nxp,phy-sel is not standard API. Driver access raw register value. such
> as write 1 to offset 0x100.
> 
> After change to SCMI, which may mapped to difference command. Even change
> to other SOC, value and offset also need be changed. It is not standilzed
> as what you expected.

We're writing to an offset in a syscon.  Right now the device tree
says that the syscon is an MMIO syscon.  But for SCMI devices we
would point the phandle to a custom syscon.  The phandle and the offset
would stay the same, but how the syscon is implemented would change.

> 
> >
> > > You still use regmap by use MMIO. /* GMAC_0_CTRL_STS */
> > >
> > > regmap = devm_regmap_init_mmio(dev, sts_offset, &regmap_config);
> > >
> >
> > You can use have an MMIO syscon, or you can create a custom driver
> > and register it as a syscon using of_syscon_register_regmap().
> 
> My means is that it is not necessary to create nxp,phy-sel, especially
> there already have <0x4007c004 0x4>;    /* GMAC_0_CTRL_STS */
> 

Right now the out of tree dwmac-s32cc.c driver does something like
this:

    89          if (gmac->use_nvmem) {
    90                  ret = write_nvmem_cell(gmac->dev, "gmac_phy_intf_sel", intf_sel);
    91                  if (ret)
    92                          return ret;
    93          } else {
    94                  writel(intf_sel, gmac->ctrl_sts);
    95          }

Which is quite complicated, but with a syscon, then it's just:

	regmap_write(gmac->sts_regmap, gmac->sts_offset, S32_PHY_INTF_SEL_RGMII);

Even without SCMI, the hardware has all these registers grouped together
it just feels cleaner to group them together in the device tree as well.

regards,
dan carpenter



From ebiggers at kernel.org  Mon Dec 15 12:16:11 2025
From: ebiggers at kernel.org (Eric Biggers)
Date: Mon, 15 Dec 2025 20:16:11 +0000
Subject: [PATCH] crypto: arm64/ghash - Fix incorrect output from
 ghash-neon
In-Reply-To: <CAMj1kXHVq1NWA28jKxBrHHi1JOPoGXEamC7uMgTOmFwzmcYxRA@mail.gmail.com>
References: <DETXT7QI62KE.F3CGH2VWX1SC@cknow-tech.com>
 <20251209223417.112294-1-ebiggers@kernel.org>
 <DEUFDH7FJURL.3J0FN5I19VV8F@cknow-tech.com>
 <CAMj1kXEQkB9MWB+PAi4XE_MuBt0ScitxTsKMDo1-7Cp-=xXOpw@mail.gmail.com>
 <20251212054020.GB4838@sol>
 <CAMj1kXHVq1NWA28jKxBrHHi1JOPoGXEamC7uMgTOmFwzmcYxRA@mail.gmail.com>
Message-ID: <20251215201611.GB10539@google.com>

On Mon, Dec 15, 2025 at 04:54:34PM +0900, Ard Biesheuvel wrote:
> > > All 64-bit RPi models except the RPi5 are affected by this, as those
> > > do not implement the crypto extensions. So I would expect QEMU to do
> > > the same.
> > >
> > > It would be nice, though, if we could emulate this on the mach-virt
> > > machine model too. It should be fairly trivial to do, so if there is
> > > demand for this I can look into it.
> >
> > I'm definitely interested in it.  I'm already testing multiple "-cpu"
> > options, and it's easy to add more.
> >
> > With qemu-system-aarch64 I'm currently only using "-M virt", since the
> > other machine models I've tried don't boot with arm64 defconfig,
> > including "-M raspi3b" and "-M raspi4b".
> >
> > There may be some tricks I'm missing.  Regardless, expanding the
> > selection of available CPUs for "-M virt" would be helpful.  Either by
> > adding "real" CPUs that have "interesting" combinations of features, or
> > by just allowing turning features off like
> > "-cpu max,aes=off,pmull=off,sha256=off".  (Certain features like sve can
> > already be turned off in that way, but not the ones relevant to us.)
> >
> 
> There are some architectural rules around which combinations of crypto
> extensions are permitted:
> - PMULL implies AES, and there is no way for the ID registers to
> describe a CPU that has PMULL but not AES
> - SHA256 implies SHA1 (but the ID register fields are independent)
> - SHA3 and SHA512 both imply SHA256+SHA1
> - SVE versions are not allowed to be implemented unless the plain NEON
> version is implemented as well
> -  FEAT_Crypto has different meanings for v8.0, v8.2 and v9.x
> 
> So it would be much easier, also in terms of future maintenance, to
> have a simple 'crypto=off' setting that applies to all emulated CPU
> models, given that disabling all crypto on any given compliant CPU
> will never result in something that the architecture does not permit.
> 
> Would that work for you?

I thought it had been established that the "crypto" grouping of features
(as implemented by gcc and clang) doesn't reflect the actual hardware
feature fields and is misleading because additional crypto extensions
continue to be added.

I'm not sure that applies here, but just something to consider.

There's certainly no need to support emulating combinations of features
that no hardware actually implements.  So yes, if that means "crypto" is
the right choice, that sounds fine.

- Eric


From krzk at kernel.org  Mon Dec 15 12:25:01 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 15 Dec 2025 21:25:01 +0100
Subject: [PATCH] ARM: dts: ixp4xx: Fix up Actiontec MI424WR DTS files
In-Reply-To: <20251211-ixp4xx-actiontec-dts-fix-v1-1-97af8e79d474@kernel.org>
References: <20251211-ixp4xx-actiontec-dts-fix-v1-1-97af8e79d474@kernel.org>
Message-ID: <176583027654.110616.5692785131178789330.b4-ty@kernel.org>


On Thu, 11 Dec 2025 14:05:01 +0100, Linus Walleij wrote:
> The KS8995 switch was unconditionally wired to EthC (eth1)
> on both MI424WR variants, this is wrong: the D revision has
> the switch connected to EthB (eth0) so pull this assingment
> out of the generic MI424WR DTSI file and make it a property
> of the respective variants instead.
> 
> 
> [...]

Applied, thanks!

[1/1] ARM: dts: ixp4xx: Fix up Actiontec MI424WR DTS files
      https://git.kernel.org/soc/soc/c/ececfba255bf3616301419e47a5c824e04b60ab8

Best regards,
-- 
Krzysztof Kozlowski <krzk at kernel.org>


From krzk at kernel.org  Mon Dec 15 12:33:30 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 15 Dec 2025 21:33:30 +0100
Subject: [PATCH v3 2/3] ARM: dts: exynos: Add Google Manta (Nexus 10)
In-Reply-To: <eb898d21-5fda-474d-979e-18da33a85415@ixit.cz>
References: <20251215-lat3st-staging-v3-0-2e4914b64dd8@timmermann.space>
 <20251215-lat3st-staging-v3-2-2e4914b64dd8@timmermann.space>
 <c62d6c99-0c8d-40e5-95fc-ae73ecaca926@ixit.cz>
 <546ff0cb-a3a2-4fa4-a78b-79c923ed7765@kernel.org>
 <eb898d21-5fda-474d-979e-18da33a85415@ixit.cz>
Message-ID: <cc15ff73-7322-41a9-b0db-a321d6835c36@kernel.org>

On 15/12/2025 21:06, David Heidelberg wrote:
>>>> +	aliases {
>>>> +		mmc0 = &mmc_0; /* eMMC */
>>>> +		mmc1 = &mmc_1; /* WiFi */
>>>> +	};
>>>> +
>>>> +	bmp180_vdda_reg: regulator-bmp180-vdda {
>>>> +		compatible = "regulator-fixed";
>>>> +		regulator-name = "BMP180_VDDA";
>>>> +	};
>>> something-something-regulator (all occurences within the DTS)
>>>
>>
>> I don't understand this suggestion.
> 
> oh right, let me clarify,
> 
> the regulator name should end with -regulator postfix.

That is not a correct suggestion for none of the SoC trees. If you
wanted to be consistent with old Exynos, then look at the sources - this
is voltage-regulator. But if we are nitpicking on that, this should be
either matching new code (regulator) or even the new style from DT bindings.

You have never reviewed anything on samsung-soc, so I wonder if this is
result of cc-ing this phone-devel. If that's the case, that list should
be just ignored.

Please do not nitpick on such stuff, especially on things not being
correct in terms of recommended style or bindings.


Best regards,
Krzysztof


From nicolinc at nvidia.com  Mon Dec 15 12:51:03 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Mon, 15 Dec 2025 12:51:03 -0800
Subject: [PATCH rc v3 1/4] iommu/arm-smmu-v3: Add ignored bits to fix STE
 update sequence
In-Reply-To: <aT87A1ur4htPjM5T@google.com>
References: <cover.1765334526.git.nicolinc@nvidia.com>
 <cc0d4ab571e2e789ee1cddfa035379dc54f0601b.1765334526.git.nicolinc@nvidia.com>
 <aT87A1ur4htPjM5T@google.com>
Message-ID: <aUB0t4MSf624Wwmw@Asurada-Nvidia>

Hi Mostafa,

On Sun, Dec 14, 2025 at 10:32:35PM +0000, Mostafa Saleh wrote:
> On Tue, Dec 09, 2025 at 06:45:16PM -0800, Nicolin Chen wrote:
> > @@ -1207,12 +1223,9 @@ void arm_smmu_write_entry(struct arm_smmu_entry_writer *writer, __le64 *entry,
> >  		entry_set(writer, entry, target, 0, 1);
> >  	} else {
> >  		/*
> > -		 * No inuse bit changed. Sanity check that all unused bits are 0
> > -		 * in the entry. The target was already sanity checked by
> > -		 * compute_qword_diff().
> > +		 * No inuse bit changed, though ignored bits may have changed.
> >  		 */
> > -		WARN_ON_ONCE(
> > -			entry_set(writer, entry, target, 0, NUM_ENTRY_QWORDS));
> > +		entry_set(writer, entry, target, 0, NUM_ENTRY_QWORDS);
> 
> After this change, no other caller uses the entry_set() return value, so it
> can be changed to return void.

OK.

> >  	}
> >  }
> >  EXPORT_SYMBOL_IF_KUNIT(arm_smmu_write_entry);
> > @@ -1543,6 +1556,7 @@ static void arm_smmu_ste_writer_sync_entry(struct arm_smmu_entry_writer *writer)
> >  static const struct arm_smmu_entry_writer_ops arm_smmu_ste_writer_ops = {
> >  	.sync = arm_smmu_ste_writer_sync_entry,
> >  	.get_used = arm_smmu_get_ste_used,
> > +	.get_ignored = arm_smmu_get_ste_ignored,
> >  };
> >  
> 
> I have some mixed feelings about this, having get_used(), then get_ignored()
> with the same bits set seems confusing to me, specially the get_ignored()
> loops back to update cur_used, which is set from get_used()
> 
> My initial though was just to remove this bit from get_used() + some changes
> to checks setting bits that are not used would be enough, and the semantics
> of get_used() can be something as:
> ?Return bits used by the updated translation regime that MUST be observed
> atomically? and in that case we can ignore things as MEV as it doesn?t
> impact the translation.
> 
> However, this approach makes it a bit explicit which bits are ignored, if we
> keep this logic, I think changing the name of get_ignored() might help, to
> something as "get_allowed_break()" or "get_update_safe()"?

I think "ignored" itself is brief and understandable.. Instead,
perhaps we can add a kdocs to make it clearer:

/**
 * struct arm_smmu_entry_writer_ops - STE/CD entry writer operations
 * @get_used: Output to @used the bits used by the hardware corresponding to the
 *            configurations bits set in a given @entry
 * @get_ignored: Output to @ignored the bits that are listed in the "used" list
 *               but allowed to be ignored by arm_smmu_entry_qword_diff(). Each
 *               field (bits) must provide a reason to justify that the entries
 *               can be updated safely without breaking STE/CD configurations.
 * @sync: Operation to synchronize the updated STE/CD entries in the memory
 */
struct arm_smmu_entry_writer_ops {
	void (*get_used)(const __le64 *entry, __le64 *used);
	void (*get_ignored)(__le64 *ignored);
	void (*sync)(struct arm_smmu_entry_writer *writer);
};

?

Thanks
Nicolin


From david at ixit.cz  Mon Dec 15 12:53:15 2025
From: david at ixit.cz (David Heidelberg)
Date: Mon, 15 Dec 2025 21:53:15 +0100
Subject: [PATCH v3 2/3] ARM: dts: exynos: Add Google Manta (Nexus 10)
In-Reply-To: <cc15ff73-7322-41a9-b0db-a321d6835c36@kernel.org>
References: <20251215-lat3st-staging-v3-0-2e4914b64dd8@timmermann.space>
 <20251215-lat3st-staging-v3-2-2e4914b64dd8@timmermann.space>
 <c62d6c99-0c8d-40e5-95fc-ae73ecaca926@ixit.cz>
 <546ff0cb-a3a2-4fa4-a78b-79c923ed7765@kernel.org>
 <eb898d21-5fda-474d-979e-18da33a85415@ixit.cz>
 <cc15ff73-7322-41a9-b0db-a321d6835c36@kernel.org>
Message-ID: <5c780cb5-d605-4568-bb53-e0fc0885f6a0@ixit.cz>

On 15/12/2025 21:33, Krzysztof Kozlowski wrote:
> On 15/12/2025 21:06, David Heidelberg wrote:
>>>>> +	aliases {
>>>>> +		mmc0 = &mmc_0; /* eMMC */
>>>>> +		mmc1 = &mmc_1; /* WiFi */
>>>>> +	};
>>>>> +
>>>>> +	bmp180_vdda_reg: regulator-bmp180-vdda {
>>>>> +		compatible = "regulator-fixed";
>>>>> +		regulator-name = "BMP180_VDDA";
>>>>> +	};
>>>> something-something-regulator (all occurences within the DTS)
>>>>
>>>
>>> I don't understand this suggestion.
>>
>> oh right, let me clarify,
>>
>> the regulator name should end with -regulator postfix.
> 
> That is not a correct suggestion for none of the SoC trees. If you
> wanted to be consistent with old Exynos, then look at the sources - this
> is voltage-regulator. But if we are nitpicking on that, this should be
> either matching new code (regulator) or even the new style from DT bindings.

Oh, sorry, my bad.

> 
> You have never reviewed anything on samsung-soc, so I wonder if this is
> result of cc-ing this phone-devel. If that's the case, that list should
> be just ignored.
> 
> Please do not nitpick on such stuff, especially on things not being
> correct in terms of recommended style or bindings.

Ok, sure.

Please ignore my review.

David

> 
> 
> Best regards,
> Krzysztof



From Frank.li at nxp.com  Mon Dec 15 13:07:48 2025
From: Frank.li at nxp.com (Frank Li)
Date: Mon, 15 Dec 2025 16:07:48 -0500
Subject: [PATCH v2 0/4] s32g: Use a syscon for GPR
In-Reply-To: <aUBrV2_Iv4oTPkC4@stanley.mountain>
References: <cover.1765806521.git.dan.carpenter@linaro.org>
 <aUAvwRmIZBC0W6ql@lizhi-Precision-Tower-5810>
 <aUBUkuLf7NHtLSl1@stanley.mountain>
 <aUBha2/xiZsIF/o5@lizhi-Precision-Tower-5810>
 <aUBrV2_Iv4oTPkC4@stanley.mountain>
Message-ID: <aUB4pFEwmMBzW52T@lizhi-Precision-Tower-5810>

On Mon, Dec 15, 2025 at 11:11:03PM +0300, Dan Carpenter wrote:
> On Mon, Dec 15, 2025 at 02:28:43PM -0500, Frank Li wrote:
> > On Mon, Dec 15, 2025 at 09:33:54PM +0300, Dan Carpenter wrote:
> > > On Mon, Dec 15, 2025 at 10:56:49AM -0500, Frank Li wrote:
> > > > On Mon, Dec 15, 2025 at 05:41:43PM +0300, Dan Carpenter wrote:
> > > > > The s32g devices have a GPR register region which holds a number of
> > > > > miscellaneous registers.  Currently only the stmmac/dwmac-s32.c uses
> > > > > anything from there and we just add a line to the device tree to
> > > > > access that GMAC_0_CTRL_STS register:
> > > > >
> > > > >                         reg = <0x4033c000 0x2000>, /* gmac IP */
> > > > >                               <0x4007c004 0x4>;    /* GMAC_0_CTRL_STS */
> > > > >
> > > > > We still have to maintain backwards compatibility to this format,
> > > > > of course, but it would be better to access these through a syscon.
> > > > > First of all, putting all the registers together is more organized
> > > > > and shows how the hardware actually is implemented.  Secondly, in
> > > > > some versions of this chipset those registers can only be accessed
> > > > > via SCMI, if the registers aren't grouped together each driver will
> > > > > have to create a whole lot of if then statements to access it via
> > > > > IOMEM or via SCMI,
> > > >
> > > > Does SCMI work as regmap? syscon look likes simple, but missed abstract
> > > > in overall.
> > > >
> > >
> > > The SCMI part of this is pretty complicated and needs discussion.  It
> > > might be that it requires a vendor extension.  Right now, the out of
> > > tree code uses a nvmem vendor extension but that probably won't get
> > > merged upstream.
> > >
> > > But in theory, it's fairly simple, you can write a regmap driver and
> > > register it as a syscon and everything that was accessing nxp,phy-sel
> > > accesses the same register but over SCMI.
> >
> > nxp,phy-sel is not standard API. Driver access raw register value. such
> > as write 1 to offset 0x100.
> >
> > After change to SCMI, which may mapped to difference command. Even change
> > to other SOC, value and offset also need be changed. It is not standilzed
> > as what you expected.
>
> We're writing to an offset in a syscon.  Right now the device tree
> says that the syscon is an MMIO syscon.  But for SCMI devices we
> would point the phandle to a custom syscon.  The phandle and the offset
> would stay the same, but how the syscon is implemented would change.

Your SCMI syscon driver will convert some private hard code to some
function, such previous example's '1' as SEL_RGMII. It is hard maintained
in long term.

>
> >
> > >
> > > > You still use regmap by use MMIO. /* GMAC_0_CTRL_STS */
> > > >
> > > > regmap = devm_regmap_init_mmio(dev, sts_offset, &regmap_config);
> > > >
> > >
> > > You can use have an MMIO syscon, or you can create a custom driver
> > > and register it as a syscon using of_syscon_register_regmap().
> >
> > My means is that it is not necessary to create nxp,phy-sel, especially
> > there already have <0x4007c004 0x4>;    /* GMAC_0_CTRL_STS */
> >
>
> Right now the out of tree dwmac-s32cc.c driver does something like
> this:
>
>     89          if (gmac->use_nvmem) {
>     90                  ret = write_nvmem_cell(gmac->dev, "gmac_phy_intf_sel", intf_sel);
>     91                  if (ret)
>     92                          return ret;
>     93          } else {
>     94                  writel(intf_sel, gmac->ctrl_sts);
>     95          }
>
> Which is quite complicated, but with a syscon, then it's just:
>
> 	regmap_write(gmac->sts_regmap, gmac->sts_offset, S32_PHY_INTF_SEL_RGMII);
>
> Even without SCMI, the hardware has all these registers grouped together
> it just feels cleaner to group them together in the device tree as well.

Why not implement standard phy interface,
phy_set_mode_ext(PHY_MODE_ETHERNET, RGMII);

For example:  drivers/pci/controller/dwc/pci-imx6.c

In legency platform, it use syscon to set some registers. It becomes mess
when more platform added.  And it becomes hard to convert because avoid
break compatibltiy now.

It doesn't become worse since new platforms switched to use standard
inteface, (phy, reset ...).

Frank

>
> regards,
> dan carpenter
>


From jolsa at kernel.org  Mon Dec 15 13:13:53 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Mon, 15 Dec 2025 22:13:53 +0100
Subject: [PATCHv5 bpf-next 0/9] ftrace,bpf: Use single direct ops for bpf trampolines
Message-ID: <20251215211402.353056-1-jolsa@kernel.org>

hi,
while poking the multi-tracing interface I ended up with just one ftrace_ops
object to attach all trampolines.

This change allows to use less direct API calls during the attachment changes
in the future code, so in effect speeding up the attachment.

In current code we get a speed up from using just a single ftrace_ops object.

- with current code:

  Performance counter stats for 'bpftrace -e fentry:vmlinux:ksys_* {} -c true':

     6,364,157,902      cycles:k
       828,728,902      cycles:u
     1,064,803,824      instructions:u                   #    1.28  insn per cycle
    23,797,500,067      instructions:k                   #    3.74  insn per cycle

       4.416004987 seconds time elapsed

       0.164121000 seconds user
       1.289550000 seconds sys


- with the fix:

   Performance counter stats for 'bpftrace -e fentry:vmlinux:ksys_* {} -c true':

     6,535,857,905      cycles:k
       810,809,429      cycles:u
     1,064,594,027      instructions:u                   #    1.31  insn per cycle
    23,962,552,894      instructions:k                   #    3.67  insn per cycle

       1.666961239 seconds time elapsed

       0.157412000 seconds user
       1.283396000 seconds sys



The speedup seems to be related to the fact that with single ftrace_ops object
we don't call ftrace_shutdown anymore (we use ftrace_update_ops instead) and
we skip the synchronize rcu calls (each ~100ms) at the end of that function.

rfc: https://lore.kernel.org/bpf/20250729102813.1531457-1-jolsa at kernel.org/
v1:  https://lore.kernel.org/bpf/20250923215147.1571952-1-jolsa at kernel.org/
v2:  https://lore.kernel.org/bpf/20251113123750.2507435-1-jolsa at kernel.org/
v3:  https://lore.kernel.org/bpf/20251120212402.466524-1-jolsa at kernel.org/
v4:  https://lore.kernel.org/bpf/20251203082402.78816-1-jolsa at kernel.org/

v5 changes:
- do not export ftrace_hash object [Steven]
- fix update_ftrace_direct_add new_filter_hash leak [ci]

v4 changes:
- rebased on top of bpf-next/master (with jmp attach changes)
  added patch 1 to deal with that
- added extra checks for update_ftrace_direct_del/mod to address
  the ci bot review

v3 changes:
- rebased on top of bpf-next/master
- fixed update_ftrace_direct_del cleanup path
- added missing inline to update_ftrace_direct_* stubs

v2 changes:
- rebased on top fo bpf-next/master plus Song's livepatch fixes [1] 
- renamed the API functions [2] [Steven]
- do not export the new api [Steven]
- kept the original direct interface:

  I'm not sure if we want to melt both *_ftrace_direct and the new interface
  into single one. It's bit different in semantic (hence the name change as
  Steven suggested [2]) and I don't think the changes are not that big so
  we could easily keep both APIs.

v1 changes:
- make the change x86 specific, after discussing with Mark options for
  arm64 [Mark]

thanks,
jirka


[1] https://lore.kernel.org/bpf/20251027175023.1521602-1-song at kernel.org/
[2] https://lore.kernel.org/bpf/20250924050415.4aefcb91 at batman.local.home/
---
Jiri Olsa (9):
      ftrace,bpf: Remove FTRACE_OPS_FL_JMP ftrace_ops flag
      ftrace: Make alloc_and_copy_ftrace_hash direct friendly
      ftrace: Export some of hash related functions
      ftrace: Add update_ftrace_direct_add function
      ftrace: Add update_ftrace_direct_del function
      ftrace: Add update_ftrace_direct_mod function
      bpf: Add trampoline ip hash table
      ftrace: Factor ftrace_ops ops_func interface
      bpf,x86: Use single ftrace_ops for direct calls

 arch/x86/Kconfig        |   1 +
 include/linux/bpf.h     |   7 ++-
 include/linux/ftrace.h  |  31 ++++++++++-
 kernel/bpf/trampoline.c | 234 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
 kernel/trace/Kconfig    |   3 ++
 kernel/trace/ftrace.c   | 357 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
 6 files changed, 560 insertions(+), 73 deletions(-)


From jolsa at kernel.org  Mon Dec 15 13:13:54 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Mon, 15 Dec 2025 22:13:54 +0100
Subject: [PATCHv5 bpf-next 1/9] ftrace,bpf: Remove FTRACE_OPS_FL_JMP ftrace_ops flag
In-Reply-To: <20251215211402.353056-1-jolsa@kernel.org>
References: <20251215211402.353056-1-jolsa@kernel.org>
Message-ID: <20251215211402.353056-2-jolsa@kernel.org>

At the moment the we allow the jmp attach only for ftrace_ops that
has FTRACE_OPS_FL_JMP set. This conflicts with following changes
where we use single ftrace_ops object for all direct call sites,
so all could be be attached via just call or jmp.

We already limit the jmp attach support with config option and bit
(LSB) set on the trampoline address. It turns out that's actually
enough to limit the jmp attach for architecture and only for chosen
addresses (with LSB bit set).

Each user of register_ftrace_direct or modify_ftrace_direct can set
the trampoline bit (LSB) to indicate it has to be attached by jmp.

The bpf trampoline generation code uses trampoline flags to generate
jmp-attach specific code and ftrace inner code uses the trampoline
bit (LSB) to handle return from jmp attachment, so there's no harm
to remove the FTRACE_OPS_FL_JMP bit.

The fexit/fmodret performance stays the same (did not drop),
current code:

  fentry         :   77.904 ? 0.546M/s
  fexit          :   62.430 ? 0.554M/s
  fmodret        :   66.503 ? 0.902M/s

with this change:

  fentry         :   80.472 ? 0.061M/s
  fexit          :   63.995 ? 0.127M/s
  fmodret        :   67.362 ? 0.175M/s

Fixes: 25e4e3565d45 ("ftrace: Introduce FTRACE_OPS_FL_JMP")
Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 include/linux/ftrace.h  |  1 -
 kernel/bpf/trampoline.c | 32 ++++++++++++++------------------
 kernel/trace/ftrace.c   | 14 --------------
 3 files changed, 14 insertions(+), 33 deletions(-)

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 015dd1049bea..505b7d3f5641 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -359,7 +359,6 @@ enum {
 	FTRACE_OPS_FL_DIRECT			= BIT(17),
 	FTRACE_OPS_FL_SUBOP			= BIT(18),
 	FTRACE_OPS_FL_GRAPH			= BIT(19),
-	FTRACE_OPS_FL_JMP			= BIT(20),
 };
 
 #ifndef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index 976d89011b15..b9a358d7a78f 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -214,10 +214,15 @@ static int modify_fentry(struct bpf_trampoline *tr, u32 orig_flags,
 	int ret;
 
 	if (tr->func.ftrace_managed) {
+		unsigned long addr = (unsigned long) new_addr;
+
+		if (bpf_trampoline_use_jmp(tr->flags))
+			addr = ftrace_jmp_set(addr);
+
 		if (lock_direct_mutex)
-			ret = modify_ftrace_direct(tr->fops, (long)new_addr);
+			ret = modify_ftrace_direct(tr->fops, addr);
 		else
-			ret = modify_ftrace_direct_nolock(tr->fops, (long)new_addr);
+			ret = modify_ftrace_direct_nolock(tr->fops, addr);
 	} else {
 		ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr,
 						   new_addr);
@@ -240,10 +245,15 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
 	}
 
 	if (tr->func.ftrace_managed) {
+		unsigned long addr = (unsigned long) new_addr;
+
+		if (bpf_trampoline_use_jmp(tr->flags))
+			addr = ftrace_jmp_set(addr);
+
 		ret = ftrace_set_filter_ip(tr->fops, (unsigned long)ip, 0, 1);
 		if (ret)
 			return ret;
-		ret = register_ftrace_direct(tr->fops, (long)new_addr);
+		ret = register_ftrace_direct(tr->fops, addr);
 	} else {
 		ret = bpf_trampoline_update_fentry(tr, 0, NULL, new_addr);
 	}
@@ -499,13 +509,6 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut
 	if (err)
 		goto out_free;
 
-#ifdef CONFIG_DYNAMIC_FTRACE_WITH_JMP
-	if (bpf_trampoline_use_jmp(tr->flags))
-		tr->fops->flags |= FTRACE_OPS_FL_JMP;
-	else
-		tr->fops->flags &= ~FTRACE_OPS_FL_JMP;
-#endif
-
 	WARN_ON(tr->cur_image && total == 0);
 	if (tr->cur_image)
 		/* progs already running at this address */
@@ -533,15 +536,8 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut
 	tr->cur_image = im;
 out:
 	/* If any error happens, restore previous flags */
-	if (err) {
+	if (err)
 		tr->flags = orig_flags;
-#ifdef CONFIG_DYNAMIC_FTRACE_WITH_JMP
-		if (bpf_trampoline_use_jmp(tr->flags))
-			tr->fops->flags |= FTRACE_OPS_FL_JMP;
-		else
-			tr->fops->flags &= ~FTRACE_OPS_FL_JMP;
-#endif
-	}
 	kfree(tlinks);
 	return err;
 
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index bbb37c0f8c6c..b0dc911411f1 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -6017,15 +6017,8 @@ int register_ftrace_direct(struct ftrace_ops *ops, unsigned long addr)
 	if (ftrace_hash_empty(hash))
 		return -EINVAL;
 
-	/* This is a "raw" address, and this should never happen. */
-	if (WARN_ON_ONCE(ftrace_is_jmp(addr)))
-		return -EINVAL;
-
 	mutex_lock(&direct_mutex);
 
-	if (ops->flags & FTRACE_OPS_FL_JMP)
-		addr = ftrace_jmp_set(addr);
-
 	/* Make sure requested entries are not already registered.. */
 	size = 1 << hash->size_bits;
 	for (i = 0; i < size; i++) {
@@ -6146,13 +6139,6 @@ __modify_ftrace_direct(struct ftrace_ops *ops, unsigned long addr)
 
 	lockdep_assert_held_once(&direct_mutex);
 
-	/* This is a "raw" address, and this should never happen. */
-	if (WARN_ON_ONCE(ftrace_is_jmp(addr)))
-		return -EINVAL;
-
-	if (ops->flags & FTRACE_OPS_FL_JMP)
-		addr = ftrace_jmp_set(addr);
-
 	/* Enable the tmp_ops to have the same functions as the direct ops */
 	ftrace_ops_init(&tmp_ops);
 	tmp_ops.func_hash = ops->func_hash;
-- 
2.52.0



From jolsa at kernel.org  Mon Dec 15 13:13:55 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Mon, 15 Dec 2025 22:13:55 +0100
Subject: [PATCHv5 bpf-next 2/9] ftrace: Make alloc_and_copy_ftrace_hash direct friendly
In-Reply-To: <20251215211402.353056-1-jolsa@kernel.org>
References: <20251215211402.353056-1-jolsa@kernel.org>
Message-ID: <20251215211402.353056-3-jolsa@kernel.org>

Make alloc_and_copy_ftrace_hash to copy also direct address
for each hash entry.

Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 kernel/trace/ftrace.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index b0dc911411f1..7e3a81bd6f1e 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1186,7 +1186,7 @@ static void __add_hash_entry(struct ftrace_hash *hash,
 }
 
 static struct ftrace_func_entry *
-add_hash_entry(struct ftrace_hash *hash, unsigned long ip)
+add_hash_entry_direct(struct ftrace_hash *hash, unsigned long ip, unsigned long direct)
 {
 	struct ftrace_func_entry *entry;
 
@@ -1195,11 +1195,18 @@ add_hash_entry(struct ftrace_hash *hash, unsigned long ip)
 		return NULL;
 
 	entry->ip = ip;
+	entry->direct = direct;
 	__add_hash_entry(hash, entry);
 
 	return entry;
 }
 
+static struct ftrace_func_entry *
+add_hash_entry(struct ftrace_hash *hash, unsigned long ip)
+{
+	return add_hash_entry_direct(hash, ip, 0);
+}
+
 static void
 free_hash_entry(struct ftrace_hash *hash,
 		  struct ftrace_func_entry *entry)
@@ -1372,7 +1379,7 @@ alloc_and_copy_ftrace_hash(int size_bits, struct ftrace_hash *hash)
 	size = 1 << hash->size_bits;
 	for (i = 0; i < size; i++) {
 		hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
-			if (add_hash_entry(new_hash, entry->ip) == NULL)
+			if (add_hash_entry_direct(new_hash, entry->ip, entry->direct) == NULL)
 				goto free_hash;
 		}
 	}
-- 
2.52.0



From jolsa at kernel.org  Mon Dec 15 13:13:56 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Mon, 15 Dec 2025 22:13:56 +0100
Subject: [PATCHv5 bpf-next 3/9] ftrace: Export some of hash related functions
In-Reply-To: <20251215211402.353056-1-jolsa@kernel.org>
References: <20251215211402.353056-1-jolsa@kernel.org>
Message-ID: <20251215211402.353056-4-jolsa@kernel.org>

We are going to use these functions in following changes.

Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 include/linux/ftrace.h | 9 +++++++++
 kernel/trace/ftrace.c  | 7 +++----
 2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 505b7d3f5641..c0a72fcae1f6 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -82,6 +82,7 @@ static inline void early_trace_init(void) { }
 
 struct module;
 struct ftrace_hash;
+struct ftrace_func_entry;
 
 #if defined(CONFIG_FUNCTION_TRACER) && defined(CONFIG_MODULES) && \
 	defined(CONFIG_DYNAMIC_FTRACE)
@@ -405,6 +406,14 @@ enum ftrace_ops_cmd {
 typedef int (*ftrace_ops_func_t)(struct ftrace_ops *op, enum ftrace_ops_cmd cmd);
 
 #ifdef CONFIG_DYNAMIC_FTRACE
+
+#define FTRACE_HASH_DEFAULT_BITS 10
+
+struct ftrace_hash *alloc_ftrace_hash(int size_bits);
+void free_ftrace_hash(struct ftrace_hash *hash);
+struct ftrace_func_entry *add_hash_entry_direct(struct ftrace_hash *hash,
+						unsigned long ip, unsigned long direct);
+
 /* The hash used to know what functions callbacks trace */
 struct ftrace_ops_hash {
 	struct ftrace_hash __rcu	*notrace_hash;
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 7e3a81bd6f1e..84aee9096a9e 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -68,7 +68,6 @@
 	})
 
 /* hash bits for specific function selection */
-#define FTRACE_HASH_DEFAULT_BITS 10
 #define FTRACE_HASH_MAX_BITS 12
 
 #ifdef CONFIG_DYNAMIC_FTRACE
@@ -1185,7 +1184,7 @@ static void __add_hash_entry(struct ftrace_hash *hash,
 	hash->count++;
 }
 
-static struct ftrace_func_entry *
+struct ftrace_func_entry *
 add_hash_entry_direct(struct ftrace_hash *hash, unsigned long ip, unsigned long direct)
 {
 	struct ftrace_func_entry *entry;
@@ -1265,7 +1264,7 @@ static void clear_ftrace_mod_list(struct list_head *head)
 	mutex_unlock(&ftrace_lock);
 }
 
-static void free_ftrace_hash(struct ftrace_hash *hash)
+void free_ftrace_hash(struct ftrace_hash *hash)
 {
 	if (!hash || hash == EMPTY_HASH)
 		return;
@@ -1305,7 +1304,7 @@ void ftrace_free_filter(struct ftrace_ops *ops)
 }
 EXPORT_SYMBOL_GPL(ftrace_free_filter);
 
-static struct ftrace_hash *alloc_ftrace_hash(int size_bits)
+struct ftrace_hash *alloc_ftrace_hash(int size_bits)
 {
 	struct ftrace_hash *hash;
 	int size;
-- 
2.52.0



From jolsa at kernel.org  Mon Dec 15 13:13:57 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Mon, 15 Dec 2025 22:13:57 +0100
Subject: [PATCHv5 bpf-next 4/9] ftrace: Add update_ftrace_direct_add function
In-Reply-To: <20251215211402.353056-1-jolsa@kernel.org>
References: <20251215211402.353056-1-jolsa@kernel.org>
Message-ID: <20251215211402.353056-5-jolsa@kernel.org>

Adding update_ftrace_direct_add function that adds all entries
(ip -> addr) provided in hash argument to direct ftrace ops
and updates its attachments.

The difference to current register_ftrace_direct is
 - hash argument that allows to register multiple ip -> direct
   entries at once
 - we can call update_ftrace_direct_add multiple times on the
   same ftrace_ops object, becase after first registration with
   register_ftrace_function_nolock, it uses ftrace_update_ops to
   update the ftrace_ops object

This change will allow us to have simple ftrace_ops for all bpf
direct interface users in following changes.

Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 include/linux/ftrace.h |   7 +++
 kernel/trace/ftrace.c  | 128 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 135 insertions(+)

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index c0a72fcae1f6..5cf151cb8e6d 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -543,6 +543,8 @@ int unregister_ftrace_direct(struct ftrace_ops *ops, unsigned long addr,
 int modify_ftrace_direct(struct ftrace_ops *ops, unsigned long addr);
 int modify_ftrace_direct_nolock(struct ftrace_ops *ops, unsigned long addr);
 
+int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash);
+
 void ftrace_stub_direct_tramp(void);
 
 #else
@@ -569,6 +571,11 @@ static inline int modify_ftrace_direct_nolock(struct ftrace_ops *ops, unsigned l
 	return -ENODEV;
 }
 
+static inline int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash)
+{
+	return -ENODEV;
+}
+
 /*
  * This must be implemented by the architecture.
  * It is the way the ftrace direct_ops helper, when called
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 84aee9096a9e..ec7d93460dac 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -6249,6 +6249,134 @@ int modify_ftrace_direct(struct ftrace_ops *ops, unsigned long addr)
 	return err;
 }
 EXPORT_SYMBOL_GPL(modify_ftrace_direct);
+
+static unsigned long hash_count(struct ftrace_hash *hash)
+{
+	return hash ? hash->count : 0;
+}
+
+/**
+ * hash_add - adds two struct ftrace_hash and returns the result
+ * @a: struct ftrace_hash object
+ * @b: struct ftrace_hash object
+ *
+ * Returns struct ftrace_hash object on success, NULL on error.
+ */
+static struct ftrace_hash *hash_add(struct ftrace_hash *a, struct ftrace_hash *b)
+{
+	struct ftrace_func_entry *entry;
+	struct ftrace_hash *add;
+	int size, i;
+
+	size = hash_count(a) + hash_count(b);
+	if (size > 32)
+		size = 32;
+
+	add = alloc_and_copy_ftrace_hash(fls(size), a);
+	if (!add)
+		goto error;
+
+	size = 1 << b->size_bits;
+	for (i = 0; i < size; i++) {
+		hlist_for_each_entry(entry, &b->buckets[i], hlist) {
+			if (add_hash_entry_direct(add, entry->ip, entry->direct) == NULL)
+				goto error;
+		}
+	}
+	return add;
+
+ error:
+	free_ftrace_hash(add);
+	return NULL;
+}
+
+int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash)
+{
+	struct ftrace_hash *old_direct_functions = NULL, *new_direct_functions;
+	struct ftrace_hash *old_filter_hash, *new_filter_hash = NULL;
+	struct ftrace_func_entry *entry;
+	int i, size, err = -EINVAL;
+	bool reg;
+
+	if (!hash_count(hash))
+		return -EINVAL;
+
+	mutex_lock(&direct_mutex);
+
+	/* Make sure requested entries are not already registered. */
+	size = 1 << hash->size_bits;
+	for (i = 0; i < size; i++) {
+		hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
+			if (__ftrace_lookup_ip(direct_functions, entry->ip))
+				goto out_unlock;
+		}
+	}
+
+	old_filter_hash = ops->func_hash ? ops->func_hash->filter_hash : NULL;
+
+	/* If there's nothing in filter_hash we need to register the ops. */
+	reg = hash_count(old_filter_hash) == 0;
+	if (reg) {
+		if (ops->func || ops->trampoline)
+			goto out_unlock;
+		if (ops->flags & FTRACE_OPS_FL_ENABLED)
+			goto out_unlock;
+	}
+
+	err = -ENOMEM;
+	new_filter_hash = hash_add(old_filter_hash, hash);
+	if (!new_filter_hash)
+		goto out_unlock;
+
+	new_direct_functions = hash_add(direct_functions, hash);
+	if (!new_direct_functions)
+		goto out_unlock;
+
+	old_direct_functions = direct_functions;
+	rcu_assign_pointer(direct_functions, new_direct_functions);
+
+	if (reg) {
+		ops->func = call_direct_funcs;
+		ops->flags |= MULTI_FLAGS;
+		ops->trampoline = FTRACE_REGS_ADDR;
+		ops->local_hash.filter_hash = new_filter_hash;
+
+		err = register_ftrace_function_nolock(ops);
+		if (err) {
+			/* restore old filter on error */
+			ops->local_hash.filter_hash = old_filter_hash;
+
+			/* cleanup for possible another register call */
+			ops->func = NULL;
+			ops->trampoline = 0;
+		} else {
+			new_filter_hash = old_filter_hash;
+		}
+	} else {
+		err = ftrace_update_ops(ops, new_filter_hash, EMPTY_HASH);
+		/*
+		 * new_filter_hash is dup-ed, so we need to release it anyway,
+		 * old_filter_hash either stays on error or is already released
+		 */
+	}
+
+	if (err) {
+		/* reset direct_functions and free the new one */
+		rcu_assign_pointer(direct_functions, old_direct_functions);
+		old_direct_functions = new_direct_functions;
+	}
+
+ out_unlock:
+	mutex_unlock(&direct_mutex);
+
+	if (old_direct_functions && old_direct_functions != EMPTY_HASH)
+		call_rcu_tasks(&old_direct_functions->rcu, register_ftrace_direct_cb);
+	if (new_filter_hash)
+		free_ftrace_hash(new_filter_hash);
+
+	return err;
+}
+
 #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
 
 /**
-- 
2.52.0



From jolsa at kernel.org  Mon Dec 15 13:13:58 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Mon, 15 Dec 2025 22:13:58 +0100
Subject: [PATCHv5 bpf-next 5/9] ftrace: Add update_ftrace_direct_del function
In-Reply-To: <20251215211402.353056-1-jolsa@kernel.org>
References: <20251215211402.353056-1-jolsa@kernel.org>
Message-ID: <20251215211402.353056-6-jolsa@kernel.org>

Adding update_ftrace_direct_del function that removes all entries
(ip -> addr) provided in hash argument to direct ftrace ops and
updates its attachments.

The difference to current unregister_ftrace_direct is
 - hash argument that allows to unregister multiple ip -> direct
   entries at once
 - we can call update_ftrace_direct_del multiple times on the
   same ftrace_ops object, becase we do not need to unregister
   all entries at once, we can do it gradualy with the help of
   ftrace_update_ops function

This change will allow us to have simple ftrace_ops for all bpf
direct interface users in following changes.

Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 include/linux/ftrace.h |   6 +++
 kernel/trace/ftrace.c  | 112 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 118 insertions(+)

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 5cf151cb8e6d..ac4b473c7fd3 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -544,6 +544,7 @@ int modify_ftrace_direct(struct ftrace_ops *ops, unsigned long addr);
 int modify_ftrace_direct_nolock(struct ftrace_ops *ops, unsigned long addr);
 
 int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash);
+int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash);
 
 void ftrace_stub_direct_tramp(void);
 
@@ -576,6 +577,11 @@ static inline int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace
 	return -ENODEV;
 }
 
+static inline int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash)
+{
+	return -ENODEV;
+}
+
 /*
  * This must be implemented by the architecture.
  * It is the way the ftrace direct_ops helper, when called
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index ec7d93460dac..48dc0de5f2ce 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -6377,6 +6377,118 @@ int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash)
 	return err;
 }
 
+/**
+ * hash_sub - substracts @b from @a and returns the result
+ * @a: struct ftrace_hash object
+ * @b: struct ftrace_hash object
+ *
+ * Returns struct ftrace_hash object on success, NULL on error.
+ */
+static struct ftrace_hash *hash_sub(struct ftrace_hash *a, struct ftrace_hash *b)
+{
+	struct ftrace_func_entry *entry, *del;
+	struct ftrace_hash *sub;
+	int size, i;
+
+	sub = alloc_and_copy_ftrace_hash(a->size_bits, a);
+	if (!sub)
+		goto error;
+
+	size = 1 << b->size_bits;
+	for (i = 0; i < size; i++) {
+		hlist_for_each_entry(entry, &b->buckets[i], hlist) {
+			del = __ftrace_lookup_ip(sub, entry->ip);
+			if (WARN_ON_ONCE(!del))
+				goto error;
+			remove_hash_entry(sub, del);
+			kfree(del);
+		}
+	}
+	return sub;
+
+ error:
+	free_ftrace_hash(sub);
+	return NULL;
+}
+
+int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash)
+{
+	struct ftrace_hash *old_direct_functions = NULL, *new_direct_functions;
+	struct ftrace_hash *old_filter_hash, *new_filter_hash = NULL;
+	struct ftrace_func_entry *del, *entry;
+	unsigned long size, i;
+	int err = -EINVAL;
+
+	if (!hash_count(hash))
+		return -EINVAL;
+	if (check_direct_multi(ops))
+		return -EINVAL;
+	if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
+		return -EINVAL;
+	if (direct_functions == EMPTY_HASH)
+		return -EINVAL;
+
+	mutex_lock(&direct_mutex);
+
+	old_filter_hash = ops->func_hash ? ops->func_hash->filter_hash : NULL;
+
+	if (!hash_count(old_filter_hash))
+		goto out_unlock;
+
+	/* Make sure requested entries are already registered. */
+	size = 1 << hash->size_bits;
+	for (i = 0; i < size; i++) {
+		hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
+			del = __ftrace_lookup_ip(direct_functions, entry->ip);
+			if (!del || del->direct != entry->direct)
+				goto out_unlock;
+		}
+	}
+
+	err = -ENOMEM;
+	new_filter_hash = hash_sub(old_filter_hash, hash);
+	if (!new_filter_hash)
+		goto out_unlock;
+
+	new_direct_functions = hash_sub(direct_functions, hash);
+	if (!new_direct_functions)
+		goto out_unlock;
+
+	/* If there's nothing left, we need to unregister the ops. */
+	if (ftrace_hash_empty(new_filter_hash)) {
+		err = unregister_ftrace_function(ops);
+		if (!err) {
+			/* cleanup for possible another register call */
+			ops->func = NULL;
+			ops->trampoline = 0;
+			ftrace_free_filter(ops);
+			ops->func_hash->filter_hash = NULL;
+		}
+	} else {
+		err = ftrace_update_ops(ops, new_filter_hash, EMPTY_HASH);
+		/*
+		 * new_filter_hash is dup-ed, so we need to release it anyway,
+		 * old_filter_hash either stays on error or is already released
+		 */
+	}
+
+	if (err) {
+		/* free the new_direct_functions */
+		old_direct_functions = new_direct_functions;
+	} else {
+		rcu_assign_pointer(direct_functions, new_direct_functions);
+	}
+
+ out_unlock:
+	mutex_unlock(&direct_mutex);
+
+	if (old_direct_functions && old_direct_functions != EMPTY_HASH)
+		call_rcu_tasks(&old_direct_functions->rcu, register_ftrace_direct_cb);
+	free_ftrace_hash(new_filter_hash);
+
+	return err;
+}
+
 #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
 
 /**
-- 
2.52.0



From jolsa at kernel.org  Mon Dec 15 13:14:00 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Mon, 15 Dec 2025 22:14:00 +0100
Subject: [PATCHv5 bpf-next 7/9] bpf: Add trampoline ip hash table
In-Reply-To: <20251215211402.353056-1-jolsa@kernel.org>
References: <20251215211402.353056-1-jolsa@kernel.org>
Message-ID: <20251215211402.353056-8-jolsa@kernel.org>

Following changes need to lookup trampoline based on its ip address,
adding hash table for that.

Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 include/linux/bpf.h     |  7 +++++--
 kernel/bpf/trampoline.c | 30 +++++++++++++++++++-----------
 2 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 28d8d6b7bb1e..7bcb33e2ec9f 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -1307,14 +1307,17 @@ struct bpf_tramp_image {
 };
 
 struct bpf_trampoline {
-	/* hlist for trampoline_table */
-	struct hlist_node hlist;
+	/* hlist for trampoline_key_table */
+	struct hlist_node hlist_key;
+	/* hlist for trampoline_ip_table */
+	struct hlist_node hlist_ip;
 	struct ftrace_ops *fops;
 	/* serializes access to fields of this trampoline */
 	struct mutex mutex;
 	refcount_t refcnt;
 	u32 flags;
 	u64 key;
+	unsigned long ip;
 	struct {
 		struct btf_func_model model;
 		void *addr;
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index b9a358d7a78f..f298bafab76e 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -24,9 +24,10 @@ const struct bpf_prog_ops bpf_extension_prog_ops = {
 #define TRAMPOLINE_HASH_BITS 10
 #define TRAMPOLINE_TABLE_SIZE (1 << TRAMPOLINE_HASH_BITS)
 
-static struct hlist_head trampoline_table[TRAMPOLINE_TABLE_SIZE];
+static struct hlist_head trampoline_key_table[TRAMPOLINE_TABLE_SIZE];
+static struct hlist_head trampoline_ip_table[TRAMPOLINE_TABLE_SIZE];
 
-/* serializes access to trampoline_table */
+/* serializes access to trampoline tables */
 static DEFINE_MUTEX(trampoline_mutex);
 
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
@@ -135,15 +136,15 @@ void bpf_image_ksym_del(struct bpf_ksym *ksym)
 			   PAGE_SIZE, true, ksym->name);
 }
 
-static struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
+static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
 {
 	struct bpf_trampoline *tr;
 	struct hlist_head *head;
 	int i;
 
 	mutex_lock(&trampoline_mutex);
-	head = &trampoline_table[hash_64(key, TRAMPOLINE_HASH_BITS)];
-	hlist_for_each_entry(tr, head, hlist) {
+	head = &trampoline_key_table[hash_64(key, TRAMPOLINE_HASH_BITS)];
+	hlist_for_each_entry(tr, head, hlist_key) {
 		if (tr->key == key) {
 			refcount_inc(&tr->refcnt);
 			goto out;
@@ -164,8 +165,12 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
 #endif
 
 	tr->key = key;
-	INIT_HLIST_NODE(&tr->hlist);
-	hlist_add_head(&tr->hlist, head);
+	tr->ip = ftrace_location(ip);
+	INIT_HLIST_NODE(&tr->hlist_key);
+	INIT_HLIST_NODE(&tr->hlist_ip);
+	hlist_add_head(&tr->hlist_key, head);
+	head = &trampoline_ip_table[hash_64(tr->ip, TRAMPOLINE_HASH_BITS)];
+	hlist_add_head(&tr->hlist_ip, head);
 	refcount_set(&tr->refcnt, 1);
 	mutex_init(&tr->mutex);
 	for (i = 0; i < BPF_TRAMP_MAX; i++)
@@ -846,7 +851,7 @@ void bpf_trampoline_unlink_cgroup_shim(struct bpf_prog *prog)
 					 prog->aux->attach_btf_id);
 
 	bpf_lsm_find_cgroup_shim(prog, &bpf_func);
-	tr = bpf_trampoline_lookup(key);
+	tr = bpf_trampoline_lookup(key, 0);
 	if (WARN_ON_ONCE(!tr))
 		return;
 
@@ -866,7 +871,7 @@ struct bpf_trampoline *bpf_trampoline_get(u64 key,
 {
 	struct bpf_trampoline *tr;
 
-	tr = bpf_trampoline_lookup(key);
+	tr = bpf_trampoline_lookup(key, tgt_info->tgt_addr);
 	if (!tr)
 		return NULL;
 
@@ -902,7 +907,8 @@ void bpf_trampoline_put(struct bpf_trampoline *tr)
 	 * fexit progs. The fentry-only trampoline will be freed via
 	 * multiple rcu callbacks.
 	 */
-	hlist_del(&tr->hlist);
+	hlist_del(&tr->hlist_key);
+	hlist_del(&tr->hlist_ip);
 	if (tr->fops) {
 		ftrace_free_filter(tr->fops);
 		kfree(tr->fops);
@@ -1175,7 +1181,9 @@ static int __init init_trampolines(void)
 	int i;
 
 	for (i = 0; i < TRAMPOLINE_TABLE_SIZE; i++)
-		INIT_HLIST_HEAD(&trampoline_table[i]);
+		INIT_HLIST_HEAD(&trampoline_key_table[i]);
+	for (i = 0; i < TRAMPOLINE_TABLE_SIZE; i++)
+		INIT_HLIST_HEAD(&trampoline_ip_table[i]);
 	return 0;
 }
 late_initcall(init_trampolines);
-- 
2.52.0



From jolsa at kernel.org  Mon Dec 15 13:14:01 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Mon, 15 Dec 2025 22:14:01 +0100
Subject: [PATCHv5 bpf-next 8/9] ftrace: Factor ftrace_ops ops_func interface
In-Reply-To: <20251215211402.353056-1-jolsa@kernel.org>
References: <20251215211402.353056-1-jolsa@kernel.org>
Message-ID: <20251215211402.353056-9-jolsa@kernel.org>

We are going to remove "ftrace_ops->private == bpf_trampoline" setup
in following changes.

Adding ip argument to ftrace_ops_func_t callback function, so we can
use it to look up the trampoline.

Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 include/linux/ftrace.h  | 2 +-
 kernel/bpf/trampoline.c | 3 ++-
 kernel/trace/ftrace.c   | 6 +++---
 3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index c3bf9cede1fe..6f94bad34492 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -403,7 +403,7 @@ enum ftrace_ops_cmd {
  *        Negative on failure. The return value is dependent on the
  *        callback.
  */
-typedef int (*ftrace_ops_func_t)(struct ftrace_ops *op, enum ftrace_ops_cmd cmd);
+typedef int (*ftrace_ops_func_t)(struct ftrace_ops *op, unsigned long ip, enum ftrace_ops_cmd cmd);
 
 #ifdef CONFIG_DYNAMIC_FTRACE
 
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index f298bafab76e..17af2aad8382 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -33,7 +33,8 @@ static DEFINE_MUTEX(trampoline_mutex);
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
 static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mutex);
 
-static int bpf_tramp_ftrace_ops_func(struct ftrace_ops *ops, enum ftrace_ops_cmd cmd)
+static int bpf_tramp_ftrace_ops_func(struct ftrace_ops *ops, unsigned long ip,
+				     enum ftrace_ops_cmd cmd)
 {
 	struct bpf_trampoline *tr = ops->private;
 	int ret = 0;
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 95a38fb18ed7..c2054fe80de7 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -2049,7 +2049,7 @@ static int __ftrace_hash_update_ipmodify(struct ftrace_ops *ops,
 				 */
 				if (!ops->ops_func)
 					return -EBUSY;
-				ret = ops->ops_func(ops, FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_SELF);
+				ret = ops->ops_func(ops, rec->ip, FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_SELF);
 				if (ret)
 					return ret;
 			} else if (is_ipmodify) {
@@ -8983,7 +8983,7 @@ static int prepare_direct_functions_for_ipmodify(struct ftrace_ops *ops)
 				if (!op->ops_func)
 					return -EBUSY;
 
-				ret = op->ops_func(op, FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_PEER);
+				ret = op->ops_func(op, ip, FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_PEER);
 				if (ret)
 					return ret;
 			}
@@ -9030,7 +9030,7 @@ static void cleanup_direct_functions_after_ipmodify(struct ftrace_ops *ops)
 
 			/* The cleanup is optional, ignore any errors */
 			if (found_op && op->ops_func)
-				op->ops_func(op, FTRACE_OPS_CMD_DISABLE_SHARE_IPMODIFY_PEER);
+				op->ops_func(op, ip, FTRACE_OPS_CMD_DISABLE_SHARE_IPMODIFY_PEER);
 		}
 	}
 	mutex_unlock(&direct_mutex);
-- 
2.52.0



From jolsa at kernel.org  Mon Dec 15 13:13:59 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Mon, 15 Dec 2025 22:13:59 +0100
Subject: [PATCHv5 bpf-next 6/9] ftrace: Add update_ftrace_direct_mod function
In-Reply-To: <20251215211402.353056-1-jolsa@kernel.org>
References: <20251215211402.353056-1-jolsa@kernel.org>
Message-ID: <20251215211402.353056-7-jolsa@kernel.org>

Adding update_ftrace_direct_mod function that modifies all entries
(ip -> direct) provided in hash argument to direct ftrace ops and
updates its attachments.

The difference to current modify_ftrace_direct is:
- hash argument that allows to modify multiple ip -> direct
  entries at once

This change will allow us to have simple ftrace_ops for all bpf
direct interface users in following changes.

Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 include/linux/ftrace.h |  6 ++++
 kernel/trace/ftrace.c  | 72 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 78 insertions(+)

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index ac4b473c7fd3..c3bf9cede1fe 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -545,6 +545,7 @@ int modify_ftrace_direct_nolock(struct ftrace_ops *ops, unsigned long addr);
 
 int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash);
 int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash);
+int update_ftrace_direct_mod(struct ftrace_ops *ops, struct ftrace_hash *hash, bool do_direct_lock);
 
 void ftrace_stub_direct_tramp(void);
 
@@ -582,6 +583,11 @@ static inline int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace
 	return -ENODEV;
 }
 
+static inline int update_ftrace_direct_mod(struct ftrace_ops *ops, struct ftrace_hash *hash, bool do_direct_lock)
+{
+	return -ENODEV;
+}
+
 /*
  * This must be implemented by the architecture.
  * It is the way the ftrace direct_ops helper, when called
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 48dc0de5f2ce..95a38fb18ed7 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -6489,6 +6489,78 @@ int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash)
 	return err;
 }
 
+int update_ftrace_direct_mod(struct ftrace_ops *ops, struct ftrace_hash *hash, bool do_direct_lock)
+{
+	struct ftrace_func_entry *entry, *tmp;
+	static struct ftrace_ops tmp_ops = {
+		.func		= ftrace_stub,
+		.flags		= FTRACE_OPS_FL_STUB,
+	};
+	struct ftrace_hash *orig_hash;
+	unsigned long size, i;
+	int err = -EINVAL;
+
+	if (!hash_count(hash))
+		return -EINVAL;
+	if (check_direct_multi(ops))
+		return -EINVAL;
+	if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
+		return -EINVAL;
+	if (direct_functions == EMPTY_HASH)
+		return -EINVAL;
+
+	if (do_direct_lock)
+		mutex_lock(&direct_mutex);
+
+	orig_hash = ops->func_hash ? ops->func_hash->filter_hash : NULL;
+	if (!orig_hash)
+		goto unlock;
+
+	/* Enable the tmp_ops to have the same functions as the direct ops */
+	ftrace_ops_init(&tmp_ops);
+	tmp_ops.func_hash = ops->func_hash;
+
+	err = register_ftrace_function_nolock(&tmp_ops);
+	if (err)
+		goto unlock;
+
+	/*
+	 * Call __ftrace_hash_update_ipmodify() here, so that we can call
+	 * ops->ops_func for the ops. This is needed because the above
+	 * register_ftrace_function_nolock() worked on tmp_ops.
+	 */
+	err = __ftrace_hash_update_ipmodify(ops, orig_hash, orig_hash, true);
+	if (err)
+		goto out;
+
+	/*
+	 * Now the ftrace_ops_list_func() is called to do the direct callers.
+	 * We can safely change the direct functions attached to each entry.
+	 */
+	mutex_lock(&ftrace_lock);
+
+	size = 1 << hash->size_bits;
+	for (i = 0; i < size; i++) {
+		hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
+			tmp = __ftrace_lookup_ip(direct_functions, entry->ip);
+			if (!tmp)
+				continue;
+			tmp->direct = entry->direct;
+		}
+	}
+
+	mutex_unlock(&ftrace_lock);
+
+out:
+	/* Removing the tmp_ops will add the updated direct callers to the functions */
+	unregister_ftrace_function(&tmp_ops);
+
+unlock:
+	if (do_direct_lock)
+		mutex_unlock(&direct_mutex);
+	return err;
+}
+
 #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
 
 /**
-- 
2.52.0



From jolsa at kernel.org  Mon Dec 15 13:14:02 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Mon, 15 Dec 2025 22:14:02 +0100
Subject: [PATCHv5 bpf-next 9/9] bpf,x86: Use single ftrace_ops for direct calls
In-Reply-To: <20251215211402.353056-1-jolsa@kernel.org>
References: <20251215211402.353056-1-jolsa@kernel.org>
Message-ID: <20251215211402.353056-10-jolsa@kernel.org>

Using single ftrace_ops for direct calls update instead of allocating
ftrace_ops object for each trampoline.

With single ftrace_ops object we can use update_ftrace_direct_* api
that allows multiple ip sites updates on single ftrace_ops object.

Adding HAVE_SINGLE_FTRACE_DIRECT_OPS config option to be enabled on
each arch that supports this.

At the moment we can enable this only on x86 arch, because arm relies
on ftrace_ops object representing just single trampoline image (stored
in ftrace_ops::direct_call). Ach that do not support this will continue
to use *_ftrace_direct api.

Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 arch/x86/Kconfig        |   1 +
 kernel/bpf/trampoline.c | 195 ++++++++++++++++++++++++++++++++++------
 kernel/trace/Kconfig    |   3 +
 kernel/trace/ftrace.c   |   7 +-
 4 files changed, 177 insertions(+), 29 deletions(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 17a107cc5244..d0c36e49e66e 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -335,6 +335,7 @@ config X86
 	select SCHED_SMT			if SMP
 	select ARCH_SUPPORTS_SCHED_CLUSTER	if SMP
 	select ARCH_SUPPORTS_SCHED_MC		if SMP
+	select HAVE_SINGLE_FTRACE_DIRECT_OPS	if X86_64 && DYNAMIC_FTRACE_WITH_DIRECT_CALLS
 
 config INSTRUCTION_DECODER
 	def_bool y
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index 17af2aad8382..02371db3db3e 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -33,12 +33,40 @@ static DEFINE_MUTEX(trampoline_mutex);
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
 static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mutex);
 
+#ifdef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS
+static struct bpf_trampoline *direct_ops_ip_lookup(struct ftrace_ops *ops, unsigned long ip)
+{
+	struct hlist_head *head_ip;
+	struct bpf_trampoline *tr;
+
+	mutex_lock(&trampoline_mutex);
+	head_ip = &trampoline_ip_table[hash_64(ip, TRAMPOLINE_HASH_BITS)];
+	hlist_for_each_entry(tr, head_ip, hlist_ip) {
+		if (tr->ip == ip)
+			goto out;
+	}
+	tr = NULL;
+out:
+	mutex_unlock(&trampoline_mutex);
+	return tr;
+}
+#else
+static struct bpf_trampoline *direct_ops_ip_lookup(struct ftrace_ops *ops, unsigned long ip)
+{
+	return ops->private;
+}
+#endif /* CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS */
+
 static int bpf_tramp_ftrace_ops_func(struct ftrace_ops *ops, unsigned long ip,
 				     enum ftrace_ops_cmd cmd)
 {
-	struct bpf_trampoline *tr = ops->private;
+	struct bpf_trampoline *tr;
 	int ret = 0;
 
+	tr = direct_ops_ip_lookup(ops, ip);
+	if (!tr)
+		return -EINVAL;
+
 	if (cmd == FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_SELF) {
 		/* This is called inside register_ftrace_direct_multi(), so
 		 * tr->mutex is already locked.
@@ -137,6 +165,139 @@ void bpf_image_ksym_del(struct bpf_ksym *ksym)
 			   PAGE_SIZE, true, ksym->name);
 }
 
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
+#ifdef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS
+/*
+ * We have only single direct_ops which contains all the direct call
+ * sites and is the only global ftrace_ops for all trampolines.
+ *
+ * We use 'update_ftrace_direct_*' api for attachment.
+ */
+struct ftrace_ops direct_ops = {
+	.ops_func = bpf_tramp_ftrace_ops_func,
+};
+
+static int direct_ops_alloc(struct bpf_trampoline *tr)
+{
+	tr->fops = &direct_ops;
+	return 0;
+}
+
+static void direct_ops_free(struct bpf_trampoline *tr) { }
+
+static struct ftrace_hash *hash_from_ip(struct bpf_trampoline *tr, void *ptr)
+{
+	unsigned long ip, addr = (unsigned long) ptr;
+	struct ftrace_hash *hash;
+
+	ip = ftrace_location(tr->ip);
+	if (!ip)
+		return NULL;
+	hash = alloc_ftrace_hash(FTRACE_HASH_DEFAULT_BITS);
+	if (!hash)
+		return NULL;
+	if (bpf_trampoline_use_jmp(tr->flags))
+		addr = ftrace_jmp_set(addr);
+	if (!add_hash_entry_direct(hash, ip, addr)) {
+		free_ftrace_hash(hash);
+		return NULL;
+	}
+	return hash;
+}
+
+static int direct_ops_add(struct bpf_trampoline *tr, void *addr)
+{
+	struct ftrace_hash *hash = hash_from_ip(tr, addr);
+	int err = -ENOMEM;
+
+	if (hash)
+		err = update_ftrace_direct_add(tr->fops, hash);
+	free_ftrace_hash(hash);
+	return err;
+}
+
+static int direct_ops_del(struct bpf_trampoline *tr, void *addr)
+{
+	struct ftrace_hash *hash = hash_from_ip(tr, addr);
+	int err = -ENOMEM;
+
+	if (hash)
+		err = update_ftrace_direct_del(tr->fops, hash);
+	free_ftrace_hash(hash);
+	return err;
+}
+
+static int direct_ops_mod(struct bpf_trampoline *tr, void *addr, bool lock_direct_mutex)
+{
+	struct ftrace_hash *hash = hash_from_ip(tr, addr);
+	int err = -ENOMEM;
+
+	if (hash)
+		err = update_ftrace_direct_mod(tr->fops, hash, lock_direct_mutex);
+	free_ftrace_hash(hash);
+	return err;
+}
+#else
+/*
+ * We allocate ftrace_ops object for each trampoline and it contains
+ * call site specific for that trampoline.
+ *
+ * We use *_ftrace_direct api for attachment.
+ */
+static int direct_ops_alloc(struct bpf_trampoline *tr)
+{
+	tr->fops = kzalloc(sizeof(struct ftrace_ops), GFP_KERNEL);
+	if (!tr->fops)
+		return -ENOMEM;
+	tr->fops->private = tr;
+	tr->fops->ops_func = bpf_tramp_ftrace_ops_func;
+	return 0;
+}
+
+static void direct_ops_free(struct bpf_trampoline *tr)
+{
+	if (tr->fops) {
+		ftrace_free_filter(tr->fops);
+		kfree(tr->fops);
+	}
+}
+
+static int direct_ops_add(struct bpf_trampoline *tr, void *ptr)
+{
+	unsigned long addr = (unsigned long) ptr;
+	struct ftrace_ops *ops = tr->fops;
+	int ret;
+
+	if (bpf_trampoline_use_jmp(tr->flags))
+		addr = ftrace_jmp_set(addr);
+
+	ret = ftrace_set_filter_ip(ops, tr->ip, 0, 1);
+	if (ret)
+		return ret;
+	return register_ftrace_direct(ops, addr);
+}
+
+static int direct_ops_del(struct bpf_trampoline *tr, void *addr)
+{
+	return unregister_ftrace_direct(tr->fops, (long)addr, false);
+}
+
+static int direct_ops_mod(struct bpf_trampoline *tr, void *ptr, bool lock_direct_mutex)
+{
+	unsigned long addr = (unsigned long) ptr;
+	struct ftrace_ops *ops = tr->fops;
+
+	if (bpf_trampoline_use_jmp(tr->flags))
+		addr = ftrace_jmp_set(addr);
+	if (lock_direct_mutex)
+		return modify_ftrace_direct(ops, addr);
+	return modify_ftrace_direct_nolock(ops, addr);
+}
+#endif /* CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS */
+#else
+static void direct_ops_free(struct bpf_trampoline *tr) { }
+#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
+
 static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
 {
 	struct bpf_trampoline *tr;
@@ -155,14 +316,11 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
 	if (!tr)
 		goto out;
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
-	tr->fops = kzalloc(sizeof(struct ftrace_ops), GFP_KERNEL);
-	if (!tr->fops) {
+	if (direct_ops_alloc(tr)) {
 		kfree(tr);
 		tr = NULL;
 		goto out;
 	}
-	tr->fops->private = tr;
-	tr->fops->ops_func = bpf_tramp_ftrace_ops_func;
 #endif
 
 	tr->key = key;
@@ -206,7 +364,7 @@ static int unregister_fentry(struct bpf_trampoline *tr, u32 orig_flags,
 	int ret;
 
 	if (tr->func.ftrace_managed)
-		ret = unregister_ftrace_direct(tr->fops, (long)old_addr, false);
+		ret = direct_ops_del(tr, old_addr);
 	else
 		ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr, NULL);
 
@@ -220,15 +378,7 @@ static int modify_fentry(struct bpf_trampoline *tr, u32 orig_flags,
 	int ret;
 
 	if (tr->func.ftrace_managed) {
-		unsigned long addr = (unsigned long) new_addr;
-
-		if (bpf_trampoline_use_jmp(tr->flags))
-			addr = ftrace_jmp_set(addr);
-
-		if (lock_direct_mutex)
-			ret = modify_ftrace_direct(tr->fops, addr);
-		else
-			ret = modify_ftrace_direct_nolock(tr->fops, addr);
+		ret = direct_ops_mod(tr, new_addr, lock_direct_mutex);
 	} else {
 		ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr,
 						   new_addr);
@@ -251,15 +401,7 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
 	}
 
 	if (tr->func.ftrace_managed) {
-		unsigned long addr = (unsigned long) new_addr;
-
-		if (bpf_trampoline_use_jmp(tr->flags))
-			addr = ftrace_jmp_set(addr);
-
-		ret = ftrace_set_filter_ip(tr->fops, (unsigned long)ip, 0, 1);
-		if (ret)
-			return ret;
-		ret = register_ftrace_direct(tr->fops, addr);
+		ret = direct_ops_add(tr, new_addr);
 	} else {
 		ret = bpf_trampoline_update_fentry(tr, 0, NULL, new_addr);
 	}
@@ -910,10 +1052,7 @@ void bpf_trampoline_put(struct bpf_trampoline *tr)
 	 */
 	hlist_del(&tr->hlist_key);
 	hlist_del(&tr->hlist_ip);
-	if (tr->fops) {
-		ftrace_free_filter(tr->fops);
-		kfree(tr->fops);
-	}
+	direct_ops_free(tr);
 	kfree(tr);
 out:
 	mutex_unlock(&trampoline_mutex);
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index 4661b9e606e0..1ad2e307c834 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -50,6 +50,9 @@ config HAVE_DYNAMIC_FTRACE_WITH_REGS
 config HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
 	bool
 
+config HAVE_SINGLE_FTRACE_DIRECT_OPS
+	bool
+
 config HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS
 	bool
 
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index c2054fe80de7..a0789727b971 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -2605,8 +2605,13 @@ unsigned long ftrace_find_rec_direct(unsigned long ip)
 static void call_direct_funcs(unsigned long ip, unsigned long pip,
 			      struct ftrace_ops *ops, struct ftrace_regs *fregs)
 {
-	unsigned long addr = READ_ONCE(ops->direct_call);
+	unsigned long addr;
 
+#ifdef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS
+	addr = ftrace_find_rec_direct(ip);
+#else
+	addr = READ_ONCE(ops->direct_call);
+#endif
 	if (!addr)
 		return;
 
-- 
2.52.0



From nicolinc at nvidia.com  Mon Dec 15 13:19:28 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Mon, 15 Dec 2025 13:19:28 -0800
Subject: [PATCH V7 3/4] dt-bindings: iommu: Add NVIDIA Tegra CMDQV support
In-Reply-To: <20251215064819.3345361-4-amhetre@nvidia.com>
References: <20251215064819.3345361-1-amhetre@nvidia.com>
 <20251215064819.3345361-4-amhetre@nvidia.com>
Message-ID: <aUB7YNiCarEY7Ig7@Asurada-Nvidia>

On Mon, Dec 15, 2025 at 06:48:18AM +0000, Ashish Mhetre wrote:
> The Command Queue Virtualization (CMDQV) hardware is part of the
> SMMUv3 implementation on NVIDIA Tegra SoCs. It assists in
> virtualizing the command queue for the SMMU.
> 
> Add a new device tree binding document for nvidia,tegra264-cmdqv.
> 
> Also update the arm,smmu-v3 binding to include an optional nvidia,cmdqv
> property. This property is a phandle to the CMDQV device node, allowing
> the SMMU driver to associate with its corresponding CMDQV instance.
> Restrict this property usage to Nvidia Tegra264 only.
> 
> Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
> Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>

Acked-by: Nicolin Chen <nicolinc at nvidia.com>


From nicolinc at nvidia.com  Mon Dec 15 13:21:19 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Mon, 15 Dec 2025 13:21:19 -0800
Subject: [PATCH V7 4/4] arm64: dts: nvidia: Add nodes for CMDQV
In-Reply-To: <20251215064819.3345361-5-amhetre@nvidia.com>
References: <20251215064819.3345361-1-amhetre@nvidia.com>
 <20251215064819.3345361-5-amhetre@nvidia.com>
Message-ID: <aUB7zz8wMJoPSVf7@Asurada-Nvidia>

On Mon, Dec 15, 2025 at 06:48:19AM +0000, Ashish Mhetre wrote:
> The Command Queue Virtualization (CMDQV) hardware is part of the
> SMMUv3 implementation on NVIDIA Tegra SoCs. It assists in
> virtualizing the command queue for the SMMU.
> 
> Update SMMU compatible strings to use nvidia,tegra264-smmu to enable
> CMDQV support. Add device tree nodes for the CMDQV hardware and enable
> them on the tegra264-p3834 platform where SMMUs are enabled. Each SMMU
> instance is paired with its corresponding CMDQV instance via the
> nvidia,cmdqv property.
> 
> Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>

Acked-by: Nicolin Chen <nicolinc at nvidia.com>


From robh at kernel.org  Mon Dec 15 13:24:56 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Mon, 15 Dec 2025 15:24:56 -0600
Subject: [PATCH] dt-bindings: PCI: socionext,uniphier-pcie: Fix interrupt controller node name
Message-ID: <20251215212456.3317558-1-robh@kernel.org>

The child node name in use by .dts files and the driver is
"legacy-interrupt-controller", not "interrupt-controller".

Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
---
 .../devicetree/bindings/pci/socionext,uniphier-pcie.yaml      | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/pci/socionext,uniphier-pcie.yaml b/Documentation/devicetree/bindings/pci/socionext,uniphier-pcie.yaml
index c07b0ed51613..8a2f1eef51bd 100644
--- a/Documentation/devicetree/bindings/pci/socionext,uniphier-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/socionext,uniphier-pcie.yaml
@@ -51,7 +51,7 @@ properties:
   phy-names:
     const: pcie-phy
 
-  interrupt-controller:
+  legacy-interrupt-controller:
     type: object
     additionalProperties: false
 
@@ -111,7 +111,7 @@ examples:
                         <0 0 0  3  &pcie_intc 2>,
                         <0 0 0  4  &pcie_intc 3>;
 
-        pcie_intc: interrupt-controller {
+        pcie_intc: legacy-interrupt-controller {
             #address-cells = <0>;
             interrupt-controller;
             #interrupt-cells = <1>;
-- 
2.51.0



From lkp at intel.com  Mon Dec 15 13:23:42 2025
From: lkp at intel.com (kernel test robot)
Date: Tue, 16 Dec 2025 05:23:42 +0800
Subject: [PATCH v8 12/12] cpuidle/poll_state: Wait for need-resched via
 tif_need_resched_relaxed_wait()
In-Reply-To: <20251215044919.460086-13-ankur.a.arora@oracle.com>
References: <20251215044919.460086-13-ankur.a.arora@oracle.com>
Message-ID: <202512160519.pKMkOXsP-lkp@intel.com>

Hi Ankur,

kernel test robot noticed the following build warnings:

[auto build test WARNING on bpf-next/master]
[also build test WARNING on bpf/master linus/master v6.19-rc1 next-20251215]
[cannot apply to arm64/for-next/core bpf-next/net arnd-asm-generic/master]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Ankur-Arora/asm-generic-barrier-Add-smp_cond_load_relaxed_timeout/20251215-130116
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master
patch link:    https://lore.kernel.org/r/20251215044919.460086-13-ankur.a.arora%40oracle.com
patch subject: [PATCH v8 12/12] cpuidle/poll_state: Wait for need-resched via tif_need_resched_relaxed_wait()
config: x86_64-randconfig-005-20251215 (https://download.01.org/0day-ci/archive/20251216/202512160519.pKMkOXsP-lkp at intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251216/202512160519.pKMkOXsP-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512160519.pKMkOXsP-lkp at intel.com/

All warnings (new ones prefixed by >>):

>> vmlinux.o: warning: objtool: poll_idle+0x3b: call to tif_need_resched_relaxed_wait() leaves .noinstr.text section

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From robh at kernel.org  Mon Dec 15 13:25:06 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Mon, 15 Dec 2025 15:25:06 -0600
Subject: [PATCH] dt-bindings: usb: Add Socionext Uniphier DWC3 controller
Message-ID: <20251215212507.3317805-1-robh@kernel.org>

The Socionext Uniphier DWC3 controller binding is already in use, but
undocumented. It's a straight-forward binding similar to other DWC3
bindings.

Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
---
 .../bindings/usb/socionext,uniphier-dwc3.yaml | 89 +++++++++++++++++++
 1 file changed, 89 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/usb/socionext,uniphier-dwc3.yaml

diff --git a/Documentation/devicetree/bindings/usb/socionext,uniphier-dwc3.yaml b/Documentation/devicetree/bindings/usb/socionext,uniphier-dwc3.yaml
new file mode 100644
index 000000000000..892ae3458c1b
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/socionext,uniphier-dwc3.yaml
@@ -0,0 +1,89 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/socionext,uniphier-dwc3.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Socionext Uniphier SuperSpeed DWC3 USB SoC controller
+
+maintainers:
+  - Kunihiko Hayashi <hayashi.kunihiko at socionext.com>
+  - Masami Hiramatsu <mhiramat at kernel.org>
+
+select:
+  properties:
+    compatible:
+      contains:
+        const: socionext,uniphier-dwc3
+  required:
+    - compatible
+
+properties:
+  compatible:
+    items:
+      - const: socionext,uniphier-dwc3
+      - const: snps,dwc3
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    minItems: 1
+    items:
+      - description: Host or single combined interrupt
+      - description: Peripheral interrupt
+
+  interrupt-names:
+    minItems: 1
+    items:
+      - enum:
+          - dwc_usb3
+          - host
+      - const: peripheral
+
+  clocks:
+    maxItems: 3
+
+  clock-names:
+    items:
+      - const: ref
+      - const: bus_early
+      - const: suspend
+
+  phys:
+    description: 1 to 4 HighSpeed PHYs followed by 1 or 2 SuperSpeed PHYs
+    minItems: 2
+    maxItems: 6
+
+  resets:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - phys
+
+unevaluatedProperties: false
+
+allOf:
+  - $ref: snps,dwc3.yaml#
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    usb at 65a00000 {
+        compatible = "socionext,uniphier-dwc3", "snps,dwc3";
+        reg = <0x65a00000 0xcd00>;
+        interrupt-names = "dwc_usb3";
+        interrupts = <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>;
+        clock-names = "ref", "bus_early", "suspend";
+        clocks = <&sys_clk 12>, <&sys_clk 12>, <&sys_clk 12>;
+        resets = <&usb0_rst 15>;
+        phys = <&usb0_hsphy0>, <&usb0_hsphy1>,
+               <&usb0_ssphy0>, <&usb0_ssphy1>;
+        dr_mode = "host";
+    };
-- 
2.51.0



From robh at kernel.org  Mon Dec 15 13:25:54 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Mon, 15 Dec 2025 15:25:54 -0600
Subject: [PATCH] dt-bindings: raspberrypi,bcm2835-firmware: Add 'power' and gpio-hog nodes
Message-ID: <20251215212554.3319105-1-robh@kernel.org>

Add missing child nodes for the RaspberryPi firmware. The firmware
implements a power domain provider in a 'power' node. GPIO hog nodes are
also supported, but the node name pattern was wrong and failed to match
them.

Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
---
 .../bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml       | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml
index 266ed6e61cee..983ea80eaec9 100644
--- a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml
+++ b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml
@@ -66,7 +66,7 @@ properties:
         minItems: 8
 
     patternProperties:
-      '^-hog$':
+      '-hog$':
         required:
           - gpio-hog
 
@@ -92,6 +92,9 @@ properties:
       - compatible
       - "#reset-cells"
 
+  power:
+    $ref: /schemas/power/raspberrypi,bcm2835-power.yaml#
+
   pwm:
     type: object
     additionalProperties: false
-- 
2.51.0



From robh at kernel.org  Mon Dec 15 13:26:59 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Mon, 15 Dec 2025 15:26:59 -0600
Subject: [PATCH] dt-bindings: bus: stm32mp25-rifsc: Allow 2 size cells
Message-ID: <20251215212700.3320634-1-robh@kernel.org>

There are users already with 2 size cells, and there's no reason to not
support that.

Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
---
 Documentation/devicetree/bindings/bus/st,stm32mp25-rifsc.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/bus/st,stm32mp25-rifsc.yaml b/Documentation/devicetree/bindings/bus/st,stm32mp25-rifsc.yaml
index 4d19917ad2c3..c6280c8c54a3 100644
--- a/Documentation/devicetree/bindings/bus/st,stm32mp25-rifsc.yaml
+++ b/Documentation/devicetree/bindings/bus/st,stm32mp25-rifsc.yaml
@@ -54,7 +54,7 @@ properties:
     const: 1
 
   "#size-cells":
-    const: 1
+    enum: [ 1, 2 ]
 
   ranges: true
 
-- 
2.51.0



From robh at kernel.org  Mon Dec 15 13:27:36 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Mon, 15 Dec 2025 15:27:36 -0600
Subject: [PATCH] dt-bindings: mmc: brcm,iproc-sdhci: Allow "dma-coherent" and "iommus" properties
Message-ID: <20251215212736.3321550-1-robh@kernel.org>

The Broadcom iProc SDHCI controller is DMA coherent and/or behind an IOMMU
on some Broadcom SoCs, so allow the dma-coherent and iommus properties.

Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
---
 Documentation/devicetree/bindings/mmc/brcm,iproc-sdhci.yaml | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Documentation/devicetree/bindings/mmc/brcm,iproc-sdhci.yaml b/Documentation/devicetree/bindings/mmc/brcm,iproc-sdhci.yaml
index 2f63f2cdeb71..65bb2f66f8cf 100644
--- a/Documentation/devicetree/bindings/mmc/brcm,iproc-sdhci.yaml
+++ b/Documentation/devicetree/bindings/mmc/brcm,iproc-sdhci.yaml
@@ -26,9 +26,14 @@ properties:
   reg:
     minItems: 1
 
+  dma-coherent: true
+
   interrupts:
     maxItems: 1
 
+  iommus:
+    maxItems: 1
+
   clocks:
     maxItems: 1
     description:
-- 
2.51.0



From robh at kernel.org  Mon Dec 15 13:28:05 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Mon, 15 Dec 2025 15:28:05 -0600
Subject: [PATCH] dt-bindings: i2c: brcm,iproc-i2c: Allow 2 reg entries for brcm,iproc-nic-i2c
Message-ID: <20251215212805.3322218-1-robh@kernel.org>

The brcm,iproc-nic-i2c variant has 2 reg entries.

The second one is related to the brcm,ape-hsls-addr-mask property, but it's
not clear what a proper description would be.

Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
---
 .../devicetree/bindings/i2c/brcm,iproc-i2c.yaml        | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.yaml b/Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.yaml
index 2aa75b7add7b..daa70a8500e9 100644
--- a/Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.yaml
+++ b/Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.yaml
@@ -16,7 +16,8 @@ properties:
       - brcm,iproc-nic-i2c
 
   reg:
-    maxItems: 1
+    minItems: 1
+    maxItems: 2
 
   clock-frequency:
     enum: [ 100000, 400000 ]
@@ -41,8 +42,15 @@ allOf:
           contains:
             const: brcm,iproc-nic-i2c
     then:
+      properties:
+        reg:
+          minItems: 2
       required:
         - brcm,ape-hsls-addr-mask
+    else:
+      properties:
+        reg:
+          maxItems: 1
 
 unevaluatedProperties: false
 
-- 
2.51.0



From robh at kernel.org  Mon Dec 15 13:29:14 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Mon, 15 Dec 2025 15:29:14 -0600
Subject: [PATCH] dt-bindings: arm: vexpress-config: Update clock and regulator node names
Message-ID: <20251215212914.3323741-1-robh@kernel.org>

The clock and regulator node names were updated to use standard node names,
but the binding wasn't updated.

Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
---
 Documentation/devicetree/bindings/arm/vexpress-config.yaml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/vexpress-config.yaml b/Documentation/devicetree/bindings/arm/vexpress-config.yaml
index b74380da3198..41c53e3acc12 100644
--- a/Documentation/devicetree/bindings/arm/vexpress-config.yaml
+++ b/Documentation/devicetree/bindings/arm/vexpress-config.yaml
@@ -103,7 +103,7 @@ required:
   - arm,vexpress,config-bridge
 
 patternProperties:
-  'clk[0-9]*$':
+  '^clock-controller.*$':
     type: object
     description:
       clocks
@@ -137,7 +137,7 @@ patternProperties:
       - arm,vexpress-sysreg,func
       - "#clock-cells"
 
-  "^volt-.+$":
+  "^regulator-.+$":
     $ref: /schemas/regulator/regulator.yaml#
     properties:
       compatible:
@@ -272,7 +272,7 @@ examples:
         compatible = "arm,vexpress,config-bus";
         arm,vexpress,config-bridge = <&v2m_sysreg>;
 
-        clk0 {
+        clock-controller {
             compatible = "arm,vexpress-osc";
             arm,vexpress-sysreg,func = <1 0>;
             #clock-cells = <0>;
-- 
2.51.0



From robh at kernel.org  Mon Dec 15 13:29:32 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Mon, 15 Dec 2025 15:29:32 -0600
Subject: [PATCH] dt-bindings: arm,vexpress-juno: Allow interrupt-map properties in bus node
Message-ID: <20251215212932.3324144-1-robh@kernel.org>

Allow interrupt-map properties which are already used in the bus node.

Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
---
 .../devicetree/bindings/arm/arm,vexpress-juno.yaml          | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/arm,vexpress-juno.yaml b/Documentation/devicetree/bindings/arm/arm,vexpress-juno.yaml
index 4cdca5320544..eae558c2758b 100644
--- a/Documentation/devicetree/bindings/arm/arm,vexpress-juno.yaml
+++ b/Documentation/devicetree/bindings/arm/arm,vexpress-juno.yaml
@@ -157,6 +157,12 @@ patternProperties:
               - const: simple-bus
           - const: simple-bus
 
+      "#interrupt-cells":
+        const: 1
+
+      interrupt-map: true
+      interrupt-map-mask: true
+
     patternProperties:
       '^motherboard-bus@':
         type: object
-- 
2.51.0



From robh at kernel.org  Mon Dec 15 13:30:21 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Mon, 15 Dec 2025 15:30:21 -0600
Subject: [PATCH] dt-bindings: arm: Drop obsolete brcm,vulcan-soc binding
Message-ID: <20251215213022.3325133-1-robh@kernel.org>

The Cavium ThunderX2 aka Broadcom Vulcan doesn't use DT, but ACPI, so drop
the SoC binding.

Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
---
 .../bindings/arm/bcm/brcm,vulcan-soc.yaml     | 24 -------------------
 1 file changed, 24 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/arm/bcm/brcm,vulcan-soc.yaml

diff --git a/Documentation/devicetree/bindings/arm/bcm/brcm,vulcan-soc.yaml b/Documentation/devicetree/bindings/arm/bcm/brcm,vulcan-soc.yaml
deleted file mode 100644
index 3f441352fbf0..000000000000
--- a/Documentation/devicetree/bindings/arm/bcm/brcm,vulcan-soc.yaml
+++ /dev/null
@@ -1,24 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/arm/bcm/brcm,vulcan-soc.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Broadcom Vulcan
-
-maintainers:
-  - Robert Richter <rrichter at marvell.com>
-
-properties:
-  $nodename:
-    const: '/'
-  compatible:
-    items:
-      - enum:
-          - brcm,vulcan-eval
-          - cavium,thunderx2-cn9900
-      - const: brcm,vulcan-soc
-
-additionalProperties: true
-
-...
-- 
2.51.0



From bot+bpf-ci at kernel.org  Mon Dec 15 13:31:51 2025
From: bot+bpf-ci at kernel.org (bot+bpf-ci at kernel.org)
Date: Mon, 15 Dec 2025 21:31:51 +0000 (UTC)
Subject: [PATCHv5 bpf-next 1/9] ftrace,bpf: Remove FTRACE_OPS_FL_JMP ftrace_ops flag
In-Reply-To: <20251215211402.353056-2-jolsa@kernel.org>
References: <20251215211402.353056-2-jolsa@kernel.org>
Message-ID: <95c13c0b793604796037ca67c191e1bfce22770dd020107c7179a698c5d49b91@mail.kernel.org>

> diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
> index 015dd1049bea..505b7d3f5641 100644
> --- a/include/linux/ftrace.h
> +++ b/include/linux/ftrace.h

[ ... ]

> diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
> index 976d89011b15..b9a358d7a78f 100644
> --- a/kernel/bpf/trampoline.c
> +++ b/kernel/bpf/trampoline.c
> @@ -214,10 +214,15 @@ static int modify_fentry(struct bpf_trampoline *tr, u32 orig_flags,
>  	int ret;
>
>  	if (tr->func.ftrace_managed) {
> +		unsigned long addr = (unsigned long) new_addr;
> +
> +		if (bpf_trampoline_use_jmp(tr->flags))
> +			addr = ftrace_jmp_set(addr);
> +
>  		if (lock_direct_mutex)
> -			ret = modify_ftrace_direct(tr->fops, (long)new_addr);
> +			ret = modify_ftrace_direct(tr->fops, addr);
>  		else
> -			ret = modify_ftrace_direct_nolock(tr->fops, (long)new_addr);
> +			ret = modify_ftrace_direct_nolock(tr->fops, addr);
>  	} else {
>  		ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr,
>  						   new_addr);
> @@ -240,10 +245,15 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
>  	}
>
>  	if (tr->func.ftrace_managed) {
> +		unsigned long addr = (unsigned long) new_addr;
> +
> +		if (bpf_trampoline_use_jmp(tr->flags))
> +			addr = ftrace_jmp_set(addr);
> +
>  		ret = ftrace_set_filter_ip(tr->fops, (unsigned long)ip, 0, 1);
>  		if (ret)
>  			return ret;
> -		ret = register_ftrace_direct(tr->fops, (long)new_addr);
> +		ret = register_ftrace_direct(tr->fops, addr);
>  	} else {
>  		ret = bpf_trampoline_update_fentry(tr, 0, NULL, new_addr);
>  	}

After this change, register_ftrace_direct() receives an address with
the LSB bit already set (via ftrace_jmp_set) and stores it as-is in
entry->direct. This address then flows through to ftrace_find_rec_direct()
which returns entry->direct unchanged.

In available_filter_functions_show():

    direct = ftrace_find_rec_direct(rec->ip);
    if (direct)
        seq_printf(m, "\n\tdirect-->%pS", (void *)direct);

Can the debug output show misleading symbol offsets? When the LSB is
set, %pS will resolve addresses like "function+0x1" instead of just
"function". This makes ftrace debug output harder to read for users
trying to understand direct call attachments.

The fix would be to strip the LSB bit before printing:
    seq_printf(m, "\n\tdirect-->%pS", (void *)ftrace_jmp_get(direct));

[ ... ]

> diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
> index bbb37c0f8c6c..b0dc911411f1 100644
> --- a/kernel/trace/ftrace.c
> +++ b/kernel/trace/ftrace.c
> @@ -6017,15 +6017,8 @@ int register_ftrace_direct(struct ftrace_ops *ops, unsigned long addr)
>  	if (ftrace_hash_empty(hash))
>  		return -EINVAL;
>
> -	/* This is a "raw" address, and this should never happen. */
> -	if (WARN_ON_ONCE(ftrace_is_jmp(addr)))
> -		return -EINVAL;
> -
>  	mutex_lock(&direct_mutex);
>
> -	if (ops->flags & FTRACE_OPS_FL_JMP)
> -		addr = ftrace_jmp_set(addr);
> -
>  	/* Make sure requested entries are not already registered.. */
>  	size = 1 << hash->size_bits;
>  	for (i = 0; i < size; i++) {

[ ... ]

> @@ -6146,13 +6139,6 @@ __modify_ftrace_direct(struct ftrace_ops *ops, unsigned long addr)
>
>  	lockdep_assert_held_once(&direct_mutex);
>
> -	/* This is a "raw" address, and this should never happen. */
> -	if (WARN_ON_ONCE(ftrace_is_jmp(addr)))
> -		return -EINVAL;
> -
> -	if (ops->flags & FTRACE_OPS_FL_JMP)
> -		addr = ftrace_jmp_set(addr);
> -
>  	/* Enable the tmp_ops to have the same functions as the direct ops */
>  	ftrace_ops_init(&tmp_ops);
>  	tmp_ops.func_hash = ops->func_hash;

[ ... ]


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/20247816064

From suzuki.poulose at arm.com  Mon Dec 15 13:33:34 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Mon, 15 Dec 2025 21:33:34 +0000
Subject: [RFC PATCH v6 02/35] arm64/sysreg: Define MDCR_EL2.E2PB values
In-Reply-To: <20251114160717.163230-3-alexandru.elisei@arm.com>
References: <20251114160717.163230-1-alexandru.elisei@arm.com>
 <20251114160717.163230-3-alexandru.elisei@arm.com>
Message-ID: <be79ca29-0233-4397-b3b0-38686512bc83@arm.com>

On 14/11/2025 16:06, Alexandru Elisei wrote:
> KVM will make use of the different values for MDCR_EL2.E2PB, document them.
> 
> Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
> ---
>   arch/arm64/tools/sysreg | 7 ++++++-
>   1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
> index 1e7b69594f04..0de8af0e0778 100644
> --- a/arch/arm64/tools/sysreg
> +++ b/arch/arm64/tools/sysreg
> @@ -3851,7 +3851,12 @@ Field	17	HPMD
>   Res0	16
>   Field	15	EnSPM
>   Field	14	TPMS
> -Field	13:12	E2PB
> +UnsignedEnum	13:12 E2PB
> +	0b00	EL2
> +	0b01	RESERVED
> +	0b10	EL1_TRAP
> +	0b11	EL1
> +EndEnum
>   Field	11	TDRA
>   Field	10	TDOSA
>   Field	9	TDA

Reviewed-by: Suzuki K Poulose <suzuki.poulose at arm.com>



From robh at kernel.org  Mon Dec 15 13:35:14 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Mon, 15 Dec 2025 15:35:14 -0600
Subject: [PATCH v2] dt-bindings: raspberrypi,bcm2835-firmware: Add 'power' and gpio-hog nodes
Message-ID: <20251215213513.3331128-2-robh@kernel.org>

Add missing child nodes for the RaspberryPi firmware. The firmware
implements a power domain provider in a 'power' node. GPIO hog nodes are
also already in use.

Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
---
v2:
 - The error in the hog pattern was from my own bad addition, so fix the 
   patch to add gpio hog nodes.

 .../bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml    | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml
index 8349c0a854d9..983ea80eaec9 100644
--- a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml
+++ b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml
@@ -65,6 +65,11 @@ properties:
       gpio-line-names:
         minItems: 8
 
+    patternProperties:
+      '-hog$':
+        required:
+          - gpio-hog
+
     required:
       - compatible
       - gpio-controller
@@ -87,6 +92,9 @@ properties:
       - compatible
       - "#reset-cells"
 
+  power:
+    $ref: /schemas/power/raspberrypi,bcm2835-power.yaml#
+
   pwm:
     type: object
     additionalProperties: false
-- 
2.51.0



From florian.fainelli at broadcom.com  Mon Dec 15 13:37:37 2025
From: florian.fainelli at broadcom.com (Florian Fainelli)
Date: Mon, 15 Dec 2025 13:37:37 -0800
Subject: [PATCH] dt-bindings: mmc: brcm,iproc-sdhci: Allow "dma-coherent"
 and "iommus" properties
In-Reply-To: <20251215212736.3321550-1-robh@kernel.org>
References: <20251215212736.3321550-1-robh@kernel.org>
Message-ID: <30d6512d-9705-414f-b2ee-3e9283968348@broadcom.com>

On 12/15/25 13:27, 'Rob Herring (Arm)' via BCM-KERNEL-FEEDBACK-LIST,PDL 
wrote:
> The Broadcom iProc SDHCI controller is DMA coherent and/or behind an IOMMU
> on some Broadcom SoCs, so allow the dma-coherent and iommus properties.
> 
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>

Reviewed-by: Florian Fainelli <florian.fainelli at broadcom.com>
-- 
Florian


From florian.fainelli at broadcom.com  Mon Dec 15 13:37:57 2025
From: florian.fainelli at broadcom.com (Florian Fainelli)
Date: Mon, 15 Dec 2025 13:37:57 -0800
Subject: [PATCH] dt-bindings: i2c: brcm,iproc-i2c: Allow 2 reg entries for
 brcm,iproc-nic-i2c
In-Reply-To: <20251215212805.3322218-1-robh@kernel.org>
References: <20251215212805.3322218-1-robh@kernel.org>
Message-ID: <ddbf78c7-539c-42d9-b3dc-0d51ab52e2d2@broadcom.com>

On 12/15/25 13:28, 'Rob Herring (Arm)' via BCM-KERNEL-FEEDBACK-LIST,PDL 
wrote:
> The brcm,iproc-nic-i2c variant has 2 reg entries.
> 
> The second one is related to the brcm,ape-hsls-addr-mask property, but it's
> not clear what a proper description would be.
> 
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>

Reviewed-by: Florian Fainelli <florian.fainelli at broadcom.com>
-- 
Florian


From florian.fainelli at broadcom.com  Mon Dec 15 13:38:11 2025
From: florian.fainelli at broadcom.com (Florian Fainelli)
Date: Mon, 15 Dec 2025 13:38:11 -0800
Subject: [PATCH] dt-bindings: raspberrypi,bcm2835-firmware: Add 'power'
 and gpio-hog nodes
In-Reply-To: <20251215212554.3319105-1-robh@kernel.org>
References: <20251215212554.3319105-1-robh@kernel.org>
Message-ID: <f14247e3-3c9c-47b9-b912-6eb4a4d34412@broadcom.com>

On 12/15/25 13:25, Rob Herring (Arm) wrote:
> Add missing child nodes for the RaspberryPi firmware. The firmware
> implements a power domain provider in a 'power' node. GPIO hog nodes are
> also supported, but the node name pattern was wrong and failed to match
> them.
> 
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>

Reviewed-by: Florian Fainelli <florian.fainelli at broadcom.com>
-- 
Florian


From alexei.starovoitov at gmail.com  Mon Dec 15 13:40:06 2025
From: alexei.starovoitov at gmail.com (Alexei Starovoitov)
Date: Mon, 15 Dec 2025 13:40:06 -0800
Subject: [PATCH v8 10/12] bpf/rqspinlock: Use smp_cond_load_acquire_timeout()
In-Reply-To: <20251215044919.460086-11-ankur.a.arora@oracle.com>
References: <20251215044919.460086-1-ankur.a.arora@oracle.com> <20251215044919.460086-11-ankur.a.arora@oracle.com>
Message-ID: <CAADnVQKYoE85HFAOE5OBFpKbXej=h12m4DVvHuPViJSjAncK4A@mail.gmail.com>

On Sun, Dec 14, 2025 at 8:51?PM Ankur Arora <ankur.a.arora at oracle.com> wrote:
>
>  /**
>   * resilient_queued_spin_lock_slowpath - acquire the queued spinlock
>   * @lock: Pointer to queued spinlock structure
> @@ -415,7 +415,9 @@ int __lockfunc resilient_queued_spin_lock_slowpath(rqspinlock_t *lock, u32 val)
>          */
>         if (val & _Q_LOCKED_MASK) {
>                 RES_RESET_TIMEOUT(ts, RES_DEF_TIMEOUT);
> -               res_smp_cond_load_acquire(&lock->locked, !VAL || RES_CHECK_TIMEOUT(ts, timeout_err, _Q_LOCKED_MASK) < 0);
> +               smp_cond_load_acquire_timeout(&lock->locked, !VAL,
> +                                             (timeout_err = clock_deadlock(lock, _Q_LOCKED_MASK, &ts)),
> +                                             ts.duration);

I'm pretty sure we already discussed this and pointed out that
this approach is not acceptable.
We cannot call ktime_get_mono_fast_ns() first.
That's why RES_CHECK_TIMEOUT() exists and it does
if (!(ts).spin++)
before doing the first check_timeout() that will do ktime_get_mono_fast_ns().
Above is a performance critical lock acquisition path where
pending is spinning on the lock word waiting for the owner to
release the lock.
Adding unconditional ktime_get_mono_fast_ns() will destroy
performance for quick critical section.


From suzuki.poulose at arm.com  Mon Dec 15 13:42:33 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Mon, 15 Dec 2025 21:42:33 +0000
Subject: [RFC PATCH v6 01/35] arm64/sysreg: Add new SPE fields
In-Reply-To: <20251114160717.163230-2-alexandru.elisei@arm.com>
References: <20251114160717.163230-1-alexandru.elisei@arm.com>
 <20251114160717.163230-2-alexandru.elisei@arm.com>
Message-ID: <f080bfaf-9946-42ee-98c4-b31badc65621@arm.com>

On 14/11/2025 16:06, Alexandru Elisei wrote:
> Add the PMBSR_EL1.MSS2, PMBISR_EL1.MaxBuffSize, PMBLIMITR_EL1.nVM and

minor nit:                ^PMBIDR_EL1

> PMBIDR_EL1.AddrMode fields, which will be used by KVM.
> 

The defintions look correct to me.

Suzuki


> Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
> ---
>   arch/arm64/tools/sysreg | 18 ++++++++++++++----
>   1 file changed, 14 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
> index 1c6cdf9d54bb..1e7b69594f04 100644
> --- a/arch/arm64/tools/sysreg
> +++ b/arch/arm64/tools/sysreg
> @@ -3070,7 +3070,9 @@ EndSysreg
>   
>   Sysreg	PMBLIMITR_EL1	3	0	9	10	0
>   Field	63:12	LIMIT
> -Res0	11:6
> +Res0	11:8
> +Field	7	nVM
> +Res0	6
>   Field	5	PMFZ
>   Res0	4:3
>   Enum	2:1	FM
> @@ -3085,7 +3087,8 @@ Field	63:0	PTR
>   EndSysreg
>   
>   Sysreg	PMBSR_EL1	3	0	9	10	3
> -Res0	63:32
> +Res0	63:56
> +Field	55:32	MSS2
>   Enum	31:26	EC
>   	0b000000	BUF
>   	0b100100	FAULT_S1
> @@ -3112,13 +3115,20 @@ Field	7:0	Attr
>   EndSysreg
>   
>   Sysreg	PMBIDR_EL1	3	0	9	10	7
> -Res0	63:12
> +Res0	63:48
> +Field	47:32	MaxBuffSize
> +Res0	31:12
>   Enum	11:8	EA
>   	0b0000	NotDescribed
>   	0b0001	Ignored
>   	0b0010	SError
>   EndEnum
> -Res0	7:6
> +Enum	7:6	AddrMode
> +	0b00	VM_ONLY
> +	0b01	BOTH
> +	0b10	RESERVED
> +	0b11	nVM_ONLY
> +EndEnum
>   Field	5	F
>   Field	4	P
>   Field	3:0	ALIGN



From nicolinc at nvidia.com  Mon Dec 15 13:42:15 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Mon, 15 Dec 2025 13:42:15 -0800
Subject: [PATCH v8 0/5] Disable ATS via iommu during PCI resets
Message-ID: <cover.1765834788.git.nicolinc@nvidia.com>

Hi all,

PCIe permits a device to ignore ATS invalidation TLPs while processing a
reset. This creates a problem visible to the OS where an ATS invalidation
command will time out: e.g. an SVA domain will have no coordination with a
reset event and can racily issue ATS invalidations to a resetting device.

The OS should do something to mitigate this as we do not want production
systems to be reporting critical ATS failures, especially in a hypervisor
environment. Broadly, OS could arrange to ignore the timeouts, block page
table mutations to prevent invalidations, or disable and block ATS.

The PCIe spec in sec 10.3.1 IMPLEMENTATION NOTE recommends to disable and
block ATS before initiating a Function Level Reset. It also mentions that
other reset methods could have the same vulnerability as well.

Provide a callback from the PCI subsystem that will enclose the reset and
have the iommu core temporarily change domains to group->blocking_domain,
so IOMMU drivers would fence any incoming ATS queries, synchronously stop
issuing new ATS invalidations, and wait for existing ATS invalidations to
complete. Doing this can avoid any ATS invaliation timeouts.

When a device is resetting, any new domain attachment has to be rejected,
until the reset is finished, to prevent ATS activity from being activated
between the two callback functions. Introduce a new resetting_domain, and
reject a concurrent __iommu_attach_device/set_group_pasid().

Finally, call these pci_dev_reset_iommu/done() functions in the PCI reset
functions.

This is on Github:
https://github.com/nicolinc/iommufd/commits/iommu_dev_reset-v8

Changelog
v8
 * Rebase on v6.19-rc1
 * Add Tested-by from Dheeraj
 * Add Reviewed-by from Jason
 * [pci] Add Acked-by from Bjorn Helgaas
v7
 https://lore.kernel.org/all/cover.1763775108.git.nicolinc at nvidia.com/
 * Rebase on Joerg's next tree
 * Add Reviewed-by from Kevin
 * [iommu] Fix inline functions when !CONFIG_IOMMU_API
v6
 https://lore.kernel.org/all/cover.1763512374.git.nicolinc at nvidia.com/
 * Add Reviewed-by from Baolu and Kevin
 * Revise inline comments, kdocs, commit messages, uAPI
 * [iommu] s/iommu_dev_reset/pci_dev_reset_iommu/g for PCI exclusively
 * [iommu] Disallow iommu group sibling devices to attach concurrently
 * [pci] Drop unnecessary initializations to "ret" and "rc"
 * [pci] Improve pci_err message unpon a prepare() failure
 * [pci] Move pci_ats_supported() check inside the IOMMU callbacks
 * [pci] Apply callbacks to pci_reset_bus_function() that was missed
v5
 https://lore.kernel.org/all/cover.1762835355.git.nicolinc at nvidia.com/
 * Rebase on Joerg's next tree
 * [iommu] Skip in shared iommu_group cases
 * [iommu] Pass in default_domain to iommu_setup_dma_ops
 * [iommu] Add kdocs to iommu_get_domain_for_dev_locked()
 * [iommu] s/get_domain_for_dev_locked/driver_get_domain_for_dev
 * [iommu] Replace per-gdev pending_reset with per-group resetting_domain
v4
 https://lore.kernel.org/all/cover.1756682135.git.nicolinc at nvidia.com/
 * Add Reviewed-by from Baolu
 * [iommu] Use guard(mutex)
 * [iommu] Update kdocs for typos and revisings
 * [iommu] Skip two corner cases (alias and SRIOV)
 * [iommu] Rework attach_dev to pass in old domain pointer
 * [iommu] Reject concurrent attach_dev/set_dev_pasid for compatibility
           concern
 * [smmuv3] Drop the old_domain depedency in its release_dev callback
 * [pci] Add pci_reset_iommu_prepare/_done() wrappers checking ATS cap
v3
 https://lore.kernel.org/all/cover.1754952762.git.nicolinc at nvidia.com/
 * Add Reviewed-by from Jason
 * [iommu] Add a fast return in iommu_deferred_attach()
 * [iommu] Update kdocs, inline comments, and commit logs
 * [iommu] Use group->blocking_domain v.s. ops->blocked_domain
 * [iommu] Drop require_direct, iommu_group_get(), and xa_lock()
 * [iommu] Set the pending_reset flag after RID/PASID domain setups
 * [iommu] Do not bypass PASID domains when RID domain is already the
           blocking_domain
 * [iommu] Add iommu_get_domain_for_dev_locked to correctly return the
           blocking_domain
v2
 https://lore.kernel.org/all/cover.1751096303.git.nicolinc at nvidia.com/
 * [iommu] Update kdocs, inline comments, and commit logs
 * [iommu] Replace long-holding group->mutex with a pending_reset flag
 * [pci] Abort reset routines if iommu_dev_reset_prepare() fails
 * [pci] Apply the same vulnerability fix to other reset functions
v1
 https://lore.kernel.org/all/cover.1749494161.git.nicolinc at nvidia.com/

Thanks
Nicolin

Nicolin Chen (5):
  iommu: Lock group->mutex in iommu_deferred_attach()
  iommu: Tidy domain for iommu_setup_dma_ops()
  iommu: Add iommu_driver_get_domain_for_dev() helper
  iommu: Introduce pci_dev_reset_iommu_prepare/done()
  PCI: Suspend iommu function prior to resetting a device

 drivers/iommu/dma-iommu.h                   |   5 +-
 include/linux/iommu.h                       |  14 ++
 include/uapi/linux/vfio.h                   |   4 +
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c |   5 +-
 drivers/iommu/dma-iommu.c                   |   4 +-
 drivers/iommu/iommu.c                       | 220 +++++++++++++++++++-
 drivers/pci/pci-acpi.c                      |  13 +-
 drivers/pci/pci.c                           |  65 +++++-
 drivers/pci/quirks.c                        |  19 +-
 9 files changed, 326 insertions(+), 23 deletions(-)

-- 
2.43.0



From nicolinc at nvidia.com  Mon Dec 15 13:42:16 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Mon, 15 Dec 2025 13:42:16 -0800
Subject: [PATCH v8 1/5] iommu: Lock group->mutex in iommu_deferred_attach()
In-Reply-To: <cover.1765834788.git.nicolinc@nvidia.com>
References: <cover.1765834788.git.nicolinc@nvidia.com>
Message-ID: <cb38f91526596f4efd0cd1cffa50b4c1b334f7a4.1765834788.git.nicolinc@nvidia.com>

The iommu_deferred_attach() function invokes __iommu_attach_device(), but
doesn't hold the group->mutex like other __iommu_attach_device() callers.

Though there is no pratical bug being triggered so far, it would be better
to apply the same locking to this __iommu_attach_device(), since the IOMMU
drivers nowaday are more aware of the group->mutex -- some of them use the
iommu_group_mutex_assert() function that could be potentially in the path
of an attach_dev callback function invoked by the __iommu_attach_device().

Worth mentioning that the iommu_deferred_attach() will soon need to check
group->resetting_domain that must be locked also.

Thus, grab the mutex to guard __iommu_attach_device() like other callers.

Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian at intel.com>
Reviewed-by: Lu Baolu <baolu.lu at linux.intel.com>
Tested-by: Dheeraj Kumar Srivastava <dheerajkumar.srivastava at amd.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/iommu.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 2ca990dfbb88..170e522b5bda 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2185,10 +2185,17 @@ EXPORT_SYMBOL_GPL(iommu_attach_device);
 
 int iommu_deferred_attach(struct device *dev, struct iommu_domain *domain)
 {
-	if (dev->iommu && dev->iommu->attach_deferred)
-		return __iommu_attach_device(domain, dev, NULL);
+	/*
+	 * This is called on the dma mapping fast path so avoid locking. This is
+	 * racy, but we have an expectation that the driver will setup its DMAs
+	 * inside probe while being single threaded to avoid racing.
+	 */
+	if (!dev->iommu || !dev->iommu->attach_deferred)
+		return 0;
 
-	return 0;
+	guard(mutex)(&dev->iommu_group->mutex);
+
+	return __iommu_attach_device(domain, dev, NULL);
 }
 
 void iommu_detach_device(struct iommu_domain *domain, struct device *dev)
-- 
2.43.0



From nicolinc at nvidia.com  Mon Dec 15 13:42:19 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Mon, 15 Dec 2025 13:42:19 -0800
Subject: [PATCH v8 4/5] iommu: Introduce pci_dev_reset_iommu_prepare/done()
In-Reply-To: <cover.1765834788.git.nicolinc@nvidia.com>
References: <cover.1765834788.git.nicolinc@nvidia.com>
Message-ID: <e5dff289a0ae10e317d87466074aeb0d9ba9c06c.1765834788.git.nicolinc@nvidia.com>

PCIe permits a device to ignore ATS invalidation TLPs while processing a
reset. This creates a problem visible to the OS where an ATS invalidation
command will time out. E.g. an SVA domain will have no coordination with a
reset event and can racily issue ATS invalidations to a resetting device.

The OS should do something to mitigate this as we do not want production
systems to be reporting critical ATS failures, especially in a hypervisor
environment. Broadly, OS could arrange to ignore the timeouts, block page
table mutations to prevent invalidations, or disable and block ATS.

The PCIe r6.0, sec 10.3.1 IMPLEMENTATION NOTE recommends SW to disable and
block ATS before initiating a Function Level Reset. It also mentions that
other reset methods could have the same vulnerability as well.

Provide a callback from the PCI subsystem that will enclose the reset and
have the iommu core temporarily change all the attached RID/PASID domains
group->blocking_domain so that the IOMMU hardware would fence any incoming
ATS queries. And IOMMU drivers should also synchronously stop issuing new
ATS invalidations and wait for all ATS invalidations to complete. This can
avoid any ATS invaliation timeouts.

However, if there is a domain attachment/replacement happening during an
ongoing reset, ATS routines may be re-activated between the two function
calls. So, introduce a new resetting_domain in the iommu_group structure
to reject any concurrent attach_dev/set_dev_pasid call during a reset for
a concern of compatibility failure. Since this changes the behavior of an
attach operation, update the uAPI accordingly.

Note that there are two corner cases:
 1. Devices in the same iommu_group
    Since an attachment is always per iommu_group, this means that any
    sibling devices in the iommu_group cannot change domain, to prevent
    race conditions.
 2. An SR-IOV PF that is being reset while its VF is not
    In such case, the VF itself is already broken. So, there is no point
    in preventing PF from going through the iommu reset.

Reviewed-by: Lu Baolu <baolu.lu at linux.intel.com>
Reviewed-by: Kevin Tian <kevin.tian at intel.com>
Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
Tested-by: Dheeraj Kumar Srivastava <dheerajkumar.srivastava at amd.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 include/linux/iommu.h     |  13 +++
 include/uapi/linux/vfio.h |   4 +
 drivers/iommu/iommu.c     | 173 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 190 insertions(+)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index ff097df318b9..54b8b48c762e 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -1188,6 +1188,10 @@ void iommu_detach_device_pasid(struct iommu_domain *domain,
 			       struct device *dev, ioasid_t pasid);
 ioasid_t iommu_alloc_global_pasid(struct device *dev);
 void iommu_free_global_pasid(ioasid_t pasid);
+
+/* PCI device reset functions */
+int pci_dev_reset_iommu_prepare(struct pci_dev *pdev);
+void pci_dev_reset_iommu_done(struct pci_dev *pdev);
 #else /* CONFIG_IOMMU_API */
 
 struct iommu_ops {};
@@ -1511,6 +1515,15 @@ static inline ioasid_t iommu_alloc_global_pasid(struct device *dev)
 }
 
 static inline void iommu_free_global_pasid(ioasid_t pasid) {}
+
+static inline int pci_dev_reset_iommu_prepare(struct pci_dev *pdev)
+{
+	return 0;
+}
+
+static inline void pci_dev_reset_iommu_done(struct pci_dev *pdev)
+{
+}
 #endif /* CONFIG_IOMMU_API */
 
 #ifdef CONFIG_IRQ_MSI_IOMMU
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index ac2329f24141..bb7b89330d35 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -964,6 +964,10 @@ struct vfio_device_bind_iommufd {
  * hwpt corresponding to the given pt_id.
  *
  * Return: 0 on success, -errno on failure.
+ *
+ * When a device is resetting, -EBUSY will be returned to reject any concurrent
+ * attachment to the resetting device itself or any sibling device in the IOMMU
+ * group having the resetting device.
  */
 struct vfio_device_attach_iommufd_pt {
 	__u32	argsz;
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 672597100e9a..0665dedd91b2 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -61,6 +61,11 @@ struct iommu_group {
 	int id;
 	struct iommu_domain *default_domain;
 	struct iommu_domain *blocking_domain;
+	/*
+	 * During a group device reset, @resetting_domain points to the physical
+	 * domain, while @domain points to the attached domain before the reset.
+	 */
+	struct iommu_domain *resetting_domain;
 	struct iommu_domain *domain;
 	struct list_head entry;
 	unsigned int owner_cnt;
@@ -2195,6 +2200,15 @@ int iommu_deferred_attach(struct device *dev, struct iommu_domain *domain)
 
 	guard(mutex)(&dev->iommu_group->mutex);
 
+	/*
+	 * This is a concurrent attach during a device reset. Reject it until
+	 * pci_dev_reset_iommu_done() attaches the device to group->domain.
+	 *
+	 * Note that this might fail the iommu_dma_map(). But there's nothing
+	 * more we can do here.
+	 */
+	if (dev->iommu_group->resetting_domain)
+		return -EBUSY;
 	return __iommu_attach_device(domain, dev, NULL);
 }
 
@@ -2253,6 +2267,17 @@ struct iommu_domain *iommu_driver_get_domain_for_dev(struct device *dev)
 
 	lockdep_assert_held(&group->mutex);
 
+	/*
+	 * Driver handles the low-level __iommu_attach_device(), including the
+	 * one invoked by pci_dev_reset_iommu_done() re-attaching the device to
+	 * the cached group->domain. In this case, the driver must get the old
+	 * domain from group->resetting_domain rather than group->domain. This
+	 * prevents it from re-attaching the device from group->domain (old) to
+	 * group->domain (new).
+	 */
+	if (group->resetting_domain)
+		return group->resetting_domain;
+
 	return group->domain;
 }
 EXPORT_SYMBOL_GPL(iommu_driver_get_domain_for_dev);
@@ -2409,6 +2434,13 @@ static int __iommu_group_set_domain_internal(struct iommu_group *group,
 	if (WARN_ON(!new_domain))
 		return -EINVAL;
 
+	/*
+	 * This is a concurrent attach during a device reset. Reject it until
+	 * pci_dev_reset_iommu_done() attaches the device to group->domain.
+	 */
+	if (group->resetting_domain)
+		return -EBUSY;
+
 	/*
 	 * Changing the domain is done by calling attach_dev() on the new
 	 * domain. This switch does not have to be atomic and DMA can be
@@ -3527,6 +3559,16 @@ int iommu_attach_device_pasid(struct iommu_domain *domain,
 		return -EINVAL;
 
 	mutex_lock(&group->mutex);
+
+	/*
+	 * This is a concurrent attach during a device reset. Reject it until
+	 * pci_dev_reset_iommu_done() attaches the device to group->domain.
+	 */
+	if (group->resetting_domain) {
+		ret = -EBUSY;
+		goto out_unlock;
+	}
+
 	for_each_group_device(group, device) {
 		/*
 		 * Skip PASID validation for devices without PASID support
@@ -3610,6 +3652,16 @@ int iommu_replace_device_pasid(struct iommu_domain *domain,
 		return -EINVAL;
 
 	mutex_lock(&group->mutex);
+
+	/*
+	 * This is a concurrent attach during a device reset. Reject it until
+	 * pci_dev_reset_iommu_done() attaches the device to group->domain.
+	 */
+	if (group->resetting_domain) {
+		ret = -EBUSY;
+		goto out_unlock;
+	}
+
 	entry = iommu_make_pasid_array_entry(domain, handle);
 	curr = xa_cmpxchg(&group->pasid_array, pasid, NULL,
 			  XA_ZERO_ENTRY, GFP_KERNEL);
@@ -3867,6 +3919,127 @@ int iommu_replace_group_handle(struct iommu_group *group,
 }
 EXPORT_SYMBOL_NS_GPL(iommu_replace_group_handle, "IOMMUFD_INTERNAL");
 
+/**
+ * pci_dev_reset_iommu_prepare() - Block IOMMU to prepare for a PCI device reset
+ * @pdev: PCI device that is going to enter a reset routine
+ *
+ * The PCIe r6.0, sec 10.3.1 IMPLEMENTATION NOTE recommends to disable and block
+ * ATS before initiating a reset. This means that a PCIe device during the reset
+ * routine wants to block any IOMMU activity: translation and ATS invalidation.
+ *
+ * This function attaches the device's RID/PASID(s) the group->blocking_domain,
+ * setting the group->resetting_domain. This allows the IOMMU driver pausing any
+ * IOMMU activity while leaving the group->domain pointer intact. Later when the
+ * reset is finished, pci_dev_reset_iommu_done() can restore everything.
+ *
+ * Caller must use pci_dev_reset_iommu_prepare() with pci_dev_reset_iommu_done()
+ * before/after the core-level reset routine, to unset the resetting_domain.
+ *
+ * Return: 0 on success or negative error code if the preparation failed.
+ *
+ * These two functions are designed to be used by PCI reset functions that would
+ * not invoke any racy iommu_release_device(), since PCI sysfs node gets removed
+ * before it notifies with a BUS_NOTIFY_REMOVED_DEVICE. When using them in other
+ * case, callers must ensure there will be no racy iommu_release_device() call,
+ * which otherwise would UAF the dev->iommu_group pointer.
+ */
+int pci_dev_reset_iommu_prepare(struct pci_dev *pdev)
+{
+	struct iommu_group *group = pdev->dev.iommu_group;
+	unsigned long pasid;
+	void *entry;
+	int ret;
+
+	if (!pci_ats_supported(pdev) || !dev_has_iommu(&pdev->dev))
+		return 0;
+
+	guard(mutex)(&group->mutex);
+
+	/* Re-entry is not allowed */
+	if (WARN_ON(group->resetting_domain))
+		return -EBUSY;
+
+	ret = __iommu_group_alloc_blocking_domain(group);
+	if (ret)
+		return ret;
+
+	/* Stage RID domain at blocking_domain while retaining group->domain */
+	if (group->domain != group->blocking_domain) {
+		ret = __iommu_attach_device(group->blocking_domain, &pdev->dev,
+					    group->domain);
+		if (ret)
+			return ret;
+	}
+
+	/*
+	 * Stage PASID domains at blocking_domain while retaining pasid_array.
+	 *
+	 * The pasid_array is mostly fenced by group->mutex, except one reader
+	 * in iommu_attach_handle_get(), so it's safe to read without xa_lock.
+	 */
+	xa_for_each_start(&group->pasid_array, pasid, entry, 1)
+		iommu_remove_dev_pasid(&pdev->dev, pasid,
+				       pasid_array_entry_to_domain(entry));
+
+	group->resetting_domain = group->blocking_domain;
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pci_dev_reset_iommu_prepare);
+
+/**
+ * pci_dev_reset_iommu_done() - Restore IOMMU after a PCI device reset is done
+ * @pdev: PCI device that has finished a reset routine
+ *
+ * After a PCIe device finishes a reset routine, it wants to restore its IOMMU
+ * IOMMU activity, including new translation as well as cache invalidation, by
+ * re-attaching all RID/PASID of the device's back to the domains retained in
+ * the core-level structure.
+ *
+ * Caller must pair it with a successful pci_dev_reset_iommu_prepare().
+ *
+ * Note that, although unlikely, there is a risk that re-attaching domains might
+ * fail due to some unexpected happening like OOM.
+ */
+void pci_dev_reset_iommu_done(struct pci_dev *pdev)
+{
+	struct iommu_group *group = pdev->dev.iommu_group;
+	unsigned long pasid;
+	void *entry;
+
+	if (!pci_ats_supported(pdev) || !dev_has_iommu(&pdev->dev))
+		return;
+
+	guard(mutex)(&group->mutex);
+
+	/* pci_dev_reset_iommu_prepare() was bypassed for the device */
+	if (!group->resetting_domain)
+		return;
+
+	/* pci_dev_reset_iommu_prepare() was not successfully called */
+	if (WARN_ON(!group->blocking_domain))
+		return;
+
+	/* Re-attach RID domain back to group->domain */
+	if (group->domain != group->blocking_domain) {
+		WARN_ON(__iommu_attach_device(group->domain, &pdev->dev,
+					      group->blocking_domain));
+	}
+
+	/*
+	 * Re-attach PASID domains back to the domains retained in pasid_array.
+	 *
+	 * The pasid_array is mostly fenced by group->mutex, except one reader
+	 * in iommu_attach_handle_get(), so it's safe to read without xa_lock.
+	 */
+	xa_for_each_start(&group->pasid_array, pasid, entry, 1)
+		WARN_ON(__iommu_set_group_pasid(
+			pasid_array_entry_to_domain(entry), group, pasid,
+			group->blocking_domain));
+
+	group->resetting_domain = NULL;
+}
+EXPORT_SYMBOL_GPL(pci_dev_reset_iommu_done);
+
 #if IS_ENABLED(CONFIG_IRQ_MSI_IOMMU)
 /**
  * iommu_dma_prepare_msi() - Map the MSI page in the IOMMU domain
-- 
2.43.0



From nicolinc at nvidia.com  Mon Dec 15 13:42:20 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Mon, 15 Dec 2025 13:42:20 -0800
Subject: [PATCH v8 5/5] PCI: Suspend iommu function prior to resetting a device
In-Reply-To: <cover.1765834788.git.nicolinc@nvidia.com>
References: <cover.1765834788.git.nicolinc@nvidia.com>
Message-ID: <348c50ab6e95b5ec6d48ee3fa05d529a784a34c3.1765834788.git.nicolinc@nvidia.com>

PCIe permits a device to ignore ATS invalidation TLPs while processing a
reset. This creates a problem visible to the OS where an ATS invalidation
command will time out: e.g. an SVA domain will have no coordination with a
reset event and can racily issue ATS invalidations to a resetting device.

The PCIe r6.0, sec 10.3.1 IMPLEMENTATION NOTE recommends SW to disable and
block ATS before initiating a Function Level Reset. It also mentions that
other reset methods could have the same vulnerability as well.

The IOMMU subsystem provides pci_dev_reset_iommu_prepare/done() callback
helpers for this matter. Use them in all the existing reset functions.

This will attach the device to its iommu_group->blocking_domain during the
device reset, so as to allow IOMMU driver to:
 - invoke pci_disable_ats() and pci_enable_ats(), if necessary
 - wait for all ATS invalidations to complete
 - stop issuing new ATS invalidations
 - fence any incoming ATS queries

Reviewed-by: Kevin Tian <kevin.tian at intel.com>
Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
Acked-by: Bjorn Helgaas <bhelgaas at google.com>
Tested-by: Dheeraj Kumar Srivastava <dheerajkumar.srivastava at amd.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/pci/pci-acpi.c | 13 +++++++--
 drivers/pci/pci.c      | 65 +++++++++++++++++++++++++++++++++++++-----
 drivers/pci/quirks.c   | 19 +++++++++++-
 3 files changed, 87 insertions(+), 10 deletions(-)

diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 9369377725fa..651d9b5561ff 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -9,6 +9,7 @@
 
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/iommu.h>
 #include <linux/irqdomain.h>
 #include <linux/pci.h>
 #include <linux/msi.h>
@@ -971,6 +972,7 @@ void pci_set_acpi_fwnode(struct pci_dev *dev)
 int pci_dev_acpi_reset(struct pci_dev *dev, bool probe)
 {
 	acpi_handle handle = ACPI_HANDLE(&dev->dev);
+	int ret;
 
 	if (!handle || !acpi_has_method(handle, "_RST"))
 		return -ENOTTY;
@@ -978,12 +980,19 @@ int pci_dev_acpi_reset(struct pci_dev *dev, bool probe)
 	if (probe)
 		return 0;
 
+	ret = pci_dev_reset_iommu_prepare(dev);
+	if (ret) {
+		pci_err(dev, "failed to stop IOMMU for a PCI reset: %d\n", ret);
+		return ret;
+	}
+
 	if (ACPI_FAILURE(acpi_evaluate_object(handle, "_RST", NULL, NULL))) {
 		pci_warn(dev, "ACPI _RST failed\n");
-		return -ENOTTY;
+		ret = -ENOTTY;
 	}
 
-	return 0;
+	pci_dev_reset_iommu_done(dev);
+	return ret;
 }
 
 bool acpi_pci_power_manageable(struct pci_dev *dev)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 13dbb405dc31..a0ba42ae7ee0 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -13,6 +13,7 @@
 #include <linux/delay.h>
 #include <linux/dmi.h>
 #include <linux/init.h>
+#include <linux/iommu.h>
 #include <linux/msi.h>
 #include <linux/of.h>
 #include <linux/pci.h>
@@ -25,6 +26,7 @@
 #include <linux/logic_pio.h>
 #include <linux/device.h>
 #include <linux/pm_runtime.h>
+#include <linux/pci-ats.h>
 #include <linux/pci_hotplug.h>
 #include <linux/vmalloc.h>
 #include <asm/dma.h>
@@ -4330,13 +4332,22 @@ EXPORT_SYMBOL(pci_wait_for_pending_transaction);
  */
 int pcie_flr(struct pci_dev *dev)
 {
+	int ret;
+
 	if (!pci_wait_for_pending_transaction(dev))
 		pci_err(dev, "timed out waiting for pending transaction; performing function level reset anyway\n");
 
+	/* Have to call it after waiting for pending DMA transaction */
+	ret = pci_dev_reset_iommu_prepare(dev);
+	if (ret) {
+		pci_err(dev, "failed to stop IOMMU for a PCI reset: %d\n", ret);
+		return ret;
+	}
+
 	pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR);
 
 	if (dev->imm_ready)
-		return 0;
+		goto done;
 
 	/*
 	 * Per PCIe r4.0, sec 6.6.2, a device must complete an FLR within
@@ -4345,7 +4356,10 @@ int pcie_flr(struct pci_dev *dev)
 	 */
 	msleep(100);
 
-	return pci_dev_wait(dev, "FLR", PCIE_RESET_READY_POLL_MS);
+	ret = pci_dev_wait(dev, "FLR", PCIE_RESET_READY_POLL_MS);
+done:
+	pci_dev_reset_iommu_done(dev);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(pcie_flr);
 
@@ -4373,6 +4387,7 @@ EXPORT_SYMBOL_GPL(pcie_reset_flr);
 
 static int pci_af_flr(struct pci_dev *dev, bool probe)
 {
+	int ret;
 	int pos;
 	u8 cap;
 
@@ -4399,10 +4414,17 @@ static int pci_af_flr(struct pci_dev *dev, bool probe)
 				 PCI_AF_STATUS_TP << 8))
 		pci_err(dev, "timed out waiting for pending transaction; performing AF function level reset anyway\n");
 
+	/* Have to call it after waiting for pending DMA transaction */
+	ret = pci_dev_reset_iommu_prepare(dev);
+	if (ret) {
+		pci_err(dev, "failed to stop IOMMU for a PCI reset: %d\n", ret);
+		return ret;
+	}
+
 	pci_write_config_byte(dev, pos + PCI_AF_CTRL, PCI_AF_CTRL_FLR);
 
 	if (dev->imm_ready)
-		return 0;
+		goto done;
 
 	/*
 	 * Per Advanced Capabilities for Conventional PCI ECN, 13 April 2006,
@@ -4412,7 +4434,10 @@ static int pci_af_flr(struct pci_dev *dev, bool probe)
 	 */
 	msleep(100);
 
-	return pci_dev_wait(dev, "AF_FLR", PCIE_RESET_READY_POLL_MS);
+	ret = pci_dev_wait(dev, "AF_FLR", PCIE_RESET_READY_POLL_MS);
+done:
+	pci_dev_reset_iommu_done(dev);
+	return ret;
 }
 
 /**
@@ -4433,6 +4458,7 @@ static int pci_af_flr(struct pci_dev *dev, bool probe)
 static int pci_pm_reset(struct pci_dev *dev, bool probe)
 {
 	u16 csr;
+	int ret;
 
 	if (!dev->pm_cap || dev->dev_flags & PCI_DEV_FLAGS_NO_PM_RESET)
 		return -ENOTTY;
@@ -4447,6 +4473,12 @@ static int pci_pm_reset(struct pci_dev *dev, bool probe)
 	if (dev->current_state != PCI_D0)
 		return -EINVAL;
 
+	ret = pci_dev_reset_iommu_prepare(dev);
+	if (ret) {
+		pci_err(dev, "failed to stop IOMMU for a PCI reset: %d\n", ret);
+		return ret;
+	}
+
 	csr &= ~PCI_PM_CTRL_STATE_MASK;
 	csr |= PCI_D3hot;
 	pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr);
@@ -4457,7 +4489,9 @@ static int pci_pm_reset(struct pci_dev *dev, bool probe)
 	pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr);
 	pci_dev_d3_sleep(dev);
 
-	return pci_dev_wait(dev, "PM D3hot->D0", PCIE_RESET_READY_POLL_MS);
+	ret = pci_dev_wait(dev, "PM D3hot->D0", PCIE_RESET_READY_POLL_MS);
+	pci_dev_reset_iommu_done(dev);
+	return ret;
 }
 
 /**
@@ -4885,10 +4919,20 @@ static int pci_reset_bus_function(struct pci_dev *dev, bool probe)
 		return -ENOTTY;
 	}
 
+	rc = pci_dev_reset_iommu_prepare(dev);
+	if (rc) {
+		pci_err(dev, "failed to stop IOMMU for a PCI reset: %d\n", rc);
+		return rc;
+	}
+
 	rc = pci_dev_reset_slot_function(dev, probe);
 	if (rc != -ENOTTY)
-		return rc;
-	return pci_parent_bus_reset(dev, probe);
+		goto done;
+
+	rc = pci_parent_bus_reset(dev, probe);
+done:
+	pci_dev_reset_iommu_done(dev);
+	return rc;
 }
 
 static int cxl_reset_bus_function(struct pci_dev *dev, bool probe)
@@ -4912,6 +4956,12 @@ static int cxl_reset_bus_function(struct pci_dev *dev, bool probe)
 	if (rc)
 		return -ENOTTY;
 
+	rc = pci_dev_reset_iommu_prepare(dev);
+	if (rc) {
+		pci_err(dev, "failed to stop IOMMU for a PCI reset: %d\n", rc);
+		return rc;
+	}
+
 	if (reg & PCI_DVSEC_CXL_PORT_CTL_UNMASK_SBR) {
 		val = reg;
 	} else {
@@ -4926,6 +4976,7 @@ static int cxl_reset_bus_function(struct pci_dev *dev, bool probe)
 		pci_write_config_word(bridge, dvsec + PCI_DVSEC_CXL_PORT_CTL,
 				      reg);
 
+	pci_dev_reset_iommu_done(dev);
 	return rc;
 }
 
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index b9c252aa6fe0..c6b999045c70 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -21,6 +21,7 @@
 #include <linux/pci.h>
 #include <linux/isa-dma.h> /* isa_dma_bridge_buggy */
 #include <linux/init.h>
+#include <linux/iommu.h>
 #include <linux/delay.h>
 #include <linux/acpi.h>
 #include <linux/dmi.h>
@@ -4228,6 +4229,22 @@ static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
 	{ 0 }
 };
 
+static int __pci_dev_specific_reset(struct pci_dev *dev, bool probe,
+				    const struct pci_dev_reset_methods *i)
+{
+	int ret;
+
+	ret = pci_dev_reset_iommu_prepare(dev);
+	if (ret) {
+		pci_err(dev, "failed to stop IOMMU for a PCI reset: %d\n", ret);
+		return ret;
+	}
+
+	ret = i->reset(dev, probe);
+	pci_dev_reset_iommu_done(dev);
+	return ret;
+}
+
 /*
  * These device-specific reset methods are here rather than in a driver
  * because when a host assigns a device to a guest VM, the host may need
@@ -4242,7 +4259,7 @@ int pci_dev_specific_reset(struct pci_dev *dev, bool probe)
 		     i->vendor == (u16)PCI_ANY_ID) &&
 		    (i->device == dev->device ||
 		     i->device == (u16)PCI_ANY_ID))
-			return i->reset(dev, probe);
+			return __pci_dev_specific_reset(dev, probe, i);
 	}
 
 	return -ENOTTY;
-- 
2.43.0



From nicolinc at nvidia.com  Mon Dec 15 13:42:18 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Mon, 15 Dec 2025 13:42:18 -0800
Subject: [PATCH v8 3/5] iommu: Add iommu_driver_get_domain_for_dev() helper
In-Reply-To: <cover.1765834788.git.nicolinc@nvidia.com>
References: <cover.1765834788.git.nicolinc@nvidia.com>
Message-ID: <9ace5b395ce7d05c774c30b9d596c0d5eba7f788.1765834788.git.nicolinc@nvidia.com>

There is a need to stage a resetting PCI device to temporarily the blocked
domain and then attach back to its previously attached domain after reset.

This can be simply done by keeping the "previously attached domain" in the
iommu_group->domain pointer while adding an iommu_group->resetting_domain,
which gives troubles to IOMMU drivers using the iommu_get_domain_for_dev()
for a device's physical domain in order to program IOMMU hardware.

And in such for-driver use cases, the iommu_group->mutex must be held, so
it doesn't fit in external callers that don't hold the iommu_group->mutex.

Introduce a new iommu_driver_get_domain_for_dev() helper, exclusively for
driver use cases that hold the iommu_group->mutex, to separate from those
external use cases.

Add a lockdep_assert_not_held to the existing iommu_get_domain_for_dev()
and highlight that in a kdoc.

Reviewed-by: Kevin Tian <kevin.tian at intel.com>
Reviewed-by: Lu Baolu <baolu.lu at linux.intel.com>
Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
Tested-by: Dheeraj Kumar Srivastava <dheerajkumar.srivastava at amd.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 include/linux/iommu.h                       |  1 +
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c |  5 ++--
 drivers/iommu/iommu.c                       | 28 +++++++++++++++++++++
 3 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 8c66284a91a8..ff097df318b9 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -910,6 +910,7 @@ extern int iommu_attach_device(struct iommu_domain *domain,
 extern void iommu_detach_device(struct iommu_domain *domain,
 				struct device *dev);
 extern struct iommu_domain *iommu_get_domain_for_dev(struct device *dev);
+struct iommu_domain *iommu_driver_get_domain_for_dev(struct device *dev);
 extern struct iommu_domain *iommu_get_dma_domain(struct device *dev);
 extern int iommu_map(struct iommu_domain *domain, unsigned long iova,
 		     phys_addr_t paddr, size_t size, int prot, gfp_t gfp);
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index d16d35c78c06..b8d2fef3ee6b 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -3125,7 +3125,8 @@ int arm_smmu_set_pasid(struct arm_smmu_master *master,
 		       struct arm_smmu_domain *smmu_domain, ioasid_t pasid,
 		       struct arm_smmu_cd *cd, struct iommu_domain *old)
 {
-	struct iommu_domain *sid_domain = iommu_get_domain_for_dev(master->dev);
+	struct iommu_domain *sid_domain =
+		iommu_driver_get_domain_for_dev(master->dev);
 	struct arm_smmu_attach_state state = {
 		.master = master,
 		.ssid = pasid,
@@ -3191,7 +3192,7 @@ static int arm_smmu_blocking_set_dev_pasid(struct iommu_domain *new_domain,
 	 */
 	if (!arm_smmu_ssids_in_use(&master->cd_table)) {
 		struct iommu_domain *sid_domain =
-			iommu_get_domain_for_dev(master->dev);
+			iommu_driver_get_domain_for_dev(master->dev);
 
 		if (sid_domain->type == IOMMU_DOMAIN_IDENTITY ||
 		    sid_domain->type == IOMMU_DOMAIN_BLOCKED)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 1e322f87b171..672597100e9a 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2217,6 +2217,15 @@ void iommu_detach_device(struct iommu_domain *domain, struct device *dev)
 }
 EXPORT_SYMBOL_GPL(iommu_detach_device);
 
+/**
+ * iommu_get_domain_for_dev() - Return the DMA API domain pointer
+ * @dev: Device to query
+ *
+ * This function can be called within a driver bound to dev. The returned
+ * pointer is valid for the lifetime of the bound driver.
+ *
+ * It should not be called by drivers with driver_managed_dma = true.
+ */
 struct iommu_domain *iommu_get_domain_for_dev(struct device *dev)
 {
 	/* Caller must be a probed driver on dev */
@@ -2225,10 +2234,29 @@ struct iommu_domain *iommu_get_domain_for_dev(struct device *dev)
 	if (!group)
 		return NULL;
 
+	lockdep_assert_not_held(&group->mutex);
+
 	return group->domain;
 }
 EXPORT_SYMBOL_GPL(iommu_get_domain_for_dev);
 
+/**
+ * iommu_driver_get_domain_for_dev() - Return the driver-level domain pointer
+ * @dev: Device to query
+ *
+ * This function can be called by an iommu driver that wants to get the physical
+ * domain within an iommu callback function where group->mutex is held.
+ */
+struct iommu_domain *iommu_driver_get_domain_for_dev(struct device *dev)
+{
+	struct iommu_group *group = dev->iommu_group;
+
+	lockdep_assert_held(&group->mutex);
+
+	return group->domain;
+}
+EXPORT_SYMBOL_GPL(iommu_driver_get_domain_for_dev);
+
 /*
  * For IOMMU_DOMAIN_DMA implementations which already provide their own
  * guarantees that the group and its default domain are valid and correct.
-- 
2.43.0



From nicolinc at nvidia.com  Mon Dec 15 13:42:17 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Mon, 15 Dec 2025 13:42:17 -0800
Subject: [PATCH v8 2/5] iommu: Tidy domain for iommu_setup_dma_ops()
In-Reply-To: <cover.1765834788.git.nicolinc@nvidia.com>
References: <cover.1765834788.git.nicolinc@nvidia.com>
Message-ID: <092a99f0b6d59237aa6a06f719f51fca59d7330a.1765834788.git.nicolinc@nvidia.com>

This function can only be called on the default_domain. Trivally pass it
in. In all three existing cases, the default domain was just attached to
the device.

This avoids iommu_setup_dma_ops() calling iommu_get_domain_for_dev() that
will be used by external callers.

Suggested-by: Jason Gunthorpe <jgg at nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian at intel.com>
Reviewed-by: Lu Baolu <baolu.lu at linux.intel.com>
Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
Tested-by: Dheeraj Kumar Srivastava <dheerajkumar.srivastava at amd.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/dma-iommu.h | 5 +++--
 drivers/iommu/dma-iommu.c | 4 +---
 drivers/iommu/iommu.c     | 6 +++---
 3 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/drivers/iommu/dma-iommu.h b/drivers/iommu/dma-iommu.h
index eca201c1f963..040d00252563 100644
--- a/drivers/iommu/dma-iommu.h
+++ b/drivers/iommu/dma-iommu.h
@@ -9,7 +9,7 @@
 
 #ifdef CONFIG_IOMMU_DMA
 
-void iommu_setup_dma_ops(struct device *dev);
+void iommu_setup_dma_ops(struct device *dev, struct iommu_domain *domain);
 
 int iommu_get_dma_cookie(struct iommu_domain *domain);
 void iommu_put_dma_cookie(struct iommu_domain *domain);
@@ -26,7 +26,8 @@ extern bool iommu_dma_forcedac;
 
 #else /* CONFIG_IOMMU_DMA */
 
-static inline void iommu_setup_dma_ops(struct device *dev)
+static inline void iommu_setup_dma_ops(struct device *dev,
+				       struct iommu_domain *domain)
 {
 }
 
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index c92088855450..aeaf8fad985c 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -2097,10 +2097,8 @@ void dma_iova_destroy(struct device *dev, struct dma_iova_state *state,
 }
 EXPORT_SYMBOL_GPL(dma_iova_destroy);
 
-void iommu_setup_dma_ops(struct device *dev)
+void iommu_setup_dma_ops(struct device *dev, struct iommu_domain *domain)
 {
-	struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
-
 	if (dev_is_pci(dev))
 		dev->iommu->pci_32bit_workaround = !iommu_dma_forcedac;
 
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 170e522b5bda..1e322f87b171 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -661,7 +661,7 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list
 	}
 
 	if (group->default_domain)
-		iommu_setup_dma_ops(dev);
+		iommu_setup_dma_ops(dev, group->default_domain);
 
 	mutex_unlock(&group->mutex);
 
@@ -1949,7 +1949,7 @@ static int bus_iommu_probe(const struct bus_type *bus)
 			return ret;
 		}
 		for_each_group_device(group, gdev)
-			iommu_setup_dma_ops(gdev->dev);
+			iommu_setup_dma_ops(gdev->dev, group->default_domain);
 		mutex_unlock(&group->mutex);
 
 		/*
@@ -3155,7 +3155,7 @@ static ssize_t iommu_group_store_type(struct iommu_group *group,
 
 	/* Make sure dma_ops is appropriatley set */
 	for_each_group_device(group, gdev)
-		iommu_setup_dma_ops(gdev->dev);
+		iommu_setup_dma_ops(gdev->dev, group->default_domain);
 
 out_unlock:
 	mutex_unlock(&group->mutex);
-- 
2.43.0



From heiko at sntech.de  Mon Dec 15 13:47:55 2025
From: heiko at sntech.de (Heiko =?UTF-8?B?U3TDvGJuZXI=?=)
Date: Mon, 15 Dec 2025 22:47:55 +0100
Subject: [PATCH] arm64: dts: rockchip: enable dual 2.5GbE on Rock 5T
In-Reply-To: <176580661874.1441131.12947657582985645446.b4-ty@sntech.de>
References: <96516D1F-9787-47FE-A67E-4745D11D9207@probably.group>
 <176580661874.1441131.12947657582985645446.b4-ty@sntech.de>
Message-ID: <2080394.PIDvDuAF1L@diego>

Am Montag, 15. Dezember 2025, 14:51:03 Mitteleurop?ische Normalzeit schrieb Heiko Stuebner:
> 
> On Fri, 12 Dec 2025 17:23:35 +0100, "Martin Holovsk? (Probably Nothing s.r.o. )" wrote:
> > The Radxa Rock 5T board features two RTL8125B 2.5GbE Ethernet controllers
> > connected via PCIe lanes pcie2x1l0 (fe170000) and pcie2x1l2 (fe190000).
> > Currently only one interface is functional because the PCIe controller
> > nodes lack the necessary reset GPIO configuration.
> > 
> > Without the reset-gpios property, the RTL8125B PHYs remain in reset state
> > and are not enumerated by the PCIe bus. This results in only one Ethernet
> > interface being detected, or none at all depending on U-Boot initialization.
> > 
> > [...]
> 
> Applied, thanks!
> 
> [1/1] arm64: dts: rockchip: enable dual 2.5GbE on Rock 5T
>       commit: 96029ffeccf677b1e4baa98f30909a83a485b6d7
> 
> I've resorted both the pcie phandles as well as the pinctrl entries
> pcie2-0 comes before pcie2-1 etc :-) .

and dropped again.

Please resend this patch with a proper Signed-off-by line, as stated
by the developers certificate of origin.

Also, what is this probably nothing s.r.o?

Heiko




From vivek.aknurwar at oss.qualcomm.com  Mon Dec 15 14:19:53 2025
From: vivek.aknurwar at oss.qualcomm.com (Vivek Aknurwar)
Date: Mon, 15 Dec 2025 14:19:53 -0800
Subject: [PATCH 1/1] firmware: arm_scmi: Increase MAX_OPPS to 64
In-Reply-To: <DEVGFVA8N0N9.13ZJADVNM9PHO@linaro.org>
References: <20251014073454.461999-1-vivek.aknurwar@oss.qualcomm.com>
 <6af5945e-7d5c-4596-ac42-c5898b4c49b7@oss.qualcomm.com>
 <DEVEXHI9CEFA.19RL3BXTV8E38@linaro.org>
 <20251211-masterful-caterpillar-of-love-bc2d4c@sudeepholla>
 <DEVFS1MAP8J6.2263USIPE4Y74@linaro.org>
 <20251211-wandering-magnificent-yak-5fb19e@sudeepholla>
 <DEVGFVA8N0N9.13ZJADVNM9PHO@linaro.org>
Message-ID: <b904647e-050f-4283-a24d-71181480dc7a@oss.qualcomm.com>

On 12/11/2025 6:25 AM, Alexey Klimov wrote:
> On Thu Dec 11, 2025 at 2:07 PM GMT, Sudeep Holla wrote:
> 
> [..]
> 
>>>> Ah good point on confusing commit message. I just assumed it is limitation
>>>> of the implementation. I can update the log when applying. It is not spec
>>>> or protocol limitation for sure.
>>>>
>>>> How about this ?
>>>>
>>>>   | firmware: arm_scmi: Increase performance MAX_OPPS limit to 64
>>>>   |
>>>>   | Some platforms expose more than 32 operating performance points (OPPs)
>>>>   | per performance domain via the SCMI performance protocol, but the
>>>>   | driver currently limits the number of OPPs it can handle to 32 via
>>>>   | MAX_OPPS.
>>>>   |
>>>>   | Bump MAX_OPPS to 64 so that these platforms can register all their
>>>>   | performance levels. This is an internal limit in the driver only and
>>>>   | does not affect the SCMI protocol ABI.
>>>>   |
>>>>   | 64 is chosen as the next power of two above the existing limit.
>>>
>>> Yeah, that sounds better :)
>>>
>> Thanks!
>>
>>> I also thought that this was a driver limitation, not the protocol/spec one
>>> as stated in the original patch.
>>>
>>> I don't mind updating the commit message like this (but I am not the author
>>> of the original patch).
>>>
>> Vivek, are you happy with the above edited commit message ?

Yes, I?m good with the suggested commit message. Thanks for clarifying!

Signed-off-by: Vivek Aknurwar <vivek.aknurwar at oss.qualcomm.com>
> 
> FWIW, with updated commit message feel free to use:
> 
> Reviewed-by: Alexey Klimov <alexey.klimov at linaro.org>
> 
> Best regards,
> Alexey



From Frank.Li at nxp.com  Mon Dec 15 14:49:51 2025
From: Frank.Li at nxp.com (Frank Li)
Date: Mon, 15 Dec 2025 17:49:51 -0500
Subject: [PATCH v3 0/5] media: platform: nxp: Trivial cleanup pathces
Message-ID: <20251215-cam_cleanup-v3-0-a61995068f38@nxp.com>

Some trivial patch to reduce goto at probe functions.

Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
Changes in v3:
- rebase to v6.19-rc1
- avoid use __free() == NULL according to cleanup.h
- Link to v2: https://lore.kernel.org/r/20251119-cam_cleanup-v2-0-df732cc83ff1 at nxp.com

Changes in v2:
- add new patch media: nxp: Add dev_err_probe() to all error paths in *async_register() helpers
- detail change see each patch's change log.
- Link to v1: https://lore.kernel.org/r/20251117-cam_cleanup-v1-0-6cd42872db79 at nxp.com

---
Frank Li (5):
      media: nxp: use devm_mutex_init() simple code
      media: nxp: use dev_err_probe() to simplify code
      media: nxp: imx8-isi: use devm_pm_runtime_enable() to simplify code
      media: nxp: use cleanup  __free(fwnode_handle) simplify code
      media: nxp: Add dev_err_probe() to all error paths in *async_register() helpers

 drivers/media/platform/nxp/imx-mipi-csis.c         | 54 ++++++-------
 drivers/media/platform/nxp/imx-pxp.c               |  5 +-
 drivers/media/platform/nxp/imx7-media-csi.c        | 14 ++--
 .../media/platform/nxp/imx8-isi/imx8-isi-core.c    | 16 ++--
 drivers/media/platform/nxp/imx8mq-mipi-csi2.c      | 88 ++++++++++------------
 drivers/media/platform/nxp/mx2_emmaprp.c           |  7 +-
 6 files changed, 83 insertions(+), 101 deletions(-)
---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20250807-cam_cleanup-b6d90ba9dac3

Best regards,
--
Frank Li <Frank.Li at nxp.com>



From Frank.Li at nxp.com  Mon Dec 15 14:49:52 2025
From: Frank.Li at nxp.com (Frank Li)
Date: Mon, 15 Dec 2025 17:49:52 -0500
Subject: [PATCH v3 1/5] media: nxp: use devm_mutex_init() simple code
In-Reply-To: <20251215-cam_cleanup-v3-0-a61995068f38@nxp.com>
References: <20251215-cam_cleanup-v3-0-a61995068f38@nxp.com>
Message-ID: <20251215-cam_cleanup-v3-1-a61995068f38@nxp.com>

Use devm_mutex_init() simple code. No functional change.

Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/media/platform/nxp/imx-pxp.c          |  5 ++++-
 drivers/media/platform/nxp/imx8mq-mipi-csi2.c | 11 +++++------
 drivers/media/platform/nxp/mx2_emmaprp.c      |  7 +++----
 3 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c
index 3f9a67a6bd4d268841f85f9b69af03138300d188..32d39c8013c7eef1f9629f971cc74afecd463ac7 100644
--- a/drivers/media/platform/nxp/imx-pxp.c
+++ b/drivers/media/platform/nxp/imx-pxp.c
@@ -1805,6 +1805,10 @@ static int pxp_probe(struct platform_device *pdev)
 
 	spin_lock_init(&dev->irqlock);
 
+	ret = devm_mutex_init(&pdev->dev, &dev->dev_mutex);
+	if (ret)
+		return ret;
+
 	ret = devm_request_irq(&pdev->dev, irq, pxp_irq_handler, 0,
 			       dev_name(&pdev->dev), dev);
 	if (ret < 0) {
@@ -1831,7 +1835,6 @@ static int pxp_probe(struct platform_device *pdev)
 		goto err_clk;
 
 	atomic_set(&dev->num_inst, 0);
-	mutex_init(&dev->dev_mutex);
 
 	dev->vfd = pxp_videodev;
 	vfd = &dev->vfd;
diff --git a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
index 371b4e81328c107269f89da23818ab0abd0179da..0851f4a9ae52d3096f454da643cfdc5017e000b1 100644
--- a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
+++ b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
@@ -1033,15 +1033,17 @@ static int imx8mq_mipi_csi_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, &state->sd);
 
-	mutex_init(&state->lock);
+	ret = devm_mutex_init(dev, &state->lock);
+	if (ret)
+		return ret;
 
 	ret = imx8mq_mipi_csi_subdev_init(state);
 	if (ret < 0)
-		goto mutex;
+		return ret;
 
 	ret = imx8mq_mipi_csi_init_icc(pdev);
 	if (ret)
-		goto mutex;
+		return ret;
 
 	/* Enable runtime PM. */
 	pm_runtime_enable(dev);
@@ -1068,8 +1070,6 @@ static int imx8mq_mipi_csi_probe(struct platform_device *pdev)
 	v4l2_async_unregister_subdev(&state->sd);
 icc:
 	imx8mq_mipi_csi_release_icc(pdev);
-mutex:
-	mutex_destroy(&state->lock);
 
 	return ret;
 }
@@ -1087,7 +1087,6 @@ static void imx8mq_mipi_csi_remove(struct platform_device *pdev)
 	imx8mq_mipi_csi_runtime_suspend(&pdev->dev);
 	media_entity_cleanup(&state->sd.entity);
 	v4l2_subdev_cleanup(&state->sd);
-	mutex_destroy(&state->lock);
 	pm_runtime_set_suspended(&pdev->dev);
 	imx8mq_mipi_csi_release_icc(pdev);
 }
diff --git a/drivers/media/platform/nxp/mx2_emmaprp.c b/drivers/media/platform/nxp/mx2_emmaprp.c
index 02d57229b9b3a600303cc0429e102139385071d6..384a2672884e96d17cca542ef51fbef62328b66a 100644
--- a/drivers/media/platform/nxp/mx2_emmaprp.c
+++ b/drivers/media/platform/nxp/mx2_emmaprp.c
@@ -824,7 +824,9 @@ static int emmaprp_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	mutex_init(&pcdev->dev_mutex);
+	ret = devm_mutex_init(&pdev->dev, &pcdev->dev_mutex);
+	if (ret)
+		return ret;
 
 	vfd = video_device_alloc();
 	if (!vfd) {
@@ -878,8 +880,6 @@ static int emmaprp_probe(struct platform_device *pdev)
 unreg_dev:
 	v4l2_device_unregister(&pcdev->v4l2_dev);
 
-	mutex_destroy(&pcdev->dev_mutex);
-
 	return ret;
 }
 
@@ -892,7 +892,6 @@ static void emmaprp_remove(struct platform_device *pdev)
 	video_unregister_device(pcdev->vfd);
 	v4l2_m2m_release(pcdev->m2m_dev);
 	v4l2_device_unregister(&pcdev->v4l2_dev);
-	mutex_destroy(&pcdev->dev_mutex);
 }
 
 static struct platform_driver emmaprp_pdrv = {

-- 
2.34.1



From Frank.Li at nxp.com  Mon Dec 15 14:49:53 2025
From: Frank.Li at nxp.com (Frank Li)
Date: Mon, 15 Dec 2025 17:49:53 -0500
Subject: [PATCH v3 2/5] media: nxp: use dev_err_probe() to simplify code
In-Reply-To: <20251215-cam_cleanup-v3-0-a61995068f38@nxp.com>
References: <20251215-cam_cleanup-v3-0-a61995068f38@nxp.com>
Message-ID: <20251215-cam_cleanup-v3-2-a61995068f38@nxp.com>

Use dev_err_probe() to simplify the code. Drop the explicit error message
after returning from imx8mq_mipi_csi_parse_dt(), as the error is already
reported by this helper.

No functional change.

Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
change in v2:
- add  Laurent Pinchart review tags
- wrap error message to new line
- remove error code print in dev_err_probe();
- drop error messaage at imx8mq_mipi_csi_parse_dt()
---
 drivers/media/platform/nxp/imx-mipi-csis.c    |  6 ++---
 drivers/media/platform/nxp/imx7-media-csi.c   | 14 ++++--------
 drivers/media/platform/nxp/imx8mq-mipi-csi2.c | 33 ++++++++++++---------------
 3 files changed, 21 insertions(+), 32 deletions(-)

diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c
index 088b2945aee33731c565f049dd17721356300b84..ce93d868746f002c22e2f86b1e0aa84ec1a76061 100644
--- a/drivers/media/platform/nxp/imx-mipi-csis.c
+++ b/drivers/media/platform/nxp/imx-mipi-csis.c
@@ -1547,10 +1547,8 @@ static int mipi_csis_probe(struct platform_device *pdev)
 	/* Now that the hardware is initialized, request the interrupt. */
 	ret = devm_request_irq(dev, irq, mipi_csis_irq_handler, 0,
 			       dev_name(dev), csis);
-	if (ret) {
-		dev_err(dev, "Interrupt request failed\n");
-		return ret;
-	}
+	if (ret)
+		return dev_err_probe(dev, ret, "Interrupt request failed\n");
 
 	/* Initialize and register the subdev. */
 	ret = mipi_csis_subdev_init(csis);
diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c
index 933a5f39f9f4c9b43ca8d2a1819d0145981266e6..7ddc7ba06e3d4e007013821f67d783898a15461f 100644
--- a/drivers/media/platform/nxp/imx7-media-csi.c
+++ b/drivers/media/platform/nxp/imx7-media-csi.c
@@ -2218,11 +2218,9 @@ static int imx7_csi_probe(struct platform_device *pdev)
 
 	/* Acquire resources and install interrupt handler. */
 	csi->mclk = devm_clk_get(&pdev->dev, "mclk");
-	if (IS_ERR(csi->mclk)) {
-		ret = PTR_ERR(csi->mclk);
-		dev_err(dev, "Failed to get mclk: %d", ret);
-		return ret;
-	}
+	if (IS_ERR(csi->mclk))
+		return dev_err_probe(dev, PTR_ERR(csi->mclk),
+				     "Failed to get mclk\n");
 
 	csi->irq = platform_get_irq(pdev, 0);
 	if (csi->irq < 0)
@@ -2236,10 +2234,8 @@ static int imx7_csi_probe(struct platform_device *pdev)
 
 	ret = devm_request_irq(dev, csi->irq, imx7_csi_irq_handler, 0, "csi",
 			       (void *)csi);
-	if (ret < 0) {
-		dev_err(dev, "Request CSI IRQ failed.\n");
-		return ret;
-	}
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "Request CSI IRQ failed.\n");
 
 	/* Initialize all the media device infrastructure. */
 	ret = imx7_csi_media_init(csi);
diff --git a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
index 0851f4a9ae52d3096f454da643cfdc5017e000b1..a007c582b4d91660a97910a6a0d53c9b6fcd73e9 100644
--- a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
+++ b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
@@ -951,10 +951,9 @@ static int imx8mq_mipi_csi_parse_dt(struct csi_state *state)
 	int ret = 0;
 
 	state->rst = devm_reset_control_array_get_exclusive(dev);
-	if (IS_ERR(state->rst)) {
-		dev_err(dev, "Failed to get reset: %pe\n", state->rst);
-		return PTR_ERR(state->rst);
-	}
+	if (IS_ERR(state->rst))
+		return dev_err_probe(dev, PTR_ERR(state->rst),
+				     "Failed to get reset\n");
 
 	if (state->pdata->use_reg_csr) {
 		const struct regmap_config regmap_config = {
@@ -977,24 +976,22 @@ static int imx8mq_mipi_csi_parse_dt(struct csi_state *state)
 
 	ret = of_property_read_u32_array(np, "fsl,mipi-phy-gpr", out_val,
 					 ARRAY_SIZE(out_val));
-	if (ret) {
-		dev_err(dev, "no fsl,mipi-phy-gpr property found: %d\n", ret);
-		return ret;
-	}
+	if (ret)
+		return dev_err_probe(dev, ret, "no %s property found\n",
+				    "fsl,mipi-phy-gpr");
 
 	ph = *out_val;
 
 	node = of_find_node_by_phandle(ph);
-	if (!node) {
-		dev_err(dev, "Error finding node by phandle\n");
-		return -ENODEV;
-	}
+	if (!node)
+		return dev_err_probe(dev, -ENODEV,
+				     "Error finding node by phandle\n");
+
 	state->phy_gpr = syscon_node_to_regmap(node);
 	of_node_put(node);
-	if (IS_ERR(state->phy_gpr)) {
-		dev_err(dev, "failed to get gpr regmap: %pe\n", state->phy_gpr);
-		return PTR_ERR(state->phy_gpr);
-	}
+	if (IS_ERR(state->phy_gpr))
+		return dev_err_probe(dev, PTR_ERR(state->phy_gpr),
+				     "failed to get gpr regmap\n");
 
 	state->phy_gpr_reg = out_val[1];
 	dev_dbg(dev, "phy gpr register set to 0x%x\n", state->phy_gpr_reg);
@@ -1017,10 +1014,8 @@ static int imx8mq_mipi_csi_probe(struct platform_device *pdev)
 	state->pdata = of_device_get_match_data(dev);
 
 	ret = imx8mq_mipi_csi_parse_dt(state);
-	if (ret < 0) {
-		dev_err(dev, "Failed to parse device tree: %d\n", ret);
+	if (ret < 0)
 		return ret;
-	}
 
 	/* Acquire resources. */
 	state->regs = devm_platform_ioremap_resource(pdev, 0);

-- 
2.34.1



From Frank.Li at nxp.com  Mon Dec 15 14:49:54 2025
From: Frank.Li at nxp.com (Frank Li)
Date: Mon, 15 Dec 2025 17:49:54 -0500
Subject: [PATCH v3 3/5] media: nxp: imx8-isi: use devm_pm_runtime_enable()
 to simplify code
In-Reply-To: <20251215-cam_cleanup-v3-0-a61995068f38@nxp.com>
References: <20251215-cam_cleanup-v3-0-a61995068f38@nxp.com>
Message-ID: <20251215-cam_cleanup-v3-3-a61995068f38@nxp.com>

Use devm_pm_runtime_enable() to simplify code. Change to use
dev_err_probe() because previous goto change to return.

No functional change.

Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
change in v2
- remove error code print at dev_err_probe.
---
 drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c
index c3d411ddf492eb27b372763ce5d344a90c6ec524..486092511d1f9381c250ddcf844fc74c61a789b7 100644
--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c
@@ -499,13 +499,14 @@ static int mxc_isi_probe(struct platform_device *pdev)
 	dma_size = isi->pdata->has_36bit_dma ? 36 : 32;
 	dma_set_mask_and_coherent(dev, DMA_BIT_MASK(dma_size));
 
-	pm_runtime_enable(dev);
+	ret = devm_pm_runtime_enable(dev);
+	if (ret)
+		return ret;
 
 	ret = mxc_isi_crossbar_init(isi);
-	if (ret) {
-		dev_err(dev, "Failed to initialize crossbar: %d\n", ret);
-		goto err_pm;
-	}
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed to initialize crossbar\n");
 
 	for (i = 0; i < isi->pdata->num_channels; ++i) {
 		ret = mxc_isi_pipe_init(isi, i);
@@ -528,8 +529,7 @@ static int mxc_isi_probe(struct platform_device *pdev)
 
 err_xbar:
 	mxc_isi_crossbar_cleanup(&isi->crossbar);
-err_pm:
-	pm_runtime_disable(isi->dev);
+
 	return ret;
 }
 
@@ -548,8 +548,6 @@ static void mxc_isi_remove(struct platform_device *pdev)
 
 	mxc_isi_crossbar_cleanup(&isi->crossbar);
 	mxc_isi_v4l2_cleanup(isi);
-
-	pm_runtime_disable(isi->dev);
 }
 
 static const struct of_device_id mxc_isi_of_match[] = {

-- 
2.34.1



From Frank.Li at nxp.com  Mon Dec 15 14:49:55 2025
From: Frank.Li at nxp.com (Frank Li)
Date: Mon, 15 Dec 2025 17:49:55 -0500
Subject: [PATCH v3 4/5] media: nxp: use cleanup __free(fwnode_handle)
 simplify code
In-Reply-To: <20251215-cam_cleanup-v3-0-a61995068f38@nxp.com>
References: <20251215-cam_cleanup-v3-0-a61995068f38@nxp.com>
Message-ID: <20251215-cam_cleanup-v3-4-a61995068f38@nxp.com>

Use cleanup __free(fwnode_handle) simplify code. No functional change.

Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
change in v3
- Rollback to v1 version to align guide at cleanup.h.
- Ref similar link

    Link: https://lore.kernel.org/r/20240904044825.1048256-1-dmitry.torokhov at gmail.com
    Link: https://patch.msgid.link/20251208020750.4727-3-krzysztof.kozlowski at oss.qualcomm.com

452e0adff2618 Input: iqs7222 - use cleanup facility for fwnodes
52776177d8b7e Input: iqs626a - use cleanup facility for fwnodes
9a540b67a9c26 Input: iqs269a - use cleanup facility for fwnodes
cc3b18f9fedec i3c: master: Fix confusing cleanup.h syntax

change in v2.
- move variable define to top.
- remove dev_err_probe() change
---
 drivers/media/platform/nxp/imx-mipi-csis.c    | 25 ++++++++-----------------
 drivers/media/platform/nxp/imx8mq-mipi-csi2.c | 25 ++++++++-----------------
 2 files changed, 16 insertions(+), 34 deletions(-)

diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c
index ce93d868746f002c22e2f86b1e0aa84ec1a76061..9a43fd1eb0bcee7ac0c47f28ad89012de45a70d9 100644
--- a/drivers/media/platform/nxp/imx-mipi-csis.c
+++ b/drivers/media/platform/nxp/imx-mipi-csis.c
@@ -12,6 +12,7 @@
  *
  */
 
+#include <linux/cleanup.h>
 #include <linux/clk.h>
 #include <linux/debugfs.h>
 #include <linux/delay.h>
@@ -1349,27 +1350,26 @@ static int mipi_csis_async_register(struct mipi_csis_device *csis)
 		.bus_type = V4L2_MBUS_CSI2_DPHY,
 	};
 	struct v4l2_async_connection *asd;
-	struct fwnode_handle *ep;
 	unsigned int i;
 	int ret;
 
 	v4l2_async_subdev_nf_init(&csis->notifier, &csis->sd);
 
-	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csis->dev), 0, 0,
-					     FWNODE_GRAPH_ENDPOINT_NEXT);
+	struct fwnode_handle *ep __free(fwnode_handle) =
+		fwnode_graph_get_endpoint_by_id(dev_fwnode(csis->dev), 0, 0,
+						FWNODE_GRAPH_ENDPOINT_NEXT);
 	if (!ep)
 		return -ENOTCONN;
 
 	ret = v4l2_fwnode_endpoint_parse(ep, &vep);
 	if (ret)
-		goto err_parse;
+		return ret;
 
 	for (i = 0; i < vep.bus.mipi_csi2.num_data_lanes; ++i) {
 		if (vep.bus.mipi_csi2.data_lanes[i] != i + 1) {
 			dev_err(csis->dev,
 				"data lanes reordering is not supported");
-			ret = -EINVAL;
-			goto err_parse;
+			return -EINVAL;
 		}
 	}
 
@@ -1381,12 +1381,8 @@ static int mipi_csis_async_register(struct mipi_csis_device *csis)
 
 	asd = v4l2_async_nf_add_fwnode_remote(&csis->notifier, ep,
 					      struct v4l2_async_connection);
-	if (IS_ERR(asd)) {
-		ret = PTR_ERR(asd);
-		goto err_parse;
-	}
-
-	fwnode_handle_put(ep);
+	if (IS_ERR(asd))
+		return PTR_ERR(asd);
 
 	csis->notifier.ops = &mipi_csis_notify_ops;
 
@@ -1395,11 +1391,6 @@ static int mipi_csis_async_register(struct mipi_csis_device *csis)
 		return ret;
 
 	return v4l2_async_register_subdev(&csis->sd);
-
-err_parse:
-	fwnode_handle_put(ep);
-
-	return ret;
 }
 
 /* -----------------------------------------------------------------------------
diff --git a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
index a007c582b4d91660a97910a6a0d53c9b6fcd73e9..550f9f725cc18fae910282ad72aa1dde37af0b47 100644
--- a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
+++ b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
@@ -6,6 +6,7 @@
  */
 
 #include <linux/bitfield.h>
+#include <linux/cleanup.h>
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/delay.h>
@@ -717,27 +718,26 @@ static int imx8mq_mipi_csi_async_register(struct csi_state *state)
 		.bus_type = V4L2_MBUS_CSI2_DPHY,
 	};
 	struct v4l2_async_connection *asd;
-	struct fwnode_handle *ep;
 	unsigned int i;
 	int ret;
 
 	v4l2_async_subdev_nf_init(&state->notifier, &state->sd);
 
-	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(state->dev), 0, 0,
-					     FWNODE_GRAPH_ENDPOINT_NEXT);
+	struct fwnode_handle *ep __free(fwnode_handle) =
+		fwnode_graph_get_endpoint_by_id(dev_fwnode(state->dev), 0, 0,
+						FWNODE_GRAPH_ENDPOINT_NEXT);
 	if (!ep)
 		return -ENOTCONN;
 
 	ret = v4l2_fwnode_endpoint_parse(ep, &vep);
 	if (ret)
-		goto err_parse;
+		return ret;
 
 	for (i = 0; i < vep.bus.mipi_csi2.num_data_lanes; ++i) {
 		if (vep.bus.mipi_csi2.data_lanes[i] != i + 1) {
 			dev_err(state->dev,
 				"data lanes reordering is not supported");
-			ret = -EINVAL;
-			goto err_parse;
+			return -EINVAL;
 		}
 	}
 
@@ -749,12 +749,8 @@ static int imx8mq_mipi_csi_async_register(struct csi_state *state)
 
 	asd = v4l2_async_nf_add_fwnode_remote(&state->notifier, ep,
 					      struct v4l2_async_connection);
-	if (IS_ERR(asd)) {
-		ret = PTR_ERR(asd);
-		goto err_parse;
-	}
-
-	fwnode_handle_put(ep);
+	if (IS_ERR(asd))
+		return PTR_ERR(asd);
 
 	state->notifier.ops = &imx8mq_mipi_csi_notify_ops;
 
@@ -763,11 +759,6 @@ static int imx8mq_mipi_csi_async_register(struct csi_state *state)
 		return ret;
 
 	return v4l2_async_register_subdev(&state->sd);
-
-err_parse:
-	fwnode_handle_put(ep);
-
-	return ret;
 }
 
 /* -----------------------------------------------------------------------------

-- 
2.34.1



From Frank.Li at nxp.com  Mon Dec 15 14:49:56 2025
From: Frank.Li at nxp.com (Frank Li)
Date: Mon, 15 Dec 2025 17:49:56 -0500
Subject: [PATCH v3 5/5] media: nxp: Add dev_err_probe() to all error paths
 in *async_register() helpers
In-Reply-To: <20251215-cam_cleanup-v3-0-a61995068f38@nxp.com>
References: <20251215-cam_cleanup-v3-0-a61995068f38@nxp.com>
Message-ID: <20251215-cam_cleanup-v3-5-a61995068f38@nxp.com>

Add dev_err_probe() to all error branches in the *async_register() helpers
to provide clearer diagnostic information when device registration fails.

Drop the explicit error message after returning from
mipi_csis_async_register(), as the error is already reported by this
helper.

No functional change.

Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
change in v2
- new patch
---
 drivers/media/platform/nxp/imx-mipi-csis.c    | 31 ++++++++++++++++-----------
 drivers/media/platform/nxp/imx8mq-mipi-csi2.c | 27 ++++++++++++++---------
 2 files changed, 35 insertions(+), 23 deletions(-)

diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c
index 9a43fd1eb0bcee7ac0c47f28ad89012de45a70d9..85098824f4917b3cda3aa71c4ed0a41939283e12 100644
--- a/drivers/media/platform/nxp/imx-mipi-csis.c
+++ b/drivers/media/platform/nxp/imx-mipi-csis.c
@@ -1359,18 +1359,18 @@ static int mipi_csis_async_register(struct mipi_csis_device *csis)
 		fwnode_graph_get_endpoint_by_id(dev_fwnode(csis->dev), 0, 0,
 						FWNODE_GRAPH_ENDPOINT_NEXT);
 	if (!ep)
-		return -ENOTCONN;
+		return dev_err_probe(csis->dev, -ENOTCONN,
+				     "failed to get remote endpoint\n");
 
 	ret = v4l2_fwnode_endpoint_parse(ep, &vep);
 	if (ret)
-		return ret;
+		return dev_err_probe(csis->dev, ret,
+				     "failed to parse endpoint\n");
 
 	for (i = 0; i < vep.bus.mipi_csi2.num_data_lanes; ++i) {
-		if (vep.bus.mipi_csi2.data_lanes[i] != i + 1) {
-			dev_err(csis->dev,
-				"data lanes reordering is not supported");
-			return -EINVAL;
-		}
+		if (vep.bus.mipi_csi2.data_lanes[i] != i + 1)
+			return dev_err_probe(csis->dev, -EINVAL,
+					     "data lanes reordering is not supported");
 	}
 
 	csis->bus = vep.bus.mipi_csi2;
@@ -1382,15 +1382,22 @@ static int mipi_csis_async_register(struct mipi_csis_device *csis)
 	asd = v4l2_async_nf_add_fwnode_remote(&csis->notifier, ep,
 					      struct v4l2_async_connection);
 	if (IS_ERR(asd))
-		return PTR_ERR(asd);
+		return dev_err_probe(csis->dev, PTR_ERR(asd),
+				     "failed to add remote fwmode to notifier\n");
 
 	csis->notifier.ops = &mipi_csis_notify_ops;
 
 	ret = v4l2_async_nf_register(&csis->notifier);
 	if (ret)
-		return ret;
+		return dev_err_probe(csis->dev, ret,
+				     "failed to register notifier\n");
 
-	return v4l2_async_register_subdev(&csis->sd);
+	ret = v4l2_async_register_subdev(&csis->sd);
+	if (ret)
+		return dev_err_probe(csis->dev, ret,
+				     "failed to register subdev\n");
+
+	return 0;
 }
 
 /* -----------------------------------------------------------------------------
@@ -1549,10 +1556,8 @@ static int mipi_csis_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, &csis->sd);
 
 	ret = mipi_csis_async_register(csis);
-	if (ret < 0) {
-		dev_err(dev, "async register failed: %d\n", ret);
+	if (ret < 0)
 		goto err_cleanup;
-	}
 
 	/* Initialize debugfs. */
 	mipi_csis_debugfs_init(csis);
diff --git a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
index 550f9f725cc18fae910282ad72aa1dde37af0b47..f63e0fb1f3091d560dba10dec92523fc74fb6384 100644
--- a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
+++ b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
@@ -727,18 +727,18 @@ static int imx8mq_mipi_csi_async_register(struct csi_state *state)
 		fwnode_graph_get_endpoint_by_id(dev_fwnode(state->dev), 0, 0,
 						FWNODE_GRAPH_ENDPOINT_NEXT);
 	if (!ep)
-		return -ENOTCONN;
+		return dev_err_probe(state->dev, -ENOTCONN,
+				     "failed to get remote endpoint fwnode\n");
 
 	ret = v4l2_fwnode_endpoint_parse(ep, &vep);
 	if (ret)
-		return ret;
+		return dev_err_probe(state->dev, ret,
+				     "failed parse endpoint fwnode\n");
 
 	for (i = 0; i < vep.bus.mipi_csi2.num_data_lanes; ++i) {
-		if (vep.bus.mipi_csi2.data_lanes[i] != i + 1) {
-			dev_err(state->dev,
-				"data lanes reordering is not supported");
-			return -EINVAL;
-		}
+		if (vep.bus.mipi_csi2.data_lanes[i] != i + 1)
+			return dev_err_probe(state->dev, -EINVAL,
+					     "data lanes reordering is not supported");
 	}
 
 	state->bus = vep.bus.mipi_csi2;
@@ -750,15 +750,22 @@ static int imx8mq_mipi_csi_async_register(struct csi_state *state)
 	asd = v4l2_async_nf_add_fwnode_remote(&state->notifier, ep,
 					      struct v4l2_async_connection);
 	if (IS_ERR(asd))
-		return PTR_ERR(asd);
+		return dev_err_probe(state->dev, PTR_ERR(asd),
+				     "failed add fwnode to notifier\n");
 
 	state->notifier.ops = &imx8mq_mipi_csi_notify_ops;
 
 	ret = v4l2_async_nf_register(&state->notifier);
 	if (ret)
-		return ret;
+		return dev_err_probe(state->dev, ret,
+				     "failed to register notifier\n");
 
-	return v4l2_async_register_subdev(&state->sd);
+	ret = v4l2_async_register_subdev(&state->sd);
+	if (ret)
+		return dev_err_probe(state->dev, ret,
+				     "failed to register subdev\n");
+
+	return 0;
 }
 
 /* -----------------------------------------------------------------------------

-- 
2.34.1



From bcreeley at amd.com  Mon Dec 15 15:39:08 2025
From: bcreeley at amd.com (Creeley, Brett)
Date: Mon, 15 Dec 2025 15:39:08 -0800
Subject: [RFC net-next v3 1/3] net: ethernet: mtk_eth_soc: Add register
 definitions for RSS and LRO
In-Reply-To: <033E8AC9-21D6-4707-AE75-37556241CC52@public-files.de>
References: <20251214110310.7009-1-linux@fw-web.de>
 <20251214110310.7009-2-linux@fw-web.de>
 <d101cf0e-bf7c-4aa7-a444-f6b61a1854ad@amd.com>
 <033E8AC9-21D6-4707-AE75-37556241CC52@public-files.de>
Message-ID: <9b7109cf-01d2-4dba-9e7b-7b94094ef4db@amd.com>



On 12/15/2025 11:57 AM, Frank Wunderlich wrote:
> Caution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
>
>
> Am 15. Dezember 2025 20:28:36 MEZ schrieb "Creeley, Brett" <bcreeley at amd.com>:
>>
>> On 12/14/2025 3:03 AM, Frank Wunderlich wrote:
>>> diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
>>> index 0168e2fbc619..334625814b97 100644
>>> --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
>>> +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
>>> @@ -1143,16 +1143,30 @@ struct mtk_reg_map {
>>>           u32     tx_irq_mask;
>>>           u32     tx_irq_status;
>>>           struct {
>>> -               u32     rx_ptr;         /* rx base pointer */
>>> -               u32     rx_cnt_cfg;     /* rx max count configuration */
>>> -               u32     pcrx_ptr;       /* rx cpu pointer */
>>> -               u32     glo_cfg;        /* global configuration */
>>> -               u32     rst_idx;        /* reset index */
>>> -               u32     delay_irq;      /* delay interrupt */
>>> -               u32     irq_status;     /* interrupt status */
>>> -               u32     irq_mask;       /* interrupt mask */
>>> +               u32     rx_ptr;                 /* rx base pointer */
>>> +               u32     rx_cnt_cfg;             /* rx max count configuration */
>>> +               u32     pcrx_ptr;               /* rx cpu pointer */
>>> +               u32     pdrx_ptr;               /* rx dma pointer */
>>> +               u32     glo_cfg;                /* global configuration */
>>> +               u32     rst_idx;                /* reset index */
>>> +               u32     rx_cfg;                 /* rx dma configuration */
>>> +               u32     delay_irq;              /* delay interrupt */
>>> +               u32     irq_status;             /* interrupt status */
>>> +               u32     irq_mask;               /* interrupt mask */
>> Small nit - is the comment alignment really necessary?
> I could transform it to something like this:
>
> <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/net/ethernet/mediatek/mtk_eth_soc.h#n921>

I think it's okay as is. I was more concerned about the extra noise, but 
it's a pretty minimal change.

Brett

>
>> Thanks,
>>
>> Brett
>
> regards Frank
>



From jgg at nvidia.com  Mon Dec 15 16:09:52 2025
From: jgg at nvidia.com (Jason Gunthorpe)
Date: Mon, 15 Dec 2025 20:09:52 -0400
Subject: [PATCH rc v3 1/4] iommu/arm-smmu-v3: Add ignored bits to fix STE
 update sequence
In-Reply-To: <aT87A1ur4htPjM5T@google.com>
References: <cover.1765334526.git.nicolinc@nvidia.com>
 <cc0d4ab571e2e789ee1cddfa035379dc54f0601b.1765334526.git.nicolinc@nvidia.com>
 <aT87A1ur4htPjM5T@google.com>
Message-ID: <20251216000952.GA6079@nvidia.com>

On Sun, Dec 14, 2025 at 10:32:35PM +0000, Mostafa Saleh wrote:
> >   * Figure out if we can do a hitless update of entry to become target. Returns a
> >   * bit mask where 1 indicates that qword needs to be set disruptively.
> > @@ -1094,13 +1100,22 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
> >  {
> >  	__le64 target_used[NUM_ENTRY_QWORDS] = {};
> >  	__le64 cur_used[NUM_ENTRY_QWORDS] = {};
> > +	__le64 ignored[NUM_ENTRY_QWORDS] = {};
> 
> I think we can avoid extra stack allocation for another STE, if we make
> the function update cur_used directly, but no strong opinion.

It does more than just mask cur_used, it also adjusts ignored:

> > +		/*
> > +		 * Ignored is only used for bits that are used by both entries,
> > +		 * otherwise it is sequenced according to the unused entry.
> > +		 */
> > +		ignored[i] &= target_used[i] & cur_used[i];

Which also explains this:

> I have some mixed feelings about this, having get_used(), then get_ignored()
> with the same bits set seems confusing to me, specially the get_ignored()
> loops back to update cur_used, which is set from get_used()

The same bits are set because of the above - we need to know what the
actual used bits are to decide if we need to rely on the ignored rule
to do the update.
 
> My initial though was just to remove this bit from get_used() + some changes
> to checks setting bits that are not used would be enough, and the semantics
> of get_used() can be something as:
> ?Return bits used by the updated translation regime that MUST be observed
> atomically? and in that case we can ignore things as MEV as it doesn?t
> impact the translation.

Aside from the above this would cause problems with the validation
assertions, so it is not a great idea.

> However, this approach makes it a bit explicit which bits are ignored, if we
> keep this logic, I think changing the name of get_ignored() might help, to
> something as "get_allowed_break()" or "get_update_safe()"?

update_safe sounds good to me

Jason


From jgg at ziepe.ca  Mon Dec 15 16:58:34 2025
From: jgg at ziepe.ca (Jason Gunthorpe)
Date: Mon, 15 Dec 2025 20:58:34 -0400
Subject: [PATCH v5 04/27] iommu/io-pgtable-arm: Factor kernel specific
 code out
In-Reply-To: <aTw2x1UlldJGVA4Y@google.com>
References: <20251117184815.1027271-1-smostafa@google.com>
 <20251117184815.1027271-5-smostafa@google.com>
 <20251128164541.GA812105@ziepe.ca>
 <aTw2x1UlldJGVA4Y@google.com>
Message-ID: <20251216005834.GC31492@ziepe.ca>

On Fri, Dec 12, 2025 at 03:37:43PM +0000, Mostafa Saleh wrote:
> On Fri, Nov 28, 2025 at 12:45:41PM -0400, Jason Gunthorpe wrote:
> > On Mon, Nov 17, 2025 at 06:47:51PM +0000, Mostafa Saleh wrote:
> > > Some of the used APIs are only part of the kernel and are not
> > > available in the hypervisor, factor those out:
> > > - alloc/free memory
> > 
> > Why not provide the iommu-pages API for the hypervisor environment?
> > 
> > Same for virt_to_phys, that could be moved into an iommu-pages wrapper
> > too..
> 
> I guess that's possible, but then we would have to stub dma_map/unmap,
> which might a bit ugly. I will look more into it.

I am hoping to drop the dma_map/unmap and replace it with an arch
cache flush call directly since the code is no longer modular and
relying on the DMA API will have some problems with a future patch
series I'm expecting..

Jason


From skhawaja at google.com  Mon Dec 15 17:14:10 2025
From: skhawaja at google.com (Samiullah Khawaja)
Date: Mon, 15 Dec 2025 17:14:10 -0800
Subject: [PATCH v8 1/5] iommu: Lock group->mutex in iommu_deferred_attach()
In-Reply-To: <cb38f91526596f4efd0cd1cffa50b4c1b334f7a4.1765834788.git.nicolinc@nvidia.com>
References: <cover.1765834788.git.nicolinc@nvidia.com> <cb38f91526596f4efd0cd1cffa50b4c1b334f7a4.1765834788.git.nicolinc@nvidia.com>
Message-ID: <CAAywjhSzKM_bEm_VbPZFffY9sR3-p==gbVppSL+555D1kPg_3Q@mail.gmail.com>

On Mon, Dec 15, 2025 at 1:42?PM Nicolin Chen <nicolinc at nvidia.com> wrote:
>
> The iommu_deferred_attach() function invokes __iommu_attach_device(), but
> doesn't hold the group->mutex like other __iommu_attach_device() callers.
>
> Though there is no pratical bug being triggered so far, it would be better
> to apply the same locking to this __iommu_attach_device(), since the IOMMU
> drivers nowaday are more aware of the group->mutex -- some of them use the
> iommu_group_mutex_assert() function that could be potentially in the path
> of an attach_dev callback function invoked by the __iommu_attach_device().
>
> Worth mentioning that the iommu_deferred_attach() will soon need to check
> group->resetting_domain that must be locked also.
>
> Thus, grab the mutex to guard __iommu_attach_device() like other callers.
>
> Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
> Reviewed-by: Kevin Tian <kevin.tian at intel.com>
> Reviewed-by: Lu Baolu <baolu.lu at linux.intel.com>
> Tested-by: Dheeraj Kumar Srivastava <dheerajkumar.srivastava at amd.com>
> Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
> ---
>  drivers/iommu/iommu.c | 13 ++++++++++---
>  1 file changed, 10 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> index 2ca990dfbb88..170e522b5bda 100644
> --- a/drivers/iommu/iommu.c
> +++ b/drivers/iommu/iommu.c
> @@ -2185,10 +2185,17 @@ EXPORT_SYMBOL_GPL(iommu_attach_device);
>
>  int iommu_deferred_attach(struct device *dev, struct iommu_domain *domain)
>  {
> -       if (dev->iommu && dev->iommu->attach_deferred)
> -               return __iommu_attach_device(domain, dev, NULL);
> +       /*
> +        * This is called on the dma mapping fast path so avoid locking. This is
> +        * racy, but we have an expectation that the driver will setup its DMAs
> +        * inside probe while being single threaded to avoid racing.
> +        */
> +       if (!dev->iommu || !dev->iommu->attach_deferred)
> +               return 0;
>
> -       return 0;
> +       guard(mutex)(&dev->iommu_group->mutex);
> +
> +       return __iommu_attach_device(domain, dev, NULL);
>  }
>
>  void iommu_detach_device(struct iommu_domain *domain, struct device *dev)
> --
> 2.43.0
>
>

Reviewed-by: Samiullah Khawaja <skhawaja at google.com>


From peng.fan at oss.nxp.com  Mon Dec 15 17:16:23 2025
From: peng.fan at oss.nxp.com (Peng Fan)
Date: Tue, 16 Dec 2025 09:16:23 +0800
Subject: [PATCH v3 0/2] firmware: arm_scmi/imx: Support dump syslog
In-Reply-To: <20251029-sm-syslog-v3-v3-0-64e14a6e3f87@nxp.com>
References: <20251029-sm-syslog-v3-v3-0-64e14a6e3f87@nxp.com>
Message-ID: <aUCy5+vAPzDGeux3@shlinux89>

Hi Sudeep, Cristian

Just checking in - did you get a chance to review this patchset?
Please let me know if you need any additional details or context.

Thanks,
Peng
On Wed, Oct 29, 2025 at 08:07:00PM +0800, Peng Fan wrote:
>This is the patch 5 and 6 from patchset [1] with switching to using raw
>dump, per check with Sudeep and NXP i.MX SM firmware owner
>
>System Manager firmware provides API to dump system log information.
>So add the interface for Linux to retrieve the information.
>
>In patch 1, I drop the two structures compared to patch 5 in [1]:
>struct scmi_imx_misc_sys_sleep_rec
>struct scmi_imx_misc_syslog
>No other changes in this patch.
>
>In patch 2, I switched to use debugfs to do raw dump the syslog, compared
>with patch 6 in [1].
>
>[1] https://lore.kernel.org/arm-scmi/PAXPR04MB845937237E3C1AF5A2ABA8FA880CA at PAXPR04MB8459.eurprd04.prod.outlook.com/T/#m6ed303ac9c584c6e2ab39f89359f3131b
>dfcc9e5
>
>Signed-off-by: Peng Fan <peng.fan at nxp.com>
>---
>Changes in v3:
>- Rebased to next-20251028
>- Drop unused variable to avoid build warning reported by kernel test robot
>- Link to v2: https://lore.kernel.org/arm-scmi/20251011-sm-syslog-v2-1-v2-0-f43a3f6b32e4 at nxp.com/
>
>Changes in v2:
>- Rebased to next-20251010
>- Patch 2: Remove the IS_ERR check for debugfs_create_dir per Dan Carpenter
>           Change 'return 0' to 'return devm_add_action_or_reset'
>	   Drop the size check
>	   Include 'linux/sizes.h' to avoid build break
>- Link to v1: https://lore.kernel.org/r/20250910-sm-syslog-v1-0-5b36f8f21da6 at nxp.com
>
>---
>Peng Fan (2):
>      firmware: arm_scmi: imx: Support getting syslog of MISC protocol
>      firmware: imx: sm-misc: Dump syslog info
>
> .../firmware/arm_scmi/vendors/imx/imx-sm-misc.c    | 83 ++++++++++++++++++++++
> drivers/firmware/imx/sm-misc.c                     | 37 +++++++++-
> include/linux/scmi_imx_protocol.h                  |  2 +
> 3 files changed, 121 insertions(+), 1 deletion(-)
>---
>base-commit: f7d2388eeec24966fc4d5cf32d706f0514f29ac5
>change-id: 20251029-sm-syslog-v3-0143f85b0ce6
>
>Best regards,
>-- 
>Peng Fan <peng.fan at nxp.com>
>


From yury.norov at gmail.com  Mon Dec 15 17:20:03 2025
From: yury.norov at gmail.com (Yury Norov (NVIDIA))
Date: Mon, 15 Dec 2025 20:20:03 -0500
Subject: [PATCH] drivers: perf: use bitmap_empty() where appropriate
Message-ID: <20251216012004.341288-1-yury.norov@gmail.com>

bitmap_empty() is more verbose and efficient, as it stops traversing
bitmaps as soon as the 1st set bit found.

Switch perf code to using bitmap_empty() where appropriate, and
correspondingly use boolean types.

Signed-off-by: Yury Norov (NVIDIA) <yury.norov at gmail.com>
---
 drivers/perf/riscv_pmu_sbi.c         | 2 +-
 drivers/perf/starfive_starlink_pmu.c | 3 +--
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
index 7dd282da67ce..9dcc22fd48ef 100644
--- a/drivers/perf/riscv_pmu_sbi.c
+++ b/drivers/perf/riscv_pmu_sbi.c
@@ -1244,7 +1244,7 @@ static int riscv_pm_pmu_notify(struct notifier_block *b, unsigned long cmd,
 {
 	struct riscv_pmu *rvpmu = container_of(b, struct riscv_pmu, riscv_pm_nb);
 	struct cpu_hw_events *cpuc = this_cpu_ptr(rvpmu->hw_events);
-	int enabled = bitmap_weight(cpuc->used_hw_ctrs, RISCV_MAX_COUNTERS);
+	bool enabled = !bitmap_empty(cpuc->used_hw_ctrs, RISCV_MAX_COUNTERS);
 	struct perf_event *event;
 	int idx;
 
diff --git a/drivers/perf/starfive_starlink_pmu.c b/drivers/perf/starfive_starlink_pmu.c
index 5e5a672b4229..964897c2baa9 100644
--- a/drivers/perf/starfive_starlink_pmu.c
+++ b/drivers/perf/starfive_starlink_pmu.c
@@ -450,8 +450,7 @@ static int starlink_pmu_pm_notify(struct notifier_block *b,
 							 starlink_pmu_pm_nb);
 	struct starlink_hw_events *hw_events =
 					this_cpu_ptr(starlink_pmu->hw_events);
-	int enabled = bitmap_weight(hw_events->used_mask,
-				    STARLINK_PMU_MAX_COUNTERS);
+	bool enabled = !bitmap_empty(hw_events->used_mask, STARLINK_PMU_MAX_COUNTERS);
 	struct perf_event *event;
 	int idx;
 
-- 
2.43.0



From hayashi.kunihiko at socionext.com  Mon Dec 15 17:20:54 2025
From: hayashi.kunihiko at socionext.com (Kunihiko Hayashi)
Date: Tue, 16 Dec 2025 10:20:54 +0900
Subject: [PATCH] dt-bindings: usb: Add Socionext Uniphier DWC3 controller
In-Reply-To: <20251215212507.3317805-1-robh@kernel.org>
References: <20251215212507.3317805-1-robh@kernel.org>
Message-ID: <0775e913-e531-44b5-b191-7ce0cf4d1e3a@socionext.com>

Hi Rob,

On 2025/12/16 6:25, Rob Herring (Arm) wrote:
> The Socionext Uniphier DWC3 controller binding is already in use, but
> undocumented. It's a straight-forward binding similar to other DWC3
> bindings.

After being pointed out by Krzysztof at OSSJapan, I've checked the bindings
and was preparing some additions or fixes to resolve the warning.

It's almost the same as my proposal, however, I add a little.

> 
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> ---
>   .../bindings/usb/socionext,uniphier-dwc3.yaml | 89 +++++++++++++++++++
>   1 file changed, 89 insertions(+)
>   create mode 100644
> Documentation/devicetree/bindings/usb/socionext,uniphier-dwc3.yaml
> 
> diff --git
> a/Documentation/devicetree/bindings/usb/socionext,uniphier-dwc3.yaml
> b/Documentation/devicetree/bindings/usb/socionext,uniphier-dwc3.yaml
> new file mode 100644
> index 000000000000..892ae3458c1b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/usb/socionext,uniphier-dwc3.yaml
> @@ -0,0 +1,89 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/usb/socionext,uniphier-dwc3.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Socionext Uniphier SuperSpeed DWC3 USB SoC controller
> +
> +maintainers:
> +  - Kunihiko Hayashi <hayashi.kunihiko at socionext.com>
> +  - Masami Hiramatsu <mhiramat at kernel.org>
> +
> +select:
> +  properties:
> +    compatible:
> +      contains:
> +        const: socionext,uniphier-dwc3
> +  required:
> +    - compatible
> +
> +properties:
> +  compatible:
> +    items:
> +      - const: socionext,uniphier-dwc3
> +      - const: snps,dwc3
> +
> +  reg:
> +    maxItems: 1
> +
> +  interrupts:
> +    minItems: 1
> +    items:
> +      - description: Host or single combined interrupt
> +      - description: Peripheral interrupt
> +
> +  interrupt-names:
> +    minItems: 1
> +    items:
> +      - enum:
> +          - dwc_usb3
> +          - host
> +      - const: peripheral
There's no problem, but how about the following description
following snps,dwc3.yaml?

   interrupt-names:
     oneOf:
       - const: dwc_usb3
       - items:
           enum: [host, peripheral]

> +
> +  clocks:
> +    maxItems: 3
> +
> +  clock-names:
> +    items:
> +      - const: ref
> +      - const: bus_early
> +      - const: suspend
> +
> +  phys:
> +    description: 1 to 4 HighSpeed PHYs followed by 1 or 2 SuperSpeed PHYs
> +    minItems: 2
> +    maxItems: 6

Since Pro4 only has one PHY, so:
     minItems: 1

> +
> +  resets:
> +    maxItems: 1
> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts
> +  - clocks
> +  - clock-names
> +  - phys
> +
> +unevaluatedProperties: false
> +
> +allOf:
> +  - $ref: snps,dwc3.yaml#
> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +
> +    usb at 65a00000 {
> +        compatible = "socionext,uniphier-dwc3", "snps,dwc3";
> +        reg = <0x65a00000 0xcd00>;
> +        interrupt-names = "dwc_usb3";
> +        interrupts = <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>;
> +        clock-names = "ref", "bus_early", "suspend";
> +        clocks = <&sys_clk 12>, <&sys_clk 12>, <&sys_clk 12>;
> +        resets = <&usb0_rst 15>;
> +        phys = <&usb0_hsphy0>, <&usb0_hsphy1>,
> +               <&usb0_ssphy0>, <&usb0_ssphy1>;
> +        dr_mode = "host";
> +    };

Thank you,

-- 
---
Best Regards
Kunihiko Hayashi


From hayashi.kunihiko at socionext.com  Mon Dec 15 17:21:06 2025
From: hayashi.kunihiko at socionext.com (Kunihiko Hayashi)
Date: Tue, 16 Dec 2025 10:21:06 +0900
Subject: [PATCH] dt-bindings: PCI: socionext,uniphier-pcie: Fix interrupt
 controller node name
In-Reply-To: <20251215212456.3317558-1-robh@kernel.org>
References: <20251215212456.3317558-1-robh@kernel.org>
Message-ID: <3f1b7852-1494-4a73-8783-b578f9ad5d40@socionext.com>

Hi Rob,

Thank you for pointing out.

On 2025/12/16 6:24, Rob Herring (Arm) wrote:
> The child node name in use by .dts files and the driver is
> "legacy-interrupt-controller", not "interrupt-controller".
After your change commit bcd7ec2cd720 were merged, it was a long time
before I realized I needed to fix it.

"interrupt-controller" is included in the list of Generic Names
Recommendation. Would it be better to apply (i.e. restore) this,
or fix the PCI driver and .dts?

> 
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> ---
>   .../devicetree/bindings/pci/socionext,uniphier-pcie.yaml      | 4 ++--
>   1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git
> a/Documentation/devicetree/bindings/pci/socionext,uniphier-pcie.yaml
> b/Documentation/devicetree/bindings/pci/socionext,uniphier-pcie.yaml
> index c07b0ed51613..8a2f1eef51bd 100644
> --- a/Documentation/devicetree/bindings/pci/socionext,uniphier-pcie.yaml
> +++ b/Documentation/devicetree/bindings/pci/socionext,uniphier-pcie.yaml
> @@ -51,7 +51,7 @@ properties:
>     phy-names:
>       const: pcie-phy
>   
> -  interrupt-controller:
> +  legacy-interrupt-controller:
>       type: object
>       additionalProperties: false
>   
> @@ -111,7 +111,7 @@ examples:
>                           <0 0 0  3  &pcie_intc 2>,
>                           <0 0 0  4  &pcie_intc 3>;
>   
> -        pcie_intc: interrupt-controller {
> +        pcie_intc: legacy-interrupt-controller {
>               #address-cells = <0>;
>               interrupt-controller;
>               #interrupt-cells = <1>;

Thank you,

---
Best Regards
Kunihiko Hayashi


From menglong.dong at linux.dev  Mon Dec 15 17:27:21 2025
From: menglong.dong at linux.dev (Menglong Dong)
Date: Tue, 16 Dec 2025 09:27:21 +0800
Subject: [PATCHv5 bpf-next 1/9] ftrace,bpf: Remove FTRACE_OPS_FL_JMP ftrace_ops
 flag
In-Reply-To: <95c13c0b793604796037ca67c191e1bfce22770dd020107c7179a698c5d49b91@mail.kernel.org>
References: <20251215211402.353056-2-jolsa@kernel.org>
 <95c13c0b793604796037ca67c191e1bfce22770dd020107c7179a698c5d49b91@mail.kernel.org>
Message-ID: <12802095.O9o76ZdvQC@7940hx>

On 2025/12/16 05:31 bot+bpf-ci at kernel.org write:
> > diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
> > index 015dd1049bea..505b7d3f5641 100644
> > --- a/include/linux/ftrace.h
> > +++ b/include/linux/ftrace.h
> 
> [ ... ]
> 
> > diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
> > index 976d89011b15..b9a358d7a78f 100644
> > --- a/kernel/bpf/trampoline.c
> > +++ b/kernel/bpf/trampoline.c
> > @@ -214,10 +214,15 @@ static int modify_fentry(struct bpf_trampoline *tr, u32 orig_flags,
> >  	int ret;
> >
> >  	if (tr->func.ftrace_managed) {
> > +		unsigned long addr = (unsigned long) new_addr;
> > +
> > +		if (bpf_trampoline_use_jmp(tr->flags))
> > +			addr = ftrace_jmp_set(addr);
> > +
> >  		if (lock_direct_mutex)
> > -			ret = modify_ftrace_direct(tr->fops, (long)new_addr);
> > +			ret = modify_ftrace_direct(tr->fops, addr);
> >  		else
> > -			ret = modify_ftrace_direct_nolock(tr->fops, (long)new_addr);
> > +			ret = modify_ftrace_direct_nolock(tr->fops, addr);
> >  	} else {
> >  		ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr,
> >  						   new_addr);
> > @@ -240,10 +245,15 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
> >  	}
> >
> >  	if (tr->func.ftrace_managed) {
> > +		unsigned long addr = (unsigned long) new_addr;
> > +
> > +		if (bpf_trampoline_use_jmp(tr->flags))
> > +			addr = ftrace_jmp_set(addr);
> > +
> >  		ret = ftrace_set_filter_ip(tr->fops, (unsigned long)ip, 0, 1);
> >  		if (ret)
> >  			return ret;
> > -		ret = register_ftrace_direct(tr->fops, (long)new_addr);
> > +		ret = register_ftrace_direct(tr->fops, addr);
> >  	} else {
> >  		ret = bpf_trampoline_update_fentry(tr, 0, NULL, new_addr);
> >  	}
> 
> After this change, register_ftrace_direct() receives an address with
> the LSB bit already set (via ftrace_jmp_set) and stores it as-is in
> entry->direct. This address then flows through to ftrace_find_rec_direct()
> which returns entry->direct unchanged.
> 
> In available_filter_functions_show():
> 
>     direct = ftrace_find_rec_direct(rec->ip);
>     if (direct)
>         seq_printf(m, "\n\tdirect-->%pS", (void *)direct);
> 
> Can the debug output show misleading symbol offsets? When the LSB is
> set, %pS will resolve addresses like "function+0x1" instead of just
> "function". This makes ftrace debug output harder to read for users
> trying to understand direct call attachments.
> 
> The fix would be to strip the LSB bit before printing:
>     seq_printf(m, "\n\tdirect-->%pS", (void *)ftrace_jmp_get(direct));

Ah, this is a good point. However, it's totally another problem, and
I'll follow up it.

Thanks!
Menglong Dong

> 
> [ ... ]
> 
> > diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
> > index bbb37c0f8c6c..b0dc911411f1 100644
> > --- a/kernel/trace/ftrace.c
> > +++ b/kernel/trace/ftrace.c
> > @@ -6017,15 +6017,8 @@ int register_ftrace_direct(struct ftrace_ops *ops, unsigned long addr)
> >  	if (ftrace_hash_empty(hash))
> >  		return -EINVAL;
> >
> > -	/* This is a "raw" address, and this should never happen. */
> > -	if (WARN_ON_ONCE(ftrace_is_jmp(addr)))
> > -		return -EINVAL;
> > -
> >  	mutex_lock(&direct_mutex);
> >
> > -	if (ops->flags & FTRACE_OPS_FL_JMP)
> > -		addr = ftrace_jmp_set(addr);
> > -
> >  	/* Make sure requested entries are not already registered.. */
> >  	size = 1 << hash->size_bits;
> >  	for (i = 0; i < size; i++) {
> 
> [ ... ]
> 
> > @@ -6146,13 +6139,6 @@ __modify_ftrace_direct(struct ftrace_ops *ops, unsigned long addr)
> >
> >  	lockdep_assert_held_once(&direct_mutex);
> >
> > -	/* This is a "raw" address, and this should never happen. */
> > -	if (WARN_ON_ONCE(ftrace_is_jmp(addr)))
> > -		return -EINVAL;
> > -
> > -	if (ops->flags & FTRACE_OPS_FL_JMP)
> > -		addr = ftrace_jmp_set(addr);
> > -
> >  	/* Enable the tmp_ops to have the same functions as the direct ops */
> >  	ftrace_ops_init(&tmp_ops);
> >  	tmp_ops.func_hash = ops->func_hash;
> 
> [ ... ]
> 
> 
> ---
> AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
> See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
> 
> CI run summary: https://github.com/kernel-patches/bpf/actions/runs/20247816064
> 






From jacky_chou at aspeedtech.com  Mon Dec 15 17:49:59 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Tue, 16 Dec 2025 09:49:59 +0800
Subject: [PATCH v7 0/7] Add ASPEED PCIe Root Complex support
Message-ID: <20251216-upstream_pcie_rc-v7-0-4aeb0f53c4ce@aspeedtech.com>

This patch series adds support for the ASPEED PCIe Root Complex,
including device tree bindings, pinctrl support, and the PCIe host controller
driver. The patches introduce the necessary device tree nodes, pinmux groups,
and driver implementation to enable PCIe functionality on ASPEED platforms.
Currently, the ASPEED PCIe Root Complex only supports a single port.

Summary of changes:
- Add device tree binding documents for ASPEED PCIe PHY and PCIe RC
- Update MAINTAINERS for new bindings and driver
- Implement ASPEED PCIe PHY driver
- Implement ASPEED PCIe Root Complex host controller driver

This series has been tested on AST2600/AST2700 platforms and enables PCIe device
enumeration and operation.

Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
---
Changes in v7:
- Add PCIe port into aspeed,ast2600-pci.yaml.
- Remove aspeed_pcie_init_ports() and merge aspeed_pcie_port_init() to
  aspeed_pcie_parse_port()
- Refactor aspeed remap pcie addr to aspeed_pcie_map_ranges()
- Link to v6: https://lore.kernel.org/r/20251201-upstream_pcie_rc-v6-0-8c8800c56b16 at aspeedtech.com

Changes in v6:
- Refer to pci-cpi-bridge.yaml to update aspeed,ast2600-pcie.yaml and
  the pcie node of aspeed-g6.dtsi.
- 'dt-bindings: pinctrl: aspeed,ast2600-pinctrl: Add PCIe RC PERST#
  group' have applied, remove it from this version.
- Adjust the defnitions in pci.h. 
- Link to v5: https://lore.kernel.org/r/20251117-upstream_pcie_rc-v5-0-b4a198576acf at aspeedtech.com

Changes in v5:
- Remove legacy-interrupt-controller and the INTx points to pcie node itself.
- Correct bar mapping description and implementation to PCIe address
  configuration in pcie-aspeed.c driver.
- Link to v4: https://lore.kernel.org/r/20251027095825.181161-1-jacky_chou at aspeedtech.com/

Changes in v4:
- Remove aspeed,ast2700-pcie-cfg.yaml
- Add more descriptions for AST2600 PCIe RC in aspeed,ast2600-pcie.yaml
- Change interrupt-controller to legacy-interrupt-controller in yaml
  and dtsi
- Remove msi-parent property in yaml and dtsi
- Modify the bus range to starting from 0x00 in aspeed-g6.dtsi
- Fixed the typo on MODULE_DEVICE_TABLE() in phy-aspeed-pcie.c
- Add PCIE_CPL_STS_SUCCESS definition in pci/pci.h
- Add prefix ASPEED_ for register definition in RC driver
- Add a flag to indicate clear msi status twice for AST2700 workaround
- Remove getting domain number
- Remove scanning AST2600 HOST bridge on device number 0
- Remove all codes about CONFIG_PCI_MSI
- Get root but number from resouce list by IORESOURCE_BUS
- Change module_platform_driver to builtin_platform_driver
- Link to v3: https://lore.kernel.org/r/20250901055922.1553550-1-jacky_chou at aspeedtech.com/

Changes in v3:
- Add ASPEED PCIe PHY driver
- Remove the aspeed,pciecfg property from AST2600 RC node, merged into RC node
- Update the binding doc for aspeed,ast2700-pcie-cfg to reflect the changes
- Update the binding doc for aspeed,ast2600-pcie to reflect the changes
- Update the binding doc for aspeed,ast2600-pinctrl to reflect the changes
- Update the device tree source to reflect the changes
- Adjusted the use of mutex in RC drivers to use GRAND
- Updated from reviewer comments
- Link to v2: https://lore.kernel.org/r/20250715034320.2553837-1-jacky_chou at aspeedtech.com/

Changes in v2:
- Moved ASPEED PCIe PHY yaml binding to `soc/aspeed` directory and
  changed it as syscon
- Added `MAINTAINERS` entry for the new PCIe RC driver
- Updated device tree bindings to reflect the new structure
- Refactored configuration read and write functions to main bus and
  child bus ops
- Refactored initialization to implement multiple ports support
- Added PCIe FMT and TYPE definitions for TLP header in
  `include/uapi/linux/pci_regs.h`
- Updated from reviewer comments
- Link to v1: https://lore.kernel.org/r/20250613033001.3153637-1-jacky_chou at aspeedtech.com/

---
Jacky Chou (7):
      dt-bindings: phy: aspeed: Add ASPEED PCIe PHY
      dt-bindings: PCI: Add ASPEED PCIe RC support
      ARM: dts: aspeed-g6: Add PCIe RC and PCIe PHY node
      PHY: aspeed: Add ASPEED PCIe PHY driver
      PCI: Add FMT, TYPE and CPL status definition for TLP header
      PCI: aspeed: Add ASPEED PCIe RC driver
      MAINTAINERS: Add ASPEED PCIe RC driver

 .../bindings/pci/aspeed,ast2600-pcie.yaml          |  182 ++++
 .../bindings/phy/aspeed,ast2600-pcie-phy.yaml      |   42 +
 MAINTAINERS                                        |   12 +
 arch/arm/boot/dts/aspeed/aspeed-g6-pinctrl.dtsi    |    5 +
 arch/arm/boot/dts/aspeed/aspeed-g6.dtsi            |   51 +
 drivers/pci/controller/Kconfig                     |   16 +
 drivers/pci/controller/Makefile                    |    1 +
 drivers/pci/controller/pcie-aspeed.c               | 1111 ++++++++++++++++++++
 drivers/pci/pci.h                                  |   15 +
 drivers/phy/Kconfig                                |    1 +
 drivers/phy/Makefile                               |    1 +
 drivers/phy/aspeed/Kconfig                         |   15 +
 drivers/phy/aspeed/Makefile                        |    2 +
 drivers/phy/aspeed/phy-aspeed-pcie.c               |  209 ++++
 14 files changed, 1663 insertions(+)
---
base-commit: 50455515d2364d7f4397b9db98515a1028558295
change-id: 20251103-upstream_pcie_rc-8445759db813

Best regards,
-- 
Jacky Chou <jacky_chou at aspeedtech.com>



From jacky_chou at aspeedtech.com  Mon Dec 15 17:50:00 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Tue, 16 Dec 2025 09:50:00 +0800
Subject: [PATCH v7 1/7] dt-bindings: phy: aspeed: Add ASPEED PCIe PHY
In-Reply-To: <20251216-upstream_pcie_rc-v7-0-4aeb0f53c4ce@aspeedtech.com>
References: <20251216-upstream_pcie_rc-v7-0-4aeb0f53c4ce@aspeedtech.com>
Message-ID: <20251216-upstream_pcie_rc-v7-1-4aeb0f53c4ce@aspeedtech.com>

Introduce device-binding for ASPEED AST2600/2700 PCIe PHY.
The PCIe PHY is used for PCIe RC to configure as RC mode.

Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
---
 .../bindings/phy/aspeed,ast2600-pcie-phy.yaml      | 42 ++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/Documentation/devicetree/bindings/phy/aspeed,ast2600-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/aspeed,ast2600-pcie-phy.yaml
new file mode 100644
index 000000000000..71a5cd91fb3f
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/aspeed,ast2600-pcie-phy.yaml
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/aspeed,ast2600-pcie-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ASPEED PCIe PHY
+
+maintainers:
+  - Jacky Chou <jacky_chou at aspeedtech.com>
+
+description:
+  The ASPEED PCIe PHY provides the physical layer functionality for PCIe
+  controllers in the SoC.
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - aspeed,ast2600-pcie-phy
+          - aspeed,ast2700-pcie-phy
+
+  reg:
+    maxItems: 1
+
+  "#phy-cells":
+    const: 0
+
+required:
+  - compatible
+  - reg
+  - "#phy-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    phy at 1e6ed200 {
+      compatible = "aspeed,ast2600-pcie-phy";
+      reg = <0x1e6ed200 0x100>;
+      #phy-cells = <0>;
+    };

-- 
2.34.1



From jacky_chou at aspeedtech.com  Mon Dec 15 17:50:01 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Tue, 16 Dec 2025 09:50:01 +0800
Subject: [PATCH v7 2/7] dt-bindings: PCI: Add ASPEED PCIe RC support
In-Reply-To: <20251216-upstream_pcie_rc-v7-0-4aeb0f53c4ce@aspeedtech.com>
References: <20251216-upstream_pcie_rc-v7-0-4aeb0f53c4ce@aspeedtech.com>
Message-ID: <20251216-upstream_pcie_rc-v7-2-4aeb0f53c4ce@aspeedtech.com>

ASPEED AST2600 provides one PCIe RC for Gen2 and AST2700 provides three
PCIe RC for two Gen4 and one Gen2. All of these RCs have just one root
port to connect to PCIe device. And also have Mem, I/O access, legacy
interrupt and MSI.

Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
---
 .../bindings/pci/aspeed,ast2600-pcie.yaml          | 182 +++++++++++++++++++++
 1 file changed, 182 insertions(+)

diff --git a/Documentation/devicetree/bindings/pci/aspeed,ast2600-pcie.yaml b/Documentation/devicetree/bindings/pci/aspeed,ast2600-pcie.yaml
new file mode 100644
index 000000000000..d9478249418a
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/aspeed,ast2600-pcie.yaml
@@ -0,0 +1,182 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pci/aspeed,ast2600-pcie.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ASPEED PCIe Root Complex Controller
+
+maintainers:
+  - Jacky Chou <jacky_chou at aspeedtech.com>
+
+description:
+  The ASPEED PCIe Root Complex controller provides PCI Express Root Complex
+  functionality for ASPEED SoCs, such as the AST2600 and AST2700.
+  This controller enables connectivity to PCIe endpoint devices, supporting
+  memory and I/O windows, MSI and INTx interrupts, and integration with
+  the SoC's clock, reset, and pinctrl subsystems. On AST2600, the PCIe Root
+  Port device number is always 8.
+
+properties:
+  compatible:
+    enum:
+      - aspeed,ast2600-pcie
+      - aspeed,ast2700-pcie
+
+  reg:
+    maxItems: 1
+
+  ranges:
+    minItems: 2
+    maxItems: 2
+
+  interrupts:
+    maxItems: 1
+    description: INTx and MSI interrupt
+
+  resets:
+    items:
+      - description: PCIe controller reset
+
+  reset-names:
+    items:
+      - const: h2x
+
+  aspeed,ahbc:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      Phandle to the ASPEED AHB Controller (AHBC) syscon node.
+      This reference is used by the PCIe controller to access
+      system-level configuration registers related to the AHB bus.
+      To enable AHB access for the PCIe controller.
+
+  aspeed,pciecfg:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      Phandle to the ASPEED PCIe configuration syscon node.
+      This reference allows the PCIe controller to access
+      SoC-specific PCIe configuration registers. There are the others
+      functions such PCIe RC and PCIe EP will use this common register
+      to configure the SoC interfaces.
+
+  interrupt-controller: true
+
+patternProperties:
+  "^pcie@[0-9a-f]+,0$":
+    type: object
+    $ref: /schemas/pci/pci-pci-bridge.yaml#
+
+    properties:
+      reg:
+        maxItems: 1
+
+      resets:
+        items:
+          - description: PERST# signal
+
+      reset-names:
+        items:
+          - const: perst
+
+      clocks:
+        maxItems: 1
+
+      phys:
+        maxItems: 1
+
+    required:
+      - resets
+      - reset-names
+      - clocks
+      - phys
+      - ranges
+
+    unevaluatedProperties: false
+
+allOf:
+  - $ref: /schemas/pci/pci-host-bridge.yaml#
+  - $ref: /schemas/interrupt-controller/msi-controller.yaml#
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: aspeed,ast2600-pcie
+    then:
+      required:
+        - aspeed,ahbc
+    else:
+      properties:
+        aspeed,ahbc: false
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: aspeed,ast2700-pcie
+    then:
+      required:
+        - aspeed,pciecfg
+    else:
+      properties:
+        aspeed,pciecfg: false
+
+required:
+  - reg
+  - interrupts
+  - bus-range
+  - ranges
+  - resets
+  - reset-names
+  - msi-controller
+  - interrupt-controller
+  - interrupt-map-mask
+  - interrupt-map
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/ast2600-clock.h>
+
+    pcie0: pcie at 1e770000 {
+      compatible = "aspeed,ast2600-pcie";
+      device_type = "pci";
+      reg = <0x1e770000 0x100>;
+      #address-cells = <3>;
+      #size-cells = <2>;
+      interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+      bus-range = <0x00 0xff>;
+
+      ranges = <0x01000000 0x0 0x00018000 0x00018000 0x0 0x00008000
+                0x02000000 0x0 0x60000000 0x60000000 0x0 0x20000000>;
+
+      resets = <&syscon ASPEED_RESET_H2X>;
+      reset-names = "h2x";
+
+      #interrupt-cells = <1>;
+      msi-controller;
+
+      aspeed,ahbc = <&ahbc>;
+
+      interrupt-controller;
+      interrupt-map-mask = <0 0 0 7>;
+      interrupt-map = <0 0 0 1 &pcie0 0>,
+                      <0 0 0 2 &pcie0 1>,
+                      <0 0 0 3 &pcie0 2>,
+                      <0 0 0 4 &pcie0 3>;
+
+      pcie at 8,0 {
+        compatible = "pciclass,0604";
+        reg = <0x00004000 0 0 0 0>;
+        #address-cells = <3>;
+        #size-cells = <2>;
+        device_type = "pci";
+        resets = <&syscon ASPEED_RESET_PCIE_RC_O>;
+        reset-names = "perst";
+        clocks = <&syscon ASPEED_CLK_GATE_BCLK>;
+        pinctrl-names = "default";
+        pinctrl-0 = <&pinctrl_pcierc1_default>;
+        phys = <&pcie_phy1>;
+        ranges;
+      };
+    };

-- 
2.34.1



From jacky_chou at aspeedtech.com  Mon Dec 15 17:50:02 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Tue, 16 Dec 2025 09:50:02 +0800
Subject: [PATCH v7 3/7] ARM: dts: aspeed-g6: Add PCIe RC and PCIe PHY node
In-Reply-To: <20251216-upstream_pcie_rc-v7-0-4aeb0f53c4ce@aspeedtech.com>
References: <20251216-upstream_pcie_rc-v7-0-4aeb0f53c4ce@aspeedtech.com>
Message-ID: <20251216-upstream_pcie_rc-v7-3-4aeb0f53c4ce@aspeedtech.com>

The AST2600 has one PCIe RC and add the PCIe PHY for RC.
And add pinctrl support for PCIe RC PERST#.

Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
---
 arch/arm/boot/dts/aspeed/aspeed-g6-pinctrl.dtsi |  5 +++
 arch/arm/boot/dts/aspeed/aspeed-g6.dtsi         | 51 +++++++++++++++++++++++++
 2 files changed, 56 insertions(+)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-g6-pinctrl.dtsi b/arch/arm/boot/dts/aspeed/aspeed-g6-pinctrl.dtsi
index e87c4b58994a..d46f2047135c 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-g6-pinctrl.dtsi
+++ b/arch/arm/boot/dts/aspeed/aspeed-g6-pinctrl.dtsi
@@ -2,6 +2,11 @@
 // Copyright 2019 IBM Corp.
 
 &pinctrl {
+	pinctrl_pcierc1_default: pcierc1-default {
+		function = "PCIERC1";
+		groups = "PCIERC1";
+	};
+
 	pinctrl_adc0_default: adc0_default {
 		function = "ADC0";
 		groups = "ADC0";
diff --git a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
index f8662c8ac089..a525c63dac3c 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
+++ b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
@@ -379,6 +379,57 @@ rng: hwrng at 1e6e2524 {
 				quality = <100>;
 			};
 
+			pcie_phy1: phy at 1e6ed200 {
+				compatible = "aspeed,ast2600-pcie-phy";
+				reg = <0x1e6ed200 0x100>;
+				#phy-cells = <0>;
+			};
+
+			pcie0: pcie at 1e770000 {
+				compatible = "aspeed,ast2600-pcie";
+				device_type = "pci";
+				reg = <0x1e770000 0x100>;
+				#address-cells = <3>;
+				#size-cells = <2>;
+				interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+				bus-range = <0x00 0xff>;
+
+				ranges = <0x01000000 0x0 0x00018000 0x00018000 0x0 0x00008000
+					  0x02000000 0x0 0x60000000 0x60000000 0x0 0x20000000>;
+
+				status = "disabled";
+
+				resets = <&syscon ASPEED_RESET_H2X>;
+				reset-names = "h2x";
+
+				#interrupt-cells = <1>;
+				msi-controller;
+
+				aspeed,ahbc = <&ahbc>;
+
+				interrupt-controller;
+				interrupt-map-mask = <0 0 0 7>;
+				interrupt-map = <0 0 0 1 &pcie0 0>,
+						<0 0 0 2 &pcie0 1>,
+						<0 0 0 3 &pcie0 2>,
+						<0 0 0 4 &pcie0 3>;
+
+				pcie at 8,0 {
+					compatible = "pciclass,0604";
+					reg = <0x00004000 0 0 0 0>;
+					#address-cells = <3>;
+					#size-cells = <2>;
+					device_type = "pci";
+					resets = <&syscon ASPEED_RESET_PCIE_RC_O>;
+					reset-names = "perst";
+					clocks = <&syscon ASPEED_CLK_GATE_BCLK>;
+					pinctrl-names = "default";
+					pinctrl-0 = <&pinctrl_pcierc1_default>;
+					phys = <&pcie_phy1>;
+					ranges;
+				};
+			};
+
 			gfx: display at 1e6e6000 {
 				compatible = "aspeed,ast2600-gfx", "syscon";
 				reg = <0x1e6e6000 0x1000>;

-- 
2.34.1



From jacky_chou at aspeedtech.com  Mon Dec 15 17:50:03 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Tue, 16 Dec 2025 09:50:03 +0800
Subject: [PATCH v7 4/7] PHY: aspeed: Add ASPEED PCIe PHY driver
In-Reply-To: <20251216-upstream_pcie_rc-v7-0-4aeb0f53c4ce@aspeedtech.com>
References: <20251216-upstream_pcie_rc-v7-0-4aeb0f53c4ce@aspeedtech.com>
Message-ID: <20251216-upstream_pcie_rc-v7-4-4aeb0f53c4ce@aspeedtech.com>

Introduce support for Aspeed PCIe PHY controller available in
AST2600/2700.

Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
---
 drivers/phy/Kconfig                  |   1 +
 drivers/phy/Makefile                 |   1 +
 drivers/phy/aspeed/Kconfig           |  15 +++
 drivers/phy/aspeed/Makefile          |   2 +
 drivers/phy/aspeed/phy-aspeed-pcie.c | 209 +++++++++++++++++++++++++++++++++++
 5 files changed, 228 insertions(+)

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 678dd0452f0a..f6a8f06fd244 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -103,6 +103,7 @@ config PHY_NXP_PTN3222
 
 source "drivers/phy/allwinner/Kconfig"
 source "drivers/phy/amlogic/Kconfig"
+source "drivers/phy/aspeed/Kconfig"
 source "drivers/phy/broadcom/Kconfig"
 source "drivers/phy/cadence/Kconfig"
 source "drivers/phy/freescale/Kconfig"
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index bfb27fb5a494..18990c87dfb0 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_PHY_AIROHA_PCIE)		+= phy-airoha-pcie.o
 obj-$(CONFIG_PHY_NXP_PTN3222)		+= phy-nxp-ptn3222.o
 obj-y					+= allwinner/	\
 					   amlogic/	\
+					   aspeed/	\
 					   broadcom/	\
 					   cadence/	\
 					   freescale/	\
diff --git a/drivers/phy/aspeed/Kconfig b/drivers/phy/aspeed/Kconfig
new file mode 100644
index 000000000000..6aeeca84091f
--- /dev/null
+++ b/drivers/phy/aspeed/Kconfig
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Phy drivers for Aspeed platforms
+#
+config PHY_ASPEED_PCIE
+	tristate "ASPEED PCIe PHY driver"
+	select GENERIC_PHY
+	depends on ARCH_ASPEED
+	default y
+	help
+	  This option enables support for the ASPEED PCIe PHY driver.
+	  The driver provides the necessary interface to control and
+	  configure the PCIe PHY hardware found on ASPEED SoCs.
+	  It is required for proper operation of PCIe devices on
+	  platforms using ASPEED chips.
\ No newline at end of file
diff --git a/drivers/phy/aspeed/Makefile b/drivers/phy/aspeed/Makefile
new file mode 100644
index 000000000000..7203152f44bf
--- /dev/null
+++ b/drivers/phy/aspeed/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_PHY_ASPEED_PCIE)		+= phy-aspeed-pcie.o
\ No newline at end of file
diff --git a/drivers/phy/aspeed/phy-aspeed-pcie.c b/drivers/phy/aspeed/phy-aspeed-pcie.c
new file mode 100644
index 000000000000..3de43a86ac17
--- /dev/null
+++ b/drivers/phy/aspeed/phy-aspeed-pcie.c
@@ -0,0 +1,209 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 Aspeed Technology Inc.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/pcie.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+
+/* AST2600 PCIe Host Controller Registers */
+#define PEHR_GLOBAL		0x30
+#define  AST2600_PORT_TYPE_MASK		GENMASK(5, 4)
+#define  AST2600_PORT_TYPE(x)		FIELD_PREP(AST2600_PORT_TYPE_MASK, x)
+#define PEHR_LOCK		0x7c
+#define  PCIE_UNLOCK			0xa8
+
+/* AST2700 PEHR */
+#define PEHR_MISC_58		0x58
+#define  LOCAL_SCALE_SUP		BIT(0)
+#define PEHR_MISC_5C		0x5c
+#define  CONFIG_RC_DEVICE		BIT(30)
+#define PEHR_MISC_60		0x60
+#define  AST2700_PORT_TYPE_MASK		GENMASK(7, 4)
+#define  PORT_TYPE_ROOT			BIT(6)
+#define PEHR_MISC_70		0x70
+#define  POSTED_DATA_CREDITS(x)		FIELD_PREP(GENMASK(15, 0), x)
+#define  POSTED_HEADER_CREDITS(x)	FIELD_PREP(GENMASK(27, 16), x)
+#define PEHR_MISC_78		0x78
+#define  COMPLETION_DATA_CREDITS(x)	FIELD_PREP(GENMASK(15, 0), x)
+#define  COMPLETION_HEADER_CREDITS(x)	FIELD_PREP(GENMASK(27, 16), x)
+
+/**
+ * struct aspeed_pcie_phy - PCIe PHY information
+ * @dev: pointer to device structure
+ * @reg: PCIe host register base address
+ * @phy: pointer to PHY structure
+ * @platform: platform specific information
+ */
+struct aspeed_pcie_phy {
+	struct device *dev;
+	void __iomem *reg;
+	struct phy *phy;
+	const struct aspeed_pcie_phy_platform *platform;
+};
+
+/**
+ * struct aspeed_pcie_phy_platform - Platform information
+ * @phy_ops: phy operations
+ */
+struct aspeed_pcie_phy_platform {
+	const struct phy_ops *phy_ops;
+};
+
+static int ast2600_phy_init(struct phy *phy)
+{
+	struct aspeed_pcie_phy *pcie_phy = phy_get_drvdata(phy);
+
+	writel(PCIE_UNLOCK, pcie_phy->reg + PEHR_LOCK);
+
+	return 0;
+}
+
+static int ast2600_phy_set_mode(struct phy *phy, enum phy_mode mode,
+				int submode)
+{
+	struct aspeed_pcie_phy *pcie_phy = phy_get_drvdata(phy);
+
+	switch (submode) {
+	case PHY_MODE_PCIE_RC:
+		writel(AST2600_PORT_TYPE(0x3), pcie_phy->reg + PEHR_GLOBAL);
+		break;
+	default:
+		dev_err(&phy->dev, "Unsupported submode %d\n", submode);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct phy_ops ast2600_phy_ops = {
+	.init		= ast2600_phy_init,
+	.set_mode	= ast2600_phy_set_mode,
+	.owner		= THIS_MODULE,
+};
+
+static int ast2700_phy_init(struct phy *phy)
+{
+	struct aspeed_pcie_phy *pcie_phy = phy_get_drvdata(phy);
+
+	writel(POSTED_DATA_CREDITS(0xc0) | POSTED_HEADER_CREDITS(0xa),
+	       pcie_phy->reg + PEHR_MISC_70);
+	writel(COMPLETION_DATA_CREDITS(0x30) | COMPLETION_HEADER_CREDITS(0x8),
+	       pcie_phy->reg + PEHR_MISC_78);
+	writel(LOCAL_SCALE_SUP, pcie_phy->reg + PEHR_MISC_58);
+
+	return 0;
+}
+
+static int ast2700_phy_set_mode(struct phy *phy, enum phy_mode mode,
+				int submode)
+{
+	struct aspeed_pcie_phy *pcie_phy = phy_get_drvdata(phy);
+	u32 cfg_val;
+
+	switch (submode) {
+	case PHY_MODE_PCIE_RC:
+		writel(CONFIG_RC_DEVICE, pcie_phy->reg + PEHR_MISC_5C);
+		cfg_val = readl(pcie_phy->reg + PEHR_MISC_60);
+		cfg_val &= ~AST2700_PORT_TYPE_MASK;
+		cfg_val |= PORT_TYPE_ROOT;
+		writel(cfg_val, pcie_phy->reg + PEHR_MISC_60);
+		break;
+	default:
+		dev_err(&phy->dev, "Unsupported submode %d\n", submode);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct phy_ops ast2700_phy_ops = {
+	.init		= ast2700_phy_init,
+	.set_mode	= ast2700_phy_set_mode,
+	.owner		= THIS_MODULE,
+};
+
+const struct aspeed_pcie_phy_platform pcie_phy_ast2600 = {
+	.phy_ops = &ast2600_phy_ops,
+};
+
+const struct aspeed_pcie_phy_platform pcie_phy_ast2700 = {
+	.phy_ops = &ast2700_phy_ops,
+};
+
+static int aspeed_pcie_phy_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct phy_provider *phy_provider;
+	struct aspeed_pcie_phy *pcie_phy;
+	const struct aspeed_pcie_phy_platform *md;
+
+	md = of_device_get_match_data(dev);
+	if (!md)
+		return -ENODEV;
+
+	pcie_phy = devm_kzalloc(dev, sizeof(*pcie_phy), GFP_KERNEL);
+	if (!pcie_phy)
+		return -ENOMEM;
+
+	pcie_phy->reg = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(pcie_phy->reg))
+		return PTR_ERR(pcie_phy->reg);
+
+	pcie_phy->dev = dev;
+	pcie_phy->platform = md;
+
+	pcie_phy->phy = devm_phy_create(dev, dev->of_node,
+					pcie_phy->platform->phy_ops);
+	if (IS_ERR(pcie_phy->phy))
+		return dev_err_probe(dev, PTR_ERR(pcie_phy->phy),
+				     "failed to create PHY\n");
+
+	phy_set_drvdata(pcie_phy->phy, pcie_phy);
+	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+	return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id aspeed_pcie_phy_of_match_table[] = {
+	{
+		.compatible = "aspeed,ast2600-pcie-phy",
+		.data = &pcie_phy_ast2600,
+	},
+	{
+		.compatible = "aspeed,ast2700-pcie-phy",
+		.data = &pcie_phy_ast2700,
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, aspeed_pcie_phy_of_match_table);
+
+static struct platform_driver aspeed_pcie_driver = {
+	.probe		= aspeed_pcie_phy_probe,
+	.driver = {
+		.name	= "aspeed-pcie-phy",
+		.of_match_table = aspeed_pcie_phy_of_match_table,
+	},
+};
+
+module_platform_driver(aspeed_pcie_driver);
+
+MODULE_AUTHOR("Jacky Chou <jacky_chou at aspeedtech.com>");
+MODULE_DESCRIPTION("ASPEED PCIe PHY");
+MODULE_LICENSE("GPL");

-- 
2.34.1



From jacky_chou at aspeedtech.com  Mon Dec 15 17:50:04 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Tue, 16 Dec 2025 09:50:04 +0800
Subject: [PATCH v7 5/7] PCI: Add FMT, TYPE and CPL status definition for
 TLP header
In-Reply-To: <20251216-upstream_pcie_rc-v7-0-4aeb0f53c4ce@aspeedtech.com>
References: <20251216-upstream_pcie_rc-v7-0-4aeb0f53c4ce@aspeedtech.com>
Message-ID: <20251216-upstream_pcie_rc-v7-5-4aeb0f53c4ce@aspeedtech.com>

According to PCIe specification, add FMT, TYPE and CPL status
definition for TLP header.

Acked-by: Bjorn Helgaas <bhelgaas at google.com>
Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
---
 drivers/pci/pci.h | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 0e67014aa001..81f2e633b116 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -63,6 +63,18 @@ struct pcie_tlp_log;
 #define PCIE_LINK_WAIT_MAX_RETRIES	10
 #define PCIE_LINK_WAIT_SLEEP_MS		90
 
+/* Format of TLP; PCIe r7.0, sec 2.2.1 */
+#define PCIE_TLP_FMT_3DW_NO_DATA	0x00 /* 3DW header, no data */
+#define PCIE_TLP_FMT_4DW_NO_DATA	0x01 /* 4DW header, no data */
+#define PCIE_TLP_FMT_3DW_DATA		0x02 /* 3DW header, with data */
+#define PCIE_TLP_FMT_4DW_DATA		0x03 /* 4DW header, with data */
+
+/* Type of TLP; PCIe r7.0, sec 2.2.1 */
+#define PCIE_TLP_TYPE_CFG0_RD		0x04 /* Config Type 0 Read Request */
+#define PCIE_TLP_TYPE_CFG0_WR		0x04 /* Config Type 0 Write Request */
+#define PCIE_TLP_TYPE_CFG1_RD		0x05 /* Config Type 1 Read Request */
+#define PCIE_TLP_TYPE_CFG1_WR		0x05 /* Config Type 1 Write Request */
+
 /* Message Routing (r[2:0]); PCIe r6.0, sec 2.2.8 */
 #define PCIE_MSG_TYPE_R_RC	0
 #define PCIE_MSG_TYPE_R_ADDR	1
@@ -84,6 +96,9 @@ struct pcie_tlp_log;
 #define PCIE_MSG_CODE_DEASSERT_INTC	0x26
 #define PCIE_MSG_CODE_DEASSERT_INTD	0x27
 
+/* Cpl. status of Complete; PCIe r7.0, sec 2.2.9.1 */
+#define PCIE_CPL_STS_SUCCESS		0x00 /* Successful Completion */
+
 #define PCI_BUS_BRIDGE_IO_WINDOW	0
 #define PCI_BUS_BRIDGE_MEM_WINDOW	1
 #define PCI_BUS_BRIDGE_PREF_MEM_WINDOW	2

-- 
2.34.1



From jacky_chou at aspeedtech.com  Mon Dec 15 17:50:05 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Tue, 16 Dec 2025 09:50:05 +0800
Subject: [PATCH v7 6/7] PCI: aspeed: Add ASPEED PCIe RC driver
In-Reply-To: <20251216-upstream_pcie_rc-v7-0-4aeb0f53c4ce@aspeedtech.com>
References: <20251216-upstream_pcie_rc-v7-0-4aeb0f53c4ce@aspeedtech.com>
Message-ID: <20251216-upstream_pcie_rc-v7-6-4aeb0f53c4ce@aspeedtech.com>

Introduce PCIe Root Complex driver for ASPEED SoCs. Support RC
initialization, reset, clock, IRQ domain, and MSI domain setup.
Implement platform-specific setup and register configuration for
ASPEED. And provide PCI config space read/write and INTx/MSI
interrupt handling.

Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
---
 drivers/pci/controller/Kconfig       |   16 +
 drivers/pci/controller/Makefile      |    1 +
 drivers/pci/controller/pcie-aspeed.c | 1111 ++++++++++++++++++++++++++++++++++
 3 files changed, 1128 insertions(+)

diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index c254d2b8bf17..5d34bb78bab2 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -58,6 +58,22 @@ config PCI_VERSATILE
 	bool "ARM Versatile PB PCI controller"
 	depends on ARCH_VERSATILE || COMPILE_TEST
 
+config PCIE_ASPEED
+	bool "ASPEED PCIe controller"
+	depends on ARCH_ASPEED || COMPILE_TEST
+	depends on OF
+	depends on PCI_MSI
+	select IRQ_MSI_LIB
+	help
+	  Enable this option to support the PCIe controller found on ASPEED
+	  SoCs.
+
+	  This driver provides initialization and management for PCIe
+	  Root Complex functionality, including INTx and MSI support.
+
+	  Select Y if your platform uses an ASPEED SoC and requires PCIe
+	  connectivity.
+
 config PCIE_BRCMSTB
 	tristate "Broadcom Brcmstb PCIe controller"
 	depends on ARCH_BRCMSTB || ARCH_BCM2835 || ARCH_BCMBCA || \
diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile
index 229929a945c2..ac8db283f0fe 100644
--- a/drivers/pci/controller/Makefile
+++ b/drivers/pci/controller/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_PCI_LOONGSON) += pci-loongson.o
 obj-$(CONFIG_PCIE_HISI_ERR) += pcie-hisi-error.o
 obj-$(CONFIG_PCIE_APPLE) += pcie-apple.o
 obj-$(CONFIG_PCIE_MT7621) += pcie-mt7621.o
+obj-$(CONFIG_PCIE_ASPEED) += pcie-aspeed.o
 
 # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
 obj-y				+= dwc/
diff --git a/drivers/pci/controller/pcie-aspeed.c b/drivers/pci/controller/pcie-aspeed.c
new file mode 100644
index 000000000000..3e1a39d1e648
--- /dev/null
+++ b/drivers/pci/controller/pcie-aspeed.c
@@ -0,0 +1,1111 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 Aspeed Technology Inc.
+ */
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqchip/irq-msi-lib.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_pci.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/phy/pcie.h>
+#include <linux/phy/phy.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#include "../pci.h"
+
+#define MAX_MSI_HOST_IRQS	64
+#define ASPEED_RESET_RC_WAIT_MS	10
+
+/* AST2600 AHBC Registers */
+#define ASPEED_AHBC_KEY			0x00
+#define  ASPEED_AHBC_UNLOCK_KEY			0xaeed1a03
+#define  ASPEED_AHBC_UNLOCK			0x01
+#define ASPEED_AHBC_ADDR_MAPPING	0x8c
+#define  ASPEED_PCIE_RC_MEMORY_EN		BIT(5)
+
+/* AST2600 H2X Controller Registers */
+#define ASPEED_H2X_INT_STS		0x08
+#define  ASPEED_PCIE_TX_IDLE_CLEAR		BIT(0)
+#define  ASPEED_PCIE_INTX_STS			GENMASK(3, 0)
+#define ASPEED_H2X_HOST_RX_DESC_DATA	0x0c
+#define ASPEED_H2X_TX_DESC0		0x10
+#define ASPEED_H2X_TX_DESC1		0x14
+#define ASPEED_H2X_TX_DESC2		0x18
+#define ASPEED_H2X_TX_DESC3		0x1c
+#define ASPEED_H2X_TX_DESC_DATA		0x20
+#define ASPEED_H2X_STS			0x24
+#define  ASPEED_PCIE_TX_IDLE			BIT(31)
+#define  ASPEED_PCIE_STATUS_OF_TX		GENMASK(25, 24)
+#define	ASPEED_PCIE_RC_H_TX_COMPLETE		BIT(25)
+#define  ASPEED_PCIE_TRIGGER_TX			BIT(0)
+#define ASPEED_H2X_AHB_ADDR_CONFIG0	0x60
+#define  ASPEED_AHB_REMAP_LO_ADDR(x)		(x & GENMASK(15, 4))
+#define  ASPEED_AHB_MASK_LO_ADDR(x)		FIELD_PREP(GENMASK(31, 20), x)
+#define ASPEED_H2X_AHB_ADDR_CONFIG1	0x64
+#define  ASPEED_AHB_REMAP_HI_ADDR(x)		(x)
+#define ASPEED_H2X_AHB_ADDR_CONFIG2	0x68
+#define  ASPEED_AHB_MASK_HI_ADDR(x)		(x)
+#define ASPEED_H2X_DEV_CTRL		0xc0
+#define  ASPEED_PCIE_RX_DMA_EN			BIT(9)
+#define  ASPEED_PCIE_RX_LINEAR			BIT(8)
+#define  ASPEED_PCIE_RX_MSI_SEL			BIT(7)
+#define  ASPEED_PCIE_RX_MSI_EN			BIT(6)
+#define  ASPEED_PCIE_UNLOCK_RX_BUFF		BIT(4)
+#define  ASPEED_PCIE_WAIT_RX_TLP_CLR		BIT(2)
+#define  ASPEED_PCIE_RC_RX_ENABLE		BIT(1)
+#define  ASPEED_PCIE_RC_ENABLE			BIT(0)
+#define ASPEED_H2X_DEV_STS		0xc8
+#define  ASPEED_PCIE_RC_RX_DONE_ISR		BIT(4)
+#define ASPEED_H2X_DEV_RX_DESC_DATA	0xcc
+#define ASPEED_H2X_DEV_RX_DESC1		0xd4
+#define ASPEED_H2X_DEV_TX_TAG		0xfc
+#define  ASPEED_RC_TLP_TX_TAG_NUM		0x28
+
+/* AST2700 H2X */
+#define ASPEED_H2X_CTRL			0x00
+#define  ASPEED_H2X_BRIDGE_EN			BIT(0)
+#define  ASPEED_H2X_BRIDGE_DIRECT_EN		BIT(1)
+#define ASPEED_H2X_CFGE_INT_STS		0x08
+#define  ASPEED_CFGE_TX_IDLE			BIT(0)
+#define  ASPEED_CFGE_RX_BUSY			BIT(1)
+#define ASPEED_H2X_CFGI_TLP		0x20
+#define  ASPEED_CFGI_BYTE_EN_MASK		GENMASK(19, 16)
+#define  ASPEED_CFGI_BYTE_EN(x) \
+		FIELD_PREP(ASPEED_CFGI_BYTE_EN_MASK, (x))
+#define ASPEED_H2X_CFGI_WR_DATA		0x24
+#define  ASPEED_CFGI_WRITE			BIT(20)
+#define ASPEED_H2X_CFGI_CTRL		0x28
+#define  ASPEED_CFGI_TLP_FIRE			BIT(0)
+#define ASPEED_H2X_CFGI_RET_DATA	0x2c
+#define ASPEED_H2X_CFGE_TLP_1ST		0x30
+#define ASPEED_H2X_CFGE_TLP_NEXT	0x34
+#define ASPEED_H2X_CFGE_CTRL		0x38
+#define  ASPEED_CFGE_TLP_FIRE			BIT(0)
+#define ASPEED_H2X_CFGE_RET_DATA	0x3c
+#define ASPEED_H2X_REMAP_PREF_ADDR	0x70
+#define  ASPEED_REMAP_PREF_ADDR_63_32(x)	(x)
+#define ASPEED_H2X_REMAP_PCI_ADDR_HI	0x74
+#define  ASPEED_REMAP_PCI_ADDR_63_32(x)		(((x) >> 32) & GENMASK(31, 0))
+#define ASPEED_H2X_REMAP_PCI_ADDR_LO	0x78
+#define  ASPEED_REMAP_PCI_ADDR_31_12(x)		((x) & GENMASK(31, 12))
+
+/* AST2700 SCU */
+#define ASPEED_SCU_60			0x60
+#define  ASPEED_RC_E2M_PATH_EN			BIT(0)
+#define  ASPEED_RC_H2XS_PATH_EN			BIT(16)
+#define  ASPEED_RC_H2XD_PATH_EN			BIT(17)
+#define  ASPEED_RC_H2XX_PATH_EN			BIT(18)
+#define  ASPEED_RC_UPSTREAM_MEM_EN		BIT(19)
+#define ASPEED_SCU_64			0x64
+#define  ASPEED_RC0_DECODE_DMA_BASE(x)		FIELD_PREP(GENMASK(7, 0), x)
+#define  ASPEED_RC0_DECODE_DMA_LIMIT(x)		FIELD_PREP(GENMASK(15, 8), x)
+#define  ASPEED_RC1_DECODE_DMA_BASE(x)		FIELD_PREP(GENMASK(23, 16), x)
+#define  ASPEED_RC1_DECODE_DMA_LIMIT(x)		FIELD_PREP(GENMASK(31, 24), x)
+#define ASPEED_SCU_70			0x70
+#define  ASPEED_DISABLE_EP_FUNC			0
+
+/* Macro to combine Fmt and Type into the 8-bit field */
+#define ASPEED_TLP_FMT_TYPE(fmt, type)	((((fmt) & 0x7) << 5) | ((type) & 0x1f))
+#define ASPEED_TLP_COMMON_FIELDS	GENMASK(31, 24)
+
+/* Completion status */
+#define CPL_STS(x)	FIELD_GET(GENMASK(15, 13), (x))
+/* TLP configuration type 0 and type 1 */
+#define CFG0_READ_FMTTYPE                                        \
+	FIELD_PREP(ASPEED_TLP_COMMON_FIELDS,                     \
+		   ASPEED_TLP_FMT_TYPE(PCIE_TLP_FMT_3DW_NO_DATA, \
+				       PCIE_TLP_TYPE_CFG0_RD))
+#define CFG0_WRITE_FMTTYPE                                    \
+	FIELD_PREP(ASPEED_TLP_COMMON_FIELDS,                  \
+		   ASPEED_TLP_FMT_TYPE(PCIE_TLP_FMT_3DW_DATA, \
+				       PCIE_TLP_TYPE_CFG0_WR))
+#define CFG1_READ_FMTTYPE                                        \
+	FIELD_PREP(ASPEED_TLP_COMMON_FIELDS,                     \
+		   ASPEED_TLP_FMT_TYPE(PCIE_TLP_FMT_3DW_NO_DATA, \
+				       PCIE_TLP_TYPE_CFG1_RD))
+#define CFG1_WRITE_FMTTYPE                                    \
+	FIELD_PREP(ASPEED_TLP_COMMON_FIELDS,                  \
+		   ASPEED_TLP_FMT_TYPE(PCIE_TLP_FMT_3DW_DATA, \
+				       PCIE_TLP_TYPE_CFG1_WR))
+#define CFG_PAYLOAD_SIZE		0x01 /* 1 DWORD */
+#define TLP_HEADER_BYTE_EN(x, y)	((GENMASK((x) - 1, 0) << ((y) % 4)))
+#define TLP_GET_VALUE(x, y, z)	\
+	(((x) >> ((((z) % 4)) * 8)) & GENMASK((8 * (y)) - 1, 0))
+#define TLP_SET_VALUE(x, y, z)	\
+	((((x) & GENMASK((8 * (y)) - 1, 0)) << ((((z) % 4)) * 8)))
+#define AST2600_TX_DESC1_VALUE		0x00002000
+#define AST2700_TX_DESC1_VALUE		0x00401000
+
+/**
+ * struct aspeed_pcie_port - PCIe port information
+ * @list: port list
+ * @pcie: pointer to PCIe host info
+ * @clk: pointer to the port clock gate
+ * @phy: pointer to PCIe PHY
+ * @perst: pointer to port reset control
+ * @slot: port slot
+ */
+struct aspeed_pcie_port {
+	struct list_head list;
+	struct aspeed_pcie *pcie;
+	struct clk *clk;
+	struct phy *phy;
+	struct reset_control *perst;
+	u32 slot;
+};
+
+/**
+ * struct aspeed_pcie - PCIe RC information
+ * @host: pointer to PCIe host bridge
+ * @dev: pointer to device structure
+ * @reg: PCIe host register base address
+ * @ahbc: pointer to AHHC register map
+ * @cfg: pointer to Aspeed PCIe configuration register map
+ * @platform: platform specific information
+ * @ports: list of PCIe ports
+ * @tx_tag: current TX tag for the port
+ * @root_bus_nr: bus number of the host bridge
+ * @h2xrst: pointer to H2X reset control
+ * @intx_domain: IRQ domain for INTx interrupts
+ * @msi_domain: IRQ domain for MSI interrupts
+ * @lock: mutex to protect MSI bitmap variable
+ * @msi_irq_in_use: bitmap to track used MSI host IRQs
+ * @clear_msi_twice: AST2700 workaround to clear MSI status twice
+ */
+struct aspeed_pcie {
+	struct pci_host_bridge *host;
+	struct device *dev;
+	void __iomem *reg;
+	struct regmap *ahbc;
+	struct regmap *cfg;
+	const struct aspeed_pcie_rc_platform *platform;
+	struct list_head ports;
+
+	u8 tx_tag;
+	u8 root_bus_nr;
+
+	struct reset_control *h2xrst;
+
+	struct irq_domain *intx_domain;
+	struct irq_domain *msi_domain;
+	struct mutex lock;
+	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_HOST_IRQS);
+
+	bool clear_msi_twice;		/* AST2700 workaround */
+};
+
+/**
+ * struct aspeed_pcie_rc_platform - Platform information
+ * @setup: initialization function
+ * @pcie_map_ranges: function to map PCIe address ranges
+ * @reg_intx_en: INTx enable register offset
+ * @reg_intx_sts: INTx status register offset
+ * @reg_msi_en: MSI enable register offset
+ * @reg_msi_sts: MSI enable register offset
+ * @msi_address: HW fixed MSI address
+ */
+struct aspeed_pcie_rc_platform {
+	int (*setup)(struct platform_device *pdev);
+	void (*pcie_map_ranges)(struct aspeed_pcie *pcie, u64 pci_addr);
+	int reg_intx_en;
+	int reg_intx_sts;
+	int reg_msi_en;
+	int reg_msi_sts;
+	u32 msi_address;
+};
+
+static void aspeed_pcie_intx_irq_ack(struct irq_data *d)
+{
+	struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(d);
+	int intx_en = pcie->platform->reg_intx_en;
+	u32 en;
+
+	en = readl(pcie->reg + intx_en);
+	en |= BIT(d->hwirq);
+	writel(en, pcie->reg + intx_en);
+}
+
+static void aspeed_pcie_intx_irq_mask(struct irq_data *d)
+{
+	struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(d);
+	int intx_en = pcie->platform->reg_intx_en;
+	u32 en;
+
+	en = readl(pcie->reg + intx_en);
+	en &= ~BIT(d->hwirq);
+	writel(en, pcie->reg + intx_en);
+}
+
+static void aspeed_pcie_intx_irq_unmask(struct irq_data *d)
+{
+	struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(d);
+	int intx_en = pcie->platform->reg_intx_en;
+	u32 en;
+
+	en = readl(pcie->reg + intx_en);
+	en |= BIT(d->hwirq);
+	writel(en, pcie->reg + intx_en);
+}
+
+static struct irq_chip aspeed_intx_irq_chip = {
+	.name = "INTx",
+	.irq_ack = aspeed_pcie_intx_irq_ack,
+	.irq_mask = aspeed_pcie_intx_irq_mask,
+	.irq_unmask = aspeed_pcie_intx_irq_unmask,
+};
+
+static int aspeed_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
+				irq_hw_number_t hwirq)
+{
+	irq_set_chip_and_handler(irq, &aspeed_intx_irq_chip, handle_level_irq);
+	irq_set_chip_data(irq, domain->host_data);
+	irq_set_status_flags(irq, IRQ_LEVEL);
+
+	return 0;
+}
+
+static const struct irq_domain_ops aspeed_intx_domain_ops = {
+	.map = aspeed_pcie_intx_map,
+};
+
+static irqreturn_t aspeed_pcie_intr_handler(int irq, void *dev_id)
+{
+	struct aspeed_pcie *pcie = dev_id;
+	const struct aspeed_pcie_rc_platform *platform = pcie->platform;
+	unsigned long status;
+	unsigned long intx;
+	u32 bit;
+	int i;
+
+	intx = FIELD_GET(ASPEED_PCIE_INTX_STS,
+			 readl(pcie->reg + platform->reg_intx_sts));
+	for_each_set_bit(bit, &intx, PCI_NUM_INTX)
+		generic_handle_domain_irq(pcie->intx_domain, bit);
+
+	for (i = 0; i < 2; i++) {
+		int msi_sts_reg = platform->reg_msi_sts + (i * 4);
+
+		status = readl(pcie->reg + msi_sts_reg);
+		writel(status, pcie->reg + msi_sts_reg);
+
+		/*
+		 * AST2700 workaround:
+		 * The MSI status needs to clear one more time.
+		 */
+		if (pcie->clear_msi_twice)
+			writel(status, pcie->reg + msi_sts_reg);
+
+		for_each_set_bit(bit, &status, 32) {
+			bit += (i * 32);
+			generic_handle_domain_irq(pcie->msi_domain, bit);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static u32 aspeed_pcie_get_bdf_offset(struct pci_bus *bus, unsigned int devfn,
+				      int where)
+{
+	return ((bus->number) << 24) | (PCI_SLOT(devfn) << 19) |
+		(PCI_FUNC(devfn) << 16) | (where & ~3);
+}
+
+static int aspeed_ast2600_conf(struct pci_bus *bus, unsigned int devfn,
+			       int where, int size, u32 *val, u32 fmt_type,
+			       bool write)
+{
+	struct aspeed_pcie *pcie = bus->sysdata;
+	u32 bdf_offset, cfg_val, isr;
+	int ret;
+
+	bdf_offset = aspeed_pcie_get_bdf_offset(bus, devfn, where);
+
+	/* Driver may set unlock RX buffer before triggering next TX config */
+	cfg_val = readl(pcie->reg + ASPEED_H2X_DEV_CTRL);
+	writel(ASPEED_PCIE_UNLOCK_RX_BUFF | cfg_val,
+	       pcie->reg + ASPEED_H2X_DEV_CTRL);
+
+	cfg_val = fmt_type | CFG_PAYLOAD_SIZE;
+	writel(cfg_val, pcie->reg + ASPEED_H2X_TX_DESC0);
+
+	cfg_val = AST2600_TX_DESC1_VALUE |
+		  FIELD_PREP(GENMASK(11, 8), pcie->tx_tag) |
+		  TLP_HEADER_BYTE_EN(size, where);
+	writel(cfg_val, pcie->reg + ASPEED_H2X_TX_DESC1);
+
+	writel(bdf_offset, pcie->reg + ASPEED_H2X_TX_DESC2);
+	writel(0, pcie->reg + ASPEED_H2X_TX_DESC3);
+	if (write)
+		writel(TLP_SET_VALUE(*val, size, where),
+		       pcie->reg + ASPEED_H2X_TX_DESC_DATA);
+
+	cfg_val = readl(pcie->reg + ASPEED_H2X_STS);
+	cfg_val |= ASPEED_PCIE_TRIGGER_TX;
+	writel(cfg_val, pcie->reg + ASPEED_H2X_STS);
+
+	ret = readl_poll_timeout(pcie->reg + ASPEED_H2X_STS, cfg_val,
+				 (cfg_val & ASPEED_PCIE_TX_IDLE), 0, 50);
+	if (ret) {
+		dev_err(pcie->dev,
+			"%02x:%02x.%d CR tx timeout sts: 0x%08x\n",
+			bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), cfg_val);
+		ret = PCIBIOS_SET_FAILED;
+		PCI_SET_ERROR_RESPONSE(val);
+		goto out;
+	}
+
+	cfg_val = readl(pcie->reg + ASPEED_H2X_INT_STS);
+	cfg_val |= ASPEED_PCIE_TX_IDLE_CLEAR;
+	writel(cfg_val, pcie->reg + ASPEED_H2X_INT_STS);
+
+	cfg_val = readl(pcie->reg + ASPEED_H2X_STS);
+	switch (cfg_val & ASPEED_PCIE_STATUS_OF_TX) {
+	case ASPEED_PCIE_RC_H_TX_COMPLETE:
+		ret = readl_poll_timeout(pcie->reg + ASPEED_H2X_DEV_STS, isr,
+					 (isr & ASPEED_PCIE_RC_RX_DONE_ISR), 0,
+					 50);
+		if (ret) {
+			dev_err(pcie->dev,
+				"%02x:%02x.%d CR rx timeout sts: 0x%08x\n",
+				bus->number, PCI_SLOT(devfn),
+				PCI_FUNC(devfn), isr);
+			ret = PCIBIOS_SET_FAILED;
+			PCI_SET_ERROR_RESPONSE(val);
+			goto out;
+		}
+		if (!write) {
+			cfg_val = readl(pcie->reg + ASPEED_H2X_DEV_RX_DESC1);
+			if (CPL_STS(cfg_val) != PCIE_CPL_STS_SUCCESS) {
+				ret = PCIBIOS_SET_FAILED;
+				PCI_SET_ERROR_RESPONSE(val);
+				goto out;
+			} else {
+				*val = readl(pcie->reg +
+					     ASPEED_H2X_DEV_RX_DESC_DATA);
+			}
+		}
+		break;
+	case ASPEED_PCIE_STATUS_OF_TX:
+		ret = PCIBIOS_SET_FAILED;
+		PCI_SET_ERROR_RESPONSE(val);
+		goto out;
+	default:
+		*val = readl(pcie->reg + ASPEED_H2X_HOST_RX_DESC_DATA);
+		break;
+	}
+
+	cfg_val = readl(pcie->reg + ASPEED_H2X_DEV_CTRL);
+	cfg_val |= ASPEED_PCIE_UNLOCK_RX_BUFF;
+	writel(cfg_val, pcie->reg + ASPEED_H2X_DEV_CTRL);
+
+	*val = TLP_GET_VALUE(*val, size, where);
+
+	ret = PCIBIOS_SUCCESSFUL;
+out:
+	cfg_val = readl(pcie->reg + ASPEED_H2X_DEV_STS);
+	writel(cfg_val, pcie->reg + ASPEED_H2X_DEV_STS);
+	pcie->tx_tag = (pcie->tx_tag + 1) % 0x8;
+	return ret;
+}
+
+static int aspeed_ast2600_rd_conf(struct pci_bus *bus, unsigned int devfn,
+				  int where, int size, u32 *val)
+{
+	/*
+	 * AST2600 has only one Root Port on the root bus.
+	 */
+	if (PCI_SLOT(devfn) != 8)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	return aspeed_ast2600_conf(bus, devfn, where, size, val,
+				   CFG0_READ_FMTTYPE, false);
+}
+
+static int aspeed_ast2600_child_rd_conf(struct pci_bus *bus, unsigned int devfn,
+					int where, int size, u32 *val)
+{
+	return aspeed_ast2600_conf(bus, devfn, where, size, val,
+				   CFG1_READ_FMTTYPE, false);
+}
+
+static int aspeed_ast2600_wr_conf(struct pci_bus *bus, unsigned int devfn,
+				  int where, int size, u32 val)
+{
+	/*
+	 * AST2600 has only one Root Port on the root bus.
+	 */
+	if (PCI_SLOT(devfn) != 8)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	return aspeed_ast2600_conf(bus, devfn, where, size, &val,
+				   CFG0_WRITE_FMTTYPE, true);
+}
+
+static int aspeed_ast2600_child_wr_conf(struct pci_bus *bus, unsigned int devfn,
+					int where, int size, u32 val)
+{
+	return aspeed_ast2600_conf(bus, devfn, where, size, &val,
+				   CFG1_WRITE_FMTTYPE, true);
+}
+
+static int aspeed_ast2700_config(struct pci_bus *bus, unsigned int devfn,
+				 int where, int size, u32 *val, bool write)
+{
+	struct aspeed_pcie *pcie = bus->sysdata;
+	u32 cfg_val;
+
+	cfg_val = ASPEED_CFGI_BYTE_EN(TLP_HEADER_BYTE_EN(size, where)) |
+		  (where & ~3);
+	if (write)
+		cfg_val |= ASPEED_CFGI_WRITE;
+	writel(cfg_val, pcie->reg + ASPEED_H2X_CFGI_TLP);
+
+	writel(TLP_SET_VALUE(*val, size, where),
+	       pcie->reg + ASPEED_H2X_CFGI_WR_DATA);
+	writel(ASPEED_CFGI_TLP_FIRE, pcie->reg + ASPEED_H2X_CFGI_CTRL);
+	*val = readl(pcie->reg + ASPEED_H2X_CFGI_RET_DATA);
+	*val = TLP_GET_VALUE(*val, size, where);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int aspeed_ast2700_child_config(struct pci_bus *bus, unsigned int devfn,
+				       int where, int size, u32 *val,
+				       bool write)
+{
+	struct aspeed_pcie *pcie = bus->sysdata;
+	u32 bdf_offset, status, cfg_val;
+	int ret;
+
+	bdf_offset = aspeed_pcie_get_bdf_offset(bus, devfn, where);
+
+	cfg_val = CFG_PAYLOAD_SIZE;
+	if (write)
+		cfg_val |= (bus->number == (pcie->root_bus_nr + 1)) ?
+				   CFG0_WRITE_FMTTYPE :
+				   CFG1_WRITE_FMTTYPE;
+	else
+		cfg_val |= (bus->number == (pcie->root_bus_nr + 1)) ?
+				   CFG0_READ_FMTTYPE :
+				   CFG1_READ_FMTTYPE;
+	writel(cfg_val, pcie->reg + ASPEED_H2X_CFGE_TLP_1ST);
+
+	cfg_val = AST2700_TX_DESC1_VALUE |
+		  FIELD_PREP(GENMASK(11, 8), pcie->tx_tag) |
+		  TLP_HEADER_BYTE_EN(size, where);
+	writel(cfg_val, pcie->reg + ASPEED_H2X_CFGE_TLP_NEXT);
+
+	writel(bdf_offset, pcie->reg + ASPEED_H2X_CFGE_TLP_NEXT);
+	if (write)
+		writel(TLP_SET_VALUE(*val, size, where),
+		       pcie->reg + ASPEED_H2X_CFGE_TLP_NEXT);
+	writel(ASPEED_CFGE_TX_IDLE | ASPEED_CFGE_RX_BUSY,
+	       pcie->reg + ASPEED_H2X_CFGE_INT_STS);
+	writel(ASPEED_CFGE_TLP_FIRE, pcie->reg + ASPEED_H2X_CFGE_CTRL);
+
+	ret = readl_poll_timeout(pcie->reg + ASPEED_H2X_CFGE_INT_STS, status,
+				 (status & ASPEED_CFGE_TX_IDLE), 0, 50);
+	if (ret) {
+		dev_err(pcie->dev,
+			"%02x:%02x.%d CR tx timeout sts: 0x%08x\n",
+			bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), status);
+		ret = PCIBIOS_SET_FAILED;
+		PCI_SET_ERROR_RESPONSE(val);
+		goto out;
+	}
+
+	ret = readl_poll_timeout(pcie->reg + ASPEED_H2X_CFGE_INT_STS, status,
+				 (status & ASPEED_CFGE_RX_BUSY), 0, 50);
+	if (ret) {
+		dev_err(pcie->dev,
+			"%02x:%02x.%d CR rx timeout sts: 0x%08x\n",
+			bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), status);
+		ret = PCIBIOS_SET_FAILED;
+		PCI_SET_ERROR_RESPONSE(val);
+		goto out;
+	}
+	*val = readl(pcie->reg + ASPEED_H2X_CFGE_RET_DATA);
+	*val = TLP_GET_VALUE(*val, size, where);
+
+	ret = PCIBIOS_SUCCESSFUL;
+out:
+	writel(status, pcie->reg + ASPEED_H2X_CFGE_INT_STS);
+	pcie->tx_tag = (pcie->tx_tag + 1) % 0xf;
+	return ret;
+}
+
+static int aspeed_ast2700_rd_conf(struct pci_bus *bus, unsigned int devfn,
+				  int where, int size, u32 *val)
+{
+	/*
+	 * AST2700 has only one Root Port on the root bus.
+	 */
+	if (devfn != 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	return aspeed_ast2700_config(bus, devfn, where, size, val, false);
+}
+
+static int aspeed_ast2700_child_rd_conf(struct pci_bus *bus, unsigned int devfn,
+					int where, int size, u32 *val)
+{
+	return aspeed_ast2700_child_config(bus, devfn, where, size, val, false);
+}
+
+static int aspeed_ast2700_wr_conf(struct pci_bus *bus, unsigned int devfn,
+				  int where, int size, u32 val)
+{
+	/*
+	 * AST2700 has only one Root Port on the root bus.
+	 */
+	if (devfn != 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	return aspeed_ast2700_config(bus, devfn, where, size, &val, true);
+}
+
+static int aspeed_ast2700_child_wr_conf(struct pci_bus *bus, unsigned int devfn,
+					int where, int size, u32 val)
+{
+	return aspeed_ast2700_child_config(bus, devfn, where, size, &val, true);
+}
+
+static struct pci_ops aspeed_ast2600_pcie_ops = {
+	.read = aspeed_ast2600_rd_conf,
+	.write = aspeed_ast2600_wr_conf,
+};
+
+static struct pci_ops aspeed_ast2600_pcie_child_ops = {
+	.read = aspeed_ast2600_child_rd_conf,
+	.write = aspeed_ast2600_child_wr_conf,
+};
+
+static struct pci_ops aspeed_ast2700_pcie_ops = {
+	.read = aspeed_ast2700_rd_conf,
+	.write = aspeed_ast2700_wr_conf,
+};
+
+static struct pci_ops aspeed_ast2700_pcie_child_ops = {
+	.read = aspeed_ast2700_child_rd_conf,
+	.write = aspeed_ast2700_child_wr_conf,
+};
+
+static void aspeed_irq_compose_msi_msg(struct irq_data *data,
+				       struct msi_msg *msg)
+{
+	struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(data);
+
+	msg->address_hi = 0;
+	msg->address_lo = pcie->platform->msi_address;
+	msg->data = data->hwirq;
+}
+
+static struct irq_chip aspeed_msi_bottom_irq_chip = {
+	.name = "ASPEED MSI",
+	.irq_compose_msi_msg = aspeed_irq_compose_msi_msg,
+};
+
+static int aspeed_irq_msi_domain_alloc(struct irq_domain *domain,
+				       unsigned int virq, unsigned int nr_irqs,
+				       void *args)
+{
+	struct aspeed_pcie *pcie = domain->host_data;
+	int bit;
+	int i;
+
+	guard(mutex)(&pcie->lock);
+
+	bit = bitmap_find_free_region(pcie->msi_irq_in_use, MAX_MSI_HOST_IRQS,
+				      get_count_order(nr_irqs));
+
+	if (bit < 0)
+		return -ENOSPC;
+
+	for (i = 0; i < nr_irqs; i++) {
+		irq_domain_set_info(domain, virq + i, bit + i,
+				    &aspeed_msi_bottom_irq_chip,
+				    domain->host_data, handle_simple_irq, NULL,
+				    NULL);
+	}
+
+	return 0;
+}
+
+static void aspeed_irq_msi_domain_free(struct irq_domain *domain,
+				       unsigned int virq, unsigned int nr_irqs)
+{
+	struct irq_data *data = irq_domain_get_irq_data(domain, virq);
+	struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(data);
+
+	guard(mutex)(&pcie->lock);
+
+	bitmap_release_region(pcie->msi_irq_in_use, data->hwirq,
+			      get_count_order(nr_irqs));
+}
+
+static const struct irq_domain_ops aspeed_msi_domain_ops = {
+	.alloc = aspeed_irq_msi_domain_alloc,
+	.free = aspeed_irq_msi_domain_free,
+};
+
+#define ASPEED_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS	| \
+				  MSI_FLAG_USE_DEF_CHIP_OPS	| \
+				  MSI_FLAG_NO_AFFINITY)
+
+#define ASPEED_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK	| \
+				   MSI_FLAG_MULTI_PCI_MSI	| \
+				   MSI_FLAG_PCI_MSIX)
+
+static const struct msi_parent_ops aspeed_msi_parent_ops = {
+	.required_flags		= ASPEED_MSI_FLAGS_REQUIRED,
+	.supported_flags	= ASPEED_MSI_FLAGS_SUPPORTED,
+	.bus_select_token	= DOMAIN_BUS_PCI_MSI,
+	.chip_flags		= MSI_CHIP_FLAG_SET_ACK,
+	.prefix			= "ASPEED-",
+	.init_dev_msi_info	= msi_lib_init_dev_msi_info,
+};
+
+static int aspeed_pcie_msi_init(struct aspeed_pcie *pcie)
+{
+	writel(~0, pcie->reg + pcie->platform->reg_msi_en);
+	writel(~0, pcie->reg + pcie->platform->reg_msi_en + 0x04);
+	writel(~0, pcie->reg + pcie->platform->reg_msi_sts);
+	writel(~0, pcie->reg + pcie->platform->reg_msi_sts + 0x04);
+
+	struct irq_domain_info info = {
+		.fwnode		= dev_fwnode(pcie->dev),
+		.ops		= &aspeed_msi_domain_ops,
+		.host_data	= pcie,
+		.size		= MAX_MSI_HOST_IRQS,
+	};
+
+	pcie->msi_domain = msi_create_parent_irq_domain(&info,
+							&aspeed_msi_parent_ops);
+	if (!pcie->msi_domain)
+		return dev_err_probe(pcie->dev, -ENOMEM,
+				     "failed to create MSI domain\n");
+
+	return 0;
+}
+
+static void aspeed_pcie_msi_free(struct aspeed_pcie *pcie)
+{
+	if (pcie->msi_domain) {
+		irq_domain_remove(pcie->msi_domain);
+		pcie->msi_domain = NULL;
+	}
+}
+
+static void aspeed_pcie_irq_domain_free(void *d)
+{
+	struct aspeed_pcie *pcie = d;
+
+	if (pcie->intx_domain) {
+		irq_domain_remove(pcie->intx_domain);
+		pcie->intx_domain = NULL;
+	}
+	aspeed_pcie_msi_free(pcie);
+}
+
+static int aspeed_pcie_init_irq_domain(struct aspeed_pcie *pcie)
+{
+	int ret;
+
+	pcie->intx_domain = irq_domain_add_linear(pcie->dev->of_node,
+						  PCI_NUM_INTX,
+						  &aspeed_intx_domain_ops,
+						  pcie);
+	if (!pcie->intx_domain) {
+		ret = dev_err_probe(pcie->dev, -ENOMEM,
+				    "failed to get INTx IRQ domain\n");
+		goto err;
+	}
+
+	writel(0, pcie->reg + pcie->platform->reg_intx_en);
+	writel(~0, pcie->reg + pcie->platform->reg_intx_sts);
+
+	ret = aspeed_pcie_msi_init(pcie);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	aspeed_pcie_irq_domain_free(pcie);
+	return ret;
+}
+
+static int aspeed_pcie_port_init(struct aspeed_pcie_port *port)
+{
+	struct aspeed_pcie *pcie = port->pcie;
+	struct device *dev = pcie->dev;
+	int ret;
+
+	ret = clk_prepare_enable(port->clk);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "failed to set clock for slot (%d)\n",
+				     port->slot);
+
+	ret = phy_init(port->phy);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "failed to init phy pcie for slot (%d)\n",
+				     port->slot);
+
+	ret = phy_set_mode_ext(port->phy, PHY_MODE_PCIE, PHY_MODE_PCIE_RC);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "failed to set phy mode for slot (%d)\n",
+				     port->slot);
+
+	reset_control_deassert(port->perst);
+	msleep(PCIE_RESET_CONFIG_WAIT_MS);
+
+	return 0;
+}
+
+static void aspeed_host_reset(struct aspeed_pcie *pcie)
+{
+	reset_control_assert(pcie->h2xrst);
+	mdelay(ASPEED_RESET_RC_WAIT_MS);
+	reset_control_deassert(pcie->h2xrst);
+}
+
+static void aspeed_pcie_map_ranges(struct aspeed_pcie *pcie)
+{
+	struct pci_host_bridge *bridge = pcie->host;
+	struct resource_entry *window;
+
+	resource_list_for_each_entry(window, &bridge->windows) {
+		u64 pci_addr;
+
+		if (resource_type(window->res) != IORESOURCE_MEM)
+			continue;
+
+		pci_addr = window->res->start - window->offset;
+		pcie->platform->pcie_map_ranges(pcie, pci_addr);
+		break;
+	}
+}
+
+static void aspeed_ast2600_pcie_map_ranges(struct aspeed_pcie *pcie,
+					  u64 pci_addr)
+{
+	u32 pci_addr_lo = pci_addr & GENMASK(31, 0);
+	u32 pci_addr_hi = (pci_addr >> 32) & GENMASK(31, 0);
+
+	pci_addr_lo >>= 16;
+	writel(ASPEED_AHB_REMAP_LO_ADDR(pci_addr_lo) |
+	       ASPEED_AHB_MASK_LO_ADDR(0xe00),
+	       pcie->reg + ASPEED_H2X_AHB_ADDR_CONFIG0);
+	writel(ASPEED_AHB_REMAP_HI_ADDR(pci_addr_hi),
+	       pcie->reg + ASPEED_H2X_AHB_ADDR_CONFIG1);
+	writel(ASPEED_AHB_MASK_HI_ADDR(~0),
+	       pcie->reg + ASPEED_H2X_AHB_ADDR_CONFIG2);
+}
+
+static int aspeed_ast2600_setup(struct platform_device *pdev)
+{
+	struct aspeed_pcie *pcie = platform_get_drvdata(pdev);
+	struct device *dev = pcie->dev;
+
+	pcie->ahbc = syscon_regmap_lookup_by_phandle(dev->of_node,
+						     "aspeed,ahbc");
+	if (IS_ERR(pcie->ahbc))
+		return dev_err_probe(dev, PTR_ERR(pcie->ahbc),
+				     "failed to map ahbc base\n");
+
+	aspeed_host_reset(pcie);
+
+	regmap_write(pcie->ahbc, ASPEED_AHBC_KEY, ASPEED_AHBC_UNLOCK_KEY);
+	regmap_update_bits(pcie->ahbc, ASPEED_AHBC_ADDR_MAPPING,
+			   ASPEED_PCIE_RC_MEMORY_EN, ASPEED_PCIE_RC_MEMORY_EN);
+	regmap_write(pcie->ahbc, ASPEED_AHBC_KEY, ASPEED_AHBC_UNLOCK);
+
+	writel(ASPEED_H2X_BRIDGE_EN, pcie->reg + ASPEED_H2X_CTRL);
+
+	writel(ASPEED_PCIE_RX_DMA_EN | ASPEED_PCIE_RX_LINEAR |
+	       ASPEED_PCIE_RX_MSI_SEL | ASPEED_PCIE_RX_MSI_EN |
+	       ASPEED_PCIE_WAIT_RX_TLP_CLR | ASPEED_PCIE_RC_RX_ENABLE |
+	       ASPEED_PCIE_RC_ENABLE,
+	       pcie->reg + ASPEED_H2X_DEV_CTRL);
+
+	writel(ASPEED_RC_TLP_TX_TAG_NUM, pcie->reg + ASPEED_H2X_DEV_TX_TAG);
+
+	pcie->host->ops = &aspeed_ast2600_pcie_ops;
+	pcie->host->child_ops = &aspeed_ast2600_pcie_child_ops;
+
+	return 0;
+}
+
+static void aspeed_ast2700_pcie_map_ranges(struct aspeed_pcie *pcie,
+					  u64 pci_addr)
+{
+	writel(ASPEED_REMAP_PCI_ADDR_31_12(pci_addr),
+		pcie->reg + ASPEED_H2X_REMAP_PCI_ADDR_LO);
+	writel(ASPEED_REMAP_PCI_ADDR_63_32(pci_addr),
+		pcie->reg + ASPEED_H2X_REMAP_PCI_ADDR_HI);
+}
+
+static int aspeed_ast2700_setup(struct platform_device *pdev)
+{
+	struct aspeed_pcie *pcie = platform_get_drvdata(pdev);
+	struct device *dev = pcie->dev;
+
+	pcie->cfg = syscon_regmap_lookup_by_phandle(dev->of_node,
+						    "aspeed,pciecfg");
+	if (IS_ERR(pcie->cfg))
+		return dev_err_probe(dev, PTR_ERR(pcie->cfg),
+				     "failed to map pciecfg base\n");
+
+	regmap_update_bits(pcie->cfg, ASPEED_SCU_60,
+			   ASPEED_RC_E2M_PATH_EN | ASPEED_RC_H2XS_PATH_EN |
+			   ASPEED_RC_H2XD_PATH_EN | ASPEED_RC_H2XX_PATH_EN |
+			   ASPEED_RC_UPSTREAM_MEM_EN,
+			   ASPEED_RC_E2M_PATH_EN | ASPEED_RC_H2XS_PATH_EN |
+			   ASPEED_RC_H2XD_PATH_EN | ASPEED_RC_H2XX_PATH_EN |
+			   ASPEED_RC_UPSTREAM_MEM_EN);
+	regmap_write(pcie->cfg, ASPEED_SCU_64,
+		     ASPEED_RC0_DECODE_DMA_BASE(0) |
+		     ASPEED_RC0_DECODE_DMA_LIMIT(0xff) |
+		     ASPEED_RC1_DECODE_DMA_BASE(0) |
+		     ASPEED_RC1_DECODE_DMA_LIMIT(0xff));
+	regmap_write(pcie->cfg, ASPEED_SCU_70, ASPEED_DISABLE_EP_FUNC);
+
+	aspeed_host_reset(pcie);
+
+	writel(0, pcie->reg + ASPEED_H2X_CTRL);
+	writel(ASPEED_H2X_BRIDGE_EN | ASPEED_H2X_BRIDGE_DIRECT_EN,
+	       pcie->reg + ASPEED_H2X_CTRL);
+
+	/* Prepare for 64-bit BAR pref */
+	writel(ASPEED_REMAP_PREF_ADDR_63_32(0x3),
+	       pcie->reg + ASPEED_H2X_REMAP_PREF_ADDR);
+
+	pcie->host->ops = &aspeed_ast2700_pcie_ops;
+	pcie->host->child_ops = &aspeed_ast2700_pcie_child_ops;
+	pcie->clear_msi_twice = true;
+
+	return 0;
+}
+
+static void aspeed_pcie_reset_release(void *d)
+{
+	struct reset_control *perst = d;
+
+	if (!perst)
+		return;
+
+	reset_control_put(perst);
+}
+
+static int aspeed_pcie_parse_port(struct aspeed_pcie *pcie,
+				  struct device_node *node,
+				  int slot)
+{
+	struct aspeed_pcie_port *port;
+	struct device *dev = pcie->dev;
+	int ret;
+
+	port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
+	if (!port)
+		return -ENOMEM;
+
+	port->clk = devm_get_clk_from_child(dev, node, NULL);
+	if (IS_ERR(port->clk))
+		return dev_err_probe(dev, PTR_ERR(port->clk),
+				     "failed to get pcie%d clock\n", slot);
+
+	port->phy = devm_of_phy_get(dev, node, NULL);
+	if (IS_ERR(port->phy))
+		return dev_err_probe(dev, PTR_ERR(port->phy),
+				     "failed to get phy pcie%d\n", slot);
+
+	port->perst = of_reset_control_get_exclusive(node, "perst");
+	if (IS_ERR(port->perst))
+		return dev_err_probe(dev, PTR_ERR(port->perst),
+				     "failed to get pcie%d reset control\n",
+				     slot);
+	ret = devm_add_action_or_reset(dev, aspeed_pcie_reset_release,
+				       port->perst);
+	if (ret)
+		return ret;
+	reset_control_assert(port->perst);
+
+	port->slot = slot;
+	port->pcie = pcie;
+
+	INIT_LIST_HEAD(&port->list);
+	list_add_tail(&port->list, &pcie->ports);
+
+	ret = aspeed_pcie_port_init(port);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int aspeed_pcie_parse_dt(struct aspeed_pcie *pcie)
+{
+	struct device *dev = pcie->dev;
+	struct device_node *node = dev->of_node;
+	int ret;
+
+	for_each_available_child_of_node_scoped(node, child) {
+		int slot;
+		const char *type;
+
+		ret = of_property_read_string(child, "device_type", &type);
+		if (ret || strcmp(type, "pci"))
+			continue;
+
+		ret = of_pci_get_devfn(child);
+		if (ret < 0)
+			return dev_err_probe(dev, ret,
+					     "failed to parse devfn\n");
+
+		slot = PCI_SLOT(ret);
+
+		ret = aspeed_pcie_parse_port(pcie, child, slot);
+		if (ret)
+			return ret;
+	}
+
+	if (list_empty(&pcie->ports))
+		return dev_err_probe(dev, -ENODEV,
+				     "No PCIe port found in DT\n");
+
+	return 0;
+}
+
+static int aspeed_pcie_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct pci_host_bridge *host;
+	struct aspeed_pcie *pcie;
+	struct resource_entry *entry;
+	const struct aspeed_pcie_rc_platform *md;
+	int irq, ret;
+
+	md = of_device_get_match_data(dev);
+	if (!md)
+		return -ENODEV;
+
+	host = devm_pci_alloc_host_bridge(dev, sizeof(*pcie));
+	if (!host)
+		return -ENOMEM;
+
+	pcie = pci_host_bridge_priv(host);
+	pcie->dev = dev;
+	pcie->tx_tag = 0;
+	platform_set_drvdata(pdev, pcie);
+
+	pcie->platform = md;
+	pcie->host = host;
+	INIT_LIST_HEAD(&pcie->ports);
+
+	/* Get root bus num for cfg command to decide tlp type 0 or type 1 */
+	entry = resource_list_first_type(&host->windows, IORESOURCE_BUS);
+	if (entry)
+		pcie->root_bus_nr = entry->res->start;
+
+	pcie->reg = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(pcie->reg))
+		return PTR_ERR(pcie->reg);
+
+	pcie->h2xrst = devm_reset_control_get_exclusive(dev, "h2x");
+	if (IS_ERR(pcie->h2xrst))
+		return dev_err_probe(dev, PTR_ERR(pcie->h2xrst),
+				     "failed to get h2x reset\n");
+
+	ret = devm_mutex_init(dev, &pcie->lock);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to init mutex\n");
+
+	ret = pcie->platform->setup(pdev);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to setup PCIe RC\n");
+
+	aspeed_pcie_map_ranges(pcie);
+
+	ret = aspeed_pcie_parse_dt(pcie);
+	if (ret)
+		return ret;
+
+	host->sysdata = pcie;
+
+	ret = aspeed_pcie_init_irq_domain(pcie);
+	if (ret)
+		return ret;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	ret = devm_add_action_or_reset(dev, aspeed_pcie_irq_domain_free, pcie);
+	if (ret)
+		return ret;
+
+	ret = devm_request_irq(dev, irq, aspeed_pcie_intr_handler, IRQF_SHARED,
+			       dev_name(dev), pcie);
+	if (ret)
+		return ret;
+
+	return pci_host_probe(host);
+}
+
+static const struct aspeed_pcie_rc_platform pcie_rc_ast2600 = {
+	.setup = aspeed_ast2600_setup,
+	.pcie_map_ranges = aspeed_ast2600_pcie_map_ranges,
+	.reg_intx_en = 0xc4,
+	.reg_intx_sts = 0xc8,
+	.reg_msi_en = 0xe0,
+	.reg_msi_sts = 0xe8,
+	.msi_address = 0x1e77005c,
+};
+
+static const struct aspeed_pcie_rc_platform pcie_rc_ast2700 = {
+	.setup = aspeed_ast2700_setup,
+	.pcie_map_ranges = aspeed_ast2700_pcie_map_ranges,
+	.reg_intx_en = 0x40,
+	.reg_intx_sts = 0x48,
+	.reg_msi_en = 0x50,
+	.reg_msi_sts = 0x58,
+	.msi_address = 0x000000f0,
+};
+
+static const struct of_device_id aspeed_pcie_of_match[] = {
+	{ .compatible = "aspeed,ast2600-pcie", .data = &pcie_rc_ast2600 },
+	{ .compatible = "aspeed,ast2700-pcie", .data = &pcie_rc_ast2700 },
+	{}
+};
+
+static struct platform_driver aspeed_pcie_driver = {
+	.driver = {
+		.name = "aspeed-pcie",
+		.of_match_table = aspeed_pcie_of_match,
+		.suppress_bind_attrs = true,
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
+	},
+	.probe = aspeed_pcie_probe,
+};
+
+builtin_platform_driver(aspeed_pcie_driver);
+
+MODULE_AUTHOR("Jacky Chou <jacky_chou at aspeedtech.com>");
+MODULE_DESCRIPTION("ASPEED PCIe Root Complex");
+MODULE_LICENSE("GPL");

-- 
2.34.1



From jacky_chou at aspeedtech.com  Mon Dec 15 17:50:06 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Tue, 16 Dec 2025 09:50:06 +0800
Subject: [PATCH v7 7/7] MAINTAINERS: Add ASPEED PCIe RC driver
In-Reply-To: <20251216-upstream_pcie_rc-v7-0-4aeb0f53c4ce@aspeedtech.com>
References: <20251216-upstream_pcie_rc-v7-0-4aeb0f53c4ce@aspeedtech.com>
Message-ID: <20251216-upstream_pcie_rc-v7-7-4aeb0f53c4ce@aspeedtech.com>

Add maintainer for ASPEED PCIe RC driver.

Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
---
 MAINTAINERS | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index aff3e162180d..c327ea375746 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3900,6 +3900,18 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/media/aspeed,video-engine.yaml
 F:	drivers/media/platform/aspeed/
 
+ASPEED PCIE CONTROLLER DRIVER
+M:	Jacky Chou <jacky_chou at aspeedtech.com>
+L:	linux-aspeed at lists.ozlabs.org (moderated for non-subscribers)
+L:	linux-pci at vger.kernel.org
+L:	linux-phy at lists.infradead.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/pci/aspeed,ast2600-pcie.yaml
+F:	Documentation/devicetree/bindings/phy/aspeed,ast2600-pcie-phy.yaml
+F:	drivers/pci/controller/pcie-aspeed.c
+F:	drivers/phy/aspeed/Kconfig
+F:	drivers/phy/aspeed/pcie-phy-aspeed.c
+
 ASUS EC HARDWARE MONITOR DRIVER
 M:	Eugene Shalygin <eugene.shalygin at gmail.com>
 L:	linux-hwmon at vger.kernel.org

-- 
2.34.1



From peng.fan at oss.nxp.com  Mon Dec 15 17:50:58 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Tue, 16 Dec 2025 09:50:58 +0800
Subject: [PATCH v4 0/5] remoteproc: imx_rproc: Support i.MX95
Message-ID: <20251216-imx95-rproc-2025-12-15-v4-0-bf1064ea8daf@nxp.com>

This patchset is pick up a previous patchset [1] with rebased on
next-20251030, and some changes applied.
 - Add runtime ops to separate cpu ops and lmm ops
 - added more comments
 - moved some check imx_sm_rproc_detect_mode() from imx_rproc_sm_prepare().

No changes to the dt-binding patch, so R-b/A-b are kept.
More info could be found in commit message of each patch and below.

[1]https://lore.kernel.org/linux-remoteproc/20250821-imx95-rproc-1-v5-0-e93191dfac51 at nxp.com/

i.MX95 features a Cortex-M33 core, six Cortex-A55 cores, and
one Cortex-M7 core. The System Control Management Interface(SCMI)
firmware runs on the M33 core. The i.MX95 SCMI firmware named System
Manager(SM) includes vendor extension protocols, Logical Machine
Management(LMM) protocol and CPU protocol and etc.

There are three cases for M7:
(1) M7 in a separate Logical Machine(LM) that Linux couldn't control it.
(2) M7 in a separate Logical Machine that Linux could control it using
    LMM protocol
(3) M7 runs in same Logical Machine as A55, so Linux could control it
    using CPU protocol

In patch 3, Use LMM and CPU protocol to manage M7. More info could be
found in the patch commit log
    Current setup relies on pre-Linux software(U-Boot) to do
M7 TCM ECC initialization. In future, we could add the support in Linux

Patchset was tested with below boot images when the patchset based on next-20251030:
imx-boot-variant-rpmsg-imx95-19x19-lpddr5-evk-sd.bin-flash_lpboot_sm_a55 (Use LMM protocol)
imx-boot-variant-alt-imx95-19x19-lpddr5-evk-sd.bin-flash_alt (Use CPU protocol)
imx-boot-imx95-19x19-lpddr5-evk-sd.bin-flash_all (M7 not under A55 control)

Also tested i.MX8MP/8ULP-EVK.

Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
Changes in V4:
- Rebased to 6.19-rc1 to resolve conflicts.
- Address Frank's comment patch 4 regarding "if (ret != 0)" -> "if (ret)"
- Link to v3: https://lore.kernel.org/linux-remoteproc/20251122-imx95-rproc-2025-11-20-v3-0-9ae6ee619a78 at nxp.com/#t

Changes in v3:
- Add R-b for patch 2,3,5
- Patch 4:
  Rename imx_rproc_ops_sm to imx_rproc_ops_sm_lmm.
  Add more comments in code
  Simplify if check in imx_rproc_sm_lmm_prepare()
  Update commit log
  Use dev_err for failure path
- Link to v2: https://lore.kernel.org/linux-remoteproc/20251031-imx95-rproc-2025-10-31-v2-0-758b2e547a55 at nxp.com/T/#t

Changes in v2:
- Patch 2: Change to const pointer for ops, update commit log and add R-b from Frank
- Patch 3: New patch, introduce prepare ops
- Patch 4: Rename imx_rproc_sm_prepare to imx_rproc_sm_lmm_prepare
           drop IMX_RPROC_FLAGS_SM_CPU_OP and IMX_RPROC_FLAGS_SM_LMM_OP
           Add a bool for dcfg->lmid and info->lmid check.
           Provide separate plat ops for lmm and cpu setup.
           Move LM permission check to a separate function.
- Patch 5: Drop macro IMX95_M7_CPUID and IMX95_M7_LMID
- Link to v1: https://lore.kernel.org/r/20251028-imx95-rproc-2025-10-28-v1-0-ce9e7db9edcb at nxp.com

---
Peng Fan (5):
      dt-bindings: remoteproc: fsl,imx-rproc: Add support for i.MX95
      remoteproc: imx_rproc: Add runtime ops copy to support dynamic behavior
      remoteproc: imx_rproc: Introduce prepare ops for imx_rproc_dcfg
      remoteproc: imx_rproc: Add support for System Manager API
      remoteproc: imx_rproc: Add support for i.MX95

 .../bindings/remoteproc/fsl,imx-rproc.yaml         |   1 +
 drivers/remoteproc/Kconfig                         |   2 +
 drivers/remoteproc/imx_rproc.c                     | 245 +++++++++++++++++++--
 drivers/remoteproc/imx_rproc.h                     |   4 +
 4 files changed, 239 insertions(+), 13 deletions(-)
---
base-commit: 4a5663c04bb679631985a15efab774da58c37815
change-id: 20251215-imx95-rproc-2025-12-15-1200ef764ca2

Best regards,
-- 
Peng Fan <peng.fan at nxp.com>



From peng.fan at oss.nxp.com  Mon Dec 15 17:50:59 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Tue, 16 Dec 2025 09:50:59 +0800
Subject: [PATCH v4 1/5] dt-bindings: remoteproc: fsl,imx-rproc: Add support
 for i.MX95
In-Reply-To: <20251216-imx95-rproc-2025-12-15-v4-0-bf1064ea8daf@nxp.com>
References: <20251216-imx95-rproc-2025-12-15-v4-0-bf1064ea8daf@nxp.com>
Message-ID: <20251216-imx95-rproc-2025-12-15-v4-1-bf1064ea8daf@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

Add compatible string for the Cortex-M7 core in i.MX95

Reviewed-by: Frank Li <Frank.Li at nxp.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
index 57d75acb0b5e52ca49d1361176fdebc18a0bf7a2..ce8ec0119469c8fc0979a192b6e3d3a03108d7d2 100644
--- a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
+++ b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
@@ -28,6 +28,7 @@ properties:
       - fsl,imx8qxp-cm4
       - fsl,imx8ulp-cm33
       - fsl,imx93-cm33
+      - fsl,imx95-cm7
 
   clocks:
     maxItems: 1

-- 
2.37.1



From peng.fan at oss.nxp.com  Mon Dec 15 17:51:00 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Tue, 16 Dec 2025 09:51:00 +0800
Subject: [PATCH v4 2/5] remoteproc: imx_rproc: Add runtime ops copy to
 support dynamic behavior
In-Reply-To: <20251216-imx95-rproc-2025-12-15-v4-0-bf1064ea8daf@nxp.com>
References: <20251216-imx95-rproc-2025-12-15-v4-0-bf1064ea8daf@nxp.com>
Message-ID: <20251216-imx95-rproc-2025-12-15-v4-2-bf1064ea8daf@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

Structure imx_rproc_dcfg contains a const pointer to imx_rproc_plat_ops,
which defines the start/stop/detect_mode operations for a remote processor.
To preserve the const correctness of the static configuration while
allowing runtime modification of ops behavior, introduce a new
imx_rproc_plat_ops member in struct imx_rproc named `ops`.

During initialization, dcfg->ops is assigned to priv->ops.
Enable the driver to safely override ops at runtime without affecting the
original const configuration.

Improve flexibility for platforms that require dynamic operation switching
(e.g. i.MX95 Logical Machine ops and CPU ops).

Reviewed-by: Frank Li <Frank.Li at nxp.com>
Reviewed-by: Daniel Baluta <daniel.baluta at nxp.com>
Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 drivers/remoteproc/imx_rproc.c | 27 +++++++++++++--------------
 1 file changed, 13 insertions(+), 14 deletions(-)

diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index 3be8790c14a2ccc789dd40508ec274000ec09978..6e50a9abd0a2c68c79909beb653567e0592ca2cb 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -116,6 +116,7 @@ struct imx_rproc {
 	u32				entry;		/* cpu start address */
 	u32				core_index;
 	struct dev_pm_domain_list	*pd_list;
+	const struct imx_rproc_plat_ops	*ops;
 };
 
 static const struct imx_rproc_att imx_rproc_att_imx93[] = {
@@ -315,7 +316,6 @@ static int imx_rproc_scu_api_start(struct rproc *rproc)
 static int imx_rproc_start(struct rproc *rproc)
 {
 	struct imx_rproc *priv = rproc->priv;
-	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
 	struct device *dev = priv->dev;
 	int ret;
 
@@ -323,10 +323,10 @@ static int imx_rproc_start(struct rproc *rproc)
 	if (ret)
 		return ret;
 
-	if (!dcfg->ops || !dcfg->ops->start)
+	if (!priv->ops || !priv->ops->start)
 		return -EOPNOTSUPP;
 
-	ret = dcfg->ops->start(rproc);
+	ret = priv->ops->start(rproc);
 	if (ret)
 		dev_err(dev, "Failed to enable remote core!\n");
 
@@ -372,14 +372,13 @@ static int imx_rproc_scu_api_stop(struct rproc *rproc)
 static int imx_rproc_stop(struct rproc *rproc)
 {
 	struct imx_rproc *priv = rproc->priv;
-	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
 	struct device *dev = priv->dev;
 	int ret;
 
-	if (!dcfg->ops || !dcfg->ops->stop)
+	if (!priv->ops || !priv->ops->stop)
 		return -EOPNOTSUPP;
 
-	ret = dcfg->ops->stop(rproc);
+	ret = priv->ops->stop(rproc);
 	if (ret)
 		dev_err(dev, "Failed to stop remote core\n");
 	else
@@ -584,12 +583,11 @@ static int imx_rproc_scu_api_detach(struct rproc *rproc)
 static int imx_rproc_detach(struct rproc *rproc)
 {
 	struct imx_rproc *priv = rproc->priv;
-	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
 
-	if (!dcfg->ops || !dcfg->ops->detach)
+	if (!priv->ops || !priv->ops->detach)
 		return -EOPNOTSUPP;
 
-	return dcfg->ops->detach(rproc);
+	return priv->ops->detach(rproc);
 }
 
 static struct resource_table *imx_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz)
@@ -979,18 +977,16 @@ static int imx_rproc_scu_api_detect_mode(struct rproc *rproc)
 
 static int imx_rproc_detect_mode(struct imx_rproc *priv)
 {
-	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
-
 	/*
 	 * To i.MX{7,8} ULP, Linux is under control of RTOS, no need
-	 * dcfg->ops or dcfg->ops->detect_mode, it is state RPROC_DETACHED.
+	 * priv->ops or priv->ops->detect_mode, it is state RPROC_DETACHED.
 	 */
-	if (!dcfg->ops || !dcfg->ops->detect_mode) {
+	if (!priv->ops || !priv->ops->detect_mode) {
 		priv->rproc->state = RPROC_DETACHED;
 		return 0;
 	}
 
-	return dcfg->ops->detect_mode(priv->rproc);
+	return priv->ops->detect_mode(priv->rproc);
 }
 
 static int imx_rproc_sys_off_handler(struct sys_off_data *data)
@@ -1040,6 +1036,9 @@ static int imx_rproc_probe(struct platform_device *pdev)
 	priv->dcfg = dcfg;
 	priv->dev = dev;
 
+	if (dcfg->ops)
+		priv->ops = dcfg->ops;
+
 	dev_set_drvdata(dev, rproc);
 	priv->workqueue = create_workqueue(dev_name(dev));
 	if (!priv->workqueue) {

-- 
2.37.1



From peng.fan at oss.nxp.com  Mon Dec 15 17:51:01 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Tue, 16 Dec 2025 09:51:01 +0800
Subject: [PATCH v4 3/5] remoteproc: imx_rproc: Introduce prepare ops for
 imx_rproc_dcfg
In-Reply-To: <20251216-imx95-rproc-2025-12-15-v4-0-bf1064ea8daf@nxp.com>
References: <20251216-imx95-rproc-2025-12-15-v4-0-bf1064ea8daf@nxp.com>
Message-ID: <20251216-imx95-rproc-2025-12-15-v4-3-bf1064ea8daf@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

Allow each platform to provide its own prepare operations, preparing
for i.MX95 LMM and CPU ops support.

No functional changes.

Reviewed-by: Daniel Baluta <daniel.baluta at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 drivers/remoteproc/imx_rproc.c | 5 +++++
 drivers/remoteproc/imx_rproc.h | 1 +
 2 files changed, 6 insertions(+)

diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index 6e50a9abd0a2c68c79909beb653567e0592ca2cb..35585235c683e6327c3e6db65d5d33253ffba327 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -527,6 +527,11 @@ static int imx_rproc_prepare(struct rproc *rproc)
 		rproc_coredump_add_segment(rproc, da, resource_size(&res));
 		rproc_add_carveout(rproc, mem);
 	}
+
+	if (priv->ops && priv->ops->prepare)
+		return priv->ops->prepare(rproc);
+
+	return 0;
 }
 
 static int imx_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h
index 1b2d9f4d6d19dcdc215be97f7e2ab3488281916a..37417568a0ade2ae4d6a4e3d0f139ea52b185254 100644
--- a/drivers/remoteproc/imx_rproc.h
+++ b/drivers/remoteproc/imx_rproc.h
@@ -24,6 +24,7 @@ struct imx_rproc_plat_ops {
 	int (*stop)(struct rproc *rproc);
 	int (*detach)(struct rproc *rproc);
 	int (*detect_mode)(struct rproc *rproc);
+	int (*prepare)(struct rproc *rproc);
 };
 
 struct imx_rproc_dcfg {

-- 
2.37.1



From peng.fan at oss.nxp.com  Mon Dec 15 17:51:02 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Tue, 16 Dec 2025 09:51:02 +0800
Subject: [PATCH v4 4/5] remoteproc: imx_rproc: Add support for System
 Manager API
In-Reply-To: <20251216-imx95-rproc-2025-12-15-v4-0-bf1064ea8daf@nxp.com>
References: <20251216-imx95-rproc-2025-12-15-v4-0-bf1064ea8daf@nxp.com>
Message-ID: <20251216-imx95-rproc-2025-12-15-v4-4-bf1064ea8daf@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

i.MX95 features a Cortex-M33 core, six Cortex-A55 cores, and
one Cortex-M7 core. The System Control Management Interface(SCMI)
firmware runs on the M33 core. The i.MX95 SCMI firmware named System
Manager(SM) includes vendor extension protocols, Logical Machine
Management(LMM) protocol and CPU protocol and etc.

Depending on SM configuration, M7 can be used as follows:
 (1) M7 in a separate Logical Machine (LM) from A55 cores, that Linux
     can't control
 (2) M7 in a separate LM from A55 cores that Linux can control using LMM
     protocol.
 (3) M7 runs in same Logical Machine as A55 cores, so Linux can control it
     using CPU protocol

So extend the driver to using LMM and CPU protocol to manage the M7 core.
 - Compare linux LM ID(got using scmi_imx_lmm_info) and M7 LM ID(the ID
   is fixed as 1 in SM firmware if M7 is in a separate LM),
   if Linux LM ID equals M7 LM ID(linux and M7 in same LM), use CPU
   protocol to start/stop. Otherwise, use LMM protocol to start/stop.
   Whether using CPU or LMM protocol to start/stop, the M7 status
   detection could use CPU protocol to detect started or not. So
   in imx_rproc_detect_mode, use scmi_imx_cpu_started to check the
   status of M7.
 - For above case (1) and (2), Use SCMI_IMX_LMM_POWER_ON to detect whether
   the M7 LM is under control of A55 LM.
 - For above case , after using SCMI_IMX_LMM_POWER_ON to check
   permission, SCMI_IMX_LMM_SHUTDOWN API should be called to shutdown
   the M7 LM to save power only when M7 LM is going to be started by
   remoteproc framework. Otherwise bypass SCMI_IMX_LMM_SHUTDOWN API if
   M7 LM is started before booting Linux.

Current setup relies on pre-Linux software(U-Boot) to do M7 TCM ECC
initialization. In future, we could add the support in Linux to decouple
U-Boot and Linux.

Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 drivers/remoteproc/Kconfig     |   2 +
 drivers/remoteproc/imx_rproc.c | 193 +++++++++++++++++++++++++++++++++++++++++
 drivers/remoteproc/imx_rproc.h |   3 +
 3 files changed, 198 insertions(+)

diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 48a0d3a69ed08057716f1e7ea950899f60bbe0cf..ee54436fea5ad08a9c198ce74d44ce7a9aa206de 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -27,6 +27,8 @@ config IMX_REMOTEPROC
 	tristate "i.MX remoteproc support"
 	depends on ARCH_MXC
 	depends on HAVE_ARM_SMCCC
+	depends on IMX_SCMI_CPU_DRV || !IMX_SCMI_CPU_DRV
+	depends on IMX_SCMI_LMM_DRV || !IMX_SCMI_LMM_DRV
 	select MAILBOX
 	help
 	  Say y here to support iMX's remote processors via the remote
diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index 35585235c683e6327c3e6db65d5d33253ffba327..55e555f2b5dd63e7d82996437e792a8152c91521 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -8,6 +8,7 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/firmware/imx/sci.h>
+#include <linux/firmware/imx/sm.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/mailbox_client.h>
@@ -22,6 +23,7 @@
 #include <linux/reboot.h>
 #include <linux/regmap.h>
 #include <linux/remoteproc.h>
+#include <linux/scmi_imx_protocol.h>
 #include <linux/workqueue.h>
 
 #include "imx_rproc.h"
@@ -92,8 +94,12 @@ struct imx_rproc_mem {
 #define ATT_CORE_MASK   0xffff
 #define ATT_CORE(I)     BIT((I))
 
+/* Linux has permission to handle the Logical Machine of remote cores */
+#define IMX_RPROC_FLAGS_SM_LMM_AVAIL	BIT(0)
+
 static int imx_rproc_xtr_mbox_init(struct rproc *rproc, bool tx_block);
 static void imx_rproc_free_mbox(void *data);
+static int imx_rproc_sm_detect_mode(struct rproc *rproc);
 
 struct imx_rproc {
 	struct device			*dev;
@@ -117,6 +123,11 @@ struct imx_rproc {
 	u32				core_index;
 	struct dev_pm_domain_list	*pd_list;
 	const struct imx_rproc_plat_ops	*ops;
+	/*
+	 * For i.MX System Manager based systems
+	 * BIT 0: IMX_RPROC_FLAGS_SM_LMM_AVAIL(RPROC LM is under Linux control )
+	 */
+	u32				flags;
 };
 
 static const struct imx_rproc_att imx_rproc_att_imx93[] = {
@@ -313,6 +324,44 @@ static int imx_rproc_scu_api_start(struct rproc *rproc)
 	return imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, true, priv->entry);
 }
 
+static int imx_rproc_sm_cpu_start(struct rproc *rproc)
+{
+	struct imx_rproc *priv = rproc->priv;
+	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+	int ret;
+
+	ret = scmi_imx_cpu_reset_vector_set(dcfg->cpuid, 0, true, false, false);
+	if (ret) {
+		dev_err(priv->dev, "Failed to set reset vector cpuid(%u): %d\n", dcfg->cpuid, ret);
+		return ret;
+	}
+
+	return scmi_imx_cpu_start(dcfg->cpuid, true);
+}
+
+static int imx_rproc_sm_lmm_start(struct rproc *rproc)
+{
+	struct imx_rproc *priv = rproc->priv;
+	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+	struct device *dev = priv->dev;
+	int ret;
+
+	ret = scmi_imx_lmm_reset_vector_set(dcfg->lmid, dcfg->cpuid, 0, 0);
+	if (ret) {
+		dev_err(dev, "Failed to set reset vector lmid(%u), cpuid(%u): %d\n",
+			dcfg->lmid, dcfg->cpuid, ret);
+		return ret;
+	}
+
+	ret = scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_BOOT, 0);
+	if (ret) {
+		dev_err(dev, "Failed to boot lmm(%d): %d\n", dcfg->lmid, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
 static int imx_rproc_start(struct rproc *rproc)
 {
 	struct imx_rproc *priv = rproc->priv;
@@ -369,6 +418,25 @@ static int imx_rproc_scu_api_stop(struct rproc *rproc)
 	return imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, false, priv->entry);
 }
 
+static int imx_rproc_sm_cpu_stop(struct rproc *rproc)
+{
+	struct imx_rproc *priv = rproc->priv;
+	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+
+	return scmi_imx_cpu_start(dcfg->cpuid, false);
+}
+
+static int imx_rproc_sm_lmm_stop(struct rproc *rproc)
+{
+	struct imx_rproc *priv = rproc->priv;
+	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+
+	if (!(priv->flags & IMX_RPROC_FLAGS_SM_LMM_AVAIL))
+		return -EACCES;
+
+	return scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_SHUTDOWN, 0);
+}
+
 static int imx_rproc_stop(struct rproc *rproc)
 {
 	struct imx_rproc *priv = rproc->priv;
@@ -485,6 +553,33 @@ static int imx_rproc_mem_release(struct rproc *rproc,
 	return 0;
 }
 
+static int imx_rproc_sm_lmm_prepare(struct rproc *rproc)
+{
+	struct imx_rproc *priv = rproc->priv;
+	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+	int ret;
+
+	/*
+	 * IMX_RPROC_FLAGS_SM_LMM_AVAIL not set indicates Linux is not able
+	 * to start/stop rproc LM, then if rproc is not in detached state,
+	 * prepare should fail. If in detached state, this is in rproc_attach()
+	 * path.
+	 */
+	if (!(priv->flags & IMX_RPROC_FLAGS_SM_LMM_AVAIL))
+		return rproc->state == RPROC_DETACHED ? 0 : -EACCES;
+
+	/* Power on the Logical Machine to make sure TCM is available. */
+	ret = scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_POWER_ON, 0);
+	if (ret) {
+		dev_err(priv->dev, "Failed to power on lmm(%d): %d\n", dcfg->lmid, ret);
+		return ret;
+	}
+
+	dev_info(priv->dev, "lmm(%d) powered on by Linux\n", dcfg->lmid);
+
+	return 0;
+}
+
 static int imx_rproc_prepare(struct rproc *rproc)
 {
 	struct imx_rproc *priv = rproc->priv;
@@ -980,6 +1075,104 @@ static int imx_rproc_scu_api_detect_mode(struct rproc *rproc)
 	return 0;
 }
 
+static const struct imx_rproc_plat_ops imx_rproc_ops_sm_lmm = {
+	.detect_mode	= imx_rproc_sm_detect_mode,
+	.prepare	= imx_rproc_sm_lmm_prepare,
+	.start		= imx_rproc_sm_lmm_start,
+	.stop		= imx_rproc_sm_lmm_stop,
+};
+
+static const struct imx_rproc_plat_ops imx_rproc_ops_sm_cpu = {
+	.detect_mode	= imx_rproc_sm_detect_mode,
+	.start		= imx_rproc_sm_cpu_start,
+	.stop		= imx_rproc_sm_cpu_stop,
+};
+
+static int imx_rproc_sm_lmm_check(struct rproc *rproc, bool started)
+{
+	struct imx_rproc *priv = rproc->priv;
+	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+	struct device *dev = priv->dev;
+	int ret;
+
+	/*
+	 * Use power on to do permission check. If rproc is in different LM,
+	 * and linux has permission to handle the LM, set IMX_RPROC_FLAGS_SM_LMM_AVAIL.
+	 */
+	ret = scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_POWER_ON, 0);
+	if (ret) {
+		if (ret == -EACCES) {
+			/*
+			 * rproc LM is booted before Linux and not under Linux Control, so only
+			 * do IPC between RPROC and Linux, not return failure
+			 */
+			dev_info(dev, "lmm(%d) not under Linux Control\n", dcfg->lmid);
+			return 0;
+		}
+
+		dev_err(dev, "power on lmm(%d) failed: %d\n", dcfg->lmid, ret);
+		return ret;
+	}
+
+	priv->flags |= IMX_RPROC_FLAGS_SM_LMM_AVAIL;
+
+	/* rproc was started before boot Linux and under control of Linux, directly return */
+	if (started)
+		return 0;
+
+	/* else shutdown the LM to save power */
+	ret = scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_SHUTDOWN, 0);
+	if (ret) {
+		priv->flags &= ~IMX_RPROC_FLAGS_SM_LMM_AVAIL;
+		dev_err(dev, "shutdown lmm(%d) failed: %d\n", dcfg->lmid, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int imx_rproc_sm_detect_mode(struct rproc *rproc)
+{
+	struct imx_rproc *priv = rproc->priv;
+	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+	struct device *dev = priv->dev;
+	struct scmi_imx_lmm_info info;
+	bool started = false;
+	int ret;
+
+	ret = scmi_imx_cpu_started(dcfg->cpuid, &started);
+	if (ret) {
+		dev_err(dev, "Failed to detect cpu(%d) status: %d\n", dcfg->cpuid, ret);
+		return ret;
+	}
+
+	if (started)
+		priv->rproc->state = RPROC_DETACHED;
+
+	/* Get current Linux Logical Machine ID */
+	ret = scmi_imx_lmm_info(LMM_ID_DISCOVER, &info);
+	if (ret) {
+		dev_err(dev, "Failed to get current LMM ID err: %d\n", ret);
+		return ret;
+	}
+
+	/*
+	 * Check whether rproc is in the same LM as host core(running Linux)
+	 * If yes, use CPU protocol API to manage rproc.
+	 * If no, use Logical Machine API to manage rproc.
+	 */
+	if (dcfg->lmid == info.lmid) {
+		priv->ops = &imx_rproc_ops_sm_cpu;
+		dev_info(dev, "Using CPU Protocol OPS\n");
+		return 0;
+	}
+
+	priv->ops = &imx_rproc_ops_sm_lmm;
+	dev_info(dev, "Using LMM Protocol OPS\n");
+
+	return imx_rproc_sm_lmm_check(rproc, started);
+}
+
 static int imx_rproc_detect_mode(struct imx_rproc *priv)
 {
 	/*
diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h
index 37417568a0ade2ae4d6a4e3d0f139ea52b185254..d37e6f90548cec727b4aeb874680b42af85bdbb4 100644
--- a/drivers/remoteproc/imx_rproc.h
+++ b/drivers/remoteproc/imx_rproc.h
@@ -38,6 +38,9 @@ struct imx_rproc_dcfg {
 	size_t				att_size;
 	u32				flags;
 	const struct imx_rproc_plat_ops	*ops;
+	/* For System Manager(SM) based SoCs */
+	u32				cpuid; /* ID of the remote core */
+	u32				lmid;  /* ID of the Logcial Machine */
 };
 
 #endif /* _IMX_RPROC_H */

-- 
2.37.1



From peng.fan at oss.nxp.com  Mon Dec 15 17:51:03 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Tue, 16 Dec 2025 09:51:03 +0800
Subject: [PATCH v4 5/5] remoteproc: imx_rproc: Add support for i.MX95
In-Reply-To: <20251216-imx95-rproc-2025-12-15-v4-0-bf1064ea8daf@nxp.com>
References: <20251216-imx95-rproc-2025-12-15-v4-0-bf1064ea8daf@nxp.com>
Message-ID: <20251216-imx95-rproc-2025-12-15-v4-5-bf1064ea8daf@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

Add imx_rproc_cfg_imx95_m7 and address(TCM and DDR) mapping.
Add i.MX95 of_device_id entry.

Reviewed-by: Daniel Baluta <daniel.baluta at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 drivers/remoteproc/imx_rproc.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index 55e555f2b5dd63e7d82996437e792a8152c91521..b2d0be0afc995a6c285c8afd4e294f95491ebb7a 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -130,6 +130,18 @@ struct imx_rproc {
 	u32				flags;
 };
 
+static const struct imx_rproc_att imx_rproc_att_imx95_m7[] = {
+	/* dev addr , sys addr  , size	    , flags */
+	/* TCM CODE NON-SECURE */
+	{ 0x00000000, 0x203C0000, 0x00040000, ATT_OWN | ATT_IOMEM },
+
+	/* TCM SYS NON-SECURE*/
+	{ 0x20000000, 0x20400000, 0x00040000, ATT_OWN | ATT_IOMEM },
+
+	/* DDR */
+	{ 0x80000000, 0x80000000, 0x50000000, 0 },
+};
+
 static const struct imx_rproc_att imx_rproc_att_imx93[] = {
 	/* dev addr , sys addr  , size	    , flags */
 	/* TCM CODE NON-SECURE */
@@ -1431,6 +1443,15 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx93 = {
 	.flags		= IMX_RPROC_NEED_CLKS,
 };
 
+static const struct imx_rproc_dcfg imx_rproc_cfg_imx95_m7 = {
+	.att		= imx_rproc_att_imx95_m7,
+	.att_size	= ARRAY_SIZE(imx_rproc_att_imx95_m7),
+	.ops		= &imx_rproc_ops_sm_lmm,
+	/* Must align with System Manager Firmware */
+	.cpuid		= 1, /* Use 1 as cpu id for M7 core */
+	.lmid		= 1, /* Use 1 as Logical Machine ID where M7 resides */
+};
+
 static const struct of_device_id imx_rproc_of_match[] = {
 	{ .compatible = "fsl,imx7ulp-cm4", .data = &imx_rproc_cfg_imx7ulp },
 	{ .compatible = "fsl,imx7d-cm4", .data = &imx_rproc_cfg_imx7d },
@@ -1445,6 +1466,7 @@ static const struct of_device_id imx_rproc_of_match[] = {
 	{ .compatible = "fsl,imx8qm-cm4", .data = &imx_rproc_cfg_imx8qm },
 	{ .compatible = "fsl,imx8ulp-cm33", .data = &imx_rproc_cfg_imx8ulp },
 	{ .compatible = "fsl,imx93-cm33", .data = &imx_rproc_cfg_imx93 },
+	{ .compatible = "fsl,imx95-cm7", .data = &imx_rproc_cfg_imx95_m7 },
 	{},
 };
 MODULE_DEVICE_TABLE(of, imx_rproc_of_match);

-- 
2.37.1



From nicolinc at nvidia.com  Mon Dec 15 18:09:29 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Mon, 15 Dec 2025 18:09:29 -0800
Subject: [PATCH v7 0/7] iommu/arm-smmu-v3: Introduce an RCU-protected invalidation array
Message-ID: <cover.1765850465.git.nicolinc@nvidia.com>

This is a work based on Jason's design and algorithm. This implementation
follows his initial draft and revising as well.

The new arm_smmu_invs array is an RCU-protected array, mutated when device
attach to the domain, iterated when an invalidation is required for IOPTE
changes in this domain. This keeps the current invalidation efficiency of
a smb_mb() followed by a conditional rwlock replacing the atomic/spinlock
combination.

A new data structure is defined for the array and its entry, representing
invalidation operations, such as S1_ASID, S2_VMID, and ATS. The algorithm
adds and deletes array entries efficiently and also keeps the array sorted
so as to group similar invalidations into batches.

During an invalidation, a new invalidation function iterates domain->invs,
and converts each entry to the corresponding invalidation command(s). This
new function is fully compatible with all the existing use cases, allowing
a simple rework/replacement.

Some races to keep in mind:

1) A domain can be shared across SMMU instances. When an SMMU instance is
   removed, the updated invs array has to be sync-ed via synchronize_rcu()
   to prevent an concurrent invalidation routine that is accessing the old
   array from issuing commands to the removed SMMU instance.

2) When there are concurrent IOPTE changes (followed by invalidations) and
   a domain attachment, the new attachment must not become out of sync at
   the HW level, meaning that an STE store and invalidation array load must
   be sequenced by the CPU's memory model.

3) When an ATS-enabled device attaches to a blocking domain, the core code
   requires a hard fence to ensure all ATS invalidations to the device are
   completed. Relying on RCU alone requires calling synchronize_rcu() that
   can be too slow. Instead, when ATS is in use, hold a conditional rwlock
   till all concurrent invalidations are finished.

Related future work and dependent projects:

 * NVIDIA is building systems with > 10 SMMU instances where > 8 are being
   used concurrently in a single VM. So having 8 copies of an identical S2
   page table is not efficient. Instead, all vSMMU instances should check
   compatibility on a shared S2 iopt, to eliminate 7 copies.

   Previous attempt based on the list/spinlock design:
     iommu/arm-smmu-v3: Allocate vmid per vsmmu instead of s2_parent
     https://lore.kernel.org/all/cover.1744692494.git.nicolinc at nvidia.com/
   now can adopt this invs array, avoiding adding complex lists/locks.

 * The guest support for BTM requires temporarily invalidating two ASIDs
   for a single instance. When it renumbers ASIDs this can now be done via
   the invs array.

 * SVA with multiple devices being used by a single process (NVIDIA today
   has 4-8) sequentially iterates the invalidations through all instances.
   This ignores the HW concurrency available in each instance. It would be
   nice to not spin on each sync but go forward and issue batches to other
   instances also. Reducing to a single SVA domain shared across instances
   is required to look at this.

This is on Github:
https://github.com/nicolinc/iommufd/commits/arm_smmu_invs-v7

Changelog
v7:
 * Rebase on v6.19-rc1
 * Fix has_ats in arm_smmu_invs_merge()
 * Fix re-attach case with a different ats_enabled
 * Constify the inv parameter in arm_smmu_inv_is_ats()
 * Update kunit test data to be closer to real-world use cases
 * Clean up SVA domain's invs in arm_smmu_blocking_set_dev_pasid()
v6:
 https://lore.kernel.org/all/cover.1764119291.git.nicolinc at nvidia.com/
 * Fix typo in kdocs
 * Fix arm_smmu_domain_free() in SVA
 * Add arm_smmu_master_build_inv() helper
 * Add max_invs and __counted_by(max_invs)
 * Return NULL if arm_smmu_invs_alloc() fails
 * Sort master->streams instead of fwspec->ids
 * s/flush_fn/free_fn (prepare for future patches)
 * s/arm_smmu_invs_flush_iotlb_tags/arm_smmu_inv_flush_iotlb_tag
 * Define arm_smmu_invs macros and helpers to reduce duplications
 * Save num_trashes in "struct arm_smmu_invs" (to avoid a re-scan)
 * Move smp_mb() in install() to PATCH-6 that adds the pairing barrier
   and description
v5:
 https://lore.kernel.org/all/cover.1762588839.git.nicolinc at nvidia.com/
 * Add Reviewed/Acked-by from Jason and Balbir
 * Add two inline comments
 * Move cmp after the trash entry validation
 * Batch commands in arm_smmu_inv_size_too_big case
 * Replace kfree_rcu() with kfree() in arm_smmu_domain_free()
v4:
 https://lore.kernel.org/all/cover.1761590851.git.nicolinc at nvidia.com/
 * Fix build errors with CONFIG_KUNIT=n
 * Fix uninitialized cmp in arm_smmu_invs_unref()
 * Add missing "__rcu" in struct arm_smmu_inv_state
 * Add missing rcu_derference_protected() in arm_smmu_domain_free()
 * Bisect two paths for the conditional lock in arm_smmu_domain_inv_range()
   to fix a sparse waring
v3:
 https://lore.kernel.org/all/cover.1760555863.git.nicolinc at nvidia.com/
 * Add Reviewed/Acked-by from Jason and Balbir
 * Rebase on v6.18-rc1
 * Drop arm_smmu_invs_dbg()
 * Improve kdocs and inline/commit comments
 * Rename arm_smmu_invs_cmp to arm_smmu_inv_cmp
 * Rename arm_smmu_invs_merge_cmp to arm_smmu_invs_cmp
 * Call arm_smmu_invs_flush_iotlb_tags() from arm_smmu_invs_unref()
 * Unconditionally trim the invs->num_invs inside arm_smmu_invs_unref(),
   and simplify arm_smmu_install_old_domain_invs().
v2:
 https://lore.kernel.org/all/cover.1757373449.git.nicolinc at nvidia.com/
 * Rebase on v6.17-rc5
 * Improve kdocs and inline comments
 * Add arm_smmu_invs_dbg() for tracing
 * Use users refcount to replace todel flag
 * Initialize num_invs in arm_smmu_invs_alloc()
 * Add a struct arm_smmu_inv_state to group invs pointers
 * Add in struct arm_smmu_invs two flags (has_ats and old)
 * Rename master->invs to master->build_invs, and sort the array
 * Rework arm_smmu_domain_inv_range() and arm_smmu_invs_end_batch()
 * Copy entries by struct arm_smmu_inv in arm_smmu_master_build_invs()
 * Add arm_smmu_invs_flush_iotlb_tags() for IOTLB flush by last device
 * Rework three invs mutation helpers, and prioritize use the in-place
   mutation for detach
 * Take writer's lock unconditionally but keep it short, and only take
   reader's lock conditionally on a has_ats flag
v1:
 https://lore.kernel.org/all/cover.1755131672.git.nicolinc at nvidia.com/

Thanks
Nicolin

Jason Gunthorpe (1):
  iommu/arm-smmu-v3: Introduce a per-domain arm_smmu_invs array

Nicolin Chen (6):
  iommu/arm-smmu-v3: Explicitly set smmu_domain->stage for SVA
  iommu/arm-smmu-v3: Add an inline arm_smmu_domain_free()
  iommu/arm-smmu-v3: Pre-allocate a per-master invalidation array
  iommu/arm-smmu-v3: Populate smmu_domain->invs when attaching masters
  iommu/arm-smmu-v3: Add arm_smmu_invs based arm_smmu_domain_inv_range()
  iommu/arm-smmu-v3: Perform per-domain invalidations using
    arm_smmu_invs

 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   | 143 ++-
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c   |  35 +-
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  |  92 ++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 898 +++++++++++++++---
 4 files changed, 988 insertions(+), 180 deletions(-)

-- 
2.43.0



From nicolinc at nvidia.com  Mon Dec 15 18:09:30 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Mon, 15 Dec 2025 18:09:30 -0800
Subject: [PATCH v7 1/7] iommu/arm-smmu-v3: Explicitly set smmu_domain->stage for SVA
In-Reply-To: <cover.1765850465.git.nicolinc@nvidia.com>
References: <cover.1765850465.git.nicolinc@nvidia.com>
Message-ID: <df4b8cbc0d67a0bfcccb09be868e0da5f0cbb743.1765850465.git.nicolinc@nvidia.com>

Both the ARM_SMMU_DOMAIN_S1 case and the SVA case use ASID, requiring ASID
based invalidation commands to flush the TLB.

Define an ARM_SMMU_DOMAIN_SVA to make the SVA case clear to share the same
path with the ARM_SMMU_DOMAIN_S1 case, which will be a part of the routine
to build a new per-domain invalidation array.

There is no function change.

Suggested-by: Jason Gunthorpe <jgg at nvidia.com>
Acked-by: Balbir Singh <balbirs at nvidia.com>
Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h     | 1 +
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 1 +
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c     | 3 +++
 3 files changed, 5 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index ae23aacc3840..5c0b38595d20 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -858,6 +858,7 @@ struct arm_smmu_master {
 enum arm_smmu_domain_stage {
 	ARM_SMMU_DOMAIN_S1 = 0,
 	ARM_SMMU_DOMAIN_S2,
+	ARM_SMMU_DOMAIN_SVA,
 };
 
 struct arm_smmu_domain {
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index 59a480974d80..6097f1f540d8 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -346,6 +346,7 @@ struct iommu_domain *arm_smmu_sva_domain_alloc(struct device *dev,
 	 * ARM_SMMU_FEAT_RANGE_INV is present
 	 */
 	smmu_domain->domain.pgsize_bitmap = PAGE_SIZE;
+	smmu_domain->stage = ARM_SMMU_DOMAIN_SVA;
 	smmu_domain->smmu = smmu;
 
 	ret = xa_alloc(&arm_smmu_asid_xa, &asid, smmu_domain,
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index d16d35c78c06..9d9f24a08062 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -3065,6 +3065,9 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev,
 		arm_smmu_install_ste_for_dev(master, &target);
 		arm_smmu_clear_cd(master, IOMMU_NO_PASID);
 		break;
+	default:
+		WARN_ON(true);
+		break;
 	}
 
 	arm_smmu_attach_commit(&state);
-- 
2.43.0



From nicolinc at nvidia.com  Mon Dec 15 18:09:31 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Mon, 15 Dec 2025 18:09:31 -0800
Subject: [PATCH v7 2/7] iommu/arm-smmu-v3: Add an inline arm_smmu_domain_free()
In-Reply-To: <cover.1765850465.git.nicolinc@nvidia.com>
References: <cover.1765850465.git.nicolinc@nvidia.com>
Message-ID: <b516338bdde0bc6f06e2719b9292ffa260085a67.1765850465.git.nicolinc@nvidia.com>

There will be a bit more things to free than smmu_domain itself. So keep a
simple inline function in the header to share aross files.

Suggested-by: Jason Gunthorpe <jgg at nvidia.com>
Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
Acked-by: Balbir Singh <balbirs at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h     | 5 +++++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 5 +++--
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c     | 4 ++--
 3 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index 5c0b38595d20..96a23ca633cb 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -954,6 +954,11 @@ extern struct mutex arm_smmu_asid_lock;
 
 struct arm_smmu_domain *arm_smmu_domain_alloc(void);
 
+static inline void arm_smmu_domain_free(struct arm_smmu_domain *smmu_domain)
+{
+	kfree(smmu_domain);
+}
+
 void arm_smmu_clear_cd(struct arm_smmu_master *master, ioasid_t ssid);
 struct arm_smmu_cd *arm_smmu_get_cd_ptr(struct arm_smmu_master *master,
 					u32 ssid);
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index 6097f1f540d8..440ad8cc07de 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -197,7 +197,8 @@ static void arm_smmu_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
 
 static void arm_smmu_mmu_notifier_free(struct mmu_notifier *mn)
 {
-	kfree(container_of(mn, struct arm_smmu_domain, mmu_notifier));
+	arm_smmu_domain_free(
+		container_of(mn, struct arm_smmu_domain, mmu_notifier));
 }
 
 static const struct mmu_notifier_ops arm_smmu_mmu_notifier_ops = {
@@ -365,6 +366,6 @@ struct iommu_domain *arm_smmu_sva_domain_alloc(struct device *dev,
 err_asid:
 	xa_erase(&arm_smmu_asid_xa, smmu_domain->cd.asid);
 err_free:
-	kfree(smmu_domain);
+	arm_smmu_domain_free(smmu_domain);
 	return ERR_PTR(ret);
 }
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 9d9f24a08062..e9759e8af0c0 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2492,7 +2492,7 @@ static void arm_smmu_domain_free_paging(struct iommu_domain *domain)
 			ida_free(&smmu->vmid_map, cfg->vmid);
 	}
 
-	kfree(smmu_domain);
+	arm_smmu_domain_free(smmu_domain);
 }
 
 static int arm_smmu_domain_finalise_s1(struct arm_smmu_device *smmu,
@@ -3359,7 +3359,7 @@ arm_smmu_domain_alloc_paging_flags(struct device *dev, u32 flags,
 	return &smmu_domain->domain;
 
 err_free:
-	kfree(smmu_domain);
+	arm_smmu_domain_free(smmu_domain);
 	return ERR_PTR(ret);
 }
 
-- 
2.43.0



From nicolinc at nvidia.com  Mon Dec 15 18:09:33 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Mon, 15 Dec 2025 18:09:33 -0800
Subject: [PATCH v7 4/7] iommu/arm-smmu-v3: Pre-allocate a per-master invalidation array
In-Reply-To: <cover.1765850465.git.nicolinc@nvidia.com>
References: <cover.1765850465.git.nicolinc@nvidia.com>
Message-ID: <a45b303a2ac706abdd3d733a9ac58e57c68ec0c8.1765850465.git.nicolinc@nvidia.com>

When a master is attached from an old domain to a new domain, it needs to
build an invalidation array to delete and add the array entries from/onto
the invalidation arrays of those two domains, passed via the to_merge and
to_unref arguments into arm_smmu_invs_merge/unref() respectively.

Since the master->num_streams might differ across masters, a memory would
have to be allocated when building an to_merge/to_unref array which might
fail with -ENOMEM.

On the other hand, an attachment to arm_smmu_blocked_domain must not fail
so it's the best to avoid any memory allocation in that path.

Pre-allocate a fixed size invalidation array for every master. This array
will be used as a scratch to fill dynamically when building a to_merge or
to_unref invs array. Sort fwspec->ids in an ascending order to fit to the
arm_smmu_invs_merge() function.

Co-developed-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h |  8 ++++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 41 +++++++++++++++++++--
 2 files changed, 45 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index a9441dc9070e..f98774962012 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -930,6 +930,14 @@ struct arm_smmu_master {
 	struct arm_smmu_device		*smmu;
 	struct device			*dev;
 	struct arm_smmu_stream		*streams;
+	/*
+	 * Scratch memory for a to_merge or to_unref array to build a per-domain
+	 * invalidation array. It'll be pre-allocated with enough enries for all
+	 * possible build scenarios. It can be used by only one caller at a time
+	 * until the arm_smmu_invs_merge/unref() finishes. Must be locked by the
+	 * iommu_group mutex.
+	 */
+	struct arm_smmu_invs		*build_invs;
 	struct arm_smmu_vmaster		*vmaster; /* use smmu->streams_mutex */
 	/* Locked by the iommu core using the group mutex */
 	struct arm_smmu_ctx_desc_cfg	cd_table;
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 39e89176fa87..cc85e7a10ea8 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -3709,12 +3709,22 @@ static int arm_smmu_init_sid_strtab(struct arm_smmu_device *smmu, u32 sid)
 	return 0;
 }
 
+static int arm_smmu_stream_id_cmp(const void *_l, const void *_r)
+{
+	const typeof_member(struct arm_smmu_stream, id) *l = _l;
+	const typeof_member(struct arm_smmu_stream, id) *r = _r;
+
+	return cmp_int(*l, *r);
+}
+
 static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
 				  struct arm_smmu_master *master)
 {
 	int i;
 	int ret = 0;
 	struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(master->dev);
+	bool ats_supported = dev_is_pci(master->dev) &&
+			     pci_ats_supported(to_pci_dev(master->dev));
 
 	master->streams = kcalloc(fwspec->num_ids, sizeof(*master->streams),
 				  GFP_KERNEL);
@@ -3722,14 +3732,35 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
 		return -ENOMEM;
 	master->num_streams = fwspec->num_ids;
 
-	mutex_lock(&smmu->streams_mutex);
+	if (!ats_supported) {
+		/* Base case has 1 ASID entry or maximum 2 VMID entries */
+		master->build_invs = arm_smmu_invs_alloc(2);
+	} else {
+		/* ATS case adds num_ids of entries, on top of the base case */
+		master->build_invs = arm_smmu_invs_alloc(2 + fwspec->num_ids);
+	}
+	if (!master->build_invs) {
+		kfree(master->streams);
+		return -ENOMEM;
+	}
+
 	for (i = 0; i < fwspec->num_ids; i++) {
 		struct arm_smmu_stream *new_stream = &master->streams[i];
-		struct rb_node *existing;
-		u32 sid = fwspec->ids[i];
 
-		new_stream->id = sid;
+		new_stream->id = fwspec->ids[i];
 		new_stream->master = master;
+	}
+
+	/* Put the ids into order for sorted to_merge/to_unref arrays */
+	sort_nonatomic(master->streams, master->num_streams,
+		       sizeof(master->streams[0]), arm_smmu_stream_id_cmp,
+		       NULL);
+
+	mutex_lock(&smmu->streams_mutex);
+	for (i = 0; i < fwspec->num_ids; i++) {
+		struct arm_smmu_stream *new_stream = &master->streams[i];
+		struct rb_node *existing;
+		u32 sid = new_stream->id;
 
 		ret = arm_smmu_init_sid_strtab(smmu, sid);
 		if (ret)
@@ -3759,6 +3790,7 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
 		for (i--; i >= 0; i--)
 			rb_erase(&master->streams[i].node, &smmu->streams);
 		kfree(master->streams);
+		kfree(master->build_invs);
 	}
 	mutex_unlock(&smmu->streams_mutex);
 
@@ -3780,6 +3812,7 @@ static void arm_smmu_remove_master(struct arm_smmu_master *master)
 	mutex_unlock(&smmu->streams_mutex);
 
 	kfree(master->streams);
+	kfree(master->build_invs);
 }
 
 static struct iommu_device *arm_smmu_probe_device(struct device *dev)
-- 
2.43.0



From nicolinc at nvidia.com  Mon Dec 15 18:09:32 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Mon, 15 Dec 2025 18:09:32 -0800
Subject: [PATCH v7 3/7] iommu/arm-smmu-v3: Introduce a per-domain arm_smmu_invs array
In-Reply-To: <cover.1765850465.git.nicolinc@nvidia.com>
References: <cover.1765850465.git.nicolinc@nvidia.com>
Message-ID: <542ff2578f7c808daae8e7044ef1bbcada16ba53.1765850465.git.nicolinc@nvidia.com>

From: Jason Gunthorpe <jgg at nvidia.com>

Create a new data structure to hold an array of invalidations that need to
be performed for the domain based on what masters are attached, to replace
the single smmu pointer and linked list of masters in the current design.

Each array entry holds one of the invalidation actions - S1_ASID, S2_VMID,
ATS or their variant with information to feed invalidation commands to HW.
It is structured so that multiple SMMUs can participate in the same array,
removing one key limitation of the current system.

To maximize performance, a sorted array is used as the data structure. It
allows grouping SYNCs together to parallelize invalidations. For instance,
it will group all the ATS entries after the ASID/VMID entry, so they will
all be pushed to the PCI devices in parallel with one SYNC.

To minimize the locking cost on the invalidation fast path (reader of the
invalidation array), the array is managed with RCU.

Provide a set of APIs to add/delete entries to/from an array, which cover
cannot-fail attach cases, e.g. attaching to arm_smmu_blocked_domain. Also
add kunit coverage for those APIs.

Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
Co-developed-by: Nicolin Chen <nicolinc at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  98 +++++++
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  |  92 +++++++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 258 ++++++++++++++++++
 3 files changed, 448 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index 96a23ca633cb..a9441dc9070e 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -649,6 +649,93 @@ struct arm_smmu_cmdq_batch {
 	int				num;
 };
 
+/*
+ * The order here also determines the sequence in which commands are sent to the
+ * command queue. E.g. TLBI must be done before ATC_INV.
+ */
+enum arm_smmu_inv_type {
+	INV_TYPE_S1_ASID,
+	INV_TYPE_S2_VMID,
+	INV_TYPE_S2_VMID_S1_CLEAR,
+	INV_TYPE_ATS,
+	INV_TYPE_ATS_FULL,
+};
+
+struct arm_smmu_inv {
+	struct arm_smmu_device *smmu;
+	u8 type;
+	u8 size_opcode;
+	u8 nsize_opcode;
+	u32 id; /* ASID or VMID or SID */
+	union {
+		size_t pgsize; /* ARM_SMMU_FEAT_RANGE_INV */
+		u32 ssid; /* INV_TYPE_ATS */
+	};
+
+	refcount_t users; /* users=0 to mark as a trash to be purged */
+};
+
+static inline bool arm_smmu_inv_is_ats(const struct arm_smmu_inv *inv)
+{
+	return inv->type == INV_TYPE_ATS || inv->type == INV_TYPE_ATS_FULL;
+}
+
+/**
+ * struct arm_smmu_invs - Per-domain invalidation array
+ * @max_invs: maximum capacity of the flexible array
+ * @num_invs: number of invalidations in the flexible array. May be smaller than
+ *            @max_invs after a tailing trash entry is excluded, but must not be
+ *            greater than @max_invs
+ * @num_trashes: number of trash entries in the array for arm_smmu_invs_purge().
+ *               Must not be greater than @num_invs
+ * @rwlock: optional rwlock to fench ATS operations
+ * @has_ats: flag if the array contains an INV_TYPE_ATS or INV_TYPE_ATS_FULL
+ * @rcu: rcu head for kfree_rcu()
+ * @inv: flexible invalidation array
+ *
+ * The arm_smmu_invs is an RCU data structure. During a ->attach_dev callback,
+ * arm_smmu_invs_merge(), arm_smmu_invs_unref() and arm_smmu_invs_purge() will
+ * be used to allocate a new copy of an old array for addition and deletion in
+ * the old domain's and new domain's invs arrays.
+ *
+ * The arm_smmu_invs_unref() mutates a given array, by internally reducing the
+ * users counts of some given entries. This exists to support a no-fail routine
+ * like attaching to an IOMMU_DOMAIN_BLOCKED. And it could pair with a followup
+ * arm_smmu_invs_purge() call to generate a new clean array.
+ *
+ * Concurrent invalidation thread will push every invalidation described in the
+ * array into the command queue for each invalidation event. It is designed like
+ * this to optimize the invalidation fast path by avoiding locks.
+ *
+ * A domain can be shared across SMMU instances. When an instance gets removed,
+ * it would delete all the entries that belong to that SMMU instance. Then, a
+ * synchronize_rcu() would have to be called to sync the array, to prevent any
+ * concurrent invalidation thread accessing the old array from issuing commands
+ * to the command queue of a removed SMMU instance.
+ */
+struct arm_smmu_invs {
+	size_t max_invs;
+	size_t num_invs;
+	size_t num_trashes;
+	rwlock_t rwlock;
+	bool has_ats;
+	struct rcu_head rcu;
+	struct arm_smmu_inv inv[] __counted_by(max_invs);
+};
+
+static inline struct arm_smmu_invs *arm_smmu_invs_alloc(size_t num_invs)
+{
+	struct arm_smmu_invs *new_invs;
+
+	new_invs = kzalloc(struct_size(new_invs, inv, num_invs), GFP_KERNEL);
+	if (!new_invs)
+		return NULL;
+	new_invs->max_invs = num_invs;
+	new_invs->num_invs = num_invs;
+	rwlock_init(&new_invs->rwlock);
+	return new_invs;
+}
+
 struct arm_smmu_evtq {
 	struct arm_smmu_queue		q;
 	struct iopf_queue		*iopf;
@@ -875,6 +962,8 @@ struct arm_smmu_domain {
 
 	struct iommu_domain		domain;
 
+	struct arm_smmu_invs __rcu	*invs;
+
 	/* List of struct arm_smmu_master_domain */
 	struct list_head		devices;
 	spinlock_t			devices_lock;
@@ -923,6 +1012,13 @@ void arm_smmu_make_cdtable_ste(struct arm_smmu_ste *target,
 void arm_smmu_make_sva_cd(struct arm_smmu_cd *target,
 			  struct arm_smmu_master *master, struct mm_struct *mm,
 			  u16 asid);
+
+struct arm_smmu_invs *arm_smmu_invs_merge(struct arm_smmu_invs *invs,
+					  struct arm_smmu_invs *to_merge);
+void arm_smmu_invs_unref(struct arm_smmu_invs *invs,
+			 struct arm_smmu_invs *to_unref,
+			 void (*free_fn)(struct arm_smmu_inv *inv));
+struct arm_smmu_invs *arm_smmu_invs_purge(struct arm_smmu_invs *invs);
 #endif
 
 struct arm_smmu_master_domain {
@@ -956,6 +1052,8 @@ struct arm_smmu_domain *arm_smmu_domain_alloc(void);
 
 static inline void arm_smmu_domain_free(struct arm_smmu_domain *smmu_domain)
 {
+	/* No concurrency with invalidation is possible at this point */
+	kfree(rcu_dereference_protected(smmu_domain->invs, true));
 	kfree(smmu_domain);
 }
 
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
index d2671bfd3798..238bfd328b5b 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
@@ -567,6 +567,97 @@ static void arm_smmu_v3_write_cd_test_sva_release(struct kunit *test)
 						      NUM_EXPECTED_SYNCS(2));
 }
 
+static void arm_smmu_v3_invs_test_verify(struct kunit *test,
+					 struct arm_smmu_invs *invs, int num,
+					 const int *ids, const int *users)
+{
+	KUNIT_EXPECT_EQ(test, invs->num_invs, num);
+	while (num--) {
+		KUNIT_EXPECT_EQ(test, invs->inv[num].id, ids[num]);
+		KUNIT_EXPECT_EQ(test, refcount_read(&invs->inv[num].users),
+				users[num]);
+	}
+}
+
+static struct arm_smmu_invs invs1 = {
+	.num_invs = 3,
+	.inv = { { .type = INV_TYPE_S2_VMID, .id = 1, },
+		 { .type = INV_TYPE_S2_VMID_S1_CLEAR, .id = 1, },
+		 { .type = INV_TYPE_ATS, .id = 3, }, },
+};
+
+static struct arm_smmu_invs invs2 = {
+	.num_invs = 3,
+	.inv = { { .type = INV_TYPE_S2_VMID, .id = 1, }, /* duplicated */
+		 { .type = INV_TYPE_ATS, .id = 4, },
+		 { .type = INV_TYPE_ATS, .id = 5, }, },
+};
+
+static struct arm_smmu_invs invs3 = {
+	.num_invs = 3,
+	.inv = { { .type = INV_TYPE_S2_VMID, .id = 1, }, /* duplicated */
+		 { .type = INV_TYPE_ATS, .id = 5, }, /* recover a trash */
+		 { .type = INV_TYPE_ATS, .id = 6, }, },
+};
+
+static void arm_smmu_v3_invs_test(struct kunit *test)
+{
+	const int results1[2][3] = { { 1, 1, 3, }, { 1, 1, 1, }, };
+	const int results2[2][5] = { { 1, 1, 3, 4, 5, }, { 2, 1, 1, 1, 1, }, };
+	const int results3[2][3] = { { 1, 1, 3, }, { 1, 1, 1, }, };
+	const int results4[2][5] = { { 1, 1, 3, 5, 6, }, { 2, 1, 1, 1, 1, }, };
+	const int results5[2][5] = { { 1, 1, 3, 5, 6, }, { 1, 0, 0, 1, 1, }, };
+	const int results6[2][3] = { { 1, 5, 6, }, { 1, 1, 1, }, };
+	struct arm_smmu_invs *test_a, *test_b;
+
+	/* New array */
+	test_a = arm_smmu_invs_alloc(0);
+	KUNIT_EXPECT_EQ(test, test_a->num_invs, 0);
+
+	/* Test1: merge invs1 (new array) */
+	test_b = arm_smmu_invs_merge(test_a, &invs1);
+	kfree(test_a);
+	arm_smmu_v3_invs_test_verify(test, test_b, ARRAY_SIZE(results1[0]),
+				     results1[0], results1[1]);
+
+	/* Test2: merge invs2 (new array) */
+	test_a = arm_smmu_invs_merge(test_b, &invs2);
+	kfree(test_b);
+	arm_smmu_v3_invs_test_verify(test, test_a, ARRAY_SIZE(results2[0]),
+				     results2[0], results2[1]);
+
+	/* Test3: unref invs2 (same array) */
+	arm_smmu_invs_unref(test_a, &invs2, NULL);
+	arm_smmu_v3_invs_test_verify(test, test_a, ARRAY_SIZE(results3[0]),
+				     results3[0], results3[1]);
+	KUNIT_EXPECT_EQ(test, test_a->num_trashes, 0);
+
+	/* Test4: merge invs3 (new array) */
+	test_b = arm_smmu_invs_merge(test_a, &invs3);
+	kfree(test_a);
+	arm_smmu_v3_invs_test_verify(test, test_b, ARRAY_SIZE(results4[0]),
+				     results4[0], results4[1]);
+
+	/* Test5: unref invs1 (same array) */
+	arm_smmu_invs_unref(test_b, &invs1, NULL);
+	arm_smmu_v3_invs_test_verify(test, test_b, ARRAY_SIZE(results5[0]),
+				     results5[0], results5[1]);
+	KUNIT_EXPECT_EQ(test, test_b->num_trashes, 2);
+
+	/* Test6: purge test_b (new array) */
+	test_a = arm_smmu_invs_purge(test_b);
+	kfree(test_b);
+	arm_smmu_v3_invs_test_verify(test, test_a, ARRAY_SIZE(results6[0]),
+				     results6[0], results6[1]);
+
+	/* Test7: unref invs3 (same array) */
+	arm_smmu_invs_unref(test_a, &invs3, NULL);
+	KUNIT_EXPECT_EQ(test, test_a->num_invs, 0);
+	KUNIT_EXPECT_EQ(test, test_a->num_trashes, 0);
+
+	kfree(test_a);
+}
+
 static struct kunit_case arm_smmu_v3_test_cases[] = {
 	KUNIT_CASE(arm_smmu_v3_write_ste_test_bypass_to_abort),
 	KUNIT_CASE(arm_smmu_v3_write_ste_test_abort_to_bypass),
@@ -590,6 +681,7 @@ static struct kunit_case arm_smmu_v3_test_cases[] = {
 	KUNIT_CASE(arm_smmu_v3_write_ste_test_s2_to_s1_stall),
 	KUNIT_CASE(arm_smmu_v3_write_cd_test_sva_clear),
 	KUNIT_CASE(arm_smmu_v3_write_cd_test_sva_release),
+	KUNIT_CASE(arm_smmu_v3_invs_test),
 	{},
 };
 
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index e9759e8af0c0..39e89176fa87 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -26,6 +26,7 @@
 #include <linux/pci.h>
 #include <linux/pci-ats.h>
 #include <linux/platform_device.h>
+#include <linux/sort.h>
 #include <linux/string_choices.h>
 #include <kunit/visibility.h>
 #include <uapi/linux/iommufd.h>
@@ -1015,6 +1016,255 @@ static void arm_smmu_page_response(struct device *dev, struct iopf_fault *unused
 	 */
 }
 
+/* Invalidation array manipulation functions */
+static inline struct arm_smmu_inv *
+arm_smmu_invs_iter_next(struct arm_smmu_invs *invs, size_t next, size_t *idx)
+{
+	while (true) {
+		if (next >= invs->num_invs) {
+			*idx = next;
+			return NULL;
+		}
+		if (!refcount_read(&invs->inv[next].users)) {
+			next++;
+			continue;
+		}
+		*idx = next;
+		return &invs->inv[next];
+	}
+}
+
+/**
+ * arm_smmu_invs_for_each_entry - Iterate over all non-trash entries in invs
+ * @invs: the base invalidation array
+ * @idx: a stack variable of 'size_t', to store the array index
+ * @cur: a stack variable of 'struct arm_smmu_inv *'
+ */
+#define arm_smmu_invs_for_each_entry(invs, idx, cur)                           \
+	for (cur = arm_smmu_invs_iter_next(invs, 0, &(idx)); cur;              \
+	     cur = arm_smmu_invs_iter_next(invs, idx + 1, &(idx)))
+
+static int arm_smmu_inv_cmp(const struct arm_smmu_inv *inv_l,
+			    const struct arm_smmu_inv *inv_r)
+{
+	if (inv_l->smmu != inv_r->smmu)
+		return cmp_int((uintptr_t)inv_l->smmu, (uintptr_t)inv_r->smmu);
+	if (inv_l->type != inv_r->type)
+		return cmp_int(inv_l->type, inv_r->type);
+	return cmp_int(inv_l->id, inv_r->id);
+}
+
+static inline int arm_smmu_invs_iter_next_cmp(struct arm_smmu_invs *invs_l,
+					      size_t next_l, size_t *idx_l,
+					      struct arm_smmu_invs *invs_r,
+					      size_t next_r, size_t *idx_r)
+{
+	struct arm_smmu_inv *cur_l =
+		arm_smmu_invs_iter_next(invs_l, next_l, idx_l);
+
+	/*
+	 * We have to update the idx_r manually, because the invs_r cannot call
+	 * arm_smmu_invs_iter_next() as the invs_r never sets any users counter.
+	 */
+	*idx_r = next_r;
+
+	/*
+	 * Compare of two sorted arrays items. If one side is past the end of
+	 * the array, return the other side to let it run out the iteration.
+	 *
+	 * If the left entry is empty, return 1 to pick the right entry.
+	 * If the right entry is empty, return -1 to pick the left entry.
+	 */
+	if (!cur_l)
+		return 1;
+	if (next_r >= invs_r->num_invs)
+		return -1;
+	return arm_smmu_inv_cmp(cur_l, &invs_r->inv[next_r]);
+}
+
+/**
+ * arm_smmu_invs_for_each_entry - Iterate over two sorted arrays computing for
+ *                                arm_smmu_invs_merge() or arm_smmu_invs_unref()
+ * @invs_l: the base invalidation array
+ * @idx_l: a stack variable of 'size_t', to store the base array index
+ * @invs_r: the build_invs array as to_merge or to_unref
+ * @idx_r: a stack variable of 'size_t', to store the build_invs index
+ * @cmp: a stack variable of 'int', to store return value (-1, 0, or 1)
+ */
+#define arm_smmu_invs_for_each_cmp(invs_l, idx_l, invs_r, idx_r, cmp)          \
+	for (idx_l = idx_r = 0,                                                \
+	     cmp = arm_smmu_invs_iter_next_cmp(invs_l, 0, &(idx_l),            \
+					       invs_r, 0, &(idx_r));           \
+	     idx_l < invs_l->num_invs || idx_r < invs_r->num_invs;             \
+	     cmp = arm_smmu_invs_iter_next_cmp(                                \
+		     invs_l, idx_l + (cmp <= 0 ? 1 : 0), &(idx_l),             \
+		     invs_r, idx_r + (cmp >= 0 ? 1 : 0), &(idx_r)))
+
+/**
+ * arm_smmu_invs_merge() - Merge @to_merge into @invs and generate a new array
+ * @invs: the base invalidation array
+ * @to_merge: an array of invlidations to merge
+ *
+ * Return: a newly allocated array on success, or ERR_PTR
+ *
+ * This function must be locked and serialized with arm_smmu_invs_unref() and
+ * arm_smmu_invs_purge(), but do not lockdep on any lock for KUNIT test.
+ *
+ * Both @invs and @to_merge must be sorted, to ensure the returned array will be
+ * sorted as well.
+ *
+ * Caller is resposible for freeing the @invs and the returned new one.
+ *
+ * Entries marked as trash will be purged in the returned array.
+ */
+VISIBLE_IF_KUNIT
+struct arm_smmu_invs *arm_smmu_invs_merge(struct arm_smmu_invs *invs,
+					  struct arm_smmu_invs *to_merge)
+{
+	struct arm_smmu_invs *new_invs;
+	struct arm_smmu_inv *new;
+	size_t num_invs = 0;
+	size_t i, j;
+	int cmp;
+
+	arm_smmu_invs_for_each_cmp(invs, i, to_merge, j, cmp)
+		num_invs++;
+
+	new_invs = arm_smmu_invs_alloc(num_invs);
+	if (!new_invs)
+		return ERR_PTR(-ENOMEM);
+
+	new = new_invs->inv;
+	arm_smmu_invs_for_each_cmp(invs, i, to_merge, j, cmp) {
+		if (cmp < 0) {
+			*new = invs->inv[i];
+		} else if (cmp == 0) {
+			*new = invs->inv[i];
+			refcount_inc(&new->users);
+		} else {
+			*new = to_merge->inv[j];
+			refcount_set(&new->users, 1);
+		}
+
+		/*
+		 * Check that the new array is sorted. This also validates that
+		 * to_merge is sorted.
+		 */
+		if (new != new_invs->inv)
+			WARN_ON_ONCE(arm_smmu_inv_cmp(new - 1, new) == 1);
+		if (arm_smmu_inv_is_ats(new))
+			new_invs->has_ats = true;
+		new++;
+	}
+
+	WARN_ON(new != new_invs->inv + new_invs->num_invs);
+
+	return new_invs;
+}
+EXPORT_SYMBOL_IF_KUNIT(arm_smmu_invs_merge);
+
+/**
+ * arm_smmu_invs_unref() - Find in @invs for all entries in @to_unref, decrease
+ *                         the user counts without deletions
+ * @invs: the base invalidation array
+ * @to_unref: an array of invlidations to decrease their user counts
+ * @free_fn: A callback function to invoke, when an entry's user count reduces
+ *           to 0
+ *
+ * Return: the number of trash entries in the array, for arm_smmu_invs_purge()
+ *
+ * This function will not fail. Any entry with users=0 will be marked as trash.
+ * All tailing trash entries in the array will be dropped. And the size of the
+ * array will be trimmed properly. All trash entries in-between will remain in
+ * the @invs until being completely deleted by the next arm_smmu_invs_merge()
+ * or an arm_smmu_invs_purge() function call.
+ *
+ * This function must be locked and serialized with arm_smmu_invs_merge() and
+ * arm_smmu_invs_purge(), but do not lockdep on any mutex for KUNIT test.
+ *
+ * Note that the final @invs->num_invs might not reflect the actual number of
+ * invalidations due to trash entries. Any reader should take the read lock to
+ * iterate each entry and check its users counter till the last entry.
+ */
+VISIBLE_IF_KUNIT
+void arm_smmu_invs_unref(struct arm_smmu_invs *invs,
+			 struct arm_smmu_invs *to_unref,
+			 void (*free_fn)(struct arm_smmu_inv *inv))
+{
+	unsigned long flags;
+	size_t num_invs = 0;
+	size_t i, j;
+	int cmp;
+
+	arm_smmu_invs_for_each_cmp(invs, i, to_unref, j, cmp) {
+		if (cmp < 0) {
+			/* not found in to_unref, leave alone */
+			num_invs = i + 1;
+		} else if (cmp == 0) {
+			/* same item */
+			if (!refcount_dec_and_test(&invs->inv[i].users)) {
+				num_invs = i + 1;
+				continue;
+			}
+
+			/* KUNIT test doesn't pass in a free_fn */
+			if (free_fn)
+				free_fn(&invs->inv[i]);
+			invs->num_trashes++;
+		} else {
+			/* item in to_unref is not in invs or already a trash */
+			WARN_ON(true);
+		}
+	}
+
+	/* Exclude any tailing trash */
+	invs->num_trashes -= invs->num_invs - num_invs;
+
+	/* The lock is required to fence concurrent ATS operations. */
+	write_lock_irqsave(&invs->rwlock, flags);
+	WRITE_ONCE(invs->num_invs, num_invs); /* Remove tailing trash entries */
+	write_unlock_irqrestore(&invs->rwlock, flags);
+}
+EXPORT_SYMBOL_IF_KUNIT(arm_smmu_invs_unref);
+
+/**
+ * arm_smmu_invs_purge() - Purge all the trash entries in the @invs
+ * @invs: the base invalidation array
+ *
+ * Return: a newly allocated array on success removing all the trash entries, or
+ *         NULL if there is no trash entry in the array or there is a bug
+ *
+ * This function must be locked and serialized with arm_smmu_invs_merge() and
+ * arm_smmu_invs_unref(), but do not lockdep on any lock for KUNIT test.
+ *
+ * Caller is resposible for freeing the @invs and the returned new one.
+ */
+VISIBLE_IF_KUNIT
+struct arm_smmu_invs *arm_smmu_invs_purge(struct arm_smmu_invs *invs)
+{
+	struct arm_smmu_invs *new_invs;
+	struct arm_smmu_inv *inv;
+	size_t i, num_invs = 0;
+
+	if (WARN_ON(invs->num_invs < invs->num_trashes))
+		return NULL;
+	if (!invs->num_invs || !invs->num_trashes)
+		return NULL;
+
+	new_invs = arm_smmu_invs_alloc(invs->num_invs - invs->num_trashes);
+	if (!new_invs)
+		return ERR_PTR(-ENOMEM);
+
+	arm_smmu_invs_for_each_entry(invs, i, inv) {
+		new_invs->inv[num_invs] = *inv;
+		num_invs++;
+	}
+
+	WARN_ON(num_invs != new_invs->num_invs);
+	return new_invs;
+}
+EXPORT_SYMBOL_IF_KUNIT(arm_smmu_invs_purge);
+
 /* Context descriptor manipulation functions */
 void arm_smmu_tlb_inv_asid(struct arm_smmu_device *smmu, u16 asid)
 {
@@ -2462,13 +2712,21 @@ static bool arm_smmu_enforce_cache_coherency(struct iommu_domain *domain)
 struct arm_smmu_domain *arm_smmu_domain_alloc(void)
 {
 	struct arm_smmu_domain *smmu_domain;
+	struct arm_smmu_invs *new_invs;
 
 	smmu_domain = kzalloc(sizeof(*smmu_domain), GFP_KERNEL);
 	if (!smmu_domain)
 		return ERR_PTR(-ENOMEM);
 
+	new_invs = arm_smmu_invs_alloc(0);
+	if (!new_invs) {
+		kfree(smmu_domain);
+		return ERR_PTR(-ENOMEM);
+	}
+
 	INIT_LIST_HEAD(&smmu_domain->devices);
 	spin_lock_init(&smmu_domain->devices_lock);
+	rcu_assign_pointer(smmu_domain->invs, new_invs);
 
 	return smmu_domain;
 }
-- 
2.43.0



From nicolinc at nvidia.com  Mon Dec 15 18:09:34 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Mon, 15 Dec 2025 18:09:34 -0800
Subject: [PATCH v7 5/7] iommu/arm-smmu-v3: Populate smmu_domain->invs when attaching masters
In-Reply-To: <cover.1765850465.git.nicolinc@nvidia.com>
References: <cover.1765850465.git.nicolinc@nvidia.com>
Message-ID: <c8054b08a73214eb99a7e7cbe68fd19cb0eefc64.1765850465.git.nicolinc@nvidia.com>

Update the invs array with the invalidations required by each domain type
during attachment operations.

Only an SVA domain or a paging domain will have an invs array:
 a. SVA domain will add an INV_TYPE_S1_ASID per SMMU and an INV_TYPE_ATS
    per SID

 b. Non-nesting-parent paging domain with no ATS-enabled master will add
    a single INV_TYPE_S1_ASID or INV_TYPE_S2_VMID per SMMU

 c. Non-nesting-parent paging domain with ATS-enabled master(s) will do
    (b) and add an INV_TYPE_ATS per SID

 d. Nesting-parent paging domain will add an INV_TYPE_S2_VMID followed by
    an INV_TYPE_S2_VMID_S1_CLEAR per vSMMU. For an ATS-enabled master, it
    will add an INV_TYPE_ATS_FULL per SID

 Note that case #d prepares for a future implementation of VMID allocation
 which requires a followup series for S2 domain sharing. So when a nesting
 parent domain is attached through a vSMMU instance using a nested domain.
 VMID will be allocated per vSMMU instance v.s. currectly per S2 domain.

The per-domain invalidation is not needed until the domain is attached to
a master (when it starts to possibly use TLB). This will make it possible
to attach the domain to multiple SMMUs and avoid unnecessary invalidation
overhead during teardown if no STEs/CDs refer to the domain. It also means
that when the last device is detached, the old domain must flush its ASID
or VMID, since any new iommu_unmap() call would not trigger invalidations
given an empty domain->invs array.

Introduce some arm_smmu_invs helper functions for building scratch arrays,
preparing and installing old/new domain's invalidation arrays.

Co-developed-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h |  17 ++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 253 +++++++++++++++++++-
 2 files changed, 269 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index f98774962012..f8dc96476c43 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -1101,6 +1101,21 @@ static inline bool arm_smmu_master_canwbs(struct arm_smmu_master *master)
 	       IOMMU_FWSPEC_PCI_RC_CANWBS;
 }
 
+/**
+ * struct arm_smmu_inv_state - Per-domain invalidation array state
+ * @invs_ptr: points to the domain->invs (unwinding nesting/etc.) or is NULL if
+ *            no change should be made
+ * @old_invs: the original invs array
+ * @new_invs: for new domain, this is the new invs array to update domain->invs;
+ *            for old domain, this is the master->build_invs to pass in as the
+ *            to_unref argument to an arm_smmu_invs_unref() call
+ */
+struct arm_smmu_inv_state {
+	struct arm_smmu_invs __rcu **invs_ptr;
+	struct arm_smmu_invs *old_invs;
+	struct arm_smmu_invs *new_invs;
+};
+
 struct arm_smmu_attach_state {
 	/* Inputs */
 	struct iommu_domain *old_domain;
@@ -1110,6 +1125,8 @@ struct arm_smmu_attach_state {
 	ioasid_t ssid;
 	/* Resulting state */
 	struct arm_smmu_vmaster *vmaster;
+	struct arm_smmu_inv_state old_domain_invst;
+	struct arm_smmu_inv_state new_domain_invst;
 	bool ats_enabled;
 };
 
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index cc85e7a10ea8..9a2281b5d9da 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -3068,6 +3068,116 @@ static void arm_smmu_disable_iopf(struct arm_smmu_master *master,
 		iopf_queue_remove_device(master->smmu->evtq.iopf, master->dev);
 }
 
+static struct arm_smmu_inv *
+arm_smmu_master_build_inv(struct arm_smmu_master *master,
+			  enum arm_smmu_inv_type type, u32 id, ioasid_t ssid,
+			  size_t pgsize)
+{
+	struct arm_smmu_invs *build_invs = master->build_invs;
+	struct arm_smmu_inv *cur, inv = {
+		.smmu = master->smmu,
+		.type = type,
+		.id = id,
+		.pgsize = pgsize,
+	};
+
+	if (WARN_ON(build_invs->num_invs >= build_invs->max_invs))
+		return NULL;
+	cur = &build_invs->inv[build_invs->num_invs];
+	build_invs->num_invs++;
+
+	*cur = inv;
+	switch (type) {
+	case INV_TYPE_S1_ASID:
+		if (master->smmu->features & ARM_SMMU_FEAT_E2H) {
+			cur->size_opcode = CMDQ_OP_TLBI_EL2_VA;
+			cur->nsize_opcode = CMDQ_OP_TLBI_EL2_ASID;
+		} else {
+			cur->size_opcode = CMDQ_OP_TLBI_NH_VA;
+			cur->nsize_opcode = CMDQ_OP_TLBI_NH_ASID;
+		}
+		break;
+	case INV_TYPE_S2_VMID:
+		cur->size_opcode = CMDQ_OP_TLBI_S2_IPA;
+		cur->nsize_opcode = CMDQ_OP_TLBI_S12_VMALL;
+		break;
+	case INV_TYPE_S2_VMID_S1_CLEAR:
+		cur->size_opcode = cur->nsize_opcode = CMDQ_OP_TLBI_NH_ALL;
+		break;
+	case INV_TYPE_ATS:
+	case INV_TYPE_ATS_FULL:
+		cur->size_opcode = cur->nsize_opcode = CMDQ_OP_ATC_INV;
+		break;
+	}
+
+	return cur;
+}
+
+/*
+ * Use the preallocated scratch array at master->build_invs, to build a to_merge
+ * or to_unref array, to pass into a following arm_smmu_invs_merge/unref() call.
+ *
+ * Do not free the returned invs array. It is reused, and will be overwritten by
+ * the next arm_smmu_master_build_invs() call.
+ */
+static struct arm_smmu_invs *
+arm_smmu_master_build_invs(struct arm_smmu_master *master, bool ats_enabled,
+			   ioasid_t ssid, struct arm_smmu_domain *smmu_domain)
+{
+	const bool nesting = smmu_domain->nest_parent;
+	size_t pgsize = 0, i;
+
+	iommu_group_mutex_assert(master->dev);
+
+	master->build_invs->num_invs = 0;
+
+	/* Range-based invalidation requires the leaf pgsize for calculation */
+	if (master->smmu->features & ARM_SMMU_FEAT_RANGE_INV)
+		pgsize = __ffs(smmu_domain->domain.pgsize_bitmap);
+
+	switch (smmu_domain->stage) {
+	case ARM_SMMU_DOMAIN_SVA:
+	case ARM_SMMU_DOMAIN_S1:
+		if (!arm_smmu_master_build_inv(master, INV_TYPE_S1_ASID,
+					       smmu_domain->cd.asid,
+					       IOMMU_NO_PASID, pgsize))
+			return NULL;
+		break;
+	case ARM_SMMU_DOMAIN_S2:
+		if (!arm_smmu_master_build_inv(master, INV_TYPE_S2_VMID,
+					       smmu_domain->s2_cfg.vmid,
+					       IOMMU_NO_PASID, pgsize))
+			return NULL;
+		break;
+	default:
+		WARN_ON(true);
+		return NULL;
+	}
+
+	/* All the nested S1 ASIDs have to be flushed when S2 parent changes */
+	if (nesting) {
+		if (!arm_smmu_master_build_inv(
+			    master, INV_TYPE_S2_VMID_S1_CLEAR,
+			    smmu_domain->s2_cfg.vmid, IOMMU_NO_PASID, 0))
+			return NULL;
+	}
+
+	for (i = 0; ats_enabled && i < master->num_streams; i++) {
+		/*
+		 * If an S2 used as a nesting parent is changed we have no
+		 * option but to completely flush the ATC.
+		 */
+		if (!arm_smmu_master_build_inv(
+			    master, nesting ? INV_TYPE_ATS_FULL : INV_TYPE_ATS,
+			    master->streams[i].id, ssid, 0))
+			return NULL;
+	}
+
+	/* Note this build_invs must have been sorted */
+
+	return master->build_invs;
+}
+
 static void arm_smmu_remove_master_domain(struct arm_smmu_master *master,
 					  struct iommu_domain *domain,
 					  ioasid_t ssid)
@@ -3097,6 +3207,131 @@ static void arm_smmu_remove_master_domain(struct arm_smmu_master *master,
 	kfree(master_domain);
 }
 
+/*
+ * During attachment, the updates of the two domain->invs arrays are sequenced:
+ *  1. new domain updates its invs array, merging master->build_invs
+ *  2. new domain starts to include the master during its invalidation
+ *  3. master updates its STE switching from the old domain to the new domain
+ *  4. old domain still includes the master during its invalidation
+ *  5. old domain updates its invs array, unreferencing master->build_invs
+ *
+ * For 1 and 5, prepare the two updated arrays in advance, handling any changes
+ * that can possibly failure. So the actual update of either 1 or 5 won't fail.
+ * arm_smmu_asid_lock ensures that the old invs in the domains are intact while
+ * we are sequencing to update them.
+ */
+static int arm_smmu_attach_prepare_invs(struct arm_smmu_attach_state *state,
+					struct arm_smmu_domain *new_smmu_domain)
+{
+	struct arm_smmu_domain *old_smmu_domain =
+		to_smmu_domain_devices(state->old_domain);
+	struct arm_smmu_master *master = state->master;
+	ioasid_t ssid = state->ssid;
+
+	/*
+	 * At this point a NULL domain indicates the domain doesn't use the
+	 * IOTLB, see to_smmu_domain_devices().
+	 */
+	if (new_smmu_domain) {
+		struct arm_smmu_inv_state *invst = &state->new_domain_invst;
+		struct arm_smmu_invs *build_invs;
+
+		invst->invs_ptr = &new_smmu_domain->invs;
+		invst->old_invs = rcu_dereference_protected(
+			new_smmu_domain->invs,
+			lockdep_is_held(&arm_smmu_asid_lock));
+		build_invs = arm_smmu_master_build_invs(
+			master, state->ats_enabled, ssid, new_smmu_domain);
+		if (!build_invs)
+			return -EINVAL;
+
+		invst->new_invs =
+			arm_smmu_invs_merge(invst->old_invs, build_invs);
+		if (IS_ERR(invst->new_invs))
+			return PTR_ERR(invst->new_invs);
+	}
+
+	if (old_smmu_domain) {
+		struct arm_smmu_inv_state *invst = &state->old_domain_invst;
+
+		invst->invs_ptr = &old_smmu_domain->invs;
+		/* A re-attach case might have a different ats_enabled state */
+		if (new_smmu_domain == old_smmu_domain)
+			invst->old_invs = state->new_domain_invst.new_invs;
+		else
+			invst->old_invs = rcu_dereference_protected(
+				old_smmu_domain->invs,
+				lockdep_is_held(&arm_smmu_asid_lock));
+		/* For old_smmu_domain, new_invs points to master->build_invs */
+		invst->new_invs = arm_smmu_master_build_invs(
+			master, master->ats_enabled, ssid, old_smmu_domain);
+	}
+
+	return 0;
+}
+
+/* Must be installed before arm_smmu_install_ste_for_dev() */
+static void
+arm_smmu_install_new_domain_invs(struct arm_smmu_attach_state *state)
+{
+	struct arm_smmu_inv_state *invst = &state->new_domain_invst;
+
+	if (!invst->invs_ptr)
+		return;
+
+	rcu_assign_pointer(*invst->invs_ptr, invst->new_invs);
+	kfree_rcu(invst->old_invs, rcu);
+}
+
+/*
+ * When an array entry's users count reaches zero, it means the ASID/VMID is no
+ * longer being invalidated by map/unmap and must be cleaned. The rule is that
+ * all ASIDs/VMIDs not in an invalidation array are left cleared in the IOTLB.
+ */
+static void arm_smmu_inv_flush_iotlb_tag(struct arm_smmu_inv *inv)
+{
+	struct arm_smmu_cmdq_ent cmd = {};
+
+	switch (inv->type) {
+	case INV_TYPE_S1_ASID:
+		cmd.tlbi.asid = inv->id;
+		break;
+	case INV_TYPE_S2_VMID:
+		/* S2_VMID using nsize_opcode covers S2_VMID_S1_CLEAR */
+		cmd.tlbi.vmid = inv->id;
+		break;
+	default:
+		return;
+	}
+
+	cmd.opcode = inv->nsize_opcode;
+	arm_smmu_cmdq_issue_cmd_with_sync(inv->smmu, &cmd);
+}
+
+/* Should be installed after arm_smmu_install_ste_for_dev() */
+static void
+arm_smmu_install_old_domain_invs(struct arm_smmu_attach_state *state)
+{
+	struct arm_smmu_inv_state *invst = &state->old_domain_invst;
+	struct arm_smmu_invs *old_invs = invst->old_invs;
+	struct arm_smmu_invs *new_invs;
+
+	lockdep_assert_held(&arm_smmu_asid_lock);
+
+	if (!invst->invs_ptr)
+		return;
+
+	arm_smmu_invs_unref(old_invs, invst->new_invs,
+			    arm_smmu_inv_flush_iotlb_tag);
+
+	new_invs = arm_smmu_invs_purge(old_invs);
+	if (!new_invs)
+		return;
+
+	rcu_assign_pointer(*invst->invs_ptr, new_invs);
+	kfree_rcu(old_invs, rcu);
+}
+
 /*
  * Start the sequence to attach a domain to a master. The sequence contains three
  * steps:
@@ -3154,12 +3389,16 @@ int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state,
 				     arm_smmu_ats_supported(master);
 	}
 
+	ret = arm_smmu_attach_prepare_invs(state, smmu_domain);
+	if (ret)
+		return ret;
+
 	if (smmu_domain) {
 		if (new_domain->type == IOMMU_DOMAIN_NESTED) {
 			ret = arm_smmu_attach_prepare_vmaster(
 				state, to_smmu_nested_domain(new_domain));
 			if (ret)
-				return ret;
+				goto err_unprepare_invs;
 		}
 
 		master_domain = kzalloc(sizeof(*master_domain), GFP_KERNEL);
@@ -3207,6 +3446,8 @@ int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state,
 			atomic_inc(&smmu_domain->nr_ats_masters);
 		list_add(&master_domain->devices_elm, &smmu_domain->devices);
 		spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
+
+		arm_smmu_install_new_domain_invs(state);
 	}
 
 	if (!state->ats_enabled && master->ats_enabled) {
@@ -3226,6 +3467,8 @@ int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state,
 	kfree(master_domain);
 err_free_vmaster:
 	kfree(state->vmaster);
+err_unprepare_invs:
+	kfree(state->new_domain_invst.new_invs);
 	return ret;
 }
 
@@ -3257,6 +3500,7 @@ void arm_smmu_attach_commit(struct arm_smmu_attach_state *state)
 	}
 
 	arm_smmu_remove_master_domain(master, state->old_domain, state->ssid);
+	arm_smmu_install_old_domain_invs(state);
 	master->ats_enabled = state->ats_enabled;
 }
 
@@ -3438,12 +3682,19 @@ static int arm_smmu_blocking_set_dev_pasid(struct iommu_domain *new_domain,
 {
 	struct arm_smmu_domain *smmu_domain = to_smmu_domain(old_domain);
 	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
+	struct arm_smmu_attach_state state = {
+		.master = master,
+		.old_domain = old_domain,
+		.ssid = pasid,
+	};
 
 	mutex_lock(&arm_smmu_asid_lock);
+	arm_smmu_attach_prepare_invs(&state, NULL);
 	arm_smmu_clear_cd(master, pasid);
 	if (master->ats_enabled)
 		arm_smmu_atc_inv_master(master, pasid);
 	arm_smmu_remove_master_domain(master, &smmu_domain->domain, pasid);
+	arm_smmu_install_old_domain_invs(&state);
 	mutex_unlock(&arm_smmu_asid_lock);
 
 	/*
-- 
2.43.0



From nicolinc at nvidia.com  Mon Dec 15 18:09:35 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Mon, 15 Dec 2025 18:09:35 -0800
Subject: [PATCH v7 6/7] iommu/arm-smmu-v3: Add arm_smmu_invs based arm_smmu_domain_inv_range()
In-Reply-To: <cover.1765850465.git.nicolinc@nvidia.com>
References: <cover.1765850465.git.nicolinc@nvidia.com>
Message-ID: <f4261c5b30ce3c6942470433033d4933ec5eef3e.1765850465.git.nicolinc@nvidia.com>

Each smmu_domain now has an arm_smmu_invs that specifies the invalidation
steps to perform after any change the IOPTEs. This includes supports for
basic ASID/VMID, the special case for nesting, and ATC invalidations.

Introduce a new arm_smmu_domain_inv helper iterating smmu_domain->invs to
convert the invalidation array to commands. Any invalidation request with
no size specified means an entire flush over a range based one.

Take advantage of the sorted array to compatible batch operations together
to the same SMMU. For instance, ATC invaliations for multiple SIDs can be
pushed as a batch.

ATC invalidations must be completed before the driver disables ATS. Or the
device is permitted to ignore any racing invalidation that would cause an
SMMU timeout. The sequencing is done with a rwlock where holding the write
side of the rwlock means that there are no outstanding ATC invalidations.
If ATS is not used the rwlock is ignored, similar to the existing code.

Co-developed-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h |   9 +
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 236 ++++++++++++++++++--
 2 files changed, 232 insertions(+), 13 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index f8dc96476c43..c3fee7f14480 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -1086,6 +1086,15 @@ void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,
 int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain,
 			    unsigned long iova, size_t size);
 
+void arm_smmu_domain_inv_range(struct arm_smmu_domain *smmu_domain,
+			       unsigned long iova, size_t size,
+			       unsigned int granule, bool leaf);
+
+static inline void arm_smmu_domain_inv(struct arm_smmu_domain *smmu_domain)
+{
+	arm_smmu_domain_inv_range(smmu_domain, 0, 0, 0, false);
+}
+
 void __arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu,
 			      struct arm_smmu_cmdq *cmdq);
 int arm_smmu_init_one_queue(struct arm_smmu_device *smmu,
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 9a2281b5d9da..497dce3c1812 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2516,23 +2516,19 @@ static void arm_smmu_tlb_inv_context(void *cookie)
 	arm_smmu_atc_inv_domain(smmu_domain, 0, 0);
 }
 
-static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd,
-				     unsigned long iova, size_t size,
-				     size_t granule,
-				     struct arm_smmu_domain *smmu_domain)
+static void arm_smmu_cmdq_batch_add_range(struct arm_smmu_device *smmu,
+					  struct arm_smmu_cmdq_batch *cmds,
+					  struct arm_smmu_cmdq_ent *cmd,
+					  unsigned long iova, size_t size,
+					  size_t granule, size_t pgsize)
 {
-	struct arm_smmu_device *smmu = smmu_domain->smmu;
-	unsigned long end = iova + size, num_pages = 0, tg = 0;
+	unsigned long end = iova + size, num_pages = 0, tg = pgsize;
 	size_t inv_range = granule;
-	struct arm_smmu_cmdq_batch cmds;
 
 	if (!size)
 		return;
 
 	if (smmu->features & ARM_SMMU_FEAT_RANGE_INV) {
-		/* Get the leaf page size */
-		tg = __ffs(smmu_domain->domain.pgsize_bitmap);
-
 		num_pages = size >> tg;
 
 		/* Convert page size of 12,14,16 (log2) to 1,2,3 */
@@ -2552,8 +2548,6 @@ static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd,
 			num_pages++;
 	}
 
-	arm_smmu_cmdq_batch_init(smmu, &cmds, cmd);
-
 	while (iova < end) {
 		if (smmu->features & ARM_SMMU_FEAT_RANGE_INV) {
 			/*
@@ -2581,9 +2575,26 @@ static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd,
 		}
 
 		cmd->tlbi.addr = iova;
-		arm_smmu_cmdq_batch_add(smmu, &cmds, cmd);
+		arm_smmu_cmdq_batch_add(smmu, cmds, cmd);
 		iova += inv_range;
 	}
+}
+
+static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd,
+				     unsigned long iova, size_t size,
+				     size_t granule,
+				     struct arm_smmu_domain *smmu_domain)
+{
+	struct arm_smmu_device *smmu = smmu_domain->smmu;
+	struct arm_smmu_cmdq_batch cmds;
+	size_t pgsize;
+
+	/* Get the leaf page size */
+	pgsize = __ffs(smmu_domain->domain.pgsize_bitmap);
+
+	arm_smmu_cmdq_batch_init(smmu, &cmds, cmd);
+	arm_smmu_cmdq_batch_add_range(smmu, &cmds, cmd, iova, size, granule,
+				      pgsize);
 	arm_smmu_cmdq_batch_submit(smmu, &cmds);
 }
 
@@ -2639,6 +2650,193 @@ void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,
 	__arm_smmu_tlb_inv_range(&cmd, iova, size, granule, smmu_domain);
 }
 
+static bool arm_smmu_inv_size_too_big(struct arm_smmu_device *smmu, size_t size,
+				      size_t granule)
+{
+	size_t max_tlbi_ops;
+
+	/* 0 size means invalidate all */
+	if (!size || size == SIZE_MAX)
+		return true;
+
+	if (smmu->features & ARM_SMMU_FEAT_RANGE_INV)
+		return false;
+
+	/*
+	 * Borrowed from the MAX_TLBI_OPS in arch/arm64/include/asm/tlbflush.h,
+	 * this is used as a threshold to replace "size_opcode" commands with a
+	 * single "nsize_opcode" command, when SMMU doesn't implement the range
+	 * invalidation feature, where there can be too many per-granule TLBIs,
+	 * resulting in a soft lockup.
+	 */
+	max_tlbi_ops = 1 << (ilog2(granule) - 3);
+	return size >= max_tlbi_ops * granule;
+}
+
+/* Used by non INV_TYPE_ATS* invalidations */
+static void arm_smmu_inv_to_cmdq_batch(struct arm_smmu_inv *inv,
+				       struct arm_smmu_cmdq_batch *cmds,
+				       struct arm_smmu_cmdq_ent *cmd,
+				       unsigned long iova, size_t size,
+				       unsigned int granule)
+{
+	if (arm_smmu_inv_size_too_big(inv->smmu, size, granule)) {
+		cmd->opcode = inv->nsize_opcode;
+		arm_smmu_cmdq_batch_add(inv->smmu, cmds, cmd);
+		return;
+	}
+
+	cmd->opcode = inv->size_opcode;
+	arm_smmu_cmdq_batch_add_range(inv->smmu, cmds, cmd, iova, size, granule,
+				      inv->pgsize);
+}
+
+static inline bool arm_smmu_invs_end_batch(struct arm_smmu_inv *cur,
+					   struct arm_smmu_inv *next)
+{
+	/* Changing smmu means changing command queue */
+	if (cur->smmu != next->smmu)
+		return true;
+	/* The batch for S2 TLBI must be done before nested S1 ASIDs */
+	if (cur->type != INV_TYPE_S2_VMID_S1_CLEAR &&
+	    next->type == INV_TYPE_S2_VMID_S1_CLEAR)
+		return true;
+	/* ATS must be after a sync of the S1/S2 invalidations */
+	if (!arm_smmu_inv_is_ats(cur) && arm_smmu_inv_is_ats(next))
+		return true;
+	return false;
+}
+
+static void __arm_smmu_domain_inv_range(struct arm_smmu_invs *invs,
+					unsigned long iova, size_t size,
+					unsigned int granule, bool leaf)
+{
+	struct arm_smmu_cmdq_batch cmds = {};
+	struct arm_smmu_inv *cur;
+	struct arm_smmu_inv *end;
+
+	cur = invs->inv;
+	end = cur + READ_ONCE(invs->num_invs);
+	/* Skip any leading entry marked as a trash */
+	for (; cur != end; cur++)
+		if (refcount_read(&cur->users))
+			break;
+	while (cur != end) {
+		struct arm_smmu_device *smmu = cur->smmu;
+		struct arm_smmu_cmdq_ent cmd = {
+			/*
+			 * Pick size_opcode to run arm_smmu_get_cmdq(). This can
+			 * be changed to nsize_opcode, which would result in the
+			 * same CMDQ pointer.
+			 */
+			.opcode = cur->size_opcode,
+		};
+		struct arm_smmu_inv *next;
+
+		if (!cmds.num)
+			arm_smmu_cmdq_batch_init(smmu, &cmds, &cmd);
+
+		switch (cur->type) {
+		case INV_TYPE_S1_ASID:
+			cmd.tlbi.asid = cur->id;
+			cmd.tlbi.leaf = leaf;
+			arm_smmu_inv_to_cmdq_batch(cur, &cmds, &cmd, iova, size,
+						   granule);
+			break;
+		case INV_TYPE_S2_VMID:
+			cmd.tlbi.vmid = cur->id;
+			cmd.tlbi.leaf = leaf;
+			arm_smmu_inv_to_cmdq_batch(cur, &cmds, &cmd, iova, size,
+						   granule);
+			break;
+		case INV_TYPE_S2_VMID_S1_CLEAR:
+			/* CMDQ_OP_TLBI_S12_VMALL already flushed S1 entries */
+			if (arm_smmu_inv_size_too_big(cur->smmu, size, granule))
+				continue;
+			cmd.tlbi.vmid = cur->id;
+			arm_smmu_cmdq_batch_add(smmu, &cmds, &cmd);
+			break;
+		case INV_TYPE_ATS:
+			arm_smmu_atc_inv_to_cmd(cur->ssid, iova, size, &cmd);
+			cmd.atc.sid = cur->id;
+			arm_smmu_cmdq_batch_add(smmu, &cmds, &cmd);
+			break;
+		case INV_TYPE_ATS_FULL:
+			arm_smmu_atc_inv_to_cmd(IOMMU_NO_PASID, 0, 0, &cmd);
+			cmd.atc.sid = cur->id;
+			arm_smmu_cmdq_batch_add(smmu, &cmds, &cmd);
+			break;
+		default:
+			WARN_ON_ONCE(1);
+			continue;
+		}
+
+		/* Skip any trash entry in-between */
+		for (next = cur + 1; next != end; next++)
+			if (refcount_read(&next->users))
+				break;
+
+		if (cmds.num &&
+		    (next == end || arm_smmu_invs_end_batch(cur, next))) {
+			arm_smmu_cmdq_batch_submit(smmu, &cmds);
+			cmds.num = 0;
+		}
+		cur = next;
+	}
+}
+
+void arm_smmu_domain_inv_range(struct arm_smmu_domain *smmu_domain,
+			       unsigned long iova, size_t size,
+			       unsigned int granule, bool leaf)
+{
+	struct arm_smmu_invs *invs;
+
+	/*
+	 * An invalidation request must follow some IOPTE change and then load
+	 * an invalidation array. In the meantime, a domain attachment mutates
+	 * the array and then stores an STE/CD asking SMMU HW to acquire those
+	 * changed IOPTEs. In other word, these two are interdependent and can
+	 * race.
+	 *
+	 * In a race, the RCU design (with its underlying memory barriers) can
+	 * ensure the invalidation array to always get updated before loaded.
+	 *
+	 * smp_mb() is used here, paired with the smp_mb() following the array
+	 * update in a concurrent attach, to ensure:
+	 *  - HW sees the new IOPTEs if it walks after STE installation
+	 *  - Invalidation thread sees the updated array with the new ASID.
+	 *
+	 *  [CPU0]                        | [CPU1]
+	 *                                |
+	 *  change IOPTEs and TLB flush:  |
+	 *  arm_smmu_domain_inv_range() { | arm_smmu_install_new_domain_invs {
+	 *    ...                         |   rcu_assign_pointer(new_invs);
+	 *    smp_mb(); // ensure IOPTEs  |   smp_mb(); // ensure new_invs
+	 *    ...                         |   kfree_rcu(old_invs, rcu);
+	 *    // load invalidation array  | }
+	 *    invs = rcu_dereference();   | arm_smmu_install_ste_for_dev {
+	 *                                |   STE = TTB0 // read new IOPTEs
+	 */
+	smp_mb();
+
+	rcu_read_lock();
+	invs = rcu_dereference(smmu_domain->invs);
+
+	/*
+	 * Avoid locking unless ATS is being used. No ATC invalidation can be
+	 * going on after a domain is detached.
+	 */
+	if (invs->has_ats) {
+		read_lock(&invs->rwlock);
+		__arm_smmu_domain_inv_range(invs, iova, size, granule, leaf);
+		read_unlock(&invs->rwlock);
+	} else {
+		__arm_smmu_domain_inv_range(invs, iova, size, granule, leaf);
+	}
+
+	rcu_read_unlock();
+}
+
 static void arm_smmu_tlb_inv_page_nosync(struct iommu_iotlb_gather *gather,
 					 unsigned long iova, size_t granule,
 					 void *cookie)
@@ -3280,6 +3478,12 @@ arm_smmu_install_new_domain_invs(struct arm_smmu_attach_state *state)
 		return;
 
 	rcu_assign_pointer(*invst->invs_ptr, invst->new_invs);
+	/*
+	 * We are committed to updating the STE. Ensure the invalidation array
+	 * is visable to concurrent map/unmap threads, and acquire any racying
+	 * IOPTE updates.
+	 */
+	smp_mb();
 	kfree_rcu(invst->old_invs, rcu);
 }
 
@@ -3329,6 +3533,12 @@ arm_smmu_install_old_domain_invs(struct arm_smmu_attach_state *state)
 		return;
 
 	rcu_assign_pointer(*invst->invs_ptr, new_invs);
+	/*
+	 * We are committed to updating the STE. Ensure the invalidation array
+	 * is visable to concurrent map/unmap threads, and acquire any racying
+	 * IOPTE updates.
+	 */
+	smp_mb();
 	kfree_rcu(old_invs, rcu);
 }
 
-- 
2.43.0



From nicolinc at nvidia.com  Mon Dec 15 18:09:36 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Mon, 15 Dec 2025 18:09:36 -0800
Subject: [PATCH v7 7/7] iommu/arm-smmu-v3: Perform per-domain invalidations using arm_smmu_invs
In-Reply-To: <cover.1765850465.git.nicolinc@nvidia.com>
References: <cover.1765850465.git.nicolinc@nvidia.com>
Message-ID: <9693f4d9aecaaca553723cd20191f454b94f7417.1765850465.git.nicolinc@nvidia.com>

Replace the old invalidation functions with arm_smmu_domain_inv_range() in
all the existing invalidation routines. And deprecate the old functions.

The new arm_smmu_domain_inv_range() handles the CMDQ_MAX_TLBI_OPS as well,
so drop it in the SVA function.

Since arm_smmu_cmdq_batch_add_range() has only one caller now, and it must
be given a valid size, add a WARN_ON_ONCE to catch any missed case.

Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |   7 -
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c   |  29 +--
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 165 +-----------------
 3 files changed, 11 insertions(+), 190 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index c3fee7f14480..4f104c1baa67 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -1079,13 +1079,6 @@ int arm_smmu_set_pasid(struct arm_smmu_master *master,
 		       struct arm_smmu_domain *smmu_domain, ioasid_t pasid,
 		       struct arm_smmu_cd *cd, struct iommu_domain *old);
 
-void arm_smmu_tlb_inv_asid(struct arm_smmu_device *smmu, u16 asid);
-void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,
-				 size_t granule, bool leaf,
-				 struct arm_smmu_domain *smmu_domain);
-int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain,
-			    unsigned long iova, size_t size);
-
 void arm_smmu_domain_inv_range(struct arm_smmu_domain *smmu_domain,
 			       unsigned long iova, size_t size,
 			       unsigned int granule, bool leaf);
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index 440ad8cc07de..f1f8e01a7e91 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -122,15 +122,6 @@ void arm_smmu_make_sva_cd(struct arm_smmu_cd *target,
 }
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_make_sva_cd);
 
-/*
- * Cloned from the MAX_TLBI_OPS in arch/arm64/include/asm/tlbflush.h, this
- * is used as a threshold to replace per-page TLBI commands to issue in the
- * command queue with an address-space TLBI command, when SMMU w/o a range
- * invalidation feature handles too many per-page TLBI commands, which will
- * otherwise result in a soft lockup.
- */
-#define CMDQ_MAX_TLBI_OPS		(1 << (PAGE_SHIFT - 3))
-
 static void arm_smmu_mm_arch_invalidate_secondary_tlbs(struct mmu_notifier *mn,
 						struct mm_struct *mm,
 						unsigned long start,
@@ -146,21 +137,8 @@ static void arm_smmu_mm_arch_invalidate_secondary_tlbs(struct mmu_notifier *mn,
 	 * range. So do a simple translation here by calculating size correctly.
 	 */
 	size = end - start;
-	if (!(smmu_domain->smmu->features & ARM_SMMU_FEAT_RANGE_INV)) {
-		if (size >= CMDQ_MAX_TLBI_OPS * PAGE_SIZE)
-			size = 0;
-	} else {
-		if (size == ULONG_MAX)
-			size = 0;
-	}
-
-	if (!size)
-		arm_smmu_tlb_inv_asid(smmu_domain->smmu, smmu_domain->cd.asid);
-	else
-		arm_smmu_tlb_inv_range_asid(start, size, smmu_domain->cd.asid,
-					    PAGE_SIZE, false, smmu_domain);
 
-	arm_smmu_atc_inv_domain(smmu_domain, start, size);
+	arm_smmu_domain_inv_range(smmu_domain, start, size, PAGE_SIZE, false);
 }
 
 static void arm_smmu_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
@@ -191,8 +169,7 @@ static void arm_smmu_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
 	}
 	spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
 
-	arm_smmu_tlb_inv_asid(smmu_domain->smmu, smmu_domain->cd.asid);
-	arm_smmu_atc_inv_domain(smmu_domain, 0, 0);
+	arm_smmu_domain_inv(smmu_domain);
 }
 
 static void arm_smmu_mmu_notifier_free(struct mmu_notifier *mn)
@@ -302,7 +279,7 @@ static void arm_smmu_sva_domain_free(struct iommu_domain *domain)
 	/*
 	 * Ensure the ASID is empty in the iommu cache before allowing reuse.
 	 */
-	arm_smmu_tlb_inv_asid(smmu_domain->smmu, smmu_domain->cd.asid);
+	arm_smmu_domain_inv(smmu_domain);
 
 	/*
 	 * Notice that the arm_smmu_mm_arch_invalidate_secondary_tlbs op can
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 497dce3c1812..afe9b9ebd24b 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1266,16 +1266,6 @@ struct arm_smmu_invs *arm_smmu_invs_purge(struct arm_smmu_invs *invs)
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_invs_purge);
 
 /* Context descriptor manipulation functions */
-void arm_smmu_tlb_inv_asid(struct arm_smmu_device *smmu, u16 asid)
-{
-	struct arm_smmu_cmdq_ent cmd = {
-		.opcode	= smmu->features & ARM_SMMU_FEAT_E2H ?
-			CMDQ_OP_TLBI_EL2_ASID : CMDQ_OP_TLBI_NH_ASID,
-		.tlbi.asid = asid,
-	};
-
-	arm_smmu_cmdq_issue_cmd_with_sync(smmu, &cmd);
-}
 
 /*
  * Based on the value of ent report which bits of the STE the HW will access. It
@@ -2430,74 +2420,10 @@ static int arm_smmu_atc_inv_master(struct arm_smmu_master *master,
 	return arm_smmu_cmdq_batch_submit(master->smmu, &cmds);
 }
 
-int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain,
-			    unsigned long iova, size_t size)
-{
-	struct arm_smmu_master_domain *master_domain;
-	int i;
-	unsigned long flags;
-	struct arm_smmu_cmdq_ent cmd = {
-		.opcode = CMDQ_OP_ATC_INV,
-	};
-	struct arm_smmu_cmdq_batch cmds;
-
-	if (!(smmu_domain->smmu->features & ARM_SMMU_FEAT_ATS))
-		return 0;
-
-	/*
-	 * Ensure that we've completed prior invalidation of the main TLBs
-	 * before we read 'nr_ats_masters' in case of a concurrent call to
-	 * arm_smmu_enable_ats():
-	 *
-	 *	// unmap()			// arm_smmu_enable_ats()
-	 *	TLBI+SYNC			atomic_inc(&nr_ats_masters);
-	 *	smp_mb();			[...]
-	 *	atomic_read(&nr_ats_masters);	pci_enable_ats() // writel()
-	 *
-	 * Ensures that we always see the incremented 'nr_ats_masters' count if
-	 * ATS was enabled at the PCI device before completion of the TLBI.
-	 */
-	smp_mb();
-	if (!atomic_read(&smmu_domain->nr_ats_masters))
-		return 0;
-
-	arm_smmu_cmdq_batch_init(smmu_domain->smmu, &cmds, &cmd);
-
-	spin_lock_irqsave(&smmu_domain->devices_lock, flags);
-	list_for_each_entry(master_domain, &smmu_domain->devices,
-			    devices_elm) {
-		struct arm_smmu_master *master = master_domain->master;
-
-		if (!master->ats_enabled)
-			continue;
-
-		if (master_domain->nested_ats_flush) {
-			/*
-			 * If a S2 used as a nesting parent is changed we have
-			 * no option but to completely flush the ATC.
-			 */
-			arm_smmu_atc_inv_to_cmd(IOMMU_NO_PASID, 0, 0, &cmd);
-		} else {
-			arm_smmu_atc_inv_to_cmd(master_domain->ssid, iova, size,
-						&cmd);
-		}
-
-		for (i = 0; i < master->num_streams; i++) {
-			cmd.atc.sid = master->streams[i].id;
-			arm_smmu_cmdq_batch_add(smmu_domain->smmu, &cmds, &cmd);
-		}
-	}
-	spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
-
-	return arm_smmu_cmdq_batch_submit(smmu_domain->smmu, &cmds);
-}
-
 /* IO_PGTABLE API */
 static void arm_smmu_tlb_inv_context(void *cookie)
 {
 	struct arm_smmu_domain *smmu_domain = cookie;
-	struct arm_smmu_device *smmu = smmu_domain->smmu;
-	struct arm_smmu_cmdq_ent cmd;
 
 	/*
 	 * NOTE: when io-pgtable is in non-strict mode, we may get here with
@@ -2506,14 +2432,7 @@ static void arm_smmu_tlb_inv_context(void *cookie)
 	 * insertion to guarantee those are observed before the TLBI. Do be
 	 * careful, 007.
 	 */
-	if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
-		arm_smmu_tlb_inv_asid(smmu, smmu_domain->cd.asid);
-	} else {
-		cmd.opcode	= CMDQ_OP_TLBI_S12_VMALL;
-		cmd.tlbi.vmid	= smmu_domain->s2_cfg.vmid;
-		arm_smmu_cmdq_issue_cmd_with_sync(smmu, &cmd);
-	}
-	arm_smmu_atc_inv_domain(smmu_domain, 0, 0);
+	arm_smmu_domain_inv(smmu_domain);
 }
 
 static void arm_smmu_cmdq_batch_add_range(struct arm_smmu_device *smmu,
@@ -2525,7 +2444,7 @@ static void arm_smmu_cmdq_batch_add_range(struct arm_smmu_device *smmu,
 	unsigned long end = iova + size, num_pages = 0, tg = pgsize;
 	size_t inv_range = granule;
 
-	if (!size)
+	if (WARN_ON_ONCE(!size))
 		return;
 
 	if (smmu->features & ARM_SMMU_FEAT_RANGE_INV) {
@@ -2580,76 +2499,6 @@ static void arm_smmu_cmdq_batch_add_range(struct arm_smmu_device *smmu,
 	}
 }
 
-static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd,
-				     unsigned long iova, size_t size,
-				     size_t granule,
-				     struct arm_smmu_domain *smmu_domain)
-{
-	struct arm_smmu_device *smmu = smmu_domain->smmu;
-	struct arm_smmu_cmdq_batch cmds;
-	size_t pgsize;
-
-	/* Get the leaf page size */
-	pgsize = __ffs(smmu_domain->domain.pgsize_bitmap);
-
-	arm_smmu_cmdq_batch_init(smmu, &cmds, cmd);
-	arm_smmu_cmdq_batch_add_range(smmu, &cmds, cmd, iova, size, granule,
-				      pgsize);
-	arm_smmu_cmdq_batch_submit(smmu, &cmds);
-}
-
-static void arm_smmu_tlb_inv_range_domain(unsigned long iova, size_t size,
-					  size_t granule, bool leaf,
-					  struct arm_smmu_domain *smmu_domain)
-{
-	struct arm_smmu_cmdq_ent cmd = {
-		.tlbi = {
-			.leaf	= leaf,
-		},
-	};
-
-	if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
-		cmd.opcode	= smmu_domain->smmu->features & ARM_SMMU_FEAT_E2H ?
-				  CMDQ_OP_TLBI_EL2_VA : CMDQ_OP_TLBI_NH_VA;
-		cmd.tlbi.asid	= smmu_domain->cd.asid;
-	} else {
-		cmd.opcode	= CMDQ_OP_TLBI_S2_IPA;
-		cmd.tlbi.vmid	= smmu_domain->s2_cfg.vmid;
-	}
-	__arm_smmu_tlb_inv_range(&cmd, iova, size, granule, smmu_domain);
-
-	if (smmu_domain->nest_parent) {
-		/*
-		 * When the S2 domain changes all the nested S1 ASIDs have to be
-		 * flushed too.
-		 */
-		cmd.opcode = CMDQ_OP_TLBI_NH_ALL;
-		arm_smmu_cmdq_issue_cmd_with_sync(smmu_domain->smmu, &cmd);
-	}
-
-	/*
-	 * Unfortunately, this can't be leaf-only since we may have
-	 * zapped an entire table.
-	 */
-	arm_smmu_atc_inv_domain(smmu_domain, iova, size);
-}
-
-void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,
-				 size_t granule, bool leaf,
-				 struct arm_smmu_domain *smmu_domain)
-{
-	struct arm_smmu_cmdq_ent cmd = {
-		.opcode	= smmu_domain->smmu->features & ARM_SMMU_FEAT_E2H ?
-			  CMDQ_OP_TLBI_EL2_VA : CMDQ_OP_TLBI_NH_VA,
-		.tlbi = {
-			.asid	= asid,
-			.leaf	= leaf,
-		},
-	};
-
-	__arm_smmu_tlb_inv_range(&cmd, iova, size, granule, smmu_domain);
-}
-
 static bool arm_smmu_inv_size_too_big(struct arm_smmu_device *smmu, size_t size,
 				      size_t granule)
 {
@@ -2850,7 +2699,9 @@ static void arm_smmu_tlb_inv_page_nosync(struct iommu_iotlb_gather *gather,
 static void arm_smmu_tlb_inv_walk(unsigned long iova, size_t size,
 				  size_t granule, void *cookie)
 {
-	arm_smmu_tlb_inv_range_domain(iova, size, granule, false, cookie);
+	struct arm_smmu_domain *smmu_domain = cookie;
+
+	arm_smmu_domain_inv_range(smmu_domain, iova, size, granule, false);
 }
 
 static const struct iommu_flush_ops arm_smmu_flush_ops = {
@@ -4123,9 +3974,9 @@ static void arm_smmu_iotlb_sync(struct iommu_domain *domain,
 	if (!gather->pgsize)
 		return;
 
-	arm_smmu_tlb_inv_range_domain(gather->start,
-				      gather->end - gather->start + 1,
-				      gather->pgsize, true, smmu_domain);
+	arm_smmu_domain_inv_range(smmu_domain, gather->start,
+				  gather->end - gather->start + 1,
+				  gather->pgsize, true);
 }
 
 static phys_addr_t
-- 
2.43.0



From robh at kernel.org  Mon Dec 15 18:18:47 2025
From: robh at kernel.org (Rob Herring)
Date: Mon, 15 Dec 2025 20:18:47 -0600
Subject: [PATCH] dt-bindings: PCI: socionext,uniphier-pcie: Fix interrupt
 controller node name
In-Reply-To: <3f1b7852-1494-4a73-8783-b578f9ad5d40@socionext.com>
References: <20251215212456.3317558-1-robh@kernel.org> <3f1b7852-1494-4a73-8783-b578f9ad5d40@socionext.com>
Message-ID: <CAL_JsqJKpQRMEac4e1T-s+6HWbR9mOZXRQCHVeTCnHqJYa=TYg@mail.gmail.com>

On Mon, Dec 15, 2025 at 7:21?PM Kunihiko Hayashi
<hayashi.kunihiko at socionext.com> wrote:
>
> Hi Rob,
>
> Thank you for pointing out.
>
> On 2025/12/16 6:24, Rob Herring (Arm) wrote:
> > The child node name in use by .dts files and the driver is
> > "legacy-interrupt-controller", not "interrupt-controller".
> After your change commit bcd7ec2cd720 were merged, it was a long time
> before I realized I needed to fix it.
>
> "interrupt-controller" is included in the list of Generic Names
> Recommendation. Would it be better to apply (i.e. restore) this,
> or fix the PCI driver and .dts?

It's an ABI. So we are stuck with it or have to support both names in
the driver forever (and backport the driver change).

Rob


From ping.bai at nxp.com  Mon Dec 15 18:26:54 2025
From: ping.bai at nxp.com (Jacky Bai)
Date: Tue, 16 Dec 2025 02:26:54 +0000
Subject: [PATCH] remoteproc: imx_rproc: Ues sync handling in rx_callback
 for i.MX7ULP suspend
In-Reply-To: <aUAzaXp1t+fTVfyT@lizhi-Precision-Tower-5810>
References: <20251215-imx7ulp_rproc-v1-1-4e96cebc4bc6@nxp.com>
 <aUAzaXp1t+fTVfyT@lizhi-Precision-Tower-5810>
Message-ID: <VE1PR04MB721317F24C6F99F7468DE02B87AAA@VE1PR04MB7213.eurprd04.prod.outlook.com>

Hi Frank,

> Subject: Re: [PATCH] remoteproc: imx_rproc: Ues sync handling in rx_callback
> for i.MX7ULP suspend
> 
> On Mon, Dec 15, 2025 at 03:26:05PM +0800, Jacky Bai wrote:
> > On i.MX7ULP platform, certain drivers that depend on rpmsg may need to
> > send an rpmsg request and receive an acknowledgment from the remote
> > core during the late_suspend stage. In the current imx_rproc
> > implementation, rx_callback defers message handling to a workqueue.
> > However, this deferred work may not execute before the system enters
> > the noirq_suspend stage. When that happens, pending mailbox IRQs will
> > cause the suspend sequence to abort.
> >
> > To address this, handle incoming messages synchronously within
> > rx_callback when running on i.MX7ULP. This ensures the message is
> > processed immediately, allows the mailbox IRQ to be cleared in time,
> > and prevents suspend failures.
> >
> > Signed-off-by: Jacky Bai <ping.bai at nxp.com>
> > ---
> >  drivers/remoteproc/imx_rproc.c | 49
> > ++++++++++++++++++++++++++++++++++++++++--
> >  drivers/remoteproc/imx_rproc.h |  1 +
> >  2 files changed, 48 insertions(+), 2 deletions(-)
> >
> ...
> >
> > -	queue_work(priv->workqueue, &priv->rproc_work);
> > +	if (priv->use_sync_rx)
> > +		idr_for_each(&rproc->notifyids, imx_rproc_notified_idr_cb, rproc);
> > +	else
> > +		queue_work(priv->workqueue, &priv->rproc_work);
> >  }
> >
> >  static int imx_rproc_xtr_mbox_init(struct rproc *rproc, bool
> > tx_block) @@ -1009,6 +1015,38 @@ static int
> imx_rproc_sys_off_handler(struct sys_off_data *data)
> >  	return NOTIFY_DONE;
> >  }
> >
> > +static int imx_rproc_pm_notify(struct notifier_block *nb,
> > +	unsigned long action, void *data)
> > +{
> > +	int ret;
> > +	struct imx_rproc *priv = container_of(nb, struct imx_rproc, pm_nb);
> 
> 	struct imx_rproc *priv = container_of(nb, struct imx_rproc, pm_nb);
> 	int ret;
> 
> > +
> > +	imx_rproc_free_mbox(priv->rproc);
> > +
> > +	switch (action) {
> > +	case PM_SUSPEND_PREPARE:
> > +		ret = imx_rproc_xtr_mbox_init(priv->rproc, false);
> 
> Any risk condition if on going message during free() and _init()?

After some further investigation, changes in remoteproc is too complex and many corner case
to handle. Plan to solve the issue directly from mailbox driver. Please ignore this patch.

Thx for your time.

BR
Jacky Bai
> 
> > +		if (ret) {
> > +			dev_err(&priv->rproc->dev, "Failed to request non-blocking
> mbox\n");
> > +			return NOTIFY_BAD;
> > +		}
> > +		priv->use_sync_rx = true;
> > +		break;
> > +	case PM_POST_SUSPEND:
> > +		ret = imx_rproc_xtr_mbox_init(priv->rproc, true);
> > +		if (ret) {
> > +			dev_err(&priv->rproc->dev, "Failed to request blocking
> mbox\n");
> > +			return NOTIFY_BAD;
> > +		}
> > +		priv->use_sync_rx = false;
> > +		break;
> > +	default:
> > +		break;
> 
> imx_rproc_free_mbox() here? if other notify comming,  mbox is free() as
> expected?
> 
> Frank
> > +	}
> > +
> > +	return NOTIFY_OK;
> > +}
> > +
> >  static void imx_rproc_destroy_workqueue(void *data)  {
> >  	struct workqueue_struct *workqueue = data; @@ -1103,6 +1141,13
> @@
> > static int imx_rproc_probe(struct platform_device *pdev)
> >  			return dev_err_probe(dev, ret, "register restart handler
> failure\n");
> >  	}
> >
> > +	if (dcfg->flags & IMX_RPROC_NEED_PM_SYNC) {
> > +		priv->pm_nb.notifier_call = imx_rproc_pm_notify;
> > +		ret = register_pm_notifier(&priv->pm_nb);
> > +		if (ret)
> > +			return dev_err_probe(dev, ret, "register pm notifier failure\n");
> > +	}
> > +
> >  	pm_runtime_enable(dev);
> >  	ret = pm_runtime_resume_and_get(dev);
> >  	if (ret)
> > @@ -1202,7 +1247,7 @@ static const struct imx_rproc_dcfg
> > imx_rproc_cfg_imx8ulp = {  static const struct imx_rproc_dcfg
> imx_rproc_cfg_imx7ulp = {
> >  	.att		= imx_rproc_att_imx7ulp,
> >  	.att_size	= ARRAY_SIZE(imx_rproc_att_imx7ulp),
> > -	.flags		= IMX_RPROC_NEED_SYSTEM_OFF,
> > +	.flags		= IMX_RPROC_NEED_SYSTEM_OFF |
> IMX_RPROC_NEED_PM_SYNC,
> >  };
> >
> >  static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = { diff --git
> > a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h
> > index
> >
> 1b2d9f4d6d19dcdc215be97f7e2ab3488281916a..0e3e460cef4ed9340fb4977
> 183e0
> > 3143c84764af 100644
> > --- a/drivers/remoteproc/imx_rproc.h
> > +++ b/drivers/remoteproc/imx_rproc.h
> > @@ -18,6 +18,7 @@ struct imx_rproc_att {
> >  /* dcfg flags */
> >  #define IMX_RPROC_NEED_SYSTEM_OFF	BIT(0)
> >  #define IMX_RPROC_NEED_CLKS		BIT(1)
> > +#define IMX_RPROC_NEED_PM_SYNC		BIT(2)
> >
> >  struct imx_rproc_plat_ops {
> >  	int (*start)(struct rproc *rproc);
> >
> > ---
> > base-commit: 5ce74bc1b7cb2732b22f9c93082545bc655d6547
> > change-id: 20251211-imx7ulp_rproc-57999329239b
> >
> > Best regards,
> > --
> > Jacky Bai <ping.bai at nxp.com>
> >


From ping.bai at nxp.com  Mon Dec 15 18:29:03 2025
From: ping.bai at nxp.com (Jacky Bai)
Date: Tue, 16 Dec 2025 02:29:03 +0000
Subject: [PATCH] remoteproc: imx_rproc: Ues sync handling in rx_callback
 for i.MX7ULP suspend
In-Reply-To: <8c00c09f-da9e-4630-a3d7-586ed29116f3@nxp.com>
References: <20251215-imx7ulp_rproc-v1-1-4e96cebc4bc6@nxp.com>
 <8c00c09f-da9e-4630-a3d7-586ed29116f3@nxp.com>
Message-ID: <VE1PR04MB72132DBDCD7422B546A2BD3B87AAA@VE1PR04MB7213.eurprd04.prod.outlook.com>

HI Luliana,

> Subject: Re: [PATCH] remoteproc: imx_rproc: Ues sync handling in rx_callback
> for i.MX7ULP suspend
> 
> On 12/15/2025 9:26 AM, Jacky Bai wrote:
> > On i.MX7ULP platform, certain drivers that depend on rpmsg may need to
> > send an rpmsg request and receive an acknowledgment from the remote
> > core during the late_suspend stage. In the current imx_rproc
> > implementation, rx_callback defers message handling to a workqueue.
> > However, this deferred work may not execute before the system enters
> > the noirq_suspend stage. When that happens, pending mailbox IRQs will
> > cause the suspend sequence to abort.
> >
> > To address this, handle incoming messages synchronously within
> > rx_callback when running on i.MX7ULP. This ensures the message is
> > processed immediately, allows the mailbox IRQ to be cleared in time,
> > and prevents suspend failures.
> >
> > Signed-off-by: Jacky Bai <ping.bai at nxp.com>
> > ---
> >   drivers/remoteproc/imx_rproc.c | 49
> ++++++++++++++++++++++++++++++++++++++++--
> >   drivers/remoteproc/imx_rproc.h |  1 +
> >   2 files changed, 48 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/remoteproc/imx_rproc.c
> > b/drivers/remoteproc/imx_rproc.c index
> >
> 3be8790c14a2ccc789dd40508ec274000ec09978..1127c56388fd94f296c80db
> 5c01a
> > 5d431d669c4d 100644
> > --- a/drivers/remoteproc/imx_rproc.c
> > +++ b/drivers/remoteproc/imx_rproc.c
> > @@ -22,6 +22,7 @@
> >   #include <linux/reboot.h>
> >   #include <linux/regmap.h>
> >   #include <linux/remoteproc.h>
> > +#include <linux/suspend.h>
> >   #include <linux/workqueue.h>
> >
> >   #include "imx_rproc.h"
> > @@ -111,11 +112,13 @@ struct imx_rproc {
> >   	void __iomem			*rsc_table;
> >   	struct imx_sc_ipc		*ipc_handle;
> >   	struct notifier_block		rproc_nb;
> > +	struct notifier_block		pm_nb;
> >   	u32				rproc_pt;	/* partition id */
> >   	u32				rsrc_id;	/* resource id */
> >   	u32				entry;		/* cpu start address */
> >   	u32				core_index;
> >   	struct dev_pm_domain_list	*pd_list;
> > +	bool				use_sync_rx;
> >   };
> >
> >   static const struct imx_rproc_att imx_rproc_att_imx93[] = { @@
> > -725,7 +728,10 @@ static void imx_rproc_rx_callback(struct mbox_client
> *cl, void *msg)
> >   	struct rproc *rproc = dev_get_drvdata(cl->dev);
> >   	struct imx_rproc *priv = rproc->priv;
> >
> > -	queue_work(priv->workqueue, &priv->rproc_work);
> > +	if (priv->use_sync_rx)
> > +		idr_for_each(&rproc->notifyids, imx_rproc_notified_idr_cb, rproc);
> > +	else
> > +		queue_work(priv->workqueue, &priv->rproc_work);
> >   }
> >
> >   static int imx_rproc_xtr_mbox_init(struct rproc *rproc, bool
> > tx_block) @@ -1009,6 +1015,38 @@ static int
> imx_rproc_sys_off_handler(struct sys_off_data *data)
> >   	return NOTIFY_DONE;
> >   }
> >
> > +static int imx_rproc_pm_notify(struct notifier_block *nb,
> > +	unsigned long action, void *data)
> > +{
> > +	int ret;
> > +	struct imx_rproc *priv = container_of(nb, struct imx_rproc, pm_nb);
> > +
> > +	imx_rproc_free_mbox(priv->rproc);
> 
> Here you free mailbox unconditinally.

Please ignore this patch, changes is not perfect and too complex. Will try to
Fix the issue from mailbox.

Thx for your comments.

BR
Jacky Bai
> > +
> > +	switch (action) {
> > +	case PM_SUSPEND_PREPARE:
> 
> When switching to sync mode, any pending work in the workqueue should be
> flushed to avoid processing messages twice.
> > +		ret = imx_rproc_xtr_mbox_init(priv->rproc, false);
> > +		if (ret) {
> > +			dev_err(&priv->rproc->dev, "Failed to request non-blocking
> mbox\n");
> > +			return NOTIFY_BAD;
> > +		}
> > +		priv->use_sync_rx = true;
> > +		break;
> > +	case PM_POST_SUSPEND:
> > +		ret = imx_rproc_xtr_mbox_init(priv->rproc, true);
> > +		if (ret) {
> > +			dev_err(&priv->rproc->dev, "Failed to request blocking
> mbox\n");
> > +			return NOTIFY_BAD;
> > +		}
> 
> If imx_rproc_xtr_mbox_init() fails in either case, the mailbox channels remain
> freed but the function returns NOTIFY_BAD. The system may continue with
> freed mailbox channels.
> 
> Only free the mailbox if re-initialization succeeds, or ensure proper cleanup on
> failure.
> 
> > +		priv->use_sync_rx = false;
> > +		break;
> > +	default:
> > +		break;
> > +	}
> > +
> > +	return NOTIFY_OK;
> > +}
> > +
> >   static void imx_rproc_destroy_workqueue(void *data)
> >   {
> >   	struct workqueue_struct *workqueue = data; @@ -1103,6
> +1141,13 @@
> > static int imx_rproc_probe(struct platform_device *pdev)
> >   			return dev_err_probe(dev, ret, "register restart handler
> failure\n");
> >   	}
> >
> > +	if (dcfg->flags & IMX_RPROC_NEED_PM_SYNC) {
> > +		priv->pm_nb.notifier_call = imx_rproc_pm_notify;
> > +		ret = register_pm_notifier(&priv->pm_nb);
> > +		if (ret)
> > +			return dev_err_probe(dev, ret, "register pm notifier failure\n");
> > +	}
> > +
> 
> The PM notifier is registered in probe but never unregistered in remove or
> error paths.
> 
> Thanks,
> Iulia
> 
> >   	pm_runtime_enable(dev);
> >   	ret = pm_runtime_resume_and_get(dev);
> >   	if (ret)
> > @@ -1202,7 +1247,7 @@ static const struct imx_rproc_dcfg
> imx_rproc_cfg_imx8ulp = {
> >   static const struct imx_rproc_dcfg imx_rproc_cfg_imx7ulp = {
> >   	.att		= imx_rproc_att_imx7ulp,
> >   	.att_size	= ARRAY_SIZE(imx_rproc_att_imx7ulp),
> > -	.flags		= IMX_RPROC_NEED_SYSTEM_OFF,
> > +	.flags		= IMX_RPROC_NEED_SYSTEM_OFF |
> IMX_RPROC_NEED_PM_SYNC,
> >   };
> >
> >   static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = { diff
> > --git a/drivers/remoteproc/imx_rproc.h
> > b/drivers/remoteproc/imx_rproc.h index
> >
> 1b2d9f4d6d19dcdc215be97f7e2ab3488281916a..0e3e460cef4ed9340fb4977
> 183e0
> > 3143c84764af 100644
> > --- a/drivers/remoteproc/imx_rproc.h
> > +++ b/drivers/remoteproc/imx_rproc.h
> > @@ -18,6 +18,7 @@ struct imx_rproc_att {
> >   /* dcfg flags */
> >   #define IMX_RPROC_NEED_SYSTEM_OFF	BIT(0)
> >   #define IMX_RPROC_NEED_CLKS		BIT(1)
> > +#define IMX_RPROC_NEED_PM_SYNC		BIT(2)
> >
> >   struct imx_rproc_plat_ops {
> >   	int (*start)(struct rproc *rproc);
> >
> > ---
> > base-commit: 5ce74bc1b7cb2732b22f9c93082545bc655d6547
> > change-id: 20251211-imx7ulp_rproc-57999329239b
> >
> > Best regards,


From zhentao.guo at amlogic.com  Mon Dec 15 18:36:17 2025
From: zhentao.guo at amlogic.com (Zhentao Guo)
Date: Tue, 16 Dec 2025 10:36:17 +0800
Subject: [PATCH RFC v2 2/3] decoder: Add V4L2 stateless H.264 decoder
 driver
In-Reply-To: <04287d0b6207c98f24112b492b9ee52f0889da39.camel@ndufresne.ca>
References: <20251124-b4-s4-vdec-upstream-v2-0-bdbbce3f11a6@amlogic.com>
 <20251124-b4-s4-vdec-upstream-v2-2-bdbbce3f11a6@amlogic.com>
 <9b74086ac938475328904960add2c284b81efd4a.camel@ndufresne.ca>
 <12f26bf8-409b-4206-a39b-4bb2a14edec0@amlogic.com>
 <f9c113914290a0701614c64b5e2167d4b3e21646.camel@ndufresne.ca>
 <9ab31529-8146-4ca7-8389-04c69f7d1b49@amlogic.com>
 <04287d0b6207c98f24112b492b9ee52f0889da39.camel@ndufresne.ca>
Message-ID: <3b3f890c-2649-4a29-a620-203d4a72688e@amlogic.com>


? 2025/12/15 21:58, Nicolas Dufresne ??:
> Le lundi 15 d?cembre 2025 ? 10:15 +0800, Zhentao Guo a ?crit?:
>> ? 2025/12/12 21:51, Nicolas Dufresne ??:
>>> Hi,
>>>
>>> Le vendredi 12 d?cembre 2025 ? 12:11 +0800, Zhentao Guo a ?crit?:
>>>>> strcpy() would be the preferred helper for this, no need to fill the
>>>>> leading
>>>>> zero liek this, see include/linux/string.h
>>>> Ok, it should be more suitable to use strcpy.
>>> I have to correct myself, I meant to suggest strscpy(dst, src, size).
>>> Passing
>>> the size for safety seems important, and unlike strncpy() it takes care of
>>> the
>>> leading zero.
>> Yes, we use strscpy() for copying all the strings.
> Indeed, I had miss-read, then you simply need to remove the code you added to
> force the last byte to be 0, this is not needed with that function.
Yes, I checked the function strscpy too. It will add the \0 if the 
parameter 'size' is proper. We will remove this step in our code.
> Nicolas
>
>>> Nicolas
>> Thanks
>>
>> Zhentao


From zhentao.guo at amlogic.com  Mon Dec 15 18:36:27 2025
From: zhentao.guo at amlogic.com (Zhentao Guo)
Date: Tue, 16 Dec 2025 10:36:27 +0800
Subject: [PATCH RFC v2 2/3] decoder: Add V4L2 stateless H.264 decoder
 driver
In-Reply-To: <04287d0b6207c98f24112b492b9ee52f0889da39.camel@ndufresne.ca>
References: <20251124-b4-s4-vdec-upstream-v2-0-bdbbce3f11a6@amlogic.com>
 <20251124-b4-s4-vdec-upstream-v2-2-bdbbce3f11a6@amlogic.com>
 <9b74086ac938475328904960add2c284b81efd4a.camel@ndufresne.ca>
 <12f26bf8-409b-4206-a39b-4bb2a14edec0@amlogic.com>
 <f9c113914290a0701614c64b5e2167d4b3e21646.camel@ndufresne.ca>
 <9ab31529-8146-4ca7-8389-04c69f7d1b49@amlogic.com>
 <04287d0b6207c98f24112b492b9ee52f0889da39.camel@ndufresne.ca>
Message-ID: <d8011eea-5073-4619-8ba2-05a2a3f251df@amlogic.com>


? 2025/12/15 21:58, Nicolas Dufresne ??:
> Le lundi 15 d?cembre 2025 ? 10:15 +0800, Zhentao Guo a ?crit?:
>> ? 2025/12/12 21:51, Nicolas Dufresne ??:
>>> Hi,
>>>
>>> Le vendredi 12 d?cembre 2025 ? 12:11 +0800, Zhentao Guo a ?crit?:
>>>>> strcpy() would be the preferred helper for this, no need to fill the
>>>>> leading
>>>>> zero liek this, see include/linux/string.h
>>>> Ok, it should be more suitable to use strcpy.
>>> I have to correct myself, I meant to suggest strscpy(dst, src, size).
>>> Passing
>>> the size for safety seems important, and unlike strncpy() it takes care of
>>> the
>>> leading zero.
>> Yes, we use strscpy() for copying all the strings.
> Indeed, I had miss-read, then you simply need to remove the code you added to
> force the last byte to be 0, this is not needed with that function.
Yes, I checked the function strscpy too. It will add the \0 if the 
parameter 'size' is proper. We will remove this step in our code.
> Nicolas
>
>>> Nicolas
>> Thanks
>>
>> Zhentao


From u-kumar1 at ti.com  Mon Dec 15 18:43:04 2025
From: u-kumar1 at ti.com (Kumar, Udit)
Date: Tue, 16 Dec 2025 08:13:04 +0530
Subject: [PATCH v3 1/4] firmware: ti_sci: add BOARDCFG_MANAGED mode
 support
In-Reply-To: <20251205-ti-sci-jacinto-s2r-restore-irq-v3-1-d06963974ad4@bootlin.com>
References: <20251205-ti-sci-jacinto-s2r-restore-irq-v3-0-d06963974ad4@bootlin.com>
 <20251205-ti-sci-jacinto-s2r-restore-irq-v3-1-d06963974ad4@bootlin.com>
Message-ID: <6252026b-15c8-4243-8db7-efa0ef0b2fd7@ti.com>


On 12/5/2025 7:58 PM, Thomas Richard (TI.com) wrote:
> In BOARDCFG_MANAGED mode, the low power mode configuration is done
> statically for the DM via the boardcfg. Constraints are not supported, and
> prepare_sleep() is not needed.
>
> Signed-off-by: Thomas Richard (TI.com) <thomas.richard at bootlin.com>
> ---
>   drivers/firmware/ti_sci.c | 10 +++++++---
>   drivers/firmware/ti_sci.h |  2 ++
>   2 files changed, 9 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
> index 4a277937211f6..d77b631d9c855 100644
> --- a/drivers/firmware/ti_sci.c
> +++ b/drivers/firmware/ti_sci.c
> @@ -3772,8 +3772,11 @@ static int ti_sci_prepare_system_suspend(struct ti_sci_info *info)
>   			return ti_sci_cmd_prepare_sleep(&info->handle,
>   							TISCI_MSG_VALUE_SLEEP_MODE_DM_MANAGED,
>   							0, 0, 0);
> +		} else if (info->fw_caps & MSG_FLAG_CAPS_LPM_BOARDCFG_MANAGED) {
> +			/* Nothing to do in the BOARDCFG_MANAGED mode */
> +			return 0;
>   		} else {
> -			/* DM Managed is not supported by the firmware. */
> +			/* DM Managed and BoardCfg Managed are not supported by the firmware. */
>   			dev_err(info->dev, "Suspend to memory is not supported by the firmware\n");
>   			return -EOPNOTSUPP;
>   		}
> @@ -4011,12 +4014,13 @@ static int ti_sci_probe(struct platform_device *pdev)
>   	}
>   
>   	ti_sci_msg_cmd_query_fw_caps(&info->handle, &info->fw_caps);
> -	dev_dbg(dev, "Detected firmware capabilities: %s%s%s%s%s\n",
> +	dev_dbg(dev, "Detected firmware capabilities: %s%s%s%s%s%s\n",
>   		info->fw_caps & MSG_FLAG_CAPS_GENERIC ? "Generic" : "",
>   		info->fw_caps & MSG_FLAG_CAPS_LPM_PARTIAL_IO ? " Partial-IO" : "",
>   		info->fw_caps & MSG_FLAG_CAPS_LPM_DM_MANAGED ? " DM-Managed" : "",
>   		info->fw_caps & MSG_FLAG_CAPS_LPM_ABORT ? " LPM-Abort" : "",
> -		info->fw_caps & MSG_FLAG_CAPS_IO_ISOLATION ? " IO-Isolation" : ""
> +		info->fw_caps & MSG_FLAG_CAPS_IO_ISOLATION ? " IO-Isolation" : "",
> +		info->fw_caps & MSG_FLAG_CAPS_LPM_BOARDCFG_MANAGED ? " BoardConfig-Managed" : ""
>   	);
>   
>   	ti_sci_setup_ops(info);
> diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h
> index 91f234550c438..5f5c1ae7a19a8 100644
> --- a/drivers/firmware/ti_sci.h
> +++ b/drivers/firmware/ti_sci.h
> @@ -150,6 +150,7 @@ struct ti_sci_msg_req_reboot {
>    *		MSG_FLAG_CAPS_LPM_DM_MANAGED: LPM can be managed by DM
>    *		MSG_FLAG_CAPS_LPM_ABORT: Abort entry to LPM
>    *		MSG_FLAG_CAPS_IO_ISOLATION: IO Isolation support
> + *		MSG_FLAG_CAPS_LPM_BOARDCFG_MANAGED: LPM config done statically for the DM via boardcfg
>    *
>    * Response to a generic message with message type TI_SCI_MSG_QUERY_FW_CAPS
>    * providing currently available SOC/firmware capabilities. SoC that don't
> @@ -162,6 +163,7 @@ struct ti_sci_msg_resp_query_fw_caps {
>   #define MSG_FLAG_CAPS_LPM_DM_MANAGED	TI_SCI_MSG_FLAG(5)
>   #define MSG_FLAG_CAPS_LPM_ABORT		TI_SCI_MSG_FLAG(9)
>   #define MSG_FLAG_CAPS_IO_ISOLATION	TI_SCI_MSG_FLAG(7)
> +#define MSG_FLAG_CAPS_LPM_BOARDCFG_MANAGED	TI_SCI_MSG_FLAG(10)


I think, you already noticed, this should be bit-12


>   #define MSG_MASK_CAPS_LPM		GENMASK_ULL(4, 1)
>   	u64 fw_caps;
>   } __packed;
>


From u-kumar1 at ti.com  Mon Dec 15 18:47:24 2025
From: u-kumar1 at ti.com (Kumar, Udit)
Date: Tue, 16 Dec 2025 08:17:24 +0530
Subject: [PATCH v3 2/4] firmware: ti_sci: handle IRQ restore in
 BOARDCFG_MANAGED mode during resume
In-Reply-To: <20251205-ti-sci-jacinto-s2r-restore-irq-v3-2-d06963974ad4@bootlin.com>
References: <20251205-ti-sci-jacinto-s2r-restore-irq-v3-0-d06963974ad4@bootlin.com>
 <20251205-ti-sci-jacinto-s2r-restore-irq-v3-2-d06963974ad4@bootlin.com>
Message-ID: <bcc7a3da-3cb5-451b-98eb-4f7896c615a1@ti.com>


On 12/5/2025 7:58 PM, Thomas Richard (TI.com) wrote:
> In BOARDCFG_MANAGED mode, the firmware cannot restore IRQs during
> resume. This responsibility is delegated to the ti_sci driver,
> which maintains an internal list of all requested IRQs. This list
> is updated on each set/free operation, and all IRQs are restored
> during the resume_noirq() phase.
>
> Signed-off-by: Thomas Richard (TI.com) <thomas.richard at bootlin.com>
> ---
>   drivers/firmware/ti_sci.c | 147 +++++++++++++++++++++++++++++++++++++++++++---
>   1 file changed, 138 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
> index d77b631d9c855..8d94745376e2a 100644
> --- a/drivers/firmware/ti_sci.c
> +++ b/drivers/firmware/ti_sci.c
> @@ -12,6 +12,7 @@
>   #include <linux/cpu.h>
>   #include <linux/debugfs.h>
>   #include <linux/export.h>
> +#include <linux/hashtable.h>
>   #include <linux/io.h>
>   #include <linux/iopoll.h>
>   #include <linux/kernel.h>
> @@ -87,6 +88,16 @@ struct ti_sci_desc {
>   	int max_msg_size;
>   };
>   
> +/**
> + * struct ti_sci_irq - Description of allocated irqs
> + * @node: Link to hash table
> + * @desc: Description of the irq
> + */
> +struct ti_sci_irq {
> +	struct hlist_node node;
> +	struct ti_sci_msg_req_manage_irq desc;
> +};
> +
>   /**
>    * struct ti_sci_info - Structure representing a TI SCI instance
>    * @dev:	Device pointer
> @@ -101,6 +112,7 @@ struct ti_sci_desc {
>    * @chan_rx:	Receive mailbox channel
>    * @minfo:	Message info
>    * @node:	list head
> + * @irqs:	List of allocated irqs
>    * @host_id:	Host ID
>    * @fw_caps:	FW/SoC low power capabilities
>    * @users:	Number of users of this instance
> @@ -117,6 +129,7 @@ struct ti_sci_info {
>   	struct mbox_chan *chan_tx;
>   	struct mbox_chan *chan_rx;
>   	struct ti_sci_xfers_info minfo;
> +	DECLARE_HASHTABLE(irqs, 8);
>   	struct list_head node;
>   	u8 host_id;
>   	u64 fw_caps;
> @@ -2301,6 +2314,32 @@ static int ti_sci_manage_irq(const struct ti_sci_handle *handle,
>   	return ret;
>   }
>   
> +/**
> + * ti_sci_irq_hash() - Helper API to compute irq hash for the hash table.
> + * @irq:	irq to hash
> + *
> + * Return: the computed hash value.
> + */
> +static int ti_sci_irq_hash(struct ti_sci_msg_req_manage_irq *irq)
> +{
> +	return irq->src_id ^ irq->src_index;
> +}
> +
> +/**
> + * ti_sci_irq_equal() - Helper API to compare two irqs (generic headers are not
> + *                       compared)
> + * @irq_a:	irq_a to compare
> + * @irq_b:	irq_b to compare
> + *
> + * Return: true if the two irqs are equal, else false.
> + */
> +static bool ti_sci_irq_equal(struct ti_sci_msg_req_manage_irq *irq_a,
> +			     struct ti_sci_msg_req_manage_irq *irq_b)
> +{
> +	return !memcmp(&irq_a->valid_params, &irq_b->valid_params,
> +		       sizeof(*irq_a) - sizeof(irq_a->hdr));
> +}
> +
>   /**
>    * ti_sci_set_irq() - Helper api to configure the irq route between the
>    *		      requested source and destination
> @@ -2324,15 +2363,43 @@ static int ti_sci_set_irq(const struct ti_sci_handle *handle, u32 valid_params,
>   			  u16 dst_host_irq, u16 ia_id, u16 vint,
>   			  u16 global_event, u8 vint_status_bit, u8 s_host)
>   {
> +	struct ti_sci_info *info = handle_to_ti_sci_info(handle);
> +	struct ti_sci_msg_req_manage_irq *desc;
> +	struct ti_sci_irq *irq;
> +	int ret;
> +
>   	pr_debug("%s: IRQ set with valid_params = 0x%x from src = %d, index = %d, to dst = %d, irq = %d,via ia_id = %d, vint = %d, global event = %d,status_bit = %d\n",
>   		 __func__, valid_params, src_id, src_index,
>   		 dst_id, dst_host_irq, ia_id, vint, global_event,
>   		 vint_status_bit);
>   
> -	return ti_sci_manage_irq(handle, valid_params, src_id, src_index,
> -				 dst_id, dst_host_irq, ia_id, vint,
> -				 global_event, vint_status_bit, s_host,
> -				 TI_SCI_MSG_SET_IRQ);
> +	ret = ti_sci_manage_irq(handle, valid_params, src_id, src_index,
> +				dst_id, dst_host_irq, ia_id, vint,
> +				global_event, vint_status_bit, s_host,
> +				TI_SCI_MSG_SET_IRQ);
> +
> +	if (ret)
> +		return ret;
> +
> +	irq = kzalloc(sizeof(*irq), GFP_KERNEL);
> +	if (!irq)
> +		return -ENOMEM;
> +
> +	desc = &irq->desc;
> +	desc->valid_params = valid_params;
> +	desc->src_id = src_id;
> +	desc->src_index = src_index;
> +	desc->dst_id = dst_id;
> +	desc->dst_host_irq = dst_host_irq;
> +	desc->ia_id = ia_id;
> +	desc->vint = vint;
> +	desc->global_event = global_event;
> +	desc->vint_status_bit = vint_status_bit;
> +	desc->secondary_host = s_host;
> +
> +	hash_add(info->irqs, &irq->node, ti_sci_irq_hash(desc));
> +
> +	return 0;
>   }
>   
>   /**
> @@ -2358,15 +2425,46 @@ static int ti_sci_free_irq(const struct ti_sci_handle *handle, u32 valid_params,
>   			   u16 dst_host_irq, u16 ia_id, u16 vint,
>   			   u16 global_event, u8 vint_status_bit, u8 s_host)
>   {
> +	struct ti_sci_info *info = handle_to_ti_sci_info(handle);
> +	struct ti_sci_msg_req_manage_irq irq_desc;
> +	struct ti_sci_irq *this_irq;
> +	struct hlist_node *tmp_node;
> +	int ret;
> +
>   	pr_debug("%s: IRQ release with valid_params = 0x%x from src = %d, index = %d, to dst = %d, irq = %d,via ia_id = %d, vint = %d, global event = %d,status_bit = %d\n",
>   		 __func__, valid_params, src_id, src_index,
>   		 dst_id, dst_host_irq, ia_id, vint, global_event,
>   		 vint_status_bit);
>   
> -	return ti_sci_manage_irq(handle, valid_params, src_id, src_index,
> -				 dst_id, dst_host_irq, ia_id, vint,
> -				 global_event, vint_status_bit, s_host,
> -				 TI_SCI_MSG_FREE_IRQ);
> +	ret = ti_sci_manage_irq(handle, valid_params, src_id, src_index,
> +				dst_id, dst_host_irq, ia_id, vint,
> +				global_event, vint_status_bit, s_host,
> +				TI_SCI_MSG_FREE_IRQ);
> +
> +	if (ret)
> +		return ret;
> +
> +	irq_desc.valid_params = valid_params;
> +	irq_desc.src_id = src_id;
> +	irq_desc.src_index = src_index;
> +	irq_desc.dst_id = dst_id;
> +	irq_desc.dst_host_irq = dst_host_irq;
> +	irq_desc.ia_id = ia_id;
> +	irq_desc.vint = vint;
> +	irq_desc.global_event = global_event;
> +	irq_desc.vint_status_bit = vint_status_bit;
> +	irq_desc.secondary_host = s_host;
> +
> +	hash_for_each_possible_safe(info->irqs, this_irq, tmp_node, node,
> +				    ti_sci_irq_hash(&irq_desc)) {
> +		if (ti_sci_irq_equal(&irq_desc, &this_irq->desc)) {
> +			hlist_del(&this_irq->node);
> +			kfree(this_irq);
> +			return 0;


IMO,? you can restrict saving of irq and list management to fw having

BOARDCFG_MANAGED capability.

Dhurva ?


> +		}
> +	}
> +
> +	return 0;
>   }
>   
>   /**
> [..]


From u-kumar1 at ti.com  Mon Dec 15 18:55:28 2025
From: u-kumar1 at ti.com (Kumar, Udit)
Date: Tue, 16 Dec 2025 08:25:28 +0530
Subject: [PATCH v3 3/4] clk: keystone: sci-clk: add restore_context()
 operation
In-Reply-To: <20251205-ti-sci-jacinto-s2r-restore-irq-v3-3-d06963974ad4@bootlin.com>
References: <20251205-ti-sci-jacinto-s2r-restore-irq-v3-0-d06963974ad4@bootlin.com>
 <20251205-ti-sci-jacinto-s2r-restore-irq-v3-3-d06963974ad4@bootlin.com>
Message-ID: <a12c3825-a80e-491f-a862-9cd5151a5f73@ti.com>


On 12/5/2025 7:58 PM, Thomas Richard (TI.com) wrote:
> Implement the restore_context() operation to restore the clock rate and the
> clock parent state. The clock rate is saved in sci_clk struct during
> set_rate() operation. The parent index is saved in sci_clk struct during
> set_parent() operation. During clock registration, the core retrieves each
> clock?s parent using get_parent() operation to ensure the internal clock
> tree reflects the actual hardware state, including any configurations made
> by the bootloader. So we also save the parent index in get_parent().
>
> Signed-off-by: Thomas Richard (TI.com) <thomas.richard at bootlin.com>
> ---
>   drivers/clk/keystone/sci-clk.c | 42 ++++++++++++++++++++++++++++++++++--------
>   1 file changed, 34 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/clk/keystone/sci-clk.c b/drivers/clk/keystone/sci-clk.c
> index 9d5071223f4cb..428050a05de31 100644
> --- a/drivers/clk/keystone/sci-clk.c
> +++ b/drivers/clk/keystone/sci-clk.c
> @@ -47,6 +47,8 @@ struct sci_clk_provider {
>    * @node:	 Link for handling clocks probed via DT
>    * @cached_req:	 Cached requested freq for determine rate calls
>    * @cached_res:	 Cached result freq for determine rate calls
> + * @parent_id:	 Parent index for this clock
> + * @rate:	 Clock rate
>    */
>   struct sci_clk {
>   	struct clk_hw hw;
> @@ -58,6 +60,8 @@ struct sci_clk {
>   	struct list_head node;
>   	unsigned long cached_req;
>   	unsigned long cached_res;
> +	u8 parent_id;
> +	unsigned long rate;
>   };
>   
>   #define to_sci_clk(_hw) container_of(_hw, struct sci_clk, hw)
> @@ -210,10 +214,16 @@ static int sci_clk_set_rate(struct clk_hw *hw, unsigned long rate,
>   			    unsigned long parent_rate)
>   {
>   	struct sci_clk *clk = to_sci_clk(hw);
> +	int ret;
> +
> +	ret = clk->provider->ops->set_freq(clk->provider->sci, clk->dev_id,
> +					   clk->clk_id, rate / 10 * 9, rate,
> +					   rate / 10 * 11);
>   
> -	return clk->provider->ops->set_freq(clk->provider->sci, clk->dev_id,
> -					    clk->clk_id, rate / 10 * 9, rate,
> -					    rate / 10 * 11);
> +	if (!ret)
> +		clk->rate = rate;
> +
> +	return ret;
>   }
>   
>   /**
> @@ -237,9 +247,9 @@ static u8 sci_clk_get_parent(struct clk_hw *hw)
>   		return 0;
>   	}
>   
> -	parent_id = parent_id - clk->clk_id - 1;
> +	clk->parent_id = (u8)(parent_id - clk->clk_id - 1);
>   
> -	return (u8)parent_id;
> +	return clk->parent_id;
>   }
>   
>   /**
> @@ -252,12 +262,27 @@ static u8 sci_clk_get_parent(struct clk_hw *hw)
>   static int sci_clk_set_parent(struct clk_hw *hw, u8 index)
>   {
>   	struct sci_clk *clk = to_sci_clk(hw);
> +	int ret;
>   
>   	clk->cached_req = 0;
>   
> -	return clk->provider->ops->set_parent(clk->provider->sci, clk->dev_id,
> -					      clk->clk_id,
> -					      index + 1 + clk->clk_id);
> +	ret = clk->provider->ops->set_parent(clk->provider->sci, clk->dev_id,
> +					     clk->clk_id,
> +					     index + 1 + clk->clk_id);
> +	if (!ret)
> +		clk->parent_id = index;
> +
> +	return ret;
> +}
> +
> +static void sci_clk_restore_context(struct clk_hw *hw)
> +{
> +	struct sci_clk *clk = to_sci_clk(hw);
> +
> +	sci_clk_set_parent(hw, clk->parent_id);
> +
> +	if (clk->rate)
> +		sci_clk_set_rate(hw, clk->rate, 0);


Mostly looks ok ,? Please add some warning prints in case of resume path 
either of

sci_clk_set_parent/sci_clk_set_rate returned failure


>   }
>   
>   static const struct clk_ops sci_clk_ops = {
> @@ -269,6 +294,7 @@ static const struct clk_ops sci_clk_ops = {
>   	.set_rate = sci_clk_set_rate,
>   	.get_parent = sci_clk_get_parent,
>   	.set_parent = sci_clk_set_parent,
> +	.restore_context = sci_clk_restore_context,
>   };
>   
>   /**
>


From haibo.chen at nxp.com  Mon Dec 15 19:20:12 2025
From: haibo.chen at nxp.com (Haibo Chen)
Date: Tue, 16 Dec 2025 11:20:12 +0800
Subject: [PATCH v7 0/2] Add support for NXP XSPI
Message-ID: <20251216-xspi-v7-0-282525220979@nxp.com>

XSPI is a flexible SPI host controller which supports up to
2 external devices (2 CS). It support Single/Dual/Quad/Octal
mode data transfer.

The difference between XSPI and Flexspi is XSPI support
multiple independent execution environments (EENVs) for HW
virtualization with some limitations. Each EENV has its own
interrupt and its own set of programming registers that exists
in a specific offset range in the XSPI memory map.
The main environment (EENV0) address space contains all of the
registers for controlling EENV0 plus all of the general XSPI
control and programming registers. The register mnemonics for
the user environments (EENV1 to EENV4) have "_SUB_n" appended
to the mnemonic for the corresponding main-environment register.

Current driver based on EENV0, which means system already give
EENV0 right to linux.

This driver use SPI memory interface of the SPI framework to issue
flash memory operations. Tested this driver with mtd_debug and
UBIFS on NXP i.MX943 EVK board which has one MT35XU512ABA spi nor
flash. NOw this driver has the following key features:
- Support up to OCT DDR mode
- Support AHB read
- Support IP read and IP write
- Support two CS

Signed-off-by: Haibo Chen <haibo.chen at nxp.com>
---
Changes in v7:
- PATCH1: adjust subject lines reflecting the style for the spi subsystem
- PATCH2: no changes, just wait this commit ef8057b07c72 ("PM: runtime:
          Wrapper macros for ACQUIRE()/ACQUIRE_ERR()"), so that current
	  driver which use the new macros PM_RUNTIME_ACQUIRE can compile
	  without error.
- Link to v6: https://lore.kernel.org/r/20251125-xspi-v6-0-22b22de50cda at nxp.com

Changes in v6:
- PATCH 2: check return of devm_pm_runtime_enable()
           return err when trigger WARN_ON()
- Link to v5: https://lore.kernel.org/r/20251124-xspi-v5-0-6fd03a6cb766 at nxp.com

Changes in v5:
- PATCH 2: fix a typo of GENMASK to avoid build warning which reproted by kernel test robot
	   -#define XSPI_DLLCRA_DLLRES_MASK                GENMASK(32, 20)
	   +#define XSPI_DLLCRA_DLLRES_MASK                GENMASK(23, 20)

	   do not write XSPI_MCR_MDIS to MCR directlly in nxp_xspi_cleanup(), instead
	   read MCR, only set this XSPI_MCR_MDIS and write MCR. Find this issue when
	   do the bind/unbind test, find some reserved bits are accidently cleared and
	   finally impact the data transfer, because the reserved bits[3,2] need to keep in
	   the default value.
- Link to v4: https://lore.kernel.org/r/20251119-xspi-v4-0-a451afbccf33 at nxp.com

Changes in v4:
- PATCH 2: add changes according to Frank's comments:
           - rename XSPI_RPM_TIMEOUT to XSPI_RPM_TIMEOUT_MS
	   - rename POLL_TOUT to POLL_TOUT_US
	   - return IRQ_NONE directlly
	   - use min_t() to replace min()
	   - use the new macros PM_RUNTIME_ACQUIRE_AUTOSUSPEND and
	     PM_RUNTIME_ACQUIRE_ERR in nxp_xspi_exec_op() and nxp_xspi_probe()
	   - refine nxp_xspi_cleanup()
	   - use devm_pm_runtime_enable()
- Link to v3: https://lore.kernel.org/r/20251118-xspi-v3-0-6d3a91b68c7e at nxp.com

Changes in v3:
- PATCH 1: fix the messed ordering in MAINTAINERS, add Krzysztof's ack
- PATCH 2: fix some typo, and add IRQ_NONE in nxp_xspi_irq_handler()
	   also add {} for else when the if has {}
- Link to v2: https://lore.kernel.org/r/20251117-xspi-v2-0-e651323993fe at nxp.com

Changes in v2:
- PATCH 1: re-name the yaml file, and correct the compatible string and reg in the example to pass binding check.
- PATCH 2: involve changes according to Frank's comments 
           - use GENMASK and FIELD_PREP
           - remove little endian, use readl/writel/read_poll_timeout directly
	   - use fsleep instead of udelay
	   - remove pm_runtime_mark_last_busy()
	   - keep one style to use up case
	   - use SYSTEM_SLEEP_PM_OPS/RUNTIME_PM_OPS
- Link to v1: https://lore.kernel.org/r/20251104-xspi-v1-0-1502847ade40 at nxp.com

---
Haibo Chen (2):
      spi: dt-bindings: nxp,imx94-xspi: Document imx94 xspi
      spi: add driver for NXP XSPI controller

 .../devicetree/bindings/spi/nxp,imx94-xspi.yaml    |   88 ++
 MAINTAINERS                                        |    9 +
 drivers/spi/Kconfig                                |   10 +
 drivers/spi/Makefile                               |    1 +
 drivers/spi/spi-nxp-xspi.c                         | 1385 ++++++++++++++++++++
 5 files changed, 1493 insertions(+)
---
base-commit: 563c8dd425b59e44470e28519107b1efc99f4c7b
change-id: 20251028-xspi-afc0a17e9708

Best regards,
-- 
Haibo Chen <haibo.chen at nxp.com>



From haibo.chen at nxp.com  Mon Dec 15 19:20:13 2025
From: haibo.chen at nxp.com (Haibo Chen)
Date: Tue, 16 Dec 2025 11:20:13 +0800
Subject: [PATCH v7 1/2] spi: dt-bindings: nxp,imx94-xspi: Document imx94
 xspi
In-Reply-To: <20251216-xspi-v7-0-282525220979@nxp.com>
References: <20251216-xspi-v7-0-282525220979@nxp.com>
Message-ID: <20251216-xspi-v7-1-282525220979@nxp.com>

Document imx94 xspi that supports interface to serial flash
supporting following features:

- Single-bit SPI, Dual SPI, Quad SPI and Octal SPI.
- Single Data Rate or Double Data Rate modes.
- Direct memory mapping of all AHB memory accesses to the
  chip system memory space.
- Multi-master AHB accesses with priority.

Reviewed-by: Krzysztof Kozlowski <krzk at kernel.org>
Signed-off-by: Haibo Chen <haibo.chen at nxp.com>
---
 .../devicetree/bindings/spi/nxp,imx94-xspi.yaml    | 88 ++++++++++++++++++++++
 MAINTAINERS                                        |  8 ++
 2 files changed, 96 insertions(+)

diff --git a/Documentation/devicetree/bindings/spi/nxp,imx94-xspi.yaml b/Documentation/devicetree/bindings/spi/nxp,imx94-xspi.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a0f4b162c85855c55d06c6ea1a2417af5121fab2
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/nxp,imx94-xspi.yaml
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/nxp,imx94-xspi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP External Serial Peripheral Interface (xSPI)
+
+maintainers:
+  - Haibo Chen <haibo.chen at nxp.com>
+  - Han Xu <han.xu at nxp.com>
+
+properties:
+  compatible:
+    oneOf:
+      - enum:
+          - nxp,imx94-xspi
+
+  reg:
+    items:
+      - description: registers address space
+      - description: memory mapped address space
+
+  reg-names:
+    items:
+      - const: base
+      - const: mmap
+
+  interrupts:
+    items:
+      - description: interrupt for EENV0
+      - description: interrupt for EENV1
+      - description: interrupt for EENV2
+      - description: interrupt for EENV3
+      - description: interrupt for EENV4
+
+  clocks:
+    items:
+      - description: SPI serial clock
+
+  clock-names:
+    items:
+      - const: per
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - interrupts
+  - clocks
+  - clock-names
+
+allOf:
+  - $ref: spi-controller.yaml#
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        spi at 42b90000 {
+            compatible = "nxp,imx94-xspi";
+            reg = <0x0 0x42b90000 0x0 0x50000>, <0x0 0x28000000 0x0 0x08000000>;
+            reg-names = "base", "mmap";
+            interrupts = <GIC_SPI 390 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 391 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 392 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 393 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 394 IRQ_TYPE_LEVEL_HIGH>;
+            #address-cells = <1>;
+            #size-cells = <0>;
+            clocks = <&scmi_1>;
+            clock-names = "per";
+
+            flash at 0 {
+                compatible = "jedec,spi-nor";
+                reg = <0>;
+                spi-max-frequency = <200000000>;
+                spi-rx-bus-width = <8>;
+                spi-tx-bus-width = <8>;
+            };
+        };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index e5b1342ee2a660575b5246a11bc89baefd973388..2808b91dae1aeabbdb79408461b0d912cdd44c39 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18958,6 +18958,14 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/sound/trivial-codec.yaml
 F:	sound/soc/codecs/tfa9879*
 
+NXP XSPI DRIVER
+M:	Han Xu <han.xu at nxp.com>
+M:	Haibo Chen <haibo.chen at nxp.com>
+L:	linux-spi at vger.kernel.org
+L:	imx at lists.linux.dev
+S:	Maintained
+F:	Documentation/devicetree/bindings/spi/nxp,imx94-xspi.yaml
+
 NXP-NCI NFC DRIVER
 S:	Orphan
 F:	Documentation/devicetree/bindings/net/nfc/nxp,nci.yaml

-- 
2.34.1



From haibo.chen at nxp.com  Mon Dec 15 19:20:14 2025
From: haibo.chen at nxp.com (Haibo Chen)
Date: Tue, 16 Dec 2025 11:20:14 +0800
Subject: [PATCH v7 2/2] spi: add driver for NXP XSPI controller
In-Reply-To: <20251216-xspi-v7-0-282525220979@nxp.com>
References: <20251216-xspi-v7-0-282525220979@nxp.com>
Message-ID: <20251216-xspi-v7-2-282525220979@nxp.com>

Add driver support for NXP XSPI controller.

XSPI is a flexible SPI host controller which supports up to
2 external devices (2 CS). It support Single/Dual/Quad/Octal
mode data transfer.

The difference between XSPI and Flexspi:
1.the register layout is total different.
2.XSPI support multiple independent execution environments
(EENVs) for HW virtualization with some limitations. Each EENV
has its own interrupt and its own set of programming registers
that exists in a specific offset range in the XSPI memory map.
The main environment (EENV0) address space contains all of the
registers for controlling EENV0 plus all of the general XSPI
control and programming registers. The register mnemonics for
the user environments (EENV1 to EENV4) have "_SUB_n" appended
to the mnemonic for the corresponding main-environment register.

Current driver based on EENV0, which means system already give
EENV0 right to linux.

This driver use SPI memory interface of the SPI framework to
issue flash memory operations. Tested this driver with UBIFS
and mtd_debug on NXP i.MX943 EVK board which has one spi nor
MT35XU512ABA flash. Now this driver has the following key
features:
- Support up to OCT DDR mode
- Support AHB read
- Support IP read and IP write
- Support two CS

Reviewed-by: Frank Li <Frank.Li at nxp.com>
Signed-off-by: Haibo Chen <haibo.chen at nxp.com>
---
 MAINTAINERS                |    1 +
 drivers/spi/Kconfig        |   10 +
 drivers/spi/Makefile       |    1 +
 drivers/spi/spi-nxp-xspi.c | 1385 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 1397 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 2808b91dae1aeabbdb79408461b0d912cdd44c39..aaef5a381ab28c03abe4dd51be844467135bebe3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18965,6 +18965,7 @@ L:	linux-spi at vger.kernel.org
 L:	imx at lists.linux.dev
 S:	Maintained
 F:	Documentation/devicetree/bindings/spi/nxp,imx94-xspi.yaml
+F:	drivers/spi/spi-nxp-xspi.c
 
 NXP-NCI NFC DRIVER
 S:	Orphan
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 5520403896fca88ac0194388613013d7592b08fe..77c36f6e2cec3889d00b8a47d589720608b06e26 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -481,6 +481,16 @@ config SPI_NXP_FLEXSPI
 	  This controller does not support generic SPI messages and only
 	  supports the high-level SPI memory interface.
 
+config SPI_NXP_XSPI
+        tristate "NXP xSPI controller"
+	depends on ARCH_MXC || COMPILE_TEST
+	depends on HAS_IOMEM
+	help
+	  This enables support for the xSPI controller. Up to two devices
+	  can be connected to one host.
+	  This controller does not support generic SPI messages and only
+	  supports the high-level SPI memory interface.
+
 config SPI_GPIO
 	tristate "GPIO-based bitbanging SPI Master"
 	depends on GPIOLIB || COMPILE_TEST
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 863b628ff1ec0b938be81dff024aa7dc7d50c36d..649dcba0aa1140da7d9bd969138859922a2e03b0 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -102,6 +102,7 @@ obj-$(CONFIG_SPI_WPCM_FIU)		+= spi-wpcm-fiu.o
 obj-$(CONFIG_SPI_NPCM_FIU)		+= spi-npcm-fiu.o
 obj-$(CONFIG_SPI_NPCM_PSPI)		+= spi-npcm-pspi.o
 obj-$(CONFIG_SPI_NXP_FLEXSPI)		+= spi-nxp-fspi.o
+obj-$(CONFIG_SPI_NXP_XSPI)		+= spi-nxp-xspi.o
 obj-$(CONFIG_SPI_OC_TINY)		+= spi-oc-tiny.o
 spi-octeon-objs				:= spi-cavium.o spi-cavium-octeon.o
 obj-$(CONFIG_SPI_OCTEON)		+= spi-octeon.o
diff --git a/drivers/spi/spi-nxp-xspi.c b/drivers/spi/spi-nxp-xspi.c
new file mode 100644
index 0000000000000000000000000000000000000000..25339492bf3a0d94f286d42e55f47e71ae1af472
--- /dev/null
+++ b/drivers/spi/spi-nxp-xspi.c
@@ -0,0 +1,1385 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/*
+ * NXP xSPI controller driver.
+ *
+ * Copyright 2025 NXP
+ *
+ * xSPI is a flexible SPI host controller which supports single
+ * external devices. This device can have up to eight bidirectional
+ * data lines, this means xSPI support Single/Dual/Quad/Octal mode
+ * data transfer (1/2/4/8 bidirectional data lines).
+ *
+ * xSPI controller is driven by the LUT(Look-up Table) registers
+ * LUT registers are a look-up-table for sequences of instructions.
+ * A valid sequence consists of five LUT registers.
+ * Maximum 16 LUT sequences can be programmed simultaneously.
+ *
+ * LUTs are being created at run-time based on the commands passed
+ * from the spi-mem framework, thus using single LUT index.
+ *
+ * Software triggered Flash read/write access by IP Bus.
+ *
+ * Memory mapped read access by AHB Bus.
+ *
+ * Based on SPI MEM interface and spi-nxp-fspi.c driver.
+ *
+ * Author:
+ *     Haibo Chen <haibo.chen at nxp.com>
+ * Co-author:
+ *     Han Xu <han.xu at nxp.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/log2.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi-mem.h>
+
+/* Runtime pm timeout */
+#define XSPI_RPM_TIMEOUT_MS 50	/* 50ms */
+/*
+ * The driver only uses one single LUT entry, that is updated on
+ * each call of exec_op(). Index 0 is preset at boot with a basic
+ * read operation, so let's use the last entry (15).
+ */
+#define	XSPI_SEQID_LUT			15
+
+#define XSPI_MCR			0x0
+#define XSPI_MCR_CKN_FA_EN		BIT(26)
+#define XSPI_MCR_DQS_FA_SEL_MASK	GENMASK(25, 24)
+#define XSPI_MCR_ISD3FA			BIT(17)
+#define XSPI_MCR_ISD2FA			BIT(16)
+#define XSPI_MCR_DOZE			BIT(15)
+#define XSPI_MCR_MDIS			BIT(14)
+#define XSPI_MCR_DLPEN			BIT(12)
+#define XSPI_MCR_CLR_TXF		BIT(11)
+#define XSPI_MCR_CLR_RXF		BIT(10)
+#define XSPI_MCR_IPS_TG_RST		BIT(9)
+#define XSPI_MCR_VAR_LAT_EN		BIT(8)
+#define XSPI_MCR_DDR_EN			BIT(7)
+#define XSPI_MCR_DQS_EN			BIT(6)
+#define XSPI_MCR_DQS_LAT_EN		BIT(5)
+#define XSPI_MCR_DQS_OUT_EN		BIT(4)
+#define XSPI_MCR_SWRSTHD		BIT(1)
+#define XSPI_MCR_SWRSTSD		BIT(0)
+
+#define XSPI_IPCR			0x8
+
+#define XSPI_FLSHCR			0xC
+#define XSPI_FLSHCR_TDH_MASK		GENMASK(17, 16)
+#define XSPI_FLSHCR_TCSH_MASK		GENMASK(11, 8)
+#define XSPI_FLSHCR_TCSS_MASK		GENMASK(3, 0)
+
+#define XSPI_BUF0CR			0x10
+#define XSPI_BUF1CR			0x14
+#define XSPI_BUF2CR			0x18
+#define XSPI_BUF3CR			0x1C
+#define XSPI_BUF3CR_ALLMST		BIT(31)
+#define XSPI_BUF3CR_ADATSZ_MASK		GENMASK(17, 8)
+#define XSPI_BUF3CR_MSTRID_MASK		GENMASK(3, 0)
+
+#define XSPI_BFGENCR			0x20
+#define XSPI_BFGENCR_SEQID_WR_MASK	GENMASK(31, 28)
+#define XSPI_BFGENCR_ALIGN_MASK		GENMASK(24, 22)
+#define XSPI_BFGENCR_PPWF_CLR		BIT(20)
+#define XSPI_BFGENCR_WR_FLUSH_EN	BIT(21)
+#define XSPI_BFGENCR_SEQID_WR_EN	BIT(17)
+#define XSPI_BFGENCR_SEQID_MASK		GENMASK(15, 12)
+
+#define XSPI_BUF0IND			0x30
+#define XSPI_BUF1IND			0x34
+#define XSPI_BUF2IND			0x38
+
+#define XSPI_DLLCRA			0x60
+#define XSPI_DLLCRA_DLLEN		BIT(31)
+#define XSPI_DLLCRA_FREQEN		BIT(30)
+#define XSPI_DLLCRA_DLL_REFCNTR_MASK	GENMASK(27, 24)
+#define XSPI_DLLCRA_DLLRES_MASK		GENMASK(23, 20)
+#define XSPI_DLLCRA_SLV_FINE_MASK	GENMASK(19, 16)
+#define XSPI_DLLCRA_SLV_DLY_MASK	GENMASK(14, 12)
+#define XSPI_DLLCRA_SLV_DLY_COARSE_MASK	GENMASK(11,  8)
+#define XSPI_DLLCRA_SLV_DLY_FINE_MASK	GENMASK(7, 5)
+#define XSPI_DLLCRA_DLL_CDL8		BIT(4)
+#define XSPI_DLLCRA_SLAVE_AUTO_UPDT	BIT(3)
+#define XSPI_DLLCRA_SLV_EN		BIT(2)
+#define XSPI_DLLCRA_SLV_DLL_BYPASS	BIT(1)
+#define XSPI_DLLCRA_SLV_UPD		BIT(0)
+
+#define XSPI_SFAR			0x100
+
+#define XSPI_SFACR			0x104
+#define XSPI_SFACR_FORCE_A10		BIT(22)
+#define XSPI_SFACR_WA_4B_EN		BIT(21)
+#define XSPI_SFACR_CAS_INTRLVD		BIT(20)
+#define XSPI_SFACR_RX_BP_EN		BIT(18)
+#define XSPI_SFACR_BYTE_SWAP		BIT(17)
+#define XSPI_SFACR_WA			BIT(16)
+#define XSPI_SFACR_CAS_MASK		GENMASK(3, 0)
+
+#define XSPI_SMPR			0x108
+#define XSPI_SMPR_DLLFSMPFA_MASK	GENMASK(26, 24)
+#define XSPI_SMPR_FSDLY			BIT(6)
+#define XSPI_SMPR_FSPHS			BIT(5)
+
+#define XSPI_RBSR			0x10C
+
+#define XSPI_RBCT			0x110
+#define XSPI_RBCT_WMRK_MASK		GENMASK(6, 0)
+
+#define XSPI_DLLSR			0x12C
+#define XSPI_DLLSR_DLLA_LOCK		BIT(15)
+#define XSPI_DLLSR_SLVA_LOCK		BIT(14)
+#define XSPI_DLLSR_DLLA_RANGE_ERR	BIT(13)
+#define XSPI_DLLSR_DLLA_FINE_UNDERFLOW	BIT(12)
+
+#define XSPI_TBSR			0x150
+
+#define XSPI_TBDR			0x154
+
+#define XSPI_TBCT			0x158
+#define XSPI_TBCT_WMRK_MASK		GENMASK(7, 0)
+
+#define XSPI_SR				0x15C
+#define XSPI_SR_TXFULL			BIT(27)
+#define XSPI_SR_TXDMA			BIT(26)
+#define XSPI_SR_TXWA			BIT(25)
+#define XSPI_SR_TXNE			BIT(24)
+#define XSPI_SR_RXDMA			BIT(23)
+#define XSPI_SR_ARB_STATE_MASK		GENMASK(23, 20)
+#define XSPI_SR_RXFULL			BIT(19)
+#define XSPI_SR_RXWE			BIT(16)
+#define XSPI_SR_ARB_LCK			BIT(15)
+#define XSPI_SR_AHBnFUL			BIT(11)
+#define XSPI_SR_AHBnNE			BIT(7)
+#define XSPI_SR_AHBTRN			BIT(6)
+#define XSPI_SR_AWRACC			BIT(4)
+#define XSPI_SR_AHB_ACC			BIT(2)
+#define XSPI_SR_IP_ACC			BIT(1)
+#define XSPI_SR_BUSY			BIT(0)
+
+#define XSPI_FR				0x160
+#define XSPI_FR_DLPFF			BIT(31)
+#define XSPI_FR_DLLABRT			BIT(28)
+#define XSPI_FR_TBFF			BIT(27)
+#define XSPI_FR_TBUF			BIT(26)
+#define XSPI_FR_DLLUNLCK		BIT(24)
+#define XSPI_FR_ILLINE			BIT(23)
+#define XSPI_FR_RBOF			BIT(17)
+#define XSPI_FR_RBDF			BIT(16)
+#define XSPI_FR_AAEF			BIT(15)
+#define XSPI_FR_AITEF			BIT(14)
+#define XSPI_FR_AIBSEF			BIT(13)
+#define XSPI_FR_ABOF			BIT(12)
+#define XSPI_FR_CRCAEF			BIT(10)
+#define XSPI_FR_PPWF			BIT(8)
+#define XSPI_FR_IPIEF			BIT(6)
+#define XSPI_FR_IPEDERR			BIT(5)
+#define XSPI_FR_PERFOVF			BIT(2)
+#define XSPI_FR_RDADDR			BIT(1)
+#define XSPI_FR_TFF			BIT(0)
+
+#define XSPI_RSER			0x164
+#define XSPI_RSER_TFIE			BIT(0)
+
+#define XSPI_SFA1AD			0x180
+
+#define XSPI_SFA2AD			0x184
+
+#define XSPI_RBDR0			0x200
+
+#define XSPI_LUTKEY			0x300
+#define XSPI_LUT_KEY_VAL		(0x5AF05AF0UL)
+
+#define XSPI_LCKCR			0x304
+#define XSPI_LOKCR_LOCK			BIT(0)
+#define XSPI_LOKCR_UNLOCK		BIT(1)
+
+#define XSPI_LUT			0x310
+#define XSPI_LUT_OFFSET			(XSPI_SEQID_LUT * 5 * 4)
+#define XSPI_LUT_REG(idx) \
+	(XSPI_LUT + XSPI_LUT_OFFSET + (idx) * 4)
+
+#define XSPI_MCREXT			0x4FC
+#define XSPI_MCREXT_RST_MASK		GENMASK(3, 0)
+
+
+#define XSPI_FRAD0_WORD2		0x808
+#define XSPI_FRAD0_WORD2_MD0ACP_MASK	GENMASK(2, 0)
+
+#define XSPI_FRAD0_WORD3		0x80C
+#define XSPI_FRAD0_WORD3_VLD		BIT(31)
+
+#define XSPI_TG0MDAD			0x900
+#define XSPI_TG0MDAD_VLD		BIT(31)
+
+#define XSPI_TG1MDAD			0x910
+
+#define XSPI_MGC			0x920
+#define XSPI_MGC_GVLD			BIT(31)
+#define XSPI_MGC_GVLDMDAD		BIT(29)
+#define XSPI_MGC_GVLDFRAD		BIT(27)
+
+#define XSPI_MTO			0x928
+
+#define XSPI_ERRSTAT			0x938
+#define XSPI_INT_EN			0x93C
+
+#define XSPI_SFP_TG_IPCR		0x958
+#define XSPI_SFP_TG_IPCR_SEQID_MASK	GENMASK(27, 24)
+#define XSPI_SFP_TG_IPCR_ARB_UNLOCK	BIT(23)
+#define XSPI_SFP_TG_IPCR_ARB_LOCK	BIT(22)
+#define XSPI_SFP_TG_IPCR_IDATSZ_MASK	GENMASK(15, 0)
+
+#define XSPI_SFP_TG_SFAR 0x95C
+
+/* Register map end */
+
+/********* XSPI CMD definitions ***************************/
+#define LUT_STOP	0x00
+#define LUT_CMD_SDR	0x01
+#define LUT_ADDR_SDR	0x02
+#define LUT_DUMMY	0x03
+#define LUT_MODE8_SDR	0x04
+#define LUT_MODE2_SDR	0x05
+#define LUT_MODE4_SDR	0x06
+#define LUT_READ_SDR	0x07
+#define LUT_WRITE_SDR	0x08
+#define LUT_JMP_ON_CS	0x09
+#define LUT_ADDR_DDR	0x0A
+#define LUT_MODE8_DDR	0x0B
+#define LUT_MODE2_DDR	0x0C
+#define LUT_MODE4_DDR	0x0D
+#define LUT_READ_DDR	0x0E
+#define LUT_WRITE_DDR	0x0F
+#define LUT_DATA_LEARN	0x10
+#define LUT_CMD_DDR	0x11
+#define LUT_CADDR_SDR	0x12
+#define LUT_CADDR_DDR	0x13
+#define JMP_TO_SEQ	0x14
+
+#define XSPI_64BIT_LE	0x3
+/*
+ * Calculate number of required PAD bits for LUT register.
+ *
+ * The pad stands for the number of IO lines [0:7].
+ * For example, the octal read needs eight IO lines,
+ * so you should use LUT_PAD(8). This macro
+ * returns 3 i.e. use eight (2^3) IP lines for read.
+ */
+#define LUT_PAD(x) (fls(x) - 1)
+
+/*
+ * Macro for constructing the LUT entries with the following
+ * register layout:
+ *
+ *  ---------------------------------------------------
+ *  | INSTR1 | PAD1 | OPRND1 | INSTR0 | PAD0 | OPRND0 |
+ *  ---------------------------------------------------
+ */
+#define PAD_SHIFT		8
+#define INSTR_SHIFT		10
+#define OPRND_SHIFT		16
+
+/* Macros for constructing the LUT register. */
+#define LUT_DEF(idx, ins, pad, opr)			  \
+	((((ins) << INSTR_SHIFT) | ((pad) << PAD_SHIFT) | \
+	(opr)) << (((idx) % 2) * OPRND_SHIFT))
+
+#define NXP_XSPI_MIN_IOMAP	SZ_4M
+#define NXP_XSPI_MAX_CHIPSELECT		2
+#define POLL_TOUT_US		5000
+
+/* Access flash memory using IP bus only */
+#define XSPI_QUIRK_USE_IP_ONLY	BIT(0)
+
+struct nxp_xspi_devtype_data {
+	unsigned int rxfifo;
+	unsigned int txfifo;
+	unsigned int ahb_buf_size;
+	unsigned int quirks;
+};
+
+static struct nxp_xspi_devtype_data imx94_data = {
+	.rxfifo = SZ_512,       /* (128 * 4 bytes)  */
+	.txfifo = SZ_1K,        /* (256 * 4 bytes)  */
+	.ahb_buf_size = SZ_4K,  /* (1024 * 4 bytes)  */
+};
+
+struct nxp_xspi {
+	void __iomem *iobase;
+	void __iomem *ahb_addr;
+	u32 memmap_phy;
+	u32 memmap_phy_size;
+	u32 memmap_start;
+	u32 memmap_len;
+	struct clk *clk;
+	struct device *dev;
+	struct completion c;
+	const struct nxp_xspi_devtype_data *devtype_data;
+	/* mutex lock for each operation */
+	struct mutex lock;
+	int selected;
+#define XSPI_DTR_PROTO		BIT(0)
+	int flags;
+	/* Save the previous operation clock rate */
+	unsigned long pre_op_rate;
+	/* The max clock rate xspi supported output to device */
+	unsigned long support_max_rate;
+};
+
+static inline int needs_ip_only(struct nxp_xspi *xspi)
+{
+	return xspi->devtype_data->quirks & XSPI_QUIRK_USE_IP_ONLY;
+}
+
+static irqreturn_t nxp_xspi_irq_handler(int irq, void *dev_id)
+{
+	struct nxp_xspi *xspi = dev_id;
+	u32 reg;
+
+	reg = readl(xspi->iobase + XSPI_FR);
+	if (reg & XSPI_FR_TFF) {
+		/* Clear interrupt */
+		writel(XSPI_FR_TFF, xspi->iobase + XSPI_FR);
+		complete(&xspi->c);
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+static int nxp_xspi_check_buswidth(struct nxp_xspi *xspi, u8 width)
+{
+	return (is_power_of_2(width) && width <= 8) ? 0 : -EOPNOTSUPP;
+}
+
+static bool nxp_xspi_supports_op(struct spi_mem *mem,
+				 const struct spi_mem_op *op)
+{
+	struct nxp_xspi *xspi = spi_controller_get_devdata(mem->spi->controller);
+	int ret;
+
+	ret = nxp_xspi_check_buswidth(xspi, op->cmd.buswidth);
+
+	if (op->addr.nbytes)
+		ret |= nxp_xspi_check_buswidth(xspi, op->addr.buswidth);
+
+	if (op->dummy.nbytes)
+		ret |= nxp_xspi_check_buswidth(xspi, op->dummy.buswidth);
+
+	if (op->data.nbytes)
+		ret |= nxp_xspi_check_buswidth(xspi, op->data.buswidth);
+
+	if (ret)
+		return false;
+
+	/*
+	 * The number of address bytes should be equal to or less than 4 bytes.
+	 */
+	if (op->addr.nbytes > 4)
+		return false;
+
+	/* Max 32 dummy clock cycles supported */
+	if (op->dummy.buswidth &&
+	    (op->dummy.nbytes * 8 / op->dummy.buswidth > 64))
+		return false;
+
+	if (needs_ip_only(xspi) && op->data.dir == SPI_MEM_DATA_IN &&
+	    op->data.nbytes > xspi->devtype_data->rxfifo)
+		return false;
+
+	if (op->data.dir == SPI_MEM_DATA_OUT &&
+			op->data.nbytes > xspi->devtype_data->txfifo)
+		return false;
+
+	return spi_mem_default_supports_op(mem, op);
+}
+
+static void nxp_xspi_prepare_lut(struct nxp_xspi *xspi,
+				 const struct spi_mem_op *op)
+{
+	void __iomem *base = xspi->iobase;
+	u32 lutval[5] = {};
+	int lutidx = 1, i;
+
+	/* cmd */
+	if (op->cmd.dtr) {
+		lutval[0] |= LUT_DEF(0, LUT_CMD_DDR, LUT_PAD(op->cmd.buswidth),
+				     op->cmd.opcode >> 8);
+		lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_CMD_DDR,
+					      LUT_PAD(op->cmd.buswidth),
+					      op->cmd.opcode & 0x00ff);
+		lutidx++;
+	} else {
+		lutval[0] |= LUT_DEF(0, LUT_CMD_SDR, LUT_PAD(op->cmd.buswidth),
+				     op->cmd.opcode);
+	}
+
+	/* Addr bytes */
+	if (op->addr.nbytes) {
+		lutval[lutidx / 2] |= LUT_DEF(lutidx, op->addr.dtr ?
+					      LUT_ADDR_DDR : LUT_ADDR_SDR,
+					      LUT_PAD(op->addr.buswidth),
+					      op->addr.nbytes * 8);
+		lutidx++;
+	}
+
+	/* Dummy bytes, if needed */
+	if (op->dummy.nbytes) {
+		lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_DUMMY,
+					      LUT_PAD(op->data.buswidth),
+					      op->dummy.nbytes * 8 /
+						/* need distinguish ddr mode */
+					      op->dummy.buswidth / (op->dummy.dtr ? 2 : 1));
+		lutidx++;
+	}
+
+	/* Read/Write data bytes */
+	if (op->data.nbytes) {
+		lutval[lutidx / 2] |= LUT_DEF(lutidx,
+					      op->data.dir == SPI_MEM_DATA_IN ?
+					      (op->data.dtr ? LUT_READ_DDR : LUT_READ_SDR) :
+					      (op->data.dtr ? LUT_WRITE_DDR : LUT_WRITE_SDR),
+					      LUT_PAD(op->data.buswidth),
+					      0);
+		lutidx++;
+	}
+
+	/* Stop condition. */
+	lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_STOP, 0, 0);
+
+	/* Unlock LUT */
+	writel(XSPI_LUT_KEY_VAL, xspi->iobase + XSPI_LUTKEY);
+	writel(XSPI_LOKCR_UNLOCK, xspi->iobase + XSPI_LCKCR);
+
+	/* Fill LUT */
+	for (i = 0; i < ARRAY_SIZE(lutval); i++)
+		writel(lutval[i], base + XSPI_LUT_REG(i));
+
+	dev_dbg(xspi->dev, "CMD[%02x] lutval[0:%08x 1:%08x 2:%08x 3:%08x 4:%08x], size: 0x%08x\n",
+		op->cmd.opcode, lutval[0], lutval[1], lutval[2], lutval[3], lutval[4],
+		op->data.nbytes);
+
+	/* Lock LUT */
+	writel(XSPI_LUT_KEY_VAL, xspi->iobase + XSPI_LUTKEY);
+	writel(XSPI_LOKCR_LOCK, xspi->iobase + XSPI_LCKCR);
+}
+
+static void nxp_xspi_disable_ddr(struct nxp_xspi *xspi)
+{
+	void __iomem *base = xspi->iobase;
+	u32 reg;
+
+	/* Disable module */
+	reg = readl(base + XSPI_MCR);
+	reg |= XSPI_MCR_MDIS;
+	writel(reg, base + XSPI_MCR);
+
+	reg &= ~XSPI_MCR_DDR_EN;
+	reg &= ~XSPI_MCR_DQS_FA_SEL_MASK;
+	/* Use dummy pad loopback mode to sample data */
+	reg |= FIELD_PREP(XSPI_MCR_DQS_FA_SEL_MASK, 0x01);
+	writel(reg, base + XSPI_MCR);
+	xspi->support_max_rate = 133000000;
+
+	reg = readl(base + XSPI_FLSHCR);
+	reg &= ~XSPI_FLSHCR_TDH_MASK;
+	writel(reg, base + XSPI_FLSHCR);
+
+	/* Select sampling at inverted clock */
+	reg = FIELD_PREP(XSPI_SMPR_DLLFSMPFA_MASK, 0) | XSPI_SMPR_FSPHS;
+	writel(reg, base + XSPI_SMPR);
+
+	/* Enable module */
+	reg = readl(base + XSPI_MCR);
+	reg &= ~XSPI_MCR_MDIS;
+	writel(reg, base + XSPI_MCR);
+}
+
+static void nxp_xspi_enable_ddr(struct nxp_xspi *xspi)
+{
+	void __iomem *base = xspi->iobase;
+	u32 reg;
+
+	/* Disable module */
+	reg = readl(base + XSPI_MCR);
+	reg |= XSPI_MCR_MDIS;
+	writel(reg, base + XSPI_MCR);
+
+	reg |= XSPI_MCR_DDR_EN;
+	reg &= ~XSPI_MCR_DQS_FA_SEL_MASK;
+	/* Use external dqs to sample data */
+	reg |= FIELD_PREP(XSPI_MCR_DQS_FA_SEL_MASK, 0x03);
+	writel(reg, base + XSPI_MCR);
+	xspi->support_max_rate = 200000000;
+
+	reg = readl(base + XSPI_FLSHCR);
+	reg &= ~XSPI_FLSHCR_TDH_MASK;
+	reg |= FIELD_PREP(XSPI_FLSHCR_TDH_MASK, 0x01);
+	writel(reg, base + XSPI_FLSHCR);
+
+	reg = FIELD_PREP(XSPI_SMPR_DLLFSMPFA_MASK, 0x04);
+	writel(reg, base + XSPI_SMPR);
+
+	/* Enable module */
+	reg = readl(base + XSPI_MCR);
+	reg &= ~XSPI_MCR_MDIS;
+	writel(reg, base + XSPI_MCR);
+}
+
+static void nxp_xspi_sw_reset(struct nxp_xspi *xspi)
+{
+	void __iomem *base = xspi->iobase;
+	bool mdis_flag = false;
+	u32 reg;
+	int ret;
+
+	reg = readl(base + XSPI_MCR);
+
+	/*
+	 * Per RM, when reset SWRSTSD and SWRSTHD, XSPI must be
+	 * enabled (MDIS = 0).
+	 * So if MDIS is 1, should clear it before assert SWRSTSD
+	 * and SWRSTHD.
+	 */
+	if (reg & XSPI_MCR_MDIS) {
+		reg &= ~XSPI_MCR_MDIS;
+		writel(reg, base + XSPI_MCR);
+		mdis_flag = true;
+	}
+
+	/* Software reset for AHB domain and Serial flash memory domain */
+	reg |= XSPI_MCR_SWRSTHD | XSPI_MCR_SWRSTSD;
+	/* Software Reset for IPS Target Group Queue 0 */
+	reg |= XSPI_MCR_IPS_TG_RST;
+	writel(reg, base + XSPI_MCR);
+
+	/* IPS_TG_RST will self-clear to 0 once IPS_TG_RST complete */
+	ret = readl_poll_timeout(base + XSPI_MCR, reg, !(reg & XSPI_MCR_IPS_TG_RST),
+			      100, 5000);
+	if (ret == -ETIMEDOUT)
+		dev_warn(xspi->dev, "XSPI_MCR_IPS_TG_RST do not self-clear in 5ms!");
+
+	/*
+	 * Per RM, must wait for at least three system cycles and
+	 * three flash cycles after changing the value of reset field.
+	 * delay 5us for safe.
+	 */
+	fsleep(5);
+
+	/*
+	 * Per RM, before dessert SWRSTSD and SWRSTHD, XSPI must be
+	 * disabled (MIDS = 1).
+	 */
+	reg = readl(base + XSPI_MCR);
+	reg |= XSPI_MCR_MDIS;
+	writel(reg, base + XSPI_MCR);
+
+	/* deassert software reset */
+	reg &= ~(XSPI_MCR_SWRSTHD | XSPI_MCR_SWRSTSD);
+	writel(reg, base + XSPI_MCR);
+
+	/*
+	 * Per RM, must wait for at least three system cycles and
+	 * three flash cycles after changing the value of reset field.
+	 * delay 5us for safe.
+	 */
+	fsleep(5);
+
+	/* Re-enable XSPI if it is enabled at beginning */
+	if (!mdis_flag) {
+		reg &= ~XSPI_MCR_MDIS;
+		writel(reg, base + XSPI_MCR);
+	}
+}
+
+static void nxp_xspi_dll_bypass(struct nxp_xspi *xspi)
+{
+	void __iomem *base = xspi->iobase;
+	int ret;
+	u32 reg;
+
+	nxp_xspi_sw_reset(xspi);
+
+	writel(0, base + XSPI_DLLCRA);
+
+	/* Set SLV EN first */
+	reg = XSPI_DLLCRA_SLV_EN;
+	writel(reg, base + XSPI_DLLCRA);
+
+	reg = XSPI_DLLCRA_FREQEN |
+	      FIELD_PREP(XSPI_DLLCRA_SLV_DLY_COARSE_MASK, 0x0) |
+	      XSPI_DLLCRA_SLV_EN | XSPI_DLLCRA_SLV_DLL_BYPASS;
+	writel(reg, base + XSPI_DLLCRA);
+
+	reg |= XSPI_DLLCRA_SLV_UPD;
+	writel(reg, base + XSPI_DLLCRA);
+
+	ret = readl_poll_timeout(base + XSPI_DLLSR, reg,
+			      reg & XSPI_DLLSR_SLVA_LOCK, 0, POLL_TOUT_US);
+	if (ret)
+		dev_err(xspi->dev,
+			"DLL SLVA unlock, the DLL status is %x, need to check!\n",
+			readl(base + XSPI_DLLSR));
+}
+
+static void nxp_xspi_dll_auto(struct nxp_xspi *xspi, unsigned long rate)
+{
+	void __iomem *base = xspi->iobase;
+	int ret;
+	u32 reg;
+
+	nxp_xspi_sw_reset(xspi);
+
+	writel(0, base + XSPI_DLLCRA);
+
+	/* Set SLV EN first */
+	reg = XSPI_DLLCRA_SLV_EN;
+	writel(reg, base + XSPI_DLLCRA);
+
+	reg = FIELD_PREP(XSPI_DLLCRA_DLL_REFCNTR_MASK, 0x02) |
+	      FIELD_PREP(XSPI_DLLCRA_DLLRES_MASK, 0x08) |
+	      XSPI_DLLCRA_SLAVE_AUTO_UPDT | XSPI_DLLCRA_SLV_EN;
+	if (rate > 133000000)
+		reg |= XSPI_DLLCRA_FREQEN;
+
+	writel(reg, base + XSPI_DLLCRA);
+
+	reg |= XSPI_DLLCRA_SLV_UPD;
+	writel(reg, base + XSPI_DLLCRA);
+
+	reg |= XSPI_DLLCRA_DLLEN;
+	writel(reg, base + XSPI_DLLCRA);
+
+	ret = readl_poll_timeout(base + XSPI_DLLSR, reg,
+			      reg & XSPI_DLLSR_DLLA_LOCK, 0, POLL_TOUT_US);
+	if (ret)
+		dev_err(xspi->dev,
+			"DLL unlock, the DLL status is %x, need to check!\n",
+			readl(base + XSPI_DLLSR));
+
+	ret = readl_poll_timeout(base + XSPI_DLLSR, reg,
+			      reg & XSPI_DLLSR_SLVA_LOCK, 0, POLL_TOUT_US);
+	if (ret)
+		dev_err(xspi->dev,
+			"DLL SLVA unlock, the DLL status is %x, need to check!\n",
+			readl(base + XSPI_DLLSR));
+}
+
+static void nxp_xspi_select_mem(struct nxp_xspi *xspi, struct spi_device *spi,
+				const struct spi_mem_op *op)
+{
+	/* xspi only support one DTR mode: 8D-8D-8D */
+	bool op_is_dtr = op->cmd.dtr && op->addr.dtr && op->dummy.dtr && op->data.dtr;
+	unsigned long root_clk_rate, rate;
+	uint64_t cs0_top_address;
+	uint64_t cs1_top_address;
+	u32 reg;
+	int ret;
+
+	/*
+	 * Return when following condition all meet,
+	 * 1, if previously selected target device is same as current
+	 *    requested target device.
+	 * 2, the DTR or STR mode do not change.
+	 * 3, previous operation max rate equals current one.
+	 *
+	 * For other case, need to re-config.
+	 */
+	if (xspi->selected == spi_get_chipselect(spi, 0) &&
+	    (!!(xspi->flags & XSPI_DTR_PROTO) == op_is_dtr) &&
+	    (xspi->pre_op_rate == op->max_freq))
+		return;
+
+	if (op_is_dtr) {
+		nxp_xspi_enable_ddr(xspi);
+		xspi->flags |= XSPI_DTR_PROTO;
+	} else {
+		nxp_xspi_disable_ddr(xspi);
+		xspi->flags &= ~XSPI_DTR_PROTO;
+	}
+	rate = min_t(unsigned long, xspi->support_max_rate, op->max_freq);
+	/*
+	 * There is two dividers between xspi_clk_root(from SoC CCM) and xspi_sfif.
+	 * xspi_clk_root ---->divider1 ----> ipg_clk_2xsfif
+	 *                              |
+	 *                              |
+	 *                              |---> divider2 ---> ipg_clk_sfif
+	 * divider1 is controlled by SOCCR, SOCCR default value is 0.
+	 * divider2 fix to divide 2.
+	 * when SOCCR = 0:
+	 *        ipg_clk_2xsfif = xspi_clk_root
+	 *        ipg_clk_sfif = ipg_clk_2xsfif / 2 = xspi_clk_root / 2
+	 * ipg_clk_2xsfif is used for DTR mode.
+	 * xspi_sck(output to device) is defined based on xspi_sfif clock.
+	 */
+	root_clk_rate = rate * 2;
+
+	clk_disable_unprepare(xspi->clk);
+
+	ret = clk_set_rate(xspi->clk, root_clk_rate);
+	if (ret)
+		return;
+
+	ret = clk_prepare_enable(xspi->clk);
+	if (ret)
+		return;
+
+	xspi->pre_op_rate = op->max_freq;
+	xspi->selected = spi_get_chipselect(spi, 0);
+
+	if (xspi->selected) {		/* CS1 select */
+		cs0_top_address = xspi->memmap_phy;
+		cs1_top_address = SZ_4G - 1;
+	} else {			/* CS0 select */
+		cs0_top_address = SZ_4G - 1;
+		cs1_top_address = SZ_4G - 1;
+	}
+	writel(cs0_top_address, xspi->iobase + XSPI_SFA1AD);
+	writel(cs1_top_address, xspi->iobase + XSPI_SFA2AD);
+
+	reg = readl(xspi->iobase + XSPI_SFACR);
+	if (op->data.swap16)
+		reg |= XSPI_SFACR_BYTE_SWAP;
+	else
+		reg &= ~XSPI_SFACR_BYTE_SWAP;
+	writel(reg, xspi->iobase + XSPI_SFACR);
+
+	if (!op_is_dtr || rate < 60000000)
+		nxp_xspi_dll_bypass(xspi);
+	else
+		nxp_xspi_dll_auto(xspi, rate);
+}
+
+static int nxp_xspi_ahb_read(struct nxp_xspi *xspi, const struct spi_mem_op *op)
+{
+	u32 start = op->addr.val;
+	u32 len = op->data.nbytes;
+
+	/* If necessary, ioremap before AHB read */
+	if ((!xspi->ahb_addr) || start < xspi->memmap_start ||
+	     start + len > xspi->memmap_start + xspi->memmap_len) {
+		if (xspi->ahb_addr)
+			iounmap(xspi->ahb_addr);
+
+		xspi->memmap_start = start;
+		xspi->memmap_len = len > NXP_XSPI_MIN_IOMAP ?
+				len : NXP_XSPI_MIN_IOMAP;
+
+		xspi->ahb_addr = ioremap(xspi->memmap_phy + xspi->memmap_start,
+					 xspi->memmap_len);
+
+		if (!xspi->ahb_addr) {
+			dev_err(xspi->dev, "failed to alloc memory\n");
+			return -ENOMEM;
+		}
+	}
+
+	/* Read out the data directly from the AHB buffer. */
+	memcpy_fromio(op->data.buf.in,
+			xspi->ahb_addr + start - xspi->memmap_start, len);
+
+	return 0;
+}
+
+static int nxp_xspi_fill_txfifo(struct nxp_xspi *xspi,
+				 const struct spi_mem_op *op)
+{
+	void __iomem *base = xspi->iobase;
+	u8 *buf = (u8 *)op->data.buf.out;
+	u32 reg, left;
+	int i;
+
+	for (i = 0; i < ALIGN(op->data.nbytes, 4); i += 4) {
+		reg = readl(base + XSPI_FR);
+		reg |= XSPI_FR_TBFF;
+		writel(reg, base + XSPI_FR);
+		/* Read again to check whether the tx fifo has rom */
+		reg = readl(base + XSPI_FR);
+		if (!(reg & XSPI_FR_TBFF)) {
+			WARN_ON(1);
+			return -EIO;
+		}
+
+		if (i == ALIGN_DOWN(op->data.nbytes, 4)) {
+			/* Use 0xFF for extra bytes */
+			left = 0xFFFFFFFF;
+			/* The last 1 to 3 bytes */
+			memcpy((u8 *)&left, buf + i, op->data.nbytes - i);
+			writel(left, base + XSPI_TBDR);
+		} else {
+			writel(*(u32 *)(buf + i), base + XSPI_TBDR);
+		}
+	}
+
+	return 0;
+}
+
+static int nxp_xspi_read_rxfifo(struct nxp_xspi *xspi,
+				const struct spi_mem_op *op)
+{
+	u32 watermark, watermark_bytes, reg;
+	void __iomem *base = xspi->iobase;
+	u8 *buf = (u8 *) op->data.buf.in;
+	int i, ret, len;
+
+	/*
+	 * Config the rx watermark half of the 64 memory-mapped RX data buffer RBDRn
+	 * refer to the RBCT config in nxp_xspi_do_op()
+	 */
+	watermark = 32;
+	watermark_bytes = watermark * 4;
+
+	len = op->data.nbytes;
+
+	while (len >= watermark_bytes) {
+		/* Make sure the RX FIFO contains valid data before read */
+		ret = readl_poll_timeout(base + XSPI_FR, reg,
+				      reg & XSPI_FR_RBDF, 0, POLL_TOUT_US);
+		if (ret) {
+			WARN_ON(1);
+			return ret;
+		}
+
+		for (i = 0; i < watermark; i++)
+			*(u32 *)(buf + i * 4) = readl(base + XSPI_RBDR0 + i * 4);
+
+		len = len - watermark_bytes;
+		buf = buf + watermark_bytes;
+		/* Pop up data to RXFIFO for next read. */
+		reg = readl(base + XSPI_FR);
+		reg |= XSPI_FR_RBDF;
+		writel(reg, base + XSPI_FR);
+	}
+
+	/* Wait for the total data transfer finished */
+	ret = readl_poll_timeout(base + XSPI_SR, reg, !(reg & XSPI_SR_BUSY), 0, POLL_TOUT_US);
+	if (ret) {
+		WARN_ON(1);
+		return ret;
+	}
+
+	i = 0;
+	while (len >= 4) {
+		*(u32 *)(buf) = readl(base + XSPI_RBDR0 + i);
+		i += 4;
+		len -= 4;
+		buf += 4;
+	}
+
+	if (len > 0) {
+		reg = readl(base + XSPI_RBDR0 + i);
+		memcpy(buf, (u8 *)&reg, len);
+	}
+
+	/* Invalid RXFIFO first */
+	reg = readl(base + XSPI_MCR);
+	reg |= XSPI_MCR_CLR_RXF;
+	writel(reg, base + XSPI_MCR);
+	/* Wait for the CLR_RXF clear */
+	ret = readl_poll_timeout(base + XSPI_MCR, reg,
+			      !(reg & XSPI_MCR_CLR_RXF), 1, POLL_TOUT_US);
+	WARN_ON(ret);
+
+	return ret;
+}
+
+static int nxp_xspi_do_op(struct nxp_xspi *xspi, const struct spi_mem_op *op)
+{
+	void __iomem *base = xspi->iobase;
+	int watermark, err = 0;
+	u32 reg, len;
+
+	len = op->data.nbytes;
+	if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_OUT) {
+		/* Clear the TX FIFO. */
+		reg = readl(base + XSPI_MCR);
+		reg |= XSPI_MCR_CLR_TXF;
+		writel(reg, base + XSPI_MCR);
+		/* Wait for the CLR_TXF clear */
+		err = readl_poll_timeout(base + XSPI_MCR, reg,
+				      !(reg & XSPI_MCR_CLR_TXF), 1, POLL_TOUT_US);
+		if (err) {
+			WARN_ON(1);
+			return err;
+		}
+
+		/* Cover the no 4bytes alignment data length */
+		watermark = (xspi->devtype_data->txfifo - ALIGN(op->data.nbytes, 4)) / 4 + 1;
+		reg = FIELD_PREP(XSPI_TBCT_WMRK_MASK, watermark);
+		writel(reg, base + XSPI_TBCT);
+		/*
+		 * According to the RM, for TBDR register, a write transaction on the
+		 * flash memory with data size of less than 32 bits leads to the removal
+		 * of one data entry from the TX buffer. The valid bits are used and the
+		 * rest of the bits are discarded.
+		 * But for data size large than 32 bits, according to test, for no 4bytes
+		 * alignment data, the last 1~3 bytes will lost, because TX buffer use
+		 * 4 bytes entries.
+		 * So here adjust the transfer data length to make it 4bytes alignment.
+		 * then will meet the upper watermark setting, trigger the 4bytes entries
+		 * pop out.
+		 * Will use extra 0xff to append, refer to nxp_xspi_fill_txfifo().
+		 */
+		if (len > 4)
+			len = ALIGN(op->data.nbytes, 4);
+
+	} else if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_IN) {
+		/* Invalid RXFIFO first */
+		reg = readl(base + XSPI_MCR);
+		reg |= XSPI_MCR_CLR_RXF;
+		writel(reg, base + XSPI_MCR);
+		/* Wait for the CLR_RXF clear */
+		err = readl_poll_timeout(base + XSPI_MCR, reg,
+				      !(reg & XSPI_MCR_CLR_RXF), 1, POLL_TOUT_US);
+		if (err) {
+			WARN_ON(1);
+			return err;
+		}
+
+		reg = FIELD_PREP(XSPI_RBCT_WMRK_MASK, 31);
+		writel(reg, base + XSPI_RBCT);
+	}
+
+	init_completion(&xspi->c);
+
+	/* Config the data address */
+	writel(op->addr.val + xspi->memmap_phy, base + XSPI_SFP_TG_SFAR);
+
+	/* Config the data size and lut id, trigger the transfer */
+	reg = FIELD_PREP(XSPI_SFP_TG_IPCR_SEQID_MASK, XSPI_SEQID_LUT) |
+	      FIELD_PREP(XSPI_SFP_TG_IPCR_IDATSZ_MASK, len);
+	writel(reg, base + XSPI_SFP_TG_IPCR);
+
+	if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_OUT) {
+		err = nxp_xspi_fill_txfifo(xspi, op);
+		if (err)
+			return err;
+	}
+
+	/* Wait for the interrupt. */
+	if (!wait_for_completion_timeout(&xspi->c, msecs_to_jiffies(1000)))
+		err = -ETIMEDOUT;
+
+	/* Invoke IP data read. */
+	if (!err && op->data.nbytes && op->data.dir == SPI_MEM_DATA_IN)
+		err = nxp_xspi_read_rxfifo(xspi, op);
+
+	return err;
+}
+
+static int nxp_xspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
+{
+	struct nxp_xspi *xspi = spi_controller_get_devdata(mem->spi->controller);
+	void __iomem *base = xspi->iobase;
+	u32 reg;
+	int err;
+
+	guard(mutex)(&xspi->lock);
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(xspi->dev, pm);
+	err = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (err)
+		return err;
+
+	/* Wait for controller being ready. */
+	err = readl_poll_timeout(base + XSPI_SR, reg,
+			      !(reg & XSPI_SR_BUSY), 1, POLL_TOUT_US);
+	if (err) {
+		dev_err(xspi->dev, "SR keeps in BUSY!");
+		return err;
+	}
+
+	nxp_xspi_select_mem(xspi, mem->spi, op);
+
+	nxp_xspi_prepare_lut(xspi, op);
+
+	/*
+	 * For read:
+	 *     the address in AHB mapped range will use AHB read.
+	 *     the address out of AHB mapped range will use IP read.
+	 * For write:
+	 *     all use IP write.
+	 */
+	if ((op->data.dir == SPI_MEM_DATA_IN) && !needs_ip_only(xspi)
+		&& ((op->addr.val + op->data.nbytes) <= xspi->memmap_phy_size))
+		err = nxp_xspi_ahb_read(xspi, op);
+	else
+		err = nxp_xspi_do_op(xspi, op);
+
+	nxp_xspi_sw_reset(xspi);
+
+	return err;
+}
+
+static int nxp_xspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
+{
+	struct nxp_xspi *xspi = spi_controller_get_devdata(mem->spi->controller);
+
+	if (op->data.dir == SPI_MEM_DATA_OUT) {
+		if (op->data.nbytes > xspi->devtype_data->txfifo)
+			op->data.nbytes = xspi->devtype_data->txfifo;
+	} else {
+		/* Limit data bytes to RX FIFO in case of IP read only */
+		if (needs_ip_only(xspi) && (op->data.nbytes > xspi->devtype_data->rxfifo))
+			op->data.nbytes = xspi->devtype_data->rxfifo;
+
+		/* Address in AHB mapped range prefer to use AHB read. */
+		if (!needs_ip_only(xspi) && (op->addr.val < xspi->memmap_phy_size)
+			&& ((op->addr.val + op->data.nbytes) > xspi->memmap_phy_size))
+			op->data.nbytes = xspi->memmap_phy_size - op->addr.val;
+	}
+
+	return 0;
+}
+
+static void nxp_xspi_config_ahb_buffer(struct nxp_xspi *xspi)
+{
+	void __iomem *base = xspi->iobase;
+	u32 ahb_data_trans_size;
+	u32 reg;
+
+	writel(0xA, base + XSPI_BUF0CR);
+	writel(0x2, base + XSPI_BUF1CR);
+	writel(0xD, base + XSPI_BUF2CR);
+
+	/* Configure buffer3 for All Master Access */
+	reg = FIELD_PREP(XSPI_BUF3CR_MSTRID_MASK, 0x06) |
+	      XSPI_BUF3CR_ALLMST;
+
+	ahb_data_trans_size = xspi->devtype_data->ahb_buf_size / 8;
+	reg |= FIELD_PREP(XSPI_BUF3CR_ADATSZ_MASK, ahb_data_trans_size);
+	writel(reg, base + XSPI_BUF3CR);
+
+	/* Only the buffer3 is used */
+	writel(0, base + XSPI_BUF0IND);
+	writel(0, base + XSPI_BUF1IND);
+	writel(0, base + XSPI_BUF2IND);
+
+	/* AHB only use ID=15 for read */
+	reg = FIELD_PREP(XSPI_BFGENCR_SEQID_MASK, XSPI_SEQID_LUT);
+	reg |= XSPI_BFGENCR_WR_FLUSH_EN;
+	/* No limit for align */
+	reg |= FIELD_PREP(XSPI_BFGENCR_ALIGN_MASK, 0);
+	writel(reg, base + XSPI_BFGENCR);
+}
+
+static int nxp_xspi_default_setup(struct nxp_xspi *xspi)
+{
+	void __iomem *base = xspi->iobase;
+	u32 reg;
+
+	/* Bypass SFP check, clear MGC_GVLD, MGC_GVLDMDAD, MGC_GVLDFRAD */
+	writel(0, base + XSPI_MGC);
+
+	/* Enable the EENV0 SFP check */
+	reg = readl(base + XSPI_TG0MDAD);
+	reg |= XSPI_TG0MDAD_VLD;
+	writel(reg, base + XSPI_TG0MDAD);
+
+	/* Give read/write access right to EENV0 */
+	reg = readl(base + XSPI_FRAD0_WORD2);
+	reg &= ~XSPI_FRAD0_WORD2_MD0ACP_MASK;
+	reg |= FIELD_PREP(XSPI_FRAD0_WORD2_MD0ACP_MASK, 0x03);
+	writel(reg, base + XSPI_FRAD0_WORD2);
+
+	/* Enable the FRAD check for EENV0 */
+	reg = readl(base + XSPI_FRAD0_WORD3);
+	reg |= XSPI_FRAD0_WORD3_VLD;
+	writel(reg, base + XSPI_FRAD0_WORD3);
+
+	/*
+	 * Config the timeout to max value, this timeout will affect the
+	 * TBDR and RBDRn access right after IP cmd triggered.
+	 */
+	writel(0xFFFFFFFF, base + XSPI_MTO);
+
+	/* Disable module */
+	reg = readl(base + XSPI_MCR);
+	reg |= XSPI_MCR_MDIS;
+	writel(reg, base + XSPI_MCR);
+
+	nxp_xspi_sw_reset(xspi);
+
+	reg = readl(base + XSPI_MCR);
+	reg &= ~(XSPI_MCR_CKN_FA_EN | XSPI_MCR_DQS_FA_SEL_MASK |
+		 XSPI_MCR_DOZE | XSPI_MCR_VAR_LAT_EN |
+		 XSPI_MCR_DDR_EN | XSPI_MCR_DQS_OUT_EN);
+	reg |= XSPI_MCR_DQS_EN;
+	reg |= XSPI_MCR_ISD3FA | XSPI_MCR_ISD2FA;
+	writel(reg, base + XSPI_MCR);
+
+	reg = readl(base + XSPI_SFACR);
+	reg &= ~(XSPI_SFACR_FORCE_A10 | XSPI_SFACR_WA_4B_EN |
+		 XSPI_SFACR_BYTE_SWAP | XSPI_SFACR_WA |
+		 XSPI_SFACR_CAS_MASK);
+	reg |= XSPI_SFACR_FORCE_A10;
+	writel(reg, base + XSPI_SFACR);
+
+	nxp_xspi_config_ahb_buffer(xspi);
+
+	reg = FIELD_PREP(XSPI_FLSHCR_TCSH_MASK, 0x03) |
+	      FIELD_PREP(XSPI_FLSHCR_TCSS_MASK, 0x03);
+	writel(reg, base + XSPI_FLSHCR);
+
+	/* Enable module */
+	reg = readl(base + XSPI_MCR);
+	reg &= ~XSPI_MCR_MDIS;
+	writel(reg, base + XSPI_MCR);
+
+	xspi->selected = -1;
+
+	/* Enable the interrupt */
+	writel(XSPI_RSER_TFIE, base + XSPI_RSER);
+
+	return 0;
+}
+
+static const char *nxp_xspi_get_name(struct spi_mem *mem)
+{
+	struct nxp_xspi *xspi = spi_controller_get_devdata(mem->spi->controller);
+	struct device *dev = &mem->spi->dev;
+	const char *name;
+
+	/* Set custom name derived from the platform_device of the controller. */
+	if (of_get_available_child_count(xspi->dev->of_node) == 1)
+		return dev_name(xspi->dev);
+
+	name = devm_kasprintf(dev, GFP_KERNEL,
+			      "%s-%d", dev_name(xspi->dev),
+			      spi_get_chipselect(mem->spi, 0));
+
+	if (!name) {
+		dev_err(dev, "failed to get memory for custom flash name\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	return name;
+}
+
+static const struct spi_controller_mem_ops nxp_xspi_mem_ops = {
+	.adjust_op_size = nxp_xspi_adjust_op_size,
+	.supports_op = nxp_xspi_supports_op,
+	.exec_op = nxp_xspi_exec_op,
+	.get_name = nxp_xspi_get_name,
+};
+
+static const struct spi_controller_mem_caps nxp_xspi_mem_caps = {
+	.dtr = true,
+	.per_op_freq = true,
+	.swap16 = true,
+};
+
+static void nxp_xspi_cleanup(void *data)
+{
+	struct nxp_xspi *xspi = data;
+	u32 reg;
+
+	pm_runtime_get_sync(xspi->dev);
+
+	/* Disable interrupt */
+	writel(0, xspi->iobase + XSPI_RSER);
+	/* Clear all the internal logic flags */
+	writel(0xFFFFFFFF, xspi->iobase + XSPI_FR);
+	/* Disable the hardware */
+	reg = readl(xspi->iobase + XSPI_MCR);
+	reg |= XSPI_MCR_MDIS;
+	writel(reg, xspi->iobase + XSPI_MCR);
+
+	pm_runtime_put_sync(xspi->dev);
+
+	if (xspi->ahb_addr)
+		iounmap(xspi->ahb_addr);
+}
+
+static int nxp_xspi_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct spi_controller *ctlr;
+	struct nxp_xspi *xspi;
+	struct resource *res;
+	int ret, irq;
+
+	ctlr = devm_spi_alloc_host(dev, sizeof(*xspi));
+	if (!ctlr)
+		return -ENOMEM;
+
+	ctlr->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL |
+			  SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL;
+
+	xspi = spi_controller_get_devdata(ctlr);
+	xspi->dev = dev;
+	xspi->devtype_data = device_get_match_data(dev);
+	if (!xspi->devtype_data)
+		return -ENODEV;
+
+	platform_set_drvdata(pdev, xspi);
+
+	/* Find the resources - configuration register address space */
+	xspi->iobase = devm_platform_ioremap_resource_byname(pdev, "base");
+	if (IS_ERR(xspi->iobase))
+		return PTR_ERR(xspi->iobase);
+
+	/* Find the resources - controller memory mapped space */
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mmap");
+	if (!res)
+		return -ENODEV;
+
+	/* Assign memory mapped starting address and mapped size. */
+	xspi->memmap_phy = res->start;
+	xspi->memmap_phy_size = resource_size(res);
+
+	/* Find the clocks */
+	xspi->clk = devm_clk_get(dev, "per");
+	if (IS_ERR(xspi->clk))
+		return PTR_ERR(xspi->clk);
+
+	/* Find the irq */
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return dev_err_probe(dev, irq,  "Failed to get irq source");
+
+	pm_runtime_set_autosuspend_delay(dev, XSPI_RPM_TIMEOUT_MS);
+	pm_runtime_use_autosuspend(dev);
+	ret = devm_pm_runtime_enable(dev);
+	if (ret)
+		return ret;
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to enable clock");
+
+	/* Clear potential interrupt by write xspi errstat */
+	writel(0xFFFFFFFF, xspi->iobase + XSPI_ERRSTAT);
+	writel(0xFFFFFFFF, xspi->iobase + XSPI_FR);
+
+	nxp_xspi_default_setup(xspi);
+
+	ret = devm_request_irq(dev, irq,
+			nxp_xspi_irq_handler, 0, pdev->name, xspi);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to request irq");
+
+	ret = devm_mutex_init(dev, &xspi->lock);
+	if (ret)
+		return ret;
+
+	ret = devm_add_action_or_reset(dev, nxp_xspi_cleanup, xspi);
+	if (ret)
+		return ret;
+
+	ctlr->bus_num = -1;
+	ctlr->num_chipselect = NXP_XSPI_MAX_CHIPSELECT;
+	ctlr->mem_ops = &nxp_xspi_mem_ops;
+	ctlr->mem_caps = &nxp_xspi_mem_caps;
+	ctlr->dev.of_node = dev->of_node;
+
+	return devm_spi_register_controller(dev, ctlr);
+}
+
+static int nxp_xspi_runtime_suspend(struct device *dev)
+{
+	struct nxp_xspi *xspi = dev_get_drvdata(dev);
+	u32 reg;
+
+	reg = readl(xspi->iobase + XSPI_MCR);
+	reg |= XSPI_MCR_MDIS;
+	writel(reg, xspi->iobase + XSPI_MCR);
+
+	clk_disable_unprepare(xspi->clk);
+
+	return 0;
+}
+
+static int nxp_xspi_runtime_resume(struct device *dev)
+{
+	struct nxp_xspi *xspi = dev_get_drvdata(dev);
+	u32 reg;
+	int ret;
+
+	ret = clk_prepare_enable(xspi->clk);
+	if (ret)
+		return ret;
+
+	reg = readl(xspi->iobase + XSPI_MCR);
+	reg &= ~XSPI_MCR_MDIS;
+	writel(reg, xspi->iobase + XSPI_MCR);
+
+	return 0;
+}
+
+static int nxp_xspi_suspend(struct device *dev)
+{
+	int ret;
+
+	ret = pinctrl_pm_select_sleep_state(dev);
+	if (ret) {
+		dev_err(dev, "select flexspi sleep pinctrl failed!\n");
+		return ret;
+	}
+
+	return pm_runtime_force_suspend(dev);
+}
+
+static int nxp_xspi_resume(struct device *dev)
+{
+	struct nxp_xspi *xspi = dev_get_drvdata(dev);
+	int ret;
+
+	ret = pm_runtime_force_resume(dev);
+	if (ret)
+		return ret;
+
+	nxp_xspi_default_setup(xspi);
+
+	ret = pinctrl_pm_select_default_state(dev);
+	if (ret)
+		dev_err(dev, "select flexspi default pinctrl failed!\n");
+
+	return ret;
+}
+
+
+static const struct dev_pm_ops nxp_xspi_pm_ops = {
+	RUNTIME_PM_OPS(nxp_xspi_runtime_suspend, nxp_xspi_runtime_resume, NULL)
+	SYSTEM_SLEEP_PM_OPS(nxp_xspi_suspend, nxp_xspi_resume)
+};
+
+static const struct of_device_id nxp_xspi_dt_ids[] = {
+	{ .compatible = "nxp,imx94-xspi", .data = (void *)&imx94_data, },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, nxp_xspi_dt_ids);
+
+static struct platform_driver nxp_xspi_driver = {
+	.driver = {
+		.name	= "nxp-xspi",
+		.of_match_table = nxp_xspi_dt_ids,
+		.pm =   pm_ptr(&nxp_xspi_pm_ops),
+	},
+	.probe          = nxp_xspi_probe,
+};
+module_platform_driver(nxp_xspi_driver);
+
+MODULE_DESCRIPTION("NXP xSPI Controller Driver");
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_AUTHOR("Haibo Chen <haibo.chen at nxp.com>");
+MODULE_LICENSE("GPL");

-- 
2.34.1



From baolin.wang at linux.alibaba.com  Mon Dec 15 19:32:58 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Tue, 16 Dec 2025 11:32:58 +0800
Subject: [PATCH v2 1/3] arm64: mm: support batch clearing of the young
 flag for large folios
In-Reply-To: <5039c6a2-09b6-4c9b-accb-26583ba120db@lucifer.local>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <e10f876ce130134fa089befe83f30561b48b9889.1765439380.git.baolin.wang@linux.alibaba.com>
 <5039c6a2-09b6-4c9b-accb-26583ba120db@lucifer.local>
Message-ID: <1a0001cd-c38d-403b-b3ef-d19e85acd772@linux.alibaba.com>



On 2025/12/15 19:36, Lorenzo Stoakes wrote:
> On Thu, Dec 11, 2025 at 04:16:54PM +0800, Baolin Wang wrote:
>> Currently, contpte_ptep_test_and_clear_young() and contpte_ptep_clear_flush_young()
>> only clear the young flag and flush TLBs for PTEs within the contiguous range.
>> To support batch PTE operations for other sized large folios in the following
>> patches, adding a new parameter to specify the number of PTEs.
>>
>> While we are at it, rename the functions to maintain consistency with other
>> contpte_*() functions.
>>
>> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
>> ---
>>   arch/arm64/include/asm/pgtable.h | 12 ++++-----
>>   arch/arm64/mm/contpte.c          | 44 ++++++++++++++++++++++----------
>>   2 files changed, 37 insertions(+), 19 deletions(-)
>>
>> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
>> index 0944e296dd4a..e03034683156 100644
>> --- a/arch/arm64/include/asm/pgtable.h
>> +++ b/arch/arm64/include/asm/pgtable.h
>> @@ -1679,10 +1679,10 @@ extern void contpte_clear_full_ptes(struct mm_struct *mm, unsigned long addr,
>>   extern pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
>>   				unsigned long addr, pte_t *ptep,
>>   				unsigned int nr, int full);
>> -extern int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
>> -				unsigned long addr, pte_t *ptep);
>> -extern int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
>> -				unsigned long addr, pte_t *ptep);
>> +extern int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
>> +				unsigned long addr, pte_t *ptep, unsigned int nr);
>> +extern int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
>> +				unsigned long addr, pte_t *ptep, unsigned int nr);
> 
> In core mm at least, as a convention, we strip 'extern' from header declarations
> as we go as they're not necessary.

Sure. I can remove the 'extern'.

> I wonder about this naming convention also. The contpte_xxx_() prefix
> obviously implies we are operating upon PTEs in the contiguous range, now
> we are doing something... different and 'nr' is a bit vague.
> 
> Is it the nr of contiguous ranges? Well in reality it's nr_pages right? But

Yes, 'nr' here means nr_pages, which follows the convention of the 
parameters in contpte_xxx_() functions.

> now we're not saying they're necessarily contiguous in the sense of contpte...
> 
> I wonder whether we'd be better off introducing a new function that
> explicitly has 'batch' or 'batched' in the name, and have the usual
> contpte_***() stuff and callers that need batching using a new underlying helper?

OK. I get your point. However, this is outside the scope of my patchset.

Perhaps we can clean up all the contpte_xxx_() functions if everyone 
agrees that this is confusing.

> Obviously I defer to Ryan on all this, just my thoughts...
> 
>>   extern void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
>>   				pte_t *ptep, unsigned int nr);
>>   extern int contpte_ptep_set_access_flags(struct vm_area_struct *vma,
>> @@ -1854,7 +1854,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
>>   	if (likely(!pte_valid_cont(orig_pte)))
>>   		return __ptep_test_and_clear_young(vma, addr, ptep);
>>
>> -	return contpte_ptep_test_and_clear_young(vma, addr, ptep);
>> +	return contpte_test_and_clear_young_ptes(vma, addr, ptep, CONT_PTES);
>>   }
>>
>>   #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
>> @@ -1866,7 +1866,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
>>   	if (likely(!pte_valid_cont(orig_pte)))
>>   		return __ptep_clear_flush_young(vma, addr, ptep);
>>
>> -	return contpte_ptep_clear_flush_young(vma, addr, ptep);
>> +	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
>>   }
>>
>>   #define wrprotect_ptes wrprotect_ptes
>> diff --git a/arch/arm64/mm/contpte.c b/arch/arm64/mm/contpte.c
>> index c0557945939c..19b122441be3 100644
>> --- a/arch/arm64/mm/contpte.c
>> +++ b/arch/arm64/mm/contpte.c
>> @@ -488,8 +488,9 @@ pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
>>   }
>>   EXPORT_SYMBOL_GPL(contpte_get_and_clear_full_ptes);
>>
>> -int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
>> -					unsigned long addr, pte_t *ptep)
>> +int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
>> +					unsigned long addr, pte_t *ptep,
>> +					unsigned int nr)
>>   {
>>   	/*
>>   	 * ptep_clear_flush_young() technically requires us to clear the access
>> @@ -500,39 +501,56 @@ int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
>>   	 * having to unfold.
>>   	 */
> 
> Hmm shouldn't you need to update this comment now 'nr' is a thing? E.g.:
> 
> "And since we only create a contig range when the range is covered by a single
> folio, we can get away with clearing young for the whole contig range here, so
> we avoid having to unfold."

I think the original comments are still clear:
"
/*
  * ptep_clear_flush_young() technically requires us to clear the access
  * flag for a _single_ pte. However, the core-mm code actually tracks
  * access/dirty per folio, not per page. And since we only create a
  * contig range when the range is covered by a single folio, we can get
  * away with clearing young for the whole contig range here, so we avoid
  * having to unfold.
  */
"

> However now you're allowing for large folios that are not contpte?
> 
> Overall feeling pretty iffy about implementing this this way.

Please see the above comments, which explain why we should do that.

>> +	unsigned long start = addr;
>> +	unsigned long end = start + nr * PAGE_SIZE;
> 
> So now [addr, addr + nr * PAGE_SIZE) must for sure be within a single PTE
> table?

Caller has made sure that (see folio_referenced_one()).

>>   	int young = 0;
>>   	int i;
>>
>> -	ptep = contpte_align_down(ptep);
>> -	addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
>> +	if (pte_cont(__ptep_get(ptep + nr - 1)))
>> +		end = ALIGN(end, CONT_PTE_SIZE);
> 
> OK so I guess for PTE_CONT to be set, it must be aligned to CONT_PTE_SIZE,
> with other PTE entries present there not having PTE_CONT set (Ryan - do
> correct me if I'm wrong!)
> 
> I guess then no worry about running off the end of the PTE table here.
> 
> I wonder about using pte_cont_addr_end() here, but I guess you are not
> intending to limit to a range here but rather capture the entire contpte
> range of the end.

Right.

> I don't love that now a function prefixed with contpte_... can have a
> condition where part of the input range is _not_ a contpte entry, or is
> specified partially...

Like I said above, this is outside the scope of my patchset. If Ryan 
also thinks we need to do some cleanups for all the contpte_xxx() 
functions in the contpte.c file, we can send a follow-up patchset to 
rename all the contpte_xxx() functions to make it clear.

>> -	for (i = 0; i < CONT_PTES; i++, ptep++, addr += PAGE_SIZE)
>> -		young |= __ptep_test_and_clear_young(vma, addr, ptep);
>> +	if (pte_cont(__ptep_get(ptep))) {
>> +		start = ALIGN_DOWN(start, CONT_PTE_SIZE);
>> +		ptep = contpte_align_down(ptep);
>> +	}
>> +
>> +	nr = (end - start) / PAGE_SIZE;
> 
> Hm don't love this reuse of input param.

OK. Will use another local variable instead.

> 
>> +	for (i = 0; i < nr; i++, ptep++, start += PAGE_SIZE)
>> +		young |= __ptep_test_and_clear_young(vma, start, ptep);
> 
> Again, overall find it a bit iffy that we are essentially overloading the
> code with non-contpte behaviour.

Let me clarify further: this is the handling logic of the contpte_xxx() 
functions in the contpte.c file. For example, the function 
contpte_set_ptes() has a parameter 'nr', which may be greater than 
CONT_PTES, meaning that it can handle multiple CONT_PTES range sizes of 
a large folio.

It might be a bit confusing, and I understand this is why you want to 
change the 'contpte_' prefix to the 'batch_' prefix. Of course, we can 
hope Ryan can provide some input on this.

Thanks for reviewing.


From baolin.wang at linux.alibaba.com  Mon Dec 15 19:47:00 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Tue, 16 Dec 2025 11:47:00 +0800
Subject: [PATCH v2 2/3] mm: rmap: support batched checks of the references
 for large folios
In-Reply-To: <4413d7f4-7734-4715-a450-2ba09db5ed22@lucifer.local>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <545dba5e899634bc6c8ca782417d16fef3bd049f.1765439381.git.baolin.wang@linux.alibaba.com>
 <4413d7f4-7734-4715-a450-2ba09db5ed22@lucifer.local>
Message-ID: <7391d74f-782c-4d5a-9f9d-02afcefdbf87@linux.alibaba.com>



On 2025/12/15 20:22, Lorenzo Stoakes wrote:
> On Thu, Dec 11, 2025 at 04:16:55PM +0800, Baolin Wang wrote:
>> Currently, folio_referenced_one() always checks the young flag for each PTE
>> sequentially, which is inefficient for large folios. This inefficiency is
>> especially noticeable when reclaiming clean file-backed large folios, where
>> folio_referenced() is observed as a significant performance hotspot.
>>
>> Moreover, on Arm architecture, which supports contiguous PTEs, there is already
> 
> arm64 you mean :)

Right. Will make it clear.

>> an optimization to clear the young flags for PTEs within a contiguous range.
>> However, this is not sufficient. We can extend this to perform batched operations
>> for the entire large folio (which might exceed the contiguous range: CONT_PTE_SIZE).
>>
>> Introduce a new API: clear_flush_young_ptes() to facilitate batched checking
>> of the young flags and flushing TLB entries, thereby improving performance
>> during large folio reclamation.
>>
>> Performance testing:
>> Allocate 10G clean file-backed folios by mmap() in a memory cgroup, and try to
>> reclaim 8G file-backed folios via the memory.reclaim interface. I can observe
>> 33% performance improvement on my Arm64 32-core server (and 10%+ improvement
>> on my X86 machine). Meanwhile, the hotspot folio_check_references() dropped
>> from approximately 35% to around 5%.
>>
>> W/o patchset:
>> real	0m1.518s
>> user	0m0.000s
>> sys	0m1.518s
>>
>> W/ patchset:
>> real	0m1.018s
>> user	0m0.000s
>> sys	0m1.018s
> 
> That's nice!
> 
> Have you performed the same kind of performance testing on non-arm64? As in the
> past we've had a batch optimisation go horribly wrong on non-arm64 even if it
> was ok on arm64 :)

Yes, seems you missed my test results for the x86 machine in the commit 
message :)

"I can observe 33% performance improvement on my Arm64 32-core server 
(and 10%+ improvement on my X86 machine)."

>> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
>> ---
>>   arch/arm64/include/asm/pgtable.h | 11 +++++++++++
>>   include/linux/mmu_notifier.h     |  9 +++++----
>>   include/linux/pgtable.h          | 19 +++++++++++++++++++
>>   mm/rmap.c                        | 22 ++++++++++++++++++++--
>>   4 files changed, 55 insertions(+), 6 deletions(-)
>>
>> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
>> index e03034683156..a865bd8c46a3 100644
>> --- a/arch/arm64/include/asm/pgtable.h
>> +++ b/arch/arm64/include/asm/pgtable.h
>> @@ -1869,6 +1869,17 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
>>   	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
>>   }
>>
>> +#define clear_flush_young_ptes clear_flush_young_ptes
>> +static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
>> +					unsigned long addr, pte_t *ptep,
>> +					unsigned int nr)
>> +{
>> +	if (likely(nr == 1))
>> +		return __ptep_clear_flush_young(vma, addr, ptep);
>> +
>> +	return contpte_clear_flush_young_ptes(vma, addr, ptep, nr);
>> +}
> 
> Hmm again this is a weird way of exposing a contepte-specific function, you
> really need to rework that as discussed in patch 1/3.
> 
> It seems to me we can share code to avoid this.

Sorry I don't think so. This is the current way of exposing a contpte 
for Arm64. Please take a look at set_ptes(), clear_full_ptes(), 
wrprotect_ptes() and so on (in this file).

>>   #define wrprotect_ptes wrprotect_ptes
>>   static __always_inline void wrprotect_ptes(struct mm_struct *mm,
>>   				unsigned long addr, pte_t *ptep, unsigned int nr)
>> diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h
>> index d1094c2d5fb6..be594b274729 100644
>> --- a/include/linux/mmu_notifier.h
>> +++ b/include/linux/mmu_notifier.h
>> @@ -515,16 +515,17 @@ static inline void mmu_notifier_range_init_owner(
>>   	range->owner = owner;
>>   }
>>
>> -#define ptep_clear_flush_young_notify(__vma, __address, __ptep)		\
>> +#define ptep_clear_flush_young_notify(__vma, __address, __ptep, __nr)	\
>>   ({									\
>>   	int __young;							\
>>   	struct vm_area_struct *___vma = __vma;				\
>>   	unsigned long ___address = __address;				\
>> -	__young = ptep_clear_flush_young(___vma, ___address, __ptep);	\
>> +	unsigned int ___nr = __nr;					\
>> +	__young = clear_flush_young_ptes(___vma, ___address, __ptep, ___nr);	\
>>   	__young |= mmu_notifier_clear_flush_young(___vma->vm_mm,	\
>>   						  ___address,		\
>>   						  ___address +		\
>> -							PAGE_SIZE);	\
>> +						nr * PAGE_SIZE);	\
>>   	__young;							\
>>   })
> 
> An aside, but I wonder why this needs to be a (pretty disgusting) macro?

Um, I can send a follow-up to clean up all these related macros.

>> @@ -650,7 +651,7 @@ static inline void mmu_notifier_subscriptions_destroy(struct mm_struct *mm)
>>
>>   #define mmu_notifier_range_update_to_read_only(r) false
>>
>> -#define ptep_clear_flush_young_notify ptep_clear_flush_young
>> +#define ptep_clear_flush_young_notify clear_flush_young_ptes
>>   #define pmdp_clear_flush_young_notify pmdp_clear_flush_young
>>   #define ptep_clear_young_notify ptep_test_and_clear_young
>>   #define pmdp_clear_young_notify pmdp_test_and_clear_young
>> diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
>> index b13b6f42be3c..c7d0fd228cb7 100644
>> --- a/include/linux/pgtable.h
>> +++ b/include/linux/pgtable.h
>> @@ -947,6 +947,25 @@ static inline void wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
>>   }
>>   #endif
>>
>> +#ifndef clear_flush_young_ptes
>> +static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
>> +					 unsigned long addr, pte_t *ptep,
>> +					 unsigned int nr)
>> +{
>> +	int young = 0;
>> +
>> +	for (;;) {
>> +		young |= ptep_clear_flush_young(vma, addr, ptep);
>> +		if (--nr == 0)
>> +			break;
>> +		ptep++;
>> +		addr += PAGE_SIZE;
>> +	}
>> +
>> +	return young;
>> +}
>> +#endif
>> +
>>   /*
>>    * On some architectures hardware does not set page access bit when accessing
>>    * memory page, it is responsibility of software setting this bit. It brings
>> diff --git a/mm/rmap.c b/mm/rmap.c
>> index d6799afe1114..ec232165c47d 100644
>> --- a/mm/rmap.c
>> +++ b/mm/rmap.c
>> @@ -827,9 +827,11 @@ static bool folio_referenced_one(struct folio *folio,
>>   	struct folio_referenced_arg *pra = arg;
>>   	DEFINE_FOLIO_VMA_WALK(pvmw, folio, vma, address, 0);
>>   	int ptes = 0, referenced = 0;
>> +	unsigned int nr;
>>
>>   	while (page_vma_mapped_walk(&pvmw)) {
>>   		address = pvmw.address;
>> +		nr = 1;
>>
>>   		if (vma->vm_flags & VM_LOCKED) {
>>   			ptes++;
>> @@ -874,9 +876,21 @@ static bool folio_referenced_one(struct folio *folio,
>>   			if (lru_gen_look_around(&pvmw))
>>   				referenced++;
>>   		} else if (pvmw.pte) {
>> +			if (folio_test_large(folio)) {
>> +				unsigned long end_addr = pmd_addr_end(address, vma->vm_end);
>> +				unsigned int max_nr = (end_addr - address) >> PAGE_SHIFT;
>> +				pte_t pteval = ptep_get(pvmw.pte);
>> +
>> +				nr = folio_pte_batch(folio, pvmw.pte, pteval, max_nr);
> 
> I do wish we could put this fiddly logic into a helper for each place in
> which we do similar kind 'end of the PTE table, maximum number we could
> have' logic.

Um, the logic is already simple, and I don?t think adding a new helper 
would improve readability. If some code can reuse this logic, we can 
factor it out into a helper at that point.

>> +			}
> 
> NIT but we're running into pretty long lines here.

OK. Will fix this.

>> +
>> +			ptes += nr;
>>   			if (ptep_clear_flush_young_notify(vma, address,
>> -						pvmw.pte))
>> +						pvmw.pte, nr))
>>   				referenced++;
> 
> I find this referenced logic weird, it seems like it should be a boolean,
> but this is outside the scope of your patch here :)

Right. Thanks for reviewing.


From nichen at iscas.ac.cn  Mon Dec 15 20:32:10 2025
From: nichen at iscas.ac.cn (Chen Ni)
Date: Tue, 16 Dec 2025 12:32:10 +0800
Subject: [PATCH] spi: stm32-ospi: Remove unneeded semicolon
Message-ID: <20251216043210.1521722-1-nichen@iscas.ac.cn>

Remove unnecessary semicolons reported by Coccinelle/coccicheck and the
semantic patch at scripts/coccinelle/misc/semicolon.cocci.

Signed-off-by: Chen Ni <nichen at iscas.ac.cn>
---
 drivers/spi/spi-stm32-ospi.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/spi/spi-stm32-ospi.c b/drivers/spi/spi-stm32-ospi.c
index c36df8d3f5cb..f396439e2281 100644
--- a/drivers/spi/spi-stm32-ospi.c
+++ b/drivers/spi/spi-stm32-ospi.c
@@ -150,7 +150,7 @@ static void stm32_ospi_read_fifo(void *val, void __iomem *addr, u8 len)
 		break;
 	case sizeof(u8):
 		*((u8 *)val) = readb_relaxed(addr);
-	};
+	}
 }
 
 static void stm32_ospi_write_fifo(void *val, void __iomem *addr, u8 len)
@@ -164,7 +164,7 @@ static void stm32_ospi_write_fifo(void *val, void __iomem *addr, u8 len)
 		break;
 	case sizeof(u8):
 		writeb_relaxed(*((u8 *)val), addr);
-	};
+	}
 }
 
 static int stm32_ospi_abort(struct stm32_ospi *ospi)
-- 
2.25.1



From ritesh.list at gmail.com  Mon Dec 15 21:14:45 2025
From: ritesh.list at gmail.com (Ritesh Harjani (IBM))
Date: Tue, 16 Dec 2025 10:44:45 +0530
Subject: [PATCH v6 03/14] powerpc/mm: implement arch_flush_lazy_mmu_mode()
In-Reply-To: <20251215150323.2218608-4-kevin.brodsky@arm.com>
References: <20251215150323.2218608-1-kevin.brodsky@arm.com> <20251215150323.2218608-4-kevin.brodsky@arm.com>
Message-ID: <87345b6m9m.ritesh.list@gmail.com>

Kevin Brodsky <kevin.brodsky at arm.com> writes:

> Upcoming changes to the lazy_mmu API will cause
> arch_flush_lazy_mmu_mode() to be called when leaving a nested
> lazy_mmu section.
>
> Move the relevant logic from arch_leave_lazy_mmu_mode() to
> arch_flush_lazy_mmu_mode() and have the former call the latter. The
> radix_enabled() check is required in both as
> arch_flush_lazy_mmu_mode() will be called directly from the generic
> layer in a subsequent patch.
>
> Note: the additional this_cpu_ptr() and radix_enabled() calls on the
> arch_leave_lazy_mmu_mode() path will be removed in a subsequent
> patch.
>
> Acked-by: David Hildenbrand <david at redhat.com>
> Tested-by: Venkat Rao Bagalkote <venkat88 at linux.ibm.com>
> Signed-off-by: Kevin Brodsky <kevin.brodsky at arm.com>
> ---
>  .../powerpc/include/asm/book3s/64/tlbflush-hash.h | 15 ++++++++++++---
>  1 file changed, 12 insertions(+), 3 deletions(-)

Sorry I was away for a while. 

Thanks for taking care of the radix path as we had discussed previously
here [1]. 

[1]: https://lore.kernel.org/all/87jz044xn4.ritesh.list at gmail.com/

The change looks good to me. So, please feel free to add:

Reviewed-by: Ritesh Harjani (IBM) <ritesh.list at gmail.com>


From baolin.wang at linux.alibaba.com  Mon Dec 15 21:48:52 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Tue, 16 Dec 2025 13:48:52 +0800
Subject: [PATCH v2 3/3] mm: rmap: support batched unmapping for file large
 folios
In-Reply-To: <70d1dedc-b4fc-4eb6-baf6-9e54b6a62249@lucifer.local>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <af330c9ea188bd0f28189b1e6e5803f6de9d2abe.1765439381.git.baolin.wang@linux.alibaba.com>
 <70d1dedc-b4fc-4eb6-baf6-9e54b6a62249@lucifer.local>
Message-ID: <eb871ca2-47c8-4b10-a61d-321716f6c147@linux.alibaba.com>



On 2025/12/15 20:38, Lorenzo Stoakes wrote:
> On Thu, Dec 11, 2025 at 04:16:56PM +0800, Baolin Wang wrote:
>> Similar to folio_referenced_one(), we can apply batched unmapping for file
>> large folios to optimize the performance of file folios reclamation.
>>
>> Performance testing:
>> Allocate 10G clean file-backed folios by mmap() in a memory cgroup, and try to
>> reclaim 8G file-backed folios via the memory.reclaim interface. I can observe
>> 75% performance improvement on my Arm64 32-core server.
> 
> Again, you must test on non-arm64 architectures and report the numbers for this
> also.

Yes, I've tested on the x86 machine, and will add the data in the commit 
message.

>> W/o patch:
>> real    0m1.018s
>> user    0m0.000s
>> sys     0m1.018s
>>
>> W/ patch:
>> real	0m0.249s
>> user	0m0.000s
>> sys	0m0.249s
>>
>> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
>> ---
>>   mm/rmap.c | 7 ++++---
>>   1 file changed, 4 insertions(+), 3 deletions(-)
>>
>> diff --git a/mm/rmap.c b/mm/rmap.c
>> index ec232165c47d..4c9d5777c8da 100644
>> --- a/mm/rmap.c
>> +++ b/mm/rmap.c
>> @@ -1855,9 +1855,10 @@ static inline unsigned int folio_unmap_pte_batch(struct folio *folio,
>>   	end_addr = pmd_addr_end(addr, vma->vm_end);
>>   	max_nr = (end_addr - addr) >> PAGE_SHIFT;
>>
>> -	/* We only support lazyfree batching for now ... */
>> -	if (!folio_test_anon(folio) || folio_test_swapbacked(folio))
>> +	/* We only support lazyfree or file folios batching for now ... */
>> +	if (folio_test_anon(folio) && folio_test_swapbacked(folio))
> 
> Why is it now ok to support file-backed batched unmapping when it wasn't in
> Barry's series (see [0])? You don't seem to be justifying this?

Barry's series[0] is merely aimed at optimizing lazyfree anonymous large 
folios and does not continue to optimize anonymous large folios or 
file-backed large folios at that point.

Subsequently, Barry sent out a new patch (see [1]) to optimize anonymous 
large folios. As for file-backed large folios, the batched unmapping 
support is relatively simple, since we only need to clear the PTE 
entries for file-backed large folios.

> [0]:https://lore.kernel.org/all/20250214093015.51024-4-21cnbao at gmail.com/T/#u

[1] https://lore.kernel.org/all/20250513084620.58231-1-21cnbao at gmail.com/

>>   		return 1;
>> +
>>   	if (pte_unused(pte))
>>   		return 1;
>>
>> @@ -2223,7 +2224,7 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
>>   			 *
>>   			 * See Documentation/mm/mmu_notifier.rst
>>   			 */
>> -			dec_mm_counter(mm, mm_counter_file(folio));
>> +			add_mm_counter(mm, mm_counter_file(folio), -nr_pages);
> 
> Was this just a bug before?

Nope. Before this patch, we never supported batched unmapping for 
file-backed large folios, so the 'nr_pages' was always 1. After this 
patch, we should use the number of pages in this file-backed large folio.


From hayashi.kunihiko at socionext.com  Mon Dec 15 21:59:03 2025
From: hayashi.kunihiko at socionext.com (Kunihiko Hayashi)
Date: Tue, 16 Dec 2025 14:59:03 +0900
Subject: [PATCH] dt-bindings: PCI: socionext,uniphier-pcie: Fix interrupt
 controller node name
In-Reply-To: <CAL_JsqJKpQRMEac4e1T-s+6HWbR9mOZXRQCHVeTCnHqJYa=TYg@mail.gmail.com>
References: <20251215212456.3317558-1-robh@kernel.org>
 <3f1b7852-1494-4a73-8783-b578f9ad5d40@socionext.com>
 <CAL_JsqJKpQRMEac4e1T-s+6HWbR9mOZXRQCHVeTCnHqJYa=TYg@mail.gmail.com>
Message-ID: <668f273b-5214-4f2d-b532-265e4fc6aaef@socionext.com>

On 2025/12/16 11:18, Rob Herring wrote:
> On Mon, Dec 15, 2025 at 7:21?PM Kunihiko Hayashi
> <hayashi.kunihiko at socionext.com> wrote:
>>
>> Hi Rob,
>>
>> Thank you for pointing out.
>>
>> On 2025/12/16 6:24, Rob Herring (Arm) wrote:
>>> The child node name in use by .dts files and the driver is
>>> "legacy-interrupt-controller", not "interrupt-controller".
>> After your change commit bcd7ec2cd720 were merged, it was a long time
>> before I realized I needed to fix it.
>>
>> "interrupt-controller" is included in the list of Generic Names
>> Recommendation. Would it be better to apply (i.e. restore) this,
>> or fix the PCI driver and .dts?
> 
> It's an ABI. So we are stuck with it or have to support both names in
> the driver forever (and backport the driver change).

I understand.
If allowing "interrupt-controller", should allow both names in the
driver and bindings.

At this time, it's preferable to align the bindings definition to
remove mismatch warnings.

Reviewed-by: Kunihiko Hayashi <hayashi.kunihiko at socionext.com>

Thank you,

---
Best Regards
Kunihiko Hayashi


From krzk at kernel.org  Mon Dec 15 22:01:49 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 16 Dec 2025 07:01:49 +0100
Subject: [PATCH v2 01/20] dt-bindings: display: tilcdc: Convert to DT
 schema
In-Reply-To: <20251211-feature_tilcdc-v2-1-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
 <20251211-feature_tilcdc-v2-1-f48bac3cd33e@bootlin.com>
Message-ID: <20251216-capable-eccentric-nightingale-b09037@quoll>

On Thu, Dec 11, 2025 at 05:38:45PM +0100, Kory Maincent (TI.com) wrote:
> diff --git a/Documentation/devicetree/bindings/display/tilcdc/tilcdc.yaml b/Documentation/devicetree/bindings/display/tilcdc/tilcdc.yaml
> new file mode 100644
> index 0000000000000..34ac1fd04d5c6
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/tilcdc/tilcdc.yaml

Filename based on compatible, so for example ti,am33xx-tilcdc.yaml or
worse case ti,tilcdc.yaml (see writing bindings and writing schema docs)


> @@ -0,0 +1,96 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/tilcdc/tilcdc.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: TI LCD Controller, found on AM335x, DA850, AM18x and OMAP-L138
> +
> +maintainers:
> +  - Kory Maincent <kory.maincent at bootlin.com>
> +
> +properties:
> +  compatible:
> +    enum:
> +      - ti,am33xx-tilcdc
> +      - ti,da850-tilcdc
> +
> +  reg:
> +    maxItems: 1
> +
> +  interrupts:
> +    maxItems: 1
> +
> +  port:
> +    $ref: /schemas/graph.yaml#/properties/port
> +
> +  ti,hwmods:
> +    $ref: /schemas/types.yaml#/definitions/string
> +    description:
> +      Name of the hwmod associated to the LCDC
> +
> +  max-bandwidth:

constraints? Is '1' valid? Is INT_MAX valid as well?

> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    description:
> +      The maximum pixels per second that the memory interface / lcd
> +      controller combination can sustain
> +
> +  max-width:
> +    $ref: /schemas/types.yaml#/definitions/uint32

constraints?

> +    description:
> +      The maximum horizontal pixel width supported by the lcd controller.
> +
> +  max-pixelclock:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    description:
> +      The maximum pixel clock that can be supported by the lcd controller
> +      in KHz.
> +
> +  blue-and-red-wiring:
> +    enum: [straight, crossed]
> +    description:
> +      This property deals with the LCDC revision 2 (found on AM335x)
> +      color errata [1].
> +       - "straight" indicates normal wiring that supports RGB565,
> +         BGR888, and XBGR8888 color formats.
> +       - "crossed" indicates wiring that has blue and red wires
> +         crossed. This setup supports BGR565, RGB888 and XRGB8888
> +         formats.
> +       - If the property is not present or its value is not recognized
> +         the legacy mode is assumed. This configuration supports RGB565,
> +         RGB888 and XRGB8888 formats. However, depending on wiring, the red
> +         and blue colors are swapped in either 16 or 24-bit color modes.
> +
> +       [1] There is an errata about AM335x color wiring. For 16-bit color
> +       mode the wires work as they should (LCD_DATA[0:4] is for Blue[3:7]),
> +       but for 24 bit color modes the wiring of blue and red components is
> +       crossed and LCD_DATA[0:4] is for Red[3:7] and LCD_DATA[11:15] is
> +       for Blue[3-7]. For more details see section 3.1.1 in AM335x
> +       Silicon Errata
> +       https://www.ti.com/general/docs/lit/getliterature.tsp?baseLiteratureNumber=sprz360
> +
> +required:
> +  - compatible
> +  - interrupts
> +  - reg
> +  - port
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    tilcdc: tilcdc at 4830e000 {

Drop unused label. Generic node name, e.g. "display-controller" or
"lcd-controller".


Best regards,
Krzysztof



From krzk at kernel.org  Mon Dec 15 22:02:07 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 16 Dec 2025 07:02:07 +0100
Subject: [PATCH v2 02/20] dt-bindings: display: tilcdc: Mark panel
 binding as deprecated
In-Reply-To: <20251211-feature_tilcdc-v2-2-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
 <20251211-feature_tilcdc-v2-2-f48bac3cd33e@bootlin.com>
Message-ID: <20251216-outrageous-dark-bloodhound-0dccfc@quoll>

On Thu, Dec 11, 2025 at 05:38:46PM +0100, Kory Maincent (TI.com) wrote:
> Mark the ti,tilcdc,panel binding as deprecated in the documentation.
> This legacy binding should no longer be used for new designs. Users
> should migrate to the standard DRM panel bindings instead.
> 
> Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof



From krzk at kernel.org  Mon Dec 15 22:02:55 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 16 Dec 2025 07:02:55 +0100
Subject: [PATCH v2 1/2] dt-bindings: arm: imx Add FRDM-IMX91 board
In-Reply-To: <20251212-imx91_frdm-v2-1-4dd6d289e81d@nxp.com>
References: <20251212-imx91_frdm-v2-0-4dd6d289e81d@nxp.com>
 <20251212-imx91_frdm-v2-1-4dd6d289e81d@nxp.com>
Message-ID: <20251216-energetic-bittern-of-diversity-b2e851@quoll>

On Fri, Dec 12, 2025 at 11:31:33AM +0900, Joseph Guo wrote:
> Add the board FRDM-IMX91 in the binding document.
> 
> Signed-off-by: Joseph Guo <qijian.guo at nxp.com>
> ---
> Change in v2:
> - rename 'frdm-imx91' to 'imx91-11x11-frdm'
> ---
>  Documentation/devicetree/bindings/arm/fsl.yaml | 1 +
>  1 file changed, 1 insertion(+)

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof



From dmitry.torokhov at gmail.com  Mon Dec 15 22:10:54 2025
From: dmitry.torokhov at gmail.com (Dmitry Torokhov)
Date: Mon, 15 Dec 2025 22:10:54 -0800
Subject: [PATCH 1/4] Input: stmfts - correct wording for the warning
 message
In-Reply-To: <20251215-fts-fixes-v1-1-8c1e3a63ebf1@ixit.cz>
References: <20251215-fts-fixes-v1-0-8c1e3a63ebf1@ixit.cz>
 <20251215-fts-fixes-v1-1-8c1e3a63ebf1@ixit.cz>
Message-ID: <n2fcsz4gl7lyniy2qxdddvrisguc4ssln4buky4g37rjnwxxo6@4lyarw5ngtqs>

On Mon, Dec 15, 2025 at 03:30:01PM +0100, David Heidelberg via B4 Relay wrote:
> From: David Heidelberg <david at ixit.cz>
> 
> We're trying to enable regulator, not disable it.
> 
> Fixes: 78bcac7b2ae1 ("Input: add support for the STMicroelectronics FingerTip touchscreen")
> Suggested-by: Petr Hodina <petr.hodina at protonmail.com>
> Signed-off-by: David Heidelberg <david at ixit.cz>

Applied, thank you.

-- 
Dmitry


From dmitry.torokhov at gmail.com  Mon Dec 15 22:11:07 2025
From: dmitry.torokhov at gmail.com (Dmitry Torokhov)
Date: Mon, 15 Dec 2025 22:11:07 -0800
Subject: [PATCH 2/4] Input: stmfts - Make comments correct
In-Reply-To: <20251215-fts-fixes-v1-2-8c1e3a63ebf1@ixit.cz>
References: <20251215-fts-fixes-v1-0-8c1e3a63ebf1@ixit.cz>
 <20251215-fts-fixes-v1-2-8c1e3a63ebf1@ixit.cz>
Message-ID: <yc65vlbqkok72lnidezzrivfvz6sdserm7jazmu4uwivbqufpa@we6qlhaufwlt>

On Mon, Dec 15, 2025 at 03:30:02PM +0100, David Heidelberg via B4 Relay wrote:
> From: Petr Hodina <petr.hodina at protonmail.com>
> 
> No functional change.
> 
> Fixes: 78bcac7b2ae1 ("Input: add support for the STMicroelectronics FingerTip touchscreen")
> Signed-off-by: Petr Hodina <petr.hodina at protonmail.com>
> Signed-off-by: David Heidelberg <david at ixit.cz>

Applied, thank you.

-- 
Dmitry


From dmitry.torokhov at gmail.com  Mon Dec 15 22:11:37 2025
From: dmitry.torokhov at gmail.com (Dmitry Torokhov)
Date: Mon, 15 Dec 2025 22:11:37 -0800
Subject: [PATCH 3/4] Input: stmfts - use sysfs_emit() instead of sprintf()
In-Reply-To: <20251215-fts-fixes-v1-3-8c1e3a63ebf1@ixit.cz>
References: <20251215-fts-fixes-v1-0-8c1e3a63ebf1@ixit.cz>
 <20251215-fts-fixes-v1-3-8c1e3a63ebf1@ixit.cz>
Message-ID: <gjnxidvenisbv4lib4jhngybjqcux2umn2iunnaqvjct764njg@qf2k7mcvebml>

On Mon, Dec 15, 2025 at 03:30:03PM +0100, David Heidelberg via B4 Relay wrote:
> From: Petr Hodina <petr.hodina at protonmail.com>
> 
> Follow the advice in Documentation/filesystems/sysfs.rst:
> show() should only use sysfs_emit() or sysfs_emit_at() when formatting
> the value to be returned to user space.
> 
> Signed-off-by: Petr Hodina <petr.hodina at protonmail.com>
> Signed-off-by: David Heidelberg <david at ixit.cz>

Applied, thank you.

-- 
Dmitry


From dmitry.torokhov at gmail.com  Mon Dec 15 22:13:11 2025
From: dmitry.torokhov at gmail.com (Dmitry Torokhov)
Date: Mon, 15 Dec 2025 22:13:11 -0800
Subject: [PATCH 4/4] Input: stmfts - use client to make future code
 cleaner
In-Reply-To: <20251215-fts-fixes-v1-4-8c1e3a63ebf1@ixit.cz>
References: <20251215-fts-fixes-v1-0-8c1e3a63ebf1@ixit.cz>
 <20251215-fts-fixes-v1-4-8c1e3a63ebf1@ixit.cz>
Message-ID: <hpmm5fhs74swrhkneaif4s5dquqeclujdlua7ygmkvcmtf6n4t@rsahxu23xwfp>

Hi David,

On Mon, Dec 15, 2025 at 03:30:04PM +0100, David Heidelberg via B4 Relay wrote:
> From: Petr Hodina <petr.hodina at protonmail.com>
> 
> Make code cleaner, compiler will optimize it away anyway.
> 
> Preparation for FTM5 support, where more steps are needed.
> 
> Signed-off-by: Petr Hodina <petr.hodina at protonmail.com>
> Signed-off-by: David Heidelberg <david at ixit.cz>
> ---
>  drivers/input/touchscreen/stmfts.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
> index 4b166b0a9a5a6..06845a00348cc 100644
> --- a/drivers/input/touchscreen/stmfts.c
> +++ b/drivers/input/touchscreen/stmfts.c
> @@ -747,9 +747,10 @@ static int stmfts_runtime_suspend(struct device *dev)
>  static int stmfts_runtime_resume(struct device *dev)
>  {
>  	struct stmfts_data *sdata = dev_get_drvdata(dev);
> +	struct i2c_client *client = sdata->client;
>  	int ret;
>  
> -	ret = i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_OUT);
> +	ret = i2c_smbus_write_byte(client, STMFTS_SLEEP_OUT);

Sorry but I do not see how using a temporary cleans things up compared
to a simple structure member access, given that it happens only once
here.

>  	if (ret)
>  		dev_err(dev, "failed to resume device: %d\n", ret);
>  
> 

Thanks.

-- 
Dmitry


From 21cnbao at gmail.com  Mon Dec 15 22:13:12 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Tue, 16 Dec 2025 14:13:12 +0800
Subject: [PATCH v2 3/3] mm: rmap: support batched unmapping for file large folios
In-Reply-To: <eb871ca2-47c8-4b10-a61d-321716f6c147@linux.alibaba.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <af330c9ea188bd0f28189b1e6e5803f6de9d2abe.1765439381.git.baolin.wang@linux.alibaba.com>
 <70d1dedc-b4fc-4eb6-baf6-9e54b6a62249@lucifer.local> <eb871ca2-47c8-4b10-a61d-321716f6c147@linux.alibaba.com>
Message-ID: <CAGsJ_4xp40A3u=N5_mw00Eo6bPmFvctD3j=1Qmy3vOo2EmX3hA@mail.gmail.com>

> >>
> >> diff --git a/mm/rmap.c b/mm/rmap.c
> >> index ec232165c47d..4c9d5777c8da 100644
> >> --- a/mm/rmap.c
> >> +++ b/mm/rmap.c
> >> @@ -1855,9 +1855,10 @@ static inline unsigned int folio_unmap_pte_batch(struct folio *folio,
> >>      end_addr = pmd_addr_end(addr, vma->vm_end);
> >>      max_nr = (end_addr - addr) >> PAGE_SHIFT;
> >>
> >> -    /* We only support lazyfree batching for now ... */
> >> -    if (!folio_test_anon(folio) || folio_test_swapbacked(folio))
> >> +    /* We only support lazyfree or file folios batching for now ... */
> >> +    if (folio_test_anon(folio) && folio_test_swapbacked(folio))
> >
> > Why is it now ok to support file-backed batched unmapping when it wasn't in
> > Barry's series (see [0])? You don't seem to be justifying this?
>
> Barry's series[0] is merely aimed at optimizing lazyfree anonymous large
> folios and does not continue to optimize anonymous large folios or
> file-backed large folios at that point.

Yep. At that time, I didn?t have an Android machine with a filesystem
that supported large folios, so I focused on lazyfree. But I
agree that lazyfree anon folios and file folios are quite
similar.

>
> Subsequently, Barry sent out a new patch (see [1]) to optimize anonymous
> large folios. As for file-backed large folios, the batched unmapping
> support is relatively simple, since we only need to clear the PTE
> entries for file-backed large folios.

Yep. It is actually quite straightforward to go from lazyfree
anon folios to file folios. Swap-backed anon folios are much
more tricky, though.

>
> > [0]:https://lore.kernel.org/all/20250214093015.51024-4-21cnbao at gmail.com/T/#u
>
> [1] https://lore.kernel.org/all/20250513084620.58231-1-21cnbao at gmail.com/

Thanks
Barry


From baolin.wang at linux.alibaba.com  Mon Dec 15 22:22:11 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Tue, 16 Dec 2025 14:22:11 +0800
Subject: [PATCH v2 3/3] mm: rmap: support batched unmapping for file large
 folios
In-Reply-To: <CAGsJ_4xp40A3u=N5_mw00Eo6bPmFvctD3j=1Qmy3vOo2EmX3hA@mail.gmail.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <af330c9ea188bd0f28189b1e6e5803f6de9d2abe.1765439381.git.baolin.wang@linux.alibaba.com>
 <70d1dedc-b4fc-4eb6-baf6-9e54b6a62249@lucifer.local>
 <eb871ca2-47c8-4b10-a61d-321716f6c147@linux.alibaba.com>
 <CAGsJ_4xp40A3u=N5_mw00Eo6bPmFvctD3j=1Qmy3vOo2EmX3hA@mail.gmail.com>
Message-ID: <9e038290-70ff-458d-b46d-bc512c3442be@linux.alibaba.com>



On 2025/12/16 14:13, Barry Song wrote:
>>>>
>>>> diff --git a/mm/rmap.c b/mm/rmap.c
>>>> index ec232165c47d..4c9d5777c8da 100644
>>>> --- a/mm/rmap.c
>>>> +++ b/mm/rmap.c
>>>> @@ -1855,9 +1855,10 @@ static inline unsigned int folio_unmap_pte_batch(struct folio *folio,
>>>>       end_addr = pmd_addr_end(addr, vma->vm_end);
>>>>       max_nr = (end_addr - addr) >> PAGE_SHIFT;
>>>>
>>>> -    /* We only support lazyfree batching for now ... */
>>>> -    if (!folio_test_anon(folio) || folio_test_swapbacked(folio))
>>>> +    /* We only support lazyfree or file folios batching for now ... */
>>>> +    if (folio_test_anon(folio) && folio_test_swapbacked(folio))
>>>
>>> Why is it now ok to support file-backed batched unmapping when it wasn't in
>>> Barry's series (see [0])? You don't seem to be justifying this?
>>
>> Barry's series[0] is merely aimed at optimizing lazyfree anonymous large
>> folios and does not continue to optimize anonymous large folios or
>> file-backed large folios at that point.
> 
> Yep. At that time, I didn?t have an Android machine with a filesystem
> that supported large folios, so I focused on lazyfree. But I
> agree that lazyfree anon folios and file folios are quite
> similar.
> 
>>
>> Subsequently, Barry sent out a new patch (see [1]) to optimize anonymous
>> large folios. As for file-backed large folios, the batched unmapping
>> support is relatively simple, since we only need to clear the PTE
>> entries for file-backed large folios.
> 
> Yep. It is actually quite straightforward to go from lazyfree
> anon folios to file folios. Swap-backed anon folios are much
> more tricky, though.

Agree. Thanks Barry for reviewing and confirming.


From quic_nihalkum at quicinc.com  Mon Dec 15 22:22:18 2025
From: quic_nihalkum at quicinc.com (Nihal Kumar Gupta)
Date: Tue, 16 Dec 2025 11:52:18 +0530
Subject: [PATCH v7 0/5] Add CCI and imx577 sensor support for monaco evk
Message-ID: <20251216062223.2474216-1-quic_nihalkum@quicinc.com>

From: nihalkum <nihalkum at qti.qualcomm.com>

Monaco EVK is a single-board computer based on the Qualcomm QCS8300 SoC.
It lacks a camera sensor in its default configuration.
This series adds CCI support and enables the IMX577 sensor via CSIPHY1
through device tree overlay.

We have tested IMX577 Sensor on CCI1 with following commands:
- media-ctl --reset
- media-ctl -V '"imx577 3-001a":0[fmt:SRGGB10/4056x3040 field:none]'
- media-ctl -V '"msm_csiphy1":0[fmt:SRGGB10/4056x3040]'
- media-ctl -V '"msm_csid0":0[fmt:SRGGB10/4056x3040]'
- media-ctl -V '"msm_vfe0_rdi0":0[fmt:SRGGB10/4056x3040]'
- media-ctl -l '"msm_csiphy1":1->"msm_csid0":0[1]'
- media-ctl -l '"msm_csid0":1->"msm_vfe0_rdi0":0[1]'
- yavta -B capture-mplane -c -I -n 5 -f SRGGB10P -s 4056x3040 -F /dev/video1
---

This patch series depends on patch series:
https://lore.kernel.org/all/20251107162521.511536-1-quic_vikramsa at quicinc.com

Bindings for Supplies are added by below patch:
https://lore.kernel.org/all/20251107162521.511536-1-quic_vikramsa at quicinc.com

Changes in v7:
- Define MCLK pinctrl definitions in monaco.dtsi - Konrad and Vladimir
- Define fixed regulators for camera AVDD rails in monaco-evk.dts - Konrad
- Link to v6:
  https://lore.kernel.org/all/20251126081057.4191122-1-quic_vikramsa at quicinc.com

Changes in v6:
- Fixed ordering of property-n and property-names in vreg_cam1_2p8 - Konrad 
- Moved vreg_cam1_2p8 defintion to monaco-evk.dts - Konrad
- Removed description of pins with MCLK and Regulators function - Konrad
- Added pin hardware description for MCLK, regulators in monaco.dtsi - Konrad
- Link to v5:
  https://lore.kernel.org/all/20251114064541.446276-1-quic_vikramsa at quicinc.com

Changes in v5:
- Rename cciX_i2cY_* to cciX_Y_* to shorten the labels - Vladimir 
- Added description of pins with MCLK function - Vladimir 
- Link to v4:
  https://lore.kernel.org/all/20251015131303.2797800-1-quic_vikramsa at quicinc.com

Changes in v4:
- Remove the AXI source clock from the CCI node - Konrad
- Updated the qcs8300-camss device tree binding.
- Link to v3:
  https://lore.kernel.org/all/20250917130647.1701883-1-quic_vikramsa at quicinc.com

Changes in v3:
- Updated and Wrapped commit messages for [PATCH v2 1/3] and [PATCH v2 2/3] - Rob
- Link to v2:
  https://lore.kernel.org/all/20250912141134.2799078-1-quic_vikramsa at quicinc.com

Changes in v2:
- Remove the patch that adds PHY supply documentation in the qcs8300 CAMSS. 
  bindings. This change should be submitted together with the qcs8300 bindings patch.
- Fix indentation and regulator node name - Krzysztof.
- Update commit message as suggested - Dmitry.
- Link to v1:
  https://lore.kernel.org/lkml/20250909114241.840842-1-quic_vikramsa at quicinc.com

Used following tools for the sanity check of these changes.
- make -j32 W=1
- checkpatch.pl
- make DT_CHECKER_FLAGS=-m W=1 DT_SCHEMA_FILES=i2c/qcom,i2c-cci.yaml dt_binding_check
- make CHECK_DTBS=y W=1 DT_SCHEMA_FILES=i2c/qcom,i2c-cci.yaml
- make DT_CHECKER_FLAGS=-m W=1 DT_SCHEMA_FILES=media/qcom,qcs8300-camss.yaml dt_binding_check
- make CHECK_DTBS=y W=1 DT_SCHEMA_FILES=media/qcom,qcs8300-camss.yaml

Signed-off-by: Nihal Kumar Gupta <quic_nihalkum at quicinc.com>
Signed-off-by: Vikram Sharma <quic_vikramsa at quicinc.com>

Nihal Kumar Gupta (5):
  dt-bindings: i2c: qcom-cci: Document qcs8300 compatible
  arm64: dts: qcom: monaco: Add CCI definitions
  arm64: dts: qcom: monaco: Add camera MCLK pinctrl
  arm64: dts: qcom: monaco-evk: Add camera AVDD regulators
  arm64: dts: qcom: monaco-evk-camera: Add DT overlay

 .../devicetree/bindings/i2c/qcom,i2c-cci.yaml |   2 +
 arch/arm64/boot/dts/qcom/Makefile             |   4 +
 .../dts/qcom/monaco-evk-camera-imx577.dtso    |  67 ++++
 arch/arm64/boot/dts/qcom/monaco-evk.dts       |  51 +++
 arch/arm64/boot/dts/qcom/monaco.dtsi          | 324 ++++++++++++++++++
 5 files changed, 448 insertions(+)
 create mode 100644 arch/arm64/boot/dts/qcom/monaco-evk-camera-imx577.dtso

-- 
2.34.1



From quic_nihalkum at quicinc.com  Mon Dec 15 22:22:19 2025
From: quic_nihalkum at quicinc.com (Nihal Kumar Gupta)
Date: Tue, 16 Dec 2025 11:52:19 +0530
Subject: [PATCH v7 1/5] dt-bindings: i2c: qcom-cci: Document qcs8300 compatible
In-Reply-To: <20251216062223.2474216-1-quic_nihalkum@quicinc.com>
References: <20251216062223.2474216-1-quic_nihalkum@quicinc.com>
Message-ID: <20251216062223.2474216-2-quic_nihalkum@quicinc.com>

The three instances of CCI found on the QCS8300 are functionally the same
as on a number of existing Qualcomm SoCs.

Introduce a new SoC-specific compatible string "qcom,qcs8300-cci" with a
common fallback.

Signed-off-by: Nihal Kumar Gupta <quic_nihalkum at quicinc.com>
Signed-off-by: Vikram Sharma <quic_vikramsa at quicinc.com>
Reviewed-by: Bryan O'Donoghue <bryan.odonoghue at linaro.org>
Acked-by: Rob Herring (Arm) <robh at kernel.org>
Reviewed-by: Vladimir Zapolskiy <vladimir.zapolskiy at linaro.org>
---
 Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml
index a3fe1eea6aec..399a09409e07 100644
--- a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml
+++ b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml
@@ -28,6 +28,7 @@ properties:
           - enum:
               - qcom,kaanapali-cci
               - qcom,qcm2290-cci
+              - qcom,qcs8300-cci
               - qcom,sa8775p-cci
               - qcom,sc7280-cci
               - qcom,sc8280xp-cci
@@ -133,6 +134,7 @@ allOf:
             enum:
               - qcom,kaanapali-cci
               - qcom,qcm2290-cci
+              - qcom,qcs8300-cci
               - qcom,sm8750-cci
     then:
       properties:
-- 
2.34.1



From quic_nihalkum at quicinc.com  Mon Dec 15 22:22:20 2025
From: quic_nihalkum at quicinc.com (Nihal Kumar Gupta)
Date: Tue, 16 Dec 2025 11:52:20 +0530
Subject: [PATCH v7 2/5] arm64: dts: qcom: monaco: Add CCI definitions
In-Reply-To: <20251216062223.2474216-1-quic_nihalkum@quicinc.com>
References: <20251216062223.2474216-1-quic_nihalkum@quicinc.com>
Message-ID: <20251216062223.2474216-3-quic_nihalkum@quicinc.com>

Qualcomm QCS8300 SoC contains three Camera Control Interface (CCI).
Compared to Lemans, the key difference is in SDA/SCL GPIO assignments
and number of CCIs.

Signed-off-by: Nihal Kumar Gupta <quic_nihalkum at quicinc.com>
Co-developed-by: Ravi Shankar <quic_rshankar at quicinc.com>
Signed-off-by: Ravi Shankar <quic_rshankar at quicinc.com>
Co-developed-by: Vishal Verma <quic_vishverm at quicinc.com>
Signed-off-by: Vishal Verma <quic_vishverm at quicinc.com>
Co-developed-by: Suresh Vankadara <quic_svankada at quicinc.com>
Signed-off-by: Suresh Vankadara <quic_svankada at quicinc.com>
Signed-off-by: Vikram Sharma <quic_vikramsa at quicinc.com>
Reviewed-by: Vladimir Zapolskiy <vladimir.zapolskiy at linaro.org>
Reviewed-by: Bryan O'Donoghue <bryan.odonoghue at linaro.org>
Reviewed-by: Konrad Dybcio <konrad.dybcio at oss.qualcomm.com>
---
 arch/arm64/boot/dts/qcom/monaco.dtsi | 303 +++++++++++++++++++++++++++
 1 file changed, 303 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/monaco.dtsi b/arch/arm64/boot/dts/qcom/monaco.dtsi
index 774255c3f6fc..4b2d8a449b00 100644
--- a/arch/arm64/boot/dts/qcom/monaco.dtsi
+++ b/arch/arm64/boot/dts/qcom/monaco.dtsi
@@ -4776,6 +4776,117 @@ videocc: clock-controller at abf0000 {
 			#power-domain-cells = <1>;
 		};
 
+		cci0: cci at ac13000 {
+			compatible = "qcom,qcs8300-cci", "qcom,msm8996-cci";
+			reg = <0x0 0x0ac13000 0x0 0x1000>;
+
+			interrupts = <GIC_SPI 460 IRQ_TYPE_EDGE_RISING>;
+
+			clocks = <&camcc CAM_CC_CPAS_AHB_CLK>,
+				 <&camcc CAM_CC_CCI_0_CLK>;
+			clock-names = "cpas_ahb",
+				      "cci";
+
+			power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>;
+
+			pinctrl-0 = <&cci0_0_default &cci0_1_default>;
+			pinctrl-1 = <&cci0_0_sleep &cci0_1_sleep>;
+			pinctrl-names = "default", "sleep";
+
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			status = "disabled";
+
+			cci0_i2c0: i2c-bus at 0 {
+				reg = <0>;
+				clock-frequency = <1000000>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+
+			cci0_i2c1: i2c-bus at 1 {
+				reg = <1>;
+				clock-frequency = <1000000>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+		};
+
+		cci1: cci at ac14000 {
+			compatible = "qcom,qcs8300-cci", "qcom,msm8996-cci";
+			reg = <0x0 0x0ac14000 0x0 0x1000>;
+
+			interrupts = <GIC_SPI 271 IRQ_TYPE_EDGE_RISING>;
+
+			clocks = <&camcc CAM_CC_CPAS_AHB_CLK>,
+				 <&camcc CAM_CC_CCI_1_CLK>;
+			clock-names = "cpas_ahb",
+				      "cci";
+
+			power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>;
+
+			pinctrl-0 = <&cci1_0_default &cci1_1_default>;
+			pinctrl-1 = <&cci1_0_sleep &cci1_1_sleep>;
+			pinctrl-names = "default", "sleep";
+
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			status = "disabled";
+
+			cci1_i2c0: i2c-bus at 0 {
+				reg = <0>;
+				clock-frequency = <1000000>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+
+			cci1_i2c1: i2c-bus at 1 {
+				reg = <1>;
+				clock-frequency = <1000000>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+		};
+
+		cci2: cci at ac15000 {
+			compatible = "qcom,qcs8300-cci", "qcom,msm8996-cci";
+			reg = <0x0 0x0ac15000 0x0 0x1000>;
+
+			interrupts = <GIC_SPI 651 IRQ_TYPE_EDGE_RISING>;
+
+			clocks = <&camcc CAM_CC_CPAS_AHB_CLK>,
+				 <&camcc CAM_CC_CCI_2_CLK>;
+			clock-names = "cpas_ahb",
+				      "cci";
+
+			power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>;
+
+			pinctrl-0 = <&cci2_0_default &cci2_1_default>;
+			pinctrl-1 = <&cci2_0_sleep &cci2_1_sleep>;
+			pinctrl-names = "default", "sleep";
+
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			status = "disabled";
+
+			cci2_i2c0: i2c-bus at 0 {
+				reg = <0>;
+				clock-frequency = <1000000>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+
+			cci2_i2c1: i2c-bus at 1 {
+				reg = <1>;
+				clock-frequency = <1000000>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+		};
+
 		camss: isp at ac78000 {
 			compatible = "qcom,qcs8300-camss";
 
@@ -5071,6 +5182,198 @@ tlmm: pinctrl at f100000 {
 			#interrupt-cells = <2>;
 			wakeup-parent = <&pdc>;
 
+			cci0_0_default: cci0-0-default-state {
+				sda-pins {
+					pins = "gpio57";
+					function = "cci_i2c_sda";
+					drive-strength = <2>;
+					bias-pull-up = <2200>;
+				};
+
+				scl-pins {
+					pins = "gpio58";
+					function = "cci_i2c_scl";
+					drive-strength = <2>;
+					bias-pull-up = <2200>;
+				};
+			};
+
+			cci0_0_sleep: cci0-0-sleep-state {
+				sda-pins {
+					pins = "gpio57";
+					function = "cci_i2c_sda";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+
+				scl-pins {
+					pins = "gpio58";
+					function = "cci_i2c_scl";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+
+			cci0_1_default: cci0-1-default-state {
+				sda-pins {
+					pins = "gpio29";
+					function = "cci_i2c_sda";
+					drive-strength = <2>;
+					bias-pull-up = <2200>;
+				};
+
+				scl-pins {
+					pins = "gpio30";
+					function = "cci_i2c_scl";
+					drive-strength = <2>;
+					bias-pull-up = <2200>;
+				};
+			};
+
+			cci0_1_sleep: cci0-1-sleep-state {
+				sda-pins {
+					pins = "gpio29";
+					function = "cci_i2c_sda";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+
+				scl-pins {
+					pins = "gpio30";
+					function = "cci_i2c_scl";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+
+			cci1_0_default: cci1-0-default-state {
+				sda-pins {
+					pins = "gpio59";
+					function = "cci_i2c_sda";
+					drive-strength = <2>;
+					bias-pull-up = <2200>;
+				};
+
+				scl-pins {
+					pins = "gpio60";
+					function = "cci_i2c_scl";
+					drive-strength = <2>;
+					bias-pull-up = <2200>;
+				};
+			};
+
+			cci1_0_sleep: cci1-0-sleep-state {
+				sda-pins {
+					pins = "gpio59";
+					function = "cci_i2c_sda";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+
+				scl-pins {
+					pins = "gpio60";
+					function = "cci_i2c_scl";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+
+			cci1_1_default: cci1-1-default-state {
+				sda-pins {
+					pins = "gpio31";
+					function = "cci_i2c_sda";
+					drive-strength = <2>;
+					bias-pull-up = <2200>;
+				};
+
+				scl-pins {
+					pins = "gpio32";
+					function = "cci_i2c_scl";
+					drive-strength = <2>;
+					bias-pull-up = <2200>;
+				};
+			};
+
+			cci1_1_sleep: cci1-1-sleep-state {
+				sda-pins {
+					pins = "gpio31";
+					function = "cci_i2c_sda";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+
+				scl-pins {
+					pins = "gpio32";
+					function = "cci_i2c_scl";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+
+			cci2_0_default: cci2-0-default-state {
+				sda-pins {
+					pins = "gpio61";
+					function = "cci_i2c_sda";
+					drive-strength = <2>;
+					bias-pull-up = <2200>;
+				};
+
+				scl-pins {
+					pins = "gpio62";
+					function = "cci_i2c_scl";
+					drive-strength = <2>;
+					bias-pull-up = <2200>;
+				};
+			};
+
+			cci2_0_sleep: cci2-0-sleep-state {
+				sda-pins {
+					pins = "gpio61";
+					function = "cci_i2c_sda";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+
+				scl-pins {
+					pins = "gpio62";
+					function = "cci_i2c_scl";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+
+			cci2_1_default: cci2-1-default-state {
+				sda-pins {
+					pins = "gpio54";
+					function = "cci_i2c_sda";
+					drive-strength = <2>;
+					bias-pull-up = <2200>;
+				};
+
+				scl-pins {
+					pins = "gpio55";
+					function = "cci_i2c_scl";
+					drive-strength = <2>;
+					bias-pull-up = <2200>;
+				};
+			};
+
+			cci2_1_sleep: cci2-1-sleep-state {
+				sda-pins {
+					pins = "gpio54";
+					function = "cci_i2c_sda";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+
+				scl-pins {
+					pins = "gpio55";
+					function = "cci_i2c_scl";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+
 			hs0_mi2s_active: hs0-mi2s-active-state {
 				pins = "gpio106", "gpio107", "gpio108", "gpio109";
 				function = "hs0_mi2s";
-- 
2.34.1



From quic_nihalkum at quicinc.com  Mon Dec 15 22:22:21 2025
From: quic_nihalkum at quicinc.com (Nihal Kumar Gupta)
Date: Tue, 16 Dec 2025 11:52:21 +0530
Subject: [PATCH v7 3/5] arm64: dts: qcom: monaco: Add camera MCLK pinctrl
In-Reply-To: <20251216062223.2474216-1-quic_nihalkum@quicinc.com>
References: <20251216062223.2474216-1-quic_nihalkum@quicinc.com>
Message-ID: <20251216062223.2474216-4-quic_nihalkum@quicinc.com>

Define pinctrl definitions to enable camera master clocks on Monaco.

Signed-off-by: Nihal Kumar Gupta <quic_nihalkum at quicinc.com>
Signed-off-by: Vikram Sharma <quic_vikramsa at quicinc.com>
---
 arch/arm64/boot/dts/qcom/monaco.dtsi | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/monaco.dtsi b/arch/arm64/boot/dts/qcom/monaco.dtsi
index 4b2d8a449b00..ace09239d167 100644
--- a/arch/arm64/boot/dts/qcom/monaco.dtsi
+++ b/arch/arm64/boot/dts/qcom/monaco.dtsi
@@ -5182,6 +5182,27 @@ tlmm: pinctrl at f100000 {
 			#interrupt-cells = <2>;
 			wakeup-parent = <&pdc>;
 
+			cam0_default: cam0-default-state {
+				pins = "gpio67";
+				function = "cam_mclk";
+				drive-strength = <2>;
+				bias-disable;
+			};
+
+			cam1_default: cam1-default-state {
+				pins = "gpio68";
+				function = "cam_mclk";
+				drive-strength = <2>;
+				bias-disable;
+			};
+
+			cam2_default: cam2-default-state {
+				pins = "gpio69";
+				function = "cam_mclk";
+				drive-strength = <2>;
+				bias-disable;
+			};
+
 			cci0_0_default: cci0-0-default-state {
 				sda-pins {
 					pins = "gpio57";
-- 
2.34.1



From quic_nihalkum at quicinc.com  Mon Dec 15 22:22:22 2025
From: quic_nihalkum at quicinc.com (Nihal Kumar Gupta)
Date: Tue, 16 Dec 2025 11:52:22 +0530
Subject: [PATCH v7 4/5] arm64: dts: qcom: monaco-evk: Add camera AVDD regulators
In-Reply-To: <20251216062223.2474216-1-quic_nihalkum@quicinc.com>
References: <20251216062223.2474216-1-quic_nihalkum@quicinc.com>
Message-ID: <20251216062223.2474216-5-quic_nihalkum@quicinc.com>

Define three fixed regulators for camera AVDD rails, each gpio-controlled
with corresponding pinctrl definitions.

Signed-off-by: Nihal Kumar Gupta <quic_nihalkum at quicinc.com>
Signed-off-by: Vikram Sharma <quic_vikramsa at quicinc.com>
---
 arch/arm64/boot/dts/qcom/monaco-evk.dts | 51 +++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/monaco-evk.dts b/arch/arm64/boot/dts/qcom/monaco-evk.dts
index bb35893da73d..75110129fd09 100644
--- a/arch/arm64/boot/dts/qcom/monaco-evk.dts
+++ b/arch/arm64/boot/dts/qcom/monaco-evk.dts
@@ -76,6 +76,36 @@ platform {
 			};
 		};
 	};
+
+	vreg_cam0_2p8: vreg-cam0-2p8 {
+		compatible = "regulator-fixed";
+		regulator-name = "vreg_cam0_2p8";
+		startup-delay-us = <10000>;
+		enable-active-high;
+		gpio = <&tlmm 73 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&cam0_avdd_2v8_en_default>;
+		pinctrl-names = "default";
+	};
+
+	vreg_cam1_2p8: vreg-cam1-2p8 {
+		compatible = "regulator-fixed";
+		regulator-name = "vreg_cam1_2p8";
+		startup-delay-us = <10000>;
+		enable-active-high;
+		gpio = <&tlmm 74 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&cam1_avdd_2v8_en_default>;
+		pinctrl-names = "default";
+	};
+
+	vreg_cam2_2p8: vreg-cam2-2p8 {
+		compatible = "regulator-fixed";
+		regulator-name = "vreg_cam2_2p8";
+		startup-delay-us = <10000>;
+		enable-active-high;
+		gpio = <&tlmm 75 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&cam2_avdd_2v8_en_default>;
+		pinctrl-names = "default";
+	};
 };
 
 &apps_rsc {
@@ -435,6 +465,27 @@ &serdes0 {
 };
 
 &tlmm {
+	cam0_avdd_2v8_en_default: cam0-avdd-2v8-en-state {
+		pins = "gpio73";
+		function = "gpio";
+		drive-strength = <2>;
+		bias-disable;
+	};
+
+	cam1_avdd_2v8_en_default: cam1-avdd-2v8-en-state {
+		pins = "gpio74";
+		function = "gpio";
+		drive-strength = <2>;
+		bias-disable;
+	};
+
+	cam2_avdd_2v8_en_default: cam2-avdd-2v8-en-state {
+		pins = "gpio75";
+		function = "gpio";
+		drive-strength = <2>;
+		bias-disable;
+	};
+
 	ethernet0_default: ethernet0-default-state {
 		ethernet0_mdc: ethernet0-mdc-pins {
 			pins = "gpio5";
-- 
2.34.1



From quic_nihalkum at quicinc.com  Mon Dec 15 22:22:23 2025
From: quic_nihalkum at quicinc.com (Nihal Kumar Gupta)
Date: Tue, 16 Dec 2025 11:52:23 +0530
Subject: [PATCH v7 5/5] arm64: dts: qcom: monaco-evk-camera: Add DT overlay
In-Reply-To: <20251216062223.2474216-1-quic_nihalkum@quicinc.com>
References: <20251216062223.2474216-1-quic_nihalkum@quicinc.com>
Message-ID: <20251216062223.2474216-6-quic_nihalkum@quicinc.com>

Monaco EVK board does not include a camera sensor in its default hardware
configuration. Introducing a device tree overlay to support optional
integration of the IMX577 sensor via CSIPHY1.

Camera reset is handled through an I2C expander, and power is enabled
via TLMM GPIO74.

An example media-ctl pipeline for the imx577 is:

media-ctl --reset
media-ctl -V '"imx577 3-001a":0[fmt:SRGGB10/4056x3040 field:none]'
media-ctl -V '"msm_csiphy1":0[fmt:SRGGB10/4056x3040]'
media-ctl -V '"msm_csid0":0[fmt:SRGGB10/4056x3040]'
media-ctl -V '"msm_vfe0_rdi0":0[fmt:SRGGB10/4056x3040]'
media-ctl -l '"msm_csiphy1":1->"msm_csid0":0[1]'
media-ctl -l '"msm_csid0":1->"msm_vfe0_rdi0":0[1]'
yavta -B capture-mplane -c -I -n 5 -f SRGGB10P -s 4056x3040 -F /dev/video1

Signed-off-by: Nihal Kumar Gupta <quic_nihalkum at quicinc.com>
Co-developed-by: Ravi Shankar <quic_rshankar at quicinc.com>
Signed-off-by: Ravi Shankar <quic_rshankar at quicinc.com>
Co-developed-by: Vishal Verma <quic_vishverm at quicinc.com>
Signed-off-by: Vishal Verma <quic_vishverm at quicinc.com>
Signed-off-by: Vikram Sharma <quic_vikramsa at quicinc.com>
Reviewed-by: Vladimir Zapolskiy <vladimir.zapolskiy at linaro.org>
Reviewed-by: Bryan O'Donoghue <bryan.odonoghue at linaro.org>
---
 arch/arm64/boot/dts/qcom/Makefile             |  4 ++
 .../dts/qcom/monaco-evk-camera-imx577.dtso    | 67 +++++++++++++++++++
 2 files changed, 71 insertions(+)
 create mode 100644 arch/arm64/boot/dts/qcom/monaco-evk-camera-imx577.dtso

diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 6f34d5ed331c..b1ba182a0d8d 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -38,6 +38,10 @@ lemans-evk-camera-dtbs	:= lemans-evk.dtb lemans-evk-camera.dtbo
 dtb-$(CONFIG_ARCH_QCOM)	+= lemans-evk-camera-csi1-imx577.dtb
 dtb-$(CONFIG_ARCH_QCOM)	+= lemans-evk-camera.dtb
 dtb-$(CONFIG_ARCH_QCOM)	+= monaco-evk.dtb
+
+monaco-evk-camera-imx577-dtbs	:= monaco-evk.dtb monaco-evk-camera-imx577.dtbo
+dtb-$(CONFIG_ARCH_QCOM)	+= monaco-evk-camera-imx577.dtb
+
 dtb-$(CONFIG_ARCH_QCOM)	+= msm8216-samsung-fortuna3g.dtb
 dtb-$(CONFIG_ARCH_QCOM)	+= msm8916-acer-a1-724.dtb
 dtb-$(CONFIG_ARCH_QCOM)	+= msm8916-alcatel-idol347.dtb
diff --git a/arch/arm64/boot/dts/qcom/monaco-evk-camera-imx577.dtso b/arch/arm64/boot/dts/qcom/monaco-evk-camera-imx577.dtso
new file mode 100644
index 000000000000..351eb5ee70ba
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/monaco-evk-camera-imx577.dtso
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,sa8775p-camcc.h>
+#include <dt-bindings/gpio/gpio.h>
+
+&camss {
+	vdda-phy-supply = <&vreg_l4a>;
+	vdda-pll-supply = <&vreg_l5a>;
+
+	status = "okay";
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 1 {
+			reg = <1>;
+
+			csiphy1_ep: endpoint {
+				clock-lanes = <7>;
+				data-lanes = <0 1 2 3>;
+				remote-endpoint = <&imx577_ep1>;
+			};
+		};
+	};
+};
+
+&cci1 {
+	pinctrl-0 = <&cci1_0_default>;
+	pinctrl-1 = <&cci1_0_sleep>;
+
+	status = "okay";
+};
+
+&cci1_i2c0 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	camera at 1a {
+		compatible = "sony,imx577";
+		reg = <0x1a>;
+
+		reset-gpios = <&expander2 1 GPIO_ACTIVE_LOW>;
+		pinctrl-0 = <&cam1_default>;
+		pinctrl-names = "default";
+
+		clocks = <&camcc CAM_CC_MCLK1_CLK>;
+		assigned-clocks = <&camcc CAM_CC_MCLK1_CLK>;
+		assigned-clock-rates = <24000000>;
+
+		avdd-supply = <&vreg_cam1_2p8>;
+
+		port {
+			imx577_ep1: endpoint {
+				link-frequencies = /bits/ 64 <600000000>;
+				data-lanes = <0 1 2 3>;
+				remote-endpoint = <&csiphy1_ep>;
+			};
+		};
+	};
+};
-- 
2.34.1



From krzk at kernel.org  Mon Dec 15 22:25:18 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 16 Dec 2025 07:25:18 +0100
Subject: [PATCH 1/8] dt-bindings: vendor-prefixes: Add AAEON vendor prefix
In-Reply-To: <20251212-dev-b4-aaeon-mcu-driver-v1-1-6bd65bc8ef12@bootlin.com>
References: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com>
 <20251212-dev-b4-aaeon-mcu-driver-v1-1-6bd65bc8ef12@bootlin.com>
Message-ID: <20251216-tricky-masterful-wildcat-1efbd5@quoll>

On Fri, Dec 12, 2025 at 08:41:04AM +0100, Thomas Perrot (Schneider Electric) wrote:
> Add the AAEON vendor prefix to support the AAEON SRG-IMX8PL MCU driver
> devicetree bindings.
> 
> Signed-off-by: Thomas Perrot (Schneider Electric) <thomas.perrot at bootlin.com>
> ---
>  Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
>  1 file changed, 2 insertions(+)

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof



From krzk at kernel.org  Mon Dec 15 22:28:39 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 16 Dec 2025 07:28:39 +0100
Subject: [PATCH 1/2] dt-bindings: power: fsl,imx-gpc: Document
 address-cells
In-Reply-To: <20251212085902.103507-1-alexander.stein@ew.tq-group.com>
References: <20251212085902.103507-1-alexander.stein@ew.tq-group.com>
Message-ID: <20251216-placid-speedy-rooster-ffcfe9@quoll>

On Fri, Dec 12, 2025 at 09:58:59AM +0100, Alexander Stein wrote:
> The GPC power controller is an interrupt controllers and can be referenced
> in interrupt-map properties, e.g. PCIe controller, thus the node should
> have address-cells property.

You could say here that there are no children, thus using value of 0.

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof



From krzk at kernel.org  Mon Dec 15 22:53:59 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 16 Dec 2025 07:53:59 +0100
Subject: [PATCH] ARM: dts: samsung: Drop s3c6400.dtsi
In-Reply-To: <20251212203226.458694-7-robh@kernel.org>
References: <20251212203226.458694-7-robh@kernel.org>
Message-ID: <176586803906.20461.7032133342686064495.b4-ty@kernel.org>


On Fri, 12 Dec 2025 14:32:13 -0600, Rob Herring (Arm) wrote:
> This .dtsi file is not included anywhere in the tree and can't be
> tested.
> 
> 

Applied, thanks!

[1/1] ARM: dts: samsung: Drop s3c6400.dtsi
      https://git.kernel.org/krzk/linux/c/549089586a4a45720702c3bbc9fd4fa2ad60ac6d

Best regards,
-- 
Krzysztof Kozlowski <krzk at kernel.org>



From rdunlap at infradead.org  Mon Dec 15 22:54:24 2025
From: rdunlap at infradead.org (Randy Dunlap)
Date: Mon, 15 Dec 2025 22:54:24 -0800
Subject: [PATCH 00/26] Introduce meminspect
In-Reply-To: <c3db6ccd-dfc7-4a6a-82b7-3d615f8cab4f@linaro.org>
References: <20251119154427.1033475-1-eugen.hristev@linaro.org>
 <bf00eec5-e9fe-41df-b758-7601815b24a0@linaro.org>
 <5903a8e1-71c6-4546-ac50-35effa078dda@infradead.org>
 <c3db6ccd-dfc7-4a6a-82b7-3d615f8cab4f@linaro.org>
Message-ID: <b74aef93-9138-413a-8327-36c746d67e10@infradead.org>



On 12/12/25 11:22 PM, Eugen Hristev wrote:
> 
> 
> On 12/13/25 08:57, Randy Dunlap wrote:
>> Hi,
>>
>> On 12/12/25 10:48 PM, Eugen Hristev wrote:
>>>
>>>
>>> On 11/19/25 17:44, Eugen Hristev wrote:
>>>> meminspect is a mechanism which allows the kernel to mark specific memory
>>>> areas for memory dumping or specific inspection, statistics, usage.
>>>> Once regions are marked, meminspect keeps an internal list with the regions
>>>> in a dedicated table.
>>>
>>> [...]
>>>
>>>
>>>> I will present this version at Plumbers conference in Tokyo on December 13th:
>>>> https://lpc.events/event/19/contributions/2080/
>>>> I am eager to discuss it there face to face.
>>>
>>> Summary of the discussions at LPC talk on Dec 13th:
>>>
>>> One main idea on the static variables annotation was to do some linker
>>> magic, to create a list of variables in the tree, that would be parsed
>>> by some script, the addresses and sizes would be then stored into the
>>> dedicated section at the script level, without having any C code change.
>>> Pros: no C code change, Cons: it would be hidden/masked from the code,
>>> easy to miss out, which might lead to people's variables being annotated
>>> without them knowing
>>>
>>> Another idea was to have variables directly stored in a dedicated
>>> section which would be added to the table.
>>> e.g. static int __attribute(section (...)) nr_irqs;
>>> Pros: no more meminspect section Cons: have to keep all interesting
>>> variables in a separate section, which might not be okay for everyone.
>>>
>>> On dynamic memory, the memblock flag marking did not receive any obvious
>>> NAKs.
>>>
>>> On dynamic memory that is bigger in size than one page, as the table
>>> entries are registered by virtual address, this would be non-contiguous
>>> in physical memory. How is this solved?
>>> -> At the moment it's left for the consumer drivers to handle this
>>> situation. If the region is a VA and the size > PAGE_SIZE, then the
>>> driver needs to handle the way it handles it. Maybe the driver that
>>> parses the entry needs to convert it into multiple contiguous entries,
>>> or just have virtual address is enough. The inspection table does not
>>> enforce or limit the entries to contiguous entries only.
>>>
>>> On the traverse/notifier system, the implementation did not receive any
>>> obvious NAKs
>>>
>>> General comments:
>>>
>>> Trilok Soni from Qualcomm mentioned they will be using this into their
>>> software deliveries in production.
>>>
>>> Someone suggested to have some mechanism to block specific data from
>>> being added to the inspection table as being sensitive non-inspectable
>>> data.
>>> [Eugen]: Still have to figure out how that could be done. Stuff is not
>>> being added to the table by default.
>>>
>>> Another comment was about what use case there is in mind, is this for
>>> servers, or for confidential computing, because each different use case
>>> might have different requirements, like ignoring some regions is an
>>> option in one case, but bloating the table in another case might not be
>>> fine.
>>> [Eugen]: The meminspect scenario should cover all cases and not be too
>>> specific. If it is generic enough and customizable enough to care for
>>> everyone's needs then I consider it being a success. It should not
>>> specialize in neither of these two different cases, but rather be
>>> tailored by each use case to provide the mandatory requirements for that
>>> case.
>>>
>>> Another comment mentioned that this usecase does not apply to many
>>> people due to firmware or specific hardware needed.
>>> [Eugen]: one interesting proposed usecase is to have a pstore
>>> driver/implementation that would traverse the inspection table at panic
>>> handler time, then gather data from there to store in the pstore
>>> (ramoops, mtdoops or whatever backend) and have it available to the
>>> userspace after reboot. This would be a nice use case that does not
>>> require firmware nor specific hardware, just pstore backend support.
>>>
>>> Ending note was whether this implementation is going in a good direction
>>> and what would be the way to having it moving upstream.
>>>
>>> Thanks everyone who attended and came up with ideas and comments.
>>> There are a few comments which I may have missed, so please feel free to
>>> reply to this email to start a discussion thread on the topic you are
>>> interested in.
>>>
>>> Eugen
>>>
>>
>> Maybe you or someone else has already mentioned this. If so, sorry I missed it.
>>
>> How does this compare or contrast to VMCOREINFO?
>>
>> thanks.
> 
> This inspection table could be created in an VMCOREINFO way, the patch
> series here[1] is something that would fit it best .
> 
> The drawbacks are :
> some static variables have to be registered to VMCOREINFO in their file
> of residence. This means including vmcoreinfo header and adding
> functions/code there, and everywhere that would be needed , or , the
> variables have to be un-static'ed , which is a no-go.
> This received more negative opinions on that particular patch series.
> The annotation idea seemed cleaner and simpler, and more generic.
> 
> We could add more and more entries to the vmcoreinfo table, but that
> would mean expanding it a lot, which it would maybe defy its purpose,
> and be getting too big, especially for the cases where custom drivers
> would like to register data.
> 
> How I see it, is that maybe the vmcoreinfo init function, could also
> parse the inspection table and create more entries if that is needed.
> So somehow memory inspection is a superset or generalization , while
> VMCOREINFO is a more particular use case that would fit here.
> 
> Do you think of some better way to integrate the meminspect table into
> VMCOREINFO ?

No, I just wanted to make sure that you or someone had looked into that.
Thanks for your summary.

> [1]
> https://lore.kernel.org/all/20250912150855.2901211-1-eugen.hristev at linaro.org/

-- 
~Randy



From krzk at kernel.org  Mon Dec 15 22:54:22 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 16 Dec 2025 07:54:22 +0100
Subject: [PATCH] arm64: dts: toshiba: tmpv7708: Align node names with
 DT bindings
In-Reply-To: <20251022133616.74492-2-krzysztof.kozlowski@linaro.org>
References: <20251022133616.74492-2-krzysztof.kozlowski@linaro.org>
Message-ID: <176586806270.20531.3411870761974576435.b4-ty@kernel.org>


On Wed, 22 Oct 2025 15:36:17 +0200, Krzysztof Kozlowski wrote:
> DT bindings expect node names to follow certain pattern, dtbs_check
> warnings:
> 
>   tmpv7708-rm-mbrc.dtb: pmux at 24190000 (toshiba,tmpv7708-pinctrl):
>     'pwm_mux' does not match any of the regexes: '-pins$', '^pinctrl-[0-9]+$'
>   tmpv7708-rm-mbrc.dtb pmux at 24190000 (toshiba,tmpv7708-pinctrl):
>     $nodename:0: 'pmux at 24190000' does not match '^(pinctrl|pinmux)(@[0-9a-f]+)?$'
>   tmpv7708-rm-mbrc.dtb: wdt at 28330000 (toshiba,visconti-wdt):
>     $nodename:0: 'wdt at 28330000' does not match '^(timer|watchdog)(@.*|-([0-9]|[1-9][0-9]+))?$'
> 
> [...]

Applied, thanks!

[1/1] arm64: dts: toshiba: tmpv7708: Align node names with DT bindings
      https://git.kernel.org/krzk/linux-dt/c/af8dbb88188784cfcdc215487e0173a6f62caf52

Best regards,
-- 
Krzysztof Kozlowski <krzk at kernel.org>



From ankur.a.arora at oracle.com  Mon Dec 15 22:55:27 2025
From: ankur.a.arora at oracle.com (Ankur Arora)
Date: Mon, 15 Dec 2025 22:55:27 -0800
Subject: [PATCH v8 12/12] cpuidle/poll_state: Wait for need-resched via
 tif_need_resched_relaxed_wait()
In-Reply-To: <CAJZ5v0imk5kdqunNGvK+6_BPh2_k89RPPC8B4MDDF1GLZrUhLQ@mail.gmail.com>
References: <20251215044919.460086-1-ankur.a.arora@oracle.com>
 <20251215044919.460086-13-ankur.a.arora@oracle.com>
 <CAJZ5v0imk5kdqunNGvK+6_BPh2_k89RPPC8B4MDDF1GLZrUhLQ@mail.gmail.com>
Message-ID: <87ecoudig0.fsf@oracle.com>


Rafael J. Wysocki <rafael at kernel.org> writes:

> On Mon, Dec 15, 2025 at 5:55?AM Ankur Arora <ankur.a.arora at oracle.com> wrote:
>>
>> The inner loop in poll_idle() polls over the thread_info flags,
>> waiting to see if the thread has TIF_NEED_RESCHED set. The loop
>> exits once the condition is met, or if the poll time limit has
>> been exceeded.
>>
>> To minimize the number of instructions executed in each iteration,
>> the time check is rate-limited. In addition, each loop iteration
>> executes cpu_relax() which on certain platforms provides a hint to
>> the pipeline that the loop busy-waits, allowing the processor to
>> reduce power consumption.
>>
>> Switch over to tif_need_resched_relaxed_wait() instead, since that
>> provides exactly that.
>>
>> However, given that when running in idle we want to minimize our power
>> consumption, continue to depend on CONFIG_ARCH_HAS_CPU_RELAX as that
>> serves as an indicator that the platform supports an optimized version
>> of tif_need_resched_relaxed_wait() (via
>> smp_cond_load_acquire_timeout()).
>>
>> Cc: "Rafael J. Wysocki" <rafael at kernel.org>
>> Cc: Daniel Lezcano <daniel.lezcano at linaro.org>
>> Cc: linux-pm at vger.kernel.org
>> Suggested-by: "Rafael J. Wysocki" <rafael at kernel.org>
>> Signed-off-by: Ankur Arora <ankur.a.arora at oracle.com>
>> ---
>>
>> Notes:
>>   - use tif_need_resched_relaxed_wait() instead of
>>     smp_cond_load_relaxed_timeout()
>>
>>  drivers/cpuidle/poll_state.c | 27 +++++----------------------
>>  1 file changed, 5 insertions(+), 22 deletions(-)
>>
>> diff --git a/drivers/cpuidle/poll_state.c b/drivers/cpuidle/poll_state.c
>> index c7524e4c522a..20136b3a08c2 100644
>> --- a/drivers/cpuidle/poll_state.c
>> +++ b/drivers/cpuidle/poll_state.c
>> @@ -6,41 +6,24 @@
>>  #include <linux/cpuidle.h>
>>  #include <linux/export.h>
>>  #include <linux/irqflags.h>
>> -#include <linux/sched.h>
>> -#include <linux/sched/clock.h>
>>  #include <linux/sched/idle.h>
>>  #include <linux/sprintf.h>
>>  #include <linux/types.h>
>>
>> -#define POLL_IDLE_RELAX_COUNT  200
>> -
>>  static int __cpuidle poll_idle(struct cpuidle_device *dev,
>>                                struct cpuidle_driver *drv, int index)
>>  {
>> -       u64 time_start;
>> -
>> -       time_start = local_clock_noinstr();
>> -
>>         dev->poll_time_limit = false;
>>
>>         raw_local_irq_enable();
>>         if (!current_set_polling_and_test()) {
>> -               unsigned int loop_count = 0;
>> -               u64 limit;
>> +               s64 limit;
>> +               bool nr_set;
>
> It doesn't look like the nr_set variable is really needed.
>
>>
>> -               limit = cpuidle_poll_time(drv, dev);
>> +               limit = (s64)cpuidle_poll_time(drv, dev);
>
> Is the explicit cast needed to suppress a warning?  If not, I'd drop it.

Ack.

>>
>> -               while (!need_resched()) {
>> -                       cpu_relax();
>> -                       if (loop_count++ < POLL_IDLE_RELAX_COUNT)
>> -                               continue;
>> -
>> -                       loop_count = 0;
>> -                       if (local_clock_noinstr() - time_start > limit) {
>> -                               dev->poll_time_limit = true;
>> -                               break;
>> -                       }
>> -               }
>> +               nr_set = tif_need_resched_relaxed_wait(limit);
>> +               dev->poll_time_limit = !nr_set;
>
> This can be
>
> dev->poll_time_limit = !tif_need_resched_relaxed_wait(limit);

Yeah that looks pretty clear.


Thanks!
--
ankur


From krzk at kernel.org  Mon Dec 15 22:56:46 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 16 Dec 2025 07:56:46 +0100
Subject: [PATCH v3 0/2] hwrng: exynos: enable GS101 TRNG support
In-Reply-To: <20251024-gs101-trng-v3-0-5d3403738f39@linaro.org>
References: <20251024-gs101-trng-v3-0-5d3403738f39@linaro.org>
Message-ID: <176586820615.20905.780207403546638829.b4-ty@kernel.org>


On Fri, 24 Oct 2025 17:57:33 +0000, Tudor Ambarus wrote:
> I propose the bindings to go through the Samsung tree as well so that we
> can match the compatible with the schema when pulling the DT patch.
> 
> Thanks!
> ta
> 

Applied, thanks!

[1/2] dt-bindings: rng: add google,gs101-trng compatible
      https://git.kernel.org/krzk/linux/c/d9465635e051ddc0d9ebb312174ace55d38d2d40
[2/2] arm64: dts: exynos: gs101: add TRNG node
      https://git.kernel.org/krzk/linux/c/d45eafec01fa31fb9ab30902de35fbbe70f63411

Best regards,
-- 
Krzysztof Kozlowski <krzk at kernel.org>



From krzk at kernel.org  Mon Dec 15 23:00:06 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 16 Dec 2025 08:00:06 +0100
Subject: [PATCH] mailmap: Add entry for Sam Protsenko
In-Reply-To: <20251118033111.23382-1-semen.protsenko@linaro.org>
References: <20251118033111.23382-1-semen.protsenko@linaro.org>
Message-ID: <5ee13869-de7f-4d17-87fb-edf9eda3388b@kernel.org>

On 18/11/2025 04:31, Sam Protsenko wrote:
> Use 'Sam Protsenko' as my name consistently in git-shortlog. Also map my
> old GlobalLogic email address to my current email to stay reachable.
> 
> Signed-off-by: Sam Protsenko <semen.protsenko at linaro.org>
> ---
>  .mailmap | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/.mailmap b/.mailmap
> index 3a3ba16c2601..9901716af12c 100644
> --- a/.mailmap
> +++ b/.mailmap
> @@ -691,6 +691,8 @@ Sachin Mokashi <sachin.mokashi at intel.com> <sachinx.mokashi at intel.com>
>  Sachin P Sant <ssant at in.ibm.com>
>  Sai Prakash Ranjan <quic_saipraka at quicinc.com> <saiprakash.ranjan at codeaurora.org>
>  Sakari Ailus <sakari.ailus at linux.intel.com> <sakari.ailus at iki.fi>
> +Sam Protsenko <semen.protsenko at linaro.org>
> +Sam Protsenko <semen.protsenko at linaro.org> <semen.protsenko at globallogic.com>


This does not apply anymore.

Best regards,
Krzysztof


From rdunlap at infradead.org  Mon Dec 15 23:00:33 2025
From: rdunlap at infradead.org (Randy Dunlap)
Date: Mon, 15 Dec 2025 23:00:33 -0800
Subject: [PATCH 00/26] Introduce meminspect
In-Reply-To: <b74aef93-9138-413a-8327-36c746d67e10@infradead.org>
References: <20251119154427.1033475-1-eugen.hristev@linaro.org>
 <bf00eec5-e9fe-41df-b758-7601815b24a0@linaro.org>
 <5903a8e1-71c6-4546-ac50-35effa078dda@infradead.org>
 <c3db6ccd-dfc7-4a6a-82b7-3d615f8cab4f@linaro.org>
 <b74aef93-9138-413a-8327-36c746d67e10@infradead.org>
Message-ID: <93682055-4a6d-4098-b74f-afef735d1699@infradead.org>



On 12/15/25 10:54 PM, Randy Dunlap wrote:
> 
> 
> On 12/12/25 11:22 PM, Eugen Hristev wrote:
>>
>>
>> On 12/13/25 08:57, Randy Dunlap wrote:
>>> Hi,
>>>
>>> On 12/12/25 10:48 PM, Eugen Hristev wrote:
>>>>
>>>>
>>>> On 11/19/25 17:44, Eugen Hristev wrote:
>>>>> meminspect is a mechanism which allows the kernel to mark specific memory
>>>>> areas for memory dumping or specific inspection, statistics, usage.
>>>>> Once regions are marked, meminspect keeps an internal list with the regions
>>>>> in a dedicated table.
>>>>
>>>> [...]
>>>>
>>>>
>>>>> I will present this version at Plumbers conference in Tokyo on December 13th:
>>>>> https://lpc.events/event/19/contributions/2080/
>>>>> I am eager to discuss it there face to face.
>>>>
>>>> Summary of the discussions at LPC talk on Dec 13th:
>>>>
>>>> One main idea on the static variables annotation was to do some linker
>>>> magic, to create a list of variables in the tree, that would be parsed
>>>> by some script, the addresses and sizes would be then stored into the
>>>> dedicated section at the script level, without having any C code change.
>>>> Pros: no C code change, Cons: it would be hidden/masked from the code,
>>>> easy to miss out, which might lead to people's variables being annotated
>>>> without them knowing
>>>>
>>>> Another idea was to have variables directly stored in a dedicated
>>>> section which would be added to the table.
>>>> e.g. static int __attribute(section (...)) nr_irqs;
>>>> Pros: no more meminspect section Cons: have to keep all interesting
>>>> variables in a separate section, which might not be okay for everyone.
>>>>
>>>> On dynamic memory, the memblock flag marking did not receive any obvious
>>>> NAKs.
>>>>
>>>> On dynamic memory that is bigger in size than one page, as the table
>>>> entries are registered by virtual address, this would be non-contiguous
>>>> in physical memory. How is this solved?
>>>> -> At the moment it's left for the consumer drivers to handle this
>>>> situation. If the region is a VA and the size > PAGE_SIZE, then the
>>>> driver needs to handle the way it handles it. Maybe the driver that
>>>> parses the entry needs to convert it into multiple contiguous entries,
>>>> or just have virtual address is enough. The inspection table does not
>>>> enforce or limit the entries to contiguous entries only.
>>>>
>>>> On the traverse/notifier system, the implementation did not receive any
>>>> obvious NAKs
>>>>
>>>> General comments:
>>>>
>>>> Trilok Soni from Qualcomm mentioned they will be using this into their
>>>> software deliveries in production.
>>>>
>>>> Someone suggested to have some mechanism to block specific data from
>>>> being added to the inspection table as being sensitive non-inspectable
>>>> data.
>>>> [Eugen]: Still have to figure out how that could be done. Stuff is not
>>>> being added to the table by default.
>>>>
>>>> Another comment was about what use case there is in mind, is this for
>>>> servers, or for confidential computing, because each different use case
>>>> might have different requirements, like ignoring some regions is an
>>>> option in one case, but bloating the table in another case might not be
>>>> fine.
>>>> [Eugen]: The meminspect scenario should cover all cases and not be too
>>>> specific. If it is generic enough and customizable enough to care for
>>>> everyone's needs then I consider it being a success. It should not
>>>> specialize in neither of these two different cases, but rather be
>>>> tailored by each use case to provide the mandatory requirements for that
>>>> case.
>>>>
>>>> Another comment mentioned that this usecase does not apply to many
>>>> people due to firmware or specific hardware needed.
>>>> [Eugen]: one interesting proposed usecase is to have a pstore
>>>> driver/implementation that would traverse the inspection table at panic
>>>> handler time, then gather data from there to store in the pstore
>>>> (ramoops, mtdoops or whatever backend) and have it available to the
>>>> userspace after reboot. This would be a nice use case that does not
>>>> require firmware nor specific hardware, just pstore backend support.
>>>>
>>>> Ending note was whether this implementation is going in a good direction
>>>> and what would be the way to having it moving upstream.
>>>>
>>>> Thanks everyone who attended and came up with ideas and comments.
>>>> There are a few comments which I may have missed, so please feel free to
>>>> reply to this email to start a discussion thread on the topic you are
>>>> interested in.
>>>>
>>>> Eugen
>>>>
>>>
>>> Maybe you or someone else has already mentioned this. If so, sorry I missed it.
>>>
>>> How does this compare or contrast to VMCOREINFO?
>>>
>>> thanks.
>>
>> This inspection table could be created in an VMCOREINFO way, the patch
>> series here[1] is something that would fit it best .
>>
>> The drawbacks are :
>> some static variables have to be registered to VMCOREINFO in their file
>> of residence. This means including vmcoreinfo header and adding
>> functions/code there, and everywhere that would be needed , or , the
>> variables have to be un-static'ed , which is a no-go.
>> This received more negative opinions on that particular patch series.
>> The annotation idea seemed cleaner and simpler, and more generic.
>>
>> We could add more and more entries to the vmcoreinfo table, but that
>> would mean expanding it a lot, which it would maybe defy its purpose,
>> and be getting too big, especially for the cases where custom drivers
>> would like to register data.
>>
>> How I see it, is that maybe the vmcoreinfo init function, could also
>> parse the inspection table and create more entries if that is needed.
>> So somehow memory inspection is a superset or generalization , while
>> VMCOREINFO is a more particular use case that would fit here.
>>
>> Do you think of some better way to integrate the meminspect table into
>> VMCOREINFO ?
> 
> No, I just wanted to make sure that you or someone had looked into that.
> Thanks for your summary.

Although you copied Stephen Brennan on this, I think it would be a good idea
to copy the linux-debuggers at vger.kernel.org mailing list also to see if
there are any other comments about it. [now done]

>> [1]
>> https://lore.kernel.org/all/20250912150855.2901211-1-eugen.hristev at linaro.org/
> 

-- 
~Randy



From tomas.melin at vaisala.com  Mon Dec 15 23:00:24 2025
From: tomas.melin at vaisala.com (Tomas Melin)
Date: Tue, 16 Dec 2025 07:00:24 +0000
Subject: [PATCH] Revert "arm64: zynqmp: Add an OP-TEE node to the device
 tree"
In-Reply-To: <7e82a871-0234-409a-8fd3-a548cbb789e8@amd.com>
References: <20251125-revert-zynqmp-optee-v1-1-d2ce4c0fcaf6@vaisala.com>
 <88b72343-e86f-4b13-adcc-ba09683eb898@amd.com>
 <199062ba-9a0d-40ae-ac8c-0fbed5615cf8@vaisala.com>
 <3654c600-553f-429a-8bec-1add7f6eb5c6@vaisala.com>
 <db79cd4a-548d-46f1-b498-aac82ca53010@amd.com>
 <0435af95-a3bc-4ec7-b07b-bdec42f25c56@vaisala.com>
 <7e82a871-0234-409a-8fd3-a548cbb789e8@amd.com>
Message-ID: <d4b2d17c-37f0-4089-b0a1-b790da36827b@vaisala.com>

On 15/12/2025 18:10, Michal Simek wrote:
>
>
> On 12/15/25 16:43, Tomas Melin wrote:
>> Hi,
>>
>> On 15/12/2025 17:21, Michal Simek wrote:
>>> Hi,
>>>
>>> On 12/12/25 13:09, Tomas Melin wrote:
>>>> Hi,
>>>>
>>>> Is there some more specific information I can provide regarding this patch?
>>>
>>> I am trying to identify U-Boot code (2026.01-rc4) which does what you have
>>> described in the commit message but I can't find it out.
>>> Can you please point me directly to file, line number where that described logic
>>> is skipped?
>>
>> Please check lib/optee/optee.c, in particular lines 128 ->
>> Target dt being linux kernel devicetree where the reserved-memory nodes
>> are automatically injected. When node is already there, it bails out early.
>
> I don't really mind that's why applied.
Sorry I didn't really understand, where is it applied?

BR,
Tomas

>
> Thanks,
> Michal
>
>



From krzk at kernel.org  Mon Dec 15 23:05:23 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 16 Dec 2025 08:05:23 +0100
Subject: [PATCH v2 0/2] Remove syscon compatible from google,gs101-pmu
 node
In-Reply-To: <20251114-remove-pmu-syscon-compat-v2-0-9496e8c496c7@linaro.org>
References: <20251114-remove-pmu-syscon-compat-v2-0-9496e8c496c7@linaro.org>
Message-ID: <176586872327.22265.10311318295410886509.b4-ty@kernel.org>


On Fri, 14 Nov 2025 12:00:15 +0000, Peter Griffin wrote:
> This series removes the syscon compatible from the pmu_system_controller
> node, by updating both yaml bindings and device tree.
> 
> Since commit ba5095ebbc7a ("mfd: syscon: Allow syscon nodes without a
> "syscon" compatible") it is possible to register a regmap without the
> syscon compatible in the node.
> 
> [...]

Applied, thanks!

[1/2] dt-bindings: soc: samsung: exynos-pmu: remove syscon for google,gs101-pmu
      https://git.kernel.org/krzk/linux/c/411727d9182d7a067fdd16a125d2069f52e8bb7f
[2/2] arm64: dts: exynos: gs101: remove syscon compatible from pmu node
      https://git.kernel.org/krzk/linux/c/a21d38b5e209c60e73f81e467cc53ad57b5d4080

Best regards,
-- 
Krzysztof Kozlowski <krzk at kernel.org>



From michal.simek at amd.com  Mon Dec 15 23:12:22 2025
From: michal.simek at amd.com (Michal Simek)
Date: Tue, 16 Dec 2025 08:12:22 +0100
Subject: [PATCH] Revert "arm64: zynqmp: Add an OP-TEE node to the device
 tree"
In-Reply-To: <d4b2d17c-37f0-4089-b0a1-b790da36827b@vaisala.com>
References: <20251125-revert-zynqmp-optee-v1-1-d2ce4c0fcaf6@vaisala.com>
 <88b72343-e86f-4b13-adcc-ba09683eb898@amd.com>
 <199062ba-9a0d-40ae-ac8c-0fbed5615cf8@vaisala.com>
 <3654c600-553f-429a-8bec-1add7f6eb5c6@vaisala.com>
 <db79cd4a-548d-46f1-b498-aac82ca53010@amd.com>
 <0435af95-a3bc-4ec7-b07b-bdec42f25c56@vaisala.com>
 <7e82a871-0234-409a-8fd3-a548cbb789e8@amd.com>
 <d4b2d17c-37f0-4089-b0a1-b790da36827b@vaisala.com>
Message-ID: <24e9397f-ddb9-4e6e-aaa8-3f0c0f647019@amd.com>



On 12/16/25 08:00, Tomas Melin wrote:
> On 15/12/2025 18:10, Michal Simek wrote:
>>
>>
>> On 12/15/25 16:43, Tomas Melin wrote:
>>> Hi,
>>>
>>> On 15/12/2025 17:21, Michal Simek wrote:
>>>> Hi,
>>>>
>>>> On 12/12/25 13:09, Tomas Melin wrote:
>>>>> Hi,
>>>>>
>>>>> Is there some more specific information I can provide regarding this patch?
>>>>
>>>> I am trying to identify U-Boot code (2026.01-rc4) which does what you have
>>>> described in the commit message but I can't find it out.
>>>> Can you please point me directly to file, line number where that described logic
>>>> is skipped?
>>>
>>> Please check lib/optee/optee.c, in particular lines 128 ->
>>> Target dt being linux kernel devicetree where the reserved-memory nodes
>>> are automatically injected. When node is already there, it bails out early.
>>
>> I don't really mind that's why applied.
> Sorry I didn't really understand, where is it applied?

https://github.com/Xilinx/linux-xlnx/tree/zynqmp/dt

And it is from today also in linux-next
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/log/arch/arm64/boot/dts/xilinx/zynqmp.dtsi?h=next-20251216

At the end of cycle it will go via soc tree to Linus.

Thanks,
Michal




From arnd at arndb.de  Mon Dec 15 23:17:51 2025
From: arnd at arndb.de (Arnd Bergmann)
Date: Tue, 16 Dec 2025 08:17:51 +0100
Subject: [PATCH] arm64: perf: fix syscalltbl path base
In-Reply-To: <20251215164920.GD681384@e132581.arm.com>
References: <b2651f20-6f3a-49f5-9cd8-3fb028b2cab5@app.fastmail.com>
 <fcefc3c0-541d-40cc-84e3-9c2460308bdb@linaro.org>
 <23c07ac4-ff13-47a5-824a-e7af1d1847a3@app.fastmail.com>
 <bda366b4-fa53-4feb-a7ce-ee47cfc404b5@linaro.org>
 <20251215112818.GB681384@e132581.arm.com>
 <0076b248-9b23-408d-9448-701df3c8d952@app.fastmail.com>
 <20251215164920.GD681384@e132581.arm.com>
Message-ID: <67bafe7d-6761-4b1c-8742-628513e7e8bd@app.fastmail.com>

On Mon, Dec 15, 2025, at 17:49, Leo Yan wrote:
> On Mon, Dec 15, 2025 at 01:22:04PM +0100, Arnd Bergmann wrote:
> As discussed in [1], I would prefer to drop these headers, but Ian
> noted that this could break builds with older toolchains.

I didn't find the reference to breaking, do you just mean it
would break when falling back to a header provided by the
toolchain's own asm/unistd.h, or a problem with the modern
generated version that is solved by using the old asm-generic
file?

> Generating the headers dynamically would avoid maintaining duplicated
> copies under tools/ and no need for periodic syncs.  However, this is a
> quite big effort, not just perf, we need to update makefiles to the path
> of the installed headers.  I'd like to hear opinions from tools
> (perf/bpf/selftest) maintainers before proceeding.

I see that we do ship the sources for generating headers on
most architectures in tools/perf/arch/*/entry/syscalls/syscall*.tbl,
the only exceptions being mips-o32, mips-n32 and x86.

I would also point out that s390 no longer needs a custom script
as of 6.19, since the last incompatibility between the s390 format
and the x86 format of the tbl files got resolved with the removal
of the s390 compat mode.

>> or we just stick with
>> the old asm-generic/unistd.h copy and use that on arm64 as well.
>
> I will proceed this way for now.  From a maintenance view, it is a
> pragmatic solution that only requires reverting a few patches and does
> not introduce any new code.

Note that if we ever need to update the
tools/include/uapi/asm-generic/unistd.h file for new syscalls,
that will get harder in the future once we remove the
kernel's own include/uapi/asm-generic/unistd.h. I'm sorry
I never sent that fix after the previous cleanup that introduced
the common script.

     Arnd


From vladimir.zapolskiy at linaro.org  Mon Dec 15 23:21:24 2025
From: vladimir.zapolskiy at linaro.org (Vladimir Zapolskiy)
Date: Tue, 16 Dec 2025 09:21:24 +0200
Subject: [PATCH v7 3/5] arm64: dts: qcom: monaco: Add camera MCLK pinctrl
In-Reply-To: <20251216062223.2474216-4-quic_nihalkum@quicinc.com>
References: <20251216062223.2474216-1-quic_nihalkum@quicinc.com>
 <20251216062223.2474216-4-quic_nihalkum@quicinc.com>
Message-ID: <87815e05-737a-4051-b139-499f388cc144@linaro.org>

On 12/16/25 08:22, Nihal Kumar Gupta wrote:
> Define pinctrl definitions to enable camera master clocks on Monaco.
> 
> Signed-off-by: Nihal Kumar Gupta <quic_nihalkum at quicinc.com>
> Signed-off-by: Vikram Sharma <quic_vikramsa at quicinc.com>
> ---
>   arch/arm64/boot/dts/qcom/monaco.dtsi | 21 +++++++++++++++++++++
>   1 file changed, 21 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/qcom/monaco.dtsi b/arch/arm64/boot/dts/qcom/monaco.dtsi
> index 4b2d8a449b00..ace09239d167 100644
> --- a/arch/arm64/boot/dts/qcom/monaco.dtsi
> +++ b/arch/arm64/boot/dts/qcom/monaco.dtsi
> @@ -5182,6 +5182,27 @@ tlmm: pinctrl at f100000 {
>   			#interrupt-cells = <2>;
>   			wakeup-parent = <&pdc>;
>   
> +			cam0_default: cam0-default-state {
> +				pins = "gpio67";
> +				function = "cam_mclk";
> +				drive-strength = <2>;
> +				bias-disable;
> +			};
> +
> +			cam1_default: cam1-default-state {
> +				pins = "gpio68";
> +				function = "cam_mclk";
> +				drive-strength = <2>;
> +				bias-disable;
> +			};
> +
> +			cam2_default: cam2-default-state {
> +				pins = "gpio69";
> +				function = "cam_mclk";
> +				drive-strength = <2>;
> +				bias-disable;
> +			};
> +
>   			cci0_0_default: cci0-0-default-state {
>   				sda-pins {
>   					pins = "gpio57";

Reviewed-by: Vladimir Zapolskiy <vladimir.zapolskiy at linaro.org>

-- 
Best wishes,
Vladimir


From eugen.hristev at linaro.org  Mon Dec 15 23:27:03 2025
From: eugen.hristev at linaro.org (Eugen Hristev)
Date: Tue, 16 Dec 2025 09:27:03 +0200
Subject: [PATCH 00/26] Introduce meminspect
In-Reply-To: <93682055-4a6d-4098-b74f-afef735d1699@infradead.org>
References: <20251119154427.1033475-1-eugen.hristev@linaro.org>
 <bf00eec5-e9fe-41df-b758-7601815b24a0@linaro.org>
 <5903a8e1-71c6-4546-ac50-35effa078dda@infradead.org>
 <c3db6ccd-dfc7-4a6a-82b7-3d615f8cab4f@linaro.org>
 <b74aef93-9138-413a-8327-36c746d67e10@infradead.org>
 <93682055-4a6d-4098-b74f-afef735d1699@infradead.org>
Message-ID: <93297eb0-1ad4-40ba-9438-ac02aa6b1d6b@linaro.org>



On 12/16/25 09:00, Randy Dunlap wrote:
> 
> 
> On 12/15/25 10:54 PM, Randy Dunlap wrote:
>>
>>
>> On 12/12/25 11:22 PM, Eugen Hristev wrote:
>>>
>>>
>>> On 12/13/25 08:57, Randy Dunlap wrote:
>>>> Hi,
>>>>
>>>> On 12/12/25 10:48 PM, Eugen Hristev wrote:
>>>>>
>>>>>
>>>>> On 11/19/25 17:44, Eugen Hristev wrote:
>>>>>> meminspect is a mechanism which allows the kernel to mark specific memory
>>>>>> areas for memory dumping or specific inspection, statistics, usage.
>>>>>> Once regions are marked, meminspect keeps an internal list with the regions
>>>>>> in a dedicated table.
>>>>>
>>>>> [...]
>>>>>
>>>>>
>>>>>> I will present this version at Plumbers conference in Tokyo on December 13th:
>>>>>> https://lpc.events/event/19/contributions/2080/
>>>>>> I am eager to discuss it there face to face.
>>>>>
>>>>> Summary of the discussions at LPC talk on Dec 13th:
>>>>>
>>>>> One main idea on the static variables annotation was to do some linker
>>>>> magic, to create a list of variables in the tree, that would be parsed
>>>>> by some script, the addresses and sizes would be then stored into the
>>>>> dedicated section at the script level, without having any C code change.
>>>>> Pros: no C code change, Cons: it would be hidden/masked from the code,
>>>>> easy to miss out, which might lead to people's variables being annotated
>>>>> without them knowing
>>>>>
>>>>> Another idea was to have variables directly stored in a dedicated
>>>>> section which would be added to the table.
>>>>> e.g. static int __attribute(section (...)) nr_irqs;
>>>>> Pros: no more meminspect section Cons: have to keep all interesting
>>>>> variables in a separate section, which might not be okay for everyone.
>>>>>
>>>>> On dynamic memory, the memblock flag marking did not receive any obvious
>>>>> NAKs.
>>>>>
>>>>> On dynamic memory that is bigger in size than one page, as the table
>>>>> entries are registered by virtual address, this would be non-contiguous
>>>>> in physical memory. How is this solved?
>>>>> -> At the moment it's left for the consumer drivers to handle this
>>>>> situation. If the region is a VA and the size > PAGE_SIZE, then the
>>>>> driver needs to handle the way it handles it. Maybe the driver that
>>>>> parses the entry needs to convert it into multiple contiguous entries,
>>>>> or just have virtual address is enough. The inspection table does not
>>>>> enforce or limit the entries to contiguous entries only.
>>>>>
>>>>> On the traverse/notifier system, the implementation did not receive any
>>>>> obvious NAKs
>>>>>
>>>>> General comments:
>>>>>
>>>>> Trilok Soni from Qualcomm mentioned they will be using this into their
>>>>> software deliveries in production.
>>>>>
>>>>> Someone suggested to have some mechanism to block specific data from
>>>>> being added to the inspection table as being sensitive non-inspectable
>>>>> data.
>>>>> [Eugen]: Still have to figure out how that could be done. Stuff is not
>>>>> being added to the table by default.
>>>>>
>>>>> Another comment was about what use case there is in mind, is this for
>>>>> servers, or for confidential computing, because each different use case
>>>>> might have different requirements, like ignoring some regions is an
>>>>> option in one case, but bloating the table in another case might not be
>>>>> fine.
>>>>> [Eugen]: The meminspect scenario should cover all cases and not be too
>>>>> specific. If it is generic enough and customizable enough to care for
>>>>> everyone's needs then I consider it being a success. It should not
>>>>> specialize in neither of these two different cases, but rather be
>>>>> tailored by each use case to provide the mandatory requirements for that
>>>>> case.
>>>>>
>>>>> Another comment mentioned that this usecase does not apply to many
>>>>> people due to firmware or specific hardware needed.
>>>>> [Eugen]: one interesting proposed usecase is to have a pstore
>>>>> driver/implementation that would traverse the inspection table at panic
>>>>> handler time, then gather data from there to store in the pstore
>>>>> (ramoops, mtdoops or whatever backend) and have it available to the
>>>>> userspace after reboot. This would be a nice use case that does not
>>>>> require firmware nor specific hardware, just pstore backend support.
>>>>>
>>>>> Ending note was whether this implementation is going in a good direction
>>>>> and what would be the way to having it moving upstream.
>>>>>
>>>>> Thanks everyone who attended and came up with ideas and comments.
>>>>> There are a few comments which I may have missed, so please feel free to
>>>>> reply to this email to start a discussion thread on the topic you are
>>>>> interested in.
>>>>>
>>>>> Eugen
>>>>>
>>>>
>>>> Maybe you or someone else has already mentioned this. If so, sorry I missed it.
>>>>
>>>> How does this compare or contrast to VMCOREINFO?
>>>>
>>>> thanks.
>>>
>>> This inspection table could be created in an VMCOREINFO way, the patch
>>> series here[1] is something that would fit it best .
>>>
>>> The drawbacks are :
>>> some static variables have to be registered to VMCOREINFO in their file
>>> of residence. This means including vmcoreinfo header and adding
>>> functions/code there, and everywhere that would be needed , or , the
>>> variables have to be un-static'ed , which is a no-go.
>>> This received more negative opinions on that particular patch series.
>>> The annotation idea seemed cleaner and simpler, and more generic.
>>>
>>> We could add more and more entries to the vmcoreinfo table, but that
>>> would mean expanding it a lot, which it would maybe defy its purpose,
>>> and be getting too big, especially for the cases where custom drivers
>>> would like to register data.
>>>
>>> How I see it, is that maybe the vmcoreinfo init function, could also
>>> parse the inspection table and create more entries if that is needed.
>>> So somehow memory inspection is a superset or generalization , while
>>> VMCOREINFO is a more particular use case that would fit here.
>>>
>>> Do you think of some better way to integrate the meminspect table into
>>> VMCOREINFO ?
>>
>> No, I just wanted to make sure that you or someone had looked into that.
>> Thanks for your summary.
> 
> Although you copied Stephen Brennan on this, I think it would be a good idea
> to copy the linux-debuggers at vger.kernel.org mailing list also to see if
> there are any other comments about it. [now done]

Thanks . I copied Stephen because we had a discussion at LPC at his talk
and he also attended my talk.

I also had a nice talk with Kees Cook and he was very interested in
having pstore as a backend for meminspect. (copied now as well)

> 
>>> [1]
>>> https://lore.kernel.org/all/20250912150855.2901211-1-eugen.hristev at linaro.org/
>>
> 



From alexander.stein at ew.tq-group.com  Mon Dec 15 23:29:31 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Tue, 16 Dec 2025 08:29:31 +0100
Subject: [PATCH v7 1/3] dt-bindings: soc: imx93-media-blk-ctrl: Add PDFC subnode
 to schema and example
In-Reply-To: <20251215175436.wwlgzxionq55zu27@pengutronix.de>
References: <20251202-v6-18-topic-imx93-parallel-display-v7-0-2cce31d64608@pengutronix.de>
 <705773fc-5aba-4bff-b05e-272e1cd0262c@nxp.com>
 <20251215175436.wwlgzxionq55zu27@pengutronix.de>
Message-ID: <3210190.mvXUDI8C0e@steina-w>

Hi,

Am Montag, 15. Dezember 2025, 18:54:36 CET schrieb Marco Felsch:
> Hi Liu,
> 
> sorry I didn't fully answer you please see below.
> 
> On 25-12-08, Liu Ying wrote:
> > Hi Marco,
> > 
> > On 12/02/2025, Marco Felsch wrote:
> > > From: Liu Ying <victor.liu at nxp.com>
> > > 
> > > i.MX93 SoC mediamix blk-ctrl contains one DISPLAY_MUX register which
> > > configures parallel display format by using the "PARALLEL_DISP_FORMAT"
> > > field. Document the Parallel Display Format Configuration(PDFC) subnode
> > > and add the subnode to example.
> > > 
> > > Signed-off-by: Liu Ying <victor.liu at nxp.com>
> > > [m.felsch at pengutronix.de: port to v6.18-rc1]
> > > [m.felsch at pengutronix.de: add bus-width]
> > > Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
> > > ---
> > >  .../bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml | 92 ++++++++++++++++++++++
> > >  1 file changed, 92 insertions(+)
> > > 
> > > diff --git a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> > > index 34aea58094e55365a2f9c86092f637e533f954ff..6e2d86d9341c75108b492bcbabc8a560d8e707cd 100644
> > > --- a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> > > +++ b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> > > @@ -26,6 +26,12 @@ properties:
> > >    reg:
> > >      maxItems: 1
> 
> ...
> 
> > > +            properties:
> > > +              endpoint:
> > > +                $ref: /schemas/graph.yaml#/$defs/endpoint-base
> > > +                unevaluatedProperties: false
> > > +
> > > +                properties:
> > > +                  bus-width:
> > 
> > In v1-v5, I thought the output bus format can be determined by the sink
> > device(a panel or a bridge) hence properties like bus-width were not needed.
> > But, if this property is really needed, then reference video-interfaces.yaml
> > since bus-width is documented there.  Should we reference bus-type defined
> > in video-interfaces.yaml too?
> 
> You're right, the bus-width should be determined by the connected panel.
> But there are cases where a 24-bit panel is connected but only the lower
> 18-bits are muxed. I added the bus-width property to handle this case.
> In the end most users don't have to specify this since the correct
> bus-width is coming from the panel bus-fmt.
> 
> > > +                    enum: [ 16, 18, 24 ]
> > 
> > The PARALLEL_DISP_FORMAT field of DISPLAY_MUX register says this IP supports
> > below formats.  It seems that the enum here may tell RGB888, RGB666 and RGB565.
> > How can we tell RGB555, YCbCr 24 bits and YUV444 then?
> > 
> > 000b RGB888 -> RGB888
> > 001b RGB888 -> RGB666
> > 010b RGB565 -> RGB565
> > 011b RGB555 -> RGB555
> > 100b YUV -> YCbCr 24 bits
> > 101b YUV -> YUV444
> 
> This enum is about the physical bus width. RGB565 == 16-bit, YUV ==
> 24-bit.
> 
> That said, I don't think that you need to specify the bus-fmt since this
> is coming from the panel. As said above, my itension with the bus-width
> property is to provide integrators (dts-writers) a possibility to limit
> the physical available bus width.

Mh, isn't [1] exactly about this? Not sure about the outcome at that time.

Best regards,
Alexander

[1] https://lore.kernel.org/all/20250304101530.969920-1-victor.liu at nxp.com/

> [snip]
-- 
TQ-Systems GmbH | M?hlstra?e 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht M?nchen, HRB 105018
Gesch?ftsf?hrer: Detlef Schneider, R?diger Stahl, Stefan Schneider
http://www.tq-group.com/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251216/7b527851/attachment-0001.sig>

From ankur.a.arora at oracle.com  Mon Dec 15 23:34:07 2025
From: ankur.a.arora at oracle.com (Ankur Arora)
Date: Mon, 15 Dec 2025 23:34:07 -0800
Subject: [PATCH v8 10/12] bpf/rqspinlock: Use
 smp_cond_load_acquire_timeout()
In-Reply-To: <CAADnVQKYoE85HFAOE5OBFpKbXej=h12m4DVvHuPViJSjAncK4A@mail.gmail.com>
References: <20251215044919.460086-1-ankur.a.arora@oracle.com>
 <20251215044919.460086-11-ankur.a.arora@oracle.com>
 <CAADnVQKYoE85HFAOE5OBFpKbXej=h12m4DVvHuPViJSjAncK4A@mail.gmail.com>
Message-ID: <874ipqc234.fsf@oracle.com>


Alexei Starovoitov <alexei.starovoitov at gmail.com> writes:

> On Sun, Dec 14, 2025 at 8:51?PM Ankur Arora <ankur.a.arora at oracle.com> wrote:
>>
>>  /**
>>   * resilient_queued_spin_lock_slowpath - acquire the queued spinlock
>>   * @lock: Pointer to queued spinlock structure
>> @@ -415,7 +415,9 @@ int __lockfunc resilient_queued_spin_lock_slowpath(rqspinlock_t *lock, u32 val)
>>          */
>>         if (val & _Q_LOCKED_MASK) {
>>                 RES_RESET_TIMEOUT(ts, RES_DEF_TIMEOUT);
>> -               res_smp_cond_load_acquire(&lock->locked, !VAL || RES_CHECK_TIMEOUT(ts, timeout_err, _Q_LOCKED_MASK) < 0);
>> +               smp_cond_load_acquire_timeout(&lock->locked, !VAL,
>> +                                             (timeout_err = clock_deadlock(lock, _Q_LOCKED_MASK, &ts)),
>> +                                             ts.duration);
>
> I'm pretty sure we already discussed this and pointed out that
> this approach is not acceptable.

Where? I don't see any mail on this at all.

In any case your technical point below is quite reasonable. It's better
to lead with that instead of peremptorily declaring what you find
acceptable and what not.

> We cannot call ktime_get_mono_fast_ns() first.
> That's why RES_CHECK_TIMEOUT() exists and it does
> if (!(ts).spin++)
> before doing the first check_timeout() that will do ktime_get_mono_fast_ns().
> Above is a performance critical lock acquisition path where
> pending is spinning on the lock word waiting for the owner to
> release the lock.
> Adding unconditional ktime_get_mono_fast_ns() will destroy
> performance for quick critical section.

Yes that makes sense.

This is not ideal, but how about something like this:

  #define smp_cond_load_relaxed_timeout(ptr, cond_expr,                 \
                                      time_expr_ns, timeout_ns)         \
  ({                                                                    \
        typeof(ptr) __PTR = (ptr);                                      \
        __unqual_scalar_typeof(*ptr) VAL;                               \
        u32 __n = 0, __spin = SMP_TIMEOUT_POLL_COUNT;                   \
        s64 __timeout = (s64)timeout_ns;                                \
        s64 __time_now, __time_end = 0;                                 \
                                                                        \
        for (;;) {                                                      \
                VAL = READ_ONCE(*__PTR);                                \
                if (cond_expr)                                          \
                        break;                                          \
                cpu_poll_relax(__PTR, VAL, __timeout);                  \
                if (++__n < __spin)                                     \
                        continue;                                       \
                __time_now = (s64)(time_expr_ns);                       \
                if (unlikely(__time_end == 0))                          \
                        __time_end = __time_now + __timeout;            \
                __timeout = __time_end - __time_now;                    \
                if (__time_now <= 0 || __timeout <= 0) {                \
                        VAL = READ_ONCE(*__PTR);                        \
                        break;                                          \
                }                                                       \
                __n = 0;                                                \
        }                                                               \
                                                                        \
        (typeof(*ptr))VAL;                                              \
  })

The problem with this version is that there's no way to know how much
time has passed in the first cpu_poll_relax()). So for the waiting case
this has a builtin overshoot of up to __timeout for the WFET case.
And ~100us for WFE and ~2us for x86 cpu_relax.

Of course we could specify a small __timeout value for the first iteration
which would help WFET.

Anyway let me take another look at this tomorrow.

But, that is more complexity.

Opinions?

--
ankur


From alexander.stein at ew.tq-group.com  Mon Dec 15 23:34:18 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Tue, 16 Dec 2025 08:34:18 +0100
Subject: [PATCH v3 2/5] media: nxp: use dev_err_probe() to simplify code
In-Reply-To: <20251215-cam_cleanup-v3-2-a61995068f38@nxp.com>
References: <20251215-cam_cleanup-v3-0-a61995068f38@nxp.com>
 <20251215-cam_cleanup-v3-2-a61995068f38@nxp.com>
Message-ID: <5462566.31r3eYUQgx@steina-w>

Hi,

Am Montag, 15. Dezember 2025, 23:49:53 CET schrieb Frank Li:
> Use dev_err_probe() to simplify the code. Drop the explicit error message
> after returning from imx8mq_mipi_csi_parse_dt(), as the error is already
> reported by this helper.
> 
> No functional change.
> 
> Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> Signed-off-by: Frank Li <Frank.Li at nxp.com>
> ---
> change in v2:
> - add  Laurent Pinchart review tags
> - wrap error message to new line
> - remove error code print in dev_err_probe();
> - drop error messaage at imx8mq_mipi_csi_parse_dt()
> ---
>  drivers/media/platform/nxp/imx-mipi-csis.c    |  6 ++---
>  drivers/media/platform/nxp/imx7-media-csi.c   | 14 ++++--------
>  drivers/media/platform/nxp/imx8mq-mipi-csi2.c | 33 ++++++++++++---------------
>  3 files changed, 21 insertions(+), 32 deletions(-)
> 
> diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c
> index 088b2945aee33731c565f049dd17721356300b84..ce93d868746f002c22e2f86b1e0aa84ec1a76061 100644
> --- a/drivers/media/platform/nxp/imx-mipi-csis.c
> +++ b/drivers/media/platform/nxp/imx-mipi-csis.c
> @@ -1547,10 +1547,8 @@ static int mipi_csis_probe(struct platform_device *pdev)
>  	/* Now that the hardware is initialized, request the interrupt. */
>  	ret = devm_request_irq(dev, irq, mipi_csis_irq_handler, 0,
>  			       dev_name(dev), csis);
> -	if (ret) {
> -		dev_err(dev, "Interrupt request failed\n");
> -		return ret;
> -	}
> +	if (ret)
> +		return dev_err_probe(dev, ret, "Interrupt request failed\n");
>  
>  	/* Initialize and register the subdev. */
>  	ret = mipi_csis_subdev_init(csis);
> diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c
> index 933a5f39f9f4c9b43ca8d2a1819d0145981266e6..7ddc7ba06e3d4e007013821f67d783898a15461f 100644
> --- a/drivers/media/platform/nxp/imx7-media-csi.c
> +++ b/drivers/media/platform/nxp/imx7-media-csi.c
> @@ -2218,11 +2218,9 @@ static int imx7_csi_probe(struct platform_device *pdev)
>  
>  	/* Acquire resources and install interrupt handler. */
>  	csi->mclk = devm_clk_get(&pdev->dev, "mclk");
> -	if (IS_ERR(csi->mclk)) {
> -		ret = PTR_ERR(csi->mclk);
> -		dev_err(dev, "Failed to get mclk: %d", ret);
> -		return ret;
> -	}
> +	if (IS_ERR(csi->mclk))
> +		return dev_err_probe(dev, PTR_ERR(csi->mclk),
> +				     "Failed to get mclk\n");
>  
>  	csi->irq = platform_get_irq(pdev, 0);
>  	if (csi->irq < 0)
> @@ -2236,10 +2234,8 @@ static int imx7_csi_probe(struct platform_device *pdev)
>  
>  	ret = devm_request_irq(dev, csi->irq, imx7_csi_irq_handler, 0, "csi",
>  			       (void *)csi);
> -	if (ret < 0) {
> -		dev_err(dev, "Request CSI IRQ failed.\n");
> -		return ret;
> -	}
> +	if (ret < 0)
> +		return dev_err_probe(dev, ret, "Request CSI IRQ failed.\n");
>  
>  	/* Initialize all the media device infrastructure. */
>  	ret = imx7_csi_media_init(csi);
> diff --git a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
> index 0851f4a9ae52d3096f454da643cfdc5017e000b1..a007c582b4d91660a97910a6a0d53c9b6fcd73e9 100644
> --- a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
> +++ b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
> @@ -951,10 +951,9 @@ static int imx8mq_mipi_csi_parse_dt(struct csi_state *state)
>  	int ret = 0;
>  
>  	state->rst = devm_reset_control_array_get_exclusive(dev);
> -	if (IS_ERR(state->rst)) {
> -		dev_err(dev, "Failed to get reset: %pe\n", state->rst);
> -		return PTR_ERR(state->rst);
> -	}
> +	if (IS_ERR(state->rst))
> +		return dev_err_probe(dev, PTR_ERR(state->rst),
> +				     "Failed to get reset\n");
>  
>  	if (state->pdata->use_reg_csr) {
>  		const struct regmap_config regmap_config = {
> @@ -977,24 +976,22 @@ static int imx8mq_mipi_csi_parse_dt(struct csi_state *state)
>  
>  	ret = of_property_read_u32_array(np, "fsl,mipi-phy-gpr", out_val,
>  					 ARRAY_SIZE(out_val));
> -	if (ret) {
> -		dev_err(dev, "no fsl,mipi-phy-gpr property found: %d\n", ret);
> -		return ret;
> -	}
> +	if (ret)
> +		return dev_err_probe(dev, ret, "no %s property found\n",
> +				    "fsl,mipi-phy-gpr");

Do you really need to pass the (fixed) property name as an argument? Why
not move into the const string directly? I would also rephrase it a bit:
"property fsl,mipi-phy-gpr not found"

With that fixed:
Reviewed-by: Alexander Stein <alexander.stein at ew.tq-group.com>

>  
>  	ph = *out_val;
>  
>  	node = of_find_node_by_phandle(ph);
> -	if (!node) {
> -		dev_err(dev, "Error finding node by phandle\n");
> -		return -ENODEV;
> -	}
> +	if (!node)
> +		return dev_err_probe(dev, -ENODEV,
> +				     "Error finding node by phandle\n");
> +
>  	state->phy_gpr = syscon_node_to_regmap(node);
>  	of_node_put(node);
> -	if (IS_ERR(state->phy_gpr)) {
> -		dev_err(dev, "failed to get gpr regmap: %pe\n", state->phy_gpr);
> -		return PTR_ERR(state->phy_gpr);
> -	}
> +	if (IS_ERR(state->phy_gpr))
> +		return dev_err_probe(dev, PTR_ERR(state->phy_gpr),
> +				     "failed to get gpr regmap\n");
>  
>  	state->phy_gpr_reg = out_val[1];
>  	dev_dbg(dev, "phy gpr register set to 0x%x\n", state->phy_gpr_reg);
> @@ -1017,10 +1014,8 @@ static int imx8mq_mipi_csi_probe(struct platform_device *pdev)
>  	state->pdata = of_device_get_match_data(dev);
>  
>  	ret = imx8mq_mipi_csi_parse_dt(state);
> -	if (ret < 0) {
> -		dev_err(dev, "Failed to parse device tree: %d\n", ret);
> +	if (ret < 0)
>  		return ret;
> -	}
>  
>  	/* Acquire resources. */
>  	state->regs = devm_platform_ioremap_resource(pdev, 0);
> 
> 


-- 
TQ-Systems GmbH | M?hlstra?e 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht M?nchen, HRB 105018
Gesch?ftsf?hrer: Detlef Schneider, R?diger Stahl, Stefan Schneider
http://www.tq-group.com/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251216/e226f413/attachment-0001.sig>

From vladimir.zapolskiy at linaro.org  Mon Dec 15 23:35:55 2025
From: vladimir.zapolskiy at linaro.org (Vladimir Zapolskiy)
Date: Tue, 16 Dec 2025 09:35:55 +0200
Subject: [PATCH v7 5/5] arm64: dts: qcom: monaco-evk-camera: Add DT
 overlay
In-Reply-To: <20251216062223.2474216-6-quic_nihalkum@quicinc.com>
References: <20251216062223.2474216-1-quic_nihalkum@quicinc.com>
 <20251216062223.2474216-6-quic_nihalkum@quicinc.com>
Message-ID: <5bd29b5f-6fcf-428d-b451-698d92f0883e@linaro.org>

On 12/16/25 08:22, Nihal Kumar Gupta wrote:
> Monaco EVK board does not include a camera sensor in its default hardware
> configuration. Introducing a device tree overlay to support optional
> integration of the IMX577 sensor via CSIPHY1.
> 
> Camera reset is handled through an I2C expander, and power is enabled
> via TLMM GPIO74.
> 
> An example media-ctl pipeline for the imx577 is:
> 
> media-ctl --reset
> media-ctl -V '"imx577 3-001a":0[fmt:SRGGB10/4056x3040 field:none]'
> media-ctl -V '"msm_csiphy1":0[fmt:SRGGB10/4056x3040]'
> media-ctl -V '"msm_csid0":0[fmt:SRGGB10/4056x3040]'
> media-ctl -V '"msm_vfe0_rdi0":0[fmt:SRGGB10/4056x3040]'
> media-ctl -l '"msm_csiphy1":1->"msm_csid0":0[1]'
> media-ctl -l '"msm_csid0":1->"msm_vfe0_rdi0":0[1]'
> yavta -B capture-mplane -c -I -n 5 -f SRGGB10P -s 4056x3040 -F /dev/video1
> 
> Signed-off-by: Nihal Kumar Gupta <quic_nihalkum at quicinc.com>
> Co-developed-by: Ravi Shankar <quic_rshankar at quicinc.com>
> Signed-off-by: Ravi Shankar <quic_rshankar at quicinc.com>
> Co-developed-by: Vishal Verma <quic_vishverm at quicinc.com>
> Signed-off-by: Vishal Verma <quic_vishverm at quicinc.com>
> Signed-off-by: Vikram Sharma <quic_vikramsa at quicinc.com>
> Reviewed-by: Vladimir Zapolskiy <vladimir.zapolskiy at linaro.org>
> Reviewed-by: Bryan O'Donoghue <bryan.odonoghue at linaro.org>
> ---
>   arch/arm64/boot/dts/qcom/Makefile             |  4 ++
>   .../dts/qcom/monaco-evk-camera-imx577.dtso    | 67 +++++++++++++++++++
>   2 files changed, 71 insertions(+)
>   create mode 100644 arch/arm64/boot/dts/qcom/monaco-evk-camera-imx577.dtso
> 
> diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
> index 6f34d5ed331c..b1ba182a0d8d 100644
> --- a/arch/arm64/boot/dts/qcom/Makefile
> +++ b/arch/arm64/boot/dts/qcom/Makefile
> @@ -38,6 +38,10 @@ lemans-evk-camera-dtbs	:= lemans-evk.dtb lemans-evk-camera.dtbo
>   dtb-$(CONFIG_ARCH_QCOM)	+= lemans-evk-camera-csi1-imx577.dtb
>   dtb-$(CONFIG_ARCH_QCOM)	+= lemans-evk-camera.dtb
>   dtb-$(CONFIG_ARCH_QCOM)	+= monaco-evk.dtb
> +
> +monaco-evk-camera-imx577-dtbs	:= monaco-evk.dtb monaco-evk-camera-imx577.dtbo
> +dtb-$(CONFIG_ARCH_QCOM)	+= monaco-evk-camera-imx577.dtb
> +
>   dtb-$(CONFIG_ARCH_QCOM)	+= msm8216-samsung-fortuna3g.dtb
>   dtb-$(CONFIG_ARCH_QCOM)	+= msm8916-acer-a1-724.dtb
>   dtb-$(CONFIG_ARCH_QCOM)	+= msm8916-alcatel-idol347.dtb
> diff --git a/arch/arm64/boot/dts/qcom/monaco-evk-camera-imx577.dtso b/arch/arm64/boot/dts/qcom/monaco-evk-camera-imx577.dtso
> new file mode 100644
> index 000000000000..351eb5ee70ba
> --- /dev/null
> +++ b/arch/arm64/boot/dts/qcom/monaco-evk-camera-imx577.dtso
> @@ -0,0 +1,67 @@
> +// SPDX-License-Identifier: BSD-3-Clause
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.

Year is missing.

> + */
> +
> +/dts-v1/;
> +/plugin/;
> +
> +#include <dt-bindings/clock/qcom,sa8775p-camcc.h>
> +#include <dt-bindings/gpio/gpio.h>
> +
> +&camss {
> +	vdda-phy-supply = <&vreg_l4a>;
> +	vdda-pll-supply = <&vreg_l5a>;
> +
> +	status = "okay";
> +
> +	ports {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		port at 1 {
> +			reg = <1>;
> +
> +			csiphy1_ep: endpoint {
> +				clock-lanes = <7>;

Please remove 'clock-lanes' property here.

> +				data-lanes = <0 1 2 3>;
> +				remote-endpoint = <&imx577_ep1>;
> +			};
> +		};
> +	};
> +};
> +
> +&cci1 {
> +	pinctrl-0 = <&cci1_0_default>;
> +	pinctrl-1 = <&cci1_0_sleep>;
> +
> +	status = "okay";
> +};
> +
> +&cci1_i2c0 {
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +
> +	camera at 1a {
> +		compatible = "sony,imx577";
> +		reg = <0x1a>;
> +
> +		reset-gpios = <&expander2 1 GPIO_ACTIVE_LOW>;
> +		pinctrl-0 = <&cam1_default>;
> +		pinctrl-names = "default";
> +
> +		clocks = <&camcc CAM_CC_MCLK1_CLK>;
> +		assigned-clocks = <&camcc CAM_CC_MCLK1_CLK>;
> +		assigned-clock-rates = <24000000>;
> +
> +		avdd-supply = <&vreg_cam1_2p8>;
> +
> +		port {
> +			imx577_ep1: endpoint {
> +				link-frequencies = /bits/ 64 <600000000>;
> +				data-lanes = <0 1 2 3>;

data-lanes property value should be '1 2 3 4>', 0 is for the clock lane.

On CAMSS side this cannot be changed, unfortunately it's a lingering issue.

> +				remote-endpoint = <&csiphy1_ep>;
> +			};
> +		};
> +	};
> +};

If only one of 3 defined from 4/5 regulators is used, do you really wish
to describle all 3 in advance? You may consider to remove 2 currently unused
GPIO controlled regulator descriptions, and squash this change with 4/5.

-- 
Best wishes,
Vladimir


From sumit.garg at oss.qualcomm.com  Mon Dec 15 23:38:38 2025
From: sumit.garg at oss.qualcomm.com (Sumit Garg)
Date: Tue, 16 Dec 2025 13:08:38 +0530
Subject: [PATCH v1 00/17] tee: Use bus callbacks instead of driver callbacks
In-Reply-To: <dhunzydod4d7vj73llpuqemxb5er2ja4emxusr66irwf77jhhb@es4yd2axzl25>
References: <cover.1765472125.git.u.kleine-koenig@baylibre.com>
 <aT--ox375kg2Mzh-@sumit-X1> <dhunzydod4d7vj73llpuqemxb5er2ja4emxusr66irwf77jhhb@es4yd2axzl25>
Message-ID: <CAGptzHOOqLhBnAXDURAzkgckUvRr__UuF1S_7MLV0u-ZxYEdyA@mail.gmail.com>

Hi Uwe,

On Mon, Dec 15, 2025 at 3:02?PM Uwe Kleine-K?nig
<u.kleine-koenig at baylibre.com> wrote:
>
> Hello Sumit,
>
> On Mon, Dec 15, 2025 at 04:54:11PM +0900, Sumit Garg wrote:
> > On Thu, Dec 11, 2025 at 06:14:54PM +0100, Uwe Kleine-K?nig wrote:
> > > Hello,
> > >
> > > the objective of this series is to make tee driver stop using callbacks
> > > in struct device_driver. These were superseded by bus methods in 2006
> > > (commit 594c8281f905 ("[PATCH] Add bus_type probe, remove, shutdown
> > > methods.")) but nobody cared to convert all subsystems accordingly.
> > >
> > > Here the tee drivers are converted. The first commit is somewhat
> > > unrelated, but simplifies the conversion (and the drivers). It
> > > introduces driver registration helpers that care about setting the bus
> > > and owner. (The latter is missing in all drivers, so by using these
> > > helpers the drivers become more correct.)
> > >
> > > The patches #4 - #17 depend on the first two, so if they should be
> > > applied to their respective subsystem trees these must contain the first
> > > two patches first.
> >
> > Thanks Uwe for your efforts to clean up the boilerplate code for TEE bus
> > drivers.
>
> Thanks for your feedback. I will prepare a v2 and address your comments
> (whitespace issues and wrong callback in the shutdown method).
>
> > > Note that after patch #2 is applied, unconverted drivers provoke a
> > > warning in driver_register(), so it would be good for the user
> > > experience if the whole series goes in during a single merge window.
> >
> > +1
> >
> > I suggest the whole series goes via the Jens tree since there shouldn't
> > be any chances for conflict here.
> >
> > > So
> > > I guess an immutable branch containing the frist three patches that can
> > > be merged into the other subsystem trees would be sensible.
> > >
> > > After all patches are applied, tee_bus_type can be made private to
> > > drivers/tee as it's not used in other places any more.
> > >
> >
> > Feel free to make the tee_bus_type private as the last patch in the series
> > such that any followup driver follows this clean approach.
>
> There is a bit more to do for that than I'm willing to invest. With my
> patch series applied `tee_bus_type` is still used in
> drivers/tee/optee/device.c and drivers/tee/tee_core.c.

Oh I see, I guess we need to come with some helpers around device
register/unregister from TEE subsystem as well. Let's plan that for a
followup patch-set, I don't want this patch-set to be bloated more.

> Maybe it's
> sensible to merge these two files into a single one.

It's not possible as the design for TEE bus is to have TEE
implementation drivers like OP-TEE, AMD-TEE, TS-TEE, QTEE and so on to
register devices on the bus.

>
> The things I wonder about additionally are:
>
>  - if CONFIG_OPTEE=n and CONFIG_TEE=y|m the tee bus is only used for
>    drivers but not devices.

Yeah since the devices are rather added by the TEE implementation driver.

>
>  - optee_register_device() calls device_create_file() on
>    &optee_device->dev after device_register(&optee_device->dev).
>    (Attention half-knowledge!) I think device_create_file() should not
>    be called on an already registered device (or you have to send a
>    uevent afterwards). This should probably use type attribute groups.
>    (Or the need_supplicant attribute should be dropped as it isn't very
>    useful. This would maybe be considered an ABI change however.)

The reasoning for this attribute should be explained by commit:
7269cba53d90 ("tee: optee: Fix supplicant based device enumeration").
In summary it's due to a weird dependency for devices we have with the
user-space daemon: tee-supplicant.

>
>  - Why does optee_probe() in drivers/tee/optee/smc_abi.c unregister all
>    optee devices in its error path (optee_unregister_devices())?

This is mostly to take care of if any device got registered before the
failure occured. Let me know if you have a better way to address that.

-Sumit


From shengjiu.wang at nxp.com  Mon Dec 15 23:42:16 2025
From: shengjiu.wang at nxp.com (Shengjiu Wang)
Date: Tue, 16 Dec 2025 15:42:16 +0800
Subject: [PATCH] remoteproc: imx_dsp_rproc: only reset carveout memory at RPROC_OFFLINE state
Message-ID: <20251216074216.447193-1-shengjiu.wang@nxp.com>

Don't need to reset memory at suspend and resume stage, because some
memory is used to save the software state for resume, if it is cleared,
the resume operation can fail.

Fixes: c4c432dfb00f ("remoteproc: imx_dsp_rproc: Add support of recovery and coredump process")
Signed-off-by: Shengjiu Wang <shengjiu.wang at nxp.com>
---
 drivers/remoteproc/imx_dsp_rproc.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c
index d03017d6b214..ac8aa71aa56c 100644
--- a/drivers/remoteproc/imx_dsp_rproc.c
+++ b/drivers/remoteproc/imx_dsp_rproc.c
@@ -984,9 +984,11 @@ static int imx_dsp_rproc_load(struct rproc *rproc, const struct firmware *fw)
 	 * Clear buffers after pm rumtime for internal ocram is not
 	 * accessible if power and clock are not enabled.
 	 */
-	list_for_each_entry(carveout, &rproc->carveouts, node) {
-		if (carveout->va)
-			memset(carveout->va, 0, carveout->len);
+	if (rproc->state == RPROC_OFFLINE) {
+		list_for_each_entry(carveout, &rproc->carveouts, node) {
+			if (carveout->va)
+				memset(carveout->va, 0, carveout->len);
+		}
 	}
 
 	ret = imx_dsp_rproc_elf_load_segments(rproc, fw);
-- 
2.34.1



From dan.carpenter at linaro.org  Mon Dec 15 23:56:02 2025
From: dan.carpenter at linaro.org (Dan Carpenter)
Date: Tue, 16 Dec 2025 10:56:02 +0300
Subject: [PATCH v2 0/4] s32g: Use a syscon for GPR
In-Reply-To: <aUB4pFEwmMBzW52T@lizhi-Precision-Tower-5810>
References: <cover.1765806521.git.dan.carpenter@linaro.org>
 <aUAvwRmIZBC0W6ql@lizhi-Precision-Tower-5810>
 <aUBUkuLf7NHtLSl1@stanley.mountain>
 <aUBha2/xiZsIF/o5@lizhi-Precision-Tower-5810>
 <aUBrV2_Iv4oTPkC4@stanley.mountain>
 <aUB4pFEwmMBzW52T@lizhi-Precision-Tower-5810>
Message-ID: <aUEQkuzSZXFs5nqr@stanley.mountain>

On Mon, Dec 15, 2025 at 04:07:48PM -0500, Frank Li wrote:
> On Mon, Dec 15, 2025 at 11:11:03PM +0300, Dan Carpenter wrote:
> > On Mon, Dec 15, 2025 at 02:28:43PM -0500, Frank Li wrote:
> > > On Mon, Dec 15, 2025 at 09:33:54PM +0300, Dan Carpenter wrote:
> > > > On Mon, Dec 15, 2025 at 10:56:49AM -0500, Frank Li wrote:
> > > > > On Mon, Dec 15, 2025 at 05:41:43PM +0300, Dan Carpenter wrote:
> > > > > > The s32g devices have a GPR register region which holds a number of
> > > > > > miscellaneous registers.  Currently only the stmmac/dwmac-s32.c uses
> > > > > > anything from there and we just add a line to the device tree to
> > > > > > access that GMAC_0_CTRL_STS register:
> > > > > >
> > > > > >                         reg = <0x4033c000 0x2000>, /* gmac IP */
> > > > > >                               <0x4007c004 0x4>;    /* GMAC_0_CTRL_STS */
> > > > > >
> > > > > > We still have to maintain backwards compatibility to this format,
> > > > > > of course, but it would be better to access these through a syscon.
> > > > > > First of all, putting all the registers together is more organized
> > > > > > and shows how the hardware actually is implemented.  Secondly, in
> > > > > > some versions of this chipset those registers can only be accessed
> > > > > > via SCMI, if the registers aren't grouped together each driver will
> > > > > > have to create a whole lot of if then statements to access it via
> > > > > > IOMEM or via SCMI,
> > > > >
> > > > > Does SCMI work as regmap? syscon look likes simple, but missed abstract
> > > > > in overall.
> > > > >
> > > >
> > > > The SCMI part of this is pretty complicated and needs discussion.  It
> > > > might be that it requires a vendor extension.  Right now, the out of
> > > > tree code uses a nvmem vendor extension but that probably won't get
> > > > merged upstream.
> > > >
> > > > But in theory, it's fairly simple, you can write a regmap driver and
> > > > register it as a syscon and everything that was accessing nxp,phy-sel
> > > > accesses the same register but over SCMI.
> > >
> > > nxp,phy-sel is not standard API. Driver access raw register value. such
> > > as write 1 to offset 0x100.
> > >
> > > After change to SCMI, which may mapped to difference command. Even change
> > > to other SOC, value and offset also need be changed. It is not standilzed
> > > as what you expected.
> >
> > We're writing to an offset in a syscon.  Right now the device tree
> > says that the syscon is an MMIO syscon.  But for SCMI devices we
> > would point the phandle to a custom syscon.  The phandle and the offset
> > would stay the same, but how the syscon is implemented would change.
> 
> Your SCMI syscon driver will convert some private hard code to some
> function, such previous example's '1' as SEL_RGMII. It is hard maintained
> in long term.
> 

No, there isn't any conversion needed.  It's exactly the same as writing
to the register except it goes through SCMI.

> >
> > >
> > > >
> > > > > You still use regmap by use MMIO. /* GMAC_0_CTRL_STS */
> > > > >
> > > > > regmap = devm_regmap_init_mmio(dev, sts_offset, &regmap_config);
> > > > >
> > > >
> > > > You can use have an MMIO syscon, or you can create a custom driver
> > > > and register it as a syscon using of_syscon_register_regmap().
> > >
> > > My means is that it is not necessary to create nxp,phy-sel, especially
> > > there already have <0x4007c004 0x4>;    /* GMAC_0_CTRL_STS */
> > >
> >
> > Right now the out of tree dwmac-s32cc.c driver does something like
> > this:
> >
> >     89          if (gmac->use_nvmem) {
> >     90                  ret = write_nvmem_cell(gmac->dev, "gmac_phy_intf_sel", intf_sel);
> >     91                  if (ret)
> >     92                          return ret;
> >     93          } else {
> >     94                  writel(intf_sel, gmac->ctrl_sts);
> >     95          }
> >
> > Which is quite complicated, but with a syscon, then it's just:
> >
> > 	regmap_write(gmac->sts_regmap, gmac->sts_offset, S32_PHY_INTF_SEL_RGMII);
> >
> > Even without SCMI, the hardware has all these registers grouped together
> > it just feels cleaner to group them together in the device tree as well.
> 
> Why not implement standard phy interface,
> phy_set_mode_ext(PHY_MODE_ETHERNET, RGMII);
> 
> For example:  drivers/pci/controller/dwc/pci-imx6.c
> 
> In legency platform, it use syscon to set some registers. It becomes mess
> when more platform added.  And it becomes hard to convert because avoid
> break compatibltiy now.
> 
> It doesn't become worse since new platforms switched to use standard
> inteface, (phy, reset ...).
> 

This happens below that layer, this is just saying where the registers
are found.  The GMAC_0_CTRL_STS is just one register in the GPR region,
most of the others are unrelated to PHY.

regards,
dan carpenter



From ping.bai at nxp.com  Tue Dec 16 00:00:54 2025
From: ping.bai at nxp.com (Jacky Bai)
Date: Tue, 16 Dec 2025 16:00:54 +0800
Subject: [PATCH] mailbox: imx: Skip the suspend flag for i.MX7ULP
Message-ID: <20251216-imx7ulp_mailbox-v1-1-66b5bbcd3005@nxp.com>

In current imx-mailbox driver, the MU IRQ is configured with
'IRQF_NO_SUSPEND' flag set. So during linux suspend/resume flow,
the MU IRQ is always enabled. With commit 892cb524ae8a ("mailbox: imx:
fix wakeup failure from freeze mode"), if the MU IRQ is triggered after
the priv->suspended flag has been set, the system suspend will be
aborted.

On i.MX7ULP platform, certain drivers that depend on rpmsg may need
to send rpmsg request and receive an acknowledgment from the remote
core during the late_suspend stage. Early suspend abort is not
expected, and the i.MX7ULP already has additional hardware and
software to make sure the system can be wakeup from freeze mode
correctly when MU IRQ is trigger.

Skip the 'suspend' flag handling logic on i.MX7ULP to avoid the
early abort when doing suspend.

Signed-off-by: Jacky Bai <ping.bai at nxp.com>
---
 drivers/mailbox/imx-mailbox.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
index 6778afc64a048c70a3afbdf44783ede0d1626937..003f9236c35e0943441b5e3cb01569451d7d0a96 100644
--- a/drivers/mailbox/imx-mailbox.c
+++ b/drivers/mailbox/imx-mailbox.c
@@ -122,6 +122,7 @@ struct imx_mu_dcfg {
 	u32	xRR;		/* Receive Register0 */
 	u32	xSR[IMX_MU_xSR_MAX];	/* Status Registers */
 	u32	xCR[IMX_MU_xCR_MAX];	/* Control Registers */
+	bool	skip_suspend_flag;
 };
 
 #define IMX_MU_xSR_GIPn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(28 + (3 - (x))))
@@ -988,6 +989,7 @@ static const struct imx_mu_dcfg imx_mu_cfg_imx7ulp = {
 	.xRR	= 0x40,
 	.xSR	= {0x60, 0x60, 0x60, 0x60},
 	.xCR	= {0x64, 0x64, 0x64, 0x64, 0x64},
+	.skip_suspend_flag = true,
 };
 
 static const struct imx_mu_dcfg imx_mu_cfg_imx8ulp = {
@@ -1071,7 +1073,8 @@ static int __maybe_unused imx_mu_suspend_noirq(struct device *dev)
 			priv->xcr[i] = imx_mu_read(priv, priv->dcfg->xCR[i]);
 	}
 
-	priv->suspend = true;
+	if (!priv->dcfg->skip_suspend_flag)
+		priv->suspend = true;
 
 	return 0;
 }
@@ -1094,7 +1097,8 @@ static int __maybe_unused imx_mu_resume_noirq(struct device *dev)
 			imx_mu_write(priv, priv->xcr[i], priv->dcfg->xCR[i]);
 	}
 
-	priv->suspend = false;
+	if (!priv->dcfg->skip_suspend_flag)
+		priv->suspend = false;
 
 	return 0;
 }

---
base-commit: 563c8dd425b59e44470e28519107b1efc99f4c7b
change-id: 20251216-imx7ulp_mailbox-9dd35bb9b94d

Best regards,
-- 
Jacky Bai <ping.bai at nxp.com>



From ardb at kernel.org  Tue Dec 16 00:15:21 2025
From: ardb at kernel.org (Ard Biesheuvel)
Date: Tue, 16 Dec 2025 09:15:21 +0100
Subject: [PATCH] crypto: arm64/ghash - Fix incorrect output from ghash-neon
In-Reply-To: <20251215201611.GB10539@google.com>
References: <DETXT7QI62KE.F3CGH2VWX1SC@cknow-tech.com> <20251209223417.112294-1-ebiggers@kernel.org>
 <DEUFDH7FJURL.3J0FN5I19VV8F@cknow-tech.com> <CAMj1kXEQkB9MWB+PAi4XE_MuBt0ScitxTsKMDo1-7Cp-=xXOpw@mail.gmail.com>
 <20251212054020.GB4838@sol> <CAMj1kXHVq1NWA28jKxBrHHi1JOPoGXEamC7uMgTOmFwzmcYxRA@mail.gmail.com>
 <20251215201611.GB10539@google.com>
Message-ID: <CAMj1kXGQvjcN7gEH_fsxQ-0KW7_Mj93i0LQ8aT6WQTCPiMMcQA@mail.gmail.com>

On Mon, 15 Dec 2025 at 21:16, Eric Biggers <ebiggers at kernel.org> wrote:
>
> On Mon, Dec 15, 2025 at 04:54:34PM +0900, Ard Biesheuvel wrote:
> > > > All 64-bit RPi models except the RPi5 are affected by this, as those
> > > > do not implement the crypto extensions. So I would expect QEMU to do
> > > > the same.
> > > >
> > > > It would be nice, though, if we could emulate this on the mach-virt
> > > > machine model too. It should be fairly trivial to do, so if there is
> > > > demand for this I can look into it.
> > >
> > > I'm definitely interested in it.  I'm already testing multiple "-cpu"
> > > options, and it's easy to add more.
> > >
> > > With qemu-system-aarch64 I'm currently only using "-M virt", since the
> > > other machine models I've tried don't boot with arm64 defconfig,
> > > including "-M raspi3b" and "-M raspi4b".
> > >
> > > There may be some tricks I'm missing.  Regardless, expanding the
> > > selection of available CPUs for "-M virt" would be helpful.  Either by
> > > adding "real" CPUs that have "interesting" combinations of features, or
> > > by just allowing turning features off like
> > > "-cpu max,aes=off,pmull=off,sha256=off".  (Certain features like sve can
> > > already be turned off in that way, but not the ones relevant to us.)
> > >
> >
> > There are some architectural rules around which combinations of crypto
> > extensions are permitted:
> > - PMULL implies AES, and there is no way for the ID registers to
> > describe a CPU that has PMULL but not AES
> > - SHA256 implies SHA1 (but the ID register fields are independent)
> > - SHA3 and SHA512 both imply SHA256+SHA1
> > - SVE versions are not allowed to be implemented unless the plain NEON
> > version is implemented as well
> > -  FEAT_Crypto has different meanings for v8.0, v8.2 and v9.x
> >
> > So it would be much easier, also in terms of future maintenance, to
> > have a simple 'crypto=off' setting that applies to all emulated CPU
> > models, given that disabling all crypto on any given compliant CPU
> > will never result in something that the architecture does not permit.
> >
> > Would that work for you?
>
> I thought it had been established that the "crypto" grouping of features
> (as implemented by gcc and clang) doesn't reflect the actual hardware
> feature fields and is misleading because additional crypto extensions
> continue to be added.
>
> I'm not sure that applies here, but just something to consider.
>

You are right, this is why 'crypto=on' can never mean anything other
than 'do not disable the crypto extensions that this particular CPU
type provides' But that does not mean 'crypto=off' is equally
problematic.

> There's certainly no need to support emulating combinations of features
> that no hardware actually implements.  So yes, if that means "crypto" is
> the right choice, that sounds fine.
>

OK, I'll have a stab at that and cc you on the patches.


From maudspierings at gocontroll.com  Tue Dec 16 00:19:40 2025
From: maudspierings at gocontroll.com (Maud Spierings)
Date: Tue, 16 Dec 2025 09:19:40 +0100
Subject: [PATCH v6 1/4] dt-bindings: backlight: Add max25014 support
In-Reply-To: <20251209190722.GA945742-robh@kernel.org>
References: <20251201-max25014-v6-0-88e3ac8112ff@gocontroll.com>
 <20251201-max25014-v6-1-88e3ac8112ff@gocontroll.com>
 <aS3H1qzSMKHamqpP@lizhi-Precision-Tower-5810>
 <b9fe6df7-fdc6-4a32-919b-8f3b44eace7d@gocontroll.com>
 <aS79eKc9Ac4np6Nf@lizhi-Precision-Tower-5810>
 <e428c3a9-49e2-4af5-b597-2cdfef7028f5@gocontroll.com>
 <20251209190722.GA945742-robh@kernel.org>
Message-ID: <d1d83ca2-d856-4e30-b53f-6b601a287768@gocontroll.com>

On 12/9/25 20:07, Rob Herring wrote:
> On Mon, Dec 08, 2025 at 02:56:50PM +0100, Maud Spierings wrote:
>> On 12/2/25 15:53, Frank Li wrote:
>>> On Tue, Dec 02, 2025 at 08:46:21AM +0100, Maud Spierings wrote:
>>>> On 12/1/25 17:52, Frank Li wrote:
>>>>> On Mon, Dec 01, 2025 at 12:53:20PM +0100, Maud Spierings via B4 Relay wrote:
>>>>>> From: Maud Spierings <maudspierings at gocontroll.com>
>>>>>>
>>>>>> The Maxim MAX25014 is a 4-channel automotive grade backlight driver IC
>>>>>> with integrated boost controller.
>>>>>>
>>>>>> Signed-off-by: Maud Spierings <maudspierings at gocontroll.com>
>>>>>>
>>>>>> ---
>>>>>>
>>>>>> In the current implementation the control registers for channel 1,
>>>>>> control all channels. So only one led subnode with led-sources is
>>>>>> supported right now. If at some point the driver functionality is
>>>>>> expanded the bindings can be easily extended with it.
>>>>>> ---
>>>>>>     .../bindings/leds/backlight/maxim,max25014.yaml    | 107 +++++++++++++++++++++
>>>>>>     MAINTAINERS                                        |   5 +
>>>>>>     2 files changed, 112 insertions(+)
>>>>>>
>>>>>> diff --git a/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml b/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
>>>>>> new file mode 100644
>>>>>> index 000000000000..e83723224b07
>>>>>> --- /dev/null
>>>>>> +++ b/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
>>>>>> @@ -0,0 +1,107 @@
>>>>>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>>>>>> +%YAML 1.2
>>>>>> +---
>>>>>> +$id: http://devicetree.org/schemas/leds/backlight/maxim,max25014.yaml#
>>>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>>>>> +
>>>>>> +title: Maxim max25014 backlight controller
>>>>>> +
>>>>>> +maintainers:
>>>>>> +  - Maud Spierings <maudspierings at gocontroll.com>
>>>>>> +
>>>>>> +properties:
>>>>>> +  compatible:
>>>>>> +    enum:
>>>>>> +      - maxim,max25014
>>>>>> +
>>>>>> +  reg:
>>>>>> +    maxItems: 1
>>>>>> +
>>>>>> +  "#address-cells":
>>>>>> +    const: 1
>>>>>> +
>>>>>> +  "#size-cells":
>>>>>> +    const: 0
>>>>>> +
>>>>>> +  enable-gpios:
>>>>>> +    maxItems: 1
>>>>>> +
>>>>>> +  interrupts:
>>>>>> +    maxItems: 1
>>>>>> +
>>>>>> +  power-supply:
>>>>>> +    description: Regulator which controls the boost converter input rail.
>>>>>> +
>>>>>> +  pwms:
>>>>>> +    maxItems: 1
>>>>>> +
>>>>>> +  maxim,iset:
>>>>>> +    $ref: /schemas/types.yaml#/definitions/uint32
>>>>>> +    maximum: 15
>>>>>> +    default: 11
>>>>>> +    description:
>>>>>> +      Value of the ISET field in the ISET register. This controls the current
>>>>>> +      scale of the outputs, a higher number means more current.
>>>>>> +
>>>>>> +  led at 0:
>>>>>
>>>>> define whole binding, allow 0-3. binding is not related with driver's
>>>>> implement.
>>>>>
>>>>> it'd better put unders leds.
>>>>>
>>>>
>>>> so like:
>>>>
>>>> backlight: backlight at 6f {
>>>> 	compatible = "maxim,max25014";
>>>> 	reg = <0x6f>;
>>>> 	enable-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
>>>> 	pinctrl-names = "default";
>>>> 	pinctrl-0 = <&pinctrl_backlight>;
>>>> 	maxim,iset = <7>;
>>>>
>>>> 	leds {
>>>> 		#address-cells = <1>;
>>>> 		#size-cells = <0>;
>>>>
>>>> 		led at 0 {
>>>> 			reg = <0>;
>>>> 			led-sources = <0 1 2>;
>>>> 			default-brightness = <50>;
>>>> 		};
>>>>
>>>> 		optional led@#....
>>>> 	};
>>>> };
>>>>
>>>> right?
>>>
>>> yes.
>>>
>>
>> I am feeling a bit weird about these led sub nodes, because it is not
>> programmed as a led driver, it is programmed as a backlight. I am trying to
>> figure out how this would be used later when the led strings are
>> individually controllable.
>>
>> it isn't possible to link the seperate strings to different displays because
>> it is only one backlight device, so I don't seen any reason why it would
>> ever be used in another way than what it is now, were all strings are
>> programmed by one register.
>>
>> The only way I can make sense of it is if instead I program this device as a
>> led driver and then use the led_bl driver as the actual backlight.
>>
>> Thats a pretty big step in a different direction, but then the led subnodes
>> at least can be properly used I feel.
> 
> If you don't have any use for anything other than driving a single
> backlight, then I'd just drop the led nodes completely.

Theoretically with how the registers are laid out, it should be able to 
control 4 led strings individually. But as I said when I configure led 
string 1 it will also affect all the others seemingly. I am not sure if 
with some other configuration you can indeed do individual control.

Before I start converting stuff back to how it was several versions ago. 
Frank, do you agree with removing the led nodes in this case? I don't 
want to get stuck between two different paths.

Kind regards,
Maud



From maudspierings at gocontroll.com  Tue Dec 16 00:22:28 2025
From: maudspierings at gocontroll.com (Maud Spierings)
Date: Tue, 16 Dec 2025 09:22:28 +0100
Subject: [PATCH v4 0/5] arm64: dts: freescale: add support for the
 GOcontroll Moduline IV/Mini
In-Reply-To: <20251117-mini_iv-v4-0-5aa63832f51a@gocontroll.com>
References: <20251117-mini_iv-v4-0-5aa63832f51a@gocontroll.com>
Message-ID: <f1e63d1a-e111-46e0-b615-3780391661d6@gocontroll.com>

Gentle ping after a month of inactivity.

Kind regards,
Maud

On 11/17/25 16:01, Maud Spierings via B4 Relay wrote:
> Add initial support for the Moduline IV and Moduline Mini embedded
> controllers.
> 
> These systems are powered by the Ka-Ro Electronics tx8m-1610 COM, which
> features an imx8mm SoC.
> 
> Signed-off-by: Maud Spierings <maudspierings at gocontroll.com>
> ---
> Changes in v4:
> - Fix BUCK6 property order
> - Change the BUCK6 min/max voltage to match the dram specs (Lothar)
> - Make it clear that the two systems are based on a SoM in commit
>    message of the dt-bindings (Conor)
> - Drop merged PMIC fix (Matti, Mark)
> - Link to v3: https://lore.kernel.org/r/20251030-mini_iv-v3-0-ef56c4d9f219 at gocontroll.com
> 
> Changes in v3:
> - Add patch fixing the pmic driver
> - Use the proper feedback properties for BUCK6
> - Slightly rework the compatibles, acked by conor dropped
> - Add missing CAN interface supplies, remove the leftover comment
> - Add missing vled-supply
> - Add missing ethernet phy interrupt (doesn't work)
> - Fix the cs-gpios properties in all spi interfaces
> - Fix the order of properties in all spi interfaces
> - Remove unused labels for regulators of the PMIC
> - Link to v2: https://lore.kernel.org/r/20251022-mini_iv-v2-0-20af8f9aac14 at gocontroll.com
> 
> Changes in v2:
> - Fix allignment issue in imx8mm-tx8m-1610.dtsi (fec1)
> - Move phy-reset into fec (works better in barebox)
> - Make the gpio-line-names groups of four on every line
> - Link to v1: https://lore.kernel.org/r/20251009-mini_iv-v1-0-f3889c492457 at gocontroll.com
> 
> ---
> Maud Spierings (5):
>        dt-bindings: arm: fsl: Add GOcontroll Moduline IV/Mini
>        arm64: dts: imx8mm: Add pinctrl config definitions
>        arm64: dts: freescale: add Ka-Ro Electronics tx8m-1610 COM
>        arm64: dts: freescale: Add the GOcontroll Moduline IV
>        arm64: dts: freescale: Add the GOcontroll Moduline Mini
> 
>   Documentation/devicetree/bindings/arm/fsl.yaml     |   8 +
>   arch/arm64/boot/dts/freescale/Makefile             |   3 +
>   arch/arm64/boot/dts/freescale/imx8mm-pinfunc.h     |  33 +
>   .../imx8mm-tx8m-1610-moduline-iv-306-d.dts         | 800 +++++++++++++++++++++
>   .../imx8mm-tx8m-1610-moduline-mini-111.dts         | 688 ++++++++++++++++++
>   .../arm64/boot/dts/freescale/imx8mm-tx8m-1610.dtsi | 444 ++++++++++++
>   6 files changed, 1976 insertions(+)
> ---
> base-commit: 7c3ba4249a3604477ea9c077e10089ba7ddcaa03
> change-id: 20251009-mini_iv-a05e5c2c1223
> 
> Best regards,



From kees at kernel.org  Tue Dec 16 00:27:38 2025
From: kees at kernel.org (Kees Cook)
Date: Tue, 16 Dec 2025 00:27:38 -0800
Subject: [PATCH v2 3/3] randomize_kstack: Unify random source across
 arches
In-Reply-To: <20251215163520.1144179-4-ryan.roberts@arm.com>
References: <20251215163520.1144179-1-ryan.roberts@arm.com>
 <20251215163520.1144179-4-ryan.roberts@arm.com>
Message-ID: <202512160024.B688A8D0@keescook>

On Mon, Dec 15, 2025 at 04:35:17PM +0000, Ryan Roberts wrote:
> [...]
> @@ -45,9 +46,22 @@ DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
>  #define KSTACK_OFFSET_MAX(x)	((x) & 0b1111111100)
>  #endif
>  
> +DECLARE_PER_CPU(struct rnd_state, kstack_rnd_state);
> +
> +static __always_inline u32 get_kstack_offset(void)
> +{
> +	struct rnd_state *state;
> +	u32 rnd;
> +
> +	state = &get_cpu_var(kstack_rnd_state);
> +	rnd = prandom_u32_state(state);
> +	put_cpu_var(kstack_rnd_state);
> +
> +	return rnd;
> +}
> [...]
> -static inline void random_kstack_task_init(struct task_struct *tsk)
> +static int random_kstack_init(void)
>  {
> -	tsk->kstack_offset = 0;
> +	prandom_seed_full_state(&kstack_rnd_state);
> +	return 0;
>  }
> +
> +late_initcall(random_kstack_init);

Doesn't this need to be run for every CPU? (And how does hotplug work
for such things?) And doesn't it need a get_cpu_var?

-- 
Kees Cook


From ardb at kernel.org  Tue Dec 16 00:30:46 2025
From: ardb at kernel.org (Ard Biesheuvel)
Date: Tue, 16 Dec 2025 09:30:46 +0100
Subject: [PATCH v2 3/3] randomize_kstack: Unify random source across arches
In-Reply-To: <202512160024.B688A8D0@keescook>
References: <20251215163520.1144179-1-ryan.roberts@arm.com>
 <20251215163520.1144179-4-ryan.roberts@arm.com> <202512160024.B688A8D0@keescook>
Message-ID: <CAMj1kXHaqfEqDpvC-iC1fUn+JpTj=oqfM2sh+sbaC8_PBVHBUQ@mail.gmail.com>

On Tue, 16 Dec 2025 at 09:27, Kees Cook <kees at kernel.org> wrote:
>
> On Mon, Dec 15, 2025 at 04:35:17PM +0000, Ryan Roberts wrote:
> > [...]
> > @@ -45,9 +46,22 @@ DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
> >  #define KSTACK_OFFSET_MAX(x) ((x) & 0b1111111100)
> >  #endif
> >
> > +DECLARE_PER_CPU(struct rnd_state, kstack_rnd_state);
> > +
> > +static __always_inline u32 get_kstack_offset(void)
> > +{
> > +     struct rnd_state *state;
> > +     u32 rnd;
> > +
> > +     state = &get_cpu_var(kstack_rnd_state);
> > +     rnd = prandom_u32_state(state);
> > +     put_cpu_var(kstack_rnd_state);
> > +
> > +     return rnd;
> > +}
> > [...]
> > -static inline void random_kstack_task_init(struct task_struct *tsk)
> > +static int random_kstack_init(void)
> >  {
> > -     tsk->kstack_offset = 0;
> > +     prandom_seed_full_state(&kstack_rnd_state);
> > +     return 0;
> >  }
> > +
> > +late_initcall(random_kstack_init);
>
> Doesn't this need to be run for every CPU? (And how does hotplug work
> for such things?) And doesn't it need a get_cpu_var?
>


 prandom_seed_full_state() takes a 'struct rnd_state __percpu
*pcpu_state', and performs the initialization for all possible CPUs.


From gatien.chevallier at foss.st.com  Tue Dec 16 00:32:16 2025
From: gatien.chevallier at foss.st.com (Gatien CHEVALLIER)
Date: Tue, 16 Dec 2025 09:32:16 +0100
Subject: [PATCH] dt-bindings: bus: stm32mp25-rifsc: Allow 2 size cells
In-Reply-To: <20251215212700.3320634-1-robh@kernel.org>
References: <20251215212700.3320634-1-robh@kernel.org>
Message-ID: <81ec27d5-1839-4a8d-9b7e-08ac49335503@foss.st.com>



On 12/15/25 22:26, Rob Herring (Arm) wrote:
> There are users already with 2 size cells, and there's no reason to not
> support that.
> 
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> ---
>   Documentation/devicetree/bindings/bus/st,stm32mp25-rifsc.yaml | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/Documentation/devicetree/bindings/bus/st,stm32mp25-rifsc.yaml b/Documentation/devicetree/bindings/bus/st,stm32mp25-rifsc.yaml
> index 4d19917ad2c3..c6280c8c54a3 100644
> --- a/Documentation/devicetree/bindings/bus/st,stm32mp25-rifsc.yaml
> +++ b/Documentation/devicetree/bindings/bus/st,stm32mp25-rifsc.yaml
> @@ -54,7 +54,7 @@ properties:
>       const: 1
>   
>     "#size-cells":
> -    const: 1
> +    enum: [ 1, 2 ]
>   
>     ranges: true
>   

Hello Rob,

Thank you!

Reviewed-by: Gatien Chevallier <gatien.chevallier at foss.st.com>

Gatien


From peng.fan at nxp.com  Tue Dec 16 00:34:46 2025
From: peng.fan at nxp.com (Peng Fan)
Date: Tue, 16 Dec 2025 08:34:46 +0000
Subject: [PATCH] mailbox: imx: Skip the suspend flag for i.MX7ULP
In-Reply-To: <20251216-imx7ulp_mailbox-v1-1-66b5bbcd3005@nxp.com>
References: <20251216-imx7ulp_mailbox-v1-1-66b5bbcd3005@nxp.com>
Message-ID: <PAXPR04MB8459A075646D9C6956035DC988AAA@PAXPR04MB8459.eurprd04.prod.outlook.com>

> Subject: [PATCH] mailbox: imx: Skip the suspend flag for i.MX7ULP
> 
> In current imx-mailbox driver, the MU IRQ is configured with
> 'IRQF_NO_SUSPEND' flag set. So during linux suspend/resume flow, the
> MU IRQ is always enabled. With commit 892cb524ae8a ("mailbox: imx:
> fix wakeup failure from freeze mode"), if the MU IRQ is triggered after
> the priv->suspended flag has been set, the system suspend will be
> aborted.
> 
> On i.MX7ULP platform, certain drivers that depend on rpmsg may need
> to send rpmsg request and receive an acknowledgment from the
> remote core during the late_suspend stage. Early suspend abort is not
> expected, and the i.MX7ULP already has additional hardware and
> software to make sure the system can be wakeup from freeze mode
> correctly when MU IRQ is trigger.
> 
> Skip the 'suspend' flag handling logic on i.MX7ULP to avoid the early
> abort when doing suspend.
> 
> Signed-off-by: Jacky Bai <ping.bai at nxp.com>

Reviewed-by: Peng Fan <peng.fan at nxp.com>

From alexandre.belloni at bootlin.com  Tue Dec 16 00:45:33 2025
From: alexandre.belloni at bootlin.com (Alexandre Belloni)
Date: Tue, 16 Dec 2025 09:45:33 +0100
Subject: [PATCH v2 3/4] Input: adc-keys - Use dev_err_probe in probe
 function
In-Reply-To: <20251215-rock4d-audio-v2-3-82a61de39b4c@collabora.com>
References: <20251215-rock4d-audio-v2-0-82a61de39b4c@collabora.com>
 <20251215-rock4d-audio-v2-3-82a61de39b4c@collabora.com>
Message-ID: <20251216084533c8786b5d@mail.local>

On 15/12/2025 13:29:31+0100, Nicolas Frattaroli wrote:
> Rework the probe function, and functions called by the probe function,
> to use dev_err_probe for error logging.
> 
> While at it, also do some minor style cleanups, like not error logging
> on -ENOMEM and using ! instead of == 0.
> 
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>

Reviewed-by: Alexandre Belloni <alexandre.belloni at bootlin.com>

> ---
>  drivers/input/keyboard/adc-keys.c | 53 ++++++++++++++++-----------------------
>  1 file changed, 21 insertions(+), 32 deletions(-)
> 
> diff --git a/drivers/input/keyboard/adc-keys.c b/drivers/input/keyboard/adc-keys.c
> index 62376f34f7d0..6f2ddcecea99 100644
> --- a/drivers/input/keyboard/adc-keys.c
> +++ b/drivers/input/keyboard/adc-keys.c
> @@ -74,10 +74,8 @@ static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st)
>  	int i;
>  
>  	st->num_keys = device_get_child_node_count(dev);
> -	if (st->num_keys == 0) {
> -		dev_err(dev, "keymap is missing\n");
> -		return -EINVAL;
> -	}
> +	if (!st->num_keys)
> +		return dev_err_probe(dev, -EINVAL, "keymap is missing\n");
>  
>  	map = devm_kmalloc_array(dev, st->num_keys, sizeof(*map), GFP_KERNEL);
>  	if (!map)
> @@ -86,17 +84,16 @@ static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st)
>  	i = 0;
>  	device_for_each_child_node_scoped(dev, child) {
>  		if (fwnode_property_read_u32(child, "press-threshold-microvolt",
> -					     &map[i].voltage)) {
> -			dev_err(dev, "Key with invalid or missing voltage\n");
> -			return -EINVAL;
> -		}
> +					     &map[i].voltage))
> +			return dev_err_probe(dev, -EINVAL,
> +					     "Key with invalid or missing voltage\n");
> +
>  		map[i].voltage /= 1000;
>  
>  		if (fwnode_property_read_u32(child, "linux,code",
> -					     &map[i].code)) {
> -			dev_err(dev, "Key with invalid or missing linux,code\n");
> -			return -EINVAL;
> -		}
> +					     &map[i].code))
> +			return dev_err_probe(dev, -EINVAL,
> +					     "Key with invalid or missing linux,code\n");
>  
>  		if (fwnode_property_read_u32(child, "linux,input-type",
>  					     &map[i].type))
> @@ -129,7 +126,8 @@ static int adc_keys_probe(struct platform_device *pdev)
>  
>  	st->channel = devm_iio_channel_get(dev, "buttons");
>  	if (IS_ERR(st->channel))
> -		return PTR_ERR(st->channel);
> +		return dev_err_probe(dev, PTR_ERR(st->channel),
> +				     "Could not get iio channel\n");
>  
>  	if (!st->channel->indio_dev)
>  		return -ENXIO;
> @@ -138,16 +136,13 @@ static int adc_keys_probe(struct platform_device *pdev)
>  	if (error < 0)
>  		return error;
>  
> -	if (type != IIO_VOLTAGE) {
> -		dev_err(dev, "Incompatible channel type %d\n", type);
> -		return -EINVAL;
> -	}
> +	if (type != IIO_VOLTAGE)
> +		return dev_err_probe(dev, -EINVAL, "Incompatible channel type %d\n", type);
>  
>  	if (device_property_read_u32(dev, "keyup-threshold-microvolt",
> -				     &st->keyup_voltage)) {
> -		dev_err(dev, "Invalid or missing keyup voltage\n");
> -		return -EINVAL;
> -	}
> +				     &st->keyup_voltage))
> +		return dev_err_probe(dev, -EINVAL, "Invalid or missing keyup voltage\n");
> +
>  	st->keyup_voltage /= 1000;
>  
>  	error = adc_keys_load_keymap(dev, st);
> @@ -155,10 +150,8 @@ static int adc_keys_probe(struct platform_device *pdev)
>  		return error;
>  
>  	input = devm_input_allocate_device(dev);
> -	if (!input) {
> -		dev_err(dev, "failed to allocate input device\n");
> +	if (!input)
>  		return -ENOMEM;
> -	}
>  
>  	input_set_drvdata(input, st);
>  
> @@ -178,19 +171,15 @@ static int adc_keys_probe(struct platform_device *pdev)
>  
>  
>  	error = input_setup_polling(input, adc_keys_poll);
> -	if (error) {
> -		dev_err(dev, "Unable to set up polling: %d\n", error);
> -		return error;
> -	}
> +	if (error)
> +		return dev_err_probe(dev, error, "Unable to set up polling\n");
>  
>  	if (!device_property_read_u32(dev, "poll-interval", &value))
>  		input_set_poll_interval(input, value);
>  
>  	error = input_register_device(input);
> -	if (error) {
> -		dev_err(dev, "Unable to register input device: %d\n", error);
> -		return error;
> -	}
> +	if (error)
> +		return dev_err_probe(dev, error, "Unable to register input device\n");
>  
>  	return 0;
>  }
> 
> -- 
> 2.52.0
> 

-- 
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From alexandre.belloni at bootlin.com  Tue Dec 16 00:45:59 2025
From: alexandre.belloni at bootlin.com (Alexandre Belloni)
Date: Tue, 16 Dec 2025 09:45:59 +0100
Subject: [PATCH v2 2/4] Input: adc-keys - support EV_SW as well, not just
 EV_KEY.
In-Reply-To: <20251215-rock4d-audio-v2-2-82a61de39b4c@collabora.com>
References: <20251215-rock4d-audio-v2-0-82a61de39b4c@collabora.com>
 <20251215-rock4d-audio-v2-2-82a61de39b4c@collabora.com>
Message-ID: <202512160845594c145070@mail.local>

On 15/12/2025 13:29:30+0100, Nicolas Frattaroli wrote:
> Instead of doing something like what gpio-keys is doing, adc-keys
> hardcodes that all keycodes must be of type EV_KEY.
> 
> This limits the usefulness of adc-keys, and overcomplicates the code
> with manual bit-setting logic.
> 
> Instead, refactor the code to read the linux,input-type fwnode property,
> and get rid of the custom bit setting logic, replacing it with
> input_set_capability instead. input_report_key is replaced with
> input_event, which allows us to explicitly pass the type.
> 
> Only EV_KEY and EV_SW is allowed at this stage.
> 
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>

Reviewed-by: Alexandre Belloni <alexandre.belloni at bootlin.com>

> ---
>  drivers/input/keyboard/adc-keys.c | 37 +++++++++++++++++++++++++------------
>  1 file changed, 25 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/input/keyboard/adc-keys.c b/drivers/input/keyboard/adc-keys.c
> index f1753207429d..62376f34f7d0 100644
> --- a/drivers/input/keyboard/adc-keys.c
> +++ b/drivers/input/keyboard/adc-keys.c
> @@ -18,13 +18,15 @@
>  
>  struct adc_keys_button {
>  	u32 voltage;
> -	u32 keycode;
> +	u32 code;
> +	u32 type;
>  };
>  
>  struct adc_keys_state {
>  	struct iio_channel *channel;
>  	u32 num_keys;
>  	u32 last_key;
> +	u32 last_type;
>  	u32 keyup_voltage;
>  	const struct adc_keys_button *map;
>  };
> @@ -34,7 +36,8 @@ static void adc_keys_poll(struct input_dev *input)
>  	struct adc_keys_state *st = input_get_drvdata(input);
>  	int i, value, ret;
>  	u32 diff, closest = 0xffffffff;
> -	int keycode = 0;
> +	u32 code = 0;
> +	u32 type = EV_KEY;
>  
>  	ret = iio_read_channel_processed(st->channel, &value);
>  	if (unlikely(ret < 0)) {
> @@ -45,22 +48,24 @@ static void adc_keys_poll(struct input_dev *input)
>  			diff = abs(st->map[i].voltage - value);
>  			if (diff < closest) {
>  				closest = diff;
> -				keycode = st->map[i].keycode;
> +				code = st->map[i].code;
> +				type = st->map[i].type;
>  			}
>  		}
>  	}
>  
>  	if (abs(st->keyup_voltage - value) < closest)
> -		keycode = 0;
> +		code = 0;
>  
> -	if (st->last_key && st->last_key != keycode)
> -		input_report_key(input, st->last_key, 0);
> +	if (st->last_key && st->last_key != code)
> +		input_event(input, st->last_type, st->last_key, 0);
>  
> -	if (keycode)
> -		input_report_key(input, keycode, 1);
> +	if (code)
> +		input_event(input, type, code, 1);
>  
>  	input_sync(input);
> -	st->last_key = keycode;
> +	st->last_key = code;
> +	st->last_type = type;
>  }
>  
>  static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st)
> @@ -88,11 +93,20 @@ static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st)
>  		map[i].voltage /= 1000;
>  
>  		if (fwnode_property_read_u32(child, "linux,code",
> -					     &map[i].keycode)) {
> +					     &map[i].code)) {
>  			dev_err(dev, "Key with invalid or missing linux,code\n");
>  			return -EINVAL;
>  		}
>  
> +		if (fwnode_property_read_u32(child, "linux,input-type",
> +					     &map[i].type))
> +			map[i].type = EV_KEY;
> +
> +		if (map[i].type != EV_KEY && map[i].type != EV_SW)
> +			return dev_err_probe(dev, -EINVAL,
> +					     "Invalid linux,input-type: 0x%x\n",
> +					     map[i].type);
> +
>  		i++;
>  	}
>  
> @@ -156,9 +170,8 @@ static int adc_keys_probe(struct platform_device *pdev)
>  	input->id.product = 0x0001;
>  	input->id.version = 0x0100;
>  
> -	__set_bit(EV_KEY, input->evbit);
>  	for (i = 0; i < st->num_keys; i++)
> -		__set_bit(st->map[i].keycode, input->keybit);
> +		input_set_capability(input, st->map[i].type, st->map[i].code);
>  
>  	if (device_property_read_bool(dev, "autorepeat"))
>  		__set_bit(EV_REP, input->evbit);
> 
> -- 
> 2.52.0
> 

-- 
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From alexandre.belloni at bootlin.com  Tue Dec 16 00:47:45 2025
From: alexandre.belloni at bootlin.com (Alexandre Belloni)
Date: Tue, 16 Dec 2025 09:47:45 +0100
Subject: [PATCH v2 1/4] dt-bindings: input: adc-keys: allow
 linux,input-type property
In-Reply-To: <20251215-rock4d-audio-v2-1-82a61de39b4c@collabora.com>
References: <20251215-rock4d-audio-v2-0-82a61de39b4c@collabora.com>
 <20251215-rock4d-audio-v2-1-82a61de39b4c@collabora.com>
Message-ID: <202512160847455082a875@mail.local>

On 15/12/2025 13:29:29+0100, Nicolas Frattaroli wrote:
> adc-keys, unlike gpio-keys, does not allow linux,input-type as a valid
> property. This makes it impossible to model devices that have ADC inputs
> that should generate switch events.
> 
> Add the property to the binding with the same default as gpio-keys.
> 
> Reviewed-by: Heiko Stuebner <heiko at sntech.de>
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
Reviewed-by: Alexandre Belloni <alexandre.belloni at bootlin.com>

> ---
>  Documentation/devicetree/bindings/input/adc-keys.yaml | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/input/adc-keys.yaml b/Documentation/devicetree/bindings/input/adc-keys.yaml
> index 7aa078dead37..e372ebc23d16 100644
> --- a/Documentation/devicetree/bindings/input/adc-keys.yaml
> +++ b/Documentation/devicetree/bindings/input/adc-keys.yaml
> @@ -42,6 +42,9 @@ patternProperties:
>  
>        linux,code: true
>  
> +      linux,input-type:
> +        default: 1  # EV_KEY
> +
>        press-threshold-microvolt:
>          description:
>            Voltage above or equal to which this key is considered pressed. No
> 
> -- 
> 2.52.0
> 

-- 
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From daniel.baluta at gmail.com  Tue Dec 16 00:52:38 2025
From: daniel.baluta at gmail.com (Daniel Baluta)
Date: Tue, 16 Dec 2025 10:52:38 +0200
Subject: [PATCH] remoteproc: imx_dsp_rproc: only reset carveout memory at
 RPROC_OFFLINE state
In-Reply-To: <20251216074216.447193-1-shengjiu.wang@nxp.com>
References: <20251216074216.447193-1-shengjiu.wang@nxp.com>
Message-ID: <CAEnQRZCZe3z8F7TsFdCz5P6mu6qzGkdoqC76XkyCCzQz+pSpmA@mail.gmail.com>

On Tue, Dec 16, 2025 at 9:59?AM Shengjiu Wang <shengjiu.wang at nxp.com> wrote:
>
> Don't need to reset memory at suspend and resume stage, because some
> memory is used to save the software state for resume, if it is cleared,
> the resume operation can fail.

I would rephrase this as "Do not reset memory ...".

"Don't need .." suggests that this operation is unnecessary, but not wrong.

With that,

Reviewed-by: Daniel Baluta <daniel.baluta at nxp.com>


From krzk at kernel.org  Tue Dec 16 00:51:56 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 16 Dec 2025 09:51:56 +0100
Subject: [PATCH v2 07/11] dt-bindings: clock: qcom: document the Kaanapali
 GPU Clock Controller
In-Reply-To: <de44560d-4ed8-41fe-be7b-56412b933a8c@oss.qualcomm.com>
References: <20251125-kaanapali-mmcc-v2-v2-0-fb44e78f300b@oss.qualcomm.com>
 <20251125-kaanapali-mmcc-v2-v2-7-fb44e78f300b@oss.qualcomm.com>
 <20251126-elated-stoic-scorpion-25b630@kuoka>
 <de44560d-4ed8-41fe-be7b-56412b933a8c@oss.qualcomm.com>
Message-ID: <fbe39eac-7c92-4a08-bafb-31e5c51a0613@kernel.org>

On 04/12/2025 07:49, Taniya Das wrote:
>>> +  power-domains:
>>> +    description:
>>> +      Power domains required for the clock controller to operate
>>> +    items:
>>> +      - description: GFX power domain
>>> +      - description: GMXC power domain
>>> +      - description: GPUCC(CX) power domain
>>> +
>>> +  '#power-domain-cells':
>>
>> Power domain controllers do not belong to clocks, so this is:
>> 1. Misplaced - wrong folder
>> 2. Probably wrongly named. gxclkctl sounds like clock controller, but
>> this is domain controller?
>>
> 
> The GFXCLKCTL is actually a clock controller which has PLLs, clocks and
> Power domains (GDSC), but the requirement here is to use the GDSC from
> the clock controller to recover the GPU firmware in case of any
> failure/hangs. The rest of the resources of the clock controller are
> being used by the firmware of GPU. The GDSC is a clock controller
> resource and modeled from the clock controller drivers across chipsets.

This should be somewhere explained.

> 
>>> +    const: 1
>>> +
>>> +  reg:
>>> +    maxItems: 1
>>> +
>>> +required:
>>> +  - compatible
>>> +  - reg
>>> +  - power-domains
>>> +  - '#power-domain-cells'
>>> +
>>> +unevaluatedProperties: false
>>> +
>>> +examples:
>>> +  - |
>>> +    #include <dt-bindings/power/qcom,rpmhpd.h>
>>> +    soc {
>>> +        #address-cells = <2>;
>>> +        #size-cells = <2>;
>>> +
>>> +        clock-controller at 3d68024 {
>>> +            compatible = "qcom,kaanapali-gxclkctl";
>>> +            reg = <0 0x3d68024 0x0 0x8>;
>>
>> Keep consistent hex, so first 0 -> 0x0.
> 
> Sure, will fix this.
> 
>> But the problem is that you defined a device for two registers,
>> basically one domain. I have doubts now whether this is complete and
>> real device.
>>
> 
> As the Linux GPU driver requires only the GDSC, I have mapped the region
> which is required by the clock controller driver. If required, the
> entire region can be mapped as well.

Required is to properly describe the hardware, please read writing
bindings doc.

> 
>>> +            power-domains = <&rpmhpd RPMHPD_GFX>,
>>> +                            <&rpmhpd RPMHPD_GMXC>,
>>> +                            <&gpucc 0>;
>>> +            #power-domain-cells = <1>;
>>
>> And cells 1 makes no sense in such case.
>>
> 
> We would like to leverage the existing common clock driver(GDSC) code to

Fix the driver code if it cannot handle other cells. Your drivers do not
matter for choices made in bindings.

> register the power-domains and also maintain uniformity across chipsets
> and consistency in consumer GDSC phandle usage.

There is no such consistency rule. Don't make up your own rules.

Best regards,
Krzysztof


From Sascha.Bischoff at arm.com  Tue Dec 16 00:57:02 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Tue, 16 Dec 2025 08:57:02 +0000
Subject: [PATCH 07/32] KVM: arm64: gic: Introduce interrupt type helpers
In-Reply-To: <86ecovohn3.wl-maz@kernel.org>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	 <20251212152215.675767-8-sascha.bischoff@arm.com>
	 <86jyynooq3.wl-maz@kernel.org> <86ecovohn3.wl-maz@kernel.org>
Message-ID: <34f4147fb0dae6123722b38c0d481af1d8f69c24.camel@arm.com>

On Mon, 2025-12-15 at 16:05 +0000, Marc Zyngier wrote:
> On Mon, 15 Dec 2025 13:32:04 +0000,
> Marc Zyngier <maz at kernel.org> wrote:
> > 
> > I'd rather you have something that denotes the non-GICv5-ness of
> > the
> > implementation. irq_is_nv5_ppi()?
> 
> Actually, this is just as bad. I spent the past 30 minutes hacking on
> this, and came up with this hack (which compiles, but probably
> doesn't
> run). It is significantly more code, but I like that it treats all
> GIC
> implementations more or less the same way.
> 
> It also clears the who [v]gic_is_v5() situation that made little
> sense.
> 
> Let me know what you think.
> 
> 	M.

Thanks, Marc!

I do think that this is better overall. It removes the naming issues as
you say, and makes the whole situation more readable (and adds in SGI
support in those checks).

It does mean that we're still passing a non-vcpu pointer for the
private irqs (PPIs, SGIs) but else it gets quite inconsistent. Going
through the code we do actually have one place where we check for a PPI
without having a vcpu - setting the GICv3 maint IRQ. I guess that it is
worth paying the price of having vcpu->kvm in a few places for the sake
of consistency.

Will work these changes into the patch series (including cleaning up
the gic type checks).

Thanks,
Sascha

> 
> diff --git a/arch/arm64/kvm/arch_timer.c
> b/arch/arm64/kvm/arch_timer.c
> index b0a5a6c6bf8da..c908d5ac4d678 100644
> --- a/arch/arm64/kvm/arch_timer.c
> +++ b/arch/arm64/kvm/arch_timer.c
> @@ -62,11 +62,6 @@ static struct irq_ops arch_timer_irq_ops_vgic_v5 =
> {
> ?	.queue_irq_unlock = vgic_v5_ppi_queue_irq_unlock,
> ?};
> ?
> -static bool vgic_is_v5(struct kvm_vcpu *vcpu)
> -{
> -	return vcpu->kvm->arch.vgic.vgic_model ==
> KVM_DEV_TYPE_ARM_VGIC_V5;
> -}
> -
> ?static int nr_timers(struct kvm_vcpu *vcpu)
> ?{
> ?	if (!vcpu_has_nv(vcpu))
> @@ -708,7 +703,7 @@ static void kvm_timer_vcpu_load_gic(struct
> arch_timer_context *ctx)
> ?
> ?	phys_active |= ctx->irq.level;
> ?
> -	if (!vgic_is_v5(vcpu))
> +	if (!vgic_is_v5(vcpu->kvm))
> ?		set_timer_irq_phys_active(ctx, phys_active);
> ?	else
> ?		set_timer_irq_phys_masked(ctx, true);
> @@ -760,7 +755,7 @@ static void
> kvm_timer_vcpu_load_nested_switch(struct kvm_vcpu *vcpu,
> ?	if (!irqchip_in_kernel(vcpu->kvm))
> ?		return;
> ?
> -	ops = vgic_is_v5(vcpu) ? &arch_timer_irq_ops_vgic_v5 :
> +	ops = vgic_is_v5(vcpu->kvm) ? &arch_timer_irq_ops_vgic_v5 :
> ?				 &arch_timer_irq_ops;
> ?
> ?	/*
> @@ -905,7 +900,7 @@ void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)
> ?
> ?	if (static_branch_likely(&has_gic_active_state)) {
> ?		/* We don't do NV on GICv5, yet */
> -		if (vcpu_has_nv(vcpu) && !vgic_is_v5(vcpu))
> +		if (vcpu_has_nv(vcpu) && !vgic_is_v5(vcpu->kvm))
> ?			kvm_timer_vcpu_load_nested_switch(vcpu,
> &map);
> ?
> ?		kvm_timer_vcpu_load_gic(map.direct_vtimer);
> @@ -977,7 +972,7 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
> ?		kvm_timer_blocking(vcpu);
> ?
> ?	/* Unmask again on GICV5 */
> -	if (vgic_is_v5(vcpu)) {
> +	if (vgic_is_v5(vcpu->kvm)) {
> ?		set_timer_irq_phys_masked(map.direct_vtimer, false);
> ?
> ?		if (map.direct_ptimer)
> @@ -1623,7 +1618,7 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
> ?		return -EINVAL;
> ?	}
> ?
> -	ops = vgic_is_v5(vcpu) ? &arch_timer_irq_ops_vgic_v5 :
> +	ops = vgic_is_v5(vcpu->kvm) ? &arch_timer_irq_ops_vgic_v5 :
> ?				 &arch_timer_irq_ops;
> ?
> ?	get_timer_map(vcpu, &map);
> @@ -1700,7 +1695,7 @@ int kvm_arm_timer_set_attr(struct kvm_vcpu
> *vcpu, struct kvm_device_attr *attr)
> ?	 * The PPIs for the Arch Timers arch architecturally defined
> for
> ?	 * GICv5. Reject anything that changes them from the
> specified value.
> ?	 */
> -	if (vgic_is_v5(vcpu) && vcpu->kvm->arch.timer_data.ppi[idx]
> != irq) {
> +	if (vgic_is_v5(vcpu->kvm) && vcpu->kvm-
> >arch.timer_data.ppi[idx] != irq) {
> ?		ret = -EINVAL;
> ?		goto out;
> ?	}
> diff --git a/arch/arm64/kvm/vgic/vgic-v5.c
> b/arch/arm64/kvm/vgic/vgic-v5.c
> index d74cc3543b9a4..19d8bf90f8f6c 100644
> --- a/arch/arm64/kvm/vgic/vgic-v5.c
> +++ b/arch/arm64/kvm/vgic/vgic-v5.c
> @@ -225,7 +225,7 @@ bool vgic_v5_ppi_queue_irq_unlock(struct kvm
> *kvm, struct vgic_irq *irq,
> ?
> ?	lockdep_assert_held(&irq->irq_lock);
> ?
> -	if (WARN_ON_ONCE(!irq_is_ppi_v5(irq->intid)))
> +	if (WARN_ON_ONCE(!__irq_is_ppi(KVM_DEV_TYPE_ARM_VGIC_V5,
> irq->intid)))
> ?		return false;
> ?
> ?	vcpu = irq->target_vcpu;
> diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
> index 62d7d4c5650e4..6d8e4cd661734 100644
> --- a/arch/arm64/kvm/vgic/vgic.c
> +++ b/arch/arm64/kvm/vgic/vgic.c
> @@ -109,10 +109,10 @@ struct vgic_irq *vgic_get_vcpu_irq(struct
> kvm_vcpu *vcpu, u32 intid)
> ?	if (WARN_ON(!vcpu))
> ?		return NULL;
> ?
> -	if (vcpu->kvm->arch.vgic.vgic_model ==
> KVM_DEV_TYPE_ARM_VGIC_V5) {
> +	if (vgic_is_v5(vcpu->kvm)) {
> ?		u32 int_num = FIELD_GET(GICV5_HWIRQ_ID, intid);
> ?
> -		if (irq_is_ppi_v5(intid)) {
> +		if (__irq_is_ppi(KVM_DEV_TYPE_ARM_VGIC_V5, intid)) {
> ?			int_num = array_index_nospec(int_num,
> VGIC_V5_NR_PRIVATE_IRQS);
> ?			return &vcpu-
> >arch.vgic_cpu.private_irqs[int_num];
> ?		}
> @@ -600,15 +600,13 @@ static int kvm_vgic_map_irq(struct kvm_vcpu
> *vcpu, struct vgic_irq *irq,
> ?	irq->hwintid = data->hwirq;
> ?	irq->ops = ops;
> ?
> -	if (vgic_is_v5(vcpu->kvm)) {
> -		/* Nothing for us to do */
> -		if (!irq_is_ppi_v5(irq->intid))
> -			return 0;
> +	if (vgic_is_v5(vcpu->kvm) &&
> +	??? !__irq_is_ppi(KVM_DEV_TYPE_ARM_VGIC_V5, irq->intid))
> +		return 0;
> ?
> -		if (FIELD_GET(GICV5_HWIRQ_ID, irq->intid) == irq-
> >hwintid) {
> -			if (!vgic_v5_set_ppi_dvi(vcpu, irq->hwintid,
> true))
> -				irq->directly_injected = true;
> -		}
> +	if (FIELD_GET(GICV5_HWIRQ_ID, irq->intid) == irq->hwintid) {
> +		if (!vgic_v5_set_ppi_dvi(vcpu, irq->hwintid, true))
> +			irq->directly_injected = true;
> ?	}
> ?
> ?	return 0;
> diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
> index 91969b3b80d04..d8a947a7eb941 100644
> --- a/arch/arm64/kvm/vgic/vgic.h
> +++ b/arch/arm64/kvm/vgic/vgic.h
> @@ -500,11 +500,6 @@ static inline bool vgic_is_v3(struct kvm *kvm)
> ?	return kvm_vgic_global_state.type == VGIC_V3 ||
> vgic_is_v3_compat(kvm);
> ?}
> ?
> -static inline bool vgic_is_v5(struct kvm *kvm)
> -{
> -	return kvm_vgic_global_state.type == VGIC_V5 &&
> !vgic_is_v3_compat(kvm);
> -}
> -
> ?bool system_supports_direct_sgis(void);
> ?bool vgic_supports_direct_msis(struct kvm *kvm);
> ?bool vgic_supports_direct_sgis(struct kvm *kvm);
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 6863e19d6eeb7..ae2897c539af7 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -36,22 +36,78 @@
> ?/* GICv5 constants */
> ?#define VGIC_V5_NR_PRIVATE_IRQS	128
> ?
> -#define irq_is_ppi_legacy(irq) ((irq) >= VGIC_NR_SGIS && (irq) <
> VGIC_NR_PRIVATE_IRQS)
> -#define irq_is_spi_legacy(irq) ((irq) >= VGIC_NR_PRIVATE_IRQS && \
> -					(irq) <= VGIC_MAX_SPI)
> -#define irq_is_lpi_legacy(irq) ((irq) > VGIC_MAX_SPI)
> -
> -#define irq_is_ppi_v5(irq) (FIELD_GET(GICV5_HWIRQ_TYPE, irq) ==
> GICV5_HWIRQ_TYPE_PPI)
> -#define irq_is_spi_v5(irq) (FIELD_GET(GICV5_HWIRQ_TYPE, irq) ==
> GICV5_HWIRQ_TYPE_SPI)
> -#define irq_is_lpi_v5(irq) (FIELD_GET(GICV5_HWIRQ_TYPE, irq) ==
> GICV5_HWIRQ_TYPE_LPI)
> -
> -#define gic_is_v5(k) ((k)->arch.vgic.vgic_model ==
> KVM_DEV_TYPE_ARM_VGIC_V5)
> -
> -#define irq_is_ppi(k, i) (gic_is_v5(k) ? irq_is_ppi_v5(i) :
> irq_is_ppi_legacy(i))
> -#define irq_is_spi(k, i) (gic_is_v5(k) ? irq_is_spi_v5(i) :
> irq_is_spi_legacy(i))
> -#define irq_is_lpi(k, i) (gic_is_v5(k) ? irq_is_lpi_v5(i) :
> irq_is_lpi_legacy(i))
> -
> -#define irq_is_private(k, i) (gic_is_v5(k) ? irq_is_ppi_v5(i) : i <
> VGIC_NR_PRIVATE_IRQS)
> +#define is_v5_type(t, i)	(FIELD_GET(GICV5_HWIRQ_TYPE, (i)) ==
> (t))
> +
> +#define __irq_is_sgi(t,
> i)						\
> +	({							
> 	\
> +		bool
> __ret;						\
> +								
> 	\
> +		switch (t)
> {						\
> +		case
> KVM_DEV_TYPE_ARM_VGIC_V5:				\
> +			__ret =
> false;					\
> +			break;					
> 	\
> +		default:					
> 	\
> +			__ret? = (i) <
> VGIC_NR_SGIS;			\
> +		}						
> 	\
> +								
> 	\
> +		__ret;						
> 	\
> +	})
> +
> +#define __irq_is_ppi(t,
> i)						\
> +	({							
> 	\
> +		bool
> __ret;						\
> +								
> 	\
> +		switch (t)
> {						\
> +		case
> KVM_DEV_TYPE_ARM_VGIC_V5:				\
> +			__ret = is_v5_type(GICV5_HWIRQ_TYPE_PPI,
> (i));	\
> +			break;					
> 	\
> +		default:					
> 	\
> +			__ret? = (i) >=
> VGIC_NR_SGIS;			\
> +			__ret &= (i) <
> VGIC_NR_PRIVATE_IRQS;		\
> +		}						
> 	\
> +								
> 	\
> +		__ret;						
> 	\
> +	})
> +
> +#define __irq_is_spi(t,
> i)						\
> +	({							
> 	\
> +		bool
> __ret;						\
> +								
> 	\
> +		switch (t)
> {						\
> +		case
> KVM_DEV_TYPE_ARM_VGIC_V5:				\
> +			__ret = is_v5_type(GICV5_HWIRQ_TYPE_SPI,
> (i));	\
> +			break;					
> 	\
> +		default:					
> 	\
> +			__ret? = (i) <=
> VGIC_MAX_SPI;			\
> +			__ret &= (i) >=
> VGIC_NR_PRIVATE_IRQS;		\
> +		}						
> 	\
> +								
> 	\
> +		__ret;						
> 	\
> +	})
> +
> +#define __irq_is_lpi(t,
> i)						\
> +	({							
> 	\
> +		bool
> __ret;						\
> +								
> 	\
> +		switch (t)
> {						\
> +		case
> KVM_DEV_TYPE_ARM_VGIC_V5:				\
> +			__ret = is_v5_type(GICV5_HWIRQ_TYPE_LPI,
> (i));	\
> +			break;					
> 	\
> +		default:					
> 	\
> +			__ret? = (i) >=
> 8192;				\
> +		}						
> 	\
> +								
> 	\
> +		__ret;						
> 	\
> +	})
> +
> +#define irq_is_sgi(k, i) __irq_is_sgi((k)->arch.vgic.vgic_model, i)
> +#define irq_is_ppi(k, i) __irq_is_ppi((k)->arch.vgic.vgic_model, i)
> +#define irq_is_spi(k, i) __irq_is_spi((k)->arch.vgic.vgic_model, i)
> +#define irq_is_lpi(k, i) __irq_is_lpi((k)->arch.vgic.vgic_model, i)
> +
> +#define irq_is_private(k, i) (irq_is_ppi(k, i) || irq_is_sgi(k, i))
> +
> +#define vgic_is_v5(k) ((k)->arch.vgic.vgic_model ==
> KVM_DEV_TYPE_ARM_VGIC_V5)
> ?
> ?enum vgic_type {
> ?	VGIC_V2,		/* Good ol' GICv2 */
> 


From peterz at infradead.org  Tue Dec 16 01:09:26 2025
From: peterz at infradead.org (Peter Zijlstra)
Date: Tue, 16 Dec 2025 10:09:26 +0100
Subject: [PATCH v7 6/7] iommu/arm-smmu-v3: Add arm_smmu_invs based
 arm_smmu_domain_inv_range()
In-Reply-To: <f4261c5b30ce3c6942470433033d4933ec5eef3e.1765850465.git.nicolinc@nvidia.com>
References: <cover.1765850465.git.nicolinc@nvidia.com>
 <f4261c5b30ce3c6942470433033d4933ec5eef3e.1765850465.git.nicolinc@nvidia.com>
Message-ID: <20251216090926.GR3707837@noisy.programming.kicks-ass.net>

On Mon, Dec 15, 2025 at 06:09:35PM -0800, Nicolin Chen wrote:


> +void arm_smmu_domain_inv_range(struct arm_smmu_domain *smmu_domain,
> +			       unsigned long iova, size_t size,
> +			       unsigned int granule, bool leaf)
> +{
> +	struct arm_smmu_invs *invs;
> +
> +	/*
> +	 * An invalidation request must follow some IOPTE change and then load
> +	 * an invalidation array. In the meantime, a domain attachment mutates
> +	 * the array and then stores an STE/CD asking SMMU HW to acquire those
> +	 * changed IOPTEs. In other word, these two are interdependent and can
> +	 * race.
> +	 *
> +	 * In a race, the RCU design (with its underlying memory barriers) can
> +	 * ensure the invalidation array to always get updated before loaded.
> +	 *
> +	 * smp_mb() is used here, paired with the smp_mb() following the array
> +	 * update in a concurrent attach, to ensure:
> +	 *  - HW sees the new IOPTEs if it walks after STE installation
> +	 *  - Invalidation thread sees the updated array with the new ASID.
> +	 *
> +	 *  [CPU0]                        | [CPU1]
> +	 *                                |
> +	 *  change IOPTEs and TLB flush:  |
> +	 *  arm_smmu_domain_inv_range() { | arm_smmu_install_new_domain_invs {
> +	 *    ...                         |   rcu_assign_pointer(new_invs);
> +	 *    smp_mb(); // ensure IOPTEs  |   smp_mb(); // ensure new_invs
> +	 *    ...                         |   kfree_rcu(old_invs, rcu);
> +	 *    // load invalidation array  | }
> +	 *    invs = rcu_dereference();   | arm_smmu_install_ste_for_dev {
> +	 *                                |   STE = TTB0 // read new IOPTEs
> +	 */
> +	smp_mb();
> +
> +	rcu_read_lock();
> +	invs = rcu_dereference(smmu_domain->invs);
> +
> +	/*
> +	 * Avoid locking unless ATS is being used. No ATC invalidation can be
> +	 * going on after a domain is detached.
> +	 */
> +	if (invs->has_ats) {
> +		read_lock(&invs->rwlock);
> +		__arm_smmu_domain_inv_range(invs, iova, size, granule, leaf);
> +		read_unlock(&invs->rwlock);
> +	} else {
> +		__arm_smmu_domain_inv_range(invs, iova, size, granule, leaf);
> +	}
> +
> +	rcu_read_unlock();
> +}
> +
>  static void arm_smmu_tlb_inv_page_nosync(struct iommu_iotlb_gather *gather,
>  					 unsigned long iova, size_t granule,
>  					 void *cookie)
> @@ -3280,6 +3478,12 @@ arm_smmu_install_new_domain_invs(struct arm_smmu_attach_state *state)
>  		return;
>  
>  	rcu_assign_pointer(*invst->invs_ptr, invst->new_invs);
> +	/*
> +	 * We are committed to updating the STE. Ensure the invalidation array
> +	 * is visable to concurrent map/unmap threads, and acquire any racying
> +	 * IOPTE updates.
> +	 */
> +	smp_mb();
>  	kfree_rcu(invst->old_invs, rcu);
>  }


s/visable/visible/ s/racying/racing/


Anyway, if I understand the above correctly, the smb_mb() is for:

  arm_smmu_domain_inv_range() 		arm_smmu_install_new_domain_invs()

    [W] IOPTE				  [Wrel] smmu_domain->invs
    smp_mb()				  smp_mb()
    [Lacq] smmu_domain->invs		  [L] IOPTE

Right? But I'm not sure about your 'HW sees the new IOPTEs' claim; that
very much depend on what coherency domain the relevant hardware plays
in. For smp_mb() to work, the hardware must be in the ISH domain, while
typically devices are (if I remember my arrrrgh64 correctly) in the OSH.

Please clarify and all that ;-)


From david at ixit.cz  Tue Dec 16 01:13:18 2025
From: david at ixit.cz (David Heidelberg)
Date: Tue, 16 Dec 2025 10:13:18 +0100
Subject: [PATCH 4/4] Input: stmfts - use client to make future code
 cleaner
In-Reply-To: <hpmm5fhs74swrhkneaif4s5dquqeclujdlua7ygmkvcmtf6n4t@rsahxu23xwfp>
References: <20251215-fts-fixes-v1-0-8c1e3a63ebf1@ixit.cz>
 <20251215-fts-fixes-v1-4-8c1e3a63ebf1@ixit.cz>
 <hpmm5fhs74swrhkneaif4s5dquqeclujdlua7ygmkvcmtf6n4t@rsahxu23xwfp>
Message-ID: <f240f2d4-c691-4166-bd5a-4bd2fbe4d736@ixit.cz>

On 16/12/2025 07:13, Dmitry Torokhov wrote:
> Hi David,
> 
> On Mon, Dec 15, 2025 at 03:30:04PM +0100, David Heidelberg via B4 Relay wrote:
>> From: Petr Hodina <petr.hodina at protonmail.com>
>>
>> Make code cleaner, compiler will optimize it away anyway.
>>
>> Preparation for FTM5 support, where more steps are needed.
>>
>> Signed-off-by: Petr Hodina <petr.hodina at protonmail.com>
>> Signed-off-by: David Heidelberg <david at ixit.cz>
>> ---
>>   drivers/input/touchscreen/stmfts.c | 3 ++-
>>   1 file changed, 2 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
>> index 4b166b0a9a5a6..06845a00348cc 100644
>> --- a/drivers/input/touchscreen/stmfts.c
>> +++ b/drivers/input/touchscreen/stmfts.c
>> @@ -747,9 +747,10 @@ static int stmfts_runtime_suspend(struct device *dev)
>>   static int stmfts_runtime_resume(struct device *dev)
>>   {
>>   	struct stmfts_data *sdata = dev_get_drvdata(dev);
>> +	struct i2c_client *client = sdata->client;
>>   	int ret;
>>   
>> -	ret = i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_OUT);
>> +	ret = i2c_smbus_write_byte(client, STMFTS_SLEEP_OUT);
> 
> Sorry but I do not see how using a temporary cleans things up compared
> to a simple structure member access, given that it happens only once
> here.

Thank you for applying rest of patchset.

This one can be postponed together with introducing fts5 support (where 
we need do more steps here).

David

> 
>>   	if (ret)
>>   		dev_err(dev, "failed to resume device: %d\n", ret);
>>   
>>
> 
> Thanks.
> 

-- 
David Heidelberg



From sudeep.holla at arm.com  Tue Dec 16 01:14:52 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Tue, 16 Dec 2025 09:14:52 +0000
Subject: [PATCH] dt-bindings: arm: vexpress-config: Update clock and
 regulator node names
In-Reply-To: <20251215212914.3323741-1-robh@kernel.org>
References: <20251215212914.3323741-1-robh@kernel.org>
Message-ID: <20251216-proud-centipede-of-reward-ad165b@sudeepholla>

On Mon, Dec 15, 2025 at 03:29:14PM -0600, Rob Herring (Arm) wrote:
> The clock and regulator node names were updated to use standard node names,
> but the binding wasn't updated.
> 

I assume you will be taking this via your tree itself.

Reviewed-by: Sudeep Holla <sudeep.holla at arm.com>

-- 
Regards,
Sudeep


From ryan.roberts at arm.com  Tue Dec 16 01:16:58 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Tue, 16 Dec 2025 09:16:58 +0000
Subject: [PATCH v2 3/3] randomize_kstack: Unify random source across
 arches
In-Reply-To: <CAMj1kXHaqfEqDpvC-iC1fUn+JpTj=oqfM2sh+sbaC8_PBVHBUQ@mail.gmail.com>
References: <20251215163520.1144179-1-ryan.roberts@arm.com>
 <20251215163520.1144179-4-ryan.roberts@arm.com>
 <202512160024.B688A8D0@keescook>
 <CAMj1kXHaqfEqDpvC-iC1fUn+JpTj=oqfM2sh+sbaC8_PBVHBUQ@mail.gmail.com>
Message-ID: <9ae8655f-e537-43bb-ae0e-3067d2481d79@arm.com>

On 16/12/2025 08:30, Ard Biesheuvel wrote:
> On Tue, 16 Dec 2025 at 09:27, Kees Cook <kees at kernel.org> wrote:
>>
>> On Mon, Dec 15, 2025 at 04:35:17PM +0000, Ryan Roberts wrote:
>>> [...]
>>> @@ -45,9 +46,22 @@ DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
>>>  #define KSTACK_OFFSET_MAX(x) ((x) & 0b1111111100)
>>>  #endif
>>>
>>> +DECLARE_PER_CPU(struct rnd_state, kstack_rnd_state);
>>> +
>>> +static __always_inline u32 get_kstack_offset(void)
>>> +{
>>> +     struct rnd_state *state;
>>> +     u32 rnd;
>>> +
>>> +     state = &get_cpu_var(kstack_rnd_state);
>>> +     rnd = prandom_u32_state(state);
>>> +     put_cpu_var(kstack_rnd_state);
>>> +
>>> +     return rnd;
>>> +}
>>> [...]
>>> -static inline void random_kstack_task_init(struct task_struct *tsk)
>>> +static int random_kstack_init(void)
>>>  {
>>> -     tsk->kstack_offset = 0;
>>> +     prandom_seed_full_state(&kstack_rnd_state);
>>> +     return 0;
>>>  }
>>> +
>>> +late_initcall(random_kstack_init);
>>
>> Doesn't this need to be run for every CPU? (And how does hotplug work
>> for such things?) And doesn't it need a get_cpu_var?
>>
> 
> 
>  prandom_seed_full_state() takes a 'struct rnd_state __percpu
> *pcpu_state', and performs the initialization for all possible CPUs.

Yes, indeed, prandom_seed_full_state() is initializing all possible CPUs so it
doesn't matter if it gets migrated. I believe this is correct as is.

void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state)
{
	int i;

	for_each_possible_cpu(i) {
		struct rnd_state *state = per_cpu_ptr(pcpu_state, i);
		u32 seeds[4];

		get_random_bytes(&seeds, sizeof(seeds));
		state->s1 = __seed(seeds[0],   2U);
		state->s2 = __seed(seeds[1],   8U);
		state->s3 = __seed(seeds[2],  16U);
		state->s4 = __seed(seeds[3], 128U);

		prandom_warmup(state);
	}
}



From ilias.apalodimas at linaro.org  Tue Dec 16 01:19:39 2025
From: ilias.apalodimas at linaro.org (Ilias Apalodimas)
Date: Tue, 16 Dec 2025 11:19:39 +0200
Subject: [PATCH v2 09/17] efi: stmm: Make use of tee bus methods
In-Reply-To: <b70ad65c88a82cf56c93cf17cf326213f8273e37.1765791463.git.u.kleine-koenig@baylibre.com>
References: <cover.1765791463.git.u.kleine-koenig@baylibre.com> <b70ad65c88a82cf56c93cf17cf326213f8273e37.1765791463.git.u.kleine-koenig@baylibre.com>
Message-ID: <CAC_iWj+TevKq7TzPQ4_eEhu0rJJ03PV=ASf7SwTszp-mJY6Vzw@mail.gmail.com>

On Mon, 15 Dec 2025 at 16:17, Uwe Kleine-K?nig
<u.kleine-koenig at baylibre.com> wrote:
>
> The tee bus got dedicated callbacks for probe and remove.
> Make use of these. This fixes a runtime warning about the driver needing
> to be converted to the bus methods.
>
> Reviewed-by: Sumit Garg <sumit.garg at oss.qualcomm.com>
> Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig at baylibre.com>
> ---

Reviewed-by: Ilias Apalodimas <ilias.apalodimas at linaro.org>

>  drivers/firmware/efi/stmm/tee_stmm_efi.c | 11 +++++------
>  1 file changed, 5 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/firmware/efi/stmm/tee_stmm_efi.c b/drivers/firmware/efi/stmm/tee_stmm_efi.c
> index 5903811858b6..7b04dd649629 100644
> --- a/drivers/firmware/efi/stmm/tee_stmm_efi.c
> +++ b/drivers/firmware/efi/stmm/tee_stmm_efi.c
> @@ -520,8 +520,9 @@ static void tee_stmm_restore_efivars_generic_ops(void)
>         efivars_generic_ops_register();
>  }
>
> -static int tee_stmm_efi_probe(struct device *dev)
> +static int tee_stmm_efi_probe(struct tee_client_device *tee_dev)
>  {
> +       struct device *dev = &tee_dev->dev;
>         struct tee_ioctl_open_session_arg sess_arg;
>         efi_status_t ret;
>         int rc;
> @@ -571,21 +572,19 @@ static int tee_stmm_efi_probe(struct device *dev)
>         return 0;
>  }
>
> -static int tee_stmm_efi_remove(struct device *dev)
> +static void tee_stmm_efi_remove(struct tee_client_device *dev)
>  {
>         tee_stmm_restore_efivars_generic_ops();
> -
> -       return 0;
>  }
>
>  MODULE_DEVICE_TABLE(tee, tee_stmm_efi_id_table);
>
>  static struct tee_client_driver tee_stmm_efi_driver = {
>         .id_table       = tee_stmm_efi_id_table,
> +       .probe          = tee_stmm_efi_probe,
> +       .remove         = tee_stmm_efi_remove,
>         .driver         = {
>                 .name           = "tee-stmm-efi",
> -               .probe          = tee_stmm_efi_probe,
> -               .remove         = tee_stmm_efi_remove,
>         },
>  };
>
> --
> 2.47.3
>


From ilias.apalodimas at linaro.org  Tue Dec 16 01:20:52 2025
From: ilias.apalodimas at linaro.org (Ilias Apalodimas)
Date: Tue, 16 Dec 2025 11:20:52 +0200
Subject: [PATCH v2 08/17] efi: stmm: Make use of module_tee_client_driver()
In-Reply-To: <6a56ee61e485703d548e9e44d53b2920b4e43ca6.1765791463.git.u.kleine-koenig@baylibre.com>
References: <cover.1765791463.git.u.kleine-koenig@baylibre.com> <6a56ee61e485703d548e9e44d53b2920b4e43ca6.1765791463.git.u.kleine-koenig@baylibre.com>
Message-ID: <CAC_iWjLG7o96E=9W-cjJ=_622RFg-b9t6hQnMrSmgHS+ThaXyw@mail.gmail.com>

On Mon, 15 Dec 2025 at 16:17, Uwe Kleine-K?nig
<u.kleine-koenig at baylibre.com> wrote:
>
> Reduce boilerplate by using the newly introduced module_tee_client_driver().
> That takes care of assigning the driver's bus, so the explicit assigning
> in this driver can be dropped.
>
> Reviewed-by: Sumit Garg <sumit.garg at oss.qualcomm.com>
> Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig at baylibre.com>
> ---

Acked-by: Ilias Apalodimas <ilias.apalodimas at linaro.org>

>  drivers/firmware/efi/stmm/tee_stmm_efi.c | 14 +-------------
>  1 file changed, 1 insertion(+), 13 deletions(-)
>
> diff --git a/drivers/firmware/efi/stmm/tee_stmm_efi.c b/drivers/firmware/efi/stmm/tee_stmm_efi.c
> index 65c0fe1ba275..5903811858b6 100644
> --- a/drivers/firmware/efi/stmm/tee_stmm_efi.c
> +++ b/drivers/firmware/efi/stmm/tee_stmm_efi.c
> @@ -584,24 +584,12 @@ static struct tee_client_driver tee_stmm_efi_driver = {
>         .id_table       = tee_stmm_efi_id_table,
>         .driver         = {
>                 .name           = "tee-stmm-efi",
> -               .bus            = &tee_bus_type,
>                 .probe          = tee_stmm_efi_probe,
>                 .remove         = tee_stmm_efi_remove,
>         },
>  };
>
> -static int __init tee_stmm_efi_mod_init(void)
> -{
> -       return driver_register(&tee_stmm_efi_driver.driver);
> -}
> -
> -static void __exit tee_stmm_efi_mod_exit(void)
> -{
> -       driver_unregister(&tee_stmm_efi_driver.driver);
> -}
> -
> -module_init(tee_stmm_efi_mod_init);
> -module_exit(tee_stmm_efi_mod_exit);
> +module_tee_client_driver(tee_stmm_efi_driver);
>
>  MODULE_LICENSE("GPL");
>  MODULE_AUTHOR("Ilias Apalodimas <ilias.apalodimas at linaro.org>");
> --
> 2.47.3
>


From sudeep.holla at arm.com  Tue Dec 16 01:25:40 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Tue, 16 Dec 2025 09:25:40 +0000
Subject: [PATCH] dt-bindings: arm,vexpress-juno: Allow interrupt-map
 properties in bus node
In-Reply-To: <20251215212932.3324144-1-robh@kernel.org>
References: <20251215212932.3324144-1-robh@kernel.org>
Message-ID: <20251216-thick-zealous-shrimp-b7afb1@sudeepholla>

On Mon, Dec 15, 2025 at 03:29:32PM -0600, Rob Herring (Arm) wrote:
> Allow interrupt-map properties which are already used in the bus node.
> 

I assume you will be taking this via your tree itself.

Reviewed-by: Sudeep Holla <sudeep.holla at arm.com>

-- 
Regards,
Sudeep


From jackmanb at google.com  Tue Dec 16 02:10:46 2025
From: jackmanb at google.com (Brendan Jackman)
Date: Tue, 16 Dec 2025 10:10:46 +0000
Subject: [PATCH 2/2] arm64: mmu: use pagetable_alloc_nolock() while stop_machine()
In-Reply-To: <aT/drjN1BkvyAGoi@e129823.arm.com>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com> <20251212161832.2067134-3-yeoreum.yun@arm.com>
 <CA+i-1C2e7QNTy5u=HF7tLsLXLq4xYbMTCbNjWGAxHz4uwgR05g@mail.gmail.com>
 <aT5/y3cSGIzi2K+m@e129823.arm.com> <DEYOI8H2OESD.1H56D3H8HKILB@google.com>
 <aT/WOAr4osoJWaMS@e129823.arm.com> <DEYP7JSVTB9D.3EFN2KEHH3O79@google.com> <aT/drjN1BkvyAGoi@e129823.arm.com>
Message-ID: <DEZK5U2YP6I0.27VJHSVK14646@google.com>

On Mon Dec 15, 2025 at 10:06 AM UTC, Yeoreum Yun wrote:
[snip]
>> Overall I am feeling a bit uncomfortable about this use of _nolock, but
>> I am also feeling pretty ignorant about PREEMPT_RT and also about this
>> arm64 code, so I am hesitant to suggest alternatives, I hope someone
>> else can offer some input here...
>
> I understand. However, as I mentioned earlier,
> my main intention was to hear opinions specifically about memory contention.
>
> That said, if there is no memory contention,
> I don?t think using the _nolock API is necessarily a bad approach.


> In fact, I believe a bigger issue is that, under PREEMPT_RT,
> code that uses the regular memory allocation APIs may give users the false impression
> that those APIs are ?safe to use,? even though they are not.

Yeah, I share this concern. I would bet I have written code that's
broken under PREEMPT_RT (luckily only in Google's kernel fork). The
comment for GFP_ATOMIC says:

 * %GFP_ATOMIC users can not sleep and need the allocation to succeed. A lower
 * watermark is applied to allow access to "atomic reserves".
 * The current implementation doesn't support NMI and few other strict
 * non-preemptive contexts (e.g. raw_spin_lock). The same applies to %GFP_NOWAIT.

It kinda sounds like it's supposed to be OK to use GFP_ATOMIC in a
normal preempt_disable() context. So do you know exactly why it's
invalid to use it in this stop_machine() context here? Maybe we need to
update this comment. Or, maybe actually we need to fix the allocator so
that GFP_ATOMIC allocs are safe in this context?


From ben.horgan at arm.com  Tue Dec 16 02:14:37 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Tue, 16 Dec 2025 10:14:37 +0000
Subject: [RFC PATCH 08/38] arm_mpam: resctrl: Pick the caches we will use
 as resctrl resources
In-Reply-To: <c0139cdf-9263-4051-938d-cb86233399b0@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-9-james.morse@arm.com>
 <c0139cdf-9263-4051-938d-cb86233399b0@arm.com>
Message-ID: <fc7ca984-544d-4aea-a644-0d9390f8469b@arm.com>

On 12/9/25 15:57, Ben Horgan wrote:
> Hi James,
> 
> On 12/5/25 21:58, James Morse wrote:
>> Systems with MPAM support may have a variety of control types at any
>> point of their system layout. We can only expose certain types of
>> control, and only if they exist at particular locations.
>>
>> Start with the well-know caches. These have to be depth 2 or 3
>> and support MPAM's cache portion bitmap controls, with a number
>> of portions fewer than resctrl's limit.
>>
>> Signed-off-by: James Morse <james.morse at arm.com>
>> ---
>>  drivers/resctrl/mpam_resctrl.c | 91 +++++++++++++++++++++++++++++++++-
>>  1 file changed, 89 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
>> index 320cebbd37ce..ceaf11af4fc1 100644
>> --- a/drivers/resctrl/mpam_resctrl.c
>> +++ b/drivers/resctrl/mpam_resctrl.c
>> @@ -60,10 +60,96 @@ struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l)
>>  	return &mpam_resctrl_controls[l].resctrl_res;
>>  }
>>  
>> +static bool cache_has_usable_cpor(struct mpam_class *class)
>> +{
>> +	struct mpam_props *cprops = &class->props;
>> +
>> +	if (!mpam_has_feature(mpam_feat_cpor_part, cprops))
>> +		return false;
>> +
>> +	/* resctrl uses u32 for all bitmap configurations */
>> +	return (class->props.cpbm_wd <= 32);
>> +}
> 
> cpbm_wd > 32 is not support properly in mpam_devices.c (e.g. reset and
> config value are limited to 32 bits.) and so we should consider just not
> adding the feature to the class in that case.

I'll keep this as is because the value still needs to be reset correctly
by mpam_devices.c even if it is not usable by resctrl.

> 
> Thanks,
> 
> Ben
> 
> 

Thanks,

Ben



From alexandru.elisei at arm.com  Tue Dec 16 02:30:49 2025
From: alexandru.elisei at arm.com (Alexandru Elisei)
Date: Tue, 16 Dec 2025 10:30:49 +0000
Subject: [PATCH v3 0/4] KVM: arm64: pKVM fixes
Message-ID: <20251216103053.47224-1-alexandru.elisei@arm.com>

v2 can be found at [1].

Similar to [2], when trying to run an unprotected VM on FVP with S1PIE enabled
and kvm-arm.mode=protected, writes to PIRE0_EL1 made by the guest in
__cpu_setup() are trapped by KVM and the BUG_ON(!r->access) is hit. That's
because HFGWTR_EL2.nPIRE0_EL1 is an inverse polarity trap and the FGT values for
the unprotected pKVM VCPU weren't being propagated from kvm_arch_vcpu_load().

Couldn't figure out how to run a protected pKVM VM, so that's untested.

Changelog v2->v3:
* Gathered Reviewed-by tags, thanks!
* In patch #2, KVM now calls bad_trap() instead of KVM_BUG(). Also changed patch
  subject to match.

[1] https://lore.kernel.org/kvmarm/20251215114409.212512-1-alexandru.elisei at arm.com/
[2] https://lore.kernel.org/all/20251112102853.47759-1-alexandru.elisei at arm.com/

Alexandru Elisei (4):
  KVM: arm64: Copy FGT traps to unprotected pKVM VCPU on VCPU load
  KVM: arm64: Inject UNDEF for a register trap without accessor
  KVM: arm64: Remove extra argument for __pvkm_host_{share,unshare}_hyp()
  KVM: arm64: Remove unused parameter in synchronize_vcpu_pstate()

 arch/arm64/kvm/hyp/include/hyp/switch.h | 2 +-
 arch/arm64/kvm/hyp/nvhe/hyp-main.c      | 3 +++
 arch/arm64/kvm/hyp/nvhe/pkvm.c          | 1 -
 arch/arm64/kvm/hyp/nvhe/switch.c        | 2 +-
 arch/arm64/kvm/hyp/vhe/switch.c         | 2 +-
 arch/arm64/kvm/mmu.c                    | 4 ++--
 arch/arm64/kvm/sys_regs.c               | 5 ++++-
 7 files changed, 12 insertions(+), 7 deletions(-)


base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
-- 
2.52.0



From alexandru.elisei at arm.com  Tue Dec 16 02:30:50 2025
From: alexandru.elisei at arm.com (Alexandru Elisei)
Date: Tue, 16 Dec 2025 10:30:50 +0000
Subject: [PATCH v3 1/4] KVM: arm64: Copy FGT traps to unprotected pKVM VCPU on VCPU load
In-Reply-To: <20251216103053.47224-1-alexandru.elisei@arm.com>
References: <20251216103053.47224-1-alexandru.elisei@arm.com>
Message-ID: <20251216103053.47224-2-alexandru.elisei@arm.com>

Commit fb10ddf35c1c ("KVM: arm64: Compute per-vCPU FGTs at vcpu_load()")
introduced per-VCPU FGT traps. For an unprotected pKVM VCPU, the untrusted
host FGT configuration is copied in pkvm_vcpu_init_traps(), which is called
from __pkvm_init_vcpu(). __pkvm_init_vcpu() is called once per VCPU (when
the VCPU is first run) which means that the uninitialized, zero, values for
the FGT registers end up being used for the entire lifetime of the VCPU.
This causes both unwanted traps (for the inverse polarity trap bits) and
the guest being allowed to access registers it shouldn't.

Fix it by copying the FGT traps for unprotected pKVM VCPUs when the
untrusted host loads the VCPU.

Fixes: fb10ddf35c1c ("KVM: arm64: Compute per-vCPU FGTs at vcpu_load()")
Acked-by: Will Deacon <will at kernel.org>
Tested-by: Fuad Tabba <tabba at google.com>
Reviewed-by: Fuad Tabba <tabba at google.com>
Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
---
 arch/arm64/kvm/hyp/nvhe/hyp-main.c | 3 +++
 arch/arm64/kvm/hyp/nvhe/pkvm.c     | 1 -
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index a7c689152f68..8ffbbce5e2ed 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -180,6 +180,9 @@ static void handle___pkvm_vcpu_load(struct kvm_cpu_context *host_ctxt)
 		/* Propagate WFx trapping flags */
 		hyp_vcpu->vcpu.arch.hcr_el2 &= ~(HCR_TWE | HCR_TWI);
 		hyp_vcpu->vcpu.arch.hcr_el2 |= hcr_el2 & (HCR_TWE | HCR_TWI);
+	} else {
+		memcpy(&hyp_vcpu->vcpu.arch.fgt, hyp_vcpu->host_vcpu->arch.fgt,
+		       sizeof(hyp_vcpu->vcpu.arch.fgt));
 	}
 }
 
diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index 8911338961c5..12b2acfbcfd1 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -172,7 +172,6 @@ static int pkvm_vcpu_init_traps(struct pkvm_hyp_vcpu *hyp_vcpu)
 
 		/* Trust the host for non-protected vcpu features. */
 		vcpu->arch.hcrx_el2 = host_vcpu->arch.hcrx_el2;
-		memcpy(vcpu->arch.fgt, host_vcpu->arch.fgt, sizeof(vcpu->arch.fgt));
 		return 0;
 	}
 
-- 
2.52.0



From alexandru.elisei at arm.com  Tue Dec 16 02:30:51 2025
From: alexandru.elisei at arm.com (Alexandru Elisei)
Date: Tue, 16 Dec 2025 10:30:51 +0000
Subject: [PATCH v3 2/4] KVM: arm64: Inject UNDEF for a register trap without accessor
In-Reply-To: <20251216103053.47224-1-alexandru.elisei@arm.com>
References: <20251216103053.47224-1-alexandru.elisei@arm.com>
Message-ID: <20251216103053.47224-3-alexandru.elisei@arm.com>

Configuring a register trap without specifying an accessor function is
abviously a bug. Instead of calling die() when that happens, let's be a
bit more helpful and print the register encoding. Also inject an
undefined instruction exception in the guest, similar to other unhandled
register accesses.

Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
---
 arch/arm64/kvm/sys_regs.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index c8fd7c6a12a1..88a57ca36d96 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -4668,7 +4668,10 @@ static void perform_access(struct kvm_vcpu *vcpu,
 	 * that we don't know how to handle. This certainly qualifies
 	 * as a gross bug that should be fixed right away.
 	 */
-	BUG_ON(!r->access);
+	if (!r->access) {
+		bad_trap(vcpu, params, r, "register access");
+		return;
+	}
 
 	/* Skip instruction if instructed so */
 	if (likely(r->access(vcpu, params, r)))
-- 
2.52.0



From alexandru.elisei at arm.com  Tue Dec 16 02:30:52 2025
From: alexandru.elisei at arm.com (Alexandru Elisei)
Date: Tue, 16 Dec 2025 10:30:52 +0000
Subject: [PATCH v3 3/4] KVM: arm64: Remove extra argument for __pvkm_host_{share,unshare}_hyp()
In-Reply-To: <20251216103053.47224-1-alexandru.elisei@arm.com>
References: <20251216103053.47224-1-alexandru.elisei@arm.com>
Message-ID: <20251216103053.47224-4-alexandru.elisei@arm.com>

__pvkm_host_share_hyp() and __pkvm_host_unshare_hyp() both have one
parameter, the pfn, not two. Even though correctness isn't impacted because
the SMCCC handlers pass the first argument and ignore the second one, let's
call the functions with the proper number of arguments.

Reviewed-by: Fuad Tabba <tabba at google.com>
Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
---
 arch/arm64/kvm/mmu.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index 48d7c372a4cd..124404eb208d 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -497,7 +497,7 @@ static int share_pfn_hyp(u64 pfn)
 	this->count = 1;
 	rb_link_node(&this->node, parent, node);
 	rb_insert_color(&this->node, &hyp_shared_pfns);
-	ret = kvm_call_hyp_nvhe(__pkvm_host_share_hyp, pfn, 1);
+	ret = kvm_call_hyp_nvhe(__pkvm_host_share_hyp, pfn);
 unlock:
 	mutex_unlock(&hyp_shared_pfns_lock);
 
@@ -523,7 +523,7 @@ static int unshare_pfn_hyp(u64 pfn)
 
 	rb_erase(&this->node, &hyp_shared_pfns);
 	kfree(this);
-	ret = kvm_call_hyp_nvhe(__pkvm_host_unshare_hyp, pfn, 1);
+	ret = kvm_call_hyp_nvhe(__pkvm_host_unshare_hyp, pfn);
 unlock:
 	mutex_unlock(&hyp_shared_pfns_lock);
 
-- 
2.52.0



From alexandru.elisei at arm.com  Tue Dec 16 02:30:53 2025
From: alexandru.elisei at arm.com (Alexandru Elisei)
Date: Tue, 16 Dec 2025 10:30:53 +0000
Subject: [PATCH v3 4/4] KVM: arm64: Remove unused parameter in synchronize_vcpu_pstate()
In-Reply-To: <20251216103053.47224-1-alexandru.elisei@arm.com>
References: <20251216103053.47224-1-alexandru.elisei@arm.com>
Message-ID: <20251216103053.47224-5-alexandru.elisei@arm.com>

synchronize_vcpu_pstate() doesn't make use of the reference to exit_code,
remove the parameter.

Reviewed-by: Fuad Tabba <tabba at google.com>
Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
---
 arch/arm64/kvm/hyp/include/hyp/switch.h | 2 +-
 arch/arm64/kvm/hyp/nvhe/switch.c        | 2 +-
 arch/arm64/kvm/hyp/vhe/switch.c         | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index c5d5e5b86eaf..afecbdd3c1e9 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -854,7 +854,7 @@ static inline bool kvm_hyp_handle_exit(struct kvm_vcpu *vcpu, u64 *exit_code,
 	return false;
 }
 
-static inline void synchronize_vcpu_pstate(struct kvm_vcpu *vcpu, u64 *exit_code)
+static inline void synchronize_vcpu_pstate(struct kvm_vcpu *vcpu)
 {
 	/*
 	 * Check for the conditions of Cortex-A510's #2077057. When these occur
diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c
index d3b9ec8a7c28..779089e42681 100644
--- a/arch/arm64/kvm/hyp/nvhe/switch.c
+++ b/arch/arm64/kvm/hyp/nvhe/switch.c
@@ -211,7 +211,7 @@ static inline bool fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
 {
 	const exit_handler_fn *handlers = kvm_get_exit_handler_array(vcpu);
 
-	synchronize_vcpu_pstate(vcpu, exit_code);
+	synchronize_vcpu_pstate(vcpu);
 
 	/*
 	 * Some guests (e.g., protected VMs) are not be allowed to run in
diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c
index 9984c492305a..9db3f11a4754 100644
--- a/arch/arm64/kvm/hyp/vhe/switch.c
+++ b/arch/arm64/kvm/hyp/vhe/switch.c
@@ -536,7 +536,7 @@ static const exit_handler_fn hyp_exit_handlers[] = {
 
 static inline bool fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
 {
-	synchronize_vcpu_pstate(vcpu, exit_code);
+	synchronize_vcpu_pstate(vcpu);
 
 	/*
 	 * If we were in HYP context on entry, adjust the PSTATE view
-- 
2.52.0



From maz at kernel.org  Tue Dec 16 02:41:11 2025
From: maz at kernel.org (Marc Zyngier)
Date: Tue, 16 Dec 2025 10:41:11 +0000
Subject: [PATCH 11/32] KVM: arm64: gic-v5: Trap and emulate ICH_PPI_HMRx_EL1 accesses
In-Reply-To: <20251212152215.675767-12-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	<20251212152215.675767-12-sascha.bischoff@arm.com>
Message-ID: <86a4ziogjc.wl-maz@kernel.org>

On Fri, 12 Dec 2025 15:22:39 +0000,
Sascha Bischoff <Sascha.Bischoff at arm.com> wrote:
> 
> The ICC_PPI_HMRx_EL1 register is used to determine which PPIs use
> Level-sensitive semantics, and which use Edge. For a GICv5 guest, the
> correct view of the virtual PPIs must be provided to the guest.

s/ICH/ICC/ in $SUBJECT

> 
> The GICv5 architecture doesn't provide an ICV_PPI_HMRx_EL1 or

The spec disagree with you here (see 9.5.4).

> ICH_PPI_HMRx_EL2 register, and therefore all guest accesses must be
> trapped to avoid the guest directly accessing the host's
> ICC_PPI_HMRx_EL1 state. This change hence configures the FGTs to
> always trap and emulate guest accesses to the HMR running a
> GICv5-based guest.

The real question is what we gain by emulating this register, given
that virtual PPIs are only guaranteed to exist if the physical version
exist. If they exist, then the handling mode is defined by the
that HW, and we can't deviate from it.

Given that, I can't really see the point in trapping something that is
bound to be the same thing as the host, unless this comes with
additional restrictions, for example a mask of interrupts that are
actually exposed to the guest.

Or am I missing something?

> 
> This change also introduces the struct vgic_v5_cpu_if, which includes
> the vgic_hmr. This is not yet populated as it can only be correctly
> populated at vcpu reset time. This will be introduced in a subsquent
> change.
> 
> Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
> ---
>  arch/arm64/kvm/config.c   |  6 +++++-
>  arch/arm64/kvm/sys_regs.c | 26 ++++++++++++++++++++++++++
>  include/kvm/arm_vgic.h    |  5 +++++
>  3 files changed, 36 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
> index cbdd8ac90f4d0..7683407ce052a 100644
> --- a/arch/arm64/kvm/config.c
> +++ b/arch/arm64/kvm/config.c
> @@ -1586,8 +1586,12 @@ static void __compute_ich_hfgrtr(struct kvm_vcpu *vcpu)
>  {
>  	__compute_fgt(vcpu, ICH_HFGRTR_EL2);
>  
> -	/* ICC_IAFFIDR_EL1 *always* needs to be trapped when running a guest */
> +	/*
> +	 * ICC_IAFFIDR_EL1 and ICH_PPI_HMRx_EL1 *always* needs to be
> +	 * trapped when running a guest.
> +	 **/
>  	*vcpu_fgt(vcpu, ICH_HFGRTR_EL2) &= ~ICH_HFGRTR_EL2_ICC_IAFFIDR_EL1;
> +	*vcpu_fgt(vcpu, ICH_HFGRTR_EL2) &= ~ICH_HFGRTR_EL2_ICC_PPI_HMRn_EL1;
>  }
>  
>  void kvm_vcpu_load_fgt(struct kvm_vcpu *vcpu)
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index 31c08fd591d08..a4ae034340040 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -699,6 +699,30 @@ static bool access_gicv5_iaffid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  	return true;
>  }
>  
> +static bool access_gicv5_ppi_hmr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +				 const struct sys_reg_desc *r)
> +{
> +	if (!vgic_is_v5(vcpu->kvm))
> +		return undef_access(vcpu, p, r);
> +
> +	if (p->is_write)
> +		return ignore_write(vcpu, p);
> +
> +	/*
> +	 * For GICv5 VMs, the IAFFID value is the same as the VPE ID. The VPE ID
> +	 * is the same as the VCPU's ID.
> +	 */

Unrelated comment?

> +
> +	if (p->Op2 == 0) {	/* ICC_PPI_HMR0_EL1 */
> +		p->regval = vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_hmr[0];
> +	} else {		/* ICC_PPI_HMR1_EL1 */
> +		p->regval = vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_hmr[1];
> +	}

nit: Can probably be written as:

	p->regval = vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_hmr[p->Op2];

Thanks,

	M.

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


From tabba at google.com  Tue Dec 16 02:43:49 2025
From: tabba at google.com (Fuad Tabba)
Date: Tue, 16 Dec 2025 10:43:49 +0000
Subject: [PATCH v3 0/4] KVM: arm64: pKVM fixes
In-Reply-To: <20251216103053.47224-1-alexandru.elisei@arm.com>
References: <20251216103053.47224-1-alexandru.elisei@arm.com>
Message-ID: <CA+EHjTwoimWFrLbL97nhBsKXAdDdSCrcb__MCacVHnk7Hvc2tA@mail.gmail.com>

Hi Alexandru,

On Tue, 16 Dec 2025 at 10:31, Alexandru Elisei <alexandru.elisei at arm.com> wrote:
>
> v2 can be found at [1].
>
> Similar to [2], when trying to run an unprotected VM on FVP with S1PIE enabled
> and kvm-arm.mode=protected, writes to PIRE0_EL1 made by the guest in
> __cpu_setup() are trapped by KVM and the BUG_ON(!r->access) is hit. That's
> because HFGWTR_EL2.nPIRE0_EL1 is an inverse polarity trap and the FGT values for
> the unprotected pKVM VCPU weren't being propagated from kvm_arch_vcpu_load().
>
> Couldn't figure out how to run a protected pKVM VM, so that's untested.

Hopefully this will change soon [1]!

I applied this to the pKVM/Android stack, and tested it with protected
VMs as well as non-protected VMs.

For the series:
Tested-by: Fuad Tabba <tabba at google.com>
Reviewed-by: Fuad Tabba <tabba at google.com>

Cheers,
/fuad

[1] https://lore.kernel.org/all/aTMPn0dBbSVUwwJ1 at willie-the-truck/


>
> Changelog v2->v3:
> * Gathered Reviewed-by tags, thanks!
> * In patch #2, KVM now calls bad_trap() instead of KVM_BUG(). Also changed patch
>   subject to match.
>
> [1] https://lore.kernel.org/kvmarm/20251215114409.212512-1-alexandru.elisei at arm.com/
> [2] https://lore.kernel.org/all/20251112102853.47759-1-alexandru.elisei at arm.com/
>
> Alexandru Elisei (4):
>   KVM: arm64: Copy FGT traps to unprotected pKVM VCPU on VCPU load
>   KVM: arm64: Inject UNDEF for a register trap without accessor
>   KVM: arm64: Remove extra argument for __pvkm_host_{share,unshare}_hyp()
>   KVM: arm64: Remove unused parameter in synchronize_vcpu_pstate()
>
>  arch/arm64/kvm/hyp/include/hyp/switch.h | 2 +-
>  arch/arm64/kvm/hyp/nvhe/hyp-main.c      | 3 +++
>  arch/arm64/kvm/hyp/nvhe/pkvm.c          | 1 -
>  arch/arm64/kvm/hyp/nvhe/switch.c        | 2 +-
>  arch/arm64/kvm/hyp/vhe/switch.c         | 2 +-
>  arch/arm64/kvm/mmu.c                    | 4 ++--
>  arch/arm64/kvm/sys_regs.c               | 5 ++++-
>  7 files changed, 12 insertions(+), 7 deletions(-)
>
>
> base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
> --
> 2.52.0
>


From vladimir.zapolskiy at linaro.org  Tue Dec 16 02:47:46 2025
From: vladimir.zapolskiy at linaro.org (Vladimir Zapolskiy)
Date: Tue, 16 Dec 2025 12:47:46 +0200
Subject: [PATCH v2 05/11] dt-bindings: clock: qcom: Add support for CAMCC
 for Kaanapali
In-Reply-To: <20251125-kaanapali-mmcc-v2-v2-5-fb44e78f300b@oss.qualcomm.com>
References: <20251125-kaanapali-mmcc-v2-v2-0-fb44e78f300b@oss.qualcomm.com>
 <20251125-kaanapali-mmcc-v2-v2-5-fb44e78f300b@oss.qualcomm.com>
Message-ID: <3658e6cc-755c-4b38-aec7-b8bfdd7c8bd2@linaro.org>

Hi Taniya.

On 11/25/25 19:45, Taniya Das wrote:
> Update the compatible and the bindings for CAMCC support on Kaanapali
> SoC.
> 
> Signed-off-by: Taniya Das <taniya.das at oss.qualcomm.com>
> ---
>   .../bindings/clock/qcom,sm8450-camcc.yaml          |   6 +
>   .../clock/qcom,kaanapali-cambistmclkcc.h           |  33 +++++
>   include/dt-bindings/clock/qcom,kaanapali-camcc.h   | 147 +++++++++++++++++++++
>   3 files changed, 186 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml
> index c1e06f39431e68a3cd2f6c2dba84be2a3c143bb1..3ec9bf4d82ad3b0fbb3e58fe312a416b3580c30c 100644
> --- a/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml
> +++ b/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml
> @@ -15,6 +15,8 @@ description: |
>     domains on SM8450.
>   
>     See also:
> +    include/dt-bindings/clock/qcom,kaanapali-camcc.h
> +    include/dt-bindings/clock/qcom,kaanapali-cambistmclkcc.h
>       include/dt-bindings/clock/qcom,sm8450-camcc.h
>       include/dt-bindings/clock/qcom,sm8550-camcc.h
>       include/dt-bindings/clock/qcom,sm8650-camcc.h
> @@ -22,6 +24,8 @@ description: |
>   properties:
>     compatible:
>       enum:
> +      - qcom,kaanapali-cambistmclkcc
> +      - qcom,kaanapali-camcc

I do have right the same review comment as the given for SM8750 CAMCC one.

The introduced qcom,kaanapali-cambistmclkcc does not inherit reset
controller or power domain controller properties, thus it should not be
added to the list of regular camera clock contollers.

Please create a new dt schema file for qcom,kaanapali-cambistmclkcc
and qcom,sm8750-cambistmclkcc IP descriptions.

>         - qcom,sm8450-camcc
>         - qcom,sm8475-camcc
>         - qcom,sm8550-camcc
> @@ -63,6 +67,8 @@ allOf:
>           compatible:
>             contains:
>               enum:
> +              - qcom,kaanapali-cambistmclkcc
> +              - qcom,kaanapali-camcc
>                 - qcom,sc8280xp-camcc
>                 - qcom,sm8450-camcc
>                 - qcom,sm8550-camcc
> diff --git a/include/dt-bindings/clock/qcom,kaanapali-cambistmclkcc.h b/include/dt-bindings/clock/qcom,kaanapali-cambistmclkcc.h
> new file mode 100644
> index 0000000000000000000000000000000000000000..ddb083b5289ecc5ddbf9ce0b8afa5e2b3bd7ccad
> --- /dev/null
> +++ b/include/dt-bindings/clock/qcom,kaanapali-cambistmclkcc.h
> @@ -0,0 +1,33 @@
> +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +
> +#ifndef _DT_BINDINGS_CLK_QCOM_CAM_BIST_MCLK_CC_KAANAPALI_H
> +#define _DT_BINDINGS_CLK_QCOM_CAM_BIST_MCLK_CC_KAANAPALI_H
> +
> +/* CAM_BIST_MCLK_CC clocks */
> +#define CAM_BIST_MCLK_CC_DEBUG_CLK				0
> +#define CAM_BIST_MCLK_CC_DEBUG_DIV_CLK_SRC			1
> +#define CAM_BIST_MCLK_CC_MCLK0_CLK				2
> +#define CAM_BIST_MCLK_CC_MCLK0_CLK_SRC				3
> +#define CAM_BIST_MCLK_CC_MCLK1_CLK				4
> +#define CAM_BIST_MCLK_CC_MCLK1_CLK_SRC				5
> +#define CAM_BIST_MCLK_CC_MCLK2_CLK				6
> +#define CAM_BIST_MCLK_CC_MCLK2_CLK_SRC				7
> +#define CAM_BIST_MCLK_CC_MCLK3_CLK				8
> +#define CAM_BIST_MCLK_CC_MCLK3_CLK_SRC				9
> +#define CAM_BIST_MCLK_CC_MCLK4_CLK				10
> +#define CAM_BIST_MCLK_CC_MCLK4_CLK_SRC				11
> +#define CAM_BIST_MCLK_CC_MCLK5_CLK				12
> +#define CAM_BIST_MCLK_CC_MCLK5_CLK_SRC				13
> +#define CAM_BIST_MCLK_CC_MCLK6_CLK				14
> +#define CAM_BIST_MCLK_CC_MCLK6_CLK_SRC				15
> +#define CAM_BIST_MCLK_CC_MCLK7_CLK				16
> +#define CAM_BIST_MCLK_CC_MCLK7_CLK_SRC				17
> +#define CAM_BIST_MCLK_CC_PLL0					18
> +#define CAM_BIST_MCLK_CC_PLL_TEST_CLK				19
> +#define CAM_BIST_MCLK_CC_PLL_TEST_DIV_CLK_SRC			20
> +#define CAM_BIST_MCLK_CC_SLEEP_CLK				21
> +
> +#endif

-- 
Best wishes,
Vladimir


From lorenzo.stoakes at oracle.com  Tue Dec 16 02:53:46 2025
From: lorenzo.stoakes at oracle.com (Lorenzo Stoakes)
Date: Tue, 16 Dec 2025 10:53:46 +0000
Subject: [PATCH v2 3/3] mm: rmap: support batched unmapping for file
 large folios
In-Reply-To: <eb871ca2-47c8-4b10-a61d-321716f6c147@linux.alibaba.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <af330c9ea188bd0f28189b1e6e5803f6de9d2abe.1765439381.git.baolin.wang@linux.alibaba.com>
 <70d1dedc-b4fc-4eb6-baf6-9e54b6a62249@lucifer.local>
 <eb871ca2-47c8-4b10-a61d-321716f6c147@linux.alibaba.com>
Message-ID: <b0cde352-0b8e-4330-8c05-fdbc68826e28@lucifer.local>

On Tue, Dec 16, 2025 at 01:48:52PM +0800, Baolin Wang wrote:
>
>
> On 2025/12/15 20:38, Lorenzo Stoakes wrote:
> > On Thu, Dec 11, 2025 at 04:16:56PM +0800, Baolin Wang wrote:
> > > Similar to folio_referenced_one(), we can apply batched unmapping for file
> > > large folios to optimize the performance of file folios reclamation.
> > >
> > > Performance testing:
> > > Allocate 10G clean file-backed folios by mmap() in a memory cgroup, and try to
> > > reclaim 8G file-backed folios via the memory.reclaim interface. I can observe
> > > 75% performance improvement on my Arm64 32-core server.
> >
> > Again, you must test on non-arm64 architectures and report the numbers for this
> > also.
>
> Yes, I've tested on the x86 machine, and will add the data in the commit
> message.
>
> > > W/o patch:
> > > real    0m1.018s
> > > user    0m0.000s
> > > sys     0m1.018s
> > >
> > > W/ patch:
> > > real	0m0.249s
> > > user	0m0.000s
> > > sys	0m0.249s
> > >
> > > Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
> > > ---
> > >   mm/rmap.c | 7 ++++---
> > >   1 file changed, 4 insertions(+), 3 deletions(-)
> > >
> > > diff --git a/mm/rmap.c b/mm/rmap.c
> > > index ec232165c47d..4c9d5777c8da 100644
> > > --- a/mm/rmap.c
> > > +++ b/mm/rmap.c
> > > @@ -1855,9 +1855,10 @@ static inline unsigned int folio_unmap_pte_batch(struct folio *folio,
> > >   	end_addr = pmd_addr_end(addr, vma->vm_end);
> > >   	max_nr = (end_addr - addr) >> PAGE_SHIFT;
> > >
> > > -	/* We only support lazyfree batching for now ... */
> > > -	if (!folio_test_anon(folio) || folio_test_swapbacked(folio))
> > > +	/* We only support lazyfree or file folios batching for now ... */
> > > +	if (folio_test_anon(folio) && folio_test_swapbacked(folio))
> >
> > Why is it now ok to support file-backed batched unmapping when it wasn't in
> > Barry's series (see [0])? You don't seem to be justifying this?
>
> Barry's series[0] is merely aimed at optimizing lazyfree anonymous large
> folios and does not continue to optimize anonymous large folios or
> file-backed large folios at that point.
>
> Subsequently, Barry sent out a new patch (see [1]) to optimize anonymous
> large folios. As for file-backed large folios, the batched unmapping support
> is relatively simple, since we only need to clear the PTE entries for
> file-backed large folios.

Yeah, but he sent an entire patch changing a bunch of logic to accommodate this,
you're just changing the conditional and not really justifying it in the commit
message?

It really needs a 'it is safe to allow this for file-backed because blah blah
blah'.

Is this relying on the prior commits you've added? If so you should say so.

If it was as easy as just changing the conditional then it begs the question as
to why Barry didn't do that in the first place :)

>
> > [0]:https://lore.kernel.org/all/20250214093015.51024-4-21cnbao at gmail.com/T/#u
>
> [1] https://lore.kernel.org/all/20250513084620.58231-1-21cnbao at gmail.com/
>
> > >   		return 1;
> > > +
> > >   	if (pte_unused(pte))
> > >   		return 1;
> > >
> > > @@ -2223,7 +2224,7 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
> > >   			 *
> > >   			 * See Documentation/mm/mmu_notifier.rst
> > >   			 */
> > > -			dec_mm_counter(mm, mm_counter_file(folio));
> > > +			add_mm_counter(mm, mm_counter_file(folio), -nr_pages);
> >
> > Was this just a bug before?
>
> Nope. Before this patch, we never supported batched unmapping for
> file-backed large folios, so the 'nr_pages' was always 1. After this patch,
> we should use the number of pages in this file-backed large folio.

Right ok :)

Cheers, Lorenzo


From lorenzo.stoakes at oracle.com  Tue Dec 16 02:54:33 2025
From: lorenzo.stoakes at oracle.com (Lorenzo Stoakes)
Date: Tue, 16 Dec 2025 10:54:33 +0000
Subject: [PATCH v2 3/3] mm: rmap: support batched unmapping for file
 large folios
In-Reply-To: <9e038290-70ff-458d-b46d-bc512c3442be@linux.alibaba.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <af330c9ea188bd0f28189b1e6e5803f6de9d2abe.1765439381.git.baolin.wang@linux.alibaba.com>
 <70d1dedc-b4fc-4eb6-baf6-9e54b6a62249@lucifer.local>
 <eb871ca2-47c8-4b10-a61d-321716f6c147@linux.alibaba.com>
 <CAGsJ_4xp40A3u=N5_mw00Eo6bPmFvctD3j=1Qmy3vOo2EmX3hA@mail.gmail.com>
 <9e038290-70ff-458d-b46d-bc512c3442be@linux.alibaba.com>
Message-ID: <e718cfdd-a39f-48f6-98c8-f17683f29bcf@lucifer.local>

On Tue, Dec 16, 2025 at 02:22:11PM +0800, Baolin Wang wrote:
>
>
> On 2025/12/16 14:13, Barry Song wrote:
> > > > >
> > > > > diff --git a/mm/rmap.c b/mm/rmap.c
> > > > > index ec232165c47d..4c9d5777c8da 100644
> > > > > --- a/mm/rmap.c
> > > > > +++ b/mm/rmap.c
> > > > > @@ -1855,9 +1855,10 @@ static inline unsigned int folio_unmap_pte_batch(struct folio *folio,
> > > > >       end_addr = pmd_addr_end(addr, vma->vm_end);
> > > > >       max_nr = (end_addr - addr) >> PAGE_SHIFT;
> > > > >
> > > > > -    /* We only support lazyfree batching for now ... */
> > > > > -    if (!folio_test_anon(folio) || folio_test_swapbacked(folio))
> > > > > +    /* We only support lazyfree or file folios batching for now ... */
> > > > > +    if (folio_test_anon(folio) && folio_test_swapbacked(folio))
> > > >
> > > > Why is it now ok to support file-backed batched unmapping when it wasn't in
> > > > Barry's series (see [0])? You don't seem to be justifying this?
> > >
> > > Barry's series[0] is merely aimed at optimizing lazyfree anonymous large
> > > folios and does not continue to optimize anonymous large folios or
> > > file-backed large folios at that point.
> >
> > Yep. At that time, I didn?t have an Android machine with a filesystem
> > that supported large folios, so I focused on lazyfree. But I
> > agree that lazyfree anon folios and file folios are quite
> > similar.
> >
> > >
> > > Subsequently, Barry sent out a new patch (see [1]) to optimize anonymous
> > > large folios. As for file-backed large folios, the batched unmapping
> > > support is relatively simple, since we only need to clear the PTE
> > > entries for file-backed large folios.
> >
> > Yep. It is actually quite straightforward to go from lazyfree
> > anon folios to file folios. Swap-backed anon folios are much
> > more tricky, though.
>
> Agree. Thanks Barry for reviewing and confirming.

OK that makes me less concerned, but you do need to put some more justification
in the commit message.

Cheers, Lorenzo


From Sascha.Bischoff at arm.com  Tue Dec 16 02:55:37 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Tue, 16 Dec 2025 10:55:37 +0000
Subject: [PATCH 23/32] KVM: arm64: gic-v5: Bump arch timer for GICv5
In-Reply-To: <86fr9boic5.wl-maz@kernel.org>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	 <20251212152215.675767-24-sascha.bischoff@arm.com>
	 <86fr9boic5.wl-maz@kernel.org>
Message-ID: <03acbb1d276e47d263caffd169c4789b504b59d8.camel@arm.com>

On Mon, 2025-12-15 at 15:50 +0000, Marc Zyngier wrote:
> On Fri, 12 Dec 2025 15:22:43 +0000,
> Sascha Bischoff <Sascha.Bischoff at arm.com> wrote:
> > 
> > Now that GICv5 has arrived, the arch timer requires some TLC to
> > address some of the key differences introduced with GICv5.
> > 
> > For PPIs on GICv5, the set_pending_state and queue_irq_unlock
> > irq_ops
> > are used as AP lists are not required at all for GICv5. The arch
> > timer
> > also introduces an irq_op - get_input_level. Extend the
> > arch-timer-provided irq_ops to include the two PPI ops for vgic_v5
> > guests.
> > 
> > When possible, DVI (Direct Virtual Interrupt) is set for PPIs when
> > using a vgic_v5, which directly inject the pending state in to the
> > guest. This means that the host never sees the interrupt for the
> > guest
> > for these interrupts. This has two impacts.
> > 
> > * First of all, the kvm_cpu_has_pending_timer check is updated to
> > ? explicitly check if the timers are expected to fire.
> > 
> > * Secondly, for mapped timers (which use DVI) they must be masked
> > on
> > ? the host prior to entering a GICv5 guest, and unmasked on the
> > return
> > ? path. This is handled in set_timer_irq_phys_masked.
> > 
> > The final, but rather important, change is that the architected
> > PPIs
> > for the timers are made mandatory for a GICv5 guest. Attempts to
> > set
> > them to anything else are actively rejected. Once a vgic_v5 is
> > initialised, the arch timer PPIs are also explicitly reinitialised
> > to
> > ensure the correct GICv5-compatible PPIs are used - this also adds
> > in
> > the GICv5 PPI type to the intid.
> > 
> > Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
> > ---
> > ?arch/arm64/kvm/arch_timer.c???? | 114 +++++++++++++++++++++++++++-
> > ----
> > ?arch/arm64/kvm/vgic/vgic-init.c |?? 9 +++
> > ?arch/arm64/kvm/vgic/vgic-v5.c?? |?? 6 +-
> > ?include/kvm/arm_arch_timer.h??? |?? 7 +-
> > ?include/kvm/arm_vgic.h????????? |?? 5 ++
> > ?5 files changed, 119 insertions(+), 22 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/arch_timer.c
> > b/arch/arm64/kvm/arch_timer.c
> > index 6f033f6644219..b0a5a6c6bf8da 100644
> > --- a/arch/arm64/kvm/arch_timer.c
> > +++ b/arch/arm64/kvm/arch_timer.c
> > @@ -56,6 +56,17 @@ static struct irq_ops arch_timer_irq_ops = {
> > ?	.get_input_level = kvm_arch_timer_get_input_level,
> > ?};
> > ?
> > +static struct irq_ops arch_timer_irq_ops_vgic_v5 = {
> > +	.get_input_level = kvm_arch_timer_get_input_level,
> > +	.set_pending_state = vgic_v5_ppi_set_pending_state,
> > +	.queue_irq_unlock = vgic_v5_ppi_queue_irq_unlock,
> > +};
> > +
> > +static bool vgic_is_v5(struct kvm_vcpu *vcpu)
> > +{
> > +	return vcpu->kvm->arch.vgic.vgic_model ==
> > KVM_DEV_TYPE_ARM_VGIC_V5;
> > +}
> > +
> 
> Drive-by comment: you also have
> 
> arch/arm64/kvm/vgic/vgic.h:static inline bool vgic_is_v5(struct kvm
> *kvm)
> include/kvm/arm_vgic.h:#define gic_is_v5(k) ((k)-
> >arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5)
> 
> At least two of them have to die.
> 
> 	M.
> 
Agreed. This has been addressed in conjunction with your int type
helper suggestions. We're now back to having ONE way of checking if the
vgic is v5.

Thanks,
Sascha

From Sascha.Bischoff at arm.com  Tue Dec 16 02:57:34 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Tue, 16 Dec 2025 10:57:34 +0000
Subject: [PATCH 10/32] KVM: arm64: gic-v5: Add emulation for
 ICC_IAFFID_EL1 accesses
In-Reply-To: <86cy4fodns.wl-maz@kernel.org>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	 <20251212152215.675767-11-sascha.bischoff@arm.com>
	 <86cy4fodns.wl-maz@kernel.org>
Message-ID: <12821001c8dfacdb45e8541b4fc95e0d5fad8739.camel@arm.com>

On Mon, 2025-12-15 at 17:31 +0000, Marc Zyngier wrote:
> On Fri, 12 Dec 2025 15:22:38 +0000,
> Sascha Bischoff <Sascha.Bischoff at arm.com> wrote:
> > 
> > GICv5 doesn't include an ICV_IAFFIDR_EL1 or ICH_IAFFIDR_EL2 for
> > providing the IAFFID to the guest. A guest access to the
> > ICH_IAFFIDR_EL1 must therefore be trapped and emulated to avoid the
> 
> nit: ICC_IAFFIDR_EL1. There is no ICH_*_EL1 register.
> 
> > guest accessing the host's ICC_IAFFIDR_EL1.
> > 
> > For GICv5, the VPE ID corresponds to the virtual IAFFID for the
> > purposes of specifying the affinity of virtual interrupts. The VPE
> > ID
> > is the index into the VPE Table, which will be the same as the
> > vcpu->vcpu_id once the various GICv5 VM tables are introduced. At
> > this
> > stage, said VM tables have yet to be introduced as they are not
> > required for PPI support. Moreover, the IAFFID should go largely
> > unused by any guest using just PPIs as they are not routable to a
> > different PE. That said, we still need to trap and emulate the
> > guest's
> > accesses to avoid leaking host state into the guest.
> 
> I think you can trim some of this. Just state that KVM makes the
> IAFFIDR, VPEID and vcpu_id the same thing, and that'll be good
> enough.
> 
> > 
> > The virtual IAFFID is provided to the guest when it reads
> > ICC_IAFFID_EL1 (which always traps back to the hypervisor). Writes
> > are
> > rightly ignored.
> > 
> > The trapping for the ICC_IAFFIDR_EL2 is always enabled when in a
> > guest
> > context.
> 
> This register doesn't exist either.
> 

Yikes. I really wasn't having a good day with my register names. I've
addressed these now and have compacted down that paragraph.

> > 
> > Co-authored-by: Timothy Hayes <timothy.hayes at arm.com>
> > Signed-off-by: Timothy Hayes <timothy.hayes at arm.com>
> > Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
> > ---
> > ?arch/arm64/kvm/config.c?? | 10 +++++++++-
> > ?arch/arm64/kvm/sys_regs.c | 19 +++++++++++++++++++
> > ?2 files changed, 28 insertions(+), 1 deletion(-)
> > 
> > diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
> > index 57ef67f718113..cbdd8ac90f4d0 100644
> > --- a/arch/arm64/kvm/config.c
> > +++ b/arch/arm64/kvm/config.c
> > @@ -1582,6 +1582,14 @@ static void __compute_hdfgwtr(struct
> > kvm_vcpu *vcpu)
> > ?		*vcpu_fgt(vcpu, HDFGWTR_EL2) |=
> > HDFGWTR_EL2_MDSCR_EL1;
> > ?}
> > ?
> > +static void __compute_ich_hfgrtr(struct kvm_vcpu *vcpu)
> > +{
> > +	__compute_fgt(vcpu, ICH_HFGRTR_EL2);
> > +
> > +	/* ICC_IAFFIDR_EL1 *always* needs to be trapped when
> > running a guest */
> > +	*vcpu_fgt(vcpu, ICH_HFGRTR_EL2) &=
> > ~ICH_HFGRTR_EL2_ICC_IAFFIDR_EL1;
> 
> Slightly redundant when !GICv5 in the guest, but that's not really a
> problem.
> 
> > +}
> > +
> > ?void kvm_vcpu_load_fgt(struct kvm_vcpu *vcpu)
> > ?{
> > ?	if (!cpus_have_final_cap(ARM64_HAS_FGT))
> > @@ -1607,7 +1615,7 @@ void kvm_vcpu_load_fgt(struct kvm_vcpu *vcpu)
> > ?	if (!cpus_have_final_cap(ARM64_HAS_GICV5_CPUIF))
> > ?		return;
> > ?
> > -	__compute_fgt(vcpu, ICH_HFGRTR_EL2);
> > +	__compute_ich_hfgrtr(vcpu);
> > ?	__compute_fgt(vcpu, ICH_HFGWTR_EL2);
> > ?	__compute_fgt(vcpu, ICH_HFGITR_EL2);
> > ?}
> > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> > index fbbd7b6ff6507..31c08fd591d08 100644
> > --- a/arch/arm64/kvm/sys_regs.c
> > +++ b/arch/arm64/kvm/sys_regs.c
> > @@ -681,6 +681,24 @@ static bool access_gic_dir(struct kvm_vcpu
> > *vcpu,
> > ?	return true;
> > ?}
> > ?
> > +static bool access_gicv5_iaffid(struct kvm_vcpu *vcpu, struct
> > sys_reg_params *p,
> > +				const struct sys_reg_desc *r)
> > +{
> > +	if (!vgic_is_v5(vcpu->kvm))
> > +		return undef_access(vcpu, p, r);
> 
> Shouldn't this be readily handled by the FGU configuration in the
> absence of GICv5 in the guest?
> 

Yeah, it should be. This was written before GICv5 was plumbed into the
FGUs. I've just tested it, and it undefs correctly without the explicit
check, so I've dropped this.

Thanks,
Sascha

> > +
> > +	if (p->is_write)
> > +		return ignore_write(vcpu, p);
> > +
> > +	/*
> > +	 * For GICv5 VMs, the IAFFID value is the same as the VPE
> > ID. The VPE ID
> > +	 * is the same as the VCPU's ID.
> > +	 */
> > +	p->regval = FIELD_PREP(ICC_IAFFIDR_EL1_IAFFID, vcpu-
> > >vcpu_id);
> > +
> > +	return true;
> > +}
> > +
> > ?static bool trap_raz_wi(struct kvm_vcpu *vcpu,
> > ?			struct sys_reg_params *p,
> > ?			const struct sys_reg_desc *r)
> > @@ -3411,6 +3429,7 @@ static const struct sys_reg_desc
> > sys_reg_descs[] = {
> > ?	{ SYS_DESC(SYS_ICC_AP1R1_EL1), undef_access },
> > ?	{ SYS_DESC(SYS_ICC_AP1R2_EL1), undef_access },
> > ?	{ SYS_DESC(SYS_ICC_AP1R3_EL1), undef_access },
> > +	{ SYS_DESC(SYS_ICC_IAFFIDR_EL1), access_gicv5_iaffid },
> > ?	{ SYS_DESC(SYS_ICC_DIR_EL1), access_gic_dir },
> > ?	{ SYS_DESC(SYS_ICC_RPR_EL1), undef_access },
> > ?	{ SYS_DESC(SYS_ICC_SGI1R_EL1), access_gic_sgi },
> 
> Thanks,
> 
> 	M.
> 


From hayashi.kunihiko at socionext.com  Tue Dec 16 03:01:08 2025
From: hayashi.kunihiko at socionext.com (Kunihiko Hayashi)
Date: Tue, 16 Dec 2025 20:01:08 +0900
Subject: [PATCH 0/5] Update UniPhier devicetree
Message-ID: <20251216110113.1801245-1-hayashi.kunihiko@socionext.com>

Add missing nodes for devices implemented in each SoC, and fix warnings
from dtbs_check.

Kunihiko Hayashi (5):
  ARM: dts: uniphier: Add missing watchdog nodes
  ARM: dts: uniphier: Add missing thermal-sensor node for Pro5
  ARM: dts: uniphier: Drop unit-address from port node of wm8960
  ARM: dts: uniphier: Remove "smpctrl" nodes
  arm64: dts: uniphier: Remove smpctrl nodes

 arch/arm/boot/dts/socionext/uniphier-ld4.dtsi    |  5 -----
 arch/arm/boot/dts/socionext/uniphier-pro4.dtsi   |  9 ++++-----
 arch/arm/boot/dts/socionext/uniphier-pro5.dtsi   | 16 +++++++++++-----
 .../boot/dts/socionext/uniphier-pxs2-gentil.dts  |  2 +-
 arch/arm/boot/dts/socionext/uniphier-pxs2.dtsi   |  9 ++++-----
 arch/arm/boot/dts/socionext/uniphier-sld8.dtsi   |  9 ++++-----
 arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi |  5 -----
 arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi |  5 -----
 arch/arm64/boot/dts/socionext/uniphier-pxs3.dtsi |  5 -----
 9 files changed, 24 insertions(+), 41 deletions(-)

-- 
2.34.1



From hayashi.kunihiko at socionext.com  Tue Dec 16 03:01:09 2025
From: hayashi.kunihiko at socionext.com (Kunihiko Hayashi)
Date: Tue, 16 Dec 2025 20:01:09 +0900
Subject: [PATCH 1/5] ARM: dts: uniphier: Add missing watchdog nodes
In-Reply-To: <20251216110113.1801245-1-hayashi.kunihiko@socionext.com>
References: <20251216110113.1801245-1-hayashi.kunihiko@socionext.com>
Message-ID: <20251216110113.1801245-2-hayashi.kunihiko@socionext.com>

Some UniPhier armv7 SoCs also have watchdog functions and are available.

Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko at socionext.com>
---
 arch/arm/boot/dts/socionext/uniphier-pro4.dtsi | 4 ++++
 arch/arm/boot/dts/socionext/uniphier-pro5.dtsi | 4 ++++
 arch/arm/boot/dts/socionext/uniphier-pxs2.dtsi | 4 ++++
 arch/arm/boot/dts/socionext/uniphier-sld8.dtsi | 4 ++++
 4 files changed, 16 insertions(+)

diff --git a/arch/arm/boot/dts/socionext/uniphier-pro4.dtsi b/arch/arm/boot/dts/socionext/uniphier-pro4.dtsi
index ba55af30e904..041add88347b 100644
--- a/arch/arm/boot/dts/socionext/uniphier-pro4.dtsi
+++ b/arch/arm/boot/dts/socionext/uniphier-pro4.dtsi
@@ -496,6 +496,10 @@ sys_rst: reset-controller {
 				compatible = "socionext,uniphier-pro4-reset";
 				#reset-cells = <1>;
 			};
+
+			watchdog {
+				compatible = "socionext,uniphier-wdt";
+			};
 		};
 
 		eth: ethernet at 65000000 {
diff --git a/arch/arm/boot/dts/socionext/uniphier-pro5.dtsi b/arch/arm/boot/dts/socionext/uniphier-pro5.dtsi
index 2d8591cdddb8..3d21fb822219 100644
--- a/arch/arm/boot/dts/socionext/uniphier-pro5.dtsi
+++ b/arch/arm/boot/dts/socionext/uniphier-pro5.dtsi
@@ -470,6 +470,10 @@ sys_rst: reset-controller {
 				compatible = "socionext,uniphier-pro5-reset";
 				#reset-cells = <1>;
 			};
+
+			watchdog {
+				compatible = "socionext,uniphier-wdt";
+			};
 		};
 
 		usb0: usb at 65a00000 {
diff --git a/arch/arm/boot/dts/socionext/uniphier-pxs2.dtsi b/arch/arm/boot/dts/socionext/uniphier-pxs2.dtsi
index f97a57222101..ef94fa0517a6 100644
--- a/arch/arm/boot/dts/socionext/uniphier-pxs2.dtsi
+++ b/arch/arm/boot/dts/socionext/uniphier-pxs2.dtsi
@@ -572,6 +572,10 @@ sys_rst: reset-controller {
 				#reset-cells = <1>;
 			};
 
+			watchdog {
+				compatible = "socionext,uniphier-wdt";
+			};
+
 			pvtctl: thermal-sensor {
 				compatible = "socionext,uniphier-pxs2-thermal";
 				interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/arch/arm/boot/dts/socionext/uniphier-sld8.dtsi b/arch/arm/boot/dts/socionext/uniphier-sld8.dtsi
index f876282760e9..0b840a8415dd 100644
--- a/arch/arm/boot/dts/socionext/uniphier-sld8.dtsi
+++ b/arch/arm/boot/dts/socionext/uniphier-sld8.dtsi
@@ -413,6 +413,10 @@ sys_rst: reset-controller {
 				compatible = "socionext,uniphier-sld8-reset";
 				#reset-cells = <1>;
 			};
+
+			watchdog {
+				compatible = "socionext,uniphier-wdt";
+			};
 		};
 
 		nand: nand-controller at 68000000 {
-- 
2.34.1



From hayashi.kunihiko at socionext.com  Tue Dec 16 03:01:10 2025
From: hayashi.kunihiko at socionext.com (Kunihiko Hayashi)
Date: Tue, 16 Dec 2025 20:01:10 +0900
Subject: [PATCH 2/5] ARM: dts: uniphier: Add missing thermal-sensor node for Pro5
In-Reply-To: <20251216110113.1801245-1-hayashi.kunihiko@socionext.com>
References: <20251216110113.1801245-1-hayashi.kunihiko@socionext.com>
Message-ID: <20251216110113.1801245-3-hayashi.kunihiko@socionext.com>

UniPhier Pro5 SoC also has a thermal sensor and is available.

Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko at socionext.com>
---
 arch/arm/boot/dts/socionext/uniphier-pro5.dtsi | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm/boot/dts/socionext/uniphier-pro5.dtsi b/arch/arm/boot/dts/socionext/uniphier-pro5.dtsi
index 3d21fb822219..be9a2c40bd7c 100644
--- a/arch/arm/boot/dts/socionext/uniphier-pro5.dtsi
+++ b/arch/arm/boot/dts/socionext/uniphier-pro5.dtsi
@@ -474,6 +474,13 @@ sys_rst: reset-controller {
 			watchdog {
 				compatible = "socionext,uniphier-wdt";
 			};
+
+			pvtctl: thermal-sensor {
+				compatible = "socionext,uniphier-pxs2-thermal";
+				interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
+				#thermal-sensor-cells = <0>;
+				socionext,tmod-calibration = <0x0f86 0x6844>;
+			};
 		};
 
 		usb0: usb at 65a00000 {
-- 
2.34.1



From hayashi.kunihiko at socionext.com  Tue Dec 16 03:01:12 2025
From: hayashi.kunihiko at socionext.com (Kunihiko Hayashi)
Date: Tue, 16 Dec 2025 20:01:12 +0900
Subject: [PATCH 4/5] ARM: dts: uniphier: Remove "smpctrl" nodes
In-Reply-To: <20251216110113.1801245-1-hayashi.kunihiko@socionext.com>
References: <20251216110113.1801245-1-hayashi.kunihiko@socionext.com>
Message-ID: <20251216110113.1801245-5-hayashi.kunihiko@socionext.com>

This node has no binding definition and does not affect various
functions, so remove the nodes from .dtsi files to avoid warnings.

  arch/arm/boot/dts/socionext/uniphier-pxs2-gentil.dtb: /soc/smpctrl at 59801000:
  failed to match any schema with compatible: ['socionext,uniphier-smpctrl']

Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko at socionext.com>
---
 arch/arm/boot/dts/socionext/uniphier-ld4.dtsi  | 5 -----
 arch/arm/boot/dts/socionext/uniphier-pro4.dtsi | 5 -----
 arch/arm/boot/dts/socionext/uniphier-pro5.dtsi | 5 -----
 arch/arm/boot/dts/socionext/uniphier-pxs2.dtsi | 5 -----
 arch/arm/boot/dts/socionext/uniphier-sld8.dtsi | 5 -----
 5 files changed, 25 deletions(-)

diff --git a/arch/arm/boot/dts/socionext/uniphier-ld4.dtsi b/arch/arm/boot/dts/socionext/uniphier-ld4.dtsi
index df2de7a40211..0cb5cb6fa19e 100644
--- a/arch/arm/boot/dts/socionext/uniphier-ld4.dtsi
+++ b/arch/arm/boot/dts/socionext/uniphier-ld4.dtsi
@@ -202,11 +202,6 @@ system_bus: system-bus at 58c00000 {
 			pinctrl-0 = <&pinctrl_system_bus>;
 		};
 
-		smpctrl at 59801000 {
-			compatible = "socionext,uniphier-smpctrl";
-			reg = <0x59801000 0x400>;
-		};
-
 		syscon at 59810000 {
 			compatible = "socionext,uniphier-ld4-mioctrl",
 				     "simple-mfd", "syscon";
diff --git a/arch/arm/boot/dts/socionext/uniphier-pro4.dtsi b/arch/arm/boot/dts/socionext/uniphier-pro4.dtsi
index 041add88347b..4dffa06474a1 100644
--- a/arch/arm/boot/dts/socionext/uniphier-pro4.dtsi
+++ b/arch/arm/boot/dts/socionext/uniphier-pro4.dtsi
@@ -236,11 +236,6 @@ system_bus: system-bus at 58c00000 {
 			pinctrl-0 = <&pinctrl_system_bus>;
 		};
 
-		smpctrl at 59801000 {
-			compatible = "socionext,uniphier-smpctrl";
-			reg = <0x59801000 0x400>;
-		};
-
 		mioctrl: syscon at 59810000 {
 			compatible = "socionext,uniphier-pro4-mioctrl",
 				     "simple-mfd", "syscon";
diff --git a/arch/arm/boot/dts/socionext/uniphier-pro5.dtsi b/arch/arm/boot/dts/socionext/uniphier-pro5.dtsi
index be9a2c40bd7c..cc61a4b5c1de 100644
--- a/arch/arm/boot/dts/socionext/uniphier-pro5.dtsi
+++ b/arch/arm/boot/dts/socionext/uniphier-pro5.dtsi
@@ -336,11 +336,6 @@ system_bus: system-bus at 58c00000 {
 			pinctrl-0 = <&pinctrl_system_bus>;
 		};
 
-		smpctrl at 59801000 {
-			compatible = "socionext,uniphier-smpctrl";
-			reg = <0x59801000 0x400>;
-		};
-
 		sdctrl: syscon at 59810000 {
 			compatible = "socionext,uniphier-pro5-sdctrl",
 				     "simple-mfd", "syscon";
diff --git a/arch/arm/boot/dts/socionext/uniphier-pxs2.dtsi b/arch/arm/boot/dts/socionext/uniphier-pxs2.dtsi
index ef94fa0517a6..15927956b4f8 100644
--- a/arch/arm/boot/dts/socionext/uniphier-pxs2.dtsi
+++ b/arch/arm/boot/dts/socionext/uniphier-pxs2.dtsi
@@ -417,11 +417,6 @@ system_bus: system-bus at 58c00000 {
 			pinctrl-0 = <&pinctrl_system_bus>;
 		};
 
-		smpctrl at 59801000 {
-			compatible = "socionext,uniphier-smpctrl";
-			reg = <0x59801000 0x400>;
-		};
-
 		sdctrl: syscon at 59810000 {
 			compatible = "socionext,uniphier-pxs2-sdctrl",
 				     "simple-mfd", "syscon";
diff --git a/arch/arm/boot/dts/socionext/uniphier-sld8.dtsi b/arch/arm/boot/dts/socionext/uniphier-sld8.dtsi
index 0b840a8415dd..fe0a7ff8a7c5 100644
--- a/arch/arm/boot/dts/socionext/uniphier-sld8.dtsi
+++ b/arch/arm/boot/dts/socionext/uniphier-sld8.dtsi
@@ -206,11 +206,6 @@ system_bus: system-bus at 58c00000 {
 			pinctrl-0 = <&pinctrl_system_bus>;
 		};
 
-		smpctrl at 59801000 {
-			compatible = "socionext,uniphier-smpctrl";
-			reg = <0x59801000 0x400>;
-		};
-
 		mioctrl: syscon at 59810000 {
 			compatible = "socionext,uniphier-sld8-mioctrl",
 				     "simple-mfd", "syscon";
-- 
2.34.1



From hayashi.kunihiko at socionext.com  Tue Dec 16 03:01:11 2025
From: hayashi.kunihiko at socionext.com (Kunihiko Hayashi)
Date: Tue, 16 Dec 2025 20:01:11 +0900
Subject: [PATCH 3/5] ARM: dts: uniphier: Drop unit-address from port node of wm8960
In-Reply-To: <20251216110113.1801245-1-hayashi.kunihiko@socionext.com>
References: <20251216110113.1801245-1-hayashi.kunihiko@socionext.com>
Message-ID: <20251216110113.1801245-4-hayashi.kunihiko@socionext.com>

The "port" node represents a logical connection and does not have a
reg property. According to dt-bindings, the "port" node should not use
unit-address. Rename "port at 0" to "port" to remove warnings.

  arch/arm/boot/dts/socionext/uniphier-pxs2-gentil.dtb: wm8960 at 1a (wlf,wm8960):
  Unevaluated properties are not allowed ('port at 0' was unexpected)

Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko at socionext.com>
---
 arch/arm/boot/dts/socionext/uniphier-pxs2-gentil.dts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/socionext/uniphier-pxs2-gentil.dts b/arch/arm/boot/dts/socionext/uniphier-pxs2-gentil.dts
index 5f18b926c50a..78653d4bec0b 100644
--- a/arch/arm/boot/dts/socionext/uniphier-pxs2-gentil.dts
+++ b/arch/arm/boot/dts/socionext/uniphier-pxs2-gentil.dts
@@ -68,7 +68,7 @@ wm8960 at 1a {
 		reg = <0x1a>;
 		#sound-dai-cells = <0>;
 
-		port at 0 {
+		port {
 			wm_speaker: endpoint {
 				dai-format = "i2s";
 				remote-endpoint = <&i2s_aux>;
-- 
2.34.1



From hayashi.kunihiko at socionext.com  Tue Dec 16 03:01:13 2025
From: hayashi.kunihiko at socionext.com (Kunihiko Hayashi)
Date: Tue, 16 Dec 2025 20:01:13 +0900
Subject: [PATCH 5/5] arm64: dts: uniphier: Remove smpctrl nodes
In-Reply-To: <20251216110113.1801245-1-hayashi.kunihiko@socionext.com>
References: <20251216110113.1801245-1-hayashi.kunihiko@socionext.com>
Message-ID: <20251216110113.1801245-6-hayashi.kunihiko@socionext.com>

This node has no bindings definition and does not affect various
functions, so remove the nodes from .dtsi files to avoid warnings.

  arch/arm64/boot/dts/socionext/uniphier-ld20-ref.dtb: /soc at 0/smpctrl at 59801000:
  failed to match any schema with compatible: ['socionext,uniphier-smpctrl']

Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko at socionext.com>
---
 arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi | 5 -----
 arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi | 5 -----
 arch/arm64/boot/dts/socionext/uniphier-pxs3.dtsi | 5 -----
 3 files changed, 15 deletions(-)

diff --git a/arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi b/arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi
index 4680571c264d..62c7980e86ce 100644
--- a/arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi
+++ b/arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi
@@ -414,11 +414,6 @@ system_bus: system-bus at 58c00000 {
 			pinctrl-0 = <&pinctrl_system_bus>;
 		};
 
-		smpctrl at 59801000 {
-			compatible = "socionext,uniphier-smpctrl";
-			reg = <0x59801000 0x400>;
-		};
-
 		syscon at 59810000 {
 			compatible = "socionext,uniphier-ld11-sdctrl",
 				     "simple-mfd", "syscon";
diff --git a/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi b/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi
index c3858666550c..5afe04325657 100644
--- a/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi
+++ b/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi
@@ -547,11 +547,6 @@ system_bus: system-bus at 58c00000 {
 			pinctrl-0 = <&pinctrl_system_bus>;
 		};
 
-		smpctrl at 59801000 {
-			compatible = "socionext,uniphier-smpctrl";
-			reg = <0x59801000 0x400>;
-		};
-
 		sdctrl: syscon at 59810000 {
 			compatible = "socionext,uniphier-ld20-sdctrl",
 				     "simple-mfd", "syscon";
diff --git a/arch/arm64/boot/dts/socionext/uniphier-pxs3.dtsi b/arch/arm64/boot/dts/socionext/uniphier-pxs3.dtsi
index e00a5caed822..eba9927f439e 100644
--- a/arch/arm64/boot/dts/socionext/uniphier-pxs3.dtsi
+++ b/arch/arm64/boot/dts/socionext/uniphier-pxs3.dtsi
@@ -367,11 +367,6 @@ system_bus: system-bus at 58c00000 {
 			pinctrl-0 = <&pinctrl_system_bus>;
 		};
 
-		smpctrl at 59801000 {
-			compatible = "socionext,uniphier-smpctrl";
-			reg = <0x59801000 0x400>;
-		};
-
 		sdctrl: syscon at 59810000 {
 			compatible = "socionext,uniphier-pxs3-sdctrl",
 				     "simple-mfd", "syscon";
-- 
2.34.1



From yeoreum.yun at arm.com  Tue Dec 16 03:03:11 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Tue, 16 Dec 2025 11:03:11 +0000
Subject: [PATCH 2/2] arm64: mmu: use pagetable_alloc_nolock() while
 stop_machine()
In-Reply-To: <DEZK5U2YP6I0.27VJHSVK14646@google.com>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com>
 <20251212161832.2067134-3-yeoreum.yun@arm.com>
 <CA+i-1C2e7QNTy5u=HF7tLsLXLq4xYbMTCbNjWGAxHz4uwgR05g@mail.gmail.com>
 <aT5/y3cSGIzi2K+m@e129823.arm.com>
 <DEYOI8H2OESD.1H56D3H8HKILB@google.com>
 <aT/WOAr4osoJWaMS@e129823.arm.com>
 <DEYP7JSVTB9D.3EFN2KEHH3O79@google.com>
 <aT/drjN1BkvyAGoi@e129823.arm.com>
 <DEZK5U2YP6I0.27VJHSVK14646@google.com>
Message-ID: <aUE8bwUVa6jSUft1@e129823.arm.com>

Hi Brendan,

> On Mon Dec 15, 2025 at 10:06 AM UTC, Yeoreum Yun wrote:
> [snip]
> >> Overall I am feeling a bit uncomfortable about this use of _nolock, but
> >> I am also feeling pretty ignorant about PREEMPT_RT and also about this
> >> arm64 code, so I am hesitant to suggest alternatives, I hope someone
> >> else can offer some input here...
> >
> > I understand. However, as I mentioned earlier,
> > my main intention was to hear opinions specifically about memory contention.
> >
> > That said, if there is no memory contention,
> > I don?t think using the _nolock API is necessarily a bad approach.
>
>
> > In fact, I believe a bigger issue is that, under PREEMPT_RT,
> > code that uses the regular memory allocation APIs may give users the false impression
> > that those APIs are ?safe to use,? even though they are not.
>
> Yeah, I share this concern. I would bet I have written code that's
> broken under PREEMPT_RT (luckily only in Google's kernel fork). The
> comment for GFP_ATOMIC says:
>
>  * %GFP_ATOMIC users can not sleep and need the allocation to succeed. A lower
>  * watermark is applied to allow access to "atomic reserves".
>  * The current implementation doesn't support NMI and few other strict
>  * non-preemptive contexts (e.g. raw_spin_lock). The same applies to %GFP_NOWAIT.
>
> It kinda sounds like it's supposed to be OK to use GFP_ATOMIC in a
> normal preempt_disable() context. So do you know exactly why it's
> invalid to use it in this stop_machine() context here? Maybe we need to
> update this comment.

In non-PREEMPT_RT configurations, this is fine to use.
However, in PREEMPT_RT, it should not be used because
spin_lock becomes a sleepable lock backed by an rt-mutex.

>From Documentation/locking/locktypes.rst:

  The fact that PREEMPT_RT changes the lock category of spinlock_t and
  rwlock_t from spinning to sleeping.

As you know, all locks related to memory allocation
(e.g., zone_lock, PCP locks, etc.) use spin_lock,
which becomes sleepable under PREEMPT_RT.

The callback of stop_machine() is executed in a preemption-disabled context
(see cpu_stopper_thread()). In this context, if it fails to acquire a spinlock
during memory allocation,
the task would be able to go to sleep while preemption is disabled,
which is an obviously problematic situation.

> Or maybe actually we need to fix the allocator
> so that GFP_ATOMIC allocs are safe in this context?

I don?t think so, because GFP_ATOMIC can still be used by
IRQ threads in PREEMPT_RT. (If an IRQ handler is non-threaded
due to IRQF_NO_THREAD, then it cannot use it.)

Although the root cause appears to be that the memory allocator uses spin_lock(),
I believe the real issue is where such allocations are allowed to be used.
If we changed the lock to raw_spin_lock(),
this would introduce significant latency during memory allocation.
So I believe this is why the memory allocator continues to use spin_lock().

IOW, what I really want to ask is whether
general memory allocation/free operations are
permissible in a stop_machine() context
(I think nolock() can be allowable only).

Thanks

--
Sincerely,
Yeoreum Yun


From u.kleine-koenig at baylibre.com  Tue Dec 16 03:08:38 2025
From: u.kleine-koenig at baylibre.com (Uwe =?utf-8?Q?Kleine-K=C3=B6nig?=)
Date: Tue, 16 Dec 2025 12:08:38 +0100
Subject: [PATCH v1 00/17] tee: Use bus callbacks instead of driver
 callbacks
In-Reply-To: <CAGptzHOOqLhBnAXDURAzkgckUvRr__UuF1S_7MLV0u-ZxYEdyA@mail.gmail.com>
References: <cover.1765472125.git.u.kleine-koenig@baylibre.com>
 <aT--ox375kg2Mzh-@sumit-X1>
 <dhunzydod4d7vj73llpuqemxb5er2ja4emxusr66irwf77jhhb@es4yd2axzl25>
 <CAGptzHOOqLhBnAXDURAzkgckUvRr__UuF1S_7MLV0u-ZxYEdyA@mail.gmail.com>
Message-ID: <ayebinxqpcnl7hpa35ytrudiy7j75u5bdk3enlirkp5pevppeg@6mx6a5fwymwf>

Hello,

On Tue, Dec 16, 2025 at 01:08:38PM +0530, Sumit Garg wrote:
> On Mon, Dec 15, 2025 at 3:02?PM Uwe Kleine-K?nig
> <u.kleine-koenig at baylibre.com> wrote:
> > On Mon, Dec 15, 2025 at 04:54:11PM +0900, Sumit Garg wrote:
> > > Feel free to make the tee_bus_type private as the last patch in the series
> > > such that any followup driver follows this clean approach.
> >
> > There is a bit more to do for that than I'm willing to invest. With my
> > patch series applied `tee_bus_type` is still used in
> > drivers/tee/optee/device.c and drivers/tee/tee_core.c.
> 
> Oh I see, I guess we need to come with some helpers around device
> register/unregister from TEE subsystem as well. Let's plan that for a
> followup patch-set, I don't want this patch-set to be bloated more.

Don't consider me in for that. But it sounds like a nice addition.

> > Maybe it's
> > sensible to merge these two files into a single one.
> 
> It's not possible as the design for TEE bus is to have TEE
> implementation drivers like OP-TEE, AMD-TEE, TS-TEE, QTEE and so on to
> register devices on the bus.

So only OP-TEE uses the bus for devices and the other *-TEE don't. Also
sounds like something worth to be fixed.

> > The things I wonder about additionally are:
> >
> >  - if CONFIG_OPTEE=n and CONFIG_TEE=y|m the tee bus is only used for
> >    drivers but not devices.
> 
> Yeah since the devices are rather added by the TEE implementation driver.
> 
> >
> >  - optee_register_device() calls device_create_file() on
> >    &optee_device->dev after device_register(&optee_device->dev).
> >    (Attention half-knowledge!) I think device_create_file() should not
> >    be called on an already registered device (or you have to send a
> >    uevent afterwards). This should probably use type attribute groups.
> >    (Or the need_supplicant attribute should be dropped as it isn't very
> >    useful. This would maybe be considered an ABI change however.)
> 
> The reasoning for this attribute should be explained by commit:
> 7269cba53d90 ("tee: optee: Fix supplicant based device enumeration").
> In summary it's due to a weird dependency for devices we have with the
> user-space daemon: tee-supplicant.

From reading that once I don't understand it. (But no need to explain
:-)

Still the file should better be added before device_add() is called.

> >  - Why does optee_probe() in drivers/tee/optee/smc_abi.c unregister all
> >    optee devices in its error path (optee_unregister_devices())?
> 
> This is mostly to take care of if any device got registered before the
> failure occured. Let me know if you have a better way to address that.

Without understanding the tee stuff, I'd say: Don't bother and only undo
the things that probe did before the failure.

Best regards
Uwe
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251216/63715f48/attachment.sig>

From lorenzo.stoakes at oracle.com  Tue Dec 16 03:11:01 2025
From: lorenzo.stoakes at oracle.com (Lorenzo Stoakes)
Date: Tue, 16 Dec 2025 11:11:01 +0000
Subject: [PATCH v2 1/3] arm64: mm: support batch clearing of the young
 flag for large folios
In-Reply-To: <1a0001cd-c38d-403b-b3ef-d19e85acd772@linux.alibaba.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <e10f876ce130134fa089befe83f30561b48b9889.1765439380.git.baolin.wang@linux.alibaba.com>
 <5039c6a2-09b6-4c9b-accb-26583ba120db@lucifer.local>
 <1a0001cd-c38d-403b-b3ef-d19e85acd772@linux.alibaba.com>
Message-ID: <671ac450-4a59-4e26-b098-7cf65add1e75@lucifer.local>

On Tue, Dec 16, 2025 at 11:32:58AM +0800, Baolin Wang wrote:
>
>
> On 2025/12/15 19:36, Lorenzo Stoakes wrote:
> > On Thu, Dec 11, 2025 at 04:16:54PM +0800, Baolin Wang wrote:
> > > Currently, contpte_ptep_test_and_clear_young() and contpte_ptep_clear_flush_young()
> > > only clear the young flag and flush TLBs for PTEs within the contiguous range.
> > > To support batch PTE operations for other sized large folios in the following
> > > patches, adding a new parameter to specify the number of PTEs.
> > >
> > > While we are at it, rename the functions to maintain consistency with other
> > > contpte_*() functions.
> > >
> > > Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
> > > ---
> > >   arch/arm64/include/asm/pgtable.h | 12 ++++-----
> > >   arch/arm64/mm/contpte.c          | 44 ++++++++++++++++++++++----------
> > >   2 files changed, 37 insertions(+), 19 deletions(-)
> > >
> > > diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
> > > index 0944e296dd4a..e03034683156 100644
> > > --- a/arch/arm64/include/asm/pgtable.h
> > > +++ b/arch/arm64/include/asm/pgtable.h
> > > @@ -1679,10 +1679,10 @@ extern void contpte_clear_full_ptes(struct mm_struct *mm, unsigned long addr,
> > >   extern pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
> > >   				unsigned long addr, pte_t *ptep,
> > >   				unsigned int nr, int full);
> > > -extern int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
> > > -				unsigned long addr, pte_t *ptep);
> > > -extern int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
> > > -				unsigned long addr, pte_t *ptep);
> > > +extern int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
> > > +				unsigned long addr, pte_t *ptep, unsigned int nr);
> > > +extern int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
> > > +				unsigned long addr, pte_t *ptep, unsigned int nr);
> >
> > In core mm at least, as a convention, we strip 'extern' from header declarations
> > as we go as they're not necessary.
>
> Sure. I can remove the 'extern'.

Thanks.

>
> > I wonder about this naming convention also. The contpte_xxx_() prefix
> > obviously implies we are operating upon PTEs in the contiguous range, now
> > we are doing something... different and 'nr' is a bit vague.
> >
> > Is it the nr of contiguous ranges? Well in reality it's nr_pages right? But
>
> Yes, 'nr' here means nr_pages, which follows the convention of the
> parameters in contpte_xxx_() functions.

Except you're violating the convention already by doing non-contpte stuff in
contpte functions?

The confusion is between nr of contpte ranges and nr of pages, so I think we
should be explicit.

>
> > now we're not saying they're necessarily contiguous in the sense of contpte...
> >
> > I wonder whether we'd be better off introducing a new function that
> > explicitly has 'batch' or 'batched' in the name, and have the usual
> > contpte_***() stuff and callers that need batching using a new underlying helper?
>
> OK. I get your point. However, this is outside the scope of my patchset.

Well, no, this is review feedback that needs to be addressed, I really don't
like this patch as-is.

So for this to be upstreamable you really need to separate this out.

>
> Perhaps we can clean up all the contpte_xxx_() functions if everyone agrees
> that this is confusing.

I mean, unless Ryan explicitly makes a case for this being fine, I'm inclined to
reject the patch unless we do this.

The contpte logic is already very confusing, and this is only adding to it.

>
> > Obviously I defer to Ryan on all this, just my thoughts...
> >
> > >   extern void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
> > >   				pte_t *ptep, unsigned int nr);
> > >   extern int contpte_ptep_set_access_flags(struct vm_area_struct *vma,
> > > @@ -1854,7 +1854,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
> > >   	if (likely(!pte_valid_cont(orig_pte)))
> > >   		return __ptep_test_and_clear_young(vma, addr, ptep);
> > >
> > > -	return contpte_ptep_test_and_clear_young(vma, addr, ptep);
> > > +	return contpte_test_and_clear_young_ptes(vma, addr, ptep, CONT_PTES);
> > >   }
> > >
> > >   #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
> > > @@ -1866,7 +1866,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
> > >   	if (likely(!pte_valid_cont(orig_pte)))
> > >   		return __ptep_clear_flush_young(vma, addr, ptep);
> > >
> > > -	return contpte_ptep_clear_flush_young(vma, addr, ptep);
> > > +	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
> > >   }
> > >
> > >   #define wrprotect_ptes wrprotect_ptes
> > > diff --git a/arch/arm64/mm/contpte.c b/arch/arm64/mm/contpte.c
> > > index c0557945939c..19b122441be3 100644
> > > --- a/arch/arm64/mm/contpte.c
> > > +++ b/arch/arm64/mm/contpte.c
> > > @@ -488,8 +488,9 @@ pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
> > >   }
> > >   EXPORT_SYMBOL_GPL(contpte_get_and_clear_full_ptes);
> > >
> > > -int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
> > > -					unsigned long addr, pte_t *ptep)
> > > +int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
> > > +					unsigned long addr, pte_t *ptep,
> > > +					unsigned int nr)
> > >   {
> > >   	/*
> > >   	 * ptep_clear_flush_young() technically requires us to clear the access
> > > @@ -500,39 +501,56 @@ int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
> > >   	 * having to unfold.
> > >   	 */
> >
> > Hmm shouldn't you need to update this comment now 'nr' is a thing? E.g.:
> >
> > "And since we only create a contig range when the range is covered by a single
> > folio, we can get away with clearing young for the whole contig range here, so
> > we avoid having to unfold."
>
> I think the original comments are still clear:
> "
> /*
>  * ptep_clear_flush_young() technically requires us to clear the access
>  * flag for a _single_ pte. However, the core-mm code actually tracks
>  * access/dirty per folio, not per page. And since we only create a
>  * contig range when the range is covered by a single folio, we can get
>  * away with clearing young for the whole contig range here, so we avoid
>  * having to unfold.
>  */
> "

Except nr means you can span more than a single contig pte range? So this
comment is no longer applicable as-is?

You've changed the function, the comment needs to change too.

>
> > However now you're allowing for large folios that are not contpte?
> >
> > Overall feeling pretty iffy about implementing this this way.
>
> Please see the above comments, which explain why we should do that.

You haven't explained anything? Maybe I missed it?

Can you explain clearly what nr might actually be in relation to contpte's? I'm
confused even as to the utility here.

Is it batched ranges of contptes? But then why are you trying to see if end is a
contpte + expand the range if so?

>
> > > +	unsigned long start = addr;
> > > +	unsigned long end = start + nr * PAGE_SIZE;
> >
> > So now [addr, addr + nr * PAGE_SIZE) must for sure be within a single PTE
> > table?
>
> Caller has made sure that (see folio_referenced_one()).

You should comment this somehow, I hate this nested assumptions stuff 'function
X which calls function Y which calls function Z makes sure that parameter A
fulfils requirements B but we don't mention it anywhere'.

>
> > >   	int young = 0;
> > >   	int i;
> > >
> > > -	ptep = contpte_align_down(ptep);
> > > -	addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
> > > +	if (pte_cont(__ptep_get(ptep + nr - 1)))
> > > +		end = ALIGN(end, CONT_PTE_SIZE);
> >
> > OK so I guess for PTE_CONT to be set, it must be aligned to CONT_PTE_SIZE,
> > with other PTE entries present there not having PTE_CONT set (Ryan - do
> > correct me if I'm wrong!)
> >
> > I guess then no worry about running off the end of the PTE table here.
> >
> > I wonder about using pte_cont_addr_end() here, but I guess you are not
> > intending to limit to a range here but rather capture the entire contpte
> > range of the end.
>
> Right.
>
> > I don't love that now a function prefixed with contpte_... can have a
> > condition where part of the input range is _not_ a contpte entry, or is
> > specified partially...
>
> Like I said above, this is outside the scope of my patchset. If Ryan also
> thinks we need to do some cleanups for all the contpte_xxx() functions in
> the contpte.c file, we can send a follow-up patchset to rename all the
> contpte_xxx() functions to make it clear.

It's really not outside of the scope of the patch set, this is review feedback
you have to address :) trying not to be a grumpy kernel dev here :>)

In general in the kernel we don't accept confusing patches then defer making
them not-confusing until later.

We review until the series is at the correct standard to be accepted before we
merge.

As always I'm happy to be convinced that I'm mistaken or something's not
necesary, however!

>
> > > -	for (i = 0; i < CONT_PTES; i++, ptep++, addr += PAGE_SIZE)
> > > -		young |= __ptep_test_and_clear_young(vma, addr, ptep);
> > > +	if (pte_cont(__ptep_get(ptep))) {
> > > +		start = ALIGN_DOWN(start, CONT_PTE_SIZE);
> > > +		ptep = contpte_align_down(ptep);
> > > +	}
> > > +
> > > +	nr = (end - start) / PAGE_SIZE;
> >
> > Hm don't love this reuse of input param.
>
> OK. Will use another local variable instead.

Thanks.

>
> >
> > > +	for (i = 0; i < nr; i++, ptep++, start += PAGE_SIZE)
> > > +		young |= __ptep_test_and_clear_young(vma, start, ptep);
> >
> > Again, overall find it a bit iffy that we are essentially overloading the
> > code with non-contpte behaviour.
>
> Let me clarify further: this is the handling logic of the contpte_xxx()
> functions in the contpte.c file. For example, the function
> contpte_set_ptes() has a parameter 'nr', which may be greater than
> CONT_PTES, meaning that it can handle multiple CONT_PTES range sizes of a
> large folio.
>
> It might be a bit confusing, and I understand this is why you want to change
> the 'contpte_' prefix to the 'batch_' prefix. Of course, we can hope Ryan
> can provide some input on this.
>
> Thanks for reviewing.

OK so we have some reeeeal confusion here. And this speaks to the patch needing
work.

This seems to answer what I asked above - basically - are we doing _batches_ of
_contpte_ entries, or are we just accepting arbitrary large folios here and
batching up operations on them, including non-contpte entries.

Presumably from the above you're saying - this is dealing with batches of
contpte entries.

In which case this has to be made _super_ clear. Not just adding an arbitrary
'nr' parameter and letting people guess.

The contpte code is _already_ confusing and somewhat surprising if you're not
aware of it, we need to be going in the other direction.

Thanks, Lorenzo


From ye.zhang at rock-chips.com  Tue Dec 16 03:20:47 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Tue, 16 Dec 2025 19:20:47 +0800
Subject: [PATCH v3 1/7] pinctrl: rockchip: Add rk3506 pinctrl support
In-Reply-To: <20251216112053.1927852-1-ye.zhang@rock-chips.com>
References: <20251216112053.1927852-1-ye.zhang@rock-chips.com>
Message-ID: <20251216112053.1927852-2-ye.zhang@rock-chips.com>

Add pinctrl support for the Rockchip RK3506 SoC, including:

1. Driver support for the 5 GPIO banks
2. Device tree binding compatible string

Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
Reviewed-by: Heiko Stuebner <heiko at sntech.de>
---
 drivers/pinctrl/pinctrl-rockchip.c | 442 ++++++++++++++++++++++++++++-
 drivers/pinctrl/pinctrl-rockchip.h |   4 +
 2 files changed, 438 insertions(+), 8 deletions(-)

diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index 7a68a6237649..e44ef262beec 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -105,6 +105,29 @@
 		.pull_type[3] = pull3,					\
 	}
 
+#define PIN_BANK_IOMUX_FLAGS_OFFSET_DRV_FLAGS(id, pins, label, iom0,	\
+					       iom1, iom2, iom3,	\
+					       offset0, offset1,	\
+					       offset2, offset3, drv0,	\
+					       drv1, drv2, drv3)	\
+	{								\
+		.bank_num	= id,					\
+		.nr_pins	= pins,					\
+		.name		= label,				\
+		.iomux		= {					\
+			{ .type = iom0, .offset = offset0 },		\
+			{ .type = iom1, .offset = offset1 },		\
+			{ .type = iom2, .offset = offset2 },		\
+			{ .type = iom3, .offset = offset3 },		\
+		},							\
+		.drv		= {					\
+			{ .drv_type = drv0, .offset = -1 },		\
+			{ .drv_type = drv1, .offset = -1 },		\
+			{ .drv_type = drv2, .offset = -1 },		\
+			{ .drv_type = drv3, .offset = -1 },		\
+		},							\
+	}
+
 #define PIN_BANK_DRV_FLAGS(id, pins, label, type0, type1, type2, type3) \
 	{								\
 		.bank_num	= id,					\
@@ -233,6 +256,35 @@
 		.pull_type[3] = pull3,					\
 	}
 
+#define PIN_BANK_IOMUX_FLAGS_OFFSET_DRV_FLAGS_PULL_FLAGS(id, pins,	\
+						label, iom0, iom1,	\
+						iom2, iom3, offset0,	\
+						offset1, offset2,	\
+						offset3, drv0, drv1,	\
+						drv2, drv3, pull0,	\
+						pull1, pull2, pull3)	\
+	{								\
+		.bank_num	= id,					\
+		.nr_pins	= pins,					\
+		.name		= label,				\
+		.iomux		= {					\
+			{ .type = iom0, .offset = offset0 },		\
+			{ .type = iom1, .offset = offset1 },		\
+			{ .type = iom2, .offset = offset2 },		\
+			{ .type = iom3, .offset = offset3 },		\
+		},							\
+		.drv		= {					\
+			{ .drv_type = drv0, .offset = -1 },		\
+			{ .drv_type = drv1, .offset = -1 },		\
+			{ .drv_type = drv2, .offset = -1 },		\
+			{ .drv_type = drv3, .offset = -1 },		\
+		},							\
+		.pull_type[0] = pull0,					\
+		.pull_type[1] = pull1,					\
+		.pull_type[2] = pull2,					\
+		.pull_type[3] = pull3,					\
+	}
+
 #define PIN_BANK_MUX_ROUTE_FLAGS(ID, PIN, FUNC, REG, VAL, FLAG)		\
 	{								\
 		.bank_num	= ID,					\
@@ -1120,6 +1172,13 @@ static int rockchip_get_mux(struct rockchip_pin_bank *bank, int pin)
 	else
 		regmap = info->regmap_base;
 
+	if (ctrl->type == RK3506) {
+		if (bank->bank_num == 1)
+			regmap = info->regmap_ioc1;
+		else if (bank->bank_num == 4)
+			return 0;
+	}
+
 	/* get basic quadrupel of mux registers and the correct reg inside */
 	mux_type = bank->iomux[iomux_num].type;
 	reg = bank->iomux[iomux_num].offset;
@@ -1239,6 +1298,13 @@ static int rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
 	else
 		regmap = info->regmap_base;
 
+	if (ctrl->type == RK3506) {
+		if (bank->bank_num == 1)
+			regmap = info->regmap_ioc1;
+		else if (bank->bank_num == 4)
+			return 0;
+	}
+
 	/* get basic quadrupel of mux registers and the correct reg inside */
 	mux_type = bank->iomux[iomux_num].type;
 	reg = bank->iomux[iomux_num].offset;
@@ -2003,6 +2069,262 @@ static int rk3399_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
 	return 0;
 }
 
+#define RK3506_DRV_BITS_PER_PIN		8
+#define RK3506_DRV_PINS_PER_REG		2
+#define RK3506_DRV_GPIO0_A_OFFSET	0x100
+#define RK3506_DRV_GPIO0_D_OFFSET	0x830
+#define RK3506_DRV_GPIO1_OFFSET		0x140
+#define RK3506_DRV_GPIO2_OFFSET		0x180
+#define RK3506_DRV_GPIO3_OFFSET		0x1c0
+#define RK3506_DRV_GPIO4_OFFSET		0x840
+
+static int rk3506_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
+					int pin_num, struct regmap **regmap,
+					int *reg, u8 *bit)
+{
+	struct rockchip_pinctrl *info = bank->drvdata;
+	int ret = 0;
+
+	switch (bank->bank_num) {
+	case 0:
+		*regmap = info->regmap_pmu;
+		if (pin_num > 24) {
+			ret = -EINVAL;
+		} else if (pin_num < 24) {
+			*reg = RK3506_DRV_GPIO0_A_OFFSET;
+		} else {
+			*reg = RK3506_DRV_GPIO0_D_OFFSET;
+			*bit = 3;
+
+			return 0;
+		}
+		break;
+
+	case 1:
+		*regmap = info->regmap_ioc1;
+		if (pin_num < 28)
+			*reg = RK3506_DRV_GPIO1_OFFSET;
+		else
+			ret = -EINVAL;
+		break;
+
+	case 2:
+		*regmap = info->regmap_base;
+		if (pin_num < 17)
+			*reg = RK3506_DRV_GPIO2_OFFSET;
+		else
+			ret = -EINVAL;
+		break;
+
+	case 3:
+		*regmap = info->regmap_base;
+		if (pin_num < 15)
+			*reg = RK3506_DRV_GPIO3_OFFSET;
+		else
+			ret = -EINVAL;
+		break;
+
+	case 4:
+		*regmap = info->regmap_base;
+		if (pin_num < 8 || pin_num > 11) {
+			ret = -EINVAL;
+		} else {
+			*reg = RK3506_DRV_GPIO4_OFFSET;
+			*bit = 10;
+
+			return 0;
+		}
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (ret) {
+		dev_err(info->dev, "unsupported bank_num %d pin_num %d\n", bank->bank_num, pin_num);
+
+		return ret;
+	}
+
+	*reg += ((pin_num / RK3506_DRV_PINS_PER_REG) * 4);
+	*bit = pin_num % RK3506_DRV_PINS_PER_REG;
+	*bit *= RK3506_DRV_BITS_PER_PIN;
+
+	return 0;
+}
+
+#define RK3506_PULL_BITS_PER_PIN	2
+#define RK3506_PULL_PINS_PER_REG	8
+#define RK3506_PULL_GPIO0_A_OFFSET	0x200
+#define RK3506_PULL_GPIO0_D_OFFSET	0x830
+#define RK3506_PULL_GPIO1_OFFSET	0x210
+#define RK3506_PULL_GPIO2_OFFSET	0x220
+#define RK3506_PULL_GPIO3_OFFSET	0x230
+#define RK3506_PULL_GPIO4_OFFSET	0x840
+
+static int rk3506_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
+					 int pin_num, struct regmap **regmap,
+					 int *reg, u8 *bit)
+{
+	struct rockchip_pinctrl *info = bank->drvdata;
+	int ret = 0;
+
+	switch (bank->bank_num) {
+	case 0:
+		*regmap = info->regmap_pmu;
+		if (pin_num > 24) {
+			ret = -EINVAL;
+		} else if (pin_num < 24) {
+			*reg = RK3506_PULL_GPIO0_A_OFFSET;
+		} else {
+			*reg = RK3506_PULL_GPIO0_D_OFFSET;
+			*bit = 5;
+
+			return 0;
+		}
+		break;
+
+	case 1:
+		*regmap = info->regmap_ioc1;
+		if (pin_num < 28)
+			*reg = RK3506_PULL_GPIO1_OFFSET;
+		else
+			ret = -EINVAL;
+		break;
+
+	case 2:
+		*regmap = info->regmap_base;
+		if (pin_num < 17)
+			*reg = RK3506_PULL_GPIO2_OFFSET;
+		else
+			ret = -EINVAL;
+		break;
+
+	case 3:
+		*regmap = info->regmap_base;
+		if (pin_num < 15)
+			*reg = RK3506_PULL_GPIO3_OFFSET;
+		else
+			ret = -EINVAL;
+		break;
+
+	case 4:
+		*regmap = info->regmap_base;
+		if (pin_num < 8 || pin_num > 11) {
+			ret = -EINVAL;
+		} else {
+			*reg = RK3506_PULL_GPIO4_OFFSET;
+			*bit = 13;
+
+			return 0;
+		}
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (ret) {
+		dev_err(info->dev, "unsupported bank_num %d pin_num %d\n", bank->bank_num, pin_num);
+
+		return ret;
+	}
+
+	*reg += ((pin_num / RK3506_PULL_PINS_PER_REG) * 4);
+	*bit = pin_num % RK3506_PULL_PINS_PER_REG;
+	*bit *= RK3506_PULL_BITS_PER_PIN;
+
+	return 0;
+}
+
+#define RK3506_SMT_BITS_PER_PIN		1
+#define RK3506_SMT_PINS_PER_REG		8
+#define RK3506_SMT_GPIO0_A_OFFSET	0x400
+#define RK3506_SMT_GPIO0_D_OFFSET	0x830
+#define RK3506_SMT_GPIO1_OFFSET		0x410
+#define RK3506_SMT_GPIO2_OFFSET		0x420
+#define RK3506_SMT_GPIO3_OFFSET		0x430
+#define RK3506_SMT_GPIO4_OFFSET		0x840
+
+static int rk3506_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank,
+					   int pin_num,
+					   struct regmap **regmap,
+					   int *reg, u8 *bit)
+{
+	struct rockchip_pinctrl *info = bank->drvdata;
+	int ret = 0;
+
+	switch (bank->bank_num) {
+	case 0:
+		*regmap = info->regmap_pmu;
+		if (pin_num > 24) {
+			ret = -EINVAL;
+		} else if (pin_num < 24) {
+			*reg = RK3506_SMT_GPIO0_A_OFFSET;
+		} else {
+			*reg = RK3506_SMT_GPIO0_D_OFFSET;
+			*bit = 9;
+
+			return 0;
+		}
+		break;
+
+	case 1:
+		*regmap = info->regmap_ioc1;
+		if (pin_num < 28)
+			*reg = RK3506_SMT_GPIO1_OFFSET;
+		else
+			ret = -EINVAL;
+		break;
+
+	case 2:
+		*regmap = info->regmap_base;
+		if (pin_num < 17)
+			*reg = RK3506_SMT_GPIO2_OFFSET;
+		else
+			ret = -EINVAL;
+		break;
+
+	case 3:
+		*regmap = info->regmap_base;
+		if (pin_num < 15)
+			*reg = RK3506_SMT_GPIO3_OFFSET;
+		else
+			ret = -EINVAL;
+		break;
+
+	case 4:
+		*regmap = info->regmap_base;
+		if (pin_num < 8 || pin_num > 11) {
+			ret = -EINVAL;
+		} else {
+			*reg = RK3506_SMT_GPIO4_OFFSET;
+			*bit = 8;
+
+			return 0;
+		}
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (ret) {
+		dev_err(info->dev, "unsupported bank_num %d pin_num %d\n", bank->bank_num, pin_num);
+
+		return ret;
+	}
+
+	*reg += ((pin_num / RK3506_SMT_PINS_PER_REG) * 4);
+	*bit = pin_num % RK3506_SMT_PINS_PER_REG;
+	*bit *= RK3506_SMT_BITS_PER_PIN;
+
+	return 0;
+}
+
 #define RK3528_DRV_BITS_PER_PIN		8
 #define RK3528_DRV_PINS_PER_REG		2
 #define RK3528_DRV_GPIO0_OFFSET		0x100
@@ -2749,7 +3071,8 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank,
 		rmask_bits = RK3588_DRV_BITS_PER_PIN;
 		ret = strength;
 		goto config;
-	} else if (ctrl->type == RK3528 ||
+	} else if (ctrl->type == RK3506 ||
+		   ctrl->type == RK3528 ||
 		   ctrl->type == RK3562 ||
 		   ctrl->type == RK3568) {
 		rmask_bits = RK3568_DRV_BITS_PER_PIN;
@@ -2828,12 +3151,37 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank,
 	case DRV_TYPE_IO_1V8_ONLY:
 		rmask_bits = RK3288_DRV_BITS_PER_PIN;
 		break;
+	case DRV_TYPE_IO_LEVEL_2_BIT:
+		ret = regmap_read(regmap, reg, &data);
+		if (ret)
+			return ret;
+		data >>= bit;
+
+		return data & 0x3;
+	case DRV_TYPE_IO_LEVEL_8_BIT:
+		ret = regmap_read(regmap, reg, &data);
+		if (ret)
+			return ret;
+		data >>= bit;
+		data &= (1 << 8) - 1;
+
+		ret = hweight8(data);
+		if (ret > 0)
+			return ret - 1;
+		else
+			return -EINVAL;
 	default:
 		dev_err(dev, "unsupported pinctrl drive type: %d\n", drv_type);
 		return -EINVAL;
 	}
 
 config:
+	if (ctrl->type == RK3506) {
+		if ((bank->bank_num == 0 && pin_num == 24) || bank->bank_num == 4) {
+			rmask_bits = 2;
+			ret = strength;
+		}
+	}
 	/* enable the write to the equivalent lower bits */
 	data = ((1 << rmask_bits) - 1) << (bit + 16);
 	rmask = data | (data >> 16);
@@ -2957,6 +3305,7 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank,
 	case RK3328:
 	case RK3368:
 	case RK3399:
+	case RK3506:
 	case RK3528:
 	case RK3562:
 	case RK3568:
@@ -3077,6 +3426,10 @@ static int rockchip_get_schmitt(struct rockchip_pin_bank *bank, int pin_num)
 		break;
 	}
 
+	if (ctrl->type == RK3506)
+		if ((bank->bank_num == 0 && pin_num == 24) ||  bank->bank_num == 4)
+			return data & 0x3;
+
 	return data & 0x1;
 }
 
@@ -3112,6 +3465,14 @@ static int rockchip_set_schmitt(struct rockchip_pin_bank *bank,
 		break;
 	}
 
+	if (ctrl->type == RK3506) {
+		if ((bank->bank_num == 0 && pin_num == 24) || bank->bank_num == 4) {
+			data = 0x3 << (bit + 16);
+			rmask = data | (data >> 16);
+			data |= ((enable ? 0x3 : 0) << bit);
+		}
+	}
+
 	return regmap_update_bits(regmap, reg, rmask, data);
 }
 
@@ -3227,6 +3588,7 @@ static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl,
 	case RK3328:
 	case RK3368:
 	case RK3399:
+	case RK3506:
 	case RK3528:
 	case RK3562:
 	case RK3568:
@@ -3880,13 +4242,10 @@ static int rockchip_pinctrl_probe(struct platform_device *pdev)
 	}
 
 	/* try to find the optional reference to the pmu syscon */
-	node = of_parse_phandle(np, "rockchip,pmu", 0);
-	if (node) {
-		info->regmap_pmu = syscon_node_to_regmap(node);
-		of_node_put(node);
-		if (IS_ERR(info->regmap_pmu))
-			return PTR_ERR(info->regmap_pmu);
-	}
+	info->regmap_pmu = syscon_regmap_lookup_by_phandle_optional(np, "rockchip,pmu");
+
+	/* try to find the optional reference to the ioc1 syscon */
+	info->regmap_ioc1 = syscon_regmap_lookup_by_phandle_optional(np, "rockchip,ioc1");
 
 	ret = rockchip_pinctrl_register(pdev, info);
 	if (ret)
@@ -4350,6 +4709,71 @@ static struct rockchip_pin_ctrl rk3399_pin_ctrl = {
 		.drv_calc_reg		= rk3399_calc_drv_reg_and_bit,
 };
 
+static struct rockchip_pin_bank rk3506_pin_banks[] = {
+	PIN_BANK_IOMUX_FLAGS_OFFSET_DRV_FLAGS_PULL_FLAGS(0, 32, "gpio0",
+				    IOMUX_WIDTH_4BIT | IOMUX_SOURCE_PMU,
+				    IOMUX_WIDTH_4BIT | IOMUX_SOURCE_PMU,
+				    IOMUX_WIDTH_4BIT | IOMUX_SOURCE_PMU,
+				    IOMUX_WIDTH_2BIT | IOMUX_SOURCE_PMU,
+				    0x0, 0x8, 0x10, 0x830,
+				    DRV_TYPE_IO_LEVEL_8_BIT,
+				    DRV_TYPE_IO_LEVEL_8_BIT,
+				    DRV_TYPE_IO_LEVEL_8_BIT,
+				    DRV_TYPE_IO_LEVEL_2_BIT,
+				    0, 0, 0, 1),
+	PIN_BANK_IOMUX_FLAGS_OFFSET_DRV_FLAGS(1, 32, "gpio1",
+				    IOMUX_WIDTH_4BIT,
+				    IOMUX_WIDTH_4BIT,
+				    IOMUX_WIDTH_4BIT,
+				    IOMUX_WIDTH_4BIT,
+				    0x20, 0x28, 0x30, 0x38,
+				    DRV_TYPE_IO_LEVEL_8_BIT,
+				    DRV_TYPE_IO_LEVEL_8_BIT,
+				    DRV_TYPE_IO_LEVEL_8_BIT,
+				    DRV_TYPE_IO_LEVEL_8_BIT),
+	PIN_BANK_IOMUX_FLAGS_OFFSET_DRV_FLAGS(2, 32, "gpio2",
+				    IOMUX_WIDTH_4BIT,
+				    IOMUX_WIDTH_4BIT,
+				    IOMUX_WIDTH_4BIT,
+				    IOMUX_WIDTH_4BIT,
+				    0x40, 0x48, 0x50, 0x58,
+				    DRV_TYPE_IO_LEVEL_8_BIT,
+				    DRV_TYPE_IO_LEVEL_8_BIT,
+				    DRV_TYPE_IO_LEVEL_8_BIT,
+				    DRV_TYPE_IO_LEVEL_8_BIT),
+	PIN_BANK_IOMUX_FLAGS_OFFSET_DRV_FLAGS(3, 32, "gpio3",
+				    IOMUX_WIDTH_4BIT,
+				    IOMUX_WIDTH_4BIT,
+				    IOMUX_WIDTH_4BIT,
+				    IOMUX_WIDTH_4BIT,
+				    0x60, 0x68, 0x70, 0x78,
+				    DRV_TYPE_IO_LEVEL_8_BIT,
+				    DRV_TYPE_IO_LEVEL_8_BIT,
+				    DRV_TYPE_IO_LEVEL_8_BIT,
+				    DRV_TYPE_IO_LEVEL_8_BIT),
+	PIN_BANK_IOMUX_FLAGS_OFFSET_DRV_FLAGS_PULL_FLAGS(4, 32, "gpio4",
+				    IOMUX_WIDTH_4BIT,
+				    IOMUX_WIDTH_4BIT,
+				    IOMUX_WIDTH_4BIT,
+				    IOMUX_WIDTH_4BIT,
+				    0x80, 0x88, 0x90, 0x98,
+				    DRV_TYPE_IO_LEVEL_2_BIT,
+				    DRV_TYPE_IO_LEVEL_2_BIT,
+				    DRV_TYPE_IO_LEVEL_2_BIT,
+				    DRV_TYPE_IO_LEVEL_2_BIT,
+				    1, 1, 1, 1),
+};
+
+static struct rockchip_pin_ctrl rk3506_pin_ctrl __maybe_unused = {
+	.pin_banks		= rk3506_pin_banks,
+	.nr_banks		= ARRAY_SIZE(rk3506_pin_banks),
+	.label			= "RK3506-GPIO",
+	.type			= RK3506,
+	.pull_calc_reg		= rk3506_calc_pull_reg_and_bit,
+	.drv_calc_reg		= rk3506_calc_drv_reg_and_bit,
+	.schmitt_calc_reg	= rk3506_calc_schmitt_reg_and_bit,
+};
+
 static struct rockchip_pin_bank rk3528_pin_banks[] = {
 	PIN_BANK_IOMUX_FLAGS_OFFSET(0, 32, "gpio0",
 				    IOMUX_WIDTH_4BIT,
@@ -4560,6 +4984,8 @@ static const struct of_device_id rockchip_pinctrl_dt_match[] = {
 		.data = &rk3368_pin_ctrl },
 	{ .compatible = "rockchip,rk3399-pinctrl",
 		.data = &rk3399_pin_ctrl },
+	{ .compatible = "rockchip,rk3506-pinctrl",
+		.data = &rk3506_pin_ctrl },
 	{ .compatible = "rockchip,rk3528-pinctrl",
 		.data = &rk3528_pin_ctrl },
 	{ .compatible = "rockchip,rk3562-pinctrl",
diff --git a/drivers/pinctrl/pinctrl-rockchip.h b/drivers/pinctrl/pinctrl-rockchip.h
index 35cd38079d1e..4f4aff42a80a 100644
--- a/drivers/pinctrl/pinctrl-rockchip.h
+++ b/drivers/pinctrl/pinctrl-rockchip.h
@@ -196,6 +196,7 @@ enum rockchip_pinctrl_type {
 	RK3328,
 	RK3368,
 	RK3399,
+	RK3506,
 	RK3528,
 	RK3562,
 	RK3568,
@@ -260,6 +261,8 @@ enum rockchip_pin_drv_type {
 	DRV_TYPE_IO_1V8_ONLY,
 	DRV_TYPE_IO_1V8_3V0_AUTO,
 	DRV_TYPE_IO_3V3_ONLY,
+	DRV_TYPE_IO_LEVEL_2_BIT,
+	DRV_TYPE_IO_LEVEL_8_BIT,
 	DRV_TYPE_MAX
 };
 
@@ -458,6 +461,7 @@ struct rockchip_pinctrl {
 	int				reg_size;
 	struct regmap			*regmap_pull;
 	struct regmap			*regmap_pmu;
+	struct regmap			*regmap_ioc1;
 	struct device			*dev;
 	struct rockchip_pin_ctrl	*ctrl;
 	struct pinctrl_desc		pctl;
-- 
2.34.1



From ye.zhang at rock-chips.com  Tue Dec 16 03:20:51 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Tue, 16 Dec 2025 19:20:51 +0800
Subject: [PATCH v3 5/7] gpio: rockchip: support new version GPIO
In-Reply-To: <20251216112053.1927852-1-ye.zhang@rock-chips.com>
References: <20251216112053.1927852-1-ye.zhang@rock-chips.com>
Message-ID: <20251216112053.1927852-6-ye.zhang@rock-chips.com>

Support the next version GPIO controller on SoCs like rv1126b.

Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
Acked-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/gpio/gpio-rockchip.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c
index 47174eb3ba76..c3e831c6bcf1 100644
--- a/drivers/gpio/gpio-rockchip.c
+++ b/drivers/gpio/gpio-rockchip.c
@@ -36,6 +36,7 @@
 #define GPIO_TYPE_V2		(0x01000C2B)
 #define GPIO_TYPE_V2_1		(0x0101157C)
 #define GPIO_TYPE_V2_2		(0x010219C8)
+#define GPIO_TYPE_V2_6          (0x01063F6E)
 
 static const struct rockchip_gpio_regs gpio_regs_v1 = {
 	.port_dr = 0x00,
@@ -674,6 +675,7 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank)
 	case GPIO_TYPE_V2:
 	case GPIO_TYPE_V2_1:
 	case GPIO_TYPE_V2_2:
+	case GPIO_TYPE_V2_6:
 		bank->gpio_regs = &gpio_regs_v2;
 		bank->gpio_type = GPIO_TYPE_V2;
 		bank->db_clk = of_clk_get(bank->of_node, 1);
-- 
2.34.1



From ye.zhang at rock-chips.com  Tue Dec 16 03:20:50 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Tue, 16 Dec 2025 19:20:50 +0800
Subject: [PATCH v3 4/7] arm64: dts: rockchip: rv1126b: Add pinconf and pinctrl dtsi for rv1126b
In-Reply-To: <20251216112053.1927852-1-ye.zhang@rock-chips.com>
References: <20251216112053.1927852-1-ye.zhang@rock-chips.com>
Message-ID: <20251216112053.1927852-5-ye.zhang@rock-chips.com>

Add the core pinctrl device tree node and pin definitions for the
Rockchip RV1126B SoC.

Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
---
 .../boot/dts/rockchip/rv1126b-pinconf.dtsi    |  660 ++++
 .../boot/dts/rockchip/rv1126b-pinctrl.dtsi    | 3218 +++++++++++++++++
 2 files changed, 3878 insertions(+)
 create mode 100644 arch/arm64/boot/dts/rockchip/rv1126b-pinconf.dtsi
 create mode 100644 arch/arm64/boot/dts/rockchip/rv1126b-pinctrl.dtsi

diff --git a/arch/arm64/boot/dts/rockchip/rv1126b-pinconf.dtsi b/arch/arm64/boot/dts/rockchip/rv1126b-pinconf.dtsi
new file mode 100644
index 000000000000..0eacbf17a5fe
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rv1126b-pinconf.dtsi
@@ -0,0 +1,660 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2025 Rockchip Electronics Co., Ltd.
+ */
+
+&pinctrl {
+	/omit-if-no-ref/
+	pcfg_pull_up: pcfg-pull-up {
+		bias-pull-up;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down: pcfg-pull-down {
+		bias-pull-down;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none: pcfg-pull-none {
+		bias-disable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_0_25: pcfg-pull-none-drv-level-0-25 {
+		bias-disable;
+		drive-strength = <0x01>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_0_50: pcfg-pull-none-drv-level-0-50 {
+		bias-disable;
+		drive-strength = <0x02>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_0_75: pcfg-pull-none-drv-level-0-75 {
+		bias-disable;
+		drive-strength = <0x03>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_1_00: pcfg-pull-none-drv-level-1-00 {
+		bias-disable;
+		drive-strength = <0x04>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_1_25: pcfg-pull-none-drv-level-1-25 {
+		bias-disable;
+		drive-strength = <0x05>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_1_50: pcfg-pull-none-drv-level-1-50 {
+		bias-disable;
+		drive-strength = <0x06>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_1_75: pcfg-pull-none-drv-level-1-75 {
+		bias-disable;
+		drive-strength = <0x07>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_2_00: pcfg-pull-none-drv-level-2-00 {
+		bias-disable;
+		drive-strength = <0x0c>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_2_25: pcfg-pull-none-drv-level-2-25 {
+		bias-disable;
+		drive-strength = <0x0d>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_2_50: pcfg-pull-none-drv-level-2-50 {
+		bias-disable;
+		drive-strength = <0x0e>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_2_75: pcfg-pull-none-drv-level-2-75 {
+		bias-disable;
+		drive-strength = <0x0f>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_3_00: pcfg-pull-none-drv-level-3-00 {
+		bias-disable;
+		drive-strength = <0x1c>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_3_25: pcfg-pull-none-drv-level-3-25 {
+		bias-disable;
+		drive-strength = <0x1d>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_3_50: pcfg-pull-none-drv-level-3-50 {
+		bias-disable;
+		drive-strength = <0x1e>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_3_75: pcfg-pull-none-drv-level-3-75 {
+		bias-disable;
+		drive-strength = <0x1f>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_4_00: pcfg-pull-none-drv-level-4-00 {
+		bias-disable;
+		drive-strength = <0x2c>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_4_25: pcfg-pull-none-drv-level-4-25 {
+		bias-disable;
+		drive-strength = <0x2d>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_4_50: pcfg-pull-none-drv-level-4-50 {
+		bias-disable;
+		drive-strength = <0x2e>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_4_75: pcfg-pull-none-drv-level-4-75 {
+		bias-disable;
+		drive-strength = <0x2f>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_5_00: pcfg-pull-none-drv-level-5-00 {
+		bias-disable;
+		drive-strength = <0x3c>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_5_25: pcfg-pull-none-drv-level-5-25 {
+		bias-disable;
+		drive-strength = <0x3d>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_5_50: pcfg-pull-none-drv-level-5-50 {
+		bias-disable;
+		drive-strength = <0x3e>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_5_75: pcfg-pull-none-drv-level-5-75 {
+		bias-disable;
+		drive-strength = <0x3f>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_0_25: pcfg-pull-up-drv-level-0-25 {
+		bias-pull-up;
+		drive-strength = <0x01>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_0_50: pcfg-pull-up-drv-level-0-50 {
+		bias-pull-up;
+		drive-strength = <0x02>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_0_75: pcfg-pull-up-drv-level-0-75 {
+		bias-pull-up;
+		drive-strength = <0x03>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_1_00: pcfg-pull-up-drv-level-1-00 {
+		bias-pull-up;
+		drive-strength = <0x04>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_1_25: pcfg-pull-up-drv-level-1-25 {
+		bias-pull-up;
+		drive-strength = <0x05>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_1_50: pcfg-pull-up-drv-level-1-50 {
+		bias-pull-up;
+		drive-strength = <0x06>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_1_75: pcfg-pull-up-drv-level-1-75 {
+		bias-pull-up;
+		drive-strength = <0x07>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_2_00: pcfg-pull-up-drv-level-2-00 {
+		bias-pull-up;
+		drive-strength = <0x0c>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_2_25: pcfg-pull-up-drv-level-2-25 {
+		bias-pull-up;
+		drive-strength = <0x0d>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_2_50: pcfg-pull-up-drv-level-2-50 {
+		bias-pull-up;
+		drive-strength = <0x0e>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_2_75: pcfg-pull-up-drv-level-2-75 {
+		bias-pull-up;
+		drive-strength = <0x0f>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_3_00: pcfg-pull-up-drv-level-3-00 {
+		bias-pull-up;
+		drive-strength = <0x1c>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_3_25: pcfg-pull-up-drv-level-3-25 {
+		bias-pull-up;
+		drive-strength = <0x1d>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_3_50: pcfg-pull-up-drv-level-3-50 {
+		bias-pull-up;
+		drive-strength = <0x1e>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_3_75: pcfg-pull-up-drv-level-3-75 {
+		bias-pull-up;
+		drive-strength = <0x1f>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_4_00: pcfg-pull-up-drv-level-4-00 {
+		bias-pull-up;
+		drive-strength = <0x2c>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_4_25: pcfg-pull-up-drv-level-4-25 {
+		bias-pull-up;
+		drive-strength = <0x2d>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_4_50: pcfg-pull-up-drv-level-4-50 {
+		bias-pull-up;
+		drive-strength = <0x2e>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_4_75: pcfg-pull-up-drv-level-4-75 {
+		bias-pull-up;
+		drive-strength = <0x2f>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_5_00: pcfg-pull-up-drv-level-5-00 {
+		bias-pull-up;
+		drive-strength = <0x3c>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_5_25: pcfg-pull-up-drv-level-5-25 {
+		bias-pull-up;
+		drive-strength = <0x3d>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_5_50: pcfg-pull-up-drv-level-5-50 {
+		bias-pull-up;
+		drive-strength = <0x3e>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_5_75: pcfg-pull-up-drv-level-5-75 {
+		bias-pull-up;
+		drive-strength = <0x3f>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_0_25: pcfg-pull-down-drv-level-0-25 {
+		bias-pull-down;
+		drive-strength = <0x01>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_0_50: pcfg-pull-down-drv-level-0-50 {
+		bias-pull-down;
+		drive-strength = <0x02>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_0_75: pcfg-pull-down-drv-level-0-75 {
+		bias-pull-down;
+		drive-strength = <0x03>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_1_00: pcfg-pull-down-drv-level-1-00 {
+		bias-pull-down;
+		drive-strength = <0x04>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_1_25: pcfg-pull-down-drv-level-1-25 {
+		bias-pull-down;
+		drive-strength = <0x05>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_1_50: pcfg-pull-down-drv-level-1-50 {
+		bias-pull-down;
+		drive-strength = <0x06>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_1_75: pcfg-pull-down-drv-level-1-75 {
+		bias-pull-down;
+		drive-strength = <0x07>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_2_00: pcfg-pull-down-drv-level-2-00 {
+		bias-pull-down;
+		drive-strength = <0x0c>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_2_25: pcfg-pull-down-drv-level-2-25 {
+		bias-pull-down;
+		drive-strength = <0x0d>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_2_50: pcfg-pull-down-drv-level-2-50 {
+		bias-pull-down;
+		drive-strength = <0x0e>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_2_75: pcfg-pull-down-drv-level-2-75 {
+		bias-pull-down;
+		drive-strength = <0x0f>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_3_00: pcfg-pull-down-drv-level-3-00 {
+		bias-pull-down;
+		drive-strength = <0x1c>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_3_25: pcfg-pull-down-drv-level-3-25 {
+		bias-pull-down;
+		drive-strength = <0x1d>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_3_50: pcfg-pull-down-drv-level-3-50 {
+		bias-pull-down;
+		drive-strength = <0x1e>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_3_75: pcfg-pull-down-drv-level-3-75 {
+		bias-pull-down;
+		drive-strength = <0x1f>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_4_00: pcfg-pull-down-drv-level-4-00 {
+		bias-pull-down;
+		drive-strength = <0x2c>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_4_25: pcfg-pull-down-drv-level-4-25 {
+		bias-pull-down;
+		drive-strength = <0x2d>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_4_50: pcfg-pull-down-drv-level-4-50 {
+		bias-pull-down;
+		drive-strength = <0x2e>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_4_75: pcfg-pull-down-drv-level-4-75 {
+		bias-pull-down;
+		drive-strength = <0x2f>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_5_00: pcfg-pull-down-drv-level-5-00 {
+		bias-pull-down;
+		drive-strength = <0x3c>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_5_25: pcfg-pull-down-drv-level-5-25 {
+		bias-pull-down;
+		drive-strength = <0x3d>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_5_50: pcfg-pull-down-drv-level-5-50 {
+		bias-pull-down;
+		drive-strength = <0x3e>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_5_75: pcfg-pull-down-drv-level-5-75 {
+		bias-pull-down;
+		drive-strength = <0x3f>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_smt: pcfg-pull-up-smt {
+		bias-pull-up;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_smt: pcfg-pull-down-smt {
+		bias-pull-down;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_smt: pcfg-pull-none-smt {
+		bias-disable;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_0_25_smt: pcfg-pull-none-drv-level-0-25-smt {
+		bias-disable;
+		drive-strength = <0x01>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_0_50_smt: pcfg-pull-none-drv-level-0-50-smt {
+		bias-disable;
+		drive-strength = <0x02>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_0_75_smt: pcfg-pull-none-drv-level-0-75-smt {
+		bias-disable;
+		drive-strength = <0x03>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_1_00_smt: pcfg-pull-none-drv-level-1-00-smt {
+		bias-disable;
+		drive-strength = <0x04>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_1_25_smt: pcfg-pull-none-drv-level-1-25-smt {
+		bias-disable;
+		drive-strength = <0x05>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_1_50_smt: pcfg-pull-none-drv-level-1-50-smt {
+		bias-disable;
+		drive-strength = <0x06>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_1_75_smt: pcfg-pull-none-drv-level-1-75-smt {
+		bias-disable;
+		drive-strength = <0x07>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_2_00_smt: pcfg-pull-none-drv-level-2-00-smt {
+		bias-disable;
+		drive-strength = <0x0c>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_2_25_smt: pcfg-pull-none-drv-level-2-25-smt {
+		bias-disable;
+		drive-strength = <0x0d>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_2_50_smt: pcfg-pull-none-drv-level-2-50-smt {
+		bias-disable;
+		drive-strength = <0x0e>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_2_75_smt: pcfg-pull-none-drv-level-2-75-smt {
+		bias-disable;
+		drive-strength = <0x0f>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_3_00_smt: pcfg-pull-none-drv-level-3-00-smt {
+		bias-disable;
+		drive-strength = <0x1c>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_3_25_smt: pcfg-pull-none-drv-level-3-25-smt {
+		bias-disable;
+		drive-strength = <0x1d>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_3_50_smt: pcfg-pull-none-drv-level-3-50-smt {
+		bias-disable;
+		drive-strength = <0x1e>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_3_75_smt: pcfg-pull-none-drv-level-3-75-smt {
+		bias-disable;
+		drive-strength = <0x1f>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_4_00_smt: pcfg-pull-none-drv-level-4-00-smt {
+		bias-disable;
+		drive-strength = <0x2c>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_4_25_smt: pcfg-pull-none-drv-level-4-25-smt {
+		bias-disable;
+		drive-strength = <0x2d>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_4_50_smt: pcfg-pull-none-drv-level-4-50-smt {
+		bias-disable;
+		drive-strength = <0x2e>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_4_75_smt: pcfg-pull-none-drv-level-4-75-smt {
+		bias-disable;
+		drive-strength = <0x2f>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_5_00_smt: pcfg-pull-none-drv-level-5-00-smt {
+		bias-disable;
+		drive-strength = <0x3c>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_5_25_smt: pcfg-pull-none-drv-level-5-25-smt {
+		bias-disable;
+		drive-strength = <0x3d>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_5_50_smt: pcfg-pull-none-drv-level-5-50-smt {
+		bias-disable;
+		drive-strength = <0x3e>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_5_75_smt: pcfg-pull-none-drv-level-5-75-smt {
+		bias-disable;
+		drive-strength = <0x3f>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_output_high: pcfg-output-high {
+		output-high;
+	};
+
+	/omit-if-no-ref/
+	pcfg_output_high_pull_up: pcfg-output-high-pull-up {
+		output-high;
+		bias-pull-up;
+	};
+
+	/omit-if-no-ref/
+	pcfg_output_high_pull_down: pcfg-output-high-pull-down {
+		output-high;
+		bias-pull-down;
+	};
+
+	/omit-if-no-ref/
+	pcfg_output_high_pull_none: pcfg-output-high-pull-none {
+		output-high;
+		bias-disable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_output_low: pcfg-output-low {
+		output-low;
+	};
+
+	/omit-if-no-ref/
+	pcfg_output_low_pull_up: pcfg-output-low-pull-up {
+		output-low;
+		bias-pull-up;
+	};
+
+	/omit-if-no-ref/
+	pcfg_output_low_pull_down: pcfg-output-low-pull-down {
+		output-low;
+		bias-pull-down;
+	};
+
+	/omit-if-no-ref/
+	pcfg_output_low_pull_none: pcfg-output-low-pull-none {
+		output-low;
+		bias-disable;
+	};
+};
diff --git a/arch/arm64/boot/dts/rockchip/rv1126b-pinctrl.dtsi b/arch/arm64/boot/dts/rockchip/rv1126b-pinctrl.dtsi
new file mode 100644
index 000000000000..f61e7435b4d4
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rv1126b-pinctrl.dtsi
@@ -0,0 +1,3218 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2024 Rockchip Electronics Co., Ltd.
+ */
+
+#include <dt-bindings/pinctrl/rockchip.h>
+#include "rv1126b-pinconf.dtsi"
+
+/*
+ * This file is auto generated by pin2dts tool, please keep these code
+ * by adding changes at end of this file.
+ */
+&pinctrl {
+	aupll_clk {
+		/omit-if-no-ref/
+		aupll_clk_pins: aupll-clk-pins {
+			rockchip,pins =
+				/* aupll_clk_in */
+				<7 RK_PA1 1 &pcfg_pull_none>;
+		};
+	};
+
+	cam_clk0 {
+		/omit-if-no-ref/
+		cam_clk0_pins: cam-clk0-pins {
+			rockchip,pins =
+				/* cam_clk0_out */
+				<4 RK_PB1 3 &pcfg_pull_none>;
+		};
+	};
+
+	cam_clk1 {
+		/omit-if-no-ref/
+		cam_clk1_pins: cam-clk1-pins {
+			rockchip,pins =
+				/* cam_clk1_out */
+				<4 RK_PB0 3 &pcfg_pull_none>;
+		};
+	};
+
+	cam_clk2 {
+		/omit-if-no-ref/
+		cam_clk2_pins: cam-clk2-pins {
+			rockchip,pins =
+				/* cam_clk2_out */
+				<4 RK_PA1 3 &pcfg_pull_none>;
+		};
+	};
+
+	cam_clk3 {
+		/omit-if-no-ref/
+		cam_clk3_pins: cam-clk3-pins {
+			rockchip,pins =
+				/* cam_clk3_out */
+				<4 RK_PA0 3 &pcfg_pull_none>;
+		};
+	};
+
+	can0 {
+		/omit-if-no-ref/
+		can0m0_pins: can0m0-pins {
+			rockchip,pins =
+				/* can0_rxd_m0 */
+				<5 RK_PD4 3 &pcfg_pull_none>,
+				/* can0_txd_m0 */
+				<5 RK_PD5 3 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		can0m1_pins: can0m1-pins {
+			rockchip,pins =
+				/* can0_rxd_m1 */
+				<6 RK_PA0 3 &pcfg_pull_none>,
+				/* can0_txd_m1 */
+				<6 RK_PA1 3 &pcfg_pull_none>;
+		};
+	};
+
+	can1 {
+		/omit-if-no-ref/
+		can1m0_pins: can1m0-pins {
+			rockchip,pins =
+				/* can1_rxd_m0 */
+				<5 RK_PD6 3 &pcfg_pull_none>,
+				/* can1_txd_m0 */
+				<5 RK_PD7 3 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		can1m1_pins: can1m1-pins {
+			rockchip,pins =
+				/* can1_rxd_m1 */
+				<6 RK_PA2 3 &pcfg_pull_none>,
+				/* can1_txd_m1 */
+				<6 RK_PA3 3 &pcfg_pull_none>;
+		};
+	};
+
+	clk {
+		/omit-if-no-ref/
+		clk_pins: clk-pins {
+			rockchip,pins =
+				/* clk_32k */
+				<0 RK_PA2 2 &pcfg_pull_none>;
+		};
+	};
+
+	dsm_aud {
+		/omit-if-no-ref/
+		dsm_aud_ln_pins: dsm-aud-ln-pins {
+			rockchip,pins =
+				/* dsm_aud_ln */
+				<7 RK_PA3 4 &pcfg_pull_down>;
+		};
+
+		/omit-if-no-ref/
+		dsm_aud_lp_pins: dsm-aud-lp-pins {
+			rockchip,pins =
+				/* dsm_aud_lp */
+				<7 RK_PA5 4 &pcfg_pull_down>;
+		};
+
+		/omit-if-no-ref/
+		dsm_aud_rn_pins: dsm-aud-rn-pins {
+			rockchip,pins =
+				/* dsm_aud_rn */
+				<7 RK_PB0 4 &pcfg_pull_down>;
+		};
+
+		/omit-if-no-ref/
+		dsm_aud_rp_pins: dsm-aud-rp-pins {
+			rockchip,pins =
+				/* dsm_aud_rp */
+				<7 RK_PB1 4 &pcfg_pull_down>;
+		};
+	};
+
+	dsmc {
+		/omit-if-no-ref/
+		dsmc_int_pins: dsmc-int-pins {
+			rockchip,pins =
+				/* dsmc_int0 */
+				<5 RK_PB6 5 &pcfg_pull_down>,
+				/* dsmc_int1 */
+				<5 RK_PB2 5 &pcfg_pull_down>;
+		};
+
+		/omit-if-no-ref/
+		dsmc_clk_pins: dsmc-clk-pins {
+			rockchip,pins =
+				/* dsmc_clkn */
+				<5 RK_PB6 4 &pcfg_pull_up>,
+				/* dsmc_resetn */
+				<5 RK_PB2 4 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		dsmc_csn_pins: dsmc-csn-pins {
+			rockchip,pins =
+				/* dsmc_csn0 */
+				<5 RK_PB4 4 &pcfg_pull_up>,
+				/* dsmc_csn1 */
+				<5 RK_PA0 4 &pcfg_pull_up>,
+				/* dsmc_csn2 */
+				<5 RK_PD1 4 &pcfg_pull_up>,
+				/* dsmc_csn3 */
+				<5 RK_PD0 4 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		dsmc_bus16_pins: dsmc-bus16-pins {
+			rockchip,pins =
+				/* dsmc_clkp */
+				<5 RK_PB7 4 &pcfg_pull_down>,
+				/* dsmc_d0 */
+				<5 RK_PC7 4 &pcfg_pull_down>,
+				/* dsmc_d1 */
+				<5 RK_PC6 4 &pcfg_pull_down>,
+				/* dsmc_d2 */
+				<5 RK_PC5 4 &pcfg_pull_down>,
+				/* dsmc_d3 */
+				<5 RK_PC4 4 &pcfg_pull_down>,
+				/* dsmc_d4 */
+				<5 RK_PC3 4 &pcfg_pull_down>,
+				/* dsmc_d5 */
+				<5 RK_PC2 4 &pcfg_pull_down>,
+				/* dsmc_d6 */
+				<5 RK_PC1 4 &pcfg_pull_down>,
+				/* dsmc_d7 */
+				<5 RK_PC0 4 &pcfg_pull_down>,
+				/* dsmc_d8 */
+				<5 RK_PB1 4 &pcfg_pull_down>,
+				/* dsmc_d9 */
+				<5 RK_PB0 4 &pcfg_pull_down>,
+				/* dsmc_d10 */
+				<5 RK_PA7 4 &pcfg_pull_down>,
+				/* dsmc_d11 */
+				<5 RK_PA6 4 &pcfg_pull_down>,
+				/* dsmc_d12 */
+				<5 RK_PA5 4 &pcfg_pull_down>,
+				/* dsmc_d13 */
+				<5 RK_PA4 4 &pcfg_pull_down>,
+				/* dsmc_d14 */
+				<5 RK_PA3 4 &pcfg_pull_down>,
+				/* dsmc_d15 */
+				<5 RK_PA2 4 &pcfg_pull_down>,
+				/* dsmc_dqs0 */
+				<5 RK_PB5 4 &pcfg_pull_down>,
+				/* dsmc_dqs1 */
+				<5 RK_PA1 4 &pcfg_pull_down>,
+				/* dsmc_int2 */
+				<5 RK_PD3 4 &pcfg_pull_down>,
+				/* dsmc_int3 */
+				<5 RK_PD2 4 &pcfg_pull_down>,
+				/* dsmc_rdyn */
+				<5 RK_PB3 4 &pcfg_pull_down>;
+		};
+	};
+
+	emmc {
+		/omit-if-no-ref/
+		emmc_pins: emmc-pins {
+			rockchip,pins =
+				/* emmc_clk */
+				<1 RK_PB3 1 &pcfg_pull_none>,
+				/* emmc_cmd */
+				<1 RK_PB1 1 &pcfg_pull_none>,
+				/* emmc_d0 */
+				<1 RK_PA0 1 &pcfg_pull_none>,
+				/* emmc_d1 */
+				<1 RK_PA1 1 &pcfg_pull_none>,
+				/* emmc_d2 */
+				<1 RK_PA2 1 &pcfg_pull_none>,
+				/* emmc_d3 */
+				<1 RK_PA3 1 &pcfg_pull_none>,
+				/* emmc_d4 */
+				<1 RK_PA4 1 &pcfg_pull_none>,
+				/* emmc_d5 */
+				<1 RK_PA5 1 &pcfg_pull_none>,
+				/* emmc_d6 */
+				<1 RK_PA6 1 &pcfg_pull_none>,
+				/* emmc_d7 */
+				<1 RK_PA7 1 &pcfg_pull_none>;
+		};
+	};
+
+	eth {
+		/omit-if-no-ref/
+		ethm0_miim_pins: ethm0-miim-pins {
+			rockchip,pins =
+				/* eth_mdc_m0 */
+				<6 RK_PC0 2 &pcfg_pull_none_drv_level_3_75>,
+				/* eth_mdio_m0 */
+				<6 RK_PB7 2 &pcfg_pull_none_drv_level_3_75>;
+		};
+
+		/omit-if-no-ref/
+		ethm0_mclk_pins: ethm0-mclk-pins {
+			rockchip,pins =
+				/* eth_mclk_m0 */
+				<6 RK_PB4 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		ethm0_rx_bus2_pins: ethm0-rx-bus2-pins {
+			rockchip,pins =
+				/* eth_rxctl_m0 */
+				<6 RK_PB5 2 &pcfg_pull_none>,
+				/* eth_rxd0_m0 */
+				<6 RK_PB2 2 &pcfg_pull_none>,
+				/* eth_rxd1_m0 */
+				<6 RK_PB3 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		ethm0_tx_bus2_pins: ethm0-tx-bus2-pins {
+			rockchip,pins =
+				/* eth_txctl_m0 */
+				<6 RK_PB1 2 &pcfg_pull_none>,
+				/* eth_txd0_m0 */
+				<6 RK_PA7 2 &pcfg_pull_none_drv_level_3_75>,
+				/* eth_txd1_m0 */
+				<6 RK_PB0 2 &pcfg_pull_none_drv_level_3_75>;
+		};
+
+		/omit-if-no-ref/
+		ethm0_rgmii_clk_pins: ethm0-rgmii-clk-pins {
+			rockchip,pins =
+				/* eth_rxclk_m0 */
+				<6 RK_PC3 2 &pcfg_pull_none>,
+				/* eth_txclk_m0 */
+				<6 RK_PC2 2 &pcfg_pull_none_drv_level_3_75>;
+		};
+
+		/omit-if-no-ref/
+		ethm0_rgmii_bus_pins: ethm0-rgmii-bus-pins {
+			rockchip,pins =
+				/* eth_rxd2_m0 */
+				<6 RK_PA3 2 &pcfg_pull_none>,
+				/* eth_rxd3_m0 */
+				<6 RK_PA4 2 &pcfg_pull_none>,
+				/* eth_txd2_m0 */
+				<6 RK_PA5 2 &pcfg_pull_none_drv_level_3_75>,
+				/* eth_txd3_m0 */
+				<6 RK_PA6 2 &pcfg_pull_none_drv_level_3_75>;
+		};
+
+		/omit-if-no-ref/
+		ethm0_ppsclk_pins: ethm0-ppsclk-pins {
+			rockchip,pins =
+				/* eth_ppsclk_m0 */
+				<6 RK_PA2 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		ethm0_ppstrig_pins: ethm0-ppstrig-pins {
+			rockchip,pins =
+				/* eth_ppstrig_m0 */
+				<6 RK_PA0 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		ethm1_miim_pins: ethm1-miim-pins {
+			rockchip,pins =
+				/* eth_mdc_m1 */
+				<5 RK_PB6 2 &pcfg_pull_none_drv_level_5_00>,
+				/* eth_mdio_m1 */
+				<5 RK_PB5 2 &pcfg_pull_none_drv_level_5_00>;
+		};
+
+		/omit-if-no-ref/
+		ethm1_mclk_pins: ethm1-mclk-pins {
+			rockchip,pins =
+				/* eth_mclk_m1 */
+				<5 RK_PB3 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		ethm1_rx_bus2_pins: ethm1-rx-bus2-pins {
+			rockchip,pins =
+				/* eth_rxctl_m1 */
+				<5 RK_PB0 2 &pcfg_pull_none>,
+				/* eth_rxd0_m1 */
+				<5 RK_PB1 2 &pcfg_pull_none>,
+				/* eth_rxd1_m1 */
+				<5 RK_PB2 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		ethm1_tx_bus2_pins: ethm1-tx-bus2-pins {
+			rockchip,pins =
+				/* eth_txctl_m1 */
+				<5 RK_PC2 2 &pcfg_pull_none>,
+				/* eth_txd0_m1 */
+				<5 RK_PB7 2 &pcfg_pull_none_drv_level_5_00>,
+				/* eth_txd1_m1 */
+				<5 RK_PC0 2 &pcfg_pull_none_drv_level_5_00>;
+		};
+
+		/omit-if-no-ref/
+		ethm1_rgmii_clk_pins: ethm1-rgmii-clk-pins {
+			rockchip,pins =
+				/* eth_rxclk_m1 */
+				<5 RK_PC7 2 &pcfg_pull_none>,
+				/* eth_txclk_m1 */
+				<5 RK_PC6 2 &pcfg_pull_none_drv_level_5_00>;
+		};
+
+		/omit-if-no-ref/
+		ethm1_rgmii_bus_pins: ethm1-rgmii-bus-pins {
+			rockchip,pins =
+				/* eth_rxd2_m1 */
+				<5 RK_PC3 2 &pcfg_pull_none>,
+				/* eth_rxd3_m1 */
+				<5 RK_PC4 2 &pcfg_pull_none>,
+				/* eth_txd2_m1 */
+				<5 RK_PC5 2 &pcfg_pull_none_drv_level_5_00>,
+				/* eth_txd3_m1 */
+				<5 RK_PA0 2 &pcfg_pull_none_drv_level_5_00>;
+		};
+
+		/omit-if-no-ref/
+		ethm1_ppsclk_pins: ethm1-ppsclk-pins {
+			rockchip,pins =
+				/* eth_ppsclk_m1 */
+				<5 RK_PA2 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		ethm1_ppstrig_pins: ethm1-ppstrig-pins {
+			rockchip,pins =
+				/* eth_ppstrig_m1 */
+				<5 RK_PD1 3 &pcfg_pull_none>;
+		};
+	};
+
+	eth_clk_25m {
+		/omit-if-no-ref/
+		eth_clk_25mm0_out_pins: eth-clk-25mm0-out-pins {
+			rockchip,pins =
+				/* eth_clk_25m_out_m0 */
+				<6 RK_PC1 2 &pcfg_pull_none_drv_level_3_75>;
+		};
+
+		/omit-if-no-ref/
+		eth_clk_25mm1_out_pins: eth-clk-25mm1-out-pins {
+			rockchip,pins =
+				/* eth_clk_25m_out_m1 */
+				<5 RK_PC1 2 &pcfg_pull_none_drv_level_5_00>;
+		};
+	};
+
+	eth_ptp {
+		/omit-if-no-ref/
+		ethm0_ptp_refclk_pins: ethm0-ptp-refclk-pins {
+			rockchip,pins =
+				/* ethm0_ptp_refclk */
+				<6 RK_PA1 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		ethm1_ptp_refclk_pins: ethm1-ptp-refclk-pins {
+			rockchip,pins =
+				/* ethm1_ptp_refclk */
+				<5 RK_PD0 3 &pcfg_pull_none>;
+		};
+	};
+
+	fephy {
+		/omit-if-no-ref/
+		fephym0_pins: fephym0-pins {
+			rockchip,pins =
+				/* fephy_ledlink_m0 */
+				<3 RK_PB4 6 &pcfg_pull_none>,
+				/* fephy_ledspd_m0 */
+				<3 RK_PB5 6 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		fephym1_pins: fephym1-pins {
+			rockchip,pins =
+				/* fephy_ledlink_m1 */
+				<5 RK_PD4 1 &pcfg_pull_none>,
+				/* fephy_ledspd_m1 */
+				<5 RK_PD5 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		fephym2_pins: fephym2-pins {
+			rockchip,pins =
+				/* fephy_ledlink_m2 */
+				<6 RK_PC2 3 &pcfg_pull_none>,
+				/* fephy_ledspd_m2 */
+				<6 RK_PC3 3 &pcfg_pull_none>;
+		};
+	};
+
+	flash_trig {
+		/omit-if-no-ref/
+		flash_trig_pins: flash-trig-pins {
+			rockchip,pins =
+				/* flash_trig_out */
+				<3 RK_PB2 6 &pcfg_pull_none>;
+		};
+	};
+
+	fspi0 {
+		/omit-if-no-ref/
+		fspi0_bus4_pins: fspi0-bus4-pins {
+			rockchip,pins =
+				/* fspi0_d0 */
+				<1 RK_PB4 1 &pcfg_pull_none>,
+				/* fspi0_d1 */
+				<1 RK_PB5 1 &pcfg_pull_none>,
+				/* fspi0_d2 */
+				<1 RK_PB2 1 &pcfg_pull_none>,
+				/* fspi0_d3 */
+				<1 RK_PB6 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		fspi0_clk_pins: fspi0-clk-pins {
+			rockchip,pins =
+				/* fspi0_clk */
+				<1 RK_PB7 1 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		fspi0_csn0_pins: fspi0-csn0-pins {
+			rockchip,pins =
+				/* fspi0_csn0 */
+				<1 RK_PB0 1 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		fspi0_csn1_pins: fspi0-csn1-pins {
+			rockchip,pins =
+				/* fspi0_csn1 */
+				<1 RK_PA5 2 &pcfg_pull_none>;
+		};
+	};
+
+	fspi1 {
+		/omit-if-no-ref/
+		fspi1m0_bus4_pins: fspi1m0-bus4-pins {
+			rockchip,pins =
+				/* fspi1_d0_m0 */
+				<0 RK_PB0 1 &pcfg_pull_none>,
+				/* fspi1_d1_m0 */
+				<0 RK_PB1 1 &pcfg_pull_none>,
+				/* fspi1_d2_m0 */
+				<0 RK_PA6 1 &pcfg_pull_none>,
+				/* fspi1_d3_m0 */
+				<0 RK_PA1 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		fspi1m0_clk_pins: fspi1m0-clk-pins {
+			rockchip,pins =
+				/* fspi1m0_clk */
+				<0 RK_PB2 1 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		fspi1m0_csn0_pins: fspi1m0-csn0-pins {
+			rockchip,pins =
+				/* fspi1m0_csn0 */
+				<0 RK_PA7 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		fspi1m1_bus4_pins: fspi1m1-bus4-pins {
+			rockchip,pins =
+				/* fspi1_d0_m1 */
+				<1 RK_PA0 2 &pcfg_pull_none>,
+				/* fspi1_d1_m1 */
+				<1 RK_PA1 2 &pcfg_pull_none>,
+				/* fspi1_d2_m1 */
+				<1 RK_PA2 2 &pcfg_pull_none>,
+				/* fspi1_d3_m1 */
+				<1 RK_PA3 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		fspi1m1_clk_pins: fspi1m1-clk-pins {
+			rockchip,pins =
+				/* fspi1m1_clk */
+				<1 RK_PB3 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		fspi1m1_csn0_pins: fspi1m1-csn0-pins {
+			rockchip,pins =
+				/* fspi1m1_csn0 */
+				<1 RK_PB1 2 &pcfg_pull_none>;
+		};
+	};
+
+	i2c0 {
+		/omit-if-no-ref/
+		i2c0m0_pins: i2c0m0-pins {
+			rockchip,pins =
+				/* i2c0_scl_m0 */
+				<0 RK_PC2 4 &pcfg_pull_none_smt>,
+				/* i2c0_sda_m0 */
+				<0 RK_PC3 4 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c0m1_pins: i2c0m1-pins {
+			rockchip,pins =
+				/* i2c0_scl_m1 */
+				<2 RK_PA1 3 &pcfg_pull_none_smt>,
+				/* i2c0_sda_m1 */
+				<2 RK_PA0 3 &pcfg_pull_none_smt>;
+		};
+	};
+
+	i2c1 {
+		/omit-if-no-ref/
+		i2c1m0_pins: i2c1m0-pins {
+			rockchip,pins =
+				/* i2c1_scl_m0 */
+				<0 RK_PB3 3 &pcfg_pull_none_smt>,
+				/* i2c1_sda_m0 */
+				<0 RK_PB4 3 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c1m1_pins: i2c1m1-pins {
+			rockchip,pins =
+				/* i2c1_scl_m1 */
+				<3 RK_PA2 2 &pcfg_pull_none_smt>,
+				/* i2c1_sda_m1 */
+				<3 RK_PA3 2 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c1m2_pins: i2c1m2-pins {
+			rockchip,pins =
+				/* i2c1_scl_m2 */
+				<4 RK_PA1 6 &pcfg_pull_none_smt>,
+				/* i2c1_sda_m2 */
+				<4 RK_PA0 6 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c1m3_pins: i2c1m3-pins {
+			rockchip,pins =
+				/* i2c1_scl_m3 */
+				<7 RK_PB0 5 &pcfg_pull_none_smt>,
+				/* i2c1_sda_m3 */
+				<7 RK_PB1 5 &pcfg_pull_none_smt>;
+		};
+	};
+
+	i2c2 {
+		/omit-if-no-ref/
+		i2c2m0_pins: i2c2m0-pins {
+			rockchip,pins =
+				/* i2c2_scl_m0 */
+				<0 RK_PD0 1 &pcfg_pull_none_smt>,
+				/* i2c2_sda_m0 */
+				<0 RK_PD1 1 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c2m1_pins: i2c2m1-pins {
+			rockchip,pins =
+				/* i2c2_scl_m1 */
+				<5 RK_PD4 6 &pcfg_pull_none_smt>,
+				/* i2c2_sda_m1 */
+				<5 RK_PD5 6 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c2m2_pins: i2c2m2-pins {
+			rockchip,pins =
+				/* i2c2_scl_m2 */
+				<6 RK_PC0 7 &pcfg_pull_none_smt>,
+				/* i2c2_sda_m2 */
+				<6 RK_PC3 7 &pcfg_pull_none_smt>;
+		};
+	};
+
+	i2c3 {
+		/omit-if-no-ref/
+		i2c3m0_pins: i2c3m0-pins {
+			rockchip,pins =
+				/* i2c3_scl_m0 */
+				<0 RK_PC0 1 &pcfg_pull_none_smt>,
+				/* i2c3_sda_m0 */
+				<0 RK_PC1 1 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c3m1_pins: i2c3m1-pins {
+			rockchip,pins =
+				/* i2c3_scl_m1 */
+				<4 RK_PA4 6 &pcfg_pull_none_smt>,
+				/* i2c3_sda_m1 */
+				<4 RK_PA5 6 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c3m2_pins: i2c3m2-pins {
+			rockchip,pins =
+				/* i2c3_scl_m2 */
+				<5 RK_PD0 6 &pcfg_pull_none_smt>,
+				/* i2c3_sda_m2 */
+				<5 RK_PD1 6 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c3m3_pins: i2c3m3-pins {
+			rockchip,pins =
+				/* i2c3_scl_m3 */
+				<6 RK_PA0 7 &pcfg_pull_none_smt>,
+				/* i2c3_sda_m3 */
+				<6 RK_PA1 7 &pcfg_pull_none_smt>;
+		};
+	};
+
+	i2c4 {
+		/omit-if-no-ref/
+		i2c4m0_pins: i2c4m0-pins {
+			rockchip,pins =
+				/* i2c4_scl_m0 */
+				<3 RK_PB4 5 &pcfg_pull_none_smt>,
+				/* i2c4_sda_m0 */
+				<3 RK_PB5 5 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c4m1_pins: i2c4m1-pins {
+			rockchip,pins =
+				/* i2c4_scl_m1 */
+				<6 RK_PA2 7 &pcfg_pull_none_smt>,
+				/* i2c4_sda_m1 */
+				<6 RK_PA3 7 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c4m2_pins: i2c4m2-pins {
+			rockchip,pins =
+				/* i2c4_scl_m2 */
+				<4 RK_PA7 6 &pcfg_pull_none_smt>,
+				/* i2c4_sda_m2 */
+				<4 RK_PA6 6 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c4m3_pins: i2c4m3-pins {
+			rockchip,pins =
+				/* i2c4_scl_m3 */
+				<7 RK_PA1 2 &pcfg_pull_none_smt>,
+				/* i2c4_sda_m3 */
+				<7 RK_PA4 2 &pcfg_pull_none_smt>;
+		};
+	};
+
+	i2c5 {
+		/omit-if-no-ref/
+		i2c5m0_pins: i2c5m0-pins {
+			rockchip,pins =
+				/* i2c5_scl_m0 */
+				<0 RK_PC4 4 &pcfg_pull_none_smt>,
+				/* i2c5_sda_m0 */
+				<0 RK_PC5 4 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c5m1_pins: i2c5m1-pins {
+			rockchip,pins =
+				/* i2c5_scl_m1 */
+				<3 RK_PB6 5 &pcfg_pull_none_smt>,
+				/* i2c5_sda_m1 */
+				<3 RK_PB7 5 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c5m2_pins: i2c5m2-pins {
+			rockchip,pins =
+				/* i2c5_scl_m2 */
+				<5 RK_PA1 2 &pcfg_pull_none_smt>,
+				/* i2c5_sda_m2 */
+				<5 RK_PA7 6 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c5m3_pins: i2c5m3-pins {
+			rockchip,pins =
+				/* i2c5_scl_m3 */
+				<6 RK_PA4 7 &pcfg_pull_none_smt>,
+				/* i2c5_sda_m3 */
+				<6 RK_PA5 7 &pcfg_pull_none_smt>;
+		};
+	};
+
+	ir_fpa {
+		/omit-if-no-ref/
+		ir_fpa_pins: ir-fpa-pins {
+			rockchip,pins =
+				/* ir_fpa_fsync */
+				<5 RK_PD4 5 &pcfg_pull_none>,
+				/* ir_fpa_mclk */
+				<5 RK_PD5 5 &pcfg_pull_none>,
+				/* ir_fpa_sda0 */
+				<5 RK_PA0 6 &pcfg_pull_none>,
+				/* ir_fpa_sda1 */
+				<5 RK_PA1 6 &pcfg_pull_none>,
+				/* ir_fpa_sda2 */
+				<5 RK_PB0 6 &pcfg_pull_none>,
+				/* ir_fpa_sda3 */
+				<5 RK_PB1 6 &pcfg_pull_none>,
+				/* ir_fpa_sda4 */
+				<5 RK_PC0 6 &pcfg_pull_none>,
+				/* ir_fpa_sda5 */
+				<5 RK_PC1 6 &pcfg_pull_none>,
+				/* ir_fpa_sda6 */
+				<5 RK_PC2 6 &pcfg_pull_none>;
+		};
+	};
+
+	jtag {
+		/omit-if-no-ref/
+		jtagm0_pins: jtagm0-pins {
+			rockchip,pins =
+				/* jtag_tck_m0 */
+				<0 RK_PB3 4 &pcfg_pull_none>,
+				/* jtag_tms_m0 */
+				<0 RK_PB4 4 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		jtagm1_pins: jtagm1-pins {
+			rockchip,pins =
+				/* jtag_tck_m1 */
+				<2 RK_PA2 4 &pcfg_pull_none>,
+				/* jtag_tms_m1 */
+				<2 RK_PA3 4 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		jtagm2_pins: jtagm2-pins {
+			rockchip,pins =
+				/* jtag_tck_m2 */
+				<5 RK_PD6 2 &pcfg_pull_none>,
+				/* jtag_tms_m2 */
+				<5 RK_PD7 2 &pcfg_pull_none>;
+		};
+	};
+
+	pdm {
+		/omit-if-no-ref/
+		pdmm0_clk0_pins: pdmm0-clk0-pins {
+			rockchip,pins =
+				/* pdm_clk0_m0 */
+				<7 RK_PA4 3 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm0_clk1_pins: pdmm0-clk1-pins {
+			rockchip,pins =
+				/* pdm_clk1_m0 */
+				<7 RK_PA1 3 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm0_sdi0_pins: pdmm0-sdi0-pins {
+			rockchip,pins =
+				/* pdm_sdi0_m0 */
+				<7 RK_PA6 3 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm0_sdi1_pins: pdmm0-sdi1-pins {
+			rockchip,pins =
+				/* pdm_sdi1_m0 */
+				<7 RK_PB1 3 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm0_sdi2_pins: pdmm0-sdi2-pins {
+			rockchip,pins =
+				/* pdm_sdi2_m0 */
+				<7 RK_PB0 3 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm0_sdi3_pins: pdmm0-sdi3-pins {
+			rockchip,pins =
+				/* pdm_sdi3_m0 */
+				<7 RK_PA7 3 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm1_clk0_pins: pdmm1-clk0-pins {
+			rockchip,pins =
+				/* pdm_clk0_m1 */
+				<6 RK_PB4 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm1_clk1_pins: pdmm1-clk1-pins {
+			rockchip,pins =
+				/* pdm_clk1_m1 */
+				<6 RK_PB7 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm1_sdi0_pins: pdmm1-sdi0-pins {
+			rockchip,pins =
+				/* pdm_sdi0_m1 */
+				<6 RK_PB5 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm1_sdi1_pins: pdmm1-sdi1-pins {
+			rockchip,pins =
+				/* pdm_sdi1_m1 */
+				<6 RK_PB6 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm1_sdi2_pins: pdmm1-sdi2-pins {
+			rockchip,pins =
+				/* pdm_sdi2_m1 */
+				<6 RK_PB2 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm1_sdi3_pins: pdmm1-sdi3-pins {
+			rockchip,pins =
+				/* pdm_sdi3_m1 */
+				<6 RK_PB3 5 &pcfg_pull_none>;
+		};
+	};
+
+	pmu {
+		/omit-if-no-ref/
+		pmu_pins: pmu-pins {
+			rockchip,pins =
+				/* pmu_dbg */
+				<0 RK_PA2 3 &pcfg_pull_none>;
+		};
+	};
+
+	prelight_trig {
+		/omit-if-no-ref/
+		prelight_trig_pins: prelight-trig-pins {
+			rockchip,pins =
+				/* prelight_trig_out */
+				<3 RK_PB3 6 &pcfg_pull_none>;
+		};
+	};
+
+	preroll {
+		/omit-if-no-ref/
+		preroll_pins: preroll-pins {
+			rockchip,pins =
+				/* preroll_dbg */
+				<0 RK_PB3 5 &pcfg_pull_none>;
+		};
+	};
+
+	pwm0 {
+		/omit-if-no-ref/
+		pwm0m0_ch0_pins: pwm0m0-ch0-pins {
+			rockchip,pins =
+				/* pwm0m0_ch0 */
+				<0 RK_PC4 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m0_ch1_pins: pwm0m0-ch1-pins {
+			rockchip,pins =
+				/* pwm0m0_ch1 */
+				<0 RK_PC5 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m0_ch2_pins: pwm0m0-ch2-pins {
+			rockchip,pins =
+				/* pwm0m0_ch2 */
+				<0 RK_PC6 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m0_ch3_pins: pwm0m0-ch3-pins {
+			rockchip,pins =
+				/* pwm0m0_ch3 */
+				<0 RK_PC7 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m0_ch4_pins: pwm0m0-ch4-pins {
+			rockchip,pins =
+				/* pwm0m0_ch4 */
+				<0 RK_PD0 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m0_ch5_pins: pwm0m0-ch5-pins {
+			rockchip,pins =
+				/* pwm0m0_ch5 */
+				<0 RK_PD1 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m0_ch6_pins: pwm0m0-ch6-pins {
+			rockchip,pins =
+				/* pwm0m0_ch6 */
+				<0 RK_PC1 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m0_ch7_pins: pwm0m0-ch7-pins {
+			rockchip,pins =
+				/* pwm0m0_ch7 */
+				<0 RK_PC0 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pwm0m1_ch0_pins: pwm0m1-ch0-pins {
+			rockchip,pins =
+				/* pwm0m1_ch0 */
+				<5 RK_PA7 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m1_ch1_pins: pwm0m1-ch1-pins {
+			rockchip,pins =
+				/* pwm0m1_ch1 */
+				<5 RK_PA6 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m1_ch2_pins: pwm0m1-ch2-pins {
+			rockchip,pins =
+				/* pwm0m1_ch2 */
+				<5 RK_PA5 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m1_ch3_pins: pwm0m1-ch3-pins {
+			rockchip,pins =
+				/* pwm0m1_ch3 */
+				<5 RK_PA4 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m1_ch4_pins: pwm0m1-ch4-pins {
+			rockchip,pins =
+				/* pwm0m1_ch4 */
+				<4 RK_PA2 4 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m1_ch5_pins: pwm0m1-ch5-pins {
+			rockchip,pins =
+				/* pwm0m1_ch5 */
+				<4 RK_PA3 4 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m1_ch6_pins: pwm0m1-ch6-pins {
+			rockchip,pins =
+				/* pwm0m1_ch6 */
+				<4 RK_PA6 4 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m1_ch7_pins: pwm0m1-ch7-pins {
+			rockchip,pins =
+				/* pwm0m1_ch7 */
+				<4 RK_PA7 4 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pwm0m2_ch0_pins: pwm0m2-ch0-pins {
+			rockchip,pins =
+				/* pwm0m2_ch0 */
+				<6 RK_PC0 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m2_ch1_pins: pwm0m2-ch1-pins {
+			rockchip,pins =
+				/* pwm0m2_ch1 */
+				<6 RK_PC1 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m2_ch2_pins: pwm0m2-ch2-pins {
+			rockchip,pins =
+				/* pwm0m2_ch2 */
+				<6 RK_PC2 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m2_ch3_pins: pwm0m2-ch3-pins {
+			rockchip,pins =
+				/* pwm0m2_ch3 */
+				<6 RK_PC3 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m2_ch4_pins: pwm0m2-ch4-pins {
+			rockchip,pins =
+				/* pwm0m2_ch4 */
+				<5 RK_PA3 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m2_ch5_pins: pwm0m2-ch5-pins {
+			rockchip,pins =
+				/* pwm0m2_ch5 */
+				<5 RK_PA2 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m2_ch6_pins: pwm0m2-ch6-pins {
+			rockchip,pins =
+				/* pwm0m2_ch6 */
+				<5 RK_PD0 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m2_ch7_pins: pwm0m2-ch7-pins {
+			rockchip,pins =
+				/* pwm0m2_ch7 */
+				<5 RK_PD4 7 &pcfg_pull_none>;
+		};
+	};
+
+	pwm1 {
+		/omit-if-no-ref/
+		pwm1m0_ch0_pins: pwm1m0-ch0-pins {
+			rockchip,pins =
+				/* pwm1m0_ch0 */
+				<0 RK_PA5 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm1m0_ch1_pins: pwm1m0-ch1-pins {
+			rockchip,pins =
+				/* pwm1m0_ch1 */
+				<0 RK_PA1 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm1m0_ch2_pins: pwm1m0-ch2-pins {
+			rockchip,pins =
+				/* pwm1m0_ch2 */
+				<0 RK_PB3 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm1m0_ch3_pins: pwm1m0-ch3-pins {
+			rockchip,pins =
+				/* pwm1m0_ch3 */
+				<0 RK_PB4 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pwm1m1_ch0_pins: pwm1m1-ch0-pins {
+			rockchip,pins =
+				/* pwm1m1_ch0 */
+				<5 RK_PD3 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm1m1_ch1_pins: pwm1m1-ch1-pins {
+			rockchip,pins =
+				/* pwm1m1_ch1 */
+				<5 RK_PD2 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm1m1_ch2_pins: pwm1m1-ch2-pins {
+			rockchip,pins =
+				/* pwm1m1_ch2 */
+				<5 RK_PD1 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm1m1_ch3_pins: pwm1m1-ch3-pins {
+			rockchip,pins =
+				/* pwm1m1_ch3 */
+				<5 RK_PD5 7 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pwm1m2_ch0_pins: pwm1m2-ch0-pins {
+			rockchip,pins =
+				/* pwm1m2_ch0 */
+				<6 RK_PA0 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm1m2_ch1_pins: pwm1m2-ch1-pins {
+			rockchip,pins =
+				/* pwm1m2_ch1 */
+				<6 RK_PA1 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm1m2_ch2_pins: pwm1m2-ch2-pins {
+			rockchip,pins =
+				/* pwm1m2_ch2 */
+				<6 RK_PA2 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm1m2_ch3_pins: pwm1m2-ch3-pins {
+			rockchip,pins =
+				/* pwm1m2_ch3 */
+				<6 RK_PA3 5 &pcfg_pull_none>;
+		};
+	};
+
+	pwm2 {
+		/omit-if-no-ref/
+		pwm2m0_ch0_pins: pwm2m0-ch0-pins {
+			rockchip,pins =
+				/* pwm2m0_ch0 */
+				<3 RK_PB2 3 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m0_ch1_pins: pwm2m0-ch1-pins {
+			rockchip,pins =
+				/* pwm2m0_ch1 */
+				<3 RK_PB3 3 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m0_ch2_pins: pwm2m0-ch2-pins {
+			rockchip,pins =
+				/* pwm2m0_ch2 */
+				<3 RK_PB4 3 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m0_ch3_pins: pwm2m0-ch3-pins {
+			rockchip,pins =
+				/* pwm2m0_ch3 */
+				<3 RK_PB5 3 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m0_ch4_pins: pwm2m0-ch4-pins {
+			rockchip,pins =
+				/* pwm2m0_ch4 */
+				<5 RK_PA0 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m0_ch5_pins: pwm2m0-ch5-pins {
+			rockchip,pins =
+				/* pwm2m0_ch5 */
+				<5 RK_PA1 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m0_ch6_pins: pwm2m0-ch6-pins {
+			rockchip,pins =
+				/* pwm2m0_ch6 */
+				<5 RK_PD6 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m0_ch7_pins: pwm2m0-ch7-pins {
+			rockchip,pins =
+				/* pwm2m0_ch7 */
+				<5 RK_PD7 7 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pwm2m1_ch0_pins: pwm2m1-ch0-pins {
+			rockchip,pins =
+				/* pwm2m1_ch0 */
+				<5 RK_PB2 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m1_ch1_pins: pwm2m1-ch1-pins {
+			rockchip,pins =
+				/* pwm2m1_ch1 */
+				<5 RK_PB3 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m1_ch2_pins: pwm2m1-ch2-pins {
+			rockchip,pins =
+				/* pwm2m1_ch2 */
+				<5 RK_PB6 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m1_ch3_pins: pwm2m1-ch3-pins {
+			rockchip,pins =
+				/* pwm2m1_ch3 */
+				<5 RK_PB7 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m1_ch4_pins: pwm2m1-ch4-pins {
+			rockchip,pins =
+				/* pwm2m1_ch4 */
+				<7 RK_PA0 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m1_ch5_pins: pwm2m1-ch5-pins {
+			rockchip,pins =
+				/* pwm2m1_ch5 */
+				<7 RK_PA1 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m1_ch6_pins: pwm2m1-ch6-pins {
+			rockchip,pins =
+				/* pwm2m1_ch6 */
+				<7 RK_PA2 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m1_ch7_pins: pwm2m1-ch7-pins {
+			rockchip,pins =
+				/* pwm2m1_ch7 */
+				<7 RK_PA3 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pwm2m2_ch0_pins: pwm2m2-ch0-pins {
+			rockchip,pins =
+				/* pwm2m2_ch0 */
+				<6 RK_PA4 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m2_ch1_pins: pwm2m2-ch1-pins {
+			rockchip,pins =
+				/* pwm2m2_ch1 */
+				<6 RK_PA5 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m2_ch2_pins: pwm2m2-ch2-pins {
+			rockchip,pins =
+				/* pwm2m2_ch2 */
+				<6 RK_PA6 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m2_ch3_pins: pwm2m2-ch3-pins {
+			rockchip,pins =
+				/* pwm2m2_ch3 */
+				<6 RK_PA7 3 &pcfg_pull_none>;
+		};
+	};
+
+	pwm3 {
+		/omit-if-no-ref/
+		pwm3m0_ch0_pins: pwm3m0-ch0-pins {
+			rockchip,pins =
+				/* pwm3m0_ch0 */
+				<1 RK_PA0 3 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m0_ch1_pins: pwm3m0-ch1-pins {
+			rockchip,pins =
+				/* pwm3m0_ch1 */
+				<1 RK_PA1 3 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m0_ch2_pins: pwm3m0-ch2-pins {
+			rockchip,pins =
+				/* pwm3m0_ch2 */
+				<1 RK_PA2 3 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m0_ch3_pins: pwm3m0-ch3-pins {
+			rockchip,pins =
+				/* pwm3m0_ch3 */
+				<1 RK_PA3 3 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m0_ch4_pins: pwm3m0-ch4-pins {
+			rockchip,pins =
+				/* pwm3m0_ch4 */
+				<1 RK_PA4 3 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m0_ch5_pins: pwm3m0-ch5-pins {
+			rockchip,pins =
+				/* pwm3m0_ch5 */
+				<1 RK_PA5 3 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m0_ch6_pins: pwm3m0-ch6-pins {
+			rockchip,pins =
+				/* pwm3m0_ch6 */
+				<1 RK_PA6 3 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m0_ch7_pins: pwm3m0-ch7-pins {
+			rockchip,pins =
+				/* pwm3m0_ch7 */
+				<1 RK_PA7 3 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pwm3m1_ch0_pins: pwm3m1-ch0-pins {
+			rockchip,pins =
+				/* pwm3m1_ch0 */
+				<5 RK_PC0 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m1_ch1_pins: pwm3m1-ch1-pins {
+			rockchip,pins =
+				/* pwm3m1_ch1 */
+				<5 RK_PC1 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m1_ch2_pins: pwm3m1-ch2-pins {
+			rockchip,pins =
+				/* pwm3m1_ch2 */
+				<5 RK_PC2 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m1_ch3_pins: pwm3m1-ch3-pins {
+			rockchip,pins =
+				/* pwm3m1_ch3 */
+				<5 RK_PC3 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m1_ch4_pins: pwm3m1-ch4-pins {
+			rockchip,pins =
+				/* pwm3m1_ch4 */
+				<5 RK_PC4 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m1_ch5_pins: pwm3m1-ch5-pins {
+			rockchip,pins =
+				/* pwm3m1_ch5 */
+				<5 RK_PC5 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m1_ch6_pins: pwm3m1-ch6-pins {
+			rockchip,pins =
+				/* pwm3m1_ch6 */
+				<5 RK_PC6 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m1_ch7_pins: pwm3m1-ch7-pins {
+			rockchip,pins =
+				/* pwm3m1_ch7 */
+				<5 RK_PC7 7 &pcfg_pull_none>;
+		};
+	};
+
+	pwr {
+		/omit-if-no-ref/
+		pwr_pins: pwr-pins {
+			rockchip,pins =
+				/* pwr_ctrl0 */
+				<0 RK_PA3 1 &pcfg_pull_none>,
+				/* pwr_ctrl1 */
+				<0 RK_PA4 1 &pcfg_pull_none>,
+				/* pwr_ctrl2 */
+				<0 RK_PC1 3 &pcfg_pull_none>;
+		};
+	};
+
+	ref_clk0 {
+		/omit-if-no-ref/
+		ref_clk0_pins: ref-clk0-pins {
+			rockchip,pins =
+				/* ref_clk0_out */
+				<0 RK_PA0 1 &pcfg_pull_none>;
+		};
+	};
+
+	rtc_32k {
+		/omit-if-no-ref/
+		rtc_32k_pins: rtc-32k-pins {
+			rockchip,pins =
+				/* rtc_32k_out */
+				<0 RK_PA2 1 &pcfg_pull_none>;
+		};
+	};
+
+	sai0 {
+		/omit-if-no-ref/
+		sai0m0_lrck_pins: sai0m0-lrck-pins {
+			rockchip,pins =
+				/* sai0_lrck_m0 */
+				<7 RK_PA3 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m0_mclk_pins: sai0m0-mclk-pins {
+			rockchip,pins =
+				/* sai0_mclk_m0 */
+				<7 RK_PA2 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m0_sclk_pins: sai0m0-sclk-pins {
+			rockchip,pins =
+				/* sai0_sclk_m0 */
+				<7 RK_PA0 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m0_sdi0_pins: sai0m0-sdi0-pins {
+			rockchip,pins =
+				/* sai0_sdi0_m0 */
+				<7 RK_PA6 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m0_sdi1_pins: sai0m0-sdi1-pins {
+			rockchip,pins =
+				/* sai0_sdi1_m0 */
+				<7 RK_PB1 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m0_sdi2_pins: sai0m0-sdi2-pins {
+			rockchip,pins =
+				/* sai0_sdi2_m0 */
+				<7 RK_PB0 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m0_sdi3_pins: sai0m0-sdi3-pins {
+			rockchip,pins =
+				/* sai0_sdi3_m0 */
+				<7 RK_PA7 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m0_sdo0_pins: sai0m0-sdo0-pins {
+			rockchip,pins =
+				/* sai0_sdo0_m0 */
+				<7 RK_PA5 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m0_sdo1_pins: sai0m0-sdo1-pins {
+			rockchip,pins =
+				/* sai0_sdo1_m0 */
+				<7 RK_PA7 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m0_sdo2_pins: sai0m0-sdo2-pins {
+			rockchip,pins =
+				/* sai0_sdo2_m0 */
+				<7 RK_PB0 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m0_sdo3_pins: sai0m0-sdo3-pins {
+			rockchip,pins =
+				/* sai0_sdo3_m0 */
+				<7 RK_PB1 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m1_lrck_pins: sai0m1-lrck-pins {
+			rockchip,pins =
+				/* sai0_lrck_m1 */
+				<6 RK_PA1 4 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m1_mclk_pins: sai0m1-mclk-pins {
+			rockchip,pins =
+				/* sai0_mclk_m1 */
+				<6 RK_PA4 4 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m1_sclk_pins: sai0m1-sclk-pins {
+			rockchip,pins =
+				/* sai0_sclk_m1 */
+				<6 RK_PA0 4 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m1_sdi0_pins: sai0m1-sdi0-pins {
+			rockchip,pins =
+				/* sai0_sdi0_m1 */
+				<6 RK_PA3 4 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m1_sdi1_pins: sai0m1-sdi1-pins {
+			rockchip,pins =
+				/* sai0_sdi1_m1 */
+				<6 RK_PB1 4 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m1_sdi2_pins: sai0m1-sdi2-pins {
+			rockchip,pins =
+				/* sai0_sdi2_m1 */
+				<6 RK_PB0 4 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m1_sdi3_pins: sai0m1-sdi3-pins {
+			rockchip,pins =
+				/* sai0_sdi3_m1 */
+				<6 RK_PA7 4 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m1_sdo0_pins: sai0m1-sdo0-pins {
+			rockchip,pins =
+				/* sai0_sdo0_m1 */
+				<6 RK_PA2 4 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m1_sdo1_pins: sai0m1-sdo1-pins {
+			rockchip,pins =
+				/* sai0_sdo1_m1 */
+				<6 RK_PA7 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m1_sdo2_pins: sai0m1-sdo2-pins {
+			rockchip,pins =
+				/* sai0_sdo2_m1 */
+				<6 RK_PB0 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m1_sdo3_pins: sai0m1-sdo3-pins {
+			rockchip,pins =
+				/* sai0_sdo3_m1 */
+				<6 RK_PB1 5 &pcfg_pull_none>;
+		};
+	};
+
+	sai1 {
+		/omit-if-no-ref/
+		sai1m0_lrck_pins: sai1m0-lrck-pins {
+			rockchip,pins =
+				/* sai1_lrck_m0 */
+				<1 RK_PB4 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai1m0_mclk_pins: sai1m0-mclk-pins {
+			rockchip,pins =
+				/* sai1_mclk_m0 */
+				<1 RK_PB0 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai1m0_sclk_pins: sai1m0-sclk-pins {
+			rockchip,pins =
+				/* sai1_sclk_m0 */
+				<1 RK_PB5 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai1m0_sdi_pins: sai1m0-sdi-pins {
+			rockchip,pins =
+				/* sai1m0_sdi */
+				<1 RK_PB6 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		sai1m0_sdo_pins: sai1m0-sdo-pins {
+			rockchip,pins =
+				/* sai1m0_sdo */
+				<1 RK_PB2 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai1m1_lrck_pins: sai1m1-lrck-pins {
+			rockchip,pins =
+				/* sai1_lrck_m1 */
+				<4 RK_PA5 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai1m1_mclk_pins: sai1m1-mclk-pins {
+			rockchip,pins =
+				/* sai1_mclk_m1 */
+				<4 RK_PA3 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai1m1_sclk_pins: sai1m1-sclk-pins {
+			rockchip,pins =
+				/* sai1_sclk_m1 */
+				<4 RK_PA4 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai1m1_sdi_pins: sai1m1-sdi-pins {
+			rockchip,pins =
+				/* sai1m1_sdi */
+				<4 RK_PA6 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		sai1m1_sdo_pins: sai1m1-sdo-pins {
+			rockchip,pins =
+				/* sai1m1_sdo */
+				<4 RK_PA7 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai1m2_lrck_pins: sai1m2-lrck-pins {
+			rockchip,pins =
+				/* sai1_lrck_m2 */
+				<5 RK_PC6 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai1m2_mclk_pins: sai1m2-mclk-pins {
+			rockchip,pins =
+				/* sai1_mclk_m2 */
+				<5 RK_PC3 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai1m2_sclk_pins: sai1m2-sclk-pins {
+			rockchip,pins =
+				/* sai1_sclk_m2 */
+				<5 RK_PC5 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai1m2_sdi_pins: sai1m2-sdi-pins {
+			rockchip,pins =
+				/* sai1m2_sdi */
+				<5 RK_PC7 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		sai1m2_sdo_pins: sai1m2-sdo-pins {
+			rockchip,pins =
+				/* sai1m2_sdo */
+				<5 RK_PC4 5 &pcfg_pull_none>;
+		};
+	};
+
+	sai2 {
+		/omit-if-no-ref/
+		sai2m0_lrck_pins: sai2m0-lrck-pins {
+			rockchip,pins =
+				/* sai2_lrck_m0 */
+				<3 RK_PB5 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai2m0_mclk_pins: sai2m0-mclk-pins {
+			rockchip,pins =
+				/* sai2_mclk_m0 */
+				<3 RK_PB6 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai2m0_sclk_pins: sai2m0-sclk-pins {
+			rockchip,pins =
+				/* sai2_sclk_m0 */
+				<3 RK_PB4 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai2m0_sdi0_pins: sai2m0-sdi0-pins {
+			rockchip,pins =
+				/* sai2_sdi0_m0 */
+				<3 RK_PB3 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai2m0_sdi1_pins: sai2m0-sdi1-pins {
+			rockchip,pins =
+				/* sai2_sdi1_m0 */
+				<3 RK_PB7 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai2m0_sdi2_pins: sai2m0-sdi2-pins {
+			rockchip,pins =
+				/* sai2_sdi2_m0 */
+				<3 RK_PB1 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai2m0_sdo_pins: sai2m0-sdo-pins {
+			rockchip,pins =
+				/* sai2m0_sdo */
+				<3 RK_PB2 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai2m1_lrck_pins: sai2m1-lrck-pins {
+			rockchip,pins =
+				/* sai2_lrck_m1 */
+				<5 RK_PA7 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai2m1_mclk_pins: sai2m1-mclk-pins {
+			rockchip,pins =
+				/* sai2_mclk_m1 */
+				<5 RK_PA3 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai2m1_sclk_pins: sai2m1-sclk-pins {
+			rockchip,pins =
+				/* sai2_sclk_m1 */
+				<5 RK_PA5 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai2m1_sdi0_pins: sai2m1-sdi0-pins {
+			rockchip,pins =
+				/* sai2_sdi0_m1 */
+				<5 RK_PA6 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai2m1_sdi1_pins: sai2m1-sdi1-pins {
+			rockchip,pins =
+				/* sai2_sdi1_m1 */
+				<5 RK_PA2 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai2m1_sdi2_pins: sai2m1-sdi2-pins {
+			rockchip,pins =
+				/* sai2_sdi2_m1 */
+				<5 RK_PA1 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai2m1_sdo_pins: sai2m1-sdo-pins {
+			rockchip,pins =
+				/* sai2m1_sdo */
+				<5 RK_PA4 5 &pcfg_pull_none>;
+		};
+	};
+
+	sdmmc0 {
+		/omit-if-no-ref/
+		sdmmc0_bus4_pins: sdmmc0-bus4-pins {
+			rockchip,pins =
+				/* sdmmc0_d0 */
+				<2 RK_PA0 1 &pcfg_pull_up_drv_level_2_75>,
+				/* sdmmc0_d1 */
+				<2 RK_PA1 1 &pcfg_pull_up_drv_level_2_75>,
+				/* sdmmc0_d2 */
+				<2 RK_PA2 1 &pcfg_pull_up_drv_level_2_75>,
+				/* sdmmc0_d3 */
+				<2 RK_PA3 1 &pcfg_pull_up_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		sdmmc0_cmd_pins: sdmmc0-cmd-pins {
+			rockchip,pins =
+				/* sdmmc0_cmd */
+				<2 RK_PA5 1 &pcfg_pull_up_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		sdmmc0_clk_pins: sdmmc0-clk-pins {
+			rockchip,pins =
+				/* sdmmc0_clk */
+				<2 RK_PA4 1 &pcfg_pull_up_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		sdmmc0_detn_pins: sdmmc0-detn-pins {
+			rockchip,pins =
+				/* sdmmc0_detn */
+				<0 RK_PA5 1 &pcfg_pull_up>;
+		};
+	};
+
+	sdmmc1 {
+		/omit-if-no-ref/
+		sdmmc1_bus4_pins: sdmmc1-bus4-pins {
+			rockchip,pins =
+				/* sdmmc1_d0 */
+				<3 RK_PA2 1 &pcfg_pull_up>,
+				/* sdmmc1_d1 */
+				<3 RK_PA3 1 &pcfg_pull_up>,
+				/* sdmmc1_d2 */
+				<3 RK_PA4 1 &pcfg_pull_up>,
+				/* sdmmc1_d3 */
+				<3 RK_PA5 1 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		sdmmc1_cmd_pins: sdmmc1-cmd-pins {
+			rockchip,pins =
+				/* sdmmc1_cmd */
+				<3 RK_PA1 1 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		sdmmc1_clk_pins: sdmmc1-clk-pins {
+			rockchip,pins =
+				/* sdmmc1_clk */
+				<3 RK_PA0 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sdmmc1_detn_pins: sdmmc1-detn-pins {
+			rockchip,pins =
+				/* sdmmc1_detn */
+				<3 RK_PB6 3 &pcfg_pull_up>;
+		};
+	};
+
+	spi0 {
+		/omit-if-no-ref/
+		spi0m0_clk_pins: spi0m0-clk-pins {
+			rockchip,pins =
+				/* spi0_clk_m0 */
+				<0 RK_PB2 2 &pcfg_pull_none_drv_level_2_75>,
+				/* spi0_miso_m0 */
+				<0 RK_PB1 2 &pcfg_pull_none_drv_level_2_75>,
+				/* spi0_mosi_m0 */
+				<0 RK_PB0 2 &pcfg_pull_none_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		spi0m0_csn0_pins: spi0m0-csn0-pins {
+			rockchip,pins =
+				/* spi0m0_csn0 */
+				<0 RK_PA7 2 &pcfg_pull_none_drv_level_2_75>;
+		};
+		/omit-if-no-ref/
+		spi0m0_csn1_pins: spi0m0-csn1-pins {
+			rockchip,pins =
+				/* spi0m0_csn1 */
+				<0 RK_PA6 2 &pcfg_pull_none_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		spi0m1_clk_pins: spi0m1-clk-pins {
+			rockchip,pins =
+				/* spi0_clk_m1 */
+				<4 RK_PA7 1 &pcfg_pull_none_drv_level_2_75>,
+				/* spi0_miso_m1 */
+				<4 RK_PA5 1 &pcfg_pull_none_drv_level_2_75>,
+				/* spi0_mosi_m1 */
+				<4 RK_PA4 1 &pcfg_pull_none_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		spi0m1_csn0_pins: spi0m1-csn0-pins {
+			rockchip,pins =
+				/* spi0m1_csn0 */
+				<4 RK_PA6 1 &pcfg_pull_none_drv_level_2_75>;
+		};
+		/omit-if-no-ref/
+		spi0m1_csn1_pins: spi0m1-csn1-pins {
+			rockchip,pins =
+				/* spi0m1_csn1 */
+				<4 RK_PA3 1 &pcfg_pull_none_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		spi0m2_clk_pins: spi0m2-clk-pins {
+			rockchip,pins =
+				/* spi0_clk_m2 */
+				<5 RK_PA6 2 &pcfg_pull_none_drv_level_2_75>,
+				/* spi0_miso_m2 */
+				<5 RK_PA5 2 &pcfg_pull_none_drv_level_2_75>,
+				/* spi0_mosi_m2 */
+				<5 RK_PA4 2 &pcfg_pull_none_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		spi0m2_csn0_pins: spi0m2-csn0-pins {
+			rockchip,pins =
+				/* spi0m2_csn0 */
+				<5 RK_PA3 2 &pcfg_pull_none_drv_level_2_75>;
+		};
+		/omit-if-no-ref/
+		spi0m2_csn1_pins: spi0m2-csn1-pins {
+			rockchip,pins =
+				/* spi0m2_csn1 */
+				<5 RK_PA7 2 &pcfg_pull_none_drv_level_2_75>;
+		};
+	};
+
+	spi1 {
+		/omit-if-no-ref/
+		spi1m0_clk_pins: spi1m0-clk-pins {
+			rockchip,pins =
+				/* spi1_clk_m0 */
+				<6 RK_PB4 3 &pcfg_pull_none_drv_level_2_75>,
+				/* spi1_miso_m0 */
+				<6 RK_PB3 3 &pcfg_pull_none_drv_level_2_75>,
+				/* spi1_mosi_m0 */
+				<6 RK_PB2 3 &pcfg_pull_none_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		spi1m0_csn0_pins: spi1m0-csn0-pins {
+			rockchip,pins =
+				/* spi1m0_csn0 */
+				<6 RK_PB1 3 &pcfg_pull_none_drv_level_2_75>;
+		};
+		/omit-if-no-ref/
+		spi1m0_csn1_pins: spi1m0-csn1-pins {
+			rockchip,pins =
+				/* spi1m0_csn1 */
+				<6 RK_PB0 3 &pcfg_pull_none_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		spi1m1_clk_pins: spi1m1-clk-pins {
+			rockchip,pins =
+				/* spi1_clk_m1 */
+				<3 RK_PB4 1 &pcfg_pull_none_drv_level_2_75>,
+				/* spi1_miso_m1 */
+				<3 RK_PB3 1 &pcfg_pull_none_drv_level_2_75>,
+				/* spi1_mosi_m1 */
+				<3 RK_PB2 1 &pcfg_pull_none_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		spi1m1_csn0_pins: spi1m1-csn0-pins {
+			rockchip,pins =
+				/* spi1m1_csn0 */
+				<3 RK_PB5 1 &pcfg_pull_none_drv_level_2_75>;
+		};
+		/omit-if-no-ref/
+		spi1m1_csn1_pins: spi1m1-csn1-pins {
+			rockchip,pins =
+				/* spi1m1_csn1 */
+				<3 RK_PB6 1 &pcfg_pull_none_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		spi1m2_clk_pins: spi1m2-clk-pins {
+			rockchip,pins =
+				/* spi1_clk_m2 */
+				<5 RK_PD1 2 &pcfg_pull_none_drv_level_2_75>,
+				/* spi1_miso_m2 */
+				<5 RK_PD3 2 &pcfg_pull_none_drv_level_2_75>,
+				/* spi1_mosi_m2 */
+				<5 RK_PD2 2 &pcfg_pull_none_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		spi1m2_csn0_pins: spi1m2-csn0-pins {
+			rockchip,pins =
+				/* spi1m2_csn0 */
+				<5 RK_PD0 2 &pcfg_pull_none_drv_level_2_75>;
+		};
+		/omit-if-no-ref/
+		spi1m2_csn1_pins: spi1m2-csn1-pins {
+			rockchip,pins =
+				/* spi1m2_csn1 */
+				<5 RK_PD4 2 &pcfg_pull_none_drv_level_2_75>;
+		};
+	};
+
+	spi2ahb {
+		/omit-if-no-ref/
+		spi2ahb_clk_pins: spi2ahb-clk-pins {
+			rockchip,pins =
+				/* spi2ahb_clk */
+				<0 RK_PC3 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		spi2ahb_csn0_pins: spi2ahb-csn0-pins {
+			rockchip,pins =
+				/* spi2ahb_csn0 */
+				<0 RK_PC2 1 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		spi2ahb_d0_pins: spi2ahb-d0-pins {
+			rockchip,pins =
+				/* spi2ahb_d0 */
+				<0 RK_PC7 1 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		spi2ahb_d1_pins: spi2ahb-d1-pins {
+			rockchip,pins =
+				/* spi2ahb_d1 */
+				<0 RK_PC6 1 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		spi2ahb_d2_pins: spi2ahb-d2-pins {
+			rockchip,pins =
+				/* spi2ahb_d2 */
+				<0 RK_PC5 1 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		spi2ahb_d3_pins: spi2ahb-d3-pins {
+			rockchip,pins =
+				/* spi2ahb_d3 */
+				<0 RK_PC4 1 &pcfg_pull_none>;
+		};
+	};
+
+	tsadc {
+		/omit-if-no-ref/
+		tsadc_pins: tsadc-pins {
+			rockchip,pins =
+				/* tsadc_shut */
+				<0 RK_PA1 3 &pcfg_pull_none>,
+				/* tsadc_shutorg */
+				<0 RK_PA1 4 &pcfg_pull_none>;
+		};
+	};
+
+	uart0 {
+		/omit-if-no-ref/
+		uart0m0_xfer_pins: uart0m0-xfer-pins {
+			rockchip,pins =
+				/* uart0_rx_m0 */
+				<2 RK_PA0 2 &pcfg_pull_up>,
+				/* uart0_tx_m0 */
+				<2 RK_PA1 2 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart0m1_xfer_pins: uart0m1-xfer-pins {
+			rockchip,pins =
+				/* uart0_rx_m1 */
+				<5 RK_PD7 1 &pcfg_pull_up>,
+				/* uart0_tx_m1 */
+				<5 RK_PD6 1 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart0m2_xfer_pins: uart0m2-xfer-pins {
+			rockchip,pins =
+				/* uart0_rx_m2 */
+				<0 RK_PB4 1 &pcfg_pull_up>,
+				/* uart0_tx_m2 */
+				<0 RK_PB3 1 &pcfg_pull_up>;
+		};
+	};
+
+	uart1 {
+		/omit-if-no-ref/
+		uart1m0_xfer_pins: uart1m0-xfer-pins {
+			rockchip,pins =
+				/* uart1_rx_m0 */
+				<0 RK_PC5 3 &pcfg_pull_up>,
+				/* uart1_tx_m0 */
+				<0 RK_PC4 3 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart1m0_ctsn_pins: uart1m0-ctsn-pins {
+			rockchip,pins =
+				/* uart1m0_ctsn */
+				<0 RK_PC7 3 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart1m0_rtsn_pins: uart1m0-rtsn-pins {
+			rockchip,pins =
+				/* uart1m0_rtsn */
+				<0 RK_PC6 3 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		uart1m1_xfer_pins: uart1m1-xfer-pins {
+			rockchip,pins =
+				/* uart1_rx_m1 */
+				<3 RK_PB7 4 &pcfg_pull_up>,
+				/* uart1_tx_m1 */
+				<3 RK_PB6 4 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart1m1_ctsn_pins: uart1m1-ctsn-pins {
+			rockchip,pins =
+				/* uart1m1_ctsn */
+				<3 RK_PB5 4 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart1m1_rtsn_pins: uart1m1-rtsn-pins {
+			rockchip,pins =
+				/* uart1m1_rtsn */
+				<3 RK_PB4 4 &pcfg_pull_none>;
+		};
+	};
+
+	uart2 {
+		/omit-if-no-ref/
+		uart2m0_xfer_pins: uart2m0-xfer-pins {
+			rockchip,pins =
+				/* uart2_rx_m0 */
+				<3 RK_PB0 4 &pcfg_pull_up>,
+				/* uart2_tx_m0 */
+				<3 RK_PB1 4 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart2m0_ctsn_pins: uart2m0-ctsn-pins {
+			rockchip,pins =
+				/* uart2m0_ctsn */
+				<3 RK_PA7 4 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart2m0_rtsn_pins: uart2m0-rtsn-pins {
+			rockchip,pins =
+				/* uart2m0_rtsn */
+				<3 RK_PA6 4 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		uart2m1_xfer_pins: uart2m1-xfer-pins {
+			rockchip,pins =
+				/* uart2_rx_m1 */
+				<7 RK_PB0 6 &pcfg_pull_up>,
+				/* uart2_tx_m1 */
+				<7 RK_PB1 6 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart2m1_ctsn_pins: uart2m1-ctsn-pins {
+			rockchip,pins =
+				/* uart2m1_ctsn */
+				<7 RK_PA4 6 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart2m1_rtsn_pins: uart2m1-rtsn-pins {
+			rockchip,pins =
+				/* uart2m1_rtsn */
+				<7 RK_PA7 6 &pcfg_pull_none>;
+		};
+	};
+
+	uart3 {
+		/omit-if-no-ref/
+		uart3m0_xfer_pins: uart3m0-xfer-pins {
+			rockchip,pins =
+				/* uart3_rx_m0 */
+				<2 RK_PA2 2 &pcfg_pull_up>,
+				/* uart3_tx_m0 */
+				<2 RK_PA3 2 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart3m0_ctsn_pins: uart3m0-ctsn-pins {
+			rockchip,pins =
+				/* uart3m0_ctsn */
+				<2 RK_PA5 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart3m0_rtsn_pins: uart3m0-rtsn-pins {
+			rockchip,pins =
+				/* uart3m0_rtsn */
+				<2 RK_PA4 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		uart3m1_xfer_pins: uart3m1-xfer-pins {
+			rockchip,pins =
+				/* uart3_rx_m1 */
+				<5 RK_PD5 8 &pcfg_pull_up>,
+				/* uart3_tx_m1 */
+				<5 RK_PD4 8 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart3m1_ctsn_pins: uart3m1-ctsn-pins {
+			rockchip,pins =
+				/* uart3m1_ctsn */
+				<5 RK_PD3 8 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart3m1_rtsn_pins: uart3m1-rtsn-pins {
+			rockchip,pins =
+				/* uart3m1_rtsn */
+				<5 RK_PD2 8 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		uart3m2_xfer_pins: uart3m2-xfer-pins {
+			rockchip,pins =
+				/* uart3_rx_m2 */
+				<6 RK_PC3 6 &pcfg_pull_up>,
+				/* uart3_tx_m2 */
+				<6 RK_PC2 6 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart3m2_ctsn_pins: uart3m2-ctsn-pins {
+			rockchip,pins =
+				/* uart3m2_ctsn */
+				<6 RK_PC1 6 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart3m2_rtsn_pins: uart3m2-rtsn-pins {
+			rockchip,pins =
+				/* uart3m2_rtsn */
+				<6 RK_PC0 6 &pcfg_pull_none>;
+		};
+	};
+
+	uart4 {
+		/omit-if-no-ref/
+		uart4m0_xfer_pins: uart4m0-xfer-pins {
+			rockchip,pins =
+				/* uart4_rx_m0 */
+				<4 RK_PA2 5 &pcfg_pull_up>,
+				/* uart4_tx_m0 */
+				<4 RK_PA3 5 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart4m0_ctsn_pins: uart4m0-ctsn-pins {
+			rockchip,pins =
+				/* uart4m0_ctsn */
+				<4 RK_PA1 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart4m0_rtsn_pins: uart4m0-rtsn-pins {
+			rockchip,pins =
+				/* uart4m0_rtsn */
+				<4 RK_PA0 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		uart4m1_xfer_pins: uart4m1-xfer-pins {
+			rockchip,pins =
+				/* uart4_rx_m1 */
+				<5 RK_PA3 8 &pcfg_pull_up>,
+				/* uart4_tx_m1 */
+				<5 RK_PA2 8 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart4m1_ctsn_pins: uart4m1-ctsn-pins {
+			rockchip,pins =
+				/* uart4m1_ctsn */
+				<5 RK_PA1 8 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart4m1_rtsn_pins: uart4m1-rtsn-pins {
+			rockchip,pins =
+				/* uart4m1_rtsn */
+				<5 RK_PA0 8 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		uart4m2_xfer_pins: uart4m2-xfer-pins {
+			rockchip,pins =
+				/* uart4_rx_m2 */
+				<6 RK_PA1 6 &pcfg_pull_up>,
+				/* uart4_tx_m2 */
+				<6 RK_PA0 6 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart4m2_ctsn_pins: uart4m2-ctsn-pins {
+			rockchip,pins =
+				/* uart4m2_ctsn */
+				<6 RK_PA7 6 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart4m2_rtsn_pins: uart4m2-rtsn-pins {
+			rockchip,pins =
+				/* uart4m2_rtsn */
+				<6 RK_PA6 6 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		uart4m3_xfer_pins: uart4m3-xfer-pins {
+			rockchip,pins =
+				/* uart4_rx_m3 */
+				<2 RK_PA4 3 &pcfg_pull_up>,
+				/* uart4_tx_m3 */
+				<2 RK_PA5 3 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart4m3_ctsn_pins: uart4m3-ctsn-pins {
+			rockchip,pins =
+				/* uart4m3_ctsn */
+				<2 RK_PA3 3 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart4m3_rtsn_pins: uart4m3-rtsn-pins {
+			rockchip,pins =
+				/* uart4m3_rtsn */
+				<2 RK_PA2 3 &pcfg_pull_none>;
+		};
+	};
+
+	uart5 {
+		/omit-if-no-ref/
+		uart5m0_xfer_pins: uart5m0-xfer-pins {
+			rockchip,pins =
+				/* uart5_rx_m0 */
+				<4 RK_PA7 5 &pcfg_pull_up>,
+				/* uart5_tx_m0 */
+				<4 RK_PA6 5 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart5m0_ctsn_pins: uart5m0-ctsn-pins {
+			rockchip,pins =
+				/* uart5m0_ctsn */
+				<4 RK_PB1 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart5m0_rtsn_pins: uart5m0-rtsn-pins {
+			rockchip,pins =
+				/* uart5m0_rtsn */
+				<4 RK_PB0 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		uart5m1_xfer_pins: uart5m1-xfer-pins {
+			rockchip,pins =
+				/* uart5_rx_m1 */
+				<5 RK_PA5 8 &pcfg_pull_up>,
+				/* uart5_tx_m1 */
+				<5 RK_PA4 8 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart5m1_ctsn_pins: uart5m1-ctsn-pins {
+			rockchip,pins =
+				/* uart5m1_ctsn */
+				<5 RK_PA7 8 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart5m1_rtsn_pins: uart5m1-rtsn-pins {
+			rockchip,pins =
+				/* uart5m1_rtsn */
+				<5 RK_PA6 8 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		uart5m2_xfer_pins: uart5m2-xfer-pins {
+			rockchip,pins =
+				/* uart5_rx_m2 */
+				<6 RK_PA3 6 &pcfg_pull_up>,
+				/* uart5_tx_m2 */
+				<6 RK_PA2 6 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart5m2_ctsn_pins: uart5m2-ctsn-pins {
+			rockchip,pins =
+				/* uart5m2_ctsn */
+				<6 RK_PA5 6 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart5m2_rtsn_pins: uart5m2-rtsn-pins {
+			rockchip,pins =
+				/* uart5m2_rtsn */
+				<6 RK_PA4 6 &pcfg_pull_none>;
+		};
+	};
+
+	uart6 {
+		/omit-if-no-ref/
+		uart6m0_xfer_pins: uart6m0-xfer-pins {
+			rockchip,pins =
+				/* uart6_rx_m0 */
+				<5 RK_PB1 8 &pcfg_pull_up>,
+				/* uart6_tx_m0 */
+				<5 RK_PB0 8 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart6m0_ctsn_pins: uart6m0-ctsn-pins {
+			rockchip,pins =
+				/* uart6m0_ctsn */
+				<5 RK_PB3 8 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart6m0_rtsn_pins: uart6m0-rtsn-pins {
+			rockchip,pins =
+				/* uart6m0_rtsn */
+				<5 RK_PB2 8 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		uart6m1_xfer_pins: uart6m1-xfer-pins {
+			rockchip,pins =
+				/* uart6_rx_m1 */
+				<6 RK_PB1 6 &pcfg_pull_up>,
+				/* uart6_tx_m1 */
+				<6 RK_PB0 6 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart6m1_ctsn_pins: uart6m1-ctsn-pins {
+			rockchip,pins =
+				/* uart6m1_ctsn */
+				<6 RK_PB3 6 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart6m1_rtsn_pins: uart6m1-rtsn-pins {
+			rockchip,pins =
+				/* uart6m1_rtsn */
+				<6 RK_PB2 6 &pcfg_pull_none>;
+		};
+	};
+
+	uart7 {
+		/omit-if-no-ref/
+		uart7m0_xfer_pins: uart7m0-xfer-pins {
+			rockchip,pins =
+				/* uart7_rx_m0 */
+				<5 RK_PB5 8 &pcfg_pull_up>,
+				/* uart7_tx_m0 */
+				<5 RK_PB4 8 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart7m0_ctsn_pins: uart7m0-ctsn-pins {
+			rockchip,pins =
+				/* uart7m0_ctsn */
+				<5 RK_PB7 8 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart7m0_rtsn_pins: uart7m0-rtsn-pins {
+			rockchip,pins =
+				/* uart7m0_rtsn */
+				<5 RK_PB6 8 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		uart7m1_xfer_pins: uart7m1-xfer-pins {
+			rockchip,pins =
+				/* uart7_rx_m1 */
+				<6 RK_PB5 6 &pcfg_pull_up>,
+				/* uart7_tx_m1 */
+				<6 RK_PB4 6 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart7m1_ctsn_pins: uart7m1-ctsn-pins {
+			rockchip,pins =
+				/* uart7m1_ctsn */
+				<6 RK_PB7 6 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart7m1_rtsn_pins: uart7m1-rtsn-pins {
+			rockchip,pins =
+				/* uart7m1_rtsn */
+				<6 RK_PB6 6 &pcfg_pull_none>;
+		};
+	};
+
+	vi_cif {
+		/omit-if-no-ref/
+		vi_cifm0_pins: vi-cifm0-pins {
+			rockchip,pins =
+				/* vi_cif_clkin_m0 */
+				<6 RK_PC1 1 &pcfg_pull_none>,
+				/* vi_cif_clkout_m0 */
+				<6 RK_PC2 1 &pcfg_pull_none>,
+				/* vi_cif_d0_m0 */
+				<6 RK_PA0 1 &pcfg_pull_none>,
+				/* vi_cif_d10_m0 */
+				<6 RK_PB2 1 &pcfg_pull_none>,
+				/* vi_cif_d11_m0 */
+				<6 RK_PB3 1 &pcfg_pull_none>,
+				/* vi_cif_d12_m0 */
+				<6 RK_PB4 1 &pcfg_pull_none>,
+				/* vi_cif_d13_m0 */
+				<6 RK_PB5 1 &pcfg_pull_none>,
+				/* vi_cif_d14_m0 */
+				<6 RK_PB6 1 &pcfg_pull_none>,
+				/* vi_cif_d15_m0 */
+				<6 RK_PB7 1 &pcfg_pull_none>,
+				/* vi_cif_d1_m0 */
+				<6 RK_PA1 1 &pcfg_pull_none>,
+				/* vi_cif_d2_m0 */
+				<6 RK_PA2 1 &pcfg_pull_none>,
+				/* vi_cif_d3_m0 */
+				<6 RK_PA3 1 &pcfg_pull_none>,
+				/* vi_cif_d4_m0 */
+				<6 RK_PA4 1 &pcfg_pull_none>,
+				/* vi_cif_d5_m0 */
+				<6 RK_PA5 1 &pcfg_pull_none>,
+				/* vi_cif_d6_m0 */
+				<6 RK_PA6 1 &pcfg_pull_none>,
+				/* vi_cif_d7_m0 */
+				<6 RK_PA7 1 &pcfg_pull_none>,
+				/* vi_cif_d8_m0 */
+				<6 RK_PB0 1 &pcfg_pull_none>,
+				/* vi_cif_d9_m0 */
+				<6 RK_PB1 1 &pcfg_pull_none>,
+				/* vi_cif_hsync_m0 */
+				<6 RK_PC3 1 &pcfg_pull_none>,
+				/* vi_cif_vsync_m0 */
+				<6 RK_PC0 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		vi_cifm1_pins: vi-cifm1-pins {
+			rockchip,pins =
+				/* vi_cif_clkin_m1 */
+				<5 RK_PC6 3 &pcfg_pull_none>,
+				/* vi_cif_clkout_m1 */
+				<5 RK_PC5 3 &pcfg_pull_none>,
+				/* vi_cif_d0_m1 */
+				<5 RK_PA0 3 &pcfg_pull_none>,
+				/* vi_cif_d10_m1 */
+				<5 RK_PB6 3 &pcfg_pull_none>,
+				/* vi_cif_d11_m1 */
+				<5 RK_PB7 3 &pcfg_pull_none>,
+				/* vi_cif_d12_m1 */
+				<5 RK_PC0 3 &pcfg_pull_none>,
+				/* vi_cif_d13_m1 */
+				<5 RK_PC1 3 &pcfg_pull_none>,
+				/* vi_cif_d14_m1 */
+				<5 RK_PC2 3 &pcfg_pull_none>,
+				/* vi_cif_d15_m1 */
+				<5 RK_PC3 3 &pcfg_pull_none>,
+				/* vi_cif_d1_m1 */
+				<5 RK_PA1 3 &pcfg_pull_none>,
+				/* vi_cif_d2_m1 */
+				<5 RK_PA2 3 &pcfg_pull_none>,
+				/* vi_cif_d3_m1 */
+				<5 RK_PA7 3 &pcfg_pull_none>,
+				/* vi_cif_d4_m1 */
+				<5 RK_PB0 3 &pcfg_pull_none>,
+				/* vi_cif_d5_m1 */
+				<5 RK_PB1 3 &pcfg_pull_none>,
+				/* vi_cif_d6_m1 */
+				<5 RK_PB2 3 &pcfg_pull_none>,
+				/* vi_cif_d7_m1 */
+				<5 RK_PB3 3 &pcfg_pull_none>,
+				/* vi_cif_d8_m1 */
+				<5 RK_PB4 3 &pcfg_pull_none>,
+				/* vi_cif_d9_m1 */
+				<5 RK_PB5 3 &pcfg_pull_none>,
+				/* vi_cif_hsync_m1 */
+				<5 RK_PC7 3 &pcfg_pull_none>,
+				/* vi_cif_vsync_m1 */
+				<5 RK_PC4 3 &pcfg_pull_none>;
+		};
+	};
+
+	vo_lcdc {
+		/omit-if-no-ref/
+		vo_lcdc_pins: vo-lcdc-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d0 */
+				<5 RK_PA0 1 &pcfg_pull_none>,
+				/* vo_lcdc_d1 */
+				<5 RK_PA1 1 &pcfg_pull_none>,
+				/* vo_lcdc_d2 */
+				<5 RK_PA2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d3 */
+				<5 RK_PA3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d4 */
+				<5 RK_PA4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d5 */
+				<5 RK_PA5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d6 */
+				<5 RK_PA6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d7 */
+				<5 RK_PA7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d8 */
+				<5 RK_PB0 1 &pcfg_pull_none>,
+				/* vo_lcdc_d9 */
+				<5 RK_PB1 1 &pcfg_pull_none>,
+				/* vo_lcdc_d10 */
+				<5 RK_PB2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d11 */
+				<5 RK_PB3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d12 */
+				<5 RK_PB4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d13 */
+				<5 RK_PB5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d14 */
+				<5 RK_PB6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d15 */
+				<5 RK_PB7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d16 */
+				<5 RK_PC0 1 &pcfg_pull_none>,
+				/* vo_lcdc_d17 */
+				<5 RK_PC1 1 &pcfg_pull_none>,
+				/* vo_lcdc_d18 */
+				<5 RK_PC2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d19 */
+				<5 RK_PC3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d20 */
+				<5 RK_PC4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d21 */
+				<5 RK_PC5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d22 */
+				<5 RK_PC6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d23 */
+				<5 RK_PC7 1 &pcfg_pull_none>,
+				/* vo_lcdc_den */
+				<5 RK_PD0 1 &pcfg_pull_none>,
+				/* vo_lcdc_hsync */
+				<5 RK_PD1 1 &pcfg_pull_none>,
+				/* vo_lcdc_vsync */
+				<5 RK_PD2 1 &pcfg_pull_none>;
+		};
+	};
+};
+
+/*
+ * This part is edited handly.
+ */
+&pinctrl {
+	dsmc {
+		/omit-if-no-ref/
+		dsmc_csn_idle: dsmc-csn-idle {
+			rockchip,pins =
+				/* dsmc_csn0 */
+				<5 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>,
+				/* dsmc_csn1 */
+				<5 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>,
+				/* dsmc_csn2 */
+				<5 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>,
+				/* dsmc_csn3 */
+				<5 RK_PD0 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	pdm {
+		/omit-if-no-ref/
+		pdmm0_clk0_idle: pdmm0-clk0-idle {
+			rockchip,pins =
+				/* pdm_clk0_m0 */
+				<7 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm0_clk1_idle: pdmm0-clk1-idle {
+			rockchip,pins =
+				/* pdm_clk1_m0 */
+				<7 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm1_clk0_idle: pdmm1-clk0-idle {
+			rockchip,pins =
+				/* pdm_clk0_m1 */
+				<6 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm1_clk1_idle: pdmm1-clk1-idle {
+			rockchip,pins =
+				/* pdm_clk1_m1 */
+				<6 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	sdmmc0 {
+		/omit-if-no-ref/
+		sdmmc0_idle_pins: sdmmc0-idle-pins {
+			rockchip,pins =
+				<2 RK_PA0 RK_FUNC_GPIO &pcfg_pull_down>,
+				<2 RK_PA1 RK_FUNC_GPIO &pcfg_pull_down>,
+				<2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_down>,
+				<2 RK_PA3 RK_FUNC_GPIO &pcfg_pull_down>,
+				<2 RK_PA4 RK_FUNC_GPIO &pcfg_pull_down>,
+				<2 RK_PA5 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+	};
+
+	sdmmc1 {
+		/omit-if-no-ref/
+		sdmmc1_idle_pins: sdmmc1-idle-pins {
+			rockchip,pins =
+				<3 RK_PA0 RK_FUNC_GPIO &pcfg_pull_down>,
+				<3 RK_PA1 RK_FUNC_GPIO &pcfg_pull_down>,
+				<3 RK_PA2 RK_FUNC_GPIO &pcfg_pull_down>,
+				<3 RK_PA3 RK_FUNC_GPIO &pcfg_pull_down>,
+				<3 RK_PA4 RK_FUNC_GPIO &pcfg_pull_down>,
+				<3 RK_PA5 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+	};
+
+	vo_lcdc {
+		/omit-if-no-ref/
+		bt1120_pins: bt1120-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none_drv_level_4_75>,
+				/* vo_lcdc_d3 */
+				<5 RK_PA3 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d4 */
+				<5 RK_PA4 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d5 */
+				<5 RK_PA5 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d6 */
+				<5 RK_PA6 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d7 */
+				<5 RK_PA7 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d10 */
+				<5 RK_PB2 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d11 */
+				<5 RK_PB3 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d12 */
+				<5 RK_PB4 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d13 */
+				<5 RK_PB5 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d14 */
+				<5 RK_PB6 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d15 */
+				<5 RK_PB7 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d19 */
+				<5 RK_PC3 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d20 */
+				<5 RK_PC4 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d21 */
+				<5 RK_PC5 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d22 */
+				<5 RK_PC6 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d23 */
+				<5 RK_PC7 1 &pcfg_pull_none_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		bt656_m0_pins: bt656-m0-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none_drv_level_4_75>,
+				/* vo_lcdc_d3 */
+				<5 RK_PA3 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d4 */
+				<5 RK_PA4 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d5 */
+				<5 RK_PA5 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d6 */
+				<5 RK_PA6 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d7 */
+				<5 RK_PA7 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d10 */
+				<5 RK_PB2 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d11 */
+				<5 RK_PB3 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d12 */
+				<5 RK_PB4 1 &pcfg_pull_none_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		bt656_m1_pins: bt656-m1-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none_drv_level_4_75>,
+				/* vo_lcdc_d13 */
+				<5 RK_PB5 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d14 */
+				<5 RK_PB6 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d15 */
+				<5 RK_PB7 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d19 */
+				<5 RK_PC3 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d20 */
+				<5 RK_PC4 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d21 */
+				<5 RK_PC5 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d22 */
+				<5 RK_PC6 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d23 */
+				<5 RK_PC7 1 &pcfg_pull_none_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		mcu_rgb3x8_rgb2x8_m0_pins: mcu-rgb3x8-rgb2x8-m0-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d3 */
+				<5 RK_PA3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d4 */
+				<5 RK_PA4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d5 */
+				<5 RK_PA5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d6 */
+				<5 RK_PA6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d7 */
+				<5 RK_PA7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d10 */
+				<5 RK_PB2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d11 */
+				<5 RK_PB3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d12 */
+				<5 RK_PB4 1 &pcfg_pull_none>,
+				/* vo_lcdc_den */
+				<5 RK_PD0 1 &pcfg_pull_none>,
+				/* vo_lcdc_hsync */
+				<5 RK_PD1 1 &pcfg_pull_none>,
+				/* vo_lcdc_vsync */
+				<5 RK_PD2 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		mcu_rgb3x8_rgb2x8_m1_pins: mcu-rgb3x8-rgb2x8-m1-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d13 */
+				<5 RK_PB5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d14 */
+				<5 RK_PB6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d15 */
+				<5 RK_PB7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d19 */
+				<5 RK_PC3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d20 */
+				<5 RK_PC4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d21 */
+				<5 RK_PC5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d22 */
+				<5 RK_PC6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d23 */
+				<5 RK_PC7 1 &pcfg_pull_none>,
+				/* vo_lcdc_den */
+				<5 RK_PD0 1 &pcfg_pull_none>,
+				/* vo_lcdc_hsync */
+				<5 RK_PD1 1 &pcfg_pull_none>,
+				/* vo_lcdc_vsync */
+				<5 RK_PD2 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		mcu_rgb565_pins: mcu-rgb565-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d3 */
+				<5 RK_PA3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d4 */
+				<5 RK_PA4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d5 */
+				<5 RK_PA5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d6 */
+				<5 RK_PA6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d7 */
+				<5 RK_PA7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d10 */
+				<5 RK_PB2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d11 */
+				<5 RK_PB3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d12 */
+				<5 RK_PB4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d13 */
+				<5 RK_PB5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d14 */
+				<5 RK_PB6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d15 */
+				<5 RK_PB7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d19 */
+				<5 RK_PC3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d20 */
+				<5 RK_PC4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d21 */
+				<5 RK_PC5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d22 */
+				<5 RK_PC6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d23 */
+				<5 RK_PC7 1 &pcfg_pull_none>,
+				/* vo_lcdc_den */
+				<5 RK_PD0 1 &pcfg_pull_none>,
+				/* vo_lcdc_hsync */
+				<5 RK_PD1 1 &pcfg_pull_none>,
+				/* vo_lcdc_vsync */
+				<5 RK_PD2 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		mcu_rgb666_pins: mcu-rgb666-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d2 */
+				<5 RK_PA2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d3 */
+				<5 RK_PA3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d4 */
+				<5 RK_PA4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d5 */
+				<5 RK_PA5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d6 */
+				<5 RK_PA6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d7 */
+				<5 RK_PA7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d10 */
+				<5 RK_PB2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d11 */
+				<5 RK_PB3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d12 */
+				<5 RK_PB4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d13 */
+				<5 RK_PB5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d14 */
+				<5 RK_PB6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d15 */
+				<5 RK_PB7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d18 */
+				<5 RK_PC2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d19 */
+				<5 RK_PC3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d20 */
+				<5 RK_PC4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d21 */
+				<5 RK_PC5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d22 */
+				<5 RK_PC6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d23 */
+				<5 RK_PC7 1 &pcfg_pull_none>,
+				/* vo_lcdc_den */
+				<5 RK_PD0 1 &pcfg_pull_none>,
+				/* vo_lcdc_hsync */
+				<5 RK_PD1 1 &pcfg_pull_none>,
+				/* vo_lcdc_vsync */
+				<5 RK_PD2 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		mcu_rgb888_pins: mcu-rgb888-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d0 */
+				<5 RK_PA0 1 &pcfg_pull_none>,
+				/* vo_lcdc_d1 */
+				<5 RK_PA1 1 &pcfg_pull_none>,
+				/* vo_lcdc_d2 */
+				<5 RK_PA2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d3 */
+				<5 RK_PA3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d4 */
+				<5 RK_PA4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d5 */
+				<5 RK_PA5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d6 */
+				<5 RK_PA6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d7 */
+				<5 RK_PA7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d8 */
+				<5 RK_PB0 1 &pcfg_pull_none>,
+				/* vo_lcdc_d9 */
+				<5 RK_PB1 1 &pcfg_pull_none>,
+				/* vo_lcdc_d10 */
+				<5 RK_PB2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d11 */
+				<5 RK_PB3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d12 */
+				<5 RK_PB4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d13 */
+				<5 RK_PB5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d14 */
+				<5 RK_PB6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d15 */
+				<5 RK_PB7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d16 */
+				<5 RK_PC0 1 &pcfg_pull_none>,
+				/* vo_lcdc_d17 */
+				<5 RK_PC1 1 &pcfg_pull_none>,
+				/* vo_lcdc_d18 */
+				<5 RK_PC2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d19 */
+				<5 RK_PC3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d20 */
+				<5 RK_PC4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d21 */
+				<5 RK_PC5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d22 */
+				<5 RK_PC6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d23 */
+				<5 RK_PC7 1 &pcfg_pull_none>,
+				/* vo_lcdc_den */
+				<5 RK_PD0 1 &pcfg_pull_none>,
+				/* vo_lcdc_hsync */
+				<5 RK_PD1 1 &pcfg_pull_none>,
+				/* vo_lcdc_vsync */
+				<5 RK_PD2 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		rgb3x8_rgb2x8_m0_pins: rgb3x8-rgb2x8-m0-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d3 */
+				<5 RK_PA3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d4 */
+				<5 RK_PA4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d5 */
+				<5 RK_PA5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d6 */
+				<5 RK_PA6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d7 */
+				<5 RK_PA7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d10 */
+				<5 RK_PB2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d11 */
+				<5 RK_PB3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d12 */
+				<5 RK_PB4 1 &pcfg_pull_none>,
+				/* vo_lcdc_den */
+				<5 RK_PD0 1 &pcfg_pull_none>,
+				/* vo_lcdc_hsync */
+				<5 RK_PD1 1 &pcfg_pull_none>,
+				/* vo_lcdc_vsync */
+				<5 RK_PD2 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		rgb3x8_rgb2x8_m1_pins: rgb3x8-rgb2x8-m1-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d13 */
+				<5 RK_PB5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d14 */
+				<5 RK_PB6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d15 */
+				<5 RK_PB7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d19 */
+				<5 RK_PC3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d20 */
+				<5 RK_PC4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d21 */
+				<5 RK_PC5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d22 */
+				<5 RK_PC6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d23 */
+				<5 RK_PC7 1 &pcfg_pull_none>,
+				/* vo_lcdc_den */
+				<5 RK_PD0 1 &pcfg_pull_none>,
+				/* vo_lcdc_hsync */
+				<5 RK_PD1 1 &pcfg_pull_none>,
+				/* vo_lcdc_vsync */
+				<5 RK_PD2 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		rgb565_pins: rgb565-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d3 */
+				<5 RK_PA3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d4 */
+				<5 RK_PA4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d5 */
+				<5 RK_PA5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d6 */
+				<5 RK_PA6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d7 */
+				<5 RK_PA7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d10 */
+				<5 RK_PB2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d11 */
+				<5 RK_PB3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d12 */
+				<5 RK_PB4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d13 */
+				<5 RK_PB5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d14 */
+				<5 RK_PB6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d15 */
+				<5 RK_PB7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d19 */
+				<5 RK_PC3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d20 */
+				<5 RK_PC4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d21 */
+				<5 RK_PC5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d22 */
+				<5 RK_PC6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d23 */
+				<5 RK_PC7 1 &pcfg_pull_none>,
+				/* vo_lcdc_den */
+				<5 RK_PD0 1 &pcfg_pull_none>,
+				/* vo_lcdc_hsync */
+				<5 RK_PD1 1 &pcfg_pull_none>,
+				/* vo_lcdc_vsync */
+				<5 RK_PD2 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		rgb666_pins: rgb666-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d2 */
+				<5 RK_PA2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d3 */
+				<5 RK_PA3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d4 */
+				<5 RK_PA4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d5 */
+				<5 RK_PA5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d6 */
+				<5 RK_PA6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d7 */
+				<5 RK_PA7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d10 */
+				<5 RK_PB2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d11 */
+				<5 RK_PB3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d12 */
+				<5 RK_PB4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d13 */
+				<5 RK_PB5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d14 */
+				<5 RK_PB6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d15 */
+				<5 RK_PB7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d18 */
+				<5 RK_PC2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d19 */
+				<5 RK_PC3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d20 */
+				<5 RK_PC4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d21 */
+				<5 RK_PC5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d22 */
+				<5 RK_PC6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d23 */
+				<5 RK_PC7 1 &pcfg_pull_none>,
+				/* vo_lcdc_den */
+				<5 RK_PD0 1 &pcfg_pull_none>,
+				/* vo_lcdc_hsync */
+				<5 RK_PD1 1 &pcfg_pull_none>,
+				/* vo_lcdc_vsync */
+				<5 RK_PD2 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		rgb888_pins: rgb888-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d0 */
+				<5 RK_PA0 1 &pcfg_pull_none>,
+				/* vo_lcdc_d1 */
+				<5 RK_PA1 1 &pcfg_pull_none>,
+				/* vo_lcdc_d2 */
+				<5 RK_PA2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d3 */
+				<5 RK_PA3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d4 */
+				<5 RK_PA4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d5 */
+				<5 RK_PA5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d6 */
+				<5 RK_PA6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d7 */
+				<5 RK_PA7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d8 */
+				<5 RK_PB0 1 &pcfg_pull_none>,
+				/* vo_lcdc_d9 */
+				<5 RK_PB1 1 &pcfg_pull_none>,
+				/* vo_lcdc_d10 */
+				<5 RK_PB2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d11 */
+				<5 RK_PB3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d12 */
+				<5 RK_PB4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d13 */
+				<5 RK_PB5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d14 */
+				<5 RK_PB6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d15 */
+				<5 RK_PB7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d16 */
+				<5 RK_PC0 1 &pcfg_pull_none>,
+				/* vo_lcdc_d17 */
+				<5 RK_PC1 1 &pcfg_pull_none>,
+				/* vo_lcdc_d18 */
+				<5 RK_PC2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d19 */
+				<5 RK_PC3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d20 */
+				<5 RK_PC4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d21 */
+				<5 RK_PC5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d22 */
+				<5 RK_PC6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d23 */
+				<5 RK_PC7 1 &pcfg_pull_none>,
+				/* vo_lcdc_den */
+				<5 RK_PD0 1 &pcfg_pull_none>,
+				/* vo_lcdc_hsync */
+				<5 RK_PD1 1 &pcfg_pull_none>,
+				/* vo_lcdc_vsync */
+				<5 RK_PD2 1 &pcfg_pull_none>;
+		};
+	};
+};
-- 
2.34.1



From ye.zhang at rock-chips.com  Tue Dec 16 03:20:52 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Tue, 16 Dec 2025 19:20:52 +0800
Subject: [PATCH v3 6/7] dt-bindings: pinctrl: rockchip: Add RMIO controller binding
In-Reply-To: <20251216112053.1927852-1-ye.zhang@rock-chips.com>
References: <20251216112053.1927852-1-ye.zhang@rock-chips.com>
Message-ID: <20251216112053.1927852-7-ye.zhang@rock-chips.com>

1. Add header file with constants for RMIO function IDs for the Rockchip
RK3506 SoC.
2. Add device tree binding for the RMIO (Rockchip Matrix I/O) controller
which is a sub-device of the main pinctrl on some Rockchip SoCs.

Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
---
 .../bindings/pinctrl/rockchip,pinctrl.yaml    |   9 ++
 .../bindings/pinctrl/rockchip,rmio.yaml       | 106 +++++++++++++++++
 .../pinctrl/rockchip,rk3506-rmio.h            | 109 ++++++++++++++++++
 3 files changed, 224 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml
 create mode 100644 include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h

diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
index 97960245676d..9a27eaf7942b 100644
--- a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
@@ -82,6 +82,15 @@ required:
   - rockchip,grf
 
 patternProperties:
+  "rmio[0-9]*$":
+    type: object
+
+    $ref: "/schemas/pinctrl/rockchip,rmio.yaml#"
+
+    description:
+      The RMIO (Rockchip Matrix I/O) controller node which functions as a
+      sub-device of the main pinctrl to handle flexible function routing.
+
   "gpio@[0-9a-f]+$":
     type: object
 
diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml b/Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml
new file mode 100644
index 000000000000..af0b34512fb9
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml
@@ -0,0 +1,106 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/rockchip,rmio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: RMIO (Rockchip Matrix I/O) Controller
+
+maintainers:
+  - Heiko Stuebner <heiko at sntech.de>
+
+description: |
+  The RMIO controller provides a flexible routing matrix that allows mapping
+  various internal peripheral functions (UART, SPI, PWM, etc.) to specific
+  physical pins. This block is typically a sub-block of the GRF
+  (General Register Files) or PMU (Power Management Unit).
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - rockchip,rk3506-rmio
+      - const: rockchip,rmio
+
+  rockchip,rmio-grf:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      The phandle of the syscon node (GRF or PMU) containing the RMIO registers.
+      This property is required if the RMIO registers are located in a different
+      syscon than the parent pinctrl node.
+
+  rockchip,offset:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      The offset of the RMIO configuration registers within the GRF.
+
+  rockchip,pins-num:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      The number of physical pins supported by this RMIO instance.
+      Used for boundary checking and driver initialization.
+
+patternProperties:
+  "^[a-z0-9-]+$":
+    type: object
+    description:
+      Function node grouping multiple groups.
+
+    patternProperties:
+      "^[a-z0-9-]+$":
+        type: object
+        description:
+          Group node containing the pinmux configuration.
+
+        properties:
+          rockchip,rmio:
+            $ref: /schemas/types.yaml#/definitions/uint32-matrix
+            description:
+              A list of pin-function pairs. The format is <pin_id function_id>.
+            minItems: 1
+            items:
+              items:
+                - description: RMIO Pin ID (0 to pins-num - 1)
+                  minimum: 0
+                  maximum: 31
+                - description: Function ID
+                  minimum: 0
+                  maximum: 98
+
+        required:
+          - rockchip,rmio
+
+        additionalProperties: false
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - rockchip,rmio-grf
+  - rockchip,offset
+  - rockchip,pins-num
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/pinctrl/rockchip,rk3506-rmio.h>
+
+    pinctrl: pinctrl {
+        rmio: rmio {
+            compatible = "rockchip,rk3506-rmio", "rockchip,rmio";
+            rockchip,rmio-grf = <&grf_pmu>;
+            rockchip,offset = <0x80>;
+            rockchip,pins-num = <32>;
+
+            rmio-uart {
+                rmio_pin27_uart1_tx: rmio-pin27-uart1-tx {
+                    rockchip,rmio = <27 RMIO_UART1_TX>;
+                };
+
+                rmio_pin28_uart1_rx: rmio-pin28-uart1-rx {
+                    rockchip,rmio = <28 RMIO_UART1_RX>;
+                };
+            };
+        };
+    };
diff --git a/include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h b/include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h
new file mode 100644
index 000000000000..b129e9a8c287
--- /dev/null
+++ b/include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/*
+ * Copyright (c) 2025 Rockchip Electronics Co., Ltd.
+ */
+
+#ifndef __DT_BINDINGS_PINCTRL_ROCKCHIP_RK3506_RMIO_H
+#define __DT_BINDINGS_PINCTRL_ROCKCHIP_RK3506_RMIO_H
+
+/* RMIO function definition */
+#define RMIO_UART1_TX			1
+#define RMIO_UART1_RX			2
+#define RMIO_UART2_TX			3
+#define RMIO_UART2_RX			4
+#define RMIO_UART3_TX			5
+#define RMIO_UART3_RX			6
+#define RMIO_UART3_CTSN			7
+#define RMIO_UART3_RTSN			8
+#define RMIO_UART4_TX			9
+#define RMIO_UART4_RX			10
+#define RMIO_UART4_CTSN			11
+#define RMIO_UART4_RTSN			12
+#define RMIO_MIPITE			13
+#define RMIO_CLK_32K			14
+#define RMIO_I2C0_SCL			15
+#define RMIO_I2C0_SDA			16
+#define RMIO_I2C1_SCL			17
+#define RMIO_I2C1_SDA			18
+#define RMIO_I2C2_SCL			19
+#define RMIO_I2C2_SDA			20
+#define RMIO_PDM_CLK0			21
+#define RMIO_PDM_SDI0			22
+#define RMIO_PDM_SDI1			23
+#define RMIO_PDM_SDI2			24
+#define RMIO_PDM_SDI3			25
+#define RMIO_CAN1_TX			26
+#define RMIO_CAN1_RX			27
+#define RMIO_CAN0_TX			28
+#define RMIO_CAN0_RX			29
+#define RMIO_PWM0_CH0			30
+#define RMIO_PWM0_CH1			31
+#define RMIO_PWM0_CH2			32
+#define RMIO_PWM0_CH3			33
+#define RMIO_PWM1_CH0			34
+#define RMIO_PWM1_CH1			35
+#define RMIO_PWM1_CH2			36
+#define RMIO_PWM1_CH3			37
+#define RMIO_PWM1_CH4			38
+#define RMIO_PWM1_CH5			39
+#define RMIO_PWM1_CH6			40
+#define RMIO_PWM1_CH7			41
+#define RMIO_TOUCH_KEY_DRIVE		42
+#define RMIO_TOUCH_KEY_IN0		43
+#define RMIO_TOUCH_KEY_IN1		44
+#define RMIO_TOUCH_KEY_IN2		45
+#define RMIO_TOUCH_KEY_IN3		46
+#define RMIO_TOUCH_KEY_IN4		47
+#define RMIO_TOUCH_KEY_IN5		48
+#define RMIO_TOUCH_KEY_IN6		49
+#define RMIO_TOUCH_KEY_IN7		50
+#define RMIO_SAI0_MCLK			51
+#define RMIO_SAI0_SCLK			52
+#define RMIO_SAI0_LRCK			53
+#define RMIO_SAI0_SDI0			54
+#define RMIO_SAI0_SDI1			55
+#define RMIO_SAI0_SDI2			56
+#define RMIO_SAI0_SDI3			57
+#define RMIO_SAI0_SDO			58
+#define RMIO_SAI1_MCLK			59
+#define RMIO_SAI1_SCLK			60
+#define RMIO_SAI1_LRCK			61
+#define RMIO_SAI1_SDI			62
+#define RMIO_SAI1_SDO0			63
+#define RMIO_SAI1_SDO1			64
+#define RMIO_SAI1_SDO2			65
+#define RMIO_SAI1_SDO3			66
+#define RMIO_SPI0_CLK			67
+#define RMIO_SPI0_MOSI			68
+#define RMIO_SPI0_MISO			69
+#define RMIO_SPI0_CSN0			70
+#define RMIO_SPI0_CSN1			71
+#define RMIO_SPI1_CLK			72
+#define RMIO_SPI1_MOSI			73
+#define RMIO_SPI1_MISO			74
+#define RMIO_SPI1_CSN0			75
+#define RMIO_SPI1_CSN1			76
+#define RMIO_WDT_TSADC_SHUT		77
+#define RMIO_PMU_SLEEP			78
+#define RMIO_CORE_POWER_OFF		79
+#define RMIO_SPDIF_TX			80
+#define RMIO_SPDIF_RX			81
+#define RMIO_PWM1_BIP_CNTR_A0		82
+#define RMIO_PWM1_BIP_CNTR_A1		83
+#define RMIO_PWM1_BIP_CNTR_A2		84
+#define RMIO_PWM1_BIP_CNTR_A3		85
+#define RMIO_PWM1_BIP_CNTR_A4		86
+#define RMIO_PWM1_BIP_CNTR_A5		87
+#define RMIO_PWM1_BIP_CNTR_B0		88
+#define RMIO_PWM1_BIP_CNTR_B1		89
+#define RMIO_PWM1_BIP_CNTR_B2		90
+#define RMIO_PWM1_BIP_CNTR_B3		91
+#define RMIO_PWM1_BIP_CNTR_B4		92
+#define RMIO_PWM1_BIP_CNTR_B5		93
+#define RMIO_PDM_CLK1			94
+#define RMIO_ETH_RMII0_PPSCLK		95
+#define RMIO_ETH_RMII0_PPSTRIG		96
+#define RMIO_ETH_RMII1_PPSCLK		97
+#define RMIO_ETH_RMII1_PPSTRIG		98
+
+#endif /* __DT_BINDINGS_PINCTRL_ROCKCHIP_RK3506_RMIO_H */
-- 
2.34.1



From ye.zhang at rock-chips.com  Tue Dec 16 03:20:48 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Tue, 16 Dec 2025 19:20:48 +0800
Subject: [PATCH v3 2/7] dt-bindings: pinctrl: Add rv1126b pinctrl support
In-Reply-To: <20251216112053.1927852-1-ye.zhang@rock-chips.com>
References: <20251216112053.1927852-1-ye.zhang@rock-chips.com>
Message-ID: <20251216112053.1927852-3-ye.zhang@rock-chips.com>

The RV1126B is a new SoC that is the successor of the RV1126. It has
different pinctrl registers and is not compatible with the RV1126.
Therefore, add a new compatible string for it.

Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
---
 Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
index 125af766b992..97960245676d 100644
--- a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
@@ -51,6 +51,7 @@ properties:
       - rockchip,rk3588-pinctrl
       - rockchip,rv1108-pinctrl
       - rockchip,rv1126-pinctrl
+      - rockchip,rv1126b-pinctrl
 
   rockchip,grf:
     $ref: /schemas/types.yaml#/definitions/phandle
-- 
2.34.1



From ye.zhang at rock-chips.com  Tue Dec 16 03:20:49 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Tue, 16 Dec 2025 19:20:49 +0800
Subject: [PATCH v3 3/7] pinctrl: rockchip: Add rv1126b pinctrl support
In-Reply-To: <20251216112053.1927852-1-ye.zhang@rock-chips.com>
References: <20251216112053.1927852-1-ye.zhang@rock-chips.com>
Message-ID: <20251216112053.1927852-4-ye.zhang@rock-chips.com>

Add gpio and pinctrl support for the 8 GPIO banks on RV1126B.

Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
---
 drivers/pinctrl/pinctrl-rockchip.c | 181 ++++++++++++++++++++++++++++-
 drivers/pinctrl/pinctrl-rockchip.h |   1 +
 2 files changed, 181 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index e44ef262beec..dc7ef12dfcb0 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -307,6 +307,20 @@
 #define RK3588_PIN_BANK_FLAGS(ID, PIN, LABEL, M, P)			\
 	PIN_BANK_IOMUX_FLAGS_PULL_FLAGS(ID, PIN, LABEL, M, M, M, M, P, P, P, P)
 
+#define PIN_BANK_IOMUX_4_OFFSET_DRV_8(id, pins, label, offset0,		\
+				      offset1, offset2, offset3)	\
+	PIN_BANK_IOMUX_FLAGS_OFFSET_DRV_FLAGS(id, pins, label,		\
+					      IOMUX_WIDTH_4BIT,		\
+					      IOMUX_WIDTH_4BIT,		\
+					      IOMUX_WIDTH_4BIT,		\
+					      IOMUX_WIDTH_4BIT,		\
+					      offset0, offset1,		\
+					      offset2, offset3,		\
+					      DRV_TYPE_IO_LEVEL_8_BIT,	\
+					      DRV_TYPE_IO_LEVEL_8_BIT,	\
+					      DRV_TYPE_IO_LEVEL_8_BIT,	\
+					      DRV_TYPE_IO_LEVEL_8_BIT)
+
 static struct regmap_config rockchip_regmap_config = {
 	.reg_bits = 32,
 	.val_bits = 32,
@@ -1701,6 +1715,136 @@ static int rv1126_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank,
 	return 0;
 }
 
+#define RV1126B_DRV_BITS_PER_PIN		8
+#define RV1126B_DRV_PINS_PER_REG		2
+#define RV1126B_DRV_GPIO0_A_OFFSET		0x100
+#define RV1126B_DRV_GPIO0_C_OFFSET		0x8120
+#define RV1126B_DRV_GPIO_OFFSET(GPION)		(0x8100 + GPION * 0x8040)
+
+static int rv1126b_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
+				       int pin_num, struct regmap **regmap,
+				       int *reg, u8 *bit)
+{
+	struct rockchip_pinctrl *info = bank->drvdata;
+
+	*regmap = info->regmap_base;
+	switch (bank->bank_num) {
+	case 0:
+		if (pin_num < 16)
+			*reg = RV1126B_DRV_GPIO0_A_OFFSET;
+		else
+			*reg = RV1126B_DRV_GPIO0_C_OFFSET - 0x20;
+		break;
+
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+	case 6:
+	case 7:
+		*reg = RV1126B_DRV_GPIO_OFFSET(bank->bank_num);
+		break;
+
+	default:
+		dev_err(info->dev, "unsupported bank_num %d\n", bank->bank_num);
+		break;
+	}
+
+	*reg += ((pin_num / RV1126B_DRV_PINS_PER_REG) * 4);
+	*bit = pin_num % RV1126B_DRV_PINS_PER_REG;
+	*bit *= RV1126B_DRV_BITS_PER_PIN;
+
+	return 0;
+}
+
+#define RV1126B_PULL_BITS_PER_PIN		2
+#define RV1126B_PULL_PINS_PER_REG		8
+#define RV1126B_PULL_GPIO0_A_OFFSET		0x300
+#define RV1126B_PULL_GPIO0_C_OFFSET		0x8308
+#define RV1126B_PULL_GPIO_OFFSET(GPION)		(0x8300 + GPION * 0x8010)
+
+static int rv1126b_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
+					int pin_num, struct regmap **regmap,
+					int *reg, u8 *bit)
+{
+	struct rockchip_pinctrl *info = bank->drvdata;
+
+	*regmap = info->regmap_base;
+	switch (bank->bank_num) {
+	case 0:
+		if (pin_num < 16)
+			*reg = RV1126B_PULL_GPIO0_A_OFFSET;
+		else
+			*reg = RV1126B_PULL_GPIO0_C_OFFSET - 0x8;
+		break;
+
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+	case 6:
+	case 7:
+		*reg = RV1126B_PULL_GPIO_OFFSET(bank->bank_num);
+		break;
+
+	default:
+		dev_err(info->dev, "unsupported bank_num %d\n", bank->bank_num);
+		break;
+	}
+
+	*reg += ((pin_num / RV1126B_PULL_PINS_PER_REG) * 4);
+	*bit = pin_num % RV1126B_PULL_PINS_PER_REG;
+	*bit *= RV1126B_PULL_BITS_PER_PIN;
+
+	return 0;
+}
+
+#define RV1126B_SMT_BITS_PER_PIN		1
+#define RV1126B_SMT_PINS_PER_REG		8
+#define RV1126B_SMT_GPIO0_A_OFFSET		0x500
+#define RV1126B_SMT_GPIO0_C_OFFSET		0x8508
+#define RV1126B_SMT_GPIO_OFFSET(GPION)		(0x8500 + GPION * 0x8010)
+
+static int rv1126b_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank,
+					   int pin_num,
+					   struct regmap **regmap,
+					   int *reg, u8 *bit)
+{
+	struct rockchip_pinctrl *info = bank->drvdata;
+
+	*regmap = info->regmap_base;
+	switch (bank->bank_num) {
+	case 0:
+		if (pin_num < 16)
+			*reg = RV1126B_SMT_GPIO0_A_OFFSET;
+		else
+			*reg = RV1126B_SMT_GPIO0_C_OFFSET - 0x8;
+		break;
+
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+	case 6:
+	case 7:
+		*reg = RV1126B_SMT_GPIO_OFFSET(bank->bank_num);
+		break;
+
+	default:
+		dev_err(info->dev, "unsupported bank_num %d\n", bank->bank_num);
+		break;
+	}
+
+	*reg += ((pin_num / RV1126B_SMT_PINS_PER_REG) * 4);
+	*bit = pin_num % RV1126B_SMT_PINS_PER_REG;
+	*bit *= RV1126B_SMT_BITS_PER_PIN;
+
+	return 0;
+}
+
 #define RK3308_SCHMITT_PINS_PER_REG		8
 #define RK3308_SCHMITT_BANK_STRIDE		16
 #define RK3308_SCHMITT_GRF_OFFSET		0x1a0
@@ -3071,7 +3215,8 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank,
 		rmask_bits = RK3588_DRV_BITS_PER_PIN;
 		ret = strength;
 		goto config;
-	} else if (ctrl->type == RK3506 ||
+	} else if (ctrl->type == RV1126B ||
+		   ctrl->type == RK3506 ||
 		   ctrl->type == RK3528 ||
 		   ctrl->type == RK3562 ||
 		   ctrl->type == RK3568) {
@@ -3237,6 +3382,7 @@ static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num)
 				: PIN_CONFIG_BIAS_DISABLE;
 	case PX30:
 	case RV1108:
+	case RV1126B:
 	case RK3188:
 	case RK3288:
 	case RK3308:
@@ -3299,6 +3445,7 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank,
 	case PX30:
 	case RV1108:
 	case RV1126:
+	case RV1126B:
 	case RK3188:
 	case RK3288:
 	case RK3308:
@@ -3582,6 +3729,7 @@ static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl,
 	case PX30:
 	case RV1108:
 	case RV1126:
+	case RV1126B:
 	case RK3188:
 	case RK3288:
 	case RK3308:
@@ -4386,6 +4534,35 @@ static struct rockchip_pin_ctrl rv1126_pin_ctrl = {
 	.schmitt_calc_reg	= rv1126_calc_schmitt_reg_and_bit,
 };
 
+static struct rockchip_pin_bank rv1126b_pin_banks[] = {
+	PIN_BANK_IOMUX_4_OFFSET_DRV_8(0, 32, "gpio0",
+				      0x0, 0x8, 0x8010, 0x8018),
+	PIN_BANK_IOMUX_4_OFFSET_DRV_8(1, 32, "gpio1",
+				      0x10020, 0x10028, 0x10030, 0x10038),
+	PIN_BANK_IOMUX_4_OFFSET_DRV_8(2, 32, "gpio2",
+				      0x18040, 0x18048, 0x18050, 0x18058),
+	PIN_BANK_IOMUX_4_OFFSET_DRV_8(3, 32, "gpio3",
+				      0x20060, 0x20068, 0x20070, 0x20078),
+	PIN_BANK_IOMUX_4_OFFSET_DRV_8(4, 32, "gpio4",
+				      0x28080, 0x28088, 0x28090, 0x28098),
+	PIN_BANK_IOMUX_4_OFFSET_DRV_8(5, 32, "gpio5",
+				      0x300a0, 0x300a8, 0x300b0, 0x300b8),
+	PIN_BANK_IOMUX_4_OFFSET_DRV_8(6, 32, "gpio6",
+				      0x380c0, 0x380c8, 0x380d0, 0x380d8),
+	PIN_BANK_IOMUX_4_OFFSET_DRV_8(7, 32, "gpio7",
+				      0x400e0, 0x400e8, 0x400f0, 0x400f8),
+};
+
+static struct rockchip_pin_ctrl rv1126b_pin_ctrl __maybe_unused = {
+	.pin_banks		= rv1126b_pin_banks,
+	.nr_banks		= ARRAY_SIZE(rv1126b_pin_banks),
+	.label			= "RV1126B-GPIO",
+	.type			= RV1126B,
+	.pull_calc_reg		= rv1126b_calc_pull_reg_and_bit,
+	.drv_calc_reg		= rv1126b_calc_drv_reg_and_bit,
+	.schmitt_calc_reg	= rv1126b_calc_schmitt_reg_and_bit,
+};
+
 static struct rockchip_pin_bank rk2928_pin_banks[] = {
 	PIN_BANK(0, 32, "gpio0"),
 	PIN_BANK(1, 32, "gpio1"),
@@ -4960,6 +5137,8 @@ static const struct of_device_id rockchip_pinctrl_dt_match[] = {
 		.data = &rv1108_pin_ctrl },
 	{ .compatible = "rockchip,rv1126-pinctrl",
 		.data = &rv1126_pin_ctrl },
+	{ .compatible = "rockchip,rv1126b-pinctrl",
+		.data = &rv1126b_pin_ctrl },
 	{ .compatible = "rockchip,rk2928-pinctrl",
 		.data = &rk2928_pin_ctrl },
 	{ .compatible = "rockchip,rk3036-pinctrl",
diff --git a/drivers/pinctrl/pinctrl-rockchip.h b/drivers/pinctrl/pinctrl-rockchip.h
index 4f4aff42a80a..fe18b62ed994 100644
--- a/drivers/pinctrl/pinctrl-rockchip.h
+++ b/drivers/pinctrl/pinctrl-rockchip.h
@@ -187,6 +187,7 @@ enum rockchip_pinctrl_type {
 	PX30,
 	RV1108,
 	RV1126,
+	RV1126B,
 	RK2928,
 	RK3066B,
 	RK3128,
-- 
2.34.1



From ye.zhang at rock-chips.com  Tue Dec 16 03:20:53 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Tue, 16 Dec 2025 19:20:53 +0800
Subject: [PATCH v3 7/7] pinctrl: rockchip: add rmio support
In-Reply-To: <20251216112053.1927852-1-ye.zhang@rock-chips.com>
References: <20251216112053.1927852-1-ye.zhang@rock-chips.com>
Message-ID: <20251216112053.1927852-8-ye.zhang@rock-chips.com>

Support Rockchip Matrix IO(RMIO), which can be configured with registers
to route arbitrary signals from low-speed IP, such as UART/I2C, to the
selected IO PAD.

Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
---
 drivers/pinctrl/pinctrl-rockchip.c | 401 ++++++++++++++++++++++++++++-
 drivers/pinctrl/pinctrl-rockchip.h |  42 +++
 2 files changed, 442 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index dc7ef12dfcb0..cfd8117ab460 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -3961,6 +3961,11 @@ static const struct of_device_id rockchip_bank_match[] = {
 	{},
 };
 
+static const struct of_device_id rockchip_rmio_dt_match[] = {
+	{ .compatible = "rockchip,rmio" },
+	{},
+};
+
 static void rockchip_pinctrl_child_count(struct rockchip_pinctrl *info,
 						struct device_node *np)
 {
@@ -3969,6 +3974,8 @@ static void rockchip_pinctrl_child_count(struct rockchip_pinctrl *info,
 	for_each_child_of_node(np, child) {
 		if (of_match_node(rockchip_bank_match, child))
 			continue;
+		if (of_match_node(rockchip_rmio_dt_match, child))
+			continue;
 
 		info->nfunctions++;
 		info->ngroups += of_get_child_count(child);
@@ -4101,6 +4108,8 @@ static int rockchip_pinctrl_parse_dt(struct platform_device *pdev,
 	for_each_child_of_node_scoped(np, child) {
 		if (of_match_node(rockchip_bank_match, child))
 			continue;
+		if (of_match_node(rockchip_rmio_dt_match, child))
+			continue;
 
 		ret = rockchip_pinctrl_parse_functions(child, info, i++);
 		if (ret) {
@@ -4431,6 +4440,388 @@ static void rockchip_pinctrl_remove(struct platform_device *pdev)
 	}
 }
 
+static int rockchip_rmio_set_mux(struct rockchip_rmio *info, int id, int func)
+{
+	struct device *dev = info->dev;
+
+	if (id >= info->nr_pins)
+		return -EINVAL;
+
+	dev_dbg(dev, "setting function of %s%d to %d\n", dev_name(dev), id, func);
+
+	return regmap_write(info->regmap, info->offset + id * 4,
+			    RK_RMIO_WRITE_ENABLE_MASK | func);
+}
+
+static int rockchip_rmio_parse_groups(struct device_node *np,
+				      struct rockchip_rmio_group *grp,
+				      struct rockchip_rmio *info,
+				      u32 index)
+{
+	struct device *dev = info->dev;
+	int count;
+	u32 *tmp;
+	int i;
+
+	dev_dbg(dev, "group(%d): %pOFn\n", index, np);
+
+	/*
+	 * the binding format is rockchip,rmio = <pin func>,
+	 * do sanity check and calculate pins number
+	 */
+	count = of_property_count_u32_elems(np, "rockchip,rmio");
+	if (count <= 0 || count % 2 != 0)
+		return -EINVAL;
+
+	tmp = kcalloc(count, sizeof(u32), GFP_KERNEL);
+	if (!tmp)
+		return -ENOMEM;
+
+	of_property_read_u32_array(np, "rockchip,rmio", tmp, count);
+
+	/* Initialise group */
+	grp->name = np->name;
+	grp->npins = count / 2;
+	grp->pins = devm_kcalloc(dev, grp->npins, sizeof(*grp->pins), GFP_KERNEL);
+	grp->func = devm_kcalloc(dev, grp->npins, sizeof(*grp->func), GFP_KERNEL);
+	if (!grp->pins || !grp->func) {
+		kfree(tmp);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < grp->npins; i++) {
+		grp->pins[i] = tmp[2 * i];
+		grp->func[i] = tmp[2 * i + 1];
+	}
+	kfree(tmp);
+
+	return 0;
+}
+
+static int rockchip_rmio_parse_functions(struct device_node *np,
+					 struct rockchip_rmio *info,
+					 u32 index)
+{
+	struct device *dev = info->dev;
+	struct device_node *child;
+	struct rockchip_rmio_func *func;
+	struct rockchip_rmio_group *grp;
+	int ret;
+	u32 i, grp_index = 0;
+
+	dev_dbg(dev, "parse function(%d): %pOFn\n", index, np);
+
+	for (i = 0, func = info->functions; i < index; i++, func++)
+		grp_index += func->ngroups;
+
+	func = &info->functions[index];
+
+	/* Initialise function */
+	func->name = np->name;
+	func->ngroups = of_get_child_count(np);
+	if (func->ngroups <= 0)
+		return 0;
+
+	func->groups = devm_kcalloc(dev, func->ngroups, sizeof(*func->groups), GFP_KERNEL);
+	if (!func->groups)
+		return -ENOMEM;
+
+	i = 0;
+	for_each_child_of_node(np, child) {
+		func->groups[i] = child->name;
+		grp = &info->groups[grp_index + i];
+		ret = rockchip_rmio_parse_groups(child, grp, info, i++);
+		if (ret) {
+			of_node_put(child);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int rockchip_rmio_parse_dt(struct platform_device *pdev,
+				  struct rockchip_rmio *info)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct device_node *child;
+	int ret;
+	int i = 0;
+
+	for_each_child_of_node(np, child) {
+		info->nfunctions++;
+		info->ngroups += of_get_child_count(child);
+	}
+
+	dev_dbg(dev, "nfunctions = %d\n", info->nfunctions);
+	dev_dbg(dev, "ngroups = %d\n", info->ngroups);
+
+	info->functions = devm_kcalloc(dev, info->nfunctions, sizeof(*info->functions), GFP_KERNEL);
+	if (!info->functions)
+		return -ENOMEM;
+
+	info->groups = devm_kcalloc(dev, info->ngroups, sizeof(*info->groups), GFP_KERNEL);
+	if (!info->groups)
+		return -ENOMEM;
+
+	for_each_child_of_node(np, child) {
+		ret = rockchip_rmio_parse_functions(child, info, i++);
+		if (ret) {
+			dev_err(dev, "failed to parse function, ret = %d\n", ret);
+			of_node_put(child);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int rockchip_rmio_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	struct rockchip_rmio *info = pinctrl_dev_get_drvdata(pctldev);
+
+	return info->ngroups;
+}
+
+static const char *rockchip_rmio_get_group_name(struct pinctrl_dev *pctldev,
+						unsigned int selector)
+{
+	struct rockchip_rmio *info = pinctrl_dev_get_drvdata(pctldev);
+
+	return info->groups[selector].name;
+}
+
+static int rockchip_rmio_get_group_pins(struct pinctrl_dev *pctldev,
+					unsigned int selector,
+					const unsigned int **pins,
+					unsigned int *npins)
+{
+	struct rockchip_rmio *info = pinctrl_dev_get_drvdata(pctldev);
+
+	if (selector >= info->ngroups)
+		return -EINVAL;
+
+	*pins = info->groups[selector].pins;
+	*npins = info->groups[selector].npins;
+
+	return 0;
+}
+
+static int rockchip_rmio_dt_node_to_map(struct pinctrl_dev *pctldev,
+					struct device_node *np,
+					struct pinctrl_map **map,
+					unsigned int *num_maps)
+{
+	struct rockchip_rmio *info = pinctrl_dev_get_drvdata(pctldev);
+	struct device *dev = info->dev;
+	struct pinctrl_map *new_map;
+	struct device_node *parent;
+
+	parent = of_get_parent(np);
+	if (!parent)
+		return -EINVAL;
+
+	/* the rmio only need to create mux map */
+	new_map = kzalloc(sizeof(*new_map), GFP_KERNEL);
+	if (!new_map) {
+		of_node_put(parent);
+		return -ENOMEM;
+	}
+
+	*map = new_map;
+	*num_maps = 1;
+
+	/* the rmio only need to create mux map */
+	new_map->type = PIN_MAP_TYPE_MUX_GROUP;
+	new_map->data.mux.function = parent->name;
+	new_map->data.mux.group = np->name;
+	of_node_put(parent);
+
+	dev_dbg(dev, "maps: function %s group %s\n",
+		(*map)->data.mux.function, (*map)->data.mux.group);
+
+	return 0;
+}
+
+static void rockchip_rmio_dt_free_map(struct pinctrl_dev *pctldev,
+				      struct pinctrl_map *map,
+				      unsigned int num_maps)
+{
+	kfree(map);
+}
+
+static const struct pinctrl_ops rockchip_rmio_pctrl_ops = {
+	.get_groups_count	= rockchip_rmio_get_groups_count,
+	.get_group_name		= rockchip_rmio_get_group_name,
+	.get_group_pins		= rockchip_rmio_get_group_pins,
+	.dt_node_to_map		= rockchip_rmio_dt_node_to_map,
+	.dt_free_map		= rockchip_rmio_dt_free_map,
+};
+
+static int rockchip_rmio_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+	struct rockchip_rmio *info = pinctrl_dev_get_drvdata(pctldev);
+
+	return info->nfunctions;
+}
+
+static const char *rockchip_rmio_get_func_name(struct pinctrl_dev *pctldev,
+					       unsigned int selector)
+{
+	struct rockchip_rmio *info = pinctrl_dev_get_drvdata(pctldev);
+
+	return info->functions[selector].name;
+}
+
+static int rockchip_rmio_get_groups(struct pinctrl_dev *pctldev,
+				    unsigned int selector,
+				    const char * const **groups,
+				    unsigned int * const num_groups)
+{
+	struct rockchip_rmio *info = pinctrl_dev_get_drvdata(pctldev);
+
+	*groups = info->functions[selector].groups;
+	*num_groups = info->functions[selector].ngroups;
+
+	return 0;
+}
+
+static int rockchip_rmio_pmx_set(struct pinctrl_dev *pctldev,
+				 unsigned int selector,
+				 unsigned int group)
+{
+	struct rockchip_rmio *info = pinctrl_dev_get_drvdata(pctldev);
+	const unsigned int *pins = info->groups[group].pins;
+	const unsigned int *func = info->groups[group].func;
+	struct device *dev = info->dev;
+	int cnt, ret = 0;
+
+	dev_dbg(dev, "enable function %s group %s\n",
+		info->functions[selector].name, info->groups[group].name);
+
+	/*
+	 * for each pin in the pin group selected, program the corresponding
+	 * pin function number in the config register.
+	 */
+	for (cnt = 0; cnt < info->groups[group].npins; cnt++) {
+		ret = rockchip_rmio_set_mux(info, pins[cnt], func[cnt]);
+		if (ret)
+			break;
+	}
+
+	if (ret && cnt) {
+		/* revert the already done pin settings */
+		for (cnt--; cnt >= 0; cnt--)
+			rockchip_rmio_set_mux(info, pins[cnt], RK_RMIO_NC);
+
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct pinmux_ops rockchip_rmio_pmx_ops = {
+	.get_functions_count	= rockchip_rmio_get_funcs_count,
+	.get_function_name	= rockchip_rmio_get_func_name,
+	.get_function_groups	= rockchip_rmio_get_groups,
+	.set_mux		= rockchip_rmio_pmx_set,
+};
+
+static int rockchip_rmio_register(struct platform_device *pdev,
+				  struct rockchip_rmio *info)
+{
+	struct pinctrl_desc *ctrldesc = &info->pctl;
+	struct pinctrl_pin_desc *pindesc, *pdesc;
+	struct device *dev = &pdev->dev;
+	char **pin_names;
+	int ret;
+	int i;
+	int nr_pins = info->nr_pins;
+
+	ctrldesc->name = dev_name(dev);
+	ctrldesc->owner = THIS_MODULE;
+	ctrldesc->pctlops = &rockchip_rmio_pctrl_ops;
+	ctrldesc->pmxops = &rockchip_rmio_pmx_ops;
+
+	pindesc = devm_kcalloc(dev, nr_pins, sizeof(*pindesc), GFP_KERNEL);
+	if (!pindesc)
+		return -ENOMEM;
+
+	ctrldesc->pins = pindesc;
+	ctrldesc->npins = nr_pins;
+
+	pdesc = pindesc;
+	pin_names = devm_kasprintf_strarray(dev, dev_name(dev), nr_pins);
+	if (IS_ERR(pin_names))
+		return PTR_ERR(pin_names);
+	for (i = 0; i < nr_pins; i++) {
+		pdesc->number = i;
+		pdesc->name = pin_names[i];
+		pdesc++;
+	}
+
+	ret = rockchip_rmio_parse_dt(pdev, info);
+	if (ret)
+		return ret;
+
+	info->pctl_dev = devm_pinctrl_register(dev, ctrldesc, info);
+	if (IS_ERR(info->pctl_dev))
+		return dev_err_probe(dev, PTR_ERR(info->pctl_dev),
+				     "could not register pinctrl driver\n");
+
+	return 0;
+}
+
+static int rockchip_rmio_probe(struct platform_device *pdev)
+{
+	struct rockchip_rmio *info;
+	struct device *dev = &pdev->dev;
+	struct device_node *np = pdev->dev.of_node;
+	int ret;
+
+	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->dev = dev;
+
+	info->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,rmio-grf");
+	if (IS_ERR(info->regmap)) {
+		dev_err(&pdev->dev, "missing rockchip,rmio-grf property\n");
+		return PTR_ERR(info->regmap);
+	}
+
+	ret = of_property_read_u32(np, "rockchip,offset", &info->offset);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "missing rockchip,offset property\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(np, "rockchip,pins-num", &info->nr_pins);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "missing rockchip,pins-num property\n");
+		return ret;
+	}
+
+	ret = rockchip_rmio_register(pdev, info);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, info);
+	dev_info(dev, "probed %pfw\n", dev_fwnode(dev));
+
+	return 0;
+}
+
+static struct platform_driver rockchip_rmio_driver = {
+	.probe = rockchip_rmio_probe,
+	.driver = {
+		.name = "rockchip-rmio",
+		.of_match_table = rockchip_rmio_dt_match,
+	},
+};
+
 static struct rockchip_pin_bank px30_pin_banks[] = {
 	PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", IOMUX_SOURCE_PMU,
 					     IOMUX_SOURCE_PMU,
@@ -5190,12 +5581,19 @@ static struct platform_driver rockchip_pinctrl_driver = {
 
 static int __init rockchip_pinctrl_drv_register(void)
 {
-	return platform_driver_register(&rockchip_pinctrl_driver);
+	int ret;
+
+	ret = platform_driver_register(&rockchip_pinctrl_driver);
+	if (ret)
+		return ret;
+
+	return platform_driver_register(&rockchip_rmio_driver);
 }
 postcore_initcall(rockchip_pinctrl_drv_register);
 
 static void __exit rockchip_pinctrl_drv_unregister(void)
 {
+	platform_driver_unregister(&rockchip_rmio_driver);
 	platform_driver_unregister(&rockchip_pinctrl_driver);
 }
 module_exit(rockchip_pinctrl_drv_unregister);
@@ -5204,3 +5602,4 @@ MODULE_DESCRIPTION("ROCKCHIP Pin Controller Driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:pinctrl-rockchip");
 MODULE_DEVICE_TABLE(of, rockchip_pinctrl_dt_match);
+MODULE_DEVICE_TABLE(of, rockchip_rmio_dt_match);
diff --git a/drivers/pinctrl/pinctrl-rockchip.h b/drivers/pinctrl/pinctrl-rockchip.h
index fe18b62ed994..db875f7a3d2f 100644
--- a/drivers/pinctrl/pinctrl-rockchip.h
+++ b/drivers/pinctrl/pinctrl-rockchip.h
@@ -183,6 +183,9 @@
 #define RK_GPIO4_D6	158
 #define RK_GPIO4_D7	159
 
+#define RK_RMIO_NC			0
+#define RK_RMIO_WRITE_ENABLE_MASK	0xFFFF0000
+
 enum rockchip_pinctrl_type {
 	PX30,
 	RV1108,
@@ -473,4 +476,43 @@ struct rockchip_pinctrl {
 	unsigned int			nfunctions;
 };
 
+/**
+ * struct rockchip_rmio_group: represent a group of pins in RMIO controller.
+ * @name: name of the pin group, used to lookup the group.
+ * @pins: array of pins included in this group.
+ * @npins: number of pins included in this group.
+ * @func: local pins function select
+ */
+struct rockchip_rmio_group {
+	const char			*name;
+	unsigned int			npins;
+	unsigned int			*pins;
+	unsigned int			*func;
+};
+
+/**
+ * struct rockchip_rmio_func: represent a RMIO pin function.
+ * @name: name of the RMIO function, used to lookup the function.
+ * @groups: array of group names that can provide this RMIO function.
+ * @ngroups: number of groups included in @groups.
+ */
+struct rockchip_rmio_func {
+	const char		*name;
+	const char		**groups;
+	u8			ngroups;
+};
+
+struct rockchip_rmio {
+	struct regmap			*regmap;
+	u32				offset;
+	struct device			*dev;
+	struct pinctrl_desc		pctl;
+	struct pinctrl_dev		*pctl_dev;
+	unsigned int			nr_pins;
+	struct rockchip_rmio_group	*groups;
+	unsigned int			ngroups;
+	struct rockchip_rmio_func	*functions;
+	unsigned int			nfunctions;
+};
+
 #endif
-- 
2.34.1



From ye.zhang at rock-chips.com  Tue Dec 16 03:20:46 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Tue, 16 Dec 2025 19:20:46 +0800
Subject: [PATCH v3 0/7] pinctrl: rockchip: Add RK3506 and RV1126B pinctrl and RMIO support
Message-ID: <20251216112053.1927852-1-ye.zhang@rock-chips.com>

This series adds pinctrl support for the Rockchip RK3506 and RV1126B SoC,
and adds support for RMIO (Rockchip Matrix I/O).

The series includes:
- RK3506 pinctrl driver implementation
- RV1126B pinctrl driver implementation
- RMIO controller binding and driver support
- GPIO driver update to support new version GPIO

Note on grouping:
The RV1126B support patches are included in this series because the RV1126B
pinctrl driver implementation depends on the PIN_BANK_IOMUX_FLAGS_OFFSET_DRV_FLAGS
macro, which is introduced in the RK3506 support patches. Splitting these
patches into separate series would break the build for RV1126B if applied
independently.

Changes in v3:
- Drop already merged patches (rk3506 basic support).
- Remove unhelpful mappings in rockchip,rk3506-rmio.h
- Improve YAML schema: fix constraints and examples for RMIO.

Changes in v2:
- Added RV1126B pinctrl support (patches 3 and 4)
- Updated GPIO driver to support new version GPIO (patch 5)
- Added header file for RK3506 RMIO (patch 6)
- RMIO is now implemented as a separate pinctrl device (patches 7, 8)

Ye Zhang (7):
  pinctrl: rockchip: Add rk3506 pinctrl support
  dt-bindings: pinctrl: Add rv1126b pinctrl support
  pinctrl: rockchip: Add rv1126b pinctrl support
  arm64: dts: rockchip: rv1126b: Add pinconf and pinctrl dtsi for
    rv1126b
  gpio: rockchip: support new version GPIO
  dt-bindings: pinctrl: rockchip: Add RMIO controller binding
  pinctrl: rockchip: add rmio support

 .../bindings/pinctrl/rockchip,pinctrl.yaml    |   10 +
 .../bindings/pinctrl/rockchip,rmio.yaml       |  106 +
 .../boot/dts/rockchip/rv1126b-pinconf.dtsi    |  660 ++++
 .../boot/dts/rockchip/rv1126b-pinctrl.dtsi    | 3218 +++++++++++++++++
 drivers/gpio/gpio-rockchip.c                  |    2 +
 drivers/pinctrl/pinctrl-rockchip.c            | 1192 +++++-
 drivers/pinctrl/pinctrl-rockchip.h            |   47 +
 .../pinctrl/rockchip,rk3506-rmio.h            |  109 +
 8 files changed, 5250 insertions(+), 94 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml
 create mode 100644 arch/arm64/boot/dts/rockchip/rv1126b-pinconf.dtsi
 create mode 100644 arch/arm64/boot/dts/rockchip/rv1126b-pinctrl.dtsi
 create mode 100644 include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h

-- 
2.34.1



From nm at ti.com  Tue Dec 16 03:26:17 2025
From: nm at ti.com (Nishanth Menon)
Date: Tue, 16 Dec 2025 05:26:17 -0600
Subject: [PATCH v2 1/2] arm64: dts: ti: k3-am62-phycore-som: Enable cpsw_mac_syscon in U-Boot
In-Reply-To: <20251124090842.3377294-1-d.schultz@phytec.de>
References: <20251124090842.3377294-1-d.schultz@phytec.de>
Message-ID: <176588434530.55546.1839102927935177683.b4-ty@ti.com>

Hi Daniel Schultz,

On Mon, 24 Nov 2025 01:08:41 -0800, Daniel Schultz wrote:
> Add the "bootph-all" property to cpsw_mac_syscon.
> 
> This fuse region contains the internal MAC address. Without this
> syscon node enabled, this interface will get a random MAC during
> network boot. This is problematic because the AM62x network
> boot is using BOOTP protocol for some binaries and this protocol
> does not support dynamic lease expiration. Therefore, the DHCP
> server can run out of free IP addresses.
> 
> [...]

I have applied the following to branch ti-k3-dts-next on [1] with cosmetic
fixups. Thank you!

[1/2] arm64: dts: ti: k3-am62-phycore-som: Enable cpsw_mac_syscon in U-Boot
      commit: d468b7b8a6fe3d21df5a186d04f9d6124ef66d4d
[2/2] arm64: dts: ti: k3-am62a-phycore-som: Enable cpsw_mac_syscon in U-Boot
      commit: a9bd8d35a88e0bf72ebf5a803eb4c7f8e4731e3e

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent up the chain during
the next merge window (or sooner if it is a relevant bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/ti/linux.git
-- 
Regards,
Nishanth Menon
Key (0xDDB5849D1736249D) / Fingerprint: F8A2 8693 54EB 8232 17A3  1A34 DDB5 849D 1736 249D
https://ti.com/opensource



From jackmanb at google.com  Tue Dec 16 03:26:29 2025
From: jackmanb at google.com (Brendan Jackman)
Date: Tue, 16 Dec 2025 11:26:29 +0000
Subject: [PATCH 2/2] arm64: mmu: use pagetable_alloc_nolock() while stop_machine()
In-Reply-To: <aUE8bwUVa6jSUft1@e129823.arm.com>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com> <20251212161832.2067134-3-yeoreum.yun@arm.com>
 <CA+i-1C2e7QNTy5u=HF7tLsLXLq4xYbMTCbNjWGAxHz4uwgR05g@mail.gmail.com>
 <aT5/y3cSGIzi2K+m@e129823.arm.com> <DEYOI8H2OESD.1H56D3H8HKILB@google.com>
 <aT/WOAr4osoJWaMS@e129823.arm.com> <DEYP7JSVTB9D.3EFN2KEHH3O79@google.com>
 <aT/drjN1BkvyAGoi@e129823.arm.com> <DEZK5U2YP6I0.27VJHSVK14646@google.com> <aUE8bwUVa6jSUft1@e129823.arm.com>
Message-ID: <DEZLRT59S25H.2YWTZ2G0TN3HV@google.com>

On Tue Dec 16, 2025 at 11:03 AM UTC, Yeoreum Yun wrote:
> Hi Brendan,
>
>> On Mon Dec 15, 2025 at 10:06 AM UTC, Yeoreum Yun wrote:
>> [snip]
>> >> Overall I am feeling a bit uncomfortable about this use of _nolock, but
>> >> I am also feeling pretty ignorant about PREEMPT_RT and also about this
>> >> arm64 code, so I am hesitant to suggest alternatives, I hope someone
>> >> else can offer some input here...
>> >
>> > I understand. However, as I mentioned earlier,
>> > my main intention was to hear opinions specifically about memory contention.
>> >
>> > That said, if there is no memory contention,
>> > I don?t think using the _nolock API is necessarily a bad approach.
>>
>>
>> > In fact, I believe a bigger issue is that, under PREEMPT_RT,
>> > code that uses the regular memory allocation APIs may give users the false impression
>> > that those APIs are ?safe to use,? even though they are not.
>>
>> Yeah, I share this concern. I would bet I have written code that's
>> broken under PREEMPT_RT (luckily only in Google's kernel fork). The
>> comment for GFP_ATOMIC says:
>>
>>  * %GFP_ATOMIC users can not sleep and need the allocation to succeed. A lower
>>  * watermark is applied to allow access to "atomic reserves".
>>  * The current implementation doesn't support NMI and few other strict
>>  * non-preemptive contexts (e.g. raw_spin_lock). The same applies to %GFP_NOWAIT.
>>
>> It kinda sounds like it's supposed to be OK to use GFP_ATOMIC in a
>> normal preempt_disable() context. So do you know exactly why it's
>> invalid to use it in this stop_machine() context here? Maybe we need to
>> update this comment.
>
> In non-PREEMPT_RT configurations, this is fine to use.
> However, in PREEMPT_RT, it should not be used because
> spin_lock becomes a sleepable lock backed by an rt-mutex.
>
> From Documentation/locking/locktypes.rst:
>
>   The fact that PREEMPT_RT changes the lock category of spinlock_t and
>   rwlock_t from spinning to sleeping.
>
> As you know, all locks related to memory allocation
> (e.g., zone_lock, PCP locks, etc.) use spin_lock,
> which becomes sleepable under PREEMPT_RT.
>
> The callback of stop_machine() is executed in a preemption-disabled context
> (see cpu_stopper_thread()). In this context, if it fails to acquire a spinlock
> during memory allocation,
> the task would be able to go to sleep while preemption is disabled,
> which is an obviously problematic situation.

But this is what I mean, doesn't this sound like the GFP_ATOMIC comment
I quoted is wrong (or at least, it implies things which are wrong)? The
comment refers specifically to raw_spin_lock() and "strict
non-preemptive contexts". Which sounds like it is being written with
PREEMPT_RT in mind. But that doesn't really match what you've said.


From lkp at intel.com  Tue Dec 16 03:24:28 2025
From: lkp at intel.com (kernel test robot)
Date: Tue, 16 Dec 2025 19:24:28 +0800
Subject: [soc:arm/fixes] BUILD SUCCESS
 ececfba255bf3616301419e47a5c824e04b60ab8
Message-ID: <202512161922.GfdvGNrc-lkp@intel.com>

tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git arm/fixes
branch HEAD: ececfba255bf3616301419e47a5c824e04b60ab8  ARM: dts: ixp4xx: Fix up Actiontec MI424WR DTS files

elapsed time: 900m

configs tested: 173
configs skipped: 10

The following configs have been built successfully.
More configs may be tested in the coming days.

tested configs:
alpha                             allnoconfig    gcc-15.1.0
alpha                            allyesconfig    gcc-15.1.0
alpha                               defconfig    gcc-15.1.0
arc                              allmodconfig    clang-16
arc                               allnoconfig    gcc-15.1.0
arc                              allyesconfig    clang-22
arc                                 defconfig    gcc-15.1.0
arc                   randconfig-001-20251216    gcc-8.5.0
arc                   randconfig-002-20251216    gcc-8.5.0
arm                               allnoconfig    gcc-15.1.0
arm                              allyesconfig    clang-16
arm                                 defconfig    gcc-15.1.0
arm                   milbeaut_m10v_defconfig    gcc-15.1.0
arm                   randconfig-001-20251216    gcc-8.5.0
arm                   randconfig-002-20251216    gcc-8.5.0
arm                   randconfig-003-20251216    gcc-8.5.0
arm                   randconfig-004-20251216    gcc-8.5.0
arm64                            allmodconfig    clang-22
arm64                             allnoconfig    gcc-15.1.0
arm64                               defconfig    gcc-15.1.0
arm64                 randconfig-001-20251216    gcc-10.5.0
arm64                 randconfig-002-20251216    gcc-10.5.0
arm64                 randconfig-003-20251216    gcc-10.5.0
arm64                 randconfig-004-20251216    gcc-10.5.0
csky                             allmodconfig    gcc-15.1.0
csky                              allnoconfig    gcc-15.1.0
csky                                defconfig    gcc-15.1.0
csky                  randconfig-001-20251216    gcc-10.5.0
csky                  randconfig-002-20251216    gcc-10.5.0
hexagon                          allmodconfig    gcc-15.1.0
hexagon                           allnoconfig    gcc-15.1.0
hexagon                             defconfig    gcc-15.1.0
hexagon               randconfig-001-20251216    gcc-8.5.0
hexagon               randconfig-002-20251216    gcc-8.5.0
i386                             allmodconfig    clang-20
i386                              allnoconfig    gcc-15.1.0
i386                             allyesconfig    clang-20
i386        buildonly-randconfig-001-20251216    gcc-14
i386        buildonly-randconfig-002-20251216    gcc-14
i386        buildonly-randconfig-003-20251216    gcc-14
i386        buildonly-randconfig-004-20251216    gcc-14
i386        buildonly-randconfig-005-20251216    gcc-14
i386        buildonly-randconfig-006-20251216    gcc-14
i386                                defconfig    gcc-15.1.0
i386                  randconfig-001-20251216    gcc-14
i386                  randconfig-002-20251216    gcc-14
i386                  randconfig-003-20251216    gcc-14
i386                  randconfig-004-20251216    gcc-14
i386                  randconfig-005-20251216    gcc-14
i386                  randconfig-006-20251216    gcc-14
i386                  randconfig-007-20251216    gcc-14
i386                  randconfig-011-20251216    gcc-13
i386                  randconfig-012-20251216    gcc-13
i386                  randconfig-013-20251216    gcc-13
i386                  randconfig-014-20251216    gcc-13
i386                  randconfig-015-20251216    gcc-13
i386                  randconfig-016-20251216    gcc-13
i386                  randconfig-017-20251216    gcc-13
loongarch                        allmodconfig    clang-22
loongarch                         allnoconfig    gcc-15.1.0
loongarch                           defconfig    clang-19
loongarch             randconfig-001-20251216    gcc-8.5.0
loongarch             randconfig-002-20251216    gcc-8.5.0
m68k                             allmodconfig    gcc-15.1.0
m68k                              allnoconfig    gcc-15.1.0
m68k                             allyesconfig    clang-16
m68k                                defconfig    clang-19
m68k                        m5272c3_defconfig    gcc-15.1.0
microblaze                        allnoconfig    gcc-15.1.0
microblaze                       allyesconfig    gcc-15.1.0
microblaze                          defconfig    clang-19
mips                             allmodconfig    gcc-15.1.0
mips                              allnoconfig    gcc-15.1.0
mips                             allyesconfig    gcc-15.1.0
mips                           ip30_defconfig    gcc-15.1.0
nios2                            allmodconfig    clang-22
nios2                             allnoconfig    clang-22
nios2                               defconfig    clang-19
nios2                 randconfig-001-20251216    gcc-8.5.0
nios2                 randconfig-002-20251216    gcc-8.5.0
openrisc                         allmodconfig    clang-22
openrisc                          allnoconfig    clang-22
openrisc                            defconfig    gcc-15.1.0
parisc                           allmodconfig    gcc-15.1.0
parisc                            allnoconfig    clang-22
parisc                           allyesconfig    clang-19
parisc                              defconfig    gcc-15.1.0
parisc                randconfig-001-20251216    clang-22
parisc                randconfig-002-20251216    clang-22
parisc64                            defconfig    clang-19
powerpc                          allmodconfig    gcc-15.1.0
powerpc                           allnoconfig    clang-22
powerpc                      bamboo_defconfig    gcc-15.1.0
powerpc                      ep88xc_defconfig    gcc-15.1.0
powerpc               randconfig-001-20251216    clang-22
powerpc               randconfig-002-20251216    clang-22
powerpc64             randconfig-001-20251216    clang-22
powerpc64             randconfig-002-20251216    clang-22
riscv                            allmodconfig    clang-22
riscv                             allnoconfig    clang-22
riscv                            allyesconfig    clang-16
riscv                               defconfig    gcc-15.1.0
riscv                 randconfig-001-20251216    clang-17
riscv                 randconfig-002-20251216    clang-17
s390                             allmodconfig    clang-19
s390                              allnoconfig    clang-22
s390                             allyesconfig    gcc-15.1.0
s390                                defconfig    gcc-15.1.0
s390                  randconfig-001-20251216    clang-17
s390                  randconfig-002-20251216    clang-17
sh                               allmodconfig    gcc-15.1.0
sh                                allnoconfig    clang-22
sh                               allyesconfig    clang-19
sh                                  defconfig    gcc-14
sh                    randconfig-001-20251216    clang-17
sh                    randconfig-002-20251216    clang-17
sh                           se7712_defconfig    gcc-15.1.0
sparc                             allnoconfig    clang-22
sparc                               defconfig    gcc-15.1.0
sparc                 randconfig-001-20251216    gcc-8.5.0
sparc                 randconfig-002-20251216    gcc-8.5.0
sparc64                          allmodconfig    clang-22
sparc64                             defconfig    gcc-14
sparc64               randconfig-001-20251216    gcc-8.5.0
sparc64               randconfig-002-20251216    gcc-8.5.0
um                               allmodconfig    clang-19
um                                allnoconfig    clang-22
um                               allyesconfig    gcc-15.1.0
um                                  defconfig    gcc-14
um                             i386_defconfig    gcc-14
um                    randconfig-001-20251216    gcc-8.5.0
um                    randconfig-002-20251216    gcc-8.5.0
um                           x86_64_defconfig    gcc-14
x86_64                           allmodconfig    clang-20
x86_64                            allnoconfig    clang-22
x86_64                           allyesconfig    clang-20
x86_64      buildonly-randconfig-001-20251216    clang-20
x86_64      buildonly-randconfig-002-20251216    clang-20
x86_64      buildonly-randconfig-003-20251216    clang-20
x86_64      buildonly-randconfig-004-20251216    clang-20
x86_64      buildonly-randconfig-005-20251216    clang-20
x86_64      buildonly-randconfig-006-20251216    clang-20
x86_64                              defconfig    gcc-14
x86_64                                  kexec    clang-20
x86_64                randconfig-001-20251216    clang-20
x86_64                randconfig-002-20251216    clang-20
x86_64                randconfig-003-20251216    clang-20
x86_64                randconfig-004-20251216    clang-20
x86_64                randconfig-005-20251216    clang-20
x86_64                randconfig-006-20251216    clang-20
x86_64                randconfig-011-20251216    clang-20
x86_64                randconfig-012-20251216    clang-20
x86_64                randconfig-013-20251216    clang-20
x86_64                randconfig-014-20251216    clang-20
x86_64                randconfig-015-20251216    clang-20
x86_64                randconfig-016-20251216    clang-20
x86_64                randconfig-071-20251216    gcc-14
x86_64                randconfig-072-20251216    gcc-14
x86_64                randconfig-073-20251216    gcc-14
x86_64                randconfig-074-20251216    gcc-14
x86_64                randconfig-075-20251216    gcc-14
x86_64                randconfig-076-20251216    gcc-14
x86_64                               rhel-9.4    clang-20
x86_64                           rhel-9.4-bpf    gcc-14
x86_64                          rhel-9.4-func    clang-20
x86_64                    rhel-9.4-kselftests    clang-20
x86_64                         rhel-9.4-kunit    gcc-14
x86_64                           rhel-9.4-ltp    gcc-14
x86_64                          rhel-9.4-rust    clang-20
xtensa                            allnoconfig    clang-22
xtensa                           allyesconfig    clang-22
xtensa                randconfig-001-20251216    gcc-8.5.0
xtensa                randconfig-002-20251216    gcc-8.5.0

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From nm at ti.com  Tue Dec 16 03:26:47 2025
From: nm at ti.com (Nishanth Menon)
Date: Tue, 16 Dec 2025 05:26:47 -0600
Subject: [PATCH] arm64: dts: ti: k3-am62(a)-phycore-som: Mark phy_gmii_sel with bootph-all
In-Reply-To: <20251124160548.2273931-1-w.egorov@phytec.de>
References: <20251124160548.2273931-1-w.egorov@phytec.de>
Message-ID: <176588438533.55896.15879666642426331708.b4-ty@ti.com>

Hi Wadim Egorov,

On Mon, 24 Nov 2025 17:05:48 +0100, Wadim Egorov wrote:
> Add the bootph-all property to the phy_gmii_sel node to ensure it is
> available during all boot phases. This is required when the bootloader
> is getting booted via network.
> 
> 

I have applied the following to branch ti-k3-dts-next on [1] with minor
cosmetic fixups. Thank you!

[1/1] arm64: dts: ti: k3-am62(a)-phycore-som: Mark phy_gmii_sel with bootph-all
      commit: e05f6566bc778bc1215283e667e18692d16b25f5

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent up the chain during
the next merge window (or sooner if it is a relevant bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/ti/linux.git
-- 
Regards,
Nishanth Menon
Key (0xDDB5849D1736249D) / Fingerprint: F8A2 8693 54EB 8232 17A3  1A34 DDB5 849D 1736 249D
https://ti.com/opensource



From nm at ti.com  Tue Dec 16 03:27:06 2025
From: nm at ti.com (Nishanth Menon)
Date: Tue, 16 Dec 2025 05:27:06 -0600
Subject: [PATCH v1 0/2] arm64: dts: ti: k3-am69-aquila: Fix USB-C Sink PDO
In-Reply-To: <20251204134220.129304-1-francesco@dolcini.it>
References: <20251204134220.129304-1-francesco@dolcini.it>
Message-ID: <176588441712.56134.6319284931357178936.b4-ty@ti.com>

Hi Francesco Dolcini,

On Thu, 04 Dec 2025 14:42:17 +0100, Francesco Dolcini wrote:
> From: Francesco Dolcini <francesco.dolcini at toradex.com>
> 
> Change USB-C Sink PDO and the amount of power that the device can sink to
> zero to maximize compatibility with other USB peers (the Aquila Clover and
> Development Boards are not sinking any current, they are self powered).
> 
> Francesco Dolcini (2):
>   arm64: dts: ti: k3-am69-aquila-dev: Fix USB-C Sink PDO
>   arm64: dts: ti: k3-am69-aquila-clover: Fix USB-C Sink PDO
> 
> [...]

I have applied the following to branch ti-k3-dts-next on [1].
Thank you!

[1/2] arm64: dts: ti: k3-am69-aquila-dev: Fix USB-C Sink PDO
      commit: 36ee9f8b1ae07fe82885a7a3553a5be347d3f978
[2/2] arm64: dts: ti: k3-am69-aquila-clover: Fix USB-C Sink PDO
      commit: b548f3949937b55ee19ab418343f05700fdf7009

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent up the chain during
the next merge window (or sooner if it is a relevant bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/ti/linux.git
-- 
Regards,
Nishanth Menon
Key (0xDDB5849D1736249D) / Fingerprint: F8A2 8693 54EB 8232 17A3  1A34 DDB5 849D 1736 249D
https://ti.com/opensource



From nm at ti.com  Tue Dec 16 03:31:01 2025
From: nm at ti.com (Nishanth Menon)
Date: Tue, 16 Dec 2025 05:31:01 -0600
Subject: [PATCH v1] arm64: dts: ti: am62p-verdin: Fix SD regulator startup delay
In-Reply-To: <20251209084126.33282-1-francesco@dolcini.it>
References: <20251209084126.33282-1-francesco@dolcini.it>
Message-ID: <176588464864.57937.8124279856116763834.b4-ty@ti.com>

Hi Francesco Dolcini,

On Tue, 09 Dec 2025 09:41:25 +0100, Francesco Dolcini wrote:
> The power switch used to power the SD card interface might have
> more than 2ms turn-on time, increase the startup delay to 20ms to
> prevent failures.
> 
> 

I have applied the following to branch ti-k3-dts-next on [1].
Thank you!

[1/1] arm64: dts: ti: am62p-verdin: Fix SD regulator startup delay
      commit: de86dbc0fb00bd3773db4b05d9f5926f0faa2244

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent up the chain during
the next merge window (or sooner if it is a relevant bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/ti/linux.git
-- 
Regards,
Nishanth Menon
Key (0xDDB5849D1736249D) / Fingerprint: F8A2 8693 54EB 8232 17A3  1A34 DDB5 849D 1736 249D
https://ti.com/opensource



From suzuki.poulose at arm.com  Tue Dec 16 03:40:20 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Tue, 16 Dec 2025 11:40:20 +0000
Subject: [RFC PATCH v6 16/35] KVM: arm64: Advertise SPE version in
 ID_AA64DFR0_EL1.PMSver
In-Reply-To: <20251114160717.163230-17-alexandru.elisei@arm.com>
References: <20251114160717.163230-1-alexandru.elisei@arm.com>
 <20251114160717.163230-17-alexandru.elisei@arm.com>
Message-ID: <36416368-4447-4b16-8496-3e3d603d88d4@arm.com>

On 14/11/2025 16:06, Alexandru Elisei wrote:
> The VCPU registers are reset during the KVM_ARM_VCPU_INIT ioctl, before
> userspace can set the desired SPU. Assume that the VCPU is initialized from


> a thread that runs on one of the physical CPUs that correspond to the SPU
> that userspace will choose for the VM. Set PMSVer to that CPUs hardware
> value.

This doesn't match the code. See below.

> 
> Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
> ---
>   arch/arm64/include/asm/kvm_spe.h |  6 ++++++
>   arch/arm64/kvm/spe.c             | 10 ++++++++++
>   arch/arm64/kvm/sys_regs.c        | 10 +++++++++-
>   3 files changed, 25 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_spe.h b/arch/arm64/include/asm/kvm_spe.h
> index 6ce70cf2abaf..5e6d7e609a48 100644
> --- a/arch/arm64/include/asm/kvm_spe.h
> +++ b/arch/arm64/include/asm/kvm_spe.h
> @@ -33,6 +33,8 @@ static __always_inline bool kvm_supports_spe(void)
>   void kvm_spe_init_vm(struct kvm *kvm);
>   int kvm_spe_vcpu_first_run_init(struct kvm_vcpu *vcpu);
>   
> +u8 kvm_spe_get_pmsver_limit(void);
> +
>   int kvm_spe_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);
>   int kvm_spe_get_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);
>   int kvm_spe_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);
> @@ -53,6 +55,10 @@ static inline int kvm_spe_vcpu_first_run_init(struct kvm_vcpu *vcpu)
>   {
>   	return 0;
>   }
> +static inline u8 kvm_spe_get_pmsver_limit(void)
> +{
> +	return 0;
> +}
>   static inline int kvm_spe_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
>   {
>   	return -ENXIO;
> diff --git a/arch/arm64/kvm/spe.c b/arch/arm64/kvm/spe.c
> index 6bd074e40f6c..0c4896c6a873 100644
> --- a/arch/arm64/kvm/spe.c
> +++ b/arch/arm64/kvm/spe.c
> @@ -68,6 +68,16 @@ int kvm_spe_vcpu_first_run_init(struct kvm_vcpu *vcpu)
>   	return 0;
>   }
>   
> +u8 kvm_spe_get_pmsver_limit(void)
> +{
> +	unsigned int pmsver;
> +
> +	pmsver = SYS_FIELD_GET(ID_AA64DFR0_EL1, PMSVer,
> +			       read_sanitised_ftr_reg(SYS_ID_AA64DFR0_EL1));

The read_sanitised_ftr_reg() gives you the system wide sanitised
version, not the one on the current CPU. You may need
read_sysreg_s() instead here.


> +
> +	return min(pmsver, ID_AA64DFR0_EL1_PMSVer_V1P5);
> +}
> +
>   static u64 max_buffer_size_to_pmbidr_el1(u64 size)
>   {
>   	u64 msb_idx, num_bits;
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index e67eb39ddc11..ac859c39c2be 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -29,6 +29,7 @@
>   #include <asm/kvm_hyp.h>
>   #include <asm/kvm_mmu.h>
>   #include <asm/kvm_nested.h>
> +#include <asm/kvm_spe.h>
>   #include <asm/perf_event.h>
>   #include <asm/sysreg.h>
>   
> @@ -1652,6 +1653,9 @@ static s64 kvm_arm64_ftr_safe_value(u32 id, const struct arm64_ftr_bits *ftrp,
>   		case ID_AA64DFR0_EL1_DebugVer_SHIFT:
>   			kvm_ftr.type = FTR_LOWER_SAFE;
>   			break;
> +		case ID_AA64DFR0_EL1_PMSVer_SHIFT:
> +			kvm_ftr.type = FTR_LOWER_SAFE;

PMSVer is already FTR_LOWER_SAFE, and we don't need to override it here 
? (unlike the DebugVer or PMU Ver)

> +			break;
>   		}
>   		break;
>   	case SYS_ID_DFR0_EL1:
> @@ -2021,8 +2025,11 @@ static u64 sanitise_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val)
>   		val |= SYS_FIELD_PREP(ID_AA64DFR0_EL1, PMUVer,
>   				      kvm_arm_pmu_get_pmuver_limit());
>   
> -	/* Hide SPE from guests */
>   	val &= ~ID_AA64DFR0_EL1_PMSVer_MASK;
> +	if (vcpu_has_spe(vcpu)) {
> +		val |= SYS_FIELD_PREP(ID_AA64DFR0_EL1, PMSVer,
> +				      kvm_spe_get_pmsver_limit());
> +	}

So, we ignore value that the user sets and go with what the SPE instance
that has been chosen ? Should we make it non-writable then ?

Suzuki

>   
>   	/* Hide BRBE from guests */
>   	val &= ~ID_AA64DFR0_EL1_BRBE_MASK;
> @@ -3209,6 +3216,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>   	 */
>   	ID_FILTERED(ID_AA64DFR0_EL1, id_aa64dfr0_el1,
>   		    ID_AA64DFR0_EL1_DoubleLock_MASK |
> +		    ID_AA64DFR0_EL1_PMSVer_MASK |
>   		    ID_AA64DFR0_EL1_WRPs_MASK |
>   		    ID_AA64DFR0_EL1_PMUVer_MASK |
>   		    ID_AA64DFR0_EL1_DebugVer_MASK),



From daniel.baluta at gmail.com  Tue Dec 16 03:51:55 2025
From: daniel.baluta at gmail.com (Daniel Baluta)
Date: Tue, 16 Dec 2025 13:51:55 +0200
Subject: [PATCH v4 4/5] remoteproc: imx_rproc: Add support for System
 Manager API
In-Reply-To: <20251216-imx95-rproc-2025-12-15-v4-4-bf1064ea8daf@nxp.com>
References: <20251216-imx95-rproc-2025-12-15-v4-0-bf1064ea8daf@nxp.com> <20251216-imx95-rproc-2025-12-15-v4-4-bf1064ea8daf@nxp.com>
Message-ID: <CAEnQRZBS7zzc9AmTymCGVKwExeZ-JNFiG9MamWOZmk=gXdBY7w@mail.gmail.com>

On Tue, Dec 16, 2025 at 3:53?AM Peng Fan (OSS) <peng.fan at oss.nxp.com> wrote:
>
> From: Peng Fan <peng.fan at nxp.com>
>
> i.MX95 features a Cortex-M33 core, six Cortex-A55 cores, and
> one Cortex-M7 core. The System Control Management Interface(SCMI)
> firmware runs on the M33 core. The i.MX95 SCMI firmware named System
> Manager(SM) includes vendor extension protocols, Logical Machine
> Management(LMM) protocol and CPU protocol and etc.
>
> Depending on SM configuration, M7 can be used as follows:
>  (1) M7 in a separate Logical Machine (LM) from A55 cores, that Linux
>      can't control
>  (2) M7 in a separate LM from A55 cores that Linux can control using LMM
>      protocol.
>  (3) M7 runs in same Logical Machine as A55 cores, so Linux can control it
>      using CPU protocol
>
> So extend the driver to using LMM and CPU protocol to manage the M7 core.
>  - Compare linux LM ID(got using scmi_imx_lmm_info) and M7 LM ID(the ID
>    is fixed as 1 in SM firmware if M7 is in a separate LM),
>    if Linux LM ID equals M7 LM ID(linux and M7 in same LM), use CPU
>    protocol to start/stop. Otherwise, use LMM protocol to start/stop.
>    Whether using CPU or LMM protocol to start/stop, the M7 status
>    detection could use CPU protocol to detect started or not. So
>    in imx_rproc_detect_mode, use scmi_imx_cpu_started to check the
>    status of M7.
>  - For above case (1) and (2), Use SCMI_IMX_LMM_POWER_ON to detect whether
>    the M7 LM is under control of A55 LM.
>  - For above case , after using SCMI_IMX_LMM_POWER_ON to check
>    permission, SCMI_IMX_LMM_SHUTDOWN API should be called to shutdown
>    the M7 LM to save power only when M7 LM is going to be started by
>    remoteproc framework. Otherwise bypass SCMI_IMX_LMM_SHUTDOWN API if
>    M7 LM is started before booting Linux.
>
> Current setup relies on pre-Linux software(U-Boot) to do M7 TCM ECC
> initialization. In future, we could add the support in Linux to decouple
> U-Boot and Linux.
>
> Signed-off-by: Peng Fan <peng.fan at nxp.com>

Reviewed-by: Daniel Baluta <daniel.baluta at nxp.com>


From Suraj.Gupta2 at amd.com  Tue Dec 16 03:53:00 2025
From: Suraj.Gupta2 at amd.com (Gupta, Suraj)
Date: Tue, 16 Dec 2025 11:53:00 +0000
Subject: [PATCH net-next v4 1/7] net: axienet: Fix resource release
 ordering
In-Reply-To: <9572f798-d294-4f24-8acb-c7972c1db247@lunn.ch>
References: <20250805153456.1313661-1-sean.anderson@linux.dev>
 <20250805153456.1313661-2-sean.anderson@linux.dev>
 <9572f798-d294-4f24-8acb-c7972c1db247@lunn.ch>
Message-ID: <SA1PR12MB6798CD01D26F4A68D6F7A214C9AAA@SA1PR12MB6798.namprd12.prod.outlook.com>

[Public]

Hi,
> -----Original Message-----
> From: Andrew Lunn <andrew at lunn.ch>
> Sent: Wednesday, August 6, 2025 2:29 AM
> To: Sean Anderson <sean.anderson at linux.dev>
> Cc: Pandey, Radhey Shyam <radhey.shyam.pandey at amd.com>; Andrew Lunn
> <andrew+netdev at lunn.ch>; David S . Miller <davem at davemloft.net>; Eric
> Dumazet <edumazet at google.com>; Jakub Kicinski <kuba at kernel.org>; Paolo
> Abeni <pabeni at redhat.com>; netdev at vger.kernel.org; linux-arm-
> kernel at lists.infradead.org; linux-kernel at vger.kernel.org; Greg Kroah-Hartman
> <gregkh at linuxfoundation.org>; Simek, Michal <michal.simek at amd.com>;
> Leon Romanovsky <leon at kernel.org>; Gupta, Suraj <Suraj.Gupta2 at amd.com>
> Subject: Re: [PATCH net-next v4 1/7] net: axienet: Fix resource release ordering
>
> Caution: This message originated from an External Source. Use proper caution
> when opening attachments, clicking links, or responding.
>
>
> > +static void axienet_disable_misc(void *clocks) {
> > +     clk_bulk_disable_unprepare(XAE_NUM_MISC_CLOCKS, clocks); }
> > +
>
> ...
>
> >       ret = devm_clk_bulk_get_optional(&pdev->dev, XAE_NUM_MISC_CLOCKS,
> lp->misc_clks);
> >       if (ret)
> > -             goto cleanup_clk;
> > +             return dev_err_probe(&pdev->dev, ret,
> > +                                  "could not get misc. clocks\n");
> >
> >       ret = clk_bulk_prepare_enable(XAE_NUM_MISC_CLOCKS, lp->misc_clks);
> >       if (ret)
> > -             goto cleanup_clk;
> > +             return dev_err_probe(&pdev->dev, ret,
> > +                                  "could not enable misc. clocks\n");
> > +
> > +     ret = devm_add_action_or_reset(&pdev->dev, axienet_disable_misc,
> > +                                    lp->misc_clks);
>
> It seems like it would be better to add
> devm_clk_bulk_get_optional_enable(). There is already an
> devm_clk_bulk_get_all_enabled() so it does not seem like too big a step.
>
>         Andrew

We are interested in this patch to fix AXI Ethernet probe path and can collaborate on upstreaming it.

Regards,
Suraj


From suzuki.poulose at arm.com  Tue Dec 16 03:54:54 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Tue, 16 Dec 2025 11:54:54 +0000
Subject: [RFC PATCH v6 17/35] KVM: arm64: Add writable SPE system
 registers to VCPU context
In-Reply-To: <20251114160717.163230-18-alexandru.elisei@arm.com>
References: <20251114160717.163230-1-alexandru.elisei@arm.com>
 <20251114160717.163230-18-alexandru.elisei@arm.com>
Message-ID: <3ccbd4df-92a3-4d70-9ed8-c4a5658508d1@arm.com>

On 14/11/2025 16:06, Alexandru Elisei wrote:
> Add the writable SPE registers to the VCPU context. The registers for now
> have generic accessors, with proper handling to be added. PMSIDR_EL1 and
> PMBIDR_EL1 are not part of the VCPU context because they are read-only
> registers.
> 
> Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
> ---
>   arch/arm64/include/asm/kvm_host.h | 13 +++++++
>   arch/arm64/include/asm/kvm_spe.h  | 11 ++++++
>   arch/arm64/kvm/debug.c            | 19 ++++++++---
>   arch/arm64/kvm/spe.c              | 13 +++++++
>   arch/arm64/kvm/sys_regs.c         | 56 ++++++++++++++++++++++++-------
>   5 files changed, 94 insertions(+), 18 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 373d22ec4783..876957320672 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -464,6 +464,19 @@ enum vcpu_sysreg {
>   	PMOVSSET_EL0,	/* Overflow Flag Status Set Register */
>   	PMUSERENR_EL0,	/* User Enable Register */
>   
> +	/* SPE registers */
> +	PMSCR_EL1,
> +	PMSNEVFR_EL1,
> +	PMSICR_EL1,
> +	PMSIRR_EL1,
> +	PMSFCR_EL1,
> +	PMSEVFR_EL1,
> +	PMSLATFR_EL1,
> +	PMBLIMITR_EL1,
> +	PMBPTR_EL1,
> +	PMBSR_EL1,
> +	PMSDSFR_EL1,
> +
>   	/* Pointer Authentication Registers in a strict increasing order. */
>   	APIAKEYLO_EL1,
>   	APIAKEYHI_EL1,
> diff --git a/arch/arm64/include/asm/kvm_spe.h b/arch/arm64/include/asm/kvm_spe.h
> index 5e6d7e609a48..3506d8c4c661 100644
> --- a/arch/arm64/include/asm/kvm_spe.h
> +++ b/arch/arm64/include/asm/kvm_spe.h
> @@ -38,6 +38,9 @@ u8 kvm_spe_get_pmsver_limit(void);
>   int kvm_spe_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);
>   int kvm_spe_get_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);
>   int kvm_spe_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);
> +
> +bool kvm_spe_write_sysreg(struct kvm_vcpu *vcpu, int reg, u64 val);
> +u64 kvm_spe_read_sysreg(struct kvm_vcpu *vcpu, int reg);
>   #else
>   struct kvm_spe {
>   };
> @@ -71,6 +74,14 @@ static inline int kvm_spe_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr
>   {
>   	return -ENXIO;
>   }
> +static inline bool kvm_spe_write_sysreg(struct kvm_vcpu *vcpu, int reg, u64 val)
> +{
> +	return true;
> +}
> +static inline u64 kvm_spe_read_sysreg(struct kvm_vcpu *vcpu, int reg)
> +{
> +	return 0;
> +}
>   #endif /* CONFIG_KVM_ARM_SPE */
>   
>   #endif /* __ARM64_KVM_SPE_H__ */
> diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
> index 3ad6b7c6e4ba..0821ebfb03fa 100644
> --- a/arch/arm64/kvm/debug.c
> +++ b/arch/arm64/kvm/debug.c
> @@ -38,19 +38,28 @@ static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu)
>   {
>   	preempt_disable();
>   
> -	/*
> -	 * This also clears MDCR_EL2_E2PB_MASK and MDCR_EL2_E2TB_MASK
> -	 * to disable guest access to the profiling and trace buffers
> -	 */
>   	vcpu->arch.mdcr_el2 = FIELD_PREP(MDCR_EL2_HPMN,
>   					 *host_data_ptr(nr_event_counters));
> +	/*
> +	 * This also clears MDCR_EL2_E2PB_MASK to disable guest access to the
> +	 * trace buffer.

nit: MDCR_EL2_E2TB_MASK is for the trace buffer.


Suzuki


> +	 */
>   	vcpu->arch.mdcr_el2 |= (MDCR_EL2_TPM |
> -				MDCR_EL2_TPMS |
>   				MDCR_EL2_TTRF |
>   				MDCR_EL2_TPMCR |
>   				MDCR_EL2_TDRA |
>   				MDCR_EL2_TDOSA);
>   
> +	if (vcpu_has_spe(vcpu)) {
> +		/* Set buffer owner to EL1 and trap the buffer registers. */
> +		vcpu->arch.mdcr_el2 |= FIELD_PREP(MDCR_EL2_E2PB, MDCR_EL2_E2PB_EL1_TRAP);
> +		/* Leave TPMS zero and don't trap the sampling registers. */
> +	} else {
> +		/* Trap the sampling registers. */
> +		vcpu->arch.mdcr_el2 |= MDCR_EL2_TPMS;
> +		/* Leave E2PB zero and trap the buffer registers. */
> +	}
> +
>   	/* Is the VM being debugged by userspace? */
>   	if (vcpu->guest_debug)
>   		/* Route all software debug exceptions to EL2 */
> diff --git a/arch/arm64/kvm/spe.c b/arch/arm64/kvm/spe.c
> index 0c4896c6a873..5b3dc622cf82 100644
> --- a/arch/arm64/kvm/spe.c
> +++ b/arch/arm64/kvm/spe.c
> @@ -8,6 +8,7 @@
>   #include <linux/kvm_host.h>
>   #include <linux/perf/arm_spe_pmu.h>
>   
> +#include <asm/kvm_emulate.h>
>   #include <asm/kvm_spe.h>
>   #include <asm/sysreg.h>
>   
> @@ -78,6 +79,18 @@ u8 kvm_spe_get_pmsver_limit(void)
>   	return min(pmsver, ID_AA64DFR0_EL1_PMSVer_V1P5);
>   }
>   
> +bool kvm_spe_write_sysreg(struct kvm_vcpu *vcpu, int reg, u64 val)
> +{
> +	__vcpu_assign_sys_reg(vcpu, val, reg);
> +
> +	return true;
> +}
> +
> +u64 kvm_spe_read_sysreg(struct kvm_vcpu *vcpu, int reg)
> +{
> +	return __vcpu_sys_reg(vcpu, reg);
> +}
> +
>   static u64 max_buffer_size_to_pmbidr_el1(u64 size)
>   {
>   	u64 msb_idx, num_bits;
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index ac859c39c2be..5eeea229b46e 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -1374,6 +1374,28 @@ static int set_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
>   	return 0;
>   }
>   
> +static unsigned int spe_visibility(const struct kvm_vcpu *vcpu,
> +				   const struct sys_reg_desc *r)
> +{
> +	if (vcpu_has_spe(vcpu))
> +		return 0;
> +
> +	return REG_HIDDEN;
> +}
> +
> +static bool access_spe_reg(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +			   const struct sys_reg_desc *r)
> +{
> +	u64 val = p->regval;
> +	int reg = r->reg;
> +
> +	if (p->is_write)
> +		return kvm_spe_write_sysreg(vcpu, reg, val);
> +
> +	p->regval = kvm_spe_read_sysreg(vcpu, reg);
> +	return true;
> +}
> +
>   /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
>   #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
>   	{ SYS_DESC(SYS_DBGBVRn_EL1(n)),					\
> @@ -1406,6 +1428,14 @@ static int set_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
>   	  .reset = reset_pmevtyper,					\
>   	  .access = access_pmu_evtyper, .reg = (PMEVTYPER0_EL0 + n), }
>   
> +#define SPE_TRAPPED_REG(name)						\
> +	SYS_DESC(SYS_##name), .reg = name, .access = access_spe_reg,	\
> +	.reset = reset_val, .val = 0, .visibility = spe_visibility
> +
> +#define SPE_UNTRAPPED_REG(name)						\
> +	SYS_DESC(SYS_##name), .reg = name, .access = undef_access,	\
> +	.reset = reset_val, .val = 0, .visibility = spe_visibility
> +
>   /* Macro to expand the AMU counter and type registers*/
>   #define AMU_AMEVCNTR0_EL0(n) { SYS_DESC(SYS_AMEVCNTR0_EL0(n)), undef_access }
>   #define AMU_AMEVTYPER0_EL0(n) { SYS_DESC(SYS_AMEVTYPER0_EL0(n)), undef_access }
> @@ -3323,19 +3353,19 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>   	{ SYS_DESC(SYS_FAR_EL1), access_vm_reg, reset_unknown, FAR_EL1 },
>   	{ SYS_DESC(SYS_PAR_EL1), NULL, reset_unknown, PAR_EL1 },
>   
> -	{ SYS_DESC(SYS_PMSCR_EL1), undef_access },
> -	{ SYS_DESC(SYS_PMSNEVFR_EL1), undef_access },
> -	{ SYS_DESC(SYS_PMSICR_EL1), undef_access },
> -	{ SYS_DESC(SYS_PMSIRR_EL1), undef_access },
> -	{ SYS_DESC(SYS_PMSFCR_EL1), undef_access },
> -	{ SYS_DESC(SYS_PMSEVFR_EL1), undef_access },
> -	{ SYS_DESC(SYS_PMSLATFR_EL1), undef_access },
> -	{ SYS_DESC(SYS_PMSIDR_EL1), undef_access },
> -	{ SYS_DESC(SYS_PMBLIMITR_EL1), undef_access },
> -	{ SYS_DESC(SYS_PMBPTR_EL1), undef_access },
> -	{ SYS_DESC(SYS_PMBSR_EL1), undef_access },
> -	{ SYS_DESC(SYS_PMSDSFR_EL1), undef_access },
> -	/* PMBIDR_EL1 is not trapped */
> +	{ SPE_UNTRAPPED_REG(PMSCR_EL1) },
> +	{ SPE_UNTRAPPED_REG(PMSNEVFR_EL1) },
> +	{ SPE_UNTRAPPED_REG(PMSICR_EL1) },
> +	{ SPE_UNTRAPPED_REG(PMSIRR_EL1) },
> +	{ SPE_UNTRAPPED_REG(PMSFCR_EL1) },
> +	{ SPE_UNTRAPPED_REG(PMSEVFR_EL1) },
> +	{ SPE_UNTRAPPED_REG(PMSLATFR_EL1) },
> +	{ SYS_DESC(SYS_PMSIDR_EL1), .access = undef_access },
> +	{ SPE_TRAPPED_REG(PMBLIMITR_EL1) },
> +	{ SPE_TRAPPED_REG(PMBPTR_EL1) },
> +	{ SPE_TRAPPED_REG(PMBSR_EL1) },
> +	{ SPE_UNTRAPPED_REG(PMSDSFR_EL1) },
> +	{ SYS_DESC(SYS_PMBIDR_EL1), .access = undef_access },
>   
>   	{ PMU_SYS_REG(PMINTENSET_EL1),
>   	  .access = access_pminten, .reg = PMINTENSET_EL1,



From Sascha.Bischoff at arm.com  Tue Dec 16 03:54:59 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Tue, 16 Dec 2025 11:54:59 +0000
Subject: [PATCH 11/32] KVM: arm64: gic-v5: Trap and emulate
 ICH_PPI_HMRx_EL1 accesses
In-Reply-To: <86a4ziogjc.wl-maz@kernel.org>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	 <20251212152215.675767-12-sascha.bischoff@arm.com>
	 <86a4ziogjc.wl-maz@kernel.org>
Message-ID: <0f686dc9ea9e32fc37a1b11eb95b32cb958ff0a8.camel@arm.com>

On Tue, 2025-12-16 at 10:41 +0000, Marc Zyngier wrote:
> On Fri, 12 Dec 2025 15:22:39 +0000,
> Sascha Bischoff <Sascha.Bischoff at arm.com> wrote:
> > 
> > The ICC_PPI_HMRx_EL1 register is used to determine which PPIs use
> > Level-sensitive semantics, and which use Edge. For a GICv5 guest,
> > the
> > correct view of the virtual PPIs must be provided to the guest.
> 
> s/ICH/ICC/ in $SUBJECT
> 
> > 
> > The GICv5 architecture doesn't provide an ICV_PPI_HMRx_EL1 or
> 
> The spec disagree with you here (see 9.5.4).
> 
> > ICH_PPI_HMRx_EL2 register, and therefore all guest accesses must be
> > trapped to avoid the guest directly accessing the host's
> > ICC_PPI_HMRx_EL1 state. This change hence configures the FGTs to
> > always trap and emulate guest accesses to the HMR running a
> > GICv5-based guest.
> 
> The real question is what we gain by emulating this register, given
> that virtual PPIs are only guaranteed to exist if the physical
> version
> exist. If they exist, then the handling mode is defined by the
> that HW, and we can't deviate from it.
> 
> Given that, I can't really see the point in trapping something that
> is
> bound to be the same thing as the host, unless this comes with
> additional restrictions, for example a mask of interrupts that are
> actually exposed to the guest.
> 
> Or am I missing something?

No, I think you're quite correct, and this doesn't add meaningful
value.

This all stems from my misunderstanding that GICv5 vPPIs are
independent from the physical PPIs. This is not the case, however, as
the set of implemented virtual PPIs matches the physically implemented
PPIs. The handling mode for each PPI will be reflected in the
ICC/ICV_PPI_HMRx_EL1 sysregs.

This actually has wider impacts:

   1. It makes sense to drop this commit altogether.
   
   2. When initialising the GICv5 PPIs ("KVM: arm64: gic-v5: Init
   Private IRQs (PPIs) for GICv5"), we skip setting their config
   (LEVEL/EDGE).
   
   3. In vgic_v5_reset ("KVM: arm64: gic-v5: Reset vcpu state"), sync
   the host's PPI HMR state (ICC_PPI_HMRx_EL1) to KVM's vPPI shadow
   state as the virtual PPIs should match that, and we need that to
   correctly handle SW-driven PPI injection. Currently, this code
   actually calculates the HMR contents for trapping and emulating,
   which again can be dropped altogether.
   
   4. vgic_hmr can be dropped from the vgic_v5 CPUIF too.

Does this sound reasonable to you?

Thanks,
Sascha

> 
> > 
> > This change also introduces the struct vgic_v5_cpu_if, which
> > includes
> > the vgic_hmr. This is not yet populated as it can only be correctly
> > populated at vcpu reset time. This will be introduced in a
> > subsquent
> > change.
> > 
> > Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
> > ---
> > ?arch/arm64/kvm/config.c?? |? 6 +++++-
> > ?arch/arm64/kvm/sys_regs.c | 26 ++++++++++++++++++++++++++
> > ?include/kvm/arm_vgic.h??? |? 5 +++++
> > ?3 files changed, 36 insertions(+), 1 deletion(-)
> > 
> > diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
> > index cbdd8ac90f4d0..7683407ce052a 100644
> > --- a/arch/arm64/kvm/config.c
> > +++ b/arch/arm64/kvm/config.c
> > @@ -1586,8 +1586,12 @@ static void __compute_ich_hfgrtr(struct
> > kvm_vcpu *vcpu)
> > ?{
> > ?	__compute_fgt(vcpu, ICH_HFGRTR_EL2);
> > ?
> > -	/* ICC_IAFFIDR_EL1 *always* needs to be trapped when
> > running a guest */
> > +	/*
> > +	 * ICC_IAFFIDR_EL1 and ICH_PPI_HMRx_EL1 *always* needs to
> > be
> > +	 * trapped when running a guest.
> > +	 **/
> > ?	*vcpu_fgt(vcpu, ICH_HFGRTR_EL2) &=
> > ~ICH_HFGRTR_EL2_ICC_IAFFIDR_EL1;
> > +	*vcpu_fgt(vcpu, ICH_HFGRTR_EL2) &=
> > ~ICH_HFGRTR_EL2_ICC_PPI_HMRn_EL1;
> > ?}
> > ?
> > ?void kvm_vcpu_load_fgt(struct kvm_vcpu *vcpu)
> > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> > index 31c08fd591d08..a4ae034340040 100644
> > --- a/arch/arm64/kvm/sys_regs.c
> > +++ b/arch/arm64/kvm/sys_regs.c
> > @@ -699,6 +699,30 @@ static bool access_gicv5_iaffid(struct
> > kvm_vcpu *vcpu, struct sys_reg_params *p,
> > ?	return true;
> > ?}
> > ?
> > +static bool access_gicv5_ppi_hmr(struct kvm_vcpu *vcpu, struct
> > sys_reg_params *p,
> > +				 const struct sys_reg_desc *r)
> > +{
> > +	if (!vgic_is_v5(vcpu->kvm))
> > +		return undef_access(vcpu, p, r);
> > +
> > +	if (p->is_write)
> > +		return ignore_write(vcpu, p);
> > +
> > +	/*
> > +	 * For GICv5 VMs, the IAFFID value is the same as the VPE
> > ID. The VPE ID
> > +	 * is the same as the VCPU's ID.
> > +	 */
> 
> Unrelated comment?
> 
> > +
> > +	if (p->Op2 == 0) {	/* ICC_PPI_HMR0_EL1 */
> > +		p->regval = vcpu-
> > >arch.vgic_cpu.vgic_v5.vgic_ppi_hmr[0];
> > +	} else {		/* ICC_PPI_HMR1_EL1 */
> > +		p->regval = vcpu-
> > >arch.vgic_cpu.vgic_v5.vgic_ppi_hmr[1];
> > +	}
> 
> nit: Can probably be written as:
> 
> 	p->regval = vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_hmr[p-
> >Op2];
> 
> Thanks,
> 
> 	M.
> 


From yeoreum.yun at arm.com  Tue Dec 16 04:01:05 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Tue, 16 Dec 2025 12:01:05 +0000
Subject: [PATCH 2/2] arm64: mmu: use pagetable_alloc_nolock() while
 stop_machine()
In-Reply-To: <DEZLRT59S25H.2YWTZ2G0TN3HV@google.com>
References: <20251212161832.2067134-3-yeoreum.yun@arm.com>
 <CA+i-1C2e7QNTy5u=HF7tLsLXLq4xYbMTCbNjWGAxHz4uwgR05g@mail.gmail.com>
 <aT5/y3cSGIzi2K+m@e129823.arm.com>
 <DEYOI8H2OESD.1H56D3H8HKILB@google.com>
 <aT/WOAr4osoJWaMS@e129823.arm.com>
 <DEYP7JSVTB9D.3EFN2KEHH3O79@google.com>
 <aT/drjN1BkvyAGoi@e129823.arm.com>
 <DEZK5U2YP6I0.27VJHSVK14646@google.com>
 <aUE8bwUVa6jSUft1@e129823.arm.com>
 <DEZLRT59S25H.2YWTZ2G0TN3HV@google.com>
Message-ID: <aUFKAdPY3zTlPmnr@e129823.arm.com>

> On Tue Dec 16, 2025 at 11:03 AM UTC, Yeoreum Yun wrote:
> > Hi Brendan,
> >
> >> On Mon Dec 15, 2025 at 10:06 AM UTC, Yeoreum Yun wrote:
> >> [snip]
> >> >> Overall I am feeling a bit uncomfortable about this use of _nolock, but
> >> >> I am also feeling pretty ignorant about PREEMPT_RT and also about this
> >> >> arm64 code, so I am hesitant to suggest alternatives, I hope someone
> >> >> else can offer some input here...
> >> >
> >> > I understand. However, as I mentioned earlier,
> >> > my main intention was to hear opinions specifically about memory contention.
> >> >
> >> > That said, if there is no memory contention,
> >> > I don?t think using the _nolock API is necessarily a bad approach.
> >>
> >>
> >> > In fact, I believe a bigger issue is that, under PREEMPT_RT,
> >> > code that uses the regular memory allocation APIs may give users the false impression
> >> > that those APIs are ?safe to use,? even though they are not.
> >>
> >> Yeah, I share this concern. I would bet I have written code that's
> >> broken under PREEMPT_RT (luckily only in Google's kernel fork). The
> >> comment for GFP_ATOMIC says:
> >>
> >>  * %GFP_ATOMIC users can not sleep and need the allocation to succeed. A lower
> >>  * watermark is applied to allow access to "atomic reserves".
> >>  * The current implementation doesn't support NMI and few other strict
> >>  * non-preemptive contexts (e.g. raw_spin_lock). The same applies to %GFP_NOWAIT.
> >>
> >> It kinda sounds like it's supposed to be OK to use GFP_ATOMIC in a
> >> normal preempt_disable() context. So do you know exactly why it's
> >> invalid to use it in this stop_machine() context here? Maybe we need to
> >> update this comment.
> >
> > In non-PREEMPT_RT configurations, this is fine to use.
> > However, in PREEMPT_RT, it should not be used because
> > spin_lock becomes a sleepable lock backed by an rt-mutex.
> >
> > From Documentation/locking/locktypes.rst:
> >
> >   The fact that PREEMPT_RT changes the lock category of spinlock_t and
> >   rwlock_t from spinning to sleeping.
> >
> > As you know, all locks related to memory allocation
> > (e.g., zone_lock, PCP locks, etc.) use spin_lock,
> > which becomes sleepable under PREEMPT_RT.
> >
> > The callback of stop_machine() is executed in a preemption-disabled context
> > (see cpu_stopper_thread()). In this context, if it fails to acquire a spinlock
> > during memory allocation,
> > the task would be able to go to sleep while preemption is disabled,
> > which is an obviously problematic situation.
>
> But this is what I mean, doesn't this sound like the GFP_ATOMIC comment
> I quoted is wrong (or at least, it implies things which are wrong)? The
> comment refers specifically to raw_spin_lock() and "strict
> non-preemptive contexts". Which sounds like it is being written with
> PREEMPT_RT in mind. But that doesn't really match what you've said.

No. I think the comment of GFP_ATOMIC is right.
It definitely said:
  The current implementation *doesn't support* NMI and few other strict
  *non-preemptive contexts (e.g. raw_spin_lock)*.

The reason It couldn't be support GFP_ATOMIC in raw_spin_lock() context
in PREEMPT_RT since critical section protected by raw_spin_lock()
is non-preemptive (preemption disabled).

This is the same reason "GFP_ATOMIC" cannot be used in the
stop_machine().

--
Sincerely,
Yeoreum Yun


From konrad.dybcio at oss.qualcomm.com  Tue Dec 16 04:02:52 2025
From: konrad.dybcio at oss.qualcomm.com (Konrad Dybcio)
Date: Tue, 16 Dec 2025 13:02:52 +0100
Subject: [PATCH] dt-bindings: Remove unused includes
In-Reply-To: <20251213165949.4b51f7cb@jic23-huawei>
References: <20251212231203.727227-1-robh@kernel.org>
 <20251213165949.4b51f7cb@jic23-huawei>
Message-ID: <695ca5d2-b713-4838-8427-a9d31751c0cf@oss.qualcomm.com>

On 12/13/25 5:59 PM, Jonathan Cameron wrote:
> On Fri, 12 Dec 2025 17:11:52 -0600
> "Rob Herring (Arm)" <robh at kernel.org> wrote:
> 
>> Remove includes which are not referenced by either DTS files or drivers.
>>
>> There's a few more which are new, so they are excluded for now.
>>
>> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> 
> Acked-by: Jonathan Cameron <jonathan.cameron at huawei.com> #for-iio
> 
> Ideally we'll get a QC ack on those as well.
> 
> Jonathan
>>  .../dt-bindings/iio/qcom,spmi-adc7-pmr735b.h  |  30 --
>>  .../dt-bindings/iio/qcom,spmi-adc7-smb139x.h  |  19 --

Those are being moved to dts/qcom:

https://lore.kernel.org/linux-arm-msm/20251127133903.208760-1-jishnu.prakash at oss.qualcomm.com/

and will hopefully be in use later in this cycle.

Krzysztof and the submitter agreed on that outcome since they represent
hw constants and aren't "real" bindings (connecting sw to sw)

Konrad 


From leo.yan at arm.com  Tue Dec 16 04:04:52 2025
From: leo.yan at arm.com (Leo Yan)
Date: Tue, 16 Dec 2025 12:04:52 +0000
Subject: [PATCH] arm64: perf: fix syscalltbl path base
In-Reply-To: <67bafe7d-6761-4b1c-8742-628513e7e8bd@app.fastmail.com>
References: <b2651f20-6f3a-49f5-9cd8-3fb028b2cab5@app.fastmail.com>
 <fcefc3c0-541d-40cc-84e3-9c2460308bdb@linaro.org>
 <23c07ac4-ff13-47a5-824a-e7af1d1847a3@app.fastmail.com>
 <bda366b4-fa53-4feb-a7ce-ee47cfc404b5@linaro.org>
 <20251215112818.GB681384@e132581.arm.com>
 <0076b248-9b23-408d-9448-701df3c8d952@app.fastmail.com>
 <20251215164920.GD681384@e132581.arm.com>
 <67bafe7d-6761-4b1c-8742-628513e7e8bd@app.fastmail.com>
Message-ID: <20251216120452.GA912180@e132581.arm.com>

On Tue, Dec 16, 2025 at 08:17:51AM +0100, Arnd Bergmann wrote:

[...]

> I didn't find the reference to breaking, do you just mean it
> would break when falling back to a header provided by the
> toolchain's own asm/unistd.h, or a problem with the modern
> generated version that is solved by using the old asm-generic
> file?

Sorry for confusion.  I mean build breakage caused by using
toolchain's own asm/unistd.h.

> I would also point out that s390 no longer needs a custom script
> as of 6.19, since the last incompatibility between the s390 format
> and the x86 format of the tbl files got resolved with the removal
> of the s390 compat mode.

Thanks for the info.  I saw 4ac286c4a8d9 ("s390/syscalls: Switch to
generic system call table generation") for the s390 consolidation.

To be clear, Perf makefile now only uses
tools/perf/arch/*/entry/syscalls/syscall*.tbl to create syscall arrays
for tracing (e.g., print beauty string for syscall trace).

The dilemma is that the *.tbl files are in ./tools/perf, if we generate
unistd_64/32.h headers are not visible to other programs under ./tools.

> >> or we just stick with
> >> the old asm-generic/unistd.h copy and use that on arm64 as well.
> >
> > I will proceed this way for now.  From a maintenance view, it is a
> > pragmatic solution that only requires reverting a few patches and does
> > not introduce any new code.
> 
> Note that if we ever need to update the
> tools/include/uapi/asm-generic/unistd.h file for new syscalls,
> that will get harder in the future once we remove the
> kernel's own include/uapi/asm-generic/unistd.h. I'm sorry
> I never sent that fix after the previous cleanup that introduced
> the common script.

I agree this is a potential risk if we stick to static headers.

Thanks,
Leo


From jun.guo at cixtech.com  Tue Dec 16 04:30:23 2025
From: jun.guo at cixtech.com (Jun Guo)
Date: Tue, 16 Dec 2025 20:30:23 +0800
Subject: [PATCH v2 0/3] dmaengine: arm-dma350: add support for shared interrupt mode
Message-ID: <20251216123026.3519923-1-jun.guo@cixtech.com>

The arm dma350 controller's hardware implementation varies: some
designs dedicate a separate interrupt line for each channel, while
others have all channels sharing a single interrupt.This patch adds
support for the hardware design where all DMA channels share a
single interrupt.

This series introduces the following enhancements for arm dma350
controller support on arm64 platforms:

Patch 1: Add a compatible string "cix,sky1-dma-350" for the cix
sky1 SoC.
Patch 2: Implement support for the shared interrupt design of the DMA
controller.
Patch 3: add DT nodes for DMA.

The patches have been tested on CIX SKY1 platform, the test steps are
as follows:
    % echo 2000 > /sys/module/dmatest/parameters/timeout
    % echo 1 > /sys/module/dmatest/parameters/iterations
    % echo "" > /sys/module/dmatest/parameters/channel
    % echo 1 > /sys/module/dmatest/parameters/run

Changes for v2:
- Update to kernel standards, enhance patch description, and refactor
 driver to use match data for hardware differentiation instead of
 compatible strings.

Jun Guo (3):
  dt-bindings: dma: arm-dma350: update DT binding docs for cix sky1 SoC
  dma: arm-dma350: add support for shared interrupt mode
  arm64: dts: cix: add DT nodes for DMA

 .../devicetree/bindings/dma/arm,dma-350.yaml  |  31 +++--
 arch/arm64/boot/dts/cix/sky1.dtsi             |   7 +
 drivers/dma/arm-dma350.c                      | 124 ++++++++++++++++--
 3 files changed, 142 insertions(+), 20 deletions(-)

-- 
2.34.1



From jun.guo at cixtech.com  Tue Dec 16 04:30:26 2025
From: jun.guo at cixtech.com (Jun Guo)
Date: Tue, 16 Dec 2025 20:30:26 +0800
Subject: [PATCH v2 3/3] arm64: dts: cix: add DT nodes for DMA
In-Reply-To: <20251216123026.3519923-1-jun.guo@cixtech.com>
References: <20251216123026.3519923-1-jun.guo@cixtech.com>
Message-ID: <20251216123026.3519923-4-jun.guo@cixtech.com>

Add the device tree node for the dma controller of the CIX SKY1 SoC.

Signed-off-by: Jun Guo <jun.guo at cixtech.com>
---
 arch/arm64/boot/dts/cix/sky1.dtsi | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm64/boot/dts/cix/sky1.dtsi b/arch/arm64/boot/dts/cix/sky1.dtsi
index 189b9a3be55c..8bd7136e822d 100644
--- a/arch/arm64/boot/dts/cix/sky1.dtsi
+++ b/arch/arm64/boot/dts/cix/sky1.dtsi
@@ -353,6 +353,13 @@ iomuxc: pinctrl at 4170000 {
 			reg = <0x0 0x04170000 0x0 0x1000>;
 		};
 
+		fch_dmac: dma-controller at 4190000 {
+			compatible = "cix,sky1-dma-350", "arm,dma-350";
+			reg = <0x0 0x4190000 0x0 0x10000>;
+			interrupts = <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH 0>;
+			#dma-cells = <1>;
+		};
+
 		mbox_ap2se: mailbox at 5060000 {
 			compatible = "cix,sky1-mbox";
 			reg = <0x0 0x05060000 0x0 0x10000>;
-- 
2.34.1



From jun.guo at cixtech.com  Tue Dec 16 04:30:25 2025
From: jun.guo at cixtech.com (Jun Guo)
Date: Tue, 16 Dec 2025 20:30:25 +0800
Subject: [PATCH v2 2/3] dma: arm-dma350: add support for shared interrupt mode
In-Reply-To: <20251216123026.3519923-1-jun.guo@cixtech.com>
References: <20251216123026.3519923-1-jun.guo@cixtech.com>
Message-ID: <20251216123026.3519923-3-jun.guo@cixtech.com>

The arm dma350 controller's hardware implementation varies: some
designs dedicate a separate interrupt line for each channel, while
others have all channels sharing a single interrupt.This patch adds
support for the hardware design where all DMA channels share a
single interrupt.

Signed-off-by: Jun Guo <jun.guo at cixtech.com>
---
 drivers/dma/arm-dma350.c | 124 +++++++++++++++++++++++++++++++++++----
 1 file changed, 114 insertions(+), 10 deletions(-)

diff --git a/drivers/dma/arm-dma350.c b/drivers/dma/arm-dma350.c
index 9efe2ca7d5ec..6bea18521edd 100644
--- a/drivers/dma/arm-dma350.c
+++ b/drivers/dma/arm-dma350.c
@@ -14,6 +14,7 @@
 #include "virt-dma.h"
 
 #define DMAINFO			0x0f00
+#define DRIVER_NAME		"arm-dma350"
 
 #define DMA_BUILDCFG0		0xb0
 #define DMA_CFG_DATA_WIDTH	GENMASK(18, 16)
@@ -142,6 +143,9 @@
 #define LINK_LINKADDR		BIT(30)
 #define LINK_LINKADDRHI		BIT(31)
 
+/* DMA NONSECURE CONTROL REGISTER */
+#define DMANSECCTRL		0x20c
+#define INTREN_ANYCHINTR_EN	BIT(0)
 
 enum ch_ctrl_donetype {
 	CH_CTRL_DONETYPE_NONE = 0,
@@ -192,11 +196,16 @@ struct d350_chan {
 
 struct d350 {
 	struct dma_device dma;
+	void __iomem *base;
 	int nchan;
 	int nreq;
 	struct d350_chan channels[] __counted_by(nchan);
 };
 
+struct d350_driver_data {
+	bool combined_irq;
+};
+
 static inline struct d350_chan *to_d350_chan(struct dma_chan *chan)
 {
 	return container_of(chan, struct d350_chan, vc.chan);
@@ -461,7 +470,61 @@ static void d350_issue_pending(struct dma_chan *chan)
 	spin_unlock_irqrestore(&dch->vc.lock, flags);
 }
 
-static irqreturn_t d350_irq(int irq, void *data)
+static irqreturn_t d350_global_irq(int irq, void *data)
+{
+	struct d350 *dmac = (struct d350 *)data;
+	struct device *dev = dmac->dma.dev;
+	irqreturn_t ret = IRQ_NONE;
+	int i;
+
+	for (i = 0; i < dmac->nchan; i++) {
+		struct d350_chan *dch = &dmac->channels[i];
+		u32 ch_status;
+
+		ch_status = readl(dch->base + CH_STATUS);
+		if (!ch_status)
+			continue;
+
+		ret = IRQ_HANDLED;
+
+		if (ch_status & CH_STAT_INTR_ERR) {
+			struct virt_dma_desc *vd = &dch->desc->vd;
+			u32 errinfo = readl_relaxed(dch->base + CH_ERRINFO);
+
+			if (errinfo &
+			    (CH_ERRINFO_AXIRDPOISERR | CH_ERRINFO_AXIRDRESPERR))
+				vd->tx_result.result = DMA_TRANS_READ_FAILED;
+			else if (errinfo & CH_ERRINFO_AXIWRRESPERR)
+				vd->tx_result.result = DMA_TRANS_WRITE_FAILED;
+			else
+				vd->tx_result.result = DMA_TRANS_ABORTED;
+
+			vd->tx_result.residue = d350_get_residue(dch);
+		} else if (!(ch_status & CH_STAT_INTR_DONE)) {
+			dev_warn(dev, "Channel %d unexpected IRQ: 0x%08x\n", i,
+				 ch_status);
+		}
+
+		writel_relaxed(ch_status, dch->base + CH_STATUS);
+
+		spin_lock(&dch->vc.lock);
+		if (ch_status & CH_STAT_INTR_DONE) {
+			vchan_cookie_complete(&dch->desc->vd);
+			dch->status = DMA_COMPLETE;
+			dch->residue = 0;
+			d350_start_next(dch);
+		} else if (ch_status & CH_STAT_INTR_ERR) {
+			vchan_cookie_complete(&dch->desc->vd);
+			dch->status = DMA_ERROR;
+			dch->residue = dch->desc->vd.tx_result.residue;
+		}
+		spin_unlock(&dch->vc.lock);
+	}
+
+	return ret;
+}
+
+static irqreturn_t d350_channel_irq(int irq, void *data)
 {
 	struct d350_chan *dch = data;
 	struct device *dev = dch->vc.chan.device->dev;
@@ -506,10 +569,18 @@ static irqreturn_t d350_irq(int irq, void *data)
 static int d350_alloc_chan_resources(struct dma_chan *chan)
 {
 	struct d350_chan *dch = to_d350_chan(chan);
-	int ret = request_irq(dch->irq, d350_irq, IRQF_SHARED,
-			      dev_name(&dch->vc.chan.dev->device), dch);
-	if (!ret)
-		writel_relaxed(CH_INTREN_DONE | CH_INTREN_ERR, dch->base + CH_INTREN);
+	int ret = 0;
+
+	if (dch->irq) {
+		ret = request_irq(dch->irq, d350_channel_irq, IRQF_SHARED,
+				  dev_name(&dch->vc.chan.dev->device), dch);
+		if (ret) {
+			dev_err(chan->device->dev, "Failed to request IRQ %d\n", dch->irq);
+			return ret;
+		}
+	}
+
+	writel_relaxed(CH_INTREN_DONE | CH_INTREN_ERR, dch->base + CH_INTREN);
 
 	return ret;
 }
@@ -526,7 +597,8 @@ static void d350_free_chan_resources(struct dma_chan *chan)
 static int d350_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct d350 *dmac;
+	struct d350 *dmac = NULL;
+	const struct d350_driver_data *data;
 	void __iomem *base;
 	u32 reg;
 	int ret, nchan, dw, aw, r, p;
@@ -556,6 +628,7 @@ static int d350_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	dmac->nchan = nchan;
+	dmac->base = base;
 
 	reg = readl_relaxed(base + DMAINFO + DMA_BUILDCFG1);
 	dmac->nreq = FIELD_GET(DMA_CFG_NUM_TRIGGER_IN, reg);
@@ -582,6 +655,27 @@ static int d350_probe(struct platform_device *pdev)
 	dmac->dma.device_issue_pending = d350_issue_pending;
 	INIT_LIST_HEAD(&dmac->dma.channels);
 
+	data = device_get_match_data(dev);
+	/* Cix Sky1 has a common host IRQ for all its channels. */
+	if (data && data->combined_irq) {
+		int host_irq = platform_get_irq(pdev, 0);
+
+		if (host_irq < 0)
+			return dev_err_probe(dev, host_irq,
+					     "Failed to get IRQ\n");
+
+		ret = devm_request_irq(&pdev->dev, host_irq, d350_global_irq,
+				       IRQF_SHARED, DRIVER_NAME, dmac);
+		if (ret)
+			return dev_err_probe(
+				dev, ret,
+				"Failed to request the combined IRQ %d\n",
+				host_irq);
+	}
+
+	/* Combined Non-Secure Channel Interrupt Enable */
+	writel_relaxed(INTREN_ANYCHINTR_EN, dmac->base + DMANSECCTRL);
+
 	/* Would be nice to have per-channel caps for this... */
 	memset = true;
 	for (int i = 0; i < nchan; i++) {
@@ -595,10 +689,15 @@ static int d350_probe(struct platform_device *pdev)
 			dev_warn(dev, "No command link support on channel %d\n", i);
 			continue;
 		}
-		dch->irq = platform_get_irq(pdev, i);
-		if (dch->irq < 0)
-			return dev_err_probe(dev, dch->irq,
-					     "Failed to get IRQ for channel %d\n", i);
+
+		if (!data) {
+			dch->irq = platform_get_irq(pdev, i);
+			if (dch->irq < 0)
+				return dev_err_probe(
+					dev, dch->irq,
+					"Failed to get IRQ for channel %d\n",
+					i);
+		}
 
 		dch->has_wrap = FIELD_GET(CH_CFG_HAS_WRAP, reg);
 		dch->has_trig = FIELD_GET(CH_CFG_HAS_TRIGIN, reg) &
@@ -639,7 +738,12 @@ static void d350_remove(struct platform_device *pdev)
 	dma_async_device_unregister(&dmac->dma);
 }
 
+static const struct d350_driver_data sky1_dma350_data = {
+	.combined_irq = true,
+};
+
 static const struct of_device_id d350_of_match[] __maybe_unused = {
+	{ .compatible = "cix,sky1-dma-350", .data = &sky1_dma350_data },
 	{ .compatible = "arm,dma-350" },
 	{}
 };
-- 
2.34.1



From jun.guo at cixtech.com  Tue Dec 16 04:30:24 2025
From: jun.guo at cixtech.com (Jun Guo)
Date: Tue, 16 Dec 2025 20:30:24 +0800
Subject: [PATCH v2 1/3] dt-bindings: dma: arm-dma350: update DT binding docs for cix sky1 SoC
In-Reply-To: <20251216123026.3519923-1-jun.guo@cixtech.com>
References: <20251216123026.3519923-1-jun.guo@cixtech.com>
Message-ID: <20251216123026.3519923-2-jun.guo@cixtech.com>

Add SoC-specific compatible strings to the DT binding documents to support
cix sky1 SoC.

When adding support for a new SoC that uses the arm dma controller,
future contributors should be encouraged to actually add SoC-specific
compatible strings. The use of the "arm,dma-350" compatible string in
isolation should be disallowed.

Signed-off-by: Jun Guo <jun.guo at cixtech.com>
---
 .../devicetree/bindings/dma/arm,dma-350.yaml  | 31 +++++++++++++------
 1 file changed, 21 insertions(+), 10 deletions(-)

diff --git a/Documentation/devicetree/bindings/dma/arm,dma-350.yaml b/Documentation/devicetree/bindings/dma/arm,dma-350.yaml
index 429f682f15d8..78bcc7f9aa8b 100644
--- a/Documentation/devicetree/bindings/dma/arm,dma-350.yaml
+++ b/Documentation/devicetree/bindings/dma/arm,dma-350.yaml
@@ -14,7 +14,11 @@ allOf:
 
 properties:
   compatible:
-    const: arm,dma-350
+    oneOf:
+      - items:
+          - enum:
+              - cix,sky1-dma-350
+          - const: arm,dma-350
 
   reg:
     items:
@@ -22,15 +26,22 @@ properties:
 
   interrupts:
     minItems: 1
-    items:
-      - description: Channel 0 interrupt
-      - description: Channel 1 interrupt
-      - description: Channel 2 interrupt
-      - description: Channel 3 interrupt
-      - description: Channel 4 interrupt
-      - description: Channel 5 interrupt
-      - description: Channel 6 interrupt
-      - description: Channel 7 interrupt
+    maxItems: 8
+    description: |
+      The DMA controller may be configured with separate interrupts for each channel,
+      or with a single combined interrupt for all channels, depending on the SoC integration.
+    oneOf:
+      - items:
+          - description: Channel 0 interrupt
+          - description: Channel 1 interrupt
+          - description: Channel 2 interrupt
+          - description: Channel 3 interrupt
+          - description: Channel 4 interrupt
+          - description: Channel 5 interrupt
+          - description: Channel 6 interrupt
+          - description: Channel 7 interrupt
+      - items:
+          - description: Combined interrupt shared by all channels
 
   "#dma-cells":
     const: 1
-- 
2.34.1



From sven at kernel.org  Tue Dec 16 04:37:12 2025
From: sven at kernel.org (Sven Peter)
Date: Tue, 16 Dec 2025 13:37:12 +0100
Subject: (subset) [PATCH v6 0/7] mfd: macsmc: add rtc, hwmon and hid subdevices
In-Reply-To: <20251215-macsmc-subdevs-v6-0-0518cb5f28ae@gmail.com>
References: <20251215-macsmc-subdevs-v6-0-0518cb5f28ae@gmail.com>
Message-ID: <176588840252.31586.16326303552542183142.b4-ty@kernel.org>

On Mon, 15 Dec 2025 19:37:44 +1000, James Calligeros wrote:
> This series adds support for the remaining SMC subdevices. These are the
> RTC, hwmon, and HID devices. They are being submitted together as the RTC
> and hwmon drivers both require changes to the SMC DT schema.
> 
> The RTC driver is responsible for getting and setting the system clock,
> and requires an NVMEM cell. This series replaces Sven's original RTC driver
> submission [1].
> 
> [...]

Applied to local tree (apple-soc/dt-6.20), thanks!

[6/7] arm64: dts: apple: t8103,t60xx,t8112: Add SMC RTC node
      https://github.com/AsahiLinux/linux/commit/faf317d4c705

Best regards,
-- 
Sven Peter <sven at kernel.org>



From jackmanb at google.com  Tue Dec 16 04:39:22 2025
From: jackmanb at google.com (Brendan Jackman)
Date: Tue, 16 Dec 2025 12:39:22 +0000
Subject: [PATCH 2/2] arm64: mmu: use pagetable_alloc_nolock() while stop_machine()
In-Reply-To: <aUFKAdPY3zTlPmnr@e129823.arm.com>
References: <20251212161832.2067134-3-yeoreum.yun@arm.com> <CA+i-1C2e7QNTy5u=HF7tLsLXLq4xYbMTCbNjWGAxHz4uwgR05g@mail.gmail.com>
 <aT5/y3cSGIzi2K+m@e129823.arm.com> <DEYOI8H2OESD.1H56D3H8HKILB@google.com>
 <aT/WOAr4osoJWaMS@e129823.arm.com> <DEYP7JSVTB9D.3EFN2KEHH3O79@google.com>
 <aT/drjN1BkvyAGoi@e129823.arm.com> <DEZK5U2YP6I0.27VJHSVK14646@google.com>
 <aUE8bwUVa6jSUft1@e129823.arm.com> <DEZLRT59S25H.2YWTZ2G0TN3HV@google.com> <aUFKAdPY3zTlPmnr@e129823.arm.com>
Message-ID: <DEZNBMBRM5M2.1974FFAQ13G5E@google.com>

On Tue Dec 16, 2025 at 12:01 PM UTC, Yeoreum Yun wrote:
>> On Tue Dec 16, 2025 at 11:03 AM UTC, Yeoreum Yun wrote:
>> > Hi Brendan,
>> >
>> >> On Mon Dec 15, 2025 at 10:06 AM UTC, Yeoreum Yun wrote:
>> >> [snip]
>> >> >> Overall I am feeling a bit uncomfortable about this use of _nolock, but
>> >> >> I am also feeling pretty ignorant about PREEMPT_RT and also about this
>> >> >> arm64 code, so I am hesitant to suggest alternatives, I hope someone
>> >> >> else can offer some input here...
>> >> >
>> >> > I understand. However, as I mentioned earlier,
>> >> > my main intention was to hear opinions specifically about memory contention.
>> >> >
>> >> > That said, if there is no memory contention,
>> >> > I don?t think using the _nolock API is necessarily a bad approach.
>> >>
>> >>
>> >> > In fact, I believe a bigger issue is that, under PREEMPT_RT,
>> >> > code that uses the regular memory allocation APIs may give users the false impression
>> >> > that those APIs are ?safe to use,? even though they are not.
>> >>
>> >> Yeah, I share this concern. I would bet I have written code that's
>> >> broken under PREEMPT_RT (luckily only in Google's kernel fork). The
>> >> comment for GFP_ATOMIC says:
>> >>
>> >>  * %GFP_ATOMIC users can not sleep and need the allocation to succeed. A lower
>> >>  * watermark is applied to allow access to "atomic reserves".
>> >>  * The current implementation doesn't support NMI and few other strict
>> >>  * non-preemptive contexts (e.g. raw_spin_lock). The same applies to %GFP_NOWAIT.
>> >>
>> >> It kinda sounds like it's supposed to be OK to use GFP_ATOMIC in a
>> >> normal preempt_disable() context. So do you know exactly why it's
>> >> invalid to use it in this stop_machine() context here? Maybe we need to
>> >> update this comment.
>> >
>> > In non-PREEMPT_RT configurations, this is fine to use.
>> > However, in PREEMPT_RT, it should not be used because
>> > spin_lock becomes a sleepable lock backed by an rt-mutex.
>> >
>> > From Documentation/locking/locktypes.rst:
>> >
>> >   The fact that PREEMPT_RT changes the lock category of spinlock_t and
>> >   rwlock_t from spinning to sleeping.
>> >
>> > As you know, all locks related to memory allocation
>> > (e.g., zone_lock, PCP locks, etc.) use spin_lock,
>> > which becomes sleepable under PREEMPT_RT.
>> >
>> > The callback of stop_machine() is executed in a preemption-disabled context
>> > (see cpu_stopper_thread()). In this context, if it fails to acquire a spinlock
>> > during memory allocation,
>> > the task would be able to go to sleep while preemption is disabled,
>> > which is an obviously problematic situation.
>>
>> But this is what I mean, doesn't this sound like the GFP_ATOMIC comment
>> I quoted is wrong (or at least, it implies things which are wrong)? The
>> comment refers specifically to raw_spin_lock() and "strict
>> non-preemptive contexts". Which sounds like it is being written with
>> PREEMPT_RT in mind. But that doesn't really match what you've said.
>
> No. I think the comment of GFP_ATOMIC is right.
> It definitely said:
>   The current implementation *doesn't support* NMI and few other strict
>   *non-preemptive contexts (e.g. raw_spin_lock)*.

But this phrasing sounds like there are other non-preemptive contexts
that it _does_ support. I would definitely read this as implying that
plain old preempt_disable() is OK. I don't understand what those "few
other strict contexts" are, nor why the stop_machine() context is
included in them.



From robin.murphy at arm.com  Tue Dec 16 04:43:07 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Tue, 16 Dec 2025 12:43:07 +0000
Subject: [PATCH v2 1/3] dt-bindings: dma: arm-dma350: update DT binding
 docs for cix sky1 SoC
In-Reply-To: <20251216123026.3519923-2-jun.guo@cixtech.com>
References: <20251216123026.3519923-1-jun.guo@cixtech.com>
 <20251216123026.3519923-2-jun.guo@cixtech.com>
Message-ID: <9d4c274f-3e4c-49a1-9b2a-a95e9a48a4a6@arm.com>

On 2025-12-16 12:30 pm, Jun Guo wrote:
> Add SoC-specific compatible strings to the DT binding documents to support
> cix sky1 SoC.
> 
> When adding support for a new SoC that uses the arm dma controller,
> future contributors should be encouraged to actually add SoC-specific
> compatible strings. The use of the "arm,dma-350" compatible string in
> isolation should be disallowed.

No, you've missed the point - however many channels the hardware 
implements, the DT should list that many interrupt specifiers; it 
doesn't matter whether any of them happen to be the same.

Thanks,
Robin.

> Signed-off-by: Jun Guo <jun.guo at cixtech.com>
> ---
>   .../devicetree/bindings/dma/arm,dma-350.yaml  | 31 +++++++++++++------
>   1 file changed, 21 insertions(+), 10 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/dma/arm,dma-350.yaml b/Documentation/devicetree/bindings/dma/arm,dma-350.yaml
> index 429f682f15d8..78bcc7f9aa8b 100644
> --- a/Documentation/devicetree/bindings/dma/arm,dma-350.yaml
> +++ b/Documentation/devicetree/bindings/dma/arm,dma-350.yaml
> @@ -14,7 +14,11 @@ allOf:
>   
>   properties:
>     compatible:
> -    const: arm,dma-350
> +    oneOf:
> +      - items:
> +          - enum:
> +              - cix,sky1-dma-350
> +          - const: arm,dma-350
>   
>     reg:
>       items:
> @@ -22,15 +26,22 @@ properties:
>   
>     interrupts:
>       minItems: 1
> -    items:
> -      - description: Channel 0 interrupt
> -      - description: Channel 1 interrupt
> -      - description: Channel 2 interrupt
> -      - description: Channel 3 interrupt
> -      - description: Channel 4 interrupt
> -      - description: Channel 5 interrupt
> -      - description: Channel 6 interrupt
> -      - description: Channel 7 interrupt
> +    maxItems: 8
> +    description: |
> +      The DMA controller may be configured with separate interrupts for each channel,
> +      or with a single combined interrupt for all channels, depending on the SoC integration.
> +    oneOf:
> +      - items:
> +          - description: Channel 0 interrupt
> +          - description: Channel 1 interrupt
> +          - description: Channel 2 interrupt
> +          - description: Channel 3 interrupt
> +          - description: Channel 4 interrupt
> +          - description: Channel 5 interrupt
> +          - description: Channel 6 interrupt
> +          - description: Channel 7 interrupt
> +      - items:
> +          - description: Combined interrupt shared by all channels
>   
>     "#dma-cells":
>       const: 1



From vkoul at kernel.org  Tue Dec 16 04:45:19 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 16 Dec 2025 18:15:19 +0530
Subject: [PATCH 0/8] dmaengine: Add new API to combine onfiguration and
 descriptor preparation
In-Reply-To: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
References: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
Message-ID: <aUFUX0e_h7RGAecz@vaman>

On 08-12-25, 12:09, Frank Li wrote:

Spell check on subject please :-)

> Previously, configuration and preparation required two separate calls. This
> works well when configuration is done only once during initialization.
> 
> However, in cases where the burst length or source/destination address must
> be adjusted for each transfer, calling two functions is verbose.
> 
> 	if (dmaengine_slave_config(chan, &sconf)) {
> 		dev_err(dev, "DMA slave config fail\n");
> 		return -EIO;
> 	}
> 
> 	tx = dmaengine_prep_slave_single(chan, dma_local, len, dir, flags);
> 
> After new API added
> 
> 	tx = dmaengine_prep_slave_single(chan, dma_local, len, dir, flags, &sconf);

Nak, we cant change the API like this.
I agree that you can add a new way to call dmaengine_slave_config() and
dmaengine_prep_slave_single() together.
maybe dmaengine_prep_config_perip_single() (yes we can go away with slave, but
cant drop it, as absence means something else entire).

I would like to retain the dmaengine_prep_slave_single() as an API for
users to call and invoke. There are users who configure channel once as
well

> 
> Additional, prevous two calls requires additional locking to ensure both
> steps complete atomically.
> 
>     mutex_lock()
>     dmaengine_slave_config()
>     dmaengine_prep_slave_single()
>     mutex_unlock()
> 
> after new API added, mutex lock can be moved. See patch
>      nvmet: pci-epf: Use dmaengine_prep_slave_single_config() API
> 
> Signed-off-by: Frank Li <Frank.Li at nxp.com>
> ---
> Frank Li (8):
>       dmaengine: Add API to combine configuration and preparation (sg and single)
>       PCI: endpoint: pci-epf-test: use new DMA API to simple code
>       dmaengine: dw-edma: Use new .device_prep_slave_sg_config() callback
>       dmaengine: dw-edma: Pass dma_slave_config to dw_edma_device_transfer()
>       nvmet: pci-epf: Remove unnecessary dmaengine_terminate_sync() on each DMA transfer
>       nvmet: pci-epf: Use dmaengine_prep_slave_single_config() API
>       PCI: epf-mhi:Using new API dmaengine_prep_slave_single_config() to simple code.
>       crypto: atmel: Use dmaengine_prep_slave_single_config() API
> 
>  drivers/crypto/atmel-aes.c                    | 10 ++---
>  drivers/dma/dw-edma/dw-edma-core.c            | 38 +++++++++++-----
>  drivers/nvme/target/pci-epf.c                 | 21 +++------
>  drivers/pci/endpoint/functions/pci-epf-mhi.c  | 52 +++++++---------------
>  drivers/pci/endpoint/functions/pci-epf-test.c |  8 +---
>  include/linux/dmaengine.h                     | 64 ++++++++++++++++++++++++---
>  6 files changed, 111 insertions(+), 82 deletions(-)
> ---
> base-commit: bc04acf4aeca588496124a6cf54bfce3db327039
> change-id: 20251204-dma_prep_config-654170d245a2
> 
> Best regards,
> --
> Frank Li <Frank.Li at nxp.com>

-- 
~Vinod


From robin.murphy at arm.com  Tue Dec 16 04:51:02 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Tue, 16 Dec 2025 12:51:02 +0000
Subject: [PATCH v2 2/3] dma: arm-dma350: add support for shared interrupt
 mode
In-Reply-To: <20251216123026.3519923-3-jun.guo@cixtech.com>
References: <20251216123026.3519923-1-jun.guo@cixtech.com>
 <20251216123026.3519923-3-jun.guo@cixtech.com>
Message-ID: <910e3db2-c4ef-4c21-9336-49469234b8e6@arm.com>

On 2025-12-16 12:30 pm, Jun Guo wrote:
> The arm dma350 controller's hardware implementation varies: some
> designs dedicate a separate interrupt line for each channel, while
> others have all channels sharing a single interrupt.This patch adds
> support for the hardware design where all DMA channels share a
> single interrupt.
> 
> Signed-off-by: Jun Guo <jun.guo at cixtech.com>
> ---
>   drivers/dma/arm-dma350.c | 124 +++++++++++++++++++++++++++++++++++----
>   1 file changed, 114 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/dma/arm-dma350.c b/drivers/dma/arm-dma350.c
> index 9efe2ca7d5ec..6bea18521edd 100644
> --- a/drivers/dma/arm-dma350.c
> +++ b/drivers/dma/arm-dma350.c
> @@ -14,6 +14,7 @@
>   #include "virt-dma.h"
>   
>   #define DMAINFO			0x0f00
> +#define DRIVER_NAME		"arm-dma350"
>   
>   #define DMA_BUILDCFG0		0xb0
>   #define DMA_CFG_DATA_WIDTH	GENMASK(18, 16)
> @@ -142,6 +143,9 @@
>   #define LINK_LINKADDR		BIT(30)
>   #define LINK_LINKADDRHI		BIT(31)
>   
> +/* DMA NONSECURE CONTROL REGISTER */
> +#define DMANSECCTRL		0x20c
> +#define INTREN_ANYCHINTR_EN	BIT(0)
>   
>   enum ch_ctrl_donetype {
>   	CH_CTRL_DONETYPE_NONE = 0,
> @@ -192,11 +196,16 @@ struct d350_chan {
>   
>   struct d350 {
>   	struct dma_device dma;
> +	void __iomem *base;
>   	int nchan;
>   	int nreq;
>   	struct d350_chan channels[] __counted_by(nchan);
>   };
>   
> +struct d350_driver_data {
> +	bool combined_irq;
> +};
> +
>   static inline struct d350_chan *to_d350_chan(struct dma_chan *chan)
>   {
>   	return container_of(chan, struct d350_chan, vc.chan);
> @@ -461,7 +470,61 @@ static void d350_issue_pending(struct dma_chan *chan)
>   	spin_unlock_irqrestore(&dch->vc.lock, flags);
>   }
>   
> -static irqreturn_t d350_irq(int irq, void *data)
> +static irqreturn_t d350_global_irq(int irq, void *data)
> +{
> +	struct d350 *dmac = (struct d350 *)data;
> +	struct device *dev = dmac->dma.dev;
> +	irqreturn_t ret = IRQ_NONE;
> +	int i;
> +
> +	for (i = 0; i < dmac->nchan; i++) {
> +		struct d350_chan *dch = &dmac->channels[i];
> +		u32 ch_status;
> +
> +		ch_status = readl(dch->base + CH_STATUS);
> +		if (!ch_status)
> +			continue;
> +
> +		ret = IRQ_HANDLED;
> +
> +		if (ch_status & CH_STAT_INTR_ERR) {
> +			struct virt_dma_desc *vd = &dch->desc->vd;
> +			u32 errinfo = readl_relaxed(dch->base + CH_ERRINFO);
> +
> +			if (errinfo &
> +			    (CH_ERRINFO_AXIRDPOISERR | CH_ERRINFO_AXIRDRESPERR))
> +				vd->tx_result.result = DMA_TRANS_READ_FAILED;
> +			else if (errinfo & CH_ERRINFO_AXIWRRESPERR)
> +				vd->tx_result.result = DMA_TRANS_WRITE_FAILED;
> +			else
> +				vd->tx_result.result = DMA_TRANS_ABORTED;
> +
> +			vd->tx_result.residue = d350_get_residue(dch);
> +		} else if (!(ch_status & CH_STAT_INTR_DONE)) {
> +			dev_warn(dev, "Channel %d unexpected IRQ: 0x%08x\n", i,
> +				 ch_status);
> +		}
> +
> +		writel_relaxed(ch_status, dch->base + CH_STATUS);
> +
> +		spin_lock(&dch->vc.lock);
> +		if (ch_status & CH_STAT_INTR_DONE) {
> +			vchan_cookie_complete(&dch->desc->vd);
> +			dch->status = DMA_COMPLETE;
> +			dch->residue = 0;
> +			d350_start_next(dch);
> +		} else if (ch_status & CH_STAT_INTR_ERR) {
> +			vchan_cookie_complete(&dch->desc->vd);
> +			dch->status = DMA_ERROR;
> +			dch->residue = dch->desc->vd.tx_result.residue;
> +		}
> +		spin_unlock(&dch->vc.lock);
> +	}
> +
> +	return ret;
> +}
> +
> +static irqreturn_t d350_channel_irq(int irq, void *data)
>   {
>   	struct d350_chan *dch = data;
>   	struct device *dev = dch->vc.chan.device->dev;
> @@ -506,10 +569,18 @@ static irqreturn_t d350_irq(int irq, void *data)
>   static int d350_alloc_chan_resources(struct dma_chan *chan)
>   {
>   	struct d350_chan *dch = to_d350_chan(chan);
> -	int ret = request_irq(dch->irq, d350_irq, IRQF_SHARED,
> -			      dev_name(&dch->vc.chan.dev->device), dch);
> -	if (!ret)
> -		writel_relaxed(CH_INTREN_DONE | CH_INTREN_ERR, dch->base + CH_INTREN);
> +	int ret = 0;
> +
> +	if (dch->irq) {
> +		ret = request_irq(dch->irq, d350_channel_irq, IRQF_SHARED,
> +				  dev_name(&dch->vc.chan.dev->device), dch);
> +		if (ret) {
> +			dev_err(chan->device->dev, "Failed to request IRQ %d\n", dch->irq);
> +			return ret;
> +		}
> +	}
> +
> +	writel_relaxed(CH_INTREN_DONE | CH_INTREN_ERR, dch->base + CH_INTREN);
>   
>   	return ret;
>   }
> @@ -526,7 +597,8 @@ static void d350_free_chan_resources(struct dma_chan *chan)
>   static int d350_probe(struct platform_device *pdev)
>   {
>   	struct device *dev = &pdev->dev;
> -	struct d350 *dmac;
> +	struct d350 *dmac = NULL;
> +	const struct d350_driver_data *data;
>   	void __iomem *base;
>   	u32 reg;
>   	int ret, nchan, dw, aw, r, p;
> @@ -556,6 +628,7 @@ static int d350_probe(struct platform_device *pdev)
>   		return -ENOMEM;
>   
>   	dmac->nchan = nchan;
> +	dmac->base = base;
>   
>   	reg = readl_relaxed(base + DMAINFO + DMA_BUILDCFG1);
>   	dmac->nreq = FIELD_GET(DMA_CFG_NUM_TRIGGER_IN, reg);
> @@ -582,6 +655,27 @@ static int d350_probe(struct platform_device *pdev)
>   	dmac->dma.device_issue_pending = d350_issue_pending;
>   	INIT_LIST_HEAD(&dmac->dma.channels);
>   
> +	data = device_get_match_data(dev);
> +	/* Cix Sky1 has a common host IRQ for all its channels. */
> +	if (data && data->combined_irq) {
> +		int host_irq = platform_get_irq(pdev, 0);
> +
> +		if (host_irq < 0)
> +			return dev_err_probe(dev, host_irq,
> +					     "Failed to get IRQ\n");
> +
> +		ret = devm_request_irq(&pdev->dev, host_irq, d350_global_irq,
> +				       IRQF_SHARED, DRIVER_NAME, dmac);
> +		if (ret)
> +			return dev_err_probe(
> +				dev, ret,
> +				"Failed to request the combined IRQ %d\n",
> +				host_irq);
> +	}
> +
> +	/* Combined Non-Secure Channel Interrupt Enable */
> +	writel_relaxed(INTREN_ANYCHINTR_EN, dmac->base + DMANSECCTRL);

This one line is all that should be needed - all the rest is pointless 
overcomplication and churn. And either way, copy-pasting the entire IRQ 
handler is not OK.

Thanks,
Robin.

> +
>   	/* Would be nice to have per-channel caps for this... */
>   	memset = true;
>   	for (int i = 0; i < nchan; i++) {
> @@ -595,10 +689,15 @@ static int d350_probe(struct platform_device *pdev)
>   			dev_warn(dev, "No command link support on channel %d\n", i);
>   			continue;
>   		}
> -		dch->irq = platform_get_irq(pdev, i);
> -		if (dch->irq < 0)
> -			return dev_err_probe(dev, dch->irq,
> -					     "Failed to get IRQ for channel %d\n", i);
> +
> +		if (!data) {
> +			dch->irq = platform_get_irq(pdev, i);
> +			if (dch->irq < 0)
> +				return dev_err_probe(
> +					dev, dch->irq,
> +					"Failed to get IRQ for channel %d\n",
> +					i);
> +		}
>   
>   		dch->has_wrap = FIELD_GET(CH_CFG_HAS_WRAP, reg);
>   		dch->has_trig = FIELD_GET(CH_CFG_HAS_TRIGIN, reg) &
> @@ -639,7 +738,12 @@ static void d350_remove(struct platform_device *pdev)
>   	dma_async_device_unregister(&dmac->dma);
>   }
>   
> +static const struct d350_driver_data sky1_dma350_data = {
> +	.combined_irq = true,
> +};
> +
>   static const struct of_device_id d350_of_match[] __maybe_unused = {
> +	{ .compatible = "cix,sky1-dma-350", .data = &sky1_dma350_data },
>   	{ .compatible = "arm,dma-350" },
>   	{}
>   };



From svarbanov at suse.de  Tue Dec 16 05:00:42 2025
From: svarbanov at suse.de (Stanimir Varbanov)
Date: Tue, 16 Dec 2025 15:00:42 +0200
Subject: [PATCH v3 4/4] arm64: dts: broadcom: bcm2712: Add watchdog DT
 node
In-Reply-To: <20251105165553.3910996-1-florian.fainelli@broadcom.com>
References: <20251031183309.1163384-1-svarbanov@suse.de>
 <20251031183309.1163384-5-svarbanov@suse.de>
 <20251105165553.3910996-1-florian.fainelli@broadcom.com>
Message-ID: <189702e0-e6f0-44c5-bed6-eef058d90b76@suse.de>

Hi Florian,

On 11/5/25 6:55 PM, Florian Fainelli wrote:
> From: Florian Fainelli <f.fainelli at gmail.com>
> 
> On Fri, 31 Oct 2025 20:33:09 +0200, Stanimir Varbanov <svarbanov at suse.de> wrote:
>> Add watchdog device-tree node for bcm2712 SoC.
>>
>> Signed-off-by: Stanimir Varbanov <svarbanov at suse.de>
>> ---
> 
> Applied to https://github.com/Broadcom/stblinux/commits/devicetree-arm64/next, thanks!

For some reason this is not part of v6.19-rc1.

~Stan


From vkoul at kernel.org  Tue Dec 16 05:11:44 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 16 Dec 2025 18:41:44 +0530
Subject: [PATCH v4 0/13] dmaengine: introduce sg_nents_for_dma() and
 convert users
In-Reply-To: <20251124121202.424072-1-andriy.shevchenko@linux.intel.com>
References: <20251124121202.424072-1-andriy.shevchenko@linux.intel.com>
Message-ID: <aUFakHZL8viMN3WR@vaman>

On 24-11-25, 13:09, Andy Shevchenko wrote:
> A handful of the DMAengine drivers use same routine to calculate the number of
> SG entries needed for the given DMA transfer. Provide a common helper for them
> and convert.
> 
> I left the new helper on SG level of API because brief grepping shows potential
> candidates outside of DMA engine, e.g.:
> 
>   drivers/crypto/chelsio/chcr_algo.c:154:  nents += DIV_ROUND_UP(less, entlen);
>   drivers/spi/spi-stm32.c:1495:  /* Count the number of entries needed */
> 
> Changelog v4:
> - fixed compilation errors (Vinod)

:-(

drivers/dma/altera-msgdma.c: In function ?msgdma_prep_slave_sg?:
drivers/dma/altera-msgdma.c:399:29: error: unused variable ?sg? [-Werror=unused-variable]

Clearly your script is not working. I am surprised that you are not able
to compile these changes. Bit disappointed tbh!

-- 
~Vinod


From robh at kernel.org  Tue Dec 16 05:11:51 2025
From: robh at kernel.org (Rob Herring)
Date: Tue, 16 Dec 2025 07:11:51 -0600
Subject: [PATCH v3 0/3] Add support for exynos5250-manta (Google Nexus
 10)
In-Reply-To: <20251215-lat3st-staging-v3-0-2e4914b64dd8@timmermann.space>
References: <20251215-lat3st-staging-v3-0-2e4914b64dd8@timmermann.space>
Message-ID: <176589052399.1815190.7793235081822033570.robh@kernel.org>


On Mon, 15 Dec 2025 16:05:21 +0100, Lukas Timmermann wrote:
> This patch series adds initial support for the google-manta board, known
> as Google Nexus 10 to users. The device is powered by
> the Exynos 5250 SoC. The bindings for the notification led are already
> in the kernel mailing list, got recently applied and can be found here:
> https://lore.kernel.org/linux-leds/20251125114015.355487-1-linux at timmermann.space/
> 
> The first two patches add the necessary device tree files and
> bindings, while the last patch makes a small modification to
> allow CPU1 to boot, as it requires a call to it's underlying firmware.
> 
> This first iteration only provides basic support to get the board
> up and running and usable via UART and with WiFi support. We will upstream additional
> features in future patches. All patches have been tested on real hardware.
> 
> Changes in v3:
>  - Added a better patch description for firmware patch. (@krzk)
>  - Reorganized nodes in DT. (@krzk)
>  - Fixed memory node to use separate entries. (@krzk)
>  - Renamed pwrseq node. (@krzk)
>  - Fixed firmware checking for old dt compatible string. (@pavel)
>  - Link to v2: https://lore.kernel.org/all/20251125-google-manta-v2-0-0f097cfff39c at timmermann.space/
> Changes in v2:
>  - Renamed to google-manta (@krzk)
>  - Link to v1: https://lore.kernel.org/all/20251120144018.961604-2-linux at timmermann.space/
> 
> Signed-off-by: Lukas Timmermann <linux at timmermann.space>
> ---
> Alexandre Marquet (3):
>       dt-bindings: ARM: samsung: Add Google Manta (Nexus 10)
>       ARM: dts: exynos: Add Google Manta (Nexus 10)
>       ARM: samsung: exynos5250: Allow CPU1 to boot
> 
>  .../bindings/arm/samsung/samsung-boards.yaml       |   1 +
>  arch/arm/boot/dts/samsung/Makefile                 |   1 +
>  arch/arm/boot/dts/samsung/exynos5250-manta.dts     | 511 +++++++++++++++++++++
>  arch/arm/mach-exynos/firmware.c                    |   4 +-
>  4 files changed, 515 insertions(+), 2 deletions(-)
> ---
> base-commit: d5f0e9098499869354aacb5b080f602f0399d396
> change-id: 20251215-lat3st-staging-d9c926d8a75f
> 
> Best regards,
> --
> Lukas Timmermann <linux at timmermann.space>
> 
> 
> 


My bot found new DTB warnings on the .dts files added or changed in this
series.

Some warnings may be from an existing SoC .dtsi. Or perhaps the warnings
are fixed by another series. Ultimately, it is up to the platform
maintainer whether these warnings are acceptable or not. No need to reply
unless the platform maintainer has comments.

If you already ran DT checks and didn't see these error(s), then
make sure dt-schema is up to date:

  pip3 install dtschema --upgrade


This patch series was applied (using b4) to base:
 Base: base-commit d5f0e9098499869354aacb5b080f602f0399d396 not known, ignoring
 Base: attempting to guess base-commit...
 Base: tags/next-20251215 (exact match)
 Base: tags/next-20251215 (use --merge-base to override)

If this is not the correct base, please add 'base-commit' tag
(or use b4 which does this automatically)

New warnings running 'make CHECK_DTBS=y for arch/arm/boot/dts/samsung/' for 20251215-lat3st-staging-v3-0-2e4914b64dd8 at timmermann.space:

arch/arm/boot/dts/samsung/exynos5250-manta.dtb: /soc/i2c at 12c70000/led-controller at 42: failed to match any schema with compatible: ['ams,as3668']
arch/arm/boot/dts/samsung/exynos5250-manta.dtb: rtc at 101e0000 (samsung,s3c6410-rtc): clock-names: ['rtc'] is too short
	from schema $id: http://devicetree.org/schemas/rtc/s3c-rtc.yaml
arch/arm/boot/dts/samsung/exynos5250-manta.dtb: rtc at 101e0000 (samsung,s3c6410-rtc): clocks: [[2, 337]] is too short
	from schema $id: http://devicetree.org/schemas/rtc/s3c-rtc.yaml







From alexander.stein at ew.tq-group.com  Tue Dec 16 05:15:28 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Tue, 16 Dec 2025 14:15:28 +0100
Subject: [PATCH 1/1] arm64: dts: mba8mx: Fix Ethernet PHY IRQ support
Message-ID: <20251216131529.886546-1-alexander.stein@ew.tq-group.com>

Ethernet PHY interrupt mode is level triggered. Adjust the mode
accordingly.

Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 arch/arm64/boot/dts/freescale/mba8mx.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/freescale/mba8mx.dtsi b/arch/arm64/boot/dts/freescale/mba8mx.dtsi
index 225cd2f1220bf..10d5c211b1c9b 100644
--- a/arch/arm64/boot/dts/freescale/mba8mx.dtsi
+++ b/arch/arm64/boot/dts/freescale/mba8mx.dtsi
@@ -192,7 +192,7 @@ ethphy0: ethernet-phy at e {
 			reset-assert-us = <500000>;
 			reset-deassert-us = <500>;
 			interrupt-parent = <&expander2>;
-			interrupts = <6 IRQ_TYPE_EDGE_FALLING>;
+			interrupts = <6 IRQ_TYPE_LEVEL_LOW>;
 		};
 	};
 };
-- 
2.43.0



From ardb at kernel.org  Tue Dec 16 05:23:28 2025
From: ardb at kernel.org (Ard Biesheuvel)
Date: Tue, 16 Dec 2025 14:23:28 +0100
Subject: [PATCH v3 9/9] efi: libstub: Simplify interfaces for primary_display
In-Reply-To: <20251126160854.553077-10-tzimmermann@suse.de>
References: <20251126160854.553077-1-tzimmermann@suse.de> <20251126160854.553077-10-tzimmermann@suse.de>
Message-ID: <CAMj1kXFeBS7O5A-CPds3UfFnjegGTpVsuF7VznBc-zZ+gjygtw@mail.gmail.com>

Hi Thomas

On Wed, 26 Nov 2025 at 17:09, Thomas Zimmermann <tzimmermann at suse.de> wrote:
>
> Rename alloc_primary_display() and __alloc_primary_display(), clarify
> free semantics to make interfaces easier to understand.
>
> Rename alloc_primary_display() to lookup_primary_display() as it
> does not necessarily allocate. Then rename __alloc_primary_display()
> to the new alloc_primary_display(). The helper belongs to
> free_primary_display), so it should be named without underscores.
>
> The lookup helper does not necessarily allocate, so the output
> parameter needs_free to indicate when free should be called.

I don't understand why we need this. Whether or not the helper
allocates is a compile time decision, and in builds where it doesn't,
the free helper doesn't do anything.

I'm all for making things simpler, but I don't think this patch
achieves that tbh.

I've queued up this series now up until this patch - once we converge
on the simplification, I'm happy to apply it on top.

Thanks,



> Pass
> an argument through the calls to track this state. Put the free
> handling into release_primary_display() for simplificy.
>
> Also move the comment fro primary_display.c to efi-stub-entry.c,
> where it now describes lookup_primary_display().
>
> Signed-off-by: Thomas Zimmermann <tzimmermann at suse.de>
> ---
>  drivers/firmware/efi/libstub/efi-stub-entry.c | 23 +++++++++++++++++--
>  drivers/firmware/efi/libstub/efi-stub.c       | 22 ++++++++++++------
>  drivers/firmware/efi/libstub/efistub.h        |  2 +-
>  .../firmware/efi/libstub/primary_display.c    | 17 +-------------
>  drivers/firmware/efi/libstub/zboot.c          |  6 +++--
>  5 files changed, 42 insertions(+), 28 deletions(-)
>
> diff --git a/drivers/firmware/efi/libstub/efi-stub-entry.c b/drivers/firmware/efi/libstub/efi-stub-entry.c
> index aa85e910fe59..3077b51fe0b2 100644
> --- a/drivers/firmware/efi/libstub/efi-stub-entry.c
> +++ b/drivers/firmware/efi/libstub/efi-stub-entry.c
> @@ -14,10 +14,29 @@ static void *kernel_image_addr(void *addr)
>         return addr + kernel_image_offset;
>  }
>
> -struct sysfb_display_info *alloc_primary_display(void)
> +/*
> + * There are two ways of populating the core kernel's sysfb_primary_display
> + * via the stub:
> + *
> + *   - using a configuration table, which relies on the EFI init code to
> + *     locate the table and copy the contents; or
> + *
> + *   - by linking directly to the core kernel's copy of the global symbol.
> + *
> + * The latter is preferred because it makes the EFIFB earlycon available very
> + * early, but it only works if the EFI stub is part of the core kernel image
> + * itself. The zboot decompressor can only use the configuration table
> + * approach.
> + */
> +
> +struct sysfb_display_info *lookup_primary_display(bool *needs_free)
>  {
> +       *needs_free = true;
> +
>         if (IS_ENABLED(CONFIG_ARM))
> -               return __alloc_primary_display();
> +               return alloc_primary_display();
> +
> +       *needs_free = false;
>
>         if (IS_ENABLED(CONFIG_X86) ||
>             IS_ENABLED(CONFIG_EFI_EARLYCON) ||
> diff --git a/drivers/firmware/efi/libstub/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c
> index 42d6073bcd06..dc545f62c62b 100644
> --- a/drivers/firmware/efi/libstub/efi-stub.c
> +++ b/drivers/firmware/efi/libstub/efi-stub.c
> @@ -51,14 +51,14 @@ static bool flat_va_mapping = (EFI_RT_VIRTUAL_OFFSET != 0);
>  void __weak free_primary_display(struct sysfb_display_info *dpy)
>  { }
>
> -static struct sysfb_display_info *setup_primary_display(void)
> +static struct sysfb_display_info *setup_primary_display(bool *dpy_needs_free)
>  {
>         struct sysfb_display_info *dpy;
>         struct screen_info *screen = NULL;
>         struct edid_info *edid = NULL;
>         efi_status_t status;
>
> -       dpy = alloc_primary_display();
> +       dpy = lookup_primary_display(dpy_needs_free);
>         if (!dpy)
>                 return NULL;
>         screen = &dpy->screen;
> @@ -68,15 +68,22 @@ static struct sysfb_display_info *setup_primary_display(void)
>
>         status = efi_setup_graphics(screen, edid);
>         if (status != EFI_SUCCESS)
> -               goto err_free_primary_display;
> +               goto err___free_primary_display;
>
>         return dpy;
>
> -err_free_primary_display:
> -       free_primary_display(dpy);
> +err___free_primary_display:
> +       if (*dpy_needs_free)
> +               free_primary_display(dpy);
>         return NULL;
>  }
>
> +static void release_primary_display(struct sysfb_display_info *dpy, bool dpy_needs_free)
> +{
> +       if (dpy && dpy_needs_free)
> +               free_primary_display(dpy);
> +}
> +
>  static void install_memreserve_table(void)
>  {
>         struct linux_efi_memreserve *rsv;
> @@ -156,13 +163,14 @@ efi_status_t efi_stub_common(efi_handle_t handle,
>                              char *cmdline_ptr)
>  {
>         struct sysfb_display_info *dpy;
> +       bool dpy_needs_free;
>         efi_status_t status;
>
>         status = check_platform_features();
>         if (status != EFI_SUCCESS)
>                 return status;
>
> -       dpy = setup_primary_display();
> +       dpy = setup_primary_display(&dpy_needs_free);
>
>         efi_retrieve_eventlog();
>
> @@ -182,7 +190,7 @@ efi_status_t efi_stub_common(efi_handle_t handle,
>
>         status = efi_boot_kernel(handle, image, image_addr, cmdline_ptr);
>
> -       free_primary_display(dpy);
> +       release_primary_display(dpy, dpy_needs_free);
>
>         return status;
>  }
> diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
> index 979a21818cc1..1503ffb82903 100644
> --- a/drivers/firmware/efi/libstub/efistub.h
> +++ b/drivers/firmware/efi/libstub/efistub.h
> @@ -1176,8 +1176,8 @@ efi_enable_reset_attack_mitigation(void) { }
>
>  void efi_retrieve_eventlog(void);
>
> +struct sysfb_display_info *lookup_primary_display(bool *needs_free);
>  struct sysfb_display_info *alloc_primary_display(void);
> -struct sysfb_display_info *__alloc_primary_display(void);
>  void free_primary_display(struct sysfb_display_info *dpy);
>
>  void efi_cache_sync_image(unsigned long image_base,
> diff --git a/drivers/firmware/efi/libstub/primary_display.c b/drivers/firmware/efi/libstub/primary_display.c
> index cdaebab26514..34c54ac1e02a 100644
> --- a/drivers/firmware/efi/libstub/primary_display.c
> +++ b/drivers/firmware/efi/libstub/primary_display.c
> @@ -7,24 +7,9 @@
>
>  #include "efistub.h"
>
> -/*
> - * There are two ways of populating the core kernel's sysfb_primary_display
> - * via the stub:
> - *
> - *   - using a configuration table, which relies on the EFI init code to
> - *     locate the table and copy the contents; or
> - *
> - *   - by linking directly to the core kernel's copy of the global symbol.
> - *
> - * The latter is preferred because it makes the EFIFB earlycon available very
> - * early, but it only works if the EFI stub is part of the core kernel image
> - * itself. The zboot decompressor can only use the configuration table
> - * approach.
> - */
> -
>  static efi_guid_t primary_display_guid = LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID;
>
> -struct sysfb_display_info *__alloc_primary_display(void)
> +struct sysfb_display_info *alloc_primary_display(void)
>  {
>         struct sysfb_display_info *dpy;
>         efi_status_t status;
> diff --git a/drivers/firmware/efi/libstub/zboot.c b/drivers/firmware/efi/libstub/zboot.c
> index 4b76f74c56da..c1fd1fdbcb08 100644
> --- a/drivers/firmware/efi/libstub/zboot.c
> +++ b/drivers/firmware/efi/libstub/zboot.c
> @@ -26,9 +26,11 @@ void __weak efi_cache_sync_image(unsigned long image_base,
>         // executable code loaded into memory to be safe for execution.
>  }
>
> -struct sysfb_display_info *alloc_primary_display(void)
> +struct sysfb_display_info *lookup_primary_display(bool *needs_free)
>  {
> -       return __alloc_primary_display();
> +       *needs_free = true;
> +
> +       return alloc_primary_display();
>  }
>
>  asmlinkage efi_status_t __efiapi
> --
> 2.51.1
>


From yeoreum.yun at arm.com  Tue Dec 16 05:25:12 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Tue, 16 Dec 2025 13:25:12 +0000
Subject: [PATCH 2/2] arm64: mmu: use pagetable_alloc_nolock() while
 stop_machine()
In-Reply-To: <DEZNBMBRM5M2.1974FFAQ13G5E@google.com>
References: <aT5/y3cSGIzi2K+m@e129823.arm.com>
 <DEYOI8H2OESD.1H56D3H8HKILB@google.com>
 <aT/WOAr4osoJWaMS@e129823.arm.com>
 <DEYP7JSVTB9D.3EFN2KEHH3O79@google.com>
 <aT/drjN1BkvyAGoi@e129823.arm.com>
 <DEZK5U2YP6I0.27VJHSVK14646@google.com>
 <aUE8bwUVa6jSUft1@e129823.arm.com>
 <DEZLRT59S25H.2YWTZ2G0TN3HV@google.com>
 <aUFKAdPY3zTlPmnr@e129823.arm.com>
 <DEZNBMBRM5M2.1974FFAQ13G5E@google.com>
Message-ID: <aUFduAz0BxYFQtc+@e129823.arm.com>

> On Tue Dec 16, 2025 at 12:01 PM UTC, Yeoreum Yun wrote:
> >> On Tue Dec 16, 2025 at 11:03 AM UTC, Yeoreum Yun wrote:
> >> > Hi Brendan,
> >> >
> >> >> On Mon Dec 15, 2025 at 10:06 AM UTC, Yeoreum Yun wrote:
> >> >> [snip]
> >> >> >> Overall I am feeling a bit uncomfortable about this use of _nolock, but
> >> >> >> I am also feeling pretty ignorant about PREEMPT_RT and also about this
> >> >> >> arm64 code, so I am hesitant to suggest alternatives, I hope someone
> >> >> >> else can offer some input here...
> >> >> >
> >> >> > I understand. However, as I mentioned earlier,
> >> >> > my main intention was to hear opinions specifically about memory contention.
> >> >> >
> >> >> > That said, if there is no memory contention,
> >> >> > I don?t think using the _nolock API is necessarily a bad approach.
> >> >>
> >> >>
> >> >> > In fact, I believe a bigger issue is that, under PREEMPT_RT,
> >> >> > code that uses the regular memory allocation APIs may give users the false impression
> >> >> > that those APIs are ?safe to use,? even though they are not.
> >> >>
> >> >> Yeah, I share this concern. I would bet I have written code that's
> >> >> broken under PREEMPT_RT (luckily only in Google's kernel fork). The
> >> >> comment for GFP_ATOMIC says:
> >> >>
> >> >>  * %GFP_ATOMIC users can not sleep and need the allocation to succeed. A lower
> >> >>  * watermark is applied to allow access to "atomic reserves".
> >> >>  * The current implementation doesn't support NMI and few other strict
> >> >>  * non-preemptive contexts (e.g. raw_spin_lock). The same applies to %GFP_NOWAIT.
> >> >>
> >> >> It kinda sounds like it's supposed to be OK to use GFP_ATOMIC in a
> >> >> normal preempt_disable() context. So do you know exactly why it's
> >> >> invalid to use it in this stop_machine() context here? Maybe we need to
> >> >> update this comment.
> >> >
> >> > In non-PREEMPT_RT configurations, this is fine to use.
> >> > However, in PREEMPT_RT, it should not be used because
> >> > spin_lock becomes a sleepable lock backed by an rt-mutex.
> >> >
> >> > From Documentation/locking/locktypes.rst:
> >> >
> >> >   The fact that PREEMPT_RT changes the lock category of spinlock_t and
> >> >   rwlock_t from spinning to sleeping.
> >> >
> >> > As you know, all locks related to memory allocation
> >> > (e.g., zone_lock, PCP locks, etc.) use spin_lock,
> >> > which becomes sleepable under PREEMPT_RT.
> >> >
> >> > The callback of stop_machine() is executed in a preemption-disabled context
> >> > (see cpu_stopper_thread()). In this context, if it fails to acquire a spinlock
> >> > during memory allocation,
> >> > the task would be able to go to sleep while preemption is disabled,
> >> > which is an obviously problematic situation.
> >>
> >> But this is what I mean, doesn't this sound like the GFP_ATOMIC comment
> >> I quoted is wrong (or at least, it implies things which are wrong)? The
> >> comment refers specifically to raw_spin_lock() and "strict
> >> non-preemptive contexts". Which sounds like it is being written with
> >> PREEMPT_RT in mind. But that doesn't really match what you've said.
> >
> > No. I think the comment of GFP_ATOMIC is right.
> > It definitely said:
> >   The current implementation *doesn't support* NMI and few other strict
> >   *non-preemptive contexts (e.g. raw_spin_lock)*.
>
> But this phrasing sounds like there are other non-preemptive contexts
> that it _does_ support. I would definitely read this as implying that
> plain old preempt_disable() is OK. I don't understand what those "few
> other strict contexts" are, nor why the stop_machine() context is
> included in them.

I think this phrasing seems to consider non-preeptive case for
the priority or schedule policy but still make me confused too.
But What I worth to say the stop_machine() -- exactly the callback
context (stopper thread context) by stop_machine() is
the same for raw_spin_lock() case where
explictly disable preemption by calling preempt_disable().

The reason why raw_spin_lock() context couldn't call the GFP_ATOMIC
since it explicitly disable preemption by calling preempt_disable().

stop_machine() callback context -- stopper thread's context is also the same.
when it calls the callback by stopper (see cpu_stopper_thread()):

  ...
  preempt_count_inc();
  ret = fn(arg);
  ...
  preempt_count_dec();
  ...

preemption is explicitly disabled like raw_spin_lock()

So it seems to include in "few strict non-preemptive context".

--
Sincerely,
Yeoreum Yun


From parvathi at couthit.com  Tue Dec 16 05:22:57 2025
From: parvathi at couthit.com (Parvathi Pudi)
Date: Tue, 16 Dec 2025 18:52:57 +0530
Subject: [RFC PATCH net-next v10 0/3] STP/RSTP SWITCH support for PRU-ICSSM Ethernet driver
Message-ID: <20251216132641.1313026-1-parvathi@couthit.com>

Hi,

The DUAL-EMAC patch series for Megabit Industrial Communication Sub-system
(ICSSM), which provides the foundational support for Ethernet functionality
over PRU-ICSS on the TI SOCs (AM335x, AM437x, and AM57x), was merged into
net-next recently [1].

This patch series enhances the PRU-ICSSM Ethernet driver to support bridge
(STP/RSTP) SWITCH mode, which has been implemented using the "switchdev"
framework and interacts with the "mstp daemon" for STP and RSTP management
in userspace.

When the  SWITCH mode is enabled, forwarding of Ethernet packets using
either the traditional store-and-forward mechanism or via cut-through is
offloaded to the two PRU based Ethernet interfaces available within the
ICSSM. The firmware running on the PRU inspects the bridge port states and
performs necessary checks before forwarding a packet. This improves the
overall system performance and significantly reduces the packet forwarding
latency.

Protocol switching from Dual-EMAC to bridge (STP/RSTP) SWITCH mode can be
done as follows.

Assuming eth2 and eth3 are the two physical ports of the ICSS2 instance:

>> brctl addbr br0
>> ip maddr add 01:80:c2:00:00:00 dev br0
>> ip link set dev br0 address $(cat /sys/class/net/eth2/address)
>> brctl addif br0 eth2
>> brctl addif br0 eth3
>> mstpd
>> brctl stp br0 on
# STP to RSTP mode
>> mstpctl setforcevers br0 rstp
>> ip link set dev br0 up

To revert back to the default dual EMAC mode, the steps are as follows:

>> ip link set dev br0 down
>> brctl delif br0 eth2
>> brctl delif br0 eth3
>> brctl delbr br0

The patches presented in this series have gone through the patch verification
tools and no warnings or errors are reported.

Sample test logs obtained from AM33x, AM43x and AM57x verifying the
functionality on Linux next kernel are available here:

[Interface up Testing](https://gist.github.com/ParvathiPudi/e95f6b38fda92feeb899ec5f8d4394f8)

[Ping Testing](https://gist.github.com/ParvathiPudi/4f7faf9f1fa82687e8d9c43f53a9e212)

[Iperf Testing](https://gist.github.com/ParvathiPudi/efc9e667a2a08589657ea3a9922c6c6c)

[1] https://lore.kernel.org/all/20250912104741.528721-1-parvathi at couthit.com/

This is the v10 of the patch series [v1]. This version of the patchset
addresses the comments made on [v9] of the series.

Changes from v9 to v10:

*) Added RFC tag as net-next is closed now.
*) Addressed applicable AI review warnings, including clearing the host lock before returning on
timeout, avoiding a race on hw_bridge_dev and adding a conditional check to avoid null
pointer dereferences.
*) Rebased the series on latest net-next.

Changes from v8 to v9:

*) Added RFC tag as net-next is closed now.
*) Addressed  Jakub Kicinski comments on patch 1 and 2 of the series.
*) Rebased the series on latest net-next.

Changes from v7 to v8:

*) Modified dev_hold/dev_put reference to netdev_hold/netdev_put in patch 2 of the series.
*) Rebased the series on latest net-next.

Changes from v6 to v7:

*) Addressed Jakub Kicinski comments on patch 2 of the series.
*) Rebased the series on latest net-next.

Changes from v5 to v6:

*) Addressed Simon Horman comments on patch 1, 2 and 3 of the series.
*) Rebased the series on latest net-next.

Changes from v4 to v5:

*) Addressed ALOK TIWARI comments on patch 1 of the series.
*) Rebased the series on latest net-next.

Changes from v3 to v4:

*) Addressed Andrew Lunn comments on patch 1 and 2 of the series.
*) Rebased the series on latest net-next.

Changes from v2 to v3:

*) Dropped the RFC tag.
*) Addressed  MD Danish Anwar comments on patch 3 of the series.
*) Rebased the series on latest net-next.

Changes from v1 to v2 :

*) Added RFC tag as net-next is closed now.
*) Updated the cover letter of the series to generalize and indicate support for
both STP and RSTP along with subject change as per Andrew Lunn's suggestion.
*) Addressed the Andrew Lunn's comments on patch 1 of the series.
*) Rebased the series on latest net-next.

[v1] https://lore.kernel.org/all/20250925141246.3433603-1-parvathi at couthit.com/
[v2] https://lore.kernel.org/all/20251006104908.775891-1-parvathi at couthit.com/
[v3] https://lore.kernel.org/all/20251014124018.1596900-1-parvathi at couthit.com/
[v4] https://lore.kernel.org/all/20251110125539.31052-1-parvathi at couthit.com/
[v5] https://lore.kernel.org/all/20251113101229.675141-1-parvathi at couthit.com/
[v6] https://lore.kernel.org/all/20251124135800.2219431-1-parvathi at couthit.com/
[v7] https://lore.kernel.org/all/20251126124602.2624264-1-parvathi at couthit.com/
[v8] https://lore.kernel.org/all/20251126163056.2697668-1-parvathi at couthit.com/
[v9] https://lore.kernel.org/all/20251205123146.462397-1-parvathi at couthit.com/

Thanks and Regards,
Parvathi.

Roger Quadros (3):
  net: ti: icssm-prueth: Add helper functions to configure and maintain
    FDB
  net: ti: icssm-prueth: Add switchdev support for icssm_prueth driver
  net: ti: icssm-prueth: Add support for ICSSM RSTP switch

 drivers/net/ethernet/ti/Makefile              |    2 +-
 drivers/net/ethernet/ti/icssm/icssm_prueth.c  |  529 +++++++-
 drivers/net/ethernet/ti/icssm/icssm_prueth.h  |   20 +-
 .../ethernet/ti/icssm/icssm_prueth_fdb_tbl.h  |   76 ++
 .../ethernet/ti/icssm/icssm_prueth_switch.c   | 1065 +++++++++++++++++
 .../ethernet/ti/icssm/icssm_prueth_switch.h   |   37 +
 drivers/net/ethernet/ti/icssm/icssm_switch.h  |  103 ++
 .../net/ethernet/ti/icssm/icssm_switchdev.c   |  333 ++++++
 .../net/ethernet/ti/icssm/icssm_switchdev.h   |   13 +
 .../ti/icssm/icssm_vlan_mcast_filter_mmap.h   |  120 ++
 10 files changed, 2275 insertions(+), 23 deletions(-)
 create mode 100644 drivers/net/ethernet/ti/icssm/icssm_prueth_fdb_tbl.h
 create mode 100644 drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c
 create mode 100644 drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h
 create mode 100644 drivers/net/ethernet/ti/icssm/icssm_switchdev.c
 create mode 100644 drivers/net/ethernet/ti/icssm/icssm_switchdev.h
 create mode 100644 drivers/net/ethernet/ti/icssm/icssm_vlan_mcast_filter_mmap.h

-- 
2.43.0



From parvathi at couthit.com  Tue Dec 16 05:22:59 2025
From: parvathi at couthit.com (Parvathi Pudi)
Date: Tue, 16 Dec 2025 18:52:59 +0530
Subject: [RFC PATCH net-next v10 2/3] net: ti: icssm-prueth: Add switchdev support for icssm_prueth driver
In-Reply-To: <20251216132641.1313026-1-parvathi@couthit.com>
References: <20251216132641.1313026-1-parvathi@couthit.com>
Message-ID: <20251216132641.1313026-3-parvathi@couthit.com>

From: Roger Quadros <rogerq at ti.com>

Add support for offloading the RSTP switch feature to the PRU-ICSS
subsystem by adding switchdev support. PRU-ICSS is capable of operating
in RSTP switch mode with two external ports and one host port.

PRUETH driver and firmware interface support will be added into
icssm_prueth in the subsequent commits.

Signed-off-by: Roger Quadros <rogerq at ti.com>
Signed-off-by: Andrew F. Davis <afd at ti.com>
Signed-off-by: Basharath Hussain Khaja <basharath at couthit.com>
Signed-off-by: Parvathi Pudi <parvathi at couthit.com>
---
 drivers/net/ethernet/ti/Makefile              |   2 +-
 drivers/net/ethernet/ti/icssm/icssm_prueth.c  | 180 ++++++++++
 drivers/net/ethernet/ti/icssm/icssm_prueth.h  |  11 +-
 .../ethernet/ti/icssm/icssm_prueth_switch.c   |  77 ++++
 .../ethernet/ti/icssm/icssm_prueth_switch.h   |  11 +-
 .../net/ethernet/ti/icssm/icssm_switchdev.c   | 333 ++++++++++++++++++
 .../net/ethernet/ti/icssm/icssm_switchdev.h   |  13 +
 .../ti/icssm/icssm_vlan_mcast_filter_mmap.h   | 120 +++++++
 8 files changed, 744 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/ethernet/ti/icssm/icssm_switchdev.c
 create mode 100644 drivers/net/ethernet/ti/icssm/icssm_switchdev.h
 create mode 100644 drivers/net/ethernet/ti/icssm/icssm_vlan_mcast_filter_mmap.h

diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile
index 1fd149dd6115..6da50f4b7c2e 100644
--- a/drivers/net/ethernet/ti/Makefile
+++ b/drivers/net/ethernet/ti/Makefile
@@ -4,7 +4,7 @@
 #
 
 obj-$(CONFIG_TI_PRUETH) += icssm-prueth.o
-icssm-prueth-y := icssm/icssm_prueth.o icssm/icssm_prueth_switch.o
+icssm-prueth-y := icssm/icssm_prueth.o icssm/icssm_prueth_switch.o icssm/icssm_switchdev.o
 
 obj-$(CONFIG_TI_CPSW) += cpsw-common.o
 obj-$(CONFIG_TI_DAVINCI_EMAC) += cpsw-common.o
diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.c b/drivers/net/ethernet/ti/icssm/icssm_prueth.c
index 293b7af04263..b779096c09e8 100644
--- a/drivers/net/ethernet/ti/icssm/icssm_prueth.c
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.c
@@ -29,6 +29,8 @@
 #include <net/pkt_cls.h>
 
 #include "icssm_prueth.h"
+#include "icssm_prueth_switch.h"
+#include "icssm_vlan_mcast_filter_mmap.h"
 #include "../icssg/icssg_mii_rt.h"
 #include "../icssg/icss_iep.h"
 
@@ -1131,11 +1133,174 @@ static void icssm_emac_ndo_get_stats64(struct net_device *ndev,
 	stats->rx_length_errors = emac->stats.rx_length_errors;
 }
 
+/* enable/disable MC filter */
+static void icssm_emac_mc_filter_ctrl(struct prueth_emac *emac, bool enable)
+{
+	struct prueth *prueth = emac->prueth;
+	void __iomem *mc_filter_ctrl;
+	void __iomem *ram;
+	u32 reg;
+
+	ram = prueth->mem[emac->dram].va;
+	mc_filter_ctrl = ram + ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_OFFSET;
+
+	if (enable)
+		reg = ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_ENABLED;
+	else
+		reg = ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_DISABLED;
+
+	writeb(reg, mc_filter_ctrl);
+}
+
+/* reset MC filter bins */
+static void icssm_emac_mc_filter_reset(struct prueth_emac *emac)
+{
+	struct prueth *prueth = emac->prueth;
+	void __iomem *mc_filter_tbl;
+	u32 mc_filter_tbl_base;
+	void __iomem *ram;
+
+	ram = prueth->mem[emac->dram].va;
+	mc_filter_tbl_base = ICSS_EMAC_FW_MULTICAST_FILTER_TABLE;
+
+	mc_filter_tbl = ram + mc_filter_tbl_base;
+	memset_io(mc_filter_tbl, 0, ICSS_EMAC_FW_MULTICAST_TABLE_SIZE_BYTES);
+}
+
+/* set MC filter hashmask */
+static void icssm_emac_mc_filter_hashmask
+		(struct prueth_emac *emac,
+		 u8 mask[ICSS_EMAC_FW_MULTICAST_FILTER_MASK_SIZE_BYTES])
+{
+	struct prueth *prueth = emac->prueth;
+	void __iomem *mc_filter_mask;
+	void __iomem *ram;
+
+	ram = prueth->mem[emac->dram].va;
+
+	mc_filter_mask = ram + ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OFFSET;
+	memcpy_toio(mc_filter_mask, mask,
+		    ICSS_EMAC_FW_MULTICAST_FILTER_MASK_SIZE_BYTES);
+}
+
+static void icssm_emac_mc_filter_bin_update(struct prueth_emac *emac, u8 hash,
+					    u8 val)
+{
+	struct prueth *prueth = emac->prueth;
+	void __iomem *mc_filter_tbl;
+	void __iomem *ram;
+
+	ram = prueth->mem[emac->dram].va;
+
+	mc_filter_tbl = ram + ICSS_EMAC_FW_MULTICAST_FILTER_TABLE;
+	writeb(val, mc_filter_tbl + hash);
+}
+
+void icssm_emac_mc_filter_bin_allow(struct prueth_emac *emac, u8 hash)
+{
+	icssm_emac_mc_filter_bin_update
+		(emac, hash,
+		 ICSS_EMAC_FW_MULTICAST_FILTER_HOST_RCV_ALLOWED);
+}
+
+void icssm_emac_mc_filter_bin_disallow(struct prueth_emac *emac, u8 hash)
+{
+	icssm_emac_mc_filter_bin_update
+		(emac, hash,
+		 ICSS_EMAC_FW_MULTICAST_FILTER_HOST_RCV_NOT_ALLOWED);
+}
+
+u8 icssm_emac_get_mc_hash(u8 *mac, u8 *mask)
+{
+	u8 hash;
+	int j;
+
+	for (j = 0, hash = 0; j < ETH_ALEN; j++)
+		hash ^= (mac[j] & mask[j]);
+
+	return hash;
+}
+
+/**
+ * icssm_emac_ndo_set_rx_mode - EMAC set receive mode function
+ * @ndev: The EMAC network adapter
+ *
+ * Called when system wants to set the receive mode of the device.
+ *
+ */
+static void icssm_emac_ndo_set_rx_mode(struct net_device *ndev)
+{
+	struct prueth_emac *emac = netdev_priv(ndev);
+	bool promisc = ndev->flags & IFF_PROMISC;
+	struct netdev_hw_addr *ha;
+	struct prueth *prueth;
+	unsigned long flags;
+	void __iomem *sram;
+	u32 mask, reg;
+	u8 hash;
+
+	prueth = emac->prueth;
+	sram = prueth->mem[PRUETH_MEM_SHARED_RAM].va;
+	reg = readl(sram + EMAC_PROMISCUOUS_MODE_OFFSET);
+
+	/* It is a shared table. So lock the access */
+	spin_lock_irqsave(&emac->addr_lock, flags);
+
+	/* Disable and reset multicast filter, allows allmulti */
+	icssm_emac_mc_filter_ctrl(emac, false);
+	icssm_emac_mc_filter_reset(emac);
+	icssm_emac_mc_filter_hashmask(emac, emac->mc_filter_mask);
+
+	if (PRUETH_IS_EMAC(prueth)) {
+		switch (emac->port_id) {
+		case PRUETH_PORT_MII0:
+			mask = EMAC_P1_PROMISCUOUS_BIT;
+			break;
+		case PRUETH_PORT_MII1:
+			mask = EMAC_P2_PROMISCUOUS_BIT;
+			break;
+		default:
+			netdev_err(ndev, "%s: invalid port\n", __func__);
+			goto unlock;
+		}
+
+		if (promisc) {
+			/* Enable promiscuous mode */
+			reg |= mask;
+		} else {
+			/* Disable promiscuous mode */
+			reg &= ~mask;
+		}
+
+		writel(reg, sram + EMAC_PROMISCUOUS_MODE_OFFSET);
+
+		if (promisc)
+			goto unlock;
+	}
+
+	if (ndev->flags & IFF_ALLMULTI && !PRUETH_IS_SWITCH(prueth))
+		goto unlock;
+
+	icssm_emac_mc_filter_ctrl(emac, true);	/* all multicast blocked */
+
+	if (netdev_mc_empty(ndev))
+		goto unlock;
+
+	netdev_for_each_mc_addr(ha, ndev) {
+		hash = icssm_emac_get_mc_hash(ha->addr, emac->mc_filter_mask);
+		icssm_emac_mc_filter_bin_allow(emac, hash);
+	}
+
+unlock:
+	spin_unlock_irqrestore(&emac->addr_lock, flags);
+}
+
 static const struct net_device_ops emac_netdev_ops = {
 	.ndo_open = icssm_emac_ndo_open,
 	.ndo_stop = icssm_emac_ndo_stop,
 	.ndo_start_xmit = icssm_emac_ndo_start_xmit,
 	.ndo_get_stats64 = icssm_emac_ndo_get_stats64,
+	.ndo_set_rx_mode = icssm_emac_ndo_set_rx_mode,
 };
 
 /* get emac_port corresponding to eth_node name */
@@ -1212,6 +1377,7 @@ static int icssm_prueth_netdev_init(struct prueth *prueth,
 	emac->prueth = prueth;
 	emac->ndev = ndev;
 	emac->port_id = port;
+	memset(&emac->mc_filter_mask[0], 0xff, ETH_ALEN);
 
 	/* by default eth_type is EMAC */
 	switch (port) {
@@ -1247,6 +1413,9 @@ static int icssm_prueth_netdev_init(struct prueth *prueth,
 		goto free;
 	}
 
+	spin_lock_init(&emac->lock);
+	spin_lock_init(&emac->addr_lock);
+
 	/* get mac address from DT and set private and netdev addr */
 	ret = of_get_ethdev_address(eth_node, ndev);
 	if (!is_valid_ether_addr(ndev->dev_addr)) {
@@ -1310,6 +1479,17 @@ static void icssm_prueth_netdev_exit(struct prueth *prueth,
 	prueth->emac[mac] = NULL;
 }
 
+bool icssm_prueth_sw_port_dev_check(const struct net_device *ndev)
+{
+	if (ndev->netdev_ops != &emac_netdev_ops)
+		return false;
+
+	if (ndev->features & NETIF_F_HW_L2FW_DOFFLOAD)
+		return true;
+
+	return false;
+}
+
 static int icssm_prueth_probe(struct platform_device *pdev)
 {
 	struct device_node *eth0_node = NULL, *eth1_node = NULL;
diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.h b/drivers/net/ethernet/ti/icssm/icssm_prueth.h
index 4b50133c5a72..f95c8c3a7ee5 100644
--- a/drivers/net/ethernet/ti/icssm/icssm_prueth.h
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.h
@@ -222,12 +222,14 @@ struct prueth_emac {
 	const char *phy_id;
 	u32 msg_enable;
 	u8 mac_addr[6];
+	unsigned char mc_filter_mask[ETH_ALEN]; /* for multicast filtering */
 	phy_interface_t phy_if;
 
 	/* spin lock used to protect
 	 * during link configuration
 	 */
 	spinlock_t lock;
+	spinlock_t addr_lock;   /* serialize access to VLAN/MC filter table */
 
 	struct hrtimer tx_hrtimer;
 	struct prueth_emac_stats stats;
@@ -249,8 +251,13 @@ struct prueth {
 	struct prueth_emac *emac[PRUETH_NUM_MACS];
 	struct net_device *registered_netdevs[PRUETH_NUM_MACS];
 
+	struct net_device *hw_bridge_dev;
 	struct fdb_tbl *fdb_tbl;
 
+	struct notifier_block prueth_netdevice_nb;
+	struct notifier_block prueth_switchdev_nb;
+	struct notifier_block prueth_switchdev_bl_nb;
+
 	unsigned int eth_type;
 	size_t ocmc_ram_size;
 	u8 emac_configured;
@@ -261,5 +268,7 @@ void icssm_parse_packet_info(struct prueth *prueth, u32 buffer_descriptor,
 int icssm_emac_rx_packet(struct prueth_emac *emac, u16 *bd_rd_ptr,
 			 struct prueth_packet_info *pkt_info,
 			 const struct prueth_queue_info *rxqueue);
-
+void icssm_emac_mc_filter_bin_allow(struct prueth_emac *emac, u8 hash);
+void icssm_emac_mc_filter_bin_disallow(struct prueth_emac *emac, u8 hash);
+u8 icssm_emac_get_mc_hash(u8 *mac, u8 *mask);
 #endif /* __NET_TI_PRUETH_H */
diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c
index 79a2ea5025f6..4e59c26dea4a 100644
--- a/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c
@@ -18,6 +18,17 @@
 #define FLAG_IS_STATIC	BIT(0)
 #define FLAG_ACTIVE	BIT(1)
 
+#define FDB_LEARN  1
+#define FDB_PURGE  2
+
+struct icssm_prueth_sw_fdb_work {
+	netdevice_tracker ndev_tracker;
+	struct work_struct work;
+	struct prueth_emac *emac;
+	u8 addr[ETH_ALEN];
+	int event;
+};
+
 void icssm_prueth_sw_free_fdb_table(struct prueth *prueth)
 {
 	if (prueth->emac_configured)
@@ -601,3 +612,69 @@ void icssm_prueth_sw_fdb_del(struct prueth_emac *emac,
 {
 	icssm_prueth_sw_delete_fdb_entry(emac, fdb->addr, 1);
 }
+
+static void icssm_prueth_sw_fdb_work(struct work_struct *work)
+{
+	struct icssm_prueth_sw_fdb_work *fdb_work =
+		container_of(work, struct icssm_prueth_sw_fdb_work, work);
+	struct prueth_emac *emac = fdb_work->emac;
+
+	rtnl_lock();
+
+	/* Interface is not up */
+	if (!emac->prueth->fdb_tbl)
+		goto free;
+
+	switch (fdb_work->event) {
+	case FDB_LEARN:
+		icssm_prueth_sw_insert_fdb_entry(emac, fdb_work->addr, 0);
+		break;
+	case FDB_PURGE:
+		icssm_prueth_sw_do_purge_fdb(emac);
+		break;
+	default:
+		break;
+	}
+
+free:
+	rtnl_unlock();
+	netdev_put(emac->ndev, &fdb_work->ndev_tracker);
+	kfree(fdb_work);
+}
+
+int icssm_prueth_sw_learn_fdb(struct prueth_emac *emac, u8 *src_mac)
+{
+	struct icssm_prueth_sw_fdb_work *fdb_work;
+
+	fdb_work = kzalloc(sizeof(*fdb_work), GFP_ATOMIC);
+	if (WARN_ON(!fdb_work))
+		return -ENOMEM;
+
+	INIT_WORK(&fdb_work->work, icssm_prueth_sw_fdb_work);
+
+	fdb_work->event = FDB_LEARN;
+	fdb_work->emac  = emac;
+	ether_addr_copy(fdb_work->addr, src_mac);
+
+	netdev_hold(emac->ndev, &fdb_work->ndev_tracker, GFP_ATOMIC);
+	queue_work(system_long_wq, &fdb_work->work);
+	return 0;
+}
+
+int icssm_prueth_sw_purge_fdb(struct prueth_emac *emac)
+{
+	struct icssm_prueth_sw_fdb_work *fdb_work;
+
+	fdb_work = kzalloc(sizeof(*fdb_work), GFP_ATOMIC);
+	if (WARN_ON(!fdb_work))
+		return -ENOMEM;
+
+	INIT_WORK(&fdb_work->work, icssm_prueth_sw_fdb_work);
+
+	fdb_work->event = FDB_PURGE;
+	fdb_work->emac  = emac;
+
+	netdev_hold(emac->ndev, &fdb_work->ndev_tracker, GFP_ATOMIC);
+	queue_work(system_long_wq, &fdb_work->work);
+	return 0;
+}
diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h
index fd013ecdc707..218cbe1d3c50 100644
--- a/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h
@@ -5,8 +5,16 @@
 #ifndef __NET_TI_PRUETH_SWITCH_H
 #define __NET_TI_PRUETH_SWITCH_H
 
+#include <net/switchdev.h>
+
 #include "icssm_prueth.h"
 #include "icssm_prueth_fdb_tbl.h"
+#include "icssm_switchdev.h"
+
+void icssm_prueth_sw_set_stp_state(struct prueth *prueth,
+				   enum prueth_port port, u8 state);
+u8 icssm_prueth_sw_get_stp_state(struct prueth *prueth,
+				 enum prueth_port port);
 
 void icssm_prueth_sw_fdb_tbl_init(struct prueth *prueth);
 int icssm_prueth_sw_init_fdb_table(struct prueth *prueth);
@@ -16,5 +24,6 @@ void icssm_prueth_sw_fdb_add(struct prueth_emac *emac,
 			     struct switchdev_notifier_fdb_info *fdb);
 void icssm_prueth_sw_fdb_del(struct prueth_emac *emac,
 			     struct switchdev_notifier_fdb_info *fdb);
-
+int icssm_prueth_sw_learn_fdb(struct prueth_emac *emac, u8 *src_mac);
+int icssm_prueth_sw_purge_fdb(struct prueth_emac *emac);
 #endif /* __NET_TI_PRUETH_SWITCH_H */
diff --git a/drivers/net/ethernet/ti/icssm/icssm_switchdev.c b/drivers/net/ethernet/ti/icssm/icssm_switchdev.c
new file mode 100644
index 000000000000..414ec9fc02a0
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssm/icssm_switchdev.c
@@ -0,0 +1,333 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* Texas Instruments ICSSM Ethernet Driver
+ *
+ * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/kernel.h>
+#include <linux/remoteproc.h>
+#include <net/switchdev.h>
+
+#include "icssm_prueth.h"
+#include "icssm_prueth_switch.h"
+#include "icssm_prueth_fdb_tbl.h"
+
+/* switchev event work */
+struct icssm_sw_event_work {
+	netdevice_tracker ndev_tracker;
+	struct work_struct work;
+	struct switchdev_notifier_fdb_info fdb_info;
+	struct prueth_emac *emac;
+	unsigned long event;
+};
+
+void icssm_prueth_sw_set_stp_state(struct prueth *prueth,
+				   enum prueth_port port, u8 state)
+{
+	struct fdb_tbl *t = prueth->fdb_tbl;
+
+	writeb(state, port - 1 ? (void __iomem *)&t->port2_stp_cfg->state :
+			(void __iomem *)&t->port1_stp_cfg->state);
+}
+
+u8 icssm_prueth_sw_get_stp_state(struct prueth *prueth, enum prueth_port port)
+{
+	struct fdb_tbl *t = prueth->fdb_tbl;
+	u8 state;
+
+	state = readb(port - 1 ? (void __iomem *)&t->port2_stp_cfg->state :
+			(void __iomem *)&t->port1_stp_cfg->state);
+	return state;
+}
+
+static int icssm_prueth_sw_attr_set(struct net_device *ndev, const void *ctx,
+				    const struct switchdev_attr *attr,
+				    struct netlink_ext_ack *extack)
+{
+	struct prueth_emac *emac = netdev_priv(ndev);
+	struct prueth *prueth = emac->prueth;
+	int err = 0;
+	u8 o_state;
+
+	/* Interface is not up */
+	if (!prueth->fdb_tbl)
+		return 0;
+
+	switch (attr->id) {
+	case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
+		o_state = icssm_prueth_sw_get_stp_state(prueth, emac->port_id);
+		icssm_prueth_sw_set_stp_state(prueth, emac->port_id,
+					      attr->u.stp_state);
+
+		if (o_state != attr->u.stp_state)
+			icssm_prueth_sw_purge_fdb(emac);
+
+		dev_dbg(prueth->dev, "attr set: stp state:%u port:%u\n",
+			attr->u.stp_state, emac->port_id);
+		break;
+	default:
+		err = -EOPNOTSUPP;
+		break;
+	}
+
+	return err;
+}
+
+static void icssm_prueth_sw_fdb_offload(struct net_device *ndev,
+					struct switchdev_notifier_fdb_info *rcv)
+{
+	struct switchdev_notifier_fdb_info info;
+
+	info.addr = rcv->addr;
+	info.vid = rcv->vid;
+	call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, ndev, &info.info,
+				 NULL);
+}
+
+/**
+ * icssm_sw_event_work - insert/delete fdb entry
+ *
+ * @work: work structure
+ *
+ */
+static void icssm_sw_event_work(struct work_struct *work)
+{
+	struct icssm_sw_event_work *switchdev_work =
+		container_of(work, struct icssm_sw_event_work, work);
+	struct prueth_emac *emac = switchdev_work->emac;
+	struct switchdev_notifier_fdb_info *fdb;
+	struct prueth *prueth = emac->prueth;
+	int port = emac->port_id;
+
+	rtnl_lock();
+
+	/* Interface is not up */
+	if (!emac->prueth->fdb_tbl)
+		goto free;
+
+	switch (switchdev_work->event) {
+	case SWITCHDEV_FDB_ADD_TO_DEVICE:
+		fdb = &switchdev_work->fdb_info;
+		dev_dbg(prueth->dev,
+			"prueth fdb add: MACID = %pM vid = %u flags = %u -- port %d\n",
+			fdb->addr, fdb->vid, fdb->added_by_user, port);
+
+		if (!fdb->added_by_user)
+			break;
+
+		if (fdb->is_local)
+			break;
+
+		icssm_prueth_sw_fdb_add(emac, fdb);
+		icssm_prueth_sw_fdb_offload(emac->ndev, fdb);
+		break;
+	case SWITCHDEV_FDB_DEL_TO_DEVICE:
+		fdb = &switchdev_work->fdb_info;
+		dev_dbg(prueth->dev,
+			"prueth fdb del: MACID = %pM vid = %u flags = %u -- port %d\n",
+			fdb->addr, fdb->vid, fdb->added_by_user, port);
+
+		if (fdb->is_local)
+			break;
+
+		icssm_prueth_sw_fdb_del(emac, fdb);
+		break;
+	default:
+		break;
+	}
+
+free:
+	rtnl_unlock();
+
+	netdev_put(emac->ndev, &switchdev_work->ndev_tracker);
+	kfree(switchdev_work->fdb_info.addr);
+	kfree(switchdev_work);
+}
+
+/* called under rcu_read_lock() */
+static int icssm_prueth_sw_switchdev_event(struct notifier_block *unused,
+					   unsigned long event, void *ptr)
+{
+	struct net_device *ndev = switchdev_notifier_info_to_dev(ptr);
+	struct switchdev_notifier_fdb_info *fdb_info = ptr;
+	struct prueth_emac *emac = netdev_priv(ndev);
+	struct icssm_sw_event_work *switchdev_work;
+	int err;
+
+	if (!icssm_prueth_sw_port_dev_check(ndev))
+		return NOTIFY_DONE;
+
+	if (event == SWITCHDEV_PORT_ATTR_SET) {
+		err = switchdev_handle_port_attr_set
+			(ndev, ptr, icssm_prueth_sw_port_dev_check,
+			 icssm_prueth_sw_attr_set);
+		return notifier_from_errno(err);
+	}
+
+	switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC);
+	if (WARN_ON(!switchdev_work))
+		return NOTIFY_BAD;
+
+	INIT_WORK(&switchdev_work->work, icssm_sw_event_work);
+	switchdev_work->emac = emac;
+	switchdev_work->event = event;
+
+	switch (event) {
+	case SWITCHDEV_FDB_ADD_TO_DEVICE:
+	case SWITCHDEV_FDB_DEL_TO_DEVICE:
+		memcpy(&switchdev_work->fdb_info, ptr,
+		       sizeof(switchdev_work->fdb_info));
+		switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC);
+		if (!switchdev_work->fdb_info.addr)
+			goto err_addr_alloc;
+		ether_addr_copy((u8 *)switchdev_work->fdb_info.addr,
+				fdb_info->addr);
+		netdev_hold(ndev, &switchdev_work->ndev_tracker, GFP_ATOMIC);
+		break;
+	default:
+		kfree(switchdev_work);
+		return NOTIFY_DONE;
+	}
+
+	queue_work(system_long_wq, &switchdev_work->work);
+
+	return NOTIFY_DONE;
+
+err_addr_alloc:
+	kfree(switchdev_work);
+	return NOTIFY_BAD;
+}
+
+static int icssm_prueth_switchdev_obj_add(struct net_device *ndev,
+					  const void *ctx,
+					  const struct switchdev_obj *obj,
+					  struct netlink_ext_ack *extack)
+{
+	struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj);
+	struct prueth_emac *emac = netdev_priv(ndev);
+	struct prueth *prueth = emac->prueth;
+	int ret = 0;
+	u8 hash;
+
+	switch (obj->id) {
+	case SWITCHDEV_OBJ_ID_HOST_MDB:
+		dev_dbg(prueth->dev, "MDB add: %s: vid %u:%pM  port: %x\n",
+			ndev->name, mdb->vid, mdb->addr, emac->port_id);
+		hash = icssm_emac_get_mc_hash(mdb->addr, emac->mc_filter_mask);
+		icssm_emac_mc_filter_bin_allow(emac, hash);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+	return ret;
+}
+
+static int icssm_prueth_switchdev_obj_del(struct net_device *ndev,
+					  const void *ctx,
+					  const struct switchdev_obj *obj)
+{
+	struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj);
+	struct prueth_emac *emac = netdev_priv(ndev);
+	struct prueth *prueth = emac->prueth;
+	struct netdev_hw_addr *ha;
+	u8 hash, tmp_hash;
+	int ret = 0;
+	u8 *mask;
+
+	switch (obj->id) {
+	case SWITCHDEV_OBJ_ID_HOST_MDB:
+		dev_dbg(prueth->dev, "MDB del: %s: vid %u:%pM  port: %x\n",
+			ndev->name, mdb->vid, mdb->addr, emac->port_id);
+		if (prueth->hw_bridge_dev) {
+			mask = emac->mc_filter_mask;
+			hash = icssm_emac_get_mc_hash(mdb->addr, mask);
+			netdev_for_each_mc_addr(ha, prueth->hw_bridge_dev) {
+				tmp_hash = icssm_emac_get_mc_hash(ha->addr,
+								  mask);
+				/* Another MC address is in the bin.
+				 * Don't disable.
+				 */
+				if (tmp_hash == hash)
+					return 0;
+			}
+			icssm_emac_mc_filter_bin_disallow(emac, hash);
+		}
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+	return ret;
+}
+
+/* switchdev notifiers */
+static int icssm_prueth_sw_blocking_event(struct notifier_block *unused,
+					  unsigned long event, void *ptr)
+{
+	struct net_device *ndev = switchdev_notifier_info_to_dev(ptr);
+	int err;
+
+	switch (event) {
+	case SWITCHDEV_PORT_OBJ_ADD:
+		err = switchdev_handle_port_obj_add
+			(ndev, ptr, icssm_prueth_sw_port_dev_check,
+			 icssm_prueth_switchdev_obj_add);
+		return notifier_from_errno(err);
+
+	case SWITCHDEV_PORT_OBJ_DEL:
+		err = switchdev_handle_port_obj_del
+			(ndev, ptr, icssm_prueth_sw_port_dev_check,
+			 icssm_prueth_switchdev_obj_del);
+		return notifier_from_errno(err);
+
+	case SWITCHDEV_PORT_ATTR_SET:
+		err = switchdev_handle_port_attr_set
+			(ndev, ptr, icssm_prueth_sw_port_dev_check,
+			 icssm_prueth_sw_attr_set);
+		return notifier_from_errno(err);
+
+	default:
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+int icssm_prueth_sw_register_notifiers(struct prueth *prueth)
+{
+	int ret = 0;
+
+	prueth->prueth_switchdev_nb.notifier_call =
+		&icssm_prueth_sw_switchdev_event;
+	ret = register_switchdev_notifier(&prueth->prueth_switchdev_nb);
+	if (ret) {
+		dev_err(prueth->dev,
+			"register switchdev notifier failed ret:%d\n", ret);
+		return ret;
+	}
+
+	prueth->prueth_switchdev_bl_nb.notifier_call =
+		&icssm_prueth_sw_blocking_event;
+	ret = register_switchdev_blocking_notifier
+		(&prueth->prueth_switchdev_bl_nb);
+	if (ret) {
+		dev_err(prueth->dev,
+			"register switchdev blocking notifier failed ret:%d\n",
+			ret);
+		unregister_switchdev_notifier(&prueth->prueth_switchdev_nb);
+	}
+
+	return ret;
+}
+
+void icssm_prueth_sw_unregister_notifiers(struct prueth *prueth)
+{
+	unregister_switchdev_blocking_notifier(&prueth->prueth_switchdev_bl_nb);
+	unregister_switchdev_notifier(&prueth->prueth_switchdev_nb);
+}
diff --git a/drivers/net/ethernet/ti/icssm/icssm_switchdev.h b/drivers/net/ethernet/ti/icssm/icssm_switchdev.h
new file mode 100644
index 000000000000..b03a98e3472e
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssm/icssm_switchdev.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com
+ */
+
+#ifndef __NET_TI_ICSSM_SWITCHDEV_H
+#define __NET_TI_ICSSM_SWITCHDEV_H
+
+#include "icssm_prueth.h"
+
+int icssm_prueth_sw_register_notifiers(struct prueth *prueth);
+void icssm_prueth_sw_unregister_notifiers(struct prueth *prueth);
+bool icssm_prueth_sw_port_dev_check(const struct net_device *ndev);
+#endif /* __NET_TI_ICSSM_SWITCHDEV_H */
diff --git a/drivers/net/ethernet/ti/icssm/icssm_vlan_mcast_filter_mmap.h b/drivers/net/ethernet/ti/icssm/icssm_vlan_mcast_filter_mmap.h
new file mode 100644
index 000000000000..c177c19a36ef
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssm/icssm_vlan_mcast_filter_mmap.h
@@ -0,0 +1,120 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* Copyright (C) 2015-2021 Texas Instruments Incorporated - https://www.ti.com
+ *
+ * This file contains VLAN/Multicast filtering feature memory map
+ *
+ */
+
+#ifndef ICSS_VLAN_MULTICAST_FILTER_MM_H
+#define ICSS_VLAN_MULTICAST_FILTER_MM_H
+
+/* VLAN/Multicast filter defines & offsets,
+ * present on both PRU0 and PRU1 DRAM
+ */
+
+/* Feature enable/disable values for multicast filtering */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_DISABLED		0x00
+#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_ENABLED		0x01
+
+/* Feature enable/disable values for VLAN filtering */
+#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_DISABLED			0x00
+#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_ENABLED			0x01
+
+/* Add/remove multicast mac id for filtering bin */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_HOST_RCV_ALLOWED		0x01
+#define ICSS_EMAC_FW_MULTICAST_FILTER_HOST_RCV_NOT_ALLOWED	0x00
+
+/* Default HASH value for the multicast filtering Mask */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_INIT_VAL			0xFF
+
+/* Size requirements for Multicast filtering feature */
+#define ICSS_EMAC_FW_MULTICAST_TABLE_SIZE_BYTES			       256
+#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_SIZE_BYTES			 6
+#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_SIZE_BYTES			 1
+#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_STATUS_SIZE_BYTES	 1
+#define ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_SIZE_BYTES		 4
+
+/* Size requirements for VLAN filtering feature : 4096 bits = 512 bytes */
+#define ICSS_EMAC_FW_VLAN_FILTER_TABLE_SIZE_BYTES		       512
+#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_SIZE_BYTES			 1
+#define ICSS_EMAC_FW_VLAN_FILTER_DROP_CNT_SIZE_BYTES			 4
+
+/* Mask override set status */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_SET			 1
+/* Mask override not set status */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_NOT_SET		 0
+/* 6 bytes HASH Mask for the MAC */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OFFSET	  0xF4
+/* 0 -> multicast filtering disabled | 1 -> multicast filtering enabled */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_OFFSET	\
+	(ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OFFSET +	\
+	 ICSS_EMAC_FW_MULTICAST_FILTER_MASK_SIZE_BYTES)
+/* Status indicating if the HASH override is done or not: 0: no, 1: yes */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_OVERRIDE_STATUS	\
+	(ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_OFFSET +	\
+	 ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_SIZE_BYTES)
+/* Multicast drop statistics */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_OFFSET	\
+	(ICSS_EMAC_FW_MULTICAST_FILTER_OVERRIDE_STATUS +\
+	 ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_STATUS_SIZE_BYTES)
+/* Multicast table */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_TABLE		\
+	(ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_OFFSET +\
+	 ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_SIZE_BYTES)
+
+/* Multicast filter defines & offsets for LRE
+ */
+#define ICSS_LRE_FW_MULTICAST_TABLE_SEARCH_OP_CONTROL_BIT	0xE0
+/* one byte field :
+ * 0 -> multicast filtering disabled
+ * 1 -> multicast filtering enabled
+ */
+#define ICSS_LRE_FW_MULTICAST_FILTER_MASK			 0xE4
+#define ICSS_LRE_FW_MULTICAST_FILTER_TABLE			 0x100
+
+/* VLAN table Offsets */
+#define ICSS_EMAC_FW_VLAN_FLTR_TBL_BASE_ADDR		 0x200
+#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_BITMAP_OFFSET	 0xEF
+#define ICSS_EMAC_FW_VLAN_FILTER_DROP_CNT_OFFSET	\
+	(ICSS_EMAC_FW_VLAN_FILTER_CTRL_BITMAP_OFFSET +	\
+	 ICSS_EMAC_FW_VLAN_FILTER_CTRL_SIZE_BYTES)
+
+/* VLAN filter Control Bit maps */
+/* one bit field, bit 0: | 0 : VLAN filter disabled (default),
+ * 1: VLAN filter enabled
+ */
+#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_ENABLE_BIT		       0
+/* one bit field, bit 1: | 0 : untagged host rcv allowed (default),
+ * 1: untagged host rcv not allowed
+ */
+#define ICSS_EMAC_FW_VLAN_FILTER_UNTAG_HOST_RCV_ALLOW_CTRL_BIT	       1
+/* one bit field, bit 1: | 0 : priotag host rcv allowed (default),
+ * 1: priotag host rcv not allowed
+ */
+#define ICSS_EMAC_FW_VLAN_FILTER_PRIOTAG_HOST_RCV_ALLOW_CTRL_BIT       2
+/* one bit field, bit 1: | 0 : skip sv vlan flow
+ * :1 : take sv vlan flow  (not applicable for dual emac )
+ */
+#define ICSS_EMAC_FW_VLAN_FILTER_SV_VLAN_FLOW_HOST_RCV_ALLOW_CTRL_BIT  3
+
+/* VLAN IDs */
+#define ICSS_EMAC_FW_VLAN_FILTER_PRIOTAG_VID			       0
+#define ICSS_EMAC_FW_VLAN_FILTER_VID_MIN			       0x0000
+#define ICSS_EMAC_FW_VLAN_FILTER_VID_MAX			       0x0FFF
+
+/* VLAN Filtering Commands */
+#define ICSS_EMAC_FW_VLAN_FILTER_ADD_VLAN_VID_CMD		       0x00
+#define ICSS_EMAC_FW_VLAN_FILTER_REMOVE_VLAN_VID_CMD		       0x01
+
+/* Switch defines for VLAN/MC filtering */
+/* SRAM
+ * VLAN filter defines & offsets
+ */
+#define ICSS_LRE_FW_VLAN_FLTR_CTRL_BYTE				 0x1FE
+/* one bit field | 0 : VLAN filter disabled
+ *		 | 1 : VLAN filter enabled
+ */
+#define ICSS_LRE_FW_VLAN_FLTR_TBL_BASE_ADDR			 0x200
+
+#endif /* ICSS_MULTICAST_FILTER_MM_H */
-- 
2.43.0



From parvathi at couthit.com  Tue Dec 16 05:23:00 2025
From: parvathi at couthit.com (Parvathi Pudi)
Date: Tue, 16 Dec 2025 18:53:00 +0530
Subject: [RFC PATCH net-next v10 3/3] net: ti: icssm-prueth: Add support for ICSSM RSTP switch
In-Reply-To: <20251216132641.1313026-1-parvathi@couthit.com>
References: <20251216132641.1313026-1-parvathi@couthit.com>
Message-ID: <20251216132641.1313026-4-parvathi@couthit.com>

From: Roger Quadros <rogerq at ti.com>

Add support for RSTP switch mode by enhancing the existing ICSSM dual EMAC
driver with switchdev support.

Enable the PRU-ICSSM to operate in switch mode, with the 2 PRU ports acting
as external ports and the host acting as an internal port. Packets received
from the PRU ports will be forwarded to the host (store and forward mode)
and also to the other PRU port (either using store and forward mode or via
cut-through mode). Packets coming from the host will be transmitted either
from one or both of the PRU ports (depending on the FDB decision).

By default, the dual EMAC firmware will be loaded in the PRU-ICSS
subsystem. To configure the PRU-ICSS to operate as a switch, a different
firmware must to be loaded.

Signed-off-by: Roger Quadros <rogerq at ti.com>
Signed-off-by: Andrew F. Davis <afd at ti.com>
Signed-off-by: Basharath Hussain Khaja <basharath at couthit.com>
Signed-off-by: Parvathi Pudi <parvathi at couthit.com>
---
 drivers/net/ethernet/ti/icssm/icssm_prueth.c  | 349 +++++++++++++++-
 drivers/net/ethernet/ti/icssm/icssm_prueth.h  |   6 +
 .../ethernet/ti/icssm/icssm_prueth_switch.c   | 385 ++++++++++++++++++
 .../ethernet/ti/icssm/icssm_prueth_switch.h   |   8 +
 drivers/net/ethernet/ti/icssm/icssm_switch.h  |  77 ++++
 5 files changed, 804 insertions(+), 21 deletions(-)

diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.c b/drivers/net/ethernet/ti/icssm/icssm_prueth.c
index b779096c09e8..617bda640ab7 100644
--- a/drivers/net/ethernet/ti/icssm/icssm_prueth.c
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.c
@@ -147,7 +147,7 @@ static const struct prueth_queue_info queue_infos[][NUM_QUEUES] = {
 	},
 };
 
-static const struct prueth_queue_desc queue_descs[][NUM_QUEUES] = {
+const struct prueth_queue_desc queue_descs[][NUM_QUEUES] = {
 	[PRUETH_PORT_QUEUE_HOST] = {
 		{ .rd_ptr = P0_Q1_BD_OFFSET, .wr_ptr = P0_Q1_BD_OFFSET, },
 		{ .rd_ptr = P0_Q2_BD_OFFSET, .wr_ptr = P0_Q2_BD_OFFSET, },
@@ -207,9 +207,9 @@ static void icssm_prueth_hostconfig(struct prueth *prueth)
 
 static void icssm_prueth_mii_init(struct prueth *prueth)
 {
+	u32 txcfg_reg, txcfg, txcfg2;
 	struct regmap *mii_rt;
 	u32 rxcfg_reg, rxcfg;
-	u32 txcfg_reg, txcfg;
 
 	mii_rt = prueth->mii_rt;
 
@@ -237,17 +237,23 @@ static void icssm_prueth_mii_init(struct prueth *prueth)
 		(TX_START_DELAY << PRUSS_MII_RT_TXCFG_TX_START_DELAY_SHIFT) |
 		(TX_CLK_DELAY_100M << PRUSS_MII_RT_TXCFG_TX_CLK_DELAY_SHIFT);
 
+	txcfg2 = txcfg;
+	if (!PRUETH_IS_EMAC(prueth))
+		txcfg2 |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
+
 	/* Configuration of Port 0 Tx */
 	txcfg_reg = PRUSS_MII_RT_TXCFG0;
 
-	regmap_write(mii_rt, txcfg_reg, txcfg);
+	regmap_write(mii_rt, txcfg_reg, txcfg2);
 
-	txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
+	txcfg2 = txcfg;
+	if (PRUETH_IS_EMAC(prueth))
+		txcfg2 |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
 
 	/* Configuration of Port 1 Tx */
 	txcfg_reg = PRUSS_MII_RT_TXCFG1;
 
-	regmap_write(mii_rt, txcfg_reg, txcfg);
+	regmap_write(mii_rt, txcfg_reg, txcfg2);
 
 	txcfg_reg = PRUSS_MII_RT_RX_FRMS0;
 
@@ -294,7 +300,10 @@ static void icssm_prueth_hostinit(struct prueth *prueth)
 		icssm_prueth_clearmem(prueth, PRUETH_MEM_DRAM1);
 
 	/* Initialize host queues in shared RAM */
-	icssm_prueth_hostconfig(prueth);
+	if (!PRUETH_IS_EMAC(prueth))
+		icssm_prueth_sw_hostconfig(prueth);
+	else
+		icssm_prueth_hostconfig(prueth);
 
 	/* Configure MII_RT */
 	icssm_prueth_mii_init(prueth);
@@ -501,19 +510,24 @@ static int icssm_prueth_tx_enqueue(struct prueth_emac *emac,
 	struct prueth_queue_desc __iomem *queue_desc;
 	const struct prueth_queue_info *txqueue;
 	struct net_device *ndev = emac->ndev;
+	struct prueth *prueth = emac->prueth;
 	unsigned int buffer_desc_count;
 	int free_blocks, update_block;
 	bool buffer_wrapped = false;
 	int write_block, read_block;
 	void *src_addr, *dst_addr;
 	int pkt_block_size;
+	void __iomem *sram;
 	void __iomem *dram;
 	int txport, pktlen;
 	u16 update_wr_ptr;
 	u32 wr_buf_desc;
 	void *ocmc_ram;
 
-	dram = emac->prueth->mem[emac->dram].va;
+	if (!PRUETH_IS_EMAC(prueth))
+		dram = prueth->mem[PRUETH_MEM_DRAM1].va;
+	else
+		dram = emac->prueth->mem[emac->dram].va;
 	if (eth_skb_pad(skb)) {
 		if (netif_msg_tx_err(emac) && net_ratelimit())
 			netdev_err(ndev, "packet pad failed\n");
@@ -526,7 +540,10 @@ static int icssm_prueth_tx_enqueue(struct prueth_emac *emac,
 	pktlen = skb->len;
 	/* Get the tx queue */
 	queue_desc = emac->tx_queue_descs + queue_id;
-	txqueue = &queue_infos[txport][queue_id];
+	if (!PRUETH_IS_EMAC(prueth))
+		txqueue = &sw_queue_infos[txport][queue_id];
+	else
+		txqueue = &queue_infos[txport][queue_id];
 
 	buffer_desc_count = icssm_get_buff_desc_count(txqueue);
 
@@ -592,7 +609,11 @@ static int icssm_prueth_tx_enqueue(struct prueth_emac *emac,
        /* update first buffer descriptor */
 	wr_buf_desc = (pktlen << PRUETH_BD_LENGTH_SHIFT) &
 		       PRUETH_BD_LENGTH_MASK;
-	writel(wr_buf_desc, dram + readw(&queue_desc->wr_ptr));
+	sram = prueth->mem[PRUETH_MEM_SHARED_RAM].va;
+	if (!PRUETH_IS_EMAC(prueth))
+		writel(wr_buf_desc, sram + readw(&queue_desc->wr_ptr));
+	else
+		writel(wr_buf_desc, dram + readw(&queue_desc->wr_ptr));
 
 	/* update the write pointer in this queue descriptor, the firmware
 	 * polls for this change so this will signal the start of transmission
@@ -606,7 +627,6 @@ static int icssm_prueth_tx_enqueue(struct prueth_emac *emac,
 void icssm_parse_packet_info(struct prueth *prueth, u32 buffer_descriptor,
 			     struct prueth_packet_info *pkt_info)
 {
-	pkt_info->shadow = !!(buffer_descriptor & PRUETH_BD_SHADOW_MASK);
 	pkt_info->port = (buffer_descriptor & PRUETH_BD_PORT_MASK) >>
 			 PRUETH_BD_PORT_SHIFT;
 	pkt_info->length = (buffer_descriptor & PRUETH_BD_LENGTH_MASK) >>
@@ -715,11 +735,19 @@ int icssm_emac_rx_packet(struct prueth_emac *emac, u16 *bd_rd_ptr,
 		src_addr += actual_pkt_len;
 	}
 
+	if (PRUETH_IS_SWITCH(emac->prueth)) {
+		skb->offload_fwd_mark = READ_ONCE(emac->offload_fwd_mark);
+		if (!pkt_info->lookup_success)
+			icssm_prueth_sw_learn_fdb(emac, skb->data + ETH_ALEN);
+	}
+
 	skb_put(skb, actual_pkt_len);
 
 	/* send packet up the stack */
 	skb->protocol = eth_type_trans(skb, ndev);
+	local_bh_disable();
 	netif_receive_skb(skb);
+	local_bh_enable();
 
 	/* update stats */
 	emac->stats.rx_bytes += actual_pkt_len;
@@ -745,6 +773,7 @@ static int icssm_emac_rx_packets(struct prueth_emac *emac, int budget)
 
 	shared_ram = emac->prueth->mem[PRUETH_MEM_SHARED_RAM].va;
 
+	/* Start and end queue is made common for EMAC, RSTP */
 	start_queue = emac->rx_queue_start;
 	end_queue = emac->rx_queue_end;
 
@@ -755,8 +784,10 @@ static int icssm_emac_rx_packets(struct prueth_emac *emac, int budget)
 	/* search host queues for packets */
 	for (i = start_queue; i <= end_queue; i++) {
 		queue_desc = emac->rx_queue_descs + i;
-		rxqueue = &queue_infos[PRUETH_PORT_HOST][i];
-
+		if (PRUETH_IS_SWITCH(emac->prueth))
+			rxqueue = &sw_queue_infos[PRUETH_PORT_HOST][i];
+		else
+			rxqueue = &queue_infos[PRUETH_PORT_HOST][i];
 		overflow_cnt = readb(&queue_desc->overflow_cnt);
 		if (overflow_cnt > 0) {
 			emac->stats.rx_over_errors += overflow_cnt;
@@ -881,6 +912,13 @@ static int icssm_emac_request_irqs(struct prueth_emac *emac)
 	return ret;
 }
 
+/* Function to free memory related to sw */
+static void icssm_prueth_free_memory(struct prueth *prueth)
+{
+	if (PRUETH_IS_SWITCH(prueth))
+		icssm_prueth_sw_free_fdb_table(prueth);
+}
+
 static void icssm_ptp_dram_init(struct prueth_emac *emac)
 {
 	void __iomem *sram = emac->prueth->mem[PRUETH_MEM_SHARED_RAM].va;
@@ -943,20 +981,38 @@ static int icssm_emac_ndo_open(struct net_device *ndev)
 	if (!prueth->emac_configured)
 		icssm_prueth_init_ethernet_mode(prueth);
 
-	icssm_prueth_emac_config(emac);
+	/* reset and start PRU firmware */
+	if (PRUETH_IS_SWITCH(prueth)) {
+		ret = icssm_prueth_sw_emac_config(emac);
+		if (ret)
+			return ret;
+
+		ret = icssm_prueth_sw_init_fdb_table(prueth);
+		if (ret)
+			return ret;
+	} else {
+		icssm_prueth_emac_config(emac);
+	}
 
 	if (!prueth->emac_configured) {
 		icssm_ptp_dram_init(emac);
 		ret = icss_iep_init(prueth->iep, NULL, NULL, 0);
 		if (ret) {
 			netdev_err(ndev, "Failed to initialize iep: %d\n", ret);
-			goto iep_exit;
+			goto free_mem;
 		}
 	}
 
-	ret = icssm_emac_set_boot_pru(emac, ndev);
-	if (ret)
-		goto iep_exit;
+	if (!PRUETH_IS_EMAC(prueth)) {
+		ret = icssm_prueth_sw_boot_prus(prueth, ndev);
+		if (ret)
+			goto iep_exit;
+	} else {
+		/* boot the PRU */
+		ret = icssm_emac_set_boot_pru(emac, ndev);
+		if (ret)
+			goto iep_exit;
+	}
 
 	ret = icssm_emac_request_irqs(emac);
 	if (ret)
@@ -971,19 +1027,25 @@ static int icssm_emac_ndo_open(struct net_device *ndev)
 	icssm_prueth_port_enable(emac, true);
 
 	prueth->emac_configured |= BIT(emac->port_id);
-
+	if (PRUETH_IS_SWITCH(prueth))
+		icssm_prueth_sw_set_stp_state(prueth, emac->port_id,
+					      BR_STATE_LEARNING);
 	if (netif_msg_drv(emac))
 		dev_notice(&ndev->dev, "started\n");
 
 	return 0;
 
 rproc_shutdown:
-	rproc_shutdown(emac->pru);
+	if (!PRUETH_IS_EMAC(prueth))
+		icssm_prueth_sw_shutdown_prus(emac, ndev);
+	else
+		rproc_shutdown(emac->pru);
 
 iep_exit:
 	if (!prueth->emac_configured)
 		icss_iep_exit(prueth->iep);
-
+free_mem:
+	icssm_prueth_free_memory(emac->prueth);
 	return ret;
 }
 
@@ -1012,17 +1074,73 @@ static int icssm_emac_ndo_stop(struct net_device *ndev)
 	hrtimer_cancel(&emac->tx_hrtimer);
 
 	/* stop the PRU */
-	rproc_shutdown(emac->pru);
+	if (!PRUETH_IS_EMAC(prueth))
+		icssm_prueth_sw_shutdown_prus(emac, ndev);
+	else
+		rproc_shutdown(emac->pru);
 
 	/* free rx interrupts */
 	free_irq(emac->rx_irq, ndev);
 
+	/* free memory related to sw */
+	icssm_prueth_free_memory(emac->prueth);
+
+	if (!prueth->emac_configured)
+		icss_iep_exit(prueth->iep);
+
 	if (netif_msg_drv(emac))
 		dev_notice(&ndev->dev, "stopped\n");
 
 	return 0;
 }
 
+static int icssm_prueth_change_mode(struct prueth *prueth,
+				    enum pruss_ethtype mode)
+{
+	bool portstatus[PRUETH_NUM_MACS];
+	struct prueth_emac *emac;
+	struct net_device *ndev;
+	int i, ret;
+
+	for (i = 0; i < PRUETH_NUM_MACS; i++) {
+		emac = prueth->emac[i];
+		ndev = emac->ndev;
+
+		portstatus[i] = netif_running(ndev);
+		if (!portstatus[i])
+			continue;
+
+		ret = ndev->netdev_ops->ndo_stop(ndev);
+		if (ret < 0) {
+			netdev_err(ndev, "failed to stop: %d", ret);
+			return ret;
+		}
+	}
+
+	if (mode == PRUSS_ETHTYPE_EMAC || mode == PRUSS_ETHTYPE_SWITCH) {
+		prueth->eth_type = mode;
+	} else {
+		dev_err(prueth->dev, "unknown mode\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < PRUETH_NUM_MACS; i++) {
+		emac = prueth->emac[i];
+		ndev = emac->ndev;
+
+		if (!portstatus[i])
+			continue;
+
+		ret = ndev->netdev_ops->ndo_open(ndev);
+		if (ret < 0) {
+			netdev_err(ndev, "failed to start: %d", ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
 /* VLAN-tag PCP to priority queue map for EMAC/Switch/HSR/PRP used by driver
  * Index is PCP val / 2.
  *   low  - pcp 0..3 maps to Q4 for Host
@@ -1291,6 +1409,15 @@ static void icssm_emac_ndo_set_rx_mode(struct net_device *ndev)
 		icssm_emac_mc_filter_bin_allow(emac, hash);
 	}
 
+	/* Add bridge device's MC addresses as well */
+	if (prueth->hw_bridge_dev) {
+		netdev_for_each_mc_addr(ha, prueth->hw_bridge_dev) {
+			hash = icssm_emac_get_mc_hash(ha->addr,
+						      emac->mc_filter_mask);
+			icssm_emac_mc_filter_bin_allow(emac, hash);
+		}
+	}
+
 unlock:
 	spin_unlock_irqrestore(&emac->addr_lock, flags);
 }
@@ -1353,6 +1480,7 @@ static enum hrtimer_restart icssm_emac_tx_timer_callback(struct hrtimer *timer)
 static int icssm_prueth_netdev_init(struct prueth *prueth,
 				    struct device_node *eth_node)
 {
+	const struct prueth_private_data *fw_data = prueth->fw_data;
 	struct prueth_emac *emac;
 	struct net_device *ndev;
 	enum prueth_port port;
@@ -1443,6 +1571,14 @@ static int icssm_prueth_netdev_init(struct prueth *prueth,
 	phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_Pause_BIT);
 	phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_Asym_Pause_BIT);
 
+	/* Protocol switching
+	 * Enabling L2 Firmware offloading
+	 */
+	if (fw_data->support_switch) {
+		ndev->features |= NETIF_F_HW_L2FW_DOFFLOAD;
+		ndev->hw_features |= NETIF_F_HW_L2FW_DOFFLOAD;
+	}
+
 	ndev->dev.of_node = eth_node;
 	ndev->netdev_ops = &emac_netdev_ops;
 
@@ -1490,6 +1626,152 @@ bool icssm_prueth_sw_port_dev_check(const struct net_device *ndev)
 	return false;
 }
 
+static int icssm_prueth_port_offload_fwd_mark_update(struct prueth *prueth)
+{
+	int set_val = 0;
+	int i, ret = 0;
+	u8 all_slaves;
+
+	all_slaves = BIT(PRUETH_PORT_MII0) | BIT(PRUETH_PORT_MII1);
+
+	if (prueth->br_members == all_slaves)
+		set_val = 1;
+
+	dev_dbg(prueth->dev, "set offload_fwd_mark %d, mbrs=0x%x\n",
+		set_val, prueth->br_members);
+
+	for (i = 0; i < PRUETH_NUM_MACS; i++)
+		WRITE_ONCE(prueth->emac[i]->offload_fwd_mark, set_val);
+
+	/* Bridge is created, load switch firmware,
+	 * if not already in that mode
+	 */
+	if (set_val && !PRUETH_IS_SWITCH(prueth)) {
+		ret = icssm_prueth_change_mode(prueth, PRUSS_ETHTYPE_SWITCH);
+		if (ret < 0)
+			dev_err(prueth->dev, "Failed to enable Switch mode\n");
+		else
+			dev_info(prueth->dev,
+				 "TI PRU ethernet now in Switch mode\n");
+	}
+
+	/* Bridge is deleted, switch to Dual EMAC mode */
+	if (!prueth->br_members && !PRUETH_IS_EMAC(prueth)) {
+		ret = icssm_prueth_change_mode(prueth, PRUSS_ETHTYPE_EMAC);
+		if (ret < 0)
+			dev_err(prueth->dev, "Failed to enable Dual EMAC mode\n");
+		else
+			dev_info(prueth->dev,
+				 "TI PRU ethernet now in Dual EMAC mode\n");
+	}
+
+	return ret;
+}
+
+static int icssm_prueth_ndev_port_link(struct net_device *ndev,
+				       struct net_device *br_ndev)
+{
+	struct prueth_emac *emac = netdev_priv(ndev);
+	struct prueth *prueth = emac->prueth;
+	unsigned long flags;
+	int ret = 0;
+
+	dev_dbg(prueth->dev, "%s: br_mbrs=0x%x %s\n",
+		__func__, prueth->br_members, ndev->name);
+
+	spin_lock_irqsave(&emac->addr_lock, flags);
+
+	if (!prueth->br_members) {
+		prueth->hw_bridge_dev = br_ndev;
+	} else {
+		/* This is adding the port to a second bridge,
+		 * this is unsupported
+		 */
+		if (prueth->hw_bridge_dev != br_ndev) {
+			spin_unlock_irqrestore(&emac->addr_lock, flags);
+			return -EOPNOTSUPP;
+		}
+	}
+
+	prueth->br_members |= BIT(emac->port_id);
+
+	ret = icssm_prueth_port_offload_fwd_mark_update(prueth);
+
+	spin_unlock_irqrestore(&emac->addr_lock, flags);
+
+	return ret;
+}
+
+static int icssm_prueth_ndev_port_unlink(struct net_device *ndev)
+{
+	struct prueth_emac *emac = netdev_priv(ndev);
+	struct prueth *prueth = emac->prueth;
+	unsigned long flags;
+	int ret = 0;
+
+	dev_dbg(prueth->dev, "emac_sw_ndev_port_unlink\n");
+
+	spin_lock_irqsave(&emac->addr_lock, flags);
+
+	prueth->br_members &= ~BIT(emac->port_id);
+
+	ret = icssm_prueth_port_offload_fwd_mark_update(prueth);
+
+	if (!prueth->br_members)
+		prueth->hw_bridge_dev = NULL;
+
+	spin_unlock_irqrestore(&emac->addr_lock, flags);
+
+	return ret;
+}
+
+static int icssm_prueth_ndev_event(struct notifier_block *unused,
+				   unsigned long event, void *ptr)
+{
+	struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
+	struct netdev_notifier_changeupper_info *info;
+	int ret = NOTIFY_DONE;
+
+	if (!icssm_prueth_sw_port_dev_check(ndev))
+		return NOTIFY_DONE;
+
+	switch (event) {
+	case NETDEV_CHANGEUPPER:
+		info = ptr;
+		if (netif_is_bridge_master(info->upper_dev)) {
+			if (info->linking)
+				ret = icssm_prueth_ndev_port_link
+					(ndev, info->upper_dev);
+			else
+				ret = icssm_prueth_ndev_port_unlink(ndev);
+		}
+		break;
+	default:
+		return NOTIFY_DONE;
+	}
+
+	return notifier_from_errno(ret);
+}
+
+static int icssm_prueth_register_notifiers(struct prueth *prueth)
+{
+	int ret = 0;
+
+	prueth->prueth_netdevice_nb.notifier_call = icssm_prueth_ndev_event;
+	ret = register_netdevice_notifier(&prueth->prueth_netdevice_nb);
+	if (ret) {
+		dev_err(prueth->dev,
+			"register netdevice notifier failed ret: %d\n", ret);
+		return ret;
+	}
+
+	ret = icssm_prueth_sw_register_notifiers(prueth);
+	if (ret)
+		unregister_netdevice_notifier(&prueth->prueth_netdevice_nb);
+
+	return ret;
+}
+
 static int icssm_prueth_probe(struct platform_device *pdev)
 {
 	struct device_node *eth0_node = NULL, *eth1_node = NULL;
@@ -1709,6 +1991,12 @@ static int icssm_prueth_probe(struct platform_device *pdev)
 			prueth->emac[PRUETH_MAC1]->ndev;
 	}
 
+	ret = icssm_prueth_register_notifiers(prueth);
+	if (ret) {
+		dev_err(dev, "can't register switchdev notifiers");
+		goto netdev_unregister;
+	}
+
 	dev_info(dev, "TI PRU ethernet driver initialized: %s EMAC mode\n",
 		 (!eth0_node || !eth1_node) ? "single" : "dual");
 
@@ -1769,6 +2057,9 @@ static void icssm_prueth_remove(struct platform_device *pdev)
 	struct device_node *eth_node;
 	int i;
 
+	unregister_netdevice_notifier(&prueth->prueth_netdevice_nb);
+	icssm_prueth_sw_unregister_notifiers(prueth);
+
 	for (i = 0; i < PRUETH_NUM_MACS; i++) {
 		if (!prueth->registered_netdevs[i])
 			continue;
@@ -1868,11 +2159,16 @@ static struct prueth_private_data am335x_prueth_pdata = {
 	.fw_pru[PRUSS_PRU0] = {
 		.fw_name[PRUSS_ETHTYPE_EMAC] =
 			"ti-pruss/am335x-pru0-prueth-fw.elf",
+		.fw_name[PRUSS_ETHTYPE_SWITCH] =
+			"ti-pruss/am335x-pru0-prusw-fw.elf",
 	},
 	.fw_pru[PRUSS_PRU1] = {
 		.fw_name[PRUSS_ETHTYPE_EMAC] =
 			"ti-pruss/am335x-pru1-prueth-fw.elf",
+		.fw_name[PRUSS_ETHTYPE_SWITCH] =
+			"ti-pruss/am335x-pru1-prusw-fw.elf",
 	},
+	.support_switch = true,
 };
 
 /* AM437x SoC-specific firmware data */
@@ -1881,11 +2177,16 @@ static struct prueth_private_data am437x_prueth_pdata = {
 	.fw_pru[PRUSS_PRU0] = {
 		.fw_name[PRUSS_ETHTYPE_EMAC] =
 			"ti-pruss/am437x-pru0-prueth-fw.elf",
+		.fw_name[PRUSS_ETHTYPE_SWITCH] =
+			"ti-pruss/am437x-pru0-prusw-fw.elf",
 	},
 	.fw_pru[PRUSS_PRU1] = {
 		.fw_name[PRUSS_ETHTYPE_EMAC] =
 			"ti-pruss/am437x-pru1-prueth-fw.elf",
+		.fw_name[PRUSS_ETHTYPE_SWITCH] =
+			"ti-pruss/am437x-pru1-prusw-fw.elf",
 	},
+	.support_switch = true,
 };
 
 /* AM57xx SoC-specific firmware data */
@@ -1894,11 +2195,17 @@ static struct prueth_private_data am57xx_prueth_pdata = {
 	.fw_pru[PRUSS_PRU0] = {
 		.fw_name[PRUSS_ETHTYPE_EMAC] =
 			"ti-pruss/am57xx-pru0-prueth-fw.elf",
+	.fw_name[PRUSS_ETHTYPE_SWITCH] =
+			"ti-pruss/am57xx-pru0-prusw-fw.elf",
 	},
 	.fw_pru[PRUSS_PRU1] = {
 		.fw_name[PRUSS_ETHTYPE_EMAC] =
 			"ti-pruss/am57xx-pru1-prueth-fw.elf",
+		.fw_name[PRUSS_ETHTYPE_SWITCH] =
+			"ti-pruss/am57xx-pru1-prusw-fw.elf",
+
 	},
+	.support_switch = true,
 };
 
 static const struct of_device_id prueth_dt_match[] = {
diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.h b/drivers/net/ethernet/ti/icssm/icssm_prueth.h
index f95c8c3a7ee5..d5b49b462c24 100644
--- a/drivers/net/ethernet/ti/icssm/icssm_prueth.h
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.h
@@ -182,10 +182,12 @@ enum pruss_device {
  * struct prueth_private_data - PRU Ethernet private data
  * @driver_data: PRU Ethernet device name
  * @fw_pru: firmware names to be used for PRUSS ethernet usecases
+ * @support_switch: boolean to indicate if switch is enabled
  */
 struct prueth_private_data {
 	enum pruss_device driver_data;
 	const struct prueth_firmware fw_pru[PRUSS_NUM_PRUS];
+	bool support_switch;
 };
 
 struct prueth_emac_stats {
@@ -233,6 +235,7 @@ struct prueth_emac {
 
 	struct hrtimer tx_hrtimer;
 	struct prueth_emac_stats stats;
+	int offload_fwd_mark;
 };
 
 struct prueth {
@@ -261,8 +264,11 @@ struct prueth {
 	unsigned int eth_type;
 	size_t ocmc_ram_size;
 	u8 emac_configured;
+	u8 br_members;
 };
 
+extern const struct prueth_queue_desc queue_descs[][NUM_QUEUES];
+
 void icssm_parse_packet_info(struct prueth *prueth, u32 buffer_descriptor,
 			     struct prueth_packet_info *pkt_info);
 int icssm_emac_rx_packet(struct prueth_emac *emac, u16 *bd_rd_ptr,
diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c
index 4e59c26dea4a..36e1eeb4af39 100644
--- a/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c
@@ -29,6 +29,176 @@ struct icssm_prueth_sw_fdb_work {
 	int event;
 };
 
+const struct prueth_queue_info sw_queue_infos[][NUM_QUEUES] = {
+	[PRUETH_PORT_QUEUE_HOST] = {
+		[PRUETH_QUEUE1] = {
+			P0_Q1_BUFFER_OFFSET,
+			P0_QUEUE_DESC_OFFSET,
+			P0_Q1_BD_OFFSET,
+			P0_Q1_BD_OFFSET + ((HOST_QUEUE_1_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE2] = {
+			P0_Q2_BUFFER_OFFSET,
+			P0_QUEUE_DESC_OFFSET + 8,
+			P0_Q2_BD_OFFSET,
+			P0_Q2_BD_OFFSET + ((HOST_QUEUE_2_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE3] = {
+			P0_Q3_BUFFER_OFFSET,
+			P0_QUEUE_DESC_OFFSET + 16,
+			P0_Q3_BD_OFFSET,
+			P0_Q3_BD_OFFSET + ((HOST_QUEUE_3_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE4] = {
+			P0_Q4_BUFFER_OFFSET,
+			P0_QUEUE_DESC_OFFSET + 24,
+			P0_Q4_BD_OFFSET,
+			P0_Q4_BD_OFFSET + ((HOST_QUEUE_4_SIZE - 1) * BD_SIZE),
+		},
+	},
+	[PRUETH_PORT_QUEUE_MII0] = {
+		[PRUETH_QUEUE1] = {
+			P1_Q1_BUFFER_OFFSET,
+			P1_Q1_BUFFER_OFFSET +
+				((QUEUE_1_SIZE - 1) * ICSS_BLOCK_SIZE),
+			P1_Q1_BD_OFFSET,
+			P1_Q1_BD_OFFSET + ((QUEUE_1_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE2] = {
+			P1_Q2_BUFFER_OFFSET,
+			P1_Q2_BUFFER_OFFSET +
+				((QUEUE_2_SIZE - 1) * ICSS_BLOCK_SIZE),
+			P1_Q2_BD_OFFSET,
+			P1_Q2_BD_OFFSET + ((QUEUE_2_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE3] = {
+			P1_Q3_BUFFER_OFFSET,
+			P1_Q3_BUFFER_OFFSET +
+				((QUEUE_3_SIZE - 1) * ICSS_BLOCK_SIZE),
+			P1_Q3_BD_OFFSET,
+			P1_Q3_BD_OFFSET + ((QUEUE_3_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE4] = {
+			P1_Q4_BUFFER_OFFSET,
+			P1_Q4_BUFFER_OFFSET +
+				((QUEUE_4_SIZE - 1) * ICSS_BLOCK_SIZE),
+			P1_Q4_BD_OFFSET,
+			P1_Q4_BD_OFFSET + ((QUEUE_4_SIZE - 1) * BD_SIZE),
+		},
+	},
+	[PRUETH_PORT_QUEUE_MII1] = {
+		[PRUETH_QUEUE1] = {
+			P2_Q1_BUFFER_OFFSET,
+			P2_Q1_BUFFER_OFFSET +
+				((QUEUE_1_SIZE - 1) * ICSS_BLOCK_SIZE),
+			P2_Q1_BD_OFFSET,
+			P2_Q1_BD_OFFSET + ((QUEUE_1_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE2] = {
+			P2_Q2_BUFFER_OFFSET,
+			P2_Q2_BUFFER_OFFSET +
+				((QUEUE_2_SIZE - 1) * ICSS_BLOCK_SIZE),
+			P2_Q2_BD_OFFSET,
+			P2_Q2_BD_OFFSET + ((QUEUE_2_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE3] = {
+			P2_Q3_BUFFER_OFFSET,
+			P2_Q3_BUFFER_OFFSET +
+				((QUEUE_3_SIZE - 1) * ICSS_BLOCK_SIZE),
+			P2_Q3_BD_OFFSET,
+			P2_Q3_BD_OFFSET + ((QUEUE_3_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE4] = {
+			P2_Q4_BUFFER_OFFSET,
+			P2_Q4_BUFFER_OFFSET +
+				((QUEUE_4_SIZE - 1) * ICSS_BLOCK_SIZE),
+			P2_Q4_BD_OFFSET,
+			P2_Q4_BD_OFFSET + ((QUEUE_4_SIZE - 1) * BD_SIZE),
+		},
+	},
+};
+
+static const struct prueth_queue_info rx_queue_infos[][NUM_QUEUES] = {
+	[PRUETH_PORT_QUEUE_HOST] = {
+		[PRUETH_QUEUE1] = {
+			P0_Q1_BUFFER_OFFSET,
+			HOST_QUEUE_DESC_OFFSET,
+			P0_Q1_BD_OFFSET,
+			P0_Q1_BD_OFFSET + ((HOST_QUEUE_1_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE2] = {
+			P0_Q2_BUFFER_OFFSET,
+			HOST_QUEUE_DESC_OFFSET + 8,
+			P0_Q2_BD_OFFSET,
+			P0_Q2_BD_OFFSET + ((HOST_QUEUE_2_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE3] = {
+			P0_Q3_BUFFER_OFFSET,
+			HOST_QUEUE_DESC_OFFSET + 16,
+			P0_Q3_BD_OFFSET,
+			P0_Q3_BD_OFFSET + ((HOST_QUEUE_3_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE4] = {
+			P0_Q4_BUFFER_OFFSET,
+			HOST_QUEUE_DESC_OFFSET + 24,
+			P0_Q4_BD_OFFSET,
+			P0_Q4_BD_OFFSET + ((HOST_QUEUE_4_SIZE - 1) * BD_SIZE),
+		},
+	},
+	[PRUETH_PORT_QUEUE_MII0] = {
+		[PRUETH_QUEUE1] = {
+			P1_Q1_BUFFER_OFFSET,
+			P1_QUEUE_DESC_OFFSET,
+			P1_Q1_BD_OFFSET,
+			P1_Q1_BD_OFFSET + ((QUEUE_1_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE2] = {
+			P1_Q2_BUFFER_OFFSET,
+			P1_QUEUE_DESC_OFFSET + 8,
+			P1_Q2_BD_OFFSET,
+			P1_Q2_BD_OFFSET + ((QUEUE_2_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE3] = {
+			P1_Q3_BUFFER_OFFSET,
+			P1_QUEUE_DESC_OFFSET + 16,
+			P1_Q3_BD_OFFSET,
+			P1_Q3_BD_OFFSET + ((QUEUE_3_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE4] = {
+			P1_Q4_BUFFER_OFFSET,
+			P1_QUEUE_DESC_OFFSET + 24,
+			P1_Q4_BD_OFFSET,
+			P1_Q4_BD_OFFSET + ((QUEUE_4_SIZE - 1) * BD_SIZE),
+		},
+	},
+	[PRUETH_PORT_QUEUE_MII1] = {
+		[PRUETH_QUEUE1] = {
+			P2_Q1_BUFFER_OFFSET,
+			P2_QUEUE_DESC_OFFSET,
+			P2_Q1_BD_OFFSET,
+			P2_Q1_BD_OFFSET + ((QUEUE_1_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE2] = {
+			P2_Q2_BUFFER_OFFSET,
+			P2_QUEUE_DESC_OFFSET + 8,
+			P2_Q2_BD_OFFSET,
+			P2_Q2_BD_OFFSET + ((QUEUE_2_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE3] = {
+			P2_Q3_BUFFER_OFFSET,
+			P2_QUEUE_DESC_OFFSET + 16,
+			P2_Q3_BD_OFFSET,
+			P2_Q3_BD_OFFSET + ((QUEUE_3_SIZE - 1) * BD_SIZE),
+		},
+		[PRUETH_QUEUE4] = {
+			P2_Q4_BUFFER_OFFSET,
+			P2_QUEUE_DESC_OFFSET + 24,
+			P2_Q4_BD_OFFSET,
+			P2_Q4_BD_OFFSET + ((QUEUE_4_SIZE - 1) * BD_SIZE),
+		},
+	},
+};
+
 void icssm_prueth_sw_free_fdb_table(struct prueth *prueth)
 {
 	if (prueth->emac_configured)
@@ -678,3 +848,218 @@ int icssm_prueth_sw_purge_fdb(struct prueth_emac *emac)
 	queue_work(system_long_wq, &fdb_work->work);
 	return 0;
 }
+
+void icssm_prueth_sw_hostconfig(struct prueth *prueth)
+{
+	void __iomem *dram1_base = prueth->mem[PRUETH_MEM_DRAM1].va;
+	void __iomem *dram;
+
+	/* queue information table */
+	dram = dram1_base + P0_Q1_RX_CONTEXT_OFFSET;
+	memcpy_toio(dram, sw_queue_infos[PRUETH_PORT_QUEUE_HOST],
+		    sizeof(sw_queue_infos[PRUETH_PORT_QUEUE_HOST]));
+
+	/* buffer descriptor offset table*/
+	dram = dram1_base + QUEUE_DESCRIPTOR_OFFSET_ADDR;
+	writew(P0_Q1_BD_OFFSET, dram);
+	writew(P0_Q2_BD_OFFSET, dram + 2);
+	writew(P0_Q3_BD_OFFSET, dram + 4);
+	writew(P0_Q4_BD_OFFSET, dram + 6);
+
+	/* buffer offset table */
+	dram = dram1_base + QUEUE_OFFSET_ADDR;
+	writew(P0_Q1_BUFFER_OFFSET, dram);
+	writew(P0_Q2_BUFFER_OFFSET, dram + 2);
+	writew(P0_Q3_BUFFER_OFFSET, dram + 4);
+	writew(P0_Q4_BUFFER_OFFSET, dram + 6);
+
+	/* queue size lookup table */
+	dram = dram1_base + QUEUE_SIZE_ADDR;
+	writew(HOST_QUEUE_1_SIZE, dram);
+	writew(HOST_QUEUE_1_SIZE, dram + 2);
+	writew(HOST_QUEUE_1_SIZE, dram + 4);
+	writew(HOST_QUEUE_1_SIZE, dram + 6);
+
+	/* queue table */
+	dram = dram1_base + P0_QUEUE_DESC_OFFSET;
+	memcpy_toio(dram, queue_descs[PRUETH_PORT_QUEUE_HOST],
+		    sizeof(queue_descs[PRUETH_PORT_QUEUE_HOST]));
+}
+
+static int icssm_prueth_sw_port_config(struct prueth *prueth,
+				       enum prueth_port port_id)
+{
+	unsigned int tx_context_ofs_addr, rx_context_ofs, queue_desc_ofs;
+	void __iomem *dram, *dram_base, *dram_mac;
+	struct prueth_emac *emac;
+	void __iomem *dram1_base;
+
+	dram1_base = prueth->mem[PRUETH_MEM_DRAM1].va;
+	emac = prueth->emac[port_id - 1];
+	switch (port_id) {
+	case PRUETH_PORT_MII0:
+		tx_context_ofs_addr     = TX_CONTEXT_P1_Q1_OFFSET_ADDR;
+		rx_context_ofs          = P1_Q1_RX_CONTEXT_OFFSET;
+		queue_desc_ofs          = P1_QUEUE_DESC_OFFSET;
+
+		/* for switch PORT MII0 mac addr is in DRAM0. */
+		dram_mac = prueth->mem[PRUETH_MEM_DRAM0].va;
+		break;
+	case PRUETH_PORT_MII1:
+		tx_context_ofs_addr     = TX_CONTEXT_P2_Q1_OFFSET_ADDR;
+		rx_context_ofs          = P2_Q1_RX_CONTEXT_OFFSET;
+		queue_desc_ofs          = P2_QUEUE_DESC_OFFSET;
+
+		/* for switch PORT MII1 mac addr is in DRAM1. */
+		dram_mac = prueth->mem[PRUETH_MEM_DRAM1].va;
+		break;
+	default:
+		netdev_err(emac->ndev, "invalid port\n");
+		return -EINVAL;
+	}
+
+	/* setup mac address */
+	memcpy_toio(dram_mac + PORT_MAC_ADDR, emac->mac_addr, 6);
+
+	/* Remaining switch port configs are in DRAM1 */
+	dram_base = prueth->mem[PRUETH_MEM_DRAM1].va;
+
+	/* queue information table */
+	memcpy_toio(dram_base + tx_context_ofs_addr,
+		    sw_queue_infos[port_id],
+		    sizeof(sw_queue_infos[port_id]));
+
+	memcpy_toio(dram_base + rx_context_ofs,
+		    rx_queue_infos[port_id],
+		    sizeof(rx_queue_infos[port_id]));
+
+	/* buffer descriptor offset table*/
+	dram = dram_base + QUEUE_DESCRIPTOR_OFFSET_ADDR +
+	       (port_id * NUM_QUEUES * sizeof(u16));
+	writew(sw_queue_infos[port_id][PRUETH_QUEUE1].buffer_desc_offset, dram);
+	writew(sw_queue_infos[port_id][PRUETH_QUEUE2].buffer_desc_offset,
+	       dram + 2);
+	writew(sw_queue_infos[port_id][PRUETH_QUEUE3].buffer_desc_offset,
+	       dram + 4);
+	writew(sw_queue_infos[port_id][PRUETH_QUEUE4].buffer_desc_offset,
+	       dram + 6);
+
+	/* buffer offset table */
+	dram = dram_base + QUEUE_OFFSET_ADDR +
+	       port_id * NUM_QUEUES * sizeof(u16);
+	writew(sw_queue_infos[port_id][PRUETH_QUEUE1].buffer_offset, dram);
+	writew(sw_queue_infos[port_id][PRUETH_QUEUE2].buffer_offset,
+	       dram + 2);
+	writew(sw_queue_infos[port_id][PRUETH_QUEUE3].buffer_offset,
+	       dram + 4);
+	writew(sw_queue_infos[port_id][PRUETH_QUEUE4].buffer_offset,
+	       dram + 6);
+
+	/* queue size lookup table */
+	dram = dram_base + QUEUE_SIZE_ADDR +
+	       port_id * NUM_QUEUES * sizeof(u16);
+	writew(QUEUE_1_SIZE, dram);
+	writew(QUEUE_2_SIZE, dram + 2);
+	writew(QUEUE_3_SIZE, dram + 4);
+	writew(QUEUE_4_SIZE, dram + 6);
+
+	/* queue table */
+	memcpy_toio(dram_base + queue_desc_ofs,
+		    &queue_descs[port_id][0],
+		    4 * sizeof(queue_descs[port_id][0]));
+
+	emac->rx_queue_descs = dram1_base + P0_QUEUE_DESC_OFFSET;
+	emac->tx_queue_descs = dram1_base +
+		rx_queue_infos[port_id][PRUETH_QUEUE1].queue_desc_offset;
+
+	return 0;
+}
+
+int icssm_prueth_sw_emac_config(struct prueth_emac *emac)
+{
+	struct prueth *prueth = emac->prueth;
+	u32 sharedramaddr, ocmcaddr;
+	int ret;
+
+	/* PRU needs local shared RAM address for C28 */
+	sharedramaddr = ICSS_LOCAL_SHARED_RAM;
+	/* PRU needs real global OCMC address for C30*/
+	ocmcaddr = (u32)prueth->mem[PRUETH_MEM_OCMC].pa;
+
+	if (prueth->emac_configured & BIT(emac->port_id))
+		return 0;
+
+	ret = icssm_prueth_sw_port_config(prueth, emac->port_id);
+	if (ret)
+		return ret;
+
+	if (!prueth->emac_configured) {
+		/* Set in constant table C28 of PRUn to ICSS Shared memory */
+		pru_rproc_set_ctable(prueth->pru0, PRU_C28, sharedramaddr);
+		pru_rproc_set_ctable(prueth->pru1, PRU_C28, sharedramaddr);
+
+		/* Set in constant table C30 of PRUn to OCMC memory */
+		pru_rproc_set_ctable(prueth->pru0, PRU_C30, ocmcaddr);
+		pru_rproc_set_ctable(prueth->pru1, PRU_C30, ocmcaddr);
+	}
+	return 0;
+}
+
+int icssm_prueth_sw_boot_prus(struct prueth *prueth, struct net_device *ndev)
+{
+	const struct prueth_firmware *pru_firmwares;
+	const char *fw_name, *fw_name1;
+	int ret;
+
+	if (prueth->emac_configured)
+		return 0;
+
+	pru_firmwares = &prueth->fw_data->fw_pru[PRUSS_PRU0];
+	fw_name = pru_firmwares->fw_name[prueth->eth_type];
+	pru_firmwares = &prueth->fw_data->fw_pru[PRUSS_PRU1];
+	fw_name1 = pru_firmwares->fw_name[prueth->eth_type];
+
+	ret = rproc_set_firmware(prueth->pru0, fw_name);
+	if (ret) {
+		netdev_err(ndev, "failed to set PRU0 firmware %s: %d\n",
+			   fw_name, ret);
+		return ret;
+	}
+	ret = rproc_boot(prueth->pru0);
+	if (ret) {
+		netdev_err(ndev, "failed to boot PRU0: %d\n", ret);
+		return ret;
+	}
+
+	ret = rproc_set_firmware(prueth->pru1, fw_name1);
+	if (ret) {
+		netdev_err(ndev, "failed to set PRU1 firmware %s: %d\n",
+			   fw_name1, ret);
+		goto rproc0_shutdown;
+	}
+	ret = rproc_boot(prueth->pru1);
+	if (ret) {
+		netdev_err(ndev, "failed to boot PRU1: %d\n", ret);
+		goto rproc0_shutdown;
+	}
+
+	return 0;
+
+rproc0_shutdown:
+	rproc_shutdown(prueth->pru0);
+	return ret;
+}
+
+int icssm_prueth_sw_shutdown_prus(struct prueth_emac *emac,
+				  struct net_device *ndev)
+{
+	struct prueth *prueth = emac->prueth;
+
+	if (prueth->emac_configured)
+		return 0;
+
+	rproc_shutdown(prueth->pru0);
+	rproc_shutdown(prueth->pru1);
+
+	return 0;
+}
diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h
index 218cbe1d3c50..e6111bba166e 100644
--- a/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h
@@ -16,6 +16,8 @@ void icssm_prueth_sw_set_stp_state(struct prueth *prueth,
 u8 icssm_prueth_sw_get_stp_state(struct prueth *prueth,
 				 enum prueth_port port);
 
+extern const struct prueth_queue_info sw_queue_infos[][4];
+
 void icssm_prueth_sw_fdb_tbl_init(struct prueth *prueth);
 int icssm_prueth_sw_init_fdb_table(struct prueth *prueth);
 void icssm_prueth_sw_free_fdb_table(struct prueth *prueth);
@@ -26,4 +28,10 @@ void icssm_prueth_sw_fdb_del(struct prueth_emac *emac,
 			     struct switchdev_notifier_fdb_info *fdb);
 int icssm_prueth_sw_learn_fdb(struct prueth_emac *emac, u8 *src_mac);
 int icssm_prueth_sw_purge_fdb(struct prueth_emac *emac);
+void icssm_prueth_sw_hostconfig(struct prueth *prueth);
+int icssm_prueth_sw_emac_config(struct prueth_emac *emac);
+int icssm_prueth_sw_boot_prus(struct prueth *prueth, struct net_device *ndev);
+int icssm_prueth_sw_shutdown_prus(struct prueth_emac *emac,
+				  struct net_device *ndev);
+
 #endif /* __NET_TI_PRUETH_SWITCH_H */
diff --git a/drivers/net/ethernet/ti/icssm/icssm_switch.h b/drivers/net/ethernet/ti/icssm/icssm_switch.h
index 4200ccb1b425..5ba9ce14da44 100644
--- a/drivers/net/ethernet/ti/icssm/icssm_switch.h
+++ b/drivers/net/ethernet/ti/icssm/icssm_switch.h
@@ -117,6 +117,15 @@
 #define STATISTICS_OFFSET	0x1F00
 #define STAT_SIZE		0x98
 
+/* The following offsets indicate which sections of the memory are used
+ * for switch internal tasks
+ */
+#define SWITCH_SPECIFIC_DRAM0_START_SIZE		0x100
+#define SWITCH_SPECIFIC_DRAM0_START_OFFSET		0x1F00
+
+#define SWITCH_SPECIFIC_DRAM1_START_SIZE		0x300
+#define SWITCH_SPECIFIC_DRAM1_START_OFFSET		0x1D00
+
 /* Offset for storing
  * 1. Storm Prevention Params
  * 2. PHY Speed Offset
@@ -146,6 +155,74 @@
 /* 4 bytes ? */
 #define STP_INVALID_STATE_OFFSET	(STATISTICS_OFFSET + STAT_SIZE + 33)
 
+/* DRAM1 Offsets for Switch */
+/* 4 queue descriptors for port 0 (host receive) */
+#define P0_QUEUE_DESC_OFFSET		0x1E7C
+#define P1_QUEUE_DESC_OFFSET		0x1E9C
+#define P2_QUEUE_DESC_OFFSET		0x1EBC
+/* collision descriptor of port 0 */
+#define P0_COL_QUEUE_DESC_OFFSET	0x1E64
+#define P1_COL_QUEUE_DESC_OFFSET	0x1E6C
+#define P2_COL_QUEUE_DESC_OFFSET	0x1E74
+/* Collision Status Register
+ *    P0: bit 0 is pending flag, bit 1..2 indicates which queue,
+ *    P1: bit 8 is pending flag, 9..10 is queue number
+ *    P2: bit 16 is pending flag, 17..18 is queue number, remaining bits are 0.
+ */
+#define COLLISION_STATUS_ADDR		0x1E60
+
+#define INTERFACE_MAC_ADDR		0x1E58
+#define P2_MAC_ADDR			0x1E50
+#define P1_MAC_ADDR			0x1E48
+
+#define QUEUE_SIZE_ADDR			0x1E30
+#define QUEUE_OFFSET_ADDR		0x1E18
+#define QUEUE_DESCRIPTOR_OFFSET_ADDR	0x1E00
+
+#define COL_RX_CONTEXT_P2_OFFSET_ADDR	(COL_RX_CONTEXT_P1_OFFSET_ADDR + 12)
+#define COL_RX_CONTEXT_P1_OFFSET_ADDR	(COL_RX_CONTEXT_P0_OFFSET_ADDR + 12)
+#define COL_RX_CONTEXT_P0_OFFSET_ADDR	(P2_Q4_RX_CONTEXT_OFFSET + 8)
+
+/* Port 2 Rx Context */
+#define P2_Q4_RX_CONTEXT_OFFSET		(P2_Q3_RX_CONTEXT_OFFSET + 8)
+#define P2_Q3_RX_CONTEXT_OFFSET		(P2_Q2_RX_CONTEXT_OFFSET + 8)
+#define P2_Q2_RX_CONTEXT_OFFSET		(P2_Q1_RX_CONTEXT_OFFSET + 8)
+#define P2_Q1_RX_CONTEXT_OFFSET		RX_CONTEXT_P2_Q1_OFFSET_ADDR
+#define RX_CONTEXT_P2_Q1_OFFSET_ADDR	(P1_Q4_RX_CONTEXT_OFFSET + 8)
+
+/* Port 1 Rx Context */
+#define P1_Q4_RX_CONTEXT_OFFSET		(P1_Q3_RX_CONTEXT_OFFSET + 8)
+#define P1_Q3_RX_CONTEXT_OFFSET		(P1_Q2_RX_CONTEXT_OFFSET + 8)
+#define P1_Q2_RX_CONTEXT_OFFSET		(P1_Q1_RX_CONTEXT_OFFSET + 8)
+#define P1_Q1_RX_CONTEXT_OFFSET		(RX_CONTEXT_P1_Q1_OFFSET_ADDR)
+#define RX_CONTEXT_P1_Q1_OFFSET_ADDR	(P0_Q4_RX_CONTEXT_OFFSET + 8)
+
+/* Host Port Rx Context */
+#define P0_Q4_RX_CONTEXT_OFFSET		(P0_Q3_RX_CONTEXT_OFFSET + 8)
+#define P0_Q3_RX_CONTEXT_OFFSET		(P0_Q2_RX_CONTEXT_OFFSET + 8)
+#define P0_Q2_RX_CONTEXT_OFFSET		(P0_Q1_RX_CONTEXT_OFFSET + 8)
+#define P0_Q1_RX_CONTEXT_OFFSET		RX_CONTEXT_P0_Q1_OFFSET_ADDR
+#define RX_CONTEXT_P0_Q1_OFFSET_ADDR	(COL_TX_CONTEXT_P2_Q1_OFFSET_ADDR + 8)
+
+/* Port 2 Tx Collision Context */
+#define COL_TX_CONTEXT_P2_Q1_OFFSET_ADDR (COL_TX_CONTEXT_P1_Q1_OFFSET_ADDR + 8)
+/* Port 1 Tx Collision Context */
+#define COL_TX_CONTEXT_P1_Q1_OFFSET_ADDR (P2_Q4_TX_CONTEXT_OFFSET + 8)
+
+/* Port 2 */
+#define P2_Q4_TX_CONTEXT_OFFSET		(P2_Q3_TX_CONTEXT_OFFSET + 8)
+#define P2_Q3_TX_CONTEXT_OFFSET		(P2_Q2_TX_CONTEXT_OFFSET + 8)
+#define P2_Q2_TX_CONTEXT_OFFSET		(P2_Q1_TX_CONTEXT_OFFSET + 8)
+#define P2_Q1_TX_CONTEXT_OFFSET		TX_CONTEXT_P2_Q1_OFFSET_ADDR
+#define TX_CONTEXT_P2_Q1_OFFSET_ADDR	(P1_Q4_TX_CONTEXT_OFFSET + 8)
+
+/* Port 1 */
+#define P1_Q4_TX_CONTEXT_OFFSET		(P1_Q3_TX_CONTEXT_OFFSET + 8)
+#define P1_Q3_TX_CONTEXT_OFFSET		(P1_Q2_TX_CONTEXT_OFFSET + 8)
+#define P1_Q2_TX_CONTEXT_OFFSET		(P1_Q1_TX_CONTEXT_OFFSET + 8)
+#define P1_Q1_TX_CONTEXT_OFFSET		TX_CONTEXT_P1_Q1_OFFSET_ADDR
+#define TX_CONTEXT_P1_Q1_OFFSET_ADDR	SWITCH_SPECIFIC_DRAM1_START_OFFSET
+
 /* DRAM Offsets for EMAC
  * Present on Both DRAM0 and DRAM1
  */
-- 
2.43.0



From parvathi at couthit.com  Tue Dec 16 05:22:58 2025
From: parvathi at couthit.com (Parvathi Pudi)
Date: Tue, 16 Dec 2025 18:52:58 +0530
Subject: [RFC PATCH net-next v10 1/3] net: ti: icssm-prueth: Add helper functions to configure and maintain FDB
In-Reply-To: <20251216132641.1313026-1-parvathi@couthit.com>
References: <20251216132641.1313026-1-parvathi@couthit.com>
Message-ID: <20251216132641.1313026-2-parvathi@couthit.com>

From: Roger Quadros <rogerq at ti.com>

Introduce helper functions to configure and maintain Forwarding
Database (FDB) tables to aid with the switch mode feature for PRU-ICSS
ports. The PRU-ICSS FDB is maintained such that it is always in sync with
the Linux bridge driver FDB.

The FDB is used by the driver to determine whether to flood a packet,
received from the user plane, to both ports or direct it to a specific port
using the flags in the FDB table entry.

The FDB is implemented in two main components: the Index table and the
MAC Address table. Adding, deleting, and maintaining entries are handled
by the PRUETH driver. There are two types of entries:

Dynamic: created from the received packets and are subject to aging.
Static: created by the user and these entries never age out.

8-bit hash value obtained using the source MAC address is used to identify
the index to the Index/Hash table. A bucket-based approach is used to
collate source MAC addresses with the same hash value. The Index/Hash table
holds the bucket index (16-bit value) and the number of entries in the
bucket with the same hash value (16-bit value). This table can hold up to
256 entries, with each entry consuming 4 bytes of memory. The bucket index
value points to the MAC address table indicating the start of MAC addresses
having the same hash values.

Each entry in the MAC Address table consists of:
1. 6 bytes of the MAC address,
2. 2-byte aging time, and
3. 1-byte each for port information and flags respectively.

When a new entry is added to the FDB, the hash value is calculated using an
XOR operation on the 6-byte MAC address. The result is used as an index
into the Hash/Index table to check if any entries exist. If no entries are
present, the first available empty slot in the MAC Address table is
allocated to insert this MAC address. If entries with the same hash value
are already present, the new MAC address entry is added to the MAC Address
table in such a way that it ensures all entries are grouped together and
sorted in ascending MAC address order. This approach helps efficiently
manage FDB entries.

Signed-off-by: Roger Quadros <rogerq at ti.com>
Signed-off-by: Andrew F. Davis <afd at ti.com>
Signed-off-by: Basharath Hussain Khaja <basharath at couthit.com>
Signed-off-by: Parvathi Pudi <parvathi at couthit.com>
---
 drivers/net/ethernet/ti/Makefile              |   2 +-
 drivers/net/ethernet/ti/icssm/icssm_prueth.h  |   3 +
 .../ethernet/ti/icssm/icssm_prueth_fdb_tbl.h  |  76 +++
 .../ethernet/ti/icssm/icssm_prueth_switch.c   | 603 ++++++++++++++++++
 .../ethernet/ti/icssm/icssm_prueth_switch.h   |  20 +
 drivers/net/ethernet/ti/icssm/icssm_switch.h  |  26 +
 6 files changed, 729 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ethernet/ti/icssm/icssm_prueth_fdb_tbl.h
 create mode 100644 drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c
 create mode 100644 drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h

diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile
index 93c0a4d0e33a..1fd149dd6115 100644
--- a/drivers/net/ethernet/ti/Makefile
+++ b/drivers/net/ethernet/ti/Makefile
@@ -4,7 +4,7 @@
 #
 
 obj-$(CONFIG_TI_PRUETH) += icssm-prueth.o
-icssm-prueth-y := icssm/icssm_prueth.o
+icssm-prueth-y := icssm/icssm_prueth.o icssm/icssm_prueth_switch.o
 
 obj-$(CONFIG_TI_CPSW) += cpsw-common.o
 obj-$(CONFIG_TI_DAVINCI_EMAC) += cpsw-common.o
diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.h b/drivers/net/ethernet/ti/icssm/icssm_prueth.h
index 8e7e0af08144..4b50133c5a72 100644
--- a/drivers/net/ethernet/ti/icssm/icssm_prueth.h
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.h
@@ -15,6 +15,7 @@
 
 #include "icssm_switch.h"
 #include "icssm_prueth_ptp.h"
+#include "icssm_prueth_fdb_tbl.h"
 
 /* ICSSM size of redundancy tag */
 #define ICSSM_LRE_TAG_SIZE	6
@@ -248,6 +249,8 @@ struct prueth {
 	struct prueth_emac *emac[PRUETH_NUM_MACS];
 	struct net_device *registered_netdevs[PRUETH_NUM_MACS];
 
+	struct fdb_tbl *fdb_tbl;
+
 	unsigned int eth_type;
 	size_t ocmc_ram_size;
 	u8 emac_configured;
diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth_fdb_tbl.h b/drivers/net/ethernet/ti/icssm/icssm_prueth_fdb_tbl.h
new file mode 100644
index 000000000000..9089259d96ea
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth_fdb_tbl.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019-2021 Texas Instruments Incorporated - https://www.ti.com */
+#ifndef __NET_TI_PRUSS_FDB_TBL_H
+#define __NET_TI_PRUSS_FDB_TBL_H
+
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include "icssm_prueth.h"
+
+/* 4 bytes */
+struct fdb_index_tbl_entry {
+	/* Bucket Table index of first Bucket with this MAC address */
+	u16 bucket_idx;
+	u16 bucket_entries; /* Number of entries in this bucket */
+};
+
+/* 4 * 256 = 1024 = 0x200 bytes */
+struct fdb_index_array {
+	struct fdb_index_tbl_entry index_tbl_entry[FDB_INDEX_TBL_MAX_ENTRIES];
+};
+
+/* 10 bytes */
+struct fdb_mac_tbl_entry {
+	u8  mac[ETH_ALEN];
+	u16 age;
+	u8  port; /* 0 based: 0=port1, 1=port2 */
+	union {
+		struct {
+			u8  is_static:1;
+			u8  active:1;
+		};
+		u8 flags;
+	};
+};
+
+/* 10 * 256 = 2560 = 0xa00 bytes */
+struct fdb_mac_tbl_array {
+	struct fdb_mac_tbl_entry mac_tbl_entry[FDB_MAC_TBL_MAX_ENTRIES];
+};
+
+/* 1 byte */
+struct fdb_stp_config {
+	u8  state; /* per-port STP state (defined in FW header) */
+};
+
+/* 1 byte */
+struct fdb_flood_config {
+	u8 host_flood_enable:1;
+	u8 port1_flood_enable:1;
+	u8 port2_flood_enable:1;
+};
+
+/* 2 byte */
+struct fdb_arbitration {
+	u8  host_lock;
+	u8  pru_locks;
+};
+
+struct fdb_tbl {
+	/* fdb index table */
+	struct fdb_index_array __iomem *index_a;
+	/* fdb MAC table */
+	struct fdb_mac_tbl_array __iomem *mac_tbl_a;
+	/* port 1 stp config */
+	struct fdb_stp_config __iomem *port1_stp_cfg;
+	/* port 2 stp config */
+	struct fdb_stp_config __iomem *port2_stp_cfg;
+	/* per-port flood enable */
+	struct fdb_flood_config __iomem *flood_enable_flags;
+	/* fdb locking mechanism */
+	struct fdb_arbitration __iomem *locks;
+	/* total number of entries in hash table */
+	u16 total_entries;
+};
+
+#endif
diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c
new file mode 100644
index 000000000000..79a2ea5025f6
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c
@@ -0,0 +1,603 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Texas Instruments PRUETH Switch Driver
+ *
+ * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com
+ */
+#include <linux/etherdevice.h>
+#include <linux/kernel.h>
+#include <linux/remoteproc.h>
+#include <net/switchdev.h>
+#include "icssm_prueth.h"
+#include "icssm_prueth_switch.h"
+#include "icssm_prueth_fdb_tbl.h"
+
+#define FDB_IDX_TBL_ENTRY(n) (&prueth->fdb_tbl->index_a->index_tbl_entry[n])
+
+#define FDB_MAC_TBL_ENTRY(n) (&prueth->fdb_tbl->mac_tbl_a->mac_tbl_entry[n])
+
+#define FLAG_IS_STATIC	BIT(0)
+#define FLAG_ACTIVE	BIT(1)
+
+void icssm_prueth_sw_free_fdb_table(struct prueth *prueth)
+{
+	if (prueth->emac_configured)
+		return;
+
+	kfree(prueth->fdb_tbl);
+	prueth->fdb_tbl = NULL;
+}
+
+void icssm_prueth_sw_fdb_tbl_init(struct prueth *prueth)
+{
+	struct fdb_tbl *t = prueth->fdb_tbl;
+	void __iomem *sram_base;
+	u8 val;
+
+	sram_base = prueth->mem[PRUETH_MEM_SHARED_RAM].va;
+
+	t->index_a = sram_base + V2_1_FDB_TBL_OFFSET;
+	t->mac_tbl_a = sram_base + FDB_MAC_TBL_OFFSET;
+	t->port1_stp_cfg = sram_base + FDB_PORT1_STP_CFG_OFFSET;
+	t->port2_stp_cfg = sram_base + FDB_PORT2_STP_CFG_OFFSET;
+	t->flood_enable_flags = sram_base + FDB_FLOOD_ENABLE_FLAGS_OFFSET;
+	t->locks = sram_base + FDB_LOCKS_OFFSET;
+
+	val = readb(t->flood_enable_flags);
+	/* host_flood_enable = 1 */
+	val |= BIT(0);
+	/* port1_flood_enable = 1 */
+	val |= BIT(1);
+	/* port2_flood_enable = 1 */
+	val |= BIT(2);
+	writeb(val, t->flood_enable_flags);
+
+	writeb(0, &t->locks->host_lock);
+	t->total_entries = 0;
+}
+
+static u8 icssm_pru_lock_done(struct fdb_tbl *fdb_tbl)
+{
+	return readb(&fdb_tbl->locks->pru_locks);
+}
+
+static int icssm_prueth_sw_fdb_spin_lock(struct fdb_tbl *fdb_tbl)
+{
+	u8 done;
+	int ret;
+
+	/* Take the host lock */
+	writeb(1, &fdb_tbl->locks->host_lock);
+
+	/* Wait for the PRUs to release their locks */
+	ret = read_poll_timeout(icssm_pru_lock_done, done, done == 0,
+				1, 10, false, fdb_tbl);
+	if (ret == -ETIMEDOUT)
+		writeb(0, &fdb_tbl->locks->host_lock);
+
+	return ret;
+}
+
+static void icssm_prueth_sw_fdb_spin_unlock(struct fdb_tbl *fdb_tbl)
+{
+	writeb(0, &fdb_tbl->locks->host_lock);
+}
+
+static u8 icssm_prueth_sw_fdb_hash(const u8 *mac)
+{
+	return (mac[0] ^ mac[1] ^ mac[2] ^ mac[3] ^ mac[4] ^ mac[5]);
+}
+
+static int
+icssm_prueth_sw_fdb_search(struct fdb_mac_tbl_array __iomem *mac_tbl,
+			   struct fdb_index_tbl_entry __iomem *bucket_info,
+			   const u8 *mac)
+{
+	unsigned int bucket_entries, mac_tbl_idx;
+	u8 tmp_mac[ETH_ALEN];
+	int i;
+
+	mac_tbl_idx = readw(&bucket_info->bucket_idx);
+	bucket_entries = readw(&bucket_info->bucket_entries);
+	for (i = 0; i < bucket_entries; i++, mac_tbl_idx++) {
+		memcpy_fromio(tmp_mac, mac_tbl->mac_tbl_entry[mac_tbl_idx].mac,
+			      ETH_ALEN);
+		if (ether_addr_equal(mac, tmp_mac))
+			return mac_tbl_idx;
+	}
+
+	return -ENODATA;
+}
+
+static int icssm_prueth_sw_fdb_find_open_slot(struct fdb_tbl *fdb_tbl)
+{
+	unsigned int i;
+	u8 flags;
+
+	for (i = 0; i < FDB_MAC_TBL_MAX_ENTRIES; i++) {
+		flags = readb(&fdb_tbl->mac_tbl_a->mac_tbl_entry[i].flags);
+		if (!(flags & FLAG_ACTIVE))
+			break;
+	}
+
+	return i;
+}
+
+static int
+icssm_prueth_sw_find_fdb_insert(struct fdb_tbl *fdb, struct prueth *prueth,
+				struct fdb_index_tbl_entry __iomem *bkt_info,
+				const u8 *mac, const u8 port)
+{
+	struct fdb_mac_tbl_array __iomem *mac_tbl = fdb->mac_tbl_a;
+	unsigned int bucket_entries, mac_tbl_idx;
+	struct fdb_mac_tbl_entry __iomem *e;
+	u8 mac_from_hw[ETH_ALEN];
+	s8 cmp;
+	int i;
+
+	mac_tbl_idx = readw(&bkt_info->bucket_idx);
+	bucket_entries = readw(&bkt_info->bucket_entries);
+
+	for (i = 0; i < bucket_entries; i++, mac_tbl_idx++) {
+		e = &mac_tbl->mac_tbl_entry[mac_tbl_idx];
+		memcpy_fromio(mac_from_hw, e->mac, ETH_ALEN);
+		cmp = memcmp(mac, mac_from_hw, ETH_ALEN);
+		if (cmp < 0) {
+			return mac_tbl_idx;
+		} else if (cmp == 0) {
+			if (readb(&e->port) != port) {
+				/* MAC is already in FDB, only port is
+				 * different. So just update the port.
+				 * Note: total_entries and bucket_entries
+				 * remain the same.
+				 */
+				writeb(port, &e->port);
+			}
+
+			/* MAC and port are the same, touch the fdb */
+			writew(0, &e->age);
+			return -EEXIST;
+		}
+	}
+
+	return mac_tbl_idx;
+}
+
+static int
+icssm_prueth_sw_fdb_empty_slot_left(struct fdb_mac_tbl_array __iomem *mac_tbl,
+				    unsigned int mac_tbl_idx)
+{
+	u8 flags;
+	int i;
+
+	for (i = mac_tbl_idx - 1; i > -1; i--) {
+		flags = readb(&mac_tbl->mac_tbl_entry[i].flags);
+		if (!(flags & FLAG_ACTIVE))
+			break;
+	}
+
+	return i;
+}
+
+static int
+icssm_prueth_sw_fdb_empty_slot_right(struct fdb_mac_tbl_array __iomem *mac_tbl,
+				     unsigned int mac_tbl_idx)
+{
+	u8 flags;
+	int i;
+
+	for (i = mac_tbl_idx; i < FDB_MAC_TBL_MAX_ENTRIES; i++) {
+		flags = readb(&mac_tbl->mac_tbl_entry[i].flags);
+		if (!(flags & FLAG_ACTIVE))
+			return i;
+	}
+
+	return -1;
+}
+
+static void icssm_prueth_sw_fdb_move_range_left(struct prueth *prueth,
+						u16 left, u16 right)
+{
+	struct fdb_mac_tbl_entry entry;
+	u32 sz = 0;
+	u16 i;
+
+	sz = sizeof(struct fdb_mac_tbl_entry);
+	for (i = left; i < right; i++) {
+		memcpy_fromio(&entry, FDB_MAC_TBL_ENTRY(i + 1), sz);
+		memcpy_toio(FDB_MAC_TBL_ENTRY(i), &entry, sz);
+	}
+}
+
+static void icssm_prueth_sw_fdb_move_range_right(struct prueth *prueth,
+						 u16 left, u16 right)
+{
+	struct fdb_mac_tbl_entry entry;
+	u32 sz = 0;
+	u16 i;
+
+	sz = sizeof(struct fdb_mac_tbl_entry);
+	for (i = right; i > left; i--) {
+		memcpy_fromio(&entry, FDB_MAC_TBL_ENTRY(i - 1), sz);
+		memcpy_toio(FDB_MAC_TBL_ENTRY(i), &entry, sz);
+	}
+}
+
+static void icssm_prueth_sw_fdb_update_index_tbl(struct prueth *prueth,
+						 u16 left, u16 right)
+{
+	unsigned int hash, hash_prev;
+	u8 mac[ETH_ALEN];
+	unsigned int i;
+
+	/* To ensure we don't improperly update the
+	 * bucket index, initialize with an invalid
+	 * hash in case we are in leftmost slot
+	 */
+	hash_prev = 0xff;
+
+	if (left > 0) {
+		memcpy_fromio(mac, FDB_MAC_TBL_ENTRY(left - 1)->mac, ETH_ALEN);
+		hash_prev = icssm_prueth_sw_fdb_hash(mac);
+	}
+
+	/* For each moved element, update the bucket index */
+	for (i = left; i <= right; i++) {
+		memcpy_fromio(mac, FDB_MAC_TBL_ENTRY(i)->mac, ETH_ALEN);
+		hash = icssm_prueth_sw_fdb_hash(mac);
+
+		/* Only need to update buckets once */
+		if (hash != hash_prev)
+			writew(i, &FDB_IDX_TBL_ENTRY(hash)->bucket_idx);
+
+		hash_prev = hash;
+	}
+}
+
+static struct fdb_mac_tbl_entry __iomem *
+icssm_prueth_sw_find_free_mac(struct prueth *prueth, struct fdb_index_tbl_entry
+			      __iomem *bucket_info, u8 suggested_mac_tbl_idx,
+			      bool *update_indexes, const u8 *mac)
+{
+	s16 empty_slot_idx = 0, left = 0, right = 0;
+	unsigned int mti = suggested_mac_tbl_idx;
+	struct fdb_mac_tbl_array __iomem *mt;
+	struct fdb_tbl *fdb;
+	u8 flags;
+
+	fdb = prueth->fdb_tbl;
+	mt = fdb->mac_tbl_a;
+
+	flags = readb(&FDB_MAC_TBL_ENTRY(mti)->flags);
+	if (!(flags & FLAG_ACTIVE)) {
+		/* Claim the entry */
+		flags |= FLAG_ACTIVE;
+		writeb(flags, &FDB_MAC_TBL_ENTRY(mti)->flags);
+
+		return FDB_MAC_TBL_ENTRY(mti);
+	}
+
+	if (fdb->total_entries == FDB_MAC_TBL_MAX_ENTRIES)
+		return NULL;
+
+	empty_slot_idx = icssm_prueth_sw_fdb_empty_slot_left(mt, mti);
+	if (empty_slot_idx == -1) {
+		/* Nothing available on the left. But table isn't full
+		 * so there must be space to the right,
+		 */
+		empty_slot_idx = icssm_prueth_sw_fdb_empty_slot_right(mt, mti);
+
+		/* Shift right */
+		left = mti;
+		right = empty_slot_idx;
+		icssm_prueth_sw_fdb_move_range_right(prueth, left, right);
+
+		/* Claim the entry */
+		flags = readb(&FDB_MAC_TBL_ENTRY(mti)->flags);
+		flags |= FLAG_ACTIVE;
+		writeb(flags, &FDB_MAC_TBL_ENTRY(mti)->flags);
+
+		memcpy_toio(FDB_MAC_TBL_ENTRY(mti)->mac, mac, ETH_ALEN);
+
+		/* There is a chance we moved something in a
+		 * different bucket, update index table
+		 */
+		icssm_prueth_sw_fdb_update_index_tbl(prueth, left, right);
+
+		return FDB_MAC_TBL_ENTRY(mti);
+	}
+
+	if (empty_slot_idx == mti - 1) {
+		/* There is space immediately left of the open slot,
+		 * which means the inserted MAC address
+		 * must be the lowest-valued MAC address in bucket.
+		 * Update bucket pointer accordingly.
+		 */
+		writew(empty_slot_idx, &bucket_info->bucket_idx);
+
+		/* Claim the entry */
+		flags = readb(&FDB_MAC_TBL_ENTRY(mti)->flags);
+		flags |= FLAG_ACTIVE;
+		writeb(flags, &FDB_MAC_TBL_ENTRY(mti)->flags);
+
+		return FDB_MAC_TBL_ENTRY(empty_slot_idx);
+	}
+
+	/* There is empty space to the left, shift MAC table entries left */
+	left = empty_slot_idx;
+	right = mti - 1;
+	icssm_prueth_sw_fdb_move_range_left(prueth, left, right);
+
+	/* Claim the entry */
+	flags = readb(&FDB_MAC_TBL_ENTRY(mti - 1)->flags);
+	flags |= FLAG_ACTIVE;
+	writeb(flags, &FDB_MAC_TBL_ENTRY(mti - 1)->flags);
+
+	memcpy_toio(FDB_MAC_TBL_ENTRY(mti - 1)->mac, mac, ETH_ALEN);
+
+	/* There is a chance we moved something in a
+	 * different bucket, update index table
+	 */
+	icssm_prueth_sw_fdb_update_index_tbl(prueth, left, right);
+
+	return FDB_MAC_TBL_ENTRY(mti - 1);
+}
+
+static int icssm_prueth_sw_insert_fdb_entry(struct prueth_emac *emac,
+					    const u8 *mac, u8 is_static)
+{
+	struct fdb_index_tbl_entry __iomem *bucket_info;
+	struct fdb_mac_tbl_entry __iomem *mac_info;
+	struct prueth *prueth = emac->prueth;
+	unsigned int hash_val, mac_tbl_idx;
+	struct prueth_emac *other_emac;
+	enum prueth_port other_port_id;
+	int total_fdb_entries;
+	struct fdb_tbl *fdb;
+	u8 flags;
+	s16 ret;
+	int err;
+	u16 val;
+
+	fdb = prueth->fdb_tbl;
+	other_port_id = (emac->port_id == PRUETH_PORT_MII0) ?
+			 PRUETH_PORT_MII1 : PRUETH_PORT_MII0;
+
+	other_emac = prueth->emac[other_port_id - 1];
+	if (!other_emac)
+		return -EINVAL;
+
+	err = icssm_prueth_sw_fdb_spin_lock(fdb);
+	if (err) {
+		dev_err(prueth->dev, "PRU lock timeout %d\n", err);
+		return err;
+	}
+
+	if (fdb->total_entries == FDB_MAC_TBL_MAX_ENTRIES) {
+		icssm_prueth_sw_fdb_spin_unlock(fdb);
+		return -ENOMEM;
+	}
+
+	if (ether_addr_equal(mac, emac->mac_addr) ||
+	    (ether_addr_equal(mac, other_emac->mac_addr))) {
+		icssm_prueth_sw_fdb_spin_unlock(fdb);
+		/* Don't insert fdb of own mac addr */
+		return -EINVAL;
+	}
+
+	/* Get the bucket that the mac belongs to */
+	hash_val = icssm_prueth_sw_fdb_hash(mac);
+	bucket_info = FDB_IDX_TBL_ENTRY(hash_val);
+
+	if (!readw(&bucket_info->bucket_entries)) {
+		mac_tbl_idx = icssm_prueth_sw_fdb_find_open_slot(fdb);
+		writew(mac_tbl_idx, &bucket_info->bucket_idx);
+	}
+
+	ret = icssm_prueth_sw_find_fdb_insert(fdb, prueth, bucket_info, mac,
+					      emac->port_id - 1);
+	if (ret < 0) {
+		icssm_prueth_sw_fdb_spin_unlock(fdb);
+		/* mac is already in fdb table */
+		return 0;
+	}
+
+	mac_tbl_idx = ret;
+
+	mac_info = icssm_prueth_sw_find_free_mac(prueth, bucket_info,
+						 mac_tbl_idx, NULL,
+						 mac);
+	if (!mac_info) {
+		/* Should not happen */
+		dev_warn(prueth->dev, "OUT of FDB MEM\n");
+		icssm_prueth_sw_fdb_spin_unlock(fdb);
+		return -ENOMEM;
+	}
+
+	memcpy_toio(mac_info->mac, mac, ETH_ALEN);
+	writew(0, &mac_info->age);
+	writeb(emac->port_id - 1, &mac_info->port);
+
+	flags = readb(&mac_info->flags);
+	if (is_static)
+		flags |= FLAG_IS_STATIC;
+	else
+		flags &= ~FLAG_IS_STATIC;
+
+	/* bit 1 - active */
+	flags |= FLAG_ACTIVE;
+	writeb(flags, &mac_info->flags);
+
+	val = readw(&bucket_info->bucket_entries);
+	val++;
+	writew(val, &bucket_info->bucket_entries);
+
+	fdb->total_entries++;
+
+	total_fdb_entries = fdb->total_entries;
+
+	icssm_prueth_sw_fdb_spin_unlock(fdb);
+
+	dev_dbg(prueth->dev, "added fdb: %pM port=%d total_entries=%u\n",
+		mac, emac->port_id, total_fdb_entries);
+
+	return 0;
+}
+
+static int icssm_prueth_sw_delete_fdb_entry(struct prueth_emac *emac,
+					    const u8 *mac, u8 is_static)
+{
+	struct fdb_index_tbl_entry __iomem *bucket_info;
+	struct fdb_mac_tbl_entry __iomem *mac_info;
+	struct fdb_mac_tbl_array __iomem *mt;
+	unsigned int hash_val, mac_tbl_idx;
+	unsigned int idx, entries;
+	struct prueth *prueth;
+	int total_fdb_entries;
+	s16 ret, left, right;
+	struct fdb_tbl *fdb;
+	u8 flags;
+	int err;
+	u16 val;
+
+	prueth = emac->prueth;
+	fdb = prueth->fdb_tbl;
+	mt = fdb->mac_tbl_a;
+
+	err = icssm_prueth_sw_fdb_spin_lock(fdb);
+	if (err) {
+		dev_err(prueth->dev, "PRU lock timeout %d\n", err);
+		return err;
+	}
+
+	if (fdb->total_entries == 0) {
+		icssm_prueth_sw_fdb_spin_unlock(fdb);
+		return 0;
+	}
+
+	/* Get the bucket that the mac belongs to */
+	hash_val = icssm_prueth_sw_fdb_hash(mac);
+	bucket_info = FDB_IDX_TBL_ENTRY(hash_val);
+
+	ret = icssm_prueth_sw_fdb_search(mt, bucket_info, mac);
+	if (ret < 0) {
+		icssm_prueth_sw_fdb_spin_unlock(fdb);
+		return ret;
+	}
+
+	mac_tbl_idx = ret;
+	mac_info = FDB_MAC_TBL_ENTRY(mac_tbl_idx);
+
+	/* Shift all elements in bucket to the left. No need to
+	 * update index table since only shifting within bucket.
+	 */
+	left = mac_tbl_idx;
+	idx = readw(&bucket_info->bucket_idx);
+	entries = readw(&bucket_info->bucket_entries);
+	right = idx + entries - 1;
+	icssm_prueth_sw_fdb_move_range_left(prueth, left, right);
+
+	/* Remove end of bucket from table */
+	mac_info = FDB_MAC_TBL_ENTRY(right);
+	flags = readb(&mac_info->flags);
+	/* active = 0 */
+	flags &= ~FLAG_ACTIVE;
+	writeb(flags, &mac_info->flags);
+	val = readw(&bucket_info->bucket_entries);
+	val--;
+	writew(val, &bucket_info->bucket_entries);
+	fdb->total_entries--;
+
+	total_fdb_entries = fdb->total_entries;
+
+	icssm_prueth_sw_fdb_spin_unlock(fdb);
+
+	dev_dbg(prueth->dev, "del fdb: %pM total_entries=%u\n",
+		mac, total_fdb_entries);
+
+	return 0;
+}
+
+int icssm_prueth_sw_do_purge_fdb(struct prueth_emac *emac)
+{
+	struct fdb_index_tbl_entry __iomem *bucket_info;
+	struct prueth *prueth = emac->prueth;
+	u8 flags, mac[ETH_ALEN];
+	unsigned int hash_val;
+	struct fdb_tbl *fdb;
+	int ret, i;
+	u16 val;
+
+	fdb = prueth->fdb_tbl;
+
+	ret = icssm_prueth_sw_fdb_spin_lock(fdb);
+	if (ret) {
+		dev_err(prueth->dev, "PRU lock timeout %d\n", ret);
+		return ret;
+	}
+
+	if (fdb->total_entries == 0) {
+		icssm_prueth_sw_fdb_spin_unlock(fdb);
+		return 0;
+	}
+
+	for (i = 0; i < FDB_MAC_TBL_MAX_ENTRIES; i++) {
+		flags = readb(&fdb->mac_tbl_a->mac_tbl_entry[i].flags);
+		if ((flags & FLAG_ACTIVE) && !(flags & FLAG_IS_STATIC)) {
+			/* Get the bucket that the mac belongs to */
+			memcpy_fromio(mac, FDB_MAC_TBL_ENTRY(i)->mac,
+				      ETH_ALEN);
+			hash_val = icssm_prueth_sw_fdb_hash(mac);
+			bucket_info = FDB_IDX_TBL_ENTRY(hash_val);
+			flags &= ~FLAG_ACTIVE;
+			writeb(flags,
+			       &fdb->mac_tbl_a->mac_tbl_entry[i].flags);
+			val = readw(&bucket_info->bucket_entries);
+			val--;
+			writew(val, &bucket_info->bucket_entries);
+			fdb->total_entries--;
+		}
+	}
+
+	icssm_prueth_sw_fdb_spin_unlock(fdb);
+	return 0;
+}
+
+int icssm_prueth_sw_init_fdb_table(struct prueth *prueth)
+{
+	if (prueth->emac_configured)
+		return 0;
+
+	prueth->fdb_tbl = kmalloc(sizeof(*prueth->fdb_tbl), GFP_KERNEL);
+	if (!prueth->fdb_tbl)
+		return -ENOMEM;
+
+	icssm_prueth_sw_fdb_tbl_init(prueth);
+
+	return 0;
+}
+
+/**
+ * icssm_prueth_sw_fdb_add - insert fdb entry
+ *
+ * @emac: EMAC data structure
+ * @fdb: fdb info
+ *
+ */
+void icssm_prueth_sw_fdb_add(struct prueth_emac *emac,
+			     struct switchdev_notifier_fdb_info *fdb)
+{
+	icssm_prueth_sw_insert_fdb_entry(emac, fdb->addr, 1);
+}
+
+/**
+ * icssm_prueth_sw_fdb_del - delete fdb entry
+ *
+ * @emac: EMAC data structure
+ * @fdb: fdb info
+ *
+ */
+void icssm_prueth_sw_fdb_del(struct prueth_emac *emac,
+			     struct switchdev_notifier_fdb_info *fdb)
+{
+	icssm_prueth_sw_delete_fdb_entry(emac, fdb->addr, 1);
+}
diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h
new file mode 100644
index 000000000000..fd013ecdc707
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com
+ */
+
+#ifndef __NET_TI_PRUETH_SWITCH_H
+#define __NET_TI_PRUETH_SWITCH_H
+
+#include "icssm_prueth.h"
+#include "icssm_prueth_fdb_tbl.h"
+
+void icssm_prueth_sw_fdb_tbl_init(struct prueth *prueth);
+int icssm_prueth_sw_init_fdb_table(struct prueth *prueth);
+void icssm_prueth_sw_free_fdb_table(struct prueth *prueth);
+int icssm_prueth_sw_do_purge_fdb(struct prueth_emac *emac);
+void icssm_prueth_sw_fdb_add(struct prueth_emac *emac,
+			     struct switchdev_notifier_fdb_info *fdb);
+void icssm_prueth_sw_fdb_del(struct prueth_emac *emac,
+			     struct switchdev_notifier_fdb_info *fdb);
+
+#endif /* __NET_TI_PRUETH_SWITCH_H */
diff --git a/drivers/net/ethernet/ti/icssm/icssm_switch.h b/drivers/net/ethernet/ti/icssm/icssm_switch.h
index 8b494ffdcde7..4200ccb1b425 100644
--- a/drivers/net/ethernet/ti/icssm/icssm_switch.h
+++ b/drivers/net/ethernet/ti/icssm/icssm_switch.h
@@ -254,4 +254,30 @@
 #define P0_COL_BUFFER_OFFSET	0xEE00
 #define P0_Q1_BUFFER_OFFSET	0x0000
 
+#define V2_1_FDB_TBL_LOC          PRUETH_MEM_SHARED_RAM
+#define V2_1_FDB_TBL_OFFSET       0x2000
+
+#define FDB_INDEX_TBL_MAX_ENTRIES     256
+#define FDB_MAC_TBL_MAX_ENTRIES       256
+
+#define FDB_INDEX_TBL_OFFSET    V2_1_FDB_TBL_OFFSET
+#define FDB_INDEX_TBL_SIZE      (FDB_INDEX_TBL_MAX_ENTRIES * \
+				 sizeof(struct fdb_index_tbl_entry))
+
+#define FDB_MAC_TBL_OFFSET      (FDB_INDEX_TBL_OFFSET + FDB_INDEX_TBL_SIZE)
+#define FDB_MAC_TBL_SIZE        (FDB_MAC_TBL_MAX_ENTRIES * \
+				 sizeof(struct fdb_mac_tbl_entry))
+
+#define FDB_PORT1_STP_CFG_OFFSET        (FDB_MAC_TBL_OFFSET + FDB_MAC_TBL_SIZE)
+#define FDB_PORT_STP_CFG_SIZE           sizeof(struct fdb_stp_config)
+#define FDB_PORT2_STP_CFG_OFFSET        (FDB_PORT1_STP_CFG_OFFSET + \
+					 FDB_PORT_STP_CFG_SIZE)
+
+#define FDB_FLOOD_ENABLE_FLAGS_OFFSET   (FDB_PORT2_STP_CFG_OFFSET + \
+					FDB_PORT_STP_CFG_SIZE)
+#define FDB_FLOOD_ENABLE_FLAGS_SIZE     sizeof(struct fdb_flood_config)
+
+#define FDB_LOCKS_OFFSET        (FDB_FLOOD_ENABLE_FLAGS_OFFSET + \
+				 FDB_FLOOD_ENABLE_FLAGS_SIZE)
+
 #endif /* __ICSS_SWITCH_H */
-- 
2.43.0



From alexander.stein at ew.tq-group.com  Tue Dec 16 05:31:04 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Tue, 16 Dec 2025 14:31:04 +0100
Subject: [PATCH 1/4] arm64: dts: imx8mm-tqma8mqml: remove virtual 3.3V regulator
Message-ID: <20251216133110.905950-1-alexander.stein@ew.tq-group.com>

From: Markus Niebel <Markus.Niebel at ew.tq-group.com>

BUCK4 rail supplies the 3.3V rail. Use the actual regulator
instead of a virtual fixed regulator.

Signed-off-by: Markus Niebel <Markus.Niebel at ew.tq-group.com>
Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 .../arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi | 14 +++-----------
 1 file changed, 3 insertions(+), 11 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi
index b82e9790ea205..16ed8ce5b5c49 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi
@@ -24,14 +24,6 @@ reg_vcc1v8: regulator-vcc1v8 {
 		regulator-max-microvolt = <1800000>;
 	};
 
-	/* identical to buck4_reg, but should never change */
-	reg_vcc3v3: regulator-vcc3v3 {
-		compatible = "regulator-fixed";
-		regulator-name = "TQMA8MXML_VCC3V3";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-	};
-
 	reserved-memory {
 		#address-cells = <2>;
 		#size-cells = <2>;
@@ -223,14 +215,14 @@ eeprom1: eeprom at 53 {
 		read-only;
 		reg = <0x53>;
 		pagesize = <16>;
-		vcc-supply = <&reg_vcc3v3>;
+		vcc-supply = <&buck4_reg>;
 	};
 
 	eeprom0: eeprom at 57 {
 		compatible = "atmel,24c64";
 		reg = <0x57>;
 		pagesize = <32>;
-		vcc-supply = <&reg_vcc3v3>;
+		vcc-supply = <&buck4_reg>;
 	};
 };
 
@@ -253,7 +245,7 @@ &usdhc3 {
 	non-removable;
 	no-sd;
 	no-sdio;
-	vmmc-supply = <&reg_vcc3v3>;
+	vmmc-supply = <&buck4_reg>;
 	vqmmc-supply = <&reg_vcc1v8>;
 	status = "okay";
 };
-- 
2.43.0



From alexander.stein at ew.tq-group.com  Tue Dec 16 05:31:07 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Tue, 16 Dec 2025 14:31:07 +0100
Subject: [PATCH 4/4] arm64: dts: imx8mm-tqma8mqml: fix LDO5 power off
In-Reply-To: <20251216133110.905950-1-alexander.stein@ew.tq-group.com>
References: <20251216133110.905950-1-alexander.stein@ew.tq-group.com>
Message-ID: <20251216133110.905950-4-alexander.stein@ew.tq-group.com>

From: Markus Niebel <Markus.Niebel at ew.tq-group.com>

Fix SD card removal caused by automatic LDO5 power off after boot.

To prevent this, add vqmmc regulator for USDHC, using a GPIO-controlled
regulator that is supplied by LDO5. Since this is implemented on SoM but
used on baseboards with SD-card interface, implement the functionality
on SoM part and optionally enable it on baseboards if needed.

Signed-off-by: Markus Niebel <Markus.Niebel at ew.tq-group.com>
Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 .../dts/freescale/imx8mm-tqma8mqml-mba8mx.dts | 13 ++++++-----
 .../boot/dts/freescale/imx8mm-tqma8mqml.dtsi  | 22 +++++++++++++++++++
 2 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml-mba8mx.dts b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml-mba8mx.dts
index b941c8c4f7bb4..8dcc5cbcb8f66 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml-mba8mx.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml-mba8mx.dts
@@ -101,6 +101,10 @@ &pcie0 {
 	status = "okay";
 };
 
+&reg_usdhc2_vqmmc {
+	status = "okay";
+};
+
 &sai3 {
 	assigned-clocks = <&clk IMX8MM_CLK_SAI3>;
 	assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>;
@@ -276,8 +280,7 @@ pinctrl_usdhc2: usdhc2grp {
 			   <MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0		0x1d4>,
 			   <MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1		0x1d4>,
 			   <MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2		0x1d4>,
-			   <MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3		0x1d4>,
-			   <MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x84>;
+			   <MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3		0x1d4>;
 	};
 
 	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
@@ -286,8 +289,7 @@ pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
 			   <MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0		0x1d4>,
 			   <MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1		0x1d4>,
 			   <MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2		0x1d4>,
-			   <MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3		0x1d4>,
-			   <MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x84>;
+			   <MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3		0x1d4>;
 	};
 
 	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
@@ -296,7 +298,6 @@ pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
 			   <MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0		0x1d4>,
 			   <MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1		0x1d4>,
 			   <MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2		0x1d4>,
-			   <MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3		0x1d4>,
-			   <MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x84>;
+			   <MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3		0x1d4>;
 	};
 };
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi
index 2e3860a5f4fd2..29b298af0d739 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi
@@ -16,6 +16,20 @@ memory at 40000000 {
 		reg = <0x00000000 0x40000000 0 0x40000000>;
 	};
 
+	reg_usdhc2_vqmmc: regulator-usdhc2-vqmmc {
+		compatible = "regulator-gpio";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_reg_usdhc2_vqmmc>;
+		regulator-name = "V_SD2";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <3300000>;
+		gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
+		states = <1800000 0x1>,
+			 <3300000 0x0>;
+		vin-supply = <&ldo5_reg>;
+		status = "disabled";
+	};
+
 	reserved-memory {
 		#address-cells = <2>;
 		#size-cells = <2>;
@@ -227,6 +241,10 @@ &pcie_phy {
 	fsl,clkreq-unsupported;
 };
 
+&usdhc2 {
+	vqmmc-supply = <&reg_usdhc2_vqmmc>;
+};
+
 &usdhc3 {
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
 	pinctrl-0 = <&pinctrl_usdhc3>;
@@ -281,6 +299,10 @@ pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
 		fsl,pins = <MX8MM_IOMUXC_SD2_RESET_B_GPIO2_IO19		0x84>;
 	};
 
+	pinctrl_reg_usdhc2_vqmmc: regusdhc2vqmmcgrp {
+		fsl,pins = <MX8MM_IOMUXC_GPIO1_IO04_GPIO1_IO4		0xc0>;
+	};
+
 	pinctrl_usdhc3: usdhc3grp {
 		fsl,pins = <MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK		0x1d4>,
 			   <MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d2>,
-- 
2.43.0



From alexander.stein at ew.tq-group.com  Tue Dec 16 05:31:05 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Tue, 16 Dec 2025 14:31:05 +0100
Subject: [PATCH 2/4] arm64: dts: imx8mm-tqma8mqml: remove virtual 1.8V regulator
In-Reply-To: <20251216133110.905950-1-alexander.stein@ew.tq-group.com>
References: <20251216133110.905950-1-alexander.stein@ew.tq-group.com>
Message-ID: <20251216133110.905950-2-alexander.stein@ew.tq-group.com>

From: Markus Niebel <Markus.Niebel at ew.tq-group.com>

BUCK5 regulator supplies the 1.8V rail. Use the actual regulator
instead of a virtual fixed regulator.

Signed-off-by: Markus Niebel <Markus.Niebel at ew.tq-group.com>
Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi
index 16ed8ce5b5c49..6e63cf8beadcd 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi
@@ -16,14 +16,6 @@ memory at 40000000 {
 		reg = <0x00000000 0x40000000 0 0x40000000>;
 	};
 
-	/* e-MMC IO, needed for HS modes */
-	reg_vcc1v8: regulator-vcc1v8 {
-		compatible = "regulator-fixed";
-		regulator-name = "TQMA8MXML_VCC1V8";
-		regulator-min-microvolt = <1800000>;
-		regulator-max-microvolt = <1800000>;
-	};
-
 	reserved-memory {
 		#address-cells = <2>;
 		#size-cells = <2>;
@@ -246,7 +238,7 @@ &usdhc3 {
 	no-sd;
 	no-sdio;
 	vmmc-supply = <&buck4_reg>;
-	vqmmc-supply = <&reg_vcc1v8>;
+	vqmmc-supply = <&buck5_reg>;
 	status = "okay";
 };
 
-- 
2.43.0



From alexander.stein at ew.tq-group.com  Tue Dec 16 05:31:06 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Tue, 16 Dec 2025 14:31:06 +0100
Subject: [PATCH 3/4] arm64: dts: imx8mm-tqma8mqml: remove superfluous line
In-Reply-To: <20251216133110.905950-1-alexander.stein@ew.tq-group.com>
References: <20251216133110.905950-1-alexander.stein@ew.tq-group.com>
Message-ID: <20251216133110.905950-3-alexander.stein@ew.tq-group.com>

From: Markus Niebel <Markus.Niebel at ew.tq-group.com>

Remove one empty line that is not needed.

Signed-off-by: Markus Niebel <Markus.Niebel at ew.tq-group.com>
Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi | 1 -
 1 file changed, 1 deletion(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi
index 6e63cf8beadcd..2e3860a5f4fd2 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi
@@ -195,7 +195,6 @@ ldo5_reg: LDO5 {
 		};
 	};
 
-
 	pcf85063: rtc at 51 {
 		compatible = "nxp,pcf85063a";
 		reg = <0x51>;
-- 
2.43.0



From alexander.stein at ew.tq-group.com  Tue Dec 16 05:39:24 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Tue, 16 Dec 2025 14:39:24 +0100
Subject: [PATCH 2/3] arm64: dts: imx8mn-tqma8mqnl: remove virtual 1.8V regulator
In-Reply-To: <20251216133927.913039-1-alexander.stein@ew.tq-group.com>
References: <20251216133927.913039-1-alexander.stein@ew.tq-group.com>
Message-ID: <20251216133927.913039-2-alexander.stein@ew.tq-group.com>

From: Markus Niebel <Markus.Niebel at ew.tq-group.com>

BUCK5 regulator supplies the 1.8V rail. Use the actual regulator
instead of a virtual fixed regulator.

Signed-off-by: Markus Niebel <Markus.Niebel at ew.tq-group.com>
Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi
index 34d6415348f8c..ac6ce5d814c50 100644
--- a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi
@@ -15,14 +15,6 @@ memory at 40000000 {
 		reg = <0x00000000 0x40000000 0 0x40000000>;
 	};
 
-	/* e-MMC IO, needed for HS modes */
-	reg_vcc1v8: regulator-vcc1v8 {
-		compatible = "regulator-fixed";
-		regulator-name = "TQMA8MXNL_VCC1V8";
-		regulator-min-microvolt = <1800000>;
-		regulator-max-microvolt = <1800000>;
-	};
-
 	reserved-memory {
 		#address-cells = <2>;
 		#size-cells = <2>;
@@ -236,7 +228,7 @@ &usdhc3 {
 	no-sd;
 	no-sdio;
 	vmmc-supply = <&buck4_reg>;
-	vqmmc-supply = <&reg_vcc1v8>;
+	vqmmc-supply = <&buck5_reg>;
 	status = "okay";
 };
 
-- 
2.43.0



From alexander.stein at ew.tq-group.com  Tue Dec 16 05:39:23 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Tue, 16 Dec 2025 14:39:23 +0100
Subject: [PATCH 1/3] arm64: dts: imx8mn-tqma8mqnl: remove virtual 3.3V regulator
Message-ID: <20251216133927.913039-1-alexander.stein@ew.tq-group.com>

From: Markus Niebel <Markus.Niebel at ew.tq-group.com>

BUCK4 rail supplies the 3.3V rail. Use the actual regulator
instead of a virtual fixed regulator.

Signed-off-by: Markus Niebel <Markus.Niebel at ew.tq-group.com>
Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi | 13 +++----------
 1 file changed, 3 insertions(+), 10 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi
index 1d23814e11cd3..34d6415348f8c 100644
--- a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi
@@ -23,13 +23,6 @@ reg_vcc1v8: regulator-vcc1v8 {
 		regulator-max-microvolt = <1800000>;
 	};
 
-	reg_vcc3v3: regulator-vcc3v3 {
-		compatible = "regulator-fixed";
-		regulator-name = "TQMA8MXNL_VCC3V3";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-	};
-
 	reserved-memory {
 		#address-cells = <2>;
 		#size-cells = <2>;
@@ -217,14 +210,14 @@ eeprom1: eeprom at 53 {
 		read-only;
 		reg = <0x53>;
 		pagesize = <16>;
-		vcc-supply = <&reg_vcc3v3>;
+		vcc-supply = <&buck4_reg>;
 	};
 
 	eeprom0: eeprom at 57 {
 		compatible = "atmel,24c64";
 		reg = <0x57>;
 		pagesize = <32>;
-		vcc-supply = <&reg_vcc3v3>;
+		vcc-supply = <&buck4_reg>;
 	};
 };
 
@@ -242,7 +235,7 @@ &usdhc3 {
 	non-removable;
 	no-sd;
 	no-sdio;
-	vmmc-supply = <&reg_vcc3v3>;
+	vmmc-supply = <&buck4_reg>;
 	vqmmc-supply = <&reg_vcc1v8>;
 	status = "okay";
 };
-- 
2.43.0



From ardb at kernel.org  Tue Dec 16 05:40:42 2025
From: ardb at kernel.org (Ard Biesheuvel)
Date: Tue, 16 Dec 2025 14:40:42 +0100
Subject: [PATCH v3 7/9] efi: Refactor init_primary_display() helpers
In-Reply-To: <20251126160854.553077-8-tzimmermann@suse.de>
References: <20251126160854.553077-1-tzimmermann@suse.de> <20251126160854.553077-8-tzimmermann@suse.de>
Message-ID: <CAMj1kXG6cFsKwZk3a+xRrOYNz73efxjo=6Jnnr8HCKRO0X-zCQ@mail.gmail.com>

On Wed, 26 Nov 2025 at 17:09, Thomas Zimmermann <tzimmermann at suse.de> wrote:
>
> Rework the kernel's init_primary_display() helpers to allow for later
> support of additional config-table entries and EDID information. No
> functional changes.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann at suse.de>
> ---
>  arch/loongarch/kernel/efi.c     | 22 +++++++++++-----------
>  drivers/firmware/efi/efi-init.c | 19 ++++++++++---------
>  2 files changed, 21 insertions(+), 20 deletions(-)
>

This patch seems unnecessary now that we've replace one table with another.

I've dropped it for now - let me know if you really want to keep it.


> diff --git a/arch/loongarch/kernel/efi.c b/arch/loongarch/kernel/efi.c
> index 638a392d2cd2..1ef38036e8ae 100644
> --- a/arch/loongarch/kernel/efi.c
> +++ b/arch/loongarch/kernel/efi.c
> @@ -81,19 +81,19 @@ EXPORT_SYMBOL_GPL(sysfb_primary_display);
>
>  static void __init init_primary_display(void)
>  {
> -       struct screen_info *si;
> -
> -       if (screen_info_table == EFI_INVALID_TABLE_ADDR)
> -               return;
> -
> -       si = early_memremap(screen_info_table, sizeof(*si));
> -       if (!si) {
> -               pr_err("Could not map screen_info config table\n");
> +       if (screen_info_table == EFI_INVALID_TABLE_ADDR) {
> +               struct screen_info *si = early_memremap(screen_info_table, sizeof(*si));
> +
> +               if (!si) {
> +                       pr_err("Could not map screen_info config table\n");
> +                       return;
> +               }
> +               sysfb_primary_display.screen = *si;
> +               memset(si, 0, sizeof(*si));
> +               early_memunmap(si, sizeof(*si));
> +       } else {
>                 return;
>         }
> -       sysfb_primary_display.screen = *si;
> -       memset(si, 0, sizeof(*si));
> -       early_memunmap(si, sizeof(*si));
>
>         memblock_reserve(__screen_info_lfb_base(&sysfb_primary_display.screen),
>                          sysfb_primary_display.screen.lfb_size);
> diff --git a/drivers/firmware/efi/efi-init.c b/drivers/firmware/efi/efi-init.c
> index d1d418a34407..ca697d485116 100644
> --- a/drivers/firmware/efi/efi-init.c
> +++ b/drivers/firmware/efi/efi-init.c
> @@ -67,10 +67,9 @@ EXPORT_SYMBOL_GPL(sysfb_primary_display);
>
>  static void __init init_primary_display(void)
>  {
> -       struct screen_info *si;
> -
>         if (screen_info_table != EFI_INVALID_TABLE_ADDR) {
> -               si = early_memremap(screen_info_table, sizeof(*si));
> +               struct screen_info *si = early_memremap(screen_info_table, sizeof(*si));
> +
>                 if (!si) {
>                         pr_err("Could not map screen_info config table\n");
>                         return;
> @@ -78,14 +77,16 @@ static void __init init_primary_display(void)
>                 sysfb_primary_display.screen = *si;
>                 memset(si, 0, sizeof(*si));
>                 early_memunmap(si, sizeof(*si));
> +       } else {
> +               return;
> +       }
>
> -               if (memblock_is_map_memory(sysfb_primary_display.screen.lfb_base))
> -                       memblock_mark_nomap(sysfb_primary_display.screen.lfb_base,
> -                                           sysfb_primary_display.screen.lfb_size);
> +       if (memblock_is_map_memory(sysfb_primary_display.screen.lfb_base))
> +               memblock_mark_nomap(sysfb_primary_display.screen.lfb_base,
> +                                   sysfb_primary_display.screen.lfb_size);
>
> -               if (IS_ENABLED(CONFIG_EFI_EARLYCON))
> -                       efi_earlycon_reprobe();
> -       }
> +       if (IS_ENABLED(CONFIG_EFI_EARLYCON))
> +               efi_earlycon_reprobe();
>  }
>
>  static int __init uefi_init(u64 efi_system_table)
> --
> 2.51.1
>


From alexander.stein at ew.tq-group.com  Tue Dec 16 05:39:25 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Tue, 16 Dec 2025 14:39:25 +0100
Subject: [PATCH 3/3] arm64: dts: imx8mn-tqma8mqnl: fix LDO5 power off
In-Reply-To: <20251216133927.913039-1-alexander.stein@ew.tq-group.com>
References: <20251216133927.913039-1-alexander.stein@ew.tq-group.com>
Message-ID: <20251216133927.913039-3-alexander.stein@ew.tq-group.com>

From: Markus Niebel <Markus.Niebel at ew.tq-group.com>

Fix SD card removal caused by automatic LDO5 power off after boot

To prevent this, add vqmmc regulator for USDHC, using a GPIO-controlled
regulator that is supplied by LDO5. Since this is implemented on SoM but
used on baseboards with SD-card interface, implement the functionality
on SoM part and optionally enable it on baseboards if needed.

Signed-off-by: Markus Niebel <Markus.Niebel at ew.tq-group.com>
Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 .../dts/freescale/imx8mn-tqma8mqnl-mba8mx.dts | 13 ++++++-----
 .../boot/dts/freescale/imx8mn-tqma8mqnl.dtsi  | 22 +++++++++++++++++++
 2 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl-mba8mx.dts b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl-mba8mx.dts
index d7f7f9aafb7d1..0d009f4be804e 100644
--- a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl-mba8mx.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl-mba8mx.dts
@@ -69,6 +69,10 @@ &mipi_dsi {
 	samsung,esc-clock-frequency = <20000000>;
 };
 
+&reg_usdhc2_vqmmc {
+	status = "okay";
+};
+
 &sai3 {
 	assigned-clocks = <&clk IMX8MN_CLK_SAI3>;
 	assigned-clock-parents = <&clk IMX8MN_AUDIO_PLL1_OUT>;
@@ -216,8 +220,7 @@ pinctrl_usdhc2: usdhc2grp {
 			   <MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0		0x1d4>,
 			   <MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1		0x1d4>,
 			   <MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2		0x1d4>,
-			   <MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3		0x1d4>,
-			   <MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x84>;
+			   <MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3		0x1d4>;
 	};
 
 	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
@@ -226,8 +229,7 @@ pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
 			   <MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0		0x1d4>,
 			   <MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1		0x1d4>,
 			   <MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2		0x1d4>,
-			   <MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3		0x1d4>,
-			   <MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x84>;
+			   <MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3		0x1d4>;
 	};
 
 	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
@@ -236,8 +238,7 @@ pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
 			   <MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0		0x1d4>,
 			   <MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1		0x1d4>,
 			   <MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2		0x1d4>,
-			   <MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3		0x1d4>,
-			   <MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x84>;
+			   <MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3		0x1d4>;
 	};
 
 	pinctrl_usdhc2_gpio: usdhc2-gpiogrp {
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi
index ac6ce5d814c50..31a3ca137e636 100644
--- a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi
@@ -15,6 +15,20 @@ memory at 40000000 {
 		reg = <0x00000000 0x40000000 0 0x40000000>;
 	};
 
+	reg_usdhc2_vqmmc: regulator-usdhc2-vqmmc {
+		compatible = "regulator-gpio";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_reg_usdhc2_vqmmc>;
+		regulator-name = "V_SD2";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <3300000>;
+		gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
+		states = <1800000 0x1>,
+			 <3300000 0x0>;
+		vin-supply = <&ldo5_reg>;
+		status = "disabled";
+	};
+
 	reserved-memory {
 		#address-cells = <2>;
 		#size-cells = <2>;
@@ -218,6 +232,10 @@ &mipi_dsi {
 	vddio-supply = <&ldo3_reg>;
 };
 
+&usdhc2 {
+	vqmmc-supply = <&reg_usdhc2_vqmmc>;
+};
+
 &usdhc3 {
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
 	pinctrl-0 = <&pinctrl_usdhc3>;
@@ -272,6 +290,10 @@ pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
 		fsl,pins = <MX8MN_IOMUXC_SD2_RESET_B_GPIO2_IO19		0x84>;
 	};
 
+	pinctrl_reg_usdhc2_vqmmc: regusdhc2vqmmcgrp {
+		fsl,pins = <MX8MN_IOMUXC_GPIO1_IO04_GPIO1_IO4		0xc0>;
+	};
+
 	pinctrl_usdhc3: usdhc3grp {
 		fsl,pins = <MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK		0x1d4>,
 			   <MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d2>,
-- 
2.43.0



From heiko at sntech.de  Tue Dec 16 05:48:23 2025
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 16 Dec 2025 14:48:23 +0100
Subject: [PATCH v7 01/18] drm/display: bridge_connector: Ensure last bridge
 determines EDID/modes detection capabilities
In-Reply-To: <ff65f453-68a9-41fc-b9e3-02733bba96e3@rock-chips.com>
References: <20251021023130.1523707-1-damon.ding@rock-chips.com>
 <DDNXIYL494D2.2N8L1J7XTBT4S@bootlin.com>
 <ff65f453-68a9-41fc-b9e3-02733bba96e3@rock-chips.com>
Message-ID: <3351986.usQuhbGJ8B@phil>

Am Mittwoch, 22. Oktober 2025, 03:15:52 Mitteleurop?ische Normalzeit schrieb Damon Ding:
> Hi Luca,
> 
> On 10/21/2025 6:31 PM, Luca Ceresoli wrote:
> > Hello Damon,
> > 
> > On Tue Oct 21, 2025 at 4:31 AM CEST, Damon Ding wrote:

> > 
> > This does not apply on current drm-misc-next, due to the patch I mentioned
> > in a previous iteration, now applied as commit 2be300f9a0b6 ("drm/display:
> > bridge_connector: get/put the stored bridges").
> > 
> > However I'm sorry I have to mention that patch turned out being buggy, so
> > I've sent a series to apply a corrected version [0]. I suggest watching the
> > disucssion about the fix series, and if that gets approved rebase on top of
> > that and adapt your changes.
> > 
> > Sorry about the mess. :(
> > 
> > [0] https://lore.kernel.org/r/20251017-drm-bridge-alloc-getput-bridge-connector-fix-hdmi_cec-v2-0-667abf6d47c0 at bootlin.com
> > 
> > 
> 
> I saw your fix patches before sending this series. I think your patches 
> will likely be merged relatively quickly, so I plan to wait until the 
> other patches in my patch series are confirmed to be fine, then submit 
> v8 version based on the latest bridge_connector driver. :-)

I think with 6.19-rc1 out, now is a great time for v8? :-)

Heiko




From ben.horgan at arm.com  Tue Dec 16 05:49:17 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Tue, 16 Dec 2025 13:49:17 +0000
Subject: [RFC PATCH 13/38] arm_mpam: resctrl: Add CDP emulation
In-Reply-To: <20251205215901.17772-14-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-14-james.morse@arm.com>
Message-ID: <6c652963-eda0-416b-b1b3-98c5313ed5fc@arm.com>

Hi James,

On 12/5/25 21:58, James Morse wrote:
> Intel RDT's CDP feature allows the cache to use a different control value
> depending on whether the accesses was for instruction fetch or a data
> access. MPAM's equivalent feature is the other way up: the CPU assigns a
> different partid label to traffic depending on whether it was instruction
> fetch or a data access, which causes the cache to use a different control
> value based solely on the partid.
> 
> MPAM can emulate CDP, with the side effect that the alternative partid is
> seen by all MSC, it can't be enabled per-MSC.
> 
> Add the resctrl hooks to turn this on or off. Add the helpers that
> match a closid against a task, which need to be aware that the value
> written to hardware is not the same as the one resctrl is using.
> 
> Update the 'arm64_mpam_global_default' variable the arch code uses
> during context switch to know when the per-cpu value should be used
> instead.
> 
> Awkwardly, the MB controls don't implement CDP. To emulate this, the
> MPAM equivalent needs programming twice by the resctrl glue, as
> resctrl expects the bandwidth controls to be applied independently for
> both data and isntruction-fetch.
> 
> CC: Dave Martin <Dave.Martin at arm.com>
> CC: Ben Horgan <ben.horgan at arm.com>
> CC: Amit Singh Tomar <amitsinght at marvell.com>
> Signed-off-by: James Morse <james.morse at arm.com>
> ---
>  arch/arm64/include/asm/mpam.h  |   1 +
>  drivers/resctrl/mpam_resctrl.c | 115 ++++++++++++++++++++++++++++++++-
>  include/linux/arm_mpam.h       |   3 +
>  3 files changed, 118 insertions(+), 1 deletion(-)
> 
[...]
>  
> @@ -272,6 +369,7 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
>  int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
>  			    u32 closid, enum resctrl_conf_type t, u32 cfg_val)
>  {
> +	int err;
>  	u32 partid;
>  	struct mpam_config cfg;
>  	struct mpam_props *cprops;
> @@ -311,7 +409,22 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
>  		return -EINVAL;
>  	}
>  
> -	return mpam_apply_config(dom->ctrl_comp, partid, &cfg);
> +	/*
> +	 * When CDP is enabled, but the resource doesn't support it, we need to
> +	 * apply the same configuration to the other partid.
> +	 */
> +	if (mpam_resctrl_hide_cdp(r->rid)) {
> +		partid = resctrl_get_config_index(closid, CDP_CODE);
> +		err = mpam_apply_config(dom->ctrl_comp, partid, &cfg);
> +		if (err)
> +			return err;
> +
> +		partid = resctrl_get_config_index(closid, CDP_DATA);
> +		return mpam_apply_config(dom->ctrl_comp, partid, &cfg);

This is indeed awkward. As we are programming twice, if instruction and
data use b/w equally then the MB setting will be as if it was double.
However, if we halved the configured value, and most of the bandwidth
was for data, then it would be as if it was halved. For controls where
the actual parts are chosen, rather than just the size then this
programming twice will work as expected. Therefore, I think your chosen
policy is the least surprising and I'll keep this as is.

> +
> +	} else {
> +		return mpam_apply_config(dom->ctrl_comp, partid, &cfg);
> +	}
>  }
[...]

Thanks,

Ben



From ben.horgan at arm.com  Tue Dec 16 05:55:00 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Tue, 16 Dec 2025 13:55:00 +0000
Subject: [RFC PATCH 18/38] arm_mpam: resctrl: Add support for csu counters
In-Reply-To: <20251205215901.17772-19-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-19-james.morse@arm.com>
Message-ID: <192e74d8-f5c7-4214-9749-d60453477bf9@arm.com>

Hi James,

On 12/5/25 21:58, James Morse wrote:
> resctrl exposes a counter via a file named llc_occupancy. This isn't really
> a counter as its value goes up and down, this is a snapshot of the cache
> storage usage monitor.
> 
> Add some picking code to find a cache as close as possible to the L3 that
> supports the CSU monitor.
> 
> If there is an L3, but it doesn't have any controls, force the L3 resource
> to exist. The existing topology_matches_l3() and
> mpam_resctrl_domain_hdr_init() code will ensure this looks like the L3,
> even if the class belongs to a later cache.
> 
> Signed-off-by: James Morse <james.morse at arm.com>
> ---
>  drivers/resctrl/mpam_internal.h |   6 ++
>  drivers/resctrl/mpam_resctrl.c  | 148 ++++++++++++++++++++++++++++++++
>  2 files changed, 154 insertions(+)
> 
> diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
> index 8684bd35d4ab..f9d2a1004c32 100644
> --- a/drivers/resctrl/mpam_internal.h
> +++ b/drivers/resctrl/mpam_internal.h
> @@ -348,6 +348,12 @@ struct mpam_resctrl_res {
>  	struct rdt_resource	resctrl_res;
>  };
>  
> +struct mpam_resctrl_mon {
> +	struct mpam_class	*class;
> +
> +	/* per-class data that resctrl needs will live here */
> +};
> +
>  static inline int mpam_alloc_csu_mon(struct mpam_class *class)
>  {
>  	struct mpam_props *cprops = &class->props;
> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
> index fe830524639e..fc1f054f187e 100644
> --- a/drivers/resctrl/mpam_resctrl.c
> +++ b/drivers/resctrl/mpam_resctrl.c
> @@ -31,6 +31,16 @@ static struct mpam_resctrl_res mpam_resctrl_controls[RDT_NUM_RESOURCES];
>  /* The lock for modifying resctrl's domain lists from cpuhp callbacks. */
>  static DEFINE_MUTEX(domain_list_lock);
>  
> +/*
> + * The classes we've picked to map to resctrl events.
> + * Resctrl believes all the worlds a Xeon, and these are all on the L3. This
> + * array lets us find the actual class backing the event counters. e.g.
> + * the only memory bandwidth counters may be on the memory controller, but to
> + * make use of them, we pretend they are on L3.
> + * Class pointer may be NULL.
> + */
> +static struct mpam_resctrl_mon mpam_resctrl_counters[QOS_NUM_EVENTS];
> +
>  static bool exposed_alloc_capable;
>  static bool exposed_mon_capable;
>  
> @@ -258,6 +268,28 @@ static bool class_has_usable_mba(struct mpam_props *cprops)
>  	return mba_class_use_mbw_max(cprops);
>  }
>  
> +static bool cache_has_usable_csu(struct mpam_class *class)
> +{
> +	struct mpam_props *cprops;
> +
> +	if (!class)
> +		return false;
> +
> +	cprops = &class->props;
> +
> +	if (!mpam_has_feature(mpam_feat_msmon_csu, cprops))
> +		return false;
> +
> +	/*
> +	 * CSU counters settle on the value, so we can get away with
> +	 * having only one.
> +	 */
> +	if (!cprops->num_csu_mon)
> +		return false;
> +
> +	return (mpam_partid_max > 1) || (mpam_pmg_max != 0);
> +}

Why not allow csu when partid_max and pmg_max are both zero?

Thanks,

Ben



From jgg at nvidia.com  Tue Dec 16 05:56:13 2025
From: jgg at nvidia.com (Jason Gunthorpe)
Date: Tue, 16 Dec 2025 09:56:13 -0400
Subject: [PATCH v7 6/7] iommu/arm-smmu-v3: Add arm_smmu_invs based
 arm_smmu_domain_inv_range()
In-Reply-To: <20251216090926.GR3707837@noisy.programming.kicks-ass.net>
References: <cover.1765850465.git.nicolinc@nvidia.com>
 <f4261c5b30ce3c6942470433033d4933ec5eef3e.1765850465.git.nicolinc@nvidia.com>
 <20251216090926.GR3707837@noisy.programming.kicks-ass.net>
Message-ID: <20251216135613.GB6079@nvidia.com>

On Tue, Dec 16, 2025 at 10:09:26AM +0100, Peter Zijlstra wrote:
> Anyway, if I understand the above correctly, the smb_mb() is for:
> 
>   arm_smmu_domain_inv_range() 		arm_smmu_install_new_domain_invs()
> 
>     [W] IOPTE				  [Wrel] smmu_domain->invs
>     smp_mb()				  smp_mb()
>     [Lacq] smmu_domain->invs		  [L] IOPTE
> 
> Right? But I'm not sure about your 'HW sees the new IOPTEs' claim;

Yes, the '[L] IOPTE' would be a DMA from HW.

> that very much depend on what coherency domain the relevant hardware
> plays in. For smp_mb() to work, the hardware must be in the ISH
> domain, while typically devices are (if I remember my arrrrgh64
> correctly) in the OSH.

The '[W] IOPTE' sequence already includes a cache flush if the
inner/outer sharable are not coherent. If a cache flush was required
then the smp_mb() must also order it, otherwise it just has to order
the store.

The page table table code has always relied on this kind of ordering
with respect to DMA working, it would be completely broken if the DMA
does not order with the barriers.

For example:

            CPU0                         CPU1
   store PMD
                                        read PMD
   store PTE 1                          store PTE 2
   	     				dma memory barrier
                                        device reads 2
   dma memory barrier
   device reads 1


The 'device reads 2' thread must be guarenteed that the HW DMA
observes the PMD stored by CPU0. It relies on the same kind of
explicit cache flushing and barriers as this patch does.

Jason


From peterz at infradead.org  Tue Dec 16 06:04:10 2025
From: peterz at infradead.org (Peter Zijlstra)
Date: Tue, 16 Dec 2025 15:04:10 +0100
Subject: [PATCH v7 6/7] iommu/arm-smmu-v3: Add arm_smmu_invs based
 arm_smmu_domain_inv_range()
In-Reply-To: <20251216135613.GB6079@nvidia.com>
References: <cover.1765850465.git.nicolinc@nvidia.com>
 <f4261c5b30ce3c6942470433033d4933ec5eef3e.1765850465.git.nicolinc@nvidia.com>
 <20251216090926.GR3707837@noisy.programming.kicks-ass.net>
 <20251216135613.GB6079@nvidia.com>
Message-ID: <20251216140410.GV3707837@noisy.programming.kicks-ass.net>

On Tue, Dec 16, 2025 at 09:56:13AM -0400, Jason Gunthorpe wrote:
> On Tue, Dec 16, 2025 at 10:09:26AM +0100, Peter Zijlstra wrote:
> > Anyway, if I understand the above correctly, the smb_mb() is for:
> > 
> >   arm_smmu_domain_inv_range() 		arm_smmu_install_new_domain_invs()
> > 
> >     [W] IOPTE				  [Wrel] smmu_domain->invs
> >     smp_mb()				  smp_mb()
> >     [Lacq] smmu_domain->invs		  [L] IOPTE
> > 
> > Right? But I'm not sure about your 'HW sees the new IOPTEs' claim;
> 
> Yes, the '[L] IOPTE' would be a DMA from HW.
> 
> > that very much depend on what coherency domain the relevant hardware
> > plays in. For smp_mb() to work, the hardware must be in the ISH
> > domain, while typically devices are (if I remember my arrrrgh64
> > correctly) in the OSH.
> 
> The '[W] IOPTE' sequence already includes a cache flush if the
> inner/outer sharable are not coherent. If a cache flush was required
> then the smp_mb() must also order it, otherwise it just has to order
> the store.
> 
> The page table table code has always relied on this kind of ordering
> with respect to DMA working, it would be completely broken if the DMA
> does not order with the barriers.
> 
> For example:
> 
>             CPU0                         CPU1
>    store PMD
>                                         read PMD
>    store PTE 1                          store PTE 2
>    	     				dma memory barrier
>                                         device reads 2
>    dma memory barrier
>    device reads 1

But here you have dma_mb(), which is dmb(osh).

> The 'device reads 2' thread must be guarenteed that the HW DMA
> observes the PMD stored by CPU0. It relies on the same kind of
> explicit cache flushing and barriers as this patch does.

OK, but then please include that in the comment, because using smp_*()
barriers and talking about devices sets of alarm bells.


From jgg at nvidia.com  Tue Dec 16 06:15:11 2025
From: jgg at nvidia.com (Jason Gunthorpe)
Date: Tue, 16 Dec 2025 10:15:11 -0400
Subject: [PATCH v7 6/7] iommu/arm-smmu-v3: Add arm_smmu_invs based
 arm_smmu_domain_inv_range()
In-Reply-To: <20251216140410.GV3707837@noisy.programming.kicks-ass.net>
References: <cover.1765850465.git.nicolinc@nvidia.com>
 <f4261c5b30ce3c6942470433033d4933ec5eef3e.1765850465.git.nicolinc@nvidia.com>
 <20251216090926.GR3707837@noisy.programming.kicks-ass.net>
 <20251216135613.GB6079@nvidia.com>
 <20251216140410.GV3707837@noisy.programming.kicks-ass.net>
Message-ID: <20251216141511.GD6079@nvidia.com>

On Tue, Dec 16, 2025 at 03:04:10PM +0100, Peter Zijlstra wrote:
> On Tue, Dec 16, 2025 at 09:56:13AM -0400, Jason Gunthorpe wrote:
> > On Tue, Dec 16, 2025 at 10:09:26AM +0100, Peter Zijlstra wrote:
> > > Anyway, if I understand the above correctly, the smb_mb() is for:
> > > 
> > >   arm_smmu_domain_inv_range() 		arm_smmu_install_new_domain_invs()
> > > 
> > >     [W] IOPTE				  [Wrel] smmu_domain->invs
> > >     smp_mb()				  smp_mb()
> > >     [Lacq] smmu_domain->invs		  [L] IOPTE
> > > 
> > > Right? But I'm not sure about your 'HW sees the new IOPTEs' claim;
> > 
> > Yes, the '[L] IOPTE' would be a DMA from HW.
> > 
> > > that very much depend on what coherency domain the relevant hardware
> > > plays in. For smp_mb() to work, the hardware must be in the ISH
> > > domain, while typically devices are (if I remember my arrrrgh64
> > > correctly) in the OSH.
> > 
> > The '[W] IOPTE' sequence already includes a cache flush if the
> > inner/outer sharable are not coherent. If a cache flush was required
> > then the smp_mb() must also order it, otherwise it just has to order
> > the store.
> > 
> > The page table table code has always relied on this kind of ordering
> > with respect to DMA working, it would be completely broken if the DMA
> > does not order with the barriers.
> > 
> > For example:
> > 
> >             CPU0                         CPU1
> >    store PMD
> >                                         read PMD
> >    store PTE 1                          store PTE 2
> >    	     				dma memory barrier
> >                                         device reads 2
> >    dma memory barrier
> >    device reads 1
> 
> But here you have dma_mb(), which is dmb(osh).

This also has a pre-existing dma_wmb(), a fuller chart would be like this:

   arm_smmu_domain_inv_range() 		arm_smmu_install_new_domain_invs()
 
     [W] IOPTE				  [Wrel] smmu_domain->invs
     smp_mb()				  smp_mb()  <--- arm_smmu_install_new_domain_invs()
					  [build the STE]
					  [post the STE]
					  dma_wmb() <--- arm_smmu_cmdq_issue_cmdlist()
                                          Doorbell Write to Device
     [Lacq] smmu_domain->invs		  [L] IOPTE via DMA

Nicolin, please elabortate more of these details in the comment.

Jason


From ben.horgan at arm.com  Tue Dec 16 06:24:46 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Tue, 16 Dec 2025 14:24:46 +0000
Subject: [RFC PATCH 13/38] arm_mpam: resctrl: Add CDP emulation
In-Reply-To: <20251205215901.17772-14-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-14-james.morse@arm.com>
Message-ID: <16b5063a-1201-4453-8038-4ef937d20abd@arm.com>

Hi James,

On 12/5/25 21:58, James Morse wrote:
> Intel RDT's CDP feature allows the cache to use a different control value
> depending on whether the accesses was for instruction fetch or a data
> access. MPAM's equivalent feature is the other way up: the CPU assigns a
> different partid label to traffic depending on whether it was instruction
> fetch or a data access, which causes the cache to use a different control
> value based solely on the partid.
> 
> MPAM can emulate CDP, with the side effect that the alternative partid is
> seen by all MSC, it can't be enabled per-MSC.
> 
> Add the resctrl hooks to turn this on or off. Add the helpers that
> match a closid against a task, which need to be aware that the value
> written to hardware is not the same as the one resctrl is using.
> 
> Update the 'arm64_mpam_global_default' variable the arch code uses
> during context switch to know when the per-cpu value should be used
> instead.
> 
> Awkwardly, the MB controls don't implement CDP. To emulate this, the
> MPAM equivalent needs programming twice by the resctrl glue, as
> resctrl expects the bandwidth controls to be applied independently for
> both data and isntruction-fetch.
> 
> CC: Dave Martin <Dave.Martin at arm.com>
> CC: Ben Horgan <ben.horgan at arm.com>
> CC: Amit Singh Tomar <amitsinght at marvell.com>
> Signed-off-by: James Morse <james.morse at arm.com>
> ---
>  arch/arm64/include/asm/mpam.h  |   1 +
>  drivers/resctrl/mpam_resctrl.c | 115 ++++++++++++++++++++++++++++++++-
>  include/linux/arm_mpam.h       |   3 +
>  3 files changed, 118 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/mpam.h
> index 2960ffaf6574..689285c4c61f 100644
> --- a/arch/arm64/include/asm/mpam.h
> +++ b/arch/arm64/include/asm/mpam.h
> @@ -4,6 +4,7 @@
>  #ifndef __ASM__MPAM_H
>  #define __ASM__MPAM_H
>  
> +#include <linux/arm_mpam.h>
>  #include <linux/bitops.h>
>  #include <linux/bitfield.h>
>  #include <linux/init.h>
> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
> index c2650abb99ec..d5f75ed67e46 100644
> --- a/drivers/resctrl/mpam_resctrl.c
> +++ b/drivers/resctrl/mpam_resctrl.c
> @@ -33,6 +33,10 @@ static DEFINE_MUTEX(domain_list_lock);
>  static bool exposed_alloc_capable;
>  static bool exposed_mon_capable;
>  
> +/*
> + * MPAM emulates CDP by setting different PARTID in the I/D fields of MPAM0_EL1.
> + * This applies globally to all traffic the CPU generates.
> + */
>  static bool cdp_enabled;
>  
>  bool resctrl_arch_alloc_capable(void)
> @@ -45,6 +49,67 @@ bool resctrl_arch_mon_capable(void)
>  	return exposed_mon_capable;
>  }
>  
> +bool resctrl_arch_get_cdp_enabled(enum resctrl_res_level rid)
> +{
> +	switch (rid) {
> +	case RDT_RESOURCE_L2:
> +	case RDT_RESOURCE_L3:
> +		return cdp_enabled;
> +	case RDT_RESOURCE_MBA:
> +	default:
> +		/*
> +		 * x86's MBA control doesn't support CDP, so user-space doesn't
> +		 * expect it.
> +		 */
> +		return false;
> +	}
> +}
> +
> +/**
> + * resctrl_reset_task_closids() - Reset the PARTID/PMG values for all tasks.
> + *
> + * At boot, all existing tasks use partid zero for D and I.
> + * To enable/disable CDP emulation, all these tasks need relabelling.
> + */
> +static void resctrl_reset_task_closids(void)
> +{
> +	struct task_struct *p, *t;
> +
> +	read_lock(&tasklist_lock);
> +	for_each_process_thread(p, t) {
> +		resctrl_arch_set_closid_rmid(t, RESCTRL_RESERVED_CLOSID,
> +					     RESCTRL_RESERVED_RMID);
> +	}
> +	read_unlock(&tasklist_lock);
> +}
> +
> +int resctrl_arch_set_cdp_enabled(enum resctrl_res_level ignored, bool enable)
> +{
> +	u32 partid_i, partid_d;
> +
> +	cdp_enabled = enable;
> +	partid_i = partid_d = RESCTRL_RESERVED_CLOSID;
> +
> +	if (enable) {
> +		u32 partid = RESCTRL_RESERVED_CLOSID;
> +
> +		partid_d = resctrl_get_config_index(partid, CDP_CODE);
> +		partid_i = resctrl_get_config_index(partid, CDP_DATA);

These are back to front, partid_d is data and partid_i is code. Also, if
there is only one partid then we don't have 2 different partids and we
should fail to enable cdp.

> +	}
> +
> +	mpam_set_task_partid_pmg(current, partid_d, partid_i, 0, 0);
> +	WRITE_ONCE(arm64_mpam_global_default, mpam_get_regval(current));
> +
> +	resctrl_reset_task_closids();
> +
> +	return 0;
> +}

Thanks,

Ben



From linusw at kernel.org  Tue Dec 16 06:27:37 2025
From: linusw at kernel.org (Linus Walleij)
Date: Tue, 16 Dec 2025 15:27:37 +0100
Subject: [PATCH v2] ARM: entry: expand comment in __switch_to
Message-ID: <20251216-comments-in-switch-to-v2-1-190d8741db14@kernel.org>

From: Linus Walleij <linus.walleij at linaro.org>

As per discussion between the developers in the mail thread
linked, expand the comment in __switch_to so that readers
of the code understand what is going on.

Link: https://lore.kernel.org/linux-arm-kernel/ZxDh9biUbf9W8gNN at J2N7QTR9R3/
Suggested-by: Mark Rutland <mark.rutland at arm.com>
Signed-off-by: Linus Walleij <linus.walleij at linaro.org>
---
Changes in v2:
- Rebased on v6.19-rc1
- Link to v1: https://lore.kernel.org/r/20241028-comments-in-switch-to-v1-0-7280d09671a8 at linaro.org
---
 arch/arm/kernel/entry-armv.S | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index ef6a657c8d13..5c016c68b5a3 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -557,9 +557,16 @@ ENTRY(__switch_to)
 	ldmia	r4, {r4 - sl, fp, ip, lr}	@ Load all regs saved previously
 #ifdef CONFIG_VMAP_STACK
 	@
-	@ Do a dummy read from the new stack while running from the old one so
-	@ that we can rely on do_translation_fault() to fix up any stale PMD
-	@ entries covering the vmalloc region.
+	@ For a non-lazy mm switch, check_vmalloc_seq() has ensured that
+	@ that the active mm's page tables have mappings for the prev
+	@ task's stack and the next task's stack.
+	@
+	@ For a lazy mm switch the active mm's page tables have mappings
+	@ for the prev task's stack but might not have mappings for the
+	@ new taks stack. Do a dummy read from the new stack while
+	@ running from the old stack so that we can rely on
+	@ do_translation_fault() to fix up any stale PMD entries
+	@ covering the vmalloc region.
 	@
 	ldr	r2, [ip]
 #ifdef CONFIG_KASAN_VMALLOC

---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20241028-comments-in-switch-to-0e24480e8495

Best regards,
-- 
Linus Walleij <linusw at kernel.org>



From alexander.stein at ew.tq-group.com  Tue Dec 16 06:35:21 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Tue, 16 Dec 2025 15:35:21 +0100
Subject: [PATCH 1/1] ARM: imx_v6_v7_defconfig: Configure CONFIG_SND_SOC_FSL_ASOC_CARD as module
Message-ID: <20251216143522.1064563-1-alexander.stein@ew.tq-group.com>

This option explicitly selects other options, e.g. SND_SOC_FSL_SAI.
These SAI drivers use DMA which in turn is dependent on CONFIG_IMX_SDMA.
SDMA needs a firmware which is not yet present if the driver is built-in.
Thus build CONFIG_SND_SOC_FSL_ASOC_CARD to avoid useless driver probe
deferrals due to missing DMA channels.

Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 arch/arm/configs/imx_v6_v7_defconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 0d55056c6f821..d75f5d71365a4 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -311,7 +311,7 @@ CONFIG_SND_IMX_SOC=y
 CONFIG_SND_SOC_EUKREA_TLV320=y
 CONFIG_SND_SOC_IMX_ES8328=y
 CONFIG_SND_SOC_IMX_SGTL5000=y
-CONFIG_SND_SOC_FSL_ASOC_CARD=y
+CONFIG_SND_SOC_FSL_ASOC_CARD=m
 CONFIG_SND_SOC_AC97_CODEC=y
 CONFIG_SND_SOC_CS42XX8_I2C=y
 CONFIG_SND_SOC_SPDIF=y
-- 
2.43.0



From geert at linux-m68k.org  Tue Dec 16 06:35:42 2025
From: geert at linux-m68k.org (Geert Uytterhoeven)
Date: Tue, 16 Dec 2025 15:35:42 +0100
Subject: [GIT PULL 3/6] soc: devicetree updates for 6.19
In-Reply-To: <52068d9c-d677-4fa6-8ced-6a7fb190a935@app.fastmail.com>
References: <334684ec-5796-47a4-b9f4-96c60f449634@app.fastmail.com> <52068d9c-d677-4fa6-8ced-6a7fb190a935@app.fastmail.com>
Message-ID: <CAMuHMdUKreg6NcMUK-jvgM=R1Mt=VQPntTrwN-PO-S3fnAUw2A@mail.gmail.com>

On Fri, 5 Dec 2025 at 19:28, Arnd Bergmann <arnd at arndb.de> wrote:
> Three new SoCs got added in existing arm64 chip families:
>
>  - Renesas R-Car X5H (R8A78000) is a new generation of automotive SoCs,
>    based on 16 Cortex-A720 (Armv9.2) cores, which makes the the currently
>    highest-perforance embedded SoC.

Actually 32 Cortex-A720AE cores, which I believe could indeed reduce to
16 cores when enabling dual-core lock-step mode.

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds


From arnd at arndb.de  Tue Dec 16 06:39:51 2025
From: arnd at arndb.de (Arnd Bergmann)
Date: Tue, 16 Dec 2025 15:39:51 +0100
Subject: [GIT PULL 3/6] soc: devicetree updates for 6.19
In-Reply-To: <CAMuHMdUKreg6NcMUK-jvgM=R1Mt=VQPntTrwN-PO-S3fnAUw2A@mail.gmail.com>
References: <334684ec-5796-47a4-b9f4-96c60f449634@app.fastmail.com>
 <52068d9c-d677-4fa6-8ced-6a7fb190a935@app.fastmail.com>
 <CAMuHMdUKreg6NcMUK-jvgM=R1Mt=VQPntTrwN-PO-S3fnAUw2A@mail.gmail.com>
Message-ID: <1ce00594-66ce-4fa7-b75a-d26dc756541e@app.fastmail.com>

On Tue, Dec 16, 2025, at 15:35, Geert Uytterhoeven wrote:
> On Fri, 5 Dec 2025 at 19:28, Arnd Bergmann <arnd at arndb.de> wrote:
>> Three new SoCs got added in existing arm64 chip families:
>>
>>  - Renesas R-Car X5H (R8A78000) is a new generation of automotive SoCs,
>>    based on 16 Cortex-A720 (Armv9.2) cores, which makes the the currently
>>    highest-perforance embedded SoC.
>
> Actually 32 Cortex-A720AE cores, which I believe could indeed reduce to
> 16 cores when enabling dual-core lock-step mode.
>

Sorry about that, I should have looked more closely.

      Arnd


From chrisi.schrefl at gmail.com  Tue Dec 16 06:41:52 2025
From: chrisi.schrefl at gmail.com (Christian Schrefl)
Date: Tue, 16 Dec 2025 15:41:52 +0100
Subject: ARMv7 Linux + Rust doesn't boot when compiling with only LLVM=1
In-Reply-To: <1286af8e-f908-45db-af7c-d9c5d592abfd@gmail.com>
References: <1286af8e-f908-45db-af7c-d9c5d592abfd@gmail.com>
Message-ID: <0705db10-3cbb-4958-a116-112457f9af6c@gmail.com>

On 12/14/25 12:54 AM, Rudraksha Gupta wrote:
> Hello all,
> 
> 
> I have the following problem: https://gitlab.postmarketos.org/postmarketOS/pmbootstrap/-/issues/2635
> 
> 
> In short, what is happening is the following:
> 
> 
> - The kernel boots and outputs via UART when I build the kernel with the following:
> 
> make LLVM=1 ARCH="$arm" CC="${CC:-gcc}"
> 
> 
> - The kernel doesn't boot and there is no output via UART when I build the kernel with the following:
> 
> make LLVM=1 ARCH="$arm"
> 
> 
> The only difference being:?CC="${CC:-gcc}". Is this expected? I think this was present in the Linux kernel ever since Rust was enabled for ARMv7, and I never encountered it because postmarketOS was originally building the first way.


I've managed to the get the build setup for qemu-armv7. For some reason
I could not get past the initrd even on kernels that are supposed to work,
but I think that is unrelated (and not a kernel issue).
On the linux-next kernel I didn't get any output on the console from qemu so I
think I've reproduced the issue. Changing CONFIG_RUST=n did not change the behavior.

So I this is almost certainly a LLVM/clang issue and not a Rust issue. I'll try to
do a bit more digging, but I'm not sure how much I'll get done.

Adding the LLVM and ARM lists to this conversation.

Cheers,
Christian


From Frank.li at nxp.com  Tue Dec 16 06:42:06 2025
From: Frank.li at nxp.com (Frank Li)
Date: Tue, 16 Dec 2025 09:42:06 -0500
Subject: [PATCH v2 0/4] s32g: Use a syscon for GPR
In-Reply-To: <aUEQkuzSZXFs5nqr@stanley.mountain>
References: <cover.1765806521.git.dan.carpenter@linaro.org>
 <aUAvwRmIZBC0W6ql@lizhi-Precision-Tower-5810>
 <aUBUkuLf7NHtLSl1@stanley.mountain>
 <aUBha2/xiZsIF/o5@lizhi-Precision-Tower-5810>
 <aUBrV2_Iv4oTPkC4@stanley.mountain>
 <aUB4pFEwmMBzW52T@lizhi-Precision-Tower-5810>
 <aUEQkuzSZXFs5nqr@stanley.mountain>
Message-ID: <aUFvvmDUai9QrhZ2@lizhi-Precision-Tower-5810>

On Tue, Dec 16, 2025 at 10:56:02AM +0300, Dan Carpenter wrote:
> On Mon, Dec 15, 2025 at 04:07:48PM -0500, Frank Li wrote:
> > On Mon, Dec 15, 2025 at 11:11:03PM +0300, Dan Carpenter wrote:
> > > On Mon, Dec 15, 2025 at 02:28:43PM -0500, Frank Li wrote:
> > > > On Mon, Dec 15, 2025 at 09:33:54PM +0300, Dan Carpenter wrote:
> > > > > On Mon, Dec 15, 2025 at 10:56:49AM -0500, Frank Li wrote:
> > > > > > On Mon, Dec 15, 2025 at 05:41:43PM +0300, Dan Carpenter wrote:
> > > > > > > The s32g devices have a GPR register region which holds a number of
> > > > > > > miscellaneous registers.  Currently only the stmmac/dwmac-s32.c uses
> > > > > > > anything from there and we just add a line to the device tree to
> > > > > > > access that GMAC_0_CTRL_STS register:
> > > > > > >
> > > > > > >                         reg = <0x4033c000 0x2000>, /* gmac IP */
> > > > > > >                               <0x4007c004 0x4>;    /* GMAC_0_CTRL_STS */
> > > > > > >
> > > > > > > We still have to maintain backwards compatibility to this format,
> > > > > > > of course, but it would be better to access these through a syscon.
> > > > > > > First of all, putting all the registers together is more organized
> > > > > > > and shows how the hardware actually is implemented.  Secondly, in
> > > > > > > some versions of this chipset those registers can only be accessed
> > > > > > > via SCMI, if the registers aren't grouped together each driver will
> > > > > > > have to create a whole lot of if then statements to access it via
> > > > > > > IOMEM or via SCMI,
> > > > > >
> > > > > > Does SCMI work as regmap? syscon look likes simple, but missed abstract
> > > > > > in overall.
> > > > > >
> > > > >
> > > > > The SCMI part of this is pretty complicated and needs discussion.  It
> > > > > might be that it requires a vendor extension.  Right now, the out of
> > > > > tree code uses a nvmem vendor extension but that probably won't get
> > > > > merged upstream.
> > > > >
> > > > > But in theory, it's fairly simple, you can write a regmap driver and
> > > > > register it as a syscon and everything that was accessing nxp,phy-sel
> > > > > accesses the same register but over SCMI.
> > > >
> > > > nxp,phy-sel is not standard API. Driver access raw register value. such
> > > > as write 1 to offset 0x100.
> > > >
> > > > After change to SCMI, which may mapped to difference command. Even change
> > > > to other SOC, value and offset also need be changed. It is not standilzed
> > > > as what you expected.
> > >
> > > We're writing to an offset in a syscon.  Right now the device tree
> > > says that the syscon is an MMIO syscon.  But for SCMI devices we
> > > would point the phandle to a custom syscon.  The phandle and the offset
> > > would stay the same, but how the syscon is implemented would change.
> >
> > Your SCMI syscon driver will convert some private hard code to some
> > function, such previous example's '1' as SEL_RGMII. It is hard maintained
> > in long term.
> >
>
> No, there isn't any conversion needed.  It's exactly the same as writing
> to the register except it goes through SCMI.
>
> > >
> > > >
> > > > >
> > > > > > You still use regmap by use MMIO. /* GMAC_0_CTRL_STS */
> > > > > >
> > > > > > regmap = devm_regmap_init_mmio(dev, sts_offset, &regmap_config);
> > > > > >
> > > > >
> > > > > You can use have an MMIO syscon, or you can create a custom driver
> > > > > and register it as a syscon using of_syscon_register_regmap().
> > > >
> > > > My means is that it is not necessary to create nxp,phy-sel, especially
> > > > there already have <0x4007c004 0x4>;    /* GMAC_0_CTRL_STS */
> > > >
> > >
> > > Right now the out of tree dwmac-s32cc.c driver does something like
> > > this:
> > >
> > >     89          if (gmac->use_nvmem) {
> > >     90                  ret = write_nvmem_cell(gmac->dev, "gmac_phy_intf_sel", intf_sel);
> > >     91                  if (ret)
> > >     92                          return ret;
> > >     93          } else {
> > >     94                  writel(intf_sel, gmac->ctrl_sts);
> > >     95          }
> > >
> > > Which is quite complicated, but with a syscon, then it's just:
> > >
> > > 	regmap_write(gmac->sts_regmap, gmac->sts_offset, S32_PHY_INTF_SEL_RGMII);
> > >
> > > Even without SCMI, the hardware has all these registers grouped together
> > > it just feels cleaner to group them together in the device tree as well.
> >
> > Why not implement standard phy interface,
> > phy_set_mode_ext(PHY_MODE_ETHERNET, RGMII);
> >
> > For example:  drivers/pci/controller/dwc/pci-imx6.c
> >
> > In legency platform, it use syscon to set some registers. It becomes mess
> > when more platform added.  And it becomes hard to convert because avoid
> > break compatibltiy now.
> >
> > It doesn't become worse since new platforms switched to use standard
> > inteface, (phy, reset ...).
> >
>
> This happens below that layer, this is just saying where the registers
> are found.  The GMAC_0_CTRL_STS is just one register in the GPR region,
> most of the others are unrelated to PHY.

The other register should work as other function's providor with mfd.

Frank

>
> regards,
> dan carpenter
>


From ryan.roberts at arm.com  Tue Dec 16 06:45:45 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Tue, 16 Dec 2025 14:45:45 +0000
Subject: [PATCH v1 00/13] arm64: Refactor TLB invalidation API and implementation
Message-ID: <20251216144601.2106412-1-ryan.roberts@arm.com>

Hi All,

This series refactors the TLB invalidation API to make it more general and
flexible, and refactors the implementation, aiming to make it more robust,
easier to understand and easier to add new features in future.

It is heavily based on the series posted by Will back in July at [1]; I've
attempted to maintain correct authorship and tags - apologies if I got any of
the etiquette wrong.

The first 8 patches reimplement the full scope of Will's series, but fixed up to
use function pointers instead of the enum, as per Linus's suggestion. Patches
9-12 then reformulate the API for the range- and page-based functions to remove
all the "nosync", "nonotify" and "local" function variants and replace with a
set of flags to modify the behaviour instead. This allows having a single
implementation that can rely on constant folding. IMO It's much cleaner and more
flexible. Finally, patch 13 provides a minor theoretical performance improvement
by hinting the TTL for page-based invalidations (the preceeding API improvements
made that pretty simple).

We have a couple of other things in the queue to put on top of this series,
which these changes make simpler:

 - Optimization to only do local TLBI when an mm is single-threaded
 - Introduce TLBIP for use with D128 pgtables

The series applies on top of v6.19-rc1, I've compile tested each patch and run
mm selftests for the end result in a VM on Apple M2; all tests pass. I've run an
earlier version of this code through our performance benchmarking system and no
regressions were found. I've looked at the generated instructions and all the
expected constant folding seems to be happening, and I've checked code size
before and after; there is no significant change.

[1] https://lore.kernel.org/linux-arm-kernel/20250711161732.384-1-will at kernel.org/

Thanks,
Ryan

Ryan Roberts (9):
  arm64: mm: Re-implement the __tlbi_level macro as a C function
  arm64: mm: Introduce a C wrapper for by-range TLB invalidation
  arm64: mm: Implicitly invalidate user ASID based on TLBI operation
  arm64: mm: Re-implement the __flush_tlb_range_op macro in C
  arm64: mm: Refactor flush_tlb_page() to use __tlbi_level_asid()
  arm64: mm: Refactor __flush_tlb_range() to take flags
  arm64: mm: More flags for __flush_tlb_range()
  arm64: mm: Wrap flush_tlb_page() around ___flush_tlb_range()
  arm64: mm: Provide level hint for flush_tlb_page()

Will Deacon (4):
  arm64: mm: Push __TLBI_VADDR() into __tlbi_level()
  arm64: mm: Inline __TLBI_VADDR_RANGE() into __tlbi_range()
  arm64: mm: Simplify __TLBI_RANGE_NUM() macro
  arm64: mm: Simplify __flush_tlb_range_limit_excess()

 arch/arm64/include/asm/hugetlb.h  |  12 +-
 arch/arm64/include/asm/pgtable.h  |  13 +-
 arch/arm64/include/asm/tlb.h      |   6 +-
 arch/arm64/include/asm/tlbflush.h | 461 +++++++++++++++++-------------
 arch/arm64/kernel/sys_compat.c    |   2 +-
 arch/arm64/kvm/hyp/nvhe/mm.c      |   2 +-
 arch/arm64/kvm/hyp/pgtable.c      |   4 +-
 arch/arm64/mm/contpte.c           |  12 +-
 arch/arm64/mm/fault.c             |   2 +-
 arch/arm64/mm/hugetlbpage.c       |   4 +-
 arch/arm64/mm/mmu.c               |   2 +-
 11 files changed, 288 insertions(+), 232 deletions(-)

--
2.43.0



From ryan.roberts at arm.com  Tue Dec 16 06:45:46 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Tue, 16 Dec 2025 14:45:46 +0000
Subject: [PATCH v1 01/13] arm64: mm: Re-implement the __tlbi_level macro as a C function
In-Reply-To: <20251216144601.2106412-1-ryan.roberts@arm.com>
References: <20251216144601.2106412-1-ryan.roberts@arm.com>
Message-ID: <20251216144601.2106412-2-ryan.roberts@arm.com>

As part of efforts to reduce our reliance on complex preprocessor macros
for TLB invalidation routines, convert the __tlbi_level macro to a C
function for by-level TLB invalidation.

Each specific tlbi level op is implemented as a C function and the
appropriate function pointer is passed to __tlbi_level(). Since
everything is declared inline and is statically resolvable, the compiler
will convert the indirect function call to a direct inline execution.

Suggested-by: Linus Torvalds <torvalds at linux-foundation.org>
Signed-off-by: Ryan Roberts <ryan.roberts at arm.com>
---
 arch/arm64/include/asm/tlbflush.h | 69 +++++++++++++++++++++++++------
 1 file changed, 56 insertions(+), 13 deletions(-)

diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
index a2d65d7d6aae..13a59cf28943 100644
--- a/arch/arm64/include/asm/tlbflush.h
+++ b/arch/arm64/include/asm/tlbflush.h
@@ -105,19 +105,62 @@ static inline unsigned long get_trans_granule(void)
 
 #define TLBI_TTL_UNKNOWN	INT_MAX
 
-#define __tlbi_level(op, addr, level) do {				\
-	u64 arg = addr;							\
-									\
-	if (alternative_has_cap_unlikely(ARM64_HAS_ARMv8_4_TTL) &&	\
-	    level >= 0 && level <= 3) {					\
-		u64 ttl = level & 3;					\
-		ttl |= get_trans_granule() << 2;			\
-		arg &= ~TLBI_TTL_MASK;					\
-		arg |= FIELD_PREP(TLBI_TTL_MASK, ttl);			\
-	}								\
-									\
-	__tlbi(op, arg);						\
-} while(0)
+typedef void (*tlbi_op)(u64 arg);
+
+static __always_inline void vae1is(u64 arg)
+{
+	__tlbi(vae1is, arg);
+}
+
+static __always_inline void vae2is(u64 arg)
+{
+	__tlbi(vae2is, arg);
+}
+
+static __always_inline void vale1(u64 arg)
+{
+	__tlbi(vale1, arg);
+	__tlbi_user(vale1, arg);
+}
+
+static __always_inline void vale1is(u64 arg)
+{
+	__tlbi(vale1is, arg);
+}
+
+static __always_inline void vale2is(u64 arg)
+{
+	__tlbi(vale2is, arg);
+}
+
+static __always_inline void vaale1is(u64 arg)
+{
+	__tlbi(vaale1is, arg);
+}
+
+static __always_inline void ipas2e1(u64 arg)
+{
+	__tlbi(ipas2e1, arg);
+}
+
+static __always_inline void ipas2e1is(u64 arg)
+{
+	__tlbi(ipas2e1is, arg);
+}
+
+static __always_inline void __tlbi_level(tlbi_op op, u64 addr, u32 level)
+{
+	u64 arg = addr;
+
+	if (alternative_has_cap_unlikely(ARM64_HAS_ARMv8_4_TTL) && level <= 3) {
+		u64 ttl = level | (get_trans_granule() << 2);
+
+		arg &= ~TLBI_TTL_MASK;
+		arg |= FIELD_PREP(TLBI_TTL_MASK, ttl);
+	}
+
+	op(arg);
+}
 
 #define __tlbi_user_level(op, arg, level) do {				\
 	if (arm64_kernel_unmapped_at_el0())				\
-- 
2.43.0



From ryan.roberts at arm.com  Tue Dec 16 06:45:47 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Tue, 16 Dec 2025 14:45:47 +0000
Subject: [PATCH v1 02/13] arm64: mm: Introduce a C wrapper for by-range TLB invalidation
In-Reply-To: <20251216144601.2106412-1-ryan.roberts@arm.com>
References: <20251216144601.2106412-1-ryan.roberts@arm.com>
Message-ID: <20251216144601.2106412-3-ryan.roberts@arm.com>

As part of efforts to reduce our reliance on complex preprocessor macros
for TLB invalidation routines, introduce a new C wrapper for by-range
TLB invalidation which can be used instead of the __tlbi() macro and can
additionally be called from C code.

Each specific tlbi range op is implemented as a C function and the
appropriate function pointer is passed to __tlbi_range(). Since
everything is declared inline and is statically resolvable, the compiler
will convert the indirect function call to a direct inline execution.

Suggested-by: Linus Torvalds <torvalds at linux-foundation.org>
Signed-off-by: Ryan Roberts <ryan.roberts at arm.com>
---
 arch/arm64/include/asm/tlbflush.h | 33 ++++++++++++++++++++++++++++++-
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
index 13a59cf28943..c5111d2afc66 100644
--- a/arch/arm64/include/asm/tlbflush.h
+++ b/arch/arm64/include/asm/tlbflush.h
@@ -459,6 +459,37 @@ static inline void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch)
  *    operations can only span an even number of pages. We save this for last to
  *    ensure 64KB start alignment is maintained for the LPA2 case.
  */
+static __always_inline void rvae1is(u64 arg)
+{
+	__tlbi(rvae1is, arg);
+}
+
+static __always_inline void rvale1(u64 arg)
+{
+	__tlbi(rvale1, arg);
+	__tlbi_user(rvale1, arg);
+}
+
+static __always_inline void rvale1is(u64 arg)
+{
+	__tlbi(rvale1is, arg);
+}
+
+static __always_inline void rvaale1is(u64 arg)
+{
+	__tlbi(rvaale1is, arg);
+}
+
+static __always_inline void ripas2e1is(u64 arg)
+{
+	__tlbi(ripas2e1is, arg);
+}
+
+static __always_inline void __tlbi_range(tlbi_op op, u64 arg)
+{
+	op(arg);
+}
+
 #define __flush_tlb_range_op(op, start, pages, stride,			\
 				asid, tlb_level, tlbi_user, lpa2)	\
 do {									\
@@ -486,7 +517,7 @@ do {									\
 		if (num >= 0) {						\
 			addr = __TLBI_VADDR_RANGE(__flush_start >> shift, asid, \
 						scale, num, tlb_level);	\
-			__tlbi(r##op, addr);				\
+			__tlbi_range(r##op, addr);			\
 			if (tlbi_user)					\
 				__tlbi_user(r##op, addr);		\
 			__flush_start += __TLBI_RANGE_PAGES(num, scale) << PAGE_SHIFT; \
-- 
2.43.0



From ryan.roberts at arm.com  Tue Dec 16 06:45:48 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Tue, 16 Dec 2025 14:45:48 +0000
Subject: [PATCH v1 03/13] arm64: mm: Implicitly invalidate user ASID based on TLBI operation
In-Reply-To: <20251216144601.2106412-1-ryan.roberts@arm.com>
References: <20251216144601.2106412-1-ryan.roberts@arm.com>
Message-ID: <20251216144601.2106412-4-ryan.roberts@arm.com>

When kpti is enabled, separate ASIDs are used for userspace and
kernelspace, requiring ASID-qualified TLB invalidation by virtual
address to invalidate both of them.

Push the logic for invalidating the two ASIDs down into the low-level
tlbi-op-specific functions and remove the burden from the caller to
handle the kpti-specific behaviour.

Co-developed-by: Will Deacon <will at kernel.org>
Signed-off-by: Will Deacon <will at kernel.org>
Signed-off-by: Ryan Roberts <ryan.roberts at arm.com>
---
 arch/arm64/include/asm/tlbflush.h | 27 ++++++++++-----------------
 1 file changed, 10 insertions(+), 17 deletions(-)

diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
index c5111d2afc66..31f43d953ce2 100644
--- a/arch/arm64/include/asm/tlbflush.h
+++ b/arch/arm64/include/asm/tlbflush.h
@@ -110,6 +110,7 @@ typedef void (*tlbi_op)(u64 arg);
 static __always_inline void vae1is(u64 arg)
 {
 	__tlbi(vae1is, arg);
+	__tlbi_user(vae1is, arg);
 }
 
 static __always_inline void vae2is(u64 arg)
@@ -126,6 +127,7 @@ static __always_inline void vale1(u64 arg)
 static __always_inline void vale1is(u64 arg)
 {
 	__tlbi(vale1is, arg);
+	__tlbi_user(vale1is, arg);
 }
 
 static __always_inline void vale2is(u64 arg)
@@ -162,11 +164,6 @@ static __always_inline void __tlbi_level(tlbi_op op, u64 addr, u32 level)
 	op(arg);
 }
 
-#define __tlbi_user_level(op, arg, level) do {				\
-	if (arm64_kernel_unmapped_at_el0())				\
-		__tlbi_level(op, (arg | USER_ASID_FLAG), level);	\
-} while (0)
-
 /*
  * This macro creates a properly formatted VA operand for the TLB RANGE. The
  * value bit assignments are:
@@ -435,8 +432,6 @@ static inline void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch)
  * @stride:	Flush granularity
  * @asid:	The ASID of the task (0 for IPA instructions)
  * @tlb_level:	Translation Table level hint, if known
- * @tlbi_user:	If 'true', call an additional __tlbi_user()
- *              (typically for user ASIDs). 'flase' for IPA instructions
  * @lpa2:	If 'true', the lpa2 scheme is used as set out below
  *
  * When the CPU does not support TLB range operations, flush the TLB
@@ -462,6 +457,7 @@ static inline void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch)
 static __always_inline void rvae1is(u64 arg)
 {
 	__tlbi(rvae1is, arg);
+	__tlbi_user(rvae1is, arg);
 }
 
 static __always_inline void rvale1(u64 arg)
@@ -473,6 +469,7 @@ static __always_inline void rvale1(u64 arg)
 static __always_inline void rvale1is(u64 arg)
 {
 	__tlbi(rvale1is, arg);
+	__tlbi_user(rvale1is, arg);
 }
 
 static __always_inline void rvaale1is(u64 arg)
@@ -491,7 +488,7 @@ static __always_inline void __tlbi_range(tlbi_op op, u64 arg)
 }
 
 #define __flush_tlb_range_op(op, start, pages, stride,			\
-				asid, tlb_level, tlbi_user, lpa2)	\
+				asid, tlb_level, lpa2)			\
 do {									\
 	typeof(start) __flush_start = start;				\
 	typeof(pages) __flush_pages = pages;				\
@@ -506,8 +503,6 @@ do {									\
 		    (lpa2 && __flush_start != ALIGN(__flush_start, SZ_64K))) {	\
 			addr = __TLBI_VADDR(__flush_start, asid);	\
 			__tlbi_level(op, addr, tlb_level);		\
-			if (tlbi_user)					\
-				__tlbi_user_level(op, addr, tlb_level);	\
 			__flush_start += stride;			\
 			__flush_pages -= stride >> PAGE_SHIFT;		\
 			continue;					\
@@ -518,8 +513,6 @@ do {									\
 			addr = __TLBI_VADDR_RANGE(__flush_start >> shift, asid, \
 						scale, num, tlb_level);	\
 			__tlbi_range(r##op, addr);			\
-			if (tlbi_user)					\
-				__tlbi_user(r##op, addr);		\
 			__flush_start += __TLBI_RANGE_PAGES(num, scale) << PAGE_SHIFT; \
 			__flush_pages -= __TLBI_RANGE_PAGES(num, scale);\
 		}							\
@@ -528,7 +521,7 @@ do {									\
 } while (0)
 
 #define __flush_s2_tlb_range_op(op, start, pages, stride, tlb_level) \
-	__flush_tlb_range_op(op, start, pages, stride, 0, tlb_level, false, kvm_lpa2_is_enabled());
+	__flush_tlb_range_op(op, start, pages, stride, 0, tlb_level, kvm_lpa2_is_enabled());
 
 static inline bool __flush_tlb_range_limit_excess(unsigned long start,
 		unsigned long end, unsigned long pages, unsigned long stride)
@@ -568,10 +561,10 @@ static inline void __flush_tlb_range_nosync(struct mm_struct *mm,
 
 	if (last_level)
 		__flush_tlb_range_op(vale1is, start, pages, stride, asid,
-				     tlb_level, true, lpa2_is_enabled());
+				     tlb_level, lpa2_is_enabled());
 	else
 		__flush_tlb_range_op(vae1is, start, pages, stride, asid,
-				     tlb_level, true, lpa2_is_enabled());
+				     tlb_level, lpa2_is_enabled());
 
 	mmu_notifier_arch_invalidate_secondary_tlbs(mm, start, end);
 }
@@ -630,7 +623,7 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end
 
 	dsb(ishst);
 	__flush_tlb_range_op(vaale1is, start, pages, stride, 0,
-			     TLBI_TTL_UNKNOWN, false, lpa2_is_enabled());
+			     TLBI_TTL_UNKNOWN, lpa2_is_enabled());
 	dsb(ish);
 	isb();
 }
@@ -681,6 +674,6 @@ static inline bool huge_pmd_needs_flush(pmd_t oldpmd, pmd_t newpmd)
 }
 #define huge_pmd_needs_flush huge_pmd_needs_flush
 
+#undef __tlbi_user
 #endif
-
 #endif
-- 
2.43.0



From ryan.roberts at arm.com  Tue Dec 16 06:45:49 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Tue, 16 Dec 2025 14:45:49 +0000
Subject: [PATCH v1 04/13] arm64: mm: Push __TLBI_VADDR() into __tlbi_level()
In-Reply-To: <20251216144601.2106412-1-ryan.roberts@arm.com>
References: <20251216144601.2106412-1-ryan.roberts@arm.com>
Message-ID: <20251216144601.2106412-5-ryan.roberts@arm.com>

From: Will Deacon <will at kernel.org>

The __TLBI_VADDR() macro takes an ASID and an address and converts them
into a single argument formatted correctly for a TLB invalidation
instruction.

Rather than have callers worry about this (especially in the case where
the ASID is zero), push the macro down into __tlbi_level() via a new
__tlbi_level_asid() helper.

Signed-off-by: Will Deacon <will at kernel.org>
Signed-off-by: Ryan Roberts <ryan.roberts at arm.com>
---
 arch/arm64/include/asm/tlbflush.h | 14 ++++++++++----
 arch/arm64/kernel/sys_compat.c    |  2 +-
 arch/arm64/kvm/hyp/nvhe/mm.c      |  2 +-
 arch/arm64/kvm/hyp/pgtable.c      |  4 ++--
 4 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
index 31f43d953ce2..39717f98c31e 100644
--- a/arch/arm64/include/asm/tlbflush.h
+++ b/arch/arm64/include/asm/tlbflush.h
@@ -150,9 +150,10 @@ static __always_inline void ipas2e1is(u64 arg)
 	__tlbi(ipas2e1is, arg);
 }
 
-static __always_inline void __tlbi_level(tlbi_op op, u64 addr, u32 level)
+static __always_inline void __tlbi_level_asid(tlbi_op op, u64 addr, u32 level,
+					      u16 asid)
 {
-	u64 arg = addr;
+	u64 arg = __TLBI_VADDR(addr, asid);
 
 	if (alternative_has_cap_unlikely(ARM64_HAS_ARMv8_4_TTL) && level <= 3) {
 		u64 ttl = level | (get_trans_granule() << 2);
@@ -164,6 +165,11 @@ static __always_inline void __tlbi_level(tlbi_op op, u64 addr, u32 level)
 	op(arg);
 }
 
+static inline void __tlbi_level(tlbi_op op, u64 addr, u32 level)
+{
+	__tlbi_level_asid(op, addr, level, 0);
+}
+
 /*
  * This macro creates a properly formatted VA operand for the TLB RANGE. The
  * value bit assignments are:
@@ -501,8 +507,7 @@ do {									\
 		if (!system_supports_tlb_range() ||			\
 		    __flush_pages == 1 ||				\
 		    (lpa2 && __flush_start != ALIGN(__flush_start, SZ_64K))) {	\
-			addr = __TLBI_VADDR(__flush_start, asid);	\
-			__tlbi_level(op, addr, tlb_level);		\
+			__tlbi_level_asid(op, __flush_start, tlb_level, asid);	\
 			__flush_start += stride;			\
 			__flush_pages -= stride >> PAGE_SHIFT;		\
 			continue;					\
@@ -675,5 +680,6 @@ static inline bool huge_pmd_needs_flush(pmd_t oldpmd, pmd_t newpmd)
 #define huge_pmd_needs_flush huge_pmd_needs_flush
 
 #undef __tlbi_user
+#undef __TLBI_VADDR
 #endif
 #endif
diff --git a/arch/arm64/kernel/sys_compat.c b/arch/arm64/kernel/sys_compat.c
index 4a609e9b65de..ad4857df4830 100644
--- a/arch/arm64/kernel/sys_compat.c
+++ b/arch/arm64/kernel/sys_compat.c
@@ -36,7 +36,7 @@ __do_compat_cache_op(unsigned long start, unsigned long end)
 			 * The workaround requires an inner-shareable tlbi.
 			 * We pick the reserved-ASID to minimise the impact.
 			 */
-			__tlbi(aside1is, __TLBI_VADDR(0, 0));
+			__tlbi(aside1is, 0UL);
 			dsb(ish);
 		}
 
diff --git a/arch/arm64/kvm/hyp/nvhe/mm.c b/arch/arm64/kvm/hyp/nvhe/mm.c
index ae8391baebc3..581385b21826 100644
--- a/arch/arm64/kvm/hyp/nvhe/mm.c
+++ b/arch/arm64/kvm/hyp/nvhe/mm.c
@@ -270,7 +270,7 @@ static void fixmap_clear_slot(struct hyp_fixmap_slot *slot)
 	 * https://lore.kernel.org/kvm/20221017115209.2099-1-will at kernel.org/T/#mf10dfbaf1eaef9274c581b81c53758918c1d0f03
 	 */
 	dsb(ishst);
-	__tlbi_level(vale2is, __TLBI_VADDR(addr, 0), level);
+	__tlbi_level(vale2is, addr, level);
 	dsb(ish);
 	isb();
 }
diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
index 947ac1a951a5..9292c569afe6 100644
--- a/arch/arm64/kvm/hyp/pgtable.c
+++ b/arch/arm64/kvm/hyp/pgtable.c
@@ -472,14 +472,14 @@ static int hyp_unmap_walker(const struct kvm_pgtable_visit_ctx *ctx,
 
 		kvm_clear_pte(ctx->ptep);
 		dsb(ishst);
-		__tlbi_level(vae2is, __TLBI_VADDR(ctx->addr, 0), TLBI_TTL_UNKNOWN);
+		__tlbi_level(vae2is, ctx->addr, TLBI_TTL_UNKNOWN);
 	} else {
 		if (ctx->end - ctx->addr < granule)
 			return -EINVAL;
 
 		kvm_clear_pte(ctx->ptep);
 		dsb(ishst);
-		__tlbi_level(vale2is, __TLBI_VADDR(ctx->addr, 0), ctx->level);
+		__tlbi_level(vale2is, ctx->addr, ctx->level);
 		*unmapped += granule;
 	}
 
-- 
2.43.0



From Frank.li at nxp.com  Tue Dec 16 06:46:00 2025
From: Frank.li at nxp.com (Frank Li)
Date: Tue, 16 Dec 2025 09:46:00 -0500
Subject: [PATCH v3 2/5] media: nxp: use dev_err_probe() to simplify code
In-Reply-To: <5462566.31r3eYUQgx@steina-w>
References: <20251215-cam_cleanup-v3-0-a61995068f38@nxp.com>
 <20251215-cam_cleanup-v3-2-a61995068f38@nxp.com>
 <5462566.31r3eYUQgx@steina-w>
Message-ID: <aUFwqMiYE+P+KdsO@lizhi-Precision-Tower-5810>

On Tue, Dec 16, 2025 at 08:34:18AM +0100, Alexander Stein wrote:
> Hi,
>
> Am Montag, 15. Dezember 2025, 23:49:53 CET schrieb Frank Li:
> > Use dev_err_probe() to simplify the code. Drop the explicit error message
> > after returning from imx8mq_mipi_csi_parse_dt(), as the error is already
> > reported by this helper.
> >
> > No functional change.
> >
> > Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> > Signed-off-by: Frank Li <Frank.Li at nxp.com>
> > ---
> > change in v2:
> > - add  Laurent Pinchart review tags
> > - wrap error message to new line
> > - remove error code print in dev_err_probe();
> > - drop error messaage at imx8mq_mipi_csi_parse_dt()
> > ---
> >  drivers/media/platform/nxp/imx-mipi-csis.c    |  6 ++---
> >  drivers/media/platform/nxp/imx7-media-csi.c   | 14 ++++--------
> >  drivers/media/platform/nxp/imx8mq-mipi-csi2.c | 33 ++++++++++++---------------
> >  3 files changed, 21 insertions(+), 32 deletions(-)
> >
> > diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c
> > index 088b2945aee33731c565f049dd17721356300b84..ce93d868746f002c22e2f86b1e0aa84ec1a76061 100644
> > --- a/drivers/media/platform/nxp/imx-mipi-csis.c
> > +++ b/drivers/media/platform/nxp/imx-mipi-csis.c
> > @@ -1547,10 +1547,8 @@ static int mipi_csis_probe(struct platform_device *pdev)
> >  	/* Now that the hardware is initialized, request the interrupt. */
> >  	ret = devm_request_irq(dev, irq, mipi_csis_irq_handler, 0,
> >  			       dev_name(dev), csis);
> > -	if (ret) {
> > -		dev_err(dev, "Interrupt request failed\n");
> > -		return ret;
> > -	}
> > +	if (ret)
> > +		return dev_err_probe(dev, ret, "Interrupt request failed\n");
> >
> >  	/* Initialize and register the subdev. */
> >  	ret = mipi_csis_subdev_init(csis);
> > diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c
> > index 933a5f39f9f4c9b43ca8d2a1819d0145981266e6..7ddc7ba06e3d4e007013821f67d783898a15461f 100644
> > --- a/drivers/media/platform/nxp/imx7-media-csi.c
> > +++ b/drivers/media/platform/nxp/imx7-media-csi.c
> > @@ -2218,11 +2218,9 @@ static int imx7_csi_probe(struct platform_device *pdev)
> >
> >  	/* Acquire resources and install interrupt handler. */
> >  	csi->mclk = devm_clk_get(&pdev->dev, "mclk");
> > -	if (IS_ERR(csi->mclk)) {
> > -		ret = PTR_ERR(csi->mclk);
> > -		dev_err(dev, "Failed to get mclk: %d", ret);
> > -		return ret;
> > -	}
> > +	if (IS_ERR(csi->mclk))
> > +		return dev_err_probe(dev, PTR_ERR(csi->mclk),
> > +				     "Failed to get mclk\n");
> >
> >  	csi->irq = platform_get_irq(pdev, 0);
> >  	if (csi->irq < 0)
> > @@ -2236,10 +2234,8 @@ static int imx7_csi_probe(struct platform_device *pdev)
> >
> >  	ret = devm_request_irq(dev, csi->irq, imx7_csi_irq_handler, 0, "csi",
> >  			       (void *)csi);
> > -	if (ret < 0) {
> > -		dev_err(dev, "Request CSI IRQ failed.\n");
> > -		return ret;
> > -	}
> > +	if (ret < 0)
> > +		return dev_err_probe(dev, ret, "Request CSI IRQ failed.\n");
> >
> >  	/* Initialize all the media device infrastructure. */
> >  	ret = imx7_csi_media_init(csi);
> > diff --git a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
> > index 0851f4a9ae52d3096f454da643cfdc5017e000b1..a007c582b4d91660a97910a6a0d53c9b6fcd73e9 100644
> > --- a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
> > +++ b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
> > @@ -951,10 +951,9 @@ static int imx8mq_mipi_csi_parse_dt(struct csi_state *state)
> >  	int ret = 0;
> >
> >  	state->rst = devm_reset_control_array_get_exclusive(dev);
> > -	if (IS_ERR(state->rst)) {
> > -		dev_err(dev, "Failed to get reset: %pe\n", state->rst);
> > -		return PTR_ERR(state->rst);
> > -	}
> > +	if (IS_ERR(state->rst))
> > +		return dev_err_probe(dev, PTR_ERR(state->rst),
> > +				     "Failed to get reset\n");
> >
> >  	if (state->pdata->use_reg_csr) {
> >  		const struct regmap_config regmap_config = {
> > @@ -977,24 +976,22 @@ static int imx8mq_mipi_csi_parse_dt(struct csi_state *state)
> >
> >  	ret = of_property_read_u32_array(np, "fsl,mipi-phy-gpr", out_val,
> >  					 ARRAY_SIZE(out_val));
> > -	if (ret) {
> > -		dev_err(dev, "no fsl,mipi-phy-gpr property found: %d\n", ret);
> > -		return ret;
> > -	}
> > +	if (ret)
> > +		return dev_err_probe(dev, ret, "no %s property found\n",
> > +				    "fsl,mipi-phy-gpr");
>
> Do you really need to pass the (fixed) property name as an argument? Why
> not move into the const string directly? I would also rephrase it a bit:
> "property fsl,mipi-phy-gpr not found"

Laurent Pinchart provide comments at previous version. The same
"fsl,mipi-phy-gpr" share one entry at RO region. slice save RO region
space.

https://lore.kernel.org/imx/20251119043307.GH17526 at pendragon.ideasonboard.com/

Frank

>
> With that fixed:
> Reviewed-by: Alexander Stein <alexander.stein at ew.tq-group.com>
>
> >
> >  	ph = *out_val;
> >
> >  	node = of_find_node_by_phandle(ph);
> > -	if (!node) {
> > -		dev_err(dev, "Error finding node by phandle\n");
> > -		return -ENODEV;
> > -	}
> > +	if (!node)
> > +		return dev_err_probe(dev, -ENODEV,
> > +				     "Error finding node by phandle\n");
> > +
> >  	state->phy_gpr = syscon_node_to_regmap(node);
> >  	of_node_put(node);
> > -	if (IS_ERR(state->phy_gpr)) {
> > -		dev_err(dev, "failed to get gpr regmap: %pe\n", state->phy_gpr);
> > -		return PTR_ERR(state->phy_gpr);
> > -	}
> > +	if (IS_ERR(state->phy_gpr))
> > +		return dev_err_probe(dev, PTR_ERR(state->phy_gpr),
> > +				     "failed to get gpr regmap\n");
> >
> >  	state->phy_gpr_reg = out_val[1];
> >  	dev_dbg(dev, "phy gpr register set to 0x%x\n", state->phy_gpr_reg);
> > @@ -1017,10 +1014,8 @@ static int imx8mq_mipi_csi_probe(struct platform_device *pdev)
> >  	state->pdata = of_device_get_match_data(dev);
> >
> >  	ret = imx8mq_mipi_csi_parse_dt(state);
> > -	if (ret < 0) {
> > -		dev_err(dev, "Failed to parse device tree: %d\n", ret);
> > +	if (ret < 0)
> >  		return ret;
> > -	}
> >
> >  	/* Acquire resources. */
> >  	state->regs = devm_platform_ioremap_resource(pdev, 0);
> >
> >
>
>
> --
> TQ-Systems GmbH | M?hlstra?e 2, Gut Delling | 82229 Seefeld, Germany
> Amtsgericht M?nchen, HRB 105018
> Gesch?ftsf?hrer: Detlef Schneider, R?diger Stahl, Stefan Schneider
> http://www.tq-group.com/




From ryan.roberts at arm.com  Tue Dec 16 06:45:50 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Tue, 16 Dec 2025 14:45:50 +0000
Subject: [PATCH v1 05/13] arm64: mm: Inline __TLBI_VADDR_RANGE() into __tlbi_range()
In-Reply-To: <20251216144601.2106412-1-ryan.roberts@arm.com>
References: <20251216144601.2106412-1-ryan.roberts@arm.com>
Message-ID: <20251216144601.2106412-6-ryan.roberts@arm.com>

From: Will Deacon <will at kernel.org>

The __TLBI_VADDR_RANGE() macro is only used in one place and isn't
something that's generally useful outside of the low-level range
invalidation gubbins.

Inline __TLBI_VADDR_RANGE() into the __tlbi_range() function so that the
macro can be removed entirely.

Signed-off-by: Will Deacon <will at kernel.org>
Signed-off-by: Ryan Roberts <ryan.roberts at arm.com>
---
 arch/arm64/include/asm/tlbflush.h | 32 +++++++++++++------------------
 1 file changed, 13 insertions(+), 19 deletions(-)

diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
index 39717f98c31e..887dd1f05a89 100644
--- a/arch/arm64/include/asm/tlbflush.h
+++ b/arch/arm64/include/asm/tlbflush.h
@@ -195,19 +195,6 @@ static inline void __tlbi_level(tlbi_op op, u64 addr, u32 level)
 #define TLBIR_TTL_MASK		GENMASK_ULL(38, 37)
 #define TLBIR_BADDR_MASK	GENMASK_ULL(36,  0)
 
-#define __TLBI_VADDR_RANGE(baddr, asid, scale, num, ttl)		\
-	({								\
-		unsigned long __ta = 0;					\
-		unsigned long __ttl = (ttl >= 1 && ttl <= 3) ? ttl : 0;	\
-		__ta |= FIELD_PREP(TLBIR_BADDR_MASK, baddr);		\
-		__ta |= FIELD_PREP(TLBIR_TTL_MASK, __ttl);		\
-		__ta |= FIELD_PREP(TLBIR_NUM_MASK, num);		\
-		__ta |= FIELD_PREP(TLBIR_SCALE_MASK, scale);		\
-		__ta |= FIELD_PREP(TLBIR_TG_MASK, get_trans_granule());	\
-		__ta |= FIELD_PREP(TLBIR_ASID_MASK, asid);		\
-		__ta;							\
-	})
-
 /* These macros are used by the TLBI RANGE feature. */
 #define __TLBI_RANGE_PAGES(num, scale)	\
 	((unsigned long)((num) + 1) << (5 * (scale) + 1))
@@ -488,8 +475,19 @@ static __always_inline void ripas2e1is(u64 arg)
 	__tlbi(ripas2e1is, arg);
 }
 
-static __always_inline void __tlbi_range(tlbi_op op, u64 arg)
+static __always_inline void __tlbi_range(tlbi_op op, u64 addr,
+					 u16 asid, int scale, int num,
+					 u32 level, bool lpa2)
 {
+	u64 arg = 0;
+
+	arg |= FIELD_PREP(TLBIR_BADDR_MASK, addr >> (lpa2 ? 16 : PAGE_SHIFT));
+	arg |= FIELD_PREP(TLBIR_TTL_MASK, level > 3 ? 0 : level);
+	arg |= FIELD_PREP(TLBIR_NUM_MASK, num);
+	arg |= FIELD_PREP(TLBIR_SCALE_MASK, scale);
+	arg |= FIELD_PREP(TLBIR_TG_MASK, get_trans_granule());
+	arg |= FIELD_PREP(TLBIR_ASID_MASK, asid);
+
 	op(arg);
 }
 
@@ -500,8 +498,6 @@ do {									\
 	typeof(pages) __flush_pages = pages;				\
 	int num = 0;							\
 	int scale = 3;							\
-	int shift = lpa2 ? 16 : PAGE_SHIFT;				\
-	unsigned long addr;						\
 									\
 	while (__flush_pages > 0) {					\
 		if (!system_supports_tlb_range() ||			\
@@ -515,9 +511,7 @@ do {									\
 									\
 		num = __TLBI_RANGE_NUM(__flush_pages, scale);		\
 		if (num >= 0) {						\
-			addr = __TLBI_VADDR_RANGE(__flush_start >> shift, asid, \
-						scale, num, tlb_level);	\
-			__tlbi_range(r##op, addr);			\
+			__tlbi_range(r##op, __flush_start, asid, scale, num, tlb_level, lpa2); \
 			__flush_start += __TLBI_RANGE_PAGES(num, scale) << PAGE_SHIFT; \
 			__flush_pages -= __TLBI_RANGE_PAGES(num, scale);\
 		}							\
-- 
2.43.0



From ryan.roberts at arm.com  Tue Dec 16 06:45:51 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Tue, 16 Dec 2025 14:45:51 +0000
Subject: [PATCH v1 06/13] arm64: mm: Re-implement the __flush_tlb_range_op macro in C
In-Reply-To: <20251216144601.2106412-1-ryan.roberts@arm.com>
References: <20251216144601.2106412-1-ryan.roberts@arm.com>
Message-ID: <20251216144601.2106412-7-ryan.roberts@arm.com>

The __flush_tlb_range_op() macro is horrible and has been a previous
source of bugs thanks to multiple expansions of its arguments (see
commit f7edb07ad7c6 ("Fix mmu notifiers for range-based invalidates")).

Rewrite the thing in C.

Suggested-by: Linus Torvalds <torvalds at linux-foundation.org>
Co-developed-by: Will Deacon <will at kernel.org>
Signed-off-by: Will Deacon <will at kernel.org>
Signed-off-by: Ryan Roberts <ryan.roberts at arm.com>
---
 arch/arm64/include/asm/tlbflush.h | 84 +++++++++++++++++--------------
 1 file changed, 46 insertions(+), 38 deletions(-)

diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
index 887dd1f05a89..d2a144a09a8f 100644
--- a/arch/arm64/include/asm/tlbflush.h
+++ b/arch/arm64/include/asm/tlbflush.h
@@ -419,12 +419,13 @@ static inline void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch)
 /*
  * __flush_tlb_range_op - Perform TLBI operation upon a range
  *
- * @op:	TLBI instruction that operates on a range (has 'r' prefix)
+ * @lop:	TLBI level operation to perform
+ * @rop:	TLBI range operation to perform
  * @start:	The start address of the range
  * @pages:	Range as the number of pages from 'start'
  * @stride:	Flush granularity
  * @asid:	The ASID of the task (0 for IPA instructions)
- * @tlb_level:	Translation Table level hint, if known
+ * @level:	Translation Table level hint, if known
  * @lpa2:	If 'true', the lpa2 scheme is used as set out below
  *
  * When the CPU does not support TLB range operations, flush the TLB
@@ -491,36 +492,44 @@ static __always_inline void __tlbi_range(tlbi_op op, u64 addr,
 	op(arg);
 }
 
-#define __flush_tlb_range_op(op, start, pages, stride,			\
-				asid, tlb_level, lpa2)			\
-do {									\
-	typeof(start) __flush_start = start;				\
-	typeof(pages) __flush_pages = pages;				\
-	int num = 0;							\
-	int scale = 3;							\
-									\
-	while (__flush_pages > 0) {					\
-		if (!system_supports_tlb_range() ||			\
-		    __flush_pages == 1 ||				\
-		    (lpa2 && __flush_start != ALIGN(__flush_start, SZ_64K))) {	\
-			__tlbi_level_asid(op, __flush_start, tlb_level, asid);	\
-			__flush_start += stride;			\
-			__flush_pages -= stride >> PAGE_SHIFT;		\
-			continue;					\
-		}							\
-									\
-		num = __TLBI_RANGE_NUM(__flush_pages, scale);		\
-		if (num >= 0) {						\
-			__tlbi_range(r##op, __flush_start, asid, scale, num, tlb_level, lpa2); \
-			__flush_start += __TLBI_RANGE_PAGES(num, scale) << PAGE_SHIFT; \
-			__flush_pages -= __TLBI_RANGE_PAGES(num, scale);\
-		}							\
-		scale--;						\
-	}								\
-} while (0)
+static __always_inline void __flush_tlb_range_op(tlbi_op lop, tlbi_op rop,
+						 u64 start, size_t pages,
+						 u64 stride, u16 asid,
+						 u32 level, bool lpa2)
+{
+	u64 addr = start, end = start + pages * PAGE_SIZE;
+	int scale = 3;
+
+	while (addr != end) {
+		int num;
+
+		pages = (end - addr) >> PAGE_SHIFT;
+
+		if (!system_supports_tlb_range() || pages == 1)
+			goto invalidate_one;
+
+		if (lpa2 && !IS_ALIGNED(addr, SZ_64K))
+			goto invalidate_one;
+
+		num = __TLBI_RANGE_NUM(pages, scale);
+		if (num >= 0) {
+			__tlbi_range(rop, addr, asid, scale, num, level, lpa2);
+			addr += __TLBI_RANGE_PAGES(num, scale) << PAGE_SHIFT;
+		}
+
+		scale--;
+		continue;
+invalidate_one:
+		__tlbi_level_asid(lop, addr, level, asid);
+		addr += stride;
+	}
+}
+
+#define __flush_s1_tlb_range_op(op, start, pages, stride, asid, tlb_level) \
+	__flush_tlb_range_op(op, r##op, start, pages, stride, asid, tlb_level, lpa2_is_enabled())
 
 #define __flush_s2_tlb_range_op(op, start, pages, stride, tlb_level) \
-	__flush_tlb_range_op(op, start, pages, stride, 0, tlb_level, kvm_lpa2_is_enabled());
+	__flush_tlb_range_op(op, r##op, start, pages, stride, 0, tlb_level, kvm_lpa2_is_enabled())
 
 static inline bool __flush_tlb_range_limit_excess(unsigned long start,
 		unsigned long end, unsigned long pages, unsigned long stride)
@@ -559,11 +568,11 @@ static inline void __flush_tlb_range_nosync(struct mm_struct *mm,
 	asid = ASID(mm);
 
 	if (last_level)
-		__flush_tlb_range_op(vale1is, start, pages, stride, asid,
-				     tlb_level, lpa2_is_enabled());
+		__flush_s1_tlb_range_op(vale1is, start, pages, stride,
+				     asid, tlb_level);
 	else
-		__flush_tlb_range_op(vae1is, start, pages, stride, asid,
-				     tlb_level, lpa2_is_enabled());
+		__flush_s1_tlb_range_op(vae1is, start, pages, stride,
+				     asid, tlb_level);
 
 	mmu_notifier_arch_invalidate_secondary_tlbs(mm, start, end);
 }
@@ -587,8 +596,7 @@ static inline void local_flush_tlb_contpte(struct vm_area_struct *vma,
 
 	dsb(nshst);
 	asid = ASID(vma->vm_mm);
-	__flush_tlb_range_op(vale1, addr, CONT_PTES, PAGE_SIZE, asid,
-			     3, true, lpa2_is_enabled());
+	__flush_s1_tlb_range_op(vale1, addr, CONT_PTES, PAGE_SIZE, asid, 3);
 	mmu_notifier_arch_invalidate_secondary_tlbs(vma->vm_mm, addr,
 						    addr + CONT_PTE_SIZE);
 	dsb(nsh);
@@ -621,8 +629,8 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end
 	}
 
 	dsb(ishst);
-	__flush_tlb_range_op(vaale1is, start, pages, stride, 0,
-			     TLBI_TTL_UNKNOWN, lpa2_is_enabled());
+	__flush_s1_tlb_range_op(vaale1is, start, pages, stride, 0,
+				TLBI_TTL_UNKNOWN);
 	dsb(ish);
 	isb();
 }
-- 
2.43.0



From ryan.roberts at arm.com  Tue Dec 16 06:45:52 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Tue, 16 Dec 2025 14:45:52 +0000
Subject: [PATCH v1 07/13] arm64: mm: Simplify __TLBI_RANGE_NUM() macro
In-Reply-To: <20251216144601.2106412-1-ryan.roberts@arm.com>
References: <20251216144601.2106412-1-ryan.roberts@arm.com>
Message-ID: <20251216144601.2106412-8-ryan.roberts@arm.com>

From: Will Deacon <will at kernel.org>

Since commit e2768b798a19 ("arm64/mm: Modify range-based tlbi to
decrement scale"), we don't need to clamp the 'pages' argument to fit
the range for the specified 'scale' as we know that the upper bits will
have been processed in a prior iteration.

Drop the clamping and simplify the __TLBI_RANGE_NUM() macro.

Signed-off-by: Will Deacon <will at kernel.org>
Reviewed-by: Ryan Roberts <ryan.roberts at arm.com>
Reviewed-by: Dev Jain <dev.jain at arm.com>
Signed-off-by: Ryan Roberts <ryan.roberts at arm.com>
---
 arch/arm64/include/asm/tlbflush.h | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
index d2a144a09a8f..0e1902f66e01 100644
--- a/arch/arm64/include/asm/tlbflush.h
+++ b/arch/arm64/include/asm/tlbflush.h
@@ -208,11 +208,7 @@ static inline void __tlbi_level(tlbi_op op, u64 addr, u32 level)
  * range.
  */
 #define __TLBI_RANGE_NUM(pages, scale)					\
-	({								\
-		int __pages = min((pages),				\
-				  __TLBI_RANGE_PAGES(31, (scale)));	\
-		(__pages >> (5 * (scale) + 1)) - 1;			\
-	})
+	(((pages) >> (5 * (scale) + 1)) - 1)
 
 /*
  *	TLB Invalidation
-- 
2.43.0



From ryan.roberts at arm.com  Tue Dec 16 06:45:53 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Tue, 16 Dec 2025 14:45:53 +0000
Subject: [PATCH v1 08/13] arm64: mm: Simplify __flush_tlb_range_limit_excess()
In-Reply-To: <20251216144601.2106412-1-ryan.roberts@arm.com>
References: <20251216144601.2106412-1-ryan.roberts@arm.com>
Message-ID: <20251216144601.2106412-9-ryan.roberts@arm.com>

From: Will Deacon <will at kernel.org>

__flush_tlb_range_limit_excess() is unnecessarily complicated:

  - It takes a 'start', 'end' and 'pages' argument, whereas it only
    needs 'pages' (which the caller has computed from the other two
    arguments!).

  - It erroneously compares 'pages' with MAX_TLBI_RANGE_PAGES when
    the system doesn't support range-based invalidation but the range to
    be invalidated would result in fewer than MAX_DVM_OPS invalidations.

Simplify the function so that it no longer takes the 'start' and 'end'
arguments and only considers the MAX_TLBI_RANGE_PAGES threshold on
systems that implement range-based invalidation.

Signed-off-by: Will Deacon <will at kernel.org>
Signed-off-by: Ryan Roberts <ryan.roberts at arm.com>
---
 arch/arm64/include/asm/tlbflush.h | 20 ++++++--------------
 1 file changed, 6 insertions(+), 14 deletions(-)

diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
index 0e1902f66e01..3b72a71feac0 100644
--- a/arch/arm64/include/asm/tlbflush.h
+++ b/arch/arm64/include/asm/tlbflush.h
@@ -527,21 +527,13 @@ static __always_inline void __flush_tlb_range_op(tlbi_op lop, tlbi_op rop,
 #define __flush_s2_tlb_range_op(op, start, pages, stride, tlb_level) \
 	__flush_tlb_range_op(op, r##op, start, pages, stride, 0, tlb_level, kvm_lpa2_is_enabled())
 
-static inline bool __flush_tlb_range_limit_excess(unsigned long start,
-		unsigned long end, unsigned long pages, unsigned long stride)
+static inline bool __flush_tlb_range_limit_excess(unsigned long pages,
+						  unsigned long stride)
 {
-	/*
-	 * When the system does not support TLB range based flush
-	 * operation, (MAX_DVM_OPS - 1) pages can be handled. But
-	 * with TLB range based operation, MAX_TLBI_RANGE_PAGES
-	 * pages can be handled.
-	 */
-	if ((!system_supports_tlb_range() &&
-	     (end - start) >= (MAX_DVM_OPS * stride)) ||
-	    pages > MAX_TLBI_RANGE_PAGES)
+	if (system_supports_tlb_range() && pages > MAX_TLBI_RANGE_PAGES)
 		return true;
 
-	return false;
+	return pages >= (MAX_DVM_OPS * stride) >> PAGE_SHIFT;
 }
 
 static inline void __flush_tlb_range_nosync(struct mm_struct *mm,
@@ -555,7 +547,7 @@ static inline void __flush_tlb_range_nosync(struct mm_struct *mm,
 	end = round_up(end, stride);
 	pages = (end - start) >> PAGE_SHIFT;
 
-	if (__flush_tlb_range_limit_excess(start, end, pages, stride)) {
+	if (__flush_tlb_range_limit_excess(pages, stride)) {
 		flush_tlb_mm(mm);
 		return;
 	}
@@ -619,7 +611,7 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end
 	end = round_up(end, stride);
 	pages = (end - start) >> PAGE_SHIFT;
 
-	if (__flush_tlb_range_limit_excess(start, end, pages, stride)) {
+	if (__flush_tlb_range_limit_excess(pages, stride)) {
 		flush_tlb_all();
 		return;
 	}
-- 
2.43.0



From ryan.roberts at arm.com  Tue Dec 16 06:45:54 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Tue, 16 Dec 2025 14:45:54 +0000
Subject: [PATCH v1 09/13] arm64: mm: Refactor flush_tlb_page() to use __tlbi_level_asid()
In-Reply-To: <20251216144601.2106412-1-ryan.roberts@arm.com>
References: <20251216144601.2106412-1-ryan.roberts@arm.com>
Message-ID: <20251216144601.2106412-10-ryan.roberts@arm.com>

Now that we have __tlbi_level_asid(), let's refactor the
*flush_tlb_page*() variants to use it rather than open coding.

The emitted tlbi(s) is/are intended to be exactly the same as before; no
TTL hint is provided. Although the spec for flush_tlb_page() allows for
setting the TTL hint to 3, it turns out that
flush_tlb_fix_spurious_fault_pmd() depends on
local_flush_tlb_page_nonotify() to invalidate the level 2 entry. This
will be fixed separately.

Signed-off-by: Ryan Roberts <ryan.roberts at arm.com>
---
 arch/arm64/include/asm/tlbflush.h | 12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
index 3b72a71feac0..37c782ddc149 100644
--- a/arch/arm64/include/asm/tlbflush.h
+++ b/arch/arm64/include/asm/tlbflush.h
@@ -327,12 +327,8 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
 static inline void __local_flush_tlb_page_nonotify_nosync(struct mm_struct *mm,
 							  unsigned long uaddr)
 {
-	unsigned long addr;
-
 	dsb(nshst);
-	addr = __TLBI_VADDR(uaddr, ASID(mm));
-	__tlbi(vale1, addr);
-	__tlbi_user(vale1, addr);
+	__tlbi_level_asid(vale1, uaddr, TLBI_TTL_UNKNOWN, ASID(mm));
 }
 
 static inline void local_flush_tlb_page_nonotify(struct vm_area_struct *vma,
@@ -354,12 +350,8 @@ static inline void local_flush_tlb_page(struct vm_area_struct *vma,
 static inline void __flush_tlb_page_nosync(struct mm_struct *mm,
 					   unsigned long uaddr)
 {
-	unsigned long addr;
-
 	dsb(ishst);
-	addr = __TLBI_VADDR(uaddr, ASID(mm));
-	__tlbi(vale1is, addr);
-	__tlbi_user(vale1is, addr);
+	__tlbi_level_asid(vale1is, uaddr, TLBI_TTL_UNKNOWN, ASID(mm));
 	mmu_notifier_arch_invalidate_secondary_tlbs(mm, uaddr & PAGE_MASK,
 						(uaddr & PAGE_MASK) + PAGE_SIZE);
 }
-- 
2.43.0



From ryan.roberts at arm.com  Tue Dec 16 06:45:55 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Tue, 16 Dec 2025 14:45:55 +0000
Subject: [PATCH v1 10/13] arm64: mm: Refactor __flush_tlb_range() to take flags
In-Reply-To: <20251216144601.2106412-1-ryan.roberts@arm.com>
References: <20251216144601.2106412-1-ryan.roberts@arm.com>
Message-ID: <20251216144601.2106412-11-ryan.roberts@arm.com>

We have function variants with "_nosync", "_local", "_nonotify" as well
as the "last_level" parameter. Let's generalize and simplify by using a
flags parameter to encode all these variants.

As a first step, convert the "last_level" boolean parameter to a flags
parameter and create the first flag, TLBF_NOWALKCACHE. When present,
walk cache entries are not evicted, which is the same as the old
last_level=true.

Signed-off-by: Ryan Roberts <ryan.roberts at arm.com>
---
 arch/arm64/include/asm/hugetlb.h  | 12 ++++++------
 arch/arm64/include/asm/pgtable.h  |  4 ++--
 arch/arm64/include/asm/tlb.h      |  6 +++---
 arch/arm64/include/asm/tlbflush.h | 28 ++++++++++++++++------------
 arch/arm64/mm/contpte.c           |  5 +++--
 arch/arm64/mm/hugetlbpage.c       |  4 ++--
 arch/arm64/mm/mmu.c               |  2 +-
 7 files changed, 33 insertions(+), 28 deletions(-)

diff --git a/arch/arm64/include/asm/hugetlb.h b/arch/arm64/include/asm/hugetlb.h
index 44c1f757bfcf..04af9499faf2 100644
--- a/arch/arm64/include/asm/hugetlb.h
+++ b/arch/arm64/include/asm/hugetlb.h
@@ -73,23 +73,23 @@ static inline void __flush_hugetlb_tlb_range(struct vm_area_struct *vma,
 					     unsigned long start,
 					     unsigned long end,
 					     unsigned long stride,
-					     bool last_level)
+					     tlbf_t flags)
 {
 	switch (stride) {
 #ifndef __PAGETABLE_PMD_FOLDED
 	case PUD_SIZE:
-		__flush_tlb_range(vma, start, end, PUD_SIZE, last_level, 1);
+		__flush_tlb_range(vma, start, end, PUD_SIZE, 1, flags);
 		break;
 #endif
 	case CONT_PMD_SIZE:
 	case PMD_SIZE:
-		__flush_tlb_range(vma, start, end, PMD_SIZE, last_level, 2);
+		__flush_tlb_range(vma, start, end, PMD_SIZE, 2, flags);
 		break;
 	case CONT_PTE_SIZE:
-		__flush_tlb_range(vma, start, end, PAGE_SIZE, last_level, 3);
+		__flush_tlb_range(vma, start, end, PAGE_SIZE, 3, flags);
 		break;
 	default:
-		__flush_tlb_range(vma, start, end, PAGE_SIZE, last_level, TLBI_TTL_UNKNOWN);
+		__flush_tlb_range(vma, start, end, PAGE_SIZE, TLBI_TTL_UNKNOWN, flags);
 	}
 }
 
@@ -100,7 +100,7 @@ static inline void flush_hugetlb_tlb_range(struct vm_area_struct *vma,
 {
 	unsigned long stride = huge_page_size(hstate_vma(vma));
 
-	__flush_hugetlb_tlb_range(vma, start, end, stride, false);
+	__flush_hugetlb_tlb_range(vma, start, end, stride, TLBF_NONE);
 }
 
 #endif /* __ASM_HUGETLB_H */
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 64d5f1d9cce9..736747fbc843 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -124,9 +124,9 @@ static inline void arch_leave_lazy_mmu_mode(void)
 
 /* Set stride and tlb_level in flush_*_tlb_range */
 #define flush_pmd_tlb_range(vma, addr, end)	\
-	__flush_tlb_range(vma, addr, end, PMD_SIZE, false, 2)
+	__flush_tlb_range(vma, addr, end, PMD_SIZE, 2, TLBF_NONE)
 #define flush_pud_tlb_range(vma, addr, end)	\
-	__flush_tlb_range(vma, addr, end, PUD_SIZE, false, 1)
+	__flush_tlb_range(vma, addr, end, PUD_SIZE, 1, TLBF_NONE)
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
 /*
diff --git a/arch/arm64/include/asm/tlb.h b/arch/arm64/include/asm/tlb.h
index 8d762607285c..10869d7731b8 100644
--- a/arch/arm64/include/asm/tlb.h
+++ b/arch/arm64/include/asm/tlb.h
@@ -53,7 +53,7 @@ static inline int tlb_get_level(struct mmu_gather *tlb)
 static inline void tlb_flush(struct mmu_gather *tlb)
 {
 	struct vm_area_struct vma = TLB_FLUSH_VMA(tlb->mm, 0);
-	bool last_level = !tlb->freed_tables;
+	tlbf_t flags = tlb->freed_tables ? TLBF_NONE : TLBF_NOWALKCACHE;
 	unsigned long stride = tlb_get_unmap_size(tlb);
 	int tlb_level = tlb_get_level(tlb);
 
@@ -63,13 +63,13 @@ static inline void tlb_flush(struct mmu_gather *tlb)
 	 * reallocate our ASID without invalidating the entire TLB.
 	 */
 	if (tlb->fullmm) {
-		if (!last_level)
+		if (tlb->freed_tables)
 			flush_tlb_mm(tlb->mm);
 		return;
 	}
 
 	__flush_tlb_range(&vma, tlb->start, tlb->end, stride,
-			  last_level, tlb_level);
+			  tlb_level, flags);
 }
 
 static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
index 37c782ddc149..9a37a6a014dc 100644
--- a/arch/arm64/include/asm/tlbflush.h
+++ b/arch/arm64/include/asm/tlbflush.h
@@ -267,16 +267,16 @@ static inline void __tlbi_level(tlbi_op op, u64 addr, u32 level)
  *		CPUs, ensuring that any walk-cache entries associated with the
  *		translation are also invalidated.
  *
- *	__flush_tlb_range(vma, start, end, stride, last_level, tlb_level)
+ *	__flush_tlb_range(vma, start, end, stride, last_level, tlb_level, flags)
  *		Invalidate the virtual-address range '[start, end)' on all
  *		CPUs for the user address space corresponding to 'vma->mm'.
  *		The invalidation operations are issued at a granularity
- *		determined by 'stride' and only affect any walk-cache entries
- *		if 'last_level' is equal to false. tlb_level is the level at
+ *		determined by 'stride'. tlb_level is the level at
  *		which the invalidation must take place. If the level is wrong,
  *		no invalidation may take place. In the case where the level
  *		cannot be easily determined, the value TLBI_TTL_UNKNOWN will
- *		perform a non-hinted invalidation.
+ *		perform a non-hinted invalidation. flags may be TLBF_NONE (0) or
+ *		TLBF_NOWALKCACHE (elide eviction of walk cache entries).
  *
  *	local_flush_tlb_page(vma, addr)
  *		Local variant of flush_tlb_page().  Stale TLB entries may
@@ -528,10 +528,14 @@ static inline bool __flush_tlb_range_limit_excess(unsigned long pages,
 	return pages >= (MAX_DVM_OPS * stride) >> PAGE_SHIFT;
 }
 
+typedef unsigned __bitwise tlbf_t;
+#define TLBF_NONE		((__force tlbf_t)0)
+#define TLBF_NOWALKCACHE	((__force tlbf_t)BIT(0))
+
 static inline void __flush_tlb_range_nosync(struct mm_struct *mm,
 				     unsigned long start, unsigned long end,
-				     unsigned long stride, bool last_level,
-				     int tlb_level)
+				     unsigned long stride, int tlb_level,
+				     tlbf_t flags)
 {
 	unsigned long asid, pages;
 
@@ -547,7 +551,7 @@ static inline void __flush_tlb_range_nosync(struct mm_struct *mm,
 	dsb(ishst);
 	asid = ASID(mm);
 
-	if (last_level)
+	if (flags & TLBF_NOWALKCACHE)
 		__flush_s1_tlb_range_op(vale1is, start, pages, stride,
 				     asid, tlb_level);
 	else
@@ -559,11 +563,11 @@ static inline void __flush_tlb_range_nosync(struct mm_struct *mm,
 
 static inline void __flush_tlb_range(struct vm_area_struct *vma,
 				     unsigned long start, unsigned long end,
-				     unsigned long stride, bool last_level,
-				     int tlb_level)
+				     unsigned long stride, int tlb_level,
+				     tlbf_t flags)
 {
 	__flush_tlb_range_nosync(vma->vm_mm, start, end, stride,
-				 last_level, tlb_level);
+				 tlb_level, flags);
 	dsb(ish);
 }
 
@@ -591,7 +595,7 @@ static inline void flush_tlb_range(struct vm_area_struct *vma,
 	 * Set the tlb_level to TLBI_TTL_UNKNOWN because we can not get enough
 	 * information here.
 	 */
-	__flush_tlb_range(vma, start, end, PAGE_SIZE, false, TLBI_TTL_UNKNOWN);
+	__flush_tlb_range(vma, start, end, PAGE_SIZE, TLBI_TTL_UNKNOWN, TLBF_NONE);
 }
 
 static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end)
@@ -632,7 +636,7 @@ static inline void __flush_tlb_kernel_pgtable(unsigned long kaddr)
 static inline void arch_tlbbatch_add_pending(struct arch_tlbflush_unmap_batch *batch,
 		struct mm_struct *mm, unsigned long start, unsigned long end)
 {
-	__flush_tlb_range_nosync(mm, start, end, PAGE_SIZE, true, 3);
+	__flush_tlb_range_nosync(mm, start, end, PAGE_SIZE, 3, TLBF_NOWALKCACHE);
 }
 
 static inline bool __pte_flags_need_flush(ptdesc_t oldval, ptdesc_t newval)
diff --git a/arch/arm64/mm/contpte.c b/arch/arm64/mm/contpte.c
index 589bcf878938..1a12bb728ee1 100644
--- a/arch/arm64/mm/contpte.c
+++ b/arch/arm64/mm/contpte.c
@@ -205,7 +205,8 @@ static void contpte_convert(struct mm_struct *mm, unsigned long addr,
 	 */
 
 	if (!system_supports_bbml2_noabort())
-		__flush_tlb_range(&vma, start_addr, addr, PAGE_SIZE, true, 3);
+		__flush_tlb_range(&vma, start_addr, addr, PAGE_SIZE, 3,
+				  TLBF_NOWALKCACHE);
 
 	__set_ptes(mm, start_addr, start_ptep, pte, CONT_PTES);
 }
@@ -527,7 +528,7 @@ int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
 		 */
 		addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
 		__flush_tlb_range_nosync(vma->vm_mm, addr, addr + CONT_PTE_SIZE,
-					 PAGE_SIZE, true, 3);
+					 PAGE_SIZE, 3, TLBF_NOWALKCACHE);
 	}
 
 	return young;
diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c
index 1d90a7e75333..7b95663f8c76 100644
--- a/arch/arm64/mm/hugetlbpage.c
+++ b/arch/arm64/mm/hugetlbpage.c
@@ -184,7 +184,7 @@ static pte_t get_clear_contig_flush(struct mm_struct *mm,
 	struct vm_area_struct vma = TLB_FLUSH_VMA(mm, 0);
 	unsigned long end = addr + (pgsize * ncontig);
 
-	__flush_hugetlb_tlb_range(&vma, addr, end, pgsize, true);
+	__flush_hugetlb_tlb_range(&vma, addr, end, pgsize, TLBF_NOWALKCACHE);
 	return orig_pte;
 }
 
@@ -212,7 +212,7 @@ static void clear_flush(struct mm_struct *mm,
 	if (mm == &init_mm)
 		flush_tlb_kernel_range(saddr, addr);
 	else
-		__flush_hugetlb_tlb_range(&vma, saddr, addr, pgsize, true);
+		__flush_hugetlb_tlb_range(&vma, saddr, addr, pgsize, TLBF_NOWALKCACHE);
 }
 
 void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 9ae7ce00a7ef..a17d617a959a 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -2150,7 +2150,7 @@ pte_t modify_prot_start_ptes(struct vm_area_struct *vma, unsigned long addr,
 		 */
 		if (pte_accessible(vma->vm_mm, pte) && pte_user_exec(pte))
 			__flush_tlb_range(vma, addr, nr * PAGE_SIZE,
-					  PAGE_SIZE, true, 3);
+					  PAGE_SIZE, 3, TLBF_NOWALKCACHE);
 	}
 
 	return pte;
-- 
2.43.0



From ryan.roberts at arm.com  Tue Dec 16 06:45:56 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Tue, 16 Dec 2025 14:45:56 +0000
Subject: [PATCH v1 11/13] arm64: mm: More flags for __flush_tlb_range()
In-Reply-To: <20251216144601.2106412-1-ryan.roberts@arm.com>
References: <20251216144601.2106412-1-ryan.roberts@arm.com>
Message-ID: <20251216144601.2106412-12-ryan.roberts@arm.com>

Refactor function variants with "_nosync", "_local" and "_nonotify" into
a single __always_inline implementation that takes flags and rely on
constant folding to select the parts that are actually needed at any
given callsite, based on the provided flags.

Flags all live in the tlbf_t (TLB flags) type; TLBF_NONE (0) continues
to provide the strongest semantics (i.e. evict from walk cache,
broadcast, synchronise and notify). Each flag reduces the strength in
some way; TLBF_NONOTIFY, TLBF_NOSYNC and TLBF_NOBROADCAST are added to
complement the existing TLBF_NOWALKCACHE.

The result is a clearer, simpler, more powerful API.

Signed-off-by: Ryan Roberts <ryan.roberts at arm.com>
---
 arch/arm64/include/asm/tlbflush.h | 101 ++++++++++++++++++------------
 arch/arm64/mm/contpte.c           |   9 ++-
 2 files changed, 68 insertions(+), 42 deletions(-)

diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
index 9a37a6a014dc..ee747e66bbef 100644
--- a/arch/arm64/include/asm/tlbflush.h
+++ b/arch/arm64/include/asm/tlbflush.h
@@ -107,6 +107,12 @@ static inline unsigned long get_trans_granule(void)
 
 typedef void (*tlbi_op)(u64 arg);
 
+static __always_inline void vae1(u64 arg)
+{
+	__tlbi(vae1, arg);
+	__tlbi_user(vae1, arg);
+}
+
 static __always_inline void vae1is(u64 arg)
 {
 	__tlbi(vae1is, arg);
@@ -276,7 +282,10 @@ static inline void __tlbi_level(tlbi_op op, u64 addr, u32 level)
  *		no invalidation may take place. In the case where the level
  *		cannot be easily determined, the value TLBI_TTL_UNKNOWN will
  *		perform a non-hinted invalidation. flags may be TLBF_NONE (0) or
- *		TLBF_NOWALKCACHE (elide eviction of walk cache entries).
+ *		any combination of TLBF_NOWALKCACHE (elide eviction of walk
+ *		cache entries), TLBF_NONOTIFY (don't call mmu notifiers),
+ *		TLBF_NOSYNC (don't issue trailing dsb) and TLBF_NOBROADCAST
+ *		(only perform the invalidation for the local cpu).
  *
  *	local_flush_tlb_page(vma, addr)
  *		Local variant of flush_tlb_page().  Stale TLB entries may
@@ -286,12 +295,6 @@ static inline void __tlbi_level(tlbi_op op, u64 addr, u32 level)
  *		Same as local_flush_tlb_page() except MMU notifier will not be
  *		called.
  *
- *	local_flush_tlb_contpte(vma, addr)
- *		Invalidate the virtual-address range
- *		'[addr, addr+CONT_PTE_SIZE)' mapped with contpte on local CPU
- *		for the user address space corresponding to 'vma->mm'.  Stale
- *		TLB entries may remain in remote CPUs.
- *
  *	Finally, take a look at asm/tlb.h to see how tlb_flush() is implemented
  *	on top of these routines, since that is our interface to the mmu_gather
  *	API as used by munmap() and friends.
@@ -436,6 +439,12 @@ static inline void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch)
  *    operations can only span an even number of pages. We save this for last to
  *    ensure 64KB start alignment is maintained for the LPA2 case.
  */
+static __always_inline void rvae1(u64 arg)
+{
+	__tlbi(rvae1, arg);
+	__tlbi_user(rvae1, arg);
+}
+
 static __always_inline void rvae1is(u64 arg)
 {
 	__tlbi(rvae1is, arg);
@@ -531,16 +540,18 @@ static inline bool __flush_tlb_range_limit_excess(unsigned long pages,
 typedef unsigned __bitwise tlbf_t;
 #define TLBF_NONE		((__force tlbf_t)0)
 #define TLBF_NOWALKCACHE	((__force tlbf_t)BIT(0))
+#define TLBF_NOSYNC		((__force tlbf_t)BIT(1))
+#define TLBF_NONOTIFY		((__force tlbf_t)BIT(2))
+#define TLBF_NOBROADCAST	((__force tlbf_t)BIT(3))
 
-static inline void __flush_tlb_range_nosync(struct mm_struct *mm,
-				     unsigned long start, unsigned long end,
-				     unsigned long stride, int tlb_level,
-				     tlbf_t flags)
+static __always_inline void ___flush_tlb_range(struct vm_area_struct *vma,
+					unsigned long start, unsigned long end,
+					unsigned long stride, int tlb_level,
+					tlbf_t flags)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long asid, pages;
 
-	start = round_down(start, stride);
-	end = round_up(end, stride);
 	pages = (end - start) >> PAGE_SHIFT;
 
 	if (__flush_tlb_range_limit_excess(pages, stride)) {
@@ -548,17 +559,41 @@ static inline void __flush_tlb_range_nosync(struct mm_struct *mm,
 		return;
 	}
 
-	dsb(ishst);
+	if (!(flags & TLBF_NOBROADCAST))
+		dsb(ishst);
+	else
+		dsb(nshst);
+
 	asid = ASID(mm);
 
-	if (flags & TLBF_NOWALKCACHE)
-		__flush_s1_tlb_range_op(vale1is, start, pages, stride,
-				     asid, tlb_level);
-	else
+	switch (flags & (TLBF_NOWALKCACHE | TLBF_NOBROADCAST)) {
+	case TLBF_NONE:
 		__flush_s1_tlb_range_op(vae1is, start, pages, stride,
-				     asid, tlb_level);
+					asid, tlb_level);
+		break;
+	case TLBF_NOWALKCACHE:
+		__flush_s1_tlb_range_op(vale1is, start, pages, stride,
+					asid, tlb_level);
+		break;
+	case TLBF_NOBROADCAST:
+		__flush_s1_tlb_range_op(vae1, start, pages, stride,
+					asid, tlb_level);
+		break;
+	case TLBF_NOWALKCACHE | TLBF_NOBROADCAST:
+		__flush_s1_tlb_range_op(vale1, start, pages, stride,
+					asid, tlb_level);
+		break;
+	}
 
-	mmu_notifier_arch_invalidate_secondary_tlbs(mm, start, end);
+	if (!(flags & TLBF_NONOTIFY))
+		mmu_notifier_arch_invalidate_secondary_tlbs(mm, start, end);
+
+	if (!(flags & TLBF_NOSYNC)) {
+		if (!(flags & TLBF_NOBROADCAST))
+			dsb(ish);
+		else
+			dsb(nsh);
+	}
 }
 
 static inline void __flush_tlb_range(struct vm_area_struct *vma,
@@ -566,24 +601,9 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma,
 				     unsigned long stride, int tlb_level,
 				     tlbf_t flags)
 {
-	__flush_tlb_range_nosync(vma->vm_mm, start, end, stride,
-				 tlb_level, flags);
-	dsb(ish);
-}
-
-static inline void local_flush_tlb_contpte(struct vm_area_struct *vma,
-					   unsigned long addr)
-{
-	unsigned long asid;
-
-	addr = round_down(addr, CONT_PTE_SIZE);
-
-	dsb(nshst);
-	asid = ASID(vma->vm_mm);
-	__flush_s1_tlb_range_op(vale1, addr, CONT_PTES, PAGE_SIZE, asid, 3);
-	mmu_notifier_arch_invalidate_secondary_tlbs(vma->vm_mm, addr,
-						    addr + CONT_PTE_SIZE);
-	dsb(nsh);
+	start = round_down(start, stride);
+	end = round_up(end, stride);
+	___flush_tlb_range(vma, start, end, stride, tlb_level, flags);
 }
 
 static inline void flush_tlb_range(struct vm_area_struct *vma,
@@ -636,7 +656,10 @@ static inline void __flush_tlb_kernel_pgtable(unsigned long kaddr)
 static inline void arch_tlbbatch_add_pending(struct arch_tlbflush_unmap_batch *batch,
 		struct mm_struct *mm, unsigned long start, unsigned long end)
 {
-	__flush_tlb_range_nosync(mm, start, end, PAGE_SIZE, 3, TLBF_NOWALKCACHE);
+	struct vm_area_struct vma = { .vm_mm = mm, .vm_flags = 0 };
+
+	__flush_tlb_range(&vma, start, end, PAGE_SIZE, 3,
+			  TLBF_NOWALKCACHE | TLBF_NOSYNC);
 }
 
 static inline bool __pte_flags_need_flush(ptdesc_t oldval, ptdesc_t newval)
diff --git a/arch/arm64/mm/contpte.c b/arch/arm64/mm/contpte.c
index 1a12bb728ee1..ec17a0e70415 100644
--- a/arch/arm64/mm/contpte.c
+++ b/arch/arm64/mm/contpte.c
@@ -527,8 +527,8 @@ int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
 		 * eliding the trailing DSB applies here.
 		 */
 		addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
-		__flush_tlb_range_nosync(vma->vm_mm, addr, addr + CONT_PTE_SIZE,
-					 PAGE_SIZE, 3, TLBF_NOWALKCACHE);
+		__flush_tlb_range(vma, addr, addr + CONT_PTE_SIZE,
+				  PAGE_SIZE, 3, TLBF_NOWALKCACHE | TLBF_NOSYNC);
 	}
 
 	return young;
@@ -623,7 +623,10 @@ int contpte_ptep_set_access_flags(struct vm_area_struct *vma,
 			__ptep_set_access_flags(vma, addr, ptep, entry, 0);
 
 		if (dirty)
-			local_flush_tlb_contpte(vma, start_addr);
+			__flush_tlb_range(vma, start_addr,
+					  start_addr + CONT_PTE_SIZE,
+					  PAGE_SIZE, 3,
+					  TLBF_NOWALKCACHE | TLBF_NOBROADCAST);
 	} else {
 		__contpte_try_unfold(vma->vm_mm, addr, ptep, orig_pte);
 		__ptep_set_access_flags(vma, addr, ptep, entry, dirty);
-- 
2.43.0



From ryan.roberts at arm.com  Tue Dec 16 06:45:57 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Tue, 16 Dec 2025 14:45:57 +0000
Subject: [PATCH v1 12/13] arm64: mm: Wrap flush_tlb_page() around ___flush_tlb_range()
In-Reply-To: <20251216144601.2106412-1-ryan.roberts@arm.com>
References: <20251216144601.2106412-1-ryan.roberts@arm.com>
Message-ID: <20251216144601.2106412-13-ryan.roberts@arm.com>

Flushing a page from the tlb is just a special case of flushing a range.
So let's rework flush_tlb_page() so that it simply wraps
___flush_tlb_range(). While at it, let's also update the API to take the
same flags that we use when flushing a range. This allows us to delete
all the ugly "_nosync", "_local" and "_nonotify" variants.

Thanks to constant folding, all of the complex looping and tlbi-by-range
options get eliminated so that the generated code for flush_tlb_page()
looks very similar to the previous version.

Signed-off-by: Ryan Roberts <ryan.roberts at arm.com>
---
 arch/arm64/include/asm/pgtable.h  |  6 +--
 arch/arm64/include/asm/tlbflush.h | 81 ++++++++++---------------------
 arch/arm64/mm/fault.c             |  2 +-
 3 files changed, 29 insertions(+), 60 deletions(-)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 736747fbc843..b96a7ca465a1 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -136,10 +136,10 @@ static inline void arch_leave_lazy_mmu_mode(void)
  * entries exist.
  */
 #define flush_tlb_fix_spurious_fault(vma, address, ptep)	\
-	local_flush_tlb_page_nonotify(vma, address)
+	__flush_tlb_page(vma, address, TLBF_NOBROADCAST | TLBF_NONOTIFY)
 
 #define flush_tlb_fix_spurious_fault_pmd(vma, address, pmdp)	\
-	local_flush_tlb_page_nonotify(vma, address)
+	__flush_tlb_page(vma, address, TLBF_NOBROADCAST | TLBF_NONOTIFY)
 
 /*
  * ZERO_PAGE is a global shared page that is always zero: used
@@ -1351,7 +1351,7 @@ static inline int __ptep_clear_flush_young(struct vm_area_struct *vma,
 		 * context-switch, which provides a DSB to complete the TLB
 		 * invalidation.
 		 */
-		flush_tlb_page_nosync(vma, address);
+		__flush_tlb_page(vma, address, TLBF_NOSYNC);
 	}
 
 	return young;
diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
index ee747e66bbef..fa5aee990742 100644
--- a/arch/arm64/include/asm/tlbflush.h
+++ b/arch/arm64/include/asm/tlbflush.h
@@ -256,10 +256,7 @@ static inline void __tlbi_level(tlbi_op op, u64 addr, u32 level)
  *		unmapping pages from vmalloc/io space.
  *
  *	flush_tlb_page(vma, addr)
- *		Invalidate a single user mapping for address 'addr' in the
- *		address space corresponding to 'vma->mm'.  Note that this
- *		operation only invalidates a single, last-level page-table
- *		entry and therefore does not affect any walk-caches.
+ *		Equivalent to __flush_tlb_page(..., flags=TLBF_NONE)
  *
  *
  *	Next, we have some undocumented invalidation routines that you probably
@@ -287,13 +284,14 @@ static inline void __tlbi_level(tlbi_op op, u64 addr, u32 level)
  *		TLBF_NOSYNC (don't issue trailing dsb) and TLBF_NOBROADCAST
  *		(only perform the invalidation for the local cpu).
  *
- *	local_flush_tlb_page(vma, addr)
- *		Local variant of flush_tlb_page().  Stale TLB entries may
- *		remain in remote CPUs.
- *
- *	local_flush_tlb_page_nonotify(vma, addr)
- *		Same as local_flush_tlb_page() except MMU notifier will not be
- *		called.
+ *	__flush_tlb_page(vma, addr, flags)
+ *		Invalidate a single user mapping for address 'addr' in the
+ *		address space corresponding to 'vma->mm'.  Note that this
+ *		operation only invalidates a single, last-level page-table entry
+ *		and therefore does not affect any walk-caches. flags may contain
+ *		any combination of TLBF_NONOTIFY (don't call mmu notifiers),
+ *		TLBF_NOSYNC (don't issue trailing dsb) and TLBF_NOBROADCAST
+ *		(only perform the invalidation for the local cpu).
  *
  *	Finally, take a look at asm/tlb.h to see how tlb_flush() is implemented
  *	on top of these routines, since that is our interface to the mmu_gather
@@ -327,51 +325,6 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
 	mmu_notifier_arch_invalidate_secondary_tlbs(mm, 0, -1UL);
 }
 
-static inline void __local_flush_tlb_page_nonotify_nosync(struct mm_struct *mm,
-							  unsigned long uaddr)
-{
-	dsb(nshst);
-	__tlbi_level_asid(vale1, uaddr, TLBI_TTL_UNKNOWN, ASID(mm));
-}
-
-static inline void local_flush_tlb_page_nonotify(struct vm_area_struct *vma,
-						 unsigned long uaddr)
-{
-	__local_flush_tlb_page_nonotify_nosync(vma->vm_mm, uaddr);
-	dsb(nsh);
-}
-
-static inline void local_flush_tlb_page(struct vm_area_struct *vma,
-					unsigned long uaddr)
-{
-	__local_flush_tlb_page_nonotify_nosync(vma->vm_mm, uaddr);
-	mmu_notifier_arch_invalidate_secondary_tlbs(vma->vm_mm, uaddr & PAGE_MASK,
-						(uaddr & PAGE_MASK) + PAGE_SIZE);
-	dsb(nsh);
-}
-
-static inline void __flush_tlb_page_nosync(struct mm_struct *mm,
-					   unsigned long uaddr)
-{
-	dsb(ishst);
-	__tlbi_level_asid(vale1is, uaddr, TLBI_TTL_UNKNOWN, ASID(mm));
-	mmu_notifier_arch_invalidate_secondary_tlbs(mm, uaddr & PAGE_MASK,
-						(uaddr & PAGE_MASK) + PAGE_SIZE);
-}
-
-static inline void flush_tlb_page_nosync(struct vm_area_struct *vma,
-					 unsigned long uaddr)
-{
-	return __flush_tlb_page_nosync(vma->vm_mm, uaddr);
-}
-
-static inline void flush_tlb_page(struct vm_area_struct *vma,
-				  unsigned long uaddr)
-{
-	flush_tlb_page_nosync(vma, uaddr);
-	dsb(ish);
-}
-
 static inline bool arch_tlbbatch_should_defer(struct mm_struct *mm)
 {
 	/*
@@ -618,6 +571,22 @@ static inline void flush_tlb_range(struct vm_area_struct *vma,
 	__flush_tlb_range(vma, start, end, PAGE_SIZE, TLBI_TTL_UNKNOWN, TLBF_NONE);
 }
 
+static inline void __flush_tlb_page(struct vm_area_struct *vma,
+				    unsigned long uaddr, tlbf_t flags)
+{
+	unsigned long start = round_down(uaddr, PAGE_SIZE);
+	unsigned long end = start + PAGE_SIZE;
+
+	___flush_tlb_range(vma, start, end, PAGE_SIZE, TLBI_TTL_UNKNOWN,
+			   TLBF_NOWALKCACHE | flags);
+}
+
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+				  unsigned long uaddr)
+{
+	__flush_tlb_page(vma, uaddr, TLBF_NONE);
+}
+
 static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end)
 {
 	const unsigned long stride = PAGE_SIZE;
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index be9dab2c7d6a..f91aa686f142 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -239,7 +239,7 @@ int __ptep_set_access_flags(struct vm_area_struct *vma,
 	 * flush_tlb_fix_spurious_fault().
 	 */
 	if (dirty)
-		local_flush_tlb_page(vma, address);
+		__flush_tlb_page(vma, address, TLBF_NOBROADCAST);
 	return 1;
 }
 
-- 
2.43.0



From ryan.roberts at arm.com  Tue Dec 16 06:45:58 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Tue, 16 Dec 2025 14:45:58 +0000
Subject: [PATCH v1 13/13] arm64: mm: Provide level hint for flush_tlb_page()
In-Reply-To: <20251216144601.2106412-1-ryan.roberts@arm.com>
References: <20251216144601.2106412-1-ryan.roberts@arm.com>
Message-ID: <20251216144601.2106412-14-ryan.roberts@arm.com>

Previously tlb invalidations issued by __flush_tlb_page() did not
contain a level hint. But the function is clearly only ever targeting
level 3 tlb entries and its documentation agrees:

  | this operation only invalidates a single, last-level page-table
  | entry and therefore does not affect any walk-caches

However, it turns out that the function was actually being used to
invalidate a level 2 mapping via flush_tlb_fix_spurious_fault_pmd(). The
bug was benign because the level hint was not set so the HW would still
invalidate the PMD mapping, and also because the TLBF_NONOTIFY flag was
set, the bounds of the mapping were never used for anything else.

Now that we have the new and improved range-invalidation API, it is
trival to fix flush_tlb_fix_spurious_fault_pmd() to explicitly flush the
whole range (locally, without notification and last level only). So
let's do that, and then update __flush_tlb_page() to hint level 3.

Signed-off-by: Ryan Roberts <ryan.roberts at arm.com>
---
 arch/arm64/include/asm/pgtable.h  | 5 +++--
 arch/arm64/include/asm/tlbflush.h | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index b96a7ca465a1..61f57647361a 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -138,8 +138,9 @@ static inline void arch_leave_lazy_mmu_mode(void)
 #define flush_tlb_fix_spurious_fault(vma, address, ptep)	\
 	__flush_tlb_page(vma, address, TLBF_NOBROADCAST | TLBF_NONOTIFY)
 
-#define flush_tlb_fix_spurious_fault_pmd(vma, address, pmdp)	\
-	__flush_tlb_page(vma, address, TLBF_NOBROADCAST | TLBF_NONOTIFY)
+#define flush_tlb_fix_spurious_fault_pmd(vma, address, pmdp)			\
+	__flush_tlb_range(vma, address, address + PMD_SIZE, PMD_SIZE, 2,	\
+			  TLBF_NOBROADCAST | TLBF_NONOTIFY | TLBF_NOWALKCACHE)
 
 /*
  * ZERO_PAGE is a global shared page that is always zero: used
diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
index fa5aee990742..f24211b51df3 100644
--- a/arch/arm64/include/asm/tlbflush.h
+++ b/arch/arm64/include/asm/tlbflush.h
@@ -577,7 +577,7 @@ static inline void __flush_tlb_page(struct vm_area_struct *vma,
 	unsigned long start = round_down(uaddr, PAGE_SIZE);
 	unsigned long end = start + PAGE_SIZE;
 
-	___flush_tlb_range(vma, start, end, PAGE_SIZE, TLBI_TTL_UNKNOWN,
+	___flush_tlb_range(vma, start, end, PAGE_SIZE, 3,
 			   TLBF_NOWALKCACHE | flags);
 }
 
-- 
2.43.0



From sean.anderson at linux.dev  Tue Dec 16 06:48:00 2025
From: sean.anderson at linux.dev (Sean Anderson)
Date: Tue, 16 Dec 2025 09:48:00 -0500
Subject: [PATCH net-next v4 1/7] net: axienet: Fix resource release
 ordering
In-Reply-To: <SA1PR12MB6798CD01D26F4A68D6F7A214C9AAA@SA1PR12MB6798.namprd12.prod.outlook.com>
References: <20250805153456.1313661-1-sean.anderson@linux.dev>
 <20250805153456.1313661-2-sean.anderson@linux.dev>
 <9572f798-d294-4f24-8acb-c7972c1db247@lunn.ch>
 <SA1PR12MB6798CD01D26F4A68D6F7A214C9AAA@SA1PR12MB6798.namprd12.prod.outlook.com>
Message-ID: <540737b2-f155-4c55-ab95-b18f113e0031@linux.dev>

On 12/16/25 06:53, Gupta, Suraj wrote:
> [Public]
> 
> Hi,
>> -----Original Message-----
>> From: Andrew Lunn <andrew at lunn.ch>
>> Sent: Wednesday, August 6, 2025 2:29 AM
>> To: Sean Anderson <sean.anderson at linux.dev>
>> Cc: Pandey, Radhey Shyam <radhey.shyam.pandey at amd.com>; Andrew Lunn
>> <andrew+netdev at lunn.ch>; David S . Miller <davem at davemloft.net>; Eric
>> Dumazet <edumazet at google.com>; Jakub Kicinski <kuba at kernel.org>; Paolo
>> Abeni <pabeni at redhat.com>; netdev at vger.kernel.org; linux-arm-
>> kernel at lists.infradead.org; linux-kernel at vger.kernel.org; Greg Kroah-Hartman
>> <gregkh at linuxfoundation.org>; Simek, Michal <michal.simek at amd.com>;
>> Leon Romanovsky <leon at kernel.org>; Gupta, Suraj <Suraj.Gupta2 at amd.com>
>> Subject: Re: [PATCH net-next v4 1/7] net: axienet: Fix resource release ordering
>>
>> Caution: This message originated from an External Source. Use proper caution
>> when opening attachments, clicking links, or responding.
>>
>>
>> > +static void axienet_disable_misc(void *clocks) {
>> > +     clk_bulk_disable_unprepare(XAE_NUM_MISC_CLOCKS, clocks); }
>> > +
>>
>> ...
>>
>> >       ret = devm_clk_bulk_get_optional(&pdev->dev, XAE_NUM_MISC_CLOCKS,
>> lp->misc_clks);
>> >       if (ret)
>> > -             goto cleanup_clk;
>> > +             return dev_err_probe(&pdev->dev, ret,
>> > +                                  "could not get misc. clocks\n");
>> >
>> >       ret = clk_bulk_prepare_enable(XAE_NUM_MISC_CLOCKS, lp->misc_clks);
>> >       if (ret)
>> > -             goto cleanup_clk;
>> > +             return dev_err_probe(&pdev->dev, ret,
>> > +                                  "could not enable misc. clocks\n");
>> > +
>> > +     ret = devm_add_action_or_reset(&pdev->dev, axienet_disable_misc,
>> > +                                    lp->misc_clks);
>>
>> It seems like it would be better to add
>> devm_clk_bulk_get_optional_enable(). There is already an
>> devm_clk_bulk_get_all_enabled() so it does not seem like too big a step.
>>
>>         Andrew
> 
> We are interested in this patch to fix AXI Ethernet probe path and can collaborate on upstreaming it.

Feel free to modify it as suggested by Andrew.

Unfortunately I have not had time to work on this series recently and probably
won't be able to return to it for another few months.

--Sean


From alexander.stein at ew.tq-group.com  Tue Dec 16 06:50:17 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Tue, 16 Dec 2025 15:50:17 +0100
Subject: [PATCH v3 2/5] media: nxp: use dev_err_probe() to simplify code
In-Reply-To: <aUFwqMiYE+P+KdsO@lizhi-Precision-Tower-5810>
References: <20251215-cam_cleanup-v3-0-a61995068f38@nxp.com>
 <5462566.31r3eYUQgx@steina-w> <aUFwqMiYE+P+KdsO@lizhi-Precision-Tower-5810>
Message-ID: <13428800.O9o76ZdvQC@steina-w>

Hi Frank,

Am Dienstag, 16. Dezember 2025, 15:46:00 CET schrieb Frank Li:
> On Tue, Dec 16, 2025 at 08:34:18AM +0100, Alexander Stein wrote:
> > Hi,
> >
> > Am Montag, 15. Dezember 2025, 23:49:53 CET schrieb Frank Li:
> > > Use dev_err_probe() to simplify the code. Drop the explicit error message
> > > after returning from imx8mq_mipi_csi_parse_dt(), as the error is already
> > > reported by this helper.
> > >
> > > No functional change.
> > >
> > > Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> > > Signed-off-by: Frank Li <Frank.Li at nxp.com>
> > > ---
> > > change in v2:
> > > - add  Laurent Pinchart review tags
> > > - wrap error message to new line
> > > - remove error code print in dev_err_probe();
> > > - drop error messaage at imx8mq_mipi_csi_parse_dt()
> > > ---
> > >  drivers/media/platform/nxp/imx-mipi-csis.c    |  6 ++---
> > >  drivers/media/platform/nxp/imx7-media-csi.c   | 14 ++++--------
> > >  drivers/media/platform/nxp/imx8mq-mipi-csi2.c | 33 ++++++++++++---------------
> > >  3 files changed, 21 insertions(+), 32 deletions(-)
> > >
> > > diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c
> > > index 088b2945aee33731c565f049dd17721356300b84..ce93d868746f002c22e2f86b1e0aa84ec1a76061 100644
> > > --- a/drivers/media/platform/nxp/imx-mipi-csis.c
> > > +++ b/drivers/media/platform/nxp/imx-mipi-csis.c
> > > @@ -1547,10 +1547,8 @@ static int mipi_csis_probe(struct platform_device *pdev)
> > >  	/* Now that the hardware is initialized, request the interrupt. */
> > >  	ret = devm_request_irq(dev, irq, mipi_csis_irq_handler, 0,
> > >  			       dev_name(dev), csis);
> > > -	if (ret) {
> > > -		dev_err(dev, "Interrupt request failed\n");
> > > -		return ret;
> > > -	}
> > > +	if (ret)
> > > +		return dev_err_probe(dev, ret, "Interrupt request failed\n");
> > >
> > >  	/* Initialize and register the subdev. */
> > >  	ret = mipi_csis_subdev_init(csis);
> > > diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c
> > > index 933a5f39f9f4c9b43ca8d2a1819d0145981266e6..7ddc7ba06e3d4e007013821f67d783898a15461f 100644
> > > --- a/drivers/media/platform/nxp/imx7-media-csi.c
> > > +++ b/drivers/media/platform/nxp/imx7-media-csi.c
> > > @@ -2218,11 +2218,9 @@ static int imx7_csi_probe(struct platform_device *pdev)
> > >
> > >  	/* Acquire resources and install interrupt handler. */
> > >  	csi->mclk = devm_clk_get(&pdev->dev, "mclk");
> > > -	if (IS_ERR(csi->mclk)) {
> > > -		ret = PTR_ERR(csi->mclk);
> > > -		dev_err(dev, "Failed to get mclk: %d", ret);
> > > -		return ret;
> > > -	}
> > > +	if (IS_ERR(csi->mclk))
> > > +		return dev_err_probe(dev, PTR_ERR(csi->mclk),
> > > +				     "Failed to get mclk\n");
> > >
> > >  	csi->irq = platform_get_irq(pdev, 0);
> > >  	if (csi->irq < 0)
> > > @@ -2236,10 +2234,8 @@ static int imx7_csi_probe(struct platform_device *pdev)
> > >
> > >  	ret = devm_request_irq(dev, csi->irq, imx7_csi_irq_handler, 0, "csi",
> > >  			       (void *)csi);
> > > -	if (ret < 0) {
> > > -		dev_err(dev, "Request CSI IRQ failed.\n");
> > > -		return ret;
> > > -	}
> > > +	if (ret < 0)
> > > +		return dev_err_probe(dev, ret, "Request CSI IRQ failed.\n");
> > >
> > >  	/* Initialize all the media device infrastructure. */
> > >  	ret = imx7_csi_media_init(csi);
> > > diff --git a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
> > > index 0851f4a9ae52d3096f454da643cfdc5017e000b1..a007c582b4d91660a97910a6a0d53c9b6fcd73e9 100644
> > > --- a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
> > > +++ b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
> > > @@ -951,10 +951,9 @@ static int imx8mq_mipi_csi_parse_dt(struct csi_state *state)
> > >  	int ret = 0;
> > >
> > >  	state->rst = devm_reset_control_array_get_exclusive(dev);
> > > -	if (IS_ERR(state->rst)) {
> > > -		dev_err(dev, "Failed to get reset: %pe\n", state->rst);
> > > -		return PTR_ERR(state->rst);
> > > -	}
> > > +	if (IS_ERR(state->rst))
> > > +		return dev_err_probe(dev, PTR_ERR(state->rst),
> > > +				     "Failed to get reset\n");
> > >
> > >  	if (state->pdata->use_reg_csr) {
> > >  		const struct regmap_config regmap_config = {
> > > @@ -977,24 +976,22 @@ static int imx8mq_mipi_csi_parse_dt(struct csi_state *state)
> > >
> > >  	ret = of_property_read_u32_array(np, "fsl,mipi-phy-gpr", out_val,
> > >  					 ARRAY_SIZE(out_val));
> > > -	if (ret) {
> > > -		dev_err(dev, "no fsl,mipi-phy-gpr property found: %d\n", ret);
> > > -		return ret;
> > > -	}
> > > +	if (ret)
> > > +		return dev_err_probe(dev, ret, "no %s property found\n",
> > > +				    "fsl,mipi-phy-gpr");
> >
> > Do you really need to pass the (fixed) property name as an argument? Why
> > not move into the const string directly? I would also rephrase it a bit:
> > "property fsl,mipi-phy-gpr not found"
> 
> Laurent Pinchart provide comments at previous version. The same
> "fsl,mipi-phy-gpr" share one entry at RO region. slice save RO region
> space.
> 
> https://lore.kernel.org/imx/20251119043307.GH17526 at pendragon.ideasonboard.com/

"assuming it's worth it". Do you have any numbers? I doubt there is a
significant benefit, but I don't have strong opinion here.
But the grammar should still be improved.

Best regards
Alexander

> Frank
> 
> >
> > With that fixed:
> > Reviewed-by: Alexander Stein <alexander.stein at ew.tq-group.com>
> >
> > >
> > >  	ph = *out_val;
> > >
> > >  	node = of_find_node_by_phandle(ph);
> > > -	if (!node) {
> > > -		dev_err(dev, "Error finding node by phandle\n");
> > > -		return -ENODEV;
> > > -	}
> > > +	if (!node)
> > > +		return dev_err_probe(dev, -ENODEV,
> > > +				     "Error finding node by phandle\n");
> > > +
> > >  	state->phy_gpr = syscon_node_to_regmap(node);
> > >  	of_node_put(node);
> > > -	if (IS_ERR(state->phy_gpr)) {
> > > -		dev_err(dev, "failed to get gpr regmap: %pe\n", state->phy_gpr);
> > > -		return PTR_ERR(state->phy_gpr);
> > > -	}
> > > +	if (IS_ERR(state->phy_gpr))
> > > +		return dev_err_probe(dev, PTR_ERR(state->phy_gpr),
> > > +				     "failed to get gpr regmap\n");
> > >
> > >  	state->phy_gpr_reg = out_val[1];
> > >  	dev_dbg(dev, "phy gpr register set to 0x%x\n", state->phy_gpr_reg);
> > > @@ -1017,10 +1014,8 @@ static int imx8mq_mipi_csi_probe(struct platform_device *pdev)
> > >  	state->pdata = of_device_get_match_data(dev);
> > >
> > >  	ret = imx8mq_mipi_csi_parse_dt(state);
> > > -	if (ret < 0) {
> > > -		dev_err(dev, "Failed to parse device tree: %d\n", ret);
> > > +	if (ret < 0)
> > >  		return ret;
> > > -	}
> > >
> > >  	/* Acquire resources. */
> > >  	state->regs = devm_platform_ioremap_resource(pdev, 0);
> > >
> > >
> >
> >
> > --
> > TQ-Systems GmbH | M?hlstra?e 2, Gut Delling | 82229 Seefeld, Germany
> > Amtsgericht M?nchen, HRB 105018
> > Gesch?ftsf?hrer: Detlef Schneider, R?diger Stahl, Stefan Schneider
> > http://www.tq-group.com/
> 
> 
> 


-- 
TQ-Systems GmbH | M?hlstra?e 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht M?nchen, HRB 105018
Gesch?ftsf?hrer: Detlef Schneider, R?diger Stahl, Stefan Schneider
http://www.tq-group.com/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251216/b0ba7a9f/attachment.sig>

From vkoul at kernel.org  Tue Dec 16 07:01:54 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 16 Dec 2025 20:31:54 +0530
Subject: [PATCH v2 1/2] dmaengine: Add cleanup FREE defines for
 dma_async_tx_descriptor
In-Reply-To: <77ff15d7-cdb9-46f7-9f05-97aff2dc8ee9@intel.com>
References: <20251003-dma_chan_free-v2-0-564946b6c563@nxp.com>
 <20251003-dma_chan_free-v2-1-564946b6c563@nxp.com>
 <2c457a46-2b7f-4d66-8555-3b3cb52afe64@intel.com>
 <aTDkODHZg0JfrZJC@lizhi-Precision-Tower-5810>
 <77ff15d7-cdb9-46f7-9f05-97aff2dc8ee9@intel.com>
Message-ID: <aUF0Yu5Cexvm7JFe@vaman>

On 04-12-25, 08:07, Dave Jiang wrote:
> 
> 
> On 12/3/25 6:30 PM, Frank Li wrote:
> > On Wed, Dec 03, 2025 at 03:48:41PM -0700, Dave Jiang wrote:
> >>
> >>
> >> On 10/3/25 9:26 AM, Frank Li wrote:
> >>> Add cleanup FREE defines for dma_async_tx_descriptor to support automatic
> >>> cleanup and simplify error handling.
> >>>
> >>> Signed-off-by: Frank Li <Frank.Li at nxp.com>
> >>> ---
> >>> Check patch report exceed 100 chars, but it's still better put into one
> >>> line to keep consistent with other DEFINE_FREE and better readablity
> >>>
> >>> change in v2
> >>> - remove surpoiouse remove empty line
> >>> ---
> >>>  include/linux/dmaengine.h | 3 +++
> >>>  1 file changed, 3 insertions(+)
> >>>
> >>> diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
> >>> index 99efe2b9b4ea9844ca6161208362ef18ef111d96..27fa1646a807c49c781e1bce9e3e7d9a3c66f41d 100644
> >>> --- a/include/linux/dmaengine.h
> >>> +++ b/include/linux/dmaengine.h
> >>> @@ -5,6 +5,7 @@
> >>>  #ifndef LINUX_DMAENGINE_H
> >>>  #define LINUX_DMAENGINE_H
> >>>
> >>> +#include <linux/cleanup.h>
> >>>  #include <linux/device.h>
> >>>  #include <linux/err.h>
> >>>  #include <linux/uio.h>
> >>> @@ -1612,6 +1613,8 @@ static inline int dmaengine_desc_free(struct dma_async_tx_descriptor *desc)
> >>>  	return desc->desc_free(desc);
> >>>  }
> >>>
> >>> +DEFINE_FREE(dma_async_tx_descriptor, struct dma_async_tx_descriptor *, if (_T) dmaengine_desc_free(_T))
> >>
> >> maybe free_dma_async_tx may be clearer as the name vs dma_async_tx_descriptor.
> > 
> > If that, 'dmaengine_desc_free' is better because avoid create new name for
> > it.
> 
> That works too.

Agree, it is better name

-- 
~Vinod


From yeoreum.yun at arm.com  Tue Dec 16 07:03:07 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Tue, 16 Dec 2025 15:03:07 +0000
Subject: [PATCH v2] smc91x: fix broken irq-context in PREEMPT_RT
In-Reply-To: <aUBBE-W4kwQbsp9t@horms.kernel.org>
References: <20251212190338.2318843-1-yeoreum.yun@arm.com>
 <aUBBE-W4kwQbsp9t@horms.kernel.org>
Message-ID: <aUF0q6ERtXNbYPdw@e129823.arm.com>

Hi Simon,

> On Fri, Dec 12, 2025 at 07:03:38PM +0000, Yeoreum Yun wrote:
> > When smc91x.c is built with PREEMPT_RT, the following splat occurs
> > in FVP_RevC:
> >
> > [   13.055000] smc91x LNRO0003:00 eth0: link up, 10Mbps, half-duplex, lpa 0x0000
> > [   13.062137] BUG: workqueue leaked atomic, lock or RCU: kworker/2:1[106]
> > [   13.062137]      preempt=0x00000000 lock=0->0 RCU=0->1 workfn=mld_ifc_work
> > [   13.062266] C
> > ** replaying previous printk message **
> > [   13.062266] CPU: 2 UID: 0 PID: 106 Comm: kworker/2:1 Not tainted 6.18.0-dirty #179 PREEMPT_{RT,(full)}
> > [   13.062353] Hardware name:  , BIOS
> > [   13.062382] Workqueue: mld mld_ifc_work
> > [   13.062469] Call trace:
> > [   13.062494]  show_stack+0x24/0x40 (C)
> > [   13.062602]  __dump_stack+0x28/0x48
> > [   13.062710]  dump_stack_lvl+0x7c/0xb0
> > [   13.062818]  dump_stack+0x18/0x34
> > [   13.062926]  process_scheduled_works+0x294/0x450
> > [   13.063043]  worker_thread+0x260/0x3d8
> > [   13.063124]  kthread+0x1c4/0x228
> > [   13.063235]  ret_from_fork+0x10/0x20
> >
> > This happens because smc_special_trylock() disables IRQs even on PREEMPT_RT,
> > but smc_special_unlock() does not restore IRQs on PREEMPT_RT.
> > The reason is that smc_special_unlock() calls spin_unlock_irqrestore(),
> > and rcu_read_unlock_bh() in __dev_queue_xmit() cannot invoke
> > rcu_read_unlock() through __local_bh_enable_ip() when current->softirq_disable_cnt becomes zero.
> >
> > To address this issue, replace smc_special_trylock() with spin_trylock_irqsave().
> >
> > Fixes: 8ff499e43c53 ("smc91x: let smc91x work well under netpoll")
> > Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
> > ---
> > This patch based on v6.18.
> >
> > History
> > ========
> >
> > >From v1 to v2:
> >   - remove debug log.
> >   - https://lore.kernel.org/all/20251212185818.2209573-1-yeoreum.yun at arm.com/
> >
>
> Firstly, I'd like to note that it seems to me that the last
> non-trivial update to this driver seems to have occurred back in 2016.
> Do you know if it is still actively used?

Unfortunately, I don't know whether it is still actively used in real.
AFAIK it could be used in qemu or arm FVP...

>
> I agree that this patch seems appropriate as a bug fix.
> But I do wonder if, as a follow-up for net-next when it re-opens,
> smc_special_*lock could be removed entirely.
> Other than being the source of this bug (which I guess is special),
> they don't seem very special anymore. Perhaps they were once,
> but that time seems to have passed.

IIUC, remove smc_special*_lock() and replace them with "spin_*lock_*" right?
If so, It seems good.
Even UP case, I think it seems better to protect
critical section in smc_hardware_send_pkt() and smc_hard_start_xmit()
with spin_lock_irqsave() from interrupt handler.
>
> Regarding the Fixes tag. I wonder if this one, which post-dates the
> currently cited commit is correct. It seems to be when RT variants of
> these locks was introduced.
>
> Fixes: 342a93247e08 ("locking/spinlock: Provide RT variant header: <linux/spinlock_rt.h>")

Yes that's would be better.

>
> Lastly, for reference, when posting fixes for Networking code, please:
>
> * Target the patches at net like this:
>
>   [PATCH net] ...

Thanks to let me know for this.

>
> * Allow at least 24h to pass before posting updated patch versions
>
> More can be found here: https://docs.kernel.org/process/maintainer-netdev.html
>
>
> Reviewed-by: Simon Horman <horms at kernel.org>

Thanks for review :).
In next patch, I'll reformat the title,
change the fix tag and includes your R-b tag.

--
Sincerely,
Yeoreum Yun


From sensor1010 at 163.com  Tue Dec 16 07:06:11 2025
From: sensor1010 at 163.com (Lizhe)
Date: Tue, 16 Dec 2025 07:06:11 -0800
Subject: [PATCH 1/2] [PATCH net-next v2 1/2] net: stmmac: dwmac-rk: rename phy_power_on to avoid conflict
Message-ID: <20251216150611.3616-1-sensor1010@163.com>

Rename local function 'phy_power_on' to 'rk_phy_power_set' to avoid
conflict with PHY subsystem function. Keep original error handling.

Signed-off-by: Lizhe <sensor1010 at 163.com>
---
 drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
index 0a95f54e725e..2f5a65c235aa 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -1498,7 +1498,7 @@ static int gmac_clk_enable(struct rk_priv_data *bsp_priv, bool enable)
 	return 0;
 }
 
-static int phy_power_on(struct rk_priv_data *bsp_priv, bool enable)
+static int rk_phy_power_set(struct rk_priv_data *bsp_priv, bool enable)
 {
 	struct regulator *ldo = bsp_priv->regulator;
 	struct device *dev = bsp_priv->dev;
@@ -1692,7 +1692,7 @@ static int rk_gmac_powerup(struct rk_priv_data *bsp_priv)
 		dev_err(dev, "NO interface defined!\n");
 	}
 
-	ret = phy_power_on(bsp_priv, true);
+	ret = rk_phy_power_set(bsp_priv, true);
 	if (ret) {
 		gmac_clk_enable(bsp_priv, false);
 		return ret;
@@ -1713,7 +1713,7 @@ static void rk_gmac_powerdown(struct rk_priv_data *gmac)
 
 	pm_runtime_put_sync(gmac->dev);
 
-	phy_power_on(gmac, false);
+	rk_phy_power_set(gmac, false);
 	gmac_clk_enable(gmac, false);
 }
 
-- 
2.17.1



From sensor1010 at 163.com  Tue Dec 16 07:07:15 2025
From: sensor1010 at 163.com (Lizhe)
Date: Tue, 16 Dec 2025 07:07:15 -0800
Subject: [PATCH 2/2] [PATCH net-next v2 2/2] net: stmmac: dwmac-rk:return actual error from phy_power_on
Message-ID: <20251216150715.3672-1-sensor1010@163.com>

The function phy_power_on currently always returns 0, even when
regulator operations fail. This patch modifies it to return the
actual error code from regulator_enable/disable operations

Signed-off-by: Lizhe <sensor1010 at 163.com>
---
 drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
index 2f5a65c235aa..fa989cb96714 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -1514,7 +1514,7 @@ static int rk_phy_power_set(struct rk_priv_data *bsp_priv, bool enable)
 			dev_err(dev, "fail to disable phy-supply\n");
 	}
 
-	return 0;
+	return ret;
 }
 
 static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,
-- 
2.17.1



From maz at kernel.org  Tue Dec 16 07:09:30 2025
From: maz at kernel.org (Marc Zyngier)
Date: Tue, 16 Dec 2025 15:09:30 +0000
Subject: [PATCH 11/32] KVM: arm64: gic-v5: Trap and emulate ICH_PPI_HMRx_EL1 accesses
In-Reply-To: <0f686dc9ea9e32fc37a1b11eb95b32cb958ff0a8.camel@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	<20251212152215.675767-12-sascha.bischoff@arm.com>
	<86a4ziogjc.wl-maz@kernel.org>
	<0f686dc9ea9e32fc37a1b11eb95b32cb958ff0a8.camel@arm.com>
Message-ID: <868qf2o445.wl-maz@kernel.org>

On Tue, 16 Dec 2025 11:54:59 +0000,
Sascha Bischoff <Sascha.Bischoff at arm.com> wrote:
> 
> On Tue, 2025-12-16 at 10:41 +0000, Marc Zyngier wrote:
> > On Fri, 12 Dec 2025 15:22:39 +0000,
> > Sascha Bischoff <Sascha.Bischoff at arm.com> wrote:
> > > 
> > > The ICC_PPI_HMRx_EL1 register is used to determine which PPIs use
> > > Level-sensitive semantics, and which use Edge. For a GICv5 guest,
> > > the
> > > correct view of the virtual PPIs must be provided to the guest.
> > 
> > s/ICH/ICC/ in $SUBJECT
> > 
> > > 
> > > The GICv5 architecture doesn't provide an ICV_PPI_HMRx_EL1 or
> > 
> > The spec disagree with you here (see 9.5.4).
> > 
> > > ICH_PPI_HMRx_EL2 register, and therefore all guest accesses must be
> > > trapped to avoid the guest directly accessing the host's
> > > ICC_PPI_HMRx_EL1 state. This change hence configures the FGTs to
> > > always trap and emulate guest accesses to the HMR running a
> > > GICv5-based guest.
> > 
> > The real question is what we gain by emulating this register, given
> > that virtual PPIs are only guaranteed to exist if the physical
> > version
> > exist. If they exist, then the handling mode is defined by the
> > that HW, and we can't deviate from it.
> > 
> > Given that, I can't really see the point in trapping something that
> > is
> > bound to be the same thing as the host, unless this comes with
> > additional restrictions, for example a mask of interrupts that are
> > actually exposed to the guest.
> > 
> > Or am I missing something?
> 
> No, I think you're quite correct, and this doesn't add meaningful
> value.
> 
> This all stems from my misunderstanding that GICv5 vPPIs are
> independent from the physical PPIs. This is not the case, however, as
> the set of implemented virtual PPIs matches the physically implemented
> PPIs. The handling mode for each PPI will be reflected in the
> ICC/ICV_PPI_HMRx_EL1 sysregs.
> 
> This actually has wider impacts:
> 
>    1. It makes sense to drop this commit altogether.
>    
>    2. When initialising the GICv5 PPIs ("KVM: arm64: gic-v5: Init
>    Private IRQs (PPIs) for GICv5"), we skip setting their config
>    (LEVEL/EDGE).
>    
>    3. In vgic_v5_reset ("KVM: arm64: gic-v5: Reset vcpu state"), sync
>    the host's PPI HMR state (ICC_PPI_HMRx_EL1) to KVM's vPPI shadow
>    state as the virtual PPIs should match that, and we need that to
>    correctly handle SW-driven PPI injection. Currently, this code
>    actually calculates the HMR contents for trapping and emulating,
>    which again can be dropped altogether.
>    
>    4. vgic_hmr can be dropped from the vgic_v5 CPUIF too.
> 
> Does this sound reasonable to you?

It does, to some extent. The one thing I have been thinking about is
how to hide PPIs that are implemented by the host, but not exposed to
the guest.

For that, I think we need a mask of PPIs that the kernel deals with
(timers, PMU, SPE one day), and use it to sanitise the HMR. For that,
we still need to trap these registers.

But it then begs the question: what does it mean for userspace
injection of PPIs? Do we still allow it? How does userspace discover
the implemented PPIs? How does userspace tells us *in advance* about
that so that we can affect the above mask?

At this stage, I'm tempted to say "screw that, userspace doesn't get
to touch PPIs -- at least not for now".

Thoughts?

	M.

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


From Frank.li at nxp.com  Tue Dec 16 07:10:01 2025
From: Frank.li at nxp.com (Frank Li)
Date: Tue, 16 Dec 2025 10:10:01 -0500
Subject: [PATCH 0/8] dmaengine: Add new API to combine onfiguration and
 descriptor preparation
In-Reply-To: <aUFUX0e_h7RGAecz@vaman>
References: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
 <aUFUX0e_h7RGAecz@vaman>
Message-ID: <aUF2SX/6bV2lHtF0@lizhi-Precision-Tower-5810>

On Tue, Dec 16, 2025 at 06:15:19PM +0530, Vinod Koul wrote:
> On 08-12-25, 12:09, Frank Li wrote:
>
> Spell check on subject please :-)
>
> > Previously, configuration and preparation required two separate calls. This
> > works well when configuration is done only once during initialization.
> >
> > However, in cases where the burst length or source/destination address must
> > be adjusted for each transfer, calling two functions is verbose.
> >
> > 	if (dmaengine_slave_config(chan, &sconf)) {
> > 		dev_err(dev, "DMA slave config fail\n");
> > 		return -EIO;
> > 	}
> >
> > 	tx = dmaengine_prep_slave_single(chan, dma_local, len, dir, flags);
> >
> > After new API added
> >
> > 	tx = dmaengine_prep_slave_single(chan, dma_local, len, dir, flags, &sconf);
>
> Nak, we cant change the API like this.

Sorry, it is typo here. in patch
	dmaengine_prep_slave_single_config(chan, dma_local, len, dir, flags, &sconf);

> I agree that you can add a new way to call dmaengine_slave_config() and
> dmaengine_prep_slave_single() together.
> maybe dmaengine_prep_config_perip_single() (yes we can go away with slave, but
> cant drop it, as absence means something else entire).

how about dmaengine_prep_peripheral_single() and dmaengine_prep_peripheral_sg()
to align recent added "dmaengine_prep_peripheral_dma_vec()"

I think "peripheral" also is reduntant. dmaengine_prep_single() and
dmaengine_prep_sg() should be enough because
- dmaengine_prep_dma_cyclic() is actually work with prepiperial FIFO
- some prepierial FIFO work like memory, by use shared memory method, like
PCIe map windows.
- argument: config and dir already passdown information to indicate if it
is device preiperial. So needn't indicate at function name.
- maybe later extend to support mem to mem by config becuase adjust burst
size for difference alignment or difference bus fabric port to optimaze
performance.

Frank

>
> I would like to retain the dmaengine_prep_slave_single() as an API for
> users to call and invoke. There are users who configure channel once as
> well
>
> >
> > Additional, prevous two calls requires additional locking to ensure both
> > steps complete atomically.
> >
> >     mutex_lock()
> >     dmaengine_slave_config()
> >     dmaengine_prep_slave_single()
> >     mutex_unlock()
> >
> > after new API added, mutex lock can be moved. See patch
> >      nvmet: pci-epf: Use dmaengine_prep_slave_single_config() API
> >
> > Signed-off-by: Frank Li <Frank.Li at nxp.com>
> > ---
> > Frank Li (8):
> >       dmaengine: Add API to combine configuration and preparation (sg and single)
> >       PCI: endpoint: pci-epf-test: use new DMA API to simple code
> >       dmaengine: dw-edma: Use new .device_prep_slave_sg_config() callback
> >       dmaengine: dw-edma: Pass dma_slave_config to dw_edma_device_transfer()
> >       nvmet: pci-epf: Remove unnecessary dmaengine_terminate_sync() on each DMA transfer
> >       nvmet: pci-epf: Use dmaengine_prep_slave_single_config() API
> >       PCI: epf-mhi:Using new API dmaengine_prep_slave_single_config() to simple code.
> >       crypto: atmel: Use dmaengine_prep_slave_single_config() API
> >
> >  drivers/crypto/atmel-aes.c                    | 10 ++---
> >  drivers/dma/dw-edma/dw-edma-core.c            | 38 +++++++++++-----
> >  drivers/nvme/target/pci-epf.c                 | 21 +++------
> >  drivers/pci/endpoint/functions/pci-epf-mhi.c  | 52 +++++++---------------
> >  drivers/pci/endpoint/functions/pci-epf-test.c |  8 +---
> >  include/linux/dmaengine.h                     | 64 ++++++++++++++++++++++++---
> >  6 files changed, 111 insertions(+), 82 deletions(-)
> > ---
> > base-commit: bc04acf4aeca588496124a6cf54bfce3db327039
> > change-id: 20251204-dma_prep_config-654170d245a2
> >
> > Best regards,
> > --
> > Frank Li <Frank.Li at nxp.com>
>
> --
> ~Vinod


From ryan.roberts at arm.com  Tue Dec 16 07:11:13 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Tue, 16 Dec 2025 15:11:13 +0000
Subject: [PATCH 0/2] introduce pagetable_alloc_nolock()
In-Reply-To: <20251212161832.2067134-1-yeoreum.yun@arm.com>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com>
Message-ID: <916c17ba-22b1-456e-a184-cb3f60249af7@arm.com>

On 12/12/2025 16:18, Yeoreum Yun wrote:
> Some architectures invoke pagetable_alloc() or __get_free_pages()
> with preemption disabled.
> For example, in arm64, linear_map_split_to_ptes() calls pagetable_alloc()
> while spliting block entry to ptes and __kpti_install_ng_mappings()
> calls __get_free_pages() to create kpti pagetable.
> 
> Under PREEMPT_RT, calling pagetable_alloc() with
> preemption disabled is not allowed, because it may acquire
> a spin lock that becomes sleepable on RT, potentially
> causing a sleep during page allocation.
> 
> Since above two functions is called as callback of stop_machine()
> where its callback is called in preemption disabled,
> They could make a potential problem. (sleeping in preemption disabled).
> 
> To address this, introduce pagetable_alloc_nolock() API.

I don't really understand what the problem is that you're trying to fix. As I
see it, there are 2 call sites in arm64 arch code that are calling into the page
allocator from stop_machine() - one via via pagetable_alloc() and another via
__get_free_pages(). But both of those calls are passing in GFP_ATOMIC. It was my
understanding that the page allocator would ensure it never sleeps when
GFP_ATOMIC is passed in, (even for PREEMPT_RT)?

What is the actual symptom you are seeing?

If the page allocator is somehow ignoring the GFP_ATOMIC request for PREEMPT_RT,
then isn't that a bug in the page allocator? I'm not sure why you would change
the callsites? Can't you just change the page allocator based on GFP_ATOMIC?

Thanks,
Ryan

> 
> Yeoreum Yun (2):
>   mm: introduce pagetable_alloc_nolock()
>   arm64: mmu: use pagetable_alloc_nolock() while stop_machine()
> 
>  arch/arm64/mm/mmu.c  | 23 ++++++++++++++++++-----
>  include/linux/mm.h   | 18 ++++++++++++++++++
>  kernel/bpf/stream.c  |  2 +-
>  kernel/bpf/syscall.c |  2 +-
>  mm/page_alloc.c      | 10 +++-------
>  5 files changed, 41 insertions(+), 14 deletions(-)
> 
> --
> LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
> 



From pmladek at suse.com  Tue Dec 16 07:12:52 2025
From: pmladek at suse.com (Petr Mladek)
Date: Tue, 16 Dec 2025 16:12:52 +0100
Subject: [PATCH 21/26] printk: Register information into meminspect
In-Reply-To: <20251119154427.1033475-22-eugen.hristev@linaro.org>
References: <20251119154427.1033475-1-eugen.hristev@linaro.org>
 <20251119154427.1033475-22-eugen.hristev@linaro.org>
Message-ID: <aUF29MLUj3YRh4v_@pathway.suse.cz>

On Wed 2025-11-19 17:44:22, Eugen Hristev wrote:
> Annotate vital static information into meminspect:
>  - prb_descs
>  - prb_infos
>  - prb
>  - prb_data
>  - printk_rb_static
>  - printk_rb_dynamic
> 
> Information on these variables is stored into inspection table.
> 
> Register dynamic information into meminspect:
>  - new_descs
>  - new_infos
>  - new_log_buf
> This information is being allocated as a memblock, so call
> memblock_mark_inspect to mark the block accordingly.
> 
> Signed-off-by: Eugen Hristev <eugen.hristev at linaro.org>

I haven't tested this. But it looks reasonable from my POV.
I assume that the output from the "log" command was from your
synthetic test so that "crash" was even able to print the messages.

Feel free to use:

Reviewed-by: Petr Mladek <pmladek at suse.com>

Best Regards,
Petr

PS: I haven't attended Plumbers conference this year so
    I do not know what is the current state of this project.
    


From vkoul at kernel.org  Tue Dec 16 07:18:17 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 16 Dec 2025 20:48:17 +0530
Subject: [PATCH RESEND] dmaengine: at_xdmac: get the number of DMA
 channels from device tree
In-Reply-To: <20251203121208.1269487-1-robert.marko@sartura.hr>
References: <20251203121208.1269487-1-robert.marko@sartura.hr>
Message-ID: <aUF4OS4DsmRlQQt3@vaman>

On 03-12-25, 13:11, Robert Marko wrote:
> From: Tony Han <tony.han at microchip.com>
> 
> In case of kernel runs in non-secure mode, the number of DMA channels can
> be got from device tree since the value read from GTYPE register is "0" as
> it's always secured.
> 
> As the number of channels can never be negative, update them to the type
> "unsigned".
> 
> This is required for LAN969x.

You updated the changelog, but tagged it as resend. It should be v2!

> 
> Signed-off-by: Tony Han <tony.han at microchip.com>
> Signed-off-by: Robert Marko <robert.marko at sartura.hr>
> ---
>  drivers/dma/at_xdmac.c | 26 +++++++++++++++++++++++---
>  1 file changed, 23 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
> index 3fbc74710a13..acabf82e293c 100644
> --- a/drivers/dma/at_xdmac.c
> +++ b/drivers/dma/at_xdmac.c
> @@ -2257,12 +2257,29 @@ static int __maybe_unused atmel_xdmac_runtime_resume(struct device *dev)
>  	return clk_enable(atxdmac->clk);
>  }
>  
> +static inline int at_xdmac_get_channel_number(struct platform_device *pdev,
> +					      u32 reg, u32 *pchannels)
> +{
> +	int	ret;
> +
> +	if (reg) {
> +		*pchannels = AT_XDMAC_NB_CH(reg);
> +		return 0;
> +	}
> +
> +	ret = of_property_read_u32(pdev->dev.of_node, "dma-channels", pchannels);
> +	if (ret)
> +		dev_err(&pdev->dev, "can't get number of channels\n");

Do we need to log error, I thought the API did that...

> +
> +	return ret;
> +}
> +
>  static int at_xdmac_probe(struct platform_device *pdev)
>  {
>  	struct at_xdmac	*atxdmac;
> -	int		irq, nr_channels, i, ret;
> +	int		irq, ret;
>  	void __iomem	*base;
> -	u32		reg;
> +	u32		nr_channels, i, reg;
>  
>  	irq = platform_get_irq(pdev, 0);
>  	if (irq < 0)
> @@ -2278,7 +2295,10 @@ static int at_xdmac_probe(struct platform_device *pdev)
>  	 * of channels to do the allocation.
>  	 */
>  	reg = readl_relaxed(base + AT_XDMAC_GTYPE);
> -	nr_channels = AT_XDMAC_NB_CH(reg);
> +	ret = at_xdmac_get_channel_number(pdev, reg, &nr_channels);
> +	if (ret)
> +		return ret;
> +
>  	if (nr_channels > AT_XDMAC_MAX_CHAN) {
>  		dev_err(&pdev->dev, "invalid number of channels (%u)\n",
>  			nr_channels);
> -- 
> 2.52.0

-- 
~Vinod


From mark.rutland at arm.com  Tue Dec 16 07:21:38 2025
From: mark.rutland at arm.com (Mark Rutland)
Date: Tue, 16 Dec 2025 15:21:38 +0000
Subject: [PATCH v2] ARM: entry: expand comment in __switch_to
In-Reply-To: <20251216-comments-in-switch-to-v2-1-190d8741db14@kernel.org>
References: <20251216-comments-in-switch-to-v2-1-190d8741db14@kernel.org>
Message-ID: <aUF5AofX5plUo9pq@J2N7QTR9R3>

Hi Linus,

On Tue, Dec 16, 2025 at 03:27:37PM +0100, Linus Walleij wrote:
> From: Linus Walleij <linus.walleij at linaro.org>
> 
> As per discussion between the developers in the mail thread
> linked, expand the comment in __switch_to so that readers
> of the code understand what is going on.
> 
> Link: https://lore.kernel.org/linux-arm-kernel/ZxDh9biUbf9W8gNN at J2N7QTR9R3/
> Suggested-by: Mark Rutland <mark.rutland at arm.com>
> Signed-off-by: Linus Walleij <linus.walleij at linaro.org>

This looks fine to me, with two minor nits noted below. With those
fixed, feel free to add:

  Acked-by: Mark Rutland <mark.rutland at arm.com>

... and I'd recommend dropping this into the patch system.

> ---
> Changes in v2:
> - Rebased on v6.19-rc1
> - Link to v1: https://lore.kernel.org/r/20241028-comments-in-switch-to-v1-0-7280d09671a8 at linaro.org
> ---
>  arch/arm/kernel/entry-armv.S | 13 ++++++++++---
>  1 file changed, 10 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
> index ef6a657c8d13..5c016c68b5a3 100644
> --- a/arch/arm/kernel/entry-armv.S
> +++ b/arch/arm/kernel/entry-armv.S
> @@ -557,9 +557,16 @@ ENTRY(__switch_to)
>  	ldmia	r4, {r4 - sl, fp, ip, lr}	@ Load all regs saved previously
>  #ifdef CONFIG_VMAP_STACK
>  	@
> -	@ Do a dummy read from the new stack while running from the old one so
> -	@ that we can rely on do_translation_fault() to fix up any stale PMD
> -	@ entries covering the vmalloc region.
> +	@ For a non-lazy mm switch, check_vmalloc_seq() has ensured that
> +	@ that the active mm's page tables have mappings for the prev
> +	@ task's stack and the next task's stack.
> +	@
> +	@ For a lazy mm switch the active mm's page tables have mappings
> +	@ for the prev task's stack but might not have mappings for the
> +	@ new taks stack. Do a dummy read from the new stack while

Typo: s/task/task's/

> +	@ running from the old stack so that we can rely on
> +	@ do_translation_fault() to fix up any stale PMD entries
> +	@ covering the vmalloc region.

Ard requested in:

  https://lore.kernel.org/linux-arm-kernel/CAMj1kXFn=pfJqTrMrnqT+OLi3UqAq0PieROQhbC2M3B2uAzyEQ at mail.gmail.com/

That we change this last part from:

  to fix up any stale PMD entries covering the vmalloc region.

... to:

  to populate missing PMD entries covering the new task's stack in the
  old task's page tables.

... and I think that'd be worthwhile.

Mark.

>  	@
>  	ldr	r2, [ip]
>  #ifdef CONFIG_KASAN_VMALLOC
> 
> ---
> base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
> change-id: 20241028-comments-in-switch-to-0e24480e8495
> 
> Best regards,
> -- 
> Linus Walleij <linusw at kernel.org>
> 


From jakub.turek at elsta.tech  Tue Dec 16 07:26:41 2025
From: jakub.turek at elsta.tech (j.turek)
Date: Tue, 16 Dec 2025 16:26:41 +0100
Subject: [PATCH] serial: xilinx_uartps: fix rs485 initialization at boot
Message-ID: <20251216152641.196221-1-jakub.turek@elsta.tech>

When 'linux,rs485-enabled-at-boot-time;' property is enabled in device-tree
and there is no rts-gpio defined there is NULL pointer dereference in
function 'cdns_rts_gpio_enable' because 'cdns_uart->port->membase' pointer
is not set at this point

Signed-off-by: Jakub Turek <jakub.turek at elsta.tech>

Fixes: fccc9d9233f9 ("tty: serial: uartps: Add rs485 support to uartps driver")
---
 drivers/tty/serial/xilinx_uartps.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index c793fc74c26b..1e4d54fd5762 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -1816,8 +1816,6 @@ static int cdns_uart_probe(struct platform_device *pdev)
 		console_port = port;
 	}
 #endif
-	if (cdns_uart_data->port->rs485.flags & SER_RS485_ENABLED)
-		cdns_rs485_rx_setup(cdns_uart_data);
 
 	rc = uart_add_one_port(&cdns_uart_uart_driver, port);
 	if (rc) {
@@ -1826,6 +1824,9 @@ static int cdns_uart_probe(struct platform_device *pdev)
 		goto err_out_pm_disable;
 	}
 
+	if (cdns_uart_data->port->rs485.flags & SER_RS485_ENABLED)
+		cdns_rs485_rx_setup(cdns_uart_data);
+
 #ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
 	/* This is not port which is used for console that's why clean it up */
 	if (console_port == port &&
-- 
2.34.1



From lkp at intel.com  Tue Dec 16 07:27:24 2025
From: lkp at intel.com (kernel test robot)
Date: Tue, 16 Dec 2025 23:27:24 +0800
Subject: [PATCH v10 5/7] media: verisilicon: AV1: Restore IOMMU context
 before decoding a frame
In-Reply-To: <20251215085349.10155-6-benjamin.gaignard@collabora.com>
References: <20251215085349.10155-6-benjamin.gaignard@collabora.com>
Message-ID: <202512162315.lcRwm6Mr-lkp@intel.com>

Hi Benjamin,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on v6.19-rc1 next-20251216]
[cannot apply to robh/for-next rockchip/for-next arm64/for-next/core]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Benjamin-Gaignard/dt-bindings-vendor-prefixes-Add-Verisilicon/20251215-165740
base:   linus/master
patch link:    https://lore.kernel.org/r/20251215085349.10155-6-benjamin.gaignard%40collabora.com
patch subject: [PATCH v10 5/7] media: verisilicon: AV1: Restore IOMMU context before decoding a frame
config: arm-randconfig-r063-20251216 (https://download.01.org/0day-ci/archive/20251216/202512162315.lcRwm6Mr-lkp at intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 1335a05ab8bc8339ce24be3a9da89d8c3f4e0571)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251216/202512162315.lcRwm6Mr-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512162315.lcRwm6Mr-lkp at intel.com/

All errors (new ones prefixed by >>):

>> drivers/iommu/vsi-iommu.c:231:3: error: call to undeclared function 'report_iommu_fault'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     231 |                 report_iommu_fault(iommu->domain, iommu->dev, iova, status);
         |                 ^
>> drivers/iommu/vsi-iommu.c:245:21: error: no member named 'iommu_fwnode' in 'struct iommu_fwspec'
     245 |                                                              fwspec->iommu_fwnode);
         |                                                              ~~~~~~  ^
>> drivers/iommu/vsi-iommu.c:254:28: error: call to undeclared function 'dev_iommu_priv_get'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     254 |         struct vsi_iommu *iommu = dev_iommu_priv_get(dev);
         |                                   ^
   drivers/iommu/vsi-iommu.c:254:28: note: did you mean 'dev_iommu_fwspec_get'?
   include/linux/iommu.h:1457:36: note: 'dev_iommu_fwspec_get' declared here
    1457 | static inline struct iommu_fwspec *dev_iommu_fwspec_get(struct device *dev)
         |                                    ^
>> drivers/iommu/vsi-iommu.c:254:20: error: incompatible integer to pointer conversion initializing 'struct vsi_iommu *' with an expression of type 'int' [-Wint-conversion]
     254 |         struct vsi_iommu *iommu = dev_iommu_priv_get(dev);
         |                           ^       ~~~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/vsi-iommu.c:496:28: error: call to undeclared function 'dev_iommu_priv_get'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     496 |         struct vsi_iommu *iommu = dev_iommu_priv_get(dev);
         |                                   ^
   drivers/iommu/vsi-iommu.c:496:20: error: incompatible integer to pointer conversion initializing 'struct vsi_iommu *' with an expression of type 'int' [-Wint-conversion]
     496 |         struct vsi_iommu *iommu = dev_iommu_priv_get(dev);
         |                           ^       ~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/iommu/vsi-iommu.c:519:38: error: variable has incomplete type 'const struct iommu_domain_ops'
     519 | static const struct iommu_domain_ops vsi_identity_ops = {
         |                                      ^
   include/linux/iommu.h:40:8: note: forward declaration of 'struct iommu_domain_ops'
      40 | struct iommu_domain_ops;
         |        ^
   drivers/iommu/vsi-iommu.c:571:28: error: call to undeclared function 'dev_iommu_priv_get'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     571 |         struct vsi_iommu *iommu = dev_iommu_priv_get(dev);
         |                                   ^
   drivers/iommu/vsi-iommu.c:571:20: error: incompatible integer to pointer conversion initializing 'struct vsi_iommu *' with an expression of type 'int' [-Wint-conversion]
     571 |         struct vsi_iommu *iommu = dev_iommu_priv_get(dev);
         |                           ^       ~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/iommu/vsi-iommu.c:644:2: error: call to undeclared function 'dev_iommu_priv_set'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     644 |         dev_iommu_priv_set(dev, iommu);
         |         ^
   drivers/iommu/vsi-iommu.c:650:28: error: call to undeclared function 'dev_iommu_priv_get'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     650 |         struct vsi_iommu *iommu = dev_iommu_priv_get(dev);
         |                                   ^
   drivers/iommu/vsi-iommu.c:650:20: error: incompatible integer to pointer conversion initializing 'struct vsi_iommu *' with an expression of type 'int' [-Wint-conversion]
     650 |         struct vsi_iommu *iommu = dev_iommu_priv_get(dev);
         |                           ^       ~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/iommu/vsi-iommu.c:657:35: error: passing 'const uint32_t[16]' (aka 'const unsigned int[16]') to parameter of type 'u32 *' (aka 'unsigned int *') discards qualifiers [-Werror,-Wincompatible-pointer-types-discards-qualifiers]
     657 |         return iommu_fwspec_add_ids(dev, args->args, 1);
         |                                          ^~~~~~~~~~
   include/linux/iommu.h:1451:65: note: passing argument to parameter 'ids' here
    1451 | static inline int iommu_fwspec_add_ids(struct device *dev, u32 *ids,
         |                                                                 ^
>> drivers/iommu/vsi-iommu.c:667:18: error: use of undeclared identifier 'generic_single_device_group'
     667 |         .device_group = generic_single_device_group,
         |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/iommu/vsi-iommu.c:669:25: error: variable has incomplete type 'const struct iommu_domain_ops'
     669 |         .default_domain_ops = &(const struct iommu_domain_ops) {
         |                                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     670 |                 .attach_dev             = vsi_iommu_attach_device,
         |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     671 |                 .map_pages              = vsi_iommu_map,
         |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     672 |                 .unmap_pages            = vsi_iommu_unmap,
         |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     673 |                 .flush_iotlb_all        = vsi_iommu_flush_tlb_all,
         |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     674 |                 .iova_to_phys           = vsi_iommu_iova_to_phys,
         |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     675 |                 .free                   = vsi_iommu_domain_free,
         |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     676 |         }
         |         ~
   include/linux/iommu.h:40:8: note: forward declaration of 'struct iommu_domain_ops'
      40 | struct iommu_domain_ops;
         |        ^
   15 errors generated.

Kconfig warnings: (for reference only)
   WARNING: unmet direct dependencies detected for VSI_IOMMU
   Depends on [n]: IOMMU_SUPPORT [=n] && (ARCH_ROCKCHIP [=n] && ARM64 || COMPILE_TEST [=y])
   Selected by [m]:
   - VIDEO_HANTRO_ROCKCHIP [=y] && MEDIA_SUPPORT [=y] && MEDIA_PLATFORM_SUPPORT [=y] && MEDIA_PLATFORM_DRIVERS [=y] && VIDEO_HANTRO [=m] && (ARCH_ROCKCHIP [=n] || COMPILE_TEST [=y])


vim +/report_iommu_fault +231 drivers/iommu/vsi-iommu.c

b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  214  
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  215  static irqreturn_t vsi_iommu_irq(int irq, void *dev_id)
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  216  {
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  217  	struct vsi_iommu *iommu = dev_id;
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  218  	unsigned long flags;
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  219  	dma_addr_t iova;
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  220  	u32 status;
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  221  
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  222  	if (pm_runtime_resume_and_get(iommu->dev) < 0)
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  223  		return IRQ_NONE;
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  224  
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  225  	spin_lock_irqsave(&iommu->lock, flags);
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  226  
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  227  	status = readl(iommu->regs + VSI_MMU_STATUS_BASE);
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  228  	if (status & VSI_MMU_IRQ_MASK) {
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  229  		dev_err(iommu->dev, "unexpected int_status=%08x\n", status);
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  230  		iova = readl(iommu->regs + VSI_MMU_PAGE_FAULT_ADDR);
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15 @231  		report_iommu_fault(iommu->domain, iommu->dev, iova, status);
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  232  	}
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  233  	writel(0, iommu->regs + VSI_MMU_STATUS_BASE);
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  234  
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  235  	spin_unlock_irqrestore(&iommu->lock, flags);
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  236  	pm_runtime_put_autosuspend(iommu->dev);
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  237  
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  238  	return IRQ_HANDLED;
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  239  }
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  240  
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  241  static struct vsi_iommu *vsi_iommu_get_from_dev(struct device *dev)
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  242  {
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  243  	struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  244  	struct device *iommu_dev = bus_find_device_by_fwnode(&platform_bus_type,
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15 @245  							     fwspec->iommu_fwnode);
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  246  
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  247  	put_device(iommu_dev);
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  248  
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  249  	return iommu_dev ? dev_get_drvdata(iommu_dev) : NULL;
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  250  }
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  251  
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  252  static struct iommu_domain *vsi_iommu_domain_alloc_paging(struct device *dev)
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  253  {
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15 @254  	struct vsi_iommu *iommu = dev_iommu_priv_get(dev);
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  255  	struct vsi_iommu_domain *vsi_domain;
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  256  
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  257  	vsi_domain = kzalloc(sizeof(*vsi_domain), GFP_KERNEL);
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  258  	if (!vsi_domain)
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  259  		return NULL;
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  260  
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  261  	vsi_domain->dev = iommu->dev;
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  262  	spin_lock_init(&vsi_domain->lock);
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  263  
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  264  	/*
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  265  	 * iommu use a 2 level pagetable.
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  266  	 * Each level1 (dt) and level2 (pt) table has 1024 4-byte entries.
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  267  	 * Allocate one 4 KiB page for each table.
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  268  	 */
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  269  	vsi_domain->dt = iommu_alloc_pages_sz(GFP_KERNEL | GFP_DMA32,
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  270  					      SPAGE_SIZE);
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  271  	if (!vsi_domain->dt)
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  272  		goto err_free_domain;
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  273  
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  274  	vsi_domain->dt_dma = dma_map_single(vsi_domain->dev, vsi_domain->dt,
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  275  					    SPAGE_SIZE, DMA_TO_DEVICE);
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  276  	if (dma_mapping_error(vsi_domain->dev, vsi_domain->dt_dma)) {
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  277  		dev_err(dev, "DMA map error for DT\n");
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  278  		goto err_free_dt;
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  279  	}
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  280  
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  281  	vsi_domain->pta = iommu_alloc_pages_sz(GFP_KERNEL | GFP_DMA32,
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  282  					       SPAGE_SIZE);
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  283  	if (!vsi_domain->pta)
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  284  		goto err_unmap_dt;
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  285  
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  286  	vsi_domain->pta[0] = vsi_mk_pta(vsi_domain->dt_dma);
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  287  	vsi_domain->pta_dma = dma_map_single(vsi_domain->dev, vsi_domain->pta,
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  288  					     SPAGE_SIZE, DMA_TO_DEVICE);
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  289  	if (dma_mapping_error(vsi_domain->dev, vsi_domain->pta_dma)) {
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  290  		dev_err(dev, "DMA map error for PTA\n");
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  291  		goto err_free_pta;
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  292  	}
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  293  
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  294  	INIT_LIST_HEAD(&vsi_domain->iommus);
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  295  
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  296  	vsi_domain->domain.geometry.aperture_start = 0;
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  297  	vsi_domain->domain.geometry.aperture_end   = DMA_BIT_MASK(32);
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  298  	vsi_domain->domain.geometry.force_aperture = true;
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  299  	vsi_domain->domain.pgsize_bitmap	   = SZ_4K;
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  300  
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  301  	return &vsi_domain->domain;
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  302  
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  303  err_free_pta:
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  304  	iommu_free_pages(vsi_domain->pta);
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  305  err_unmap_dt:
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  306  	dma_unmap_single(vsi_domain->dev, vsi_domain->dt_dma,
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  307  			 SPAGE_SIZE, DMA_TO_DEVICE);
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  308  err_free_dt:
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  309  	iommu_free_pages(vsi_domain->dt);
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  310  err_free_domain:
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  311  	kfree(vsi_domain);
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  312  
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  313  	return NULL;
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  314  }
b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  315  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From lkp at intel.com  Tue Dec 16 07:27:25 2025
From: lkp at intel.com (kernel test robot)
Date: Tue, 16 Dec 2025 23:27:25 +0800
Subject: [PATCH v2 3/3] randomize_kstack: Unify random source across
 arches
In-Reply-To: <20251215163520.1144179-4-ryan.roberts@arm.com>
References: <20251215163520.1144179-4-ryan.roberts@arm.com>
Message-ID: <202512162320.WFgo042e-lkp@intel.com>

Hi Ryan,

kernel test robot noticed the following build errors:

[auto build test ERROR on tip/sched/core]
[also build test ERROR on akpm-mm/mm-everything linus/master v6.19-rc1 next-20251216]
[cannot apply to kees/for-next/hardening kees/for-next/execve]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Ryan-Roberts/prandom-Convert-prandom_u32_state-to-__always_inline/20251216-013546
base:   tip/sched/core
patch link:    https://lore.kernel.org/r/20251215163520.1144179-4-ryan.roberts%40arm.com
patch subject: [PATCH v2 3/3] randomize_kstack: Unify random source across arches
config: x86_64-rhel-9.4-rust (https://download.01.org/0day-ci/archive/20251216/202512162320.WFgo042e-lkp at intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
rustc: rustc 1.88.0 (6b00bc388 2025-06-23)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251216/202512162320.WFgo042e-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512162320.WFgo042e-lkp at intel.com/

All errors (new ones prefixed by >>):

>> arch/x86/kvm/svm/svm.c:5509:1: error: redefinition of '__inittest'
    5509 | module_init(svm_init)
         | ^
   include/linux/module.h:132:42: note: expanded from macro 'module_init'
     132 |         static inline initcall_t __maybe_unused __inittest(void)                \
         |                                                 ^
   include/linux/randomize_kstack.h:86:1: note: previous definition is here
      86 | late_initcall(random_kstack_init);
         | ^
   include/linux/module.h:125:28: note: expanded from macro 'late_initcall'
     125 | #define late_initcall(fn)               module_init(fn)
         |                                         ^
   include/linux/module.h:132:42: note: expanded from macro 'module_init'
     132 |         static inline initcall_t __maybe_unused __inittest(void)                \
         |                                                 ^
>> arch/x86/kvm/svm/svm.c:5509:1: error: redefinition of 'init_module'
    5509 | module_init(svm_init)
         | ^
   include/linux/module.h:134:6: note: expanded from macro 'module_init'
     134 |         int init_module(void) __copy(initfn)                    \
         |             ^
   include/linux/randomize_kstack.h:86:1: note: previous definition is here
      86 | late_initcall(random_kstack_init);
         | ^
   include/linux/module.h:125:28: note: expanded from macro 'late_initcall'
     125 | #define late_initcall(fn)               module_init(fn)
         |                                         ^
   include/linux/module.h:134:6: note: expanded from macro 'module_init'
     134 |         int init_module(void) __copy(initfn)                    \
         |             ^
   2 errors generated.
--
>> drivers/misc/sgi-xp/xpc_main.c:1285:1: error: redefinition of '__inittest'
    1285 | module_init(xpc_init);
         | ^
   include/linux/module.h:132:42: note: expanded from macro 'module_init'
     132 |         static inline initcall_t __maybe_unused __inittest(void)                \
         |                                                 ^
   include/linux/randomize_kstack.h:86:1: note: previous definition is here
      86 | late_initcall(random_kstack_init);
         | ^
   include/linux/module.h:125:28: note: expanded from macro 'late_initcall'
     125 | #define late_initcall(fn)               module_init(fn)
         |                                         ^
   include/linux/module.h:132:42: note: expanded from macro 'module_init'
     132 |         static inline initcall_t __maybe_unused __inittest(void)                \
         |                                                 ^
>> drivers/misc/sgi-xp/xpc_main.c:1285:1: error: redefinition of 'init_module'
    1285 | module_init(xpc_init);
         | ^
   include/linux/module.h:134:6: note: expanded from macro 'module_init'
     134 |         int init_module(void) __copy(initfn)                    \
         |             ^
   include/linux/randomize_kstack.h:86:1: note: previous definition is here
      86 | late_initcall(random_kstack_init);
         | ^
   include/linux/module.h:125:28: note: expanded from macro 'late_initcall'
     125 | #define late_initcall(fn)               module_init(fn)
         |                                         ^
   include/linux/module.h:134:6: note: expanded from macro 'module_init'
     134 |         int init_module(void) __copy(initfn)                    \
         |             ^
   2 errors generated.


vim +/__inittest +5509 arch/x86/kvm/svm/svm.c

6aa8b732ca01c3d drivers/kvm/svm.c Avi Kivity 2006-12-10  5508  
6aa8b732ca01c3d drivers/kvm/svm.c Avi Kivity 2006-12-10 @5509  module_init(svm_init)

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From C.Stoidner at phytec.de  Tue Dec 16 07:29:55 2025
From: C.Stoidner at phytec.de (Christoph Stoidner)
Date: Tue, 16 Dec 2025 15:29:55 +0000
Subject: [PATCH 2/2] arm64: dts: imx93-phyboard-segin: Add peb-av-02
 overlay
In-Reply-To: <20251215170750.j2l6gnbocmhdloe6@pengutronix.de>
References: <20251202-v6-18-topic-imx93-phyboard-segin-av-02-display-v1-0-9c14be6c7478@pengutronix.de>
	 <20251202-v6-18-topic-imx93-phyboard-segin-av-02-display-v1-2-9c14be6c7478@pengutronix.de>
	 <15bb2331-713a-4b6a-ae9a-4870066e84dc@norik.com>
	 <20251215170750.j2l6gnbocmhdloe6@pengutronix.de>
Message-ID: <09a773bb51331940e76fbeb5e8128c183bf6d621.camel@phytec.de>

Hi Marco,

On Mo, 2025-12-15 at 18:07 +0100, Marco Felsch wrote:
> Hi Primoz,
> 
> On 25-12-03, Primoz Fiser wrote:
> > Hi Marco,
> > 
> > On 2. 12. 25 14:44, Marco Felsch wrote:
> > > From: Andrej Picej <andrej.picej at norik.com>
> > > 
> > > Add overlay for Audio-Video module PEB-AV-02. Add support for
> > > panel
> > > display, capacitive touchscreen and backlight.
> > > 
> > > For now the backlight is configured as a GPIO, brightness of the
> > > display
> > > can not be set. When the FLEXIO PWM driver is available this
> > > should be
> > > switched to PWM backlight driver.
> > > 
> > > Signed-off-by: Andrej Picej <andrej.picej at norik.com>
> > > [rework commit message, use local regulator, remove compatible]
> > > Signed-off-by: Primoz Fiser <primoz.fiser at norik.com>
> > > Signed-off-by: Christian Hemp <c.hemp at phytec.de>
> > > [m.felsch at pengutronix.de: cleanup downstream commit]
> > > Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
> > > ---
> > > ?arch/arm64/boot/dts/freescale/Makefile???????????? |?? 2 +
> > > ?.../freescale/imx93-phyboard-segin-peb-av-02.dtso? | 135
> > > +++++++++++++++++++++
> > > ?2 files changed, 137 insertions(+)
> > > 
> > > diff --git a/arch/arm64/boot/dts/freescale/Makefile
> > > b/arch/arm64/boot/dts/freescale/Makefile
> > > index
> > > 525ef180481d331e9c4decd092b7b831c497b67e..27e27ac29e82bc0692e86c2
> > > ba15c240dc9fbe1c6 100644
> > > --- a/arch/arm64/boot/dts/freescale/Makefile
> > > +++ b/arch/arm64/boot/dts/freescale/Makefile
> > > @@ -357,10 +357,12 @@ dtb-$(CONFIG_ARCH_MXC) += imx93-phyboard-
> > > nash.dtb
> > > ?dtb-$(CONFIG_ARCH_MXC) += imx93-phyboard-segin.dtb
> > > ?
> > > ?imx93-phyboard-nash-peb-wlbt-07-dtbs += imx93-phyboard-nash.dtb
> > > imx93-phyboard-nash-peb-wlbt-07.dtbo
> > > +imx93-phyboard-segin-peb-av-02-dtbs += imx93-phyboard-segin.dtb
> > > imx93-phyboard-segin-peb-av-02.dtbo
> > > ?imx93-phyboard-segin-peb-eval-01-dtbs += imx93-phyboard-
> > > segin.dtb imx93-phyboard-segin-peb-eval-01.dtbo
> > > ?imx93-phyboard-segin-peb-wlbt-05-dtbs += imx93-phyboard-
> > > segin.dtb imx93-phyboard-segin-peb-wlbt-05.dtbo
> > > ?imx93-phycore-rpmsg-dtbs += imx93-phyboard-nash.dtb imx93-
> > > phyboard-segin.dtb imx93-phycore-rpmsg.dtbo
> > > ?dtb-$(CONFIG_ARCH_MXC) += imx93-phyboard-nash-peb-wlbt-07.dtb
> > > +dtb-$(CONFIG_ARCH_MXC) += imx93-phyboard-segin-peb-av-02.dtb
> > 
> > Here you need to rebase since new commits on linux-next.
> 
> Argh.. will do.
> 
> > > ?dtb-$(CONFIG_ARCH_MXC) += imx93-phyboard-segin-peb-eval-01.dtb
> > > ?dtb-$(CONFIG_ARCH_MXC) += imx93-phyboard-segin-peb-wlbt-05.dtb
> > > ?dtb-$(CONFIG_ARCH_MXC) += imx93-phycore-rpmsg.dtb
> > > diff --git a/arch/arm64/boot/dts/freescale/imx93-phyboard-segin-
> > > peb-av-02.dtso b/arch/arm64/boot/dts/freescale/imx93-phyboard-
> > > segin-peb-av-02.dtso
> > > new file mode 100644
> > > index
> > > 0000000000000000000000000000000000000000..2e7074e402dc8fdeb1568d4
> > > f2d4960431e972501
> > > --- /dev/null
> > > +++ b/arch/arm64/boot/dts/freescale/imx93-phyboard-segin-peb-av-
> > > 02.dtso
> > > @@ -0,0 +1,135 @@
> > > +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> > > +/*
> > > + * Copyright (C) 2025 PHYTEC Messtechnik GmbH
> > > + * Copyright (C) 2025 Pengutronix
> > > + *
> > > + * Author: Andrej Picej <andrej.picej at norik.com>
> > > + * Author: Marco Felsch <kernel at pengutronix.de>
> > > + */
> > > +
> > > +#include <dt-bindings/clock/imx93-clock.h>
> > > +#include <dt-bindings/gpio/gpio.h>
> > > +#include <dt-bindings/interrupt-controller/arm-gic.h>
> > > +#include "imx93-pinfunc.h"
> > > +
> > > +/dts-v1/;
> > > +/plugin/;
> > > +
> > > +&{/} {
> > > +	/* TODO: Convert to PWM backlight once the FlexIO PWM is
> > > supported */
> > > +	backlight: backlight {
> > > +		compatible = "gpio-backlight";
> > > +		pinctrl-names = "default";
> > > +		pinctrl-0 = <&pinctrl_backlight>;
> > > +		gpios = <&gpio4 28 GPIO_ACTIVE_HIGH>;
> > > +	};
> > > +
> > > +	panel {
> > > +		compatible = "edt,etm0700g0edh6";
> > > +		pinctrl-names = "default";
> > > +		pinctrl-0 = <&pinctrl_panel>;
> > > +
> > > +		backlight = <&backlight>;
> > > +		enable-gpios = <&gpio4 29 GPIO_ACTIVE_HIGH>;
> > > +		power-supply = <&reg_x71_vcc_3v3>;
> > > +
> > > +		port {
> > > +			panel_in: endpoint {
> > > +				remote-endpoint =
> > > <&dpi_to_panel>;
> > > +			};
> > > +		};
> > > +	};
> > > +
> > > +	reg_x71_vcc_3v3: regulator-x71-vcc-3v3 {
> > 
> > I just checked the schematics.
> > 
> > Can we rename this to reg_vcc_3v3_con in v2 maybe?
> > 
> > > +		compatible = "regulator-fixed";
> > > +		regulator-name = "X71-VCC3V3";
> > 
> > And this to "VCC3V3_CON"?
> > 
> > The reasoning behind is that "X71-VCC3V3" voltage doesn't exist on
> > the
> > schematics, while there is actually "VCC3V3_CON" voltage supplying
> > the
> > display panel.
> 
> I know that "X71-VCC3V3" doesn't exist, I also thought about
> "X71:VCC3V3" to make it clear. Why I mentioned the X71 in the first
> place was to not cause any naming conflict. I would like to keep the
> X71
> naming since "VCC3V3_CON" really is the "X71-VCC3V3" with some
> filters
> applied. Anyway, I can change this of course.
> 
> > > +		regulator-max-microvolt = <3300000>;
> > > +		regulator-min-microvolt = <3300000>;
> > > +	};
> > > +};
> > > +
> > > +&dpi_bridge {
> > > +	status = "okay";
> > > +};
> > > +
> > > +&dpi_to_panel {
> > > +	remote-endpoint = <&panel_in>;
> > > +	bus-width = <18>;
> > > +};
> > > +
> > > +&lcdif {
> > > +	pinctrl-names = "default";
> > > +	pinctrl-0 = <&pinctrl_lcdif>;
> > > +	assigned-clocks = <&clk IMX93_CLK_VIDEO_PLL>;
> > > +	assigned-clock-rates = <332600000>;
> > > +	status = "okay";
> > > +};
> > > +
> > > +&lpi2c2 {
> > > +	#address-cells = <1>;
> > > +	#size-cells = <0>;
> > > +
> > > +	touchscreen at 38 {
> > > +		compatible = "edt,edt-ft5406";
> > > +		reg = <0x38>;
> > > +		pinctrl-names = "default";
> > > +		pinctrl-0 = <&pinctrl_touchscreen>;
> > > +		interrupt-parent = <&gpio4>;
> > > +		interrupts = <12 IRQ_TYPE_EDGE_FALLING>;
> > > +		reset-gpios = <&gpio4 1 GPIO_ACTIVE_LOW>;
> > > +		touchscreen-size-x = <1792>;
> > > +		touchscreen-size-y = <1024>;
> > 
> > Please add "wakeup-source" property here like in the downstream
> > commit.
> > 
> > With this in place, panel touch can be used to wake up the board
> > from sleep.
> 
> Is this a required feature? Touchscreens with no certain
> low-power mode handlig (e.g. reduced scanning time) can draw much
> power
> in suspend.
> 
> I can add it if Phytec is aware of this fact and still wants to have
> thsi feature.

Yes, please add this "wakeup-source" property again. This feature?
shall?work on our platform by default. And one who wants to avoid
touchscreen as wakeup-source can modify the device-tree or disable?
it?for wakeup via policy/sysfs.

Thanks, 
Christoph

> 
> > Last but not least, can you add the vcc and iovcc supply regulators
> > here
> > like in the downstream commit:
> > 
> > vcc-supply = <&reg_vcc_3v3_con>;
> > iovcc-supply = <&reg_vcc_3v3_con>;
> > 
> > to get rid of the following warnings:
> > 
> > edt_ft5x06 1-0038: supply vcc not found, using dummy regulator
> > edt_ft5x06 1-0038: supply iovcc not found, using dummy regulator
> 
> Will do.
> 
> > Anyway, I tested the display on the segin board with latest linux-
> > next
> > and your patches. Can report display, touch and backlight work as
> > expected.
> > 
> > Thank you!
> > 
> > Tested-by: Primoz Fiser <primoz.fiser at norik.com>
> 
> Regards,
> ? Marco
> 
> > 
> > BR,
> > Primoz
> > 
> > > +	};
> > > +};
> > > +
> > > +&media_blk_ctrl {
> > > +	status = "okay";
> > > +};
> > > +
> > > +&iomuxc {
> > > +	pinctrl_backlight: backlightgrp {
> > > +		fsl,pins = <
> > > +			MX93_PAD_CCM_CLKO3__GPIO4_IO28		
> > > 	0x1133e
> > > +		>;
> > > +	};
> > > +
> > > +	pinctrl_lcdif: lcdifgrp {
> > > +		fsl,pins = <
> > > +			MX93_PAD_GPIO_IO00__MEDIAMIX_DISP_CLK	
> > > 	0x50e
> > > +			MX93_PAD_GPIO_IO01__MEDIAMIX_DISP_DE	
> > > 	0x50e
> > > +			MX93_PAD_GPIO_IO02__MEDIAMIX_DISP_VSYNC
> > > 		0x50e
> > > +			MX93_PAD_GPIO_IO03__MEDIAMIX_DISP_HSYNC
> > > 		0x50e
> > > +			MX93_PAD_GPIO_IO04__MEDIAMIX_DISP_DATA00
> > > 	0x50e
> > > +			MX93_PAD_GPIO_IO05__MEDIAMIX_DISP_DATA01
> > > 	0x50e
> > > +			MX93_PAD_GPIO_IO06__MEDIAMIX_DISP_DATA02
> > > 	0x50e
> > > +			MX93_PAD_GPIO_IO07__MEDIAMIX_DISP_DATA03
> > > 	0x50e
> > > +			MX93_PAD_GPIO_IO08__MEDIAMIX_DISP_DATA04
> > > 	0x50e
> > > +			MX93_PAD_GPIO_IO09__MEDIAMIX_DISP_DATA05
> > > 	0x51e
> > > +			MX93_PAD_GPIO_IO10__MEDIAMIX_DISP_DATA06
> > > 	0x50e
> > > +			MX93_PAD_GPIO_IO11__MEDIAMIX_DISP_DATA07
> > > 	0x50e
> > > +			MX93_PAD_GPIO_IO12__MEDIAMIX_DISP_DATA08
> > > 	0x50e
> > > +			MX93_PAD_GPIO_IO13__MEDIAMIX_DISP_DATA09
> > > 	0x50e
> > > +			MX93_PAD_GPIO_IO14__MEDIAMIX_DISP_DATA10
> > > 	0x50e
> > > +			MX93_PAD_GPIO_IO15__MEDIAMIX_DISP_DATA11
> > > 	0x50e
> > > +			MX93_PAD_GPIO_IO16__MEDIAMIX_DISP_DATA12
> > > 	0x506
> > > +			MX93_PAD_GPIO_IO17__MEDIAMIX_DISP_DATA13
> > > 	0x506
> > > +			MX93_PAD_GPIO_IO18__MEDIAMIX_DISP_DATA14
> > > 	0x506
> > > +			MX93_PAD_GPIO_IO19__MEDIAMIX_DISP_DATA15
> > > 	0x506
> > > +			MX93_PAD_GPIO_IO20__MEDIAMIX_DISP_DATA16
> > > 	0x506
> > > +			MX93_PAD_GPIO_IO21__MEDIAMIX_DISP_DATA17
> > > 	0x506
> > > +		>;
> > > +	};
> > > +
> > > +	pinctrl_panel: panelgrp {
> > > +		fsl,pins = <
> > > +			MX93_PAD_CCM_CLKO4__GPIO4_IO29		
> > > 	0x1133e
> > > +		>;
> > > +	};
> > > +
> > > +	pinctrl_touchscreen: touchscreengrp {
> > > +		fsl,pins = <
> > > +			MX93_PAD_ENET1_MDIO__GPIO4_IO01	
> > > 		0x11e
> > > +			MX93_PAD_ENET1_RD2__GPIO4_IO12		
> > > 	0x1133e
> > > +		>;
> > > +	};
> > > +};
> > > 
> > 
> > -- 
> > Primoz Fiser
> > phone: +386-41-390-545
> > email: primoz.fiser at norik.com
> > --
> > Norik systems d.o.o.
> > Your embedded software partner
> > Slovenia, EU
> > phone: +386-41-540-545
> > email: info at norik.com
> > 
> > 
> 


From james.clark at linaro.org  Tue Dec 16 07:34:20 2025
From: james.clark at linaro.org (James Clark)
Date: Tue, 16 Dec 2025 17:34:20 +0200
Subject: [PATCH 10/19] coresight: trbe: Always check fault action when
 updating buffer
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-10-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-10-7da32b076b28@arm.com>
Message-ID: <e22497a2-1019-4eec-95b4-b6fd80090a3f@linaro.org>



On 01/12/2025 13:22, Leo Yan wrote:
> The current code checks the fault action only via the IRQ status bit,
> which is unreliable due to possible hardware latency.

This makes it sound like it's fixing a bug, but without a fixes: tag I'm 
assuming it's not a bug. Also I don't get how the change improves the 
latency situation, it still calls trbe_get_fault_act() basically in the 
same place. I think there might be another reason like it makes the code 
cleaner for a later change? Or the commit message needs some elaboration.

> 
> Move the fault action check out of the IRQ status condition.  This also
> causes the buffer size to be calculated for non-WRAP and fault cases,
> which is fine since the write pointer is trusted for the calculation.
> 
> Signed-off-by: Leo Yan <leo.yan at arm.com>
> ---
>   drivers/hwtracing/coresight/coresight-trbe.c | 17 +++--------------
>   1 file changed, 3 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
> index f56ecdeaa6596afb440e4d53732e08a85f9bf89d..e579ea98523c24d23a0cd265dcdd0a46b52b52da 100644
> --- a/drivers/hwtracing/coresight/coresight-trbe.c
> +++ b/drivers/hwtracing/coresight/coresight-trbe.c
> @@ -806,7 +806,6 @@ static unsigned long arm_trbe_update_buffer(struct coresight_device *csdev,
>   	enum trbe_fault_action act;
>   	unsigned long size, status;
>   	unsigned long flags;
> -	bool wrap = false;
>   
>   	WARN_ON(buf->cpudata != cpudata);
>   	WARN_ON(cpudata->cpu != smp_processor_id());
> @@ -858,21 +857,11 @@ static unsigned long arm_trbe_update_buffer(struct coresight_device *csdev,
>   		 */
>   		clr_trbe_irq();
>   		isb();
> -
> -		act = trbe_get_fault_act(handle, status);
> -		/*
> -		 * If this was not due to a WRAP event, we have some
> -		 * errors and as such buffer is empty.
> -		 */
> -		if (act != TRBE_FAULT_ACT_WRAP) {
> -			size = 0;
> -			goto done;
> -		}
> -
> -		wrap = true;
>   	}
>   
> -	size = trbe_get_trace_size(handle, buf, wrap);
> +	act = trbe_get_fault_act(handle, status);
> +
> +	size = trbe_get_trace_size(handle, buf, act == TRBE_FAULT_ACT_WRAP);
>   
>   done:
>   	local_irq_restore(flags);
> 



From lpieralisi at kernel.org  Tue Dec 16 07:40:55 2025
From: lpieralisi at kernel.org (Lorenzo Pieralisi)
Date: Tue, 16 Dec 2025 16:40:55 +0100
Subject: [PATCH 29/32] irqchip/gic-v5: Check if impl is virt capable
In-Reply-To: <20251212152215.675767-30-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
 <20251212152215.675767-30-sascha.bischoff@arm.com>
Message-ID: <aUF9hwjBuUKA73U8@lpieralisi>

On Fri, Dec 12, 2025 at 03:22:45PM +0000, Sascha Bischoff wrote:
> Now that there is support for creating a GICv5-based guest with KVM,

The only comment I have is - as discussed, this patch is not really
dependent on GICv5 KVM support - ie, if IRS_IDR0.VIRT == b0 there isn't
a chance GIC v3 legacy support is implemented either, maybe it is worth
clarifying that.

Otherwise LGTM:

Reviewed-by: Lorenzo Pieralisi <lpieralisi at kernel.org>

> check that the hardware itself supports virtualisation, skipping the
> setting of struct gic_kvm_info if not.
> 
> Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
> ---
>  drivers/irqchip/irq-gic-v5-irs.c   | 4 ++++
>  drivers/irqchip/irq-gic-v5.c       | 5 +++++
>  include/linux/irqchip/arm-gic-v5.h | 4 ++++
>  3 files changed, 13 insertions(+)


> 
> diff --git a/drivers/irqchip/irq-gic-v5-irs.c b/drivers/irqchip/irq-gic-v5-irs.c
> index ce2732d649a3e..eebf9f219ac8c 100644
> --- a/drivers/irqchip/irq-gic-v5-irs.c
> +++ b/drivers/irqchip/irq-gic-v5-irs.c
> @@ -744,6 +744,10 @@ static int __init gicv5_irs_init(struct device_node *node)
>  	 */
>  	if (list_empty(&irs_nodes)) {
>  
> +		idr = irs_readl_relaxed(irs_data, GICV5_IRS_IDR0);
> +		gicv5_global_data.virt_capable =
> +			!!FIELD_GET(GICV5_IRS_IDR0_VIRT, idr);
> +
>  		idr = irs_readl_relaxed(irs_data, GICV5_IRS_IDR1);
>  		irs_setup_pri_bits(idr);
>  
> diff --git a/drivers/irqchip/irq-gic-v5.c b/drivers/irqchip/irq-gic-v5.c
> index 41ef286c4d781..f5b17a2557aa1 100644
> --- a/drivers/irqchip/irq-gic-v5.c
> +++ b/drivers/irqchip/irq-gic-v5.c
> @@ -1064,6 +1064,11 @@ static struct gic_kvm_info gic_v5_kvm_info __initdata;
>  
>  static void __init gic_of_setup_kvm_info(struct device_node *node)
>  {
> +	if (!gicv5_global_data.virt_capable) {
> +		pr_info("GIC implementation is not virtualization capable\n");
> +		return;
> +	}
> +
>  	gic_v5_kvm_info.type = GIC_V5;
>  
>  	/* GIC Virtual CPU interface maintenance interrupt */
> diff --git a/include/linux/irqchip/arm-gic-v5.h b/include/linux/irqchip/arm-gic-v5.h
> index 9607b36f021ee..36f4c0e8ef8e9 100644
> --- a/include/linux/irqchip/arm-gic-v5.h
> +++ b/include/linux/irqchip/arm-gic-v5.h
> @@ -45,6 +45,7 @@
>  /*
>   * IRS registers and tables structures
>   */
> +#define GICV5_IRS_IDR0			0x0000
>  #define GICV5_IRS_IDR1			0x0004
>  #define GICV5_IRS_IDR2			0x0008
>  #define GICV5_IRS_IDR5			0x0014
> @@ -65,6 +66,8 @@
>  #define GICV5_IRS_IST_STATUSR		0x0194
>  #define GICV5_IRS_MAP_L2_ISTR		0x01c0
>  
> +#define GICV5_IRS_IDR0_VIRT		BIT(6)
> +
>  #define GICV5_IRS_IDR1_PRIORITY_BITS	GENMASK(22, 20)
>  #define GICV5_IRS_IDR1_IAFFID_BITS	GENMASK(19, 16)
>  
> @@ -280,6 +283,7 @@ struct gicv5_chip_data {
>  	u8			cpuif_pri_bits;
>  	u8			cpuif_id_bits;
>  	u8			irs_pri_bits;
> +	bool			virt_capable;
>  	struct {
>  		__le64 *l1ist_addr;
>  		u32 l2_size;
> -- 
> 2.34.1


From Frank.li at nxp.com  Tue Dec 16 07:41:52 2025
From: Frank.li at nxp.com (Frank Li)
Date: Tue, 16 Dec 2025 10:41:52 -0500
Subject: [PATCH v3 2/5] media: nxp: use dev_err_probe() to simplify code
In-Reply-To: <13428800.O9o76ZdvQC@steina-w>
References: <20251215-cam_cleanup-v3-0-a61995068f38@nxp.com>
 <5462566.31r3eYUQgx@steina-w>
 <aUFwqMiYE+P+KdsO@lizhi-Precision-Tower-5810>
 <13428800.O9o76ZdvQC@steina-w>
Message-ID: <aUF9wPzPaGD1nmM2@lizhi-Precision-Tower-5810>

On Tue, Dec 16, 2025 at 03:50:17PM +0100, Alexander Stein wrote:
> Hi Frank,
>
> Am Dienstag, 16. Dezember 2025, 15:46:00 CET schrieb Frank Li:
> > On Tue, Dec 16, 2025 at 08:34:18AM +0100, Alexander Stein wrote:
> > > Hi,
> > >
> > > Am Montag, 15. Dezember 2025, 23:49:53 CET schrieb Frank Li:
> > > > Use dev_err_probe() to simplify the code. Drop the explicit error message
> > > > after returning from imx8mq_mipi_csi_parse_dt(), as the error is already
> > > > reported by this helper.
> > > >
> > > > No functional change.
> > > >
> > > > Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> > > > Signed-off-by: Frank Li <Frank.Li at nxp.com>
> > > > ---
> > > > change in v2:
> > > > - add  Laurent Pinchart review tags
> > > > - wrap error message to new line
> > > > - remove error code print in dev_err_probe();
> > > > - drop error messaage at imx8mq_mipi_csi_parse_dt()
> > > > ---
> > > >  drivers/media/platform/nxp/imx-mipi-csis.c    |  6 ++---
> > > >  drivers/media/platform/nxp/imx7-media-csi.c   | 14 ++++--------
> > > >  drivers/media/platform/nxp/imx8mq-mipi-csi2.c | 33 ++++++++++++---------------
> > > >  3 files changed, 21 insertions(+), 32 deletions(-)
> > > >
> > > > diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c
> > > > index 088b2945aee33731c565f049dd17721356300b84..ce93d868746f002c22e2f86b1e0aa84ec1a76061 100644
> > > > --- a/drivers/media/platform/nxp/imx-mipi-csis.c
> > > > +++ b/drivers/media/platform/nxp/imx-mipi-csis.c
> > > > @@ -1547,10 +1547,8 @@ static int mipi_csis_probe(struct platform_device *pdev)
> > > >  	/* Now that the hardware is initialized, request the interrupt. */
> > > >  	ret = devm_request_irq(dev, irq, mipi_csis_irq_handler, 0,
> > > >  			       dev_name(dev), csis);
> > > > -	if (ret) {
> > > > -		dev_err(dev, "Interrupt request failed\n");
> > > > -		return ret;
> > > > -	}
> > > > +	if (ret)
> > > > +		return dev_err_probe(dev, ret, "Interrupt request failed\n");
> > > >
> > > >  	/* Initialize and register the subdev. */
> > > >  	ret = mipi_csis_subdev_init(csis);
> > > > diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c
> > > > index 933a5f39f9f4c9b43ca8d2a1819d0145981266e6..7ddc7ba06e3d4e007013821f67d783898a15461f 100644
> > > > --- a/drivers/media/platform/nxp/imx7-media-csi.c
> > > > +++ b/drivers/media/platform/nxp/imx7-media-csi.c
> > > > @@ -2218,11 +2218,9 @@ static int imx7_csi_probe(struct platform_device *pdev)
> > > >
> > > >  	/* Acquire resources and install interrupt handler. */
> > > >  	csi->mclk = devm_clk_get(&pdev->dev, "mclk");
> > > > -	if (IS_ERR(csi->mclk)) {
> > > > -		ret = PTR_ERR(csi->mclk);
> > > > -		dev_err(dev, "Failed to get mclk: %d", ret);
> > > > -		return ret;
> > > > -	}
> > > > +	if (IS_ERR(csi->mclk))
> > > > +		return dev_err_probe(dev, PTR_ERR(csi->mclk),
> > > > +				     "Failed to get mclk\n");
> > > >
> > > >  	csi->irq = platform_get_irq(pdev, 0);
> > > >  	if (csi->irq < 0)
> > > > @@ -2236,10 +2234,8 @@ static int imx7_csi_probe(struct platform_device *pdev)
> > > >
> > > >  	ret = devm_request_irq(dev, csi->irq, imx7_csi_irq_handler, 0, "csi",
> > > >  			       (void *)csi);
> > > > -	if (ret < 0) {
> > > > -		dev_err(dev, "Request CSI IRQ failed.\n");
> > > > -		return ret;
> > > > -	}
> > > > +	if (ret < 0)
> > > > +		return dev_err_probe(dev, ret, "Request CSI IRQ failed.\n");
> > > >
> > > >  	/* Initialize all the media device infrastructure. */
> > > >  	ret = imx7_csi_media_init(csi);
> > > > diff --git a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
> > > > index 0851f4a9ae52d3096f454da643cfdc5017e000b1..a007c582b4d91660a97910a6a0d53c9b6fcd73e9 100644
> > > > --- a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
> > > > +++ b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
> > > > @@ -951,10 +951,9 @@ static int imx8mq_mipi_csi_parse_dt(struct csi_state *state)
> > > >  	int ret = 0;
> > > >
> > > >  	state->rst = devm_reset_control_array_get_exclusive(dev);
> > > > -	if (IS_ERR(state->rst)) {
> > > > -		dev_err(dev, "Failed to get reset: %pe\n", state->rst);
> > > > -		return PTR_ERR(state->rst);
> > > > -	}
> > > > +	if (IS_ERR(state->rst))
> > > > +		return dev_err_probe(dev, PTR_ERR(state->rst),
> > > > +				     "Failed to get reset\n");
> > > >
> > > >  	if (state->pdata->use_reg_csr) {
> > > >  		const struct regmap_config regmap_config = {
> > > > @@ -977,24 +976,22 @@ static int imx8mq_mipi_csi_parse_dt(struct csi_state *state)
> > > >
> > > >  	ret = of_property_read_u32_array(np, "fsl,mipi-phy-gpr", out_val,
> > > >  					 ARRAY_SIZE(out_val));
> > > > -	if (ret) {
> > > > -		dev_err(dev, "no fsl,mipi-phy-gpr property found: %d\n", ret);
> > > > -		return ret;
> > > > -	}
> > > > +	if (ret)
> > > > +		return dev_err_probe(dev, ret, "no %s property found\n",
> > > > +				    "fsl,mipi-phy-gpr");
> > >
> > > Do you really need to pass the (fixed) property name as an argument? Why
> > > not move into the const string directly? I would also rephrase it a bit:
> > > "property fsl,mipi-phy-gpr not found"
> >
> > Laurent Pinchart provide comments at previous version. The same
> > "fsl,mipi-phy-gpr" share one entry at RO region. slice save RO region
> > space.
> >
> > https://lore.kernel.org/imx/20251119043307.GH17526 at pendragon.ideasonboard.com/
>
> "assuming it's worth it". Do you have any numbers? I doubt there is a
> significant benefit, but I don't have strong opinion here.

Yes, only few byte. But no worth to argue this. Laurent Pinchart, who pick
patches.

> But the grammar should still be improved.

Okay, will update it.

Frank

>
> Best regards
> Alexander
>
> > Frank
> >
> > >
> > > With that fixed:
> > > Reviewed-by: Alexander Stein <alexander.stein at ew.tq-group.com>
> > >
> > > >
> > > >  	ph = *out_val;
> > > >
> > > >  	node = of_find_node_by_phandle(ph);
> > > > -	if (!node) {
> > > > -		dev_err(dev, "Error finding node by phandle\n");
> > > > -		return -ENODEV;
> > > > -	}
> > > > +	if (!node)
> > > > +		return dev_err_probe(dev, -ENODEV,
> > > > +				     "Error finding node by phandle\n");
> > > > +
> > > >  	state->phy_gpr = syscon_node_to_regmap(node);
> > > >  	of_node_put(node);
> > > > -	if (IS_ERR(state->phy_gpr)) {
> > > > -		dev_err(dev, "failed to get gpr regmap: %pe\n", state->phy_gpr);
> > > > -		return PTR_ERR(state->phy_gpr);
> > > > -	}
> > > > +	if (IS_ERR(state->phy_gpr))
> > > > +		return dev_err_probe(dev, PTR_ERR(state->phy_gpr),
> > > > +				     "failed to get gpr regmap\n");
> > > >
> > > >  	state->phy_gpr_reg = out_val[1];
> > > >  	dev_dbg(dev, "phy gpr register set to 0x%x\n", state->phy_gpr_reg);
> > > > @@ -1017,10 +1014,8 @@ static int imx8mq_mipi_csi_probe(struct platform_device *pdev)
> > > >  	state->pdata = of_device_get_match_data(dev);
> > > >
> > > >  	ret = imx8mq_mipi_csi_parse_dt(state);
> > > > -	if (ret < 0) {
> > > > -		dev_err(dev, "Failed to parse device tree: %d\n", ret);
> > > > +	if (ret < 0)
> > > >  		return ret;
> > > > -	}
> > > >
> > > >  	/* Acquire resources. */
> > > >  	state->regs = devm_platform_ioremap_resource(pdev, 0);
> > > >
> > > >
> > >
> > >
> > > --
> > > TQ-Systems GmbH | M?hlstra?e 2, Gut Delling | 82229 Seefeld, Germany
> > > Amtsgericht M?nchen, HRB 105018
> > > Gesch?ftsf?hrer: Detlef Schneider, R?diger Stahl, Stefan Schneider
> > > http://www.tq-group.com/
> >
> >
> >
>
>
> --
> TQ-Systems GmbH | M?hlstra?e 2, Gut Delling | 82229 Seefeld, Germany
> Amtsgericht M?nchen, HRB 105018
> Gesch?ftsf?hrer: Detlef Schneider, R?diger Stahl, Stefan Schneider
> http://www.tq-group.com/




From vkoul at kernel.org  Tue Dec 16 07:43:07 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 16 Dec 2025 21:13:07 +0530
Subject: [PATCH 0/8] dmaengine: Add new API to combine onfiguration and
 descriptor preparation
In-Reply-To: <aUF2SX/6bV2lHtF0@lizhi-Precision-Tower-5810>
References: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
 <aUFUX0e_h7RGAecz@vaman>
 <aUF2SX/6bV2lHtF0@lizhi-Precision-Tower-5810>
Message-ID: <aUF-C8iUCs-dYXGm@vaman>

On 16-12-25, 10:10, Frank Li wrote:
> On Tue, Dec 16, 2025 at 06:15:19PM +0530, Vinod Koul wrote:
> > On 08-12-25, 12:09, Frank Li wrote:
> >
> > Spell check on subject please :-)
> >
> > > Previously, configuration and preparation required two separate calls. This
> > > works well when configuration is done only once during initialization.
> > >
> > > However, in cases where the burst length or source/destination address must
> > > be adjusted for each transfer, calling two functions is verbose.
> > >
> > > 	if (dmaengine_slave_config(chan, &sconf)) {
> > > 		dev_err(dev, "DMA slave config fail\n");
> > > 		return -EIO;
> > > 	}
> > >
> > > 	tx = dmaengine_prep_slave_single(chan, dma_local, len, dir, flags);
> > >
> > > After new API added
> > >
> > > 	tx = dmaengine_prep_slave_single(chan, dma_local, len, dir, flags, &sconf);
> >
> > Nak, we cant change the API like this.
> 
> Sorry, it is typo here. in patch
> 	dmaengine_prep_slave_single_config(chan, dma_local, len, dir, flags, &sconf);
> 
> > I agree that you can add a new way to call dmaengine_slave_config() and
> > dmaengine_prep_slave_single() together.
> > maybe dmaengine_prep_config_perip_single() (yes we can go away with slave, but
> > cant drop it, as absence means something else entire).
> 
> how about dmaengine_prep_peripheral_single() and dmaengine_prep_peripheral_sg()
> to align recent added "dmaengine_prep_peripheral_dma_vec()"

It doesnt imply config has been done, how does it differ from usual
prep_ calls. I see confusions can be caused!

> I think "peripheral" also is reduntant. dmaengine_prep_single() and
> dmaengine_prep_sg() should be enough because

Then you are missing the basic premises of dmaengine that we have memcpy
ops and peripheral dma ops (aka slave) Absence of peripheral always
implies that it is memcpy

> - dmaengine_prep_dma_cyclic() is actually work with prepiperial FIFO
> - some prepierial FIFO work like memory, by use shared memory method, like
> PCIe map windows.
> - argument: config and dir already passdown information to indicate if it
> is device preiperial. So needn't indicate at function name.
> - maybe later extend to support mem to mem by config becuase adjust burst
> size for difference alignment or difference bus fabric port to optimaze
> performance.
> 
> Frank
> 
> >
> > I would like to retain the dmaengine_prep_slave_single() as an API for
> > users to call and invoke. There are users who configure channel once as
> > well
> >
> > >
> > > Additional, prevous two calls requires additional locking to ensure both
> > > steps complete atomically.
> > >
> > >     mutex_lock()
> > >     dmaengine_slave_config()
> > >     dmaengine_prep_slave_single()
> > >     mutex_unlock()
> > >
> > > after new API added, mutex lock can be moved. See patch
> > >      nvmet: pci-epf: Use dmaengine_prep_slave_single_config() API
> > >
> > > Signed-off-by: Frank Li <Frank.Li at nxp.com>
> > > ---
> > > Frank Li (8):
> > >       dmaengine: Add API to combine configuration and preparation (sg and single)
> > >       PCI: endpoint: pci-epf-test: use new DMA API to simple code
> > >       dmaengine: dw-edma: Use new .device_prep_slave_sg_config() callback
> > >       dmaengine: dw-edma: Pass dma_slave_config to dw_edma_device_transfer()
> > >       nvmet: pci-epf: Remove unnecessary dmaengine_terminate_sync() on each DMA transfer
> > >       nvmet: pci-epf: Use dmaengine_prep_slave_single_config() API
> > >       PCI: epf-mhi:Using new API dmaengine_prep_slave_single_config() to simple code.
> > >       crypto: atmel: Use dmaengine_prep_slave_single_config() API
> > >
> > >  drivers/crypto/atmel-aes.c                    | 10 ++---
> > >  drivers/dma/dw-edma/dw-edma-core.c            | 38 +++++++++++-----
> > >  drivers/nvme/target/pci-epf.c                 | 21 +++------
> > >  drivers/pci/endpoint/functions/pci-epf-mhi.c  | 52 +++++++---------------
> > >  drivers/pci/endpoint/functions/pci-epf-test.c |  8 +---
> > >  include/linux/dmaengine.h                     | 64 ++++++++++++++++++++++++---
> > >  6 files changed, 111 insertions(+), 82 deletions(-)
> > > ---
> > > base-commit: bc04acf4aeca588496124a6cf54bfce3db327039
> > > change-id: 20251204-dma_prep_config-654170d245a2
> > >
> > > Best regards,
> > > --
> > > Frank Li <Frank.Li at nxp.com>
> >
> > --
> > ~Vinod

-- 
~Vinod


From robh at kernel.org  Tue Dec 16 07:44:14 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Tue, 16 Dec 2025 09:44:14 -0600
Subject: [PATCH v3 6/7] dt-bindings: pinctrl: rockchip: Add RMIO
 controller binding
In-Reply-To: <20251216112053.1927852-7-ye.zhang@rock-chips.com>
References: <20251216112053.1927852-1-ye.zhang@rock-chips.com>
 <20251216112053.1927852-7-ye.zhang@rock-chips.com>
Message-ID: <176589985437.2528677.5118158763336562885.robh@kernel.org>


On Tue, 16 Dec 2025 19:20:52 +0800, Ye Zhang wrote:
> 1. Add header file with constants for RMIO function IDs for the Rockchip
> RK3506 SoC.
> 2. Add device tree binding for the RMIO (Rockchip Matrix I/O) controller
> which is a sub-device of the main pinctrl on some Rockchip SoCs.
> 
> Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
> ---
>  .../bindings/pinctrl/rockchip,pinctrl.yaml    |   9 ++
>  .../bindings/pinctrl/rockchip,rmio.yaml       | 106 +++++++++++++++++
>  .../pinctrl/rockchip,rk3506-rmio.h            | 109 ++++++++++++++++++
>  3 files changed, 224 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml
>  create mode 100644 include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:
./Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml:88:11: [error] string value is redundantly quoted with any quotes (quoted-strings)

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/pinctrl/rockchip,rmio.example.dtb: rmio (rockchip,rk3506-rmio): compatible: ['rockchip,rk3506-rmio', 'rockchip,rmio'] is not of type 'object'
	from schema $id: http://devicetree.org/schemas/pinctrl/rockchip,rmio.yaml

doc reference errors (make refcheckdocs):

See https://patchwork.kernel.org/project/devicetree/patch/20251216112053.1927852-7-ye.zhang at rock-chips.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.



From sean.anderson at linux.dev  Tue Dec 16 07:44:34 2025
From: sean.anderson at linux.dev (Sean Anderson)
Date: Tue, 16 Dec 2025 10:44:34 -0500
Subject: [PATCH] serial: xilinx_uartps: fix rs485 initialization at boot
In-Reply-To: <20251216152641.196221-1-jakub.turek@elsta.tech>
References: <20251216152641.196221-1-jakub.turek@elsta.tech>
Message-ID: <7f42e053-b7d6-4216-9ed1-c496db3a54d0@linux.dev>

On 12/16/25 10:26, j.turek wrote:
> When 'linux,rs485-enabled-at-boot-time;' property is enabled in device-tree
> and there is no rts-gpio defined there is NULL pointer dereference in
> function 'cdns_rts_gpio_enable' because 'cdns_uart->port->membase' pointer
> is not set at this point
> 
> Signed-off-by: Jakub Turek <jakub.turek at elsta.tech>
> 
> Fixes: fccc9d9233f9 ("tty: serial: uartps: Add rs485 support to uartps driver")
> ---
>  drivers/tty/serial/xilinx_uartps.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
> index c793fc74c26b..1e4d54fd5762 100644
> --- a/drivers/tty/serial/xilinx_uartps.c
> +++ b/drivers/tty/serial/xilinx_uartps.c
> @@ -1816,8 +1816,6 @@ static int cdns_uart_probe(struct platform_device *pdev)
>  		console_port = port;
>  	}
>  #endif
> -	if (cdns_uart_data->port->rs485.flags & SER_RS485_ENABLED)
> -		cdns_rs485_rx_setup(cdns_uart_data);
>  
>  	rc = uart_add_one_port(&cdns_uart_uart_driver, port);
>  	if (rc) {
> @@ -1826,6 +1824,9 @@ static int cdns_uart_probe(struct platform_device *pdev)
>  		goto err_out_pm_disable;
>  	}
>  
> +	if (cdns_uart_data->port->rs485.flags & SER_RS485_ENABLED)
> +		cdns_rs485_rx_setup(cdns_uart_data);
> +
>  #ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
>  	/* This is not port which is used for console that's why clean it up */
>  	if (console_port == port &&

Is probe the right place to do this configuration? Maybe
cdns_rs485_rx_setup should get moved to cdns_rs485_config.

--Sean


From alexander.stein at ew.tq-group.com  Tue Dec 16 07:51:38 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Tue, 16 Dec 2025 16:51:38 +0100
Subject: [PATCH v3 2/5] media: nxp: use dev_err_probe() to simplify code
In-Reply-To: <aUF9wPzPaGD1nmM2@lizhi-Precision-Tower-5810>
References: <20251215-cam_cleanup-v3-0-a61995068f38@nxp.com>
 <13428800.O9o76ZdvQC@steina-w> <aUF9wPzPaGD1nmM2@lizhi-Precision-Tower-5810>
Message-ID: <5692334.31r3eYUQgx@steina-w>

Am Dienstag, 16. Dezember 2025, 16:41:52 CET schrieb Frank Li:
> On Tue, Dec 16, 2025 at 03:50:17PM +0100, Alexander Stein wrote:
> > Hi Frank,
> >
> > Am Dienstag, 16. Dezember 2025, 15:46:00 CET schrieb Frank Li:
> > > On Tue, Dec 16, 2025 at 08:34:18AM +0100, Alexander Stein wrote:
> > > > Hi,
> > > >
> > > > Am Montag, 15. Dezember 2025, 23:49:53 CET schrieb Frank Li:
> > > > > Use dev_err_probe() to simplify the code. Drop the explicit error message
> > > > > after returning from imx8mq_mipi_csi_parse_dt(), as the error is already
> > > > > reported by this helper.
> > > > >
> > > > > No functional change.
> > > > >
> > > > > Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> > > > > Signed-off-by: Frank Li <Frank.Li at nxp.com>
> > > > > ---
> > > > > change in v2:
> > > > > - add  Laurent Pinchart review tags
> > > > > - wrap error message to new line
> > > > > - remove error code print in dev_err_probe();
> > > > > - drop error messaage at imx8mq_mipi_csi_parse_dt()
> > > > > ---
> > > > >  drivers/media/platform/nxp/imx-mipi-csis.c    |  6 ++---
> > > > >  drivers/media/platform/nxp/imx7-media-csi.c   | 14 ++++--------
> > > > >  drivers/media/platform/nxp/imx8mq-mipi-csi2.c | 33 ++++++++++++---------------
> > > > >  3 files changed, 21 insertions(+), 32 deletions(-)
> > > > >
> > > > > diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c
> > > > > index 088b2945aee33731c565f049dd17721356300b84..ce93d868746f002c22e2f86b1e0aa84ec1a76061 100644
> > > > > --- a/drivers/media/platform/nxp/imx-mipi-csis.c
> > > > > +++ b/drivers/media/platform/nxp/imx-mipi-csis.c
> > > > > @@ -1547,10 +1547,8 @@ static int mipi_csis_probe(struct platform_device *pdev)
> > > > >  	/* Now that the hardware is initialized, request the interrupt. */
> > > > >  	ret = devm_request_irq(dev, irq, mipi_csis_irq_handler, 0,
> > > > >  			       dev_name(dev), csis);
> > > > > -	if (ret) {
> > > > > -		dev_err(dev, "Interrupt request failed\n");
> > > > > -		return ret;
> > > > > -	}
> > > > > +	if (ret)
> > > > > +		return dev_err_probe(dev, ret, "Interrupt request failed\n");
> > > > >
> > > > >  	/* Initialize and register the subdev. */
> > > > >  	ret = mipi_csis_subdev_init(csis);
> > > > > diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c
> > > > > index 933a5f39f9f4c9b43ca8d2a1819d0145981266e6..7ddc7ba06e3d4e007013821f67d783898a15461f 100644
> > > > > --- a/drivers/media/platform/nxp/imx7-media-csi.c
> > > > > +++ b/drivers/media/platform/nxp/imx7-media-csi.c
> > > > > @@ -2218,11 +2218,9 @@ static int imx7_csi_probe(struct platform_device *pdev)
> > > > >
> > > > >  	/* Acquire resources and install interrupt handler. */
> > > > >  	csi->mclk = devm_clk_get(&pdev->dev, "mclk");
> > > > > -	if (IS_ERR(csi->mclk)) {
> > > > > -		ret = PTR_ERR(csi->mclk);
> > > > > -		dev_err(dev, "Failed to get mclk: %d", ret);
> > > > > -		return ret;
> > > > > -	}
> > > > > +	if (IS_ERR(csi->mclk))
> > > > > +		return dev_err_probe(dev, PTR_ERR(csi->mclk),
> > > > > +				     "Failed to get mclk\n");
> > > > >
> > > > >  	csi->irq = platform_get_irq(pdev, 0);
> > > > >  	if (csi->irq < 0)
> > > > > @@ -2236,10 +2234,8 @@ static int imx7_csi_probe(struct platform_device *pdev)
> > > > >
> > > > >  	ret = devm_request_irq(dev, csi->irq, imx7_csi_irq_handler, 0, "csi",
> > > > >  			       (void *)csi);
> > > > > -	if (ret < 0) {
> > > > > -		dev_err(dev, "Request CSI IRQ failed.\n");
> > > > > -		return ret;
> > > > > -	}
> > > > > +	if (ret < 0)
> > > > > +		return dev_err_probe(dev, ret, "Request CSI IRQ failed.\n");
> > > > >
> > > > >  	/* Initialize all the media device infrastructure. */
> > > > >  	ret = imx7_csi_media_init(csi);
> > > > > diff --git a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
> > > > > index 0851f4a9ae52d3096f454da643cfdc5017e000b1..a007c582b4d91660a97910a6a0d53c9b6fcd73e9 100644
> > > > > --- a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
> > > > > +++ b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
> > > > > @@ -951,10 +951,9 @@ static int imx8mq_mipi_csi_parse_dt(struct csi_state *state)
> > > > >  	int ret = 0;
> > > > >
> > > > >  	state->rst = devm_reset_control_array_get_exclusive(dev);
> > > > > -	if (IS_ERR(state->rst)) {
> > > > > -		dev_err(dev, "Failed to get reset: %pe\n", state->rst);
> > > > > -		return PTR_ERR(state->rst);
> > > > > -	}
> > > > > +	if (IS_ERR(state->rst))
> > > > > +		return dev_err_probe(dev, PTR_ERR(state->rst),
> > > > > +				     "Failed to get reset\n");
> > > > >
> > > > >  	if (state->pdata->use_reg_csr) {
> > > > >  		const struct regmap_config regmap_config = {
> > > > > @@ -977,24 +976,22 @@ static int imx8mq_mipi_csi_parse_dt(struct csi_state *state)
> > > > >
> > > > >  	ret = of_property_read_u32_array(np, "fsl,mipi-phy-gpr", out_val,
> > > > >  					 ARRAY_SIZE(out_val));
> > > > > -	if (ret) {
> > > > > -		dev_err(dev, "no fsl,mipi-phy-gpr property found: %d\n", ret);
> > > > > -		return ret;
> > > > > -	}
> > > > > +	if (ret)
> > > > > +		return dev_err_probe(dev, ret, "no %s property found\n",
> > > > > +				    "fsl,mipi-phy-gpr");
> > > >
> > > > Do you really need to pass the (fixed) property name as an argument? Why
> > > > not move into the const string directly? I would also rephrase it a bit:
> > > > "property fsl,mipi-phy-gpr not found"
> > >
> > > Laurent Pinchart provide comments at previous version. The same
> > > "fsl,mipi-phy-gpr" share one entry at RO region. slice save RO region
> > > space.
> > >
> > > https://lore.kernel.org/imx/20251119043307.GH17526 at pendragon.ideasonboard.com/
> >
> > "assuming it's worth it". Do you have any numbers? I doubt there is a
> > significant benefit, but I don't have strong opinion here.
> 
> Yes, only few byte. But no worth to argue this. Laurent Pinchart, who pick
> patches.

Agreed.

> 
> > But the grammar should still be improved.
> 
> Okay, will update it.

Thanks

Best regards
Alexander
-- 
TQ-Systems GmbH | M?hlstra?e 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht M?nchen, HRB 105018
Gesch?ftsf?hrer: Detlef Schneider, R?diger Stahl, Stefan Schneider
http://www.tq-group.com/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251216/1ea686fb/attachment.sig>

From krzk at kernel.org  Tue Dec 16 07:52:08 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 16 Dec 2025 16:52:08 +0100
Subject: [PATCH v3 6/7] dt-bindings: pinctrl: rockchip: Add RMIO
 controller binding
In-Reply-To: <20251216112053.1927852-7-ye.zhang@rock-chips.com>
References: <20251216112053.1927852-1-ye.zhang@rock-chips.com>
 <20251216112053.1927852-7-ye.zhang@rock-chips.com>
Message-ID: <5154ca76-0f23-4b52-8e6d-07005c52ac6d@kernel.org>

On 16/12/2025 12:20, Ye Zhang wrote:
> 1. Add header file with constants for RMIO function IDs for the Rockchip
> RK3506 SoC.
> 2. Add device tree binding for the RMIO (Rockchip Matrix I/O) controller
> which is a sub-device of the main pinctrl on some Rockchip SoCs.
> 
> Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
> ---
>  .../bindings/pinctrl/rockchip,pinctrl.yaml    |   9 ++
>  .../bindings/pinctrl/rockchip,rmio.yaml       | 106 +++++++++++++++++
>  .../pinctrl/rockchip,rk3506-rmio.h            | 109 ++++++++++++++++++
>  3 files changed, 224 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml
>  create mode 100644 include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h
> 
> diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
> index 97960245676d..9a27eaf7942b 100644
> --- a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
> +++ b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
> @@ -82,6 +82,15 @@ required:
>    - rockchip,grf
>  
>  patternProperties:
> +  "rmio[0-9]*$":
> +    type: object
> +
> +    $ref: "/schemas/pinctrl/rockchip,rmio.yaml#"
> +
> +    description:
> +      The RMIO (Rockchip Matrix I/O) controller node which functions as a
> +      sub-device of the main pinctrl to handle flexible function routing.

No. Your child has no resources, so it's not proper hardware
representation. Don't use Linux driver model in the bindings.

That's a NAK. Don't send the same AGAIN without addressing comments like
you did here.

> +
>    "gpio@[0-9a-f]+$":
>      type: object
>  
> diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml b/Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml
> new file mode 100644
> index 000000000000..af0b34512fb9
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml
> @@ -0,0 +1,106 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/pinctrl/rockchip,rmio.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: RMIO (Rockchip Matrix I/O) Controller
> +
> +maintainers:
> +  - Heiko Stuebner <heiko at sntech.de>
> +
> +description: |
> +  The RMIO controller provides a flexible routing matrix that allows mapping
> +  various internal peripheral functions (UART, SPI, PWM, etc.) to specific
> +  physical pins. This block is typically a sub-block of the GRF
> +  (General Register Files) or PMU (Power Management Unit).
> +
> +properties:
> +  compatible:
> +    items:
> +      - enum:
> +          - rockchip,rk3506-rmio
> +      - const: rockchip,rmio

I don't see how pinctrl deserves generic compatible. I already commented
on this.


> +
> +  rockchip,rmio-grf:
> +    $ref: /schemas/types.yaml#/definitions/phandle
> +    description:
> +      The phandle of the syscon node (GRF or PMU) containing the RMIO registers.
> +      This property is required if the RMIO registers are located in a different
> +      syscon than the parent pinctrl node.

Why "if"? How this can be flexible?

Anyway, you did not address my previous comment at all.

NAK

> +
> +  rockchip,offset:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    description:
> +      The offset of the RMIO configuration registers within the GRF.

No, this belongs to the phandle.

Look how this is already described and do not come with other style.

> +
> +  rockchip,pins-num:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    description:
> +      The number of physical pins supported by this RMIO instance.
> +      Used for boundary checking and driver initialization.
> +
> +patternProperties:
> +  "^[a-z0-9-]+$":

No, use a prefix or suffix. See other pinctrl bindings.

> +    type: object
> +    description:
> +      Function node grouping multiple groups.
> +
> +    patternProperties:
> +      "^[a-z0-9-]+$":

Same ocmment

> +        type: object
> +        description:
> +          Group node containing the pinmux configuration.
> +
> +        properties:
> +          rockchip,rmio:
> +            $ref: /schemas/types.yaml#/definitions/uint32-matrix
> +            description:
> +              A list of pin-function pairs. The format is <pin_id function_id>.
> +            minItems: 1
> +            items:
> +              items:
> +                - description: RMIO Pin ID (0 to pins-num - 1)
> +                  minimum: 0
> +                  maximum: 31
> +                - description: Function ID
> +                  minimum: 0
> +                  maximum: 98
> +
> +        required:
> +          - rockchip,rmio

Why aren't you using standard pinctrl bindings?

> +
> +        additionalProperties: false
> +
> +    additionalProperties: false
> +
> +required:
> +  - compatible
> +  - rockchip,rmio-grf
> +  - rockchip,offset
> +  - rockchip,pins-num
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/pinctrl/rockchip,rk3506-rmio.h>
> +
> +    pinctrl: pinctrl {

What's this?

> +        rmio: rmio {
> +            compatible = "rockchip,rk3506-rmio", "rockchip,rmio";
> +            rockchip,rmio-grf = <&grf_pmu>;
> +            rockchip,offset = <0x80>;
> +            rockchip,pins-num = <32>;
> +
> +            rmio-uart {
> +                rmio_pin27_uart1_tx: rmio-pin27-uart1-tx {
> +                    rockchip,rmio = <27 RMIO_UART1_TX>;
> +                };
> +
> +                rmio_pin28_uart1_rx: rmio-pin28-uart1-rx {
> +                    rockchip,rmio = <28 RMIO_UART1_RX>;
> +                };
> +            };
> +        };
> +    };
> diff --git a/include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h b/include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h
> new file mode 100644
> index 000000000000..b129e9a8c287
> --- /dev/null
> +++ b/include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h
> @@ -0,0 +1,109 @@
> +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
> +/*
> + * Copyright (c) 2025 Rockchip Electronics Co., Ltd.
> + */
> +
> +#ifndef __DT_BINDINGS_PINCTRL_ROCKCHIP_RK3506_RMIO_H
> +#define __DT_BINDINGS_PINCTRL_ROCKCHIP_RK3506_RMIO_H
> +
> +/* RMIO function definition */
> +#define RMIO_UART1_TX			1
> +#define RMIO_UART1_RX			2
> +#define RMIO_UART2_TX			3
> +#define RMIO_UART2_RX			4
> +#define RMIO_UART3_TX			5
> +#define RMIO_UART3_RX			6
> +#define RMIO_UART3_CTSN			7
> +#define RMIO_UART3_RTSN			8
> +#define RMIO_UART4_TX			9
> +#define RMIO_UART4_RX			10
> +#define RMIO_UART4_CTSN			11
> +#define RMIO_UART4_RTSN			12
> +#define RMIO_MIPITE			13
> +#define RMIO_CLK_32K			14
> +#define RMIO_I2C0_SCL			15
> +#define RMIO_I2C0_SDA			16


I do not see how this is a binding. Please point me to the patch using
this in the driver.

Best regards,
Krzysztof


From Frank.li at nxp.com  Tue Dec 16 07:55:26 2025
From: Frank.li at nxp.com (Frank Li)
Date: Tue, 16 Dec 2025 10:55:26 -0500
Subject: [PATCH 0/8] dmaengine: Add new API to combine onfiguration and
 descriptor preparation
In-Reply-To: <aUF-C8iUCs-dYXGm@vaman>
References: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
 <aUFUX0e_h7RGAecz@vaman>
 <aUF2SX/6bV2lHtF0@lizhi-Precision-Tower-5810>
 <aUF-C8iUCs-dYXGm@vaman>
Message-ID: <aUGA7tmDYm1MhRXn@lizhi-Precision-Tower-5810>

On Tue, Dec 16, 2025 at 09:13:07PM +0530, Vinod Koul wrote:
> On 16-12-25, 10:10, Frank Li wrote:
> > On Tue, Dec 16, 2025 at 06:15:19PM +0530, Vinod Koul wrote:
> > > On 08-12-25, 12:09, Frank Li wrote:
> > >
> > > Spell check on subject please :-)
> > >
> > > > Previously, configuration and preparation required two separate calls. This
> > > > works well when configuration is done only once during initialization.
> > > >
> > > > However, in cases where the burst length or source/destination address must
> > > > be adjusted for each transfer, calling two functions is verbose.
> > > >
> > > > 	if (dmaengine_slave_config(chan, &sconf)) {
> > > > 		dev_err(dev, "DMA slave config fail\n");
> > > > 		return -EIO;
> > > > 	}
> > > >
> > > > 	tx = dmaengine_prep_slave_single(chan, dma_local, len, dir, flags);
> > > >
> > > > After new API added
> > > >
> > > > 	tx = dmaengine_prep_slave_single(chan, dma_local, len, dir, flags, &sconf);
> > >
> > > Nak, we cant change the API like this.
> >
> > Sorry, it is typo here. in patch
> > 	dmaengine_prep_slave_single_config(chan, dma_local, len, dir, flags, &sconf);
> >
> > > I agree that you can add a new way to call dmaengine_slave_config() and
> > > dmaengine_prep_slave_single() together.
> > > maybe dmaengine_prep_config_perip_single() (yes we can go away with slave, but
> > > cant drop it, as absence means something else entire).
> >
> > how about dmaengine_prep_peripheral_single() and dmaengine_prep_peripheral_sg()
> > to align recent added "dmaengine_prep_peripheral_dma_vec()"
>
> It doesnt imply config has been done, how does it differ from usual
> prep_ calls. I see confusions can be caused!

dmaengine_prep_peripheral_single(.., &sconf) and
dmaengine_prep_peripheral_sg(..., &sconf).

The above two funcitions have pass down &sconf.

The usual prep_ call have not sconf argument, which need depend on previous
config.

further, If passdown NULL for config, it means use previuos config.

>
> > I think "peripheral" also is reduntant. dmaengine_prep_single() and
> > dmaengine_prep_sg() should be enough because
>
> Then you are missing the basic premises of dmaengine that we have memcpy
> ops and peripheral dma ops (aka slave) Absence of peripheral always
> implies that it is memcpy

Okay, it is not big deal. is dmaengine_prep_dma_cyclic() exception? which
have not "peripheral" or "slave", but it is not for memcpy.

Frank
>
> > - dmaengine_prep_dma_cyclic() is actually work with prepiperial FIFO
> > - some prepierial FIFO work like memory, by use shared memory method, like
> > PCIe map windows.
> > - argument: config and dir already passdown information to indicate if it
> > is device preiperial. So needn't indicate at function name.
> > - maybe later extend to support mem to mem by config becuase adjust burst
> > size for difference alignment or difference bus fabric port to optimaze
> > performance.
> >
> > Frank
> >
> > >
> > > I would like to retain the dmaengine_prep_slave_single() as an API for
> > > users to call and invoke. There are users who configure channel once as
> > > well
> > >
> > > >
> > > > Additional, prevous two calls requires additional locking to ensure both
> > > > steps complete atomically.
> > > >
> > > >     mutex_lock()
> > > >     dmaengine_slave_config()
> > > >     dmaengine_prep_slave_single()
> > > >     mutex_unlock()
> > > >
> > > > after new API added, mutex lock can be moved. See patch
> > > >      nvmet: pci-epf: Use dmaengine_prep_slave_single_config() API
> > > >
> > > > Signed-off-by: Frank Li <Frank.Li at nxp.com>
> > > > ---
> > > > Frank Li (8):
> > > >       dmaengine: Add API to combine configuration and preparation (sg and single)
> > > >       PCI: endpoint: pci-epf-test: use new DMA API to simple code
> > > >       dmaengine: dw-edma: Use new .device_prep_slave_sg_config() callback
> > > >       dmaengine: dw-edma: Pass dma_slave_config to dw_edma_device_transfer()
> > > >       nvmet: pci-epf: Remove unnecessary dmaengine_terminate_sync() on each DMA transfer
> > > >       nvmet: pci-epf: Use dmaengine_prep_slave_single_config() API
> > > >       PCI: epf-mhi:Using new API dmaengine_prep_slave_single_config() to simple code.
> > > >       crypto: atmel: Use dmaengine_prep_slave_single_config() API
> > > >
> > > >  drivers/crypto/atmel-aes.c                    | 10 ++---
> > > >  drivers/dma/dw-edma/dw-edma-core.c            | 38 +++++++++++-----
> > > >  drivers/nvme/target/pci-epf.c                 | 21 +++------
> > > >  drivers/pci/endpoint/functions/pci-epf-mhi.c  | 52 +++++++---------------
> > > >  drivers/pci/endpoint/functions/pci-epf-test.c |  8 +---
> > > >  include/linux/dmaengine.h                     | 64 ++++++++++++++++++++++++---
> > > >  6 files changed, 111 insertions(+), 82 deletions(-)
> > > > ---
> > > > base-commit: bc04acf4aeca588496124a6cf54bfce3db327039
> > > > change-id: 20251204-dma_prep_config-654170d245a2
> > > >
> > > > Best regards,
> > > > --
> > > > Frank Li <Frank.Li at nxp.com>
> > >
> > > --
> > > ~Vinod
>
> --
> ~Vinod


From ben.horgan at arm.com  Tue Dec 16 07:56:53 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Tue, 16 Dec 2025 15:56:53 +0000
Subject: [RFC PATCH 16/38] arm_mpam: resctrl: Add support for 'MB'
 resource
In-Reply-To: <6d257a70-d27f-4741-8fa5-fa765fa10643@redhat.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-17-james.morse@arm.com>
 <6d257a70-d27f-4741-8fa5-fa765fa10643@redhat.com>
Message-ID: <934ac602-f467-4359-8505-de7879201b7a@arm.com>

Hi Gavin,

On 12/12/25 04:27, Gavin Shan wrote:
> Hi James and Ben,
> 
> On 12/6/25 7:58 AM, James Morse wrote:
>> resctrl supports 'MB', as a percentage throttling of traffic somewhere
>> after the L3. This is the control that mba_sc uses, so ideally the
>> class chosen should be as close as possible to the counters used for
>> mba_local.
>>
>> MB's percentage control should be backed either with the fixed point
>> fraction MBW_MAX. The bandwidth portion bitmaps is not used as its
>> tricky to pick which bits to use to avoid contention, and may be
>> possible to expose this as something other than a percentage in the
>> future.
>>
>> CC: Zeng Heng <zengheng4 at huawei.com>
>> Co-developed-by: Dave Martin <Dave.Martin at arm.com>
>> Signed-off-by: Dave Martin <Dave.Martin at arm.com>
>> Signed-off-by: James Morse <james.morse at arm.com>>
>> ---
>> ? drivers/resctrl/mpam_resctrl.c | 212 ++++++++++++++++++++++++++++++++-
>> ? 1 file changed, 211 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/
>> mpam_resctrl.c
>> index 55576d0caf12..b9f3f00d8cad 100644
>> --- a/drivers/resctrl/mpam_resctrl.c
>> +++ b/drivers/resctrl/mpam_resctrl.c
>> @@ -247,6 +247,33 @@ static bool cache_has_usable_cpor(struct
>> mpam_class *class)
>> ????? return (class->props.cpbm_wd <= 32);
>> ? }
>> ? +static bool mba_class_use_mbw_max(struct mpam_props *cprops)
>> +{
>> +??? return (mpam_has_feature(mpam_feat_mbw_max, cprops) &&
>> +??????? cprops->bwa_wd);
>> +}
>> +
>> +static bool class_has_usable_mba(struct mpam_props *cprops)
>> +{
>> +??? return mba_class_use_mbw_max(cprops);
>> +}
>> +
>> +/*
>> + * Calculate the worst-case percentage change from each implemented step
>> + * in the control.
>> + */
>> +static u32 get_mba_granularity(struct mpam_props *cprops)
>> +{
>> +??? if (!mba_class_use_mbw_max(cprops))
>> +??????? return 0;
>> +
>> +??? /*
>> +???? * bwa_wd is the number of bits implemented in the 0.xxx
>> +???? * fixed point fraction. 1 bit is 50%, 2 is 25% etc.
>> +???? */
>> +??? return DIV_ROUND_UP(MAX_MBA_BW, 1 << cprops->bwa_wd);
>> +}
>> +
>> ? /*
>> ?? * Each fixed-point hardware value architecturally represents a range
>> ?? * of values: the full range 0% - 100% is split contiguously into
>> @@ -287,6 +314,96 @@ static u16 percent_to_mbw_max(u8 pc, struct
>> mpam_props *cprops)
>> ????? return val;
>> ? }
>> ? +static u32 get_mba_min(struct mpam_props *cprops)
>> +{
>> +??? u32 val = 0;
>> +
>> +??? if (mba_class_use_mbw_max(cprops))
>> +??????? val = mbw_max_to_percent(val, cprops);
>> +??? else
>> +??????? WARN_ON_ONCE(1);
>> +
>> +??? return val;
>> +}
>> +
>> +/* Find the L3 cache that has affinity with this CPU */
>> +static int find_l3_equivalent_bitmask(int cpu, cpumask_var_t
>> tmp_cpumask)
>> +{
>> +??? u32 cache_id = get_cpu_cacheinfo_id(cpu, 3);
>> +
>> +??? lockdep_assert_cpus_held();
>> +
>> +??? return mpam_get_cpumask_from_cache_id(cache_id, 3, tmp_cpumask);
>> +}
>> +
>> +/*
>> + * topology_matches_l3() - Is the provided class the same shape as L3
>> + * @victim:??????? The class we'd like to pretend is L3.
>> + *
>> + * resctrl expects all the world's a Xeon, and all counters are on the
>> + * L3. We play fast and loose with this, mapping counters on other
>> + * classes - provided the CPU->domain mapping is the same kind of shape.
>> + *
>> + * Using cacheinfo directly would make this work even if resctrl can't
>> + * use the L3 - but cacheinfo can't tell us anything about offline CPUs.
>> + * Using the L3 resctrl domain list also depends on CPUs being online.
>> + * Using the mpam_class we picked for L3 so we can use its domain list
>> + * assumes that there are MPAM controls on the L3.
>> + * Instead, this path eventually uses the
>> mpam_get_cpumask_from_cache_id()
>> + * helper which can tell us about offline CPUs ... but getting the
>> cache_id
>> + * to start with relies on at least one CPU per L3 cache being online at
>> + * boot.
>> + *
>> + * Walk the victim component list and compare the affinity mask with the
>> + * corresponding L3. The topology matches if each victim:component's
>> affinity
>> + * mask is the same as the CPU's corresponding L3's. These lists/
>> masks are
>> + * computed from firmware tables so don't change at runtime.
>> + */
>> +static bool topology_matches_l3(struct mpam_class *victim)
>> +{
>> +??? int cpu, err;
>> +??? struct mpam_component *victim_iter;
>> +??? cpumask_var_t __free(free_cpumask_var) tmp_cpumask;
>> +
>> +??? if (!alloc_cpumask_var(&tmp_cpumask, GFP_KERNEL))
>> +??????? return false;
>> +
>> +??? guard(srcu)(&mpam_srcu);
>> +??? list_for_each_entry_srcu(victim_iter, &victim->components,
>> class_list,
>> +???????????????? srcu_read_lock_held(&mpam_srcu)) {
>> +??????? if (cpumask_empty(&victim_iter->affinity)) {
>> +??????????? pr_debug("class %u has CPU-less component %u - can't
>> match L3!\n",
>> +???????????????? victim->level, victim_iter->comp_id);
>> +??????????? return false;
>> +??????? }
>> +
>> +??????? cpu = cpumask_any(&victim_iter->affinity);
>> +??????? if (WARN_ON_ONCE(cpu >= nr_cpu_ids))
>> +??????????? return false;
>> +
>> +??????? cpumask_clear(tmp_cpumask);
>> +??????? err = find_l3_equivalent_bitmask(cpu, tmp_cpumask);
>> +??????? if (err) {
>> +??????????? pr_debug("Failed to find L3's equivalent component to
>> class %u component %u\n",
>> +???????????????? victim->level, victim_iter->comp_id);
>> +??????????? return false;
>> +??????? }
>> +
>> +??????? /* Any differing bits in the affinity mask? */
>> +??????? if (!cpumask_equal(tmp_cpumask, &victim_iter->affinity)) {
>> +??????????? pr_debug("class %u component %u has Mismatched CPU mask
>> with L3 equivalent\n"
>> +???????????????? "L3:%*pbl != victim:%*pbl\n",
>> +???????????????? victim->level, victim_iter->comp_id,
>> +???????????????? cpumask_pr_args(tmp_cpumask),
>> +???????????????? cpumask_pr_args(&victim_iter->affinity));
>> +
>> +??????????? return false;
>> +??????? }
>> +??? }
>> +
>> +??? return true;
>> +}
>> +
>> ? /* Test whether we can export MPAM_CLASS_CACHE:{2,3}? */
>> ? static void mpam_resctrl_pick_caches(void)
>> ? {
>> @@ -330,10 +447,63 @@ static void mpam_resctrl_pick_caches(void)
>> ????? }
>> ? }
>> ? +static void mpam_resctrl_pick_mba(void)
>> +{
>> +??? struct mpam_class *class, *candidate_class = NULL;
>> +??? struct mpam_resctrl_res *res;
>> +
>> +??? lockdep_assert_cpus_held();
>> +
>> +??? guard(srcu)(&mpam_srcu);
>> +??? list_for_each_entry_srcu(class, &mpam_classes, classes_list,
>> +???????????????? srcu_read_lock_held(&mpam_srcu)) {
>> +??????? struct mpam_props *cprops = &class->props;
>> +
>> +??????? if (class->level < 3) {
>> +??????????? pr_debug("class %u is before L3\n", class->level);
>> +??????????? continue;
>> +??????? }
>> +
>> +??????? if (!class_has_usable_mba(cprops)) {
>> +??????????? pr_debug("class %u has no bandwidth control\n",
>> +???????????????? class->level);
>> +??????????? continue;
>> +??????? }
>> +
>> +??????? if (!cpumask_equal(&class->affinity, cpu_possible_mask)) {
>> +??????????? pr_debug("class %u has missing CPUs\n", class->level);
>> +??????????? continue;
>> +??????? }
>> +
>> +??????? if (!topology_matches_l3(class)) {
>> +??????????? pr_debug("class %u topology doesn't match L3\n",
>> +???????????????? class->level);
>> +??????????? continue;
>> +??????? }
>> +
>> +??????? /*
>> +???????? * mba_sc reads the mbm_local counter, and waggles the MBA
>> +???????? * controls. mbm_local is implicitly part of the L3, pick a
>> +???????? * resource to be MBA that as close as possible to the L3.
>> +???????? */
>> +??????? if (!candidate_class || class->level < candidate_class->level)
>> +??????????? candidate_class = class;
>> +??? }
>> +
>> +??? if (candidate_class) {
>> +??????? pr_debug("selected class %u to back MBA\n",
>> +???????????? candidate_class->level);
>> +??????? res = &mpam_resctrl_controls[RDT_RESOURCE_MBA];
>> +??????? res->class = candidate_class;
>> +??????? exposed_alloc_capable = true;
>> +??? }
>> +}
>> +
>> ? static int mpam_resctrl_control_init(struct mpam_resctrl_res *res,
>> ?????????????????????? enum resctrl_res_level type)
>> ? {
>> ????? struct mpam_class *class = res->class;
>> +??? struct mpam_props *cprops = &class->props;
>> ????? struct rdt_resource *r = &res->resctrl_res;
>> ? ????? switch (res->resctrl_res.rid) {
>> @@ -362,6 +532,20 @@ static int mpam_resctrl_control_init(struct
>> mpam_resctrl_res *res,
>> ?????????? * 'all the bits' is the correct answer here.
>> ?????????? */
>> ????????? r->cache.shareable_bits = resctrl_get_default_ctrl(r);
>> +??????? break;
>> +??? case RDT_RESOURCE_MBA:
>> +??????? r->alloc_capable = true;
>> +??????? r->schema_fmt = RESCTRL_SCHEMA_RANGE;
>> +??????? r->ctrl_scope = RESCTRL_L3_CACHE;
>> +
>> +??????? r->membw.delay_linear = true;
>> +??????? r->membw.throttle_mode = THREAD_THROTTLE_UNDEFINED;
>> +??????? r->membw.min_bw = get_mba_min(cprops);
>> +??????? r->membw.max_bw = MAX_MBA_BW;
>> +??????? r->membw.bw_gran = get_mba_granularity(cprops);
>> +
>> +??????? r->name = "MB";
>> +
>> ????????? break;
>> ????? default:
>> ????????? break;
>> @@ -377,7 +561,17 @@ static int mpam_resctrl_pick_domain_id(int cpu,
>> struct mpam_component *comp)
>> ????? if (class->type == MPAM_CLASS_CACHE)
>> ????????? return comp->comp_id;
>> ? -??? /* TODO: repaint domain ids to match the L3 domain ids */
>> +??? if (topology_matches_l3(class)) {
>> +??????? /* Use the corresponding L3 component ID as the domain ID */
>> +??????? int id = get_cpu_cacheinfo_id(cpu, 3);
>> +
>> +??????? /* Implies topology_matches_l3() made a mistake */
>> +??????? if (WARN_ON_ONCE(id == -1))
>> +??????????? return comp->comp_id;
>> +
>> +??????? return id;
>> +??? }
>> +
>> ????? /*
>> ?????? * Otherwise, expose the ID used by the firmware table code.
>> ?????? */
>> @@ -419,6 +613,12 @@ u32 resctrl_arch_get_config(struct rdt_resource
>> *r, struct rdt_ctrl_domain *d,
>> ????? case RDT_RESOURCE_L3:
>> ????????? configured_by = mpam_feat_cpor_part;
>> ????????? break;
>> +??? case RDT_RESOURCE_MBA:
>> +??????? if (mpam_has_feature(mpam_feat_mbw_max, cprops)) {
>> +??????????? configured_by = mpam_feat_mbw_max;
>> +??????????? break;
>> +??????? }
>> +??????? fallthrough;
>> ????? default:
>> ????????? return resctrl_get_default_ctrl(r);
>> ????? }
>> @@ -430,6 +630,8 @@ u32 resctrl_arch_get_config(struct rdt_resource
>> *r, struct rdt_ctrl_domain *d,
>> ????? switch (configured_by) {
>> ????? case mpam_feat_cpor_part:
>> ????????? return cfg->cpbm;
>> +??? case mpam_feat_mbw_max:
>> +??????? return mbw_max_to_percent(cfg->mbw_max, cprops);
>> ????? default:
>> ????????? return resctrl_get_default_ctrl(r);
>> ????? }
>> @@ -474,6 +676,13 @@ int resctrl_arch_update_one(struct rdt_resource
>> *r, struct rdt_ctrl_domain *d,
>> ????????? cfg.cpbm = cfg_val;
>> ????????? mpam_set_feature(mpam_feat_cpor_part, &cfg);
>> ????????? break;
>> +??? case RDT_RESOURCE_MBA:
>> +??????? if (mpam_has_feature(mpam_feat_mbw_max, cprops)) {
>> +??????????? cfg.mbw_max = percent_to_mbw_max(cfg_val, cprops);
>> +??????????? mpam_set_feature(mpam_feat_mbw_max, &cfg);
>> +??????????? break;
>> +??????? }
>> +??????? fallthrough;
> 
> I think mpam_feat_mbw_min peroperly need to be cleared in '&cfg', whose
> content
> is copied from that of the component. mpam_feat_mbw_min may have been
> existing
> in '&cfg' and struct mpam_config::mbw_min won't be updated correctly in the
> subsequent call mpam_extend_config(). It means register MPAMCFG_MBW_MIN
> isn't
> updated correctly.

Thanks for the report. The suggested fix makes sense too. I'll fix this
in the later patch where mbw_min is introduced.

> 
> On NVidia's grace-hopper machine, I got:
> 
> host$ mount none -tresctrl /sys/fs/resctrl/
> host$ mkdir -p /sys/fs/resctrl/all
> host$ mkdir -p /sys/fs/resctrl/test
> host$ cat /proc/dump_feat_regs
> MPAMF_IDR???????? 0000008057010027
> MAPMF_MBW_IDR???? 00000c07
> 
> host$ echo "MB:1=98" > /sys/fs/resctrl/test/schemata
> host$ cat /proc/dump_cfg_regs
> MPAMCFG_PART_SEL? 00000002
> MPAMCFG_MBW_MAX?? 0000f9ff
> MPAMCFG_MBW_MIN?? 0000f000
> 
> host$ echo "MB:1=2" > /sys/fs/resctrl/test/schemata
> host$ cat /proc/dump_cfg_regs
> MPAMCFG_PART_SEL? 00000002
> MPAMCFG_MBW_MAX?? 000005ff
> MPAMCFG_MBW_MIN?? 0000f000
> 
> With 'mpam_clear_feature(mpam_feat_mbw_min, &cfg);' applied here, the
> register
> can be updated correctly. It also makes my (soft) MBW limiting tests happy.
> 
> host$ echo "MB:1=98" > /sys/fs/resctrl/test/schemata
> host$ cat /proc/dump_cfg_regs
> MPAMCFG_PART_SEL? 00000002
> MPAMCFG_MBW_MAX?? 0000f9ff
> MPAMCFG_MBW_MIN?? 0000ea00
> 
> host$ echo "MB:1=2" > /sys/fs/resctrl/test/schemata
> host$ cat /proc/dump_cfg_regs
> MPAMCFG_PART_SEL? 00000002
> MPAMCFG_MBW_MAX?? 000005ff
> MPAMCFG_MBW_MIN?? 00000200
> 
> 
> Thanks,
> Gavin
> 
>> ????? default:
>> ????????? return -EINVAL;
>> ????? }
>> @@ -743,6 +952,7 @@ int mpam_resctrl_setup(void)
>> ? ????? /* Find some classes to use for controls */
>> ????? mpam_resctrl_pick_caches();
>> +??? mpam_resctrl_pick_mba();
>> ? ????? /* Initialise the resctrl structures from the classes */
>> ????? for (i = 0; i < RDT_NUM_RESOURCES; i++) {
> 

Thanks,

Ben



From james.clark at linaro.org  Tue Dec 16 08:08:21 2025
From: james.clark at linaro.org (James Clark)
Date: Tue, 16 Dec 2025 18:08:21 +0200
Subject: [PATCH 16/19] coresight: trbe: Support trigger mode
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-16-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-16-7da32b076b28@arm.com>
Message-ID: <0b381f5b-66a4-4407-9b91-18ecc28b3695@linaro.org>



On 01/12/2025 13:22, Leo Yan wrote:
> The buffer currently operates in fill mode, where tracing stops when it
> reaches the end of the buffer and a maintenance interrupt is raised.
> However, due to IRQ latency, trace data may be lost during the window in
> which tracing is halted but the program continues to run.
> 
> To mitigate the issue, this commit enables the trigger count to support
> buffer maintenance without disabling tracing.  This is fulfilled with
> two modes:
> 
> 1) Set a trigger count as a watermark and use fill mode to prevent the
>     buffer from being overwritten.  Once the count is decremented to
>     zero, an interrupt is raised for buffer maintenance, but the hardware
>     continues collecting trace data until limit.
> 
>            head            watermark tail
>       +----+---------------+---------+-------+
>       |$$$$|               |         |$$$$$$$|
>       +----+---------------+---------+-------+
>       base `---- count ----'         limit   base + nr_pages
> 
>       $$$ : Filled trace data
> 
> 2) Use wrap mode so that tracing continues when reach the top of the
>     buffer.  The trigger count is configured as "Stop on trigger" to
>     guard the trace data not to be overwritten.
> 
>                watermark   tail      head
>       +--------+-----------+---------+-------+
>       |        |           |$$$$$$$$$|       |
>       +--------+-----------+---------+-------+

I think some of the existing comments and diagrams need to be updated 
for wrap mode. For example this one isn't true anymore:

   neither an wrap around nor an IRQ is expected while being enabled.

It's quite hard to make sense of the comments in __trbe_normal_offset() 
because they don't even mention the new mode of operation because they 
were written before it. But when reading them they appear to describe 
definitively how the buffer works.

Also these diagrams in the commit message are inconsistent with the 
existing ones that use #### for free instead of blank. Personally I 
prefer blank for free as I don't have to keep going back to the legend 
to see which one is free. Same for the kunit tests.

>       base                                   base + nr_pages
>                                              limit
> 
>                                      `------->
>       >-- counter ---------'
> 
>       $$$ : Filled trace data
> 
> The modes are selected by comparing the limit with the trigger position.
> 
> An extra TRBE_FAULT_ACT_TRIG state is introduced for fault action, it is
> used to distinguish the trigger event from the WRAP event.
> 
> Signed-off-by: Leo Yan <leo.yan at arm.com>
> ---
>   drivers/hwtracing/coresight/coresight-trbe.c | 101 +++++++++++++++++++++------
>   drivers/hwtracing/coresight/coresight-trbe.h |  14 ++++
>   2 files changed, 94 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
> index 8390d0a8fe23d35945610df15f21751279ee37ee..0551ea9b4f8286c156e3c9c7ac94e2ecd3b9dc3f 100644
> --- a/drivers/hwtracing/coresight/coresight-trbe.c
> +++ b/drivers/hwtracing/coresight/coresight-trbe.c
> @@ -48,6 +48,7 @@
>   #define TRBE_TRACE_MIN_BUF_SIZE		64
>   
>   enum trbe_fault_action {
> +	TRBE_FAULT_ACT_TRIG,
>   	TRBE_FAULT_ACT_WRAP,
>   	TRBE_FAULT_ACT_SPURIOUS,
>   	TRBE_FAULT_ACT_FATAL,
> @@ -67,6 +68,7 @@ struct trbe_buf {
>   	unsigned long trbe_hw_base;
>   	unsigned long trbe_limit;
>   	unsigned long trbe_write;
> +	unsigned long trbe_count;
>   	int nr_pages;
>   	void **pages;
>   	bool snapshot;
> @@ -478,6 +480,10 @@ static unsigned long __trbe_normal_offset(struct perf_output_handle *handle)
>   	if (head < tail)
>   		limit = round_down(tail, PAGE_SIZE);
>   
> +	/* If trigger mode is enabled, no need to use limit for watermark */
> +	if (!static_branch_unlikely(&trbe_trigger_mode_bypass))
> +		goto out;
> +
>   	/*
>   	 * Wakeup may be arbitrarily far into the future. If it's not in the
>   	 * current generation, either we'll wrap before hitting it, or it's
> @@ -495,6 +501,7 @@ static unsigned long __trbe_normal_offset(struct perf_output_handle *handle)
>   	if (handle->wakeup < (handle->head + handle->size) && head <= wakeup)
>   		limit = min(limit, round_up(wakeup, PAGE_SIZE));
>   
> +out:
>   	/*
>   	 * There is a situation when this can happen i.e limit is before
>   	 * the head and hence TRBE cannot be configured.
> @@ -518,6 +525,39 @@ static unsigned long __trbe_normal_offset(struct perf_output_handle *handle)
>   	return 0;
>   }
>   
> +static u64 __trbe_normal_trigger_count(struct perf_output_handle *handle)
> +{
> +	struct trbe_buf *buf = etm_perf_sink_config(handle);
> +	struct trbe_cpudata *cpudata = buf->cpudata;
> +	u64 limit, head, wakeup;
> +	u64 count = 0;
> +
> +	if (static_branch_unlikely(&trbe_trigger_mode_bypass))
> +		return 0;
> +
> +	limit = buf->trbe_limit - buf->trbe_base;
> +	head = PERF_IDX2OFF(handle->head, buf);
> +	wakeup = PERF_IDX2OFF(handle->wakeup, buf);
> +
> +	/* Set the count to guard the end of free buffer after wrap around */
> +	if (limit == buf->nr_pages * PAGE_SIZE && (head + handle->size) > limit)
> +		count = handle->size;
> +
> +	/*
> +	 * If the watermark is less than the limit, use the trigger count for
> +	 * the watermark maintenance.
> +	 */
> +	if (handle->wakeup < (handle->head + handle->size) && head <= wakeup) {
> +		u64 wakeup_count =
> +			round_up(wakeup - head, cpudata->trbe_hw_align);
> +
> +		if (head + wakeup_count < limit)
> +			count = wakeup_count;
> +	}
> +
> +	return count;
> +}
> +
>   static int trbe_normal_offset(struct perf_output_handle *handle)
>   {
>   	struct trbe_buf *buf = etm_perf_sink_config(handle);
> @@ -542,6 +582,7 @@ static int trbe_normal_offset(struct perf_output_handle *handle)
>   		return -ENOSPC;
>   
>   	buf->trbe_limit = buf->trbe_base + limit;
> +	buf->trbe_count = __trbe_normal_trigger_count(handle);
>   	return 0;
>   }
>   
> @@ -594,24 +635,40 @@ static void set_trbe_limit_pointer_enabled(struct trbe_buf *buf)
>   	trblimitr &= ~TRBLIMITR_EL1_TM_MASK;
>   	trblimitr &= ~TRBLIMITR_EL1_LIMIT_MASK;
>   
> -	/*
> -	 * Fill trace buffer mode is used here while configuring the
> -	 * TRBE for trace capture. In this particular mode, the trace
> -	 * collection is stopped and a maintenance interrupt is raised
> -	 * when the current write pointer wraps. This pause in trace
> -	 * collection gives the software an opportunity to capture the
> -	 * trace data in the interrupt handler, before reconfiguring
> -	 * the TRBE.
> -	 */
> -	trblimitr |= (TRBLIMITR_EL1_FM_FILL << TRBLIMITR_EL1_FM_SHIFT) &
> -		     TRBLIMITR_EL1_FM_MASK;
> +	if (!buf->trbe_count ||
> +	    buf->trbe_write + buf->trbe_count == buf->trbe_limit) {
> +		/*
> +		 * Fill trace buffer mode is used here while configuring the
> +		 * TRBE for trace capture. In this particular mode, the trace
> +		 * collection is stopped and a maintenance interrupt is raised
> +		 * when the current write pointer wraps. This pause in trace
> +		 * collection gives the software an opportunity to capture the
> +		 * trace data in the interrupt handler, before reconfiguring
> +		 * the TRBE.
> +		 */
> +		trblimitr |= FIELD_PREP(TRBLIMITR_EL1_FM_MASK, TRBLIMITR_EL1_FM_FILL) |
> +			     FIELD_PREP(TRBLIMITR_EL1_TM_MASK, TRBLIMITR_EL1_TM_IGNR);

I thought there were only two modes required: Wrap with trigger stop or 
Fill with trigger IRQ. What's this first one for? Is this to support the 
errata cases where the trigger counter isn't used?

> +	} else if (buf->trbe_write + buf->trbe_count < buf->trbe_limit) {
> +		/*
> +		 * Fill mode is used here to stop trace collection and prevent
> +		 * the buffer from being overwritten. Trigger mode continues
> +		 * trace collection and raises a maintenance interrupt on a
> +		 * trigger event, which acts as a watermark for notifying
> +		 * userspace.
> +		 */
> +		trblimitr |= FIELD_PREP(TRBLIMITR_EL1_FM_MASK, TRBLIMITR_EL1_FM_FILL) |
> +			     FIELD_PREP(TRBLIMITR_EL1_TM_MASK, TRBLIMITR_EL1_TM_IRQ);
> +	} else if (buf->trbe_write + buf->trbe_count > buf->trbe_limit) {
> +		/*
> +		 * Wrap buffer mode continues trace collection and raises
> +		 * maintenance interrupt on buffer wrap. Trigger mode stops
> +		 * trace on trigger event to guard the buffer from being
> +		 * overwritten.
> +		 */
> +		trblimitr |= FIELD_PREP(TRBLIMITR_EL1_FM_MASK, TRBLIMITR_EL1_FM_WRAP) |
> +			     FIELD_PREP(TRBLIMITR_EL1_TM_MASK, TRBLIMITR_EL1_TM_STOP);
> +	}

Can you document what the case is for a final else here, even if there's 
no code? Or should it even be a WARN()?

>   
> -	/*
> -	 * Trigger mode is not used here while configuring the TRBE for
> -	 * the trace capture. Hence just keep this in the ignore mode.
> -	 */
> -	trblimitr |= (TRBLIMITR_EL1_TM_IGNR << TRBLIMITR_EL1_TM_SHIFT) &
> -		     TRBLIMITR_EL1_TM_MASK;
>   	trblimitr |= (addr & PAGE_MASK);
>   	set_trbe_enabled(buf->cpudata, trblimitr);
>   }
> @@ -623,6 +680,7 @@ static void trbe_enable_hw(struct trbe_buf *buf)
>   	WARN_ON(buf->trbe_write >= buf->trbe_limit);
>   	set_trbe_base_pointer(buf->trbe_hw_base);
>   	set_trbe_write_pointer(buf->trbe_write);
> +	set_trbe_trigger_count(buf->trbe_count);
>   
>   	/*
>   	 * Synchronize all the register updates
> @@ -639,8 +697,6 @@ static enum trbe_fault_action trbe_get_fault_act(struct perf_output_handle *hand
>   	int ec = get_trbe_ec(trbsr);
>   	int bsc = get_trbe_bsc(trbsr);
>   
> -	WARN_ON(is_trbe_running(trbsr));
> -
>   	if (is_trbe_abort(trbsr)) {
>   		err_str = "External abort";
>   		goto out_fatal;
> @@ -672,8 +728,7 @@ static enum trbe_fault_action trbe_get_fault_act(struct perf_output_handle *hand
>   	case TRBE_BSC_FILLED:
>   		break;
>   	case TRBE_BSC_TRIGGERED:
> -		err_str = "Unexpected trigger status";
> -		goto out_fatal;
> +		break;
>   	default:
>   		err_str = "Unexpected buffer status code";
>   		goto out_fatal;
> @@ -692,6 +747,9 @@ static enum trbe_fault_action trbe_get_fault_act(struct perf_output_handle *hand
>   	if (is_trbe_wrap(trbsr))
>   		return TRBE_FAULT_ACT_WRAP;
>   
> +	if (is_trbe_trg(trbsr))
> +		return TRBE_FAULT_ACT_TRIG;
> +
>   	return TRBE_FAULT_ACT_SPURIOUS;
>   
>   out_fatal:
> @@ -1180,6 +1238,7 @@ static irqreturn_t arm_trbe_irq_handler(int irq, void *dev)
>   		clr_trbe_status();
>   
>   	switch (act) {
> +	case TRBE_FAULT_ACT_TRIG:
>   	case TRBE_FAULT_ACT_WRAP:
>   		truncated = !!trbe_handle_overflow(handle, act);
>   		break;
> diff --git a/drivers/hwtracing/coresight/coresight-trbe.h b/drivers/hwtracing/coresight/coresight-trbe.h
> index d7f7cd763c0c7139cf322b7336ee563073e3bea0..4c65d164a946ec9860825e7564196745b60d730b 100644
> --- a/drivers/hwtracing/coresight/coresight-trbe.h
> +++ b/drivers/hwtracing/coresight/coresight-trbe.h
> @@ -114,6 +114,20 @@ static inline void set_trbe_write_pointer(unsigned long addr)
>   	write_sysreg_s(addr, SYS_TRBPTR_EL1);
>   }
>   
> +static inline void set_trbe_trigger_count(unsigned long count)
> +{
> +	u64 trbsr;
> +
> +	write_sysreg_s(count, SYS_TRBTRG_EL1);
> +
> +	/* TRBSR_EL1.TRG has been cleared in clr_trbe_status() */
> +	if (!count)
> +		return;
> +
> +	trbsr = read_sysreg_s(SYS_TRBSR_EL1);
> +	write_sysreg_s(trbsr | TRBSR_EL1_TRG, SYS_TRBSR_EL1);
> +}
> +
>   static inline unsigned long get_trbe_limit_pointer(void)
>   {
>   	u64 trblimitr = read_sysreg_s(SYS_TRBLIMITR_EL1);
> 



From james.clark at linaro.org  Tue Dec 16 08:27:27 2025
From: james.clark at linaro.org (James Clark)
Date: Tue, 16 Dec 2025 18:27:27 +0200
Subject: [PATCH 16/19] coresight: trbe: Support trigger mode
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-16-7da32b076b28@arm.com>
References: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>
 <20251201-trbe_buffer_refactor_v1-1-v1-16-7da32b076b28@arm.com>
Message-ID: <c8fad013-b022-4037-94e8-1f0536535469@linaro.org>



On 01/12/2025 13:22, Leo Yan wrote:
> The buffer currently operates in fill mode, where tracing stops when it
> reaches the end of the buffer and a maintenance interrupt is raised.
> However, due to IRQ latency, trace data may be lost during the window in
> which tracing is halted but the program continues to run.
> 
> To mitigate the issue, this commit enables the trigger count to support
> buffer maintenance without disabling tracing.  This is fulfilled with
> two modes:
> 
> 1) Set a trigger count as a watermark and use fill mode to prevent the
>     buffer from being overwritten.  Once the count is decremented to
>     zero, an interrupt is raised for buffer maintenance, but the hardware
>     continues collecting trace data until limit.
> 
>            head            watermark tail
>       +----+---------------+---------+-------+
>       |$$$$|               |         |$$$$$$$|
>       +----+---------------+---------+-------+
>       base `---- count ----'         limit   base + nr_pages
> 
>       $$$ : Filled trace data
> 
> 2) Use wrap mode so that tracing continues when reach the top of the
>     buffer.  The trigger count is configured as "Stop on trigger" to
>     guard the trace data not to be overwritten.
> 
>                watermark   tail      head
>       +--------+-----------+---------+-------+
>       |        |           |$$$$$$$$$|       |
>       +--------+-----------+---------+-------+
>       base                                   base + nr_pages
>                                              limit
> 
>                                      `------->
>       >-- counter ---------'
> 
>       $$$ : Filled trace data
> 
> The modes are selected by comparing the limit with the trigger position.
> 
> An extra TRBE_FAULT_ACT_TRIG state is introduced for fault action, it is
> used to distinguish the trigger event from the WRAP event.
> 
> Signed-off-by: Leo Yan <leo.yan at arm.com>
> ---
>   drivers/hwtracing/coresight/coresight-trbe.c | 101 +++++++++++++++++++++------
>   drivers/hwtracing/coresight/coresight-trbe.h |  14 ++++
>   2 files changed, 94 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
> index 8390d0a8fe23d35945610df15f21751279ee37ee..0551ea9b4f8286c156e3c9c7ac94e2ecd3b9dc3f 100644
> --- a/drivers/hwtracing/coresight/coresight-trbe.c
> +++ b/drivers/hwtracing/coresight/coresight-trbe.c
> @@ -48,6 +48,7 @@
>   #define TRBE_TRACE_MIN_BUF_SIZE		64
>   
>   enum trbe_fault_action {
> +	TRBE_FAULT_ACT_TRIG,
>   	TRBE_FAULT_ACT_WRAP,
>   	TRBE_FAULT_ACT_SPURIOUS,
>   	TRBE_FAULT_ACT_FATAL,
> @@ -67,6 +68,7 @@ struct trbe_buf {
>   	unsigned long trbe_hw_base;
>   	unsigned long trbe_limit;
>   	unsigned long trbe_write;
> +	unsigned long trbe_count;
>   	int nr_pages;
>   	void **pages;
>   	bool snapshot;
> @@ -478,6 +480,10 @@ static unsigned long __trbe_normal_offset(struct perf_output_handle *handle)
>   	if (head < tail)
>   		limit = round_down(tail, PAGE_SIZE);
>   
> +	/* If trigger mode is enabled, no need to use limit for watermark */
> +	if (!static_branch_unlikely(&trbe_trigger_mode_bypass))
> +		goto out;
> +
>   	/*
>   	 * Wakeup may be arbitrarily far into the future. If it's not in the
>   	 * current generation, either we'll wrap before hitting it, or it's
> @@ -495,6 +501,7 @@ static unsigned long __trbe_normal_offset(struct perf_output_handle *handle)
>   	if (handle->wakeup < (handle->head + handle->size) && head <= wakeup)
>   		limit = min(limit, round_up(wakeup, PAGE_SIZE));

I kept wondering how this limit was relvant now in wrap mode. But I see 
it's skipped from the goto above, but that only jumps over one 
statement. Can we have that static branch as a regular if statement 
guarding the limit calculation instead of the goto?

Negating "trigger_mode_bypass" and renaming it into just "trigger_mode" 
might help too. The double negative of "not trigger_trigger_mode_bypass 
goto" is a bit hard to understand.

>   
> +out:
>   	/*
>


From lkp at intel.com  Tue Dec 16 08:31:27 2025
From: lkp at intel.com (kernel test robot)
Date: Wed, 17 Dec 2025 00:31:27 +0800
Subject: [PATCH v2 3/3] randomize_kstack: Unify random source across
 arches
In-Reply-To: <20251215163520.1144179-4-ryan.roberts@arm.com>
References: <20251215163520.1144179-4-ryan.roberts@arm.com>
Message-ID: <202512170038.vJZdUhEN-lkp@intel.com>

Hi Ryan,

kernel test robot noticed the following build errors:

[auto build test ERROR on tip/sched/core]
[also build test ERROR on akpm-mm/mm-everything linus/master v6.19-rc1 next-20251216]
[cannot apply to kees/for-next/hardening kees/for-next/execve]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Ryan-Roberts/prandom-Convert-prandom_u32_state-to-__always_inline/20251216-013546
base:   tip/sched/core
patch link:    https://lore.kernel.org/r/20251215163520.1144179-4-ryan.roberts%40arm.com
patch subject: [PATCH v2 3/3] randomize_kstack: Unify random source across arches
config: x86_64-rhel-9.4-ltp (https://download.01.org/0day-ci/archive/20251217/202512170038.vJZdUhEN-lkp at intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251217/202512170038.vJZdUhEN-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512170038.vJZdUhEN-lkp at intel.com/

All error/warnings (new ones prefixed by >>):

>> arch/x86/boot/startup/sev-startup.o: warning: objtool: section .discard.addressable has absolute relocation at offset 0x0
--
   In file included from include/linux/device/driver.h:21,
                    from include/linux/device.h:32,
                    from include/linux/blk_types.h:11,
                    from include/linux/writeback.h:13,
                    from include/linux/memcontrol.h:23,
                    from include/linux/resume_user_mode.h:8,
                    from include/linux/entry-virt.h:6,
                    from include/linux/kvm_host.h:5,
                    from arch/x86/kvm/svm/svm.c:3:
>> include/linux/module.h:132:49: error: redefinition of '__inittest'
     132 |         static inline initcall_t __maybe_unused __inittest(void)                \
         |                                                 ^~~~~~~~~~
   arch/x86/kvm/svm/svm.c:5509:1: note: in expansion of macro 'module_init'
    5509 | module_init(svm_init)
         | ^~~~~~~~~~~
   include/linux/module.h:132:49: note: previous definition of '__inittest' with type 'int (*(void))(void)'
     132 |         static inline initcall_t __maybe_unused __inittest(void)                \
         |                                                 ^~~~~~~~~~
   include/linux/module.h:125:41: note: in expansion of macro 'module_init'
     125 | #define late_initcall(fn)               module_init(fn)
         |                                         ^~~~~~~~~~~
   include/linux/randomize_kstack.h:86:1: note: in expansion of macro 'late_initcall'
      86 | late_initcall(random_kstack_init);
         | ^~~~~~~~~~~~~
>> include/linux/module.h:134:13: error: redefinition of 'init_module'
     134 |         int init_module(void) __copy(initfn)                    \
         |             ^~~~~~~~~~~
   arch/x86/kvm/svm/svm.c:5509:1: note: in expansion of macro 'module_init'
    5509 | module_init(svm_init)
         | ^~~~~~~~~~~
   include/linux/module.h:134:13: note: previous definition of 'init_module' with type 'int(void)'
     134 |         int init_module(void) __copy(initfn)                    \
         |             ^~~~~~~~~~~
   include/linux/module.h:125:41: note: in expansion of macro 'module_init'
     125 | #define late_initcall(fn)               module_init(fn)
         |                                         ^~~~~~~~~~~
   include/linux/randomize_kstack.h:86:1: note: in expansion of macro 'late_initcall'
      86 | late_initcall(random_kstack_init);
         | ^~~~~~~~~~~~~
--
   ld: arch/x86/kvm/vmx/main.o: in function `vt_init':
>> arch/x86/kvm/vmx/main.c:1038: multiple definition of `init_module'; arch/x86/kvm/vmx/vmx.o:include/linux/randomize_kstack.h:81: first defined here
--
   In file included from drivers/misc/sgi-xp/xpc_main.c:47:
>> include/linux/module.h:132:49: error: redefinition of '__inittest'
     132 |         static inline initcall_t __maybe_unused __inittest(void)                \
         |                                                 ^~~~~~~~~~
   drivers/misc/sgi-xp/xpc_main.c:1285:1: note: in expansion of macro 'module_init'
    1285 | module_init(xpc_init);
         | ^~~~~~~~~~~
   include/linux/module.h:132:49: note: previous definition of '__inittest' with type 'int (*(void))(void)'
     132 |         static inline initcall_t __maybe_unused __inittest(void)                \
         |                                                 ^~~~~~~~~~
   include/linux/module.h:125:41: note: in expansion of macro 'module_init'
     125 | #define late_initcall(fn)               module_init(fn)
         |                                         ^~~~~~~~~~~
   include/linux/randomize_kstack.h:86:1: note: in expansion of macro 'late_initcall'
      86 | late_initcall(random_kstack_init);
         | ^~~~~~~~~~~~~
>> include/linux/module.h:134:13: error: redefinition of 'init_module'
     134 |         int init_module(void) __copy(initfn)                    \
         |             ^~~~~~~~~~~
   drivers/misc/sgi-xp/xpc_main.c:1285:1: note: in expansion of macro 'module_init'
    1285 | module_init(xpc_init);
         | ^~~~~~~~~~~
   include/linux/module.h:134:13: note: previous definition of 'init_module' with type 'int(void)'
     134 |         int init_module(void) __copy(initfn)                    \
         |             ^~~~~~~~~~~
   include/linux/module.h:125:41: note: in expansion of macro 'module_init'
     125 | #define late_initcall(fn)               module_init(fn)
         |                                         ^~~~~~~~~~~
   include/linux/randomize_kstack.h:86:1: note: in expansion of macro 'late_initcall'
      86 | late_initcall(random_kstack_init);
         | ^~~~~~~~~~~~~


vim +1038 arch/x86/kvm/vmx/main.c

d6bee7813752b3 Kai Huang 2025-01-22  1036  
d6bee7813752b3 Kai Huang 2025-01-22  1037  static int __init vt_init(void)
d6bee7813752b3 Kai Huang 2025-01-22 @1038  {

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From robh at kernel.org  Tue Dec 16 08:38:54 2025
From: robh at kernel.org (Rob Herring)
Date: Tue, 16 Dec 2025 10:38:54 -0600
Subject: [PATCH] dt-bindings: usb: Add Socionext Uniphier DWC3 controller
In-Reply-To: <0775e913-e531-44b5-b191-7ce0cf4d1e3a@socionext.com>
References: <20251215212507.3317805-1-robh@kernel.org> <0775e913-e531-44b5-b191-7ce0cf4d1e3a@socionext.com>
Message-ID: <CAL_Jsq+sXky33rD1-DkLvWdNcUEBNAty8t2NzvHFx-2ZK1cCSQ@mail.gmail.com>

On Mon, Dec 15, 2025 at 7:22?PM Kunihiko Hayashi
<hayashi.kunihiko at socionext.com> wrote:
>
> Hi Rob,
>
> On 2025/12/16 6:25, Rob Herring (Arm) wrote:
> > The Socionext Uniphier DWC3 controller binding is already in use, but
> > undocumented. It's a straight-forward binding similar to other DWC3
> > bindings.
>
> After being pointed out by Krzysztof at OSSJapan, I've checked the bindings
> and was preparing some additions or fixes to resolve the warning.
>
> It's almost the same as my proposal, however, I add a little.
>
> >
> > Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> > ---
> >   .../bindings/usb/socionext,uniphier-dwc3.yaml | 89 +++++++++++++++++++
> >   1 file changed, 89 insertions(+)
> >   create mode 100644
> > Documentation/devicetree/bindings/usb/socionext,uniphier-dwc3.yaml
> >
> > diff --git
> > a/Documentation/devicetree/bindings/usb/socionext,uniphier-dwc3.yaml
> > b/Documentation/devicetree/bindings/usb/socionext,uniphier-dwc3.yaml
> > new file mode 100644
> > index 000000000000..892ae3458c1b
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/usb/socionext,uniphier-dwc3.yaml
> > @@ -0,0 +1,89 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/usb/socionext,uniphier-dwc3.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Socionext Uniphier SuperSpeed DWC3 USB SoC controller
> > +
> > +maintainers:
> > +  - Kunihiko Hayashi <hayashi.kunihiko at socionext.com>
> > +  - Masami Hiramatsu <mhiramat at kernel.org>
> > +
> > +select:
> > +  properties:
> > +    compatible:
> > +      contains:
> > +        const: socionext,uniphier-dwc3
> > +  required:
> > +    - compatible
> > +
> > +properties:
> > +  compatible:
> > +    items:
> > +      - const: socionext,uniphier-dwc3
> > +      - const: snps,dwc3
> > +
> > +  reg:
> > +    maxItems: 1
> > +
> > +  interrupts:
> > +    minItems: 1
> > +    items:
> > +      - description: Host or single combined interrupt
> > +      - description: Peripheral interrupt
> > +
> > +  interrupt-names:
> > +    minItems: 1
> > +    items:
> > +      - enum:
> > +          - dwc_usb3
> > +          - host
> > +      - const: peripheral
> There's no problem, but how about the following description
> following snps,dwc3.yaml?
>
>    interrupt-names:
>      oneOf:
>        - const: dwc_usb3
>        - items:
>            enum: [host, peripheral]

That allows for 'peripheral, host' or just 'peripheral'. Mine would
seemingly allow 'dwc_usb3, host', but snps,dwc3.yaml will prevent
that.

>
> > +
> > +  clocks:
> > +    maxItems: 3
> > +
> > +  clock-names:
> > +    items:
> > +      - const: ref
> > +      - const: bus_early
> > +      - const: suspend
> > +
> > +  phys:
> > +    description: 1 to 4 HighSpeed PHYs followed by 1 or 2 SuperSpeed PHYs
> > +    minItems: 2
> > +    maxItems: 6
>
> Since Pro4 only has one PHY, so:
>      minItems: 1

Ah, I only checked arm64. Will fix.

If there's other arm32 warnings, I'm not looking at those. So fixes
appreciated there.

Rob


From robh at kernel.org  Tue Dec 16 08:40:56 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Tue, 16 Dec 2025 10:40:56 -0600
Subject: [PATCH] dt-bindings: arm,vexpress-juno: Allow interrupt-map
 properties in bus node
In-Reply-To: <20251215212932.3324144-1-robh@kernel.org>
References: <20251215212932.3324144-1-robh@kernel.org>
Message-ID: <176590325593.2606466.6619016689348303654.robh@kernel.org>


On Mon, 15 Dec 2025 15:29:32 -0600, Rob Herring (Arm) wrote:
> Allow interrupt-map properties which are already used in the bus node.
> 
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> ---
>  .../devicetree/bindings/arm/arm,vexpress-juno.yaml          | 6 ++++++
>  1 file changed, 6 insertions(+)
> 

Applied, thanks!



From robh at kernel.org  Tue Dec 16 08:41:09 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Tue, 16 Dec 2025 10:41:09 -0600
Subject: [PATCH] dt-bindings: arm: vexpress-config: Update clock and
 regulator node names
In-Reply-To: <20251215212914.3323741-1-robh@kernel.org>
References: <20251215212914.3323741-1-robh@kernel.org>
Message-ID: <176590326845.2606868.3243744984088093789.robh@kernel.org>


On Mon, 15 Dec 2025 15:29:14 -0600, Rob Herring (Arm) wrote:
> The clock and regulator node names were updated to use standard node names,
> but the binding wasn't updated.
> 
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> ---
>  Documentation/devicetree/bindings/arm/vexpress-config.yaml | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 

Applied, thanks!



From robh at kernel.org  Tue Dec 16 08:41:25 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Tue, 16 Dec 2025 10:41:25 -0600
Subject: [PATCH] dt-bindings: bus: stm32mp25-rifsc: Allow 2 size cells
In-Reply-To: <20251215212700.3320634-1-robh@kernel.org>
References: <20251215212700.3320634-1-robh@kernel.org>
Message-ID: <176590328507.2607309.18218209388270739835.robh@kernel.org>


On Mon, 15 Dec 2025 15:26:59 -0600, Rob Herring (Arm) wrote:
> There are users already with 2 size cells, and there's no reason to not
> support that.
> 
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> ---
>  Documentation/devicetree/bindings/bus/st,stm32mp25-rifsc.yaml | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 

Applied, thanks!



From broonie at kernel.org  Tue Dec 16 08:46:33 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 16 Dec 2025 16:46:33 +0000
Subject: (subset) [PATCH 0/3] spi: st: add power-domains on stm32mp2x
In-Reply-To: <20251215-stm32-spi-mp2x-dt-updates-v1-0-464a5fd20f13@foss.st.com>
References: <20251215-stm32-spi-mp2x-dt-updates-v1-0-464a5fd20f13@foss.st.com>
Message-ID: <176590359301.183097.12758319202580831902.b4-ty@kernel.org>

On Mon, 15 Dec 2025 13:26:19 +0100, Alain Volmat wrote:
> This series add the possibility to indicate a power-domains for an spi
> instance and set the related property for all spi instances on
> stm32mp2x.
> 
> 

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next

Thanks!

[1/3] dt-bindings: spi: st,stm32-spi: add 'power-domains' property
      commit: f4acea9eef704607d1a950909ce3a52a770d6be2

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark



From vkoul at kernel.org  Tue Dec 16 08:53:18 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 16 Dec 2025 22:23:18 +0530
Subject: [PATCH 3/6] dmaengine: qcom: Remove redundant
 pm_runtime_mark_last_busy() calls
In-Reply-To: <20251027133232.392898-3-sakari.ailus@linux.intel.com>
References: <20251027133232.392898-1-sakari.ailus@linux.intel.com>
 <20251027133232.392898-3-sakari.ailus@linux.intel.com>
Message-ID: <aUGOfs7gI__Q-bua@vaman>

On 27-10-25, 15:32, Sakari Ailus wrote:
> pm_runtime_put_autosuspend(), pm_runtime_put_sync_autosuspend(),
> pm_runtime_autosuspend() and pm_request_autosuspend() now include a call
> to pm_runtime_mark_last_busy(). Remove the now-reduntant explicit call to
> pm_runtime_mark_last_busy().

This one fails for me. I have picked the rest. Can you please rebase
this one

-- 
~Vinod


From yeoreum.yun at arm.com  Tue Dec 16 08:52:13 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Tue, 16 Dec 2025 16:52:13 +0000
Subject: [PATCH 0/2] introduce pagetable_alloc_nolock()
In-Reply-To: <916c17ba-22b1-456e-a184-cb3f60249af7@arm.com>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com>
 <916c17ba-22b1-456e-a184-cb3f60249af7@arm.com>
Message-ID: <aUGOPd7gNRf1xHEc@e129823.arm.com>

Hi Ryan,

> On 12/12/2025 16:18, Yeoreum Yun wrote:
> > Some architectures invoke pagetable_alloc() or __get_free_pages()
> > with preemption disabled.
> > For example, in arm64, linear_map_split_to_ptes() calls pagetable_alloc()
> > while spliting block entry to ptes and __kpti_install_ng_mappings()
> > calls __get_free_pages() to create kpti pagetable.
> >
> > Under PREEMPT_RT, calling pagetable_alloc() with
> > preemption disabled is not allowed, because it may acquire
> > a spin lock that becomes sleepable on RT, potentially
> > causing a sleep during page allocation.
> >
> > Since above two functions is called as callback of stop_machine()
> > where its callback is called in preemption disabled,
> > They could make a potential problem. (sleeping in preemption disabled).
> >
> > To address this, introduce pagetable_alloc_nolock() API.
>
> I don't really understand what the problem is that you're trying to fix. As I
> see it, there are 2 call sites in arm64 arch code that are calling into the page
> allocator from stop_machine() - one via via pagetable_alloc() and another via
> __get_free_pages(). But both of those calls are passing in GFP_ATOMIC. It was my
> understanding that the page allocator would ensure it never sleeps when
> GFP_ATOMIC is passed in, (even for PREEMPT_RT)?

Although GFP_ATOMIC is specify, it only affects of "water mark" of the
page with __GFP_HIGH. and to get a page, it must grab the lock --
zone->lock or pcp_lock in the rmqueue().

This zone->lock and pcp_lock is spin_lock and it's a sleepable in
PREEMPT_RT that's why the memory allocation/free using general API
except nolock() version couldn't be called since
if "contention" happens they'll sleep while waiting to get the lock.

The reason why "nolock()" can use, it always uses "trylock" with
ALLOC_TRYLOCK flags. otherwise GFP_ATOMIC also can be sleepable in
PREEMPT_RT.

>
> What is the actual symptom you are seeing?

Since the place where called while smp_cpus_done() and there seems no
contention, there seems no problem. However as I mention in another
thread
(https://lore.kernel.org/all/aT%2FdrjN1BkvyAGoi at e129823.arm.com/),
This gives a the false impression --
GFP_ATOMIC are ?safe to use in preemption disabled?
even though they are not in PREEMPT_RT case, I've changed it.

>
> If the page allocator is somehow ignoring the GFP_ATOMIC request for PREEMPT_RT,
> then isn't that a bug in the page allocator? I'm not sure why you would change
> the callsites? Can't you just change the page allocator based on GFP_ATOMIC?

It doesn't ignore the GFP_ATOMIC feature:
  - __GFP_HIGH: use water mark till min reserved
  - __GFP_KSWAPD_RECLAIM: wake up kswapd if reclaim required.

But, it's a restriction -- "page allocation / free" API cannot be called
in preempt-disabled context at PREEMPT_RT.

That's why I think it's wrong usage not a page allocator bug.

[...]

--
Sincerely,
Yeoreum Yun


From vkoul at kernel.org  Tue Dec 16 08:56:26 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 16 Dec 2025 22:26:26 +0530
Subject: [PATCH RESEND] dmaengine: xilinx_dma: Fix uninitialized
 addr_width when "xlnx,addrwidth" property is missing
In-Reply-To: <20251021183006.3434495-1-suraj.gupta2@amd.com>
References: <20251021183006.3434495-1-suraj.gupta2@amd.com>
Message-ID: <176590418615.422798.3456929870875820677.b4-ty@kernel.org>


On Wed, 22 Oct 2025 00:00:06 +0530, Suraj Gupta wrote:
> When device tree lacks optional "xlnx,addrwidth" property, the addr_width
> variable remained uninitialized with garbage values, causing incorrect
> DMA mask configuration and subsequent probe failure. The fix ensures a
> fallback to the default 32-bit address width when this property is missing.
> 
> 

Applied, thanks!

[1/1] dmaengine: xilinx_dma: Fix uninitialized addr_width when "xlnx,addrwidth" property is missing
      commit: c0732fe78728718c853ef8e7af5bbb05262acbd1

Best regards,
-- 
~Vinod




From ben.horgan at arm.com  Tue Dec 16 08:58:32 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Tue, 16 Dec 2025 16:58:32 +0000
Subject: [RFC PATCH 24/38] arm_mpam: resctrl: Allow resctrl to allocate
 monitors
In-Reply-To: <20251205215901.17772-25-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-25-james.morse@arm.com>
Message-ID: <ffc80ae1-cbed-438e-af19-25006fbf4545@arm.com>

Hi James,

On 12/5/25 21:58, James Morse wrote:
> When resctrl wants to read a domain's 'QOS_L3_OCCUP', it needs
> to allocate a monitor on the corresponding resource. Monitors are
> allocated by class instead of component.
> 
> MBM monitors are much more complicated, if there are enough monitors,
> they will be pre-allocated and free-running. If ABMC is in use instead
> then 'some' are pre-allocated in a different way, and need assigning.
> 
> Add helpers to allocate a CSU monitor. These helper return an out
> of range value for MBM counters.
> 
> Allocating a montitor context is expected to block until hardware
> resources become available. This only makes sense for QOS_L3_OCCUP
> as unallocated MBM counters are losing data.
> 
> Signed-off-by: James Morse <james.morse at arm.com>
> ---
> Since ABMC got merged it may be possible to remove the monitor alloc
> call for MBM counters from resctrl as this work is now done by ABMC's
> assign call.
> ---
>  drivers/resctrl/mpam_internal.h | 14 ++++++-
>  drivers/resctrl/mpam_resctrl.c  | 68 +++++++++++++++++++++++++++++++++
>  include/linux/arm_mpam.h        |  4 ++
>  3 files changed, 85 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
> index 05101186af17..3a68ebd498fa 100644
> --- a/drivers/resctrl/mpam_internal.h
> +++ b/drivers/resctrl/mpam_internal.h
> @@ -32,6 +32,14 @@ DECLARE_STATIC_KEY_FALSE(mpam_enabled);
>  #define PACKED_FOR_KUNIT
>  #endif
>  
> +/*
> + * This 'mon' values must not alias an actual monitor, so must be larger than
> + * U16_MAX, but not be confused with an errno value, so smaller than
> + * (u32)-SZ_4K.
> + * USE_PRE_ALLOCATED is used to avoid confusion with an actual monitor.
> + */
> +#define USE_PRE_ALLOCATED      (U16_MAX + 1)
> +
>  static inline bool mpam_is_enabled(void)
>  {
>  	return static_branch_likely(&mpam_enabled);
> @@ -215,7 +223,11 @@ enum mon_filter_options {
>  };
>  
>  struct mon_cfg {
> -	u16			mon;
> +	/*
> +	 * mon must be large enough to hold out of range values like
> +	 * USE_RMID_IDX
> +	 */

USE_RMID_IDX -> USE_PRE_ALLOCATED

Thanks,

Ben



From vkoul at kernel.org  Tue Dec 16 08:59:35 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 16 Dec 2025 22:29:35 +0530
Subject: [PATCH v2 0/4] dmaengine: stm32-dma3: improvements and helper
 functions
In-Reply-To: <20251121-dma3_improv-v2-0-76a207b13ea6@foss.st.com>
References: <20251121-dma3_improv-v2-0-76a207b13ea6@foss.st.com>
Message-ID: <176590437579.430148.12860558109000484739.b4-ty@kernel.org>


On Fri, 21 Nov 2025 14:36:55 +0100, Amelie Delaunay wrote:
> This series introduces improvements and helper functions for channel
> and driver management.
> 
> It enables proper unloading of the stm32_dma3 module, replacing the
> previous subsys_initcall() mechanism with module_plaform_driver().
> 
> It introduces helper functions to take and release the channel semaphore,
> and restores the semaphore state on resume, considering the possible
> reset of CxSEMCR register during suspend.
> 
> [...]

Applied, thanks!

[1/4] dmaengine: stm32-dma3: use module_platform_driver
      commit: 0d41ed4ea496fabbb4dc21171e32d9a924c2a661
[2/4] dmaengine: stm32-dma3: introduce channel semaphore helpers
      commit: d26eb4a75a4a2bbf27305e62ad82cedf5f8c577c
[3/4] dmaengine: stm32-dma3: restore channel semaphore status after suspend
      commit: dea737e31c2c62df5a45871bfb4ceb90a112dbd8
[4/4] dmaengine: stm32-dma3: introduce ddata2dev helper
      commit: 8be4f3cbe263d22053d7afea4efee2e7178eee21

Best regards,
-- 
~Vinod




From vkoul at kernel.org  Tue Dec 16 08:59:40 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 16 Dec 2025 22:29:40 +0530
Subject: [PATCH 1/6] dmaengine: at_xdmac: Remove redundant
 pm_runtime_mark_last_busy() calls
In-Reply-To: <20251027133232.392898-1-sakari.ailus@linux.intel.com>
References: <20251027133232.392898-1-sakari.ailus@linux.intel.com>
Message-ID: <176590438034.430148.2613882199706918410.b4-ty@kernel.org>


On Mon, 27 Oct 2025 15:32:27 +0200, Sakari Ailus wrote:
> pm_runtime_put_autosuspend(), pm_runtime_put_sync_autosuspend(),
> pm_runtime_autosuspend() and pm_request_autosuspend() now include a call
> to pm_runtime_mark_last_busy(). Remove the now-reduntant explicit call to
> pm_runtime_mark_last_busy().
> 
> 

Applied, thanks!

[1/6] dmaengine: at_xdmac: Remove redundant pm_runtime_mark_last_busy() calls
      commit: bce33c132a2061c9a7958474c3e2d030c22664de
[2/6] dmaengine: pl330: Remove redundant pm_runtime_mark_last_busy() calls
      commit: 5f6f0cad6d2d599b765d572216a290e48bfdcb5f
[3/6] dmaengine: qcom: Remove redundant pm_runtime_mark_last_busy() calls
      (no commit info)
[4/6] dmaengine: ste_dma40: Remove redundant pm_runtime_mark_last_busy() calls
      commit: 01f2bcf06d7e0e3c4badd03c030cf634ca10a172
[5/6] dmaengine: ti: Remove redundant pm_runtime_mark_last_busy() calls
      commit: 35d522a9612f5ba83192416521725acede02c28f
[6/6] dmaengine: zynqmp_dma: Remove redundant pm_runtime_mark_last_busy() calls
      commit: 3b81235280026c551660c6374ede9599fc82f617

Best regards,
-- 
~Vinod




From robh at kernel.org  Tue Dec 16 09:15:05 2025
From: robh at kernel.org (Rob Herring)
Date: Tue, 16 Dec 2025 11:15:05 -0600
Subject: [PATCH] dt-bindings: Remove unused includes
In-Reply-To: <695ca5d2-b713-4838-8427-a9d31751c0cf@oss.qualcomm.com>
References: <20251212231203.727227-1-robh@kernel.org>
 <20251213165949.4b51f7cb@jic23-huawei>
 <695ca5d2-b713-4838-8427-a9d31751c0cf@oss.qualcomm.com>
Message-ID: <20251216171505.GA2641341-robh@kernel.org>

On Tue, Dec 16, 2025 at 01:02:52PM +0100, Konrad Dybcio wrote:
> On 12/13/25 5:59 PM, Jonathan Cameron wrote:
> > On Fri, 12 Dec 2025 17:11:52 -0600
> > "Rob Herring (Arm)" <robh at kernel.org> wrote:
> > 
> >> Remove includes which are not referenced by either DTS files or drivers.
> >>
> >> There's a few more which are new, so they are excluded for now.
> >>
> >> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> > 
> > Acked-by: Jonathan Cameron <jonathan.cameron at huawei.com> #for-iio
> > 
> > Ideally we'll get a QC ack on those as well.
> > 
> > Jonathan
> >>  .../dt-bindings/iio/qcom,spmi-adc7-pmr735b.h  |  30 --
> >>  .../dt-bindings/iio/qcom,spmi-adc7-smb139x.h  |  19 --
> 
> Those are being moved to dts/qcom:
> 
> https://lore.kernel.org/linux-arm-msm/20251127133903.208760-1-jishnu.prakash at oss.qualcomm.com/
> 
> and will hopefully be in use later in this cycle.
> 
> Krzysztof and the submitter agreed on that outcome since they represent
> hw constants and aren't "real" bindings (connecting sw to sw)

Okay, I'll drop those 2 when applying.

Rob


From vkoul at kernel.org  Tue Dec 16 09:17:57 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 16 Dec 2025 22:47:57 +0530
Subject: [PATCH 0/8] dmaengine: Add new API to combine onfiguration and
 descriptor preparation
In-Reply-To: <aUGA7tmDYm1MhRXn@lizhi-Precision-Tower-5810>
References: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
 <aUFUX0e_h7RGAecz@vaman>
 <aUF2SX/6bV2lHtF0@lizhi-Precision-Tower-5810>
 <aUF-C8iUCs-dYXGm@vaman>
 <aUGA7tmDYm1MhRXn@lizhi-Precision-Tower-5810>
Message-ID: <aUGURVuW33WSTuyI@vaman>

On 16-12-25, 10:55, Frank Li wrote:
> On Tue, Dec 16, 2025 at 09:13:07PM +0530, Vinod Koul wrote:
> > On 16-12-25, 10:10, Frank Li wrote:
> > > On Tue, Dec 16, 2025 at 06:15:19PM +0530, Vinod Koul wrote:
> > > > On 08-12-25, 12:09, Frank Li wrote:
> > > >
> > > > Spell check on subject please :-)
> > > >
> > > > > Previously, configuration and preparation required two separate calls. This
> > > > > works well when configuration is done only once during initialization.
> > > > >
> > > > > However, in cases where the burst length or source/destination address must
> > > > > be adjusted for each transfer, calling two functions is verbose.
> > > > >
> > > > > 	if (dmaengine_slave_config(chan, &sconf)) {
> > > > > 		dev_err(dev, "DMA slave config fail\n");
> > > > > 		return -EIO;
> > > > > 	}
> > > > >
> > > > > 	tx = dmaengine_prep_slave_single(chan, dma_local, len, dir, flags);
> > > > >
> > > > > After new API added
> > > > >
> > > > > 	tx = dmaengine_prep_slave_single(chan, dma_local, len, dir, flags, &sconf);
> > > >
> > > > Nak, we cant change the API like this.
> > >
> > > Sorry, it is typo here. in patch
> > > 	dmaengine_prep_slave_single_config(chan, dma_local, len, dir, flags, &sconf);
> > >
> > > > I agree that you can add a new way to call dmaengine_slave_config() and
> > > > dmaengine_prep_slave_single() together.
> > > > maybe dmaengine_prep_config_perip_single() (yes we can go away with slave, but
> > > > cant drop it, as absence means something else entire).
> > >
> > > how about dmaengine_prep_peripheral_single() and dmaengine_prep_peripheral_sg()
> > > to align recent added "dmaengine_prep_peripheral_dma_vec()"
> >
> > It doesnt imply config has been done, how does it differ from usual
> > prep_ calls. I see confusions can be caused!
> 
> dmaengine_prep_peripheral_single(.., &sconf) and
> dmaengine_prep_peripheral_sg(..., &sconf).
> 
> The above two funcitions have pass down &sconf.
> 
> The usual prep_ call have not sconf argument, which need depend on previous
> config.
> 
> further, If passdown NULL for config, it means use previuos config.

I know it is bit longer but somehow I would feel better for the API to
imply config as well please

> 
> >
> > > I think "peripheral" also is reduntant. dmaengine_prep_single() and
> > > dmaengine_prep_sg() should be enough because
> >
> > Then you are missing the basic premises of dmaengine that we have memcpy
> > ops and peripheral dma ops (aka slave) Absence of peripheral always
> > implies that it is memcpy
> 
> Okay, it is not big deal. is dmaengine_prep_dma_cyclic() exception? which
> have not "peripheral" or "slave", but it is not for memcpy.

Cyclic by definition implies a cyclic dma over a peripheral

-- 
~Vinod


From Frank.li at nxp.com  Tue Dec 16 09:28:21 2025
From: Frank.li at nxp.com (Frank Li)
Date: Tue, 16 Dec 2025 12:28:21 -0500
Subject: [PATCH 0/8] dmaengine: Add new API to combine onfiguration and
 descriptor preparation
In-Reply-To: <aUGURVuW33WSTuyI@vaman>
References: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
 <aUFUX0e_h7RGAecz@vaman>
 <aUF2SX/6bV2lHtF0@lizhi-Precision-Tower-5810>
 <aUF-C8iUCs-dYXGm@vaman>
 <aUGA7tmDYm1MhRXn@lizhi-Precision-Tower-5810>
 <aUGURVuW33WSTuyI@vaman>
Message-ID: <aUGWtarjFNNy2KyZ@lizhi-Precision-Tower-5810>

On Tue, Dec 16, 2025 at 10:47:57PM +0530, Vinod Koul wrote:
> On 16-12-25, 10:55, Frank Li wrote:
> > On Tue, Dec 16, 2025 at 09:13:07PM +0530, Vinod Koul wrote:
> > > On 16-12-25, 10:10, Frank Li wrote:
> > > > On Tue, Dec 16, 2025 at 06:15:19PM +0530, Vinod Koul wrote:
> > > > > On 08-12-25, 12:09, Frank Li wrote:
> > > > >
> > > > > Spell check on subject please :-)
> > > > >
> > > > > > Previously, configuration and preparation required two separate calls. This
> > > > > > works well when configuration is done only once during initialization.
> > > > > >
> > > > > > However, in cases where the burst length or source/destination address must
> > > > > > be adjusted for each transfer, calling two functions is verbose.
> > > > > >
> > > > > > 	if (dmaengine_slave_config(chan, &sconf)) {
> > > > > > 		dev_err(dev, "DMA slave config fail\n");
> > > > > > 		return -EIO;
> > > > > > 	}
> > > > > >
> > > > > > 	tx = dmaengine_prep_slave_single(chan, dma_local, len, dir, flags);
> > > > > >
> > > > > > After new API added
> > > > > >
> > > > > > 	tx = dmaengine_prep_slave_single(chan, dma_local, len, dir, flags, &sconf);
> > > > >
> > > > > Nak, we cant change the API like this.
> > > >
> > > > Sorry, it is typo here. in patch
> > > > 	dmaengine_prep_slave_single_config(chan, dma_local, len, dir, flags, &sconf);
> > > >
> > > > > I agree that you can add a new way to call dmaengine_slave_config() and
> > > > > dmaengine_prep_slave_single() together.
> > > > > maybe dmaengine_prep_config_perip_single() (yes we can go away with slave, but
> > > > > cant drop it, as absence means something else entire).
> > > >
> > > > how about dmaengine_prep_peripheral_single() and dmaengine_prep_peripheral_sg()
> > > > to align recent added "dmaengine_prep_peripheral_dma_vec()"
> > >
> > > It doesnt imply config has been done, how does it differ from usual
> > > prep_ calls. I see confusions can be caused!
> >
> > dmaengine_prep_peripheral_single(.., &sconf) and
> > dmaengine_prep_peripheral_sg(..., &sconf).
> >
> > The above two funcitions have pass down &sconf.
> >
> > The usual prep_ call have not sconf argument, which need depend on previous
> > config.
> >
> > further, If passdown NULL for config, it means use previuos config.
>
> I know it is bit longer but somehow I would feel better for the API to
> imply config as well please

I can use you suggested dmaengine_prep_config_perip_single().

But how about use dmaengine_prep_config_single(), which little bit shorter
and use "config" to imply it is for periperal? (similar to cyclic case?)

Frank

>
> >
> > >
> > > > I think "peripheral" also is reduntant. dmaengine_prep_single() and
> > > > dmaengine_prep_sg() should be enough because
> > >
> > > Then you are missing the basic premises of dmaengine that we have memcpy
> > > ops and peripheral dma ops (aka slave) Absence of peripheral always
> > > implies that it is memcpy
> >
> > Okay, it is not big deal. is dmaengine_prep_dma_cyclic() exception? which
> > have not "peripheral" or "slave", but it is not for memcpy.
>
> Cyclic by definition implies a cyclic dma over a peripheral
>
> --
> ~Vinod


From jonathan.cameron at huawei.com  Tue Dec 16 09:53:09 2025
From: jonathan.cameron at huawei.com (Jonathan Cameron)
Date: Tue, 16 Dec 2025 17:53:09 +0000
Subject: [PATCH v1 01/13] arm64: mm: Re-implement the __tlbi_level macro
 as a C function
In-Reply-To: <20251216144601.2106412-2-ryan.roberts@arm.com>
References: <20251216144601.2106412-1-ryan.roberts@arm.com>
	<20251216144601.2106412-2-ryan.roberts@arm.com>
Message-ID: <20251216175309.00001935@huawei.com>

On Tue, 16 Dec 2025 14:45:46 +0000
Ryan Roberts <ryan.roberts at arm.com> wrote:

> As part of efforts to reduce our reliance on complex preprocessor macros
> for TLB invalidation routines, convert the __tlbi_level macro to a C
> function for by-level TLB invalidation.
> 
> Each specific tlbi level op is implemented as a C function and the
> appropriate function pointer is passed to __tlbi_level(). Since
> everything is declared inline and is statically resolvable, the compiler
> will convert the indirect function call to a direct inline execution.
> 
> Suggested-by: Linus Torvalds <torvalds at linux-foundation.org>
> Signed-off-by: Ryan Roberts <ryan.roberts at arm.com>
> ---

> +static __always_inline void __tlbi_level(tlbi_op op, u64 addr, u32 level)
> +{
> +	u64 arg = addr;
> +
> +	if (alternative_has_cap_unlikely(ARM64_HAS_ARMv8_4_TTL) && level <= 3) {
> +		u64 ttl = level | (get_trans_granule() << 2);
> +
> +		arg &= ~TLBI_TTL_MASK;
> +		arg |= FIELD_PREP(TLBI_TTL_MASK, ttl);

Probably don't care, but I think you could do
		FIELD_MODIFY(TLBI_TTL_MASK, &arg, ttl);
instead of those two lines. Code generation hopefully similar?
So depends on which macros you find more readable.

> +	}
> +
> +	op(arg);
> +}
>  
>  #define __tlbi_user_level(op, arg, level) do {				\
>  	if (arm64_kernel_unmapped_at_el0())				\



From luca.ceresoli at bootlin.com  Tue Dec 16 09:58:33 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Tue, 16 Dec 2025 18:58:33 +0100
Subject: [PATCH v3 00/22] drm/bridge: add of_drm_find_and_get_bridge() and
 a managed *next_bridge, deprecate of_drm_find_bridge()
Message-ID: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>

This series deprecates of_drm_find_bridge(), adds a replacement which
handles bridge refcounting, and converts some of the direct users.

This is part of the work to support hotplug of DRM bridges. The grand plan
was discussed in [0].

Here's the work breakdown (? marks the current series):

 1. ? add refcounting to DRM bridges struct drm_bridge,
      based on devm_drm_bridge_alloc()
    A. ? add new alloc API and refcounting (v6.16)
    B. ? convert all bridge drivers to new API (v6.17)
    C. ? kunit tests (v6.17)
    D. ? add get/put to drm_bridge_add/remove() + attach/detach()
         and warn on old allocation pattern (v6.17)
    E. ? add get/put on drm_bridge accessors
       1. ? drm_bridge_chain_get_first_bridge(), add cleanup action (v6.18)
       2. ? drm_bridge_get_prev_bridge() (v6.18)
       3. ? drm_bridge_get_next_bridge() (v6.19)
       4. ? drm_for_each_bridge_in_chain() (v6.19)
       5. ? drm_bridge_connector_init (v6.19)
       6. ? protect encoder bridge chain with a mutex
       7. ? of_drm_find_bridge()
          a. ? add of_drm_find_and_get_bridge(), convert some direct users
	  b. convert other direct users
	  c. convert bridge-only drm_of_find_panel_or_bridge() users
       8. drm_of_find_panel_or_bridge, *_of_get_bridge
       9. ? enforce drm_bridge_add before drm_bridge_attach (v6.19)
    F. ? debugfs improvements
       1. ? add top-level 'bridges' file (v6.16)
       2. ? show refcount and list lingering bridges (v6.19)
 2. ? handle gracefully atomic updates during bridge removal
    A. ? Add drm_dev_enter/exit() to protect device resources (v6.20?)
    B. ? protect private_obj removal from list
 3. ? DSI host-device driver interaction
 4. ? removing the need for the "always-disconnected" connector
 5. finish the hotplug bridge work, moving code to the core and potentially
    removing the hotplug-bridge itself (this needs to be clarified as
    points 1-3 are developed)

[0] https://lore.kernel.org/lkml/20250206-hotplug-drm-bridge-v6-0-9d6f2c9c3058 at bootlin.com/#t

Almost all the functions returning a struct drm_bridge pointer have been
modified to drm_bridge_get() the returned bridge, and their users updated
to drm_bridge_put() it. See items 1.E.{1-6} above.

of_drm_find_bridge() could be modified easily in the same way, but it has a
lot of (direct + indirect) callers, and most notably
drm_of_find_panel_or_bridge() which is very hard to adapt without reworking
the panel_bridge lifetime.

This has been discussed in [1] and Maxime proposed an incremental approach:

> So maybe we can just create drm_of_find_bridge() that takes a reference,
> make of_drm_find_bridge() deprecated in favour of drm_of_find_bridge(),
> add a TODO, and call it a day. People will gradually switch to the new
> API over time.

That proposal is implemented by this series with the various changes
discussed after the initial proposal. Some of the direct callers are also
converted: a few of the simple ones plus two complex cases. One of the
complex cases also shows how to use the .destroy func when the next_bridge
is not enough.

Follow-up series will:
- convert remaining direct callers of of_drm_find_bridge()
- convert simple cases of drm_of_find_panel_or_bridge()

[1] https://lore.kernel.org/dri-devel/20250319-stylish-lime-mongoose-0a18ad at houat/

Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
---
Changes in v3:
- Completely rewrote using the __drm_bridge_free() idea to prevent
  use-after-free of the next_bridge for the common cases
- Added needed cleanups to the imx8qxp-pixel-link and imx8qxp-pxl2dpi
  drivers
- Removed various patches converting simple cases, to reduce the number of
  e-mails sent; will be moved to the follow-up series
- Link to v2: https://lore.kernel.org/r/20251128-drm-bridge-alloc-getput-drm_of_find_bridge-v2-0-88f8a107eca2 at bootlin.com

Changes in v2:
- All patches: renamed drm_of_find_bridge() -> of_drm_get_bridge()
- Various fixes and improvements to patches 1-6, see individual patches
  changelog
- Removed bouncing recipient: Edmund Dea <edmund.j.dea at intel.com>
- Link to v1: https://lore.kernel.org/r/20251119-drm-bridge-alloc-getput-drm_of_find_bridge-v1-0-0db98a7fe474 at bootlin.com

---
Luca Ceresoli (22):
      drm/bridge: add of_drm_find_and_get_bridge()
      drm/bridge: deprecate of_drm_find_bridge()
      drm/todo: add entry about converting to of_drm_find_and_get_bridge()
      drm/bridge: make of_drm_find_bridge() a wrapper of of_drm_find_and_get_bridge()
      drm/arcpgu: convert to of_drm_find_and_get_bridge()
      drm/bridge: add next_bridge pointer to struct drm_bridge
      drm/bridge: ite-it66121: get/put the next bridge
      drm/bridge: imx8qxp-pixel-combiner: get/put the next bridge
      drm/bridge: simple-bridge: get/put the next bridge
      drm/meson: encoder_cvbs: get/put the next bridge
      drm/meson: encoder_dsi: get/put the next bridge
      drm/meson: encoder_hdmi: get/put the next bridge
      drm/bridge: imx8qxp-pxl2dpi: simplify put of device_node pointers
      drm/bridge: imx8qxp-pxl2dpi: remove excess error message
      drm/bridge: imx8qxp-pxl2dpi: imx8qxp_pxl2dpi_find_next_bridge: return int, not ERR_PTR
      drm/bridge: imx8qxp-pxl2dpi: get/put the next bridge
      drm/bridge: imx8qxp-pxl2dpi: get/put the companion bridge
      drm/bridge: imx8qxp-pixel-link: simplify logic to find next bridge
      drm/bridge: imx8qxp-pixel-link: simplify freeing of the remote device_node
      drm/bridge: imx8qxp-pixel-link: remove excess error message
      drm/bridge: imx8qxp-pixel-link: imx8qxp_pixel_link_find_next_bridge: return int, not ERR_PTR
      drm/bridge: imx8qxp-pixel-link: get/put the next bridge

 Documentation/gpu/todo.rst                         | 16 +++++
 .../gpu/drm/bridge/imx/imx8qxp-pixel-combiner.c    |  9 ++-
 drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c    | 56 ++++++++----------
 drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c       | 63 ++++++++------------
 drivers/gpu/drm/bridge/ite-it66121.c               |  7 +--
 drivers/gpu/drm/bridge/simple-bridge.c             | 15 +++--
 drivers/gpu/drm/drm_bridge.c                       | 69 +++++++++++++++++-----
 drivers/gpu/drm/meson/meson_encoder_cvbs.c         |  7 +--
 drivers/gpu/drm/meson/meson_encoder_dsi.c          |  7 +--
 drivers/gpu/drm/meson/meson_encoder_hdmi.c         |  9 ++-
 drivers/gpu/drm/tiny/arcpgu.c                      |  5 +-
 include/drm/drm_bridge.h                           | 16 +++++
 12 files changed, 162 insertions(+), 117 deletions(-)
---
base-commit: 441223656cd43291f4f8277ab98fd3e9e61eeb33
change-id: 20251117-drm-bridge-alloc-getput-drm_of_find_bridge-74903367448d

Best regards,
-- 
Luca Ceresoli <luca.ceresoli at bootlin.com>



From robh at kernel.org  Tue Dec 16 09:59:13 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Tue, 16 Dec 2025 11:59:13 -0600
Subject: [PATCH] arm64: dts: xilinx: Drop "label" property on dlg,slg7xl45106
Message-ID: <20251216175914.2791200-1-robh@kernel.org>

The "label" property is not documented for the dlg,slg7xl45106. Nor is
it common to use for GPIO controllers. So drop it.

Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
---
 arch/arm64/boot/dts/xilinx/zynqmp-sck-kd-g-revA.dtso | 1 -
 arch/arm64/boot/dts/xilinx/zynqmp-sck-kr-g-revA.dtso | 1 -
 arch/arm64/boot/dts/xilinx/zynqmp-sck-kr-g-revB.dtso | 1 -
 3 files changed, 3 deletions(-)

diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kd-g-revA.dtso b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kd-g-revA.dtso
index 02be5e1e8686..d0230da47068 100644
--- a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kd-g-revA.dtso
+++ b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kd-g-revA.dtso
@@ -75,7 +75,6 @@ u3: ina260 at 40 { /* u3 */
 	slg7xl45106: gpio at 11 { /* u13 - reset logic */
 		compatible = "dlg,slg7xl45106";
 		reg = <0x11>;
-		label = "resetchip";
 		gpio-controller;
 		#gpio-cells = <2>;
 		gpio-line-names = "USB0_PHY_RESET_B", "",
diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kr-g-revA.dtso b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kr-g-revA.dtso
index b92dcb86e87e..5d1f031bbd89 100644
--- a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kr-g-revA.dtso
+++ b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kr-g-revA.dtso
@@ -103,7 +103,6 @@ u14: ina260 at 40 { /* u14 */
 	slg7xl45106: gpio at 11 { /* u19 - reset logic */
 		compatible = "dlg,slg7xl45106";
 		reg = <0x11>;
-		label = "resetchip";
 		gpio-controller;
 		#gpio-cells = <2>;
 		gpio-line-names = "USB0_PHY_RESET_B", "USB1_PHY_RESET_B",
diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kr-g-revB.dtso b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kr-g-revB.dtso
index 99ad220d13d6..1d5c95bd6073 100644
--- a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kr-g-revB.dtso
+++ b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kr-g-revB.dtso
@@ -104,7 +104,6 @@ u14: ina260 at 40 { /* u14 */
 	slg7xl45106: gpio at 11 { /* u19 - reset logic */
 		compatible = "dlg,slg7xl45106";
 		reg = <0x11>;
-		label = "resetchip";
 		gpio-controller;
 		#gpio-cells = <2>;
 		gpio-line-names = "USB0_PHY_RESET_B", "USB1_PHY_RESET_B",
-- 
2.51.0



From luca.ceresoli at bootlin.com  Tue Dec 16 09:58:34 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Tue, 16 Dec 2025 18:58:34 +0100
Subject: [PATCH v3 01/22] drm/bridge: add of_drm_find_and_get_bridge()
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
Message-ID: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-1-b5165fab8058@bootlin.com>

of_drm_find_bridge() does not increment the refcount for the returned
bridge, but that is required now. However converting it and all its users
is not realistically doable at once given the large amount of (direct and
indirect) callers and the complexity of some.

Solve this issue by creating a new of_drm_find_and_get_bridge() function
that is identical to of_drm_find_bridge() except also it takes a
reference. Then of_drm_find_bridge() will be deprecated to be eventually
removed.

Suggested-by: Maxime Ripard <mripard at kernel.org>
Link: https://lore.kernel.org/dri-devel/20250319-stylish-lime-mongoose-0a18ad at houat/
Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>

---

Changes in v3:
- rename to of_drm_find_and_get_bridge()

Changes in v2:
- fix "mutex_unlock() before drm_bridge_get()", and use scoped_guard() to
  do it cleaning instead of complicating code
- rename to of_drm_get_bridge()

Note: a simple implementation would just be
  { return drm_bridge_get(of_drm_find_bridge(np)); }
but it would release the mutex before getting the reference, so it is
not safe. Make things simple by duplicating the code. A later patch will
make instead the (to be deprecated) of_drm_find_bridge() become a wrapper
of the new of_drm_get_bridge()
---
 drivers/gpu/drm/drm_bridge.c | 25 +++++++++++++++++++++++++
 include/drm/drm_bridge.h     |  5 +++++
 2 files changed, 30 insertions(+)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index db40c26d1cb3..0dbc8b59c3be 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -1479,6 +1479,31 @@ void drm_bridge_hpd_notify(struct drm_bridge *bridge,
 EXPORT_SYMBOL_GPL(drm_bridge_hpd_notify);
 
 #ifdef CONFIG_OF
+/**
+ * of_drm_find_and_get_bridge - find the bridge corresponding to the device
+ *                              node in the global bridge list
+ * @np: device node
+ *
+ * The refcount of the returned bridge is incremented. Use drm_bridge_put()
+ * when done with it.
+ *
+ * RETURNS:
+ * drm_bridge control struct on success, NULL on failure
+ */
+struct drm_bridge *of_drm_find_and_get_bridge(struct device_node *np)
+{
+	struct drm_bridge *bridge;
+
+	scoped_guard(mutex, &bridge_lock) {
+		list_for_each_entry(bridge, &bridge_list, list)
+			if (bridge->of_node == np)
+				return drm_bridge_get(bridge);
+	}
+
+	return NULL;
+}
+EXPORT_SYMBOL(of_drm_find_and_get_bridge);
+
 /**
  * of_drm_find_bridge - find the bridge corresponding to the device node in
  *			the global bridge list
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index d2683846cc61..8f10d2fd6016 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -1325,8 +1325,13 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
 		      enum drm_bridge_attach_flags flags);
 
 #ifdef CONFIG_OF
+struct drm_bridge *of_drm_find_and_get_bridge(struct device_node *np);
 struct drm_bridge *of_drm_find_bridge(struct device_node *np);
 #else
+static inline struct drm_bridge *of_drm_find_and_get_bridge(struct device_node *np)
+{
+	return NULL;
+}
 static inline struct drm_bridge *of_drm_find_bridge(struct device_node *np)
 {
 	return NULL;

-- 
2.52.0



From luca.ceresoli at bootlin.com  Tue Dec 16 09:58:35 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Tue, 16 Dec 2025 18:58:35 +0100
Subject: [PATCH v3 02/22] drm/bridge: deprecate of_drm_find_bridge()
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
Message-ID: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-2-b5165fab8058@bootlin.com>

of_drm_find_bridge() does not increment the returned bridge
refcount. of_drm_find_and_get_bridge() is to be used as a replacement.

Suggested-by: Maxime Ripard <mripard at kernel.org>
Link: https://lore.kernel.org/dri-devel/20250319-stylish-lime-mongoose-0a18ad at houat/
Reviewed-by: Maxime Ripard <mripard at kernel.org>
Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
---

Changes in v3:
- update after of_drm_get_bridge() -> of_drm_find_and_get_bridge() rename

Changes in v2:
- expand comment to mention why this function is dangerous and what users
  should do about refcounting
---
 drivers/gpu/drm/drm_bridge.c | 22 ++++++++++++++++++----
 1 file changed, 18 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 0dbc8b59c3be..f612d486cad0 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -361,7 +361,7 @@ EXPORT_SYMBOL(__devm_drm_bridge_alloc);
  * @bridge: bridge control structure
  *
  * Add the given bridge to the global list of bridges, where they can be
- * found by users via of_drm_find_bridge().
+ * found by users via of_drm_find_and_get_bridge().
  *
  * The bridge to be added must have been allocated by
  * devm_drm_bridge_alloc().
@@ -422,9 +422,9 @@ EXPORT_SYMBOL(devm_drm_bridge_add);
  * @bridge: bridge control structure
  *
  * Remove the given bridge from the global list of registered bridges, so
- * it won't be found by users via of_drm_find_bridge(), and add it to the
- * lingering bridge list, to keep track of it until its allocated memory is
- * eventually freed.
+ * it won't be found by users via of_drm_find_and_get_bridge(), and add it
+ * to the lingering bridge list, to keep track of it until its allocated
+ * memory is eventually freed.
  */
 void drm_bridge_remove(struct drm_bridge *bridge)
 {
@@ -1510,6 +1510,20 @@ EXPORT_SYMBOL(of_drm_find_and_get_bridge);
  *
  * @np: device node
  *
+ * This function is deprecated. Convert to of_drm_find_and_get_bridge()
+ * instead for proper refcounting.
+ *
+ * The bridge returned by this function is not refcounted. This is
+ * dangerous because the bridge might be deallocated even before the caller
+ * has a chance to use it. To use this function you have to do one of:
+ * - get a reference with drm_bridge_get() as soon as possible to
+ *   minimize the race window, and then drm_bridge_put() when no longer
+ *   using the pointer
+ * - not call drm_bridge_get() or drm_bridge_put() at all, which used to
+ *   be the correct practice before dynamic bridge lifetime was introduced
+ * - again, convert to of_drm_find_and_get_bridge(), which is the only safe
+ *   thing to do
+ *
  * RETURNS:
  * drm_bridge control struct on success, NULL on failure
  */

-- 
2.52.0



From luca.ceresoli at bootlin.com  Tue Dec 16 09:58:36 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Tue, 16 Dec 2025 18:58:36 +0100
Subject: [PATCH v3 03/22] drm/todo: add entry about converting to
 of_drm_find_and_get_bridge()
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
Message-ID: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-3-b5165fab8058@bootlin.com>

of_drm_find_bridge() is deprecated, but converting some users is very
complex and should be reasonably doable only after the DRM panel bridge
lifetime rework. Add a TODO to track this.

Suggested-by: Maxime Ripard <mripard at kernel.org>
Link: https://lore.kernel.org/dri-devel/20250319-stylish-lime-mongoose-0a18ad at houat/
Reviewed-by: Maxime Ripard <mripard at kernel.org>
Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>

---

Changes in v3:
- update after of_drm_get_bridge() -> of_drm_find_and_get_bridge() rename
---
 Documentation/gpu/todo.rst | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst
index 22487ac1b011..520da44a04a6 100644
--- a/Documentation/gpu/todo.rst
+++ b/Documentation/gpu/todo.rst
@@ -506,6 +506,22 @@ Contact: Maxime Ripard <mripard at kernel.org>,
 
 Level: Intermediate
 
+Convert users of of_drm_find_bridge() to of_drm_find_and_get_bridge()
+---------------------------------------------------------------------
+
+Taking a struct drm_bridge pointer requires getting a reference and putting
+it after disposing of the pointer. Most functions returning a struct
+drm_bridge pointer already call drm_bridge_get() to increment the refcount
+and their users have been updated to call drm_bridge_put() when
+appropriate. of_drm_find_bridge() does not get a reference and it has been
+deprecated in favor of of_drm_find_and_get_bridge() which does, but some
+users still need to be converted.
+
+Contact: Maxime Ripard <mripard at kernel.org>,
+         Luca Ceresoli <luca.ceresoli at bootlin.com>
+
+Level: Intermediate
+
 Core refactorings
 =================
 

-- 
2.52.0



From luca.ceresoli at bootlin.com  Tue Dec 16 09:58:37 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Tue, 16 Dec 2025 18:58:37 +0100
Subject: [PATCH v3 04/22] drm/bridge: make of_drm_find_bridge() a wrapper
 of of_drm_find_and_get_bridge()
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
Message-ID: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-4-b5165fab8058@bootlin.com>

of_drm_find_bridge() is identical to of_drm_find_and_get_bridge() except it
does not increment the refcount. Rewrite it as a wrapper and put the bridge
being returned so the behaviour is still the same.

Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>

---

Changes in v3:
- update after of_drm_get_bridge() -> of_drm_find_and_get_bridge() rename
- fixed kerneldoc syntax for non-kerneldoc comment

Changes in v2:
- Added comment to document why we put the reference
---
 drivers/gpu/drm/drm_bridge.c | 20 +++++++++-----------
 1 file changed, 9 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index f612d486cad0..64aa69dcf46f 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -1529,19 +1529,17 @@ EXPORT_SYMBOL(of_drm_find_and_get_bridge);
  */
 struct drm_bridge *of_drm_find_bridge(struct device_node *np)
 {
-	struct drm_bridge *bridge;
-
-	mutex_lock(&bridge_lock);
+	struct drm_bridge *bridge = of_drm_find_and_get_bridge(np);
 
-	list_for_each_entry(bridge, &bridge_list, list) {
-		if (bridge->of_node == np) {
-			mutex_unlock(&bridge_lock);
-			return bridge;
-		}
-	}
+	/*
+	 * We need to emulate the original semantics of
+	 * of_drm_find_bridge(), which was not getting any bridge
+	 * reference. Being now based on of_drm_find_and_get_bridge() which
+	 * gets a reference, put it before returning.
+	 */
+	drm_bridge_put(bridge);
 
-	mutex_unlock(&bridge_lock);
-	return NULL;
+	return bridge;
 }
 EXPORT_SYMBOL(of_drm_find_bridge);
 #endif

-- 
2.52.0



From luca.ceresoli at bootlin.com  Tue Dec 16 09:58:38 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Tue, 16 Dec 2025 18:58:38 +0100
Subject: [PATCH v3 05/22] drm/arcpgu: convert to
 of_drm_find_and_get_bridge()
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
Message-ID: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-5-b5165fab8058@bootlin.com>

of_drm_find_bridge() is deprecated. Move to its replacement
of_drm_find_and_get_bridge() which gets a bridge reference, and ensure it
is put it when done.

Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>

---

Changes in v3:
- update after of_drm_get_bridge() -> of_drm_find_and_get_bridge() rename
---
 drivers/gpu/drm/tiny/arcpgu.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/tiny/arcpgu.c b/drivers/gpu/drm/tiny/arcpgu.c
index 7cf0f0ea1bfe..505888497482 100644
--- a/drivers/gpu/drm/tiny/arcpgu.c
+++ b/drivers/gpu/drm/tiny/arcpgu.c
@@ -308,10 +308,9 @@ static int arcpgu_load(struct arcpgu_drm_private *arcpgu)
 		return ret;
 
 	if (encoder_node) {
-		struct drm_bridge *bridge;
-
 		/* Locate drm bridge from the hdmi encoder DT node */
-		bridge = of_drm_find_bridge(encoder_node);
+		struct drm_bridge *bridge __free(drm_bridge_put) =
+			of_drm_find_and_get_bridge(encoder_node);
 		if (!bridge)
 			return -EPROBE_DEFER;
 

-- 
2.52.0



From luca.ceresoli at bootlin.com  Tue Dec 16 09:58:40 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Tue, 16 Dec 2025 18:58:40 +0100
Subject: [PATCH v3 07/22] drm/bridge: ite-it66121: get/put the next bridge
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
Message-ID: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-7-b5165fab8058@bootlin.com>

This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
function and stores it until driver removal. of_drm_find_bridge() is
deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
refcounted and use bridge->next_bridge to put the reference on
deallocation.

Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
---
 drivers/gpu/drm/bridge/ite-it66121.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c
index 0185f61e6e59..9246e9c15a6e 100644
--- a/drivers/gpu/drm/bridge/ite-it66121.c
+++ b/drivers/gpu/drm/bridge/ite-it66121.c
@@ -298,7 +298,6 @@ struct it66121_chip_info {
 struct it66121_ctx {
 	struct regmap *regmap;
 	struct drm_bridge bridge;
-	struct drm_bridge *next_bridge;
 	struct drm_connector *connector;
 	struct device *dev;
 	struct gpio_desc *gpio_reset;
@@ -596,7 +595,7 @@ static int it66121_bridge_attach(struct drm_bridge *bridge,
 	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
 		return -EINVAL;
 
-	ret = drm_bridge_attach(encoder, ctx->next_bridge, bridge, flags);
+	ret = drm_bridge_attach(encoder, ctx->bridge.next_bridge, bridge, flags);
 	if (ret)
 		return ret;
 
@@ -1543,9 +1542,9 @@ static int it66121_probe(struct i2c_client *client)
 		return -EINVAL;
 	}
 
-	ctx->next_bridge = of_drm_find_bridge(ep);
+	ctx->bridge.next_bridge = of_drm_find_and_get_bridge(ep);
 	of_node_put(ep);
-	if (!ctx->next_bridge) {
+	if (!ctx->bridge.next_bridge) {
 		dev_dbg(ctx->dev, "Next bridge not found, deferring probe\n");
 		return -EPROBE_DEFER;
 	}

-- 
2.52.0



From luca.ceresoli at bootlin.com  Tue Dec 16 09:58:39 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Tue, 16 Dec 2025 18:58:39 +0100
Subject: [PATCH v3 06/22] drm/bridge: add next_bridge pointer to struct
 drm_bridge
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
Message-ID: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-6-b5165fab8058@bootlin.com>

Many bridge drivers store a next_bridge pointer in their private data and
use it for attach and sometimes other purposes. This is going to be risky
when bridge hot-unplug is used.

Considering this example scenario:

  1. pipeline: encoder --> bridge A --> bridge B --> bridge C
  2. encoder takes a reference to bridge B
  3. bridge B takes a next_bridge reference to bridge C
  4. encoder calls (bridge B)->b_foo(), which in turns references
     next_bridge, e.g.:

       b_foo() {
           bar(b->next_bridge);
       }

If bridges B and C are removed, bridge C can be freed but B is still
allocated because the encoder holds a reference to B. So when step 4
happens, 'b->next-bridge' would be a use-after-free.

Calling drm_bridge_put() in the B bridge .remove function does not solve
the problem as it leaves a (potentially long) risk window between B removal
and the final deallocation of B. A safe moment to put the B reference is in
__drm_bridge_free(), when the last reference has been put. This can be done
by drivers in the .destroy func. However to avoid the need for so many
drivers to implement a .destroy func, just offer a next_bridge pointer to
all bridges that is automatically put it in __drm_bridge_free(), exactly
when the .destroy func is called.

Suggested-by: Maxime Ripard <mripard at kernel.org>
Link: https://lore.kernel.org/all/20251201-thick-jasmine-oarfish-1eceb0 at houat/
Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
---
 drivers/gpu/drm/drm_bridge.c |  2 ++
 include/drm/drm_bridge.h     | 11 +++++++++++
 2 files changed, 13 insertions(+)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 64aa69dcf46f..6dcf8f6d3ecf 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -275,6 +275,8 @@ static void __drm_bridge_free(struct kref *kref)
 	if (bridge->funcs->destroy)
 		bridge->funcs->destroy(bridge);
 
+	drm_bridge_put(bridge->next_bridge);
+
 	kfree(bridge->container);
 }
 
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 8f10d2fd6016..63660256c4f5 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -1278,6 +1278,17 @@ struct drm_bridge {
 	 * @hpd_cb.
 	 */
 	void *hpd_data;
+
+	/**
+	 * @next_bridge: Pointer to the following bridge, automatically put
+	 * when this bridge is freed (i.e. at destroy time). This is for
+	 * drivers needing to store a pointer to the next bridge in the
+	 * chain, and ensures any code still holding a reference to this
+	 * bridge after its removal cannot use-after-free the next
+	 * bridge. Any other bridge pointers stored by the driver must be
+	 * put in the .destroy callback by driver code.
+	 */
+	struct drm_bridge *next_bridge;
 };
 
 static inline struct drm_bridge *

-- 
2.52.0



From luca.ceresoli at bootlin.com  Tue Dec 16 09:58:41 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Tue, 16 Dec 2025 18:58:41 +0100
Subject: [PATCH v3 08/22] drm/bridge: imx8qxp-pixel-combiner: get/put the
 next bridge
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
Message-ID: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-8-b5165fab8058@bootlin.com>

This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
function and stores it until driver removal. of_drm_find_bridge() is
deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
refcounted and use bridge->next_bridge to put the reference on
deallocation.

Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
---
 drivers/gpu/drm/bridge/imx/imx8qxp-pixel-combiner.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-combiner.c b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-combiner.c
index 8517b1c953d4..74eda8b54023 100644
--- a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-combiner.c
+++ b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-combiner.c
@@ -60,7 +60,6 @@ enum imx8qxp_pc_pix_data_format {
 
 struct imx8qxp_pc_channel {
 	struct drm_bridge bridge;
-	struct drm_bridge *next_bridge;
 	struct imx8qxp_pc *pc;
 	unsigned int stream_id;
 };
@@ -120,7 +119,7 @@ static int imx8qxp_pc_bridge_attach(struct drm_bridge *bridge,
 	}
 
 	return drm_bridge_attach(encoder,
-				 ch->next_bridge, bridge,
+				 ch->bridge.next_bridge, bridge,
 				 DRM_BRIDGE_ATTACH_NO_CONNECTOR);
 }
 
@@ -326,8 +325,8 @@ static int imx8qxp_pc_bridge_probe(struct platform_device *pdev)
 			goto free_child;
 		}
 
-		ch->next_bridge = of_drm_find_bridge(remote);
-		if (!ch->next_bridge) {
+		ch->bridge.next_bridge = of_drm_find_and_get_bridge(remote);
+		if (!ch->bridge.next_bridge) {
 			of_node_put(remote);
 			ret = -EPROBE_DEFER;
 			DRM_DEV_DEBUG_DRIVER(dev,
@@ -349,7 +348,7 @@ static int imx8qxp_pc_bridge_probe(struct platform_device *pdev)
 free_child:
 	of_node_put(child);
 
-	if (i == 1 && pc->ch[0]->next_bridge)
+	if (i == 1 && pc->ch[0]->bridge.next_bridge)
 		drm_bridge_remove(&pc->ch[0]->bridge);
 
 	pm_runtime_disable(dev);

-- 
2.52.0



From luca.ceresoli at bootlin.com  Tue Dec 16 09:58:42 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Tue, 16 Dec 2025 18:58:42 +0100
Subject: [PATCH v3 09/22] drm/bridge: simple-bridge: get/put the next
 bridge
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
Message-ID: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-9-b5165fab8058@bootlin.com>

This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
function and stores it until driver removal. of_drm_find_bridge() is
deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
refcounted and use bridge->next_bridge to put the reference on
deallocation.

Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
---
 drivers/gpu/drm/bridge/simple-bridge.c | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/simple-bridge.c b/drivers/gpu/drm/bridge/simple-bridge.c
index 2cd1847ba776..873b32cfb508 100644
--- a/drivers/gpu/drm/bridge/simple-bridge.c
+++ b/drivers/gpu/drm/bridge/simple-bridge.c
@@ -31,7 +31,6 @@ struct simple_bridge {
 
 	const struct simple_bridge_info *info;
 
-	struct drm_bridge	*next_bridge;
 	struct regulator	*vdd;
 	struct gpio_desc	*enable;
 };
@@ -54,8 +53,8 @@ static int simple_bridge_get_modes(struct drm_connector *connector)
 	const struct drm_edid *drm_edid;
 	int ret;
 
-	if (sbridge->next_bridge->ops & DRM_BRIDGE_OP_EDID) {
-		drm_edid = drm_bridge_edid_read(sbridge->next_bridge, connector);
+	if (sbridge->bridge.next_bridge->ops & DRM_BRIDGE_OP_EDID) {
+		drm_edid = drm_bridge_edid_read(sbridge->bridge.next_bridge, connector);
 		if (!drm_edid)
 			DRM_INFO("EDID read failed. Fallback to standard modes\n");
 	} else {
@@ -90,7 +89,7 @@ simple_bridge_connector_detect(struct drm_connector *connector, bool force)
 {
 	struct simple_bridge *sbridge = drm_connector_to_simple_bridge(connector);
 
-	return drm_bridge_detect(sbridge->next_bridge, connector);
+	return drm_bridge_detect(sbridge->bridge.next_bridge, connector);
 }
 
 static const struct drm_connector_funcs simple_bridge_con_funcs = {
@@ -109,7 +108,7 @@ static int simple_bridge_attach(struct drm_bridge *bridge,
 	struct simple_bridge *sbridge = drm_bridge_to_simple_bridge(bridge);
 	int ret;
 
-	ret = drm_bridge_attach(encoder, sbridge->next_bridge, bridge,
+	ret = drm_bridge_attach(encoder, sbridge->bridge.next_bridge, bridge,
 				DRM_BRIDGE_ATTACH_NO_CONNECTOR);
 	if (ret < 0)
 		return ret;
@@ -122,7 +121,7 @@ static int simple_bridge_attach(struct drm_bridge *bridge,
 	ret = drm_connector_init_with_ddc(bridge->dev, &sbridge->connector,
 					  &simple_bridge_con_funcs,
 					  sbridge->info->connector_type,
-					  sbridge->next_bridge->ddc);
+					  sbridge->bridge.next_bridge->ddc);
 	if (ret) {
 		DRM_ERROR("Failed to initialize connector\n");
 		return ret;
@@ -180,10 +179,10 @@ static int simple_bridge_probe(struct platform_device *pdev)
 	if (!remote)
 		return -EINVAL;
 
-	sbridge->next_bridge = of_drm_find_bridge(remote);
+	sbridge->bridge.next_bridge = of_drm_find_and_get_bridge(remote);
 	of_node_put(remote);
 
-	if (!sbridge->next_bridge) {
+	if (!sbridge->bridge.next_bridge) {
 		dev_dbg(&pdev->dev, "Next bridge not found, deferring probe\n");
 		return -EPROBE_DEFER;
 	}

-- 
2.52.0



From luca.ceresoli at bootlin.com  Tue Dec 16 09:58:43 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Tue, 16 Dec 2025 18:58:43 +0100
Subject: [PATCH v3 10/22] drm/meson: encoder_cvbs: get/put the next bridge
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
Message-ID: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-10-b5165fab8058@bootlin.com>

This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
function and stores it until driver removal. of_drm_find_bridge() is
deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
refcounted and use bridge->next_bridge to put the reference on
deallocation.

Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
---
 drivers/gpu/drm/meson/meson_encoder_cvbs.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/meson/meson_encoder_cvbs.c b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
index dc374bfc5951..41071d6e05e5 100644
--- a/drivers/gpu/drm/meson/meson_encoder_cvbs.c
+++ b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
@@ -33,7 +33,6 @@
 struct meson_encoder_cvbs {
 	struct drm_encoder	encoder;
 	struct drm_bridge	bridge;
-	struct drm_bridge	*next_bridge;
 	struct meson_drm	*priv;
 };
 
@@ -89,7 +88,7 @@ static int meson_encoder_cvbs_attach(struct drm_bridge *bridge,
 	struct meson_encoder_cvbs *meson_encoder_cvbs =
 					bridge_to_meson_encoder_cvbs(bridge);
 
-	return drm_bridge_attach(encoder, meson_encoder_cvbs->next_bridge,
+	return drm_bridge_attach(encoder, meson_encoder_cvbs->bridge.next_bridge,
 				 &meson_encoder_cvbs->bridge, flags);
 }
 
@@ -241,9 +240,9 @@ int meson_encoder_cvbs_probe(struct meson_drm *priv)
 		return 0;
 	}
 
-	meson_encoder_cvbs->next_bridge = of_drm_find_bridge(remote);
+	meson_encoder_cvbs->bridge.next_bridge = of_drm_find_and_get_bridge(remote);
 	of_node_put(remote);
-	if (!meson_encoder_cvbs->next_bridge)
+	if (!meson_encoder_cvbs->bridge.next_bridge)
 		return dev_err_probe(priv->dev, -EPROBE_DEFER,
 				     "Failed to find CVBS Connector bridge\n");
 

-- 
2.52.0



From luca.ceresoli at bootlin.com  Tue Dec 16 09:58:44 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Tue, 16 Dec 2025 18:58:44 +0100
Subject: [PATCH v3 11/22] drm/meson: encoder_dsi: get/put the next bridge
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
Message-ID: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-11-b5165fab8058@bootlin.com>

This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
function and stores it until driver removal. of_drm_find_bridge() is
deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
refcounted and use bridge->next_bridge to put the reference on
deallocation.

Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
---
 drivers/gpu/drm/meson/meson_encoder_dsi.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/meson/meson_encoder_dsi.c b/drivers/gpu/drm/meson/meson_encoder_dsi.c
index 6c6624f9ba24..eba246791c68 100644
--- a/drivers/gpu/drm/meson/meson_encoder_dsi.c
+++ b/drivers/gpu/drm/meson/meson_encoder_dsi.c
@@ -25,7 +25,6 @@
 struct meson_encoder_dsi {
 	struct drm_encoder encoder;
 	struct drm_bridge bridge;
-	struct drm_bridge *next_bridge;
 	struct meson_drm *priv;
 };
 
@@ -38,7 +37,7 @@ static int meson_encoder_dsi_attach(struct drm_bridge *bridge,
 {
 	struct meson_encoder_dsi *encoder_dsi = bridge_to_meson_encoder_dsi(bridge);
 
-	return drm_bridge_attach(encoder, encoder_dsi->next_bridge,
+	return drm_bridge_attach(encoder, encoder_dsi->bridge.next_bridge,
 				 &encoder_dsi->bridge, flags);
 }
 
@@ -120,8 +119,8 @@ int meson_encoder_dsi_probe(struct meson_drm *priv)
 		return 0;
 	}
 
-	meson_encoder_dsi->next_bridge = of_drm_find_bridge(remote);
-	if (!meson_encoder_dsi->next_bridge)
+	meson_encoder_dsi->bridge.next_bridge = of_drm_find_and_get_bridge(remote);
+	if (!meson_encoder_dsi->bridge.next_bridge)
 		return dev_err_probe(priv->dev, -EPROBE_DEFER,
 				     "Failed to find DSI transceiver bridge\n");
 

-- 
2.52.0



From luca.ceresoli at bootlin.com  Tue Dec 16 09:58:45 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Tue, 16 Dec 2025 18:58:45 +0100
Subject: [PATCH v3 12/22] drm/meson: encoder_hdmi: get/put the next bridge
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
Message-ID: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-12-b5165fab8058@bootlin.com>

This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
function and stores it until driver removal. of_drm_find_bridge() is
deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
refcounted and use bridge->next_bridge to put the reference on
deallocation.

Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
---
 drivers/gpu/drm/meson/meson_encoder_hdmi.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/meson/meson_encoder_hdmi.c b/drivers/gpu/drm/meson/meson_encoder_hdmi.c
index 8205ee56a691..dc4e23590a6e 100644
--- a/drivers/gpu/drm/meson/meson_encoder_hdmi.c
+++ b/drivers/gpu/drm/meson/meson_encoder_hdmi.c
@@ -38,7 +38,6 @@
 struct meson_encoder_hdmi {
 	struct drm_encoder encoder;
 	struct drm_bridge bridge;
-	struct drm_bridge *next_bridge;
 	struct drm_connector *connector;
 	struct meson_drm *priv;
 	unsigned long output_bus_fmt;
@@ -54,7 +53,7 @@ static int meson_encoder_hdmi_attach(struct drm_bridge *bridge,
 {
 	struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge);
 
-	return drm_bridge_attach(encoder, encoder_hdmi->next_bridge,
+	return drm_bridge_attach(encoder, encoder_hdmi->bridge.next_bridge,
 				 &encoder_hdmi->bridge, flags);
 }
 
@@ -334,7 +333,7 @@ static void meson_encoder_hdmi_hpd_notify(struct drm_bridge *bridge,
 		const struct drm_edid *drm_edid;
 		const struct edid *edid;
 
-		drm_edid = drm_bridge_edid_read(encoder_hdmi->next_bridge,
+		drm_edid = drm_bridge_edid_read(encoder_hdmi->bridge.next_bridge,
 						encoder_hdmi->connector);
 		if (!drm_edid)
 			return;
@@ -390,8 +389,8 @@ int meson_encoder_hdmi_probe(struct meson_drm *priv)
 		return 0;
 	}
 
-	meson_encoder_hdmi->next_bridge = of_drm_find_bridge(remote);
-	if (!meson_encoder_hdmi->next_bridge) {
+	meson_encoder_hdmi->bridge.next_bridge = of_drm_find_and_get_bridge(remote);
+	if (!meson_encoder_hdmi->bridge.next_bridge) {
 		ret = dev_err_probe(priv->dev, -EPROBE_DEFER,
 				    "Failed to find HDMI transceiver bridge\n");
 		goto err_put_node;

-- 
2.52.0



From robh at kernel.org  Tue Dec 16 09:59:52 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Tue, 16 Dec 2025 11:59:52 -0600
Subject: [PATCH] arm64: dts: lg: Use recommended simple-bus node name
Message-ID: <20251216175951.2791921-2-robh@kernel.org>

Update LG LG131x 'amba' bus node name to 'amba-bus' following the
standard names for simple-bus nodes. Generally, node names and paths
aren't considered ABI, so it is safe to change them.

Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
---
SoC maintainers, Please take this directly.

 arch/arm64/boot/dts/lg/lg131x.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/lg/lg131x.dtsi b/arch/arm64/boot/dts/lg/lg131x.dtsi
index 4cb1e4510897..90988770cb5c 100644
--- a/arch/arm64/boot/dts/lg/lg131x.dtsi
+++ b/arch/arm64/boot/dts/lg/lg131x.dtsi
@@ -102,7 +102,7 @@ clk_bus: clk_bus {
 		clock-output-names = "BUSCLK";
 	};
 
-	amba {
+	amba-bus {
 		#address-cells = <2>;
 		#size-cells = <1>;
 
-- 
2.51.0



From luca.ceresoli at bootlin.com  Tue Dec 16 09:58:46 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Tue, 16 Dec 2025 18:58:46 +0100
Subject: [PATCH v3 13/22] drm/bridge: imx8qxp-pxl2dpi: simplify put of
 device_node pointers
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
Message-ID: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-13-b5165fab8058@bootlin.com>

Simplify the error-management code in
imx8qxp_pxl2dpi_get_available_ep_from_port() by using a release action for
the struct device_node pointers.

Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
---
 drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c | 21 +++++++--------------
 1 file changed, 7 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c b/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c
index 111310acab2c..a4941f39a2e6 100644
--- a/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c
+++ b/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c
@@ -258,35 +258,28 @@ imx8qxp_pxl2dpi_get_available_ep_from_port(struct imx8qxp_pxl2dpi *p2d,
 static struct drm_bridge *
 imx8qxp_pxl2dpi_find_next_bridge(struct imx8qxp_pxl2dpi *p2d)
 {
-	struct device_node *ep, *remote;
 	struct drm_bridge *next_bridge;
 	int ret;
 
-	ep = imx8qxp_pxl2dpi_get_available_ep_from_port(p2d, 1);
+	struct device_node *ep __free(device_node) =
+		imx8qxp_pxl2dpi_get_available_ep_from_port(p2d, 1);
 	if (IS_ERR(ep)) {
 		ret = PTR_ERR(ep);
 		return ERR_PTR(ret);
 	}
 
-	remote = of_graph_get_remote_port_parent(ep);
+	struct device_node *remote __free(device_node) = of_graph_get_remote_port_parent(ep);
 	if (!remote || !of_device_is_available(remote)) {
 		DRM_DEV_ERROR(p2d->dev, "no available remote\n");
-		next_bridge = ERR_PTR(-ENODEV);
-		goto out;
+		return ERR_PTR(-ENODEV);
 	} else if (!of_device_is_available(remote->parent)) {
 		DRM_DEV_ERROR(p2d->dev, "remote parent is not available\n");
-		next_bridge = ERR_PTR(-ENODEV);
-		goto out;
+		return ERR_PTR(-ENODEV);
 	}
 
 	next_bridge = of_drm_find_bridge(remote);
-	if (!next_bridge) {
-		next_bridge = ERR_PTR(-EPROBE_DEFER);
-		goto out;
-	}
-out:
-	of_node_put(remote);
-	of_node_put(ep);
+	if (!next_bridge)
+		return ERR_PTR(-EPROBE_DEFER);
 
 	return next_bridge;
 }

-- 
2.52.0



From luca.ceresoli at bootlin.com  Tue Dec 16 09:58:47 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Tue, 16 Dec 2025 18:58:47 +0100
Subject: [PATCH v3 14/22] drm/bridge: imx8qxp-pxl2dpi: remove excess error
 message
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
Message-ID: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-14-b5165fab8058@bootlin.com>

imx8qxp_pxl2dpi_find_next_bridge() already emits a DRM_DEV_ERROR() for
every error except -EPROBE_DEFER. The caller emits another one, which is
redundant. Remove the message in the caller and keep the two in
imx8qxp_pxl2dpi_find_next_bridge() as they are more informative about the
error cause.

Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
---
 drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c b/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c
index a4941f39a2e6..e03a411cb9db 100644
--- a/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c
+++ b/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c
@@ -415,13 +415,8 @@ static int imx8qxp_pxl2dpi_bridge_probe(struct platform_device *pdev)
 	}
 
 	p2d->next_bridge = imx8qxp_pxl2dpi_find_next_bridge(p2d);
-	if (IS_ERR(p2d->next_bridge)) {
-		ret = PTR_ERR(p2d->next_bridge);
-		if (ret != -EPROBE_DEFER)
-			DRM_DEV_ERROR(dev, "failed to find next bridge: %d\n",
-				      ret);
-		return ret;
-	}
+	if (IS_ERR(p2d->next_bridge))
+		return PTR_ERR(p2d->next_bridge);
 
 	ret = imx8qxp_pxl2dpi_set_pixel_link_sel(p2d);
 	if (ret)

-- 
2.52.0



From luca.ceresoli at bootlin.com  Tue Dec 16 09:58:48 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Tue, 16 Dec 2025 18:58:48 +0100
Subject: [PATCH v3 15/22] drm/bridge: imx8qxp-pxl2dpi:
 imx8qxp_pxl2dpi_find_next_bridge: return int, not ERR_PTR
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
Message-ID: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-15-b5165fab8058@bootlin.com>

In preparation for using bridge->next_bridge, we need to ensure that it
will never contain anything but NULL or a valid bridge pointer. Current
code stores an ERR_PTR when imx8qxp_pxl2dpi_find_next_bridge() errors
out. Instead of fixing that after the facts in the caller, change the
function to internally set the next_pointer and just return an int error
value.

No functional changes.

Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
---
 drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c | 30 +++++++++++-----------------
 1 file changed, 12 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c b/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c
index e03a411cb9db..2e66b003386e 100644
--- a/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c
+++ b/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c
@@ -255,33 +255,27 @@ imx8qxp_pxl2dpi_get_available_ep_from_port(struct imx8qxp_pxl2dpi *p2d,
 	return ep;
 }
 
-static struct drm_bridge *
-imx8qxp_pxl2dpi_find_next_bridge(struct imx8qxp_pxl2dpi *p2d)
+static int imx8qxp_pxl2dpi_find_next_bridge(struct imx8qxp_pxl2dpi *p2d)
 {
-	struct drm_bridge *next_bridge;
-	int ret;
-
 	struct device_node *ep __free(device_node) =
 		imx8qxp_pxl2dpi_get_available_ep_from_port(p2d, 1);
-	if (IS_ERR(ep)) {
-		ret = PTR_ERR(ep);
-		return ERR_PTR(ret);
-	}
+	if (IS_ERR(ep))
+		return PTR_ERR(ep);
 
 	struct device_node *remote __free(device_node) = of_graph_get_remote_port_parent(ep);
 	if (!remote || !of_device_is_available(remote)) {
 		DRM_DEV_ERROR(p2d->dev, "no available remote\n");
-		return ERR_PTR(-ENODEV);
+		return -ENODEV;
 	} else if (!of_device_is_available(remote->parent)) {
 		DRM_DEV_ERROR(p2d->dev, "remote parent is not available\n");
-		return ERR_PTR(-ENODEV);
+		return -ENODEV;
 	}
 
-	next_bridge = of_drm_find_bridge(remote);
-	if (!next_bridge)
-		return ERR_PTR(-EPROBE_DEFER);
+	p2d->next_bridge = of_drm_find_bridge(remote);
+	if (!p2d->next_bridge)
+		return -EPROBE_DEFER;
 
-	return next_bridge;
+	return 0;
 }
 
 static int imx8qxp_pxl2dpi_set_pixel_link_sel(struct imx8qxp_pxl2dpi *p2d)
@@ -414,9 +408,9 @@ static int imx8qxp_pxl2dpi_bridge_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	p2d->next_bridge = imx8qxp_pxl2dpi_find_next_bridge(p2d);
-	if (IS_ERR(p2d->next_bridge))
-		return PTR_ERR(p2d->next_bridge);
+	ret = imx8qxp_pxl2dpi_find_next_bridge(p2d);
+	if (ret)
+		return ret;
 
 	ret = imx8qxp_pxl2dpi_set_pixel_link_sel(p2d);
 	if (ret)

-- 
2.52.0



From luca.ceresoli at bootlin.com  Tue Dec 16 09:58:49 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Tue, 16 Dec 2025 18:58:49 +0100
Subject: [PATCH v3 16/22] drm/bridge: imx8qxp-pxl2dpi: get/put the next
 bridge
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
Message-ID: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-16-b5165fab8058@bootlin.com>

This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
function and stores it until driver removal. of_drm_find_bridge() is
deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
refcounted and use bridge->next_bridge to put the reference on
deallocation.

Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
---
 drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c b/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c
index 2e66b003386e..556aec3b3734 100644
--- a/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c
+++ b/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c
@@ -35,7 +35,6 @@
 struct imx8qxp_pxl2dpi {
 	struct regmap *regmap;
 	struct drm_bridge bridge;
-	struct drm_bridge *next_bridge;
 	struct drm_bridge *companion;
 	struct device *dev;
 	struct imx_sc_ipc *ipc_handle;
@@ -60,7 +59,7 @@ static int imx8qxp_pxl2dpi_bridge_attach(struct drm_bridge *bridge,
 	}
 
 	return drm_bridge_attach(encoder,
-				 p2d->next_bridge, bridge,
+				 p2d->bridge.next_bridge, bridge,
 				 DRM_BRIDGE_ATTACH_NO_CONNECTOR);
 }
 
@@ -271,8 +270,8 @@ static int imx8qxp_pxl2dpi_find_next_bridge(struct imx8qxp_pxl2dpi *p2d)
 		return -ENODEV;
 	}
 
-	p2d->next_bridge = of_drm_find_bridge(remote);
-	if (!p2d->next_bridge)
+	p2d->bridge.next_bridge = of_drm_find_and_get_bridge(remote);
+	if (!p2d->bridge.next_bridge)
 		return -EPROBE_DEFER;
 
 	return 0;
@@ -351,8 +350,8 @@ static int imx8qxp_pxl2dpi_parse_dt_companion(struct imx8qxp_pxl2dpi *p2d)
 	 * the next bridges are connected to.  If they are marked as expecting
 	 * even pixels and odd pixels than we need to use the companion PXL2DPI.
 	 */
-	port1 = of_graph_get_port_by_id(p2d->next_bridge->of_node, 1);
-	port2 = of_graph_get_port_by_id(companion_p2d->next_bridge->of_node, 1);
+	port1 = of_graph_get_port_by_id(p2d->bridge.next_bridge->of_node, 1);
+	port2 = of_graph_get_port_by_id(companion_p2d->bridge.next_bridge->of_node, 1);
 	dual_link = drm_of_lvds_get_dual_link_pixel_order(port1, port2);
 	of_node_put(port1);
 	of_node_put(port2);

-- 
2.52.0



From luca.ceresoli at bootlin.com  Tue Dec 16 09:58:50 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Tue, 16 Dec 2025 18:58:50 +0100
Subject: [PATCH v3 17/22] drm/bridge: imx8qxp-pxl2dpi: get/put the
 companion bridge
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
Message-ID: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-17-b5165fab8058@bootlin.com>

This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
function and stores it until driver removal. of_drm_find_bridge() is
deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
refcounted and use the destroy hook to put the reference on deallocation.

Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
---
 drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c b/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c
index 556aec3b3734..2c40ca86e319 100644
--- a/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c
+++ b/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c
@@ -63,6 +63,13 @@ static int imx8qxp_pxl2dpi_bridge_attach(struct drm_bridge *bridge,
 				 DRM_BRIDGE_ATTACH_NO_CONNECTOR);
 }
 
+static void imx8qxp_pxl2dpi_bridge_destroy(struct drm_bridge *bridge)
+{
+	struct imx8qxp_pxl2dpi *p2d = bridge->driver_private;
+
+	drm_bridge_put(p2d->companion);
+}
+
 static int
 imx8qxp_pxl2dpi_bridge_atomic_check(struct drm_bridge *bridge,
 				    struct drm_bridge_state *bridge_state,
@@ -205,6 +212,7 @@ static const struct drm_bridge_funcs imx8qxp_pxl2dpi_bridge_funcs = {
 	.atomic_destroy_state	= drm_atomic_helper_bridge_destroy_state,
 	.atomic_reset		= drm_atomic_helper_bridge_reset,
 	.attach			= imx8qxp_pxl2dpi_bridge_attach,
+	.destroy		= imx8qxp_pxl2dpi_bridge_destroy,
 	.atomic_check		= imx8qxp_pxl2dpi_bridge_atomic_check,
 	.mode_set		= imx8qxp_pxl2dpi_bridge_mode_set,
 	.atomic_disable		= imx8qxp_pxl2dpi_bridge_atomic_disable,
@@ -333,7 +341,7 @@ static int imx8qxp_pxl2dpi_parse_dt_companion(struct imx8qxp_pxl2dpi *p2d)
 		goto out;
 	}
 
-	p2d->companion = of_drm_find_bridge(companion);
+	p2d->companion = of_drm_find_and_get_bridge(companion);
 	if (!p2d->companion) {
 		ret = -EPROBE_DEFER;
 		DRM_DEV_DEBUG_DRIVER(p2d->dev,

-- 
2.52.0



From luca.ceresoli at bootlin.com  Tue Dec 16 09:58:52 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Tue, 16 Dec 2025 18:58:52 +0100
Subject: [PATCH v3 19/22] drm/bridge: imx8qxp-pixel-link: simplify freeing
 of the remote device_node
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
Message-ID: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-19-b5165fab8058@bootlin.com>

The main loop in imx8qxp_pixel_link_find_next_bridge() requires calling
of_node_put() in multiple places, complicating code flow. Simplify it by
using a cleanup action and making the 'remote' variable scope local to the
loop.

Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
---
 drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
index 53016f0d53a0..2ecc3c1051e5 100644
--- a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
+++ b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
@@ -260,7 +260,7 @@ static struct drm_bridge *
 imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
 {
 	struct device_node *np = pl->dev->of_node;
-	struct device_node *port, *remote;
+	struct device_node *port;
 	struct drm_bridge *selected_bridge = NULL;
 	u32 port_id;
 	bool found_port = false;
@@ -286,7 +286,8 @@ imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
 	}
 
 	for (reg = 0; reg < PL_MAX_NEXT_BRIDGES; reg++) {
-		remote = of_graph_get_remote_node(np, port_id, reg);
+		struct device_node *remote __free(device_node) =
+			of_graph_get_remote_node(np, port_id, reg);
 		if (!remote)
 			continue;
 
@@ -294,15 +295,12 @@ imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
 			DRM_DEV_DEBUG(pl->dev,
 				      "port%u endpoint%u remote parent is not available\n",
 				      port_id, reg);
-			of_node_put(remote);
 			continue;
 		}
 
 		struct drm_bridge *next_bridge = of_drm_find_bridge(remote);
-		if (!next_bridge) {
-			of_node_put(remote);
+		if (!next_bridge)
 			return ERR_PTR(-EPROBE_DEFER);
-		}
 
 		/*
 		 * Select the next bridge with companion PXL2DPI if
@@ -310,8 +308,6 @@ imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
 		 */
 		if (!selected_bridge || of_property_present(remote, "fsl,companion-pxl2dpi"))
 			selected_bridge = next_bridge;
-
-		of_node_put(remote);
 	}
 
 	pl->mst_addr = port_id - 1;

-- 
2.52.0



From luca.ceresoli at bootlin.com  Tue Dec 16 09:58:51 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Tue, 16 Dec 2025 18:58:51 +0100
Subject: [PATCH v3 18/22] drm/bridge: imx8qxp-pixel-link: simplify logic to
 find next bridge
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
Message-ID: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-18-b5165fab8058@bootlin.com>

imx8qxp_pixel_link_find_next_bridge() uses a sophisticated logic to find
the preferred next bridge, using an array with two supporting index
variables. This is more sophisticated than required because we only ever
need a pointer to the "current" bridge and to the "best so far" bridge.

Additionally this logic is going to make the addition of proper refcounting
quite complex.

Rewrite the logic using two drm_bridge pointers, which is by itself
slightly simpler and is a preparation step for introducing bridge
refcounting in a later commit.

Also reword a comment to make it clearer.

Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
---
 drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c | 23 +++++++++++------------
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
index e5943506981d..53016f0d53a0 100644
--- a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
+++ b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
@@ -261,12 +261,10 @@ imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
 {
 	struct device_node *np = pl->dev->of_node;
 	struct device_node *port, *remote;
-	struct drm_bridge *next_bridge[PL_MAX_NEXT_BRIDGES];
+	struct drm_bridge *selected_bridge = NULL;
 	u32 port_id;
 	bool found_port = false;
-	int reg, ep_cnt = 0;
-	/* select the first next bridge by default */
-	int bridge_sel = 0;
+	int reg;
 
 	for (port_id = 1; port_id <= PL_MAX_MST_ADDR + 1; port_id++) {
 		port = of_graph_get_port_by_id(np, port_id);
@@ -300,24 +298,25 @@ imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
 			continue;
 		}
 
-		next_bridge[ep_cnt] = of_drm_find_bridge(remote);
-		if (!next_bridge[ep_cnt]) {
+		struct drm_bridge *next_bridge = of_drm_find_bridge(remote);
+		if (!next_bridge) {
 			of_node_put(remote);
 			return ERR_PTR(-EPROBE_DEFER);
 		}
 
-		/* specially select the next bridge with companion PXL2DPI */
-		if (of_property_present(remote, "fsl,companion-pxl2dpi"))
-			bridge_sel = ep_cnt;
-
-		ep_cnt++;
+		/*
+		 * Select the next bridge with companion PXL2DPI if
+		 * present, otherwise default to the first bridge
+		 */
+		if (!selected_bridge || of_property_present(remote, "fsl,companion-pxl2dpi"))
+			selected_bridge = next_bridge;
 
 		of_node_put(remote);
 	}
 
 	pl->mst_addr = port_id - 1;
 
-	return next_bridge[bridge_sel];
+	return selected_bridge;
 }
 
 static int imx8qxp_pixel_link_bridge_probe(struct platform_device *pdev)

-- 
2.52.0



From luca.ceresoli at bootlin.com  Tue Dec 16 09:58:53 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Tue, 16 Dec 2025 18:58:53 +0100
Subject: [PATCH v3 20/22] drm/bridge: imx8qxp-pixel-link: remove excess
 error message
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
Message-ID: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-20-b5165fab8058@bootlin.com>

imx8qxp_pixel_link_find_next_bridge() already emits a DRM_DEV_ERROR() on
error except for -EPROBE_DEFER. The caller emits another one, which is
redundant. Remove the message in the caller and keep the one in
imx8qxp_pixel_link_find_next_bridge() as it is more informative about the
error cause.

Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
---
 drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
index 2ecc3c1051e5..0c5ed06eee1b 100644
--- a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
+++ b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
@@ -369,13 +369,8 @@ static int imx8qxp_pixel_link_bridge_probe(struct platform_device *pdev)
 		return ret;
 
 	pl->next_bridge = imx8qxp_pixel_link_find_next_bridge(pl);
-	if (IS_ERR(pl->next_bridge)) {
-		ret = PTR_ERR(pl->next_bridge);
-		if (ret != -EPROBE_DEFER)
-			DRM_DEV_ERROR(dev, "failed to find next bridge: %d\n",
-				      ret);
-		return ret;
-	}
+	if (IS_ERR(pl->next_bridge))
+		return PTR_ERR(pl->next_bridge);
 
 	platform_set_drvdata(pdev, pl);
 

-- 
2.52.0



From luca.ceresoli at bootlin.com  Tue Dec 16 09:58:54 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Tue, 16 Dec 2025 18:58:54 +0100
Subject: [PATCH v3 21/22] drm/bridge: imx8qxp-pixel-link:
 imx8qxp_pixel_link_find_next_bridge: return int, not ERR_PTR
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
Message-ID: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-21-b5165fab8058@bootlin.com>

In preparation for using bridge->next_bridge, we need to ensure that it
will never contain anything but NULL or a valid bridge pointer. Current
code stores an ERR_PTR when imx8qxp_pixel_link_find_next_bridge() errors
out. Instead of fixing that after the facts in the caller, change the
function to internally set pl->next_bridge and just return an int error
value.

No functional changes.

Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
---
 drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
index 0c5ed06eee1b..91e4f4d55469 100644
--- a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
+++ b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
@@ -256,8 +256,7 @@ static int imx8qxp_pixel_link_disable_all_controls(struct imx8qxp_pixel_link *pl
 	return imx8qxp_pixel_link_disable_sync(pl);
 }
 
-static struct drm_bridge *
-imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
+static int imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
 {
 	struct device_node *np = pl->dev->of_node;
 	struct device_node *port;
@@ -282,7 +281,7 @@ imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
 
 	if (!found_port) {
 		DRM_DEV_ERROR(pl->dev, "no available output port\n");
-		return ERR_PTR(-ENODEV);
+		return -ENODEV;
 	}
 
 	for (reg = 0; reg < PL_MAX_NEXT_BRIDGES; reg++) {
@@ -300,7 +299,7 @@ imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
 
 		struct drm_bridge *next_bridge = of_drm_find_bridge(remote);
 		if (!next_bridge)
-			return ERR_PTR(-EPROBE_DEFER);
+			return -EPROBE_DEFER;
 
 		/*
 		 * Select the next bridge with companion PXL2DPI if
@@ -311,8 +310,9 @@ imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
 	}
 
 	pl->mst_addr = port_id - 1;
+	pl->next_bridge = selected_bridge;
 
-	return selected_bridge;
+	return 0;
 }
 
 static int imx8qxp_pixel_link_bridge_probe(struct platform_device *pdev)
@@ -368,9 +368,9 @@ static int imx8qxp_pixel_link_bridge_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	pl->next_bridge = imx8qxp_pixel_link_find_next_bridge(pl);
-	if (IS_ERR(pl->next_bridge))
-		return PTR_ERR(pl->next_bridge);
+	ret = imx8qxp_pixel_link_find_next_bridge(pl);
+	if (ret)
+		return ret;
 
 	platform_set_drvdata(pdev, pl);
 

-- 
2.52.0



From robh at kernel.org  Tue Dec 16 10:00:54 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Tue, 16 Dec 2025 12:00:54 -0600
Subject: [PATCH] arm64: dts: toshiba: Use recommended node names
Message-ID: <20251216180055.2793215-2-robh@kernel.org>

Update Toshiba TMPV7708 node name to the recommended standard node
names. Generally, node names and paths aren't considered ABI, so it
is safe to change them.

Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
---
SoC maintainers, Please take this directly.

 arch/arm64/boot/dts/toshiba/tmpv7708-rm-mbrc.dts      | 2 +-
 arch/arm64/boot/dts/toshiba/tmpv7708-visrobo-vrb.dts  | 2 +-
 arch/arm64/boot/dts/toshiba/tmpv7708-visrobo-vrc.dtsi | 2 +-
 arch/arm64/boot/dts/toshiba/tmpv7708.dtsi             | 4 ++--
 arch/arm64/boot/dts/toshiba/tmpv7708_pins.dtsi        | 2 +-
 5 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/boot/dts/toshiba/tmpv7708-rm-mbrc.dts b/arch/arm64/boot/dts/toshiba/tmpv7708-rm-mbrc.dts
index d209fdc98597..8d099b237025 100644
--- a/arch/arm64/boot/dts/toshiba/tmpv7708-rm-mbrc.dts
+++ b/arch/arm64/boot/dts/toshiba/tmpv7708-rm-mbrc.dts
@@ -43,7 +43,7 @@ &piether {
 	phy-handle = <&phy0>;
 	phy-mode = "rgmii-id";
 
-	mdio0 {
+	mdio {
 		#address-cells = <1>;
 		#size-cells = <0>;
 		compatible = "snps,dwmac-mdio";
diff --git a/arch/arm64/boot/dts/toshiba/tmpv7708-visrobo-vrb.dts b/arch/arm64/boot/dts/toshiba/tmpv7708-visrobo-vrb.dts
index ed7aa7e457b1..4439b3e8acbb 100644
--- a/arch/arm64/boot/dts/toshiba/tmpv7708-visrobo-vrb.dts
+++ b/arch/arm64/boot/dts/toshiba/tmpv7708-visrobo-vrb.dts
@@ -43,7 +43,7 @@ &piether {
 	phy-handle = <&phy0>;
 	phy-mode = "rgmii-id";
 
-	mdio0 {
+	mdio {
 		#address-cells = <1>;
 		#size-cells = <0>;
 		compatible = "snps,dwmac-mdio";
diff --git a/arch/arm64/boot/dts/toshiba/tmpv7708-visrobo-vrc.dtsi b/arch/arm64/boot/dts/toshiba/tmpv7708-visrobo-vrc.dtsi
index 0c8321022a73..af406f7285c4 100644
--- a/arch/arm64/boot/dts/toshiba/tmpv7708-visrobo-vrc.dtsi
+++ b/arch/arm64/boot/dts/toshiba/tmpv7708-visrobo-vrc.dtsi
@@ -26,7 +26,7 @@ &spi0_pins {
 &spi0 {
 	status = "okay";
 
-	mmc-slot at 0 {
+	mmc at 0 {
 		compatible = "mmc-spi-slot";
 		reg = <0>;
 		gpios = <&gpio 15 GPIO_ACTIVE_LOW>;
diff --git a/arch/arm64/boot/dts/toshiba/tmpv7708.dtsi b/arch/arm64/boot/dts/toshiba/tmpv7708.dtsi
index 9aa7b1872bd6..88e38d6efcaa 100644
--- a/arch/arm64/boot/dts/toshiba/tmpv7708.dtsi
+++ b/arch/arm64/boot/dts/toshiba/tmpv7708.dtsi
@@ -161,7 +161,7 @@ gic: interrupt-controller at 24001000 {
 			      <0 0x24006000 0 0x2000>;
 		};
 
-		pmux: pmux at 24190000 {
+		pmux: pinctrl at 24190000 {
 			compatible = "toshiba,tmpv7708-pinctrl";
 			reg = <0 0x24190000 0 0x10000>;
 		};
@@ -463,7 +463,7 @@ piether: ethernet at 28000000 {
 			status = "disabled";
 		};
 
-		wdt: wdt at 28330000 {
+		wdt: watchdog at 28330000 {
 			compatible = "toshiba,visconti-wdt";
 			reg = <0 0x28330000 0 0x1000>;
 			clocks = <&pismu TMPV770X_CLK_WDTCLK>;
diff --git a/arch/arm64/boot/dts/toshiba/tmpv7708_pins.dtsi b/arch/arm64/boot/dts/toshiba/tmpv7708_pins.dtsi
index a480c6ba5f5d..5ea835fe08a8 100644
--- a/arch/arm64/boot/dts/toshiba/tmpv7708_pins.dtsi
+++ b/arch/arm64/boot/dts/toshiba/tmpv7708_pins.dtsi
@@ -91,7 +91,7 @@ i2c8_pins: i2c8-pins {
 		bias-pull-up;
 	};
 
-	pwm_mux: pwm_mux {
+	pwm_mux: pwm-pins {
 		function = "pwm";
 	};
 
-- 
2.51.0



From luca.ceresoli at bootlin.com  Tue Dec 16 09:58:55 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Tue, 16 Dec 2025 18:58:55 +0100
Subject: [PATCH v3 22/22] drm/bridge: imx8qxp-pixel-link: get/put the next
 bridge
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
Message-ID: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-22-b5165fab8058@bootlin.com>

This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
function and stores it until driver removal. of_drm_find_bridge() is
deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
refcounted and use bridge->next_bridge to put the reference on
deallocation.

This needs to be handled in various steps:

 * the bridge returned of_drm_get_bridge() is stored in the local temporary
   variable next_bridge whose scope is the for loop, so a cleanup action is
   enough
 * the value of next_bridge is copied into selected_bridge, potentially
   more than once, so a cleanup action at function scope plus a
   drm_bridge_put() in case of reassignment are enough
 * on successful return selected_bridge is stored in bridge->next_bridge,
   which ensures it is put when the bridge is deallocated

Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
---
 drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
index 91e4f4d55469..b3050310a7f0 100644
--- a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
+++ b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
@@ -23,7 +23,6 @@
 
 struct imx8qxp_pixel_link {
 	struct drm_bridge bridge;
-	struct drm_bridge *next_bridge;
 	struct device *dev;
 	struct imx_sc_ipc *ipc_handle;
 	u8 stream_id;
@@ -140,7 +139,7 @@ static int imx8qxp_pixel_link_bridge_attach(struct drm_bridge *bridge,
 	}
 
 	return drm_bridge_attach(encoder,
-				 pl->next_bridge, bridge,
+				 pl->bridge.next_bridge, bridge,
 				 DRM_BRIDGE_ATTACH_NO_CONNECTOR);
 }
 
@@ -260,7 +259,7 @@ static int imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
 {
 	struct device_node *np = pl->dev->of_node;
 	struct device_node *port;
-	struct drm_bridge *selected_bridge = NULL;
+	struct drm_bridge *selected_bridge __free(drm_bridge_put) = NULL;
 	u32 port_id;
 	bool found_port = false;
 	int reg;
@@ -297,7 +296,8 @@ static int imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
 			continue;
 		}
 
-		struct drm_bridge *next_bridge = of_drm_find_bridge(remote);
+		struct drm_bridge *next_bridge __free(drm_bridge_put) =
+			of_drm_find_and_get_bridge(remote);
 		if (!next_bridge)
 			return -EPROBE_DEFER;
 
@@ -305,12 +305,14 @@ static int imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
 		 * Select the next bridge with companion PXL2DPI if
 		 * present, otherwise default to the first bridge
 		 */
-		if (!selected_bridge || of_property_present(remote, "fsl,companion-pxl2dpi"))
-			selected_bridge = next_bridge;
+		if (!selected_bridge || of_property_present(remote, "fsl,companion-pxl2dpi")) {
+			drm_bridge_put(selected_bridge);
+			selected_bridge = drm_bridge_get(next_bridge);
+		}
 	}
 
 	pl->mst_addr = port_id - 1;
-	pl->next_bridge = selected_bridge;
+	pl->bridge.next_bridge = drm_bridge_get(selected_bridge);
 
 	return 0;
 }

-- 
2.52.0



From jonathan.cameron at huawei.com  Tue Dec 16 10:01:18 2025
From: jonathan.cameron at huawei.com (Jonathan Cameron)
Date: Tue, 16 Dec 2025 18:01:18 +0000
Subject: [PATCH v1 03/13] arm64: mm: Implicitly invalidate user ASID
 based on TLBI operation
In-Reply-To: <20251216144601.2106412-4-ryan.roberts@arm.com>
References: <20251216144601.2106412-1-ryan.roberts@arm.com>
	<20251216144601.2106412-4-ryan.roberts@arm.com>
Message-ID: <20251216180118.00005085@huawei.com>

On Tue, 16 Dec 2025 14:45:48 +0000
Ryan Roberts <ryan.roberts at arm.com> wrote:

> When kpti is enabled, separate ASIDs are used for userspace and
> kernelspace, requiring ASID-qualified TLB invalidation by virtual
> address to invalidate both of them.
> 
> Push the logic for invalidating the two ASIDs down into the low-level
> tlbi-op-specific functions and remove the burden from the caller to
> handle the kpti-specific behaviour.
> 
> Co-developed-by: Will Deacon <will at kernel.org>
> Signed-off-by: Will Deacon <will at kernel.org>
> Signed-off-by: Ryan Roberts <ryan.roberts at arm.com>
> ---
>  arch/arm64/include/asm/tlbflush.h | 27 ++++++++++-----------------
>  1 file changed, 10 insertions(+), 17 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
> index c5111d2afc66..31f43d953ce2 100644
> --- a/arch/arm64/include/asm/tlbflush.h
> +++ b/arch/arm64/include/asm/tlbflush.h

> +#undef __tlbi_user
>  #endif
> -
Hi Ryan,

It's trivial Tuesday so... Unrelated white space change.

>  #endif



From robh at kernel.org  Tue Dec 16 10:02:02 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Tue, 16 Dec 2025 12:02:02 -0600
Subject: [PATCH] arm64: dts: cavium: Drop thunder2
Message-ID: <20251216180202.2794695-2-robh@kernel.org>

The Cavium thunder2 DT support
 is incomplete. It consists of 4 cores
(out of 128) and only a serial port. The thunder2 specific drivers in
the kernel don't have DT support either. The few remaining users of
this platform likely use ACPI.

Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
---
SoC maintainers, Please take this directly.

 arch/arm64/boot/dts/cavium/Makefile           |   1 -
 arch/arm64/boot/dts/cavium/thunder2-99xx.dts  |  30 ----
 arch/arm64/boot/dts/cavium/thunder2-99xx.dtsi | 144 ------------------
 3 files changed, 175 deletions(-)
 delete mode 100644 arch/arm64/boot/dts/cavium/thunder2-99xx.dts
 delete mode 100644 arch/arm64/boot/dts/cavium/thunder2-99xx.dtsi

diff --git a/arch/arm64/boot/dts/cavium/Makefile b/arch/arm64/boot/dts/cavium/Makefile
index c178f7e06e18..8a1854380993 100644
--- a/arch/arm64/boot/dts/cavium/Makefile
+++ b/arch/arm64/boot/dts/cavium/Makefile
@@ -1,3 +1,2 @@
 # SPDX-License-Identifier: GPL-2.0
 dtb-$(CONFIG_ARCH_THUNDER) += thunder-88xx.dtb
-dtb-$(CONFIG_ARCH_THUNDER2) += thunder2-99xx.dtb
diff --git a/arch/arm64/boot/dts/cavium/thunder2-99xx.dts b/arch/arm64/boot/dts/cavium/thunder2-99xx.dts
deleted file mode 100644
index 89fc4107a0c4..000000000000
--- a/arch/arm64/boot/dts/cavium/thunder2-99xx.dts
+++ /dev/null
@@ -1,30 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * dts file for Cavium ThunderX2 CN99XX Evaluation Platform
- *
- * Copyright (c) 2017 Cavium Inc.
- * Copyright (c) 2013-2016 Broadcom
- */
-
-/dts-v1/;
-
-#include "thunder2-99xx.dtsi"
-
-/ {
-	model = "Cavium ThunderX2 CN99XX";
-	compatible = "cavium,thunderx2-cn9900", "brcm,vulcan-soc";
-
-	memory at 80000000 {
-		device_type = "memory";
-		reg = <0x00000000 0x80000000 0x0 0x80000000>,  /* 2G @ 2G  */
-		      <0x00000008 0x80000000 0x0 0x80000000>;  /* 2G @ 34G */
-	};
-
-	aliases {
-		serial0 = &uart0;
-	};
-
-	chosen {
-		stdout-path = "serial0:115200n8";
-	};
-};
diff --git a/arch/arm64/boot/dts/cavium/thunder2-99xx.dtsi b/arch/arm64/boot/dts/cavium/thunder2-99xx.dtsi
deleted file mode 100644
index 966fb57280f3..000000000000
--- a/arch/arm64/boot/dts/cavium/thunder2-99xx.dtsi
+++ /dev/null
@@ -1,144 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * dtsi file for Cavium ThunderX2 CN99XX processor
- *
- * Copyright (c) 2017 Cavium Inc.
- * Copyright (c) 2013-2016 Broadcom
- * Author: Zi Shen Lim <zlim at broadcom.com>
- */
-
-#include <dt-bindings/interrupt-controller/arm-gic.h>
-
-/ {
-	model = "Cavium ThunderX2 CN99XX";
-	compatible = "cavium,thunderx2-cn9900", "brcm,vulcan-soc";
-	interrupt-parent = <&gic>;
-	#address-cells = <2>;
-	#size-cells = <2>;
-
-	/* just 4 cpus now, 128 needed in full config */
-	cpus {
-		#address-cells = <0x2>;
-		#size-cells = <0x0>;
-
-		cpu at 0 {
-			device_type = "cpu";
-			compatible = "cavium,thunder2", "brcm,vulcan";
-			reg = <0x0 0x0>;
-			enable-method = "psci";
-		};
-
-		cpu at 1 {
-			device_type = "cpu";
-			compatible = "cavium,thunder2", "brcm,vulcan";
-			reg = <0x0 0x1>;
-			enable-method = "psci";
-		};
-
-		cpu at 2 {
-			device_type = "cpu";
-			compatible = "cavium,thunder2", "brcm,vulcan";
-			reg = <0x0 0x2>;
-			enable-method = "psci";
-		};
-
-		cpu at 3 {
-			device_type = "cpu";
-			compatible = "cavium,thunder2", "brcm,vulcan";
-			reg = <0x0 0x3>;
-			enable-method = "psci";
-		};
-	};
-
-	psci {
-		compatible = "arm,psci-0.2";
-		method = "smc";
-	};
-
-	gic: interrupt-controller at 4000080000 {
-		compatible = "arm,gic-v3";
-		#interrupt-cells = <3>;
-		#address-cells = <2>;
-		#size-cells = <2>;
-		ranges;
-		interrupt-controller;
-		#redistributor-regions = <1>;
-		reg = <0x04 0x00080000 0x0 0x20000>,	/* GICD */
-		      <0x04 0x01000000 0x0 0x1000000>;	/* GICR */
-		interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
-
-		gicits: msi-controller at 4000100000 {
-			compatible = "arm,gic-v3-its";
-			msi-controller;
-			reg = <0x04 0x00100000 0x0 0x20000>;	/* GIC ITS */
-		};
-	};
-
-	timer {
-		compatible = "arm,armv8-timer";
-		interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_PPI 14 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_PPI 10 IRQ_TYPE_LEVEL_HIGH>;
-	};
-
-	pmu {
-		compatible = "brcm,vulcan-pmu";
-		interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH>; /* PMU overflow */
-	};
-
-	clk125mhz: uart_clk125mhz {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <125000000>;
-		clock-output-names = "clk125mhz";
-	};
-
-	pcie at 30000000 {
-		compatible = "pci-host-ecam-generic";
-		device_type = "pci";
-		#interrupt-cells = <1>;
-		#address-cells = <3>;
-		#size-cells = <2>;
-
-		/* ECAM at 0x3000_0000 - 0x4000_0000 */
-		reg = <0x0 0x30000000  0x0 0x10000000>;
-
-		/*
-		 * PCI ranges:
-		 *   IO		no supported
-		 *   MEM        0x4000_0000 - 0x6000_0000
-		 *   MEM64 pref 0x40_0000_0000 - 0x60_0000_0000
-		 */
-		ranges =
-		  <0x02000000    0 0x40000000    0 0x40000000    0 0x20000000
-		   0x43000000 0x40 0x00000000 0x40 0x00000000 0x20 0x00000000>;
-		bus-range = <0 0xff>;
-		interrupt-map-mask = <0 0 0 7>;
-		interrupt-map =
-		      /* addr  pin  ic   icaddr  icintr */
-			<0 0 0  1  &gic   0 0    GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH
-			 0 0 0  2  &gic   0 0    GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH
-			 0 0 0  3  &gic   0 0    GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH
-			 0 0 0  4  &gic   0 0    GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
-		msi-parent = <&gicits>;
-		dma-coherent;
-	};
-
-	soc {
-		compatible = "simple-bus";
-		#address-cells = <2>;
-		#size-cells = <2>;
-		ranges;
-
-		uart0: serial at 402020000 {
-			compatible = "arm,pl011", "arm,primecell";
-			reg = <0x04 0x02020000 0x0 0x1000>;
-			interrupt-parent = <&gic>;
-			interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&clk125mhz>, <&clk125mhz>;
-			clock-names = "uartclk", "apb_pclk";
-		};
-	};
-
-};
-- 
2.51.0



From sethjenkins at google.com  Tue Dec 16 10:13:49 2025
From: sethjenkins at google.com (Seth Jenkins)
Date: Tue, 16 Dec 2025 13:13:49 -0500
Subject: [RFC PATCH] arm64: Bring back linear map randomization using
 PArange override
In-Reply-To: <20251211040935.1288349-2-ardb@kernel.org>
References: <20251211040935.1288349-2-ardb@kernel.org>
Message-ID: <CALxfFW4gyv3gSc1JhkPNqk4LL6S6gZbDRJx2y21PFZ8-8_9s_A@mail.gmail.com>

> This is posted as an RFC because there are obvious shortcomings to this
> approach. However, before I spend more time on this, I'd like to gauge
> if there is any consensus that bringing this back is a good idea.
I may be a minority, but I do think bringing this back is a good idea.
It has now been 9+ years since hardware side channels for bypassing
KASLR were discovered, and it still appears that real-world attackers
overwhelmingly prefer alternative strategies - such as this one.

I'm under no illusion that if we just do this one thing KASLR will be
secure again, but I think this patch would still have a meaningful
real-world impact in terms of making exploits significantly harder to
write.


On Wed, Dec 10, 2025 at 11:10?PM Ard Biesheuvel <ardb at kernel.org> wrote:
>
> Commit
>
>   1db780bafa4ce ("arm64/mm: Remove randomization of the linear map")
>
> removed linear map randomization from the arm64 port, on the basis that
> a prior change to the logic rendered it non-functional on the majority
> of relevant CPU implementations.
>
> As has been reported numerous times now, the upshot of this is that the
> virtual addresses of statically allocated kernel data structures are
> highly predictable if the kernel is loaded at a known physical address.
> Any bootloader that still adheres to the original arm64 boot protocol,
> which stipulated that the kernel should be loaded at the lowest
> available physical address, is affected by this.
>
> So bring back the most recent version of linear map randomization, which
> is based on the CPU's physical address range, but this time, allow this
> PA range to be overridden on the kernel command line.
>
> E.g., by passing
>
>   id_aa64mmfr0.parange=1 # 36 bits
>   id_aa64mmfr0.parange=2 # 40 bits
>
> the CPU's supported physical range can be reduced to the point where
> linear map randomization becomes feasible again. It also means that
> nothing else is permitted to appear in that physical window, i.e.,
> hotplug memory but also non-memory peripherals, or stage-2 mappings on
> behalf of KVM guests.
>
> Signed-off-by: Ard Biesheuvel <ardb at kernel.org>
> ---
> Cc: Liz Prucka <lizprucka at google.com>
> Cc: Seth Jenkins <sethjenkins at google.com>
>
> This is posted as an RFC because there are obvious shortcomings to this
> approach. However, before I spend more time on this, I'd like to gauge
> if there is any consensus that bringing this back is a good idea.
>
>  arch/arm64/include/asm/cpufeature.h   | 13 +++++++++++++
>  arch/arm64/kernel/image-vars.h        |  1 +
>  arch/arm64/kernel/kaslr.c             |  2 ++
>  arch/arm64/kernel/pi/idreg-override.c |  1 +
>  arch/arm64/kernel/pi/kaslr_early.c    |  4 ++++
>  arch/arm64/mm/init.c                  | 16 ++++++++++++++++
>  6 files changed, 37 insertions(+)
>
> diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
> index 4de51f8d92cb..fdb1331c406d 100644
> --- a/arch/arm64/include/asm/cpufeature.h
> +++ b/arch/arm64/include/asm/cpufeature.h
> @@ -1078,6 +1078,19 @@ static inline bool cpu_has_lpa2(void)
>  #endif
>  }
>
> +static inline u64 cpu_get_phys_range(void)
> +{
> +       u64 mmfr0 = read_sysreg(id_aa64mmfr0_el1);
> +
> +       mmfr0 &= ~id_aa64mmfr0_override.mask;
> +       mmfr0 |= id_aa64mmfr0_override.val;
> +
> +       int parange = cpuid_feature_extract_unsigned_field(mmfr0,
> +                                               ID_AA64MMFR0_EL1_PARANGE_SHIFT);
> +
> +       return BIT(id_aa64mmfr0_parange_to_phys_shift(parange));
> +}
> +
>  #endif /* __ASSEMBLER__ */
>
>  #endif
> diff --git a/arch/arm64/kernel/image-vars.h b/arch/arm64/kernel/image-vars.h
> index 85bc629270bd..263543ad6155 100644
> --- a/arch/arm64/kernel/image-vars.h
> +++ b/arch/arm64/kernel/image-vars.h
> @@ -58,6 +58,7 @@ PI_EXPORT_SYM(id_aa64zfr0_override);
>  PI_EXPORT_SYM(arm64_sw_feature_override);
>  PI_EXPORT_SYM(arm64_use_ng_mappings);
>  PI_EXPORT_SYM(_ctype);
> +PI_EXPORT_SYM(memstart_offset_seed);
>
>  PI_EXPORT_SYM(swapper_pg_dir);
>
> diff --git a/arch/arm64/kernel/kaslr.c b/arch/arm64/kernel/kaslr.c
> index c9503ed45a6c..1da3e25f9d9e 100644
> --- a/arch/arm64/kernel/kaslr.c
> +++ b/arch/arm64/kernel/kaslr.c
> @@ -10,6 +10,8 @@
>  #include <asm/cpufeature.h>
>  #include <asm/memory.h>
>
> +u16 __initdata memstart_offset_seed;
> +
>  bool __ro_after_init __kaslr_is_enabled = false;
>
>  void __init kaslr_init(void)
> diff --git a/arch/arm64/kernel/pi/idreg-override.c b/arch/arm64/kernel/pi/idreg-override.c
> index bc57b290e5e7..a8351ba70300 100644
> --- a/arch/arm64/kernel/pi/idreg-override.c
> +++ b/arch/arm64/kernel/pi/idreg-override.c
> @@ -43,6 +43,7 @@ static const struct ftr_set_desc mmfr0 __prel64_initconst = {
>         .override       = &id_aa64mmfr0_override,
>         .fields         = {
>                 FIELD("ecv", ID_AA64MMFR0_EL1_ECV_SHIFT, NULL),
> +               FIELD("parange", ID_AA64MMFR0_EL1_PARANGE_SHIFT, NULL),
>                 {}
>         },
>  };
> diff --git a/arch/arm64/kernel/pi/kaslr_early.c b/arch/arm64/kernel/pi/kaslr_early.c
> index e0e018046a46..0257b43819db 100644
> --- a/arch/arm64/kernel/pi/kaslr_early.c
> +++ b/arch/arm64/kernel/pi/kaslr_early.c
> @@ -18,6 +18,8 @@
>
>  #include "pi.h"
>
> +extern u16 memstart_offset_seed;
> +
>  static u64 __init get_kaslr_seed(void *fdt, int node)
>  {
>         static char const seed_str[] __initconst = "kaslr-seed";
> @@ -51,6 +53,8 @@ u64 __init kaslr_early_init(void *fdt, int chosen)
>                         return 0;
>         }
>
> +       memstart_offset_seed = seed & U16_MAX;
> +
>         /*
>          * OK, so we are proceeding with KASLR enabled. Calculate a suitable
>          * kernel image offset from the seed. Let's place the kernel in the
> diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
> index 524d34a0e921..6c55eca6ccad 100644
> --- a/arch/arm64/mm/init.c
> +++ b/arch/arm64/mm/init.c
> @@ -275,6 +275,22 @@ void __init arm64_memblock_init(void)
>                 }
>         }
>
> +       if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
> +               extern u16 memstart_offset_seed;
> +               s64 range = linear_region_size - cpu_get_phys_range();
> +
> +               /*
> +                * If the size of the linear region exceeds, by a sufficient
> +                * margin, the size of the region that the physical memory can
> +                * span, randomize the linear region as well.
> +                */
> +               if (memstart_offset_seed > 0 && range >= (s64)ARM64_MEMSTART_ALIGN) {
> +                       range /= ARM64_MEMSTART_ALIGN;
> +                       memstart_addr -= ARM64_MEMSTART_ALIGN *
> +                                        ((range * memstart_offset_seed) >> 16);
> +               }
> +       }
> +
>         /*
>          * Register the kernel text, kernel data, initrd, and initial
>          * pagetables with memblock.
> --
> 2.47.3
>


From dan.carpenter at linaro.org  Tue Dec 16 10:30:08 2025
From: dan.carpenter at linaro.org (Dan Carpenter)
Date: Tue, 16 Dec 2025 21:30:08 +0300
Subject: [PATCH v2 0/4] s32g: Use a syscon for GPR
In-Reply-To: <aUFvvmDUai9QrhZ2@lizhi-Precision-Tower-5810>
References: <cover.1765806521.git.dan.carpenter@linaro.org>
 <aUAvwRmIZBC0W6ql@lizhi-Precision-Tower-5810>
 <aUBUkuLf7NHtLSl1@stanley.mountain>
 <aUBha2/xiZsIF/o5@lizhi-Precision-Tower-5810>
 <aUBrV2_Iv4oTPkC4@stanley.mountain>
 <aUB4pFEwmMBzW52T@lizhi-Precision-Tower-5810>
 <aUEQkuzSZXFs5nqr@stanley.mountain>
 <aUFvvmDUai9QrhZ2@lizhi-Precision-Tower-5810>
Message-ID: <aUGlMP7J19L_AHF2@stanley.mountain>

On Tue, Dec 16, 2025 at 09:42:06AM -0500, Frank Li wrote:
> > >
> > > Why not implement standard phy interface,
> > > phy_set_mode_ext(PHY_MODE_ETHERNET, RGMII);
> > >
> > > For example:  drivers/pci/controller/dwc/pci-imx6.c
> > >
> > > In legency platform, it use syscon to set some registers. It becomes mess
> > > when more platform added.  And it becomes hard to convert because avoid
> > > break compatibltiy now.
> > >
> > > It doesn't become worse since new platforms switched to use standard
> > > inteface, (phy, reset ...).
> > >
> >
> > This happens below that layer, this is just saying where the registers
> > are found.  The GMAC_0_CTRL_STS is just one register in the GPR region,
> > most of the others are unrelated to PHY.
> 
> The other register should work as other function's providor with mfd.
> 

Syscons are a really standard way to do register accesses.  The
pci-imx6.c driver you mentioned earlier does it that way...  The only
thing which my code does differently is I put the offset into the
phandle, but that's not so unusual and it's arguably a cleaner way
because now both the base address and offset are in the same file.

regards,
dan carpenter



From robh at kernel.org  Tue Dec 16 11:12:12 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Tue, 16 Dec 2025 13:12:12 -0600
Subject: [PATCH] ARM: dts: vexpress/v2m-rs1: Use documented arm,vexpress,config-bus child node names
Message-ID: <20251216191212.2879226-2-robh@kernel.org>

Update the arm,vexpress,config-bus child node names to use the
documented ones. Most of these were updated a while back, but I missed
these.

Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
---
SoC maintainers may want to take this directly?

 arch/arm/boot/dts/arm/vexpress-v2m-rs1.dtsi | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boot/dts/arm/vexpress-v2m-rs1.dtsi b/arch/arm/boot/dts/arm/vexpress-v2m-rs1.dtsi
index 158b3923eae3..248b8e492d43 100644
--- a/arch/arm/boot/dts/arm/vexpress-v2m-rs1.dtsi
+++ b/arch/arm/boot/dts/arm/vexpress-v2m-rs1.dtsi
@@ -420,7 +420,7 @@ mcc {
 					compatible = "arm,vexpress,config-bus";
 					arm,vexpress,config-bridge = <&v2m_sysreg>;
 
-					oscclk0 {
+					clock-controller-0 {
 						/* MCC static memory clock */
 						compatible = "arm,vexpress-osc";
 						arm,vexpress-sysreg,func = <1 0>;
@@ -429,7 +429,7 @@ oscclk0 {
 						clock-output-names = "v2m:oscclk0";
 					};
 
-					v2m_oscclk1: oscclk1 {
+					v2m_oscclk1: clock-controller-1 {
 						/* CLCD clock */
 						compatible = "arm,vexpress-osc";
 						arm,vexpress-sysreg,func = <1 1>;
@@ -438,7 +438,7 @@ v2m_oscclk1: oscclk1 {
 						clock-output-names = "v2m:oscclk1";
 					};
 
-					v2m_oscclk2: oscclk2 {
+					v2m_oscclk2: clock-controller-2 {
 						/* IO FPGA peripheral clock */
 						compatible = "arm,vexpress-osc";
 						arm,vexpress-sysreg,func = <1 2>;
@@ -447,7 +447,7 @@ v2m_oscclk2: oscclk2 {
 						clock-output-names = "v2m:oscclk2";
 					};
 
-					volt-vio {
+					regulator-vio {
 						/* Logic level voltage */
 						compatible = "arm,vexpress-volt";
 						arm,vexpress-sysreg,func = <2 0>;
-- 
2.51.0



From nicolinc at nvidia.com  Tue Dec 16 11:14:42 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Tue, 16 Dec 2025 11:14:42 -0800
Subject: [PATCH v7 6/7] iommu/arm-smmu-v3: Add arm_smmu_invs based
 arm_smmu_domain_inv_range()
In-Reply-To: <20251216141511.GD6079@nvidia.com>
References: <cover.1765850465.git.nicolinc@nvidia.com>
 <f4261c5b30ce3c6942470433033d4933ec5eef3e.1765850465.git.nicolinc@nvidia.com>
 <20251216090926.GR3707837@noisy.programming.kicks-ass.net>
 <20251216135613.GB6079@nvidia.com>
 <20251216140410.GV3707837@noisy.programming.kicks-ass.net>
 <20251216141511.GD6079@nvidia.com>
Message-ID: <aUGvojnCaMKWM6QG@Asurada-Nvidia>

On Tue, Dec 16, 2025 at 10:15:11AM -0400, Jason Gunthorpe wrote:
> This also has a pre-existing dma_wmb(), a fuller chart would be like this:
> 
>    arm_smmu_domain_inv_range() 		arm_smmu_install_new_domain_invs()
>  
>      [W] IOPTE				  [Wrel] smmu_domain->invs
>      smp_mb()				  smp_mb()  <--- arm_smmu_install_new_domain_invs()
> 					  [build the STE]
> 					  [post the STE]
> 					  dma_wmb() <--- arm_smmu_cmdq_issue_cmdlist()
>                                           Doorbell Write to Device
>      [Lacq] smmu_domain->invs		  [L] IOPTE via DMA
> 
> Nicolin, please elabortate more of these details in the comment.

Ack. I will add the chart above.

Thanks
Nicolin


From cleger at rivosinc.com  Tue Dec 16 12:36:21 2025
From: cleger at rivosinc.com (=?UTF-8?B?Q2zDqW1lbnQgTMOpZ2Vy?=)
Date: Tue, 16 Dec 2025 21:36:21 +0100
Subject: [External] [PATCH v8 4/5] perf: RISC-V: add support for SSE event
In-Reply-To: <CAEEQ3wnQiUdNVjUpdDgAx1=y76vSo66vCD0Wf3EGes274jnkxw@mail.gmail.com>
References: <20251105082639.342973-1-cleger@rivosinc.com> <20251105082639.342973-5-cleger@rivosinc.com>
 <CAEEQ3wnQiUdNVjUpdDgAx1=y76vSo66vCD0Wf3EGes274jnkxw@mail.gmail.com>
Message-ID: <CADGDLFgnx3z9WMZBjURx7eEFeeDwb9tj+8WAik4siR_G8erk0Q@mail.gmail.com>

On Fri, Dec 12, 2025 at 4:17?AM yunhui cui <cuiyunhui at bytedance.com> wrote:
>
> Hi Cl?ment,
>
> On Wed, Nov 5, 2025 at 4:29?PM Cl?ment L?ger <cleger at rivosinc.com> wrote:
> >
> > In order to use SSE within PMU drivers, register a SSE handler for the
> > local PMU event. Reuse the existing overflow IRQ handler and pass
> > appropriate pt_regs. Add a config option RISCV_PMU_SSE to select event
> > delivery via SSE events.
> >
> > Signed-off-by: Cl?ment L?ger <cleger at rivosinc.com>
> > ---
> >  drivers/perf/Kconfig           | 10 +++++
> >  drivers/perf/riscv_pmu.c       | 23 +++++++++++
> >  drivers/perf/riscv_pmu_sbi.c   | 71 +++++++++++++++++++++++++++++-----
> >  include/linux/perf/riscv_pmu.h |  5 +++
> >  4 files changed, 99 insertions(+), 10 deletions(-)
> >
> > diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig
> > index 638321fc9800..d6ffc2b036e5 100644
> > --- a/drivers/perf/Kconfig
> > +++ b/drivers/perf/Kconfig
> > @@ -105,6 +105,16 @@ config RISCV_PMU_SBI
> >           full perf feature support i.e. counter overflow, privilege mode
> >           filtering, counter configuration.
> >
> > +config RISCV_PMU_SBI_SSE
> > +       depends on RISCV_PMU && RISCV_SBI_SSE
> > +       bool "RISC-V PMU SSE events"
> > +       default n
> > +       help
> > +         Say y if you want to use SSE events to deliver PMU interrupts. This
> > +         provides a way to profile the kernel at any level by using NMI-like
> > +         SSE events. SSE events being really intrusive, this option allows
> > +         to select it only if needed.
> > +
> >  config STARFIVE_STARLINK_PMU
> >         depends on ARCH_STARFIVE || COMPILE_TEST
> >         depends on 64BIT
> > diff --git a/drivers/perf/riscv_pmu.c b/drivers/perf/riscv_pmu.c
> > index 7644147d50b4..dda2814801c0 100644
> > --- a/drivers/perf/riscv_pmu.c
> > +++ b/drivers/perf/riscv_pmu.c
> > @@ -13,6 +13,7 @@
> >  #include <linux/irqdesc.h>
> >  #include <linux/perf/riscv_pmu.h>
> >  #include <linux/printk.h>
> > +#include <linux/riscv_sbi_sse.h>
> >  #include <linux/smp.h>
> >  #include <linux/sched_clock.h>
> >
> > @@ -254,6 +255,24 @@ void riscv_pmu_start(struct perf_event *event, int flags)
> >         perf_event_update_userpage(event);
> >  }
> >
> > +#ifdef CONFIG_RISCV_PMU_SBI_SSE
> > +static void riscv_pmu_disable(struct pmu *pmu)
> > +{
> > +       struct riscv_pmu *rvpmu = to_riscv_pmu(pmu);
> > +
> > +       if (rvpmu->sse_evt)
> > +               sse_event_disable_local(rvpmu->sse_evt);
> > +}
> > +
> > +static void riscv_pmu_enable(struct pmu *pmu)
> > +{
> > +       struct riscv_pmu *rvpmu = to_riscv_pmu(pmu);
> > +
> > +       if (rvpmu->sse_evt)
> > +               sse_event_enable_local(rvpmu->sse_evt);
> > +}
> > +#endif
> > +
> >  static int riscv_pmu_add(struct perf_event *event, int flags)
> >  {
> >         struct riscv_pmu *rvpmu = to_riscv_pmu(event->pmu);
> > @@ -411,6 +430,10 @@ struct riscv_pmu *riscv_pmu_alloc(void)
> >                 .event_mapped   = riscv_pmu_event_mapped,
> >                 .event_unmapped = riscv_pmu_event_unmapped,
> >                 .event_idx      = riscv_pmu_event_idx,
> > +#ifdef CONFIG_RISCV_PMU_SBI_SSE
> > +               .pmu_enable     = riscv_pmu_enable,
> > +               .pmu_disable    = riscv_pmu_disable,
> > +#endif
> >                 .add            = riscv_pmu_add,
> >                 .del            = riscv_pmu_del,
> >                 .start          = riscv_pmu_start,
> > diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
> > index e255c1b069ec..c852f64a5022 100644
> > --- a/drivers/perf/riscv_pmu_sbi.c
> > +++ b/drivers/perf/riscv_pmu_sbi.c
> > @@ -17,6 +17,7 @@
> >  #include <linux/irqdomain.h>
> >  #include <linux/of_irq.h>
> >  #include <linux/of.h>
> > +#include <linux/riscv_sbi_sse.h>
> >  #include <linux/cpu_pm.h>
> >  #include <linux/sched/clock.h>
> >  #include <linux/soc/andes/irq.h>
> > @@ -1038,10 +1039,10 @@ static void pmu_sbi_start_overflow_mask(struct riscv_pmu *pmu,
> >                 pmu_sbi_start_ovf_ctrs_sbi(cpu_hw_evt, ctr_ovf_mask);
> >  }
> >
> > -static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
> > +static irqreturn_t pmu_sbi_ovf_handler(struct cpu_hw_events *cpu_hw_evt,
> > +                                      struct pt_regs *regs, bool from_sse)
> >  {
> >         struct perf_sample_data data;
> > -       struct pt_regs *regs;
> >         struct hw_perf_event *hw_evt;
> >         union sbi_pmu_ctr_info *info;
> >         int lidx, hidx, fidx;
> > @@ -1049,7 +1050,6 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
> >         struct perf_event *event;
> >         u64 overflow;
> >         u64 overflowed_ctrs = 0;
> > -       struct cpu_hw_events *cpu_hw_evt = dev;
> >         u64 start_clock = sched_clock();
> >         struct riscv_pmu_snapshot_data *sdata = cpu_hw_evt->snapshot_addr;
> >
> > @@ -1059,13 +1059,15 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
> >         /* Firmware counter don't support overflow yet */
> >         fidx = find_first_bit(cpu_hw_evt->used_hw_ctrs, RISCV_MAX_COUNTERS);
> >         if (fidx == RISCV_MAX_COUNTERS) {
> > -               csr_clear(CSR_SIP, BIT(riscv_pmu_irq_num));
> > +               if (!from_sse)
> > +                       csr_clear(CSR_SIP, BIT(riscv_pmu_irq_num));
> >                 return IRQ_NONE;
> >         }
> >
> >         event = cpu_hw_evt->events[fidx];
> >         if (!event) {
> > -               ALT_SBI_PMU_OVF_CLEAR_PENDING(riscv_pmu_irq_mask);
> > +               if (!from_sse)
> > +                       ALT_SBI_PMU_OVF_CLEAR_PENDING(riscv_pmu_irq_mask);
> >                 return IRQ_NONE;
> >         }
> >
> > @@ -1080,16 +1082,16 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
> >
> >         /*
> >          * Overflow interrupt pending bit should only be cleared after stopping
> > -        * all the counters to avoid any race condition.
> > +        * all the counters to avoid any race condition. When using SSE,
> > +        * interrupt is cleared when stopping counters.
> >          */
> > -       ALT_SBI_PMU_OVF_CLEAR_PENDING(riscv_pmu_irq_mask);
> > +       if (!from_sse)
> > +               ALT_SBI_PMU_OVF_CLEAR_PENDING(riscv_pmu_irq_mask);
> >
> >         /* No overflow bit is set */
> >         if (!overflow)
> >                 return IRQ_NONE;
> >
> > -       regs = get_irq_regs();
> > -
> >         for_each_set_bit(lidx, cpu_hw_evt->used_hw_ctrs, RISCV_MAX_COUNTERS) {
> >                 struct perf_event *event = cpu_hw_evt->events[lidx];
> >
> > @@ -1145,6 +1147,51 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
> >         return IRQ_HANDLED;
> >  }
> >
> > +static irqreturn_t pmu_sbi_ovf_irq_handler(int irq, void *dev)
> > +{
> > +       return pmu_sbi_ovf_handler(dev, get_irq_regs(), false);
> > +}
> > +
> > +#ifdef CONFIG_RISCV_PMU_SBI_SSE
> > +static int pmu_sbi_ovf_sse_handler(u32 evt, void *arg, struct pt_regs *regs)
> > +{
> > +       struct cpu_hw_events __percpu *hw_events = arg;
> > +       struct cpu_hw_events *hw_event = raw_cpu_ptr(hw_events);
> > +
> > +       pmu_sbi_ovf_handler(hw_event, regs, true);
> > +
> > +       return 0;
> > +}
> > +
> > +static int pmu_sbi_setup_sse(struct riscv_pmu *pmu)
> > +{
> > +       int ret;
> > +       struct sse_event *evt;
> > +       struct cpu_hw_events __percpu *hw_events = pmu->hw_events;
> > +
> > +       evt = sse_event_register(SBI_SSE_EVENT_LOCAL_PMU_OVERFLOW, 0,
> > +                                pmu_sbi_ovf_sse_handler, hw_events);
>
> As Radim suggested, we had better preset a priority for different
> events, such as these events and future ones:
> SBI_SSE_EVENT_LOCAL_HIGH_PRIO_RAS
> SBI_SSE_EVENT_LOCAL_DOUBLE_TRAP
> SBI_SSE_EVENT_GLOBAL_HIGH_PRIO_RAS
> SBI_SSE_EVENT_LOCAL_PMU_OVERFLOW
> SBI_SSE_EVENT_LOCAL_LOW_PRIO_RAS
> SBI_SSE_EVENT_GLOBAL_LOW_PRIO_RAS
> SBI_SSE_EVENT_LOCAL_SOFTWARE_INJECTED
> SBI_SSE_EVENT_LOCAL_UNKNOWN_NMI
> SBI_SSE_EVENT_GLOBAL_SOFTWARE_INJECTED

Hey Yunhui,

What do you mean exactly ? Events have default priority based on their
ID. However, the register call will set a priority = 0 for the event.
I'll modify that to allow using an optional priority (or even remove
it)

Thanks,

Cl?ment

>
> Could you please help add a "global priority enum"?
>
>
> > +       if (IS_ERR(evt))
> > +               return PTR_ERR(evt);
> > +
> > +       ret = sse_event_enable(evt);
> > +       if (ret) {
> > +               sse_event_unregister(evt);
> > +               return ret;
> > +       }
> > +
> > +       pr_info("using SSE for PMU event delivery\n");
> > +       pmu->sse_evt = evt;
> > +
> > +       return ret;
> > +}
> > +#else
> > +static int pmu_sbi_setup_sse(struct riscv_pmu *pmu)
> > +{
> > +       return -EOPNOTSUPP;
> > +}
> > +#endif
> > +
> >  static int pmu_sbi_starting_cpu(unsigned int cpu, struct hlist_node *node)
> >  {
> >         struct riscv_pmu *pmu = hlist_entry_safe(node, struct riscv_pmu, node);
> > @@ -1195,6 +1242,10 @@ static int pmu_sbi_setup_irqs(struct riscv_pmu *pmu, struct platform_device *pde
> >         struct cpu_hw_events __percpu *hw_events = pmu->hw_events;
> >         struct irq_domain *domain = NULL;
> >
> > +       ret = pmu_sbi_setup_sse(pmu);
> > +       if (!ret)
> > +               return 0;
> > +
> >         if (riscv_isa_extension_available(NULL, SSCOFPMF)) {
> >                 riscv_pmu_irq_num = RV_IRQ_PMU;
> >                 riscv_pmu_use_irq = true;
> > @@ -1229,7 +1280,7 @@ static int pmu_sbi_setup_irqs(struct riscv_pmu *pmu, struct platform_device *pde
> >                 return -ENODEV;
> >         }
> >
> > -       ret = request_percpu_irq(riscv_pmu_irq, pmu_sbi_ovf_handler, "riscv-pmu", hw_events);
> > +       ret = request_percpu_irq(riscv_pmu_irq, pmu_sbi_ovf_irq_handler, "riscv-pmu", hw_events);
> >         if (ret) {
> >                 pr_err("registering percpu irq failed [%d]\n", ret);
> >                 return ret;
> > diff --git a/include/linux/perf/riscv_pmu.h b/include/linux/perf/riscv_pmu.h
> > index f82a28040594..08fdcf6baf4e 100644
> > --- a/include/linux/perf/riscv_pmu.h
> > +++ b/include/linux/perf/riscv_pmu.h
> > @@ -28,6 +28,8 @@
> >
> >  #define RISCV_PMU_CONFIG1_GUEST_EVENTS 0x1
> >
> > +struct sse_event;
> > +
> >  struct cpu_hw_events {
> >         /* currently enabled events */
> >         int                     n_events;
> > @@ -54,6 +56,9 @@ struct riscv_pmu {
> >         char            *name;
> >
> >         irqreturn_t     (*handle_irq)(int irq_num, void *dev);
> > +#ifdef CONFIG_RISCV_PMU_SBI_SSE
> > +       struct sse_event *sse_evt;
> > +#endif
> >
> >         unsigned long   cmask;
> >         u64             (*ctr_read)(struct perf_event *event);
> > --
> > 2.43.0
> >
>
> Thanks,
> Yunhui


From irogers at google.com  Tue Dec 16 12:39:15 2025
From: irogers at google.com (Ian Rogers)
Date: Tue, 16 Dec 2025 12:39:15 -0800
Subject: [PATCH v3 03/12] perf parse-events: Track all user changed config bits
In-Reply-To: <20251212-james-perf-config-bits-v3-3-aa36a4846776@linaro.org>
References: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org> <20251212-james-perf-config-bits-v3-3-aa36a4846776@linaro.org>
Message-ID: <CAP-5=fUBSOHcK5rjJgyJed3PkgLb_dMys_qDNu=Cy_18faLX_Q@mail.gmail.com>

On Fri, Dec 12, 2025 at 7:32?AM James Clark <james.clark at linaro.org> wrote:
>
> Currently we only track which bits were set by the user in attr->config.
> But all configN fields should be treated equally as they can all have
> default and user overridden values.
>
> Track them all by making get_config_chgs() generic and calling it once
> for each config value.
>
> Signed-off-by: James Clark <james.clark at linaro.org>
> ---
>  tools/perf/util/evsel.c        |  6 ++-
>  tools/perf/util/evsel_config.h |  6 ++-
>  tools/perf/util/parse-events.c | 98 +++++++++++++++++++++++-------------------
>  tools/perf/util/pmu.c          |  2 +-
>  4 files changed, 65 insertions(+), 47 deletions(-)
>
> diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
> index 9cd706f6279313c2cc53eba1adbd45f352090f75..dcadf022405d398bf394b3da7f0db5c81a3ec268 100644
> --- a/tools/perf/util/evsel.c
> +++ b/tools/perf/util/evsel.c
> @@ -1242,7 +1242,11 @@ static void evsel__apply_config_terms(struct evsel *evsel,
>                 case EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE:
>                         /* Already applied by auxtrace */
>                         break;
> -               case EVSEL__CONFIG_TERM_CFG_CHG:
> +               case EVSEL__CONFIG_TERM_USR_CHG_CONFIG:
> +               case EVSEL__CONFIG_TERM_USR_CHG_CONFIG1:
> +               case EVSEL__CONFIG_TERM_USR_CHG_CONFIG2:
> +               case EVSEL__CONFIG_TERM_USR_CHG_CONFIG3:
> +               case EVSEL__CONFIG_TERM_USR_CHG_CONFIG4:
>                         break;
>                 case EVSEL__CONFIG_TERM_RATIO_TO_PREV:
>                         rtp_buf = term->val.str;
> diff --git a/tools/perf/util/evsel_config.h b/tools/perf/util/evsel_config.h
> index 685fd8d5c4a88fb8ae601ded60c1fc36dde73403..7b565d76c0bc4277effbbf950110986b423f571c 100644
> --- a/tools/perf/util/evsel_config.h
> +++ b/tools/perf/util/evsel_config.h
> @@ -27,7 +27,11 @@ enum evsel_term_type {
>         EVSEL__CONFIG_TERM_AUX_OUTPUT,
>         EVSEL__CONFIG_TERM_AUX_ACTION,
>         EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE,
> -       EVSEL__CONFIG_TERM_CFG_CHG,
> +       EVSEL__CONFIG_TERM_USR_CHG_CONFIG,
> +       EVSEL__CONFIG_TERM_USR_CHG_CONFIG1,
> +       EVSEL__CONFIG_TERM_USR_CHG_CONFIG2,
> +       EVSEL__CONFIG_TERM_USR_CHG_CONFIG3,
> +       EVSEL__CONFIG_TERM_USR_CHG_CONFIG4,
>         EVSEL__CONFIG_TERM_RATIO_TO_PREV,
>  };
>
> diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
> index 46422286380f33a48087e7079a45bb21beb2d573..7ef63b808d0542999fd1303b9f94cae68e38030f 100644
> --- a/tools/perf/util/parse-events.c
> +++ b/tools/perf/util/parse-events.c
> @@ -1253,66 +1253,32 @@ static int get_config_terms(const struct parse_events_terms *head_config,
>         return 0;
>  }
>
> -/*
> - * Add EVSEL__CONFIG_TERM_CFG_CHG where cfg_chg will have a bit set for
> - * each bit of attr->config that the user has changed.
> - */
> -static int get_config_chgs(struct perf_pmu *pmu, struct parse_events_terms *head_config,
> -                          struct list_head *head_terms)
> +static int add_cfg_chg(struct perf_pmu *pmu,
> +                      struct parse_events_terms *head_config,

nit: the head_config could be made const here.

> +                      struct list_head *head_terms,
> +                      int format_type,
> +                      enum parse_events__term_type term_type,
> +                      enum evsel_term_type new_term_type)
>  {
>         struct parse_events_term *term;
>         u64 bits = 0;
>         int type;
>
>         list_for_each_entry(term, &head_config->terms, list) {
> -               switch (term->type_term) {
> -               case PARSE_EVENTS__TERM_TYPE_USER:
> +               if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER) {
>                         type = perf_pmu__format_type(pmu, term->config);
> -                       if (type != PERF_PMU_FORMAT_VALUE_CONFIG)
> +                       if (type != format_type)
>                                 continue;
>                         bits |= perf_pmu__format_bits(pmu, term->config);
> -                       break;
> -               case PARSE_EVENTS__TERM_TYPE_CONFIG:
> +               } else if (term->type_term == term_type) {
>                         bits = ~(u64)0;
> -                       break;
> -               case PARSE_EVENTS__TERM_TYPE_CONFIG1:
> -               case PARSE_EVENTS__TERM_TYPE_CONFIG2:
> -               case PARSE_EVENTS__TERM_TYPE_CONFIG3:
> -               case PARSE_EVENTS__TERM_TYPE_CONFIG4:
> -               case PARSE_EVENTS__TERM_TYPE_LEGACY_HARDWARE_CONFIG:
> -               case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE_CONFIG:
> -               case PARSE_EVENTS__TERM_TYPE_NAME:
> -               case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
> -               case PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ:
> -               case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
> -               case PARSE_EVENTS__TERM_TYPE_TIME:
> -               case PARSE_EVENTS__TERM_TYPE_CALLGRAPH:
> -               case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
> -               case PARSE_EVENTS__TERM_TYPE_NOINHERIT:
> -               case PARSE_EVENTS__TERM_TYPE_INHERIT:
> -               case PARSE_EVENTS__TERM_TYPE_MAX_STACK:
> -               case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS:
> -               case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE:
> -               case PARSE_EVENTS__TERM_TYPE_OVERWRITE:
> -               case PARSE_EVENTS__TERM_TYPE_DRV_CFG:
> -               case PARSE_EVENTS__TERM_TYPE_PERCORE:
> -               case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT:
> -               case PARSE_EVENTS__TERM_TYPE_AUX_ACTION:
> -               case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE:
> -               case PARSE_EVENTS__TERM_TYPE_METRIC_ID:
> -               case PARSE_EVENTS__TERM_TYPE_RAW:
> -               case PARSE_EVENTS__TERM_TYPE_CPU:
> -               case PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV:
> -               default:
> -                       break;
>                 }
>         }
>
>         if (bits) {
>                 struct evsel_config_term *new_term;
>
> -               new_term = add_config_term(EVSEL__CONFIG_TERM_CFG_CHG,
> -                                          head_terms, false);
> +               new_term = add_config_term(new_term_type, head_terms, false);
>                 if (!new_term)
>                         return -ENOMEM;
>                 new_term->val.cfg_chg = bits;
> @@ -1321,6 +1287,50 @@ static int get_config_chgs(struct perf_pmu *pmu, struct parse_events_terms *head
>         return 0;
>  }
>
> +/*
> + * Add EVSEL__CONFIG_TERM_USR_CFG_CONFIGn where cfg_chg will have a bit set for
> + * each bit of attr->configN that the user has changed.
> + */
> +static int get_config_chgs(struct perf_pmu *pmu,
> +                          struct parse_events_terms *head_config,
> +                          struct list_head *head_terms)
> +{
> +       int ret;
> +
> +       ret = add_cfg_chg(pmu, head_config, head_terms,
> +                         PERF_PMU_FORMAT_VALUE_CONFIG,
> +                         PARSE_EVENTS__TERM_TYPE_CONFIG,
> +                         EVSEL__CONFIG_TERM_USR_CHG_CONFIG);
> +       if (ret)
> +               return ret;
> +
> +       ret = add_cfg_chg(pmu, head_config, head_terms,
> +                         PERF_PMU_FORMAT_VALUE_CONFIG1,
> +                         PARSE_EVENTS__TERM_TYPE_CONFIG1,
> +                         EVSEL__CONFIG_TERM_USR_CHG_CONFIG1);
> +       if (ret)
> +               return ret;
> +
> +       ret = add_cfg_chg(pmu, head_config, head_terms,
> +                         PERF_PMU_FORMAT_VALUE_CONFIG2,
> +                         PARSE_EVENTS__TERM_TYPE_CONFIG2,
> +                         EVSEL__CONFIG_TERM_USR_CHG_CONFIG2);
> +       if (ret)
> +               return ret;
> +
> +       ret = add_cfg_chg(pmu, head_config, head_terms,
> +                         PERF_PMU_FORMAT_VALUE_CONFIG3,
> +                         PARSE_EVENTS__TERM_TYPE_CONFIG3,
> +                         EVSEL__CONFIG_TERM_USR_CHG_CONFIG3);
> +       if (ret)
> +               return ret;
> +
> +       return add_cfg_chg(pmu, head_config, head_terms,
> +                          PERF_PMU_FORMAT_VALUE_CONFIG4,
> +                          PARSE_EVENTS__TERM_TYPE_CONFIG4,
> +                          EVSEL__CONFIG_TERM_USR_CHG_CONFIG4);
> +}
> +
>  int parse_events_add_tracepoint(struct parse_events_state *parse_state,
>                                 struct list_head *list,
>                                 const char *sys, const char *event,
> diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
> index 2c26c8d76bed920c7b5b43beb867e4d1bcaa2970..e02f74d4020c151082ecc434c29c0ec4c2c9b2c8 100644
> --- a/tools/perf/util/pmu.c
> +++ b/tools/perf/util/pmu.c
> @@ -1387,7 +1387,7 @@ void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
>                                 const char *config_name, u64 val)
>  {
>         u64 user_bits = 0, bits;
> -       struct evsel_config_term *term = evsel__get_config_term(evsel, CFG_CHG);
> +       struct evsel_config_term *term = evsel__get_config_term(evsel, USR_CHG_CONFIG);
>
>         if (term)
>                 user_bits = term->val.cfg_chg;
>
> --
> 2.34.1
>


From irogers at google.com  Tue Dec 16 12:44:40 2025
From: irogers at google.com (Ian Rogers)
Date: Tue, 16 Dec 2025 12:44:40 -0800
Subject: [PATCH v3 05/12] perf evsel: Add a helper to get the value of a
 config field
In-Reply-To: <20251212-james-perf-config-bits-v3-5-aa36a4846776@linaro.org>
References: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org> <20251212-james-perf-config-bits-v3-5-aa36a4846776@linaro.org>
Message-ID: <CAP-5=fUbr56hFd7e7yt33-gnhEGGa72GLmShQ5bCHxQjFAbFCQ@mail.gmail.com>

On Fri, Dec 12, 2025 at 7:32?AM James Clark <james.clark at linaro.org> wrote:
>
> This will be used by aux PMUs to read an already written value for
> configuring their events and for also testing.
>
> Its helper pmu_format_unpack() does the opposite of the existing
> pmu_format_value() so rename that one to pmu_format_pack() so it's clear
> how they are related.
>
> Signed-off-by: James Clark <james.clark at linaro.org>
> ---
>  tools/perf/util/evsel.h |  2 ++
>  tools/perf/util/pmu.c   | 77 ++++++++++++++++++++++++++++++++++++++++++-------
>  2 files changed, 68 insertions(+), 11 deletions(-)
>
> diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
> index a08130ff2e47a887b19f6c47bfa9f51e0c40d226..092904a61ec7afdc59253f9b78a9fe8b7cb5bfa7 100644
> --- a/tools/perf/util/evsel.h
> +++ b/tools/perf/util/evsel.h
> @@ -575,6 +575,8 @@ void evsel__uniquify_counter(struct evsel *counter);
>         ((((src) >> (pos)) & ((1ull << (size)) - 1)) << (63 - ((pos) + (size) - 1)))
>
>  u64 evsel__bitfield_swap_branch_flags(u64 value);
> +int evsel__get_config_val(struct perf_pmu *pmu, struct evsel *evsel,
> +                         const char *config_name, u64 *val);
>  void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
>                                 const char *config_name, u64 val);
>
> diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
> index 514cba91f5d99b399d2d6a1e350971660c54a9fc..ef7358ad1fb955f29f2e68b3d0ce711754e4d67c 100644
> --- a/tools/perf/util/pmu.c
> +++ b/tools/perf/util/pmu.c
> @@ -144,8 +144,8 @@ struct perf_pmu_format {
>  };
>
>  static int pmu_aliases_parse(struct perf_pmu *pmu);
> -static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
> -                            bool zero);
> +static void pmu_format_pack(unsigned long *format, __u64 value, __u64 *v,
> +                           bool zero);
>  static struct perf_pmu_format *pmu_find_format(const struct list_head *formats,
>                                                const char *name);
>
> @@ -1377,6 +1377,61 @@ bool evsel__is_aux_event(const struct evsel *evsel)
>         return pmu && pmu->auxtrace;
>  }
>
> +/*
> + * Unpacks a raw config[n] value using the sparse bitfield that defines a
> + * format attr. For example "config1:1,6-7,44" defines a 4 bit value across non
> + * contiguous bits and this function returns those 4 bits as a value.
> + */
> +static u64 pmu_format_unpack(u64 format, u64 config_val)
> +{
> +       int val_bit = 0;
> +       u64 res = 0;
> +       int fmt_bit;
> +
> +       for_each_set_bit(fmt_bit, &format, PERF_PMU_FORMAT_BITS) {
> +               if (test_bit(fmt_bit, &config_val))
> +                       res |= BIT_ULL(val_bit);
> +
> +               val_bit++;
> +       }
> +       return res;
> +}
> +
> +int evsel__get_config_val(struct perf_pmu *pmu, struct evsel *evsel,
> +                         const char *config_name, u64 *val)

nits:
This is an evsel__ function but the evsel is the 2nd argument not the first.
Why pass the PMU and not just read evsel->pmu (or better evsel__find_pmu) ?
Why not place this in evsel.c to match the header file declaration?
The evsel could be likely be const.

Thanks,
Ian

> +{
> +       struct perf_pmu_format *format = pmu_find_format(&pmu->format, config_name);
> +       u64 bits = perf_pmu__format_bits(pmu, config_name);
> +
> +       if (!format || !bits) {
> +               pr_err("Unknown/empty format name: %s\n", config_name);
> +               *val = 0;
> +               return -EINVAL;
> +       }
> +
> +       switch (format->value) {
> +       case PERF_PMU_FORMAT_VALUE_CONFIG:
> +               *val = pmu_format_unpack(bits, evsel->core.attr.config);
> +               return 0;
> +       case PERF_PMU_FORMAT_VALUE_CONFIG1:
> +               *val = pmu_format_unpack(bits, evsel->core.attr.config1);
> +               return 0;
> +       case PERF_PMU_FORMAT_VALUE_CONFIG2:
> +               *val = pmu_format_unpack(bits, evsel->core.attr.config2);
> +               return 0;
> +       case PERF_PMU_FORMAT_VALUE_CONFIG3:
> +               *val = pmu_format_unpack(bits, evsel->core.attr.config3);
> +               return 0;
> +       case PERF_PMU_FORMAT_VALUE_CONFIG4:
> +               *val = pmu_format_unpack(bits, evsel->core.attr.config4);
> +               return 0;
> +       default:
> +               pr_err("Unknown format value: %d\n", format->value);
> +               *val = 0;
> +               return -EINVAL;
> +       }
> +}
> +
>  /*
>   * Set @config_name to @val as long as the user hasn't already set or cleared it
>   * by passing a config term on the command line.
> @@ -1432,7 +1487,7 @@ void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
>                 return;
>
>         /* Otherwise replace it */
> -       pmu_format_value(&bits, val, vp, /*zero=*/true);
> +       pmu_format_pack(&bits, val, vp, /*zero=*/true);
>  }
>
>  static struct perf_pmu_format *
> @@ -1477,8 +1532,8 @@ int perf_pmu__format_type(struct perf_pmu *pmu, const char *name)
>   * Sets value based on the format definition (format parameter)
>   * and unformatted value (value parameter).
>   */
> -static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
> -                            bool zero)
> +static void pmu_format_pack(unsigned long *format, __u64 value, __u64 *v,
> +                           bool zero)
>  {
>         unsigned long fbit, vbit;
>
> @@ -1595,23 +1650,23 @@ static int pmu_config_term(const struct perf_pmu *pmu,
>                 switch (term->type_term) {
>                 case PARSE_EVENTS__TERM_TYPE_CONFIG:
>                         assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
> -                       pmu_format_value(bits, term->val.num, &attr->config, zero);
> +                       pmu_format_pack(bits, term->val.num, &attr->config, zero);
>                         break;
>                 case PARSE_EVENTS__TERM_TYPE_CONFIG1:
>                         assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
> -                       pmu_format_value(bits, term->val.num, &attr->config1, zero);
> +                       pmu_format_pack(bits, term->val.num, &attr->config1, zero);
>                         break;
>                 case PARSE_EVENTS__TERM_TYPE_CONFIG2:
>                         assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
> -                       pmu_format_value(bits, term->val.num, &attr->config2, zero);
> +                       pmu_format_pack(bits, term->val.num, &attr->config2, zero);
>                         break;
>                 case PARSE_EVENTS__TERM_TYPE_CONFIG3:
>                         assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
> -                       pmu_format_value(bits, term->val.num, &attr->config3, zero);
> +                       pmu_format_pack(bits, term->val.num, &attr->config3, zero);
>                         break;
>                 case PARSE_EVENTS__TERM_TYPE_CONFIG4:
>                         assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
> -                       pmu_format_value(bits, term->val.num, &attr->config4, zero);
> +                       pmu_format_pack(bits, term->val.num, &attr->config4, zero);
>                         break;
>                 case PARSE_EVENTS__TERM_TYPE_LEGACY_HARDWARE_CONFIG:
>                         assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
> @@ -1749,7 +1804,7 @@ static int pmu_config_term(const struct perf_pmu *pmu,
>                  */
>         }
>
> -       pmu_format_value(format->bits, val, vp, zero);
> +       pmu_format_pack(format->bits, val, vp, zero);
>         return 0;
>  }
>
>
> --
> 2.34.1
>


From nicolinc at nvidia.com  Tue Dec 16 12:46:59 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Tue, 16 Dec 2025 12:46:59 -0800
Subject: [PATCH rc v3 1/4] iommu/arm-smmu-v3: Add ignored bits to fix STE
 update sequence
In-Reply-To: <20251216000952.GA6079@nvidia.com>
References: <cover.1765334526.git.nicolinc@nvidia.com>
 <cc0d4ab571e2e789ee1cddfa035379dc54f0601b.1765334526.git.nicolinc@nvidia.com>
 <aT87A1ur4htPjM5T@google.com>
 <20251216000952.GA6079@nvidia.com>
Message-ID: <aUHFQ1Ep2x4/vdk/@Asurada-Nvidia>

On Mon, Dec 15, 2025 at 08:09:52PM -0400, Jason Gunthorpe wrote:
> On Sun, Dec 14, 2025 at 10:32:35PM +0000, Mostafa Saleh wrote:
> > However, this approach makes it a bit explicit which bits are ignored, if we
> > keep this logic, I think changing the name of get_ignored() might help, to
> > something as "get_allowed_break()" or "get_update_safe()"?
> 
> update_safe sounds good to me

I have renamed the op and changed entry_set to void. I'll send v4
later today.

Thanks
Nicolin


From detlev.casanova at collabora.com  Tue Dec 16 12:48:45 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Tue, 16 Dec 2025 15:48:45 -0500
Subject: [PATCH v5 01/15] media: uapi: HEVC: Add
 v4l2_ctrl_hevc_ext_sps_[ls]t_rps controls
In-Reply-To: <d8ef0f88-e81d-4159-8945-52197cbc95ba@kernel.org>
References: <20251023214247.459931-1-detlev.casanova@collabora.com>
 <20251023214247.459931-2-detlev.casanova@collabora.com>
 <d8ef0f88-e81d-4159-8945-52197cbc95ba@kernel.org>
Message-ID: <37da2fe3-41bd-470e-bb6c-93fe35ee1528@collabora.com>

Hi Hans,

On 10/24/25 03:55, Hans Verkuil wrote:
> On 23/10/2025 23:42, Detlev Casanova wrote:
>> Some hardware (e.g.: Rockchip's rk3588 hevc decoder) need the
>> long and short term reference information for HEVC decoding.
>>
>> Add controls to provide it as the raw data form the stream.
>>
>> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
>> ---
>>   .../media/v4l/ext-ctrls-codec-stateless.rst   | 114 ++++++++++++++++++
>>   .../media/v4l/videodev2.h.rst.exceptions      |   2 +
>>   .../media/v4l/vidioc-queryctrl.rst            |  12 ++
>>   3 files changed, 128 insertions(+)
>>
>> diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst
>> index 497ae74379f6..7b18e12fafbb 100644
>> --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst
>> +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst
>> @@ -2959,6 +2959,120 @@ This structure contains all loop filter related parameters. See sections
>>         - 0x00000004
>>         -
>>   
>> +``V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS (struct)``
>> +    Specifies the list of Long-Term reference sets parameters from the SPS.
>> +    These parameters are defined according to :ref:`hevc`.
>> +    They are described in section 7.4.3.2.1 "General sequence parameter set
>> +    RBSP semantics" of the specification.
>> +    This control is a dynamically sized 1-dimensional array,
>> +    V4L2_CTRL_FLAG_DYNAMIC_ARRAY flag must be set when using it.
> I'd drop this last sentence. It suggests that the application has to set it,
> but is it set by the kernel.
>
> Same for the next control below.
>
> I noticed that this is probably a copy-and-paste from the V4L2_CID_STATELESS_HEVC_SLICE_PARAMS
> documentation: can you post a separate patch removing that same line from the description of
> that control? I think it is a confusing line, and we missed it during the original review
> of V4L2_CID_STATELESS_HEVC_SLICE_PARAMS.
>
> I have another question about these two controls: currently dynamic controls have always at
> least one element. I have been working on supporting zero-sized dynamic controls. Would
> that make sense here? Or will these two controls - if present - always have one element or
> more?
>
> If zero-length dynamic array controls are useful here, then I can clean up my patches and
> post them so you can use it.

I guess that could happen depending on what userspace does, but the size 
of the array is determined by num_long_term_ref_pics_sps and 
num_short_term_ref_pic_sets from v4l2_ctrl_hevc_sps respectively.

If that value is 0, there is no point in setting the (respective) 
control, except for simplifying userspace code I suppose.

So 0-length support is avoidable.

Detlev.

> Regards,
>
> 	Hans
>
>> +
>> +.. c:type:: v4l2_ctrl_hevc_ext_sps_lt_rps
>> +
>> +.. cssclass:: longtable
>> +
>> +.. flat-table:: struct v4l2_ctrl_hevc_ext_sps_lt_rps
>> +    :header-rows:  0
>> +    :stub-columns: 0
>> +    :widths:       1 1 2
>> +
>> +    * - __u16
>> +      - ``lt_ref_pic_poc_lsb_sps``
>> +      - Long term reference picture order count as described in section 7.4.3.2.1
>> +        "General sequence parameter set RBSP semantics" of the specification.
>> +    * - __u8
>> +      - ``flags``
>> +      - See :ref:`Extended Long-Term RPS Flags <hevc_ext_sps_lt_rps_flags>`
>> +
>> +.. _hevc_ext_sps_lt_rps_flags:
>> +
>> +``Extended SPS Long-Term RPS Flags``
>> +
>> +.. cssclass:: longtable
>> +
>> +.. flat-table::
>> +    :header-rows:  0
>> +    :stub-columns: 0
>> +    :widths:       1 1 2
>> +
>> +    * - ``V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_USED_LT``
>> +      - 0x00000001
>> +      - Specifies if the long-term reference picture is used 7.4.3.2.1 "General sequence parameter
>> +        set RBSP semantics" of the specification.
>> +
>> +``V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS (struct)``
>> +    Specifies the list of Short-Term reference sets parameters from the SPS.
>> +    These parameters are defined according to :ref:`hevc`.
>> +    They are described in section 7.4.8 "Short-term reference picture set
>> +    semantics" of the specification.
>> +    This control is a dynamically sized 1-dimensional array,
>> +    V4L2_CTRL_FLAG_DYNAMIC_ARRAY flag must be set when using it.
>> +
>> +.. c:type:: v4l2_ctrl_hevc_ext_sps_st_rps
>> +
>> +.. cssclass:: longtable
>> +
>> +.. flat-table:: struct v4l2_ctrl_hevc_ext_sps_st_rps
>> +    :header-rows:  0
>> +    :stub-columns: 0
>> +    :widths:       1 1 2
>> +
>> +    * - __u8
>> +      - ``delta_idx_minus1``
>> +      - Specifies the delta compare to the index. See details in section 7.4.8 "Short-term
>> +        reference picture set semantics" of the specification.
>> +    * - __u8
>> +      - ``delta_rps_sign``
>> +      - Sign of the delta as specified in section 7.4.8 "Short-term reference picture set
>> +        semantics" of the specification.
>> +    * - __u16
>> +      - ``abs_delta_rps_minus1``
>> +      - Absolute delta RPS as specified in section 7.4.8 "Short-term reference picture set
>> +        semantics" of the specification.
>> +    * - __u8
>> +      - ``num_negative_pics``
>> +      - Number of short-term RPS entries that have picture order count values less than the
>> +        picture order count value of the current picture.
>> +    * - __u8
>> +      - ``num_positive_pics``
>> +      - Number of short-term RPS entries that have picture order count values greater than the
>> +        picture order count value of the current picture.
>> +    * - __u32
>> +      - ``used_by_curr_pic``
>> +      - Bit i specifies if short-term RPS i is used by the current picture.
>> +    * - __u32
>> +      - ``use_delta_flag``
>> +      - Bit i specifies if short-term RPS i is included in the short-term RPS entries.
>> +    * - __u16
>> +      - ``delta_poc_s0_minus1[16]``
>> +      - Specifies the negative picture order count delta for the i-th entry in the short-term RPS.
>> +        See details in section 7.4.8 "Short-term reference picture set semantics" of the
>> +        specification.
>> +    * - __u16
>> +      - ``delta_poc_s1_minus1[16]``
>> +      - Specifies the positive picture order count delta for the i-th entry in the short-term RPS.
>> +        See details in section 7.4.8 "Short-term reference picture set semantics" of the
>> +        specification.
>> +    * - __u8
>> +      - ``flags``
>> +      - See :ref:`Extended Short-Term RPS Flags <hevc_ext_sps_st_rps_flags>`
>> +
>> +.. _hevc_ext_sps_st_rps_flags:
>> +
>> +``Extended SPS Short-Term RPS Flags``
>> +
>> +.. cssclass:: longtable
>> +
>> +.. flat-table::
>> +    :header-rows:  0
>> +    :stub-columns: 0
>> +    :widths:       1 1 2
>> +
>> +    * - ``V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED``
>> +      - 0x00000001
>> +      - Specifies if the short-term RPS is predicted from another short term RPS. See details in
>> +        section 7.4.8 "Short-term reference picture set semantics" of the specification.
>> +
>>   .. _v4l2-codec-stateless-av1:
>>   
>>   ``V4L2_CID_STATELESS_AV1_SEQUENCE (struct)``
>> diff --git a/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions b/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions
>> index c41693115db6..6182b4e2d2ee 100644
>> --- a/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions
>> +++ b/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions
>> @@ -150,6 +150,8 @@ replace symbol V4L2_CTRL_TYPE_H264_SCALING_MATRIX :c:type:`V4L.v4l2_ctrl_type`
>>   replace symbol V4L2_CTRL_TYPE_H264_PRED_WEIGHTS :c:type:`V4L.v4l2_ctrl_type`
>>   replace symbol V4L2_CTRL_TYPE_H264_SLICE_PARAMS :c:type:`V4L.v4l2_ctrl_type`
>>   replace symbol V4L2_CTRL_TYPE_H264_DECODE_PARAMS :c:type:`V4L.v4l2_ctrl_type`
>> +replace symbol V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS :c:type:`V4L.v4l2_ctrl_type`
>> +replace symbol V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS :c:type:`V4L.v4l2_ctrl_type`
>>   replace symbol V4L2_CTRL_TYPE_HEVC_SPS :c:type:`V4L.v4l2_ctrl_type`
>>   replace symbol V4L2_CTRL_TYPE_HEVC_PPS :c:type:`V4L.v4l2_ctrl_type`
>>   replace symbol V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS :c:type:`V4L.v4l2_ctrl_type`
>> diff --git a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
>> index c8baa9430c14..82c8b52e771c 100644
>> --- a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
>> +++ b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
>> @@ -531,6 +531,18 @@ See also the examples in :ref:`control`.
>>         - n/a
>>         - A struct :c:type:`v4l2_ctrl_hevc_decode_params`, containing HEVC
>>   	decoding parameters for stateless video decoders.
>> +    * - ``V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS``
>> +      - n/a
>> +      - n/a
>> +      - n/a
>> +      - A struct :c:type:`v4l2_ctrl_hevc_ext_sps_lt_rps`, containing HEVC
>> +	extended Long-Term RPS for stateless video decoders.
>> +    * - ``V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS``
>> +      - n/a
>> +      - n/a
>> +      - n/a
>> +      - A struct :c:type:`v4l2_ctrl_hevc_ext_sps_st_rps`, containing HEVC
>> +	extended Short-Term RPS for stateless video decoders.
>>       * - ``V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR``
>>         - n/a
>>         - n/a


From mathieu.poirier at linaro.org  Tue Dec 16 12:53:42 2025
From: mathieu.poirier at linaro.org (Mathieu Poirier)
Date: Tue, 16 Dec 2025 13:53:42 -0700
Subject: [PATCH] remoteproc: imx_rproc: Use strstarts for "rsc-table"
 check
In-Reply-To: <20251208233302.684139-1-shenwei.wang@nxp.com>
References: <20251208233302.684139-1-shenwei.wang@nxp.com>
Message-ID: <aUHG1svhft249rn8@p14s>

On Mon, Dec 08, 2025 at 05:33:02PM -0600, Shenwei Wang wrote:
> The resource name may include an address suffix, for example:
> rsc-table at 1fff8000.
> 
> To handle such cases, use strstarts() instead of strcmp() when checking
> for "rsc-table".
> 
> Signed-off-by: Shenwei Wang <shenwei.wang at nxp.com>
> ---
>  drivers/remoteproc/imx_rproc.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>

Applied.

Thanks,
Mathieu
 
> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
> index 3be8790c14a2..33f21ab24c92 100644
> --- a/drivers/remoteproc/imx_rproc.c
> +++ b/drivers/remoteproc/imx_rproc.c
> @@ -694,7 +694,7 @@ static int imx_rproc_addr_init(struct imx_rproc *priv,
>  		}
>  		priv->mem[b].sys_addr = res.start;
>  		priv->mem[b].size = resource_size(&res);
> -		if (!strcmp(res.name, "rsc-table"))
> +		if (strstarts(res.name, "rsc-table"))
>  			priv->rsc_table = priv->mem[b].cpu_addr;
>  		b++;
>  	}
> -- 
> 2.43.0
> 


From nicolas at ndufresne.ca  Tue Dec 16 12:57:27 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Tue, 16 Dec 2025 15:57:27 -0500
Subject: [PATCH v11 01/12] media: mediatek: jpeg: fix jpeg hw count
 setting
In-Reply-To: <20251202094800.6140-2-kyrie.wu@mediatek.com>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
	 <20251202094800.6140-2-kyrie.wu@mediatek.com>
Message-ID: <cd4c9c6f89d2ad506113745f4273ff6e6b65c75a.camel@ndufresne.ca>

Hi,

Le mardi 02 d?cembre 2025 ? 17:47 +0800, Kyrie Wu a ?crit?:
> Different ICs have different amounts of hardware,
> use a variable to set the amount of hardware.

Did you mean different amount of cores ? The use of "hardware" is strange in
this description.

> 
> Fixes: 934e8bccac95 ("mtk-jpegenc: support jpegenc multi-hardware")
> Fixes: 0fa49df4222f ("media: mtk-jpegdec: support jpegdec multi-hardware")

Its not clear from your description if this is in preparation of MT8196 or an
actual fix. If its in preparation of, drop this, if it fixes some existing SoC,
please tell use which one. And tell us how it breaks without this fix.

regards,
Nicolas

> 
> Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
> Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
> ---
> ?drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c?? | 8 ++++----
> ?drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h?? | 2 ++
> ?drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c | 1 +
> ?drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c | 1 +
> ?4 files changed, 8 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> index 6268d651bdcf..6a7e01130f1c 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> @@ -1467,7 +1467,7 @@ static int mtk_jpegenc_get_hw(struct mtk_jpeg_ctx *ctx)
> ?	int i;
> ?
> ?	spin_lock_irqsave(&jpeg->hw_lock, flags);
> -	for (i = 0; i < MTK_JPEGENC_HW_MAX; i++) {
> +	for (i = 0; i < jpeg->max_hw_count; i++) {
> ?		comp_jpeg = jpeg->enc_hw_dev[i];
> ?		if (comp_jpeg->hw_state == MTK_JPEG_HW_IDLE) {
> ?			hw_id = i;
> @@ -1514,7 +1514,7 @@ static int mtk_jpegdec_get_hw(struct mtk_jpeg_ctx *ctx)
> ?	int i;
> ?
> ?	spin_lock_irqsave(&jpeg->hw_lock, flags);
> -	for (i = 0; i < MTK_JPEGDEC_HW_MAX; i++) {
> +	for (i = 0; i < jpeg->max_hw_count; i++) {
> ?		comp_jpeg = jpeg->dec_hw_dev[i];
> ?		if (comp_jpeg->hw_state == MTK_JPEG_HW_IDLE) {
> ?			hw_id = i;
> @@ -1597,7 +1597,7 @@ static void mtk_jpegenc_worker(struct work_struct *work)
> ?		jpeg_work);
> ?	struct mtk_jpeg_dev *jpeg = ctx->jpeg;
> ?
> -	for (i = 0; i < MTK_JPEGENC_HW_MAX; i++)
> +	for (i = 0; i < jpeg->max_hw_count; i++)
> ?		comp_jpeg[i] = jpeg->enc_hw_dev[i];
> ?	i = 0;
> ?
> @@ -1692,7 +1692,7 @@ static void mtk_jpegdec_worker(struct work_struct *work)
> ?	struct mtk_jpeg_fb fb;
> ?	unsigned long flags;
> ?
> -	for (i = 0; i < MTK_JPEGDEC_HW_MAX; i++)
> +	for (i = 0; i < jpeg->max_hw_count; i++)
> ?		comp_jpeg[i] = jpeg->dec_hw_dev[i];
> ?	i = 0;
> ?
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> index 02ed0ed5b736..6be5cf30dea1 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> @@ -212,6 +212,7 @@ struct mtk_jpegdec_comp_dev {
> ? * @reg_decbase:	jpg decode register base addr
> ? * @dec_hw_dev:	jpg decode hardware device
> ? * @hw_index:		jpg hw index
> + * @max_hw_count:	jpeg hw-core count
> ? */
> ?struct mtk_jpeg_dev {
> ?	struct mutex		lock;
> @@ -234,6 +235,7 @@ struct mtk_jpeg_dev {
> ?	void __iomem *reg_decbase[MTK_JPEGDEC_HW_MAX];
> ?	struct mtk_jpegdec_comp_dev *dec_hw_dev[MTK_JPEGDEC_HW_MAX];
> ?	atomic_t hw_index;
> +	u32 max_hw_count;
> ?};
> ?
> ?/**
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> index e78e1d11093c..a1e54715cb7e 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> @@ -664,6 +664,7 @@ static int mtk_jpegdec_hw_probe(struct platform_device *pdev)
> ?	master_dev->dec_hw_dev[i] = dev;
> ?	master_dev->reg_decbase[i] = dev->reg_base;
> ?	dev->master_dev = master_dev;
> +	master_dev->max_hw_count++;
> ?
> ?	platform_set_drvdata(pdev, dev);
> ?	pm_runtime_enable(&pdev->dev);
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> index 9ab27aee302a..28d05909c96f 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> @@ -386,6 +386,7 @@ static int mtk_jpegenc_hw_probe(struct platform_device *pdev)
> ?	master_dev->enc_hw_dev[i] = dev;
> ?	master_dev->reg_encbase[i] = dev->reg_base;
> ?	dev->master_dev = master_dev;
> +	master_dev->max_hw_count++;
> ?
> ?	platform_set_drvdata(pdev, dev);
> ?	pm_runtime_enable(&pdev->dev);
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251216/4de5083f/attachment.sig>

From irogers at google.com  Tue Dec 16 13:00:32 2025
From: irogers at google.com (Ian Rogers)
Date: Tue, 16 Dec 2025 13:00:32 -0800
Subject: [PATCH v3 00/12] perf cs-etm/arm-spe: Remove hard coded config fields
In-Reply-To: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
References: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
Message-ID: <CAP-5=fXrLck7XACML16hzQO-pHGXA+qAM69kDDC6Za4O5S=SmA@mail.gmail.com>

On Fri, Dec 12, 2025 at 7:32?AM James Clark <james.clark at linaro.org> wrote:
>
> The specific config field that an event format attribute is in is
> consistently hard coded, even though the API is supposed to be that the
> driver publishes the config field name. To stop this pattern from being
> copy pasted and causing problems in the future, replace them all with
> calls to a new helper that returns the value that a user set.
>
> This reveals some issues in evsel__set_config_if_unset(). It doesn't
> work with sparse bitfields, which are an unused but documented feature.
> And it also only writes to the attr.config field. To fix it we need to
> start tracking user changes for all config fields and then use existing
> helper functions that support sparse bitfields. Some other refactoring
> was also required and a test was added.
>
> Signed-off-by: James Clark <james.clark at linaro.org>

Outside of some nits, for the series:
Reviewed-by: Ian Rogers <irogers at google.com>

Thanks,
Ian

> ---
> Changes in v3:
> - Fix uninitialized variable warning on GCC
> - Fix leak of evlist in test
> - Confirm no type punning issues with ubsan (Ian)
> - Link to v2: https://lore.kernel.org/r/20251208-james-perf-config-bits-v2-0-4ac0281993b0 at linaro.org
>
> Changes in v2:
> - Remove macros in get_config_chgs() and some other refactoring.
> - Support sparse bitfields in evsel__set_config_if_unset().
> - Always track user changes instead of only when
>   'pmu->perf_event_attr_init_default' is set.
> - Add a test.
> - Don't bail out in cs-etm.c if any format fields are missing (Leo).
> - Rename 'guess' to 'synth' (Mike).
> - Link to v1: https://lore.kernel.org/r/20251201-james-perf-config-bits-v1-0-22ecbbf8007c at linaro.org
>
> ---
> James Clark (12):
>       perf parse-events: Refactor get_config_terms() to remove macros
>       perf evsel: Support sparse fields in evsel__set_config_if_unset()
>       perf parse-events: Track all user changed config bits
>       perf evsel: apply evsel__set_config_if_unset() to all config fields
>       perf evsel: Add a helper to get the value of a config field
>       perf parse-events: Always track user config changes
>       perf tests: Test evsel__set_config_if_unset() and config change tracking
>       perf cs-etm: Make a helper to find the Coresight evsel
>       perf cs-etm: Don't use hard coded config bits when setting up ETMCR
>       perf cs-etm: Don't use hard coded config bits when setting up TRCCONFIGR
>       perf cs-etm: Don't hard code config attribute when configuring the event
>       perf arm-spe: Don't hard code config attribute
>
>  tools/perf/arch/arm/util/cs-etm.c    | 193 +++++++++++++++------------
>  tools/perf/arch/arm64/util/arm-spe.c |  15 ++-
>  tools/perf/tests/pmu.c               |  91 +++++++++++++
>  tools/perf/util/evsel.c              |   6 +-
>  tools/perf/util/evsel.h              |   2 +
>  tools/perf/util/evsel_config.h       |   7 +-
>  tools/perf/util/parse-events.c       | 248 ++++++++++++++++++++---------------
>  tools/perf/util/pmu.c                | 112 ++++++++++++++--
>  8 files changed, 460 insertions(+), 214 deletions(-)
> ---
> base-commit: 2eeb09fe1c5173b659929f92fee4461796ca8c14
> change-id: 20251112-james-perf-config-bits-bee7106f0f00
>
> Best regards,
> --
> James Clark <james.clark at linaro.org>
>


From irogers at google.com  Tue Dec 16 13:03:52 2025
From: irogers at google.com (Ian Rogers)
Date: Tue, 16 Dec 2025 13:03:52 -0800
Subject: [PATCH 1/2] perf mem: Simplify Arm SPE event config
In-Reply-To: <6a642215-2834-4c27-b716-477d5444ad9c@linaro.org>
References: <20251212-perf_c2c_update_event-v1-0-29a26c7a949b@arm.com>
 <20251212-perf_c2c_update_event-v1-1-29a26c7a949b@arm.com> <6a642215-2834-4c27-b716-477d5444ad9c@linaro.org>
Message-ID: <CAP-5=fWB7QxTvtEY6_9DBoQ23J471zvrRz+z6TYgNk3eJOWGRg@mail.gmail.com>

On Fri, Dec 12, 2025 at 7:18?AM James Clark <james.clark at linaro.org> wrote:
>
> On 12/12/2025 14:44, Leo Yan wrote:
> > Since configuration fields default to zero, the zero assignments are
> > redundant, remove them.
> >
> > Signed-off-by: Leo Yan <leo.yan at arm.com>
> > ---
> >   tools/perf/arch/arm64/util/mem-events.c | 4 ++--
> >   1 file changed, 2 insertions(+), 2 deletions(-)
> >
> > diff --git a/tools/perf/arch/arm64/util/mem-events.c b/tools/perf/arch/arm64/util/mem-events.c
> > index 9f8da7937255cc9b14c3c58a1119b40bd0c76f6b..eaf00e0609c6c1b7d939a02fe3794471d1ed119b 100644
> > --- a/tools/perf/arch/arm64/util/mem-events.c
> > +++ b/tools/perf/arch/arm64/util/mem-events.c
> > @@ -6,7 +6,7 @@
> >   #define E(t, n, s, l, a) { .tag = t, .name = n, .event_name = s, .ldlat = l, .aux_event = a }
> >
> >   struct perf_mem_event perf_mem_events_arm[PERF_MEM_EVENTS__MAX] = {
> > -     E("spe-load",   "%s/ts_enable=1,pa_enable=1,load_filter=1,store_filter=0,min_latency=%u/",      NULL,   true,   0),
> > -     E("spe-store",  "%s/ts_enable=1,pa_enable=1,load_filter=0,store_filter=1/",                     NULL,   false,  0),
> > +     E("spe-load",   "%s/ts_enable=1,pa_enable=1,load_filter=1,min_latency=%u/",     NULL,   true,   0),
> > +     E("spe-store",  "%s/ts_enable=1,pa_enable=1,store_filter=1/",                   NULL,   false,  0),
> >       E("spe-ldst",   "%s/ts_enable=1,pa_enable=1,load_filter=1,store_filter=1,min_latency=%u/",      NULL,   true,   0),
> >   };
> >
>
> Reviewed-by: James Clark <james.clark at linaro.org>

Reviewed-by: Ian Rogers <irogers at google.com>

Thanks,
Ian


From nicolas at ndufresne.ca  Tue Dec 16 13:15:43 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Tue, 16 Dec 2025 16:15:43 -0500
Subject: [PATCH v11 02/12] media: mediatek: jpeg: fix jpeg buffer
 payload setting
In-Reply-To: <20251202094800.6140-3-kyrie.wu@mediatek.com>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
	 <20251202094800.6140-3-kyrie.wu@mediatek.com>
Message-ID: <36268d4980a1cd6d976bdf5de148f1c2668a92e4.camel@ndufresne.ca>

Hi.

Le mardi 02 d?cembre 2025 ? 17:47 +0800, Kyrie Wu a ?crit?:
> For multi-core jpegdec, if one of hws gets the event of resolution
> changing, the payload size, representing the size of Y/C data,

-> "gets the resolution change event, ..."

> needed to change. But others hws are decoding at the same time and

needed -> needs,               hws -> cores ?

It this specific to decoders or any type of cores ?

> it can not be changed immediately, which results that the payload

                                                    in the playload

> size is not equal to the real buffer length of the hw's, which occurred

size to not match the real buffer lenght for the ... hw ?

> resolution changing and a warnning call trace will print.

Can't parse. You can probably split that large sentence, and it needs to be
rework.

> So the setting of payload size must less than the real buffer length
> to remove the warnning logs.
> 
> Fixes: 0fa49df4222f ("media: mtk-jpegdec: support jpegdec multi-hardware")
> 

Don't add blank line in tags please.

> Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
> ---
> ?.../platform/mediatek/jpeg/mtk_jpeg_core.c??? | 19 ++++++++++++++-----
> ?1 file changed, 14 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> index 6a7e01130f1c..0cf3dc5407e4 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> @@ -709,6 +709,7 @@ static int mtk_jpeg_buf_prepare(struct vb2_buffer *vb)
> ?	struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
> ?	struct mtk_jpeg_q_data *q_data = NULL;
> ?	struct v4l2_plane_pix_format plane_fmt = {};
> +	unsigned long max_size;

size_t ?

> ?	int i;
> ?
> ?	q_data = mtk_jpeg_get_q_data(ctx, vb->vb2_queue->type);
> @@ -717,12 +718,20 @@ static int mtk_jpeg_buf_prepare(struct vb2_buffer *vb)
> ?
> ?	for (i = 0; i < q_data->fmt->colplanes; i++) {
> ?		plane_fmt = q_data->pix_mp.plane_fmt[i];
> +		max_size = plane_fmt.sizeimage;
> +
> ?		if (ctx->enable_exif &&
> -		??? q_data->fmt->fourcc == V4L2_PIX_FMT_JPEG)
> -			vb2_set_plane_payload(vb, i, plane_fmt.sizeimage +
> -					????? MTK_JPEG_MAX_EXIF_SIZE);
> -		else
> -			vb2_set_plane_payload(vb, i,? plane_fmt.sizeimage);
> +			q_data->fmt->fourcc == V4L2_PIX_FMT_JPEG) {
> +			max_size += MTK_JPEG_MAX_EXIF_SIZE;
> +
> +			vb2_set_plane_payload(vb, i,
> +					????? MIN(vb->planes[i].length,
> +						? max_size));

This is still not quite right. sizeimage, straight from s_fmt should already
account for the EXIF headers. If enable_exif is unknown at the moment, then you
should just always include that space. This way, the buffer length will only be
bigger if userspace asked for more at allocation time, and wil never be smaller
then this.

The point of sizeimage it to allow userspace allocate externally the right size,
this driver failed at that task it seems.

Stepping back a little, I don't even understand why you set the payload size
like this here. Why isn't the true payload size written once, when the buffer is
encoded ? Are you using bytesused to tell the HW how much space can be written
too ? Just give it the full space, wich is the allocated size (length).

Nicolas


> +		} else {
> +			vb2_set_plane_payload(vb, i,
> +					????? MIN(plane_fmt.sizeimage,
> +						? vb->planes[i].length));
> +		}
> ?	}
> ?
> ?	return 0;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251216/b2a98f33/attachment.sig>

From nicolas at ndufresne.ca  Tue Dec 16 13:22:46 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Tue, 16 Dec 2025 16:22:46 -0500
Subject: [PATCH v11 03/12] media: mediatek: jpeg: fix jpeg buffer layout
In-Reply-To: <20251202094800.6140-4-kyrie.wu@mediatek.com>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
	 <20251202094800.6140-4-kyrie.wu@mediatek.com>
Message-ID: <89f845b45405bbf985a5e92c195078074bcce0e2.camel@ndufresne.ca>

Hi,

Le mardi 02 d?cembre 2025 ? 17:47 +0800, Kyrie Wu a ?crit?:
> For memory alloc operation of jpeg dst buffer: the mallocing
> memory function interface use vb2_buffer as the base addr.
> If structure mtk_jpeg_src_buf wants to be allocated to memory,
> it needs to be placed vb2_v4l2_buffer at the starting position,
> because structure vb2_buffer is at the starting position of
> vb2_v4l2_buffer, and the allocated size is set to the size of
> structure mtk_jpeg_src_buf, so as to ensure that structures
> mtk_jpeg_src_buf, vb2_v4l2_buffer and vb2_buffer can all be
> allocated memory.

Please correct the wording, "mallocing" is not a word, addr -> address. I tend
to do the same, but refrain from giving the code a personality, the vb2_buffer
have no will. This is overall complicated way to simply say:

	Fix the size of the allocated mtk_jpeg_src_buf structure.

> 
> Fixes: 5fb1c2361e56 ("mtk-jpegenc: add jpeg encode worker interface")
> 

Drop the blank line.

> Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
> ---
> ?drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c | 2 +-
> ?drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h | 2 +-
> ?2 files changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> index 0cf3dc5407e4..bd0afc93d491 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> @@ -1099,7 +1099,7 @@ static int mtk_jpeg_queue_init(void *priv, struct vb2_queue *src_vq,
> ?	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
> ?	dst_vq->io_modes = VB2_DMABUF | VB2_MMAP;
> ?	dst_vq->drv_priv = ctx;
> -	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
> +	dst_vq->buf_struct_size = sizeof(struct mtk_jpeg_src_buf);
> ?	dst_vq->ops = jpeg->variant->qops;
> ?	dst_vq->mem_ops = &vb2_dma_contig_memops;
> ?	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> index 6be5cf30dea1..148fd41759b7 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> @@ -85,10 +85,10 @@ struct mtk_jpeg_variant {
> ?};
> ?
> ?struct mtk_jpeg_src_buf {
> -	u32 frame_num;
> ?	struct vb2_v4l2_buffer b;
> ?	struct list_head list;
> ?	u32 bs_size;
> +	u32 frame_num;

I like the change, but this shouldn't be an issue if you use container_of, which
is safer then a plain cast. Please review the code and make sure to use it. It
may be confusing to include a cosmetic change in a fixes.

Nicolas

> ?	struct mtk_jpeg_dec_param dec_param;
> ?
> ?	struct mtk_jpeg_ctx *curr_ctx;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251216/679cdc42/attachment-0001.sig>

From nicolas at ndufresne.ca  Tue Dec 16 13:27:05 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Tue, 16 Dec 2025 16:27:05 -0500
Subject: [PATCH v11 04/12] media: mediatek: jpeg: fix stop streaming
 flow for multi-core
In-Reply-To: <20251202094800.6140-5-kyrie.wu@mediatek.com>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
	 <20251202094800.6140-5-kyrie.wu@mediatek.com>
Message-ID: <bf9d84ad6973d55f40bafdb9a70dc49178d4af10.camel@ndufresne.ca>

Le mardi 02 d?cembre 2025 ? 17:47 +0800, Kyrie Wu a ?crit?:
> For jpeg multi-core architecture, if all hardware run at the
> same time, some input and output buffers are occupied.
> If one hardware is completed firstly, while other hardwares are

is compelted -> completes
harwares -> core, matches mtk_jpeg_core.c file name

> still running. The decoding completion signal calls

decoding -> decode.

> mtk_jpeg_dec_stop_streaming, and the function of v4l2_m2m_buf_done
> is called in mtk_jpeg_dec_stop_streaming to complete all
> input/output buffers. However, some buffers are occupied by other
> hardwares, resulting in errors. It needs to add a counter to
> calculate the used decoding buffer counts, it will increase 1 when
> the buffer set to hardware and decrease to 0 until the all buffers
> decoded and the function could continue to be executed.

More things to fix, also same for other of your commits, please reflow between
70 and 75 as suggested in the guide. It should look even.

> 
> Fixes: 0fa49df4222f ("media: mtk-jpegdec: support jpegdec multi-hardware")
> Fixes: dedc21500334 ("media: mtk-jpegdec: add jpeg decode worker interface")
> Fixes: 934e8bccac95 ("mtk-jpegenc: support jpegenc multi-hardware")
> Fixes: 5fb1c2361e56 ("mtk-jpegenc: add jpeg encode worker interface")
> 
> Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
> ---
> ?.../media/platform/mediatek/jpeg/mtk_jpeg_core.c | 16 ++++++++++++++++
> ?.../media/platform/mediatek/jpeg/mtk_jpeg_core.h |? 2 ++
> ?.../platform/mediatek/jpeg/mtk_jpeg_dec_hw.c???? |? 9 +++++++++
> ?.../platform/mediatek/jpeg/mtk_jpeg_enc_hw.c???? |? 9 +++++++++
> ?4 files changed, 36 insertions(+)
> 
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> index bd0afc93d491..59fd79c89f88 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> @@ -857,8 +857,12 @@ static struct vb2_v4l2_buffer *mtk_jpeg_buf_remove(struct mtk_jpeg_ctx *ctx,
> ?static void mtk_jpeg_enc_stop_streaming(struct vb2_queue *q)
> ?{
> ?	struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(q);
> +	struct mtk_jpeg_dev *jpeg = ctx->jpeg;
> ?	struct vb2_v4l2_buffer *vb;
> ?
> +	if (jpeg->variant->multi_core)
> +		wait_event(jpeg->hw_wq, (atomic_read(&ctx->buf_list_cnt) == 0));
> +

Can't it simply be solved with vb2_wait_for_all_buffers() ?

Nicolas

> ?	while ((vb = mtk_jpeg_buf_remove(ctx, q->type)))
> ?		v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR);
> ?}
> @@ -866,6 +870,7 @@ static void mtk_jpeg_enc_stop_streaming(struct vb2_queue *q)
> ?static void mtk_jpeg_dec_stop_streaming(struct vb2_queue *q)
> ?{
> ?	struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(q);
> +	struct mtk_jpeg_dev *jpeg = ctx->jpeg;
> ?	struct vb2_v4l2_buffer *vb;
> ?
> ?	/*
> @@ -873,6 +878,9 @@ static void mtk_jpeg_dec_stop_streaming(struct vb2_queue *q)
> ?	 * Before STREAMOFF, we still have to return the old resolution and
> ?	 * subsampling. Update capture queue when the stream is off.
> ?	 */
> +	if (jpeg->variant->multi_core)
> +		wait_event(jpeg->hw_wq, (atomic_read(&ctx->buf_list_cnt) == 0));
> +
> ?	if (ctx->state == MTK_JPEG_SOURCE_CHANGE &&
> ?	??? V4L2_TYPE_IS_CAPTURE(q->type)) {
> ?		struct mtk_jpeg_src_buf *src_buf;
> @@ -1181,6 +1189,7 @@ static int mtk_jpeg_open(struct file *file)
> ?	spin_lock_init(&ctx->done_queue_lock);
> ?	v4l2_fh_init(&ctx->fh, vfd);
> ?	v4l2_fh_add(&ctx->fh, file);
> +	atomic_set(&ctx->buf_list_cnt, 0);
> ?
> ?	ctx->jpeg = jpeg;
> ?	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx,
> @@ -1563,6 +1572,11 @@ static int mtk_jpegdec_set_hw_param(struct mtk_jpeg_ctx *ctx,
> ?	return 0;
> ?}
> ?
> +static void jpeg_buf_queue_inc(struct mtk_jpeg_ctx *ctx)
> +{
> +	atomic_inc(&ctx->buf_list_cnt);
> +}
> +
> ?static irqreturn_t mtk_jpeg_enc_done(struct mtk_jpeg_dev *jpeg)
> ?{
> ?	struct mtk_jpeg_ctx *ctx;
> @@ -1671,6 +1685,7 @@ static void mtk_jpegenc_worker(struct work_struct *work)
> ?			???? &src_buf->vb2_buf);
> ?	mtk_jpeg_set_enc_params(ctx, comp_jpeg[hw_id]->reg_base);
> ?	mtk_jpeg_enc_start(comp_jpeg[hw_id]->reg_base);
> +	jpeg_buf_queue_inc(ctx);
> ?	v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
> ?	spin_unlock_irqrestore(&comp_jpeg[hw_id]->hw_lock, flags);
> ?
> @@ -1786,6 +1801,7 @@ static void mtk_jpegdec_worker(struct work_struct *work)
> ?				&bs,
> ?				&fb);
> ?	mtk_jpeg_dec_start(comp_jpeg[hw_id]->reg_base);
> +	jpeg_buf_queue_inc(ctx);
> ?	v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
> ?	spin_unlock_irqrestore(&comp_jpeg[hw_id]->hw_lock, flags);
> ?
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> index 148fd41759b7..33f7fbc4ca5e 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> @@ -288,6 +288,7 @@ struct mtk_jpeg_q_data {
> ? * @dst_done_queue:		encoded frame buffer queue
> ? * @done_queue_lock:		encoded frame operation spinlock
> ? * @last_done_frame_num:	the last encoded frame number
> + * @buf_list_cnt:		the frame buffer count own by jpeg driver
> ? */
> ?struct mtk_jpeg_ctx {
> ?	struct mtk_jpeg_dev		*jpeg;
> @@ -306,6 +307,7 @@ struct mtk_jpeg_ctx {
> ?	/* spinlock protecting the encode done buffer */
> ?	spinlock_t done_queue_lock;
> ?	u32 last_done_frame_num;
> +	atomic_t buf_list_cnt;
> ?};
> ?
> ?#endif /* _MTK_JPEG_CORE_H */
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> index a1e54715cb7e..84d12eea35f7 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> @@ -519,6 +519,11 @@ static void mtk_jpegdec_put_buf(struct mtk_jpegdec_comp_dev *jpeg)
> ?	spin_unlock_irqrestore(&ctx->done_queue_lock, flags);
> ?}
> ?
> +static void jpeg_buf_queue_dec(struct mtk_jpeg_ctx *ctx)
> +{
> +	atomic_dec(&ctx->buf_list_cnt);
> +}
> +
> ?static void mtk_jpegdec_timeout_work(struct work_struct *work)
> ?{
> ?	enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR;
> @@ -527,9 +532,11 @@ static void mtk_jpegdec_timeout_work(struct work_struct *work)
> ?			???? job_timeout_work.work);
> ?	struct mtk_jpeg_dev *master_jpeg = cjpeg->master_dev;
> ?	struct vb2_v4l2_buffer *src_buf, *dst_buf;
> +	struct mtk_jpeg_ctx *ctx;
> ?
> ?	src_buf = cjpeg->hw_param.src_buffer;
> ?	dst_buf = cjpeg->hw_param.dst_buffer;
> +	ctx = cjpeg->hw_param.curr_ctx;
> ?	v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
> ?
> ?	mtk_jpeg_dec_reset(cjpeg->reg_base);
> @@ -540,6 +547,7 @@ static void mtk_jpegdec_timeout_work(struct work_struct *work)
> ?	wake_up(&master_jpeg->hw_wq);
> ?	v4l2_m2m_buf_done(src_buf, buf_state);
> ?	mtk_jpegdec_put_buf(cjpeg);
> +	jpeg_buf_queue_dec(ctx);
> ?}
> ?
> ?static irqreturn_t mtk_jpegdec_hw_irq_handler(int irq, void *priv)
> @@ -580,6 +588,7 @@ static irqreturn_t mtk_jpegdec_hw_irq_handler(int irq, void *priv)
> ?	buf_state = VB2_BUF_STATE_DONE;
> ?	v4l2_m2m_buf_done(src_buf, buf_state);
> ?	mtk_jpegdec_put_buf(jpeg);
> +	jpeg_buf_queue_dec(ctx);
> ?	pm_runtime_put(ctx->jpeg->dev);
> ?	clk_disable_unprepare(jpeg->jdec_clk.clks->clk);
> ?
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> index 28d05909c96f..1862444f35f5 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> @@ -248,6 +248,11 @@ static void mtk_jpegenc_put_buf(struct mtk_jpegenc_comp_dev *jpeg)
> ?	spin_unlock_irqrestore(&ctx->done_queue_lock, flags);
> ?}
> ?
> +static void jpeg_buf_queue_enc(struct mtk_jpeg_ctx *ctx)
> +{
> +	atomic_dec(&ctx->buf_list_cnt);
> +}
> +
> ?static void mtk_jpegenc_timeout_work(struct work_struct *work)
> ?{
> ?	struct delayed_work *dly_work = to_delayed_work(work);
> @@ -258,9 +263,11 @@ static void mtk_jpegenc_timeout_work(struct work_struct *work)
> ?	struct mtk_jpeg_dev *master_jpeg = cjpeg->master_dev;
> ?	enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR;
> ?	struct vb2_v4l2_buffer *src_buf, *dst_buf;
> +	struct mtk_jpeg_ctx *ctx;
> ?
> ?	src_buf = cjpeg->hw_param.src_buffer;
> ?	dst_buf = cjpeg->hw_param.dst_buffer;
> +	ctx = cjpeg->hw_param.curr_ctx;
> ?	v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
> ?
> ?	mtk_jpeg_enc_reset(cjpeg->reg_base);
> @@ -271,6 +278,7 @@ static void mtk_jpegenc_timeout_work(struct work_struct *work)
> ?	wake_up(&master_jpeg->hw_wq);
> ?	v4l2_m2m_buf_done(src_buf, buf_state);
> ?	mtk_jpegenc_put_buf(cjpeg);
> +	jpeg_buf_queue_enc(ctx);
> ?}
> ?
> ?static irqreturn_t mtk_jpegenc_hw_irq_handler(int irq, void *priv)
> @@ -304,6 +312,7 @@ static irqreturn_t mtk_jpegenc_hw_irq_handler(int irq, void *priv)
> ?	buf_state = VB2_BUF_STATE_DONE;
> ?	v4l2_m2m_buf_done(src_buf, buf_state);
> ?	mtk_jpegenc_put_buf(jpeg);
> +	jpeg_buf_queue_enc(ctx);
> ?	pm_runtime_put(ctx->jpeg->dev);
> ?	clk_disable_unprepare(jpeg->venc_clk.clks->clk);
> ?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251216/dea353b2/attachment.sig>

From nicolas at ndufresne.ca  Tue Dec 16 13:33:59 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Tue, 16 Dec 2025 16:33:59 -0500
Subject: [PATCH v11 05/12] media: mediatek: jpeg: fix multi-core clk
 suspend and resume setting
In-Reply-To: <20251202094800.6140-6-kyrie.wu@mediatek.com>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
	 <20251202094800.6140-6-kyrie.wu@mediatek.com>
Message-ID: <8f985a1b2add6fbcba354a0a3d330447380a6ccb.camel@ndufresne.ca>

Hi,

Le mardi 02 d?cembre 2025 ? 17:47 +0800, Kyrie Wu a ?crit?:
> The suspend/resume callback function is defined in the dev_pm_ops
> structure, which is defined in platform_driver. For multiple-core
> architecture, each hardware driver will register a platform_driver
> structure, so it is necessary to add a suspend/resume callback
> function for each hardware to support this operation.
> 
> Fixes: 934e8bccac95 ("mtk-jpegenc: support jpegenc multi-hardware")
> Fixes: 0fa49df4222f ("media: mtk-jpegdec: support jpegdec multi-hardware")
> 
> Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
> ---
> ?.../platform/mediatek/jpeg/mtk_jpeg_core.c??? | 28 +++----
> ?.../platform/mediatek/jpeg/mtk_jpeg_dec_hw.c? | 75 ++++++++++++++++++-
> ?.../platform/mediatek/jpeg/mtk_jpeg_enc_hw.c? | 75 ++++++++++++++++++-
> ?3 files changed, 151 insertions(+), 27 deletions(-)
> 
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> index 59fd79c89f88..e45d7e82b8a0 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> @@ -1122,6 +1122,9 @@ static void mtk_jpeg_clk_on(struct mtk_jpeg_dev *jpeg)
> ?{
> ?	int ret;
> ?
> +	if (jpeg->variant->multi_core)
> +		return;
> +
> ?	ret = clk_bulk_prepare_enable(jpeg->variant->num_clks,
> ?				????? jpeg->variant->clks);
> ?	if (ret)
> @@ -1130,6 +1133,9 @@ static void mtk_jpeg_clk_on(struct mtk_jpeg_dev *jpeg)
> ?
> ?static void mtk_jpeg_clk_off(struct mtk_jpeg_dev *jpeg)
> ?{
> +	if (jpeg->variant->multi_core)
> +		return;
> +
> ?	clk_bulk_disable_unprepare(jpeg->variant->num_clks,
> ?				?? jpeg->variant->clks);
> ?}
> @@ -1658,13 +1664,6 @@ static void mtk_jpegenc_worker(struct work_struct
> *work)
> ?		goto enc_end;
> ?	}
> ?
> -	ret = clk_prepare_enable(comp_jpeg[hw_id]->venc_clk.clks->clk);
> -	if (ret) {
> -		dev_err(jpeg->dev, "%s : %d, jpegenc clk_prepare_enable
> fail\n",
> -			__func__, __LINE__);
> -		goto enc_end;
> -	}
> -
> ?	v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> ?	v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> ?
> @@ -1762,20 +1761,13 @@ static void mtk_jpegdec_worker(struct work_struct
> *work)
> ?	jpeg_dst_buf->frame_num = ctx->total_frame_num;
> ?
> ?	mtk_jpegdec_set_hw_param(ctx, hw_id, src_buf, dst_buf);
> -	ret = pm_runtime_get_sync(comp_jpeg[hw_id]->dev);
> +	ret = pm_runtime_resume_and_get(comp_jpeg[hw_id]->dev);
> ?	if (ret < 0) {
> ?		dev_err(jpeg->dev, "%s : %d, pm_runtime_get_sync fail !!!\n",
> ?			__func__, __LINE__);
> ?		goto dec_end;
> ?	}
> ?
> -	ret = clk_prepare_enable(comp_jpeg[hw_id]->jdec_clk.clks->clk);
> -	if (ret) {
> -		dev_err(jpeg->dev, "%s : %d, jpegdec clk_prepare_enable
> fail\n",
> -			__func__, __LINE__);
> -		goto clk_end;
> -	}
> -
> ?	v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> ?	v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> ?
> @@ -1785,7 +1777,7 @@ static void mtk_jpegdec_worker(struct work_struct *work)
> ?				 &dst_buf->vb2_buf, &fb)) {
> ?		dev_err(jpeg->dev, "%s : %d, mtk_jpeg_set_dec_dst fail\n",
> ?			__func__, __LINE__);
> -		goto setdst_end;
> +		goto set_dst_fail;
> ?	}
> ?
> ?	schedule_delayed_work(&comp_jpeg[hw_id]->job_timeout_work,
> @@ -1807,9 +1799,7 @@ static void mtk_jpegdec_worker(struct work_struct *work)
> ?
> ?	return;
> ?
> -setdst_end:
> -	clk_disable_unprepare(comp_jpeg[hw_id]->jdec_clk.clks->clk);
> -clk_end:
> +set_dst_fail:
> ?	pm_runtime_put(comp_jpeg[hw_id]->dev);
> ?dec_end:
> ?	v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> index 84d12eea35f7..5f1557dafad6 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> @@ -540,14 +540,13 @@ static void mtk_jpegdec_timeout_work(struct work_struct
> *work)
> ?	v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
> ?
> ?	mtk_jpeg_dec_reset(cjpeg->reg_base);
> -	clk_disable_unprepare(cjpeg->jdec_clk.clks->clk);
> -	pm_runtime_put(cjpeg->dev);
> ?	cjpeg->hw_state = MTK_JPEG_HW_IDLE;
> ?	atomic_inc(&master_jpeg->hw_rdy);
> ?	wake_up(&master_jpeg->hw_wq);
> ?	v4l2_m2m_buf_done(src_buf, buf_state);
> ?	mtk_jpegdec_put_buf(cjpeg);
> ?	jpeg_buf_queue_dec(ctx);
> +	pm_runtime_put(cjpeg->dev);
> ?}
> ?
> ?static irqreturn_t mtk_jpegdec_hw_irq_handler(int irq, void *priv)
> @@ -589,12 +588,11 @@ static irqreturn_t mtk_jpegdec_hw_irq_handler(int irq,
> void *priv)
> ?	v4l2_m2m_buf_done(src_buf, buf_state);
> ?	mtk_jpegdec_put_buf(jpeg);
> ?	jpeg_buf_queue_dec(ctx);
> -	pm_runtime_put(ctx->jpeg->dev);
> -	clk_disable_unprepare(jpeg->jdec_clk.clks->clk);
> ?
> ?	jpeg->hw_state = MTK_JPEG_HW_IDLE;
> ?	wake_up(&master_jpeg->hw_wq);
> ?	atomic_inc(&master_jpeg->hw_rdy);
> +	pm_runtime_put(jpeg->dev);
> ?
> ?	return IRQ_HANDLED;
> ?}
> @@ -677,15 +675,84 @@ static int mtk_jpegdec_hw_probe(struct platform_device
> *pdev)
> ?
> ?	platform_set_drvdata(pdev, dev);
> ?	pm_runtime_enable(&pdev->dev);
> +	ret = devm_clk_bulk_get(dev->dev,
> +				jpegdec_clk->clk_num,
> +				jpegdec_clk->clks);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Failed to init clk\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static void mtk_jpeg_clk_on(struct mtk_jpegdec_comp_dev *jpeg)
> +{
> +	int ret;
> +
> +	ret = clk_bulk_prepare_enable(jpeg->jdec_clk.clk_num,
> +				????? jpeg->jdec_clk.clks);
> +	if (ret)
> +		dev_err(jpeg->dev, "%s : %d, jpegdec clk_prepare_enable
> fail\n",
> +			__func__, __LINE__);
> +}
> +
> +static void mtk_jpeg_clk_off(struct mtk_jpegdec_comp_dev *jpeg)
> +{
> +	clk_bulk_disable_unprepare(jpeg->jdec_clk.clk_num,
> +				?? jpeg->jdec_clk.clks);
> +}
> +
> +static __maybe_unused int mtk_jpegdec_pm_suspend(struct device *dev)

Its used its passed to mtk_jpegdec_pm_ops structure. Same below. Unless you had
the intention to ifdef that structure and you forgot.

> +{
> +	struct mtk_jpegdec_comp_dev *jpeg = dev_get_drvdata(dev);
> +
> +	mtk_jpeg_clk_off(jpeg);
> ?
> ?	return 0;
> ?}
> ?
> +static __maybe_unused int mtk_jpegdec_pm_resume(struct device *dev)
> +{
> +	struct mtk_jpegdec_comp_dev *jpeg = dev_get_drvdata(dev);
> +
> +	mtk_jpeg_clk_on(jpeg);
> +
> +	return 0;
> +}
> +
> +static __maybe_unused int mtk_jpegdec_suspend(struct device *dev)
> +{
> +	struct mtk_jpegdec_comp_dev *jpeg = dev_get_drvdata(dev);
> +
> +	v4l2_m2m_suspend(jpeg->master_dev->m2m_dev);
> +	return pm_runtime_force_suspend(dev);
> +}
> +
> +static __maybe_unused int mtk_jpegdec_resume(struct device *dev)
> +{
> +	struct mtk_jpegdec_comp_dev *jpeg = dev_get_drvdata(dev);
> +	int ret;
> +
> +	ret = pm_runtime_force_resume(dev);
> +	if (ret < 0)
> +		return ret;
> +
> +	v4l2_m2m_resume(jpeg->master_dev->m2m_dev);
> +	return ret;
> +}
> +
> +static const struct dev_pm_ops mtk_jpegdec_pm_ops = {
> +	SET_SYSTEM_SLEEP_PM_OPS(mtk_jpegdec_suspend, mtk_jpegdec_resume)
> +	SET_RUNTIME_PM_OPS(mtk_jpegdec_pm_suspend, mtk_jpegdec_pm_resume,
> NULL)
> +};
> +
> ?static struct platform_driver mtk_jpegdec_hw_driver = {
> ?	.probe = mtk_jpegdec_hw_probe,
> ?	.driver = {
> ?		.name = "mtk-jpegdec-hw",
> ?		.of_match_table = mtk_jpegdec_hw_ids,
> +		.pm???????????? = &mtk_jpegdec_pm_ops,
> ?	},
> ?};
> ?
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> index 1862444f35f5..785db5ba4770 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> @@ -271,14 +271,13 @@ static void mtk_jpegenc_timeout_work(struct work_struct
> *work)
> ?	v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
> ?
> ?	mtk_jpeg_enc_reset(cjpeg->reg_base);
> -	clk_disable_unprepare(cjpeg->venc_clk.clks->clk);
> -	pm_runtime_put(cjpeg->dev);
> ?	cjpeg->hw_state = MTK_JPEG_HW_IDLE;
> ?	atomic_inc(&master_jpeg->hw_rdy);
> ?	wake_up(&master_jpeg->hw_wq);
> ?	v4l2_m2m_buf_done(src_buf, buf_state);
> ?	mtk_jpegenc_put_buf(cjpeg);
> ?	jpeg_buf_queue_enc(ctx);
> +	pm_runtime_put(cjpeg->dev);
> ?}
> ?
> ?static irqreturn_t mtk_jpegenc_hw_irq_handler(int irq, void *priv)
> @@ -313,12 +312,11 @@ static irqreturn_t mtk_jpegenc_hw_irq_handler(int irq,
> void *priv)
> ?	v4l2_m2m_buf_done(src_buf, buf_state);
> ?	mtk_jpegenc_put_buf(jpeg);
> ?	jpeg_buf_queue_enc(ctx);
> -	pm_runtime_put(ctx->jpeg->dev);
> -	clk_disable_unprepare(jpeg->venc_clk.clks->clk);
> ?
> ?	jpeg->hw_state = MTK_JPEG_HW_IDLE;
> ?	wake_up(&master_jpeg->hw_wq);
> ?	atomic_inc(&master_jpeg->hw_rdy);
> +	pm_runtime_put(jpeg->dev);
> ?
> ?	return IRQ_HANDLED;
> ?}
> @@ -399,15 +397,84 @@ static int mtk_jpegenc_hw_probe(struct platform_device
> *pdev)
> ?
> ?	platform_set_drvdata(pdev, dev);
> ?	pm_runtime_enable(&pdev->dev);
> +	ret = devm_clk_bulk_get(dev->dev,
> +				jpegenc_clk->clk_num,
> +				jpegenc_clk->clks);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Failed to init clk\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static void mtk_jpeg_clk_on(struct mtk_jpegenc_comp_dev *jpeg)
> +{
> +	int ret;
> +
> +	ret = clk_bulk_prepare_enable(jpeg->venc_clk.clk_num,
> +				????? jpeg->venc_clk.clks);
> +	if (ret)
> +		dev_err(jpeg->dev, "%s : %d, jpegenc clk_prepare_enable
> fail\n",
> +			__func__, __LINE__);
> +}
> +
> +static void mtk_jpeg_clk_off(struct mtk_jpegenc_comp_dev *jpeg)
> +{
> +	clk_bulk_disable_unprepare(jpeg->venc_clk.clk_num,
> +				?? jpeg->venc_clk.clks);
> +}
> +
> +static __maybe_unused int mtk_jpegenc_pm_suspend(struct device *dev)
> +{
> +	struct mtk_jpegenc_comp_dev *jpeg = dev_get_drvdata(dev);
> +
> +	mtk_jpeg_clk_off(jpeg);

This is the only call to that function, move the code here.

> ?
> ?	return 0;
> ?}
> ?
> +static __maybe_unused int mtk_jpegenc_pm_resume(struct device *dev)
> +{
> +	struct mtk_jpegenc_comp_dev *jpeg = dev_get_drvdata(dev);
> +
> +	mtk_jpeg_clk_on(jpeg);

This is the only call to that function, move the code here. Decides if the ret
value should be passed or not too, add a comment if not.

Its worrying not too, since usually if the clock are not running, we risk
hanging the CPU writing to registers.

> +
> +	return 0;
> +}
> +
> +static __maybe_unused int mtk_jpegenc_suspend(struct device *dev)
> +{
> +	struct mtk_jpegenc_comp_dev *jpeg = dev_get_drvdata(dev);
> +
> +	v4l2_m2m_suspend(jpeg->master_dev->m2m_dev);
> +	return pm_runtime_force_suspend(dev);
> +}
> +
> +static __maybe_unused int mtk_jpegenc_resume(struct device *dev)
> +{
> +	struct mtk_jpegenc_comp_dev *jpeg = dev_get_drvdata(dev);
> +	int ret;
> +
> +	ret = pm_runtime_force_resume(dev);
> +	if (ret < 0)
> +		return ret;
> +
> +	v4l2_m2m_resume(jpeg->master_dev->m2m_dev);
> +	return ret;
> +}
> +
> +static const struct dev_pm_ops mtk_jpegenc_pm_ops = {
> +	SET_SYSTEM_SLEEP_PM_OPS(mtk_jpegenc_suspend, mtk_jpegenc_resume)
> +	SET_RUNTIME_PM_OPS(mtk_jpegenc_pm_suspend, mtk_jpegenc_pm_resume,
> NULL)
> +};
> +
> ?static struct platform_driver mtk_jpegenc_hw_driver = {
> ?	.probe = mtk_jpegenc_hw_probe,
> ?	.driver = {
> ?		.name = "mtk-jpegenc-hw",
> ?		.of_match_table = mtk_jpegenc_drv_ids,
> +		.pm = &mtk_jpegenc_pm_ops,
> ?	},
> ?};
> ?

Looks like the right way though,looking forward an update.

Nicolas
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251216/5ea28a7c/attachment-0001.sig>

From nicolas at ndufresne.ca  Tue Dec 16 13:37:05 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Tue, 16 Dec 2025 16:37:05 -0500
Subject: [PATCH v11 06/12] media: mediatek: jpeg: fix decoding buffer
 number setting timing issue
In-Reply-To: <20251202094800.6140-7-kyrie.wu@mediatek.com>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
	 <20251202094800.6140-7-kyrie.wu@mediatek.com>
Message-ID: <043630a657ff5403b74202f6a856ff4bcfc6a192.camel@ndufresne.ca>

Hi,

Le mardi 02 d?cembre 2025 ? 17:47 +0800, Kyrie Wu a ?crit?:
> move decoding buffer increase code into spinlock
> protecting aera for multi-core

I don't understand this text, please rework.

> 
> Fixes: dedc21500334 ("media: mtk-jpegdec: add jpeg decode worker interface")
> 

Drop that blank line.

> Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
> ---
> ?drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c?? | 9 +++------
> ?drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c | 1 +
> ?drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c | 1 +
> ?3 files changed, 5 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> index e45d7e82b8a0..5ffaee4dcd19 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> @@ -1746,7 +1746,6 @@ static void mtk_jpegdec_worker(struct work_struct *work)
> ?
> ?	v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
> ?	jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(&src_buf->vb2_buf);
> -	jpeg_dst_buf = mtk_jpeg_vb2_to_srcbuf(&dst_buf->vb2_buf);
> ?
> ?	if (mtk_jpeg_check_resolution_change(ctx,
> ?					???? &jpeg_src_buf->dec_param)) {
> @@ -1755,11 +1754,6 @@ static void mtk_jpegdec_worker(struct work_struct *work)
> ?		goto getbuf_fail;
> ?	}
> ?
> -	jpeg_src_buf->curr_ctx = ctx;
> -	jpeg_src_buf->frame_num = ctx->total_frame_num;
> -	jpeg_dst_buf->curr_ctx = ctx;
> -	jpeg_dst_buf->frame_num = ctx->total_frame_num;
> -
> ?	mtk_jpegdec_set_hw_param(ctx, hw_id, src_buf, dst_buf);
> ?	ret = pm_runtime_resume_and_get(comp_jpeg[hw_id]->dev);
> ?	if (ret < 0) {
> @@ -1784,6 +1778,9 @@ static void mtk_jpegdec_worker(struct work_struct *work)
> ?			????? msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC));
> ?
> ?	spin_lock_irqsave(&comp_jpeg[hw_id]->hw_lock, flags);
> +	jpeg_dst_buf = mtk_jpeg_vb2_to_srcbuf(&dst_buf->vb2_buf);
> +	jpeg_dst_buf->curr_ctx = ctx;
> +	jpeg_dst_buf->frame_num = ctx->total_frame_num;
> ?	ctx->total_frame_num++;
> ?	mtk_jpeg_dec_reset(comp_jpeg[hw_id]->reg_base);
> ?	mtk_jpeg_dec_set_config(comp_jpeg[hw_id]->reg_base,
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> index 5f1557dafad6..b3142dc9be85 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> @@ -513,6 +513,7 @@ static void mtk_jpegdec_put_buf(struct mtk_jpegdec_comp_dev *jpeg)
> ?				v4l2_m2m_buf_done(&tmp_dst_done_buf->b,
> ?						? VB2_BUF_STATE_DONE);
> ?				ctx->last_done_frame_num++;
> +				break;
> ?			}
> ?		}
> ?	}
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> index 785db5ba4770..82c971936c4d 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> @@ -242,6 +242,7 @@ static void mtk_jpegenc_put_buf(struct mtk_jpegenc_comp_dev *jpeg)
> ?				v4l2_m2m_buf_done(&tmp_dst_done_buf->b,
> ?						? VB2_BUF_STATE_DONE);
> ?				ctx->last_done_frame_num++;
> +				break;
> ?			}
> ?		}
> ?	}

Normally I'd seek for the context in the code. But I think I'll wait for a
proper commit message, and do a proper review then.

Nicolas
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251216/7e8e253a/attachment.sig>

From nicolas at ndufresne.ca  Tue Dec 16 13:40:44 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Tue, 16 Dec 2025 16:40:44 -0500
Subject: [PATCH v11 07/12] media: mediatek: jpeg: fix decoding
 resolution change operation
In-Reply-To: <20251202094800.6140-8-kyrie.wu@mediatek.com>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
	 <20251202094800.6140-8-kyrie.wu@mediatek.com>
Message-ID: <41e00b0f4c667ff8e8a8f8b81f64fe1bbca7c001.camel@ndufresne.ca>

Hi,

Le mardi 02 d?cembre 2025 ? 17:47 +0800, Kyrie Wu a ?crit?:
> 1.add a judgement for src buffer to avoid kernel crash
> in the stop streaming function;
> 2.When a resolution changing occurs, it needs to set new
> resolution parameter immediately and then report this event.
> Otherwise, if the original software process is maintained,
> the resolution change event is reported firstly, the CPU is
> dispatched to the app to process the event, and the driver
> does not set a new resolution, which will cause parameter errors.
> 3.After a resolution change occurred, decoding should not continue,
> needs to wait until new buffers are ready and the state machine
> changed.

I mention this in other patchset, very often, 3 bullets means 3 distinct
changes. Don't use bullets. Reflow this text, rework this text, there is many
syntax error here.

> 
> Fixes: dedc21500334 ("media: mtk-jpegdec: add jpeg decode worker interface")
> 
> Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
> ---
> ?drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c | 9 +++++++--
> ?1 file changed, 7 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> index 5ffaee4dcd19..9233bbfe2d97 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> @@ -887,7 +887,8 @@ static void mtk_jpeg_dec_stop_streaming(struct vb2_queue
> *q)
> ?
> ?		vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
> ?		src_buf = mtk_jpeg_vb2_to_srcbuf(&vb->vb2_buf);
> -		mtk_jpeg_set_queue_data(ctx, &src_buf->dec_param);
> +		if (!IS_ERR_OR_NULL(src_buf))
> +			mtk_jpeg_set_queue_data(ctx, &src_buf->dec_param);

The lack of vb2_wait_for_all_buffers() might explains this better, you might not
need to do random null checks like this.

Nicolas

> ?		ctx->state = MTK_JPEG_RUNNING;
> ?	} else if (V4L2_TYPE_IS_OUTPUT(q->type)) {
> ?		ctx->state = MTK_JPEG_INIT;
> @@ -1749,11 +1750,15 @@ static void mtk_jpegdec_worker(struct work_struct
> *work)
> ?
> ?	if (mtk_jpeg_check_resolution_change(ctx,
> ?					???? &jpeg_src_buf->dec_param)) {
> -		mtk_jpeg_queue_src_chg_event(ctx);
> +		mtk_jpeg_set_queue_data(ctx, &jpeg_src_buf->dec_param);
> ?		ctx->state = MTK_JPEG_SOURCE_CHANGE;
> +		mtk_jpeg_queue_src_chg_event(ctx);
> ?		goto getbuf_fail;
> ?	}
> ?
> +	if (ctx->state == MTK_JPEG_SOURCE_CHANGE)
> +		goto getbuf_fail;
> +
> ?	mtk_jpegdec_set_hw_param(ctx, hw_id, src_buf, dst_buf);
> ?	ret = pm_runtime_resume_and_get(comp_jpeg[hw_id]->dev);
> ?	if (ret < 0) {
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251216/eaa5ffa7/attachment.sig>

From nicolas at ndufresne.ca  Tue Dec 16 13:43:31 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Tue, 16 Dec 2025 16:43:31 -0500
Subject: [PATCH v11 08/12] media: mediatek: jpeg: fix remove buffer
 operation for multi-core
In-Reply-To: <20251202094800.6140-9-kyrie.wu@mediatek.com>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
	 <20251202094800.6140-9-kyrie.wu@mediatek.com>
Message-ID: <a8376a71b87cc8944bf05be3bc45dc2e4fe2764e.camel@ndufresne.ca>

Hi,

Le mardi 02 d?cembre 2025 ? 17:47 +0800, Kyrie Wu a ?crit?:
> move remove buffer code to spinlock protect area for multi-core

Perhaps:

Move calls to v4l2_m2m_src/dst_buf_remove() outside of the spinlock protected
scope.

And perhaps extend in why this is needed. Deadlock, bad lock ordering?

> 
> Fixes: 86379bd9d399 ("media: mtk-jpeg: Fixes jpeg enc&dec worker sw flow")
> 

No blank.

> Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

Nicolas

> ---
> ?drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c | 10 ++++------
> ?1 file changed, 4 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> index 9233bbfe2d97..da1ca494ed4b 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> @@ -1665,9 +1665,6 @@ static void mtk_jpegenc_worker(struct work_struct *work)
> ?		goto enc_end;
> ?	}
> ?
> -	v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> -	v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> -
> ?	schedule_delayed_work(&comp_jpeg[hw_id]->job_timeout_work,
> ?			????? msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC));
> ?
> @@ -1685,6 +1682,8 @@ static void mtk_jpegenc_worker(struct work_struct *work)
> ?			???? &src_buf->vb2_buf);
> ?	mtk_jpeg_set_enc_params(ctx, comp_jpeg[hw_id]->reg_base);
> ?	mtk_jpeg_enc_start(comp_jpeg[hw_id]->reg_base);
> +	v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> +	v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> ?	jpeg_buf_queue_inc(ctx);
> ?	v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
> ?	spin_unlock_irqrestore(&comp_jpeg[hw_id]->hw_lock, flags);
> @@ -1767,9 +1766,6 @@ static void mtk_jpegdec_worker(struct work_struct *work)
> ?		goto dec_end;
> ?	}
> ?
> -	v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> -	v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> -
> ?	mtk_jpeg_set_dec_src(ctx, &src_buf->vb2_buf, &bs);
> ?	if (mtk_jpeg_set_dec_dst(ctx,
> ?				 &jpeg_src_buf->dec_param,
> @@ -1794,6 +1790,8 @@ static void mtk_jpegdec_worker(struct work_struct *work)
> ?				jpeg_src_buf->bs_size,
> ?				&bs,
> ?				&fb);
> +	v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> +	v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> ?	mtk_jpeg_dec_start(comp_jpeg[hw_id]->reg_base);
> ?	jpeg_buf_queue_inc(ctx);
> ?	v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251216/22de25ec/attachment-0001.sig>

From nicolas at ndufresne.ca  Tue Dec 16 13:48:21 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Tue, 16 Dec 2025 16:48:21 -0500
Subject: [PATCH v11 12/12] media: mediatek: jpeg: add jpeg smmu sid
 setting
In-Reply-To: <20251202094800.6140-13-kyrie.wu@mediatek.com>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
	 <20251202094800.6140-13-kyrie.wu@mediatek.com>
Message-ID: <086b940b975a9c0f9cb5d5cf2fabe21ddb188821.camel@ndufresne.ca>

Hi,

Le mardi 02 d?cembre 2025 ? 17:48 +0800, Kyrie Wu a ?crit?:
> Add a configuration to set jpeg dec & enc smmu sid
> 
> Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
> ---
> ?.../platform/mediatek/jpeg/mtk_jpeg_core.c??? | 37 +++++++++++++++++++
> ?.../platform/mediatek/jpeg/mtk_jpeg_core.h??? | 15 ++++++++
> ?.../platform/mediatek/jpeg/mtk_jpeg_dec_hw.c? | 23 ++++++++++++
> ?.../platform/mediatek/jpeg/mtk_jpeg_enc_hw.c? | 23 ++++++++++++
> ?4 files changed, 98 insertions(+)
> 
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> index 10a588b92e76..625dfa8468e1 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> @@ -15,6 +15,7 @@
> ?#include <linux/of_platform.h>
> ?#include <linux/platform_device.h>
> ?#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> ?#include <linux/slab.h>
> ?#include <linux/spinlock.h>
> ?#include <media/v4l2-event.h>
> @@ -1613,6 +1614,20 @@ static irqreturn_t mtk_jpeg_enc_done(struct mtk_jpeg_dev *jpeg)
> ?	return IRQ_HANDLED;
> ?}
> ?
> +static void mtk_jpeg_enc_set_smmu_sid(struct mtk_jpegenc_comp_dev *jpeg)
> +{
> +	struct mtk_jpeg_dev *mjpeg = jpeg->master_dev;
> +
> +	if (!mjpeg->variant->support_smmu || !jpeg->smmu_regmap)
> +		return;
> +
> +	regmap_update_bits(jpeg->smmu_regmap, JPEG_ENC_SMMU_SID,
> +			?? JPG_REG_GUSER_ID_MASK <<
> +			?? JPG_REG_ENC_GUSER_ID_SHIFT,
> +			?? JPG_REG_GUSER_ID_ENC_SID <<
> +			?? JPG_REG_ENC_GUSER_ID_SHIFT);
> +}
> +
> ?static void mtk_jpegenc_worker(struct work_struct *work)
> ?{
> ?	struct mtk_jpegenc_comp_dev *comp_jpeg[MTK_JPEGENC_HW_MAX];
> @@ -1674,6 +1689,9 @@ static void mtk_jpegenc_worker(struct work_struct *work)
> ?	jpeg_dst_buf->frame_num = ctx->total_frame_num;
> ?	ctx->total_frame_num++;
> ?	mtk_jpeg_enc_reset(comp_jpeg[hw_id]->reg_base);
> +
> +	mtk_jpeg_enc_set_smmu_sid(comp_jpeg[hw_id]);
> +
> ?	mtk_jpeg_set_enc_dst(ctx,
> ?			???? comp_jpeg[hw_id]->reg_base,
> ?			???? &dst_buf->vb2_buf);
> @@ -1701,6 +1719,20 @@ static void mtk_jpegenc_worker(struct work_struct *work)
> ?	v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
> ?}
> ?
> +static void mtk_jpeg_dec_set_smmu_sid(struct mtk_jpegdec_comp_dev *jpeg)
> +{
> +	struct mtk_jpeg_dev *mjpeg = jpeg->master_dev;
> +
> +	if (!mjpeg->variant->support_smmu || !jpeg->smmu_regmap)
> +		return;
> +
> +	regmap_update_bits(jpeg->smmu_regmap, JPEG_DEC_SMMU_SID,
> +			?? JPG_REG_GUSER_ID_MASK <<
> +			?? JPG_REG_DEC_GUSER_ID_SHIFT,
> +			?? JPG_REG_GUSER_ID_DEC_SID <<
> +			?? JPG_REG_DEC_GUSER_ID_SHIFT);
> +}

Can you deduplicate that function. Just make one, and pass the SID as parameter.

> +
> ?static void mtk_jpegdec_worker(struct work_struct *work)
> ?{
> ?	struct mtk_jpeg_ctx *ctx = container_of(work, struct mtk_jpeg_ctx,
> @@ -1784,6 +1816,9 @@ static void mtk_jpegdec_worker(struct work_struct *work)
> ?	jpeg_dst_buf->frame_num = ctx->total_frame_num;
> ?	ctx->total_frame_num++;
> ?	mtk_jpeg_dec_reset(comp_jpeg[hw_id]->reg_base);
> +
> +	mtk_jpeg_dec_set_smmu_sid(comp_jpeg[hw_id]);
> +
> ?	mtk_jpeg_dec_set_config(comp_jpeg[hw_id]->reg_base,
> ?				jpeg->variant->support_34bit,
> ?				&jpeg_src_buf->dec_param,
> @@ -1943,6 +1978,7 @@ static struct mtk_jpeg_variant mtk8196_jpegenc_drvdata = {
> ?	.cap_q_default_fourcc = V4L2_PIX_FMT_JPEG,
> ?	.multi_core = true,
> ?	.jpeg_worker = mtk_jpegenc_worker,
> +	.support_smmu = true,
> ?};
> ?
> ?static const struct mtk_jpeg_variant mtk8195_jpegdec_drvdata = {
> @@ -1969,6 +2005,7 @@ static const struct mtk_jpeg_variant mtk8196_jpegdec_drvdata = {
> ?	.cap_q_default_fourcc = V4L2_PIX_FMT_YUV420M,
> ?	.multi_core = true,
> ?	.jpeg_worker = mtk_jpegdec_worker,
> +	.support_smmu = true,
> ?};
> ?
> ?static const struct of_device_id mtk_jpeg_match[] = {
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> index 33f7fbc4ca5e..6e8304680393 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> @@ -11,6 +11,7 @@
> ?
> ?#include <linux/clk.h>
> ?#include <linux/interrupt.h>
> +#include <linux/mfd/syscon.h>
> ?#include <media/v4l2-ctrls.h>
> ?#include <media/v4l2-device.h>
> ?#include <media/v4l2-fh.h>
> @@ -34,6 +35,14 @@
> ?
> ?#define MTK_JPEG_MAX_EXIF_SIZE	(64 * 1024)
> ?
> +#define JPEG_DEC_SMMU_SID				0
> +#define JPEG_ENC_SMMU_SID				0
> +#define JPG_REG_GUSER_ID_MASK			0x7
> +#define JPG_REG_GUSER_ID_DEC_SID		0x4
> +#define JPG_REG_GUSER_ID_ENC_SID		0x5
> +#define JPG_REG_DEC_GUSER_ID_SHIFT		8
> +#define JPG_REG_ENC_GUSER_ID_SHIFT		4
> +
> ?#define MTK_JPEG_ADDR_MASK GENMASK(1, 0)
> ?
> ?/**
> @@ -65,6 +74,7 @@ enum mtk_jpeg_ctx_state {
> ? * @multi_core:		mark jpeg hw is multi_core or not
> ? * @jpeg_worker:		jpeg dec or enc worker
> ? * @support_34bit:	flag to check support for 34-bit DMA address
> + * @support_smmu:	flag to check if support smmu
> ? */
> ?struct mtk_jpeg_variant {
> ?	struct clk_bulk_data *clks;
> @@ -82,6 +92,7 @@ struct mtk_jpeg_variant {
> ?	bool multi_core;
> ?	void (*jpeg_worker)(struct work_struct *work);
> ?	bool support_34bit;
> +	bool support_smmu;
> ?};
> ?
> ?struct mtk_jpeg_src_buf {
> @@ -150,6 +161,7 @@ struct mtk_jpegdec_clk {
> ? * @hw_param:		jpeg encode hw parameters
> ? * @hw_state:		record hw state
> ? * @hw_lock:		spinlock protecting the hw device resource
> + * @smmu_regmap:	SMMU registers mapping
> ? */
> ?struct mtk_jpegenc_comp_dev {
> ?	struct device *dev;
> @@ -163,6 +175,7 @@ struct mtk_jpegenc_comp_dev {
> ?	enum mtk_jpeg_hw_state hw_state;
> ?	/* spinlock protecting the hw device resource */
> ?	spinlock_t hw_lock;
> +	struct regmap *smmu_regmap;
> ?};
> ?
> ?/**
> @@ -177,6 +190,7 @@ struct mtk_jpegenc_comp_dev {
> ? * @hw_param:			jpeg decode hw parameters
> ? * @hw_state:			record hw state
> ? * @hw_lock:			spinlock protecting hw
> + * @smmu_regmap:		SMMU registers mapping
> ? */
> ?struct mtk_jpegdec_comp_dev {
> ?	struct device *dev;
> @@ -190,6 +204,7 @@ struct mtk_jpegdec_comp_dev {
> ?	enum mtk_jpeg_hw_state hw_state;
> ?	/* spinlock protecting the hw device resource */
> ?	spinlock_t hw_lock;
> +	struct regmap *smmu_regmap;
> ?};
> ?
> ?/**
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> index e453a1634f33..da753a636eaa 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> @@ -624,6 +624,25 @@ static int mtk_jpegdec_hw_init_irq(struct mtk_jpegdec_comp_dev *dev)
> ?	return 0;
> ?}
> ?
> +static int mtk_jpegdec_smmu_init(struct mtk_jpegdec_comp_dev *dev)
> +{
> +	struct mtk_jpeg_dev *master_dev = dev->master_dev;
> +
> +	if (!master_dev->variant->support_smmu)
> +		return 0;
> +
> +	dev->smmu_regmap =
> +		syscon_regmap_lookup_by_phandle(dev->plat_dev->dev.of_node,
> +						"mediatek,smmu-config");
> +	if (IS_ERR(dev->smmu_regmap)) {
> +		return dev_err_probe(dev->dev, PTR_ERR(dev->smmu_regmap),
> +				???? "mmap smmu_base failed(%ld)\n",
> +				???? PTR_ERR(dev->smmu_regmap));
> +	}
> +
> +	return 0;
> +}
> +
> ?static int mtk_jpegdec_hw_probe(struct platform_device *pdev)
> ?{
> ?	struct mtk_jpegdec_clk *jpegdec_clk;
> @@ -677,6 +696,10 @@ static int mtk_jpegdec_hw_probe(struct platform_device *pdev)
> ?	dev->master_dev = master_dev;
> ?	master_dev->max_hw_count++;
> ?
> +	ret = mtk_jpegdec_smmu_init(dev);
> +	if (ret)
> +		return ret;
> +
> ?	platform_set_drvdata(pdev, dev);
> ?	pm_runtime_enable(&pdev->dev);
> ?	ret = devm_clk_bulk_get(dev->dev,
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> index b30c728c3712..8a61d5537315 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> @@ -348,6 +348,25 @@ static int mtk_jpegenc_hw_init_irq(struct mtk_jpegenc_comp_dev *dev)
> ?	return 0;
> ?}
> ?
> +static int mtk_jpegenc_smmu_init(struct mtk_jpegenc_comp_dev *dev)
> +{
> +	struct mtk_jpeg_dev *master_dev = dev->master_dev;
> +
> +	if (!master_dev->variant->support_smmu)
> +		return 0;
> +
> +	dev->smmu_regmap =
> +		syscon_regmap_lookup_by_phandle(dev->plat_dev->dev.of_node,
> +						"mediatek,smmu-config");
> +	if (IS_ERR(dev->smmu_regmap)) {
> +		return dev_err_probe(dev->dev, PTR_ERR(dev->smmu_regmap),
> +				???? "mmap smmu_base failed(%ld)\n",
> +				???? PTR_ERR(dev->smmu_regmap));
> +	}
> +
> +	return 0;
> +}
> +
> ?static int mtk_jpegenc_hw_probe(struct platform_device *pdev)
> ?{
> ?	struct mtk_jpegenc_clk *jpegenc_clk;
> @@ -399,6 +418,10 @@ static int mtk_jpegenc_hw_probe(struct platform_device *pdev)
> ?	dev->master_dev = master_dev;
> ?	master_dev->max_hw_count++;
> ?
> +	ret = mtk_jpegenc_smmu_init(dev);
> +	if (ret)
> +		return ret;
> +
> ?	platform_set_drvdata(pdev, dev);
> ?	pm_runtime_enable(&pdev->dev);
> ?	ret = devm_clk_bulk_get(dev->dev,

With that minor fix:

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251216/f4c24f74/attachment.sig>

From nicolas at ndufresne.ca  Tue Dec 16 13:49:12 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Tue, 16 Dec 2025 16:49:12 -0500
Subject: [PATCH v11 11/12] media: mediatek: jpeg: add jpeg compatible
In-Reply-To: <20251202094800.6140-12-kyrie.wu@mediatek.com>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
	 <20251202094800.6140-12-kyrie.wu@mediatek.com>
Message-ID: <3dd2c364f84725a68823f13a9f2b1f0499abaed5.camel@ndufresne.ca>

Le mardi 02 d?cembre 2025 ? 17:47 +0800, Kyrie Wu a ?crit?:
> Add jpeg dec and enc compatible for mt8196
> 
> Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?.../platform/mediatek/jpeg/mtk_jpeg_core.c??? | 34 +++++++++++++++++++
> ?.../platform/mediatek/jpeg/mtk_jpeg_dec_hw.c? |? 3 ++
> ?.../platform/mediatek/jpeg/mtk_jpeg_enc_hw.c? |? 3 ++
> ?3 files changed, 40 insertions(+)
> 
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> index da1ca494ed4b..10a588b92e76 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> @@ -1932,6 +1932,19 @@ static struct mtk_jpeg_variant mtk8195_jpegenc_drvdata
> = {
> ?	.jpeg_worker = mtk_jpegenc_worker,
> ?};
> ?
> +static struct mtk_jpeg_variant mtk8196_jpegenc_drvdata = {
> +	.formats = mtk_jpeg_enc_formats,
> +	.num_formats = MTK_JPEG_ENC_NUM_FORMATS,
> +	.qops = &mtk_jpeg_enc_qops,
> +	.m2m_ops = &mtk_jpeg_multicore_enc_m2m_ops,
> +	.dev_name = "mtk-jpeg-enc",
> +	.ioctl_ops = &mtk_jpeg_enc_ioctl_ops,
> +	.out_q_default_fourcc = V4L2_PIX_FMT_YUYV,
> +	.cap_q_default_fourcc = V4L2_PIX_FMT_JPEG,
> +	.multi_core = true,
> +	.jpeg_worker = mtk_jpegenc_worker,
> +};
> +
> ?static const struct mtk_jpeg_variant mtk8195_jpegdec_drvdata = {
> ?	.formats = mtk_jpeg_dec_formats,
> ?	.num_formats = MTK_JPEG_DEC_NUM_FORMATS,
> @@ -1945,6 +1958,19 @@ static const struct mtk_jpeg_variant
> mtk8195_jpegdec_drvdata = {
> ?	.jpeg_worker = mtk_jpegdec_worker,
> ?};
> ?
> +static const struct mtk_jpeg_variant mtk8196_jpegdec_drvdata = {
> +	.formats = mtk_jpeg_dec_formats,
> +	.num_formats = MTK_JPEG_DEC_NUM_FORMATS,
> +	.qops = &mtk_jpeg_dec_qops,
> +	.m2m_ops = &mtk_jpeg_multicore_dec_m2m_ops,
> +	.dev_name = "mtk-jpeg-dec",
> +	.ioctl_ops = &mtk_jpeg_dec_ioctl_ops,
> +	.out_q_default_fourcc = V4L2_PIX_FMT_JPEG,
> +	.cap_q_default_fourcc = V4L2_PIX_FMT_YUV420M,
> +	.multi_core = true,
> +	.jpeg_worker = mtk_jpegdec_worker,
> +};
> +
> ?static const struct of_device_id mtk_jpeg_match[] = {
> ?	{
> ?		.compatible = "mediatek,mt8173-jpgdec",
> @@ -1966,6 +1992,14 @@ static const struct of_device_id mtk_jpeg_match[] = {
> ?		.compatible = "mediatek,mt8195-jpgdec",
> ?		.data = &mtk8195_jpegdec_drvdata,
> ?	},
> +	{
> +		.compatible = "mediatek,mt8196-jpgenc",
> +		.data = &mtk8196_jpegenc_drvdata,
> +	},
> +	{
> +		.compatible = "mediatek,mt8196-jpgdec",
> +		.data = &mtk8196_jpegdec_drvdata,
> +	},
> ?	{},
> ?};
> ?
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> index b3142dc9be85..e453a1634f33 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> @@ -45,6 +45,9 @@ static const struct of_device_id mtk_jpegdec_hw_ids[] = {
> ?	{
> ?		.compatible = "mediatek,mt8195-jpgdec-hw",
> ?	},
> +	{
> +		.compatible = "mediatek,mt8196-jpgdec-hw",
> +	},
> ?	{},
> ?};
> ?MODULE_DEVICE_TABLE(of, mtk_jpegdec_hw_ids);
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> index 82c971936c4d..b30c728c3712 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> @@ -52,6 +52,9 @@ static const struct of_device_id mtk_jpegenc_drv_ids[] = {
> ?	{
> ?		.compatible = "mediatek,mt8195-jpgenc-hw",
> ?	},
> +	{
> +		.compatible = "mediatek,mt8196-jpgenc-hw",
> +	},
> ?	{},
> ?};
> ?MODULE_DEVICE_TABLE(of, mtk_jpegenc_drv_ids);
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251216/092d4551/attachment.sig>

From nicolas.dufresne at collabora.com  Tue Dec 16 14:02:39 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Tue, 16 Dec 2025 17:02:39 -0500
Subject: [PATCH v5 01/15] media: uapi: HEVC: Add
 v4l2_ctrl_hevc_ext_sps_[ls]t_rps controls
In-Reply-To: <37da2fe3-41bd-470e-bb6c-93fe35ee1528@collabora.com>
References: <20251023214247.459931-1-detlev.casanova@collabora.com>
	 <20251023214247.459931-2-detlev.casanova@collabora.com>
	 <d8ef0f88-e81d-4159-8945-52197cbc95ba@kernel.org>
	 <37da2fe3-41bd-470e-bb6c-93fe35ee1528@collabora.com>
Message-ID: <bcbf8247a778c0a179cef2e0338acb2266c18809.camel@collabora.com>

Hi,

Le mardi 16 d?cembre 2025 ? 15:48 -0500, Detlev Casanova a ?crit?:
> Hi Hans,
> 
> On 10/24/25 03:55, Hans Verkuil wrote:
> > On 23/10/2025 23:42, Detlev Casanova wrote:
> > > Some hardware (e.g.: Rockchip's rk3588 hevc decoder) need the
> > > long and short term reference information for HEVC decoding.
> > > 
> > > Add controls to provide it as the raw data form the stream.
> > > 
> > > Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
> > > ---
> > > ? .../media/v4l/ext-ctrls-codec-stateless.rst?? | 114 ++++++++++++++++++
> > > ? .../media/v4l/videodev2.h.rst.exceptions????? |?? 2 +
> > > ? .../media/v4l/vidioc-queryctrl.rst??????????? |? 12 ++
> > > ? 3 files changed, 128 insertions(+)
> > > 
> > > diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst
> > > index 497ae74379f6..7b18e12fafbb 100644
> > > --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst
> > > +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst
> > > @@ -2959,6 +2959,120 @@ This structure contains all loop filter related parameters. See sections
> > > ??????? - 0x00000004
> > > ??????? -
> > > ? 
> > > +``V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS (struct)``
> > > +??? Specifies the list of Long-Term reference sets parameters from the SPS.
> > > +??? These parameters are defined according to :ref:`hevc`.
> > > +??? They are described in section 7.4.3.2.1 "General sequence parameter set
> > > +??? RBSP semantics" of the specification.
> > > +??? This control is a dynamically sized 1-dimensional array,
> > > +??? V4L2_CTRL_FLAG_DYNAMIC_ARRAY flag must be set when using it.
> > I'd drop this last sentence. It suggests that the application has to set it,
> > but is it set by the kernel.
> > 
> > Same for the next control below.
> > 
> > I noticed that this is probably a copy-and-paste from the V4L2_CID_STATELESS_HEVC_SLICE_PARAMS
> > documentation: can you post a separate patch removing that same line from the description of
> > that control? I think it is a confusing line, and we missed it during the original review
> > of V4L2_CID_STATELESS_HEVC_SLICE_PARAMS.
> > 
> > I have another question about these two controls: currently dynamic controls have always at
> > least one element. I have been working on supporting zero-sized dynamic controls. Would
> > that make sense here? Or will these two controls - if present - always have one element or
> > more?
> > 
> > If zero-length dynamic array controls are useful here, then I can clean up my patches and
> > post them so you can use it.
> 
> I guess that could happen depending on what userspace does, but the size 
> of the array is determined by num_long_term_ref_pics_sps and 
> num_short_term_ref_pic_sets from v4l2_ctrl_hevc_sps respectively.
> 
> If that value is 0, there is no point in setting the (respective) 
> control, except for simplifying userspace code I suppose.
> 
> So 0-length support is avoidable.

With our rule of keeping controls as consistent as possible, we'd need a zero
length array here since key frame have zero long and short references.

Basically, we should be able to clear that control when
long_term_ref_pics_present_flag is not set, or num_short_term_ref_pic_sets is
zero.

Feel free to send an update anyway, since I don't expect Hans to be able to
provide this code now, would have been better to reply earlier. In fact, I agree
we can probably move on without the zero-length immediately added and add it
later.

Before going that route, how big are these two arrays ? Short term can be 64
ref, long term 32, how big in bytes that is ? Was is worth goign with dynamic
array ? Its not like slices, where we can have 600 or more.

Nicolas

> 
> Detlev.
> 
> > Regards,
> > 
> > 	Hans
> > 
> > > +
> > > +.. c:type:: v4l2_ctrl_hevc_ext_sps_lt_rps
> > > +
> > > +.. cssclass:: longtable
> > > +
> > > +.. flat-table:: struct v4l2_ctrl_hevc_ext_sps_lt_rps
> > > +??? :header-rows:? 0
> > > +??? :stub-columns: 0
> > > +??? :widths:?????? 1 1 2
> > > +
> > > +??? * - __u16
> > > +????? - ``lt_ref_pic_poc_lsb_sps``
> > > +????? - Long term reference picture order count as described in section 7.4.3.2.1
> > > +??????? "General sequence parameter set RBSP semantics" of the specification.
> > > +??? * - __u8
> > > +????? - ``flags``
> > > +????? - See :ref:`Extended Long-Term RPS Flags <hevc_ext_sps_lt_rps_flags>`
> > > +
> > > +.. _hevc_ext_sps_lt_rps_flags:
> > > +
> > > +``Extended SPS Long-Term RPS Flags``
> > > +
> > > +.. cssclass:: longtable
> > > +
> > > +.. flat-table::
> > > +??? :header-rows:? 0
> > > +??? :stub-columns: 0
> > > +??? :widths:?????? 1 1 2
> > > +
> > > +??? * - ``V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_USED_LT``
> > > +????? - 0x00000001
> > > +????? - Specifies if the long-term reference picture is used 7.4.3.2.1 "General sequence parameter
> > > +??????? set RBSP semantics" of the specification.
> > > +
> > > +``V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS (struct)``
> > > +??? Specifies the list of Short-Term reference sets parameters from the SPS.
> > > +??? These parameters are defined according to :ref:`hevc`.
> > > +??? They are described in section 7.4.8 "Short-term reference picture set
> > > +??? semantics" of the specification.
> > > +??? This control is a dynamically sized 1-dimensional array,
> > > +??? V4L2_CTRL_FLAG_DYNAMIC_ARRAY flag must be set when using it.
> > > +
> > > +.. c:type:: v4l2_ctrl_hevc_ext_sps_st_rps
> > > +
> > > +.. cssclass:: longtable
> > > +
> > > +.. flat-table:: struct v4l2_ctrl_hevc_ext_sps_st_rps
> > > +??? :header-rows:? 0
> > > +??? :stub-columns: 0
> > > +??? :widths:?????? 1 1 2
> > > +
> > > +??? * - __u8
> > > +????? - ``delta_idx_minus1``
> > > +????? - Specifies the delta compare to the index. See details in section 7.4.8 "Short-term
> > > +??????? reference picture set semantics" of the specification.
> > > +??? * - __u8
> > > +????? - ``delta_rps_sign``
> > > +????? - Sign of the delta as specified in section 7.4.8 "Short-term reference picture set
> > > +??????? semantics" of the specification.
> > > +??? * - __u16
> > > +????? - ``abs_delta_rps_minus1``
> > > +????? - Absolute delta RPS as specified in section 7.4.8 "Short-term reference picture set
> > > +??????? semantics" of the specification.
> > > +??? * - __u8
> > > +????? - ``num_negative_pics``
> > > +????? - Number of short-term RPS entries that have picture order count values less than the
> > > +??????? picture order count value of the current picture.
> > > +??? * - __u8
> > > +????? - ``num_positive_pics``
> > > +????? - Number of short-term RPS entries that have picture order count values greater than the
> > > +??????? picture order count value of the current picture.
> > > +??? * - __u32
> > > +????? - ``used_by_curr_pic``
> > > +????? - Bit i specifies if short-term RPS i is used by the current picture.
> > > +??? * - __u32
> > > +????? - ``use_delta_flag``
> > > +????? - Bit i specifies if short-term RPS i is included in the short-term RPS entries.
> > > +??? * - __u16
> > > +????? - ``delta_poc_s0_minus1[16]``
> > > +????? - Specifies the negative picture order count delta for the i-th entry in the short-term RPS.
> > > +??????? See details in section 7.4.8 "Short-term reference picture set semantics" of the
> > > +??????? specification.
> > > +??? * - __u16
> > > +????? - ``delta_poc_s1_minus1[16]``
> > > +????? - Specifies the positive picture order count delta for the i-th entry in the short-term RPS.
> > > +??????? See details in section 7.4.8 "Short-term reference picture set semantics" of the
> > > +??????? specification.
> > > +??? * - __u8
> > > +????? - ``flags``
> > > +????? - See :ref:`Extended Short-Term RPS Flags <hevc_ext_sps_st_rps_flags>`
> > > +
> > > +.. _hevc_ext_sps_st_rps_flags:
> > > +
> > > +``Extended SPS Short-Term RPS Flags``
> > > +
> > > +.. cssclass:: longtable
> > > +
> > > +.. flat-table::
> > > +??? :header-rows:? 0
> > > +??? :stub-columns: 0
> > > +??? :widths:?????? 1 1 2
> > > +
> > > +??? * - ``V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED``
> > > +????? - 0x00000001
> > > +????? - Specifies if the short-term RPS is predicted from another short term RPS. See details in
> > > +??????? section 7.4.8 "Short-term reference picture set semantics" of the specification.
> > > +
> > > ? .. _v4l2-codec-stateless-av1:
> > > ? 
> > > ? ``V4L2_CID_STATELESS_AV1_SEQUENCE (struct)``
> > > diff --git a/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions b/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions
> > > index c41693115db6..6182b4e2d2ee 100644
> > > --- a/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions
> > > +++ b/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions
> > > @@ -150,6 +150,8 @@ replace symbol V4L2_CTRL_TYPE_H264_SCALING_MATRIX :c:type:`V4L.v4l2_ctrl_type`
> > > ? replace symbol V4L2_CTRL_TYPE_H264_PRED_WEIGHTS :c:type:`V4L.v4l2_ctrl_type`
> > > ? replace symbol V4L2_CTRL_TYPE_H264_SLICE_PARAMS :c:type:`V4L.v4l2_ctrl_type`
> > > ? replace symbol V4L2_CTRL_TYPE_H264_DECODE_PARAMS :c:type:`V4L.v4l2_ctrl_type`
> > > +replace symbol V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS :c:type:`V4L.v4l2_ctrl_type`
> > > +replace symbol V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS :c:type:`V4L.v4l2_ctrl_type`
> > > ? replace symbol V4L2_CTRL_TYPE_HEVC_SPS :c:type:`V4L.v4l2_ctrl_type`
> > > ? replace symbol V4L2_CTRL_TYPE_HEVC_PPS :c:type:`V4L.v4l2_ctrl_type`
> > > ? replace symbol V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS :c:type:`V4L.v4l2_ctrl_type`
> > > diff --git a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
> > > index c8baa9430c14..82c8b52e771c 100644
> > > --- a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
> > > +++ b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
> > > @@ -531,6 +531,18 @@ See also the examples in :ref:`control`.
> > > ??????? - n/a
> > > ??????? - A struct :c:type:`v4l2_ctrl_hevc_decode_params`, containing HEVC
> > > ??	decoding parameters for stateless video decoders.
> > > +??? * - ``V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS``
> > > +????? - n/a
> > > +????? - n/a
> > > +????? - n/a
> > > +????? - A struct :c:type:`v4l2_ctrl_hevc_ext_sps_lt_rps`, containing HEVC
> > > +	extended Long-Term RPS for stateless video decoders.
> > > +??? * - ``V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS``
> > > +????? - n/a
> > > +????? - n/a
> > > +????? - n/a
> > > +????? - A struct :c:type:`v4l2_ctrl_hevc_ext_sps_st_rps`, containing HEVC
> > > +	extended Short-Term RPS for stateless video decoders.
> > > ????? * - ``V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR``
> > > ??????? - n/a
> > > ??????? - n/a
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251216/440c655f/attachment-0001.sig>

From mathieu.poirier at linaro.org  Tue Dec 16 14:12:57 2025
From: mathieu.poirier at linaro.org (Mathieu Poirier)
Date: Tue, 16 Dec 2025 15:12:57 -0700
Subject: [PATCH v2] remoteproc: imx_dsp_rproc: Fix multiple start/stop
 operations
In-Reply-To: <20251210154906.99210-1-daniel.baluta@nxp.com>
References: <20251210154906.99210-1-daniel.baluta@nxp.com>
Message-ID: <aUHZaapZ1IAs_mRE@p14s>

Good day,

On Wed, Dec 10, 2025 at 05:49:06PM +0200, Daniel Baluta wrote:
> After commit 67a7bc7f0358 ("remoteproc: Use of reserved_mem_region_*
> functions for "memory-region"") following commands with
> imx-dsp-rproc started to fail:
> 
> $ echo zephyr.elf > /sys/class/remoteproc/remoteproc0/firmware
> $ echo start > /sys/class/remoteproc/remoteproc0/state
> $ echo stop > /sys/class/remoteproc/remoteproc0/state
> $ echo start > /sys/class/remoteproc/remoteproc0/state #! This fails
> -sh: echo: write error: Device or resource busy
> 
> This happens because aforementioned commit replaced devm_ioremap_wc with
> devm_ioremap_resource_wc which will "reserve" the memory region with the
> first start and then will fail at the second start if the memory
> region is already reserved.
> 
> Even partially reverting the faulty commit won't fix the
> underlying issue because we map the address in prepare() but we never
> unmap it at unprepare(), so we will keep leaking memory regions.
> 
> So, lets use alloc() and release() callbacks for memory carveout
> handling. This will nicely map() the memory region at prepare() time
> and unmap() it at unprepare().
> 
> Fixes: 67a7bc7f0358 ("remoteproc: Use of_reserved_mem_region_* functions for "memory-region"")
> Signed-off-by: Daniel Baluta <daniel.baluta at nxp.com>
> ---
> Changes since v1:
>  * https://lore.kernel.org/imx/091a4f29-5435-428a-9a1c-ef82465211cb at nxp.com/T/#t 
>  * took a different approach and instead of partially reverting the
>   faulty patch, used alloc() and release() callbacks to handle memory
>   region mapping.
>  drivers/remoteproc/imx_dsp_rproc.c | 50 ++++++++++++++++++++----------
>  1 file changed, 33 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c
> index 5130a35214c9..83468558e634 100644
> --- a/drivers/remoteproc/imx_dsp_rproc.c
> +++ b/drivers/remoteproc/imx_dsp_rproc.c
> @@ -644,6 +644,32 @@ static void imx_dsp_rproc_free_mbox(struct imx_dsp_rproc *priv)
>  	mbox_free_channel(priv->rxdb_ch);
>  }
>  
> +static int imx_dsp_rproc_mem_alloc(struct rproc *rproc,
> +				   struct rproc_mem_entry *mem)
> +{
> +	struct device *dev = rproc->dev.parent;
> +	void *va;
> +
> +	va = ioremap_wc(mem->dma, mem->len);
> +	if (!va) {
> +		dev_err(dev, "Unable to map memory region: %pa+%zx\n",
> +			&mem->dma, mem->len);
> +		return -ENOMEM;
> +	}
> +
> +	mem->va = va;
> +
> +	return 0;
> +}
> +
> +static int imx_dsp_rproc_mem_release(struct rproc *rproc,
> +				     struct rproc_mem_entry *mem)
> +{
> +	iounmap(mem->va);
> +
> +	return 0;
> +}
> +
>  /**
>   * imx_dsp_rproc_add_carveout() - request mailbox channels
>   * @priv: private data pointer
> @@ -659,7 +685,6 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv)
>  	struct device *dev = rproc->dev.parent;
>  	struct device_node *np = dev->of_node;
>  	struct rproc_mem_entry *mem;
> -	void __iomem *cpu_addr;
>  	int a, i = 0;
>  	u64 da;
>  
> @@ -673,15 +698,10 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv)
>  		if (imx_dsp_rproc_sys_to_da(priv, att->sa, att->size, &da))
>  			return -EINVAL;
>  
> -		cpu_addr = devm_ioremap_wc(dev, att->sa, att->size);
> -		if (!cpu_addr) {
> -			dev_err(dev, "failed to map memory %p\n", &att->sa);
> -			return -ENOMEM;
> -		}
> -
>  		/* Register memory region */
> -		mem = rproc_mem_entry_init(dev, (void __force *)cpu_addr, (dma_addr_t)att->sa,
> -					   att->size, da, NULL, NULL, "dsp_mem");
> +		mem = rproc_mem_entry_init(dev, NULL, (dma_addr_t)att->sa,
> +					   att->size, da, imx_dsp_rproc_mem_alloc,
> +					   imx_dsp_rproc_mem_release, "dsp_mem");

Was there a reason you kept those here rather than moving them to probe() as
Iuliana suggested?  Note that I would be fine with this solution since this is
how it was before, but if we have to go through a refactoring we may as well
take those things into account.

>  
>  		if (mem)
>  			rproc_coredump_add_segment(rproc, da, att->size);
> @@ -709,15 +729,11 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv)
>  		if (imx_dsp_rproc_sys_to_da(priv, res.start, resource_size(&res), &da))
>  			return -EINVAL;
>  
> -		cpu_addr = devm_ioremap_resource_wc(dev, &res);
> -		if (IS_ERR(cpu_addr)) {
> -			dev_err(dev, "failed to map memory %pR\n", &res);
> -			return PTR_ERR(cpu_addr);
> -		}
> -
>  		/* Register memory region */
> -		mem = rproc_mem_entry_init(dev, (void __force *)cpu_addr, (dma_addr_t)res.start,
> -					   resource_size(&res), da, NULL, NULL,
> +		mem = rproc_mem_entry_init(dev, NULL, (dma_addr_t)res.start,
> +					   resource_size(&res), da,
> +					    imx_dsp_rproc_mem_alloc,
> +					    imx_dsp_rproc_mem_release,
>  					   "%.*s", strchrnul(res.name, '@') - res.name, res.name);

I'm fine with this part.

Thanks,
Mathieu

>  		if (!mem)
>  			return -ENOMEM;
> -- 
> 2.45.2
> 


From detlev.casanova at collabora.com  Tue Dec 16 14:18:20 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Tue, 16 Dec 2025 17:18:20 -0500
Subject: [PATCH v5 01/15] media: uapi: HEVC: Add
 v4l2_ctrl_hevc_ext_sps_[ls]t_rps controls
In-Reply-To: <bcbf8247a778c0a179cef2e0338acb2266c18809.camel@collabora.com>
References: <20251023214247.459931-1-detlev.casanova@collabora.com>
 <20251023214247.459931-2-detlev.casanova@collabora.com>
 <d8ef0f88-e81d-4159-8945-52197cbc95ba@kernel.org>
 <37da2fe3-41bd-470e-bb6c-93fe35ee1528@collabora.com>
 <bcbf8247a778c0a179cef2e0338acb2266c18809.camel@collabora.com>
Message-ID: <e88eb64e-ae47-4c70-87af-44c8f0371be9@collabora.com>

Hi,

On 12/16/25 17:02, Nicolas Dufresne wrote:
> Hi,
>
> Le mardi 16 d?cembre 2025 ? 15:48 -0500, Detlev Casanova a ?crit?:
>> Hi Hans,
>>
>> On 10/24/25 03:55, Hans Verkuil wrote:
>>> On 23/10/2025 23:42, Detlev Casanova wrote:
>>>> Some hardware (e.g.: Rockchip's rk3588 hevc decoder) need the
>>>> long and short term reference information for HEVC decoding.
>>>>
>>>> Add controls to provide it as the raw data form the stream.
>>>>
>>>> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
>>>> ---
>>>>  ? .../media/v4l/ext-ctrls-codec-stateless.rst?? | 114 ++++++++++++++++++
>>>>  ? .../media/v4l/videodev2.h.rst.exceptions????? |?? 2 +
>>>>  ? .../media/v4l/vidioc-queryctrl.rst??????????? |? 12 ++
>>>>  ? 3 files changed, 128 insertions(+)
>>>>
>>>> diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst
>>>> index 497ae74379f6..7b18e12fafbb 100644
>>>> --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst
>>>> +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst
>>>> @@ -2959,6 +2959,120 @@ This structure contains all loop filter related parameters. See sections
>>>>  ??????? - 0x00000004
>>>>  ??????? -
>>>>    
>>>> +``V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS (struct)``
>>>> +??? Specifies the list of Long-Term reference sets parameters from the SPS.
>>>> +??? These parameters are defined according to :ref:`hevc`.
>>>> +??? They are described in section 7.4.3.2.1 "General sequence parameter set
>>>> +??? RBSP semantics" of the specification.
>>>> +??? This control is a dynamically sized 1-dimensional array,
>>>> +??? V4L2_CTRL_FLAG_DYNAMIC_ARRAY flag must be set when using it.
>>> I'd drop this last sentence. It suggests that the application has to set it,
>>> but is it set by the kernel.
>>>
>>> Same for the next control below.
>>>
>>> I noticed that this is probably a copy-and-paste from the V4L2_CID_STATELESS_HEVC_SLICE_PARAMS
>>> documentation: can you post a separate patch removing that same line from the description of
>>> that control? I think it is a confusing line, and we missed it during the original review
>>> of V4L2_CID_STATELESS_HEVC_SLICE_PARAMS.
>>>
>>> I have another question about these two controls: currently dynamic controls have always at
>>> least one element. I have been working on supporting zero-sized dynamic controls. Would
>>> that make sense here? Or will these two controls - if present - always have one element or
>>> more?
>>>
>>> If zero-length dynamic array controls are useful here, then I can clean up my patches and
>>> post them so you can use it.
>> I guess that could happen depending on what userspace does, but the size
>> of the array is determined by num_long_term_ref_pics_sps and
>> num_short_term_ref_pic_sets from v4l2_ctrl_hevc_sps respectively.
>>
>> If that value is 0, there is no point in setting the (respective)
>> control, except for simplifying userspace code I suppose.
>>
>> So 0-length support is avoidable.
> With our rule of keeping controls as consistent as possible, we'd need a zero
> length array here since key frame have zero long and short references.
>
> Basically, we should be able to clear that control when
> long_term_ref_pics_present_flag is not set, or num_short_term_ref_pic_sets is
> zero.
>
> Feel free to send an update anyway, since I don't expect Hans to be able to
> provide this code now, would have been better to reply earlier. In fact, I agree
> we can probably move on without the zero-length immediately added and add it
> later.
I don't really see why it can't currently be set to a zero-length though.
> Before going that route, how big are these two arrays ? Short term can be 64
> ref, long term 32, how big in bytes that is ? Was is worth goign with dynamic
> array ? Its not like slices, where we can have 600 or more.

The short term one can still be quite big, it's about 80 bytes per 
element, so 5120 bytes for the 64.

I don't know how often we go that high, I've seen around 10 short term 
ref sets in test videos.

> Nicolas
>
>> Detlev.
>>
>>> Regards,
>>>
>>> 	Hans
>>>
>>>> +
>>>> +.. c:type:: v4l2_ctrl_hevc_ext_sps_lt_rps
>>>> +
>>>> +.. cssclass:: longtable
>>>> +
>>>> +.. flat-table:: struct v4l2_ctrl_hevc_ext_sps_lt_rps
>>>> +??? :header-rows:? 0
>>>> +??? :stub-columns: 0
>>>> +??? :widths:?????? 1 1 2
>>>> +
>>>> +??? * - __u16
>>>> +????? - ``lt_ref_pic_poc_lsb_sps``
>>>> +????? - Long term reference picture order count as described in section 7.4.3.2.1
>>>> +??????? "General sequence parameter set RBSP semantics" of the specification.
>>>> +??? * - __u8
>>>> +????? - ``flags``
>>>> +????? - See :ref:`Extended Long-Term RPS Flags <hevc_ext_sps_lt_rps_flags>`
>>>> +
>>>> +.. _hevc_ext_sps_lt_rps_flags:
>>>> +
>>>> +``Extended SPS Long-Term RPS Flags``
>>>> +
>>>> +.. cssclass:: longtable
>>>> +
>>>> +.. flat-table::
>>>> +??? :header-rows:? 0
>>>> +??? :stub-columns: 0
>>>> +??? :widths:?????? 1 1 2
>>>> +
>>>> +??? * - ``V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_USED_LT``
>>>> +????? - 0x00000001
>>>> +????? - Specifies if the long-term reference picture is used 7.4.3.2.1 "General sequence parameter
>>>> +??????? set RBSP semantics" of the specification.
>>>> +
>>>> +``V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS (struct)``
>>>> +??? Specifies the list of Short-Term reference sets parameters from the SPS.
>>>> +??? These parameters are defined according to :ref:`hevc`.
>>>> +??? They are described in section 7.4.8 "Short-term reference picture set
>>>> +??? semantics" of the specification.
>>>> +??? This control is a dynamically sized 1-dimensional array,
>>>> +??? V4L2_CTRL_FLAG_DYNAMIC_ARRAY flag must be set when using it.
>>>> +
>>>> +.. c:type:: v4l2_ctrl_hevc_ext_sps_st_rps
>>>> +
>>>> +.. cssclass:: longtable
>>>> +
>>>> +.. flat-table:: struct v4l2_ctrl_hevc_ext_sps_st_rps
>>>> +??? :header-rows:? 0
>>>> +??? :stub-columns: 0
>>>> +??? :widths:?????? 1 1 2
>>>> +
>>>> +??? * - __u8
>>>> +????? - ``delta_idx_minus1``
>>>> +????? - Specifies the delta compare to the index. See details in section 7.4.8 "Short-term
>>>> +??????? reference picture set semantics" of the specification.
>>>> +??? * - __u8
>>>> +????? - ``delta_rps_sign``
>>>> +????? - Sign of the delta as specified in section 7.4.8 "Short-term reference picture set
>>>> +??????? semantics" of the specification.
>>>> +??? * - __u16
>>>> +????? - ``abs_delta_rps_minus1``
>>>> +????? - Absolute delta RPS as specified in section 7.4.8 "Short-term reference picture set
>>>> +??????? semantics" of the specification.
>>>> +??? * - __u8
>>>> +????? - ``num_negative_pics``
>>>> +????? - Number of short-term RPS entries that have picture order count values less than the
>>>> +??????? picture order count value of the current picture.
>>>> +??? * - __u8
>>>> +????? - ``num_positive_pics``
>>>> +????? - Number of short-term RPS entries that have picture order count values greater than the
>>>> +??????? picture order count value of the current picture.
>>>> +??? * - __u32
>>>> +????? - ``used_by_curr_pic``
>>>> +????? - Bit i specifies if short-term RPS i is used by the current picture.
>>>> +??? * - __u32
>>>> +????? - ``use_delta_flag``
>>>> +????? - Bit i specifies if short-term RPS i is included in the short-term RPS entries.
>>>> +??? * - __u16
>>>> +????? - ``delta_poc_s0_minus1[16]``
>>>> +????? - Specifies the negative picture order count delta for the i-th entry in the short-term RPS.
>>>> +??????? See details in section 7.4.8 "Short-term reference picture set semantics" of the
>>>> +??????? specification.
>>>> +??? * - __u16
>>>> +????? - ``delta_poc_s1_minus1[16]``
>>>> +????? - Specifies the positive picture order count delta for the i-th entry in the short-term RPS.
>>>> +??????? See details in section 7.4.8 "Short-term reference picture set semantics" of the
>>>> +??????? specification.
>>>> +??? * - __u8
>>>> +????? - ``flags``
>>>> +????? - See :ref:`Extended Short-Term RPS Flags <hevc_ext_sps_st_rps_flags>`
>>>> +
>>>> +.. _hevc_ext_sps_st_rps_flags:
>>>> +
>>>> +``Extended SPS Short-Term RPS Flags``
>>>> +
>>>> +.. cssclass:: longtable
>>>> +
>>>> +.. flat-table::
>>>> +??? :header-rows:? 0
>>>> +??? :stub-columns: 0
>>>> +??? :widths:?????? 1 1 2
>>>> +
>>>> +??? * - ``V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED``
>>>> +????? - 0x00000001
>>>> +????? - Specifies if the short-term RPS is predicted from another short term RPS. See details in
>>>> +??????? section 7.4.8 "Short-term reference picture set semantics" of the specification.
>>>> +
>>>>  ? .. _v4l2-codec-stateless-av1:
>>>>    
>>>>  ? ``V4L2_CID_STATELESS_AV1_SEQUENCE (struct)``
>>>> diff --git a/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions b/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions
>>>> index c41693115db6..6182b4e2d2ee 100644
>>>> --- a/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions
>>>> +++ b/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions
>>>> @@ -150,6 +150,8 @@ replace symbol V4L2_CTRL_TYPE_H264_SCALING_MATRIX :c:type:`V4L.v4l2_ctrl_type`
>>>>  ? replace symbol V4L2_CTRL_TYPE_H264_PRED_WEIGHTS :c:type:`V4L.v4l2_ctrl_type`
>>>>  ? replace symbol V4L2_CTRL_TYPE_H264_SLICE_PARAMS :c:type:`V4L.v4l2_ctrl_type`
>>>>  ? replace symbol V4L2_CTRL_TYPE_H264_DECODE_PARAMS :c:type:`V4L.v4l2_ctrl_type`
>>>> +replace symbol V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS :c:type:`V4L.v4l2_ctrl_type`
>>>> +replace symbol V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS :c:type:`V4L.v4l2_ctrl_type`
>>>>  ? replace symbol V4L2_CTRL_TYPE_HEVC_SPS :c:type:`V4L.v4l2_ctrl_type`
>>>>  ? replace symbol V4L2_CTRL_TYPE_HEVC_PPS :c:type:`V4L.v4l2_ctrl_type`
>>>>  ? replace symbol V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS :c:type:`V4L.v4l2_ctrl_type`
>>>> diff --git a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
>>>> index c8baa9430c14..82c8b52e771c 100644
>>>> --- a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
>>>> +++ b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
>>>> @@ -531,6 +531,18 @@ See also the examples in :ref:`control`.
>>>>  ??????? - n/a
>>>>  ??????? - A struct :c:type:`v4l2_ctrl_hevc_decode_params`, containing HEVC
>>>>  ??	decoding parameters for stateless video decoders.
>>>> +??? * - ``V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS``
>>>> +????? - n/a
>>>> +????? - n/a
>>>> +????? - n/a
>>>> +????? - A struct :c:type:`v4l2_ctrl_hevc_ext_sps_lt_rps`, containing HEVC
>>>> +	extended Long-Term RPS for stateless video decoders.
>>>> +??? * - ``V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS``
>>>> +????? - n/a
>>>> +????? - n/a
>>>> +????? - n/a
>>>> +????? - A struct :c:type:`v4l2_ctrl_hevc_ext_sps_st_rps`, containing HEVC
>>>> +	extended Short-Term RPS for stateless video decoders.
>>>>  ????? * - ``V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR``
>>>>  ??????? - n/a
>>>>  ??????? - n/a


From robh at kernel.org  Tue Dec 16 14:28:57 2025
From: robh at kernel.org (Rob Herring)
Date: Tue, 16 Dec 2025 16:28:57 -0600
Subject: [PATCH v2 0/2] Update firmware dt-binding
In-Reply-To: <20251212100542.2756757-1-ronak.jain@amd.com>
References: <20251212100542.2756757-1-ronak.jain@amd.com>
Message-ID: <20251216222857.GA3151380-robh@kernel.org>

On Fri, Dec 12, 2025 at 02:05:40AM -0800, Ronak Jain wrote:
> The patch fixes/enhances below problems,
>     1. Add missing compatible property under the example section for
>     zynqmp_firmware node.
>     2. Add conditional pinctrl schema
> 
> Changes in v2:
> - Added acked-by signature in patch #1
> - Following up on the queries again in patch #2. No code changes in
> the patch itself
> - Dropped off patch #3
> 
> Ronak Jain (2):
>   dt-bindings: firmware: xilinx: Add xlnx,zynqmp-firmware compatible
>   dt-bindings: firmware: xilinx: Add conditional pinctrl schema

Applied, thanks.

Rob


From robh at kernel.org  Tue Dec 16 14:35:01 2025
From: robh at kernel.org (Rob Herring)
Date: Tue, 16 Dec 2025 16:35:01 -0600
Subject: [PATCH v2 2/2] dt-bindings: firmware: xilinx: Add conditional
 pinctrl schema
In-Reply-To: <20251212100542.2756757-3-ronak.jain@amd.com>
References: <20251212100542.2756757-1-ronak.jain@amd.com>
 <20251212100542.2756757-3-ronak.jain@amd.com>
Message-ID: <20251216223501.GB3151380-robh@kernel.org>

On Fri, Dec 12, 2025 at 02:05:42AM -0800, Ronak Jain wrote:
> Updates the Device Tree bindings for Xilinx firmware by introducing
> conditional schema references for the pinctrl node.
> 
> Previously, the pinctrl node directly referenced
> xlnx,zynqmp-pinctrl.yaml. However, this patch modifies the schema to
> conditionally apply the correct pinctrl schema based on the compatible
> property. Specifically:
> - If compatible contains "xlnx,zynqmp-pinctrl", reference
>   xlnx,zynqmp-pinctrl.yaml.
> - If compatible contains "xlnx,versal-pinctrl", reference
>   xlnx,versal-pinctrl.yaml.
> 
> Additionally, an example entry for "xlnx,versal-pinctrl" has been
> added under the examples section.
> 
> Signed-off-by: Ronak Jain <ronak.jain at amd.com>
> ---
> Suggestion from Rob:
> 
> The somewhat preferred way to do this would be to do this in the top
> level:
> 
> pinctrl:
>   type: object
>   additionalProperties: true
>   properties:
>     compatible:
>       contains:
>         enum:
>           - xlnx,zynqmp-pinctrl
>           - xlnx,versal-pinctrl
>   required:
>     - compatible
> 
> Otherwise, the pinctrl schema ends up being applied twice.
> 
> 
> My response:
> 
> In your suggested code, the schema allows either xlnx,zynqmp-pinctrl
> or xlnx,versal-pinctrl on any platform, which is incorrect. This
> means that if a user mistakenly assigns xlnx,versal-pinctrl to a
> ZynqMP platform or xlnx,zynqmp-pinctrl to a Versal platform, the
> wrong reference will be used, but no error is reported. The
> dt-binding check still passes instead of flagging this as an issue.

True, but you can create a whole DT that's just random bindings from all 
sorts of different SoCs and the schema validation would be perfectly 
happy. We can't really ever check everything.

> By using a conditional schema, we can enforce platform-specific
> compatibility, ensuring that the correct compatible string is used
> for the corresponding platform. This would also generate an error if
> an incorrect compatible string is provided, preventing
> misconfigurations.

But what you have is fine too. It will validate the node twice as I 
pointed out and that slows things down some, but it's already slow...

Rob


From smostafa at google.com  Tue Dec 16 14:49:58 2025
From: smostafa at google.com (Mostafa Saleh)
Date: Tue, 16 Dec 2025 22:49:58 +0000
Subject: [PATCH rc v3 1/4] iommu/arm-smmu-v3: Add ignored bits to fix STE
 update sequence
In-Reply-To: <aUB0t4MSf624Wwmw@Asurada-Nvidia>
References: <cover.1765334526.git.nicolinc@nvidia.com> <cc0d4ab571e2e789ee1cddfa035379dc54f0601b.1765334526.git.nicolinc@nvidia.com>
 <aT87A1ur4htPjM5T@google.com> <aUB0t4MSf624Wwmw@Asurada-Nvidia>
Message-ID: <CAFgf54pDfBhx8j0M0JJfJR8kDwqOyPem7W1E8kpmBur5q2pjxQ@mail.gmail.com>

On Mon, Dec 15, 2025 at 8:51?PM Nicolin Chen <nicolinc at nvidia.com> wrote:
>
> Hi Mostafa,
>
> On Sun, Dec 14, 2025 at 10:32:35PM +0000, Mostafa Saleh wrote:
> > On Tue, Dec 09, 2025 at 06:45:16PM -0800, Nicolin Chen wrote:
> > > @@ -1207,12 +1223,9 @@ void arm_smmu_write_entry(struct arm_smmu_entry_writer *writer, __le64 *entry,
> > >             entry_set(writer, entry, target, 0, 1);
> > >     } else {
> > >             /*
> > > -            * No inuse bit changed. Sanity check that all unused bits are 0
> > > -            * in the entry. The target was already sanity checked by
> > > -            * compute_qword_diff().
> > > +            * No inuse bit changed, though ignored bits may have changed.
> > >              */
> > > -           WARN_ON_ONCE(
> > > -                   entry_set(writer, entry, target, 0, NUM_ENTRY_QWORDS));
> > > +           entry_set(writer, entry, target, 0, NUM_ENTRY_QWORDS);
> >
> > After this change, no other caller uses the entry_set() return value, so it
> > can be changed to return void.
>
> OK.
>
> > >     }
> > >  }
> > >  EXPORT_SYMBOL_IF_KUNIT(arm_smmu_write_entry);
> > > @@ -1543,6 +1556,7 @@ static void arm_smmu_ste_writer_sync_entry(struct arm_smmu_entry_writer *writer)
> > >  static const struct arm_smmu_entry_writer_ops arm_smmu_ste_writer_ops = {
> > >     .sync = arm_smmu_ste_writer_sync_entry,
> > >     .get_used = arm_smmu_get_ste_used,
> > > +   .get_ignored = arm_smmu_get_ste_ignored,
> > >  };
> > >
> >
> > I have some mixed feelings about this, having get_used(), then get_ignored()
> > with the same bits set seems confusing to me, specially the get_ignored()
> > loops back to update cur_used, which is set from get_used()
> >
> > My initial though was just to remove this bit from get_used() + some changes
> > to checks setting bits that are not used would be enough, and the semantics
> > of get_used() can be something as:
> > ?Return bits used by the updated translation regime that MUST be observed
> > atomically? and in that case we can ignore things as MEV as it doesn?t
> > impact the translation.
> >
> > However, this approach makes it a bit explicit which bits are ignored, if we
> > keep this logic, I think changing the name of get_ignored() might help, to
> > something as "get_allowed_break()" or "get_update_safe()"?
>
> I think "ignored" itself is brief and understandable.. Instead,
> perhaps we can add a kdocs to make it clearer:
>
> /**
>  * struct arm_smmu_entry_writer_ops - STE/CD entry writer operations
>  * @get_used: Output to @used the bits used by the hardware corresponding to the
>  *            configurations bits set in a given @entry
>  * @get_ignored: Output to @ignored the bits that are listed in the "used" list
>  *               but allowed to be ignored by arm_smmu_entry_qword_diff(). Each
>  *               field (bits) must provide a reason to justify that the entries
>  *               can be updated safely without breaking STE/CD configurations.
>  * @sync: Operation to synchronize the updated STE/CD entries in the memory
>  */
> struct arm_smmu_entry_writer_ops {
>         void (*get_used)(const __le64 *entry, __le64 *used);
>         void (*get_ignored)(__le64 *ignored);
>         void (*sync)(struct arm_smmu_entry_writer *writer);
> };
>
> ?
>

A comment is indeed helpful, but my point was that "used" and
"ignored" make it seem that they are mutually exclusive.

Thanks,
Mostafa

> Thanks
> Nicolin


From dlechner at baylibre.com  Tue Dec 16 14:57:53 2025
From: dlechner at baylibre.com (David Lechner)
Date: Tue, 16 Dec 2025 16:57:53 -0600
Subject: [PATCH] arm64: dts: mediatek: mt8365: fix infracfg_nao node
Message-ID: <20251216-mtk-fix-infracfg_nao-compatibile-v1-1-d339b151ac81@baylibre.com>

Use correct compatible string for the infracfg_nao: node and remove
the #clock-cells property.

Likely this was copied from the similar infracfg: node. However,
infracfg_nao: is just a syscon node with it's own register definitions
and is not a clock provider.

Fixes: 6ff945376556 ("arm64: dts: mediatek: Initial mt8365-evk support")
Signed-off-by: David Lechner <dlechner at baylibre.com>
---
 arch/arm64/boot/dts/mediatek/mt8365.dtsi | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/mediatek/mt8365.dtsi b/arch/arm64/boot/dts/mediatek/mt8365.dtsi
index a5ca3cda6ef3..4116f96c81a9 100644
--- a/arch/arm64/boot/dts/mediatek/mt8365.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8365.dtsi
@@ -537,9 +537,8 @@ iommu: iommu at 10205000 {
 		};
 
 		infracfg_nao: infracfg at 1020e000 {
-			compatible = "mediatek,mt8365-infracfg", "syscon";
+			compatible = "mediatek,mt8365-infracfg-nao", "syscon";
 			reg = <0 0x1020e000 0 0x1000>;
-			#clock-cells = <1>;
 		};
 
 		rng: rng at 1020f000 {

---
base-commit: 6987d58a9cbc5bd57c983baa514474a86c945d56
change-id: 20251216-mtk-fix-infracfg_nao-compatibile-ba543769f5b9

Best regards,
-- 
David Lechner <dlechner at baylibre.com>



From smostafa at google.com  Tue Dec 16 14:58:33 2025
From: smostafa at google.com (Mostafa Saleh)
Date: Tue, 16 Dec 2025 22:58:33 +0000
Subject: [PATCH rc v3 1/4] iommu/arm-smmu-v3: Add ignored bits to fix STE
 update sequence
In-Reply-To: <20251216000952.GA6079@nvidia.com>
References: <cover.1765334526.git.nicolinc@nvidia.com>
 <cc0d4ab571e2e789ee1cddfa035379dc54f0601b.1765334526.git.nicolinc@nvidia.com>
 <aT87A1ur4htPjM5T@google.com>
 <20251216000952.GA6079@nvidia.com>
Message-ID: <aUHkGCEeu7L5uCMR@google.com>

On Mon, Dec 15, 2025 at 08:09:52PM -0400, Jason Gunthorpe wrote:
> On Sun, Dec 14, 2025 at 10:32:35PM +0000, Mostafa Saleh wrote:
> > >   * Figure out if we can do a hitless update of entry to become target. Returns a
> > >   * bit mask where 1 indicates that qword needs to be set disruptively.
> > > @@ -1094,13 +1100,22 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
> > >  {
> > >  	__le64 target_used[NUM_ENTRY_QWORDS] = {};
> > >  	__le64 cur_used[NUM_ENTRY_QWORDS] = {};
> > > +	__le64 ignored[NUM_ENTRY_QWORDS] = {};
> > 
> > I think we can avoid extra stack allocation for another STE, if we make
> > the function update cur_used directly, but no strong opinion.
> 
> It does more than just mask cur_used, it also adjusts ignored:
> 
> > > +		/*
> > > +		 * Ignored is only used for bits that are used by both entries,
> > > +		 * otherwise it is sequenced according to the unused entry.
> > > +		 */
> > > +		ignored[i] &= target_used[i] & cur_used[i];
> 
> Which also explains this:

I haven't tested that, but I was thinking about (applies on top of the patches)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 72ba41591fdb..9981eefcf0da 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1083,7 +1083,7 @@ void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits)
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_used);

 VISIBLE_IF_KUNIT
-void arm_smmu_get_ste_ignored(__le64 *ignored_bits)
+void arm_smmu_get_ste_ignored(__le64 *used)
 {
 	/*
 	 * MEV does not meaningfully impact the operation of the HW, it only
@@ -1093,17 +1093,14 @@ void arm_smmu_get_ste_ignored(__le64 *ignored_bits)
 	 *
 	 *  Note: Software must expect, and be able to deal with, coalesced
 	 *  fault records even when MEV == 0.
-	 */
-	ignored_bits[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
-
-	/*
+	 *
 	 * EATS is used to reject and control the ATS behavior of the device. If
 	 * we are changing it away from 0 then we already trust the device to
 	 * use ATS properly and we have sequenced the device's ATS enable in PCI
 	 * config space to prevent it from issuing ATS while we are changing
 	 * EATS.
 	 */
-	ignored_bits[1] |= cpu_to_le64(STRTAB_STE_1_EATS);
+	used[1] &= ~cpu_to_le64(STRTAB_STE_1_EATS | STRTAB_STE_1_MEV);
 }
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_ignored);

@@ -1119,22 +1116,15 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
 {
 	__le64 target_used[NUM_ENTRY_QWORDS] = {};
 	__le64 cur_used[NUM_ENTRY_QWORDS] = {};
-	__le64 ignored[NUM_ENTRY_QWORDS] = {};
 	u8 used_qword_diff = 0;
 	unsigned int i;

 	writer->ops->get_used(entry, cur_used);
 	writer->ops->get_used(target, target_used);
-	if (writer->ops->get_ignored)
-		writer->ops->get_ignored(ignored);
+	if (writer->ops->filter_ignored)
+		writer->ops->filter_ignored(cur_used);

 	for (i = 0; i != NUM_ENTRY_QWORDS; i++) {
-		/*
-		 * Ignored is only used for bits that are used by both entries,
-		 * otherwise it is sequenced according to the unused entry.
-		 */
-		ignored[i] &= target_used[i] & cur_used[i];
-
 		/*
 		 * Check that masks are up to date, the make functions are not
 		 * allowed to set a bit to 1 if the used function doesn't say it
@@ -1142,8 +1132,6 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
 		 */
 		WARN_ON_ONCE(target[i] & ~target_used[i]);

-		/* Bits can change because they are not currently being used */
-		cur_used[i] &= ~ignored[i];
 		unused_update[i] = (entry[i] & cur_used[i]) |
 				   (target[i] & ~cur_used[i]);
 		/*
@@ -1575,7 +1563,7 @@ static void arm_smmu_ste_writer_sync_entry(struct arm_smmu_entry_writer *writer)
 static const struct arm_smmu_entry_writer_ops arm_smmu_ste_writer_ops = {
 	.sync = arm_smmu_ste_writer_sync_entry,
 	.get_used = arm_smmu_get_ste_used,
-	.get_ignored = arm_smmu_get_ste_ignored,
+	.filter_ignored = arm_smmu_get_ste_ignored,
 };

 static void arm_smmu_write_ste(struct arm_smmu_master *master, u32 sid,
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index d5f0e5407b9f..97b995974049 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -900,7 +900,7 @@ struct arm_smmu_entry_writer {

 struct arm_smmu_entry_writer_ops {
 	void (*get_used)(const __le64 *entry, __le64 *used);
-	void (*get_ignored)(__le64 *ignored_bits);
+	void (*filter_ignored)(__le64 *used);
 	void (*sync)(struct arm_smmu_entry_writer *writer);
 };


And we only clear the bits from cur_used, there is no need to for the
other mask ignored (ignored[i] &= target_used[i] & cur_used[i])
- If an ignored bit is not in cur_used it will not impact
  "cur_used[i] &= ~ignored[i]" as it must be already zero
- If an ignored bit is not in target_used, it doesn't really matter,
  we can ignore it anyway, as it is safe to do so.

Anyway, I am not fixated on that though, extra 64B on the stack is not that bad.

> 
> > I have some mixed feelings about this, having get_used(), then get_ignored()
> > with the same bits set seems confusing to me, specially the get_ignored()
> > loops back to update cur_used, which is set from get_used()
> 
> The same bits are set because of the above - we need to know what the
> actual used bits are to decide if we need to rely on the ignored rule
> to do the update.
>  
> > My initial though was just to remove this bit from get_used() + some changes
> > to checks setting bits that are not used would be enough, and the semantics
> > of get_used() can be something as:
> > ?Return bits used by the updated translation regime that MUST be observed
> > atomically? and in that case we can ignore things as MEV as it doesn?t
> > impact the translation.
> 
> Aside from the above this would cause problems with the validation
> assertions, so it is not a great idea.

Yes, that's why I didn't like this, it had to hack the validation logic.

Thanks,
Mostafa

> 
> > However, this approach makes it a bit explicit which bits are ignored, if we
> > keep this logic, I think changing the name of get_ignored() might help, to
> > something as "get_allowed_break()" or "get_update_safe()"?
> 
> update_safe sounds good to me
> 
> Jason


From smostafa at google.com  Tue Dec 16 15:08:14 2025
From: smostafa at google.com (Mostafa Saleh)
Date: Tue, 16 Dec 2025 23:08:14 +0000
Subject: [PATCH v5 04/27] iommu/io-pgtable-arm: Factor kernel specific
 code out
In-Reply-To: <20251216005834.GC31492@ziepe.ca>
References: <20251117184815.1027271-1-smostafa@google.com>
 <20251117184815.1027271-5-smostafa@google.com>
 <20251128164541.GA812105@ziepe.ca>
 <aTw2x1UlldJGVA4Y@google.com>
 <20251216005834.GC31492@ziepe.ca>
Message-ID: <aUHmXkdehGGYX5Mg@google.com>

On Mon, Dec 15, 2025 at 08:58:34PM -0400, Jason Gunthorpe wrote:
> On Fri, Dec 12, 2025 at 03:37:43PM +0000, Mostafa Saleh wrote:
> > On Fri, Nov 28, 2025 at 12:45:41PM -0400, Jason Gunthorpe wrote:
> > > On Mon, Nov 17, 2025 at 06:47:51PM +0000, Mostafa Saleh wrote:
> > > > Some of the used APIs are only part of the kernel and are not
> > > > available in the hypervisor, factor those out:
> > > > - alloc/free memory
> > > 
> > > Why not provide the iommu-pages API for the hypervisor environment?
> > > 
> > > Same for virt_to_phys, that could be moved into an iommu-pages wrapper
> > > too..
> > 
> > I guess that's possible, but then we would have to stub dma_map/unmap,
> > which might a bit ugly. I will look more into it.
> 
> I am hoping to drop the dma_map/unmap and replace it with an arch
> cache flush call directly since the code is no longer modular and
> relying on the DMA API will have some problems with a future patch
> series I'm expecting..
> 

I see, I always wondered about that, it's because CMO are not exported
for modules, I can look more into it and send a separate clean up.

Thanks,
Mostafa

> Jason


From Thinh.Nguyen at synopsys.com  Tue Dec 16 15:18:57 2025
From: Thinh.Nguyen at synopsys.com (Thinh Nguyen)
Date: Tue, 16 Dec 2025 23:18:57 +0000
Subject: [PATCH v2 1/3] usb: dwc3: drd: extend dwc3_pre_set_role() to
 extcon and otg usecase
In-Reply-To: <20251205032942.2259671-1-xu.yang_2@nxp.com>
References: <20251205032942.2259671-1-xu.yang_2@nxp.com>
Message-ID: <20251216231856.onmuj3dhqfgaxr7i@synopsys.com>

On Fri, Dec 05, 2025, Xu Yang wrote:
> Call dwc3_pre_set_role() to support both extcon and otg usecase, so that
> the glue driver can do proper action in case of role changes.
> 
> Reviewed-by: Frank Li <Frank.Li at nxp.com>
> Acked-by: Thinh Nguyen <Thinh.Nguyen at synopsys.com>
> Signed-off-by: Xu Yang <xu.yang_2 at nxp.com>
> 
> ---
> Changes in v2:
>  - improve commit message
>  - add Rb and Ab tag
> ---
>  drivers/usb/dwc3/drd.c | 10 +++++++---
>  1 file changed, 7 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c
> index 589bbeb27454..031cfd12300a 100644
> --- a/drivers/usb/dwc3/drd.c
> +++ b/drivers/usb/dwc3/drd.c
> @@ -381,6 +381,7 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus)
>  		dwc3_otgregs_init(dwc);
>  		dwc3_otg_host_init(dwc);
>  		spin_unlock_irqrestore(&dwc->lock, flags);
> +		dwc3_pre_set_role(dwc, USB_ROLE_HOST);
>  		ret = dwc3_host_init(dwc);
>  		if (ret) {
>  			dev_err(dwc->dev, "failed to initialize host\n");
> @@ -406,6 +407,7 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus)
>  			otg_set_vbus(dwc->usb2_phy->otg, false);
>  		if (dwc->usb2_generic_phy[0])
>  			phy_set_mode(dwc->usb2_generic_phy[0], PHY_MODE_USB_DEVICE);
> +		dwc3_pre_set_role(dwc, USB_ROLE_DEVICE);
>  		ret = dwc3_gadget_init(dwc);
>  		if (ret)
>  			dev_err(dwc->dev, "failed to initialize peripheral\n");
> @@ -433,10 +435,12 @@ static int dwc3_drd_notifier(struct notifier_block *nb,
>  			     unsigned long event, void *ptr)
>  {
>  	struct dwc3 *dwc = container_of(nb, struct dwc3, edev_nb);
> +	u32 mode = event ? DWC3_GCTL_PRTCAP_HOST : DWC3_GCTL_PRTCAP_DEVICE;
> +	enum usb_role role = mode == DWC3_GCTL_PRTCAP_HOST ?
> +				     USB_ROLE_HOST : USB_ROLE_DEVICE;
>  
> -	dwc3_set_mode(dwc, event ?
> -		      DWC3_GCTL_PRTCAP_HOST :
> -		      DWC3_GCTL_PRTCAP_DEVICE);
> +	dwc3_pre_set_role(dwc, role);
> +	dwc3_set_mode(dwc, mode);
>  
>  	return NOTIFY_DONE;
>  }
> -- 
> 2.34.1
> 

This patch series should be v3.

BR,
Thinh

From Thinh.Nguyen at synopsys.com  Tue Dec 16 15:19:32 2025
From: Thinh.Nguyen at synopsys.com (Thinh Nguyen)
Date: Tue, 16 Dec 2025 23:19:32 +0000
Subject: [PATCH v2 2/3] usb: dwc3: imx8mp: rename dwc3 to dwc3_pdev in
 struct dwc3_imx8mp
In-Reply-To: <20251205032942.2259671-2-xu.yang_2@nxp.com>
References: <20251205032942.2259671-1-xu.yang_2@nxp.com>
 <20251205032942.2259671-2-xu.yang_2@nxp.com>
Message-ID: <20251216231930.o3d3b5lrbeb776ip@synopsys.com>

On Fri, Dec 05, 2025, Xu Yang wrote:
> It's confuse to let "dwc3" represent a platform_device, because "dwc3"
> may also represent a dwc3 core structure. Rename it for better
> distinction.
> 
> Signed-off-by: Xu Yang <xu.yang_2 at nxp.com>
> 
> ---
> Changes in v2:
>  - new patch
> ---
>  drivers/usb/dwc3/dwc3-imx8mp.c | 16 ++++++++--------
>  1 file changed, 8 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/usb/dwc3/dwc3-imx8mp.c b/drivers/usb/dwc3/dwc3-imx8mp.c
> index 050da327f785..8bece4baecbf 100644
> --- a/drivers/usb/dwc3/dwc3-imx8mp.c
> +++ b/drivers/usb/dwc3/dwc3-imx8mp.c
> @@ -51,7 +51,7 @@
>  
>  struct dwc3_imx8mp {
>  	struct device			*dev;
> -	struct platform_device		*dwc3;
> +	struct platform_device		*dwc3_pdev;
>  	void __iomem			*hsio_blk_base;
>  	void __iomem			*glue_base;
>  	struct clk			*hsio_clk;
> @@ -100,7 +100,7 @@ static void imx8mp_configure_glue(struct dwc3_imx8mp *dwc3_imx)
>  static void dwc3_imx8mp_wakeup_enable(struct dwc3_imx8mp *dwc3_imx,
>  				      pm_message_t msg)
>  {
> -	struct dwc3	*dwc3 = platform_get_drvdata(dwc3_imx->dwc3);
> +	struct dwc3	*dwc3 = platform_get_drvdata(dwc3_imx->dwc3_pdev);
>  	u32		val;
>  
>  	if (!dwc3)
> @@ -142,7 +142,7 @@ static const struct software_node dwc3_imx8mp_swnode = {
>  static irqreturn_t dwc3_imx8mp_interrupt(int irq, void *_dwc3_imx)
>  {
>  	struct dwc3_imx8mp	*dwc3_imx = _dwc3_imx;
> -	struct dwc3		*dwc = platform_get_drvdata(dwc3_imx->dwc3);
> +	struct dwc3		*dwc = platform_get_drvdata(dwc3_imx->dwc3_pdev);
>  
>  	if (!dwc3_imx->pm_suspended)
>  		return IRQ_HANDLED;
> @@ -233,8 +233,8 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev)
>  		goto remove_swnode;
>  	}
>  
> -	dwc3_imx->dwc3 = of_find_device_by_node(dwc3_np);
> -	if (!dwc3_imx->dwc3) {
> +	dwc3_imx->dwc3_pdev = of_find_device_by_node(dwc3_np);
> +	if (!dwc3_imx->dwc3_pdev) {
>  		dev_err(dev, "failed to get dwc3 platform device\n");
>  		err = -ENODEV;
>  		goto depopulate;
> @@ -253,7 +253,7 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev)
>  	return 0;
>  
>  put_dwc3:
> -	put_device(&dwc3_imx->dwc3->dev);
> +	put_device(&dwc3_imx->dwc3_pdev->dev);
>  depopulate:
>  	of_platform_depopulate(dev);
>  remove_swnode:
> @@ -270,7 +270,7 @@ static void dwc3_imx8mp_remove(struct platform_device *pdev)
>  	struct dwc3_imx8mp *dwc3_imx = platform_get_drvdata(pdev);
>  	struct device *dev = &pdev->dev;
>  
> -	put_device(&dwc3_imx->dwc3->dev);
> +	put_device(&dwc3_imx->dwc3_pdev->dev);
>  
>  	pm_runtime_get_sync(dev);
>  	of_platform_depopulate(dev);
> @@ -296,7 +296,7 @@ static int dwc3_imx8mp_suspend(struct dwc3_imx8mp *dwc3_imx, pm_message_t msg)
>  
>  static int dwc3_imx8mp_resume(struct dwc3_imx8mp *dwc3_imx, pm_message_t msg)
>  {
> -	struct dwc3	*dwc = platform_get_drvdata(dwc3_imx->dwc3);
> +	struct dwc3	*dwc = platform_get_drvdata(dwc3_imx->dwc3_pdev);
>  	int ret = 0;
>  
>  	if (!dwc3_imx->pm_suspended)
> -- 
> 2.34.1
> 

Acked-by: Thinh Nguyen <Thinh.Nguyen at synopsys.com>

Thanks,
Thinh

From Thinh.Nguyen at synopsys.com  Tue Dec 16 15:26:40 2025
From: Thinh.Nguyen at synopsys.com (Thinh Nguyen)
Date: Tue, 16 Dec 2025 23:26:40 +0000
Subject: [PATCH v2 3/3] usb: dwc3: imx8mp: disable auto suspend for host
 role
In-Reply-To: <20251205032942.2259671-3-xu.yang_2@nxp.com>
References: <20251205032942.2259671-1-xu.yang_2@nxp.com>
 <20251205032942.2259671-3-xu.yang_2@nxp.com>
Message-ID: <20251216232638.rglecm3op6qit5a5@synopsys.com>

On Fri, Dec 05, 2025, Xu Yang wrote:
> Do dwc3 core auto suspend enable for device and disable for host
> , this can make sure dwc3 core device auto suspend setting is
> correct all the time, the background of disable dwc3 core device
> auto suspend is to make its parent device suspend immediately
> (so wakeup enable can be enabled) after xhci-plat device suspended,
> for device mode, we keep the dwc3 core device auto suspend is to
> give some wait for gadget to be enumerated.
> 
> Note: It's a temporary solution until we switch to using the new
>       flatten model.
> 
> Signed-off-by: Xu Yang <xu.yang_2 at nxp.com>
> 
> ---
> Changes in v2:
>  - add a note suggested by Thinh
> ---
>  drivers/usb/dwc3/dwc3-imx8mp.c | 31 +++++++++++++++++++++++++++++++
>  1 file changed, 31 insertions(+)
> 
> diff --git a/drivers/usb/dwc3/dwc3-imx8mp.c b/drivers/usb/dwc3/dwc3-imx8mp.c
> index 8bece4baecbf..2e13ca588f42 100644
> --- a/drivers/usb/dwc3/dwc3-imx8mp.c
> +++ b/drivers/usb/dwc3/dwc3-imx8mp.c
> @@ -158,11 +158,31 @@ static irqreturn_t dwc3_imx8mp_interrupt(int irq, void *_dwc3_imx)
>  	return IRQ_HANDLED;
>  }
>  
> +static void dwc3_imx_pre_set_role(struct dwc3 *dwc, enum usb_role role)
> +{
> +	if (role == USB_ROLE_HOST)
> +		/*
> +		 * For xhci host, we need disable dwc core auto
> +		 * suspend, because during this auto suspend delay(5s),
> +		 * xhci host RUN_STOP is cleared and wakeup is not
> +		 * enabled, if device is inserted, xhci host can't
> +		 * response the connection.
> +		 */
> +		pm_runtime_dont_use_autosuspend(dwc->dev);

As noted previously, don't we need to unwind this in dwc3_imx8mp_remove
if the current mode device?

> +	else
> +		pm_runtime_use_autosuspend(dwc->dev);
> +}
> +
> +struct dwc3_glue_ops dwc3_imx_glue_ops = {
> +	.pre_set_role   = dwc3_imx_pre_set_role,
> +};
> +
>  static int dwc3_imx8mp_probe(struct platform_device *pdev)
>  {
>  	struct device		*dev = &pdev->dev;
>  	struct device_node	*node = dev->of_node;
>  	struct dwc3_imx8mp	*dwc3_imx;
> +	struct dwc3		*dwc3;
>  	struct resource		*res;
>  	int			err, irq;
>  
> @@ -240,6 +260,17 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev)
>  		goto depopulate;
>  	}
>  
> +	dwc3 = platform_get_drvdata(dwc3_imx->dwc3_pdev);
> +	if (!dwc3) {
> +		err = dev_err_probe(dev, -EPROBE_DEFER, "failed to get dwc3 platform data\n");
> +		goto depopulate;
> +	}
> +
> +	dwc3->glue_ops = &dwc3_imx_glue_ops;
> +
> +	if (dwc3->dr_mode == USB_DR_MODE_HOST)
> +		pm_runtime_dont_use_autosuspend(dwc3->dev);
> +
>  	err = devm_request_threaded_irq(dev, irq, NULL, dwc3_imx8mp_interrupt,
>  					IRQF_ONESHOT, dev_name(dev), dwc3_imx);
>  	if (err) {
> -- 
> 2.34.1
> 

The question above is trivial. You can add this in v3:

Acked-by: Thinh Nguyen <Thinh.Nguyen at synopsys.com>

Thanks,
Thinh

From Thinh.Nguyen at synopsys.com  Tue Dec 16 15:34:41 2025
From: Thinh.Nguyen at synopsys.com (Thinh Nguyen)
Date: Tue, 16 Dec 2025 23:34:41 +0000
Subject: [PATCH v9 2/2] usb: dwc3: Add Google Tensor SoC DWC3 glue driver
In-Reply-To: <CA+zupgzL7v5MZDpxKDQQCqAZaqTdHbiG9-xTr+8RnigMFZJ_7Q@mail.gmail.com>
References: <20251205-controller-v9-0-9f158b18f979@google.com>
 <20251205-controller-v9-2-9f158b18f979@google.com>
 <2025120553-suffrage-divisive-5890@gregkh>
 <CA+zupgzL7v5MZDpxKDQQCqAZaqTdHbiG9-xTr+8RnigMFZJ_7Q@mail.gmail.com>
Message-ID: <20251216233439.vqigcx2zs6taergz@synopsys.com>

On Thu, Dec 04, 2025, Roy Luo wrote:
> On Thu, Dec 4, 2025 at 10:05?PM Greg Kroah-Hartman
> <gregkh at linuxfoundation.org> wrote:
> >
> > On Fri, Dec 05, 2025 at 02:26:38AM +0000, Roy Luo wrote:
> > > +config USB_DWC3_GOOGLE
> > > +     tristate "Google Platform"
> > > +     depends on ARCH_GOOGLE || COMPILE_TEST
> >
> > There is no ARCH_GOOGLE in the tree now, so how is this supposed to
> > work?  Shouldn't tools that check for "invalid config options" trigger
> > on this?
> >
> > thanks,
> >
> > greg k-h
> 
> Hi Greg,
> 
> The menuconfig looks like the following and it doesn't complain:
> | Symbol: ARCH_GOOGLE [=ARCH_GOOGLE]
> | Type  : unknown
> |
> | Symbol: PHY_GOOGLE_USB [=y]
> | Type  : tristate
> | Defined at drivers/phy/Kconfig:104
> |     Prompt: Google Tensor SoC USB PHY driver
> |     Depends on: ARCH_GOOGLE || COMPILE_TEST [=y]
> 
> According to Kconfig documentation [1], the unknown symbol
> would simply be evaluated as an "n", which is what we want.
> "Convert the symbol into an expression. Boolean and tristate
> symbols are simply converted into the respective expression
> values. All other symbol types result in ?n?."
> 
> In a different Kconfig documentation, an environment variable
> "KCONFIG_WARN_UNKNOWN_SYMBOLS" is there to detect
> undefined symbols in the "config input", but I can't find one that
> catches undefined symbols in the Kconfig tree itself.
> 
> That is, the tool seems to allow this.
> However, if this turns out to be a major problem. I think we
> can either:
> - Remove ARCH_GOOGLE and leave COMPILE_TEST as
>   the only dependency. Then add ARCH_GOOGLE back
>   later once it's in the tree.
> - Defer the whole patch series until ARCH_GOOGLE is
>   present (I hope not).
> 
> [1] https://urldefense.com/v3/__https://docs.kernel.org/kbuild/kconfig-language.html*menu-dependencies__;Iw!!A4F2R9G_pg!e-y2_BsSNhXF1v5K6tBJX-OabgKJM9WVdvwyKoB6tg9ooCLVg8WiQ4UrStOF2YZQ_Zs6tC6HVh7wCpqkEfU$ 
> [2] https://urldefense.com/v3/__https://www.kernel.org/doc/Documentation/kbuild/kconfig.rst__;!!A4F2R9G_pg!e-y2_BsSNhXF1v5K6tBJX-OabgKJM9WVdvwyKoB6tg9ooCLVg8WiQ4UrStOF2YZQ_Zs6tC6HVh7wHpoUlhY$ 
> 

Hi Greg, Roy,

Just checking, are we aligned here?

BR,
Thinh

From martin.blumenstingl at googlemail.com  Tue Dec 16 15:43:46 2025
From: martin.blumenstingl at googlemail.com (Martin Blumenstingl)
Date: Wed, 17 Dec 2025 00:43:46 +0100
Subject: [PATCH RFC v2 1/3] media: dt-bindings: Add Amlogic V4L2 video decoder
In-Reply-To: <20251124-b4-s4-vdec-upstream-v2-1-bdbbce3f11a6@amlogic.com>
References: <20251124-b4-s4-vdec-upstream-v2-0-bdbbce3f11a6@amlogic.com> <20251124-b4-s4-vdec-upstream-v2-1-bdbbce3f11a6@amlogic.com>
Message-ID: <CAFBinCDO5UWVEtbOOdMn9vy=0H2Q1hJDKhH+X7i0nMsSsw=wbg@mail.gmail.com>

Hi,

On Mon, Nov 24, 2025 at 4:32?AM Zhentao Guo via B4 Relay
<devnull+zhentao.guo.amlogic.com at kernel.org> wrote:
>
> From: Zhentao Guo <zhentao.guo at amlogic.com>
>
> Describe the initial support for the V4L2 stateless video decoder
> driver used with the Amlogic S4 (S805X2) platform.
>
> Signed-off-by: Zhentao Guo <zhentao.guo at amlogic.com>
> ---
>  .../bindings/media/amlogic,s4-vcodec-dec.yaml      | 87 ++++++++++++++++++++++
>  1 file changed, 87 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/media/amlogic,s4-vcodec-dec.yaml b/Documentation/devicetree/bindings/media/amlogic,s4-vcodec-dec.yaml
> new file mode 100644
> index 000000000000..401a5a32902e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/amlogic,s4-vcodec-dec.yaml
> @@ -0,0 +1,87 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +# Copyright (C) 2025 Amlogic, Inc. All rights reserved
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/media/amlogic,vcodec-dec.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Amlogic Video Decode Accelerator
> +
> +maintainers:
> +  - Zhentao Guo <zhentao.guo at amlogic.com>
> +
> +description:
> +  The Video Decoder Accelerator present on Amlogic SOCs.
> +  It supports stateless h264 decoding.
> +
> +properties:
> +  compatible:
> +    const: amlogic,s4-vcodec-dec
> +
> +  reg:
> +    maxItems: 2
> +
> +  reg-names:
> +    items:
> +      - const: dos
> +      - const: dmc
Neil has commented on the driver patch (in v1) to use the existing
canvas driver.
The same applies to the binding: you can replace the whole "dmc"
registers with an "amlogic,canvas" property (see
Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml for
an example).

[...]
> +required:
> +  - compatible
> +  - reg
> +  - reg-names
> +  - interrupts
> +  - clocks
> +  - clock-names
> +  - power-domains
> +  - power-domain-names
I did a quick:
$ git grep RESET_DOS
{include/dt-bindings/reset/amlogic,arch/arm64/boot/dts/amlogic/}*.h
-> that lists DOS reset lines for most (all?) SoCs that were supported
by the old vdec driver as well as DOS reset lines for the S4 SoC (for
which you're adding support here).
If some of those reset lines are wired in hardware to the DOS region
then you should include them in the binding.
For reference in case you are not already familiar with it: [0] "[...]
make bindings complete even if a driver doesn?t support some features.
For example, if a device has an interrupt, then include the
?interrupts? property even if the driver is only polled mode".
(the same also applies to any additional clocks or power-domains that
are wired as inputs into the hardware which you have not listed yet as
they are not needed for the initially supported codecs)


Best regards,
Martin


[0] https://docs.kernel.org/devicetree/bindings/writing-bindings.html


From florian.fainelli at broadcom.com  Tue Dec 16 15:56:49 2025
From: florian.fainelli at broadcom.com (Florian Fainelli)
Date: Tue, 16 Dec 2025 15:56:49 -0800
Subject: [GIT PULL 1/1] Broadcom devicetree-arm64 changes for 6.19
Message-ID: <20251216235649.633331-1-florian.fainelli@broadcom.com>

The following changes since commit 3a8660878839faadb4f1a6dd72c3179c1df56787:

  Linux 6.18-rc1 (2025-10-12 13:42:36 -0700)

are available in the Git repository at:

  https://github.com/Broadcom/stblinux.git tags/arm-soc/for-6.19/devicetree-arm64

for you to fetch changes up to 37c3a91e9730e274fe2eca9703033ae0f154cb62:

  arm64: dts: broadcom: bcm2712: Add watchdog DT node (2025-11-05 10:28:29 -0800)

----------------------------------------------------------------
This pull request contains Broadcom ARM64-based SoCs Device Tre updates
for 6.19, please pull the following:

- Peter enables the random number generator on BCM2712

- Stanimir adds the watchdog Device Tree node for BCM2712

----------------------------------------------------------------
Peter Robinson (1):
      arm64: dts: broadcom: bcm2712: Enable RNG

Stanimir Varbanov (1):
      arm64: dts: broadcom: bcm2712: Add watchdog DT node

 arch/arm64/boot/dts/broadcom/bcm2712.dtsi | 15 +++++++++++++++
 1 file changed, 15 insertions(+)


From florian.fainelli at broadcom.com  Tue Dec 16 15:59:04 2025
From: florian.fainelli at broadcom.com (Florian Fainelli)
Date: Tue, 16 Dec 2025 15:59:04 -0800
Subject: [PATCH v3 4/4] arm64: dts: broadcom: bcm2712: Add watchdog DT
 node
In-Reply-To: <189702e0-e6f0-44c5-bed6-eef058d90b76@suse.de>
References: <20251031183309.1163384-1-svarbanov@suse.de>
 <20251031183309.1163384-5-svarbanov@suse.de>
 <20251105165553.3910996-1-florian.fainelli@broadcom.com>
 <189702e0-e6f0-44c5-bed6-eef058d90b76@suse.de>
Message-ID: <351d9321-e5e9-43cd-bd74-68aef80aa177@broadcom.com>

On 12/16/25 05:00, Stanimir Varbanov wrote:
> Hi Florian,
> 
> On 11/5/25 6:55 PM, Florian Fainelli wrote:
>> From: Florian Fainelli <f.fainelli at gmail.com>
>>
>> On Fri, 31 Oct 2025 20:33:09 +0200, Stanimir Varbanov <svarbanov at suse.de> wrote:
>>> Add watchdog device-tree node for bcm2712 SoC.
>>>
>>> Signed-off-by: Stanimir Varbanov <svarbanov at suse.de>
>>> ---
>>
>> Applied to https://github.com/Broadcom/stblinux/commits/devicetree-arm64/next, thanks!
> 
> For some reason this is not part of v6.19-rc1.

I did not send out the pull request, sorry about that. Let's see if the 
SoC maintainers can still take it, if not that will be v6.20 material.
-- 
Florian


From florian.fainelli at broadcom.com  Tue Dec 16 16:03:43 2025
From: florian.fainelli at broadcom.com (Florian Fainelli)
Date: Tue, 16 Dec 2025 16:03:43 -0800
Subject: [GIT PULL 1/1] Broadcom devicetree-arm64 changes for 6.19
In-Reply-To: <20251216235649.633331-1-florian.fainelli@broadcom.com>
References: <20251216235649.633331-1-florian.fainelli@broadcom.com>
Message-ID: <822bdd19-276b-4868-b3e4-59a187bc7048@broadcom.com>

On 12/16/25 15:56, Florian Fainelli wrote:
> The following changes since commit 3a8660878839faadb4f1a6dd72c3179c1df56787:
> 
>    Linux 6.18-rc1 (2025-10-12 13:42:36 -0700)
> 
> are available in the Git repository at:
> 
>    https://github.com/Broadcom/stblinux.git tags/arm-soc/for-6.19/devicetree-arm64
> 
> for you to fetch changes up to 37c3a91e9730e274fe2eca9703033ae0f154cb62:
> 
>    arm64: dts: broadcom: bcm2712: Add watchdog DT node (2025-11-05 10:28:29 -0800)
> 
> ----------------------------------------------------------------
> This pull request contains Broadcom ARM64-based SoCs Device Tre updates
> for 6.19, please pull the following:
> 
> - Peter enables the random number generator on BCM2712
> 
> - Stanimir adds the watchdog Device Tree node for BCM2712
> 
> ----------------------------------------------------------------
> Peter Robinson (1):
>        arm64: dts: broadcom: bcm2712: Enable RNG
> 
> Stanimir Varbanov (1):
>        arm64: dts: broadcom: bcm2712: Add watchdog DT node
> 
>   arch/arm64/boot/dts/broadcom/bcm2712.dtsi | 15 +++++++++++++++
>   1 file changed, 15 insertions(+)
> 

Apologies for sending this so late, after v6.19-rc1, these changes are 
somewhat minor, so please let me know if they can be accepted as late 
changes to the 6.19 merge window.

Thank you!
-- 
Florian



From oupton at kernel.org  Tue Dec 16 16:13:17 2025
From: oupton at kernel.org (Oliver Upton)
Date: Tue, 16 Dec 2025 16:13:17 -0800
Subject: [PATCH v5 10/24] KVM: arm64: Set up FGT for Partitioned PMU
In-Reply-To: <gsnty0n72zl5.fsf@coltonlewis-kvm.c.googlers.com>
References: <aTiPvS49uMOJEBrf@kernel.org>
 <gsnty0n72zl5.fsf@coltonlewis-kvm.c.googlers.com>
Message-ID: <aUH1nZB83m62kkUH@kernel.org>

On Fri, Dec 12, 2025 at 08:51:34PM +0000, Colton Lewis wrote:
> > The other reason for doing this is kvm_pmu_fgt_bits() assumes a
> > 'positive' trap polarity, even though there are several cases where FGTs
> > have a 'negative' priority (i.e. 0 => trap).
> 
> For the bits I was concerned with they all had positive polarity, except
> for the dedicated instruction counter. (Side note: Why would ARM do
> this?)

Old software on new hardware, you don't want the guest to magically get
access to things it shouldn't.

> IIRC the FGT setup I plugged into in previous versions of the patch had
> some icky macros that accounted for polarity. They were confusing and I
> didn't like the effort to understand them.

I'm guessing you're referring to the undef infrastructure (FGUs), which
is a meaningfully load-bearing part of KVM.

> Is there a good reason not to adopt a convetion that 1 => trap for
> kernel code? Reversing the negative polarities immediately before write
> could be easy: Have a bitmap of the negative polarity bits to xor with
> the traps we actually want.

This *significantly* muddies the water around FGTs. I quite like that the
current representation matches the architecture. NV forces KVM to deal
with the native representations anyway.

Thanks,
Oliver


From jgg at nvidia.com  Tue Dec 16 16:23:52 2025
From: jgg at nvidia.com (Jason Gunthorpe)
Date: Tue, 16 Dec 2025 20:23:52 -0400
Subject: [PATCH rc v3 1/4] iommu/arm-smmu-v3: Add ignored bits to fix STE
 update sequence
In-Reply-To: <aUHkGCEeu7L5uCMR@google.com>
References: <cover.1765334526.git.nicolinc@nvidia.com>
 <cc0d4ab571e2e789ee1cddfa035379dc54f0601b.1765334526.git.nicolinc@nvidia.com>
 <aT87A1ur4htPjM5T@google.com>
 <20251216000952.GA6079@nvidia.com>
 <aUHkGCEeu7L5uCMR@google.com>
Message-ID: <20251217002352.GJ6079@nvidia.com>

On Tue, Dec 16, 2025 at 10:58:33PM +0000, Mostafa Saleh wrote:
>  	for (i = 0; i != NUM_ENTRY_QWORDS; i++) {
> -		/*
> -		 * Ignored is only used for bits that are used by both entries,
> -		 * otherwise it is sequenced according to the unused entry.
> -		 */
> -		ignored[i] &= target_used[i] & cur_used[i];
> -

It is not functionally the same thing without this..

> And we only clear the bits from cur_used, there is no need to for the
> other mask ignored (ignored[i] &= target_used[i] & cur_used[i])
> - If an ignored bit is not in cur_used it will not impact
>   "cur_used[i] &= ~ignored[i]" as it must be already zero
> - If an ignored bit is not in target_used, it doesn't really matter,
>   we can ignore it anyway, as it is safe to do so.

That was an earlier version, it was switched away to this so as to be
less of a change though the reasoning is sound.

Jason


From royluo at google.com  Tue Dec 16 16:25:21 2025
From: royluo at google.com (Roy Luo)
Date: Tue, 16 Dec 2025 16:25:21 -0800
Subject: [PATCH v9 2/2] usb: dwc3: Add Google Tensor SoC DWC3 glue driver
In-Reply-To: <20251216233439.vqigcx2zs6taergz@synopsys.com>
References: <20251205-controller-v9-0-9f158b18f979@google.com>
 <20251205-controller-v9-2-9f158b18f979@google.com> <2025120553-suffrage-divisive-5890@gregkh>
 <CA+zupgzL7v5MZDpxKDQQCqAZaqTdHbiG9-xTr+8RnigMFZJ_7Q@mail.gmail.com> <20251216233439.vqigcx2zs6taergz@synopsys.com>
Message-ID: <CA+zupgxV0aHEXqmmHbe6cKSQUvYg1iFXjiDfG7wKdF7KKTo6iA@mail.gmail.com>

On Tue, Dec 16, 2025 at 3:34?PM Thinh Nguyen <Thinh.Nguyen at synopsys.com> wrote:
>
> On Thu, Dec 04, 2025, Roy Luo wrote:
> > On Thu, Dec 4, 2025 at 10:05?PM Greg Kroah-Hartman
> > <gregkh at linuxfoundation.org> wrote:
> > >
> > > On Fri, Dec 05, 2025 at 02:26:38AM +0000, Roy Luo wrote:
> > > > +config USB_DWC3_GOOGLE
> > > > +     tristate "Google Platform"
> > > > +     depends on ARCH_GOOGLE || COMPILE_TEST
> > >
> > > There is no ARCH_GOOGLE in the tree now, so how is this supposed to
> > > work?  Shouldn't tools that check for "invalid config options" trigger
> > > on this?
> > >
> > > thanks,
> > >
> > > greg k-h
> >
> > Hi Greg,
> >
> > The menuconfig looks like the following and it doesn't complain:
> > | Symbol: ARCH_GOOGLE [=ARCH_GOOGLE]
> > | Type  : unknown
> > |
> > | Symbol: PHY_GOOGLE_USB [=y]
> > | Type  : tristate
> > | Defined at drivers/phy/Kconfig:104
> > |     Prompt: Google Tensor SoC USB PHY driver
> > |     Depends on: ARCH_GOOGLE || COMPILE_TEST [=y]
> >
> > According to Kconfig documentation [1], the unknown symbol
> > would simply be evaluated as an "n", which is what we want.
> > "Convert the symbol into an expression. Boolean and tristate
> > symbols are simply converted into the respective expression
> > values. All other symbol types result in ?n?."
> >
> > In a different Kconfig documentation, an environment variable
> > "KCONFIG_WARN_UNKNOWN_SYMBOLS" is there to detect
> > undefined symbols in the "config input", but I can't find one that
> > catches undefined symbols in the Kconfig tree itself.
> >
> > That is, the tool seems to allow this.
> > However, if this turns out to be a major problem. I think we
> > can either:
> > - Remove ARCH_GOOGLE and leave COMPILE_TEST as
> >   the only dependency. Then add ARCH_GOOGLE back
> >   later once it's in the tree.
> > - Defer the whole patch series until ARCH_GOOGLE is
> >   present (I hope not).
> >
> > [1] https://urldefense.com/v3/__https://docs.kernel.org/kbuild/kconfig-language.html*menu-dependencies__;Iw!!A4F2R9G_pg!e-y2_BsSNhXF1v5K6tBJX-OabgKJM9WVdvwyKoB6tg9ooCLVg8WiQ4UrStOF2YZQ_Zs6tC6HVh7wCpqkEfU$
> > [2] https://urldefense.com/v3/__https://www.kernel.org/doc/Documentation/kbuild/kconfig.rst__;!!A4F2R9G_pg!e-y2_BsSNhXF1v5K6tBJX-OabgKJM9WVdvwyKoB6tg9ooCLVg8WiQ4UrStOF2YZQ_Zs6tC6HVh7wHpoUlhY$
> >
>
> Hi Greg, Roy,
>
> Just checking, are we aligned here?
>
> BR,
> Thinh

Thinh,

Thanks for checking in. I'm still waiting on Greg's reply
regarding the Kconfig question.

BTW, I silently dropped your Ack-by tag in v8 due to the
changes in Kconfig and MAINTAINERS files, which I
should've noted in the changelog but I didn't. Sorry for
the inconvenience. Could you please review the current
version again and provide your tag if it looks good?

Regards,
Roy


From oupton at kernel.org  Tue Dec 16 16:38:56 2025
From: oupton at kernel.org (Oliver Upton)
Date: Tue, 16 Dec 2025 16:38:56 -0800
Subject: [PATCH v5 14/24] KVM: arm64: Write fast path PMU register
 handlers
In-Reply-To: <20251209205121.1871534-15-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
 <20251209205121.1871534-15-coltonlewis@google.com>
Message-ID: <aUH7oC41XaEMsXf_@kernel.org>

On Tue, Dec 09, 2025 at 08:51:11PM +0000, Colton Lewis wrote:
> diff --git a/arch/arm64/include/asm/arm_pmuv3.h b/arch/arm64/include/asm/arm_pmuv3.h
> index 3e25c0313263c..41ec6730ebc62 100644
> --- a/arch/arm64/include/asm/arm_pmuv3.h
> +++ b/arch/arm64/include/asm/arm_pmuv3.h
> @@ -39,6 +39,16 @@ static inline unsigned long read_pmevtypern(int n)
>  	return 0;
>  }
>  
> +static inline void write_pmxevcntr(u64 val)
> +{
> +	write_sysreg(val, pmxevcntr_el0);
> +}
> +
> +static inline u64 read_pmxevcntr(void)
> +{
> +	return read_sysreg(pmxevcntr_el0);
> +}
> +
>  static inline unsigned long read_pmmir(void)
>  {
>  	return read_cpuid(PMMIR_EL1);
> @@ -105,21 +115,41 @@ static inline void write_pmcntenset(u64 val)
>  	write_sysreg(val, pmcntenset_el0);
>  }
>  
> +static inline u64 read_pmcntenset(void)
> +{
> +	return read_sysreg(pmcntenset_el0);
> +}
> +
>  static inline void write_pmcntenclr(u64 val)
>  {
>  	write_sysreg(val, pmcntenclr_el0);
>  }
>  
> +static inline u64 read_pmcntenclr(void)
> +{
> +	return read_sysreg(pmcntenclr_el0);
> +}
> +
>  static inline void write_pmintenset(u64 val)
>  {
>  	write_sysreg(val, pmintenset_el1);
>  }
>  
> +static inline u64 read_pmintenset(void)
> +{
> +	return read_sysreg(pmintenset_el1);
> +}
> +
>  static inline void write_pmintenclr(u64 val)
>  {
>  	write_sysreg(val, pmintenclr_el1);
>  }
>  
> +static inline u64 read_pmintenclr(void)
> +{
> +	return read_sysreg(pmintenclr_el1);
> +}
> +
>  static inline void write_pmccfiltr(u64 val)
>  {
>  	write_sysreg(val, pmccfiltr_el0);
> @@ -160,11 +190,16 @@ static inline u64 read_pmovsclr(void)
>  	return read_sysreg(pmovsclr_el0);
>  }
>  
> -static inline void write_pmuserenr(u32 val)
> +static inline void write_pmuserenr(u64 val)
>  {
>  	write_sysreg(val, pmuserenr_el0);
>  }
>  
> +static inline u64 read_pmuserenr(void)
> +{
> +	return read_sysreg(pmuserenr_el0);
> +}
> +
>  static inline void write_pmuacr(u64 val)
>  {
>  	write_sysreg_s(val, SYS_PMUACR_EL1);

I wouldn't bother with adding accessors to the PMUv3 driver header, this
gets a bit confusing when the 32-bit counterpart lacks matching definitions.
Additionally, the part of KVM you're modifying is very much an
"internal" part meant to run in a not-quite-kernel context.

Considering this, I'd prefer KVM directly accessed the PMU registers to
avoid the possibility of taking some instrumented codepath in the
future.

> +	if (!kvm_vcpu_pmu_is_partitioned(vcpu)
> +	    || pmu_access_el0_disabled(vcpu))

Always put operators on the preceding line for line continuations.

Also, don't call pmu_access_el0_disabled() from here. It can potentially
do a full emulated exception entry even though the vCPU is in an
extremely inconsistent state (i.e. haven't returned to kernel context
yet). Isn't the current value for PMUSERENR_EL0 on the CPU instead of in
the vCPU's saved context anyway?

The fast-path accessors really need to be *just* accessors, reading
state from the CPU in the unfortunate situation that a TPM trap has been
forced upon us.

> +	case SYS_PMXEVCNTR_EL0:
> +		idx = FIELD_GET(PMSELR_EL0_SEL, read_pmselr());
> +
> +		if (pmu_access_event_counter_el0_disabled(vcpu))
> +			return false;
> +
> +		if (!pmu_counter_idx_valid(vcpu, idx))
> +			return false;
> +
> +		ret = handle_pmu_reg(vcpu, &p, PMEVCNTR0_EL0 + idx, rt, val,
> +				     &read_pmxevcntr, &write_pmxevcntr);
> +		break;

It is a bit odd to handle the muxing for finding the in-memory value yet
using the selector-based register for hardware.

> +	case SYS_PMEVCNTRn_EL0(0) ... SYS_PMEVCNTRn_EL0(30):
> +		idx = ((p.CRm & 3) << 3) | (p.Op2 & 7);
> +
> +		if (pmu_access_event_counter_el0_disabled(vcpu))
> +			return false;
> +
> +		if (!pmu_counter_idx_valid(vcpu, idx))
> +			return false;
> +
> +		if (p.is_write) {
> +			write_pmevcntrn(idx, val);
> +			__vcpu_assign_sys_reg(vcpu, PMEVCNTR0_EL0 + idx, val);
> +		} else {
> +			vcpu_set_reg(vcpu, rt, read_pmevcntrn(idx));
> +		}
> +
> +		ret = true;
> +		break;

Can't both of these cases share a helper once you've worked out the
index? Same for PMEVTYPERn_EL0.

> +	default:
> +		ret = false;
> +	}
> +
> +	if (ret)
> +		__kvm_skip_instr(vcpu);
> +
> +	return ret;
> +}
> +
>  static inline bool kvm_hyp_handle_sysreg(struct kvm_vcpu *vcpu, u64 *exit_code)
>  {
>  	if (cpus_have_final_cap(ARM64_WORKAROUND_CAVIUM_TX2_219_TVM) &&
> @@ -785,6 +983,9 @@ static inline bool kvm_hyp_handle_sysreg(struct kvm_vcpu *vcpu, u64 *exit_code)
>  	if (kvm_handle_cntxct(vcpu))
>  		return true;
>  
> +	if (kvm_hyp_handle_pmu_regs(vcpu))
> +		return true;
> +

Since the whole partitioned PMU feature is constrained to VHE-only you
should call this from kvm_hyp_handle_sysreg_vhe().

> +
> +bool check_pmu_access_disabled(struct kvm_vcpu *vcpu, u64 flags)
> +{
> +	u64 reg = __vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> +	bool enabled = (reg & flags) || vcpu_mode_priv(vcpu);
> +
> +	if (!enabled)
> +		kvm_inject_undefined(vcpu);
> +
> +	return !enabled;
> +}
> +
> +bool pmu_access_el0_disabled(struct kvm_vcpu *vcpu)
> +{
> +	return check_pmu_access_disabled(vcpu, ARMV8_PMU_USERENR_EN);
> +}
> +
> +bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx)
> +{
> +	u64 pmcr, val;
> +
> +	pmcr = kvm_vcpu_read_pmcr(vcpu);
> +	val = FIELD_GET(ARMV8_PMU_PMCR_N, pmcr);
> +	if (idx >= val && idx != ARMV8_PMU_CYCLE_IDX) {
> +		kvm_inject_undefined(vcpu);
> +		return false;
> +	}
> +
> +	return true;
> +}
> +
> +bool pmu_access_cycle_counter_el0_disabled(struct kvm_vcpu *vcpu)
> +{
> +	return check_pmu_access_disabled(vcpu, ARMV8_PMU_USERENR_CR | ARMV8_PMU_USERENR_EN);
> +}
> +
> +bool pmu_access_event_counter_el0_disabled(struct kvm_vcpu *vcpu)
> +{
> +	return check_pmu_access_disabled(vcpu, ARMV8_PMU_USERENR_ER | ARMV8_PMU_USERENR_EN);
> +}

Refactorings need to happen in a separate patch.

Thanks,
Oliver


From oupton at kernel.org  Tue Dec 16 16:57:19 2025
From: oupton at kernel.org (Oliver Upton)
Date: Tue, 16 Dec 2025 16:57:19 -0800
Subject: [PATCH v5 18/24] KVM: arm64: Enforce PMU event filter at
 vcpu_load()
In-Reply-To: <20251209205121.1871534-19-coltonlewis@google.com>
References: <20251209205121.1871534-1-coltonlewis@google.com>
 <20251209205121.1871534-19-coltonlewis@google.com>
Message-ID: <aUH_7yYZsmFlRvEc@kernel.org>

Re-reading this patch...

On Tue, Dec 09, 2025 at 08:51:15PM +0000, Colton Lewis wrote:
> The KVM API for event filtering says that counters do not count when
> blocked by the event filter. To enforce that, the event filter must be
> rechecked on every load since it might have changed since the last
> time the guest wrote a value.

Just directly state that this is guarding against userspace programming
an unsupported event ID.

> +static void kvm_pmu_apply_event_filter(struct kvm_vcpu *vcpu)
> +{
> +	struct arm_pmu *pmu = vcpu->kvm->arch.arm_pmu;
> +	u64 evtyper_set = ARMV8_PMU_EXCLUDE_EL0 |
> +		ARMV8_PMU_EXCLUDE_EL1;
> +	u64 evtyper_clr = ARMV8_PMU_INCLUDE_EL2;
> +	u8 i;
> +	u64 val;
> +	u64 evsel;
> +
> +	if (!pmu)
> +		return;
> +
> +	for (i = 0; i < pmu->hpmn_max; i++) {

Iterate the bitmask of counters and you'll handle the cycle counter 'for
free'.

<snip>

> +		val = __vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i);
> +		evsel = val & kvm_pmu_event_mask(vcpu->kvm);
> +
> +		if (vcpu->kvm->arch.pmu_filter &&
> +		    !test_bit(evsel, vcpu->kvm->arch.pmu_filter))
> +			val |= evtyper_set;
> +
> +		val &= ~evtyper_clr;
> +		write_pmevtypern(i, val);

</snip>

This all needs to be shared with writethrough_pmevtyper() instead of
open-coding the same thing.

Thanks,
Oliver


From robh at kernel.org  Tue Dec 16 16:57:58 2025
From: robh at kernel.org (Rob Herring)
Date: Tue, 16 Dec 2025 18:57:58 -0600
Subject: [PATCH v6 1/5] dt-bindings: remoteproc: imx_rproc: Add "rpmsg"
 subnode support
In-Reply-To: <20251212194341.966387-2-shenwei.wang@nxp.com>
References: <20251212194341.966387-1-shenwei.wang@nxp.com>
 <20251212194341.966387-2-shenwei.wang@nxp.com>
Message-ID: <20251217005758.GA3452672-robh@kernel.org>

On Fri, Dec 12, 2025 at 01:43:37PM -0600, Shenwei Wang wrote:
> Remote processors may announce multiple devices (e.g., I2C, GPIO) over
> an RPMSG channel. 

Which channel does that happen on?

> These devices may require corresponding device tree
> nodes, especially when acting as providers, to supply phandles for their
> consumers.
> 
> Define an RPMSG node to work as a container for a group of RPMSG channels
> under the imx_rproc node.
> 
> Each subnode within "rpmsg" represents an individual RPMSG channel. The
> name of each subnode corresponds to the channel name as defined by the
> remote processor.
> 
> All remote devices associated with a given channel are defined as child
> nodes under the corresponding channel node.
> 
> Signed-off-by: Shenwei Wang <shenwei.wang at nxp.com>
> ---
>  .../devicetree/bindings/gpio/gpio-rpmsg.yaml  | 49 +++++++++++++++++
>  .../bindings/remoteproc/fsl,imx-rproc.yaml    | 54 +++++++++++++++++++
>  2 files changed, 103 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/gpio/gpio-rpmsg.yaml
> 
> diff --git a/Documentation/devicetree/bindings/gpio/gpio-rpmsg.yaml b/Documentation/devicetree/bindings/gpio/gpio-rpmsg.yaml
> new file mode 100644
> index 000000000000..b3e1a5dbf731
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/gpio/gpio-rpmsg.yaml
> @@ -0,0 +1,49 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/gpio/gpio-rpmsg.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Generic GPIO driver over RPMSG

The driver doesn't go over RPMSG. It's a GPIO provider or protocol.

> +
> +maintainers:
> +  - Shenwei Wang <shenwei.wang at nxp.com>
> +
> +description:
> +  On an AMP platform, some GPIO controllers are exposed by the remote processor
> +  through the RPMSG bus. The RPMSG GPIO transport protocol defines the packet
> +  structure and communication flow between Linux and the remote firmware. Those
> +  controllers are managed via this transport protocol.

Got a reference to where any of this is defined?

> +
> +properties:
> +  compatible:
> +    oneOf:
> +      - items:
> +          - enum:
> +              - fsl,rpmsg-gpio
> +          - const: rpmsg-gpio
> +      - const: rpmsg-gpio
> +
> +  reg:
> +    maxItems: 1

I still don't understand how 'reg' is determined. You may have explained 
it previously, but *this* patch needs to make me understand.

> +
> +  "#gpio-cells":
> +    const: 2
> +
> +  gpio-controller: true
> +
> +  interrupt-controller: true
> +
> +  "#interrupt-cells":
> +    const: 2
> +
> +required:
> +  - compatible
> +  - reg
> +  - "#gpio-cells"
> +  - "#interrupt-cells"
> +
> +allOf:
> +  - $ref: /schemas/gpio/gpio.yaml#
> +
> +unevaluatedProperties: false
> diff --git a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
> index 57d75acb0b5e..fd8e5a61a459 100644
> --- a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
> +++ b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
> @@ -84,6 +84,33 @@ properties:
>        This property is to specify the resource id of the remote processor in SoC
>        which supports SCFW
>  
> +  rpmsg:
> +    type: object
> +    additionalProperties: false
> +    description:
> +      Present a group of RPMSG channel devices.
> +
> +    properties:
> +      rpmsg-io-channel:
> +        type: object
> +        additionalProperties: false
> +        properties:
> +          '#address-cells':
> +            const: 1
> +
> +          '#size-cells':
> +            const: 0
> +
> +        patternProperties:
> +          "gpio@[0-9a-f]+$":
> +            type: object
> +            $ref: /schemas/gpio/gpio-rpmsg.yaml#
> +            unevaluatedProperties: false
> +
> +        required:
> +          - '#address-cells'
> +          - '#size-cells'
> +
>  required:
>    - compatible
>  
> @@ -146,5 +173,32 @@ examples:
>                  &mu 3 1>;
>        memory-region = <&vdev0buffer>, <&vdev0vring0>, <&vdev0vring1>, <&rsc_table>;
>        syscon = <&src>;
> +
> +      rpmsg {

What's the purpose of this node? Is it going to contain things other 
than "rpmsg io channels"?

> +        rpmsg-io-channel {
> +          #address-cells = <1>;
> +          #size-cells = <0>;
> +
> +          gpio at 0 {
> +            compatible = "rpmsg-gpio";
> +            reg = <0>;
> +            gpio-controller;
> +            #gpio-cells = <2>;
> +            #interrupt-cells = <2>;
> +            interrupt-controller;
> +            interrupt-parent = <&rpmsg_gpioa>;
> +          };
> +
> +          gpio at 1 {
> +            compatible = "rpmsg-gpio";
> +            reg = <1>;
> +            gpio-controller;
> +            #gpio-cells = <2>;
> +            #interrupt-cells = <2>;
> +            interrupt-controller;
> +            interrupt-parent = <&rpmsg_gpiob>;
> +          };
> +        };
> +      };
>      };
>  ...
> -- 
> 2.43.0
> 


From peng.fan at oss.nxp.com  Tue Dec 16 17:58:25 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Wed, 17 Dec 2025 09:58:25 +0800
Subject: [PATCH 0/3] arm64: dts: Initial support for i.MX952
Message-ID: <20251217-imx952-v1-v1-0-a55a7fe2df0b@nxp.com>

Initial device tree for i.MX952 and i.MX952-EVK.
i.MX952 is designed for AI-powered sensor fusion and vision sensing
applications, it features 4 Corte-A55, 1 Cortex-M33, 1 Cortex-M7 and
NXP eIQ NPU and advanced graphics, video and advanced security with
edgelock.

Product info could be found at[1].

Note:
There is checkpatch error for the pin headers:
ERROR: Macros with complex values should be enclosed in parentheses
checkpatch.pl maintainer said "Just ignore the message instead", see[2]

[1]https://www.nxp.com/products/i.MX-952
[2]https://lore.kernel.org/all/fce65a7761fb0e880beb469e2521598f at perches.com/

Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
Peng Fan (3):
      dt-bindings: arm: fsl: add i.MX952 EVK board
      arm64: dts: freescale: Add initial device tree for i.MX952
      arm64: dts: freescale: Add i.MX952 EVK basic device tree

 Documentation/devicetree/bindings/arm/fsl.yaml |    6 +
 arch/arm64/boot/dts/freescale/Makefile         |    2 +
 arch/arm64/boot/dts/freescale/imx952-clock.h   |  215 ++++
 arch/arm64/boot/dts/freescale/imx952-evk.dts   |  217 ++++
 arch/arm64/boot/dts/freescale/imx952-pinfunc.h |  867 ++++++++++++++++
 arch/arm64/boot/dts/freescale/imx952-power.h   |   44 +
 arch/arm64/boot/dts/freescale/imx952.dtsi      | 1248 ++++++++++++++++++++++++
 7 files changed, 2599 insertions(+)
---
base-commit: 563c8dd425b59e44470e28519107b1efc99f4c7b
change-id: 20251216-imx952-v1-e5c2debf20c4

Best regards,
-- 
Peng Fan <peng.fan at nxp.com>



From peng.fan at oss.nxp.com  Tue Dec 16 17:58:26 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Wed, 17 Dec 2025 09:58:26 +0800
Subject: [PATCH 1/3] dt-bindings: arm: fsl: add i.MX952 EVK board
In-Reply-To: <20251217-imx952-v1-v1-0-a55a7fe2df0b@nxp.com>
References: <20251217-imx952-v1-v1-0-a55a7fe2df0b@nxp.com>
Message-ID: <20251217-imx952-v1-v1-1-a55a7fe2df0b@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

Add DT compatible string for NXP i.MX952 EVK board.

Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 Documentation/devicetree/bindings/arm/fsl.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
index 68a2d5fecc43b06711e2efce61ac1fc2794b79bc..b3a6f72341fcddd05ec21912e975878c9d0fed73 100644
--- a/Documentation/devicetree/bindings/arm/fsl.yaml
+++ b/Documentation/devicetree/bindings/arm/fsl.yaml
@@ -1436,6 +1436,12 @@ properties:
               - toradex,verdin-imx95-19x19-evk  # i.MX95 Verdin Evaluation Kit (EVK)
           - const: fsl,imx95
 
+      - description: i.MX952 based Boards
+        items:
+          - enum:
+              - fsl,imx952-evk            # i.MX952 EVK Board
+          - const: fsl,imx952
+
       - description: PHYTEC i.MX 95 FPSC based Boards
         items:
           - enum:

-- 
2.37.1



From peng.fan at oss.nxp.com  Tue Dec 16 17:58:28 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Wed, 17 Dec 2025 09:58:28 +0800
Subject: [PATCH 3/3] arm64: dts: freescale: Add i.MX952 EVK basic device
 tree
In-Reply-To: <20251217-imx952-v1-v1-0-a55a7fe2df0b@nxp.com>
References: <20251217-imx952-v1-v1-0-a55a7fe2df0b@nxp.com>
Message-ID: <20251217-imx952-v1-v1-3-a55a7fe2df0b@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

Add i.MX952 EVK basic device tree, with UART1, SDHC[1,2] supported.

Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 arch/arm64/boot/dts/freescale/Makefile       |   2 +
 arch/arm64/boot/dts/freescale/imx952-evk.dts | 217 +++++++++++++++++++++++++++
 2 files changed, 219 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index f30d3fd724d0ce6b38f7bef10e3970ac34f70f4a..05d8ccd89186478ad4310f56a02783b51034f839 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -414,6 +414,8 @@ dtb-$(CONFIG_ARCH_MXC) += imx95-libra-rdk-fpsc.dtb
 
 dtb-$(CONFIG_ARCH_MXC) += imx95-19x19-verdin-evk.dtb
 
+dtb-$(CONFIG_ARCH_MXC) += imx952-evk.dtb
+
 imx8mm-kontron-dl-dtbs			:= imx8mm-kontron-bl.dtb imx8mm-kontron-dl.dtbo
 imx8mm-kontron-bl-lte-dtbs		:= imx8mm-kontron-bl.dtb imx8mm-kontron-bl-lte.dtbo
 
diff --git a/arch/arm64/boot/dts/freescale/imx952-evk.dts b/arch/arm64/boot/dts/freescale/imx952-evk.dts
new file mode 100644
index 0000000000000000000000000000000000000000..2c753fcbae3c5d545f5d835bd70492667061d626
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx952-evk.dts
@@ -0,0 +1,217 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2025 NXP
+ */
+
+/dts-v1/;
+
+#include "imx952.dtsi"
+
+/ {
+	model = "NXP i.MX952 EVK board";
+	compatible = "fsl,imx952-evk", "fsl,imx952";
+
+	aliases {
+		gpio0 = &gpio1;
+		gpio1 = &gpio2;
+		gpio2 = &gpio3;
+		gpio3 = &gpio4;
+		gpio4 = &gpio5;
+		mmc0 = &usdhc1;
+		mmc1 = &usdhc2;
+		serial0 = &lpuart1;
+	};
+
+	chosen {
+		stdout-path = &lpuart1;
+	};
+
+	memory at 80000000 {
+		device_type = "memory";
+		reg = <0x0 0x80000000 0 0x80000000>;
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		linux_cma: linux,cma {
+			compatible = "shared-dma-pool";
+			alloc-ranges = <0 0x80000000 0 0x7f000000>;
+			size = <0 0x3c000000>;
+			linux,cma-default;
+			reusable;
+		};
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "+V3.3_SW";
+	};
+
+	reg_1p8v: regulator-1p8v {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <1800000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-name = "+V1.8_SW";
+	};
+
+	reg_vref_1v8: regulator-adc-vref {
+		compatible = "regulator-fixed";
+		regulator-name = "vref_1v8";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	reg_usdhc2_vmmc: regulator-usdhc2 {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
+		regulator-name = "VDD_SD2_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio3 7 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		off-on-delay-us = <12000>;
+	};
+};
+
+&lpuart1 {
+	/* console */
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart1>;
+	status = "okay";
+};
+
+&usdhc1 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
+	pinctrl-0 = <&pinctrl_usdhc1>;
+	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
+	pinctrl-3 = <&pinctrl_usdhc1>;
+	bus-width = <8>;
+	non-removable;
+	no-sdio;
+	no-sd;
+	status = "okay";
+};
+
+&usdhc2 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
+	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-3 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	cd-gpios = <&gpio3 0 GPIO_ACTIVE_LOW>;
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	bus-width = <4>;
+	status = "okay";
+};
+
+&scmi_iomuxc {
+	pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
+		fsl,pins = <
+			IMX952_PAD_SD2_RESET_B__WAKEUPMIX_TOP_GPIO3_IO_7	0x31e
+		>;
+	};
+
+	pinctrl_uart1: uart1grp {
+		fsl,pins = <
+			IMX952_PAD_UART1_RXD__AONMIX_TOP_LPUART1_RX		0x31e
+			IMX952_PAD_UART1_TXD__AONMIX_TOP_LPUART1_TX		0x31e
+		>;
+	};
+
+	pinctrl_usdhc1: usdhc1grp {
+		fsl,pins = <
+			IMX952_PAD_SD1_CLK__WAKEUPMIX_TOP_USDHC1_CLK		0x158e
+			IMX952_PAD_SD1_CMD__WAKEUPMIX_TOP_USDHC1_CMD		0x138e
+			IMX952_PAD_SD1_DATA0__WAKEUPMIX_TOP_USDHC1_DATA0	0x138e
+			IMX952_PAD_SD1_DATA1__WAKEUPMIX_TOP_USDHC1_DATA1	0x138e
+			IMX952_PAD_SD1_DATA2__WAKEUPMIX_TOP_USDHC1_DATA2	0x138e
+			IMX952_PAD_SD1_DATA3__WAKEUPMIX_TOP_USDHC1_DATA3	0x138e
+			IMX952_PAD_SD1_DATA4__WAKEUPMIX_TOP_USDHC1_DATA4	0x138e
+			IMX952_PAD_SD1_DATA5__WAKEUPMIX_TOP_USDHC1_DATA5	0x138e
+			IMX952_PAD_SD1_DATA6__WAKEUPMIX_TOP_USDHC1_DATA6	0x138e
+			IMX952_PAD_SD1_DATA7__WAKEUPMIX_TOP_USDHC1_DATA7	0x138e
+			IMX952_PAD_SD1_STROBE__WAKEUPMIX_TOP_USDHC1_STROBE	0x158e
+		>;
+	};
+
+	pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp {
+		fsl,pins = <
+			IMX952_PAD_SD1_CLK__WAKEUPMIX_TOP_USDHC1_CLK		0x158e
+			IMX952_PAD_SD1_CMD__WAKEUPMIX_TOP_USDHC1_CMD		0x138e
+			IMX952_PAD_SD1_DATA0__WAKEUPMIX_TOP_USDHC1_DATA0	0x138e
+			IMX952_PAD_SD1_DATA1__WAKEUPMIX_TOP_USDHC1_DATA1	0x138e
+			IMX952_PAD_SD1_DATA2__WAKEUPMIX_TOP_USDHC1_DATA2	0x138e
+			IMX952_PAD_SD1_DATA3__WAKEUPMIX_TOP_USDHC1_DATA3	0x138e
+			IMX952_PAD_SD1_DATA4__WAKEUPMIX_TOP_USDHC1_DATA4	0x138e
+			IMX952_PAD_SD1_DATA5__WAKEUPMIX_TOP_USDHC1_DATA5	0x138e
+			IMX952_PAD_SD1_DATA6__WAKEUPMIX_TOP_USDHC1_DATA6	0x138e
+			IMX952_PAD_SD1_DATA7__WAKEUPMIX_TOP_USDHC1_DATA7	0x138e
+			IMX952_PAD_SD1_STROBE__WAKEUPMIX_TOP_USDHC1_STROBE	0x158e
+		>;
+	};
+
+	pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp {
+		fsl,pins = <
+			IMX952_PAD_SD1_CLK__WAKEUPMIX_TOP_USDHC1_CLK		0x15fe
+			IMX952_PAD_SD1_CMD__WAKEUPMIX_TOP_USDHC1_CMD		0x13fe
+			IMX952_PAD_SD1_DATA0__WAKEUPMIX_TOP_USDHC1_DATA0	0x13fe
+			IMX952_PAD_SD1_DATA1__WAKEUPMIX_TOP_USDHC1_DATA1	0x13fe
+			IMX952_PAD_SD1_DATA2__WAKEUPMIX_TOP_USDHC1_DATA2	0x13fe
+			IMX952_PAD_SD1_DATA3__WAKEUPMIX_TOP_USDHC1_DATA3	0x13fe
+			IMX952_PAD_SD1_DATA4__WAKEUPMIX_TOP_USDHC1_DATA4	0x13fe
+			IMX952_PAD_SD1_DATA5__WAKEUPMIX_TOP_USDHC1_DATA5	0x13fe
+			IMX952_PAD_SD1_DATA6__WAKEUPMIX_TOP_USDHC1_DATA6	0x13fe
+			IMX952_PAD_SD1_DATA7__WAKEUPMIX_TOP_USDHC1_DATA7	0x13fe
+			IMX952_PAD_SD1_STROBE__WAKEUPMIX_TOP_USDHC1_STROBE	0x15fe
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			IMX952_PAD_SD2_CLK__WAKEUPMIX_TOP_USDHC2_CLK		0x158e
+			IMX952_PAD_SD2_CMD__WAKEUPMIX_TOP_USDHC2_CMD		0x138e
+			IMX952_PAD_SD2_DATA0__WAKEUPMIX_TOP_USDHC2_DATA0	0x138e
+			IMX952_PAD_SD2_DATA1__WAKEUPMIX_TOP_USDHC2_DATA1	0x138e
+			IMX952_PAD_SD2_DATA2__WAKEUPMIX_TOP_USDHC2_DATA2	0x138e
+			IMX952_PAD_SD2_DATA3__WAKEUPMIX_TOP_USDHC2_DATA3	0x138e
+			IMX952_PAD_SD2_VSELECT__WAKEUPMIX_TOP_USDHC2_VSELECT	0x51e
+		>;
+	};
+
+	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+		fsl,pins = <
+			IMX952_PAD_SD2_CLK__WAKEUPMIX_TOP_USDHC2_CLK		0x158e
+			IMX952_PAD_SD2_CMD__WAKEUPMIX_TOP_USDHC2_CMD		0x138e
+			IMX952_PAD_SD2_DATA0__WAKEUPMIX_TOP_USDHC2_DATA0	0x138e
+			IMX952_PAD_SD2_DATA1__WAKEUPMIX_TOP_USDHC2_DATA1	0x138e
+			IMX952_PAD_SD2_DATA2__WAKEUPMIX_TOP_USDHC2_DATA2	0x138e
+			IMX952_PAD_SD2_DATA3__WAKEUPMIX_TOP_USDHC2_DATA3	0x138e
+			IMX952_PAD_SD2_VSELECT__WAKEUPMIX_TOP_USDHC2_VSELECT	0x51e
+		>;
+	};
+
+	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+		fsl,pins = <
+			IMX952_PAD_SD2_CLK__WAKEUPMIX_TOP_USDHC2_CLK		0x158e
+			IMX952_PAD_SD2_CMD__WAKEUPMIX_TOP_USDHC2_CMD		0x138e
+			IMX952_PAD_SD2_DATA0__WAKEUPMIX_TOP_USDHC2_DATA0	0x138e
+			IMX952_PAD_SD2_DATA1__WAKEUPMIX_TOP_USDHC2_DATA1	0x138e
+			IMX952_PAD_SD2_DATA2__WAKEUPMIX_TOP_USDHC2_DATA2	0x138e
+			IMX952_PAD_SD2_DATA3__WAKEUPMIX_TOP_USDHC2_DATA3	0x138e
+			IMX952_PAD_SD2_VSELECT__WAKEUPMIX_TOP_USDHC2_VSELECT	0x51e
+		>;
+	};
+
+	pinctrl_usdhc2_gpio: usdhc2gpiogrp {
+		fsl,pins = <
+			IMX952_PAD_SD2_CD_B__WAKEUPMIX_TOP_GPIO3_IO_0		0x31e
+		>;
+	};
+};

-- 
2.37.1



From jun.guo at cixtech.com  Tue Dec 16 18:12:50 2025
From: jun.guo at cixtech.com (Jun Guo)
Date: Wed, 17 Dec 2025 10:12:50 +0800
Subject: [PATCH v2 2/3] dma: arm-dma350: add support for shared interrupt
 mode
In-Reply-To: <910e3db2-c4ef-4c21-9336-49469234b8e6@arm.com>
References: <20251216123026.3519923-1-jun.guo@cixtech.com>
 <20251216123026.3519923-3-jun.guo@cixtech.com>
 <910e3db2-c4ef-4c21-9336-49469234b8e6@arm.com>
Message-ID: <87ad76b4-0141-46d9-81df-1e2948f46803@cixtech.com>


On 12/16/2025 8:51 PM, Robin Murphy wrote:
> On 2025-12-16 12:30 pm, Jun Guo wrote:
>> The arm dma350 controller's hardware implementation varies: some
>> designs dedicate a separate interrupt line for each channel, while
>> others have all channels sharing a single interrupt.This patch adds
>> support for the hardware design where all DMA channels share a
>> single interrupt.
>>
>> Signed-off-by: Jun Guo <jun.guo at cixtech.com>
>> ---
>> ? drivers/dma/arm-dma350.c | 124 +++++++++++++++++++++++++++++++++++----
>> ? 1 file changed, 114 insertions(+), 10 deletions(-)
>>
>> diff --git a/drivers/dma/arm-dma350.c b/drivers/dma/arm-dma350.c
>> index 9efe2ca7d5ec..6bea18521edd 100644
>> --- a/drivers/dma/arm-dma350.c
>> +++ b/drivers/dma/arm-dma350.c
>> @@ -14,6 +14,7 @@
>> ? #include "virt-dma.h"
>>
>> ? #define DMAINFO???????????????????? 0x0f00
>> +#define DRIVER_NAME????????? "arm-dma350"
>>
>> ? #define DMA_BUILDCFG0?????????????? 0xb0
>> ? #define DMA_CFG_DATA_WIDTH? GENMASK(18, 16)
>> @@ -142,6 +143,9 @@
>> ? #define LINK_LINKADDR?????????????? BIT(30)
>> ? #define LINK_LINKADDRHI???????????? BIT(31)
>>
>> +/* DMA NONSECURE CONTROL REGISTER */
>> +#define DMANSECCTRL????????? 0x20c
>> +#define INTREN_ANYCHINTR_EN? BIT(0)
>>
>> ? enum ch_ctrl_donetype {
>> ????? CH_CTRL_DONETYPE_NONE = 0,
>> @@ -192,11 +196,16 @@ struct d350_chan {
>>
>> ? struct d350 {
>> ????? struct dma_device dma;
>> +???? void __iomem *base;
>> ????? int nchan;
>> ????? int nreq;
>> ????? struct d350_chan channels[] __counted_by(nchan);
>> ? };
>>
>> +struct d350_driver_data {
>> +???? bool combined_irq;
>> +};
>> +
>> ? static inline struct d350_chan *to_d350_chan(struct dma_chan *chan)
>> ? {
>> ????? return container_of(chan, struct d350_chan, vc.chan);
>> @@ -461,7 +470,61 @@ static void d350_issue_pending(struct dma_chan 
>> *chan)
>> ????? spin_unlock_irqrestore(&dch->vc.lock, flags);
>> ? }
>>
>> -static irqreturn_t d350_irq(int irq, void *data)
>> +static irqreturn_t d350_global_irq(int irq, void *data)
>> +{
>> +???? struct d350 *dmac = (struct d350 *)data;
>> +???? struct device *dev = dmac->dma.dev;
>> +???? irqreturn_t ret = IRQ_NONE;
>> +???? int i;
>> +
>> +???? for (i = 0; i < dmac->nchan; i++) {
>> +???????????? struct d350_chan *dch = &dmac->channels[i];
>> +???????????? u32 ch_status;
>> +
>> +???????????? ch_status = readl(dch->base + CH_STATUS);
>> +???????????? if (!ch_status)
>> +???????????????????? continue;
>> +
>> +???????????? ret = IRQ_HANDLED;
>> +
>> +???????????? if (ch_status & CH_STAT_INTR_ERR) {
>> +???????????????????? struct virt_dma_desc *vd = &dch->desc->vd;
>> +???????????????????? u32 errinfo = readl_relaxed(dch->base + 
>> CH_ERRINFO);
>> +
>> +???????????????????? if (errinfo &
>> +???????????????????????? (CH_ERRINFO_AXIRDPOISERR | 
>> CH_ERRINFO_AXIRDRESPERR))
>> +???????????????????????????? vd->tx_result.result = 
>> DMA_TRANS_READ_FAILED;
>> +???????????????????? else if (errinfo & CH_ERRINFO_AXIWRRESPERR)
>> +???????????????????????????? vd->tx_result.result = 
>> DMA_TRANS_WRITE_FAILED;
>> +???????????????????? else
>> +???????????????????????????? vd->tx_result.result = DMA_TRANS_ABORTED;
>> +
>> +???????????????????? vd->tx_result.residue = d350_get_residue(dch);
>> +???????????? } else if (!(ch_status & CH_STAT_INTR_DONE)) {
>> +???????????????????? dev_warn(dev, "Channel %d unexpected IRQ: 
>> 0x%08x\n", i,
>> +????????????????????????????? ch_status);
>> +???????????? }
>> +
>> +???????????? writel_relaxed(ch_status, dch->base + CH_STATUS);
>> +
>> +???????????? spin_lock(&dch->vc.lock);
>> +???????????? if (ch_status & CH_STAT_INTR_DONE) {
>> +???????????????????? vchan_cookie_complete(&dch->desc->vd);
>> +???????????????????? dch->status = DMA_COMPLETE;
>> +???????????????????? dch->residue = 0;
>> +???????????????????? d350_start_next(dch);
>> +???????????? } else if (ch_status & CH_STAT_INTR_ERR) {
>> +???????????????????? vchan_cookie_complete(&dch->desc->vd);
>> +???????????????????? dch->status = DMA_ERROR;
>> +???????????????????? dch->residue = dch->desc->vd.tx_result.residue;
>> +???????????? }
>> +???????????? spin_unlock(&dch->vc.lock);
>> +???? }
>> +
>> +???? return ret;
>> +}
>> +
>> +static irqreturn_t d350_channel_irq(int irq, void *data)
>> ? {
>> ????? struct d350_chan *dch = data;
>> ????? struct device *dev = dch->vc.chan.device->dev;
>> @@ -506,10 +569,18 @@ static irqreturn_t d350_irq(int irq, void *data)
>> ? static int d350_alloc_chan_resources(struct dma_chan *chan)
>> ? {
>> ????? struct d350_chan *dch = to_d350_chan(chan);
>> -???? int ret = request_irq(dch->irq, d350_irq, IRQF_SHARED,
>> -?????????????????????????? dev_name(&dch->vc.chan.dev->device), dch);
>> -???? if (!ret)
>> -???????????? writel_relaxed(CH_INTREN_DONE | CH_INTREN_ERR, dch->base 
>> + CH_INTREN);
>> +???? int ret = 0;
>> +
>> +???? if (dch->irq) {
>> +???????????? ret = request_irq(dch->irq, d350_channel_irq, IRQF_SHARED,
>> +?????????????????????????????? dev_name(&dch->vc.chan.dev->device), 
>> dch);
>> +???????????? if (ret) {
>> +???????????????????? dev_err(chan->device->dev, "Failed to request 
>> IRQ %d\n", dch->irq);
>> +???????????????????? return ret;
>> +???????????? }
>> +???? }
>> +
>> +???? writel_relaxed(CH_INTREN_DONE | CH_INTREN_ERR, dch->base + 
>> CH_INTREN);
>>
>> ????? return ret;
>> ? }
>> @@ -526,7 +597,8 @@ static void d350_free_chan_resources(struct 
>> dma_chan *chan)
>> ? static int d350_probe(struct platform_device *pdev)
>> ? {
>> ????? struct device *dev = &pdev->dev;
>> -???? struct d350 *dmac;
>> +???? struct d350 *dmac = NULL;
>> +???? const struct d350_driver_data *data;
>> ????? void __iomem *base;
>> ????? u32 reg;
>> ????? int ret, nchan, dw, aw, r, p;
>> @@ -556,6 +628,7 @@ static int d350_probe(struct platform_device *pdev)
>> ????????????? return -ENOMEM;
>>
>> ????? dmac->nchan = nchan;
>> +???? dmac->base = base;
>>
>> ????? reg = readl_relaxed(base + DMAINFO + DMA_BUILDCFG1);
>> ????? dmac->nreq = FIELD_GET(DMA_CFG_NUM_TRIGGER_IN, reg);
>> @@ -582,6 +655,27 @@ static int d350_probe(struct platform_device *pdev)
>> ????? dmac->dma.device_issue_pending = d350_issue_pending;
>> ????? INIT_LIST_HEAD(&dmac->dma.channels);
>>
>> +???? data = device_get_match_data(dev);
>> +???? /* Cix Sky1 has a common host IRQ for all its channels. */
>> +???? if (data && data->combined_irq) {
>> +???????????? int host_irq = platform_get_irq(pdev, 0);
>> +
>> +???????????? if (host_irq < 0)
>> +???????????????????? return dev_err_probe(dev, host_irq,
>> +????????????????????????????????????????? "Failed to get IRQ\n");
>> +
>> +???????????? ret = devm_request_irq(&pdev->dev, host_irq, 
>> d350_global_irq,
>> +??????????????????????????????????? IRQF_SHARED, DRIVER_NAME, dmac);
>> +???????????? if (ret)
>> +???????????????????? return dev_err_probe(
>> +???????????????????????????? dev, ret,
>> +???????????????????????????? "Failed to request the combined IRQ %d\n",
>> +???????????????????????????? host_irq);
>> +???? }
>> +
>> +???? /* Combined Non-Secure Channel Interrupt Enable */
>> +???? writel_relaxed(INTREN_ANYCHINTR_EN, dmac->base + DMANSECCTRL);
> 
> This one line is all that should be needed - all the rest is pointless
> overcomplication and churn. And either way, copy-pasting the entire IRQ
> handler is not OK.
> 
> Thanks,
> Robin.

If the design uses a single interrupt line for all channels, then I only 
need to request one interrupt. When the interrupt occurs, I have to poll 
within the interrupt handler to determine which channel triggered it. 
Are you saying that just this one line is enough to achieve that? I 
don't quite understand.

Best wishes,
Jun Guo


From nobuhiro.iwamatsu.x90 at mail.toshiba  Tue Dec 16 18:13:00 2025
From: nobuhiro.iwamatsu.x90 at mail.toshiba (nobuhiro.iwamatsu.x90 at mail.toshiba)
Date: Wed, 17 Dec 2025 02:13:00 +0000
Subject: [PATCH] arm64: dts: toshiba: Use recommended node names
In-Reply-To: <20251216180055.2793215-2-robh@kernel.org>
References: <20251216180055.2793215-2-robh@kernel.org>
Message-ID: <TY7PR01MB148187A7304501EA9EB3B2DFCCDABA@TY7PR01MB14818.jpnprd01.prod.outlook.com>

Hi Rob,

> -----Original Message-----
> From: Rob Herring (Arm) <robh at kernel.org>
> Sent: Wednesday, December 17, 2025 3:01 AM
> To: soc at kernel.org; iwamatsu nobuhiro(?? ?? ?????????)
> <nobuhiro.iwamatsu.x90 at mail.toshiba>; Krzysztof Kozlowski
> <krzk+dt at kernel.org>; Conor Dooley <conor+dt at kernel.org>
> Cc: linux-arm-kernel at lists.infradead.org; devicetree at vger.kernel.org;
> linux-kernel at vger.kernel.org
> Subject: [PATCH] arm64: dts: toshiba: Use recommended node names
> 
> Update Toshiba TMPV7708 node name to the recommended standard node
> names. Generally, node names and paths aren't considered ABI, so it is safe to
> change them.
> 
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>

Reviewed-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.x90 at mail.toshiba>

Best regards,
  Nobuhiro
> ---
> SoC maintainers, Please take this directly.
> 
>  arch/arm64/boot/dts/toshiba/tmpv7708-rm-mbrc.dts      | 2 +-
>  arch/arm64/boot/dts/toshiba/tmpv7708-visrobo-vrb.dts  | 2 +-
> arch/arm64/boot/dts/toshiba/tmpv7708-visrobo-vrc.dtsi | 2 +-
>  arch/arm64/boot/dts/toshiba/tmpv7708.dtsi             | 4 ++--
>  arch/arm64/boot/dts/toshiba/tmpv7708_pins.dtsi        | 2 +-
>  5 files changed, 6 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/toshiba/tmpv7708-rm-mbrc.dts
> b/arch/arm64/boot/dts/toshiba/tmpv7708-rm-mbrc.dts
> index d209fdc98597..8d099b237025 100644
> --- a/arch/arm64/boot/dts/toshiba/tmpv7708-rm-mbrc.dts
> +++ b/arch/arm64/boot/dts/toshiba/tmpv7708-rm-mbrc.dts
> @@ -43,7 +43,7 @@ &piether {
>  	phy-handle = <&phy0>;
>  	phy-mode = "rgmii-id";
> 
> -	mdio0 {
> +	mdio {
>  		#address-cells = <1>;
>  		#size-cells = <0>;
>  		compatible = "snps,dwmac-mdio";
> diff --git a/arch/arm64/boot/dts/toshiba/tmpv7708-visrobo-vrb.dts
> b/arch/arm64/boot/dts/toshiba/tmpv7708-visrobo-vrb.dts
> index ed7aa7e457b1..4439b3e8acbb 100644
> --- a/arch/arm64/boot/dts/toshiba/tmpv7708-visrobo-vrb.dts
> +++ b/arch/arm64/boot/dts/toshiba/tmpv7708-visrobo-vrb.dts
> @@ -43,7 +43,7 @@ &piether {
>  	phy-handle = <&phy0>;
>  	phy-mode = "rgmii-id";
> 
> -	mdio0 {
> +	mdio {
>  		#address-cells = <1>;
>  		#size-cells = <0>;
>  		compatible = "snps,dwmac-mdio";
> diff --git a/arch/arm64/boot/dts/toshiba/tmpv7708-visrobo-vrc.dtsi
> b/arch/arm64/boot/dts/toshiba/tmpv7708-visrobo-vrc.dtsi
> index 0c8321022a73..af406f7285c4 100644
> --- a/arch/arm64/boot/dts/toshiba/tmpv7708-visrobo-vrc.dtsi
> +++ b/arch/arm64/boot/dts/toshiba/tmpv7708-visrobo-vrc.dtsi
> @@ -26,7 +26,7 @@ &spi0_pins {
>  &spi0 {
>  	status = "okay";
> 
> -	mmc-slot at 0 {
> +	mmc at 0 {
>  		compatible = "mmc-spi-slot";
>  		reg = <0>;
>  		gpios = <&gpio 15 GPIO_ACTIVE_LOW>;
> diff --git a/arch/arm64/boot/dts/toshiba/tmpv7708.dtsi
> b/arch/arm64/boot/dts/toshiba/tmpv7708.dtsi
> index 9aa7b1872bd6..88e38d6efcaa 100644
> --- a/arch/arm64/boot/dts/toshiba/tmpv7708.dtsi
> +++ b/arch/arm64/boot/dts/toshiba/tmpv7708.dtsi
> @@ -161,7 +161,7 @@ gic: interrupt-controller at 24001000 {
>  			      <0 0x24006000 0 0x2000>;
>  		};
> 
> -		pmux: pmux at 24190000 {
> +		pmux: pinctrl at 24190000 {
>  			compatible = "toshiba,tmpv7708-pinctrl";
>  			reg = <0 0x24190000 0 0x10000>;
>  		};
> @@ -463,7 +463,7 @@ piether: ethernet at 28000000 {
>  			status = "disabled";
>  		};
> 
> -		wdt: wdt at 28330000 {
> +		wdt: watchdog at 28330000 {
>  			compatible = "toshiba,visconti-wdt";
>  			reg = <0 0x28330000 0 0x1000>;
>  			clocks = <&pismu TMPV770X_CLK_WDTCLK>; diff
> --git a/arch/arm64/boot/dts/toshiba/tmpv7708_pins.dtsi
> b/arch/arm64/boot/dts/toshiba/tmpv7708_pins.dtsi
> index a480c6ba5f5d..5ea835fe08a8 100644
> --- a/arch/arm64/boot/dts/toshiba/tmpv7708_pins.dtsi
> +++ b/arch/arm64/boot/dts/toshiba/tmpv7708_pins.dtsi
> @@ -91,7 +91,7 @@ i2c8_pins: i2c8-pins {
>  		bias-pull-up;
>  	};
> 
> -	pwm_mux: pwm_mux {
> +	pwm_mux: pwm-pins {
>  		function = "pwm";
>  	};
> 
> --
> 2.51.0




From cuiyunhui at bytedance.com  Tue Dec 16 18:22:13 2025
From: cuiyunhui at bytedance.com (yunhui cui)
Date: Wed, 17 Dec 2025 10:22:13 +0800
Subject: [External] [PATCH v8 4/5] perf: RISC-V: add support for SSE event
In-Reply-To: <CADGDLFgnx3z9WMZBjURx7eEFeeDwb9tj+8WAik4siR_G8erk0Q@mail.gmail.com>
References: <20251105082639.342973-1-cleger@rivosinc.com> <20251105082639.342973-5-cleger@rivosinc.com>
 <CAEEQ3wnQiUdNVjUpdDgAx1=y76vSo66vCD0Wf3EGes274jnkxw@mail.gmail.com> <CADGDLFgnx3z9WMZBjURx7eEFeeDwb9tj+8WAik4siR_G8erk0Q@mail.gmail.com>
Message-ID: <CAEEQ3wmLvBy0rVCwP_LcF9ube0=a1K6QFyp9jnE7JRMXxL11nw@mail.gmail.com>

Hi Cl?ment,

On Wed, Dec 17, 2025 at 4:36?AM Cl?ment L?ger <cleger at rivosinc.com> wrote:
>
> On Fri, Dec 12, 2025 at 4:17?AM yunhui cui <cuiyunhui at bytedance.com> wrote:
> >
> > Hi Cl?ment,
> >
> > On Wed, Nov 5, 2025 at 4:29?PM Cl?ment L?ger <cleger at rivosinc.com> wrote:
> > >
> > > In order to use SSE within PMU drivers, register a SSE handler for the
> > > local PMU event. Reuse the existing overflow IRQ handler and pass
> > > appropriate pt_regs. Add a config option RISCV_PMU_SSE to select event
> > > delivery via SSE events.
> > >
> > > Signed-off-by: Cl?ment L?ger <cleger at rivosinc.com>
> > > ---
> > >  drivers/perf/Kconfig           | 10 +++++
> > >  drivers/perf/riscv_pmu.c       | 23 +++++++++++
> > >  drivers/perf/riscv_pmu_sbi.c   | 71 +++++++++++++++++++++++++++++-----
> > >  include/linux/perf/riscv_pmu.h |  5 +++
> > >  4 files changed, 99 insertions(+), 10 deletions(-)
> > >
> > > diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig
> > > index 638321fc9800..d6ffc2b036e5 100644
> > > --- a/drivers/perf/Kconfig
> > > +++ b/drivers/perf/Kconfig
> > > @@ -105,6 +105,16 @@ config RISCV_PMU_SBI
> > >           full perf feature support i.e. counter overflow, privilege mode
> > >           filtering, counter configuration.
> > >
> > > +config RISCV_PMU_SBI_SSE
> > > +       depends on RISCV_PMU && RISCV_SBI_SSE
> > > +       bool "RISC-V PMU SSE events"
> > > +       default n
> > > +       help
> > > +         Say y if you want to use SSE events to deliver PMU interrupts. This
> > > +         provides a way to profile the kernel at any level by using NMI-like
> > > +         SSE events. SSE events being really intrusive, this option allows
> > > +         to select it only if needed.
> > > +
> > >  config STARFIVE_STARLINK_PMU
> > >         depends on ARCH_STARFIVE || COMPILE_TEST
> > >         depends on 64BIT
> > > diff --git a/drivers/perf/riscv_pmu.c b/drivers/perf/riscv_pmu.c
> > > index 7644147d50b4..dda2814801c0 100644
> > > --- a/drivers/perf/riscv_pmu.c
> > > +++ b/drivers/perf/riscv_pmu.c
> > > @@ -13,6 +13,7 @@
> > >  #include <linux/irqdesc.h>
> > >  #include <linux/perf/riscv_pmu.h>
> > >  #include <linux/printk.h>
> > > +#include <linux/riscv_sbi_sse.h>
> > >  #include <linux/smp.h>
> > >  #include <linux/sched_clock.h>
> > >
> > > @@ -254,6 +255,24 @@ void riscv_pmu_start(struct perf_event *event, int flags)
> > >         perf_event_update_userpage(event);
> > >  }
> > >
> > > +#ifdef CONFIG_RISCV_PMU_SBI_SSE
> > > +static void riscv_pmu_disable(struct pmu *pmu)
> > > +{
> > > +       struct riscv_pmu *rvpmu = to_riscv_pmu(pmu);
> > > +
> > > +       if (rvpmu->sse_evt)
> > > +               sse_event_disable_local(rvpmu->sse_evt);
> > > +}
> > > +
> > > +static void riscv_pmu_enable(struct pmu *pmu)
> > > +{
> > > +       struct riscv_pmu *rvpmu = to_riscv_pmu(pmu);
> > > +
> > > +       if (rvpmu->sse_evt)
> > > +               sse_event_enable_local(rvpmu->sse_evt);
> > > +}
> > > +#endif
> > > +
> > >  static int riscv_pmu_add(struct perf_event *event, int flags)
> > >  {
> > >         struct riscv_pmu *rvpmu = to_riscv_pmu(event->pmu);
> > > @@ -411,6 +430,10 @@ struct riscv_pmu *riscv_pmu_alloc(void)
> > >                 .event_mapped   = riscv_pmu_event_mapped,
> > >                 .event_unmapped = riscv_pmu_event_unmapped,
> > >                 .event_idx      = riscv_pmu_event_idx,
> > > +#ifdef CONFIG_RISCV_PMU_SBI_SSE
> > > +               .pmu_enable     = riscv_pmu_enable,
> > > +               .pmu_disable    = riscv_pmu_disable,
> > > +#endif
> > >                 .add            = riscv_pmu_add,
> > >                 .del            = riscv_pmu_del,
> > >                 .start          = riscv_pmu_start,
> > > diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
> > > index e255c1b069ec..c852f64a5022 100644
> > > --- a/drivers/perf/riscv_pmu_sbi.c
> > > +++ b/drivers/perf/riscv_pmu_sbi.c
> > > @@ -17,6 +17,7 @@
> > >  #include <linux/irqdomain.h>
> > >  #include <linux/of_irq.h>
> > >  #include <linux/of.h>
> > > +#include <linux/riscv_sbi_sse.h>
> > >  #include <linux/cpu_pm.h>
> > >  #include <linux/sched/clock.h>
> > >  #include <linux/soc/andes/irq.h>
> > > @@ -1038,10 +1039,10 @@ static void pmu_sbi_start_overflow_mask(struct riscv_pmu *pmu,
> > >                 pmu_sbi_start_ovf_ctrs_sbi(cpu_hw_evt, ctr_ovf_mask);
> > >  }
> > >
> > > -static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
> > > +static irqreturn_t pmu_sbi_ovf_handler(struct cpu_hw_events *cpu_hw_evt,
> > > +                                      struct pt_regs *regs, bool from_sse)
> > >  {
> > >         struct perf_sample_data data;
> > > -       struct pt_regs *regs;
> > >         struct hw_perf_event *hw_evt;
> > >         union sbi_pmu_ctr_info *info;
> > >         int lidx, hidx, fidx;
> > > @@ -1049,7 +1050,6 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
> > >         struct perf_event *event;
> > >         u64 overflow;
> > >         u64 overflowed_ctrs = 0;
> > > -       struct cpu_hw_events *cpu_hw_evt = dev;
> > >         u64 start_clock = sched_clock();
> > >         struct riscv_pmu_snapshot_data *sdata = cpu_hw_evt->snapshot_addr;
> > >
> > > @@ -1059,13 +1059,15 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
> > >         /* Firmware counter don't support overflow yet */
> > >         fidx = find_first_bit(cpu_hw_evt->used_hw_ctrs, RISCV_MAX_COUNTERS);
> > >         if (fidx == RISCV_MAX_COUNTERS) {
> > > -               csr_clear(CSR_SIP, BIT(riscv_pmu_irq_num));
> > > +               if (!from_sse)
> > > +                       csr_clear(CSR_SIP, BIT(riscv_pmu_irq_num));
> > >                 return IRQ_NONE;
> > >         }
> > >
> > >         event = cpu_hw_evt->events[fidx];
> > >         if (!event) {
> > > -               ALT_SBI_PMU_OVF_CLEAR_PENDING(riscv_pmu_irq_mask);
> > > +               if (!from_sse)
> > > +                       ALT_SBI_PMU_OVF_CLEAR_PENDING(riscv_pmu_irq_mask);
> > >                 return IRQ_NONE;
> > >         }
> > >
> > > @@ -1080,16 +1082,16 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
> > >
> > >         /*
> > >          * Overflow interrupt pending bit should only be cleared after stopping
> > > -        * all the counters to avoid any race condition.
> > > +        * all the counters to avoid any race condition. When using SSE,
> > > +        * interrupt is cleared when stopping counters.
> > >          */
> > > -       ALT_SBI_PMU_OVF_CLEAR_PENDING(riscv_pmu_irq_mask);
> > > +       if (!from_sse)
> > > +               ALT_SBI_PMU_OVF_CLEAR_PENDING(riscv_pmu_irq_mask);
> > >
> > >         /* No overflow bit is set */
> > >         if (!overflow)
> > >                 return IRQ_NONE;
> > >
> > > -       regs = get_irq_regs();
> > > -
> > >         for_each_set_bit(lidx, cpu_hw_evt->used_hw_ctrs, RISCV_MAX_COUNTERS) {
> > >                 struct perf_event *event = cpu_hw_evt->events[lidx];
> > >
> > > @@ -1145,6 +1147,51 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
> > >         return IRQ_HANDLED;
> > >  }
> > >
> > > +static irqreturn_t pmu_sbi_ovf_irq_handler(int irq, void *dev)
> > > +{
> > > +       return pmu_sbi_ovf_handler(dev, get_irq_regs(), false);
> > > +}
> > > +
> > > +#ifdef CONFIG_RISCV_PMU_SBI_SSE
> > > +static int pmu_sbi_ovf_sse_handler(u32 evt, void *arg, struct pt_regs *regs)
> > > +{
> > > +       struct cpu_hw_events __percpu *hw_events = arg;
> > > +       struct cpu_hw_events *hw_event = raw_cpu_ptr(hw_events);
> > > +
> > > +       pmu_sbi_ovf_handler(hw_event, regs, true);
> > > +
> > > +       return 0;
> > > +}
> > > +
> > > +static int pmu_sbi_setup_sse(struct riscv_pmu *pmu)
> > > +{
> > > +       int ret;
> > > +       struct sse_event *evt;
> > > +       struct cpu_hw_events __percpu *hw_events = pmu->hw_events;
> > > +
> > > +       evt = sse_event_register(SBI_SSE_EVENT_LOCAL_PMU_OVERFLOW, 0,
> > > +                                pmu_sbi_ovf_sse_handler, hw_events);
> >
> > As Radim suggested, we had better preset a priority for different
> > events, such as these events and future ones:
> > SBI_SSE_EVENT_LOCAL_HIGH_PRIO_RAS
> > SBI_SSE_EVENT_LOCAL_DOUBLE_TRAP
> > SBI_SSE_EVENT_GLOBAL_HIGH_PRIO_RAS
> > SBI_SSE_EVENT_LOCAL_PMU_OVERFLOW
> > SBI_SSE_EVENT_LOCAL_LOW_PRIO_RAS
> > SBI_SSE_EVENT_GLOBAL_LOW_PRIO_RAS
> > SBI_SSE_EVENT_LOCAL_SOFTWARE_INJECTED
> > SBI_SSE_EVENT_LOCAL_UNKNOWN_NMI
> > SBI_SSE_EVENT_GLOBAL_SOFTWARE_INJECTED
>
> Hey Yunhui,
>
> What do you mean exactly ? Events have default priority based on their
> ID. However, the register call will set a priority = 0 for the event.
> I'll modify that to allow using an optional priority (or even remove
> it)

Actually, each event needs to be assigned a reasonable priority.
Reference: https://lore.kernel.org/all/CAEEQ3wmEVVHC=S795dFsQ9iM5Xkz-KOBe_CxXbvzyDBUo3wU6A at mail.gmail.com/

>
> Thanks,
>
> Cl?ment
>
> >
> > Could you please help add a "global priority enum"?
> >
> >
> > > +       if (IS_ERR(evt))
> > > +               return PTR_ERR(evt);
> > > +
> > > +       ret = sse_event_enable(evt);
> > > +       if (ret) {
> > > +               sse_event_unregister(evt);
> > > +               return ret;
> > > +       }
> > > +
> > > +       pr_info("using SSE for PMU event delivery\n");
> > > +       pmu->sse_evt = evt;
> > > +
> > > +       return ret;
> > > +}
> > > +#else
> > > +static int pmu_sbi_setup_sse(struct riscv_pmu *pmu)
> > > +{
> > > +       return -EOPNOTSUPP;
> > > +}
> > > +#endif
> > > +
> > >  static int pmu_sbi_starting_cpu(unsigned int cpu, struct hlist_node *node)
> > >  {
> > >         struct riscv_pmu *pmu = hlist_entry_safe(node, struct riscv_pmu, node);
> > > @@ -1195,6 +1242,10 @@ static int pmu_sbi_setup_irqs(struct riscv_pmu *pmu, struct platform_device *pde
> > >         struct cpu_hw_events __percpu *hw_events = pmu->hw_events;
> > >         struct irq_domain *domain = NULL;
> > >
> > > +       ret = pmu_sbi_setup_sse(pmu);
> > > +       if (!ret)
> > > +               return 0;
> > > +
> > >         if (riscv_isa_extension_available(NULL, SSCOFPMF)) {
> > >                 riscv_pmu_irq_num = RV_IRQ_PMU;
> > >                 riscv_pmu_use_irq = true;
> > > @@ -1229,7 +1280,7 @@ static int pmu_sbi_setup_irqs(struct riscv_pmu *pmu, struct platform_device *pde
> > >                 return -ENODEV;
> > >         }
> > >
> > > -       ret = request_percpu_irq(riscv_pmu_irq, pmu_sbi_ovf_handler, "riscv-pmu", hw_events);
> > > +       ret = request_percpu_irq(riscv_pmu_irq, pmu_sbi_ovf_irq_handler, "riscv-pmu", hw_events);
> > >         if (ret) {
> > >                 pr_err("registering percpu irq failed [%d]\n", ret);
> > >                 return ret;
> > > diff --git a/include/linux/perf/riscv_pmu.h b/include/linux/perf/riscv_pmu.h
> > > index f82a28040594..08fdcf6baf4e 100644
> > > --- a/include/linux/perf/riscv_pmu.h
> > > +++ b/include/linux/perf/riscv_pmu.h
> > > @@ -28,6 +28,8 @@
> > >
> > >  #define RISCV_PMU_CONFIG1_GUEST_EVENTS 0x1
> > >
> > > +struct sse_event;
> > > +
> > >  struct cpu_hw_events {
> > >         /* currently enabled events */
> > >         int                     n_events;
> > > @@ -54,6 +56,9 @@ struct riscv_pmu {
> > >         char            *name;
> > >
> > >         irqreturn_t     (*handle_irq)(int irq_num, void *dev);
> > > +#ifdef CONFIG_RISCV_PMU_SBI_SSE
> > > +       struct sse_event *sse_evt;
> > > +#endif
> > >
> > >         unsigned long   cmask;
> > >         u64             (*ctr_read)(struct perf_event *event);
> > > --
> > > 2.43.0
> > >
> >
> > Thanks,
> > Yunhui

Thanks,
Yunhui


From zhentao.guo at amlogic.com  Tue Dec 16 18:38:33 2025
From: zhentao.guo at amlogic.com (Zhentao Guo)
Date: Wed, 17 Dec 2025 10:38:33 +0800
Subject: [PATCH RFC v2 1/3] media: dt-bindings: Add Amlogic V4L2 video
 decoder
In-Reply-To: <CAFBinCDO5UWVEtbOOdMn9vy=0H2Q1hJDKhH+X7i0nMsSsw=wbg@mail.gmail.com>
References: <20251124-b4-s4-vdec-upstream-v2-0-bdbbce3f11a6@amlogic.com>
 <20251124-b4-s4-vdec-upstream-v2-1-bdbbce3f11a6@amlogic.com>
 <CAFBinCDO5UWVEtbOOdMn9vy=0H2Q1hJDKhH+X7i0nMsSsw=wbg@mail.gmail.com>
Message-ID: <7ea65b00-a2d9-471c-bc3d-cc340ee1046d@amlogic.com>

Hi Martain,

? 2025/12/17 7:43, Martin Blumenstingl ??:
> [ EXTERNAL EMAIL ]
>
> Hi,
>
> On Mon, Nov 24, 2025 at 4:32?AM Zhentao Guo via B4 Relay
> <devnull+zhentao.guo.amlogic.com at kernel.org> wrote:
>> From: Zhentao Guo <zhentao.guo at amlogic.com>
>>
>> Describe the initial support for the V4L2 stateless video decoder
>> driver used with the Amlogic S4 (S805X2) platform.
>>
>> Signed-off-by: Zhentao Guo <zhentao.guo at amlogic.com>
>> ---
>>   .../bindings/media/amlogic,s4-vcodec-dec.yaml      | 87 ++++++++++++++++++++++
>>   1 file changed, 87 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/media/amlogic,s4-vcodec-dec.yaml b/Documentation/devicetree/bindings/media/amlogic,s4-vcodec-dec.yaml
>> new file mode 100644
>> index 000000000000..401a5a32902e
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/media/amlogic,s4-vcodec-dec.yaml
>> @@ -0,0 +1,87 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +# Copyright (C) 2025 Amlogic, Inc. All rights reserved
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/media/amlogic,vcodec-dec.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Amlogic Video Decode Accelerator
>> +
>> +maintainers:
>> +  - Zhentao Guo <zhentao.guo at amlogic.com>
>> +
>> +description:
>> +  The Video Decoder Accelerator present on Amlogic SOCs.
>> +  It supports stateless h264 decoding.
>> +
>> +properties:
>> +  compatible:
>> +    const: amlogic,s4-vcodec-dec
>> +
>> +  reg:
>> +    maxItems: 2
>> +
>> +  reg-names:
>> +    items:
>> +      - const: dos
>> +      - const: dmc
> Neil has commented on the driver patch (in v1) to use the existing
> canvas driver.
> The same applies to the binding: you can replace the whole "dmc"
> registers with an "amlogic,canvas" property (see
> Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml for
> an example).

Indeed, only a section of the dmc registers is for canvas. For the reset 
part of the registers, canvas driver should not access them directely.

For example, on S805X2 platform, the DMC registers range from 0xfe036000 
to 0xfe038000. The?canvas?registers only range from?0xfe036048 
to?0xfe03605c.

The decoder driver also need to access the register?0xfe036000, which is 
not contained in the range of?canvas registers, so we still need to 
remap this register in the decoder driver. Therefore, the property 'dmc' 
is still needed.

>
> [...]
>> +required:
>> +  - compatible
>> +  - reg
>> +  - reg-names
>> +  - interrupts
>> +  - clocks
>> +  - clock-names
>> +  - power-domains
>> +  - power-domain-names
> I did a quick:
> $ git grep RESET_DOS
> {include/dt-bindings/reset/amlogic,arch/arm64/boot/dts/amlogic/}*.h
> -> that lists DOS reset lines for most (all?) SoCs that were supported
> by the old vdec driver as well as DOS reset lines for the S4 SoC (for
> which you're adding support here).
> If some of those reset lines are wired in hardware to the DOS region
> then you should include them in the binding.
> For reference in case you are not already familiar with it: [0] "[...]
> make bindings complete even if a driver doesn?t support some features.
> For example, if a device has an interrupt, then include the
> ?interrupts? property even if the driver is only polled mode".
> (the same also applies to any additional clocks or power-domains that
> are wired as inputs into the hardware which you have not listed yet as
> they are not needed for the initially supported codecs)
Yes, I also noticed this issue. The DOS reset line should be added. We 
will fix this in the next patch version. Thanks for your suggestions!
> Best regards,
> Martin
>
BRs

Zhentao

> [0] https://docs.kernel.org/devicetree/bindings/writing-bindings.html


From peng.fan at oss.nxp.com  Tue Dec 16 18:40:44 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Wed, 17 Dec 2025 10:40:44 +0800
Subject: [PATCH 0/2] pinctrl: imx: Support i.MX952 and update for i.MX94
Message-ID: <20251217-imx952-pin-v1-0-2747f09144dd@nxp.com>

Patch 1:
For the changes to i.MX94, some pins' mux options are not controlled by
IOMUXC, they are controlled in WAKUPMIX BLK CTRL. SM extends the pinctrl
protocol, by adding a new cfg option.

Patch 2:
Similar as i.MX95 and i.MX94, i.MX952 IOMUXC is also managed by System
Manager(SM) and exposed to Linux through SCMI pinctrl protocol.

i.MX952's select input register offset is different, so need to update
driver to include it.

Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
Peng Fan (1):
      pinctrl: imx: Add support for NXP i.MX952

Ranjani Vaidyanathan (1):
      pinctrl: imx: Support NXP scmi extended mux config

 drivers/pinctrl/freescale/pinctrl-imx-scmi.c | 20 ++++++++++++++++----
 drivers/pinctrl/pinctrl-scmi.c               |  3 ++-
 2 files changed, 18 insertions(+), 5 deletions(-)
---
base-commit: 563c8dd425b59e44470e28519107b1efc99f4c7b
change-id: 20251217-imx952-pin-2731d9cb6a15

Best regards,
-- 
Peng Fan <peng.fan at nxp.com>



From peng.fan at oss.nxp.com  Tue Dec 16 18:40:45 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Wed, 17 Dec 2025 10:40:45 +0800
Subject: [PATCH 1/2] pinctrl: imx: Support NXP scmi extended mux config
In-Reply-To: <20251217-imx952-pin-v1-0-2747f09144dd@nxp.com>
References: <20251217-imx952-pin-v1-0-2747f09144dd@nxp.com>
Message-ID: <20251217-imx952-pin-v1-1-2747f09144dd@nxp.com>

From: Ranjani Vaidyanathan <ranjani.vaidyanathan at nxp.com>

i.MX94 has special muxing options for certain pins. Their mux settings
are not in IOMUXC module. i.MX System Manager Firmware includes new vendor
defined pinctrl type to SCMI pinctrl driver to handle these pins. The MUX
value field in the IOMUX table is extended to 16 bits where the lower 8
bits represent the current IOMUX value and the upper 8 bits represent the
new extended mux added in i.MX94.

Signed-off-by: Ranjani Vaidyanathan <ranjani.vaidyanathan at nxp.com>
Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 drivers/pinctrl/freescale/pinctrl-imx-scmi.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/pinctrl/freescale/pinctrl-imx-scmi.c b/drivers/pinctrl/freescale/pinctrl-imx-scmi.c
index 4e8ab919b334a11e3e716c4580e18bb0e65a6c02..04728ad807d38367a19e6e774d4ccc985549ecfe 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx-scmi.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx-scmi.c
@@ -38,11 +38,12 @@ struct scmi_pinctrl_imx {
 };
 
 /* SCMI pin control types, aligned with SCMI firmware */
-#define IMX_SCMI_NUM_CFG	4
+#define IMX_SCMI_NUM_CFG	5
 #define IMX_SCMI_PIN_MUX	192
 #define IMX_SCMI_PIN_CONFIG	193
 #define IMX_SCMI_PIN_DAISY_ID	194
 #define IMX_SCMI_PIN_DAISY_CFG	195
+#define IMX_SCMI_PIN_EXT	196
 
 #define IMX_SCMI_NO_PAD_CTL		BIT(31)
 #define IMX_SCMI_PAD_SION		BIT(30)
@@ -118,7 +119,14 @@ static int pinctrl_scmi_imx_dt_node_to_map(struct pinctrl_dev *pctldev,
 
 		pin_id = mux_reg / 4;
 
-		cfg[j++] = pinconf_to_config_packed(IMX_SCMI_PIN_MUX, mux_val);
+		cfg[j++] = pinconf_to_config_packed(IMX_SCMI_PIN_MUX, (mux_val & 0xFF));
+
+		if (mux_val & 0xFF00) {
+			int ext_val = (mux_val & 0xFF00) >> 8;
+
+			cfg[j++] = pinconf_to_config_packed(IMX_SCMI_PIN_EXT, ext_val);
+		} else
+			ncfg--;
 
 		if (!conf_reg || (conf_val & IMX_SCMI_NO_PAD_CTL))
 			ncfg--;

-- 
2.37.1



From peng.fan at oss.nxp.com  Tue Dec 16 18:40:46 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Wed, 17 Dec 2025 10:40:46 +0800
Subject: [PATCH 2/2] pinctrl: imx: Add support for NXP i.MX952
In-Reply-To: <20251217-imx952-pin-v1-0-2747f09144dd@nxp.com>
References: <20251217-imx952-pin-v1-0-2747f09144dd@nxp.com>
Message-ID: <20251217-imx952-pin-v1-2-2747f09144dd@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

The i.MX952 System Manager (SM) firmware supports the System Control
Management Interface (SCMI) pinctrl protocol, similar to the i.MX95 SM.
The base offset for the i.MX952 IOMUXC Daisy input register differs from
that of the i.MX95. Update the pinctrl-imx-scmi driver to add support for
i.MX952.

Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 drivers/pinctrl/freescale/pinctrl-imx-scmi.c | 8 ++++++--
 drivers/pinctrl/pinctrl-scmi.c               | 3 ++-
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/drivers/pinctrl/freescale/pinctrl-imx-scmi.c b/drivers/pinctrl/freescale/pinctrl-imx-scmi.c
index 04728ad807d38367a19e6e774d4ccc985549ecfe..dab2fabdf4561c21f747773f2908f15b61eebb50 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx-scmi.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx-scmi.c
@@ -51,8 +51,9 @@ struct scmi_pinctrl_imx {
 
 #define IMX_SCMI_PIN_SIZE	24
 
-#define IMX95_DAISY_OFF		0x408
 #define IMX94_DAISY_OFF		0x608
+#define IMX95_DAISY_OFF		0x408
+#define IMX952_DAISY_OFF	0x460
 
 static int pinctrl_scmi_imx_dt_node_to_map(struct pinctrl_dev *pctldev,
 					   struct device_node *np,
@@ -74,6 +75,8 @@ static int pinctrl_scmi_imx_dt_node_to_map(struct pinctrl_dev *pctldev,
 			daisy_off = IMX95_DAISY_OFF;
 		} else if (of_machine_is_compatible("fsl,imx94")) {
 			daisy_off = IMX94_DAISY_OFF;
+		} else if (of_machine_is_compatible("fsl,imx952")) {
+			daisy_off = IMX952_DAISY_OFF;
 		} else {
 			dev_err(pctldev->dev, "platform not support scmi pinctrl\n");
 			return -EINVAL;
@@ -299,8 +302,9 @@ scmi_pinctrl_imx_get_pins(struct scmi_pinctrl_imx *pmx, struct pinctrl_desc *des
 }
 
 static const char * const scmi_pinctrl_imx_allowlist[] = {
-	"fsl,imx95",
 	"fsl,imx94",
+	"fsl,imx95",
+	"fsl,imx952",
 	NULL
 };
 
diff --git a/drivers/pinctrl/pinctrl-scmi.c b/drivers/pinctrl/pinctrl-scmi.c
index af3ac031e3626818495a168a96c7930907d9524a..d5fb8649cd9aaddee679ebfd86d8f3d1127b8e01 100644
--- a/drivers/pinctrl/pinctrl-scmi.c
+++ b/drivers/pinctrl/pinctrl-scmi.c
@@ -504,8 +504,9 @@ static int pinctrl_scmi_get_pins(struct scmi_pinctrl *pmx,
 }
 
 static const char * const scmi_pinctrl_blocklist[] = {
-	"fsl,imx95",
 	"fsl,imx94",
+	"fsl,imx95",
+	"fsl,imx952",
 	NULL
 };
 

-- 
2.37.1



From chou.cosmo at gmail.com  Tue Dec 16 18:39:33 2025
From: chou.cosmo at gmail.com (Cosmo Chou)
Date: Wed, 17 Dec 2025 10:39:33 +0800
Subject: [PATCH v2 0/5] ARM: dts: aspeed: bletchley: Fix dt-schema warnings
Message-ID: <20251217023938.445721-1-chou.cosmo@gmail.com>

This series fixes dt-schema validation warnings by using generic node
names, correcting GPIO property suffixes, and removing unsupported
properties. No functional changes.

Changes in v2:
- Split single patch into 5 separate patches by change type

Cosmo Chou (5):
  ARM: dts: aspeed: bletchley: Use generic node names
  ARM: dts: aspeed: bletchley: Fix SPI GPIO property names
  ARM: dts: aspeed: bletchley: Remove unused pca9539 properties
  ARM: dts: aspeed: bletchley: Remove unused i2c13 property
  ARM: dts: aspeed: bletchley: Fix ADC vref property names

 .../aspeed/aspeed-bmc-facebook-bletchley.dts  | 100 ++++++++++--------
 1 file changed, 54 insertions(+), 46 deletions(-)

-- 
2.43.0



From chou.cosmo at gmail.com  Tue Dec 16 18:39:34 2025
From: chou.cosmo at gmail.com (Cosmo Chou)
Date: Wed, 17 Dec 2025 10:39:34 +0800
Subject: [PATCH v2 1/5] ARM: dts: aspeed: bletchley: Use generic node names
In-Reply-To: <20251217023938.445721-1-chou.cosmo@gmail.com>
References: <20251217023938.445721-1-chou.cosmo@gmail.com>
Message-ID: <20251217023938.445721-2-chou.cosmo@gmail.com>

Use generic node names to fix dt-schema warnings:
- spi1_gpio: rename to generic "spi" node name
- LED nodes: rename to led-N and move names to label properties
- GPIO key nodes: add "-switch" suffix to node names

Signed-off-by: Cosmo Chou <chou.cosmo at gmail.com>
---
 .../aspeed/aspeed-bmc-facebook-bletchley.dts  | 77 ++++++++++++-------
 1 file changed, 49 insertions(+), 28 deletions(-)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts
index abdb1562115a..9cb01381e482 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts
+++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts
@@ -34,7 +34,7 @@ iio-hwmon {
 			<&adc1 4>, <&adc1 5>, <&adc1 6>, <&adc1 7>;
 	};
 
-	spi1_gpio: spi1-gpio {
+	spi1_gpio: spi {
 		compatible = "spi-gpio";
 		#address-cells = <1>;
 		#size-cells = <0>;
@@ -54,7 +54,8 @@ tpm at 0 {
 
 	front_gpio_leds {
 		compatible = "gpio-leds";
-		sys_log_id {
+		led-0 {
+			label = "sys_log_id";
 			default-state = "off";
 			gpios = <&front_leds 0 GPIO_ACTIVE_LOW>;
 		};
@@ -62,42 +63,50 @@ sys_log_id {
 
 	fan_gpio_leds {
 		compatible = "gpio-leds";
-		fan0_blue {
+		led-0 {
+			label = "fan0_blue";
 			retain-state-shutdown;
 			default-state = "on";
 			gpios = <&fan_leds 8 GPIO_ACTIVE_HIGH>;
 		};
-		fan1_blue {
+		led-1 {
+			label = "fan1_blue";
 			retain-state-shutdown;
 			default-state = "on";
 			gpios = <&fan_leds 9 GPIO_ACTIVE_HIGH>;
 		};
-		fan2_blue {
+		led-2 {
+			label = "fan2_blue";
 			retain-state-shutdown;
 			default-state = "on";
 			gpios = <&fan_leds 10 GPIO_ACTIVE_HIGH>;
 		};
-		fan3_blue {
+		led-3 {
+			label = "fan3_blue";
 			retain-state-shutdown;
 			default-state = "on";
 			gpios = <&fan_leds 11 GPIO_ACTIVE_HIGH>;
 		};
-		fan0_amber {
+		led-4 {
+			label = "fan0_amber";
 			retain-state-shutdown;
 			default-state = "off";
 			gpios = <&fan_leds 12 GPIO_ACTIVE_HIGH>;
 		};
-		fan1_amber {
+		led-5 {
+			label = "fan1_amber";
 			retain-state-shutdown;
 			default-state = "off";
 			gpios = <&fan_leds 13 GPIO_ACTIVE_HIGH>;
 		};
-		fan2_amber {
+		led-6 {
+			label = "fan2_amber";
 			retain-state-shutdown;
 			default-state = "off";
 			gpios = <&fan_leds 14 GPIO_ACTIVE_HIGH>;
 		};
-		fan3_amber {
+		led-7 {
+			label = "fan3_amber";
 			retain-state-shutdown;
 			default-state = "off";
 			gpios = <&fan_leds 15 GPIO_ACTIVE_HIGH>;
@@ -106,12 +115,14 @@ fan3_amber {
 
 	sled1_gpio_leds {
 		compatible = "gpio-leds";
-		sled1_amber {
+		led-0 {
+			label = "sled1_amber";
 			retain-state-shutdown;
 			default-state = "keep";
 			gpios = <&sled1_leds 0 GPIO_ACTIVE_LOW>;
 		};
-		sled1_blue {
+		led-1 {
+			label = "sled1_blue";
 			retain-state-shutdown;
 			default-state = "keep";
 			gpios = <&sled1_leds 1 GPIO_ACTIVE_LOW>;
@@ -120,12 +131,14 @@ sled1_blue {
 
 	sled2_gpio_leds {
 		compatible = "gpio-leds";
-		sled2_amber {
+		led-0 {
+			label = "sled2_amber";
 			retain-state-shutdown;
 			default-state = "keep";
 			gpios = <&sled2_leds 0 GPIO_ACTIVE_LOW>;
 		};
-		sled2_blue {
+		led-1 {
+			label = "sled2_blue";
 			retain-state-shutdown;
 			default-state = "keep";
 			gpios = <&sled2_leds 1 GPIO_ACTIVE_LOW>;
@@ -134,12 +147,14 @@ sled2_blue {
 
 	sled3_gpio_leds {
 		compatible = "gpio-leds";
-		sled3_amber {
+		led-0 {
+			label = "sled3_amber";
 			retain-state-shutdown;
 			default-state = "keep";
 			gpios = <&sled3_leds 0 GPIO_ACTIVE_LOW>;
 		};
-		sled3_blue {
+		led-1 {
+			label = "sled3_blue";
 			retain-state-shutdown;
 			default-state = "keep";
 			gpios = <&sled3_leds 1 GPIO_ACTIVE_LOW>;
@@ -148,12 +163,14 @@ sled3_blue {
 
 	sled4_gpio_leds {
 		compatible = "gpio-leds";
-		sled4_amber {
+		led-0 {
+			label = "sled4_amber";
 			retain-state-shutdown;
 			default-state = "keep";
 			gpios = <&sled4_leds 0 GPIO_ACTIVE_LOW>;
 		};
-		sled4_blue {
+		led-1 {
+			label = "sled4_blue";
 			retain-state-shutdown;
 			default-state = "keep";
 			gpios = <&sled4_leds 1 GPIO_ACTIVE_LOW>;
@@ -162,12 +179,14 @@ sled4_blue {
 
 	sled5_gpio_leds {
 		compatible = "gpio-leds";
-		sled5_amber {
+		led-0 {
+			label = "sled5_amber";
 			retain-state-shutdown;
 			default-state = "keep";
 			gpios = <&sled5_leds 0 GPIO_ACTIVE_LOW>;
 		};
-		sled5_blue {
+		led-1 {
+			label = "sled5_blue";
 			retain-state-shutdown;
 			default-state = "keep";
 			gpios = <&sled5_leds 1 GPIO_ACTIVE_LOW>;
@@ -176,12 +195,14 @@ sled5_blue {
 
 	sled6_gpio_leds {
 		compatible = "gpio-leds";
-		sled6_amber {
+		led-0 {
+			label = "sled6_amber";
 			retain-state-shutdown;
 			default-state = "keep";
 			gpios = <&sled6_leds 0 GPIO_ACTIVE_LOW>;
 		};
-		sled6_blue {
+		led-1 {
+			label = "sled6_blue";
 			retain-state-shutdown;
 			default-state = "keep";
 			gpios = <&sled6_leds 1 GPIO_ACTIVE_LOW>;
@@ -191,32 +212,32 @@ sled6_blue {
 	gpio-keys {
 		compatible = "gpio-keys";
 
-		presence-sled1 {
+		presence-sled1-switch {
 			label = "presence-sled1";
 			gpios = <&gpio0 ASPEED_GPIO(H, 2) GPIO_ACTIVE_LOW>;
 			linux,code = <ASPEED_GPIO(H, 2)>;
 		};
-		presence-sled2 {
+		presence-sled2-switch {
 			label = "presence-sled2";
 			gpios = <&gpio0 ASPEED_GPIO(H, 3) GPIO_ACTIVE_LOW>;
 			linux,code = <ASPEED_GPIO(H, 3)>;
 		};
-		presence-sled3 {
+		presence-sled3-switch {
 			label = "presence-sled3";
 			gpios = <&gpio0 ASPEED_GPIO(H, 4) GPIO_ACTIVE_LOW>;
 			linux,code = <ASPEED_GPIO(H, 4)>;
 		};
-		presence-sled4 {
+		presence-sled4-switch {
 			label = "presence-sled4";
 			gpios = <&gpio0 ASPEED_GPIO(H, 5) GPIO_ACTIVE_LOW>;
 			linux,code = <ASPEED_GPIO(H, 5)>;
 		};
-		presence-sled5 {
+		presence-sled5-switch {
 			label = "presence-sled5";
 			gpios = <&gpio0 ASPEED_GPIO(H, 6) GPIO_ACTIVE_LOW>;
 			linux,code = <ASPEED_GPIO(H, 6)>;
 		};
-		presence-sled6 {
+		presence-sled6-switch {
 			label = "presence-sled6";
 			gpios = <&gpio0 ASPEED_GPIO(H, 7) GPIO_ACTIVE_LOW>;
 			linux,code = <ASPEED_GPIO(H, 7)>;
-- 
2.43.0



From chou.cosmo at gmail.com  Tue Dec 16 18:39:35 2025
From: chou.cosmo at gmail.com (Cosmo Chou)
Date: Wed, 17 Dec 2025 10:39:35 +0800
Subject: [PATCH v2 2/5] ARM: dts: aspeed: bletchley: Fix SPI GPIO property names
In-Reply-To: <20251217023938.445721-1-chou.cosmo@gmail.com>
References: <20251217023938.445721-1-chou.cosmo@gmail.com>
Message-ID: <20251217023938.445721-3-chou.cosmo@gmail.com>

Update SPI GPIO properties to use "-gpios" suffix:
- gpio-sck -> sck-gpios
- gpio-mosi -> mosi-gpios
- gpio-miso -> miso-gpios

Signed-off-by: Cosmo Chou <chou.cosmo at gmail.com>
---
 arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts
index 9cb01381e482..5919a5046078 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts
+++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts
@@ -39,9 +39,9 @@ spi1_gpio: spi {
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		gpio-sck = <&gpio0 ASPEED_GPIO(Z, 3) GPIO_ACTIVE_HIGH>;
-		gpio-mosi = <&gpio0 ASPEED_GPIO(Z, 4) GPIO_ACTIVE_HIGH>;
-		gpio-miso = <&gpio0 ASPEED_GPIO(Z, 5) GPIO_ACTIVE_HIGH>;
+		sck-gpios = <&gpio0 ASPEED_GPIO(Z, 3) GPIO_ACTIVE_HIGH>;
+		mosi-gpios = <&gpio0 ASPEED_GPIO(Z, 4) GPIO_ACTIVE_HIGH>;
+		miso-gpios = <&gpio0 ASPEED_GPIO(Z, 5) GPIO_ACTIVE_HIGH>;
 		num-chipselects = <1>;
 		cs-gpios = <&gpio0 ASPEED_GPIO(Z, 0) GPIO_ACTIVE_LOW>;
 
-- 
2.43.0



From chou.cosmo at gmail.com  Tue Dec 16 18:39:36 2025
From: chou.cosmo at gmail.com (Cosmo Chou)
Date: Wed, 17 Dec 2025 10:39:36 +0800
Subject: [PATCH v2 3/5] ARM: dts: aspeed: bletchley: Remove unused pca9539 properties
In-Reply-To: <20251217023938.445721-1-chou.cosmo@gmail.com>
References: <20251217023938.445721-1-chou.cosmo@gmail.com>
Message-ID: <20251217023938.445721-4-chou.cosmo@gmail.com>

Remove unused #address-cells and #size-cells properties from
pca9539 nodes to fix dt-schema warnings.

Signed-off-by: Cosmo Chou <chou.cosmo at gmail.com>
---
 .../dts/aspeed/aspeed-bmc-facebook-bletchley.dts     | 12 ------------
 1 file changed, 12 deletions(-)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts
index 5919a5046078..8df145d2bcfd 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts
+++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts
@@ -373,8 +373,6 @@ sled1_ioexp41: pca9536 at 41 {
 	sled1_ioexp: pca9539 at 76 {
 		compatible = "nxp,pca9539";
 		reg = <0x76>;
-		#address-cells = <1>;
-		#size-cells = <0>;
 		gpio-controller;
 		#gpio-cells = <2>;
 
@@ -462,8 +460,6 @@ sled2_ioexp41: pca9536 at 41 {
 	sled2_ioexp: pca9539 at 76 {
 		compatible = "nxp,pca9539";
 		reg = <0x76>;
-		#address-cells = <1>;
-		#size-cells = <0>;
 		gpio-controller;
 		#gpio-cells = <2>;
 
@@ -551,8 +547,6 @@ sled3_ioexp41: pca9536 at 41 {
 	sled3_ioexp: pca9539 at 76 {
 		compatible = "nxp,pca9539";
 		reg = <0x76>;
-		#address-cells = <1>;
-		#size-cells = <0>;
 		gpio-controller;
 		#gpio-cells = <2>;
 
@@ -640,8 +634,6 @@ sled4_ioexp41: pca9536 at 41 {
 	sled4_ioexp: pca9539 at 76 {
 		compatible = "nxp,pca9539";
 		reg = <0x76>;
-		#address-cells = <1>;
-		#size-cells = <0>;
 		gpio-controller;
 		#gpio-cells = <2>;
 
@@ -729,8 +721,6 @@ sled5_ioexp41: pca9536 at 41 {
 	sled5_ioexp: pca9539 at 76 {
 		compatible = "nxp,pca9539";
 		reg = <0x76>;
-		#address-cells = <1>;
-		#size-cells = <0>;
 		gpio-controller;
 		#gpio-cells = <2>;
 
@@ -818,8 +808,6 @@ sled6_ioexp41: pca9536 at 41 {
 	sled6_ioexp: pca9539 at 76 {
 		compatible = "nxp,pca9539";
 		reg = <0x76>;
-		#address-cells = <1>;
-		#size-cells = <0>;
 		gpio-controller;
 		#gpio-cells = <2>;
 
-- 
2.43.0



From chou.cosmo at gmail.com  Tue Dec 16 18:39:37 2025
From: chou.cosmo at gmail.com (Cosmo Chou)
Date: Wed, 17 Dec 2025 10:39:37 +0800
Subject: [PATCH v2 4/5] ARM: dts: aspeed: bletchley: Remove unused i2c13 property
In-Reply-To: <20251217023938.445721-1-chou.cosmo@gmail.com>
References: <20251217023938.445721-1-chou.cosmo@gmail.com>
Message-ID: <20251217023938.445721-5-chou.cosmo@gmail.com>

Remove 'aspeed,hw-timeout-ms' property which is not supported by
the driver and causes dt-schema warnings.

Signed-off-by: Cosmo Chou <chou.cosmo at gmail.com>
---
 arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts | 1 -
 1 file changed, 1 deletion(-)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts
index 8df145d2bcfd..123e2d1891f6 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts
+++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts
@@ -962,7 +962,6 @@ fan_leds: pca9552 at 67 {
 
 &i2c13 {
 	multi-master;
-	aspeed,hw-timeout-ms = <1000>;
 	status = "okay";
 
 	//USB Debug Connector
-- 
2.43.0



From chou.cosmo at gmail.com  Tue Dec 16 18:39:38 2025
From: chou.cosmo at gmail.com (Cosmo Chou)
Date: Wed, 17 Dec 2025 10:39:38 +0800
Subject: [PATCH v2 5/5] ARM: dts: aspeed: bletchley: Fix ADC vref property names
In-Reply-To: <20251217023938.445721-1-chou.cosmo@gmail.com>
References: <20251217023938.445721-1-chou.cosmo@gmail.com>
Message-ID: <20251217023938.445721-6-chou.cosmo@gmail.com>

Replace non-functional 'vref' with 'aspeed,int-vref-microvolt'
using the default 2.5V that the driver was already applying.

Signed-off-by: Cosmo Chou <chou.cosmo at gmail.com>
---
 arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts
index 123e2d1891f6..7c27bf6bb51d 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts
+++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts
@@ -1032,7 +1032,7 @@ &gpio0 {
 };
 
 &adc0 {
-	vref = <1800>;
+	aspeed,int-vref-microvolt = <2500000>;
 	status = "okay";
 
 	pinctrl-names = "default";
@@ -1043,7 +1043,7 @@ &pinctrl_adc4_default &pinctrl_adc5_default
 };
 
 &adc1 {
-	vref = <2500>;
+	aspeed,int-vref-microvolt = <2500000>;
 	status = "okay";
 
 	pinctrl-names = "default";
-- 
2.43.0



From nichen at iscas.ac.cn  Tue Dec 16 18:37:21 2025
From: nichen at iscas.ac.cn (Chen Ni)
Date: Wed, 17 Dec 2025 10:37:21 +0800
Subject: [PATCH] spi: stm32-qspi: Remove unneeded semicolon
Message-ID: <20251217023721.1684244-1-nichen@iscas.ac.cn>

Remove unnecessary semicolons reported by Coccinelle/coccicheck and the
semantic patch at scripts/coccinelle/misc/semicolon.cocci.

Signed-off-by: Chen Ni <nichen at iscas.ac.cn>
---
 drivers/spi/spi-stm32-qspi.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c
index 2a0ee96786fa..d1df66875809 100644
--- a/drivers/spi/spi-stm32-qspi.c
+++ b/drivers/spi/spi-stm32-qspi.c
@@ -153,7 +153,7 @@ static void stm32_qspi_read_fifo(void *val, void __iomem *addr, u8 len)
 		break;
 	case sizeof(u8):
 		*((u8 *)val) = readb_relaxed(addr);
-	};
+	}
 }
 
 static void stm32_qspi_write_fifo(void *val, void __iomem *addr, u8 len)
@@ -167,7 +167,7 @@ static void stm32_qspi_write_fifo(void *val, void __iomem *addr, u8 len)
 		break;
 	case sizeof(u8):
 		writeb_relaxed(*((u8 *)val), addr);
-	};
+	}
 }
 
 static int stm32_qspi_tx_poll(struct stm32_qspi *qspi,
-- 
2.25.1



From damon.ding at rock-chips.com  Tue Dec 16 18:53:27 2025
From: damon.ding at rock-chips.com (Damon Ding)
Date: Wed, 17 Dec 2025 10:53:27 +0800
Subject: [PATCH v7 01/18] drm/display: bridge_connector: Ensure last
 bridge determines EDID/modes detection capabilities
In-Reply-To: <3351986.usQuhbGJ8B@phil>
References: <20251021023130.1523707-1-damon.ding@rock-chips.com>
 <DDNXIYL494D2.2N8L1J7XTBT4S@bootlin.com>
 <ff65f453-68a9-41fc-b9e3-02733bba96e3@rock-chips.com>
 <3351986.usQuhbGJ8B@phil>
Message-ID: <49580dcf-28ec-47e1-83a0-65e16e3d7cdc@rock-chips.com>

Hi Heiko,

On 12/16/2025 9:48 PM, Heiko Stuebner wrote:
> Am Mittwoch, 22. Oktober 2025, 03:15:52 Mitteleurop?ische Normalzeit schrieb Damon Ding:
>> Hi Luca,
>>
>> On 10/21/2025 6:31 PM, Luca Ceresoli wrote:
>>> Hello Damon,
>>>
>>> On Tue Oct 21, 2025 at 4:31 AM CEST, Damon Ding wrote:
> 
>>>
>>> This does not apply on current drm-misc-next, due to the patch I mentioned
>>> in a previous iteration, now applied as commit 2be300f9a0b6 ("drm/display:
>>> bridge_connector: get/put the stored bridges").
>>>
>>> However I'm sorry I have to mention that patch turned out being buggy, so
>>> I've sent a series to apply a corrected version [0]. I suggest watching the
>>> disucssion about the fix series, and if that gets approved rebase on top of
>>> that and adapt your changes.
>>>
>>> Sorry about the mess. :(
>>>
>>> [0] https://lore.kernel.org/r/20251017-drm-bridge-alloc-getput-bridge-connector-fix-hdmi_cec-v2-0-667abf6d47c0 at bootlin.com
>>>
>>>
>>
>> I saw your fix patches before sending this series. I think your patches
>> will likely be merged relatively quickly, so I plan to wait until the
>> other patches in my patch series are confirmed to be fine, then submit
>> v8 version based on the latest bridge_connector driver. :-)
> 
> I think with 6.19-rc1 out, now is a great time for v8? :-)
> 

Agreed! Luca's patches have been merged. I will reconfirm these commits 
on the latest branch and update v8 in a few day. :-)

Best regards,
Damon



From cuiyunhui at bytedance.com  Tue Dec 16 18:55:03 2025
From: cuiyunhui at bytedance.com (yunhui cui)
Date: Wed, 17 Dec 2025 10:55:03 +0800
Subject: [External] Re: [PATCH v6 1/2] watchdog: move arm64 watchdog_hld
 into common code
In-Reply-To: <af5765d2-ba72-481c-8c7a-6fb09fe44709@picoheart.com>
References: <20251114033243.76509-1-cuiyunhui@bytedance.com>
 <20251114033243.76509-2-cuiyunhui@bytedance.com> <af5765d2-ba72-481c-8c7a-6fb09fe44709@picoheart.com>
Message-ID: <CAEEQ3w=c=ooNhDknfaO3_7c72n_fSXQD=WZnuXF5EcDugkgZ5Q@mail.gmail.com>

Hi Yicong,

On Fri, Dec 5, 2025 at 2:53?PM Yicong Yang <yang.yicong at picoheart.com> wrote:
>
> On 2025/11/14 11:32, Yunhui Cui wrote:
> > Move the contents of arch/arm64/watchdog_hld.c to kernel/watchdog_perf.c
> > to create a generic implementation that can be reused by other arch,
> > such as RISC-V.
> >
> > Signed-off-by: Yunhui Cui <cuiyunhui at bytedance.com>
> > Reviewed-by: Douglas Anderson <dianders at chromium.org>
> > ---
> >  arch/arm64/Kconfig               |  1 +
> >  arch/arm64/kernel/Makefile       |  1 -
> >  arch/arm64/kernel/watchdog_hld.c | 94 --------------------------------
> >  drivers/perf/arm_pmu.c           | 10 +++-
> >  include/linux/perf/arm_pmu.h     |  2 -
> >  kernel/watchdog_perf.c           | 83 ++++++++++++++++++++++++++++
> >  lib/Kconfig.debug                |  8 +++
> >  7 files changed, 101 insertions(+), 98 deletions(-)
> >  delete mode 100644 arch/arm64/kernel/watchdog_hld.c
> >
> > diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> > index 6663ffd23f252..6614ff45b1e06 100644
> > --- a/arch/arm64/Kconfig
> > +++ b/arch/arm64/Kconfig
> > @@ -231,6 +231,7 @@ config ARM64
> >       select HAVE_GCC_PLUGINS
> >       select HAVE_HARDLOCKUP_DETECTOR_PERF if PERF_EVENTS && \
> >               HW_PERF_EVENTS && HAVE_PERF_EVENTS_NMI
> > +     select WATCHDOG_PERF_ADJUST_PERIOD if HARDLOCKUP_DETECTOR_PERF
> >       select HAVE_HW_BREAKPOINT if PERF_EVENTS
> >       select HAVE_IOREMAP_PROT
> >       select HAVE_IRQ_TIME_ACCOUNTING
> > diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
> > index 76f32e424065e..12d77f373fea4 100644
> > --- a/arch/arm64/kernel/Makefile
> > +++ b/arch/arm64/kernel/Makefile
> > @@ -44,7 +44,6 @@ obj-$(CONFIG_KUSER_HELPERS)         += kuser32.o
> >  obj-$(CONFIG_FUNCTION_TRACER)                += ftrace.o entry-ftrace.o
> >  obj-$(CONFIG_MODULES)                        += module.o module-plts.o
> >  obj-$(CONFIG_PERF_EVENTS)            += perf_regs.o perf_callchain.o
> > -obj-$(CONFIG_HARDLOCKUP_DETECTOR_PERF)       += watchdog_hld.o
> >  obj-$(CONFIG_HAVE_HW_BREAKPOINT)     += hw_breakpoint.o
> >  obj-$(CONFIG_CPU_PM)                 += sleep.o suspend.o
> >  obj-$(CONFIG_KGDB)                   += kgdb.o
> > diff --git a/arch/arm64/kernel/watchdog_hld.c b/arch/arm64/kernel/watchdog_hld.c
> > deleted file mode 100644
> > index 3093037dcb7be..0000000000000
> > --- a/arch/arm64/kernel/watchdog_hld.c
> > +++ /dev/null
> > @@ -1,94 +0,0 @@
> > -// SPDX-License-Identifier: GPL-2.0
> > -#include <linux/nmi.h>
> > -#include <linux/cpufreq.h>
> > -#include <linux/perf/arm_pmu.h>
> > -
> > -/*
> > - * Safe maximum CPU frequency in case a particular platform doesn't implement
> > - * cpufreq driver. Although, architecture doesn't put any restrictions on
> > - * maximum frequency but 5 GHz seems to be safe maximum given the available
> > - * Arm CPUs in the market which are clocked much less than 5 GHz. On the other
> > - * hand, we can't make it much higher as it would lead to a large hard-lockup
> > - * detection timeout on parts which are running slower (eg. 1GHz on
> > - * Developerbox) and doesn't possess a cpufreq driver.
> > - */
> > -#define SAFE_MAX_CPU_FREQ    5000000000UL // 5 GHz
> > -u64 hw_nmi_get_sample_period(int watchdog_thresh)
> > -{
> > -     unsigned int cpu = smp_processor_id();
> > -     unsigned long max_cpu_freq;
> > -
> > -     max_cpu_freq = cpufreq_get_hw_max_freq(cpu) * 1000UL;
> > -     if (!max_cpu_freq)
> > -             max_cpu_freq = SAFE_MAX_CPU_FREQ;
> > -
> > -     return (u64)max_cpu_freq * watchdog_thresh;
> > -}
> > -
> > -bool __init arch_perf_nmi_is_available(void)
> > -{
> > -     /*
> > -      * hardlockup_detector_perf_init() will success even if Pseudo-NMI turns off,
> > -      * however, the pmu interrupts will act like a normal interrupt instead of
> > -      * NMI and the hardlockup detector would be broken.
> > -      */
> > -     return arm_pmu_irq_is_nmi();
> > -}
> > -
> > -static int watchdog_perf_update_period(void *data)
> > -{
> > -     int cpu = smp_processor_id();
> > -     u64 max_cpu_freq, new_period;
> > -
> > -     max_cpu_freq = cpufreq_get_hw_max_freq(cpu) * 1000UL;
> > -     if (!max_cpu_freq)
> > -             return 0;
> > -
> > -     new_period = watchdog_thresh * max_cpu_freq;
> > -     hardlockup_detector_perf_adjust_period(new_period);
> > -
> > -     return 0;
> > -}
> > -
> > -static int watchdog_freq_notifier_callback(struct notifier_block *nb,
> > -                                        unsigned long val, void *data)
> > -{
> > -     struct cpufreq_policy *policy = data;
> > -     int cpu;
> > -
> > -     if (val != CPUFREQ_CREATE_POLICY)
> > -             return NOTIFY_DONE;
> > -
> > -     /*
> > -      * Let each online CPU related to the policy update the period by their
> > -      * own. This will serialize with the framework on start/stop the lockup
> > -      * detector (softlockup_{start,stop}_all) and avoid potential race
> > -      * condition. Otherwise we may have below theoretical race condition:
> > -      * (core 0/1 share the same policy)
> > -      * [core 0]                      [core 1]
> > -      *                               hardlockup_detector_event_create()
> > -      *                                 hw_nmi_get_sample_period()
> > -      * (cpufreq registered, notifier callback invoked)
> > -      * watchdog_freq_notifier_callback()
> > -      *   watchdog_perf_update_period()
> > -      *   (since core 1's event's not yet created,
> > -      *    the period is not set)
> > -      *                                 perf_event_create_kernel_counter()
> > -      *                                 (event's period is SAFE_MAX_CPU_FREQ)
> > -      */
> > -     for_each_cpu(cpu, policy->cpus)
> > -             smp_call_on_cpu(cpu, watchdog_perf_update_period, NULL, false);
> > -
> > -     return NOTIFY_DONE;
> > -}
> > -
> > -static struct notifier_block watchdog_freq_notifier = {
> > -     .notifier_call = watchdog_freq_notifier_callback,
> > -};
> > -
> > -static int __init init_watchdog_freq_notifier(void)
> > -{
> > -     return cpufreq_register_notifier(&watchdog_freq_notifier,
> > -                                      CPUFREQ_POLICY_NOTIFIER);
> > -}
> > -core_initcall(init_watchdog_freq_notifier);
> > diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
> > index 973a027d90639..294a5c3438ad1 100644
> > --- a/drivers/perf/arm_pmu.c
> > +++ b/drivers/perf/arm_pmu.c
> > @@ -17,6 +17,7 @@
> >  #include <linux/cpu_pm.h>
> >  #include <linux/export.h>
> >  #include <linux/kernel.h>
> > +#include <linux/nmi.h>
> >  #include <linux/perf/arm_pmu.h>
> >  #include <linux/slab.h>
> >  #include <linux/sched/clock.h>
> > @@ -703,10 +704,17 @@ static int armpmu_get_cpu_irq(struct arm_pmu *pmu, int cpu)
> >       return per_cpu(hw_events->irq, cpu);
> >  }
> >
> > -bool arm_pmu_irq_is_nmi(void)
> > +#ifdef CONFIG_HARDLOCKUP_DETECTOR_PERF
> > +bool arch_perf_nmi_is_available(void)
> >  {
> > +     /*
> > +      * watchdog_hardlockup_probe() will success even if Pseudo-NMI turns off,
> > +      * however, the pmu interrupts will act like a normal interrupt instead of
> > +      * NMI and the hardlockup detector would be broken.
> > +      */
>
> the comment makes me a bit confused. we'll only declare the NMI support if we successfully
> registered the PMU interrupt as NMI interrupt. If pseudo-nmi is turned off, we'll
> failed to register the NMI interrupt since neither the gicv3 irqchip will declare NMI
> suppport [1] nor the irq_chip::irq_nmi_setup() will success [2], then the has_nmi will
> be false. In this case the hardlockup detector is not probed at all [3].
>
> [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/irqchip/irq-gic-v3.c#n1956
> [2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/irqchip/irq-gic-v3.c#n602
> [3] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/kernel/watchdog_perf.c#n268

This patch does not modify this part of the logic itself.

>
> >       return has_nmi;
> >  }
> > +#endif
> >
> >  /*
> >   * PMU hardware loses all context when a CPU goes offline.
> > diff --git a/include/linux/perf/arm_pmu.h b/include/linux/perf/arm_pmu.h
> > index 52b37f7bdbf9e..8f06751f1e176 100644
> > --- a/include/linux/perf/arm_pmu.h
> > +++ b/include/linux/perf/arm_pmu.h
> > @@ -183,8 +183,6 @@ void kvm_host_pmu_init(struct arm_pmu *pmu);
> >  #define kvm_host_pmu_init(x) do { } while(0)
> >  #endif
> >
> > -bool arm_pmu_irq_is_nmi(void);
> > -
> >  /* Internal functions only for core arm_pmu code */
> >  struct arm_pmu *armpmu_alloc(void);
> >  void armpmu_free(struct arm_pmu *pmu);
> > diff --git a/kernel/watchdog_perf.c b/kernel/watchdog_perf.c
> > index d3ca70e3c256a..8aa5e9a0ba20a 100644
> > --- a/kernel/watchdog_perf.c
> > +++ b/kernel/watchdog_perf.c
> > @@ -15,6 +15,7 @@
> >  #include <linux/panic.h>
> >  #include <linux/nmi.h>
> >  #include <linux/atomic.h>
> > +#include <linux/cpufreq.h>
> >  #include <linux/module.h>
> >  #include <linux/sched/debug.h>
> >
> > @@ -306,3 +307,85 @@ void __init hardlockup_config_perf_event(const char *str)
> >       wd_hw_attr.type = PERF_TYPE_RAW;
> >       wd_hw_attr.config = config;
> >  }
> > +
> > +#ifdef CONFIG_WATCHDOG_PERF_ADJUST_PERIOD
> > +/*
> > + * Safe maximum CPU frequency in case a particular platform doesn't implement
> > + * cpufreq driver. Although, architecture doesn't put any restrictions on
> > + * maximum frequency but 5 GHz seems to be safe maximum given the available
> > + * CPUs in the market which are clocked much less than 5 GHz. On the other
> > + * hand, we can't make it much higher as it would lead to a large hard-lockup
> > + * detection timeout on parts which are running slower (eg. 1GHz on
> > + * Developerbox) and doesn't possess a cpufreq driver.
> > + */
> > +#define SAFE_MAX_CPU_FREQ    5000000000UL // 5 GHz
> > +u64 hw_nmi_get_sample_period(int watchdog_thresh)
> > +{
> > +     unsigned int cpu = smp_processor_id();
> > +     unsigned long max_cpu_freq;
> > +
> > +     max_cpu_freq = cpufreq_get_hw_max_freq(cpu) * 1000UL;
> > +     if (!max_cpu_freq)
> > +             max_cpu_freq = SAFE_MAX_CPU_FREQ;
> > +
> > +     return (u64)max_cpu_freq * watchdog_thresh;
> > +}
> > +
> > +static int watchdog_perf_update_period(void *data)
> > +{
> > +     int cpu = smp_processor_id();
> > +     u64 max_cpu_freq, new_period;
> > +
> > +     max_cpu_freq = cpufreq_get_hw_max_freq(cpu) * 1000UL;
> > +     if (!max_cpu_freq)
> > +             return 0;
> > +
> > +     new_period = watchdog_thresh * max_cpu_freq;
> > +     hardlockup_detector_perf_adjust_period(new_period);
> > +
> > +     return 0;
> > +}
> > +
> > +static int watchdog_freq_notifier_callback(struct notifier_block *nb,
> > +                                        unsigned long val, void *data)
> > +{
> > +     struct cpufreq_policy *policy = data;
> > +     int cpu;
> > +
> > +     if (val != CPUFREQ_CREATE_POLICY)
> > +             return NOTIFY_DONE;
> > +
> > +     /*
> > +      * Let each online CPU related to the policy update the period by their
> > +      * own. This will serialize with the framework on start/stop the lockup
> > +      * detector (softlockup_{start,stop}_all) and avoid potential race
> > +      * condition. Otherwise we may have below theoretical race condition:
> > +      * (core 0/1 share the same policy)
> > +      * [core 0]                      [core 1]
> > +      *                               hardlockup_detector_event_create()
> > +      *                                 hw_nmi_get_sample_period()
> > +      * (cpufreq registered, notifier callback invoked)
> > +      * watchdog_freq_notifier_callback()
> > +      *   watchdog_perf_update_period()
> > +      *   (since core 1's event's not yet created,
> > +      *    the period is not set)
> > +      *                                 perf_event_create_kernel_counter()
> > +      *                                 (event's period is SAFE_MAX_CPU_FREQ)
> > +      */
> > +     for_each_cpu(cpu, policy->cpus)
> > +             smp_call_on_cpu(cpu, watchdog_perf_update_period, NULL, false);
> > +
> > +     return NOTIFY_DONE;
> > +}
> > +
> > +static struct notifier_block watchdog_freq_notifier = {
> > +     .notifier_call = watchdog_freq_notifier_callback,
> > +};
> > +
> > +static int __init init_watchdog_freq_notifier(void)
> > +{
> > +     return cpufreq_register_notifier(&watchdog_freq_notifier,
> > +                                      CPUFREQ_POLICY_NOTIFIER);
> > +}
> > +core_initcall(init_watchdog_freq_notifier);
> > +#endif
> > diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> > index 2cbfa3dead0be..85fdfa9b52346 100644
> > --- a/lib/Kconfig.debug
> > +++ b/lib/Kconfig.debug
> > @@ -1193,6 +1193,14 @@ config HARDLOCKUP_DETECTOR_PERF
> >       depends on !HAVE_HARDLOCKUP_DETECTOR_ARCH
> >       select HARDLOCKUP_DETECTOR_COUNTS_HRTIMER
> >
> > +config WATCHDOG_PERF_ADJUST_PERIOD
> > +     bool
>
> it's reasonable to make it depends on HARDLOCKUP_DETECTOR_PERF.

In arch/(arm64|riscv)/Kconfig, there is the configuration line:
select WATCHDOG_PERF_ADJUST_PERIOD if HARDLOCKUP_DETECTOR_PERF

>
> otherwise looks good to me :)
>
> Thanks.
>
> > +     help
> > +       Adjust the watchdog hardlockup detector's period based on CPU max
> > +       frequency. Uses cpufreq if available; falls back to a safe 5 GHz
> > +       default otherwise. Registers a cpufreq notifier to update the period
> > +       automatically.
> > +
> >  config HARDLOCKUP_DETECTOR_BUDDY
> >       bool
> >       depends on HARDLOCKUP_DETECTOR


Thanks,
Yunhui


From cuiyunhui at bytedance.com  Tue Dec 16 18:59:57 2025
From: cuiyunhui at bytedance.com (yunhui cui)
Date: Wed, 17 Dec 2025 10:59:57 +0800
Subject: [External] Re: [PATCH v6 2/2] riscv: add HARDLOCKUP_DETECTOR_PERF support
In-Reply-To: <96fd2a69-baf4-4109-8341-0d4bb6c60393@picoheart.com>
References: <20251114033243.76509-1-cuiyunhui@bytedance.com>
 <20251114033243.76509-3-cuiyunhui@bytedance.com> <96fd2a69-baf4-4109-8341-0d4bb6c60393@picoheart.com>
Message-ID: <CAEEQ3wkq5P=WE_XsPDFOK5ESZDP6igQ9dAcN7Bd6-LkEv7N17g@mail.gmail.com>

Hi Yicong,

On Fri, Dec 5, 2025 at 2:12?PM Yicong Yang <yang.yicong at picoheart.com> wrote:
>
> Hi Yunhui,
>
> this has conflicts on the mainline master. looks like you have a dependency
> on the SSE PMU support patchset [1], need to mention it for the maintainer
> to apply.
>
> [1] https://lore.kernel.org/linux-riscv/20250908181717.1997461-5-cleger at rivosinc.com/
>
> one comment below.
>
> On 2025/11/14 11:32, Yunhui Cui wrote:
> > Enable the HARDLOCKUP_DETECTOR_PERF function based on RISC-V SSE.
> >
> > Signed-off-by: Yunhui Cui <cuiyunhui at bytedance.com>
> > Reviewed-by: Douglas Anderson <dianders at chromium.org>
> > Acked-by: Paul Walmsley <pjw at kernel.org>
> > ---
> >  arch/riscv/Kconfig           |  3 +++
> >  drivers/perf/riscv_pmu_sbi.c | 10 ++++++++++
> >  2 files changed, 13 insertions(+)
> >
> > diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
> > index fadec20b87a8e..46ccd33732fa8 100644
> > --- a/arch/riscv/Kconfig
> > +++ b/arch/riscv/Kconfig
> > @@ -186,6 +186,9 @@ config RISCV
> >       select HAVE_PAGE_SIZE_4KB
> >       select HAVE_PCI
> >       select HAVE_PERF_EVENTS
> > +     select HAVE_PERF_EVENTS_NMI if RISCV_PMU_SBI_SSE
> > +     select HAVE_HARDLOCKUP_DETECTOR_PERF if PERF_EVENTS && HAVE_PERF_EVENTS_NMI
> > +     select WATCHDOG_PERF_ADJUST_PERIOD if HARDLOCKUP_DETECTOR_PERF
> >       select HAVE_PERF_REGS
> >       select HAVE_PERF_USER_STACK_DUMP
> >       select HAVE_POSIX_CPU_TIMERS_TASK_WORK
> > diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
> > index c852f64a50221..0c7c5924687c9 100644
> > --- a/drivers/perf/riscv_pmu_sbi.c
> > +++ b/drivers/perf/riscv_pmu_sbi.c
> > @@ -22,6 +22,7 @@
> >  #include <linux/sched/clock.h>
> >  #include <linux/soc/andes/irq.h>
> >  #include <linux/workqueue.h>
> > +#include <linux/nmi.h>
> >
> >  #include <asm/errata_list.h>
> >  #include <asm/sbi.h>
> > @@ -1192,6 +1193,13 @@ static int pmu_sbi_setup_sse(struct riscv_pmu *pmu)
> >  }
> >  #endif
> >
> > +#ifdef CONFIG_HARDLOCKUP_DETECTOR_PERF
> > +bool arch_perf_nmi_is_available(void)
> > +{
> > +     return IS_ENABLED(CONFIG_RISCV_PMU_SBI_SSE);
>
> this looks incorrect per implementation in [1]. we'll fallback to the normal
> interrupt if failed to register the SSE event, in which case NMI is not
> available for the PMU. Check the kconfig is not sufficient.
>
> you can check pmu->sse_evt instead for the NMI support here, or cached the
> NMI status somewhere like how arm_pmu does.
>
> Thanks.
>

Well, based on CONFIG_RISCV_PMU_SBI_SSE, further check registration success.

> > +}
> > +#endif
> > +
> >  static int pmu_sbi_starting_cpu(unsigned int cpu, struct hlist_node *node)
> >  {
> >       struct riscv_pmu *pmu = hlist_entry_safe(node, struct riscv_pmu, node);
> > @@ -1618,6 +1626,8 @@ static int __init pmu_sbi_devinit(void)
> >       /* Notify legacy implementation that SBI pmu is available*/
> >       riscv_pmu_legacy_skip_init();
> >
> > +     lockup_detector_retry_init();
> > +
> >       return ret;
> >  }
> >  device_initcall(pmu_sbi_devinit)

Thanks,
Yunhui


From ming.qian at oss.nxp.com  Tue Dec 16 19:02:20 2025
From: ming.qian at oss.nxp.com (ming.qian at oss.nxp.com)
Date: Wed, 17 Dec 2025 11:02:20 +0800
Subject: [PATCH v4 0/3] Trigger dynamic source change for colorspace
Message-ID: <20251217030227.1546-1-ming.qian@oss.nxp.com>

From: Ming Qian <ming.qian at oss.nxp.com>

If colorspace changes, the client needs to renegotiate the pipeline,
otherwise the decoded frame may not be displayed correctly.

A change in colorspace triggers a source change, allowing the client to
detect the specific reason and decide whether request buffer
reallocation.

Change logs:
v4
- Drop V4L2_EVENT_SRC_CH_COLORSPACE, to avoid backward compatibility
  issues.
- Add cover-leter

v3
- Improve the description according to comments

v2
- Add V4L2_EVENT_SRC_CH_COLORSPACE for colorspace source change event

Ming Qian (3):
  media: docs: dev-decoder: Trigger dynamic source change for colorspace
  media: amphion: Clear last_buffer_dequeued flag for DEC_CMD_START
  media: amphion: Trigger source change if colorspace changed

 .../userspace-api/media/v4l/dev-decoder.rst   |  5 +-
 drivers/media/platform/amphion/vdec.c         | 62 ++++++++++++-------
 drivers/media/platform/amphion/vpu_v4l2.c     |  1 -
 3 files changed, 45 insertions(+), 23 deletions(-)


base-commit: f7231cff1f3ff8259bef02dc4999bc132abf29cf
prerequisite-patch-id: 0000000000000000000000000000000000000000
prerequisite-patch-id: f33b49b7c9c245b32701d1a6e8250da297ccc39b
-- 
2.52.0



From ming.qian at oss.nxp.com  Tue Dec 16 19:02:21 2025
From: ming.qian at oss.nxp.com (ming.qian at oss.nxp.com)
Date: Wed, 17 Dec 2025 11:02:21 +0800
Subject: [PATCH v4 1/3] media: docs: dev-decoder: Trigger dynamic source change for colorspace
In-Reply-To: <20251217030227.1546-1-ming.qian@oss.nxp.com>
References: <20251217030227.1546-1-ming.qian@oss.nxp.com>
Message-ID: <20251217030227.1546-2-ming.qian@oss.nxp.com>

From: Ming Qian <ming.qian at oss.nxp.com>

If colorspace changes, the client needs to renegotiate the pipeline,
otherwise the decoded frame may not be displayed correctly.

So add colorspace as a trigger parameter for dynamic resolution change.

Signed-off-by: Ming Qian <ming.qian at oss.nxp.com>
---
 Documentation/userspace-api/media/v4l/dev-decoder.rst | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Documentation/userspace-api/media/v4l/dev-decoder.rst b/Documentation/userspace-api/media/v4l/dev-decoder.rst
index eb662ced0ab4..2beb6ba1b3c2 100644
--- a/Documentation/userspace-api/media/v4l/dev-decoder.rst
+++ b/Documentation/userspace-api/media/v4l/dev-decoder.rst
@@ -933,7 +933,10 @@ reflected by corresponding queries):
 
 * the minimum number of buffers needed for decoding,
 
-* bit-depth of the bitstream has been changed.
+* bit-depth of the bitstream has been changed,
+
+* colorspace of the bitstream has been changed, but it doesn't require
+  buffer reallocation.
 
 Whenever that happens, the decoder must proceed as follows:
 
-- 
2.52.0



From ming.qian at oss.nxp.com  Tue Dec 16 19:02:22 2025
From: ming.qian at oss.nxp.com (ming.qian at oss.nxp.com)
Date: Wed, 17 Dec 2025 11:02:22 +0800
Subject: [PATCH v4 2/3] media: amphion: Clear last_buffer_dequeued flag for DEC_CMD_START
In-Reply-To: <20251217030227.1546-1-ming.qian@oss.nxp.com>
References: <20251217030227.1546-1-ming.qian@oss.nxp.com>
Message-ID: <20251217030227.1546-3-ming.qian@oss.nxp.com>

From: Ming Qian <ming.qian at oss.nxp.com>

The V4L2_DEC_CMD_START command may be used to handle the dynamic source
change, which will triggers an implicit decoder drain.
The last_buffer_dequeued flag is set in the implicit decoder drain,
so driver need to clear it to continue the following decoding flow.

Signed-off-by: Ming Qian <ming.qian at oss.nxp.com>
---
 drivers/media/platform/amphion/vdec.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/media/platform/amphion/vdec.c b/drivers/media/platform/amphion/vdec.c
index c0d2aabb9e0e..f25dbcebdccf 100644
--- a/drivers/media/platform/amphion/vdec.c
+++ b/drivers/media/platform/amphion/vdec.c
@@ -724,6 +724,7 @@ static int vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd
 	switch (cmd->cmd) {
 	case V4L2_DEC_CMD_START:
 		vdec_cmd_start(inst);
+		vb2_clear_last_buffer_dequeued(v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx));
 		break;
 	case V4L2_DEC_CMD_STOP:
 		vdec_cmd_stop(inst);
-- 
2.52.0



From ming.qian at oss.nxp.com  Tue Dec 16 19:02:23 2025
From: ming.qian at oss.nxp.com (ming.qian at oss.nxp.com)
Date: Wed, 17 Dec 2025 11:02:23 +0800
Subject: [PATCH v4 3/3] media: amphion: Trigger source change if colorspace changed
In-Reply-To: <20251217030227.1546-1-ming.qian@oss.nxp.com>
References: <20251217030227.1546-1-ming.qian@oss.nxp.com>
Message-ID: <20251217030227.1546-4-ming.qian@oss.nxp.com>

From: Ming Qian <ming.qian at oss.nxp.com>

After encountering a colorspace change in the stream, the decoder
sends a V4L2_EVENT_SOURCE_CHANGE event with changes set to
V4L2_EVENT_SRC_CH_RESOLUTION.

Then the client can detect and handle the colorspace change without any
buffer reallocation

Signed-off-by: Ming Qian <ming.qian at oss.nxp.com>
---
 drivers/media/platform/amphion/vdec.c     | 61 +++++++++++++++--------
 drivers/media/platform/amphion/vpu_v4l2.c |  1 -
 2 files changed, 40 insertions(+), 22 deletions(-)

diff --git a/drivers/media/platform/amphion/vdec.c b/drivers/media/platform/amphion/vdec.c
index f25dbcebdccf..beeaf75c76b4 100644
--- a/drivers/media/platform/amphion/vdec.c
+++ b/drivers/media/platform/amphion/vdec.c
@@ -950,7 +950,7 @@ static void vdec_stop_done(struct vpu_inst *inst)
 	vpu_inst_unlock(inst);
 }
 
-static bool vdec_check_source_change(struct vpu_inst *inst)
+static bool vdec_check_source_change(struct vpu_inst *inst, struct vpu_dec_codec_info *hdr)
 {
 	struct vdec_t *vdec = inst->priv;
 	const struct vpu_format *sibling;
@@ -962,26 +962,35 @@ static bool vdec_check_source_change(struct vpu_inst *inst)
 		return false;
 
 	sibling = vpu_helper_find_sibling(inst, inst->cap_format.type, inst->cap_format.pixfmt);
-	if (sibling && vdec->codec_info.pixfmt == sibling->pixfmt)
-		vdec->codec_info.pixfmt = inst->cap_format.pixfmt;
+	if (sibling && hdr->pixfmt == sibling->pixfmt)
+		hdr->pixfmt = inst->cap_format.pixfmt;
 
 	if (!vb2_is_streaming(v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx)))
 		return true;
-	if (inst->cap_format.pixfmt != vdec->codec_info.pixfmt)
+	if (inst->cap_format.pixfmt != hdr->pixfmt)
 		return true;
-	if (inst->cap_format.width != vdec->codec_info.decoded_width)
+	if (inst->cap_format.width != hdr->decoded_width)
 		return true;
-	if (inst->cap_format.height != vdec->codec_info.decoded_height)
+	if (inst->cap_format.height != hdr->decoded_height)
 		return true;
 	if (vpu_get_num_buffers(inst, inst->cap_format.type) < inst->min_buffer_cap)
 		return true;
-	if (inst->crop.left != vdec->codec_info.offset_x)
+	if (inst->crop.left != hdr->offset_x)
 		return true;
-	if (inst->crop.top != vdec->codec_info.offset_y)
+	if (inst->crop.top != hdr->offset_y)
 		return true;
-	if (inst->crop.width != vdec->codec_info.width)
+	if (inst->crop.width != hdr->width)
 		return true;
-	if (inst->crop.height != vdec->codec_info.height)
+	if (inst->crop.height != hdr->height)
+		return true;
+	if (!hdr->progressive)
+		return true;
+
+	if (vdec->seq_hdr_found &&
+	    (hdr->color_primaries != vdec->codec_info.color_primaries ||
+	     hdr->transfer_chars != vdec->codec_info.transfer_chars ||
+	     hdr->matrix_coeffs != vdec->codec_info.matrix_coeffs ||
+	     hdr->full_range != vdec->codec_info.full_range))
 		return true;
 
 	return false;
@@ -1333,20 +1342,25 @@ static void vdec_event_seq_hdr(struct vpu_inst *inst, struct vpu_dec_codec_info
 	struct vdec_t *vdec = inst->priv;
 
 	vpu_inst_lock(inst);
-	memcpy(&vdec->codec_info, hdr, sizeof(vdec->codec_info));
 
-	vpu_trace(inst->dev, "[%d] %d x %d, crop : (%d, %d) %d x %d, %d, %d\n",
+	vpu_trace(inst->dev,
+		  "[%d] %d x %d, crop : (%d, %d) %d x %d, %d, %d, colorspace: %d, %d, %d, %d\n",
 		  inst->id,
-		  vdec->codec_info.decoded_width,
-		  vdec->codec_info.decoded_height,
-		  vdec->codec_info.offset_x,
-		  vdec->codec_info.offset_y,
-		  vdec->codec_info.width,
-		  vdec->codec_info.height,
+		  hdr->decoded_width,
+		  hdr->decoded_height,
+		  hdr->offset_x,
+		  hdr->offset_y,
+		  hdr->width,
+		  hdr->height,
 		  hdr->num_ref_frms,
-		  hdr->num_dpb_frms);
+		  hdr->num_dpb_frms,
+		  hdr->color_primaries,
+		  hdr->transfer_chars,
+		  hdr->matrix_coeffs,
+		  hdr->full_range);
 	inst->min_buffer_cap = hdr->num_ref_frms + hdr->num_dpb_frms;
-	vdec->is_source_changed = vdec_check_source_change(inst);
+	vdec->is_source_changed = vdec_check_source_change(inst, hdr);
+	memcpy(&vdec->codec_info, hdr, sizeof(vdec->codec_info));
 	vdec_init_fmt(inst);
 	vdec_init_crop(inst);
 	vdec_init_mbi(inst);
@@ -1375,7 +1389,12 @@ static void vdec_event_resolution_change(struct vpu_inst *inst)
 {
 	struct vdec_t *vdec = inst->priv;
 
-	vpu_trace(inst->dev, "[%d]\n", inst->id);
+	vpu_trace(inst->dev, "[%d] input : %d, decoded : %d, display : %d, sequence : %d\n",
+		  inst->id,
+		  vdec->params.frame_count,
+		  vdec->decoded_frame_count,
+		  vdec->display_frame_count,
+		  vdec->sequence);
 	vpu_inst_lock(inst);
 	vdec->seq_tag = vdec->codec_info.tag;
 	vdec_clear_fs(&vdec->mbi);
diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c
index 47dff9a35bb4..121165a7184f 100644
--- a/drivers/media/platform/amphion/vpu_v4l2.c
+++ b/drivers/media/platform/amphion/vpu_v4l2.c
@@ -102,7 +102,6 @@ static int vpu_notify_eos(struct vpu_inst *inst)
 int vpu_notify_source_change(struct vpu_inst *inst)
 {
 	static const struct v4l2_event ev = {
-		.id = 0,
 		.type = V4L2_EVENT_SOURCE_CHANGE,
 		.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION
 	};
-- 
2.52.0



From baolin.wang at linux.alibaba.com  Tue Dec 16 19:11:35 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Wed, 17 Dec 2025 11:11:35 +0800
Subject: [PATCH v2 3/3] mm: rmap: support batched unmapping for file large
 folios
In-Reply-To: <e718cfdd-a39f-48f6-98c8-f17683f29bcf@lucifer.local>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <af330c9ea188bd0f28189b1e6e5803f6de9d2abe.1765439381.git.baolin.wang@linux.alibaba.com>
 <70d1dedc-b4fc-4eb6-baf6-9e54b6a62249@lucifer.local>
 <eb871ca2-47c8-4b10-a61d-321716f6c147@linux.alibaba.com>
 <CAGsJ_4xp40A3u=N5_mw00Eo6bPmFvctD3j=1Qmy3vOo2EmX3hA@mail.gmail.com>
 <9e038290-70ff-458d-b46d-bc512c3442be@linux.alibaba.com>
 <e718cfdd-a39f-48f6-98c8-f17683f29bcf@lucifer.local>
Message-ID: <8bfcae1c-74a0-43e8-807b-fff22a770241@linux.alibaba.com>



On 2025/12/16 18:54, Lorenzo Stoakes wrote:
> On Tue, Dec 16, 2025 at 02:22:11PM +0800, Baolin Wang wrote:
>>
>>
>> On 2025/12/16 14:13, Barry Song wrote:
>>>>>>
>>>>>> diff --git a/mm/rmap.c b/mm/rmap.c
>>>>>> index ec232165c47d..4c9d5777c8da 100644
>>>>>> --- a/mm/rmap.c
>>>>>> +++ b/mm/rmap.c
>>>>>> @@ -1855,9 +1855,10 @@ static inline unsigned int folio_unmap_pte_batch(struct folio *folio,
>>>>>>        end_addr = pmd_addr_end(addr, vma->vm_end);
>>>>>>        max_nr = (end_addr - addr) >> PAGE_SHIFT;
>>>>>>
>>>>>> -    /* We only support lazyfree batching for now ... */
>>>>>> -    if (!folio_test_anon(folio) || folio_test_swapbacked(folio))
>>>>>> +    /* We only support lazyfree or file folios batching for now ... */
>>>>>> +    if (folio_test_anon(folio) && folio_test_swapbacked(folio))
>>>>>
>>>>> Why is it now ok to support file-backed batched unmapping when it wasn't in
>>>>> Barry's series (see [0])? You don't seem to be justifying this?
>>>>
>>>> Barry's series[0] is merely aimed at optimizing lazyfree anonymous large
>>>> folios and does not continue to optimize anonymous large folios or
>>>> file-backed large folios at that point.
>>>
>>> Yep. At that time, I didn?t have an Android machine with a filesystem
>>> that supported large folios, so I focused on lazyfree. But I
>>> agree that lazyfree anon folios and file folios are quite
>>> similar.
>>>
>>>>
>>>> Subsequently, Barry sent out a new patch (see [1]) to optimize anonymous
>>>> large folios. As for file-backed large folios, the batched unmapping
>>>> support is relatively simple, since we only need to clear the PTE
>>>> entries for file-backed large folios.
>>>
>>> Yep. It is actually quite straightforward to go from lazyfree
>>> anon folios to file folios. Swap-backed anon folios are much
>>> more tricky, though.
>>
>> Agree. Thanks Barry for reviewing and confirming.
> 
> OK that makes me less concerned, but you do need to put some more justification
> in the commit message.

Sure. Will do.


From baolin.wang at linux.alibaba.com  Tue Dec 16 19:53:31 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Wed, 17 Dec 2025 11:53:31 +0800
Subject: [PATCH v2 1/3] arm64: mm: support batch clearing of the young
 flag for large folios
In-Reply-To: <671ac450-4a59-4e26-b098-7cf65add1e75@lucifer.local>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <e10f876ce130134fa089befe83f30561b48b9889.1765439380.git.baolin.wang@linux.alibaba.com>
 <5039c6a2-09b6-4c9b-accb-26583ba120db@lucifer.local>
 <1a0001cd-c38d-403b-b3ef-d19e85acd772@linux.alibaba.com>
 <671ac450-4a59-4e26-b098-7cf65add1e75@lucifer.local>
Message-ID: <37915af9-d307-4955-969e-c16ea26f7f4a@linux.alibaba.com>



On 2025/12/16 19:11, Lorenzo Stoakes wrote:
> On Tue, Dec 16, 2025 at 11:32:58AM +0800, Baolin Wang wrote:
>>
>>
>> On 2025/12/15 19:36, Lorenzo Stoakes wrote:
>>> On Thu, Dec 11, 2025 at 04:16:54PM +0800, Baolin Wang wrote:
>>>> Currently, contpte_ptep_test_and_clear_young() and contpte_ptep_clear_flush_young()
>>>> only clear the young flag and flush TLBs for PTEs within the contiguous range.
>>>> To support batch PTE operations for other sized large folios in the following
>>>> patches, adding a new parameter to specify the number of PTEs.
>>>>
>>>> While we are at it, rename the functions to maintain consistency with other
>>>> contpte_*() functions.
>>>>
>>>> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
>>>> ---
>>>>    arch/arm64/include/asm/pgtable.h | 12 ++++-----
>>>>    arch/arm64/mm/contpte.c          | 44 ++++++++++++++++++++++----------
>>>>    2 files changed, 37 insertions(+), 19 deletions(-)
>>>>
>>>> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
>>>> index 0944e296dd4a..e03034683156 100644
>>>> --- a/arch/arm64/include/asm/pgtable.h
>>>> +++ b/arch/arm64/include/asm/pgtable.h
>>>> @@ -1679,10 +1679,10 @@ extern void contpte_clear_full_ptes(struct mm_struct *mm, unsigned long addr,
>>>>    extern pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
>>>>    				unsigned long addr, pte_t *ptep,
>>>>    				unsigned int nr, int full);
>>>> -extern int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
>>>> -				unsigned long addr, pte_t *ptep);
>>>> -extern int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
>>>> -				unsigned long addr, pte_t *ptep);
>>>> +extern int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
>>>> +				unsigned long addr, pte_t *ptep, unsigned int nr);
>>>> +extern int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
>>>> +				unsigned long addr, pte_t *ptep, unsigned int nr);
>>>
>>> In core mm at least, as a convention, we strip 'extern' from header declarations
>>> as we go as they're not necessary.
>>
>> Sure. I can remove the 'extern'.
> 
> Thanks.
> 
>>
>>> I wonder about this naming convention also. The contpte_xxx_() prefix
>>> obviously implies we are operating upon PTEs in the contiguous range, now
>>> we are doing something... different and 'nr' is a bit vague.
>>>
>>> Is it the nr of contiguous ranges? Well in reality it's nr_pages right? But
>>
>> Yes, 'nr' here means nr_pages, which follows the convention of the
>> parameters in contpte_xxx_() functions.
> 
> Except you're violating the convention already by doing non-contpte stuff in
> contpte functions?

Nope. Sorry for my poor English, which might have caused some confusion. 
I followed the contpte's convention, and let me try to explain it again 
below.

> The confusion is between nr of contpte ranges and nr of pages, so I think we
> should be explicit.
> 
>>
>>> now we're not saying they're necessarily contiguous in the sense of contpte...
>>>
>>> I wonder whether we'd be better off introducing a new function that
>>> explicitly has 'batch' or 'batched' in the name, and have the usual
>>> contpte_***() stuff and callers that need batching using a new underlying helper?
>>
>> OK. I get your point. However, this is outside the scope of my patchset.
> 
> Well, no, this is review feedback that needs to be addressed, I really don't
> like this patch as-is.
> 
> So for this to be upstreamable you really need to separate this out.
> 
>>
>> Perhaps we can clean up all the contpte_xxx_() functions if everyone agrees
>> that this is confusing.
> 
> I mean, unless Ryan explicitly makes a case for this being fine, I'm inclined to
> reject the patch unless we do this.
> 
> The contpte logic is already very confusing, and this is only adding to it.
> 
>>
>>> Obviously I defer to Ryan on all this, just my thoughts...
>>>
>>>>    extern void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
>>>>    				pte_t *ptep, unsigned int nr);
>>>>    extern int contpte_ptep_set_access_flags(struct vm_area_struct *vma,
>>>> @@ -1854,7 +1854,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
>>>>    	if (likely(!pte_valid_cont(orig_pte)))
>>>>    		return __ptep_test_and_clear_young(vma, addr, ptep);
>>>>
>>>> -	return contpte_ptep_test_and_clear_young(vma, addr, ptep);
>>>> +	return contpte_test_and_clear_young_ptes(vma, addr, ptep, CONT_PTES);
>>>>    }
>>>>
>>>>    #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
>>>> @@ -1866,7 +1866,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
>>>>    	if (likely(!pte_valid_cont(orig_pte)))
>>>>    		return __ptep_clear_flush_young(vma, addr, ptep);
>>>>
>>>> -	return contpte_ptep_clear_flush_young(vma, addr, ptep);
>>>> +	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
>>>>    }
>>>>
>>>>    #define wrprotect_ptes wrprotect_ptes
>>>> diff --git a/arch/arm64/mm/contpte.c b/arch/arm64/mm/contpte.c
>>>> index c0557945939c..19b122441be3 100644
>>>> --- a/arch/arm64/mm/contpte.c
>>>> +++ b/arch/arm64/mm/contpte.c
>>>> @@ -488,8 +488,9 @@ pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
>>>>    }
>>>>    EXPORT_SYMBOL_GPL(contpte_get_and_clear_full_ptes);
>>>>
>>>> -int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
>>>> -					unsigned long addr, pte_t *ptep)
>>>> +int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
>>>> +					unsigned long addr, pte_t *ptep,
>>>> +					unsigned int nr)
>>>>    {
>>>>    	/*
>>>>    	 * ptep_clear_flush_young() technically requires us to clear the access
>>>> @@ -500,39 +501,56 @@ int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
>>>>    	 * having to unfold.
>>>>    	 */
>>>
>>> Hmm shouldn't you need to update this comment now 'nr' is a thing? E.g.:
>>>
>>> "And since we only create a contig range when the range is covered by a single
>>> folio, we can get away with clearing young for the whole contig range here, so
>>> we avoid having to unfold."
>>
>> I think the original comments are still clear:
>> "
>> /*
>>   * ptep_clear_flush_young() technically requires us to clear the access
>>   * flag for a _single_ pte. However, the core-mm code actually tracks
>>   * access/dirty per folio, not per page. And since we only create a
>>   * contig range when the range is covered by a single folio, we can get
>>   * away with clearing young for the whole contig range here, so we avoid
>>   * having to unfold.
>>   */
>> "
> 
> Except nr means you can span more than a single contig pte range? So this
> comment is no longer applicable as-is?

The nr means consecutive (present) PTEs that map consecutive pages of 
the same large folio in a single VMA and a single page table.

I think this is a prerequisite. If you think it's necessary to explain 
it, I can add it to the comments.

> You've changed the function, the comment needs to change too.
> 
>>
>>> However now you're allowing for large folios that are not contpte?
>>>
>>> Overall feeling pretty iffy about implementing this this way.
>>
>> Please see the above comments, which explain why we should do that.
> 
> You haven't explained anything? Maybe I missed it?
> 
> Can you explain clearly what nr might actually be in relation to contpte's? I'm
> confused even as to the utility here.
> 
> Is it batched ranges of contptes? But then why are you trying to see if end is a
> contpte + expand the range if so?

See below.

>>>> +	unsigned long start = addr;
>>>> +	unsigned long end = start + nr * PAGE_SIZE;
>>>
>>> So now [addr, addr + nr * PAGE_SIZE) must for sure be within a single PTE
>>> table?
>>
>> Caller has made sure that (see folio_referenced_one()).
> 
> You should comment this somehow, I hate this nested assumptions stuff 'function
> X which calls function Y which calls function Z makes sure that parameter A
> fulfils requirements B but we don't mention it anywhere'.

Sure.

>>>>    	int young = 0;
>>>>    	int i;
>>>>
>>>> -	ptep = contpte_align_down(ptep);
>>>> -	addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
>>>> +	if (pte_cont(__ptep_get(ptep + nr - 1)))
>>>> +		end = ALIGN(end, CONT_PTE_SIZE);
>>>
>>> OK so I guess for PTE_CONT to be set, it must be aligned to CONT_PTE_SIZE,
>>> with other PTE entries present there not having PTE_CONT set (Ryan - do
>>> correct me if I'm wrong!)
>>>
>>> I guess then no worry about running off the end of the PTE table here.
>>>
>>> I wonder about using pte_cont_addr_end() here, but I guess you are not
>>> intending to limit to a range here but rather capture the entire contpte
>>> range of the end.
>>
>> Right.
>>
>>> I don't love that now a function prefixed with contpte_... can have a
>>> condition where part of the input range is _not_ a contpte entry, or is
>>> specified partially...
>>
>> Like I said above, this is outside the scope of my patchset. If Ryan also
>> thinks we need to do some cleanups for all the contpte_xxx() functions in
>> the contpte.c file, we can send a follow-up patchset to rename all the
>> contpte_xxx() functions to make it clear.
> 
> It's really not outside of the scope of the patch set, this is review feedback
> you have to address :) trying not to be a grumpy kernel dev here :>)
> 
> In general in the kernel we don't accept confusing patches then defer making
> them not-confusing until later.
> 
> We review until the series is at the correct standard to be accepted before we
> merge.
> 
> As always I'm happy to be convinced that I'm mistaken or something's not
> necesary, however!

Yes, let me try to explain it again. See below.

>>>> -	for (i = 0; i < CONT_PTES; i++, ptep++, addr += PAGE_SIZE)
>>>> -		young |= __ptep_test_and_clear_young(vma, addr, ptep);
>>>> +	if (pte_cont(__ptep_get(ptep))) {
>>>> +		start = ALIGN_DOWN(start, CONT_PTE_SIZE);
>>>> +		ptep = contpte_align_down(ptep);
>>>> +	}
>>>> +
>>>> +	nr = (end - start) / PAGE_SIZE;
>>>
>>> Hm don't love this reuse of input param.
>>
>> OK. Will use another local variable instead.
> 
> Thanks.
> 
>>
>>>
>>>> +	for (i = 0; i < nr; i++, ptep++, start += PAGE_SIZE)
>>>> +		young |= __ptep_test_and_clear_young(vma, start, ptep);
>>>
>>> Again, overall find it a bit iffy that we are essentially overloading the
>>> code with non-contpte behaviour.
>>
>> Let me clarify further: this is the handling logic of the contpte_xxx()
>> functions in the contpte.c file. For example, the function
>> contpte_set_ptes() has a parameter 'nr', which may be greater than
>> CONT_PTES, meaning that it can handle multiple CONT_PTES range sizes of a
>> large folio.
>>
>> It might be a bit confusing, and I understand this is why you want to change
>> the 'contpte_' prefix to the 'batch_' prefix. Of course, we can hope Ryan
>> can provide some input on this.
>>
>> Thanks for reviewing.
> 
> OK so we have some reeeeal confusion here. And this speaks to the patch needing
> work.
> 
> This seems to answer what I asked above - basically - are we doing _batches_ of
> _contpte_ entries, or are we just accepting arbitrary large folios here and
> batching up operations on them, including non-contpte entries.
> 
> Presumably from the above you're saying - this is dealing with batches of
> contpte entries.
> 
> In which case this has to be made _super_ clear. Not just adding an arbitrary
> 'nr' parameter and letting people guess.
> 
> The contpte code is _already_ confusing and somewhat surprising if you're not
> aware of it, we need to be going in the other direction.

Sure. Sorry for causing confusion. I try to explain it again to make it 
clear.

First, it is necessary to explain how the contpte implementation in 
Arm64 is exposed, using set_ptes() as an example.

Arm64 defines an arch-specific implementation of set_ptes():
"
static __always_inline void set_ptes(struct mm_struct *mm, unsigned long 
addr,
				pte_t *ptep, pte_t pte, unsigned int nr)
{
	pte = pte_mknoncont(pte);

	if (likely(nr == 1)) {
		contpte_try_unfold(mm, addr, ptep, __ptep_get(ptep));
		__set_ptes(mm, addr, ptep, pte, 1);
		contpte_try_fold(mm, addr, ptep, pte);
	} else {
		contpte_set_ptes(mm, addr, ptep, pte, nr);
	}
}
"

Here, 'nr' refers to consecutive (present) PTEs that map consecutive 
pages of the same large folio within a single VMA and a single page 
table. Based on 'nr', it determines whether the PTE_CONT attribute 
should be set or not.

Second, the underlying implementation of contpte_set_ptes() also 
calculates 'end' based on 'nr' and checks whether the PTE_CONT attribute 
should be set. For example:

For a large folio with order = 3 (nr = 8), the PTE_CONT attribute will 
not be set since the 'next' is not aligned with CONT_PTE_MASK.

For a large folio with order = 4 (nr = 16), it aligns perfectly, 
allowing the PTE_CONT attribute to be set for the entire PTE entries of 
the large folio.

For a large folio with order = 5 (nr = 32), this involves two ranges of 
CONT_PTE_SIZE (16 PTEs in each range), requiring the PTE_CONT attribute 
to be set separately for each range.

"
void contpte_set_ptes(struct mm_struct *mm, unsigned long addr,
					pte_t *ptep, pte_t pte, unsigned int nr)
{
	.......

	end = addr + (nr << PAGE_SHIFT);
	pfn = pte_pfn(pte);
	prot = pte_pgprot(pte);

	do {
		next = pte_cont_addr_end(addr, end);
		nr = (next - addr) >> PAGE_SHIFT;
		pte = pfn_pte(pfn, prot);

		if (((addr | next | (pfn << PAGE_SHIFT)) & ~CONT_PTE_MASK) == 0)
			pte = pte_mkcont(pte);
		else
			pte = pte_mknoncont(pte);

		__set_ptes(mm, addr, ptep, pte, nr);

		addr = next;
		ptep += nr;
		pfn += nr;

	} while (addr != end);
}
"

Third, regarding the implementation of my patch, I have followed the 
contpte logic here by adding the 'nr' parameter to 
contpte_ptep_test_and_clear_young() for batch processing consecutive 
(present) PTEs. Moreover, the semantics of 'nr' remain consistent with 
the original contpte functions, and I have not broken the existing 
contpte implementation logic.


From jibin.zhang at mediatek.com  Tue Dec 16 19:55:42 2025
From: jibin.zhang at mediatek.com (Jibin Zhang)
Date: Wed, 17 Dec 2025 11:55:42 +0800
Subject: [PATCH] net: fix segmentation of forwarding fraglist GRO
Message-ID: <20251217035548.8104-1-jibin.zhang@mediatek.com>

This patch enhances GSO segment checks by verifying the presence
of frag_list and protocol consistency, addressing low throughput
issues on IPv4 servers when used as hotspots

Specifically, it fixes a bug in GSO segmentation when forwarding
GRO packets with frag_list. The function skb_segment_list cannot
correctly process GRO skbs converted by XLAT, because XLAT only
converts the header of the head skb. As a result, skbs in the
frag_list may remain unconverted, leading to protocol
inconsistencies and reduced throughput.

To resolve this, the patch uses skb_segment to handle forwarded
packets converted by XLAT, ensuring that all fragments are
properly converted and segmented.

Signed-off-by: Jibin Zhang <jibin.zhang at mediatek.com>
---
 net/ipv4/tcp_offload.c | 3 ++-
 net/ipv4/udp_offload.c | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c
index fdda18b1abda..162a384a15bb 100644
--- a/net/ipv4/tcp_offload.c
+++ b/net/ipv4/tcp_offload.c
@@ -104,7 +104,8 @@ static struct sk_buff *tcp4_gso_segment(struct sk_buff *skb,
 	if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
 		return ERR_PTR(-EINVAL);
 
-	if (skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST) {
+	if ((skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST) && skb_has_frag_list(skb) &&
+	    (skb->protocol == skb_shinfo(skb)->frag_list->protocol)) {
 		struct tcphdr *th = tcp_hdr(skb);
 
 		if (skb_pagelen(skb) - th->doff * 4 == skb_shinfo(skb)->gso_size)
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
index 19d0b5b09ffa..704fb32d10d7 100644
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -512,7 +512,8 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
 		return NULL;
 	}
 
-	if (skb_shinfo(gso_skb)->gso_type & SKB_GSO_FRAGLIST) {
+	if ((skb_shinfo(gso_skb)->gso_type & SKB_GSO_FRAGLIST) && skb_has_frag_list(gso_skb) &&
+	    (gso_skb->protocol == skb_shinfo(gso_skb)->frag_list->protocol)) {
 		 /* Detect modified geometry and pass those to skb_segment. */
 		if (skb_pagelen(gso_skb) - sizeof(*uh) == skb_shinfo(gso_skb)->gso_size)
 			return __udp_gso_segment_list(gso_skb, features, is_ipv6);
-- 
2.45.2



From akpm at linux-foundation.org  Tue Dec 16 20:14:03 2025
From: akpm at linux-foundation.org (Andrew Morton)
Date: Tue, 16 Dec 2025 20:14:03 -0800
Subject: [PATCH v6 14/14] mm: Add basic tests for lazy_mmu
In-Reply-To: <20251215150323.2218608-15-kevin.brodsky@arm.com>
References: <20251215150323.2218608-1-kevin.brodsky@arm.com>
	<20251215150323.2218608-15-kevin.brodsky@arm.com>
Message-ID: <20251216201403.4647a4f9861d3122ee9e90d7@linux-foundation.org>

On Mon, 15 Dec 2025 15:03:23 +0000 Kevin Brodsky <kevin.brodsky at arm.com> wrote:

> Add basic KUnit tests for the generic aspects of the lazy MMU mode:
> ensure that it appears active when it should, depending on how
> enable/disable and pause/resume pairs are nested.

I needed this for powerpc allmodconfig;

--- a/arch/powerpc/mm/book3s64/hash_tlb.c~mm-add-basic-tests-for-lazy_mmu-fix
+++ a/arch/powerpc/mm/book3s64/hash_tlb.c
@@ -30,6 +30,7 @@
 #include <trace/events/thp.h>
 
 DEFINE_PER_CPU(struct ppc64_tlb_batch, ppc64_tlb_batch);
+EXPORT_SYMBOL_GPL(ppc64_tlb_batch);
 
 /*
  * A linux PTE was changed and the corresponding hash table entry
@@ -154,6 +155,7 @@ void __flush_tlb_pending(struct ppc64_tl
 		flush_hash_range(i, local);
 	batch->index = 0;
 }
+EXPORT_SYMBOL_GPL(__flush_tlb_pending);
 
 void hash__tlb_flush(struct mmu_gather *tlb)
 {
_



From nicolinc at nvidia.com  Tue Dec 16 20:26:00 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Tue, 16 Dec 2025 20:26:00 -0800
Subject: [PATCH rc v4 2/4] iommu/arm-smmu-v3: Mark STE MEV safe when computing the update sequence
In-Reply-To: <cover.1765945258.git.nicolinc@nvidia.com>
References: <cover.1765945258.git.nicolinc@nvidia.com>
Message-ID: <83f991cbbb1331213aabe7c1fc5f725e79f60ecd.1765945258.git.nicolinc@nvidia.com>

From: Jason Gunthorpe <jgg at nvidia.com>

Nested CD tables set the MEV bit to try to reduce multi-fault spamming on
the hypervisor. Since MEV is in STE word 1 this causes a breaking update
sequence that is not required and impacts real workloads.

For the purposes of STE updates the value of MEV doesn't matter, if it is
set/cleared early or late it just results in a change to the fault reports
that must be supported by the kernel anyhow. The spec says:

 Note: Software must expect, and be able to deal with, coalesced fault
 records even when MEV == 0.

So mark STE MEV safe when computing the update sequence, to avoid creating
a breaking update.

Fixes: da0c56520e88 ("iommu/arm-smmu-v3: Set MEV bit in nested STE for DoS mitigations")
Cc: stable at vger.kernel.org
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 8dbf4ad5b51e..12a9669bcc83 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1085,6 +1085,16 @@ EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_used);
 VISIBLE_IF_KUNIT
 void arm_smmu_get_ste_update_safe(__le64 *safe_bits)
 {
+	/*
+	 * MEV does not meaningfully impact the operation of the HW, it only
+	 * changes how many fault events are generated, thus we can relax it
+	 * when computing the ordering. The spec notes the device can act like
+	 * MEV=1 anyhow:
+	 *
+	 *  Note: Software must expect, and be able to deal with, coalesced
+	 *  fault records even when MEV == 0.
+	 */
+	safe_bits[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
 }
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_update_safe);
 
-- 
2.43.0



From nicolinc at nvidia.com  Tue Dec 16 20:25:59 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Tue, 16 Dec 2025 20:25:59 -0800
Subject: [PATCH rc v4 1/4] iommu/arm-smmu-v3: Add update_safe bits to fix STE update sequence
In-Reply-To: <cover.1765945258.git.nicolinc@nvidia.com>
References: <cover.1765945258.git.nicolinc@nvidia.com>
Message-ID: <58f5af553fa7c3b5fd16f1eb13a81ae428f85678.1765945258.git.nicolinc@nvidia.com>

From: Jason Gunthorpe <jgg at nvidia.com>

C_BAD_STE was observed when updating nested STE from an S1-bypass mode to
an S1DSS-bypass mode. As both modes enabled S2, the used bit is slightly
different than the normal S1-bypass and S1DSS-bypass modes. As a result,
fields like MEV and EATS in S2's used list marked the word1 as a critical
word that requested a STE.V=0. This breaks a hitless update.

However, both MEV and EATS aren't critical in terms of STE update. One
controls the merge of the events and the other controls the ATS that is
managed by the driver at the same time via pci_enable_ats().

Add an arm_smmu_get_ste_update_safe() to allow STE update algorithm to
relax those fields, avoiding the STE update breakages.

After this change, entry_set has no caller checking its return value, so
change it to void.

Note that this change is required by both MEV and EATS fields, which were
introduced in different kernel versions. So add get_update_safe() first.
MEV and EATS will be added to arm_smmu_get_ste_update_safe() separately.

Fixes: 1e8be08d1c91 ("iommu/arm-smmu-v3: Support IOMMU_DOMAIN_NESTED")
Cc: stable at vger.kernel.org
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  2 ++
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  | 18 ++++++++++---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 27 ++++++++++++++-----
 3 files changed, 37 insertions(+), 10 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index ae23aacc3840..a6c976fa9df2 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -900,6 +900,7 @@ struct arm_smmu_entry_writer {
 
 struct arm_smmu_entry_writer_ops {
 	void (*get_used)(const __le64 *entry, __le64 *used);
+	void (*get_update_safe)(__le64 *safe_bits);
 	void (*sync)(struct arm_smmu_entry_writer *writer);
 };
 
@@ -911,6 +912,7 @@ void arm_smmu_make_s2_domain_ste(struct arm_smmu_ste *target,
 
 #if IS_ENABLED(CONFIG_KUNIT)
 void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits);
+void arm_smmu_get_ste_update_safe(__le64 *safe_bits);
 void arm_smmu_write_entry(struct arm_smmu_entry_writer *writer, __le64 *cur,
 			  const __le64 *target);
 void arm_smmu_get_cd_used(const __le64 *ent, __le64 *used_bits);
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
index d2671bfd3798..5db14718fdd6 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
@@ -38,13 +38,16 @@ enum arm_smmu_test_master_feat {
 static bool arm_smmu_entry_differs_in_used_bits(const __le64 *entry,
 						const __le64 *used_bits,
 						const __le64 *target,
+						const __le64 *safe,
 						unsigned int length)
 {
 	bool differs = false;
 	unsigned int i;
 
 	for (i = 0; i < length; i++) {
-		if ((entry[i] & used_bits[i]) != target[i])
+		__le64 used = used_bits[i] & ~safe[i];
+
+		if ((entry[i] & used) != (target[i] & used))
 			differs = true;
 	}
 	return differs;
@@ -56,12 +59,17 @@ arm_smmu_test_writer_record_syncs(struct arm_smmu_entry_writer *writer)
 	struct arm_smmu_test_writer *test_writer =
 		container_of(writer, struct arm_smmu_test_writer, writer);
 	__le64 *entry_used_bits;
+	__le64 *safe;
 
 	entry_used_bits = kunit_kzalloc(
 		test_writer->test, sizeof(*entry_used_bits) * NUM_ENTRY_QWORDS,
 		GFP_KERNEL);
 	KUNIT_ASSERT_NOT_NULL(test_writer->test, entry_used_bits);
 
+	safe = kunit_kzalloc(test_writer->test,
+			     sizeof(*safe) * NUM_ENTRY_QWORDS, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test_writer->test, safe);
+
 	pr_debug("STE value is now set to: ");
 	print_hex_dump_debug("    ", DUMP_PREFIX_NONE, 16, 8,
 			     test_writer->entry,
@@ -79,14 +87,17 @@ arm_smmu_test_writer_record_syncs(struct arm_smmu_entry_writer *writer)
 		 * configuration.
 		 */
 		writer->ops->get_used(test_writer->entry, entry_used_bits);
+		if (writer->ops->get_update_safe)
+			writer->ops->get_update_safe(safe);
 		KUNIT_EXPECT_FALSE(
 			test_writer->test,
 			arm_smmu_entry_differs_in_used_bits(
 				test_writer->entry, entry_used_bits,
-				test_writer->init_entry, NUM_ENTRY_QWORDS) &&
+				test_writer->init_entry, safe,
+				NUM_ENTRY_QWORDS) &&
 				arm_smmu_entry_differs_in_used_bits(
 					test_writer->entry, entry_used_bits,
-					test_writer->target_entry,
+					test_writer->target_entry, safe,
 					NUM_ENTRY_QWORDS));
 	}
 }
@@ -106,6 +117,7 @@ arm_smmu_v3_test_debug_print_used_bits(struct arm_smmu_entry_writer *writer,
 static const struct arm_smmu_entry_writer_ops test_ste_ops = {
 	.sync = arm_smmu_test_writer_record_syncs,
 	.get_used = arm_smmu_get_ste_used,
+	.get_update_safe = arm_smmu_get_ste_update_safe,
 };
 
 static const struct arm_smmu_entry_writer_ops test_cd_ops = {
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index d16d35c78c06..8dbf4ad5b51e 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1082,6 +1082,12 @@ void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits)
 }
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_used);
 
+VISIBLE_IF_KUNIT
+void arm_smmu_get_ste_update_safe(__le64 *safe_bits)
+{
+}
+EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_update_safe);
+
 /*
  * Figure out if we can do a hitless update of entry to become target. Returns a
  * bit mask where 1 indicates that qword needs to be set disruptively.
@@ -1094,13 +1100,22 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
 {
 	__le64 target_used[NUM_ENTRY_QWORDS] = {};
 	__le64 cur_used[NUM_ENTRY_QWORDS] = {};
+	__le64 safe[NUM_ENTRY_QWORDS] = {};
 	u8 used_qword_diff = 0;
 	unsigned int i;
 
 	writer->ops->get_used(entry, cur_used);
 	writer->ops->get_used(target, target_used);
+	if (writer->ops->get_update_safe)
+		writer->ops->get_update_safe(safe);
 
 	for (i = 0; i != NUM_ENTRY_QWORDS; i++) {
+		/*
+		 * Safe is only used for bits that are used by both entries,
+		 * otherwise it is sequenced according to the unused entry.
+		 */
+		safe[i] &= target_used[i] & cur_used[i];
+
 		/*
 		 * Check that masks are up to date, the make functions are not
 		 * allowed to set a bit to 1 if the used function doesn't say it
@@ -1109,6 +1124,7 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
 		WARN_ON_ONCE(target[i] & ~target_used[i]);
 
 		/* Bits can change because they are not currently being used */
+		cur_used[i] &= ~safe[i];
 		unused_update[i] = (entry[i] & cur_used[i]) |
 				   (target[i] & ~cur_used[i]);
 		/*
@@ -1121,7 +1137,7 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
 	return used_qword_diff;
 }
 
-static bool entry_set(struct arm_smmu_entry_writer *writer, __le64 *entry,
+static void entry_set(struct arm_smmu_entry_writer *writer, __le64 *entry,
 		      const __le64 *target, unsigned int start,
 		      unsigned int len)
 {
@@ -1137,7 +1153,6 @@ static bool entry_set(struct arm_smmu_entry_writer *writer, __le64 *entry,
 
 	if (changed)
 		writer->ops->sync(writer);
-	return changed;
 }
 
 /*
@@ -1207,12 +1222,9 @@ void arm_smmu_write_entry(struct arm_smmu_entry_writer *writer, __le64 *entry,
 		entry_set(writer, entry, target, 0, 1);
 	} else {
 		/*
-		 * No inuse bit changed. Sanity check that all unused bits are 0
-		 * in the entry. The target was already sanity checked by
-		 * compute_qword_diff().
+		 * No inuse bit changed, though safe bits may have changed.
 		 */
-		WARN_ON_ONCE(
-			entry_set(writer, entry, target, 0, NUM_ENTRY_QWORDS));
+		entry_set(writer, entry, target, 0, NUM_ENTRY_QWORDS);
 	}
 }
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_write_entry);
@@ -1543,6 +1555,7 @@ static void arm_smmu_ste_writer_sync_entry(struct arm_smmu_entry_writer *writer)
 static const struct arm_smmu_entry_writer_ops arm_smmu_ste_writer_ops = {
 	.sync = arm_smmu_ste_writer_sync_entry,
 	.get_used = arm_smmu_get_ste_used,
+	.get_update_safe = arm_smmu_get_ste_update_safe,
 };
 
 static void arm_smmu_write_ste(struct arm_smmu_master *master, u32 sid,
-- 
2.43.0



From nicolinc at nvidia.com  Tue Dec 16 20:26:02 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Tue, 16 Dec 2025 20:26:02 -0800
Subject: [PATCH rc v4 4/4] iommu/arm-smmu-v3-test: Add nested s1bypass/s1dssbypass coverage
In-Reply-To: <cover.1765945258.git.nicolinc@nvidia.com>
References: <cover.1765945258.git.nicolinc@nvidia.com>
Message-ID: <6fcdd663d62dcab4005401bac2d23d18dd28e0c4.1765945258.git.nicolinc@nvidia.com>

STE in a nested case requires both S1 and S2 fields. And this makes the use
case different from the existing one.

Add coverage for previously failed cases shifting between S2-only and S1+S2
STEs.

Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  | 46 +++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
index 5db14718fdd6..8255a02f4efa 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
@@ -33,8 +33,12 @@ static struct mm_struct sva_mm = {
 enum arm_smmu_test_master_feat {
 	ARM_SMMU_MASTER_TEST_ATS = BIT(0),
 	ARM_SMMU_MASTER_TEST_STALL = BIT(1),
+	ARM_SMMU_MASTER_TEST_NESTED = BIT(2),
 };
 
+static void arm_smmu_test_make_s2_ste(struct arm_smmu_ste *ste,
+				      enum arm_smmu_test_master_feat feat);
+
 static bool arm_smmu_entry_differs_in_used_bits(const __le64 *entry,
 						const __le64 *used_bits,
 						const __le64 *target,
@@ -197,6 +201,17 @@ static void arm_smmu_test_make_cdtable_ste(struct arm_smmu_ste *ste,
 	};
 
 	arm_smmu_make_cdtable_ste(ste, &master, ats_enabled, s1dss);
+	if (feat & ARM_SMMU_MASTER_TEST_NESTED) {
+		struct arm_smmu_ste s2ste;
+		int i;
+
+		arm_smmu_test_make_s2_ste(&s2ste, ARM_SMMU_MASTER_TEST_ATS);
+		ste->data[0] |= cpu_to_le64(
+			FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_NESTED));
+		ste->data[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
+		for (i = 2; i < NUM_ENTRY_QWORDS; i++)
+			ste->data[i] = s2ste.data[i];
+	}
 }
 
 static void arm_smmu_v3_write_ste_test_bypass_to_abort(struct kunit *test)
@@ -554,6 +569,35 @@ static void arm_smmu_v3_write_ste_test_s2_to_s1_stall(struct kunit *test)
 						       NUM_EXPECTED_SYNCS(3));
 }
 
+static void
+arm_smmu_v3_write_ste_test_nested_s1dssbypass_to_s1bypass(struct kunit *test)
+{
+	struct arm_smmu_ste s1_ste;
+	struct arm_smmu_ste s2_ste;
+
+	arm_smmu_test_make_cdtable_ste(
+		&s1_ste, STRTAB_STE_1_S1DSS_BYPASS, fake_cdtab_dma_addr,
+		ARM_SMMU_MASTER_TEST_ATS | ARM_SMMU_MASTER_TEST_NESTED);
+	arm_smmu_test_make_s2_ste(&s2_ste, 0);
+	/* Expect an additional sync to unset ignored bits: EATS and MEV */
+	arm_smmu_v3_test_ste_expect_hitless_transition(test, &s1_ste, &s2_ste,
+						       NUM_EXPECTED_SYNCS(3));
+}
+
+static void
+arm_smmu_v3_write_ste_test_nested_s1bypass_to_s1dssbypass(struct kunit *test)
+{
+	struct arm_smmu_ste s1_ste;
+	struct arm_smmu_ste s2_ste;
+
+	arm_smmu_test_make_cdtable_ste(
+		&s1_ste, STRTAB_STE_1_S1DSS_BYPASS, fake_cdtab_dma_addr,
+		ARM_SMMU_MASTER_TEST_ATS | ARM_SMMU_MASTER_TEST_NESTED);
+	arm_smmu_test_make_s2_ste(&s2_ste, 0);
+	arm_smmu_v3_test_ste_expect_hitless_transition(test, &s2_ste, &s1_ste,
+						       NUM_EXPECTED_SYNCS(2));
+}
+
 static void arm_smmu_v3_write_cd_test_sva_clear(struct kunit *test)
 {
 	struct arm_smmu_cd cd = {};
@@ -600,6 +644,8 @@ static struct kunit_case arm_smmu_v3_test_cases[] = {
 	KUNIT_CASE(arm_smmu_v3_write_cd_test_s1_change_asid),
 	KUNIT_CASE(arm_smmu_v3_write_ste_test_s1_to_s2_stall),
 	KUNIT_CASE(arm_smmu_v3_write_ste_test_s2_to_s1_stall),
+	KUNIT_CASE(arm_smmu_v3_write_ste_test_nested_s1dssbypass_to_s1bypass),
+	KUNIT_CASE(arm_smmu_v3_write_ste_test_nested_s1bypass_to_s1dssbypass),
 	KUNIT_CASE(arm_smmu_v3_write_cd_test_sva_clear),
 	KUNIT_CASE(arm_smmu_v3_write_cd_test_sva_release),
 	{},
-- 
2.43.0



From nicolinc at nvidia.com  Tue Dec 16 20:25:58 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Tue, 16 Dec 2025 20:25:58 -0800
Subject: [PATCH rc v4 0/4] iommu/arm-smmu-v3: Fix hitless STE update in nesting cases
Message-ID: <cover.1765945258.git.nicolinc@nvidia.com>

Occasional C_BAD_STE errors were observed in nesting setups where a device
attached to a nested bypass/identity domain enables PASID.

This occurred when the physical STE was updated from S2-only mode to S1+S2
nesting mode, but the update failed to use the hitless routine that it was
supposed to use. Instead, it cleared STE.V bit to load the CD table, while
the default substream was still actively performing DMA.

It was later found that the diff algorithm in arm_smmu_entry_qword_diff()
enforced an additional critical word due to misaligned MEV and EATS fields
between S2-only and S1+S2 modes.

Both fields are either well-managed or non-critical, so move them to the
"ignored" list to relax the qword diff algorithm.

Additionally, add KUnit test coverage for these nesting STE cases.

This is on Github:
https://github.com/nicolinc/iommufd/commits/smmuv3_ste_fixes/

A host kernel must apply this to fix the bug.

Changelog
v4:
 * s/ignored/update_safe
 * Change entry_set to void
v3:
 https://lore.kernel.org/all/cover.1765334526.git.nicolinc at nvidia.com/
 * Add Reviewed-by from Shuai
 * Add an inline comments in nested test cases
 * Reuse arm_smmu_test_make_cdtable_ste() for nested test cases
v2:
 https://lore.kernel.org/all/cover.1765140287.git.nicolinc at nvidia.com/
 * Fix kunit tests
 * Update commit message and inline comments
 * Keep MEV/EATS in used list by masking them away using ignored_bits
v1:
 https://lore.kernel.org/all/cover.1764982046.git.nicolinc at nvidia.com/

Jason Gunthorpe (3):
  iommu/arm-smmu-v3: Add update_safe bits to fix STE update sequence
  iommu/arm-smmu-v3: Mark STE MEV safe when computing the update
    sequence
  iommu/arm-smmu-v3: Mark STE EATS safe when computing the update
    sequence

Nicolin Chen (1):
  iommu/arm-smmu-v3-test: Add nested s1bypass/s1dssbypass coverage

 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  2 +
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  | 64 ++++++++++++++++++-
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 46 +++++++++++--
 3 files changed, 102 insertions(+), 10 deletions(-)

-- 
2.43.0



From nicolinc at nvidia.com  Tue Dec 16 20:26:01 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Tue, 16 Dec 2025 20:26:01 -0800
Subject: [PATCH rc v4 3/4] iommu/arm-smmu-v3: Mark STE EATS safe when computing the update sequence
In-Reply-To: <cover.1765945258.git.nicolinc@nvidia.com>
References: <cover.1765945258.git.nicolinc@nvidia.com>
Message-ID: <adf08c3b9f289188aca4fe80e506dca7aa48aa19.1765945258.git.nicolinc@nvidia.com>

From: Jason Gunthorpe <jgg at nvidia.com>

If a VM wants to toggle EATS off at the same time as changing the CFG, the
hypervisor will see EATS change to 0 and insert a V=0 breaking update into
the STE even though the VM did not ask for that.

In bare metal, EATS is ignored by CFG=ABORT/BYPASS, which is why this does
not cause a problem until we have nested where CFG is always a variation of
S2 trans that does use EATS.

Relax the rules for EATS sequencing, we don't need it to be exact because
the enclosing code will always disable ATS at the PCI device if we are
changing EATS. This ensures there are no ATS transactions that can race
with an EATS change so we don't need to carefully sequence these bits.

Fixes: 1e8be08d1c91 ("iommu/arm-smmu-v3: Support IOMMU_DOMAIN_NESTED")
Cc: stable at vger.kernel.org
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 12a9669bcc83..a3b29ad20a82 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1095,6 +1095,15 @@ void arm_smmu_get_ste_update_safe(__le64 *safe_bits)
 	 *  fault records even when MEV == 0.
 	 */
 	safe_bits[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
+
+	/*
+	 * EATS is used to reject and control the ATS behavior of the device. If
+	 * we are changing it away from 0 then we already trust the device to
+	 * use ATS properly and we have sequenced the device's ATS enable in PCI
+	 * config space to prevent it from issuing ATS while we are changing
+	 * EATS.
+	 */
+	safe_bits[1] |= cpu_to_le64(STRTAB_STE_1_EATS);
 }
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_update_safe);
 
-- 
2.43.0



From alim.akhtar at samsung.com  Tue Dec 16 20:28:08 2025
From: alim.akhtar at samsung.com (Alim Akhtar)
Date: Wed, 17 Dec 2025 09:58:08 +0530
Subject: [PATCH v3 1/5] pinctrl: samsung: Consolidate pin-bank macros
 under EXYNOS9_* and pass bank_type explicitly
In-Reply-To: <20251202093613.852109-2-youngmin.nam@samsung.com>
References: <20251202093613.852109-1-youngmin.nam@samsung.com>
	<CGME20251202093026epcas2p28ddfd32305695df996841fd73b231b6b@epcas2p2.samsung.com>
	<20251202093613.852109-2-youngmin.nam@samsung.com>
Message-ID: <12a301dc6f0d$8fea7ec0$afbf7c40$@samsung.com>

Hello Youngmin,

> -----Original Message-----
> From: Youngmin Nam <youngmin.nam at samsung.com>
> Sent: Tuesday, December 2, 2025 3:06 PM
> To: krzk at kernel.org; s.nawrocki at samsung.com; alim.akhtar at samsung.com;
> linus.walleij at linaro.org; peter.griffin at linaro.org;
> semen.protsenko at linaro.org; ivo.ivanov.ivanov1 at gmail.com
> Cc: ryu.real at samsung.com; d7271.choe at samsung.com;
> shin.son at samsung.com; jaewon02.kim at samsung.com; linux-arm-
> kernel at lists.infradead.org; linux-samsung-soc at vger.kernel.org; linux-
> gpio at vger.kernel.org; linux-kernel at vger.kernel.org; Youngmin Nam
> <youngmin.nam at samsung.com>
> Subject: [PATCH v3 1/5] pinctrl: samsung: Consolidate pin-bank macros under
> EXYNOS9_* and pass bank_type explicitly
> 
> Modern Exynos platforms have several near-duplicate pin-bank macro
> families (EXYNOS850_*, EXYNOS8895_*, EXYNOS7870_*), which makes
> tables verbose and harder to share across SoCs that differ only by
> bank_type (alive/off) layout.
> 
> This patch unifies them into one EXYNOS9_* macro family and makes the
> bank_type an explicit argument. The common 850-era bank types are also
> renamed to 'exynos9_bank_type_{alive,off}' to reflect their reuse on
> later Exynos 9xxx-generation parts.
> 
> Naming rationale:
> - Use of the EXYNOS9_* prefix indicates that these macros target
>   current Exynos generations sharing the same register layout and
>   EINT wiring model. Compared to SoC-specific prefixes
>   (EXYNOS850_*, EXYNOS8895_*),
>   EXYNOS9_* is clearer and more future-proof for modern parts.
> 
> Key changes:
> - Introduce:
>   - 'EXYNOS9_PIN_BANK_EINTN(bank_type, pins, reg, id)'
>   - 'EXYNOS9_PIN_BANK_EINTG(bank_type, pins, reg, id, offs)'
>   - 'EXYNOS9_PIN_BANK_EINTW(bank_type, pins, reg, id, offs)'
> - Rename:
>   - 'exynos850_bank_type_alive'-> 'exynos9_bank_type_alive'
>   - 'exynos850_bank_type_off'  -> 'exynos9_bank_type_off'
> - Convert pin-bank tables for:
>   - Exynos2200, 7870, 7885, 850, 990, 9810, 8890, 8895,
>     AutoV9, AutoV920, FSD
> - Update GS101/EXYNOSV920 helpers to reference 'exynos9_bank_type_*'
>   instead of the old exynos850 names.
> - Standardize on EXYNOS9_* macros while keeping SoC-specific
>   '*_bank_type_*' when layouts differ (e.g., 7870/8895).
> 
> No functional change intended.
> 
> Signed-off-by: Youngmin Nam <youngmin.nam at samsung.com>
> Reviewed-by: Sam Protsenko <semen.protsenko at linaro.org>
> Tested-by: Sam Protsenko <semen.protsenko at linaro.org>
> ---
Thanks for consolidating this.
Feel free to add
Reviewed-by: Alim Akhtar <alim.akhtar at samsung.com>

Also tested on SADK based on Exynosautov920, GPIO EINT works fine. 

Tested-by: Alim Akhtar <alim.akhtar at samsung.com>




From alim.akhtar at samsung.com  Tue Dec 16 20:33:10 2025
From: alim.akhtar at samsung.com (Alim Akhtar)
Date: Wed, 17 Dec 2025 10:03:10 +0530
Subject: [PATCH v3 2/5] pinctrl: samsung: fix incorrect pin-bank entries
 on Exynos2200/7885/8890/8895
In-Reply-To: <20251202093613.852109-3-youngmin.nam@samsung.com>
References: <20251202093613.852109-1-youngmin.nam@samsung.com>
	<CGME20251202093027epcas2p24adbd3226dd50b2780baceee6588f3ba@epcas2p2.samsung.com>
	<20251202093613.852109-3-youngmin.nam@samsung.com>
Message-ID: <12a401dc6f0e$441ae1f0$cc50a5d0$@samsung.com>

Hello Youngmin

> -----Original Message-----
> From: Youngmin Nam <youngmin.nam at samsung.com>
> Sent: Tuesday, December 2, 2025 3:06 PM
> To: krzk at kernel.org; s.nawrocki at samsung.com; alim.akhtar at samsung.com;
> linus.walleij at linaro.org; peter.griffin at linaro.org;
> semen.protsenko at linaro.org; ivo.ivanov.ivanov1 at gmail.com
> Cc: ryu.real at samsung.com; d7271.choe at samsung.com;
> shin.son at samsung.com; jaewon02.kim at samsung.com; linux-arm-
> kernel at lists.infradead.org; linux-samsung-soc at vger.kernel.org; linux-
> gpio at vger.kernel.org; linux-kernel at vger.kernel.org; Youngmin Nam
> <youngmin.nam at samsung.com>
> Subject: [PATCH v3 2/5] pinctrl: samsung: fix incorrect pin-bank entries on
> Exynos2200/7885/8890/8895
> 
> This patch corrects wrong pin bank table definitions for 4 SoCs based on their
> TRMs.
> 
> Exynos2200
> - gpq0/1/2 were using EXYNOS_PIN_BANK_EINTN(), which implies a
>   'bank_type_off' layout (.fld_width = {4,1,2,2,2,2}).
> - Per the SoC TRM these banks must use the 'alive' layout
>   (.fld_width = {4,1,4,4}).
> - Switch them to EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, ...).
> 
> Exynos7885
> - etc0, etc1: update bank type to match the SoC TRM.
> - gpq0 is a non-wakeup interrupt bank; change EINTW -> EINTN accordingly.
> 
> Exynos8890
> - Per the SoC TRM, rename bank ect0 to gpb3 and mark it as
>   a non-external interrupt bank.
> - gpi1, gpi2: update bank type to match the SoC TRM.
>   exynos8895_bank_type_off (.fld_width = {4,1,2,3,2,2}) ->
>   exynos5433_bank_type_off (.fld_width = {4,1,2,4,2,2})
> - Per the SoC TRM, mark etc1 as a non-external interrupt bank.
> - apply lower case style for hex numbers.
> 
> Exynos8895
> - gpa4 is a non-wakeup interrupt bank per the SoC TRM.
>   change EINTW -> EINTN. (The bank_type itself was correct and is kept
>   unchanged.)
> - apply lower case style for hex numbers.
> 
> This aligns the pin-bank tables with the documented bitfield layouts and
> wakeup domains. No DT/ABI change.
> 
> Signed-off-by: Youngmin Nam <youngmin.nam at samsung.com>
> Reviewed-by: Sam Protsenko <semen.protsenko at linaro.org>
> Reviewed-by: Ivaylo Ivanov <ivo.ivanov.ivanov1 at gmail.com>
> Tested-by: Sam Protsenko <semen.protsenko at linaro.org>
> ---

Reviewed-by: Alim Akhtar <alim.akhtar at samsung.com>

Tested on Exynosautov920 SADK board

Tested-by: Alim Akhtar <alim.akhtar at samsung.com>





From alim.akhtar at samsung.com  Tue Dec 16 20:43:19 2025
From: alim.akhtar at samsung.com (Alim Akhtar)
Date: Wed, 17 Dec 2025 10:13:19 +0530
Subject: [PATCH v3 4/5] pinctrl: samsung: fold GS101 pin-bank macros
 into EXYNOS9_*
In-Reply-To: <20251202093613.852109-5-youngmin.nam@samsung.com>
References: <20251202093613.852109-1-youngmin.nam@samsung.com>
	<CGME20251202093028epcas2p1955176332d21ce4cadf7ed8894c5c1fa@epcas2p1.samsung.com>
	<20251202093613.852109-5-youngmin.nam@samsung.com>
Message-ID: <12a501dc6f0f$ace76270$06b62750$@samsung.com>

Hi Youngmin

> -----Original Message-----
> From: Youngmin Nam <youngmin.nam at samsung.com>
> Sent: Tuesday, December 2, 2025 3:06 PM
> To: krzk at kernel.org; s.nawrocki at samsung.com; alim.akhtar at samsung.com;
> linus.walleij at linaro.org; peter.griffin at linaro.org;
> semen.protsenko at linaro.org; ivo.ivanov.ivanov1 at gmail.com
> Cc: ryu.real at samsung.com; d7271.choe at samsung.com;
> shin.son at samsung.com; jaewon02.kim at samsung.com; linux-arm-
> kernel at lists.infradead.org; linux-samsung-soc at vger.kernel.org; linux-
> gpio at vger.kernel.org; linux-kernel at vger.kernel.org; Youngmin Nam
> <youngmin.nam at samsung.com>
> Subject: [PATCH v3 4/5] pinctrl: samsung: fold GS101 pin-bank macros into
> EXYNOS9_*
> 
> GS101 had dedicated GS101_PIN_BANK_EINT{G,W} helpers, but they are
> redundant with EXYNOS9_PIN_BANK_EINT{G,W} (same semantics, including
> the per-bank .eint_fltcon_offset).
> This change removes the GS101_* macros and switches the GS101 pin-bank
> tables to the EXYNOS9_* helpers with exynos9_bank_type_{alive,off}.
> While here, update the struct comment to note FLTCON is Exynos9-specific
> (not 'GS101-specific').
> 
> One macro family for all Exynos9-era SoCs (incl. GS101) reduces copy-paste
> drift and keeps the FLTCON handling consistent.
> There is no functional change.
> 
> Signed-off-by: Youngmin Nam <youngmin.nam at samsung.com>
> Reviewed-by: Sam Protsenko <semen.protsenko at linaro.org>
> Reviewed-by: Peter Griffin <peter.griffin at linaro.org>
> Tested-by: Sam Protsenko <semen.protsenko at linaro.org>
> Tested-by: Peter Griffin <peter.griffin at linaro.org> (tested on Pixel6/gs101)
> ---
Reviewed-by: Alim Akhtar <alim.akhtar at samsung.com>

Tested this series on Exynosautov920 sadk board

Tested-by: Alim Akhtar <alim.akhtar at samsung.com>



From alim.akhtar at samsung.com  Tue Dec 16 20:46:19 2025
From: alim.akhtar at samsung.com (Alim Akhtar)
Date: Wed, 17 Dec 2025 10:16:19 +0530
Subject: [PATCH v3 3/5] pinctrl: samsung: add per-bank FLTCON offset to
 EXYNOS9_PIN_BANK_* and fix tables
In-Reply-To: <20251202093613.852109-4-youngmin.nam@samsung.com>
References: <20251202093613.852109-1-youngmin.nam@samsung.com>
	<CGME20251202093028epcas2p456b6a2bfebfc76384f706a9962266fcf@epcas2p4.samsung.com>
	<20251202093613.852109-4-youngmin.nam@samsung.com>
Message-ID: <12a601dc6f10$18b46e30$4a1d4a90$@samsung.com>

Hi Youngmin

> -----Original Message-----
> From: Youngmin Nam <youngmin.nam at samsung.com>
> Sent: Tuesday, December 2, 2025 3:06 PM
> To: krzk at kernel.org; s.nawrocki at samsung.com; alim.akhtar at samsung.com;
> linus.walleij at linaro.org; peter.griffin at linaro.org;
> semen.protsenko at linaro.org; ivo.ivanov.ivanov1 at gmail.com
> Cc: ryu.real at samsung.com; d7271.choe at samsung.com;
> shin.son at samsung.com; jaewon02.kim at samsung.com; linux-arm-
> kernel at lists.infradead.org; linux-samsung-soc at vger.kernel.org; linux-
> gpio at vger.kernel.org; linux-kernel at vger.kernel.org; Youngmin Nam
> <youngmin.nam at samsung.com>
> Subject: [PATCH v3 3/5] pinctrl: samsung: add per-bank FLTCON offset to
> EXYNOS9_PIN_BANK_* and fix tables
> 
> Several Exynos9-era pin-bank tables were implicitly assuming that the
> filter control (FLTCON) registers are laid out contiguously from the
> EINT base offset. Per the TRMs this is not always true. FLTCON can live
> at a separate per-bank offset, and the current tables cause the driver
> to program the wrong FLTCON addresses for some banks.
> 
> - Extends EXYNOS9_PIN_BANK_EINTG()/EINTW() to take an explicit
>   .eint_fltcon_offset parameter.
> - Updates pin-bank tables with the correct FLTCON offsets for:
>   Exynos2200 (ALIVE/CMGP/HSI1/UFS/HSI1UFS/PERIC0/1/2/VTS),
>   Exynos7870 (ALIVE/DISPAUD/ESE/FSYS/MIF/NFC/TOP/TOUCH),
>   Exynos7885 (ALIVE/DISPAUD/FSYS/TOP),
>   Exynos850  (ALIVE/CMGP/AUD/HSI/CORE/PERI),
>   Exynos990  (ALIVE/CMGP/HSI1/HSI2/PERIC0/1/VTS),
>   Exynos9810 (ALIVE/AUD/CHUB/CMGP/FSYS0/FSYS1/PERIC0/1/VTS),
>   ExynosAuto v9 (ALIVE/AUD/FSYS0/1/2/PERIC0/1),
>   Exynos8890 (ALIVE/AUD/CCORE/ESE/FP/FSYS0/1/NFC/PERIC0/1/TOUCH),
>   Exynos8895 (ALIVE/ABOX/VTS/FSYS0/1/BUSC/PERIC0/1),
>   and FSD (FSYS/PERIC).
> 
> Notes:
> - GS101 already programs per-bank filter control registers. This change
>   aligns the Exynos9 path with that model.
> - Banks without filters (EINTN) are unaffected.
> 
> Signed-off-by: Youngmin Nam <youngmin.nam at samsung.com>
> Reviewed-by: Sam Protsenko <semen.protsenko at linaro.org>
> Tested-by: Sam Protsenko <semen.protsenko at linaro.org>
> ---
Reviewed-by: Alim Akhtar <alim.akhtar at samsung.com>

Tested this series on Exynosautov920 sadk

Tested-by: Alim Akhtar <alim.akhtar at samsung.com>




From alim.akhtar at samsung.com  Tue Dec 16 20:53:40 2025
From: alim.akhtar at samsung.com (Alim Akhtar)
Date: Wed, 17 Dec 2025 10:23:40 +0530
Subject: [PATCH v3 5/5] pinctrl: samsung: rename gs101_pinctrl_* to
 exynos9_pinctrl_*
In-Reply-To: <20251202093613.852109-6-youngmin.nam@samsung.com>
References: <20251202093613.852109-1-youngmin.nam@samsung.com>
	<CGME20251202093029epcas2p19224bab81f8ed2b9f63613fdd010ab57@epcas2p1.samsung.com>
	<20251202093613.852109-6-youngmin.nam@samsung.com>
Message-ID: <12a701dc6f11$1e9412a0$5bbc37e0$@samsung.com>

Hello Youngmin

> -----Original Message-----
> From: Youngmin Nam <youngmin.nam at samsung.com>
> Sent: Tuesday, December 2, 2025 3:06 PM
> To: krzk at kernel.org; s.nawrocki at samsung.com; alim.akhtar at samsung.com;
> linus.walleij at linaro.org; peter.griffin at linaro.org;
> semen.protsenko at linaro.org; ivo.ivanov.ivanov1 at gmail.com
> Cc: ryu.real at samsung.com; d7271.choe at samsung.com;
> shin.son at samsung.com; jaewon02.kim at samsung.com; linux-arm-
> kernel at lists.infradead.org; linux-samsung-soc at vger.kernel.org; linux-
> gpio at vger.kernel.org; linux-kernel at vger.kernel.org; Youngmin Nam
> <youngmin.nam at samsung.com>
> Subject: [PATCH v3 5/5] pinctrl: samsung: rename gs101_pinctrl_* to
> exynos9_pinctrl_*
> 
> The suspend/resume helpers named gs101_pinctrl_{suspend,resume} are
> not GS101-specific. They implement the generic save/restore sequence used
> by Exynos9-style controllers that have EINT filter configuration
> (eint_fltcon) to preserve.
> 
> Rename them to exynos9_pinctrl_{suspend,resume} and update all users:
>   - exynos2200, exynos9810, exynos8895, exynos7885, exynos7870,
>     exynosautov9, fsd, and gs101 controller tables
>   - prototypes in pinctrl-exynos.h
>   - definitions in pinctrl-exynos.c
> 
> This aligns naming with the earlier macro/doc cleanups (e.g. using
> EXYNOS9_PIN_BANK_* and describing eint_fltcon as Exynos9-specific) and
> makes the helpers clearly reusable by other Exynos9-like SoCs.
> 
> Signed-off-by: Youngmin Nam <youngmin.nam at samsung.com>
> Reviewed-by: Sam Protsenko <semen.protsenko at linaro.org>
> Reviewed-by: Peter Griffin <peter.griffin at linaro.org>
> Tested-by: Peter Griffin <peter.griffin at linaro.org> (tested on Pixel6/gs101)
> ---
Reviewed-by: Alim Akhtar <alim.akhtar at samsung.com>

Tested this series on Exynosautov920 sadk

Tested-by: Alim Akhtar <alim.akhtar at samsung.com>




From vkoul at kernel.org  Tue Dec 16 21:10:28 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Wed, 17 Dec 2025 10:40:28 +0530
Subject: [PATCH 0/8] dmaengine: Add new API to combine onfiguration and
 descriptor preparation
In-Reply-To: <aUGWtarjFNNy2KyZ@lizhi-Precision-Tower-5810>
References: <20251208-dma_prep_config-v1-0-53490c5e1e2a@nxp.com>
 <aUFUX0e_h7RGAecz@vaman>
 <aUF2SX/6bV2lHtF0@lizhi-Precision-Tower-5810>
 <aUF-C8iUCs-dYXGm@vaman>
 <aUGA7tmDYm1MhRXn@lizhi-Precision-Tower-5810>
 <aUGURVuW33WSTuyI@vaman>
 <aUGWtarjFNNy2KyZ@lizhi-Precision-Tower-5810>
Message-ID: <aUI7RJvQUx3m2IRf@vaman>

On 16-12-25, 12:28, Frank Li wrote:
> On Tue, Dec 16, 2025 at 10:47:57PM +0530, Vinod Koul wrote:
> > On 16-12-25, 10:55, Frank Li wrote:
> > > The usual prep_ call have not sconf argument, which need depend on previous
> > > config.
> > >
> > > further, If passdown NULL for config, it means use previuos config.
> >
> > I know it is bit longer but somehow I would feel better for the API to
> > imply config as well please
> 
> I can use you suggested dmaengine_prep_config_perip_single().
> 
> But how about use dmaengine_prep_config_single(), which little bit shorter
> and use "config" to imply it is for periperal? (similar to cyclic case?)

Yes that is a good idea. config does imply peripheral cases. Please make
sure API documentation marks that clearly

BR
-- 
~Vinod


From d-gole at ti.com  Tue Dec 16 21:29:38 2025
From: d-gole at ti.com (Dhruva Gole)
Date: Wed, 17 Dec 2025 10:59:38 +0530
Subject: [PATCH v3 2/4] firmware: ti_sci: handle IRQ restore in
 BOARDCFG_MANAGED mode during resume
In-Reply-To: <bcc7a3da-3cb5-451b-98eb-4f7896c615a1@ti.com>
References: <20251205-ti-sci-jacinto-s2r-restore-irq-v3-0-d06963974ad4@bootlin.com>
 <20251205-ti-sci-jacinto-s2r-restore-irq-v3-2-d06963974ad4@bootlin.com>
 <bcc7a3da-3cb5-451b-98eb-4f7896c615a1@ti.com>
Message-ID: <20251217052938.fpgclxhmyydvw7ce@lcpd911>

On Dec 16, 2025 at 08:17:24 +0530, Kumar, Udit wrote:
> 
> On 12/5/2025 7:58 PM, Thomas Richard (TI.com) wrote:
> > In BOARDCFG_MANAGED mode, the firmware cannot restore IRQs during
> > resume. This responsibility is delegated to the ti_sci driver,
> > which maintains an internal list of all requested IRQs. This list
> > is updated on each set/free operation, and all IRQs are restored
> > during the resume_noirq() phase.
> > 
> > Signed-off-by: Thomas Richard (TI.com) <thomas.richard at bootlin.com>
> > ---
> >   drivers/firmware/ti_sci.c | 147 +++++++++++++++++++++++++++++++++++++++++++---
> >   1 file changed, 138 insertions(+), 9 deletions(-)
> > 
> > diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
> > index d77b631d9c855..8d94745376e2a 100644
> > --- a/drivers/firmware/ti_sci.c
> > +++ b/drivers/firmware/ti_sci.c
> > @@ -12,6 +12,7 @@
> >   #include <linux/cpu.h>
> >   #include <linux/debugfs.h>
> >   #include <linux/export.h>
> > +#include <linux/hashtable.h>
> >   #include <linux/io.h>
> >   #include <linux/iopoll.h>
> >   #include <linux/kernel.h>
> > @@ -87,6 +88,16 @@ struct ti_sci_desc {
> >   	int max_msg_size;
> >   };
> > +/**
> > + * struct ti_sci_irq - Description of allocated irqs
> > + * @node: Link to hash table
> > + * @desc: Description of the irq
> > + */
> > +struct ti_sci_irq {
> > +	struct hlist_node node;
> > +	struct ti_sci_msg_req_manage_irq desc;
> > +};
> > +
> >   /**
> >    * struct ti_sci_info - Structure representing a TI SCI instance
> >    * @dev:	Device pointer
> > @@ -101,6 +112,7 @@ struct ti_sci_desc {
> >    * @chan_rx:	Receive mailbox channel
> >    * @minfo:	Message info
> >    * @node:	list head
> > + * @irqs:	List of allocated irqs
> >    * @host_id:	Host ID
> >    * @fw_caps:	FW/SoC low power capabilities
> >    * @users:	Number of users of this instance
> > @@ -117,6 +129,7 @@ struct ti_sci_info {
> >   	struct mbox_chan *chan_tx;
> >   	struct mbox_chan *chan_rx;
> >   	struct ti_sci_xfers_info minfo;
> > +	DECLARE_HASHTABLE(irqs, 8);
> >   	struct list_head node;
> >   	u8 host_id;
> >   	u64 fw_caps;
> > @@ -2301,6 +2314,32 @@ static int ti_sci_manage_irq(const struct ti_sci_handle *handle,
> >   	return ret;
> >   }
> > +/**
> > + * ti_sci_irq_hash() - Helper API to compute irq hash for the hash table.
> > + * @irq:	irq to hash
> > + *
> > + * Return: the computed hash value.
> > + */
> > +static int ti_sci_irq_hash(struct ti_sci_msg_req_manage_irq *irq)
> > +{
> > +	return irq->src_id ^ irq->src_index;
> > +}
> > +
> > +/**
> > + * ti_sci_irq_equal() - Helper API to compare two irqs (generic headers are not
> > + *                       compared)
> > + * @irq_a:	irq_a to compare
> > + * @irq_b:	irq_b to compare
> > + *
> > + * Return: true if the two irqs are equal, else false.
> > + */
> > +static bool ti_sci_irq_equal(struct ti_sci_msg_req_manage_irq *irq_a,
> > +			     struct ti_sci_msg_req_manage_irq *irq_b)
> > +{
> > +	return !memcmp(&irq_a->valid_params, &irq_b->valid_params,
> > +		       sizeof(*irq_a) - sizeof(irq_a->hdr));
> > +}
> > +
> >   /**
> >    * ti_sci_set_irq() - Helper api to configure the irq route between the
> >    *		      requested source and destination
> > @@ -2324,15 +2363,43 @@ static int ti_sci_set_irq(const struct ti_sci_handle *handle, u32 valid_params,
> >   			  u16 dst_host_irq, u16 ia_id, u16 vint,
> >   			  u16 global_event, u8 vint_status_bit, u8 s_host)
> >   {
> > +	struct ti_sci_info *info = handle_to_ti_sci_info(handle);
> > +	struct ti_sci_msg_req_manage_irq *desc;
> > +	struct ti_sci_irq *irq;
> > +	int ret;
> > +
> >   	pr_debug("%s: IRQ set with valid_params = 0x%x from src = %d, index = %d, to dst = %d, irq = %d,via ia_id = %d, vint = %d, global event = %d,status_bit = %d\n",
> >   		 __func__, valid_params, src_id, src_index,
> >   		 dst_id, dst_host_irq, ia_id, vint, global_event,
> >   		 vint_status_bit);
> > -	return ti_sci_manage_irq(handle, valid_params, src_id, src_index,
> > -				 dst_id, dst_host_irq, ia_id, vint,
> > -				 global_event, vint_status_bit, s_host,
> > -				 TI_SCI_MSG_SET_IRQ);
> > +	ret = ti_sci_manage_irq(handle, valid_params, src_id, src_index,
> > +				dst_id, dst_host_irq, ia_id, vint,
> > +				global_event, vint_status_bit, s_host,
> > +				TI_SCI_MSG_SET_IRQ);
> > +
> > +	if (ret)
> > +		return ret;
> > +
> > +	irq = kzalloc(sizeof(*irq), GFP_KERNEL);
> > +	if (!irq)
> > +		return -ENOMEM;
> > +
> > +	desc = &irq->desc;
> > +	desc->valid_params = valid_params;
> > +	desc->src_id = src_id;
> > +	desc->src_index = src_index;
> > +	desc->dst_id = dst_id;
> > +	desc->dst_host_irq = dst_host_irq;
> > +	desc->ia_id = ia_id;
> > +	desc->vint = vint;
> > +	desc->global_event = global_event;
> > +	desc->vint_status_bit = vint_status_bit;
> > +	desc->secondary_host = s_host;
> > +
> > +	hash_add(info->irqs, &irq->node, ti_sci_irq_hash(desc));
> > +
> > +	return 0;
> >   }
> >   /**
> > @@ -2358,15 +2425,46 @@ static int ti_sci_free_irq(const struct ti_sci_handle *handle, u32 valid_params,
> >   			   u16 dst_host_irq, u16 ia_id, u16 vint,
> >   			   u16 global_event, u8 vint_status_bit, u8 s_host)
> >   {
> > +	struct ti_sci_info *info = handle_to_ti_sci_info(handle);
> > +	struct ti_sci_msg_req_manage_irq irq_desc;
> > +	struct ti_sci_irq *this_irq;
> > +	struct hlist_node *tmp_node;
> > +	int ret;
> > +
> >   	pr_debug("%s: IRQ release with valid_params = 0x%x from src = %d, index = %d, to dst = %d, irq = %d,via ia_id = %d, vint = %d, global event = %d,status_bit = %d\n",
> >   		 __func__, valid_params, src_id, src_index,
> >   		 dst_id, dst_host_irq, ia_id, vint, global_event,
> >   		 vint_status_bit);
> > -	return ti_sci_manage_irq(handle, valid_params, src_id, src_index,
> > -				 dst_id, dst_host_irq, ia_id, vint,
> > -				 global_event, vint_status_bit, s_host,
> > -				 TI_SCI_MSG_FREE_IRQ);
> > +	ret = ti_sci_manage_irq(handle, valid_params, src_id, src_index,
> > +				dst_id, dst_host_irq, ia_id, vint,
> > +				global_event, vint_status_bit, s_host,
> > +				TI_SCI_MSG_FREE_IRQ);
> > +
> > +	if (ret)
> > +		return ret;
> > +
> > +	irq_desc.valid_params = valid_params;
> > +	irq_desc.src_id = src_id;
> > +	irq_desc.src_index = src_index;
> > +	irq_desc.dst_id = dst_id;
> > +	irq_desc.dst_host_irq = dst_host_irq;
> > +	irq_desc.ia_id = ia_id;
> > +	irq_desc.vint = vint;
> > +	irq_desc.global_event = global_event;
> > +	irq_desc.vint_status_bit = vint_status_bit;
> > +	irq_desc.secondary_host = s_host;
> > +
> > +	hash_for_each_possible_safe(info->irqs, this_irq, tmp_node, node,
> > +				    ti_sci_irq_hash(&irq_desc)) {
> > +		if (ti_sci_irq_equal(&irq_desc, &this_irq->desc)) {
> > +			hlist_del(&this_irq->node);
> > +			kfree(this_irq);
> > +			return 0;
> 
> 
> IMO,? you can restrict saving of irq and list management to fw having
> 
> BOARDCFG_MANAGED capability.
> 
> Dhurva ?

Yes I agree with Udit, we should gate hash operations by firmware capability.
Everywhere else you'll need to make it conditional accordingly.

Also, how much is the IRQ count usually? If IRQ count is typically small (< 50),
then won't a simple linked list be more efficient than a hash table? The
code becomes a bit more readable too that way IMO.
Take a call based on if there's really that many IRQs that LL's become
less practical.

-- 
Best regards,
Dhruva Gole
Texas Instruments Incorporated


From qijian.guo at nxp.com  Tue Dec 16 21:52:11 2025
From: qijian.guo at nxp.com (Joseph Guo)
Date: Wed, 17 Dec 2025 14:52:11 +0900
Subject: [PATCH v2 2/2] arm64: dts: freescale: add NXP FRDM-IMX91S board
 support
In-Reply-To: <20251215-imx91s-frdm-v2-2-87996bdaa59c@nxp.com>
References: <20251215-imx91s-frdm-v2-0-87996bdaa59c@nxp.com>
 <20251215-imx91s-frdm-v2-2-87996bdaa59c@nxp.com>
Message-ID: <aUJFC4ll033PzX7L@lsvm11u0000395.swis.ap-northeast-2.aws.nxp.com>

On Mon, Dec 15, 2025 at 05:42:52PM +0900, Yanan Yang wrote:
> Add DeviceTree support for the NXP FRDM-IMX91S development board based
> on the i.MX91 SoC. FRDM-IMX91S is a cost-optimized variant of FRDM-IMX91
> and differs in memory, storage, Ethernet, and PMIC configuration:
> 
> - 512MB LPDDR4 (FRDM-IMX91 uses 1GB)
> - 256MB FlexSPI-NAND (FRDM-IMX91 uses 8GB eMMC)
> - Single GbE port (FRDM-IMX91 has dual GbE)
> - PMIC PF9453 (FRDM-IMX91 uses PCA9451A)
> 
> This DT enables:
> - ADC1
> - UART1 and UART5
> - I2C bus and children nodes
> - USB and related nodes
> - uSDHC1 and uSDHC2
> - FlexSPI NAND flash
> - Watchdog3
> - Ethernet (eqos)
> - FlexCAN
> - MQS
> 
> Link: https://www.nxp.com/design/design-center/development-boards-and-designs/FRDM-IMX91S
> (FRDM-IMX91S board page)
> Link: https://www.nxp.com/design/design-center/development-boards-and-designs/FRDM-IMX91
> (FRDM-IMX91 board page)
> 
> Co-developed-by: Lei Xu <lei.xu at nxp.com>
> Signed-off-by: Lei Xu <lei.xu at nxp.com>
> Co-developed-by: Xiaofeng Wei <xiaofeng.wei at nxp.com>
> Signed-off-by: Xiaofeng Wei <xiaofeng.wei at nxp.com>
> Signed-off-by: Yanan Yang <yanan.yang at nxp.com>
> 
> ---
> Changes in v2:
> - Correct author name: removed extra period in "Yanan.Yang"
> - Removed aliases pointing to disabled nodes from DTS
> - Add "rtc0 = &pcf2131;" in aliases to make external RTC the primary device
> - Fix DT node name: change
>   "usdhc1_pwrseq: usdhc1_pwrseq" to "usdhc1_pwrseq: usdhc1-pwrseq"
> - Renamed LED node from 'status' to 'led-0' to comply with gpio-leds binding
> - Replace regulator-based transceiver (reg_can_stby) with CAN PHY (nxp,tja1051)
> - Replaced 'xceiver-supply' property with 'phys' in flexcan1 node
> - Adjusted alignment in fsl,pins property: used spaces between pin names and values for proper DTS style.
> ---
>  arch/arm64/boot/dts/freescale/Makefile             |   1 +
>  .../boot/dts/freescale/imx91-11x11-frdm-s.dts      | 677 +++++++++++++++++++++
>  2 files changed, 678 insertions(+)
>

Hi Yanan,

According to u-boot requirement. We should ensure the minimum difference to the U-boot dts and kernel DTS.
So I suggesst to add bootph- properties to the nodes should be initialized at u-boot stage.

Regards,
Joseph


From d-gole at ti.com  Tue Dec 16 22:07:27 2025
From: d-gole at ti.com (Dhruva Gole)
Date: Wed, 17 Dec 2025 11:37:27 +0530
Subject: [PATCH v3 4/4] firmware: ti_sci: restore clock context during
 resume in BOARDCFG_MANAGED mode
In-Reply-To: <20251205-ti-sci-jacinto-s2r-restore-irq-v3-4-d06963974ad4@bootlin.com>
References: <20251205-ti-sci-jacinto-s2r-restore-irq-v3-0-d06963974ad4@bootlin.com>
 <20251205-ti-sci-jacinto-s2r-restore-irq-v3-4-d06963974ad4@bootlin.com>
Message-ID: <20251217060727.idneboxj7kwslie2@lcpd911>

On Dec 05, 2025 at 15:28:26 +0100, Thomas Richard (TI.com) wrote:
> In BOARDCFG_MANAGED mode, the firmware cannot restore the clock rates and
> the clock parents. This responsibility is therefore delegated to the ti_sci
> driver, which uses clk_restore_context() to trigger the context_restore()
> operation for all registered clocks, including those managed by the sci-clk
> driver. The sci-clk driver implements the context_restore() operation to
> ensure rates and clock parents are correctly restored.
> 
> Signed-off-by: Thomas Richard (TI.com) <thomas.richard at bootlin.com>
> ---
>  drivers/firmware/ti_sci.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
> index 8d94745376e2a..6ef687e481c49 100644
> --- a/drivers/firmware/ti_sci.c
> +++ b/drivers/firmware/ti_sci.c
> @@ -9,6 +9,7 @@
>  #define pr_fmt(fmt) "%s: " fmt, __func__
>  
>  #include <linux/bitmap.h>
> +#include <linux/clk.h>
>  #include <linux/cpu.h>
>  #include <linux/debugfs.h>
>  #include <linux/export.h>
> @@ -3980,6 +3981,8 @@ static int ti_sci_resume_noirq(struct device *dev)
>  				if (ret)
>  					return ret;
>  			}
> +
> +			clk_restore_context();

Here as well, make it conditional to only BOARDCFG_MANAGED. Other
platforms/ firmwares have lived without this for a while now, and it's
evident that we don't always need this.

Thinking more about this, I think we're over using this BOARDCFG_MANAGED
mode a bit much. We should really just come up with new FW caps for
this, one for clk_restore , other for the previous IRQ restore patch.

That's the only way I can see this scaling. In future if we ever need
more devices that may actually be BOARDCFG_MANAGED, but don't need the
IRQ or clock restoration then the current approach won't work.

MODE should only be passed in the prepare_sleep, where it makes sense.
Using it for anything else just does not feel clean to me.

Thoughts?

-- 
Best regards,
Dhruva Gole
Texas Instruments Incorporated


From guoniu.zhou at oss.nxp.com  Tue Dec 16 22:11:24 2025
From: guoniu.zhou at oss.nxp.com (Guoniu Zhou)
Date: Wed, 17 Dec 2025 14:11:24 +0800
Subject: [PATCH v2 0/2] media: nxp: Add CSI Pixel Formatter support
Message-ID: <20251217-csi_formatter-v2-0-62168af80210@nxp.com>

CSI Pixel Formatter is a module found on i.MX95. It could unpack the
pixels received by the formatter and reformat them to meet the pixel
link format requirement.

This patch series adds a new v4l2 driver for CSI Pixel Formatter.

v4l2-compliance 1.28.1-5233, 64 bits, 64-bit time_t
v4l2-compliance SHA: fc15e229d9d3 2024-07-23 19:22:15

Compliance test for device /dev/v4l-subdev9:

Driver Info:
	Driver version   : 6.18.0
	Capabilities     : 0x00000002
		Streams Support
	Client Capabilities: 0x0000000000000003
streams interval-uses-which
Required ioctls:
	test VIDIOC_SUDBEV_QUERYCAP: OK
	test invalid ioctls: OK

Allow for multiple opens:
	test second /dev/v4l-subdev9 open: OK
	test VIDIOC_SUBDEV_QUERYCAP: OK
	test for unlimited opens: OK

Debug ioctls:
	test VIDIOC_LOG_STATUS: OK (Not Supported)

Input ioctls:
	test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
	test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
	test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
	test VIDIOC_ENUMAUDIO: OK (Not Supported)
	test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
	test VIDIOC_G/S_AUDIO: OK (Not Supported)
	Inputs: 0 Audio Inputs: 0 Tuners: 0

Output ioctls:
	test VIDIOC_G/S_MODULATOR: OK (Not Supported)
	test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
	test VIDIOC_ENUMAUDOUT: OK (Not Supported)
	test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
	test VIDIOC_G/S_AUDOUT: OK (Not Supported)
	Outputs: 0 Audio Outputs: 0 Modulators: 0

Input/Output configuration ioctls:
	test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
	test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
	test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
	test VIDIOC_G/S_EDID: OK (Not Supported)

Sub-Device routing ioctls:
	test Try VIDIOC_SUBDEV_G_ROUTING/VIDIOC_SUBDEV_S_ROUTING: OK
	test Active VIDIOC_SUBDEV_G_ROUTING/VIDIOC_SUBDEV_S_ROUTING: OK

Control ioctls:
	test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK (Not Supported)
	test VIDIOC_QUERYCTRL: OK (Not Supported)
	test VIDIOC_G/S_CTRL: OK (Not Supported)
	test VIDIOC_G/S/TRY_EXT_CTRLS: OK (Not Supported)
	test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK (Not Supported)
	test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
	Standard Controls: 0 Private Controls: 0

Format ioctls:
	test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK (Not Supported)
	test VIDIOC_G/S_PARM: OK (Not Supported)
	test VIDIOC_G_FBUF: OK (Not Supported)
	test VIDIOC_G_FMT: OK (Not Supported)
	test VIDIOC_TRY_FMT: OK (Not Supported)
	test VIDIOC_S_FMT: OK (Not Supported)
	test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
	test Cropping: OK (Not Supported)
	test Composing: OK (Not Supported)
	test Scaling: OK (Not Supported)

Codec ioctls:
	test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
	test VIDIOC_G_ENC_INDEX: OK (Not Supported)
	test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

Buffer ioctls:
	test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK (Not Supported)
	test CREATE_BUFS maximum buffers: OK
	test VIDIOC_REMOVE_BUFS: OK
	test VIDIOC_EXPBUF: OK (Not Supported)
	test Requests: OK (Not Supported)

Total for device /dev/v4l-subdev9: 47, Succeeded: 47, Failed: 0, Warnings: 0

Signed-off-by: Guoniu Zhou <guoniu.zhou at nxp.com>
---
Changes in v2:
- Delete "|" for description key. 
- Add empty line between child node and property.
- Delete labels for endpoint of child nodes.
  [PATCH 1/2] media: dt-bindings: Add CSI Pixel Formatter DT bindings

- Update commit message.
- Use the value defined by bellow macros directly since they are used only once.
  #define CSI_FORMATTER_DEF_MBUS_CODE	MEDIA_BUS_FMT_UYVY8_1X16
  #define CSI_FORMATTER_DEF_PIX_WIDTH	1920U
  #define CSI_FORMATTER_DEF_PIX_HEIGHT	1080U
  #define CSI_FORMATTER_MAX_PIX_WIDTH	0xffff
  #define CSI_FORMATTER_MAX_PIX_HEIGHT	0xffff
- Use macro pm_ptr() to fix build warning when CONFIG_PM is disabled. 
- Finish route loop by break statement, instead of goto.
- Return dev_err_probe() when meet errors in probe() function instead of dev_err().
- Remove MODULE_ALIAS().
- Refine .enable(.dsable)_stream callback implementation, include bellow changes:
  Add stream checking.
  Fix potential pm runtime count unbalance issue.
  Add stop stream error handling when enabling remote subdev stream.
- Use __free(fwnode_handle) to drop reference to a device node automatically.
  [PATCH 2/2] media: nxp: Add i.MX9 CSI pixel formatter v4l2 driver

- Link to v1: https://lore.kernel.org/r/20251203-csi_formatter-v1-0-eb9e1147b49e at nxp.com

---
Guoniu Zhou (2):
      media: dt-bindings: Add CSI Pixel Formatter DT bindings
      media: nxp: Add i.MX9 CSI pixel formatter v4l2 driver

 .../bindings/media/nxp,imx9-csi-formatter.yaml     |  98 +++
 MAINTAINERS                                        |   8 +
 drivers/media/platform/nxp/Kconfig                 |  14 +
 drivers/media/platform/nxp/Makefile                |   1 +
 drivers/media/platform/nxp/imx9-csi-formatter.c    | 881 +++++++++++++++++++++
 5 files changed, 1002 insertions(+)
---
base-commit: 1f2353f5a1af995efbf7bea44341aa0d03460b28
change-id: 20251125-csi_formatter-e6d29316dce6

Best regards,
-- 
Guoniu Zhou <guoniu.zhou at nxp.com>



From guoniu.zhou at oss.nxp.com  Tue Dec 16 22:11:25 2025
From: guoniu.zhou at oss.nxp.com (Guoniu Zhou)
Date: Wed, 17 Dec 2025 14:11:25 +0800
Subject: [PATCH v2 1/2] media: dt-bindings: Add CSI Pixel Formatter DT
 bindings
In-Reply-To: <20251217-csi_formatter-v2-0-62168af80210@nxp.com>
References: <20251217-csi_formatter-v2-0-62168af80210@nxp.com>
Message-ID: <20251217-csi_formatter-v2-1-62168af80210@nxp.com>

From: Guoniu Zhou <guoniu.zhou at nxp.com>

The i.MX9 CSI pixel formatting module uses packet info, pixel and
non-pixel data from the CSI-2 host controller and reformat them to
match Pixel Link(PL) definition.

Signed-off-by: Guoniu Zhou <guoniu.zhou at nxp.com>
---
 .../bindings/media/nxp,imx9-csi-formatter.yaml     | 98 ++++++++++++++++++++++
 1 file changed, 98 insertions(+)

diff --git a/Documentation/devicetree/bindings/media/nxp,imx9-csi-formatter.yaml b/Documentation/devicetree/bindings/media/nxp,imx9-csi-formatter.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a4ad4a0841d71646dacf5e564735dfe0a27cc1dc
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/nxp,imx9-csi-formatter.yaml
@@ -0,0 +1,98 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/nxp,imx9-csi-formatter.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: i.MX9 CSI Pixel Formatter
+
+maintainers:
+  - Guoniu Zhou <guoniu.zhou at nxp.com>
+
+description:
+  The CSI pixel formatting module uses packet info, pixel and non-pixel
+  data from the CSI-2 host controller and reformat them to match Pixel
+  Link(PL) definition.
+
+properties:
+  compatible:
+    const: fsl,imx9-csi-formatter
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 1
+
+  ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+
+    properties:
+      port at 0:
+        $ref: /schemas/graph.yaml#/$defs/port-base
+        unevaluatedProperties: false
+        description: MIPI CSI-2 RX IDI interface
+
+        properties:
+          endpoint:
+            $ref: video-interfaces.yaml#
+            unevaluatedProperties: false
+
+      port at 1:
+        $ref: /schemas/graph.yaml#/properties/port
+        description: Pixel Link Interface
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - power-domains
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/nxp,imx95-clock.h>
+
+    /*
+     * Power domain definitions from arch/arm64/boot/dts/freescale/imx95-power.h
+     */
+
+    #define IMX95_PD_CAMERA		3
+
+    formatter at 20 {
+        compatible = "fsl,imx9-csi-formatter";
+        reg = <0x20 0x100>;
+        clocks = <&cameramix_csr IMX95_CLK_CAMBLK_CSI2_FOR0>;
+        clock-names = "pixel";
+        power-domains = <&scmi_devpd IMX95_PD_CAMERA>;
+
+        ports {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            port at 0 {
+                reg = <0>;
+
+                endpoint {
+                    remote-endpoint = <&mipi_csi_0_out>;
+                };
+            };
+
+            port at 1 {
+                reg = <1>;
+
+                endpoint {
+                    remote-endpoint = <&isi_in_2>;
+                };
+            };
+        };
+    };

-- 
2.34.1



From guoniu.zhou at oss.nxp.com  Tue Dec 16 22:11:26 2025
From: guoniu.zhou at oss.nxp.com (Guoniu Zhou)
Date: Wed, 17 Dec 2025 14:11:26 +0800
Subject: [PATCH v2 2/2] media: nxp: Add i.MX9 CSI pixel formatter v4l2
 driver
In-Reply-To: <20251217-csi_formatter-v2-0-62168af80210@nxp.com>
References: <20251217-csi_formatter-v2-0-62168af80210@nxp.com>
Message-ID: <20251217-csi_formatter-v2-2-62168af80210@nxp.com>

From: Guoniu Zhou <guoniu.zhou at nxp.com>

The CSI pixel formatter is a module found on i.MX95 used to reformat
packet info, pixel and non-pixel data from CSI-2 host controller to
match Pixel Link(PL) definition.

Add data formatting support.

Signed-off-by: Guoniu Zhou <guoniu.zhou at nxp.com>
---
 MAINTAINERS                                     |   8 +
 drivers/media/platform/nxp/Kconfig              |  14 +
 drivers/media/platform/nxp/Makefile             |   1 +
 drivers/media/platform/nxp/imx9-csi-formatter.c | 881 ++++++++++++++++++++++++
 4 files changed, 904 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 4205ca007e076f869613032b51e8cc5bff06b98e..24681a787818c3e69f93dcc220ee9838cef99886 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18626,6 +18626,14 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/media/nxp,imx8-jpeg.yaml
 F:	drivers/media/platform/nxp/imx-jpeg
 
+NXP i.MX 9 CSI PIXEL FORMATTER V4L2 DRIVER
+M:	Guoniu Zhou <guoniu.zhou at nxp.com>
+L:	imx at lists.linux.dev
+L:	linux-media at vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/media/nxp,imx9-csi-formatter.yaml
+F:	drivers/media/platform/nxp/imx9-csi-formatter.c
+
 NXP i.MX CLOCK DRIVERS
 M:	Abel Vesa <abelvesa at kernel.org>
 R:	Peng Fan <peng.fan at nxp.com>
diff --git a/drivers/media/platform/nxp/Kconfig b/drivers/media/platform/nxp/Kconfig
index 40e3436669e213fdc5da70821dc0b420e1821f4f..a7bb62a2b0249659ffdfeac50fa488aee9590a87 100644
--- a/drivers/media/platform/nxp/Kconfig
+++ b/drivers/media/platform/nxp/Kconfig
@@ -28,6 +28,20 @@ config VIDEO_IMX8MQ_MIPI_CSI2
 	  Video4Linux2 driver for the MIPI CSI-2 receiver found on the i.MX8MQ
 	  SoC.
 
+config VIDEO_IMX9_CSI_FORMATTER
+	tristate "NXP i.MX9 CSI Pixel Formatter driver"
+	depends on ARCH_MXC || COMPILE_TEST
+	depends on VIDEO_DEV
+	select MEDIA_CONTROLLER
+	select V4L2_FWNODE
+	select VIDEO_V4L2_SUBDEV_API
+	help
+	  This driver provides support for the CSI Pixel Formatter found on
+	  i.MX9 series SoC. This module unpacks the pixels received by the
+	  formatter and reformats them to meet the pixel link format requirement.
+
+	  Say Y here to enable CSI Pixel Formater module for i.MX9 SoC.
+
 config VIDEO_IMX_MIPI_CSIS
 	tristate "NXP MIPI CSI-2 CSIS receiver found on i.MX7 and i.MX8 models"
 	depends on ARCH_MXC || COMPILE_TEST
diff --git a/drivers/media/platform/nxp/Makefile b/drivers/media/platform/nxp/Makefile
index 4d90eb71365259ebdda84ea58483e1c4131d3ac7..39ba5660ba923141e7637b01b5b34a021dad7bb3 100644
--- a/drivers/media/platform/nxp/Makefile
+++ b/drivers/media/platform/nxp/Makefile
@@ -6,6 +6,7 @@ obj-y += imx8-isi/
 
 obj-$(CONFIG_VIDEO_IMX7_CSI) += imx7-media-csi.o
 obj-$(CONFIG_VIDEO_IMX8MQ_MIPI_CSI2) += imx8mq-mipi-csi2.o
+obj-$(CONFIG_VIDEO_IMX9_CSI_FORMATTER) += imx9-csi-formatter.o
 obj-$(CONFIG_VIDEO_IMX_MIPI_CSIS) += imx-mipi-csis.o
 obj-$(CONFIG_VIDEO_IMX_PXP) += imx-pxp.o
 obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o
diff --git a/drivers/media/platform/nxp/imx9-csi-formatter.c b/drivers/media/platform/nxp/imx9-csi-formatter.c
new file mode 100644
index 0000000000000000000000000000000000000000..62ba929639d2ef0ea1b5134153c286d0d511688d
--- /dev/null
+++ b/drivers/media/platform/nxp/imx9-csi-formatter.c
@@ -0,0 +1,881 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2025 NXP
+ */
+
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include <media/mipi-csi2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mc.h>
+#include <media/v4l2-subdev.h>
+
+/* CSI Pixel Formatter registers map */
+
+#define CSI_VCx_INTERLACED_LINE_CNT(x)		(0x00 + (x) * 0x04)
+#define INTERLACED_ODD_LINE_CNT_SET(x)		FIELD_PREP(GENMASK(13, 0), (x))
+#define INTERLACED_EVEN_LINE_CNT_SET(x)		FIELD_PREP(GENMASK(29, 16), (x))
+
+#define CSI_VC_INTERLACED_CTRL			0x20
+
+#define CSI_VC_INTERLACED_ERR			0x24
+#define CSI_VC_ERR_MASK				GENMASK(7, 0)
+#define CSI_VC_ERR(vc)				BIT((vc))
+
+#define CSI_VC_YUV420_FIRST_LINE_EVEN		0x28
+#define YUV420_FIRST_LINE_EVEN(vc)		BIT((vc))
+
+#define CSI_RAW32_CTRL				0x30
+#define CSI_VCX_RAW32_MODE(vc)			BIT((vc))
+#define CSI_VCX_RAW32_SWAP_MODE(vc)		BIT((vc) + 8)
+
+#define STREAM_FENCING_CTRL			0x34
+#define CSI_VCx_STREAM_FENCING(vc)		BIT((vc))
+#define CSI_VCx_STREAM_FENCING_RST(vc)		BIT((vc) + 8)
+
+#define STREAM_FENCING_STS			0x38
+#define STREAM_FENCING_STS_MASK			GENMASK(7, 0)
+
+#define CSI_VCX_NON_PIXEL_DATA_TYPE(vc)		(0x40 + (vc) * 0x04)
+
+#define CSI_VCX_PIXEL_DATA_CTRL(vc)		(0x60 + (vc) * 0x04)
+#define NEW_VC(x)				FIELD_PREP(GENMASK(3, 1), x)
+#define REROUTE_VC_ENABLE			BIT(0)
+
+#define CSI_VCx_ROUTE_PIXEL_DATA_TYPE(vc)	(0x80 + (vc) * 0x04)
+
+#define CSI_VCx_NON_PIXEL_DATA_CTRL(vc)		(0xa0 + (vc) * 0x04)
+
+#define CSI_VCx_PIXEL_DATA_TYPE(vc)		(0xc0 + (vc) * 0x04)
+
+#define CSI_VCx_PIXEL_DATA_TYPE_ERR(vc)		(0xe0 + (vc) * 0x04)
+
+#define CSI_FORMATTER_PAD_SINK			0
+#define CSI_FORMATTER_PAD_SOURCE		1
+#define CSI_FORMATTER_PAD_NUM			2
+
+#define CSI_FORMATTER_DRV_NAME			"csi-pixel-formatter"
+#define CSI_FORMATTER_VC_MAX			8
+
+struct formatter_pix_format {
+	u32 code;
+	u32 data_type;
+};
+
+struct csi_formatter {
+	struct device *dev;
+	struct regmap *regs;
+	struct clk *clk;
+
+	struct v4l2_subdev sd;
+	struct v4l2_subdev *csi_sd;
+	struct v4l2_async_notifier notifier;
+	struct v4l2_mbus_framefmt format[CSI_FORMATTER_PAD_NUM];
+	struct media_pad pads[CSI_FORMATTER_PAD_NUM];
+	const struct formatter_pix_format *fmt;
+
+	u16 remote_pad;
+	u32 reg_offset;
+	u64 enabled_streams;
+};
+
+struct dt_index {
+	u8 dtype;
+	u8 index;
+};
+
+static const struct dt_index formatter_dt_to_index_map[] = {
+	{ .dtype = MIPI_CSI2_DT_YUV420_8B,        .index = 0 },
+	{ .dtype = MIPI_CSI2_DT_YUV420_8B_LEGACY, .index = 2 },
+	{ .dtype = MIPI_CSI2_DT_YUV422_8B,        .index = 6 },
+	{ .dtype = MIPI_CSI2_DT_RGB444,		  .index = 8 },
+	{ .dtype = MIPI_CSI2_DT_RGB555,           .index = 9 },
+	{ .dtype = MIPI_CSI2_DT_RGB565,           .index = 10 },
+	{ .dtype = MIPI_CSI2_DT_RGB666,           .index = 11 },
+	{ .dtype = MIPI_CSI2_DT_RGB888,           .index = 12 },
+	{ .dtype = MIPI_CSI2_DT_RAW6,             .index = 16 },
+	{ .dtype = MIPI_CSI2_DT_RAW7,             .index = 17 },
+	{ .dtype = MIPI_CSI2_DT_RAW8,             .index = 18 },
+	{ .dtype = MIPI_CSI2_DT_RAW10,            .index = 19 },
+	{ .dtype = MIPI_CSI2_DT_RAW12,            .index = 20 },
+	{ .dtype = MIPI_CSI2_DT_RAW14,            .index = 21 },
+	{ .dtype = MIPI_CSI2_DT_RAW16,            .index = 22 },
+};
+
+static const struct formatter_pix_format formats[] = {
+	/* YUV formats */
+	{
+		.code = MEDIA_BUS_FMT_UYVY8_1X16,
+		.data_type = MIPI_CSI2_DT_YUV422_8B,
+	},
+	/* RGB formats */
+	{
+		.code = MEDIA_BUS_FMT_RGB565_1X16,
+		.data_type = MIPI_CSI2_DT_RGB565,
+	}, {
+		.code = MEDIA_BUS_FMT_RGB888_1X24,
+		.data_type = MIPI_CSI2_DT_RGB888,
+	},
+	/* RAW (Bayer and greyscale) formats. */
+	{
+		.code = MEDIA_BUS_FMT_SBGGR8_1X8,
+		.data_type = MIPI_CSI2_DT_RAW8,
+	}, {
+		.code = MEDIA_BUS_FMT_SGBRG8_1X8,
+		.data_type = MIPI_CSI2_DT_RAW8,
+	}, {
+		.code = MEDIA_BUS_FMT_SGRBG8_1X8,
+		.data_type = MIPI_CSI2_DT_RAW8,
+	}, {
+		.code = MEDIA_BUS_FMT_SRGGB8_1X8,
+		.data_type = MIPI_CSI2_DT_RAW8,
+	}, {
+		.code = MEDIA_BUS_FMT_Y8_1X8,
+		.data_type = MIPI_CSI2_DT_RAW8,
+	}, {
+		.code = MEDIA_BUS_FMT_SBGGR10_1X10,
+		.data_type = MIPI_CSI2_DT_RAW10,
+	}, {
+		.code = MEDIA_BUS_FMT_SGBRG10_1X10,
+		.data_type = MIPI_CSI2_DT_RAW10,
+	}, {
+		.code = MEDIA_BUS_FMT_SGRBG10_1X10,
+		.data_type = MIPI_CSI2_DT_RAW10,
+	}, {
+		.code = MEDIA_BUS_FMT_SRGGB10_1X10,
+		.data_type = MIPI_CSI2_DT_RAW10,
+	}, {
+		.code = MEDIA_BUS_FMT_Y10_1X10,
+		.data_type = MIPI_CSI2_DT_RAW10,
+	}, {
+		.code = MEDIA_BUS_FMT_SBGGR12_1X12,
+		.data_type = MIPI_CSI2_DT_RAW12,
+	}, {
+		.code = MEDIA_BUS_FMT_SGBRG12_1X12,
+		.data_type = MIPI_CSI2_DT_RAW12,
+	}, {
+		.code = MEDIA_BUS_FMT_SGRBG12_1X12,
+		.data_type = MIPI_CSI2_DT_RAW12,
+	}, {
+		.code = MEDIA_BUS_FMT_SRGGB12_1X12,
+		.data_type = MIPI_CSI2_DT_RAW12,
+	}, {
+		.code = MEDIA_BUS_FMT_Y12_1X12,
+		.data_type = MIPI_CSI2_DT_RAW12,
+	}, {
+		.code = MEDIA_BUS_FMT_SBGGR14_1X14,
+		.data_type = MIPI_CSI2_DT_RAW14,
+	}, {
+		.code = MEDIA_BUS_FMT_SGBRG14_1X14,
+		.data_type = MIPI_CSI2_DT_RAW14,
+	}, {
+		.code = MEDIA_BUS_FMT_SGRBG14_1X14,
+		.data_type = MIPI_CSI2_DT_RAW14,
+	}, {
+		.code = MEDIA_BUS_FMT_SRGGB14_1X14,
+		.data_type = MIPI_CSI2_DT_RAW14,
+	}, {
+		.code = MEDIA_BUS_FMT_SBGGR16_1X16,
+		.data_type = MIPI_CSI2_DT_RAW16,
+	}, {
+		.code = MEDIA_BUS_FMT_SGBRG16_1X16,
+		.data_type = MIPI_CSI2_DT_RAW16,
+	}, {
+		.code = MEDIA_BUS_FMT_SGRBG16_1X16,
+		.data_type = MIPI_CSI2_DT_RAW16,
+	}, {
+		.code = MEDIA_BUS_FMT_SRGGB16_1X16,
+		.data_type = MIPI_CSI2_DT_RAW16,
+	}
+};
+
+static const struct v4l2_mbus_framefmt formatter_default_fmt = {
+	.code = MEDIA_BUS_FMT_UYVY8_1X16,
+	.width = 1920U,
+	.height = 1080U,
+	.field = V4L2_FIELD_NONE,
+	.colorspace = V4L2_COLORSPACE_SMPTE170M,
+	.xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SMPTE170M),
+	.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SMPTE170M),
+	.quantization = V4L2_QUANTIZATION_LIM_RANGE,
+};
+
+static const struct formatter_pix_format *find_csi_format(u32 code)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(formats); i++)
+		if (code == formats[i].code)
+			return &formats[i];
+
+	return &formats[0];
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+static inline struct csi_formatter *sd_to_formatter(struct v4l2_subdev *sdev)
+{
+	return container_of(sdev, struct csi_formatter, sd);
+}
+
+static int __formatter_subdev_set_routing(struct v4l2_subdev *sd,
+					  struct v4l2_subdev_state *state,
+					  struct v4l2_subdev_krouting *routing)
+{
+	int ret;
+
+	if (routing->num_routes > V4L2_FRAME_DESC_ENTRY_MAX)
+		return -EINVAL;
+
+	ret = v4l2_subdev_routing_validate(sd, routing,
+					   V4L2_SUBDEV_ROUTING_ONLY_1_TO_1);
+	if (ret)
+		return ret;
+
+	return v4l2_subdev_set_routing_with_fmt(sd, state, routing,
+						&formatter_default_fmt);
+}
+
+static int formatter_subdev_init_state(struct v4l2_subdev *sd,
+				       struct v4l2_subdev_state *sd_state)
+{
+	struct v4l2_subdev_route routes[] = {
+		{
+			.sink_pad = CSI_FORMATTER_PAD_SINK,
+			.sink_stream = 0,
+			.source_pad = CSI_FORMATTER_PAD_SOURCE,
+			.source_stream = 0,
+			.flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
+		},
+	};
+
+	struct v4l2_subdev_krouting routing = {
+		.num_routes = ARRAY_SIZE(routes),
+		.routes = routes,
+	};
+
+	return __formatter_subdev_set_routing(sd, sd_state, &routing);
+}
+
+static int formatter_subdev_enum_mbus_code(struct v4l2_subdev *sd,
+					   struct v4l2_subdev_state *sd_state,
+					   struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->pad == CSI_FORMATTER_PAD_SOURCE) {
+		struct v4l2_mbus_framefmt *fmt;
+
+		if (code->index > 0)
+			return -EINVAL;
+
+		fmt = v4l2_subdev_state_get_format(sd_state, code->pad,
+						   code->stream);
+		code->code = fmt->code;
+		return 0;
+	}
+
+	if (code->index >= ARRAY_SIZE(formats))
+		return -EINVAL;
+
+	code->code = formats[code->index].code;
+
+	return 0;
+}
+
+static int formatter_subdev_set_fmt(struct v4l2_subdev *sd,
+				    struct v4l2_subdev_state *sd_state,
+				    struct v4l2_subdev_format *sdformat)
+{
+	struct csi_formatter *formatter = sd_to_formatter(sd);
+	struct formatter_pix_format const *format;
+	struct v4l2_mbus_framefmt *fmt;
+
+	if (sdformat->pad == CSI_FORMATTER_PAD_SOURCE)
+		return v4l2_subdev_get_fmt(sd, sd_state, sdformat);
+
+	/*
+	 * Validate the media bus code and clamp and align the size.
+	 *
+	 * The total number of bits per line must be a multiple of 8. We thus
+	 * need to align the width for formats that are not multiples of 8
+	 * bits.
+	 */
+	format = find_csi_format(sdformat->format.code);
+
+	v4l_bound_align_image(&sdformat->format.width, 1, 0xffff, 2,
+			      &sdformat->format.height, 1, 0xffff, 0, 0);
+
+	fmt = v4l2_subdev_state_get_format(sd_state, sdformat->pad,
+					   sdformat->stream);
+	*fmt = sdformat->format;
+
+	/* Set default code if user set an invalid value */
+	fmt->code = format->code;
+
+	/* Propagate the format from sink stream to source stream */
+	fmt = v4l2_subdev_state_get_opposite_stream_format(sd_state, sdformat->pad,
+							   sdformat->stream);
+	if (!fmt)
+		return -EINVAL;
+
+	*fmt = sdformat->format;
+
+	/* Store the CSIS format descriptor for active formats. */
+	if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+		formatter->fmt = format;
+
+	return 0;
+}
+
+static int formatter_subdev_get_frame_desc(struct v4l2_subdev *sd,
+					   unsigned int pad,
+					   struct v4l2_mbus_frame_desc *fd)
+{
+	struct csi_formatter *formatter = sd_to_formatter(sd);
+	struct v4l2_mbus_frame_desc csi_fd;
+	struct v4l2_subdev_route *route;
+	struct v4l2_subdev_state *state;
+	int ret;
+
+	if (pad != CSI_FORMATTER_PAD_SOURCE)
+		return -EINVAL;
+
+	ret = v4l2_subdev_call(formatter->csi_sd, pad, get_frame_desc,
+			       formatter->remote_pad, &csi_fd);
+	if (ret)
+		return ret;
+
+	if (csi_fd.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) {
+		dev_err(formatter->dev,
+			"Frame descriptor does not describe CSI-2 link\n");
+		return -EINVAL;
+	}
+
+	memset(fd, 0, sizeof(*fd));
+
+	fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2;
+
+	state = v4l2_subdev_lock_and_get_active_state(sd);
+
+	for_each_active_route(&state->routing, route) {
+		struct v4l2_mbus_frame_desc_entry *entry = NULL;
+		unsigned int i;
+
+		if (route->source_pad != pad)
+			continue;
+
+		for (i = 0; i < csi_fd.num_entries; ++i) {
+			if (csi_fd.entry[i].stream == route->sink_stream) {
+				entry = &csi_fd.entry[i];
+				break;
+			}
+		}
+
+		if (!entry) {
+			dev_err(formatter->dev,
+				"Failed to find stream from source frames desc\n");
+			ret = -EPIPE;
+			break;
+		}
+
+		fd->entry[fd->num_entries].stream = route->source_stream;
+		fd->entry[fd->num_entries].flags = entry->flags;
+		fd->entry[fd->num_entries].length = entry->length;
+		fd->entry[fd->num_entries].pixelcode = entry->pixelcode;
+		fd->entry[fd->num_entries].bus.csi2.vc = entry->bus.csi2.vc;
+		fd->entry[fd->num_entries].bus.csi2.dt = entry->bus.csi2.dt;
+
+		fd->num_entries++;
+	}
+
+	v4l2_subdev_unlock_state(state);
+	return ret;
+}
+
+static int formatter_subdev_set_routing(struct v4l2_subdev *sd,
+					struct v4l2_subdev_state *state,
+					enum v4l2_subdev_format_whence which,
+					struct v4l2_subdev_krouting *routing)
+{
+	if (which == V4L2_SUBDEV_FORMAT_ACTIVE &&
+	    media_entity_is_streaming(&sd->entity))
+		return -EBUSY;
+
+	return __formatter_subdev_set_routing(sd, state, routing);
+}
+
+static inline void formatter_write(struct csi_formatter *formatter,
+				   unsigned int reg, unsigned int value)
+{
+	u32 offset = formatter->reg_offset;
+
+	regmap_write(formatter->regs, reg + offset, value);
+}
+
+static u8 get_index_by_dt(u8 data_type)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(formatter_dt_to_index_map); ++i)
+		if (data_type == formatter_dt_to_index_map[i].dtype)
+			break;
+
+	if (i == ARRAY_SIZE(formatter_dt_to_index_map))
+		return formatter_dt_to_index_map[0].index;
+
+	return formatter_dt_to_index_map[i].index;
+}
+
+static int get_vc(struct csi_formatter *formatter, unsigned int stream)
+{
+	struct v4l2_mbus_frame_desc source_fd;
+	struct v4l2_mbus_frame_desc_entry *entry = NULL;
+	unsigned int i;
+	int ret;
+
+	/*
+	 * Return virtual channel 0 as default value when remote subdev
+	 * don't implement .get_frame_desc subdev callback
+	 */
+	ret = v4l2_subdev_call(formatter->csi_sd, pad, get_frame_desc,
+			       formatter->remote_pad, &source_fd);
+	if (ret < 0)
+		return (ret == -ENOIOCTLCMD) ? 0 : ret;
+
+	for (i = 0; i < source_fd.num_entries; ++i) {
+		if (source_fd.entry[i].stream == stream) {
+			entry = &source_fd.entry[i];
+			break;
+		}
+	}
+
+	if (!entry) {
+		dev_err(formatter->dev,
+			"Can't find valid frame desc corresponding to stream %d\n", stream);
+		return -EPIPE;
+	}
+
+	return entry->bus.csi2.vc;
+}
+
+static int csi_formatter_start_stream(struct csi_formatter *formatter,
+				      u64 stream_mask)
+{
+	const struct formatter_pix_format *fmt = formatter->fmt;
+	unsigned int i;
+	u32 val;
+	int vc;
+
+	for (i = 0; i < V4L2_FRAME_DESC_ENTRY_MAX; ++i) {
+		if (stream_mask & BIT(i))
+			break;
+	}
+
+	if (i == V4L2_FRAME_DESC_ENTRY_MAX) {
+		dev_err(formatter->dev, "Stream ID out of range\n");
+		return -EINVAL;
+	}
+
+	val = BIT(get_index_by_dt(fmt->data_type));
+	vc = get_vc(formatter, i);
+
+	if (vc < 0 || vc > CSI_FORMATTER_VC_MAX) {
+		dev_err(formatter->dev, "Invalid virtual channel(%d)\n", vc);
+		return -EINVAL;
+	}
+
+	formatter_write(formatter, CSI_VCx_PIXEL_DATA_TYPE(vc), val);
+
+	return 0;
+}
+
+static int csi_formatter_stop_stream(struct csi_formatter *formatter,
+				     u64 stream_mask)
+{
+	unsigned int i;
+	int vc;
+
+	for (i = 0; i < V4L2_FRAME_DESC_ENTRY_MAX; ++i) {
+		if (stream_mask & BIT(i))
+			break;
+	}
+
+	if (i == V4L2_FRAME_DESC_ENTRY_MAX) {
+		dev_err(formatter->dev, "Stream ID out of range\n");
+		return -EINVAL;
+	}
+
+	vc = get_vc(formatter, i);
+
+	if (vc < 0 || vc > CSI_FORMATTER_VC_MAX) {
+		dev_err(formatter->dev, "Invalid virtual channel(%d)\n", vc);
+		return -EINVAL;
+	}
+
+	formatter_write(formatter, CSI_VCx_PIXEL_DATA_TYPE(vc), 0);
+
+	return 0;
+}
+
+static int formatter_subdev_enable_streams(struct v4l2_subdev *sd,
+					   struct v4l2_subdev_state *state,
+					   u32 pad, u64 streams_mask)
+{
+	struct csi_formatter *formatter = sd_to_formatter(sd);
+	struct device *dev = formatter->dev;
+	u64 sink_streams;
+	int ret;
+
+	sink_streams = v4l2_subdev_state_xlate_streams(state,
+						       CSI_FORMATTER_PAD_SOURCE,
+						       CSI_FORMATTER_PAD_SINK,
+						       &streams_mask);
+	if (!sink_streams || !streams_mask)
+		return -EINVAL;
+
+	dev_dbg(dev, "remote sd: %s pad: %u, sink_stream:0x%llx\n",
+		formatter->csi_sd->name, formatter->remote_pad, sink_streams);
+
+	if (!formatter->csi_sd) {
+		dev_err(dev, "CSI controller don't link with formatter\n");
+		return -EPIPE;
+	}
+
+	if (!formatter->enabled_streams) {
+		ret = pm_runtime_resume_and_get(formatter->dev);
+		if (ret < 0) {
+			dev_err(dev, "Formatter runtime get fail\n");
+			return ret;
+		}
+	}
+
+	ret = csi_formatter_start_stream(formatter, streams_mask);
+	if (ret)
+		goto runtime_put;
+
+	ret = v4l2_subdev_enable_streams(formatter->csi_sd,
+					 formatter->remote_pad,
+					 sink_streams);
+	if (ret)
+		goto stop_stream;
+
+	formatter->enabled_streams |= streams_mask;
+
+	return 0;
+
+stop_stream:
+	csi_formatter_stop_stream(formatter, streams_mask);
+runtime_put:
+	if (!formatter->enabled_streams)
+		pm_runtime_put(formatter->dev);
+	return ret;
+}
+
+static int formatter_subdev_disable_streams(struct v4l2_subdev *sd,
+					    struct v4l2_subdev_state *state,
+					    u32 pad, u64 streams_mask)
+{
+	struct csi_formatter *formatter = sd_to_formatter(sd);
+	u64 sink_streams;
+	int ret;
+
+	sink_streams = v4l2_subdev_state_xlate_streams(state,
+						       CSI_FORMATTER_PAD_SOURCE,
+						       CSI_FORMATTER_PAD_SINK,
+						       &streams_mask);
+	if (!sink_streams || !streams_mask)
+		return -EINVAL;
+
+	ret = v4l2_subdev_disable_streams(formatter->csi_sd, formatter->remote_pad,
+					  sink_streams);
+	if (ret)
+		return ret;
+
+	ret = csi_formatter_stop_stream(formatter, streams_mask);
+	if (ret)
+		return ret;
+
+	formatter->enabled_streams &= ~streams_mask;
+
+	if (!formatter->enabled_streams)
+		pm_runtime_put(formatter->dev);
+
+	return 0;
+}
+
+static const struct v4l2_subdev_pad_ops formatter_subdev_pad_ops = {
+	.enum_mbus_code		= formatter_subdev_enum_mbus_code,
+	.get_fmt		= v4l2_subdev_get_fmt,
+	.set_fmt		= formatter_subdev_set_fmt,
+	.get_frame_desc		= formatter_subdev_get_frame_desc,
+	.set_routing		= formatter_subdev_set_routing,
+	.enable_streams		= formatter_subdev_enable_streams,
+	.disable_streams	= formatter_subdev_disable_streams,
+};
+
+static const struct v4l2_subdev_ops formatter_subdev_ops = {
+	.pad = &formatter_subdev_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops formatter_internal_ops = {
+	.init_state = formatter_subdev_init_state,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+static const struct media_entity_operations formatter_entity_ops = {
+	.link_validate	= v4l2_subdev_link_validate,
+	.get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1,
+};
+
+static int csi_formatter_subdev_init(struct csi_formatter *formatter)
+{
+	struct v4l2_subdev *sd = &formatter->sd;
+	int ret;
+
+	v4l2_subdev_init(sd, &formatter_subdev_ops);
+
+	snprintf(sd->name, sizeof(sd->name), "%s", dev_name(formatter->dev));
+	sd->internal_ops = &formatter_internal_ops;
+
+	sd->owner = THIS_MODULE;
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+		     V4L2_SUBDEV_FL_HAS_EVENTS |
+		     V4L2_SUBDEV_FL_STREAMS;
+	sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
+	sd->entity.ops = &formatter_entity_ops;
+	sd->dev = formatter->dev;
+
+	formatter->pads[CSI_FORMATTER_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+	formatter->pads[CSI_FORMATTER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+	ret = media_entity_pads_init(&sd->entity, CSI_FORMATTER_PAD_NUM,
+				     formatter->pads);
+	if (ret) {
+		dev_err(formatter->dev, "Failed to init pads\n");
+		return ret;
+	}
+
+	ret = v4l2_subdev_init_finalize(sd);
+	if (ret)
+		media_entity_cleanup(&sd->entity);
+
+	return ret;
+}
+
+static inline struct csi_formatter *
+notifier_to_formatter(struct v4l2_async_notifier *n)
+{
+	return container_of(n, struct csi_formatter, notifier);
+}
+
+static int csi_formatter_notify_bound(struct v4l2_async_notifier *notifier,
+				      struct v4l2_subdev *sd,
+				      struct v4l2_async_connection *asc)
+{
+	const unsigned int link_flags = MEDIA_LNK_FL_IMMUTABLE
+				      | MEDIA_LNK_FL_ENABLED;
+	struct csi_formatter *formatter = notifier_to_formatter(notifier);
+	struct v4l2_subdev *sdev = &formatter->sd;
+	struct media_pad *sink = &sdev->entity.pads[CSI_FORMATTER_PAD_SINK];
+	struct media_pad *remote_pad;
+	int ret;
+
+	formatter->csi_sd = sd;
+
+	dev_dbg(formatter->dev, "Bound subdev: %s pad\n", sd->name);
+
+	ret = v4l2_create_fwnode_links_to_pad(sd, sink, link_flags);
+	if (ret < 0)
+		return ret;
+
+	remote_pad = media_pad_remote_pad_first(sink);
+	if (!remote_pad) {
+		dev_err(formatter->dev, "Pipe not setup correctly\n");
+		return -EPIPE;
+	}
+	formatter->remote_pad = remote_pad->index;
+
+	return 0;
+}
+
+static const struct v4l2_async_notifier_operations formatter_notify_ops = {
+	.bound = csi_formatter_notify_bound,
+};
+
+static int csi_formatter_async_register(struct csi_formatter *formatter)
+{
+	struct device *dev = formatter->dev;
+	struct v4l2_async_connection *asc;
+	struct fwnode_handle *ep __free(fwnode_handle) = NULL;
+	int ret;
+
+	v4l2_async_subdev_nf_init(&formatter->notifier, &formatter->sd);
+
+	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0,
+					     FWNODE_GRAPH_ENDPOINT_NEXT);
+	if (!ep)
+		return -ENOTCONN;
+
+	asc = v4l2_async_nf_add_fwnode_remote(&formatter->notifier, ep,
+					      struct v4l2_async_connection);
+	if (IS_ERR(asc))
+		return PTR_ERR(asc);
+
+	formatter->notifier.ops = &formatter_notify_ops;
+
+	ret = v4l2_async_nf_register(&formatter->notifier);
+	if (ret)
+		return ret;
+
+	return v4l2_async_register_subdev(&formatter->sd);
+}
+
+/* -----------------------------------------------------------------------------
+ * Suspend/resume
+ */
+
+static int csi_formatter_system_suspend(struct device *dev)
+{
+	return pm_runtime_force_suspend(dev);
+}
+
+static int csi_formatter_system_resume(struct device *dev)
+{
+	int ret;
+
+	ret = pm_runtime_force_resume(dev);
+	if (ret < 0) {
+		dev_err(dev, "force resume %s failed!\n", dev_name(dev));
+		return ret;
+	}
+
+	return 0;
+}
+
+static int csi_formatter_runtime_suspend(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct csi_formatter *formatter = sd_to_formatter(sd);
+
+	clk_disable_unprepare(formatter->clk);
+
+	return 0;
+}
+
+static int csi_formatter_runtime_resume(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct csi_formatter *formatter = sd_to_formatter(sd);
+
+	return clk_prepare_enable(formatter->clk);
+}
+
+static const struct dev_pm_ops csi_formatter_pm_ops = {
+	SYSTEM_SLEEP_PM_OPS(csi_formatter_system_suspend,
+			    csi_formatter_system_resume)
+	RUNTIME_PM_OPS(csi_formatter_runtime_suspend,
+		       csi_formatter_runtime_resume, NULL)
+};
+
+static int csi_formatter_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct csi_formatter *formatter;
+	u32 val;
+	int ret;
+
+	formatter = devm_kzalloc(dev, sizeof(*formatter), GFP_KERNEL);
+	if (!formatter)
+		return -ENOMEM;
+
+	formatter->dev = dev;
+
+	formatter->regs = syscon_node_to_regmap(dev->parent->of_node);
+	if (IS_ERR(formatter->regs))
+		return dev_err_probe(dev, PTR_ERR(formatter->regs),
+				     "Failed to get csi formatter regmap\n");
+
+	ret = of_property_read_u32(dev->of_node, "reg", &val);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "Failed to get csi formatter reg property\n");
+
+	formatter->reg_offset = val;
+
+	formatter->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(formatter->clk))
+		return dev_err_probe(dev, PTR_ERR(formatter->clk),
+				     "Failed to get pixel clock\n");
+
+	ret = csi_formatter_subdev_init(formatter);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "formatter subdev init fail\n");
+
+	/* Initialize formatter pixel format */
+	formatter->fmt = find_csi_format(formatter_default_fmt.code);
+
+	ret = csi_formatter_async_register(formatter);
+	if (ret < 0) {
+		v4l2_subdev_cleanup(&formatter->sd);
+		return dev_err_probe(dev, ret, "Async register failed\n");
+	}
+
+	platform_set_drvdata(pdev, &formatter->sd);
+
+	/* Enable runtime PM. */
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static void csi_formatter_remove(struct platform_device *pdev)
+{
+	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+	struct csi_formatter *formatter = sd_to_formatter(sd);
+
+	v4l2_async_nf_unregister(&formatter->notifier);
+	v4l2_async_nf_cleanup(&formatter->notifier);
+	v4l2_async_unregister_subdev(&formatter->sd);
+
+	pm_runtime_disable(&pdev->dev);
+	media_entity_cleanup(&formatter->sd.entity);
+	pm_runtime_set_suspended(&pdev->dev);
+}
+
+static const struct of_device_id csi_formatter_of_match[] = {
+	{ .compatible = "fsl,imx9-csi-formatter" },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, csi_formatter_of_match);
+
+static struct platform_driver csi_formatter_device_driver = {
+	.driver = {
+		.owner          = THIS_MODULE,
+		.name           = CSI_FORMATTER_DRV_NAME,
+		.of_match_table = csi_formatter_of_match,
+		.pm             = pm_ptr(&csi_formatter_pm_ops),
+	},
+	.probe  = csi_formatter_probe,
+	.remove = csi_formatter_remove,
+};
+
+module_platform_driver(csi_formatter_device_driver);
+
+MODULE_AUTHOR("NXP Semiconductor, Inc.");
+MODULE_DESCRIPTION("NXP i.MX9 CSI Pixel Formatter driver");
+MODULE_LICENSE("GPL");

-- 
2.34.1



From dev.jain at arm.com  Tue Dec 16 22:23:25 2025
From: dev.jain at arm.com (Dev Jain)
Date: Wed, 17 Dec 2025 11:53:25 +0530
Subject: [PATCH v2 2/3] mm: rmap: support batched checks of the references
 for large folios
In-Reply-To: <545dba5e899634bc6c8ca782417d16fef3bd049f.1765439381.git.baolin.wang@linux.alibaba.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <545dba5e899634bc6c8ca782417d16fef3bd049f.1765439381.git.baolin.wang@linux.alibaba.com>
Message-ID: <17380b96-3a9e-46f9-b22b-0e770f7f1b4f@arm.com>


On 11/12/25 1:46 pm, Baolin Wang wrote:
> Currently, folio_referenced_one() always checks the young flag for each PTE
> sequentially, which is inefficient for large folios. This inefficiency is
> especially noticeable when reclaiming clean file-backed large folios, where
> folio_referenced() is observed as a significant performance hotspot.
>
> Moreover, on Arm architecture, which supports contiguous PTEs, there is already
> an optimization to clear the young flags for PTEs within a contiguous range.
> However, this is not sufficient. We can extend this to perform batched operations
> for the entire large folio (which might exceed the contiguous range: CONT_PTE_SIZE).
>
> Introduce a new API: clear_flush_young_ptes() to facilitate batched checking
> of the young flags and flushing TLB entries, thereby improving performance
> during large folio reclamation.
>
> Performance testing:
> Allocate 10G clean file-backed folios by mmap() in a memory cgroup, and try to
> reclaim 8G file-backed folios via the memory.reclaim interface. I can observe
> 33% performance improvement on my Arm64 32-core server (and 10%+ improvement
> on my X86 machine). Meanwhile, the hotspot folio_check_references() dropped
> from approximately 35% to around 5%.
>
> W/o patchset:
> real	0m1.518s
> user	0m0.000s
> sys	0m1.518s
>
> W/ patchset:
> real	0m1.018s
> user	0m0.000s
> sys	0m1.018s
>
> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
> ---
>  arch/arm64/include/asm/pgtable.h | 11 +++++++++++
>  include/linux/mmu_notifier.h     |  9 +++++----
>  include/linux/pgtable.h          | 19 +++++++++++++++++++
>  mm/rmap.c                        | 22 ++++++++++++++++++++--
>  4 files changed, 55 insertions(+), 6 deletions(-)
>
> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
> index e03034683156..a865bd8c46a3 100644
> --- a/arch/arm64/include/asm/pgtable.h
> +++ b/arch/arm64/include/asm/pgtable.h
> @@ -1869,6 +1869,17 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
>  	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
>  }
>  
> +#define clear_flush_young_ptes clear_flush_young_ptes
> +static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
> +					unsigned long addr, pte_t *ptep,
> +					unsigned int nr)
> +{
> +	if (likely(nr == 1))
> +		return __ptep_clear_flush_young(vma, addr, ptep);
> +
> +	return contpte_clear_flush_young_ptes(vma, addr, ptep, nr);
> +}
> +
>  #define wrprotect_ptes wrprotect_ptes
>  static __always_inline void wrprotect_ptes(struct mm_struct *mm,
>  				unsigned long addr, pte_t *ptep, unsigned int nr)
> diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h
> index d1094c2d5fb6..be594b274729 100644
> --- a/include/linux/mmu_notifier.h
> +++ b/include/linux/mmu_notifier.h
> @@ -515,16 +515,17 @@ static inline void mmu_notifier_range_init_owner(
>  	range->owner = owner;
>  }
>  
> -#define ptep_clear_flush_young_notify(__vma, __address, __ptep)		\
> +#define ptep_clear_flush_young_notify(__vma, __address, __ptep, __nr)	\
>  ({									\
>  	int __young;							\
>  	struct vm_area_struct *___vma = __vma;				\
>  	unsigned long ___address = __address;				\
> -	__young = ptep_clear_flush_young(___vma, ___address, __ptep);	\
> +	unsigned int ___nr = __nr;					\
> +	__young = clear_flush_young_ptes(___vma, ___address, __ptep, ___nr);	\
>  	__young |= mmu_notifier_clear_flush_young(___vma->vm_mm,	\
>  						  ___address,		\
>  						  ___address +		\
> -							PAGE_SIZE);	\
> +						nr * PAGE_SIZE);	\
>  	__young;							\
>  })

Do we have an existing bug here, in that mmu_notifier_clear_flush_young() should
have been called for CONT_PTES length if the folio was contpte mapped?

>  
> @@ -650,7 +651,7 @@ static inline void mmu_notifier_subscriptions_destroy(struct mm_struct *mm)
>  
>  #define mmu_notifier_range_update_to_read_only(r) false
>  
> -#define ptep_clear_flush_young_notify ptep_clear_flush_young
> +#define ptep_clear_flush_young_notify clear_flush_young_ptes
>  #define pmdp_clear_flush_young_notify pmdp_clear_flush_young
>  #define ptep_clear_young_notify ptep_test_and_clear_young
>  #define pmdp_clear_young_notify pmdp_test_and_clear_young
> diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
> index b13b6f42be3c..c7d0fd228cb7 100644
> --- a/include/linux/pgtable.h
> +++ b/include/linux/pgtable.h
> @@ -947,6 +947,25 @@ static inline void wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
>  }
>  #endif
>  
> +#ifndef clear_flush_young_ptes
> +static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
> +					 unsigned long addr, pte_t *ptep,
> +					 unsigned int nr)
> +{
> +	int young = 0;
> +
> +	for (;;) {
> +		young |= ptep_clear_flush_young(vma, addr, ptep);
> +		if (--nr == 0)
> +			break;
> +		ptep++;
> +		addr += PAGE_SIZE;
> +	}
> +
> +	return young;
> +}
> +#endif
> +
>  /*
>   * On some architectures hardware does not set page access bit when accessing
>   * memory page, it is responsibility of software setting this bit. It brings
> diff --git a/mm/rmap.c b/mm/rmap.c
> index d6799afe1114..ec232165c47d 100644
> --- a/mm/rmap.c
> +++ b/mm/rmap.c
> @@ -827,9 +827,11 @@ static bool folio_referenced_one(struct folio *folio,
>  	struct folio_referenced_arg *pra = arg;
>  	DEFINE_FOLIO_VMA_WALK(pvmw, folio, vma, address, 0);
>  	int ptes = 0, referenced = 0;
> +	unsigned int nr;
>  
>  	while (page_vma_mapped_walk(&pvmw)) {
>  		address = pvmw.address;
> +		nr = 1;
>  
>  		if (vma->vm_flags & VM_LOCKED) {
>  			ptes++;
> @@ -874,9 +876,21 @@ static bool folio_referenced_one(struct folio *folio,
>  			if (lru_gen_look_around(&pvmw))
>  				referenced++;
>  		} else if (pvmw.pte) {
> +			if (folio_test_large(folio)) {
> +				unsigned long end_addr = pmd_addr_end(address, vma->vm_end);
> +				unsigned int max_nr = (end_addr - address) >> PAGE_SHIFT;
> +				pte_t pteval = ptep_get(pvmw.pte);
> +
> +				nr = folio_pte_batch(folio, pvmw.pte, pteval, max_nr);
> +			}
> +
> +			ptes += nr;
>  			if (ptep_clear_flush_young_notify(vma, address,
> -						pvmw.pte))
> +						pvmw.pte, nr))
>  				referenced++;
> +			/* Skip the batched PTEs */
> +			pvmw.pte += nr - 1;
> +			pvmw.address += (nr - 1) * PAGE_SIZE;
>  		} else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) {
>  			if (pmdp_clear_flush_young_notify(vma, address,
>  						pvmw.pmd))
> @@ -886,7 +900,11 @@ static bool folio_referenced_one(struct folio *folio,
>  			WARN_ON_ONCE(1);
>  		}
>  
> -		pra->mapcount--;
> +		pra->mapcount -= nr;
> +		if (ptes == pvmw.nr_pages) {
> +			page_vma_mapped_walk_done(&pvmw);
> +			break;
> +		}
>  	}
>  
>  	if (referenced)


From lance.yang at linux.dev  Tue Dec 16 22:27:22 2025
From: lance.yang at linux.dev (Lance Yang)
Date: Wed, 17 Dec 2025 14:27:22 +0800
Subject: [PATCH] watchdog: softlockup: panic when lockup duration exceeds
 N thresholds
In-Reply-To: <20251216074521.2796-1-lirongqing@baidu.com>
References: <20251216074521.2796-1-lirongqing@baidu.com>
Message-ID: <e216e4ae-b882-454d-be8f-24f21a3549d9@linux.dev>



On 2025/12/16 15:45, lirongqing wrote:
> From: Li RongQing <lirongqing at baidu.com>
> 
> The softlockup_panic sysctl is currently a binary option: panic immediately
> or never panic on soft lockups.
> 
> Panicking on any soft lockup, regardless of duration, can be overly
> aggressive for brief stalls that may be caused by legitimate operations.
> Conversely, never panicking may allow severe system hangs to persist
> undetected.
> 
> Extend softlockup_panic to accept an integer threshold, allowing the kernel
> to panic only when the normalized lockup duration exceeds N watchdog
> threshold periods. This provides finer-grained control to distinguish
> between transient delays and persistent system failures.
> 
> The accepted values are:
> - 0: Don't panic (unchanged)
> - 1: Panic when duration >= 1 * threshold (20s default, original behavior)
> - N > 1: Panic when duration >= N * threshold (e.g., 2 = 40s, 3 = 60s.)
> 
> The original behavior is preserved for values 0 and 1, maintaining full
> backward compatibility while allowing systems to tolerate brief lockups
> while still catching severe, persistent hangs.

Thanks! Just a couple of minor things below ;)

> 
> Signed-off-by: Li RongQing <lirongqing at baidu.com>
> ---
>   Documentation/admin-guide/kernel-parameters.txt      | 10 +++++-----
>   arch/arm/configs/aspeed_g5_defconfig                 |  2 +-
>   arch/arm/configs/pxa3xx_defconfig                    |  2 +-
>   arch/openrisc/configs/or1klitex_defconfig            |  2 +-
>   arch/powerpc/configs/skiroot_defconfig               |  2 +-
>   drivers/gpu/drm/ci/arm.config                        |  2 +-
>   drivers/gpu/drm/ci/arm64.config                      |  2 +-
>   drivers/gpu/drm/ci/x86_64.config                     |  2 +-
>   kernel/watchdog.c                                    |  8 +++++---
>   lib/Kconfig.debug                                    | 13 +++++++------
>   tools/testing/selftests/bpf/config                   |  2 +-
>   tools/testing/selftests/wireguard/qemu/kernel.config |  2 +-
>   12 files changed, 26 insertions(+), 23 deletions(-)
> 
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index a8d0afd..27c5f96 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -6934,12 +6934,12 @@ Kernel parameters
>   
>   	softlockup_panic=
>   			[KNL] Should the soft-lockup detector generate panics.
> -			Format: 0 | 1
> +			Format: <int>
>   
> -			A value of 1 instructs the soft-lockup detector
> -			to panic the machine when a soft-lockup occurs. It is
> -			also controlled by the kernel.softlockup_panic sysctl
> -			and CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC, which is the
> +			A value of non-zero instructs the soft-lockup detector
> +			to panic the machine when a soft-lockup duration exceeds
> +			N thresholds. It is also controlled by the kernel.softlockup_panic
> +			sysctl and CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC, which is the
>   			respective build-time switch to that functionality.

Seems like kernel/configs/debug.config still has the old format
"# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set" ...

Should be updated to "CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=0", right?

>   
>   	softlockup_all_cpu_backtrace=
> diff --git a/arch/arm/configs/aspeed_g5_defconfig b/arch/arm/configs/aspeed_g5_defconfig
> index 2e6ea13..ec558e5 100644
> --- a/arch/arm/configs/aspeed_g5_defconfig
> +++ b/arch/arm/configs/aspeed_g5_defconfig
> @@ -306,7 +306,7 @@ CONFIG_SCHED_STACK_END_CHECK=y
>   CONFIG_PANIC_ON_OOPS=y
>   CONFIG_PANIC_TIMEOUT=-1
>   CONFIG_SOFTLOCKUP_DETECTOR=y
> -CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
> +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=1
>   CONFIG_BOOTPARAM_HUNG_TASK_PANIC=1
>   CONFIG_WQ_WATCHDOG=y
>   # CONFIG_SCHED_DEBUG is not set
> diff --git a/arch/arm/configs/pxa3xx_defconfig b/arch/arm/configs/pxa3xx_defconfig
> index 07d422f..fb272e3 100644
> --- a/arch/arm/configs/pxa3xx_defconfig
> +++ b/arch/arm/configs/pxa3xx_defconfig
> @@ -100,7 +100,7 @@ CONFIG_PRINTK_TIME=y
>   CONFIG_DEBUG_KERNEL=y
>   CONFIG_MAGIC_SYSRQ=y
>   CONFIG_DEBUG_SHIRQ=y
> -CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
> +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=1
>   # CONFIG_SCHED_DEBUG is not set
>   CONFIG_DEBUG_SPINLOCK=y
>   CONFIG_DEBUG_SPINLOCK_SLEEP=y
> diff --git a/arch/openrisc/configs/or1klitex_defconfig b/arch/openrisc/configs/or1klitex_defconfig
> index fb1eb9a..984b0e3 100644
> --- a/arch/openrisc/configs/or1klitex_defconfig
> +++ b/arch/openrisc/configs/or1klitex_defconfig
> @@ -52,5 +52,5 @@ CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity,bpf"
>   CONFIG_PRINTK_TIME=y
>   CONFIG_PANIC_ON_OOPS=y
>   CONFIG_SOFTLOCKUP_DETECTOR=y
> -CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
> +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=1
>   CONFIG_BUG_ON_DATA_CORRUPTION=y
> diff --git a/arch/powerpc/configs/skiroot_defconfig b/arch/powerpc/configs/skiroot_defconfig
> index 2b71a6d..a4114fc 100644
> --- a/arch/powerpc/configs/skiroot_defconfig
> +++ b/arch/powerpc/configs/skiroot_defconfig
> @@ -289,7 +289,7 @@ CONFIG_SCHED_STACK_END_CHECK=y
>   CONFIG_DEBUG_STACKOVERFLOW=y
>   CONFIG_PANIC_ON_OOPS=y
>   CONFIG_SOFTLOCKUP_DETECTOR=y
> -CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
> +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=1
>   CONFIG_HARDLOCKUP_DETECTOR=y
>   CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y
>   CONFIG_WQ_WATCHDOG=y
> diff --git a/drivers/gpu/drm/ci/arm.config b/drivers/gpu/drm/ci/arm.config
> index 411e814..d7c5167 100644
> --- a/drivers/gpu/drm/ci/arm.config
> +++ b/drivers/gpu/drm/ci/arm.config
> @@ -52,7 +52,7 @@ CONFIG_TMPFS=y
>   CONFIG_PROVE_LOCKING=n
>   CONFIG_DEBUG_LOCKDEP=n
>   CONFIG_SOFTLOCKUP_DETECTOR=n
> -CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=n
> +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=0
>   
>   CONFIG_FW_LOADER_COMPRESS=y
>   
> diff --git a/drivers/gpu/drm/ci/arm64.config b/drivers/gpu/drm/ci/arm64.config
> index fddfbd4..ea0e307 100644
> --- a/drivers/gpu/drm/ci/arm64.config
> +++ b/drivers/gpu/drm/ci/arm64.config
> @@ -161,7 +161,7 @@ CONFIG_TMPFS=y
>   CONFIG_PROVE_LOCKING=n
>   CONFIG_DEBUG_LOCKDEP=n
>   CONFIG_SOFTLOCKUP_DETECTOR=y
> -CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
> +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=1
>   
>   CONFIG_DETECT_HUNG_TASK=y
>   
> diff --git a/drivers/gpu/drm/ci/x86_64.config b/drivers/gpu/drm/ci/x86_64.config
> index 8eaba388..7ac98a7 100644
> --- a/drivers/gpu/drm/ci/x86_64.config
> +++ b/drivers/gpu/drm/ci/x86_64.config
> @@ -47,7 +47,7 @@ CONFIG_TMPFS=y
>   CONFIG_PROVE_LOCKING=n
>   CONFIG_DEBUG_LOCKDEP=n
>   CONFIG_SOFTLOCKUP_DETECTOR=y
> -CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
> +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=1
>   
>   CONFIG_DETECT_HUNG_TASK=y
>   
> diff --git a/kernel/watchdog.c b/kernel/watchdog.c
> index 0685e3a..a5fa116 100644
> --- a/kernel/watchdog.c
> +++ b/kernel/watchdog.c
> @@ -363,7 +363,7 @@ static struct cpumask watchdog_allowed_mask __read_mostly;
>   
>   /* Global variables, exported for sysctl */
>   unsigned int __read_mostly softlockup_panic =
> -			IS_ENABLED(CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC);
> +			CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC;
>   
>   static bool softlockup_initialized __read_mostly;
>   static u64 __read_mostly sample_period;
> @@ -879,7 +879,9 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
>   
>   		add_taint(TAINT_SOFTLOCKUP, LOCKDEP_STILL_OK);
>   		sys_info(softlockup_si_mask & ~SYS_INFO_ALL_BT);
> -		if (softlockup_panic)
> +		duration = duration / get_softlockup_thresh();

Nit: reusing "duration" here makes things a bit confusing, maybe just
use a temp variable?

	thresh_count = duration / get_softlockup_thresh();

	if (softlockup_panic && thresh_count >= softlockup_panic)
		panic("softlockup: hung tasks");

Cheers,
Lance

> +
> +		if (softlockup_panic && duration >= softlockup_panic)
>   			panic("softlockup: hung tasks");
>   	}
>   
> @@ -1228,7 +1230,7 @@ static const struct ctl_table watchdog_sysctls[] = {
>   		.mode		= 0644,
>   		.proc_handler	= proc_dointvec_minmax,
>   		.extra1		= SYSCTL_ZERO,
> -		.extra2		= SYSCTL_ONE,
> +		.extra2		= SYSCTL_INT_MAX,
>   	},
>   	{
>   		.procname	= "softlockup_sys_info",
> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> index ba36939..17a7a77 100644
> --- a/lib/Kconfig.debug
> +++ b/lib/Kconfig.debug
> @@ -1110,13 +1110,14 @@ config SOFTLOCKUP_DETECTOR_INTR_STORM
>   	  the CPU stats and the interrupt counts during the "soft lockups".
>   
>   config BOOTPARAM_SOFTLOCKUP_PANIC
> -	bool "Panic (Reboot) On Soft Lockups"
> +	int "Panic (Reboot) On Soft Lockups"
>   	depends on SOFTLOCKUP_DETECTOR
> +	default 0
>   	help
> -	  Say Y here to enable the kernel to panic on "soft lockups",
> -	  which are bugs that cause the kernel to loop in kernel
> -	  mode for more than 20 seconds (configurable using the watchdog_thresh
> -	  sysctl), without giving other tasks a chance to run.
> +	  Set to a non-zero value N to enable the kernel to panic on "soft
> +	  lockups", which are bugs that cause the kernel to loop in kernel
> +	  mode for more than (N * 20 seconds) (configurable using the
> +	  watchdog_thresh sysctl), without giving other tasks a chance to run.
>   
>   	  The panic can be used in combination with panic_timeout,
>   	  to cause the system to reboot automatically after a
> @@ -1124,7 +1125,7 @@ config BOOTPARAM_SOFTLOCKUP_PANIC
>   	  high-availability systems that have uptime guarantees and
>   	  where a lockup must be resolved ASAP.
>   
> -	  Say N if unsure.
> +	  Say 0 if unsure.
>   
>   config HAVE_HARDLOCKUP_DETECTOR_BUDDY
>   	bool
> diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config
> index 558839e..2485538 100644
> --- a/tools/testing/selftests/bpf/config
> +++ b/tools/testing/selftests/bpf/config
> @@ -1,6 +1,6 @@
>   CONFIG_BLK_DEV_LOOP=y
>   CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y
> -CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
> +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=1
>   CONFIG_BPF=y
>   CONFIG_BPF_EVENTS=y
>   CONFIG_BPF_JIT=y
> diff --git a/tools/testing/selftests/wireguard/qemu/kernel.config b/tools/testing/selftests/wireguard/qemu/kernel.config
> index 0504c11..bb89d2d 100644
> --- a/tools/testing/selftests/wireguard/qemu/kernel.config
> +++ b/tools/testing/selftests/wireguard/qemu/kernel.config
> @@ -80,7 +80,7 @@ CONFIG_HARDLOCKUP_DETECTOR=y
>   CONFIG_WQ_WATCHDOG=y
>   CONFIG_DETECT_HUNG_TASK=y
>   CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y
> -CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
> +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=1
>   CONFIG_BOOTPARAM_HUNG_TASK_PANIC=1
>   CONFIG_PANIC_TIMEOUT=-1
>   CONFIG_STACKTRACE=y



From xiaoshun.xu at mediatek.corp-partner.google.com  Tue Dec 16 22:34:09 2025
From: xiaoshun.xu at mediatek.corp-partner.google.com (Xiaoshun Xu)
Date: Wed, 17 Dec 2025 14:34:09 +0800
Subject: [PATCH v2 0/4] soc: mediatek: Add devapc support for MT8189
Message-ID: <20251217063429.1157084-1-xiaoshun.xu@mediatek.corp-partner.google.com>


External email : Please do not click links or open attachments until you have verified the sender or the content.


From: Xiaoshun Xu <xiaoshun.xu at mediatek.com>

Based on tag: next-20251216, linux-next/master

This series of patches add support for Mediatek devapc of MT8189 soc.

Changes in v2:
  - Updated cover letter subject
  - Updated yaml for dt-bindings
  - Add support for MT8189 devapc
  - Refine devapc clock control flow
  - Refine devapc interrupt handler

Changes in v1:
Xiaoshun Xu (4):
  dt-bindings: soc: mediatek: devapc: Add bindings for MT8189
  soc: mediatek: mtk-devapc: Add support for MT8189 devapc
  soc: mediatek: mtk-devapc: refine devapc clock control
  soc: mediatek: mtk-devapc: refine devapc interrupt handler

 .../bindings/soc/mediatek/devapc.yaml         |  10 +-
 drivers/soc/mediatek/mtk-devapc.c             | 189 ++++++++++++++----
 2 files changed, 159 insertions(+), 40 deletions(-)

--
2.45.2



From xiaoshun.xu at mediatek.corp-partner.google.com  Tue Dec 16 22:34:10 2025
From: xiaoshun.xu at mediatek.corp-partner.google.com (Xiaoshun Xu)
Date: Wed, 17 Dec 2025 14:34:10 +0800
Subject: [PATCH v2 1/4] dt-bindings: soc: mediatek: devapc: Add bindings for MT8189
In-Reply-To: <20251217063429.1157084-1-xiaoshun.xu@mediatek.corp-partner.google.com>
References: <20251217063429.1157084-1-xiaoshun.xu@mediatek.corp-partner.google.com>
Message-ID: <20251217063429.1157084-2-xiaoshun.xu@mediatek.corp-partner.google.com>


External email : Please do not click links or open attachments until you have verified the sender or the content.


From: Xiaoshun Xu <xiaoshun.xu at mediatek.com>

Extend the devapc device tree bindings to support the MediaTek MT8189
SoC. This includes:

- Adding "mediatek,mt8189-devapc" to the list of compatible strings.
- Introducing the "vio-idx-num" property to specify the number of bus
  slaves managed by devapc.

These changes enable proper configuration and integration of devapc on
MT8189 platforms, ensuring accurate device matching and resource
allocation in the device tree.

Signed-off-by: Xiaoshun Xu <xiaoshun.xu at mediatek.com>
---
 .../devicetree/bindings/soc/mediatek/devapc.yaml       | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/soc/mediatek/devapc.yaml b/Documentation/devicetree/bindings/soc/mediatek/devapc.yaml
index 99e2caafeadf..06a096440331 100644
--- a/Documentation/devicetree/bindings/soc/mediatek/devapc.yaml
+++ b/Documentation/devicetree/bindings/soc/mediatek/devapc.yaml
@@ -14,13 +14,14 @@ description: |
   analysis and countermeasures.

 maintainers:
-  - Neal Liu <neal.liu at mediatek.com>
+  - Xiaoshun Xu <xiaoshun.xu at mediatek.com>

 properties:
   compatible:
     enum:
       - mediatek,mt6779-devapc
       - mediatek,mt8186-devapc
+      - mediatek,mt8189-devapc

   reg:
     description: The base address of devapc register bank
@@ -30,6 +31,10 @@ properties:
     description: A single interrupt specifier
     maxItems: 1

+  vio-idx-num:
+    description: Describe the number of bus slaves controlled by devapc
+    $ref: /schemas/types.yaml#/definitions/uint32
+
   clocks:
     description: Contains module clock source and clock names
     maxItems: 1
@@ -42,8 +47,6 @@ required:
   - compatible
   - reg
   - interrupts
-  - clocks
-  - clock-names

 additionalProperties: false

@@ -55,6 +58,7 @@ examples:
     devapc: devapc at 10207000 {
       compatible = "mediatek,mt6779-devapc";
       reg = <0x10207000 0x1000>;
+      vio-idx-num = <132>;
       interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_LOW>;
       clocks = <&infracfg_ao CLK_INFRA_DEVICE_APC>;
       clock-names = "devapc-infra-clock";
--
2.45.2



From xiaoshun.xu at mediatek.corp-partner.google.com  Tue Dec 16 22:34:12 2025
From: xiaoshun.xu at mediatek.corp-partner.google.com (Xiaoshun Xu)
Date: Wed, 17 Dec 2025 14:34:12 +0800
Subject: [PATCH v2 3/4] soc: mediatek: mtk-devapc: refine devapc clock control
In-Reply-To: <20251217063429.1157084-1-xiaoshun.xu@mediatek.corp-partner.google.com>
References: <20251217063429.1157084-1-xiaoshun.xu@mediatek.corp-partner.google.com>
Message-ID: <20251217063429.1157084-4-xiaoshun.xu@mediatek.corp-partner.google.com>


External email : Please do not click links or open attachments until you have verified the sender or the content.


From: Xiaoshun Xu <xiaoshun.xu at mediatek.com>

Because the new devapc design, devapc clock is controlled by
HW power domains, the control flow of devapc clock is not
necessary, but to maintain compatibility with legacy ICs,
keep this part of code.

Signed-off-by: Xiaoshun Xu <xiaoshun.xu at mediatek.com>
---
 drivers/soc/mediatek/mtk-devapc.c | 23 ++++++++++++++++++-----
 1 file changed, 18 insertions(+), 5 deletions(-)

diff --git a/drivers/soc/mediatek/mtk-devapc.c b/drivers/soc/mediatek/mtk-devapc.c
index b91df4cf7a61..61628b941d92 100644
--- a/drivers/soc/mediatek/mtk-devapc.c
+++ b/drivers/soc/mediatek/mtk-devapc.c
@@ -373,16 +373,27 @@ static int mtk_devapc_probe(struct platform_device *pdev)
                goto err;
        }

-       ctx->infra_clk = devm_clk_get_enabled(&pdev->dev, "devapc-infra-clock");
+       /*
+        * The new design of DAPC clock is controlled by HW power domains,
+        * making it unnecessary to provide the clock control driver.
+        */
+       ctx->infra_clk = devm_clk_get_optional(&pdev->dev, "devapc-infra-clock");
        if (IS_ERR(ctx->infra_clk)) {
-               ret = -EINVAL;
-               goto err;
+               dev_err(ctx->dev, "Cannot get devapc clock from CCF\n");
+               ctx->infra_clk = NULL;
+       } else {
+               if (clk_prepare_enable(ctx->infra_clk)) {
+                       ret = -EINVAL;
+                       goto err;
+               }
        }

        ret = devm_request_irq(&pdev->dev, devapc_irq, devapc_violation_irq,
-                              IRQF_TRIGGER_NONE, "devapc", ctx);
-       if (ret)
+                              IRQF_TRIGGER_NONE | IRQF_SHARED, "devapc", ctx);
+       if (ret) {
+               clk_disable_unprepare(ctx->infra_clk);
                goto err;
+       }

        platform_set_drvdata(pdev, ctx);

@@ -401,6 +412,8 @@ static void mtk_devapc_remove(struct platform_device *pdev)

        stop_devapc(ctx);

+       clk_disable_unprepare(ctx->infra_clk);
+
        iounmap(ctx->base);
 }

--
2.45.2



From xiaoshun.xu at mediatek.corp-partner.google.com  Tue Dec 16 22:34:11 2025
From: xiaoshun.xu at mediatek.corp-partner.google.com (Xiaoshun Xu)
Date: Wed, 17 Dec 2025 14:34:11 +0800
Subject: [PATCH v2 2/4] soc: mediatek: mtk-devapc: Add support for MT8189 devapc
In-Reply-To: <20251217063429.1157084-1-xiaoshun.xu@mediatek.corp-partner.google.com>
References: <20251217063429.1157084-1-xiaoshun.xu@mediatek.corp-partner.google.com>
Message-ID: <20251217063429.1157084-3-xiaoshun.xu@mediatek.corp-partner.google.com>


External email : Please do not click links or open attachments until you have verified the sender or the content.


From: Xiaoshun Xu <xiaoshun.xu at mediatek.com>

Add support for MT8189 devapc, devapc debug registers have new version,
so refine the structure of devapc_regs_ofs_xxxx to devapc_regs_ofs_verX,
and rename the infra_base to base in mtk_devapc_context because devapc
not only access the infra_base to dump debug information when violation
happens

Signed-off-by: Xiaoshun Xu <xiaoshun.xu at mediatek.com>
---
 drivers/soc/mediatek/mtk-devapc.c | 158 ++++++++++++++++++++++++------
 1 file changed, 127 insertions(+), 31 deletions(-)

diff --git a/drivers/soc/mediatek/mtk-devapc.c b/drivers/soc/mediatek/mtk-devapc.c
index f54c966138b5..b91df4cf7a61 100644
--- a/drivers/soc/mediatek/mtk-devapc.c
+++ b/drivers/soc/mediatek/mtk-devapc.c
@@ -26,9 +26,19 @@ struct mtk_devapc_vio_dbgs {
                        u32 addr_h:4;
                        u32 resv:4;
                } dbg0_bits;
+
+               struct {
+                       u32 dmnid:6;
+                       u32 vio_w:1;
+                       u32 vio_r:1;
+                       u32 addr_h:4;
+                       u32 resv:20;
+               } dbg0_bits_ver2;
        };

        u32 vio_dbg1;
+       u32 vio_dbg2;
+       u32 vio_dbg3;
 };

 struct mtk_devapc_regs_ofs {
@@ -37,6 +47,8 @@ struct mtk_devapc_regs_ofs {
        u32 vio_sta_offset;
        u32 vio_dbg0_offset;
        u32 vio_dbg1_offset;
+       u32 vio_dbg2_offset;
+       u32 vio_dbg3_offset;
        u32 apc_con_offset;
        u32 vio_shift_sta_offset;
        u32 vio_shift_sel_offset;
@@ -44,16 +56,20 @@ struct mtk_devapc_regs_ofs {
 };

 struct mtk_devapc_data {
-       /* numbers of violation index */
-       u32 vio_idx_num;
+       u32 version;
+       /* Default numbers of violation index */
+       u32 default_vio_idx_num;
        const struct mtk_devapc_regs_ofs *regs_ofs;
 };

 struct mtk_devapc_context {
        struct device *dev;
-       void __iomem *infra_base;
+       void __iomem *base;
        struct clk *infra_clk;
        const struct mtk_devapc_data *data;
+
+       /* numbers of violation index */
+       u32 vio_idx_num;
 };

 static void clear_vio_status(struct mtk_devapc_context *ctx)
@@ -61,12 +77,12 @@ static void clear_vio_status(struct mtk_devapc_context *ctx)
        void __iomem *reg;
        int i;

-       reg = ctx->infra_base + ctx->data->regs_ofs->vio_sta_offset;
+       reg = ctx->base + ctx->data->regs_ofs->vio_sta_offset;

-       for (i = 0; i < VIO_MOD_TO_REG_IND(ctx->data->vio_idx_num) - 1; i++)
+       for (i = 0; i < VIO_MOD_TO_REG_IND(ctx->vio_idx_num - 1); i++)
                writel(GENMASK(31, 0), reg + 4 * i);

-       writel(GENMASK(VIO_MOD_TO_REG_OFF(ctx->data->vio_idx_num) - 1, 0),
+       writel(GENMASK(VIO_MOD_TO_REG_OFF(ctx->vio_idx_num - 1), 0),
               reg + 4 * i);
 }

@@ -76,22 +92,22 @@ static void mask_module_irq(struct mtk_devapc_context *ctx, bool mask)
        u32 val;
        int i;

-       reg = ctx->infra_base + ctx->data->regs_ofs->vio_mask_offset;
+       reg = ctx->base + ctx->data->regs_ofs->vio_mask_offset;

        if (mask)
                val = GENMASK(31, 0);
        else
                val = 0;

-       for (i = 0; i < VIO_MOD_TO_REG_IND(ctx->data->vio_idx_num) - 1; i++)
+       for (i = 0; i < VIO_MOD_TO_REG_IND(ctx->vio_idx_num - 1); i++)
                writel(val, reg + 4 * i);

        val = readl(reg + 4 * i);
        if (mask)
-               val |= GENMASK(VIO_MOD_TO_REG_OFF(ctx->data->vio_idx_num) - 1,
+               val |= GENMASK(VIO_MOD_TO_REG_OFF(ctx->vio_idx_num - 1),
                               0);
        else
-               val &= ~GENMASK(VIO_MOD_TO_REG_OFF(ctx->data->vio_idx_num) - 1,
+               val &= ~GENMASK(VIO_MOD_TO_REG_OFF(ctx->vio_idx_num - 1),
                                0);

        writel(val, reg + 4 * i);
@@ -118,11 +134,11 @@ static int devapc_sync_vio_dbg(struct mtk_devapc_context *ctx)
        int ret;
        u32 val;

-       pd_vio_shift_sta_reg = ctx->infra_base +
+       pd_vio_shift_sta_reg = ctx->base +
                               ctx->data->regs_ofs->vio_shift_sta_offset;
-       pd_vio_shift_sel_reg = ctx->infra_base +
+       pd_vio_shift_sel_reg = ctx->base +
                               ctx->data->regs_ofs->vio_shift_sel_offset;
-       pd_vio_shift_con_reg = ctx->infra_base +
+       pd_vio_shift_con_reg = ctx->base +
                               ctx->data->regs_ofs->vio_shift_con_offset;

        /* Find the minimum shift group which has violation */
@@ -163,22 +179,52 @@ static void devapc_extract_vio_dbg(struct mtk_devapc_context *ctx)
        struct mtk_devapc_vio_dbgs vio_dbgs;
        void __iomem *vio_dbg0_reg;
        void __iomem *vio_dbg1_reg;
+       void __iomem *vio_dbg2_reg;
+       void __iomem *vio_dbg3_reg;
+       u32 vio_addr_l, vio_addr_h, bus_id, domain_id;
+       u32 vio_w, vio_r;
+       u64 vio_addr;

-       vio_dbg0_reg = ctx->infra_base + ctx->data->regs_ofs->vio_dbg0_offset;
-       vio_dbg1_reg = ctx->infra_base + ctx->data->regs_ofs->vio_dbg1_offset;
+       vio_dbg0_reg = ctx->base + ctx->data->regs_ofs->vio_dbg0_offset;
+       vio_dbg1_reg = ctx->base + ctx->data->regs_ofs->vio_dbg1_offset;
+       vio_dbg2_reg = ctx->base + ctx->data->regs_ofs->vio_dbg2_offset;
+       vio_dbg3_reg = ctx->base + ctx->data->regs_ofs->vio_dbg3_offset;

        vio_dbgs.vio_dbg0 = readl(vio_dbg0_reg);
        vio_dbgs.vio_dbg1 = readl(vio_dbg1_reg);
+       if (ctx->data->version >= 2U)
+               vio_dbgs.vio_dbg2 = readl(vio_dbg2_reg);
+       if (ctx->data->version == 3U)
+               vio_dbgs.vio_dbg3 = readl(vio_dbg3_reg);
+
+       if (ctx->data->version == 1U) {
+               /* arch version 1 */
+               bus_id = vio_dbgs.dbg0_bits.mstid;
+               vio_addr = vio_dbgs.vio_dbg1;
+               domain_id = vio_dbgs.dbg0_bits.dmnid;
+               vio_w = vio_dbgs.dbg0_bits.vio_w;
+               vio_r = vio_dbgs.dbg0_bits.vio_r;
+       } else {
+               /* arch version 2 & 3 */
+               bus_id = vio_dbgs.vio_dbg1;
+
+               vio_addr_l = vio_dbgs.vio_dbg2;
+               vio_addr_h = ctx->data->version == 2U ? vio_dbgs.dbg0_bits_ver2.addr_h :
+                                                       vio_dbgs.vio_dbg3;
+               vio_addr = ((u64)vio_addr_h << 32) + vio_addr_l;
+               domain_id = vio_dbgs.dbg0_bits_ver2.dmnid;
+               vio_w = vio_dbgs.dbg0_bits_ver2.vio_w;
+               vio_r = vio_dbgs.dbg0_bits_ver2.vio_r;
+       }

        /* Print violation information */
-       if (vio_dbgs.dbg0_bits.vio_w)
+       if (vio_w)
                dev_info(ctx->dev, "Write Violation\n");
-       else if (vio_dbgs.dbg0_bits.vio_r)
+       else if (vio_r)
                dev_info(ctx->dev, "Read Violation\n");

-       dev_info(ctx->dev, "Bus ID:0x%x, Dom ID:0x%x, Vio Addr:0x%x\n",
-                vio_dbgs.dbg0_bits.mstid, vio_dbgs.dbg0_bits.dmnid,
-                vio_dbgs.vio_dbg1);
+       dev_info(ctx->dev, "Bus ID:0x%x, Dom ID:0x%x, Vio Addr:0x%llx\n",
+                bus_id, domain_id, vio_addr);
 }

 /*
@@ -203,7 +249,8 @@ static irqreturn_t devapc_violation_irq(int irq_number, void *data)
  */
 static void start_devapc(struct mtk_devapc_context *ctx)
 {
-       writel(BIT(31), ctx->infra_base + ctx->data->regs_ofs->apc_con_offset);
+
+       writel(BIT(31), ctx->base + ctx->data->regs_ofs->apc_con_offset);

        mask_module_irq(ctx, false);
 }
@@ -215,10 +262,10 @@ static void stop_devapc(struct mtk_devapc_context *ctx)
 {
        mask_module_irq(ctx, true);

-       writel(BIT(2), ctx->infra_base + ctx->data->regs_ofs->apc_con_offset);
+       writel(BIT(2), ctx->base + ctx->data->regs_ofs->apc_con_offset);
 }

-static const struct mtk_devapc_regs_ofs devapc_regs_ofs_mt6779 = {
+static const struct mtk_devapc_regs_ofs devapc_regs_ofs_ver1 = {
        .vio_mask_offset = 0x0,
        .vio_sta_offset = 0x400,
        .vio_dbg0_offset = 0x900,
@@ -229,14 +276,46 @@ static const struct mtk_devapc_regs_ofs devapc_regs_ofs_mt6779 = {
        .vio_shift_con_offset = 0xF20,
 };

+static const struct mtk_devapc_regs_ofs devapc_regs_ofs_ver2 = {
+       .vio_mask_offset = 0x0,
+       .vio_sta_offset = 0x400,
+       .vio_dbg0_offset = 0x900,
+       .vio_dbg1_offset = 0x904,
+       .vio_dbg2_offset = 0x908,
+       .apc_con_offset = 0xF00,
+       .vio_shift_sta_offset = 0xF20,
+       .vio_shift_sel_offset = 0xF30,
+       .vio_shift_con_offset = 0xF10,
+};
+
+static const struct mtk_devapc_regs_ofs devapc_regs_ofs_ver3 = {
+       .vio_mask_offset = 0x0,
+       .vio_sta_offset = 0x400,
+       .vio_dbg0_offset = 0x900,
+       .vio_dbg1_offset = 0x904,
+       .vio_dbg2_offset = 0x908,
+       .vio_dbg3_offset = 0x90c,
+       .apc_con_offset = 0xF00,
+       .vio_shift_sta_offset = 0xF20,
+       .vio_shift_sel_offset = 0xF30,
+       .vio_shift_con_offset = 0xF10,
+};
+
 static const struct mtk_devapc_data devapc_mt6779 = {
-       .vio_idx_num = 511,
-       .regs_ofs = &devapc_regs_ofs_mt6779,
+       .version = 1,
+       .default_vio_idx_num = 511,
+       .regs_ofs = &devapc_regs_ofs_ver1,
 };

 static const struct mtk_devapc_data devapc_mt8186 = {
-       .vio_idx_num = 519,
-       .regs_ofs = &devapc_regs_ofs_mt6779,
+       .version = 1,
+       .default_vio_idx_num = 519,
+       .regs_ofs = &devapc_regs_ofs_ver1,
+};
+
+static const struct mtk_devapc_data devapc_mt8189 = {
+       .version = 3,
+       .regs_ofs = &devapc_regs_ofs_ver3,
 };

 static const struct of_device_id mtk_devapc_dt_match[] = {
@@ -246,6 +325,9 @@ static const struct of_device_id mtk_devapc_dt_match[] = {
        }, {
                .compatible = "mediatek,mt8186-devapc",
                .data = &devapc_mt8186,
+       }, {
+               .compatible = "mediatek,mt8189-devapc",
+               .data = &devapc_mt8189,
        }, {
        },
 };
@@ -268,10 +350,23 @@ static int mtk_devapc_probe(struct platform_device *pdev)
        ctx->data = of_device_get_match_data(&pdev->dev);
        ctx->dev = &pdev->dev;

-       ctx->infra_base = of_iomap(node, 0);
-       if (!ctx->infra_base)
+       ctx->base = of_iomap(node, 0);
+       if (!ctx->base)
                return -EINVAL;

+       /*
+        * Set effective vio_idx_num from default value.
+        * If vio_idx_num is 0, get the info from DT.
+        */
+       ctx->vio_idx_num = ctx->data->default_vio_idx_num;
+       if (ctx->vio_idx_num == 0)
+               if (of_property_read_u32(node,
+                                        "vio-idx-num",
+                                        &ctx->vio_idx_num)) {
+                       ret = -EINVAL;
+                       goto err;
+               }
+
        devapc_irq = irq_of_parse_and_map(node, 0);
        if (!devapc_irq) {
                ret = -EINVAL;
@@ -296,7 +391,7 @@ static int mtk_devapc_probe(struct platform_device *pdev)
        return 0;

 err:
-       iounmap(ctx->infra_base);
+       iounmap(ctx->base);
        return ret;
 }

@@ -305,7 +400,8 @@ static void mtk_devapc_remove(struct platform_device *pdev)
        struct mtk_devapc_context *ctx = platform_get_drvdata(pdev);

        stop_devapc(ctx);
-       iounmap(ctx->infra_base);
+
+       iounmap(ctx->base);
 }

 static struct platform_driver mtk_devapc_driver = {
--
2.45.2



From xiaoshun.xu at mediatek.corp-partner.google.com  Tue Dec 16 22:34:13 2025
From: xiaoshun.xu at mediatek.corp-partner.google.com (Xiaoshun Xu)
Date: Wed, 17 Dec 2025 14:34:13 +0800
Subject: [PATCH v2 4/4] soc: mediatek: mtk-devapc: refine devapc interrupt handler
In-Reply-To: <20251217063429.1157084-1-xiaoshun.xu@mediatek.corp-partner.google.com>
References: <20251217063429.1157084-1-xiaoshun.xu@mediatek.corp-partner.google.com>
Message-ID: <20251217063429.1157084-5-xiaoshun.xu@mediatek.corp-partner.google.com>


External email : Please do not click links or open attachments until you have verified the sender or the content.


From: Xiaoshun Xu <xiaoshun.xu at mediatek.com>

Because the violation IRQ uses a while loop, it might cause the
system to remain in the interrupt handler indefinitely. We are
currently optimizing this part of the process to handle only 20
violations for debug violation issues, and then exit the loop

Signed-off-by: Xiaoshun Xu <xiaoshun.xu at mediatek.com>
---
 drivers/soc/mediatek/mtk-devapc.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/soc/mediatek/mtk-devapc.c b/drivers/soc/mediatek/mtk-devapc.c
index 61628b941d92..ea38086c5554 100644
--- a/drivers/soc/mediatek/mtk-devapc.c
+++ b/drivers/soc/mediatek/mtk-devapc.c
@@ -12,6 +12,7 @@
 #include <linux/of_irq.h>
 #include <linux/of_address.h>

+#define MAX_VIO_NUM 20
 #define VIO_MOD_TO_REG_IND(m)  ((m) / 32)
 #define VIO_MOD_TO_REG_OFF(m)  ((m) % 32)

@@ -234,13 +235,18 @@ static void devapc_extract_vio_dbg(struct mtk_devapc_context *ctx)
  */
 static irqreturn_t devapc_violation_irq(int irq_number, void *data)
 {
+       u32 vio_num = 0;
        struct mtk_devapc_context *ctx = data;

-       while (devapc_sync_vio_dbg(ctx))
+       mask_module_irq(ctx, true);
+
+       for (vio_num = 0; (vio_num < MAX_VIO_NUM) && (devapc_sync_vio_dbg(ctx)); ++vio_num)
                devapc_extract_vio_dbg(ctx);

        clear_vio_status(ctx);

+       mask_module_irq(ctx, false);
+
        return IRQ_HANDLED;
 }

--
2.45.2



From baolin.wang at linux.alibaba.com  Tue Dec 16 22:44:34 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Wed, 17 Dec 2025 14:44:34 +0800
Subject: [PATCH v2 2/3] mm: rmap: support batched checks of the references
 for large folios
In-Reply-To: <17380b96-3a9e-46f9-b22b-0e770f7f1b4f@arm.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <545dba5e899634bc6c8ca782417d16fef3bd049f.1765439381.git.baolin.wang@linux.alibaba.com>
 <17380b96-3a9e-46f9-b22b-0e770f7f1b4f@arm.com>
Message-ID: <abba55d3-08f9-41c0-9870-4bdbc705d647@linux.alibaba.com>



On 2025/12/17 14:23, Dev Jain wrote:
> 
> On 11/12/25 1:46 pm, Baolin Wang wrote:
>> Currently, folio_referenced_one() always checks the young flag for each PTE
>> sequentially, which is inefficient for large folios. This inefficiency is
>> especially noticeable when reclaiming clean file-backed large folios, where
>> folio_referenced() is observed as a significant performance hotspot.
>>
>> Moreover, on Arm architecture, which supports contiguous PTEs, there is already
>> an optimization to clear the young flags for PTEs within a contiguous range.
>> However, this is not sufficient. We can extend this to perform batched operations
>> for the entire large folio (which might exceed the contiguous range: CONT_PTE_SIZE).
>>
>> Introduce a new API: clear_flush_young_ptes() to facilitate batched checking
>> of the young flags and flushing TLB entries, thereby improving performance
>> during large folio reclamation.
>>
>> Performance testing:
>> Allocate 10G clean file-backed folios by mmap() in a memory cgroup, and try to
>> reclaim 8G file-backed folios via the memory.reclaim interface. I can observe
>> 33% performance improvement on my Arm64 32-core server (and 10%+ improvement
>> on my X86 machine). Meanwhile, the hotspot folio_check_references() dropped
>> from approximately 35% to around 5%.
>>
>> W/o patchset:
>> real	0m1.518s
>> user	0m0.000s
>> sys	0m1.518s
>>
>> W/ patchset:
>> real	0m1.018s
>> user	0m0.000s
>> sys	0m1.018s
>>
>> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
>> ---
>>   arch/arm64/include/asm/pgtable.h | 11 +++++++++++
>>   include/linux/mmu_notifier.h     |  9 +++++----
>>   include/linux/pgtable.h          | 19 +++++++++++++++++++
>>   mm/rmap.c                        | 22 ++++++++++++++++++++--
>>   4 files changed, 55 insertions(+), 6 deletions(-)
>>
>> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
>> index e03034683156..a865bd8c46a3 100644
>> --- a/arch/arm64/include/asm/pgtable.h
>> +++ b/arch/arm64/include/asm/pgtable.h
>> @@ -1869,6 +1869,17 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
>>   	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
>>   }
>>   
>> +#define clear_flush_young_ptes clear_flush_young_ptes
>> +static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
>> +					unsigned long addr, pte_t *ptep,
>> +					unsigned int nr)
>> +{
>> +	if (likely(nr == 1))
>> +		return __ptep_clear_flush_young(vma, addr, ptep);
>> +
>> +	return contpte_clear_flush_young_ptes(vma, addr, ptep, nr);
>> +}
>> +
>>   #define wrprotect_ptes wrprotect_ptes
>>   static __always_inline void wrprotect_ptes(struct mm_struct *mm,
>>   				unsigned long addr, pte_t *ptep, unsigned int nr)
>> diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h
>> index d1094c2d5fb6..be594b274729 100644
>> --- a/include/linux/mmu_notifier.h
>> +++ b/include/linux/mmu_notifier.h
>> @@ -515,16 +515,17 @@ static inline void mmu_notifier_range_init_owner(
>>   	range->owner = owner;
>>   }
>>   
>> -#define ptep_clear_flush_young_notify(__vma, __address, __ptep)		\
>> +#define ptep_clear_flush_young_notify(__vma, __address, __ptep, __nr)	\
>>   ({									\
>>   	int __young;							\
>>   	struct vm_area_struct *___vma = __vma;				\
>>   	unsigned long ___address = __address;				\
>> -	__young = ptep_clear_flush_young(___vma, ___address, __ptep);	\
>> +	unsigned int ___nr = __nr;					\
>> +	__young = clear_flush_young_ptes(___vma, ___address, __ptep, ___nr);	\
>>   	__young |= mmu_notifier_clear_flush_young(___vma->vm_mm,	\
>>   						  ___address,		\
>>   						  ___address +		\
>> -							PAGE_SIZE);	\
>> +						nr * PAGE_SIZE);	\
>>   	__young;							\
>>   })
> 
> Do we have an existing bug here, in that mmu_notifier_clear_flush_young() should
> have been called for CONT_PTES length if the folio was contpte mapped?

I can't call it a bug, because folio_referenced_one() does iterate 
through each PTE of the large folio, but it is indeed inefficient.


From dev.jain at arm.com  Tue Dec 16 22:49:19 2025
From: dev.jain at arm.com (Dev Jain)
Date: Wed, 17 Dec 2025 12:19:19 +0530
Subject: [PATCH v2 2/3] mm: rmap: support batched checks of the references
 for large folios
In-Reply-To: <545dba5e899634bc6c8ca782417d16fef3bd049f.1765439381.git.baolin.wang@linux.alibaba.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <545dba5e899634bc6c8ca782417d16fef3bd049f.1765439381.git.baolin.wang@linux.alibaba.com>
Message-ID: <52ed7e12-b32e-4a73-ba55-eed993b930b9@arm.com>


On 11/12/25 1:46 pm, Baolin Wang wrote:
> Currently, folio_referenced_one() always checks the young flag for each PTE
> sequentially, which is inefficient for large folios. This inefficiency is
> especially noticeable when reclaiming clean file-backed large folios, where
> folio_referenced() is observed as a significant performance hotspot.
>
> Moreover, on Arm architecture, which supports contiguous PTEs, there is already
> an optimization to clear the young flags for PTEs within a contiguous range.
> However, this is not sufficient. We can extend this to perform batched operations
> for the entire large folio (which might exceed the contiguous range: CONT_PTE_SIZE).
>
> Introduce a new API: clear_flush_young_ptes() to facilitate batched checking
> of the young flags and flushing TLB entries, thereby improving performance
> during large folio reclamation.
>
> Performance testing:
> Allocate 10G clean file-backed folios by mmap() in a memory cgroup, and try to
> reclaim 8G file-backed folios via the memory.reclaim interface. I can observe
> 33% performance improvement on my Arm64 32-core server (and 10%+ improvement
> on my X86 machine). Meanwhile, the hotspot folio_check_references() dropped
> from approximately 35% to around 5%.
>
> W/o patchset:
> real	0m1.518s
> user	0m0.000s
> sys	0m1.518s
>
> W/ patchset:
> real	0m1.018s
> user	0m0.000s
> sys	0m1.018s
>
> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
> ---
>  arch/arm64/include/asm/pgtable.h | 11 +++++++++++
>  include/linux/mmu_notifier.h     |  9 +++++----
>  include/linux/pgtable.h          | 19 +++++++++++++++++++
>  mm/rmap.c                        | 22 ++++++++++++++++++++--
>  4 files changed, 55 insertions(+), 6 deletions(-)
>
> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
> index e03034683156..a865bd8c46a3 100644
> --- a/arch/arm64/include/asm/pgtable.h
> +++ b/arch/arm64/include/asm/pgtable.h
> @@ -1869,6 +1869,17 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
>  	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
>  }
>  
> +#define clear_flush_young_ptes clear_flush_young_ptes
> +static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
> +					unsigned long addr, pte_t *ptep,
> +					unsigned int nr)
> +{
> +	if (likely(nr == 1))
> +		return __ptep_clear_flush_young(vma, addr, ptep);
> +
> +	return contpte_clear_flush_young_ptes(vma, addr, ptep, nr);
> +}
> +
>  #define wrprotect_ptes wrprotect_ptes
>  static __always_inline void wrprotect_ptes(struct mm_struct *mm,
>  				unsigned long addr, pte_t *ptep, unsigned int nr)
> diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h
> index d1094c2d5fb6..be594b274729 100644
> --- a/include/linux/mmu_notifier.h
> +++ b/include/linux/mmu_notifier.h
> @@ -515,16 +515,17 @@ static inline void mmu_notifier_range_init_owner(
>  	range->owner = owner;
>  }
>  
> -#define ptep_clear_flush_young_notify(__vma, __address, __ptep)		\
> +#define ptep_clear_flush_young_notify(__vma, __address, __ptep, __nr)	\
>  ({									\
>  	int __young;							\
>  	struct vm_area_struct *___vma = __vma;				\
>  	unsigned long ___address = __address;				\
> -	__young = ptep_clear_flush_young(___vma, ___address, __ptep);	\
> +	unsigned int ___nr = __nr;					\
> +	__young = clear_flush_young_ptes(___vma, ___address, __ptep, ___nr);	\
>  	__young |= mmu_notifier_clear_flush_young(___vma->vm_mm,	\
>  						  ___address,		\
>  						  ___address +		\
> -							PAGE_SIZE);	\
> +						nr * PAGE_SIZE);	\
>  	__young;							\
>  })
>  
> @@ -650,7 +651,7 @@ static inline void mmu_notifier_subscriptions_destroy(struct mm_struct *mm)
>  
>  #define mmu_notifier_range_update_to_read_only(r) false
>  
> -#define ptep_clear_flush_young_notify ptep_clear_flush_young
> +#define ptep_clear_flush_young_notify clear_flush_young_ptes
>  #define pmdp_clear_flush_young_notify pmdp_clear_flush_young
>  #define ptep_clear_young_notify ptep_test_and_clear_young
>  #define pmdp_clear_young_notify pmdp_test_and_clear_young
> diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
> index b13b6f42be3c..c7d0fd228cb7 100644
> --- a/include/linux/pgtable.h
> +++ b/include/linux/pgtable.h
> @@ -947,6 +947,25 @@ static inline void wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
>  }
>  #endif
>  
> +#ifndef clear_flush_young_ptes
> +static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
> +					 unsigned long addr, pte_t *ptep,
> +					 unsigned int nr)
> +{
> +	int young = 0;
> +
> +	for (;;) {
> +		young |= ptep_clear_flush_young(vma, addr, ptep);
> +		if (--nr == 0)
> +			break;
> +		ptep++;
> +		addr += PAGE_SIZE;
> +	}
> +
> +	return young;
> +}
> +#endif
> +
>  /*
>   * On some architectures hardware does not set page access bit when accessing
>   * memory page, it is responsibility of software setting this bit. It brings
> diff --git a/mm/rmap.c b/mm/rmap.c
> index d6799afe1114..ec232165c47d 100644
> --- a/mm/rmap.c
> +++ b/mm/rmap.c
> @@ -827,9 +827,11 @@ static bool folio_referenced_one(struct folio *folio,
>  	struct folio_referenced_arg *pra = arg;
>  	DEFINE_FOLIO_VMA_WALK(pvmw, folio, vma, address, 0);
>  	int ptes = 0, referenced = 0;
> +	unsigned int nr;
>  
>  	while (page_vma_mapped_walk(&pvmw)) {
>  		address = pvmw.address;
> +		nr = 1;
>  
>  		if (vma->vm_flags & VM_LOCKED) {
>  			ptes++;
> @@ -874,9 +876,21 @@ static bool folio_referenced_one(struct folio *folio,
>  			if (lru_gen_look_around(&pvmw))
>  				referenced++;
>  		} else if (pvmw.pte) {
> +			if (folio_test_large(folio)) {
> +				unsigned long end_addr = pmd_addr_end(address, vma->vm_end);

I may be hallucinating here but I am just trying to recall things - is this a bug in
folio_pte_batch_flags()? A folio may not be naturally aligned in virtual space and hence
we may cross the PTE table while batching across it, which can be fixed by taking into
account pmd_addr_end() while computing max_nr.

> +				unsigned int max_nr = (end_addr - address) >> PAGE_SHIFT;
> +				pte_t pteval = ptep_get(pvmw.pte);
> +
> +				nr = folio_pte_batch(folio, pvmw.pte, pteval, max_nr);
> +			}
> +
> +			ptes += nr;
>  			if (ptep_clear_flush_young_notify(vma, address,
> -						pvmw.pte))
> +						pvmw.pte, nr))
>  				referenced++;
> +			/* Skip the batched PTEs */
> +			pvmw.pte += nr - 1;
> +			pvmw.address += (nr - 1) * PAGE_SIZE;
>  		} else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) {
>  			if (pmdp_clear_flush_young_notify(vma, address,
>  						pvmw.pmd))
> @@ -886,7 +900,11 @@ static bool folio_referenced_one(struct folio *folio,
>  			WARN_ON_ONCE(1);
>  		}
>  
> -		pra->mapcount--;
> +		pra->mapcount -= nr;
> +		if (ptes == pvmw.nr_pages) {
> +			page_vma_mapped_walk_done(&pvmw);
> +			break;
> +		}
>  	}
>  
>  	if (referenced)


From patrice.chotard at foss.st.com  Tue Dec 16 23:02:04 2025
From: patrice.chotard at foss.st.com (Patrice CHOTARD)
Date: Wed, 17 Dec 2025 08:02:04 +0100
Subject: [Linux-stm32] [PATCH] spi: stm32-ospi: Remove unneeded semicolon
In-Reply-To: <20251216043210.1521722-1-nichen@iscas.ac.cn>
References: <20251216043210.1521722-1-nichen@iscas.ac.cn>
Message-ID: <d288742b-0f01-4871-b9c6-bc2a807be359@foss.st.com>



On 12/16/25 05:32, Chen Ni wrote:
> Remove unnecessary semicolons reported by Coccinelle/coccicheck and the
> semantic patch at scripts/coccinelle/misc/semicolon.cocci.
> 
> Signed-off-by: Chen Ni <nichen at iscas.ac.cn>
> ---
>  drivers/spi/spi-stm32-ospi.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/spi/spi-stm32-ospi.c b/drivers/spi/spi-stm32-ospi.c
> index c36df8d3f5cb..f396439e2281 100644
> --- a/drivers/spi/spi-stm32-ospi.c
> +++ b/drivers/spi/spi-stm32-ospi.c
> @@ -150,7 +150,7 @@ static void stm32_ospi_read_fifo(void *val, void __iomem *addr, u8 len)
>  		break;
>  	case sizeof(u8):
>  		*((u8 *)val) = readb_relaxed(addr);
> -	};
> +	}
>  }
>  
>  static void stm32_ospi_write_fifo(void *val, void __iomem *addr, u8 len)
> @@ -164,7 +164,7 @@ static void stm32_ospi_write_fifo(void *val, void __iomem *addr, u8 len)
>  		break;
>  	case sizeof(u8):
>  		writeb_relaxed(*((u8 *)val), addr);
> -	};
> +	}
>  }
>  
>  static int stm32_ospi_abort(struct stm32_ospi *ospi)

Hi Chen

Reviewed-by: Patrice Chotard <patrice.chotard at foss.st.com>

Thanks
Patrice


From abhiraj21put at gmail.com  Tue Dec 16 23:03:03 2025
From: abhiraj21put at gmail.com (Abhishek Rajput)
Date: Wed, 17 Dec 2025 12:33:03 +0530
Subject: [PATCH] drm/mediatek: Convert legacy DRM logging to drm_* helpers in mtk_crtc.c
Message-ID: <20251217070303.689913-1-abhiraj21put@gmail.com>

Replace DRM_ERROR() and DRM_DEBUG_DRIVER() calls in
drivers/gpu/drm/mediatek/mtk_crtc.c with the corresponding drm__err()
and drm_dbg_driver() helpers.

The drm_*() logging helpers take a struct drm_device * argument,
allowing the DRM core to prefix log messages with the correct device
name and instance. This is required to correctly distinguish log
messages on systems with multiple GPUs.

This change aligns the Mediatek DRM driver with the DRM TODO item:
"Convert logging to drm_* functions with drm_device parameter".

Signed-off-by: Abhishek Rajput <abhiraj21put at gmail.com>

diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c b/drivers/gpu/drm/mediatek/mtk_crtc.c
index 991cdb3d7d5f..9f7e2c7fee93 100644
--- a/drivers/gpu/drm/mediatek/mtk_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_crtc.c
@@ -227,11 +227,12 @@ static int mtk_crtc_ddp_clk_enable(struct mtk_crtc *mtk_crtc)
 {
 	int ret;
 	int i;
+	struct drm_device *dev = mtk_crtc->base.dev;
 
 	for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
 		ret = mtk_ddp_comp_clk_enable(mtk_crtc->ddp_comp[i]);
 		if (ret) {
-			DRM_ERROR("Failed to enable clock %d: %d\n", i, ret);
+			drm_err(dev, "Failed to enable clock %d: %d\n", i, ret);
 			goto err;
 		}
 	}
@@ -343,6 +344,7 @@ static int mtk_crtc_ddp_hw_init(struct mtk_crtc *mtk_crtc)
 	struct drm_connector *connector;
 	struct drm_encoder *encoder;
 	struct drm_connector_list_iter conn_iter;
+	struct drm_device *dev = mtk_crtc->base.dev;
 	unsigned int width, height, vrefresh, bpc = MTK_MAX_BPC;
 	int ret;
 	int i;
@@ -371,19 +373,19 @@ static int mtk_crtc_ddp_hw_init(struct mtk_crtc *mtk_crtc)
 
 	ret = pm_runtime_resume_and_get(crtc->dev->dev);
 	if (ret < 0) {
-		DRM_ERROR("Failed to enable power domain: %d\n", ret);
+		drm_err(dev, "Failed to enable power domain: %d\n", ret);
 		return ret;
 	}
 
 	ret = mtk_mutex_prepare(mtk_crtc->mutex);
 	if (ret < 0) {
-		DRM_ERROR("Failed to enable mutex clock: %d\n", ret);
+		drm_err(dev, "Failed to enable mutex clock: %d\n", ret);
 		goto err_pm_runtime_put;
 	}
 
 	ret = mtk_crtc_ddp_clk_enable(mtk_crtc);
 	if (ret < 0) {
-		DRM_ERROR("Failed to enable component clocks: %d\n", ret);
+		drm_err(dev, "Failed to enable component clocks: %d\n", ret);
 		goto err_mutex_unprepare;
 	}
 
@@ -646,12 +648,13 @@ static void mtk_crtc_ddp_irq(void *data)
 	struct drm_crtc *crtc = data;
 	struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
 	struct mtk_drm_private *priv = crtc->dev->dev_private;
+	struct drm_device *dev = mtk_crtc->base.dev;
 
 #if IS_REACHABLE(CONFIG_MTK_CMDQ)
 	if (!priv->data->shadow_register && !mtk_crtc->cmdq_client.chan)
 		mtk_crtc_ddp_config(crtc, NULL);
 	else if (mtk_crtc->cmdq_vblank_cnt > 0 && --mtk_crtc->cmdq_vblank_cnt == 0)
-		DRM_ERROR("mtk_crtc %d CMDQ execute command timeout!\n",
+		drm_err(dev, "mtk_crtc %d CMDQ execute command timeout!\n",
 			  drm_crtc_index(&mtk_crtc->base));
 #else
 	if (!priv->data->shadow_register)
@@ -776,9 +779,10 @@ static void mtk_crtc_atomic_enable(struct drm_crtc *crtc,
 {
 	struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
 	struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0];
+	struct drm_device *dev = mtk_crtc->base.dev;
 	int ret;
 
-	DRM_DEBUG_DRIVER("%s %d\n", __func__, crtc->base.id);
+	drm_dbg_driver(dev, "%s %d\n", __func__, crtc->base.id);
 
 	ret = mtk_ddp_comp_power_on(comp);
 	if (ret < 0) {
@@ -803,9 +807,10 @@ static void mtk_crtc_atomic_disable(struct drm_crtc *crtc,
 {
 	struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
 	struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0];
+	struct drm_device *dev = mtk_crtc->base.dev;
 	int i;
 
-	DRM_DEBUG_DRIVER("%s %d\n", __func__, crtc->base.id);
+	drm_dbg_driver(dev, "%s %d\n", __func__, crtc->base.id);
 	if (!mtk_crtc->enabled)
 		return;
 
@@ -845,10 +850,11 @@ static void mtk_crtc_atomic_begin(struct drm_crtc *crtc,
 									  crtc);
 	struct mtk_crtc_state *mtk_crtc_state = to_mtk_crtc_state(crtc_state);
 	struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
+	struct drm_device *dev = mtk_crtc->base.dev;
 	unsigned long flags;
 
 	if (mtk_crtc->event && mtk_crtc_state->base.event)
-		DRM_ERROR("new event while there is still a pending event\n");
+		drm_err(dev, "new event while there is still a pending event\n");
 
 	if (mtk_crtc_state->base.event) {
 		mtk_crtc_state->base.event->pipe = drm_crtc_index(crtc);
-- 
2.43.0



From baolin.wang at linux.alibaba.com  Tue Dec 16 23:09:47 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Wed, 17 Dec 2025 15:09:47 +0800
Subject: [PATCH v2 2/3] mm: rmap: support batched checks of the references
 for large folios
In-Reply-To: <52ed7e12-b32e-4a73-ba55-eed993b930b9@arm.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <545dba5e899634bc6c8ca782417d16fef3bd049f.1765439381.git.baolin.wang@linux.alibaba.com>
 <52ed7e12-b32e-4a73-ba55-eed993b930b9@arm.com>
Message-ID: <753ee7bd-8c9a-4242-a216-98defcd8280f@linux.alibaba.com>



On 2025/12/17 14:49, Dev Jain wrote:
> 
> On 11/12/25 1:46 pm, Baolin Wang wrote:
>> Currently, folio_referenced_one() always checks the young flag for each PTE
>> sequentially, which is inefficient for large folios. This inefficiency is
>> especially noticeable when reclaiming clean file-backed large folios, where
>> folio_referenced() is observed as a significant performance hotspot.
>>
>> Moreover, on Arm architecture, which supports contiguous PTEs, there is already
>> an optimization to clear the young flags for PTEs within a contiguous range.
>> However, this is not sufficient. We can extend this to perform batched operations
>> for the entire large folio (which might exceed the contiguous range: CONT_PTE_SIZE).
>>
>> Introduce a new API: clear_flush_young_ptes() to facilitate batched checking
>> of the young flags and flushing TLB entries, thereby improving performance
>> during large folio reclamation.
>>
>> Performance testing:
>> Allocate 10G clean file-backed folios by mmap() in a memory cgroup, and try to
>> reclaim 8G file-backed folios via the memory.reclaim interface. I can observe
>> 33% performance improvement on my Arm64 32-core server (and 10%+ improvement
>> on my X86 machine). Meanwhile, the hotspot folio_check_references() dropped
>> from approximately 35% to around 5%.
>>
>> W/o patchset:
>> real	0m1.518s
>> user	0m0.000s
>> sys	0m1.518s
>>
>> W/ patchset:
>> real	0m1.018s
>> user	0m0.000s
>> sys	0m1.018s
>>
>> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
>> ---
>>   arch/arm64/include/asm/pgtable.h | 11 +++++++++++
>>   include/linux/mmu_notifier.h     |  9 +++++----
>>   include/linux/pgtable.h          | 19 +++++++++++++++++++
>>   mm/rmap.c                        | 22 ++++++++++++++++++++--
>>   4 files changed, 55 insertions(+), 6 deletions(-)
>>
>> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
>> index e03034683156..a865bd8c46a3 100644
>> --- a/arch/arm64/include/asm/pgtable.h
>> +++ b/arch/arm64/include/asm/pgtable.h
>> @@ -1869,6 +1869,17 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
>>   	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
>>   }
>>   
>> +#define clear_flush_young_ptes clear_flush_young_ptes
>> +static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
>> +					unsigned long addr, pte_t *ptep,
>> +					unsigned int nr)
>> +{
>> +	if (likely(nr == 1))
>> +		return __ptep_clear_flush_young(vma, addr, ptep);
>> +
>> +	return contpte_clear_flush_young_ptes(vma, addr, ptep, nr);
>> +}
>> +
>>   #define wrprotect_ptes wrprotect_ptes
>>   static __always_inline void wrprotect_ptes(struct mm_struct *mm,
>>   				unsigned long addr, pte_t *ptep, unsigned int nr)
>> diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h
>> index d1094c2d5fb6..be594b274729 100644
>> --- a/include/linux/mmu_notifier.h
>> +++ b/include/linux/mmu_notifier.h
>> @@ -515,16 +515,17 @@ static inline void mmu_notifier_range_init_owner(
>>   	range->owner = owner;
>>   }
>>   
>> -#define ptep_clear_flush_young_notify(__vma, __address, __ptep)		\
>> +#define ptep_clear_flush_young_notify(__vma, __address, __ptep, __nr)	\
>>   ({									\
>>   	int __young;							\
>>   	struct vm_area_struct *___vma = __vma;				\
>>   	unsigned long ___address = __address;				\
>> -	__young = ptep_clear_flush_young(___vma, ___address, __ptep);	\
>> +	unsigned int ___nr = __nr;					\
>> +	__young = clear_flush_young_ptes(___vma, ___address, __ptep, ___nr);	\
>>   	__young |= mmu_notifier_clear_flush_young(___vma->vm_mm,	\
>>   						  ___address,		\
>>   						  ___address +		\
>> -							PAGE_SIZE);	\
>> +						nr * PAGE_SIZE);	\
>>   	__young;							\
>>   })
>>   
>> @@ -650,7 +651,7 @@ static inline void mmu_notifier_subscriptions_destroy(struct mm_struct *mm)
>>   
>>   #define mmu_notifier_range_update_to_read_only(r) false
>>   
>> -#define ptep_clear_flush_young_notify ptep_clear_flush_young
>> +#define ptep_clear_flush_young_notify clear_flush_young_ptes
>>   #define pmdp_clear_flush_young_notify pmdp_clear_flush_young
>>   #define ptep_clear_young_notify ptep_test_and_clear_young
>>   #define pmdp_clear_young_notify pmdp_test_and_clear_young
>> diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
>> index b13b6f42be3c..c7d0fd228cb7 100644
>> --- a/include/linux/pgtable.h
>> +++ b/include/linux/pgtable.h
>> @@ -947,6 +947,25 @@ static inline void wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
>>   }
>>   #endif
>>   
>> +#ifndef clear_flush_young_ptes
>> +static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
>> +					 unsigned long addr, pte_t *ptep,
>> +					 unsigned int nr)
>> +{
>> +	int young = 0;
>> +
>> +	for (;;) {
>> +		young |= ptep_clear_flush_young(vma, addr, ptep);
>> +		if (--nr == 0)
>> +			break;
>> +		ptep++;
>> +		addr += PAGE_SIZE;
>> +	}
>> +
>> +	return young;
>> +}
>> +#endif
>> +
>>   /*
>>    * On some architectures hardware does not set page access bit when accessing
>>    * memory page, it is responsibility of software setting this bit. It brings
>> diff --git a/mm/rmap.c b/mm/rmap.c
>> index d6799afe1114..ec232165c47d 100644
>> --- a/mm/rmap.c
>> +++ b/mm/rmap.c
>> @@ -827,9 +827,11 @@ static bool folio_referenced_one(struct folio *folio,
>>   	struct folio_referenced_arg *pra = arg;
>>   	DEFINE_FOLIO_VMA_WALK(pvmw, folio, vma, address, 0);
>>   	int ptes = 0, referenced = 0;
>> +	unsigned int nr;
>>   
>>   	while (page_vma_mapped_walk(&pvmw)) {
>>   		address = pvmw.address;
>> +		nr = 1;
>>   
>>   		if (vma->vm_flags & VM_LOCKED) {
>>   			ptes++;
>> @@ -874,9 +876,21 @@ static bool folio_referenced_one(struct folio *folio,
>>   			if (lru_gen_look_around(&pvmw))
>>   				referenced++;
>>   		} else if (pvmw.pte) {
>> +			if (folio_test_large(folio)) {
>> +				unsigned long end_addr = pmd_addr_end(address, vma->vm_end);
> 
> I may be hallucinating here but I am just trying to recall things - is this a bug in
> folio_pte_batch_flags()? A folio may not be naturally aligned in virtual space and hence
> we may cross the PTE table while batching across it, which can be fixed by taking into
> account pmd_addr_end() while computing max_nr.

IMHO, the comments for the folio_pte_batch_flags() function have already 
made clear requirements for the caller to avoid such situations:

"
* @ptep must map any page of the folio. max_nr must be at least one and
* must be limited by the caller so scanning cannot exceed a single VMA and
* a single page table.
"

Additionally, Lance recently fixed a similar issue, see commit 
ddd05742b45b ("mm/rmap: fix potential out-of-bounds page table access 
during batched unmap").


From dev.jain at arm.com  Tue Dec 16 23:23:46 2025
From: dev.jain at arm.com (Dev Jain)
Date: Wed, 17 Dec 2025 12:53:46 +0530
Subject: [PATCH v2 2/3] mm: rmap: support batched checks of the references
 for large folios
In-Reply-To: <753ee7bd-8c9a-4242-a216-98defcd8280f@linux.alibaba.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <545dba5e899634bc6c8ca782417d16fef3bd049f.1765439381.git.baolin.wang@linux.alibaba.com>
 <52ed7e12-b32e-4a73-ba55-eed993b930b9@arm.com>
 <753ee7bd-8c9a-4242-a216-98defcd8280f@linux.alibaba.com>
Message-ID: <b1075258-a42d-4e2f-95d7-5f8cb11f0d7d@arm.com>


On 17/12/25 12:39 pm, Baolin Wang wrote:
>
>
> On 2025/12/17 14:49, Dev Jain wrote:
>>
>> On 11/12/25 1:46 pm, Baolin Wang wrote:
>>> Currently, folio_referenced_one() always checks the young flag for each PTE
>>> sequentially, which is inefficient for large folios. This inefficiency is
>>> especially noticeable when reclaiming clean file-backed large folios, where
>>> folio_referenced() is observed as a significant performance hotspot.
>>>
>>> Moreover, on Arm architecture, which supports contiguous PTEs, there is already
>>> an optimization to clear the young flags for PTEs within a contiguous range.
>>> However, this is not sufficient. We can extend this to perform batched
>>> operations
>>> for the entire large folio (which might exceed the contiguous range:
>>> CONT_PTE_SIZE).
>>>
>>> Introduce a new API: clear_flush_young_ptes() to facilitate batched checking
>>> of the young flags and flushing TLB entries, thereby improving performance
>>> during large folio reclamation.
>>>
>>> Performance testing:
>>> Allocate 10G clean file-backed folios by mmap() in a memory cgroup, and try to
>>> reclaim 8G file-backed folios via the memory.reclaim interface. I can observe
>>> 33% performance improvement on my Arm64 32-core server (and 10%+ improvement
>>> on my X86 machine). Meanwhile, the hotspot folio_check_references() dropped
>>> from approximately 35% to around 5%.
>>>
>>> W/o patchset:
>>> real??? 0m1.518s
>>> user??? 0m0.000s
>>> sys??? 0m1.518s
>>>
>>> W/ patchset:
>>> real??? 0m1.018s
>>> user??? 0m0.000s
>>> sys??? 0m1.018s
>>>
>>> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
>>> ---
>>> ? arch/arm64/include/asm/pgtable.h | 11 +++++++++++
>>> ? include/linux/mmu_notifier.h???? |? 9 +++++----
>>> ? include/linux/pgtable.h????????? | 19 +++++++++++++++++++
>>> ? mm/rmap.c??????????????????????? | 22 ++++++++++++++++++++--
>>> ? 4 files changed, 55 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/arch/arm64/include/asm/pgtable.h
>>> b/arch/arm64/include/asm/pgtable.h
>>> index e03034683156..a865bd8c46a3 100644
>>> --- a/arch/arm64/include/asm/pgtable.h
>>> +++ b/arch/arm64/include/asm/pgtable.h
>>> @@ -1869,6 +1869,17 @@ static inline int ptep_clear_flush_young(struct
>>> vm_area_struct *vma,
>>> ????? return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
>>> ? }
>>> ? +#define clear_flush_young_ptes clear_flush_young_ptes
>>> +static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
>>> +??????????????????? unsigned long addr, pte_t *ptep,
>>> +??????????????????? unsigned int nr)
>>> +{
>>> +??? if (likely(nr == 1))
>>> +??????? return __ptep_clear_flush_young(vma, addr, ptep);
>>> +
>>> +??? return contpte_clear_flush_young_ptes(vma, addr, ptep, nr);
>>> +}
>>> +
>>> ? #define wrprotect_ptes wrprotect_ptes
>>> ? static __always_inline void wrprotect_ptes(struct mm_struct *mm,
>>> ????????????????? unsigned long addr, pte_t *ptep, unsigned int nr)
>>> diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h
>>> index d1094c2d5fb6..be594b274729 100644
>>> --- a/include/linux/mmu_notifier.h
>>> +++ b/include/linux/mmu_notifier.h
>>> @@ -515,16 +515,17 @@ static inline void mmu_notifier_range_init_owner(
>>> ????? range->owner = owner;
>>> ? }
>>> ? -#define ptep_clear_flush_young_notify(__vma, __address, __ptep)??????? \
>>> +#define ptep_clear_flush_young_notify(__vma, __address, __ptep, __nr)??? \
>>> ? ({??????????????????????????????????? \
>>> ????? int __young;??????????????????????????? \
>>> ????? struct vm_area_struct *___vma = __vma;??????????????? \
>>> ????? unsigned long ___address = __address;??????????????? \
>>> -??? __young = ptep_clear_flush_young(___vma, ___address, __ptep);??? \
>>> +??? unsigned int ___nr = __nr;??????????????????? \
>>> +??? __young = clear_flush_young_ptes(___vma, ___address, __ptep, ___nr);??? \
>>> ????? __young |= mmu_notifier_clear_flush_young(___vma->vm_mm,??? \
>>> ??????????????????????????? ___address,??????? \
>>> ??????????????????????????? ___address +??????? \
>>> -??????????????????????????? PAGE_SIZE);??? \
>>> +??????????????????????? nr * PAGE_SIZE);??? \
>>> ????? __young;??????????????????????????? \
>>> ? })
>>> ? @@ -650,7 +651,7 @@ static inline void
>>> mmu_notifier_subscriptions_destroy(struct mm_struct *mm)
>>> ? ? #define mmu_notifier_range_update_to_read_only(r) false
>>> ? -#define ptep_clear_flush_young_notify ptep_clear_flush_young
>>> +#define ptep_clear_flush_young_notify clear_flush_young_ptes
>>> ? #define pmdp_clear_flush_young_notify pmdp_clear_flush_young
>>> ? #define ptep_clear_young_notify ptep_test_and_clear_young
>>> ? #define pmdp_clear_young_notify pmdp_test_and_clear_young
>>> diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
>>> index b13b6f42be3c..c7d0fd228cb7 100644
>>> --- a/include/linux/pgtable.h
>>> +++ b/include/linux/pgtable.h
>>> @@ -947,6 +947,25 @@ static inline void wrprotect_ptes(struct mm_struct *mm,
>>> unsigned long addr,
>>> ? }
>>> ? #endif
>>> ? +#ifndef clear_flush_young_ptes
>>> +static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
>>> +???????????????????? unsigned long addr, pte_t *ptep,
>>> +???????????????????? unsigned int nr)
>>> +{
>>> +??? int young = 0;
>>> +
>>> +??? for (;;) {
>>> +??????? young |= ptep_clear_flush_young(vma, addr, ptep);
>>> +??????? if (--nr == 0)
>>> +??????????? break;
>>> +??????? ptep++;
>>> +??????? addr += PAGE_SIZE;
>>> +??? }
>>> +
>>> +??? return young;
>>> +}
>>> +#endif
>>> +
>>> ? /*
>>> ?? * On some architectures hardware does not set page access bit when accessing
>>> ?? * memory page, it is responsibility of software setting this bit. It brings
>>> diff --git a/mm/rmap.c b/mm/rmap.c
>>> index d6799afe1114..ec232165c47d 100644
>>> --- a/mm/rmap.c
>>> +++ b/mm/rmap.c
>>> @@ -827,9 +827,11 @@ static bool folio_referenced_one(struct folio *folio,
>>> ????? struct folio_referenced_arg *pra = arg;
>>> ????? DEFINE_FOLIO_VMA_WALK(pvmw, folio, vma, address, 0);
>>> ????? int ptes = 0, referenced = 0;
>>> +??? unsigned int nr;
>>> ? ????? while (page_vma_mapped_walk(&pvmw)) {
>>> ????????? address = pvmw.address;
>>> +??????? nr = 1;
>>> ? ????????? if (vma->vm_flags & VM_LOCKED) {
>>> ????????????? ptes++;
>>> @@ -874,9 +876,21 @@ static bool folio_referenced_one(struct folio *folio,
>>> ????????????? if (lru_gen_look_around(&pvmw))
>>> ????????????????? referenced++;
>>> ????????? } else if (pvmw.pte) {
>>> +??????????? if (folio_test_large(folio)) {
>>> +??????????????? unsigned long end_addr = pmd_addr_end(address, vma->vm_end);
>>
>> I may be hallucinating here but I am just trying to recall things - is this a
>> bug in
>> folio_pte_batch_flags()? A folio may not be naturally aligned in virtual
>> space and hence
>> we may cross the PTE table while batching across it, which can be fixed by
>> taking into
>> account pmd_addr_end() while computing max_nr.
>
> IMHO, the comments for the folio_pte_batch_flags() function have already made
> clear requirements for the caller to avoid such situations:
>
> "
> * @ptep must map any page of the folio. max_nr must be at least one and
> * must be limited by the caller so scanning cannot exceed a single VMA and
> * a single page table.
> "
>
> Additionally, Lance recently fixed a similar issue, see commit ddd05742b45b
> ("mm/rmap: fix potential out-of-bounds page table access during batched unmap").
?

Ah I see, all other users of the folio_pte_batch API constrain start and end
because they are already operating on a single PTE table. But for rmap code

this may not be the case.?



From krzk at kernel.org  Tue Dec 16 23:42:34 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 17 Dec 2025 08:42:34 +0100
Subject: [PATCH v2 2/2] media: nxp: Add i.MX9 CSI pixel formatter v4l2
 driver
In-Reply-To: <20251217-csi_formatter-v2-2-62168af80210@nxp.com>
References: <20251217-csi_formatter-v2-0-62168af80210@nxp.com>
 <20251217-csi_formatter-v2-2-62168af80210@nxp.com>
Message-ID: <360ecc21-b748-474c-9ada-ca72b7ae3a4a@kernel.org>

On 17/12/2025 07:11, Guoniu Zhou wrote:
> +
> +static const struct v4l2_async_notifier_operations formatter_notify_ops = {
> +	.bound = csi_formatter_notify_bound,
> +};
> +
> +static int csi_formatter_async_register(struct csi_formatter *formatter)
> +{
> +	struct device *dev = formatter->dev;
> +	struct v4l2_async_connection *asc;
> +	struct fwnode_handle *ep __free(fwnode_handle) = NULL;

This is an undesired syntax explicitly documented as one to avoid. You
need here proper assignment, not NULL. Please don't use cleanup.h if you
do not intend to follow it because it does not make the code simpler.

> +	int ret;
> +
> +	v4l2_async_subdev_nf_init(&formatter->notifier, &formatter->sd);
> +
> +	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0,
> +					     FWNODE_GRAPH_ENDPOINT_NEXT);
> +	if (!ep)
> +		return -ENOTCONN;
> +
> +	asc = v4l2_async_nf_add_fwnode_remote(&formatter->notifier, ep,
> +					      struct v4l2_async_connection);
> +	if (IS_ERR(asc))
> +		return PTR_ERR(asc);
> +
> +	formatter->notifier.ops = &formatter_notify_ops;
> +
> +	ret = v4l2_async_nf_register(&formatter->notifier);
> +	if (ret)
> +		return ret;
> +
> +	return v4l2_async_register_subdev(&formatter->sd);
> +}
> +
> +/* -----------------------------------------------------------------------------
> + * Suspend/resume
> + */
> +
> +static int csi_formatter_system_suspend(struct device *dev)
> +{
> +	return pm_runtime_force_suspend(dev);
> +}
> +
> +static int csi_formatter_system_resume(struct device *dev)
> +{
> +	int ret;
> +
> +	ret = pm_runtime_force_resume(dev);
> +	if (ret < 0) {
> +		dev_err(dev, "force resume %s failed!\n", dev_name(dev));
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int csi_formatter_runtime_suspend(struct device *dev)
> +{
> +	struct v4l2_subdev *sd = dev_get_drvdata(dev);
> +	struct csi_formatter *formatter = sd_to_formatter(sd);
> +
> +	clk_disable_unprepare(formatter->clk);
> +
> +	return 0;
> +}
> +
> +static int csi_formatter_runtime_resume(struct device *dev)
> +{
> +	struct v4l2_subdev *sd = dev_get_drvdata(dev);
> +	struct csi_formatter *formatter = sd_to_formatter(sd);
> +
> +	return clk_prepare_enable(formatter->clk);
> +}
> +
> +static const struct dev_pm_ops csi_formatter_pm_ops = {
> +	SYSTEM_SLEEP_PM_OPS(csi_formatter_system_suspend,
> +			    csi_formatter_system_resume)
> +	RUNTIME_PM_OPS(csi_formatter_runtime_suspend,
> +		       csi_formatter_runtime_resume, NULL)
> +};
> +
> +static int csi_formatter_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct csi_formatter *formatter;
> +	u32 val;
> +	int ret;
> +
> +	formatter = devm_kzalloc(dev, sizeof(*formatter), GFP_KERNEL);
> +	if (!formatter)
> +		return -ENOMEM;
> +
> +	formatter->dev = dev;
> +
> +	formatter->regs = syscon_node_to_regmap(dev->parent->of_node);
> +	if (IS_ERR(formatter->regs))
> +		return dev_err_probe(dev, PTR_ERR(formatter->regs),
> +				     "Failed to get csi formatter regmap\n");
> +
> +	ret = of_property_read_u32(dev->of_node, "reg", &val);
> +	if (ret < 0)
> +		return dev_err_probe(dev, ret, "Failed to get csi formatter reg property\n");
> +
> +	formatter->reg_offset = val;
> +
> +	formatter->clk = devm_clk_get(dev, NULL);
> +	if (IS_ERR(formatter->clk))
> +		return dev_err_probe(dev, PTR_ERR(formatter->clk),
> +				     "Failed to get pixel clock\n");
> +
> +	ret = csi_formatter_subdev_init(formatter);
> +	if (ret < 0)
> +		return dev_err_probe(dev, ret, "formatter subdev init fail\n");
> +
> +	/* Initialize formatter pixel format */
> +	formatter->fmt = find_csi_format(formatter_default_fmt.code);
> +
> +	ret = csi_formatter_async_register(formatter);
> +	if (ret < 0) {
> +		v4l2_subdev_cleanup(&formatter->sd);
> +		return dev_err_probe(dev, ret, "Async register failed\n");
> +	}
> +
> +	platform_set_drvdata(pdev, &formatter->sd);
> +
> +	/* Enable runtime PM. */
> +	pm_runtime_enable(dev);
> +
> +	return 0;
> +}
> +
> +static void csi_formatter_remove(struct platform_device *pdev)
> +{
> +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> +	struct csi_formatter *formatter = sd_to_formatter(sd);
> +
> +	v4l2_async_nf_unregister(&formatter->notifier);
> +	v4l2_async_nf_cleanup(&formatter->notifier);
> +	v4l2_async_unregister_subdev(&formatter->sd);
> +
> +	pm_runtime_disable(&pdev->dev);
> +	media_entity_cleanup(&formatter->sd.entity);
> +	pm_runtime_set_suspended(&pdev->dev);
> +}
> +
> +static const struct of_device_id csi_formatter_of_match[] = {
> +	{ .compatible = "fsl,imx9-csi-formatter" },
> +	{ /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(of, csi_formatter_of_match);
> +
> +static struct platform_driver csi_formatter_device_driver = {
> +	.driver = {
> +		.owner          = THIS_MODULE,

Why are you sending us 12 year old code without cleaning it up first?

> +		.name           = CSI_FORMATTER_DRV_NAME,
> +		.of_match_table = csi_formatter_of_match,
> +		.pm             = pm_ptr(&csi_formatter_pm_ops),
> +	},
> +	.probe  = csi_formatter_probe,
> +	.remove = csi_formatter_remove,
> +};
> +
Best regards,
Krzysztof


From daniel.lezcano at linaro.org  Tue Dec 16 23:49:56 2025
From: daniel.lezcano at linaro.org (Daniel Lezcano)
Date: Wed, 17 Dec 2025 08:49:56 +0100
Subject: [PATCH v3 2/3] dt-bindings: counter: Add NXP System Timer Module Counter
In-Reply-To: <20251217075000.2592966-1-daniel.lezcano@linaro.org>
References: <20251217075000.2592966-1-daniel.lezcano@linaro.org>
Message-ID: <20251217075000.2592966-3-daniel.lezcano@linaro.org>

Add the System Timer Module description found on the NXP s32 platform
when it is used as a counter and the compatible for the s32g2 variant.

Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Daniel Lezcano <daniel.lezcano at linaro.org>
---
 .../bindings/counter/nxp,s32g2-stm-cnt.yaml   | 64 +++++++++++++++++++
 1 file changed, 64 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/counter/nxp,s32g2-stm-cnt.yaml

diff --git a/Documentation/devicetree/bindings/counter/nxp,s32g2-stm-cnt.yaml b/Documentation/devicetree/bindings/counter/nxp,s32g2-stm-cnt.yaml
new file mode 100644
index 000000000000..4d42996f5ad3
--- /dev/null
+++ b/Documentation/devicetree/bindings/counter/nxp,s32g2-stm-cnt.yaml
@@ -0,0 +1,64 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/counter/nxp,s32g2-stm-cnt.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP System Timer Module (STM)
+
+maintainers:
+  - Daniel Lezcano <daniel.lezcano at kernel.org>
+
+description:
+  The System Timer Module supports commonly required system and application
+  software timing functions. STM includes a 32-bit count-up timer and four
+  32-bit compare channels with a separate interrupt source for each channel.
+  The counter is driven by the STM module clock divided by an 8-bit prescale
+  value.
+
+properties:
+  compatible:
+    oneOf:
+      - const: nxp,s32g2-stm-cnt
+      - items:
+          - const: nxp,s32g3-stm-cnt
+          - const: nxp,s32g2-stm-cnt
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: Counter clock
+      - description: Module clock
+      - description: Register clock
+
+  clock-names:
+    items:
+      - const: counter
+      - const: module
+      - const: register
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    timer at 4011c000 {
+        compatible = "nxp,s32g2-stm-cnt";
+        reg = <0x4011c000 0x3000>;
+        interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&clks 0x3b>, <&clks 0x3c>, <&clks 0x3c>;
+        clock-names = "counter", "module", "register";
+    };
-- 
2.43.0



From daniel.lezcano at linaro.org  Tue Dec 16 23:49:57 2025
From: daniel.lezcano at linaro.org (Daniel Lezcano)
Date: Wed, 17 Dec 2025 08:49:57 +0100
Subject: [PATCH v3 3/3] counter: Add STM based counter
In-Reply-To: <20251217075000.2592966-1-daniel.lezcano@linaro.org>
References: <20251217075000.2592966-1-daniel.lezcano@linaro.org>
Message-ID: <20251217075000.2592966-4-daniel.lezcano@linaro.org>

The NXP S32G2 automotive platform integrates four Cortex-A53 cores and
three Cortex-M7 cores, along with a large number of timers and
counters. These hardware blocks can be used as clocksources or
clockevents, or as timestamp counters shared across the various
subsystems running alongside the Linux kernel, such as firmware
components. Their actual usage depends on the overall platform
software design.

In a Linux-based system, the kernel controls the counter, which is a
read-only shared resource for the other subsystems. One of its primary
purposes is to act as a common timestamp source for messages or
traces, allowing correlation of events occurring in different
operating system contexts.

These changes introduce a basic counter driver that can start, stop,
and reset the counter. It also handles overflow accounting and
configures the prescaler value.

Signed-off-by: Daniel Lezcano <daniel.lezcano at linaro.org>
---
 drivers/counter/Kconfig       |  10 +
 drivers/counter/Makefile      |   1 +
 drivers/counter/nxp-stm-cnt.c | 386 ++++++++++++++++++++++++++++++++++
 3 files changed, 397 insertions(+)
 create mode 100644 drivers/counter/nxp-stm-cnt.c

diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig
index d30d22dfe577..bf5b281f194c 100644
--- a/drivers/counter/Kconfig
+++ b/drivers/counter/Kconfig
@@ -90,6 +90,16 @@ config MICROCHIP_TCB_CAPTURE
 	  To compile this driver as a module, choose M here: the
 	  module will be called microchip-tcb-capture.
 
+config NXP_STM_CNT
+	tristate "NXP System Timer Module Counter driver"
+	depends on ARCH_S32 || COMPILE_TEST
+	help
+	  Select this option to enable the NXP System Timer Module
+	  Counter driver.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called nxp_stm_cnt.
+
 config RZ_MTU3_CNT
 	tristate "Renesas RZ/G2L MTU3a counter driver"
 	depends on RZ_MTU3
diff --git a/drivers/counter/Makefile b/drivers/counter/Makefile
index 40e644948e7a..196b3c216875 100644
--- a/drivers/counter/Makefile
+++ b/drivers/counter/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_I8254)			+= i8254.o
 obj-$(CONFIG_INTEL_QEP)			+= intel-qep.o
 obj-$(CONFIG_INTERRUPT_CNT)		+= interrupt-cnt.o
 obj-$(CONFIG_MICROCHIP_TCB_CAPTURE)	+= microchip-tcb-capture.o
+obj-$(CONFIG_NXP_STM_CNT)		+= nxp-stm-cnt.o
 obj-$(CONFIG_RZ_MTU3_CNT)		+= rz-mtu3-cnt.o
 obj-$(CONFIG_STM32_TIMER_CNT)		+= stm32-timer-cnt.o
 obj-$(CONFIG_STM32_LPTIMER_CNT)		+= stm32-lptimer-cnt.o
diff --git a/drivers/counter/nxp-stm-cnt.c b/drivers/counter/nxp-stm-cnt.c
new file mode 100644
index 000000000000..36463fcbc9df
--- /dev/null
+++ b/drivers/counter/nxp-stm-cnt.c
@@ -0,0 +1,386 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2018,2021-2025 NXP
+ * Copyright 2025 Linaro Limited
+ *
+ * Author: Daniel Lezcano <daniel.lezcano at linaro.org>
+ *
+ * NXP S32G System Timer Module counters:
+ *
+ *  STM supports commonly required system and application software
+ *  timing functions. STM includes a 32-bit count-up timer and four
+ *  32-bit compare channels with a separate interrupt source for each
+ *  channel. The timer is driven by the STM module clock divided by an
+ *  8-bit prescale value (1 to 256). It has ability to stop the timer
+ *  in Debug mode
+ *
+ */
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/counter.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#define STM_CR(__base)		(__base)
+#define STM_CR_TEN		BIT(0)
+#define STM_CR_FRZ		BIT(1)
+#define STM_CR_CPS_MASK         GENMASK(15, 8)
+
+#define STM_CCR0(__base)	((__base) + 0x10)
+#define STM_CCR_CEN		BIT(0)
+
+#define STM_CIR0(__base)	((__base) + 0x14)
+#define STM_CIR_CIF		BIT(0)
+
+#define STM_CMP0(__base)	((__base) + 0x18)
+
+#define STM_CNT(__base)		((__base) + 0x04)
+
+#define STM_ENABLE_MASK	(STM_CR_FRZ | STM_CR_TEN)
+
+struct nxp_stm_cnt {
+	spinlock_t lock;
+	void __iomem *base;
+	u64 overflow;
+	u32 counter;
+	u8 prescaler;
+	bool is_started;
+};
+
+static void nxp_stm_cnt_enable(struct nxp_stm_cnt *stm_cnt)
+{
+	u32 reg;
+
+	reg = readl(STM_CR(stm_cnt->base));
+
+	reg |= STM_ENABLE_MASK;
+
+	writel(reg, STM_CR(stm_cnt->base));
+}
+
+static void nxp_stm_cnt_disable(struct nxp_stm_cnt *stm_cnt)
+{
+	u32 reg;
+
+	reg = readl(STM_CR(stm_cnt->base));
+
+	reg &= ~STM_ENABLE_MASK;
+
+	writel(reg, STM_CR(stm_cnt->base));
+}
+
+static void nxp_stm_cnt_ccr_disable(struct nxp_stm_cnt *stm_cnt)
+{
+	writel(0, STM_CCR0(stm_cnt->base));
+}
+
+static void nxp_stm_cnt_ccr_enable(struct nxp_stm_cnt *stm_cnt)
+{
+	writel(STM_CCR_CEN, STM_CCR0(stm_cnt->base));
+}
+
+static void nxp_stm_cnt_set_overflow(struct nxp_stm_cnt *stm_cnt)
+{
+	writel(UINT_MAX, STM_CMP0(stm_cnt->base));
+}
+
+static u32 nxp_stm_cnt_get_counter(struct nxp_stm_cnt *stm_cnt)
+{
+	return readl(STM_CNT(stm_cnt->base));
+}
+
+static void nxp_stm_cnt_set_counter(struct nxp_stm_cnt *stm_cnt, u32 counter)
+{
+	writel(counter, STM_CNT(stm_cnt->base));
+}
+
+static void nxp_stm_cnt_set_prescaler(struct nxp_stm_cnt *stm_cnt, u8 prescaler)
+{
+	u32 reg;
+
+	reg = readl(STM_CR(stm_cnt->base));
+
+	FIELD_MODIFY(STM_CR_CPS_MASK, &reg, prescaler);
+
+	writel(reg, STM_CR(stm_cnt->base));
+}
+
+static u8 nxp_stm_cnt_get_prescaler(struct nxp_stm_cnt *stm_cnt)
+{
+	u32 reg = readl(STM_CR(stm_cnt->base));
+
+	return FIELD_GET(STM_CR_CPS_MASK, reg);
+}
+
+static bool nxp_stm_cnt_is_started(struct nxp_stm_cnt *stm_cnt)
+{
+	u32 reg;
+
+	reg = readl(STM_CR(stm_cnt->base));
+
+	return !!FIELD_GET(STM_CR_TEN, reg);
+}
+
+static void nxp_stm_cnt_irq_ack(struct nxp_stm_cnt *stm_cnt)
+{
+	writel(STM_CIR_CIF, STM_CIR0(stm_cnt->base));
+}
+
+static irqreturn_t nxp_stm_cnt_irq(int irq, void *dev_id)
+{
+	struct nxp_stm_cnt *stm_cnt = dev_id;
+
+	nxp_stm_cnt_irq_ack(stm_cnt);
+
+	spin_lock(&stm_cnt->lock);
+	stm_cnt->overflow++;
+	spin_unlock(&stm_cnt->lock);
+
+	return IRQ_HANDLED;
+}
+
+static void nxp_stm_cnt_start(struct nxp_stm_cnt *stm_cnt)
+{
+	nxp_stm_cnt_ccr_enable(stm_cnt);
+	nxp_stm_cnt_set_overflow(stm_cnt);
+	nxp_stm_cnt_enable(stm_cnt);
+}
+
+static void nxp_stm_cnt_stop(struct nxp_stm_cnt *stm_cnt)
+{
+	nxp_stm_cnt_disable(stm_cnt);
+	nxp_stm_cnt_irq_ack(stm_cnt);
+	nxp_stm_cnt_ccr_disable(stm_cnt);
+}
+
+static int nxp_stm_cnt_overflow_read(struct counter_device *counter,
+				     struct counter_count *count, u64 *val)
+{
+	struct nxp_stm_cnt *stm_cnt = counter_priv(counter);
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&stm_cnt->lock, irqflags);
+	*val = stm_cnt->overflow;
+	spin_unlock_irqrestore(&stm_cnt->lock, irqflags);
+
+	return 0;
+}
+
+static int nxp_stm_cnt_overflow_write(struct counter_device *counter,
+				      struct counter_count *count, u64 val)
+{
+	struct nxp_stm_cnt *stm_cnt = counter_priv(counter);
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&stm_cnt->lock, irqflags);
+	stm_cnt->overflow = val;
+	spin_unlock_irqrestore(&stm_cnt->lock, irqflags);
+
+	return 0;
+}
+
+static int nxp_stm_cnt_reset_write(struct counter_device *counter,
+				   struct counter_count *count, u8 val)
+{
+	struct nxp_stm_cnt *stm_cnt = counter_priv(counter);
+
+	nxp_stm_cnt_set_counter(stm_cnt, 0);
+	spin_lock(&stm_cnt->lock);
+	stm_cnt->overflow = 0;
+	spin_unlock(&stm_cnt->lock);
+
+	return 0;
+}
+
+static int nxp_stm_cnt_prescaler_read(struct counter_device *counter,
+				      struct counter_count *count, u8 *val)
+{
+	struct nxp_stm_cnt *stm_cnt = counter_priv(counter);
+
+	*val = nxp_stm_cnt_get_prescaler(stm_cnt);
+
+	return 0;
+}
+
+static int nxp_stm_cnt_prescaler_write(struct counter_device *counter,
+				       struct counter_count *count, u8 val)
+{
+	struct nxp_stm_cnt *stm_cnt = counter_priv(counter);
+
+	nxp_stm_cnt_set_prescaler(stm_cnt, val);
+
+	return 0;
+}
+
+static int nxp_stm_cnt_count_enable_write(struct counter_device *counter,
+					  struct counter_count *count, u8 enable)
+{
+	struct nxp_stm_cnt *stm_cnt = counter_priv(counter);
+
+	if (enable)
+		nxp_stm_cnt_start(stm_cnt);
+	else
+		nxp_stm_cnt_stop(stm_cnt);
+
+	return 0;
+}
+
+static int nxp_stm_cnt_count_enable_read(struct counter_device *counter,
+					 struct counter_count *count, u8 *enable)
+{
+	struct nxp_stm_cnt *stm_cnt = counter_priv(counter);
+
+	*enable = nxp_stm_cnt_is_started(stm_cnt);
+
+	return 0;
+}
+
+static struct counter_comp stm_cnt_count_ext[] = {
+	COUNTER_COMP_COUNT_BOOL("reset",  NULL, nxp_stm_cnt_reset_write),
+	COUNTER_COMP_COUNT_U8("prescaler", nxp_stm_cnt_prescaler_read, nxp_stm_cnt_prescaler_write),
+	COUNTER_COMP_COUNT_U64("overflows", nxp_stm_cnt_overflow_read, nxp_stm_cnt_overflow_write),
+	COUNTER_COMP_ENABLE(nxp_stm_cnt_count_enable_read, nxp_stm_cnt_count_enable_write),
+};
+
+static int nxp_stm_cnt_count_read(struct counter_device *dev,
+				  struct counter_count *count, u64 *val)
+{
+	struct nxp_stm_cnt *stm_cnt = counter_priv(dev);
+
+	*val = nxp_stm_cnt_get_counter(stm_cnt);
+
+	return 0;
+}
+
+static const struct counter_ops nxp_stm_cnt_counter_ops = {
+	.count_read  = nxp_stm_cnt_count_read,
+};
+
+static struct counter_count nxp_stm_cnt_counts[] = {
+	{
+		.id = 0,
+		.name = "stm_cnt",
+		.ext = stm_cnt_count_ext,
+		.num_ext = ARRAY_SIZE(stm_cnt_count_ext),
+	},
+};
+
+static int nxp_stm_cnt_suspend(struct device *dev)
+{
+	struct nxp_stm_cnt *stm_cnt = dev_get_drvdata(dev);
+
+	stm_cnt->is_started = nxp_stm_cnt_is_started(stm_cnt);
+
+	if (stm_cnt->is_started) {
+		nxp_stm_cnt_stop(stm_cnt);
+		stm_cnt->prescaler = nxp_stm_cnt_get_prescaler(stm_cnt);
+		stm_cnt->counter = nxp_stm_cnt_get_counter(stm_cnt);
+	}
+
+	return 0;
+}
+
+static int nxp_stm_cnt_resume(struct device *dev)
+{
+	struct nxp_stm_cnt *stm_cnt = dev_get_drvdata(dev);
+
+	if (stm_cnt->is_started) {
+		nxp_stm_cnt_set_counter(stm_cnt, stm_cnt->counter);
+		nxp_stm_cnt_set_prescaler(stm_cnt, stm_cnt->prescaler);
+		nxp_stm_cnt_start(stm_cnt);
+	}
+
+	return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(nxp_stm_cnt_pm_ops, nxp_stm_cnt_suspend,
+				nxp_stm_cnt_resume);
+
+static int nxp_stm_cnt_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct counter_device *counter;
+	struct nxp_stm_cnt *stm_cnt;
+	struct clk *clk;
+	void __iomem *base;
+	int irq, ret;
+
+	base = devm_of_iomap(dev, np, 0, NULL);
+	if (IS_ERR(base))
+		return dev_err_probe(dev, PTR_ERR(base), "Failed to iomap %pOFn\n", np);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return dev_err_probe(dev, irq, "Failed to get IRQ\n");
+
+	clk = devm_clk_get_enabled(dev, NULL);
+	if (IS_ERR(clk))
+		return dev_err_probe(dev, PTR_ERR(clk), "Clock not found\n");
+
+	counter = devm_counter_alloc(dev, sizeof(*stm_cnt));
+	if (!counter)
+		return -ENOMEM;
+
+	stm_cnt = counter_priv(counter);
+
+	stm_cnt->base = base;
+	stm_cnt->overflow = 0;
+	spin_lock_init(&stm_cnt->lock);
+
+	counter->name       = "stm_counter";
+	counter->parent     = &pdev->dev;
+	counter->ops        = &nxp_stm_cnt_counter_ops;
+	counter->counts     = nxp_stm_cnt_counts;
+	counter->num_counts = ARRAY_SIZE(nxp_stm_cnt_counts);
+
+	ret = devm_request_irq(dev, irq, nxp_stm_cnt_irq, IRQF_TIMER | IRQF_NOBALANCING,
+			       dev_name(&counter->dev), stm_cnt);
+	if (ret)
+		return dev_err_probe(dev, ret, "Unable to allocate interrupt line\n");
+
+	ret = devm_counter_add(dev, counter);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to register counter\n");
+
+	platform_set_drvdata(pdev, stm_cnt);
+
+	return 0;
+}
+
+static void nxp_stm_cnt_remove(struct platform_device *pdev)
+{
+	struct nxp_stm_cnt *stm_cnt = platform_get_drvdata(pdev);
+
+	if (nxp_stm_cnt_is_started(stm_cnt))
+		nxp_stm_cnt_stop(stm_cnt);
+}
+
+static const struct of_device_id nxp_stm_cnt_of_match[] = {
+	{ .compatible = "nxp,s32g2-stm-cnt", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, nxp_stm_cnt_of_match);
+
+static struct platform_driver nxp_stm_cnt_driver = {
+	.probe  = nxp_stm_cnt_probe,
+	.remove = nxp_stm_cnt_remove,
+	.driver = {
+		.name           = "nxp-stm-cnt",
+		.pm		= pm_sleep_ptr(&nxp_stm_cnt_pm_ops),
+		.of_match_table = nxp_stm_cnt_of_match,
+	},
+};
+module_platform_driver(nxp_stm_cnt_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Daniel Lezcano");
+MODULE_DESCRIPTION("NXP System Timer Module counter driver");
+MODULE_IMPORT_NS("COUNTER");
-- 
2.43.0



From sumit.garg at kernel.org  Tue Dec 16 23:55:39 2025
From: sumit.garg at kernel.org (Sumit Garg)
Date: Wed, 17 Dec 2025 13:25:39 +0530
Subject: [PATCH v1 00/17] tee: Use bus callbacks instead of driver
 callbacks
In-Reply-To: <ayebinxqpcnl7hpa35ytrudiy7j75u5bdk3enlirkp5pevppeg@6mx6a5fwymwf>
References: <cover.1765472125.git.u.kleine-koenig@baylibre.com>
 <aT--ox375kg2Mzh-@sumit-X1>
 <dhunzydod4d7vj73llpuqemxb5er2ja4emxusr66irwf77jhhb@es4yd2axzl25>
 <CAGptzHOOqLhBnAXDURAzkgckUvRr__UuF1S_7MLV0u-ZxYEdyA@mail.gmail.com>
 <ayebinxqpcnl7hpa35ytrudiy7j75u5bdk3enlirkp5pevppeg@6mx6a5fwymwf>
Message-ID: <aUJh--HGVeJWIilS@sumit-xelite>

On Tue, Dec 16, 2025 at 12:08:38PM +0100, Uwe Kleine-K?nig wrote:
> Hello,
> 
> On Tue, Dec 16, 2025 at 01:08:38PM +0530, Sumit Garg wrote:
> > On Mon, Dec 15, 2025 at 3:02?PM Uwe Kleine-K?nig
> > <u.kleine-koenig at baylibre.com> wrote:
> > > On Mon, Dec 15, 2025 at 04:54:11PM +0900, Sumit Garg wrote:
> > > > Feel free to make the tee_bus_type private as the last patch in the series
> > > > such that any followup driver follows this clean approach.
> > >
> > > There is a bit more to do for that than I'm willing to invest. With my
> > > patch series applied `tee_bus_type` is still used in
> > > drivers/tee/optee/device.c and drivers/tee/tee_core.c.
> > 
> > Oh I see, I guess we need to come with some helpers around device
> > register/unregister from TEE subsystem as well. Let's plan that for a
> > followup patch-set, I don't want this patch-set to be bloated more.
> 
> Don't consider me in for that. But it sounds like a nice addition.
>

No worries, the current cleanup is fine for now.

> > > Maybe it's
> > > sensible to merge these two files into a single one.
> > 
> > It's not possible as the design for TEE bus is to have TEE
> > implementation drivers like OP-TEE, AMD-TEE, TS-TEE, QTEE and so on to
> > register devices on the bus.
> 
> So only OP-TEE uses the bus for devices and the other *-TEE don't. Also
> sounds like something worth to be fixed.

The TEE bus is common for all the TEE implementation drivers which need
to support kernel TEE client drivers. I am aware there will be QTEE and
TS-TEE from past discussion that they will be exposing devices on the
TEE bus.

> 
> > > The things I wonder about additionally are:
> > >
> > >  - if CONFIG_OPTEE=n and CONFIG_TEE=y|m the tee bus is only used for
> > >    drivers but not devices.
> > 
> > Yeah since the devices are rather added by the TEE implementation driver.
> > 
> > >
> > >  - optee_register_device() calls device_create_file() on
> > >    &optee_device->dev after device_register(&optee_device->dev).
> > >    (Attention half-knowledge!) I think device_create_file() should not
> > >    be called on an already registered device (or you have to send a
> > >    uevent afterwards). This should probably use type attribute groups.
> > >    (Or the need_supplicant attribute should be dropped as it isn't very
> > >    useful. This would maybe be considered an ABI change however.)
> > 
> > The reasoning for this attribute should be explained by commit:
> > 7269cba53d90 ("tee: optee: Fix supplicant based device enumeration").
> > In summary it's due to a weird dependency for devices we have with the
> > user-space daemon: tee-supplicant.
> 
> From reading that once I don't understand it. (But no need to explain
> :-)
> 
> Still the file should better be added before device_add() is called.

Noted, let me see if I can get to fix this until someone jumps in before
me.

> 
> > >  - Why does optee_probe() in drivers/tee/optee/smc_abi.c unregister all
> > >    optee devices in its error path (optee_unregister_devices())?
> > 
> > This is mostly to take care of if any device got registered before the
> > failure occured. Let me know if you have a better way to address that.
> 
> Without understanding the tee stuff, I'd say: Don't bother and only undo
> the things that probe did before the failure.
> 

True, but this is special case where if there is any leftover device
registered from the TEE implementation then it is likely going to cause
the corresponding kernel client driver crash.

-Sumit


From Paul-pl.Chen at mediatek.com  Tue Dec 16 23:57:33 2025
From: Paul-pl.Chen at mediatek.com (=?utf-8?B?UGF1bC1wbCBDaGVuICjpmbPmn4/pnJYp?=)
Date: Wed, 17 Dec 2025 07:57:33 +0000
Subject: [PATCH v4 06/19] soc: mediatek: Add runtime PM and top clocks and
 async controls for MMSYS
In-Reply-To: <9d157ab1fbfc268a052b44955192092757ce48bd.camel@mediatek.com>
References: <20250828080855.3502514-1-paul-pl.chen@mediatek.com>
	 <20250828080855.3502514-7-paul-pl.chen@mediatek.com>
	 <9d157ab1fbfc268a052b44955192092757ce48bd.camel@mediatek.com>
Message-ID: <9b88f8f2dc6450c137291e082986e478e8f941a8.camel@mediatek.com>

On Tue, 2025-09-16 at 03:03 +0000, CK Hu (???) wrote:
> On Thu, 2025-08-28 at 16:07 +0800, Paul Chen wrote:
> > From: Nancy Lin <nancy.lin at mediatek.com>
> > 
> > - Add initialization of top clocks and async clocks for each MMSYS.
> > - Add PM runtime control and new functions to manage these clocks.
> > - Add functions to set these clocks according to the default
> > ? configuration of the corresponding MMSYS.
> 
> This patch include 3 things:
> 1. Add runtime PM
> 2. top clock control
> 3. async control
> 
> I would like you to separate these to different patch.
> 
> > 
> > Sure I will seperate it to three different patch.
> > Signed-off-by: Nancy Lin <nancy.lin at mediatek.com>
> > Signed-off-by: Paul-pl Chen <paul-pl.chen at mediatek.com>
> > ---
> 
> [snip]
> 
> > +
> > +int mtk_mmsys_ddp_clk_enable(struct device *dev, enum
> > mtk_ddp_comp_id comp_id)
> 
> This is to control async clock, so change the function name to
> 
> mtk_mmsys_async_clk_enable()
> 
> 
> OK Got it.
> > +{
> > +	struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
> > +	const struct mtk_mmsys_async_info *async = mmsys->data-
> > >async_info;
> > +
> > +	int i;
> > +
> > +	if (!mmsys->data->num_async_info)
> 
> for-loop would check this, so drop this.
> 
Sure, I will drop this condition check.
> > +		return 0;
> > +
> > +	for (i = 0; i < mmsys->data->num_async_info; i++)
> > +		if (comp_id == async[i].comp_id)
> > +			return clk_prepare_enable(mmsys-
> > >async_clk[async[i].index]);
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_clk_enable);
> > +
> > +void mtk_mmsys_ddp_clk_disable(struct device *dev, enum
> > mtk_ddp_comp_id comp_id)
> > +{
> > +	struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
> > +	const struct mtk_mmsys_async_info *async = mmsys->data-
> > >async_info;
> > +	int i;
> > +
> > +	if (!mmsys->data->num_async_info)
> 
> for-loop would check this, so drop this.
> 
> Sure, I will drop this condition check.
> 
> > +		return;
> > +
> > +	for (i = 0; i < mmsys->data->num_async_info; i++)
> > +		if (comp_id == async[i].comp_id)
> > +			clk_disable_unprepare(mmsys-
> > >async_clk[async[i].index]);
> > +}
> > +EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_clk_disable);
> > +
> > +void mtk_mmsys_ddp_config(struct device *dev, enum mtk_ddp_comp_id
> > comp_id,
> > +			? int width, int height, struct cmdq_pkt
> > *cmdq_pkt)
> 
> This is to control async. So change the function name to
> 
> mtk_mmsys_async_config()
> 
> > +{
> > +	struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
> > +	const struct mtk_mmsys_async_info *async = mmsys->data-
> > >async_info;
> > +	int i;
> > +	u32 val;
> > +
> > +	if (!mmsys->data->num_async_info)
> 
> If mmsys->data->num_async_info = 0, then i = 0, and it would return
> below.
> So this checking is redundant.
> 
> > +		return;
> > +
> > +	for (i = 0; i < mmsys->data->num_async_info; i++)
> > +		if (comp_id == async[i].comp_id)
> > +			break;
> > +
> > +	if (i == mmsys->data->num_async_info)
> > +		return;
> > +
> > +	val = FIELD_PREP(GENMASK(31, 16), height);
> > +	val |= FIELD_PREP(GENMASK(15, 0), width);
> > +	mtk_mmsys_update_bits(mmsys, async[i].offset,
> > async[i].mask, val, cmdq_pkt);
> > +}
> > +EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_config);
> > +
> > +void mtk_mmsys_default_config(struct device *dev)
> 
> Why not do this when mmsys probe?

> 
> 
> The mtk_mmsys_default_config is also using at DP Suspnd /Resume.
Hence, we need to keep the default config setting at here.

Best, Paul-pl Chen

> 
>  
> 
> Regards,
> CK
> 
> > +{
> > +	struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
> > +	const struct mtk_mmsys_default *def_config = mmsys->data-
> > >def_config;
> > +	int i;
> > +
> > +	if (!mmsys->data->num_def_config)
> > +		return;
> > +
> > +	for (i = 0; i < mmsys->data->num_def_config; i++)
> > +		mtk_mmsys_update_bits(mmsys, def_config[i].offset,
> > def_config[i].mask,
> > +				????? def_config[i].val, NULL);
> > +}
> > +EXPORT_SYMBOL_GPL(mtk_mmsys_default_config);
> > +
> 
> 


From daniel.baluta at gmail.com  Wed Dec 17 00:07:17 2025
From: daniel.baluta at gmail.com (Daniel Baluta)
Date: Wed, 17 Dec 2025 10:07:17 +0200
Subject: [PATCH 0/3] arm64: dts: Initial support for i.MX952
In-Reply-To: <20251217-imx952-v1-v1-0-a55a7fe2df0b@nxp.com>
References: <20251217-imx952-v1-v1-0-a55a7fe2df0b@nxp.com>
Message-ID: <CAEnQRZBTkXtiT1attxPpjXUwLz9bMVXP8_-ChBFDY=V9p3NR8A@mail.gmail.com>

On Wed, Dec 17, 2025 at 3:59?AM Peng Fan (OSS) <peng.fan at oss.nxp.com> wrote:
>
> Initial device tree for i.MX952 and i.MX952-EVK.
> i.MX952 is designed for AI-powered sensor fusion and vision sensing
> applications, it features 4 Corte-A55, 1 Cortex-M33, 1 Cortex-M7 and
> NXP eIQ NPU and advanced graphics, video and advanced security with
> edgelock.
>
> Product info could be found at[1].
>
> Note:
> There is checkpatch error for the pin headers:
> ERROR: Macros with complex values should be enclosed in parentheses
> checkpatch.pl maintainer said "Just ignore the message instead", see[2]
>
> [1]https://www.nxp.com/products/i.MX-952
> [2]https://lore.kernel.org/all/fce65a7761fb0e880beb469e2521598f at perches.com/

I think this information ^ should also be placed in the commit message
of one of the
patches that gets merged in the tree. E.g patch 2/3 or 3/3.


From dev.jain at arm.com  Wed Dec 17 00:12:14 2025
From: dev.jain at arm.com (Dev Jain)
Date: Wed, 17 Dec 2025 13:42:14 +0530
Subject: [PATCH v1 08/13] arm64: mm: Simplify
 __flush_tlb_range_limit_excess()
In-Reply-To: <20251216144601.2106412-9-ryan.roberts@arm.com>
References: <20251216144601.2106412-1-ryan.roberts@arm.com>
 <20251216144601.2106412-9-ryan.roberts@arm.com>
Message-ID: <3de2b568-66f8-432f-a501-b19ca6c3a805@arm.com>


On 16/12/25 8:15 pm, Ryan Roberts wrote:
> From: Will Deacon <will at kernel.org>
>
> __flush_tlb_range_limit_excess() is unnecessarily complicated:
>
>   - It takes a 'start', 'end' and 'pages' argument, whereas it only
>     needs 'pages' (which the caller has computed from the other two
>     arguments!).
>
>   - It erroneously compares 'pages' with MAX_TLBI_RANGE_PAGES when
>     the system doesn't support range-based invalidation but the range to
>     be invalidated would result in fewer than MAX_DVM_OPS invalidations.
>
> Simplify the function so that it no longer takes the 'start' and 'end'
> arguments and only considers the MAX_TLBI_RANGE_PAGES threshold on
> systems that implement range-based invalidation.
>
> Signed-off-by: Will Deacon <will at kernel.org>
> Signed-off-by: Ryan Roberts <ryan.roberts at arm.com>
> ---
>  arch/arm64/include/asm/tlbflush.h | 20 ++++++--------------
>  1 file changed, 6 insertions(+), 14 deletions(-)
>
> diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
> index 0e1902f66e01..3b72a71feac0 100644
> --- a/arch/arm64/include/asm/tlbflush.h
> +++ b/arch/arm64/include/asm/tlbflush.h
> @@ -527,21 +527,13 @@ static __always_inline void __flush_tlb_range_op(tlbi_op lop, tlbi_op rop,
>  #define __flush_s2_tlb_range_op(op, start, pages, stride, tlb_level) \
>  	__flush_tlb_range_op(op, r##op, start, pages, stride, 0, tlb_level, kvm_lpa2_is_enabled())
>  
> -static inline bool __flush_tlb_range_limit_excess(unsigned long start,
> -		unsigned long end, unsigned long pages, unsigned long stride)
> +static inline bool __flush_tlb_range_limit_excess(unsigned long pages,
> +						  unsigned long stride)
>  {
> -	/*
> -	 * When the system does not support TLB range based flush
> -	 * operation, (MAX_DVM_OPS - 1) pages can be handled. But
> -	 * with TLB range based operation, MAX_TLBI_RANGE_PAGES
> -	 * pages can be handled.
> -	 */
> -	if ((!system_supports_tlb_range() &&
> -	     (end - start) >= (MAX_DVM_OPS * stride)) ||
> -	    pages > MAX_TLBI_RANGE_PAGES)
> +	if (system_supports_tlb_range() && pages > MAX_TLBI_RANGE_PAGES)
>  		return true;
>  
> -	return false;
> +	return pages >= (MAX_DVM_OPS * stride) >> PAGE_SHIFT;

The function will return true if tlb range is supported, but
((MAX_DVM_OPS * stride) >> PAGE_SHIFT) < pages <= MAX_TLBI_RANGE_PAGES.
So I think you need to do
https://lore.kernel.org/all/1b15b4f0-5490-4dac-8344-e716dd189751 at arm.com/

>  }
>  
>  static inline void __flush_tlb_range_nosync(struct mm_struct *mm,
> @@ -555,7 +547,7 @@ static inline void __flush_tlb_range_nosync(struct mm_struct *mm,
>  	end = round_up(end, stride);
>  	pages = (end - start) >> PAGE_SHIFT;
>  
> -	if (__flush_tlb_range_limit_excess(start, end, pages, stride)) {
> +	if (__flush_tlb_range_limit_excess(pages, stride)) {
>  		flush_tlb_mm(mm);
>  		return;
>  	}
> @@ -619,7 +611,7 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end
>  	end = round_up(end, stride);
>  	pages = (end - start) >> PAGE_SHIFT;
>  
> -	if (__flush_tlb_range_limit_excess(start, end, pages, stride)) {
> +	if (__flush_tlb_range_limit_excess(pages, stride)) {
>  		flush_tlb_all();
>  		return;
>  	}


From alexander.stein at ew.tq-group.com  Wed Dec 17 00:13:02 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Wed, 17 Dec 2025 09:13:02 +0100
Subject: [PATCH 1/1] phy: freescale: imx8qm-hsio: provide regmap names
Message-ID: <20251217081303.1181922-1-alexander.stein@ew.tq-group.com>

This driver uses multiple regmaps, which will causes name conflicts
in debugfs like:
  debugfs: '5f1a0000.phy' already exists in 'regmap'
Fix this by using a dedicated regmap config for each resource, each
having a dedicated regmap name.

Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 drivers/phy/freescale/phy-fsl-imx8qm-hsio.c | 23 +++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)

diff --git a/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c b/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c
index 977d21d753a59..0a0e10792dff4 100644
--- a/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c
+++ b/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c
@@ -107,7 +107,22 @@ static const char * const lan2_pcieb_clks[] = {"apb_pclk2", "pclk2", "ctl1_crr",
 static const char * const lan2_sata_clks[] = {"pclk2", "epcs_tx", "epcs_rx",
 					      "phy1_crr", "misc_crr"};
 
-static const struct regmap_config regmap_config = {
+static const struct regmap_config regmap_phy_config = {
+	.name = "phy",
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+};
+
+static const struct regmap_config regmap_ctrl_config = {
+	.name = "ctrl",
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+};
+
+static const struct regmap_config regmap_misc_config = {
+	.name = "misc",
 	.reg_bits = 32,
 	.val_bits = 32,
 	.reg_stride = 4,
@@ -562,19 +577,19 @@ static int imx_hsio_probe(struct platform_device *pdev)
 		return PTR_ERR(priv->base);
 
 	off = devm_platform_ioremap_resource_byname(pdev, "phy");
-	priv->phy = devm_regmap_init_mmio(dev, off, &regmap_config);
+	priv->phy = devm_regmap_init_mmio(dev, off, &regmap_phy_config);
 	if (IS_ERR(priv->phy))
 		return dev_err_probe(dev, PTR_ERR(priv->phy),
 				     "unable to find phy csr registers\n");
 
 	off = devm_platform_ioremap_resource_byname(pdev, "ctrl");
-	priv->ctrl = devm_regmap_init_mmio(dev, off, &regmap_config);
+	priv->ctrl = devm_regmap_init_mmio(dev, off, &regmap_ctrl_config);
 	if (IS_ERR(priv->ctrl))
 		return dev_err_probe(dev, PTR_ERR(priv->ctrl),
 				     "unable to find ctrl csr registers\n");
 
 	off = devm_platform_ioremap_resource_byname(pdev, "misc");
-	priv->misc = devm_regmap_init_mmio(dev, off, &regmap_config);
+	priv->misc = devm_regmap_init_mmio(dev, off, &regmap_misc_config);
 	if (IS_ERR(priv->misc))
 		return dev_err_probe(dev, PTR_ERR(priv->misc),
 				     "unable to find misc csr registers\n");
-- 
2.43.0



From amelie.delaunay at foss.st.com  Wed Dec 17 00:15:03 2025
From: amelie.delaunay at foss.st.com (Amelie Delaunay)
Date: Wed, 17 Dec 2025 09:15:03 +0100
Subject: [PATCH v2] dmaengine: stm32-mdma: initialize m2m_hw_period and ccr
 to fix warnings
Message-ID: <20251217-mdma_warnings_fix-v2-1-340200e0bb55@foss.st.com>

From: Cl?ment Le Goffic <clement.legoffic at foss.st.com>

m2m_hw_period is initialized only when chan_config->m2m_hw is true. This
triggers a warning:
?m2m_hw_period? may be used uninitialized [-Wmaybe-uninitialized]
Although m2m_hw_period is only used when chan_config->m2m_hw is true and
ignored otherwise, initialize it unconditionally to 0.

ccr is initialized by stm32_mdma_set_xfer_param() when the sg list is not
empty. This triggers a warning:
?ccr? may be used uninitialized [-Wmaybe-uninitialized]
Indeed, it could be used uninitialized if the sg list is empty. Initialize
it to 0.

Signed-off-by: Cl?ment Le Goffic <clement.legoffic at foss.st.com>
Reviewed-by: Cl?ment Le Goffic <legoffic.clement at gmail.com>
Signed-off-by: Amelie Delaunay <amelie.delaunay at foss.st.com>
---
Changes in v2:
- Added code-review trailer
- Rebased on top of v6.19-rc1 
- Link to v1: https://lore.kernel.org/r/20251030-mdma_warnings_fix-v1-1-987f67c75794 at foss.st.com
---
 drivers/dma/stm32/stm32-mdma.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/dma/stm32/stm32-mdma.c b/drivers/dma/stm32/stm32-mdma.c
index 080c1c725216..b87d41b234df 100644
--- a/drivers/dma/stm32/stm32-mdma.c
+++ b/drivers/dma/stm32/stm32-mdma.c
@@ -731,7 +731,7 @@ static int stm32_mdma_setup_xfer(struct stm32_mdma_chan *chan,
 	struct stm32_mdma_chan_config *chan_config = &chan->chan_config;
 	struct scatterlist *sg;
 	dma_addr_t src_addr, dst_addr;
-	u32 m2m_hw_period, ccr, ctcr, ctbr;
+	u32 m2m_hw_period = 0, ccr = 0, ctcr, ctbr;
 	int i, ret = 0;
 
 	if (chan_config->m2m_hw)

---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20251030-mdma_warnings_fix-df4b3d1405ed

Best regards,
-- 
Amelie Delaunay <amelie.delaunay at foss.st.com>



From krzk at kernel.org  Wed Dec 17 00:18:46 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 17 Dec 2025 09:18:46 +0100
Subject: [PATCH v3 0/3] Add support for exynos5250-manta (Google Nexus 10)
In-Reply-To: <20251215-lat3st-staging-v3-0-2e4914b64dd8@timmermann.space>
References: <20251215-lat3st-staging-v3-0-2e4914b64dd8@timmermann.space>
Message-ID: <20251217-placid-taipan-of-fascination-20e002@quoll>

On Mon, Dec 15, 2025 at 04:05:21PM +0100, Lukas Timmermann wrote:
> This patch series adds initial support for the google-manta board, known
> as Google Nexus 10 to users. The device is powered by
> the Exynos 5250 SoC. The bindings for the notification led are already 
> in the kernel mailing list, got recently applied and can be found here:

$ git describe
next-20251217
$ git grep ams,as3668
Nothing.

> https://lore.kernel.org/linux-leds/20251125114015.355487-1-linux at timmermann.space/

That's the posting, if you wanted to convince me, you could link to
actual commits in maintainer's tree.

Please ping me when this reaches next.

Best regards,
Krzysztof



From Guocai.He.CN at windriver.com  Wed Dec 17 00:21:19 2025
From: Guocai.He.CN at windriver.com (He, Guocai (CN))
Date: Wed, 17 Dec 2025 08:21:19 +0000
Subject: [BUG][RT][ti-j72xx] spi: cadence-quadspi: boot failed with rtmutex
 deadlock detected
Message-ID: <CO6PR11MB558695EFB87C578370014430CDABA@CO6PR11MB5586.namprd11.prod.outlook.com>

Hi all,

I am seeing an reproducible issue in
drivers/spi/spi-cadence-quadspi.c on TI J72xx platform.

Kernel:
  v6.1/standard/preempt-rt/ti-sdk-6.1/ti-j7xxx
  (based on Linux v6.1.159 PREEMPT_RT)

Platform:
  TI J72xx
  QSPI controller: Cadence QuadSPI

Problem description:
when boot fail with the following call trace:
[    2.028205] ------------[ cut here ]------------
[    2.028213] rtmutex deadlock detected
[    2.028227] WARNING: CPU: 1 PID: 50 at kernel/locking/rtmutex.c:1642 __rt_mutex_slowlock_locked.constprop.0+0x184/0x2dc
[    2.028246] Modules linked in:
[    2.028256] CPU: 1 PID: 50 Comm: kworker/u8:1 Not tainted 6.1.159-rt32-yocto-preempt-rt #1
[    2.028263] Hardware name: Texas Instruments AM62A7 SK (DT)
[    2.028269] Workqueue: events_unbound deferred_probe_work_func
[    2.028282] pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[    2.028288] pc : __rt_mutex_slowlock_locked.constprop.0+0x184/0x2dc
[    2.028294] lr : __rt_mutex_slowlock_locked.constprop.0+0x184/0x2dc
[    2.028300] sp : fffffe000abef090
[    2.028302] x29: fffffe000abef110 x28: fffffe00090dc620 x27: 0000000000000001
[    2.028311] x26: fffffc0801af98f8 x25: 0000000000000000 x24: fffffc0804ac4088
[    2.028319] x23: 0000000000000000 x22: fffffe000abef098 x21: 00000000ffffffdd
[    2.028327] x20: fffffc0801a01d80 x19: fffffc08034b53e0 x18: ffffffffffffffff
[    2.028335] x17: 0000000000000000 x16: 0000000000000001 x15: fffffe000abef5b0
[    2.028343] x14: fffffc0804d1ad8e x13: 0a64657463657465 x12: 64206b636f6c6461
[    2.028351] x11: fffffffffffe0000 x10: 2d2d2d2d2d2d2d2d x9 : fffffe00080fc87c
[    2.028359] x8 : fffffe000abef090 x7 : 6b636f6c64616564 x6 : 000000000000000c
[    2.028367] x5 : 00000000fffff141 x4 : fffffe000abeee40 x3 : 0000000000000000
[    2.028375] x2 : 0000000000000000 x1 : 0000000000000000 x0 : fffffc0801a01d80
[    2.028384] Call trace:
[    2.028386]  __rt_mutex_slowlock_locked.constprop.0+0x184/0x2dc
[    2.028393]  mutex_lock+0x98/0xbc
[    2.028401]  spi_controller_resume+0x28/0xbc
[    2.028410]  cqspi_resume+0x58/0xa4
[    2.028418]  pm_generic_runtime_resume+0x34/0x50
[    2.028426]  __genpd_runtime_resume+0x38/0x90
[    2.028434]  genpd_runtime_resume+0x148/0x27c
[    2.028443]  __rpm_callback+0x50/0x1b4
[    2.028452]  rpm_callback+0x74/0x80
[    2.028459]  rpm_resume+0x5e4/0x85c
[    2.028467]  __pm_runtime_resume+0x5c/0xc0
[    2.028474]  cqspi_exec_mem_op+0x64/0xf50
[    2.028481]  spi_mem_exec_op+0x3bc/0x410
[    2.028487]  spinand_reset_op.constprop.0+0x64/0xa0
[    2.028495]  spinand_probe+0xdc/0x650
[    2.028502]  spi_mem_probe+0x74/0xc4
[    2.028508]  spi_probe+0x8c/0xec
[    2.028515]  really_probe+0xc4/0x2e0
[    2.028523]  __driver_probe_device+0x80/0x120
[    2.028531]  driver_probe_device+0xdc/0x170
[    2.028539]  __device_attach_driver+0xc0/0x14c
[    2.028548]  bus_for_each_drv+0x88/0xec
[    2.028555]  __device_attach+0xa8/0x1ac
[    2.028563]  device_initial_probe+0x1c/0x30
[    2.028572]  bus_probe_device+0xa4/0xb0
[    2.028579]  device_add+0x380/0x784
[    2.028586]  __spi_add_device+0x74/0x114
[    2.028592]  spi_add_device+0x68/0xa0
[    2.028597]  spi_register_controller+0x730/0xb00
[    2.028602]  cqspi_probe+0x690/0x98c
[    2.028608]  platform_probe+0x70/0xcc
[    2.028615]  really_probe+0xc4/0x2e0
[    2.028623]  __driver_probe_device+0x80/0x120
[    2.028631]  driver_probe_device+0xdc/0x170
[    2.028639]  __device_attach_driver+0xc0/0x14c
[    2.028648]  bus_for_each_drv+0x88/0xec
[    2.028655]  __device_attach+0xa8/0x1ac
[    2.028663]  device_initial_probe+0x1c/0x30
[    2.028671]  bus_probe_device+0xa4/0xb0
[    2.028679]  deferred_probe_work_func+0x90/0xd0
[    2.028687]  process_one_work+0x1f8/0x4b0
[    2.028696]  worker_thread+0x238/0x440
[    2.028703]  kthread+0x138/0x140
[    2.028710]  ret_from_fork+0x10/0x20
[    2.028718] ---[ end trace 0000000000000000 ]---

Analysis:
* 18db8c7f20a6 (HEAD) Revert "spi: cadence-qspi: fix pointer reference in runtime PM hooks"
*   7083c6620486 Merge branch 'v6.1/standard/base' into v6.1/standard/preempt-rt/ti-sdk-6.1/ti-j7xxx
|\
| *   2c1b513331dc Merge tag 'v6.1.140' into v6.1/standard/base
| |\
| | * da3c5173c55f (tag: v6.1.140) Linux 6.1.140
| | * 05e85d376720 x86/modules: Set VM_FLUSH_RESET_PERMS in module_alloc()

It is ok at da3c5173c55f?but it is bad at 7083c6620486.
I revert the commit(2c914aac952) which merged from stable release,  it also ok at 18db8c7f20a6.
Maybe it is a compatibility issue between v6.1/standard/preempt-rt/ti-sdk-6.1/ti-j7xxx and the stable release.

if this is an known issue ? 

Thanks,
Guocai He

From u.kleine-koenig at baylibre.com  Wed Dec 17 00:21:41 2025
From: u.kleine-koenig at baylibre.com (Uwe =?utf-8?Q?Kleine-K=C3=B6nig?=)
Date: Wed, 17 Dec 2025 09:21:41 +0100
Subject: [PATCH v1 00/17] tee: Use bus callbacks instead of driver
 callbacks
In-Reply-To: <aUJh--HGVeJWIilS@sumit-xelite>
References: <cover.1765472125.git.u.kleine-koenig@baylibre.com>
 <aT--ox375kg2Mzh-@sumit-X1>
 <dhunzydod4d7vj73llpuqemxb5er2ja4emxusr66irwf77jhhb@es4yd2axzl25>
 <CAGptzHOOqLhBnAXDURAzkgckUvRr__UuF1S_7MLV0u-ZxYEdyA@mail.gmail.com>
 <ayebinxqpcnl7hpa35ytrudiy7j75u5bdk3enlirkp5pevppeg@6mx6a5fwymwf>
 <aUJh--HGVeJWIilS@sumit-xelite>
Message-ID: <max5wxkcjjvnftwfwgymybwbnvf5s3ytwpy4oo5i74kfvnav4m@m2wasqyxsf4h>

Hello Sumit,

On Wed, Dec 17, 2025 at 01:25:39PM +0530, Sumit Garg wrote:
> On Tue, Dec 16, 2025 at 12:08:38PM +0100, Uwe Kleine-K?nig wrote:
> > On Tue, Dec 16, 2025 at 01:08:38PM +0530, Sumit Garg wrote:
> > > On Mon, Dec 15, 2025 at 3:02?PM Uwe Kleine-K?nig
> > > <u.kleine-koenig at baylibre.com> wrote:
> > > >  - Why does optee_probe() in drivers/tee/optee/smc_abi.c unregister all
> > > >    optee devices in its error path (optee_unregister_devices())?
> > > 
> > > This is mostly to take care of if any device got registered before the
> > > failure occured. Let me know if you have a better way to address that.
> > 
> > Without understanding the tee stuff, I'd say: Don't bother and only undo
> > the things that probe did before the failure.
> 
> True, but this is special case where if there is any leftover device
> registered from the TEE implementation then it is likely going to cause
> the corresponding kernel client driver crash.

You are aware that this is racy? So if a driver crashes e.g. after
teedev_close_context() it might happen that it is registered just after
optee_unregister_devices() returns.

Best regards
Uwe
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251217/6faec691/attachment-0001.sig>

From krzk at kernel.org  Wed Dec 17 00:22:41 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 17 Dec 2025 09:22:41 +0100
Subject: [PATCH v3 2/3] ARM: dts: exynos: Add Google Manta (Nexus 10)
In-Reply-To: <20251215-lat3st-staging-v3-2-2e4914b64dd8@timmermann.space>
References: <20251215-lat3st-staging-v3-0-2e4914b64dd8@timmermann.space>
 <20251215-lat3st-staging-v3-2-2e4914b64dd8@timmermann.space>
Message-ID: <7a942f63-4193-44d2-a459-c19e2baa5281@kernel.org>

On 15/12/2025 16:05, Lukas Timmermann wrote:
> +
> +&pinctrl_1 {
> +	bh1721fvc_reset: bh1721fvc-reset-pins {
> +		samsung,pins = "gph1-2";
> +		samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
> +		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
> +	};
> +	msense_rst: msense-rst-pins {
> +		samsung,pins = "gpg2-0";
> +		samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
> +	};
> +	onewire_sleep: onewire-sleep-pins {
> +		samsung,pins = "gpg0-0";
> +		samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
> +		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
> +		samsung,pin-con-pdn = <EXYNOS_PIN_PDN_INPUT>;
> +		samsung,pin-pud-pdn = <EXYNOS_PIN_PULL_NONE>;
> +	};


I really wonder what did you take as reference/starting point. None of
new files follow such syntax without blank lines. Neither do Google
devices for Exynos5250.

Please rewrite the DTS to match the latest used style from arm64. This
also includes sorting pin nodes - if there are not grouped, then by pin
name.

You also got some other comments. In general, if you took recent file as
the starting point then most of the nits would be gone.

Best regards,
Krzysztof


From richard.genoud at bootlin.com  Wed Dec 17 00:25:00 2025
From: richard.genoud at bootlin.com (Richard Genoud)
Date: Wed, 17 Dec 2025 09:25:00 +0100
Subject: [PATCH v2 0/4] Introduce Allwinner H616 PWM controller
Message-ID: <20251217082504.80226-1-richard.genoud@bootlin.com>

Allwinner H616 PWM controller is quite different from the A10 one.

It can drive 6 PWM channels, and like for the A10, each channel has a
bypass that permits to output a clock, bypassing the PWM logic, when
enabled.

But, the channels are paired 2 by 2, sharing a first set of
MUX/prescaler/gate.
Then, for each channel, there's another prescaler (that will be bypassed
if the bypass is enabled for this channel).

It looks like that:
            _____      ______      ________
OSC24M --->|     |    |      |    |        |
APB1 ----->| Mux |--->| Gate |--->| /div_m |-----> PWM_clock_src_xy
           |_____|    |______|    |________|
                          ________
                         |        |
                      +->| /div_k |---> PWM_clock_x
                      |  |________|
                      |    ______
                      |   |      |
                      +-->| Gate |----> PWM_bypass_clock_x
                      |   |______|
PWM_clock_src_xy -----+   ________
                      |  |        |
                      +->| /div_k |---> PWM_clock_y
                      |  |________|
                      |    ______
                      |   |      |
                      +-->| Gate |----> PWM_bypass_clock_y
                          |______|

Where xy can be 0/1, 2/3, 4/5

PWM_clock_x/y serve for the PWM purpose.
PWM_bypass_clock_x/y serve for the clock-provider purpose.
The common clock framework has been used to manage those clocks.

This PWM driver serves as a clock-provider for PWM_bypass_clocks.
This is needed for example by the embedded AC300 PHY which clock comes
from PMW5 pin (PB12).

This series is based onto v6.19-rc1

Changes since v1:
- rebase onto v6.19-rc1
- add missing headers
- remove MODULE_ALIAS (suggested by Krzysztof)
- use sun4i-pwm binding instead of creating a new one (suggested by Krzysztof)
- retrieve the parent clocks from the devicetree
- switch num_parents to unsigned int

Richard Genoud (4):
  dt-bindings: pwm: allwinner: add h616 pwm compatible
  pwm: sun50i: Add H616 PWM support
  arm64: dts: allwinner: h616: add PWM controller
  MAINTAINERS: Add entry on Allwinner H616 PWM driver

 .../bindings/pwm/allwinner,sun4i-a10-pwm.yaml |  19 +-
 MAINTAINERS                                   |   5 +
 .../arm64/boot/dts/allwinner/sun50i-h616.dtsi |  47 +
 drivers/pwm/Kconfig                           |  12 +
 drivers/pwm/Makefile                          |   1 +
 drivers/pwm/pwm-sun50i-h616.c                 | 892 ++++++++++++++++++
 6 files changed, 975 insertions(+), 1 deletion(-)
 create mode 100644 drivers/pwm/pwm-sun50i-h616.c


base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
-- 
2.47.3



From richard.genoud at bootlin.com  Wed Dec 17 00:25:01 2025
From: richard.genoud at bootlin.com (Richard Genoud)
Date: Wed, 17 Dec 2025 09:25:01 +0100
Subject: [PATCH v2 1/4] dt-bindings: pwm: allwinner: add h616 pwm compatible
In-Reply-To: <20251217082504.80226-1-richard.genoud@bootlin.com>
References: <20251217082504.80226-1-richard.genoud@bootlin.com>
Message-ID: <20251217082504.80226-2-richard.genoud@bootlin.com>

Allwinner H616 PWM block is quite different from the A10 or H6, but at
the end, it uses the same clocks as the H6; so the sun4i pwm binding can
be used.
It has 6 channels than can generate PWM waveforms or clocks if bypass is
enabled.

Suggested-by: Krzysztof Kozlowski <krzk at kernel.org>
Signed-off-by: Richard Genoud <richard.genoud at bootlin.com>
---
 .../bindings/pwm/allwinner,sun4i-a10-pwm.yaml | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml b/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml
index 1197858e431f..4f58110ec98f 100644
--- a/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml
+++ b/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml
@@ -14,6 +14,9 @@ properties:
   "#pwm-cells":
     const: 3
 
+  "#clock-cells":
+    const: 1
+
   compatible:
     oneOf:
       - const: allwinner,sun4i-a10-pwm
@@ -36,6 +39,7 @@ properties:
           - const: allwinner,sun50i-h5-pwm
           - const: allwinner,sun5i-a13-pwm
       - const: allwinner,sun50i-h6-pwm
+      - const: allwinner,sun50i-h616-pwm
 
   reg:
     maxItems: 1
@@ -62,7 +66,9 @@ allOf:
       properties:
         compatible:
           contains:
-            const: allwinner,sun50i-h6-pwm
+            enum:
+              - allwinner,sun50i-h6-pwm
+              - allwinner,sun50i-h616-pwm
 
     then:
       properties:
@@ -83,6 +89,17 @@ allOf:
         clocks:
           maxItems: 1
 
+  - if:
+      not:
+        properties:
+          compatible:
+            contains:
+              const: allwinner,sun50i-h616-pwm
+
+    then:
+      properties:
+        "#clock-cells": false
+
 required:
   - compatible
   - reg
-- 
2.47.3



From richard.genoud at bootlin.com  Wed Dec 17 00:25:02 2025
From: richard.genoud at bootlin.com (Richard Genoud)
Date: Wed, 17 Dec 2025 09:25:02 +0100
Subject: [PATCH v2 2/4] pwm: sun50i: Add H616 PWM support
In-Reply-To: <20251217082504.80226-1-richard.genoud@bootlin.com>
References: <20251217082504.80226-1-richard.genoud@bootlin.com>
Message-ID: <20251217082504.80226-3-richard.genoud@bootlin.com>

Add driver for Allwinner H616 PWM controller, supporting up to 6
channels.
Those channels output can be either a PWM signal output or a clock
output, thanks to the bypass.

The channels are paired (0/1, 2/3 and 4/5) and each pair has a
prescaler/mux/gate.
Moreover, each channel has its own prescaler and bypass.

Tested-by: Joao Schim <joao at schimsalabim.eu>
Signed-off-by: Richard Genoud <richard.genoud at bootlin.com>
---
 drivers/pwm/Kconfig           |  12 +
 drivers/pwm/Makefile          |   1 +
 drivers/pwm/pwm-sun50i-h616.c | 892 ++++++++++++++++++++++++++++++++++
 3 files changed, 905 insertions(+)
 create mode 100644 drivers/pwm/pwm-sun50i-h616.c

diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 6f3147518376..66534e033761 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -736,6 +736,18 @@ config PWM_SUN4I
 	  To compile this driver as a module, choose M here: the module
 	  will be called pwm-sun4i.
 
+config PWM_SUN50I_H616
+	tristate "Allwinner H616 PWM support"
+	depends on ARCH_SUNXI || COMPILE_TEST
+	depends on HAS_IOMEM && COMMON_CLK
+	help
+	  Generic PWM framework driver for Allwinner H616 SoCs.
+	  It supports generic PWM, but can also provides a plain clock.
+	  The AC300 PHY integrated in H616 SoC needs such a clock.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called pwm-h616.
+
 config PWM_SUNPLUS
 	tristate "Sunplus PWM support"
 	depends on ARCH_SUNPLUS || COMPILE_TEST
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 0dc0d2b69025..a16ae9eef9e5 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_PWM_STM32)		+= pwm-stm32.o
 obj-$(CONFIG_PWM_STM32_LP)	+= pwm-stm32-lp.o
 obj-$(CONFIG_PWM_STMPE)		+= pwm-stmpe.o
 obj-$(CONFIG_PWM_SUN4I)		+= pwm-sun4i.o
+obj-$(CONFIG_PWM_SUN50I_H616)	+= pwm-sun50i-h616.o
 obj-$(CONFIG_PWM_SUNPLUS)	+= pwm-sunplus.o
 obj-$(CONFIG_PWM_TEGRA)		+= pwm-tegra.o
 obj-$(CONFIG_PWM_TH1520)	+= pwm_th1520.o
diff --git a/drivers/pwm/pwm-sun50i-h616.c b/drivers/pwm/pwm-sun50i-h616.c
new file mode 100644
index 000000000000..b002ea5935e4
--- /dev/null
+++ b/drivers/pwm/pwm-sun50i-h616.c
@@ -0,0 +1,892 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for Allwinner H616 Pulse Width Modulation Controller
+ *
+ * (C) Copyright 2025 Richard Genoud, Bootlin <richard.genoud at bootlin.com>
+ *
+ * Based on drivers/pwm/pwm-sun4i.c with Copyright:
+ *
+ * Copyright (C) 2014 Alexandre Belloni <alexandre.belloni at bootlin.com>
+ *
+ * Limitations:
+ * - When outputing the source clock directly, the PWM logic is bypassed and the
+ *   currently running period is not guaranteed to be completed.
+ * - As the channels are paired (0/1, 2/3, 4/5), they share the same clock
+ *   source and prescaler(div_m), but they also have their own prescaler(div_k)
+ *   and bypass.
+ *
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/reset.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+
+#ifndef UINT32_MAX
+#define UINT32_MAX 0xffffffffU
+#endif
+
+/* PWM IRQ Enable Register */
+#define PWM_IER				0x0
+
+/* PWM IRQ Status Register */
+#define PWM_ISR				0x4
+
+/* PWM Capture IRQ Enable Register */
+#define PWM_CIER			0x10
+
+/* PWM Capture IRQ Status Register */
+#define PWM_CISR			0x14
+
+/* PWMCC Pairs Clock Configuration Registers */
+#define PWM_XY_CLK_CR(pair)		(0x20 + ((pair) * 0x4))
+#define PWM_XY_CLK_CR_SRC_SHIFT		7
+#define PWM_XY_CLK_CR_SRC_MASK		1
+#define PWM_XY_CLK_CR_GATE_BIT		4
+#define PWM_XY_CLK_CR_BYPASS_BIT(chan)	((chan) % 2 + 5)
+#define PWM_XY_CLK_CR_DIV_M_SHIFT	0
+
+/* PWMCC Pairs Dead Zone Control Registers */
+#define PWM_XY_DZ(pair)			(0x30 + ((pair) * 0x4))
+
+/* PWM Enable Register */
+#define PWM_ENR				0x40
+#define PWM_ENABLE(x)			BIT(x)
+
+/* PWM Capture Enable Register */
+#define PWM_CER				0x44
+
+/* PWM Control Register */
+#define PWM_CTRL_REG(chan)		(0x60 + (chan) * 0x20)
+#define PWM_CTRL_PRESCAL_K_SHIFT	0
+#define PWM_CTRL_PRESCAL_K_WIDTH	8
+#define PWM_CTRL_ACTIVE_STATE		BIT(8)
+
+/* PWM Period Register */
+#define PWM_PERIOD_REG(ch)		(0x64 + (ch) * 0x20)
+#define PWM_PERIOD_MASK			GENMASK(31, 16)
+#define PWM_DUTY_MASK			GENMASK(15, 0)
+#define PWM_REG_PERIOD(reg)		(FIELD_GET(PWM_PERIOD_MASK, reg) + 1)
+#define PWM_REG_DUTY(reg)		FIELD_GET(PWM_DUTY_MASK, reg)
+#define PWM_PERIOD(prd)			FIELD_PREP(PWM_PERIOD_MASK, (prd) - 1)
+#define PWM_DUTY(dty)			FIELD_PREP(PWM_DUTY_MASK, dty)
+#define PWM_PERIOD_MAX			FIELD_MAX(PWM_PERIOD_MASK)
+
+
+/* PWM Count Register */
+#define PWM_CNT_REG(x)			(0x68 + (x) * 0x20)
+
+/* PWM Capture Control Register */
+#define PWM_CCR(x)			(0x6c + (x) * 0x20)
+
+/* PWM Capture Rise Lock Register */
+#define PWM_CRLR(x)			(0x70 + (x) * 0x20)
+
+/* PWM Capture Fall Lock Register */
+#define PWM_CFLR(x)			(0x74 + (x) * 0x20)
+
+#define PWM_PAIR_IDX(chan)		((chan) >> 2)
+
+/*
+ * Block diagram of the PWM clock controller:
+ *
+ *             _____      ______      ________
+ * OSC24M --->|     |    |      |    |        |
+ * APB1 ----->| Mux |--->| Gate |--->| /div_m |-----> PWM_clock_src_xy
+ *            |_____|    |______|    |________|
+ *                           ________
+ *                          |        |
+ *                       +->| /div_k |---> PWM_clock_x
+ *                       |  |________|
+ *                       |    ______
+ *                       |   |      |
+ *                       +-->| Gate |----> PWM_bypass_clock_x
+ *                       |   |______|
+ * PWM_clock_src_xy -----+   ________
+ *                       |  |        |
+ *                       +->| /div_k |---> PWM_clock_y
+ *                       |  |________|
+ *                       |    ______
+ *                       |   |      |
+ *                       +-->| Gate |----> PWM_bypass_clock_y
+ *                           |______|
+ *
+ * NB: when the bypass is set, all the PWM logic is bypassed.
+ * So, the duty cycle and polarity can't be modified (we just have a clock).
+ * The bypass in PWM mode is used to achieve a 1/2 duty cycle with the fastest
+ * clock.
+ *
+ * PWM_clock_x/y serve for the PWM purpose.
+ * PWM_bypass_clock_x/y serve for the clock-provider purpose.
+ *
+ */
+
+/*
+ * Table used for /div_m (diviser before obtaining PWM_clock_src_xy)
+ * It's actually CLK_DIVIDER_POWER_OF_TWO, but limited to /256
+ */
+static const struct clk_div_table clk_table_div_m[] = {
+	{ .val = 0, .div = 1, },
+	{ .val = 1, .div = 2, },
+	{ .val = 2, .div = 4, },
+	{ .val = 3, .div = 8, },
+	{ .val = 4, .div = 16, },
+	{ .val = 5, .div = 32, },
+	{ .val = 6, .div = 64, },
+	{ .val = 7, .div = 128, },
+	{ .val = 8, .div = 256, },
+	{ .val = 0, .div = 0, }, /* last entry */
+};
+
+#define PWM_XY_SRC_GATE(_pair, _reg)			\
+struct clk_gate gate_xy_##_pair = {			\
+	.reg = (void *)_reg,				\
+	.bit_idx = PWM_XY_CLK_CR_GATE_BIT,		\
+	.hw.init = &(struct clk_init_data){		\
+		.ops =  &clk_gate_ops,			\
+	}						\
+}
+
+#define PWM_XY_SRC_MUX(_pair, _reg)			\
+struct clk_mux mux_xy_##_pair = {			\
+	.reg = (void *)_reg,				\
+	.shift = PWM_XY_CLK_CR_SRC_SHIFT,		\
+	.mask = PWM_XY_CLK_CR_SRC_MASK,			\
+	.flags = CLK_MUX_ROUND_CLOSEST,			\
+	.hw.init = &(struct clk_init_data){		\
+		.ops =  &clk_mux_ops,			\
+	}						\
+}
+
+#define PWM_XY_SRC_DIV(_pair, _reg)			\
+struct clk_divider rate_xy_##_pair = {			\
+	.reg = (void *)_reg,				\
+	.shift = PWM_XY_CLK_CR_DIV_M_SHIFT,		\
+	.table = clk_table_div_m,			\
+	.hw.init = &(struct clk_init_data){		\
+		.ops =  &clk_divider_ops,		\
+	}						\
+}
+
+#define PWM_X_DIV(_idx, _reg)				\
+struct clk_divider rate_x_##_idx = {			\
+	.reg = (void *)_reg,				\
+	.shift = PWM_CTRL_PRESCAL_K_SHIFT,		\
+	.width = PWM_CTRL_PRESCAL_K_WIDTH,		\
+	.hw.init = &(struct clk_init_data){		\
+		.ops =  &clk_divider_ops,		\
+	}						\
+}
+
+#define PWM_X_BYPASS_GATE(_idx)				\
+struct clk_gate gate_x_bypass_##_idx = {		\
+	.reg = (void *)PWM_ENR,				\
+	.bit_idx = _idx,				\
+	.hw.init = &(struct clk_init_data){		\
+		.ops =  &clk_gate_ops,			\
+	}						\
+}
+
+#define PWM_XY_CLK_SRC(_pair, _reg)			\
+	static PWM_XY_SRC_MUX(_pair, _reg);		\
+	static PWM_XY_SRC_GATE(_pair, _reg);		\
+	static PWM_XY_SRC_DIV(_pair, _reg)
+
+#define PWM_X_CLK(_idx)					\
+	static PWM_X_DIV(_idx, PWM_CTRL_REG(_idx))
+
+#define PWM_X_BYPASS_CLK(_idx)						\
+	PWM_X_BYPASS_GATE(_idx)
+
+#define REF_CLK_XY_SRC(_pair)						\
+	{								\
+		.name = "pwm-clk-src" #_pair,				\
+		.mux_hw = &mux_xy_##_pair.hw,				\
+		.gate_hw = &gate_xy_##_pair.hw,				\
+		.rate_hw = &rate_xy_##_pair.hw,				\
+	}
+
+#define REF_CLK_X(_idx, _pair)						\
+	{								\
+		.name = "pwm-clk" #_idx,				\
+		.parent_names = (const char *[]){ "pwm-clk-src" #_pair }, \
+		.num_parents = 1,					\
+		.rate_hw = &rate_x_##_idx.hw,				\
+		.flags = CLK_SET_RATE_PARENT,				\
+	}
+
+#define REF_CLK_BYPASS(_idx, _pair)					\
+	{								\
+		.name = "pwm-clk-bypass" #_idx,				\
+		.parent_names = (const char *[]){ "pwm-clk-src" #_pair }, \
+		.num_parents = 1,					\
+		.gate_hw = &gate_x_bypass_##_idx.hw,			\
+		.flags = CLK_SET_RATE_PARENT,	\
+	}
+
+/*
+ * PWM_clock_src_xy generation:
+ *             _____      ______      ________
+ * OSC24M --->|     |    |      |    |        |
+ * APB1 ----->| Mux |--->| Gate |--->| /div_m |-----> PWM_clock_src_xy
+ *            |_____|    |______|    |________|
+ */
+PWM_XY_CLK_SRC(01, PWM_XY_CLK_CR(0));
+PWM_XY_CLK_SRC(23, PWM_XY_CLK_CR(1));
+PWM_XY_CLK_SRC(45, PWM_XY_CLK_CR(2));
+
+/*
+ * PWM_clock_x_div generation:
+ *                       ________
+ *                      |        | PWM_clock_x/y
+ * PWM_clock_src_xy --->| /div_k |--------------->
+ *                      |________|
+ */
+PWM_X_CLK(0);
+PWM_X_CLK(1);
+PWM_X_CLK(2);
+PWM_X_CLK(3);
+PWM_X_CLK(4);
+PWM_X_CLK(5);
+
+/*
+ * PWM_bypass_clock_xy generation:
+ *                        ______
+ *                       |      |
+ * PWM_clock_src_xy ---->| Gate |-------> PWM_bypass_clock_x
+ *                       |______|
+ *
+ * The gate is actually PWM_ENR register.
+ */
+PWM_X_BYPASS_CLK(0);
+PWM_X_BYPASS_CLK(1);
+PWM_X_BYPASS_CLK(2);
+PWM_X_BYPASS_CLK(3);
+PWM_X_BYPASS_CLK(4);
+PWM_X_BYPASS_CLK(5);
+
+struct clk_pwm_data {
+	const char *name;
+	const char **parent_names;
+	unsigned int num_parents;
+	struct clk_hw *mux_hw;
+	struct clk_hw *rate_hw;
+	struct clk_hw *gate_hw;
+	unsigned long flags;
+};
+
+#define CLK_BYPASS(h616chip, ch) ((h616chip)->data->npwm + (ch))
+#define CLK_XY_SRC_IDX(h616chip, ch) ((h616chip)->data->npwm * 2 + ((ch) >> 1))
+static struct clk_pwm_data pwmcc_data[] = {
+	REF_CLK_X(0, 01),
+	REF_CLK_X(1, 01),
+	REF_CLK_X(2, 23),
+	REF_CLK_X(3, 23),
+	REF_CLK_X(4, 45),
+	REF_CLK_X(5, 45),
+	REF_CLK_BYPASS(0, 01),
+	REF_CLK_BYPASS(1, 01),
+	REF_CLK_BYPASS(2, 23),
+	REF_CLK_BYPASS(3, 23),
+	REF_CLK_BYPASS(4, 45),
+	REF_CLK_BYPASS(5, 45),
+	REF_CLK_XY_SRC(01),
+	REF_CLK_XY_SRC(23),
+	REF_CLK_XY_SRC(45),
+	{ /* sentinel */ },
+};
+
+enum h616_pwm_mode {
+	H616_PWM_MODE_NONE,
+	H616_PWM_MODE_PWM,
+	H616_PWM_MODE_CLK,
+};
+
+struct h616_pwm_data {
+	unsigned int npwm;
+};
+
+struct h616_pwm_channel {
+	struct clk *pwm_clk;
+	unsigned long rate;
+	unsigned int entire_cycles;
+	unsigned int active_cycles;
+	enum h616_pwm_mode mode;
+	bool bypass;
+};
+
+struct clk_pwm_pdata {
+	struct clk_hw_onecell_data *hw_data;
+	spinlock_t lock;
+	void __iomem *reg;
+};
+
+struct h616_pwm_chip {
+	struct clk_pwm_pdata *clk_pdata;
+	struct h616_pwm_channel *channels;
+	struct clk *bus_clk;
+	struct reset_control *rst;
+	void __iomem *base;
+	const struct h616_pwm_data *data;
+};
+
+static inline struct h616_pwm_chip *to_h616_pwm_chip(struct pwm_chip *chip)
+{
+	return pwmchip_get_drvdata(chip);
+}
+
+static inline u32 h616_pwm_readl(struct h616_pwm_chip *h616chip,
+				 unsigned long offset)
+{
+	return readl(h616chip->base + offset);
+}
+
+static inline void h616_pwm_writel(struct h616_pwm_chip *h616chip,
+				   u32 val, unsigned long offset)
+{
+	writel(val, h616chip->base + offset);
+}
+
+static void h616_pwm_set_bypass(struct h616_pwm_chip *h616chip, unsigned int idx,
+				bool en_bypass)
+{
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&h616chip->clk_pdata->lock, flags);
+
+	val = h616_pwm_readl(h616chip, PWM_XY_CLK_CR(PWM_PAIR_IDX(idx)));
+	if (en_bypass)
+		val |= BIT(PWM_XY_CLK_CR_BYPASS_BIT(idx));
+	else
+		val &= ~BIT(PWM_XY_CLK_CR_BYPASS_BIT(idx));
+
+	h616_pwm_writel(h616chip, val, PWM_XY_CLK_CR(PWM_PAIR_IDX(idx)));
+
+	spin_unlock_irqrestore(&h616chip->clk_pdata->lock, flags);
+}
+
+static int h616_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct h616_pwm_chip *h616chip = to_h616_pwm_chip(chip);
+	struct h616_pwm_channel *chan = &h616chip->channels[pwm->hwpwm];
+	struct device *dev = pwmchip_parent(chip);
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&h616chip->clk_pdata->lock, flags);
+
+	if (chan->mode == H616_PWM_MODE_CLK)
+		ret = -EBUSY;
+	else
+		chan->mode = H616_PWM_MODE_PWM;
+
+	spin_unlock_irqrestore(&h616chip->clk_pdata->lock, flags);
+	if (ret)
+		goto out;
+
+	ret = clk_prepare_enable(chan->pwm_clk);
+	if (ret < 0) {
+		dev_err(dev, "Failed to enable clock %s: %d\n",
+			__clk_get_name(chan->pwm_clk), ret);
+	}
+out:
+	return ret;
+}
+
+static void h616_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct h616_pwm_chip *h616chip = to_h616_pwm_chip(chip);
+	struct h616_pwm_channel *chan = &h616chip->channels[pwm->hwpwm];
+
+	clk_disable_unprepare(chan->pwm_clk);
+	chan->mode = H616_PWM_MODE_NONE;
+}
+
+static int h616_pwm_get_state(struct pwm_chip *chip,
+			      struct pwm_device *pwm,
+			      struct pwm_state *state)
+{
+	struct h616_pwm_chip *h616chip = to_h616_pwm_chip(chip);
+	struct h616_pwm_channel *chan = &h616chip->channels[pwm->hwpwm];
+	u64 clk_rate, tmp;
+	u32 val;
+
+	clk_rate = clk_get_rate(chan->pwm_clk);
+	if (!clk_rate)
+		return -EINVAL;
+
+	val = h616_pwm_readl(h616chip, PWM_ENR);
+	state->enabled = !!(PWM_ENABLE(pwm->hwpwm) & val);
+
+	val = h616_pwm_readl(h616chip, PWM_XY_CLK_CR(PWM_PAIR_IDX(pwm->hwpwm)));
+	if (val & BIT(PWM_XY_CLK_CR_BYPASS_BIT(pwm->hwpwm))) {
+		/*
+		 * When bypass is enabled, the PWM logic is inactive.
+		 * The PWM_clock_src_xy is directly routed to PWM_clock_x
+		 */
+		state->period = DIV_ROUND_UP_ULL(NSEC_PER_SEC, clk_rate);
+		state->duty_cycle = DIV_ROUND_UP_ULL(state->period, 2);
+		state->polarity = PWM_POLARITY_NORMAL;
+		return 0;
+	}
+
+	state->enabled &= !!(BIT(PWM_XY_CLK_CR_GATE_BIT) & val);
+
+	val = h616_pwm_readl(h616chip, PWM_CTRL_REG(pwm->hwpwm));
+	if (val & PWM_CTRL_ACTIVE_STATE)
+		state->polarity = PWM_POLARITY_NORMAL;
+	else
+		state->polarity = PWM_POLARITY_INVERSED;
+
+	val = h616_pwm_readl(h616chip, PWM_PERIOD_REG(pwm->hwpwm));
+
+	tmp = NSEC_PER_SEC * PWM_REG_DUTY(val);
+	state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate);
+
+	tmp = NSEC_PER_SEC * PWM_REG_PERIOD(val);
+	state->period = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate);
+
+	return 0;
+}
+
+static int h616_pwm_calc(struct pwm_chip *chip, unsigned int idx,
+			 const struct pwm_state *state)
+{
+	struct h616_pwm_chip *h616chip = to_h616_pwm_chip(chip);
+	struct h616_pwm_channel *chan = &h616chip->channels[idx];
+	unsigned int cnt, duty_cnt;
+	unsigned long max_rate;
+	long calc_rate;
+	u64 duty, period, freq;
+
+	duty = state->duty_cycle;
+	period = state->period;
+
+	max_rate = clk_round_rate(chan->pwm_clk, UINT32_MAX);
+
+	dev_dbg(pwmchip_parent(chip), "max_rate: %ld Hz\n", max_rate);
+
+	if ((period * max_rate >= NSEC_PER_SEC) &&
+	    (period * max_rate < 2 * NSEC_PER_SEC) &&
+	    (duty * max_rate * 2 >= NSEC_PER_SEC)) {
+		/*
+		 * If the requested period is to small to be generated by the
+		 * PWM, we can just select the highest clock and bypass the
+		 * PWM logic
+		 */
+		dev_dbg(pwmchip_parent(chip), "Setting bypass (period=%lld)\n",
+			period);
+		freq = div64_u64(NSEC_PER_SEC, period);
+		chan->bypass = true;
+		duty = period / 2;
+	} else {
+		chan->bypass = false;
+		freq = div64_u64(NSEC_PER_SEC * (u64)PWM_PERIOD_MAX, period);
+		if (freq > UINT32_MAX)
+			freq = UINT32_MAX;
+	}
+
+	calc_rate = clk_round_rate(chan->pwm_clk, freq);
+	if (calc_rate <= 0) {
+		dev_err(pwmchip_parent(chip),
+			"Invalid source clock frequency %llu\n", freq);
+		return calc_rate ? calc_rate : -EINVAL;
+	}
+
+	dev_dbg(pwmchip_parent(chip), "calc_rate: %ld Hz\n", calc_rate);
+
+	cnt = mul_u64_u64_div_u64(calc_rate, period, NSEC_PER_SEC);
+	if ((cnt == 0) || (cnt > PWM_PERIOD_MAX)) {
+		dev_err(pwmchip_parent(chip), "Period out of range\n");
+		return -EINVAL;
+	}
+
+	duty_cnt = mul_u64_u64_div_u64(calc_rate, duty, NSEC_PER_SEC);
+
+	if (duty_cnt >= cnt)
+		duty_cnt = cnt - 1;
+
+	dev_dbg(pwmchip_parent(chip), "period=%llu cnt=%u duty=%llu duty_cnt=%u\n",
+		period, cnt, duty, duty_cnt);
+
+	chan->active_cycles = duty_cnt;
+	chan->entire_cycles = cnt;
+
+	chan->rate = calc_rate;
+
+	return 0;
+}
+
+static int h616_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+			  const struct pwm_state *state)
+{
+	struct h616_pwm_chip *h616chip = to_h616_pwm_chip(chip);
+	struct h616_pwm_channel *chan = &h616chip->channels[pwm->hwpwm];
+	struct pwm_state cstate;
+	unsigned long flags;
+	u32 val;
+	int ret;
+
+	ret = h616_pwm_calc(chip, pwm->hwpwm, state);
+	if (ret) {
+		dev_err(pwmchip_parent(chip), "period exceeds the maximum value\n");
+		return ret;
+	}
+
+	pwm_get_state(pwm, &cstate);
+
+	ret = clk_set_rate(chan->pwm_clk, chan->rate);
+	if (ret) {
+		dev_err(pwmchip_parent(chip), "failed to set PWM %d clock rate to %lu\n",
+			pwm->hwpwm, chan->rate);
+		return ret;
+	}
+
+	h616_pwm_set_bypass(h616chip, pwm->hwpwm, chan->bypass);
+
+	/*
+	 * If bypass is set, the PWM logic (polarity, duty) can't be applied
+	 */
+
+	if (chan->bypass && (state->polarity == PWM_POLARITY_INVERSED)) {
+		dev_warn(pwmchip_parent(chip),
+			 "Can't set inversed polarity with bypass enabled\n");
+	} else {
+		val = h616_pwm_readl(h616chip, PWM_CTRL_REG(pwm->hwpwm));
+		val &= ~PWM_CTRL_ACTIVE_STATE;
+		if (state->polarity == PWM_POLARITY_NORMAL)
+			val |= PWM_CTRL_ACTIVE_STATE;
+		h616_pwm_writel(h616chip, val, PWM_CTRL_REG(pwm->hwpwm));
+	}
+
+	if (chan->bypass && (state->duty_cycle * 2 != state->period)) {
+		dev_warn(pwmchip_parent(chip),
+			 "Can't set a duty cycle with bypass enabled\n");
+	}
+
+	if (!chan->bypass) {
+		val = PWM_DUTY(chan->active_cycles);
+		val |= PWM_PERIOD(chan->entire_cycles);
+		h616_pwm_writel(h616chip, val, PWM_PERIOD_REG(pwm->hwpwm));
+	}
+
+	if (state->enabled == cstate.enabled)
+		return 0;
+
+	if (cstate.enabled) {
+		unsigned long delay_us;
+
+		/*
+		 * We need a full period to elapse before
+		 * disabling the channel.
+		 */
+		delay_us = DIV_ROUND_UP_ULL(cstate.period, NSEC_PER_USEC);
+		fsleep(delay_us);
+	}
+
+	spin_lock_irqsave(&h616chip->clk_pdata->lock, flags);
+
+	val = h616_pwm_readl(h616chip, PWM_ENR);
+	if (state->enabled)
+		val |= PWM_ENABLE(pwm->hwpwm);
+	else
+		val &= ~PWM_ENABLE(pwm->hwpwm);
+	h616_pwm_writel(h616chip, val, PWM_ENR);
+
+	spin_unlock_irqrestore(&h616chip->clk_pdata->lock, flags);
+
+	return 0;
+}
+
+static const struct pwm_ops h616_pwm_ops = {
+	.apply = h616_pwm_apply,
+	.get_state = h616_pwm_get_state,
+	.request = h616_pwm_request,
+	.free = h616_pwm_free,
+};
+
+static struct clk_hw *h616_pwm_of_clk_get(struct of_phandle_args *clkspec,
+					  void *data)
+{
+	struct h616_pwm_chip *h616chip = data;
+	struct clk_hw_onecell_data *hw_data = h616chip->clk_pdata->hw_data;
+	unsigned int idx = clkspec->args[0];
+	struct h616_pwm_channel *chan;
+	struct clk_hw *ret_clk = NULL;
+	unsigned long flags;
+
+	if (idx >= h616chip->data->npwm)
+		return ERR_PTR(-EINVAL);
+
+	chan = &h616chip->channels[idx];
+
+	spin_lock_irqsave(&h616chip->clk_pdata->lock, flags);
+
+	if (chan->mode == H616_PWM_MODE_PWM) {
+		ret_clk = ERR_PTR(-EBUSY);
+	} else {
+		chan->mode = H616_PWM_MODE_CLK;
+		ret_clk = hw_data->hws[CLK_BYPASS(h616chip, idx)];
+	}
+	spin_unlock_irqrestore(&h616chip->clk_pdata->lock, flags);
+
+	if (IS_ERR(ret_clk))
+		goto out;
+
+	chan->bypass = true;
+	h616_pwm_set_bypass(h616chip, idx, chan->bypass);
+out:
+	return ret_clk;
+}
+
+static int h616_add_composite_clk(struct clk_pwm_data *data,
+				  void __iomem *reg, spinlock_t *lock,
+				  struct device *dev, struct clk_hw **hw)
+{
+	const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, *rate_ops = NULL;
+	struct clk_hw *mux_hw = NULL, *gate_hw = NULL, *rate_hw = NULL;
+	struct device_node *node = dev->of_node;
+
+	if (data->mux_hw) {
+		struct clk_mux *mux;
+
+		mux_hw = data->mux_hw;
+		mux = to_clk_mux(mux_hw);
+		mux->lock = lock;
+		mux_ops = mux_hw->init->ops;
+		mux->reg = (u64)mux->reg + reg;
+	}
+
+	if (data->gate_hw) {
+		struct clk_gate *gate;
+
+		gate_hw = data->gate_hw;
+		gate = to_clk_gate(gate_hw);
+		gate->lock = lock;
+		gate_ops = gate_hw->init->ops;
+		gate->reg = (u64)gate->reg + reg;
+	}
+
+	if (data->rate_hw) {
+		struct clk_divider *rate;
+
+		rate_hw = data->rate_hw;
+		rate = to_clk_divider(rate_hw);
+		rate_ops = rate_hw->init->ops;
+		rate->lock = lock;
+		rate->reg = (u64)rate->reg + reg;
+
+		if (rate->table) {
+			const struct clk_div_table *clkt;
+			int table_size = 0;
+
+			for (clkt = rate->table; clkt->div; clkt++)
+				table_size++;
+			rate->width = order_base_2(table_size);
+		}
+	}
+
+	/*
+	 * Retrieve the parent clock names from DTS for pwm-clk-srcxy
+	 */
+	if (!data->parent_names) {
+		data->num_parents = of_clk_get_parent_count(node);
+		if (data->num_parents == 0)
+			return -ENOENT;
+
+		data->parent_names = devm_kzalloc(dev,
+						  sizeof(*data->parent_names),
+						  GFP_KERNEL);
+		for (unsigned int i = 0; i < data->num_parents; i++)
+			data->parent_names[i] = of_clk_get_parent_name(node, i);
+	}
+
+	*hw = clk_hw_register_composite(dev, data->name, data->parent_names,
+					data->num_parents, mux_hw,
+					mux_ops, rate_hw, rate_ops,
+					gate_hw, gate_ops, data->flags);
+
+	return PTR_ERR_OR_ZERO(*hw);
+}
+
+static int h616_pwm_init_clocks(struct platform_device *pdev,
+				struct h616_pwm_chip *h616chip)
+{
+	struct clk_pwm_pdata *pdata;
+	struct device *dev = &pdev->dev;
+	int num_clocks = 0;
+	int ret;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	while (pwmcc_data[num_clocks].name)
+		num_clocks++;
+
+	pdata->hw_data = devm_kzalloc(dev, struct_size(pdata->hw_data, hws, num_clocks),
+				      GFP_KERNEL);
+	if (!pdata->hw_data)
+		return -ENOMEM;
+
+	pdata->hw_data->num = num_clocks;
+	pdata->reg = h616chip->base;
+
+	spin_lock_init(&pdata->lock);
+
+	for (int i = 0; i < num_clocks; i++) {
+		struct clk_hw **hw = &pdata->hw_data->hws[i];
+
+		ret = h616_add_composite_clk(&pwmcc_data[i], pdata->reg,
+					     &pdata->lock, dev, hw);
+		if (ret) {
+			dev_err_probe(dev, ret,
+				      "Failed to register hw clock %s\n",
+				      pwmcc_data[i].name);
+			for (i--; i >= 0; i--)
+				clk_hw_unregister_composite(pdata->hw_data->hws[i]);
+			return ret;
+		}
+	}
+
+	h616chip->clk_pdata = pdata;
+
+	return 0;
+}
+
+static int h616_pwm_probe(struct platform_device *pdev)
+{
+	const struct h616_pwm_data *data;
+	struct device *dev = &pdev->dev;
+	struct h616_pwm_chip *h616chip;
+	struct pwm_chip *chip;
+	int ret;
+
+	data = of_device_get_match_data(dev);
+	if (!data)
+		return -ENODEV;
+
+	chip = devm_pwmchip_alloc(dev, data->npwm, sizeof(*h616chip));
+	if (IS_ERR(chip))
+		return dev_err_probe(dev, PTR_ERR(chip),
+				     "Failed to allocate pwmchip\n");
+
+	h616chip = to_h616_pwm_chip(chip);
+	h616chip->data = data;
+	h616chip->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(h616chip->base))
+		return dev_err_probe(dev, PTR_ERR(h616chip->base),
+				     "Failed to get PWM base address\n");
+
+	h616chip->bus_clk = devm_clk_get_enabled(dev, "bus");
+	if (IS_ERR(h616chip->bus_clk))
+		return dev_err_probe(dev, PTR_ERR(h616chip->bus_clk),
+				     "Failed to get bus clock\n");
+
+	h616chip->channels = devm_kmalloc_array(dev, data->npwm,
+						sizeof(*(h616chip->channels)),
+						GFP_KERNEL);
+	if (!h616chip->channels)
+		return dev_err_probe(dev, -ENOMEM,
+				     "Failed to allocate %d channels array\n",
+				     data->npwm);
+
+	h616chip->rst = devm_reset_control_get_shared(dev, NULL);
+	if (IS_ERR(h616chip->rst))
+		return dev_err_probe(dev, PTR_ERR(h616chip->rst),
+				     "Failed to get reset control\n");
+
+	chip->ops = &h616_pwm_ops;
+
+	ret = h616_pwm_init_clocks(pdev, h616chip);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to initialize clocks\n");
+
+	for (unsigned int i = 0; i < data->npwm; i++) {
+		struct h616_pwm_channel *chan = &h616chip->channels[i];
+		struct clk_hw **hw = &h616chip->clk_pdata->hw_data->hws[i];
+
+		chan->pwm_clk = devm_clk_hw_get_clk(dev, *hw, NULL);
+		if (IS_ERR(chan->pwm_clk)) {
+			ret = dev_err_probe(dev, PTR_ERR(chan->pwm_clk),
+					    "Failed to register PWM clock %d\n", i);
+			goto err_get_clk;
+		}
+		chan->mode = H616_PWM_MODE_NONE;
+	}
+
+	ret = devm_of_clk_add_hw_provider(dev, h616_pwm_of_clk_get, h616chip);
+	if (ret) {
+		dev_err_probe(dev, ret, "Failed to add HW clock provider\n");
+		goto err_add_clk_provider;
+	}
+
+	/* Deassert reset */
+	ret = reset_control_deassert(h616chip->rst);
+	if (ret) {
+		dev_err_probe(dev, ret, "Cannot deassert reset control\n");
+		goto err_ctrl_deassert;
+	}
+
+	ret = pwmchip_add(chip);
+	if (ret < 0) {
+		dev_err_probe(dev, ret, "Failed to add PWM chip\n");
+		goto err_pwm_add;
+	}
+
+	platform_set_drvdata(pdev, chip);
+
+	return 0;
+
+err_pwm_add:
+	reset_control_assert(h616chip->rst);
+
+err_ctrl_deassert:
+err_add_clk_provider:
+err_get_clk:
+	for (int i = 0; i < h616chip->clk_pdata->hw_data->num; i++)
+		clk_hw_unregister_composite(h616chip->clk_pdata->hw_data->hws[i]);
+
+	return ret;
+}
+
+static const struct h616_pwm_data sun50i_h616_pwm_data = {
+	.npwm = 6,
+};
+
+static const struct of_device_id h616_pwm_dt_ids[] = {
+	{
+		.compatible = "allwinner,sun50i-h616-pwm",
+		.data = &sun50i_h616_pwm_data,
+	}, {
+		/* sentinel */
+	},
+};
+MODULE_DEVICE_TABLE(of, h616_pwm_dt_ids);
+
+
+static struct platform_driver h616_pwm_driver = {
+	.driver = {
+		.name = "h616-pwm",
+		.of_match_table = h616_pwm_dt_ids,
+	},
+	.probe = h616_pwm_probe,
+};
+module_platform_driver(h616_pwm_driver);
+
+MODULE_AUTHOR("Richard Genoud <richard.genoud at bootlin.com>");
+MODULE_DESCRIPTION("Allwinner H616 PWM driver");
+MODULE_LICENSE("GPL");
-- 
2.47.3



From richard.genoud at bootlin.com  Wed Dec 17 00:25:03 2025
From: richard.genoud at bootlin.com (Richard Genoud)
Date: Wed, 17 Dec 2025 09:25:03 +0100
Subject: [PATCH v2 3/4] arm64: dts: allwinner: h616: add PWM controller
In-Reply-To: <20251217082504.80226-1-richard.genoud@bootlin.com>
References: <20251217082504.80226-1-richard.genoud@bootlin.com>
Message-ID: <20251217082504.80226-4-richard.genoud@bootlin.com>

The H616 has a PWM controller that can provide PWM signals, but also
plain clocks.

Add the PWM controller node and pins in the device tree.

Tested-by: Joao Schim <joao at schimsalabim.eu>
Signed-off-by: Richard Genoud <richard.genoud at bootlin.com>
---
 .../arm64/boot/dts/allwinner/sun50i-h616.dtsi | 47 +++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi
index 8d1110c14bad..1c7628a6e4bb 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi
@@ -236,6 +236,17 @@ watchdog: watchdog at 30090a0 {
 			clocks = <&osc24M>;
 		};
 
+		pwm: pwm at 300a000 {
+			compatible = "allwinner,sun50i-h616-pwm";
+			reg = <0x0300a000 0x400>;
+			clocks = <&osc24M>, <&ccu CLK_BUS_PWM>;
+			clock-names = "mod", "bus";
+			resets = <&ccu RST_BUS_PWM>;
+			#pwm-cells = <3>;
+			#clock-cells = <1>;
+			status = "disabled";
+		};
+
 		pio: pinctrl at 300b000 {
 			compatible = "allwinner,sun50i-h616-pinctrl";
 			reg = <0x0300b000 0x400>;
@@ -340,6 +351,42 @@ nand_rb1_pin: nand-rb1-pin {
 				bias-pull-up;
 			};
 
+			/omit-if-no-ref/
+			pwm0_pin: pwm0-pin {
+				pins = "PD28";
+				function = "pwm0";
+			};
+
+			/omit-if-no-ref/
+			pwm1_pin: pwm1-pin {
+				pins = "PG19";
+				function = "pwm1";
+			};
+
+			/omit-if-no-ref/
+			pwm2_pin: pwm2-pin {
+				pins = "PH2";
+				function = "pwm2";
+			};
+
+			/omit-if-no-ref/
+			pwm3_pin: pwm3-pin {
+				pins = "PH0";
+				function = "pwm3";
+			};
+
+			/omit-if-no-ref/
+			pwm4_pin: pwm4-pin {
+				pins = "PI14";
+				function = "pwm4";
+			};
+
+			/omit-if-no-ref/
+			pwm5_pin: pwm5-pin {
+				pins = "PA12";
+				function = "pwm5";
+			};
+
 			/omit-if-no-ref/
 			spi0_pins: spi0-pins {
 				pins = "PC0", "PC2", "PC4";
-- 
2.47.3



From richard.genoud at bootlin.com  Wed Dec 17 00:25:04 2025
From: richard.genoud at bootlin.com (Richard Genoud)
Date: Wed, 17 Dec 2025 09:25:04 +0100
Subject: [PATCH v2 4/4] MAINTAINERS: Add entry on Allwinner H616 PWM driver
In-Reply-To: <20251217082504.80226-1-richard.genoud@bootlin.com>
References: <20251217082504.80226-1-richard.genoud@bootlin.com>
Message-ID: <20251217082504.80226-5-richard.genoud@bootlin.com>

Add myself as maintainer of Allwinner H616 PWM driver and device-tree
bindings.

Signed-off-by: Richard Genoud <richard.genoud at bootlin.com>
---
 MAINTAINERS | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 5b11839cba9d..df2de03e6e38 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -903,6 +903,11 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/sound/allwinner,sun50i-h6-dmic.yaml
 F:	sound/soc/sunxi/sun50i-dmic.c
 
+ALLWINNER H616 PWM DRIVER
+M:	Richard Genoud <richard.genoud at bootlin.com>
+S:	Maintained
+F:	drivers/pwm/pwm-sun50i-h616.c
+
 ALLWINNER HARDWARE SPINLOCK SUPPORT
 M:	Wilken Gottwalt <wilken.gottwalt at posteo.net>
 S:	Maintained
-- 
2.47.3



From jacky_chou at aspeedtech.com  Wed Dec 17 00:28:57 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Wed, 17 Dec 2025 08:28:57 +0000
Subject: [PATCH net-next v5 3/4] net: ftgmac100: Add RGMII delay support for
 AST2600
In-Reply-To: <8a991b33-f653-4f0c-bbea-b5b3404cdfe6@lunn.ch>
References: <20251205-rgmii_delay_2600-v5-0-bd2820ad3da7@aspeedtech.com>
 <20251205-rgmii_delay_2600-v5-3-bd2820ad3da7@aspeedtech.com>
 <8a991b33-f653-4f0c-bbea-b5b3404cdfe6@lunn.ch>
Message-ID: <SEYPR06MB5134025EC9AD6DE6210F21ED9DABA@SEYPR06MB5134.apcprd06.prod.outlook.com>

Hi Andrew,

Thank you for your reply.

> > @@ -1907,6 +2179,10 @@ static int ftgmac100_probe(struct
> platform_device *pdev)
> >  		priv->rxdes0_edorr_mask = BIT(30);
> >  		priv->txdes0_edotr_mask = BIT(30);
> >  		priv->is_aspeed = true;
> > +		/* Configure RGMII delay if there are the corresponding compatibles
> */
> > +		err = ftgmac100_set_internal_delay(priv, &phy_intf);
> > +		if (err)
> > +			goto err_phy_connect;
> 
> Thinking forward to when you add 2700 support, i really think you need to
> break the probe up into helpers for 2500 and before, 2600 and in the future
> 2700. You currently have a couple of tests on the compatible which you can
> reduce to one.
> 
> In fact, this driver has 10 calls to of_device_is_compatible(). I think you should
> first refactor the code to list each compatible in ftgmac100_of_match[], and
> add a data structure which contains an enum of the MAC type. You can then
> transfer this to priv, and replace all the of_device_is_compatible() tests to just
> look at the enum value.
> 

We will start to refactor the probe() in this driver.
We will also pause work on the RGMII delay patches until this task is completed.

Thanks,
Jacky



From krzk at kernel.org  Wed Dec 17 00:31:15 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 17 Dec 2025 09:31:15 +0100
Subject: [PATCH v2 1/4] dt-bindings: input: adc-keys: allow
 linux,input-type property
In-Reply-To: <20251215-rock4d-audio-v2-1-82a61de39b4c@collabora.com>
References: <20251215-rock4d-audio-v2-0-82a61de39b4c@collabora.com>
 <20251215-rock4d-audio-v2-1-82a61de39b4c@collabora.com>
Message-ID: <20251217-tough-ultra-junglefowl-f1a9ae@quoll>

On Mon, Dec 15, 2025 at 01:29:29PM +0100, Nicolas Frattaroli wrote:
> adc-keys, unlike gpio-keys, does not allow linux,input-type as a valid
> property. This makes it impossible to model devices that have ADC inputs
> that should generate switch events.

The solution is to use unevaluatedProps instead, which also allows
dropping other properties.

Best regards,
Krzysztof



From andrew at codeconstruct.com.au  Wed Dec 17 00:31:15 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Wed, 17 Dec 2025 19:01:15 +1030
Subject: [PATCH v2 0/5] ARM: dts: aspeed: bletchley: Fix dt-schema
 warnings
In-Reply-To: <20251217023938.445721-1-chou.cosmo@gmail.com>
References: <20251217023938.445721-1-chou.cosmo@gmail.com>
Message-ID: <176596027534.2875246.12913980516498879452.b4-ty@codeconstruct.com.au>

On Wed, 17 Dec 2025 10:39:33 +0800, Cosmo Chou wrote:
> This series fixes dt-schema validation warnings by using generic node
> names, correcting GPIO property suffixes, and removing unsupported
> properties. No functional changes.
> 
> Changes in v2:
> - Split single patch into 5 separate patches by change type
> 
> [...]

Thanks, I've applied this to the BMC tree.

-- 
Andrew Jeffery <andrew at codeconstruct.com.au>



From jacky_chou at aspeedtech.com  Wed Dec 17 00:35:58 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Wed, 17 Dec 2025 08:35:58 +0000
Subject: [PATCH net-next v5 3/4] net: ftgmac100: Add RGMII delay support for
 AST2600
In-Reply-To: <20251209205034.GB1056291-robh@kernel.org>
References: <20251205-rgmii_delay_2600-v5-0-bd2820ad3da7@aspeedtech.com>
 <20251205-rgmii_delay_2600-v5-3-bd2820ad3da7@aspeedtech.com>
 <8a991b33-f653-4f0c-bbea-b5b3404cdfe6@lunn.ch>
 <20251209205034.GB1056291-robh@kernel.org>
Message-ID: <SEYPR06MB51340B307868D8D6AD1ECFAD9DABA@SEYPR06MB5134.apcprd06.prod.outlook.com>

Hi Rob,

> On Sat, Dec 06, 2025 at 07:30:30PM +0100, Andrew Lunn wrote:
> > > @@ -1907,6 +2179,10 @@ static int ftgmac100_probe(struct
> platform_device *pdev)
> > >  		priv->rxdes0_edorr_mask = BIT(30);
> > >  		priv->txdes0_edotr_mask = BIT(30);
> > >  		priv->is_aspeed = true;
> > > +		/* Configure RGMII delay if there are the corresponding
> compatibles */
> > > +		err = ftgmac100_set_internal_delay(priv, &phy_intf);
> > > +		if (err)
> > > +			goto err_phy_connect;
> >
> > Thinking forward to when you add 2700 support, i really think you need
> > to break the probe up into helpers for 2500 and before, 2600 and in
> > the future 2700. You currently have a couple of tests on the
> > compatible which you can reduce to one.
> >
> > In fact, this driver has 10 calls to of_device_is_compatible(). I
> > think you should first refactor the code to list each compatible in
> > ftgmac100_of_match[], and add a data structure which contains an enum
> > of the MAC type. You can then transfer this to priv, and replace all
> > the of_device_is_compatible() tests to just look at the enum value.
> 
> Better yet, define a structure which defines the different settings directly. Such
> as:
> 
> priv->rxdes0_edorr_mask
> priv->txdes0_edotr_mask
> priv->is_aspeed
> 
> And anything else needed...
> 

Thanks for the feedback.
We'll take your suggestions into account and adjust the structure accordingly if needed

Thanks,
Jacky



From krzk at kernel.org  Wed Dec 17 00:38:31 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 17 Dec 2025 09:38:31 +0100
Subject: [PATCH 1/2] dt-bindings: mfd: atmel,hlcdc: Add sama7d65
 compatible string
In-Reply-To: <20251215090639.346288-1-manikandan.m@microchip.com>
References: <20251215090639.346288-1-manikandan.m@microchip.com>
Message-ID: <20251217-secret-beluga-of-patience-3ba530@quoll>

On Mon, Dec 15, 2025 at 02:36:38PM +0530, Manikandan Muralidharan wrote:
> Add LCD compatible string for sama7d65.
> 
> Signed-off-by: Manikandan Muralidharan <manikandan.m at microchip.com>
> ---
>  Documentation/devicetree/bindings/mfd/atmel,hlcdc.yaml | 1 +
>  1 file changed, 1 insertion(+)

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof



From krzk at kernel.org  Wed Dec 17 00:39:19 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 17 Dec 2025 09:39:19 +0100
Subject: [PATCH 1/5] dt-bindings: i2c: st,stm32-i2c: add 'power-domains'
 property
In-Reply-To: <20251215-stm32-i2c-mp2x-dt-updates-v1-1-2738a05a7af8@foss.st.com>
References: <20251215-stm32-i2c-mp2x-dt-updates-v1-0-2738a05a7af8@foss.st.com>
 <20251215-stm32-i2c-mp2x-dt-updates-v1-1-2738a05a7af8@foss.st.com>
Message-ID: <20251217-realistic-pug-of-glory-dd4fb1@quoll>

On Mon, Dec 15, 2025 at 01:19:40PM +0100, Alain Volmat wrote:
> STM32 I2C may be in a power domain which is the case for the STM32MP2x
> based boards. Allow a single 'power-domains' entry for STM32 I2C.
> 
> Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
> ---
>  Documentation/devicetree/bindings/i2c/st,stm32-i2c.yaml | 3 +++
>  1 file changed, 3 insertions(+)

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof



From pankaj.gupta at nxp.com  Wed Dec 17 00:40:03 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Wed, 17 Dec 2025 08:40:03 +0000
Subject: [PATCH v21 5/7] firmware: drivers: imx: adds miscdev
In-Reply-To: <aTxIsAQMe3sbxXQ4@lizhi-Precision-Tower-5810>
References: <20251212-imx-se-if-v21-0-ee7d6052d848@nxp.com>
 <20251212-imx-se-if-v21-5-ee7d6052d848@nxp.com>
 <aTxIsAQMe3sbxXQ4@lizhi-Precision-Tower-5810>
Message-ID: <AM9PR04MB860463DED50B8371D349E3F095ABA@AM9PR04MB8604.eurprd04.prod.outlook.com>

> > Adds the driver for communication interface to secure-enclave, that
> > enables exchanging messages with NXP secure enclave HW IP(s) like
> > EdgeLock Enclave, from:
> > - User-Space Applications via character driver.
> >
> > ABI documentation for the NXP secure-enclave driver.
> >
> > User-space library using this driver:
> > - i.MX Secure Enclave library:
> >   -- URL: https://github.com/nxp-imx/imx-secure-enclave.git,
> > - i.MX Secure Middle-Ware:
> >   -- URL: https://github.com/nxp-imx/imx-smw.git
> >
> > Following checks are performed on the incoming msg-header, to block
> > exchanging invalid arbitrary commands:
> > - maximum allowed words,
> > - check if command-tag & response-tag are valid
> > - version,
> > - command id validation check, to allow limited base-line API(s)
> >   and restrict following:
> >   - exchanging power management commands.
> >   - reset requests.
> >   - BBSM configuration requests.
> >   - re-initializing the FW.
> >   - RNG init
> >   - CAAM resource release management
> >   - SE's internal memory management.
> > from user-space.
> >
> > Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
> > Reviewed-by: Frank Li <Frank.Li at nxp.com>
> > ---
> > changes from v20 to v21
> > - removed "__free(kfree)" & added kfree();
> 
> KK's means is that correctly use __free according to cleanup.h.
> 
> fun()
> {
> 	...
> 	some code logic
> 	...
> 
> 	struct .... __free(kfree) rx_msg =
> kzalloc(cmd_snd_rcv_rsp_info.rx_buf_sz, GFP_KERNEL);
> 	...
> }
> 
> Frank

Hi Krzysztof, Hi Frank,

Thank you for the review comments.

I misunderstood earlier and removed __free(kfree) in v21, thinking it was not preferred.
After revisiting your feedback, I see the intent is to use __free(kfree) correctly as per cleanup.h guidelines for automatic cleanup instead of manual kfree() calls.

I will revert the previous change and update the patch to follow the recommended pattern:
-  strucivt se_api_msg *tx_msg __free(kfree) = kzalloc (XXXXX, GFP_KERNEL);
-  Make sure the source files has: #include <linux/cleanup.h>

This will be included in v22 along with a clear comment disposition referencing your suggestion.
Thanks for clarifying and for your guidance.

Best regards,
Pankaj Gupta


From olsajiri at gmail.com  Wed Dec 17 00:40:15 2025
From: olsajiri at gmail.com (Jiri Olsa)
Date: Wed, 17 Dec 2025 09:40:15 +0100
Subject: [PATCHv5 bpf-next 1/9] ftrace,bpf: Remove FTRACE_OPS_FL_JMP
 ftrace_ops flag
In-Reply-To: <95c13c0b793604796037ca67c191e1bfce22770dd020107c7179a698c5d49b91@mail.kernel.org>
References: <20251215211402.353056-2-jolsa@kernel.org>
 <95c13c0b793604796037ca67c191e1bfce22770dd020107c7179a698c5d49b91@mail.kernel.org>
Message-ID: <aUJsb2up5zHDfIpC@krava>

On Mon, Dec 15, 2025 at 09:31:51PM +0000, bot+bpf-ci at kernel.org wrote:
> > diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
> > index 015dd1049bea..505b7d3f5641 100644
> > --- a/include/linux/ftrace.h
> > +++ b/include/linux/ftrace.h
> 
> [ ... ]
> 
> > diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
> > index 976d89011b15..b9a358d7a78f 100644
> > --- a/kernel/bpf/trampoline.c
> > +++ b/kernel/bpf/trampoline.c
> > @@ -214,10 +214,15 @@ static int modify_fentry(struct bpf_trampoline *tr, u32 orig_flags,
> >  	int ret;
> >
> >  	if (tr->func.ftrace_managed) {
> > +		unsigned long addr = (unsigned long) new_addr;
> > +
> > +		if (bpf_trampoline_use_jmp(tr->flags))
> > +			addr = ftrace_jmp_set(addr);
> > +
> >  		if (lock_direct_mutex)
> > -			ret = modify_ftrace_direct(tr->fops, (long)new_addr);
> > +			ret = modify_ftrace_direct(tr->fops, addr);
> >  		else
> > -			ret = modify_ftrace_direct_nolock(tr->fops, (long)new_addr);
> > +			ret = modify_ftrace_direct_nolock(tr->fops, addr);
> >  	} else {
> >  		ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr,
> >  						   new_addr);
> > @@ -240,10 +245,15 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
> >  	}
> >
> >  	if (tr->func.ftrace_managed) {
> > +		unsigned long addr = (unsigned long) new_addr;
> > +
> > +		if (bpf_trampoline_use_jmp(tr->flags))
> > +			addr = ftrace_jmp_set(addr);
> > +
> >  		ret = ftrace_set_filter_ip(tr->fops, (unsigned long)ip, 0, 1);
> >  		if (ret)
> >  			return ret;
> > -		ret = register_ftrace_direct(tr->fops, (long)new_addr);
> > +		ret = register_ftrace_direct(tr->fops, addr);
> >  	} else {
> >  		ret = bpf_trampoline_update_fentry(tr, 0, NULL, new_addr);
> >  	}
> 
> After this change, register_ftrace_direct() receives an address with
> the LSB bit already set (via ftrace_jmp_set) and stores it as-is in
> entry->direct. This address then flows through to ftrace_find_rec_direct()
> which returns entry->direct unchanged.
> 
> In available_filter_functions_show():

hum, there's no such function.. AFAICS it's t_show called through
ftrace_avail_fops->ftrace_avail_open->show_ftrace_seq_ops

> 
>     direct = ftrace_find_rec_direct(rec->ip);
>     if (direct)
>         seq_printf(m, "\n\tdirect-->%pS", (void *)direct);
> 

but yep, it's related problem, that Menglong said he will address in
separate patch

thanks,
jirka

> Can the debug output show misleading symbol offsets? When the LSB is
> set, %pS will resolve addresses like "function+0x1" instead of just
> "function". This makes ftrace debug output harder to read for users
> trying to understand direct call attachments.
> 
> The fix would be to strip the LSB bit before printing:
>     seq_printf(m, "\n\tdirect-->%pS", (void *)ftrace_jmp_get(direct));
> 
> [ ... ]
> 
> > diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
> > index bbb37c0f8c6c..b0dc911411f1 100644
> > --- a/kernel/trace/ftrace.c
> > +++ b/kernel/trace/ftrace.c
> > @@ -6017,15 +6017,8 @@ int register_ftrace_direct(struct ftrace_ops *ops, unsigned long addr)
> >  	if (ftrace_hash_empty(hash))
> >  		return -EINVAL;
> >
> > -	/* This is a "raw" address, and this should never happen. */
> > -	if (WARN_ON_ONCE(ftrace_is_jmp(addr)))
> > -		return -EINVAL;
> > -
> >  	mutex_lock(&direct_mutex);
> >
> > -	if (ops->flags & FTRACE_OPS_FL_JMP)
> > -		addr = ftrace_jmp_set(addr);
> > -
> >  	/* Make sure requested entries are not already registered.. */
> >  	size = 1 << hash->size_bits;
> >  	for (i = 0; i < size; i++) {
> 
> [ ... ]
> 
> > @@ -6146,13 +6139,6 @@ __modify_ftrace_direct(struct ftrace_ops *ops, unsigned long addr)
> >
> >  	lockdep_assert_held_once(&direct_mutex);
> >
> > -	/* This is a "raw" address, and this should never happen. */
> > -	if (WARN_ON_ONCE(ftrace_is_jmp(addr)))
> > -		return -EINVAL;
> > -
> > -	if (ops->flags & FTRACE_OPS_FL_JMP)
> > -		addr = ftrace_jmp_set(addr);
> > -
> >  	/* Enable the tmp_ops to have the same functions as the direct ops */
> >  	ftrace_ops_init(&tmp_ops);
> >  	tmp_ops.func_hash = ops->func_hash;
> 
> [ ... ]
> 
> 
> ---
> AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
> See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
> 
> CI run summary: https://github.com/kernel-patches/bpf/actions/runs/20247816064



From krzk at kernel.org  Wed Dec 17 00:46:50 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 17 Dec 2025 09:46:50 +0100
Subject: [PATCH v2 1/2] media: dt-bindings: Add CSI Pixel Formatter DT
 bindings
In-Reply-To: <20251217-csi_formatter-v2-1-62168af80210@nxp.com>
References: <20251217-csi_formatter-v2-0-62168af80210@nxp.com>
 <20251217-csi_formatter-v2-1-62168af80210@nxp.com>
Message-ID: <230106b7-26f0-482b-9d45-38eeb344b853@kernel.org>

On 17/12/2025 07:11, Guoniu Zhou wrote:
> From: Guoniu Zhou <guoniu.zhou at nxp.com>
> 
> The i.MX9 CSI pixel formatting module uses packet info, pixel and
> non-pixel data from the CSI-2 host controller and reformat them to
> match Pixel Link(PL) definition.
> 
> Signed-off-by: Guoniu Zhou <guoniu.zhou at nxp.com>
> ---
>  .../bindings/media/nxp,imx9-csi-formatter.yaml     | 98 ++++++++++++++++++++++
>  1 file changed, 98 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/media/nxp,imx9-csi-formatter.yaml b/Documentation/devicetree/bindings/media/nxp,imx9-csi-formatter.yaml
> new file mode 100644
> index 0000000000000000000000000000000000000000..a4ad4a0841d71646dacf5e564735dfe0a27cc1dc
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/nxp,imx9-csi-formatter.yaml

Filename must match the compatible.

> @@ -0,0 +1,98 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/media/nxp,imx9-csi-formatter.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: i.MX9 CSI Pixel Formatter
> +
> +maintainers:
> +  - Guoniu Zhou <guoniu.zhou at nxp.com>
> +
> +description:
> +  The CSI pixel formatting module uses packet info, pixel and non-pixel
> +  data from the CSI-2 host controller and reformat them to match Pixel
> +  Link(PL) definition.
> +
> +properties:
> +  compatible:
> +    const: fsl,imx9-csi-formatter
> +
> +  reg:
> +    maxItems: 1
> +
> +  clocks:
> +    maxItems: 1
> +
> +  clock-names:
> +    maxItems: 1

There is no such syntax alone, so I am confused from where did you take
it. You need to say the name, but likely my next comment would be -
redundant name - so just drop the property.

> +
> +  power-domains:
> +    maxItems: 1
> +
> +  ports:
> +    $ref: /schemas/graph.yaml#/properties/ports
> +
> +    properties:
> +      port at 0:
> +        $ref: /schemas/graph.yaml#/$defs/port-base
> +        unevaluatedProperties: false
> +        description: MIPI CSI-2 RX IDI interface
> +
> +        properties:
> +          endpoint:
> +            $ref: video-interfaces.yaml#
> +            unevaluatedProperties: false
> +
> +      port at 1:
> +        $ref: /schemas/graph.yaml#/properties/port
> +        description: Pixel Link Interface
> +
> +required:
> +  - compatible
> +  - reg
> +  - clocks
> +  - clock-names
> +  - power-domains
> +  - ports
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/clock/nxp,imx95-clock.h>
> +
> +    /*
> +     * Power domain definitions from arch/arm64/boot/dts/freescale/imx95-power.h
> +     */
> +
> +    #define IMX95_PD_CAMERA		3

Drop and use whatever you wish in the example.


Best regards,
Krzysztof


From alexander.stein at ew.tq-group.com  Wed Dec 17 00:48:04 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Wed, 17 Dec 2025 09:48:04 +0100
Subject: [PATCH 1/1] arm64: dts: mb-smarc-2: Add PCIe support
Message-ID: <20251217084806.41853-1-alexander.stein@ew.tq-group.com>

TQMa8XxS on MB-SMARC-2 supports mPCIe on X44.

Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 .../boot/dts/freescale/tqma8xxs-mb-smarc-2.dtsi    | 10 ++++++++++
 arch/arm64/boot/dts/freescale/tqma8xxs.dtsi        | 14 +++++++++++---
 2 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/tqma8xxs-mb-smarc-2.dtsi b/arch/arm64/boot/dts/freescale/tqma8xxs-mb-smarc-2.dtsi
index 8bfe77113d64b..050ae23c4dc1e 100644
--- a/arch/arm64/boot/dts/freescale/tqma8xxs-mb-smarc-2.dtsi
+++ b/arch/arm64/boot/dts/freescale/tqma8xxs-mb-smarc-2.dtsi
@@ -126,6 +126,12 @@ &flexcan3 {
 	status = "okay";
 };
 
+&hsio_phy {
+	fsl,hsio-cfg = "pciea-x2-pcieb";
+	fsl,refclk-pad-mode = "input";
+	status = "okay";
+};
+
 &i2c0 {
 	tlv320aic3x04: audio-codec at 18 {
 		compatible = "ti,tlv320aic32x4";
@@ -156,6 +162,10 @@ &lpuart3 {
 	status = "okay";
 };
 
+&pcieb {
+	status = "okay";
+};
+
 &reg_sdvmmc {
 	off-on-delay-us = <200000>;
 	status = "okay";
diff --git a/arch/arm64/boot/dts/freescale/tqma8xxs.dtsi b/arch/arm64/boot/dts/freescale/tqma8xxs.dtsi
index ebf20d5b5df9c..bfc918f18d011 100644
--- a/arch/arm64/boot/dts/freescale/tqma8xxs.dtsi
+++ b/arch/arm64/boot/dts/freescale/tqma8xxs.dtsi
@@ -402,6 +402,14 @@ &mu1_m0 {
 	status = "okay";
 };
 
+&pcieb {
+	phys = <&hsio_phy 0 PHY_TYPE_PCIE 0>;
+	phy-names = "pcie-phy";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pcieb>;
+	reset-gpio = <&lsio_gpio4 0 GPIO_ACTIVE_LOW>;
+};
+
 &sai1 {
 	assigned-clocks = <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_PLL>,
 			  <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_SLV_BUS>,
@@ -646,9 +654,9 @@ pinctrl_i2c0_gpio_mipi_lvds0: mipi-lvds0-i2c0-gpiogrp {
 	};
 
 	pinctrl_pcieb: pcieagrp {
-		fsl,pins = <IMX8QXP_PCIE_CTRL0_PERST_B_LSIO_GPIO4_IO00	0x06000041>,
-			   <IMX8QXP_PCIE_CTRL0_CLKREQ_B_LSIO_GPIO4_IO01	0x06000041>,
-			   <IMX8QXP_PCIE_CTRL0_WAKE_B_LSIO_GPIO4_IO02	0x04000041>;
+		fsl,pins = <IMX8QXP_PCIE_CTRL0_PERST_B_LSIO_GPIO4_IO00		0x06000041>,
+			   <IMX8QXP_PCIE_CTRL0_CLKREQ_B_HSIO_PCIE0_CLKREQ_B	0x06000041>,
+			   <IMX8QXP_PCIE_CTRL0_WAKE_B_LSIO_GPIO4_IO02		0x04000041>;
 	};
 
 	pinctrl_pwm_mipi_lvds0: mipi-lvds0-pwmgrp {
-- 
2.43.0



From yeoreum.yun at arm.com  Wed Dec 17 00:51:15 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Wed, 17 Dec 2025 08:51:15 +0000
Subject: [PATCH net v3] smc91x: fix broken irq-context in PREEMPT_RT
Message-ID: <20251217085115.1730036-1-yeoreum.yun@arm.com>

When smc91x.c is built with PREEMPT_RT, the following splat occurs
in FVP_RevC:

[   13.055000] smc91x LNRO0003:00 eth0: link up, 10Mbps, half-duplex, lpa 0x0000
[   13.062137] BUG: workqueue leaked atomic, lock or RCU: kworker/2:1[106]
[   13.062137]      preempt=0x00000000 lock=0->0 RCU=0->1 workfn=mld_ifc_work
[   13.062266] C
** replaying previous printk message **
[   13.062266] CPU: 2 UID: 0 PID: 106 Comm: kworker/2:1 Not tainted 6.18.0-dirty #179 PREEMPT_{RT,(full)}
[   13.062353] Hardware name:  , BIOS
[   13.062382] Workqueue: mld mld_ifc_work
[   13.062469] Call trace:
[   13.062494]  show_stack+0x24/0x40 (C)
[   13.062602]  __dump_stack+0x28/0x48
[   13.062710]  dump_stack_lvl+0x7c/0xb0
[   13.062818]  dump_stack+0x18/0x34
[   13.062926]  process_scheduled_works+0x294/0x450
[   13.063043]  worker_thread+0x260/0x3d8
[   13.063124]  kthread+0x1c4/0x228
[   13.063235]  ret_from_fork+0x10/0x20

This happens because smc_special_trylock() disables IRQs even on PREEMPT_RT,
but smc_special_unlock() does not restore IRQs on PREEMPT_RT.
The reason is that smc_special_unlock() calls spin_unlock_irqrestore(),
and rcu_read_unlock_bh() in __dev_queue_xmit() cannot invoke
rcu_read_unlock() through __local_bh_enable_ip() when current->softirq_disable_cnt becomes zero.

To address this issue, replace smc_special_trylock() with spin_trylock_irqsave().

Fixes: 342a93247e08 ("locking/spinlock: Provide RT variant header: <linux/spinlock_rt.h>")
Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
Reviewed-by: Simon Horman <horms at kernel.org>
---

History
========
>From v2 to v3:
  - rebased to linux-net tree.
  - modify patch title & add r-b tags
  - https://lore.kernel.org/all/20251212190338.2318843-1-yeoreum.yun at arm.com/

>From v1 to v2:
  - remove debug log.
  - https://lore.kernel.org/all/20251212185818.2209573-1-yeoreum.yun at arm.com/

---
 drivers/net/ethernet/smsc/smc91x.c | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c
index 9d1a83a5fa7e..d16c178d1034 100644
--- a/drivers/net/ethernet/smsc/smc91x.c
+++ b/drivers/net/ethernet/smsc/smc91x.c
@@ -516,15 +516,7 @@ static inline void  smc_rcv(struct net_device *dev)
  * any other concurrent access and C would always interrupt B. But life
  * isn't that easy in a SMP world...
  */
-#define smc_special_trylock(lock, flags)				\
-({									\
-	int __ret;							\
-	local_irq_save(flags);						\
-	__ret = spin_trylock(lock);					\
-	if (!__ret)							\
-		local_irq_restore(flags);				\
-	__ret;								\
-})
+#define smc_special_trylock(lock, flags)	spin_trylock_irqsave(lock, flags)
 #define smc_special_lock(lock, flags)		spin_lock_irqsave(lock, flags)
 #define smc_special_unlock(lock, flags) 	spin_unlock_irqrestore(lock, flags)
 #else
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



From benjamin.gaignard at collabora.com  Wed Dec 17 01:01:48 2025
From: benjamin.gaignard at collabora.com (Benjamin Gaignard)
Date: Wed, 17 Dec 2025 10:01:48 +0100
Subject: [PATCH v10 5/7] media: verisilicon: AV1: Restore IOMMU context
 before decoding a frame
In-Reply-To: <202512162315.lcRwm6Mr-lkp@intel.com>
References: <20251215085349.10155-6-benjamin.gaignard@collabora.com>
 <202512162315.lcRwm6Mr-lkp@intel.com>
Message-ID: <913d3056-0619-4e05-ac5f-1a21cf0e47c9@collabora.com>


Le 16/12/2025 ? 16:27, kernel test robot a ?crit?:
> Hi Benjamin,
>
> kernel test robot noticed the following build errors:
>
> [auto build test ERROR on linus/master]
> [also build test ERROR on v6.19-rc1 next-20251216]
> [cannot apply to robh/for-next rockchip/for-next arm64/for-next/core]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
>
> url:    https://github.com/intel-lab-lkp/linux/commits/Benjamin-Gaignard/dt-bindings-vendor-prefixes-Add-Verisilicon/20251215-165740
> base:   linus/master
> patch link:    https://lore.kernel.org/r/20251215085349.10155-6-benjamin.gaignard%40collabora.com
> patch subject: [PATCH v10 5/7] media: verisilicon: AV1: Restore IOMMU context before decoding a frame
> config: arm-randconfig-r063-20251216 (https://download.01.org/0day-ci/archive/20251216/202512162315.lcRwm6Mr-lkp at intel.com/config)
> compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 1335a05ab8bc8339ce24be3a9da89d8c3f4e0571)
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251216/202512162315.lcRwm6Mr-lkp at intel.com/reproduce)
>
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp at intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202512162315.lcRwm6Mr-lkp at intel.com/
>
> All errors (new ones prefixed by >>):
>
>>> drivers/iommu/vsi-iommu.c:231:3: error: call to undeclared function 'report_iommu_fault'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
>       231 |                 report_iommu_fault(iommu->domain, iommu->dev, iova, status);
>           |                 ^
>>> drivers/iommu/vsi-iommu.c:245:21: error: no member named 'iommu_fwnode' in 'struct iommu_fwspec'
>       245 |                                                              fwspec->iommu_fwnode);
>           |                                                              ~~~~~~  ^
>>> drivers/iommu/vsi-iommu.c:254:28: error: call to undeclared function 'dev_iommu_priv_get'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
>       254 |         struct vsi_iommu *iommu = dev_iommu_priv_get(dev);
>           |                                   ^
>     drivers/iommu/vsi-iommu.c:254:28: note: did you mean 'dev_iommu_fwspec_get'?
>     include/linux/iommu.h:1457:36: note: 'dev_iommu_fwspec_get' declared here
>      1457 | static inline struct iommu_fwspec *dev_iommu_fwspec_get(struct device *dev)
>           |                                    ^
>>> drivers/iommu/vsi-iommu.c:254:20: error: incompatible integer to pointer conversion initializing 'struct vsi_iommu *' with an expression of type 'int' [-Wint-conversion]
>       254 |         struct vsi_iommu *iommu = dev_iommu_priv_get(dev);
>           |                           ^       ~~~~~~~~~~~~~~~~~~~~~~~
>     drivers/iommu/vsi-iommu.c:496:28: error: call to undeclared function 'dev_iommu_priv_get'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
>       496 |         struct vsi_iommu *iommu = dev_iommu_priv_get(dev);
>           |                                   ^
>     drivers/iommu/vsi-iommu.c:496:20: error: incompatible integer to pointer conversion initializing 'struct vsi_iommu *' with an expression of type 'int' [-Wint-conversion]
>       496 |         struct vsi_iommu *iommu = dev_iommu_priv_get(dev);
>           |                           ^       ~~~~~~~~~~~~~~~~~~~~~~~
>>> drivers/iommu/vsi-iommu.c:519:38: error: variable has incomplete type 'const struct iommu_domain_ops'
>       519 | static const struct iommu_domain_ops vsi_identity_ops = {
>           |                                      ^
>     include/linux/iommu.h:40:8: note: forward declaration of 'struct iommu_domain_ops'
>        40 | struct iommu_domain_ops;
>           |        ^
>     drivers/iommu/vsi-iommu.c:571:28: error: call to undeclared function 'dev_iommu_priv_get'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
>       571 |         struct vsi_iommu *iommu = dev_iommu_priv_get(dev);
>           |                                   ^
>     drivers/iommu/vsi-iommu.c:571:20: error: incompatible integer to pointer conversion initializing 'struct vsi_iommu *' with an expression of type 'int' [-Wint-conversion]
>       571 |         struct vsi_iommu *iommu = dev_iommu_priv_get(dev);
>           |                           ^       ~~~~~~~~~~~~~~~~~~~~~~~
>>> drivers/iommu/vsi-iommu.c:644:2: error: call to undeclared function 'dev_iommu_priv_set'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
>       644 |         dev_iommu_priv_set(dev, iommu);
>           |         ^
>     drivers/iommu/vsi-iommu.c:650:28: error: call to undeclared function 'dev_iommu_priv_get'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
>       650 |         struct vsi_iommu *iommu = dev_iommu_priv_get(dev);
>           |                                   ^
>     drivers/iommu/vsi-iommu.c:650:20: error: incompatible integer to pointer conversion initializing 'struct vsi_iommu *' with an expression of type 'int' [-Wint-conversion]
>       650 |         struct vsi_iommu *iommu = dev_iommu_priv_get(dev);
>           |                           ^       ~~~~~~~~~~~~~~~~~~~~~~~
>>> drivers/iommu/vsi-iommu.c:657:35: error: passing 'const uint32_t[16]' (aka 'const unsigned int[16]') to parameter of type 'u32 *' (aka 'unsigned int *') discards qualifiers [-Werror,-Wincompatible-pointer-types-discards-qualifiers]
>       657 |         return iommu_fwspec_add_ids(dev, args->args, 1);
>           |                                          ^~~~~~~~~~
>     include/linux/iommu.h:1451:65: note: passing argument to parameter 'ids' here
>      1451 | static inline int iommu_fwspec_add_ids(struct device *dev, u32 *ids,
>           |                                                                 ^
>>> drivers/iommu/vsi-iommu.c:667:18: error: use of undeclared identifier 'generic_single_device_group'
>       667 |         .device_group = generic_single_device_group,
>           |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~
>     drivers/iommu/vsi-iommu.c:669:25: error: variable has incomplete type 'const struct iommu_domain_ops'
>       669 |         .default_domain_ops = &(const struct iommu_domain_ops) {
>           |                                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>       670 |                 .attach_dev             = vsi_iommu_attach_device,
>           |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>       671 |                 .map_pages              = vsi_iommu_map,
>           |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>       672 |                 .unmap_pages            = vsi_iommu_unmap,
>           |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>       673 |                 .flush_iotlb_all        = vsi_iommu_flush_tlb_all,
>           |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>       674 |                 .iova_to_phys           = vsi_iommu_iova_to_phys,
>           |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>       675 |                 .free                   = vsi_iommu_domain_free,
>           |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>       676 |         }
>           |         ~
>     include/linux/iommu.h:40:8: note: forward declaration of 'struct iommu_domain_ops'
>        40 | struct iommu_domain_ops;
>           |        ^
>     15 errors generated.
>
> Kconfig warnings: (for reference only)
>     WARNING: unmet direct dependencies detected for VSI_IOMMU
>     Depends on [n]: IOMMU_SUPPORT [=n] && (ARCH_ROCKCHIP [=n] && ARM64 || COMPILE_TEST [=y])
>     Selected by [m]:
>     - VIDEO_HANTRO_ROCKCHIP [=y] && MEDIA_SUPPORT [=y] && MEDIA_PLATFORM_SUPPORT [=y] && MEDIA_PLATFORM_DRIVERS [=y] && VIDEO_HANTRO [=m] && (ARCH_ROCKCHIP [=n] || COMPILE_TEST [=y])VSI_IOMMU

I will make VIDEO_HANTRO_ROCKCHIP depends on VSI_IOMMU instead of select it on the next version.
Regards,
Benjamin

>
>
> vim +/report_iommu_fault +231 drivers/iommu/vsi-iommu.c
>
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  214
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  215  static irqreturn_t vsi_iommu_irq(int irq, void *dev_id)
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  216  {
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  217  	struct vsi_iommu *iommu = dev_id;
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  218  	unsigned long flags;
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  219  	dma_addr_t iova;
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  220  	u32 status;
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  221
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  222  	if (pm_runtime_resume_and_get(iommu->dev) < 0)
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  223  		return IRQ_NONE;
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  224
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  225  	spin_lock_irqsave(&iommu->lock, flags);
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  226
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  227  	status = readl(iommu->regs + VSI_MMU_STATUS_BASE);
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  228  	if (status & VSI_MMU_IRQ_MASK) {
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  229  		dev_err(iommu->dev, "unexpected int_status=%08x\n", status);
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  230  		iova = readl(iommu->regs + VSI_MMU_PAGE_FAULT_ADDR);
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15 @231  		report_iommu_fault(iommu->domain, iommu->dev, iova, status);
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  232  	}
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  233  	writel(0, iommu->regs + VSI_MMU_STATUS_BASE);
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  234
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  235  	spin_unlock_irqrestore(&iommu->lock, flags);
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  236  	pm_runtime_put_autosuspend(iommu->dev);
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  237
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  238  	return IRQ_HANDLED;
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  239  }
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  240
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  241  static struct vsi_iommu *vsi_iommu_get_from_dev(struct device *dev)
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  242  {
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  243  	struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  244  	struct device *iommu_dev = bus_find_device_by_fwnode(&platform_bus_type,
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15 @245  							     fwspec->iommu_fwnode);
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  246
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  247  	put_device(iommu_dev);
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  248
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  249  	return iommu_dev ? dev_get_drvdata(iommu_dev) : NULL;
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  250  }
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  251
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  252  static struct iommu_domain *vsi_iommu_domain_alloc_paging(struct device *dev)
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  253  {
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15 @254  	struct vsi_iommu *iommu = dev_iommu_priv_get(dev);
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  255  	struct vsi_iommu_domain *vsi_domain;
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  256
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  257  	vsi_domain = kzalloc(sizeof(*vsi_domain), GFP_KERNEL);
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  258  	if (!vsi_domain)
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  259  		return NULL;
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  260
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  261  	vsi_domain->dev = iommu->dev;
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  262  	spin_lock_init(&vsi_domain->lock);
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  263
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  264  	/*
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  265  	 * iommu use a 2 level pagetable.
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  266  	 * Each level1 (dt) and level2 (pt) table has 1024 4-byte entries.
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  267  	 * Allocate one 4 KiB page for each table.
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  268  	 */
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  269  	vsi_domain->dt = iommu_alloc_pages_sz(GFP_KERNEL | GFP_DMA32,
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  270  					      SPAGE_SIZE);
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  271  	if (!vsi_domain->dt)
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  272  		goto err_free_domain;
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  273
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  274  	vsi_domain->dt_dma = dma_map_single(vsi_domain->dev, vsi_domain->dt,
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  275  					    SPAGE_SIZE, DMA_TO_DEVICE);
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  276  	if (dma_mapping_error(vsi_domain->dev, vsi_domain->dt_dma)) {
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  277  		dev_err(dev, "DMA map error for DT\n");
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  278  		goto err_free_dt;
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  279  	}
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  280
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  281  	vsi_domain->pta = iommu_alloc_pages_sz(GFP_KERNEL | GFP_DMA32,
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  282  					       SPAGE_SIZE);
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  283  	if (!vsi_domain->pta)
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  284  		goto err_unmap_dt;
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  285
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  286  	vsi_domain->pta[0] = vsi_mk_pta(vsi_domain->dt_dma);
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  287  	vsi_domain->pta_dma = dma_map_single(vsi_domain->dev, vsi_domain->pta,
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  288  					     SPAGE_SIZE, DMA_TO_DEVICE);
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  289  	if (dma_mapping_error(vsi_domain->dev, vsi_domain->pta_dma)) {
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  290  		dev_err(dev, "DMA map error for PTA\n");
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  291  		goto err_free_pta;
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  292  	}
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  293
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  294  	INIT_LIST_HEAD(&vsi_domain->iommus);
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  295
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  296  	vsi_domain->domain.geometry.aperture_start = 0;
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  297  	vsi_domain->domain.geometry.aperture_end   = DMA_BIT_MASK(32);
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  298  	vsi_domain->domain.geometry.force_aperture = true;
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  299  	vsi_domain->domain.pgsize_bitmap	   = SZ_4K;
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  300
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  301  	return &vsi_domain->domain;
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  302
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  303  err_free_pta:
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  304  	iommu_free_pages(vsi_domain->pta);
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  305  err_unmap_dt:
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  306  	dma_unmap_single(vsi_domain->dev, vsi_domain->dt_dma,
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  307  			 SPAGE_SIZE, DMA_TO_DEVICE);
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  308  err_free_dt:
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  309  	iommu_free_pages(vsi_domain->dt);
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  310  err_free_domain:
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  311  	kfree(vsi_domain);
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  312
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  313  	return NULL;
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  314  }
> b9e3cd4bea55cd Benjamin Gaignard 2025-12-15  315
>


From sumit.garg at kernel.org  Wed Dec 17 01:02:02 2025
From: sumit.garg at kernel.org (Sumit Garg)
Date: Wed, 17 Dec 2025 14:32:02 +0530
Subject: [PATCH v1 00/17] tee: Use bus callbacks instead of driver
 callbacks
In-Reply-To: <max5wxkcjjvnftwfwgymybwbnvf5s3ytwpy4oo5i74kfvnav4m@m2wasqyxsf4h>
References: <cover.1765472125.git.u.kleine-koenig@baylibre.com>
 <aT--ox375kg2Mzh-@sumit-X1>
 <dhunzydod4d7vj73llpuqemxb5er2ja4emxusr66irwf77jhhb@es4yd2axzl25>
 <CAGptzHOOqLhBnAXDURAzkgckUvRr__UuF1S_7MLV0u-ZxYEdyA@mail.gmail.com>
 <ayebinxqpcnl7hpa35ytrudiy7j75u5bdk3enlirkp5pevppeg@6mx6a5fwymwf>
 <aUJh--HGVeJWIilS@sumit-xelite>
 <max5wxkcjjvnftwfwgymybwbnvf5s3ytwpy4oo5i74kfvnav4m@m2wasqyxsf4h>
Message-ID: <aUJxiioKnDVSC34H@sumit-xelite>

On Wed, Dec 17, 2025 at 09:21:41AM +0100, Uwe Kleine-K?nig wrote:
> Hello Sumit,
> 
> On Wed, Dec 17, 2025 at 01:25:39PM +0530, Sumit Garg wrote:
> > On Tue, Dec 16, 2025 at 12:08:38PM +0100, Uwe Kleine-K?nig wrote:
> > > On Tue, Dec 16, 2025 at 01:08:38PM +0530, Sumit Garg wrote:
> > > > On Mon, Dec 15, 2025 at 3:02?PM Uwe Kleine-K?nig
> > > > <u.kleine-koenig at baylibre.com> wrote:
> > > > >  - Why does optee_probe() in drivers/tee/optee/smc_abi.c unregister all
> > > > >    optee devices in its error path (optee_unregister_devices())?
> > > > 
> > > > This is mostly to take care of if any device got registered before the
> > > > failure occured. Let me know if you have a better way to address that.
> > > 
> > > Without understanding the tee stuff, I'd say: Don't bother and only undo
> > > the things that probe did before the failure.
> > 
> > True, but this is special case where if there is any leftover device
> > registered from the TEE implementation then it is likely going to cause
> > the corresponding kernel client driver crash.
> 
> You are aware that this is racy? So if a driver crashes e.g. after
> teedev_close_context() it might happen that it is registered just after
> optee_unregister_devices() returns.
> 

I see your point about the unavoidable race. Maybe it's better to not
try anything and let the kernel client driver fail.

-Sumit


From matthias.schiffer at ew.tq-group.com  Wed Dec 17 01:10:16 2025
From: matthias.schiffer at ew.tq-group.com (Matthias Schiffer)
Date: Wed, 17 Dec 2025 10:10:16 +0100
Subject: [PATCH v4 2/2] arm64: dts: ti: Add TQ-Systems TQMa62xx SoM and
 MBa62xx carrier board Device Trees
In-Reply-To: <671625aa-f5da-4e34-9c8c-7a1da282aa5e@ti.com>
References: <cover.1762775119.git.matthias.schiffer@ew.tq-group.com>
	 <0079cc291c78b94068f3d8c59df103e951247acc.1762775119.git.matthias.schiffer@ew.tq-group.com>
	 <d13a95659bdd1c840dfaa46afd6d8583f1b7c88f.camel@ew.tq-group.com>
	 <671625aa-f5da-4e34-9c8c-7a1da282aa5e@ti.com>
Message-ID: <637f14d1c77c2a1d19f7ea221addbbea51392bd9.camel@ew.tq-group.com>

On Wed, 2025-11-26 at 10:47 +0530, Vignesh Raghavendra wrote:
> Hi Matthias,
> 
> On 25/11/25 15:32, Matthias Schiffer wrote:
> > On Mon, 2025-11-10 at 12:49 +0100, Matthias Schiffer wrote:
> > > The TQMa62xx is a SoM family with a pluggable board connector based on the
> > > TI AM62x SoCs. Add DTS(I) for the AM625 (2x Cortex-A53) variant and its
> > > combination with our MBa62xx carrier board.
> > 
> > Hi Vignesh,
> > 
> > do you have any further comments? Can we get this in for 6.19?
> > 
> 
> Oops, this somehow fell through the crack, my apologies!
> 
> I have already sent out the PRs for v6.19. Sorry, this would need to
> wait for v6.20 cycle.
> 
> [...]
> 
> 

Hi Vignesh,

will these patches by applied for v6.20 (if there aren't any more review
comments)? Should I resend them?

Best,
Matthias





-- 
TQ-Systems GmbH | M?hlstra?e 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht M?nchen, HRB 105018
Gesch?ftsf?hrer: Detlef Schneider, R?diger Stahl, Stefan Schneider
https://www.tq-group.com/


From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec 17 01:18:08 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed, 17 Dec 2025 10:18:08 +0100
Subject: [PATCH RESEND] arm64: dts: rockchip: Fix wifi interrupts flag on Sakura Pi RK3308B
Message-ID: <20251217091808.38253-2-krzysztof.kozlowski@oss.qualcomm.com>

GPIO_ACTIVE_x flags are not correct in the context of interrupt flags.
These are simple defines so they could be used in DTS but they will not
have the same meaning: GPIO_ACTIVE_HIGH = 0 = IRQ_TYPE_NONE.

Correct the interrupt flags, assuming the author of the code wanted same
logical behavior behind the name "ACTIVE_xxx", this is:
  ACTIVE_HIGH  => IRQ_TYPE_LEVEL_HIGH

Fixes: 79f2a1702441 ("arm64: dts: rockchip: add DTs for Sakura Pi RK3308B")
Cc: <stable+noautosel at kernel.org> # Needs testing, because actual level is just a guess
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

---

Re-sending after 4 months:
https://lore.kernel.org/all/20250818090445.28112-3-krzysztof.kozlowski at linaro.org/
---
 arch/arm64/boot/dts/rockchip/rk3308-sakurapi-rk3308b.dts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3308-sakurapi-rk3308b.dts b/arch/arm64/boot/dts/rockchip/rk3308-sakurapi-rk3308b.dts
index e5e6b800c2d1..3473db08b9b2 100644
--- a/arch/arm64/boot/dts/rockchip/rk3308-sakurapi-rk3308b.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3308-sakurapi-rk3308b.dts
@@ -199,7 +199,7 @@ brcmf: wifi at 1 {
 		compatible = "brcm,bcm43455-fmac", "brcm,bcm4329-fmac";
 		reg = <1>;
 		interrupt-parent = <&gpio0>;
-		interrupts = <RK_PA3 GPIO_ACTIVE_HIGH>;
+		interrupts = <RK_PA3 IRQ_TYPE_LEVEL_HIGH>;
 		interrupt-names = "host-wake";
 		pinctrl-names = "default";
 		pinctrl-0 = <&wifi_host_wake>;
-- 
2.51.0



From maz at kernel.org  Wed Dec 17 01:18:23 2025
From: maz at kernel.org (Marc Zyngier)
Date: Wed, 17 Dec 2025 09:18:23 +0000
Subject: [PATCH v3 0/4] KVM: arm64: pKVM fixes
In-Reply-To: <20251216103053.47224-1-alexandru.elisei@arm.com>
References: <20251216103053.47224-1-alexandru.elisei@arm.com>
Message-ID: <867bulo49s.wl-maz@kernel.org>

On Tue, 16 Dec 2025 10:30:49 +0000,
Alexandru Elisei <alexandru.elisei at arm.com> wrote:
> 
> v2 can be found at [1].
> 
> Similar to [2], when trying to run an unprotected VM on FVP with S1PIE enabled
> and kvm-arm.mode=protected, writes to PIRE0_EL1 made by the guest in
> __cpu_setup() are trapped by KVM and the BUG_ON(!r->access) is hit. That's
> because HFGWTR_EL2.nPIRE0_EL1 is an inverse polarity trap and the FGT values for
> the unprotected pKVM VCPU weren't being propagated from kvm_arch_vcpu_load().
> 
> Couldn't figure out how to run a protected pKVM VM, so that's untested.

Reviewed-by: Marc Zyngier <maz at kernel.org>

	M.

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


From kevin.brodsky at arm.com  Wed Dec 17 01:26:12 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Wed, 17 Dec 2025 10:26:12 +0100
Subject: [PATCH v6 14/14] mm: Add basic tests for lazy_mmu
In-Reply-To: <20251216201403.4647a4f9861d3122ee9e90d7@linux-foundation.org>
References: <20251215150323.2218608-1-kevin.brodsky@arm.com>
 <20251215150323.2218608-15-kevin.brodsky@arm.com>
 <20251216201403.4647a4f9861d3122ee9e90d7@linux-foundation.org>
Message-ID: <f9550d22-8810-4145-aaa8-48961f6ea35e@arm.com>

On 17/12/2025 05:14, Andrew Morton wrote:
> On Mon, 15 Dec 2025 15:03:23 +0000 Kevin Brodsky <kevin.brodsky at arm.com> wrote:
>
>> Add basic KUnit tests for the generic aspects of the lazy MMU mode:
>> ensure that it appears active when it should, depending on how
>> enable/disable and pause/resume pairs are nested.
> I needed this for powerpc allmodconfig;
>
> --- a/arch/powerpc/mm/book3s64/hash_tlb.c~mm-add-basic-tests-for-lazy_mmu-fix
> +++ a/arch/powerpc/mm/book3s64/hash_tlb.c
> @@ -30,6 +30,7 @@
>  #include <trace/events/thp.h>
>  
>  DEFINE_PER_CPU(struct ppc64_tlb_batch, ppc64_tlb_batch);
> +EXPORT_SYMBOL_GPL(ppc64_tlb_batch);
>  
>  /*
>   * A linux PTE was changed and the corresponding hash table entry
> @@ -154,6 +155,7 @@ void __flush_tlb_pending(struct ppc64_tl
>  		flush_hash_range(i, local);
>  	batch->index = 0;
>  }
> +EXPORT_SYMBOL_GPL(__flush_tlb_pending);
>  
>  void hash__tlb_flush(struct mmu_gather *tlb)
>  {
> _

Oh indeed I hadn't considered that arch_{enter,leave}_lazy_mmu_mode()
refer to those symbols on powerpc... Maybe a bit overkill to export
those just for a test module, but I'm not sure there's a good
alternative. Forcing LAZY_MMU_MODE_KUNIT_TEST=y is ugly as it would also
force KUNIT=y. Alternatively we could depend on !PPC, not pretty either.

- Kevin


From james.clark at linaro.org  Wed Dec 17 01:30:47 2025
From: james.clark at linaro.org (James Clark)
Date: Wed, 17 Dec 2025 11:30:47 +0200
Subject: [PATCH v3 05/12] perf evsel: Add a helper to get the value of a
 config field
In-Reply-To: <CAP-5=fUbr56hFd7e7yt33-gnhEGGa72GLmShQ5bCHxQjFAbFCQ@mail.gmail.com>
References: <20251212-james-perf-config-bits-v3-0-aa36a4846776@linaro.org>
 <20251212-james-perf-config-bits-v3-5-aa36a4846776@linaro.org>
 <CAP-5=fUbr56hFd7e7yt33-gnhEGGa72GLmShQ5bCHxQjFAbFCQ@mail.gmail.com>
Message-ID: <58d9f452-c075-4499-8975-387f3cdb052a@linaro.org>



On 16/12/2025 22:44, Ian Rogers wrote:
> On Fri, Dec 12, 2025 at 7:32?AM James Clark <james.clark at linaro.org> wrote:
>>
>> This will be used by aux PMUs to read an already written value for
>> configuring their events and for also testing.
>>
>> Its helper pmu_format_unpack() does the opposite of the existing
>> pmu_format_value() so rename that one to pmu_format_pack() so it's clear
>> how they are related.
>>
>> Signed-off-by: James Clark <james.clark at linaro.org>
>> ---
>>   tools/perf/util/evsel.h |  2 ++
>>   tools/perf/util/pmu.c   | 77 ++++++++++++++++++++++++++++++++++++++++++-------
>>   2 files changed, 68 insertions(+), 11 deletions(-)
>>
>> diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
>> index a08130ff2e47a887b19f6c47bfa9f51e0c40d226..092904a61ec7afdc59253f9b78a9fe8b7cb5bfa7 100644
>> --- a/tools/perf/util/evsel.h
>> +++ b/tools/perf/util/evsel.h
>> @@ -575,6 +575,8 @@ void evsel__uniquify_counter(struct evsel *counter);
>>          ((((src) >> (pos)) & ((1ull << (size)) - 1)) << (63 - ((pos) + (size) - 1)))
>>
>>   u64 evsel__bitfield_swap_branch_flags(u64 value);
>> +int evsel__get_config_val(struct perf_pmu *pmu, struct evsel *evsel,
>> +                         const char *config_name, u64 *val);
>>   void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
>>                                  const char *config_name, u64 val);
>>
>> diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
>> index 514cba91f5d99b399d2d6a1e350971660c54a9fc..ef7358ad1fb955f29f2e68b3d0ce711754e4d67c 100644
>> --- a/tools/perf/util/pmu.c
>> +++ b/tools/perf/util/pmu.c
>> @@ -144,8 +144,8 @@ struct perf_pmu_format {
>>   };
>>
>>   static int pmu_aliases_parse(struct perf_pmu *pmu);
>> -static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
>> -                            bool zero);
>> +static void pmu_format_pack(unsigned long *format, __u64 value, __u64 *v,
>> +                           bool zero);
>>   static struct perf_pmu_format *pmu_find_format(const struct list_head *formats,
>>                                                 const char *name);
>>
>> @@ -1377,6 +1377,61 @@ bool evsel__is_aux_event(const struct evsel *evsel)
>>          return pmu && pmu->auxtrace;
>>   }
>>
>> +/*
>> + * Unpacks a raw config[n] value using the sparse bitfield that defines a
>> + * format attr. For example "config1:1,6-7,44" defines a 4 bit value across non
>> + * contiguous bits and this function returns those 4 bits as a value.
>> + */
>> +static u64 pmu_format_unpack(u64 format, u64 config_val)
>> +{
>> +       int val_bit = 0;
>> +       u64 res = 0;
>> +       int fmt_bit;
>> +
>> +       for_each_set_bit(fmt_bit, &format, PERF_PMU_FORMAT_BITS) {
>> +               if (test_bit(fmt_bit, &config_val))
>> +                       res |= BIT_ULL(val_bit);
>> +
>> +               val_bit++;
>> +       }
>> +       return res;
>> +}
>> +
>> +int evsel__get_config_val(struct perf_pmu *pmu, struct evsel *evsel,
>> +                         const char *config_name, u64 *val)
> 
> nits:
> This is an evsel__ function but the evsel is the 2nd argument not the first.
> Why pass the PMU and not just read evsel->pmu (or better evsel__find_pmu) ?

That makes sense, I can do that.

> Why not place this in evsel.c to match the header file declaration?

This was for consistency with evsel__set_config_if_unset() that Arnaldo 
moved to pmu.c because of an issue with the Python bindings [1]. That 
doesn't seem to be an issue any more so I could move both to evsel.c. 
That would require making the following things public:

   struct perf_pmu_format
   pmu_format_pack()
   pmu_format_unpack()
   pmu_find_format()

Probably not the end of the world though?

[1]: https://lore.kernel.org/all/ZEbAS2yx2fguW60w at kernel.org/

> The evsel could be likely be const.
> 

Will do

> Thanks,
> Ian
> 
>> +{
>> +       struct perf_pmu_format *format = pmu_find_format(&pmu->format, config_name);
>> +       u64 bits = perf_pmu__format_bits(pmu, config_name);
>> +
>> +       if (!format || !bits) {
>> +               pr_err("Unknown/empty format name: %s\n", config_name);
>> +               *val = 0;
>> +               return -EINVAL;
>> +       }
>> +
>> +       switch (format->value) {
>> +       case PERF_PMU_FORMAT_VALUE_CONFIG:
>> +               *val = pmu_format_unpack(bits, evsel->core.attr.config);
>> +               return 0;
>> +       case PERF_PMU_FORMAT_VALUE_CONFIG1:
>> +               *val = pmu_format_unpack(bits, evsel->core.attr.config1);
>> +               return 0;
>> +       case PERF_PMU_FORMAT_VALUE_CONFIG2:
>> +               *val = pmu_format_unpack(bits, evsel->core.attr.config2);
>> +               return 0;
>> +       case PERF_PMU_FORMAT_VALUE_CONFIG3:
>> +               *val = pmu_format_unpack(bits, evsel->core.attr.config3);
>> +               return 0;
>> +       case PERF_PMU_FORMAT_VALUE_CONFIG4:
>> +               *val = pmu_format_unpack(bits, evsel->core.attr.config4);
>> +               return 0;
>> +       default:
>> +               pr_err("Unknown format value: %d\n", format->value);
>> +               *val = 0;
>> +               return -EINVAL;
>> +       }
>> +}
>> +
>>   /*
>>    * Set @config_name to @val as long as the user hasn't already set or cleared it
>>    * by passing a config term on the command line.
>> @@ -1432,7 +1487,7 @@ void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
>>                  return;
>>
>>          /* Otherwise replace it */
>> -       pmu_format_value(&bits, val, vp, /*zero=*/true);
>> +       pmu_format_pack(&bits, val, vp, /*zero=*/true);
>>   }
>>
>>   static struct perf_pmu_format *
>> @@ -1477,8 +1532,8 @@ int perf_pmu__format_type(struct perf_pmu *pmu, const char *name)
>>    * Sets value based on the format definition (format parameter)
>>    * and unformatted value (value parameter).
>>    */
>> -static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
>> -                            bool zero)
>> +static void pmu_format_pack(unsigned long *format, __u64 value, __u64 *v,
>> +                           bool zero)
>>   {
>>          unsigned long fbit, vbit;
>>
>> @@ -1595,23 +1650,23 @@ static int pmu_config_term(const struct perf_pmu *pmu,
>>                  switch (term->type_term) {
>>                  case PARSE_EVENTS__TERM_TYPE_CONFIG:
>>                          assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
>> -                       pmu_format_value(bits, term->val.num, &attr->config, zero);
>> +                       pmu_format_pack(bits, term->val.num, &attr->config, zero);
>>                          break;
>>                  case PARSE_EVENTS__TERM_TYPE_CONFIG1:
>>                          assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
>> -                       pmu_format_value(bits, term->val.num, &attr->config1, zero);
>> +                       pmu_format_pack(bits, term->val.num, &attr->config1, zero);
>>                          break;
>>                  case PARSE_EVENTS__TERM_TYPE_CONFIG2:
>>                          assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
>> -                       pmu_format_value(bits, term->val.num, &attr->config2, zero);
>> +                       pmu_format_pack(bits, term->val.num, &attr->config2, zero);
>>                          break;
>>                  case PARSE_EVENTS__TERM_TYPE_CONFIG3:
>>                          assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
>> -                       pmu_format_value(bits, term->val.num, &attr->config3, zero);
>> +                       pmu_format_pack(bits, term->val.num, &attr->config3, zero);
>>                          break;
>>                  case PARSE_EVENTS__TERM_TYPE_CONFIG4:
>>                          assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
>> -                       pmu_format_value(bits, term->val.num, &attr->config4, zero);
>> +                       pmu_format_pack(bits, term->val.num, &attr->config4, zero);
>>                          break;
>>                  case PARSE_EVENTS__TERM_TYPE_LEGACY_HARDWARE_CONFIG:
>>                          assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
>> @@ -1749,7 +1804,7 @@ static int pmu_config_term(const struct perf_pmu *pmu,
>>                   */
>>          }
>>
>> -       pmu_format_value(format->bits, val, vp, zero);
>> +       pmu_format_pack(format->bits, val, vp, zero);
>>          return 0;
>>   }
>>
>>
>> --
>> 2.34.1
>>



From taniya.das at oss.qualcomm.com  Wed Dec 17 01:32:06 2025
From: taniya.das at oss.qualcomm.com (Taniya Das)
Date: Wed, 17 Dec 2025 15:02:06 +0530
Subject: [PATCH v2 07/11] dt-bindings: clock: qcom: document the Kaanapali
 GPU Clock Controller
In-Reply-To: <fbe39eac-7c92-4a08-bafb-31e5c51a0613@kernel.org>
References: <20251125-kaanapali-mmcc-v2-v2-0-fb44e78f300b@oss.qualcomm.com>
 <20251125-kaanapali-mmcc-v2-v2-7-fb44e78f300b@oss.qualcomm.com>
 <20251126-elated-stoic-scorpion-25b630@kuoka>
 <de44560d-4ed8-41fe-be7b-56412b933a8c@oss.qualcomm.com>
 <fbe39eac-7c92-4a08-bafb-31e5c51a0613@kernel.org>
Message-ID: <503f445e-0d12-407d-bc77-f48ad335639b@oss.qualcomm.com>



On 12/16/2025 2:21 PM, Krzysztof Kozlowski wrote:
> On 04/12/2025 07:49, Taniya Das wrote:
>>>> +  power-domains:
>>>> +    description:
>>>> +      Power domains required for the clock controller to operate
>>>> +    items:
>>>> +      - description: GFX power domain
>>>> +      - description: GMXC power domain
>>>> +      - description: GPUCC(CX) power domain
>>>> +
>>>> +  '#power-domain-cells':
>>>
>>> Power domain controllers do not belong to clocks, so this is:
>>> 1. Misplaced - wrong folder
>>> 2. Probably wrongly named. gxclkctl sounds like clock controller, but
>>> this is domain controller?
>>>
>>
>> The GFXCLKCTL is actually a clock controller which has PLLs, clocks and
>> Power domains (GDSC), but the requirement here is to use the GDSC from
>> the clock controller to recover the GPU firmware in case of any
>> failure/hangs. The rest of the resources of the clock controller are
>> being used by the firmware of GPU. The GDSC is a clock controller
>> resource and modeled from the clock controller drivers across chipsets.
> 
> This should be somewhere explained.

I will capture it in the binding description in the next patch set.

> 
>>
>>>> +    const: 1
>>>> +
>>>> +  reg:
>>>> +    maxItems: 1
>>>> +
>>>> +required:
>>>> +  - compatible
>>>> +  - reg
>>>> +  - power-domains
>>>> +  - '#power-domain-cells'
>>>> +
>>>> +unevaluatedProperties: false
>>>> +
>>>> +examples:
>>>> +  - |
>>>> +    #include <dt-bindings/power/qcom,rpmhpd.h>
>>>> +    soc {
>>>> +        #address-cells = <2>;
>>>> +        #size-cells = <2>;
>>>> +
>>>> +        clock-controller at 3d68024 {
>>>> +            compatible = "qcom,kaanapali-gxclkctl";
>>>> +            reg = <0 0x3d68024 0x0 0x8>;
>>>
>>> Keep consistent hex, so first 0 -> 0x0.
>>
>> Sure, will fix this.
>>
>>> But the problem is that you defined a device for two registers,
>>> basically one domain. I have doubts now whether this is complete and
>>> real device.
>>>
>>
>> As the Linux GPU driver requires only the GDSC, I have mapped the region
>> which is required by the clock controller driver. If required, the
>> entire region can be mapped as well.
> 
> Required is to properly describe the hardware, please read writing
> bindings doc.
> 

Sure, will map the entire region to be describe the entire hardware.

>>
>>>> +            power-domains = <&rpmhpd RPMHPD_GFX>,
>>>> +                            <&rpmhpd RPMHPD_GMXC>,
>>>> +                            <&gpucc 0>;
>>>> +            #power-domain-cells = <1>;
>>>
>>> And cells 1 makes no sense in such case.
>>>
>>
>> We would like to leverage the existing common clock driver(GDSC) code to
> 
> Fix the driver code if it cannot handle other cells. Your drivers do not
> matter for choices made in bindings.
> 

As it is still a clock controller from hardware design and in SW I will
be map the entire hardware region and this way this clock controller
will also be aligned to the existing clock controllers and keep the
#power-domain-cells = <1> as other CCs.

>> register the power-domains and also maintain uniformity across chipsets
>> and consistency in consumer GDSC phandle usage.
> 
> There is no such consistency rule. Don't make up your own rules.
> 
-- 
Thanks,
Taniya Das



From damon.ding at rock-chips.com  Wed Dec 17 01:33:04 2025
From: damon.ding at rock-chips.com (Damon Ding)
Date: Wed, 17 Dec 2025 17:33:04 +0800
Subject: [PATCH v8 01/18] drm/display: bridge_connector: Ensure last bridge determines EDID/modes detection capabilities
In-Reply-To: <20251217093321.3108939-1-damon.ding@rock-chips.com>
References: <20251217093321.3108939-1-damon.ding@rock-chips.com>
Message-ID: <20251217093321.3108939-2-damon.ding@rock-chips.com>

When multiple bridges are present, EDID detection capability
(DRM_BRIDGE_OP_EDID) takes precedence over modes detection
(DRM_BRIDGE_OP_MODES). To ensure the above two capabilities are
determined by the last bridge in the chain, we handle three cases:

Case 1: The later bridge declares only DRM_BRIDGE_OP_MODES
 - If the previous bridge declares DRM_BRIDGE_OP_EDID, set
   &drm_bridge_connector.bridge_edid to NULL and set
   &drm_bridge_connector.bridge_modes to the later bridge.
 - Ensure modes detection capability of the later bridge will not
   be ignored.

Case 2: The later bridge declares only DRM_BRIDGE_OP_EDID
 - If the previous bridge declares DRM_BRIDGE_OP_MODES, set
   &drm_bridge_connector.bridge_modes to NULL and set
   &drm_bridge_connector.bridge_edid to the later bridge.
 - Although EDID detection capability has higher priority, this
   operation is for balance and makes sense.

Case 3: the later bridge declares both of them
 - Assign later bridge as &drm_bridge_connector.bridge_edid and
   and &drm_bridge_connector.bridge_modes to this bridge.
 - Just leave transfer of these two capabilities as before.

Signed-off-by: Damon Ding <damon.ding at rock-chips.com>
Suggested-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Tested-by: Marek Szyprowski <m.szyprowski at samsung.com>

---

Changes in v7:
- As Luca suggested, simplify the code and related comment.

Changes in v8:
- Adapt the modifications to the newest bridge_connector driver.
---
 drivers/gpu/drm/display/drm_bridge_connector.c | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index a2d30cf9e06d..92b9e8ec520d 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -690,9 +690,19 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
 		if (!bridge->ycbcr_420_allowed)
 			connector->ycbcr_420_allowed = false;
 
-		if (bridge->ops & DRM_BRIDGE_OP_EDID) {
+		/*
+		 * Ensure the last bridge declares OP_EDID or OP_MODES or both.
+		 */
+		if (bridge->ops & DRM_BRIDGE_OP_EDID || bridge->ops & DRM_BRIDGE_OP_MODES) {
 			drm_bridge_put(bridge_connector->bridge_edid);
-			bridge_connector->bridge_edid = drm_bridge_get(bridge);
+			bridge_connector->bridge_edid = NULL;
+			drm_bridge_put(bridge_connector->bridge_modes);
+			bridge_connector->bridge_modes = NULL;
+
+			if (bridge->ops & DRM_BRIDGE_OP_EDID)
+				bridge_connector->bridge_edid = drm_bridge_get(bridge);
+			if (bridge->ops & DRM_BRIDGE_OP_MODES)
+				bridge_connector->bridge_modes = drm_bridge_get(bridge);
 		}
 		if (bridge->ops & DRM_BRIDGE_OP_HPD) {
 			drm_bridge_put(bridge_connector->bridge_hpd);
@@ -702,10 +712,6 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
 			drm_bridge_put(bridge_connector->bridge_detect);
 			bridge_connector->bridge_detect = drm_bridge_get(bridge);
 		}
-		if (bridge->ops & DRM_BRIDGE_OP_MODES) {
-			drm_bridge_put(bridge_connector->bridge_modes);
-			bridge_connector->bridge_modes = drm_bridge_get(bridge);
-		}
 		if (bridge->ops & DRM_BRIDGE_OP_HDMI) {
 			if (bridge_connector->bridge_hdmi)
 				return ERR_PTR(-EBUSY);
-- 
2.34.1



From damon.ding at rock-chips.com  Wed Dec 17 01:33:03 2025
From: damon.ding at rock-chips.com (Damon Ding)
Date: Wed, 17 Dec 2025 17:33:03 +0800
Subject: [PATCH v8 00/18] Apply drm_bridge_connector and panel_bridge helper for the Analogix DP driver
Message-ID: <20251217093321.3108939-1-damon.ding@rock-chips.com>

PATCH 1 is to ensure the last bridge declares OP_EDID or OP_MODES or both.
PATCH 2 is a small format optimization for struct analogid_dp_device.
PATCH 3 is to perform mode setting in &drm_bridge_funcs.atomic_enable.
PATCH 4 is to add a new parameter to store the point of next bridge.
PATCH 5 is to make legacy bridge driver more universal.
PATCH 6-11 are preparations for apply drm_bridge_connector helper.
PATCH 12 is to apply the drm_bridge_connector helper.
PATCH 13-15 are to move the panel/bridge parsing to the Analogix side.
PATCH 16 is to attach the next bridge on Analogix side uniformly.
PATCH 17-18 are to apply the panel_bridge helper.

The following reviewed commits, which to make codes more concise, are
rebased to the front of this patch series:

https://lore.kernel.org/all/20251110085823.1197472-1-damon.ding at rock-chips.com/
https://lore.kernel.org/all/20251111022103.1350183-1-damon.ding at rock-chips.com/

Damon Ding (18):
  drm/display: bridge_connector: Ensure last bridge determines
    EDID/modes detection capabilities
  drm/bridge: analogix_dp: Formalize the struct analogix_dp_device
  drm/bridge: analogix_dp: Move &drm_bridge_funcs.mode_set to
    &drm_bridge_funcs.atomic_enable
  drm/bridge: analogix_dp: Add &analogix_dp_plat_data.next_bridge
  drm/bridge: Move legacy bridge driver out of imx directory for
    multi-platform use
  drm/exynos: exynos_dp: Remove &exynos_dp_device.ptn_bridge
  drm/exynos: exynos_dp: Remove unused &exynos_dp_device.connector
  drm/exynos: exynos_dp: Apply of-display-mode-bridge to parse the
    display-timings node
  drm/bridge: analogix_dp: Remove redundant
    &analogix_dp_plat_data.skip_connector
  drm/bridge: analogix_dp: Move the color format check to
    .atomic_check() for Rockchip platforms
  drm/bridge: analogix_dp: Remove unused
    &analogix_dp_plat_data.get_modes()
  drm/bridge: analogix_dp: Apply drm_bridge_connector helper
  drm/bridge: analogix_dp: Add new API analogix_dp_finish_probe()
  drm/rockchip: analogix_dp: Apply analogix_dp_finish_probe()
  drm/exynos: exynos_dp: Apply analogix_dp_finish_probe()
  drm/bridge: analogix_dp: Attach the next bridge in
    analogix_dp_bridge_attach()
  drm/bridge: analogix_dp: Remove bridge disabing and panel unpreparing
    in analogix_dp_unbind()
  drm/bridge: analogix_dp: Apply panel_bridge helper

 drivers/gpu/drm/bridge/Kconfig                |  10 +
 drivers/gpu/drm/bridge/Makefile               |   1 +
 drivers/gpu/drm/bridge/analogix/Kconfig       |   1 +
 .../drm/bridge/analogix/analogix_dp_core.c    | 395 +++++++++---------
 .../drm/bridge/analogix/analogix_dp_core.h    |   5 +-
 drivers/gpu/drm/bridge/imx/Kconfig            |  10 -
 drivers/gpu/drm/bridge/imx/Makefile           |   1 -
 .../gpu/drm/bridge/imx/imx-legacy-bridge.c    |  91 ----
 .../gpu/drm/bridge/of-display-mode-bridge.c   |  93 +++++
 .../gpu/drm/display/drm_bridge_connector.c    |  18 +-
 drivers/gpu/drm/exynos/Kconfig                |   2 +
 drivers/gpu/drm/exynos/exynos_dp.c            | 110 ++---
 drivers/gpu/drm/imx/ipuv3/Kconfig             |   4 +-
 drivers/gpu/drm/imx/ipuv3/imx-ldb.c           |   6 +-
 drivers/gpu/drm/imx/ipuv3/parallel-display.c  |   5 +-
 drivers/gpu/drm/rockchip/Kconfig              |   1 +
 .../gpu/drm/rockchip/analogix_dp-rockchip.c   |  67 +--
 include/drm/bridge/analogix_dp.h              |   8 +-
 include/drm/bridge/imx.h                      |  17 -
 include/drm/bridge/of-display-mode-bridge.h   |  17 +
 20 files changed, 391 insertions(+), 471 deletions(-)
 delete mode 100644 drivers/gpu/drm/bridge/imx/imx-legacy-bridge.c
 create mode 100644 drivers/gpu/drm/bridge/of-display-mode-bridge.c
 delete mode 100644 include/drm/bridge/imx.h
 create mode 100644 include/drm/bridge/of-display-mode-bridge.h

---

Changes in v2:
- Update Exynos DP driver synchronously.
- Move the panel/bridge parsing to the Analogix side.

Changes in v3:
- Rebase for the existing devm_drm_bridge_alloc() applying commit.
- Fix the typographical error of panel/bridge check in exynos_dp_bind().
- Squash all commits related to skip_connector deletion in both Exynos and
  Analogix code into one.
- Apply panel_bridge helper to make the codes more concise.
- Fix the handing of bridge in analogix_dp_bridge_get_modes().
- Remove unnecessary parameter struct drm_connector* for callback
  &analogix_dp_plat_data.attach().
- In order to decouple the connector driver and the bridge driver, move
  the bridge connector initilization to the Rockchip and Exynos sides.

Changes in v4:
- Rebase for the applied &drm_bridge_funcs.detect() modification commit.
- Rename analogix_dp_find_panel_or_bridge() to analogix_dp_finish_probe().
- Drop the drmm_encoder_init() modification commit.
- Rename the &analogix_dp_plat_data.bridge to
  &analogix_dp_plat_data.next_bridge.

Changes in v5:
- Add legacy bridge to parse the display-timings node under the dp node
  for Exynos side.
- Move color format check to &drm_connector_helper_funcs.atomic_check()
  in order to get rid of &analogix_dp_plat_data.get_modes().
- Remove unused callback &analogix_dp_plat_data.get_modes().
- Distinguish the &drm_bridge->ops of Analogix bridge based on whether
  the downstream device is a panel, a bridge or neither.
- Select DRM_DISPLAY_DP_AUX_BUS for DRM_ANALOGIX_DP, and remove it for
  ROCKCHIP_ANALOGIX_DP.
- Apply rockchip_dp_attach() to support the next bridge attachment for
  the Rockchip side.
- Move next_bridge attachment from Analogix side to Rockchip/Exynos sides.

Changes in v6:
- Move legacy bridge driver out of imx directory for multi-platform use.
- Apply DRM legacy bridge to parse display timings intead of implementing
  the same codes only for Exynos DP.
- Ensure last bridge determines EDID/modes detection capabilities in DRM
  bridge_connector driver.
- Remove unnecessary drm_bridge_get_modes() in
  analogix_dp_bridge_get_modes().
- Simplify analogix_dp_bridge_edid_read().
- If the next is a bridge, set DRM_BRIDGE_OP_DETECT and return
  connector_status_connected in analogix_dp_bridge_detect().
- Set flag DRM_BRIDGE_ATTACH_NO_CONNECTOR for bridge attachment while
  binding. Meanwhile, make DRM_BRIDGE_ATTACH_NO_CONNECTOR unsuppported
  in analogix_dp_bridge_attach().
- Move the next bridge attachment to the Analogix side rather than
  scattered on Rockchip and Exynos sides.
- Remove the unnecessary analogix_dp_bridge_get_modes().
- Squash [PATCH v5 15/17] into [PATCH v5 17/17].
- Fix the &drm_bridge->ops to DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT.

Changes in v7:
- As Luca suggested, simplify the code and related comment for bridge_connector
  modifications. Additionally, move the commit related to bridge_connector to
  the top of this patch series.
- Rename legacy-bridge driver to of-display-mode-bridge driver.
- Remove unnecessary API drm_bridge_is_legacy() and apply a temporary flag
  &exynos_dp_device.has_of_bridge instead, which will be removed finally.
- Remove exynos_dp_legacy_bridge_init() and inline API
  devm_drm_of_display_mode_bridge().

Changes in v8:
- Adapt the related modifications to the newest bridge_connector driver.

-- 
2.34.1



From damon.ding at rock-chips.com  Wed Dec 17 01:33:05 2025
From: damon.ding at rock-chips.com (Damon Ding)
Date: Wed, 17 Dec 2025 17:33:05 +0800
Subject: [PATCH v8 02/18] drm/bridge: analogix_dp: Formalize the struct analogix_dp_device
In-Reply-To: <20251217093321.3108939-1-damon.ding@rock-chips.com>
References: <20251217093321.3108939-1-damon.ding@rock-chips.com>
Message-ID: <20251217093321.3108939-3-damon.ding@rock-chips.com>

Use the tap instead of the space for &analogix_dp_device.aux and
&analogix_dp_device.force_hpd.

Signed-off-by: Damon Ding <damon.ding at rock-chips.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Tested-by: Marek Szyprowski <m.szyprowski at samsung.com>
---
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index b86e93f30ed6..91b215c6a0cf 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -156,7 +156,7 @@ struct analogix_dp_device {
 	struct drm_device	*drm_dev;
 	struct drm_connector	connector;
 	struct drm_bridge	bridge;
-	struct drm_dp_aux       aux;
+	struct drm_dp_aux	aux;
 	struct clk		*clock;
 	unsigned int		irq;
 	void __iomem		*reg_base;
@@ -166,7 +166,7 @@ struct analogix_dp_device {
 	struct phy		*phy;
 	int			dpms_mode;
 	struct gpio_desc	*hpd_gpiod;
-	bool                    force_hpd;
+	bool			force_hpd;
 	bool			fast_train_enable;
 	bool			psr_supported;
 
-- 
2.34.1



From damon.ding at rock-chips.com  Wed Dec 17 01:33:06 2025
From: damon.ding at rock-chips.com (Damon Ding)
Date: Wed, 17 Dec 2025 17:33:06 +0800
Subject: [PATCH v8 03/18] drm/bridge: analogix_dp: Move &drm_bridge_funcs.mode_set to &drm_bridge_funcs.atomic_enable
In-Reply-To: <20251217093321.3108939-1-damon.ding@rock-chips.com>
References: <20251217093321.3108939-1-damon.ding@rock-chips.com>
Message-ID: <20251217093321.3108939-4-damon.ding@rock-chips.com>

According to the include/drm/drm_bridge.h, the callback
&drm_bridge_funcs.mode_set is deprecated and it should be better to
include the mode setting in the &drm_bridge_funcs.atomic_enable instead.

Signed-off-by: Damon Ding <damon.ding at rock-chips.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Tested-by: Marek Szyprowski <m.szyprowski at samsung.com>
---
 .../drm/bridge/analogix/analogix_dp_core.c    | 161 +++++++++---------
 1 file changed, 82 insertions(+), 79 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 1e834d3656c1..3caa47d31649 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1086,12 +1086,88 @@ static int analogix_dp_set_bridge(struct analogix_dp_device *dp)
 	return ret;
 }
 
+static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge,
+					const struct drm_display_mode *mode)
+{
+	struct analogix_dp_device *dp = to_dp(bridge);
+	struct drm_display_info *display_info = &dp->connector.display_info;
+	struct video_info *video = &dp->video_info;
+	struct device_node *dp_node = dp->dev->of_node;
+	int vic;
+
+	/* Input video interlaces & hsync pol & vsync pol */
+	video->interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
+	video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
+	video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
+
+	/* Input video dynamic_range & colorimetry */
+	vic = drm_match_cea_mode(mode);
+	if ((vic == 6) || (vic == 7) || (vic == 21) || (vic == 22) ||
+	    (vic == 2) || (vic == 3) || (vic == 17) || (vic == 18)) {
+		video->dynamic_range = CEA;
+		video->ycbcr_coeff = COLOR_YCBCR601;
+	} else if (vic) {
+		video->dynamic_range = CEA;
+		video->ycbcr_coeff = COLOR_YCBCR709;
+	} else {
+		video->dynamic_range = VESA;
+		video->ycbcr_coeff = COLOR_YCBCR709;
+	}
+
+	/* Input vide bpc and color_formats */
+	switch (display_info->bpc) {
+	case 12:
+		video->color_depth = COLOR_12;
+		break;
+	case 10:
+		video->color_depth = COLOR_10;
+		break;
+	case 8:
+		video->color_depth = COLOR_8;
+		break;
+	case 6:
+		video->color_depth = COLOR_6;
+		break;
+	default:
+		video->color_depth = COLOR_8;
+		break;
+	}
+	if (display_info->color_formats & DRM_COLOR_FORMAT_YCBCR444)
+		video->color_space = COLOR_YCBCR444;
+	else if (display_info->color_formats & DRM_COLOR_FORMAT_YCBCR422)
+		video->color_space = COLOR_YCBCR422;
+	else
+		video->color_space = COLOR_RGB;
+
+	/*
+	 * NOTE: those property parsing code is used for providing backward
+	 * compatibility for samsung platform.
+	 * Due to we used the "of_property_read_u32" interfaces, when this
+	 * property isn't present, the "video_info" can keep the original
+	 * values and wouldn't be modified.
+	 */
+	of_property_read_u32(dp_node, "samsung,color-space",
+			     &video->color_space);
+	of_property_read_u32(dp_node, "samsung,dynamic-range",
+			     &video->dynamic_range);
+	of_property_read_u32(dp_node, "samsung,ycbcr-coeff",
+			     &video->ycbcr_coeff);
+	of_property_read_u32(dp_node, "samsung,color-depth",
+			     &video->color_depth);
+	if (of_property_read_bool(dp_node, "hsync-active-high"))
+		video->h_sync_polarity = true;
+	if (of_property_read_bool(dp_node, "vsync-active-high"))
+		video->v_sync_polarity = true;
+	if (of_property_read_bool(dp_node, "interlaced"))
+		video->interlaced = true;
+}
+
 static void analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge,
 					     struct drm_atomic_state *old_state)
 {
 	struct analogix_dp_device *dp = to_dp(bridge);
 	struct drm_crtc *crtc;
-	struct drm_crtc_state *old_crtc_state;
+	struct drm_crtc_state *old_crtc_state, *new_crtc_state;
 	int timeout_loop = 0;
 	int ret;
 
@@ -1099,6 +1175,11 @@ static void analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge,
 	if (!crtc)
 		return;
 
+	new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc);
+	if (!new_crtc_state)
+		return;
+	analogix_dp_bridge_mode_set(bridge, &new_crtc_state->adjusted_mode);
+
 	old_crtc_state = drm_atomic_get_old_crtc_state(old_state, crtc);
 	/* Not a full enable, just disable PSR and continue */
 	if (old_crtc_state && old_crtc_state->self_refresh_active) {
@@ -1205,83 +1286,6 @@ static void analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge,
 		DRM_ERROR("Failed to enable psr (%d)\n", ret);
 }
 
-static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge,
-				const struct drm_display_mode *orig_mode,
-				const struct drm_display_mode *mode)
-{
-	struct analogix_dp_device *dp = to_dp(bridge);
-	struct drm_display_info *display_info = &dp->connector.display_info;
-	struct video_info *video = &dp->video_info;
-	struct device_node *dp_node = dp->dev->of_node;
-	int vic;
-
-	/* Input video interlaces & hsync pol & vsync pol */
-	video->interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
-	video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
-	video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
-
-	/* Input video dynamic_range & colorimetry */
-	vic = drm_match_cea_mode(mode);
-	if ((vic == 6) || (vic == 7) || (vic == 21) || (vic == 22) ||
-	    (vic == 2) || (vic == 3) || (vic == 17) || (vic == 18)) {
-		video->dynamic_range = CEA;
-		video->ycbcr_coeff = COLOR_YCBCR601;
-	} else if (vic) {
-		video->dynamic_range = CEA;
-		video->ycbcr_coeff = COLOR_YCBCR709;
-	} else {
-		video->dynamic_range = VESA;
-		video->ycbcr_coeff = COLOR_YCBCR709;
-	}
-
-	/* Input vide bpc and color_formats */
-	switch (display_info->bpc) {
-	case 12:
-		video->color_depth = COLOR_12;
-		break;
-	case 10:
-		video->color_depth = COLOR_10;
-		break;
-	case 8:
-		video->color_depth = COLOR_8;
-		break;
-	case 6:
-		video->color_depth = COLOR_6;
-		break;
-	default:
-		video->color_depth = COLOR_8;
-		break;
-	}
-	if (display_info->color_formats & DRM_COLOR_FORMAT_YCBCR444)
-		video->color_space = COLOR_YCBCR444;
-	else if (display_info->color_formats & DRM_COLOR_FORMAT_YCBCR422)
-		video->color_space = COLOR_YCBCR422;
-	else
-		video->color_space = COLOR_RGB;
-
-	/*
-	 * NOTE: those property parsing code is used for providing backward
-	 * compatibility for samsung platform.
-	 * Due to we used the "of_property_read_u32" interfaces, when this
-	 * property isn't present, the "video_info" can keep the original
-	 * values and wouldn't be modified.
-	 */
-	of_property_read_u32(dp_node, "samsung,color-space",
-			     &video->color_space);
-	of_property_read_u32(dp_node, "samsung,dynamic-range",
-			     &video->dynamic_range);
-	of_property_read_u32(dp_node, "samsung,ycbcr-coeff",
-			     &video->ycbcr_coeff);
-	of_property_read_u32(dp_node, "samsung,color-depth",
-			     &video->color_depth);
-	if (of_property_read_bool(dp_node, "hsync-active-high"))
-		video->h_sync_polarity = true;
-	if (of_property_read_bool(dp_node, "vsync-active-high"))
-		video->v_sync_polarity = true;
-	if (of_property_read_bool(dp_node, "interlaced"))
-		video->interlaced = true;
-}
-
 static const struct drm_bridge_funcs analogix_dp_bridge_funcs = {
 	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
@@ -1290,7 +1294,6 @@ static const struct drm_bridge_funcs analogix_dp_bridge_funcs = {
 	.atomic_enable = analogix_dp_bridge_atomic_enable,
 	.atomic_disable = analogix_dp_bridge_atomic_disable,
 	.atomic_post_disable = analogix_dp_bridge_atomic_post_disable,
-	.mode_set = analogix_dp_bridge_mode_set,
 	.attach = analogix_dp_bridge_attach,
 };
 
-- 
2.34.1



From damon.ding at rock-chips.com  Wed Dec 17 01:33:08 2025
From: damon.ding at rock-chips.com (Damon Ding)
Date: Wed, 17 Dec 2025 17:33:08 +0800
Subject: [PATCH v8 05/18] drm/bridge: Move legacy bridge driver out of imx directory for multi-platform use
In-Reply-To: <20251217093321.3108939-1-damon.ding@rock-chips.com>
References: <20251217093321.3108939-1-damon.ding@rock-chips.com>
Message-ID: <20251217093321.3108939-6-damon.ding@rock-chips.com>

As suggested by Dmitry, the DRM legacy bridge driver can be pulled
out of imx/ subdir for multi-platform use. The driver is also renamed
to make it more generic and suitable for platforms other than i.MX.

Signed-off-by: Damon Ding <damon.ding at rock-chips.com>
Suggested-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Tested-by: Marek Szyprowski <m.szyprowski at samsung.com>

---

Changes in v7:
- Rename legacy-bridge to of-display-mode-bridge.
- Remove unnecessary API drm_bridge_is_legacy().
---
 drivers/gpu/drm/bridge/Kconfig                | 10 ++
 drivers/gpu/drm/bridge/Makefile               |  1 +
 drivers/gpu/drm/bridge/imx/Kconfig            | 10 --
 drivers/gpu/drm/bridge/imx/Makefile           |  1 -
 .../gpu/drm/bridge/imx/imx-legacy-bridge.c    | 91 ------------------
 .../gpu/drm/bridge/of-display-mode-bridge.c   | 93 +++++++++++++++++++
 drivers/gpu/drm/imx/ipuv3/Kconfig             |  4 +-
 drivers/gpu/drm/imx/ipuv3/imx-ldb.c           |  6 +-
 drivers/gpu/drm/imx/ipuv3/parallel-display.c  |  5 +-
 include/drm/bridge/imx.h                      | 17 ----
 include/drm/bridge/of-display-mode-bridge.h   | 17 ++++
 11 files changed, 129 insertions(+), 126 deletions(-)
 delete mode 100644 drivers/gpu/drm/bridge/imx/imx-legacy-bridge.c
 create mode 100644 drivers/gpu/drm/bridge/of-display-mode-bridge.c
 delete mode 100644 include/drm/bridge/imx.h
 create mode 100644 include/drm/bridge/of-display-mode-bridge.h

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index a250afd8d662..65784f6db797 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -244,6 +244,16 @@ config DRM_NXP_PTN3460
 	help
 	  NXP PTN3460 eDP-LVDS bridge chip driver.
 
+config DRM_OF_DISPLAY_MODE_BRIDGE
+	tristate
+	depends on DRM_BRIDGE && OF
+	help
+	  This is a DRM bridge implementation that uses of_get_drm_display_mode
+	  to acquire display mode.
+
+	  Newer designs should not use this bridge and should use proper panel
+	  driver instead.
+
 config DRM_PARADE_PS8622
 	tristate "Parade eDP/LVDS bridge"
 	depends on OF
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index c7dc03182e59..41146faef91a 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o
 obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o
 obj-$(CONFIG_DRM_MICROCHIP_LVDS_SERIALIZER) += microchip-lvds.o
 obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
+obj-$(CONFIG_DRM_OF_DISPLAY_MODE_BRIDGE) += of-display-mode-bridge.o
 obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
 obj-$(CONFIG_DRM_PARADE_PS8640) += parade-ps8640.o
 obj-$(CONFIG_DRM_SAMSUNG_DSIM) += samsung-dsim.o
diff --git a/drivers/gpu/drm/bridge/imx/Kconfig b/drivers/gpu/drm/bridge/imx/Kconfig
index b9028a5e5a06..8877b9789868 100644
--- a/drivers/gpu/drm/bridge/imx/Kconfig
+++ b/drivers/gpu/drm/bridge/imx/Kconfig
@@ -3,16 +3,6 @@ if ARCH_MXC || COMPILE_TEST
 config DRM_IMX_LDB_HELPER
 	tristate
 
-config DRM_IMX_LEGACY_BRIDGE
-	tristate
-	depends on DRM_IMX
-	help
-	  This is a DRM bridge implementation for the DRM i.MX IPUv3 driver,
-	  that uses of_get_drm_display_mode to acquire display mode.
-
-	  Newer designs should not use this bridge and should use proper panel
-	  driver instead.
-
 config DRM_IMX8MP_DW_HDMI_BRIDGE
 	tristate "Freescale i.MX8MP HDMI-TX bridge support"
 	depends on OF
diff --git a/drivers/gpu/drm/bridge/imx/Makefile b/drivers/gpu/drm/bridge/imx/Makefile
index 8d01fda25451..69d9f9abbe36 100644
--- a/drivers/gpu/drm/bridge/imx/Makefile
+++ b/drivers/gpu/drm/bridge/imx/Makefile
@@ -1,5 +1,4 @@
 obj-$(CONFIG_DRM_IMX_LDB_HELPER) += imx-ldb-helper.o
-obj-$(CONFIG_DRM_IMX_LEGACY_BRIDGE) += imx-legacy-bridge.o
 obj-$(CONFIG_DRM_IMX8MP_DW_HDMI_BRIDGE) += imx8mp-hdmi-tx.o
 obj-$(CONFIG_DRM_IMX8MP_HDMI_PAI) += imx8mp-hdmi-pai.o
 obj-$(CONFIG_DRM_IMX8MP_HDMI_PVI) += imx8mp-hdmi-pvi.o
diff --git a/drivers/gpu/drm/bridge/imx/imx-legacy-bridge.c b/drivers/gpu/drm/bridge/imx/imx-legacy-bridge.c
deleted file mode 100644
index 0e31d5000e7c..000000000000
--- a/drivers/gpu/drm/bridge/imx/imx-legacy-bridge.c
+++ /dev/null
@@ -1,91 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Freescale i.MX drm driver
- *
- * bridge driver for legacy DT bindings, utilizing display-timings node
- */
-
-#include <linux/export.h>
-
-#include <drm/drm_bridge.h>
-#include <drm/drm_modes.h>
-#include <drm/drm_probe_helper.h>
-#include <drm/bridge/imx.h>
-
-#include <video/of_display_timing.h>
-#include <video/of_videomode.h>
-
-struct imx_legacy_bridge {
-	struct drm_bridge base;
-
-	struct drm_display_mode mode;
-	u32 bus_flags;
-};
-
-#define to_imx_legacy_bridge(bridge)	container_of(bridge, struct imx_legacy_bridge, base)
-
-static int imx_legacy_bridge_attach(struct drm_bridge *bridge,
-				    struct drm_encoder *encoder,
-				    enum drm_bridge_attach_flags flags)
-{
-	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
-		return -EINVAL;
-
-	return 0;
-}
-
-static int imx_legacy_bridge_get_modes(struct drm_bridge *bridge,
-				       struct drm_connector *connector)
-{
-	struct imx_legacy_bridge *imx_bridge = to_imx_legacy_bridge(bridge);
-	int ret;
-
-	ret = drm_connector_helper_get_modes_fixed(connector, &imx_bridge->mode);
-	if (ret)
-		return ret;
-
-	connector->display_info.bus_flags = imx_bridge->bus_flags;
-
-	return 0;
-}
-
-struct drm_bridge_funcs imx_legacy_bridge_funcs = {
-	.attach = imx_legacy_bridge_attach,
-	.get_modes = imx_legacy_bridge_get_modes,
-};
-
-struct drm_bridge *devm_imx_drm_legacy_bridge(struct device *dev,
-					      struct device_node *np,
-					      int type)
-{
-	struct imx_legacy_bridge *imx_bridge;
-	int ret;
-
-	imx_bridge = devm_drm_bridge_alloc(dev, struct imx_legacy_bridge,
-					   base, &imx_legacy_bridge_funcs);
-	if (IS_ERR(imx_bridge))
-		return ERR_CAST(imx_bridge);
-
-	ret = of_get_drm_display_mode(np,
-				      &imx_bridge->mode,
-				      &imx_bridge->bus_flags,
-				      OF_USE_NATIVE_MODE);
-	if (ret)
-		return ERR_PTR(ret);
-
-	imx_bridge->mode.type |= DRM_MODE_TYPE_DRIVER;
-
-	imx_bridge->base.of_node = np;
-	imx_bridge->base.ops = DRM_BRIDGE_OP_MODES;
-	imx_bridge->base.type = type;
-
-	ret = devm_drm_bridge_add(dev, &imx_bridge->base);
-	if (ret)
-		return ERR_PTR(ret);
-
-	return &imx_bridge->base;
-}
-EXPORT_SYMBOL_GPL(devm_imx_drm_legacy_bridge);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Freescale i.MX DRM bridge driver for legacy DT bindings");
diff --git a/drivers/gpu/drm/bridge/of-display-mode-bridge.c b/drivers/gpu/drm/bridge/of-display-mode-bridge.c
new file mode 100644
index 000000000000..cb15713f3a79
--- /dev/null
+++ b/drivers/gpu/drm/bridge/of-display-mode-bridge.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2012 Sascha Hauer, Pengutronix
+ *
+ * bridge driver for legacy DT bindings, utilizing display-timings node
+ *
+ * Author: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
+ */
+
+#include <linux/export.h>
+
+#include <drm/drm_bridge.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/bridge/of-display-mode-bridge.h>
+
+#include <video/of_display_timing.h>
+#include <video/of_videomode.h>
+
+struct of_display_mode_bridge {
+	struct drm_bridge base;
+
+	struct drm_display_mode mode;
+	u32 bus_flags;
+};
+
+#define to_of_display_mode_bridge(bridge) container_of(bridge, struct of_display_mode_bridge, base)
+
+static int of_display_mode_bridge_attach(struct drm_bridge *bridge,
+					 struct drm_encoder *encoder,
+					 enum drm_bridge_attach_flags flags)
+{
+	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int of_display_mode_bridge_get_modes(struct drm_bridge *bridge,
+					    struct drm_connector *connector)
+{
+	struct of_display_mode_bridge *of_bridge = to_of_display_mode_bridge(bridge);
+	int ret;
+
+	ret = drm_connector_helper_get_modes_fixed(connector, &of_bridge->mode);
+	if (ret)
+		return ret;
+
+	connector->display_info.bus_flags = of_bridge->bus_flags;
+
+	return 0;
+}
+
+struct drm_bridge_funcs of_display_mode_bridge_funcs = {
+	.attach = of_display_mode_bridge_attach,
+	.get_modes = of_display_mode_bridge_get_modes,
+};
+
+struct drm_bridge *devm_drm_of_display_mode_bridge(struct device *dev,
+						   struct device_node *np,
+						   int type)
+{
+	struct of_display_mode_bridge *of_bridge;
+	int ret;
+
+	of_bridge = devm_drm_bridge_alloc(dev, struct of_display_mode_bridge,
+					  base, &of_display_mode_bridge_funcs);
+	if (IS_ERR(of_bridge))
+		return ERR_CAST(of_bridge);
+
+	ret = of_get_drm_display_mode(np,
+				      &of_bridge->mode,
+				      &of_bridge->bus_flags,
+				      OF_USE_NATIVE_MODE);
+	if (ret)
+		return ERR_PTR(ret);
+
+	of_bridge->mode.type |= DRM_MODE_TYPE_DRIVER;
+
+	of_bridge->base.of_node = np;
+	of_bridge->base.ops = DRM_BRIDGE_OP_MODES;
+	of_bridge->base.type = type;
+
+	ret = devm_drm_bridge_add(dev, &of_bridge->base);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return &of_bridge->base;
+}
+EXPORT_SYMBOL_GPL(devm_drm_of_display_mode_bridge);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DRM bridge driver for legacy DT bindings");
diff --git a/drivers/gpu/drm/imx/ipuv3/Kconfig b/drivers/gpu/drm/imx/ipuv3/Kconfig
index acaf25089001..e98f8d35efaa 100644
--- a/drivers/gpu/drm/imx/ipuv3/Kconfig
+++ b/drivers/gpu/drm/imx/ipuv3/Kconfig
@@ -15,7 +15,7 @@ config DRM_IMX_PARALLEL_DISPLAY
 	depends on DRM_IMX
 	select DRM_BRIDGE
 	select DRM_BRIDGE_CONNECTOR
-	select DRM_IMX_LEGACY_BRIDGE
+	select DRM_OF_DISPLAY_MODE_BRIDGE
 	select DRM_PANEL_BRIDGE
 	select VIDEOMODE_HELPERS
 
@@ -36,7 +36,7 @@ config DRM_IMX_LDB
 	select DRM_BRIDGE
 	select DRM_BRIDGE_CONNECTOR
 	select DRM_PANEL_BRIDGE
-	select DRM_IMX_LEGACY_BRIDGE
+	select DRM_OF_DISPLAY_MODE_BRIDGE
 	help
 	  Choose this to enable the internal LVDS Display Bridge (LDB)
 	  found on i.MX53 and i.MX6 processors.
diff --git a/drivers/gpu/drm/imx/ipuv3/imx-ldb.c b/drivers/gpu/drm/imx/ipuv3/imx-ldb.c
index 626d410d9150..730caf883e83 100644
--- a/drivers/gpu/drm/imx/ipuv3/imx-ldb.c
+++ b/drivers/gpu/drm/imx/ipuv3/imx-ldb.c
@@ -28,7 +28,7 @@
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
 #include <drm/drm_simple_kms_helper.h>
-#include <drm/bridge/imx.h>
+#include <drm/bridge/of-display-mode-bridge.h>
 
 #include "imx-drm.h"
 
@@ -605,8 +605,8 @@ static int imx_ldb_probe(struct platform_device *pdev)
 		 * checking the bus_format property.
 		 */
 		if (!channel->bridge) {
-			channel->bridge = devm_imx_drm_legacy_bridge(dev, child,
-								     DRM_MODE_CONNECTOR_LVDS);
+			channel->bridge = devm_drm_of_display_mode_bridge(dev, child,
+									  DRM_MODE_CONNECTOR_LVDS);
 			if (IS_ERR(channel->bridge)) {
 				ret = PTR_ERR(channel->bridge);
 				goto free_child;
diff --git a/drivers/gpu/drm/imx/ipuv3/parallel-display.c b/drivers/gpu/drm/imx/ipuv3/parallel-display.c
index 61fab3698807..b17d2b06b0e6 100644
--- a/drivers/gpu/drm/imx/ipuv3/parallel-display.c
+++ b/drivers/gpu/drm/imx/ipuv3/parallel-display.c
@@ -19,7 +19,7 @@
 #include <drm/drm_of.h>
 #include <drm/drm_probe_helper.h>
 #include <drm/drm_simple_kms_helper.h>
-#include <drm/bridge/imx.h>
+#include <drm/bridge/of-display-mode-bridge.h>
 
 #include "imx-drm.h"
 
@@ -235,7 +235,8 @@ static int imx_pd_probe(struct platform_device *pdev)
 	/* port at 1 is the output port */
 	imxpd->next_bridge = devm_drm_of_get_bridge(dev, np, 1, 0);
 	if (imxpd->next_bridge == ERR_PTR(-ENODEV))
-		imxpd->next_bridge = devm_imx_drm_legacy_bridge(dev, np, DRM_MODE_CONNECTOR_DPI);
+		imxpd->next_bridge = devm_drm_of_display_mode_bridge(dev, np,
+								     DRM_MODE_CONNECTOR_DPI);
 	if (IS_ERR(imxpd->next_bridge)) {
 		ret = PTR_ERR(imxpd->next_bridge);
 		return ret;
diff --git a/include/drm/bridge/imx.h b/include/drm/bridge/imx.h
deleted file mode 100644
index b93f719fe0e7..000000000000
--- a/include/drm/bridge/imx.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2012 Sascha Hauer, Pengutronix
- */
-
-#ifndef DRM_IMX_BRIDGE_H
-#define DRM_IMX_BRIDGE_H
-
-struct device;
-struct device_node;
-struct drm_bridge;
-
-struct drm_bridge *devm_imx_drm_legacy_bridge(struct device *dev,
-					      struct device_node *np,
-					      int type);
-
-#endif
diff --git a/include/drm/bridge/of-display-mode-bridge.h b/include/drm/bridge/of-display-mode-bridge.h
new file mode 100644
index 000000000000..89fcfedf68d8
--- /dev/null
+++ b/include/drm/bridge/of-display-mode-bridge.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2012 Sascha Hauer, Pengutronix
+ */
+
+#ifndef DRM_OF_DISPLAY_MODE_BRIDGE_H
+#define DRM_OF_DISPLAY_MODE_BRIDGE_H
+
+struct device;
+struct device_node;
+struct drm_bridge;
+
+struct drm_bridge *devm_drm_of_display_mode_bridge(struct device *dev,
+						   struct device_node *np,
+						   int type);
+
+#endif
-- 
2.34.1



From damon.ding at rock-chips.com  Wed Dec 17 01:33:07 2025
From: damon.ding at rock-chips.com (Damon Ding)
Date: Wed, 17 Dec 2025 17:33:07 +0800
Subject: [PATCH v8 04/18] drm/bridge: analogix_dp: Add &analogix_dp_plat_data.next_bridge
In-Reply-To: <20251217093321.3108939-1-damon.ding@rock-chips.com>
References: <20251217093321.3108939-1-damon.ding@rock-chips.com>
Message-ID: <20251217093321.3108939-5-damon.ding@rock-chips.com>

In order to move the panel/bridge parsing and attachmenet to the
Analogix side, add component struct drm_bridge *next_bridge to
platform data struct analogix_dp_plat_data.

The movement makes sense because the panel/bridge should logically
be positioned behind the Analogix bridge in the display pipeline.

Signed-off-by: Damon Ding <damon.ding at rock-chips.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Tested-by: Marek Szyprowski <m.szyprowski at samsung.com>

---

Changes in v4:
- Rename the &analogix_dp_plat_data.bridge to
  &analogix_dp_plat_data.next_bridge
---
 include/drm/bridge/analogix_dp.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h
index cf17646c1310..582357c20640 100644
--- a/include/drm/bridge/analogix_dp.h
+++ b/include/drm/bridge/analogix_dp.h
@@ -27,6 +27,7 @@ static inline bool is_rockchip(enum analogix_dp_devtype type)
 struct analogix_dp_plat_data {
 	enum analogix_dp_devtype dev_type;
 	struct drm_panel *panel;
+	struct drm_bridge *next_bridge;
 	struct drm_encoder *encoder;
 	struct drm_connector *connector;
 	bool skip_connector;
-- 
2.34.1



From damon.ding at rock-chips.com  Wed Dec 17 01:33:09 2025
From: damon.ding at rock-chips.com (Damon Ding)
Date: Wed, 17 Dec 2025 17:33:09 +0800
Subject: [PATCH v8 06/18] drm/exynos: exynos_dp: Remove &exynos_dp_device.ptn_bridge
In-Reply-To: <20251217093321.3108939-1-damon.ding@rock-chips.com>
References: <20251217093321.3108939-1-damon.ding@rock-chips.com>
Message-ID: <20251217093321.3108939-7-damon.ding@rock-chips.com>

Use &analogix_dp_plat_data.bridge instead of &exynos_dp_device.ptn_bridge
directly.

Signed-off-by: Damon Ding <damon.ding at rock-chips.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Tested-by: Marek Szyprowski <m.szyprowski at samsung.com>

------

Changes in v3:
- Fix the typographical error for &dp->plat_data.bridge.

Changes in v4:
- Rename the &analogix_dp_plat_data.bridge to
  &analogix_dp_plat_data.next_bridge.
---
 drivers/gpu/drm/exynos/exynos_dp.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index 5bcf41e0bd04..f469ac5b3c2a 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -36,7 +36,6 @@
 struct exynos_dp_device {
 	struct drm_encoder         encoder;
 	struct drm_connector       *connector;
-	struct drm_bridge          *ptn_bridge;
 	struct drm_device          *drm_dev;
 	struct device              *dev;
 
@@ -106,8 +105,8 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
 	dp->connector = connector;
 
 	/* Pre-empt DP connector creation if there's a bridge */
-	if (dp->ptn_bridge) {
-		ret = drm_bridge_attach(&dp->encoder, dp->ptn_bridge, bridge,
+	if (plat_data->next_bridge) {
+		ret = drm_bridge_attach(&dp->encoder, plat_data->next_bridge, bridge,
 					0);
 		if (ret)
 			return ret;
@@ -155,7 +154,7 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 
 	dp->drm_dev = drm_dev;
 
-	if (!dp->plat_data.panel && !dp->ptn_bridge) {
+	if (!dp->plat_data.panel && !dp->plat_data.next_bridge) {
 		ret = exynos_dp_dt_parse_panel(dp);
 		if (ret)
 			return ret;
@@ -232,6 +231,7 @@ static int exynos_dp_probe(struct platform_device *pdev)
 
 	/* The remote port can be either a panel or a bridge */
 	dp->plat_data.panel = panel;
+	dp->plat_data.next_bridge = bridge;
 	dp->plat_data.dev_type = EXYNOS_DP;
 	dp->plat_data.power_on = exynos_dp_poweron;
 	dp->plat_data.power_off = exynos_dp_poweroff;
@@ -239,8 +239,6 @@ static int exynos_dp_probe(struct platform_device *pdev)
 	dp->plat_data.get_modes = exynos_dp_get_modes;
 	dp->plat_data.skip_connector = !!bridge;
 
-	dp->ptn_bridge = bridge;
-
 out:
 	dp->adp = analogix_dp_probe(dev, &dp->plat_data);
 	if (IS_ERR(dp->adp))
-- 
2.34.1



From damon.ding at rock-chips.com  Wed Dec 17 01:33:10 2025
From: damon.ding at rock-chips.com (Damon Ding)
Date: Wed, 17 Dec 2025 17:33:10 +0800
Subject: [PATCH v8 07/18] drm/exynos: exynos_dp: Remove unused &exynos_dp_device.connector
In-Reply-To: <20251217093321.3108939-1-damon.ding@rock-chips.com>
References: <20251217093321.3108939-1-damon.ding@rock-chips.com>
Message-ID: <20251217093321.3108939-8-damon.ding@rock-chips.com>

The &exynos_dp_device.connector is assigned in exynos_dp_bridge_attach()
but never used. It should make sense to remove it.

Signed-off-by: Damon Ding <damon.ding at rock-chips.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Tested-by: Marek Szyprowski <m.szyprowski at samsung.com>

---

Changes in v5:
- Fix the 'drm/bridge' to 'drm/exynos' in commit message.
---
 drivers/gpu/drm/exynos/exynos_dp.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index f469ac5b3c2a..e20513164032 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -35,7 +35,6 @@
 
 struct exynos_dp_device {
 	struct drm_encoder         encoder;
-	struct drm_connector       *connector;
 	struct drm_device          *drm_dev;
 	struct device              *dev;
 
@@ -102,8 +101,6 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
 	struct exynos_dp_device *dp = to_dp(plat_data);
 	int ret;
 
-	dp->connector = connector;
-
 	/* Pre-empt DP connector creation if there's a bridge */
 	if (plat_data->next_bridge) {
 		ret = drm_bridge_attach(&dp->encoder, plat_data->next_bridge, bridge,
-- 
2.34.1



From damon.ding at rock-chips.com  Wed Dec 17 01:33:11 2025
From: damon.ding at rock-chips.com (Damon Ding)
Date: Wed, 17 Dec 2025 17:33:11 +0800
Subject: [PATCH v8 08/18] drm/exynos: exynos_dp: Apply of-display-mode-bridge to parse the display-timings node
In-Reply-To: <20251217093321.3108939-1-damon.ding@rock-chips.com>
References: <20251217093321.3108939-1-damon.ding@rock-chips.com>
Message-ID: <20251217093321.3108939-9-damon.ding@rock-chips.com>

If there is neither a panel nor a bridge, the display timing can be
parsed from the display-timings node under the dp node.

In order to get rid of &analogix_dp_plat_data.get_modes() and make
the codes more consistent, apply DRM of-display-mode-bridge to parse
display timings.

Signed-off-by: Damon Ding <damon.ding at rock-chips.com>
Tested-by: Marek Szyprowski <m.szyprowski at samsung.com>

------

Changes in v6:
- Apply DRM legacy bridge to parse display timings instead of
  implementing the same codes only for Exynos DP.

Changes in v7:
- Use temporary flag &exynos_dp_device.has_of_bridge, which will be
  removed in the following patch, instead of applying API
  drm_bridge_is_legacy().
- Remove exynos_dp_legacy_bridge_init() and inline API
  devm_drm_of_display_mode_bridge().
---
 drivers/gpu/drm/exynos/Kconfig     |  1 +
 drivers/gpu/drm/exynos/exynos_dp.c | 66 ++++++++----------------------
 2 files changed, 17 insertions(+), 50 deletions(-)

diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 0d13828e7d9e..380d9a8ce259 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -72,6 +72,7 @@ config DRM_EXYNOS_DP
 	select DRM_ANALOGIX_DP
 	select DRM_DISPLAY_DP_HELPER
 	default DRM_EXYNOS
+	select DRM_OF_DISPLAY_MODE_BRIDGE
 	select DRM_PANEL
 	help
 	  This enables support for DP device.
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index e20513164032..ac16138a22fe 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -19,6 +19,7 @@
 #include <video/videomode.h>
 
 #include <drm/bridge/analogix_dp.h>
+#include <drm/bridge/of-display-mode-bridge.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
@@ -38,9 +39,10 @@ struct exynos_dp_device {
 	struct drm_device          *drm_dev;
 	struct device              *dev;
 
-	struct videomode           vm;
 	struct analogix_dp_device *adp;
 	struct analogix_dp_plat_data plat_data;
+
+	bool has_of_bridge;
 };
 
 static int exynos_dp_crtc_clock_enable(struct analogix_dp_plat_data *plat_data,
@@ -67,44 +69,20 @@ static int exynos_dp_poweroff(struct analogix_dp_plat_data *plat_data)
 	return exynos_dp_crtc_clock_enable(plat_data, false);
 }
 
-static int exynos_dp_get_modes(struct analogix_dp_plat_data *plat_data,
-			       struct drm_connector *connector)
-{
-	struct exynos_dp_device *dp = to_dp(plat_data);
-	struct drm_display_mode *mode;
-
-	if (dp->plat_data.panel)
-		return 0;
-
-	mode = drm_mode_create(connector->dev);
-	if (!mode) {
-		DRM_DEV_ERROR(dp->dev,
-			      "failed to create a new display mode.\n");
-		return 0;
-	}
-
-	drm_display_mode_from_videomode(&dp->vm, mode);
-	connector->display_info.width_mm = mode->width_mm;
-	connector->display_info.height_mm = mode->height_mm;
-
-	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
-	drm_mode_set_name(mode);
-	drm_mode_probed_add(connector, mode);
-
-	return 1;
-}
-
 static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
 				   struct drm_bridge *bridge,
 				   struct drm_connector *connector)
 {
 	struct exynos_dp_device *dp = to_dp(plat_data);
+	enum drm_bridge_attach_flags flags = 0;
 	int ret;
 
 	/* Pre-empt DP connector creation if there's a bridge */
 	if (plat_data->next_bridge) {
-		ret = drm_bridge_attach(&dp->encoder, plat_data->next_bridge, bridge,
-					0);
+		if (dp->has_of_bridge)
+			flags = DRM_BRIDGE_ATTACH_NO_CONNECTOR;
+
+		ret = drm_bridge_attach(&dp->encoder, plat_data->next_bridge, bridge, flags);
 		if (ret)
 			return ret;
 	}
@@ -129,19 +107,6 @@ static const struct drm_encoder_helper_funcs exynos_dp_encoder_helper_funcs = {
 	.disable = exynos_dp_nop,
 };
 
-static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp)
-{
-	int ret;
-
-	ret = of_get_videomode(dp->dev->of_node, &dp->vm, OF_USE_NATIVE_MODE);
-	if (ret) {
-		DRM_DEV_ERROR(dp->dev,
-			      "failed: of_get_videomode() : %d\n", ret);
-		return ret;
-	}
-	return 0;
-}
-
 static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 {
 	struct exynos_dp_device *dp = dev_get_drvdata(dev);
@@ -151,12 +116,6 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 
 	dp->drm_dev = drm_dev;
 
-	if (!dp->plat_data.panel && !dp->plat_data.next_bridge) {
-		ret = exynos_dp_dt_parse_panel(dp);
-		if (ret)
-			return ret;
-	}
-
 	drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_TMDS);
 
 	drm_encoder_helper_add(encoder, &exynos_dp_encoder_helper_funcs);
@@ -223,6 +182,14 @@ static int exynos_dp_probe(struct platform_device *pdev)
 	}
 
 	ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &panel, &bridge);
+	if (ret == -ENODEV) {
+		dp->plat_data.next_bridge = devm_drm_of_display_mode_bridge(dp->dev,
+									dp->dev->of_node,
+									DRM_MODE_CONNECTOR_eDP);
+		ret = IS_ERR(dp->plat_data.next_bridge) ? PTR_ERR(dp->plat_data.next_bridge) : 0;
+		if (!ret)
+			dp->has_of_bridge = true;
+	}
 	if (ret)
 		return ret;
 
@@ -233,7 +200,6 @@ static int exynos_dp_probe(struct platform_device *pdev)
 	dp->plat_data.power_on = exynos_dp_poweron;
 	dp->plat_data.power_off = exynos_dp_poweroff;
 	dp->plat_data.attach = exynos_dp_bridge_attach;
-	dp->plat_data.get_modes = exynos_dp_get_modes;
 	dp->plat_data.skip_connector = !!bridge;
 
 out:
-- 
2.34.1



From damon.ding at rock-chips.com  Wed Dec 17 01:33:12 2025
From: damon.ding at rock-chips.com (Damon Ding)
Date: Wed, 17 Dec 2025 17:33:12 +0800
Subject: [PATCH v8 09/18] drm/bridge: analogix_dp: Remove redundant &analogix_dp_plat_data.skip_connector
In-Reply-To: <20251217093321.3108939-1-damon.ding@rock-chips.com>
References: <20251217093321.3108939-1-damon.ding@rock-chips.com>
Message-ID: <20251217093321.3108939-10-damon.ding@rock-chips.com>

The &analogix_dp_plat_data.skip_connector related check can be replaced
by &analogix_dp_plat_data.bridge.

Signed-off-by: Damon Ding <damon.ding at rock-chips.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Tested-by: Marek Szyprowski <m.szyprowski at samsung.com>

------

Changes in v3:
- Squash the Exynos side commit and the Analogix side commit together.

Changes in v4:
- Rename the &analogix_dp_plat_data.bridge to
  &analogix_dp_plat_data.next_bridge.
---
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 2 +-
 drivers/gpu/drm/exynos/exynos_dp.c                 | 1 -
 include/drm/bridge/analogix_dp.h                   | 1 -
 3 files changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 3caa47d31649..4606ecc3f480 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -959,7 +959,7 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge,
 		return -EINVAL;
 	}
 
-	if (!dp->plat_data->skip_connector) {
+	if (!dp->plat_data->next_bridge) {
 		connector = &dp->connector;
 		connector->polled = DRM_CONNECTOR_POLL_HPD;
 
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index ac16138a22fe..1eeb0b15f99a 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -200,7 +200,6 @@ static int exynos_dp_probe(struct platform_device *pdev)
 	dp->plat_data.power_on = exynos_dp_poweron;
 	dp->plat_data.power_off = exynos_dp_poweroff;
 	dp->plat_data.attach = exynos_dp_bridge_attach;
-	dp->plat_data.skip_connector = !!bridge;
 
 out:
 	dp->adp = analogix_dp_probe(dev, &dp->plat_data);
diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h
index 582357c20640..f06da105d8f2 100644
--- a/include/drm/bridge/analogix_dp.h
+++ b/include/drm/bridge/analogix_dp.h
@@ -30,7 +30,6 @@ struct analogix_dp_plat_data {
 	struct drm_bridge *next_bridge;
 	struct drm_encoder *encoder;
 	struct drm_connector *connector;
-	bool skip_connector;
 
 	int (*power_on)(struct analogix_dp_plat_data *);
 	int (*power_off)(struct analogix_dp_plat_data *);
-- 
2.34.1



From damon.ding at rock-chips.com  Wed Dec 17 01:33:13 2025
From: damon.ding at rock-chips.com (Damon Ding)
Date: Wed, 17 Dec 2025 17:33:13 +0800
Subject: [PATCH v8 10/18] drm/bridge: analogix_dp: Move the color format check to .atomic_check() for Rockchip platforms
In-Reply-To: <20251217093321.3108939-1-damon.ding@rock-chips.com>
References: <20251217093321.3108939-1-damon.ding@rock-chips.com>
Message-ID: <20251217093321.3108939-11-damon.ding@rock-chips.com>

For Rockchip platforms, the YUV color formats are currently unsupported.
This compatibility check was previously implemented in
&analogix_dp_plat_data.get_modes().

Moving color format check to &drm_connector_helper_funcs.atomic_check()
would get rid of &analogix_dp_plat_data.get_modes() and be more
reasonable than before.

Signed-off-by: Damon Ding <damon.ding at rock-chips.com>
Tested-by: Marek Szyprowski <m.szyprowski at samsung.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
---
 .../gpu/drm/bridge/analogix/analogix_dp_core.c | 11 +++++++++++
 .../gpu/drm/rockchip/analogix_dp-rockchip.c    | 18 ------------------
 2 files changed, 11 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 4606ecc3f480..5bf41b364aba 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -894,8 +894,19 @@ static int analogix_dp_atomic_check(struct drm_connector *connector,
 				    struct drm_atomic_state *state)
 {
 	struct analogix_dp_device *dp = to_dp(connector);
+	struct drm_display_info *di = &connector->display_info;
 	struct drm_connector_state *conn_state;
 	struct drm_crtc_state *crtc_state;
+	u32 mask = DRM_COLOR_FORMAT_YCBCR444 | DRM_COLOR_FORMAT_YCBCR422;
+
+	if (is_rockchip(dp->plat_data->dev_type)) {
+		if ((di->color_formats & mask)) {
+			DRM_DEBUG_KMS("Swapping display color format from YUV to RGB\n");
+			di->color_formats &= ~mask;
+			di->color_formats |= DRM_COLOR_FORMAT_RGB444;
+			di->bpc = 8;
+		}
+	}
 
 	conn_state = drm_atomic_get_new_connector_state(state, connector);
 	if (WARN_ON(!conn_state))
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index fdab71d51e2a..70fe5ae69e2e 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -166,23 +166,6 @@ static int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data)
 	return 0;
 }
 
-static int rockchip_dp_get_modes(struct analogix_dp_plat_data *plat_data,
-				 struct drm_connector *connector)
-{
-	struct drm_display_info *di = &connector->display_info;
-	/* VOP couldn't output YUV video format for eDP rightly */
-	u32 mask = DRM_COLOR_FORMAT_YCBCR444 | DRM_COLOR_FORMAT_YCBCR422;
-
-	if ((di->color_formats & mask)) {
-		DRM_DEBUG_KMS("Swapping display color format from YUV to RGB\n");
-		di->color_formats &= ~mask;
-		di->color_formats |= DRM_COLOR_FORMAT_RGB444;
-		di->bpc = 8;
-	}
-
-	return 0;
-}
-
 static bool
 rockchip_dp_drm_encoder_mode_fixup(struct drm_encoder *encoder,
 				   const struct drm_display_mode *mode,
@@ -481,7 +464,6 @@ static int rockchip_dp_probe(struct platform_device *pdev)
 	dp->plat_data.dev_type = dp->data->chip_type;
 	dp->plat_data.power_on = rockchip_dp_poweron;
 	dp->plat_data.power_off = rockchip_dp_powerdown;
-	dp->plat_data.get_modes = rockchip_dp_get_modes;
 
 	ret = rockchip_dp_of_probe(dp);
 	if (ret < 0)
-- 
2.34.1



From damon.ding at rock-chips.com  Wed Dec 17 01:33:14 2025
From: damon.ding at rock-chips.com (Damon Ding)
Date: Wed, 17 Dec 2025 17:33:14 +0800
Subject: [PATCH v8 11/18] drm/bridge: analogix_dp: Remove unused &analogix_dp_plat_data.get_modes()
In-Reply-To: <20251217093321.3108939-1-damon.ding@rock-chips.com>
References: <20251217093321.3108939-1-damon.ding@rock-chips.com>
Message-ID: <20251217093321.3108939-12-damon.ding@rock-chips.com>

The callback &analogix_dp_plat_data.get_modes() is not implemented
by either Rockchip side or Exynos side.

Signed-off-by: Damon Ding <damon.ding at rock-chips.com>
Tested-by: Marek Szyprowski <m.szyprowski at samsung.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
---
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 3 ---
 include/drm/bridge/analogix_dp.h                   | 2 --
 2 files changed, 5 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 5bf41b364aba..b0bc96693fdb 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -875,9 +875,6 @@ static int analogix_dp_get_modes(struct drm_connector *connector)
 		}
 	}
 
-	if (dp->plat_data->get_modes)
-		num_modes += dp->plat_data->get_modes(dp->plat_data, connector);
-
 	return num_modes;
 }
 
diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h
index f06da105d8f2..3301392eda5f 100644
--- a/include/drm/bridge/analogix_dp.h
+++ b/include/drm/bridge/analogix_dp.h
@@ -35,8 +35,6 @@ struct analogix_dp_plat_data {
 	int (*power_off)(struct analogix_dp_plat_data *);
 	int (*attach)(struct analogix_dp_plat_data *, struct drm_bridge *,
 		      struct drm_connector *);
-	int (*get_modes)(struct analogix_dp_plat_data *,
-			 struct drm_connector *);
 };
 
 int analogix_dp_resume(struct analogix_dp_device *dp);
-- 
2.34.1



From damon.ding at rock-chips.com  Wed Dec 17 01:33:16 2025
From: damon.ding at rock-chips.com (Damon Ding)
Date: Wed, 17 Dec 2025 17:33:16 +0800
Subject: [PATCH v8 13/18] drm/bridge: analogix_dp: Add new API analogix_dp_finish_probe()
In-Reply-To: <20251217093321.3108939-1-damon.ding@rock-chips.com>
References: <20251217093321.3108939-1-damon.ding@rock-chips.com>
Message-ID: <20251217093321.3108939-14-damon.ding@rock-chips.com>

Since the panel/bridge should logically be positioned behind the
Analogix bridge in the display pipeline, it makes sense to handle
the panel/bridge parsing on the Analogix side. Therefore, we add
a new API analogix_dp_finish_probe(), which combines the panel/bridge
parsing with component addition, to do it.

Signed-off-by: Damon Ding <damon.ding at rock-chips.com>
Tested-by: Marek Szyprowski <m.szyprowski at samsung.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>

---

Changes in v4:
- Rename the &analogix_dp_plat_data.bridge to
  &analogix_dp_plat_data.next_bridge.
- Remame API analogix_dp_find_panel_or_bridge() to
  analogix_dp_finish_probe().

Changes in v5:
- Select DRM_DISPLAY_DP_AUX_BUS for DRM_ANALOGIX_DP.
---
 drivers/gpu/drm/bridge/analogix/Kconfig       |  1 +
 .../drm/bridge/analogix/analogix_dp_core.c    | 48 +++++++++++++++++++
 include/drm/bridge/analogix_dp.h              |  2 +
 3 files changed, 51 insertions(+)

diff --git a/drivers/gpu/drm/bridge/analogix/Kconfig b/drivers/gpu/drm/bridge/analogix/Kconfig
index 4846b2e9be7c..964122b5bd39 100644
--- a/drivers/gpu/drm/bridge/analogix/Kconfig
+++ b/drivers/gpu/drm/bridge/analogix/Kconfig
@@ -29,6 +29,7 @@ config DRM_ANALOGIX_ANX78XX
 config DRM_ANALOGIX_DP
 	tristate
 	depends on DRM
+	select DRM_DISPLAY_DP_AUX_BUS
 
 config DRM_ANALOGIX_ANX7625
 	tristate "Analogix Anx7625 MIPI to DP interface support"
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 81c6e81dd352..933f1843777f 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -20,12 +20,14 @@
 #include <linux/platform_device.h>
 
 #include <drm/bridge/analogix_dp.h>
+#include <drm/display/drm_dp_aux_bus.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_device.h>
 #include <drm/drm_edid.h>
+#include <drm/drm_of.h>
 #include <drm/drm_panel.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
@@ -1581,6 +1583,52 @@ struct drm_dp_aux *analogix_dp_get_aux(struct analogix_dp_device *dp)
 }
 EXPORT_SYMBOL_GPL(analogix_dp_get_aux);
 
+static int analogix_dp_aux_done_probing(struct drm_dp_aux *aux)
+{
+	struct analogix_dp_device *dp = to_dp(aux);
+	struct analogix_dp_plat_data *plat_data = dp->plat_data;
+	int port = plat_data->dev_type == EXYNOS_DP ? 0 : 1;
+	int ret;
+
+	/*
+	 * If drm_of_find_panel_or_bridge() returns -ENODEV, there may be no valid panel
+	 * or bridge nodes. The driver should go on for the driver-free bridge or the DP
+	 * mode applications.
+	 */
+	ret = drm_of_find_panel_or_bridge(dp->dev->of_node, port, 0,
+					  &plat_data->panel, &plat_data->next_bridge);
+	if (ret && ret != -ENODEV)
+		return ret;
+
+	return component_add(dp->dev, plat_data->ops);
+}
+
+int analogix_dp_finish_probe(struct analogix_dp_device *dp)
+{
+	int ret;
+
+	ret = devm_of_dp_aux_populate_bus(&dp->aux, analogix_dp_aux_done_probing);
+	if (ret) {
+		/*
+		 * If devm_of_dp_aux_populate_bus() returns -ENODEV, the done_probing() will
+		 * not be called because there are no EP devices. Then the callback function
+		 * analogix_dp_aux_done_probing() will be called directly in order to support
+		 * the other valid DT configurations.
+		 *
+		 * NOTE: The devm_of_dp_aux_populate_bus() is allowed to return -EPROBE_DEFER.
+		 */
+		if (ret != -ENODEV) {
+			dev_err(dp->dev, "failed to populate aux bus\n");
+			return ret;
+		}
+
+		return analogix_dp_aux_done_probing(&dp->aux);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_finish_probe);
+
 MODULE_AUTHOR("Jingoo Han <jg1.han at samsung.com>");
 MODULE_DESCRIPTION("Analogix DP Core Driver");
 MODULE_LICENSE("GPL v2");
diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h
index 3428ffff24c5..bae969dec63a 100644
--- a/include/drm/bridge/analogix_dp.h
+++ b/include/drm/bridge/analogix_dp.h
@@ -30,6 +30,7 @@ struct analogix_dp_plat_data {
 	struct drm_bridge *next_bridge;
 	struct drm_encoder *encoder;
 	struct drm_connector *connector;
+	const struct component_ops *ops;
 
 	int (*power_on)(struct analogix_dp_plat_data *);
 	int (*power_off)(struct analogix_dp_plat_data *);
@@ -49,5 +50,6 @@ int analogix_dp_stop_crc(struct drm_connector *connector);
 
 struct analogix_dp_plat_data *analogix_dp_aux_to_plat_data(struct drm_dp_aux *aux);
 struct drm_dp_aux *analogix_dp_get_aux(struct analogix_dp_device *dp);
+int analogix_dp_finish_probe(struct analogix_dp_device *dp);
 
 #endif /* _ANALOGIX_DP_H_ */
-- 
2.34.1



From damon.ding at rock-chips.com  Wed Dec 17 01:33:15 2025
From: damon.ding at rock-chips.com (Damon Ding)
Date: Wed, 17 Dec 2025 17:33:15 +0800
Subject: [PATCH v8 12/18] drm/bridge: analogix_dp: Apply drm_bridge_connector helper
In-Reply-To: <20251217093321.3108939-1-damon.ding@rock-chips.com>
References: <20251217093321.3108939-1-damon.ding@rock-chips.com>
Message-ID: <20251217093321.3108939-13-damon.ding@rock-chips.com>

Apply drm_bridge_connector helper for Analogix DP driver.

The following changes have been made:
- Apply drm_bridge_connector helper to get rid of &drm_connector_funcs
  and &drm_connector_helper_funcs.
- Remove unnecessary parameter struct drm_connector* for callback
  &analogix_dp_plat_data.attach.
- Remove &analogix_dp_device.connector.
- Convert analogix_dp_atomic_check()/analogix_dp_detect() to
  &drm_bridge_funcs.atomic_check()/&drm_bridge_funcs.detect().
- Split analogix_dp_get_modes() into &drm_bridge_funcs.get_modes() and
  &drm_bridge_funcs.edid_read().
- Set flag DRM_BRIDGE_ATTACH_NO_CONNECTOR for bridge attachment while
  binding. Meanwhile, make DRM_BRIDGE_ATTACH_NO_CONNECTOR unsuppported
  in analogix_dp_bridge_attach().
- Set &drm_bridge.ops according to different cases.

Signed-off-by: Damon Ding <damon.ding at rock-chips.com>
Tested-by: Marek Szyprowski <m.szyprowski at samsung.com>

------

Changes in v2:
- For &drm_bridge.ops, remove DRM_BRIDGE_OP_HPD and add
  DRM_BRIDGE_OP_EDID.
- Add analogix_dp_bridge_edid_read().
- Move &analogix_dp_plat_data.skip_connector deletion to the previous
  patches.

Changes in v3:
- Rebase with the new devm_drm_bridge_alloc() related commit
  48f05c3b4b70 ("drm/bridge: analogix_dp: Use devm_drm_bridge_alloc()
  API").
- Expand the commit message.
- Call drm_bridge_get_modes() in analogix_dp_bridge_get_modes() if the
  bridge is available.
- Remove unnecessary parameter struct drm_connector* for callback
  &analogix_dp_plat_data.attach.
- In order to decouple the connector driver and the bridge driver, move
  the bridge connector initilization to the Rockchip and Exynos sides.

Changes in v4:
- Expand analogix_dp_bridge_detect() parameters to &drm_bridge and
  &drm_connector.
- Rename the &analogix_dp_plat_data.bridge to
  &analogix_dp_plat_data.next_bridge.

Changes in v5:
- Set the flag fo drm_bridge_attach() to DRM_BRIDGE_ATTACH_NO_CONNECTOR
  for next bridge attachment of Exynos side.
- Distinguish the &drm_bridge->ops of Analogix bridge based on whether
  the downstream device is a panel, a bridge or neither.
- Remove the calls to &analogix_dp_plat_data.get_modes().

Changes in v6:
- Select DRM_BRIDGE_CONNECTOR for both Rockchip and Exynos sides.
- Remove unnecessary drm_bridge_get_modes() in
  analogix_dp_bridge_get_modes().
- Simplify analogix_dp_bridge_edid_read().
- If the next is a bridge, set DRM_BRIDGE_OP_DETECT and return
  connector_status_connected in analogix_dp_bridge_detect().
- Set flag DRM_BRIDGE_ATTACH_NO_CONNECTOR for bridge attachment while
  binding. Meanwhile, make DRM_BRIDGE_ATTACH_NO_CONNECTOR unsuppported
  in analogix_dp_bridge_attach().
- Simplify the check of bridge capabilities.

Changes in v7:
- Remove temporary flag &exynos_dp_device.has_of_bridge.
---
 .../drm/bridge/analogix/analogix_dp_core.c    | 148 ++++++++----------
 .../drm/bridge/analogix/analogix_dp_core.h    |   1 -
 drivers/gpu/drm/exynos/Kconfig                |   1 +
 drivers/gpu/drm/exynos/exynos_dp.c            |  29 ++--
 drivers/gpu/drm/rockchip/Kconfig              |   1 +
 .../gpu/drm/rockchip/analogix_dp-rockchip.c   |  11 +-
 include/drm/bridge/analogix_dp.h              |   3 +-
 7 files changed, 90 insertions(+), 104 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index b0bc96693fdb..81c6e81dd352 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -856,44 +856,32 @@ static int analogix_dp_disable_psr(struct analogix_dp_device *dp)
 	return analogix_dp_send_psr_spd(dp, &psr_vsc, true);
 }
 
-static int analogix_dp_get_modes(struct drm_connector *connector)
+static int analogix_dp_bridge_get_modes(struct drm_bridge *bridge, struct drm_connector *connector)
 {
-	struct analogix_dp_device *dp = to_dp(connector);
-	const struct drm_edid *drm_edid;
+	struct analogix_dp_device *dp = to_dp(bridge);
 	int num_modes = 0;
 
-	if (dp->plat_data->panel) {
+	if (dp->plat_data->panel)
 		num_modes += drm_panel_get_modes(dp->plat_data->panel, connector);
-	} else {
-		drm_edid = drm_edid_read_ddc(connector, &dp->aux.ddc);
-
-		drm_edid_connector_update(&dp->connector, drm_edid);
-
-		if (drm_edid) {
-			num_modes += drm_edid_connector_add_modes(&dp->connector);
-			drm_edid_free(drm_edid);
-		}
-	}
 
 	return num_modes;
 }
 
-static struct drm_encoder *
-analogix_dp_best_encoder(struct drm_connector *connector)
+static const struct drm_edid *analogix_dp_bridge_edid_read(struct drm_bridge *bridge,
+							   struct drm_connector *connector)
 {
-	struct analogix_dp_device *dp = to_dp(connector);
+	struct analogix_dp_device *dp = to_dp(bridge);
 
-	return dp->encoder;
+	return drm_edid_read_ddc(connector, &dp->aux.ddc);
 }
 
-
-static int analogix_dp_atomic_check(struct drm_connector *connector,
-				    struct drm_atomic_state *state)
+static int analogix_dp_bridge_atomic_check(struct drm_bridge *bridge,
+					   struct drm_bridge_state *bridge_state,
+					   struct drm_crtc_state *crtc_state,
+					   struct drm_connector_state *conn_state)
 {
-	struct analogix_dp_device *dp = to_dp(connector);
-	struct drm_display_info *di = &connector->display_info;
-	struct drm_connector_state *conn_state;
-	struct drm_crtc_state *crtc_state;
+	struct analogix_dp_device *dp = to_dp(bridge);
+	struct drm_display_info *di = &conn_state->connector->display_info;
 	u32 mask = DRM_COLOR_FORMAT_YCBCR444 | DRM_COLOR_FORMAT_YCBCR422;
 
 	if (is_rockchip(dp->plat_data->dev_type)) {
@@ -905,38 +893,21 @@ static int analogix_dp_atomic_check(struct drm_connector *connector,
 		}
 	}
 
-	conn_state = drm_atomic_get_new_connector_state(state, connector);
-	if (WARN_ON(!conn_state))
-		return -ENODEV;
-
 	conn_state->self_refresh_aware = true;
 
-	if (!conn_state->crtc)
-		return 0;
-
-	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
-	if (!crtc_state)
-		return 0;
-
 	if (crtc_state->self_refresh_active && !dp->psr_supported)
 		return -EINVAL;
 
 	return 0;
 }
 
-static const struct drm_connector_helper_funcs analogix_dp_connector_helper_funcs = {
-	.get_modes = analogix_dp_get_modes,
-	.best_encoder = analogix_dp_best_encoder,
-	.atomic_check = analogix_dp_atomic_check,
-};
-
 static enum drm_connector_status
-analogix_dp_detect(struct drm_connector *connector, bool force)
+analogix_dp_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connector)
 {
-	struct analogix_dp_device *dp = to_dp(connector);
+	struct analogix_dp_device *dp = to_dp(bridge);
 	enum drm_connector_status status = connector_status_disconnected;
 
-	if (dp->plat_data->panel)
+	if (dp->plat_data->panel || dp->plat_data->next_bridge)
 		return connector_status_connected;
 
 	if (!analogix_dp_detect_hpd(dp))
@@ -945,53 +916,20 @@ analogix_dp_detect(struct drm_connector *connector, bool force)
 	return status;
 }
 
-static const struct drm_connector_funcs analogix_dp_connector_funcs = {
-	.fill_modes = drm_helper_probe_single_connector_modes,
-	.detect = analogix_dp_detect,
-	.destroy = drm_connector_cleanup,
-	.reset = drm_atomic_helper_connector_reset,
-	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
-	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-};
-
 static int analogix_dp_bridge_attach(struct drm_bridge *bridge,
 				     struct drm_encoder *encoder,
 				     enum drm_bridge_attach_flags flags)
 {
 	struct analogix_dp_device *dp = to_dp(bridge);
-	struct drm_connector *connector = NULL;
 	int ret = 0;
 
-	if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
-		DRM_ERROR("Fix bridge driver to make connector optional!");
+	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
+		DRM_ERROR("Unsupported connector creation\n");
 		return -EINVAL;
 	}
 
-	if (!dp->plat_data->next_bridge) {
-		connector = &dp->connector;
-		connector->polled = DRM_CONNECTOR_POLL_HPD;
-
-		ret = drm_connector_init(dp->drm_dev, connector,
-					 &analogix_dp_connector_funcs,
-					 DRM_MODE_CONNECTOR_eDP);
-		if (ret) {
-			DRM_ERROR("Failed to initialize connector with drm\n");
-			return ret;
-		}
-
-		drm_connector_helper_add(connector,
-					 &analogix_dp_connector_helper_funcs);
-		drm_connector_attach_encoder(connector, encoder);
-	}
-
-	/*
-	 * NOTE: the connector registration is implemented in analogix
-	 * platform driver, that to say connector would be exist after
-	 * plat_data->attch return, that's why we record the connector
-	 * point after plat attached.
-	 */
 	if (dp->plat_data->attach) {
-		ret = dp->plat_data->attach(dp->plat_data, bridge, connector);
+		ret = dp->plat_data->attach(dp->plat_data, bridge);
 		if (ret) {
 			DRM_ERROR("Failed at platform attach func\n");
 			return ret;
@@ -1095,14 +1033,21 @@ static int analogix_dp_set_bridge(struct analogix_dp_device *dp)
 }
 
 static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge,
+					struct drm_atomic_state *state,
 					const struct drm_display_mode *mode)
 {
 	struct analogix_dp_device *dp = to_dp(bridge);
-	struct drm_display_info *display_info = &dp->connector.display_info;
 	struct video_info *video = &dp->video_info;
 	struct device_node *dp_node = dp->dev->of_node;
+	struct drm_connector *connector;
+	struct drm_display_info *display_info;
 	int vic;
 
+	connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
+	if (!connector)
+		return;
+	display_info = &connector->display_info;
+
 	/* Input video interlaces & hsync pol & vsync pol */
 	video->interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
 	video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
@@ -1186,7 +1131,7 @@ static void analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge,
 	new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc);
 	if (!new_crtc_state)
 		return;
-	analogix_dp_bridge_mode_set(bridge, &new_crtc_state->adjusted_mode);
+	analogix_dp_bridge_mode_set(bridge, old_state, &new_crtc_state->adjusted_mode);
 
 	old_crtc_state = drm_atomic_get_old_crtc_state(old_state, crtc);
 	/* Not a full enable, just disable PSR and continue */
@@ -1302,7 +1247,11 @@ static const struct drm_bridge_funcs analogix_dp_bridge_funcs = {
 	.atomic_enable = analogix_dp_bridge_atomic_enable,
 	.atomic_disable = analogix_dp_bridge_atomic_disable,
 	.atomic_post_disable = analogix_dp_bridge_atomic_post_disable,
+	.atomic_check = analogix_dp_bridge_atomic_check,
 	.attach = analogix_dp_bridge_attach,
+	.get_modes = analogix_dp_bridge_get_modes,
+	.edid_read = analogix_dp_bridge_edid_read,
+	.detect = analogix_dp_bridge_detect,
 };
 
 static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp)
@@ -1532,6 +1481,7 @@ EXPORT_SYMBOL_GPL(analogix_dp_resume);
 
 int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev)
 {
+	struct drm_bridge *bridge = &dp->bridge;
 	int ret;
 
 	dp->drm_dev = drm_dev;
@@ -1545,7 +1495,18 @@ int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev)
 		return ret;
 	}
 
-	ret = drm_bridge_attach(dp->encoder, &dp->bridge, NULL, 0);
+	if (dp->plat_data->panel)
+		bridge->ops = DRM_BRIDGE_OP_MODES | DRM_BRIDGE_OP_DETECT;
+	else
+		bridge->ops = DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT;
+
+	bridge->of_node = dp->dev->of_node;
+	bridge->type = DRM_MODE_CONNECTOR_eDP;
+	ret = devm_drm_bridge_add(dp->dev, &dp->bridge);
+	if (ret)
+		goto err_unregister_aux;
+
+	ret = drm_bridge_attach(dp->encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
 	if (ret) {
 		DRM_ERROR("failed to create bridge (%d)\n", ret);
 		goto err_unregister_aux;
@@ -1563,7 +1524,6 @@ EXPORT_SYMBOL_GPL(analogix_dp_bind);
 void analogix_dp_unbind(struct analogix_dp_device *dp)
 {
 	analogix_dp_bridge_disable(&dp->bridge);
-	dp->connector.funcs->destroy(&dp->connector);
 
 	drm_panel_unprepare(dp->plat_data->panel);
 
@@ -1573,7 +1533,8 @@ EXPORT_SYMBOL_GPL(analogix_dp_unbind);
 
 int analogix_dp_start_crc(struct drm_connector *connector)
 {
-	struct analogix_dp_device *dp = to_dp(connector);
+	struct analogix_dp_device *dp;
+	struct drm_bridge *bridge;
 
 	if (!connector->state->crtc) {
 		DRM_ERROR("Connector %s doesn't currently have a CRTC.\n",
@@ -1581,13 +1542,26 @@ int analogix_dp_start_crc(struct drm_connector *connector)
 		return -EINVAL;
 	}
 
+	bridge = drm_bridge_chain_get_first_bridge(connector->encoder);
+	if (bridge->type != DRM_MODE_CONNECTOR_eDP)
+		return -EINVAL;
+
+	dp = to_dp(bridge);
+
 	return drm_dp_start_crc(&dp->aux, connector->state->crtc);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_start_crc);
 
 int analogix_dp_stop_crc(struct drm_connector *connector)
 {
-	struct analogix_dp_device *dp = to_dp(connector);
+	struct analogix_dp_device *dp;
+	struct drm_bridge *bridge;
+
+	bridge = drm_bridge_chain_get_first_bridge(connector->encoder);
+	if (bridge->type != DRM_MODE_CONNECTOR_eDP)
+		return -EINVAL;
+
+	dp = to_dp(bridge);
 
 	return drm_dp_stop_crc(&dp->aux);
 }
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index 91b215c6a0cf..17347448c6b0 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -154,7 +154,6 @@ struct analogix_dp_device {
 	struct drm_encoder	*encoder;
 	struct device		*dev;
 	struct drm_device	*drm_dev;
-	struct drm_connector	connector;
 	struct drm_bridge	bridge;
 	struct drm_dp_aux	aux;
 	struct clk		*clock;
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 380d9a8ce259..38bf070866f6 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -70,6 +70,7 @@ config DRM_EXYNOS_DP
 	bool "Exynos specific extensions for Analogix DP driver"
 	depends on DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON
 	select DRM_ANALOGIX_DP
+	select DRM_BRIDGE_CONNECTOR
 	select DRM_DISPLAY_DP_HELPER
 	default DRM_EXYNOS
 	select DRM_OF_DISPLAY_MODE_BRIDGE
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index 1eeb0b15f99a..478eaa6f3175 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -22,6 +22,7 @@
 #include <drm/bridge/of-display-mode-bridge.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_bridge.h>
+#include <drm/drm_bridge_connector.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_of.h>
 #include <drm/drm_panel.h>
@@ -41,8 +42,6 @@ struct exynos_dp_device {
 
 	struct analogix_dp_device *adp;
 	struct analogix_dp_plat_data plat_data;
-
-	bool has_of_bridge;
 };
 
 static int exynos_dp_crtc_clock_enable(struct analogix_dp_plat_data *plat_data,
@@ -70,19 +69,15 @@ static int exynos_dp_poweroff(struct analogix_dp_plat_data *plat_data)
 }
 
 static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
-				   struct drm_bridge *bridge,
-				   struct drm_connector *connector)
+				   struct drm_bridge *bridge)
 {
 	struct exynos_dp_device *dp = to_dp(plat_data);
-	enum drm_bridge_attach_flags flags = 0;
 	int ret;
 
 	/* Pre-empt DP connector creation if there's a bridge */
 	if (plat_data->next_bridge) {
-		if (dp->has_of_bridge)
-			flags = DRM_BRIDGE_ATTACH_NO_CONNECTOR;
-
-		ret = drm_bridge_attach(&dp->encoder, plat_data->next_bridge, bridge, flags);
+		ret = drm_bridge_attach(&dp->encoder, plat_data->next_bridge, bridge,
+					DRM_BRIDGE_ATTACH_NO_CONNECTOR);
 		if (ret)
 			return ret;
 	}
@@ -112,6 +107,7 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 	struct exynos_dp_device *dp = dev_get_drvdata(dev);
 	struct drm_encoder *encoder = &dp->encoder;
 	struct drm_device *drm_dev = data;
+	struct drm_connector *connector;
 	int ret;
 
 	dp->drm_dev = drm_dev;
@@ -127,10 +123,19 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 	dp->plat_data.encoder = encoder;
 
 	ret = analogix_dp_bind(dp->adp, dp->drm_dev);
-	if (ret)
+	if (ret) {
 		dp->encoder.funcs->destroy(&dp->encoder);
+		return ret;
+	}
+
+	connector = drm_bridge_connector_init(dp->drm_dev, dp->plat_data.encoder);
+	if (IS_ERR(connector)) {
+		ret = PTR_ERR(connector);
+		dev_err(dp->dev, "Failed to initialize bridge_connector\n");
+		return ret;
+	}
 
-	return ret;
+	return drm_connector_attach_encoder(connector, dp->plat_data.encoder);
 }
 
 static void exynos_dp_unbind(struct device *dev, struct device *master,
@@ -187,8 +192,6 @@ static int exynos_dp_probe(struct platform_device *pdev)
 									dp->dev->of_node,
 									DRM_MODE_CONNECTOR_eDP);
 		ret = IS_ERR(dp->plat_data.next_bridge) ? PTR_ERR(dp->plat_data.next_bridge) : 0;
-		if (!ret)
-			dp->has_of_bridge = true;
 	}
 	if (ret)
 		return ret;
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index b7b025814e72..61e95a3ca6ab 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -43,6 +43,7 @@ config ROCKCHIP_VOP2
 config ROCKCHIP_ANALOGIX_DP
 	bool "Rockchip specific extensions for Analogix DP driver"
 	depends on ROCKCHIP_VOP
+	select DRM_BRIDGE_CONNECTOR
 	select DRM_DISPLAY_HELPER
 	select DRM_DISPLAY_DP_HELPER
 	help
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 70fe5ae69e2e..7fa17ba26c46 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -25,6 +25,7 @@
 #include <drm/display/drm_dp_helper.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge_connector.h>
 #include <drm/bridge/analogix_dp.h>
 #include <drm/drm_of.h>
 #include <drm/drm_panel.h>
@@ -369,6 +370,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 {
 	struct rockchip_dp_device *dp = dev_get_drvdata(dev);
 	struct drm_device *drm_dev = data;
+	struct drm_connector *connector;
 	int ret;
 
 	dp->drm_dev = drm_dev;
@@ -388,7 +390,14 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 	if (ret)
 		goto err_cleanup_encoder;
 
-	return 0;
+	connector = drm_bridge_connector_init(dp->drm_dev, dp->plat_data.encoder);
+	if (IS_ERR(connector)) {
+		ret = PTR_ERR(connector);
+		dev_err(dp->dev, "Failed to initialize bridge_connector\n");
+		goto err_cleanup_encoder;
+	}
+
+	return drm_connector_attach_encoder(connector, dp->plat_data.encoder);
 err_cleanup_encoder:
 	dp->encoder.encoder.funcs->destroy(&dp->encoder.encoder);
 	return ret;
diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h
index 3301392eda5f..3428ffff24c5 100644
--- a/include/drm/bridge/analogix_dp.h
+++ b/include/drm/bridge/analogix_dp.h
@@ -33,8 +33,7 @@ struct analogix_dp_plat_data {
 
 	int (*power_on)(struct analogix_dp_plat_data *);
 	int (*power_off)(struct analogix_dp_plat_data *);
-	int (*attach)(struct analogix_dp_plat_data *, struct drm_bridge *,
-		      struct drm_connector *);
+	int (*attach)(struct analogix_dp_plat_data *, struct drm_bridge *);
 };
 
 int analogix_dp_resume(struct analogix_dp_device *dp);
-- 
2.34.1



From ryan.roberts at arm.com  Wed Dec 17 01:34:15 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Wed, 17 Dec 2025 09:34:15 +0000
Subject: [PATCH 0/2] introduce pagetable_alloc_nolock()
In-Reply-To: <aUGOPd7gNRf1xHEc@e129823.arm.com>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com>
 <916c17ba-22b1-456e-a184-cb3f60249af7@arm.com>
 <aUGOPd7gNRf1xHEc@e129823.arm.com>
Message-ID: <100cc8da-b826-4fc2-a624-746bf6fb049d@arm.com>

On 16/12/2025 16:52, Yeoreum Yun wrote:
> Hi Ryan,
> 
>> On 12/12/2025 16:18, Yeoreum Yun wrote:
>>> Some architectures invoke pagetable_alloc() or __get_free_pages()
>>> with preemption disabled.
>>> For example, in arm64, linear_map_split_to_ptes() calls pagetable_alloc()
>>> while spliting block entry to ptes and __kpti_install_ng_mappings()
>>> calls __get_free_pages() to create kpti pagetable.
>>>
>>> Under PREEMPT_RT, calling pagetable_alloc() with
>>> preemption disabled is not allowed, because it may acquire
>>> a spin lock that becomes sleepable on RT, potentially
>>> causing a sleep during page allocation.
>>>
>>> Since above two functions is called as callback of stop_machine()
>>> where its callback is called in preemption disabled,
>>> They could make a potential problem. (sleeping in preemption disabled).
>>>
>>> To address this, introduce pagetable_alloc_nolock() API.
>>
>> I don't really understand what the problem is that you're trying to fix. As I
>> see it, there are 2 call sites in arm64 arch code that are calling into the page
>> allocator from stop_machine() - one via via pagetable_alloc() and another via
>> __get_free_pages(). But both of those calls are passing in GFP_ATOMIC. It was my
>> understanding that the page allocator would ensure it never sleeps when
>> GFP_ATOMIC is passed in, (even for PREEMPT_RT)?
> 
> Although GFP_ATOMIC is specify, it only affects of "water mark" of the
> page with __GFP_HIGH. and to get a page, it must grab the lock --
> zone->lock or pcp_lock in the rmqueue().
> 
> This zone->lock and pcp_lock is spin_lock and it's a sleepable in
> PREEMPT_RT that's why the memory allocation/free using general API
> except nolock() version couldn't be called since
> if "contention" happens they'll sleep while waiting to get the lock.
> 
> The reason why "nolock()" can use, it always uses "trylock" with
> ALLOC_TRYLOCK flags. otherwise GFP_ATOMIC also can be sleepable in
> PREEMPT_RT.
> 
>>
>> What is the actual symptom you are seeing?
> 
> Since the place where called while smp_cpus_done() and there seems no
> contention, there seems no problem. However as I mention in another
> thread
> (https://lore.kernel.org/all/aT%2FdrjN1BkvyAGoi at e129823.arm.com/),
> This gives a the false impression --
> GFP_ATOMIC are ?safe to use in preemption disabled?
> even though they are not in PREEMPT_RT case, I've changed it.
> 
>>
>> If the page allocator is somehow ignoring the GFP_ATOMIC request for PREEMPT_RT,
>> then isn't that a bug in the page allocator? I'm not sure why you would change
>> the callsites? Can't you just change the page allocator based on GFP_ATOMIC?
> 
> It doesn't ignore the GFP_ATOMIC feature:
>   - __GFP_HIGH: use water mark till min reserved
>   - __GFP_KSWAPD_RECLAIM: wake up kswapd if reclaim required.
> 
> But, it's a restriction -- "page allocation / free" API cannot be called
> in preempt-disabled context at PREEMPT_RT.
> 
> That's why I think it's wrong usage not a page allocator bug.

I've taken a look at this and I agree with your analysis. Thanks for explaining.

Looking at other stop_machine() callbacks, there are some that call printk() and
I would assume that spinlocks could be taken there which may present the same
kind of issue or PREEMPT_RT? (I'm guessing). I don't see any others that attempt
to allocate memory though.

Anyway, to fix the 2 arm64 callsites, I see 2 possible approaches:

- Call the nolock variant (as you are doing). But that would just convert a
deadlock to a panic; if the lock is held when stop_machine() runs, without your
change, we now have a deadlock due to waiting on the lock inside stop_machine().
With your change, we notice the lock is already taken and panic. I guess it is
marginally better, but not by much. Certainly I would just _always_ call the
nolock variant regardless of PREEMPT_RT if we take this route; For !PREEMPT_RT,
the lock is guarranteed to be free so nolock will always succeed.

- Preallocate the memory before entering stop_machine(). I think this would be
much more robust. For kpti_install_ng_mappings() I think you could hoist the
allocation/free out of stop_machine() and pass the pointer in pretty easily. For
linear_map_split_to_ptes() its a bit more complex; Perhaps, we need to walk the
pgtable to figure out how much to preallocate, allocate it, then set it up as a
special allocator, wrapped by an allocation function and modify the callchain to
take a callback function instead of gfp flags.

What do you think?

Thanks,
Ryan

> 
> [...]
> 
> --
> Sincerely,
> Yeoreum Yun



From maz at kernel.org  Wed Dec 17 01:34:38 2025
From: maz at kernel.org (Marc Zyngier)
Date: Wed, 17 Dec 2025 09:34:38 +0000
Subject: [PATCH 16/32] KVM: arm64: gic: Introduce irq_queue and set_pending_state to irq_ops
In-Reply-To: <20251212152215.675767-17-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	<20251212152215.675767-17-sascha.bischoff@arm.com>
Message-ID: <865xa5o3ip.wl-maz@kernel.org>

On Fri, 12 Dec 2025 15:22:40 +0000,
Sascha Bischoff <Sascha.Bischoff at arm.com> wrote:
> 
> There are times when the default behaviour of vgic_queue_irq_unlock is
> undesirable. This is because some GICs, such a GICv5 which is the main
> driver for this change, handle the majority of the interrupt lifecycle
> in hardware. In this case, there is no need for a per-VCPU AP list as
> the interrupt can be made pending directly. This is done either via
> the ICH_PPI_x_EL2 registers for PPIs, or with the VDPEND system
> instruction for SPIs and LPIs.
> 
> The queue_irq_unlock function is made overridable using a new function
> pointer in struct irq_ops. In kvm_vgic_inject_irq,
> vgic_queue_irq_unlock is overridden if the function pointer is
> non-null.
> 
> Additionally, a new function is added via a function pointer -
> set_pending_state. The intent is for this to be used to directly set
> the pending state in hardware.
> 
> Both of these new irq_ops are unused in this change - it is purely
> providing the infrastructure itself. The subsequent PPI injection
> changes provide a demonstration of their usage.
> 
> Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
> ---
>  arch/arm64/kvm/vgic/vgic.c |  9 ++++++++-
>  include/kvm/arm_vgic.h     | 15 +++++++++++++++
>  2 files changed, 23 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
> index 1fe3dcc997860..fc01c6d07fe62 100644
> --- a/arch/arm64/kvm/vgic/vgic.c
> +++ b/arch/arm64/kvm/vgic/vgic.c
> @@ -547,7 +547,14 @@ int kvm_vgic_inject_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  	else
>  		irq->pending_latch = true;
>  
> -	vgic_queue_irq_unlock(kvm, irq, flags);
> +	if (irq->ops && irq->ops->set_pending_state)
> +		WARN_ON_ONCE(!irq->ops->set_pending_state(vcpu, irq));
> +
> +	if (irq->ops && irq->ops->queue_irq_unlock)
> +		WARN_ON_ONCE(!irq->ops->queue_irq_unlock(kvm, irq, flags));
> +	else
> +		vgic_queue_irq_unlock(kvm, irq, flags);

I find it slightly dubious to WARN() in one case but not the other.

More importantly, why isn't the per-irq queue_unlock operation tucked
into the vgic_queue_irq_unlock() primitive? We have 16 call sites for
this function, and it is odd that only the injection primitive would
benefit from this.

Thanks,

	M.

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


From laurentiumihalcea111 at gmail.com  Wed Dec 17 01:38:56 2025
From: laurentiumihalcea111 at gmail.com (Laurentiu Mihalcea)
Date: Wed, 17 Dec 2025 01:38:56 -0800
Subject: [PATCH v6 0/5] Add support for i.MX8ULP's SIM LPAV
In-Reply-To: <20251126124218.803-1-laurentiumihalcea111@gmail.com>
References: <20251126124218.803-1-laurentiumihalcea111@gmail.com>
Message-ID: <23326a3a-fd1a-440c-acd6-28d2e7c0f186@gmail.com>


On 11/26/2025 4:42 AM, Laurentiu Mihalcea wrote:
> From: Laurentiu Mihalcea <laurentiu.mihalcea at nxp.com>
>
> The LPAV System Integration Module (SIM) is an IP found inside i.MX8ULP's
> LPAV subsystem, which offers clock gating, reset line
> assertion/de-assertion, and various other misc. options.
>
> This series adds support for the IP by introducing a new clock HW provider
> driver and by modifying i.MX8MP's AUDIOMIX block control reset driver to
> allow it to be used for i.MX8ULP's SIM LPAV as well.
>
> This series is a spin-off from [1].
>
> [1]: https://lore.kernel.org/lkml/20240922174225.75948-1-laurentiumihalcea111 at gmail.com/


Hi Shawn and Philipp,


Gentle ping on this.


Thanks,

Laurentiu



From leo.yan at arm.com  Wed Dec 17 01:39:20 2025
From: leo.yan at arm.com (Leo Yan)
Date: Wed, 17 Dec 2025 09:39:20 +0000
Subject: [PATCH] stm class: Fix Kconfig symbols
Message-ID: <20251217-fix_stm_kconfig-v1-1-531fb3674549@arm.com>

Kconfig symbols must not include the CONFIG_ prefix.  Remove the CONFIG_
prefix for default values to work.

Fixes: a02509f301c6 ("stm class: Factor out default framing protocol")
Fixes: d69d5e83110f ("stm class: Add MIPI SyS-T protocol support")
Signed-off-by: Leo Yan <leo.yan at arm.com>
---
 drivers/hwtracing/stm/Kconfig | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/hwtracing/stm/Kconfig b/drivers/hwtracing/stm/Kconfig
index eda6b11d40a1f9ab49a1ec1e6faae8ee178c5ed3..cd7f0b0f3fbebc74775d8835187e49e5bd21d646 100644
--- a/drivers/hwtracing/stm/Kconfig
+++ b/drivers/hwtracing/stm/Kconfig
@@ -13,7 +13,7 @@ if STM
 
 config STM_PROTO_BASIC
 	tristate "Basic STM framing protocol driver"
-	default CONFIG_STM
+	default STM
 	help
 	  This is a simple framing protocol for sending data over STM
 	  devices. This was the protocol that the STM framework used
@@ -28,7 +28,7 @@ config STM_PROTO_BASIC
 
 config STM_PROTO_SYS_T
 	tristate "MIPI SyS-T STM framing protocol driver"
-	default CONFIG_STM
+	default STM
 	help
 	  This is an implementation of MIPI SyS-T protocol to be used
 	  over the STP transport. In addition to the data payload, it

---
base-commit: 40fbbd64bba6c6e7a72885d2f59b6a3be9991eeb
change-id: 20251216-fix_stm_kconfig-a72f40c7612c

Best regards,
-- 
Leo Yan <leo.yan at arm.com>



From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec 17 01:51:53 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed, 17 Dec 2025 10:51:53 +0100
Subject: [PATCH v2 0/4] watchdog: s3c2410_wdt: Simplify, cleanup and drop
 S3C2410
Message-ID: <20251217-watchdog-s3c-cleanup-v2-0-79d8caf65ec3@oss.qualcomm.com>

Changes in v2:
- None, just rebase and apply tags.
- Can this be finally applied? It's waiting for almost four months.
- Link to v1: https://lore.kernel.org/r/20250830-watchdog-s3c-cleanup-v1-0-837ae94a21b5 at linaro.org

S3C2410 is gone from kernel, so we can drop its support.  Also cleanup
and correct a bit the bindings.

Best regards,
Krzysztof

---
Krzysztof Kozlowski (4):
      dt-bindings: watchdog: samsung-wdt: Define cluster constraints top-level
      watchdog: s3c2410_wdt: Drop S3C2410 support
      dt-bindings: watchdog: samsung-wdt: Drop S3C2410
      dt-bindings: watchdog: samsung-wdt: Split if:then: and constrain more

 .../devicetree/bindings/watchdog/samsung-wdt.yaml  | 72 ++++++++++++++++------
 drivers/watchdog/s3c2410_wdt.c                     | 22 +------
 2 files changed, 53 insertions(+), 41 deletions(-)
---
base-commit: 12b95d29eb979e5c4f4f31bb05817bc935c52050
change-id: 20250830-watchdog-s3c-cleanup-cfa28bf8bb2c

Best regards,
-- 
Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>



From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec 17 01:51:54 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed, 17 Dec 2025 10:51:54 +0100
Subject: [PATCH v2 1/4] dt-bindings: watchdog: samsung-wdt: Define cluster
 constraints top-level
In-Reply-To: <20251217-watchdog-s3c-cleanup-v2-0-79d8caf65ec3@oss.qualcomm.com>
References: <20251217-watchdog-s3c-cleanup-v2-0-79d8caf65ec3@oss.qualcomm.com>
Message-ID: <20251217-watchdog-s3c-cleanup-v2-1-79d8caf65ec3@oss.qualcomm.com>

Properties should be always constrained in top-level part of the
bindings, so move the samsung,cluster-index constrain from if: block.

Acked-by: Guenter Roeck <linux at roeck-us.net>
Acked-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml b/Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml
index 53fc64f5b56d..445c5271879f 100644
--- a/Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml
+++ b/Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml
@@ -49,6 +49,7 @@ properties:
 
   samsung,cluster-index:
     $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [0, 1, 2]
     description:
       Index of CPU cluster on which watchdog is running (in case of Exynos850,
       Exynos990 or Google gs101).
@@ -104,8 +105,6 @@ allOf:
           items:
             - const: watchdog
             - const: watchdog_src
-        samsung,cluster-index:
-          enum: [0, 1, 2]
       required:
         - samsung,cluster-index
     else:

-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec 17 01:51:55 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed, 17 Dec 2025 10:51:55 +0100
Subject: [PATCH v2 2/4] watchdog: s3c2410_wdt: Drop S3C2410 support
In-Reply-To: <20251217-watchdog-s3c-cleanup-v2-0-79d8caf65ec3@oss.qualcomm.com>
References: <20251217-watchdog-s3c-cleanup-v2-0-79d8caf65ec3@oss.qualcomm.com>
Message-ID: <20251217-watchdog-s3c-cleanup-v2-2-79d8caf65ec3@oss.qualcomm.com>

Samsung S3C2410 SoC was removed from Linux kernel in the
commit 61b7f8920b17 ("ARM: s3c: remove all s3c24xx support"), in January
2023.  There are no in-kernel users of samsung,s3c2410-wdt compatible
and s3c2410-wdt platform device name, so drop both.  This leaves the
driver boundable only via compatibles, so drop any CONFIG_OF ifdefs.

Reviewed-by: Guenter Roeck <linux at roeck-us.net>
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/watchdog/s3c2410_wdt.c | 22 +---------------------
 1 file changed, 1 insertion(+), 21 deletions(-)

diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index b774477190b6..e31f93db0509 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -208,11 +208,6 @@ struct s3c2410_wdt {
 	u32 max_cnt;
 };
 
-static const struct s3c2410_wdt_variant drv_data_s3c2410 = {
-	.quirks = 0
-};
-
-#ifdef CONFIG_OF
 static const struct s3c2410_wdt_variant drv_data_s3c6410 = {
 	.quirks = QUIRK_HAS_WTCLRINT_REG,
 };
@@ -378,8 +373,6 @@ static const struct s3c2410_wdt_variant drv_data_exynosautov920_cl1 = {
 static const struct of_device_id s3c2410_wdt_match[] = {
 	{ .compatible = "google,gs101-wdt",
 	  .data = &drv_data_gs101_cl0 },
-	{ .compatible = "samsung,s3c2410-wdt",
-	  .data = &drv_data_s3c2410 },
 	{ .compatible = "samsung,s3c6410-wdt",
 	  .data = &drv_data_s3c6410 },
 	{ .compatible = "samsung,exynos5250-wdt",
@@ -399,16 +392,6 @@ static const struct of_device_id s3c2410_wdt_match[] = {
 	{},
 };
 MODULE_DEVICE_TABLE(of, s3c2410_wdt_match);
-#endif
-
-static const struct platform_device_id s3c2410_wdt_ids[] = {
-	{
-		.name = "s3c2410-wdt",
-		.driver_data = (unsigned long)&drv_data_s3c2410,
-	},
-	{}
-};
-MODULE_DEVICE_TABLE(platform, s3c2410_wdt_ids);
 
 /* functions */
 
@@ -720,7 +703,6 @@ s3c2410_get_wdt_drv_data(struct platform_device *pdev, struct s3c2410_wdt *wdt)
 			   platform_get_device_id(pdev)->driver_data;
 	}
 
-#ifdef CONFIG_OF
 	/* Choose Exynos850/ExynosAutov9 driver data w.r.t. cluster index */
 	if (variant == &drv_data_exynos850_cl0 ||
 	    variant == &drv_data_exynosautov9_cl0 ||
@@ -756,7 +738,6 @@ s3c2410_get_wdt_drv_data(struct platform_device *pdev, struct s3c2410_wdt *wdt)
 			return dev_err_probe(dev, -EINVAL, "wrong cluster index: %u\n", index);
 		}
 	}
-#endif
 
 	wdt->drv_data = variant;
 	return 0;
@@ -949,11 +930,10 @@ static DEFINE_SIMPLE_DEV_PM_OPS(s3c2410wdt_pm_ops,
 static struct platform_driver s3c2410wdt_driver = {
 	.probe		= s3c2410wdt_probe,
 	.shutdown	= s3c2410wdt_shutdown,
-	.id_table	= s3c2410_wdt_ids,
 	.driver		= {
 		.name	= "s3c2410-wdt",
 		.pm	= pm_sleep_ptr(&s3c2410wdt_pm_ops),
-		.of_match_table	= of_match_ptr(s3c2410_wdt_match),
+		.of_match_table	= s3c2410_wdt_match,
 	},
 };
 

-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec 17 01:51:56 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed, 17 Dec 2025 10:51:56 +0100
Subject: [PATCH v2 3/4] dt-bindings: watchdog: samsung-wdt: Drop S3C2410
In-Reply-To: <20251217-watchdog-s3c-cleanup-v2-0-79d8caf65ec3@oss.qualcomm.com>
References: <20251217-watchdog-s3c-cleanup-v2-0-79d8caf65ec3@oss.qualcomm.com>
Message-ID: <20251217-watchdog-s3c-cleanup-v2-3-79d8caf65ec3@oss.qualcomm.com>

Samsung S3C2410 SoC was removed from Linux kernel in the
commit 61b7f8920b17 ("ARM: s3c: remove all s3c24xx support"), in January
2023.  There are no in-kernel users of samsung,s3c2410-wdt compatible
anymore and platform is so old, that there should be no out-of-tree
users.  If such existed, they would have enough of time to object
dropping Samsung S3C2410 SoC removal from the kernel (which did not
happen).

Acked-by: Guenter Roeck <linux at roeck-us.net>
Acked-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml b/Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml
index 445c5271879f..51e597ba7db2 100644
--- a/Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml
+++ b/Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml
@@ -19,7 +19,6 @@ properties:
     oneOf:
       - enum:
           - google,gs101-wdt                      # for Google gs101
-          - samsung,s3c2410-wdt                   # for S3C2410
           - samsung,s3c6410-wdt                   # for S3C6410, S5PV210 and Exynos4
           - samsung,exynos5250-wdt                # for Exynos5250
           - samsung,exynos5420-wdt                # for Exynos5420

-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec 17 01:51:57 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed, 17 Dec 2025 10:51:57 +0100
Subject: [PATCH v2 4/4] dt-bindings: watchdog: samsung-wdt: Split if:then:
 and constrain more
In-Reply-To: <20251217-watchdog-s3c-cleanup-v2-0-79d8caf65ec3@oss.qualcomm.com>
References: <20251217-watchdog-s3c-cleanup-v2-0-79d8caf65ec3@oss.qualcomm.com>
Message-ID: <20251217-watchdog-s3c-cleanup-v2-4-79d8caf65ec3@oss.qualcomm.com>

Binding defined two if:then: blocks covering different conditions but
not fully constraining the properties per each variant:
1. "if:" to require samsung,syscon-phandle,
2. "if:" with "else:" to narrow number of clocks and require or disallow
   samsung,cluster-index.

This still did not cover following cases:
1. Disallow samsung,syscon-phandle when not applicable,
2. Narrow samsung,cluster-index to [0, 1], for SoCs with only two
   clusters.

Solving this in current format would lead to spaghetti code, so re-write
entire "if:then:" approach into mutually exclusive cases so each SoC
appears only in one "if:" block.  This allows to forbid
samsung,syscon-phandle for S3C6410, and narrow samsung,cluster-index
to [0, 1].

Acked-by: Guenter Roeck <linux at roeck-us.net>
Acked-by: Rob Herring (Arm) <robh at kernel.org>
Reviewed-by: Alim Akhtar <alim.akhtar at samsung.com>
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 .../devicetree/bindings/watchdog/samsung-wdt.yaml  | 70 ++++++++++++++++------
 1 file changed, 52 insertions(+), 18 deletions(-)

diff --git a/Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml b/Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml
index 51e597ba7db2..41aee1655b0c 100644
--- a/Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml
+++ b/Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml
@@ -74,24 +74,7 @@ allOf:
           contains:
             enum:
               - google,gs101-wdt
-              - samsung,exynos5250-wdt
-              - samsung,exynos5420-wdt
-              - samsung,exynos7-wdt
               - samsung,exynos850-wdt
-              - samsung,exynos990-wdt
-              - samsung,exynosautov9-wdt
-              - samsung,exynosautov920-wdt
-    then:
-      required:
-        - samsung,syscon-phandle
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - google,gs101-wdt
-              - samsung,exynos850-wdt
-              - samsung,exynos990-wdt
               - samsung,exynosautov9-wdt
               - samsung,exynosautov920-wdt
     then:
@@ -104,9 +87,41 @@ allOf:
           items:
             - const: watchdog
             - const: watchdog_src
+        samsung,cluster-index:
+          enum: [0, 1]
       required:
         - samsung,cluster-index
-    else:
+        - samsung,syscon-phandle
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - samsung,exynos990-wdt
+    then:
+      properties:
+        clocks:
+          items:
+            - description: Bus clock, used for register interface
+            - description: Source clock (driving watchdog counter)
+        clock-names:
+          items:
+            - const: watchdog
+            - const: watchdog_src
+      required:
+        - samsung,cluster-index
+        - samsung,syscon-phandle
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - samsung,exynos5250-wdt
+              - samsung,exynos5420-wdt
+              - samsung,exynos7-wdt
+    then:
       properties:
         clocks:
           items:
@@ -115,6 +130,25 @@ allOf:
           items:
             - const: watchdog
         samsung,cluster-index: false
+      required:
+        - samsung,syscon-phandle
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - samsung,s3c6410-wdt
+    then:
+      properties:
+        clocks:
+          items:
+            - description: Bus clock, which is also a source clock
+        clock-names:
+          items:
+            - const: watchdog
+        samsung,cluster-index: false
+        samsung,syscon-phandle: false
 
 unevaluatedProperties: false
 

-- 
2.51.0



From taniya.das at oss.qualcomm.com  Wed Dec 17 01:58:54 2025
From: taniya.das at oss.qualcomm.com (Taniya Das)
Date: Wed, 17 Dec 2025 15:28:54 +0530
Subject: [PATCH 2/3] dt-bindings: clock: qcom: Add camera clock controller
 for SM8750 SoC
In-Reply-To: <7e22e126-cb08-4bc2-bad6-a895a4e35a8d@linaro.org>
References: <20251202-sm8750_camcc-v1-0-b3f7ef6723f1@oss.qualcomm.com>
 <20251202-sm8750_camcc-v1-2-b3f7ef6723f1@oss.qualcomm.com>
 <7e22e126-cb08-4bc2-bad6-a895a4e35a8d@linaro.org>
Message-ID: <ca336f38-f831-4cb7-8f2d-66a4302e0efb@oss.qualcomm.com>



On 12/3/2025 7:39 PM, Vladimir Zapolskiy wrote:
> Hi Taniya.
> 
> On 12/2/25 12:26, Taniya Das wrote:
>> Add device tree bindings for the camera clock controller on
>> Qualcomm SM8750 platform. The camera clock controller is split between
>> camcc and cambist. The cambist controls the mclks of the camera clock
>> controller.
>>
>> Signed-off-by: Taniya Das <taniya.das at oss.qualcomm.com>
>> ---
>> ? .../bindings/clock/qcom,sm8450-camcc.yaml????????? |?? 5 +
>> ? .../dt-bindings/clock/qcom,sm8750-cambistmclkcc.h? |? 30 ++++
>> ? include/dt-bindings/clock/qcom,sm8750-camcc.h????? | 151 +++++++++++
>> ++++++++++
>> ? 3 files changed, 186 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8450-
>> camcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8450-
>> camcc.yaml
>> index
>> c1e06f39431e68a3cd2f6c2dba84be2a3c143bb1..8e3baba5270b384eb03a68b4e47785e6c91ec6f7 100644
>> --- a/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml
>> +++ b/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml
>> @@ -9,6 +9,7 @@ title: Qualcomm Camera Clock & Reset Controller on SM8450
>> ? maintainers:
>> ??? - Vladimir Zapolskiy <vladimir.zapolskiy at linaro.org>
>> ??? - Jagadeesh Kona <quic_jkona at quicinc.com>
>> +? - Taniya Das <taniya.das at oss.qualcomm.com>
>> ? ? description: |
>> ??? Qualcomm camera clock control module provides the clocks, resets
>> and power
>> @@ -18,6 +19,8 @@ description: |
>> ????? include/dt-bindings/clock/qcom,sm8450-camcc.h
>> ????? include/dt-bindings/clock/qcom,sm8550-camcc.h
>> ????? include/dt-bindings/clock/qcom,sm8650-camcc.h
>> +??? include/dt-bindings/clock/qcom,sm8750-cambistmclkcc.h
>> +??? include/dt-bindings/clock/qcom,sm8750-camcc.h
>> ? ? properties:
>> ??? compatible:
>> @@ -26,6 +29,8 @@ properties:
>> ??????? - qcom,sm8475-camcc
>> ??????? - qcom,sm8550-camcc
>> ??????? - qcom,sm8650-camcc
>> +????? - qcom,sm8750-cambistmclkcc
> 
> Due to the very distinct nature of this new clock controller, I suppose
> it does not inherit most of the properties of other CAMCC clocks, and
> therefore it should be described in a separate dt binding documentation
> file.
> 

Vladimir, from a clock controller design PoV, CAMBISTMCLK CC does
support resets/_ares at hardware level and thus documenting the same.
But currently SW is not using them, thus I have not modelled the resets
in the macro definition.

> Looking at the list of macro definitions from a new header file, a
> noticeable
> remark is that this new clock controller is neither a reset controller nor
> a power domain controller.
> 
>> +????? - qcom,sm8750-camcc
>> ? ??? clocks:
>> ????? items:
>> diff --git a/include/dt-bindings/clock/qcom,sm8750-cambistmclkcc.h b/
>> include/dt-bindings/clock/qcom,sm8750-cambistmclkcc.h
>> new file mode 100644
>> index
>> 0000000000000000000000000000000000000000..51615bee307fd9e7f81f7e5c1662535093dd8b55
>> --- /dev/null
>> +++ b/include/dt-bindings/clock/qcom,sm8750-cambistmclkcc.h
>> @@ -0,0 +1,30 @@
>> +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
>> +/*
>> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
>> + */
>> +
>> +#ifndef _DT_BINDINGS_CLK_QCOM_CAM_BIST_MCLK_CC_SM8750_H
>> +#define _DT_BINDINGS_CLK_QCOM_CAM_BIST_MCLK_CC_SM8750_H
>> +
>> +/* CAM_BIST_MCLK_CC clocks */
>> +#define CAM_BIST_MCLK_CC_MCLK0_CLK??????????????? 0
>> +#define CAM_BIST_MCLK_CC_MCLK0_CLK_SRC??????????????? 1
>> +#define CAM_BIST_MCLK_CC_MCLK1_CLK??????????????? 2
>> +#define CAM_BIST_MCLK_CC_MCLK1_CLK_SRC??????????????? 3
>> +#define CAM_BIST_MCLK_CC_MCLK2_CLK??????????????? 4
>> +#define CAM_BIST_MCLK_CC_MCLK2_CLK_SRC??????????????? 5
>> +#define CAM_BIST_MCLK_CC_MCLK3_CLK??????????????? 6
>> +#define CAM_BIST_MCLK_CC_MCLK3_CLK_SRC??????????????? 7
>> +#define CAM_BIST_MCLK_CC_MCLK4_CLK??????????????? 8
>> +#define CAM_BIST_MCLK_CC_MCLK4_CLK_SRC??????????????? 9
>> +#define CAM_BIST_MCLK_CC_MCLK5_CLK??????????????? 10
>> +#define CAM_BIST_MCLK_CC_MCLK5_CLK_SRC??????????????? 11
>> +#define CAM_BIST_MCLK_CC_MCLK6_CLK??????????????? 12
>> +#define CAM_BIST_MCLK_CC_MCLK6_CLK_SRC??????????????? 13
>> +#define CAM_BIST_MCLK_CC_MCLK7_CLK??????????????? 14
>> +#define CAM_BIST_MCLK_CC_MCLK7_CLK_SRC??????????????? 15
>> +#define CAM_BIST_MCLK_CC_PLL0??????????????????? 16
>> +#define CAM_BIST_MCLK_CC_SLEEP_CLK??????????????? 17
>> +#define CAM_BIST_MCLK_CC_SLEEP_CLK_SRC??????????????? 18
>> +
>> +#endif
>> diff --git a/include/dt-bindings/clock/qcom,sm8750-camcc.h b/include/
>> dt-bindings/clock/qcom,sm8750-camcc.h
>> new file mode 100644
>> index
>> 0000000000000000000000000000000000000000..dae788247afe896ef812bef716897c6cf80df2bb
>> --- /dev/null
>> +++ b/include/dt-bindings/clock/qcom,sm8750-camcc.h
>> @@ -0,0 +1,151 @@
>> +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
>> +/*
>> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
>> + */
>> +
>> +#ifndef _DT_BINDINGS_CLK_QCOM_CAM_CC_SM8750_H
>> +#define _DT_BINDINGS_CLK_QCOM_CAM_CC_SM8750_H
>> +
>> +/* CAM_CC clocks */
>> +#define CAM_CC_CAM_TOP_AHB_CLK??????????????????? 0
>> +#define CAM_CC_CAM_TOP_FAST_AHB_CLK??????????????? 1
>> +#define CAM_CC_CAMNOC_DCD_XO_CLK??????????????? 2
>> +#define CAM_CC_CAMNOC_NRT_AXI_CLK??????????????? 3
>> +#define CAM_CC_CAMNOC_NRT_CRE_CLK??????????????? 4
>> +#define CAM_CC_CAMNOC_NRT_IPE_NPS_CLK??????????????? 5
>> +#define CAM_CC_CAMNOC_NRT_OFE_ANCHOR_CLK??????????? 6
>> +#define CAM_CC_CAMNOC_NRT_OFE_HDR_CLK??????????????? 7
>> +#define CAM_CC_CAMNOC_NRT_OFE_MAIN_CLK??????????????? 8
>> +#define CAM_CC_CAMNOC_RT_AXI_CLK??????????????? 9
>> +#define CAM_CC_CAMNOC_RT_AXI_CLK_SRC??????????????? 10
>> +#define CAM_CC_CAMNOC_RT_IFE_LITE_CLK??????????????? 11
>> +#define CAM_CC_CAMNOC_RT_TFE_0_BAYER_CLK??????????? 12
>> +#define CAM_CC_CAMNOC_RT_TFE_0_MAIN_CLK??????????????? 13
>> +#define CAM_CC_CAMNOC_RT_TFE_1_BAYER_CLK??????????? 14
>> +#define CAM_CC_CAMNOC_RT_TFE_1_MAIN_CLK??????????????? 15
>> +#define CAM_CC_CAMNOC_RT_TFE_2_BAYER_CLK??????????? 16
>> +#define CAM_CC_CAMNOC_RT_TFE_2_MAIN_CLK??????????????? 17
>> +#define CAM_CC_CAMNOC_XO_CLK??????????????????? 18
>> +#define CAM_CC_CCI_0_CLK??????????????????? 19
>> +#define CAM_CC_CCI_0_CLK_SRC??????????????????? 20
>> +#define CAM_CC_CCI_1_CLK??????????????????? 21
>> +#define CAM_CC_CCI_1_CLK_SRC??????????????????? 22
>> +#define CAM_CC_CCI_2_CLK??????????????????? 23
>> +#define CAM_CC_CCI_2_CLK_SRC??????????????????? 24
>> +#define CAM_CC_CORE_AHB_CLK??????????????????? 25
>> +#define CAM_CC_CPHY_RX_CLK_SRC??????????????????? 26
>> +#define CAM_CC_CRE_AHB_CLK??????????????????? 27
>> +#define CAM_CC_CRE_CLK??????????????????????? 28
>> +#define CAM_CC_CRE_CLK_SRC??????????????????? 29
>> +#define CAM_CC_CSI0PHYTIMER_CLK??????????????????? 30
>> +#define CAM_CC_CSI0PHYTIMER_CLK_SRC??????????????? 31
>> +#define CAM_CC_CSI1PHYTIMER_CLK??????????????????? 32
>> +#define CAM_CC_CSI1PHYTIMER_CLK_SRC??????????????? 33
>> +#define CAM_CC_CSI2PHYTIMER_CLK??????????????????? 34
>> +#define CAM_CC_CSI2PHYTIMER_CLK_SRC??????????????? 35
>> +#define CAM_CC_CSI3PHYTIMER_CLK??????????????????? 36
>> +#define CAM_CC_CSI3PHYTIMER_CLK_SRC??????????????? 37
>> +#define CAM_CC_CSI4PHYTIMER_CLK??????????????????? 38
>> +#define CAM_CC_CSI4PHYTIMER_CLK_SRC??????????????? 39
>> +#define CAM_CC_CSI5PHYTIMER_CLK??????????????????? 40
>> +#define CAM_CC_CSI5PHYTIMER_CLK_SRC??????????????? 41
>> +#define CAM_CC_CSID_CLK??????????????????????? 42
>> +#define CAM_CC_CSID_CLK_SRC??????????????????? 43
>> +#define CAM_CC_CSID_CSIPHY_RX_CLK??????????????? 44
>> +#define CAM_CC_CSIPHY0_CLK??????????????????? 45
>> +#define CAM_CC_CSIPHY1_CLK??????????????????? 46
>> +#define CAM_CC_CSIPHY2_CLK??????????????????? 47
>> +#define CAM_CC_CSIPHY3_CLK??????????????????? 48
>> +#define CAM_CC_CSIPHY4_CLK??????????????????? 49
>> +#define CAM_CC_CSIPHY5_CLK??????????????????? 50
>> +#define CAM_CC_DRV_AHB_CLK??????????????????? 51
>> +#define CAM_CC_DRV_XO_CLK??????????????????? 52
>> +#define CAM_CC_FAST_AHB_CLK_SRC??????????????????? 53
>> +#define CAM_CC_GDSC_CLK??????????????????????? 54
>> +#define CAM_CC_ICP_0_AHB_CLK??????????????????? 55
>> +#define CAM_CC_ICP_0_CLK??????????????????? 56
>> +#define CAM_CC_ICP_0_CLK_SRC??????????????????? 57
>> +#define CAM_CC_ICP_1_AHB_CLK??????????????????? 58
>> +#define CAM_CC_ICP_1_CLK??????????????????? 59
>> +#define CAM_CC_ICP_1_CLK_SRC??????????????????? 60
>> +#define CAM_CC_IFE_LITE_AHB_CLK??????????????????? 61
>> +#define CAM_CC_IFE_LITE_CLK??????????????????? 62
>> +#define CAM_CC_IFE_LITE_CLK_SRC??????????????????? 63
>> +#define CAM_CC_IFE_LITE_CPHY_RX_CLK??????????????? 64
>> +#define CAM_CC_IFE_LITE_CSID_CLK??????????????? 65
>> +#define CAM_CC_IFE_LITE_CSID_CLK_SRC??????????????? 66
>> +#define CAM_CC_IPE_NPS_AHB_CLK??????????????????? 67
>> +#define CAM_CC_IPE_NPS_CLK??????????????????? 68
>> +#define CAM_CC_IPE_NPS_CLK_SRC??????????????????? 69
>> +#define CAM_CC_IPE_NPS_FAST_AHB_CLK??????????????? 70
>> +#define CAM_CC_IPE_PPS_CLK??????????????????? 71
>> +#define CAM_CC_IPE_PPS_FAST_AHB_CLK??????????????? 72
>> +#define CAM_CC_JPEG_0_CLK??????????????????? 73
>> +#define CAM_CC_JPEG_1_CLK??????????????????? 74
>> +#define CAM_CC_JPEG_CLK_SRC??????????????????? 75
>> +#define CAM_CC_OFE_AHB_CLK??????????????????? 76
>> +#define CAM_CC_OFE_ANCHOR_CLK??????????????????? 77
>> +#define CAM_CC_OFE_ANCHOR_FAST_AHB_CLK??????????????? 78
>> +#define CAM_CC_OFE_CLK_SRC??????????????????? 79
>> +#define CAM_CC_OFE_HDR_CLK??????????????????? 80
>> +#define CAM_CC_OFE_HDR_FAST_AHB_CLK??????????????? 81
>> +#define CAM_CC_OFE_MAIN_CLK??????????????????? 82
>> +#define CAM_CC_OFE_MAIN_FAST_AHB_CLK??????????????? 83
>> +#define CAM_CC_PLL0??????????????????????? 84
>> +#define CAM_CC_PLL0_OUT_EVEN??????????????????? 85
>> +#define CAM_CC_PLL0_OUT_ODD??????????????????? 86
>> +#define CAM_CC_PLL1??????????????????????? 87
>> +#define CAM_CC_PLL1_OUT_EVEN??????????????????? 88
>> +#define CAM_CC_PLL2??????????????????????? 89
>> +#define CAM_CC_PLL2_OUT_EVEN??????????????????? 90
>> +#define CAM_CC_PLL3??????????????????????? 91
>> +#define CAM_CC_PLL3_OUT_EVEN??????????????????? 92
>> +#define CAM_CC_PLL4??????????????????????? 93
>> +#define CAM_CC_PLL4_OUT_EVEN??????????????????? 94
>> +#define CAM_CC_PLL5??????????????????????? 95
>> +#define CAM_CC_PLL5_OUT_EVEN??????????????????? 96
>> +#define CAM_CC_PLL6??????????????????????? 97
>> +#define CAM_CC_PLL6_OUT_EVEN??????????????????? 98
>> +#define CAM_CC_PLL6_OUT_ODD??????????????????? 99
>> +#define CAM_CC_QDSS_DEBUG_CLK??????????????????? 100
>> +#define CAM_CC_QDSS_DEBUG_CLK_SRC??????????????? 101
>> +#define CAM_CC_QDSS_DEBUG_XO_CLK??????????????? 102
>> +#define CAM_CC_SLEEP_CLK??????????????????? 103
>> +#define CAM_CC_SLEEP_CLK_SRC??????????????????? 104
>> +#define CAM_CC_SLOW_AHB_CLK_SRC??????????????????? 105
>> +#define CAM_CC_TFE_0_BAYER_CLK??????????????????? 106
>> +#define CAM_CC_TFE_0_BAYER_FAST_AHB_CLK??????????????? 107
>> +#define CAM_CC_TFE_0_CLK_SRC??????????????????? 108
>> +#define CAM_CC_TFE_0_MAIN_CLK??????????????????? 109
>> +#define CAM_CC_TFE_0_MAIN_FAST_AHB_CLK??????????????? 110
>> +#define CAM_CC_TFE_1_BAYER_CLK??????????????????? 111
>> +#define CAM_CC_TFE_1_BAYER_FAST_AHB_CLK??????????????? 112
>> +#define CAM_CC_TFE_1_CLK_SRC??????????????????? 113
>> +#define CAM_CC_TFE_1_MAIN_CLK??????????????????? 114
>> +#define CAM_CC_TFE_1_MAIN_FAST_AHB_CLK??????????????? 115
>> +#define CAM_CC_TFE_2_BAYER_CLK??????????????????? 116
>> +#define CAM_CC_TFE_2_BAYER_FAST_AHB_CLK??????????????? 117
>> +#define CAM_CC_TFE_2_CLK_SRC??????????????????? 118
>> +#define CAM_CC_TFE_2_MAIN_CLK??????????????????? 119
>> +#define CAM_CC_TFE_2_MAIN_FAST_AHB_CLK??????????????? 120
>> +#define CAM_CC_XO_CLK_SRC??????????????????? 121
>> +
>> +/* CAM_CC power domains */
>> +#define CAM_CC_TITAN_TOP_GDSC??????????????????? 0
>> +#define CAM_CC_IPE_0_GDSC??????????????????? 1
>> +#define CAM_CC_OFE_GDSC??????????????????????? 2
>> +#define CAM_CC_TFE_0_GDSC??????????????????? 3
>> +#define CAM_CC_TFE_1_GDSC??????????????????? 4
>> +#define CAM_CC_TFE_2_GDSC??????????????????? 5
>> +
>> +/* CAM_CC resets */
>> +#define CAM_CC_DRV_BCR??????????????????????? 0
>> +#define CAM_CC_ICP_BCR??????????????????????? 1
>> +#define CAM_CC_IPE_0_BCR??????????????????? 2
>> +#define CAM_CC_OFE_BCR??????????????????????? 3
>> +#define CAM_CC_QDSS_DEBUG_BCR??????????????????? 4
>> +#define CAM_CC_TFE_0_BCR??????????????????? 5
>> +#define CAM_CC_TFE_1_BCR??????????????????? 6
>> +#define CAM_CC_TFE_2_BCR??????????????????? 7
>> +
>> +#endif
>>
> 

-- 
Thanks,
Taniya Das



From ck.hu at mediatek.com  Wed Dec 17 01:59:05 2025
From: ck.hu at mediatek.com (=?utf-8?B?Q0sgSHUgKOiDoeS/iuWFiSk=?=)
Date: Wed, 17 Dec 2025 09:59:05 +0000
Subject: [PATCH v7 1/2] drm/mediatek: Adjust bandwidth limit for DP
In-Reply-To: <f4e8ba2e9f9a8e5fd4b35afe25b9874c64c6ea17.camel@mediatek.com>
References: <20251104085957.1175-1-liankun.yang@mediatek.com>
	 <20251104085957.1175-2-liankun.yang@mediatek.com>
	 <18cd9c74699b5afe4d0bff9a6c325389d2881e29.camel@mediatek.com>
	 <dfd8767809d52efee2e7592e4b45cfd2425334b8.camel@mediatek.com>
	 <54b075b4ff6b9aa7cd916bb65e34e5edae3642dc.camel@mediatek.com>
	 <f4e8ba2e9f9a8e5fd4b35afe25b9874c64c6ea17.camel@mediatek.com>
Message-ID: <63a3900c13c329fd04ac2fac838ef6058b5e2d5d.camel@mediatek.com>

On Mon, 2025-12-01 at 06:39 +0000, LIANKUN YANG (???) wrote:
> On Wed, 2025-11-26 at 03:11 +0000, CK Hu (???) wrote:
> > On Mon, 2025-11-24 at 09:14 +0000, LIANKUN YANG (???) wrote:
> > > On Wed, 2025-11-19 at 09:18 +0000, CK Hu (???) wrote:
> > > > On Tue, 2025-11-04 at 16:55 +0800, Liankun Yang wrote:
> > > > > By adjusting the order of link training and relocating it to
> > > > > HPD,
> > > > > link training can identify the usability of each lane in the
> > > > > current link.
> > > > > 
> > > > > It also supports handling signal instability and weakness due
> > > > > to
> > > > > environmental issues, enabling the acquisition of a stable
> > > > > bandwidth
> > > > > for the current link. Subsequently, DP work can proceed based
> > > > > on
> > > > > the actual maximum bandwidth.
> > > > > 
> > > > > It should training in the hpd event thread.
> > > > > Check the mode with lane count and link rate of training.
> > > > > 
> > > > > If we're eDP and capabilities were already parsed we can skip
> > > > > reading again because eDP panels aren't hotpluggable hence the
> > > > > caps and training information won't ever change in a boot life
> > > > > 
> > > > > Therefore, bridge typec judgment is required for edp training
> > > > > in
> > > > > atomic_enable function.
> > > > > 
> > > > > The `mtk_dp_aux_panel_poweron` function fails to align.
> > > > > Within the `mtk_dp_hpd_event_thread`, if DP is disconnected,
> > > > > the `mtk_dp_aux_panel_poweron` function will write from `aux`
> > > > > to
> > > > > `DPRX`,
> > > > > causing a failure and thus preventing symmetry.
> > > > 
> > > > I'm curious about another case.
> > > > In your description, when DP plug out and plug in, DRM core would
> > > > not
> > > > call mtk_dp_bridge_atomic_enable(), right?
> > > > If so, when I plug out DP, and plug in another DP panel which
> > > > support
> > > > smaller resolution,
> > > > then mtk_dp_bridge_atomic_enable() is not called and below call
> > > > sequence would not happen:
> > > > 
> > > > mtk_dp_bridge_atomic_enable() -> mtk_dp_video_enable() ->
> > > > mtk_dp_set_tx_out() -> mtk_dp_setup_tu()
> > > > 
> > > > In mtk_dp_setup_tu, it would set sram_read_start according to
> > > > lane_count.
> > > > But the call sequence would not happen when new plug in, the
> > > > sram_read_start would be old value which may incorrect.
> > > > If think that when plug in and plug out, it should disable DP and
> > > > then enable DP again.
> > > > If DRM core does not do this, I think we should modify DRM core
> > > > or
> > > > you should reconfig the whole DP when plug in, not only training.
> > > > 
> > > > Regards,
> > > > CK
> > > > 
> > > 
> > > Hi CK
> > > 
> > > When DP plug out, DRM core will call
> > > mtk_dp_bridge_atomic_disable().
> > > When DP plug in, DRM core will call mtk_dp_bridge_atomic_enable().
> > 
> > 
> > When DP plug in, DRM core will call mtk_dp_bridge_atomic_enable(),
> > and mtk_dp_bridge_atomic_enable would call mtk_dp_training().
> > So it's not necessary to call mtk_dp_training() in
> > mtk_dp_hpd_event_thread().
> > 
> > Regards,
> > CK
> > 
> 
> Hi CK.
> 
> This shows the current timings after the DP cable is plugged in,
> as well as the modified timings.
> 
> current timings:		Fix timings:
> 
> mtk_dp_hpd_event_thread()	mtk_dp_hpd_event_thread()
> 				(including DP link training) 
> 	|				|
>        ...			       ...
> mtk_dp_bridge_mode_valid()	mtk_dp_bridge_mode_valid()
> 	|
>        ...			       ...
> mtk_dp_bridge_atomic_check()	mtk_dp_bridge_atomic_check()
> 	|
>        ...			       ...
> mtk_dp_bridge_atomic_enable()	mtk_dp_bridge_atomic_enable()
> (including DP link training)
> 
> 
> PS:
> 1. "..." represents ommited steps;
> 
> 2. `mtk_dp_bridge_mode_valid()` calculates the bandwidth using the
> current lane count and link rate, and then filters each mode to
> determine if it supports returning a status.
> 
> 3. In the `drm_display_mode_to_videomode(&crtc_state->adjusted_mode,
> &mtk_dp->info.vm);` function, within the `mtk_dp_bridge_atomic_check()`
> function, `adjusted_mode` sets the currently selected display mode for
> the DRM.
> 
> 4. DP link training tests the signal conditions of the link between
> DPTX and DPRX, and selects the lane count and link rate that meet
> the signal conditions.
> 
> 5. For example, the platform support DP 4lane 5.4G,
> but panel A support DP 2lane 5.4G.
> 
>    This is a time sequence:
> 
>    a).Plug in panel A. According to the platform, it can output 4K
>    60Hz.
>    b). Timing mode set 4K 60Hz(Including in mtk_dp_bridge_atomic_check
>    function).
>    c). Atomic enable(Based on panel A ability, training pass 2lane
>    5.4G).
>    d). Finally, due to 2lane 5.4G bandwidth limitation, the platform
>    cannot output 4K 60Hz, resulting in a black sreen.
> 
>    If apply this patch.
> 
>    a). Plug in panel A.
>    b). Training pass 2lane 5.4G
>    c). Timing mode set 2K 60Hz(Based on the 2lane 5.4G bandwidth limit
>    and including in mtk_dp_bridge_atomic_check function).
>    d). Atomic enable for output screen.

The original commit message does not show WHY need to training in hotplug thread.
This explain shows WHY need to training in hotplug thread.
So replace the commit message with this explain.

Regards,
CK

> 
> Best Regards
> Liankun.
> 
> > > 
> > > If DP plug in, sram_read_start will be recalculate based on the
> > > lane
> > > count.
> > > 
> > > Regards
> > > Liankun.
> > > 
> > > > 
> > > > > 
> > > > > Signed-off-by: Liankun Yang <liankun.yang at mediatek.com>
> > > > > ---
> > > > > ---
> > > > >  drivers/gpu/drm/mediatek/mtk_dp.c | 20 ++++++++++++++++++++
> > > > >  1 file changed, 20 insertions(+)
> > > > > 
> > > > > diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c
> > > > > b/drivers/gpu/drm/mediatek/mtk_dp.c
> > > > > index bef6eeb30d3e..0ba2c208811c 100644
> > > > > --- a/drivers/gpu/drm/mediatek/mtk_dp.c
> > > > > +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
> > > > > @@ -1976,6 +1976,7 @@ static irqreturn_t
> > > > > mtk_dp_hpd_event_thread(int hpd, void *dev)
> > > > >  	struct mtk_dp *mtk_dp = dev;
> > > > >  	unsigned long flags;
> > > > >  	u32 status;
> > > > > +	int ret;
> > > > >  
> > > > >  	if (mtk_dp->need_debounce && mtk_dp-
> > > > > > train_info.cable_plugged_in)
> > > > > 
> > > > >  		msleep(100);
> > > > > @@ -1994,9 +1995,28 @@ static irqreturn_t
> > > > > mtk_dp_hpd_event_thread(int hpd, void *dev)
> > > > >  			memset(&mtk_dp->info.audio_cur_cfg, 0,
> > > > >  			       sizeof(mtk_dp-
> > > > > > info.audio_cur_cfg));
> > > > >  
> > > > > +			mtk_dp->enabled = false;
> > > > > +			/* power off aux */
> > > > > +			mtk_dp_update_bits(mtk_dp,
> > > > > MTK_DP_TOP_PWR_STATE,
> > > > > +					   DP_PWR_STATE_BANDGAP
> > > > > _TPLL,
> > > > > +					   DP_PWR_STATE_MASK);
> > > > > +
> > > > >  			mtk_dp->need_debounce = false;
> > > > >  			mod_timer(&mtk_dp->debounce_timer,
> > > > >  				  jiffies +
> > > > > msecs_to_jiffies(100) - 1);
> > > > > +		} else {
> > > > > +			mtk_dp_aux_panel_poweron(mtk_dp, true);
> > > > > +
> > > > > +			ret =
> > > > > mtk_dp_parse_capabilities(mtk_dp);
> > > > > +			if (ret)
> > > > > +				drm_err(mtk_dp->drm_dev, "Can't
> > > > > parse
> > > > > capabilities\n");
> > > > > +
> > > > > +			/* Training */
> > > > > +			ret = mtk_dp_training(mtk_dp);
> > > > > +			if (ret)
> > > > > +				drm_err(mtk_dp->drm_dev,
> > > > > "Training
> > > > > failed, %d\n", ret);
> > > > > +
> > > > > +			mtk_dp->enabled = true;
> > > > >  		}
> > > > >  	}
> > > > >  
> > > > 
> > > > 
> > 
> > 


From damon.ding at rock-chips.com  Wed Dec 17 01:59:08 2025
From: damon.ding at rock-chips.com (Damon Ding)
Date: Wed, 17 Dec 2025 17:59:08 +0800
Subject: [PATCH v8 14/18] drm/rockchip: analogix_dp: Apply analogix_dp_finish_probe()
In-Reply-To: <20251217093321.3108939-1-damon.ding@rock-chips.com>
References: <20251217093321.3108939-1-damon.ding@rock-chips.com>
Message-ID: <20251217095912.3109103-1-damon.ding@rock-chips.com>

Apply analogix_dp_finish_probe() in order to move the panel/bridge
parsing from Rockchip side to the Analogix side.

Signed-off-by: Damon Ding <damon.ding at rock-chips.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>

---

Changes in v4:
- Rename analogix_dp_find_panel_or_bridge() to
  analogix_dp_finish_probe().

Changes in v5:
- Remove DRM_DISPLAY_DP_AUX_BUS for ROCKCHIP_ANALOGIX_DP
---
 .../gpu/drm/rockchip/analogix_dp-rockchip.c   | 38 +------------------
 1 file changed, 2 insertions(+), 36 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 7fa17ba26c46..832e9766bef0 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -21,14 +21,12 @@
 #include <video/of_videomode.h>
 #include <video/videomode.h>
 
-#include <drm/display/drm_dp_aux_bus.h>
 #include <drm/display/drm_dp_helper.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_bridge_connector.h>
 #include <drm/bridge/analogix_dp.h>
 #include <drm/drm_of.h>
-#include <drm/drm_panel.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
 #include <drm/drm_simple_kms_helper.h>
@@ -417,24 +415,6 @@ static const struct component_ops rockchip_dp_component_ops = {
 	.unbind = rockchip_dp_unbind,
 };
 
-static int rockchip_dp_link_panel(struct drm_dp_aux *aux)
-{
-	struct analogix_dp_plat_data *plat_data = analogix_dp_aux_to_plat_data(aux);
-	struct rockchip_dp_device *dp = pdata_encoder_to_dp(plat_data);
-	int ret;
-
-	/*
-	 * If drm_of_find_panel_or_bridge() returns -ENODEV, there may be no valid panel
-	 * or bridge nodes. The driver should go on for the driver-free bridge or the DP
-	 * mode applications.
-	 */
-	ret = drm_of_find_panel_or_bridge(dp->dev->of_node, 1, 0, &plat_data->panel, NULL);
-	if (ret && ret != -ENODEV)
-		return ret;
-
-	return component_add(dp->dev, &rockchip_dp_component_ops);
-}
-
 static int rockchip_dp_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -473,6 +453,7 @@ static int rockchip_dp_probe(struct platform_device *pdev)
 	dp->plat_data.dev_type = dp->data->chip_type;
 	dp->plat_data.power_on = rockchip_dp_poweron;
 	dp->plat_data.power_off = rockchip_dp_powerdown;
+	dp->plat_data.ops = &rockchip_dp_component_ops;
 
 	ret = rockchip_dp_of_probe(dp);
 	if (ret < 0)
@@ -484,22 +465,7 @@ static int rockchip_dp_probe(struct platform_device *pdev)
 	if (IS_ERR(dp->adp))
 		return PTR_ERR(dp->adp);
 
-	ret = devm_of_dp_aux_populate_bus(analogix_dp_get_aux(dp->adp), rockchip_dp_link_panel);
-	if (ret) {
-		/*
-		 * If devm_of_dp_aux_populate_bus() returns -ENODEV, the done_probing() will not
-		 * be called because there are no EP devices. Then the rockchip_dp_link_panel()
-		 * will be called directly in order to support the other valid DT configurations.
-		 *
-		 * NOTE: The devm_of_dp_aux_populate_bus() is allowed to return -EPROBE_DEFER.
-		 */
-		if (ret != -ENODEV)
-			return dev_err_probe(dp->dev, ret, "failed to populate aux bus\n");
-
-		return rockchip_dp_link_panel(analogix_dp_get_aux(dp->adp));
-	}
-
-	return 0;
+	return analogix_dp_finish_probe(dp->adp);
 }
 
 static void rockchip_dp_remove(struct platform_device *pdev)
-- 
2.34.1



From damon.ding at rock-chips.com  Wed Dec 17 01:59:09 2025
From: damon.ding at rock-chips.com (Damon Ding)
Date: Wed, 17 Dec 2025 17:59:09 +0800
Subject: [PATCH v8 15/18] drm/exynos: exynos_dp: Apply analogix_dp_finish_probe()
In-Reply-To: <20251217095912.3109103-1-damon.ding@rock-chips.com>
References: <20251217093321.3108939-1-damon.ding@rock-chips.com>
 <20251217095912.3109103-1-damon.ding@rock-chips.com>
Message-ID: <20251217095912.3109103-2-damon.ding@rock-chips.com>

Apply analogix_dp_finish_probe() in order to move the panel/bridge
parsing from Exynos side to the Analogix side.

Signed-off-by: Damon Ding <damon.ding at rock-chips.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Tested-by: Marek Szyprowski <m.szyprowski at samsung.com>

---

Changes in v4:
- Rename analogix_dp_find_panel_or_bridge() to
  analogix_dp_finish_probe().

Changes in v7:
- Remove exynos_dp_legacy_bridge_init() and inline API
  devm_drm_of_display_mode_bridge().
- If the panel or the next_bridge is parsed from DT, use ptr validity
  to check whether to call component_add() directly at the end of
  probing.
---
 drivers/gpu/drm/exynos/exynos_dp.c | 19 ++++++++-----------
 1 file changed, 8 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index 478eaa6f3175..6126820aad3b 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -157,9 +157,6 @@ static int exynos_dp_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct device_node *np;
 	struct exynos_dp_device *dp;
-	struct drm_panel *panel;
-	struct drm_bridge *bridge;
-	int ret;
 
 	dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device),
 			  GFP_KERNEL);
@@ -186,30 +183,30 @@ static int exynos_dp_probe(struct platform_device *pdev)
 		goto out;
 	}
 
-	ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &panel, &bridge);
-	if (ret == -ENODEV) {
+	if (of_get_display_timings(dev->of_node)) {
 		dp->plat_data.next_bridge = devm_drm_of_display_mode_bridge(dp->dev,
 									dp->dev->of_node,
 									DRM_MODE_CONNECTOR_eDP);
-		ret = IS_ERR(dp->plat_data.next_bridge) ? PTR_ERR(dp->plat_data.next_bridge) : 0;
+		if (IS_ERR(dp->plat_data.next_bridge))
+			return PTR_ERR(dp->plat_data.next_bridge);
 	}
-	if (ret)
-		return ret;
 
 	/* The remote port can be either a panel or a bridge */
-	dp->plat_data.panel = panel;
-	dp->plat_data.next_bridge = bridge;
 	dp->plat_data.dev_type = EXYNOS_DP;
 	dp->plat_data.power_on = exynos_dp_poweron;
 	dp->plat_data.power_off = exynos_dp_poweroff;
 	dp->plat_data.attach = exynos_dp_bridge_attach;
+	dp->plat_data.ops = &exynos_dp_ops;
 
 out:
 	dp->adp = analogix_dp_probe(dev, &dp->plat_data);
 	if (IS_ERR(dp->adp))
 		return PTR_ERR(dp->adp);
 
-	return component_add(&pdev->dev, &exynos_dp_ops);
+	if (dp->plat_data.panel || dp->plat_data.next_bridge)
+		return component_add(&pdev->dev, &exynos_dp_ops);
+	else
+		return analogix_dp_finish_probe(dp->adp);
 }
 
 static void exynos_dp_remove(struct platform_device *pdev)
-- 
2.34.1



From damon.ding at rock-chips.com  Wed Dec 17 01:59:10 2025
From: damon.ding at rock-chips.com (Damon Ding)
Date: Wed, 17 Dec 2025 17:59:10 +0800
Subject: [PATCH v8 16/18] drm/bridge: analogix_dp: Attach the next bridge in analogix_dp_bridge_attach()
In-Reply-To: <20251217095912.3109103-1-damon.ding@rock-chips.com>
References: <20251217093321.3108939-1-damon.ding@rock-chips.com>
 <20251217095912.3109103-1-damon.ding@rock-chips.com>
Message-ID: <20251217095912.3109103-3-damon.ding@rock-chips.com>

Uniformly, move the next bridge attachment to the Analogix side
rather than scattered on Rockchip and Exynos sides. It can also
help get rid of the callback &analogix_dp_plat_data.attach() and
make codes more concise.

Signed-off-by: Damon Ding <damon.ding at rock-chips.com>
Tested-by: Marek Szyprowski <m.szyprowski at samsung.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>

------

Changes in v6:
- Move the next bridge attachment to the Analogix side rather than
  scattered on Rockchip and Exynos sides.
---
 .../gpu/drm/bridge/analogix/analogix_dp_core.c |  7 ++++---
 drivers/gpu/drm/exynos/exynos_dp.c             | 18 ------------------
 include/drm/bridge/analogix_dp.h               |  1 -
 3 files changed, 4 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 933f1843777f..a6c5601e16ff 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -930,10 +930,11 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge,
 		return -EINVAL;
 	}
 
-	if (dp->plat_data->attach) {
-		ret = dp->plat_data->attach(dp->plat_data, bridge);
+	if (dp->plat_data->next_bridge) {
+		ret = drm_bridge_attach(dp->encoder, dp->plat_data->next_bridge, bridge,
+					DRM_BRIDGE_ATTACH_NO_CONNECTOR);
 		if (ret) {
-			DRM_ERROR("Failed at platform attach func\n");
+			dev_err(dp->dev, "failed to attach following panel or bridge (%d)\n", ret);
 			return ret;
 		}
 	}
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index 6126820aad3b..6884ea6d04eb 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -68,23 +68,6 @@ static int exynos_dp_poweroff(struct analogix_dp_plat_data *plat_data)
 	return exynos_dp_crtc_clock_enable(plat_data, false);
 }
 
-static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
-				   struct drm_bridge *bridge)
-{
-	struct exynos_dp_device *dp = to_dp(plat_data);
-	int ret;
-
-	/* Pre-empt DP connector creation if there's a bridge */
-	if (plat_data->next_bridge) {
-		ret = drm_bridge_attach(&dp->encoder, plat_data->next_bridge, bridge,
-					DRM_BRIDGE_ATTACH_NO_CONNECTOR);
-		if (ret)
-			return ret;
-	}
-
-	return 0;
-}
-
 static void exynos_dp_mode_set(struct drm_encoder *encoder,
 			       struct drm_display_mode *mode,
 			       struct drm_display_mode *adjusted_mode)
@@ -195,7 +178,6 @@ static int exynos_dp_probe(struct platform_device *pdev)
 	dp->plat_data.dev_type = EXYNOS_DP;
 	dp->plat_data.power_on = exynos_dp_poweron;
 	dp->plat_data.power_off = exynos_dp_poweroff;
-	dp->plat_data.attach = exynos_dp_bridge_attach;
 	dp->plat_data.ops = &exynos_dp_ops;
 
 out:
diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h
index bae969dec63a..854af692229b 100644
--- a/include/drm/bridge/analogix_dp.h
+++ b/include/drm/bridge/analogix_dp.h
@@ -34,7 +34,6 @@ struct analogix_dp_plat_data {
 
 	int (*power_on)(struct analogix_dp_plat_data *);
 	int (*power_off)(struct analogix_dp_plat_data *);
-	int (*attach)(struct analogix_dp_plat_data *, struct drm_bridge *);
 };
 
 int analogix_dp_resume(struct analogix_dp_device *dp);
-- 
2.34.1



From damon.ding at rock-chips.com  Wed Dec 17 01:59:11 2025
From: damon.ding at rock-chips.com (Damon Ding)
Date: Wed, 17 Dec 2025 17:59:11 +0800
Subject: [PATCH v8 17/18] drm/bridge: analogix_dp: Remove bridge disabing and panel unpreparing in analogix_dp_unbind()
In-Reply-To: <20251217095912.3109103-1-damon.ding@rock-chips.com>
References: <20251217093321.3108939-1-damon.ding@rock-chips.com>
 <20251217095912.3109103-1-damon.ding@rock-chips.com>
Message-ID: <20251217095912.3109103-4-damon.ding@rock-chips.com>

The analogix_dp_unbind() should be balanced with analogix_dp_bind().
There are no bridge enabling and panel preparing in analogix_dp_bind(),
so it should be reasonable to remove the bridge disabing and panel
unpreparing in analogix_dp_unbind().

Signed-off-by: Damon Ding <damon.ding at rock-chips.com>
Tested-by: Marek Szyprowski <m.szyprowski at samsung.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
---
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index a6c5601e16ff..7e3e9d4f4ea2 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1526,10 +1526,6 @@ EXPORT_SYMBOL_GPL(analogix_dp_bind);
 
 void analogix_dp_unbind(struct analogix_dp_device *dp)
 {
-	analogix_dp_bridge_disable(&dp->bridge);
-
-	drm_panel_unprepare(dp->plat_data->panel);
-
 	drm_dp_aux_unregister(&dp->aux);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_unbind);
-- 
2.34.1



From damon.ding at rock-chips.com  Wed Dec 17 01:59:12 2025
From: damon.ding at rock-chips.com (Damon Ding)
Date: Wed, 17 Dec 2025 17:59:12 +0800
Subject: [PATCH v8 18/18] drm/bridge: analogix_dp: Apply panel_bridge helper
In-Reply-To: <20251217095912.3109103-1-damon.ding@rock-chips.com>
References: <20251217093321.3108939-1-damon.ding@rock-chips.com>
 <20251217095912.3109103-1-damon.ding@rock-chips.com>
Message-ID: <20251217095912.3109103-5-damon.ding@rock-chips.com>

In order to unify the handling of the panel and bridge, apply
panel_bridge helpers for Analogix DP driver. With this patch, the
bridge support will also become available.

The following changes have ben made:
- Apply plane_bridge helper to wrap the panel as the bridge.
- Remove the explicit panel APIs calls, which can be replaced with
  the automic bridge APIs calls wrapped by the panel.
- Remove the unnecessary analogix_dp_bridge_get_modes().

Signed-off-by: Damon Ding <damon.ding at rock-chips.com>
Tested-by: Marek Szyprowski <m.szyprowski at samsung.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>

---

Changes in v4:
- Rename the &analogix_dp_plat_data.bridge to
  &analogix_dp_plat_data.next_bridge.

Changes in v5:
- Move panel_bridge addition a little forward.
- Move next_bridge attachment from Analogix side to Rockchip/Exynos
  side.

Changes in v6
- Remove the unnecessary analogix_dp_bridge_get_modes().
- Not to set DRM_BRIDGE_OP_MODES if the next is a panel.
- Squash [PATCH v5 15/17]drm/bridge: analogix_dp: Remove panel
  disabling and enabling in analogix_dp_set_bridge() into this
  commit.
- Fix the &drm_bridge->ops to DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT.
---
 .../drm/bridge/analogix/analogix_dp_core.c    | 41 +++++--------------
 1 file changed, 11 insertions(+), 30 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 7e3e9d4f4ea2..d2ea93e1c9a3 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -749,9 +749,6 @@ static int analogix_dp_commit(struct analogix_dp_device *dp)
 {
 	int ret;
 
-	/* Keep the panel disabled while we configure video */
-	drm_panel_disable(dp->plat_data->panel);
-
 	ret = analogix_dp_train_link(dp);
 	if (ret) {
 		dev_err(dp->dev, "unable to do link train, ret=%d\n", ret);
@@ -771,9 +768,6 @@ static int analogix_dp_commit(struct analogix_dp_device *dp)
 		return ret;
 	}
 
-	/* Safe to enable the panel now */
-	drm_panel_enable(dp->plat_data->panel);
-
 	/* Check whether panel supports fast training */
 	ret = analogix_dp_fast_link_train_detection(dp);
 	if (ret)
@@ -858,17 +852,6 @@ static int analogix_dp_disable_psr(struct analogix_dp_device *dp)
 	return analogix_dp_send_psr_spd(dp, &psr_vsc, true);
 }
 
-static int analogix_dp_bridge_get_modes(struct drm_bridge *bridge, struct drm_connector *connector)
-{
-	struct analogix_dp_device *dp = to_dp(bridge);
-	int num_modes = 0;
-
-	if (dp->plat_data->panel)
-		num_modes += drm_panel_get_modes(dp->plat_data->panel, connector);
-
-	return num_modes;
-}
-
 static const struct drm_edid *analogix_dp_bridge_edid_read(struct drm_bridge *bridge,
 							   struct drm_connector *connector)
 {
@@ -909,7 +892,7 @@ analogix_dp_bridge_detect(struct drm_bridge *bridge, struct drm_connector *conne
 	struct analogix_dp_device *dp = to_dp(bridge);
 	enum drm_connector_status status = connector_status_disconnected;
 
-	if (dp->plat_data->panel || dp->plat_data->next_bridge)
+	if (dp->plat_data->next_bridge)
 		return connector_status_connected;
 
 	if (!analogix_dp_detect_hpd(dp))
@@ -995,8 +978,6 @@ static void analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge,
 	/* Don't touch the panel if we're coming back from PSR */
 	if (old_crtc_state && old_crtc_state->self_refresh_active)
 		return;
-
-	drm_panel_prepare(dp->plat_data->panel);
 }
 
 static int analogix_dp_set_bridge(struct analogix_dp_device *dp)
@@ -1168,16 +1149,12 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
 	if (dp->dpms_mode != DRM_MODE_DPMS_ON)
 		return;
 
-	drm_panel_disable(dp->plat_data->panel);
-
 	disable_irq(dp->irq);
 
 	analogix_dp_set_analog_power_down(dp, POWER_ALL, 1);
 
 	pm_runtime_put_sync(dp->dev);
 
-	drm_panel_unprepare(dp->plat_data->panel);
-
 	dp->fast_train_enable = false;
 	dp->psr_supported = false;
 	dp->dpms_mode = DRM_MODE_DPMS_OFF;
@@ -1252,7 +1229,6 @@ static const struct drm_bridge_funcs analogix_dp_bridge_funcs = {
 	.atomic_post_disable = analogix_dp_bridge_atomic_post_disable,
 	.atomic_check = analogix_dp_bridge_atomic_check,
 	.attach = analogix_dp_bridge_attach,
-	.get_modes = analogix_dp_bridge_get_modes,
 	.edid_read = analogix_dp_bridge_edid_read,
 	.detect = analogix_dp_bridge_detect,
 };
@@ -1498,17 +1474,22 @@ int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev)
 		return ret;
 	}
 
-	if (dp->plat_data->panel)
-		bridge->ops = DRM_BRIDGE_OP_MODES | DRM_BRIDGE_OP_DETECT;
-	else
-		bridge->ops = DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT;
-
+	bridge->ops = DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT;
 	bridge->of_node = dp->dev->of_node;
 	bridge->type = DRM_MODE_CONNECTOR_eDP;
 	ret = devm_drm_bridge_add(dp->dev, &dp->bridge);
 	if (ret)
 		goto err_unregister_aux;
 
+	if (dp->plat_data->panel) {
+		dp->plat_data->next_bridge = devm_drm_panel_bridge_add(dp->dev,
+								       dp->plat_data->panel);
+		if (IS_ERR(dp->plat_data->next_bridge)) {
+			ret = PTR_ERR(bridge);
+			goto err_unregister_aux;
+		}
+	}
+
 	ret = drm_bridge_attach(dp->encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
 	if (ret) {
 		DRM_ERROR("failed to create bridge (%d)\n", ret);
-- 
2.34.1



From ryan.roberts at arm.com  Wed Dec 17 02:01:30 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Wed, 17 Dec 2025 10:01:30 +0000
Subject: [PATCH v6 14/14] mm: Add basic tests for lazy_mmu
In-Reply-To: <f9550d22-8810-4145-aaa8-48961f6ea35e@arm.com>
References: <20251215150323.2218608-1-kevin.brodsky@arm.com>
 <20251215150323.2218608-15-kevin.brodsky@arm.com>
 <20251216201403.4647a4f9861d3122ee9e90d7@linux-foundation.org>
 <f9550d22-8810-4145-aaa8-48961f6ea35e@arm.com>
Message-ID: <ca0da7fd-245c-4d52-8f4d-f8fce4717494@arm.com>

On 17/12/2025 09:26, Kevin Brodsky wrote:
> On 17/12/2025 05:14, Andrew Morton wrote:
>> On Mon, 15 Dec 2025 15:03:23 +0000 Kevin Brodsky <kevin.brodsky at arm.com> wrote:
>>
>>> Add basic KUnit tests for the generic aspects of the lazy MMU mode:
>>> ensure that it appears active when it should, depending on how
>>> enable/disable and pause/resume pairs are nested.
>> I needed this for powerpc allmodconfig;
>>
>> --- a/arch/powerpc/mm/book3s64/hash_tlb.c~mm-add-basic-tests-for-lazy_mmu-fix
>> +++ a/arch/powerpc/mm/book3s64/hash_tlb.c
>> @@ -30,6 +30,7 @@
>>  #include <trace/events/thp.h>
>>  
>>  DEFINE_PER_CPU(struct ppc64_tlb_batch, ppc64_tlb_batch);
>> +EXPORT_SYMBOL_GPL(ppc64_tlb_batch);
>>  
>>  /*
>>   * A linux PTE was changed and the corresponding hash table entry
>> @@ -154,6 +155,7 @@ void __flush_tlb_pending(struct ppc64_tl
>>  		flush_hash_range(i, local);
>>  	batch->index = 0;
>>  }
>> +EXPORT_SYMBOL_GPL(__flush_tlb_pending);
>>  
>>  void hash__tlb_flush(struct mmu_gather *tlb)
>>  {
>> _
> 
> Oh indeed I hadn't considered that arch_{enter,leave}_lazy_mmu_mode()
> refer to those symbols on powerpc... Maybe a bit overkill to export
> those just for a test module, but I'm not sure there's a good
> alternative. Forcing LAZY_MMU_MODE_KUNIT_TEST=y is ugly as it would also
> force KUNIT=y. Alternatively we could depend on !PPC, not pretty either.

Does EXPORT_SYMBOL_IF_KUNIT() help?

> 
> - Kevin



From ck.hu at mediatek.com  Wed Dec 17 02:08:23 2025
From: ck.hu at mediatek.com (=?utf-8?B?Q0sgSHUgKOiDoeS/iuWFiSk=?=)
Date: Wed, 17 Dec 2025 10:08:23 +0000
Subject: [PATCH v7 2/2] drm/mediatek: Add isolation to edp
In-Reply-To: <20251104085957.1175-3-liankun.yang@mediatek.com>
References: <20251104085957.1175-1-liankun.yang@mediatek.com>
	 <20251104085957.1175-3-liankun.yang@mediatek.com>
Message-ID: <e9f167c88c29fa30ef3a22995c2955cde478b41d.camel@mediatek.com>

On Tue, 2025-11-04 at 16:55 +0800, Liankun Yang wrote:
> Because edp doesn't expect any (un)plug events during runtime and
> its process differs from DP. Therefore, it is necessary to isolate
> the parsing capability, panel power, training state and enable state.
> 
> And DP related behaviors are adjusted to execute in the second half
> of the interrupt.
> For DP details, see drm/mediatek: Adjust bandwidth limit for DP
> 
> Signed-off-by: Liankun Yang <liankun.yang at mediatek.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_dp.c | 37 +++++++++++++++----------------
>  1 file changed, 18 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
> index 0ba2c208811c..efd4c45985ca 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
> @@ -2187,7 +2187,8 @@ static const struct drm_edid *mtk_dp_edid_read(struct drm_bridge *bridge,
>  	 * Parse capability here to let atomic_get_input_bus_fmts and
>  	 * mode_valid use the capability to calculate sink bitrates.
>  	 */
> -	if (mtk_dp_parse_capabilities(mtk_dp)) {
> +	if (mtk_dp->bridge.type == DRM_MODE_CONNECTOR_eDP &&
> +	    mtk_dp_parse_capabilities(mtk_dp)) {

This is not related to dp training.
If dp does not need to parse edid, describe WHY and do not mix edid modification with dp training modification.

>  		drm_err(mtk_dp->drm_dev, "Can't parse capabilities\n");
>  		drm_edid_free(drm_edid);
>  		drm_edid = NULL;
> @@ -2385,13 +2386,15 @@ static void mtk_dp_bridge_atomic_enable(struct drm_bridge *bridge,
>  		return;
>  	}
>  
> -	mtk_dp_aux_panel_poweron(mtk_dp, true);
> +	if (mtk_dp->data->bridge_type == DRM_MODE_CONNECTOR_eDP) {
> +		mtk_dp_aux_panel_poweron(mtk_dp, true);
>  
> -	/* Training */
> -	ret = mtk_dp_training(mtk_dp);
> -	if (ret) {
> -		drm_err(mtk_dp->drm_dev, "Training failed, %d\n", ret);
> -		goto power_off_aux;
> +		/* Training */
> +		ret = mtk_dp_training(mtk_dp);
> +		if (ret) {
> +			drm_err(mtk_dp->drm_dev, "Training failed, %d\n", ret);
> +			goto power_off_aux;
> +		}

Merge this to previous patch.

>  	}
>  
>  	ret = mtk_dp_video_config(mtk_dp);
> @@ -2411,7 +2414,9 @@ static void mtk_dp_bridge_atomic_enable(struct drm_bridge *bridge,
>  		       sizeof(mtk_dp->info.audio_cur_cfg));
>  	}
>  
> -	mtk_dp->enabled = true;
> +	if (mtk_dp->data->bridge_type == DRM_MODE_CONNECTOR_eDP)
> +		mtk_dp->enabled = true;

Merge this to previous patch.

> +
>  	mtk_dp_update_plugged_status(mtk_dp);
>  
>  	return;
> @@ -2426,21 +2431,15 @@ static void mtk_dp_bridge_atomic_disable(struct drm_bridge *bridge,
>  {
>  	struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
>  
> -	mtk_dp->enabled = false;
> +	if (mtk_dp->data->bridge_type == DRM_MODE_CONNECTOR_eDP) {
> +		mtk_dp->enabled = false;

Merge this to previous patch.

> +		mtk_dp_aux_panel_poweron(mtk_dp, false);

You change the code flow of DRM_MODE_CONNECTOR_eDP.
I think you should not change this.

> +	}
> +
>  	mtk_dp_update_plugged_status(mtk_dp);
>  	mtk_dp_video_enable(mtk_dp, false);
>  	mtk_dp_audio_mute(mtk_dp, true);
>  
> -	if (mtk_dp->train_info.cable_plugged_in) {
> -		drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D3);
> -		usleep_range(2000, 3000);

For DRM_MODE_CONNECTOR_DP, you remove this usleep. This may cause side effect.
Doesn't it?

> -	}
> -
> -	/* power off aux */
> -	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
> -			   DP_PWR_STATE_BANDGAP_TPLL,
> -			   DP_PWR_STATE_MASK);

if (mtk_dp->data->bridge_type == DRM_MODE_CONNECTOR_eDP) {
	/* power off aux */
	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
			   DP_PWR_STATE_BANDGAP_TPLL,
			   DP_PWR_STATE_MASK);
}

Regards,
CK

> -
>  	/* SDP path reset sw*/
>  	mtk_dp_sdp_path_reset(mtk_dp);
>  


From krzk at kernel.org  Wed Dec 17 02:09:21 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 17 Dec 2025 11:09:21 +0100
Subject: [PATCH v2 07/11] dt-bindings: clock: qcom: document the Kaanapali
 GPU Clock Controller
In-Reply-To: <503f445e-0d12-407d-bc77-f48ad335639b@oss.qualcomm.com>
References: <20251125-kaanapali-mmcc-v2-v2-0-fb44e78f300b@oss.qualcomm.com>
 <20251125-kaanapali-mmcc-v2-v2-7-fb44e78f300b@oss.qualcomm.com>
 <20251126-elated-stoic-scorpion-25b630@kuoka>
 <de44560d-4ed8-41fe-be7b-56412b933a8c@oss.qualcomm.com>
 <fbe39eac-7c92-4a08-bafb-31e5c51a0613@kernel.org>
 <503f445e-0d12-407d-bc77-f48ad335639b@oss.qualcomm.com>
Message-ID: <e8bdb176-b6fb-4dd2-8b5b-9da8073fa915@kernel.org>

On 17/12/2025 10:32, Taniya Das wrote:
>>>
>>> We would like to leverage the existing common clock driver(GDSC) code to
>>
>> Fix the driver code if it cannot handle other cells. Your drivers do not
>> matter for choices made in bindings.
>>
> 
> As it is still a clock controller from hardware design and in SW I will
> be map the entire hardware region and this way this clock controller
> will also be aligned to the existing clock controllers and keep the
> #power-domain-cells = <1> as other CCs.

I don't see how this resolves my comment.

Best regards,
Krzysztof


From steven.price at arm.com  Wed Dec 17 02:10:37 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:10:37 +0000
Subject: [PATCH v12 00/46] arm64: Support for Arm CCA in KVM
Message-ID: <20251217101125.91098-1-steven.price@arm.com>

This series adds support for running protected VMs using KVM under the
Arm Confidential Compute Architecture (CCA). I've changed the uAPI
following feedback from Marc.

The main change is that rather than providing a multiplex CAP and
expecting the VMM to drive the different stages of realm construction,
there's now just a minimal interface and KVM performs the necessary
operations when needed.

This series is lightly tested and is meant as a demonstration of the new
uAPI. There are a number of (known) rough corners in the implementation
that I haven't dealt with properly.

In particular please note that this series is still targetting RMM v1.0.
There is an alpha quality version of RMM v2.0 available[1]. Feedback was
that there are a number of blockers for merging with RMM v1.0 and so I
expect to rework this series to support RMM v2.0 before it is merged.
That will necessarily involve reworking the implementation.

Specifically I'm expecting improvements in:

 * GIC handling - passing state in registers, and allowing the host to
   fully emulate the GIC by allowing trap bits to be set.

 * PMU handling - again providing flexibility to the host's emulation.

 * Page size/granule size mismatch. RMM v1.0 defines the granule as 4k,
   RMM v2.0 provide the option for the host to change the granule size.
   The intention is that Linux would simply set the granule size equal
   to its page size which will significantly simplify the management of
   granules.

 * Some performance improvement from the use of range-based map/unmap
   RMI calls.

This series is based on v6.19-rc1. It is also available as a git
repository:

https://gitlab.arm.com/linux-arm/linux-cca cca-host/v12

Work in progress changes for kvmtool are available from the git
repository below:

https://gitlab.arm.com/linux-arm/kvmtool-cca cca/v10

[1] https://developer.arm.com/documentation/den0137/latest/

Jean-Philippe Brucker (7):
  arm64: RMI: Propagate number of breakpoints and watchpoints to
    userspace
  arm64: RMI: Set breakpoint parameters through SET_ONE_REG
  arm64: RMI: Initialize PMCR.N with number counter supported by RMM
  arm64: RMI: Propagate max SVE vector length from RMM
  arm64: RMI: Configure max SVE vector length for a Realm
  arm64: RMI: Provide register list for unfinalized RMI RECs
  arm64: RMI: Provide accurate register list

Joey Gouly (2):
  arm64: RMI: allow userspace to inject aborts
  arm64: RMI: support RSI_HOST_CALL

Steven Price (34):
  arm64: RME: Handle Granule Protection Faults (GPFs)
  arm64: RMI: Add SMC definitions for calling the RMM
  arm64: RMI: Add wrappers for RMI calls
  arm64: RMI: Check for RMI support at KVM init
  arm64: RMI: Define the user ABI
  arm64: RMI: Basic infrastructure for creating a realm.
  KVM: arm64: Allow passing machine type in KVM creation
  arm64: RMI: RTT tear down
  arm64: RMI: Activate realm on first VCPU run
  arm64: RMI: Allocate/free RECs to match vCPUs
  KVM: arm64: vgic: Provide helper for number of list registers
  arm64: RMI: Support for the VGIC in realms
  KVM: arm64: Support timers in realm RECs
  arm64: RMI: Handle realm enter/exit
  arm64: RMI: Handle RMI_EXIT_RIPAS_CHANGE
  KVM: arm64: Handle realm MMIO emulation
  KVM: arm64: Expose support for private memory
  arm64: RMI: Allow populating initial contents
  arm64: RMI: Set RIPAS of initial memslots
  arm64: RMI: Create the realm descriptor
  arm64: RMI: Add a VMID allocator for realms
  arm64: RMI: Runtime faulting of memory
  KVM: arm64: Handle realm VCPU load
  KVM: arm64: Validate register access for a Realm VM
  KVM: arm64: Handle Realm PSCI requests
  KVM: arm64: WARN on injected undef exceptions
  arm64: Don't expose stolen time for realm guests
  arm64: RMI: Always use 4k pages for realms
  arm64: RMI: Prevent Device mappings for Realms
  HACK: Restore per-CPU cpu_armpmu pointer
  arm_pmu: Provide a mechanism for disabling the physical IRQ
  arm64: RMI: Enable PMU support with a realm guest
  KVM: arm64: Expose KVM_ARM_VCPU_REC to user space
  arm64: RMI: Enable realms to be created

Suzuki K Poulose (3):
  kvm: arm64: Include kvm_emulate.h in kvm/arm_psci.h
  kvm: arm64: Don't expose unsupported capabilities for realm guests
  arm64: RMI: Allow checking SVE on VM instance

 Documentation/virt/kvm/api.rst       |   78 +-
 arch/arm64/include/asm/kvm_emulate.h |   31 +
 arch/arm64/include/asm/kvm_host.h    |   13 +-
 arch/arm64/include/asm/kvm_rmi.h     |  137 +++
 arch/arm64/include/asm/rmi_cmds.h    |  508 ++++++++
 arch/arm64/include/asm/rmi_smc.h     |  269 +++++
 arch/arm64/include/asm/virt.h        |    1 +
 arch/arm64/kernel/cpufeature.c       |    1 +
 arch/arm64/kvm/Kconfig               |    2 +
 arch/arm64/kvm/Makefile              |    2 +-
 arch/arm64/kvm/arch_timer.c          |   37 +-
 arch/arm64/kvm/arm.c                 |  179 ++-
 arch/arm64/kvm/guest.c               |   95 +-
 arch/arm64/kvm/hypercalls.c          |    4 +-
 arch/arm64/kvm/inject_fault.c        |    5 +-
 arch/arm64/kvm/mmio.c                |   16 +-
 arch/arm64/kvm/mmu.c                 |  214 +++-
 arch/arm64/kvm/pmu-emul.c            |    6 +
 arch/arm64/kvm/psci.c                |   30 +
 arch/arm64/kvm/reset.c               |   13 +-
 arch/arm64/kvm/rmi-exit.c            |  207 ++++
 arch/arm64/kvm/rmi.c                 | 1663 ++++++++++++++++++++++++++
 arch/arm64/kvm/sys_regs.c            |   53 +-
 arch/arm64/kvm/vgic/vgic-init.c      |    2 +-
 arch/arm64/kvm/vgic/vgic-v2.c        |    6 +-
 arch/arm64/kvm/vgic/vgic-v3.c        |   14 +-
 arch/arm64/kvm/vgic/vgic.c           |   55 +-
 arch/arm64/kvm/vgic/vgic.h           |   20 +-
 arch/arm64/mm/fault.c                |   28 +-
 drivers/perf/arm_pmu.c               |   20 +
 include/kvm/arm_arch_timer.h         |    2 +
 include/kvm/arm_pmu.h                |    4 +
 include/kvm/arm_psci.h               |    2 +
 include/linux/perf/arm_pmu.h         |    7 +
 include/uapi/linux/kvm.h             |   42 +-
 35 files changed, 3650 insertions(+), 116 deletions(-)
 create mode 100644 arch/arm64/include/asm/kvm_rmi.h
 create mode 100644 arch/arm64/include/asm/rmi_cmds.h
 create mode 100644 arch/arm64/include/asm/rmi_smc.h
 create mode 100644 arch/arm64/kvm/rmi-exit.c
 create mode 100644 arch/arm64/kvm/rmi.c

-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:10:38 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:10:38 +0000
Subject: [PATCH v12 01/46] kvm: arm64: Include kvm_emulate.h in kvm/arm_psci.h
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-2-steven.price@arm.com>

From: Suzuki K Poulose <suzuki.poulose at arm.com>

Fix a potential build error (like below, when asm/kvm_emulate.h gets
included after the kvm/arm_psci.h) by including the missing header file
in kvm/arm_psci.h:

./include/kvm/arm_psci.h: In function ?kvm_psci_version?:
./include/kvm/arm_psci.h:29:13: error: implicit declaration of function
   ?vcpu_has_feature?; did you mean ?cpu_have_feature?? [-Werror=implicit-function-declaration]
   29 |         if (vcpu_has_feature(vcpu, KVM_ARM_VCPU_PSCI_0_2)) {
	         |             ^~~~~~~~~~~~~~~~
			       |             cpu_have_feature

Reviewed-by: Gavin Shan <gshan at redhat.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose at arm.com>
Signed-off-by: Steven Price <steven.price at arm.com>
---
 include/kvm/arm_psci.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
index cbaec804eb83..38dab7add79b 100644
--- a/include/kvm/arm_psci.h
+++ b/include/kvm/arm_psci.h
@@ -10,6 +10,8 @@
 #include <linux/kvm_host.h>
 #include <uapi/linux/psci.h>
 
+#include <asm/kvm_emulate.h>
+
 #define KVM_ARM_PSCI_0_1	PSCI_VERSION(0, 1)
 #define KVM_ARM_PSCI_0_2	PSCI_VERSION(0, 2)
 #define KVM_ARM_PSCI_1_0	PSCI_VERSION(1, 0)
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:10:39 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:10:39 +0000
Subject: [PATCH v12 02/46] arm64: RME: Handle Granule Protection Faults (GPFs)
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-3-steven.price@arm.com>

If the host attempts to access granules that have been delegated for use
in a realm these accesses will be caught and will trigger a Granule
Protection Fault (GPF).

A fault during a page walk signals a bug in the kernel and is handled by
oopsing the kernel. A non-page walk fault could be caused by user space
having access to a page which has been delegated to the kernel and will
trigger a SIGBUS to allow debugging why user space is trying to access a
delegated page.

Reviewed-by: Suzuki K Poulose <suzuki.poulose at arm.com>
Reviewed-by: Gavin Shan <gshan at redhat.com>
Signed-off-by: Steven Price <steven.price at arm.com>
---
Changes since v10:
 * Don't call arm64_notify_die() in do_gpf() but simply return 1.
Changes since v2:
 * Include missing "Granule Protection Fault at level -1"
---
 arch/arm64/mm/fault.c | 28 ++++++++++++++++++++++------
 1 file changed, 22 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index be9dab2c7d6a..13b1d5de6d77 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -858,6 +858,22 @@ static int do_tag_check_fault(unsigned long far, unsigned long esr,
 	return 0;
 }
 
+static int do_gpf_ptw(unsigned long far, unsigned long esr, struct pt_regs *regs)
+{
+	const struct fault_info *inf = esr_to_fault_info(esr);
+
+	die_kernel_fault(inf->name, far, esr, regs);
+	return 0;
+}
+
+static int do_gpf(unsigned long far, unsigned long esr, struct pt_regs *regs)
+{
+	if (!is_el1_instruction_abort(esr) && fixup_exception(regs, esr))
+		return 0;
+
+	return 1;
+}
+
 static const struct fault_info fault_info[] = {
 	{ do_bad,		SIGKILL, SI_KERNEL,	"ttbr address size fault"	},
 	{ do_bad,		SIGKILL, SI_KERNEL,	"level 1 address size fault"	},
@@ -894,12 +910,12 @@ static const struct fault_info fault_info[] = {
 	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 32"			},
 	{ do_alignment_fault,	SIGBUS,  BUS_ADRALN,	"alignment fault"		},
 	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 34"			},
-	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 35"			},
-	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 36"			},
-	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 37"			},
-	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 38"			},
-	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 39"			},
-	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 40"			},
+	{ do_gpf_ptw,		SIGKILL, SI_KERNEL,	"Granule Protection Fault at level -1" },
+	{ do_gpf_ptw,		SIGKILL, SI_KERNEL,	"Granule Protection Fault at level 0" },
+	{ do_gpf_ptw,		SIGKILL, SI_KERNEL,	"Granule Protection Fault at level 1" },
+	{ do_gpf_ptw,		SIGKILL, SI_KERNEL,	"Granule Protection Fault at level 2" },
+	{ do_gpf_ptw,		SIGKILL, SI_KERNEL,	"Granule Protection Fault at level 3" },
+	{ do_gpf,		SIGBUS,  SI_KERNEL,	"Granule Protection Fault not on table walk" },
 	{ do_bad,		SIGKILL, SI_KERNEL,	"level -1 address size fault"	},
 	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 42"			},
 	{ do_translation_fault,	SIGSEGV, SEGV_MAPERR,	"level -1 translation fault"	},
-- 
2.43.0



From fshao at chromium.org  Wed Dec 17 02:10:47 2025
From: fshao at chromium.org (Fei Shao)
Date: Wed, 17 Dec 2025 18:10:47 +0800
Subject: [PATCH] spi: mt65xx: Use IRQF_ONESHOT with threaded IRQ
Message-ID: <20251217101131.1975131-1-fshao@chromium.org>

This driver is migrated to use threaded IRQ since commit 5972eb05ca32
("spi: spi-mt65xx: Use threaded interrupt for non-SPIMEM transfer"), and
we almost always want to disable the interrupt line to avoid excess
interrupts while the threaded handler is processing SPI transfer.
Use IRQF_ONESHOT for that purpose.

In practice, we see MediaTek devices show SPI transfer timeout errors
when communicating with ChromeOS EC in certain scenarios, and with
IRQF_ONESHOT, the issue goes away.

Signed-off-by: Fei Shao <fshao at chromium.org>
---

 drivers/spi/spi-mt65xx.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c
index 4b40985af1ea..90e5813cfdc3 100644
--- a/drivers/spi/spi-mt65xx.c
+++ b/drivers/spi/spi-mt65xx.c
@@ -1320,7 +1320,7 @@ static int mtk_spi_probe(struct platform_device *pdev)
 
 	ret = devm_request_threaded_irq(dev, irq, mtk_spi_interrupt,
 					mtk_spi_interrupt_thread,
-					IRQF_TRIGGER_NONE, dev_name(dev), host);
+					IRQF_ONESHOT, dev_name(dev), host);
 	if (ret)
 		return dev_err_probe(dev, ret, "failed to register irq\n");
 
-- 
2.52.0.305.g3fc767764a-goog



From steven.price at arm.com  Wed Dec 17 02:10:40 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:10:40 +0000
Subject: [PATCH v12 03/46] arm64: RMI: Add SMC definitions for calling the RMM
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-4-steven.price@arm.com>

The RMM (Realm Management Monitor) provides functionality that can be
accessed by SMC calls from the host.

The SMC definitions are based on DEN0137[1] version 1.0-rel0

[1] https://developer.arm.com/documentation/den0137/1-0rel0/

Reviewed-by: Gavin Shan <gshan at redhat.com>
Reviewed-by: Suzuki K Poulose <suzuki.poulose at arm.com>
Signed-off-by: Steven Price <steven.price at arm.com>
---
Changes since v9:
 * Corrected size of 'ripas_value' in struct rec_exit. The spec states
   this is an 8-bit type with padding afterwards (rather than a u64).
Changes since v8:
 * Added RMI_PERMITTED_GICV3_HCR_BITS to define which bits the RMM
   permits to be modified.
Changes since v6:
 * Renamed REC_ENTER_xxx defines to include 'FLAG' to make it obvious
   these are flag values.
Changes since v5:
 * Sorted the SMC #defines by value.
 * Renamed SMI_RxI_CALL to SMI_RMI_CALL since the macro is only used for
   RMI calls.
 * Renamed REC_GIC_NUM_LRS to REC_MAX_GIC_NUM_LRS since the actual
   number of available list registers could be lower.
 * Provided a define for the reserved fields of FeatureRegister0.
 * Fix inconsistent names for padding fields.
Changes since v4:
 * Update to point to final released RMM spec.
 * Minor rearrangements.
Changes since v3:
 * Update to match RMM spec v1.0-rel0-rc1.
Changes since v2:
 * Fix specification link.
 * Rename rec_entry->rec_enter to match spec.
 * Fix size of pmu_ovf_status to match spec.
---
 arch/arm64/include/asm/rmi_smc.h | 269 +++++++++++++++++++++++++++++++
 1 file changed, 269 insertions(+)
 create mode 100644 arch/arm64/include/asm/rmi_smc.h

diff --git a/arch/arm64/include/asm/rmi_smc.h b/arch/arm64/include/asm/rmi_smc.h
new file mode 100644
index 000000000000..1000368f1bca
--- /dev/null
+++ b/arch/arm64/include/asm/rmi_smc.h
@@ -0,0 +1,269 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023-2024 ARM Ltd.
+ *
+ * The values and structures in this file are from the Realm Management Monitor
+ * specification (DEN0137) version 1.0-rel0:
+ * https://developer.arm.com/documentation/den0137/1-0rel0/
+ */
+
+#ifndef __ASM_RMI_SMC_H
+#define __ASM_RMI_SMC_H
+
+#include <linux/arm-smccc.h>
+
+#define SMC_RMI_CALL(func)				\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,		\
+			   ARM_SMCCC_SMC_64,		\
+			   ARM_SMCCC_OWNER_STANDARD,	\
+			   (func))
+
+#define SMC_RMI_VERSION			SMC_RMI_CALL(0x0150)
+#define SMC_RMI_GRANULE_DELEGATE	SMC_RMI_CALL(0x0151)
+#define SMC_RMI_GRANULE_UNDELEGATE	SMC_RMI_CALL(0x0152)
+#define SMC_RMI_DATA_CREATE		SMC_RMI_CALL(0x0153)
+#define SMC_RMI_DATA_CREATE_UNKNOWN	SMC_RMI_CALL(0x0154)
+#define SMC_RMI_DATA_DESTROY		SMC_RMI_CALL(0x0155)
+
+#define SMC_RMI_REALM_ACTIVATE		SMC_RMI_CALL(0x0157)
+#define SMC_RMI_REALM_CREATE		SMC_RMI_CALL(0x0158)
+#define SMC_RMI_REALM_DESTROY		SMC_RMI_CALL(0x0159)
+#define SMC_RMI_REC_CREATE		SMC_RMI_CALL(0x015a)
+#define SMC_RMI_REC_DESTROY		SMC_RMI_CALL(0x015b)
+#define SMC_RMI_REC_ENTER		SMC_RMI_CALL(0x015c)
+#define SMC_RMI_RTT_CREATE		SMC_RMI_CALL(0x015d)
+#define SMC_RMI_RTT_DESTROY		SMC_RMI_CALL(0x015e)
+#define SMC_RMI_RTT_MAP_UNPROTECTED	SMC_RMI_CALL(0x015f)
+
+#define SMC_RMI_RTT_READ_ENTRY		SMC_RMI_CALL(0x0161)
+#define SMC_RMI_RTT_UNMAP_UNPROTECTED	SMC_RMI_CALL(0x0162)
+
+#define SMC_RMI_PSCI_COMPLETE		SMC_RMI_CALL(0x0164)
+#define SMC_RMI_FEATURES		SMC_RMI_CALL(0x0165)
+#define SMC_RMI_RTT_FOLD		SMC_RMI_CALL(0x0166)
+#define SMC_RMI_REC_AUX_COUNT		SMC_RMI_CALL(0x0167)
+#define SMC_RMI_RTT_INIT_RIPAS		SMC_RMI_CALL(0x0168)
+#define SMC_RMI_RTT_SET_RIPAS		SMC_RMI_CALL(0x0169)
+
+#define RMI_ABI_MAJOR_VERSION	1
+#define RMI_ABI_MINOR_VERSION	0
+
+#define RMI_ABI_VERSION_GET_MAJOR(version) ((version) >> 16)
+#define RMI_ABI_VERSION_GET_MINOR(version) ((version) & 0xFFFF)
+#define RMI_ABI_VERSION(major, minor)      (((major) << 16) | (minor))
+
+#define RMI_UNASSIGNED			0
+#define RMI_ASSIGNED			1
+#define RMI_TABLE			2
+
+#define RMI_RETURN_STATUS(ret)		((ret) & 0xFF)
+#define RMI_RETURN_INDEX(ret)		(((ret) >> 8) & 0xFF)
+
+#define RMI_SUCCESS		0
+#define RMI_ERROR_INPUT		1
+#define RMI_ERROR_REALM		2
+#define RMI_ERROR_REC		3
+#define RMI_ERROR_RTT		4
+
+enum rmi_ripas {
+	RMI_EMPTY = 0,
+	RMI_RAM = 1,
+	RMI_DESTROYED = 2,
+};
+
+#define RMI_NO_MEASURE_CONTENT	0
+#define RMI_MEASURE_CONTENT	1
+
+#define RMI_FEATURE_REGISTER_0_S2SZ		GENMASK(7, 0)
+#define RMI_FEATURE_REGISTER_0_LPA2		BIT(8)
+#define RMI_FEATURE_REGISTER_0_SVE_EN		BIT(9)
+#define RMI_FEATURE_REGISTER_0_SVE_VL		GENMASK(13, 10)
+#define RMI_FEATURE_REGISTER_0_NUM_BPS		GENMASK(19, 14)
+#define RMI_FEATURE_REGISTER_0_NUM_WPS		GENMASK(25, 20)
+#define RMI_FEATURE_REGISTER_0_PMU_EN		BIT(26)
+#define RMI_FEATURE_REGISTER_0_PMU_NUM_CTRS	GENMASK(31, 27)
+#define RMI_FEATURE_REGISTER_0_HASH_SHA_256	BIT(32)
+#define RMI_FEATURE_REGISTER_0_HASH_SHA_512	BIT(33)
+#define RMI_FEATURE_REGISTER_0_GICV3_NUM_LRS	GENMASK(37, 34)
+#define RMI_FEATURE_REGISTER_0_MAX_RECS_ORDER	GENMASK(41, 38)
+#define RMI_FEATURE_REGISTER_0_Reserved		GENMASK(63, 42)
+
+#define RMI_REALM_PARAM_FLAG_LPA2		BIT(0)
+#define RMI_REALM_PARAM_FLAG_SVE		BIT(1)
+#define RMI_REALM_PARAM_FLAG_PMU		BIT(2)
+
+/*
+ * Note many of these fields are smaller than u64 but all fields have u64
+ * alignment, so use u64 to ensure correct alignment.
+ */
+struct realm_params {
+	union { /* 0x0 */
+		struct {
+			u64 flags;
+			u64 s2sz;
+			u64 sve_vl;
+			u64 num_bps;
+			u64 num_wps;
+			u64 pmu_num_ctrs;
+			u64 hash_algo;
+		};
+		u8 padding0[0x400];
+	};
+	union { /* 0x400 */
+		u8 rpv[64];
+		u8 padding1[0x400];
+	};
+	union { /* 0x800 */
+		struct {
+			u64 vmid;
+			u64 rtt_base;
+			s64 rtt_level_start;
+			u64 rtt_num_start;
+		};
+		u8 padding2[0x800];
+	};
+};
+
+/*
+ * The number of GPRs (starting from X0) that are
+ * configured by the host when a REC is created.
+ */
+#define REC_CREATE_NR_GPRS		8
+
+#define REC_PARAMS_FLAG_RUNNABLE	BIT_ULL(0)
+
+#define REC_PARAMS_AUX_GRANULES		16
+
+struct rec_params {
+	union { /* 0x0 */
+		u64 flags;
+		u8 padding0[0x100];
+	};
+	union { /* 0x100 */
+		u64 mpidr;
+		u8 padding1[0x100];
+	};
+	union { /* 0x200 */
+		u64 pc;
+		u8 padding2[0x100];
+	};
+	union { /* 0x300 */
+		u64 gprs[REC_CREATE_NR_GPRS];
+		u8 padding3[0x500];
+	};
+	union { /* 0x800 */
+		struct {
+			u64 num_rec_aux;
+			u64 aux[REC_PARAMS_AUX_GRANULES];
+		};
+		u8 padding4[0x800];
+	};
+};
+
+#define REC_ENTER_FLAG_EMULATED_MMIO	BIT(0)
+#define REC_ENTER_FLAG_INJECT_SEA	BIT(1)
+#define REC_ENTER_FLAG_TRAP_WFI		BIT(2)
+#define REC_ENTER_FLAG_TRAP_WFE		BIT(3)
+#define REC_ENTER_FLAG_RIPAS_RESPONSE	BIT(4)
+
+#define REC_RUN_GPRS			31
+#define REC_MAX_GIC_NUM_LRS		16
+
+#define RMI_PERMITTED_GICV3_HCR_BITS	(ICH_HCR_EL2_UIE |		\
+					 ICH_HCR_EL2_LRENPIE |		\
+					 ICH_HCR_EL2_NPIE |		\
+					 ICH_HCR_EL2_VGrp0EIE |		\
+					 ICH_HCR_EL2_VGrp0DIE |		\
+					 ICH_HCR_EL2_VGrp1EIE |		\
+					 ICH_HCR_EL2_VGrp1DIE |		\
+					 ICH_HCR_EL2_TDIR)
+
+struct rec_enter {
+	union { /* 0x000 */
+		u64 flags;
+		u8 padding0[0x200];
+	};
+	union { /* 0x200 */
+		u64 gprs[REC_RUN_GPRS];
+		u8 padding1[0x100];
+	};
+	union { /* 0x300 */
+		struct {
+			u64 gicv3_hcr;
+			u64 gicv3_lrs[REC_MAX_GIC_NUM_LRS];
+		};
+		u8 padding2[0x100];
+	};
+	u8 padding3[0x400];
+};
+
+#define RMI_EXIT_SYNC			0x00
+#define RMI_EXIT_IRQ			0x01
+#define RMI_EXIT_FIQ			0x02
+#define RMI_EXIT_PSCI			0x03
+#define RMI_EXIT_RIPAS_CHANGE		0x04
+#define RMI_EXIT_HOST_CALL		0x05
+#define RMI_EXIT_SERROR			0x06
+
+struct rec_exit {
+	union { /* 0x000 */
+		u8 exit_reason;
+		u8 padding0[0x100];
+	};
+	union { /* 0x100 */
+		struct {
+			u64 esr;
+			u64 far;
+			u64 hpfar;
+		};
+		u8 padding1[0x100];
+	};
+	union { /* 0x200 */
+		u64 gprs[REC_RUN_GPRS];
+		u8 padding2[0x100];
+	};
+	union { /* 0x300 */
+		struct {
+			u64 gicv3_hcr;
+			u64 gicv3_lrs[REC_MAX_GIC_NUM_LRS];
+			u64 gicv3_misr;
+			u64 gicv3_vmcr;
+		};
+		u8 padding3[0x100];
+	};
+	union { /* 0x400 */
+		struct {
+			u64 cntp_ctl;
+			u64 cntp_cval;
+			u64 cntv_ctl;
+			u64 cntv_cval;
+		};
+		u8 padding4[0x100];
+	};
+	union { /* 0x500 */
+		struct {
+			u64 ripas_base;
+			u64 ripas_top;
+			u8 ripas_value;
+			u8 padding8[7];
+		};
+		u8 padding5[0x100];
+	};
+	union { /* 0x600 */
+		u16 imm;
+		u8 padding6[0x100];
+	};
+	union { /* 0x700 */
+		struct {
+			u8 pmu_ovf_status;
+		};
+		u8 padding7[0x100];
+	};
+};
+
+struct rec_run {
+	struct rec_enter enter;
+	struct rec_exit exit;
+};
+
+#endif /* __ASM_RMI_SMC_H */
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:10:41 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:10:41 +0000
Subject: [PATCH v12 04/46] arm64: RMI: Add wrappers for RMI calls
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-5-steven.price@arm.com>

The wrappers make the call sites easier to read and deal with the
boiler plate of handling the error codes from the RMM.

Reviewed-by: Gavin Shan <gshan at redhat.com>
Reviewed-by: Suzuki K Poulose <suzuki.poulose at arm.com>
Signed-off-by: Steven Price <steven.price at arm.com>
---
Changes from v8:
 * Switch from arm_smccc_1_2_smc() to arm_smccc_1_2_invoke() in
   rmi_rtt_read_entry() for consistency.
Changes from v7:
 * Minor renaming of parameters and updated comments
Changes from v5:
 * Further improve comments
Changes from v4:
 * Improve comments
Changes from v2:
 * Make output arguments optional.
 * Mask RIPAS value rmi_rtt_read_entry()
 * Drop unused rmi_rtt_get_phys()
---
 arch/arm64/include/asm/rmi_cmds.h | 508 ++++++++++++++++++++++++++++++
 1 file changed, 508 insertions(+)
 create mode 100644 arch/arm64/include/asm/rmi_cmds.h

diff --git a/arch/arm64/include/asm/rmi_cmds.h b/arch/arm64/include/asm/rmi_cmds.h
new file mode 100644
index 000000000000..ef53147c1984
--- /dev/null
+++ b/arch/arm64/include/asm/rmi_cmds.h
@@ -0,0 +1,508 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 ARM Ltd.
+ */
+
+#ifndef __ASM_RMI_CMDS_H
+#define __ASM_RMI_CMDS_H
+
+#include <linux/arm-smccc.h>
+
+#include <asm/rmi_smc.h>
+
+struct rtt_entry {
+	unsigned long walk_level;
+	unsigned long desc;
+	int state;
+	int ripas;
+};
+
+/**
+ * rmi_data_create() - Create a data granule
+ * @rd: PA of the RD
+ * @data: PA of the target granule
+ * @ipa: IPA at which the granule will be mapped in the guest
+ * @src: PA of the source granule
+ * @flags: RMI_MEASURE_CONTENT if the contents should be measured
+ *
+ * Create a new data granule, copying contents from a non-secure granule.
+ *
+ * Return: RMI return code
+ */
+static inline int rmi_data_create(unsigned long rd, unsigned long data,
+				  unsigned long ipa, unsigned long src,
+				  unsigned long flags)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_DATA_CREATE, rd, data, ipa, src,
+			     flags, &res);
+
+	return res.a0;
+}
+
+/**
+ * rmi_data_create_unknown() - Create a data granule with unknown contents
+ * @rd: PA of the RD
+ * @data: PA of the target granule
+ * @ipa: IPA at which the granule will be mapped in the guest
+ *
+ * Return: RMI return code
+ */
+static inline int rmi_data_create_unknown(unsigned long rd,
+					  unsigned long data,
+					  unsigned long ipa)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_DATA_CREATE_UNKNOWN, rd, data, ipa, &res);
+
+	return res.a0;
+}
+
+/**
+ * rmi_data_destroy() - Destroy a data granule
+ * @rd: PA of the RD
+ * @ipa: IPA at which the granule is mapped in the guest
+ * @data_out: PA of the granule which was destroyed
+ * @top_out: Top IPA of non-live RTT entries
+ *
+ * Unmap a protected IPA from stage 2, transitioning it to DESTROYED.
+ * The IPA cannot be used by the guest unless it is transitioned to RAM again
+ * by the realm guest.
+ *
+ * Return: RMI return code
+ */
+static inline int rmi_data_destroy(unsigned long rd, unsigned long ipa,
+				   unsigned long *data_out,
+				   unsigned long *top_out)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_DATA_DESTROY, rd, ipa, &res);
+
+	if (data_out)
+		*data_out = res.a1;
+	if (top_out)
+		*top_out = res.a2;
+
+	return res.a0;
+}
+
+/**
+ * rmi_features() - Read feature register
+ * @index: Feature register index
+ * @out: Feature register value is written to this pointer
+ *
+ * Return: RMI return code
+ */
+static inline int rmi_features(unsigned long index, unsigned long *out)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_FEATURES, index, &res);
+
+	if (out)
+		*out = res.a1;
+	return res.a0;
+}
+
+/**
+ * rmi_granule_delegate() - Delegate a granule
+ * @phys: PA of the granule
+ *
+ * Delegate a granule for use by the realm world.
+ *
+ * Return: RMI return code
+ */
+static inline int rmi_granule_delegate(unsigned long phys)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_GRANULE_DELEGATE, phys, &res);
+
+	return res.a0;
+}
+
+/**
+ * rmi_granule_undelegate() - Undelegate a granule
+ * @phys: PA of the granule
+ *
+ * Undelegate a granule to allow use by the normal world. Will fail if the
+ * granule is in use.
+ *
+ * Return: RMI return code
+ */
+static inline int rmi_granule_undelegate(unsigned long phys)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_GRANULE_UNDELEGATE, phys, &res);
+
+	return res.a0;
+}
+
+/**
+ * rmi_psci_complete() - Complete pending PSCI command
+ * @calling_rec: PA of the calling REC
+ * @target_rec: PA of the target REC
+ * @status: Status of the PSCI request
+ *
+ * Completes a pending PSCI command which was called with an MPIDR argument, by
+ * providing the corresponding REC.
+ *
+ * Return: RMI return code
+ */
+static inline int rmi_psci_complete(unsigned long calling_rec,
+				    unsigned long target_rec,
+				    unsigned long status)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_PSCI_COMPLETE, calling_rec, target_rec,
+			     status, &res);
+
+	return res.a0;
+}
+
+/**
+ * rmi_realm_activate() - Active a realm
+ * @rd: PA of the RD
+ *
+ * Mark a realm as Active signalling that creation is complete and allowing
+ * execution of the realm.
+ *
+ * Return: RMI return code
+ */
+static inline int rmi_realm_activate(unsigned long rd)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_REALM_ACTIVATE, rd, &res);
+
+	return res.a0;
+}
+
+/**
+ * rmi_realm_create() - Create a realm
+ * @rd: PA of the RD
+ * @params: PA of realm parameters
+ *
+ * Create a new realm using the given parameters.
+ *
+ * Return: RMI return code
+ */
+static inline int rmi_realm_create(unsigned long rd, unsigned long params)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_REALM_CREATE, rd, params, &res);
+
+	return res.a0;
+}
+
+/**
+ * rmi_realm_destroy() - Destroy a realm
+ * @rd: PA of the RD
+ *
+ * Destroys a realm, all objects belonging to the realm must be destroyed first.
+ *
+ * Return: RMI return code
+ */
+static inline int rmi_realm_destroy(unsigned long rd)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_REALM_DESTROY, rd, &res);
+
+	return res.a0;
+}
+
+/**
+ * rmi_rec_aux_count() - Get number of auxiliary granules required
+ * @rd: PA of the RD
+ * @aux_count: Number of granules written to this pointer
+ *
+ * A REC may require extra auxiliary granules to be delegated for the RMM to
+ * store metadata (not visible to the normal world) in. This function provides
+ * the number of granules that are required.
+ *
+ * Return: RMI return code
+ */
+static inline int rmi_rec_aux_count(unsigned long rd, unsigned long *aux_count)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_REC_AUX_COUNT, rd, &res);
+
+	if (aux_count)
+		*aux_count = res.a1;
+	return res.a0;
+}
+
+/**
+ * rmi_rec_create() - Create a REC
+ * @rd: PA of the RD
+ * @rec: PA of the target REC
+ * @params: PA of REC parameters
+ *
+ * Create a REC using the parameters specified in the struct rec_params pointed
+ * to by @params.
+ *
+ * Return: RMI return code
+ */
+static inline int rmi_rec_create(unsigned long rd, unsigned long rec,
+				 unsigned long params)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_REC_CREATE, rd, rec, params, &res);
+
+	return res.a0;
+}
+
+/**
+ * rmi_rec_destroy() - Destroy a REC
+ * @rec: PA of the target REC
+ *
+ * Destroys a REC. The REC must not be running.
+ *
+ * Return: RMI return code
+ */
+static inline int rmi_rec_destroy(unsigned long rec)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_REC_DESTROY, rec, &res);
+
+	return res.a0;
+}
+
+/**
+ * rmi_rec_enter() - Enter a REC
+ * @rec: PA of the target REC
+ * @run_ptr: PA of RecRun structure
+ *
+ * Starts (or continues) execution within a REC.
+ *
+ * Return: RMI return code
+ */
+static inline int rmi_rec_enter(unsigned long rec, unsigned long run_ptr)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_REC_ENTER, rec, run_ptr, &res);
+
+	return res.a0;
+}
+
+/**
+ * rmi_rtt_create() - Creates an RTT
+ * @rd: PA of the RD
+ * @rtt: PA of the target RTT
+ * @ipa: Base of the IPA range described by the RTT
+ * @level: Depth of the RTT within the tree
+ *
+ * Creates an RTT (Realm Translation Table) at the specified level for the
+ * translation of the specified address within the realm.
+ *
+ * Return: RMI return code
+ */
+static inline int rmi_rtt_create(unsigned long rd, unsigned long rtt,
+				 unsigned long ipa, long level)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_RTT_CREATE, rd, rtt, ipa, level, &res);
+
+	return res.a0;
+}
+
+/**
+ * rmi_rtt_destroy() - Destroy an RTT
+ * @rd: PA of the RD
+ * @ipa: Base of the IPA range described by the RTT
+ * @level: Depth of the RTT within the tree
+ * @out_rtt: Pointer to write the PA of the RTT which was destroyed
+ * @out_top: Pointer to write the top IPA of non-live RTT entries
+ *
+ * Destroys an RTT. The RTT must be non-live, i.e. none of the entries in the
+ * table are in ASSIGNED or TABLE state.
+ *
+ * Return: RMI return code.
+ */
+static inline int rmi_rtt_destroy(unsigned long rd,
+				  unsigned long ipa,
+				  long level,
+				  unsigned long *out_rtt,
+				  unsigned long *out_top)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_RTT_DESTROY, rd, ipa, level, &res);
+
+	if (out_rtt)
+		*out_rtt = res.a1;
+	if (out_top)
+		*out_top = res.a2;
+
+	return res.a0;
+}
+
+/**
+ * rmi_rtt_fold() - Fold an RTT
+ * @rd: PA of the RD
+ * @ipa: Base of the IPA range described by the RTT
+ * @level: Depth of the RTT within the tree
+ * @out_rtt: Pointer to write the PA of the RTT which was destroyed
+ *
+ * Folds an RTT. If all entries with the RTT are 'homogeneous' the RTT can be
+ * folded into the parent and the RTT destroyed.
+ *
+ * Return: RMI return code
+ */
+static inline int rmi_rtt_fold(unsigned long rd, unsigned long ipa,
+			       long level, unsigned long *out_rtt)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_RTT_FOLD, rd, ipa, level, &res);
+
+	if (out_rtt)
+		*out_rtt = res.a1;
+
+	return res.a0;
+}
+
+/**
+ * rmi_rtt_init_ripas() - Set RIPAS for new realm
+ * @rd: PA of the RD
+ * @base: Base of target IPA region
+ * @top: Top of target IPA region
+ * @out_top: Top IPA of range whose RIPAS was modified
+ *
+ * Sets the RIPAS of a target IPA range to RAM, for a realm in the NEW state.
+ *
+ * Return: RMI return code
+ */
+static inline int rmi_rtt_init_ripas(unsigned long rd, unsigned long base,
+				     unsigned long top, unsigned long *out_top)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_RTT_INIT_RIPAS, rd, base, top, &res);
+
+	if (out_top)
+		*out_top = res.a1;
+
+	return res.a0;
+}
+
+/**
+ * rmi_rtt_map_unprotected() - Map NS granules into a realm
+ * @rd: PA of the RD
+ * @ipa: Base IPA of the mapping
+ * @level: Depth within the RTT tree
+ * @desc: RTTE descriptor
+ *
+ * Create a mapping from an Unprotected IPA to a Non-secure PA.
+ *
+ * Return: RMI return code
+ */
+static inline int rmi_rtt_map_unprotected(unsigned long rd,
+					  unsigned long ipa,
+					  long level,
+					  unsigned long desc)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_RTT_MAP_UNPROTECTED, rd, ipa, level,
+			     desc, &res);
+
+	return res.a0;
+}
+
+/**
+ * rmi_rtt_read_entry() - Read an RTTE
+ * @rd: PA of the RD
+ * @ipa: IPA for which to read the RTTE
+ * @level: RTT level at which to read the RTTE
+ * @rtt: Output structure describing the RTTE
+ *
+ * Reads a RTTE (Realm Translation Table Entry).
+ *
+ * Return: RMI return code
+ */
+static inline int rmi_rtt_read_entry(unsigned long rd, unsigned long ipa,
+				     long level, struct rtt_entry *rtt)
+{
+	struct arm_smccc_1_2_regs regs = {
+		SMC_RMI_RTT_READ_ENTRY,
+		rd, ipa, level
+	};
+
+	arm_smccc_1_2_invoke(&regs, &regs);
+
+	rtt->walk_level = regs.a1;
+	rtt->state = regs.a2 & 0xFF;
+	rtt->desc = regs.a3;
+	rtt->ripas = regs.a4 & 0xFF;
+
+	return regs.a0;
+}
+
+/**
+ * rmi_rtt_set_ripas() - Set RIPAS for an running realm
+ * @rd: PA of the RD
+ * @rec: PA of the REC making the request
+ * @base: Base of target IPA region
+ * @top: Top of target IPA region
+ * @out_top: Pointer to write top IPA of range whose RIPAS was modified
+ *
+ * Completes a request made by the realm to change the RIPAS of a target IPA
+ * range.
+ *
+ * Return: RMI return code
+ */
+static inline int rmi_rtt_set_ripas(unsigned long rd, unsigned long rec,
+				    unsigned long base, unsigned long top,
+				    unsigned long *out_top)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_RTT_SET_RIPAS, rd, rec, base, top, &res);
+
+	if (out_top)
+		*out_top = res.a1;
+
+	return res.a0;
+}
+
+/**
+ * rmi_rtt_unmap_unprotected() - Remove a NS mapping
+ * @rd: PA of the RD
+ * @ipa: Base IPA of the mapping
+ * @level: Depth within the RTT tree
+ * @out_top: Pointer to write top IPA of non-live RTT entries
+ *
+ * Removes a mapping at an Unprotected IPA.
+ *
+ * Return: RMI return code
+ */
+static inline int rmi_rtt_unmap_unprotected(unsigned long rd,
+					    unsigned long ipa,
+					    long level,
+					    unsigned long *out_top)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_RTT_UNMAP_UNPROTECTED, rd, ipa,
+			     level, &res);
+
+	if (out_top)
+		*out_top = res.a1;
+
+	return res.a0;
+}
+
+#endif /* __ASM_RMI_CMDS_H */
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:10:42 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:10:42 +0000
Subject: [PATCH v12 05/46] arm64: RMI: Check for RMI support at KVM init
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-6-steven.price@arm.com>

Query the RMI version number and check if it is a compatible version. A
static key is also provided to signal that a supported RMM is available.

Functions are provided to query if a VM or VCPU is a realm (or rec)
which currently will always return false.

Later patches make use of struct realm and the states as the ioctls
interfaces are added to support realm and REC creation and destruction.

Signed-off-by: Steven Price <steven.price at arm.com>
---
Changes since v11:
 * Reword slightly the comments on the realm states.
Changes since v10:
 * kvm_is_realm() no longer has a NULL check.
 * Rename from "rme" to "rmi" when referring to the RMM interface.
 * Check for RME (hardware) support before probing for RMI support.
Changes since v8:
 * No need to guard kvm_init_rme() behind 'in_hyp_mode'.
Changes since v6:
 * Improved message for an unsupported RMI ABI version.
Changes since v5:
 * Reword "unsupported" message from "host supports" to "we want" to
   clarify that 'we' are the 'host'.
Changes since v2:
 * Drop return value from kvm_init_rme(), it was always 0.
 * Rely on the RMM return value to identify whether the RSI ABI is
   compatible.
---
 arch/arm64/include/asm/kvm_emulate.h | 18 ++++++++
 arch/arm64/include/asm/kvm_host.h    |  4 ++
 arch/arm64/include/asm/kvm_rmi.h     | 56 +++++++++++++++++++++++++
 arch/arm64/include/asm/virt.h        |  1 +
 arch/arm64/kernel/cpufeature.c       |  1 +
 arch/arm64/kvm/Makefile              |  2 +-
 arch/arm64/kvm/arm.c                 |  5 +++
 arch/arm64/kvm/rmi.c                 | 61 ++++++++++++++++++++++++++++
 8 files changed, 147 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm64/include/asm/kvm_rmi.h
 create mode 100644 arch/arm64/kvm/rmi.c

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index c9eab316398e..67f75678e489 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -696,4 +696,22 @@ static inline void vcpu_set_hcrx(struct kvm_vcpu *vcpu)
 			vcpu->arch.hcrx_el2 |= HCRX_EL2_SCTLR2En;
 	}
 }
+
+static inline bool kvm_is_realm(struct kvm *kvm)
+{
+	if (static_branch_unlikely(&kvm_rmi_is_available))
+		return kvm->arch.is_realm;
+	return false;
+}
+
+static inline enum realm_state kvm_realm_state(struct kvm *kvm)
+{
+	return READ_ONCE(kvm->arch.realm.state);
+}
+
+static inline bool vcpu_is_rec(struct kvm_vcpu *vcpu)
+{
+	return false;
+}
+
 #endif /* __ARM64_KVM_EMULATE_H__ */
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index ac7f970c7883..da913fee70b6 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -27,6 +27,7 @@
 #include <asm/fpsimd.h>
 #include <asm/kvm.h>
 #include <asm/kvm_asm.h>
+#include <asm/kvm_rmi.h>
 #include <asm/vncr_mapping.h>
 
 #define __KVM_HAVE_ARCH_INTC_INITIALIZED
@@ -408,6 +409,9 @@ struct kvm_arch {
 	 * the associated pKVM instance in the hypervisor.
 	 */
 	struct kvm_protected_vm pkvm;
+
+	bool is_realm;
+	struct realm realm;
 };
 
 struct kvm_vcpu_fault_info {
diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_rmi.h
new file mode 100644
index 000000000000..3506f50b05cd
--- /dev/null
+++ b/arch/arm64/include/asm/kvm_rmi.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023-2025 ARM Ltd.
+ */
+
+#ifndef __ASM_KVM_RMI_H
+#define __ASM_KVM_RMI_H
+
+/**
+ * enum realm_state - State of a Realm
+ */
+enum realm_state {
+	/**
+	 * @REALM_STATE_NONE:
+	 *      Realm has not yet been created. rmi_realm_create() has not
+	 *      yet been called.
+	 */
+	REALM_STATE_NONE,
+	/**
+	 * @REALM_STATE_NEW:
+	 *      Realm is under construction, rmi_realm_create() has been
+	 *      called, but it is not yet activated. Pages may be populated.
+	 */
+	REALM_STATE_NEW,
+	/**
+	 * @REALM_STATE_ACTIVE:
+	 *      Realm has been created and is eligible for execution with
+	 *      rmi_rec_enter(). Pages may no longer be populated with
+	 *      rmi_data_create().
+	 */
+	REALM_STATE_ACTIVE,
+	/**
+	 * @REALM_STATE_DYING:
+	 *      Realm is in the process of being destroyed or has already been
+	 *      destroyed.
+	 */
+	REALM_STATE_DYING,
+	/**
+	 * @REALM_STATE_DEAD:
+	 *      Realm has been destroyed.
+	 */
+	REALM_STATE_DEAD
+};
+
+/**
+ * struct realm - Additional per VM data for a Realm
+ *
+ * @state: The lifetime state machine for the realm
+ */
+struct realm {
+	enum realm_state state;
+};
+
+void kvm_init_rmi(void);
+
+#endif /* __ASM_KVM_RMI_H */
diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h
index b51ab6840f9c..dc9b2899e0b2 100644
--- a/arch/arm64/include/asm/virt.h
+++ b/arch/arm64/include/asm/virt.h
@@ -87,6 +87,7 @@ void __hyp_reset_vectors(void);
 bool is_kvm_arm_initialised(void);
 
 DECLARE_STATIC_KEY_FALSE(kvm_protected_mode_initialized);
+DECLARE_STATIC_KEY_FALSE(kvm_rmi_is_available);
 
 static inline bool is_pkvm_initialized(void)
 {
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index c840a93b9ef9..fa5ef83af7de 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -288,6 +288,7 @@ static const struct arm64_ftr_bits ftr_id_aa64isar3[] = {
 static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1_CSV3_SHIFT, 4, 0),
 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1_CSV2_SHIFT, 4, 0),
+	ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1_RME_SHIFT, 4, 0),
 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1_DIT_SHIFT, 4, 0),
 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1_AMU_SHIFT, 4, 0),
 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1_MPAM_SHIFT, 4, 0),
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index 3ebc0570345c..e17c4077d8e7 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -16,7 +16,7 @@ CFLAGS_handle_exit.o += -Wno-override-init
 kvm-y += arm.o mmu.o mmio.o psci.o hypercalls.o pvtime.o \
 	 inject_fault.o va_layout.o handle_exit.o config.o \
 	 guest.o debug.o reset.o sys_regs.o stacktrace.o \
-	 vgic-sys-reg-v3.o fpsimd.o pkvm.o \
+	 vgic-sys-reg-v3.o fpsimd.o pkvm.o rmi.o \
 	 arch_timer.o trng.o vmid.o emulate-nested.o nested.o at.o \
 	 vgic/vgic.o vgic/vgic-init.o \
 	 vgic/vgic-irqfd.o vgic/vgic-v2.o \
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 4f80da0c0d1d..a537f56f97db 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -39,6 +39,7 @@
 #include <asm/kvm_nested.h>
 #include <asm/kvm_pkvm.h>
 #include <asm/kvm_ptrauth.h>
+#include <asm/kvm_rmi.h>
 #include <asm/sections.h>
 
 #include <kvm/arm_hypercalls.h>
@@ -58,6 +59,8 @@ enum kvm_wfx_trap_policy {
 static enum kvm_wfx_trap_policy kvm_wfi_trap_policy __read_mostly = KVM_WFX_NOTRAP_SINGLE_TASK;
 static enum kvm_wfx_trap_policy kvm_wfe_trap_policy __read_mostly = KVM_WFX_NOTRAP_SINGLE_TASK;
 
+DEFINE_STATIC_KEY_FALSE(kvm_rmi_is_available);
+
 DECLARE_KVM_HYP_PER_CPU(unsigned long, kvm_hyp_vector);
 
 DEFINE_PER_CPU(unsigned long, kvm_arm_hyp_stack_base);
@@ -2865,6 +2868,8 @@ static __init int kvm_arm_init(void)
 
 	in_hyp_mode = is_kernel_in_hyp_mode();
 
+	kvm_init_rmi();
+
 	if (cpus_have_final_cap(ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE) ||
 	    cpus_have_final_cap(ARM64_WORKAROUND_1508412))
 		kvm_info("Guests without required CPU erratum workarounds can deadlock system!\n" \
diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
new file mode 100644
index 000000000000..629ace10cacc
--- /dev/null
+++ b/arch/arm64/kvm/rmi.c
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023-2025 ARM Ltd.
+ */
+
+#include <linux/kvm_host.h>
+
+#include <asm/rmi_cmds.h>
+#include <asm/virt.h>
+
+static int rmi_check_version(void)
+{
+	struct arm_smccc_res res;
+	unsigned short version_major, version_minor;
+	unsigned long host_version = RMI_ABI_VERSION(RMI_ABI_MAJOR_VERSION,
+						     RMI_ABI_MINOR_VERSION);
+	unsigned long aa64pfr0 = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
+
+	/* If RME isn't supported, then RMI can't be */
+	if (cpuid_feature_extract_unsigned_field(aa64pfr0, ID_AA64PFR0_EL1_RME_SHIFT) == 0)
+		return -ENXIO;
+
+	arm_smccc_1_1_invoke(SMC_RMI_VERSION, host_version, &res);
+
+	if (res.a0 == SMCCC_RET_NOT_SUPPORTED)
+		return -ENXIO;
+
+	version_major = RMI_ABI_VERSION_GET_MAJOR(res.a1);
+	version_minor = RMI_ABI_VERSION_GET_MINOR(res.a1);
+
+	if (res.a0 != RMI_SUCCESS) {
+		unsigned short high_version_major, high_version_minor;
+
+		high_version_major = RMI_ABI_VERSION_GET_MAJOR(res.a2);
+		high_version_minor = RMI_ABI_VERSION_GET_MINOR(res.a2);
+
+		kvm_err("Unsupported RMI ABI (v%d.%d - v%d.%d) we want v%d.%d\n",
+			version_major, version_minor,
+			high_version_major, high_version_minor,
+			RMI_ABI_MAJOR_VERSION,
+			RMI_ABI_MINOR_VERSION);
+		return -ENXIO;
+	}
+
+	kvm_info("RMI ABI version %d.%d\n", version_major, version_minor);
+
+	return 0;
+}
+
+void kvm_init_rmi(void)
+{
+	/* Only 4k page size on the host is supported */
+	if (PAGE_SIZE != SZ_4K)
+		return;
+
+	/* Continue without realm support if we can't agree on a version */
+	if (rmi_check_version())
+		return;
+
+	/* Future patch will enable static branch kvm_rmi_is_available */
+}
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:10:43 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:10:43 +0000
Subject: [PATCH v12 06/46] arm64: RMI: Define the user ABI
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-7-steven.price@arm.com>

There is one CAP which identified the presence of CCA, and two ioctls.
One ioctl is used to populate memory and the other is used when user
space is providing the PSCI implementation to identify the target of the
operation.

Signed-off-by: Steven Price <steven.price at arm.com>
---
Changes since v11:
 * Completely reworked to be more implicit. Rather than having explicit
   CAP operations to progress the realm construction these operations
   are done when needed (on populating and on first vCPU run).
 * Populate and PSCI complete are promoted to proper ioctls.
Changes since v10:
 * Rename symbols from RME to RMI.
Changes since v9:
 * Improvements to documentation.
 * Bump the magic number for KVM_CAP_ARM_RME to avoid conflicts.
Changes since v8:
 * Minor improvements to documentation following review.
 * Bump the magic numbers to avoid conflicts.
Changes since v7:
 * Add documentation of new ioctls
 * Bump the magic numbers to avoid conflicts
Changes since v6:
 * Rename some of the symbols to make their usage clearer and avoid
   repetition.
Changes from v5:
 * Actually expose the new VCPU capability (KVM_ARM_VCPU_REC) by bumping
   KVM_VCPU_MAX_FEATURES - note this also exposes KVM_ARM_VCPU_HAS_EL2!
---
 Documentation/virt/kvm/api.rst | 57 ++++++++++++++++++++++++++++++++++
 include/uapi/linux/kvm.h       | 23 ++++++++++++++
 2 files changed, 80 insertions(+)

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 01a3abef8abb..2d5dc7e48954 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -6517,6 +6517,54 @@ the capability to be present.
 
 `flags` must currently be zero.
 
+4.144 KVM_ARM_VCPU_RMI_PSCI_COMPLETE
+------------------------------------
+
+:Capability: KVM_CAP_ARM_RMI
+:Architectures: arm64
+:Type: vcpu ioctl
+:Parameters: struct kvm_arm_rmi_psci_complete (in)
+:Returns: 0 if successful, < 0 on error
+
+::
+
+  struct kvm_arm_rmi_psci_complete {
+	__u64 target_mpidr;
+	__u32 psci_status;
+	__u32 padding[3];
+  };
+
+Where PSCI functions are handled by user space, the RMM needs to be informed of
+the target of the operation using `target_mpidr`, along with the status
+(`psci_status`). The RMM v1.0 specification defines two functions that require
+this call: PSCI_CPU_ON and PSCI_AFFINITY_INFO.
+
+If the kernel is handling PSCI then this is done automatically and the VMM
+doesn't need to call this ioctl.
+
+4.145 KVM_ARM_RMI_POPULATE
+--------------------------
+
+:Capability: KVM_CAP_ARM_RMI
+:Architectures: arm64
+:Type: vm ioctl
+:Parameters: struct kvm_arm_rmi_populate (in)
+:Returns: number of bytes populated, < 0 on error
+
+::
+
+  struct kvm_arm_rmi_populate {
+	__u64 base;
+	__u64 size;
+	__u64 source_uaddr;
+	__u32 flags;
+	__u32 reserved;
+  };
+
+Populate a region of protected address space by copying the data from the user
+space pointer provided. This is only valid before any VCPUs have been run.
+The ioctl might not populate the entire region and user space may have to
+repeatedly call it (with updated pointers) to populate the entire region.
 
 .. _kvm_run:
 
@@ -8765,6 +8813,15 @@ helpful if user space wants to emulate instructions which are not
 This capability can be enabled dynamically even if VCPUs were already
 created and are running.
 
+7.47 KVM_CAP_ARM_RMI
+--------------------
+
+:Architectures: arm64
+:Target: VM
+:Parameters: None
+
+This capability indicates that support for CCA realms is available.
+
 8. Other capabilities.
 ======================
 
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index dddb781b0507..8e66ba9c81db 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -974,6 +974,7 @@ struct kvm_enable_cap {
 #define KVM_CAP_GUEST_MEMFD_FLAGS 244
 #define KVM_CAP_ARM_SEA_TO_USER 245
 #define KVM_CAP_S390_USER_OPEREXEC 246
+#define KVM_CAP_ARM_RMI 247
 
 struct kvm_irq_routing_irqchip {
 	__u32 irqchip;
@@ -1628,4 +1629,26 @@ struct kvm_pre_fault_memory {
 	__u64 padding[5];
 };
 
+/* Available with KVM_CAP_ARM_RMI, only for VMs with KVM_VM_TYPE_ARM_REALM  */
+struct kvm_arm_rmi_psci_complete {
+	__u64 target_mpidr;
+	__u32 psci_status;
+	__u32 padding[3];
+};
+
+#define KVM_ARM_VCPU_RMI_PSCI_COMPLETE	_IOW(KVMIO, 0xd6, struct kvm_arm_rmi_psci_complete)
+
+/* Available with KVM_CAP_ARM_RMI, only for VMs with KVM_VM_TYPE_ARM_REALM */
+struct kvm_arm_rmi_populate {
+	__u64 base;
+	__u64 size;
+	__u64 source_uaddr;
+	__u32 flags;
+	__u32 reserved;
+};
+
+#define KVM_ARM_RMI_POPULATE_FLAGS_MEASURE	(1 << 0)
+
+#define KVM_ARM_RMI_POPULATE	_IOW(KVMIO, 0xd7, struct kvm_arm_rmi_populate)
+
 #endif /* __LINUX_KVM_H */
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:10:44 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:10:44 +0000
Subject: [PATCH v12 07/46] arm64: RMI: Basic infrastructure for creating a realm.
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-8-steven.price@arm.com>

Introduce the skeleton functions for creating and destroying a realm.
The IPA size requested is checked against what the RMM supports.

The actual work of constructing the realm will be added in future
patches.

Signed-off-by: Steven Price <steven.price at arm.com>
---
Changes since v11:
 * Major rework to drop the realm configuration and make the
   construction of realms implicit rather than driven by the VMM
   directly.
 * The code to create RDs, handle VMIDs etc is moved to later patches.
Changes since v10:
 * Rename from RME to RMI.
 * Move the stage2 cleanup to a later patch.
Changes since v9:
 * Avoid walking the stage 2 page tables when destroying the realm -
   the real ones are not accessible to the non-secure world, and the RMM
   may leave junk in the physical pages when returning them.
 * Fix an error path in realm_create_rd() to actually return an error value.
Changes since v8:
 * Fix free_delegated_granule() to not call kvm_account_pgtable_pages();
   a separate wrapper will be introduced in a later patch to deal with
   RTTs.
 * Minor code cleanups following review.
Changes since v7:
 * Minor code cleanup following Gavin's review.
Changes since v6:
 * Separate RMM RTT calculations from host PAGE_SIZE. This allows the
   host page size to be larger than 4k while still communicating with an
   RMM which uses 4k granules.
Changes since v5:
 * Introduce free_delegated_granule() to replace many
   undelegate/free_page() instances and centralise the comment on
   leaking when the undelegate fails.
 * Several other minor improvements suggested by reviews - thanks for
   the feedback!
Changes since v2:
 * Improved commit description.
 * Improved return failures for rmi_check_version().
 * Clear contents of PGD after it has been undelegated in case the RMM
   left stale data.
 * Minor changes to reflect changes in previous patches.
---
 arch/arm64/include/asm/kvm_emulate.h |  5 ++
 arch/arm64/include/asm/kvm_rmi.h     | 18 +++++++
 arch/arm64/kvm/arm.c                 | 11 ++++
 arch/arm64/kvm/mmu.c                 | 11 ++--
 arch/arm64/kvm/rmi.c                 | 81 ++++++++++++++++++++++++++++
 5 files changed, 123 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 67f75678e489..e7e9364ae118 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -709,6 +709,11 @@ static inline enum realm_state kvm_realm_state(struct kvm *kvm)
 	return READ_ONCE(kvm->arch.realm.state);
 }
 
+static inline bool kvm_realm_is_created(struct kvm *kvm)
+{
+	return kvm_is_realm(kvm) && kvm_realm_state(kvm) != REALM_STATE_NONE;
+}
+
 static inline bool vcpu_is_rec(struct kvm_vcpu *vcpu)
 {
 	return false;
diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_rmi.h
index 3506f50b05cd..7f06aa5b0550 100644
--- a/arch/arm64/include/asm/kvm_rmi.h
+++ b/arch/arm64/include/asm/kvm_rmi.h
@@ -6,6 +6,8 @@
 #ifndef __ASM_KVM_RMI_H
 #define __ASM_KVM_RMI_H
 
+#include <asm/rmi_smc.h>
+
 /**
  * enum realm_state - State of a Realm
  */
@@ -46,11 +48,27 @@ enum realm_state {
  * struct realm - Additional per VM data for a Realm
  *
  * @state: The lifetime state machine for the realm
+ * @rd: Kernel mapping of the Realm Descriptor (RD)
+ * @params: Parameters for the RMI_REALM_CREATE command
+ * @num_aux: The number of auxiliary pages required by the RMM
+ * @vmid: VMID to be used by the RMM for the realm
+ * @ia_bits: Number of valid Input Address bits in the IPA
  */
 struct realm {
 	enum realm_state state;
+
+	void *rd;
+	struct realm_params *params;
+
+	unsigned long num_aux;
+	unsigned int vmid;
+	unsigned int ia_bits;
 };
 
 void kvm_init_rmi(void);
+u32 kvm_realm_ipa_limit(void);
+
+int kvm_init_realm_vm(struct kvm *kvm);
+void kvm_destroy_realm(struct kvm *kvm);
 
 #endif /* __ASM_KVM_RMI_H */
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index a537f56f97db..4ce3ad1d69b0 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -207,6 +207,13 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 
 	bitmap_zero(kvm->arch.vcpu_features, KVM_VCPU_MAX_FEATURES);
 
+	/* Initialise the realm bits after the generic bits are enabled */
+	if (kvm_is_realm(kvm)) {
+		ret = kvm_init_realm_vm(kvm);
+		if (ret)
+			goto err_free_cpumask;
+	}
+
 	return 0;
 
 err_free_cpumask:
@@ -266,6 +273,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
 	kvm_unshare_hyp(kvm, kvm + 1);
 
 	kvm_arm_teardown_hypercalls(kvm);
+	kvm_destroy_realm(kvm);
 }
 
 static bool kvm_has_full_ptr_auth(void)
@@ -427,6 +435,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 		else
 			r = kvm_supports_cacheable_pfnmap();
 		break;
+	case KVM_CAP_ARM_RMI:
+		r = static_key_enabled(&kvm_rmi_is_available);
+		break;
 
 	default:
 		r = 0;
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index 48d7c372a4cd..d91e7eb2c8d3 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -872,12 +872,16 @@ static struct kvm_pgtable_mm_ops kvm_s2_mm_ops = {
 	.icache_inval_pou	= invalidate_icache_guest_page,
 };
 
-static int kvm_init_ipa_range(struct kvm_s2_mmu *mmu, unsigned long type)
+static int kvm_init_ipa_range(struct kvm *kvm,
+			      struct kvm_s2_mmu *mmu, unsigned long type)
 {
 	u32 kvm_ipa_limit = get_kvm_ipa_limit();
 	u64 mmfr0, mmfr1;
 	u32 phys_shift;
 
+	if (kvm_is_realm(kvm))
+		kvm_ipa_limit = kvm_realm_ipa_limit();
+
 	if (type & ~KVM_VM_TYPE_ARM_IPA_SIZE_MASK)
 		return -EINVAL;
 
@@ -974,7 +978,7 @@ int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long t
 		return -EINVAL;
 	}
 
-	err = kvm_init_ipa_range(mmu, type);
+	err = kvm_init_ipa_range(kvm, mmu, type);
 	if (err)
 		return err;
 
@@ -1113,7 +1117,8 @@ void kvm_free_stage2_pgd(struct kvm_s2_mmu *mmu)
 	write_unlock(&kvm->mmu_lock);
 
 	if (pgt) {
-		kvm_stage2_destroy(pgt);
+		if (!kvm_is_realm(kvm))
+			kvm_stage2_destroy(pgt);
 		kfree(pgt);
 	}
 }
diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
index 629ace10cacc..c2b13fecfd11 100644
--- a/arch/arm64/kvm/rmi.c
+++ b/arch/arm64/kvm/rmi.c
@@ -5,9 +5,18 @@
 
 #include <linux/kvm_host.h>
 
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_mmu.h>
 #include <asm/rmi_cmds.h>
 #include <asm/virt.h>
 
+#include <asm/kvm_pgtable.h>
+
+static unsigned long rmm_feat_reg0;
+
+#define RMM_PAGE_SHIFT		12
+#define RMM_PAGE_SIZE		BIT(RMM_PAGE_SHIFT)
+
 static int rmi_check_version(void)
 {
 	struct arm_smccc_res res;
@@ -47,6 +56,75 @@ static int rmi_check_version(void)
 	return 0;
 }
 
+u32 kvm_realm_ipa_limit(void)
+{
+	return u64_get_bits(rmm_feat_reg0, RMI_FEATURE_REGISTER_0_S2SZ);
+}
+
+static int free_delegated_granule(phys_addr_t phys)
+{
+	if (WARN_ON(rmi_granule_undelegate(phys))) {
+		/* Undelegate failed: leak the page */
+		return -EBUSY;
+	}
+
+	free_page((unsigned long)phys_to_virt(phys));
+
+	return 0;
+}
+
+void kvm_destroy_realm(struct kvm *kvm)
+{
+	struct realm *realm = &kvm->arch.realm;
+	size_t pgd_size = kvm_pgtable_stage2_pgd_size(kvm->arch.mmu.vtcr);
+	int i;
+
+	write_lock(&kvm->mmu_lock);
+	kvm_stage2_unmap_range(&kvm->arch.mmu, 0,
+			       BIT(realm->ia_bits - 1), true);
+	write_unlock(&kvm->mmu_lock);
+
+	if (realm->params) {
+		free_page((unsigned long)realm->params);
+		realm->params = NULL;
+	}
+
+	if (!kvm_realm_is_created(kvm))
+		return;
+
+	WRITE_ONCE(realm->state, REALM_STATE_DYING);
+
+	if (realm->rd) {
+		phys_addr_t rd_phys = virt_to_phys(realm->rd);
+
+		if (WARN_ON(rmi_realm_destroy(rd_phys)))
+			return;
+		free_delegated_granule(rd_phys);
+		realm->rd = NULL;
+	}
+
+	for (i = 0; i < pgd_size; i += RMM_PAGE_SIZE) {
+		phys_addr_t pgd_phys = kvm->arch.mmu.pgd_phys + i;
+
+		if (WARN_ON(rmi_granule_undelegate(pgd_phys)))
+			return;
+	}
+
+	WRITE_ONCE(realm->state, REALM_STATE_DEAD);
+
+	/* Now that the Realm is destroyed, free the entry level RTTs */
+	kvm_free_stage2_pgd(&kvm->arch.mmu);
+}
+
+int kvm_init_realm_vm(struct kvm *kvm)
+{
+	kvm->arch.realm.params = (void *)get_zeroed_page(GFP_KERNEL);
+
+	if (!kvm->arch.realm.params)
+		return -ENOMEM;
+	return 0;
+}
+
 void kvm_init_rmi(void)
 {
 	/* Only 4k page size on the host is supported */
@@ -57,5 +135,8 @@ void kvm_init_rmi(void)
 	if (rmi_check_version())
 		return;
 
+	if (WARN_ON(rmi_features(0, &rmm_feat_reg0)))
+		return;
+
 	/* Future patch will enable static branch kvm_rmi_is_available */
 }
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:10:45 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:10:45 +0000
Subject: [PATCH v12 08/46] kvm: arm64: Don't expose unsupported capabilities for realm guests
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-9-steven.price@arm.com>

From: Suzuki K Poulose <suzuki.poulose at arm.com>

RMM v1.0 provides no mechanism for the host to perform debug operations
on the guest. So limit the extensions that are visible to an allowlist
so that only those capabilities we can support are advertised.

Signed-off-by: Suzuki K Poulose <suzuki.poulose at arm.com>
Signed-off-by: Steven Price <steven.price at arm.com>
---
Changes since v10:
 * Add a kvm_realm_ext_allowed() function which limits which extensions
   are exposed to an allowlist. This removes the need for special casing
   various extensions.
Changes since v7:
 * Remove the helper functions and inline the kvm_is_realm() check with
   a ternary operator.
 * Rewrite the commit message to explain this patch.
---
 arch/arm64/kvm/arm.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 4ce3ad1d69b0..345d9f56e98e 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -310,6 +310,26 @@ static bool kvm_has_full_ptr_auth(void)
 		(apa + api + apa3) == 1);
 }
 
+static bool kvm_realm_ext_allowed(long ext)
+{
+	switch (ext) {
+	case KVM_CAP_IRQCHIP:
+	case KVM_CAP_ARM_PSCI:
+	case KVM_CAP_ARM_PSCI_0_2:
+	case KVM_CAP_NR_VCPUS:
+	case KVM_CAP_MAX_VCPUS:
+	case KVM_CAP_MAX_VCPU_ID:
+	case KVM_CAP_MSI_DEVID:
+	case KVM_CAP_ARM_VM_IPA_SIZE:
+	case KVM_CAP_ARM_PMU_V3:
+	case KVM_CAP_ARM_PTRAUTH_ADDRESS:
+	case KVM_CAP_ARM_PTRAUTH_GENERIC:
+	case KVM_CAP_ARM_RMI:
+		return true;
+	}
+	return false;
+}
+
 int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 {
 	int r;
@@ -317,6 +337,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 	if (kvm && kvm_vm_is_protected(kvm) && !kvm_pvm_ext_allowed(ext))
 		return 0;
 
+	if (kvm && kvm_is_realm(kvm) && !kvm_realm_ext_allowed(ext))
+		return 0;
+
 	switch (ext) {
 	case KVM_CAP_IRQCHIP:
 		r = vgic_present;
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:10:46 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:10:46 +0000
Subject: [PATCH v12 09/46] KVM: arm64: Allow passing machine type in KVM creation
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-10-steven.price@arm.com>

Previously machine type was used purely for specifying the physical
address size of the guest. Reserve the higher bits to specify an ARM
specific machine type and declare a new type 'KVM_VM_TYPE_ARM_REALM'
used to create a realm guest.

Reviewed-by: Suzuki K Poulose <suzuki.poulose at arm.com>
Reviewed-by: Gavin Shan <gshan at redhat.com>
Signed-off-by: Steven Price <steven.price at arm.com>
---
Changes since v9:
 * Explictly set realm.state to REALM_STATE_NONE rather than rely on the
   zeroing of the structure.
Changes since v7:
 * Add some documentation explaining the new machine type.
Changes since v6:
 * Make the check for kvm_rme_is_available more visible and report an
   error code of -EPERM (instead of -EINVAL) to make it explicit that
   the kernel supports RME, but the platform doesn't.
---
 Documentation/virt/kvm/api.rst | 16 ++++++++++++++--
 arch/arm64/kvm/arm.c           | 16 ++++++++++++++++
 arch/arm64/kvm/mmu.c           |  3 ---
 include/uapi/linux/kvm.h       | 19 +++++++++++++++----
 4 files changed, 45 insertions(+), 9 deletions(-)

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 2d5dc7e48954..d7ebf42933e8 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -181,8 +181,20 @@ flag KVM_VM_MIPS_VZ.
 ARM64:
 ^^^^^^
 
-On arm64, the physical address size for a VM (IPA Size limit) is limited
-to 40bits by default. The limit can be configured if the host supports the
+On arm64, the machine type identifier is used to encode a type and the
+physical address size for the VM. The lower byte (bits[7-0]) encode the
+address size and the upper bits[11-8] encode a machine type. The machine
+types that might be available are:
+
+ ======================   ============================================
+ KVM_VM_TYPE_ARM_NORMAL   A standard VM
+ KVM_VM_TYPE_ARM_REALM    A "Realm" VM using the Arm Confidential
+                          Compute extensions, the VM's memory is
+                          protected from the host.
+ ======================   ============================================
+
+The physical address size for a VM (IPA Size limit) is limited to 40bits
+by default. The limit can be configured if the host supports the
 extension KVM_CAP_ARM_VM_IPA_SIZE. When supported, use
 KVM_VM_TYPE_ARM_IPA_SIZE(IPA_Bits) to set the size in the machine type
 identifier, where IPA_Bits is the maximum width of any physical
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 345d9f56e98e..941d1bec8e77 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -170,6 +170,22 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 	mutex_unlock(&kvm->lock);
 #endif
 
+	if (type & ~(KVM_VM_TYPE_ARM_MASK | KVM_VM_TYPE_ARM_IPA_SIZE_MASK))
+		return -EINVAL;
+
+	switch (type & KVM_VM_TYPE_ARM_MASK) {
+	case KVM_VM_TYPE_ARM_NORMAL:
+		break;
+	case KVM_VM_TYPE_ARM_REALM:
+		if (!static_branch_unlikely(&kvm_rmi_is_available))
+			return -EINVAL;
+		WRITE_ONCE(kvm->arch.realm.state, REALM_STATE_NONE);
+		kvm->arch.is_realm = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
 	kvm_init_nested(kvm);
 
 	ret = kvm_share_hyp(kvm, kvm + 1);
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index d91e7eb2c8d3..ed86a10f08e0 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -882,9 +882,6 @@ static int kvm_init_ipa_range(struct kvm *kvm,
 	if (kvm_is_realm(kvm))
 		kvm_ipa_limit = kvm_realm_ipa_limit();
 
-	if (type & ~KVM_VM_TYPE_ARM_IPA_SIZE_MASK)
-		return -EINVAL;
-
 	phys_shift = KVM_VM_TYPE_ARM_IPA_SIZE(type);
 	if (is_protected_kvm_enabled()) {
 		phys_shift = kvm_ipa_limit;
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 8e66ba9c81db..c51fd88feedf 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -681,14 +681,25 @@ struct kvm_enable_cap {
 #define KVM_S390_SIE_PAGE_OFFSET 1
 
 /*
- * On arm64, machine type can be used to request the physical
- * address size for the VM. Bits[7-0] are reserved for the guest
- * PA size shift (i.e, log2(PA_Size)). For backward compatibility,
- * value 0 implies the default IPA size, 40bits.
+ * On arm64, machine type can be used to request both the machine type and
+ * the physical address size for the VM.
+ *
+ * Bits[11-8] are reserved for the ARM specific machine type.
+ *
+ * Bits[7-0] are reserved for the guest PA size shift (i.e, log2(PA_Size)).
+ * For backward compatibility, value 0 implies the default IPA size, 40bits.
  */
+#define KVM_VM_TYPE_ARM_SHIFT		8
+#define KVM_VM_TYPE_ARM_MASK		(0xfULL << KVM_VM_TYPE_ARM_SHIFT)
+#define KVM_VM_TYPE_ARM(_type)		\
+	(((_type) << KVM_VM_TYPE_ARM_SHIFT) & KVM_VM_TYPE_ARM_MASK)
+#define KVM_VM_TYPE_ARM_NORMAL		KVM_VM_TYPE_ARM(0)
+#define KVM_VM_TYPE_ARM_REALM		KVM_VM_TYPE_ARM(1)
+
 #define KVM_VM_TYPE_ARM_IPA_SIZE_MASK	0xffULL
 #define KVM_VM_TYPE_ARM_IPA_SIZE(x)		\
 	((x) & KVM_VM_TYPE_ARM_IPA_SIZE_MASK)
+
 /*
  * ioctls for /dev/kvm fds:
  */
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:10:47 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:10:47 +0000
Subject: [PATCH v12 10/46] arm64: RMI: RTT tear down
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-11-steven.price@arm.com>

The RMM owns the stage 2 page tables for a realm, and KVM must request
that the RMM creates/destroys entries as necessary. The physical pages
to store the page tables are delegated to the realm as required, and can
be undelegated when no longer used.

Creating new RTTs is the easy part, tearing down is a little more
tricky. The result of realm_rtt_destroy() can be used to effectively
walk the tree and destroy the entries (undelegating pages that were
given to the realm).

Signed-off-by: Steven Price <steven.price at arm.com>
---
Changes since v11:
 * Moved some code from earlier in the series to this one so that it's
   added when it's first used.
Changes since v10:
 * RME->RMI rename.
 * Some code to handle freeing stage 2 PGD moved into this patch where
   it belongs.
Changes since v9:
 * Add a comment clarifying that root level RTTs are not destroyed until
   after the RD is destroyed.
Changes since v8:
 * Introduce free_rtt() wrapper which calls free_delegated_granule()
   followed by kvm_account_pgtable_pages(). This makes it clear where an
   RTT is being freed rather than just a delegated granule.
Changes since v6:
 * Move rme_rtt_level_mapsize() and supporting defines from kvm_rme.h
   into rme.c as they are only used in that file.
Changes since v5:
 * Rename some RME_xxx defines to do with page sizes as RMM_xxx - they are
   a property of the RMM specification not the RME architecture.
Changes since v2:
 * Moved {alloc,free}_delegated_page() and ensure_spare_page() to a
   later patch when they are actually used.
 * Some simplifications now rmi_xxx() functions allow NULL as an output
   parameter.
 * Improved comments and code layout.
---
 arch/arm64/include/asm/kvm_rmi.h |   7 ++
 arch/arm64/kvm/mmu.c             |  15 ++-
 arch/arm64/kvm/rmi.c             | 151 +++++++++++++++++++++++++++++++
 3 files changed, 172 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_rmi.h
index 7f06aa5b0550..cb7350f8a01a 100644
--- a/arch/arm64/include/asm/kvm_rmi.h
+++ b/arch/arm64/include/asm/kvm_rmi.h
@@ -70,5 +70,12 @@ u32 kvm_realm_ipa_limit(void);
 
 int kvm_init_realm_vm(struct kvm *kvm);
 void kvm_destroy_realm(struct kvm *kvm);
+void kvm_realm_destroy_rtts(struct kvm *kvm);
+
+static inline bool kvm_realm_is_private_address(struct realm *realm,
+						unsigned long addr)
+{
+	return !(addr & BIT(realm->ia_bits - 1));
+}
 
 #endif /* __ASM_KVM_RMI_H */
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index ed86a10f08e0..68e6cefe1135 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -1098,10 +1098,23 @@ void stage2_unmap_vm(struct kvm *kvm)
 void kvm_free_stage2_pgd(struct kvm_s2_mmu *mmu)
 {
 	struct kvm *kvm = kvm_s2_mmu_to_kvm(mmu);
-	struct kvm_pgtable *pgt = NULL;
+	struct kvm_pgtable *pgt;
 
 	write_lock(&kvm->mmu_lock);
 	pgt = mmu->pgt;
+	if (kvm_is_realm(kvm) &&
+	    (kvm_realm_state(kvm) != REALM_STATE_DEAD &&
+	     kvm_realm_state(kvm) != REALM_STATE_NONE)) {
+		write_unlock(&kvm->mmu_lock);
+		kvm_realm_destroy_rtts(kvm);
+
+		/*
+		 * The PGD pages can be reclaimed only after the realm (RD) is
+		 * destroyed. We call this again from kvm_destroy_realm() after
+		 * the RD is destroyed.
+		 */
+		return;
+	}
 	if (pgt) {
 		mmu->pgd_phys = 0;
 		mmu->pgt = NULL;
diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
index c2b13fecfd11..e57e8b7eafa9 100644
--- a/arch/arm64/kvm/rmi.c
+++ b/arch/arm64/kvm/rmi.c
@@ -17,6 +17,22 @@ static unsigned long rmm_feat_reg0;
 #define RMM_PAGE_SHIFT		12
 #define RMM_PAGE_SIZE		BIT(RMM_PAGE_SHIFT)
 
+#define RMM_RTT_BLOCK_LEVEL	2
+#define RMM_RTT_MAX_LEVEL	3
+
+/* See ARM64_HW_PGTABLE_LEVEL_SHIFT() */
+#define RMM_RTT_LEVEL_SHIFT(l)	\
+	((RMM_PAGE_SHIFT - 3) * (4 - (l)) + 3)
+#define RMM_L2_BLOCK_SIZE	BIT(RMM_RTT_LEVEL_SHIFT(2))
+
+static inline unsigned long rmi_rtt_level_mapsize(int level)
+{
+	if (WARN_ON(level > RMM_RTT_MAX_LEVEL))
+		return RMM_PAGE_SIZE;
+
+	return (1UL << RMM_RTT_LEVEL_SHIFT(level));
+}
+
 static int rmi_check_version(void)
 {
 	struct arm_smccc_res res;
@@ -61,6 +77,15 @@ u32 kvm_realm_ipa_limit(void)
 	return u64_get_bits(rmm_feat_reg0, RMI_FEATURE_REGISTER_0_S2SZ);
 }
 
+static int get_start_level(struct realm *realm)
+{
+	/*
+	 * Open coded version of 4 - stage2_pgtable_levels(ia_bits) but using
+	 * the RMM's page size rather than the host's.
+	 */
+	return 4 - ((realm->ia_bits - 8) / (RMM_PAGE_SHIFT - 3));
+}
+
 static int free_delegated_granule(phys_addr_t phys)
 {
 	if (WARN_ON(rmi_granule_undelegate(phys))) {
@@ -73,6 +98,131 @@ static int free_delegated_granule(phys_addr_t phys)
 	return 0;
 }
 
+static void free_rtt(phys_addr_t phys)
+{
+	if (free_delegated_granule(phys))
+		return;
+
+	kvm_account_pgtable_pages(phys_to_virt(phys), -1);
+}
+
+static int realm_rtt_destroy(struct realm *realm, unsigned long addr,
+			     int level, phys_addr_t *rtt_granule,
+			     unsigned long *next_addr)
+{
+	unsigned long out_rtt;
+	int ret;
+
+	ret = rmi_rtt_destroy(virt_to_phys(realm->rd), addr, level,
+			      &out_rtt, next_addr);
+
+	*rtt_granule = out_rtt;
+
+	return ret;
+}
+
+static int realm_tear_down_rtt_level(struct realm *realm, int level,
+				     unsigned long start, unsigned long end)
+{
+	ssize_t map_size;
+	unsigned long addr, next_addr;
+
+	if (WARN_ON(level > RMM_RTT_MAX_LEVEL))
+		return -EINVAL;
+
+	map_size = rmi_rtt_level_mapsize(level - 1);
+
+	for (addr = start; addr < end; addr = next_addr) {
+		phys_addr_t rtt_granule;
+		int ret;
+		unsigned long align_addr = ALIGN(addr, map_size);
+
+		next_addr = ALIGN(addr + 1, map_size);
+
+		if (next_addr > end || align_addr != addr) {
+			/*
+			 * The target range is smaller than what this level
+			 * covers, recurse deeper.
+			 */
+			ret = realm_tear_down_rtt_level(realm,
+							level + 1,
+							addr,
+							min(next_addr, end));
+			if (ret)
+				return ret;
+			continue;
+		}
+
+		ret = realm_rtt_destroy(realm, addr, level,
+					&rtt_granule, &next_addr);
+
+		switch (RMI_RETURN_STATUS(ret)) {
+		case RMI_SUCCESS:
+			free_rtt(rtt_granule);
+			break;
+		case RMI_ERROR_RTT:
+			if (next_addr > addr) {
+				/* Missing RTT, skip */
+				break;
+			}
+			/*
+			 * We tear down the RTT range for the full IPA
+			 * space, after everything is unmapped. Also we
+			 * descend down only if we cannot tear down a
+			 * top level RTT. Thus RMM must be able to walk
+			 * to the requested level. e.g., a block mapping
+			 * exists at L1 or L2.
+			 */
+			if (WARN_ON(RMI_RETURN_INDEX(ret) != level))
+				return -EBUSY;
+			if (WARN_ON(level == RMM_RTT_MAX_LEVEL))
+				return -EBUSY;
+
+			/*
+			 * The table has active entries in it, recurse deeper
+			 * and tear down the RTTs.
+			 */
+			next_addr = ALIGN(addr + 1, map_size);
+			ret = realm_tear_down_rtt_level(realm,
+							level + 1,
+							addr,
+							next_addr);
+			if (ret)
+				return ret;
+			/*
+			 * Now that the child RTTs are destroyed,
+			 * retry at this level.
+			 */
+			next_addr = addr;
+			break;
+		default:
+			WARN_ON(1);
+			return -ENXIO;
+		}
+	}
+
+	return 0;
+}
+
+static int realm_tear_down_rtt_range(struct realm *realm,
+				     unsigned long start, unsigned long end)
+{
+	/*
+	 * Root level RTTs can only be destroyed after the RD is destroyed. So
+	 * tear down everything below the root level
+	 */
+	return realm_tear_down_rtt_level(realm, get_start_level(realm) + 1,
+					 start, end);
+}
+
+void kvm_realm_destroy_rtts(struct kvm *kvm)
+{
+	struct realm *realm = &kvm->arch.realm;
+	unsigned int ia_bits = realm->ia_bits;
+
+	WARN_ON(realm_tear_down_rtt_range(realm, 0, (1UL << ia_bits)));
+}
+
 void kvm_destroy_realm(struct kvm *kvm)
 {
 	struct realm *realm = &kvm->arch.realm;
@@ -83,6 +233,7 @@ void kvm_destroy_realm(struct kvm *kvm)
 	kvm_stage2_unmap_range(&kvm->arch.mmu, 0,
 			       BIT(realm->ia_bits - 1), true);
 	write_unlock(&kvm->mmu_lock);
+	kvm_realm_destroy_rtts(kvm);
 
 	if (realm->params) {
 		free_page((unsigned long)realm->params);
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:10:48 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:10:48 +0000
Subject: [PATCH v12 11/46] arm64: RMI: Activate realm on first VCPU run
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-12-steven.price@arm.com>

When a VCPU migrates to another physical CPU check if this is the first
time the guest has run, and if so activate the realm.

Before the realm can be activated it must first be created, this is a
stub in this patch and will be filled in by a later patch.

Signed-off-by: Steven Price <steven.price at arm.com>
---
New patch for v12
---
 arch/arm64/include/asm/kvm_rmi.h |  1 +
 arch/arm64/kvm/arm.c             |  6 +++++
 arch/arm64/kvm/rmi.c             | 42 ++++++++++++++++++++++++++++++++
 3 files changed, 49 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_rmi.h
index cb7350f8a01a..e4534af06d96 100644
--- a/arch/arm64/include/asm/kvm_rmi.h
+++ b/arch/arm64/include/asm/kvm_rmi.h
@@ -69,6 +69,7 @@ void kvm_init_rmi(void);
 u32 kvm_realm_ipa_limit(void);
 
 int kvm_init_realm_vm(struct kvm *kvm);
+int kvm_activate_realm(struct kvm *kvm);
 void kvm_destroy_realm(struct kvm *kvm);
 void kvm_realm_destroy_rtts(struct kvm *kvm);
 
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 941d1bec8e77..542df37b9e82 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -951,6 +951,12 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
 			return ret;
 	}
 
+	if (kvm_is_realm(vcpu->kvm)) {
+		ret = kvm_activate_realm(kvm);
+		if (ret)
+			return ret;
+	}
+
 	mutex_lock(&kvm->arch.config_lock);
 	set_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags);
 	mutex_unlock(&kvm->arch.config_lock);
diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
index e57e8b7eafa9..98929382c365 100644
--- a/arch/arm64/kvm/rmi.c
+++ b/arch/arm64/kvm/rmi.c
@@ -223,6 +223,48 @@ void kvm_realm_destroy_rtts(struct kvm *kvm)
 	WARN_ON(realm_tear_down_rtt_range(realm, 0, (1UL << ia_bits)));
 }
 
+static int realm_ensure_created(struct kvm *kvm)
+{
+	/* Provided in later patch */
+	return -ENXIO;
+}
+
+int kvm_activate_realm(struct kvm *kvm)
+{
+	struct realm *realm = &kvm->arch.realm;
+	int ret;
+
+	if (!kvm_is_realm(kvm))
+		return -ENXIO;
+
+	if (kvm_realm_state(kvm) == REALM_STATE_ACTIVE)
+		return 0;
+
+	guard(mutex)(&kvm->arch.config_lock);
+	/* Check again with the lock held */
+	if (kvm_realm_state(kvm) == REALM_STATE_ACTIVE)
+		return 0;
+
+	ret = realm_ensure_created(kvm);
+	if (ret)
+		return ret;
+
+	/* Mark state as dead in case we fail */
+	WRITE_ONCE(realm->state, REALM_STATE_DEAD);
+
+	if (!irqchip_in_kernel(kvm)) {
+		/* Userspace irqchip not yet supported with realms */
+		return -EOPNOTSUPP;
+	}
+
+	ret = rmi_realm_activate(virt_to_phys(realm->rd));
+	if (ret)
+		return -ENXIO;
+
+	WRITE_ONCE(realm->state, REALM_STATE_ACTIVE);
+	return 0;
+}
+
 void kvm_destroy_realm(struct kvm *kvm)
 {
 	struct realm *realm = &kvm->arch.realm;
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:10:49 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:10:49 +0000
Subject: [PATCH v12 12/46] arm64: RMI: Allocate/free RECs to match vCPUs
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-13-steven.price@arm.com>

The RMM maintains a data structure known as the Realm Execution Context
(or REC). It is similar to struct kvm_vcpu and tracks the state of the
virtual CPUs. KVM must delegate memory and request the structures are
created when vCPUs are created, and suitably tear down on destruction.

RECs must also be supplied with addition pages - auxiliary (or AUX)
granules - for storing the larger registers state (e.g. for SVE). The
number of AUX granules for a REC depends on the parameters with which
the Realm was created - the RMM makes this information available via the
RMI_REC_AUX_COUNT call performed after creating the Realm Descriptor (RD).

Note that only some of register state for the REC can be set by KVM, the
rest is defined by the RMM (zeroed). The register state then cannot be
changed by KVM after the REC is created (except when the guest
explicitly requests this e.g. by performing a PSCI call).

Signed-off-by: Steven Price <steven.price at arm.com>
---
Changes since v11:
 * Remove the KVM_ARM_VCPU_REC feature. User space no longer needs to
   configure each VCPU separately, RECs are created on the first VCPU
   run of the guest.
Changes since v9:
 * Size the aux_pages array according to the PAGE_SIZE of the host.
Changes since v7:
 * Add comment explaining the aux_pages array.
 * Rename "undeleted_failed" variable to "should_free" to avoid a
   confusing double negative.
Changes since v6:
 * Avoid reporting the KVM_ARM_VCPU_REC feature if the guest isn't a
   realm guest.
 * Support host page size being larger than RMM's granule size when
   allocating/freeing aux granules.
Changes since v5:
 * Separate the concept of vcpu_is_rec() and
   kvm_arm_vcpu_rec_finalized() by using the KVM_ARM_VCPU_REC feature as
   the indication that the VCPU is a REC.
Changes since v2:
 * Free rec->run earlier in kvm_destroy_realm() and adapt to previous patches.
---
 arch/arm64/include/asm/kvm_emulate.h |   2 +-
 arch/arm64/include/asm/kvm_host.h    |   3 +
 arch/arm64/include/asm/kvm_rmi.h     |  21 +++
 arch/arm64/kvm/arm.c                 |  10 +-
 arch/arm64/kvm/reset.c               |   1 +
 arch/arm64/kvm/rmi.c                 | 185 +++++++++++++++++++++++++++
 6 files changed, 219 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index e7e9364ae118..f884bac43c06 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -716,7 +716,7 @@ static inline bool kvm_realm_is_created(struct kvm *kvm)
 
 static inline bool vcpu_is_rec(struct kvm_vcpu *vcpu)
 {
-	return false;
+	return kvm_is_realm(vcpu->kvm);
 }
 
 #endif /* __ARM64_KVM_EMULATE_H__ */
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index da913fee70b6..5a24227088c1 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -900,6 +900,9 @@ struct kvm_vcpu_arch {
 
 	/* Per-vcpu TLB for VNCR_EL2 -- NULL when !NV */
 	struct vncr_tlb	*vncr_tlb;
+
+	/* Realm meta data */
+	struct realm_rec rec;
 };
 
 /*
diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_rmi.h
index e4534af06d96..dbb4b97d5d42 100644
--- a/arch/arm64/include/asm/kvm_rmi.h
+++ b/arch/arm64/include/asm/kvm_rmi.h
@@ -65,6 +65,26 @@ struct realm {
 	unsigned int ia_bits;
 };
 
+/**
+ * struct realm_rec - Additional per VCPU data for a Realm
+ *
+ * @mpidr: MPIDR (Multiprocessor Affinity Register) value to identify this VCPU
+ * @rec_page: Kernel VA of the RMM's private page for this REC
+ * @aux_pages: Additional pages private to the RMM for this REC
+ * @run: Kernel VA of the RmiRecRun structure shared with the RMM
+ */
+struct realm_rec {
+	unsigned long mpidr;
+	void *rec_page;
+	/*
+	 * REC_PARAMS_AUX_GRANULES is the maximum number of 4K granules that
+	 * the RMM can require. The array is sized to be large enough for the
+	 * maximum number of host sized pages that could be required.
+	 */
+	struct page *aux_pages[(REC_PARAMS_AUX_GRANULES * SZ_4K) >> PAGE_SHIFT];
+	struct rec_run *run;
+};
+
 void kvm_init_rmi(void);
 u32 kvm_realm_ipa_limit(void);
 
@@ -72,6 +92,7 @@ int kvm_init_realm_vm(struct kvm *kvm);
 int kvm_activate_realm(struct kvm *kvm);
 void kvm_destroy_realm(struct kvm *kvm);
 void kvm_realm_destroy_rtts(struct kvm *kvm);
+void kvm_destroy_rec(struct kvm_vcpu *vcpu);
 
 static inline bool kvm_realm_is_private_address(struct realm *realm,
 						unsigned long addr)
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 542df37b9e82..512d0ec9de60 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -529,6 +529,8 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
 	/* Force users to call KVM_ARM_VCPU_INIT */
 	vcpu_clear_flag(vcpu, VCPU_INITIALIZED);
 
+	vcpu->arch.rec.mpidr = INVALID_HWID;
+
 	vcpu->arch.mmu_page_cache.gfp_zero = __GFP_ZERO;
 
 	/* Set up the timer */
@@ -1502,7 +1504,7 @@ int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level,
 	return -EINVAL;
 }
 
-static unsigned long system_supported_vcpu_features(void)
+static unsigned long system_supported_vcpu_features(struct kvm *kvm)
 {
 	unsigned long features = KVM_VCPU_VALID_FEATURES;
 
@@ -1540,7 +1542,7 @@ static int kvm_vcpu_init_check_features(struct kvm_vcpu *vcpu,
 			return -ENOENT;
 	}
 
-	if (features & ~system_supported_vcpu_features())
+	if (features & ~system_supported_vcpu_features(vcpu->kvm))
 		return -EINVAL;
 
 	/*
@@ -1562,6 +1564,10 @@ static int kvm_vcpu_init_check_features(struct kvm_vcpu *vcpu,
 	if (test_bit(KVM_ARM_VCPU_HAS_EL2, &features))
 		return -EINVAL;
 
+	/* Realms are incompatible with AArch32 */
+	if (vcpu_is_rec(vcpu))
+		return -EINVAL;
+
 	return 0;
 }
 
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index 959532422d3a..4bbf58892928 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -161,6 +161,7 @@ void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu)
 	free_page((unsigned long)vcpu->arch.ctxt.vncr_array);
 	kfree(vcpu->arch.vncr_tlb);
 	kfree(vcpu->arch.ccsidr);
+	kvm_destroy_rec(vcpu);
 }
 
 static void kvm_vcpu_reset_sve(struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
index 98929382c365..27ecd7d9f757 100644
--- a/arch/arm64/kvm/rmi.c
+++ b/arch/arm64/kvm/rmi.c
@@ -229,9 +229,188 @@ static int realm_ensure_created(struct kvm *kvm)
 	return -ENXIO;
 }
 
+static void free_rec_aux(struct page **aux_pages,
+			 unsigned int num_aux)
+{
+	unsigned int i, j;
+	unsigned int page_count = 0;
+
+	for (i = 0; i < num_aux;) {
+		struct page *aux_page = aux_pages[page_count++];
+		phys_addr_t aux_page_phys = page_to_phys(aux_page);
+		bool should_free = true;
+
+		for (j = 0; j < PAGE_SIZE && i < num_aux; j += RMM_PAGE_SIZE) {
+			if (WARN_ON(rmi_granule_undelegate(aux_page_phys)))
+				should_free = false;
+			aux_page_phys += RMM_PAGE_SIZE;
+			i++;
+		}
+		/* Only free if all the undelegate calls were successful */
+		if (should_free)
+			__free_page(aux_page);
+	}
+}
+
+static int alloc_rec_aux(struct page **aux_pages,
+			 u64 *aux_phys_pages,
+			 unsigned int num_aux)
+{
+	struct page *aux_page;
+	int page_count = 0;
+	unsigned int i, j;
+	int ret;
+
+	for (i = 0; i < num_aux;) {
+		phys_addr_t aux_page_phys;
+
+		aux_page = alloc_page(GFP_KERNEL);
+		if (!aux_page) {
+			ret = -ENOMEM;
+			goto out_err;
+		}
+
+		aux_page_phys = page_to_phys(aux_page);
+		for (j = 0; j < PAGE_SIZE && i < num_aux; j += RMM_PAGE_SIZE) {
+			if (rmi_granule_delegate(aux_page_phys)) {
+				ret = -ENXIO;
+				goto err_undelegate;
+			}
+			aux_phys_pages[i++] = aux_page_phys;
+			aux_page_phys += RMM_PAGE_SIZE;
+		}
+		aux_pages[page_count++] = aux_page;
+	}
+
+	return 0;
+err_undelegate:
+	while (j > 0) {
+		j -= RMM_PAGE_SIZE;
+		i--;
+		if (WARN_ON(rmi_granule_undelegate(aux_phys_pages[i]))) {
+			/* Leak the page if the undelegate fails */
+			goto out_err;
+		}
+	}
+	__free_page(aux_page);
+out_err:
+	free_rec_aux(aux_pages, i);
+	return ret;
+}
+
+static int kvm_create_rec(struct kvm_vcpu *vcpu)
+{
+	struct user_pt_regs *vcpu_regs = vcpu_gp_regs(vcpu);
+	unsigned long mpidr = kvm_vcpu_get_mpidr_aff(vcpu);
+	struct realm *realm = &vcpu->kvm->arch.realm;
+	struct realm_rec *rec = &vcpu->arch.rec;
+	unsigned long rec_page_phys;
+	struct rec_params *params;
+	int r, i;
+
+	if (rec->run)
+		return -EBUSY;
+
+	/*
+	 * The RMM will report PSCI v1.0 to Realms and the KVM_ARM_VCPU_PSCI_0_2
+	 * flag covers v0.2 and onwards.
+	 */
+	if (!vcpu_has_feature(vcpu, KVM_ARM_VCPU_PSCI_0_2))
+		return -EINVAL;
+
+	BUILD_BUG_ON(sizeof(*params) > PAGE_SIZE);
+	BUILD_BUG_ON(sizeof(*rec->run) > PAGE_SIZE);
+
+	params = (struct rec_params *)get_zeroed_page(GFP_KERNEL);
+	rec->rec_page = (void *)__get_free_page(GFP_KERNEL);
+	rec->run = (void *)get_zeroed_page(GFP_KERNEL);
+	if (!params || !rec->rec_page || !rec->run) {
+		r = -ENOMEM;
+		goto out_free_pages;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(params->gprs); i++)
+		params->gprs[i] = vcpu_regs->regs[i];
+
+	params->pc = vcpu_regs->pc;
+
+	if (vcpu->vcpu_id == 0)
+		params->flags |= REC_PARAMS_FLAG_RUNNABLE;
+
+	rec_page_phys = virt_to_phys(rec->rec_page);
+
+	if (rmi_granule_delegate(rec_page_phys)) {
+		r = -ENXIO;
+		goto out_free_pages;
+	}
+
+	r = alloc_rec_aux(rec->aux_pages, params->aux, realm->num_aux);
+	if (r)
+		goto out_undelegate_rmm_rec;
+
+	params->num_rec_aux = realm->num_aux;
+	params->mpidr = mpidr;
+
+	if (rmi_rec_create(virt_to_phys(realm->rd),
+			   rec_page_phys,
+			   virt_to_phys(params))) {
+		r = -ENXIO;
+		goto out_free_rec_aux;
+	}
+
+	rec->mpidr = mpidr;
+
+	free_page((unsigned long)params);
+	return 0;
+
+out_free_rec_aux:
+	free_rec_aux(rec->aux_pages, realm->num_aux);
+out_undelegate_rmm_rec:
+	if (WARN_ON(rmi_granule_undelegate(rec_page_phys)))
+		rec->rec_page = NULL;
+out_free_pages:
+	free_page((unsigned long)rec->run);
+	free_page((unsigned long)rec->rec_page);
+	free_page((unsigned long)params);
+	return r;
+}
+
+void kvm_destroy_rec(struct kvm_vcpu *vcpu)
+{
+	struct realm *realm = &vcpu->kvm->arch.realm;
+	struct realm_rec *rec = &vcpu->arch.rec;
+	unsigned long rec_page_phys;
+
+	if (!vcpu_is_rec(vcpu))
+		return;
+
+	if (!rec->run) {
+		/* Nothing to do if the VCPU hasn't been finalized */
+		return;
+	}
+
+	free_page((unsigned long)rec->run);
+
+	rec_page_phys = virt_to_phys(rec->rec_page);
+
+	/*
+	 * The REC and any AUX pages cannot be reclaimed until the REC is
+	 * destroyed. So if the REC destroy fails then the REC page and any AUX
+	 * pages will be leaked.
+	 */
+	if (WARN_ON(rmi_rec_destroy(rec_page_phys)))
+		return;
+
+	free_rec_aux(rec->aux_pages, realm->num_aux);
+
+	free_delegated_granule(rec_page_phys);
+}
+
 int kvm_activate_realm(struct kvm *kvm)
 {
 	struct realm *realm = &kvm->arch.realm;
+	struct kvm_vcpu *vcpu;
+	unsigned long i;
 	int ret;
 
 	if (!kvm_is_realm(kvm))
@@ -257,6 +436,12 @@ int kvm_activate_realm(struct kvm *kvm)
 		return -EOPNOTSUPP;
 	}
 
+	kvm_for_each_vcpu(i, vcpu, kvm) {
+		ret = kvm_create_rec(vcpu);
+		if (ret)
+			return ret;
+	}
+
 	ret = rmi_realm_activate(virt_to_phys(realm->rd));
 	if (ret)
 		return -ENXIO;
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:10:50 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:10:50 +0000
Subject: [PATCH v12 13/46] KVM: arm64: vgic: Provide helper for number of list registers
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-14-steven.price@arm.com>

Currently the number of list registers available is stored in a global
(kvm_vgic_global_state.nr_lr). With Arm CCA the RMM is permitted to
reserve list registers for its own use and so the number of available
list registers can be fewer for a realm VM. Provide wrapper functions
to fetch the global in preparation for restricting nr_lr when dealing
with a realm VM.

Signed-off-by: Steven Price <steven.price at arm.com>
---
Changes in v12:
 * Upstream changes mean that vcpu isn't available everywhere we need
   it, so update helpers to take vcpu.
 * Note that the VGIC handling will be reworked for the RMM 2.0 spec.
New patch for v6
---
 arch/arm64/kvm/vgic/vgic-v2.c |  6 +++---
 arch/arm64/kvm/vgic/vgic-v3.c |  8 ++++----
 arch/arm64/kvm/vgic/vgic.c    |  6 +++---
 arch/arm64/kvm/vgic/vgic.h    | 18 ++++++++++++------
 4 files changed, 22 insertions(+), 16 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic-v2.c b/arch/arm64/kvm/vgic/vgic-v2.c
index 585491fbda80..990bf693f65d 100644
--- a/arch/arm64/kvm/vgic/vgic-v2.c
+++ b/arch/arm64/kvm/vgic/vgic-v2.c
@@ -34,11 +34,11 @@ void vgic_v2_configure_hcr(struct kvm_vcpu *vcpu,
 
 	cpuif->vgic_hcr = GICH_HCR_EN;
 
-	if (irqs_pending_outside_lrs(als))
+	if (irqs_pending_outside_lrs(als, vcpu))
 		cpuif->vgic_hcr |= GICH_HCR_NPIE;
-	if (irqs_active_outside_lrs(als))
+	if (irqs_active_outside_lrs(als, vcpu))
 		cpuif->vgic_hcr |= GICH_HCR_LRENPIE;
-	if (irqs_outside_lrs(als))
+	if (irqs_outside_lrs(als, vcpu))
 		cpuif->vgic_hcr |= GICH_HCR_UIE;
 
 	cpuif->vgic_hcr |= (cpuif->vgic_vmcr & GICH_VMCR_ENABLE_GRP0_MASK) ?
diff --git a/arch/arm64/kvm/vgic/vgic-v3.c b/arch/arm64/kvm/vgic/vgic-v3.c
index 1d6dd1b545bd..c9ff4f90c975 100644
--- a/arch/arm64/kvm/vgic/vgic-v3.c
+++ b/arch/arm64/kvm/vgic/vgic-v3.c
@@ -31,11 +31,11 @@ void vgic_v3_configure_hcr(struct kvm_vcpu *vcpu,
 
 	cpuif->vgic_hcr = ICH_HCR_EL2_En;
 
-	if (irqs_pending_outside_lrs(als))
+	if (irqs_pending_outside_lrs(als, vcpu))
 		cpuif->vgic_hcr |= ICH_HCR_EL2_NPIE;
-	if (irqs_active_outside_lrs(als))
+	if (irqs_active_outside_lrs(als, vcpu))
 		cpuif->vgic_hcr |= ICH_HCR_EL2_LRENPIE;
-	if (irqs_outside_lrs(als))
+	if (irqs_outside_lrs(als, vcpu))
 		cpuif->vgic_hcr |= ICH_HCR_EL2_UIE;
 
 	if (!als->nr_sgi)
@@ -60,7 +60,7 @@ void vgic_v3_configure_hcr(struct kvm_vcpu *vcpu,
 	 * can change behind our back without any warning...
 	 */
 	if (!cpus_have_final_cap(ARM64_HAS_ICH_HCR_EL2_TDIR) ||
-	    irqs_active_outside_lrs(als)		     ||
+	    irqs_active_outside_lrs(als, vcpu)		     ||
 	    atomic_read(&vcpu->kvm->arch.vgic.active_spis))
 		cpuif->vgic_hcr |= ICH_HCR_EL2_TDIR;
 }
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index 430aa98888fd..2fdcef3d28d1 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -957,7 +957,7 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
 
 	summarize_ap_list(vcpu, &als);
 
-	if (irqs_outside_lrs(&als))
+	if (irqs_outside_lrs(&als, vcpu))
 		vgic_sort_ap_list(vcpu);
 
 	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
@@ -967,12 +967,12 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
 			}
 		}
 
-		if (count == kvm_vgic_global_state.nr_lr)
+		if (count == kvm_vcpu_vgic_nr_lr(vcpu))
 			break;
 	}
 
 	/* Nuke remaining LRs */
-	for (int i = count ; i < kvm_vgic_global_state.nr_lr; i++)
+	for (int i = count ; i < kvm_vcpu_vgic_nr_lr(vcpu); i++)
 		vgic_clear_lr(vcpu, i);
 
 	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif)) {
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index 5f0fc96b4dc2..55a1142efc6f 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -7,6 +7,7 @@
 
 #include <linux/irqchip/arm-gic-common.h>
 #include <asm/kvm_mmu.h>
+#include <asm/kvm_rmi.h>
 
 #define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
 #define IMPLEMENTER_ARM		0x43b
@@ -242,14 +243,19 @@ struct ap_list_summary {
 	unsigned int	nr_sgi;		/* any SGI */
 };
 
-#define irqs_outside_lrs(s)						\
-	 (((s)->nr_pend + (s)->nr_act) > kvm_vgic_global_state.nr_lr)
+static inline int kvm_vcpu_vgic_nr_lr(struct kvm_vcpu *vcpu)
+{
+	return kvm_vgic_global_state.nr_lr;
+}
+
+#define irqs_outside_lrs(s, vcpu)					\
+	 (((s)->nr_pend + (s)->nr_act) > kvm_vcpu_vgic_nr_lr(vcpu))
 
-#define irqs_pending_outside_lrs(s)			\
-	((s)->nr_pend > kvm_vgic_global_state.nr_lr)
+#define irqs_pending_outside_lrs(s, vcpu)			\
+	((s)->nr_pend > kvm_vcpu_vgic_nr_lr(vcpu))
 
-#define irqs_active_outside_lrs(s)		\
-	((s)->nr_act &&	irqs_outside_lrs(s))
+#define irqs_active_outside_lrs(s, vcpu)		\
+	((s)->nr_act &&	irqs_outside_lrs(s, vcpu))
 
 int vgic_v3_parse_attr(struct kvm_device *dev, struct kvm_device_attr *attr,
 		       struct vgic_reg_attr *reg_attr);
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:10:51 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:10:51 +0000
Subject: [PATCH v12 14/46] arm64: RMI: Support for the VGIC in realms
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-15-steven.price@arm.com>

The RMM provides emulation of a VGIC to the realm guest but delegates
much of the handling to the host. Implement support in KVM for
saving/restoring state to/from the REC structure.

Signed-off-by: Steven Price <steven.price at arm.com>
---
Changes from v11:
 * Minor changes to align with the previous patches. Note that the VGIC
   handling will change with RMM v2.0.
Changes from v10:
 * Make sure we sync the VGIC v4 state, and only populate valid lrs from
   the list.
Changes from v9:
 * Copy gicv3_vmcr from the RMM at the same time as gicv3_hcr rather
   than having to handle that as a special case.
Changes from v8:
 * Propagate gicv3_hcr to from the RMM.
Changes from v5:
 * Handle RMM providing fewer GIC LRs than the hardware supports.
---
 arch/arm64/include/asm/kvm_rmi.h |  1 +
 arch/arm64/kvm/arm.c             | 11 +++++--
 arch/arm64/kvm/rmi.c             |  5 ++++
 arch/arm64/kvm/vgic/vgic-init.c  |  2 +-
 arch/arm64/kvm/vgic/vgic-v3.c    |  6 ++--
 arch/arm64/kvm/vgic/vgic.c       | 49 +++++++++++++++++++++++++++++---
 arch/arm64/kvm/vgic/vgic.h       |  2 ++
 7 files changed, 65 insertions(+), 11 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_rmi.h
index dbb4b97d5d42..6190d75cc615 100644
--- a/arch/arm64/include/asm/kvm_rmi.h
+++ b/arch/arm64/include/asm/kvm_rmi.h
@@ -87,6 +87,7 @@ struct realm_rec {
 
 void kvm_init_rmi(void);
 u32 kvm_realm_ipa_limit(void);
+u32 kvm_realm_vgic_nr_lr(void);
 
 int kvm_init_realm_vm(struct kvm *kvm);
 int kvm_activate_realm(struct kvm *kvm);
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 512d0ec9de60..66f23b8b3144 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -723,19 +723,24 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
 		kvm_call_hyp_nvhe(__pkvm_vcpu_put);
 	}
 
+	kvm_timer_vcpu_put(vcpu);
+	kvm_vgic_put(vcpu);
+
+	vcpu->cpu = -1;
+
+	if (vcpu_is_rec(vcpu))
+		return;
+
 	kvm_vcpu_put_debug(vcpu);
 	kvm_arch_vcpu_put_fp(vcpu);
 	if (has_vhe())
 		kvm_vcpu_put_vhe(vcpu);
-	kvm_timer_vcpu_put(vcpu);
-	kvm_vgic_put(vcpu);
 	kvm_vcpu_pmu_restore_host(vcpu);
 	if (vcpu_has_nv(vcpu))
 		kvm_vcpu_put_hw_mmu(vcpu);
 	kvm_arm_vmid_clear_active();
 
 	vcpu_clear_on_unsupported_cpu(vcpu);
-	vcpu->cpu = -1;
 }
 
 static void __kvm_arm_vcpu_power_off(struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
index 27ecd7d9f757..275b266c6614 100644
--- a/arch/arm64/kvm/rmi.c
+++ b/arch/arm64/kvm/rmi.c
@@ -77,6 +77,11 @@ u32 kvm_realm_ipa_limit(void)
 	return u64_get_bits(rmm_feat_reg0, RMI_FEATURE_REGISTER_0_S2SZ);
 }
 
+u32 kvm_realm_vgic_nr_lr(void)
+{
+	return u64_get_bits(rmm_feat_reg0, RMI_FEATURE_REGISTER_0_GICV3_NUM_LRS);
+}
+
 static int get_start_level(struct realm *realm)
 {
 	/*
diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index dc9f9db31026..bb1a876bf298 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -82,7 +82,7 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
 	 * the proper checks already.
 	 */
 	if (type == KVM_DEV_TYPE_ARM_VGIC_V2 &&
-		!kvm_vgic_global_state.can_emulate_gicv2)
+	    (!kvm_vgic_global_state.can_emulate_gicv2 || kvm_is_realm(kvm)))
 		return -ENODEV;
 
 	/*
diff --git a/arch/arm64/kvm/vgic/vgic-v3.c b/arch/arm64/kvm/vgic/vgic-v3.c
index c9ff4f90c975..f01dd30330e3 100644
--- a/arch/arm64/kvm/vgic/vgic-v3.c
+++ b/arch/arm64/kvm/vgic/vgic-v3.c
@@ -982,10 +982,10 @@ void vgic_v3_load(struct kvm_vcpu *vcpu)
 		return;
 	}
 
-	if (likely(!is_protected_kvm_enabled()))
+	if (likely(!is_protected_kvm_enabled()) && !vcpu_is_rec(vcpu))
 		kvm_call_hyp(__vgic_v3_restore_vmcr_aprs, cpu_if);
 
-	if (has_vhe())
+	if (has_vhe() && !vcpu_is_rec(vcpu))
 		__vgic_v3_activate_traps(cpu_if);
 
 	WARN_ON(vgic_v4_load(vcpu));
@@ -1004,6 +1004,6 @@ void vgic_v3_put(struct kvm_vcpu *vcpu)
 		kvm_call_hyp(__vgic_v3_save_aprs, cpu_if);
 	WARN_ON(vgic_v4_put(vcpu));
 
-	if (has_vhe())
+	if (has_vhe() && !vcpu_is_rec(vcpu))
 		__vgic_v3_deactivate_traps(cpu_if);
 }
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index 2fdcef3d28d1..b317b2a9815f 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -10,6 +10,7 @@
 #include <linux/list_sort.h>
 #include <linux/nospec.h>
 
+#include <asm/kvm_emulate.h>
 #include <asm/kvm_hyp.h>
 
 #include "vgic.h"
@@ -994,10 +995,26 @@ static inline bool can_access_vgic_from_kernel(void)
 	return !static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif) || has_vhe();
 }
 
+static inline void vgic_rmm_save_state(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
+	int i;
+
+	for (i = 0; i < kvm_vcpu_vgic_nr_lr(vcpu); i++) {
+		cpu_if->vgic_lr[i] = vcpu->arch.rec.run->exit.gicv3_lrs[i];
+		vcpu->arch.rec.run->enter.gicv3_lrs[i] = 0;
+	}
+
+	cpu_if->vgic_hcr = vcpu->arch.rec.run->exit.gicv3_hcr;
+	cpu_if->vgic_vmcr = vcpu->arch.rec.run->exit.gicv3_vmcr;
+}
+
 static inline void vgic_save_state(struct kvm_vcpu *vcpu)
 {
 	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		vgic_v2_save_state(vcpu);
+	else if (vcpu_is_rec(vcpu))
+		vgic_rmm_save_state(vcpu);
 	else
 		__vgic_v3_save_state(&vcpu->arch.vgic_cpu.vgic_v3);
 }
@@ -1032,10 +1049,30 @@ void kvm_vgic_process_async_update(struct kvm_vcpu *vcpu)
 	local_irq_restore(flags);
 }
 
+static inline void vgic_rmm_restore_state(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
+	int i;
+
+	for (i = 0; i < cpu_if->used_lrs; i++) {
+		vcpu->arch.rec.run->enter.gicv3_lrs[i] = cpu_if->vgic_lr[i];
+		/*
+		 * Also populate the rec.run->exit copies so that a late
+		 * decision to back out from entering the realm doesn't cause
+		 * the state to be lost
+		 */
+		vcpu->arch.rec.run->exit.gicv3_lrs[i] = cpu_if->vgic_lr[i];
+	}
+
+	vcpu->arch.rec.run->enter.gicv3_hcr = cpu_if->vgic_hcr & RMI_PERMITTED_GICV3_HCR_BITS;
+}
+
 static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
 {
 	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		vgic_v2_restore_state(vcpu);
+	else if (vcpu_is_rec(vcpu))
+		vgic_rmm_restore_state(vcpu);
 	else
 		__vgic_v3_restore_state(&vcpu->arch.vgic_cpu.vgic_v3);
 }
@@ -1088,8 +1125,10 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 
 void kvm_vgic_load(struct kvm_vcpu *vcpu)
 {
-	if (unlikely(!irqchip_in_kernel(vcpu->kvm) || !vgic_initialized(vcpu->kvm))) {
-		if (has_vhe() && static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
+	if (unlikely(!irqchip_in_kernel(vcpu->kvm) ||
+		     !vgic_initialized(vcpu->kvm))) {
+		if (has_vhe() && !vcpu_is_rec(vcpu) &&
+		    static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 			__vgic_v3_activate_traps(&vcpu->arch.vgic_cpu.vgic_v3);
 		return;
 	}
@@ -1102,8 +1141,10 @@ void kvm_vgic_load(struct kvm_vcpu *vcpu)
 
 void kvm_vgic_put(struct kvm_vcpu *vcpu)
 {
-	if (unlikely(!irqchip_in_kernel(vcpu->kvm) || !vgic_initialized(vcpu->kvm))) {
-		if (has_vhe() && static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
+	if (unlikely(!irqchip_in_kernel(vcpu->kvm) ||
+		     !vgic_initialized(vcpu->kvm))) {
+		if (has_vhe() && !vcpu_is_rec(vcpu) &&
+		    static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 			__vgic_v3_deactivate_traps(&vcpu->arch.vgic_cpu.vgic_v3);
 		return;
 	}
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index 55a1142efc6f..282a9701dea6 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -245,6 +245,8 @@ struct ap_list_summary {
 
 static inline int kvm_vcpu_vgic_nr_lr(struct kvm_vcpu *vcpu)
 {
+	if (unlikely(vcpu_is_rec(vcpu)))
+		return kvm_realm_vgic_nr_lr();
 	return kvm_vgic_global_state.nr_lr;
 }
 
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:10:52 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:10:52 +0000
Subject: [PATCH v12 15/46] KVM: arm64: Support timers in realm RECs
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-16-steven.price@arm.com>

The RMM keeps track of the timer while the realm REC is running, but on
exit to the normal world KVM is responsible for handling the timers.

A later patch adds the support for propagating the timer values from the
exit data structure and calling kvm_realm_timers_update().

Signed-off-by: Steven Price <steven.price at arm.com>
---
Changes since v11:
 * Drop the kvm_is_realm() check from timer_set_offset(). We already
   ensure that the offset is 0 when calling the function.
Changes since v10:
 * KVM_CAP_COUNTER_OFFSET is now already hidden by a previous patch.
Changes since v9:
 * No need to move the call to kvm_timer_unblocking() in
   kvm_timer_vcpu_load().
Changes since v7:
 * Hide KVM_CAP_COUNTER_OFFSET for realm guests.
---
 arch/arm64/kvm/arch_timer.c  | 37 ++++++++++++++++++++++++++++++++++--
 include/kvm/arm_arch_timer.h |  2 ++
 2 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c
index 99a07972068d..99308bde2a05 100644
--- a/arch/arm64/kvm/arch_timer.c
+++ b/arch/arm64/kvm/arch_timer.c
@@ -453,6 +453,21 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level,
 			    timer_ctx);
 }
 
+void kvm_realm_timers_update(struct kvm_vcpu *vcpu)
+{
+	struct arch_timer_cpu *arch_timer = &vcpu->arch.timer_cpu;
+	int i;
+
+	for (i = 0; i < NR_KVM_EL0_TIMERS; i++) {
+		struct arch_timer_context *timer = &arch_timer->timers[i];
+		bool status = timer_get_ctl(timer) & ARCH_TIMER_CTRL_IT_STAT;
+		bool level = kvm_timer_irq_can_fire(timer) && status;
+
+		if (level != timer->irq.level)
+			kvm_timer_update_irq(vcpu, level, timer);
+	}
+}
+
 /* Only called for a fully emulated timer */
 static void timer_emulate(struct arch_timer_context *ctx)
 {
@@ -1056,7 +1071,9 @@ static void timer_context_init(struct kvm_vcpu *vcpu, int timerid)
 
 	ctxt->timer_id = timerid;
 
-	if (timerid == TIMER_VTIMER)
+	if (kvm_is_realm(vcpu->kvm))
+		ctxt->offset.vm_offset = NULL;
+	else if (timerid == TIMER_VTIMER)
 		ctxt->offset.vm_offset = &kvm->arch.timer_data.voffset;
 	else
 		ctxt->offset.vm_offset = &kvm->arch.timer_data.poffset;
@@ -1078,13 +1095,19 @@ static void timer_context_init(struct kvm_vcpu *vcpu, int timerid)
 void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
 {
 	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
+	u64 cntvoff;
 
 	for (int i = 0; i < NR_KVM_TIMERS; i++)
 		timer_context_init(vcpu, i);
 
+	if (kvm_is_realm(vcpu->kvm))
+		cntvoff = 0;
+	else
+		cntvoff = kvm_phys_timer_read();
+
 	/* Synchronize offsets across timers of a VM if not already provided */
 	if (!test_bit(KVM_ARCH_FLAG_VM_COUNTER_OFFSET, &vcpu->kvm->arch.flags)) {
-		timer_set_offset(vcpu_vtimer(vcpu), kvm_phys_timer_read());
+		timer_set_offset(vcpu_vtimer(vcpu), cntvoff);
 		timer_set_offset(vcpu_ptimer(vcpu), 0);
 	}
 
@@ -1556,6 +1579,13 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
 		return -EINVAL;
 	}
 
+	/*
+	 * We don't use mapped IRQs for Realms because the RMI doesn't allow
+	 * us setting the LR.HW bit in the VGIC.
+	 */
+	if (vcpu_is_rec(vcpu))
+		return 0;
+
 	get_timer_map(vcpu, &map);
 
 	ret = kvm_vgic_map_phys_irq(vcpu,
@@ -1687,6 +1717,9 @@ int kvm_vm_ioctl_set_counter_offset(struct kvm *kvm,
 	if (offset->reserved)
 		return -EINVAL;
 
+	if (kvm_is_realm(kvm))
+		return -EINVAL;
+
 	mutex_lock(&kvm->lock);
 
 	if (!kvm_trylock_all_vcpus(kvm)) {
diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index 7310841f4512..bab0daafc6b1 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -111,6 +111,8 @@ int kvm_arm_timer_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);
 int kvm_arm_timer_get_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);
 int kvm_arm_timer_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);
 
+void kvm_realm_timers_update(struct kvm_vcpu *vcpu);
+
 u64 kvm_phys_timer_read(void);
 
 void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu);
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:10:53 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:10:53 +0000
Subject: [PATCH v12 16/46] arm64: RMI: Handle realm enter/exit
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-17-steven.price@arm.com>

Entering a realm is done using a SMC call to the RMM. On exit the
exit-codes need to be handled slightly differently to the normal KVM
path so define our own functions for realm enter/exit and hook them
in if the guest is a realm guest.

Signed-off-by: Steven Price <steven.price at arm.com>
Reviewed-by: Gavin Shan <gshan at redhat.com>
---
Changes since v8:
 * Introduce kvm_rec_pre_enter() called before entering an atomic
   section to handle operations that might require memory allocation
   (specifically completing a RIPAS change introduced in a later patch).
 * Updates to align with upstream changes to hpfar_el2 which now (ab)uses
   HPFAR_EL2_NS as a valid flag.
 * Fix exit reason when racing with PSCI shutdown to return
   KVM_EXIT_SHUTDOWN rather than KVM_EXIT_UNKNOWN.
Changes since v7:
 * A return of 0 from kvm_handle_sys_reg() doesn't mean the register has
   been read (although that can never happen in the current code). Tidy
   up the condition to handle any future refactoring.
Changes since v6:
 * Use vcpu_err() rather than pr_err/kvm_err when there is an associated
   vcpu to the error.
 * Return -EFAULT for KVM_EXIT_MEMORY_FAULT as per the documentation for
   this exit type.
 * Split code handling a RIPAS change triggered by the guest to the
   following patch.
Changes since v5:
 * For a RIPAS_CHANGE request from the guest perform the actual RIPAS
   change on next entry rather than immediately on the exit. This allows
   the VMM to 'reject' a RIPAS change by refusing to continue
   scheduling.
Changes since v4:
 * Rename handle_rme_exit() to handle_rec_exit()
 * Move the loop to copy registers into the REC enter structure from the
   to rec_exit_handlers callbacks to kvm_rec_enter(). This fixes a bug
   where the handler exits to user space and user space wants to modify
   the GPRS.
 * Some code rearrangement in rec_exit_ripas_change().
Changes since v2:
 * realm_set_ipa_state() now provides an output parameter for the
   top_iap that was changed. Use this to signal the VMM with the correct
   range that has been transitioned.
 * Adapt to previous patch changes.
---
 arch/arm64/include/asm/kvm_rmi.h |   4 +
 arch/arm64/kvm/Makefile          |   2 +-
 arch/arm64/kvm/arm.c             |  22 +++-
 arch/arm64/kvm/rmi-exit.c        | 178 +++++++++++++++++++++++++++++++
 arch/arm64/kvm/rmi.c             |  38 +++++++
 5 files changed, 239 insertions(+), 5 deletions(-)
 create mode 100644 arch/arm64/kvm/rmi-exit.c

diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_rmi.h
index 6190d75cc615..faf0af563210 100644
--- a/arch/arm64/include/asm/kvm_rmi.h
+++ b/arch/arm64/include/asm/kvm_rmi.h
@@ -95,6 +95,10 @@ void kvm_destroy_realm(struct kvm *kvm);
 void kvm_realm_destroy_rtts(struct kvm *kvm);
 void kvm_destroy_rec(struct kvm_vcpu *vcpu);
 
+int kvm_rec_enter(struct kvm_vcpu *vcpu);
+int kvm_rec_pre_enter(struct kvm_vcpu *vcpu);
+int handle_rec_exit(struct kvm_vcpu *vcpu, int rec_run_status);
+
 static inline bool kvm_realm_is_private_address(struct realm *realm,
 						unsigned long addr)
 {
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index e17c4077d8e7..4b103bcbe760 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -16,7 +16,7 @@ CFLAGS_handle_exit.o += -Wno-override-init
 kvm-y += arm.o mmu.o mmio.o psci.o hypercalls.o pvtime.o \
 	 inject_fault.o va_layout.o handle_exit.o config.o \
 	 guest.o debug.o reset.o sys_regs.o stacktrace.o \
-	 vgic-sys-reg-v3.o fpsimd.o pkvm.o rmi.o \
+	 vgic-sys-reg-v3.o fpsimd.o pkvm.o rmi.o rmi-exit.o \
 	 arch_timer.o trng.o vmid.o emulate-nested.o nested.o at.o \
 	 vgic/vgic.o vgic/vgic-init.o \
 	 vgic/vgic-irqfd.o vgic/vgic-v2.o \
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 66f23b8b3144..7927181887cf 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -1264,6 +1264,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 		if (ret > 0)
 			ret = check_vcpu_requests(vcpu);
 
+		if (ret > 0 && vcpu_is_rec(vcpu))
+			ret = kvm_rec_pre_enter(vcpu);
+
 		/*
 		 * Preparing the interrupts to be injected also
 		 * involves poking the GIC, which must be done in a
@@ -1311,7 +1314,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 		trace_kvm_entry(*vcpu_pc(vcpu));
 		guest_timing_enter_irqoff();
 
-		ret = kvm_arm_vcpu_enter_exit(vcpu);
+		if (vcpu_is_rec(vcpu))
+			ret = kvm_rec_enter(vcpu);
+		else
+			ret = kvm_arm_vcpu_enter_exit(vcpu);
 
 		vcpu->mode = OUTSIDE_GUEST_MODE;
 		vcpu->stat.exits++;
@@ -1369,8 +1375,13 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 
 		trace_kvm_exit(ret, kvm_vcpu_trap_get_class(vcpu), *vcpu_pc(vcpu));
 
-		/* Exit types that need handling before we can be preempted */
-		handle_exit_early(vcpu, ret);
+		if (!vcpu_is_rec(vcpu)) {
+			/*
+			 * Exit types that need handling before we can be
+			 * preempted
+			 */
+			handle_exit_early(vcpu, ret);
+		}
 
 		kvm_nested_sync_hwstate(vcpu);
 
@@ -1395,7 +1406,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 			ret = ARM_EXCEPTION_IL;
 		}
 
-		ret = handle_exit(vcpu, ret);
+		if (vcpu_is_rec(vcpu))
+			ret = handle_rec_exit(vcpu, ret);
+		else
+			ret = handle_exit(vcpu, ret);
 	}
 
 	/* Tell userspace about in-kernel device output levels */
diff --git a/arch/arm64/kvm/rmi-exit.c b/arch/arm64/kvm/rmi-exit.c
new file mode 100644
index 000000000000..f5701153dec0
--- /dev/null
+++ b/arch/arm64/kvm/rmi-exit.c
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023 ARM Ltd.
+ */
+
+#include <linux/kvm_host.h>
+#include <kvm/arm_hypercalls.h>
+#include <kvm/arm_psci.h>
+
+#include <asm/rmi_smc.h>
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_rmi.h>
+#include <asm/kvm_mmu.h>
+
+typedef int (*exit_handler_fn)(struct kvm_vcpu *vcpu);
+
+static int rec_exit_reason_notimpl(struct kvm_vcpu *vcpu)
+{
+	struct realm_rec *rec = &vcpu->arch.rec;
+
+	vcpu_err(vcpu, "Unhandled exit reason from realm (ESR: %#llx)\n",
+		 rec->run->exit.esr);
+	return -ENXIO;
+}
+
+static int rec_exit_sync_dabt(struct kvm_vcpu *vcpu)
+{
+	return kvm_handle_guest_abort(vcpu);
+}
+
+static int rec_exit_sync_iabt(struct kvm_vcpu *vcpu)
+{
+	struct realm_rec *rec = &vcpu->arch.rec;
+
+	vcpu_err(vcpu, "Unhandled instruction abort (ESR: %#llx).\n",
+		 rec->run->exit.esr);
+	return -ENXIO;
+}
+
+static int rec_exit_sys_reg(struct kvm_vcpu *vcpu)
+{
+	struct realm_rec *rec = &vcpu->arch.rec;
+	unsigned long esr = kvm_vcpu_get_esr(vcpu);
+	int rt = kvm_vcpu_sys_get_rt(vcpu);
+	bool is_write = !(esr & 1);
+	int ret;
+
+	if (is_write)
+		vcpu_set_reg(vcpu, rt, rec->run->exit.gprs[0]);
+
+	ret = kvm_handle_sys_reg(vcpu);
+	if (!is_write)
+		rec->run->enter.gprs[0] = vcpu_get_reg(vcpu, rt);
+
+	return ret;
+}
+
+static exit_handler_fn rec_exit_handlers[] = {
+	[0 ... ESR_ELx_EC_MAX]	= rec_exit_reason_notimpl,
+	[ESR_ELx_EC_SYS64]	= rec_exit_sys_reg,
+	[ESR_ELx_EC_DABT_LOW]	= rec_exit_sync_dabt,
+	[ESR_ELx_EC_IABT_LOW]	= rec_exit_sync_iabt
+};
+
+static int rec_exit_psci(struct kvm_vcpu *vcpu)
+{
+	struct realm_rec *rec = &vcpu->arch.rec;
+	int i;
+
+	for (i = 0; i < REC_RUN_GPRS; i++)
+		vcpu_set_reg(vcpu, i, rec->run->exit.gprs[i]);
+
+	return kvm_smccc_call_handler(vcpu);
+}
+
+static int rec_exit_ripas_change(struct kvm_vcpu *vcpu)
+{
+	struct kvm *kvm = vcpu->kvm;
+	struct realm *realm = &kvm->arch.realm;
+	struct realm_rec *rec = &vcpu->arch.rec;
+	unsigned long base = rec->run->exit.ripas_base;
+	unsigned long top = rec->run->exit.ripas_top;
+	unsigned long ripas = rec->run->exit.ripas_value;
+
+	if (!kvm_realm_is_private_address(realm, base) ||
+	    !kvm_realm_is_private_address(realm, top - 1)) {
+		vcpu_err(vcpu, "Invalid RIPAS_CHANGE for %#lx - %#lx, ripas: %#lx\n",
+			 base, top, ripas);
+		/* Set RMI_REJECT bit */
+		rec->run->enter.flags = REC_ENTER_FLAG_RIPAS_RESPONSE;
+		return -EINVAL;
+	}
+
+	/* Exit to VMM, the actual RIPAS change is done on next entry */
+	kvm_prepare_memory_fault_exit(vcpu, base, top - base, false, false,
+				      ripas == RMI_RAM);
+
+	/*
+	 * KVM_EXIT_MEMORY_FAULT requires an return code of -EFAULT, see the
+	 * API documentation
+	 */
+	return -EFAULT;
+}
+
+static void update_arch_timer_irq_lines(struct kvm_vcpu *vcpu)
+{
+	struct realm_rec *rec = &vcpu->arch.rec;
+
+	__vcpu_assign_sys_reg(vcpu, CNTV_CTL_EL0, rec->run->exit.cntv_ctl);
+	__vcpu_assign_sys_reg(vcpu, CNTV_CVAL_EL0, rec->run->exit.cntv_cval);
+	__vcpu_assign_sys_reg(vcpu, CNTP_CTL_EL0, rec->run->exit.cntp_ctl);
+	__vcpu_assign_sys_reg(vcpu, CNTP_CVAL_EL0, rec->run->exit.cntp_cval);
+
+	kvm_realm_timers_update(vcpu);
+}
+
+/*
+ * Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on
+ * proper exit to userspace.
+ */
+int handle_rec_exit(struct kvm_vcpu *vcpu, int rec_run_ret)
+{
+	struct realm_rec *rec = &vcpu->arch.rec;
+	u8 esr_ec = ESR_ELx_EC(rec->run->exit.esr);
+	unsigned long status, index;
+
+	status = RMI_RETURN_STATUS(rec_run_ret);
+	index = RMI_RETURN_INDEX(rec_run_ret);
+
+	/*
+	 * If a PSCI_SYSTEM_OFF request raced with a vcpu executing, we might
+	 * see the following status code and index indicating an attempt to run
+	 * a REC when the RD state is SYSTEM_OFF.  In this case, we just need to
+	 * return to user space which can deal with the system event or will try
+	 * to run the KVM VCPU again, at which point we will no longer attempt
+	 * to enter the Realm because we will have a sleep request pending on
+	 * the VCPU as a result of KVM's PSCI handling.
+	 */
+	if (status == RMI_ERROR_REALM && index == 1) {
+		vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN;
+		return 0;
+	}
+
+	if (rec_run_ret)
+		return -ENXIO;
+
+	vcpu->arch.fault.esr_el2 = rec->run->exit.esr;
+	vcpu->arch.fault.far_el2 = rec->run->exit.far;
+	/* HPFAR_EL2 is only valid for RMI_EXIT_SYNC */
+	vcpu->arch.fault.hpfar_el2 = 0;
+
+	update_arch_timer_irq_lines(vcpu);
+
+	/* Reset the emulation flags for the next run of the REC */
+	rec->run->enter.flags = 0;
+
+	switch (rec->run->exit.exit_reason) {
+	case RMI_EXIT_SYNC:
+		/*
+		 * HPFAR_EL2_NS is hijacked to indicate a valid HPFAR value,
+		 * see __get_fault_info()
+		 */
+		vcpu->arch.fault.hpfar_el2 = rec->run->exit.hpfar | HPFAR_EL2_NS;
+		return rec_exit_handlers[esr_ec](vcpu);
+	case RMI_EXIT_IRQ:
+	case RMI_EXIT_FIQ:
+		return 1;
+	case RMI_EXIT_PSCI:
+		return rec_exit_psci(vcpu);
+	case RMI_EXIT_RIPAS_CHANGE:
+		return rec_exit_ripas_change(vcpu);
+	}
+
+	kvm_pr_unimpl("Unsupported exit reason: %u\n",
+		      rec->run->exit.exit_reason);
+	vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+	return 0;
+}
diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
index 275b266c6614..215eb4f4fc47 100644
--- a/arch/arm64/kvm/rmi.c
+++ b/arch/arm64/kvm/rmi.c
@@ -234,6 +234,44 @@ static int realm_ensure_created(struct kvm *kvm)
 	return -ENXIO;
 }
 
+/*
+ * kvm_rec_pre_enter - Complete operations before entering a REC
+ *
+ * Some operations require work to be completed before entering a realm. That
+ * work may require memory allocation so cannot be done in the kvm_rec_enter()
+ * call.
+ *
+ * Return: 1 if we should enter the guest
+ *	   0 if we should exit to userspace
+ *	   < 0 if we should exit to userspace, where the return value indicates
+ *	   an error
+ */
+int kvm_rec_pre_enter(struct kvm_vcpu *vcpu)
+{
+	struct realm_rec *rec = &vcpu->arch.rec;
+
+	if (kvm_realm_state(vcpu->kvm) != REALM_STATE_ACTIVE)
+		return -EINVAL;
+
+	switch (rec->run->exit.exit_reason) {
+	case RMI_EXIT_HOST_CALL:
+	case RMI_EXIT_PSCI:
+		for (int i = 0; i < REC_RUN_GPRS; i++)
+			rec->run->enter.gprs[i] = vcpu_get_reg(vcpu, i);
+		break;
+	}
+
+	return 1;
+}
+
+int kvm_rec_enter(struct kvm_vcpu *vcpu)
+{
+	struct realm_rec *rec = &vcpu->arch.rec;
+
+	return rmi_rec_enter(virt_to_phys(rec->rec_page),
+			     virt_to_phys(rec->run));
+}
+
 static void free_rec_aux(struct page **aux_pages,
 			 unsigned int num_aux)
 {
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:10:54 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:10:54 +0000
Subject: [PATCH v12 17/46] arm64: RMI: Handle RMI_EXIT_RIPAS_CHANGE
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-18-steven.price@arm.com>

The guest can request that a region of it's protected address space is
switched between RIPAS_RAM and RIPAS_EMPTY (and back) using
RSI_IPA_STATE_SET. This causes a guest exit with the
RMI_EXIT_RIPAS_CHANGE code. We treat this as a request to convert a
protected region to unprotected (or back), exiting to the VMM to make
the necessary changes to the guest_memfd and memslot mappings. On the
next entry the RIPAS changes are committed by making RMI_RTT_SET_RIPAS
calls.

The VMM may wish to reject the RIPAS change requested by the guest. For
now it can only do with by no longer scheduling the VCPU as we don't
currently have a usecase for returning that rejection to the guest, but
by postponing the RMI_RTT_SET_RIPAS changes to entry we leave the door
open for adding a new ioctl in the future for this purpose.

There's a FIXME for the case where the RMM rejects a RIPAS change when
(a portion of) the region. The current RMM API makes this difficult to
handle efficiently, but it should be fixed in a later version of the
spec.

Signed-off-by: Steven Price <steven.price at arm.com>
---
Changes since v11:
 * Combine the "Allow VMM to set RIPAS" patch into this one to avoid
   adding functions before they are used.
 * Drop the CAP for setting RIPAS and adapt to changes from previous
   patches.
Changes since v10:
 * Add comment explaining the assignment of rec->run->exit.ripas_base in
   kvm_complete_ripas_change().
Changes since v8:
 * Make use of ripas_change() from a previous patch to implement
   realm_set_ipa_state().
 * Update exit.ripas_base after a RIPAS change so that, if instead of
   entering the guest we exit to user space, we don't attempt to repeat
   the RIPAS change (triggering an error from the RMM).
Changes since v7:
 * Rework the loop in realm_set_ipa_state() to make it clear when the
   'next' output value of rmi_rtt_set_ripas() is used.
New patch for v7: The code was previously split awkwardly between two
other patches.
---
 arch/arm64/include/asm/kvm_rmi.h |   6 +
 arch/arm64/kvm/mmu.c             |   8 +-
 arch/arm64/kvm/rmi.c             | 459 +++++++++++++++++++++++++++++++
 3 files changed, 470 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_rmi.h
index faf0af563210..8a862fc1a99d 100644
--- a/arch/arm64/include/asm/kvm_rmi.h
+++ b/arch/arm64/include/asm/kvm_rmi.h
@@ -99,6 +99,12 @@ int kvm_rec_enter(struct kvm_vcpu *vcpu);
 int kvm_rec_pre_enter(struct kvm_vcpu *vcpu);
 int handle_rec_exit(struct kvm_vcpu *vcpu, int rec_run_status);
 
+void kvm_realm_unmap_range(struct kvm *kvm,
+			   unsigned long ipa,
+			   unsigned long size,
+			   bool unmap_private,
+			   bool may_block);
+
 static inline bool kvm_realm_is_private_address(struct realm *realm,
 						unsigned long addr)
 {
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index 68e6cefe1135..cac3d7b73b3d 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -319,6 +319,7 @@ static void invalidate_icache_guest_page(void *va, size_t size)
  * @start: The intermediate physical base address of the range to unmap
  * @size:  The size of the area to unmap
  * @may_block: Whether or not we are permitted to block
+ * @only_shared: If true then protected mappings should not be unmapped
  *
  * Clear a range of stage-2 mappings, lowering the various ref-counts.  Must
  * be called while holding mmu_lock (unless for freeing the stage2 pgd before
@@ -326,7 +327,7 @@ static void invalidate_icache_guest_page(void *va, size_t size)
  * with things behind our backs.
  */
 static void __unmap_stage2_range(struct kvm_s2_mmu *mmu, phys_addr_t start, u64 size,
-				 bool may_block)
+				 bool may_block, bool only_shared)
 {
 	struct kvm *kvm = kvm_s2_mmu_to_kvm(mmu);
 	phys_addr_t end = start + size;
@@ -340,7 +341,7 @@ static void __unmap_stage2_range(struct kvm_s2_mmu *mmu, phys_addr_t start, u64
 void kvm_stage2_unmap_range(struct kvm_s2_mmu *mmu, phys_addr_t start,
 			    u64 size, bool may_block)
 {
-	__unmap_stage2_range(mmu, start, size, may_block);
+	__unmap_stage2_range(mmu, start, size, may_block, false);
 }
 
 void kvm_stage2_flush_range(struct kvm_s2_mmu *mmu, phys_addr_t addr, phys_addr_t end)
@@ -2230,7 +2231,8 @@ bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range)
 
 	__unmap_stage2_range(&kvm->arch.mmu, range->start << PAGE_SHIFT,
 			     (range->end - range->start) << PAGE_SHIFT,
-			     range->may_block);
+			     range->may_block,
+			     !(range->attr_filter & KVM_FILTER_PRIVATE));
 
 	kvm_nested_s2_unmap(kvm, range->may_block);
 	return false;
diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
index 215eb4f4fc47..fe15b400091c 100644
--- a/arch/arm64/kvm/rmi.c
+++ b/arch/arm64/kvm/rmi.c
@@ -91,6 +91,59 @@ static int get_start_level(struct realm *realm)
 	return 4 - ((realm->ia_bits - 8) / (RMM_PAGE_SHIFT - 3));
 }
 
+static int find_map_level(struct realm *realm,
+			  unsigned long start,
+			  unsigned long end)
+{
+	int level = RMM_RTT_MAX_LEVEL;
+
+	while (level > get_start_level(realm)) {
+		unsigned long map_size = rmi_rtt_level_mapsize(level - 1);
+
+		if (!IS_ALIGNED(start, map_size) ||
+		    (start + map_size) > end)
+			break;
+
+		level--;
+	}
+
+	return level;
+}
+
+static phys_addr_t alloc_delegated_granule(struct kvm_mmu_memory_cache *mc)
+{
+	phys_addr_t phys;
+	void *virt;
+
+	if (mc) {
+		virt = kvm_mmu_memory_cache_alloc(mc);
+	} else {
+		virt = (void *)__get_free_page(GFP_ATOMIC | __GFP_ZERO |
+					       __GFP_ACCOUNT);
+	}
+
+	if (!virt)
+		return PHYS_ADDR_MAX;
+
+	phys = virt_to_phys(virt);
+	if (rmi_granule_delegate(phys)) {
+		free_page((unsigned long)virt);
+		return PHYS_ADDR_MAX;
+	}
+
+	return phys;
+}
+
+static phys_addr_t alloc_rtt(struct kvm_mmu_memory_cache *mc)
+{
+	phys_addr_t phys = alloc_delegated_granule(mc);
+
+	if (phys != PHYS_ADDR_MAX)
+		kvm_account_pgtable_pages(phys_to_virt(phys), 1);
+
+	return phys;
+}
+
 static int free_delegated_granule(phys_addr_t phys)
 {
 	if (WARN_ON(rmi_granule_undelegate(phys))) {
@@ -111,6 +164,32 @@ static void free_rtt(phys_addr_t phys)
 	kvm_account_pgtable_pages(phys_to_virt(phys), -1);
 }
 
+static int realm_rtt_create(struct realm *realm,
+			    unsigned long addr,
+			    int level,
+			    phys_addr_t phys)
+{
+	addr = ALIGN_DOWN(addr, rmi_rtt_level_mapsize(level - 1));
+	return rmi_rtt_create(virt_to_phys(realm->rd), phys, addr, level);
+}
+
+static int realm_rtt_fold(struct realm *realm,
+			  unsigned long addr,
+			  int level,
+			  phys_addr_t *rtt_granule)
+{
+	unsigned long out_rtt;
+	int ret;
+
+	addr = ALIGN_DOWN(addr, rmi_rtt_level_mapsize(level - 1));
+	ret = rmi_rtt_fold(virt_to_phys(realm->rd), addr, level, &out_rtt);
+
+	if (rtt_granule)
+		*rtt_granule = out_rtt;
+
+	return ret;
+}
+
 static int realm_rtt_destroy(struct realm *realm, unsigned long addr,
 			     int level, phys_addr_t *rtt_granule,
 			     unsigned long *next_addr)
@@ -126,6 +205,38 @@ static int realm_rtt_destroy(struct realm *realm, unsigned long addr,
 	return ret;
 }
 
+static int realm_create_rtt_levels(struct realm *realm,
+				   unsigned long ipa,
+				   int level,
+				   int max_level,
+				   struct kvm_mmu_memory_cache *mc)
+{
+	while (level++ < max_level) {
+		phys_addr_t rtt = alloc_rtt(mc);
+		int ret;
+
+		if (rtt == PHYS_ADDR_MAX)
+			return -ENOMEM;
+
+		ret = realm_rtt_create(realm, ipa, level, rtt);
+		if (RMI_RETURN_STATUS(ret) == RMI_ERROR_RTT &&
+		    RMI_RETURN_INDEX(ret) == level - 1) {
+			/* The RTT already exists, continue */
+			free_rtt(rtt);
+			continue;
+		}
+
+		if (ret) {
+			WARN(1, "Failed to create RTT at level %d: %d\n",
+			     level, ret);
+			free_rtt(rtt);
+			return -ENXIO;
+		}
+	}
+
+	return 0;
+}
+
 static int realm_tear_down_rtt_level(struct realm *realm, int level,
 				     unsigned long start, unsigned long end)
 {
@@ -220,6 +331,62 @@ static int realm_tear_down_rtt_range(struct realm *realm,
 					 start, end);
 }
 
+/*
+ * Returns 0 on successful fold, a negative value on error, a positive value if
+ * we were not able to fold all tables at this level.
+ */
+static int realm_fold_rtt_level(struct realm *realm, int level,
+				unsigned long start, unsigned long end)
+{
+	int not_folded = 0;
+	ssize_t map_size;
+	unsigned long addr, next_addr;
+
+	if (WARN_ON(level > RMM_RTT_MAX_LEVEL))
+		return -EINVAL;
+
+	map_size = rmi_rtt_level_mapsize(level - 1);
+
+	for (addr = start; addr < end; addr = next_addr) {
+		phys_addr_t rtt_granule;
+		int ret;
+		unsigned long align_addr = ALIGN(addr, map_size);
+
+		next_addr = ALIGN(addr + 1, map_size);
+
+		ret = realm_rtt_fold(realm, align_addr, level, &rtt_granule);
+
+		switch (RMI_RETURN_STATUS(ret)) {
+		case RMI_SUCCESS:
+			free_rtt(rtt_granule);
+			break;
+		case RMI_ERROR_RTT:
+			if (level == RMM_RTT_MAX_LEVEL ||
+			    RMI_RETURN_INDEX(ret) < level) {
+				not_folded++;
+				break;
+			}
+			/* Recurse a level deeper */
+			ret = realm_fold_rtt_level(realm,
+						   level + 1,
+						   addr,
+						   next_addr);
+			if (ret < 0) {
+				return ret;
+			} else if (ret == 0) {
+				/* Try again at this level */
+				next_addr = addr;
+			}
+			break;
+		default:
+			WARN_ON(1);
+			return -ENXIO;
+		}
+	}
+
+	return not_folded;
+}
+
 void kvm_realm_destroy_rtts(struct kvm *kvm)
 {
 	struct realm *realm = &kvm->arch.realm;
@@ -228,12 +395,301 @@ void kvm_realm_destroy_rtts(struct kvm *kvm)
 	WARN_ON(realm_tear_down_rtt_range(realm, 0, (1UL << ia_bits)));
 }
 
+static int realm_destroy_private_granule(struct realm *realm,
+					 unsigned long ipa,
+					 unsigned long *next_addr)
+{
+	unsigned long rd = virt_to_phys(realm->rd);
+	unsigned long phy_addr;
+	phys_addr_t rtt;
+	int ret;
+
+retry:
+	ret = rmi_data_destroy(rd, ipa, &phy_addr, next_addr);
+	if (RMI_RETURN_STATUS(ret) == RMI_ERROR_RTT) {
+		if (*next_addr > ipa)
+			return 0; /* UNASSIGNED */
+		rtt = alloc_rtt(NULL);
+		if (WARN_ON(rtt == PHYS_ADDR_MAX))
+			return -ENOMEM;
+		/*
+		 * ASSIGNED - ipa is mapped as a block, so split. The index
+		 * from the return code should be 2 otherwise it appears
+		 * there's a huge page bigger than KVM currently supports
+		 */
+		WARN_ON(RMI_RETURN_INDEX(ret) != 2);
+		ret = realm_rtt_create(realm, ipa, 3, rtt);
+		if (WARN_ON(ret)) {
+			free_rtt(rtt);
+			return -ENXIO;
+		}
+		goto retry;
+	} else if (WARN_ON(ret)) {
+		return -ENXIO;
+	}
+
+	ret = rmi_granule_undelegate(phy_addr);
+	if (WARN_ON(ret))
+		return -ENXIO;
+
+	return 0;
+}
+
+static void realm_unmap_shared_range(struct kvm *kvm,
+				     int level,
+				     unsigned long start,
+				     unsigned long end,
+				     bool may_block)
+{
+	struct realm *realm = &kvm->arch.realm;
+	unsigned long rd = virt_to_phys(realm->rd);
+	ssize_t map_size = rmi_rtt_level_mapsize(level);
+	unsigned long next_addr, addr;
+	unsigned long shared_bit = BIT(realm->ia_bits - 1);
+
+	if (WARN_ON(level > RMM_RTT_MAX_LEVEL))
+		return;
+
+	start |= shared_bit;
+	end |= shared_bit;
+
+	for (addr = start; addr < end; addr = next_addr) {
+		unsigned long align_addr = ALIGN(addr, map_size);
+		int ret;
+
+		next_addr = ALIGN(addr + 1, map_size);
+
+		if (align_addr != addr || next_addr > end) {
+			/* Need to recurse deeper */
+			if (addr < align_addr)
+				next_addr = align_addr;
+			realm_unmap_shared_range(kvm, level + 1, addr,
+						 min(next_addr, end),
+						 may_block);
+			continue;
+		}
+
+		ret = rmi_rtt_unmap_unprotected(rd, addr, level, &next_addr);
+		switch (RMI_RETURN_STATUS(ret)) {
+		case RMI_SUCCESS:
+			break;
+		case RMI_ERROR_RTT:
+			if (next_addr == addr) {
+				/*
+				 * There's a mapping here, but it's not a block
+				 * mapping, so reset next_addr to the next block
+				 * boundary and recurse to clear out the pages
+				 * one level deeper.
+				 */
+				next_addr = ALIGN(addr + 1, map_size);
+				realm_unmap_shared_range(kvm, level + 1, addr,
+							 next_addr,
+							 may_block);
+			}
+			break;
+		default:
+			WARN_ON(1);
+			return;
+		}
+
+		if (may_block)
+			cond_resched_rwlock_write(&kvm->mmu_lock);
+	}
+
+	realm_fold_rtt_level(realm, get_start_level(realm) + 1,
+			     start, end);
+}
+
+static int realm_unmap_private_page(struct realm *realm,
+				    unsigned long ipa,
+				    unsigned long *next_addr)
+{
+	unsigned long end = ALIGN(ipa + 1, PAGE_SIZE);
+	unsigned long addr;
+	int ret;
+
+	for (addr = ipa; addr < end; addr = *next_addr) {
+		ret = realm_destroy_private_granule(realm, addr, next_addr);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static void realm_unmap_private_range(struct kvm *kvm,
+				      unsigned long start,
+				      unsigned long end,
+				      bool may_block)
+{
+	struct realm *realm = &kvm->arch.realm;
+	unsigned long next_addr, addr;
+	int ret;
+
+	for (addr = start; addr < end; addr = next_addr) {
+		ret = realm_unmap_private_page(realm, addr, &next_addr);
+
+		if (ret)
+			break;
+
+		if (may_block)
+			cond_resched_rwlock_write(&kvm->mmu_lock);
+	}
+
+	realm_fold_rtt_level(realm, get_start_level(realm) + 1,
+			     start, end);
+}
+
+void kvm_realm_unmap_range(struct kvm *kvm, unsigned long start,
+			   unsigned long size, bool unmap_private,
+			   bool may_block)
+{
+	unsigned long end = start + size;
+	struct realm *realm = &kvm->arch.realm;
+
+	end = min(BIT(realm->ia_bits - 1), end);
+
+	if (!kvm_realm_is_created(kvm))
+		return;
+
+	realm_unmap_shared_range(kvm, find_map_level(realm, start, end),
+				 start, end, may_block);
+	if (unmap_private)
+		realm_unmap_private_range(kvm, start, end, may_block);
+}
+
+enum ripas_action {
+	RIPAS_INIT,
+	RIPAS_SET,
+};
+
+static int ripas_change(struct kvm *kvm,
+			struct kvm_vcpu *vcpu,
+			unsigned long ipa,
+			unsigned long end,
+			enum ripas_action action,
+			unsigned long *top_ipa)
+{
+	struct realm *realm = &kvm->arch.realm;
+	phys_addr_t rd_phys = virt_to_phys(realm->rd);
+	phys_addr_t rec_phys;
+	struct kvm_mmu_memory_cache *memcache = NULL;
+	int ret = 0;
+
+	if (vcpu) {
+		rec_phys = virt_to_phys(vcpu->arch.rec.rec_page);
+		memcache = &vcpu->arch.mmu_page_cache;
+
+		WARN_ON(action != RIPAS_SET);
+	} else {
+		WARN_ON(action != RIPAS_INIT);
+	}
+
+	while (ipa < end) {
+		unsigned long next = ~0;
+
+		switch (action) {
+		case RIPAS_INIT:
+			ret = rmi_rtt_init_ripas(rd_phys, ipa, end, &next);
+			break;
+		case RIPAS_SET:
+			ret = rmi_rtt_set_ripas(rd_phys, rec_phys, ipa, end,
+						&next);
+			break;
+		}
+
+		switch (RMI_RETURN_STATUS(ret)) {
+		case RMI_SUCCESS:
+			ipa = next;
+			break;
+		case RMI_ERROR_RTT: {
+			int err_level = RMI_RETURN_INDEX(ret);
+			int level = find_map_level(realm, ipa, end);
+
+			if (err_level >= level) {
+				/* FIXME: Ugly hack to skip regions which are
+				 * already RIPAS_RAM
+				 */
+				ipa += PAGE_SIZE;
+				break;
+				return -EINVAL;
+			}
+
+			ret = realm_create_rtt_levels(realm, ipa, err_level,
+						      level, memcache);
+			if (ret)
+				return ret;
+			/* Retry with the RTT levels in place */
+			break;
+		}
+		default:
+			WARN_ON(1);
+			return -ENXIO;
+		}
+	}
+
+	if (top_ipa)
+		*top_ipa = ipa;
+
+	return 0;
+}
+
+static int realm_set_ipa_state(struct kvm_vcpu *vcpu,
+			       unsigned long start,
+			       unsigned long end,
+			       unsigned long ripas,
+			       unsigned long *top_ipa)
+{
+	struct kvm *kvm = vcpu->kvm;
+	int ret = ripas_change(kvm, vcpu, start, end, RIPAS_SET, top_ipa);
+
+	if (ripas == RMI_EMPTY && *top_ipa != start)
+		realm_unmap_private_range(kvm, start, *top_ipa, false);
+
+	return ret;
+}
+
 static int realm_ensure_created(struct kvm *kvm)
 {
 	/* Provided in later patch */
 	return -ENXIO;
 }
 
+static void kvm_complete_ripas_change(struct kvm_vcpu *vcpu)
+{
+	struct kvm *kvm = vcpu->kvm;
+	struct realm_rec *rec = &vcpu->arch.rec;
+	unsigned long base = rec->run->exit.ripas_base;
+	unsigned long top = rec->run->exit.ripas_top;
+	unsigned long ripas = rec->run->exit.ripas_value;
+	unsigned long top_ipa;
+	int ret;
+
+	do {
+		kvm_mmu_topup_memory_cache(&vcpu->arch.mmu_page_cache,
+					   kvm_mmu_cache_min_pages(vcpu->arch.hw_mmu));
+		write_lock(&kvm->mmu_lock);
+		ret = realm_set_ipa_state(vcpu, base, top, ripas, &top_ipa);
+		write_unlock(&kvm->mmu_lock);
+
+		if (WARN_RATELIMIT(ret && ret != -ENOMEM,
+				   "Unable to satisfy RIPAS_CHANGE for %#lx - %#lx, ripas: %#lx\n",
+				   base, top, ripas))
+			break;
+
+		base = top_ipa;
+	} while (base < top);
+
+	/*
+	 * If this function is called again before the REC_ENTER call then
+	 * avoid calling realm_set_ipa_state() again by changing to the value
+	 * of ripas_base for the part that has already been covered. The RMM
+	 * ignores the contains of the rec_exit structure so this doesn't
+	 * affect the RMM.
+	 */
+	rec->run->exit.ripas_base = base;
+}
+
 /*
  * kvm_rec_pre_enter - Complete operations before entering a REC
  *
@@ -259,6 +715,9 @@ int kvm_rec_pre_enter(struct kvm_vcpu *vcpu)
 		for (int i = 0; i < REC_RUN_GPRS; i++)
 			rec->run->enter.gprs[i] = vcpu_get_reg(vcpu, i);
 		break;
+	case RMI_EXIT_RIPAS_CHANGE:
+		kvm_complete_ripas_change(vcpu);
+		break;
 	}
 
 	return 1;
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:10:55 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:10:55 +0000
Subject: [PATCH v12 18/46] KVM: arm64: Handle realm MMIO emulation
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-19-steven.price@arm.com>

MMIO emulation for a realm cannot be done directly with the VM's
registers as they are protected from the host. However, for emulatable
data aborts, the RMM uses GPRS[0] to provide the read/written value.
We can transfer this from/to the equivalent VCPU's register entry and
then depend on the generic MMIO handling code in KVM.

For a MMIO read, the value is placed in the shared RecExit structure
during kvm_handle_mmio_return() rather than in the VCPU's register
entry.

Signed-off-by: Steven Price <steven.price at arm.com>
Reviewed-by: Gavin Shan <gshan at redhat.com>
Reviewed-by: Suzuki K Poulose <suzuki.poulose at arm.com>
---
Changes since v7:
 * New comment for rec_exit_sync_dabt() explaining the call to
   vcpu_set_reg().
Changes since v5:
 * Inject SEA to the guest is an emulatable MMIO access triggers a data
   abort.
 * kvm_handle_mmio_return() - disable kvm_incr_pc() for a REC (as the PC
   isn't under the host's control) and move the REC_ENTER_EMULATED_MMIO
   flag setting to this location (as that tells the RMM to skip the
   instruction).
---
 arch/arm64/kvm/inject_fault.c |  4 +++-
 arch/arm64/kvm/mmio.c         | 16 ++++++++++++----
 arch/arm64/kvm/rmi-exit.c     | 14 ++++++++++++++
 3 files changed, 29 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
index dfcd66c65517..5e00f7a69bcc 100644
--- a/arch/arm64/kvm/inject_fault.c
+++ b/arch/arm64/kvm/inject_fault.c
@@ -224,7 +224,9 @@ static void inject_abt32(struct kvm_vcpu *vcpu, bool is_pabt, u32 addr)
 
 static void __kvm_inject_sea(struct kvm_vcpu *vcpu, bool iabt, u64 addr)
 {
-	if (vcpu_el1_is_32bit(vcpu))
+	if (unlikely(vcpu_is_rec(vcpu)))
+		vcpu->arch.rec.run->enter.flags |= REC_ENTER_FLAG_INJECT_SEA;
+	else if (vcpu_el1_is_32bit(vcpu))
 		inject_abt32(vcpu, iabt, addr);
 	else
 		inject_abt64(vcpu, iabt, addr);
diff --git a/arch/arm64/kvm/mmio.c b/arch/arm64/kvm/mmio.c
index 54f9358c9e0e..d7ad291b5357 100644
--- a/arch/arm64/kvm/mmio.c
+++ b/arch/arm64/kvm/mmio.c
@@ -6,6 +6,7 @@
 
 #include <linux/kvm_host.h>
 #include <asm/kvm_emulate.h>
+#include <asm/rmi_smc.h>
 #include <trace/events/kvm.h>
 
 #include "trace.h"
@@ -138,14 +139,21 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu)
 		trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr,
 			       &data);
 		data = vcpu_data_host_to_guest(vcpu, data, len);
-		vcpu_set_reg(vcpu, kvm_vcpu_dabt_get_rd(vcpu), data);
+
+		if (vcpu_is_rec(vcpu))
+			vcpu->arch.rec.run->enter.gprs[0] = data;
+		else
+			vcpu_set_reg(vcpu, kvm_vcpu_dabt_get_rd(vcpu), data);
 	}
 
 	/*
 	 * The MMIO instruction is emulated and should not be re-executed
 	 * in the guest.
 	 */
-	kvm_incr_pc(vcpu);
+	if (vcpu_is_rec(vcpu))
+		vcpu->arch.rec.run->enter.flags |= REC_ENTER_FLAG_EMULATED_MMIO;
+	else
+		kvm_incr_pc(vcpu);
 
 	return 1;
 }
@@ -164,14 +172,14 @@ int io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
 	 * No valid syndrome? Ask userspace for help if it has
 	 * volunteered to do so, and bail out otherwise.
 	 *
-	 * In the protected VM case, there isn't much userspace can do
+	 * In the protected/realm VM case, there isn't much userspace can do
 	 * though, so directly deliver an exception to the guest.
 	 */
 	if (!kvm_vcpu_dabt_isvalid(vcpu)) {
 		trace_kvm_mmio_nisv(*vcpu_pc(vcpu), kvm_vcpu_get_esr(vcpu),
 				    kvm_vcpu_get_hfar(vcpu), fault_ipa);
 
-		if (vcpu_is_protected(vcpu))
+		if (vcpu_is_protected(vcpu) || vcpu_is_rec(vcpu))
 			return kvm_inject_sea_dabt(vcpu, kvm_vcpu_get_hfar(vcpu));
 
 		if (test_bit(KVM_ARCH_FLAG_RETURN_NISV_IO_ABORT_TO_USER,
diff --git a/arch/arm64/kvm/rmi-exit.c b/arch/arm64/kvm/rmi-exit.c
index f5701153dec0..b4843f094615 100644
--- a/arch/arm64/kvm/rmi-exit.c
+++ b/arch/arm64/kvm/rmi-exit.c
@@ -25,6 +25,20 @@ static int rec_exit_reason_notimpl(struct kvm_vcpu *vcpu)
 
 static int rec_exit_sync_dabt(struct kvm_vcpu *vcpu)
 {
+	struct realm_rec *rec = &vcpu->arch.rec;
+
+	/*
+	 * In the case of a write, copy over gprs[0] to the target GPR,
+	 * preparing to handle MMIO write fault. The content to be written has
+	 * been saved to gprs[0] by the RMM (even if another register was used
+	 * by the guest). In the case of normal memory access this is redundant
+	 * (the guest will replay the instruction), but the overhead is
+	 * minimal.
+	 */
+	if (kvm_vcpu_dabt_iswrite(vcpu) && kvm_vcpu_dabt_isvalid(vcpu))
+		vcpu_set_reg(vcpu, kvm_vcpu_dabt_get_rd(vcpu),
+			     rec->run->exit.gprs[0]);
+
 	return kvm_handle_guest_abort(vcpu);
 }
 
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:10:56 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:10:56 +0000
Subject: [PATCH v12 19/46] KVM: arm64: Expose support for private memory
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-20-steven.price@arm.com>

Select KVM_GENERIC_MEMORY_ATTRIBUTES and provide the necessary support
functions.

Signed-off-by: Steven Price <steven.price at arm.com>
---
Changes since v10:
 * KVM_GENERIC_PRIVATE_MEM replacd with KVM_GENERIC_MEMORY_ATTRIBUTES.
Changes since v9:
 * Drop the #ifdef CONFIG_KVM_PRIVATE_MEM guard from the definition of
   kvm_arch_has_private_mem()
Changes since v2:
 * Switch kvm_arch_has_private_mem() to a macro to avoid overhead of a
   function call.
 * Guard definitions of kvm_arch_{pre,post}_set_memory_attributes() with
   #ifdef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES.
 * Early out in kvm_arch_post_set_memory_attributes() if the WARN_ON
   should trigger.
---
 arch/arm64/include/asm/kvm_host.h |  2 ++
 arch/arm64/kvm/Kconfig            |  1 +
 arch/arm64/kvm/mmu.c              | 24 ++++++++++++++++++++++++
 3 files changed, 27 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 5a24227088c1..7590d86c78a5 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -1462,6 +1462,8 @@ struct kvm *kvm_arch_alloc_vm(void);
 
 #define vcpu_is_protected(vcpu)		kvm_vm_is_protected((vcpu)->kvm)
 
+#define kvm_arch_has_private_mem(kvm) ((kvm)->arch.is_realm)
+
 int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int feature);
 bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu);
 
diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index 4f803fd1c99a..1cac6dfc0972 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -38,6 +38,7 @@ menuconfig KVM
 	select SCHED_INFO
 	select GUEST_PERF_EVENTS if PERF_EVENTS
 	select KVM_GUEST_MEMFD
+	select KVM_GENERIC_MEMORY_ATTRIBUTES
 	help
 	  Support hosting virtualized guest machines.
 
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index cac3d7b73b3d..f2ac01c1de04 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -2503,6 +2503,30 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
 	return ret;
 }
 
+#ifdef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES
+bool kvm_arch_pre_set_memory_attributes(struct kvm *kvm,
+					struct kvm_gfn_range *range)
+{
+	WARN_ON_ONCE(!kvm_arch_has_private_mem(kvm));
+	return false;
+}
+
+bool kvm_arch_post_set_memory_attributes(struct kvm *kvm,
+					 struct kvm_gfn_range *range)
+{
+	if (WARN_ON_ONCE(!kvm_arch_has_private_mem(kvm)))
+		return false;
+
+	if (range->arg.attributes & KVM_MEMORY_ATTRIBUTE_PRIVATE)
+		range->attr_filter = KVM_FILTER_SHARED;
+	else
+		range->attr_filter = KVM_FILTER_PRIVATE;
+	kvm_unmap_gfn_range(kvm, range);
+
+	return false;
+}
+#endif
+
 void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot)
 {
 }
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:10:57 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:10:57 +0000
Subject: [PATCH v12 20/46] arm64: RMI: Allow populating initial contents
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-21-steven.price@arm.com>

The VMM needs to populate the realm with some data before starting (e.g.
a kernel and initrd). This is measured by the RMM and used as part of
the attestation later on.

Signed-off-by: Steven Price <steven.price at arm.com>
---
Changes since v11:
 * The multiplex CAP is gone and there's a new ioctl which makes use of
   the generic kvm_gmem_populate() functionality.
Changes since v7:
 * Improve the error codes.
 * Other minor changes from review.
Changes since v6:
 * Handle host potentially having a larger page size than the RMM
   granule.
 * Drop historic "par" (protected address range) from
   populate_par_region() - it doesn't exist within the current
   architecture.
 * Add a cond_resched() call in kvm_populate_realm().
Changes since v5:
 * Refactor to use PFNs rather than tracking struct page in
   realm_create_protected_data_page().
 * Pull changes from a later patch (in the v5 series) for accessing
   pages from a guest memfd.
 * Do the populate in chunks to avoid holding locks for too long and
   triggering RCU stall warnings.
---
 arch/arm64/include/asm/kvm_rmi.h |   4 +
 arch/arm64/kvm/Kconfig           |   1 +
 arch/arm64/kvm/arm.c             |   9 ++
 arch/arm64/kvm/rmi.c             | 175 +++++++++++++++++++++++++++++++
 4 files changed, 189 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_rmi.h
index 8a862fc1a99d..b5e36344975c 100644
--- a/arch/arm64/include/asm/kvm_rmi.h
+++ b/arch/arm64/include/asm/kvm_rmi.h
@@ -99,6 +99,10 @@ int kvm_rec_enter(struct kvm_vcpu *vcpu);
 int kvm_rec_pre_enter(struct kvm_vcpu *vcpu);
 int handle_rec_exit(struct kvm_vcpu *vcpu, int rec_run_status);
 
+struct kvm_arm_rmi_populate;
+
+int kvm_arm_rmi_populate(struct kvm *kvm,
+			 struct kvm_arm_rmi_populate *arg);
 void kvm_realm_unmap_range(struct kvm *kvm,
 			   unsigned long ipa,
 			   unsigned long size,
diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index 1cac6dfc0972..b495dfd3a8b4 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -39,6 +39,7 @@ menuconfig KVM
 	select GUEST_PERF_EVENTS if PERF_EVENTS
 	select KVM_GUEST_MEMFD
 	select KVM_GENERIC_MEMORY_ATTRIBUTES
+	select HAVE_KVM_ARCH_GMEM_POPULATE
 	help
 	  Support hosting virtualized guest machines.
 
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 7927181887cf..0a06ed9d1a64 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -2037,6 +2037,15 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
 			return -EFAULT;
 		return kvm_vm_ioctl_get_reg_writable_masks(kvm, &range);
 	}
+	case KVM_ARM_RMI_POPULATE: {
+		struct kvm_arm_rmi_populate req;
+
+		if (!kvm_is_realm(kvm))
+			return -EPERM;
+		if (copy_from_user(&req, argp, sizeof(req)))
+			return -EFAULT;
+		return kvm_arm_rmi_populate(kvm, &req);
+	}
 	default:
 		return -EINVAL;
 	}
diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
index fe15b400091c..39577e956a59 100644
--- a/arch/arm64/kvm/rmi.c
+++ b/arch/arm64/kvm/rmi.c
@@ -558,6 +558,150 @@ void kvm_realm_unmap_range(struct kvm *kvm, unsigned long start,
 		realm_unmap_private_range(kvm, start, end, may_block);
 }
 
+static int realm_create_protected_data_granule(struct realm *realm,
+					       unsigned long ipa,
+					       phys_addr_t dst_phys,
+					       phys_addr_t src_phys,
+					       unsigned long flags)
+{
+	phys_addr_t rd = virt_to_phys(realm->rd);
+	int ret;
+
+	if (rmi_granule_delegate(dst_phys))
+		return -ENXIO;
+
+	ret = rmi_data_create(rd, dst_phys, ipa, src_phys, flags);
+	if (RMI_RETURN_STATUS(ret) == RMI_ERROR_RTT) {
+		/* Create missing RTTs and retry */
+		int level = RMI_RETURN_INDEX(ret);
+
+		WARN_ON(level == RMM_RTT_MAX_LEVEL);
+
+		ret = realm_create_rtt_levels(realm, ipa, level,
+					      RMM_RTT_MAX_LEVEL, NULL);
+		if (ret)
+			return -EIO;
+
+		ret = rmi_data_create(rd, dst_phys, ipa, src_phys, flags);
+	}
+	if (ret)
+		return -EIO;
+
+	return 0;
+}
+
+static int realm_create_protected_data_page(struct realm *realm,
+					    unsigned long ipa,
+					    kvm_pfn_t dst_pfn,
+					    kvm_pfn_t src_pfn,
+					    unsigned long flags)
+{
+	unsigned long rd = virt_to_phys(realm->rd);
+	phys_addr_t dst_phys, src_phys;
+	bool undelegate_failed = false;
+	int ret, offset;
+
+	dst_phys = __pfn_to_phys(dst_pfn);
+	src_phys = __pfn_to_phys(src_pfn);
+
+	for (offset = 0; offset < PAGE_SIZE; offset += RMM_PAGE_SIZE) {
+		ret = realm_create_protected_data_granule(realm,
+							  ipa,
+							  dst_phys,
+							  src_phys,
+							  flags);
+		if (ret)
+			goto err;
+
+		ipa += RMM_PAGE_SIZE;
+		dst_phys += RMM_PAGE_SIZE;
+		src_phys += RMM_PAGE_SIZE;
+	}
+
+	return 0;
+
+err:
+	if (ret == -EIO) {
+		/* current offset needs undelegating */
+		if (WARN_ON(rmi_granule_undelegate(dst_phys)))
+			undelegate_failed = true;
+	}
+	while (offset > 0) {
+		ipa -= RMM_PAGE_SIZE;
+		offset -= RMM_PAGE_SIZE;
+		dst_phys -= RMM_PAGE_SIZE;
+
+		rmi_data_destroy(rd, ipa, NULL, NULL);
+
+		if (WARN_ON(rmi_granule_undelegate(dst_phys)))
+			undelegate_failed = true;
+	}
+
+	if (undelegate_failed) {
+		/*
+		 * A granule could not be undelegated,
+		 * so the page has to be leaked
+		 */
+		get_page(pfn_to_page(dst_pfn));
+	}
+
+	return -ENXIO;
+}
+
+static int populate_region_cb(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn,
+			      void __user *src, int order, void *opaque)
+{
+	struct realm *realm = &kvm->arch.realm;
+	unsigned long data_flags = *(unsigned long *)opaque;
+	phys_addr_t ipa = gfn_to_gpa(gfn);
+	int npages = (1 << order);
+	int i;
+
+	for (i = 0; i < npages; i++) {
+		struct page *src_page;
+		int ret;
+
+		ret = get_user_pages((unsigned long)src, 1, 0, &src_page);
+		if (ret < 0)
+			return ret;
+		if (ret != 1)
+			return -ENOMEM;
+
+		ret = realm_create_protected_data_page(realm, ipa, pfn,
+						       page_to_pfn(src_page),
+						       data_flags);
+
+		put_page(src_page);
+
+		if (ret)
+			return ret;
+
+		ipa += PAGE_SIZE;
+		pfn++;
+		src += PAGE_SIZE;
+	}
+
+	return 0;
+}
+
+static long populate_region(struct kvm *kvm,
+			    gfn_t base_gfn,
+			    unsigned long pages,
+			    u64 uaddr,
+			    unsigned long data_flags)
+{
+	long ret = 0;
+
+	mutex_lock(&kvm->slots_lock);
+	mmap_read_lock(current->mm);
+	ret = kvm_gmem_populate(kvm, base_gfn, u64_to_user_ptr(uaddr), pages,
+				populate_region_cb, &data_flags);
+	mmap_read_unlock(current->mm);
+	mutex_unlock(&kvm->slots_lock);
+
+	return ret;
+}
+
 enum ripas_action {
 	RIPAS_INIT,
 	RIPAS_SET,
@@ -655,6 +799,37 @@ static int realm_ensure_created(struct kvm *kvm)
 	return -ENXIO;
 }
 
+int kvm_arm_rmi_populate(struct kvm *kvm,
+			 struct kvm_arm_rmi_populate *args)
+{
+	unsigned long data_flags = 0;
+	unsigned long ipa_start = args->base;
+	unsigned long ipa_end = ipa_start + args->size;
+	int ret;
+
+	if (args->reserved ||
+	    (args->flags & ~KVM_ARM_RMI_POPULATE_FLAGS_MEASURE) ||
+	    !IS_ALIGNED(ipa_start, PAGE_SIZE) ||
+	    !IS_ALIGNED(ipa_end, PAGE_SIZE))
+		return -EINVAL;
+
+	ret = realm_ensure_created(kvm);
+	if (ret)
+		return ret;
+
+	if (args->flags & KVM_ARM_RMI_POPULATE_FLAGS_MEASURE)
+		data_flags |= RMI_MEASURE_CONTENT;
+
+	ret = populate_region(kvm, gpa_to_gfn(ipa_start),
+			      args->size >> PAGE_SHIFT,
+			      args->source_uaddr, args->flags);
+
+	if (ret < 0)
+		return ret;
+
+	return ret * PAGE_SIZE;
+}
+
 static void kvm_complete_ripas_change(struct kvm_vcpu *vcpu)
 {
 	struct kvm *kvm = vcpu->kvm;
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:10:58 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:10:58 +0000
Subject: [PATCH v12 21/46] arm64: RMI: Set RIPAS of initial memslots
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-22-steven.price@arm.com>

The memory which the realm guest accesses must be set to RIPAS_RAM.
Iterate over the memslots and set all gmem memslots to RIPAS_RAM.

Signed-off-by: Steven Price <steven.price at arm.com>
---
New patch for v12.
---
 arch/arm64/kvm/rmi.c | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
index 39577e956a59..b51e68e56d56 100644
--- a/arch/arm64/kvm/rmi.c
+++ b/arch/arm64/kvm/rmi.c
@@ -793,12 +793,44 @@ static int realm_set_ipa_state(struct kvm_vcpu *vcpu,
 	return ret;
 }
 
+static int realm_init_ipa_state(struct kvm *kvm,
+				unsigned long gfn,
+				unsigned long pages)
+{
+	return ripas_change(kvm, NULL, gfn_to_gpa(gfn), gfn_to_gpa(gfn + pages),
+			    RIPAS_INIT, NULL);
+}
+
 static int realm_ensure_created(struct kvm *kvm)
 {
 	/* Provided in later patch */
 	return -ENXIO;
 }
 
+static int set_ripas_of_protected_regions(struct kvm *kvm)
+{
+	struct kvm_memslots *slots;
+	struct kvm_memory_slot *memslot;
+	int idx, bkt;
+	int ret = 0;
+
+	idx = srcu_read_lock(&kvm->srcu);
+
+	slots = kvm_memslots(kvm);
+	kvm_for_each_memslot(memslot, bkt, slots) {
+		if (!kvm_slot_has_gmem(memslot))
+			continue;
+
+		ret = realm_init_ipa_state(kvm, memslot->base_gfn,
+					   memslot->npages);
+		if (ret)
+			break;
+	}
+	srcu_read_unlock(&kvm->srcu, idx);
+
+	return ret;
+}
+
 int kvm_arm_rmi_populate(struct kvm *kvm,
 			 struct kvm_arm_rmi_populate *args)
 {
@@ -1119,6 +1151,10 @@ int kvm_activate_realm(struct kvm *kvm)
 			return ret;
 	}
 
+	ret = set_ripas_of_protected_regions(kvm);
+	if (ret)
+		return ret;
+
 	ret = rmi_realm_activate(virt_to_phys(realm->rd));
 	if (ret)
 		return -ENXIO;
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:10:59 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:10:59 +0000
Subject: [PATCH v12 22/46] arm64: RMI: Create the realm descriptor
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-23-steven.price@arm.com>

Creating a realm involves first creating a realm descriptor (RD). This
involves passing the configuration information to the RMM. Do this as
part of realm_ensure_created() so that the realm is created when it is
first needed.

Signed-off-by: Steven Price <steven.price at arm.com>
---
New patch for v12
---
 arch/arm64/kvm/rmi.c | 117 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 115 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
index b51e68e56d56..18edc7eeb5fa 100644
--- a/arch/arm64/kvm/rmi.c
+++ b/arch/arm64/kvm/rmi.c
@@ -500,6 +500,106 @@ static void realm_unmap_shared_range(struct kvm *kvm,
 			     start, end);
 }
 
+/* Calculate the number of s2 root rtts needed */
+static int realm_num_root_rtts(struct realm *realm)
+{
+	unsigned int ipa_bits = realm->ia_bits;
+	unsigned int levels = 4 - get_start_level(realm);
+	unsigned int sl_ipa_bits = levels * (RMM_PAGE_SHIFT - 3) +
+				   RMM_PAGE_SHIFT;
+
+	if (sl_ipa_bits >= ipa_bits)
+		return 1;
+
+	return 1 << (ipa_bits - sl_ipa_bits);
+}
+
+static int realm_create_rd(struct kvm *kvm)
+{
+	struct realm *realm = &kvm->arch.realm;
+	struct realm_params *params = realm->params;
+	void *rd = NULL;
+	phys_addr_t rd_phys, params_phys;
+	size_t pgd_size = kvm_pgtable_stage2_pgd_size(kvm->arch.mmu.vtcr);
+	int i, r;
+	int rtt_num_start;
+
+	realm->ia_bits = VTCR_EL2_IPA(kvm->arch.mmu.vtcr);
+	rtt_num_start = realm_num_root_rtts(realm);
+
+	if (WARN_ON(realm->rd || !realm->params))
+		return -EEXIST;
+
+	if (pgd_size / RMM_PAGE_SIZE < rtt_num_start)
+		return -EINVAL;
+
+	rd = (void *)__get_free_page(GFP_KERNEL);
+	if (!rd)
+		return -ENOMEM;
+
+	rd_phys = virt_to_phys(rd);
+	if (rmi_granule_delegate(rd_phys)) {
+		r = -ENXIO;
+		goto free_rd;
+	}
+
+	for (i = 0; i < pgd_size; i += RMM_PAGE_SIZE) {
+		phys_addr_t pgd_phys = kvm->arch.mmu.pgd_phys + i;
+
+		if (rmi_granule_delegate(pgd_phys)) {
+			r = -ENXIO;
+			goto out_undelegate_tables;
+		}
+	}
+
+	params->s2sz = VTCR_EL2_IPA(kvm->arch.mmu.vtcr);
+	params->rtt_level_start = get_start_level(realm);
+	params->rtt_num_start = rtt_num_start;
+	params->rtt_base = kvm->arch.mmu.pgd_phys;
+	params->vmid = realm->vmid;
+
+	params_phys = virt_to_phys(params);
+
+	if (rmi_realm_create(rd_phys, params_phys)) {
+		r = -ENXIO;
+		goto out_undelegate_tables;
+	}
+
+	if (WARN_ON(rmi_rec_aux_count(rd_phys, &realm->num_aux))) {
+		WARN_ON(rmi_realm_destroy(rd_phys));
+		r = -ENXIO;
+		goto out_undelegate_tables;
+	}
+
+	realm->rd = rd;
+	WRITE_ONCE(realm->state, REALM_STATE_NEW);
+	/* The realm is up, free the parameters.  */
+	free_page((unsigned long)realm->params);
+	realm->params = NULL;
+
+	return 0;
+
+out_undelegate_tables:
+	while (i > 0) {
+		i -= RMM_PAGE_SIZE;
+
+		phys_addr_t pgd_phys = kvm->arch.mmu.pgd_phys + i;
+
+		if (WARN_ON(rmi_granule_undelegate(pgd_phys))) {
+			/* Leak the pages if they cannot be returned */
+			kvm->arch.mmu.pgt = NULL;
+			break;
+		}
+	}
+	if (WARN_ON(rmi_granule_undelegate(rd_phys))) {
+		/* Leak the page if it isn't returned */
+		return r;
+	}
+free_rd:
+	free_page((unsigned long)rd);
+	return r;
+}
+
 static int realm_unmap_private_page(struct realm *realm,
 				    unsigned long ipa,
 				    unsigned long *next_addr)
@@ -803,8 +903,21 @@ static int realm_init_ipa_state(struct kvm *kvm,
 
 static int realm_ensure_created(struct kvm *kvm)
 {
-	/* Provided in later patch */
-	return -ENXIO;
+	int ret;
+
+	switch (kvm_realm_state(kvm)) {
+	case REALM_STATE_NONE:
+		break;
+	case REALM_STATE_NEW:
+		return 0;
+	case REALM_STATE_DEAD:
+		return -ENXIO;
+	default:
+		return -EBUSY;
+	}
+
+	ret = realm_create_rd(kvm);
+	return ret;
 }
 
 static int set_ripas_of_protected_regions(struct kvm *kvm)
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:11:00 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:11:00 +0000
Subject: [PATCH v12 23/46] arm64: RMI: Add a VMID allocator for realms
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-24-steven.price@arm.com>

The RMM v1.0 spec requires that the host manage the VMIDs of realm
guests. Add a basic allocator and assign a unique VMID to the guest when
creating the realm descriptor.

Signed-off-by: Steven Price <steven.price at arm.com>
---
New patch for v12.
NOTE: RMM v2.0 will remove the requirement for the host to manage VMIDs
---
 arch/arm64/kvm/rmi.c | 48 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
index 18edc7eeb5fa..ede6c250bcfb 100644
--- a/arch/arm64/kvm/rmi.c
+++ b/arch/arm64/kvm/rmi.c
@@ -600,6 +600,42 @@ static int realm_create_rd(struct kvm *kvm)
 	return r;
 }
 
+/* Protects access to rmi_vmid_bitmap */
+static DEFINE_SPINLOCK(rmi_vmid_lock);
+static unsigned long *rmi_vmid_bitmap;
+
+static int rmi_vmid_init(void)
+{
+	unsigned int vmid_count = 1 << kvm_get_vmid_bits();
+
+	rmi_vmid_bitmap = bitmap_zalloc(vmid_count, GFP_KERNEL);
+	if (!rmi_vmid_bitmap) {
+		kvm_err("%s: Couldn't allocate rmi vmid bitmap\n", __func__);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static int rmi_vmid_reserve(void)
+{
+	int ret;
+	unsigned int vmid_count = 1 << kvm_get_vmid_bits();
+
+	spin_lock(&rmi_vmid_lock);
+	ret = bitmap_find_free_region(rmi_vmid_bitmap, vmid_count, 0);
+	spin_unlock(&rmi_vmid_lock);
+
+	return ret;
+}
+
+static void rmi_vmid_release(unsigned int vmid)
+{
+	spin_lock(&rmi_vmid_lock);
+	bitmap_release_region(rmi_vmid_bitmap, vmid, 0);
+	spin_unlock(&rmi_vmid_lock);
+}
+
 static int realm_unmap_private_page(struct realm *realm,
 				    unsigned long ipa,
 				    unsigned long *next_addr)
@@ -903,6 +939,7 @@ static int realm_init_ipa_state(struct kvm *kvm,
 
 static int realm_ensure_created(struct kvm *kvm)
 {
+	struct realm *realm = &kvm->arch.realm;
 	int ret;
 
 	switch (kvm_realm_state(kvm)) {
@@ -916,7 +953,13 @@ static int realm_ensure_created(struct kvm *kvm)
 		return -EBUSY;
 	}
 
+	ret = rmi_vmid_reserve();
+	if (ret < 0)
+		return ret;
+	realm->vmid = ret;
 	ret = realm_create_rd(kvm);
+	if (ret)
+		rmi_vmid_release(realm->vmid);
 	return ret;
 }
 
@@ -1307,6 +1350,8 @@ void kvm_destroy_realm(struct kvm *kvm)
 		realm->rd = NULL;
 	}
 
+	rmi_vmid_release(realm->vmid);
+
 	for (i = 0; i < pgd_size; i += RMM_PAGE_SIZE) {
 		phys_addr_t pgd_phys = kvm->arch.mmu.pgd_phys + i;
 
@@ -1342,5 +1387,8 @@ void kvm_init_rmi(void)
 	if (WARN_ON(rmi_features(0, &rmm_feat_reg0)))
 		return;
 
+	if (rmi_vmid_init())
+		return;
+
 	/* Future patch will enable static branch kvm_rmi_is_available */
 }
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:11:01 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:11:01 +0000
Subject: [PATCH v12 24/46] arm64: RMI: Runtime faulting of memory
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-25-steven.price@arm.com>

At runtime if the realm guest accesses memory which hasn't yet been
mapped then KVM needs to either populate the region or fault the guest.

For memory in the lower (protected) region of IPA a fresh page is
provided to the RMM which will zero the contents. For memory in the
upper (shared) region of IPA, the memory from the memslot is mapped
into the realm VM non secure.

Signed-off-by: Steven Price <steven.price at arm.com>
---
Changes since v11:
 * Adapt to upstream changes.
Changes since v10:
 * RME->RMI renaming.
 * Adapt to upstream gmem changes.
Changes since v9:
 * Fix call to kvm_stage2_unmap_range() in kvm_free_stage2_pgd() to set
   may_block to avoid stall warnings.
 * Minor coding style fixes.
Changes since v8:
 * Propagate the may_block flag.
 * Minor comments and coding style changes.
Changes since v7:
 * Remove redundant WARN_ONs for realm_create_rtt_levels() - it will
   internally WARN when necessary.
Changes since v6:
 * Handle PAGE_SIZE being larger than RMM granule size.
 * Some minor renaming following review comments.
Changes since v5:
 * Reduce use of struct page in preparation for supporting the RMM
   having a different page size to the host.
 * Handle a race when delegating a page where another CPU has faulted on
   a the same page (and already delegated the physical page) but not yet
   mapped it. In this case simply return to the guest to either use the
   mapping from the other CPU (or refault if the race is lost).
 * The changes to populate_par_region() are moved into the previous
   patch where they belong.
Changes since v4:
 * Code cleanup following review feedback.
 * Drop the PTE_SHARED bit when creating unprotected page table entries.
   This is now set by the RMM and the host has no control of it and the
   spec requires the bit to be set to zero.
Changes since v2:
 * Avoid leaking memory if failing to map it in the realm.
 * Correctly mask RTT based on LPA2 flag (see rtt_get_phys()).
 * Adapt to changes in previous patches.
---
 arch/arm64/include/asm/kvm_emulate.h |   8 ++
 arch/arm64/include/asm/kvm_rmi.h     |  10 ++
 arch/arm64/kvm/mmu.c                 | 139 ++++++++++++++++++++---
 arch/arm64/kvm/rmi.c                 | 164 +++++++++++++++++++++++++++
 4 files changed, 307 insertions(+), 14 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index f884bac43c06..7d8380fede14 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -714,6 +714,14 @@ static inline bool kvm_realm_is_created(struct kvm *kvm)
 	return kvm_is_realm(kvm) && kvm_realm_state(kvm) != REALM_STATE_NONE;
 }
 
+static inline gpa_t kvm_gpa_from_fault(struct kvm *kvm, phys_addr_t ipa)
+{
+	if (!kvm_is_realm(kvm))
+		return ipa;
+
+	return ipa & ~BIT(kvm->arch.realm.ia_bits - 1);
+}
+
 static inline bool vcpu_is_rec(struct kvm_vcpu *vcpu)
 {
 	return kvm_is_realm(vcpu->kvm);
diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_rmi.h
index b5e36344975c..bfe6428eaf16 100644
--- a/arch/arm64/include/asm/kvm_rmi.h
+++ b/arch/arm64/include/asm/kvm_rmi.h
@@ -108,6 +108,16 @@ void kvm_realm_unmap_range(struct kvm *kvm,
 			   unsigned long size,
 			   bool unmap_private,
 			   bool may_block);
+int realm_map_protected(struct realm *realm,
+			unsigned long base_ipa,
+			kvm_pfn_t pfn,
+			unsigned long size,
+			struct kvm_mmu_memory_cache *memcache);
+int realm_map_non_secure(struct realm *realm,
+			 unsigned long ipa,
+			 kvm_pfn_t pfn,
+			 unsigned long size,
+			 struct kvm_mmu_memory_cache *memcache);
 
 static inline bool kvm_realm_is_private_address(struct realm *realm,
 						unsigned long addr)
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index f2ac01c1de04..860c42aabcf0 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -334,8 +334,15 @@ static void __unmap_stage2_range(struct kvm_s2_mmu *mmu, phys_addr_t start, u64
 
 	lockdep_assert_held_write(&kvm->mmu_lock);
 	WARN_ON(size & ~PAGE_MASK);
-	WARN_ON(stage2_apply_range(mmu, start, end, KVM_PGT_FN(kvm_pgtable_stage2_unmap),
-				   may_block));
+
+	if (kvm_is_realm(kvm)) {
+		kvm_realm_unmap_range(kvm, start, size, !only_shared,
+				      may_block);
+	} else {
+		WARN_ON(stage2_apply_range(mmu, start, end,
+					   KVM_PGT_FN(kvm_pgtable_stage2_unmap),
+					   may_block));
+	}
 }
 
 void kvm_stage2_unmap_range(struct kvm_s2_mmu *mmu, phys_addr_t start,
@@ -355,7 +362,10 @@ static void stage2_flush_memslot(struct kvm *kvm,
 	phys_addr_t addr = memslot->base_gfn << PAGE_SHIFT;
 	phys_addr_t end = addr + PAGE_SIZE * memslot->npages;
 
-	kvm_stage2_flush_range(&kvm->arch.mmu, addr, end);
+	if (kvm_is_realm(kvm))
+		kvm_realm_unmap_range(kvm, addr, end - addr, false, true);
+	else
+		kvm_stage2_flush_range(&kvm->arch.mmu, addr, end);
 }
 
 /**
@@ -1081,6 +1091,10 @@ void stage2_unmap_vm(struct kvm *kvm)
 	struct kvm_memory_slot *memslot;
 	int idx, bkt;
 
+	/* For realms this is handled by the RMM so nothing to do here */
+	if (kvm_is_realm(kvm))
+		return;
+
 	idx = srcu_read_lock(&kvm->srcu);
 	mmap_read_lock(current->mm);
 	write_lock(&kvm->mmu_lock);
@@ -1106,6 +1120,9 @@ void kvm_free_stage2_pgd(struct kvm_s2_mmu *mmu)
 	if (kvm_is_realm(kvm) &&
 	    (kvm_realm_state(kvm) != REALM_STATE_DEAD &&
 	     kvm_realm_state(kvm) != REALM_STATE_NONE)) {
+		struct realm *realm = &kvm->arch.realm;
+
+		kvm_stage2_unmap_range(mmu, 0, BIT(realm->ia_bits - 1), true);
 		write_unlock(&kvm->mmu_lock);
 		kvm_realm_destroy_rtts(kvm);
 
@@ -1515,6 +1532,29 @@ static bool kvm_vma_mte_allowed(struct vm_area_struct *vma)
 	return vma->vm_flags & VM_MTE_ALLOWED;
 }
 
+static int realm_map_ipa(struct kvm *kvm, phys_addr_t ipa,
+			 kvm_pfn_t pfn, unsigned long map_size,
+			 enum kvm_pgtable_prot prot,
+			 struct kvm_mmu_memory_cache *memcache)
+{
+	struct realm *realm = &kvm->arch.realm;
+
+	/*
+	 * Write permission is required for now even though it's possible to
+	 * map unprotected pages (granules) as read-only. It's impossible to
+	 * map protected pages (granules) as read-only.
+	 */
+	if (WARN_ON(!(prot & KVM_PGTABLE_PROT_W)))
+		return -EFAULT;
+
+	ipa = ALIGN_DOWN(ipa, PAGE_SIZE);
+	if (!kvm_realm_is_private_address(realm, ipa))
+		return realm_map_non_secure(realm, ipa, pfn, map_size,
+					    memcache);
+
+	return realm_map_protected(realm, ipa, pfn, map_size, memcache);
+}
+
 static bool kvm_vma_is_cacheable(struct vm_area_struct *vma)
 {
 	switch (FIELD_GET(PTE_ATTRINDX_MASK, pgprot_val(vma->vm_page_prot))) {
@@ -1589,6 +1629,7 @@ static int gmem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 	enum kvm_pgtable_walk_flags flags = KVM_PGTABLE_WALK_MEMABORT_FLAGS;
 	enum kvm_pgtable_prot prot = KVM_PGTABLE_PROT_R;
 	struct kvm_pgtable *pgt = vcpu->arch.hw_mmu->pgt;
+	gpa_t gpa = kvm_gpa_from_fault(vcpu->kvm, fault_ipa);
 	unsigned long mmu_seq;
 	struct page *page;
 	struct kvm *kvm = vcpu->kvm;
@@ -1597,6 +1638,29 @@ static int gmem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 	gfn_t gfn;
 	int ret;
 
+	if (kvm_is_realm(vcpu->kvm)) {
+		/* check for memory attribute mismatch */
+		bool is_priv_gfn = kvm_mem_is_private(kvm, gpa >> PAGE_SHIFT);
+		/*
+		 * For Realms, the shared address is an alias of the private
+		 * PA with the top bit set. Thus is the fault address matches
+		 * the GPA then it is the private alias.
+		 */
+		bool is_priv_fault = (gpa == fault_ipa);
+
+		if (is_priv_gfn != is_priv_fault) {
+			kvm_prepare_memory_fault_exit(vcpu, gpa, PAGE_SIZE,
+						      kvm_is_write_fault(vcpu),
+						      false,
+						      is_priv_fault);
+			/*
+			 * KVM_EXIT_MEMORY_FAULT requires an return code of
+			 * -EFAULT, see the API documentation
+			 */
+			return -EFAULT;
+		}
+	}
+
 	ret = prepare_mmu_memcache(vcpu, true, &memcache);
 	if (ret)
 		return ret;
@@ -1604,7 +1668,7 @@ static int gmem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 	if (nested)
 		gfn = kvm_s2_trans_output(nested) >> PAGE_SHIFT;
 	else
-		gfn = fault_ipa >> PAGE_SHIFT;
+		gfn = gpa >> PAGE_SHIFT;
 
 	write_fault = kvm_is_write_fault(vcpu);
 	exec_fault = kvm_vcpu_trap_is_exec_fault(vcpu);
@@ -1617,7 +1681,7 @@ static int gmem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 
 	ret = kvm_gmem_get_pfn(kvm, memslot, gfn, &pfn, &page, NULL);
 	if (ret) {
-		kvm_prepare_memory_fault_exit(vcpu, fault_ipa, PAGE_SIZE,
+		kvm_prepare_memory_fault_exit(vcpu, gpa, PAGE_SIZE,
 					      write_fault, exec_fault, false);
 		return ret;
 	}
@@ -1639,15 +1703,25 @@ static int gmem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 	kvm_fault_lock(kvm);
 	if (mmu_invalidate_retry(kvm, mmu_seq)) {
 		ret = -EAGAIN;
-		goto out_unlock;
+		goto out_release_page;
+	}
+
+	if (kvm_is_realm(kvm)) {
+		ret = realm_map_ipa(kvm, fault_ipa, pfn,
+				    PAGE_SIZE, KVM_PGTABLE_PROT_W, memcache);
+		/* if successful don't release the page */
+		if (!ret)
+			goto out_unlock;
+		goto out_release_page;
 	}
 
 	ret = KVM_PGT_FN(kvm_pgtable_stage2_map)(pgt, fault_ipa, PAGE_SIZE,
 						 __pfn_to_phys(pfn), prot,
 						 memcache, flags);
 
-out_unlock:
+out_release_page:
 	kvm_release_faultin_page(kvm, page, !!ret, writable);
+out_unlock:
 	kvm_fault_unlock(kvm);
 
 	if (writable && !ret)
@@ -1686,6 +1760,14 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 	if (fault_is_perm)
 		fault_granule = kvm_vcpu_trap_get_perm_fault_granule(vcpu);
 	write_fault = kvm_is_write_fault(vcpu);
+
+	/*
+	 * Realms cannot map protected pages read-only
+	 * FIXME: It should be possible to map unprotected pages read-only
+	 */
+	if (vcpu_is_rec(vcpu))
+		write_fault = true;
+
 	exec_fault = kvm_vcpu_trap_is_exec_fault(vcpu);
 	VM_WARN_ON_ONCE(write_fault && exec_fault);
 
@@ -1780,7 +1862,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 		ipa &= ~(vma_pagesize - 1);
 	}
 
-	gfn = ipa >> PAGE_SHIFT;
+	gfn = kvm_gpa_from_fault(kvm, ipa) >> PAGE_SHIFT;
 	mte_allowed = kvm_vma_mte_allowed(vma);
 
 	vfio_allow_any_uc = vma->vm_flags & VM_ALLOW_ANY_UNCACHED;
@@ -1856,6 +1938,15 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 	if (exec_fault && s2_force_noncacheable)
 		ret = -ENOEXEC;
 
+	/*
+	 * For now we shouldn't be hitting protected addresses because they are
+	 * handled in gmem_abort(). In the future this check may be relaxed to
+	 * support e.g. protected devices.
+	 */
+	if (!ret && vcpu_is_rec(vcpu) &&
+	    kvm_gpa_from_fault(kvm, fault_ipa) == fault_ipa)
+		ret = -EINVAL;
+
 	if (ret) {
 		kvm_release_page_unused(page);
 		return ret;
@@ -1929,6 +2020,9 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 		 */
 		prot &= ~KVM_NV_GUEST_MAP_SZ;
 		ret = KVM_PGT_FN(kvm_pgtable_stage2_relax_perms)(pgt, fault_ipa, prot, flags);
+	} else if (kvm_is_realm(kvm)) {
+		ret = realm_map_ipa(kvm, fault_ipa, pfn, vma_pagesize,
+				    prot, memcache);
 	} else {
 		ret = KVM_PGT_FN(kvm_pgtable_stage2_map)(pgt, fault_ipa, vma_pagesize,
 					     __pfn_to_phys(pfn), prot,
@@ -2039,6 +2133,13 @@ int kvm_handle_guest_sea(struct kvm_vcpu *vcpu)
 	return 0;
 }
 
+static bool shared_ipa_fault(struct kvm *kvm, phys_addr_t fault_ipa)
+{
+	gpa_t gpa = kvm_gpa_from_fault(kvm, fault_ipa);
+
+	return (gpa != fault_ipa);
+}
+
 /**
  * kvm_handle_guest_abort - handles all 2nd stage aborts
  * @vcpu:	the VCPU pointer
@@ -2148,8 +2249,9 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
 		nested = &nested_trans;
 	}
 
-	gfn = ipa >> PAGE_SHIFT;
+	gfn = kvm_gpa_from_fault(vcpu->kvm, ipa) >> PAGE_SHIFT;
 	memslot = gfn_to_memslot(vcpu->kvm, gfn);
+
 	hva = gfn_to_hva_memslot_prot(memslot, gfn, &writable);
 	write_fault = kvm_is_write_fault(vcpu);
 	if (kvm_is_error_hva(hva) || (write_fault && !writable)) {
@@ -2192,7 +2294,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
 		 * of the page size.
 		 */
 		ipa |= kvm_vcpu_get_hfar(vcpu) & GENMASK(11, 0);
-		ret = io_mem_abort(vcpu, ipa);
+		ret = io_mem_abort(vcpu, kvm_gpa_from_fault(vcpu->kvm, ipa));
 		goto out_unlock;
 	}
 
@@ -2208,7 +2310,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
 	VM_WARN_ON_ONCE(kvm_vcpu_trap_is_permission_fault(vcpu) &&
 			!write_fault && !kvm_vcpu_trap_is_exec_fault(vcpu));
 
-	if (kvm_slot_has_gmem(memslot))
+	if (kvm_slot_has_gmem(memslot) && !shared_ipa_fault(vcpu->kvm, fault_ipa))
 		ret = gmem_abort(vcpu, fault_ipa, nested, memslot,
 				 esr_fsc_is_permission_fault(esr));
 	else
@@ -2245,6 +2347,10 @@ bool kvm_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
 	if (!kvm->arch.mmu.pgt)
 		return false;
 
+	/* We don't support aging for Realms */
+	if (kvm_is_realm(kvm))
+		return true;
+
 	return KVM_PGT_FN(kvm_pgtable_stage2_test_clear_young)(kvm->arch.mmu.pgt,
 						   range->start << PAGE_SHIFT,
 						   size, true);
@@ -2261,6 +2367,10 @@ bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
 	if (!kvm->arch.mmu.pgt)
 		return false;
 
+	/* We don't support aging for Realms */
+	if (kvm_is_realm(kvm))
+		return true;
+
 	return KVM_PGT_FN(kvm_pgtable_stage2_test_clear_young)(kvm->arch.mmu.pgt,
 						   range->start << PAGE_SHIFT,
 						   size, false);
@@ -2447,10 +2557,11 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
 		return -EFAULT;
 
 	/*
-	 * Only support guest_memfd backed memslots with mappable memory, since
-	 * there aren't any CoCo VMs that support only private memory on arm64.
+	 * Only support guest_memfd backed memslots with mappable memory,
+	 * unless the guest is a CCA realm guest.
 	 */
-	if (kvm_slot_has_gmem(new) && !kvm_memslot_is_gmem_only(new))
+	if (kvm_slot_has_gmem(new) && !kvm_memslot_is_gmem_only(new) &&
+	    !kvm_is_realm(kvm))
 		return -EINVAL;
 
 	hva = new->userspace_addr;
diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
index ede6c250bcfb..de1a66df7a5e 100644
--- a/arch/arm64/kvm/rmi.c
+++ b/arch/arm64/kvm/rmi.c
@@ -784,6 +784,170 @@ static int realm_create_protected_data_page(struct realm *realm,
 	return -ENXIO;
 }
 
+static int fold_rtt(struct realm *realm, unsigned long addr, int level)
+{
+	phys_addr_t rtt_addr;
+	int ret;
+
+	ret = realm_rtt_fold(realm, addr, level, &rtt_addr);
+	if (ret)
+		return ret;
+
+	free_rtt(rtt_addr);
+
+	return 0;
+}
+
+int realm_map_protected(struct realm *realm,
+			unsigned long ipa,
+			kvm_pfn_t pfn,
+			unsigned long map_size,
+			struct kvm_mmu_memory_cache *memcache)
+{
+	phys_addr_t phys = __pfn_to_phys(pfn);
+	phys_addr_t rd = virt_to_phys(realm->rd);
+	unsigned long base_ipa = ipa;
+	unsigned long size;
+	int map_level = IS_ALIGNED(map_size, RMM_L2_BLOCK_SIZE) ?
+			RMM_RTT_BLOCK_LEVEL : RMM_RTT_MAX_LEVEL;
+	int ret = 0;
+
+	if (WARN_ON(!IS_ALIGNED(map_size, RMM_PAGE_SIZE) ||
+		    !IS_ALIGNED(ipa, map_size)))
+		return -EINVAL;
+
+	if (map_level < RMM_RTT_MAX_LEVEL) {
+		/*
+		 * A temporary RTT is needed during the map, precreate it,
+		 * however if there is an error (e.g. missing parent tables)
+		 * this will be handled below.
+		 */
+		realm_create_rtt_levels(realm, ipa, map_level,
+					RMM_RTT_MAX_LEVEL, memcache);
+	}
+
+	for (size = 0; size < map_size; size += RMM_PAGE_SIZE) {
+		if (rmi_granule_delegate(phys)) {
+			/*
+			 * It's likely we raced with another VCPU on the same
+			 * fault. Assume the other VCPU has handled the fault
+			 * and return to the guest.
+			 */
+			return 0;
+		}
+
+		ret = rmi_data_create_unknown(rd, phys, ipa);
+
+		if (RMI_RETURN_STATUS(ret) == RMI_ERROR_RTT) {
+			/* Create missing RTTs and retry */
+			int level = RMI_RETURN_INDEX(ret);
+
+			WARN_ON(level == RMM_RTT_MAX_LEVEL);
+			ret = realm_create_rtt_levels(realm, ipa, level,
+						      RMM_RTT_MAX_LEVEL,
+						      memcache);
+			if (ret)
+				goto err_undelegate;
+
+			ret = rmi_data_create_unknown(rd, phys, ipa);
+		}
+
+		if (WARN_ON(ret))
+			goto err_undelegate;
+
+		phys += RMM_PAGE_SIZE;
+		ipa += RMM_PAGE_SIZE;
+	}
+
+	if (map_size == RMM_L2_BLOCK_SIZE) {
+		ret = fold_rtt(realm, base_ipa, map_level + 1);
+		if (WARN_ON(ret))
+			goto err;
+	}
+
+	return 0;
+
+err_undelegate:
+	if (WARN_ON(rmi_granule_undelegate(phys))) {
+		/* Page can't be returned to NS world so is lost */
+		get_page(phys_to_page(phys));
+	}
+err:
+	while (size > 0) {
+		unsigned long data, top;
+
+		phys -= RMM_PAGE_SIZE;
+		size -= RMM_PAGE_SIZE;
+		ipa -= RMM_PAGE_SIZE;
+
+		WARN_ON(rmi_data_destroy(rd, ipa, &data, &top));
+
+		if (WARN_ON(rmi_granule_undelegate(phys))) {
+			/* Page can't be returned to NS world so is lost */
+			get_page(phys_to_page(phys));
+		}
+	}
+	return -ENXIO;
+}
+
+int realm_map_non_secure(struct realm *realm,
+			 unsigned long ipa,
+			 kvm_pfn_t pfn,
+			 unsigned long size,
+			 struct kvm_mmu_memory_cache *memcache)
+{
+	phys_addr_t rd = virt_to_phys(realm->rd);
+	phys_addr_t phys = __pfn_to_phys(pfn);
+	unsigned long offset;
+	/* TODO: Support block mappings */
+	int map_level = RMM_RTT_MAX_LEVEL;
+	int map_size = rmi_rtt_level_mapsize(map_level);
+	int ret = 0;
+
+	if (WARN_ON(!IS_ALIGNED(size, RMM_PAGE_SIZE) ||
+		    !IS_ALIGNED(ipa, size)))
+		return -EINVAL;
+
+	for (offset = 0; offset < size; offset += map_size) {
+		/*
+		 * realm_map_ipa() enforces that the memory is writable,
+		 * so for now we permit both read and write.
+		 */
+		unsigned long desc = phys |
+				     PTE_S2_MEMATTR(MT_S2_FWB_NORMAL) |
+				     KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R |
+				     KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W;
+		ret = rmi_rtt_map_unprotected(rd, ipa, map_level, desc);
+
+		if (RMI_RETURN_STATUS(ret) == RMI_ERROR_RTT) {
+			/* Create missing RTTs and retry */
+			int level = RMI_RETURN_INDEX(ret);
+
+			ret = realm_create_rtt_levels(realm, ipa, level,
+						      map_level, memcache);
+			if (ret)
+				return -ENXIO;
+
+			ret = rmi_rtt_map_unprotected(rd, ipa, map_level, desc);
+		}
+		/*
+		 * RMI_ERROR_RTT can be reported for two reasons: either the
+		 * RTT tables are not there, or there is an RTTE already
+		 * present for the address.  The above call to create RTTs
+		 * handles the first case, and in the second case this
+		 * indicates that another thread has already populated the RTTE
+		 * for us, so we can ignore the error and continue.
+		 */
+		if (ret && RMI_RETURN_STATUS(ret) != RMI_ERROR_RTT)
+			return -ENXIO;
+
+		ipa += map_size;
+		phys += map_size;
+	}
+
+	return 0;
+}
+
 static int populate_region_cb(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn,
 			      void __user *src, int order, void *opaque)
 {
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:11:02 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:11:02 +0000
Subject: [PATCH v12 25/46] KVM: arm64: Handle realm VCPU load
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-26-steven.price@arm.com>

When loading a realm VCPU much of the work is handled by the RMM so only
some of the actions are required. Rearrange kvm_arch_vcpu_load()
slightly so we can bail out early for a realm guest.

Signed-off-by: Steven Price <steven.price at arm.com>
---
 arch/arm64/kvm/arm.c | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 0a06ed9d1a64..06070bc47ee3 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -641,7 +641,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 	struct kvm_s2_mmu *mmu;
 	int *last_ran;
 
-	if (is_protected_kvm_enabled())
+	if (is_protected_kvm_enabled() || kvm_is_realm(vcpu->kvm))
 		goto nommu;
 
 	if (vcpu_has_nv(vcpu))
@@ -685,12 +685,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 	kvm_vgic_load(vcpu);
 	kvm_vcpu_load_debug(vcpu);
 	kvm_vcpu_load_fgt(vcpu);
-	if (has_vhe())
-		kvm_vcpu_load_vhe(vcpu);
-	kvm_arch_vcpu_load_fp(vcpu);
-	kvm_vcpu_pmu_restore_guest(vcpu);
-	if (kvm_arm_is_pvtime_enabled(&vcpu->arch))
-		kvm_make_request(KVM_REQ_RECORD_STEAL, vcpu);
 
 	if (kvm_vcpu_should_clear_twe(vcpu))
 		vcpu->arch.hcr_el2 &= ~HCR_TWE;
@@ -712,6 +706,17 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 			     &vcpu->arch.vgic_cpu.vgic_v3);
 	}
 
+	/* No additional state needs to be loaded on Realmed VMs */
+	if (vcpu_is_rec(vcpu))
+		return;
+
+	if (has_vhe())
+		kvm_vcpu_load_vhe(vcpu);
+	kvm_arch_vcpu_load_fp(vcpu);
+	kvm_vcpu_pmu_restore_guest(vcpu);
+	if (kvm_arm_is_pvtime_enabled(&vcpu->arch))
+		kvm_make_request(KVM_REQ_RECORD_STEAL, vcpu);
+
 	if (!cpumask_test_cpu(cpu, vcpu->kvm->arch.supported_cpus))
 		vcpu_set_on_unsupported_cpu(vcpu);
 }
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:11:03 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:11:03 +0000
Subject: [PATCH v12 26/46] KVM: arm64: Validate register access for a Realm VM
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-27-steven.price@arm.com>

The RMM only allows setting the GPRS (x0-x30) and PC for a realm
guest. Check this in kvm_arm_set_reg() so that the VMM can receive a
suitable error return if other registers are written to.

The RMM makes similar restrictions for reading of the guest's registers
(this is *confidential* compute after all), however we don't impose the
restriction here. This allows the VMM to read (stale) values from the
registers which might be useful to read back the initial values even if
the RMM doesn't provide the latest version. For migration of a realm VM,
a new interface will be needed so that the VMM can receive an
(encrypted) blob of the VM's state.

Reviewed-by: Gavin Shan <gshan at redhat.com>
Reviewed-by: Suzuki K Poulose <suzuki.poulose at arm.com>
Reviewed-by: Joey Gouly <joey.gouly at arm.com>
Signed-off-by: Steven Price <steven.price at arm.com>
---
Changes since v5:
 * Upper GPRS can be set as part of a HOST_CALL return, so fix up the
   test to allow them.
---
 arch/arm64/kvm/guest.c | 41 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 1c87699fd886..e62a4feddff3 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -73,6 +73,25 @@ static u64 core_reg_offset_from_id(u64 id)
 	return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE);
 }
 
+static bool kvm_realm_validate_core_reg(u64 off)
+{
+	/*
+	 * Note that GPRs can only sometimes be controlled by the VMM.
+	 * For PSCI only X0-X6 are used, higher registers are ignored (restored
+	 * from the REC).
+	 * For HOST_CALL all of X0-X30 are copied to the RsiHostCall structure.
+	 * For emulated MMIO X0 is always used.
+	 * PC can only be set before the realm is activated.
+	 */
+	switch (off) {
+	case KVM_REG_ARM_CORE_REG(regs.regs[0]) ...
+	     KVM_REG_ARM_CORE_REG(regs.regs[30]):
+	case KVM_REG_ARM_CORE_REG(regs.pc):
+		return true;
+	}
+	return false;
+}
+
 static int core_reg_size_from_offset(const struct kvm_vcpu *vcpu, u64 off)
 {
 	int size;
@@ -716,12 +735,34 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	return kvm_arm_sys_reg_get_reg(vcpu, reg);
 }
 
+/*
+ * The RMI ABI only enables setting some GPRs and PC. The selection of GPRs
+ * that are available depends on the Realm state and the reason for the last
+ * exit.  All other registers are reset to architectural or otherwise defined
+ * reset values by the RMM, except for a few configuration fields that
+ * correspond to Realm parameters.
+ */
+static bool validate_realm_set_reg(struct kvm_vcpu *vcpu,
+				   const struct kvm_one_reg *reg)
+{
+	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE) {
+		u64 off = core_reg_offset_from_id(reg->id);
+
+		return kvm_realm_validate_core_reg(off);
+	}
+
+	return false;
+}
+
 int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 {
 	/* We currently use nothing arch-specific in upper 32 bits */
 	if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
 		return -EINVAL;
 
+	if (kvm_is_realm(vcpu->kvm) && !validate_realm_set_reg(vcpu, reg))
+		return -EINVAL;
+
 	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
 	case KVM_REG_ARM_CORE:	return set_core_reg(vcpu, reg);
 	case KVM_REG_ARM_FW:
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:11:04 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:11:04 +0000
Subject: [PATCH v12 27/46] KVM: arm64: Handle Realm PSCI requests
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-28-steven.price@arm.com>

The RMM needs to be informed of the target REC when a PSCI call is made
with an MPIDR argument. Expose an ioctl to the userspace in case the PSCI
is handled by it.

Co-developed-by: Suzuki K Poulose <suzuki.poulose at arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose at arm.com>
Signed-off-by: Steven Price <steven.price at arm.com>
Reviewed-by: Gavin Shan <gshan at redhat.com>
---
Changes since v11:
 * RMM->RMI renaming.
Changes since v6:
 * Use vcpu_is_rec() rather than kvm_is_realm(vcpu->kvm).
 * Minor renaming/formatting fixes.
---
 arch/arm64/include/asm/kvm_rmi.h |  3 +++
 arch/arm64/kvm/arm.c             | 25 +++++++++++++++++++++++++
 arch/arm64/kvm/psci.c            | 30 ++++++++++++++++++++++++++++++
 arch/arm64/kvm/rmi.c             | 14 ++++++++++++++
 4 files changed, 72 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_rmi.h
index bfe6428eaf16..77da297ca09d 100644
--- a/arch/arm64/include/asm/kvm_rmi.h
+++ b/arch/arm64/include/asm/kvm_rmi.h
@@ -118,6 +118,9 @@ int realm_map_non_secure(struct realm *realm,
 			 kvm_pfn_t pfn,
 			 unsigned long size,
 			 struct kvm_mmu_memory_cache *memcache);
+int realm_psci_complete(struct kvm_vcpu *source,
+			struct kvm_vcpu *target,
+			unsigned long status);
 
 static inline bool kvm_realm_is_private_address(struct realm *realm,
 						unsigned long addr)
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 06070bc47ee3..fb04d032504e 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -1797,6 +1797,22 @@ static int kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
 	return __kvm_arm_vcpu_set_events(vcpu, events);
 }
 
+static int kvm_arm_vcpu_rmi_psci_complete(struct kvm_vcpu *vcpu,
+					  struct kvm_arm_rmi_psci_complete *arg)
+{
+	struct kvm_vcpu *target = kvm_mpidr_to_vcpu(vcpu->kvm, arg->target_mpidr);
+
+	if (!target)
+		return -EINVAL;
+
+	/*
+	 * RMM v1.0 only supports PSCI_RET_SUCCESS or PSCI_RET_DENIED
+	 * for the status. But, let us leave it to the RMM to filter
+	 * for making this future proof.
+	 */
+	return realm_psci_complete(vcpu, target, arg->psci_status);
+}
+
 long kvm_arch_vcpu_ioctl(struct file *filp,
 			 unsigned int ioctl, unsigned long arg)
 {
@@ -1925,6 +1941,15 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 
 		return kvm_arm_vcpu_finalize(vcpu, what);
 	}
+	case KVM_ARM_VCPU_RMI_PSCI_COMPLETE: {
+		struct kvm_arm_rmi_psci_complete req;
+
+		if (!vcpu_is_rec(vcpu))
+			return -EPERM;
+		if (copy_from_user(&req, argp, sizeof(req)))
+			return -EFAULT;
+		return kvm_arm_vcpu_rmi_psci_complete(vcpu, &req);
+	}
 	default:
 		r = -EINVAL;
 	}
diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
index 3b5dbe9a0a0e..a68f3c1878a5 100644
--- a/arch/arm64/kvm/psci.c
+++ b/arch/arm64/kvm/psci.c
@@ -103,6 +103,12 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
 
 	reset_state->reset = true;
 	kvm_make_request(KVM_REQ_VCPU_RESET, vcpu);
+	/*
+	 * Make sure we issue PSCI_COMPLETE before the VCPU can be
+	 * scheduled.
+	 */
+	if (vcpu_is_rec(vcpu))
+		realm_psci_complete(source_vcpu, vcpu, PSCI_RET_SUCCESS);
 
 	/*
 	 * Make sure the reset request is observed if the RUNNABLE mp_state is
@@ -115,6 +121,11 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
 
 out_unlock:
 	spin_unlock(&vcpu->arch.mp_state_lock);
+	if (vcpu_is_rec(vcpu) && ret != PSCI_RET_SUCCESS) {
+		realm_psci_complete(source_vcpu, vcpu,
+				    ret == PSCI_RET_ALREADY_ON ?
+				    PSCI_RET_SUCCESS : PSCI_RET_DENIED);
+	}
 	return ret;
 }
 
@@ -142,6 +153,25 @@ static unsigned long kvm_psci_vcpu_affinity_info(struct kvm_vcpu *vcpu)
 	/* Ignore other bits of target affinity */
 	target_affinity &= target_affinity_mask;
 
+	if (vcpu_is_rec(vcpu)) {
+		struct kvm_vcpu *target_vcpu;
+
+		/* RMM supports only zero affinity level */
+		if (lowest_affinity_level != 0)
+			return PSCI_RET_INVALID_PARAMS;
+
+		target_vcpu = kvm_mpidr_to_vcpu(kvm, target_affinity);
+		if (!target_vcpu)
+			return PSCI_RET_INVALID_PARAMS;
+
+		/*
+		 * Provide the references of the source and target RECs to the
+		 * RMM so that the RMM can complete the PSCI request.
+		 */
+		realm_psci_complete(vcpu, target_vcpu, PSCI_RET_SUCCESS);
+		return PSCI_RET_SUCCESS;
+	}
+
 	/*
 	 * If one or more VCPU matching target affinity are running
 	 * then ON else OFF
diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
index de1a66df7a5e..5f50566c701d 100644
--- a/arch/arm64/kvm/rmi.c
+++ b/arch/arm64/kvm/rmi.c
@@ -164,6 +164,20 @@ static void free_rtt(phys_addr_t phys)
 	kvm_account_pgtable_pages(phys_to_virt(phys), -1);
 }
 
+int realm_psci_complete(struct kvm_vcpu *source, struct kvm_vcpu *target,
+			unsigned long status)
+{
+	int ret;
+
+	ret = rmi_psci_complete(virt_to_phys(source->arch.rec.rec_page),
+				virt_to_phys(target->arch.rec.rec_page),
+				status);
+	if (ret)
+		return -EINVAL;
+
+	return 0;
+}
+
 static int realm_rtt_create(struct realm *realm,
 			    unsigned long addr,
 			    int level,
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:11:05 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:11:05 +0000
Subject: [PATCH v12 28/46] KVM: arm64: WARN on injected undef exceptions
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-29-steven.price@arm.com>

The RMM doesn't allow injection of a undefined exception into a realm
guest. Add a WARN to catch if this ever happens.

Signed-off-by: Steven Price <steven.price at arm.com>
Reviewed-by: Gavin Shan <gshan at redhat.com>
---
Changes since v6:
 * if (x) WARN(1, ...) makes no sense, just WARN(x, ...)!
---
 arch/arm64/kvm/inject_fault.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
index 5e00f7a69bcc..22bd9258665b 100644
--- a/arch/arm64/kvm/inject_fault.c
+++ b/arch/arm64/kvm/inject_fault.c
@@ -289,6 +289,7 @@ void kvm_inject_size_fault(struct kvm_vcpu *vcpu)
  */
 void kvm_inject_undefined(struct kvm_vcpu *vcpu)
 {
+	WARN(vcpu_is_rec(vcpu), "Unexpected undefined exception injection to REC");
 	if (vcpu_el1_is_32bit(vcpu))
 		inject_undef32(vcpu);
 	else
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:11:06 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:11:06 +0000
Subject: [PATCH v12 29/46] arm64: Don't expose stolen time for realm guests
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-30-steven.price@arm.com>

It doesn't make much sense as a realm guest wouldn't want to trust the
host. It will also need some extra work to ensure that KVM will only
attempt to write into a shared memory region. So for now just disable
it.

Reviewed-by: Suzuki K Poulose <suzuki.poulose at arm.com>
Reviewed-by: Gavin Shan <gshan at redhat.com>
Signed-off-by: Steven Price <steven.price at arm.com>
---
Changes since v7:
 * Update the documentation to add a note about stolen time being
   unavailable in a realm.
---
 Documentation/virt/kvm/api.rst | 3 +++
 arch/arm64/kvm/arm.c           | 5 ++++-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index d7ebf42933e8..6788a8242fc7 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -9101,6 +9101,9 @@ is supported, than the other should as well and vice versa.  For arm64
 see Documentation/virt/kvm/devices/vcpu.rst "KVM_ARM_VCPU_PVTIME_CTRL".
 For x86 see Documentation/virt/kvm/x86/msr.rst "MSR_KVM_STEAL_TIME".
 
+Note that steal time accounting is not available when a guest is running
+within a Arm CCA realm (machine type KVM_VM_TYPE_ARM_REALM).
+
 8.25 KVM_CAP_S390_DIAG318
 -------------------------
 
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index fb04d032504e..403f9119543e 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -423,7 +423,10 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 		r = system_supports_mte();
 		break;
 	case KVM_CAP_STEAL_TIME:
-		r = kvm_arm_pvtime_supported();
+		if (kvm_is_realm(kvm))
+			r = 0;
+		else
+			r = kvm_arm_pvtime_supported();
 		break;
 	case KVM_CAP_ARM_EL1_32BIT:
 		r = cpus_have_final_cap(ARM64_HAS_32BIT_EL1);
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:11:07 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:11:07 +0000
Subject: [PATCH v12 30/46] arm64: RMI: allow userspace to inject aborts
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-31-steven.price@arm.com>

From: Joey Gouly <joey.gouly at arm.com>

Extend KVM_SET_VCPU_EVENTS to support realms, where KVM cannot set the
system registers, and the RMM must perform it on next REC entry.

Signed-off-by: Joey Gouly <joey.gouly at arm.com>
Signed-off-by: Steven Price <steven.price at arm.com>
Reviewed-by: Gavin Shan <gshan at redhat.com>
---
 Documentation/virt/kvm/api.rst |  2 ++
 arch/arm64/kvm/guest.c         | 24 ++++++++++++++++++++++++
 2 files changed, 26 insertions(+)

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 6788a8242fc7..609bf0981f6e 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -1310,6 +1310,8 @@ User space may need to inject several types of events to the guest.
 Set the pending SError exception state for this VCPU. It is not possible to
 'cancel' an Serror that has been made pending.
 
+User space cannot inject SErrors into Realms.
+
 If the guest performed an access to I/O memory which could not be handled by
 userspace, for example because of missing instruction syndrome decode
 information or because there is no device mapped at the accessed IPA, then
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index e62a4feddff3..d9f392cb2759 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -827,6 +827,30 @@ int __kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
 	u64 esr = events->exception.serror_esr;
 	int ret = 0;
 
+	if (vcpu_is_rec(vcpu)) {
+		/* Cannot inject SError into a Realm. */
+		if (serror_pending)
+			return -EINVAL;
+
+		/*
+		 * If a data abort is pending, set the flag and let the RMM
+		 * inject an SEA when the REC is scheduled to be run.
+		 */
+		if (ext_dabt_pending) {
+			/*
+			 * Can only inject SEA into a Realm if the previous exit
+			 * was due to a data abort of an Unprotected IPA.
+			 */
+			if (!(vcpu->arch.rec.run->enter.flags & REC_ENTER_FLAG_EMULATED_MMIO))
+				return -EINVAL;
+
+			vcpu->arch.rec.run->enter.flags &= ~REC_ENTER_FLAG_EMULATED_MMIO;
+			vcpu->arch.rec.run->enter.flags |= REC_ENTER_FLAG_INJECT_SEA;
+		}
+
+		return 0;
+	}
+
 	/*
 	 * Immediately commit the pending SEA to the vCPU's architectural
 	 * state which is necessary since we do not return a pending SEA
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:11:08 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:11:08 +0000
Subject: [PATCH v12 31/46] arm64: RMI: support RSI_HOST_CALL
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-32-steven.price@arm.com>

From: Joey Gouly <joey.gouly at arm.com>

Forward RSI_HOST_CALLS to KVM's HVC handler.

Signed-off-by: Joey Gouly <joey.gouly at arm.com>
Signed-off-by: Steven Price <steven.price at arm.com>
Reviewed-by: Gavin Shan <gshan at redhat.com>
---
Changes since v7:
 * Avoid turning a negative return from kvm_smccc_call_handler() into a
   error response to the guest. Instead propogate the error back to user
   space.
Changes since v4:
 * Setting GPRS is now done by kvm_rec_enter() rather than
   rec_exit_host_call() (see previous patch - arm64: RME: Handle realm
   enter/exit). This fixes a bug where the registers set by user space
   were being ignored.
---
 arch/arm64/kvm/rmi-exit.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/arch/arm64/kvm/rmi-exit.c b/arch/arm64/kvm/rmi-exit.c
index b4843f094615..7eff6967530c 100644
--- a/arch/arm64/kvm/rmi-exit.c
+++ b/arch/arm64/kvm/rmi-exit.c
@@ -116,6 +116,19 @@ static int rec_exit_ripas_change(struct kvm_vcpu *vcpu)
 	return -EFAULT;
 }
 
+static int rec_exit_host_call(struct kvm_vcpu *vcpu)
+{
+	int i;
+	struct realm_rec *rec = &vcpu->arch.rec;
+
+	vcpu->stat.hvc_exit_stat++;
+
+	for (i = 0; i < REC_RUN_GPRS; i++)
+		vcpu_set_reg(vcpu, i, rec->run->exit.gprs[i]);
+
+	return kvm_smccc_call_handler(vcpu);
+}
+
 static void update_arch_timer_irq_lines(struct kvm_vcpu *vcpu)
 {
 	struct realm_rec *rec = &vcpu->arch.rec;
@@ -183,6 +196,8 @@ int handle_rec_exit(struct kvm_vcpu *vcpu, int rec_run_ret)
 		return rec_exit_psci(vcpu);
 	case RMI_EXIT_RIPAS_CHANGE:
 		return rec_exit_ripas_change(vcpu);
+	case RMI_EXIT_HOST_CALL:
+		return rec_exit_host_call(vcpu);
 	}
 
 	kvm_pr_unimpl("Unsupported exit reason: %u\n",
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:11:09 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:11:09 +0000
Subject: [PATCH v12 32/46] arm64: RMI: Allow checking SVE on VM instance
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-33-steven.price@arm.com>

From: Suzuki K Poulose <suzuki.poulose at arm.com>

Given we have different types of VMs supported, check the
support for SVE for the given instance of the VM to accurately
report the status.

Signed-off-by: Suzuki K Poulose <suzuki.poulose at arm.com>
Signed-off-by: Steven Price <steven.price at arm.com>
Reviewed-by: Gavin Shan <gshan at redhat.com>
Reviewed-by: Joey Gouly <joey.gouly at arm.com>
---
Changes since v10:
 * RME->RMI renaming.
 * Adapt to move CAP check to kvm_realm_ext_allowed().
---
 arch/arm64/include/asm/kvm_rmi.h |  2 ++
 arch/arm64/kvm/arm.c             |  2 ++
 arch/arm64/kvm/rmi.c             | 10 ++++++++++
 3 files changed, 14 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_rmi.h
index 77da297ca09d..82280c138935 100644
--- a/arch/arm64/include/asm/kvm_rmi.h
+++ b/arch/arm64/include/asm/kvm_rmi.h
@@ -89,6 +89,8 @@ void kvm_init_rmi(void);
 u32 kvm_realm_ipa_limit(void);
 u32 kvm_realm_vgic_nr_lr(void);
 
+bool kvm_rmi_supports_sve(void);
+
 int kvm_init_realm_vm(struct kvm *kvm);
 int kvm_activate_realm(struct kvm *kvm);
 void kvm_destroy_realm(struct kvm *kvm);
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 403f9119543e..f8255de92902 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -342,6 +342,8 @@ static bool kvm_realm_ext_allowed(long ext)
 	case KVM_CAP_ARM_PTRAUTH_GENERIC:
 	case KVM_CAP_ARM_RMI:
 		return true;
+	case KVM_CAP_ARM_SVE:
+		return kvm_rmi_supports_sve();
 	}
 	return false;
 }
diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
index 5f50566c701d..7ef5d7f48d0b 100644
--- a/arch/arm64/kvm/rmi.c
+++ b/arch/arm64/kvm/rmi.c
@@ -33,6 +33,16 @@ static inline unsigned long rmi_rtt_level_mapsize(int level)
 	return (1UL << RMM_RTT_LEVEL_SHIFT(level));
 }
 
+static bool rmi_has_feature(unsigned long feature)
+{
+	return !!u64_get_bits(rmm_feat_reg0, feature);
+}
+
+bool kvm_rmi_supports_sve(void)
+{
+	return rmi_has_feature(RMI_FEATURE_REGISTER_0_SVE_EN);
+}
+
 static int rmi_check_version(void)
 {
 	struct arm_smccc_res res;
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:11:10 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:11:10 +0000
Subject: [PATCH v12 33/46] arm64: RMI: Always use 4k pages for realms
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-34-steven.price@arm.com>

Guest_memfd doesn't yet natively support huge pages, and there are
currently difficulties for a VMM to manage huge pages efficiently so for
now always split up mappings to PTE (4k).

The two issues that need progressing before supporting huge pages for
realms are:

 1. guest_memfd needs to be able to allocate from an appropriate
    allocator which can provide huge pages.

 2. The VMM needs to be able to repurpose private memory for a shared
    mapping when the guest VM requests memory is transitioned. Because
    this can happen at a 4k granularity it isn't possible to
    free/reallocate while huge pages are in use. Allowing the VMM to
    mmap() the shared portion of a huge page would allow the huge page
    to be recreated when the memory is unshared and made protected again.

These two issues are not specific to realms and don't affect the realm
API, so for now just break everything down to 4k pages in the RMM
controlled stage 2. Future work can add huge page support without
changing the uAPI.

Signed-off-by: Steven Price <steven.price at arm.com>
Reviewed-by: Gavin Shan <gshan at redhat.com>
Reviewed-by: Suzuki K Poulose <suzuki.poulose at arm.com>
---
Changes since v7:
 * Rewritten commit message
---
 arch/arm64/kvm/mmu.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index 860c42aabcf0..c30d7be27361 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -1762,11 +1762,14 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 	write_fault = kvm_is_write_fault(vcpu);
 
 	/*
-	 * Realms cannot map protected pages read-only
+	 * Realms cannot map protected pages read-only, also force PTE mappings
+	 * for Realms.
 	 * FIXME: It should be possible to map unprotected pages read-only
 	 */
-	if (vcpu_is_rec(vcpu))
+	if (vcpu_is_rec(vcpu)) {
 		write_fault = true;
+		force_pte = true;
+	}
 
 	exec_fault = kvm_vcpu_trap_is_exec_fault(vcpu);
 	VM_WARN_ON_ONCE(write_fault && exec_fault);
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:11:11 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:11:11 +0000
Subject: [PATCH v12 34/46] arm64: RMI: Prevent Device mappings for Realms
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-35-steven.price@arm.com>

Physical device assignment is not supported by RMM v1.0, so it
doesn't make much sense to allow device mappings within the realm.
Prevent them when the guest is a realm.

Signed-off-by: Steven Price <steven.price at arm.com>
---
Changes from v6:
 * Fix the check in user_mem_abort() to prevent all pages that are not
   guest_memfd() from being mapped into the protected half of the IPA.
Changes from v5:
 * Also prevent accesses in user_mem_abort()
---
 arch/arm64/kvm/mmu.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index c30d7be27361..e71ef41fb6b1 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -1221,6 +1221,10 @@ int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,
 	if (is_protected_kvm_enabled())
 		return -EPERM;
 
+	/* We don't support mapping special pages into a Realm */
+	if (kvm_is_realm(kvm))
+		return -EPERM;
+
 	size += offset_in_page(guest_ipa);
 	guest_ipa &= PAGE_MASK;
 
@@ -1955,6 +1959,15 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 		return ret;
 	}
 
+	/*
+	 * For now we shouldn't be hitting protected addresses because they are
+	 * handled in private_memslot_fault(). In the future this check may be
+	 * relaxed to support e.g. protected devices.
+	 */
+	if (vcpu_is_rec(vcpu) &&
+	    kvm_gpa_from_fault(kvm, fault_ipa) == fault_ipa)
+		return -EINVAL;
+
 	if (nested)
 		adjust_nested_fault_perms(nested, &prot, &writable);
 
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:11:12 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:11:12 +0000
Subject: [PATCH v12 35/46] HACK: Restore per-CPU cpu_armpmu pointer
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-36-steven.price@arm.com>

Commit fa9d27773873 ("perf: arm_pmu: Kill last use of per-CPU cpu_armpmu
pointer") removed the per-CPU cpu_armpmu. Rather than refactoring the
code to deal with this just reintroduce it. The CCA PMU code will be
changing when switching to the RMM v2.0 ABI and will need completely
reworking.

Signed-off-by: Steven Price <steven.price at arm.com>
---
 drivers/perf/arm_pmu.c       | 5 +++++
 include/linux/perf/arm_pmu.h | 2 ++
 2 files changed, 7 insertions(+)

diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
index 973a027d9063..c94494db06f5 100644
--- a/drivers/perf/arm_pmu.c
+++ b/drivers/perf/arm_pmu.c
@@ -104,6 +104,7 @@ static const struct pmu_irq_ops percpu_pmunmi_ops = {
 	.free_pmuirq = armpmu_free_percpu_pmunmi
 };
 
+DEFINE_PER_CPU(struct arm_pmu *, cpu_armpmu);
 static DEFINE_PER_CPU(int, cpu_irq);
 static DEFINE_PER_CPU(const struct pmu_irq_ops *, cpu_irq_ops);
 
@@ -724,6 +725,8 @@ static int arm_perf_starting_cpu(unsigned int cpu, struct hlist_node *node)
 	if (pmu->reset)
 		pmu->reset(pmu);
 
+	per_cpu(cpu_armpmu, cpu) = pmu;
+
 	irq = armpmu_get_cpu_irq(pmu, cpu);
 	if (irq)
 		per_cpu(cpu_irq_ops, cpu)->enable_pmuirq(irq);
@@ -743,6 +746,8 @@ static int arm_perf_teardown_cpu(unsigned int cpu, struct hlist_node *node)
 	if (irq)
 		per_cpu(cpu_irq_ops, cpu)->disable_pmuirq(irq);
 
+	per_cpu(cpu_armpmu, cpu) = NULL;
+
 	return 0;
 }
 
diff --git a/include/linux/perf/arm_pmu.h b/include/linux/perf/arm_pmu.h
index 52b37f7bdbf9..e1be4a6c8b43 100644
--- a/include/linux/perf/arm_pmu.h
+++ b/include/linux/perf/arm_pmu.h
@@ -133,6 +133,8 @@ struct arm_pmu {
 
 #define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu))
 
+DECLARE_PER_CPU(struct arm_pmu *, cpu_armpmu);
+
 u64 armpmu_event_update(struct perf_event *event);
 
 int armpmu_event_set_period(struct perf_event *event);
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:11:13 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:11:13 +0000
Subject: [PATCH v12 36/46] arm_pmu: Provide a mechanism for disabling the physical IRQ
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-37-steven.price@arm.com>

Arm CCA assigns the physical PMU device to the guest running in realm
world, however the IRQs are routed via the host. To enter a realm guest
while a PMU IRQ is pending it is necessary to block the physical IRQ to
prevent an immediate exit. Provide a mechanism in the PMU driver for KVM
to control the physical IRQ.

Signed-off-by: Steven Price <steven.price at arm.com>
Reviewed-by: Gavin Shan <gshan at redhat.com>
---
v3: Add a dummy function for the !CONFIG_ARM_PMU case.
---
 drivers/perf/arm_pmu.c       | 15 +++++++++++++++
 include/linux/perf/arm_pmu.h |  5 +++++
 2 files changed, 20 insertions(+)

diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
index c94494db06f5..6705c61c73c2 100644
--- a/drivers/perf/arm_pmu.c
+++ b/drivers/perf/arm_pmu.c
@@ -751,6 +751,21 @@ static int arm_perf_teardown_cpu(unsigned int cpu, struct hlist_node *node)
 	return 0;
 }
 
+void arm_pmu_set_phys_irq(bool enable)
+{
+	int cpu = get_cpu();
+	struct arm_pmu *pmu = per_cpu(cpu_armpmu, cpu);
+	int irq;
+
+	irq = armpmu_get_cpu_irq(pmu, cpu);
+	if (irq && !enable)
+		per_cpu(cpu_irq_ops, cpu)->disable_pmuirq(irq);
+	else if (irq && enable)
+		per_cpu(cpu_irq_ops, cpu)->enable_pmuirq(irq);
+
+	put_cpu();
+}
+
 #ifdef CONFIG_CPU_PM
 static void cpu_pm_pmu_setup(struct arm_pmu *armpmu, unsigned long cmd)
 {
diff --git a/include/linux/perf/arm_pmu.h b/include/linux/perf/arm_pmu.h
index e1be4a6c8b43..de49f92f6ebf 100644
--- a/include/linux/perf/arm_pmu.h
+++ b/include/linux/perf/arm_pmu.h
@@ -186,6 +186,7 @@ void kvm_host_pmu_init(struct arm_pmu *pmu);
 #endif
 
 bool arm_pmu_irq_is_nmi(void);
+void arm_pmu_set_phys_irq(bool enable);
 
 /* Internal functions only for core arm_pmu code */
 struct arm_pmu *armpmu_alloc(void);
@@ -196,6 +197,10 @@ void armpmu_free_irq(struct arm_pmu * __percpu *armpmu, int irq, int cpu);
 
 #define ARMV8_PMU_PDEV_NAME "armv8-pmu"
 
+#else /* CONFIG_ARM_PMU */
+
+static inline void arm_pmu_set_phys_irq(bool enable) {}
+
 #endif /* CONFIG_ARM_PMU */
 
 #define ARMV8_SPE_PDEV_NAME "arm,spe-v1"
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:11:14 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:11:14 +0000
Subject: [PATCH v12 37/46] arm64: RMI: Enable PMU support with a realm guest
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-38-steven.price@arm.com>

Use the PMU registers from the RmiRecExit structure to identify when an
overflow interrupt is due and inject it into the guest. Also hook up the
configuration option for enabling the PMU within the guest.

When entering a realm guest with a PMU interrupt pending, it is
necessary to disable the physical interrupt. Otherwise when the RMM
restores the PMU state the physical interrupt will trigger causing an
immediate exit back to the host. The guest is expected to acknowledge
the interrupt causing a host exit (to update the GIC state) which gives
the opportunity to re-enable the physical interrupt before the next PMU
event.

Number of PMU counters is configured by the VMM by writing to PMCR.N.

Reviewed-by: Gavin Shan <gshan at redhat.com>
Signed-off-by: Steven Price <steven.price at arm.com>
---
Changes since v2:
 * Add a macro kvm_pmu_get_irq_level() to avoid compile issues when PMU
   support is disabled.
---
 arch/arm64/kvm/arm.c      | 11 +++++++++++
 arch/arm64/kvm/guest.c    |  7 +++++++
 arch/arm64/kvm/pmu-emul.c |  3 +++
 arch/arm64/kvm/rmi.c      |  8 ++++++++
 arch/arm64/kvm/sys_regs.c |  5 +++--
 include/kvm/arm_pmu.h     |  4 ++++
 6 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index f8255de92902..b2e1401cc223 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -14,6 +14,7 @@
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
 #include <linux/mman.h>
+#include <linux/perf/arm_pmu.h>
 #include <linux/sched.h>
 #include <linux/kvm.h>
 #include <linux/kvm_irqfd.h>
@@ -1264,6 +1265,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 	run->exit_reason = KVM_EXIT_UNKNOWN;
 	run->flags = 0;
 	while (ret > 0) {
+		bool pmu_stopped = false;
+
 		/*
 		 * Check conditions before entering the guest
 		 */
@@ -1289,6 +1292,11 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 		if (kvm_vcpu_has_pmu(vcpu))
 			kvm_pmu_flush_hwstate(vcpu);
 
+		if (vcpu_is_rec(vcpu) && kvm_pmu_get_irq_level(vcpu)) {
+			pmu_stopped = true;
+			arm_pmu_set_phys_irq(false);
+		}
+
 		local_irq_disable();
 
 		kvm_vgic_flush_hwstate(vcpu);
@@ -1397,6 +1405,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 
 		preempt_enable();
 
+		if (pmu_stopped)
+			arm_pmu_set_phys_irq(true);
+
 		/*
 		 * The ARMv8 architecture doesn't give the hypervisor
 		 * a mechanism to prevent a guest from dropping to AArch32 EL0
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index d9f392cb2759..14302130d341 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -735,6 +735,8 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	return kvm_arm_sys_reg_get_reg(vcpu, reg);
 }
 
+#define KVM_REG_ARM_PMCR_EL0		ARM64_SYS_REG(3, 3, 9, 12, 0)
+
 /*
  * The RMI ABI only enables setting some GPRs and PC. The selection of GPRs
  * that are available depends on the Realm state and the reason for the last
@@ -749,6 +751,11 @@ static bool validate_realm_set_reg(struct kvm_vcpu *vcpu,
 		u64 off = core_reg_offset_from_id(reg->id);
 
 		return kvm_realm_validate_core_reg(off);
+	} else {
+		switch (reg->id) {
+		case KVM_REG_ARM_PMCR_EL0:
+			return true;
+		}
 	}
 
 	return false;
diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c
index b03dbda7f1ab..41331f883780 100644
--- a/arch/arm64/kvm/pmu-emul.c
+++ b/arch/arm64/kvm/pmu-emul.c
@@ -374,6 +374,9 @@ static bool kvm_pmu_overflow_status(struct kvm_vcpu *vcpu)
 {
 	u64 reg = __vcpu_sys_reg(vcpu, PMOVSSET_EL0);
 
+	if (vcpu_is_rec(vcpu))
+		return vcpu->arch.rec.run->exit.pmu_ovf_status;
+
 	reg &= __vcpu_sys_reg(vcpu, PMINTENSET_EL1);
 
 	/*
diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
index 7ef5d7f48d0b..1d26fd893caf 100644
--- a/arch/arm64/kvm/rmi.c
+++ b/arch/arm64/kvm/rmi.c
@@ -582,6 +582,11 @@ static int realm_create_rd(struct kvm *kvm)
 	params->rtt_base = kvm->arch.mmu.pgd_phys;
 	params->vmid = realm->vmid;
 
+	if (kvm->arch.arm_pmu) {
+		params->pmu_num_ctrs = kvm->arch.nr_pmu_counters;
+		params->flags |= RMI_REALM_PARAM_FLAG_PMU;
+	}
+
 	params_phys = virt_to_phys(params);
 
 	if (rmi_realm_create(rd_phys, params_phys)) {
@@ -1371,6 +1376,9 @@ static int kvm_create_rec(struct kvm_vcpu *vcpu)
 	if (!vcpu_has_feature(vcpu, KVM_ARM_VCPU_PSCI_0_2))
 		return -EINVAL;
 
+	if (vcpu->kvm->arch.arm_pmu && !kvm_vcpu_has_pmu(vcpu))
+		return -EINVAL;
+
 	BUILD_BUG_ON(sizeof(*params) > PAGE_SIZE);
 	BUILD_BUG_ON(sizeof(*rec->run) > PAGE_SIZE);
 
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index c8fd7c6a12a1..af641939a033 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1360,8 +1360,9 @@ static int set_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
 	 * implements. Ignore this error to maintain compatibility
 	 * with the existing KVM behavior.
 	 */
-	if (!kvm_vm_has_ran_once(kvm) &&
-	    !vcpu_has_nv(vcpu)	      &&
+	if (!kvm_vm_has_ran_once(kvm)  &&
+	    !kvm_realm_is_created(kvm) &&
+	    !vcpu_has_nv(vcpu)	       &&
 	    new_n <= kvm_arm_pmu_get_max_counters(kvm))
 		kvm->arch.nr_pmu_counters = new_n;
 
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 96754b51b411..da32f1bd9f8c 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -70,6 +70,8 @@ void kvm_vcpu_pmu_restore_guest(struct kvm_vcpu *vcpu);
 void kvm_vcpu_pmu_restore_host(struct kvm_vcpu *vcpu);
 void kvm_vcpu_pmu_resync_el0(void);
 
+#define kvm_pmu_get_irq_level(vcpu) ((vcpu)->arch.pmu.irq_level)
+
 #define kvm_vcpu_has_pmu(vcpu)					\
 	(vcpu_has_feature(vcpu, KVM_ARM_VCPU_PMU_V3))
 
@@ -157,6 +159,8 @@ static inline u64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmceid1)
 	return 0;
 }
 
+#define kvm_pmu_get_irq_level(vcpu) (false)
+
 #define kvm_vcpu_has_pmu(vcpu)		({ false; })
 static inline void kvm_pmu_update_vcpu_events(struct kvm_vcpu *vcpu) {}
 static inline void kvm_vcpu_pmu_restore_guest(struct kvm_vcpu *vcpu) {}
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:11:15 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:11:15 +0000
Subject: [PATCH v12 38/46] arm64: RMI: Propagate number of breakpoints and watchpoints to userspace
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-39-steven.price@arm.com>

From: Jean-Philippe Brucker <jean-philippe at linaro.org>

The RMM describes the maximum number of BPs/WPs available to the guest
in the Feature Register 0. Propagate those numbers into ID_AA64DFR0_EL1,
which is visible to userspace. A VMM needs this information in order to
set up realm parameters.

Signed-off-by: Jean-Philippe Brucker <jean-philippe at linaro.org>
Signed-off-by: Steven Price <steven.price at arm.com>
Reviewed-by: Gavin Shan <gshan at redhat.com>
Reviewed-by: Suzuki K Poulose <suzuki.poulose at arm.com>
Reviewed-by: Joey Gouly <joey.gouly at arm.com>
---
 arch/arm64/include/asm/kvm_rmi.h |  2 ++
 arch/arm64/kvm/rmi.c             | 22 ++++++++++++++++++++++
 arch/arm64/kvm/sys_regs.c        |  2 +-
 3 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_rmi.h
index 82280c138935..f36d3c845836 100644
--- a/arch/arm64/include/asm/kvm_rmi.h
+++ b/arch/arm64/include/asm/kvm_rmi.h
@@ -89,6 +89,8 @@ void kvm_init_rmi(void);
 u32 kvm_realm_ipa_limit(void);
 u32 kvm_realm_vgic_nr_lr(void);
 
+u64 kvm_realm_reset_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val);
+
 bool kvm_rmi_supports_sve(void);
 
 int kvm_init_realm_vm(struct kvm *kvm);
diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
index 1d26fd893caf..1c5257636ef1 100644
--- a/arch/arm64/kvm/rmi.c
+++ b/arch/arm64/kvm/rmi.c
@@ -92,6 +92,28 @@ u32 kvm_realm_vgic_nr_lr(void)
 	return u64_get_bits(rmm_feat_reg0, RMI_FEATURE_REGISTER_0_GICV3_NUM_LRS);
 }
 
+u64 kvm_realm_reset_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val)
+{
+	u32 bps = u64_get_bits(rmm_feat_reg0, RMI_FEATURE_REGISTER_0_NUM_BPS);
+	u32 wps = u64_get_bits(rmm_feat_reg0, RMI_FEATURE_REGISTER_0_NUM_WPS);
+	u32 ctx_cmps;
+
+	if (!kvm_is_realm(vcpu->kvm))
+		return val;
+
+	/* Ensure CTX_CMPs is still valid */
+	ctx_cmps = FIELD_GET(ID_AA64DFR0_EL1_CTX_CMPs, val);
+	ctx_cmps = min(bps, ctx_cmps);
+
+	val &= ~(ID_AA64DFR0_EL1_BRPs_MASK | ID_AA64DFR0_EL1_WRPs_MASK |
+		 ID_AA64DFR0_EL1_CTX_CMPs);
+	val |= FIELD_PREP(ID_AA64DFR0_EL1_BRPs_MASK, bps) |
+	       FIELD_PREP(ID_AA64DFR0_EL1_WRPs_MASK, wps) |
+	       FIELD_PREP(ID_AA64DFR0_EL1_CTX_CMPs, ctx_cmps);
+
+	return val;
+}
+
 static int get_start_level(struct realm *realm)
 {
 	/*
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index af641939a033..70b51b5cdea8 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -2043,7 +2043,7 @@ static u64 sanitise_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val)
 	/* Hide BRBE from guests */
 	val &= ~ID_AA64DFR0_EL1_BRBE_MASK;
 
-	return val;
+	return kvm_realm_reset_id_aa64dfr0_el1(vcpu, val);
 }
 
 /*
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:11:17 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:11:17 +0000
Subject: [PATCH v12 40/46] arm64: RMI: Initialize PMCR.N with number counter supported by RMM
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-41-steven.price@arm.com>

From: Jean-Philippe Brucker <jean-philippe at linaro.org>

Provide an accurate number of available PMU counters to userspace when
setting up a Realm.

Signed-off-by: Jean-Philippe Brucker <jean-philippe at linaro.org>
Signed-off-by: Steven Price <steven.price at arm.com>
Reviewed-by: Gavin Shan <gshan at redhat.com>
Reviewed-by: Suzuki K Poulose <suzuki.poulose at arm.com>
Reviewed-by: Joey Gouly <joey.gouly at arm.com>
---
 arch/arm64/include/asm/kvm_rmi.h | 1 +
 arch/arm64/kvm/pmu-emul.c        | 3 +++
 arch/arm64/kvm/rmi.c             | 5 +++++
 3 files changed, 9 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_rmi.h
index f36d3c845836..39770d9e9fcb 100644
--- a/arch/arm64/include/asm/kvm_rmi.h
+++ b/arch/arm64/include/asm/kvm_rmi.h
@@ -88,6 +88,7 @@ struct realm_rec {
 void kvm_init_rmi(void);
 u32 kvm_realm_ipa_limit(void);
 u32 kvm_realm_vgic_nr_lr(void);
+u8 kvm_realm_max_pmu_counters(void);
 
 u64 kvm_realm_reset_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val);
 
diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c
index 41331f883780..6604aa982d02 100644
--- a/arch/arm64/kvm/pmu-emul.c
+++ b/arch/arm64/kvm/pmu-emul.c
@@ -1014,6 +1014,9 @@ u8 kvm_arm_pmu_get_max_counters(struct kvm *kvm)
 {
 	struct arm_pmu *arm_pmu = kvm->arch.arm_pmu;
 
+	if (kvm_is_realm(kvm))
+		return kvm_realm_max_pmu_counters();
+
 	/*
 	 * PMUv3 requires that all event counters are capable of counting any
 	 * event, though the same may not be true of non-PMUv3 hardware.
diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
index 5f3164539bfe..4e1c7bc2f52a 100644
--- a/arch/arm64/kvm/rmi.c
+++ b/arch/arm64/kvm/rmi.c
@@ -92,6 +92,11 @@ u32 kvm_realm_vgic_nr_lr(void)
 	return u64_get_bits(rmm_feat_reg0, RMI_FEATURE_REGISTER_0_GICV3_NUM_LRS);
 }
 
+u8 kvm_realm_max_pmu_counters(void)
+{
+	return u64_get_bits(rmm_feat_reg0, RMI_FEATURE_REGISTER_0_PMU_NUM_CTRS);
+}
+
 u64 kvm_realm_reset_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val)
 {
 	u32 bps = u64_get_bits(rmm_feat_reg0, RMI_FEATURE_REGISTER_0_NUM_BPS);
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:11:16 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:11:16 +0000
Subject: [PATCH v12 39/46] arm64: RMI: Set breakpoint parameters through SET_ONE_REG
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-40-steven.price@arm.com>

From: Jean-Philippe Brucker <jean-philippe at linaro.org>

Allow userspace to configure the number of breakpoints and watchpoints
of a Realm VM through KVM_SET_ONE_REG ID_AA64DFR0_EL1.

The KVM sys_reg handler checks the user value against the maximum value
given by RMM (arm64_check_features() gets it from the
read_sanitised_id_aa64dfr0_el1() reset handler).

Userspace discovers that it can write these fields by issuing a
KVM_ARM_GET_REG_WRITABLE_MASKS ioctl.

Signed-off-by: Jean-Philippe Brucker <jean-philippe at linaro.org>
Signed-off-by: Steven Price <steven.price at arm.com>
Reviewed-by: Gavin Shan <gshan at redhat.com>
Reviewed-by: Suzuki K Poulose <suzuki.poulose at arm.com>
---
 arch/arm64/kvm/guest.c    |  2 ++
 arch/arm64/kvm/rmi.c      |  3 +++
 arch/arm64/kvm/sys_regs.c | 17 +++++++++++------
 3 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 14302130d341..7cf919db1adc 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -736,6 +736,7 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 }
 
 #define KVM_REG_ARM_PMCR_EL0		ARM64_SYS_REG(3, 3, 9, 12, 0)
+#define KVM_REG_ARM_ID_AA64DFR0_EL1	ARM64_SYS_REG(3, 0, 0, 5, 0)
 
 /*
  * The RMI ABI only enables setting some GPRs and PC. The selection of GPRs
@@ -754,6 +755,7 @@ static bool validate_realm_set_reg(struct kvm_vcpu *vcpu,
 	} else {
 		switch (reg->id) {
 		case KVM_REG_ARM_PMCR_EL0:
+		case KVM_REG_ARM_ID_AA64DFR0_EL1:
 			return true;
 		}
 	}
diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
index 1c5257636ef1..5f3164539bfe 100644
--- a/arch/arm64/kvm/rmi.c
+++ b/arch/arm64/kvm/rmi.c
@@ -567,6 +567,7 @@ static int realm_create_rd(struct kvm *kvm)
 	void *rd = NULL;
 	phys_addr_t rd_phys, params_phys;
 	size_t pgd_size = kvm_pgtable_stage2_pgd_size(kvm->arch.mmu.vtcr);
+	u64 dfr0 = kvm_read_vm_id_reg(kvm, SYS_ID_AA64DFR0_EL1);
 	int i, r;
 	int rtt_num_start;
 
@@ -603,6 +604,8 @@ static int realm_create_rd(struct kvm *kvm)
 	params->rtt_num_start = rtt_num_start;
 	params->rtt_base = kvm->arch.mmu.pgd_phys;
 	params->vmid = realm->vmid;
+	params->num_bps = SYS_FIELD_GET(ID_AA64DFR0_EL1, BRPs, dfr0);
+	params->num_wps = SYS_FIELD_GET(ID_AA64DFR0_EL1, WRPs, dfr0);
 
 	if (kvm->arch.arm_pmu) {
 		params->pmu_num_ctrs = kvm->arch.nr_pmu_counters;
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 70b51b5cdea8..f93e37bc77aa 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -2072,6 +2072,9 @@ static int set_id_aa64dfr0_el1(struct kvm_vcpu *vcpu,
 {
 	u8 debugver = SYS_FIELD_GET(ID_AA64DFR0_EL1, DebugVer, val);
 	u8 pmuver = SYS_FIELD_GET(ID_AA64DFR0_EL1, PMUVer, val);
+	u8 bps = SYS_FIELD_GET(ID_AA64DFR0_EL1, BRPs, val);
+	u8 wps = SYS_FIELD_GET(ID_AA64DFR0_EL1, WRPs, val);
+	u8 ctx_cmps = SYS_FIELD_GET(ID_AA64DFR0_EL1, CTX_CMPs, val);
 
 	/*
 	 * Prior to commit 3d0dba5764b9 ("KVM: arm64: PMU: Move the
@@ -2091,10 +2094,11 @@ static int set_id_aa64dfr0_el1(struct kvm_vcpu *vcpu,
 		val &= ~ID_AA64DFR0_EL1_PMUVer_MASK;
 
 	/*
-	 * ID_AA64DFR0_EL1.DebugVer is one of those awkward fields with a
-	 * nonzero minimum safe value.
+	 * ID_AA64DFR0_EL1.DebugVer, BRPs and WRPs all have to be greater than
+	 * zero. CTX_CMPs is never greater than BRPs.
 	 */
-	if (debugver < ID_AA64DFR0_EL1_DebugVer_IMP)
+	if (debugver < ID_AA64DFR0_EL1_DebugVer_IMP || !bps || !wps ||
+	    ctx_cmps > bps)
 		return -EINVAL;
 
 	if (ignore_feat_doublelock(vcpu, val)) {
@@ -2329,10 +2333,11 @@ static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
 	mutex_lock(&vcpu->kvm->arch.config_lock);
 
 	/*
-	 * Once the VM has started the ID registers are immutable. Reject any
-	 * write that does not match the final register value.
+	 * Once the VM has started or the Realm descriptor is created, the ID
+	 * registers are immutable. Reject any write that does not match the
+	 * final register value.
 	 */
-	if (kvm_vm_has_ran_once(vcpu->kvm)) {
+	if (kvm_vm_has_ran_once(vcpu->kvm) || kvm_realm_is_created(vcpu->kvm)) {
 		if (val != read_id_reg(vcpu, rd))
 			ret = -EBUSY;
 		else
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:11:18 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:11:18 +0000
Subject: [PATCH v12 41/46] arm64: RMI: Propagate max SVE vector length from RMM
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-42-steven.price@arm.com>

From: Jean-Philippe Brucker <jean-philippe at linaro.org>

RMM provides the maximum vector length it supports for a guest in its
feature register. Make it visible to the rest of KVM and to userspace
via KVM_REG_ARM64_SVE_VLS.

Signed-off-by: Jean-Philippe Brucker <jean-philippe at linaro.org>
Signed-off-by: Steven Price <steven.price at arm.com>
Reviewed-by: Gavin Shan <gshan at redhat.com>
Reviewed-by: Suzuki K Poulose <suzuki.poulose at arm.com>
---
 arch/arm64/include/asm/kvm_host.h |  2 +-
 arch/arm64/include/asm/kvm_rmi.h  |  1 +
 arch/arm64/kvm/guest.c            |  2 +-
 arch/arm64/kvm/reset.c            | 12 ++++++++++--
 arch/arm64/kvm/rmi.c              |  6 ++++++
 5 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 7590d86c78a5..97c747cfb5be 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -78,9 +78,9 @@ enum kvm_mode kvm_get_mode(void);
 static inline enum kvm_mode kvm_get_mode(void) { return KVM_MODE_NONE; };
 #endif
 
-extern unsigned int __ro_after_init kvm_sve_max_vl;
 extern unsigned int __ro_after_init kvm_host_sve_max_vl;
 int __init kvm_arm_init_sve(void);
+unsigned int kvm_sve_get_max_vl(struct kvm *kvm);
 
 u32 __attribute_const__ kvm_target_cpu(void);
 void kvm_reset_vcpu(struct kvm_vcpu *vcpu);
diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_rmi.h
index 39770d9e9fcb..073b999bcd96 100644
--- a/arch/arm64/include/asm/kvm_rmi.h
+++ b/arch/arm64/include/asm/kvm_rmi.h
@@ -89,6 +89,7 @@ void kvm_init_rmi(void);
 u32 kvm_realm_ipa_limit(void);
 u32 kvm_realm_vgic_nr_lr(void);
 u8 kvm_realm_max_pmu_counters(void);
+unsigned int kvm_realm_sve_max_vl(void);
 
 u64 kvm_realm_reset_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val);
 
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 7cf919db1adc..705c2ccc335d 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -375,7 +375,7 @@ static int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 		if (vq_present(vqs, vq))
 			max_vq = vq;
 
-	if (max_vq > sve_vq_from_vl(kvm_sve_max_vl))
+	if (max_vq > sve_vq_from_vl(kvm_sve_get_max_vl(vcpu->kvm)))
 		return -EINVAL;
 
 	/*
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index 4bbf58892928..08883c9e848f 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -46,7 +46,7 @@ unsigned int __ro_after_init kvm_host_sve_max_vl;
 #define VCPU_RESET_PSTATE_SVC	(PSR_AA32_MODE_SVC | PSR_AA32_A_BIT | \
 				 PSR_AA32_I_BIT | PSR_AA32_F_BIT)
 
-unsigned int __ro_after_init kvm_sve_max_vl;
+static unsigned int __ro_after_init kvm_sve_max_vl;
 
 int __init kvm_arm_init_sve(void)
 {
@@ -76,9 +76,17 @@ int __init kvm_arm_init_sve(void)
 	return 0;
 }
 
+unsigned int kvm_sve_get_max_vl(struct kvm *kvm)
+{
+	if (kvm_is_realm(kvm))
+		return kvm_realm_sve_max_vl();
+	else
+		return kvm_sve_max_vl;
+}
+
 static void kvm_vcpu_enable_sve(struct kvm_vcpu *vcpu)
 {
-	vcpu->arch.sve_max_vl = kvm_sve_max_vl;
+	vcpu->arch.sve_max_vl = kvm_sve_get_max_vl(vcpu->kvm);
 
 	/*
 	 * Userspace can still customize the vector lengths by writing
diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
index 4e1c7bc2f52a..b719c39329c8 100644
--- a/arch/arm64/kvm/rmi.c
+++ b/arch/arm64/kvm/rmi.c
@@ -97,6 +97,12 @@ u8 kvm_realm_max_pmu_counters(void)
 	return u64_get_bits(rmm_feat_reg0, RMI_FEATURE_REGISTER_0_PMU_NUM_CTRS);
 }
 
+unsigned int kvm_realm_sve_max_vl(void)
+{
+	return sve_vl_from_vq(u64_get_bits(rmm_feat_reg0,
+					   RMI_FEATURE_REGISTER_0_SVE_VL) + 1);
+}
+
 u64 kvm_realm_reset_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val)
 {
 	u32 bps = u64_get_bits(rmm_feat_reg0, RMI_FEATURE_REGISTER_0_NUM_BPS);
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:11:19 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:11:19 +0000
Subject: [PATCH v12 42/46] arm64: RMI: Configure max SVE vector length for a Realm
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-43-steven.price@arm.com>

From: Jean-Philippe Brucker <jean-philippe at linaro.org>

Obtain the max vector length configured by userspace on the vCPUs, and
write it into the Realm parameters. By default the vCPU is configured
with the max vector length reported by RMM, and userspace can reduce it
with a write to KVM_REG_ARM64_SVE_VLS.

Signed-off-by: Jean-Philippe Brucker <jean-philippe at linaro.org>
Signed-off-by: Steven Price <steven.price at arm.com>
---
Changes since v6:
 * Rename max_vl/realm_max_vl to vl/last_vl - there is nothing "maximum"
   about them, we're just checking that all realms have the same vector
   length
---
 arch/arm64/kvm/guest.c |  3 ++-
 arch/arm64/kvm/rmi.c   | 37 +++++++++++++++++++++++++++++++++++++
 2 files changed, 39 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 705c2ccc335d..999edf0b5219 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -361,7 +361,7 @@ static int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	if (!vcpu_has_sve(vcpu))
 		return -ENOENT;
 
-	if (kvm_arm_vcpu_sve_finalized(vcpu))
+	if (kvm_arm_vcpu_sve_finalized(vcpu) || kvm_realm_is_created(vcpu->kvm))
 		return -EPERM; /* too late! */
 
 	if (WARN_ON(vcpu->arch.sve_state))
@@ -756,6 +756,7 @@ static bool validate_realm_set_reg(struct kvm_vcpu *vcpu,
 		switch (reg->id) {
 		case KVM_REG_ARM_PMCR_EL0:
 		case KVM_REG_ARM_ID_AA64DFR0_EL1:
+		case KVM_REG_ARM64_SVE_VLS:
 			return true;
 		}
 	}
diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
index b719c39329c8..657d70eab0ab 100644
--- a/arch/arm64/kvm/rmi.c
+++ b/arch/arm64/kvm/rmi.c
@@ -557,6 +557,39 @@ static void realm_unmap_shared_range(struct kvm *kvm,
 			     start, end);
 }
 
+static int realm_init_sve_param(struct kvm *kvm, struct realm_params *params)
+{
+	unsigned long i;
+	struct kvm_vcpu *vcpu;
+	int vl, last_vl = -1;
+
+	if (!kvm_has_sve(kvm))
+		return 0;
+
+	/*
+	 * Get the preferred SVE configuration, set by userspace with the
+	 * KVM_ARM_VCPU_SVE feature and KVM_REG_ARM64_SVE_VLS pseudo-register.
+	 */
+	kvm_for_each_vcpu(i, vcpu, kvm) {
+		if (!kvm_arm_vcpu_sve_finalized(vcpu))
+			return -EINVAL;
+
+		vl = vcpu->arch.sve_max_vl;
+
+		/* We need all vCPUs to have the same SVE config */
+		if (last_vl >= 0 && last_vl != vl)
+			return -EINVAL;
+
+		last_vl = vl;
+	}
+
+	if (last_vl > 0) {
+		params->sve_vl = sve_vq_from_vl(last_vl) - 1;
+		params->flags |= RMI_REALM_PARAM_FLAG_SVE;
+	}
+	return 0;
+}
+
 /* Calculate the number of s2 root rtts needed */
 static int realm_num_root_rtts(struct realm *realm)
 {
@@ -623,6 +656,10 @@ static int realm_create_rd(struct kvm *kvm)
 		params->flags |= RMI_REALM_PARAM_FLAG_PMU;
 	}
 
+	r = realm_init_sve_param(kvm, params);
+	if (r)
+		goto out_undelegate_tables;
+
 	params_phys = virt_to_phys(params);
 
 	if (rmi_realm_create(rd_phys, params_phys)) {
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:11:20 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:11:20 +0000
Subject: [PATCH v12 43/46] arm64: RMI: Provide register list for unfinalized RMI RECs
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-44-steven.price@arm.com>

From: Jean-Philippe Brucker <jean-philippe at linaro.org>

KVM_GET_REG_LIST should not be called before SVE is finalized. The ioctl
handler currently returns -EPERM in this case. But because it uses
kvm_arm_vcpu_is_finalized(), it now also rejects the call for
unfinalized REC even though finalizing the REC can only be done late,
after Realm descriptor creation.

Move the check to copy_sve_reg_indices(). One adverse side effect of
this change is that a KVM_GET_REG_LIST call that only probes for the
array size will now succeed even if SVE is not finalized, but that seems
harmless since the following KVM_GET_REG_LIST with the full array will
fail.

Signed-off-by: Jean-Philippe Brucker <jean-philippe at linaro.org>
Signed-off-by: Steven Price <steven.price at arm.com>
Reviewed-by: Gavin Shan <gshan at redhat.com>
---
 arch/arm64/kvm/arm.c   |  4 ----
 arch/arm64/kvm/guest.c | 10 +++++-----
 2 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index b2e1401cc223..88a807a78c04 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -1883,10 +1883,6 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 		if (unlikely(!kvm_vcpu_initialized(vcpu)))
 			break;
 
-		r = -EPERM;
-		if (!kvm_arm_vcpu_is_finalized(vcpu))
-			break;
-
 		r = -EFAULT;
 		if (copy_from_user(&reg_list, user_list, sizeof(reg_list)))
 			break;
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 999edf0b5219..2c4db2d1a6ca 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -617,8 +617,8 @@ static unsigned long num_sve_regs(const struct kvm_vcpu *vcpu)
 	if (!vcpu_has_sve(vcpu))
 		return 0;
 
-	/* Policed by KVM_GET_REG_LIST: */
-	WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu));
+	if (!kvm_arm_vcpu_sve_finalized(vcpu))
+		return 1; /* KVM_REG_ARM64_SVE_VLS */
 
 	return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */)
 		+ 1; /* KVM_REG_ARM64_SVE_VLS */
@@ -635,9 +635,6 @@ static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
 	if (!vcpu_has_sve(vcpu))
 		return 0;
 
-	/* Policed by KVM_GET_REG_LIST: */
-	WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu));
-
 	/*
 	 * Enumerate this first, so that userspace can save/restore in
 	 * the order reported by KVM_GET_REG_LIST:
@@ -647,6 +644,9 @@ static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
 		return -EFAULT;
 	++num_regs;
 
+	if (!kvm_arm_vcpu_sve_finalized(vcpu))
+		return num_regs;
+
 	for (i = 0; i < slices; i++) {
 		for (n = 0; n < SVE_NUM_ZREGS; n++) {
 			reg = KVM_REG_ARM64_SVE_ZREG(n, i);
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:11:21 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:11:21 +0000
Subject: [PATCH v12 44/46] arm64: RMI: Provide accurate register list
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-45-steven.price@arm.com>

From: Jean-Philippe Brucker <jean-philippe at linaro.org>

Userspace can set a few registers with KVM_SET_ONE_REG (9 GP registers
at runtime, and 3 system registers during initialization). Update the
register list returned by KVM_GET_REG_LIST.

Signed-off-by: Jean-Philippe Brucker <jean-philippe at linaro.org>
Signed-off-by: Steven Price <steven.price at arm.com>
---
Changes since v11:
 * Reworked due to upstream changes.
Changes since v8:
 * Minor type changes following review.
Changes since v7:
 * Reworked on upstream changes.
---
 arch/arm64/kvm/guest.c      |  6 ++++++
 arch/arm64/kvm/hypercalls.c |  4 ++--
 arch/arm64/kvm/sys_regs.c   | 29 +++++++++++++++++++++++------
 3 files changed, 31 insertions(+), 8 deletions(-)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 2c4db2d1a6ca..23fdb2ee8a61 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -620,6 +620,9 @@ static unsigned long num_sve_regs(const struct kvm_vcpu *vcpu)
 	if (!kvm_arm_vcpu_sve_finalized(vcpu))
 		return 1; /* KVM_REG_ARM64_SVE_VLS */
 
+	if (kvm_is_realm(vcpu->kvm))
+		return 1; /* KVM_REG_ARM64_SVE_VLS */
+
 	return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */)
 		+ 1; /* KVM_REG_ARM64_SVE_VLS */
 }
@@ -647,6 +650,9 @@ static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
 	if (!kvm_arm_vcpu_sve_finalized(vcpu))
 		return num_regs;
 
+	if (kvm_is_realm(vcpu->kvm))
+		return num_regs;
+
 	for (i = 0; i < slices; i++) {
 		for (n = 0; n < SVE_NUM_ZREGS; n++) {
 			reg = KVM_REG_ARM64_SVE_ZREG(n, i);
diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
index 58c5fe7d7572..70ac7971416c 100644
--- a/arch/arm64/kvm/hypercalls.c
+++ b/arch/arm64/kvm/hypercalls.c
@@ -414,14 +414,14 @@ void kvm_arm_teardown_hypercalls(struct kvm *kvm)
 
 int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
 {
-	return ARRAY_SIZE(kvm_arm_fw_reg_ids);
+	return kvm_is_realm(vcpu->kvm) ? 0 : ARRAY_SIZE(kvm_arm_fw_reg_ids);
 }
 
 int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(kvm_arm_fw_reg_ids); i++) {
+	for (i = 0; i < kvm_arm_get_fw_num_regs(vcpu); i++) {
 		if (put_user(kvm_arm_fw_reg_ids[i], uindices++))
 			return -EFAULT;
 	}
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index f93e37bc77aa..32b7be718e54 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -5401,18 +5401,18 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
 				    sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
 }
 
-static unsigned int num_demux_regs(void)
+static inline unsigned int num_demux_regs(struct kvm_vcpu *vcpu)
 {
-	return CSSELR_MAX;
+	return kvm_is_realm(vcpu->kvm) ? 0 : CSSELR_MAX;
 }
 
-static int write_demux_regids(u64 __user *uindices)
+static int write_demux_regids(struct kvm_vcpu *vcpu, u64 __user *uindices)
 {
 	u64 val = KVM_REG_ARM64 | KVM_REG_SIZE_U32 | KVM_REG_ARM_DEMUX;
 	unsigned int i;
 
 	val |= KVM_REG_ARM_DEMUX_ID_CCSIDR;
-	for (i = 0; i < CSSELR_MAX; i++) {
+	for (i = 0; i < num_demux_regs(vcpu); i++) {
 		if (put_user(val | i, uindices))
 			return -EFAULT;
 		uindices++;
@@ -5456,11 +5456,28 @@ static bool copy_reg_to_user(const struct sys_reg_desc *reg, u64 __user **uind)
 	return true;
 }
 
+static inline bool kvm_realm_sys_reg_hidden_user(const struct kvm_vcpu *vcpu,
+						 u64 reg)
+{
+	if (!kvm_is_realm(vcpu->kvm))
+		return false;
+
+	switch (reg) {
+	case SYS_ID_AA64DFR0_EL1:
+	case SYS_PMCR_EL0:
+		return false;
+	}
+	return true;
+}
+
 static int walk_one_sys_reg(const struct kvm_vcpu *vcpu,
 			    const struct sys_reg_desc *rd,
 			    u64 __user **uind,
 			    unsigned int *total)
 {
+	if (kvm_realm_sys_reg_hidden_user(vcpu, reg_to_encoding(rd)))
+		return 0;
+
 	/*
 	 * Ignore registers we trap but don't save,
 	 * and for which no custom user accessor is provided.
@@ -5498,7 +5515,7 @@ static int walk_sys_regs(struct kvm_vcpu *vcpu, u64 __user *uind)
 
 unsigned long kvm_arm_num_sys_reg_descs(struct kvm_vcpu *vcpu)
 {
-	return num_demux_regs()
+	return num_demux_regs(vcpu)
 		+ walk_sys_regs(vcpu, (u64 __user *)NULL);
 }
 
@@ -5511,7 +5528,7 @@ int kvm_arm_copy_sys_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 		return err;
 	uindices += err;
 
-	return write_demux_regids(uindices);
+	return write_demux_regids(vcpu, uindices);
 }
 
 #define KVM_ARM_FEATURE_ID_RANGE_INDEX(r)			\
-- 
2.43.0



From steven.price at arm.com  Wed Dec 17 02:11:22 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:11:22 +0000
Subject: [PATCH v12 45/46] KVM: arm64: Expose KVM_ARM_VCPU_REC to user space
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-46-steven.price@arm.com>

Increment KVM_VCPU_MAX_FEATURES to expose the new capability to user
space.

Signed-off-by: Steven Price <steven.price at arm.com>
Reviewed-by: Gavin Shan <gshan at redhat.com>
---
Changes since v8:
 * Since NV is now merged and enabled, this no longer conflicts with it.
---
 arch/arm64/include/asm/kvm_host.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 97c747cfb5be..7e3221d102a9 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -40,7 +40,7 @@
 
 #define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
 
-#define KVM_VCPU_MAX_FEATURES 9
+#define KVM_VCPU_MAX_FEATURES 10
 #define KVM_VCPU_VALID_FEATURES	(BIT(KVM_VCPU_MAX_FEATURES) - 1)
 
 #define KVM_REQ_SLEEP \
-- 
2.43.0



From mripard at kernel.org  Wed Dec 17 02:15:28 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Wed, 17 Dec 2025 10:15:28 +0000
Subject: [PATCH v3 01/22] drm/bridge: add of_drm_find_and_get_bridge()
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-1-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-1-b5165fab8058@bootlin.com>
Message-ID: <0ba037c65f9cadd51082abf2b7857ba7@kernel.org>

On Tue, 16 Dec 2025 18:58:34 +0100, Luca Ceresoli wrote:
> of_drm_find_bridge() does not increment the refcount for the returned
> bridge, but that is required now. However converting it and all its users
> is not realistically doable at once given the large amount of (direct and
> indirect) callers and the complexity of some.
> 
> 
> [ ... ]

Reviewed-by: Maxime Ripard <mripard at kernel.org>

Thanks!
Maxime


From steven.price at arm.com  Wed Dec 17 02:11:23 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 10:11:23 +0000
Subject: [PATCH v12 46/46] arm64: RMI: Enable realms to be created
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <20251217101125.91098-47-steven.price@arm.com>

All the pieces are now in place, so enable kvm_rmi_is_available when the
RMM is detected.

Signed-off-by: Steven Price <steven.price at arm.com>
---
 arch/arm64/kvm/rmi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
index 657d70eab0ab..0e470f31d46a 100644
--- a/arch/arm64/kvm/rmi.c
+++ b/arch/arm64/kvm/rmi.c
@@ -1659,5 +1659,5 @@ void kvm_init_rmi(void)
 	if (rmi_vmid_init())
 		return;
 
-	/* Future patch will enable static branch kvm_rmi_is_available */
+	static_branch_enable(&kvm_rmi_is_available);
 }
-- 
2.43.0



From mripard at kernel.org  Wed Dec 17 02:16:20 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Wed, 17 Dec 2025 10:16:20 +0000
Subject: [PATCH v3 04/22] drm/bridge: make of_drm_find_bridge() a
 wrapper of of_drm_find_and_get_bridge()
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-4-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-4-b5165fab8058@bootlin.com>
Message-ID: <bf2654046433c0f580bac440c3e72299@kernel.org>

On Tue, 16 Dec 2025 18:58:37 +0100, Luca Ceresoli wrote:
> of_drm_find_bridge() is identical to of_drm_find_and_get_bridge() except it
> does not increment the refcount. Rewrite it as a wrapper and put the bridge
> being returned so the behaviour is still the same.
> 
> Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
> 
> [ ... ]

Reviewed-by: Maxime Ripard <mripard at kernel.org>

Thanks!
Maxime


From mripard at kernel.org  Wed Dec 17 02:16:35 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Wed, 17 Dec 2025 10:16:35 +0000
Subject: [PATCH v3 05/22] drm/arcpgu: convert to
 of_drm_find_and_get_bridge()
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-5-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-5-b5165fab8058@bootlin.com>
Message-ID: <1644597c6c9e114cd27898a80014c699@kernel.org>

On Tue, 16 Dec 2025 18:58:38 +0100, Luca Ceresoli wrote:
> of_drm_find_bridge() is deprecated. Move to its replacement
> of_drm_find_and_get_bridge() which gets a bridge reference, and ensure it
> is put it when done.
> 
> Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
> 
> [ ... ]

Reviewed-by: Maxime Ripard <mripard at kernel.org>

Thanks!
Maxime


From mripard at kernel.org  Wed Dec 17 02:17:03 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Wed, 17 Dec 2025 10:17:03 +0000
Subject: [PATCH v3 06/22] drm/bridge: add next_bridge pointer to struct
 drm_bridge
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-6-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-6-b5165fab8058@bootlin.com>
Message-ID: <58a8aea8735f1ec8db23a95da8b7e0a8@kernel.org>

On Tue, 16 Dec 2025 18:58:39 +0100, Luca Ceresoli wrote:
> Many bridge drivers store a next_bridge pointer in their private data and
> use it for attach and sometimes other purposes. This is going to be risky
> when bridge hot-unplug is used.
> 
> Considering this example scenario:
> 
> [ ... ]

Reviewed-by: Maxime Ripard <mripard at kernel.org>

Thanks!
Maxime


From mripard at kernel.org  Wed Dec 17 02:17:27 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Wed, 17 Dec 2025 10:17:27 +0000
Subject: [PATCH v3 07/22] drm/bridge: ite-it66121: get/put the next
 bridge
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-7-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-7-b5165fab8058@bootlin.com>
Message-ID: <5797d5b801c1c43b31ddf70d385c8ef1@kernel.org>

On Tue, 16 Dec 2025 18:58:40 +0100, Luca Ceresoli wrote:
> This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
> function and stores it until driver removal. of_drm_find_bridge() is
> deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
> refcounted and use bridge->next_bridge to put the reference on
> deallocation.
> 
> [ ... ]

Reviewed-by: Maxime Ripard <mripard at kernel.org>

Thanks!
Maxime


From mripard at kernel.org  Wed Dec 17 02:17:39 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Wed, 17 Dec 2025 10:17:39 +0000
Subject: [PATCH v3 08/22] drm/bridge: imx8qxp-pixel-combiner: get/put
 the next bridge
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-8-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-8-b5165fab8058@bootlin.com>
Message-ID: <c88ececc4692f3b9d8d5284bb398470a@kernel.org>

On Tue, 16 Dec 2025 18:58:41 +0100, Luca Ceresoli wrote:
> This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
> function and stores it until driver removal. of_drm_find_bridge() is
> deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
> refcounted and use bridge->next_bridge to put the reference on
> deallocation.
> 
> [ ... ]

Reviewed-by: Maxime Ripard <mripard at kernel.org>

Thanks!
Maxime


From mripard at kernel.org  Wed Dec 17 02:17:58 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Wed, 17 Dec 2025 10:17:58 +0000
Subject: [PATCH v3 10/22] drm/meson: encoder_cvbs: get/put the next
 bridge
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-10-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-10-b5165fab8058@bootlin.com>
Message-ID: <0330f880f446091e7bb31872f69f6de5@kernel.org>

On Tue, 16 Dec 2025 18:58:43 +0100, Luca Ceresoli wrote:
> This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
> function and stores it until driver removal. of_drm_find_bridge() is
> deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
> refcounted and use bridge->next_bridge to put the reference on
> deallocation.
> 
> [ ... ]

Reviewed-by: Maxime Ripard <mripard at kernel.org>

Thanks!
Maxime


From mripard at kernel.org  Wed Dec 17 02:18:10 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Wed, 17 Dec 2025 10:18:10 +0000
Subject: [PATCH v3 11/22] drm/meson: encoder_dsi: get/put the next
 bridge
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-11-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-11-b5165fab8058@bootlin.com>
Message-ID: <035de7e7f585cedbe6cd28ce30ef5995@kernel.org>

On Tue, 16 Dec 2025 18:58:44 +0100, Luca Ceresoli wrote:
> This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
> function and stores it until driver removal. of_drm_find_bridge() is
> deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
> refcounted and use bridge->next_bridge to put the reference on
> deallocation.
> 
> [ ... ]

Reviewed-by: Maxime Ripard <mripard at kernel.org>

Thanks!
Maxime


From mripard at kernel.org  Wed Dec 17 02:18:20 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Wed, 17 Dec 2025 10:18:20 +0000
Subject: [PATCH v3 12/22] drm/meson: encoder_hdmi: get/put the next
 bridge
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-12-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-12-b5165fab8058@bootlin.com>
Message-ID: <7e16dd4d1eb87f96ab70ded4f16a04ef@kernel.org>

On Tue, 16 Dec 2025 18:58:45 +0100, Luca Ceresoli wrote:
> This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
> function and stores it until driver removal. of_drm_find_bridge() is
> deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
> refcounted and use bridge->next_bridge to put the reference on
> deallocation.
> 
> [ ... ]

Reviewed-by: Maxime Ripard <mripard at kernel.org>

Thanks!
Maxime


From mripard at kernel.org  Wed Dec 17 02:18:48 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Wed, 17 Dec 2025 10:18:48 +0000
Subject: [PATCH v3 13/22] drm/bridge: imx8qxp-pxl2dpi: simplify put of
 device_node pointers
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-13-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-13-b5165fab8058@bootlin.com>
Message-ID: <36c9a024a4c96830f13bc1e7c005f231@kernel.org>

On Tue, 16 Dec 2025 18:58:46 +0100, Luca Ceresoli wrote:
> Simplify the error-management code in
> imx8qxp_pxl2dpi_get_available_ep_from_port() by using a release action for
> the struct device_node pointers.
> 
> Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
> 
> [ ... ]

Reviewed-by: Maxime Ripard <mripard at kernel.org>

Thanks!
Maxime


From louisalexis.eyraud at collabora.com  Wed Dec 17 02:19:00 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Wed, 17 Dec 2025 11:19:00 +0100
Subject: [PATCH v2 01/12] dt-bindings: phy: mediatek,hdmi-phy: Fix clock
 output names for MT8195
In-Reply-To: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
References: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
Message-ID: <20251217-mtk-genio-evk-hdmi-support-v2-1-a994976bb39a@collabora.com>

From: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>

For all of the HDMI PHYs compatible with the one found on MT8195
the output clock has a different datasheet name and specifically
it is called "hdmi_txpll", differently from the older HDMI PHYs
which output block is called "hdmitx_dig_cts".

Replace clock output name string check by max item number one to allow
the new name on all of the HDMI PHY IPs that are perfectly compatible
with MT8195.

[Louis-Alexis Eyraud: split patch, addressed previous feedback from
mailing list, and reworded description]

Fixes: c78fe548b062 ("dt-bindings: phy: mediatek: hdmi-phy: Add mt8195 compatible")
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml
index f3a8b0b745d13ffc55d391570bff20830d925ed3..10f1d9326f18dba85b92b4c88f4c0f6cdddc4c25 100644
--- a/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml
@@ -42,8 +42,7 @@ properties:
       - const: pll_ref
 
   clock-output-names:
-    items:
-      - const: hdmitx_dig_cts
+    maxItems: 1
 
   "#phy-cells":
     const: 0

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Wed Dec 17 02:18:59 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Wed, 17 Dec 2025 11:18:59 +0100
Subject: [PATCH v2 00/12] Add HDMI support for Mediatek Genio
 510/700/1200-EVK and Radxa NIO-12L boards
Message-ID: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>

This patch series adds and enables the HDMI output support for the
following boards:
- Mediatek Genio 510-EVK (MT8370)
- Mediatek Genio 700-EVK (MT8390)
- Mediatek Genio 1200-EVK (MT8395)
- Radxa NIO-12L (MT8395)

Patch 1 is a 'mediatek,hdmi-phy' dt-binding fix for MT8195 SoC and a
revised version of [1], that addresses previous feedback from mailing
list ([2]).
Patch 2 was split from [1] into a separate patch and adds a MT8188 SoC
compatible in 'mediatek,hdmi-phy' dt-binding.
Patch 3 documents in 'mediatek,hdmi-phy' dt-binding extra clocks for
MT8195 SoC.
Patch 4 adds all of the nodes that are required to enable HDMI output
for MT8195 SoC and its variant (MT8395).
Patch 5 adds the same but for MT8188 SoC and its variants (MT8370,
MT8390).
Patches 6 to 11 enable HDMI output and sound support for each board.
Patch 12 enables the Mediatek HDMIv2 driver as module in defconfig.

The series is based on linux-next (tag: next-20251217).

[1] https://lore.kernel.org/linux-mediatek/20250724083914.61351-16-angelogioacchino.delregno at collabora.com/
[2] https://lore.kernel.org/linux-mediatek/ee525312-bde1-4724-b32f-83be32c87696 at kernel.org/

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
Changes in v2: 
- Rebased over next-20151217 tag
- Updated patch 3 to take into account Rob Herring remarks and simplify
  patch
- Updated patch 4 to align HDMI phy clock name changes done in patch 3. 
- Add reviewed-by trailer in patch 1
- Link to v1: https://lore.kernel.org/r/20251209-mtk-genio-evk-hdmi-support-v1-0-9a6106effba6 at collabora.com

---
AngeloGioacchino Del Regno (5):
      dt-bindings: phy: mediatek,hdmi-phy: Fix clock output names for MT8195
      arm64: dts: mediatek: mt8195: Add DPI1, HDMI, HDMI PHY/DDC nodes
      arm64: dts: mediatek: mt8188: Add DPI1, HDMI, HDMI PHY/DDC nodes
      arm64: dts: mediatek: mt8390-genio-common: Enable HDMI output
      arm64: dts: mediatek: mt8395-radxa-nio-12l: Enable HDMI output

Louis-Alexis Eyraud (6):
      dt-bindings: phy: mediatek,hdmi-phy: Add support for MT8188 SoC
      arm64: dts: mediatek: mt8390-genio-common: Add HDMI sound output support
      arm64: dts: mediatek: mt8395-radxa-nio-12l: Add HDMI sound output support
      arm64: dts: mediatek: mt8395-genio-common: Enable HDMI output
      arm64: dts: mediatek: mt8395-genio-common: Add HDMI sound output support
      arm64: defconfig: Enable Mediatek HDMIv2 driver

N?colas F. R. A. Prado (1):
      dt-bindings: phy: mediatek,hdmi-phy: Document extra clocks for MT8195

 .../devicetree/bindings/phy/mediatek,hdmi-phy.yaml |  29 +++-
 arch/arm64/boot/dts/mediatek/mt8188.dtsi           |  82 +++++++++++
 arch/arm64/boot/dts/mediatek/mt8195.dtsi           |  85 ++++++++++++
 .../boot/dts/mediatek/mt8390-genio-common.dtsi     | 150 +++++++++++++++++++++
 .../boot/dts/mediatek/mt8395-genio-common.dtsi     | 150 +++++++++++++++++++++
 .../boot/dts/mediatek/mt8395-radxa-nio-12l.dts     | 150 +++++++++++++++++++++
 arch/arm64/configs/defconfig                       |   1 +
 7 files changed, 645 insertions(+), 2 deletions(-)
---
base-commit: a512be9e8838afec6baa83767e291dfca8657410
change-id: 20251203-mtk-genio-evk-hdmi-support-17da5161827a

Best regards,
-- 
Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>



From louisalexis.eyraud at collabora.com  Wed Dec 17 02:19:02 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Wed, 17 Dec 2025 11:19:02 +0100
Subject: [PATCH v2 03/12] dt-bindings: phy: mediatek,hdmi-phy: Document
 extra clocks for MT8195
In-Reply-To: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
References: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
Message-ID: <20251217-mtk-genio-evk-hdmi-support-v2-3-a994976bb39a@collabora.com>

From: "N?colas F. R. A. Prado" <nfraprado at collabora.com>

MT8195's HDMI PHY block has 4 clocks instead of just a single one.
Describe the extra clocks for it.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
[Louis-Alexis Eyraud: addressed feedback from mailing list]
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 .../devicetree/bindings/phy/mediatek,hdmi-phy.yaml | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml
index cd4ac42ee45e4648ed512f68f6f28d1f3f2e1116..ac93069f48013b7f082f1b64ee0a6a60a3a912eb 100644
--- a/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml
@@ -38,12 +38,20 @@ properties:
     maxItems: 1
 
   clocks:
+    minItems: 1
     items:
       - description: PLL reference clock
+      - description: HDMI 26MHz clock
+      - description: HDMI PLL1 clock
+      - description: HDMI PLL2 clock
 
   clock-names:
+    minItems: 1
     items:
       - const: pll_ref
+      - const: 26m
+      - const: pll1
+      - const: pll2
 
   clock-output-names:
     maxItems: 1
@@ -79,6 +87,20 @@ required:
   - "#phy-cells"
   - "#clock-cells"
 
+allOf:
+  - if:
+      not:
+        properties:
+          compatible:
+            contains:
+              const: mediatek,mt8195-hdmi-phy
+    then:
+      properties:
+        clocks:
+          maxItems: 1
+        clock-names:
+          maxItems: 1
+
 additionalProperties: false
 
 examples:

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Wed Dec 17 02:19:01 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Wed, 17 Dec 2025 11:19:01 +0100
Subject: [PATCH v2 02/12] dt-bindings: phy: mediatek,hdmi-phy: Add support
 for MT8188 SoC
In-Reply-To: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
References: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
Message-ID: <20251217-mtk-genio-evk-hdmi-support-v2-2-a994976bb39a@collabora.com>

Add compatible string for the HDMI PHY IP on MT8188 SoC, that is
compatible with the one found on MT8195 SoC.

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml
index 10f1d9326f18dba85b92b4c88f4c0f6cdddc4c25..cd4ac42ee45e4648ed512f68f6f28d1f3f2e1116 100644
--- a/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml
@@ -26,6 +26,10 @@ properties:
           - enum:
               - mediatek,mt7623-hdmi-phy
           - const: mediatek,mt2701-hdmi-phy
+      - items:
+          - enum:
+              - mediatek,mt8188-hdmi-phy
+          - const: mediatek,mt8195-hdmi-phy
       - const: mediatek,mt2701-hdmi-phy
       - const: mediatek,mt8173-hdmi-phy
       - const: mediatek,mt8195-hdmi-phy

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Wed Dec 17 02:19:03 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Wed, 17 Dec 2025 11:19:03 +0100
Subject: [PATCH v2 04/12] arm64: dts: mediatek: mt8195: Add DPI1, HDMI,
 HDMI PHY/DDC nodes
In-Reply-To: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
References: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
Message-ID: <20251217-mtk-genio-evk-hdmi-support-v2-4-a994976bb39a@collabora.com>

From: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>

Add all of the nodes that are required to enable HDMI output,
including ones describing the HDMI PHY, Controller and DDC,
and the Digital Parallel Interface instance that is internally
connected to the HDMI Controller.

All of the added nodes are disabled by default as usage is
board dependent.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
[Louis-Alexis Eyraud: addressed feedback from mailing list]
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 arch/arm64/boot/dts/mediatek/mt8195.dtsi | 85 ++++++++++++++++++++++++++++++++
 1 file changed, 85 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8195.dtsi b/arch/arm64/boot/dts/mediatek/mt8195.dtsi
index c7adafaa83288d2d86ddf45c97cc984344e1ff77..c72e34c57629d0fabd08fabab8250e2f865de915 100644
--- a/arch/arm64/boot/dts/mediatek/mt8195.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8195.dtsi
@@ -26,8 +26,10 @@ / {
 	aliases {
 		dp-intf0 = &dp_intf0;
 		dp-intf1 = &dp_intf1;
+		dpi1 = &dpi1;
 		gce0 = &gce0;
 		gce1 = &gce1;
+		hdmi0 = &hdmi;
 		ethdr0 = &ethdr0;
 		mutex0 = &mutex;
 		mutex1 = &mutex1;
@@ -1857,6 +1859,23 @@ imp_iic_wrap_s: clock-controller at 11d03000 {
 			#clock-cells = <1>;
 		};
 
+		hdmi_phy: hdmi-phy at 11d5f000 {
+			compatible = "mediatek,mt8195-hdmi-phy";
+			reg = <0 0x11d5f000 0 0x100>;
+			clocks = <&topckgen CLK_TOP_HDMI_XTAL>,
+				 <&infracfg_ao CLK_INFRA_AO_HDMI_26M>,
+				 <&apmixedsys CLK_APMIXED_HDMIPLL1>,
+				 <&apmixedsys CLK_APMIXED_HDMIPLL2>;
+			clock-names = "pll_ref", "26m", "pll1", "pll2";
+			clock-output-names = "hdmi_txpll";
+
+			#clock-cells = <0>;
+			#phy-cells = <0>;
+			mediatek,ibias = <0xa>;
+			mediatek,ibias_up = <0x1c>;
+			status = "disabled";
+		};
+
 		i2c0: i2c at 11e00000 {
 			compatible = "mediatek,mt8195-i2c",
 				     "mediatek,mt8192-i2c";
@@ -3670,6 +3689,34 @@ merge5: vpp-merge at 1c110000 {
 			resets = <&vdosys1 MT8195_VDOSYS1_SW0_RST_B_MERGE4_DL_ASYNC>;
 		};
 
+		dpi1: dpi at 1c112000 {
+			compatible = "mediatek,mt8195-dpi";
+			reg = <0 0x1c112000 0 0x1000>;
+			clocks = <&vdosys1 CLK_VDO1_DPI1>,
+				 <&vdosys1 CLK_VDO1_DPI1_MM>,
+				 <&vdosys1 CLK_VDO1_DPI1_HDMI>;
+			clock-names = "pixel", "engine", "pll";
+			interrupts = <GIC_SPI 512 IRQ_TYPE_LEVEL_HIGH 0>;
+			power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>;
+			resets = <&vdosys1 MT8195_VDOSYS1_SW0_RST_B_DPI1>;
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+					dpi1_in: endpoint { };
+				};
+
+				port at 1 {
+					reg = <1>;
+					dpi1_out: endpoint { };
+				};
+			};
+		};
+
 		dp_intf1: dp-intf at 1c113000 {
 			compatible = "mediatek,mt8195-dp-intf";
 			reg = <0 0x1c113000 0 0x1000>;
@@ -3730,6 +3777,44 @@ ethdr0: hdr-engine at 1c114000 {
 				      "gfx_fe1_async", "vdo_be_async";
 		};
 
+		hdmi: hdmi-tx at 1c300000 {
+			compatible = "mediatek,mt8195-hdmi-tx";
+			#sound-dai-cells = <1>;
+			reg = <0 0x1c300000 0 0x1000>;
+			clocks = <&topckgen CLK_TOP_HDMI_APB>,
+				 <&topckgen CLK_TOP_HDCP>,
+				 <&topckgen CLK_TOP_HDCP_24M>,
+				 <&vppsys1 CLK_VPP1_VPP_SPLIT_HDMI>;
+			clock-names = "bus", "hdcp", "hdcp24m", "hdmi-split";
+			assigned-clocks = <&topckgen CLK_TOP_HDCP>;
+			assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D4_D8>;
+			interrupts = <GIC_SPI 677 IRQ_TYPE_LEVEL_HIGH 0>;
+			power-domains = <&spm MT8195_POWER_DOMAIN_HDMI_TX>;
+			phys = <&hdmi_phy>;
+			phy-names = "hdmi";
+			status = "disabled";
+
+			hdmitx_ddc: i2c {
+				compatible = "mediatek,mt8195-hdmi-ddc";
+				clocks = <&clk26m>;
+			};
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+					hdmi0_in: endpoint { };
+				};
+
+				port at 1 {
+					reg = <1>;
+					hdmi0_out: endpoint { };
+				};
+			};
+		};
+
 		edp_tx: edp-tx at 1c500000 {
 			compatible = "mediatek,mt8195-edp-tx";
 			reg = <0 0x1c500000 0 0x8000>;

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Wed Dec 17 02:19:05 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Wed, 17 Dec 2025 11:19:05 +0100
Subject: [PATCH v2 06/12] arm64: dts: mediatek: mt8390-genio-common: Enable
 HDMI output
In-Reply-To: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
References: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
Message-ID: <20251217-mtk-genio-evk-hdmi-support-v2-6-a994976bb39a@collabora.com>

From: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>

Add a node for the HDMI-A connector found on this board, then
configure the display pipeline and enable the required DPI1
interface, HDMI controller, its integrated DDC and the HDMI
PHY to enable support for the HDMI output provided by these EVKs.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
[Louis-Alexis Eyraud: reworded subject and description]
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 .../boot/dts/mediatek/mt8390-genio-common.dtsi     | 141 +++++++++++++++++++++
 1 file changed, 141 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8390-genio-common.dtsi b/arch/arm64/boot/dts/mediatek/mt8390-genio-common.dtsi
index a2cdecd2b9034e2f295d817e846d6ed1845e686a..5fa1f5fbad18f2bf9b153ae9a029829641e43023 100644
--- a/arch/arm64/boot/dts/mediatek/mt8390-genio-common.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8390-genio-common.dtsi
@@ -55,6 +55,20 @@ dmic_codec: dmic-codec {
 		wakeup-delay-ms = <30>;
 	};
 
+	connector {
+		compatible = "hdmi-connector";
+		label = "hdmi";
+		type = "a";
+		ddc-i2c-bus = <&hdmi_ddc>;
+		hdmi-pwr-supply = <&hdmi_phy>;
+
+		port {
+			hdmi_connector_in: endpoint {
+				remote-endpoint = <&hdmi0_out>;
+			};
+		};
+	};
+
 	firmware {
 		optee {
 			compatible = "linaro,optee-tz";
@@ -328,6 +342,18 @@ &dither0_out {
 	remote-endpoint = <&dsi0_in>;
 };
 
+&dpi1 {
+	status = "okay";
+};
+
+&dpi1_in {
+	remote-endpoint = <&merge5_out>;
+};
+
+&dpi1_out {
+	remote-endpoint = <&hdmi0_in>;
+};
+
 &gamma0_out {
 	remote-endpoint = <&postmask0_in>;
 };
@@ -337,6 +363,55 @@ &gpu {
 	status = "okay";
 };
 
+&ethdr0 {
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			ethdr0_in: endpoint at 1 {
+				reg = <1>;
+				remote-endpoint = <&vdosys1_ep_ext>;
+			};
+		};
+
+		port at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			ethdr0_out: endpoint at 1 {
+				reg = <1>;
+				remote-endpoint = <&merge5_in>;
+			};
+		};
+	};
+};
+
+&hdmi {
+	pinctrl-names = "default";
+	pinctrl-0 = <&hdmi_pins>;
+	status = "okay";
+};
+
+&hdmi0_in {
+	remote-endpoint = <&dpi1_out>;
+};
+
+&hdmi0_out {
+	remote-endpoint = <&hdmi_connector_in>;
+};
+
+&hdmi_phy {
+	pinctrl-names = "default";
+	pinctrl-0 = <&hdmi_vreg_pins>;
+	status = "okay";
+};
+
 &i2c0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&i2c0_pins>;
@@ -475,6 +550,35 @@ &i2c6 {
 	status = "okay";
 };
 
+&merge5 {
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			merge5_in: endpoint at 1 {
+				reg = <1>;
+				remote-endpoint = <&ethdr0_out>;
+			};
+		};
+
+		port at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			merge5_out: endpoint at 1 {
+				reg = <1>;
+				remote-endpoint = <&dpi1_in>;
+			};
+		};
+	};
+};
+
 &mfg0 {
 	domain-supply = <&mt6359_vproc2_buck_reg>;
 };
@@ -727,6 +831,31 @@ pins-txd {
 		};
 	};
 
+	hdmi_vreg_pins: hdmi-vreg-pins {
+		pins-pwr {
+			pinmux = <PINMUX_GPIO50__FUNC_O_HDMITX20_PWR5V>;
+			bias-disable;
+		};
+	};
+
+	hdmi_pins: hdmi-pins {
+		pins-hotplug {
+			pinmux = <PINMUX_GPIO51__FUNC_I0_HDMITX20_HTPLG>;
+			bias-pull-down;
+		};
+
+		pins-cec {
+			pinmux = <PINMUX_GPIO52__FUNC_B1_HDMITX20_CEC>;
+			bias-disable;
+		};
+
+		pins-ddc {
+			pinmux = <PINMUX_GPIO53__FUNC_B1_HDMITX20_SCL>,
+				 <PINMUX_GPIO54__FUNC_B1_HDMITX20_SDA>;
+			drive-strength = <10>;
+		};
+	};
+
 	i2c0_pins: i2c0-pins {
 		pins {
 			pinmux = <PINMUX_GPIO56__FUNC_B1_SDA0>,
@@ -1286,6 +1415,18 @@ connector {
 	};
 };
 
+&vdosys1 {
+	port {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		vdosys1_ep_ext: endpoint at 1 {
+			reg = <1>;
+			remote-endpoint = <&ethdr0_in>;
+		};
+	};
+};
+
 &xhci0 {
 	status = "okay";
 };

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Wed Dec 17 02:19:04 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Wed, 17 Dec 2025 11:19:04 +0100
Subject: [PATCH v2 05/12] arm64: dts: mediatek: mt8188: Add DPI1, HDMI,
 HDMI PHY/DDC nodes
In-Reply-To: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
References: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
Message-ID: <20251217-mtk-genio-evk-hdmi-support-v2-5-a994976bb39a@collabora.com>

From: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>

Add all of the nodes that are required to enable HDMI output,
including ones describing the HDMI PHY, Controller and DDC,
and the Digital Parallel Interface instance that is internally
connected to the HDMI Controller.

All of the added nodes are disabled by default as usage is
board dependent.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
[Louis-Alexis Eyraud: reworded subject and description]
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 arch/arm64/boot/dts/mediatek/mt8188.dtsi | 82 ++++++++++++++++++++++++++++++++
 1 file changed, 82 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8188.dtsi b/arch/arm64/boot/dts/mediatek/mt8188.dtsi
index 90c388f1890f5139be6a9513c4cd9b683a501279..e2a17359e407f0bdd3ae6ef8ade668e67a9bd493 100644
--- a/arch/arm64/boot/dts/mediatek/mt8188.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8188.dtsi
@@ -26,6 +26,7 @@ / {
 	aliases {
 		dp-intf0 = &dp_intf0;
 		dp-intf1 = &dp_intf1;
+		dpi1 = &dpi1;
 		dsc0 = &dsc0;
 		ethdr0 = &ethdr0;
 		gce0 = &gce0;
@@ -2038,6 +2039,19 @@ pcieport: pcie-phy at 0 {
 			};
 		};
 
+		hdmi_phy: hdmi-phy at 11d5f000 {
+			compatible = "mediatek,mt8188-hdmi-phy", "mediatek,mt8195-hdmi-phy";
+			reg = <0 0x11d5f000 0 0x100>;
+			clocks = <&infracfg_ao CLK_INFRA_AO_HDMI_26M>;
+			clock-names = "pll_ref";
+			clock-output-names = "hdmi_txpll";
+			#clock-cells = <0>;
+			#phy-cells = <0>;
+			mediatek,ibias = <0xa>;
+			mediatek,ibias_up = <0x1c>;
+			status = "disabled";
+		};
+
 		mipi_tx_config0: dsi-phy at 11c80000 {
 			compatible = "mediatek,mt8188-mipi-tx", "mediatek,mt8183-mipi-tx";
 			reg = <0 0x11c80000 0 0x1000>;
@@ -3406,6 +3420,34 @@ merge5: merge at 1c110000 {
 			mediatek,merge-fifo-en;
 		};
 
+		dpi1: dpi at 1c112000 {
+			compatible = "mediatek,mt8188-dpi", "mediatek,mt8195-dpi";
+			reg = <0 0x1c112000 0 0x1000>;
+			clocks = <&vdosys1 CLK_VDO1_DPI1>,
+				 <&vdosys1 CLK_VDO1_DPI1_MM>,
+				 <&vdosys1 CLK_VDO1_DPI1_HDMI>;
+			clock-names = "pixel", "engine", "pll";
+			interrupts = <GIC_SPI 524 IRQ_TYPE_LEVEL_HIGH 0>;
+			power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>;
+			resets = <&vdosys1 MT8188_VDO1_RST_DPI1_MM_CK>;
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+					dpi1_in: endpoint { };
+				};
+
+				port at 1 {
+					reg = <1>;
+					dpi1_out: endpoint { };
+				};
+			};
+		};
+
 		dp_intf1: dp-intf at 1c113000 {
 			compatible = "mediatek,mt8188-dp-intf";
 			reg = <0 0x1c113000 0 0x1000>;
@@ -3530,6 +3572,46 @@ padding7: padding at 1c124000 {
 			mediatek,gce-client-reg = <&gce0 SUBSYS_1c12XXXX 0x4000 0x1000>;
 		};
 
+		hdmi: hdmi at 1c300000 {
+			compatible = "mediatek,mt8188-hdmi-tx";
+			#sound-dai-cells = <1>;
+			reg = <0 0x1c300000 0 0x1000>;
+			clocks = <&topckgen CLK_TOP_HDMI_APB>,
+				 <&topckgen CLK_TOP_HDCP>,
+				 <&topckgen CLK_TOP_HDCP_24M>,
+				 <&vppsys1 CLK_VPP1_VPP_SPLIT_HDMI>;
+			clock-names = "bus", "hdcp", "hdcp24m", "hdmi-split";
+			assigned-clocks = <&topckgen CLK_TOP_HDCP>;
+			assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D4_D8>;
+			interrupts = <GIC_SPI 686 IRQ_TYPE_LEVEL_HIGH 0>;
+			power-domains = <&spm MT8188_POWER_DOMAIN_HDMI_TX>;
+			phys = <&hdmi_phy>;
+			phy-names = "hdmi";
+			status = "disabled";
+
+			hdmi_ddc: i2c {
+				compatible = "mediatek,mt8188-hdmi-ddc",
+					     "mediatek,mt8195-hdmi-ddc";
+				clocks = <&clk26m>;
+			};
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+					hdmi0_in: endpoint { };
+				};
+
+				port at 1 {
+					reg = <1>;
+					hdmi0_out: endpoint { };
+				};
+			};
+		};
+
+
 		edp_tx: edp-tx at 1c500000 {
 			compatible = "mediatek,mt8188-edp-tx";
 			reg = <0 0x1c500000 0 0x8000>;

-- 
2.52.0



From mripard at kernel.org  Wed Dec 17 02:19:42 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Wed, 17 Dec 2025 10:19:42 +0000
Subject: [PATCH v3 14/22] drm/bridge: imx8qxp-pxl2dpi: remove excess
 error message
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-14-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-14-b5165fab8058@bootlin.com>
Message-ID: <aff5a75a33e6e111347a7a79ebc26ddc@kernel.org>

On Tue, 16 Dec 2025 18:58:47 +0100, Luca Ceresoli wrote:
> imx8qxp_pxl2dpi_find_next_bridge() already emits a DRM_DEV_ERROR() for
> every error except -EPROBE_DEFER. The caller emits another one, which is
> redundant. Remove the message in the caller and keep the two in
> imx8qxp_pxl2dpi_find_next_bridge() as they are more informative about the
> error cause.
> 
> [ ... ]

Reviewed-by: Maxime Ripard <mripard at kernel.org>

Thanks!
Maxime


From louisalexis.eyraud at collabora.com  Wed Dec 17 02:19:07 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Wed, 17 Dec 2025 11:19:07 +0100
Subject: [PATCH v2 08/12] arm64: dts: mediatek: mt8395-radxa-nio-12l:
 Enable HDMI output
In-Reply-To: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
References: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
Message-ID: <20251217-mtk-genio-evk-hdmi-support-v2-8-a994976bb39a@collabora.com>

From: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>

Add a definition for the on-board HDMI connector, enable and add
the relevant configuration for the HDMI PHY and controller, and
define the pins used by those.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 .../boot/dts/mediatek/mt8395-radxa-nio-12l.dts     | 142 +++++++++++++++++++++
 1 file changed, 142 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8395-radxa-nio-12l.dts b/arch/arm64/boot/dts/mediatek/mt8395-radxa-nio-12l.dts
index d32f973f5e0528bc3233ff01f029006dbe6ef894..b0e18876bd5d2341c6f17f47e9f11433be807ccd 100644
--- a/arch/arm64/boot/dts/mediatek/mt8395-radxa-nio-12l.dts
+++ b/arch/arm64/boot/dts/mediatek/mt8395-radxa-nio-12l.dts
@@ -37,6 +37,20 @@ chosen {
 		stdout-path = "serial0:921600n8";
 	};
 
+	connector {
+		compatible = "hdmi-connector";
+		label = "hdmi";
+		type = "a";
+		ddc-i2c-bus = <&hdmitx_ddc>;
+		hdmi-pwr-supply = <&hdmi_phy>;
+
+		port {
+			hdmi_connector_in: endpoint {
+				remote-endpoint = <&hdmi0_out>;
+			};
+		};
+	};
+
 	firmware {
 		optee {
 			compatible = "linaro,optee-tz";
@@ -245,6 +259,18 @@ port at 1 {
 	};
 };
 
+&dpi1 {
+	status = "okay";
+};
+
+&dpi1_in {
+	remote-endpoint = <&merge5_out>;
+};
+
+&dpi1_out {
+	remote-endpoint = <&hdmi0_in>;
+};
+
 &eth {
 	phy-mode = "rgmii-rxid";
 	phy-handle = <&rgmii_phy>;
@@ -265,11 +291,61 @@ rgmii_phy: ethernet-phy at 1 {
 	};
 };
 
+&ethdr0 {
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			ethdr0_in: endpoint at 1 {
+				reg = <1>;
+				remote-endpoint = <&vdosys1_ep_ext>;
+			};
+		};
+
+		port at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			ethdr0_out: endpoint at 1 {
+				reg = <1>;
+				remote-endpoint = <&merge5_in>;
+			};
+		};
+	};
+};
+
 &gpu {
 	mali-supply = <&mt6315_7_vbuck1>;
 	status = "okay";
 };
 
+&hdmi {
+	pinctrl-names = "default";
+	pinctrl-0 = <&hdmi_pins>;
+	status = "okay";
+};
+
+&hdmi0_in {
+	remote-endpoint = <&dpi1_out>;
+};
+
+&hdmi0_out {
+	remote-endpoint = <&hdmi_connector_in>;
+};
+
+&hdmi_phy {
+	pinctrl-names = "default";
+	pinctrl-0 = <&hdmi_vreg_pins>;
+
+	status = "okay";
+};
+
 &i2c2 {
 	clock-frequency = <400000>;
 	pinctrl-0 = <&i2c2_pins>;
@@ -448,6 +524,35 @@ typec_con_mux: endpoint {
 	};
 };
 
+&merge5 {
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			merge5_in: endpoint at 1 {
+				reg = <1>;
+				remote-endpoint = <&ethdr0_out>;
+			};
+		};
+
+		port at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			merge5_out: endpoint at 1 {
+				reg = <1>;
+				remote-endpoint = <&dpi1_in>;
+			};
+		};
+	};
+};
+
 &mfg0 {
 	domain-supply = <&mt6315_7_vbuck1>;
 };
@@ -647,6 +752,31 @@ pins {
 		};
 	};
 
+	hdmi_vreg_pins: hdmi-vreg-pins {
+		pins-pwr {
+			pinmux = <PINMUX_GPIO31__FUNC_HDMITX20_PWR5V>;
+			bias-disable;
+		};
+	};
+
+	hdmi_pins: hdmi-pins {
+		pins-hotplug {
+			pinmux = <PINMUX_GPIO32__FUNC_HDMITX20_HTPLG>;
+			bias-pull-down;
+		};
+
+		pins-ddc {
+			pinmux = <PINMUX_GPIO34__FUNC_HDMITX20_SCL>,
+				 <PINMUX_GPIO35__FUNC_HDMITX20_SDA>;
+			drive-strength = <10>;
+		};
+
+		pins-cec {
+			pinmux = <PINMUX_GPIO33__FUNC_HDMITX20_CEC>;
+			bias-disable;
+		};
+	};
+
 	i2c2_pins: i2c2-pins {
 		pins-bus {
 			pinmux = <PINMUX_GPIO12__FUNC_SDA2>,
@@ -1058,6 +1188,18 @@ &ssusb2 {
 	status = "okay";
 };
 
+&vdosys1 {
+	port {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		vdosys1_ep_ext: endpoint at 1 {
+			reg = <1>;
+			remote-endpoint = <&ethdr0_in>;
+		};
+	};
+};
+
 &xhci0 {
 	vbus-supply = <&otg_vbus_regulator>;
 	status = "okay";

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Wed Dec 17 02:19:06 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Wed, 17 Dec 2025 11:19:06 +0100
Subject: [PATCH v2 07/12] arm64: dts: mediatek: mt8390-genio-common: Add
 HDMI sound output support
In-Reply-To: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
References: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
Message-ID: <20251217-mtk-genio-evk-hdmi-support-v2-7-a994976bb39a@collabora.com>

Add in the sound node a new dai-link for ETDM3_OUT_BE to add the sound
output support through the HDMI connector.

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 arch/arm64/boot/dts/mediatek/mt8390-genio-common.dtsi | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8390-genio-common.dtsi b/arch/arm64/boot/dts/mediatek/mt8390-genio-common.dtsi
index 5fa1f5fbad18f2bf9b153ae9a029829641e43023..2062506f6cc523d7797adc8b7e74732be9320201 100644
--- a/arch/arm64/boot/dts/mediatek/mt8390-genio-common.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8390-genio-common.dtsi
@@ -1344,6 +1344,15 @@ codec {
 			sound-dai = <&dmic_codec>;
 		};
 	};
+
+	dai-link-2 {
+		link-name = "ETDM3_OUT_BE";
+
+		codec {
+			sound-dai = <&hdmi 0>;
+		};
+	};
+
 };
 
 &spi2 {

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Wed Dec 17 02:19:08 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Wed, 17 Dec 2025 11:19:08 +0100
Subject: [PATCH v2 09/12] arm64: dts: mediatek: mt8395-radxa-nio-12l: Add
 HDMI sound output support
In-Reply-To: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
References: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
Message-ID: <20251217-mtk-genio-evk-hdmi-support-v2-9-a994976bb39a@collabora.com>

Add in the sound node a new dai-link for ETDM3_OUT_BE to add the sound
output support through the HDMI TX connector.

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 arch/arm64/boot/dts/mediatek/mt8395-radxa-nio-12l.dts | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8395-radxa-nio-12l.dts b/arch/arm64/boot/dts/mediatek/mt8395-radxa-nio-12l.dts
index b0e18876bd5d2341c6f17f47e9f11433be807ccd..1cd4b84e98615be6c5cb13d01b7baed0e017c3be 100644
--- a/arch/arm64/boot/dts/mediatek/mt8395-radxa-nio-12l.dts
+++ b/arch/arm64/boot/dts/mediatek/mt8395-radxa-nio-12l.dts
@@ -1072,6 +1072,14 @@ codec {
 			sound-dai = <&pmic 0>;
 		};
 	};
+
+	hdmi-dai-link {
+		link-name = "ETDM3_OUT_BE";
+
+		codec {
+			sound-dai = <&hdmi 0>;
+		};
+	};
 };
 
 &spi1 {

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Wed Dec 17 02:19:09 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Wed, 17 Dec 2025 11:19:09 +0100
Subject: [PATCH v2 10/12] arm64: dts: mediatek: mt8395-genio-common: Enable
 HDMI output
In-Reply-To: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
References: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
Message-ID: <20251217-mtk-genio-evk-hdmi-support-v2-10-a994976bb39a@collabora.com>

Add a definition for the on-board HDMI connector, enable and add
the relevant configuration for the HDMI PHY and controller, and
define the pins used by those.

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 .../boot/dts/mediatek/mt8395-genio-common.dtsi     | 142 +++++++++++++++++++++
 1 file changed, 142 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8395-genio-common.dtsi b/arch/arm64/boot/dts/mediatek/mt8395-genio-common.dtsi
index 2b7167804e71d0ced33c048ecb2040667b5fece1..345fc5ac9e039de8660ae325f36ae6265ef3a7c8 100644
--- a/arch/arm64/boot/dts/mediatek/mt8395-genio-common.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8395-genio-common.dtsi
@@ -26,6 +26,20 @@ chosen {
 		stdout-path = "serial0:921600n8";
 	};
 
+	connector {
+		compatible = "hdmi-connector";
+		label = "hdmi";
+		type = "a";
+		ddc-i2c-bus = <&hdmitx_ddc>;
+		hdmi-pwr-supply = <&hdmi_phy>;
+
+		port {
+			hdmi_connector_in: endpoint {
+				remote-endpoint = <&hdmi0_out>;
+			};
+		};
+	};
+
 	firmware {
 		optee {
 			compatible = "linaro,optee-tz";
@@ -247,6 +261,18 @@ &dmic_codec {
 	wakeup-delay-ms = <200>;
 };
 
+&dpi1 {
+	status = "okay";
+};
+
+&dpi1_in {
+	remote-endpoint = <&merge5_out>;
+};
+
+&dpi1_out {
+	remote-endpoint = <&hdmi0_in>;
+};
+
 &dsi0 {
 	#address-cells = <1>;
 	#size-cells = <0>;
@@ -313,6 +339,35 @@ eth_phy0: ethernet-phy at 1 {
 	};
 };
 
+&ethdr0 {
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			ethdr0_in: endpoint at 1 {
+				reg = <1>;
+				remote-endpoint = <&vdosys1_ep_ext>;
+			};
+		};
+
+		port at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			ethdr0_out: endpoint at 1 {
+				reg = <1>;
+				remote-endpoint = <&merge5_in>;
+			};
+		};
+	};
+};
+
 &gamma0_out {
 	remote-endpoint = <&dither0_in>;
 };
@@ -329,6 +384,27 @@ &i2c0 {
 	status = "okay";
 };
 
+&hdmi {
+	pinctrl-names = "default";
+	pinctrl-0 = <&hdmi_pins>;
+	status = "okay";
+};
+
+&hdmi0_in {
+	remote-endpoint = <&dpi1_out>;
+};
+
+&hdmi0_out {
+	remote-endpoint = <&hdmi_connector_in>;
+};
+
+&hdmi_phy {
+	pinctrl-names = "default";
+	pinctrl-0 = <&hdmi_vreg_pins>;
+
+	status = "okay";
+};
+
 &i2c1 {
 	clock-frequency = <400000>;
 	pinctrl-0 = <&i2c1_pins>;
@@ -533,6 +609,35 @@ mt6360_ssusb_sbu_ep: endpoint {
 	};
 };
 
+&merge5 {
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			merge5_in: endpoint at 1 {
+				reg = <1>;
+				remote-endpoint = <&ethdr0_out>;
+			};
+		};
+
+		port at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			merge5_out: endpoint at 1 {
+				reg = <1>;
+				remote-endpoint = <&dpi1_in>;
+			};
+		};
+	};
+};
+
 &mfg0 {
 	domain-supply = <&mt6315_7_vbuck1>;
 };
@@ -762,6 +867,31 @@ pins {
 		};
 	};
 
+	hdmi_vreg_pins: hdmi-vreg-pins {
+		pins-pwr {
+			pinmux = <PINMUX_GPIO31__FUNC_HDMITX20_PWR5V>;
+			bias-disable;
+		};
+	};
+
+	hdmi_pins: hdmi-pins {
+		pins-hotplug {
+			pinmux = <PINMUX_GPIO32__FUNC_HDMITX20_HTPLG>;
+			bias-pull-down;
+		};
+
+		pins-ddc {
+			pinmux = <PINMUX_GPIO34__FUNC_HDMITX20_SCL>,
+				 <PINMUX_GPIO35__FUNC_HDMITX20_SDA>;
+			drive-strength = <10>;
+		};
+
+		pins-cec {
+			pinmux = <PINMUX_GPIO33__FUNC_HDMITX20_CEC>;
+			bias-disable;
+		};
+	};
+
 	i2c0_pins: i2c0-pins {
 		pins {
 			pinmux = <PINMUX_GPIO8__FUNC_SDA0>,
@@ -1212,6 +1342,18 @@ vdosys0_ep_main: endpoint at 0 {
 	};
 };
 
+&vdosys1 {
+	port {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		vdosys1_ep_ext: endpoint at 1 {
+			reg = <1>;
+			remote-endpoint = <&ethdr0_in>;
+		};
+	};
+};
+
 &xhci0 {
 	status = "okay";
 };

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Wed Dec 17 02:19:10 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Wed, 17 Dec 2025 11:19:10 +0100
Subject: [PATCH v2 11/12] arm64: dts: mediatek: mt8395-genio-common: Add
 HDMI sound output support
In-Reply-To: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
References: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
Message-ID: <20251217-mtk-genio-evk-hdmi-support-v2-11-a994976bb39a@collabora.com>

Add in the sound node a new dai-link for ETDM3_OUT_BE to add the sound
output support through the HDMI TX connector.

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 arch/arm64/boot/dts/mediatek/mt8395-genio-common.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8395-genio-common.dtsi b/arch/arm64/boot/dts/mediatek/mt8395-genio-common.dtsi
index 345fc5ac9e039de8660ae325f36ae6265ef3a7c8..d849af4d36134df6a7b9f7967efd0db13c372d7a 100644
--- a/arch/arm64/boot/dts/mediatek/mt8395-genio-common.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8395-genio-common.dtsi
@@ -1189,6 +1189,14 @@ codec {
 			sound-dai = <&pmic 0>;
 		};
 	};
+
+	hdmi-dai-link {
+		link-name = "ETDM3_OUT_BE";
+
+		codec {
+			sound-dai = <&hdmi 0>;
+		};
+	};
 };
 
 &spi1 {

-- 
2.52.0



From louisalexis.eyraud at collabora.com  Wed Dec 17 02:19:11 2025
From: louisalexis.eyraud at collabora.com (Louis-Alexis Eyraud)
Date: Wed, 17 Dec 2025 11:19:11 +0100
Subject: [PATCH v2 12/12] arm64: defconfig: Enable Mediatek HDMIv2 driver
In-Reply-To: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
References: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
Message-ID: <20251217-mtk-genio-evk-hdmi-support-v2-12-a994976bb39a@collabora.com>

In order to enable the HDMI output support on Mediatek Genio 510-EVK,
700-EVK, and 1200-EVK boards, enable the driver for it in the default
configuration.

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
---
 arch/arm64/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 982b894a36d29ebbdda025a3ae9713ddfd7195d8..975297e8c01a28fe4fd90185635d654e970ae83c 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -1016,6 +1016,7 @@ CONFIG_DRM_HISI_KIRIN=m
 CONFIG_DRM_MEDIATEK=m
 CONFIG_DRM_MEDIATEK_DP=m
 CONFIG_DRM_MEDIATEK_HDMI=m
+CONFIG_DRM_MEDIATEK_HDMI_V2=m
 CONFIG_DRM_MXSFB=m
 CONFIG_DRM_IMX_LCDIF=m
 CONFIG_DRM_MESON=m

-- 
2.52.0



From mripard at kernel.org  Wed Dec 17 02:20:14 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Wed, 17 Dec 2025 10:20:14 +0000
Subject: [PATCH v3 15/22] drm/bridge: imx8qxp-pxl2dpi:
 imx8qxp_pxl2dpi_find_next_bridge: return int, not ERR_PTR
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-15-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-15-b5165fab8058@bootlin.com>
Message-ID: <8c0e9399c1f8bb388eb3f0ee2cf37089@kernel.org>

On Tue, 16 Dec 2025 18:58:48 +0100, Luca Ceresoli wrote:
> In preparation for using bridge->next_bridge, we need to ensure that it
> will never contain anything but NULL or a valid bridge pointer. Current
> code stores an ERR_PTR when imx8qxp_pxl2dpi_find_next_bridge() errors
> out. Instead of fixing that after the facts in the caller, change the
> function to internally set the next_pointer and just return an int error
> 
> [ ... ]

Reviewed-by: Maxime Ripard <mripard at kernel.org>

Thanks!
Maxime


From mripard at kernel.org  Wed Dec 17 02:20:24 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Wed, 17 Dec 2025 10:20:24 +0000
Subject: [PATCH v3 16/22] drm/bridge: imx8qxp-pxl2dpi: get/put the next
 bridge
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-16-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-16-b5165fab8058@bootlin.com>
Message-ID: <55901cff3f0021167c6a3abecadfd3d6@kernel.org>

On Tue, 16 Dec 2025 18:58:49 +0100, Luca Ceresoli wrote:
> This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
> function and stores it until driver removal. of_drm_find_bridge() is
> deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
> refcounted and use bridge->next_bridge to put the reference on
> deallocation.
> 
> [ ... ]

Reviewed-by: Maxime Ripard <mripard at kernel.org>

Thanks!
Maxime


From mripard at kernel.org  Wed Dec 17 02:20:42 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Wed, 17 Dec 2025 10:20:42 +0000
Subject: [PATCH v3 17/22] drm/bridge: imx8qxp-pxl2dpi: get/put the
 companion bridge
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-17-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-17-b5165fab8058@bootlin.com>
Message-ID: <21d359fbd3c0279ad82ad3dc0f2494b3@kernel.org>

On Tue, 16 Dec 2025 18:58:50 +0100, Luca Ceresoli wrote:
> This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
> function and stores it until driver removal. of_drm_find_bridge() is
> deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
> refcounted and use the destroy hook to put the reference on deallocation.
> 
> 
> [ ... ]

Reviewed-by: Maxime Ripard <mripard at kernel.org>

Thanks!
Maxime


From mripard at kernel.org  Wed Dec 17 02:20:59 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Wed, 17 Dec 2025 10:20:59 +0000
Subject: [PATCH v3 20/22] drm/bridge: imx8qxp-pixel-link: remove excess
 error message
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-20-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-20-b5165fab8058@bootlin.com>
Message-ID: <5a69eb5665e9f64d2e1773f834bc4921@kernel.org>

On Tue, 16 Dec 2025 18:58:53 +0100, Luca Ceresoli wrote:
> imx8qxp_pixel_link_find_next_bridge() already emits a DRM_DEV_ERROR() on
> error except for -EPROBE_DEFER. The caller emits another one, which is
> redundant. Remove the message in the caller and keep the one in
> imx8qxp_pixel_link_find_next_bridge() as it is more informative about the
> error cause.
> 
> [ ... ]

Reviewed-by: Maxime Ripard <mripard at kernel.org>

Thanks!
Maxime


From guptarud at gmail.com  Wed Dec 17 02:21:11 2025
From: guptarud at gmail.com (Rudraksha Gupta)
Date: Wed, 17 Dec 2025 02:21:11 -0800
Subject: ARMv7 Linux + Rust doesn't boot when compiling with only LLVM=1
In-Reply-To: <0705db10-3cbb-4958-a116-112457f9af6c@gmail.com>
References: <1286af8e-f908-45db-af7c-d9c5d592abfd@gmail.com>
 <0705db10-3cbb-4958-a116-112457f9af6c@gmail.com>
Message-ID: <1910f4b6-db74-4c86-9010-28ab4462c5a7@gmail.com>

On 12/16/25 06:41, Christian Schrefl wrote:
> On 12/14/25 12:54 AM, Rudraksha Gupta wrote:
>> Hello all,
>>
>>
>> I have the following problem: https://gitlab.postmarketos.org/postmarketOS/pmbootstrap/-/issues/2635
>>
>>
>> In short, what is happening is the following:
>>
>>
>> - The kernel boots and outputs via UART when I build the kernel with the following:
>>
>> make LLVM=1 ARCH="$arm" CC="${CC:-gcc}"
>>
>>
>> - The kernel doesn't boot and there is no output via UART when I build the kernel with the following:
>>
>> make LLVM=1 ARCH="$arm"
>>
>>
>> The only difference being:?CC="${CC:-gcc}". Is this expected? I think this was present in the Linux kernel ever since Rust was enabled for ARMv7, and I never encountered it because postmarketOS was originally building the first way.
>
> I've managed to the get the build setup for qemu-armv7. For some reason
> I could not get past the initrd even on kernels that are supposed to work,
> but I think that is unrelated (and not a kernel issue).

Yep, I just got qemu-arm working to drop into a debug shell for now. I 
have to look into why other things aren't behaving nicely (but that's a 
problem for later me :P). For now, it seems to demonstrate the problem 
nicely:

https://gitlab.postmarketos.org/postmarketOS/pmbootstrap/-/issues/2635#note_521740


> On the linux-next kernel I didn't get any output on the console from qemu so I
> think I've reproduced the issue. Changing CONFIG_RUST=n did not change the behavior.
>
> So I this is almost certainly a LLVM/clang issue and not a Rust issue. I'll try to
> do a bit more digging, but I'm not sure how much I'll get done.

Did a little more testing in addition to the testing in the gitlab issue 
mentioned above:

- Removed Rust configs from linux-next/pmos.config -> didn't boot on 
qemu-arm and my phone

- Then I removed Rust dependencies from linux-next/APKBUILD -> didn't 
boot on qemu-arm and my phone

- used linux-stable instead of linux-next -> booted on qemu-arm to a 
debug shell

linux-stable is built via gcc:
https://gitlab.alpinelinux.org/alpine/aports/-/blob/master/community/linux-stable/APKBUILD#L179

linux-next is built via clang:
https://gitlab.postmarketos.org/postmarketOS/pmaports/-/blob/master/device/testing/linux-next/APKBUILD#L68



>
> Adding the LLVM and ARM lists to this conversation.
>
> Cheers,
> Christian


From wangyushan12 at huawei.com  Wed Dec 17 02:23:57 2025
From: wangyushan12 at huawei.com (Yushan Wang)
Date: Wed, 17 Dec 2025 18:23:57 +0800
Subject: [PATCH RFC v2 3/3] Documentation: soc cache: Add documentation to HiSilicon SoC cache
In-Reply-To: <20251217102357.1730573-1-wangyushan12@huawei.com>
References: <20251217102357.1730573-1-wangyushan12@huawei.com>
Message-ID: <20251217102357.1730573-4-wangyushan12@huawei.com>

Add necessary documentation to HiSilicon SoC cache for reference.

Signed-off-by: Yushan Wang <wangyushan12 at huawei.com>
---
 Documentation/driver-api/hisi-soc-cache.rst | 62 +++++++++++++++++++++
 Documentation/driver-api/index.rst          |  1 +
 MAINTAINERS                                 |  1 +
 3 files changed, 64 insertions(+)
 create mode 100644 Documentation/driver-api/hisi-soc-cache.rst

diff --git a/Documentation/driver-api/hisi-soc-cache.rst b/Documentation/driver-api/hisi-soc-cache.rst
new file mode 100644
index 000000000000..3c17de79bba2
--- /dev/null
+++ b/Documentation/driver-api/hisi-soc-cache.rst
@@ -0,0 +1,62 @@
+==========================
+HiSilicon SoC Cache Driver
+==========================
+
+Introduction
+============
+
+HiSilicon SoC cache provides the capabilities of preventing given range of
+memory from being evicted from L3 cache. The driver exports the lockdown API to
+userspace, allowing allocation of memory that is guranteed to be placed in L3
+cache, thus decreasing average memory access latency.
+
+Usage
+=====
+
+Kernel built with CONFIG_HISI_SOC_CACHE on will have the device file at
+`/dev/hisi_l3c`, cache operations can be performed through it.
+
+mmap():
+-------
+
+This interface can be used to allocate memory that is guranteed to not be
+evicted out of HiSilicon L3 cache. Newly allocated memory will be prefetched to
+L3 cache automatically.
+
+Users should set `PROT_READ` or `PROT_WRITE` to enable read/write to the memory
+region. Once mmap call succeeds, read and write can be applied to the memory
+region indicated by the returned pointer.
+
+Calling `munmap()` to the pointer can be used to unlock the memory regions.
+
+Restrictions of the cache lockdown are listed below:
+  - Only limited number of memory regions are supported, the exact number is
+    reported by firmware.
+  - Sum of the sizes of locked memory regions should be less than 70% of the
+    total size of cache instance.
+  - Lock/unlock can only be performed during allocation/deallocation, locking
+    existing memory is not supported yet.
+
+ioctl():
+--------
+
+This interface provides useful information of HiSilicon L3 cache.
+
+HISI_L3C_LOCK_INFO
+  - struct hisi_l3c_lock_info (read)
+
+  Gets detailed information of L3 cache lock restrictions.
+
+This ioctl call returns the detailed information of HiSilicon L3 cache lock
+restriction. Information will be presented in the form of::
+
+        struct hisi_l3c_lock_info {
+                unsigned int lock_region_num;
+                size_t lock_size;
+                bool address_alignment;
+                size_t max_lock_size;
+                size_t min_lock_size;
+        };
+
+User may perform a query before issueing cache lock to check for available
+resource.
diff --git a/Documentation/driver-api/index.rst b/Documentation/driver-api/index.rst
index 1833e6a0687e..a1d4bf2a22de 100644
--- a/Documentation/driver-api/index.rst
+++ b/Documentation/driver-api/index.rst
@@ -95,6 +95,7 @@ Subsystem-specific APIs
    generic-counter
    generic_pt
    gpio/index
+   hisi-soc-cache
    hsi
    hte/index
    hw-recoverable-errors
diff --git a/MAINTAINERS b/MAINTAINERS
index f09b718f59fd..bb79ed1f9d45 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11369,6 +11369,7 @@ F:	drivers/soc/hisilicon/kunpeng_hccs.h
 HISILICON SOC L3C DRIVER
 M:	Yushan Wang <wangyushan12 at huawei.com>
 S:	Maintained
+F:	Documentation/driver-api/hisi-soc-cache.rst
 F:	drivers/soc/hisilicon/hisi_soc_l3c.c
 F:	include/uapi/misc/hisi_l3c.h
 
-- 
2.33.0



From wangyushan12 at huawei.com  Wed Dec 17 02:23:54 2025
From: wangyushan12 at huawei.com (Yushan Wang)
Date: Wed, 17 Dec 2025 18:23:54 +0800
Subject: [PATCH RFC v2 0/3] soc: Enable cache lockdown for HiSilicon L3 cache
Message-ID: <20251217102357.1730573-1-wangyushan12@huawei.com>

Cache has been playing the transparent yet crucial role of performance
for modern computers. To fully exploit the potential of SoC cache, we
made an attempt to lockdown the HiSilicon L3 cache.

Cache lockdown means to make a memory region locked inside the L3 cache
for better access latency. The data stored in L3 cache will behave like
any other data (i.e. it still follows cache coherency protocol etc.)
except it won't be evicted unless explicitly asked to by deallocation.

Ideally locked data will have stable low access latency despite high
background stress. It is also useful for scenarios that have especially
high cache miss penalty. However, while enhancing some processes,
reserving cache resource will raise the performance problem to other
processes running on the CPUs that share the L3 cache that carries
locked data, users should be careful to do so.

I would like to ask for opinions about the possibility to make this
driver upstream, and the possible usecase of L3 cache lock within
kernel.

Signed-off-by: Yushan Wang <wangyushan12 at huawei.com>

---

Changes since v1:
- Fixed compile errors of types specified in uapi header files.
- Changed ioctl numbers to avoid confliction.
- Link to v1: https://lore.kernel.org/all/20251125080542.3721829-1-wangyushan12 at huawei.com/

Yushan Wang (3):
  soc cache: L3 cache driver for HiSilicon SoC
  soc cache: L3 cache lockdown support for HiSilicon SoC
  Documentation: soc cache: Add documentation to HiSilicon SoC cache

 Documentation/driver-api/hisi-soc-cache.rst   |  62 ++
 Documentation/driver-api/index.rst            |   1 +
 .../userspace-api/ioctl/ioctl-number.rst      |   1 +
 MAINTAINERS                                   |   7 +
 drivers/soc/hisilicon/Kconfig                 |  10 +
 drivers/soc/hisilicon/Makefile                |   2 +
 drivers/soc/hisilicon/hisi_soc_l3c.c          | 877 ++++++++++++++++++
 include/uapi/misc/hisi_l3c.h                  |  28 +
 8 files changed, 988 insertions(+)
 create mode 100644 Documentation/driver-api/hisi-soc-cache.rst
 create mode 100644 drivers/soc/hisilicon/hisi_soc_l3c.c
 create mode 100644 include/uapi/misc/hisi_l3c.h

-- 
2.33.0



From wangyushan12 at huawei.com  Wed Dec 17 02:23:55 2025
From: wangyushan12 at huawei.com (Yushan Wang)
Date: Wed, 17 Dec 2025 18:23:55 +0800
Subject: [PATCH RFC v2 1/3] soc cache: L3 cache driver for HiSilicon SoC
In-Reply-To: <20251217102357.1730573-1-wangyushan12@huawei.com>
References: <20251217102357.1730573-1-wangyushan12@huawei.com>
Message-ID: <20251217102357.1730573-2-wangyushan12@huawei.com>

The driver will create a file of `/dev/hisi_l3c` on init, mmap
operations to it will allocate a memory region that is guaranteed to be
placed in L3 cache.

The driver also provides unmap() to deallocated the locked memory.

The driver also provides an ioctl interface for user to get cache lock
information, such as lock restrictions and locked sizes.

Signed-off-by: Yushan Wang <wangyushan12 at huawei.com>
---
 .../userspace-api/ioctl/ioctl-number.rst      |   1 +
 MAINTAINERS                                   |   6 +
 drivers/soc/hisilicon/Kconfig                 |  10 +
 drivers/soc/hisilicon/Makefile                |   2 +
 drivers/soc/hisilicon/hisi_soc_l3c.c          | 359 ++++++++++++++++++
 include/uapi/misc/hisi_l3c.h                  |  28 ++
 6 files changed, 406 insertions(+)
 create mode 100644 drivers/soc/hisilicon/hisi_soc_l3c.c
 create mode 100644 include/uapi/misc/hisi_l3c.h

diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst
index 7232b3544cec..439c5bcbfa94 100644
--- a/Documentation/userspace-api/ioctl/ioctl-number.rst
+++ b/Documentation/userspace-api/ioctl/ioctl-number.rst
@@ -387,6 +387,7 @@ Code  Seq#    Include File                                             Comments
                                                                        <mailto:linux-hyperv at vger.kernel.org>
 0xBA  00-0F  uapi/linux/liveupdate.h                                   Pasha Tatashin
                                                                        <mailto:pasha.tatashin at soleen.com>
+0xBB  all    uapi/misc/hisi_soc_cache.h                                HiSilicon SoC cache driver
 0xC0  00-0F  linux/usb/iowarrior.h
 0xCA  00-0F  uapi/misc/cxl.h                                           Dead since 6.15
 0xCA  10-2F  uapi/misc/ocxl.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 5b11839cba9d..f09b718f59fd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11366,6 +11366,12 @@ F:	Documentation/ABI/testing/sysfs-devices-platform-kunpeng_hccs
 F:	drivers/soc/hisilicon/kunpeng_hccs.c
 F:	drivers/soc/hisilicon/kunpeng_hccs.h
 
+HISILICON SOC L3C DRIVER
+M:	Yushan Wang <wangyushan12 at huawei.com>
+S:	Maintained
+F:	drivers/soc/hisilicon/hisi_soc_l3c.c
+F:	include/uapi/misc/hisi_l3c.h
+
 HISILICON LPC BUS DRIVER
 M:	Jay Fang <f.fangjian at huawei.com>
 S:	Maintained
diff --git a/drivers/soc/hisilicon/Kconfig b/drivers/soc/hisilicon/Kconfig
index 6d7c244d2e78..ea16dffccd5e 100644
--- a/drivers/soc/hisilicon/Kconfig
+++ b/drivers/soc/hisilicon/Kconfig
@@ -21,4 +21,14 @@ config KUNPENG_HCCS
 	  health status and port information of HCCS, or reducing system
 	  power consumption on Kunpeng SoC.
 
+config HISI_SOC_L3C
+	bool "HiSilicon L3 Cache device driver"
+	depends on ARM64 && ACPI || COMPILE_TEST
+	help
+	  This driver provides the functions to lock L3 cache entries from
+	  being evicted for better performance.
+
+	  This driver can be built as a module. If so, the module will be
+	  called hisi_soc_l3c.
+
 endmenu
diff --git a/drivers/soc/hisilicon/Makefile b/drivers/soc/hisilicon/Makefile
index 226e747e70d6..16ff2c73c4a5 100644
--- a/drivers/soc/hisilicon/Makefile
+++ b/drivers/soc/hisilicon/Makefile
@@ -1,2 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_KUNPENG_HCCS)	+= kunpeng_hccs.o
+
+obj-$(CONFIG_HISI_SOC_L3C)	+= hisi_soc_l3c.o
diff --git a/drivers/soc/hisilicon/hisi_soc_l3c.c b/drivers/soc/hisilicon/hisi_soc_l3c.c
new file mode 100644
index 000000000000..2c196c4dfff1
--- /dev/null
+++ b/drivers/soc/hisilicon/hisi_soc_l3c.c
@@ -0,0 +1,359 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for HiSilicon L3 cache.
+ *
+ * Copyright (c) 2025 HiSilicon Technologies Co., Ltd.
+ * Author: Yushan Wang <wangyushan12 at huawei.com>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/cleanup.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/spinlock_types.h>
+#include <linux/types.h>
+
+#include <asm/cputype.h>
+
+#include <uapi/misc/hisi_l3c.h>
+
+#define to_hisi_l3c(p) container_of((p), struct hisi_l3c, comp)
+
+/**
+ * struct hisi_soc_comp - Struct of HiSilicon SoC cache components.
+ *
+ * @node: list node of hisi_soc_comp_list.
+ * @ops: possible operations a component may perform.
+ * @affinity_mask: cpus that associate with this component.
+ * @private: component specific data.
+ */
+struct hisi_soc_comp {
+	struct list_head node;
+	struct hisi_soc_comp_ops *ops;
+	cpumask_t affinity_mask;
+	void *private;
+};
+
+/**
+ * struct hisi_soc_comp_ops - Callbacks for SoC cache drivers to handle
+ *			      operation requests.
+ *
+ * @do_lock: lock certain region of L3 cache from being evicted.
+ * @poll_lock_done: check if the lock operation has succeeded.
+ * @do_unlock: unlock the locked region of L3 cache back to normal.
+ * @poll_unlock_done: check if the unlock operation has succeeded.
+	      operation requests.
+ *
+ * Operations are decoupled into two phases so that framework does not have
+ * to wait for one operation to finish before calling the next when multiple
+ * hardwares onboard.
+ *
+ * Implementers must implement the functions in pairs.  Implementation should
+ * return -EBUSY when:
+ * - insufficient resources are available to perform the operation.
+ * - previously raised operation is not finished.
+ * - new operations (do_lock(), do_unlock() etc.) to the same address
+ *   before corresponding done functions being called.
+ */
+struct hisi_soc_comp_ops {
+	int (*do_lock)(struct hisi_soc_comp *comp, phys_addr_t addr, size_t size);
+	int (*poll_lock_done)(struct hisi_soc_comp *comp, phys_addr_t addr, size_t size);
+	int (*do_unlock)(struct hisi_soc_comp *comp, phys_addr_t addr);
+	int (*poll_unlock_done)(struct hisi_soc_comp *comp, phys_addr_t addr);
+};
+
+struct hisi_l3c_lock_region {
+	/* physical address of the arena allocated for aligned address */
+	unsigned long arena_start;
+	/* VMA region of locked memory for future release */
+	unsigned long vm_start;
+	unsigned long vm_end;
+	phys_addr_t addr;
+	size_t size;
+	/* Return value of cache lock call */
+	int status;
+	int cpu;
+};
+
+struct hisi_soc_comp_list {
+	struct list_head node;
+	/* protects list of HiSilicon SoC cache components */
+	spinlock_t lock;
+};
+
+static struct hisi_soc_comp_list l3c_devs;
+
+static int hisi_l3c_lock(int cpu, phys_addr_t addr, size_t size)
+{
+	struct hisi_soc_comp *comp;
+	int ret;
+
+	guard(spinlock)(&l3c_devs.lock);
+
+	/* When there is no instance onboard, no locked memory is available. */
+	if (list_empty(&l3c_devs.node))
+		return -ENOMEM;
+
+	/* Lock need to be performed on each channel of associated L3 cache. */
+	list_for_each_entry(comp, &l3c_devs.node, node) {
+		if (!cpumask_test_cpu(cpu, &comp->affinity_mask))
+			continue;
+		ret = comp->ops->do_lock(comp, addr, size);
+		if (ret)
+			return ret;
+	}
+
+	list_for_each_entry(comp, &l3c_devs.node, node) {
+		if (!cpumask_test_cpu(cpu, &comp->affinity_mask))
+			continue;
+		ret = comp->ops->poll_lock_done(comp, addr, size);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int hisi_l3c_unlock(int cpu, phys_addr_t addr)
+{
+	struct hisi_soc_comp *comp;
+	int ret;
+
+	guard(spinlock)(&l3c_devs.lock);
+
+	if (list_empty(&l3c_devs.node))
+		return -EINVAL;
+
+	/* Perform unlock on each channel of associated L3 cache. */
+	list_for_each_entry(comp, &l3c_devs.node, node) {
+		if (!cpumask_test_cpu(cpu, &comp->affinity_mask))
+			continue;
+		ret = comp->ops->do_unlock(comp, addr);
+		if (ret)
+			return ret;
+	}
+
+	list_for_each_entry(comp, &l3c_devs.node, node) {
+		if (!cpumask_test_cpu(cpu, &comp->affinity_mask))
+			continue;
+		ret = comp->ops->poll_unlock_done(comp, addr);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static void hisi_soc_comp_add(struct hisi_soc_comp *comp)
+{
+	guard(spinlock)(&l3c_devs.lock);
+	list_add_tail(&comp->node, &l3c_devs.node);
+}
+
+/* Null @comp means to delete all instances. */
+static int hisi_soc_comp_del(struct hisi_soc_comp *comp)
+{
+	struct hisi_soc_comp *entry, *tmp;
+
+	guard(spinlock)(&l3c_devs.lock);
+	list_for_each_entry_safe(entry, tmp, &l3c_devs.node, node) {
+		if (comp && comp != entry)
+			continue;
+
+		list_del(&entry->node);
+
+		/* Only continue to delete nodes when @comp is NULL */
+		if (comp)
+			break;
+	}
+
+	return 0;
+}
+
+static void hisi_l3c_vm_open(struct vm_area_struct *vma)
+{
+	struct hisi_l3c_lock_region *clr = vma->vm_private_data;
+
+	/*
+	 * Only perform cache lock when the vma passed in is created in
+	 * hisi_l3c_mmap.
+	 */
+	if (clr->vm_start != vma->vm_start || clr->vm_end != vma->vm_end)
+		return;
+
+	clr->status = hisi_l3c_lock(clr->cpu, clr->addr, clr->size);
+}
+
+static void hisi_l3c_vm_close(struct vm_area_struct *vma)
+{
+	struct hisi_l3c_lock_region *clr = vma->vm_private_data;
+	int order = get_order(clr->size);
+
+	/*
+	 * Only perform cache unlock when the vma passed in is created
+	 * in hisi_l3c_mmap.
+	 */
+	if (clr->vm_start != vma->vm_start || clr->vm_end != vma->vm_end)
+		return;
+
+	hisi_l3c_unlock(clr->cpu, clr->addr);
+
+	free_contig_range(PHYS_PFN(clr->addr), 1 << order);
+	kfree(clr);
+	vma->vm_private_data = NULL;
+}
+
+/* mremap operation is not supported for HiSilicon SoC cache. */
+static int hisi_l3c_vm_mremap(struct vm_area_struct *vma)
+{
+	struct hisi_l3c_lock_region *clr = vma->vm_private_data;
+
+	/*
+	 * vma region size will be changed as requested by mremap despite the
+	 * callback failure in this function.  Thus, change the vma region
+	 * stored in clr according to the parameters to verify if the pages
+	 * should be freed when unmapping.
+	 */
+	clr->vm_end = clr->vm_start + (vma->vm_end - vma->vm_start);
+	pr_err("mremap for HiSilicon SoC locked cache is not supported\n");
+
+	return -EOPNOTSUPP;
+}
+
+static int hisi_l3c_may_split(struct vm_area_struct *area, unsigned long addr)
+{
+	pr_err("HiSilicon SoC locked cache may not be split.\n");
+	return -EINVAL;
+}
+
+static const struct vm_operations_struct hisi_l3c_vm_ops = {
+	.open = hisi_l3c_vm_open,
+	.close = hisi_l3c_vm_close,
+	.may_split = hisi_l3c_may_split,
+	.mremap = hisi_l3c_vm_mremap,
+};
+
+static int hisi_l3c_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	unsigned long size = vma->vm_end - vma->vm_start;
+	int order = get_order(size);
+	unsigned long addr;
+	struct page *pg;
+	int ret;
+
+	struct hisi_l3c_lock_region *clr __free(kfree) = kzalloc(sizeof(*clr), GFP_KERNEL);
+	if (!clr)
+		return -ENOMEM;
+
+	/* Continuous physical memory is required for L3 cache lock. */
+	pg = alloc_contig_pages(1 << order, GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
+				cpu_to_node(smp_processor_id()), NULL);
+	if (!pg)
+		return -ENOMEM;
+
+	addr = page_to_phys(pg);
+	*clr = (struct hisi_l3c_lock_region) {
+		.addr = addr,
+		.size = size,
+		.cpu = smp_processor_id(),
+		/* vma should not be moved, store here for validation */
+		.vm_start = vma->vm_start,
+		.vm_end = vma->vm_end,
+	};
+
+	vm_flags_set(vma, VM_DONTCOPY | VM_DONTEXPAND);
+	vma->vm_ops = &hisi_l3c_vm_ops;
+	vma->vm_private_data = clr;
+
+	hisi_l3c_vm_ops.open(vma);
+	if (clr->status) {
+		ret = clr->status;
+		goto out_page;
+	}
+
+	ret = remap_pfn_range(vma, vma->vm_start, PFN_DOWN(addr), size,
+			      vma->vm_page_prot);
+	if (ret)
+		goto out_page;
+
+	/* Save clr from being freed when lock succeeds. */
+	vma->vm_private_data = no_free_ptr(clr);
+
+	return 0;
+
+out_page:
+	free_contig_range(PHYS_PFN(clr->addr), 1 << order);
+	return ret;
+}
+
+static int hisi_l3c_lock_restriction(unsigned long arg)
+{
+	void __user *uarg = (void __user *)arg;
+	int cpu = smp_processor_id();
+	struct hisi_soc_comp *comp;
+
+	if (list_empty(&l3c_devs.node))
+		return -ENODEV;
+
+	list_for_each_entry(comp, &l3c_devs.node, node) {
+		if (!cpumask_test_cpu(cpu, &comp->affinity_mask))
+			continue;
+
+		if (!comp->private)
+			return -ENOENT;
+
+		if (copy_to_user(uarg, comp->private, sizeof(struct hisi_l3c_lock_info)))
+			return -EFAULT;
+
+		return 0;
+	}
+
+	return -ENODEV;
+}
+
+static long hisi_l3c_ioctl(struct file *file, u32 cmd, unsigned long arg)
+{
+	switch (cmd) {
+	case HISI_L3C_LOCK_INFO:
+		return hisi_l3c_lock_restriction(arg);
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct file_operations l3c_dev_fops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = hisi_l3c_ioctl,
+	.mmap = hisi_l3c_mmap,
+};
+
+static struct miscdevice l3c_miscdev = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "hisi_l3c",
+	.fops = &l3c_dev_fops,
+	.mode = 0600,
+};
+
+static int __init hisi_l3c_init(void)
+{
+	spin_lock_init(&l3c_devs.lock);
+	INIT_LIST_HEAD(&l3c_devs.node);
+
+	return misc_register(&l3c_miscdev);
+}
+module_init(hisi_l3c_init);
+
+static void __exit hisi_l3c_exit(void)
+{
+	misc_deregister(&l3c_miscdev);
+	hisi_soc_comp_del(NULL);
+}
+module_exit(hisi_l3c_exit);
+
+MODULE_DESCRIPTION("Hisilicon L3 Cache Driver");
+MODULE_AUTHOR("Yushan Wang <wangyushan12 at huawei.com>");
+MODULE_LICENSE("GPL");
diff --git a/include/uapi/misc/hisi_l3c.h b/include/uapi/misc/hisi_l3c.h
new file mode 100644
index 000000000000..6555be18aa1c
--- /dev/null
+++ b/include/uapi/misc/hisi_l3c.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later WITH Linux-syscall-note */
+/* Copyright (c) 2024 HiSilicon Technologies Co., Ltd. */
+#ifndef _UAPI_HISI_SOC_L3C_H
+#define _UAPI_HISI_SOC_L3C_H
+
+#include <linux/types.h>
+
+/* HISI_L3C_INFO: cache lock info for HiSilicon SoC */
+#define HISI_L3C_LOCK_INFO	_IOW(0xBB, 1, unsigned long)
+
+/**
+ * struct hisi_l3c_info - User data for hisi cache operates.
+ * @lock_region_num: available locked memory region on a L3C instance
+ * @lock_size: available size to be locked of the L3C instance.
+ * @address_alignment: if the L3C lock requires locked region physical start
+ *		       address to be aligned with the memory region size.
+ * @max_lock_size: maximum locked memory size on a L3C instance.
+ * @min_lock_size: minimum locked memory size on a L3C instance.
+ */
+struct hisi_l3c_lock_info {
+	__u32 lock_region_num;
+	__u64 lock_size;
+	__u8 address_alignment;
+	__u64 max_lock_size;
+	__u64 min_lock_size;
+};
+
+#endif
-- 
2.33.0



From wangyushan12 at huawei.com  Wed Dec 17 02:23:56 2025
From: wangyushan12 at huawei.com (Yushan Wang)
Date: Wed, 17 Dec 2025 18:23:56 +0800
Subject: [PATCH RFC v2 2/3] soc cache: L3 cache lockdown support for HiSilicon SoC
In-Reply-To: <20251217102357.1730573-1-wangyushan12@huawei.com>
References: <20251217102357.1730573-1-wangyushan12@huawei.com>
Message-ID: <20251217102357.1730573-3-wangyushan12@huawei.com>

This driver implements the interface exposed by framework, passes cache
lock/unlock requests to hardware.

The number of locked memory region is limited according to firmware,
and the total size of locked memory regions must be less than 70% of
cache size.

Signed-off-by: Yushan Wang <wangyushan12 at huawei.com>
---
 drivers/soc/hisilicon/hisi_soc_l3c.c | 520 ++++++++++++++++++++++++++-
 1 file changed, 519 insertions(+), 1 deletion(-)

diff --git a/drivers/soc/hisilicon/hisi_soc_l3c.c b/drivers/soc/hisilicon/hisi_soc_l3c.c
index 2c196c4dfff1..1e3419436173 100644
--- a/drivers/soc/hisilicon/hisi_soc_l3c.c
+++ b/drivers/soc/hisilicon/hisi_soc_l3c.c
@@ -8,19 +8,49 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/acpi.h>
 #include <linux/cleanup.h>
+#include <linux/cpuhotplug.h>
 #include <linux/init.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/mm.h>
 #include <linux/miscdevice.h>
 #include <linux/module.h>
+#include <linux/platform_device.h>
 #include <linux/spinlock.h>
 #include <linux/spinlock_types.h>
 #include <linux/types.h>
+#include <linux/xarray.h>
 
 #include <asm/cputype.h>
 
 #include <uapi/misc/hisi_l3c.h>
 
+#define HISI_L3C_LOCK_CTRL	0x0530
+#define HISI_L3C_LOCK_AREA	0x0534
+#define HISI_L3C_LOCK_START_L	0x0538
+#define HISI_L3C_LOCK_START_H	0x053C
+
+#define HISI_L3C_DYNAMIC_AUCTRL	0x0404
+
+#define HISI_L3C_LOCK_CTRL_POLL_GAP_US	10
+#define HISI_L3C_LOCK_CTRL_POLL_MAX_US	10000
+
+/* L3C control register bit definition */
+#define HISI_L3C_LOCK_CTRL_LOCK_EN		BIT(0)
+#define HISI_L3C_LOCK_CTRL_LOCK_DONE		BIT(1)
+#define HISI_L3C_LOCK_CTRL_UNLOCK_EN		BIT(2)
+#define HISI_L3C_LOCK_CTRL_UNLOCK_DONE		BIT(3)
+
+#define HISI_L3C_LOCK_MIN_SIZE		(1 * 1024 * 1024)
+#define HISI_L3_CACHE_LINE_SIZE		64
+
+/* Allow maximum 70% of cache locked. */
+#define HISI_L3C_MAX_LOCK_SIZE(size)	((size) / 10 * 7)
+
+#define l3c_lock_reg_offset(reg, set)	((reg) + 16 * (set))
+
 #define to_hisi_l3c(p) container_of((p), struct hisi_l3c, comp)
 
 /**
@@ -85,8 +115,280 @@ struct hisi_soc_comp_list {
 	spinlock_t lock;
 };
 
+struct hisi_l3c {
+	struct hisi_soc_comp comp;
+	cpumask_t associated_cpus;
+
+	/* Stores the first address locked by each register sets. */
+	struct xarray lock_sets;
+	/* Locks lock_sets to forbid overlapping access. */
+	spinlock_t reg_lock;
+
+	struct hlist_node node;
+	void __iomem *base;
+
+	/* ID of Super CPU cluster on where the L3 cache locates. */
+	int sccl_id;
+	/* ID of CPU cluster where L3 cache is located. */
+	int ccl_id;
+};
+
+static int hisi_l3c_cpuhp_state;
+
 static struct hisi_soc_comp_list l3c_devs;
 
+/**
+ * hisi_l3c_alloc_lock_reg_set - Allocate an available control register set
+ *				     of L3 cache for lock & unlock operations.
+ * @l3c:	The L3C instance on which the register set will be allocated.
+ * @addr:	The address to be locked.
+ * @size:	The size to be locked.
+ *
+ * @return:
+ *   - -EBUSY: If there is no available register sets.
+ *   - -ENOMEM: If there is no available memory for lock region struct.
+ *   - -EINVAL: If there is no available cache size for lock.
+ *   - 0: If allocation succeeds.
+ *
+ * Maintains the resource of control registers of L3 cache.  On allocation,
+ * the index of a spare set of registers is returned, then the address is
+ * stored inside for future match of unlock operation.
+ */
+static int hisi_l3c_alloc_lock_reg_set(struct hisi_l3c *l3c, phys_addr_t addr, size_t size)
+{
+	struct hisi_l3c_lock_info *info = l3c->comp.private;
+	struct hisi_l3c_lock_region *lr;
+	void *entry;
+	int idx, ret;
+
+	if (size > info->lock_size)
+		return -EINVAL;
+
+	for (idx = 0; idx < info->lock_region_num; ++idx) {
+		entry = xa_load(&l3c->lock_sets, idx);
+		if (!entry)
+			break;
+	}
+
+	if (idx > info->lock_region_num)
+		return -EBUSY;
+
+	lr = kzalloc(sizeof(*lr), GFP_KERNEL);
+	if (!lr)
+		return -ENOMEM;
+
+	lr->addr = addr;
+	lr->size = size;
+
+	ret = xa_alloc(&l3c->lock_sets, &idx, lr, xa_limit_31b, GFP_KERNEL);
+	if (ret) {
+		kfree(lr);
+		return ret;
+	}
+
+	info->lock_size -= size;
+	info->lock_region_num -= 1;
+
+	return idx;
+}
+
+/**
+ * hisi_l3c_get_locked_reg_set - Get the index of an allocated register set
+ *				     by locked address.
+ * @l3c:	The L3C instance on which the register set is allocated.
+ * @addr:	The locked address.
+ *
+ * @return:
+ *   - >= 0: index of register set which controls locked memory region of @addr.
+ *   - -EINVAL: If @addr is not locked in this cache.
+ */
+static int hisi_l3c_get_locked_reg_set(struct hisi_l3c *l3c, phys_addr_t addr)
+{
+	struct hisi_l3c_lock_region *entry;
+	unsigned long idx;
+
+	xa_for_each(&l3c->lock_sets, idx, entry) {
+		if (entry->addr == addr)
+			return idx;
+	}
+	return -EINVAL;
+}
+
+/**
+ * hisi_l3c_free_lock_reg_set - Free an allocated register set by locked
+ *				    address.
+ *
+ * @l3c:	The L3C instance on which the register set is allocated.
+ * @regset:	ID of Register set to be freed.
+ */
+static void hisi_l3c_free_lock_reg_set(struct hisi_l3c *l3c, int regset)
+{
+	struct hisi_l3c_lock_info *info = l3c->comp.private;
+	struct hisi_l3c_lock_region *entry;
+
+	if (regset < 0)
+		return;
+
+	entry = xa_erase(&l3c->lock_sets, regset);
+	if (!entry)
+		return;
+
+	info->lock_size += entry->size;
+	info->lock_region_num += 1;
+	kfree(entry);
+}
+
+static bool hisi_l3c_lock_wait_finished(struct hisi_l3c *l3c, int regset)
+{
+	void *reg = l3c->base + l3c_lock_reg_offset(HISI_L3C_LOCK_CTRL, regset);
+	/* Wait until neither lock or unlock operation is going on. */
+	u32 mask = HISI_L3C_LOCK_CTRL_LOCK_DONE | HISI_L3C_LOCK_CTRL_UNLOCK_DONE;
+	u32 val;
+
+	/*
+	 * Lock/unlock done bits are initially 0 if no lock operation was ever
+	 * issued, and will be set until next operation comes.
+	 * Check if this is the first lock operation after boot by checking if
+	 * the register is 0. If so, proceed with the operation.
+	 */
+	val = readl(reg);
+	if (!val)
+		return true;
+
+	return !readl_poll_timeout_atomic(reg, val, val & mask,
+			HISI_L3C_LOCK_CTRL_POLL_GAP_US,
+			HISI_L3C_LOCK_CTRL_POLL_MAX_US);
+}
+
+static int hisi_l3c_do_lock(struct hisi_soc_comp *comp, phys_addr_t addr, size_t size)
+{
+	struct hisi_l3c *l3c = to_hisi_l3c(comp);
+	struct hisi_l3c_lock_info *info = l3c->comp.private;
+	void *base = l3c->base;
+	int regset;
+	u32 ctrl;
+
+	if (info->address_alignment && addr % size != 0)
+		return -EINVAL;
+
+	if (size < info->min_lock_size || size > info->max_lock_size)
+		return -EINVAL;
+
+	guard(spinlock)(&l3c->reg_lock);
+
+	regset = hisi_l3c_alloc_lock_reg_set(l3c, addr, size);
+	if (regset < 0)
+		return -EBUSY;
+
+	if (!hisi_l3c_lock_wait_finished(l3c, regset)) {
+		hisi_l3c_free_lock_reg_set(l3c, regset);
+		return -EBUSY;
+	}
+
+	writel(lower_32_bits(addr),
+	       base + l3c_lock_reg_offset(HISI_L3C_LOCK_START_L, regset));
+	writel(upper_32_bits(addr),
+	       base + l3c_lock_reg_offset(HISI_L3C_LOCK_START_H, regset));
+	writel(size, base + l3c_lock_reg_offset(HISI_L3C_LOCK_AREA, regset));
+
+	ctrl = readl(base + HISI_L3C_DYNAMIC_AUCTRL);
+	ctrl |= BIT(regset);
+	writel(ctrl, base + HISI_L3C_DYNAMIC_AUCTRL);
+
+	ctrl = readl(base + l3c_lock_reg_offset(HISI_L3C_LOCK_CTRL, regset));
+	ctrl = (ctrl | HISI_L3C_LOCK_CTRL_LOCK_EN) &
+		~HISI_L3C_LOCK_CTRL_UNLOCK_EN;
+	writel(ctrl, base + l3c_lock_reg_offset(HISI_L3C_LOCK_CTRL, regset));
+
+	return 0;
+}
+
+static int hisi_l3c_poll_lock_done(struct hisi_soc_comp *comp, phys_addr_t addr, size_t size)
+{
+	struct hisi_l3c *l3c = to_hisi_l3c(comp);
+	int regset;
+
+	guard(spinlock)(&l3c->reg_lock);
+
+	regset = hisi_l3c_get_locked_reg_set(l3c, addr);
+	if (regset < 0)
+		return -EINVAL;
+
+	if (!hisi_l3c_lock_wait_finished(l3c, regset))
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int hisi_l3c_do_unlock(struct hisi_soc_comp *comp, phys_addr_t addr)
+{
+	struct hisi_l3c *l3c = to_hisi_l3c(comp);
+	void *base = l3c->base;
+	int regset;
+	u32 ctrl;
+
+	guard(spinlock)(&l3c->reg_lock);
+
+	regset = hisi_l3c_get_locked_reg_set(l3c, addr);
+	if (regset < 0)
+		return -EINVAL;
+
+	if (!hisi_l3c_lock_wait_finished(l3c, regset))
+		return -EBUSY;
+
+	ctrl = readl(base + HISI_L3C_DYNAMIC_AUCTRL);
+	ctrl &= ~BIT(regset);
+	writel(ctrl, base + HISI_L3C_DYNAMIC_AUCTRL);
+
+	ctrl = readl(base + l3c_lock_reg_offset(HISI_L3C_LOCK_CTRL, regset));
+	ctrl = (ctrl | HISI_L3C_LOCK_CTRL_UNLOCK_EN) &
+		~HISI_L3C_LOCK_CTRL_LOCK_EN;
+	writel(ctrl, base + l3c_lock_reg_offset(HISI_L3C_LOCK_CTRL, regset));
+
+	return 0;
+}
+
+static int hisi_l3c_poll_unlock_done(struct hisi_soc_comp *comp, phys_addr_t addr)
+{
+	struct hisi_l3c *l3c = to_hisi_l3c(comp);
+	int regset;
+
+	guard(spinlock)(&l3c->reg_lock);
+
+	regset = hisi_l3c_get_locked_reg_set(l3c, addr);
+	if (regset < 0)
+		return -EINVAL;
+
+	if (!hisi_l3c_lock_wait_finished(l3c, regset))
+		return -ETIMEDOUT;
+
+	hisi_l3c_free_lock_reg_set(l3c, regset);
+
+	return 0;
+}
+
+static void hisi_l3c_remove_locks(struct hisi_l3c *l3c)
+{
+	void *base = l3c->base;
+	unsigned long regset;
+	void *entry;
+
+	guard(spinlock)(&l3c->reg_lock);
+
+	xa_for_each(&l3c->lock_sets, regset, entry) {
+		int timeout;
+		u32 ctrl;
+
+		ctrl = readl(base + l3c_lock_reg_offset(HISI_L3C_LOCK_CTRL, regset));
+		ctrl = (ctrl | HISI_L3C_LOCK_CTRL_UNLOCK_EN) & ~HISI_L3C_LOCK_CTRL_LOCK_EN;
+		writel(ctrl, base + l3c_lock_reg_offset(HISI_L3C_LOCK_CTRL, regset));
+
+		timeout = hisi_l3c_lock_wait_finished(l3c, regset);
+		if (timeout)
+			pr_err("failed to remove %lu-th cache lock.\n", regset);
+	}
+}
+
 static int hisi_l3c_lock(int cpu, phys_addr_t addr, size_t size)
 {
 	struct hisi_soc_comp *comp;
@@ -315,6 +617,196 @@ static int hisi_l3c_lock_restriction(unsigned long arg)
 	return -ENODEV;
 }
 
+static int hisi_l3c_init_lock_capacity(struct hisi_l3c *l3c, struct device *dev)
+{
+	int ret;
+	u32 val;
+
+	struct hisi_l3c_lock_info *info __free(kfree) = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	ret = device_property_read_u32(dev, "hisilicon,l3c-lockregion-num", &val);
+	if (ret || val <= 0)
+		return -EINVAL;
+
+	info->lock_region_num = val;
+
+	ret = device_property_read_u32(dev, "hisilicon,l3c-max-single-lockregion-size", &val);
+	if (ret || val <= 0)
+		return -EINVAL;
+
+	info->lock_size = HISI_L3C_MAX_LOCK_SIZE(val);
+	info->address_alignment = info->lock_region_num == 1;
+	info->max_lock_size = HISI_L3C_MAX_LOCK_SIZE(val);
+	info->min_lock_size = info->lock_region_num == 1
+					? HISI_L3C_LOCK_MIN_SIZE
+					: HISI_L3_CACHE_LINE_SIZE;
+
+	l3c->comp.private = no_free_ptr(info);
+
+	return 0;
+}
+
+static int hisi_l3c_init_topology(struct hisi_l3c *l3c, struct device *dev)
+{
+	l3c->sccl_id = -1;
+	l3c->ccl_id = -1;
+
+	if (device_property_read_u32(dev, "hisilicon,scl-id", &l3c->sccl_id) ||
+	    l3c->sccl_id < 0)
+		return -EINVAL;
+
+	if (device_property_read_u32(dev, "hisilicon,ccl-id", &l3c->ccl_id) ||
+	    l3c->ccl_id < 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void hisi_init_associated_cpus(struct hisi_l3c *l3c)
+{
+	if (!cpumask_empty(&l3c->associated_cpus))
+		return;
+	cpumask_clear(&l3c->associated_cpus);
+	cpumask_copy(&l3c->comp.affinity_mask, &l3c->associated_cpus);
+}
+
+static struct hisi_soc_comp_ops hisi_comp_ops = {
+	.do_lock = hisi_l3c_do_lock,
+	.poll_lock_done = hisi_l3c_poll_lock_done,
+	.do_unlock = hisi_l3c_do_unlock,
+	.poll_unlock_done = hisi_l3c_poll_unlock_done,
+};
+
+static struct hisi_soc_comp hisi_comp = {
+	.ops = &hisi_comp_ops,
+};
+
+static int hisi_l3c_probe(struct platform_device *pdev)
+{
+	struct hisi_l3c *l3c;
+	struct resource *mem;
+	int ret;
+
+	l3c = devm_kzalloc(&pdev->dev, sizeof(*l3c), GFP_KERNEL);
+	if (!l3c)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, l3c);
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem)
+		return -ENODEV;
+
+	l3c->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
+	if (IS_ERR_OR_NULL(l3c->base))
+		return PTR_ERR(l3c->base);
+
+	l3c->comp = hisi_comp;
+	spin_lock_init(&l3c->reg_lock);
+	xa_init_flags(&l3c->lock_sets, XA_FLAGS_ALLOC);
+
+	ret = hisi_l3c_init_lock_capacity(l3c, &pdev->dev);
+	if (ret)
+		goto err_xa;
+
+	hisi_init_associated_cpus(l3c);
+
+	ret = hisi_l3c_init_topology(l3c, &pdev->dev);
+	if (ret)
+		goto err_xa;
+
+	ret = cpuhp_state_add_instance(hisi_l3c_cpuhp_state, &l3c->node);
+	if (ret)
+		goto err_xa;
+
+	hisi_soc_comp_add(&l3c->comp);
+
+	return 0;
+
+err_xa:
+	xa_destroy(&l3c->lock_sets);
+	return ret;
+}
+
+static void hisi_l3c_remove(struct platform_device *pdev)
+{
+	struct hisi_l3c *l3c = platform_get_drvdata(pdev);
+	unsigned long idx;
+	struct hisi_l3c_lock_region *entry;
+
+	hisi_l3c_remove_locks(l3c);
+
+	hisi_soc_comp_del(&l3c->comp);
+
+	cpuhp_state_remove_instance_nocalls(hisi_l3c_cpuhp_state, &l3c->node);
+
+	xa_for_each(&l3c->lock_sets, idx, entry)
+		entry = xa_erase(&l3c->lock_sets, idx);
+
+	xa_destroy(&l3c->lock_sets);
+}
+
+static void hisi_read_sccl_and_ccl_id(int *scclp, int *cclp)
+{
+	u64 mpidr = read_cpuid_mpidr();
+	int aff3 = MPIDR_AFFINITY_LEVEL(mpidr, 3);
+	int aff2 = MPIDR_AFFINITY_LEVEL(mpidr, 2);
+	int aff1 = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+	int sccl, ccl;
+
+	if (mpidr & MPIDR_MT_BITMASK) {
+		sccl = aff3;
+		ccl = aff2;
+	} else {
+		sccl = aff2;
+		ccl = aff1;
+	}
+
+	*scclp = sccl;
+	*cclp = ccl;
+}
+
+static bool hisi_l3c_is_associated(struct hisi_l3c *l3c)
+{
+	int sccl_id, ccl_id;
+
+	hisi_read_sccl_and_ccl_id(&sccl_id, &ccl_id);
+
+	return sccl_id == l3c->sccl_id && ccl_id == l3c->ccl_id;
+}
+
+static int hisi_l3c_online_cpu(unsigned int cpu, struct hlist_node *node)
+{
+	struct hisi_l3c *l3c = hlist_entry_safe(node, struct hisi_l3c, node);
+
+	if (!cpumask_test_cpu(cpu, &l3c->associated_cpus)) {
+		if (!(hisi_l3c_is_associated(l3c)))
+			return 0;
+
+		cpumask_set_cpu(cpu, &l3c->associated_cpus);
+		cpumask_copy(&l3c->comp.affinity_mask,
+			     &l3c->associated_cpus);
+	}
+	return 0;
+}
+
+static const struct acpi_device_id hisi_l3c_acpi_match[] = {
+	{ "HISI0501", },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, hisi_l3c_acpi_match);
+
+static struct platform_driver hisi_l3c_driver = {
+	.driver = {
+		.name = "hisi_l3c",
+		.acpi_match_table = hisi_l3c_acpi_match,
+	},
+	.probe = hisi_l3c_probe,
+	.remove = hisi_l3c_remove,
+};
+
 static long hisi_l3c_ioctl(struct file *file, u32 cmd, unsigned long arg)
 {
 	switch (cmd) {
@@ -340,15 +832,41 @@ static struct miscdevice l3c_miscdev = {
 
 static int __init hisi_l3c_init(void)
 {
+	int ret;
+
 	spin_lock_init(&l3c_devs.lock);
 	INIT_LIST_HEAD(&l3c_devs.node);
 
-	return misc_register(&l3c_miscdev);
+	ret = misc_register(&l3c_miscdev);
+	if (ret)
+		return ret;
+
+	ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "hisi_l3c",
+				      hisi_l3c_online_cpu, NULL);
+	if (ret < 0)
+		goto err_hp;
+
+	hisi_l3c_cpuhp_state = ret;
+
+	ret = platform_driver_register(&hisi_l3c_driver);
+	if (ret)
+		goto err_plat;
+
+	return 0;
+
+err_plat:
+	cpuhp_remove_multi_state(CPUHP_AP_ONLINE_DYN);
+err_hp:
+	misc_deregister(&l3c_miscdev);
+
+	return ret;
 }
 module_init(hisi_l3c_init);
 
 static void __exit hisi_l3c_exit(void)
 {
+	platform_driver_unregister(&hisi_l3c_driver);
+	cpuhp_remove_multi_state(CPUHP_AP_ONLINE_DYN);
 	misc_deregister(&l3c_miscdev);
 	hisi_soc_comp_del(NULL);
 }
-- 
2.33.0



From mripard at kernel.org  Wed Dec 17 02:25:04 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Wed, 17 Dec 2025 10:25:04 +0000
Subject: [PATCH v3 21/22] drm/bridge: imx8qxp-pixel-link:
 imx8qxp_pixel_link_find_next_bridge: return int, not ERR_PTR
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-21-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-21-b5165fab8058@bootlin.com>
Message-ID: <aabaa59f3204da6203c62c5ba01dccd0@kernel.org>

On Tue, 16 Dec 2025 18:58:54 +0100, Luca Ceresoli wrote:
> In preparation for using bridge->next_bridge, we need to ensure that it
> will never contain anything but NULL or a valid bridge pointer. Current
> code stores an ERR_PTR when imx8qxp_pixel_link_find_next_bridge() errors
> out. Instead of fixing that after the facts in the caller, change the
> function to internally set pl->next_bridge and just return an int error
> 
> [ ... ]

Reviewed-by: Maxime Ripard <mripard at kernel.org>

Thanks!
Maxime


From mripard at kernel.org  Wed Dec 17 02:25:19 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Wed, 17 Dec 2025 10:25:19 +0000
Subject: [PATCH v3 19/22] drm/bridge: imx8qxp-pixel-link: simplify
 freeing of the remote device_node
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-19-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-19-b5165fab8058@bootlin.com>
Message-ID: <b95966ec5cffced78db429efa87dcf95@kernel.org>

On Tue, 16 Dec 2025 18:58:52 +0100, Luca Ceresoli wrote:
> The main loop in imx8qxp_pixel_link_find_next_bridge() requires calling
> of_node_put() in multiple places, complicating code flow. Simplify it by
> using a cleanup action and making the 'remote' variable scope local to the
> loop.
> 
> 
> [ ... ]

Reviewed-by: Maxime Ripard <mripard at kernel.org>

Thanks!
Maxime


From mripard at kernel.org  Wed Dec 17 02:25:47 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Wed, 17 Dec 2025 10:25:47 +0000
Subject: [PATCH v3 22/22] drm/bridge: imx8qxp-pixel-link: get/put the
 next bridge
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-22-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-22-b5165fab8058@bootlin.com>
Message-ID: <e6df5ec2f2d0b38a533c3d154587948f@kernel.org>

On Tue, 16 Dec 2025 18:58:55 +0100, Luca Ceresoli wrote:
> This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
> function and stores it until driver removal. of_drm_find_bridge() is
> deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
> refcounted and use bridge->next_bridge to put the reference on
> deallocation.
> 
> [ ... ]

Reviewed-by: Maxime Ripard <mripard at kernel.org>

Thanks!
Maxime


From linux at fw-web.de  Wed Dec 17 02:26:41 2025
From: linux at fw-web.de (Frank Wunderlich)
Date: Wed, 17 Dec 2025 11:26:41 +0100
Subject: [RFC net-next v4 0/3] Add RSS and LRO support
Message-ID: <20251217102648.47093-1-linux@fw-web.de>

From: Frank Wunderlich <frank-w at public-files.de>

This series add RSS and LRO hardware acceleration for terminating
traffic on MT798x.

It is currently only for discussion to get the upported SDK driver
changes in a good shape.

patches are upported from mtk SDK:
- https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/refs/heads/master/master/files/target/linux/mediatek/patches-6.12/999-eth-08-mtk_eth_soc-add-register-definitions-for-rss-lro-reg.patch
- https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/refs/heads/master/master/files/target/linux/mediatek/patches-6.12/999-eth-09-mtk_eth_soc-add-rss-support.patch
- https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/refs/heads/master/master/files/target/linux/mediatek/patches-6.12/999-eth-10-mtk_eth_soc-add-hw-lro-support.patch
with additional fixes

changes:
v4:
- drop unrelated file
- rss-changes suggested by andrew
  - fix MTK_HW_LRO_RING_NUM macro (add eth)
  - fix MTK_LRO_CTRL_DW[123]_CFG (add reg_map param)
  - fix MTK_RX_DONE_INT (add eth param)
- fix lro reverse christmas tree and LRO params suggested by andrew
- drop mtk_hwlro_stats_ebl and unused IS_HW_LRO_RING (only used in
  properitary debugfs)

v3:
- readded the change dropped in v2 because it was a fix
  for getting RSS working on mt7986
- changes requested by jakub
- reworked coverletter (dropped instructions for configuration)
- name all PDMA-IRQ the same way
- retested on
  - BPI-R3/mt7986 (RSS needs to be enabled)
  - BPI-R4/mt7988
  - BPI-R64/mt7622 and BPI-R2/mt7623 for not breaking network functionality

v2:
- drop wrong change (MTK_CDMP_IG_CTRL is only netsys v1)
- Fix immutable string IRQ setup (thx to Emilia Schotte)
- drop links to 6.6 patches/commits in sdk in comments

Mason Chang (3):
  net: ethernet: mtk_eth_soc: Add register definitions for RSS and LRO
  net: ethernet: mtk_eth_soc: Add RSS support
  net: ethernet: mtk_eth_soc: Add LRO support

 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 809 ++++++++++++++++----
 drivers/net/ethernet/mediatek/mtk_eth_soc.h | 168 ++--
 2 files changed, 770 insertions(+), 207 deletions(-)

-- 
2.43.0



From linux at fw-web.de  Wed Dec 17 02:26:42 2025
From: linux at fw-web.de (Frank Wunderlich)
Date: Wed, 17 Dec 2025 11:26:42 +0100
Subject: [RFC net-next v4 1/3] net: ethernet: mtk_eth_soc: Add register definitions for RSS and LRO
In-Reply-To: <20251217102648.47093-1-linux@fw-web.de>
References: <20251217102648.47093-1-linux@fw-web.de>
Message-ID: <20251217102648.47093-2-linux@fw-web.de>

From: Mason Chang <mason-cw.chang at mediatek.com>

Add definitions for Receive Side Scaling and Large Receive Offload support.

Signed-off-by: Mason Chang <mason-cw.chang at mediatek.com>
Signed-off-by: Frank Wunderlich <frank-w at public-files.de>
---
 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 23 +++++++++++++++
 drivers/net/ethernet/mediatek/mtk_eth_soc.h | 32 +++++++++++++++------
 2 files changed, 46 insertions(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index e68997a29191..243ff16fd15e 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -50,13 +50,18 @@ static const struct mtk_reg_map mtk_reg_map = {
 		.rx_ptr		= 0x0900,
 		.rx_cnt_cfg	= 0x0904,
 		.pcrx_ptr	= 0x0908,
+		.lro_ctrl_dw0   = 0x0980,
 		.glo_cfg	= 0x0a04,
 		.rst_idx	= 0x0a08,
 		.delay_irq	= 0x0a0c,
 		.irq_status	= 0x0a20,
 		.irq_mask	= 0x0a28,
 		.adma_rx_dbg0	= 0x0a38,
+		.lro_alt_score_delta	= 0x0a4c,
 		.int_grp	= 0x0a50,
+		.lro_rx1_dly_int	= 0x0a70,
+		.lro_ring_dip_dw0	= 0x0b04,
+		.lro_ring_ctrl_dw1	= 0x0b28,
 	},
 	.qdma = {
 		.qtx_cfg	= 0x1800,
@@ -113,6 +118,7 @@ static const struct mtk_reg_map mt7986_reg_map = {
 	.tx_irq_mask		= 0x461c,
 	.tx_irq_status		= 0x4618,
 	.pdma = {
+		.rss_glo_cfg    = 0x2800,
 		.rx_ptr		= 0x4100,
 		.rx_cnt_cfg	= 0x4104,
 		.pcrx_ptr	= 0x4108,
@@ -123,6 +129,12 @@ static const struct mtk_reg_map mt7986_reg_map = {
 		.irq_mask	= 0x4228,
 		.adma_rx_dbg0	= 0x4238,
 		.int_grp	= 0x4250,
+		.int_grp3	= 0x422c,
+		.lro_ctrl_dw0	= 0x4180,
+		.lro_alt_score_delta	= 0x424c,
+		.lro_rx1_dly_int	= 0x4270,
+		.lro_ring_dip_dw0	= 0x4304,
+		.lro_ring_ctrl_dw1	= 0x4328,
 	},
 	.qdma = {
 		.qtx_cfg	= 0x4400,
@@ -170,10 +182,21 @@ static const struct mtk_reg_map mt7988_reg_map = {
 		.glo_cfg	= 0x6a04,
 		.rst_idx	= 0x6a08,
 		.delay_irq	= 0x6a0c,
+		.rx_cfg		= 0x6a10,
 		.irq_status	= 0x6a20,
 		.irq_mask	= 0x6a28,
 		.adma_rx_dbg0	= 0x6a38,
 		.int_grp	= 0x6a50,
+		.int_grp3	= 0x6a58,
+		.tx_delay_irq	= 0x6ab0,
+		.rx_delay_irq	= 0x6ac0,
+		.lro_ctrl_dw0	= 0x6c08,
+		.lro_alt_score_delta	= 0x6c1c,
+		.lro_ring_dip_dw0	= 0x6c14,
+		.lro_ring_ctrl_dw1	= 0x6c38,
+		.lro_alt_dbg	= 0x6c40,
+		.lro_alt_dbg_data	= 0x6c44,
+		.rss_glo_cfg	= 0x7000,
 	},
 	.qdma = {
 		.qtx_cfg	= 0x4400,
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index 0168e2fbc619..334625814b97 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -1143,16 +1143,30 @@ struct mtk_reg_map {
 	u32	tx_irq_mask;
 	u32	tx_irq_status;
 	struct {
-		u32	rx_ptr;		/* rx base pointer */
-		u32	rx_cnt_cfg;	/* rx max count configuration */
-		u32	pcrx_ptr;	/* rx cpu pointer */
-		u32	glo_cfg;	/* global configuration */
-		u32	rst_idx;	/* reset index */
-		u32	delay_irq;	/* delay interrupt */
-		u32	irq_status;	/* interrupt status */
-		u32	irq_mask;	/* interrupt mask */
+		u32	rx_ptr;			/* rx base pointer */
+		u32	rx_cnt_cfg;		/* rx max count configuration */
+		u32	pcrx_ptr;		/* rx cpu pointer */
+		u32	pdrx_ptr;		/* rx dma pointer */
+		u32	glo_cfg;		/* global configuration */
+		u32	rst_idx;		/* reset index */
+		u32	rx_cfg;			/* rx dma configuration */
+		u32	delay_irq;		/* delay interrupt */
+		u32	irq_status;		/* interrupt status */
+		u32	irq_mask;		/* interrupt mask */
 		u32	adma_rx_dbg0;
-		u32	int_grp;
+		u32	int_grp;		/* interrupt group1 */
+		u32	int_grp3;		/* interrupt group3 */
+		u32	tx_delay_irq;		/* tx delay interrupt */
+		u32	rx_delay_irq;		/* rx delay interrupt */
+		u32	lro_ctrl_dw0;		/* lro ctrl dword0 */
+		u32	lro_alt_score_delta;	/* lro auto-learn score delta */
+		u32	lro_rx1_dly_int;	/* lro rx ring1 delay interrupt */
+		u32	lro_ring_dip_dw0;	/* lro ring dip dword0 */
+		u32	lro_ring_ctrl_dw1;	/* lro ring ctrl dword1 */
+		u32	lro_alt_dbg;		/* lro auto-learn debug */
+		u32	lro_alt_dbg_data;	/* lro auto-learn debug data */
+		u32	rss_glo_cfg;		/* rss global configuration */
+
 	} pdma;
 	struct {
 		u32	qtx_cfg;	/* tx queue configuration */
-- 
2.43.0



From linux at fw-web.de  Wed Dec 17 02:26:44 2025
From: linux at fw-web.de (Frank Wunderlich)
Date: Wed, 17 Dec 2025 11:26:44 +0100
Subject: [RFC net-next v4 3/3] net: ethernet: mtk_eth_soc: Add LRO support
In-Reply-To: <20251217102648.47093-1-linux@fw-web.de>
References: <20251217102648.47093-1-linux@fw-web.de>
Message-ID: <20251217102648.47093-4-linux@fw-web.de>

From: Mason Chang <mason-cw.chang at mediatek.com>

Add Large Receive Offload support to mediatek ethernet driver and
activate it for MT7988.

Signed-off-by: Mason Chang <mason-cw.chang at mediatek.com>
Signed-off-by: Frank Wunderlich <frank-w at public-files.de>
---
v4:
- fix lro reverse christmas tree and LRO params suggested by andrew
- drop mtk_hwlro_stats_ebl and unused IS_HW_LRO_RING (only used in
  properitary debugfs)

v2:
- drop link to commit for 6.6 patch
---
 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 244 +++++++++++++++++---
 drivers/net/ethernet/mediatek/mtk_eth_soc.h |  47 ++--
 2 files changed, 235 insertions(+), 56 deletions(-)

diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 4dfff59a3c8a..301bdd6d0c14 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -2772,7 +2772,7 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag)
 
 	if (rx_flag == MTK_RX_FLAGS_HWLRO) {
 		rx_data_len = MTK_MAX_LRO_RX_LENGTH;
-		rx_dma_size = MTK_HW_LRO_DMA_SIZE;
+		rx_dma_size = MTK_HW_LRO_DMA_SIZE(eth);
 	} else {
 		rx_data_len = ETH_DATA_LEN;
 		rx_dma_size = soc->rx.dma_size;
@@ -2785,7 +2785,7 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag)
 	if (!ring->data)
 		return -ENOMEM;
 
-	if (mtk_page_pool_enabled(eth)) {
+	if (mtk_page_pool_enabled(eth) && rcu_access_pointer(eth->prog))  {
 		struct page_pool *pp;
 
 		pp = mtk_create_page_pool(eth, &ring->xdp_q, ring_no,
@@ -2931,10 +2931,11 @@ static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring, bool in_
 
 static int mtk_hwlro_rx_init(struct mtk_eth *eth)
 {
-	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
-	int i;
 	u32 ring_ctrl_dw1 = 0, ring_ctrl_dw2 = 0, ring_ctrl_dw3 = 0;
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
+	const struct mtk_soc_data *soc = eth->soc;
 	u32 lro_ctrl_dw0 = 0, lro_ctrl_dw3 = 0;
+	int i, val;
 
 	/* set LRO rings to auto-learn modes */
 	ring_ctrl_dw2 |= MTK_RING_AUTO_LERAN_MODE;
@@ -2953,30 +2954,44 @@ static int mtk_hwlro_rx_init(struct mtk_eth *eth)
 	ring_ctrl_dw2 |= MTK_RING_MAX_AGG_CNT_L;
 	ring_ctrl_dw3 |= MTK_RING_MAX_AGG_CNT_H;
 
-	for (i = 1; i < MTK_MAX_RX_RING_NUM; i++) {
+	for (i = 1; i <= MTK_HW_LRO_RING_NUM(eth); i++) {
 		mtk_w32(eth, ring_ctrl_dw1, MTK_LRO_CTRL_DW1_CFG(reg_map, i));
 		mtk_w32(eth, ring_ctrl_dw2, MTK_LRO_CTRL_DW2_CFG(reg_map, i));
 		mtk_w32(eth, ring_ctrl_dw3, MTK_LRO_CTRL_DW3_CFG(reg_map, i));
 	}
 
 	/* IPv4 checksum update enable */
-	lro_ctrl_dw0 |= MTK_L3_CKS_UPD_EN;
+	lro_ctrl_dw0 |= MTK_L3_CKS_UPD_EN(eth);
 
 	/* switch priority comparison to packet count mode */
 	lro_ctrl_dw0 |= MTK_LRO_ALT_PKT_CNT_MODE;
 
 	/* bandwidth threshold setting */
-	mtk_w32(eth, MTK_HW_LRO_BW_THRE, MTK_PDMA_LRO_CTRL_DW2);
+	mtk_w32(eth, MTK_HW_LRO_BW_THRE, MTK_PDMA_LRO_CTRL_DW2(reg_map));
 
 	/* auto-learn score delta setting */
-	mtk_w32(eth, MTK_HW_LRO_REPLACE_DELTA, MTK_PDMA_LRO_ALT_SCORE_DELTA);
+	mtk_w32(eth, MTK_HW_LRO_REPLACE_DELTA, MTK_PDMA_LRO_ALT_SCORE_DELTA(reg_map));
 
 	/* set refresh timer for altering flows to 1 sec. (unit: 20us) */
 	mtk_w32(eth, (MTK_HW_LRO_TIMER_UNIT << 16) | MTK_HW_LRO_REFRESH_TIME,
 		MTK_PDMA_LRO_ALT_REFRESH_TIMER);
 
-	/* set HW LRO mode & the max aggregation count for rx packets */
-	lro_ctrl_dw3 |= MTK_ADMA_MODE | (MTK_HW_LRO_MAX_AGG_CNT & 0xff);
+	if (mtk_is_netsys_v3_or_greater(eth)) {
+		val = mtk_r32(eth, reg_map->pdma.rx_cfg);
+		mtk_w32(eth, val | ((MTK_PDMA_LRO_SDL + MTK_MAX_RX_LENGTH) <<
+			MTK_RX_CFG_SDL_OFFSET), reg_map->pdma.rx_cfg);
+
+		lro_ctrl_dw0 |= MTK_PDMA_LRO_SDL << MTK_CTRL_DW0_SDL_OFFSET;
+
+		/* enable cpu reason black list */
+		lro_ctrl_dw0 |= MTK_LRO_CRSN_BNW(eth);
+
+		/* no use PPE cpu reason */
+		mtk_w32(eth, 0xffffffff, MTK_PDMA_LRO_CTRL_DW1(reg_map));
+	} else {
+		/* set HW LRO mode & the max aggregation count for rx packets */
+		lro_ctrl_dw3 |= MTK_ADMA_MODE | (MTK_HW_LRO_MAX_AGG_CNT & 0xff);
+	}
 
 	/* the minimal remaining room of SDL0 in RXD for lro aggregation */
 	lro_ctrl_dw3 |= MTK_LRO_MIN_RXD_SDL;
@@ -2984,8 +2999,19 @@ static int mtk_hwlro_rx_init(struct mtk_eth *eth)
 	/* enable HW LRO */
 	lro_ctrl_dw0 |= MTK_LRO_EN;
 
-	mtk_w32(eth, lro_ctrl_dw3, MTK_PDMA_LRO_CTRL_DW3);
-	mtk_w32(eth, lro_ctrl_dw0, MTK_PDMA_LRO_CTRL_DW0);
+	mtk_w32(eth, lro_ctrl_dw3, MTK_PDMA_LRO_CTRL_DW3(reg_map));
+	mtk_w32(eth, lro_ctrl_dw0, MTK_PDMA_LRO_CTRL_DW0(reg_map));
+
+	if (mtk_is_netsys_v2_or_greater(eth)) {
+		i = (soc->rx.desc_size == sizeof(struct mtk_rx_dma_v2)) ? 1 : 0;
+		mtk_m32(eth, MTK_RX_DONE_INT(eth, MTK_HW_LRO_RING(eth, i)),
+			MTK_RX_DONE_INT(eth, MTK_HW_LRO_RING(eth, i)), reg_map->pdma.int_grp);
+		mtk_m32(eth, MTK_RX_DONE_INT(eth, MTK_HW_LRO_RING(eth, i + 1)),
+			MTK_RX_DONE_INT(eth, MTK_HW_LRO_RING(eth, i + 1)),
+			reg_map->pdma.int_grp + 0x4);
+		mtk_m32(eth, MTK_RX_DONE_INT(eth, MTK_HW_LRO_RING(eth, i + 2)),
+			MTK_RX_DONE_INT(eth, MTK_HW_LRO_RING(eth, i + 2)), reg_map->pdma.int_grp3);
+	}
 
 	return 0;
 }
@@ -2993,16 +3019,16 @@ static int mtk_hwlro_rx_init(struct mtk_eth *eth)
 static void mtk_hwlro_rx_uninit(struct mtk_eth *eth)
 {
 	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
-	int i;
 	u32 val;
+	int i;
 
 	/* relinquish lro rings, flush aggregated packets */
-	mtk_w32(eth, MTK_LRO_RING_RELINQUISH_REQ, MTK_PDMA_LRO_CTRL_DW0);
+	mtk_w32(eth, MTK_LRO_RING_RELINQUISH_REQ(eth), MTK_PDMA_LRO_CTRL_DW0(reg_map));
 
 	/* wait for relinquishments done */
 	for (i = 0; i < 10; i++) {
-		val = mtk_r32(eth, MTK_PDMA_LRO_CTRL_DW0);
-		if (val & MTK_LRO_RING_RELINQUISH_DONE) {
+		val = mtk_r32(eth, MTK_PDMA_LRO_CTRL_DW0(reg_map));
+		if (val & MTK_LRO_RING_RELINQUISH_DONE(eth)) {
 			msleep(20);
 			continue;
 		}
@@ -3010,11 +3036,11 @@ static void mtk_hwlro_rx_uninit(struct mtk_eth *eth)
 	}
 
 	/* invalidate lro rings */
-	for (i = 1; i < MTK_MAX_RX_RING_NUM; i++)
+	for (i = 1; i <= MTK_HW_LRO_RING_NUM(eth); i++)
 		mtk_w32(eth, 0, MTK_LRO_CTRL_DW2_CFG(reg_map, i));
 
 	/* disable HW LRO */
-	mtk_w32(eth, 0, MTK_PDMA_LRO_CTRL_DW0);
+	mtk_w32(eth, 0, MTK_PDMA_LRO_CTRL_DW0(reg_map));
 }
 
 static void mtk_hwlro_val_ipaddr(struct mtk_eth *eth, int idx, __be32 ip)
@@ -3027,7 +3053,7 @@ static void mtk_hwlro_val_ipaddr(struct mtk_eth *eth, int idx, __be32 ip)
 	/* invalidate the IP setting */
 	mtk_w32(eth, (reg_val & ~MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(reg_map, idx));
 
-	mtk_w32(eth, ip, MTK_LRO_DIP_DW0_CFG(idx));
+	mtk_w32(eth, ip, MTK_LRO_DIP_DW0_CFG(reg_map, idx));
 
 	/* validate the IP setting */
 	mtk_w32(eth, (reg_val | MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(reg_map, idx));
@@ -3043,7 +3069,7 @@ static void mtk_hwlro_inval_ipaddr(struct mtk_eth *eth, int idx)
 	/* invalidate the IP setting */
 	mtk_w32(eth, (reg_val & ~MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(reg_map, idx));
 
-	mtk_w32(eth, 0, MTK_LRO_DIP_DW0_CFG(idx));
+	mtk_w32(eth, 0, MTK_LRO_DIP_DW0_CFG(reg_map, idx));
 }
 
 static int mtk_hwlro_get_ip_cnt(struct mtk_mac *mac)
@@ -3059,6 +3085,65 @@ static int mtk_hwlro_get_ip_cnt(struct mtk_mac *mac)
 	return cnt;
 }
 
+static int mtk_hwlro_add_ipaddr_idx(struct net_device *dev, u32 ip4dst)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	const struct mtk_reg_map *reg_map;
+	struct mtk_eth *eth = mac->hw;
+	u32 reg_val;
+	int i;
+
+	reg_map = eth->soc->reg_map;
+
+	/* check for duplicate IP address in the current DIP list */
+	for (i = 1; i <= MTK_HW_LRO_DIP_NUM(eth); i++) {
+		reg_val = mtk_r32(eth, MTK_LRO_DIP_DW0_CFG(reg_map, i));
+		if (reg_val == ip4dst)
+			break;
+	}
+
+	if (i < MTK_HW_LRO_DIP_NUM(eth) + 1) {
+		netdev_warn(dev, "Duplicate IP address at DIP(%d)!\n", i);
+		return -EEXIST;
+	}
+
+	/* find out available DIP index */
+	for (i = 1; i <= MTK_HW_LRO_DIP_NUM(eth); i++) {
+		reg_val = mtk_r32(eth, MTK_LRO_DIP_DW0_CFG(reg_map, i));
+		if (reg_val == 0UL)
+			break;
+	}
+
+	if (i >= MTK_HW_LRO_DIP_NUM(eth) + 1) {
+		netdev_warn(dev, "DIP index is currently out of resource!\n");
+		return -EBUSY;
+	}
+
+	return i;
+}
+
+static int mtk_hwlro_get_ipaddr_idx(struct net_device *dev, u32 ip4dst)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	u32 reg_val;
+	int i;
+
+	/* find out DIP index that matches the given IP address */
+	for (i = 1; i <= MTK_HW_LRO_DIP_NUM(eth); i++) {
+		reg_val = mtk_r32(eth, MTK_LRO_DIP_DW0_CFG(eth->soc->reg_map, i));
+		if (reg_val == ip4dst)
+			break;
+	}
+
+	if (i >= MTK_HW_LRO_DIP_NUM(eth) + 1) {
+		netdev_warn(dev, "DIP address is not exist!\n");
+		return -ENOENT;
+	}
+
+	return i;
+}
+
 static int mtk_hwlro_add_ipaddr(struct net_device *dev,
 				struct ethtool_rxnfc *cmd)
 {
@@ -3067,15 +3152,19 @@ static int mtk_hwlro_add_ipaddr(struct net_device *dev,
 	struct mtk_mac *mac = netdev_priv(dev);
 	struct mtk_eth *eth = mac->hw;
 	int hwlro_idx;
+	u32 ip4dst;
 
 	if ((fsp->flow_type != TCP_V4_FLOW) ||
 	    (!fsp->h_u.tcp_ip4_spec.ip4dst) ||
 	    (fsp->location > 1))
 		return -EINVAL;
 
-	mac->hwlro_ip[fsp->location] = htonl(fsp->h_u.tcp_ip4_spec.ip4dst);
-	hwlro_idx = (mac->id * MTK_MAX_LRO_IP_CNT) + fsp->location;
+	ip4dst = htonl(fsp->h_u.tcp_ip4_spec.ip4dst);
+	hwlro_idx = mtk_hwlro_add_ipaddr_idx(dev, ip4dst);
+	if (hwlro_idx < 0)
+		return hwlro_idx;
 
+	mac->hwlro_ip[fsp->location] = ip4dst;
 	mac->hwlro_ip_cnt = mtk_hwlro_get_ip_cnt(mac);
 
 	mtk_hwlro_val_ipaddr(eth, hwlro_idx, mac->hwlro_ip[fsp->location]);
@@ -3091,13 +3180,17 @@ static int mtk_hwlro_del_ipaddr(struct net_device *dev,
 	struct mtk_mac *mac = netdev_priv(dev);
 	struct mtk_eth *eth = mac->hw;
 	int hwlro_idx;
+	u32 ip4dst;
 
 	if (fsp->location > 1)
 		return -EINVAL;
 
-	mac->hwlro_ip[fsp->location] = 0;
-	hwlro_idx = (mac->id * MTK_MAX_LRO_IP_CNT) + fsp->location;
+	ip4dst = mac->hwlro_ip[fsp->location];
+	hwlro_idx = mtk_hwlro_get_ipaddr_idx(dev, ip4dst);
+	if (hwlro_idx < 0)
+		return hwlro_idx;
 
+	mac->hwlro_ip[fsp->location] = 0;
 	mac->hwlro_ip_cnt = mtk_hwlro_get_ip_cnt(mac);
 
 	mtk_hwlro_inval_ipaddr(eth, hwlro_idx);
@@ -3105,6 +3198,24 @@ static int mtk_hwlro_del_ipaddr(struct net_device *dev,
 	return 0;
 }
 
+static void mtk_hwlro_netdev_enable(struct net_device *dev)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	int i, hwlro_idx;
+
+	for (i = 0; i < MTK_MAX_LRO_IP_CNT; i++) {
+		if (mac->hwlro_ip[i] == 0)
+			continue;
+
+		hwlro_idx = mtk_hwlro_get_ipaddr_idx(dev, mac->hwlro_ip[i]);
+		if (hwlro_idx < 0)
+			continue;
+
+		mtk_hwlro_val_ipaddr(eth, hwlro_idx, mac->hwlro_ip[i]);
+	}
+}
+
 static void mtk_hwlro_netdev_disable(struct net_device *dev)
 {
 	struct mtk_mac *mac = netdev_priv(dev);
@@ -3112,8 +3223,14 @@ static void mtk_hwlro_netdev_disable(struct net_device *dev)
 	int i, hwlro_idx;
 
 	for (i = 0; i < MTK_MAX_LRO_IP_CNT; i++) {
+		if (mac->hwlro_ip[i] == 0)
+			continue;
+
+		hwlro_idx = mtk_hwlro_get_ipaddr_idx(dev, mac->hwlro_ip[i]);
+		if (hwlro_idx < 0)
+			continue;
+
 		mac->hwlro_ip[i] = 0;
-		hwlro_idx = (mac->id * MTK_MAX_LRO_IP_CNT) + i;
 
 		mtk_hwlro_inval_ipaddr(eth, hwlro_idx);
 	}
@@ -3293,6 +3410,8 @@ static int mtk_set_features(struct net_device *dev, netdev_features_t features)
 
 	if ((diff & NETIF_F_LRO) && !(features & NETIF_F_LRO))
 		mtk_hwlro_netdev_disable(dev);
+	else if ((diff & NETIF_F_LRO) && (features & NETIF_F_LRO))
+		mtk_hwlro_netdev_enable(dev);
 
 	return 0;
 }
@@ -3350,8 +3469,8 @@ static int mtk_dma_init(struct mtk_eth *eth)
 		return err;
 
 	if (eth->hwlro) {
-		for (i = 1; i < MTK_MAX_RX_RING_NUM; i++) {
-			err = mtk_rx_alloc(eth, i, MTK_RX_FLAGS_HWLRO);
+		for (i = 0; i < MTK_HW_LRO_RING_NUM(eth); i++) {
+			err = mtk_rx_alloc(eth, MTK_HW_LRO_RING(eth, i), MTK_RX_FLAGS_HWLRO);
 			if (err)
 				return err;
 		}
@@ -3413,8 +3532,8 @@ static void mtk_dma_free(struct mtk_eth *eth)
 
 	if (eth->hwlro) {
 		mtk_hwlro_rx_uninit(eth);
-		for (i = 1; i < MTK_MAX_RX_RING_NUM; i++)
-			mtk_rx_clean(eth, &eth->rx_ring[i], false);
+		for (i = 0; i < MTK_HW_LRO_RING_NUM(eth); i++)
+			mtk_rx_clean(eth, &eth->rx_ring[MTK_HW_LRO_RING(eth, i)], false);
 	}
 
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
@@ -3609,16 +3728,21 @@ static int mtk_start_dma(struct mtk_eth *eth)
 			val |= MTK_RX_BT_32DWORDS;
 		mtk_w32(eth, val, reg_map->qdma.glo_cfg);
 
-		mtk_w32(eth,
-			MTK_RX_DMA_EN | rx_2b_offset |
-			MTK_RX_BT_32DWORDS | MTK_MULTI_EN,
-			reg_map->pdma.glo_cfg);
+		val = mtk_r32(eth, reg_map->pdma.glo_cfg);
+		val |= MTK_RX_DMA_EN | rx_2b_offset |
+		       MTK_RX_BT_32DWORDS | MTK_MULTI_EN;
+		mtk_w32(eth, val, reg_map->pdma.glo_cfg);
 	} else {
 		mtk_w32(eth, MTK_TX_WB_DDONE | MTK_TX_DMA_EN | MTK_RX_DMA_EN |
 			MTK_MULTI_EN | MTK_PDMA_SIZE_8DWORDS,
 			reg_map->pdma.glo_cfg);
 	}
 
+	if (eth->hwlro && mtk_is_netsys_v3_or_greater(eth)) {
+		val = mtk_r32(eth, reg_map->pdma.glo_cfg);
+		mtk_w32(eth, val | MTK_RX_DMA_LRO_EN, reg_map->pdma.glo_cfg);
+	}
+
 	return 0;
 }
 
@@ -3762,6 +3886,14 @@ static int mtk_open(struct net_device *dev)
 			}
 		}
 
+		if (eth->hwlro) {
+			for (i = 0; i < MTK_HW_LRO_RING_NUM(eth); i++) {
+				napi_enable(&eth->rx_napi[MTK_HW_LRO_RING(eth, i)].napi);
+				mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(eth,
+								       MTK_HW_LRO_RING(eth, i)));
+			}
+		}
+
 		refcount_set(&eth->dma_refcnt, 1);
 	} else {
 		refcount_inc(&eth->dma_refcnt);
@@ -3857,6 +3989,14 @@ static int mtk_stop(struct net_device *dev)
 		}
 	}
 
+	if (eth->hwlro) {
+		for (i = 0; i < MTK_HW_LRO_RING_NUM(eth); i++) {
+			mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(eth, MTK_HW_LRO_RING(eth, i)));
+			napi_synchronize(&eth->rx_napi[MTK_HW_LRO_RING(eth, i)].napi);
+			napi_disable(&eth->rx_napi[MTK_HW_LRO_RING(eth, i)].napi);
+		}
+	}
+
 	cancel_work_sync(&eth->rx_dim.work);
 	cancel_work_sync(&eth->tx_dim.work);
 
@@ -4256,6 +4396,14 @@ static int mtk_napi_init(struct mtk_eth *eth)
 		}
 	}
 
+	if (eth->hwlro) {
+		for (i = 0; i < MTK_HW_LRO_RING_NUM(eth); i++) {
+			rx_napi = &eth->rx_napi[MTK_HW_LRO_RING(eth, i)];
+			rx_napi->eth = eth;
+			rx_napi->rx_ring = &eth->rx_ring[MTK_HW_LRO_RING(eth, i)];
+		}
+	}
+
 	return 0;
 }
 
@@ -4818,7 +4966,7 @@ static int mtk_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
 	switch (cmd->cmd) {
 	case ETHTOOL_GRXRINGS:
 		if (dev->hw_features & NETIF_F_LRO) {
-			cmd->data = MTK_MAX_RX_RING_NUM;
+			cmd->data = MTK_HW_LRO_RING_NUM(eth);
 			ret = 0;
 		} else if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
 			cmd->data = MTK_RX_RSS_NUM(eth);
@@ -5523,6 +5671,21 @@ static int mtk_probe(struct platform_device *pdev)
 						goto err_free_dev;
 				}
 			}
+
+			if (eth->hwlro) {
+				for (i = 0; i < MTK_HW_LRO_RING_NUM(eth); i++) {
+					irqname = devm_kasprintf(eth->dev, GFP_KERNEL,
+								 "%s LRO RX %d",
+								 dev_name(eth->dev), i);
+					err = devm_request_irq(eth->dev,
+							       eth->irq_pdma[MTK_HW_LRO_IRQ(eth, i)],
+							       mtk_handle_irq_rx, IRQF_SHARED,
+							       irqname,
+							       &eth->rx_napi[MTK_HW_LRO_RING(eth, i)]);
+					if (err)
+						goto err_free_dev;
+				}
+			}
 		} else {
 			irqname = devm_kasprintf(eth->dev, GFP_KERNEL, "%s RX",
 						 dev_name(eth->dev));
@@ -5594,6 +5757,13 @@ static int mtk_probe(struct platform_device *pdev)
 				       mtk_napi_rx);
 	}
 
+	if (eth->hwlro) {
+		for (i = 0; i < MTK_HW_LRO_RING_NUM(eth); i++) {
+			netif_napi_add(eth->dummy_dev, &eth->rx_napi[MTK_HW_LRO_RING(eth, i)].napi,
+				       mtk_napi_rx);
+		}
+	}
+
 	platform_set_drvdata(pdev, eth);
 	schedule_delayed_work(&eth->reset.monitor_work,
 			      MTK_DMA_MONITOR_TIMEOUT);
@@ -5642,6 +5812,12 @@ static void mtk_remove(struct platform_device *pdev)
 		for (i = 1; i < MTK_RX_RSS_NUM(eth); i++)
 			netif_napi_del(&eth->rx_napi[MTK_RSS_RING(i)].napi);
 	}
+
+	if (eth->hwlro) {
+		for (i = 0; i < MTK_HW_LRO_RING_NUM(eth); i++)
+			netif_napi_del(&eth->rx_napi[MTK_HW_LRO_RING(eth, i)].napi);
+	}
+
 	mtk_cleanup(eth);
 	free_netdev(eth->dummy_dev);
 	mtk_mdio_cleanup(eth);
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index 1ef4a210a4cd..4bbce80e11a0 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -35,7 +35,7 @@
 #define MTK_DMA_SIZE(x)		(SZ_##x)
 #define MTK_FQ_DMA_HEAD		32
 #define MTK_FQ_DMA_LENGTH	2048
-#define MTK_RX_ETH_HLEN		(ETH_HLEN + ETH_FCS_LEN)
+#define MTK_RX_ETH_HLEN		(VLAN_ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN)
 #define MTK_RX_HLEN		(NET_SKB_PAD + MTK_RX_ETH_HLEN + NET_IP_ALIGN)
 #define MTK_DMA_DUMMY_DESC	0xffffffff
 #define MTK_DEFAULT_MSG_ENABLE	(NETIF_MSG_DRV | \
@@ -63,10 +63,9 @@
 
 #define MTK_QRX_OFFSET		0x10
 
-#define MTK_MAX_RX_RING_NUM	4
-#define MTK_HW_LRO_DMA_SIZE	8
-
-#define	MTK_MAX_LRO_RX_LENGTH		(4096 * 3)
+#define MTK_MAX_RX_RING_NUM	(8)
+#define MTK_HW_LRO_DMA_SIZE(eth)	(mtk_is_netsys_v3_or_greater(eth) ? 64 : 8)
+#define	MTK_MAX_LRO_RX_LENGTH		(4096 * 3 + MTK_MAX_RX_LENGTH)
 #define	MTK_MAX_LRO_IP_CNT		2
 #define	MTK_HW_LRO_TIMER_UNIT		1	/* 20 us */
 #define	MTK_HW_LRO_REFRESH_TIME		50000	/* 1 sec. */
@@ -182,31 +181,35 @@
 #define MTK_CDMM_THRES		0x165c
 
 /* PDMA HW LRO Control Registers */
-#define MTK_PDMA_LRO_CTRL_DW0	0x980
-#define MTK_HW_LRO_RING_NUM(eth)		(mtk_is_netsys_v3_or_greater(eth) ? 4 : 3)
+#define MTK_HW_LRO_DIP_NUM(eth)		(mtk_is_netsys_v3_or_greater(eth) ? 4 : 3)
+#define MTK_HW_LRO_RING_NUM(eth)	(mtk_is_netsys_v3_or_greater(eth) ? 4 : 3)
+#define MTK_HW_LRO_RING(eth, x)		((x) + (mtk_is_netsys_v3_or_greater(eth) ? 4 : 1))
+#define MTK_HW_LRO_IRQ(eth, x)		((x) + (mtk_is_netsys_v3_or_greater(eth) ? 0 : 1))
+#define MTK_LRO_CRSN_BNW(eth)		BIT((mtk_is_netsys_v3_or_greater(eth) ? 22 : 6))
 #define MTK_LRO_EN			BIT(0)
 #define MTK_NON_LRO_MULTI_EN		BIT(2)
 #define MTK_LRO_DLY_INT_EN		BIT(5)
-#define MTK_L3_CKS_UPD_EN		BIT(7)
-#define MTK_L3_CKS_UPD_EN_V2		BIT(19)
+#define MTK_L3_CKS_UPD_EN(eth)		BIT(mtk_is_netsys_v3_or_greater(eth) ? 19 : 7)
 #define MTK_LRO_ALT_PKT_CNT_MODE	BIT(21)
-#define MTK_LRO_RING_RELINQUISH_REQ	(0x7 << 26)
-#define MTK_LRO_RING_RELINQUISH_REQ_V2	(0xf << 24)
-#define MTK_LRO_RING_RELINQUISH_DONE	(0x7 << 29)
-#define MTK_LRO_RING_RELINQUISH_DONE_V2	(0xf << 28)
-
-#define MTK_PDMA_LRO_CTRL_DW1	0x984
-#define MTK_PDMA_LRO_CTRL_DW2	0x988
-#define MTK_PDMA_LRO_CTRL_DW3	0x98c
+#define MTK_LRO_RING_RELINQUISH_REQ(eth)	(mtk_is_netsys_v3_or_greater(eth) ? 0xf << 24 : 0x7 << 26)
+#define MTK_LRO_RING_RELINQUISH_DONE(eth)	(mtk_is_netsys_v3_or_greater(eth) ? 0xf << 28 : 0x7 << 29)
+
+#define MTK_PDMA_LRO_CTRL_DW0(reg_map)	(reg_map->pdma.lro_ctrl_dw0)
+#define MTK_PDMA_LRO_CTRL_DW1(reg_map)	(reg_map->pdma.lro_ctrl_dw0 + 0x04)
+#define MTK_PDMA_LRO_CTRL_DW2(reg_map)	(reg_map->pdma.lro_ctrl_dw0 + 0x08)
+#define MTK_PDMA_LRO_CTRL_DW3(reg_map)	(reg_map->pdma.lro_ctrl_dw0 + 0x0c)
 #define MTK_ADMA_MODE		BIT(15)
 #define MTK_LRO_MIN_RXD_SDL	(MTK_HW_LRO_SDL_REMAIN_ROOM << 16)
 
+#define MTK_CTRL_DW0_SDL_OFFSET	(3)
+#define MTK_CTRL_DW0_SDL_MASK	BITS(3, 18)
+
 #define MTK_RX_DMA_LRO_EN	BIT(8)
 #define MTK_MULTI_EN		BIT(10)
 #define MTK_PDMA_SIZE_8DWORDS	(1 << 4)
 
 /* PDMA RSS Control Registers */
-#define MTK_RX_NAPI_NUM			(4)
+#define MTK_RX_NAPI_NUM			(8)
 #define MTK_RX_RSS_NUM(eth)		(eth->soc->rss_num)
 #define MTK_RSS_RING(x)			(x)
 #define MTK_RSS_EN			BIT(0)
@@ -242,11 +245,10 @@
 #define MTK_PDMA_DELAY_PTIME_MASK	0xff
 
 /* PDMA HW LRO Alter Flow Delta Register */
-#define MTK_PDMA_LRO_ALT_SCORE_DELTA	0xa4c
+#define MTK_PDMA_LRO_ALT_SCORE_DELTA(reg_map)	(reg_map->pdma.lro_alt_score_delta)
 
 /* PDMA HW LRO IP Setting Registers */
-#define MTK_LRO_RX_RING0_DIP_DW0	0xb04
-#define MTK_LRO_DIP_DW0_CFG(x)		(MTK_LRO_RX_RING0_DIP_DW0 + (x * 0x40))
+#define MTK_LRO_DIP_DW0_CFG(reg_map, x)	(reg_map->pdma.lro_ring_dip_dw0 + ((x) * 0x40))
 #define MTK_RING_MYIP_VLD		BIT(9)
 
 /* PDMA HW LRO Ring Control Registers */
@@ -1184,7 +1186,8 @@ enum mkt_eth_capabilities {
 
 #define MT7988_CAPS  (MTK_36BIT_DMA | MTK_GDM1_ESW | MTK_GMAC2_2P5GPHY | \
 		      MTK_MUX_GMAC2_TO_2P5GPHY | MTK_QDMA | MTK_RSTCTRL_PPE1 | \
-		      MTK_RSTCTRL_PPE2 | MTK_SRAM | MTK_PDMA_INT | MTK_RSS)
+		      MTK_RSTCTRL_PPE2 | MTK_SRAM | MTK_PDMA_INT | MTK_RSS | \
+		      MTK_HWLRO)
 
 struct mtk_tx_dma_desc_info {
 	dma_addr_t	addr;
-- 
2.43.0



From linux at fw-web.de  Wed Dec 17 02:26:43 2025
From: linux at fw-web.de (Frank Wunderlich)
Date: Wed, 17 Dec 2025 11:26:43 +0100
Subject: [RFC net-next v4 2/3] net: ethernet: mtk_eth_soc: Add RSS support
In-Reply-To: <20251217102648.47093-1-linux@fw-web.de>
References: <20251217102648.47093-1-linux@fw-web.de>
Message-ID: <20251217102648.47093-3-linux@fw-web.de>

From: Mason Chang <mason-cw.chang at mediatek.com>

Add support for Receive Side Scaling.

We can adjust SMP affinity with the following command:
echo [CPU bitmap num] > /proc/irq/[virtual IRQ ID]/smp_affinity,
with interrupts evenly assigned to 4 CPUs, we were able to measure
an RX throughput of 7.3Gbps using iperf3 on the MT7988. Further
optimizations will be carried out in the future.

The experimental command is as follows:
PC: iperf3 -c [IP] -P 10
DUT: iperf3 -s

The entire indirection table can be imagined as 128 buckets, we
can use the ethtool command to mark which RX ring we want to send
the packets in these buckets to.

Show RSS RX ring parameters in indirection table and RSS hash key:
ethtool -x [interface]
Change RSS RX rings weight under uniform distribution:
ethtool --set-rxfh-indir [interface] equal [ring num]
Change RSS RX rings weight under non-uniform distribution:
ethtool --set-rxfh-indir [interface] weight [ring0 weight]
[ring1 weight] [ring2 weight] [ring3 weight]

Signed-off-by: Mason Chang <mason-cw.chang at mediatek.com>
Signed-off-by: Frank Wunderlich <frank-w at public-files.de>
---
v4:
- drop unrelated file
- rss-changes suggested by andrew
  - fix MTK_HW_LRO_RING_NUM macro (add eth)
  - fix MTK_LRO_CTRL_DW[123]_CFG (add reg_map param)
  - fix MTK_RX_DONE_INT (add eth param)

v3:
- changes requested by jakub
- readded rss fix for mt7986
- name all PDMA-IRQ the same way

v2:
- drop wrong change (MTK_CDMP_IG_CTRL is only netsys v1)
- Fix immutable string IRQ setup (thx to Emilia Schotte)
- drop link to no more existent 6.6 patch in comment
---
 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 544 +++++++++++++++-----
 drivers/net/ethernet/mediatek/mtk_eth_soc.h |  95 +++-
 2 files changed, 493 insertions(+), 146 deletions(-)

diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 243ff16fd15e..4dfff59a3c8a 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -1275,6 +1275,7 @@ static bool mtk_rx_get_desc(struct mtk_eth *eth, struct mtk_rx_dma_v2 *rxd,
 	if (mtk_is_netsys_v3_or_greater(eth)) {
 		rxd->rxd5 = READ_ONCE(dma_rxd->rxd5);
 		rxd->rxd6 = READ_ONCE(dma_rxd->rxd6);
+		rxd->rxd7 = READ_ONCE(dma_rxd->rxd7);
 	}
 
 	return true;
@@ -1842,47 +1843,9 @@ static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	return NETDEV_TX_OK;
 }
 
-static struct mtk_rx_ring *mtk_get_rx_ring(struct mtk_eth *eth)
+static void mtk_update_rx_cpu_idx(struct mtk_eth *eth, struct mtk_rx_ring *ring)
 {
-	int i;
-	struct mtk_rx_ring *ring;
-	int idx;
-
-	if (!eth->hwlro)
-		return &eth->rx_ring[0];
-
-	for (i = 0; i < MTK_MAX_RX_RING_NUM; i++) {
-		struct mtk_rx_dma *rxd;
-
-		ring = &eth->rx_ring[i];
-		idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size);
-		rxd = ring->dma + idx * eth->soc->rx.desc_size;
-		if (rxd->rxd2 & RX_DMA_DONE) {
-			ring->calc_idx_update = true;
-			return ring;
-		}
-	}
-
-	return NULL;
-}
-
-static void mtk_update_rx_cpu_idx(struct mtk_eth *eth)
-{
-	struct mtk_rx_ring *ring;
-	int i;
-
-	if (!eth->hwlro) {
-		ring = &eth->rx_ring[0];
-		mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg);
-	} else {
-		for (i = 0; i < MTK_MAX_RX_RING_NUM; i++) {
-			ring = &eth->rx_ring[i];
-			if (ring->calc_idx_update) {
-				ring->calc_idx_update = false;
-				mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg);
-			}
-		}
-	}
+	mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg);
 }
 
 static bool mtk_page_pool_enabled(struct mtk_eth *eth)
@@ -1913,7 +1876,7 @@ static struct page_pool *mtk_create_page_pool(struct mtk_eth *eth,
 		return pp;
 
 	err = __xdp_rxq_info_reg(xdp_q, eth->dummy_dev, id,
-				 eth->rx_napi.napi_id, PAGE_SIZE);
+				 eth->rx_napi[id].napi.napi_id, PAGE_SIZE);
 	if (err < 0)
 		goto err_free_pp;
 
@@ -2202,7 +2165,8 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
 		       struct mtk_eth *eth)
 {
 	struct dim_sample dim_sample = {};
-	struct mtk_rx_ring *ring;
+	struct mtk_napi *rx_napi = container_of(napi, struct mtk_napi, napi);
+	struct mtk_rx_ring *ring = rx_napi->rx_ring;
 	bool xdp_flush = false;
 	int idx;
 	struct sk_buff *skb;
@@ -2213,16 +2177,15 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
 	dma_addr_t dma_addr = DMA_MAPPING_ERROR;
 	int ppe_idx = 0;
 
+	if (unlikely(!ring))
+		goto rx_done;
+
 	while (done < budget) {
 		unsigned int pktlen, *rxdcsum;
 		struct net_device *netdev;
 		u32 hash, reason;
 		int mac = 0;
 
-		ring = mtk_get_rx_ring(eth);
-		if (unlikely(!ring))
-			goto rx_done;
-
 		idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size);
 		rxd = ring->dma + idx * eth->soc->rx.desc_size;
 		data = ring->data[idx];
@@ -2414,7 +2377,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
 		 * we continue
 		 */
 		wmb();
-		mtk_update_rx_cpu_idx(eth);
+		mtk_update_rx_cpu_idx(eth, ring);
 	}
 
 	eth->rx_packets += done;
@@ -2623,7 +2586,9 @@ static int mtk_napi_tx(struct napi_struct *napi, int budget)
 
 static int mtk_napi_rx(struct napi_struct *napi, int budget)
 {
-	struct mtk_eth *eth = container_of(napi, struct mtk_eth, rx_napi);
+	struct mtk_napi *rx_napi = container_of(napi, struct mtk_napi, napi);
+	struct mtk_eth *eth = rx_napi->eth;
+	struct mtk_rx_ring *ring = rx_napi->rx_ring;
 	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
 	int rx_done_total = 0;
 
@@ -2632,7 +2597,7 @@ static int mtk_napi_rx(struct napi_struct *napi, int budget)
 	do {
 		int rx_done;
 
-		mtk_w32(eth, eth->soc->rx.irq_done_mask,
+		mtk_w32(eth, MTK_RX_DONE_INT(eth, ring->ring_no),
 			reg_map->pdma.irq_status);
 		rx_done = mtk_poll_rx(napi, budget - rx_done_total, eth);
 		rx_done_total += rx_done;
@@ -2648,10 +2613,10 @@ static int mtk_napi_rx(struct napi_struct *napi, int budget)
 			return budget;
 
 	} while (mtk_r32(eth, reg_map->pdma.irq_status) &
-		 eth->soc->rx.irq_done_mask);
+		 MTK_RX_DONE_INT(eth, ring->ring_no));
 
 	if (napi_complete_done(napi, rx_done_total))
-		mtk_rx_irq_enable(eth, eth->soc->rx.irq_done_mask);
+		mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(eth, ring->ring_no));
 
 	return rx_done_total;
 }
@@ -2897,6 +2862,7 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag)
 	else
 		ring->crx_idx_reg = reg_map->pdma.pcrx_ptr +
 				    ring_no * MTK_QRX_OFFSET;
+	ring->ring_no = ring_no;
 	/* make sure that all changes to the dma ring are flushed before we
 	 * continue
 	 */
@@ -2965,6 +2931,7 @@ static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring, bool in_
 
 static int mtk_hwlro_rx_init(struct mtk_eth *eth)
 {
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
 	int i;
 	u32 ring_ctrl_dw1 = 0, ring_ctrl_dw2 = 0, ring_ctrl_dw3 = 0;
 	u32 lro_ctrl_dw0 = 0, lro_ctrl_dw3 = 0;
@@ -2987,9 +2954,9 @@ static int mtk_hwlro_rx_init(struct mtk_eth *eth)
 	ring_ctrl_dw3 |= MTK_RING_MAX_AGG_CNT_H;
 
 	for (i = 1; i < MTK_MAX_RX_RING_NUM; i++) {
-		mtk_w32(eth, ring_ctrl_dw1, MTK_LRO_CTRL_DW1_CFG(i));
-		mtk_w32(eth, ring_ctrl_dw2, MTK_LRO_CTRL_DW2_CFG(i));
-		mtk_w32(eth, ring_ctrl_dw3, MTK_LRO_CTRL_DW3_CFG(i));
+		mtk_w32(eth, ring_ctrl_dw1, MTK_LRO_CTRL_DW1_CFG(reg_map, i));
+		mtk_w32(eth, ring_ctrl_dw2, MTK_LRO_CTRL_DW2_CFG(reg_map, i));
+		mtk_w32(eth, ring_ctrl_dw3, MTK_LRO_CTRL_DW3_CFG(reg_map, i));
 	}
 
 	/* IPv4 checksum update enable */
@@ -3025,6 +2992,7 @@ static int mtk_hwlro_rx_init(struct mtk_eth *eth)
 
 static void mtk_hwlro_rx_uninit(struct mtk_eth *eth)
 {
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
 	int i;
 	u32 val;
 
@@ -3043,7 +3011,7 @@ static void mtk_hwlro_rx_uninit(struct mtk_eth *eth)
 
 	/* invalidate lro rings */
 	for (i = 1; i < MTK_MAX_RX_RING_NUM; i++)
-		mtk_w32(eth, 0, MTK_LRO_CTRL_DW2_CFG(i));
+		mtk_w32(eth, 0, MTK_LRO_CTRL_DW2_CFG(reg_map, i));
 
 	/* disable HW LRO */
 	mtk_w32(eth, 0, MTK_PDMA_LRO_CTRL_DW0);
@@ -3051,27 +3019,29 @@ static void mtk_hwlro_rx_uninit(struct mtk_eth *eth)
 
 static void mtk_hwlro_val_ipaddr(struct mtk_eth *eth, int idx, __be32 ip)
 {
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
 	u32 reg_val;
 
-	reg_val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(idx));
+	reg_val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(reg_map, idx));
 
 	/* invalidate the IP setting */
-	mtk_w32(eth, (reg_val & ~MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(idx));
+	mtk_w32(eth, (reg_val & ~MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(reg_map, idx));
 
 	mtk_w32(eth, ip, MTK_LRO_DIP_DW0_CFG(idx));
 
 	/* validate the IP setting */
-	mtk_w32(eth, (reg_val | MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(idx));
+	mtk_w32(eth, (reg_val | MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(reg_map, idx));
 }
 
 static void mtk_hwlro_inval_ipaddr(struct mtk_eth *eth, int idx)
 {
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
 	u32 reg_val;
 
-	reg_val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(idx));
+	reg_val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(reg_map, idx));
 
 	/* invalidate the IP setting */
-	mtk_w32(eth, (reg_val & ~MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(idx));
+	mtk_w32(eth, (reg_val & ~MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(reg_map, idx));
 
 	mtk_w32(eth, 0, MTK_LRO_DIP_DW0_CFG(idx));
 }
@@ -3201,6 +3171,105 @@ static int mtk_hwlro_get_fdir_all(struct net_device *dev,
 	return 0;
 }
 
+static u32 mtk_rss_indr_table(struct mtk_rss_params *rss_params, int index)
+{
+	u32 val = 0;
+	int i;
+
+	for (i = 16 * index; i < 16 * index + 16; i++)
+		val |= (rss_params->indirection_table[i] << (2 * (i % 16)));
+
+	return val;
+}
+
+static int mtk_rss_init(struct mtk_eth *eth)
+{
+	const struct mtk_soc_data *soc = eth->soc;
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
+	struct mtk_rss_params *rss_params = &eth->rss_params;
+	u32 val;
+	int i;
+
+	netdev_rss_key_fill(rss_params->hash_key, MTK_RSS_HASH_KEYSIZE);
+
+	for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE; i++)
+		rss_params->indirection_table[i] = ethtool_rxfh_indir_default(i, eth->soc->rss_num);
+
+	if (soc->rx.desc_size == sizeof(struct mtk_rx_dma)) {
+		/* Set RSS rings to PSE modes */
+		for (i = 1; i <= MTK_HW_LRO_RING_NUM(eth); i++) {
+			val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(reg_map, i));
+			val |= MTK_RING_PSE_MODE;
+			mtk_w32(eth, val, MTK_LRO_CTRL_DW2_CFG(reg_map, i));
+		}
+
+		/* Enable non-lro multiple rx */
+		val = mtk_r32(eth, reg_map->pdma.lro_ctrl_dw0);
+		val |= MTK_NON_LRO_MULTI_EN;
+		mtk_w32(eth, val, reg_map->pdma.lro_ctrl_dw0);
+
+		/* Enable RSS dly int supoort */
+		val |= MTK_LRO_DLY_INT_EN;
+		mtk_w32(eth, val, reg_map->pdma.lro_ctrl_dw0);
+	}
+
+	/* Hash Type */
+	val = mtk_r32(eth, reg_map->pdma.rss_glo_cfg);
+	val |= MTK_RSS_IPV4_STATIC_HASH;
+	val |= MTK_RSS_IPV6_STATIC_HASH;
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+	/* Hash Key */
+	for (i = 0; i < MTK_RSS_HASH_KEYSIZE / sizeof(u32); i++)
+		mtk_w32(eth, rss_params->hash_key[i], MTK_RSS_HASH_KEY_DW(reg_map, i));
+
+	/* Select the size of indirection table */
+	for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE / 16; i++)
+		mtk_w32(eth, mtk_rss_indr_table(rss_params, i),
+			MTK_RSS_INDR_TABLE_DW(reg_map, i));
+
+	/* Pause */
+	val |= MTK_RSS_CFG_REQ;
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+	/* Enable RSS */
+	val |= MTK_RSS_EN;
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+	/* Release pause */
+	val &= ~(MTK_RSS_CFG_REQ);
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+	/* Set perRSS GRP INT */
+	mtk_m32(eth, MTK_RX_DONE_INT(eth, MTK_RSS_RING(1)),
+		MTK_RX_DONE_INT(eth, MTK_RSS_RING(1)), reg_map->pdma.int_grp);
+	mtk_m32(eth, MTK_RX_DONE_INT(eth, MTK_RSS_RING(2)),
+		MTK_RX_DONE_INT(eth, MTK_RSS_RING(2)), reg_map->pdma.int_grp + 0x4);
+	mtk_m32(eth, MTK_RX_DONE_INT(eth, MTK_RSS_RING(3)),
+		MTK_RX_DONE_INT(eth, MTK_RSS_RING(3)), reg_map->pdma.int_grp3);
+
+	return 0;
+}
+
+static void mtk_rss_uninit(struct mtk_eth *eth)
+{
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
+	u32 val;
+
+	/* Pause */
+	val = mtk_r32(eth, reg_map->pdma.rss_glo_cfg);
+	val |= MTK_RSS_CFG_REQ;
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+	/* Disable RSS */
+	val &= ~(MTK_RSS_EN);
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+	/* Release pause */
+	val &= ~(MTK_RSS_CFG_REQ);
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+}
+
 static netdev_features_t mtk_fix_features(struct net_device *dev,
 					  netdev_features_t features)
 {
@@ -3291,6 +3360,17 @@ static int mtk_dma_init(struct mtk_eth *eth)
 			return err;
 	}
 
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		for (i = 1; i < MTK_RX_RSS_NUM(eth); i++) {
+			err = mtk_rx_alloc(eth, MTK_RSS_RING(i), MTK_RX_FLAGS_NORMAL);
+			if (err)
+				return err;
+		}
+		err = mtk_rss_init(eth);
+		if (err)
+			return err;
+	}
+
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {
 		/* Enable random early drop and set drop threshold
 		 * automatically
@@ -3337,6 +3417,12 @@ static void mtk_dma_free(struct mtk_eth *eth)
 			mtk_rx_clean(eth, &eth->rx_ring[i], false);
 	}
 
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		mtk_rss_uninit(eth);
+		for (i = 1; i < MTK_RX_RSS_NUM(eth); i++)
+			mtk_rx_clean(eth, &eth->rx_ring[MTK_RSS_RING(i)], true);
+	}
+
 	for (i = 0; i < DIV_ROUND_UP(soc->tx.fq_dma_size, MTK_FQ_DMA_LENGTH); i++) {
 		kfree(eth->scratch_head[i]);
 		eth->scratch_head[i] = NULL;
@@ -3369,23 +3455,23 @@ static void mtk_tx_timeout(struct net_device *dev, unsigned int txqueue)
 	schedule_work(&eth->pending_work);
 }
 
-static int mtk_get_irqs(struct platform_device *pdev, struct mtk_eth *eth)
+static int mtk_get_irqs_fe(struct platform_device *pdev, struct mtk_eth *eth)
 {
 	int i;
 
 	/* future SoCs beginning with MT7988 should use named IRQs in dts */
-	eth->irq[MTK_FE_IRQ_TX] = platform_get_irq_byname_optional(pdev, "fe1");
-	eth->irq[MTK_FE_IRQ_RX] = platform_get_irq_byname_optional(pdev, "fe2");
-	if (eth->irq[MTK_FE_IRQ_TX] >= 0 && eth->irq[MTK_FE_IRQ_RX] >= 0)
+	eth->irq_fe[MTK_FE_IRQ_TX] = platform_get_irq_byname_optional(pdev, "fe1");
+	eth->irq_fe[MTK_FE_IRQ_RX] = platform_get_irq_byname_optional(pdev, "fe2");
+	if (eth->irq_fe[MTK_FE_IRQ_TX] >= 0 && eth->irq_fe[MTK_FE_IRQ_RX] >= 0)
 		return 0;
 
 	/* only use legacy mode if platform_get_irq_byname_optional returned -ENXIO */
-	if (eth->irq[MTK_FE_IRQ_TX] != -ENXIO)
-		return dev_err_probe(&pdev->dev, eth->irq[MTK_FE_IRQ_TX],
+	if (eth->irq_fe[MTK_FE_IRQ_TX] != -ENXIO)
+		return dev_err_probe(&pdev->dev, eth->irq_fe[MTK_FE_IRQ_TX],
 				     "Error requesting FE TX IRQ\n");
 
-	if (eth->irq[MTK_FE_IRQ_RX] != -ENXIO)
-		return dev_err_probe(&pdev->dev, eth->irq[MTK_FE_IRQ_RX],
+	if (eth->irq_fe[MTK_FE_IRQ_RX] != -ENXIO)
+		return dev_err_probe(&pdev->dev, eth->irq_fe[MTK_FE_IRQ_RX],
 				     "Error requesting FE RX IRQ\n");
 
 	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT))
@@ -3400,14 +3486,14 @@ static int mtk_get_irqs(struct platform_device *pdev, struct mtk_eth *eth)
 	for (i = 0; i < MTK_FE_IRQ_NUM; i++) {
 		if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT)) {
 			if (i == MTK_FE_IRQ_SHARED)
-				eth->irq[MTK_FE_IRQ_SHARED] = platform_get_irq(pdev, i);
+				eth->irq_fe[MTK_FE_IRQ_SHARED] = platform_get_irq(pdev, i);
 			else
-				eth->irq[i] = eth->irq[MTK_FE_IRQ_SHARED];
+				eth->irq_fe[i] = eth->irq_fe[MTK_FE_IRQ_SHARED];
 		} else {
-			eth->irq[i] = platform_get_irq(pdev, i + 1);
+			eth->irq_fe[i] = platform_get_irq(pdev, i + 1);
 		}
 
-		if (eth->irq[i] < 0) {
+		if (eth->irq_fe[i] < 0) {
 			dev_err(&pdev->dev, "no IRQ%d resource found\n", i);
 			return -ENXIO;
 		}
@@ -3416,14 +3502,36 @@ static int mtk_get_irqs(struct platform_device *pdev, struct mtk_eth *eth)
 	return 0;
 }
 
-static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth)
+static int mtk_get_irqs_pdma(struct platform_device *pdev, struct mtk_eth *eth)
 {
-	struct mtk_eth *eth = _eth;
+	char rxring[] = "pdma0";
+	int i;
+
+	for (i = 0; i < MTK_PDMA_IRQ_NUM; i++) {
+		rxring[4] = '0' + i;
+		eth->irq_pdma[i] = platform_get_irq_byname(pdev, rxring);
+		if (eth->irq_pdma[i] < 0)
+			return eth->irq_pdma[i];
+	}
+
+	return 0;
+}
+
+static irqreturn_t mtk_handle_irq_rx(int irq, void *priv)
+{
+	struct mtk_napi *rx_napi = priv;
+	struct mtk_eth *eth = rx_napi->eth;
+	struct mtk_rx_ring *ring = rx_napi->rx_ring;
 
 	eth->rx_events++;
-	if (likely(napi_schedule_prep(&eth->rx_napi))) {
-		mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask);
-		__napi_schedule(&eth->rx_napi);
+	if (unlikely(!(mtk_r32(eth, eth->soc->reg_map->pdma.irq_status) &
+		       mtk_r32(eth, eth->soc->reg_map->pdma.irq_mask) &
+		       MTK_RX_DONE_INT(eth, ring->ring_no))))
+		return IRQ_NONE;
+
+	if (likely(napi_schedule_prep(&rx_napi->napi))) {
+		mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(eth, ring->ring_no));
+		__napi_schedule(&rx_napi->napi);
 	}
 
 	return IRQ_HANDLED;
@@ -3448,10 +3556,10 @@ static irqreturn_t mtk_handle_irq(int irq, void *_eth)
 	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
 
 	if (mtk_r32(eth, reg_map->pdma.irq_mask) &
-	    eth->soc->rx.irq_done_mask) {
+	    MTK_RX_DONE_INT(eth, 0)) {
 		if (mtk_r32(eth, reg_map->pdma.irq_status) &
-		    eth->soc->rx.irq_done_mask)
-			mtk_handle_irq_rx(irq, _eth);
+		    MTK_RX_DONE_INT(eth, 0))
+			mtk_handle_irq_rx(irq, &eth->rx_napi[0]);
 	}
 	if (mtk_r32(eth, reg_map->tx_irq_mask) & MTK_TX_DONE_INT) {
 		if (mtk_r32(eth, reg_map->tx_irq_status) & MTK_TX_DONE_INT)
@@ -3468,10 +3576,10 @@ static void mtk_poll_controller(struct net_device *dev)
 	struct mtk_eth *eth = mac->hw;
 
 	mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
-	mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask);
-	mtk_handle_irq_rx(eth->irq[MTK_FE_IRQ_RX], dev);
+	mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(eth, 0));
+	mtk_handle_irq_rx(eth->irq_fe[MTK_FE_IRQ_RX], &eth->rx_napi[0]);
 	mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
-	mtk_rx_irq_enable(eth, eth->soc->rx.irq_done_mask);
+	mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(eth, 0));
 }
 #endif
 
@@ -3643,9 +3751,17 @@ static int mtk_open(struct net_device *dev)
 		}
 
 		napi_enable(&eth->tx_napi);
-		napi_enable(&eth->rx_napi);
+		napi_enable(&eth->rx_napi[0].napi);
 		mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
-		mtk_rx_irq_enable(eth, soc->rx.irq_done_mask);
+		mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(eth, 0));
+
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+			for (i = 1; i < MTK_RX_RSS_NUM(eth); i++) {
+				napi_enable(&eth->rx_napi[MTK_RSS_RING(i)].napi);
+				mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(eth, MTK_RSS_RING(i)));
+			}
+		}
+
 		refcount_set(&eth->dma_refcnt, 1);
 	} else {
 		refcount_inc(&eth->dma_refcnt);
@@ -3730,9 +3846,16 @@ static int mtk_stop(struct net_device *dev)
 		mtk_gdm_config(eth, i, MTK_GDMA_DROP_ALL);
 
 	mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
-	mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask);
+	mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(eth, 0));
 	napi_disable(&eth->tx_napi);
-	napi_disable(&eth->rx_napi);
+	napi_disable(&eth->rx_napi[0].napi);
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		for (i = 1; i < MTK_RX_RSS_NUM(eth); i++) {
+			mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(eth, MTK_RSS_RING(i)));
+			napi_disable(&eth->rx_napi[MTK_RSS_RING(i)].napi);
+		}
+	}
 
 	cancel_work_sync(&eth->rx_dim.work);
 	cancel_work_sync(&eth->tx_dim.work);
@@ -3843,9 +3966,7 @@ static void mtk_dim_rx(struct work_struct *work)
 						dim->profile_ix);
 	spin_lock_bh(&eth->dim_lock);
 
-	val = mtk_r32(eth, reg_map->pdma.delay_irq);
-	val &= MTK_PDMA_DELAY_TX_MASK;
-	val |= MTK_PDMA_DELAY_RX_EN;
+	val = MTK_PDMA_DELAY_RX_EN;
 
 	cur = min_t(u32, DIV_ROUND_UP(cur_profile.usec, 20), MTK_PDMA_DELAY_PTIME_MASK);
 	val |= cur << MTK_PDMA_DELAY_RX_PTIME_SHIFT;
@@ -3853,9 +3974,19 @@ static void mtk_dim_rx(struct work_struct *work)
 	cur = min_t(u32, cur_profile.pkts, MTK_PDMA_DELAY_PINT_MASK);
 	val |= cur << MTK_PDMA_DELAY_RX_PINT_SHIFT;
 
-	mtk_w32(eth, val, reg_map->pdma.delay_irq);
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
-		mtk_w32(eth, val, reg_map->qdma.delay_irq);
+		mtk_m32(eth, MTK_PDMA_DELAY_TX_MASK,
+			val << MTK_PDMA_DELAY_TX_PTIME_SHIFT, reg_map->qdma.delay_irq);
+
+	if (eth->soc->rx.desc_size == sizeof(struct mtk_rx_dma)) {
+		mtk_m32(eth, MTK_PDMA_DELAY_RX_MASK, val, reg_map->pdma.delay_irq);
+		mtk_w32(eth, val, reg_map->pdma.lro_rx1_dly_int);
+		mtk_w32(eth, val, reg_map->pdma.lro_rx1_dly_int + 0x4);
+		mtk_w32(eth, val, reg_map->pdma.lro_rx1_dly_int + 0x8);
+	} else {
+		val = val | (val << MTK_PDMA_DELAY_RX_RING_SHIFT);
+		mtk_w32(eth, val, reg_map->pdma.rx_delay_irq);
+	}
 
 	spin_unlock_bh(&eth->dim_lock);
 
@@ -3874,9 +4005,7 @@ static void mtk_dim_tx(struct work_struct *work)
 						dim->profile_ix);
 	spin_lock_bh(&eth->dim_lock);
 
-	val = mtk_r32(eth, reg_map->pdma.delay_irq);
-	val &= MTK_PDMA_DELAY_RX_MASK;
-	val |= MTK_PDMA_DELAY_TX_EN;
+	val = MTK_PDMA_DELAY_TX_EN;
 
 	cur = min_t(u32, DIV_ROUND_UP(cur_profile.usec, 20), MTK_PDMA_DELAY_PTIME_MASK);
 	val |= cur << MTK_PDMA_DELAY_TX_PTIME_SHIFT;
@@ -3884,9 +4013,16 @@ static void mtk_dim_tx(struct work_struct *work)
 	cur = min_t(u32, cur_profile.pkts, MTK_PDMA_DELAY_PINT_MASK);
 	val |= cur << MTK_PDMA_DELAY_TX_PINT_SHIFT;
 
-	mtk_w32(eth, val, reg_map->pdma.delay_irq);
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
-		mtk_w32(eth, val, reg_map->qdma.delay_irq);
+		mtk_m32(eth, MTK_PDMA_DELAY_RX_MASK,
+			val >> MTK_PDMA_DELAY_TX_PTIME_SHIFT, reg_map->qdma.delay_irq);
+
+	if (eth->soc->rx.desc_size == sizeof(struct mtk_rx_dma)) {
+		mtk_m32(eth, MTK_PDMA_DELAY_TX_MASK, val, reg_map->pdma.delay_irq);
+	} else {
+		mtk_w32(eth, val >> MTK_PDMA_DELAY_TX_PTIME_SHIFT,
+			reg_map->pdma.tx_delay_irq);
+	}
 
 	spin_unlock_bh(&eth->dim_lock);
 
@@ -4104,6 +4240,25 @@ static void mtk_hw_reset_monitor_work(struct work_struct *work)
 			      MTK_DMA_MONITOR_TIMEOUT);
 }
 
+static int mtk_napi_init(struct mtk_eth *eth)
+{
+	struct mtk_napi *rx_napi = &eth->rx_napi[0];
+	int i;
+
+	rx_napi->eth = eth;
+	rx_napi->rx_ring = &eth->rx_ring[0];
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		for (i = 1; i < MTK_RX_RSS_NUM(eth); i++) {
+			rx_napi = &eth->rx_napi[MTK_RSS_RING(i)];
+			rx_napi->eth = eth;
+			rx_napi->rx_ring = &eth->rx_ring[MTK_RSS_RING(i)];
+		}
+	}
+
+	return 0;
+}
+
 static int mtk_hw_init(struct mtk_eth *eth, bool reset)
 {
 	u32 dma_mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA |
@@ -4193,12 +4348,11 @@ static int mtk_hw_init(struct mtk_eth *eth, bool reset)
 	 */
 	val = mtk_r32(eth, MTK_CDMQ_IG_CTRL);
 	mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL);
-	if (mtk_is_netsys_v1(eth)) {
-		val = mtk_r32(eth, MTK_CDMP_IG_CTRL);
-		mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL);
+	val = mtk_r32(eth, MTK_CDMP_IG_CTRL);
+	mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL);
 
+	if (mtk_is_netsys_v1(eth))
 		mtk_w32(eth, 1, MTK_CDMP_EG_CTRL);
-	}
 
 	/* set interrupt delays based on current Net DIM sample */
 	mtk_dim_rx(&eth->rx_dim.work);
@@ -4209,11 +4363,17 @@ static int mtk_hw_init(struct mtk_eth *eth, bool reset)
 	mtk_rx_irq_disable(eth, ~0);
 
 	/* FE int grouping */
-	mtk_w32(eth, MTK_TX_DONE_INT, reg_map->pdma.int_grp);
-	mtk_w32(eth, eth->soc->rx.irq_done_mask, reg_map->pdma.int_grp + 4);
+
 	mtk_w32(eth, MTK_TX_DONE_INT, reg_map->qdma.int_grp);
-	mtk_w32(eth, eth->soc->rx.irq_done_mask, reg_map->qdma.int_grp + 4);
-	mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP);
+	mtk_w32(eth, MTK_RX_DONE_INT(eth, 0), reg_map->qdma.int_grp + 4);
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_PDMA_INT)) {
+		mtk_w32(eth, 0x210FFFF2, MTK_FE_INT_GRP);
+	} else {
+		mtk_w32(eth, MTK_TX_DONE_INT, reg_map->pdma.int_grp);
+		mtk_w32(eth, MTK_RX_DONE_INT(eth, 0), reg_map->pdma.int_grp + 4);
+		mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP);
+	}
 
 	if (mtk_is_netsys_v3_or_greater(eth)) {
 		/* PSE dummy page mechanism */
@@ -4651,6 +4811,8 @@ static void mtk_get_ethtool_stats(struct net_device *dev,
 static int mtk_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
 			 u32 *rule_locs)
 {
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
 	int ret = -EOPNOTSUPP;
 
 	switch (cmd->cmd) {
@@ -4658,6 +4820,9 @@ static int mtk_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
 		if (dev->hw_features & NETIF_F_LRO) {
 			cmd->data = MTK_MAX_RX_RING_NUM;
 			ret = 0;
+		} else if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+			cmd->data = MTK_RX_RSS_NUM(eth);
+			ret = 0;
 		}
 		break;
 	case ETHTOOL_GRXCLSRLCNT:
@@ -4732,6 +4897,70 @@ static int mtk_set_eee(struct net_device *dev, struct ethtool_keee *eee)
 	return phylink_ethtool_set_eee(mac->phylink, eee);
 }
 
+static u32 mtk_get_rxfh_key_size(struct net_device *dev)
+{
+	return MTK_RSS_HASH_KEYSIZE;
+}
+
+static u32 mtk_get_rxfh_indir_size(struct net_device *dev)
+{
+	return MTK_RSS_MAX_INDIRECTION_TABLE;
+}
+
+static int mtk_get_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	struct mtk_rss_params *rss_params = &eth->rss_params;
+	int i;
+
+	rxfh->hfunc = ETH_RSS_HASH_TOP;	/* Toeplitz */
+
+	if (rxfh->key) {
+		memcpy(rxfh->key, rss_params->hash_key,
+		       sizeof(rss_params->hash_key));
+	}
+
+	if (rxfh->indir) {
+		for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE; i++)
+			rxfh->indir[i] = rss_params->indirection_table[i];
+	}
+
+	return 0;
+}
+
+static int mtk_set_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh,
+			struct netlink_ext_ack *extack)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	struct mtk_rss_params *rss_params = &eth->rss_params;
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
+	int i;
+
+	if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+	    rxfh->hfunc != ETH_RSS_HASH_TOP)
+		return -EOPNOTSUPP;
+
+	if (rxfh->key) {
+		memcpy(rss_params->hash_key, rxfh->key,
+		       sizeof(rss_params->hash_key));
+		for (i = 0; i < MTK_RSS_HASH_KEYSIZE / sizeof(u32); i++)
+			mtk_w32(eth, rss_params->hash_key[i],
+				MTK_RSS_HASH_KEY_DW(reg_map, i));
+	}
+
+	if (rxfh->indir) {
+		for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE; i++)
+			rss_params->indirection_table[i] = rxfh->indir[i];
+		for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE / 16; i++)
+			mtk_w32(eth, mtk_rss_indr_table(rss_params, i),
+				MTK_RSS_INDR_TABLE_DW(reg_map, i));
+	}
+
+	return 0;
+}
+
 static u16 mtk_select_queue(struct net_device *dev, struct sk_buff *skb,
 			    struct net_device *sb_dev)
 {
@@ -4766,6 +4995,10 @@ static const struct ethtool_ops mtk_ethtool_ops = {
 	.set_rxnfc		= mtk_set_rxnfc,
 	.get_eee		= mtk_get_eee,
 	.set_eee		= mtk_set_eee,
+	.get_rxfh_key_size	= mtk_get_rxfh_key_size,
+	.get_rxfh_indir_size	= mtk_get_rxfh_indir_size,
+	.get_rxfh		= mtk_get_rxfh,
+	.set_rxfh		= mtk_set_rxfh,
 };
 
 static const struct net_device_ops mtk_netdev_ops = {
@@ -4955,7 +5188,7 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
 	eth->netdev[id]->features |= eth->soc->hw_features;
 	eth->netdev[id]->ethtool_ops = &mtk_ethtool_ops;
 
-	eth->netdev[id]->irq = eth->irq[MTK_FE_IRQ_SHARED];
+	eth->netdev[id]->irq = eth->irq_fe[MTK_FE_IRQ_SHARED];
 	eth->netdev[id]->dev.of_node = np;
 
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628))
@@ -5066,6 +5299,7 @@ static int mtk_probe(struct platform_device *pdev)
 	struct resource *res = NULL;
 	struct device_node *mac_np;
 	struct mtk_eth *eth;
+	char *irqname;
 	int err, i;
 
 	eth = devm_kzalloc(&pdev->dev, sizeof(*eth), GFP_KERNEL);
@@ -5197,10 +5431,16 @@ static int mtk_probe(struct platform_device *pdev)
 		}
 	}
 
-	err = mtk_get_irqs(pdev, eth);
+	err = mtk_get_irqs_fe(pdev, eth);
 	if (err)
 		goto err_wed_exit;
 
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_PDMA_INT)) {
+		err = mtk_get_irqs_pdma(pdev, eth);
+		if (err)
+			goto err_wed_exit;
+	}
+
 	for (i = 0; i < ARRAY_SIZE(eth->clks); i++) {
 		eth->clks[i] = devm_clk_get(eth->dev,
 					    mtk_clks_source_name[i]);
@@ -5243,23 +5483,56 @@ static int mtk_probe(struct platform_device *pdev)
 		}
 	}
 
+	err = mtk_napi_init(eth);
+	if (err)
+		goto err_free_dev;
+
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT)) {
-		err = devm_request_irq(eth->dev, eth->irq[MTK_FE_IRQ_SHARED],
+		err = devm_request_irq(eth->dev, eth->irq_fe[MTK_FE_IRQ_SHARED],
 				       mtk_handle_irq, 0,
 				       dev_name(eth->dev), eth);
 	} else {
-		err = devm_request_irq(eth->dev, eth->irq[MTK_FE_IRQ_TX],
+		irqname = devm_kasprintf(eth->dev, GFP_KERNEL, "%s TX",
+					 dev_name(eth->dev));
+		err = devm_request_irq(eth->dev, eth->irq_fe[MTK_FE_IRQ_TX],
 				       mtk_handle_irq_tx, 0,
-				       dev_name(eth->dev), eth);
+				       irqname, eth);
 		if (err)
 			goto err_free_dev;
 
-		err = devm_request_irq(eth->dev, eth->irq[MTK_FE_IRQ_RX],
-				       mtk_handle_irq_rx, 0,
-				       dev_name(eth->dev), eth);
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_PDMA_INT)) {
+			irqname = devm_kasprintf(eth->dev, GFP_KERNEL, "%s PDMA RX %d",
+						 dev_name(eth->dev), 0);
+			err = devm_request_irq(eth->dev, eth->irq_pdma[0],
+					       mtk_handle_irq_rx, IRQF_SHARED,
+					       irqname, &eth->rx_napi[0]);
+			if (err)
+				goto err_free_dev;
+
+			if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+				for (i = 1; i < MTK_RX_RSS_NUM(eth); i++) {
+					irqname = devm_kasprintf(eth->dev, GFP_KERNEL,
+								 "%s PDMA RX %d",
+								 dev_name(eth->dev), i);
+					err = devm_request_irq(eth->dev,
+							       eth->irq_pdma[MTK_RSS_RING(i)],
+							       mtk_handle_irq_rx, IRQF_SHARED,
+							       irqname,
+							       &eth->rx_napi[MTK_RSS_RING(i)]);
+					if (err)
+						goto err_free_dev;
+				}
+			}
+		} else {
+			irqname = devm_kasprintf(eth->dev, GFP_KERNEL, "%s RX",
+						 dev_name(eth->dev));
+			err = devm_request_irq(eth->dev, eth->irq_fe[MTK_FE_IRQ_RX],
+					       mtk_handle_irq_rx, 0,
+					       irqname, &eth->rx_napi[0]);
+			if (err)
+				goto err_free_dev;
+		}
 	}
-	if (err)
-		goto err_free_dev;
 
 	/* No MT7628/88 support yet */
 	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) {
@@ -5300,7 +5573,7 @@ static int mtk_probe(struct platform_device *pdev)
 		} else
 			netif_info(eth, probe, eth->netdev[i],
 				   "mediatek frame engine at 0x%08lx, irq %d\n",
-				   eth->netdev[i]->base_addr, eth->irq[MTK_FE_IRQ_SHARED]);
+				   eth->netdev[i]->base_addr, eth->irq_fe[MTK_FE_IRQ_SHARED]);
 	}
 
 	/* we run 2 devices on the same DMA ring so we need a dummy device
@@ -5313,7 +5586,13 @@ static int mtk_probe(struct platform_device *pdev)
 		goto err_unreg_netdev;
 	}
 	netif_napi_add(eth->dummy_dev, &eth->tx_napi, mtk_napi_tx);
-	netif_napi_add(eth->dummy_dev, &eth->rx_napi, mtk_napi_rx);
+	netif_napi_add(eth->dummy_dev, &eth->rx_napi[0].napi, mtk_napi_rx);
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		for (i = 1; i < MTK_RX_RSS_NUM(eth); i++)
+			netif_napi_add(eth->dummy_dev, &eth->rx_napi[MTK_RSS_RING(i)].napi,
+				       mtk_napi_rx);
+	}
 
 	platform_set_drvdata(pdev, eth);
 	schedule_delayed_work(&eth->reset.monitor_work,
@@ -5357,7 +5636,12 @@ static void mtk_remove(struct platform_device *pdev)
 	mtk_hw_deinit(eth);
 
 	netif_napi_del(&eth->tx_napi);
-	netif_napi_del(&eth->rx_napi);
+	netif_napi_del(&eth->rx_napi[0].napi);
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		for (i = 1; i < MTK_RX_RSS_NUM(eth); i++)
+			netif_napi_del(&eth->rx_napi[MTK_RSS_RING(i)].napi);
+	}
 	mtk_cleanup(eth);
 	free_netdev(eth->dummy_dev);
 	mtk_mdio_cleanup(eth);
@@ -5370,6 +5654,7 @@ static const struct mtk_soc_data mt2701_data = {
 	.required_clks = MT7623_CLKS_BITMAP,
 	.required_pctl = true,
 	.version = 1,
+	.rss_num = 0,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5379,7 +5664,6 @@ static const struct mtk_soc_data mt2701_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID,
 		.dma_size = MTK_DMA_SIZE(2K),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5398,6 +5682,7 @@ static const struct mtk_soc_data mt7621_data = {
 	.ppe_num = 1,
 	.hash_offset = 2,
 	.foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
+	.rss_num = 0,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5407,7 +5692,6 @@ static const struct mtk_soc_data mt7621_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID,
 		.dma_size = MTK_DMA_SIZE(2K),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5428,6 +5712,7 @@ static const struct mtk_soc_data mt7622_data = {
 	.hash_offset = 2,
 	.has_accounting = true,
 	.foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
+	.rss_num = 0,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5437,7 +5722,6 @@ static const struct mtk_soc_data mt7622_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID,
 		.dma_size = MTK_DMA_SIZE(2K),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5457,6 +5741,7 @@ static const struct mtk_soc_data mt7623_data = {
 	.hash_offset = 2,
 	.foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
 	.disable_pll_modes = true,
+	.rss_num = 0,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5466,7 +5751,6 @@ static const struct mtk_soc_data mt7623_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID,
 		.dma_size = MTK_DMA_SIZE(2K),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5483,6 +5767,7 @@ static const struct mtk_soc_data mt7629_data = {
 	.required_pctl = false,
 	.has_accounting = true,
 	.version = 1,
+	.rss_num = 0,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5492,7 +5777,6 @@ static const struct mtk_soc_data mt7629_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID,
 		.dma_size = MTK_DMA_SIZE(2K),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5513,16 +5797,16 @@ static const struct mtk_soc_data mt7981_data = {
 	.hash_offset = 4,
 	.has_accounting = true,
 	.foe_entry_size = MTK_FOE_ENTRY_V2_SIZE,
+	.rss_num = 4,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma_v2),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
 		.dma_len_offset = 8,
-		.dma_size = MTK_DMA_SIZE(2K),
+		.dma_size = MTK_DMA_SIZE(4K),
 		.fq_dma_size = MTK_DMA_SIZE(2K),
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID_V2,
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
 		.dma_len_offset = 16,
@@ -5543,6 +5827,7 @@ static const struct mtk_soc_data mt7986_data = {
 	.hash_offset = 4,
 	.has_accounting = true,
 	.foe_entry_size = MTK_FOE_ENTRY_V2_SIZE,
+	.rss_num = 4,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma_v2),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
@@ -5552,7 +5837,6 @@ static const struct mtk_soc_data mt7986_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID_V2,
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
 		.dma_len_offset = 16,
@@ -5573,20 +5857,20 @@ static const struct mtk_soc_data mt7988_data = {
 	.hash_offset = 4,
 	.has_accounting = true,
 	.foe_entry_size = MTK_FOE_ENTRY_V3_SIZE,
+	.rss_num = 4,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma_v2),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
 		.dma_len_offset = 8,
-		.dma_size = MTK_DMA_SIZE(2K),
+		.dma_size = MTK_DMA_SIZE(4K),
 		.fq_dma_size = MTK_DMA_SIZE(4K),
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma_v2),
-		.irq_done_mask = MTK_RX_DONE_INT_V2,
 		.dma_l4_valid = RX_DMA_L4_VALID_V2,
 		.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
 		.dma_len_offset = 8,
-		.dma_size = MTK_DMA_SIZE(2K),
+		.dma_size = MTK_DMA_SIZE(1K),
 	},
 };
 
@@ -5597,6 +5881,7 @@ static const struct mtk_soc_data rt5350_data = {
 	.required_clks = MT7628_CLKS_BITMAP,
 	.required_pctl = false,
 	.version = 1,
+	.rss_num = 0,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5605,7 +5890,6 @@ static const struct mtk_soc_data rt5350_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID_PDMA,
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
 		.dma_len_offset = 16,
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index 334625814b97..1ef4a210a4cd 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -76,6 +76,8 @@
 #define	MTK_HW_LRO_BW_THRE		3000
 #define	MTK_HW_LRO_REPLACE_DELTA	1000
 #define	MTK_HW_LRO_SDL_REMAIN_ROOM	1522
+#define MTK_RSS_HASH_KEYSIZE		40
+#define MTK_RSS_MAX_INDIRECTION_TABLE	128
 
 /* Frame Engine Global Configuration */
 #define MTK_FE_GLO_CFG(x)	(((x) == MTK_GMAC3_ID) ? 0x24 : 0x00)
@@ -97,6 +99,8 @@
 #define MTK_GDM1_AF		BIT(28)
 #define MTK_GDM2_AF		BIT(29)
 
+#define MTK_PDMA_IRQ_NUM	(4)
+
 /* PDMA HW LRO Alter Flow Timer Register */
 #define MTK_PDMA_LRO_ALT_REFRESH_TIMER	0x1c
 
@@ -179,7 +183,10 @@
 
 /* PDMA HW LRO Control Registers */
 #define MTK_PDMA_LRO_CTRL_DW0	0x980
+#define MTK_HW_LRO_RING_NUM(eth)		(mtk_is_netsys_v3_or_greater(eth) ? 4 : 3)
 #define MTK_LRO_EN			BIT(0)
+#define MTK_NON_LRO_MULTI_EN		BIT(2)
+#define MTK_LRO_DLY_INT_EN		BIT(5)
 #define MTK_L3_CKS_UPD_EN		BIT(7)
 #define MTK_L3_CKS_UPD_EN_V2		BIT(19)
 #define MTK_LRO_ALT_PKT_CNT_MODE	BIT(21)
@@ -198,6 +205,19 @@
 #define MTK_MULTI_EN		BIT(10)
 #define MTK_PDMA_SIZE_8DWORDS	(1 << 4)
 
+/* PDMA RSS Control Registers */
+#define MTK_RX_NAPI_NUM			(4)
+#define MTK_RX_RSS_NUM(eth)		(eth->soc->rss_num)
+#define MTK_RSS_RING(x)			(x)
+#define MTK_RSS_EN			BIT(0)
+#define MTK_RSS_CFG_REQ			BIT(2)
+#define MTK_RSS_IPV6_STATIC_HASH	(0x7 << 8)
+#define MTK_RSS_IPV4_STATIC_HASH	(0x7 << 12)
+#define MTK_RSS_HASH_KEY_DW(reg_map, x)		(reg_map->pdma.rss_glo_cfg + 0x20 +	\
+						((x) * 0x4))
+#define MTK_RSS_INDR_TABLE_DW(reg_map, x)	(reg_map->pdma.rss_glo_cfg + 0x50 +	\
+						((x) * 0x4))
+
 /* PDMA Global Configuration Register */
 #define MTK_PDMA_LRO_SDL	0x3000
 #define MTK_RX_CFG_SDL_OFFSET	16
@@ -209,6 +229,7 @@
 /* PDMA Delay Interrupt Register */
 #define MTK_PDMA_DELAY_RX_MASK		GENMASK(15, 0)
 #define MTK_PDMA_DELAY_RX_EN		BIT(15)
+#define MTK_PDMA_DELAY_RX_RING_SHIFT	16
 #define MTK_PDMA_DELAY_RX_PINT_SHIFT	8
 #define MTK_PDMA_DELAY_RX_PTIME_SHIFT	0
 
@@ -229,14 +250,12 @@
 #define MTK_RING_MYIP_VLD		BIT(9)
 
 /* PDMA HW LRO Ring Control Registers */
-#define MTK_LRO_RX_RING0_CTRL_DW1	0xb28
-#define MTK_LRO_RX_RING0_CTRL_DW2	0xb2c
-#define MTK_LRO_RX_RING0_CTRL_DW3	0xb30
-#define MTK_LRO_CTRL_DW1_CFG(x)		(MTK_LRO_RX_RING0_CTRL_DW1 + (x * 0x40))
-#define MTK_LRO_CTRL_DW2_CFG(x)		(MTK_LRO_RX_RING0_CTRL_DW2 + (x * 0x40))
-#define MTK_LRO_CTRL_DW3_CFG(x)		(MTK_LRO_RX_RING0_CTRL_DW3 + (x * 0x40))
+#define MTK_LRO_CTRL_DW1_CFG(reg_map, x)	(reg_map->pdma.lro_ring_ctrl_dw1 + ((x) * 0x40))
+#define MTK_LRO_CTRL_DW2_CFG(reg_map, x)	(reg_map->pdma.lro_ring_ctrl_dw1 + 0x4 + ((x) * 0x40))
+#define MTK_LRO_CTRL_DW3_CFG(reg_map, x)	(reg_map->pdma.lro_ring_ctrl_dw1 + 0x8 + ((x) * 0x40))
 #define MTK_RING_AGE_TIME_L		((MTK_HW_LRO_AGE_TIME & 0x3ff) << 22)
 #define MTK_RING_AGE_TIME_H		((MTK_HW_LRO_AGE_TIME >> 10) & 0x3f)
+#define MTK_RING_PSE_MODE		BIT(6)
 #define MTK_RING_AUTO_LERAN_MODE	(3 << 6)
 #define MTK_RING_VLD			BIT(8)
 #define MTK_RING_MAX_AGG_TIME		((MTK_HW_LRO_AGG_TIME & 0xffff) << 10)
@@ -290,7 +309,20 @@
 #define FC_THRES_MIN		0x4444
 
 /* QDMA Interrupt Status Register */
-#define MTK_RX_DONE_DLY		BIT(30)
+#define MTK_RX_DONE_INT_V1(ring_no) \
+	( \
+		(ring_no) ? \
+		BIT(24 + (ring_no)) : \
+		BIT(30) \
+	)
+
+#define MTK_RX_DONE_INT_V2(ring_no)	BIT(24 + (ring_no))
+
+#define MTK_RX_DONE_INT(eth, ring_no)		\
+	(mtk_is_netsys_v3_or_greater(eth) ?  \
+	 MTK_RX_DONE_INT_V2(ring_no) : \
+	 MTK_RX_DONE_INT_V1(ring_no))
+
 #define MTK_TX_DONE_DLY		BIT(28)
 #define MTK_RX_DONE_INT3	BIT(19)
 #define MTK_RX_DONE_INT2	BIT(18)
@@ -300,11 +332,8 @@
 #define MTK_TX_DONE_INT2	BIT(2)
 #define MTK_TX_DONE_INT1	BIT(1)
 #define MTK_TX_DONE_INT0	BIT(0)
-#define MTK_RX_DONE_INT		MTK_RX_DONE_DLY
 #define MTK_TX_DONE_INT		MTK_TX_DONE_DLY
 
-#define MTK_RX_DONE_INT_V2	BIT(14)
-
 #define MTK_CDM_TXFIFO_RDY	BIT(7)
 
 /* QDMA Interrupt grouping registers */
@@ -942,6 +971,7 @@ struct mtk_tx_ring {
 	struct mtk_tx_dma *dma_pdma;	/* For MT7628/88 PDMA handling */
 	dma_addr_t phys_pdma;
 	int cpu_idx;
+	bool in_sram;
 };
 
 /* PDMA rx ring mode */
@@ -967,13 +997,38 @@ struct mtk_rx_ring {
 	u16 buf_size;
 	u16 dma_size;
 	bool calc_idx_update;
+	bool in_sram;
 	u16 calc_idx;
 	u32 crx_idx_reg;
+	u32 ring_no;
 	/* page_pool */
 	struct page_pool *page_pool;
 	struct xdp_rxq_info xdp_q;
 };
 
+/* struct mtk_rss_params -	This is the structure holding parameters
+ *				for the RSS ring
+ * @hash_key			The element is used to record the
+ *				secret key for the RSS ring
+ * indirection_table		The element is used to record the
+ *				indirection table for the RSS ring
+ */
+struct mtk_rss_params {
+	u32		hash_key[MTK_RSS_HASH_KEYSIZE / sizeof(u32)];
+	u8		indirection_table[MTK_RSS_MAX_INDIRECTION_TABLE];
+};
+
+/* struct mtk_napi -	This is the structure holding NAPI-related information,
+ *			and a mtk_napi struct is binding to one interrupt group
+ * @napi:		The NAPI struct
+ * @rx_ring:		Pointer to the memory holding info about the RX ring
+ */
+struct mtk_napi {
+	struct napi_struct	napi;
+	struct mtk_eth		*eth;
+	struct mtk_rx_ring	*rx_ring;
+};
+
 enum mkt_eth_capabilities {
 	MTK_RGMII_BIT = 0,
 	MTK_TRGMII_BIT,
@@ -985,7 +1040,9 @@ enum mkt_eth_capabilities {
 	MTK_INFRA_BIT,
 	MTK_SHARED_SGMII_BIT,
 	MTK_HWLRO_BIT,
+	MTK_RSS_BIT,
 	MTK_SHARED_INT_BIT,
+	MTK_PDMA_INT_BIT,
 	MTK_TRGMII_MT7621_CLK_BIT,
 	MTK_QDMA_BIT,
 	MTK_SOC_MT7628_BIT,
@@ -1025,7 +1082,9 @@ enum mkt_eth_capabilities {
 #define MTK_INFRA		BIT_ULL(MTK_INFRA_BIT)
 #define MTK_SHARED_SGMII	BIT_ULL(MTK_SHARED_SGMII_BIT)
 #define MTK_HWLRO		BIT_ULL(MTK_HWLRO_BIT)
+#define MTK_RSS			BIT_ULL(MTK_RSS_BIT)
 #define MTK_SHARED_INT		BIT_ULL(MTK_SHARED_INT_BIT)
+#define MTK_PDMA_INT		BIT_ULL(MTK_PDMA_INT_BIT)
 #define MTK_TRGMII_MT7621_CLK	BIT_ULL(MTK_TRGMII_MT7621_CLK_BIT)
 #define MTK_QDMA		BIT_ULL(MTK_QDMA_BIT)
 #define MTK_SOC_MT7628		BIT_ULL(MTK_SOC_MT7628_BIT)
@@ -1117,15 +1176,15 @@ enum mkt_eth_capabilities {
 #define MT7981_CAPS  (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC2_GEPHY | \
 		      MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \
 		      MTK_MUX_U3_GMAC2_TO_QPHY | MTK_U3_COPHY_V2 | \
-		      MTK_RSTCTRL_PPE1 | MTK_SRAM)
+		      MTK_RSTCTRL_PPE1 | MTK_SRAM | MTK_PDMA_INT)
 
 #define MT7986_CAPS  (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \
 		      MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \
-		      MTK_RSTCTRL_PPE1 | MTK_SRAM)
+		      MTK_RSTCTRL_PPE1 | MTK_SRAM | MTK_PDMA_INT)
 
 #define MT7988_CAPS  (MTK_36BIT_DMA | MTK_GDM1_ESW | MTK_GMAC2_2P5GPHY | \
 		      MTK_MUX_GMAC2_TO_2P5GPHY | MTK_QDMA | MTK_RSTCTRL_PPE1 | \
-		      MTK_RSTCTRL_PPE2 | MTK_SRAM)
+		      MTK_RSTCTRL_PPE2 | MTK_SRAM | MTK_PDMA_INT | MTK_RSS)
 
 struct mtk_tx_dma_desc_info {
 	dma_addr_t	addr;
@@ -1223,6 +1282,7 @@ struct mtk_reg_map {
 struct mtk_soc_data {
 	const struct mtk_reg_map *reg_map;
 	u32             ana_rgc3;
+	u32		rss_num;
 	u64		caps;
 	u64		required_clks;
 	bool		required_pctl;
@@ -1270,7 +1330,8 @@ struct mtk_soc_data {
  *			dummy for NAPI to work
  * @netdev:		The netdev instances
  * @mac:		Each netdev is linked to a physical MAC
- * @irq:		The IRQ that we are using
+ * @irq_fe:		Array of IRQs of the frame engine
+ * @irq_pdma:		Array of IRQs of the PDMA used for RSS
  * @msg_enable:		Ethtool msg level
  * @ethsys:		The register map pointing at the range used to setup
  *			MII modes
@@ -1314,7 +1375,8 @@ struct mtk_eth {
 	struct net_device		*dummy_dev;
 	struct net_device		*netdev[MTK_MAX_DEVS];
 	struct mtk_mac			*mac[MTK_MAX_DEVS];
-	int				irq[MTK_FE_IRQ_NUM];
+	int				irq_fe[MTK_FE_IRQ_NUM];
+	int				irq_pdma[MTK_PDMA_IRQ_NUM];
 	u32				msg_enable;
 	unsigned long			sysclk;
 	struct regmap			*ethsys;
@@ -1327,7 +1389,8 @@ struct mtk_eth {
 	struct mtk_rx_ring		rx_ring[MTK_MAX_RX_RING_NUM];
 	struct mtk_rx_ring		rx_ring_qdma;
 	struct napi_struct		tx_napi;
-	struct napi_struct		rx_napi;
+	struct mtk_napi			rx_napi[MTK_RX_NAPI_NUM];
+	struct mtk_rss_params		rss_params;
 	void				*scratch_ring;
 	dma_addr_t			phy_scratch_ring;
 	void				*scratch_head[MTK_FQ_DMA_HEAD];
-- 
2.43.0



From maz at kernel.org  Wed Dec 17 02:33:00 2025
From: maz at kernel.org (Marc Zyngier)
Date: Wed, 17 Dec 2025 10:33:00 +0000
Subject: [PATCH 17/32] KVM: arm64: gic-v5: Implement PPI interrupt injection
In-Reply-To: <20251212152215.675767-18-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	<20251212152215.675767-18-sascha.bischoff@arm.com>
Message-ID: <864ippo0tf.wl-maz@kernel.org>

On Fri, 12 Dec 2025 15:22:41 +0000,
Sascha Bischoff <Sascha.Bischoff at arm.com> wrote:
> 
> This change introduces interrupt injection for PPIs for GICv5-based
> guests.
> 
> The lifecycle of PPIs is largely managed by the hardware for a GICv5
> system. The hypervisor injects pending state into the guest by using
> the ICH_PPI_PENDRx_EL2 registers. These are used by the hardware to
> pick a Highest Priority Pending Interrupt (HPPI) for the guest based
> on the enable state of each individual interrupt. The enable state and
> priority for each interrupt are provided by the guest itself (through
> writes to the PPI registers).
> 
> When Direct Virtual Interrupt (DVI) is set for a particular PPI, the
> hypervisor is even able to skip the injection of the pending state
> altogether - it all happens in hardware.
> 
> The result of the above is that no AP lists are required for GICv5,
> unlike for older GICs. Instead, for PPIs the ICH_PPI_* registers
> fulfil the same purpose for all 128 PPIs. Hence, as long as the
> ICH_PPI_* registers are populated prior to guest entry, and merged
> back into the KVM shadow state on exit, the PPI state is preserved,
> and interrupts can be injected.
> 
> When injecting the state of a PPI the state is merged into the KVM's
> shadow state using the set_pending_state irq_op. The directly sets the
> relevant bit in the shadow ICH_PPI_PENDRx_EL2, which is presented to
> the guest (and GICv5 hardware) on next guest entry. The
> queue_irq_unlock irq_op is required to kick the vCPU to ensure that it
> seems the new state. The result is that no AP lists are used for
> private interrupts on GICv5.
> 
> Prior to entering the guest, vgic_v5_flush_ppi_state is called from
> kvm_vgic_flush_hwstate. The effectively snapshots the shadow PPI
> pending state (twice - an entry and an exit copy) in order to track
> any changes. These changes can come from a guest consuming an
> interrupt or from a guest making an Edge-triggered interrupt pending.
> 
> When returning from running a guest, the guest's PPI state is merged
> back into KVM's shadow state in vgic_v5_merge_ppi_state from
> kvm_vgic_sync_hwstate. The Enable and Active state is synced back for
> all PPIs, and the pending state is synced back for Edge PPIs (Level is
> driven directly by the devices generating said levels). The incoming
> pending state from the guest is merged with KVM's shadow state to
> avoid losing any incoming interrupts.
> 
> Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
> ---
>  arch/arm64/kvm/vgic/vgic-v5.c | 157 ++++++++++++++++++++++++++++++++++
>  arch/arm64/kvm/vgic/vgic.c    |  35 ++++++--
>  arch/arm64/kvm/vgic/vgic.h    |  49 ++++++++---
>  include/kvm/arm_vgic.h        |   3 +
>  4 files changed, 226 insertions(+), 18 deletions(-)
> 
> diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
> index 22558080711eb..d54595fbf4586 100644
> --- a/arch/arm64/kvm/vgic/vgic-v5.c
> +++ b/arch/arm64/kvm/vgic/vgic-v5.c
> @@ -54,6 +54,163 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
>  	return 0;
>  }
>  
> +static bool vgic_v5_ppi_set_pending_state(struct kvm_vcpu *vcpu,
> +					  struct vgic_irq *irq)
> +{
> +	struct vgic_v5_cpu_if *cpu_if;
> +	const u32 id_bit = BIT_ULL(irq->intid % 64);

Try that with intid==32...

> +	const u32 reg = FIELD_GET(GICV5_HWIRQ_ID, irq->intid) / 64;
> +
> +	if (!vcpu || !irq)
> +		return false;
> +
> +	/* Skip injecting the state altogether */
> +	if (irq->directly_injected)
> +		return true;

It is unclear to me under which circumstances we could end-up here.
Wouldn't that be a bug?

> +
> +	cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> +
> +	if (irq_is_pending(irq))
> +		cpu_if->vgic_ppi_pendr[reg] |= id_bit;
> +	else
> +		cpu_if->vgic_ppi_pendr[reg] &= ~id_bit;
> +
> +	return true;
> +}
> +
> +/*
> + * For GICv5, the PPIs are mostly directly managed by the hardware. We
> + * (the hypervisor) handle the pending, active, enable state
> + * save/restore, but don't need the PPIs to be queued on a per-VCPU AP
> + * list. Therefore, sanity check the state, unlock, and return.
> + */
> +static bool vgic_v5_ppi_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq,
> +					 unsigned long flags)
> +	__releases(&irq->irq_lock)
> +{
> +	struct kvm_vcpu *vcpu;
> +
> +	lockdep_assert_held(&irq->irq_lock);
> +
> +	if (WARN_ON_ONCE(!irq_is_ppi_v5(irq->intid)))
> +		return false;
> +
> +	vcpu = irq->target_vcpu;
> +	if (WARN_ON_ONCE(!vcpu))
> +		return false;

Errr... You're returning with the lock held, making a bad bug even
worse!

> +
> +	raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
> +
> +	/* Directly kick the target VCPU to make sure it sees the IRQ */
> +	kvm_make_request(KVM_REQ_IRQ_PENDING, vcpu);
> +	kvm_vcpu_kick(vcpu);
> +
> +	return true;
> +}
> +
> +static struct irq_ops vgic_v5_ppi_irq_ops = {
> +	.set_pending_state = vgic_v5_ppi_set_pending_state,
> +	.queue_irq_unlock = vgic_v5_ppi_queue_irq_unlock,
> +};
> +
> +void vgic_v5_set_ppi_ops(struct vgic_irq *irq)
> +{
> +	if (WARN_ON(!irq) || WARN_ON(irq->ops))
> +		return;
> +
> +	irq->ops = &vgic_v5_ppi_irq_ops;

Is there any locking requirement here?

> +}
> +
> +/*
> + * Detect any PPIs state changes, and propagate the state with KVM's
> + * shadow structures.
> + */
> +static void vgic_v5_merge_ppi_state(struct kvm_vcpu *vcpu)

Since this is only called from vgic_v5_fold_irq_state(), do yourself a
favour and call it that.

> +{
> +	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> +	unsigned long flags;
> +	int i, reg;
> +
> +	for (reg = 0; reg < 2; reg++) {
> +		unsigned long changed_bits;
> +		const unsigned long enabler = cpu_if->vgic_ich_ppi_enabler_exit[reg];
> +		const unsigned long activer = cpu_if->vgic_ppi_activer_exit[reg];
> +		const unsigned long pendr = cpu_if->vgic_ppi_pendr_exit[reg];
> +
> +		/*
> +		 * Track what changed across enabler, activer, pendr, but mask
> +		 * with ~DVI.
> +		 */
> +		changed_bits = cpu_if->vgic_ich_ppi_enabler_entry[reg] ^ enabler;
> +		changed_bits |= cpu_if->vgic_ppi_activer_entry[reg] ^ activer;
> +		changed_bits |= cpu_if->vgic_ppi_pendr_entry[reg] ^ pendr;
> +		changed_bits &= ~cpu_if->vgic_ppi_dvir[reg];
> +
> +		for_each_set_bit(i, &changed_bits, 64) {
> +			struct vgic_irq *irq;
> +			u32 intid;
> +
> +			intid = FIELD_PREP(GICV5_HWIRQ_TYPE, GICV5_HWIRQ_TYPE_PPI);
> +			intid |= FIELD_PREP(GICV5_HWIRQ_ID, reg * 64 + i);
> +
> +			irq = vgic_get_vcpu_irq(vcpu, intid);
> +
> +			raw_spin_lock_irqsave(&irq->irq_lock, flags);

Consider using a scoped_guard() for this.

> +			irq->enabled = !!(enabler & BIT(i));
> +			irq->active = !!(activer & BIT(i));
> +			/* This is an OR to avoid losing incoming edges! */
> +			if (irq->config == VGIC_CONFIG_EDGE)
> +				irq->pending_latch |= !!(pendr & BIT(i));
> +			raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
> +
> +			vgic_put_irq(vcpu->kvm, irq);
> +		}
> +
> +		/* Re-inject the exit state as entry state next time! */
> +		cpu_if->vgic_ich_ppi_enabler_entry[reg] = enabler;
> +		cpu_if->vgic_ppi_activer_entry[reg] = activer;
> +
> +		/*
> +		 * Pending state is a bit different. We only propagate back
> +		 * pending state for Edge interrupts. Moreover, this is OR'd
> +		 * with the incoming state to make sure we don't lose incoming
> +		 * edges. Use the (inverse) HMR to mask off all Level bits, and
> +		 * OR.
> +		 */
> +		cpu_if->vgic_ppi_pendr[reg] |= pendr & ~cpu_if->vgic_ppi_hmr[reg];
> +	}
> +}
> +
> +void vgic_v5_flush_ppi_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> +
> +	/*
> +	 * We're about to enter the guest. Copy the shadow state to the pending
> +	 * reg that will be written to the ICH_PPI_PENDRx_EL2 regs. While the
> +	 * guest is running we track any incoming changes to the pending state in
> +	 * vgic_ppi_pendr. The incoming changes are merged with the outgoing
> +	 * changes on the return path.
> +	 */
> +	cpu_if->vgic_ppi_pendr_entry[0] = cpu_if->vgic_ppi_pendr[0];
> +	cpu_if->vgic_ppi_pendr_entry[1] = cpu_if->vgic_ppi_pendr[1];
> +
> +	/*
> +	 * Make sure that we can correctly detect "edges" in the PPI
> +	 * state. There's a path where we never actually enter the guest, and
> +	 * failure to do this risks losing pending state
> +	 */
> +	cpu_if->vgic_ppi_pendr_exit[0] = cpu_if->vgic_ppi_pendr[0];
> +	cpu_if->vgic_ppi_pendr_exit[1] = cpu_if->vgic_ppi_pendr[1];

I find it a bit objectionable that this entry/exit stuff is kept on a
per vcpu basis. Given that we cannot be preempted between flush and
fold, the intermediate bookkeeping should probably live in a per-CPU
structure.

> +
> +}
> +
> +void vgic_v5_fold_irq_state(struct kvm_vcpu *vcpu)
> +{
> +	/* Sync back the guest PPI state to the KVM shadow state */
> +	vgic_v5_merge_ppi_state(vcpu);
> +}
> +
>  /*
>   * Sets/clears the corresponding bit in the ICH_PPI_DVIR register.
>   */
> diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
> index fc01c6d07fe62..e534876656ca7 100644
> --- a/arch/arm64/kvm/vgic/vgic.c
> +++ b/arch/arm64/kvm/vgic/vgic.c
> @@ -105,6 +105,15 @@ struct vgic_irq *vgic_get_vcpu_irq(struct kvm_vcpu *vcpu, u32 intid)
>  	if (WARN_ON(!vcpu))
>  		return NULL;
>  
> +	if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5) {
> +		u32 int_num = FIELD_GET(GICV5_HWIRQ_ID, intid);
> +
> +		if (irq_is_ppi_v5(intid)) {
> +			int_num = array_index_nospec(int_num, VGIC_V5_NR_PRIVATE_IRQS);
> +			return &vcpu->arch.vgic_cpu.private_irqs[int_num];
> +		}
> +	}
> +
>  	/* SGIs and PPIs */
>  	if (intid < VGIC_NR_PRIVATE_IRQS) {
>  		intid = array_index_nospec(intid, VGIC_NR_PRIVATE_IRQS);
> @@ -258,10 +267,12 @@ struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
>  	 * If the distributor is disabled, pending interrupts shouldn't be
>  	 * forwarded.
>  	 */
> -	if (irq->enabled && irq_is_pending(irq)) {
> -		if (unlikely(irq->target_vcpu &&
> -			     !irq->target_vcpu->kvm->arch.vgic.enabled))
> -			return NULL;
> +	if (irq_is_enabled(irq) && irq_is_pending(irq)) {
> +		if (irq->target_vcpu) {
> +			if (!vgic_is_v5(irq->target_vcpu->kvm) &&
> +			    unlikely(!irq->target_vcpu->kvm->arch.vgic.enabled))
> +				return NULL;
> +		}
>  
>  		return irq->target_vcpu;
>  	}
> @@ -1044,7 +1055,11 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
>  	if (can_access_vgic_from_kernel())
>  		vgic_save_state(vcpu);
>  
> -	vgic_fold_lr_state(vcpu);
> +	if (!vgic_is_v5(vcpu->kvm))
> +		vgic_fold_lr_state(vcpu);
> +	else
> +		vgic_v5_fold_irq_state(vcpu);
> +

This is gross. We already have this:

static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
{
	if (kvm_vgic_global_state.type == VGIC_V2)
		vgic_v2_fold_lr_state(vcpu);
	else
		vgic_v3_fold_lr_state(vcpu);
}

Rename it to vgic_fold_state(), drop the inline, make it a switch(),
and hook the v5 stuff in it.

>  	vgic_prune_ap_list(vcpu);

Are you actually pruning the ap_list() on v5? What is there the first place?

>  }
>  
> @@ -1105,13 +1120,17 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
>  
>  	DEBUG_SPINLOCK_BUG_ON(!irqs_disabled());
>  
> -	scoped_guard(raw_spinlock, &vcpu->arch.vgic_cpu.ap_list_lock)
> -		vgic_flush_lr_state(vcpu);
> +	if (!vgic_is_v5(vcpu->kvm)) {
> +		scoped_guard(raw_spinlock, &vcpu->arch.vgic_cpu.ap_list_lock)
> +			vgic_flush_lr_state(vcpu);
> +	} else {
> +		vgic_v5_flush_ppi_state(vcpu);
> +	}

Same thing here. Move everything into the common helper, including the
lock management.

>  
>  	if (can_access_vgic_from_kernel())
>  		vgic_restore_state(vcpu);
>  
> -	if (vgic_supports_direct_irqs(vcpu->kvm))
> +	if (vgic_supports_direct_irqs(vcpu->kvm) && !vgic_is_v5(vcpu->kvm))
>  		vgic_v4_commit(vcpu);

nit: swap the two terms of the conjunction, making it more readable
(for me...). Or move the conditions into vgic_v4_commit().

>  }
>  
> diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
> index b6e3f5e3aba18..5a77318ddb87a 100644
> --- a/arch/arm64/kvm/vgic/vgic.h
> +++ b/arch/arm64/kvm/vgic/vgic.h
> @@ -132,6 +132,28 @@ static inline bool irq_is_pending(struct vgic_irq *irq)
>  		return irq->pending_latch || irq->line_level;
>  }
>  
> +/* Requires the irq_lock to be held by the caller. */
> +static inline bool irq_is_enabled(struct vgic_irq *irq)
> +{
> +	if (irq->enabled)
> +		return true;
> +
> +	/*
> +	 * We always consider GICv5 interrupts as enabled as we can
> +	 * always inject them. The state is handled by the hardware,
> +	 * and the hardware will only signal the interrupt to the
> +	 * guest once the guest enables it.
> +	 */
> +	if (irq->target_vcpu) {

Under which circumstances is target_vcpu NULL for PPIs?

> +		u32 vgic_model = irq->target_vcpu->kvm->arch.vgic.vgic_model;
> +
> +		if (vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5)
> +			return true;
> +	}
> +
> +	return false;
> +}
> +
>  static inline bool vgic_irq_is_mapped_level(struct vgic_irq *irq)
>  {
>  	return irq->config == VGIC_CONFIG_LEVEL && irq->hw;
> @@ -306,7 +328,7 @@ static inline bool vgic_try_get_irq_ref(struct vgic_irq *irq)
>  	if (!irq)
>  		return false;
>  
> -	if (irq->intid < VGIC_MIN_LPI)
> +	if (irq->target_vcpu && !irq_is_lpi(irq->target_vcpu->kvm, irq->intid))
>  		return true;

This change is rather obscure, and doesn't do what you think it does.

What has target_vcpu to do with anything? For example, a GICv3 SPI
that has its target_vcpu set to NULL (just point its IROUTER register
to a non-existent vcpu) would end-up using the refcount path,
something that isn't expected at all.

You should make clear what the refcounting rules are for GICv5, and
use that, instead of using odd side-effects.

>  
>  	return refcount_inc_not_zero(&irq->refcount);
> @@ -363,7 +385,10 @@ void vgic_debug_init(struct kvm *kvm);
>  void vgic_debug_destroy(struct kvm *kvm);
>  
>  int vgic_v5_probe(const struct gic_kvm_info *info);
> +void vgic_v5_set_ppi_ops(struct vgic_irq *irq);
>  int vgic_v5_set_ppi_dvi(struct kvm_vcpu *vcpu, u32 irq, bool dvi);
> +void vgic_v5_flush_ppi_state(struct kvm_vcpu *vcpu);
> +void vgic_v5_fold_irq_state(struct kvm_vcpu *vcpu);
>  void vgic_v5_load(struct kvm_vcpu *vcpu);
>  void vgic_v5_put(struct kvm_vcpu *vcpu);
>  void vgic_v5_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
> @@ -432,15 +457,6 @@ void vgic_its_invalidate_all_caches(struct kvm *kvm);
>  int vgic_its_inv_lpi(struct kvm *kvm, struct vgic_irq *irq);
>  int vgic_its_invall(struct kvm_vcpu *vcpu);
>  
> -bool system_supports_direct_sgis(void);
> -bool vgic_supports_direct_msis(struct kvm *kvm);
> -bool vgic_supports_direct_sgis(struct kvm *kvm);
> -
> -static inline bool vgic_supports_direct_irqs(struct kvm *kvm)
> -{
> -	return vgic_supports_direct_msis(kvm) || vgic_supports_direct_sgis(kvm);
> -}
> -
>  int vgic_v4_init(struct kvm *kvm);
>  void vgic_v4_teardown(struct kvm *kvm);
>  void vgic_v4_configure_vsgis(struct kvm *kvm);
> @@ -485,6 +501,19 @@ static inline bool vgic_is_v5(struct kvm *kvm)
>  	return kvm_vgic_global_state.type == VGIC_V5 && !vgic_is_v3_compat(kvm);
>  }
>  
> +bool system_supports_direct_sgis(void);
> +bool vgic_supports_direct_msis(struct kvm *kvm);
> +bool vgic_supports_direct_sgis(struct kvm *kvm);
> +
> +static inline bool vgic_supports_direct_irqs(struct kvm *kvm)
> +{
> +	/* GICv5 always supports direct IRQs */
> +	if (vgic_is_v5(kvm))
> +		return true;
> +
> +	return vgic_supports_direct_msis(kvm) || vgic_supports_direct_sgis(kvm);
> +}
> +
>  int vgic_its_debug_init(struct kvm_device *dev);
>  void vgic_its_debug_destroy(struct kvm_device *dev);
>  
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 20c908730fa00..5a46fe3c35b5c 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -32,6 +32,9 @@
>  #define VGIC_MIN_LPI		8192
>  #define KVM_IRQCHIP_NUM_PINS	(1020 - 32)
>  
> +/* GICv5 constants */
> +#define VGIC_V5_NR_PRIVATE_IRQS	128
> +
>  #define irq_is_ppi_legacy(irq) ((irq) >= VGIC_NR_SGIS && (irq) < VGIC_NR_PRIVATE_IRQS)
>  #define irq_is_spi_legacy(irq) ((irq) >= VGIC_NR_PRIVATE_IRQS && \
>  					(irq) <= VGIC_MAX_SPI)

Thanks,

	M.

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


From mripard at kernel.org  Wed Dec 17 02:41:03 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Wed, 17 Dec 2025 10:41:03 +0000
Subject: [PATCH v3 09/22] drm/bridge: simple-bridge: get/put the next
 bridge
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-9-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-9-b5165fab8058@bootlin.com>
Message-ID: <654c1bbfcade818bfea35b52bc5e80ae@kernel.org>

On Tue, 16 Dec 2025 18:58:42 +0100, Luca Ceresoli wrote:
> This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
> function and stores it until driver removal. of_drm_find_bridge() is
> deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
> refcounted and use bridge->next_bridge to put the reference on
> deallocation.
> 
> [ ... ]

Reviewed-by: Maxime Ripard <mripard at kernel.org>

Thanks!
Maxime


From yeoreum.yun at arm.com  Wed Dec 17 02:48:05 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Wed, 17 Dec 2025 10:48:05 +0000
Subject: [PATCH 0/2] introduce pagetable_alloc_nolock()
In-Reply-To: <100cc8da-b826-4fc2-a624-746bf6fb049d@arm.com>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com>
 <916c17ba-22b1-456e-a184-cb3f60249af7@arm.com>
 <aUGOPd7gNRf1xHEc@e129823.arm.com>
 <100cc8da-b826-4fc2-a624-746bf6fb049d@arm.com>
Message-ID: <aUKKZR0u22KOPfd7@e129823.arm.com>

Hi Ryan,

> On 16/12/2025 16:52, Yeoreum Yun wrote:
> > Hi Ryan,
> >
> >> On 12/12/2025 16:18, Yeoreum Yun wrote:
> >>> Some architectures invoke pagetable_alloc() or __get_free_pages()
> >>> with preemption disabled.
> >>> For example, in arm64, linear_map_split_to_ptes() calls pagetable_alloc()
> >>> while spliting block entry to ptes and __kpti_install_ng_mappings()
> >>> calls __get_free_pages() to create kpti pagetable.
> >>>
> >>> Under PREEMPT_RT, calling pagetable_alloc() with
> >>> preemption disabled is not allowed, because it may acquire
> >>> a spin lock that becomes sleepable on RT, potentially
> >>> causing a sleep during page allocation.
> >>>
> >>> Since above two functions is called as callback of stop_machine()
> >>> where its callback is called in preemption disabled,
> >>> They could make a potential problem. (sleeping in preemption disabled).
> >>>
> >>> To address this, introduce pagetable_alloc_nolock() API.
> >>
> >> I don't really understand what the problem is that you're trying to fix. As I
> >> see it, there are 2 call sites in arm64 arch code that are calling into the page
> >> allocator from stop_machine() - one via via pagetable_alloc() and another via
> >> __get_free_pages(). But both of those calls are passing in GFP_ATOMIC. It was my
> >> understanding that the page allocator would ensure it never sleeps when
> >> GFP_ATOMIC is passed in, (even for PREEMPT_RT)?
> >
> > Although GFP_ATOMIC is specify, it only affects of "water mark" of the
> > page with __GFP_HIGH. and to get a page, it must grab the lock --
> > zone->lock or pcp_lock in the rmqueue().
> >
> > This zone->lock and pcp_lock is spin_lock and it's a sleepable in
> > PREEMPT_RT that's why the memory allocation/free using general API
> > except nolock() version couldn't be called since
> > if "contention" happens they'll sleep while waiting to get the lock.
> >
> > The reason why "nolock()" can use, it always uses "trylock" with
> > ALLOC_TRYLOCK flags. otherwise GFP_ATOMIC also can be sleepable in
> > PREEMPT_RT.
> >
> >>
> >> What is the actual symptom you are seeing?
> >
> > Since the place where called while smp_cpus_done() and there seems no
> > contention, there seems no problem. However as I mention in another
> > thread
> > (https://lore.kernel.org/all/aT%2FdrjN1BkvyAGoi at e129823.arm.com/),
> > This gives a the false impression --
> > GFP_ATOMIC are ?safe to use in preemption disabled?
> > even though they are not in PREEMPT_RT case, I've changed it.
> >
> >>
> >> If the page allocator is somehow ignoring the GFP_ATOMIC request for PREEMPT_RT,
> >> then isn't that a bug in the page allocator? I'm not sure why you would change
> >> the callsites? Can't you just change the page allocator based on GFP_ATOMIC?
> >
> > It doesn't ignore the GFP_ATOMIC feature:
> >   - __GFP_HIGH: use water mark till min reserved
> >   - __GFP_KSWAPD_RECLAIM: wake up kswapd if reclaim required.
> >
> > But, it's a restriction -- "page allocation / free" API cannot be called
> > in preempt-disabled context at PREEMPT_RT.
> >
> > That's why I think it's wrong usage not a page allocator bug.
>
> I've taken a look at this and I agree with your analysis. Thanks for explaining.
>
> Looking at other stop_machine() callbacks, there are some that call printk() and
> I would assume that spinlocks could be taken there which may present the same
> kind of issue or PREEMPT_RT? (I'm guessing). I don't see any others that attempt
> to allocate memory though.

IIRC, there was a problem related for printk while try to grab
pl011_console related lock (spin_lock) while holding
console_lock(raw_spin_lock) in v6.10.0-rc7 at rpi5:

    [  230.381263] CPU: 2 PID: 5574 Comm: syz.4.1695 Not tainted 6.10.0-rc7-01903-g52828ea60dfd #3
    [  230.381479] Hardware name: linux,dummy-virt (DT)
    [  230.381565] Call trace:
    [  230.381607]  dump_backtrace+0x318/0x348
    [  230.381727]  show_stack+0x4c/0x80
    [  230.381875]  dump_stack_lvl+0x214/0x328
    [  230.382159]  dump_stack+0x3c/0x58
    [  230.382456]  __lock_acquire+0x4398/0x4720
    [  230.382683]  lock_acquire+0x648/0xb70
    [  230.382928]  _raw_spin_lock_irqsave+0x138/0x240
    [  230.383121]  pl011_console_write+0x240/0x8a0
    [  230.383356]  console_flush_all+0x708/0x1368
    [  230.383571]  console_unlock+0x180/0x440
    [  230.383742]  vprintk_emit+0x1f8/0x9d0
    [  230.383832]  vprintk_default+0x64/0x90
    [  230.383914]  vprintk+0x2d0/0x400
    [  230.383971]  _printk+0xdc/0x128
    [  230.384229]  hrtimer_interrupt+0x8f0/0x920
    [  230.384414]  arch_timer_handler_virt+0xc0/0x100
    [  230.384812]  handle_percpu_devid_irq+0x20c/0x4e0
    [  230.385053]  generic_handle_domain_irq+0xc0/0x120
    [  230.385367]  gic_handle_irq+0x88/0x360
    [  230.385559]  call_on_irq_stack+0x24/0x70
    [  230.385801]  do_interrupt_handler+0xf8/0x200
    [  230.386092]  el1_interrupt+0x68/0xc0
    [  230.386434]  el1h_64_irq_handler+0x18/0x28
    [  230.386716]  el1h_64_irq+0x64/0x68
    [  230.386853]  __sanitizer_cov_trace_const_cmp2+0x30/0x68
    [  230.387026]  alloc_pages_mpol_noprof+0x170/0x698
    [  230.387309]  vma_alloc_folio_noprof+0x128/0x2a8
    [  230.387610]  vma_alloc_zeroed_movable_folio+0xa0/0xe0
    [  230.387822]  folio_prealloc+0x5c/0x280
    [  230.388008]  do_wp_page+0xc30/0x3bc0
    [  230.388206]  __handle_mm_fault+0xdb8/0x2ba0
    [  230.388448]  handle_mm_fault+0x194/0x8a8
    [  230.388676]  do_page_fault+0x6bc/0x1030
    [  230.388924]  do_mem_abort+0x8c/0x240
    [  230.389056]  el0_da+0xf0/0x3f8
    [  230.389178]  el0t_64_sync_handler+0xb4/0x130
    [  230.389452]  el0t_64_sync+0x190/0x198

But this problem is gone when I try with some of patches in rt-tree
related for printk which are merged in current tree
(https://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git/log/?h=linux-6.10.y-rt-rebase).

So I think printk() wouldn't be a problem.

>
> Anyway, to fix the 2 arm64 callsites, I see 2 possible approaches:
>
> - Call the nolock variant (as you are doing). But that would just convert a
> deadlock to a panic; if the lock is held when stop_machine() runs, without your
> change, we now have a deadlock due to waiting on the lock inside stop_machine().
> With your change, we notice the lock is already taken and panic. I guess it is
> marginally better, but not by much. Certainly I would just _always_ call the
> nolock variant regardless of PREEMPT_RT if we take this route; For !PREEMPT_RT,
> the lock is guarranteed to be free so nolock will always succeed.
>
> - Preallocate the memory before entering stop_machine(). I think this would be
> much more robust. For kpti_install_ng_mappings() I think you could hoist the
> allocation/free out of stop_machine() and pass the pointer in pretty easily. For
> linear_map_split_to_ptes() its a bit more complex; Perhaps, we need to walk the
> pgtable to figure out how much to preallocate, allocate it, then set it up as a
> special allocator, wrapped by an allocation function and modify the callchain to
> take a callback function instead of gfp flags.
>
> What do you think?

Definitely, second suggestoin is much better.
My question is whether *memory contention* really happen in the point
both functions are called.

Above two functions are called as last step of "smp_init()" -- smp_cpus_done().
If we can be sure, I think we don't need to go to complex way and
I believe the reason why we couldn't find out this problem,
even using GFP_ATOMIC in PREEMPT_RT since there was *no contection*
in this time of both functions are called.

That's why I first try with the "simple way".

What do you think?

--
Sincerely,
Yeoreum Yun


From maz at kernel.org  Wed Dec 17 03:07:04 2025
From: maz at kernel.org (Marc Zyngier)
Date: Wed, 17 Dec 2025 11:07:04 +0000
Subject: [PATCH 13/32] KVM: arm64: gic-v5: Add vgic-v5 save/restore hyp interface
In-Reply-To: <20251212152215.675767-14-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	<20251212152215.675767-14-sascha.bischoff@arm.com>
Message-ID: <863459nz8n.wl-maz@kernel.org>

On Fri, 12 Dec 2025 15:22:39 +0000,
Sascha Bischoff <Sascha.Bischoff at arm.com> wrote:
> 
> Introduce hyp functions to save/restore the following GICv5 state:
> 
> * ICC_ICSR_EL1
> * ICH_APR_EL2
> * ICH_PPI_ACTIVERx_EL2
> * ICH_PPI_DVIRx_EL2
> * ICH_PPI_ENABLERx_EL2
> * ICH_PPI_PENDRRx_EL2
> * ICH_PPI_PRIORITYRx_EL2
> * ICH_VMCR_EL2
> 
> All of these are saved/restored to/from the KVM vgic_v5 CPUIF shadow
> state.
> 
> The ICSR must be save/restored as this register is shared between host
> and guest. Therefore, to avoid leaking host state to the guest, this
> must be saved and restored. Moreover, as this can by used by the host
> at any time, it must be save/restored eagerly. Note: the host state is
> not preserved as the host should only use this register when
> preemption is disabled.
> 
> As part of restoring the ICH_VMCR_EL2 and ICH_APR_EL2, GICv3-compat
> mode is also disabled by setting the ICH_VCTLR_EL2.V3 bit to 0. The
> correspoinding GICv3-compat mode enable is part of the VMCR & APR
> restore for a GICv3 guest as it only takes effect when actually
> running a guest.
> 
> Co-authored-by: Timothy Hayes <timothy.hayes at arm.com>
> Signed-off-by: Timothy Hayes <timothy.hayes at arm.com>
> Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
> ---
>  arch/arm64/include/asm/kvm_asm.h   |   4 +
>  arch/arm64/include/asm/kvm_hyp.h   |   8 ++
>  arch/arm64/kvm/hyp/nvhe/Makefile   |   2 +-
>  arch/arm64/kvm/hyp/nvhe/hyp-main.c |  32 ++++++
>  arch/arm64/kvm/hyp/vgic-v5.c       | 155 +++++++++++++++++++++++++++++
>  arch/arm64/kvm/hyp/vhe/Makefile    |   2 +-
>  include/kvm/arm_vgic.h             |  28 ++++++
>  7 files changed, 229 insertions(+), 2 deletions(-)
>  create mode 100644 arch/arm64/kvm/hyp/vgic-v5.c
> 
> diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
> index a1ad12c72ebf1..5f669299fb956 100644
> --- a/arch/arm64/include/asm/kvm_asm.h
> +++ b/arch/arm64/include/asm/kvm_asm.h
> @@ -89,6 +89,10 @@ enum __kvm_host_smccc_func {
>  	__KVM_HOST_SMCCC_FUNC___pkvm_vcpu_load,
>  	__KVM_HOST_SMCCC_FUNC___pkvm_vcpu_put,
>  	__KVM_HOST_SMCCC_FUNC___pkvm_tlb_flush_vmid,
> +	__KVM_HOST_SMCCC_FUNC___vgic_v5_save_vmcr_aprs,

As we recently found out with v2/v3, delaying saving VMCR (and
therefore lobbing it with the APRs) is a bad idea if you need to look
at it from inside the run loop.

In general, please align the behaviour with the existing
infrastructure as often as possible. We can always optimise things
later once GICv5 becomes relevant.

> +	__KVM_HOST_SMCCC_FUNC___vgic_v5_restore_vmcr_aprs,
> +	__KVM_HOST_SMCCC_FUNC___vgic_v5_save_ppi_state,
> +	__KVM_HOST_SMCCC_FUNC___vgic_v5_restore_ppi_state,
>  };
>  
>  #define DECLARE_KVM_VHE_SYM(sym)	extern char sym[]
> diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
> index 76ce2b94bd97e..f6cf59a719ac6 100644
> --- a/arch/arm64/include/asm/kvm_hyp.h
> +++ b/arch/arm64/include/asm/kvm_hyp.h
> @@ -87,6 +87,14 @@ void __vgic_v3_save_aprs(struct vgic_v3_cpu_if *cpu_if);
>  void __vgic_v3_restore_vmcr_aprs(struct vgic_v3_cpu_if *cpu_if);
>  int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);
>  
> +/* GICv5 */
> +void __vgic_v5_save_vmcr_aprs(struct vgic_v5_cpu_if *cpu_if);
> +void __vgic_v5_restore_vmcr_aprs(struct vgic_v5_cpu_if *cpu_if);
> +void __vgic_v5_save_ppi_state(struct vgic_v5_cpu_if *cpu_if);
> +void __vgic_v5_restore_ppi_state(struct vgic_v5_cpu_if *cpu_if);
> +void __vgic_v5_save_icsr(struct vgic_v5_cpu_if *cpu_if);
> +void __vgic_v5_restore_icsr(struct vgic_v5_cpu_if *cpu_if);
> +
>  #ifdef __KVM_NVHE_HYPERVISOR__
>  void __timer_enable_traps(struct kvm_vcpu *vcpu);
>  void __timer_disable_traps(struct kvm_vcpu *vcpu);
> diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile
> index a244ec25f8c5b..d860fbe9bc476 100644
> --- a/arch/arm64/kvm/hyp/nvhe/Makefile
> +++ b/arch/arm64/kvm/hyp/nvhe/Makefile
> @@ -26,7 +26,7 @@ hyp-obj-y := timer-sr.o sysreg-sr.o debug-sr.o switch.o tlb.o hyp-init.o host.o
>  	 hyp-main.o hyp-smp.o psci-relay.o early_alloc.o page_alloc.o \
>  	 cache.o setup.o mm.o mem_protect.o sys_regs.o pkvm.o stacktrace.o ffa.o
>  hyp-obj-y += ../vgic-v3-sr.o ../aarch32.o ../vgic-v2-cpuif-proxy.o ../entry.o \
> -	 ../fpsimd.o ../hyp-entry.o ../exception.o ../pgtable.o
> +	 ../fpsimd.o ../hyp-entry.o ../exception.o ../pgtable.o ../vgic-v5.o
>  hyp-obj-y += ../../../kernel/smccc-call.o
>  hyp-obj-$(CONFIG_LIST_HARDENED) += list_debug.o
>  hyp-obj-y += $(lib-objs)
> diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> index a7c689152f686..6bc5a4f75fd01 100644
> --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> @@ -586,6 +586,34 @@ static void handle___pkvm_teardown_vm(struct kvm_cpu_context *host_ctxt)
>  	cpu_reg(host_ctxt, 1) = __pkvm_teardown_vm(handle);
>  }
>  
> +static void handle___vgic_v5_save_vmcr_aprs(struct kvm_cpu_context *host_ctxt)
> +{
> +	DECLARE_REG(struct vgic_v5_cpu_if *, cpu_if, host_ctxt, 1);
> +
> +	__vgic_v5_save_vmcr_aprs(kern_hyp_va(cpu_if));
> +}
> +
> +static void handle___vgic_v5_restore_vmcr_aprs(struct kvm_cpu_context *host_ctxt)
> +{
> +	DECLARE_REG(struct vgic_v5_cpu_if *, cpu_if, host_ctxt, 1);
> +
> +	__vgic_v5_restore_vmcr_aprs(kern_hyp_va(cpu_if));
> +}
> +
> +static void handle___vgic_v5_save_ppi_state(struct kvm_cpu_context *host_ctxt)
> +{
> +	DECLARE_REG(struct vgic_v5_cpu_if *, cpu_if, host_ctxt, 1);
> +
> +	__vgic_v5_save_ppi_state(kern_hyp_va(cpu_if));
> +}
> +
> +static void handle___vgic_v5_restore_ppi_state(struct kvm_cpu_context *host_ctxt)
> +{
> +	DECLARE_REG(struct vgic_v5_cpu_if *, cpu_if, host_ctxt, 1);
> +
> +	__vgic_v5_restore_ppi_state(kern_hyp_va(cpu_if));
> +}
> +
>  typedef void (*hcall_t)(struct kvm_cpu_context *);
>  
>  #define HANDLE_FUNC(x)	[__KVM_HOST_SMCCC_FUNC_##x] = (hcall_t)handle_##x
> @@ -627,6 +655,10 @@ static const hcall_t host_hcall[] = {
>  	HANDLE_FUNC(__pkvm_vcpu_load),
>  	HANDLE_FUNC(__pkvm_vcpu_put),
>  	HANDLE_FUNC(__pkvm_tlb_flush_vmid),
> +	HANDLE_FUNC(__vgic_v5_save_vmcr_aprs),
> +	HANDLE_FUNC(__vgic_v5_restore_vmcr_aprs),
> +	HANDLE_FUNC(__vgic_v5_save_ppi_state),
> +	HANDLE_FUNC(__vgic_v5_restore_ppi_state),
>  };
>  
>  static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
> diff --git a/arch/arm64/kvm/hyp/vgic-v5.c b/arch/arm64/kvm/hyp/vgic-v5.c
> new file mode 100644
> index 0000000000000..11b67ae09e326
> --- /dev/null
> +++ b/arch/arm64/kvm/hyp/vgic-v5.c

maz at valley-girl:~/hot-poop/arm-platforms$ find . -name vgic-v5.c
./arch/arm64/kvm/vgic/vgic-v5.c
./arch/arm64/kvm/hyp/vgic-v5.c

It doesn't look like much, but that's *very* annoying. Which is why we
have vgic-v3.c on one side, and vgic-v3-sr.c on the other. Consider
doing the same thing here.

> @@ -0,0 +1,155 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2025 - ARM Ltd
> + */
> +
> +#include <hyp/adjust_pc.h>
> +
> +#include <linux/compiler.h>
> +#include <linux/irqchip/arm-gic-v5.h>
> +#include <linux/kvm_host.h>
> +
> +#include <asm/kvm_emulate.h>
> +#include <asm/kvm_hyp.h>
> +#include <asm/kvm_mmu.h>
> +
> +void __vgic_v5_save_vmcr_aprs(struct vgic_v5_cpu_if *cpu_if)
> +{
> +	cpu_if->vgic_vmcr = read_sysreg_s(SYS_ICH_VMCR_EL2);
> +	cpu_if->vgic_apr = read_sysreg_s(SYS_ICH_APR_EL2);
> +}
> +
> +static void  __vgic_v5_compat_mode_disable(void)
> +{
> +	sysreg_clear_set_s(SYS_ICH_VCTLR_EL2, ICH_VCTLR_EL2_V3, 0);
> +	isb();
> +}
> +
> +void __vgic_v5_restore_vmcr_aprs(struct vgic_v5_cpu_if *cpu_if)
> +{
> +	__vgic_v5_compat_mode_disable();
> +
> +	write_sysreg_s(cpu_if->vgic_vmcr, SYS_ICH_VMCR_EL2);
> +	write_sysreg_s(cpu_if->vgic_apr, SYS_ICH_APR_EL2);
> +}
> +
> +void __vgic_v5_save_ppi_state(struct vgic_v5_cpu_if *cpu_if)
> +{
> +	cpu_if->vgic_ppi_activer_exit[0] =
> +		read_sysreg_s(SYS_ICH_PPI_ACTIVER0_EL2);
> +	cpu_if->vgic_ppi_activer_exit[1] =
> +		read_sysreg_s(SYS_ICH_PPI_ACTIVER1_EL2);

Please don't break assignments. Long lines are fine.

> +
> +	cpu_if->vgic_ich_ppi_enabler_exit[0] =
> +		read_sysreg_s(SYS_ICH_PPI_ENABLER0_EL2);
> +	cpu_if->vgic_ich_ppi_enabler_exit[1] =
> +		read_sysreg_s(SYS_ICH_PPI_ENABLER1_EL2);
> +
> +	cpu_if->vgic_ppi_pendr_exit[0] = read_sysreg_s(SYS_ICH_PPI_PENDR0_EL2);
> +	cpu_if->vgic_ppi_pendr_exit[1] = read_sysreg_s(SYS_ICH_PPI_PENDR1_EL2);
> +
> +	cpu_if->vgic_ppi_priorityr[0] =
> +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR0_EL2);
> +	cpu_if->vgic_ppi_priorityr[1] =
> +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR1_EL2);
> +	cpu_if->vgic_ppi_priorityr[2] =
> +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR2_EL2);
> +	cpu_if->vgic_ppi_priorityr[3] =
> +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR3_EL2);
> +	cpu_if->vgic_ppi_priorityr[4] =
> +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR4_EL2);
> +	cpu_if->vgic_ppi_priorityr[5] =
> +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR5_EL2);
> +	cpu_if->vgic_ppi_priorityr[6] =
> +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR6_EL2);
> +	cpu_if->vgic_ppi_priorityr[7] =
> +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR7_EL2);
> +	cpu_if->vgic_ppi_priorityr[8] =
> +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR8_EL2);
> +	cpu_if->vgic_ppi_priorityr[9] =
> +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR9_EL2);
> +	cpu_if->vgic_ppi_priorityr[10] =
> +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR10_EL2);
> +	cpu_if->vgic_ppi_priorityr[11] =
> +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR11_EL2);
> +	cpu_if->vgic_ppi_priorityr[12] =
> +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR12_EL2);
> +	cpu_if->vgic_ppi_priorityr[13] =
> +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR13_EL2);
> +	cpu_if->vgic_ppi_priorityr[14] =
> +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR14_EL2);
> +	cpu_if->vgic_ppi_priorityr[15] =
> +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR15_EL2);

There is clearly scope for optimisation here. The most likely case is
that we will only care about a handful of PPIs, all grouped in the
first 4 registers. That's a good reason to track the PPIs that the
guest can see.

> +
> +	/* Now that we are done, disable DVI */
> +	write_sysreg_s(0, SYS_ICH_PPI_DVIR0_EL2);
> +	write_sysreg_s(0, SYS_ICH_PPI_DVIR1_EL2);
> +}
> +
> +void __vgic_v5_restore_ppi_state(struct vgic_v5_cpu_if *cpu_if)
> +{
> +	 /* Now enable DVI so that the guest's interrupt config takes over */
> +	 write_sysreg_s(cpu_if->vgic_ppi_dvir[0], SYS_ICH_PPI_DVIR0_EL2);
> +	 write_sysreg_s(cpu_if->vgic_ppi_dvir[1], SYS_ICH_PPI_DVIR1_EL2);
> +
> +	 write_sysreg_s(cpu_if->vgic_ppi_activer_entry[0],
> +			SYS_ICH_PPI_ACTIVER0_EL2);
> +	 write_sysreg_s(cpu_if->vgic_ppi_activer_entry[1],
> +			SYS_ICH_PPI_ACTIVER1_EL2);
> +
> +	 write_sysreg_s(cpu_if->vgic_ich_ppi_enabler_entry[0],
> +			SYS_ICH_PPI_ENABLER0_EL2);
> +	 write_sysreg_s(cpu_if->vgic_ich_ppi_enabler_entry[1],
> +			SYS_ICH_PPI_ENABLER1_EL2);
> +
> +	 /* Update the pending state of the NON-DVI'd PPIs, only */
> +	 write_sysreg_s(cpu_if->vgic_ppi_pendr_entry[0] &
> +				~cpu_if->vgic_ppi_dvir[0],

Again, don't insert line breaks in logical operations.

> +			SYS_ICH_PPI_PENDR0_EL2);
> +	 write_sysreg_s(cpu_if->vgic_ppi_pendr_entry[1] &
> +				~cpu_if->vgic_ppi_dvir[1],
> +			SYS_ICH_PPI_PENDR1_EL2);
> +
> +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[0],
> +			SYS_ICH_PPI_PRIORITYR0_EL2);
> +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[1],
> +			SYS_ICH_PPI_PRIORITYR1_EL2);
> +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[2],
> +			SYS_ICH_PPI_PRIORITYR2_EL2);
> +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[3],
> +			SYS_ICH_PPI_PRIORITYR3_EL2);
> +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[4],
> +			SYS_ICH_PPI_PRIORITYR4_EL2);
> +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[5],
> +			SYS_ICH_PPI_PRIORITYR5_EL2);
> +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[6],
> +			SYS_ICH_PPI_PRIORITYR6_EL2);
> +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[7],
> +			SYS_ICH_PPI_PRIORITYR7_EL2);
> +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[8],
> +			SYS_ICH_PPI_PRIORITYR8_EL2);
> +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[9],
> +			SYS_ICH_PPI_PRIORITYR9_EL2);
> +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[10],
> +			SYS_ICH_PPI_PRIORITYR10_EL2);
> +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[11],
> +			SYS_ICH_PPI_PRIORITYR11_EL2);
> +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[12],
> +			SYS_ICH_PPI_PRIORITYR12_EL2);
> +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[13],
> +			SYS_ICH_PPI_PRIORITYR13_EL2);
> +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[14],
> +			SYS_ICH_PPI_PRIORITYR14_EL2);
> +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[15],
> +			SYS_ICH_PPI_PRIORITYR15_EL2);
> +}
> +
> +void __vgic_v5_save_icsr(struct vgic_v5_cpu_if *cpu_if)
> +{
> +	cpu_if->vgic_icsr = read_sysreg_s(SYS_ICC_ICSR_EL1);
> +}
> +
> +void __vgic_v5_restore_icsr(struct vgic_v5_cpu_if *cpu_if)
> +{
> +	write_sysreg_s(cpu_if->vgic_icsr, SYS_ICC_ICSR_EL1);
> +}
> diff --git a/arch/arm64/kvm/hyp/vhe/Makefile b/arch/arm64/kvm/hyp/vhe/Makefile
> index afc4aed9231ac..fcf5e68ab591c 100644
> --- a/arch/arm64/kvm/hyp/vhe/Makefile
> +++ b/arch/arm64/kvm/hyp/vhe/Makefile
> @@ -10,4 +10,4 @@ CFLAGS_switch.o += -Wno-override-init
>  
>  obj-y := timer-sr.o sysreg-sr.o debug-sr.o switch.o tlb.o
>  obj-y += ../vgic-v3-sr.o ../aarch32.o ../vgic-v2-cpuif-proxy.o ../entry.o \
> -	 ../fpsimd.o ../hyp-entry.o ../exception.o
> +	 ../fpsimd.o ../hyp-entry.o ../exception.o ../vgic-v5.o
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index fbbaef4ad2114..525c8b83e83c9 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -359,7 +359,35 @@ struct vgic_v3_cpu_if {
>  };
>  
>  struct vgic_v5_cpu_if {
> +	u64	vgic_apr;
> +	u64	vgic_vmcr;
> +
> +	/* PPI register state */
>  	u64	vgic_ppi_hmr[2];
> +	u64	vgic_ppi_dvir[2];
> +	u64	vgic_ppi_priorityr[16];
> +
> +	/* The pending state of the guest. This is merged with the exit state */
> +	u64	vgic_ppi_pendr[2];
> +
> +	/* The state flushed to the regs when entering the guest */
> +	u64	vgic_ppi_activer_entry[2];
> +	u64	vgic_ich_ppi_enabler_entry[2];
> +	u64	vgic_ppi_pendr_entry[2];
> +
> +	/* The saved state of the regs when leaving the guest */
> +	u64	vgic_ppi_activer_exit[2];
> +	u64	vgic_ich_ppi_enabler_exit[2];
> +	u64	vgic_ppi_pendr_exit[2];

See my comment on patch 17, requesting to make these entry/exit states
per CPU, and not per vcpu.

> +
> +	/*
> +	 * The ICSR is re-used across host and guest, and hence it needs to be
> +	 * saved/restored. Only one copy is required as the host should block
> +	 * preemption between executing GIC CDRCFG and acccessing the
> +	 * ICC_ICSR_EL1. A guest, of course, can never guarantee this, and hence
> +	 * it is the hyp's responsibility to keep the state constistent.
> +	 */
> +	u64	vgic_icsr;
>  };
>  
>  struct vgic_cpu {

Thanks,

	M.

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


From hkelam at marvell.com  Wed Dec 17 03:08:13 2025
From: hkelam at marvell.com (Hariprasad Kelam)
Date: Wed, 17 Dec 2025 16:38:13 +0530
Subject: [PATCH net] net: stmmac: fix the crash issue for zero copy
 XDP_TX action
In-Reply-To: <20251204071332.1907111-1-wei.fang@nxp.com>
References: <20251204071332.1907111-1-wei.fang@nxp.com>
Message-ID: <aUKPHdtAPDnMqB7X@test-OptiPlex-Tower-Plus-7010>

On 2025-12-04 at 12:43:32, Wei Fang (wei.fang at nxp.com) wrote:
> There is a crash issue when running zero copy XDP_TX action, the crash
> log is shown below.
> 
> [  216.122464] Unable to handle kernel paging request at virtual address fffeffff80000000
> [  216.187524] Internal error: Oops: 0000000096000144 [#1]  SMP
> [  216.301694] Call trace:
> [  216.304130]  dcache_clean_poc+0x20/0x38 (P)
> [  216.308308]  __dma_sync_single_for_device+0x1bc/0x1e0
> [  216.313351]  stmmac_xdp_xmit_xdpf+0x354/0x400
> [  216.317701]  __stmmac_xdp_run_prog+0x164/0x368
> [  216.322139]  stmmac_napi_poll_rxtx+0xba8/0xf00
> [  216.326576]  __napi_poll+0x40/0x218
> [  216.408054] Kernel panic - not syncing: Oops: Fatal exception in interrupt
> 
> For XDP_TX action, the xdp_buff is converted to xdp_frame by
> xdp_convert_buff_to_frame(). The memory type of the resulting xdp_frame
> depends on the memory type of the xdp_buff. For page pool based xdp_buff
> it produces xdp_frame with memory type MEM_TYPE_PAGE_POOL. For zero copy
> XSK pool based xdp_buff it produces xdp_frame with memory type
> MEM_TYPE_PAGE_ORDER0. However, stmmac_xdp_xmit_back() does not check the
> memory type and always uses the page pool type, this leads to invalid
> mappings and causes the crash. Therefore, check the xdp_buff memory type
> in stmmac_xdp_xmit_back() to fix this issue.
> 
> Fixes: bba2556efad6 ("net: stmmac: Enable RX via AF_XDP zero-copy")
> Signed-off-by: Wei Fang <wei.fang at nxp.com>
> ---
>  .../net/ethernet/stmicro/stmmac/stmmac_main.c   | 17 +++++++++++++++--
>  1 file changed, 15 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index 7b90ecd3a55e..a6664f300e4a 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -88,6 +88,7 @@ MODULE_PARM_DESC(phyaddr, "Physical device address");
>  #define STMMAC_XDP_CONSUMED	BIT(0)
>  #define STMMAC_XDP_TX		BIT(1)
>  #define STMMAC_XDP_REDIRECT	BIT(2)
> +#define STMMAC_XSK_CONSUMED	BIT(3)
>  
>  static int flow_ctrl = 0xdead;
>  module_param(flow_ctrl, int, 0644);
> @@ -4988,6 +4989,7 @@ static int stmmac_xdp_get_tx_queue(struct stmmac_priv *priv,
>  static int stmmac_xdp_xmit_back(struct stmmac_priv *priv,
>  				struct xdp_buff *xdp)
>  {
> +	bool zc = !!(xdp->rxq->mem.type == MEM_TYPE_XSK_BUFF_POOL);
>  	struct xdp_frame *xdpf = xdp_convert_buff_to_frame(xdp);
>  	int cpu = smp_processor_id();
>  	struct netdev_queue *nq;
> @@ -5004,9 +5006,18 @@ static int stmmac_xdp_xmit_back(struct stmmac_priv *priv,
>  	/* Avoids TX time-out as we are sharing with slow path */
>  	txq_trans_cond_update(nq);
>  
> -	res = stmmac_xdp_xmit_xdpf(priv, queue, xdpf, false);
> -	if (res == STMMAC_XDP_TX)
> +	/* For zero copy XDP_TX action, dma_map is true */
> +	res = stmmac_xdp_xmit_xdpf(priv, queue, xdpf, zc);
	Seems stmmac_xdp_xmit_xdpf is using dma_map_single if we pass zc is true.
        Ideally in case of zc, driver can use page_pool_get_dma_addr, may be you
        need pass zc param as false. Please check

Thanks,
Hariprasad k
	


From konrad.dybcio at oss.qualcomm.com  Wed Dec 17 03:12:58 2025
From: konrad.dybcio at oss.qualcomm.com (Konrad Dybcio)
Date: Wed, 17 Dec 2025 12:12:58 +0100
Subject: [PATCH v7 3/5] arm64: dts: qcom: monaco: Add camera MCLK pinctrl
In-Reply-To: <20251216062223.2474216-4-quic_nihalkum@quicinc.com>
References: <20251216062223.2474216-1-quic_nihalkum@quicinc.com>
 <20251216062223.2474216-4-quic_nihalkum@quicinc.com>
Message-ID: <417d7e80-e098-4993-85ae-59ebfe50934e@oss.qualcomm.com>

On 12/16/25 7:22 AM, Nihal Kumar Gupta wrote:
> Define pinctrl definitions to enable camera master clocks on Monaco.
> 
> Signed-off-by: Nihal Kumar Gupta <quic_nihalkum at quicinc.com>
> Signed-off-by: Vikram Sharma <quic_vikramsa at quicinc.com>
> ---

Reviewed-by: Konrad Dybcio <konrad.dybcio at oss.qualcomm.com>

Konrad


From konrad.dybcio at oss.qualcomm.com  Wed Dec 17 03:14:15 2025
From: konrad.dybcio at oss.qualcomm.com (Konrad Dybcio)
Date: Wed, 17 Dec 2025 12:14:15 +0100
Subject: [PATCH v7 4/5] arm64: dts: qcom: monaco-evk: Add camera AVDD
 regulators
In-Reply-To: <20251216062223.2474216-5-quic_nihalkum@quicinc.com>
References: <20251216062223.2474216-1-quic_nihalkum@quicinc.com>
 <20251216062223.2474216-5-quic_nihalkum@quicinc.com>
Message-ID: <19bf8b37-4b40-4825-a8be-a94139389c69@oss.qualcomm.com>

On 12/16/25 7:22 AM, Nihal Kumar Gupta wrote:
> Define three fixed regulators for camera AVDD rails, each gpio-controlled
> with corresponding pinctrl definitions.
> 
> Signed-off-by: Nihal Kumar Gupta <quic_nihalkum at quicinc.com>
> Signed-off-by: Vikram Sharma <quic_vikramsa at quicinc.com>
> ---

[...]

>  &tlmm {
> +	cam0_avdd_2v8_en_default: cam0-avdd-2v8-en-state {
> +		pins = "gpio73";
> +		function = "gpio";
> +		drive-strength = <2>;
> +		bias-disable;
> +	};

All other entries in this scope are sorted wrt the pin index..
Please take care of that and add my

Reviewed-by: Konrad Dybcio <konrad.dybcio at oss.qualcomm.com>

Konrad

> +
> +	cam1_avdd_2v8_en_default: cam1-avdd-2v8-en-state {
> +		pins = "gpio74";
> +		function = "gpio";
> +		drive-strength = <2>;
> +		bias-disable;
> +	};
> +
> +	cam2_avdd_2v8_en_default: cam2-avdd-2v8-en-state {
> +		pins = "gpio75";
> +		function = "gpio";
> +		drive-strength = <2>;
> +		bias-disable;
> +	};
> +
>  	ethernet0_default: ethernet0-default-state {
>  		ethernet0_mdc: ethernet0-mdc-pins {
>  			pins = "gpio5";


From u.kleine-koenig at baylibre.com  Wed Dec 17 03:20:33 2025
From: u.kleine-koenig at baylibre.com (=?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?=)
Date: Wed, 17 Dec 2025 12:20:33 +0100
Subject: [PATCH] Bluetooth: btmtksdio: Use pm_ptr instead of #ifdef CONFIG_PM
Message-ID: <20251217112033.3309281-3-u.kleine-koenig@baylibre.com>

This increases build coverage and allows to drop an #ifdef.

Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig at baylibre.com>
---
Hello,

I found the patch opportunity while looking in this driver for a different
reason.

Best regards
Uwe

 drivers/bluetooth/btmtksdio.c | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c
index fba3ab6d30a5..e986e5af51ae 100644
--- a/drivers/bluetooth/btmtksdio.c
+++ b/drivers/bluetooth/btmtksdio.c
@@ -1472,7 +1472,6 @@ static void btmtksdio_remove(struct sdio_func *func)
 	hci_free_dev(hdev);
 }
 
-#ifdef CONFIG_PM
 static int btmtksdio_runtime_suspend(struct device *dev)
 {
 	struct sdio_func *func = dev_to_sdio_func(dev);
@@ -1542,18 +1541,13 @@ static const struct dev_pm_ops btmtksdio_pm_ops = {
 	RUNTIME_PM_OPS(btmtksdio_runtime_suspend, btmtksdio_runtime_resume, NULL)
 };
 
-#define BTMTKSDIO_PM_OPS (&btmtksdio_pm_ops)
-#else	/* CONFIG_PM */
-#define BTMTKSDIO_PM_OPS NULL
-#endif	/* CONFIG_PM */
-
 static struct sdio_driver btmtksdio_driver = {
 	.name		= "btmtksdio",
 	.probe		= btmtksdio_probe,
 	.remove		= btmtksdio_remove,
 	.id_table	= btmtksdio_table,
 	.drv = {
-		.pm = BTMTKSDIO_PM_OPS,
+		.pm = pm_ptr(&btmtksdio_pm_ops),
 	}
 };
 

base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
-- 
2.47.3



From kory.maincent at bootlin.com  Wed Dec 17 03:20:54 2025
From: kory.maincent at bootlin.com (Kory Maincent)
Date: Wed, 17 Dec 2025 12:20:54 +0100
Subject: [PATCH v2 01/20] dt-bindings: display: tilcdc: Convert to DT
 schema
In-Reply-To: <20251216-capable-eccentric-nightingale-b09037@quoll>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
	<20251211-feature_tilcdc-v2-1-f48bac3cd33e@bootlin.com>
	<20251216-capable-eccentric-nightingale-b09037@quoll>
Message-ID: <20251217122054.4682c6dd@kmaincent-XPS-13-7390>

On Tue, 16 Dec 2025 07:01:49 +0100
Krzysztof Kozlowski <krzk at kernel.org> wrote:

> On Thu, Dec 11, 2025 at 05:38:45PM +0100, Kory Maincent (TI.com) wrote:
> > diff --git a/Documentation/devicetree/bindings/display/tilcdc/tilcdc.yaml
> > b/Documentation/devicetree/bindings/display/tilcdc/tilcdc.yaml new file
> > mode 100644 index 0000000000000..34ac1fd04d5c6
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/display/tilcdc/tilcdc.yaml  
> 
> Filename based on compatible, so for example ti,am33xx-tilcdc.yaml or
> worse case ti,tilcdc.yaml (see writing bindings and writing schema docs)

Oh indeed forgot that rule. Sorry.
 
> > @@ -0,0 +1,96 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/display/tilcdc/tilcdc.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: TI LCD Controller, found on AM335x, DA850, AM18x and OMAP-L138
> > +
> > +maintainers:
> > +  - Kory Maincent <kory.maincent at bootlin.com>
> > +
> > +properties:
> > +  compatible:
> > +    enum:
> > +      - ti,am33xx-tilcdc
> > +      - ti,da850-tilcdc
> > +
> > +  reg:
> > +    maxItems: 1
> > +
> > +  interrupts:
> > +    maxItems: 1
> > +
> > +  port:
> > +    $ref: /schemas/graph.yaml#/properties/port
> > +
> > +  ti,hwmods:
> > +    $ref: /schemas/types.yaml#/definitions/string
> > +    description:
> > +      Name of the hwmod associated to the LCDC
> > +
> > +  max-bandwidth:  
> 
> constraints? Is '1' valid? Is INT_MAX valid as well?

These maximums values are kind of software only check. See:
https://elixir.bootlin.com/linux/v6.18.1/source/drivers/gpu/drm/tilcdc/tilcdc_crtc.c#L846
but there are no mainline devicetree using it. We have to keep them because
they were present in the text binding.

I think we can still add a maximum constraint matching the tilcdc maximum
resolution value.

...

> Drop unused label. Generic node name, e.g. "display-controller" or
> "lcd-controller".

Ok, thank you for the review!

Regards,
-- 
K?ry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com


From ahmed.tiba at arm.com  Wed Dec 17 03:28:33 2025
From: ahmed.tiba at arm.com (Ahmed Tiba)
Date: Wed, 17 Dec 2025 11:28:33 +0000
Subject: [PATCH 00/12] ras: share firmware-first estatus handling
Message-ID: <20251217112845.1814119-1-ahmed.tiba@arm.com>

Platforms that rely on firmware-first RAS today only get the full Linux
handling pipeline when the records arrive through ACPI/APEI GHES. This
series lifts the generic parts of GHES into a reusable estatus core, wires
GHES up to that core, and adds a DeviceTree-facing provider so non-ACPI
systems can route CPER records through the same logic. The final patches
document the binding and the admin-guide flow.

The end result is a single estatus implementation that covers vendor record
notifier support, memory error queueing, IRQ/NMI handling and the CXL/PCIe.
GHES and DT users now simply provide transport-specific ops.

This is based on v6.19-rc1

Ahmed Tiba (12):
  ras: add estatus core interfaces
  ras: add estatus core implementation
  ras: add estatus vendor handling and processing
  ras: add estatus queuing and IRQ/NMI handling
  ras: flesh out estatus processing core
  efi/cper: adopt estatus iteration helpers
  ghes: prepare estatus hooks for shared handling
  ghes: add estatus provider ops
  ghes: route error handling through shared estatus core
  dt-bindings: ras: document estatus provider
  ras: add DeviceTree estatus provider driver
  doc: ras: describe firmware-first estatus flow

 Documentation/admin-guide/RAS/main.rst        |   24 +
 .../devicetree/bindings/ras/arm,ras-ffh.yaml  |   95 ++
 MAINTAINERS                                   |    8 +
 arch/arm64/include/asm/fixmap.h               |    5 +
 drivers/acpi/apei/Kconfig                     |    1 +
 drivers/acpi/apei/ghes.c                      | 1292 +++--------------
 drivers/firmware/efi/Kconfig                  |   11 +
 drivers/firmware/efi/Makefile                 |    1 +
 drivers/firmware/efi/cper.c                   |   29 +-
 drivers/firmware/efi/estatus.c                | 1056 ++++++++++++++
 drivers/ras/Kconfig                           |   14 +
 drivers/ras/Makefile                          |    1 +
 drivers/ras/estatus-dt.c                      |  318 ++++
 include/acpi/ghes.h                           |   58 +-
 include/linux/estatus.h                       |  267 ++++
 15 files changed, 2001 insertions(+), 1179 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/ras/arm,ras-ffh.yaml
 create mode 100644 drivers/firmware/efi/estatus.c
 create mode 100644 drivers/ras/estatus-dt.c
 create mode 100644 include/linux/estatus.h

-- 
2.43.0



From ahmed.tiba at arm.com  Wed Dec 17 03:28:34 2025
From: ahmed.tiba at arm.com (Ahmed Tiba)
Date: Wed, 17 Dec 2025 11:28:34 +0000
Subject: [PATCH 01/12] ras: add estatus core interfaces
In-Reply-To: <20251217112845.1814119-1-ahmed.tiba@arm.com>
References: <20251217112845.1814119-1-ahmed.tiba@arm.com>
Message-ID: <20251217112845.1814119-2-ahmed.tiba@arm.com>

Introduce CONFIG_RAS_ESTATUS_CORE and the public header that exposes
the generic error-status abstractions. Nothing uses the option yet, but
the definitions are shared by both GHES and the forthcoming DeviceTree
provider, so land them ahead of the core implementation.

Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>
---
 MAINTAINERS                  |   5 +
 drivers/firmware/efi/Kconfig |  11 ++
 include/linux/estatus.h      | 267 +++++++++++++++++++++++++++++++++++
 3 files changed, 283 insertions(+)
 create mode 100644 include/linux/estatus.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 5b11839cba9d..501b6d300aa5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -21757,6 +21757,11 @@ M:	Alexandre Bounine <alex.bou9 at gmail.com>
 S:	Maintained
 F:	drivers/rapidio/
 
+RAS ERROR STATUS
+M:	Ahmed Tiba <ahmed.tiba at arm.com>
+S:	Maintained
+F:	include/linux/estatus.h
+
 RAS INFRASTRUCTURE
 M:	Tony Luck <tony.luck at intel.com>
 M:	Borislav Petkov <bp at alien8.de>
diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
index 29e0729299f5..d348ceb81cfb 100644
--- a/drivers/firmware/efi/Kconfig
+++ b/drivers/firmware/efi/Kconfig
@@ -329,6 +329,17 @@ config UEFI_CPER_X86
 	depends on UEFI_CPER && X86
 	default y
 
+config RAS_ESTATUS_CORE
+	bool "Firmware-first estatus processing core"
+	depends on UEFI_CPER
+	select GENERIC_ALLOCATOR
+	help
+	  Provide the shared Common Platform Error Record (CPER) handling core
+	  that firmware-first error sources reuse to read, cache, log, and
+	  dispatch Generic Hardware Error Status Blocks. This gets selected
+	  automatically by providers such as ACPI APEI GHES or the DeviceTree
+	  estatus driver.
+
 config TEE_STMM_EFI
 	tristate "TEE-based EFI runtime variable service driver"
 	depends on EFI && OPTEE
diff --git a/include/linux/estatus.h b/include/linux/estatus.h
new file mode 100644
index 000000000000..002a9533c85a
--- /dev/null
+++ b/include/linux/estatus.h
@@ -0,0 +1,267 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Firmware-first RAS: Generic Error Status Core
+ *
+ * Copyright (C) 2025 ARM Ltd.
+ * Author: Ahmed Tiba <ahmed.tiba at arm.com>
+ */
+
+#ifndef __LINUX_ESTATUS_H
+#define __LINUX_ESTATUS_H
+
+/* "estatus" abbreviates "error status" (CPER status blocks). */
+
+/*
+ * "estatus" is a contraction of "error status".  The naming mirrors the ACPI
+ * Generic Error Status Block (HEST/CPER) terminology while staying agnostic of
+ * the transport (ACPI, DeviceTree, etc.).
+ */
+
+#include <linux/irq_work.h>
+#include <linux/kconfig.h>
+#include <linux/cper.h>
+#include <asm/fixmap.h>
+
+#if IS_ENABLED(CONFIG_ACPI)
+#include <linux/acpi.h>
+#include <acpi/actbl1.h>
+#define estatus_generic_status struct acpi_hest_generic_status
+#define estatus_generic_data struct acpi_hest_generic_data
+#define estatus_generic_data_v300 struct acpi_hest_generic_data_v300
+#else
+struct estatus_generic_status {
+	u32 block_status;
+	u32 raw_data_offset;
+	u32 raw_data_length;
+	u32 data_length;
+	u32 error_severity;
+} __packed;
+
+struct estatus_generic_data {
+	u8 section_type[16];
+	u32 error_severity;
+	u16 revision;
+	u8 validation_bits;
+	u8 flags;
+	u32 error_data_length;
+	u8 fru_id[16];
+	u8 fru_text[20];
+} __packed;
+
+struct estatus_generic_data_v300 {
+	u8 section_type[16];
+	u32 error_severity;
+	u16 revision;
+	u8 validation_bits;
+	u8 flags;
+	u32 error_data_length;
+	u8 fru_id[16];
+	u8 fru_text[20];
+	u64 time_stamp;
+} __packed;
+
+#define estatus_generic_status struct estatus_generic_status
+#define estatus_generic_data struct estatus_generic_data
+#define estatus_generic_data_v300 struct estatus_generic_data_v300
+
+#define acpi_hest_generic_status estatus_generic_status
+#define acpi_hest_generic_data estatus_generic_data
+#define acpi_hest_generic_data_v300 estatus_generic_data_v300
+#endif
+
+struct estatus_source;
+
+#if IS_ENABLED(CONFIG_ACPI_APEI_GHES)
+#include <acpi/apei.h>
+#endif
+
+void estatus_report_mem_error(int sev, struct cper_sec_mem_err *mem_err);
+
+enum estatus_notify_mode {
+	ESTATUS_NOTIFY_ASYNC,
+	ESTATUS_NOTIFY_SEA,
+};
+
+struct estatus_ops {
+	int (*get_phys)(struct estatus_source *source, phys_addr_t *addr);
+	int (*read)(struct estatus_source *source, phys_addr_t addr,
+		    void *buf, size_t len, enum fixed_addresses fixmap_idx);
+	int (*write)(struct estatus_source *source, phys_addr_t addr,
+		     const void *buf, size_t len, enum fixed_addresses fixmap_idx);
+	void (*ack)(struct estatus_source *source);
+	size_t (*get_max_len)(struct estatus_source *source);
+	enum estatus_notify_mode (*get_notify_mode)(struct estatus_source *source);
+	const char *(*get_name)(struct estatus_source *source);
+};
+
+struct estatus_source {
+	const struct estatus_ops *ops;
+	void *priv;
+	estatus_generic_status *estatus;
+	enum fixed_addresses fixmap_idx;
+};
+
+struct estatus_node {
+	struct llist_node llnode;
+	struct estatus_source *source;
+};
+
+struct estatus_cache {
+	u32 estatus_len;
+	atomic_t count;
+	struct estatus_source *source;
+	unsigned long long time_in;
+	struct rcu_head rcu;
+};
+
+enum {
+	ESTATUS_SEV_NO = 0x0,
+	ESTATUS_SEV_CORRECTED = 0x1,
+	ESTATUS_SEV_RECOVERABLE = 0x2,
+	ESTATUS_SEV_PANIC = 0x3,
+};
+
+int estatus_proc(struct estatus_source *ghes);
+int estatus_in_nmi_queue_one_entry(struct estatus_source *ghes,
+				   enum fixed_addresses fixmap_idx);
+void estatus_proc_in_irq(struct irq_work *irq_work);
+
+/**
+ * estatus_register_vendor_record_notifier - register a notifier for vendor
+ * records that the kernel would otherwise ignore.
+ * @nb: pointer to the notifier_block structure of the event handler.
+ *
+ * return 0 : SUCCESS, non-zero : FAIL
+ */
+int estatus_register_vendor_record_notifier(struct notifier_block *nb);
+
+/**
+ * estatus_unregister_vendor_record_notifier - unregister the previously
+ * registered vendor record notifier.
+ * @nb: pointer to the notifier_block structure of the vendor record handler.
+ */
+void estatus_unregister_vendor_record_notifier(struct notifier_block *nb);
+
+int estatus_pool_init(unsigned int num_ghes);
+
+struct notifier_block;
+void estatus_register_report_chain(struct notifier_block *nb);
+void estatus_unregister_report_chain(struct notifier_block *nb);
+
+static inline int estatus_get_version(estatus_generic_data *gdata)
+{
+	return gdata->revision >> 8;
+}
+
+static inline void *estatus_get_payload(estatus_generic_data *gdata)
+{
+	if (estatus_get_version(gdata) >= 3)
+		return (void *)(((estatus_generic_data_v300 *)(gdata)) + 1);
+
+	return gdata + 1;
+}
+
+static inline int estatus_get_error_length(estatus_generic_data *gdata)
+{
+	return gdata->error_data_length;
+}
+
+static inline int estatus_get_size(estatus_generic_data *gdata)
+{
+	if (estatus_get_version(gdata) >= 3)
+		return sizeof(estatus_generic_data_v300);
+
+	return sizeof(estatus_generic_data);
+}
+
+static inline int estatus_get_record_size(estatus_generic_data *gdata)
+{
+	return (estatus_get_size(gdata) + estatus_get_error_length(gdata));
+}
+
+static inline void *estatus_get_next(estatus_generic_data *gdata)
+{
+	return (void *)(gdata) + estatus_get_record_size(gdata);
+}
+
+static inline estatus_generic_data *
+estatus_first_section(estatus_generic_status *estatus)
+{
+	return (estatus_generic_data *)(estatus + 1);
+}
+
+static inline bool
+estatus_section_valid(estatus_generic_status *estatus,
+		      estatus_generic_data *section)
+{
+	return (void *)section - (void *)(estatus + 1) < estatus->data_length;
+}
+
+struct estatus_section_iter {
+	estatus_generic_status *estatus;
+	estatus_generic_data *section;
+	bool started;
+};
+
+static inline estatus_generic_data *
+estatus_section_iter_next(struct estatus_section_iter *iter,
+			  estatus_generic_status *estatus)
+{
+	if (!iter->started) {
+		iter->estatus = estatus;
+		iter->section = estatus_first_section(estatus);
+		iter->started = true;
+	} else if (iter->section) {
+		iter->section = estatus_get_next(iter->section);
+	}
+
+	if (!iter->section)
+		return NULL;
+
+	if (!estatus_section_valid(iter->estatus, iter->section)) {
+		iter->section = NULL;
+		return NULL;
+	}
+
+	return iter->section;
+}
+
+#define estatus_for_each_section(_estatus, _section)				\
+	for (struct estatus_section_iter __estatus_iter = {0};		\
+	     ((_section) = estatus_section_iter_next(&__estatus_iter, (_estatus))); \
+	     )
+
+static inline int acpi_hest_get_version(struct acpi_hest_generic_data *gdata)
+{
+	return estatus_get_version(gdata);
+}
+
+static inline void *acpi_hest_get_payload(struct acpi_hest_generic_data *gdata)
+{
+	return estatus_get_payload(gdata);
+}
+
+static inline int acpi_hest_get_error_length(struct acpi_hest_generic_data *gdata)
+{
+	return estatus_get_error_length(gdata);
+}
+
+static inline int acpi_hest_get_size(struct acpi_hest_generic_data *gdata)
+{
+	return estatus_get_size(gdata);
+}
+
+static inline int acpi_hest_get_record_size(struct acpi_hest_generic_data *gdata)
+{
+	return estatus_get_record_size(gdata);
+}
+
+static inline void *acpi_hest_get_next(struct acpi_hest_generic_data *gdata)
+{
+	return estatus_get_next(gdata);
+}
+
+#define apei_estatus_for_each_section(estatus, section)			\
+	estatus_for_each_section(estatus, section)
+
+#endif
-- 
2.43.0



From ahmed.tiba at arm.com  Wed Dec 17 03:28:35 2025
From: ahmed.tiba at arm.com (Ahmed Tiba)
Date: Wed, 17 Dec 2025 11:28:35 +0000
Subject: [PATCH 02/12] ras: add estatus core implementation
In-Reply-To: <20251217112845.1814119-1-ahmed.tiba@arm.com>
References: <20251217112845.1814119-1-ahmed.tiba@arm.com>
Message-ID: <20251217112845.1814119-3-ahmed.tiba@arm.com>

Add estatus.c, hook it into the EFI Makefile, and register
the MAINTAINERS entry for the new code. The implementation provides the
memory-pool helpers, notifier plumbing, and utility functions that the
GHES and DeviceTree providers will reuse in later commits.

Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>
---
 MAINTAINERS                    |   1 +
 drivers/firmware/efi/Makefile  |   1 +
 drivers/firmware/efi/estatus.c | 560 +++++++++++++++++++++++++++++++++
 3 files changed, 562 insertions(+)
 create mode 100644 drivers/firmware/efi/estatus.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 501b6d300aa5..67d79d4e612d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -21760,6 +21760,7 @@ F:	drivers/rapidio/
 RAS ERROR STATUS
 M:	Ahmed Tiba <ahmed.tiba at arm.com>
 S:	Maintained
+F:	drivers/firmware/efi/estatus.c
 F:	include/linux/estatus.h
 
 RAS INFRASTRUCTURE
diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile
index 8efbcf699e4f..03708d915bcf 100644
--- a/drivers/firmware/efi/Makefile
+++ b/drivers/firmware/efi/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_EFI_PARAMS_FROM_FDT)	+= fdtparams.o
 obj-$(CONFIG_EFI_ESRT)			+= esrt.o
 obj-$(CONFIG_EFI_VARS_PSTORE)		+= efi-pstore.o
 obj-$(CONFIG_UEFI_CPER)			+= cper.o cper_cxl.o
+obj-$(CONFIG_RAS_ESTATUS_CORE)		+= estatus.o
 obj-$(CONFIG_EFI_RUNTIME_WRAPPERS)	+= runtime-wrappers.o
 subdir-$(CONFIG_EFI_STUB)		+= libstub
 obj-$(CONFIG_EFI_BOOTLOADER_CONTROL)	+= efibc.o
diff --git a/drivers/firmware/efi/estatus.c b/drivers/firmware/efi/estatus.c
new file mode 100644
index 000000000000..8dae5c73ce27
--- /dev/null
+++ b/drivers/firmware/efi/estatus.c
@@ -0,0 +1,560 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Firmware-first RAS: Generic Error Status Core
+ *
+ * Copyright (C) 2025 ARM Ltd.
+ * Author: Ahmed Tiba <ahmed.tiba at arm.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/cper.h>
+#include <linux/ratelimit.h>
+#include <linux/vmalloc.h>
+#include <linux/llist.h>
+#include <linux/genalloc.h>
+#include <linux/pci.h>
+#include <linux/pfn.h>
+#include <linux/aer.h>
+#include <linux/nmi.h>
+#include <linux/sched/clock.h>
+#include <linux/uuid.h>
+#include <linux/kconfig.h>
+#include <linux/ras.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+#include <linux/workqueue.h>
+#include <linux/task_work.h>
+#include <ras/ras_event.h>
+
+#include <linux/estatus.h>
+#include <asm/fixmap.h>
+
+void estatus_pool_region_free(unsigned long addr, u32 size);
+
+static void estatus_log_hw_error(char level, const char *seq_tag,
+				 const char *name)
+{
+	switch (level) {
+	case '0':
+		pr_emerg("%sHardware error from %s\n", seq_tag, name);
+		break;
+	case '1':
+		pr_alert("%sHardware error from %s\n", seq_tag, name);
+		break;
+	case '2':
+		pr_crit("%sHardware error from %s\n", seq_tag, name);
+		break;
+	case '3':
+		pr_err("%sHardware error from %s\n", seq_tag, name);
+		break;
+	case '4':
+		pr_warn("%sHardware error from %s\n", seq_tag, name);
+		break;
+	case '5':
+		pr_notice("%sHardware error from %s\n", seq_tag, name);
+		break;
+	case '6':
+		pr_info("%sHardware error from %s\n", seq_tag, name);
+		break;
+	default:
+		pr_debug("%sHardware error from %s\n", seq_tag, name);
+		break;
+	}
+}
+
+static inline u32 estatus_len(struct acpi_hest_generic_status *estatus)
+{
+	if (estatus->raw_data_length)
+		return estatus->raw_data_offset + estatus->raw_data_length;
+
+	return sizeof(*estatus) + estatus->data_length;
+}
+
+#define ESTATUS_PFX	"ESTATUS: "
+
+#define ESTATUS_ESOURCE_PREALLOC_MAX_SIZE_SIZE	65536
+
+#define ESTATUS_POOL_MIN_ALLOC_ORDER 3
+
+/* This is just an estimation for memory pool allocation */
+#define ESTATUS_CACHE_AVG_SIZE	512
+
+#define ESTATUS_CACHES_SIZE	4
+
+#define ESTATUS_IN_CACHE_MAX_NSEC	10000000000ULL
+/* Prevent too many caches are allocated because of RCU */
+#define ESTATUS_CACHE_ALLOCED_MAX	(ESTATUS_CACHES_SIZE * 3 / 2)
+
+#define ESTATUS_CACHE_LEN(estatus_len)			\
+	(sizeof(struct estatus_cache) + (estatus_len))
+#define ESTATUS_FROM_CACHE(cache)			\
+	((struct acpi_hest_generic_status *)		\
+	 ((struct estatus_cache *)(cache) + 1))
+
+#define ESTATUS_NODE_LEN(estatus_len)			\
+	(sizeof(struct estatus_node) + (estatus_len))
+#define ESTATUS_FROM_NODE(node)				\
+	((struct acpi_hest_generic_status *)		\
+	 ((struct estatus_node *)(node) + 1))
+
+#define ESTATUS_VENDOR_ENTRY_LEN(gdata_len)		\
+	(sizeof(struct estatus_vendor_record_entry) + (gdata_len))
+#define ESTATUS_GDATA_FROM_VENDOR_ENTRY(vendor_entry)	\
+	((struct acpi_hest_generic_data *)		\
+	((struct estatus_vendor_record_entry *)(vendor_entry) + 1))
+
+static ATOMIC_NOTIFIER_HEAD(estatus_report_chain);
+
+struct estatus_vendor_record_entry {
+	struct work_struct work;
+	int error_severity;
+	char vendor_record[];
+};
+
+static struct estatus_cache __rcu *estatus_caches[ESTATUS_CACHES_SIZE];
+static atomic_t estatus_cache_alloced;
+
+static int estatus_panic_timeout __read_mostly = 30;
+
+static struct gen_pool *estatus_pool;
+static DEFINE_MUTEX(estatus_pool_mutex);
+
+static inline const char *estatus_source_name(struct estatus_source *source)
+{
+	if (source->ops && source->ops->get_name)
+		return source->ops->get_name(source);
+
+	return "unknown";
+}
+
+static inline size_t estatus_source_max_len(struct estatus_source *source)
+{
+	if (source->ops && source->ops->get_max_len)
+		return source->ops->get_max_len(source);
+
+	return 0;
+}
+
+static inline enum estatus_notify_mode
+estatus_source_notify_mode(struct estatus_source *source)
+{
+	if (source->ops && source->ops->get_notify_mode)
+		return source->ops->get_notify_mode(source);
+
+	return ESTATUS_NOTIFY_ASYNC;
+}
+
+static inline int estatus_source_get_phys(struct estatus_source *source,
+					  phys_addr_t *addr)
+{
+	if (!source->ops || !source->ops->get_phys)
+		return -EOPNOTSUPP;
+
+	return source->ops->get_phys(source, addr);
+}
+
+static inline int estatus_source_read(struct estatus_source *source,
+				      phys_addr_t addr, void *buf, size_t len,
+				      enum fixed_addresses fixmap_idx)
+{
+	if (!source->ops || !source->ops->read)
+		return -EOPNOTSUPP;
+
+	return source->ops->read(source, addr, buf, len, fixmap_idx);
+}
+
+static inline int estatus_source_write(struct estatus_source *source,
+				       phys_addr_t addr, const void *buf,
+				       size_t len,
+				       enum fixed_addresses fixmap_idx)
+{
+	if (!source->ops || !source->ops->write)
+		return -EOPNOTSUPP;
+
+	return source->ops->write(source, addr, buf, len, fixmap_idx);
+}
+
+static inline void estatus_source_ack(struct estatus_source *source)
+{
+	if (source->ops && source->ops->ack)
+		source->ops->ack(source);
+}
+
+int estatus_pool_init(unsigned int num_ghes)
+{
+	unsigned long addr, len;
+	int rc = 0;
+
+	mutex_lock(&estatus_pool_mutex);
+	if (estatus_pool)
+		goto out_unlock;
+
+	estatus_pool = gen_pool_create(ESTATUS_POOL_MIN_ALLOC_ORDER, -1);
+	if (!estatus_pool) {
+		rc = -ENOMEM;
+		goto out_unlock;
+	}
+
+	if (!num_ghes)
+		num_ghes = 1;
+
+	len = ESTATUS_CACHE_AVG_SIZE * ESTATUS_CACHE_ALLOCED_MAX;
+	len += (num_ghes * ESTATUS_ESOURCE_PREALLOC_MAX_SIZE_SIZE);
+
+	addr = (unsigned long)vmalloc(PAGE_ALIGN(len));
+	if (!addr) {
+		rc = -ENOMEM;
+		goto err_pool_alloc;
+	}
+
+	rc = gen_pool_add(estatus_pool, addr, PAGE_ALIGN(len), -1);
+	if (rc)
+		goto err_pool_add;
+
+out_unlock:
+	mutex_unlock(&estatus_pool_mutex);
+	return rc;
+
+err_pool_add:
+	vfree((void *)addr);
+err_pool_alloc:
+	gen_pool_destroy(estatus_pool);
+	estatus_pool = NULL;
+	goto out_unlock;
+}
+
+/**
+ * estatus_pool_region_free - free previously allocated memory
+ *				   from the estatus_pool.
+ * @addr: address of memory to free.
+ * @size: size of memory to free.
+ *
+ * Returns none.
+ */
+void estatus_pool_region_free(unsigned long addr, u32 size)
+{
+	gen_pool_free(estatus_pool, addr, size);
+}
+EXPORT_SYMBOL_GPL(estatus_pool_region_free);
+
+/* Check the top-level record header has an appropriate size. */
+static int __estatus_check_estatus(struct estatus_source *source,
+				   struct acpi_hest_generic_status *estatus)
+{
+	u32 len = estatus_len(estatus);
+	size_t max_len = estatus_source_max_len(source);
+
+	if (len < sizeof(*estatus)) {
+		pr_warn_ratelimited(FW_WARN ESTATUS_PFX "Truncated error status block!\n");
+		return -EIO;
+	}
+
+	if (max_len && len > max_len) {
+		pr_warn_ratelimited(FW_WARN ESTATUS_PFX "Invalid error status block length!\n");
+		return -EIO;
+	}
+
+	if (cper_estatus_check_header(estatus)) {
+		pr_warn_ratelimited(FW_WARN ESTATUS_PFX "Invalid CPER header!\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/* Read the CPER block, returning its address, and header in estatus. */
+static int __estatus_peek_estatus(struct estatus_source *source,
+				  struct acpi_hest_generic_status *estatus,
+				  phys_addr_t *buf_paddr,
+				  enum fixed_addresses fixmap_idx)
+{
+	int rc;
+
+	rc = estatus_source_get_phys(source, buf_paddr);
+	if (rc) {
+		*buf_paddr = 0;
+		pr_warn_ratelimited(FW_WARN ESTATUS_PFX
+				    "Failed to get error status block address for provider %s: %d\n",
+				    estatus_source_name(source), rc);
+		return rc;
+	}
+
+	if (!*buf_paddr)
+		return -ENOENT;
+
+	rc = estatus_source_read(source, *buf_paddr, estatus,
+				 sizeof(*estatus), fixmap_idx);
+	if (rc)
+		return rc;
+
+	if (!estatus->block_status) {
+		*buf_paddr = 0;
+		return -ENOENT;
+	}
+
+	return 0;
+}
+
+static int __estatus_read_estatus(struct estatus_source *source,
+				  struct acpi_hest_generic_status *estatus,
+				  phys_addr_t buf_paddr,
+				  enum fixed_addresses fixmap_idx,
+				  size_t buf_len)
+{
+	int rc;
+
+	rc = estatus_source_read(source, buf_paddr, estatus, buf_len,
+				 fixmap_idx);
+	if (rc)
+		return rc;
+
+	if (cper_estatus_check(estatus)) {
+		pr_warn_ratelimited(FW_WARN ESTATUS_PFX
+				    "Failed to read error status block for provider %s!\n",
+				    estatus_source_name(source));
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int estatus_read_estatus(struct estatus_source *source,
+				struct acpi_hest_generic_status *estatus,
+				phys_addr_t *buf_paddr,
+				enum fixed_addresses fixmap_idx)
+{
+	int rc;
+
+	rc = __estatus_peek_estatus(source, estatus, buf_paddr, fixmap_idx);
+	if (rc)
+		return rc;
+
+	rc = __estatus_check_estatus(source, estatus);
+	if (rc)
+		return rc;
+
+	return __estatus_read_estatus(source, estatus, *buf_paddr,
+				      fixmap_idx, estatus_len(estatus));
+}
+
+static void estatus_clear_estatus(struct estatus_source *source,
+				  struct acpi_hest_generic_status *estatus,
+				  phys_addr_t buf_paddr,
+				  enum fixed_addresses fixmap_idx)
+{
+	int rc;
+
+	estatus->block_status = 0;
+
+	if (!buf_paddr)
+		return;
+
+	rc = estatus_source_write(source, buf_paddr, estatus,
+				  sizeof(estatus->block_status), fixmap_idx);
+	if (rc)
+		pr_warn_ratelimited(FW_WARN ESTATUS_PFX
+				    "Failed to clear error status block for provider %s: %d\n",
+				    estatus_source_name(source), rc);
+
+	estatus_source_ack(source);
+}
+
+static inline int estatus_severity(int severity)
+{
+	switch (severity) {
+	case CPER_SEV_INFORMATIONAL:
+		return ESTATUS_SEV_NO;
+	case CPER_SEV_CORRECTED:
+		return ESTATUS_SEV_CORRECTED;
+	case CPER_SEV_RECOVERABLE:
+		return ESTATUS_SEV_RECOVERABLE;
+	case CPER_SEV_FATAL:
+		return ESTATUS_SEV_PANIC;
+	default:
+		/* Unknown, go panic */
+		return ESTATUS_SEV_PANIC;
+	}
+}
+
+static void __estatus_print_estatus(const char *pfx,
+				    struct estatus_source *source,
+				    const struct acpi_hest_generic_status *estatus)
+{
+	static atomic_t seqno;
+	unsigned int curr_seqno;
+	char pfx_seq[64];
+	char seq_tag[64];
+	const char *name = estatus_source_name(source);
+	const char *level = pfx;
+	char level_char = '4';
+
+	if (!level) {
+		if (estatus_severity(estatus->error_severity) <=
+		    ESTATUS_SEV_CORRECTED)
+			level = KERN_WARNING;
+		else
+			level = KERN_ERR;
+	}
+
+	if (level[0] == KERN_SOH_ASCII && level[1])
+		level_char = level[1];
+	else if (estatus_severity(estatus->error_severity) > ESTATUS_SEV_CORRECTED)
+		level_char = '3';
+
+	curr_seqno = atomic_inc_return(&seqno);
+	snprintf(seq_tag, sizeof(seq_tag), "{%u}" HW_ERR, curr_seqno);
+	snprintf(pfx_seq, sizeof(pfx_seq), "%s%s", level, seq_tag);
+	estatus_log_hw_error(level_char, seq_tag, name);
+	cper_estatus_print(pfx_seq, estatus);
+}
+
+static int estatus_print_estatus(const char *pfx,
+				 struct estatus_source *source,
+				 const struct acpi_hest_generic_status *estatus)
+{
+	/* Not more than 2 messages every 5 seconds */
+	static DEFINE_RATELIMIT_STATE(ratelimit_corrected, 5 * HZ, 2);
+	static DEFINE_RATELIMIT_STATE(ratelimit_uncorrected, 5 * HZ, 2);
+	struct ratelimit_state *ratelimit;
+
+	if (estatus_severity(estatus->error_severity) <= ESTATUS_SEV_CORRECTED)
+		ratelimit = &ratelimit_corrected;
+	else
+		ratelimit = &ratelimit_uncorrected;
+	if (__ratelimit(ratelimit)) {
+		__estatus_print_estatus(pfx, source, estatus);
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * GHES error status reporting throttle, to report more kinds of
+ * errors, instead of just most frequently occurred errors.
+ */
+static int estatus_cached(struct acpi_hest_generic_status *estatus)
+{
+	u32 len;
+	int i, cached = 0;
+	unsigned long long now;
+	struct estatus_cache *cache;
+	struct acpi_hest_generic_status *cache_estatus;
+
+	len = estatus_len(estatus);
+	rcu_read_lock();
+	for (i = 0; i < ESTATUS_CACHES_SIZE; i++) {
+		cache = rcu_dereference(estatus_caches[i]);
+		if (!cache)
+			continue;
+		if (len != cache->estatus_len)
+			continue;
+		cache_estatus = ESTATUS_FROM_CACHE(cache);
+		if (memcmp(estatus, cache_estatus, len))
+			continue;
+		atomic_inc(&cache->count);
+		now = sched_clock();
+		if (now - cache->time_in < ESTATUS_IN_CACHE_MAX_NSEC)
+			cached = 1;
+		break;
+	}
+	rcu_read_unlock();
+	return cached;
+}
+
+static struct estatus_cache *estatus_cache_alloc(struct estatus_source *source,
+						 struct acpi_hest_generic_status *estatus)
+{
+	int alloced;
+	u32 len, cache_len;
+	struct estatus_cache *cache;
+	struct acpi_hest_generic_status *cache_estatus;
+
+	alloced = atomic_add_return(1, &estatus_cache_alloced);
+	if (alloced > ESTATUS_CACHE_ALLOCED_MAX) {
+		atomic_dec(&estatus_cache_alloced);
+		return NULL;
+	}
+	len = estatus_len(estatus);
+	cache_len = ESTATUS_CACHE_LEN(len);
+	cache = (void *)gen_pool_alloc(estatus_pool, cache_len);
+	if (!cache) {
+		atomic_dec(&estatus_cache_alloced);
+		return NULL;
+	}
+	cache_estatus = ESTATUS_FROM_CACHE(cache);
+	memcpy(cache_estatus, estatus, len);
+	cache->estatus_len = len;
+	atomic_set(&cache->count, 0);
+	cache->source = source;
+	cache->time_in = sched_clock();
+	return cache;
+}
+
+static void estatus_cache_rcu_free(struct rcu_head *head)
+{
+	struct estatus_cache *cache;
+	u32 len;
+
+	cache = container_of(head, struct estatus_cache, rcu);
+	len = estatus_len(ESTATUS_FROM_CACHE(cache));
+	len = ESTATUS_CACHE_LEN(len);
+	gen_pool_free(estatus_pool, (unsigned long)cache, len);
+	atomic_dec(&estatus_cache_alloced);
+}
+
+static void estatus_cache_add(struct estatus_source *source,
+			      struct acpi_hest_generic_status *estatus)
+{
+	unsigned long long now, duration, period, max_period = 0;
+	struct estatus_cache *cache, *new_cache;
+	struct estatus_cache __rcu *victim;
+	int i, slot = -1, count;
+
+	new_cache = estatus_cache_alloc(source, estatus);
+	if (!new_cache)
+		return;
+
+	rcu_read_lock();
+	now = sched_clock();
+	for (i = 0; i < ESTATUS_CACHES_SIZE; i++) {
+		cache = rcu_dereference(estatus_caches[i]);
+		if (!cache) {
+			slot = i;
+			break;
+		}
+		duration = now - cache->time_in;
+		if (duration >= ESTATUS_IN_CACHE_MAX_NSEC) {
+			slot = i;
+			break;
+		}
+		count = atomic_read(&cache->count);
+		period = duration;
+		do_div(period, (count + 1));
+		if (period > max_period) {
+			max_period = period;
+			slot = i;
+		}
+	}
+	rcu_read_unlock();
+
+	if (slot != -1) {
+		/*
+		 * Use release semantics to ensure that estatus_cached()
+		 * running on another CPU will see the updated cache fields if
+		 * it can see the new value of the pointer.
+		 */
+		victim = xchg_release(&estatus_caches[slot],
+				      RCU_INITIALIZER(new_cache));
+
+		/*
+		 * At this point, victim may point to a cached item different
+		 * from the one based on which we selected the slot. Instead of
+		 * going to the loop again to pick another slot, let's just
+		 * drop the other item anyway: this may cause a false cache
+		 * miss later on, but that won't cause any problems.
+		 */
+		if (victim)
+			call_rcu(&unrcu_pointer(victim)->rcu,
+				 estatus_cache_rcu_free);
+	}
+}
-- 
2.43.0



From ahmed.tiba at arm.com  Wed Dec 17 03:28:36 2025
From: ahmed.tiba at arm.com (Ahmed Tiba)
Date: Wed, 17 Dec 2025 11:28:36 +0000
Subject: [PATCH 03/12] ras: add estatus vendor handling and processing
In-Reply-To: <20251217112845.1814119-1-ahmed.tiba@arm.com>
References: <20251217112845.1814119-1-ahmed.tiba@arm.com>
Message-ID: <20251217112845.1814119-4-ahmed.tiba@arm.com>

Teach the estatus core how to walk CPER records and expose the vendor
record notification path. This adds the section iteration helpers,
the logging helpers that mirror the GHES behaviour, and the deferred
work used to hand vendor GUIDs to interested drivers. No users switch
over yet; this simply moves the common logic out of GHES so the next
patches can wire it up.

Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>
---
 drivers/firmware/efi/estatus.c | 415 +++++++++++++++++++++++++++++++++
 1 file changed, 415 insertions(+)

diff --git a/drivers/firmware/efi/estatus.c b/drivers/firmware/efi/estatus.c
index 8dae5c73ce27..5a848d1b218e 100644
--- a/drivers/firmware/efi/estatus.c
+++ b/drivers/firmware/efi/estatus.c
@@ -17,6 +17,7 @@
 #include <linux/aer.h>
 #include <linux/nmi.h>
 #include <linux/sched/clock.h>
+#include <linux/sched/signal.h>
 #include <linux/uuid.h>
 #include <linux/kconfig.h>
 #include <linux/ras.h>
@@ -119,6 +120,14 @@ static int estatus_panic_timeout __read_mostly = 30;
 static struct gen_pool *estatus_pool;
 static DEFINE_MUTEX(estatus_pool_mutex);
 
+static enum fixed_addresses estatus_source_fixmap(struct estatus_source *source)
+{
+	if (WARN_ON_ONCE(!source->fixmap_idx))
+		return FIX_HOLE;
+
+	return source->fixmap_idx;
+}
+
 static inline const char *estatus_source_name(struct estatus_source *source)
 {
 	if (source->ops && source->ops->get_name)
@@ -558,3 +567,409 @@ static void estatus_cache_add(struct estatus_source *source,
 				 estatus_cache_rcu_free);
 	}
 }
+
+struct estatus_task_work {
+	struct callback_head twork;
+	u64 pfn;
+	int flags;
+};
+
+static void estatus_memory_failure_cb(struct callback_head *twork)
+{
+	struct estatus_task_work *twcb = container_of(twork, struct estatus_task_work, twork);
+	int ret;
+
+	ret = memory_failure(twcb->pfn, twcb->flags);
+	gen_pool_free(estatus_pool, (unsigned long)twcb, sizeof(*twcb));
+
+	if (!ret || ret == -EHWPOISON || ret == -EOPNOTSUPP)
+		return;
+
+	pr_err(HW_ERR ESTATUS_PFX
+	       "%#llx: Sending SIGBUS to %s:%d due to hardware memory corruption\n",
+	       twcb->pfn, current->comm, task_pid_nr(current));
+	force_sig(SIGBUS);
+}
+
+static bool estatus_do_memory_failure(u64 physical_addr, int flags)
+{
+	struct estatus_task_work *twcb;
+	unsigned long pfn;
+
+	if (!IS_ENABLED(CONFIG_ACPI_APEI_MEMORY_FAILURE))
+		return false;
+
+	pfn = PHYS_PFN(physical_addr);
+	if (!pfn_valid(pfn) && !arch_is_platform_page(physical_addr)) {
+		pr_warn_ratelimited(FW_WARN ESTATUS_PFX
+		"Invalid address in generic error data: %#llx\n",
+		physical_addr);
+		return false;
+	}
+
+	if (flags == MF_ACTION_REQUIRED && current->mm) {
+		twcb = (void *)gen_pool_alloc(estatus_pool, sizeof(*twcb));
+		if (!twcb)
+			return false;
+
+		twcb->pfn = pfn;
+		twcb->flags = flags;
+		init_task_work(&twcb->twork, estatus_memory_failure_cb);
+		task_work_add(current, &twcb->twork, TWA_RESUME);
+		return true;
+	}
+
+	memory_failure_queue(pfn, flags);
+	return true;
+}
+
+static bool estatus_handle_memory_failure(estatus_generic_data *gdata, int sev, bool sync)
+{
+	int flags = -1;
+	int sec_sev = estatus_severity(gdata->error_severity);
+	struct cper_sec_mem_err *mem_err = estatus_get_payload(gdata);
+
+	if (!(mem_err->validation_bits & CPER_MEM_VALID_PA))
+		return false;
+
+	/* iff following two events can be handled properly by now */
+	if (sec_sev == ESTATUS_SEV_CORRECTED &&
+	    (gdata->flags & CPER_SEC_ERROR_THRESHOLD_EXCEEDED))
+		flags = MF_SOFT_OFFLINE;
+	if (sev == ESTATUS_SEV_RECOVERABLE && sec_sev == ESTATUS_SEV_RECOVERABLE)
+		flags = sync ? MF_ACTION_REQUIRED : 0;
+
+	if (flags != -1)
+		return estatus_do_memory_failure(mem_err->physical_addr, flags);
+
+	return false;
+}
+
+static bool estatus_handle_arm_hw_error(estatus_generic_data *gdata, int sev, bool sync)
+{
+	struct cper_sec_proc_arm *err = estatus_get_payload(gdata);
+	int flags = sync ? MF_ACTION_REQUIRED : 0;
+	bool queued = false;
+	int sec_sev, i;
+	char *p;
+
+	log_arm_hw_error(err);
+
+	sec_sev = estatus_severity(gdata->error_severity);
+	if (sev != ESTATUS_SEV_RECOVERABLE || sec_sev != ESTATUS_SEV_RECOVERABLE)
+		return false;
+
+	p = (char *)(err + 1);
+	for (i = 0; i < err->err_info_num; i++) {
+		struct cper_arm_err_info *err_info = (struct cper_arm_err_info *)p;
+		bool is_cache = (err_info->type == CPER_ARM_CACHE_ERROR);
+		bool has_pa = (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR);
+		const char *error_type = "unknown error";
+
+		/*
+		 * The field (err_info->error_info & BIT(26)) is fixed to set to
+		 * 1 in some old firmware of HiSilicon Kunpeng920. We assume that
+		 * firmware won't mix corrected errors in an uncorrected section,
+		 * and don't filter out 'corrected' error here.
+		 */
+		if (is_cache && has_pa) {
+			queued = estatus_do_memory_failure(err_info->physical_fault_addr, flags);
+			p += err_info->length;
+			continue;
+		}
+
+		if (err_info->type < ARRAY_SIZE(cper_proc_error_type_strs))
+			error_type = cper_proc_error_type_strs[err_info->type];
+
+		pr_warn_ratelimited(FW_WARN ESTATUS_PFX
+				    "Unhandled processor error type: %s\n",
+				    error_type);
+		p += err_info->length;
+	}
+
+	return queued;
+}
+
+/*
+ * PCIe AER errors need to be sent to the AER driver for reporting and
+ * recovery. The ESTATUS severities map to the following AER severities and
+ * require the following handling:
+ *
+ * ESTATUS_SEV_CORRECTABLE -> AER_CORRECTABLE
+ *     These need to be reported by the AER driver but no recovery is
+ *     necessary.
+ * ESTATUS_SEV_RECOVERABLE -> AER_NONFATAL
+ * ESTATUS_SEV_RECOVERABLE && CPER_SEC_RESET -> AER_FATAL
+ *     These both need to be reported and recovered from by the AER driver.
+ * ESTATUS_SEV_PANIC does not make it to this handling since the kernel must
+ *     panic.
+ */
+static void estatus_handle_aer(estatus_generic_data *gdata)
+{
+#ifdef CONFIG_ACPI_APEI_PCIEAER
+	struct cper_sec_pcie *pcie_err = estatus_get_payload(gdata);
+
+	if (pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID &&
+	    pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO) {
+		unsigned int devfn;
+		int aer_severity;
+		u8 *aer_info;
+
+		devfn = PCI_DEVFN(pcie_err->device_id.device,
+				  pcie_err->device_id.function);
+		aer_severity = cper_severity_to_aer(gdata->error_severity);
+
+		/*
+		 * If firmware reset the component to contain
+		 * the error, we must reinitialize it before
+		 * use, so treat it as a fatal AER error.
+		 */
+		if (gdata->flags & CPER_SEC_RESET)
+			aer_severity = AER_FATAL;
+
+		aer_info = (void *)gen_pool_alloc(estatus_pool,
+						  sizeof(struct aer_capability_regs));
+		if (!aer_info)
+			return;
+		memcpy(aer_info, pcie_err->aer_info, sizeof(struct aer_capability_regs));
+
+		aer_recover_queue(pcie_err->device_id.segment,
+				  pcie_err->device_id.bus,
+				  devfn, aer_severity,
+				  (struct aer_capability_regs *)
+				  aer_info);
+	}
+#endif
+}
+
+static BLOCKING_NOTIFIER_HEAD(vendor_record_notify_list);
+
+int estatus_register_vendor_record_notifier(struct notifier_block *nb)
+{
+	return blocking_notifier_chain_register(&vendor_record_notify_list, nb);
+}
+EXPORT_SYMBOL_GPL(estatus_register_vendor_record_notifier);
+
+void estatus_unregister_vendor_record_notifier(struct notifier_block *nb)
+{
+	blocking_notifier_chain_unregister(&vendor_record_notify_list, nb);
+}
+EXPORT_SYMBOL_GPL(estatus_unregister_vendor_record_notifier);
+
+static void estatus_vendor_record_work_func(struct work_struct *work)
+{
+	struct estatus_vendor_record_entry *entry;
+	estatus_generic_data *gdata;
+	u32 len;
+
+	entry = container_of(work, struct estatus_vendor_record_entry, work);
+	gdata = ESTATUS_GDATA_FROM_VENDOR_ENTRY(entry);
+
+	blocking_notifier_call_chain(&vendor_record_notify_list,
+				     entry->error_severity, gdata);
+
+	len = ESTATUS_VENDOR_ENTRY_LEN(estatus_get_record_size(gdata));
+	gen_pool_free(estatus_pool, (unsigned long)entry, len);
+}
+
+static void estatus_defer_non_standard_event(estatus_generic_data *gdata, int sev)
+{
+	estatus_generic_data *copied_gdata;
+	struct estatus_vendor_record_entry *entry;
+	u32 len;
+
+	len = ESTATUS_VENDOR_ENTRY_LEN(estatus_get_record_size(gdata));
+	entry = (void *)gen_pool_alloc(estatus_pool, len);
+	if (!entry)
+		return;
+
+	copied_gdata = ESTATUS_GDATA_FROM_VENDOR_ENTRY(entry);
+	memcpy(copied_gdata, gdata, estatus_get_record_size(gdata));
+	entry->error_severity = sev;
+
+	INIT_WORK(&entry->work, estatus_vendor_record_work_func);
+	schedule_work(&entry->work);
+}
+
+/*
+ * A platform may describe one error source for the handling of synchronous
+ * errors (e.g. MCE or SEA), or for handling asynchronous errors (e.g. SCI
+ * or External Interrupt). On x86, the HEST notifications are always
+ * asynchronous, so only SEA on ARM is delivered as a synchronous
+ * notification.
+ */
+static inline bool estatus_is_sync_notify(struct estatus_source *source)
+{
+	return estatus_source_notify_mode(source) == ESTATUS_NOTIFY_SEA;
+}
+
+static void estatus_do_proc(struct estatus_source *source, const estatus_generic_status *estatus)
+{
+	int sev, sec_sev;
+	estatus_generic_data *gdata;
+	guid_t *sec_type;
+	const guid_t *fru_id = &guid_null;
+	char *fru_text = "";
+	bool queued = false;
+	bool sync = estatus_is_sync_notify(source);
+
+	sev = estatus_severity(estatus->error_severity);
+	estatus_for_each_section(estatus, gdata) {
+		sec_type = (guid_t *)gdata->section_type;
+		sec_sev = estatus_severity(gdata->error_severity);
+		if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
+			fru_id = (guid_t *)gdata->fru_id;
+
+		if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
+			fru_text = gdata->fru_text;
+
+		if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
+			struct cper_sec_mem_err *mem_err = estatus_get_payload(gdata);
+
+			atomic_notifier_call_chain(&estatus_report_chain, sev, mem_err);
+
+			estatus_report_mem_error(sev, mem_err);
+			queued = estatus_handle_memory_failure(gdata, sev, sync);
+		} else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
+			estatus_handle_aer(gdata);
+		} else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
+			queued = estatus_handle_arm_hw_error(gdata, sev, sync);
+		} else {
+			void *err = estatus_get_payload(gdata);
+
+			estatus_defer_non_standard_event(gdata, sev);
+			log_non_standard_event(sec_type, fru_id, fru_text,
+					       sec_sev, err,
+					       gdata->error_data_length);
+		}
+	}
+
+	if (sync && !queued) {
+		pr_err(HW_ERR ESTATUS_PFX
+		       "%s: synchronous unrecoverable error (SIGBUS)\n",
+		       estatus_source_name(source));
+		force_sig(SIGBUS);
+	}
+}
+
+static void __estatus_panic(struct estatus_source *source, estatus_generic_status *estatus,
+			    phys_addr_t buf_paddr, enum fixed_addresses fixmap_idx)
+{
+	const char *msg = ESTATUS_PFX "Fatal hardware error";
+
+	__estatus_print_estatus(KERN_EMERG, source, estatus);
+
+	add_taint(TAINT_MACHINE_CHECK, LOCKDEP_STILL_OK);
+
+	estatus_clear_estatus(source, estatus, buf_paddr, fixmap_idx);
+
+	if (!panic_timeout)
+		pr_emerg("%s but panic disabled\n", msg);
+
+	panic(msg);
+}
+
+int estatus_proc(struct estatus_source *source)
+{
+	estatus_generic_status *estatus = source->estatus;
+	phys_addr_t buf_paddr;
+	enum fixed_addresses fixmap_idx = estatus_source_fixmap(source);
+	int rc;
+
+	rc = estatus_read_estatus(source, estatus, &buf_paddr, fixmap_idx);
+	if (rc)
+		goto out;
+
+	if (estatus_severity(estatus->error_severity) >= ESTATUS_SEV_PANIC)
+		__estatus_panic(source, estatus, buf_paddr, fixmap_idx);
+
+	if (!estatus_cached(estatus)) {
+		if (estatus_print_estatus(NULL, source, estatus))
+			estatus_cache_add(source, estatus);
+	}
+	estatus_do_proc(source, estatus);
+
+out:
+	estatus_clear_estatus(source, estatus, buf_paddr, fixmap_idx);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(estatus_proc);
+
+/*
+ * Handlers for CPER records may not be NMI safe. For example,
+ * memory_failure_queue() takes spinlocks and calls schedule_work_on().
+ * In any NMI-like handler, memory from estatus_pool is used to save
+ * estatus, and added to the estatus_llist. irq_work_queue() causes
+ * estatus_proc_in_irq() to run in IRQ context where each estatus in
+ * estatus_llist is processed.
+ *
+ * Memory from the estatus_pool is also used with the estatus_cache
+ * to suppress frequent messages.
+ */
+static struct llist_head estatus_llist;
+
+void estatus_proc_in_irq(struct irq_work *irq_work)
+{
+	struct llist_node *llnode, *next;
+	struct estatus_node *estatus_node;
+	struct estatus_source *source;
+	estatus_generic_status *estatus;
+	u32 len, node_len;
+
+	llnode = llist_del_all(&estatus_llist);
+	/*
+	 * Because the time order of estatus in list is reversed,
+	 * revert it back to proper order.
+	 */
+	llnode = llist_reverse_order(llnode);
+	while (llnode) {
+		next = llnode->next;
+		estatus_node = llist_entry(llnode, struct estatus_node,
+					   llnode);
+		source = estatus_node->source;
+		estatus = ESTATUS_FROM_NODE(estatus_node);
+		len = estatus_len(estatus);
+		node_len = ESTATUS_NODE_LEN(len);
+		estatus_do_proc(source, estatus);
+		if (!estatus_cached(estatus)) {
+			if (estatus_print_estatus(NULL, source, estatus))
+				estatus_cache_add(source, estatus);
+		}
+		gen_pool_free(estatus_pool,
+			      (unsigned long)estatus_node, node_len);
+
+		llnode = next;
+	}
+}
+EXPORT_SYMBOL_GPL(estatus_proc_in_irq);
+
+static void estatus_print_queued_estatus(void)
+{
+	struct llist_node *llnode;
+	struct estatus_node *estatus_node;
+	struct estatus_source *source;
+	estatus_generic_status *estatus;
+
+	llnode = llist_del_all(&estatus_llist);
+	/*
+	 * Because the time order of estatus in list is reversed,
+	 * revert it back to proper order.
+	 */
+	llnode = llist_reverse_order(llnode);
+	while (llnode) {
+		estatus_node = llist_entry(llnode, struct estatus_node,
+					   llnode);
+		estatus = ESTATUS_FROM_NODE(estatus_node);
+		source = estatus_node->source;
+		estatus_print_estatus(NULL, source, estatus);
+		llnode = llnode->next;
+	}
+}
+
+void estatus_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
+{
+#if IS_ENABLED(CONFIG_ACPI_APEI_GHES)
+	arch_apei_report_mem_error(sev, mem_err);
+#endif
+}
-- 
2.43.0



From ahmed.tiba at arm.com  Wed Dec 17 03:28:37 2025
From: ahmed.tiba at arm.com (Ahmed Tiba)
Date: Wed, 17 Dec 2025 11:28:37 +0000
Subject: [PATCH 04/12] ras: add estatus queuing and IRQ/NMI handling
In-Reply-To: <20251217112845.1814119-1-ahmed.tiba@arm.com>
References: <20251217112845.1814119-1-ahmed.tiba@arm.com>
Message-ID: <20251217112845.1814119-5-ahmed.tiba@arm.com>

Hook the estatus core into the IRQ-work and NMI-safe queues that used to
live in GHES. The new code records CPER payloads into a per-source node,
ships them via irq_work so heavy processing happens out of the NMI path,
and adds the task_work hook used by memory-failure. Behaviour remains the
same as before, but the logic now lives alongside the rest of the estatus
infrastructure so both GHES and DeviceTree providers can reuse it.

Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>
---
 drivers/firmware/efi/estatus.c | 78 ++++++++++++++++++++++++++++++++++
 include/linux/estatus.h        |  3 +-
 2 files changed, 79 insertions(+), 2 deletions(-)

diff --git a/drivers/firmware/efi/estatus.c b/drivers/firmware/efi/estatus.c
index 5a848d1b218e..8b62b23e2e93 100644
--- a/drivers/firmware/efi/estatus.c
+++ b/drivers/firmware/efi/estatus.c
@@ -973,3 +973,81 @@ void estatus_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
 	arch_apei_report_mem_error(sev, mem_err);
 #endif
 }
+
+int estatus_in_nmi_queue_one_entry(struct estatus_source *source, enum fixed_addresses fixmap_idx)
+{
+	estatus_generic_status *estatus, tmp_header;
+	struct estatus_node *estatus_node;
+	u32 len, node_len;
+	phys_addr_t buf_paddr;
+	int sev, rc;
+
+	if (!IS_ENABLED(CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG))
+		return -EOPNOTSUPP;
+
+	rc = __estatus_peek_estatus(source, &tmp_header, &buf_paddr,
+				    fixmap_idx);
+	if (rc) {
+		estatus_clear_estatus(source, &tmp_header, buf_paddr,
+				      fixmap_idx);
+		return rc;
+	}
+
+	rc = __estatus_check_estatus(source, &tmp_header);
+	if (rc) {
+		estatus_clear_estatus(source, &tmp_header, buf_paddr,
+				      fixmap_idx);
+		return rc;
+	}
+
+	len = estatus_len(&tmp_header);
+	node_len = ESTATUS_NODE_LEN(len);
+	estatus_node = (void *)gen_pool_alloc(estatus_pool, node_len);
+	if (!estatus_node)
+		return -ENOMEM;
+
+	estatus_node->source = source;
+	estatus = ESTATUS_FROM_NODE(estatus_node);
+
+	if (__estatus_read_estatus(source, estatus, buf_paddr, fixmap_idx,
+				   len)) {
+		estatus_clear_estatus(source, estatus, buf_paddr, fixmap_idx);
+		rc = -ENOENT;
+		goto no_work;
+	}
+
+	sev = estatus_severity(estatus->error_severity);
+	if (sev >= ESTATUS_SEV_PANIC) {
+		estatus_print_queued_estatus();
+		__estatus_panic(source, estatus, buf_paddr, fixmap_idx);
+	}
+
+	estatus_clear_estatus(source, &tmp_header, buf_paddr, fixmap_idx);
+
+	/* This error has been reported before, don't process it again. */
+	if (estatus_cached(estatus))
+		goto no_work;
+
+	llist_add(&estatus_node->llnode, &estatus_llist);
+
+	return rc;
+
+no_work:
+	gen_pool_free(estatus_pool, (unsigned long)estatus_node,
+		      node_len);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(estatus_in_nmi_queue_one_entry);
+
+void estatus_register_report_chain(struct notifier_block *nb)
+{
+	atomic_notifier_chain_register(&estatus_report_chain, nb);
+}
+EXPORT_SYMBOL_GPL(estatus_register_report_chain);
+
+void estatus_unregister_report_chain(struct notifier_block *nb)
+{
+	atomic_notifier_chain_unregister(&estatus_report_chain, nb);
+}
+EXPORT_SYMBOL_GPL(estatus_unregister_report_chain);
diff --git a/include/linux/estatus.h b/include/linux/estatus.h
index 002a9533c85a..506a74ad60b9 100644
--- a/include/linux/estatus.h
+++ b/include/linux/estatus.h
@@ -122,8 +122,7 @@ enum {
 };
 
 int estatus_proc(struct estatus_source *ghes);
-int estatus_in_nmi_queue_one_entry(struct estatus_source *ghes,
-				   enum fixed_addresses fixmap_idx);
+int estatus_in_nmi_queue_one_entry(struct estatus_source *ghes, enum fixed_addresses fixmap_idx);
 void estatus_proc_in_irq(struct irq_work *irq_work);
 
 /**
-- 
2.43.0



From ahmed.tiba at arm.com  Wed Dec 17 03:28:38 2025
From: ahmed.tiba at arm.com (Ahmed Tiba)
Date: Wed, 17 Dec 2025 11:28:38 +0000
Subject: [PATCH 05/12] ras: flesh out estatus processing core
In-Reply-To: <20251217112845.1814119-1-ahmed.tiba@arm.com>
References: <20251217112845.1814119-1-ahmed.tiba@arm.com>
Message-ID: <20251217112845.1814119-6-ahmed.tiba@arm.com>

Complete the estatus core by adding the cache throttling logic, vendor
record notifier plumbing, IRQ/NMI queue handling and the processing
paths that walk CPER records. Landing the full implementation ahead of
the GHES conversion keeps the follow-on patches focused on their call
sites while leaving behaviour unchanged for existing users.

Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>
---
 drivers/firmware/efi/estatus.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/drivers/firmware/efi/estatus.c b/drivers/firmware/efi/estatus.c
index 8b62b23e2e93..8043d68f907b 100644
--- a/drivers/firmware/efi/estatus.c
+++ b/drivers/firmware/efi/estatus.c
@@ -32,6 +32,7 @@
 
 void estatus_pool_region_free(unsigned long addr, u32 size);
 
+/* Emit a printk at the exact level encoded in the HW_ERR tag we build. */
 static void estatus_log_hw_error(char level, const char *seq_tag,
 				 const char *name)
 {
@@ -704,7 +705,7 @@ static bool estatus_handle_arm_hw_error(estatus_generic_data *gdata, int sev, bo
  * ESTATUS_SEV_PANIC does not make it to this handling since the kernel must
  *     panic.
  */
-static void estatus_handle_aer(estatus_generic_data *gdata)
+static void estatus_handle_aer(struct acpi_hest_generic_data *gdata)
 {
 #ifdef CONFIG_ACPI_APEI_PCIEAER
 	struct cper_sec_pcie *pcie_err = estatus_get_payload(gdata);
@@ -759,7 +760,7 @@ EXPORT_SYMBOL_GPL(estatus_unregister_vendor_record_notifier);
 static void estatus_vendor_record_work_func(struct work_struct *work)
 {
 	struct estatus_vendor_record_entry *entry;
-	estatus_generic_data *gdata;
+	struct acpi_hest_generic_data *gdata;
 	u32 len;
 
 	entry = container_of(work, struct estatus_vendor_record_entry, work);
@@ -774,7 +775,7 @@ static void estatus_vendor_record_work_func(struct work_struct *work)
 
 static void estatus_defer_non_standard_event(estatus_generic_data *gdata, int sev)
 {
-	estatus_generic_data *copied_gdata;
+	struct acpi_hest_generic_data *copied_gdata;
 	struct estatus_vendor_record_entry *entry;
 	u32 len;
 
@@ -806,7 +807,7 @@ static inline bool estatus_is_sync_notify(struct estatus_source *source)
 static void estatus_do_proc(struct estatus_source *source, const estatus_generic_status *estatus)
 {
 	int sev, sec_sev;
-	estatus_generic_data *gdata;
+	struct acpi_hest_generic_data *gdata;
 	guid_t *sec_type;
 	const guid_t *fru_id = &guid_null;
 	char *fru_text = "";
@@ -871,7 +872,7 @@ static void __estatus_panic(struct estatus_source *source, estatus_generic_statu
 
 int estatus_proc(struct estatus_source *source)
 {
-	estatus_generic_status *estatus = source->estatus;
+	struct acpi_hest_generic_status *estatus = source->estatus;
 	phys_addr_t buf_paddr;
 	enum fixed_addresses fixmap_idx = estatus_source_fixmap(source);
 	int rc;
@@ -913,7 +914,7 @@ void estatus_proc_in_irq(struct irq_work *irq_work)
 {
 	struct llist_node *llnode, *next;
 	struct estatus_node *estatus_node;
-	struct estatus_source *source;
+	struct acpi_hest_generic_status *source;
 	estatus_generic_status *estatus;
 	u32 len, node_len;
 
@@ -927,7 +928,7 @@ void estatus_proc_in_irq(struct irq_work *irq_work)
 		next = llnode->next;
 		estatus_node = llist_entry(llnode, struct estatus_node,
 					   llnode);
-		source = estatus_node->source;
+		struct estatus_source *source = estatus_node->source;
 		estatus = ESTATUS_FROM_NODE(estatus_node);
 		len = estatus_len(estatus);
 		node_len = ESTATUS_NODE_LEN(len);
@@ -949,7 +950,7 @@ static void estatus_print_queued_estatus(void)
 	struct llist_node *llnode;
 	struct estatus_node *estatus_node;
 	struct estatus_source *source;
-	estatus_generic_status *estatus;
+	struct acpi_hest_generic_status *estatus;
 
 	llnode = llist_del_all(&estatus_llist);
 	/*
@@ -976,7 +977,7 @@ void estatus_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
 
 int estatus_in_nmi_queue_one_entry(struct estatus_source *source, enum fixed_addresses fixmap_idx)
 {
-	estatus_generic_status *estatus, tmp_header;
+	struct acpi_hest_generic_status *estatus, tmp_header;
 	struct estatus_node *estatus_node;
 	u32 len, node_len;
 	phys_addr_t buf_paddr;
-- 
2.43.0



From ahmed.tiba at arm.com  Wed Dec 17 03:28:39 2025
From: ahmed.tiba at arm.com (Ahmed Tiba)
Date: Wed, 17 Dec 2025 11:28:39 +0000
Subject: [PATCH 06/12] efi/cper: adopt estatus iteration helpers
In-Reply-To: <20251217112845.1814119-1-ahmed.tiba@arm.com>
References: <20251217112845.1814119-1-ahmed.tiba@arm.com>
Message-ID: <20251217112845.1814119-7-ahmed.tiba@arm.com>

Switch the CPER printer and validator to the estatus_*() accessor
wrappers introduced by the new core. This is a mechanical change that
replaces the local acpi_hest_*() helpers with their aliases and keeps
the section iteration code shared ahead of the GHES conversion.

Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>
---
 drivers/firmware/efi/cper.c | 29 +++++++++++++-------------
 include/acpi/ghes.h         | 41 ++-----------------------------------
 2 files changed, 17 insertions(+), 53 deletions(-)

diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c
index 0232bd040f61..07119940486a 100644
--- a/drivers/firmware/efi/cper.c
+++ b/drivers/firmware/efi/cper.c
@@ -26,6 +26,7 @@
 #include <acpi/ghes.h>
 #include <ras/ras_event.h>
 #include <cxl/event.h>
+#include <linux/estatus.h>
 
 /*
  * CPER record ID need to be unique even after reboot, because record
@@ -525,7 +526,7 @@ static void cper_print_fw_err(const char *pfx,
 			      struct acpi_hest_generic_data *gdata,
 			      const struct cper_sec_fw_err_rec_ref *fw_err)
 {
-	void *buf = acpi_hest_get_payload(gdata);
+	void *buf = estatus_get_payload(gdata);
 	u32 offset, length = gdata->error_data_length;
 
 	printk("%s""Firmware Error Record Type: %s\n", pfx,
@@ -607,7 +608,7 @@ cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata
 	__u16 severity;
 	char newpfx[64];
 
-	if (acpi_hest_get_version(gdata) >= 3)
+	if (estatus_get_version(gdata) >= 3)
 		cper_print_tstamp(pfx, (struct acpi_hest_generic_data_v300 *)gdata);
 
 	severity = gdata->error_severity;
@@ -628,7 +629,7 @@ cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata
 	}
 
 	if (guid_equal(sec_type, &CPER_SEC_PROC_GENERIC)) {
-		struct cper_sec_proc_generic *proc_err = acpi_hest_get_payload(gdata);
+		struct cper_sec_proc_generic *proc_err = estatus_get_payload(gdata);
 
 		printk("%s""section_type: general processor error\n", newpfx);
 		if (gdata->error_data_length >= sizeof(*proc_err))
@@ -636,7 +637,7 @@ cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata
 		else
 			goto err_section_too_small;
 	} else if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
-		struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
+		struct cper_sec_mem_err *mem_err = estatus_get_payload(gdata);
 
 		printk("%s""section_type: memory error\n", newpfx);
 		if (gdata->error_data_length >=
@@ -646,7 +647,7 @@ cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata
 		else
 			goto err_section_too_small;
 	} else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
-		struct cper_sec_pcie *pcie = acpi_hest_get_payload(gdata);
+		struct cper_sec_pcie *pcie = estatus_get_payload(gdata);
 
 		printk("%s""section_type: PCIe error\n", newpfx);
 		if (gdata->error_data_length >= sizeof(*pcie))
@@ -655,7 +656,7 @@ cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata
 			goto err_section_too_small;
 #if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
 	} else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
-		struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata);
+		struct cper_sec_proc_arm *arm_err = estatus_get_payload(gdata);
 
 		printk("%ssection_type: ARM processor error\n", newpfx);
 		if (gdata->error_data_length >= sizeof(*arm_err))
@@ -665,7 +666,7 @@ cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata
 #endif
 #if defined(CONFIG_UEFI_CPER_X86)
 	} else if (guid_equal(sec_type, &CPER_SEC_PROC_IA)) {
-		struct cper_sec_proc_ia *ia_err = acpi_hest_get_payload(gdata);
+		struct cper_sec_proc_ia *ia_err = estatus_get_payload(gdata);
 
 		printk("%ssection_type: IA32/X64 processor error\n", newpfx);
 		if (gdata->error_data_length >= sizeof(*ia_err))
@@ -674,7 +675,7 @@ cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata
 			goto err_section_too_small;
 #endif
 	} else if (guid_equal(sec_type, &CPER_SEC_FW_ERR_REC_REF)) {
-		struct cper_sec_fw_err_rec_ref *fw_err = acpi_hest_get_payload(gdata);
+		struct cper_sec_fw_err_rec_ref *fw_err = estatus_get_payload(gdata);
 
 		printk("%ssection_type: Firmware Error Record Reference\n",
 		       newpfx);
@@ -684,7 +685,7 @@ cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata
 		else
 			goto err_section_too_small;
 	} else if (guid_equal(sec_type, &CPER_SEC_CXL_PROT_ERR)) {
-		struct cxl_cper_sec_prot_err *prot_err = acpi_hest_get_payload(gdata);
+		struct cxl_cper_sec_prot_err *prot_err = estatus_get_payload(gdata);
 
 		printk("%ssection_type: CXL Protocol Error\n", newpfx);
 		if (gdata->error_data_length >= sizeof(*prot_err))
@@ -692,7 +693,7 @@ cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata
 		else
 			goto err_section_too_small;
 	} else {
-		const void *err = acpi_hest_get_payload(gdata);
+		const void *err = estatus_get_payload(gdata);
 
 		printk("%ssection type: unknown, %pUl\n", newpfx, sec_type);
 		printk("%ssection length: %#x\n", newpfx,
@@ -723,7 +724,7 @@ void cper_estatus_print(const char *pfx,
 	printk("%s""event severity: %s\n", pfx, cper_severity_str(severity));
 	snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
 
-	apei_estatus_for_each_section(estatus, gdata) {
+	estatus_for_each_section(estatus, gdata) {
 		cper_estatus_print_section(newpfx, gdata, sec_no);
 		sec_no++;
 	}
@@ -755,11 +756,11 @@ int cper_estatus_check(const struct acpi_hest_generic_status *estatus)
 
 	data_len = estatus->data_length;
 
-	apei_estatus_for_each_section(estatus, gdata) {
-		if (acpi_hest_get_size(gdata) > data_len)
+	estatus_for_each_section(estatus, gdata) {
+		if (estatus_get_size(gdata) > data_len)
 			return -EINVAL;
 
-		record_size = acpi_hest_get_record_size(gdata);
+		record_size = estatus_get_record_size(gdata);
 		if (record_size > data_len)
 			return -EINVAL;
 
diff --git a/include/acpi/ghes.h b/include/acpi/ghes.h
index ebd21b05fe6e..022c0325f1e0 100644
--- a/include/acpi/ghes.h
+++ b/include/acpi/ghes.h
@@ -4,6 +4,7 @@
 
 #include <acpi/apei.h>
 #include <acpi/hed.h>
+#include <linux/estatus.h>
 
 /*
  * One struct ghes is created for each generic hardware error source.
@@ -80,46 +81,8 @@ static inline void ghes_estatus_pool_region_free(unsigned long addr, u32 size) {
 
 int ghes_estatus_pool_init(unsigned int num_ghes);
 
-static inline int acpi_hest_get_version(struct acpi_hest_generic_data *gdata)
-{
-	return gdata->revision >> 8;
-}
-
-static inline void *acpi_hest_get_payload(struct acpi_hest_generic_data *gdata)
-{
-	if (acpi_hest_get_version(gdata) >= 3)
-		return (void *)(((struct acpi_hest_generic_data_v300 *)(gdata)) + 1);
-
-	return gdata + 1;
-}
-
-static inline int acpi_hest_get_error_length(struct acpi_hest_generic_data *gdata)
-{
-	return ((struct acpi_hest_generic_data *)(gdata))->error_data_length;
-}
-
-static inline int acpi_hest_get_size(struct acpi_hest_generic_data *gdata)
-{
-	if (acpi_hest_get_version(gdata) >= 3)
-		return sizeof(struct acpi_hest_generic_data_v300);
-
-	return sizeof(struct acpi_hest_generic_data);
-}
-
-static inline int acpi_hest_get_record_size(struct acpi_hest_generic_data *gdata)
-{
-	return (acpi_hest_get_size(gdata) + acpi_hest_get_error_length(gdata));
-}
-
-static inline void *acpi_hest_get_next(struct acpi_hest_generic_data *gdata)
-{
-	return (void *)(gdata) + acpi_hest_get_record_size(gdata);
-}
-
 #define apei_estatus_for_each_section(estatus, section)			\
-	for (section = (struct acpi_hest_generic_data *)(estatus + 1);	\
-	     (void *)section - (void *)(estatus + 1) < estatus->data_length; \
-	     section = acpi_hest_get_next(section))
+	estatus_for_each_section(estatus, section)
 
 #ifdef CONFIG_ACPI_APEI_SEA
 int ghes_notify_sea(void);
-- 
2.43.0



From ahmed.tiba at arm.com  Wed Dec 17 03:28:40 2025
From: ahmed.tiba at arm.com (Ahmed Tiba)
Date: Wed, 17 Dec 2025 11:28:40 +0000
Subject: [PATCH 07/12] ghes: prepare estatus hooks for shared handling
In-Reply-To: <20251217112845.1814119-1-ahmed.tiba@arm.com>
References: <20251217112845.1814119-1-ahmed.tiba@arm.com>
Message-ID: <20251217112845.1814119-8-ahmed.tiba@arm.com>

Introduce struct estatus_source inside struct ghes and export thin
wrappers around the existing GHES estatus helpers. These helpers are
not ACPI-specific, so moving them behind a common interface is the
first step toward reusing the logic for other firmware providers.
Behaviour stays the same for GHES in this patch.

Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>
---
 drivers/acpi/apei/Kconfig      |  1 +
 drivers/firmware/efi/estatus.c |  3 +--
 include/acpi/ghes.h            | 17 +++++++++++++----
 3 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig
index 070c07d68dfb..90cb8360988b 100644
--- a/drivers/acpi/apei/Kconfig
+++ b/drivers/acpi/apei/Kconfig
@@ -24,6 +24,7 @@ config ACPI_APEI_GHES
 	select IRQ_WORK
 	select GENERIC_ALLOCATOR
 	select ARM_SDE_INTERFACE if ARM64
+	select RAS_ESTATUS_CORE
 	help
 	  Generic Hardware Error Source provides a way to report
 	  platform hardware errors (such as that from chipset). It
diff --git a/drivers/firmware/efi/estatus.c b/drivers/firmware/efi/estatus.c
index 8043d68f907b..259122730303 100644
--- a/drivers/firmware/efi/estatus.c
+++ b/drivers/firmware/efi/estatus.c
@@ -654,9 +654,8 @@ static bool estatus_handle_arm_hw_error(estatus_generic_data *gdata, int sev, bo
 	int sec_sev, i;
 	char *p;
 
-	log_arm_hw_error(err);
-
 	sec_sev = estatus_severity(gdata->error_severity);
+	log_arm_hw_error(err, sec_sev);
 	if (sev != ESTATUS_SEV_RECOVERABLE || sec_sev != ESTATUS_SEV_RECOVERABLE)
 		return false;
 
diff --git a/include/acpi/ghes.h b/include/acpi/ghes.h
index 022c0325f1e0..7dc6acde3e2e 100644
--- a/include/acpi/ghes.h
+++ b/include/acpi/ghes.h
@@ -5,6 +5,7 @@
 #include <acpi/apei.h>
 #include <acpi/hed.h>
 #include <linux/estatus.h>
+#include <linux/notifier.h>
 
 /*
  * One struct ghes is created for each generic hardware error source.
@@ -22,6 +23,7 @@ struct ghes {
 		struct acpi_hest_generic_v2 *generic_v2;
 	};
 	struct acpi_hest_generic_status *estatus;
+	struct estatus_source estatus_src;
 	unsigned long flags;
 	union {
 		struct list_head list;
@@ -30,6 +32,7 @@ struct ghes {
 	};
 	struct device *dev;
 	struct list_head elist;
+	char name[32];
 };
 
 struct ghes_estatus_node {
@@ -47,10 +50,10 @@ struct ghes_estatus_cache {
 };
 
 enum {
-	GHES_SEV_NO = 0x0,
-	GHES_SEV_CORRECTED = 0x1,
-	GHES_SEV_RECOVERABLE = 0x2,
-	GHES_SEV_PANIC = 0x3,
+	GHES_SEV_NO = ESTATUS_SEV_NO,
+	GHES_SEV_CORRECTED = ESTATUS_SEV_CORRECTED,
+	GHES_SEV_RECOVERABLE = ESTATUS_SEV_RECOVERABLE,
+	GHES_SEV_PANIC = ESTATUS_SEV_PANIC,
 };
 
 #ifdef CONFIG_ACPI_APEI_GHES
@@ -73,6 +76,12 @@ void ghes_unregister_vendor_record_notifier(struct notifier_block *nb);
 struct list_head *ghes_get_devices(void);
 
 void ghes_estatus_pool_region_free(unsigned long addr, u32 size);
+int ghes_register_vendor_record_notifier(struct notifier_block *nb);
+void ghes_unregister_vendor_record_notifier(struct notifier_block *nb);
+void ghes_register_report_chain(struct notifier_block *nb);
+void ghes_unregister_report_chain(struct notifier_block *nb);
+
+void estatus_pool_region_free(unsigned long addr, u32 size);
 #else
 static inline struct list_head *ghes_get_devices(void) { return NULL; }
 
-- 
2.43.0



From ahmed.tiba at arm.com  Wed Dec 17 03:28:41 2025
From: ahmed.tiba at arm.com (Ahmed Tiba)
Date: Wed, 17 Dec 2025 11:28:41 +0000
Subject: [PATCH 08/12] ghes: add estatus provider ops
In-Reply-To: <20251217112845.1814119-1-ahmed.tiba@arm.com>
References: <20251217112845.1814119-1-ahmed.tiba@arm.com>
Message-ID: <20251217112845.1814119-9-ahmed.tiba@arm.com>

Add the estatus_ops implementation that lets GHES present its CPER buffer
through the new core. The helper plugs the existing fixmap read/write code
into the generic callbacks, wires up the acknowledgment path for GHESv2
sources, and exposes the source name/notification attributes. No behaviour
changes yet?the next patch switches the GHES paths over to these hooks.

Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>
---
 drivers/acpi/apei/ghes.c | 157 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 157 insertions(+)

diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 0dc767392a6c..5932542ea942 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -53,6 +53,7 @@
 #include <asm/tlbflush.h>
 #include <cxl/event.h>
 #include <ras/ras_event.h>
+#include <linux/estatus.h>
 
 #include "apei-internal.h"
 
@@ -250,6 +251,8 @@ static void unmap_gen_v2(struct ghes *ghes)
 	apei_unmap_generic_address(&ghes->generic_v2->read_ack_register);
 }
 
+static const struct estatus_ops ghes_estatus_ops;
+
 static void ghes_ack_error(struct acpi_hest_generic_v2 *gv2)
 {
 	int rc;
@@ -276,6 +279,8 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic)
 		return ERR_PTR(-ENOMEM);
 
 	ghes->generic = generic;
+	scnprintf(ghes->name, sizeof(ghes->name), "GHES source %d",
+		  generic->header.source_id);
 	if (is_hest_type_generic_v2(ghes)) {
 		rc = map_gen_v2(ghes);
 		if (rc)
@@ -299,6 +304,12 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic)
 		goto err_unmap_status_addr;
 	}
 
+	ghes->estatus_src.ops = &ghes_estatus_ops;
+	ghes->estatus_src.priv = ghes;
+	ghes->estatus_src.estatus = ghes->estatus;
+	ghes->estatus_src.fixmap_idx = FIX_APEI_GHES_IRQ;
+	INIT_LIST_HEAD(&ghes->elist);
+
 	return ghes;
 
 err_unmap_status_addr:
@@ -1844,3 +1855,149 @@ void ghes_unregister_report_chain(struct notifier_block *nb)
 	atomic_notifier_chain_unregister(&ghes_report_chain, nb);
 }
 EXPORT_SYMBOL_GPL(ghes_unregister_report_chain);
+
+#define GHES_ESTATUS_RW_FROM_PHYS	1
+#define GHES_ESTATUS_RW_TO_PHYS		0
+
+static void __iomem *ghes_estatus_map(struct ghes *ghes, u64 pfn,
+				      enum fixed_addresses fixmap_idx)
+{
+	phys_addr_t paddr = PFN_PHYS(pfn);
+	pgprot_t prot = arch_apei_get_mem_attribute(paddr);
+
+	__set_fixmap(fixmap_idx, paddr, prot);
+
+	return (void __iomem *)__fix_to_virt(fixmap_idx);
+}
+
+static void ghes_estatus_unmap(void __iomem *vaddr,
+			       enum fixed_addresses fixmap_idx)
+{
+	int _idx = virt_to_fix((unsigned long)vaddr);
+
+	WARN_ON_ONCE(fixmap_idx != _idx);
+	clear_fixmap(fixmap_idx);
+}
+
+static void ghes_estatus_copy_buffer(struct ghes *ghes, void *buffer,
+				     phys_addr_t paddr, size_t len,
+				     int from_phys,
+				     enum fixed_addresses fixmap_idx)
+{
+	void __iomem *vaddr;
+	u64 offset;
+	u32 chunk;
+
+	while (len > 0) {
+		offset = paddr - (paddr & PAGE_MASK);
+		vaddr = ghes_estatus_map(ghes, PHYS_PFN(paddr), fixmap_idx);
+		chunk = PAGE_SIZE - offset;
+		chunk = min_t(u32, chunk, len);
+		if (from_phys == GHES_ESTATUS_RW_FROM_PHYS)
+			memcpy_fromio(buffer, vaddr + offset, chunk);
+		else
+			memcpy_toio(vaddr + offset, buffer, chunk);
+
+		len -= chunk;
+		paddr += chunk;
+		buffer += chunk;
+		ghes_estatus_unmap(vaddr, fixmap_idx);
+	}
+}
+
+static int ghes_estatus_get_phys(struct estatus_source *source,
+				 phys_addr_t *addr)
+{
+	struct ghes *ghes = source->priv;
+	u64 value = 0;
+	int rc;
+
+	rc = apei_read(&value, &ghes->generic->error_status_address);
+	if (rc)
+		return rc;
+
+	*addr = value;
+	return 0;
+}
+
+static int ghes_estatus_read(struct estatus_source *source, phys_addr_t addr,
+			     void *buf, size_t len,
+			     enum fixed_addresses fixmap_idx)
+{
+	struct ghes *ghes = source->priv;
+
+	ghes_estatus_copy_buffer(ghes, buf, addr, len,
+				 GHES_ESTATUS_RW_FROM_PHYS, fixmap_idx);
+	return 0;
+}
+
+static int ghes_estatus_write(struct estatus_source *source, phys_addr_t addr,
+			      const void *buf, size_t len,
+			      enum fixed_addresses fixmap_idx)
+{
+	struct ghes *ghes = source->priv;
+
+	ghes_estatus_copy_buffer(ghes, (void *)buf, addr, len,
+				 GHES_ESTATUS_RW_TO_PHYS, fixmap_idx);
+	return 0;
+}
+
+static void ghes_estatus_ack(struct estatus_source *source)
+{
+	struct ghes *ghes = source->priv;
+	struct acpi_hest_generic_v2 *gv2;
+	u64 val = 0;
+	int rc;
+
+	if (ghes->generic->header.type != ACPI_HEST_TYPE_GENERIC_ERROR_V2)
+		return;
+
+	gv2 = ghes->generic_v2;
+	rc = apei_read(&val, &gv2->read_ack_register);
+	if (rc)
+		return;
+
+	val &= gv2->read_ack_preserve << gv2->read_ack_register.bit_offset;
+	val |= gv2->read_ack_write << gv2->read_ack_register.bit_offset;
+
+	apei_write(val, &gv2->read_ack_register);
+}
+
+static size_t ghes_estatus_get_max_len(struct estatus_source *source)
+{
+	struct ghes *ghes = source->priv;
+
+	return ghes->generic->error_block_length;
+}
+
+static enum estatus_notify_mode
+ghes_estatus_get_notify_mode(struct estatus_source *source)
+{
+	struct ghes *ghes = source->priv;
+	u8 notify_type = ghes->generic->notify.type;
+
+	if (notify_type == ACPI_HEST_NOTIFY_SEA)
+		return ESTATUS_NOTIFY_SEA;
+
+	return ESTATUS_NOTIFY_ASYNC;
+}
+
+static const char *ghes_estatus_get_name(struct estatus_source *source)
+{
+	struct ghes *ghes = source->priv;
+
+	if (ghes->dev)
+		return dev_name(ghes->dev);
+
+	return ghes->name;
+}
+
+static const struct estatus_ops ghes_estatus_ops = {
+	.get_phys	= ghes_estatus_get_phys,
+	.read		= ghes_estatus_read,
+	.write		= ghes_estatus_write,
+	.ack		= ghes_estatus_ack,
+	.get_max_len	= ghes_estatus_get_max_len,
+	.get_notify_mode = ghes_estatus_get_notify_mode,
+	.get_name	= ghes_estatus_get_name,
+};
-- 
2.43.0



From ahmed.tiba at arm.com  Wed Dec 17 03:28:42 2025
From: ahmed.tiba at arm.com (Ahmed Tiba)
Date: Wed, 17 Dec 2025 11:28:42 +0000
Subject: [PATCH 09/12] ghes: route error handling through shared estatus core
In-Reply-To: <20251217112845.1814119-1-ahmed.tiba@arm.com>
References: <20251217112845.1814119-1-ahmed.tiba@arm.com>
Message-ID: <20251217112845.1814119-10-ahmed.tiba@arm.com>

Switch GHES over to the shared estatus. GHES call the common helpers.
This shrinks ghes.c considerably
while keeping runtime behaviour identical, and it allows other
firmware-first providers to reuse exactly the same processing logic.

Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>
---
 drivers/acpi/apei/ghes.c       | 1137 +-------------------------------
 drivers/firmware/efi/estatus.c |   55 +-
 2 files changed, 43 insertions(+), 1149 deletions(-)

diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 5932542ea942..8a9fb9d4ffda 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -60,36 +60,6 @@
 #define GHES_PFX	"GHES: "
 
 #define GHES_ESTATUS_MAX_SIZE		65536
-#define GHES_ESOURCE_PREALLOC_MAX_SIZE	65536
-
-#define GHES_ESTATUS_POOL_MIN_ALLOC_ORDER 3
-
-/* This is just an estimation for memory pool allocation */
-#define GHES_ESTATUS_CACHE_AVG_SIZE	512
-
-#define GHES_ESTATUS_CACHES_SIZE	4
-
-#define GHES_ESTATUS_IN_CACHE_MAX_NSEC	10000000000ULL
-/* Prevent too many caches are allocated because of RCU */
-#define GHES_ESTATUS_CACHE_ALLOCED_MAX	(GHES_ESTATUS_CACHES_SIZE * 3 / 2)
-
-#define GHES_ESTATUS_CACHE_LEN(estatus_len)			\
-	(sizeof(struct ghes_estatus_cache) + (estatus_len))
-#define GHES_ESTATUS_FROM_CACHE(estatus_cache)			\
-	((struct acpi_hest_generic_status *)				\
-	 ((struct ghes_estatus_cache *)(estatus_cache) + 1))
-
-#define GHES_ESTATUS_NODE_LEN(estatus_len)			\
-	(sizeof(struct ghes_estatus_node) + (estatus_len))
-#define GHES_ESTATUS_FROM_NODE(estatus_node)			\
-	((struct acpi_hest_generic_status *)				\
-	 ((struct ghes_estatus_node *)(estatus_node) + 1))
-
-#define GHES_VENDOR_ENTRY_LEN(gdata_len)                               \
-	(sizeof(struct ghes_vendor_record_entry) + (gdata_len))
-#define GHES_GDATA_FROM_VENDOR_ENTRY(vendor_entry)                     \
-	((struct acpi_hest_generic_data *)                              \
-	((struct ghes_vendor_record_entry *)(vendor_entry) + 1))
 
 /*
  *  NMI-like notifications vary by architecture, before the compiler can prune
@@ -100,27 +70,11 @@
 #define FIX_APEI_GHES_SDEI_CRITICAL	__end_of_fixed_addresses
 #endif
 
-static ATOMIC_NOTIFIER_HEAD(ghes_report_chain);
-
 static inline bool is_hest_type_generic_v2(struct ghes *ghes)
 {
 	return ghes->generic->header.type == ACPI_HEST_TYPE_GENERIC_ERROR_V2;
 }
 
-/*
- * A platform may describe one error source for the handling of synchronous
- * errors (e.g. MCE or SEA), or for handling asynchronous errors (e.g. SCI
- * or External Interrupt). On x86, the HEST notifications are always
- * asynchronous, so only SEA on ARM is delivered as a synchronous
- * notification.
- */
-static inline bool is_hest_sync_notify(struct ghes *ghes)
-{
-	u8 notify_type = ghes->generic->notify.type;
-
-	return notify_type == ACPI_HEST_NOTIFY_SEA;
-}
-
 /*
  * This driver isn't really modular, however for the time being,
  * continuing to use module_param is the easiest way to remain
@@ -165,67 +119,11 @@ static DEFINE_MUTEX(ghes_devs_mutex);
  */
 static DEFINE_SPINLOCK(ghes_notify_lock_irq);
 
-struct ghes_vendor_record_entry {
-	struct work_struct work;
-	int error_severity;
-	char vendor_record[];
-};
-
-static struct gen_pool *ghes_estatus_pool;
-
-static struct ghes_estatus_cache __rcu *ghes_estatus_caches[GHES_ESTATUS_CACHES_SIZE];
-static atomic_t ghes_estatus_cache_alloced;
-
-static void __iomem *ghes_map(u64 pfn, enum fixed_addresses fixmap_idx)
-{
-	phys_addr_t paddr;
-	pgprot_t prot;
-
-	paddr = PFN_PHYS(pfn);
-	prot = arch_apei_get_mem_attribute(paddr);
-	__set_fixmap(fixmap_idx, paddr, prot);
-
-	return (void __iomem *) __fix_to_virt(fixmap_idx);
-}
-
-static void ghes_unmap(void __iomem *vaddr, enum fixed_addresses fixmap_idx)
-{
-	int _idx = virt_to_fix((unsigned long)vaddr);
-
-	WARN_ON_ONCE(fixmap_idx != _idx);
-	clear_fixmap(fixmap_idx);
-}
-
 int ghes_estatus_pool_init(unsigned int num_ghes)
 {
-	unsigned long addr, len;
-	int rc;
-
-	ghes_estatus_pool = gen_pool_create(GHES_ESTATUS_POOL_MIN_ALLOC_ORDER, -1);
-	if (!ghes_estatus_pool)
-		return -ENOMEM;
-
-	len = GHES_ESTATUS_CACHE_AVG_SIZE * GHES_ESTATUS_CACHE_ALLOCED_MAX;
-	len += (num_ghes * GHES_ESOURCE_PREALLOC_MAX_SIZE);
-
-	addr = (unsigned long)vmalloc(PAGE_ALIGN(len));
-	if (!addr)
-		goto err_pool_alloc;
-
-	rc = gen_pool_add(ghes_estatus_pool, addr, PAGE_ALIGN(len), -1);
-	if (rc)
-		goto err_pool_add;
-
-	return 0;
-
-err_pool_add:
-	vfree((void *)addr);
-
-err_pool_alloc:
-	gen_pool_destroy(ghes_estatus_pool);
-
-	return -ENOMEM;
+	return estatus_pool_init(num_ghes);
 }
+EXPORT_SYMBOL_GPL(ghes_estatus_pool_init);
 
 /**
  * ghes_estatus_pool_region_free - free previously allocated memory
@@ -237,7 +135,7 @@ int ghes_estatus_pool_init(unsigned int num_ghes)
  */
 void ghes_estatus_pool_region_free(unsigned long addr, u32 size)
 {
-	gen_pool_free(ghes_estatus_pool, addr, size);
+	estatus_pool_region_free(addr, size);
 }
 EXPORT_SYMBOL_GPL(ghes_estatus_pool_region_free);
 
@@ -253,21 +151,6 @@ static void unmap_gen_v2(struct ghes *ghes)
 
 static const struct estatus_ops ghes_estatus_ops;
 
-static void ghes_ack_error(struct acpi_hest_generic_v2 *gv2)
-{
-	int rc;
-	u64 val = 0;
-
-	rc = apei_read(&val, &gv2->read_ack_register);
-	if (rc)
-		return;
-
-	val &= gv2->read_ack_preserve << gv2->read_ack_register.bit_offset;
-	val |= gv2->read_ack_write    << gv2->read_ack_register.bit_offset;
-
-	apei_write(val, &gv2->read_ack_register);
-}
-
 static struct ghes *ghes_new(struct acpi_hest_generic *generic)
 {
 	struct ghes *ghes;
@@ -329,876 +212,18 @@ static void ghes_fini(struct ghes *ghes)
 	if (is_hest_type_generic_v2(ghes))
 		unmap_gen_v2(ghes);
 }
-
-static inline int ghes_severity(int severity)
-{
-	switch (severity) {
-	case CPER_SEV_INFORMATIONAL:
-		return GHES_SEV_NO;
-	case CPER_SEV_CORRECTED:
-		return GHES_SEV_CORRECTED;
-	case CPER_SEV_RECOVERABLE:
-		return GHES_SEV_RECOVERABLE;
-	case CPER_SEV_FATAL:
-		return GHES_SEV_PANIC;
-	default:
-		/* Unknown, go panic */
-		return GHES_SEV_PANIC;
-	}
-}
-
-static void ghes_copy_tofrom_phys(void *buffer, u64 paddr, u32 len,
-				  int from_phys,
-				  enum fixed_addresses fixmap_idx)
-{
-	void __iomem *vaddr;
-	u64 offset;
-	u32 trunk;
-
-	while (len > 0) {
-		offset = paddr - (paddr & PAGE_MASK);
-		vaddr = ghes_map(PHYS_PFN(paddr), fixmap_idx);
-		trunk = PAGE_SIZE - offset;
-		trunk = min(trunk, len);
-		if (from_phys)
-			memcpy_fromio(buffer, vaddr + offset, trunk);
-		else
-			memcpy_toio(vaddr + offset, buffer, trunk);
-		len -= trunk;
-		paddr += trunk;
-		buffer += trunk;
-		ghes_unmap(vaddr, fixmap_idx);
-	}
-}
-
-/* Check the top-level record header has an appropriate size. */
-static int __ghes_check_estatus(struct ghes *ghes,
-				struct acpi_hest_generic_status *estatus)
-{
-	u32 len = cper_estatus_len(estatus);
-
-	if (len < sizeof(*estatus)) {
-		pr_warn_ratelimited(FW_WARN GHES_PFX "Truncated error status block!\n");
-		return -EIO;
-	}
-
-	if (len > ghes->generic->error_block_length) {
-		pr_warn_ratelimited(FW_WARN GHES_PFX "Invalid error status block length!\n");
-		return -EIO;
-	}
-
-	if (cper_estatus_check_header(estatus)) {
-		pr_warn_ratelimited(FW_WARN GHES_PFX "Invalid CPER header!\n");
-		return -EIO;
-	}
-
-	return 0;
-}
-
-/* Read the CPER block, returning its address, and header in estatus. */
-static int __ghes_peek_estatus(struct ghes *ghes,
-			       struct acpi_hest_generic_status *estatus,
-			       u64 *buf_paddr, enum fixed_addresses fixmap_idx)
-{
-	struct acpi_hest_generic *g = ghes->generic;
-	int rc;
-
-	rc = apei_read(buf_paddr, &g->error_status_address);
-	if (rc) {
-		*buf_paddr = 0;
-		pr_warn_ratelimited(FW_WARN GHES_PFX
-"Failed to read error status block address for hardware error source: %d.\n",
-				   g->header.source_id);
-		return -EIO;
-	}
-	if (!*buf_paddr)
-		return -ENOENT;
-
-	ghes_copy_tofrom_phys(estatus, *buf_paddr, sizeof(*estatus), 1,
-			      fixmap_idx);
-	if (!estatus->block_status) {
-		*buf_paddr = 0;
-		return -ENOENT;
-	}
-
-	return 0;
-}
-
-static int __ghes_read_estatus(struct acpi_hest_generic_status *estatus,
-			       u64 buf_paddr, enum fixed_addresses fixmap_idx,
-			       size_t buf_len)
-{
-	ghes_copy_tofrom_phys(estatus, buf_paddr, buf_len, 1, fixmap_idx);
-	if (cper_estatus_check(estatus)) {
-		pr_warn_ratelimited(FW_WARN GHES_PFX
-				    "Failed to read error status block!\n");
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static int ghes_read_estatus(struct ghes *ghes,
-			     struct acpi_hest_generic_status *estatus,
-			     u64 *buf_paddr, enum fixed_addresses fixmap_idx)
-{
-	int rc;
-
-	rc = __ghes_peek_estatus(ghes, estatus, buf_paddr, fixmap_idx);
-	if (rc)
-		return rc;
-
-	rc = __ghes_check_estatus(ghes, estatus);
-	if (rc)
-		return rc;
-
-	return __ghes_read_estatus(estatus, *buf_paddr, fixmap_idx,
-				   cper_estatus_len(estatus));
-}
-
-static void ghes_clear_estatus(struct ghes *ghes,
-			       struct acpi_hest_generic_status *estatus,
-			       u64 buf_paddr, enum fixed_addresses fixmap_idx)
-{
-	estatus->block_status = 0;
-
-	if (!buf_paddr)
-		return;
-
-	ghes_copy_tofrom_phys(estatus, buf_paddr,
-			      sizeof(estatus->block_status), 0,
-			      fixmap_idx);
-
-	/*
-	 * GHESv2 type HEST entries introduce support for error acknowledgment,
-	 * so only acknowledge the error if this support is present.
-	 */
-	if (is_hest_type_generic_v2(ghes))
-		ghes_ack_error(ghes->generic_v2);
-}
-
-/**
- * struct ghes_task_work - for synchronous RAS event
- *
- * @twork:                callback_head for task work
- * @pfn:                  page frame number of corrupted page
- * @flags:                work control flags
- *
- * Structure to pass task work to be handled before
- * returning to user-space via task_work_add().
- */
-struct ghes_task_work {
-	struct callback_head twork;
-	u64 pfn;
-	int flags;
-};
-
-static void memory_failure_cb(struct callback_head *twork)
-{
-	struct ghes_task_work *twcb = container_of(twork, struct ghes_task_work, twork);
-	int ret;
-
-	ret = memory_failure(twcb->pfn, twcb->flags);
-	gen_pool_free(ghes_estatus_pool, (unsigned long)twcb, sizeof(*twcb));
-
-	if (!ret || ret == -EHWPOISON || ret == -EOPNOTSUPP)
-		return;
-
-	pr_err("%#llx: Sending SIGBUS to %s:%d due to hardware memory corruption\n",
-			twcb->pfn, current->comm, task_pid_nr(current));
-	force_sig(SIGBUS);
-}
-
-static bool ghes_do_memory_failure(u64 physical_addr, int flags)
-{
-	struct ghes_task_work *twcb;
-	unsigned long pfn;
-
-	if (!IS_ENABLED(CONFIG_ACPI_APEI_MEMORY_FAILURE))
-		return false;
-
-	pfn = PHYS_PFN(physical_addr);
-
-	if (flags == MF_ACTION_REQUIRED && current->mm) {
-		twcb = (void *)gen_pool_alloc(ghes_estatus_pool, sizeof(*twcb));
-		if (!twcb)
-			return false;
-
-		twcb->pfn = pfn;
-		twcb->flags = flags;
-		init_task_work(&twcb->twork, memory_failure_cb);
-		task_work_add(current, &twcb->twork, TWA_RESUME);
-		return true;
-	}
-
-	memory_failure_queue(pfn, flags);
-	return true;
-}
-
-static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata,
-				       int sev, bool sync)
-{
-	int flags = -1;
-	int sec_sev = ghes_severity(gdata->error_severity);
-	struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
-
-	if (!(mem_err->validation_bits & CPER_MEM_VALID_PA))
-		return false;
-
-	/* iff following two events can be handled properly by now */
-	if (sec_sev == GHES_SEV_CORRECTED &&
-	    (gdata->flags & CPER_SEC_ERROR_THRESHOLD_EXCEEDED))
-		flags = MF_SOFT_OFFLINE;
-	if (sev == GHES_SEV_RECOVERABLE && sec_sev == GHES_SEV_RECOVERABLE)
-		flags = sync ? MF_ACTION_REQUIRED : 0;
-
-	if (flags != -1)
-		return ghes_do_memory_failure(mem_err->physical_addr, flags);
-
-	return false;
-}
-
-static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata,
-				     int sev, bool sync)
-{
-	struct cper_sec_proc_arm *err = acpi_hest_get_payload(gdata);
-	int flags = sync ? MF_ACTION_REQUIRED : 0;
-	char error_type[120];
-	bool queued = false;
-	int sec_sev, i;
-	char *p;
-
-	sec_sev = ghes_severity(gdata->error_severity);
-	log_arm_hw_error(err, sec_sev);
-	if (sev != GHES_SEV_RECOVERABLE || sec_sev != GHES_SEV_RECOVERABLE)
-		return false;
-
-	p = (char *)(err + 1);
-	for (i = 0; i < err->err_info_num; i++) {
-		struct cper_arm_err_info *err_info = (struct cper_arm_err_info *)p;
-		bool is_cache = err_info->type & CPER_ARM_CACHE_ERROR;
-		bool has_pa = (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR);
-
-		/*
-		 * The field (err_info->error_info & BIT(26)) is fixed to set to
-		 * 1 in some old firmware of HiSilicon Kunpeng920. We assume that
-		 * firmware won't mix corrected errors in an uncorrected section,
-		 * and don't filter out 'corrected' error here.
-		 */
-		if (is_cache && has_pa) {
-			queued = ghes_do_memory_failure(err_info->physical_fault_addr, flags);
-			p += err_info->length;
-			continue;
-		}
-
-		cper_bits_to_str(error_type, sizeof(error_type),
-				 FIELD_GET(CPER_ARM_ERR_TYPE_MASK, err_info->type),
-				 cper_proc_error_type_strs,
-				 ARRAY_SIZE(cper_proc_error_type_strs));
-
-		pr_warn_ratelimited(FW_WARN GHES_PFX
-				    "Unhandled processor error type 0x%02x: %s%s\n",
-				    err_info->type, error_type,
-				    (err_info->type & ~CPER_ARM_ERR_TYPE_MASK) ? " with reserved bit(s)" : "");
-		p += err_info->length;
-	}
-
-	return queued;
-}
-
-/*
- * PCIe AER errors need to be sent to the AER driver for reporting and
- * recovery. The GHES severities map to the following AER severities and
- * require the following handling:
- *
- * GHES_SEV_CORRECTABLE -> AER_CORRECTABLE
- *     These need to be reported by the AER driver but no recovery is
- *     necessary.
- * GHES_SEV_RECOVERABLE -> AER_NONFATAL
- * GHES_SEV_RECOVERABLE && CPER_SEC_RESET -> AER_FATAL
- *     These both need to be reported and recovered from by the AER driver.
- * GHES_SEV_PANIC does not make it to this handling since the kernel must
- *     panic.
- */
-static void ghes_handle_aer(struct acpi_hest_generic_data *gdata)
-{
-#ifdef CONFIG_ACPI_APEI_PCIEAER
-	struct cper_sec_pcie *pcie_err = acpi_hest_get_payload(gdata);
-
-	if (pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID &&
-	    pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO) {
-		unsigned int devfn;
-		int aer_severity;
-		u8 *aer_info;
-
-		devfn = PCI_DEVFN(pcie_err->device_id.device,
-				  pcie_err->device_id.function);
-		aer_severity = cper_severity_to_aer(gdata->error_severity);
-
-		/*
-		 * If firmware reset the component to contain
-		 * the error, we must reinitialize it before
-		 * use, so treat it as a fatal AER error.
-		 */
-		if (gdata->flags & CPER_SEC_RESET)
-			aer_severity = AER_FATAL;
-
-		aer_info = (void *)gen_pool_alloc(ghes_estatus_pool,
-						  sizeof(struct aer_capability_regs));
-		if (!aer_info)
-			return;
-		memcpy(aer_info, pcie_err->aer_info, sizeof(struct aer_capability_regs));
-
-		aer_recover_queue(pcie_err->device_id.segment,
-				  pcie_err->device_id.bus,
-				  devfn, aer_severity,
-				  (struct aer_capability_regs *)
-				  aer_info);
-	}
-#endif
-}
-
-static BLOCKING_NOTIFIER_HEAD(vendor_record_notify_list);
-
 int ghes_register_vendor_record_notifier(struct notifier_block *nb)
 {
-	return blocking_notifier_chain_register(&vendor_record_notify_list, nb);
+	return estatus_register_vendor_record_notifier(nb);
 }
 EXPORT_SYMBOL_GPL(ghes_register_vendor_record_notifier);
 
 void ghes_unregister_vendor_record_notifier(struct notifier_block *nb)
 {
-	blocking_notifier_chain_unregister(&vendor_record_notify_list, nb);
+	estatus_unregister_vendor_record_notifier(nb);
 }
 EXPORT_SYMBOL_GPL(ghes_unregister_vendor_record_notifier);
 
-static void ghes_vendor_record_work_func(struct work_struct *work)
-{
-	struct ghes_vendor_record_entry *entry;
-	struct acpi_hest_generic_data *gdata;
-	u32 len;
-
-	entry = container_of(work, struct ghes_vendor_record_entry, work);
-	gdata = GHES_GDATA_FROM_VENDOR_ENTRY(entry);
-
-	blocking_notifier_call_chain(&vendor_record_notify_list,
-				     entry->error_severity, gdata);
-
-	len = GHES_VENDOR_ENTRY_LEN(acpi_hest_get_record_size(gdata));
-	gen_pool_free(ghes_estatus_pool, (unsigned long)entry, len);
-}
-
-static void ghes_defer_non_standard_event(struct acpi_hest_generic_data *gdata,
-					  int sev)
-{
-	struct acpi_hest_generic_data *copied_gdata;
-	struct ghes_vendor_record_entry *entry;
-	u32 len;
-
-	len = GHES_VENDOR_ENTRY_LEN(acpi_hest_get_record_size(gdata));
-	entry = (void *)gen_pool_alloc(ghes_estatus_pool, len);
-	if (!entry)
-		return;
-
-	copied_gdata = GHES_GDATA_FROM_VENDOR_ENTRY(entry);
-	memcpy(copied_gdata, gdata, acpi_hest_get_record_size(gdata));
-	entry->error_severity = sev;
-
-	INIT_WORK(&entry->work, ghes_vendor_record_work_func);
-	schedule_work(&entry->work);
-}
-
-/* Room for 8 entries */
-#define CXL_CPER_PROT_ERR_FIFO_DEPTH 8
-static DEFINE_KFIFO(cxl_cper_prot_err_fifo, struct cxl_cper_prot_err_work_data,
-		    CXL_CPER_PROT_ERR_FIFO_DEPTH);
-
-/* Synchronize schedule_work() with cxl_cper_prot_err_work changes */
-static DEFINE_SPINLOCK(cxl_cper_prot_err_work_lock);
-struct work_struct *cxl_cper_prot_err_work;
-
-static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,
-				   int severity)
-{
-#ifdef CONFIG_ACPI_APEI_PCIEAER
-	struct cxl_cper_prot_err_work_data wd;
-	u8 *dvsec_start, *cap_start;
-
-	if (!(prot_err->valid_bits & PROT_ERR_VALID_AGENT_ADDRESS)) {
-		pr_err_ratelimited("CXL CPER invalid agent type\n");
-		return;
-	}
-
-	if (!(prot_err->valid_bits & PROT_ERR_VALID_ERROR_LOG)) {
-		pr_err_ratelimited("CXL CPER invalid protocol error log\n");
-		return;
-	}
-
-	if (prot_err->err_len != sizeof(struct cxl_ras_capability_regs)) {
-		pr_err_ratelimited("CXL CPER invalid RAS Cap size (%u)\n",
-				   prot_err->err_len);
-		return;
-	}
-
-	if (!(prot_err->valid_bits & PROT_ERR_VALID_SERIAL_NUMBER))
-		pr_warn(FW_WARN "CXL CPER no device serial number\n");
-
-	guard(spinlock_irqsave)(&cxl_cper_prot_err_work_lock);
-
-	if (!cxl_cper_prot_err_work)
-		return;
-
-	switch (prot_err->agent_type) {
-	case RCD:
-	case DEVICE:
-	case LD:
-	case FMLD:
-	case RP:
-	case DSP:
-	case USP:
-		memcpy(&wd.prot_err, prot_err, sizeof(wd.prot_err));
-
-		dvsec_start = (u8 *)(prot_err + 1);
-		cap_start = dvsec_start + prot_err->dvsec_len;
-
-		memcpy(&wd.ras_cap, cap_start, sizeof(wd.ras_cap));
-		wd.severity = cper_severity_to_aer(severity);
-		break;
-	default:
-		pr_err_ratelimited("CXL CPER invalid agent type: %d\n",
-				   prot_err->agent_type);
-		return;
-	}
-
-	if (!kfifo_put(&cxl_cper_prot_err_fifo, wd)) {
-		pr_err_ratelimited("CXL CPER kfifo overflow\n");
-		return;
-	}
-
-	schedule_work(cxl_cper_prot_err_work);
-#endif
-}
-
-int cxl_cper_register_prot_err_work(struct work_struct *work)
-{
-	if (cxl_cper_prot_err_work)
-		return -EINVAL;
-
-	guard(spinlock)(&cxl_cper_prot_err_work_lock);
-	cxl_cper_prot_err_work = work;
-	return 0;
-}
-EXPORT_SYMBOL_NS_GPL(cxl_cper_register_prot_err_work, "CXL");
-
-int cxl_cper_unregister_prot_err_work(struct work_struct *work)
-{
-	if (cxl_cper_prot_err_work != work)
-		return -EINVAL;
-
-	guard(spinlock)(&cxl_cper_prot_err_work_lock);
-	cxl_cper_prot_err_work = NULL;
-	return 0;
-}
-EXPORT_SYMBOL_NS_GPL(cxl_cper_unregister_prot_err_work, "CXL");
-
-int cxl_cper_prot_err_kfifo_get(struct cxl_cper_prot_err_work_data *wd)
-{
-	return kfifo_get(&cxl_cper_prot_err_fifo, wd);
-}
-EXPORT_SYMBOL_NS_GPL(cxl_cper_prot_err_kfifo_get, "CXL");
-
-/* Room for 8 entries for each of the 4 event log queues */
-#define CXL_CPER_FIFO_DEPTH 32
-DEFINE_KFIFO(cxl_cper_fifo, struct cxl_cper_work_data, CXL_CPER_FIFO_DEPTH);
-
-/* Synchronize schedule_work() with cxl_cper_work changes */
-static DEFINE_SPINLOCK(cxl_cper_work_lock);
-struct work_struct *cxl_cper_work;
-
-static void cxl_cper_post_event(enum cxl_event_type event_type,
-				struct cxl_cper_event_rec *rec)
-{
-	struct cxl_cper_work_data wd;
-
-	if (rec->hdr.length <= sizeof(rec->hdr) ||
-	    rec->hdr.length > sizeof(*rec)) {
-		pr_err(FW_WARN "CXL CPER Invalid section length (%u)\n",
-		       rec->hdr.length);
-		return;
-	}
-
-	if (!(rec->hdr.validation_bits & CPER_CXL_COMP_EVENT_LOG_VALID)) {
-		pr_err(FW_WARN "CXL CPER invalid event\n");
-		return;
-	}
-
-	guard(spinlock_irqsave)(&cxl_cper_work_lock);
-
-	if (!cxl_cper_work)
-		return;
-
-	wd.event_type = event_type;
-	memcpy(&wd.rec, rec, sizeof(wd.rec));
-
-	if (!kfifo_put(&cxl_cper_fifo, wd)) {
-		pr_err_ratelimited("CXL CPER kfifo overflow\n");
-		return;
-	}
-
-	schedule_work(cxl_cper_work);
-}
-
-int cxl_cper_register_work(struct work_struct *work)
-{
-	if (cxl_cper_work)
-		return -EINVAL;
-
-	guard(spinlock)(&cxl_cper_work_lock);
-	cxl_cper_work = work;
-	return 0;
-}
-EXPORT_SYMBOL_NS_GPL(cxl_cper_register_work, "CXL");
-
-int cxl_cper_unregister_work(struct work_struct *work)
-{
-	if (cxl_cper_work != work)
-		return -EINVAL;
-
-	guard(spinlock)(&cxl_cper_work_lock);
-	cxl_cper_work = NULL;
-	return 0;
-}
-EXPORT_SYMBOL_NS_GPL(cxl_cper_unregister_work, "CXL");
-
-int cxl_cper_kfifo_get(struct cxl_cper_work_data *wd)
-{
-	return kfifo_get(&cxl_cper_fifo, wd);
-}
-EXPORT_SYMBOL_NS_GPL(cxl_cper_kfifo_get, "CXL");
-
-static void ghes_log_hwerr(int sev, guid_t *sec_type)
-{
-	if (sev != CPER_SEV_RECOVERABLE)
-		return;
-
-	if (guid_equal(sec_type, &CPER_SEC_PROC_ARM) ||
-	    guid_equal(sec_type, &CPER_SEC_PROC_GENERIC) ||
-	    guid_equal(sec_type, &CPER_SEC_PROC_IA)) {
-		hwerr_log_error_type(HWERR_RECOV_CPU);
-		return;
-	}
-
-	if (guid_equal(sec_type, &CPER_SEC_CXL_PROT_ERR) ||
-	    guid_equal(sec_type, &CPER_SEC_CXL_GEN_MEDIA_GUID) ||
-	    guid_equal(sec_type, &CPER_SEC_CXL_DRAM_GUID) ||
-	    guid_equal(sec_type, &CPER_SEC_CXL_MEM_MODULE_GUID)) {
-		hwerr_log_error_type(HWERR_RECOV_CXL);
-		return;
-	}
-
-	if (guid_equal(sec_type, &CPER_SEC_PCIE) ||
-	    guid_equal(sec_type, &CPER_SEC_PCI_X_BUS)) {
-		hwerr_log_error_type(HWERR_RECOV_PCI);
-		return;
-	}
-
-	if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
-		hwerr_log_error_type(HWERR_RECOV_MEMORY);
-		return;
-	}
-
-	hwerr_log_error_type(HWERR_RECOV_OTHERS);
-}
-
-static void ghes_do_proc(struct ghes *ghes,
-			 const struct acpi_hest_generic_status *estatus)
-{
-	int sev, sec_sev;
-	struct acpi_hest_generic_data *gdata;
-	guid_t *sec_type;
-	const guid_t *fru_id = &guid_null;
-	char *fru_text = "";
-	bool queued = false;
-	bool sync = is_hest_sync_notify(ghes);
-
-	sev = ghes_severity(estatus->error_severity);
-	apei_estatus_for_each_section(estatus, gdata) {
-		sec_type = (guid_t *)gdata->section_type;
-		sec_sev = ghes_severity(gdata->error_severity);
-		if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
-			fru_id = (guid_t *)gdata->fru_id;
-
-		if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
-			fru_text = gdata->fru_text;
-
-		ghes_log_hwerr(sev, sec_type);
-		if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
-			struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
-
-			atomic_notifier_call_chain(&ghes_report_chain, sev, mem_err);
-
-			arch_apei_report_mem_error(sev, mem_err);
-			queued = ghes_handle_memory_failure(gdata, sev, sync);
-		} else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
-			ghes_handle_aer(gdata);
-		} else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
-			queued = ghes_handle_arm_hw_error(gdata, sev, sync);
-		} else if (guid_equal(sec_type, &CPER_SEC_CXL_PROT_ERR)) {
-			struct cxl_cper_sec_prot_err *prot_err = acpi_hest_get_payload(gdata);
-
-			cxl_cper_post_prot_err(prot_err, gdata->error_severity);
-		} else if (guid_equal(sec_type, &CPER_SEC_CXL_GEN_MEDIA_GUID)) {
-			struct cxl_cper_event_rec *rec = acpi_hest_get_payload(gdata);
-
-			cxl_cper_post_event(CXL_CPER_EVENT_GEN_MEDIA, rec);
-		} else if (guid_equal(sec_type, &CPER_SEC_CXL_DRAM_GUID)) {
-			struct cxl_cper_event_rec *rec = acpi_hest_get_payload(gdata);
-
-			cxl_cper_post_event(CXL_CPER_EVENT_DRAM, rec);
-		} else if (guid_equal(sec_type, &CPER_SEC_CXL_MEM_MODULE_GUID)) {
-			struct cxl_cper_event_rec *rec = acpi_hest_get_payload(gdata);
-
-			cxl_cper_post_event(CXL_CPER_EVENT_MEM_MODULE, rec);
-		} else {
-			void *err = acpi_hest_get_payload(gdata);
-
-			ghes_defer_non_standard_event(gdata, sev);
-			log_non_standard_event(sec_type, fru_id, fru_text,
-					       sec_sev, err,
-					       gdata->error_data_length);
-		}
-	}
-
-	/*
-	 * If no memory failure work is queued for abnormal synchronous
-	 * errors, do a force kill.
-	 */
-	if (sync && !queued) {
-		dev_err(ghes->dev,
-			HW_ERR GHES_PFX "%s:%d: synchronous unrecoverable error (SIGBUS)\n",
-			current->comm, task_pid_nr(current));
-		force_sig(SIGBUS);
-	}
-}
-
-static void __ghes_print_estatus(const char *pfx,
-				 const struct acpi_hest_generic *generic,
-				 const struct acpi_hest_generic_status *estatus)
-{
-	static atomic_t seqno;
-	unsigned int curr_seqno;
-	char pfx_seq[64];
-
-	if (pfx == NULL) {
-		if (ghes_severity(estatus->error_severity) <=
-		    GHES_SEV_CORRECTED)
-			pfx = KERN_WARNING;
-		else
-			pfx = KERN_ERR;
-	}
-	curr_seqno = atomic_inc_return(&seqno);
-	snprintf(pfx_seq, sizeof(pfx_seq), "%s{%u}" HW_ERR, pfx, curr_seqno);
-	printk("%s""Hardware error from APEI Generic Hardware Error Source: %d\n",
-	       pfx_seq, generic->header.source_id);
-	cper_estatus_print(pfx_seq, estatus);
-}
-
-static int ghes_print_estatus(const char *pfx,
-			      const struct acpi_hest_generic *generic,
-			      const struct acpi_hest_generic_status *estatus)
-{
-	/* Not more than 2 messages every 5 seconds */
-	static DEFINE_RATELIMIT_STATE(ratelimit_corrected, 5*HZ, 2);
-	static DEFINE_RATELIMIT_STATE(ratelimit_uncorrected, 5*HZ, 2);
-	struct ratelimit_state *ratelimit;
-
-	if (ghes_severity(estatus->error_severity) <= GHES_SEV_CORRECTED)
-		ratelimit = &ratelimit_corrected;
-	else
-		ratelimit = &ratelimit_uncorrected;
-	if (__ratelimit(ratelimit)) {
-		__ghes_print_estatus(pfx, generic, estatus);
-		return 1;
-	}
-	return 0;
-}
-
-/*
- * GHES error status reporting throttle, to report more kinds of
- * errors, instead of just most frequently occurred errors.
- */
-static int ghes_estatus_cached(struct acpi_hest_generic_status *estatus)
-{
-	u32 len;
-	int i, cached = 0;
-	unsigned long long now;
-	struct ghes_estatus_cache *cache;
-	struct acpi_hest_generic_status *cache_estatus;
-
-	len = cper_estatus_len(estatus);
-	rcu_read_lock();
-	for (i = 0; i < GHES_ESTATUS_CACHES_SIZE; i++) {
-		cache = rcu_dereference(ghes_estatus_caches[i]);
-		if (cache == NULL)
-			continue;
-		if (len != cache->estatus_len)
-			continue;
-		cache_estatus = GHES_ESTATUS_FROM_CACHE(cache);
-		if (memcmp(estatus, cache_estatus, len))
-			continue;
-		atomic_inc(&cache->count);
-		now = sched_clock();
-		if (now - cache->time_in < GHES_ESTATUS_IN_CACHE_MAX_NSEC)
-			cached = 1;
-		break;
-	}
-	rcu_read_unlock();
-	return cached;
-}
-
-static struct ghes_estatus_cache *ghes_estatus_cache_alloc(
-	struct acpi_hest_generic *generic,
-	struct acpi_hest_generic_status *estatus)
-{
-	int alloced;
-	u32 len, cache_len;
-	struct ghes_estatus_cache *cache;
-	struct acpi_hest_generic_status *cache_estatus;
-
-	alloced = atomic_add_return(1, &ghes_estatus_cache_alloced);
-	if (alloced > GHES_ESTATUS_CACHE_ALLOCED_MAX) {
-		atomic_dec(&ghes_estatus_cache_alloced);
-		return NULL;
-	}
-	len = cper_estatus_len(estatus);
-	cache_len = GHES_ESTATUS_CACHE_LEN(len);
-	cache = (void *)gen_pool_alloc(ghes_estatus_pool, cache_len);
-	if (!cache) {
-		atomic_dec(&ghes_estatus_cache_alloced);
-		return NULL;
-	}
-	cache_estatus = GHES_ESTATUS_FROM_CACHE(cache);
-	memcpy(cache_estatus, estatus, len);
-	cache->estatus_len = len;
-	atomic_set(&cache->count, 0);
-	cache->generic = generic;
-	cache->time_in = sched_clock();
-	return cache;
-}
-
-static void ghes_estatus_cache_rcu_free(struct rcu_head *head)
-{
-	struct ghes_estatus_cache *cache;
-	u32 len;
-
-	cache = container_of(head, struct ghes_estatus_cache, rcu);
-	len = cper_estatus_len(GHES_ESTATUS_FROM_CACHE(cache));
-	len = GHES_ESTATUS_CACHE_LEN(len);
-	gen_pool_free(ghes_estatus_pool, (unsigned long)cache, len);
-	atomic_dec(&ghes_estatus_cache_alloced);
-}
-
-static void
-ghes_estatus_cache_add(struct acpi_hest_generic *generic,
-		       struct acpi_hest_generic_status *estatus)
-{
-	unsigned long long now, duration, period, max_period = 0;
-	struct ghes_estatus_cache *cache, *new_cache;
-	struct ghes_estatus_cache __rcu *victim;
-	int i, slot = -1, count;
-
-	new_cache = ghes_estatus_cache_alloc(generic, estatus);
-	if (!new_cache)
-		return;
-
-	rcu_read_lock();
-	now = sched_clock();
-	for (i = 0; i < GHES_ESTATUS_CACHES_SIZE; i++) {
-		cache = rcu_dereference(ghes_estatus_caches[i]);
-		if (cache == NULL) {
-			slot = i;
-			break;
-		}
-		duration = now - cache->time_in;
-		if (duration >= GHES_ESTATUS_IN_CACHE_MAX_NSEC) {
-			slot = i;
-			break;
-		}
-		count = atomic_read(&cache->count);
-		period = duration;
-		do_div(period, (count + 1));
-		if (period > max_period) {
-			max_period = period;
-			slot = i;
-		}
-	}
-	rcu_read_unlock();
-
-	if (slot != -1) {
-		/*
-		 * Use release semantics to ensure that ghes_estatus_cached()
-		 * running on another CPU will see the updated cache fields if
-		 * it can see the new value of the pointer.
-		 */
-		victim = xchg_release(&ghes_estatus_caches[slot],
-				      RCU_INITIALIZER(new_cache));
-
-		/*
-		 * At this point, victim may point to a cached item different
-		 * from the one based on which we selected the slot. Instead of
-		 * going to the loop again to pick another slot, let's just
-		 * drop the other item anyway: this may cause a false cache
-		 * miss later on, but that won't cause any problems.
-		 */
-		if (victim)
-			call_rcu(&unrcu_pointer(victim)->rcu,
-				 ghes_estatus_cache_rcu_free);
-	}
-}
-
-static void __ghes_panic(struct ghes *ghes,
-			 struct acpi_hest_generic_status *estatus,
-			 u64 buf_paddr, enum fixed_addresses fixmap_idx)
-{
-	const char *msg = GHES_PFX "Fatal hardware error";
-
-	__ghes_print_estatus(KERN_EMERG, ghes->generic, estatus);
-
-	add_taint(TAINT_MACHINE_CHECK, LOCKDEP_STILL_OK);
-
-	ghes_clear_estatus(ghes, estatus, buf_paddr, fixmap_idx);
-
-	if (!panic_timeout)
-		pr_emerg("%s but panic disabled\n", msg);
-
-	panic(msg);
-}
-
-static int ghes_proc(struct ghes *ghes)
-{
-	struct acpi_hest_generic_status *estatus = ghes->estatus;
-	u64 buf_paddr;
-	int rc;
-
-	rc = ghes_read_estatus(ghes, estatus, &buf_paddr, FIX_APEI_GHES_IRQ);
-	if (rc)
-		goto out;
-
-	if (ghes_severity(estatus->error_severity) >= GHES_SEV_PANIC)
-		__ghes_panic(ghes, estatus, buf_paddr, FIX_APEI_GHES_IRQ);
-
-	if (!ghes_estatus_cached(estatus)) {
-		if (ghes_print_estatus(NULL, ghes->generic, estatus))
-			ghes_estatus_cache_add(ghes->generic, estatus);
-	}
-	ghes_do_proc(ghes, estatus);
-
-out:
-	ghes_clear_estatus(ghes, estatus, buf_paddr, FIX_APEI_GHES_IRQ);
-
-	return rc;
-}
-
 static void ghes_add_timer(struct ghes *ghes)
 {
 	struct acpi_hest_generic *g = ghes->generic;
@@ -1220,7 +245,7 @@ static void ghes_poll_func(struct timer_list *t)
 	unsigned long flags;
 
 	spin_lock_irqsave(&ghes_notify_lock_irq, flags);
-	ghes_proc(ghes);
+	estatus_proc(&ghes->estatus_src);
 	spin_unlock_irqrestore(&ghes_notify_lock_irq, flags);
 	if (!(ghes->flags & GHES_EXITING))
 		ghes_add_timer(ghes);
@@ -1233,7 +258,7 @@ static irqreturn_t ghes_irq_func(int irq, void *data)
 	int rc;
 
 	spin_lock_irqsave(&ghes_notify_lock_irq, flags);
-	rc = ghes_proc(ghes);
+	rc = estatus_proc(&ghes->estatus_src);
 	spin_unlock_irqrestore(&ghes_notify_lock_irq, flags);
 	if (rc)
 		return IRQ_NONE;
@@ -1250,7 +275,7 @@ static int ghes_notify_hed(struct notifier_block *this, unsigned long event,
 
 	spin_lock_irqsave(&ghes_notify_lock_irq, flags);
 	list_for_each_entry_rcu(ghes, &ghes_hed, list) {
-		if (!ghes_proc(ghes))
+		if (!estatus_proc(&ghes->estatus_src))
 			ret = NOTIFY_OK;
 	}
 	spin_unlock_irqrestore(&ghes_notify_lock_irq, flags);
@@ -1262,142 +287,8 @@ static struct notifier_block ghes_notifier_hed = {
 	.notifier_call = ghes_notify_hed,
 };
 
-/*
- * Handlers for CPER records may not be NMI safe. For example,
- * memory_failure_queue() takes spinlocks and calls schedule_work_on().
- * In any NMI-like handler, memory from ghes_estatus_pool is used to save
- * estatus, and added to the ghes_estatus_llist. irq_work_queue() causes
- * ghes_proc_in_irq() to run in IRQ context where each estatus in
- * ghes_estatus_llist is processed.
- *
- * Memory from the ghes_estatus_pool is also used with the ghes_estatus_cache
- * to suppress frequent messages.
- */
-static struct llist_head ghes_estatus_llist;
 static struct irq_work ghes_proc_irq_work;
 
-static void ghes_proc_in_irq(struct irq_work *irq_work)
-{
-	struct llist_node *llnode, *next;
-	struct ghes_estatus_node *estatus_node;
-	struct acpi_hest_generic *generic;
-	struct acpi_hest_generic_status *estatus;
-	u32 len, node_len;
-
-	llnode = llist_del_all(&ghes_estatus_llist);
-	/*
-	 * Because the time order of estatus in list is reversed,
-	 * revert it back to proper order.
-	 */
-	llnode = llist_reverse_order(llnode);
-	while (llnode) {
-		next = llnode->next;
-		estatus_node = llist_entry(llnode, struct ghes_estatus_node,
-					   llnode);
-		estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
-		len = cper_estatus_len(estatus);
-		node_len = GHES_ESTATUS_NODE_LEN(len);
-
-		ghes_do_proc(estatus_node->ghes, estatus);
-
-		if (!ghes_estatus_cached(estatus)) {
-			generic = estatus_node->generic;
-			if (ghes_print_estatus(NULL, generic, estatus))
-				ghes_estatus_cache_add(generic, estatus);
-		}
-		gen_pool_free(ghes_estatus_pool, (unsigned long)estatus_node,
-			      node_len);
-
-		llnode = next;
-	}
-}
-
-static void ghes_print_queued_estatus(void)
-{
-	struct llist_node *llnode;
-	struct ghes_estatus_node *estatus_node;
-	struct acpi_hest_generic *generic;
-	struct acpi_hest_generic_status *estatus;
-
-	llnode = llist_del_all(&ghes_estatus_llist);
-	/*
-	 * Because the time order of estatus in list is reversed,
-	 * revert it back to proper order.
-	 */
-	llnode = llist_reverse_order(llnode);
-	while (llnode) {
-		estatus_node = llist_entry(llnode, struct ghes_estatus_node,
-					   llnode);
-		estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
-		generic = estatus_node->generic;
-		ghes_print_estatus(NULL, generic, estatus);
-		llnode = llnode->next;
-	}
-}
-
-static int ghes_in_nmi_queue_one_entry(struct ghes *ghes,
-				       enum fixed_addresses fixmap_idx)
-{
-	struct acpi_hest_generic_status *estatus, tmp_header;
-	struct ghes_estatus_node *estatus_node;
-	u32 len, node_len;
-	u64 buf_paddr;
-	int sev, rc;
-
-	if (!IS_ENABLED(CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG))
-		return -EOPNOTSUPP;
-
-	rc = __ghes_peek_estatus(ghes, &tmp_header, &buf_paddr, fixmap_idx);
-	if (rc) {
-		ghes_clear_estatus(ghes, &tmp_header, buf_paddr, fixmap_idx);
-		return rc;
-	}
-
-	rc = __ghes_check_estatus(ghes, &tmp_header);
-	if (rc) {
-		ghes_clear_estatus(ghes, &tmp_header, buf_paddr, fixmap_idx);
-		return rc;
-	}
-
-	len = cper_estatus_len(&tmp_header);
-	node_len = GHES_ESTATUS_NODE_LEN(len);
-	estatus_node = (void *)gen_pool_alloc(ghes_estatus_pool, node_len);
-	if (!estatus_node)
-		return -ENOMEM;
-
-	estatus_node->ghes = ghes;
-	estatus_node->generic = ghes->generic;
-	estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
-
-	if (__ghes_read_estatus(estatus, buf_paddr, fixmap_idx, len)) {
-		ghes_clear_estatus(ghes, estatus, buf_paddr, fixmap_idx);
-		rc = -ENOENT;
-		goto no_work;
-	}
-
-	sev = ghes_severity(estatus->error_severity);
-	if (sev >= GHES_SEV_PANIC) {
-		ghes_print_queued_estatus();
-		__ghes_panic(ghes, estatus, buf_paddr, fixmap_idx);
-	}
-
-	ghes_clear_estatus(ghes, &tmp_header, buf_paddr, fixmap_idx);
-
-	/* This error has been reported before, don't process it again. */
-	if (ghes_estatus_cached(estatus))
-		goto no_work;
-
-	llist_add(&estatus_node->llnode, &ghes_estatus_llist);
-
-	return rc;
-
-no_work:
-	gen_pool_free(ghes_estatus_pool, (unsigned long)estatus_node,
-		      node_len);
-
-	return rc;
-}
-
 static int ghes_in_nmi_spool_from_list(struct list_head *rcu_list,
 				       enum fixed_addresses fixmap_idx)
 {
@@ -1406,7 +297,7 @@ static int ghes_in_nmi_spool_from_list(struct list_head *rcu_list,
 
 	rcu_read_lock();
 	list_for_each_entry_rcu(ghes, rcu_list, list) {
-		if (!ghes_in_nmi_queue_one_entry(ghes, fixmap_idx))
+		if (!estatus_in_nmi_queue_one_entry(&ghes->estatus_src, fixmap_idx))
 			ret = 0;
 	}
 	rcu_read_unlock();
@@ -1510,13 +401,13 @@ static inline void ghes_nmi_remove(struct ghes *ghes) { }
 
 static void ghes_nmi_init_cxt(void)
 {
-	init_irq_work(&ghes_proc_irq_work, ghes_proc_in_irq);
+	init_irq_work(&ghes_proc_irq_work, estatus_proc_in_irq);
 }
 
 static int __ghes_sdei_callback(struct ghes *ghes,
 				enum fixed_addresses fixmap_idx)
 {
-	if (!ghes_in_nmi_queue_one_entry(ghes, fixmap_idx)) {
+	if (!estatus_in_nmi_queue_one_entry(&ghes->estatus_src, fixmap_idx)) {
 		irq_work_queue(&ghes_proc_irq_work);
 
 		return 0;
@@ -1693,7 +584,7 @@ static int ghes_probe(struct platform_device *ghes_dev)
 
 	/* Handle any pending errors right away */
 	spin_lock_irqsave(&ghes_notify_lock_irq, flags);
-	ghes_proc(ghes);
+	estatus_proc(&ghes->estatus_src);
 	spin_unlock_irqrestore(&ghes_notify_lock_irq, flags);
 
 	return 0;
@@ -1846,13 +737,13 @@ EXPORT_SYMBOL_GPL(ghes_get_devices);
 
 void ghes_register_report_chain(struct notifier_block *nb)
 {
-	atomic_notifier_chain_register(&ghes_report_chain, nb);
+	estatus_register_report_chain(nb);
 }
 EXPORT_SYMBOL_GPL(ghes_register_report_chain);
 
 void ghes_unregister_report_chain(struct notifier_block *nb)
 {
-	atomic_notifier_chain_unregister(&ghes_report_chain, nb);
+	estatus_unregister_report_chain(nb);
 }
 EXPORT_SYMBOL_GPL(ghes_unregister_report_chain);
 
diff --git a/drivers/firmware/efi/estatus.c b/drivers/firmware/efi/estatus.c
index 259122730303..2080abef673d 100644
--- a/drivers/firmware/efi/estatus.c
+++ b/drivers/firmware/efi/estatus.c
@@ -16,23 +16,26 @@
 #include <linux/pfn.h>
 #include <linux/aer.h>
 #include <linux/nmi.h>
+#include <linux/mm.h>
 #include <linux/sched/clock.h>
 #include <linux/sched/signal.h>
+#include <linux/spinlock.h>
 #include <linux/uuid.h>
 #include <linux/kconfig.h>
 #include <linux/ras.h>
 #include <linux/mutex.h>
+#include <linux/kfifo.h>
 #include <linux/notifier.h>
 #include <linux/workqueue.h>
 #include <linux/task_work.h>
 #include <ras/ras_event.h>
+#include <cxl/event.h>
 
 #include <linux/estatus.h>
 #include <asm/fixmap.h>
 
 void estatus_pool_region_free(unsigned long addr, u32 size);
 
-/* Emit a printk at the exact level encoded in the HW_ERR tag we build. */
 static void estatus_log_hw_error(char level, const char *seq_tag,
 				 const char *name)
 {
@@ -64,7 +67,7 @@ static void estatus_log_hw_error(char level, const char *seq_tag,
 	}
 }
 
-static inline u32 estatus_len(struct acpi_hest_generic_status *estatus)
+static inline u32 estatus_len(estatus_generic_status *estatus)
 {
 	if (estatus->raw_data_length)
 		return estatus->raw_data_offset + estatus->raw_data_length;
@@ -90,19 +93,19 @@ static inline u32 estatus_len(struct acpi_hest_generic_status *estatus)
 #define ESTATUS_CACHE_LEN(estatus_len)			\
 	(sizeof(struct estatus_cache) + (estatus_len))
 #define ESTATUS_FROM_CACHE(cache)			\
-	((struct acpi_hest_generic_status *)		\
+	((estatus_generic_status *)		\
 	 ((struct estatus_cache *)(cache) + 1))
 
 #define ESTATUS_NODE_LEN(estatus_len)			\
 	(sizeof(struct estatus_node) + (estatus_len))
 #define ESTATUS_FROM_NODE(node)				\
-	((struct acpi_hest_generic_status *)		\
+	((estatus_generic_status *)		\
 	 ((struct estatus_node *)(node) + 1))
 
 #define ESTATUS_VENDOR_ENTRY_LEN(gdata_len)		\
 	(sizeof(struct estatus_vendor_record_entry) + (gdata_len))
 #define ESTATUS_GDATA_FROM_VENDOR_ENTRY(vendor_entry)	\
-	((struct acpi_hest_generic_data *)		\
+	((estatus_generic_data *)		\
 	((struct estatus_vendor_record_entry *)(vendor_entry) + 1))
 
 static ATOMIC_NOTIFIER_HEAD(estatus_report_chain);
@@ -249,7 +252,7 @@ EXPORT_SYMBOL_GPL(estatus_pool_region_free);
 
 /* Check the top-level record header has an appropriate size. */
 static int __estatus_check_estatus(struct estatus_source *source,
-				   struct acpi_hest_generic_status *estatus)
+				   estatus_generic_status *estatus)
 {
 	u32 len = estatus_len(estatus);
 	size_t max_len = estatus_source_max_len(source);
@@ -274,7 +277,7 @@ static int __estatus_check_estatus(struct estatus_source *source,
 
 /* Read the CPER block, returning its address, and header in estatus. */
 static int __estatus_peek_estatus(struct estatus_source *source,
-				  struct acpi_hest_generic_status *estatus,
+				  estatus_generic_status *estatus,
 				  phys_addr_t *buf_paddr,
 				  enum fixed_addresses fixmap_idx)
 {
@@ -306,7 +309,7 @@ static int __estatus_peek_estatus(struct estatus_source *source,
 }
 
 static int __estatus_read_estatus(struct estatus_source *source,
-				  struct acpi_hest_generic_status *estatus,
+				  estatus_generic_status *estatus,
 				  phys_addr_t buf_paddr,
 				  enum fixed_addresses fixmap_idx,
 				  size_t buf_len)
@@ -329,7 +332,7 @@ static int __estatus_read_estatus(struct estatus_source *source,
 }
 
 static int estatus_read_estatus(struct estatus_source *source,
-				struct acpi_hest_generic_status *estatus,
+				estatus_generic_status *estatus,
 				phys_addr_t *buf_paddr,
 				enum fixed_addresses fixmap_idx)
 {
@@ -348,7 +351,7 @@ static int estatus_read_estatus(struct estatus_source *source,
 }
 
 static void estatus_clear_estatus(struct estatus_source *source,
-				  struct acpi_hest_generic_status *estatus,
+				  estatus_generic_status *estatus,
 				  phys_addr_t buf_paddr,
 				  enum fixed_addresses fixmap_idx)
 {
@@ -388,7 +391,7 @@ static inline int estatus_severity(int severity)
 
 static void __estatus_print_estatus(const char *pfx,
 				    struct estatus_source *source,
-				    const struct acpi_hest_generic_status *estatus)
+				    const estatus_generic_status *estatus)
 {
 	static atomic_t seqno;
 	unsigned int curr_seqno;
@@ -420,7 +423,7 @@ static void __estatus_print_estatus(const char *pfx,
 
 static int estatus_print_estatus(const char *pfx,
 				 struct estatus_source *source,
-				 const struct acpi_hest_generic_status *estatus)
+				 const estatus_generic_status *estatus)
 {
 	/* Not more than 2 messages every 5 seconds */
 	static DEFINE_RATELIMIT_STATE(ratelimit_corrected, 5 * HZ, 2);
@@ -442,13 +445,13 @@ static int estatus_print_estatus(const char *pfx,
  * GHES error status reporting throttle, to report more kinds of
  * errors, instead of just most frequently occurred errors.
  */
-static int estatus_cached(struct acpi_hest_generic_status *estatus)
+static int estatus_cached(estatus_generic_status *estatus)
 {
 	u32 len;
 	int i, cached = 0;
 	unsigned long long now;
 	struct estatus_cache *cache;
-	struct acpi_hest_generic_status *cache_estatus;
+	estatus_generic_status *cache_estatus;
 
 	len = estatus_len(estatus);
 	rcu_read_lock();
@@ -472,12 +475,12 @@ static int estatus_cached(struct acpi_hest_generic_status *estatus)
 }
 
 static struct estatus_cache *estatus_cache_alloc(struct estatus_source *source,
-						 struct acpi_hest_generic_status *estatus)
+						 estatus_generic_status *estatus)
 {
 	int alloced;
 	u32 len, cache_len;
 	struct estatus_cache *cache;
-	struct acpi_hest_generic_status *cache_estatus;
+	estatus_generic_status *cache_estatus;
 
 	alloced = atomic_add_return(1, &estatus_cache_alloced);
 	if (alloced > ESTATUS_CACHE_ALLOCED_MAX) {
@@ -513,7 +516,7 @@ static void estatus_cache_rcu_free(struct rcu_head *head)
 }
 
 static void estatus_cache_add(struct estatus_source *source,
-			      struct acpi_hest_generic_status *estatus)
+			      estatus_generic_status *estatus)
 {
 	unsigned long long now, duration, period, max_period = 0;
 	struct estatus_cache *cache, *new_cache;
@@ -704,7 +707,7 @@ static bool estatus_handle_arm_hw_error(estatus_generic_data *gdata, int sev, bo
  * ESTATUS_SEV_PANIC does not make it to this handling since the kernel must
  *     panic.
  */
-static void estatus_handle_aer(struct acpi_hest_generic_data *gdata)
+static void estatus_handle_aer(estatus_generic_data *gdata)
 {
 #ifdef CONFIG_ACPI_APEI_PCIEAER
 	struct cper_sec_pcie *pcie_err = estatus_get_payload(gdata);
@@ -759,7 +762,7 @@ EXPORT_SYMBOL_GPL(estatus_unregister_vendor_record_notifier);
 static void estatus_vendor_record_work_func(struct work_struct *work)
 {
 	struct estatus_vendor_record_entry *entry;
-	struct acpi_hest_generic_data *gdata;
+	estatus_generic_data *gdata;
 	u32 len;
 
 	entry = container_of(work, struct estatus_vendor_record_entry, work);
@@ -774,7 +777,7 @@ static void estatus_vendor_record_work_func(struct work_struct *work)
 
 static void estatus_defer_non_standard_event(estatus_generic_data *gdata, int sev)
 {
-	struct acpi_hest_generic_data *copied_gdata;
+	estatus_generic_data *copied_gdata;
 	struct estatus_vendor_record_entry *entry;
 	u32 len;
 
@@ -806,7 +809,7 @@ static inline bool estatus_is_sync_notify(struct estatus_source *source)
 static void estatus_do_proc(struct estatus_source *source, const estatus_generic_status *estatus)
 {
 	int sev, sec_sev;
-	struct acpi_hest_generic_data *gdata;
+	estatus_generic_data *gdata;
 	guid_t *sec_type;
 	const guid_t *fru_id = &guid_null;
 	char *fru_text = "";
@@ -871,7 +874,7 @@ static void __estatus_panic(struct estatus_source *source, estatus_generic_statu
 
 int estatus_proc(struct estatus_source *source)
 {
-	struct acpi_hest_generic_status *estatus = source->estatus;
+	estatus_generic_status *estatus = source->estatus;
 	phys_addr_t buf_paddr;
 	enum fixed_addresses fixmap_idx = estatus_source_fixmap(source);
 	int rc;
@@ -913,7 +916,7 @@ void estatus_proc_in_irq(struct irq_work *irq_work)
 {
 	struct llist_node *llnode, *next;
 	struct estatus_node *estatus_node;
-	struct acpi_hest_generic_status *source;
+	struct estatus_source *source;
 	estatus_generic_status *estatus;
 	u32 len, node_len;
 
@@ -927,7 +930,7 @@ void estatus_proc_in_irq(struct irq_work *irq_work)
 		next = llnode->next;
 		estatus_node = llist_entry(llnode, struct estatus_node,
 					   llnode);
-		struct estatus_source *source = estatus_node->source;
+		source = estatus_node->source;
 		estatus = ESTATUS_FROM_NODE(estatus_node);
 		len = estatus_len(estatus);
 		node_len = ESTATUS_NODE_LEN(len);
@@ -949,7 +952,7 @@ static void estatus_print_queued_estatus(void)
 	struct llist_node *llnode;
 	struct estatus_node *estatus_node;
 	struct estatus_source *source;
-	struct acpi_hest_generic_status *estatus;
+	estatus_generic_status *estatus;
 
 	llnode = llist_del_all(&estatus_llist);
 	/*
@@ -976,7 +979,7 @@ void estatus_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
 
 int estatus_in_nmi_queue_one_entry(struct estatus_source *source, enum fixed_addresses fixmap_idx)
 {
-	struct acpi_hest_generic_status *estatus, tmp_header;
+	estatus_generic_status *estatus, tmp_header;
 	struct estatus_node *estatus_node;
 	u32 len, node_len;
 	phys_addr_t buf_paddr;
-- 
2.43.0



From ahmed.tiba at arm.com  Wed Dec 17 03:28:43 2025
From: ahmed.tiba at arm.com (Ahmed Tiba)
Date: Wed, 17 Dec 2025 11:28:43 +0000
Subject: [PATCH 10/12] dt-bindings: ras: document estatus provider
In-Reply-To: <20251217112845.1814119-1-ahmed.tiba@arm.com>
References: <20251217112845.1814119-1-ahmed.tiba@arm.com>
Message-ID: <20251217112845.1814119-11-ahmed.tiba@arm.com>

Add a binding for firmware-first CPER providers described via
DeviceTree. It covers the shared status block, optional acknowledgment
registers, interrupt versus polling modes and the SEA notification
flag so non-ACPI platforms can describe their error sources.

Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>
---
 .../devicetree/bindings/ras/arm,ras-ffh.yaml  | 95 +++++++++++++++++++
 MAINTAINERS                                   |  1 +
 2 files changed, 96 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/ras/arm,ras-ffh.yaml

diff --git a/Documentation/devicetree/bindings/ras/arm,ras-ffh.yaml b/Documentation/devicetree/bindings/ras/arm,ras-ffh.yaml
new file mode 100644
index 000000000000..0d2acbf8e8a8
--- /dev/null
+++ b/Documentation/devicetree/bindings/ras/arm,ras-ffh.yaml
@@ -0,0 +1,95 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/ras/arm,ras-ffh.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Arm Firmware-First Handler (FFH) CPER provider
+
+maintainers:
+  - Ahmed Tiba <ahmed.tiba at arm.com>
+
+description: |
+  Some Arm platforms describe a firmware-first error handler that exposes a
+  Common Platform Error Record (CPER) buffer directly via DeviceTree. The OS
+  maps the buffer to consume the error records, and firmware signals that a new
+  record is ready either by asserting an interrupt or by relying on a periodic
+  poll. This binding describes the buffer and the associated notification
+  signal. If firmware delivers the error via Synchronous External Abort (SEA),
+  the optional sea-notify flag marks the source accordingly.
+
+properties:
+  compatible:
+    const: arm,ras-ffh
+
+  reg:
+    minItems: 1
+    items:
+      - description: CPER status block exposed by firmware
+      - description:
+          Optional 32- or 64-bit acknowledgment register. Firmware watches this
+          register and expects bit 0 to be written to 1 once the OS consumes the
+          status buffer so it can reuse the record.
+
+  reg-names:
+    items:
+      - const: status
+      - const: ack
+
+  interrupts:
+    maxItems: 1
+    description:
+      Optional interrupt used to signal that a new status record is ready. If
+      omitted, the OS relies on the polling interval property.
+
+  poll-interval:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 1
+    description:
+      Optional polling interval, in milliseconds, for platforms that cannot
+      route an interrupt.
+
+  arm,sea-notify:
+    type: boolean
+    description:
+      Set if the platform delivers these errors as Synchronous External Aborts.
+
+required:
+  - compatible
+  - reg
+
+allOf:
+  - if:
+      properties:
+        poll-interval: false
+    then:
+      required:
+        - interrupts
+  - if:
+      properties:
+        interrupts: false
+    then:
+      required:
+        - poll-interval
+  - if:
+      properties:
+        reg:
+          minItems: 2
+    then:
+      required:
+        - reg-names
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    ras-ffh at fe800000 {
+        compatible = "arm,ras-ffh";
+        reg = <0xfe800000 0x1000>,
+              <0xfe810000 0x4>;
+        reg-names = "status", "ack";
+        interrupts = <0 32 IRQ_TYPE_LEVEL_HIGH>;
+    };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 67d79d4e612d..6b2ef2ddc0c7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -21760,6 +21760,7 @@ F:	drivers/rapidio/
 RAS ERROR STATUS
 M:	Ahmed Tiba <ahmed.tiba at arm.com>
 S:	Maintained
+F:	Documentation/devicetree/bindings/ras/arm,ras-ffh.yaml
 F:	drivers/firmware/efi/estatus.c
 F:	include/linux/estatus.h
 
-- 
2.43.0



From ahmed.tiba at arm.com  Wed Dec 17 03:28:44 2025
From: ahmed.tiba at arm.com (Ahmed Tiba)
Date: Wed, 17 Dec 2025 11:28:44 +0000
Subject: [PATCH 11/12] ras: add DeviceTree estatus provider driver
In-Reply-To: <20251217112845.1814119-1-ahmed.tiba@arm.com>
References: <20251217112845.1814119-1-ahmed.tiba@arm.com>
Message-ID: <20251217112845.1814119-12-ahmed.tiba@arm.com>

Introduce a platform driver that maps the CPER status block described
in DeviceTree, feeds it into the estatus core and handles either IRQ- or
poll-driven notifications. Arm64 gains a FIX_ESTATUS_IRQ slot so the
driver can safely map the shared buffer while copying records.

Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>
---
 MAINTAINERS                     |   1 +
 arch/arm64/include/asm/fixmap.h |   5 +
 drivers/ras/Kconfig             |  14 ++
 drivers/ras/Makefile            |   1 +
 drivers/ras/estatus-dt.c        | 318 ++++++++++++++++++++++++++++++++
 include/linux/estatus.h         |   3 +-
 6 files changed, 341 insertions(+), 1 deletion(-)
 create mode 100644 drivers/ras/estatus-dt.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 6b2ef2ddc0c7..5567d5e82053 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -21761,6 +21761,7 @@ RAS ERROR STATUS
 M:	Ahmed Tiba <ahmed.tiba at arm.com>
 S:	Maintained
 F:	Documentation/devicetree/bindings/ras/arm,ras-ffh.yaml
+F:	drivers/ras/estatus-dt.c
 F:	drivers/firmware/efi/estatus.c
 F:	include/linux/estatus.h
 
diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h
index 65555284446e..85ffba87bab9 100644
--- a/arch/arm64/include/asm/fixmap.h
+++ b/arch/arm64/include/asm/fixmap.h
@@ -64,6 +64,11 @@ enum fixed_addresses {
 #endif
 #endif /* CONFIG_ACPI_APEI_GHES */
 
+#ifdef CONFIG_RAS_ESTATUS_DT
+	/* Used for ESTATUS mapping from assorted contexts */
+	FIX_ESTATUS_IRQ,
+#endif /* CONFIG_RAS_ESTATUS_DT */
+
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
 #ifdef CONFIG_RELOCATABLE
 	FIX_ENTRY_TRAMP_TEXT4,	/* one extra slot for the data page */
diff --git a/drivers/ras/Kconfig b/drivers/ras/Kconfig
index fc4f4bb94a4c..0f8c0d3c26db 100644
--- a/drivers/ras/Kconfig
+++ b/drivers/ras/Kconfig
@@ -34,6 +34,20 @@ if RAS
 source "arch/x86/ras/Kconfig"
 source "drivers/ras/amd/atl/Kconfig"
 
+config RAS_ESTATUS_DT
+	tristate "DeviceTree estatus provider"
+	depends on ARM64
+	depends on OF && HAS_IOMEM
+	select UEFI_CPER
+	select RAS_ESTATUS_CORE
+	help
+	  Enable support for firmware-first CPER providers that are described
+	  via DeviceTree.  The driver maps the firmware-provided CPER buffer
+	  and consumes records when firmware signals that new data is ready,
+	  either with an interrupt or via polling.  Select this when running on
+	  platforms that expose firmware-first error records without
+	  ACPI/APEI GHES.
+
 config RAS_FMPM
 	tristate "FRU Memory Poison Manager"
 	default m
diff --git a/drivers/ras/Makefile b/drivers/ras/Makefile
index 11f95d59d397..726455bcf950 100644
--- a/drivers/ras/Makefile
+++ b/drivers/ras/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_RAS_CEC)	+= cec.o
 
 obj-$(CONFIG_RAS_FMPM)	+= amd/fmpm.o
 obj-y			+= amd/atl/
+obj-$(CONFIG_RAS_ESTATUS_DT)	+= estatus-dt.o
diff --git a/drivers/ras/estatus-dt.c b/drivers/ras/estatus-dt.c
new file mode 100644
index 000000000000..75c85c404cb6
--- /dev/null
+++ b/drivers/ras/estatus-dt.c
@@ -0,0 +1,318 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * DeviceTree provider for firmware-first estatus error records
+ *
+ * Copyright (C) 2025 ARM Ltd.
+ * Author: Ahmed Tiba <ahmed.tiba at arm.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+
+#include <linux/estatus.h>
+#include <asm/fixmap.h>
+
+struct estatus_dt_ack {
+	void __iomem *addr;
+	u64 preserve;
+	u64 set;
+	u8 width;
+	bool present;
+};
+
+struct estatus_dt {
+	struct device *dev;
+	void __iomem *base;
+	phys_addr_t phys;
+	size_t block_size;
+
+	struct estatus_dt_ack ack;
+
+	struct estatus_source source;
+	int irq;
+
+	struct timer_list poll_timer;
+	u32 poll_interval_ms;
+	bool polling;
+
+	bool sea_notify;
+};
+
+static int estatus_dt_get_phys(struct estatus_source *source, phys_addr_t *addr)
+{
+	struct estatus_dt *ctx = source->priv;
+
+	*addr = ctx->phys;
+	return 0;
+}
+
+static int estatus_dt_read(struct estatus_source *source, phys_addr_t addr,
+			   void *buf, size_t len,
+			   enum fixed_addresses fixmap_idx)
+{
+	struct estatus_dt *ctx = source->priv;
+
+	(void)addr;
+	(void)fixmap_idx;
+
+	if (WARN_ON(len > ctx->block_size))
+		len = ctx->block_size;
+
+	memcpy_fromio(buf, ctx->base, len);
+
+	return 0;
+}
+
+static int estatus_dt_write(struct estatus_source *source, phys_addr_t addr,
+			    const void *buf, size_t len,
+			    enum fixed_addresses fixmap_idx)
+{
+	struct estatus_dt *ctx = source->priv;
+
+	(void)addr;
+	(void)fixmap_idx;
+
+	if (WARN_ON(len > ctx->block_size))
+		len = ctx->block_size;
+
+	memcpy_toio(ctx->base, buf, len);
+
+	return 0;
+}
+
+static void estatus_dt_ack(struct estatus_source *source)
+{
+	struct estatus_dt *ctx = source->priv;
+	u64 val;
+
+	if (!ctx->ack.present)
+		return;
+
+	if (ctx->ack.width == 64) {
+		val = readq(ctx->ack.addr);
+		val &= ctx->ack.preserve;
+		val |= ctx->ack.set;
+		writeq(val, ctx->ack.addr);
+	} else {
+		val = readl(ctx->ack.addr);
+		val &= (u32)ctx->ack.preserve;
+		val |= (u32)ctx->ack.set;
+		writel(val, ctx->ack.addr);
+	}
+}
+
+static size_t estatus_dt_get_max_len(struct estatus_source *source)
+{
+	struct estatus_dt *ctx = source->priv;
+
+	return ctx->block_size;
+}
+
+static enum estatus_notify_mode
+estatus_dt_get_notify_mode(struct estatus_source *source)
+{
+	struct estatus_dt *ctx = source->priv;
+
+	if (ctx->sea_notify)
+		return ESTATUS_NOTIFY_SEA;
+
+	return ESTATUS_NOTIFY_ASYNC;
+}
+
+static const char *estatus_dt_get_name(struct estatus_source *source)
+{
+	struct estatus_dt *ctx = source->priv;
+
+	return dev_name(ctx->dev);
+}
+
+static const struct estatus_ops estatus_dt_ops = {
+	.get_phys	= estatus_dt_get_phys,
+	.read		= estatus_dt_read,
+	.write		= estatus_dt_write,
+	.ack		= estatus_dt_ack,
+	.get_max_len	= estatus_dt_get_max_len,
+	.get_notify_mode = estatus_dt_get_notify_mode,
+	.get_name	= estatus_dt_get_name,
+};
+
+static irqreturn_t estatus_dt_irq(int irq, void *data)
+{
+	struct estatus_dt *ctx = data;
+
+	if (estatus_proc(&ctx->source))
+		return IRQ_NONE;
+
+	return IRQ_HANDLED;
+}
+
+static void estatus_dt_poll(struct timer_list *t)
+{
+	struct estatus_dt *ctx = timer_container_of(ctx, t, poll_timer);
+
+	estatus_proc(&ctx->source);
+	mod_timer(&ctx->poll_timer,
+		  jiffies + msecs_to_jiffies(ctx->poll_interval_ms));
+}
+
+static int estatus_dt_init_ack(struct platform_device *pdev,
+			       struct estatus_dt *ctx)
+{
+	struct resource *res;
+	u64 preserve;
+	size_t size;
+	u32 width;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ack");
+	if (!res)
+		return 0;
+
+	ctx->ack.addr = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(ctx->ack.addr))
+		return PTR_ERR(ctx->ack.addr);
+
+	size = resource_size(res);
+	if (size == 4)
+		width = 32;
+	else if (size == 8)
+		width = 64;
+	else {
+		dev_err(&pdev->dev, "Unsupported ack resource size %zu\n", size);
+		return -EINVAL;
+	}
+	ctx->ack.width = width;
+
+	preserve = width == 64 ? ~0ULL : ~0U;
+	ctx->ack.preserve = preserve;
+	ctx->ack.set = BIT_ULL(0);
+
+	ctx->ack.present = true;
+
+	return 0;
+}
+
+static int estatus_dt_probe(struct platform_device *pdev)
+{
+	struct estatus_dt *ctx;
+	struct resource *res;
+	size_t block_size;
+	int rc;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -EINVAL;
+
+	block_size = resource_size(res);
+	if (!block_size) {
+		dev_err(&pdev->dev, "Status block region has zero size\n");
+		return -EINVAL;
+	}
+
+	rc = estatus_pool_init(1);
+	if (rc)
+		return rc;
+
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ctx->dev = &pdev->dev;
+	ctx->sea_notify = of_property_read_bool(pdev->dev.of_node,
+						"arm,sea-notify");
+	ctx->poll_interval_ms = 0;
+	of_property_read_u32(pdev->dev.of_node,
+			     "poll-interval", &ctx->poll_interval_ms);
+	if (ctx->poll_interval_ms)
+		ctx->polling = true;
+
+	ctx->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(ctx->base))
+		return PTR_ERR(ctx->base);
+
+	ctx->phys = res->start;
+	ctx->block_size = block_size;
+
+	ctx->source.ops = &estatus_dt_ops;
+	ctx->source.priv = ctx;
+	ctx->source.estatus = devm_kzalloc(&pdev->dev, block_size, GFP_KERNEL);
+	if (!ctx->source.estatus)
+		return -ENOMEM;
+	ctx->source.fixmap_idx = FIX_ESTATUS_IRQ;
+
+	rc = estatus_dt_init_ack(pdev, ctx);
+	if (rc)
+		return rc;
+
+	ctx->irq = platform_get_irq_optional(pdev, 0);
+	if (ctx->irq < 0) {
+		if (ctx->irq != -ENXIO && ctx->irq != -EINVAL)
+			return ctx->irq;
+		ctx->irq = 0;
+	}
+
+	if (ctx->irq > 0) {
+		rc = devm_request_threaded_irq(&pdev->dev, ctx->irq,
+					       NULL, estatus_dt_irq,
+					       IRQF_ONESHOT,
+					       dev_name(&pdev->dev), ctx);
+		if (rc)
+			return rc;
+	}
+
+	if (!ctx->polling && ctx->irq <= 0) {
+		dev_err(&pdev->dev,
+			"Either poll-interval or an interrupt is required\n");
+		return -EINVAL;
+	}
+
+	if (ctx->polling) {
+		timer_setup(&ctx->poll_timer, estatus_dt_poll, 0);
+		mod_timer(&ctx->poll_timer,
+			  jiffies + msecs_to_jiffies(ctx->poll_interval_ms));
+	}
+
+	platform_set_drvdata(pdev, ctx);
+
+	dev_info(&pdev->dev, "Registered estatus provider (%s)\n",
+		 ctx->polling ? "polling" : "interrupt");
+
+	return 0;
+}
+
+static void estatus_dt_remove(struct platform_device *pdev)
+{
+	struct estatus_dt *ctx = platform_get_drvdata(pdev);
+
+	if (ctx->polling)
+		timer_delete_sync(&ctx->poll_timer);
+}
+
+static const struct of_device_id estatus_dt_of_match[] = {
+	{ .compatible = "arm,ras-ffh", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, estatus_dt_of_match);
+
+static struct platform_driver estatus_dt_driver = {
+	.probe = estatus_dt_probe,
+	.remove = estatus_dt_remove,
+	.driver = {
+		.name = "estatus-dt",
+		.of_match_table = estatus_dt_of_match,
+	},
+};
+
+module_platform_driver(estatus_dt_driver);
+
+MODULE_AUTHOR("Ahmed Tiba <ahmed.tiba at arm.com>");
+MODULE_DESCRIPTION("DeviceTree estatus provider");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/estatus.h b/include/linux/estatus.h
index 506a74ad60b9..2478f54b62e4 100644
--- a/include/linux/estatus.h
+++ b/include/linux/estatus.h
@@ -227,7 +227,8 @@ estatus_section_iter_next(struct estatus_section_iter *iter,
 
 #define estatus_for_each_section(_estatus, _section)				\
 	for (struct estatus_section_iter __estatus_iter = {0};		\
-	     ((_section) = estatus_section_iter_next(&__estatus_iter, (_estatus))); \
+	     ((_section) = estatus_section_iter_next(&__estatus_iter,		\
+				    (estatus_generic_status *)(_estatus)));	\
 	     )
 
 static inline int acpi_hest_get_version(struct acpi_hest_generic_data *gdata)
-- 
2.43.0



From ahmed.tiba at arm.com  Wed Dec 17 03:28:45 2025
From: ahmed.tiba at arm.com (Ahmed Tiba)
Date: Wed, 17 Dec 2025 11:28:45 +0000
Subject: [PATCH 12/12] doc: ras: describe firmware-first estatus flow
In-Reply-To: <20251217112845.1814119-1-ahmed.tiba@arm.com>
References: <20251217112845.1814119-1-ahmed.tiba@arm.com>
Message-ID: <20251217112845.1814119-13-ahmed.tiba@arm.com>

Add a short section to the RAS admin guide that explains how the new
estatus core and DeviceTree provider are enabled, and point readers to
the binding that describes the firmware-first CPER layout.

Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>
---
 Documentation/admin-guide/RAS/main.rst | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/Documentation/admin-guide/RAS/main.rst b/Documentation/admin-guide/RAS/main.rst
index 5a45db32c49b..adff8b4bc84b 100644
--- a/Documentation/admin-guide/RAS/main.rst
+++ b/Documentation/admin-guide/RAS/main.rst
@@ -205,6 +205,30 @@ Architecture (MCA)\ [#f3]_.
 .. [#f3] For more details about the Machine Check Architecture (MCA),
   please read Documentation/arch/x86/x86_64/machinecheck.rst at the Kernel tree.
 
+Firmware-first CPER status providers
+------------------------------------
+
+Some systems expose Common Platform Error Record (CPER) data via firmware
+interfaces instead of relying on CPU machine-check banks. The kernel routes
+those records through the shared *estatus* core:
+
+* ``CONFIG_RAS_ESTATUS_CORE`` hosts the in-kernel data movers and notifiers.
+  It is selected automatically when ACPI/APEI GHES support is enabled or when
+  the DeviceTree provider below is built.
+* ``CONFIG_RAS_ESTATUS_DT`` adds the ``drivers/ras/estatus-dt.c`` provider that
+  maps a firmware-advertised CPER status block on non-ACPI platforms. The
+  DeviceTree binding is documented in
+  ``Documentation/devicetree/bindings/ras/arm,ras-ffh.yaml`` and describes the
+  status-buffer region and the notification signal (interrupt or polling) that
+  firmware uses to advertise new records.
+
+Once a platform describes a firmware-first provider, both ACPI GHES and the
+DeviceTree driver reuse the same code paths: CPER sections are iterated with
+``estatus_for_each_section()``, logged through ``cper_estatus_print()``, and
+handed to the RAS notifier chains that trigger memory-offline, PCIe AER, or
+vendor-specific handlers. This keeps the behaviour consistent regardless of
+whether the error source is described via ACPI tables or DeviceTree.
+
 EDAC - Error Detection And Correction
 *************************************
 
-- 
2.43.0



From maz at kernel.org  Wed Dec 17 03:40:31 2025
From: maz at kernel.org (Marc Zyngier)
Date: Wed, 17 Dec 2025 11:40:31 +0000
Subject: [PATCH 15/32] KVM: arm64: gic-v5: Implement direct injection of PPIs
In-Reply-To: <20251212152215.675767-16-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	<20251212152215.675767-16-sascha.bischoff@arm.com>
Message-ID: <861pktnxow.wl-maz@kernel.org>

On Fri, 12 Dec 2025 15:22:40 +0000,
Sascha Bischoff <Sascha.Bischoff at arm.com> wrote:
> 
> GICv5 is able to directly inject PPI pending state into a guest using
> a mechanism called DVI whereby the pending bit for a paticular PPI is
> driven directly by the physically-connected hardware. This mechanism
> itself doesn't allow for any ID translation, so the host interrupt is
> directly mapped into a guest with the same interrupt ID.
> 
> When mapping a virtual interrupt to a physical interrupt via
> kvm_vgic_map_irq for a GICv5 guest, check if the interrupt itself is a
> PPI or not. If it is, and the host's interrupt ID matches that used
> for the guest DVI is enabled, and the interrupt itself is marked as
> directly_injected.
> 
> When the interrupt is unmapped again, this process is reversed, and
> DVI is disabled for the interrupt again.
> 
> Note: the expectation is that a directly injected PPI is disabled on
> the host while the guest state is loaded. The reason is that although
> DVI is enabled to drive the guest's pending state directly, the host
> pending state also remains driven. In order to avoid the same PPI
> firing on both the host and the guest, the host's interrupt must be
> disabled (masked). This is left up to the code that owns the device
> generating the PPI as this needs to be handled on a per-VM basis. One
> VM might use DVI, while another might not, in which case the physical
> PPI should be enabled for the latter.
> 
> Co-authored-by: Timothy Hayes <timothy.hayes at arm.com>
> Signed-off-by: Timothy Hayes <timothy.hayes at arm.com>
> Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
> ---
>  arch/arm64/kvm/vgic/vgic-v5.c | 22 ++++++++++++++++++++++
>  arch/arm64/kvm/vgic/vgic.c    | 16 ++++++++++++++++
>  arch/arm64/kvm/vgic/vgic.h    |  1 +
>  include/kvm/arm_vgic.h        |  1 +
>  4 files changed, 40 insertions(+)
> 
> diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
> index 2fb2db23ed39a..22558080711eb 100644
> --- a/arch/arm64/kvm/vgic/vgic-v5.c
> +++ b/arch/arm64/kvm/vgic/vgic-v5.c
> @@ -54,6 +54,28 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
>  	return 0;
>  }
>  
> +/*
> + * Sets/clears the corresponding bit in the ICH_PPI_DVIR register.
> + */
> +int vgic_v5_set_ppi_dvi(struct kvm_vcpu *vcpu, u32 irq, bool dvi)
> +{
> +	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> +	u32 ppi = FIELD_GET(GICV5_HWIRQ_ID, irq);
> +
> +	if (ppi >= 128)
> +		return -EINVAL;

Surely this is bad. *very* bad. How can we get here the first place?

> +
> +	if (dvi) {
> +		/* Set the bit */
> +		cpu_if->vgic_ppi_dvir[ppi / 64] |= 1UL << (ppi % 64);
> +	} else {
> +		/* Clear the bit */
> +		cpu_if->vgic_ppi_dvir[ppi / 64] &= ~(1UL << (ppi % 64));
> +	}

This should be simplified:

diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index d74cc3543b9a4..f434ee85f7e1a 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -191,8 +191,8 @@ bool vgic_v5_ppi_set_pending_state(struct kvm_vcpu *vcpu,
 				   struct vgic_irq *irq)
 {
 	struct vgic_v5_cpu_if *cpu_if;
-	const u32 id_bit = BIT_ULL(irq->intid % 64);
 	const u32 reg = FIELD_GET(GICV5_HWIRQ_ID, irq->intid) / 64;
+	unsigned long *p;
 
 	if (!vcpu || !irq)
 		return false;
@@ -203,10 +203,8 @@ bool vgic_v5_ppi_set_pending_state(struct kvm_vcpu *vcpu,
 
 	cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
 
-	if (irq_is_pending(irq))
-		cpu_if->vgic_ppi_pendr[reg] |= id_bit;
-	else
-		cpu_if->vgic_ppi_pendr[reg] &= ~id_bit;
+	p = (unsigned long *)&cpu_if->vgic_ppi_pendr[reg];
+	__assign_bit(irq->intid % 64, p, irq_is_pending(irq));
 
 	return true;
 }
@@ -449,17 +447,13 @@ int vgic_v5_set_ppi_dvi(struct kvm_vcpu *vcpu, u32 irq, bool dvi)
 {
 	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
 	u32 ppi = FIELD_GET(GICV5_HWIRQ_ID, irq);
+	unsigned long *p;
 
 	if (ppi >= 128)
 		return -EINVAL;
 
-	if (dvi) {
-		/* Set the bit */
-		cpu_if->vgic_ppi_dvir[ppi / 64] |= 1UL << (ppi % 64);
-	} else {
-		/* Clear the bit */
-		cpu_if->vgic_ppi_dvir[ppi / 64] &= ~(1UL << (ppi % 64));
-	}
+	p = (unsigned long *)&cpu_if->vgic_ppi_dvir[ppi / 64];
+	__assign_bit(ppi % 64, p, dvi);
 
 	return 0;
 }

(yes, unsigned long and u64 are the same thing on any sane
architecture).

> +
> +	return 0;
> +}
> +
>  void vgic_v5_load(struct kvm_vcpu *vcpu)
>  {
>  	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
> index 1005ff5f36235..1fe3dcc997860 100644
> --- a/arch/arm64/kvm/vgic/vgic.c
> +++ b/arch/arm64/kvm/vgic/vgic.c
> @@ -577,12 +577,28 @@ static int kvm_vgic_map_irq(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
>  	irq->host_irq = host_irq;
>  	irq->hwintid = data->hwirq;
>  	irq->ops = ops;
> +
> +	if (vgic_is_v5(vcpu->kvm)) {
> +		/* Nothing for us to do */
> +		if (!irq_is_ppi_v5(irq->intid))
> +			return 0;
> +
> +		if (FIELD_GET(GICV5_HWIRQ_ID, irq->intid) == irq->hwintid) {
> +			if (!vgic_v5_set_ppi_dvi(vcpu, irq->hwintid, true))
> +				irq->directly_injected = true;

The error handling gives me the creeps. If we can end-up at this stage
with the wrong INTID, we're screwed.

> +		}
> +	}
> +
>  	return 0;
>  }
>  
>  /* @irq->irq_lock must be held */
>  static inline void kvm_vgic_unmap_irq(struct vgic_irq *irq)
>  {
> +	if (irq->directly_injected && vgic_is_v5(irq->target_vcpu->kvm))
> +		WARN_ON(vgic_v5_set_ppi_dvi(irq->target_vcpu, irq->hwintid, false));
> +
> +	irq->directly_injected = false;
>  	irq->hw = false;
>  	irq->hwintid = 0;
>  	irq->ops = NULL;
> diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
> index 6e1f386dffade..b6e3f5e3aba18 100644
> --- a/arch/arm64/kvm/vgic/vgic.h
> +++ b/arch/arm64/kvm/vgic/vgic.h
> @@ -363,6 +363,7 @@ void vgic_debug_init(struct kvm *kvm);
>  void vgic_debug_destroy(struct kvm *kvm);
>  
>  int vgic_v5_probe(const struct gic_kvm_info *info);
> +int vgic_v5_set_ppi_dvi(struct kvm_vcpu *vcpu, u32 irq, bool dvi);
>  void vgic_v5_load(struct kvm_vcpu *vcpu);
>  void vgic_v5_put(struct kvm_vcpu *vcpu);
>  void vgic_v5_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 45d83f45b065d..ce9e149b85a58 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -163,6 +163,7 @@ struct vgic_irq {
>  	bool enabled:1;
>  	bool active:1;
>  	bool hw:1;			/* Tied to HW IRQ */
> +	bool directly_injected:1;	/* A directly injected HW IRQ */
>  	bool on_lr:1;			/* Present in a CPU LR */
>  	refcount_t refcount;		/* Used for LPIs */
>  	u32 hwintid;			/* HW INTID number */

Thanks,

	M.

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


From a06-help at 20252027frontrepublicain.site  Wed Dec 17 03:40:00 2025
From: a06-help at 20252027frontrepublicain.site (a06-help at 20252027frontrepublicain.site)
Date: 17 Dec 2025 11:40:00 -0000
Subject: ezmlm warning
Message-ID: <1765971600.26811.ezmlm-warn@20252027frontrepublicain.site>

Bonjour ! Je suis le programme ezmlm. Je m'occupe de la liste
de diffusion a06 at 20252027frontrepublicain.site.

Un certain nombre de messages provenant de la liste de diffusion
a06 n'ont pas pu vous etre remis correctement. En attachement, vous trouverez
une copie du premier message de retour a l'envoyeur que j'ai recu.

Si le message que vous lisez actuellement ne parvient pas non plus a
destination, un dernier message vous sera envoye. Si celui-ci echoue aussi,
votre adresse sera malheureusement retiree de la liste a06.

J'ai conserve une liste des messages de la liste de diffusion a06 qui
n'ont temporairement pas pu etre delivres a votre adresse.

Voici les numeros des messages en question :
   1
   2

--- Ci-dessous se trouve une copie du message problematique qui m'est revenu :
Return-Path: <>
Received: from localhost (HELO queue) (127.0.0.1)
	by localhost with SMTP; 4 Dec 2025 12:07:21 +0200
Received: from unknown (HELO output52.mail.ovh.net) (192.168.13.188)
  by 192.168.9.18 with AES256-GCM-SHA384 encrypted SMTP; 4 Dec 2025 12:07:21 +0200
Received: from vr39.mail.ovh.net (unknown [10.101.8.39])
	by out52.mail.ovh.net (Postfix) with ESMTP id 4dMVYP0Mr1zBrS7
	for <a06-return-1-linux-arm-kernel=lists.infradead.org at 20252027frontrepublicain.site>; Thu,  4 Dec 2025 10:07:21 +0000 (UTC)
Received: from in59.mail.ovh.net (unknown [10.101.4.59])
	by vr39.mail.ovh.net (Postfix) with ESMTP id 4dMVYN6ffqz1N7QM
	for <a06-return-1-linux-arm-kernel=lists.infradead.org at 20252027frontrepublicain.site>; Thu,  4 Dec 2025 10:07:20 +0000 (UTC)
Received: from 4.mo594.mail-out.ovh.net (4.mo594.mail-out.ovh.net [178.33.252.92])
	by in59.mail.ovh.net (Postfix) with ESMTPS id 4dMVYN5m4jz3fjgh
	for <a06-return-1-linux-arm-kernel=lists.infradead.org at 20252027frontrepublicain.site>; Thu,  4 Dec 2025 10:07:20 +0000 (UTC)
Authentication-Results: mx.mail.ovh.net;
    arc=none (no signatures found);
    dkim=none (no signatures found);
    dmarc=fail policy.published-domain-policy=none policy.applied-disposition=none policy.evaluated-disposition=none (p=none,d=none,d.eval=none) policy.policy-from=p header.from=mo594.mail-out.ovh.net;
    spf=none smtp.mailfrom="" smtp.helo=4.mo594.mail-out.ovh.net;
    x-tls=pass smtp.version=TLSv1.3 smtp.cipher=TLS_AES_256_GCM_SHA384 smtp.bits=256
Received-SPF: none
    (4.mo594.mail-out.ovh.net: No applicable sender policy available)
    receiver=in59.mail.ovh.net;
    identity=helo;
    helo=4.mo594.mail-out.ovh.net;
    client-ip=178.33.252.92
Received: by mo594.mail-out.ovh.net (Postfix)
	id 4dMVYN4nrZz3xfD; Thu,  4 Dec 2025 10:07:20 +0000 (UTC)
Date: Thu,  4 Dec 2025 10:07:20 +0000 (UTC)
From: Mail Delivery System <MAILER-DAEMON at mo594.mail-out.ovh.net>
Subject: Undelivered Mail Returned to Sender
To: a06-return-1-linux-arm-kernel=lists.infradead.org at 20252027frontrepublicain.site
Auto-Submitted: auto-replied
MIME-Version: 1.0
Content-Type: multipart/report; report-type=delivery-status;
	boundary="4dMVY307Hpz3wpC.1764842840/mo594.mail-out.ovh.net"
Message-Id: <4dMVYN4nrZz3xfD at mo594.mail-out.ovh.net>
X-OVH-Remote: 178.33.252.92 (4.mo594.mail-out.ovh.net)
X-Ovh-Tracer-Id: 6726126047121343819
X-VR-SPAMSTATE: BOUNCE
X-VR-SPAMSCORE: 10000
X-VR-SPAMCAUSE:  
X-Ovh-Spam-Status: OK
X-Ovh-Spam-Reason: vr: BOUNCE; dkim: disabled; spf: disabled
X-Ovh-Message-Type: BOUNCE

This is a MIME-encapsulated message.

--4dMVY307Hpz3wpC.1764842840/mo594.mail-out.ovh.net
Content-Description: Notification
Content-Type: text/plain; charset=us-ascii

This is the mail system at host mo594.mail-out.ovh.net.

I'm sorry to have to inform you that your message could not
be delivered to one or more recipients. It's attached below.

For further assistance, please send mail to postmaster.

If you do so, please include this problem report. You can
delete your own text from the attached returned message.

                   The mail system

<linux-arm-kernel at lists.infradead.org>: host
    bombadil.infradead.org[198.137.202.133] said: 550-Mailing lists do not
    accept HTML mail. See 550 http://david.woodhou.se/email.html (in reply to
    end of DATA command)

--4dMVY307Hpz3wpC.1764842840/mo594.mail-out.ovh.net
Content-Description: Delivery report
Content-Type: message/delivery-status

Reporting-MTA: dns; mo594.mail-out.ovh.net
X-Postfix-Queue-ID: 4dMVY307Hpz3wpC
X-Postfix-Sender: rfc822; a06-return-1-linux-arm-kernel=lists.infradead.org at 20252027frontrepublicain.site
Arrival-Date: Thu,  4 Dec 2025 10:07:02 +0000 (UTC)

Final-Recipient: rfc822; linux-arm-kernel at lists.infradead.org
Original-Recipient: rfc822;linux-arm-kernel at lists.infradead.org
Action: failed
Status: 5.0.0
Remote-MTA: dns; bombadil.infradead.org
Diagnostic-Code: smtp; 550-Mailing lists do not accept HTML mail. See 550
    http://david.woodhou.se/email.html

--4dMVY307Hpz3wpC.1764842840/mo594.mail-out.ovh.net
Content-Description: Undelivered Message Headers
Content-Type: text/rfc822-headers

Return-Path: <a06-return-1-linux-arm-kernel=lists.infradead.org at 20252027frontrepublicain.site>
Received: from mx1.ovh.net (unknown [10.110.113.114])
	by mo594.mail-out.ovh.net (Postfix) with SMTP id 4dMVY307Hpz3wpC
	for <linux-arm-kernel at lists.infradead.org>; Thu,  4 Dec 2025 10:07:02 +0000 (UTC)
Received: from localhost (HELO queueml) (127.0.0.1)
	by localhost with SMTP; 4 Dec 2025 11:58:37 +0200
Mailing-List: contact a06-help at 20252027frontrepublicain.site; run by ezmlm
Precedence: bulk
X-No-Archive: yes
List-Post: <mailto:a06 at 20252027frontrepublicain.site>
List-Help: <mailto:a06-help at 20252027frontrepublicain.site>
List-Unsubscribe: <mailto:a06-unsubscribe at 20252027frontrepublicain.site>
List-Subscribe: <mailto:a06-subscribe at 20252027frontrepublicain.site>
Reply-To: test at 20252027frontrepublicain.site
Delivered-To: mailing list a06 at 20252027frontrepublicain.site
Delivered-To: moderator for a06 at 20252027frontrepublicain.site
Received: from localhost (HELO queue) (127.0.0.1)
	by localhost with SMTP; 3 Dec 2025 16:13:39 +0200
Received: from unknown (HELO output43.mail.ovh.net) (192.168.13.173)
  by 192.168.9.18 with AES256-GCM-SHA384 encrypted SMTP; 3 Dec 2025 16:13:39 +0200
Received: from vr23.mail.ovh.net (unknown [10.101.8.23])
	by out43.mail.ovh.net (Postfix) with ESMTP id 4dM0431YlPz2cMZF
	for <a06 at 20252027frontrepublicain.site>; Wed,  3 Dec 2025 14:13:39 +0000 (UTC)
Received: from in54.mail.ovh.net (unknown [10.101.4.54])
	by vr23.mail.ovh.net (Postfix) with ESMTP id 4dM04260tbztQbb
	for <a06 at 20252027frontrepublicain.site>; Wed,  3 Dec 2025 14:13:38 +0000 (UTC)
Received: from mail-pl1-f170.google.com (mail-pl1-f170.google.com [209.85.214.170])
	by in54.mail.ovh.net (Postfix) with ESMTPS id 4dM041322Qz2pFPl
	for <a06 at 20252027frontrepublicain.site>; Wed,  3 Dec 2025 14:13:37 +0000 (UTC)
Authentication-Results: mx.mail.ovh.net;
    arc=none (no signatures found);
    dkim=pass (2048-bit rsa key sha256) header.d=front-republicain-info.20230601.gappssmtp.com header.i=@front-republicain-info.20230601.gappssmtp.com header.b=M1IgvPom header.a=rsa-sha256 header.s=20230601;
    dmarc=none policy.published-domain-policy=none policy.applied-disposition=none policy.evaluated-disposition=none (p=none,d=none,d.eval=none) policy.policy-from=p header.from=front-republicain.info;
    spf=fail smtp.mailfrom=president at front-republicain.info smtp.helo=mail-pl1-f170.google.com;
    x-tls=pass smtp.version=TLSv1.3 smtp.cipher=TLS_AES_256_GCM_SHA384 smtp.bits=256
Received-SPF: fail
    (front-republicain.info: Sender is not authorized by default to use 'president at front-republicain.info' in 'mfrom' identity (mechanism '-all' matched))
    receiver=in54.mail.ovh.net;
    identity=mailfrom;
    envelope-from="president at front-republicain.info";
    helo=mail-pl1-f170.google.com;
    client-ip=209.85.214.170
Received: by mail-pl1-f170.google.com with SMTP id d9443c01a7336-2955623e6faso75958165ad.1
        for <a06 at 20252027frontrepublicain.site>; Wed, 03 Dec 2025 06:13:37 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=front-republicain-info.20230601.gappssmtp.com; s=20230601; t=1764771216; x=1765376016; darn=20252027frontrepublicain.site;
        h=to:subject:message-id:date:from:in-reply-to:references:mime-version
         :from:to:cc:subject:date:message-id:reply-to;
        bh=SZ7aZ9wD9cvgcu+Oy5QihJ9y566Bnppw39eAHA6L4Q0=;
        b=M1IgvPomwBEeVyyGNYT1zPcXINGmjvb8P2I1OP7lSIlfFce4asqHeXcMkOrBXaA8oO
         6QABEPUMfZGqvWdGikr3ji/epWQPpzlv188IgkYyzT0oEoHc6pqE3+5aBOjmgar93XHf
         35kYZKoCeeWKNmOxRYoGg0DtF3TO1Qvw2E3nFBaCgPqxEA+MgP+NOYTcPV7mT+CWiqP/
         bKrX5tJI5wszlB8kmnmjiNdsYMOodhv70BFn5twwoHfEWttEbh3bzr8q/BCECx9npNPQ
         7y+ZJNrTjSdrGEIy/MgG28tpK3l8UtLVbxs1fXifCXqayrkIr5PAKJnXAV3lnrsan0G9
         Caow==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20230601; t=1764771216; x=1765376016;
        h=to:subject:message-id:date:from:in-reply-to:references:mime-version
         :x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id
         :reply-to;
        bh=SZ7aZ9wD9cvgcu+Oy5QihJ9y566Bnppw39eAHA6L4Q0=;
        b=dXv5HxI8o59vw99ViWS5ja2SNizJ72OCOw92xx8lElkDkSEhd4cSUjsge4X/Yw7w++
         molCGC82jWZo4qshbuJMAIFT5vAkuwxRsIOe1b4GHU+wV2oG9V6/OcUC6HbYl9VBXz33
         +NJwpGLdZ01wvQLsqjokmmr9aQ9ZzndSuATQtctwbuq/ur1k5c/eFA+/NnCuMCBrQ8KG
         VRTfxe2dowMmzuDp636flCFOLmhIC+hrv2nuEoqBzdlzrLCRIA0Rxz1YcTxt1jnSjO2U
         Z9QXZpSK86d8Dakn1VyuJleWcAVcpIKGC1ELkuiAbIPrAAS2iDtvyHk75MrZi1nhrgJj
         WGuw==
X-Forwarded-Encrypted: i=1; AJvYcCWIgxxK96ZoizYgOKx7eh2JxA3OoZobYHJ07BqlQXZORsYK5n+I0baPnnXL4Rvw19AgYTU=@20252027frontrepublicain.site
X-Gm-Message-State: AOJu0YwvWFggBBj9FZLsot4PuWpavi1UZTpRcDxVE43vWAellVVgXWPV
	rhzfvRKu4Cvu6beMPdJ0RG1vf7cN7/2SHQFLhHErwpzDtZWd366YGaV1oCnUnZNG6xAc+2W+dQA
	mrYtQbVNqMRPGTz+aBnfG/YYuJGBOf0pHdz5bfyTAiJg=
X-Gm-Gg: ASbGnctGEQaUcO3T/THdJzzwGquIYCD1qp/Fi2B12Ch6uWcLHjFURfoqpLfX6iQkNL4
	PM+Dz0763rbLSlKvOsBj3zMclpve0WtvC2WTtzxbmmxpXBYY2iZFaf/+qzQM3HHZjN5yMYVLm5H
	HuMny89QzUXqWb0eBqdcyVJ7BK2khLXxzWbvq/h+8+ip7tIGAUeE9+ofhLZlnjo07fKiHz8sW0C
	NyayzSBotcB06bzPxdU4XJP61Rfek32D3Nc1vHT1thHQ7wSrcWhm5BCzHSjEYho8w7E+qw=
X-Google-Smtp-Source: AGHT+IHEpX4tKWyjNOeKW8QpSd++zszEzleNYP7tdcuvFQDLFU0EkOOm32ot6RDG0fCFnzPkpWrWESu7Zn6hycktx6c=
X-Received: by 2002:a17:903:b07:b0:296:4d61:6cd3 with SMTP id
 d9443c01a7336-29d68451d5emr29655375ad.40.1764771214171; Wed, 03 Dec 2025
 06:13:34 -0800 (PST)
MIME-Version: 1.0
References: <CAL3Nd=-fPqV=dBMQCARopUhm+hBKgGoPWvrxAXZnzxc2kTe+Tg at mail.gmail.com>
 <CAL3Nd=-1fhSdsPmF-+UaAR9PpUxWnSoOxwwRyZZmL3P+AZpnAA at mail.gmail.com>
In-Reply-To: <CAL3Nd=-1fhSdsPmF-+UaAR9PpUxWnSoOxwwRyZZmL3P+AZpnAA at mail.gmail.com>
From: =?UTF-8?Q?FRONT_R=C3=A9publicain_=2D_S=C3=A9bastien_PERETTI?= <president at front-republicain.info>
Date: Wed, 3 Dec 2025 15:13:16 +0100
X-Gm-Features: AWmQ_blQYBeN7sSA7lJd_feBYs5cmC2PDtXB2aRBPQuibOd2vTebH4Q7CVzt5Nc
Message-ID: <CAL3Nd=_2DHXHWSWKomNwD7bc5g+JEaOz4YamhsjJ+bvLUT-_MQ at mail.gmail.com>
To: e01 at frontrepublicain.blog, e02 at frontrepublicain.blog, 
	e03 at frontrepublicain.blog, e04 at frontrepublicain.blog, 
	e05 at frontrepublicain.blog, e06 at frontrepublicain.blog, 
	e07 at frontrepublicain.blog, e08 at frontrepublicain.blog, 
	e09 at frontrepublicain.blog, e10 at frontrepublicain.blog, 
	d01 at front-republicain.store, d02 at front-republicain.store, 
	d03 at front-republicain.store, d04 at front-republicain.store, 
	d05 at front-republicain.store, d06 at front-republicain.store, 
	d07 at front-republicain.store, d08 at front-republicain.store, 
	d09 at front-republicain.store, d10 at front-republicain.store, 
	b01 at front-republicain.eu, b02 at front-republicain.eu, b03 at front-republicain.eu, 
	b04 at front-republicain.eu, b05 at front-republicain.eu, b06 at front-republicain.eu, 
	b07 at front-republicain.eu, b08 at front-republicain.eu, b09 at front-republicain.eu, 
	b10 at front-republicain.eu, a01 at 20252027frontrepublicain.site, 
	a02 at 20252027frontrepublicain.site, a03 at 20252027frontrepublicain.site, 
	a04 at 20252027frontrepublicain.site, a05 at 20252027frontrepublicain.site, 
	a06 at 20252027frontrepublicain.site, a07 at 20252027frontrepublicain.site, 
	a08 at 20252027frontrepublicain.site, a09 at 20252027frontrepublicain.site, 
	a10 at 20252027frontrepublicain.site
Content-Type: multipart/mixed; boundary="00000000000054faf406450cd186"
X-OVH-Remote: 209.85.214.170 (mail-pl1-f170.google.com)
X-Ovh-Tracer-Id: 5013069337901664930
X-VR-SPAMSTATE: OK
X-VR-SPAMSCORE: 89
X-VR-SPAMCAUSE:  
X-Ovh-Spam-Status: OK
X-Ovh-Spam-Reason: vr: OK; dkim: disabled; spf: disabled
X-Ovh-Message-Type: OK
Subject: [a06] =?UTF-8?Q?Le_FRONT_R=C3=A9publicain=2C_=C3=A0_l=27attention_de_M=2E_le_Pr=C3=A9s?=
	=?UTF-8?Q?ident_TRUMP_et_=C3=A0_tous_les_membres_du_Club_BILDERBERG_et_du_?=
	=?UTF-8?Q?BOHEMIAN_Club_=2D_Communiqu=C3=A9_du_29=2F11=2F2025=2E?=
X-VR-SPAMSTATE: OK
X-VR-SPAMSCORE: 20
X-VR-SPAMCAUSE:  

--4dMVY307Hpz3wpC.1764842840/mo594.mail-out.ovh.net--


From krzk at kernel.org  Wed Dec 17 03:41:23 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 17 Dec 2025 12:41:23 +0100
Subject: [PATCH 10/12] dt-bindings: ras: document estatus provider
In-Reply-To: <20251217112845.1814119-11-ahmed.tiba@arm.com>
References: <20251217112845.1814119-1-ahmed.tiba@arm.com>
 <20251217112845.1814119-11-ahmed.tiba@arm.com>
Message-ID: <cd04e23a-9523-4d25-8240-29a0dffa0e75@kernel.org>

On 17/12/2025 12:28, Ahmed Tiba wrote:
> Add a binding for firmware-first CPER providers described via
> DeviceTree. It covers the shared status block, optional acknowledgment
> registers, interrupt versus polling modes and the SEA notification
> flag so non-ACPI platforms can describe their error sources.
> 
> Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>
> ---
>  .../devicetree/bindings/ras/arm,ras-ffh.yaml  | 95 +++++++++++++++++++
>  MAINTAINERS                                   |  1 +
>  2 files changed, 96 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/ras/arm,ras-ffh.yaml
> 
> diff --git a/Documentation/devicetree/bindings/ras/arm,ras-ffh.yaml b/Documentation/devicetree/bindings/ras/arm,ras-ffh.yaml
> new file mode 100644
> index 000000000000..0d2acbf8e8a8
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/ras/arm,ras-ffh.yaml

What is ras? There is no such directory so some description would be
useful. Usually you do not get your own directory per binding.

> @@ -0,0 +1,95 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/ras/arm,ras-ffh.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Arm Firmware-First Handler (FFH) CPER provider
> +
> +maintainers:
> +  - Ahmed Tiba <ahmed.tiba at arm.com>
> +
> +description: |
> +  Some Arm platforms describe a firmware-first error handler that exposes a
> +  Common Platform Error Record (CPER) buffer directly via DeviceTree. The OS
> +  maps the buffer to consume the error records, and firmware signals that a new
> +  record is ready either by asserting an interrupt or by relying on a periodic
> +  poll. This binding describes the buffer and the associated notification

Do not describe what the binding does. Describe the hardware or firmware.

> +  signal. If firmware delivers the error via Synchronous External Abort (SEA),
> +  the optional sea-notify flag marks the source accordingly.
> +
> +properties:
> +  compatible:
> +    const: arm,ras-ffh

Again ras - what's that? Your patch or binding must explain that.

> +
> +  reg:
> +    minItems: 1

Why is this flexible?

> +    items:
> +      - description: CPER status block exposed by firmware
> +      - description:
> +          Optional 32- or 64-bit acknowledgment register. Firmware watches this
> +          register and expects bit 0 to be written to 1 once the OS consumes the
> +          status buffer so it can reuse the record.
> +
> +  reg-names:
> +    items:
> +      - const: status
> +      - const: ack

Does not match reg.

> +
> +  interrupts:
> +    maxItems: 1
> +    description:
> +      Optional interrupt used to signal that a new status record is ready. If
> +      omitted, the OS relies on the polling interval property.

What OS is doing should not really matter. Either you have the interrupt
or not.


> +
> +  poll-interval:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    minimum: 1
> +    description:
> +      Optional polling interval, in milliseconds, for platforms that cannot
> +      route an interrupt.

That's OS policy, not suitable for binding.

> +
> +  arm,sea-notify:
> +    type: boolean
> +    description:
> +      Set if the platform delivers these errors as Synchronous External Aborts.

This is implied by the compatible, no?

> +
> +required:
> +  - compatible
> +  - reg
> +
> +allOf:
> +  - if:
> +      properties:
> +        poll-interval: false
> +    then:
> +      required:
> +        - interrupts
> +  - if:
> +      properties:
> +        interrupts: false
> +    then:
> +      required:
> +        - poll-interval
> +  - if:
> +      properties:
> +        reg:
> +          minItems: 2
> +    then:
> +      required:
> +        - reg-names

Drop all this.

> +
> +unevaluatedProperties: false

I do not see any schema referenced.

> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +
> +    ras-ffh at fe800000 {

Node names should be generic. See also an explanation and list of
examples (not exhaustive) in DT specification:
https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation
If you cannot find a name matching your device, please check in kernel
sources for similar cases or you can grow the spec (via pull request to
DT spec repo).

> +        compatible = "arm,ras-ffh";
> +        reg = <0xfe800000 0x1000>,
> +              <0xfe810000 0x4>;
> +        reg-names = "status", "ack";
> +        interrupts = <0 32 IRQ_TYPE_LEVEL_HIGH>;

Use proper defines.

Best regards,
Krzysztof


From joey.gouly at arm.com  Wed Dec 17 03:49:32 2025
From: joey.gouly at arm.com (Joey Gouly)
Date: Wed, 17 Dec 2025 11:49:32 +0000
Subject: [PATCH 18/32] KVM: arm64: gic-v5: Check for pending PPIs
In-Reply-To: <20251212152215.675767-19-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
 <20251212152215.675767-19-sascha.bischoff@arm.com>
Message-ID: <20251217114932.GA1626516@e124191.cambridge.arm.com>

Hi Sascha,

On Fri, Dec 12, 2025 at 03:22:41PM +0000, Sascha Bischoff wrote:
> This change allows KVM to check for pending PPI interrupts. This has
> two main components:
> 
> First of all, the effective priority mask is calculated.  This is a
> combination of the priority mask in the VPEs ICC_PCR_EL1.PRIORITY and
> the currently running priority as determined from the VPE's
> ICH_APR_EL1. If an interrupt's prioirity is greater than or equal to
> the effective priority mask, it can be signalled. Otherwise, it
> cannot.
> 
> Secondly, any Enabled and Pending PPIs must be checked against this
> compound priority mask. The reqires the PPI priorities to by synced
> back to the KVM shadow state - this is skipped in general operation as
> it isn't required and is rather expensive. If any Enabled and Pending
> PPIs are of sufficient priority to be signalled, then there are
> pending PPIs. Else, there are not.  This ensures that a VPE is not
> woken when it cannot actually process the pending interrupts.
> 
> Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
> ---
>  arch/arm64/kvm/vgic/vgic-v5.c | 123 ++++++++++++++++++++++++++++++++++
>  arch/arm64/kvm/vgic/vgic.c    |  10 ++-
>  arch/arm64/kvm/vgic/vgic.h    |   1 +
>  3 files changed, 131 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
> index d54595fbf4586..35740e88b3591 100644
> --- a/arch/arm64/kvm/vgic/vgic-v5.c
> +++ b/arch/arm64/kvm/vgic/vgic-v5.c
> @@ -54,6 +54,31 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
>  	return 0;
>  }
>  
> +static u32 vgic_v5_get_effective_priority_mask(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> +	unsigned highest_ap, priority_mask;
> +
> +	/*
> +	 * Counting the number of trailing zeros gives the current
> +	 * active priority. Explicitly use the 32-bit version here as
> +	 * we have 32 priorities. 0x20 then means that there are no
> +	 * active priorities.
> +	 */
> +	highest_ap = __builtin_ctz(cpu_if->vgic_apr);

__builtin_ctz(0) is undefined (https://gcc.gnu.org/onlinedocs/gcc/Bit-Operation-Builtins.html)

Looking at __vgic_v3_clear_highest_active_priority(), it handles that like this:

	c0 = ap0 ? __ffs(ap0) : 32;

Thanks,
Joey

> +
> +	/*
> +	 * An interrupt is of sufficient priority if it is equal to or
> +	 * greater than the priority mask. Add 1 to the priority mask
> +	 * (i.e., lower priority) to match the APR logic before taking
> +	 * the min. This gives us the lowest priority that is masked.
> +	 */
> +	priority_mask = FIELD_GET(FEAT_GCIE_ICH_VMCR_EL2_VPMR, cpu_if->vgic_vmcr);
> +	priority_mask = min(highest_ap, priority_mask + 1);
> +
> +	return priority_mask;
> +}
> +
>  static bool vgic_v5_ppi_set_pending_state(struct kvm_vcpu *vcpu,
>  					  struct vgic_irq *irq)
>  {
> @@ -121,6 +146,104 @@ void vgic_v5_set_ppi_ops(struct vgic_irq *irq)
>  	irq->ops = &vgic_v5_ppi_irq_ops;
>  }
>  
> +
> +/*
> + * Sync back the PPI priorities to the vgic_irq shadow state
> + */
> +static void vgic_v5_sync_ppi_priorities(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> +	unsigned long flags;
> +	int i, reg;
> +
> +	/* We have 16 PPI Priority regs */
> +	for (reg = 0; reg < 16; reg++) {
> +		const unsigned long priorityr = cpu_if->vgic_ppi_priorityr[reg];
> +
> +		for (i = 0; i < 8; ++i) {
> +			struct vgic_irq *irq;
> +			u32 intid;
> +			u8 priority;
> +
> +			priority = (priorityr >> (i * 8)) & 0x1f;
> +
> +			intid = FIELD_PREP(GICV5_HWIRQ_TYPE, GICV5_HWIRQ_TYPE_PPI);
> +			intid |= FIELD_PREP(GICV5_HWIRQ_ID, reg * 8 + i);
> +
> +			irq = vgic_get_vcpu_irq(vcpu, intid);
> +			raw_spin_lock_irqsave(&irq->irq_lock, flags);
> +
> +			irq->priority = priority;
> +
> +			raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
> +			vgic_put_irq(vcpu->kvm, irq);
> +		}
> +	}
> +}
> +
> +bool vgic_v5_has_pending_ppi(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> +	unsigned long flags;
> +	int i, reg;
> +	unsigned int priority_mask;
> +
> +	/* If no pending bits are set, exit early */
> +	if (likely(!cpu_if->vgic_ppi_pendr[0] && !cpu_if->vgic_ppi_pendr[1]))
> +		return false;
> +
> +	priority_mask = vgic_v5_get_effective_priority_mask(vcpu);
> +
> +	/* If the combined priority mask is 0, nothing can be signalled! */
> +	if (!priority_mask)
> +		return false;
> +
> +	/* The shadow priority is only updated on demand, sync it across first */
> +	vgic_v5_sync_ppi_priorities(vcpu);
> +
> +	for (reg = 0; reg < 2; reg++) {
> +		unsigned long possible_bits;
> +		const unsigned long enabler = cpu_if->vgic_ich_ppi_enabler_exit[reg];
> +		const unsigned long pendr = cpu_if->vgic_ppi_pendr_exit[reg];
> +		bool has_pending = false;
> +
> +		/* Check all interrupts that are enabled and pending */
> +		possible_bits = enabler & pendr;
> +
> +		/*
> +		 * Optimisation: pending and enabled with no active priorities
> +		 */
> +		if (possible_bits && priority_mask > 0x1f)
> +			return true;
> +
> +		for_each_set_bit(i, &possible_bits, 64) {
> +			struct vgic_irq *irq;
> +			u32 intid;
> +
> +			intid = FIELD_PREP(GICV5_HWIRQ_TYPE, GICV5_HWIRQ_TYPE_PPI);
> +			intid |= FIELD_PREP(GICV5_HWIRQ_ID, reg * 64 + i);
> +
> +			irq = vgic_get_vcpu_irq(vcpu, intid);
> +			raw_spin_lock_irqsave(&irq->irq_lock, flags);
> +
> +			/*
> +			 * We know that the interrupt is enabled and pending, so
> +			 * only check the priority.
> +			 */
> +			if (irq->priority <= priority_mask)
> +				has_pending = true;
> +
> +			raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
> +			vgic_put_irq(vcpu->kvm, irq);
> +
> +			if (has_pending)
> +				return true;
> +		}
> +	}
> +
> +	return false;
> +}
> +
>  /*
>   * Detect any PPIs state changes, and propagate the state with KVM's
>   * shadow structures.
> diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
> index e534876656ca7..5d18a03cc11d5 100644
> --- a/arch/arm64/kvm/vgic/vgic.c
> +++ b/arch/arm64/kvm/vgic/vgic.c
> @@ -1174,11 +1174,15 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
>  	unsigned long flags;
>  	struct vgic_vmcr vmcr;
>  
> -	if (!vcpu->kvm->arch.vgic.enabled)
> +	if (!vcpu->kvm->arch.vgic.enabled && !vgic_is_v5(vcpu->kvm))
>  		return false;
>  
> -	if (vcpu->arch.vgic_cpu.vgic_v3.its_vpe.pending_last)
> -		return true;
> +	if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5) {
> +		return vgic_v5_has_pending_ppi(vcpu);
> +	} else {
> +		if (vcpu->arch.vgic_cpu.vgic_v3.its_vpe.pending_last)
> +			return true;
> +	}
>  
>  	vgic_get_vmcr(vcpu, &vmcr);
>  
> diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
> index 5a77318ddb87a..4b3a1e7ca3fb4 100644
> --- a/arch/arm64/kvm/vgic/vgic.h
> +++ b/arch/arm64/kvm/vgic/vgic.h
> @@ -387,6 +387,7 @@ void vgic_debug_destroy(struct kvm *kvm);
>  int vgic_v5_probe(const struct gic_kvm_info *info);
>  void vgic_v5_set_ppi_ops(struct vgic_irq *irq);
>  int vgic_v5_set_ppi_dvi(struct kvm_vcpu *vcpu, u32 irq, bool dvi);
> +bool vgic_v5_has_pending_ppi(struct kvm_vcpu *vcpu);
>  void vgic_v5_flush_ppi_state(struct kvm_vcpu *vcpu);
>  void vgic_v5_fold_irq_state(struct kvm_vcpu *vcpu);
>  void vgic_v5_load(struct kvm_vcpu *vcpu);
> -- 
> 2.34.1


From joey.gouly at arm.com  Wed Dec 17 04:00:35 2025
From: joey.gouly at arm.com (Joey Gouly)
Date: Wed, 17 Dec 2025 12:00:35 +0000
Subject: [PATCH 18/32] KVM: arm64: gic-v5: Check for pending PPIs
In-Reply-To: <20251217114932.GA1626516@e124191.cambridge.arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
 <20251212152215.675767-19-sascha.bischoff@arm.com>
 <20251217114932.GA1626516@e124191.cambridge.arm.com>
Message-ID: <20251217120035.GA1628893@e124191.cambridge.arm.com>

On Wed, Dec 17, 2025 at 11:49:32AM +0000, Joey Gouly wrote:
> Hi Sascha,
> 
> On Fri, Dec 12, 2025 at 03:22:41PM +0000, Sascha Bischoff wrote:
> > This change allows KVM to check for pending PPI interrupts. This has
> > two main components:
> > 
> > First of all, the effective priority mask is calculated.  This is a
> > combination of the priority mask in the VPEs ICC_PCR_EL1.PRIORITY and
> > the currently running priority as determined from the VPE's
> > ICH_APR_EL1. If an interrupt's prioirity is greater than or equal to
> > the effective priority mask, it can be signalled. Otherwise, it
> > cannot.
> > 
> > Secondly, any Enabled and Pending PPIs must be checked against this
> > compound priority mask. The reqires the PPI priorities to by synced
> > back to the KVM shadow state - this is skipped in general operation as
> > it isn't required and is rather expensive. If any Enabled and Pending
> > PPIs are of sufficient priority to be signalled, then there are
> > pending PPIs. Else, there are not.  This ensures that a VPE is not
> > woken when it cannot actually process the pending interrupts.
> > 
> > Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
> > ---
> >  arch/arm64/kvm/vgic/vgic-v5.c | 123 ++++++++++++++++++++++++++++++++++
> >  arch/arm64/kvm/vgic/vgic.c    |  10 ++-
> >  arch/arm64/kvm/vgic/vgic.h    |   1 +
> >  3 files changed, 131 insertions(+), 3 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
> > index d54595fbf4586..35740e88b3591 100644
> > --- a/arch/arm64/kvm/vgic/vgic-v5.c
> > +++ b/arch/arm64/kvm/vgic/vgic-v5.c
> > @@ -54,6 +54,31 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
> >  	return 0;
> >  }
> >  
> > +static u32 vgic_v5_get_effective_priority_mask(struct kvm_vcpu *vcpu)
> > +{
> > +	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> > +	unsigned highest_ap, priority_mask;
> > +
> > +	/*
> > +	 * Counting the number of trailing zeros gives the current
> > +	 * active priority. Explicitly use the 32-bit version here as
> > +	 * we have 32 priorities. 0x20 then means that there are no
> > +	 * active priorities.
> > +	 */
> > +	highest_ap = __builtin_ctz(cpu_if->vgic_apr);
> 
> __builtin_ctz(0) is undefined (https://gcc.gnu.org/onlinedocs/gcc/Bit-Operation-Builtins.html)
> 
> Looking at __vgic_v3_clear_highest_active_priority(), it handles that like this:
> 
> 	c0 = ap0 ? __ffs(ap0) : 32;

Sorry forgot ffs() was 1-based, so:

	highest_ap = cpu_if->vgic_apr ? __builtin_ctz(cpu_if->vgic_apr) : 32;

Thanks,
Joey

> 
> Thanks,
> Joey
> 
> > +
> > +	/*
> > +	 * An interrupt is of sufficient priority if it is equal to or
> > +	 * greater than the priority mask. Add 1 to the priority mask
> > +	 * (i.e., lower priority) to match the APR logic before taking
> > +	 * the min. This gives us the lowest priority that is masked.
> > +	 */
> > +	priority_mask = FIELD_GET(FEAT_GCIE_ICH_VMCR_EL2_VPMR, cpu_if->vgic_vmcr);
> > +	priority_mask = min(highest_ap, priority_mask + 1);
> > +
> > +	return priority_mask;
> > +}
> > +
> >  static bool vgic_v5_ppi_set_pending_state(struct kvm_vcpu *vcpu,
> >  					  struct vgic_irq *irq)
> >  {
> > @@ -121,6 +146,104 @@ void vgic_v5_set_ppi_ops(struct vgic_irq *irq)
> >  	irq->ops = &vgic_v5_ppi_irq_ops;
> >  }
> >  
> > +
> > +/*
> > + * Sync back the PPI priorities to the vgic_irq shadow state
> > + */
> > +static void vgic_v5_sync_ppi_priorities(struct kvm_vcpu *vcpu)
> > +{
> > +	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> > +	unsigned long flags;
> > +	int i, reg;
> > +
> > +	/* We have 16 PPI Priority regs */
> > +	for (reg = 0; reg < 16; reg++) {
> > +		const unsigned long priorityr = cpu_if->vgic_ppi_priorityr[reg];
> > +
> > +		for (i = 0; i < 8; ++i) {
> > +			struct vgic_irq *irq;
> > +			u32 intid;
> > +			u8 priority;
> > +
> > +			priority = (priorityr >> (i * 8)) & 0x1f;
> > +
> > +			intid = FIELD_PREP(GICV5_HWIRQ_TYPE, GICV5_HWIRQ_TYPE_PPI);
> > +			intid |= FIELD_PREP(GICV5_HWIRQ_ID, reg * 8 + i);
> > +
> > +			irq = vgic_get_vcpu_irq(vcpu, intid);
> > +			raw_spin_lock_irqsave(&irq->irq_lock, flags);
> > +
> > +			irq->priority = priority;
> > +
> > +			raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
> > +			vgic_put_irq(vcpu->kvm, irq);
> > +		}
> > +	}
> > +}
> > +
> > +bool vgic_v5_has_pending_ppi(struct kvm_vcpu *vcpu)
> > +{
> > +	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> > +	unsigned long flags;
> > +	int i, reg;
> > +	unsigned int priority_mask;
> > +
> > +	/* If no pending bits are set, exit early */
> > +	if (likely(!cpu_if->vgic_ppi_pendr[0] && !cpu_if->vgic_ppi_pendr[1]))
> > +		return false;
> > +
> > +	priority_mask = vgic_v5_get_effective_priority_mask(vcpu);
> > +
> > +	/* If the combined priority mask is 0, nothing can be signalled! */
> > +	if (!priority_mask)
> > +		return false;
> > +
> > +	/* The shadow priority is only updated on demand, sync it across first */
> > +	vgic_v5_sync_ppi_priorities(vcpu);
> > +
> > +	for (reg = 0; reg < 2; reg++) {
> > +		unsigned long possible_bits;
> > +		const unsigned long enabler = cpu_if->vgic_ich_ppi_enabler_exit[reg];
> > +		const unsigned long pendr = cpu_if->vgic_ppi_pendr_exit[reg];
> > +		bool has_pending = false;
> > +
> > +		/* Check all interrupts that are enabled and pending */
> > +		possible_bits = enabler & pendr;
> > +
> > +		/*
> > +		 * Optimisation: pending and enabled with no active priorities
> > +		 */
> > +		if (possible_bits && priority_mask > 0x1f)
> > +			return true;
> > +
> > +		for_each_set_bit(i, &possible_bits, 64) {
> > +			struct vgic_irq *irq;
> > +			u32 intid;
> > +
> > +			intid = FIELD_PREP(GICV5_HWIRQ_TYPE, GICV5_HWIRQ_TYPE_PPI);
> > +			intid |= FIELD_PREP(GICV5_HWIRQ_ID, reg * 64 + i);
> > +
> > +			irq = vgic_get_vcpu_irq(vcpu, intid);
> > +			raw_spin_lock_irqsave(&irq->irq_lock, flags);
> > +
> > +			/*
> > +			 * We know that the interrupt is enabled and pending, so
> > +			 * only check the priority.
> > +			 */
> > +			if (irq->priority <= priority_mask)
> > +				has_pending = true;
> > +
> > +			raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
> > +			vgic_put_irq(vcpu->kvm, irq);
> > +
> > +			if (has_pending)
> > +				return true;
> > +		}
> > +	}
> > +
> > +	return false;
> > +}
> > +
> >  /*
> >   * Detect any PPIs state changes, and propagate the state with KVM's
> >   * shadow structures.
> > diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
> > index e534876656ca7..5d18a03cc11d5 100644
> > --- a/arch/arm64/kvm/vgic/vgic.c
> > +++ b/arch/arm64/kvm/vgic/vgic.c
> > @@ -1174,11 +1174,15 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
> >  	unsigned long flags;
> >  	struct vgic_vmcr vmcr;
> >  
> > -	if (!vcpu->kvm->arch.vgic.enabled)
> > +	if (!vcpu->kvm->arch.vgic.enabled && !vgic_is_v5(vcpu->kvm))
> >  		return false;
> >  
> > -	if (vcpu->arch.vgic_cpu.vgic_v3.its_vpe.pending_last)
> > -		return true;
> > +	if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5) {
> > +		return vgic_v5_has_pending_ppi(vcpu);
> > +	} else {
> > +		if (vcpu->arch.vgic_cpu.vgic_v3.its_vpe.pending_last)
> > +			return true;
> > +	}
> >  
> >  	vgic_get_vmcr(vcpu, &vmcr);
> >  
> > diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
> > index 5a77318ddb87a..4b3a1e7ca3fb4 100644
> > --- a/arch/arm64/kvm/vgic/vgic.h
> > +++ b/arch/arm64/kvm/vgic/vgic.h
> > @@ -387,6 +387,7 @@ void vgic_debug_destroy(struct kvm *kvm);
> >  int vgic_v5_probe(const struct gic_kvm_info *info);
> >  void vgic_v5_set_ppi_ops(struct vgic_irq *irq);
> >  int vgic_v5_set_ppi_dvi(struct kvm_vcpu *vcpu, u32 irq, bool dvi);
> > +bool vgic_v5_has_pending_ppi(struct kvm_vcpu *vcpu);
> >  void vgic_v5_flush_ppi_state(struct kvm_vcpu *vcpu);
> >  void vgic_v5_fold_irq_state(struct kvm_vcpu *vcpu);
> >  void vgic_v5_load(struct kvm_vcpu *vcpu);
> > -- 
> > 2.34.1


From ryan.roberts at arm.com  Wed Dec 17 04:04:48 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Wed, 17 Dec 2025 12:04:48 +0000
Subject: [PATCH 0/2] introduce pagetable_alloc_nolock()
In-Reply-To: <aUKKZR0u22KOPfd7@e129823.arm.com>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com>
 <916c17ba-22b1-456e-a184-cb3f60249af7@arm.com>
 <aUGOPd7gNRf1xHEc@e129823.arm.com>
 <100cc8da-b826-4fc2-a624-746bf6fb049d@arm.com>
 <aUKKZR0u22KOPfd7@e129823.arm.com>
Message-ID: <d96ac977-222e-4e8d-9487-da1306198419@arm.com>

On 17/12/2025 10:48, Yeoreum Yun wrote:
> Hi Ryan,
> 
>> On 16/12/2025 16:52, Yeoreum Yun wrote:
>>> Hi Ryan,
>>>
>>>> On 12/12/2025 16:18, Yeoreum Yun wrote:
>>>>> Some architectures invoke pagetable_alloc() or __get_free_pages()
>>>>> with preemption disabled.
>>>>> For example, in arm64, linear_map_split_to_ptes() calls pagetable_alloc()
>>>>> while spliting block entry to ptes and __kpti_install_ng_mappings()
>>>>> calls __get_free_pages() to create kpti pagetable.
>>>>>
>>>>> Under PREEMPT_RT, calling pagetable_alloc() with
>>>>> preemption disabled is not allowed, because it may acquire
>>>>> a spin lock that becomes sleepable on RT, potentially
>>>>> causing a sleep during page allocation.
>>>>>
>>>>> Since above two functions is called as callback of stop_machine()
>>>>> where its callback is called in preemption disabled,
>>>>> They could make a potential problem. (sleeping in preemption disabled).
>>>>>
>>>>> To address this, introduce pagetable_alloc_nolock() API.
>>>>
>>>> I don't really understand what the problem is that you're trying to fix. As I
>>>> see it, there are 2 call sites in arm64 arch code that are calling into the page
>>>> allocator from stop_machine() - one via via pagetable_alloc() and another via
>>>> __get_free_pages(). But both of those calls are passing in GFP_ATOMIC. It was my
>>>> understanding that the page allocator would ensure it never sleeps when
>>>> GFP_ATOMIC is passed in, (even for PREEMPT_RT)?
>>>
>>> Although GFP_ATOMIC is specify, it only affects of "water mark" of the
>>> page with __GFP_HIGH. and to get a page, it must grab the lock --
>>> zone->lock or pcp_lock in the rmqueue().
>>>
>>> This zone->lock and pcp_lock is spin_lock and it's a sleepable in
>>> PREEMPT_RT that's why the memory allocation/free using general API
>>> except nolock() version couldn't be called since
>>> if "contention" happens they'll sleep while waiting to get the lock.
>>>
>>> The reason why "nolock()" can use, it always uses "trylock" with
>>> ALLOC_TRYLOCK flags. otherwise GFP_ATOMIC also can be sleepable in
>>> PREEMPT_RT.
>>>
>>>>
>>>> What is the actual symptom you are seeing?
>>>
>>> Since the place where called while smp_cpus_done() and there seems no
>>> contention, there seems no problem. However as I mention in another
>>> thread
>>> (https://lore.kernel.org/all/aT%2FdrjN1BkvyAGoi at e129823.arm.com/),
>>> This gives a the false impression --
>>> GFP_ATOMIC are ?safe to use in preemption disabled?
>>> even though they are not in PREEMPT_RT case, I've changed it.
>>>
>>>>
>>>> If the page allocator is somehow ignoring the GFP_ATOMIC request for PREEMPT_RT,
>>>> then isn't that a bug in the page allocator? I'm not sure why you would change
>>>> the callsites? Can't you just change the page allocator based on GFP_ATOMIC?
>>>
>>> It doesn't ignore the GFP_ATOMIC feature:
>>>   - __GFP_HIGH: use water mark till min reserved
>>>   - __GFP_KSWAPD_RECLAIM: wake up kswapd if reclaim required.
>>>
>>> But, it's a restriction -- "page allocation / free" API cannot be called
>>> in preempt-disabled context at PREEMPT_RT.
>>>
>>> That's why I think it's wrong usage not a page allocator bug.
>>
>> I've taken a look at this and I agree with your analysis. Thanks for explaining.
>>
>> Looking at other stop_machine() callbacks, there are some that call printk() and
>> I would assume that spinlocks could be taken there which may present the same
>> kind of issue or PREEMPT_RT? (I'm guessing). I don't see any others that attempt
>> to allocate memory though.
> 
> IIRC, there was a problem related for printk while try to grab
> pl011_console related lock (spin_lock) while holding
> console_lock(raw_spin_lock) in v6.10.0-rc7 at rpi5:
> 
>     [  230.381263] CPU: 2 PID: 5574 Comm: syz.4.1695 Not tainted 6.10.0-rc7-01903-g52828ea60dfd #3
>     [  230.381479] Hardware name: linux,dummy-virt (DT)
>     [  230.381565] Call trace:
>     [  230.381607]  dump_backtrace+0x318/0x348
>     [  230.381727]  show_stack+0x4c/0x80
>     [  230.381875]  dump_stack_lvl+0x214/0x328
>     [  230.382159]  dump_stack+0x3c/0x58
>     [  230.382456]  __lock_acquire+0x4398/0x4720
>     [  230.382683]  lock_acquire+0x648/0xb70
>     [  230.382928]  _raw_spin_lock_irqsave+0x138/0x240
>     [  230.383121]  pl011_console_write+0x240/0x8a0
>     [  230.383356]  console_flush_all+0x708/0x1368
>     [  230.383571]  console_unlock+0x180/0x440
>     [  230.383742]  vprintk_emit+0x1f8/0x9d0
>     [  230.383832]  vprintk_default+0x64/0x90
>     [  230.383914]  vprintk+0x2d0/0x400
>     [  230.383971]  _printk+0xdc/0x128
>     [  230.384229]  hrtimer_interrupt+0x8f0/0x920
>     [  230.384414]  arch_timer_handler_virt+0xc0/0x100
>     [  230.384812]  handle_percpu_devid_irq+0x20c/0x4e0
>     [  230.385053]  generic_handle_domain_irq+0xc0/0x120
>     [  230.385367]  gic_handle_irq+0x88/0x360
>     [  230.385559]  call_on_irq_stack+0x24/0x70
>     [  230.385801]  do_interrupt_handler+0xf8/0x200
>     [  230.386092]  el1_interrupt+0x68/0xc0
>     [  230.386434]  el1h_64_irq_handler+0x18/0x28
>     [  230.386716]  el1h_64_irq+0x64/0x68
>     [  230.386853]  __sanitizer_cov_trace_const_cmp2+0x30/0x68
>     [  230.387026]  alloc_pages_mpol_noprof+0x170/0x698
>     [  230.387309]  vma_alloc_folio_noprof+0x128/0x2a8
>     [  230.387610]  vma_alloc_zeroed_movable_folio+0xa0/0xe0
>     [  230.387822]  folio_prealloc+0x5c/0x280
>     [  230.388008]  do_wp_page+0xc30/0x3bc0
>     [  230.388206]  __handle_mm_fault+0xdb8/0x2ba0
>     [  230.388448]  handle_mm_fault+0x194/0x8a8
>     [  230.388676]  do_page_fault+0x6bc/0x1030
>     [  230.388924]  do_mem_abort+0x8c/0x240
>     [  230.389056]  el0_da+0xf0/0x3f8
>     [  230.389178]  el0t_64_sync_handler+0xb4/0x130
>     [  230.389452]  el0t_64_sync+0x190/0x198
> 
> But this problem is gone when I try with some of patches in rt-tree
> related for printk which are merged in current tree
> (https://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git/log/?h=linux-6.10.y-rt-rebase).
> 
> So I think printk() wouldn't be a problem.
> 
>>
>> Anyway, to fix the 2 arm64 callsites, I see 2 possible approaches:
>>
>> - Call the nolock variant (as you are doing). But that would just convert a
>> deadlock to a panic; if the lock is held when stop_machine() runs, without your
>> change, we now have a deadlock due to waiting on the lock inside stop_machine().
>> With your change, we notice the lock is already taken and panic. I guess it is
>> marginally better, but not by much. Certainly I would just _always_ call the
>> nolock variant regardless of PREEMPT_RT if we take this route; For !PREEMPT_RT,
>> the lock is guarranteed to be free so nolock will always succeed.
>>
>> - Preallocate the memory before entering stop_machine(). I think this would be
>> much more robust. For kpti_install_ng_mappings() I think you could hoist the
>> allocation/free out of stop_machine() and pass the pointer in pretty easily. For
>> linear_map_split_to_ptes() its a bit more complex; Perhaps, we need to walk the
>> pgtable to figure out how much to preallocate, allocate it, then set it up as a
>> special allocator, wrapped by an allocation function and modify the callchain to
>> take a callback function instead of gfp flags.
>>
>> What do you think?
> 
> Definitely, second suggestoin is much better.
> My question is whether *memory contention* really happen in the point
> both functions are called.

My guess would be that it's unlikely, but not impossible. The secondary CPUs are
up, and presumably running their idle thread. I think various power management
things can be plugged into the idle thread; if so, then I guess it's possible
that the CPU could be running some hook as part of a power state transition, and
that could be dynamically allocating memory? That's all just a guess though; I
don't know the details of that part of the system.

> 
> Above two functions are called as last step of "smp_init()" -- smp_cpus_done().
> If we can be sure, I think we don't need to go to complex way and
> I believe the reason why we couldn't find out this problem,
> even using GFP_ATOMIC in PREEMPT_RT since there was *no contection*
> in this time of both functions are called.
> > That's why I first try with the "simple way".
> 
> What do you think?

As far as linear_map_split_to_ptes() is concerned, it was implemented under the
impression that doing allocation with GFP_ATOMIC was safe, even in
stop_machine(). Given that's an incorrect assumption, I think we should fix it
to pre-allocate outside of stop_machine() regardless of the likelihood of
actually hitting the race.

Thanks,
Ryan

> 
> --
> Sincerely,
> Yeoreum Yun



From linux at roeck-us.net  Wed Dec 17 04:17:38 2025
From: linux at roeck-us.net (Guenter Roeck)
Date: Wed, 17 Dec 2025 04:17:38 -0800
Subject: [PATCH v5 09/14] parisc: Convert DMA map_page to map_phys
 interface [qemu test failure]
In-Reply-To: <20251015-remove-map-page-v5-9-3bbfe3a25cdf@kernel.org>
References: <20251015-remove-map-page-v5-0-3bbfe3a25cdf@kernel.org>
 <20251015-remove-map-page-v5-9-3bbfe3a25cdf@kernel.org>
Message-ID: <b184f1bf-96dc-4546-8512-9cba5ecb58f7@roeck-us.net>

Hi,

On Wed, Oct 15, 2025 at 12:12:55PM +0300, Leon Romanovsky wrote:
> From: Leon Romanovsky <leonro at nvidia.com>
> 
> Perform mechanical conversion from .map_page to .map_phys callback.
> 
> Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
> Signed-off-by: Leon Romanovsky <leonro at nvidia.com>

This patch causes all my 32-bit parisc qemu tests with C3700 machine
to fail. Network interface tests fail, and all boot attempts from
any kind of hard drive (scsi, usb) fail with this patch in the tree.

Guenter

---
# bad: [8f0b4cce4481fb22653697cced8d0d04027cb1e8] Linux 6.19-rc1
# good: [7d0a66e4bb9081d75c82ec4957c50034cb0ea449] Linux 6.18
git bisect start 'HEAD' 'v6.18'
# good: [6dfafbd0299a60bfb5d5e277fdf100037c7ded07] Merge tag 'drm-next-2025-12-03' of https://gitlab.freedesktop.org/drm/kernel
git bisect good 6dfafbd0299a60bfb5d5e277fdf100037c7ded07
# good: [09cab48db950b6fb8c114314a20c0fd5a80cf990] Merge tag 'soc-arm-6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
git bisect good 09cab48db950b6fb8c114314a20c0fd5a80cf990
# bad: [701d7d782d98242a64cdeed90750f88ff733bc39] Merge tag 'spdx-6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/spdx
git bisect bad 701d7d782d98242a64cdeed90750f88ff733bc39
# good: [66a1025f7f0bc00404ec6357af68815c70dadae2] Merge tag 'soc-newsoc-6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
git bisect good 66a1025f7f0bc00404ec6357af68815c70dadae2
# good: [c84d574698bad2c02aad506dfe712f83cbe3b771] Merge tag 'modules-6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/modules/linux
git bisect good c84d574698bad2c02aad506dfe712f83cbe3b771
# bad: [b0319c4642638bad4b36974055b1c0894b2c7aa9] Merge tag 'nfsd-6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux
git bisect bad b0319c4642638bad4b36974055b1c0894b2c7aa9
# bad: [e637b37a520513a04d00f4add07ec25f357e6c6d] Merge tag 'rproc-v6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux
git bisect bad e637b37a520513a04d00f4add07ec25f357e6c6d
# bad: [56a1a04dc9bf252641c622aad525894dadc61a07] Merge tag 'libnvdimm-for-6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm
git bisect bad 56a1a04dc9bf252641c622aad525894dadc61a07
# good: [d0cf6512bbcf77afb6102f886fcd7fd48b7ae043] rust: bitmap: add BitmapVec::new_inline()
git bisect good d0cf6512bbcf77afb6102f886fcd7fd48b7ae043
# bad: [936a9f0cb16b0646143f8e05afab458adc51d0a0] xen: swiotlb: Convert mapping routine to rely on physical address
git bisect bad 936a9f0cb16b0646143f8e05afab458adc51d0a0
# good: [14cb413af00c5d3950d1a339dd2b6f01ce313fce] dma-mapping: remove unused mapping resource callbacks
git bisect good 14cb413af00c5d3950d1a339dd2b6f01ce313fce
# bad: [96ddf2ef58ec070afa8275f371b619462cd8fb2c] parisc: Convert DMA map_page to map_phys interface
git bisect bad 96ddf2ef58ec070afa8275f371b619462cd8fb2c
# good: [e4e3fff66a57a7aee048e0737a16874aeaffe9f4] MIPS/jazzdma: Provide physical address directly
git bisect good e4e3fff66a57a7aee048e0737a16874aeaffe9f4
# first bad commit: [96ddf2ef58ec070afa8275f371b619462cd8fb2c] parisc: Convert DMA map_page to map_phys interface


From michal.simek at amd.com  Wed Dec 17 04:38:44 2025
From: michal.simek at amd.com (Michal Simek)
Date: Wed, 17 Dec 2025 13:38:44 +0100
Subject: [PATCH] arm64: dts: xilinx: Drop "label" property on
 dlg,slg7xl45106
In-Reply-To: <20251216175914.2791200-1-robh@kernel.org>
References: <20251216175914.2791200-1-robh@kernel.org>
Message-ID: <aa064ecf-1714-4d40-8658-19952392cae8@amd.com>



On 12/16/25 18:59, Rob Herring (Arm) wrote:
> The "label" property is not documented for the dlg,slg7xl45106. Nor is
> it common to use for GPIO controllers. So drop it.
> 

Correct it is not documented but it is at least used in Linux also by
drivers/gpio/gpio-mmio.c:810:	err = device_property_read_string(dev, "label", 
&label);

which is also not documented in DT binding.

I don't have a problem with it because I can't see it used anywhere.

But there are other devices where label is the part of binding. And IMHO this 
should be more generic property.

Thanks,
Michal




From krzk at kernel.org  Wed Dec 17 04:42:28 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 17 Dec 2025 13:42:28 +0100
Subject: [PATCH] arm64: dts: xilinx: Drop "label" property on
 dlg,slg7xl45106
In-Reply-To: <aa064ecf-1714-4d40-8658-19952392cae8@amd.com>
References: <20251216175914.2791200-1-robh@kernel.org>
 <aa064ecf-1714-4d40-8658-19952392cae8@amd.com>
Message-ID: <8c50d838-2f41-4539-bc96-ccdc521c8014@kernel.org>

On 17/12/2025 13:38, Michal Simek wrote:
> 
> 
> On 12/16/25 18:59, Rob Herring (Arm) wrote:
>> The "label" property is not documented for the dlg,slg7xl45106. Nor is
>> it common to use for GPIO controllers. So drop it.
>>
> 
> Correct it is not documented but it is at least used in Linux also by
> drivers/gpio/gpio-mmio.c:810:	err = device_property_read_string(dev, "label", 
> &label);
> 
> which is also not documented in DT binding.
> 
> I don't have a problem with it because I can't see it used anywhere.
> 
> But there are other devices where label is the part of binding. And IMHO this 
> should be more generic property.

No, please read the EXPLICIT comment:

"+	 * This property *must not* be used in device-tree sources, it's only"

It was added only for ACPI.

We have indeed the problem with documenting disallowed ABI for cases
where drivers use fwnode/device_property(). So far I insisted on
comments, but as we can see people can just ignore the comments and
still use something explicitly disallowed.

Rob,

Would it be okay to add for such cases "label: false" in the binding to
mark that this is not ABI for DT?

Best regards,
Krzysztof


From peng.fan at oss.nxp.com  Wed Dec 17 04:42:06 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Wed, 17 Dec 2025 20:42:06 +0800
Subject: [PATCH 0/3] soc: imx: misc clean up and support i.MX9[4,52]
Message-ID: <20251217-soc-imx9-fix-v1-0-0c763c2dbe29@nxp.com>

Patch 1, 2: Use device managed API and dev_err_probe to clean up driver
Patch 3: Support i.MX94/52

Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
Peng Fan (3):
      soc: imx: Use device-managed APIs for i.MX9
      soc: imx: Use dev_err_probe() for i.MX9
      soc: imx: Spport i.MX9[4,52]

 drivers/soc/imx/soc-imx9.c | 46 ++++++++++++++++------------------------------
 1 file changed, 16 insertions(+), 30 deletions(-)
---
base-commit: 563c8dd425b59e44470e28519107b1efc99f4c7b
change-id: 20251217-soc-imx9-fix-dfa285722307

Best regards,
-- 
Peng Fan <peng.fan at nxp.com>



From peng.fan at oss.nxp.com  Wed Dec 17 04:42:07 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Wed, 17 Dec 2025 20:42:07 +0800
Subject: [PATCH 1/3] soc: imx: Use device-managed APIs for i.MX9
In-Reply-To: <20251217-soc-imx9-fix-v1-0-0c763c2dbe29@nxp.com>
References: <20251217-soc-imx9-fix-v1-0-0c763c2dbe29@nxp.com>
Message-ID: <20251217-soc-imx9-fix-v1-1-0c763c2dbe29@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

Use device-managed APi to simplify code.

Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 drivers/soc/imx/soc-imx9.c | 28 +++++++++-------------------
 1 file changed, 9 insertions(+), 19 deletions(-)

diff --git a/drivers/soc/imx/soc-imx9.c b/drivers/soc/imx/soc-imx9.c
index b46d22cf0212c3f40f61ec5be85ca11e5d3207ac..0b1c59c7ddb244549bfeedc47ae6e8d83c20b39b 100644
--- a/drivers/soc/imx/soc-imx9.c
+++ b/drivers/soc/imx/soc-imx9.c
@@ -18,6 +18,7 @@
 
 static int imx9_soc_probe(struct platform_device *pdev)
 {
+	struct device *dev = &pdev->dev;
 	struct soc_device_attribute *attr;
 	struct arm_smccc_res res;
 	struct soc_device *sdev;
@@ -25,17 +26,17 @@ static int imx9_soc_probe(struct platform_device *pdev)
 	u64 uid127_64, uid63_0;
 	int err;
 
-	attr = kzalloc(sizeof(*attr), GFP_KERNEL);
+	attr = devm_kzalloc(dev, sizeof(*attr), GFP_KERNEL);
 	if (!attr)
 		return -ENOMEM;
 
 	err = of_property_read_string(of_root, "model", &attr->machine);
 	if (err) {
 		pr_err("%s: missing model property: %d\n", __func__, err);
-		goto attr;
+		return err;
 	}
 
-	attr->family = kasprintf(GFP_KERNEL, "Freescale i.MX");
+	attr->family = devm_kasprintf(dev, GFP_KERNEL, "Freescale i.MX");
 
 	/*
 	 * Retrieve the soc id, rev & uid info:
@@ -47,39 +48,28 @@ static int imx9_soc_probe(struct platform_device *pdev)
 	arm_smccc_smc(IMX_SIP_GET_SOC_INFO, 0, 0, 0, 0, 0, 0, 0, &res);
 	if (res.a0 != SMCCC_RET_SUCCESS) {
 		pr_err("%s: SMC failed: 0x%lx\n", __func__, res.a0);
-		err = -EINVAL;
-		goto family;
+		return -EINVAL;
 	}
 
 	soc_id = SOC_ID(res.a1);
 	rev_major = SOC_REV_MAJOR(res.a1);
 	rev_minor = SOC_REV_MINOR(res.a1);
 
-	attr->soc_id = kasprintf(GFP_KERNEL, "i.MX%2x", soc_id);
-	attr->revision = kasprintf(GFP_KERNEL, "%d.%d", rev_major, rev_minor);
+	attr->soc_id = devm_kasprintf(dev, GFP_KERNEL, "i.MX%2x", soc_id);
+	attr->revision = devm_kasprintf(dev, GFP_KERNEL, "%d.%d", rev_major, rev_minor);
 
 	uid127_64 = res.a2;
 	uid63_0 = res.a3;
-	attr->serial_number = kasprintf(GFP_KERNEL, "%016llx%016llx", uid127_64, uid63_0);
+	attr->serial_number = devm_kasprintf(dev, GFP_KERNEL, "%016llx%016llx", uid127_64, uid63_0);
 
 	sdev = soc_device_register(attr);
 	if (IS_ERR(sdev)) {
 		err = PTR_ERR(sdev);
 		pr_err("%s failed to register SoC as a device: %d\n", __func__, err);
-		goto serial_number;
+		return err;
 	}
 
 	return 0;
-
-serial_number:
-	kfree(attr->serial_number);
-	kfree(attr->revision);
-	kfree(attr->soc_id);
-family:
-	kfree(attr->family);
-attr:
-	kfree(attr);
-	return err;
 }
 
 static __maybe_unused const struct of_device_id imx9_soc_match[] = {

-- 
2.37.1



From peng.fan at oss.nxp.com  Wed Dec 17 04:42:08 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Wed, 17 Dec 2025 20:42:08 +0800
Subject: [PATCH 2/3] soc: imx: Use dev_err_probe() for i.MX9
In-Reply-To: <20251217-soc-imx9-fix-v1-0-0c763c2dbe29@nxp.com>
References: <20251217-soc-imx9-fix-v1-0-0c763c2dbe29@nxp.com>
Message-ID: <20251217-soc-imx9-fix-v1-2-0c763c2dbe29@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

Use dev_err_probe() to simplify code. No functional changes.

Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 drivers/soc/imx/soc-imx9.c | 20 +++++++-------------
 1 file changed, 7 insertions(+), 13 deletions(-)

diff --git a/drivers/soc/imx/soc-imx9.c b/drivers/soc/imx/soc-imx9.c
index 0b1c59c7ddb244549bfeedc47ae6e8d83c20b39b..d9a686299c5f710bb9988c55ed601fc9d9f19229 100644
--- a/drivers/soc/imx/soc-imx9.c
+++ b/drivers/soc/imx/soc-imx9.c
@@ -31,10 +31,8 @@ static int imx9_soc_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	err = of_property_read_string(of_root, "model", &attr->machine);
-	if (err) {
-		pr_err("%s: missing model property: %d\n", __func__, err);
-		return err;
-	}
+	if (err)
+		return dev_err_probe(dev, err, "%s: missing model property\n", __func__);
 
 	attr->family = devm_kasprintf(dev, GFP_KERNEL, "Freescale i.MX");
 
@@ -46,10 +44,8 @@ static int imx9_soc_probe(struct platform_device *pdev)
 	 * res.a3: uid[63:0];
 	 */
 	arm_smccc_smc(IMX_SIP_GET_SOC_INFO, 0, 0, 0, 0, 0, 0, 0, &res);
-	if (res.a0 != SMCCC_RET_SUCCESS) {
-		pr_err("%s: SMC failed: 0x%lx\n", __func__, res.a0);
-		return -EINVAL;
-	}
+	if (res.a0 != SMCCC_RET_SUCCESS)
+		return dev_err_probe(dev, -EINVAL, "%s: SMC failed: 0x%lx\n", __func__, res.a0);
 
 	soc_id = SOC_ID(res.a1);
 	rev_major = SOC_REV_MAJOR(res.a1);
@@ -63,11 +59,9 @@ static int imx9_soc_probe(struct platform_device *pdev)
 	attr->serial_number = devm_kasprintf(dev, GFP_KERNEL, "%016llx%016llx", uid127_64, uid63_0);
 
 	sdev = soc_device_register(attr);
-	if (IS_ERR(sdev)) {
-		err = PTR_ERR(sdev);
-		pr_err("%s failed to register SoC as a device: %d\n", __func__, err);
-		return err;
-	}
+	if (IS_ERR(sdev))
+		return dev_err_probe(dev, PTR_ERR(sdev),
+				     "%s failed to register SoC as a device\n", __func__);
 
 	return 0;
 }

-- 
2.37.1



From peng.fan at oss.nxp.com  Wed Dec 17 04:42:09 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Wed, 17 Dec 2025 20:42:09 +0800
Subject: [PATCH 3/3] soc: imx: Spport i.MX9[4,52]
In-Reply-To: <20251217-soc-imx9-fix-v1-0-0c763c2dbe29@nxp.com>
References: <20251217-soc-imx9-fix-v1-0-0c763c2dbe29@nxp.com>
Message-ID: <20251217-soc-imx9-fix-v1-3-0c763c2dbe29@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

Add i.MX9[4,52] machine compatible to allow soc device could be created.

SOC_ID is 16bit format data:
 - i.MX943: 0x9430
 - i.MX952: 0x9520
Update SOC_ID macro to get the accurate data.

Co-developed-by: Jacky Bai <ping.bai at nxp.com>
Signed-off-by: Jacky Bai <ping.bai at nxp.com>
Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 drivers/soc/imx/soc-imx9.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/soc/imx/soc-imx9.c b/drivers/soc/imx/soc-imx9.c
index d9a686299c5f710bb9988c55ed601fc9d9f19229..d67bc7402b10e2966ff77cbf3b15c087540bd377 100644
--- a/drivers/soc/imx/soc-imx9.c
+++ b/drivers/soc/imx/soc-imx9.c
@@ -12,7 +12,7 @@
 #include <linux/sys_soc.h>
 
 #define IMX_SIP_GET_SOC_INFO	0xc2000006
-#define SOC_ID(x)		(((x) & 0xFFFF) >> 8)
+#define SOC_ID(x)		(((x) & 0xFF) ? ((x) & 0xFFFF) >> 4 : ((x) & 0xFFFF) >> 8)
 #define SOC_REV_MAJOR(x)	((((x) >> 28) & 0xF) - 0x9)
 #define SOC_REV_MINOR(x)	(((x) >> 24) & 0xF)
 
@@ -68,7 +68,9 @@ static int imx9_soc_probe(struct platform_device *pdev)
 
 static __maybe_unused const struct of_device_id imx9_soc_match[] = {
 	{ .compatible = "fsl,imx93", },
+	{ .compatible = "fsl,imx94", },
 	{ .compatible = "fsl,imx95", },
+	{ .compatible = "fsl,imx952", },
 	{ }
 };
 

-- 
2.37.1



From krzk at kernel.org  Wed Dec 17 04:44:02 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 17 Dec 2025 13:44:02 +0100
Subject: [PATCH] arm64: dts: xilinx: Drop "label" property on
 dlg,slg7xl45106
In-Reply-To: <8c50d838-2f41-4539-bc96-ccdc521c8014@kernel.org>
References: <20251216175914.2791200-1-robh@kernel.org>
 <aa064ecf-1714-4d40-8658-19952392cae8@amd.com>
 <8c50d838-2f41-4539-bc96-ccdc521c8014@kernel.org>
Message-ID: <0400eb44-4200-452e-9d1f-d1851f661cb8@kernel.org>

On 17/12/2025 13:42, Krzysztof Kozlowski wrote:
> On 17/12/2025 13:38, Michal Simek wrote:
>>
>>
>> On 12/16/25 18:59, Rob Herring (Arm) wrote:
>>> The "label" property is not documented for the dlg,slg7xl45106. Nor is
>>> it common to use for GPIO controllers. So drop it.
>>>
>>
>> Correct it is not documented but it is at least used in Linux also by
>> drivers/gpio/gpio-mmio.c:810:	err = device_property_read_string(dev, "label", 
>> &label);
>>
>> which is also not documented in DT binding.
>>
>> I don't have a problem with it because I can't see it used anywhere.
>>
>> But there are other devices where label is the part of binding. And IMHO this 
>> should be more generic property.
> 
> No, please read the EXPLICIT comment:
> 
> "+	 * This property *must not* be used in device-tree sources, it's only"
> 
> It was added only for ACPI.

Uh, my bad, the comment is above "gpio-mmio,base", not "label", but I
have impression it was applicable to label as well. Maybe that's not the
case...

> 
> We have indeed the problem with documenting disallowed ABI for cases
> where drivers use fwnode/device_property(). So far I insisted on
> comments, but as we can see people can just ignore the comments and
> still use something explicitly disallowed.
> 
> Rob,
> 
> Would it be okay to add for such cases "label: false" in the binding to
> mark that this is not ABI for DT?
> 
> Best regards,
> Krzysztof


Best regards,
Krzysztof


From alim.akhtar at samsung.com  Wed Dec 17 04:44:12 2025
From: alim.akhtar at samsung.com (Alim Akhtar)
Date: Wed, 17 Dec 2025 18:14:12 +0530
Subject: [PATCH 1/3] dt-bindings: clock: exynosautov920: add MFD clock
 definitions
In-Reply-To: <20251119114744.1914416-2-raghav.s@samsung.com>
References: <20251119114744.1914416-1-raghav.s@samsung.com>
	<CGME20251119113927epcas5p15154cb4a7824e9ca65ac18842b68d785@epcas5p1.samsung.com>
	<20251119114744.1914416-2-raghav.s@samsung.com>
Message-ID: <139901dc6f52$dba09d50$92e1d7f0$@samsung.com>

Hi Raghav

> -----Original Message-----
> From: Raghav Sharma <raghav.s at samsung.com>
> Sent: Wednesday, November 19, 2025 5:18 PM
> To: krzk at kernel.org; s.nawrocki at samsung.com; cw00.choi at samsung.com;
> alim.akhtar at samsung.com; mturquette at baylibre.com; sboyd at kernel.org;
> robh at kernel.org; conor+dt at kernel.org; sunyeal.hong at samsung.com;
> shin.son at samsung.com
> Cc: linux-samsung-soc at vger.kernel.org; linux-clk at vger.kernel.org;
> devicetree at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux-
> kernel at vger.kernel.org; chandan.vn at samsung.com;
> dev.tailor at samsung.com; karthik.sun at samsung.com; Raghav Sharma
> <raghav.s at samsung.com>
> Subject: [PATCH 1/3] dt-bindings: clock: exynosautov920: add MFD clock
> definitions
> 
> Add device tree clock binding definitions for CMU_MFD
> 
> Signed-off-by: Raghav Sharma <raghav.s at samsung.com>
> ---

Reviewed-by: Alim Akhtar <alim.akhtar at samsung.com>




From alim.akhtar at samsung.com  Wed Dec 17 04:46:29 2025
From: alim.akhtar at samsung.com (Alim Akhtar)
Date: Wed, 17 Dec 2025 18:16:29 +0530
Subject: [PATCH 2/3] clk: samsung: exynosautov920: add clock support
In-Reply-To: <20251119114744.1914416-3-raghav.s@samsung.com>
References: <20251119114744.1914416-1-raghav.s@samsung.com>
	<CGME20251119113930epcas5p1116fba63f1fa2905a67e2f5f3e016c56@epcas5p1.samsung.com>
	<20251119114744.1914416-3-raghav.s@samsung.com>
Message-ID: <139a01dc6f53$2f861f80$8e925e80$@samsung.com>

Hi Raghav

> -----Original Message-----
> From: Raghav Sharma <raghav.s at samsung.com>
> Sent: Wednesday, November 19, 2025 5:18 PM
> To: krzk at kernel.org; s.nawrocki at samsung.com; cw00.choi at samsung.com;
> alim.akhtar at samsung.com; mturquette at baylibre.com; sboyd at kernel.org;
> robh at kernel.org; conor+dt at kernel.org; sunyeal.hong at samsung.com;
> shin.son at samsung.com
> Cc: linux-samsung-soc at vger.kernel.org; linux-clk at vger.kernel.org;
> devicetree at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux-
> kernel at vger.kernel.org; chandan.vn at samsung.com;
> dev.tailor at samsung.com; karthik.sun at samsung.com; Raghav Sharma
> <raghav.s at samsung.com>
> Subject: [PATCH 2/3] clk: samsung: exynosautov920: add clock support
> 
> Add support for CMU_MFD which provides clocks to MFD block, and register
> the required compatible and cmu_info for the same.
> 
> Signed-off-by: Raghav Sharma <raghav.s at samsung.com>
> ---
Reviewed-by: Alim Akhtar <alim.akhtar at samsung.com>




From alim.akhtar at samsung.com  Wed Dec 17 04:47:29 2025
From: alim.akhtar at samsung.com (Alim Akhtar)
Date: Wed, 17 Dec 2025 18:17:29 +0530
Subject: [PATCH 3/3] arm64: dts: exynosautov920: add CMU_MFD clock DT
 nodes
In-Reply-To: <20251119114744.1914416-4-raghav.s@samsung.com>
References: <20251119114744.1914416-1-raghav.s@samsung.com>
	<CGME20251119113935epcas5p33c4cac5a961ce334bde5988ef74b09ed@epcas5p3.samsung.com>
	<20251119114744.1914416-4-raghav.s@samsung.com>
Message-ID: <139b01dc6f53$534e6e90$f9eb4bb0$@samsung.com>

Hello Raghav

> -----Original Message-----
> From: Raghav Sharma <raghav.s at samsung.com>
> Sent: Wednesday, November 19, 2025 5:18 PM
> To: krzk at kernel.org; s.nawrocki at samsung.com; cw00.choi at samsung.com;
> alim.akhtar at samsung.com; mturquette at baylibre.com; sboyd at kernel.org;
> robh at kernel.org; conor+dt at kernel.org; sunyeal.hong at samsung.com;
> shin.son at samsung.com
> Cc: linux-samsung-soc at vger.kernel.org; linux-clk at vger.kernel.org;
> devicetree at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux-
> kernel at vger.kernel.org; chandan.vn at samsung.com;
> dev.tailor at samsung.com; karthik.sun at samsung.com; Raghav Sharma
> <raghav.s at samsung.com>
> Subject: [PATCH 3/3] arm64: dts: exynosautov920: add CMU_MFD clock DT
> nodes
> 
> Add required dt node for cmu_mfd block, which provides clocks for MFD IP
> 
> Signed-off-by: Raghav Sharma <raghav.s at samsung.com>
> ---
Reviewed-by: Alim Akhtar <alim.akhtar at samsung.com>




From wei.fang at nxp.com  Wed Dec 17 04:49:19 2025
From: wei.fang at nxp.com (Wei Fang)
Date: Wed, 17 Dec 2025 12:49:19 +0000
Subject: [PATCH net] net: stmmac: fix the crash issue for zero copy XDP_TX
 action
In-Reply-To: <aUKPHdtAPDnMqB7X@test-OptiPlex-Tower-Plus-7010>
References: <20251204071332.1907111-1-wei.fang@nxp.com>
 <aUKPHdtAPDnMqB7X@test-OptiPlex-Tower-Plus-7010>
Message-ID: <AS8PR04MB849779A6392D543049A3F5BE88ABA@AS8PR04MB8497.eurprd04.prod.outlook.com>

> > -	res = stmmac_xdp_xmit_xdpf(priv, queue, xdpf, false);
> > -	if (res == STMMAC_XDP_TX)
> > +	/* For zero copy XDP_TX action, dma_map is true */
> > +	res = stmmac_xdp_xmit_xdpf(priv, queue, xdpf, zc);
> 	Seems stmmac_xdp_xmit_xdpf is using dma_map_single if we pass zc is
> true.
>         Ideally in case of zc, driver can use page_pool_get_dma_addr, may be
> you
>         need pass zc param as false. Please check
> 

No, the memory type of xdpf->data is MEM_TYPE_PAGE_ORDER0 rather
than MEM_TYPE_PAGE_POOL, so we should use dma_map_single().
Otherwise, it will lead to invalid mappings and cause the crash.



From yeoreum.yun at arm.com  Wed Dec 17 04:52:13 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Wed, 17 Dec 2025 12:52:13 +0000
Subject: [PATCH 0/2] introduce pagetable_alloc_nolock()
In-Reply-To: <d96ac977-222e-4e8d-9487-da1306198419@arm.com>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com>
 <916c17ba-22b1-456e-a184-cb3f60249af7@arm.com>
 <aUGOPd7gNRf1xHEc@e129823.arm.com>
 <100cc8da-b826-4fc2-a624-746bf6fb049d@arm.com>
 <aUKKZR0u22KOPfd7@e129823.arm.com>
 <d96ac977-222e-4e8d-9487-da1306198419@arm.com>
Message-ID: <aUKnfU/3FREY13g1@e129823.arm.com>

> On 17/12/2025 10:48, Yeoreum Yun wrote:
> > Hi Ryan,
> >
> >> On 16/12/2025 16:52, Yeoreum Yun wrote:
> >>> Hi Ryan,
> >>>
> >>>> On 12/12/2025 16:18, Yeoreum Yun wrote:
> >>>>> Some architectures invoke pagetable_alloc() or __get_free_pages()
> >>>>> with preemption disabled.
> >>>>> For example, in arm64, linear_map_split_to_ptes() calls pagetable_alloc()
> >>>>> while spliting block entry to ptes and __kpti_install_ng_mappings()
> >>>>> calls __get_free_pages() to create kpti pagetable.
> >>>>>
> >>>>> Under PREEMPT_RT, calling pagetable_alloc() with
> >>>>> preemption disabled is not allowed, because it may acquire
> >>>>> a spin lock that becomes sleepable on RT, potentially
> >>>>> causing a sleep during page allocation.
> >>>>>
> >>>>> Since above two functions is called as callback of stop_machine()
> >>>>> where its callback is called in preemption disabled,
> >>>>> They could make a potential problem. (sleeping in preemption disabled).
> >>>>>
> >>>>> To address this, introduce pagetable_alloc_nolock() API.
> >>>>
> >>>> I don't really understand what the problem is that you're trying to fix. As I
> >>>> see it, there are 2 call sites in arm64 arch code that are calling into the page
> >>>> allocator from stop_machine() - one via via pagetable_alloc() and another via
> >>>> __get_free_pages(). But both of those calls are passing in GFP_ATOMIC. It was my
> >>>> understanding that the page allocator would ensure it never sleeps when
> >>>> GFP_ATOMIC is passed in, (even for PREEMPT_RT)?
> >>>
> >>> Although GFP_ATOMIC is specify, it only affects of "water mark" of the
> >>> page with __GFP_HIGH. and to get a page, it must grab the lock --
> >>> zone->lock or pcp_lock in the rmqueue().
> >>>
> >>> This zone->lock and pcp_lock is spin_lock and it's a sleepable in
> >>> PREEMPT_RT that's why the memory allocation/free using general API
> >>> except nolock() version couldn't be called since
> >>> if "contention" happens they'll sleep while waiting to get the lock.
> >>>
> >>> The reason why "nolock()" can use, it always uses "trylock" with
> >>> ALLOC_TRYLOCK flags. otherwise GFP_ATOMIC also can be sleepable in
> >>> PREEMPT_RT.
> >>>
> >>>>
> >>>> What is the actual symptom you are seeing?
> >>>
> >>> Since the place where called while smp_cpus_done() and there seems no
> >>> contention, there seems no problem. However as I mention in another
> >>> thread
> >>> (https://lore.kernel.org/all/aT%2FdrjN1BkvyAGoi at e129823.arm.com/),
> >>> This gives a the false impression --
> >>> GFP_ATOMIC are ?safe to use in preemption disabled?
> >>> even though they are not in PREEMPT_RT case, I've changed it.
> >>>
> >>>>
> >>>> If the page allocator is somehow ignoring the GFP_ATOMIC request for PREEMPT_RT,
> >>>> then isn't that a bug in the page allocator? I'm not sure why you would change
> >>>> the callsites? Can't you just change the page allocator based on GFP_ATOMIC?
> >>>
> >>> It doesn't ignore the GFP_ATOMIC feature:
> >>>   - __GFP_HIGH: use water mark till min reserved
> >>>   - __GFP_KSWAPD_RECLAIM: wake up kswapd if reclaim required.
> >>>
> >>> But, it's a restriction -- "page allocation / free" API cannot be called
> >>> in preempt-disabled context at PREEMPT_RT.
> >>>
> >>> That's why I think it's wrong usage not a page allocator bug.
> >>
> >> I've taken a look at this and I agree with your analysis. Thanks for explaining.
> >>
> >> Looking at other stop_machine() callbacks, there are some that call printk() and
> >> I would assume that spinlocks could be taken there which may present the same
> >> kind of issue or PREEMPT_RT? (I'm guessing). I don't see any others that attempt
> >> to allocate memory though.
> >
> > IIRC, there was a problem related for printk while try to grab
> > pl011_console related lock (spin_lock) while holding
> > console_lock(raw_spin_lock) in v6.10.0-rc7 at rpi5:
> >
> >     [  230.381263] CPU: 2 PID: 5574 Comm: syz.4.1695 Not tainted 6.10.0-rc7-01903-g52828ea60dfd #3
> >     [  230.381479] Hardware name: linux,dummy-virt (DT)
> >     [  230.381565] Call trace:
> >     [  230.381607]  dump_backtrace+0x318/0x348
> >     [  230.381727]  show_stack+0x4c/0x80
> >     [  230.381875]  dump_stack_lvl+0x214/0x328
> >     [  230.382159]  dump_stack+0x3c/0x58
> >     [  230.382456]  __lock_acquire+0x4398/0x4720
> >     [  230.382683]  lock_acquire+0x648/0xb70
> >     [  230.382928]  _raw_spin_lock_irqsave+0x138/0x240
> >     [  230.383121]  pl011_console_write+0x240/0x8a0
> >     [  230.383356]  console_flush_all+0x708/0x1368
> >     [  230.383571]  console_unlock+0x180/0x440
> >     [  230.383742]  vprintk_emit+0x1f8/0x9d0
> >     [  230.383832]  vprintk_default+0x64/0x90
> >     [  230.383914]  vprintk+0x2d0/0x400
> >     [  230.383971]  _printk+0xdc/0x128
> >     [  230.384229]  hrtimer_interrupt+0x8f0/0x920
> >     [  230.384414]  arch_timer_handler_virt+0xc0/0x100
> >     [  230.384812]  handle_percpu_devid_irq+0x20c/0x4e0
> >     [  230.385053]  generic_handle_domain_irq+0xc0/0x120
> >     [  230.385367]  gic_handle_irq+0x88/0x360
> >     [  230.385559]  call_on_irq_stack+0x24/0x70
> >     [  230.385801]  do_interrupt_handler+0xf8/0x200
> >     [  230.386092]  el1_interrupt+0x68/0xc0
> >     [  230.386434]  el1h_64_irq_handler+0x18/0x28
> >     [  230.386716]  el1h_64_irq+0x64/0x68
> >     [  230.386853]  __sanitizer_cov_trace_const_cmp2+0x30/0x68
> >     [  230.387026]  alloc_pages_mpol_noprof+0x170/0x698
> >     [  230.387309]  vma_alloc_folio_noprof+0x128/0x2a8
> >     [  230.387610]  vma_alloc_zeroed_movable_folio+0xa0/0xe0
> >     [  230.387822]  folio_prealloc+0x5c/0x280
> >     [  230.388008]  do_wp_page+0xc30/0x3bc0
> >     [  230.388206]  __handle_mm_fault+0xdb8/0x2ba0
> >     [  230.388448]  handle_mm_fault+0x194/0x8a8
> >     [  230.388676]  do_page_fault+0x6bc/0x1030
> >     [  230.388924]  do_mem_abort+0x8c/0x240
> >     [  230.389056]  el0_da+0xf0/0x3f8
> >     [  230.389178]  el0t_64_sync_handler+0xb4/0x130
> >     [  230.389452]  el0t_64_sync+0x190/0x198
> >
> > But this problem is gone when I try with some of patches in rt-tree
> > related for printk which are merged in current tree
> > (https://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git/log/?h=linux-6.10.y-rt-rebase).
> >
> > So I think printk() wouldn't be a problem.
> >
> >>
> >> Anyway, to fix the 2 arm64 callsites, I see 2 possible approaches:
> >>
> >> - Call the nolock variant (as you are doing). But that would just convert a
> >> deadlock to a panic; if the lock is held when stop_machine() runs, without your
> >> change, we now have a deadlock due to waiting on the lock inside stop_machine().
> >> With your change, we notice the lock is already taken and panic. I guess it is
> >> marginally better, but not by much. Certainly I would just _always_ call the
> >> nolock variant regardless of PREEMPT_RT if we take this route; For !PREEMPT_RT,
> >> the lock is guarranteed to be free so nolock will always succeed.
> >>
> >> - Preallocate the memory before entering stop_machine(). I think this would be
> >> much more robust. For kpti_install_ng_mappings() I think you could hoist the
> >> allocation/free out of stop_machine() and pass the pointer in pretty easily. For
> >> linear_map_split_to_ptes() its a bit more complex; Perhaps, we need to walk the
> >> pgtable to figure out how much to preallocate, allocate it, then set it up as a
> >> special allocator, wrapped by an allocation function and modify the callchain to
> >> take a callback function instead of gfp flags.
> >>
> >> What do you think?
> >
> > Definitely, second suggestoin is much better.
> > My question is whether *memory contention* really happen in the point
> > both functions are called.
>
> My guess would be that it's unlikely, but not impossible. The secondary CPUs are
> up, and presumably running their idle thread. I think various power management
> things can be plugged into the idle thread; if so, then I guess it's possible
> that the CPU could be running some hook as part of a power state transition, and
> that could be dynamically allocating memory? That's all just a guess though; I
> don't know the details of that part of the system.
>
> >
> > Above two functions are called as last step of "smp_init()" -- smp_cpus_done().
> > If we can be sure, I think we don't need to go to complex way and
> > I believe the reason why we couldn't find out this problem,
> > even using GFP_ATOMIC in PREEMPT_RT since there was *no contection*
> > in this time of both functions are called.
> > > That's why I first try with the "simple way".
> >
> > What do you think?
>
> As far as linear_map_split_to_ptes() is concerned, it was implemented under the
> impression that doing allocation with GFP_ATOMIC was safe, even in
> stop_machine(). Given that's an incorrect assumption, I think we should fix it
> to pre-allocate outside of stop_machine() regardless of the likelihood of
> actually hitting the race.
>

Yeap. It?s better to be certain than uncertain. Thanks for checking.
I'll repsin with the preallocate way.

Thanks!

--
Sincerely,
Yeoreum Yun


From daniel.baluta at gmail.com  Wed Dec 17 04:57:24 2025
From: daniel.baluta at gmail.com (Daniel Baluta)
Date: Wed, 17 Dec 2025 14:57:24 +0200
Subject: [PATCH v2] remoteproc: imx_dsp_rproc: Fix multiple start/stop operations
In-Reply-To: <aUHZaapZ1IAs_mRE@p14s>
References: <20251210154906.99210-1-daniel.baluta@nxp.com> <aUHZaapZ1IAs_mRE@p14s>
Message-ID: <CAEnQRZC0WU+MGfZ5z3yJCz==MBCcFG4BUwNs2v1ABOMkiRbPrw@mail.gmail.com>

On Wed, Dec 17, 2025 at 12:13?AM Mathieu Poirier
<mathieu.poirier at linaro.org> wrote:
>
> Good day,
>
> On Wed, Dec 10, 2025 at 05:49:06PM +0200, Daniel Baluta wrote:
> > After commit 67a7bc7f0358 ("remoteproc: Use of reserved_mem_region_*
> > functions for "memory-region"") following commands with
> > imx-dsp-rproc started to fail:
> >
> > $ echo zephyr.elf > /sys/class/remoteproc/remoteproc0/firmware
> > $ echo start > /sys/class/remoteproc/remoteproc0/state
> > $ echo stop > /sys/class/remoteproc/remoteproc0/state
> > $ echo start > /sys/class/remoteproc/remoteproc0/state #! This fails
> > -sh: echo: write error: Device or resource busy
> >
> > This happens because aforementioned commit replaced devm_ioremap_wc with
> > devm_ioremap_resource_wc which will "reserve" the memory region with the
> > first start and then will fail at the second start if the memory
> > region is already reserved.
> >
> > Even partially reverting the faulty commit won't fix the
> > underlying issue because we map the address in prepare() but we never
> > unmap it at unprepare(), so we will keep leaking memory regions.
> >
> > So, lets use alloc() and release() callbacks for memory carveout
> > handling. This will nicely map() the memory region at prepare() time
> > and unmap() it at unprepare().
> >
> > Fixes: 67a7bc7f0358 ("remoteproc: Use of_reserved_mem_region_* functions for "memory-region"")
> > Signed-off-by: Daniel Baluta <daniel.baluta at nxp.com>
> > ---
> > Changes since v1:
> >  * https://lore.kernel.org/imx/091a4f29-5435-428a-9a1c-ef82465211cb at nxp.com/T/#t
> >  * took a different approach and instead of partially reverting the
> >   faulty patch, used alloc() and release() callbacks to handle memory
> >   region mapping.
> >  drivers/remoteproc/imx_dsp_rproc.c | 50 ++++++++++++++++++++----------
> >  1 file changed, 33 insertions(+), 17 deletions(-)
> >
> > diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c
> > index 5130a35214c9..83468558e634 100644
> > --- a/drivers/remoteproc/imx_dsp_rproc.c
> > +++ b/drivers/remoteproc/imx_dsp_rproc.c
> > @@ -644,6 +644,32 @@ static void imx_dsp_rproc_free_mbox(struct imx_dsp_rproc *priv)
> >       mbox_free_channel(priv->rxdb_ch);
> >  }
> >
> > +static int imx_dsp_rproc_mem_alloc(struct rproc *rproc,
> > +                                struct rproc_mem_entry *mem)
> > +{
> > +     struct device *dev = rproc->dev.parent;
> > +     void *va;
> > +
> > +     va = ioremap_wc(mem->dma, mem->len);
> > +     if (!va) {
> > +             dev_err(dev, "Unable to map memory region: %pa+%zx\n",
> > +                     &mem->dma, mem->len);
> > +             return -ENOMEM;
> > +     }
> > +
> > +     mem->va = va;
> > +
> > +     return 0;
> > +}
> > +
> > +static int imx_dsp_rproc_mem_release(struct rproc *rproc,
> > +                                  struct rproc_mem_entry *mem)
> > +{
> > +     iounmap(mem->va);
> > +
> > +     return 0;
> > +}
> > +
> >  /**
> >   * imx_dsp_rproc_add_carveout() - request mailbox channels
> >   * @priv: private data pointer
> > @@ -659,7 +685,6 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv)
> >       struct device *dev = rproc->dev.parent;
> >       struct device_node *np = dev->of_node;
> >       struct rproc_mem_entry *mem;
> > -     void __iomem *cpu_addr;
> >       int a, i = 0;
> >       u64 da;
> >
> > @@ -673,15 +698,10 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv)
> >               if (imx_dsp_rproc_sys_to_da(priv, att->sa, att->size, &da))
> >                       return -EINVAL;
> >
> > -             cpu_addr = devm_ioremap_wc(dev, att->sa, att->size);
> > -             if (!cpu_addr) {
> > -                     dev_err(dev, "failed to map memory %p\n", &att->sa);
> > -                     return -ENOMEM;
> > -             }
> > -
> >               /* Register memory region */
> > -             mem = rproc_mem_entry_init(dev, (void __force *)cpu_addr, (dma_addr_t)att->sa,
> > -                                        att->size, da, NULL, NULL, "dsp_mem");
> > +             mem = rproc_mem_entry_init(dev, NULL, (dma_addr_t)att->sa,
> > +                                        att->size, da, imx_dsp_rproc_mem_alloc,
> > +                                        imx_dsp_rproc_mem_release, "dsp_mem");
>
> Was there a reason you kept those here rather than moving them to probe() as
> Iuliana suggested?  Note that I would be fine with this solution since this is
> how it was before, but if we have to go through a refactoring we may as well
> take those things into account.

Tried moving imx_dsp_rproc_add_carveout at probe() time but it doesn't work
because stop() will clean the carveout list and then the next start() will fail.

at probe()
imx_dsp_rproc_add_carveout
-> rproc_add_carveout (adds allocated carveout to the list).

at start():
   -> first start OK

at stop()
   -> rproc_shutdown
       -> rproc_stop
       -> rproc_resource_cleanup ;//cleans up careveout allocations

at next start()
     -> CRASH


From robh at kernel.org  Wed Dec 17 04:57:47 2025
From: robh at kernel.org (Rob Herring)
Date: Wed, 17 Dec 2025 06:57:47 -0600
Subject: [PATCH v5] dt-bindings: arm: keystone: add boot_* mboxes to
 ti,sci
In-Reply-To: <20251215135708.ij5e7jr3binzmlbf@panda>
References: <20251215-k3_syscon_add_boot_mailboxes-v5-1-5a8fe567fd31@ti.com>
 <20251215135708.ij5e7jr3binzmlbf@panda>
Message-ID: <20251217125747.GA689283-robh@kernel.org>

On Mon, Dec 15, 2025 at 07:57:08AM -0600, Nishanth Menon wrote:
> On 11:38-20251215, Anshul Dalal wrote:
> > The bootloader on K3 devices makes use of mailboxes as per the ROM spec
> > which might be different than one's available to the kernel (firmware
> > spec).
> > 
> > Therefore, this patch adds the missing mailbox entries to the DT binding
> > if the matching compatible is ti,am654-sci to represent the mailboxes
> > exposed by the hardware during boot for the purpose of loading the
> > firmware. The newly added mboxes are made optional by keeping minItems
> > as 2 to remain compliant with existing device-trees.
> > 
> > Signed-off-by: Anshul Dalal <anshuld at ti.com>
> > ---
> > Changes in v5:
> > - Added commit description for the optional mailboxes
> > - Link to v4: https://lore.kernel.org/r/20251205-k3_syscon_add_boot_mailboxes-v4-1-8e216fb88941 at ti.com
> > 
> > Changes in v4:
> > - Make new boot_* mboxes conditional on ti,am654-sci compatible
> > - Link to v3: https://lore.kernel.org/r/20251112-k3_syscon_add_boot_mailboxes-v3-1-66155a4236dc at ti.com
> > 
> > Changes in v3:
> > - Drop [1/2] of the last patch series
> > - Update existing example with boot_* mailboxes instead of adding a new one
> > - Link to v2: https://lore.kernel.org/r/20251112-k3_syscon_add_boot_mailboxes-v2-0-aebc1e47b391 at ti.com
> > 
> > Changes in v2:
> > - Remove maxItems entry
> > - Remove RFC tag from patch (added by mistake in v1)
> > - Document the new mailboxes in mboxes instead of mbox-names
> > - Provide example with all the mailboxes set
> > - Update commit title to have "ti,sci"
> > - Split into two patches
> > - Link to v1: https://lore.kernel.org/r/20251111-k3_syscon_add_boot_mailboxes-v1-1-529a27f21076 at ti.com
> > ---
> >  .../devicetree/bindings/arm/keystone/ti,sci.yaml   | 50 +++++++++++++++++++---
> >  1 file changed, 43 insertions(+), 7 deletions(-)
> > 
> > diff --git a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
> > index 25a2b42105e5..d9eb2a81e539 100644
> > --- a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
> > +++ b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
> > @@ -51,15 +51,15 @@ properties:
> >      minItems: 1
> >  
> >    mbox-names:
> > +    minItems: 2
> > +    maxItems: 6
> >      description: |
> >        Specifies the mailboxes used to communicate with TI-SCI Controller
> >        made available from TI-SCI controller.
> > -    items:
> > -      - const: rx
> > -      - const: tx
> >  
> >    mboxes:
> >      minItems: 2
> > +    maxItems: 6
> >  
> >    ti,host-id:
> >      $ref: /schemas/types.yaml#/definitions/uint32
> > @@ -79,6 +79,42 @@ properties:
> >      type: object
> >      $ref: /schemas/reset/ti,sci-reset.yaml#
> >  
> > +if:
> > +  properties:
> > +    compatible:
> > +      contains:
> > +        const: ti,am654-sci
> > +then:
> > +  properties:
> > +    mbox-names:
> > +      minItems: 2
> > +      items:
> > +        - const: rx
> > +        - const: tx
> > +        - const: notify
> > +        - const: boot_rx
> > +        - const: boot_tx
> > +        - const: boot_notify
> > +    mboxes:
> > +      minItems: 2
> > +      items:
> > +        - description: RX thread
> > +        - description: TX thread
> > +        - description: Notify thread
> > +        - description: boot stage RX thread
> > +        - description: boot stage TX thread
> > +        - description: boot stage Notify thread
> > +else:
> > +  properties:
> > +    mbox-names:
> > +      items:
> > +        - const: rx
> > +        - const: tx
> > +    mboxes:
> > +      items:
> > +        - description: RX thread
> > +        - description: TX thread
> > +
> >  required:
> >    - compatible
> >    - mbox-names
> > @@ -99,11 +135,11 @@ examples:
> >  
> >    - |
> >      dmsc: system-controller at 44083000 {
> > -      compatible = "ti,k2g-sci";
> > +      compatible = "ti,am654-sci";
> >        ti,host-id = <12>;
> > -      mbox-names = "rx", "tx";
> > -      mboxes = <&secure_proxy_main 11>,
> > -               <&secure_proxy_main 13>;
> > +      mbox-names = "rx", "tx", "notify", "boot_rx", "boot_tx";
> > +      mboxes= <&secure_proxy_mcu 6>, <&secure_proxy_mcu 8>,
> > +        <&secure_proxy_mcu 5>, <&secure_proxy_mcu 5>, <&secure_proxy_mcu 4>;
> >        reg-names = "debug_messages";
> >        reg = <0x44083000 0x1000>;
> 
> Please add a different example for am654, i want to make sure k2g still
> continues to be checked.
> 
> That said, AM62 series of devices do not use notification pipe for
> standard communication. So, the schema will break for those.
> 
> in summary:
> k2g: rx, tx
> am654, j721e, j721s2, j7200, j784s4, .. : rx, tx, notify, boot_rx,
> boot_tx, boot_notify
> am625, am62p ..: rx, tx, boot_rx, boot_tx, boot_notify
> 
> we will need three examples, and will need to add am62x series as one
> additional compatible.

Do we really? We have a whole tree of examples in .dts files.

Rob


From nicolas.frattaroli at collabora.com  Wed Dec 17 04:57:46 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Wed, 17 Dec 2025 13:57:46 +0100
Subject: [PATCH v2 1/4] dt-bindings: input: adc-keys: allow linux,input-type
 property
In-Reply-To: <20251217-tough-ultra-junglefowl-f1a9ae@quoll>
References: <20251215-rock4d-audio-v2-0-82a61de39b4c@collabora.com>
 <20251215-rock4d-audio-v2-1-82a61de39b4c@collabora.com>
 <20251217-tough-ultra-junglefowl-f1a9ae@quoll>
Message-ID: <6778765.lOV4Wx5bFT@workhorse>

On Wednesday, 17 December 2025 09:31:15 Central European Standard Time Krzysztof Kozlowski wrote:
> On Mon, Dec 15, 2025 at 01:29:29PM +0100, Nicolas Frattaroli wrote:
> > adc-keys, unlike gpio-keys, does not allow linux,input-type as a valid
> > property. This makes it impossible to model devices that have ADC inputs
> > that should generate switch events.
> 
> The solution is to use unevaluatedProps instead, which also allows
> dropping other properties.
> 
> Best regards,
> Krzysztof
> 
> 

Hi Krzysztof,

to understand the motivation behind this suggestion correctly:
are the "linux," vendor prefixed properties, especially with regards
to key codes, generally a bit of a thorn in the side of DT bindings
maintainers?

I'd imagine so since they technically tie the DT to a specific OS
kernel (though of course, others are free to translate those key
codes). And the whole idea of configuring which code is emitted
from something is basically abusing DT for configuring software
rather than describing hardware.

I'm mainly interested because this is a thought that has been in
the back of my mind for a while now, and I'm curious if the DT
binding maintainers happen to have arrived at the same impass?,
where linux,input-type et al abuse the DT model for something we
would tell any other vendor not to abuse it for, but no better
solution exists right now to achieve the same thing.

Kind regards,
Nicolas Frattaroli





From vbabka at suse.cz  Wed Dec 17 05:15:42 2025
From: vbabka at suse.cz (Vlastimil Babka)
Date: Wed, 17 Dec 2025 14:15:42 +0100
Subject: [PATCH 0/2] introduce pagetable_alloc_nolock()
In-Reply-To: <aUKnfU/3FREY13g1@e129823.arm.com>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com>
 <916c17ba-22b1-456e-a184-cb3f60249af7@arm.com>
 <aUGOPd7gNRf1xHEc@e129823.arm.com>
 <100cc8da-b826-4fc2-a624-746bf6fb049d@arm.com>
 <aUKKZR0u22KOPfd7@e129823.arm.com>
 <d96ac977-222e-4e8d-9487-da1306198419@arm.com>
 <aUKnfU/3FREY13g1@e129823.arm.com>
Message-ID: <d912480a-5229-4efe-9336-b31acded30f5@suse.cz>

On 12/17/25 13:52, Yeoreum Yun wrote:
>> On 17/12/2025 10:48, Yeoreum Yun wrote:
>> > Hi Ryan,
>> >
>> >> On 16/12/2025 16:52, Yeoreum Yun wrote:
>> >>> Hi Ryan,
>> >>>
>> >>>> On 12/12/2025 16:18, Yeoreum Yun wrote:
>> >>>>> Some architectures invoke pagetable_alloc() or __get_free_pages()
>> >>>>> with preemption disabled.
>> >>>>> For example, in arm64, linear_map_split_to_ptes() calls pagetable_alloc()
>> >>>>> while spliting block entry to ptes and __kpti_install_ng_mappings()
>> >>>>> calls __get_free_pages() to create kpti pagetable.
>> >>>>>
>> >>>>> Under PREEMPT_RT, calling pagetable_alloc() with
>> >>>>> preemption disabled is not allowed, because it may acquire
>> >>>>> a spin lock that becomes sleepable on RT, potentially
>> >>>>> causing a sleep during page allocation.
>> >>>>>
>> >>>>> Since above two functions is called as callback of stop_machine()
>> >>>>> where its callback is called in preemption disabled,
>> >>>>> They could make a potential problem. (sleeping in preemption disabled).
>> >>>>>
>> >>>>> To address this, introduce pagetable_alloc_nolock() API.
>> >>>>
>> >>>> I don't really understand what the problem is that you're trying to fix. As I
>> >>>> see it, there are 2 call sites in arm64 arch code that are calling into the page
>> >>>> allocator from stop_machine() - one via via pagetable_alloc() and another via
>> >>>> __get_free_pages(). But both of those calls are passing in GFP_ATOMIC. It was my
>> >>>> understanding that the page allocator would ensure it never sleeps when
>> >>>> GFP_ATOMIC is passed in, (even for PREEMPT_RT)?
>> >>>
>> >>> Although GFP_ATOMIC is specify, it only affects of "water mark" of the
>> >>> page with __GFP_HIGH. and to get a page, it must grab the lock --
>> >>> zone->lock or pcp_lock in the rmqueue().
>> >>>
>> >>> This zone->lock and pcp_lock is spin_lock and it's a sleepable in
>> >>> PREEMPT_RT that's why the memory allocation/free using general API
>> >>> except nolock() version couldn't be called since
>> >>> if "contention" happens they'll sleep while waiting to get the lock.
>> >>>
>> >>> The reason why "nolock()" can use, it always uses "trylock" with
>> >>> ALLOC_TRYLOCK flags. otherwise GFP_ATOMIC also can be sleepable in
>> >>> PREEMPT_RT.
>> >>>
>> >>>>
>> >>>> What is the actual symptom you are seeing?
>> >>>
>> >>> Since the place where called while smp_cpus_done() and there seems no
>> >>> contention, there seems no problem. However as I mention in another
>> >>> thread
>> >>> (https://lore.kernel.org/all/aT%2FdrjN1BkvyAGoi at e129823.arm.com/),
>> >>> This gives a the false impression --
>> >>> GFP_ATOMIC are ?safe to use in preemption disabled?
>> >>> even though they are not in PREEMPT_RT case, I've changed it.
>> >>>
>> >>>>
>> >>>> If the page allocator is somehow ignoring the GFP_ATOMIC request for PREEMPT_RT,
>> >>>> then isn't that a bug in the page allocator? I'm not sure why you would change
>> >>>> the callsites? Can't you just change the page allocator based on GFP_ATOMIC?
>> >>>
>> >>> It doesn't ignore the GFP_ATOMIC feature:
>> >>>   - __GFP_HIGH: use water mark till min reserved
>> >>>   - __GFP_KSWAPD_RECLAIM: wake up kswapd if reclaim required.
>> >>>
>> >>> But, it's a restriction -- "page allocation / free" API cannot be called
>> >>> in preempt-disabled context at PREEMPT_RT.
>> >>>
>> >>> That's why I think it's wrong usage not a page allocator bug.
>> >>
>> >> I've taken a look at this and I agree with your analysis. Thanks for explaining.
>> >>
>> >> Looking at other stop_machine() callbacks, there are some that call printk() and
>> >> I would assume that spinlocks could be taken there which may present the same
>> >> kind of issue or PREEMPT_RT? (I'm guessing). I don't see any others that attempt
>> >> to allocate memory though.
>> >
>> > IIRC, there was a problem related for printk while try to grab
>> > pl011_console related lock (spin_lock) while holding
>> > console_lock(raw_spin_lock) in v6.10.0-rc7 at rpi5:
>> >
>> >     [  230.381263] CPU: 2 PID: 5574 Comm: syz.4.1695 Not tainted 6.10.0-rc7-01903-g52828ea60dfd #3
>> >     [  230.381479] Hardware name: linux,dummy-virt (DT)
>> >     [  230.381565] Call trace:
>> >     [  230.381607]  dump_backtrace+0x318/0x348
>> >     [  230.381727]  show_stack+0x4c/0x80
>> >     [  230.381875]  dump_stack_lvl+0x214/0x328
>> >     [  230.382159]  dump_stack+0x3c/0x58
>> >     [  230.382456]  __lock_acquire+0x4398/0x4720
>> >     [  230.382683]  lock_acquire+0x648/0xb70
>> >     [  230.382928]  _raw_spin_lock_irqsave+0x138/0x240
>> >     [  230.383121]  pl011_console_write+0x240/0x8a0
>> >     [  230.383356]  console_flush_all+0x708/0x1368
>> >     [  230.383571]  console_unlock+0x180/0x440
>> >     [  230.383742]  vprintk_emit+0x1f8/0x9d0
>> >     [  230.383832]  vprintk_default+0x64/0x90
>> >     [  230.383914]  vprintk+0x2d0/0x400
>> >     [  230.383971]  _printk+0xdc/0x128
>> >     [  230.384229]  hrtimer_interrupt+0x8f0/0x920
>> >     [  230.384414]  arch_timer_handler_virt+0xc0/0x100
>> >     [  230.384812]  handle_percpu_devid_irq+0x20c/0x4e0
>> >     [  230.385053]  generic_handle_domain_irq+0xc0/0x120
>> >     [  230.385367]  gic_handle_irq+0x88/0x360
>> >     [  230.385559]  call_on_irq_stack+0x24/0x70
>> >     [  230.385801]  do_interrupt_handler+0xf8/0x200
>> >     [  230.386092]  el1_interrupt+0x68/0xc0
>> >     [  230.386434]  el1h_64_irq_handler+0x18/0x28
>> >     [  230.386716]  el1h_64_irq+0x64/0x68
>> >     [  230.386853]  __sanitizer_cov_trace_const_cmp2+0x30/0x68
>> >     [  230.387026]  alloc_pages_mpol_noprof+0x170/0x698
>> >     [  230.387309]  vma_alloc_folio_noprof+0x128/0x2a8
>> >     [  230.387610]  vma_alloc_zeroed_movable_folio+0xa0/0xe0
>> >     [  230.387822]  folio_prealloc+0x5c/0x280
>> >     [  230.388008]  do_wp_page+0xc30/0x3bc0
>> >     [  230.388206]  __handle_mm_fault+0xdb8/0x2ba0
>> >     [  230.388448]  handle_mm_fault+0x194/0x8a8
>> >     [  230.388676]  do_page_fault+0x6bc/0x1030
>> >     [  230.388924]  do_mem_abort+0x8c/0x240
>> >     [  230.389056]  el0_da+0xf0/0x3f8
>> >     [  230.389178]  el0t_64_sync_handler+0xb4/0x130
>> >     [  230.389452]  el0t_64_sync+0x190/0x198
>> >
>> > But this problem is gone when I try with some of patches in rt-tree
>> > related for printk which are merged in current tree
>> > (https://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git/log/?h=linux-6.10.y-rt-rebase).
>> >
>> > So I think printk() wouldn't be a problem.
>> >
>> >>
>> >> Anyway, to fix the 2 arm64 callsites, I see 2 possible approaches:
>> >>
>> >> - Call the nolock variant (as you are doing). But that would just convert a
>> >> deadlock to a panic; if the lock is held when stop_machine() runs, without your
>> >> change, we now have a deadlock due to waiting on the lock inside stop_machine().
>> >> With your change, we notice the lock is already taken and panic. I guess it is
>> >> marginally better, but not by much. Certainly I would just _always_ call the
>> >> nolock variant regardless of PREEMPT_RT if we take this route; For !PREEMPT_RT,
>> >> the lock is guarranteed to be free so nolock will always succeed.
>> >>
>> >> - Preallocate the memory before entering stop_machine(). I think this would be
>> >> much more robust. For kpti_install_ng_mappings() I think you could hoist the
>> >> allocation/free out of stop_machine() and pass the pointer in pretty easily. For
>> >> linear_map_split_to_ptes() its a bit more complex; Perhaps, we need to walk the
>> >> pgtable to figure out how much to preallocate, allocate it, then set it up as a
>> >> special allocator, wrapped by an allocation function and modify the callchain to
>> >> take a callback function instead of gfp flags.
>> >>
>> >> What do you think?
>> >
>> > Definitely, second suggestoin is much better.
>> > My question is whether *memory contention* really happen in the point
>> > both functions are called.
>>
>> My guess would be that it's unlikely, but not impossible. The secondary CPUs are
>> up, and presumably running their idle thread. I think various power management
>> things can be plugged into the idle thread; if so, then I guess it's possible
>> that the CPU could be running some hook as part of a power state transition, and
>> that could be dynamically allocating memory? That's all just a guess though; I
>> don't know the details of that part of the system.
>>
>> >
>> > Above two functions are called as last step of "smp_init()" -- smp_cpus_done().
>> > If we can be sure, I think we don't need to go to complex way and
>> > I believe the reason why we couldn't find out this problem,
>> > even using GFP_ATOMIC in PREEMPT_RT since there was *no contection*
>> > in this time of both functions are called.
>> > > That's why I first try with the "simple way".
>> >
>> > What do you think?
>>
>> As far as linear_map_split_to_ptes() is concerned, it was implemented under the
>> impression that doing allocation with GFP_ATOMIC was safe, even in
>> stop_machine(). Given that's an incorrect assumption, I think we should fix it
>> to pre-allocate outside of stop_machine() regardless of the likelihood of
>> actually hitting the race.
>>
> 
> Yeap. It?s better to be certain than uncertain. Thanks for checking.
> I'll repsin with the preallocate way.

Note this is explained in Documentation/core-api/real-time/differences.rst:

Memory allocation
-----------------

The memory allocation APIs, such as kmalloc() and alloc_pages(), require a
gfp_t flag to indicate the allocation context. On non-PREEMPT_RT kernels, it is
necessary to use GFP_ATOMIC when allocating memory from interrupt context or
from sections where preemption is disabled. This is because the allocator must
not sleep in these contexts waiting for memory to become available.

However, this approach does not work on PREEMPT_RT kernels. The memory
allocator in PREEMPT_RT uses sleeping locks internally, which cannot be
acquired when preemption is disabled. Fortunately, this is generally not a
problem, because PREEMPT_RT moves most contexts that would traditionally run
with preemption or interrupts disabled into threaded context, where sleeping is
allowed.

What remains problematic is code that explicitly disables preemption or
interrupts. In such cases, memory allocation must be performed outside the
critical section.

This restriction also applies to memory deallocation routines such as kfree()
and free_pages(), which may also involve internal locking and must not be
called from non-preemptible contexts.



From konrad.dybcio at oss.qualcomm.com  Wed Dec 17 05:21:03 2025
From: konrad.dybcio at oss.qualcomm.com (Konrad Dybcio)
Date: Wed, 17 Dec 2025 14:21:03 +0100
Subject: [PATCH v2 07/11] dt-bindings: clock: qcom: document the Kaanapali
 GPU Clock Controller
In-Reply-To: <e8bdb176-b6fb-4dd2-8b5b-9da8073fa915@kernel.org>
References: <20251125-kaanapali-mmcc-v2-v2-0-fb44e78f300b@oss.qualcomm.com>
 <20251125-kaanapali-mmcc-v2-v2-7-fb44e78f300b@oss.qualcomm.com>
 <20251126-elated-stoic-scorpion-25b630@kuoka>
 <de44560d-4ed8-41fe-be7b-56412b933a8c@oss.qualcomm.com>
 <fbe39eac-7c92-4a08-bafb-31e5c51a0613@kernel.org>
 <503f445e-0d12-407d-bc77-f48ad335639b@oss.qualcomm.com>
 <e8bdb176-b6fb-4dd2-8b5b-9da8073fa915@kernel.org>
Message-ID: <ca118faf-3451-4b83-9074-82bc5e1f731e@oss.qualcomm.com>

On 12/17/25 11:09 AM, Krzysztof Kozlowski wrote:
> On 17/12/2025 10:32, Taniya Das wrote:
>>>>
>>>> We would like to leverage the existing common clock driver(GDSC) code to
>>>
>>> Fix the driver code if it cannot handle other cells. Your drivers do not
>>> matter for choices made in bindings.
>>>
>>
>> As it is still a clock controller from hardware design and in SW I will
>> be map the entire hardware region and this way this clock controller
>> will also be aligned to the existing clock controllers and keep the
>> #power-domain-cells = <1> as other CCs.
> 
> I don't see how this resolves my comment.

Spanning the entire 0x6000-long block will remove your worry about this
description only being 2-register-wide

This block provides more than one GDSC - although again, not all of them
need/should be accessed by Linux. I suppose just enumerating the "extra"
ones in bindings will be a good enough compromise?

Konrad


From konrad.dybcio at oss.qualcomm.com  Wed Dec 17 05:22:59 2025
From: konrad.dybcio at oss.qualcomm.com (Konrad Dybcio)
Date: Wed, 17 Dec 2025 14:22:59 +0100
Subject: [PATCH v2 11/11] clk: qcom: Add support for GPUCC and GXCLK for
 Kaanapali
In-Reply-To: <20251125-kaanapali-mmcc-v2-v2-11-fb44e78f300b@oss.qualcomm.com>
References: <20251125-kaanapali-mmcc-v2-v2-0-fb44e78f300b@oss.qualcomm.com>
 <20251125-kaanapali-mmcc-v2-v2-11-fb44e78f300b@oss.qualcomm.com>
Message-ID: <ed17edd9-fd96-4562-a3dc-45cf7185f66a@oss.qualcomm.com>

On 11/25/25 6:45 PM, Taniya Das wrote:
> Support the graphics clock controller for Kaanapali for Graphics SW
> driver to use the clocks. GXCLKCTL (Graphics GX Clock Controller) is a
> block dedicated to managing clocks for the GPU subsystem on GX power
> domain. The GX clock controller driver manages only the GX GDSC and the
> rest of the resources of the controller are managed by the firmware.
> 
> Signed-off-by: Taniya Das <taniya.das at oss.qualcomm.com>
> ---
>  drivers/clk/qcom/Kconfig              |   9 +
>  drivers/clk/qcom/Makefile             |   1 +
>  drivers/clk/qcom/gpucc-kaanapali.c    | 494 ++++++++++++++++++++++++++++++++++
>  drivers/clk/qcom/gxclkctl-kaanapali.c |  76 ++++++

I previously proposed bunching the little guy with the other
object file:

https://lore.kernel.org/linux-arm-msm/20250723-topic-8750_gpucc-v2-2-56c93b84c390 at oss.qualcomm.com/

And I still think that's a better idea. Alternatively, we could
create a small "gxclkctl.c" and make it common across all such
platforms, but I'm not sure that makes sense, if for each one of
them we're already going to carry a gpucc-xyz.c anyway

Konrad


From gregkh at linuxfoundation.org  Wed Dec 17 05:24:27 2025
From: gregkh at linuxfoundation.org (Greg Kroah-Hartman)
Date: Wed, 17 Dec 2025 14:24:27 +0100
Subject: [PATCH v9 2/2] usb: dwc3: Add Google Tensor SoC DWC3 glue driver
In-Reply-To: <CA+zupgzL7v5MZDpxKDQQCqAZaqTdHbiG9-xTr+8RnigMFZJ_7Q@mail.gmail.com>
References: <20251205-controller-v9-0-9f158b18f979@google.com>
 <20251205-controller-v9-2-9f158b18f979@google.com>
 <2025120553-suffrage-divisive-5890@gregkh>
 <CA+zupgzL7v5MZDpxKDQQCqAZaqTdHbiG9-xTr+8RnigMFZJ_7Q@mail.gmail.com>
Message-ID: <2025121728-reliably-crabgrass-2601@gregkh>

On Thu, Dec 04, 2025 at 11:14:39PM -0800, Roy Luo wrote:
> On Thu, Dec 4, 2025 at 10:05?PM Greg Kroah-Hartman
> <gregkh at linuxfoundation.org> wrote:
> >
> > On Fri, Dec 05, 2025 at 02:26:38AM +0000, Roy Luo wrote:
> > > +config USB_DWC3_GOOGLE
> > > +     tristate "Google Platform"
> > > +     depends on ARCH_GOOGLE || COMPILE_TEST
> >
> > There is no ARCH_GOOGLE in the tree now, so how is this supposed to
> > work?  Shouldn't tools that check for "invalid config options" trigger
> > on this?
> >
> > thanks,
> >
> > greg k-h
> 
> Hi Greg,
> 
> The menuconfig looks like the following and it doesn't complain:
> | Symbol: ARCH_GOOGLE [=ARCH_GOOGLE]
> | Type  : unknown
> |
> | Symbol: PHY_GOOGLE_USB [=y]
> | Type  : tristate
> | Defined at drivers/phy/Kconfig:104
> |     Prompt: Google Tensor SoC USB PHY driver
> |     Depends on: ARCH_GOOGLE || COMPILE_TEST [=y]
> 
> According to Kconfig documentation [1], the unknown symbol
> would simply be evaluated as an "n", which is what we want.
> "Convert the symbol into an expression. Boolean and tristate
> symbols are simply converted into the respective expression
> values. All other symbol types result in ?n?."
> 
> In a different Kconfig documentation, an environment variable
> "KCONFIG_WARN_UNKNOWN_SYMBOLS" is there to detect
> undefined symbols in the "config input", but I can't find one that
> catches undefined symbols in the Kconfig tree itself.
> 
> That is, the tool seems to allow this.
> However, if this turns out to be a major problem. I think we
> can either:
> - Remove ARCH_GOOGLE and leave COMPILE_TEST as
>   the only dependency. Then add ARCH_GOOGLE back
>   later once it's in the tree.

Please do this.  I do not want to take patches that purposfully add
dependencies on config options that might, or might not, appear in the
future.  Please just remove all of the dependancies for now, as they are
not needed, right?

thanks,

greg k-h


From nicolas.dufresne at collabora.com  Wed Dec 17 05:34:33 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Wed, 17 Dec 2025 08:34:33 -0500
Subject: [PATCH v5 01/15] media: uapi: HEVC: Add
 v4l2_ctrl_hevc_ext_sps_[ls]t_rps controls
In-Reply-To: <e88eb64e-ae47-4c70-87af-44c8f0371be9@collabora.com>
References: <20251023214247.459931-1-detlev.casanova@collabora.com>
	 <20251023214247.459931-2-detlev.casanova@collabora.com>
	 <d8ef0f88-e81d-4159-8945-52197cbc95ba@kernel.org>
	 <37da2fe3-41bd-470e-bb6c-93fe35ee1528@collabora.com>
	 <bcbf8247a778c0a179cef2e0338acb2266c18809.camel@collabora.com>
	 <e88eb64e-ae47-4c70-87af-44c8f0371be9@collabora.com>
Message-ID: <0482b76919217cf007d0abe1c683e862903a1a40.camel@collabora.com>

Hi,

Le mardi 16 d?cembre 2025 ? 17:18 -0500, Detlev Casanova a ?crit?:
> > Before going that route, how big are these two arrays ? Short term can be 64
> > ref, long term 32, how big in bytes that is ? Was is worth goign with
> > dynamic
> > array ? Its not like slices, where we can have 600 or more.
> 
> The short term one can still be quite big, it's about 80 bytes per 
> element, so 5120 bytes for the 64.
> 
> I don't know how often we go that high, I've seen around 10 short term 
> ref sets in test videos.

We've never defined a threshold, so its hard to just define which direction to
go. I generally think using dynamic array was logical thing to do though.

Nicolas
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251217/8f32e54f/attachment-0001.sig>

From robh at kernel.org  Wed Dec 17 05:34:40 2025
From: robh at kernel.org (Rob Herring)
Date: Wed, 17 Dec 2025 07:34:40 -0600
Subject: [PATCH v2 1/4] dt-bindings: input: adc-keys: allow
 linux,input-type property
In-Reply-To: <6778765.lOV4Wx5bFT@workhorse>
References: <20251215-rock4d-audio-v2-0-82a61de39b4c@collabora.com>
 <20251215-rock4d-audio-v2-1-82a61de39b4c@collabora.com>
 <20251217-tough-ultra-junglefowl-f1a9ae@quoll>
 <6778765.lOV4Wx5bFT@workhorse>
Message-ID: <20251217133440.GA724723-robh@kernel.org>

On Wed, Dec 17, 2025 at 01:57:46PM +0100, Nicolas Frattaroli wrote:
> On Wednesday, 17 December 2025 09:31:15 Central European Standard Time Krzysztof Kozlowski wrote:
> > On Mon, Dec 15, 2025 at 01:29:29PM +0100, Nicolas Frattaroli wrote:
> > > adc-keys, unlike gpio-keys, does not allow linux,input-type as a valid
> > > property. This makes it impossible to model devices that have ADC inputs
> > > that should generate switch events.
> > 
> > The solution is to use unevaluatedProps instead, which also allows
> > dropping other properties.
> > 
> > Best regards,
> > Krzysztof
> > 
> > 
> 
> Hi Krzysztof,
> 
> to understand the motivation behind this suggestion correctly:
> are the "linux," vendor prefixed properties, especially with regards
> to key codes, generally a bit of a thorn in the side of DT bindings
> maintainers?

Not really. Most have existed for decades. New ones get extra scrutiny 
and often end up dropping the linux prefix.

> I'd imagine so since they technically tie the DT to a specific OS
> kernel (though of course, others are free to translate those key
> codes). And the whole idea of configuring which code is emitted
> from something is basically abusing DT for configuring software
> rather than describing hardware.
> 
> I'm mainly interested because this is a thought that has been in
> the back of my mind for a while now, and I'm curious if the DT
> binding maintainers happen to have arrived at the same impass?,
> where linux,input-type et al abuse the DT model for something we
> would tell any other vendor not to abuse it for, but no better
> solution exists right now to achieve the same thing.

Not sure what the BSDs do here. It's never come up that I remember. Best 
I can tell is they just make it a userspace problem. So every possible 
keyboard needs a keymap file. Though I'm not sure how that would work 
with GPIO keys as you don't really have a scan code.

Rob


From jackmanb at google.com  Wed Dec 17 05:35:37 2025
From: jackmanb at google.com (Brendan Jackman)
Date: Wed, 17 Dec 2025 13:35:37 +0000
Subject: [PATCH 0/2] introduce pagetable_alloc_nolock()
In-Reply-To: <d912480a-5229-4efe-9336-b31acded30f5@suse.cz>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com> <916c17ba-22b1-456e-a184-cb3f60249af7@arm.com>
 <aUGOPd7gNRf1xHEc@e129823.arm.com> <100cc8da-b826-4fc2-a624-746bf6fb049d@arm.com>
 <aUKKZR0u22KOPfd7@e129823.arm.com> <d96ac977-222e-4e8d-9487-da1306198419@arm.com>
 <aUKnfU/3FREY13g1@e129823.arm.com> <d912480a-5229-4efe-9336-b31acded30f5@suse.cz>
Message-ID: <DF0J58HOVLL4.2E16Q87D2UXRW@google.com>

On Wed Dec 17, 2025 at 1:15 PM UTC, Vlastimil Babka wrote:
> On 12/17/25 13:52, Yeoreum Yun wrote:
>>> On 17/12/2025 10:48, Yeoreum Yun wrote:
>>> > Hi Ryan,
>>> >
>>> >> On 16/12/2025 16:52, Yeoreum Yun wrote:
>>> >>> Hi Ryan,
>>> >>>
>>> >>>> On 12/12/2025 16:18, Yeoreum Yun wrote:
>>> >>>>> Some architectures invoke pagetable_alloc() or __get_free_pages()
>>> >>>>> with preemption disabled.
>>> >>>>> For example, in arm64, linear_map_split_to_ptes() calls pagetable_alloc()
>>> >>>>> while spliting block entry to ptes and __kpti_install_ng_mappings()
>>> >>>>> calls __get_free_pages() to create kpti pagetable.
>>> >>>>>
>>> >>>>> Under PREEMPT_RT, calling pagetable_alloc() with
>>> >>>>> preemption disabled is not allowed, because it may acquire
>>> >>>>> a spin lock that becomes sleepable on RT, potentially
>>> >>>>> causing a sleep during page allocation.
>>> >>>>>
>>> >>>>> Since above two functions is called as callback of stop_machine()
>>> >>>>> where its callback is called in preemption disabled,
>>> >>>>> They could make a potential problem. (sleeping in preemption disabled).
>>> >>>>>
>>> >>>>> To address this, introduce pagetable_alloc_nolock() API.
>>> >>>>
>>> >>>> I don't really understand what the problem is that you're trying to fix. As I
>>> >>>> see it, there are 2 call sites in arm64 arch code that are calling into the page
>>> >>>> allocator from stop_machine() - one via via pagetable_alloc() and another via
>>> >>>> __get_free_pages(). But both of those calls are passing in GFP_ATOMIC. It was my
>>> >>>> understanding that the page allocator would ensure it never sleeps when
>>> >>>> GFP_ATOMIC is passed in, (even for PREEMPT_RT)?
>>> >>>
>>> >>> Although GFP_ATOMIC is specify, it only affects of "water mark" of the
>>> >>> page with __GFP_HIGH. and to get a page, it must grab the lock --
>>> >>> zone->lock or pcp_lock in the rmqueue().
>>> >>>
>>> >>> This zone->lock and pcp_lock is spin_lock and it's a sleepable in
>>> >>> PREEMPT_RT that's why the memory allocation/free using general API
>>> >>> except nolock() version couldn't be called since
>>> >>> if "contention" happens they'll sleep while waiting to get the lock.
>>> >>>
>>> >>> The reason why "nolock()" can use, it always uses "trylock" with
>>> >>> ALLOC_TRYLOCK flags. otherwise GFP_ATOMIC also can be sleepable in
>>> >>> PREEMPT_RT.
>>> >>>
>>> >>>>
>>> >>>> What is the actual symptom you are seeing?
>>> >>>
>>> >>> Since the place where called while smp_cpus_done() and there seems no
>>> >>> contention, there seems no problem. However as I mention in another
>>> >>> thread
>>> >>> (https://lore.kernel.org/all/aT%2FdrjN1BkvyAGoi at e129823.arm.com/),
>>> >>> This gives a the false impression --
>>> >>> GFP_ATOMIC are ?safe to use in preemption disabled?
>>> >>> even though they are not in PREEMPT_RT case, I've changed it.
>>> >>>
>>> >>>>
>>> >>>> If the page allocator is somehow ignoring the GFP_ATOMIC request for PREEMPT_RT,
>>> >>>> then isn't that a bug in the page allocator? I'm not sure why you would change
>>> >>>> the callsites? Can't you just change the page allocator based on GFP_ATOMIC?
>>> >>>
>>> >>> It doesn't ignore the GFP_ATOMIC feature:
>>> >>>   - __GFP_HIGH: use water mark till min reserved
>>> >>>   - __GFP_KSWAPD_RECLAIM: wake up kswapd if reclaim required.
>>> >>>
>>> >>> But, it's a restriction -- "page allocation / free" API cannot be called
>>> >>> in preempt-disabled context at PREEMPT_RT.
>>> >>>
>>> >>> That's why I think it's wrong usage not a page allocator bug.
>>> >>
>>> >> I've taken a look at this and I agree with your analysis. Thanks for explaining.
>>> >>
>>> >> Looking at other stop_machine() callbacks, there are some that call printk() and
>>> >> I would assume that spinlocks could be taken there which may present the same
>>> >> kind of issue or PREEMPT_RT? (I'm guessing). I don't see any others that attempt
>>> >> to allocate memory though.
>>> >
>>> > IIRC, there was a problem related for printk while try to grab
>>> > pl011_console related lock (spin_lock) while holding
>>> > console_lock(raw_spin_lock) in v6.10.0-rc7 at rpi5:
>>> >
>>> >     [  230.381263] CPU: 2 PID: 5574 Comm: syz.4.1695 Not tainted 6.10.0-rc7-01903-g52828ea60dfd #3
>>> >     [  230.381479] Hardware name: linux,dummy-virt (DT)
>>> >     [  230.381565] Call trace:
>>> >     [  230.381607]  dump_backtrace+0x318/0x348
>>> >     [  230.381727]  show_stack+0x4c/0x80
>>> >     [  230.381875]  dump_stack_lvl+0x214/0x328
>>> >     [  230.382159]  dump_stack+0x3c/0x58
>>> >     [  230.382456]  __lock_acquire+0x4398/0x4720
>>> >     [  230.382683]  lock_acquire+0x648/0xb70
>>> >     [  230.382928]  _raw_spin_lock_irqsave+0x138/0x240
>>> >     [  230.383121]  pl011_console_write+0x240/0x8a0
>>> >     [  230.383356]  console_flush_all+0x708/0x1368
>>> >     [  230.383571]  console_unlock+0x180/0x440
>>> >     [  230.383742]  vprintk_emit+0x1f8/0x9d0
>>> >     [  230.383832]  vprintk_default+0x64/0x90
>>> >     [  230.383914]  vprintk+0x2d0/0x400
>>> >     [  230.383971]  _printk+0xdc/0x128
>>> >     [  230.384229]  hrtimer_interrupt+0x8f0/0x920
>>> >     [  230.384414]  arch_timer_handler_virt+0xc0/0x100
>>> >     [  230.384812]  handle_percpu_devid_irq+0x20c/0x4e0
>>> >     [  230.385053]  generic_handle_domain_irq+0xc0/0x120
>>> >     [  230.385367]  gic_handle_irq+0x88/0x360
>>> >     [  230.385559]  call_on_irq_stack+0x24/0x70
>>> >     [  230.385801]  do_interrupt_handler+0xf8/0x200
>>> >     [  230.386092]  el1_interrupt+0x68/0xc0
>>> >     [  230.386434]  el1h_64_irq_handler+0x18/0x28
>>> >     [  230.386716]  el1h_64_irq+0x64/0x68
>>> >     [  230.386853]  __sanitizer_cov_trace_const_cmp2+0x30/0x68
>>> >     [  230.387026]  alloc_pages_mpol_noprof+0x170/0x698
>>> >     [  230.387309]  vma_alloc_folio_noprof+0x128/0x2a8
>>> >     [  230.387610]  vma_alloc_zeroed_movable_folio+0xa0/0xe0
>>> >     [  230.387822]  folio_prealloc+0x5c/0x280
>>> >     [  230.388008]  do_wp_page+0xc30/0x3bc0
>>> >     [  230.388206]  __handle_mm_fault+0xdb8/0x2ba0
>>> >     [  230.388448]  handle_mm_fault+0x194/0x8a8
>>> >     [  230.388676]  do_page_fault+0x6bc/0x1030
>>> >     [  230.388924]  do_mem_abort+0x8c/0x240
>>> >     [  230.389056]  el0_da+0xf0/0x3f8
>>> >     [  230.389178]  el0t_64_sync_handler+0xb4/0x130
>>> >     [  230.389452]  el0t_64_sync+0x190/0x198
>>> >
>>> > But this problem is gone when I try with some of patches in rt-tree
>>> > related for printk which are merged in current tree
>>> > (https://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git/log/?h=linux-6.10.y-rt-rebase).
>>> >
>>> > So I think printk() wouldn't be a problem.
>>> >
>>> >>
>>> >> Anyway, to fix the 2 arm64 callsites, I see 2 possible approaches:
>>> >>
>>> >> - Call the nolock variant (as you are doing). But that would just convert a
>>> >> deadlock to a panic; if the lock is held when stop_machine() runs, without your
>>> >> change, we now have a deadlock due to waiting on the lock inside stop_machine().
>>> >> With your change, we notice the lock is already taken and panic. I guess it is
>>> >> marginally better, but not by much. Certainly I would just _always_ call the
>>> >> nolock variant regardless of PREEMPT_RT if we take this route; For !PREEMPT_RT,
>>> >> the lock is guarranteed to be free so nolock will always succeed.
>>> >>
>>> >> - Preallocate the memory before entering stop_machine(). I think this would be
>>> >> much more robust. For kpti_install_ng_mappings() I think you could hoist the
>>> >> allocation/free out of stop_machine() and pass the pointer in pretty easily. For
>>> >> linear_map_split_to_ptes() its a bit more complex; Perhaps, we need to walk the
>>> >> pgtable to figure out how much to preallocate, allocate it, then set it up as a
>>> >> special allocator, wrapped by an allocation function and modify the callchain to
>>> >> take a callback function instead of gfp flags.
>>> >>
>>> >> What do you think?
>>> >
>>> > Definitely, second suggestoin is much better.
>>> > My question is whether *memory contention* really happen in the point
>>> > both functions are called.
>>>
>>> My guess would be that it's unlikely, but not impossible. The secondary CPUs are
>>> up, and presumably running their idle thread. I think various power management
>>> things can be plugged into the idle thread; if so, then I guess it's possible
>>> that the CPU could be running some hook as part of a power state transition, and
>>> that could be dynamically allocating memory? That's all just a guess though; I
>>> don't know the details of that part of the system.
>>>
>>> >
>>> > Above two functions are called as last step of "smp_init()" -- smp_cpus_done().
>>> > If we can be sure, I think we don't need to go to complex way and
>>> > I believe the reason why we couldn't find out this problem,
>>> > even using GFP_ATOMIC in PREEMPT_RT since there was *no contection*
>>> > in this time of both functions are called.
>>> > > That's why I first try with the "simple way".
>>> >
>>> > What do you think?
>>>
>>> As far as linear_map_split_to_ptes() is concerned, it was implemented under the
>>> impression that doing allocation with GFP_ATOMIC was safe, even in
>>> stop_machine(). Given that's an incorrect assumption, I think we should fix it
>>> to pre-allocate outside of stop_machine() regardless of the likelihood of
>>> actually hitting the race.
>>>
>> 
>> Yeap. It?s better to be certain than uncertain. Thanks for checking.
>> I'll repsin with the preallocate way.
>
> Note this is explained in Documentation/core-api/real-time/differences.rst:
>
> Memory allocation
> -----------------
>
> The memory allocation APIs, such as kmalloc() and alloc_pages(), require a
> gfp_t flag to indicate the allocation context. On non-PREEMPT_RT kernels, it is
> necessary to use GFP_ATOMIC when allocating memory from interrupt context or
> from sections where preemption is disabled. This is because the allocator must
> not sleep in these contexts waiting for memory to become available.
>
> However, this approach does not work on PREEMPT_RT kernels. The memory
> allocator in PREEMPT_RT uses sleeping locks internally, which cannot be
> acquired when preemption is disabled. Fortunately, this is generally not a
> problem, because PREEMPT_RT moves most contexts that would traditionally run
> with preemption or interrupts disabled into threaded context, where sleeping is
> allowed.
>
> What remains problematic is code that explicitly disables preemption or
> interrupts. In such cases, memory allocation must be performed outside the
> critical section.
>
> This restriction also applies to memory deallocation routines such as kfree()
> and free_pages(), which may also involve internal locking and must not be
> called from non-preemptible contexts.

Oh, thanks for pointing to that, I had never read that before (oops).

Shall we point to this from the doc-comment? Something like the below.

BTW, Yeorum, assuming you care about PREEMPT_RT, maybe you can get
Sparse to find some other bugs of this nature? Or if not, plain old
Coccinelle would probably find a few.

---

>From 4c6b4d4cb08aee9559d02a348b9ecf799142c96f Mon Sep 17 00:00:00 2001
From: Brendan Jackman <jackmanb at google.com>
Date: Wed, 17 Dec 2025 13:26:28 +0000
Subject: [PATCH] mm: clarify GFP_ATOMIC/GFP_NOWAIT doc-comment

The current description of contexts where it's invalid to make
GFP_ATOMIC and GFP_NOWAIT calls is rather vague.

Replace this with a direct description of the actual contexts of concern
and refer to the RT docs where this is explained more discursively.

While rejigging this prose, also move the documentation of GFP_NOWAIT to
the GFP_NOWAIT section.

Link: https://lore.kernel.org/all/d912480a-5229-4efe-9336-b31acded30f5 at suse.cz/
Signed-off-by: Brendan Jackman <jackmanb at google.com>
---
 include/linux/gfp_types.h | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/include/linux/gfp_types.h b/include/linux/gfp_types.h
index 3de43b12209ee..07a378542caf2 100644
--- a/include/linux/gfp_types.h
+++ b/include/linux/gfp_types.h
@@ -309,8 +309,10 @@ enum {
  *
  * %GFP_ATOMIC users can not sleep and need the allocation to succeed. A lower
  * watermark is applied to allow access to "atomic reserves".
- * The current implementation doesn't support NMI and few other strict
- * non-preemptive contexts (e.g. raw_spin_lock). The same applies to %GFP_NOWAIT.
+ * The current implementation doesn't support NMI, nor contexts that disable
+ * preemption under PREEMPT_RT. This includes raw_spin_lock() and plain
+ * preempt_disable() - see Documentation/core-api/real-time/differences.rst for
+ * more info.
  *
  * %GFP_KERNEL is typical for kernel-internal allocations. The caller requires
  * %ZONE_NORMAL or a lower zone for direct access but can direct reclaim.
@@ -321,6 +323,7 @@ enum {
  * %GFP_NOWAIT is for kernel allocations that should not stall for direct
  * reclaim, start physical IO or use any filesystem callback.  It is very
  * likely to fail to allocate memory, even for very small allocations.
+ * The same restrictions on calling contexts apply as for %GFP_ATOMIC.
  *
  * %GFP_NOIO will use direct reclaim to discard clean pages or slab pages
  * that do not require the starting of any physical IO.
--
2.50.1


From robert.hoo.linux at gmail.com  Wed Dec 17 05:39:45 2025
From: robert.hoo.linux at gmail.com (Robert Hoo)
Date: Wed, 17 Dec 2025 21:39:45 +0800
Subject: [PATCH v2 4/5] KVM: arm64: Enable HDBSS support and handle HDBSSF
 events
In-Reply-To: <20251121092342.3393318-5-zhengtian10@huawei.com>
References: <20251121092342.3393318-1-zhengtian10@huawei.com>
 <20251121092342.3393318-5-zhengtian10@huawei.com>
Message-ID: <87df4cba-b191-49cf-9486-fc379470a6eb@gmail.com>

On 11/21/2025 5:23 PM, Tian Zheng wrote:
> From: eillon <yezhenyu2 at huawei.com>
> 
> Implement the HDBSS enable/disable functionality using the
> KVM_CAP_ARM_HW_DIRTY_STATE_TRACK ioctl.
> 
> Userspace (e.g., QEMU) can enable HDBSS by invoking the ioctl
> at the start of live migration, configuring the buffer size.
> The feature is disabled by invoking the ioctl again with size
> set to 0 once migration completes.
> 
> Add support for updating the dirty bitmap based on the HDBSS
> buffer. Similar to the x86 PML implementation, KVM flushes the
> buffer on all VM-Exits, so running vCPUs only need to be kicked
> to force a VM-Exit.
> 
> Signed-off-by: eillon <yezhenyu2 at huawei.com>
> Signed-off-by: Tian Zheng <zhengtian10 at huawei.com>
> ---
>   arch/arm64/include/asm/kvm_host.h |  10 +++
>   arch/arm64/include/asm/kvm_mmu.h  |  17 +++++
>   arch/arm64/kvm/arm.c              | 107 ++++++++++++++++++++++++++++++
>   arch/arm64/kvm/handle_exit.c      |  45 +++++++++++++
>   arch/arm64/kvm/hyp/vhe/switch.c   |   1 +
>   arch/arm64/kvm/mmu.c              |  10 +++
>   arch/arm64/kvm/reset.c            |   3 +
>   include/linux/kvm_host.h          |   1 +
>   8 files changed, 194 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index d962932f0e5f..408e4c2b3d1a 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -87,6 +87,7 @@ int __init kvm_arm_init_sve(void);
>   u32 __attribute_const__ kvm_target_cpu(void);
>   void kvm_reset_vcpu(struct kvm_vcpu *vcpu);
>   void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu);
> +void kvm_arm_vcpu_free_hdbss(struct kvm_vcpu *vcpu);
> 
>   struct kvm_hyp_memcache {
>   	phys_addr_t head;
> @@ -793,6 +794,12 @@ struct vcpu_reset_state {
>   	bool		reset;
>   };
> 
> +struct vcpu_hdbss_state {
> +	phys_addr_t base_phys;
> +	u32 size;
> +	u32 next_index;
> +};
> +
>   struct vncr_tlb;
> 
>   struct kvm_vcpu_arch {
> @@ -897,6 +904,9 @@ struct kvm_vcpu_arch {
> 
>   	/* Per-vcpu TLB for VNCR_EL2 -- NULL when !NV */
>   	struct vncr_tlb	*vncr_tlb;
> +
> +	/* HDBSS registers info */
> +	struct vcpu_hdbss_state hdbss;
>   };
> 
>   /*
> diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
> index e4069f2ce642..6ace1080aed5 100644
> --- a/arch/arm64/include/asm/kvm_mmu.h
> +++ b/arch/arm64/include/asm/kvm_mmu.h
> @@ -331,6 +331,23 @@ static __always_inline void __load_stage2(struct kvm_s2_mmu *mmu,
>   	asm(ALTERNATIVE("nop", "isb", ARM64_WORKAROUND_SPECULATIVE_AT));
>   }
> 
> +static __always_inline void __load_hdbss(struct kvm_vcpu *vcpu)
> +{
> +	struct kvm *kvm = vcpu->kvm;
> +	u64 br_el2, prod_el2;
> +
> +	if (!kvm->enable_hdbss)
> +		return;
> +
> +	br_el2 = HDBSSBR_EL2(vcpu->arch.hdbss.base_phys, vcpu->arch.hdbss.size);
> +	prod_el2 = vcpu->arch.hdbss.next_index;
> +
> +	write_sysreg_s(br_el2, SYS_HDBSSBR_EL2);
> +	write_sysreg_s(prod_el2, SYS_HDBSSPROD_EL2);
> +
> +	isb();
> +}
> +
>   static inline struct kvm *kvm_s2_mmu_to_kvm(struct kvm_s2_mmu *mmu)
>   {
>   	return container_of(mmu->arch, struct kvm, arch);
> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
> index 870953b4a8a7..64f65e3c2a89 100644
> --- a/arch/arm64/kvm/arm.c
> +++ b/arch/arm64/kvm/arm.c
> @@ -79,6 +79,92 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
>   	return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE;
>   }
> 
> +void kvm_arm_vcpu_free_hdbss(struct kvm_vcpu *vcpu)
> +{
> +	struct page *hdbss_pg = NULL;
> +
> +	hdbss_pg = phys_to_page(vcpu->arch.hdbss.base_phys);
> +	if (hdbss_pg)
> +		__free_pages(hdbss_pg, vcpu->arch.hdbss.size);
> +
> +	vcpu->arch.hdbss = (struct vcpu_hdbss_state) {
> +		.base_phys = 0,
> +		.size = 0,
> +		.next_index = 0,
> +	};
> +}
> +
> +static int kvm_cap_arm_enable_hdbss(struct kvm *kvm,
> +				    struct kvm_enable_cap *cap)
> +{
> +	unsigned long i;
> +	struct kvm_vcpu *vcpu;
> +	struct page *hdbss_pg = NULL;
> +	int size = cap->args[0];
> +	int ret = 0;
> +
> +	if (!system_supports_hdbss()) {
> +		kvm_err("This system does not support HDBSS!\n");
> +		return -EINVAL;
> +	}
> +
> +	if (size < 0 || size > HDBSS_MAX_SIZE) {
> +		kvm_err("Invalid HDBSS buffer size: %d!\n", size);
> +		return -EINVAL;
> +	}
> +

I think you should check if it's already enabled here. What if user space calls 
this twice?

> +	/* Enable the HDBSS feature if size > 0, otherwise disable it. */
> +	if (size) {
> +		kvm_for_each_vcpu(i, vcpu, kvm) {
> +			hdbss_pg = alloc_pages(GFP_KERNEL_ACCOUNT, size);
> +			if (!hdbss_pg) {
> +				kvm_err("Alloc HDBSS buffer failed!\n");
> +				ret = -ENOMEM;
> +				goto error_alloc;
> +			}
> +
> +			vcpu->arch.hdbss = (struct vcpu_hdbss_state) {
> +				.base_phys = page_to_phys(hdbss_pg),
> +				.size = size,
> +				.next_index = 0,
> +			};
> +		}
> +
> +		kvm->enable_hdbss = true;
> +		kvm->arch.mmu.vtcr |= VTCR_EL2_HD | VTCR_EL2_HDBSS;

VTCR_EL2_HA is also a necessity for VTCR_EL2_HDBSS to take effect.

> +
> +		/*
> +		 * We should kick vcpus out of guest mode here to load new
> +		 * vtcr value to vtcr_el2 register when re-enter guest mode.
> +		 */
> +		kvm_for_each_vcpu(i, vcpu, kvm)
> +			kvm_vcpu_kick(vcpu);
> +	} else if (kvm->enable_hdbss) {
> +		kvm->arch.mmu.vtcr &= ~(VTCR_EL2_HD | VTCR_EL2_HDBSS);
> +
> +		kvm_for_each_vcpu(i, vcpu, kvm) {
> +			/* Kick vcpus to flush hdbss buffer. */
> +			kvm_vcpu_kick(vcpu);
> +
> +			kvm_arm_vcpu_free_hdbss(vcpu);
> +		}
> +
> +		kvm->enable_hdbss = false;
> +	}
> +
> +	return ret;
> +
> +error_alloc:
> +	kvm_for_each_vcpu(i, vcpu, kvm) {
> +		if (!vcpu->arch.hdbss.base_phys && !vcpu->arch.hdbss.size)
> +			continue;
> +
> +		kvm_arm_vcpu_free_hdbss(vcpu);
> +	}
> +
> +	return ret;
> +}
> +
>   int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
>   			    struct kvm_enable_cap *cap)
>   {
> @@ -132,6 +218,11 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
>   		}
>   		mutex_unlock(&kvm->lock);
>   		break;
> +	case KVM_CAP_ARM_HW_DIRTY_STATE_TRACK:
> +		mutex_lock(&kvm->lock);
> +		r = kvm_cap_arm_enable_hdbss(kvm, cap);
> +		mutex_unlock(&kvm->lock);
> +		break;
>   	default:
>   		break;
>   	}
> @@ -420,6 +511,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
>   			r = kvm_supports_cacheable_pfnmap();
>   		break;
> 
> +	case KVM_CAP_ARM_HW_DIRTY_STATE_TRACK:
> +		r = system_supports_hdbss();
> +		break;
>   	default:
>   		r = 0;
>   	}
> @@ -1837,7 +1931,20 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
> 
>   void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)
>   {
> +	/*
> +	 * Flush all CPUs' dirty log buffers to the dirty_bitmap.  Called
> +	 * before reporting dirty_bitmap to userspace.  KVM flushes the buffers
> +	 * on all VM-Exits, thus we only need to kick running vCPUs to force a
> +	 * VM-Exit.
> +	 */
> +	struct kvm_vcpu *vcpu;
> +	unsigned long i;
> 
> +	if (!kvm->enable_hdbss)
> +		return;
> +
> +	kvm_for_each_vcpu(i, vcpu, kvm)
> +		kvm_vcpu_kick(vcpu);
>   }
> 
>   static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm,
> diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
> index cc7d5d1709cb..9ba0ea6305ef 100644
> --- a/arch/arm64/kvm/handle_exit.c
> +++ b/arch/arm64/kvm/handle_exit.c
> @@ -412,6 +412,49 @@ static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu)
>   	return arm_exit_handlers[esr_ec];
>   }
> 
> +static void kvm_flush_hdbss_buffer(struct kvm_vcpu *vcpu)
> +{
> +	int idx, curr_idx;
> +	u64 *hdbss_buf;
> +	struct kvm *kvm = vcpu->kvm;
> +	u64 br_el2;
> +
> +	if (!kvm->enable_hdbss)
> +		return;
> +
> +	dsb(sy);
> +	isb();
> +	curr_idx = HDBSSPROD_IDX(read_sysreg_s(SYS_HDBSSPROD_EL2));
> +	br_el2 = HDBSSBR_EL2(vcpu->arch.hdbss.base_phys, vcpu->arch.hdbss.size);
> +
> +	/* Do nothing if HDBSS buffer is empty or br_el2 is NULL */
> +	if (curr_idx == 0 || br_el2 == 0)
> +		return;
> +
> +	hdbss_buf = page_address(phys_to_page(vcpu->arch.hdbss.base_phys));
> +	if (!hdbss_buf) {
> +		kvm_err("Enter flush hdbss buffer with buffer == NULL!");
> +		return;
> +	}
> +
> +	guard(write_lock_irqsave)(&vcpu->kvm->mmu_lock);
> +	for (idx = 0; idx < curr_idx; idx++) {
> +		u64 gpa;
> +
> +		gpa = hdbss_buf[idx];
> +		if (!(gpa & HDBSS_ENTRY_VALID))
> +			continue;
> +
> +		gpa &= HDBSS_ENTRY_IPA;
> +		kvm_vcpu_mark_page_dirty(vcpu, gpa >> PAGE_SHIFT);
> +	}
> +
> +	/* reset HDBSS index */
> +	write_sysreg_s(0, SYS_HDBSSPROD_EL2);
> +	vcpu->arch.hdbss.next_index = 0;
> +	isb();
> +}
> +
>   /*
>    * We may be single-stepping an emulated instruction. If the emulation
>    * has been completed in the kernel, we can return to userspace with a
> @@ -447,6 +490,8 @@ int handle_exit(struct kvm_vcpu *vcpu, int exception_index)
>   {
>   	struct kvm_run *run = vcpu->run;
> 
> +	kvm_flush_hdbss_buffer(vcpu);
> +
>   	if (ARM_SERROR_PENDING(exception_index)) {
>   		/*
>   		 * The SError is handled by handle_exit_early(). If the guest
> diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c
> index 9984c492305a..3787c9c5810d 100644
> --- a/arch/arm64/kvm/hyp/vhe/switch.c
> +++ b/arch/arm64/kvm/hyp/vhe/switch.c
> @@ -220,6 +220,7 @@ void kvm_vcpu_load_vhe(struct kvm_vcpu *vcpu)
>   	__vcpu_load_switch_sysregs(vcpu);
>   	__vcpu_load_activate_traps(vcpu);
>   	__load_stage2(vcpu->arch.hw_mmu, vcpu->arch.hw_mmu->arch);
> +	__load_hdbss(vcpu);
>   }
> 
>   void kvm_vcpu_put_vhe(struct kvm_vcpu *vcpu)
> diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
> index 7cc964af8d30..91a2f9dbb406 100644
> --- a/arch/arm64/kvm/mmu.c
> +++ b/arch/arm64/kvm/mmu.c
> @@ -1843,6 +1843,9 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
>   	if (writable)
>   		prot |= KVM_PGTABLE_PROT_W;
> 
> +	if (writable && kvm->enable_hdbss && logging_active)
> +		prot |= KVM_PGTABLE_PROT_DBM;
> +
>   	if (exec_fault)
>   		prot |= KVM_PGTABLE_PROT_X;
> 
> @@ -1950,6 +1953,13 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
> 
>   	is_iabt = kvm_vcpu_trap_is_iabt(vcpu);
> 
> +	/*
> +	 * HDBSS buffer already flushed when enter handle_trap_exceptions().
> +	 * Nothing to do here.
> +	 */
> +	if (ESR_ELx_ISS2(esr) & ESR_ELx_HDBSSF)
> +		return 1;
> +
>   	if (esr_fsc_is_translation_fault(esr)) {
>   		/* Beyond sanitised PARange (which is the IPA limit) */
>   		if (fault_ipa >= BIT_ULL(get_kvm_ipa_limit())) {
> diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
> index 959532422d3a..65e8f890f863 100644
> --- a/arch/arm64/kvm/reset.c
> +++ b/arch/arm64/kvm/reset.c
> @@ -161,6 +161,9 @@ void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu)
>   	free_page((unsigned long)vcpu->arch.ctxt.vncr_array);
>   	kfree(vcpu->arch.vncr_tlb);
>   	kfree(vcpu->arch.ccsidr);
> +
> +	if (vcpu->arch.hdbss.base_phys || vcpu->arch.hdbss.size)
> +		kvm_arm_vcpu_free_hdbss(vcpu);
>   }
> 
>   static void kvm_vcpu_reset_sve(struct kvm_vcpu *vcpu)
> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> index 5bd76cf394fa..aa8138604b1e 100644
> --- a/include/linux/kvm_host.h
> +++ b/include/linux/kvm_host.h
> @@ -876,6 +876,7 @@ struct kvm {
>   	struct xarray mem_attr_array;
>   #endif
>   	char stats_id[KVM_STATS_NAME_SIZE];
> +	bool enable_hdbss;
>   };
> 
>   #define kvm_err(fmt, ...) \
> --
> 2.33.0
> 
> 



From ulf.hansson at linaro.org  Wed Dec 17 05:45:01 2025
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Wed, 17 Dec 2025 14:45:01 +0100
Subject: [PATCH] dt-bindings: mmc: brcm,iproc-sdhci: Allow "dma-coherent"
 and "iommus" properties
In-Reply-To: <20251215212736.3321550-1-robh@kernel.org>
References: <20251215212736.3321550-1-robh@kernel.org>
Message-ID: <CAPDyKFrQ0Pm6524L15wrtAh_yyH4URWUf-hVELKsKYt=DiQ_WA@mail.gmail.com>

On Mon, 15 Dec 2025 at 22:27, Rob Herring (Arm) <robh at kernel.org> wrote:
>
> The Broadcom iProc SDHCI controller is DMA coherent and/or behind an IOMMU
> on some Broadcom SoCs, so allow the dma-coherent and iommus properties.
>
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>

Applied for next, thanks!

Kind regards
Uffe


> ---
>  Documentation/devicetree/bindings/mmc/brcm,iproc-sdhci.yaml | 5 +++++
>  1 file changed, 5 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/mmc/brcm,iproc-sdhci.yaml b/Documentation/devicetree/bindings/mmc/brcm,iproc-sdhci.yaml
> index 2f63f2cdeb71..65bb2f66f8cf 100644
> --- a/Documentation/devicetree/bindings/mmc/brcm,iproc-sdhci.yaml
> +++ b/Documentation/devicetree/bindings/mmc/brcm,iproc-sdhci.yaml
> @@ -26,9 +26,14 @@ properties:
>    reg:
>      minItems: 1
>
> +  dma-coherent: true
> +
>    interrupts:
>      maxItems: 1
>
> +  iommus:
> +    maxItems: 1
> +
>    clocks:
>      maxItems: 1
>      description:
> --
> 2.51.0
>


From ulf.hansson at linaro.org  Wed Dec 17 05:45:11 2025
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Wed, 17 Dec 2025 14:45:11 +0100
Subject: [PATCH] mmc: sdhci-of-arasan: Increase CD stable timeout to 2 seconds
In-Reply-To: <20251212063509.2002910-1-sai.krishna.potthuri@amd.com>
References: <20251212063509.2002910-1-sai.krishna.potthuri@amd.com>
Message-ID: <CAPDyKFrA7TiqX26BrSKaKeNyq8TRSoMpxvChuE1AhdVShvspGg@mail.gmail.com>

On Fri, 12 Dec 2025 at 07:36, Sai Krishna Potthuri
<sai.krishna.potthuri at amd.com> wrote:
>
> On Xilinx/AMD platforms, the CD stable bit take slightly longer than
> one second(about an additional 100ms) to assert after a host
> controller reset. Although no functional failure observed with the
> existing one second delay but to ensure reliable initialization, increase
> the CD stable timeout to 2 seconds.
>
> Fixes: e251709aaddb ("mmc: sdhci-of-arasan: Ensure CD logic stabilization before power-up")
> Signed-off-by: Sai Krishna Potthuri <sai.krishna.potthuri at amd.com>

Applied for fixes and by adding a stable-tag, thanks!

Kind regards
Uffe


> ---
>  drivers/mmc/host/sdhci-of-arasan.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
> index b97d042897ad..ab7f0ffe7b4f 100644
> --- a/drivers/mmc/host/sdhci-of-arasan.c
> +++ b/drivers/mmc/host/sdhci-of-arasan.c
> @@ -99,7 +99,7 @@
>  #define HIWORD_UPDATE(val, mask, shift) \
>                 ((val) << (shift) | (mask) << ((shift) + 16))
>
> -#define CD_STABLE_TIMEOUT_US           1000000
> +#define CD_STABLE_TIMEOUT_US           2000000
>  #define CD_STABLE_MAX_SLEEP_US         10
>
>  /**
> --
> 2.25.1
>


From ulf.hansson at linaro.org  Wed Dec 17 05:45:17 2025
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Wed, 17 Dec 2025 14:45:17 +0100
Subject: [PATCH] mmc: sdhci-esdhc-imx: add alternate ARCH_S32 dependency
 to Kconfig
In-Reply-To: <20251212-s32g-sdhci-kconfig-v1-1-8e278c8d7f78@redhat.com>
References: <20251212-s32g-sdhci-kconfig-v1-1-8e278c8d7f78@redhat.com>
Message-ID: <CAPDyKFp++OQFxkY_zqkZSJz2R0sqxBnd-6U+VLsyZYDQ4H9MeA@mail.gmail.com>

On Fri, 12 Dec 2025 at 16:04, Jared Kangas <jkangas at redhat.com> wrote:
>
> MMC_SDHCI_ESDHC_IMX requires ARCH_MXC despite also being used on
> ARCH_S32, which results in unmet dependencies when compiling strictly
> for ARCH_S32. Resolve this by adding ARCH_S32 as an alternative to
> ARCH_MXC in the driver's dependencies.
>
> Fixes: 5c4f00627c9a ("mmc: sdhci-esdhc-imx: add NXP S32G2 support")
> Signed-off-by: Jared Kangas <jkangas at redhat.com>

Applied for fixes and by adding a stable-tag, thanks!

Kind regards
Uffe


> ---
>  drivers/mmc/host/Kconfig | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> index 10d0ef58ef493102d3586d7a31d755543297999a..c94ae4794545de1c818ad50be7f91331862b6acf 100644
> --- a/drivers/mmc/host/Kconfig
> +++ b/drivers/mmc/host/Kconfig
> @@ -315,14 +315,14 @@ config MMC_SDHCI_ESDHC_MCF
>
>  config MMC_SDHCI_ESDHC_IMX
>         tristate "SDHCI support for the Freescale eSDHC/uSDHC i.MX controller"
> -       depends on ARCH_MXC || COMPILE_TEST
> +       depends on ARCH_MXC || ARCH_S32 || COMPILE_TEST
>         depends on MMC_SDHCI_PLTFM
>         depends on OF
>         select MMC_SDHCI_IO_ACCESSORS
>         select MMC_CQHCI
>         help
>           This selects the Freescale eSDHC/uSDHC controller support
> -         found on i.MX25, i.MX35 i.MX5x and i.MX6x.
> +         found on i.MX25, i.MX35, i.MX5x, i.MX6x, and S32G.
>
>           If you have a controller with this interface, say Y or M here.
>
>
> ---
> base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
> change-id: 20251211-s32g-sdhci-kconfig-585b6909f7b4
>
> Best regards,
> --
> Jared Kangas <jkangas at redhat.com>
>


From konrad.dybcio at oss.qualcomm.com  Wed Dec 17 05:52:24 2025
From: konrad.dybcio at oss.qualcomm.com (Konrad Dybcio)
Date: Wed, 17 Dec 2025 14:52:24 +0100
Subject: [PATCH v2 2/3] arm64: dts: qcom: lemans: add mdss1 display device
 nodes
In-Reply-To: <faau2h5z53frwfply57oh75zr5gcz4gf3za4vflbyht3ok4zgz@2ylcwcqcl4rt>
References: <20251125105622.1755651-1-quic_mkuntuma@quicinc.com>
 <20251125105622.1755651-3-quic_mkuntuma@quicinc.com>
 <32f013e7-ce2a-484b-8575-e98f2d23f59b@oss.qualcomm.com>
 <faau2h5z53frwfply57oh75zr5gcz4gf3za4vflbyht3ok4zgz@2ylcwcqcl4rt>
Message-ID: <5dc3d3e0-a338-4f2f-8987-5705fc1fde51@oss.qualcomm.com>

On 12/10/25 9:21 AM, Dmitry Baryshkov wrote:
> On Mon, Dec 01, 2025 at 02:35:44PM +0100, Konrad Dybcio wrote:
>> On 11/25/25 11:56 AM, Mani Chandana Ballary Kuntumalla wrote:
>>> Add devicetree changes to enable second Mobile Display Subsystem (mdss1),
>>> Display Processing Unit(DPU), Display Port(DP) controllers and eDP PHYs
>>> on the Qualcomm Lemans platform.
>>>
>>> Signed-off-by: Mahadevan P <mahadevan.p at oss.qualcomm.com>
>>> Signed-off-by: Mani Chandana Ballary Kuntumalla <quic_mkuntuma at quicinc.com>
>>> ---
>>
>> [...]
>>
>>> +			mdss1_dp1: displayport-controller at 2215c000 {
>>> +				compatible = "qcom,sa8775p-dp";
>>> +
>>> +				reg = <0x0 0x2215c000 0x0 0x104>,
>>> +				      <0x0 0x2215c200 0x0 0x0c0>,
>>> +				      <0x0 0x2215d000 0x0 0x770>,
>>> +				      <0x0 0x2215e000 0x0 0x09c>,
>>> +				      <0x0 0x2215f000 0x0 0x09c>,
>>> +				      <0x0 0x22160000 0x0 0x09c>,
>>> +				      <0x0 0x22161000 0x0 0x09c>,
>>> +				      <0x0 0x22162000 0x0 0x23c>,
>>> +				      <0x0 0x22163000 0x0 0x23c>;
>>
>> The last two regions still happen not to exist
> 
> According to the memory map I observe, they do exist.

Hm, you're right, I don't know why I couldn't find them in the past

Konrad


From krzk at kernel.org  Wed Dec 17 05:54:57 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 17 Dec 2025 14:54:57 +0100
Subject: [PATCH v2 07/11] dt-bindings: clock: qcom: document the Kaanapali
 GPU Clock Controller
In-Reply-To: <ca118faf-3451-4b83-9074-82bc5e1f731e@oss.qualcomm.com>
References: <20251125-kaanapali-mmcc-v2-v2-0-fb44e78f300b@oss.qualcomm.com>
 <20251125-kaanapali-mmcc-v2-v2-7-fb44e78f300b@oss.qualcomm.com>
 <20251126-elated-stoic-scorpion-25b630@kuoka>
 <de44560d-4ed8-41fe-be7b-56412b933a8c@oss.qualcomm.com>
 <fbe39eac-7c92-4a08-bafb-31e5c51a0613@kernel.org>
 <503f445e-0d12-407d-bc77-f48ad335639b@oss.qualcomm.com>
 <e8bdb176-b6fb-4dd2-8b5b-9da8073fa915@kernel.org>
 <ca118faf-3451-4b83-9074-82bc5e1f731e@oss.qualcomm.com>
Message-ID: <3e8128f4-3cba-4c13-a846-e5f1638a1e0f@kernel.org>

On 17/12/2025 14:21, Konrad Dybcio wrote:
> On 12/17/25 11:09 AM, Krzysztof Kozlowski wrote:
>> On 17/12/2025 10:32, Taniya Das wrote:
>>>>>
>>>>> We would like to leverage the existing common clock driver(GDSC) code to
>>>>
>>>> Fix the driver code if it cannot handle other cells. Your drivers do not
>>>> matter for choices made in bindings.
>>>>
>>>
>>> As it is still a clock controller from hardware design and in SW I will
>>> be map the entire hardware region and this way this clock controller
>>> will also be aligned to the existing clock controllers and keep the
>>> #power-domain-cells = <1> as other CCs.
>>
>> I don't see how this resolves my comment.
> 
> Spanning the entire 0x6000-long block will remove your worry about this
> description only being 2-register-wide

But that was not the comment here. Taniya replied under comment about
cells. We are not discussing here some other things...

Best regards,
Krzysztof


From yeoreum.yun at arm.com  Wed Dec 17 05:56:00 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Wed, 17 Dec 2025 13:56:00 +0000
Subject: [PATCH 0/2] introduce pagetable_alloc_nolock()
In-Reply-To: <DF0J58HOVLL4.2E16Q87D2UXRW@google.com>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com>
 <916c17ba-22b1-456e-a184-cb3f60249af7@arm.com>
 <aUGOPd7gNRf1xHEc@e129823.arm.com>
 <100cc8da-b826-4fc2-a624-746bf6fb049d@arm.com>
 <aUKKZR0u22KOPfd7@e129823.arm.com>
 <d96ac977-222e-4e8d-9487-da1306198419@arm.com>
 <aUKnfU/3FREY13g1@e129823.arm.com>
 <d912480a-5229-4efe-9336-b31acded30f5@suse.cz>
 <DF0J58HOVLL4.2E16Q87D2UXRW@google.com>
Message-ID: <aUK2cALmtIUPeeWy@e129823.arm.com>

[...]

> > Note this is explained in Documentation/core-api/real-time/differences.rst:
> >
> > Memory allocation
> > -----------------
> >
> > The memory allocation APIs, such as kmalloc() and alloc_pages(), require a
> > gfp_t flag to indicate the allocation context. On non-PREEMPT_RT kernels, it is
> > necessary to use GFP_ATOMIC when allocating memory from interrupt context or
> > from sections where preemption is disabled. This is because the allocator must
> > not sleep in these contexts waiting for memory to become available.
> >
> > However, this approach does not work on PREEMPT_RT kernels. The memory
> > allocator in PREEMPT_RT uses sleeping locks internally, which cannot be
> > acquired when preemption is disabled. Fortunately, this is generally not a
> > problem, because PREEMPT_RT moves most contexts that would traditionally run
> > with preemption or interrupts disabled into threaded context, where sleeping is
> > allowed.
> >
> > What remains problematic is code that explicitly disables preemption or
> > interrupts. In such cases, memory allocation must be performed outside the
> > critical section.
> >
> > This restriction also applies to memory deallocation routines such as kfree()
> > and free_pages(), which may also involve internal locking and must not be
> > called from non-preemptible contexts.
>
> Oh, thanks for pointing to that, I had never read that before (oops).
>
> Shall we point to this from the doc-comment? Something like the below.
>
> BTW, Yeorum, assuming you care about PREEMPT_RT, maybe you can get
> Sparse to find some other bugs of this nature? Or if not, plain old
> Coccinelle would probably find a few.

That's good idea. I'll try to sparse later.

Although this is a slightly different topic, based on Ryan?s suggestion,
I plan to address this misuse on arm64 by switching to pre-allocated pages.
As a result, I will remove the pgtable_alloc_nolock() interface.

> From 4c6b4d4cb08aee9559d02a348b9ecf799142c96f Mon Sep 17 00:00:00 2001
> From: Brendan Jackman <jackmanb at google.com>
> Date: Wed, 17 Dec 2025 13:26:28 +0000
> Subject: [PATCH] mm: clarify GFP_ATOMIC/GFP_NOWAIT doc-comment
>
> The current description of contexts where it's invalid to make
> GFP_ATOMIC and GFP_NOWAIT calls is rather vague.
>
> Replace this with a direct description of the actual contexts of concern
> and refer to the RT docs where this is explained more discursively.
>
> While rejigging this prose, also move the documentation of GFP_NOWAIT to
> the GFP_NOWAIT section.
>
> Link: https://lore.kernel.org/all/d912480a-5229-4efe-9336-b31acded30f5 at suse.cz/
> Signed-off-by: Brendan Jackman <jackmanb at google.com>
> ---
>  include/linux/gfp_types.h | 7 +++++--
>  1 file changed, 5 insertions(+), 2 deletions(-)
>
> diff --git a/include/linux/gfp_types.h b/include/linux/gfp_types.h
> index 3de43b12209ee..07a378542caf2 100644
> --- a/include/linux/gfp_types.h
> +++ b/include/linux/gfp_types.h
> @@ -309,8 +309,10 @@ enum {
>   *
>   * %GFP_ATOMIC users can not sleep and need the allocation to succeed. A lower
>   * watermark is applied to allow access to "atomic reserves".
> - * The current implementation doesn't support NMI and few other strict
> - * non-preemptive contexts (e.g. raw_spin_lock). The same applies to %GFP_NOWAIT.
> + * The current implementation doesn't support NMI, nor contexts that disable
> + * preemption under PREEMPT_RT. This includes raw_spin_lock() and plain
> + * preempt_disable() - see Documentation/core-api/real-time/differences.rst for
> + * more info.
>   *
>   * %GFP_KERNEL is typical for kernel-internal allocations. The caller requires
>   * %ZONE_NORMAL or a lower zone for direct access but can direct reclaim.
> @@ -321,6 +323,7 @@ enum {
>   * %GFP_NOWAIT is for kernel allocations that should not stall for direct
>   * reclaim, start physical IO or use any filesystem callback.  It is very
>   * likely to fail to allocate memory, even for very small allocations.
> + * The same restrictions on calling contexts apply as for %GFP_ATOMIC.
>   *
>   * %GFP_NOIO will use direct reclaim to discard clean pages or slab pages
>   * that do not require the starting of any physical IO.
> --
> 2.50.1

This patch looks good to me. Feel free to add:

Reviewed-by: Yeoreum Yun <yeoreum.yun at arm.com>

--
Sincerely,
Yeoreum Yun


From jgg at ziepe.ca  Wed Dec 17 05:59:22 2025
From: jgg at ziepe.ca (Jason Gunthorpe)
Date: Wed, 17 Dec 2025 09:59:22 -0400
Subject: [PATCH v5 07/27] iommu/arm-smmu-v3: Move IDR parsing to common
 functions
In-Reply-To: <aTw31-mh8z81yi4Y@google.com>
References: <20251117184815.1027271-1-smostafa@google.com>
 <20251117184815.1027271-8-smostafa@google.com>
 <20251128164816.GC812105@ziepe.ca>
 <aTw31-mh8z81yi4Y@google.com>
Message-ID: <20251217135922.GE31492@ziepe.ca>

On Fri, Dec 12, 2025 at 03:42:15PM +0000, Mostafa Saleh wrote:
> On Fri, Nov 28, 2025 at 12:48:16PM -0400, Jason Gunthorpe wrote:
> > On Mon, Nov 17, 2025 at 06:47:54PM +0000, Mostafa Saleh wrote:
> > > Move parsing of IDRs to functions so that it can be re-used
> > > from the hypervisor.
> > > 
> > > Signed-off-by: Mostafa Saleh <smostafa at google.com>
> > > ---
> > >  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 112 +++-----------------
> > >  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 111 +++++++++++++++++++
> > >  2 files changed, 126 insertions(+), 97 deletions(-)
> > 
> > I don't see that this slow path stuff needs to be inlined?
> > 
> > +10 to my prior remark to not dump all the huge inlines in the main
> > header.
> 
> They are inline as they are defined in the header file, otherwise they
> get defined multiple times.

Put them in a shared C file

Jason


From jgg at ziepe.ca  Wed Dec 17 06:00:46 2025
From: jgg at ziepe.ca (Jason Gunthorpe)
Date: Wed, 17 Dec 2025 10:00:46 -0400
Subject: [PATCH v5 14/27] iommu/arm-smmu-v3: Support probing KVM emulated
 devices
In-Reply-To: <aTw6afum4eqr5_e7@google.com>
References: <20251117184815.1027271-1-smostafa@google.com>
 <20251117184815.1027271-15-smostafa@google.com>
 <20251128165616.GD812105@ziepe.ca>
 <aTw6afum4eqr5_e7@google.com>
Message-ID: <20251217140046.GF31492@ziepe.ca>

On Fri, Dec 12, 2025 at 03:53:13PM +0000, Mostafa Saleh wrote:
> > It is OK I guess, I wouldn't insist you change it, but I think it is
> > kind of gross. Registering the iommu driver against the platform
> > device instead of the aux is pretty ugly and denies userspace the
> > ability to see that the hypervisor is sitting in there through the
> > sysfs topology.
> 
> Yes, that?s why I was wondering if it?s better to keep this as a platform
> driver and create the aux devices for the parent(KVM) but that was really
> complicated to handle the probe ordering.

That sounds worse and inverts the required probe ordering.

Attach it to the aux device :\

> > Not sure why the commentary about built-in though, what does that have
> > to do with anything? If the aux driver is not built in then it will
> > just module load later and everything should be fine?
> 
> As at the moment the KVM driver doesn?t use drvdata(nor any device
> resources) and the main driver(aux) does, but if that was a module, we
> can?t know which version does what (if that changes in the future,
> although unlikely).

Kernel is monolithic, you don't need to worry about people doing silly
games with modules.

Jason


From robh at kernel.org  Wed Dec 17 06:07:09 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Wed, 17 Dec 2025 08:07:09 -0600
Subject: [PATCH v7 2/7] dt-bindings: PCI: Add ASPEED PCIe RC support
In-Reply-To: <20251216-upstream_pcie_rc-v7-2-4aeb0f53c4ce@aspeedtech.com>
References: <20251216-upstream_pcie_rc-v7-0-4aeb0f53c4ce@aspeedtech.com>
 <20251216-upstream_pcie_rc-v7-2-4aeb0f53c4ce@aspeedtech.com>
Message-ID: <176598042865.925447.819427829703405501.robh@kernel.org>


On Tue, 16 Dec 2025 09:50:01 +0800, Jacky Chou wrote:
> ASPEED AST2600 provides one PCIe RC for Gen2 and AST2700 provides three
> PCIe RC for two Gen4 and one Gen2. All of these RCs have just one root
> port to connect to PCIe device. And also have Mem, I/O access, legacy
> interrupt and MSI.
> 
> Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
> ---
>  .../bindings/pci/aspeed,ast2600-pcie.yaml          | 182 +++++++++++++++++++++
>  1 file changed, 182 insertions(+)
> 

Reviewed-by: Rob Herring (Arm) <robh at kernel.org>



From quic_nihalkum at quicinc.com  Wed Dec 17 06:18:28 2025
From: quic_nihalkum at quicinc.com (Nihal Kumar Gupta)
Date: Wed, 17 Dec 2025 19:48:28 +0530
Subject: [PATCH v7 4/5] arm64: dts: qcom: monaco-evk: Add camera AVDD
 regulators
In-Reply-To: <19bf8b37-4b40-4825-a8be-a94139389c69@oss.qualcomm.com>
References: <20251216062223.2474216-1-quic_nihalkum@quicinc.com>
 <20251216062223.2474216-5-quic_nihalkum@quicinc.com>
 <19bf8b37-4b40-4825-a8be-a94139389c69@oss.qualcomm.com>
Message-ID: <2e14bc60-8cfb-4710-bcfb-d2cef8f370b6@quicinc.com>



On 17-12-2025 16:44, Konrad Dybcio wrote:
>> +		bias-disable;
>> +	};
> All other entries in this scope are sorted wrt the pin index..
> Please take care of that and add my
> 
> Reviewed-by: Konrad Dybcio <konrad.dybcio at oss.qualcomm.com>
> 
> Konrad
> 
>> +
ACK, Will address this in the next version.

-- 
Regards,
Nihal Kumar Gupta



From quic_nihalkum at quicinc.com  Wed Dec 17 06:19:42 2025
From: quic_nihalkum at quicinc.com (Nihal Kumar Gupta)
Date: Wed, 17 Dec 2025 19:49:42 +0530
Subject: [PATCH v7 5/5] arm64: dts: qcom: monaco-evk-camera: Add DT
 overlay
In-Reply-To: <5bd29b5f-6fcf-428d-b451-698d92f0883e@linaro.org>
References: <20251216062223.2474216-1-quic_nihalkum@quicinc.com>
 <20251216062223.2474216-6-quic_nihalkum@quicinc.com>
 <5bd29b5f-6fcf-428d-b451-698d92f0883e@linaro.org>
Message-ID: <facbe87c-a2e1-4cc2-8dc1-30f716814588@quicinc.com>



On 16-12-2025 13:05, Vladimir Zapolskiy wrote:
>> @@ -0,0 +1,67 @@
>> +// SPDX-License-Identifier: BSD-3-Clause
>> +/*
>> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> 
> Year is missing.
> 
This is as per new yearless copyright format.

>> + */
>> + 
>> +
>> +??????????? csiphy1_ep: endpoint {
>> +??????????????? clock-lanes = <7>;
> 
> Please remove 'clock-lanes' property here.
> 
ACK

>> +??????????????? data-lanes = <0 1 2 3>;
>> +??????????????? remote-endpoint = <&imx577_ep1>;
>> +??????????? };
>> +??????? };
>> +??? };
>> +??????????? imx577_ep1: endpoint {
>> +??????????????? link-frequencies = /bits/ 64 <600000000>;
>> +??????????????? data-lanes = <0 1 2 3>;
> 
> data-lanes property value should be '1 2 3 4>', 0 is for the clock lane.
> 
> On CAMSS side this cannot be changed, unfortunately it's a lingering issue.
> 
So, I should set data-lanes = <1 2 3 4> in imx577_ep1, and keep csiphy1_ep as <0 1 2 3>, correct?
Is there a reason CAMSS side can?t change this? We should handle it properly in future targets.

>> +??????????????? remote-endpoint = <&csiphy1_ep>;
>> +??????????? };
>> +??????? };
>> +??? };
>> +};
> 
> If only one of 3 defined from 4/5 regulators is used, do you really wish
> to describle all 3 in advance? You may consider to remove 2 currently unused
> GPIO controlled regulator descriptions, and squash this change with 4/5.
As discussed, we agreed to add support for other sensors: https://lore.kernel.org/all/4b73f64a-1e28-4f25-80d2-3d59575b9da2 at oss.qualcomm.com

Regulator changes are in monaco-evk.dts, and sensor overlay changes are present in monaco-evk-camera-imx577.dtso
It?s better to keep these as separate patches rather than merging them into one.

-- 
Regards,
Nihal Kumar Gupta



From luca.ceresoli at bootlin.com  Wed Dec 17 06:20:09 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Wed, 17 Dec 2025 15:20:09 +0100
Subject: [PATCH v2 03/20] drm/tilcdc: Remove simulate_vesa_sync flag
In-Reply-To: <20251211-feature_tilcdc-v2-3-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
 <20251211-feature_tilcdc-v2-3-f48bac3cd33e@bootlin.com>
Message-ID: <DF0K3BRQKOSI.10X5SMXI1YM60@bootlin.com>

Hi K?ry,

On Thu Dec 11, 2025 at 5:38 PM CET, Kory Maincent (TI.com) wrote:
> The tilcdc hardware does not generate VESA-compliant sync signals. It
> aligns the vertical sync (VS) on the second edge of the horizontal sync
> (HS) instead of the first edge. To compensate for this hardware
> behavior, the driver applies a timing adjustment in mode_fixup().
>
> Previously, this adjustment was conditional based on the simulate_vesa_sync
> flag, which was only set when using external encoders. This appears
> problematic because:
>
> 1. The timing adjustment seems needed for the hardware behavior regardless
>    of whether an external encoder is used
> 2. The external encoder infrastructure is driver-specific and being
>    removed due to design issues
> 3. Boards using tilcdc without bridges (e.g., am335x-evm, am335x-evmsk)
>    may not be getting the necessary timing adjustments
>
> Remove the simulate_vesa_sync flag and apply the VESA sync timing
> adjustment unconditionally, ensuring consistent behavior across all
> configurations. While it's unclear if the previous conditional behavior
> was causing actual issues, the unconditional adjustment better reflects
> the hardware's characteristics.
>
> Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>

Code looks good. Based on your testing, which covered both boards currently
setting simulate_vesa_sync and boards not setting it:

Reviewed-by: Luca Ceresoli <luca.ceresoli at bootlin.com>

Still it would be good to have this series, and especially this patch,
tested by someone having access to other TI boards.

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From luca.ceresoli at bootlin.com  Wed Dec 17 06:20:49 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Wed, 17 Dec 2025 15:20:49 +0100
Subject: [PATCH v2 04/20] drm/tilcdc: Add support for DRM bus flags and
 simplify panel config
In-Reply-To: <20251211-feature_tilcdc-v2-4-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
 <20251211-feature_tilcdc-v2-4-f48bac3cd33e@bootlin.com>
Message-ID: <DF0K3U9DB08N.2LEUCUUQ7FN0L@bootlin.com>

On Thu Dec 11, 2025 at 5:38 PM CET, Kory Maincent (TI.com) wrote:
> Migrate CRTC mode configuration to use standard DRM bus flags in
> preparation for removing the tilcdc_panel driver and its custom
> tilcdc_panel_info structure.
>
> Add support for DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE and
> DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE flags to control pixel clock and sync
> signal edge polarity, while maintaining backward compatibility with the
> existing tilcdc panel info structure.
>
> Simplify several hardware parameters by setting them to fixed defaults
> based on common usage across existing device trees:
> - DMA burst size: 16 (previously configurable via switch statement)
> - AC bias frequency: 255 (previously panel-specific)
> - FIFO DMA request delay: 128 (previously panel-specific)
>
> These parameters show no variation in real-world usage, so hardcoding
> them simplifies the driver without losing functionality.
>
> Preserve FIFO threshold configurability by detecting the SoC type, as
> this parameter varies between AM33xx (8) and DA850 (16) platforms.
>
> Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>

Reviewed-by: Luca Ceresoli <luca.ceresoli at bootlin.com>

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From liviu.dudau at arm.com  Wed Dec 17 06:21:58 2025
From: liviu.dudau at arm.com (Liviu Dudau)
Date: Wed, 17 Dec 2025 14:21:58 +0000
Subject: [PATCH] ARM: dts: vexpress/v2m-rs1: Use documented
 arm,vexpress,config-bus child node names
In-Reply-To: <20251216191212.2879226-2-robh@kernel.org>
References: <20251216191212.2879226-2-robh@kernel.org>
Message-ID: <aUK8hkoz0LmsIZXA@e142607>

On Tue, Dec 16, 2025 at 01:12:12PM -0600, Rob Herring (Arm) wrote:
> Update the arm,vexpress,config-bus child node names to use the
> documented ones. Most of these were updated a while back, but I missed
> these.
> 
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>

Reviewed-by: Liviu Dudau <liviu.dudau at arm.com>

Best regards,
Liviu

> ---
> SoC maintainers may want to take this directly?
> 
>  arch/arm/boot/dts/arm/vexpress-v2m-rs1.dtsi | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm/boot/dts/arm/vexpress-v2m-rs1.dtsi b/arch/arm/boot/dts/arm/vexpress-v2m-rs1.dtsi
> index 158b3923eae3..248b8e492d43 100644
> --- a/arch/arm/boot/dts/arm/vexpress-v2m-rs1.dtsi
> +++ b/arch/arm/boot/dts/arm/vexpress-v2m-rs1.dtsi
> @@ -420,7 +420,7 @@ mcc {
>  					compatible = "arm,vexpress,config-bus";
>  					arm,vexpress,config-bridge = <&v2m_sysreg>;
>  
> -					oscclk0 {
> +					clock-controller-0 {
>  						/* MCC static memory clock */
>  						compatible = "arm,vexpress-osc";
>  						arm,vexpress-sysreg,func = <1 0>;
> @@ -429,7 +429,7 @@ oscclk0 {
>  						clock-output-names = "v2m:oscclk0";
>  					};
>  
> -					v2m_oscclk1: oscclk1 {
> +					v2m_oscclk1: clock-controller-1 {
>  						/* CLCD clock */
>  						compatible = "arm,vexpress-osc";
>  						arm,vexpress-sysreg,func = <1 1>;
> @@ -438,7 +438,7 @@ v2m_oscclk1: oscclk1 {
>  						clock-output-names = "v2m:oscclk1";
>  					};
>  
> -					v2m_oscclk2: oscclk2 {
> +					v2m_oscclk2: clock-controller-2 {
>  						/* IO FPGA peripheral clock */
>  						compatible = "arm,vexpress-osc";
>  						arm,vexpress-sysreg,func = <1 2>;
> @@ -447,7 +447,7 @@ v2m_oscclk2: oscclk2 {
>  						clock-output-names = "v2m:oscclk2";
>  					};
>  
> -					volt-vio {
> +					regulator-vio {
>  						/* Logic level voltage */
>  						compatible = "arm,vexpress-volt";
>  						arm,vexpress-sysreg,func = <2 0>;
> -- 
> 2.51.0
> 


From vulab at iscas.ac.cn  Wed Dec 17 06:21:22 2025
From: vulab at iscas.ac.cn (Wentao Liang)
Date: Wed, 17 Dec 2025 14:21:22 +0000
Subject: [PATCH] ARM: omap2: Fix reference count leaks in omap_control_init()
Message-ID: <20251217142122.1861292-1-vulab@iscas.ac.cn>

The of_get_child_by_name() function increments the reference count
of child nodes, causing multiple reference leaks in omap_control_init():

1. scm_conf node never released in normal/error paths
2. clocks node leak when checking existence
3. Missing scm_conf release before np in error paths

Fix these leaks by adding proper of_node_put() calls and separate error
handling.

Fixes: e5b635742e98 ("ARM: OMAP2+: control: add syscon support for register accesses")
Cc: stable at vger.kernel.org
Signed-off-by: Wentao Liang <vulab at iscas.ac.cn>
---
 arch/arm/mach-omap2/control.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c
index 79860b23030d..eb6fc7c61b6e 100644
--- a/arch/arm/mach-omap2/control.c
+++ b/arch/arm/mach-omap2/control.c
@@ -732,7 +732,7 @@ int __init omap2_control_base_init(void)
  */
 int __init omap_control_init(void)
 {
-	struct device_node *np, *scm_conf;
+	struct device_node *np, *scm_conf, *clocks_node;
 	const struct of_device_id *match;
 	const struct omap_prcm_init_data *data;
 	int ret;
@@ -753,16 +753,19 @@ int __init omap_control_init(void)
 
 			if (IS_ERR(syscon)) {
 				ret = PTR_ERR(syscon);
-				goto of_node_put;
+				goto err_put_scm_conf;
 			}
 
-			if (of_get_child_by_name(scm_conf, "clocks")) {
+			clocks_node = of_get_child_by_name(scm_conf, "clocks");
+			if (clocks_node) {
+				of_node_put(clocks_node);
 				ret = omap2_clk_provider_init(scm_conf,
 							      data->index,
 							      syscon, NULL);
 				if (ret)
-					goto of_node_put;
+					goto err_put_scm_conf;
 			}
+			of_node_put(scm_conf);
 		} else {
 			/* No scm_conf found, direct access */
 			ret = omap2_clk_provider_init(np, data->index, NULL,
@@ -780,6 +783,9 @@ int __init omap_control_init(void)
 
 	return 0;
 
+err_put_scm_conf:
+	if (scm_conf)
+		of_node_put(scm_conf);
 of_node_put:
 	of_node_put(np);
 	return ret;
-- 
2.34.1



From luca.ceresoli at bootlin.com  Wed Dec 17 06:23:26 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Wed, 17 Dec 2025 15:23:26 +0100
Subject: [PATCH v2 05/20] drm/tilcdc: Convert legacy panel binding via
 DT overlay at boot time
In-Reply-To: <20251211-feature_tilcdc-v2-5-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
 <20251211-feature_tilcdc-v2-5-f48bac3cd33e@bootlin.com>
Message-ID: <DF0K5UFX46JA.OH85T6IPC5MW@bootlin.com>

Hi,

Cc: Herv?, can you review the DT overlay aspects?

On Thu Dec 11, 2025 at 5:38 PM CET, Kory Maincent (TI.com) wrote:
> To maintain backward compatibility while removing the deprecated
> tilcdc_panel driver, add a tilcdc_panel_legacy subdriver that converts
> the legacy "ti,tilcdc,panel" devicetree binding to the standard
> panel-dpi binding at early boot.
>
> The conversion uses an embedded device tree overlay that is applied and
> modified during subsys_initcall. The process:

I was a bit skeptical about the overlay idea initially. But after having
seen the code and thought about any alternative solution, I think you
probably took the simplest approach.

> - Apply embedded overlay to create a panel-dpi node with placeholder
>   timing properties and port/endpoint connections to the LCDC
> - Copy all properties from the legacy panel node to the new panel-dpi
> - Copy display-timings from the legacy panel
> - Convert legacy panel-info properties (invert-pxl-clk, sync-edge) to
>   standard display timing properties (pixelclk-active, syncclk-active)
> - Disable the legacy panel by removing its compatible property to
>   prevent the deprecated driver from binding
>
> The result is a standard panel-dpi node with proper endpoints and
> timing properties, allowing the DRM panel infrastructure to work with
> legacy devicetrees without modification.
>
> Other legacy panel-info properties are not migrated as they consistently
> use default values across all mainline devicetrees and can be hardcoded
> in the tilcdc driver.
>
> This feature is optional via CONFIG_DRM_TILCDC_PANEL_LEGACY and should
> only be enabled for systems with legacy devicetrees containing
> "ti,tilcdc,panel" nodes.
>
> Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>

It's fair to add before your SoB line:
 Suggested-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
 Link: https://lore.kernel.org/all/1d9a9269-bfda-4d43-938b-2df6b82b9369 at ideasonboard.com/

> ---
>
> Using the approach of applying an overlay and then modifying the live
> device tree is the solution I found that requires no modification of the
> OF core. Dealing entirely with overlay changesets would bring additional
> requirements such as phandle resolution management, which is internal to
> the OF framework. I intend to avoid OF core change to support this legacy
> binding.
>
> Change in v2:
> - New patch.
> ---
>  drivers/gpu/drm/tilcdc/Kconfig                  |  14 +++
>  drivers/gpu/drm/tilcdc/Makefile                 |   2 +
>  drivers/gpu/drm/tilcdc/tilcdc_panel_legacy.c    | 159 ++++++++++++++++++++++++
>  drivers/gpu/drm/tilcdc/tilcdc_panel_legacy.dtso |  44 +++++++
>  4 files changed, 219 insertions(+)
>
> diff --git a/drivers/gpu/drm/tilcdc/Kconfig b/drivers/gpu/drm/tilcdc/Kconfig
> index 24f9a245ba593..4dcae0a06b819 100644
> --- a/drivers/gpu/drm/tilcdc/Kconfig
> +++ b/drivers/gpu/drm/tilcdc/Kconfig
> @@ -14,3 +14,17 @@ config DRM_TILCDC
>  	  controller, for example AM33xx in beagle-bone, DA8xx, or
>  	  OMAP-L1xx.  This driver replaces the FB_DA8XX fbdev driver.
>
> +config DRM_TILCDC_PANEL_LEGACY
> +	bool "Support device tree blobs using TI LCDC Panel binding"
> +	default n

'default' defaults to 'n', you can drop this line.

However I think it should instead be enabled by default. You propose to
entirely remove the tilcdc panel driver in the next patch, so any users
without DRM_TILCDC_PANEL_LEGACY in their defconfig would be broken. For
this reason, I propose to enable DRM_TILCDC_PANEL_LEGACY in all cases where
the tilcdc_panel was compiled in, which I guess means:

    default DRM_TILCDC

Except I think if DRM_TILCDC=m, DRM_TILCDC_PANEL_LEGACY should be =y. I
don't know how to do that in Kconfig. But I'm not really sure about this
last topic.

> +	depends on DRM_TILCDC
> +        depends on OF
> +        depends on BACKLIGHT_CLASS_DEVICE
> +        depends on PM
> +	select OF_OVERLAY
> +	select DRM_PANEL_SIMPLE
> +	help
> +	  Choose this option if you need a kernel that is compatible
> +	  with device tree blobs using the obsolete "ti,tilcdc,panel"
> +	  binding. If you find "ti,tilcdc,panel"-string from your DTB,
> +	  you probably need this. Otherwise you do not.

Maybe mention here what it does?

For example, rewording your commit message:

  Modifies the live device tree at early boot to convert the legacy
  "ti,tilcdc,panel" devicetree node to the standard panel-dpi node.  This
  allows to maintain backward compatibility for boards which were using the
  deprecated tilcdc_panel driver.

> diff --git a/drivers/gpu/drm/tilcdc/Makefile b/drivers/gpu/drm/tilcdc/Makefile
> index f5190477de721..6d6a08b5adf40 100644
> --- a/drivers/gpu/drm/tilcdc/Makefile
> +++ b/drivers/gpu/drm/tilcdc/Makefile
> @@ -11,3 +11,5 @@ tilcdc-y := \
>  	tilcdc_drv.o
>
>  obj-$(CONFIG_DRM_TILCDC)	+= tilcdc.o
> +obj-$(CONFIG_DRM_TILCDC_PANEL_LEGACY)	+= tilcdc_panel_legacy.o \
> +					   tilcdc_panel_legacy.dtbo.o
> diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel_legacy.c b/drivers/gpu/drm/tilcdc/tilcdc_panel_legacy.c
> new file mode 100644
> index 0000000000000..a9651dd9f9935
> --- /dev/null
> +++ b/drivers/gpu/drm/tilcdc/tilcdc_panel_legacy.c
> @@ -0,0 +1,159 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2025 Kory Maincent <kory.maincent at bootlin.com>
> + *
> + * To support the legacy "ti,tilcdc,panel" binding, the devicetree has to
> + * be transformed to the new panel-dpi binding with the endpoint associated.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/of.h>
> +#include <linux/of_fdt.h>
> +#include <linux/slab.h>
> +
> +/* Embedded dtbo symbols created by cmd_wrap_S_dtb in scripts/Makefile.lib */
> +extern char __dtbo_tilcdc_panel_legacy_begin[];
> +extern char __dtbo_tilcdc_panel_legacy_end[];
> +
> +static void __init
> +tilcdc_panel_update_prop(struct device_node *node, char *name,
> +			 void *val, int length)
> +{
> +	struct property *prop;
> +
> +	prop = kzalloc(sizeof(*prop), GFP_KERNEL);
> +	if (!prop)
> +		return;
> +
> +	prop->name = kstrdup(name, GFP_KERNEL);
> +	prop->length = length;
> +	prop->value = kmemdup(val, length, GFP_KERNEL);
> +	of_update_property(node, prop);
> +}
> +
> +static int __init tilcdc_panel_copy_props(struct device_node *old_panel,
> +					  struct device_node *new_panel)
> +{
> +	struct device_node *child, *old_timing, *new_timing, *panel_info;
> +	u32 invert_pxl_clk = 0, sync_edge = 0;
> +	struct property *prop;
> +
> +	/* Copy all panel properties to the new panel node */
> +	for_each_property_of_node(old_panel, prop) {
> +		if (!strncmp(prop->name, "compatible", sizeof("compatible")))
> +			continue;
> +
> +		tilcdc_panel_update_prop(new_panel, prop->name,
> +					 prop->value, prop->length);
> +	}
> +
> +	child = of_get_child_by_name(old_panel, "display-timings");

There's some housekeeping code in this function to ensure you put all the
device_node refs. It would be simpler and less error prone to use a cleanup
action. E.g.:

-	struct device_node *child, *old_timing, *new_timing, *panel_info;

-	child = of_get_child_by_name(old_panel, "display-timings");
+	struct device_node *child __free(device_node) = of_get_child_by_name(old_panel, "display-timings");

> +	if (!child)
> +		return -EINVAL;
> +
> +	/* The default display timing is the one specified as native-mode.
> +	 * If no native-mode is specified then the first node is assumed
> +	 * to be the native mode.
> +	 */
> +	old_timing = of_parse_phandle(child, "native-mode", 0);
> +	if (!old_timing) {
> +		old_timing = of_get_next_child(child, NULL);
> +		if (!old_timing) {
> +			of_node_put(child);
> +			return -EINVAL;
> +		}
> +	}
> +	of_node_put(child);
> +
> +	new_timing = of_get_child_by_name(new_panel, "panel-timing");
> +	if (!new_timing)
> +		return -EINVAL;
> +
> +	/* Copy all panel timing property to the new panel node */
> +	for_each_property_of_node(old_timing, prop)
> +		tilcdc_panel_update_prop(new_timing, prop->name,
> +					 prop->value, prop->length);
> +
> +	panel_info = of_get_child_by_name(old_panel, "panel-info");
> +	if (!panel_info)
> +		return -EINVAL;

tilcdc_panel_update_prop() has previously done various allocations which
will not be freed if you return here. You shoudl probably do all the
of_get_*() at the top, and if they all succeed start copying data along
with with the needed allocations.

> +	/* Looked only for these two parameter as all the other are always
> +	 * set to default and not related to common DRM properties.
> +	 */
> +	of_property_read_u32(panel_info, "invert-pxl-clk", &invert_pxl_clk);
> +	of_property_read_u32(panel_info, "sync-edge", &sync_edge);
> +
> +	if (!invert_pxl_clk)
> +		tilcdc_panel_update_prop(new_timing, "pixelclk-active",
> +					 &(int){1}, sizeof(int));
> +
> +	if (!sync_edge)
> +		tilcdc_panel_update_prop(new_timing, "syncclk-active",
> +					 &(int){1}, sizeof(int));
> +
> +	of_node_put(panel_info);
> +	of_node_put(old_timing);
> +	of_node_put(new_timing);
> +	return 0;
> +}
> +
> +static const struct of_device_id tilcdc_panel_of_match[] __initconst = {
> +	{ .compatible = "ti,tilcdc,panel", },
> +	{},
> +};
> +
> +static const struct of_device_id tilcdc_of_match[] __initconst = {
> +	{ .compatible = "ti,am33xx-tilcdc", },
> +	{ .compatible = "ti,da850-tilcdc", },
> +	{},
> +};
> +
> +static int __init tilcdc_panel_legacy_init(void)
> +{
> +	struct device_node *panel, *lcdc, *new_panel;
> +	void *dtbo_start;
> +	u32 dtbo_size;
> +	int ovcs_id;
> +	int ret;
> +
> +	lcdc = of_find_matching_node(NULL, tilcdc_of_match);
> +	panel = of_find_matching_node(NULL, tilcdc_panel_of_match);
> +
> +	if (!of_device_is_available(panel) ||
> +	    !of_device_is_available(lcdc)) {
> +		ret = -ENODEV;
> +		goto out;
> +	}
> +
> +	dtbo_start = __dtbo_tilcdc_panel_legacy_begin;
> +	dtbo_size = __dtbo_tilcdc_panel_legacy_end -
> +		    __dtbo_tilcdc_panel_legacy_begin;
> +
> +	ret = of_overlay_fdt_apply(dtbo_start, dtbo_size, &ovcs_id, NULL);
> +	if (ret)
> +		goto out;
> +
> +	new_panel = of_find_node_by_name(NULL, "panel-dpi");
> +	if (!new_panel) {
> +		ret = -ENODEV;
> +		goto overlay_remove;
> +	}
> +
> +	ret = tilcdc_panel_copy_props(panel, new_panel);
> +	if (ret)
> +		goto overlay_remove;
> +
> +	/* Remove compatible property to avoid any driver compatible match */
> +	of_remove_property(panel, of_find_property(panel, "compatible",
> +						   NULL));
> +overlay_remove:
> +	of_overlay_remove(&ovcs_id);

Is it correct to remove the overlay here? Won't it remove what you have
just added?

> +out:
> +	of_node_put(new_panel);
> +	of_node_put(panel);
> +	of_node_put(lcdc);

Here too you can use cleanup actions, even though the current code is
slightly simpler than tilcdc_panel_copy_props as far as of_node_put() is
concerned.

> +	return ret;
> +}
> +
> +subsys_initcall(tilcdc_panel_legacy_init);
> diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel_legacy.dtso b/drivers/gpu/drm/tilcdc/tilcdc_panel_legacy.dtso
> new file mode 100644
> index 0000000000000..77f3ec9391d55
> --- /dev/null
> +++ b/drivers/gpu/drm/tilcdc/tilcdc_panel_legacy.dtso
> @@ -0,0 +1,44 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * DTS overlay for converting ti,tilcdc,panel binding to new binding.
> + *
> + * Copyright (C) Kory Maincent <kory.maincent at bootlin.com>
> + */
> +
> +/dts-v1/;
> +/plugin/;
> +
> +&{/} {
> +	panel-dpi {
> +		compatible = "panel-dpi";
> +		port {
> +			panel_in: endpoint at 0 {
> +				remote-endpoint = <&lcd_0>;
> +			};
> +		};
> +		panel-timing {
> +			clock-frequency = <0>;
> +			hactive = <0>;
> +			vactive = <0>;
> +			hfront-porch = <0>;
> +			hback-porch = <0>;
> +			hsync-len = <0>;
> +			vfront-porch = <0>;
> +			vback-porch = <0>;
> +			vsync-len = <0>;
> +			hsync-active = <0>;
> +			vsync-active = <0>;
> +			de-active = <0>;
> +			pixelclk-active = <0>;
> +			syncclk-active = <0>;
> +		};
> +	};
> +};
> +
> +&lcdc {
> +	port {
> +		lcd_0: endpoint at 0 {
> +			remote-endpoint = <&panel_in>;
> +		};
> +	};
> +};




--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From luca.ceresoli at bootlin.com  Wed Dec 17 06:23:51 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Wed, 17 Dec 2025 15:23:51 +0100
Subject: [PATCH v2 06/20] drm/tilcdc: Remove tilcdc panel driver
In-Reply-To: <20251211-feature_tilcdc-v2-6-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
 <20251211-feature_tilcdc-v2-6-f48bac3cd33e@bootlin.com>
Message-ID: <DF0K65TJOOB8.1G6MD72ZQOGFZ@bootlin.com>

On Thu Dec 11, 2025 at 5:38 PM CET, Kory Maincent (TI.com) wrote:
> The tilcdc panel subdriver is a legacy, non-standard driver that has been
> replaced by the standard panel-dpi driver and panel-simple infrastructure.
>
> With the device tree bindings removed and all in-tree users migrated to
> use panel-dpi, this driver no longer has any associated device tree
> bindings or users. The panel-dpi driver combined with DRM bus flags
> provides equivalent functionality in a standard way that is compatible
> with the broader DRM panel ecosystem.
>
> This removal eliminates 400+ lines of redundant code and completes the
> migration to standard panel handling.
>
> Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>

Reviewed-by: Luca Ceresoli <luca.ceresoli at bootlin.com>

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From luca.ceresoli at bootlin.com  Wed Dec 17 06:24:28 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Wed, 17 Dec 2025 15:24:28 +0100
Subject: [PATCH v2 10/20] drm/tilcdc: Remove unused encoder and
 connector tracking arrays
In-Reply-To: <20251211-feature_tilcdc-v2-10-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
 <20251211-feature_tilcdc-v2-10-f48bac3cd33e@bootlin.com>
Message-ID: <DF0K6MSS1DFB.N65T1V2RLN05@bootlin.com>

On Thu Dec 11, 2025 at 5:38 PM CET, Kory Maincent (TI.com) wrote:
> The num_encoders/encoders and num_connectors/connectors arrays in
> tilcdc_drm_private are never populated or used by the driver.
>
> Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>

Reviewed-by: Luca Ceresoli <luca.ceresoli at bootlin.com>

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From luca.ceresoli at bootlin.com  Wed Dec 17 06:25:21 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Wed, 17 Dec 2025 15:25:21 +0100
Subject: [PATCH v2 11/20] drm/tilcdc: Rename external_encoder and
 external_connector to encoder and connector
In-Reply-To: <20251211-feature_tilcdc-v2-11-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
 <20251211-feature_tilcdc-v2-11-f48bac3cd33e@bootlin.com>
Message-ID: <DF0K7B1PN30B.272AQ4V3PA162@bootlin.com>

On Thu Dec 11, 2025 at 5:38 PM CET, Kory Maincent (TI.com) wrote:
> Remove the "external_" prefix from encoder and connector members in the
> tilcdc driver. These are internal driver structures and the "external"
> naming is misleading. The simpler names better reflect that these are
> the primary encoder and connector managed by this driver.
>
> Also rename tilcdc_attach_external_device() to tilcdc_encoder_create()
> for consistency and to better describe the function's purpose.
>
> Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>

[...]

> @@ -65,13 +65,13 @@ int tilcdc_attach_external_device(struct drm_device *ddev)
>  	else if (ret)
>  		return ret;
>
> -	priv->external_encoder = devm_kzalloc(ddev->dev,
> -					      sizeof(*priv->external_encoder),
> -					      GFP_KERNEL);
> -	if (!priv->external_encoder)
> +	priv->encoder = devm_kzalloc(ddev->dev,
> +				     sizeof(*priv->encoder),
> +				     GFP_KERNEL);

It would be nice to rewrap this and other lines that would now probably fit
in 100 chars. But not that important, so with or without that:

Reviewed-by: Luca Ceresoli <luca.ceresoli at bootlin.com>

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From luca.ceresoli at bootlin.com  Wed Dec 17 06:25:33 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Wed, 17 Dec 2025 15:25:33 +0100
Subject: [PATCH v2 12/20] drm/tilcdc: Rename tilcdc_external to
 tilcdc_encoder
In-Reply-To: <20251211-feature_tilcdc-v2-12-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
 <20251211-feature_tilcdc-v2-12-f48bac3cd33e@bootlin.com>
Message-ID: <DF0K7GL30M9O.2Y1P92MSM6CEY@bootlin.com>

On Thu Dec 11, 2025 at 5:38 PM CET, Kory Maincent (TI.com) wrote:
> The tilcdc_external module describes the encoder part of the tilcdc
> driver. Rename it to tilcdc_encoder for better clarity and to make
> the naming more consistent with DRM subsystem conventions, where
> encoder-related files typically use "encoder" in their names.
>
> Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>

Makes sense!

Reviewed-by: Luca Ceresoli <luca.ceresoli at bootlin.com>

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From luca.ceresoli at bootlin.com  Wed Dec 17 06:25:40 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Wed, 17 Dec 2025 15:25:40 +0100
Subject: [PATCH v2 13/20] drm/tilcdc: Remove the useless module list
 support
In-Reply-To: <20251211-feature_tilcdc-v2-13-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
 <20251211-feature_tilcdc-v2-13-f48bac3cd33e@bootlin.com>
Message-ID: <DF0K7JPSOKLU.3V1FT4LAZSPGB@bootlin.com>

On Thu Dec 11, 2025 at 5:38 PM CET, Kory Maincent (TI.com) wrote:
> The tilcdc driver previously supported a sub-module system where
> external display drivers (panels, encoders) could register themselves
> through tilcdc_module_init() and be automatically initialized through
> a module list. This infrastructure became unused after the component
> framework support and panel driver was removed.
>
> Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>

[...]

> @@ -562,24 +533,7 @@ static struct platform_driver tilcdc_platform_driver = {
>  		.of_match_table = tilcdc_of_match,
>  	},
>  };
> -
> -static int __init tilcdc_drm_init(void)
> -{
> -	if (drm_firmware_drivers_only())
> -		return -ENODEV;
> -
> -	DBG("init");
> -	return platform_driver_register(&tilcdc_platform_driver);
> -}
> -
> -static void __exit tilcdc_drm_fini(void)
> -{
> -	DBG("fini");
> -	platform_driver_unregister(&tilcdc_platform_driver);
> -}
> -
> -module_init(tilcdc_drm_init);
> -module_exit(tilcdc_drm_fini);
> +module_platform_driver(tilcdc_platform_driver);

Is this hunk related to the removal of the module list? Looks like it
should be a separate patch.

With that hunk removed (or kept if I'm wrong and it should stay):
Reviewed-by: Luca Ceresoli <luca.ceresoli at bootlin.com>

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From luca.ceresoli at bootlin.com  Wed Dec 17 06:25:57 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Wed, 17 Dec 2025 15:25:57 +0100
Subject: [PATCH v2 14/20] drm/tilcdc: Modernize driver initialization
 and cleanup paths
In-Reply-To: <20251211-feature_tilcdc-v2-14-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
 <20251211-feature_tilcdc-v2-14-f48bac3cd33e@bootlin.com>
Message-ID: <DF0K7RO8E02J.1RCQAZSDLE2PD@bootlin.com>

On Thu Dec 11, 2025 at 5:38 PM CET, Kory Maincent (TI.com) wrote:
> Refactor the driver initialization to use modern DRM managed resource
> APIs, simplifying the code.
>
> The tilcdc_init and tilcdc_fini wrapper functions are removed since they
> served no purpose after the component framework was eliminated. Their
> logic is integrated directly into probe and remove.
>
> Key changes:
> - Use devm_drm_dev_alloc() instead of drm_dev_alloc().
> - Use drmm_mode_config_init() instead of drm_mode_config_init().
> - Align the remove path with the probe error path to ensure consistent
>   cleanup ordering in both success and failure cases.
> - Adjust platform_set_drvdata() to store the private structure instead
>   of the drm_device, matching the new allocation pattern.
>
> These changes reduce error-prone code while maintaining the same
> functional behavior.
>
> Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>

Overall looks good:
Reviewed-by: Luca Ceresoli <luca.ceresoli at bootlin.com>

However the diff is not very readable dues to the code moved around. I
suspect this could have been split in multiple patches: some just moving
code around and no functional changes, others doing the actual work but
without moving around code so the diff is more readable.

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From luca.ceresoli at bootlin.com  Wed Dec 17 06:26:05 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Wed, 17 Dec 2025 15:26:05 +0100
Subject: [PATCH v2 15/20] drm/tilcdc: Remove the use of drm_device
 private_data
In-Reply-To: <20251211-feature_tilcdc-v2-15-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
 <20251211-feature_tilcdc-v2-15-f48bac3cd33e@bootlin.com>
Message-ID: <DF0K7V50IFHF.2AD4ETTQ19CE0@bootlin.com>

On Thu Dec 11, 2025 at 5:38 PM CET, Kory Maincent (TI.com) wrote:
> The DRM core documentation recommends against using dev_private:
> "Instead of using this pointer it is recommended that drivers use
> embed the struct &drm_device in their larger per-device structure."
>
> This patch refactors the tilcdc driver to follow this recommendation
> by embedding struct drm_device within struct tilcdc_drm_private and
> replacing all dev->dev_private accesses with the ddev_to_tilcdc_priv()
> helper macro that uses container_of().
>
> This change aligns the driver with modern DRM best practices.
>
> Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>

Reviewed-by: Luca Ceresoli <luca.ceresoli at bootlin.com>

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From luca.ceresoli at bootlin.com  Wed Dec 17 06:26:16 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Wed, 17 Dec 2025 15:26:16 +0100
Subject: [PATCH v2 16/20] drm/bridge: tda998x: Remove component support
In-Reply-To: <20251211-feature_tilcdc-v2-16-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
 <20251211-feature_tilcdc-v2-16-f48bac3cd33e@bootlin.com>
Message-ID: <DF0K80GZ8QQZ.2HKNJGNJ4LYC9@bootlin.com>

On Thu Dec 11, 2025 at 5:39 PM CET, Kory Maincent (TI.com) wrote:
> The tilcdc driver no longer uses the component framework to bind the
> tda998x bridge driver. The component bind/unbind operations and the
> encoder initialization code are now dead code and can be safely removed.
>
> Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>

Reviewed-by: Luca Ceresoli <luca.ceresoli at bootlin.com>

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From luca.ceresoli at bootlin.com  Wed Dec 17 06:26:22 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Wed, 17 Dec 2025 15:26:22 +0100
Subject: [PATCH v2 17/20] drm/bridge: tda998x: Move
 tda998x_create/destroy into probe and remove
In-Reply-To: <20251211-feature_tilcdc-v2-17-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
 <20251211-feature_tilcdc-v2-17-f48bac3cd33e@bootlin.com>
Message-ID: <DF0K83B46R5Y.387A8AWR3CDP5@bootlin.com>

On Thu Dec 11, 2025 at 5:39 PM CET, Kory Maincent (TI.com) wrote:

Small nit:

> Now that tda998x_create and tda998x_destroy are called only in the probe
> function, there is no need for separate functions.
 ^ add "and remove" here

> Move the code into the tda998x_probe and tda998x_remove functions.
> Rewrite the cleanup path using goto calls in probe and reorder it in the
> remove function.
>
> Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>
> ---
>  drivers/gpu/drm/bridge/tda998x_drv.c | 99 +++++++++++++++++++-----------------
>  1 file changed, 51 insertions(+), 48 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/tda998x_drv.c b/drivers/gpu/drm/bridge/tda998x_drv.c
> index 865285ba2bd8c..4be49dd5bfc01 100644
> --- a/drivers/gpu/drm/bridge/tda998x_drv.c
> +++ b/drivers/gpu/drm/bridge/tda998x_drv.c
> @@ -1748,38 +1748,20 @@ static int tda998x_get_audio_ports(struct tda998x_priv *priv,
>  	return 0;
>  }
>
> -static void tda998x_destroy(struct device *dev)
> -{
> -	struct tda998x_priv *priv = dev_get_drvdata(dev);
> -
> -	drm_bridge_remove(&priv->bridge);
> -
> -	/* disable all IRQs and free the IRQ handler */
> -	cec_write(priv, REG_CEC_RXSHPDINTENA, 0);
> -	reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
> -
> -	if (priv->audio_pdev)
> -		platform_device_unregister(priv->audio_pdev);
> -
> -	if (priv->hdmi->irq)
> -		free_irq(priv->hdmi->irq, priv);

Compared to the original code being removed...

> @@ -1956,26 +1941,44 @@ static int tda998x_create(struct device *dev)
>
>  	return 0;
>
> -fail:
> -	tda998x_destroy(dev);
> -err_irq:
> +unregister_dev:
> +	i2c_unregister_device(priv->cec);
> +notifier_conn_unregister:
> +	cec_notifier_conn_unregister(priv->cec_notify);
> +free_irq:
> +	if (client->irq) {
> +		free_irq(client->irq, priv);
> +		cec_write(priv, REG_CEC_RXSHPDINTENA, 0);
> +		reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
> +	}

...here you moved free_irq() before writing registers. It should stay last,
as per free_irq() documentation.

[...]

> -static void tda998x_remove(struct i2c_client *client)
> -{
> -	tda998x_destroy(&client->dev);
> +	if (priv->audio_pdev)
> +		platform_device_unregister(priv->audio_pdev);
> +
> +	i2c_unregister_device(priv->cec);
> +
> +	cec_notifier_conn_unregister(priv->cec_notify);
> +
> +	/* disable all IRQs and free the IRQ handler */
> +	if (client->irq) {
> +		cec_write(priv, REG_CEC_RXSHPDINTENA, 0);
> +		reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
> +		free_irq(priv->hdmi->irq, priv);
> +	}

Here the order is correct.

Otherwise looks good! With the above fixed and no other changes you can
add my Reviewed-by: Luca Ceresoli <luca.ceresoli at bootlin.com>

Luca

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From luca.ceresoli at bootlin.com  Wed Dec 17 06:26:33 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Wed, 17 Dec 2025 15:26:33 +0100
Subject: [PATCH v2 18/20] drm/bridge: tda998x: Remove useless
 tda998x_connector_destroy wrapper
In-Reply-To: <20251211-feature_tilcdc-v2-18-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
 <20251211-feature_tilcdc-v2-18-f48bac3cd33e@bootlin.com>
Message-ID: <DF0K882BFGXR.24HWWIISN3RVS@bootlin.com>

On Thu Dec 11, 2025 at 5:39 PM CET, Kory Maincent (TI.com) wrote:
> Use directly drm_connector_cleanup in the destroy ops instead of having
> a custom function that does nothing more.
>
> Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>

Reviewed-by: Luca Ceresoli <luca.ceresoli at bootlin.com>

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From luca.ceresoli at bootlin.com  Wed Dec 17 06:26:41 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Wed, 17 Dec 2025 15:26:41 +0100
Subject: [PATCH v2 19/20] drm/bridge: tda998x: Add support for
 DRM_BRIDGE_ATTACH_NO_CONNECTOR
In-Reply-To: <20251211-feature_tilcdc-v2-19-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
 <20251211-feature_tilcdc-v2-19-f48bac3cd33e@bootlin.com>
Message-ID: <DF0K8BWFMM5G.2DEY7RJB6SSBA@bootlin.com>

On Thu Dec 11, 2025 at 5:39 PM CET, Kory Maincent (TI.com) wrote:
> Add support for the DRM_BRIDGE_ATTACH_NO_CONNECTOR flag to allow display
> controller drivers to create their own connectors. This modernizes the
> driver to work with the current DRM bridge framework.
>
> The implementation includes:
> - Refactoring detection and EDID reading into bridge-usable helpers
> - Adding bridge operations: edid_read, detect, hpd_enable, hpd_disable
> - Setting appropriate bridge ops (DRM_BRIDGE_OP_EDID, DRM_BRIDGE_OP_DETECT,
>   DRM_BRIDGE_OP_HPD) and connector type (HDMIA)
> - Skipping connector creation when DRM_BRIDGE_ATTACH_NO_CONNECTOR is set
> - Handling conditional connector cleanup in bridge_detach
>
> The driver maintains backward compatibility by continuing to create its
> own connector when the flag is not set.
>
> Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>

Reviewed-by: Luca Ceresoli <luca.ceresoli at bootlin.com>

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From luca.ceresoli at bootlin.com  Wed Dec 17 06:26:49 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Wed, 17 Dec 2025 15:26:49 +0100
Subject: [PATCH v2 20/20] drm/tilcdc: Add support for
 DRM_BRIDGE_ATTACH_NO_CONNECTOR
In-Reply-To: <20251211-feature_tilcdc-v2-20-f48bac3cd33e@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
 <20251211-feature_tilcdc-v2-20-f48bac3cd33e@bootlin.com>
Message-ID: <DF0K8FGRVIGZ.1UTD9XSHX4CVF@bootlin.com>

On Thu Dec 11, 2025 at 5:39 PM CET, Kory Maincent (TI.com) wrote:
> Convert the driver to use the DRM_BRIDGE_ATTACH_NO_CONNECTOR flag when
> attaching bridges. This modernizes the driver by delegating connector
> creation to the bridge subsystem through drm_bridge_connector_init()
> instead of manually searching for connectors created by the bridge.
>
> The custom tilcdc_encoder_find_connector() function is removed and
> replaced with the standard drm_bridge_connector infrastructure, which
> simplifies the code and aligns with current DRM bridge best practices.
>
> This change is safe as there are now no in-tree devicetrees that
> connect tilcdc to bridges which do not support the
> DRM_BRIDGE_ATTACH_NO_CONNECTOR flag.
>
> Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>

Reviewed-by: Luca Ceresoli <luca.ceresoli at bootlin.com>

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From lorenzo.stoakes at oracle.com  Wed Dec 17 06:28:36 2025
From: lorenzo.stoakes at oracle.com (Lorenzo Stoakes)
Date: Wed, 17 Dec 2025 14:28:36 +0000
Subject: [PATCH v2 3/3] mm: rmap: support batched unmapping for file
 large folios
In-Reply-To: <8bfcae1c-74a0-43e8-807b-fff22a770241@linux.alibaba.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <af330c9ea188bd0f28189b1e6e5803f6de9d2abe.1765439381.git.baolin.wang@linux.alibaba.com>
 <70d1dedc-b4fc-4eb6-baf6-9e54b6a62249@lucifer.local>
 <eb871ca2-47c8-4b10-a61d-321716f6c147@linux.alibaba.com>
 <CAGsJ_4xp40A3u=N5_mw00Eo6bPmFvctD3j=1Qmy3vOo2EmX3hA@mail.gmail.com>
 <9e038290-70ff-458d-b46d-bc512c3442be@linux.alibaba.com>
 <e718cfdd-a39f-48f6-98c8-f17683f29bcf@lucifer.local>
 <8bfcae1c-74a0-43e8-807b-fff22a770241@linux.alibaba.com>
Message-ID: <9d63ccc4-7243-401c-a07c-60a84392fde3@lucifer.local>

On Wed, Dec 17, 2025 at 11:11:35AM +0800, Baolin Wang wrote:
>
>
> On 2025/12/16 18:54, Lorenzo Stoakes wrote:
> > On Tue, Dec 16, 2025 at 02:22:11PM +0800, Baolin Wang wrote:
> > >
> > >
> > > On 2025/12/16 14:13, Barry Song wrote:
> > > > > > >
> > > > > > > diff --git a/mm/rmap.c b/mm/rmap.c
> > > > > > > index ec232165c47d..4c9d5777c8da 100644
> > > > > > > --- a/mm/rmap.c
> > > > > > > +++ b/mm/rmap.c
> > > > > > > @@ -1855,9 +1855,10 @@ static inline unsigned int folio_unmap_pte_batch(struct folio *folio,
> > > > > > >        end_addr = pmd_addr_end(addr, vma->vm_end);
> > > > > > >        max_nr = (end_addr - addr) >> PAGE_SHIFT;
> > > > > > >
> > > > > > > -    /* We only support lazyfree batching for now ... */
> > > > > > > -    if (!folio_test_anon(folio) || folio_test_swapbacked(folio))
> > > > > > > +    /* We only support lazyfree or file folios batching for now ... */
> > > > > > > +    if (folio_test_anon(folio) && folio_test_swapbacked(folio))
> > > > > >
> > > > > > Why is it now ok to support file-backed batched unmapping when it wasn't in
> > > > > > Barry's series (see [0])? You don't seem to be justifying this?
> > > > >
> > > > > Barry's series[0] is merely aimed at optimizing lazyfree anonymous large
> > > > > folios and does not continue to optimize anonymous large folios or
> > > > > file-backed large folios at that point.
> > > >
> > > > Yep. At that time, I didn?t have an Android machine with a filesystem
> > > > that supported large folios, so I focused on lazyfree. But I
> > > > agree that lazyfree anon folios and file folios are quite
> > > > similar.
> > > >
> > > > >
> > > > > Subsequently, Barry sent out a new patch (see [1]) to optimize anonymous
> > > > > large folios. As for file-backed large folios, the batched unmapping
> > > > > support is relatively simple, since we only need to clear the PTE
> > > > > entries for file-backed large folios.
> > > >
> > > > Yep. It is actually quite straightforward to go from lazyfree
> > > > anon folios to file folios. Swap-backed anon folios are much
> > > > more tricky, though.
> > >
> > > Agree. Thanks Barry for reviewing and confirming.
> >
> > OK that makes me less concerned, but you do need to put some more justification
> > in the commit message.
>
> Sure. Will do.

Thanks!


From maz at kernel.org  Wed Dec 17 06:29:18 2025
From: maz at kernel.org (Marc Zyngier)
Date: Wed, 17 Dec 2025 14:29:18 +0000
Subject: [PATCH 18/32] KVM: arm64: gic-v5: Check for pending PPIs
In-Reply-To: <20251212152215.675767-19-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	<20251212152215.675767-19-sascha.bischoff@arm.com>
Message-ID: <86zf7hmbb5.wl-maz@kernel.org>

On Fri, 12 Dec 2025 15:22:41 +0000,
Sascha Bischoff <Sascha.Bischoff at arm.com> wrote:
> 
> This change allows KVM to check for pending PPI interrupts. This has
> two main components:
> 
> First of all, the effective priority mask is calculated.  This is a
> combination of the priority mask in the VPEs ICC_PCR_EL1.PRIORITY and
> the currently running priority as determined from the VPE's
> ICH_APR_EL1. If an interrupt's prioirity is greater than or equal to
> the effective priority mask, it can be signalled. Otherwise, it
> cannot.
> 
> Secondly, any Enabled and Pending PPIs must be checked against this
> compound priority mask. The reqires the PPI priorities to by synced
> back to the KVM shadow state - this is skipped in general operation as
> it isn't required and is rather expensive. If any Enabled and Pending
> PPIs are of sufficient priority to be signalled, then there are
> pending PPIs. Else, there are not.  This ensures that a VPE is not
> woken when it cannot actually process the pending interrupts.
> 
> Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
> ---
>  arch/arm64/kvm/vgic/vgic-v5.c | 123 ++++++++++++++++++++++++++++++++++
>  arch/arm64/kvm/vgic/vgic.c    |  10 ++-
>  arch/arm64/kvm/vgic/vgic.h    |   1 +
>  3 files changed, 131 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
> index d54595fbf4586..35740e88b3591 100644
> --- a/arch/arm64/kvm/vgic/vgic-v5.c
> +++ b/arch/arm64/kvm/vgic/vgic-v5.c
> @@ -54,6 +54,31 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
>  	return 0;
>  }
>  
> +static u32 vgic_v5_get_effective_priority_mask(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> +	unsigned highest_ap, priority_mask;

Please use explicit types that match their assignment.

> +
> +	/*
> +	 * Counting the number of trailing zeros gives the current
> +	 * active priority. Explicitly use the 32-bit version here as
> +	 * we have 32 priorities. 0x20 then means that there are no
> +	 * active priorities.
> +	 */
> +	highest_ap = __builtin_ctz(cpu_if->vgic_apr);

From https://gcc.gnu.org/onlinedocs/gcc/Bit-Operation-Builtins.html

<quote>
Built-in Function: int __builtin_ctz (unsigned int x)

    Returns the number of trailing 0-bits in x, starting at the least
significant bit position. If x is 0, the result is undefined.
</quote>

We really don't like undefined results.

> +
> +	/*
> +	 * An interrupt is of sufficient priority if it is equal to or
> +	 * greater than the priority mask. Add 1 to the priority mask
> +	 * (i.e., lower priority) to match the APR logic before taking
> +	 * the min. This gives us the lowest priority that is masked.
> +	 */
> +	priority_mask = FIELD_GET(FEAT_GCIE_ICH_VMCR_EL2_VPMR, cpu_if->vgic_vmcr);
> +	priority_mask = min(highest_ap, priority_mask + 1);
> +
> +	return priority_mask;
> +}
> +
>  static bool vgic_v5_ppi_set_pending_state(struct kvm_vcpu *vcpu,
>  					  struct vgic_irq *irq)
>  {
> @@ -121,6 +146,104 @@ void vgic_v5_set_ppi_ops(struct vgic_irq *irq)
>  	irq->ops = &vgic_v5_ppi_irq_ops;
>  }
>  
> +
> +/*
> + * Sync back the PPI priorities to the vgic_irq shadow state
> + */
> +static void vgic_v5_sync_ppi_priorities(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> +	unsigned long flags;
> +	int i, reg;
> +
> +	/* We have 16 PPI Priority regs */
> +	for (reg = 0; reg < 16; reg++) {
> +		const unsigned long priorityr = cpu_if->vgic_ppi_priorityr[reg];
> +
> +		for (i = 0; i < 8; ++i) {

Urgh... 128 locks being taken is no good. We need something better.

> +			struct vgic_irq *irq;
> +			u32 intid;
> +			u8 priority;
> +
> +			priority = (priorityr >> (i * 8)) & 0x1f;
> +
> +			intid = FIELD_PREP(GICV5_HWIRQ_TYPE, GICV5_HWIRQ_TYPE_PPI);
> +			intid |= FIELD_PREP(GICV5_HWIRQ_ID, reg * 8 + i);
> +
> +			irq = vgic_get_vcpu_irq(vcpu, intid);
> +			raw_spin_lock_irqsave(&irq->irq_lock, flags);
> +
> +			irq->priority = priority;
> +
> +			raw_spin_unlock_irqrestore(&irq->irq_lock, flags);

scoped_guard()

> +			vgic_put_irq(vcpu->kvm, irq);
> +		}
> +	}
> +}
> +
> +bool vgic_v5_has_pending_ppi(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> +	unsigned long flags;
> +	int i, reg;
> +	unsigned int priority_mask;
> +
> +	/* If no pending bits are set, exit early */
> +	if (likely(!cpu_if->vgic_ppi_pendr[0] && !cpu_if->vgic_ppi_pendr[1]))
> +		return false;
> +
> +	priority_mask = vgic_v5_get_effective_priority_mask(vcpu);
> +
> +	/* If the combined priority mask is 0, nothing can be signalled! */
> +	if (!priority_mask)
> +		return false;
> +
> +	/* The shadow priority is only updated on demand, sync it across first */
> +	vgic_v5_sync_ppi_priorities(vcpu);
> +
> +	for (reg = 0; reg < 2; reg++) {
> +		unsigned long possible_bits;
> +		const unsigned long enabler = cpu_if->vgic_ich_ppi_enabler_exit[reg];
> +		const unsigned long pendr = cpu_if->vgic_ppi_pendr_exit[reg];
> +		bool has_pending = false;
> +
> +		/* Check all interrupts that are enabled and pending */
> +		possible_bits = enabler & pendr;
> +
> +		/*
> +		 * Optimisation: pending and enabled with no active priorities
> +		 */
> +		if (possible_bits && priority_mask > 0x1f)
> +			return true;
> +
> +		for_each_set_bit(i, &possible_bits, 64) {
> +			struct vgic_irq *irq;
> +			u32 intid;
> +
> +			intid = FIELD_PREP(GICV5_HWIRQ_TYPE, GICV5_HWIRQ_TYPE_PPI);
> +			intid |= FIELD_PREP(GICV5_HWIRQ_ID, reg * 64 + i);
> +
> +			irq = vgic_get_vcpu_irq(vcpu, intid);
> +			raw_spin_lock_irqsave(&irq->irq_lock, flags);
> +
> +			/*
> +			 * We know that the interrupt is enabled and pending, so
> +			 * only check the priority.
> +			 */
> +			if (irq->priority <= priority_mask)
> +				has_pending = true;
> +
> +			raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
> +			vgic_put_irq(vcpu->kvm, irq);
> +
> +			if (has_pending)
> +				return true;
> +		}
> +	}

So we do this stuff *twice*. Doesn't strike me as being optimal. It is
also not clear that we need to resync it all when calling
kvm_vgic_vcpu_pending_irq(), which can happen for any odd reason
(spurious wake-up from kvm_vcpu_check_block()).

> +
> +	return false;
> +}
> +
>  /*
>   * Detect any PPIs state changes, and propagate the state with KVM's
>   * shadow structures.
> diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
> index e534876656ca7..5d18a03cc11d5 100644
> --- a/arch/arm64/kvm/vgic/vgic.c
> +++ b/arch/arm64/kvm/vgic/vgic.c
> @@ -1174,11 +1174,15 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
>  	unsigned long flags;
>  	struct vgic_vmcr vmcr;
>  
> -	if (!vcpu->kvm->arch.vgic.enabled)
> +	if (!vcpu->kvm->arch.vgic.enabled && !vgic_is_v5(vcpu->kvm))
>  		return false;
>  
> -	if (vcpu->arch.vgic_cpu.vgic_v3.its_vpe.pending_last)
> -		return true;
> +	if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5) {
> +		return vgic_v5_has_pending_ppi(vcpu);
> +	} else {

Drop the 'else'.

> +		if (vcpu->arch.vgic_cpu.vgic_v3.its_vpe.pending_last)
> +			return true;
> +	}
>  
>  	vgic_get_vmcr(vcpu, &vmcr);
>  
> diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
> index 5a77318ddb87a..4b3a1e7ca3fb4 100644
> --- a/arch/arm64/kvm/vgic/vgic.h
> +++ b/arch/arm64/kvm/vgic/vgic.h
> @@ -387,6 +387,7 @@ void vgic_debug_destroy(struct kvm *kvm);
>  int vgic_v5_probe(const struct gic_kvm_info *info);
>  void vgic_v5_set_ppi_ops(struct vgic_irq *irq);
>  int vgic_v5_set_ppi_dvi(struct kvm_vcpu *vcpu, u32 irq, bool dvi);
> +bool vgic_v5_has_pending_ppi(struct kvm_vcpu *vcpu);
>  void vgic_v5_flush_ppi_state(struct kvm_vcpu *vcpu);
>  void vgic_v5_fold_irq_state(struct kvm_vcpu *vcpu);
>  void vgic_v5_load(struct kvm_vcpu *vcpu);

Thanks,

	M.

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


From suzuki.poulose at arm.com  Wed Dec 17 06:29:46 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Wed, 17 Dec 2025 14:29:46 +0000
Subject: [PATCH v12 11/46] arm64: RMI: Activate realm on first VCPU run
In-Reply-To: <20251217101125.91098-12-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
 <20251217101125.91098-12-steven.price@arm.com>
Message-ID: <f04bdf46-c752-43ec-88fa-dcd37f29d374@arm.com>

On 17/12/2025 10:10, Steven Price wrote:
> When a VCPU migrates to another physical CPU check if this is the first
> time the guest has run, and if so activate the realm.
> 
> Before the realm can be activated it must first be created, this is a
> stub in this patch and will be filled in by a later patch.
> 
> Signed-off-by: Steven Price <steven.price at arm.com>
> ---
> New patch for v12
> ---
>   arch/arm64/include/asm/kvm_rmi.h |  1 +
>   arch/arm64/kvm/arm.c             |  6 +++++
>   arch/arm64/kvm/rmi.c             | 42 ++++++++++++++++++++++++++++++++
>   3 files changed, 49 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_rmi.h
> index cb7350f8a01a..e4534af06d96 100644
> --- a/arch/arm64/include/asm/kvm_rmi.h
> +++ b/arch/arm64/include/asm/kvm_rmi.h
> @@ -69,6 +69,7 @@ void kvm_init_rmi(void);
>   u32 kvm_realm_ipa_limit(void);
>   
>   int kvm_init_realm_vm(struct kvm *kvm);
> +int kvm_activate_realm(struct kvm *kvm);
>   void kvm_destroy_realm(struct kvm *kvm);
>   void kvm_realm_destroy_rtts(struct kvm *kvm);
>   
> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
> index 941d1bec8e77..542df37b9e82 100644
> --- a/arch/arm64/kvm/arm.c
> +++ b/arch/arm64/kvm/arm.c
> @@ -951,6 +951,12 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
>   			return ret;
>   	}
>   
> +	if (kvm_is_realm(vcpu->kvm)) {
> +		ret = kvm_activate_realm(kvm);
> +		if (ret)
> +			return ret;
> +	}
> +
>   	mutex_lock(&kvm->arch.config_lock);
>   	set_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags);
>   	mutex_unlock(&kvm->arch.config_lock);
> diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
> index e57e8b7eafa9..98929382c365 100644
> --- a/arch/arm64/kvm/rmi.c
> +++ b/arch/arm64/kvm/rmi.c
> @@ -223,6 +223,48 @@ void kvm_realm_destroy_rtts(struct kvm *kvm)
>   	WARN_ON(realm_tear_down_rtt_range(realm, 0, (1UL << ia_bits)));
>   }
>   
> +static int realm_ensure_created(struct kvm *kvm)
> +{
> +	/* Provided in later patch */
> +	return -ENXIO;
> +}
> +
> +int kvm_activate_realm(struct kvm *kvm)
> +{
> +	struct realm *realm = &kvm->arch.realm;
> +	int ret;
> +
> +	if (!kvm_is_realm(kvm))
> +		return -ENXIO;
> +
> +	if (kvm_realm_state(kvm) == REALM_STATE_ACTIVE)
> +		return 0;
> +
> +	guard(mutex)(&kvm->arch.config_lock);
> +	/* Check again with the lock held */
> +	if (kvm_realm_state(kvm) == REALM_STATE_ACTIVE)
> +		return 0;
> +
> +	ret = realm_ensure_created(kvm);
> +	if (ret)
> +		return ret;
> +
> +	/* Mark state as dead in case we fail */
> +	WRITE_ONCE(realm->state, REALM_STATE_DEAD);
> +
> +	if (!irqchip_in_kernel(kvm)) {
> +		/* Userspace irqchip not yet supported with realms */
> +		return -EOPNOTSUPP;
> +	}

super minor nit: We could do this check before create the realm, within
the config_lock'ed region.

Suzuki



From luca.ceresoli at bootlin.com  Wed Dec 17 06:31:01 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Wed, 17 Dec 2025 15:31:01 +0100
Subject: [PATCH v3 01/22] drm/bridge: add of_drm_find_and_get_bridge()
In-Reply-To: <0ba037c65f9cadd51082abf2b7857ba7@kernel.org>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-1-b5165fab8058@bootlin.com> <0ba037c65f9cadd51082abf2b7857ba7@kernel.org>
Message-ID: <DF0KBN5Y22XW.2RE8HKDFY87XK@bootlin.com>

Hi Maxime,

On Wed Dec 17, 2025 at 11:15 AM CET, Maxime Ripard wrote:
> On Tue, 16 Dec 2025 18:58:34 +0100, Luca Ceresoli wrote:
>> of_drm_find_bridge() does not increment the refcount for the returned
>> bridge, but that is required now. However converting it and all its users
>> is not realistically doable at once given the large amount of (direct and
>> indirect) callers and the complexity of some.
>>
>>
>> [ ... ]
>
> Reviewed-by: Maxime Ripard <mripard at kernel.org>

Thank you for the prompt review!

All patches are reviewed now except patch 18 which has no reply. I'm just
pointing out in case it's something you missed.

Luca

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From lorenzo.stoakes at oracle.com  Wed Dec 17 06:50:50 2025
From: lorenzo.stoakes at oracle.com (Lorenzo Stoakes)
Date: Wed, 17 Dec 2025 14:50:50 +0000
Subject: [PATCH v2 1/3] arm64: mm: support batch clearing of the young
 flag for large folios
In-Reply-To: <37915af9-d307-4955-969e-c16ea26f7f4a@linux.alibaba.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <e10f876ce130134fa089befe83f30561b48b9889.1765439380.git.baolin.wang@linux.alibaba.com>
 <5039c6a2-09b6-4c9b-accb-26583ba120db@lucifer.local>
 <1a0001cd-c38d-403b-b3ef-d19e85acd772@linux.alibaba.com>
 <671ac450-4a59-4e26-b098-7cf65add1e75@lucifer.local>
 <37915af9-d307-4955-969e-c16ea26f7f4a@linux.alibaba.com>
Message-ID: <16d6642b-6f22-4d7b-94d6-92692b63cbd9@lucifer.local>

On Wed, Dec 17, 2025 at 11:53:31AM +0800, Baolin Wang wrote:
>
>
> On 2025/12/16 19:11, Lorenzo Stoakes wrote:
> > On Tue, Dec 16, 2025 at 11:32:58AM +0800, Baolin Wang wrote:
> > >
> > >
> > > On 2025/12/15 19:36, Lorenzo Stoakes wrote:
> > > > On Thu, Dec 11, 2025 at 04:16:54PM +0800, Baolin Wang wrote:
> > > > > Currently, contpte_ptep_test_and_clear_young() and contpte_ptep_clear_flush_young()
> > > > > only clear the young flag and flush TLBs for PTEs within the contiguous range.
> > > > > To support batch PTE operations for other sized large folios in the following
> > > > > patches, adding a new parameter to specify the number of PTEs.
> > > > >
> > > > > While we are at it, rename the functions to maintain consistency with other
> > > > > contpte_*() functions.
> > > > >
> > > > > Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
> > > > > ---
> > > > >    arch/arm64/include/asm/pgtable.h | 12 ++++-----
> > > > >    arch/arm64/mm/contpte.c          | 44 ++++++++++++++++++++++----------
> > > > >    2 files changed, 37 insertions(+), 19 deletions(-)
> > > > >
> > > > > diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
> > > > > index 0944e296dd4a..e03034683156 100644
> > > > > --- a/arch/arm64/include/asm/pgtable.h
> > > > > +++ b/arch/arm64/include/asm/pgtable.h
> > > > > @@ -1679,10 +1679,10 @@ extern void contpte_clear_full_ptes(struct mm_struct *mm, unsigned long addr,
> > > > >    extern pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
> > > > >    				unsigned long addr, pte_t *ptep,
> > > > >    				unsigned int nr, int full);
> > > > > -extern int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
> > > > > -				unsigned long addr, pte_t *ptep);
> > > > > -extern int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
> > > > > -				unsigned long addr, pte_t *ptep);
> > > > > +extern int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
> > > > > +				unsigned long addr, pte_t *ptep, unsigned int nr);
> > > > > +extern int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
> > > > > +				unsigned long addr, pte_t *ptep, unsigned int nr);
> > > >
> > > > In core mm at least, as a convention, we strip 'extern' from header declarations
> > > > as we go as they're not necessary.
> > >
> > > Sure. I can remove the 'extern'.
> >
> > Thanks.
> >
> > >
> > > > I wonder about this naming convention also. The contpte_xxx_() prefix
> > > > obviously implies we are operating upon PTEs in the contiguous range, now
> > > > we are doing something... different and 'nr' is a bit vague.
> > > >
> > > > Is it the nr of contiguous ranges? Well in reality it's nr_pages right? But
> > >
> > > Yes, 'nr' here means nr_pages, which follows the convention of the
> > > parameters in contpte_xxx_() functions.
> >
> > Except you're violating the convention already by doing non-contpte stuff in
> > contpte functions?
>
> Nope. Sorry for my poor English, which might have caused some confusion. I
> followed the contpte's convention, and let me try to explain it again below.
>
> > The confusion is between nr of contpte ranges and nr of pages, so I think we
> > should be explicit.
> >
> > >
> > > > now we're not saying they're necessarily contiguous in the sense of contpte...
> > > >
> > > > I wonder whether we'd be better off introducing a new function that
> > > > explicitly has 'batch' or 'batched' in the name, and have the usual
> > > > contpte_***() stuff and callers that need batching using a new underlying helper?
> > >
> > > OK. I get your point. However, this is outside the scope of my patchset.
> >
> > Well, no, this is review feedback that needs to be addressed, I really don't
> > like this patch as-is.
> >
> > So for this to be upstreamable you really need to separate this out.
> >
> > >
> > > Perhaps we can clean up all the contpte_xxx_() functions if everyone agrees
> > > that this is confusing.
> >
> > I mean, unless Ryan explicitly makes a case for this being fine, I'm inclined to
> > reject the patch unless we do this.
> >
> > The contpte logic is already very confusing, and this is only adding to it.
> >
> > >
> > > > Obviously I defer to Ryan on all this, just my thoughts...
> > > >
> > > > >    extern void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
> > > > >    				pte_t *ptep, unsigned int nr);
> > > > >    extern int contpte_ptep_set_access_flags(struct vm_area_struct *vma,
> > > > > @@ -1854,7 +1854,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
> > > > >    	if (likely(!pte_valid_cont(orig_pte)))
> > > > >    		return __ptep_test_and_clear_young(vma, addr, ptep);
> > > > >
> > > > > -	return contpte_ptep_test_and_clear_young(vma, addr, ptep);
> > > > > +	return contpte_test_and_clear_young_ptes(vma, addr, ptep, CONT_PTES);
> > > > >    }
> > > > >
> > > > >    #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
> > > > > @@ -1866,7 +1866,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
> > > > >    	if (likely(!pte_valid_cont(orig_pte)))
> > > > >    		return __ptep_clear_flush_young(vma, addr, ptep);
> > > > >
> > > > > -	return contpte_ptep_clear_flush_young(vma, addr, ptep);
> > > > > +	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
> > > > >    }
> > > > >
> > > > >    #define wrprotect_ptes wrprotect_ptes
> > > > > diff --git a/arch/arm64/mm/contpte.c b/arch/arm64/mm/contpte.c
> > > > > index c0557945939c..19b122441be3 100644
> > > > > --- a/arch/arm64/mm/contpte.c
> > > > > +++ b/arch/arm64/mm/contpte.c
> > > > > @@ -488,8 +488,9 @@ pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
> > > > >    }
> > > > >    EXPORT_SYMBOL_GPL(contpte_get_and_clear_full_ptes);
> > > > >
> > > > > -int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
> > > > > -					unsigned long addr, pte_t *ptep)
> > > > > +int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
> > > > > +					unsigned long addr, pte_t *ptep,
> > > > > +					unsigned int nr)
> > > > >    {
> > > > >    	/*
> > > > >    	 * ptep_clear_flush_young() technically requires us to clear the access
> > > > > @@ -500,39 +501,56 @@ int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
> > > > >    	 * having to unfold.
> > > > >    	 */
> > > >
> > > > Hmm shouldn't you need to update this comment now 'nr' is a thing? E.g.:
> > > >
> > > > "And since we only create a contig range when the range is covered by a single
> > > > folio, we can get away with clearing young for the whole contig range here, so
> > > > we avoid having to unfold."
> > >
> > > I think the original comments are still clear:
> > > "
> > > /*
> > >   * ptep_clear_flush_young() technically requires us to clear the access
> > >   * flag for a _single_ pte. However, the core-mm code actually tracks
> > >   * access/dirty per folio, not per page. And since we only create a
> > >   * contig range when the range is covered by a single folio, we can get
> > >   * away with clearing young for the whole contig range here, so we avoid
> > >   * having to unfold.
> > >   */
> > > "
> >
> > Except nr means you can span more than a single contig pte range? So this
> > comment is no longer applicable as-is?
>
> The nr means consecutive (present) PTEs that map consecutive pages of the
> same large folio in a single VMA and a single page table.
>
> I think this is a prerequisite. If you think it's necessary to explain it, I
> can add it to the comments.
>
> > You've changed the function, the comment needs to change too.
> >
> > >
> > > > However now you're allowing for large folios that are not contpte?
> > > >
> > > > Overall feeling pretty iffy about implementing this this way.
> > >
> > > Please see the above comments, which explain why we should do that.
> >
> > You haven't explained anything? Maybe I missed it?
> >
> > Can you explain clearly what nr might actually be in relation to contpte's? I'm
> > confused even as to the utility here.
> >
> > Is it batched ranges of contptes? But then why are you trying to see if end is a
> > contpte + expand the range if so?
>
> See below.
>
> > > > > +	unsigned long start = addr;
> > > > > +	unsigned long end = start + nr * PAGE_SIZE;
> > > >
> > > > So now [addr, addr + nr * PAGE_SIZE) must for sure be within a single PTE
> > > > table?
> > >
> > > Caller has made sure that (see folio_referenced_one()).
> >
> > You should comment this somehow, I hate this nested assumptions stuff 'function
> > X which calls function Y which calls function Z makes sure that parameter A
> > fulfils requirements B but we don't mention it anywhere'.
>
> Sure.
>
> > > > >    	int young = 0;
> > > > >    	int i;
> > > > >
> > > > > -	ptep = contpte_align_down(ptep);
> > > > > -	addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
> > > > > +	if (pte_cont(__ptep_get(ptep + nr - 1)))
> > > > > +		end = ALIGN(end, CONT_PTE_SIZE);
> > > >
> > > > OK so I guess for PTE_CONT to be set, it must be aligned to CONT_PTE_SIZE,
> > > > with other PTE entries present there not having PTE_CONT set (Ryan - do
> > > > correct me if I'm wrong!)
> > > >
> > > > I guess then no worry about running off the end of the PTE table here.
> > > >
> > > > I wonder about using pte_cont_addr_end() here, but I guess you are not
> > > > intending to limit to a range here but rather capture the entire contpte
> > > > range of the end.
> > >
> > > Right.
> > >
> > > > I don't love that now a function prefixed with contpte_... can have a
> > > > condition where part of the input range is _not_ a contpte entry, or is
> > > > specified partially...
> > >
> > > Like I said above, this is outside the scope of my patchset. If Ryan also
> > > thinks we need to do some cleanups for all the contpte_xxx() functions in
> > > the contpte.c file, we can send a follow-up patchset to rename all the
> > > contpte_xxx() functions to make it clear.
> >
> > It's really not outside of the scope of the patch set, this is review feedback
> > you have to address :) trying not to be a grumpy kernel dev here :>)
> >
> > In general in the kernel we don't accept confusing patches then defer making
> > them not-confusing until later.
> >
> > We review until the series is at the correct standard to be accepted before we
> > merge.
> >
> > As always I'm happy to be convinced that I'm mistaken or something's not
> > necesary, however!
>
> Yes, let me try to explain it again. See below.
>
> > > > > -	for (i = 0; i < CONT_PTES; i++, ptep++, addr += PAGE_SIZE)
> > > > > -		young |= __ptep_test_and_clear_young(vma, addr, ptep);
> > > > > +	if (pte_cont(__ptep_get(ptep))) {
> > > > > +		start = ALIGN_DOWN(start, CONT_PTE_SIZE);
> > > > > +		ptep = contpte_align_down(ptep);
> > > > > +	}
> > > > > +
> > > > > +	nr = (end - start) / PAGE_SIZE;
> > > >
> > > > Hm don't love this reuse of input param.
> > >
> > > OK. Will use another local variable instead.
> >
> > Thanks.
> >
> > >
> > > >
> > > > > +	for (i = 0; i < nr; i++, ptep++, start += PAGE_SIZE)
> > > > > +		young |= __ptep_test_and_clear_young(vma, start, ptep);
> > > >
> > > > Again, overall find it a bit iffy that we are essentially overloading the
> > > > code with non-contpte behaviour.
> > >
> > > Let me clarify further: this is the handling logic of the contpte_xxx()
> > > functions in the contpte.c file. For example, the function
> > > contpte_set_ptes() has a parameter 'nr', which may be greater than
> > > CONT_PTES, meaning that it can handle multiple CONT_PTES range sizes of a
> > > large folio.
> > >
> > > It might be a bit confusing, and I understand this is why you want to change
> > > the 'contpte_' prefix to the 'batch_' prefix. Of course, we can hope Ryan
> > > can provide some input on this.
> > >
> > > Thanks for reviewing.
> >
> > OK so we have some reeeeal confusion here. And this speaks to the patch needing
> > work.
> >
> > This seems to answer what I asked above - basically - are we doing _batches_ of
> > _contpte_ entries, or are we just accepting arbitrary large folios here and
> > batching up operations on them, including non-contpte entries.
> >
> > Presumably from the above you're saying - this is dealing with batches of
> > contpte entries.
> >
> > In which case this has to be made _super_ clear. Not just adding an arbitrary
> > 'nr' parameter and letting people guess.
> >
> > The contpte code is _already_ confusing and somewhat surprising if you're not
> > aware of it, we need to be going in the other direction.
>
> Sure. Sorry for causing confusion. I try to explain it again to make it
> clear.
>
> First, it is necessary to explain how the contpte implementation in Arm64 is
> exposed, using set_ptes() as an example.
>
> Arm64 defines an arch-specific implementation of set_ptes():
> "
> static __always_inline void set_ptes(struct mm_struct *mm, unsigned long
> addr,
> 				pte_t *ptep, pte_t pte, unsigned int nr)
> {
> 	pte = pte_mknoncont(pte);
>
> 	if (likely(nr == 1)) {
> 		contpte_try_unfold(mm, addr, ptep, __ptep_get(ptep));
> 		__set_ptes(mm, addr, ptep, pte, 1);
> 		contpte_try_fold(mm, addr, ptep, pte);
> 	} else {
> 		contpte_set_ptes(mm, addr, ptep, pte, nr);
> 	}
> }
> "
>
> Here, 'nr' refers to consecutive (present) PTEs that map consecutive pages
> of the same large folio within a single VMA and a single page table. Based
> on 'nr', it determines whether the PTE_CONT attribute should be set or not.
>
> Second, the underlying implementation of contpte_set_ptes() also calculates
> 'end' based on 'nr' and checks whether the PTE_CONT attribute should be set.
> For example:
>
> For a large folio with order = 3 (nr = 8), the PTE_CONT attribute will not
> be set since the 'next' is not aligned with CONT_PTE_MASK.
>
> For a large folio with order = 4 (nr = 16), it aligns perfectly, allowing
> the PTE_CONT attribute to be set for the entire PTE entries of the large
> folio.
>
> For a large folio with order = 5 (nr = 32), this involves two ranges of
> CONT_PTE_SIZE (16 PTEs in each range), requiring the PTE_CONT attribute to
> be set separately for each range.
>
> "
> void contpte_set_ptes(struct mm_struct *mm, unsigned long addr,
> 					pte_t *ptep, pte_t pte, unsigned int nr)
> {
> 	.......
>
> 	end = addr + (nr << PAGE_SHIFT);
> 	pfn = pte_pfn(pte);
> 	prot = pte_pgprot(pte);
>
> 	do {
> 		next = pte_cont_addr_end(addr, end);
> 		nr = (next - addr) >> PAGE_SHIFT;
> 		pte = pfn_pte(pfn, prot);
>
> 		if (((addr | next | (pfn << PAGE_SHIFT)) & ~CONT_PTE_MASK) == 0)
> 			pte = pte_mkcont(pte);
> 		else
> 			pte = pte_mknoncont(pte);
>
> 		__set_ptes(mm, addr, ptep, pte, nr);
>
> 		addr = next;
> 		ptep += nr;
> 		pfn += nr;
>
> 	} while (addr != end);
> }
> "
>
> Third, regarding the implementation of my patch, I have followed the contpte
> logic here by adding the 'nr' parameter to
> contpte_ptep_test_and_clear_young() for batch processing consecutive
> (present) PTEs. Moreover, the semantics of 'nr' remain consistent with the
> original contpte functions, and I have not broken the existing contpte
> implementation logic.

OK that helps a lot thanks.

So the nr will be number of PTEs that are consecutive, belong to the same folio,
and have the same PTE bit set excluding accessed, writable, dirty, soft-dirty.

But since we are retrieving accessed bit state (young), isn't it a problem we're
ignoring this bit when considering what goes into the batch?

I mean now it's going to return true even if some do not have the accessed flag
set?

I am more convinced things are correct in style at least then this way as, as
you say, this is the approach taken in set_ptes().

Thanks, Lorenzo


From maz at kernel.org  Wed Dec 17 06:55:57 2025
From: maz at kernel.org (Marc Zyngier)
Date: Wed, 17 Dec 2025 14:55:57 +0000
Subject: [PATCH v12 00/46] arm64: Support for Arm CCA in KVM
In-Reply-To: <20251217101125.91098-1-steven.price@arm.com>
References: <20251217101125.91098-1-steven.price@arm.com>
Message-ID: <86y0n1ma2q.wl-maz@kernel.org>

On Wed, 17 Dec 2025 10:10:37 +0000,
Steven Price <steven.price at arm.com> wrote:
> 
> This series adds support for running protected VMs using KVM under the
> Arm Confidential Compute Architecture (CCA). I've changed the uAPI
> following feedback from Marc.
> 
> The main change is that rather than providing a multiplex CAP and
> expecting the VMM to drive the different stages of realm construction,
> there's now just a minimal interface and KVM performs the necessary
> operations when needed.

What are the relevant patches? I'd rather not look at the non-2.0
patches at all, given that they are pretty meaningless for KVM.

	M.

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


From broonie at kernel.org  Wed Dec 17 07:09:44 2025
From: broonie at kernel.org (Mark Brown)
Date: Wed, 17 Dec 2025 15:09:44 +0000
Subject: [BUG][RT][ti-j72xx] spi: cadence-quadspi: boot failed with
 rtmutex deadlock detected
In-Reply-To: <CO6PR11MB558695EFB87C578370014430CDABA@CO6PR11MB5586.namprd11.prod.outlook.com>
References: <CO6PR11MB558695EFB87C578370014430CDABA@CO6PR11MB5586.namprd11.prod.outlook.com>
Message-ID: <8bc899ad-9fd8-428c-8c56-97e56e8e45b9@sirena.org.uk>

On Wed, Dec 17, 2025 at 08:21:19AM +0000, He, Guocai (CN) wrote:

> Kernel:
>   v6.1/standard/preempt-rt/ti-sdk-6.1/ti-j7xxx
>   (based on Linux v6.1.159 PREEMPT_RT)

v6.1 is pretty old.

> It is ok at da3c5173c55f?but it is bad at 7083c6620486.
> I revert the commit(2c914aac952) which merged from stable release,  it also ok at 18db8c7f20a6.
> Maybe it is a compatibility issue between v6.1/standard/preempt-rt/ti-sdk-6.1/ti-j7xxx and the stable release.

> if this is an known issue ? 

This isn't something I've heard about before, and there are no fixes for
that commit in -next.  It's entirely plausible that whatever issue this
is also exists in mainline, looking at the patch it's likely there were
problems before this with the locking just not happening properly at all.

Please include human readable descriptions of things like commits and
issues being discussed in e-mail in your mails, this makes them much
easier for humans to read especially when they have no internet access.
I do frequently catch up on my mail on flights or while otherwise
travelling so this is even more pressing for me than just being about
making things a bit easier to read.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251217/73b76f84/attachment.sig>

From vbabka at suse.cz  Wed Dec 17 07:10:54 2025
From: vbabka at suse.cz (Vlastimil Babka)
Date: Wed, 17 Dec 2025 16:10:54 +0100
Subject: [PATCH 0/2] introduce pagetable_alloc_nolock()
In-Reply-To: <DF0J58HOVLL4.2E16Q87D2UXRW@google.com>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com>
 <916c17ba-22b1-456e-a184-cb3f60249af7@arm.com>
 <aUGOPd7gNRf1xHEc@e129823.arm.com>
 <100cc8da-b826-4fc2-a624-746bf6fb049d@arm.com>
 <aUKKZR0u22KOPfd7@e129823.arm.com>
 <d96ac977-222e-4e8d-9487-da1306198419@arm.com>
 <aUKnfU/3FREY13g1@e129823.arm.com>
 <d912480a-5229-4efe-9336-b31acded30f5@suse.cz>
 <DF0J58HOVLL4.2E16Q87D2UXRW@google.com>
Message-ID: <d5354d96-6f28-41d7-9f66-64c254d9477b@suse.cz>

On 12/17/25 14:35, Brendan Jackman wrote:
> On Wed Dec 17, 2025 at 1:15 PM UTC, Vlastimil Babka wrote:
>> On 12/17/25 13:52, Yeoreum Yun wrote:
>>>> On 17/12/2025 10:48, Yeoreum Yun wrote:
>>>> > Hi Ryan,
>>>> >
>>>> >> On 16/12/2025 16:52, Yeoreum Yun wrote:
>>>> >>> Hi Ryan,
>>>> >>>
>>>> >>>> On 12/12/2025 16:18, Yeoreum Yun wrote:
>>>> >>>>> Some architectures invoke pagetable_alloc() or __get_free_pages()
>>>> >>>>> with preemption disabled.
>>>> >>>>> For example, in arm64, linear_map_split_to_ptes() calls pagetable_alloc()
>>>> >>>>> while spliting block entry to ptes and __kpti_install_ng_mappings()
>>>> >>>>> calls __get_free_pages() to create kpti pagetable.
>>>> >>>>>
>>>> >>>>> Under PREEMPT_RT, calling pagetable_alloc() with
>>>> >>>>> preemption disabled is not allowed, because it may acquire
>>>> >>>>> a spin lock that becomes sleepable on RT, potentially
>>>> >>>>> causing a sleep during page allocation.
>>>> >>>>>
>>>> >>>>> Since above two functions is called as callback of stop_machine()
>>>> >>>>> where its callback is called in preemption disabled,
>>>> >>>>> They could make a potential problem. (sleeping in preemption disabled).
>>>> >>>>>
>>>> >>>>> To address this, introduce pagetable_alloc_nolock() API.
>>>> >>>>
>>>> >>>> I don't really understand what the problem is that you're trying to fix. As I
>>>> >>>> see it, there are 2 call sites in arm64 arch code that are calling into the page
>>>> >>>> allocator from stop_machine() - one via via pagetable_alloc() and another via
>>>> >>>> __get_free_pages(). But both of those calls are passing in GFP_ATOMIC. It was my
>>>> >>>> understanding that the page allocator would ensure it never sleeps when
>>>> >>>> GFP_ATOMIC is passed in, (even for PREEMPT_RT)?
>>>> >>>
>>>> >>> Although GFP_ATOMIC is specify, it only affects of "water mark" of the
>>>> >>> page with __GFP_HIGH. and to get a page, it must grab the lock --
>>>> >>> zone->lock or pcp_lock in the rmqueue().
>>>> >>>
>>>> >>> This zone->lock and pcp_lock is spin_lock and it's a sleepable in
>>>> >>> PREEMPT_RT that's why the memory allocation/free using general API
>>>> >>> except nolock() version couldn't be called since
>>>> >>> if "contention" happens they'll sleep while waiting to get the lock.
>>>> >>>
>>>> >>> The reason why "nolock()" can use, it always uses "trylock" with
>>>> >>> ALLOC_TRYLOCK flags. otherwise GFP_ATOMIC also can be sleepable in
>>>> >>> PREEMPT_RT.
>>>> >>>
>>>> >>>>
>>>> >>>> What is the actual symptom you are seeing?
>>>> >>>
>>>> >>> Since the place where called while smp_cpus_done() and there seems no
>>>> >>> contention, there seems no problem. However as I mention in another
>>>> >>> thread
>>>> >>> (https://lore.kernel.org/all/aT%2FdrjN1BkvyAGoi at e129823.arm.com/),
>>>> >>> This gives a the false impression --
>>>> >>> GFP_ATOMIC are ?safe to use in preemption disabled?
>>>> >>> even though they are not in PREEMPT_RT case, I've changed it.
>>>> >>>
>>>> >>>>
>>>> >>>> If the page allocator is somehow ignoring the GFP_ATOMIC request for PREEMPT_RT,
>>>> >>>> then isn't that a bug in the page allocator? I'm not sure why you would change
>>>> >>>> the callsites? Can't you just change the page allocator based on GFP_ATOMIC?
>>>> >>>
>>>> >>> It doesn't ignore the GFP_ATOMIC feature:
>>>> >>>   - __GFP_HIGH: use water mark till min reserved
>>>> >>>   - __GFP_KSWAPD_RECLAIM: wake up kswapd if reclaim required.
>>>> >>>
>>>> >>> But, it's a restriction -- "page allocation / free" API cannot be called
>>>> >>> in preempt-disabled context at PREEMPT_RT.
>>>> >>>
>>>> >>> That's why I think it's wrong usage not a page allocator bug.
>>>> >>
>>>> >> I've taken a look at this and I agree with your analysis. Thanks for explaining.
>>>> >>
>>>> >> Looking at other stop_machine() callbacks, there are some that call printk() and
>>>> >> I would assume that spinlocks could be taken there which may present the same
>>>> >> kind of issue or PREEMPT_RT? (I'm guessing). I don't see any others that attempt
>>>> >> to allocate memory though.
>>>> >
>>>> > IIRC, there was a problem related for printk while try to grab
>>>> > pl011_console related lock (spin_lock) while holding
>>>> > console_lock(raw_spin_lock) in v6.10.0-rc7 at rpi5:
>>>> >
>>>> >     [  230.381263] CPU: 2 PID: 5574 Comm: syz.4.1695 Not tainted 6.10.0-rc7-01903-g52828ea60dfd #3
>>>> >     [  230.381479] Hardware name: linux,dummy-virt (DT)
>>>> >     [  230.381565] Call trace:
>>>> >     [  230.381607]  dump_backtrace+0x318/0x348
>>>> >     [  230.381727]  show_stack+0x4c/0x80
>>>> >     [  230.381875]  dump_stack_lvl+0x214/0x328
>>>> >     [  230.382159]  dump_stack+0x3c/0x58
>>>> >     [  230.382456]  __lock_acquire+0x4398/0x4720
>>>> >     [  230.382683]  lock_acquire+0x648/0xb70
>>>> >     [  230.382928]  _raw_spin_lock_irqsave+0x138/0x240
>>>> >     [  230.383121]  pl011_console_write+0x240/0x8a0
>>>> >     [  230.383356]  console_flush_all+0x708/0x1368
>>>> >     [  230.383571]  console_unlock+0x180/0x440
>>>> >     [  230.383742]  vprintk_emit+0x1f8/0x9d0
>>>> >     [  230.383832]  vprintk_default+0x64/0x90
>>>> >     [  230.383914]  vprintk+0x2d0/0x400
>>>> >     [  230.383971]  _printk+0xdc/0x128
>>>> >     [  230.384229]  hrtimer_interrupt+0x8f0/0x920
>>>> >     [  230.384414]  arch_timer_handler_virt+0xc0/0x100
>>>> >     [  230.384812]  handle_percpu_devid_irq+0x20c/0x4e0
>>>> >     [  230.385053]  generic_handle_domain_irq+0xc0/0x120
>>>> >     [  230.385367]  gic_handle_irq+0x88/0x360
>>>> >     [  230.385559]  call_on_irq_stack+0x24/0x70
>>>> >     [  230.385801]  do_interrupt_handler+0xf8/0x200
>>>> >     [  230.386092]  el1_interrupt+0x68/0xc0
>>>> >     [  230.386434]  el1h_64_irq_handler+0x18/0x28
>>>> >     [  230.386716]  el1h_64_irq+0x64/0x68
>>>> >     [  230.386853]  __sanitizer_cov_trace_const_cmp2+0x30/0x68
>>>> >     [  230.387026]  alloc_pages_mpol_noprof+0x170/0x698
>>>> >     [  230.387309]  vma_alloc_folio_noprof+0x128/0x2a8
>>>> >     [  230.387610]  vma_alloc_zeroed_movable_folio+0xa0/0xe0
>>>> >     [  230.387822]  folio_prealloc+0x5c/0x280
>>>> >     [  230.388008]  do_wp_page+0xc30/0x3bc0
>>>> >     [  230.388206]  __handle_mm_fault+0xdb8/0x2ba0
>>>> >     [  230.388448]  handle_mm_fault+0x194/0x8a8
>>>> >     [  230.388676]  do_page_fault+0x6bc/0x1030
>>>> >     [  230.388924]  do_mem_abort+0x8c/0x240
>>>> >     [  230.389056]  el0_da+0xf0/0x3f8
>>>> >     [  230.389178]  el0t_64_sync_handler+0xb4/0x130
>>>> >     [  230.389452]  el0t_64_sync+0x190/0x198
>>>> >
>>>> > But this problem is gone when I try with some of patches in rt-tree
>>>> > related for printk which are merged in current tree
>>>> > (https://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git/log/?h=linux-6.10.y-rt-rebase).
>>>> >
>>>> > So I think printk() wouldn't be a problem.
>>>> >
>>>> >>
>>>> >> Anyway, to fix the 2 arm64 callsites, I see 2 possible approaches:
>>>> >>
>>>> >> - Call the nolock variant (as you are doing). But that would just convert a
>>>> >> deadlock to a panic; if the lock is held when stop_machine() runs, without your
>>>> >> change, we now have a deadlock due to waiting on the lock inside stop_machine().
>>>> >> With your change, we notice the lock is already taken and panic. I guess it is
>>>> >> marginally better, but not by much. Certainly I would just _always_ call the
>>>> >> nolock variant regardless of PREEMPT_RT if we take this route; For !PREEMPT_RT,
>>>> >> the lock is guarranteed to be free so nolock will always succeed.
>>>> >>
>>>> >> - Preallocate the memory before entering stop_machine(). I think this would be
>>>> >> much more robust. For kpti_install_ng_mappings() I think you could hoist the
>>>> >> allocation/free out of stop_machine() and pass the pointer in pretty easily. For
>>>> >> linear_map_split_to_ptes() its a bit more complex; Perhaps, we need to walk the
>>>> >> pgtable to figure out how much to preallocate, allocate it, then set it up as a
>>>> >> special allocator, wrapped by an allocation function and modify the callchain to
>>>> >> take a callback function instead of gfp flags.
>>>> >>
>>>> >> What do you think?
>>>> >
>>>> > Definitely, second suggestoin is much better.
>>>> > My question is whether *memory contention* really happen in the point
>>>> > both functions are called.
>>>>
>>>> My guess would be that it's unlikely, but not impossible. The secondary CPUs are
>>>> up, and presumably running their idle thread. I think various power management
>>>> things can be plugged into the idle thread; if so, then I guess it's possible
>>>> that the CPU could be running some hook as part of a power state transition, and
>>>> that could be dynamically allocating memory? That's all just a guess though; I
>>>> don't know the details of that part of the system.
>>>>
>>>> >
>>>> > Above two functions are called as last step of "smp_init()" -- smp_cpus_done().
>>>> > If we can be sure, I think we don't need to go to complex way and
>>>> > I believe the reason why we couldn't find out this problem,
>>>> > even using GFP_ATOMIC in PREEMPT_RT since there was *no contection*
>>>> > in this time of both functions are called.
>>>> > > That's why I first try with the "simple way".
>>>> >
>>>> > What do you think?
>>>>
>>>> As far as linear_map_split_to_ptes() is concerned, it was implemented under the
>>>> impression that doing allocation with GFP_ATOMIC was safe, even in
>>>> stop_machine(). Given that's an incorrect assumption, I think we should fix it
>>>> to pre-allocate outside of stop_machine() regardless of the likelihood of
>>>> actually hitting the race.
>>>>
>>> 
>>> Yeap. It?s better to be certain than uncertain. Thanks for checking.
>>> I'll repsin with the preallocate way.
>>
>> Note this is explained in Documentation/core-api/real-time/differences.rst:
>>
>> Memory allocation
>> -----------------
>>
>> The memory allocation APIs, such as kmalloc() and alloc_pages(), require a
>> gfp_t flag to indicate the allocation context. On non-PREEMPT_RT kernels, it is
>> necessary to use GFP_ATOMIC when allocating memory from interrupt context or
>> from sections where preemption is disabled. This is because the allocator must
>> not sleep in these contexts waiting for memory to become available.
>>
>> However, this approach does not work on PREEMPT_RT kernels. The memory
>> allocator in PREEMPT_RT uses sleeping locks internally, which cannot be
>> acquired when preemption is disabled. Fortunately, this is generally not a
>> problem, because PREEMPT_RT moves most contexts that would traditionally run
>> with preemption or interrupts disabled into threaded context, where sleeping is
>> allowed.
>>
>> What remains problematic is code that explicitly disables preemption or
>> interrupts. In such cases, memory allocation must be performed outside the
>> critical section.
>>
>> This restriction also applies to memory deallocation routines such as kfree()
>> and free_pages(), which may also involve internal locking and must not be
>> called from non-preemptible contexts.
> 
> Oh, thanks for pointing to that, I had never read that before (oops).
> 
> Shall we point to this from the doc-comment? Something like the below.
> 
> BTW, Yeorum, assuming you care about PREEMPT_RT, maybe you can get
> Sparse to find some other bugs of this nature? Or if not, plain old
> Coccinelle would probably find a few.
> 
> ---
> 
> From 4c6b4d4cb08aee9559d02a348b9ecf799142c96f Mon Sep 17 00:00:00 2001
> From: Brendan Jackman <jackmanb at google.com>
> Date: Wed, 17 Dec 2025 13:26:28 +0000
> Subject: [PATCH] mm: clarify GFP_ATOMIC/GFP_NOWAIT doc-comment
> 
> The current description of contexts where it's invalid to make
> GFP_ATOMIC and GFP_NOWAIT calls is rather vague.
> 
> Replace this with a direct description of the actual contexts of concern
> and refer to the RT docs where this is explained more discursively.
> 
> While rejigging this prose, also move the documentation of GFP_NOWAIT to
> the GFP_NOWAIT section.

There doesn't seem to be any move?

> 
> Link: https://lore.kernel.org/all/d912480a-5229-4efe-9336-b31acded30f5 at suse.cz/
> Signed-off-by: Brendan Jackman <jackmanb at google.com>

Acked-by: Vlastimil Babka <vbabka at suse.cz>
Nit below:

> ---
>  include/linux/gfp_types.h | 7 +++++--
>  1 file changed, 5 insertions(+), 2 deletions(-)
> 
> diff --git a/include/linux/gfp_types.h b/include/linux/gfp_types.h
> index 3de43b12209ee..07a378542caf2 100644
> --- a/include/linux/gfp_types.h
> +++ b/include/linux/gfp_types.h
> @@ -309,8 +309,10 @@ enum {
>   *
>   * %GFP_ATOMIC users can not sleep and need the allocation to succeed. A lower
>   * watermark is applied to allow access to "atomic reserves".
> - * The current implementation doesn't support NMI and few other strict
> - * non-preemptive contexts (e.g. raw_spin_lock). The same applies to %GFP_NOWAIT.
> + * The current implementation doesn't support NMI, nor contexts that disable
> + * preemption under PREEMPT_RT. This includes raw_spin_lock() and plain
> + * preempt_disable() - see Documentation/core-api/real-time/differences.rst for
> + * more info.

Can we reference the "Memory allocation" section directly?

>   *
>   * %GFP_KERNEL is typical for kernel-internal allocations. The caller requires
>   * %ZONE_NORMAL or a lower zone for direct access but can direct reclaim.
> @@ -321,6 +323,7 @@ enum {
>   * %GFP_NOWAIT is for kernel allocations that should not stall for direct
>   * reclaim, start physical IO or use any filesystem callback.  It is very
>   * likely to fail to allocate memory, even for very small allocations.
> + * The same restrictions on calling contexts apply as for %GFP_ATOMIC.
>   *
>   * %GFP_NOIO will use direct reclaim to discard clean pages or slab pages
>   * that do not require the starting of any physical IO.
> --
> 2.50.1



From tanze at kylinos.cn  Wed Dec 17 07:11:59 2025
From: tanze at kylinos.cn (tanze at kylinos.cn)
Date: Wed, 17 Dec 2025 23:11:59 +0800
Subject: [PATCH v1] arm64/mpam: Replace the arm64.nompam parameter with arm64.mpam
Message-ID: <20251217151159.1076002-1-tanze@kylinos.cn>

From: tanze <tanze at kylinos.cn>

In practical application scenarios, some manufacturers use outdated
firmware and do not add relevant configurations to the kernel command
line during deployment, which will result in system boot failure.
For manufacturers, disabling the MPAM feature by default and
enabling it via additional boot parameters only when required
is a more effective way to ensure compatibility.

Fixes: 10f885d63a0e ("arm64: Add override for MPAM")
Signed-off-by: tanze <tanze at kylinos.cn>
---
 Documentation/admin-guide/kernel-parameters.txt | 6 +++---
 arch/arm64/kernel/pi/idreg-override.c           | 8 +++++++-
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index a8d0afde7f85..c10d9529147c 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -556,9 +556,6 @@ Kernel parameters
 	arm64.nomops	[ARM64] Unconditionally disable Memory Copy and Memory
 			Set instructions support
 
-	arm64.nompam	[ARM64] Unconditionally disable Memory Partitioning And
-			Monitoring support
-
 	arm64.nomte	[ARM64] Unconditionally disable Memory Tagging Extension
 			support
 
@@ -571,6 +568,9 @@ Kernel parameters
 	arm64.nosve	[ARM64] Unconditionally disable Scalable Vector
 			Extension support
 
+	arm64.mpam	[ARM64] Unconditionally enable Memory Partitioning And
+			Monitoring support
+
 	ataflop=	[HW,M68k]
 
 	atarimouse=	[HW,MOUSE] Atari Mouse
diff --git a/arch/arm64/kernel/pi/idreg-override.c b/arch/arm64/kernel/pi/idreg-override.c
index bc57b290e5e7..f4e3972155c4 100644
--- a/arch/arm64/kernel/pi/idreg-override.c
+++ b/arch/arm64/kernel/pi/idreg-override.c
@@ -248,7 +248,7 @@ static const struct {
 	{ "rodata=off",			"arm64_sw.rodataoff=1" },
 	{ "arm64.nolva",		"id_aa64mmfr2.varange=0" },
 	{ "arm64.no32bit_el0",		"id_aa64pfr0.el0=1" },
-	{ "arm64.nompam",		"id_aa64pfr0.mpam=0 id_aa64pfr1.mpam_frac=0" },
+	{ "arm64.mpam",			"id_aa64pfr0.mpam=1 id_aa64pfr1.mpam_frac=1" },
 };
 
 static int __init parse_hexdigit(const char *p, u64 *v)
@@ -409,6 +409,12 @@ void __init init_feature_override(u64 boot_status, const void *fdt,
 
 	__boot_status = boot_status;
 
+	/*
+	 * Set the boot parameter to disable the MPAM feature,
+	 * thus avoiding system boot failure.
+	 */
+	match_options("id_aa64pfr0.mpam=0 id_aa64pfr1.mpam_frac=0");
+
 	parse_cmdline(fdt, chosen);
 
 	for (i = 0; i < ARRAY_SIZE(regs); i++) {
-- 
2.25.1



From steven.price at arm.com  Wed Dec 17 07:28:16 2025
From: steven.price at arm.com (Steven Price)
Date: Wed, 17 Dec 2025 15:28:16 +0000
Subject: [PATCH v12 00/46] arm64: Support for Arm CCA in KVM
In-Reply-To: <86y0n1ma2q.wl-maz@kernel.org>
References: <20251217101125.91098-1-steven.price@arm.com>
 <86y0n1ma2q.wl-maz@kernel.org>
Message-ID: <505e2e14-7f02-4a6d-b0fa-d322cf0c8b29@arm.com>

On 17/12/2025 14:55, Marc Zyngier wrote:
> On Wed, 17 Dec 2025 10:10:37 +0000,
> Steven Price <steven.price at arm.com> wrote:
>>
>> This series adds support for running protected VMs using KVM under the
>> Arm Confidential Compute Architecture (CCA). I've changed the uAPI
>> following feedback from Marc.
>>
>> The main change is that rather than providing a multiplex CAP and
>> expecting the VMM to drive the different stages of realm construction,
>> there's now just a minimal interface and KVM performs the necessary
>> operations when needed.
> 
> What are the relevant patches? I'd rather not look at the non-2.0
> patches at all, given that they are pretty meaningless for KVM.

Sorry, I really should have included that in the cover letter.

Patch 6 defines the uAPI - so I'd welcome feedback on whether that is
now the right shape.

Patch 11 shows how the "first VCPU run" is handled with a hook in
kvm_arch_vcpu_run_pid_change() (similar to pKVM).

Patch 20 is implementation of the new populate ioctl.

Patch 21 handles the INIT_RIPAS by assuming that any memslot with gmem
is private and should be RIPAS_RAM.

Patch 27 handles the PSCI requests which is the other ioctl. No real
change from the previous posting, but it would be good to know if there
are any issues with the uAPI here.

I think other than those there's either very little change from the
previous series, or it's likely to change with RMM v2.0.

Thanks,
Steve



From maz at kernel.org  Wed Dec 17 07:30:19 2025
From: maz at kernel.org (Marc Zyngier)
Date: Wed, 17 Dec 2025 15:30:19 +0000
Subject: [PATCH v1] arm64/mpam: Replace the arm64.nompam parameter with arm64.mpam
In-Reply-To: <20251217151159.1076002-1-tanze@kylinos.cn>
References: <20251217151159.1076002-1-tanze@kylinos.cn>
Message-ID: <86wm2lm8hg.wl-maz@kernel.org>

On Wed, 17 Dec 2025 15:11:59 +0000,
tanze at kylinos.cn wrote:
> 
> From: tanze <tanze at kylinos.cn>
> 
> In practical application scenarios, some manufacturers use outdated
> firmware and do not add relevant configurations to the kernel command
> line during deployment, which will result in system boot failure.
> For manufacturers, disabling the MPAM feature by default and
> enabling it via additional boot parameters only when required
> is a more effective way to ensure compatibility.

No. I don't see the need to be overly cooperative with people who do
not care about what they ship.

If you want to run on broken systems, pass the option that allow you
to do so. But don't make it more complicated for people who have HW
that actually works.

I would rather remove the option to disable MPAM altogether and leave
these broken systems completely unsupported.

	M.

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


From robh at kernel.org  Wed Dec 17 07:37:28 2025
From: robh at kernel.org (Rob Herring)
Date: Wed, 17 Dec 2025 09:37:28 -0600
Subject: [PATCH RFC 01/16] dt-bindings: hwmon: Convert aspeed,ast2400-pwm-tacho
 to DT schema
In-Reply-To: <20251211-dev-dt-warnings-all-v1-1-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
 <20251211-dev-dt-warnings-all-v1-1-21b18b9ada77@codeconstruct.com.au>
Message-ID: <CAL_JsqJUaKKsJ8BCNbVXe4vLVsQ2Av7VuWqf9DnUKHeLzLb8NQ@mail.gmail.com>

On Thu, Dec 11, 2025 at 2:46?AM Andrew Jeffery
<andrew at codeconstruct.com.au> wrote:
>
> From: "Rob Herring (Arm)" <robh at kernel.org>
>
> Convert the ASpeed fan controller binding to DT schema format.
>
> The '#cooling-cells' value used is 1 rather than 2. '#size-cells' is 0
> rather 1.

Okay, I can't figure out why I thought '#cooling-cells' needed to be 1
here. I don't see that anywhere in the tree. The driver for sure only
supports 2, so anything that's not is an error in any case.

> Some users define more that 8 fan nodes where 2 fans share a PWM. The
> driver seems to let the 2nd fan just overwrite the 1st one. That also
> creates some addressing errors in the DT (duplicate addresses and wrong
> unit-addresses).
>
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>
> ---
>  .../bindings/hwmon/aspeed,ast2400-pwm-tacho.yaml   | 106 +++++++++++++++++++++
>  .../devicetree/bindings/hwmon/aspeed-pwm-tacho.txt |  73 --------------
>  2 files changed, 106 insertions(+), 73 deletions(-)


From kevin.brodsky at arm.com  Wed Dec 17 07:37:32 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Wed, 17 Dec 2025 16:37:32 +0100
Subject: [PATCH v6 14/14] mm: Add basic tests for lazy_mmu
In-Reply-To: <ca0da7fd-245c-4d52-8f4d-f8fce4717494@arm.com>
References: <20251215150323.2218608-1-kevin.brodsky@arm.com>
 <20251215150323.2218608-15-kevin.brodsky@arm.com>
 <20251216201403.4647a4f9861d3122ee9e90d7@linux-foundation.org>
 <f9550d22-8810-4145-aaa8-48961f6ea35e@arm.com>
 <ca0da7fd-245c-4d52-8f4d-f8fce4717494@arm.com>
Message-ID: <6afcb722-80cc-4bb2-a745-d9ad7893f0ae@arm.com>

On 17/12/2025 11:01, Ryan Roberts wrote:
> On 17/12/2025 09:26, Kevin Brodsky wrote:
>> On 17/12/2025 05:14, Andrew Morton wrote:
>>> On Mon, 15 Dec 2025 15:03:23 +0000 Kevin Brodsky <kevin.brodsky at arm.com> wrote:
>>>
>>>> Add basic KUnit tests for the generic aspects of the lazy MMU mode:
>>>> ensure that it appears active when it should, depending on how
>>>> enable/disable and pause/resume pairs are nested.
>>> I needed this for powerpc allmodconfig;
>>>
>>> --- a/arch/powerpc/mm/book3s64/hash_tlb.c~mm-add-basic-tests-for-lazy_mmu-fix
>>> +++ a/arch/powerpc/mm/book3s64/hash_tlb.c
>>> @@ -30,6 +30,7 @@
>>>  #include <trace/events/thp.h>
>>>  
>>>  DEFINE_PER_CPU(struct ppc64_tlb_batch, ppc64_tlb_batch);
>>> +EXPORT_SYMBOL_GPL(ppc64_tlb_batch);
>>>  
>>>  /*
>>>   * A linux PTE was changed and the corresponding hash table entry
>>> @@ -154,6 +155,7 @@ void __flush_tlb_pending(struct ppc64_tl
>>>  		flush_hash_range(i, local);
>>>  	batch->index = 0;
>>>  }
>>> +EXPORT_SYMBOL_GPL(__flush_tlb_pending);
>>>  
>>>  void hash__tlb_flush(struct mmu_gather *tlb)
>>>  {
>>> _
>> Oh indeed I hadn't considered that arch_{enter,leave}_lazy_mmu_mode()
>> refer to those symbols on powerpc... Maybe a bit overkill to export
>> those just for a test module, but I'm not sure there's a good
>> alternative. Forcing LAZY_MMU_MODE_KUNIT_TEST=y is ugly as it would also
>> force KUNIT=y. Alternatively we could depend on !PPC, not pretty either.
> Does EXPORT_SYMBOL_IF_KUNIT() help?

It most certainly would, I didn't know about that one, thanks!

- Kevin


From arnaud.pouliquen at foss.st.com  Wed Dec 17 07:39:11 2025
From: arnaud.pouliquen at foss.st.com (Arnaud Pouliquen)
Date: Wed, 17 Dec 2025 16:39:11 +0100
Subject: [PATCH v20 0/6] Introduction of a remoteproc tee to load signed firmware
Message-ID: <20251217153917.3998544-1-arnaud.pouliquen@foss.st.com>

Main updates from version V19[3]:
--------------------------------
The devicetree is now structured as follows:

	firmware {
		optee {
			compatible = "linaro,optee-tz";
			method = "smc";
			#address-cells = <1>;
			#size-cells = <0>;
			rproc-service at 0 {
				compatible = "rproc-service-80a4c275-0a47-4905-8285-1486a9771a08";
				reg = <0>;
				#address-cells = <1>;
				#size-cells = <0>;
				status = "okay";
				m4: m4 at 0 {
					compatible = "st,stm32mp15-m4-tee";
					reg = <0>;
					mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
					mbox-names = "vq0", "vq1", "shutdown";
					memory-region = <&vdev0vring0>,	<&m_ipc_shm>, <&mcuram2>,
							<&vdev0vring1>, <&vdev0buffer>, <&retram>;
					interrupt-parent = <&exti>;
					interrupts = <68 1>;
					status = "okay";
				};
			};
		};
	};

As a consequence, this version:

- Introduces a new stm32_rproc_tee.c remoteproc driver.

  Instead of further complicating the existing stm32_rproc.c driver, a
  dedicated TEE-based driver is added. Both drivers are intended to also
  support the STM32MP2x Cortex-M33 remote processor in a next step.

- Reworks the bindings:
  - Drop the st,stm32-rproc.yaml updates that were introduced in previous
    revisions.
  - Add remoteproc-tee.yaml for the
    "rproc-service-80a4c275-0a47-4905-8285-1486a9771a08" compatible.
  - Add st,stm32-rproc-tee.yaml for the "st,stm32mp15-m4-tee" compatible.

- Reworks the probing sequence:

  The m4 at 0 device is now probed by the remoteproc-tee driver, which itself
  is instantiated by the TEE (OP-TEE) bus.


Main updates from version V18[2]:
--------------------------------
- rework documentation for the release_fw ops 
- rework function documentation in remoteproc_tee.c
- replace spinlock by mutex and generalize usage in remoteproc_tee.c


Main updates from version V17[1]:
--------------------------------
- Fix:  warning: EXPORT_SYMBOL() is used, but #include <linux/export.h>
  is missing


More details are available in each patch commit message.

[1] https://lore.kernel.org/linux-remoteproc/20250613091650.2337411-1-arnaud.pouliquen at foss.st.com/
[2] https://lore.kernel.org/linux-remoteproc/20250616075530.4106090-1-arnaud.pouliquen at foss.st.com/
[3] https://lore.kernel.org/linux-devicetree/20250625094028.758016-1-arnaud.pouliquen at foss.st.com/


Tested-on:
---------
commit 7d0a66e4bb90 ("Linux 6.18")

Description of the feature:
--------------------------
This series proposes the implementation of a remoteproc tee driver to
communicate with a TEE trusted application responsible for authenticating
and loading the remoteproc firmware image in an Arm secure context.

1) Principle:

The remoteproc tee driver provides services to communicate with the OP-TEE
trusted application running on the Trusted Execution Context (TEE).
The trusted application in TEE manages the remote processor lifecycle:

- authenticating and loading firmware images,
- isolating and securing the remote processor memories,
- supporting multi-firmware (e.g., TF-M + Zephyr on a Cortex-M33),
- managing the start and stop of the firmware by the TEE.

2) Format of the signed image:

Refer to:
https://github.com/OP-TEE/optee_os/blob/master/ta/remoteproc/src/remoteproc_core.c#L18-L57

3) OP-TEE trusted application API:

Refer to:
https://github.com/OP-TEE/optee_os/blob/master/ta/remoteproc/include/ta_remoteproc.h

4) OP-TEE signature script

Refer to:
https://github.com/OP-TEE/optee_os/blob/master/scripts/sign_rproc_fw.py

Example of usage:
sign_rproc_fw.py --in <fw1.elf> --in <fw2.elf> --out <signed_fw.sign> --key ${OP-TEE_PATH}/keys/default.pem


5) Impact on User space Application

No sysfs impact. The user only needs to provide the signed firmware image
instead of the ELF image.


For more information about the implementation, a presentation is available here
(note that the format of the signed image has evolved between the presentation
and the integration in OP-TEE).

https://resources.linaro.org/en/resource/6c5bGvZwUAjX56fvxthxds

Arnaud Pouliquen (6):
  dt-bindings: firmware: Add TEE remoteproc service binding
  dt-bindings: remoteproc: Add STM32 TEE-controlled rproc binding
  remoteproc: core: Introduce rproc_pa_to_va helper
  remoteproc: Introduce optional release_fw operation
  remoteproc: Add TEE support
  remoteproc: stm32: Add TEE-controlled STM32 driver

 .../arm/firmware/linaro,optee-tz.yaml         |   6 +
 .../bindings/remoteproc/remoteproc-tee.yaml   |  47 ++
 .../remoteproc/st,stm32-rproc-tee.yaml        | 100 +++
 drivers/remoteproc/Kconfig                    |  10 +
 drivers/remoteproc/Makefile                   |   3 +-
 drivers/remoteproc/remoteproc_core.c          |  52 ++
 drivers/remoteproc/remoteproc_internal.h      |   6 +
 drivers/remoteproc/remoteproc_tee.c           | 771 ++++++++++++++++++
 drivers/remoteproc/stm32_rproc_tee.c          | 526 ++++++++++++
 include/linux/remoteproc.h                    |   6 +
 include/linux/remoteproc_tee.h                |  89 ++
 11 files changed, 1615 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/remoteproc/remoteproc-tee.yaml
 create mode 100644 Documentation/devicetree/bindings/remoteproc/st,stm32-rproc-tee.yaml
 create mode 100644 drivers/remoteproc/remoteproc_tee.c
 create mode 100644 drivers/remoteproc/stm32_rproc_tee.c
 create mode 100644 include/linux/remoteproc_tee.h


base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
-- 
2.43.0



From arnaud.pouliquen at foss.st.com  Wed Dec 17 07:39:12 2025
From: arnaud.pouliquen at foss.st.com (Arnaud Pouliquen)
Date: Wed, 17 Dec 2025 16:39:12 +0100
Subject: [PATCH v20 1/6] dt-bindings: firmware: Add TEE remoteproc service binding
In-Reply-To: <20251217153917.3998544-1-arnaud.pouliquen@foss.st.com>
References: <20251217153917.3998544-1-arnaud.pouliquen@foss.st.com>
Message-ID: <20251217153917.3998544-2-arnaud.pouliquen@foss.st.com>

Add a device tree binding for the TEE-based remote processor control
service implemented as an OP-TEE Trusted Application identified by
UUID 80a4c275-0a47-4905-8285-1486a9771a08.

The TEE service node is a child of the "linaro,optee-tz" firmware node and
acts as a container for remoteproc devices that are controlled via TEE.

In addition, the "linaro,optee-tz" binding is updated to specify the
'#address-cells' and '#size-cells' values used for child TEE service
nodes.

Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen at foss.st.com>
---
 .../arm/firmware/linaro,optee-tz.yaml         |  6 +++
 .../bindings/remoteproc/remoteproc-tee.yaml   | 47 +++++++++++++++++++
 2 files changed, 53 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/remoteproc/remoteproc-tee.yaml

diff --git a/Documentation/devicetree/bindings/arm/firmware/linaro,optee-tz.yaml b/Documentation/devicetree/bindings/arm/firmware/linaro,optee-tz.yaml
index 5d033570b57b..ab69eecba9ad 100644
--- a/Documentation/devicetree/bindings/arm/firmware/linaro,optee-tz.yaml
+++ b/Documentation/devicetree/bindings/arm/firmware/linaro,optee-tz.yaml
@@ -41,6 +41,12 @@ properties:
       HVC #0, register assignments
       register assignments are specified in drivers/tee/optee/optee_smc.h
 
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
 required:
   - compatible
   - method
diff --git a/Documentation/devicetree/bindings/remoteproc/remoteproc-tee.yaml b/Documentation/devicetree/bindings/remoteproc/remoteproc-tee.yaml
new file mode 100644
index 000000000000..083ecf1f38cf
--- /dev/null
+++ b/Documentation/devicetree/bindings/remoteproc/remoteproc-tee.yaml
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/remoteproc/remoteproc-tee.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: TEE Remote Processor Control Service (UUID 80a4c275-0a47-4905-8285-1486a9771a08)
+
+maintainers:
+  - Arnaud Pouliquen <arnaud.pouliquen at foss.st.com>
+
+description: |
+  Node describing a TEE-based remote processor control service implemented as
+  a Trusted Application identified by UUID 80a4c275-0a47-4905-8285-1486a9771a08.
+
+  It is a child of the OP-TEE firmware node ("linaro,optee-tz") and acts as a
+  container for child remoteproc devices (for example, the STM32MP15 M4 core
+  described by "st,stm32mp1-tee").
+
+properties:
+  compatible:
+    const: rproc-service-80a4c275-0a47-4905-8285-1486a9771a08
+
+  reg:
+    description: |
+      Logical identifier of the TEE remoteproc service instance.
+    maxItems: 1
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+patternProperties:
+  "^[a-zA-Z0-9,._-]+@[0-9a-fA-F]+$":
+    type: object
+
+
+required:
+  - compatible
+  - reg
+  - "#address-cells"
+  - "#size-cells"
+
+additionalProperties: false
+...
-- 
2.43.0



From arnaud.pouliquen at foss.st.com  Wed Dec 17 07:39:13 2025
From: arnaud.pouliquen at foss.st.com (Arnaud Pouliquen)
Date: Wed, 17 Dec 2025 16:39:13 +0100
Subject: [PATCH v20 2/6] dt-bindings: remoteproc: Add STM32 TEE-controlled rproc binding
In-Reply-To: <20251217153917.3998544-1-arnaud.pouliquen@foss.st.com>
References: <20251217153917.3998544-1-arnaud.pouliquen@foss.st.com>
Message-ID: <20251217153917.3998544-3-arnaud.pouliquen@foss.st.com>

Add a device tree binding for the STM32 remote processor controlled
via a TEE Trusted Application. Provide an example of the STM32MP15
Cortex-M4 core exposed as a child of the TEE remoteproc service
(rproc-service-80a4c275-0a47-4905-8285-1486a9771a08) and managed by
the remoteproc through a TEE client driver.

Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen at foss.st.com>
---
 .../remoteproc/st,stm32-rproc-tee.yaml        | 100 ++++++++++++++++++
 1 file changed, 100 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/remoteproc/st,stm32-rproc-tee.yaml

diff --git a/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc-tee.yaml b/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc-tee.yaml
new file mode 100644
index 000000000000..e9cf8e781543
--- /dev/null
+++ b/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc-tee.yaml
@@ -0,0 +1,100 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/remoteproc/st,stm32-rproc-tee.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics STM32 remote processor controlled via TEE
+
+maintainers:
+  - Arnaud Pouliquen <arnaud.pouliquen at foss.st.com>
+
+description: |
+  STM32MP remote processor controlled by a Trusted Application
+  running in OP-TEE. This node is a child of the TEE remoteproc service
+  (UUID 80a4c275-0a47-4905-8285-1486a9771a08) and exposes a remoteproc
+  instance managed by the Linux remoteproc core via the TEE rproc service.
+
+  Firmware loading, authentication and remote processor start/stop are managed
+  by the TEE application. The STM32-specific driver handles platform resources
+  such as the mailboxes and reserved-memory.
+
+properties:
+  compatible:
+    const: st,stm32mp15-m4-tee
+
+  reg:
+    description: |
+      Remote processor identifier used by the TEE service. The <0> value
+      in the example denotes a single instance with ID 0.
+    maxItems: 1
+
+  mboxes:
+    description: |
+      Mailbox channels used for rpmsg/virtio functionality and processor
+      shutdown.
+    maxItems: 3
+
+  mbox-names:
+    items:
+      - const: vq0
+      - const: vq1
+      - const: shutdown
+
+  memory-region:
+    description: |
+      List of phandles to reserved-memory nodes describing the memory layout
+      for the interprocessors communication.
+
+  interrupts:
+    description: |
+      Optional watchdog / status interrupt line used to detect crashes
+      and optionally wake up the system.
+    maxItems: 1
+
+  st,auto-boot:
+    type: boolean
+    description: |
+      If present, the remote processor will be automatically started by
+      the remoteproc core at boot.
+
+  wakeup-source:
+    type: boolean
+    description: |
+      Indicates that the watchdog interrupt can be used as a wakeup source.
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    rproc_service: rproc-service at 0 {
+      compatible = "rproc-service-80a4c275-0a47-4905-8285-1486a9771a08";
+      reg = <0 0>;
+      #address-cells = <1>;
+      #size-cells = <0>;
+      status = "okay";
+
+      m4: m4 at 0 {
+        compatible = "st,stm32mp15-m4-tee";
+        reg = <0>;
+
+        mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
+        mbox-names = "vq0", "vq1", "shutdown";
+
+        memory-region = <&vdev0vring0>, <&m_ipc_shm>, <&mcuram2>,
+                        <&vdev0vring1>, <&vdev0buffer>, <&retram>;
+
+        interrupt-parent = <&exti>;
+        interrupts = <68 1>;
+
+        st,auto-boot;
+        wakeup-source;
+
+        status = "okay";
+      };
+    };
+...
-- 
2.43.0



From arnaud.pouliquen at foss.st.com  Wed Dec 17 07:39:15 2025
From: arnaud.pouliquen at foss.st.com (Arnaud Pouliquen)
Date: Wed, 17 Dec 2025 16:39:15 +0100
Subject: [PATCH v20 4/6] remoteproc: Introduce optional release_fw operation
In-Reply-To: <20251217153917.3998544-1-arnaud.pouliquen@foss.st.com>
References: <20251217153917.3998544-1-arnaud.pouliquen@foss.st.com>
Message-ID: <20251217153917.3998544-5-arnaud.pouliquen@foss.st.com>

The release_fw operation allows releasing remote processor resources
configured during rproc_parse_fw() and rproc_load_segments().
For example, it can release carveouts mapped during these operations.

This operation is invoked in the following cases:
 - When an error occurs during remote processor boot.
 - When an error occurs during remote processor recovery start.
 - After stopping the remote processor.

This operation is required for the remoteproc_tee implementation following
a stop or upon encountering an error. Since the remoteproc image is loaded
during resource table parsing, multiple failure scenarios may occur prior
to remote processor startup, including issues with resource handling and
carveout allocation.

Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen at foss.st.com>

---

Version 19 updates:
- Rewrite rproc_ops::release_fw documentation
- Improve commit message

Version 17 updates:
- Removed the rproc:load_fw() ops introduced in previous version.
- Removed duplicate calls to rproc_release_fw in rproc_fw_boot and rproc_boot.
---
 drivers/remoteproc/remoteproc_core.c     | 6 ++++++
 drivers/remoteproc/remoteproc_internal.h | 6 ++++++
 include/linux/remoteproc.h               | 5 +++++
 3 files changed, 17 insertions(+)

diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index f7c96dbed189..1a3d646c99ab 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -1857,6 +1857,8 @@ static int rproc_boot_recovery(struct rproc *rproc)
 
 	/* boot the remote processor up again */
 	ret = rproc_start(rproc, firmware_p);
+	if (ret)
+		rproc_release_fw(rproc);
 
 	release_firmware(firmware_p);
 
@@ -1998,6 +2000,8 @@ int rproc_boot(struct rproc *rproc)
 		}
 
 		ret = rproc_fw_boot(rproc, firmware_p);
+		if (ret)
+			rproc_release_fw(rproc);
 
 		release_firmware(firmware_p);
 	}
@@ -2067,6 +2071,8 @@ int rproc_shutdown(struct rproc *rproc)
 
 	rproc_disable_iommu(rproc);
 
+	rproc_release_fw(rproc);
+
 	/* Free the copy of the resource table */
 	kfree(rproc->cached_table);
 	rproc->cached_table = NULL;
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 0cd09e67ac14..c7fb908f8652 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -221,4 +221,10 @@ bool rproc_u64_fit_in_size_t(u64 val)
 	return (val <= (size_t) -1);
 }
 
+static inline void rproc_release_fw(struct rproc *rproc)
+{
+	if (rproc->ops->release_fw)
+		rproc->ops->release_fw(rproc);
+}
+
 #endif /* REMOTEPROC_INTERNAL_H */
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 8fd0d7f63c8e..a2bb51a113b1 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -381,6 +381,10 @@ enum rsc_handling_status {
  * @panic:	optional callback to react to system panic, core will delay
  *		panic at least the returned number of milliseconds
  * @coredump:	  collect firmware dump after the subsystem is shutdown
+ * @release_fw:	Optional function to release resources allocated during
+ *		parse_fw() or load() operations. This function is called after
+ *		stopping the remote processor or in case of an error during the
+ *		boot or recovery sequence.
  */
 struct rproc_ops {
 	int (*prepare)(struct rproc *rproc);
@@ -403,6 +407,7 @@ struct rproc_ops {
 	u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
 	unsigned long (*panic)(struct rproc *rproc);
 	void (*coredump)(struct rproc *rproc);
+	void (*release_fw)(struct rproc *rproc);
 };
 
 /**
-- 
2.43.0



From arnaud.pouliquen at foss.st.com  Wed Dec 17 07:39:14 2025
From: arnaud.pouliquen at foss.st.com (Arnaud Pouliquen)
Date: Wed, 17 Dec 2025 16:39:14 +0100
Subject: [PATCH v20 3/6] remoteproc: core: Introduce rproc_pa_to_va helper
In-Reply-To: <20251217153917.3998544-1-arnaud.pouliquen@foss.st.com>
References: <20251217153917.3998544-1-arnaud.pouliquen@foss.st.com>
Message-ID: <20251217153917.3998544-4-arnaud.pouliquen@foss.st.com>

When a resource table is loaded by an external entity such as U-boot or
OP-TEE, we do not necessarily get the device address(da) but the physical
address(pa).
This helper performs similar translation than the rproc_da_to_va()
but based on a physical address.

Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen at foss.st.com>
---
 drivers/remoteproc/remoteproc_core.c | 46 ++++++++++++++++++++++++++++
 include/linux/remoteproc.h           |  1 +
 2 files changed, 47 insertions(+)

diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 825672100528..f7c96dbed189 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -230,6 +230,52 @@ void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)
 }
 EXPORT_SYMBOL(rproc_da_to_va);
 
+/**
+ * rproc_pa_to_va() - lookup the kernel virtual address for a physical address of a remoteproc
+ * memory
+ *
+ * @rproc: handle of a remote processor
+ * @pa: remoteproc physical address
+ * @len: length of the memory region @pa is pointing to
+ * @is_iomem: optional pointer filled in to indicate if @da is iomapped memory
+ *
+ * This function is a helper function similar to rproc_da_to_va() but it deals with physical
+ * addresses instead of device addresses.
+ *
+ * Return: a valid kernel address on success or NULL on failure
+ */
+void *rproc_pa_to_va(struct rproc *rproc, phys_addr_t pa, size_t len, bool *is_iomem)
+{
+	struct rproc_mem_entry *carveout;
+	void *ptr = NULL;
+
+	list_for_each_entry(carveout, &rproc->carveouts, node) {
+		int offset = pa - carveout->dma;
+
+		/*  Verify that carveout is allocated */
+		if (!carveout->va)
+			continue;
+
+		/* try next carveout if da is too small */
+		if (offset < 0)
+			continue;
+
+		/* try next carveout if da is too large */
+		if (offset + len > carveout->len)
+			continue;
+
+		ptr = carveout->va + offset;
+
+		if (is_iomem)
+			*is_iomem = carveout->is_iomem;
+
+		break;
+	}
+
+	return ptr;
+}
+EXPORT_SYMBOL(rproc_pa_to_va);
+
 /**
  * rproc_find_carveout_by_name() - lookup the carveout region by a name
  * @rproc: handle of a remote processor
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index b4795698d8c2..8fd0d7f63c8e 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -690,6 +690,7 @@ int rproc_detach(struct rproc *rproc);
 int rproc_set_firmware(struct rproc *rproc, const char *fw_name);
 void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type);
 void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem);
+void *rproc_pa_to_va(struct rproc *rproc, phys_addr_t pa, size_t len, bool *is_iomem);
 
 /* from remoteproc_coredump.c */
 void rproc_coredump_cleanup(struct rproc *rproc);
-- 
2.43.0



From arnaud.pouliquen at foss.st.com  Wed Dec 17 07:39:16 2025
From: arnaud.pouliquen at foss.st.com (Arnaud Pouliquen)
Date: Wed, 17 Dec 2025 16:39:16 +0100
Subject: [PATCH v20 5/6] remoteproc: Add TEE support
In-Reply-To: <20251217153917.3998544-1-arnaud.pouliquen@foss.st.com>
References: <20251217153917.3998544-1-arnaud.pouliquen@foss.st.com>
Message-ID: <20251217153917.3998544-6-arnaud.pouliquen@foss.st.com>

Add a remoteproc TEE (Trusted Execution Environment) driver that will be
probed by the TEE bus. If the associated Trusted application is supported
on the secure part, this driver offers a client interface to load firmware
by the secure part.
This firmware could be authenticated by the secure trusted application.

A specificity of the implementation is that the firmware has to be
authenticated and optionally decrypted to access the resource table.

Consequently, the boot sequence is:

1) rproc_parse_fw --> rproc_tee_parse_fw
   remoteproc TEE:
   - Requests the TEE application to authenticate and load the firmware
     in the remote processor memories.
   - Requests the TEE application for the address of the resource table.
   - Creates a copy of the resource table stored in rproc->cached_table.

2) rproc_load_segments --> rproc_tee_load_fw
   remoteproc TEE:
   - Requests the TEE application to load the firmware. Nothing is done
     at the TEE application as the firmware is already loaded.
   - In case of recovery, the TEE application has to reload the firmware.

3) rproc_tee_get_loaded_rsc_table
   remoteproc TEE requests the TEE application for the address of the
   resource table.

4) rproc_start --> rproc_tee_start
   - Requests the TEE application to start the remote processor.

The shutdown sequence is:

5) rproc_stop --> rproc_tee_stop
   - Requests the TEE application to stop the remote processor.

6) rproc_tee_release_fw
   This function is used to request the TEE application to perform actions
   to return to the initial state on stop or on error during the boot
   sequence.

Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen at foss.st.com>
---
Version 20 updates:
- rework probe. the remoteproc-tee now probe the remoteproc devices
  defined in device tree as child.
  - creation of rproc-service-80a4c275-0a47-4905-8285-1486a9771a08 compatible
  - use of of_find_compatible_node() to find node in DT
  - use of of_platform_populate() to probe remoteproc devices
- remove device_link_add() as now managed by of_platform_populate)
- add "auto_boot" parameter in rproc_tee_register()
- rename TA_RPROC_FW_CMD_* TEE CMD in  TA_RPROC_CMD_* command
- use of DEFINE_MUTEX

Version 19 updates:
- rework/fix function headers
- use memremap instead of ioremap for the resource table.
- realign comments to 80 chars limit, with few exceptions for readability
- replace spinlock by mutex and and protect APIs from concurrent access
- add support of 64-bit address in rproc_tee_get_loaded_rsc_table()
- update copyright year

Version 18 updates:
Fix warning:
warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
---
 drivers/remoteproc/Kconfig          |  10 +
 drivers/remoteproc/Makefile         |   1 +
 drivers/remoteproc/remoteproc_tee.c | 771 ++++++++++++++++++++++++++++
 include/linux/remoteproc_tee.h      |  89 ++++
 4 files changed, 871 insertions(+)
 create mode 100644 drivers/remoteproc/remoteproc_tee.c
 create mode 100644 include/linux/remoteproc_tee.h

diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 48a0d3a69ed0..75265f3f5008 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -23,6 +23,16 @@ config REMOTEPROC_CDEV
 
 	  It's safe to say N if you don't want to use this interface.
 
+config REMOTEPROC_TEE
+	bool "Remoteproc support by a TEE application"
+	depends on OPTEE
+	help
+	  Support a remote processor that is managed by an application running in a Trusted
+	  Execution Environment (TEE). This application is responsible for loading the remote
+	  processor firmware image and managing its lifecycle.
+
+	  It's safe to say N if the remote processor is not managed by a TEE.
+
 config IMX_REMOTEPROC
 	tristate "i.MX remoteproc support"
 	depends on ARCH_MXC
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 1c7598b8475d..a1a5201982d4 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -11,6 +11,7 @@ remoteproc-y				+= remoteproc_sysfs.o
 remoteproc-y				+= remoteproc_virtio.o
 remoteproc-y				+= remoteproc_elf_loader.o
 obj-$(CONFIG_REMOTEPROC_CDEV)		+= remoteproc_cdev.o
+obj-$(CONFIG_REMOTEPROC_TEE)		+= remoteproc_tee.o
 obj-$(CONFIG_IMX_REMOTEPROC)		+= imx_rproc.o
 obj-$(CONFIG_IMX_DSP_REMOTEPROC)	+= imx_dsp_rproc.o
 obj-$(CONFIG_INGENIC_VPU_RPROC)		+= ingenic_rproc.o
diff --git a/drivers/remoteproc/remoteproc_tee.c b/drivers/remoteproc/remoteproc_tee.c
new file mode 100644
index 000000000000..081420c35c88
--- /dev/null
+++ b/drivers/remoteproc/remoteproc_tee.c
@@ -0,0 +1,771 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) STMicroelectronics 2025
+ * Author: Arnaud Pouliquen <arnaud.pouliquen at foss.st.com>
+ */
+
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/mutex.h>
+#include <linux/remoteproc.h>
+#include <linux/remoteproc_tee.h>
+#include <linux/slab.h>
+#include <linux/tee_drv.h>
+
+#include "remoteproc_internal.h"
+
+#define MAX_TEE_PARAM_ARRAY_MEMBER	4
+
+/*
+ * Authentication and load of the firmware image in the remote processor
+ * memories by the TEE. After this step the firmware is installed in destination
+ * memories, which can then be locked to prevent access by Linux.
+ *
+ * [in]  params[0].value.a: remote processor identifier
+ * [in]  params[1].memref:  buffer containing a temporary copy of the signed
+ *			    image to load.
+ */
+#define TA_RPROC_CMD_LOAD_FW		1
+
+/*
+ * Start the remote processor by the TEE
+ *
+ * [in]  params[0].value.a: remote processor identifier
+ */
+#define TA_RPROC_CMD_START		2
+
+/*
+ * Stop the remote processor by the TEE
+ *
+ * [in]  params[0].value.a: remote processor identifier
+ */
+#define TA_RPROC_CMD_STOP		3
+
+/*
+ * Return the address of the resource table, or 0 if not found.
+ *
+ * [in]  params[0].value.a: remote processor identifier
+ * [out] params[1].value.a: 32bit LSB resource table memory address
+ * [out] params[1].value.b: 32bit MSB resource table memory address
+ * [out] params[2].value.a: 32bit LSB resource table memory size
+ * [out] params[2].value.b: 32bit MSB resource table memory size
+ */
+#define TA_RPROC_CMD_GET_RSC_TABLE	4
+
+/*
+ * Release remote processor firmware images and associated resources.
+ * This command should be used in case an error occurs between the loading of
+ * the firmware images (TA_RPROC_CMD_LOAD_FW) and the starting of the remote
+ * processor (TA_RPROC_CMD_START) or after stopping the remote processor
+ * to release associated resources (TA_RPROC_CMD_STOP).
+ *
+ * [in]  params[0].value.a: remote processor identifier
+ */
+#define TA_RPROC_CMD_RELEASE_FW		6
+
+struct rproc_tee_context {
+	struct list_head	rproc_list;
+	struct tee_context	*tee_ctx;
+	struct device		*dev;
+};
+
+/**
+ * struct rproc_tee - TEE remoteproc structure
+ * @node:       Reference in list
+ * @rproc:      Remoteproc reference
+ * @rproc_id:   remote processor identifier
+ * @session_id: TEE session identifier
+ */
+struct rproc_tee {
+	struct list_head node;
+	struct rproc *rproc;
+	u32 rproc_id;
+	u32 session_id;
+};
+
+static struct rproc_tee_context rproc_tee_ctx;
+static DEFINE_MUTEX(ctx_lock); /* Protects concurrent manipulations of the rproc_tee_ctx*/
+
+static struct rproc_tee *rproc_to_trproc(struct rproc *rproc)
+{
+	struct rproc_tee *trproc;
+
+	list_for_each_entry(trproc, &rproc_tee_ctx.rproc_list, node)
+		if (trproc->rproc == rproc)
+			return trproc;
+	return NULL;
+}
+
+static void rproc_tee_prepare_args(struct rproc_tee *trproc, int cmd,
+				   struct tee_ioctl_invoke_arg *arg,
+				   struct tee_param *param,
+				   unsigned int num_params)
+{
+	memset(arg, 0, sizeof(*arg));
+	memset(param, 0, MAX_TEE_PARAM_ARRAY_MEMBER * sizeof(*param));
+
+	arg->func = cmd;
+	arg->session = trproc->session_id;
+	arg->num_params = num_params + 1;
+
+	param[0] = (struct tee_param) {
+		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+		.u.value.a = trproc->rproc_id,
+	};
+}
+
+/**
+ * rproc_tee_release_fw() - Release the firmware for a TEE-based remote processor
+ * @rproc: Pointer to the struct rproc representing the remote processor
+ *
+ * This function invokes the TA_RPROC_CMD_RELEASE_FW TEE client function to
+ * release the firmware. It should only be called when the remoteproc state is
+ * RPROC_OFFLINE or RPROC_DETACHED. The function requests the TEE remoteproc
+ * application to release the firmware loaded by rproc_tee_load_fw().
+ * The request is ignored if the rproc state is RPROC_DETACHED as the remote
+ * processor is still running.
+ */
+void rproc_tee_release_fw(struct rproc *rproc)
+{
+	struct tee_param param[MAX_TEE_PARAM_ARRAY_MEMBER];
+	struct rproc_tee *trproc;
+	struct tee_ioctl_invoke_arg arg;
+	int ret;
+
+	ret = mutex_lock_interruptible(&ctx_lock);
+	if (ret)
+		return;
+
+	if (!rproc_tee_ctx.dev)
+		goto out;
+
+	trproc = rproc_to_trproc(rproc);
+	if (!trproc)
+		goto out;
+
+	/*
+	 * If the remote processor state is RPROC_DETACHED, just ignore the
+	 * request, as the remote processor is still running.
+	 */
+	if (rproc->state == RPROC_DETACHED)
+		goto out;
+
+	if (rproc->state != RPROC_OFFLINE) {
+		dev_err(rproc_tee_ctx.dev, "unexpected rproc state: %d\n", rproc->state);
+		goto out;
+	}
+
+	rproc_tee_prepare_args(trproc, TA_RPROC_CMD_RELEASE_FW, &arg, param, 0);
+
+	ret = tee_client_invoke_func(rproc_tee_ctx.tee_ctx, &arg, param);
+	if (ret < 0 || arg.ret != 0) {
+		dev_err(rproc_tee_ctx.dev,
+			"TA_RPROC_CMD_RELEASE_FW invoke failed TEE err: %#x, ret:%d\n",
+			arg.ret, ret);
+	}
+
+out:
+	mutex_unlock(&ctx_lock);
+}
+EXPORT_SYMBOL_GPL(rproc_tee_release_fw);
+
+/**
+ * rproc_tee_load_fw() - Load firmware from TEE application
+ * @rproc: Pointer to the struct rproc representing the remote processor
+ * @fw: Pointer to the firmware structure containing the firmware data and size
+ *
+ * This function invokes the TA_RPROC_CMD_LOAD_FW TEE client function to load
+ * the firmware. It registers the fw->data as a shared memory region with the
+ * TEE, and request the TEE to load the firmware. This function can be called
+ * twice during the remote processor boot, a first by rproc_tee_parse_fw() to
+ * parse the resource table , and a second time by rproc_tee_load_fw().
+ * The TEE application should ignores the command if the firmware
+ * is already loaded by rproc_tee_parse_fw().
+ *
+ * Return: 0 on success, or an error code on failure
+ */
+int rproc_tee_load_fw(struct rproc *rproc, const struct firmware *fw)
+{
+	struct tee_param param[MAX_TEE_PARAM_ARRAY_MEMBER];
+	struct rproc_tee *trproc;
+	struct tee_ioctl_invoke_arg arg;
+	struct tee_shm *fw_shm;
+	int ret;
+
+	ret = mutex_lock_interruptible(&ctx_lock);
+	if (ret)
+		return ret;
+
+	if (!rproc_tee_ctx.dev) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	trproc = rproc_to_trproc(rproc);
+	if (!trproc) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	fw_shm = tee_shm_register_kernel_buf(rproc_tee_ctx.tee_ctx, (void *)fw->data, fw->size);
+	if (IS_ERR(fw_shm)) {
+		ret = PTR_ERR(fw_shm);
+		goto out;
+	}
+
+	rproc_tee_prepare_args(trproc, TA_RPROC_CMD_LOAD_FW, &arg, param, 1);
+
+	/* Provide the address of the firmware image */
+	param[1] = (struct tee_param) {
+		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT,
+		.u.memref = {
+			.shm = fw_shm,
+			.size = fw->size,
+			.shm_offs = 0,
+		},
+	};
+
+	ret = tee_client_invoke_func(rproc_tee_ctx.tee_ctx, &arg, param);
+	if (ret < 0 || arg.ret != 0) {
+		dev_err(rproc_tee_ctx.dev,
+			"TA_RPROC_CMD_LOAD_FW invoke failed TEE err: %#x, ret:%d\n",
+			arg.ret, ret);
+		if (!ret)
+			ret = -EIO;
+	}
+
+	tee_shm_free(fw_shm);
+
+out:
+	mutex_unlock(&ctx_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(rproc_tee_load_fw);
+
+static int rproc_tee_get_loaded_rsc_table(struct rproc *rproc, phys_addr_t *rsc_pa,
+					  size_t *table_sz)
+{
+	struct tee_param param[MAX_TEE_PARAM_ARRAY_MEMBER];
+	struct rproc_tee *trproc;
+	struct tee_ioctl_invoke_arg arg;
+	int ret;
+
+	ret = mutex_lock_interruptible(&ctx_lock);
+	if (ret)
+		return ret;
+
+	if (!rproc_tee_ctx.dev) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	trproc = rproc_to_trproc(rproc);
+	if (!trproc) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	rproc_tee_prepare_args(trproc, TA_RPROC_CMD_GET_RSC_TABLE, &arg, param, 2);
+
+	param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
+	param[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
+
+	ret = tee_client_invoke_func(rproc_tee_ctx.tee_ctx, &arg, param);
+	if (ret < 0 || arg.ret != 0) {
+		dev_err(rproc_tee_ctx.dev,
+			"TA_RPROC_CMD_GET_RSC_TABLE invoke failed TEE err: %#x, ret:%d\n",
+			arg.ret, ret);
+		ret = -EIO;
+		goto out;
+	}
+
+	*table_sz = param[2].u.value.a;
+	if (sizeof(phys_addr_t) == sizeof(u64))
+		*table_sz |= param[2].u.value.b << 32;
+
+	if (*table_sz) {
+		*rsc_pa = param[1].u.value.a;
+		if (sizeof(phys_addr_t) == sizeof(u64))
+			*rsc_pa |= param[1].u.value.b << 32;
+	} else {
+		*rsc_pa = 0;
+	}
+
+out:
+	mutex_unlock(&ctx_lock);
+	return ret;
+}
+
+/**
+ * rproc_tee_parse_fw() - Get the resource table from TEE application
+ * @rproc: Pointer to the struct rproc representing the remote processor
+ * @fw: Pointer to the firmware structure containing the firmware data and size
+ *
+ * This function retrieves the loaded resource table and creates a cached_table
+ * copy. Since the firmware image is signed and potentially encrypted, the
+ * firmware must be loaded first to access the loaded resource table.
+ *
+ * Return: 0 on success, or an error code on failure
+ */
+int rproc_tee_parse_fw(struct rproc *rproc, const struct firmware *fw)
+{
+	phys_addr_t rsc_table;
+	void *rsc_va;
+	size_t table_sz;
+	int ret;
+
+	if (!rproc)
+		return -EINVAL;
+
+	/* We need first to Load the firmware, to be able to get the resource table. */
+	ret = rproc_tee_load_fw(rproc, fw);
+	if (ret)
+		return ret;
+
+	ret = rproc_tee_get_loaded_rsc_table(rproc, &rsc_table, &table_sz);
+	if (ret)
+		goto release_fw;
+
+	/*
+	 * We assume here that the memory mapping is the same between the TEE
+	 * and Linux kernel contexts. Else a new TEE remoteproc service could be
+	 * needed to get a copy of the resource table.
+	 */
+	rsc_va = memremap(rsc_table, table_sz, MEMREMAP_WC);
+	if (!rsc_va) {
+		dev_err(rproc_tee_ctx.dev, "Unable to map memory region: %pa+%zx\n",
+			&rsc_table, table_sz);
+		ret = -ENOMEM;
+		goto release_fw;
+	}
+
+	/*
+	 * Create a copy of the resource table to have the same behavior as the
+	 * ELF loader. This cached table will be used by the remoteproc core
+	 * after the remoteproc stops to free resources and for crash recovery
+	 * to reapply the settings.
+	 * The cached table will be freed by the remoteproc core.
+	 */
+	rproc->cached_table = kmemdup(rsc_va, table_sz, GFP_KERNEL);
+	memunmap(rsc_va);
+
+	if (!rproc->cached_table) {
+		ret = -ENOMEM;
+		goto release_fw;
+	}
+
+	rproc->table_ptr = rproc->cached_table;
+	rproc->table_sz = table_sz;
+
+	return 0;
+
+release_fw:
+	rproc_tee_release_fw(rproc);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(rproc_tee_parse_fw);
+
+/**
+ * rproc_tee_find_loaded_rsc_table() - Find the loaded resource table loaded by
+ *				       the TEE application
+ * @rproc: Pointer to the struct rproc representing the remote processor
+ * @fw: Pointer to the firmware structure containing the firmware data and size
+ *
+ * This function retrieves the physical address and size of the resource table
+ * loaded by the TEE application.
+ *
+ * Return: pointer to the resource table if found, or NULL if not found or size
+ * is 0
+ */
+struct resource_table *rproc_tee_find_loaded_rsc_table(struct rproc *rproc,
+						       const struct firmware *fw)
+{
+	phys_addr_t rsc_table;
+	size_t table_sz;
+	int ret;
+
+	ret = rproc_tee_get_loaded_rsc_table(rproc, &rsc_table, &table_sz);
+	if (ret)
+		return NULL;
+
+	rproc->table_sz = table_sz;
+	if (!table_sz)
+		return NULL;
+
+	/*
+	 * At this step the memory area that contains the resource table should
+	 * have been registered by the remote proc platform driver and allocated
+	 * by rproc_alloc_registered_carveouts().
+	 */
+	return rproc_pa_to_va(rproc, rsc_table, table_sz, NULL);
+}
+EXPORT_SYMBOL_GPL(rproc_tee_find_loaded_rsc_table);
+
+/**
+ * rproc_tee_start() - Request the TEE application to start the remote processor
+ * @rproc: Pointer to the struct rproc representing the remote processor
+ *
+ * This function invokes the TA_RPROC_CMD_START command to start the remote
+ * processor.
+ *
+ * Return: Returns 0 on success, -EINVAL or -EIO on failure
+ */
+int rproc_tee_start(struct rproc *rproc)
+{
+	struct tee_param param[MAX_TEE_PARAM_ARRAY_MEMBER];
+	struct rproc_tee *trproc;
+	struct tee_ioctl_invoke_arg arg;
+	int ret;
+
+	ret = mutex_lock_interruptible(&ctx_lock);
+	if (ret)
+		return ret;
+
+	if (!rproc_tee_ctx.dev) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	trproc = rproc_to_trproc(rproc);
+	if (!trproc) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	rproc_tee_prepare_args(trproc, TA_RPROC_CMD_START, &arg, param, 0);
+
+	ret = tee_client_invoke_func(rproc_tee_ctx.tee_ctx, &arg, param);
+	if (ret < 0 || arg.ret != 0) {
+		dev_err(rproc_tee_ctx.dev,
+			"TA_RPROC_CMD_START invoke failed TEE err: %#x, ret:%d\n", arg.ret, ret);
+		if (!ret)
+			ret = -EIO;
+	}
+
+out:
+	mutex_unlock(&ctx_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(rproc_tee_start);
+
+/**
+ * rproc_tee_stop() - Request the TEE application to start the remote processor
+ * @rproc: Pointer to the struct rproc representing the remote processor
+ *
+ * This function invokes the TA_RPROC_CMD_STOP command to stop the remote
+ * processor.
+ *
+ * Return: Returns 0 on success, -EINVAL or -EIO on failure
+ */
+int rproc_tee_stop(struct rproc *rproc)
+{
+	struct tee_param param[MAX_TEE_PARAM_ARRAY_MEMBER];
+	struct rproc_tee *trproc;
+	struct tee_ioctl_invoke_arg arg;
+	int ret;
+
+	ret = mutex_lock_interruptible(&ctx_lock);
+	if (ret)
+		return ret;
+
+	if (!rproc_tee_ctx.dev) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	trproc = rproc_to_trproc(rproc);
+	if (!trproc) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	rproc_tee_prepare_args(trproc, TA_RPROC_CMD_STOP, &arg, param, 0);
+
+	ret = tee_client_invoke_func(rproc_tee_ctx.tee_ctx, &arg, param);
+	if (ret < 0 || arg.ret != 0) {
+		dev_err(rproc_tee_ctx.dev,
+			"TA_RPROC_CMD_STOP invoke failed TEE err: %#x, ret:%d\n", arg.ret, ret);
+		if (!ret)
+			ret = -EIO;
+	}
+
+out:
+	mutex_unlock(&ctx_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(rproc_tee_stop);
+
+static const struct rproc_ops rproc_tee_default_ops = {
+	.start		= rproc_tee_start,
+	.stop		= rproc_tee_stop,
+	.load		= rproc_tee_load_fw,
+	.parse_fw	= rproc_tee_parse_fw,
+	.find_loaded_rsc_table = rproc_tee_find_loaded_rsc_table,
+	.release_fw	= rproc_tee_release_fw,
+};
+
+static const struct tee_client_device_id rproc_tee_id_table[] = {
+	{UUID_INIT(0x80a4c275, 0x0a47, 0x4905, 0x82, 0x85, 0x14, 0x86, 0xa9, 0x77, 0x1a, 0x08)},
+	{ /* sentinel */ }
+};
+
+/**
+ * rproc_tee_register() - Register a remote processor controlled by the TEE application.
+ * @dev: Pointer to client rproc device
+ * @rproc: Pointer to the struct rproc representing the remote processor
+ * @rproc_id: ID of the remote processor
+ * @auto_boot: flag to indicate if remote processor should be auto-started
+ *
+ * This function registers a remote processor that will be managed by a TEE
+ * application, by opening a session with the TEE client.
+ *
+ * Return: Returns 0 on success, or an error code on failure
+ */
+int rproc_tee_register(struct device *dev, struct rproc **rproc,
+		       unsigned int rproc_id, bool auto_boot)
+{
+	struct tee_param param[MAX_TEE_PARAM_ARRAY_MEMBER];
+	struct tee_ioctl_open_session_arg sess_arg;
+	struct device_node *np = dev->of_node;
+	struct tee_client_device *tee_device;
+	struct rproc *new_rproc;
+	struct rproc_tee *trproc;
+	const char *fw_name;
+	int ret;
+
+	ret = mutex_lock_interruptible(&ctx_lock);
+	if (ret)
+		return ret;
+
+	if (!rproc_tee_ctx.dev) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	trproc = kzalloc(sizeof(*trproc), GFP_KERNEL);
+	if (!trproc) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	/* Look for an optional firmware name */
+	ret = rproc_of_parse_firmware(dev, 0, &fw_name);
+	if (ret < 0 && ret != -EINVAL)
+		goto free_tproc;
+
+	new_rproc = rproc_alloc(dev, np->name, &rproc_tee_default_ops,
+				fw_name, sizeof(*trproc));
+	if (!new_rproc) {
+		ret = -ENOMEM;
+		goto free_tproc;
+	}
+
+	tee_device = to_tee_client_device(rproc_tee_ctx.dev);
+	memset(&sess_arg, 0, sizeof(sess_arg));
+
+	memcpy(sess_arg.uuid, tee_device->id.uuid.b, TEE_IOCTL_UUID_LEN);
+
+	sess_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL;
+	sess_arg.num_params = 1;
+
+	param[0] = (struct tee_param) {
+		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+		.u.value.a = rproc_id,
+	};
+
+	ret = tee_client_open_session(rproc_tee_ctx.tee_ctx, &sess_arg, param);
+	if (ret < 0 || sess_arg.ret != 0) {
+		dev_err(dev, "tee_client_open_session failed, err: %#x\n", sess_arg.ret);
+		ret = -EINVAL;
+		goto free_rproc;
+	}
+
+	trproc->rproc_id = rproc_id;
+	trproc->session_id = sess_arg.session;
+	new_rproc->auto_boot = auto_boot;
+
+	ret = rproc_add(new_rproc);
+	if (ret)
+		goto close_tee;
+
+	trproc->rproc = new_rproc;
+	*rproc = new_rproc;
+
+	list_add_tail(&trproc->node, &rproc_tee_ctx.rproc_list);
+
+	mutex_unlock(&ctx_lock);
+
+	return 0;
+
+close_tee:
+	if (tee_client_close_session(rproc_tee_ctx.tee_ctx, trproc->session_id))
+		dev_err(rproc_tee_ctx.dev, "tee_client_close_session failed\n");
+free_rproc:
+	rproc_free(new_rproc);
+free_tproc:
+	kfree(trproc);
+out:
+	mutex_unlock(&ctx_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(rproc_tee_register);
+
+/**
+ * rproc_tee_unregister - Unregister a remote processor controlled by the TEE
+ *                        application.
+ * @dev: Pointer to client rproc device
+ * @rproc: Pointer to the struct rproc representing the remote processor
+ *
+ * This function unregisters a remote processor previously registered by the
+ * rproc_tee_register() function.
+ *
+ * Return: Returns 0 on success, or an error code on failure
+ */
+int rproc_tee_unregister(struct device *dev, struct rproc *rproc)
+{
+	struct rproc_tee *trproc;
+	int ret;
+
+	if (!rproc_tee_ctx.dev) {
+		ret = -ENODEV;
+		return ret;
+	}
+
+	trproc = rproc_to_trproc(rproc);
+	if (!trproc) {
+		ret = -EINVAL;
+		return ret;
+	}
+
+	rproc_del(rproc);
+	rproc_free(rproc);
+
+	ret = mutex_lock_interruptible(&ctx_lock);
+	if (ret)
+		return ret;
+
+	ret = tee_client_close_session(rproc_tee_ctx.tee_ctx, trproc->session_id);
+	if (ret < 0)
+		dev_err(rproc_tee_ctx.dev, "tee_client_close_session failed, err: %#x\n", ret);
+	list_del(&trproc->node);
+	kfree(trproc);
+	mutex_unlock(&ctx_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(rproc_tee_unregister);
+
+static int rproc_tee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
+{
+	/* Today we support only the OP-TEE, could be extend to other tees */
+	return (ver->impl_id == TEE_IMPL_ID_OPTEE);
+}
+
+static const struct of_device_id remoteproc_tee_of_match[] = {
+	{ .compatible = "rproc-service-80a4c275-0a47-4905-8285-1486a9771a08" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, remoteproc_tee_of_match);
+
+static int rproc_tee_probe(struct device *dev)
+{
+	struct tee_context *tee_ctx;
+	struct device_node *np;
+	int ret;
+
+	pr_err("%s %d", __func__, __LINE__);
+	np = of_find_compatible_node(NULL, NULL,
+				     remoteproc_tee_of_match[0].compatible);
+	if (!np) {
+		dev_err(dev, "Device node not found\n");
+		return -ENODEV;
+	}
+
+	/* Open context with TEE driver */
+	tee_ctx = tee_client_open_context(NULL, rproc_tee_ctx_match, NULL, NULL);
+	if (IS_ERR(tee_ctx)) {
+		ret = PTR_ERR(tee_ctx);
+		goto put_node;
+	}
+
+	ret = mutex_lock_interruptible(&ctx_lock);
+	if (ret)
+		goto close_ctx;
+
+	rproc_tee_ctx.dev = dev;
+	rproc_tee_ctx.tee_ctx = tee_ctx;
+	INIT_LIST_HEAD(&rproc_tee_ctx.rproc_list);
+
+	mutex_unlock(&ctx_lock);
+
+	ret = device_add_of_node(dev, np);
+	if (ret)
+		goto clean_ctx;
+
+	ret = of_platform_populate(np, NULL, NULL, dev);
+	if (ret) {
+		dev_err(dev, "cannot populate node (%d)\n", ret);
+		goto clean_ctx;
+	}
+
+	return 0;
+
+clean_ctx:
+	mutex_lock(&ctx_lock);
+	rproc_tee_ctx.dev = NULL;
+	rproc_tee_ctx.tee_ctx = NULL;
+	mutex_unlock(&ctx_lock);
+
+close_ctx:
+	tee_client_close_context(tee_ctx);
+
+put_node:
+	of_node_put(np);
+	return ret;
+}
+
+static int rproc_tee_remove(struct device *dev)
+{
+	of_platform_depopulate(dev);
+
+	device_remove_of_node(dev);
+
+	mutex_lock(&ctx_lock);
+	tee_client_close_context(rproc_tee_ctx.tee_ctx);
+	rproc_tee_ctx.dev = NULL;
+	rproc_tee_ctx.tee_ctx = NULL;
+	mutex_unlock(&ctx_lock);
+
+	return 0;
+}
+
+MODULE_DEVICE_TABLE(tee, rproc_tee_id_table);
+
+static struct tee_client_driver rproc_tee_fw_driver = {
+	.id_table	= rproc_tee_id_table,
+	.driver		= {
+		.name		= KBUILD_MODNAME,
+		.bus		= &tee_bus_type,
+		.probe		= rproc_tee_probe,
+		.remove		= rproc_tee_remove,
+	},
+};
+
+static int __init rproc_tee_fw_mod_init(void)
+{
+	return driver_register(&rproc_tee_fw_driver.driver);
+}
+
+static void __exit rproc_tee_fw_mod_exit(void)
+{
+	driver_unregister(&rproc_tee_fw_driver.driver);
+}
+
+module_init(rproc_tee_fw_mod_init);
+module_exit(rproc_tee_fw_mod_exit);
+
+MODULE_DESCRIPTION("remote processor TEE module");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/remoteproc_tee.h b/include/linux/remoteproc_tee.h
new file mode 100644
index 000000000000..33150cff7a5a
--- /dev/null
+++ b/include/linux/remoteproc_tee.h
@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright(c) 2025 STMicroelectronics
+ */
+
+#ifndef REMOTEPROC_TEE_H
+#define REMOTEPROC_TEE_H
+
+#include <linux/tee_drv.h>
+#include <linux/firmware.h>
+#include <linux/remoteproc.h>
+
+#if IS_ENABLED(CONFIG_REMOTEPROC_TEE)
+
+int rproc_tee_register(struct device *dev, struct rproc **rproc,
+		       unsigned int rproc_id, bool auto_boot);
+int rproc_tee_unregister(struct device *dev, struct rproc *rproc);
+int rproc_tee_parse_fw(struct rproc *rproc, const struct firmware *fw);
+int rproc_tee_load_fw(struct rproc *rproc, const struct firmware *fw);
+void rproc_tee_release_fw(struct rproc *rproc);
+struct resource_table *rproc_tee_find_loaded_rsc_table(struct rproc *rproc,
+						       const struct firmware *fw);
+int rproc_tee_start(struct rproc *rproc);
+int rproc_tee_stop(struct rproc *rproc);
+int rproc_tee_pa_to_da(struct rproc *rproc, phys_addr_t pa, size_t size, u64 *da);
+#else
+
+static inline int rproc_tee_register(struct device *dev, struct rproc **rproc,
+				     unsigned int rproc_id, bool auto_boot)
+{
+	return -ENODEV;
+}
+
+static inline int rproc_tee_parse_fw(struct rproc *rproc, const struct firmware *fw)
+{
+	/* This shouldn't be possible */
+	WARN_ON(1);
+
+	return 0;
+}
+
+static inline int rproc_tee_unregister(struct device *dev, struct rproc *rproc)
+{
+	/* This shouldn't be possible */
+	WARN_ON(1);
+
+	return 0;
+}
+
+static inline int rproc_tee_load_fw(struct rproc *rproc, const struct firmware *fw)
+{
+	/* This shouldn't be possible */
+	WARN_ON(1);
+
+	return 0;
+}
+
+static inline int rproc_tee_start(struct rproc *rproc)
+{
+	/* This shouldn't be possible */
+	WARN_ON(1);
+
+	return 0;
+}
+
+static inline int rproc_tee_stop(struct rproc *rproc)
+{
+	/* This shouldn't be possible */
+	WARN_ON(1);
+
+	return 0;
+}
+
+static inline void rproc_tee_release_fw(struct rproc *rproc)
+{
+	/* This shouldn't be possible */
+	WARN_ON(1);
+}
+
+static inline struct resource_table *
+rproc_tee_find_loaded_rsc_table(struct rproc *rproc, const struct firmware *fw)
+{
+	/* This shouldn't be possible */
+	WARN_ON(1);
+
+	return NULL;
+}
+#endif /* CONFIG_REMOTEPROC_TEE */
+#endif /* REMOTEPROC_TEE_H */
-- 
2.43.0



From arnaud.pouliquen at foss.st.com  Wed Dec 17 07:39:17 2025
From: arnaud.pouliquen at foss.st.com (Arnaud Pouliquen)
Date: Wed, 17 Dec 2025 16:39:17 +0100
Subject: [PATCH v20 6/6] remoteproc: stm32: Add TEE-controlled STM32 driver
In-Reply-To: <20251217153917.3998544-1-arnaud.pouliquen@foss.st.com>
References: <20251217153917.3998544-1-arnaud.pouliquen@foss.st.com>
Message-ID: <20251217153917.3998544-7-arnaud.pouliquen@foss.st.com>

Add a remoteproc platform driver for the STM32MP15 Cortex-M4 core
controlled via a TEE Trusted Application.

The driver integrates with the generic TEE remoteproc layer
(rproc_tee_*) to delegate firmware authentication, loading and
start/stop operations to the TEE, while handling STM32-specific
platform resources on the Linux side:

  - Translation between physical and device addresses using
    SoC-specific DMA ranges.
  - Registration of reserved-memory carveouts from "memory-region"
    phandles (including vdev vrings and buffers).
  - Mailbox-based virtio queue kicks and a shutdown channel using
    the IPCC mailbox controller.
  - Optional watchdog interrupt for crash reporting and wakeup.

This enables secure boot and runtime isolation of the M4 firmware
while still using the standard remoteproc and rpmsg frameworks
on STM32MP15.

Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen at foss.st.com>
---
 drivers/remoteproc/Makefile          |   2 +-
 drivers/remoteproc/stm32_rproc_tee.c | 526 +++++++++++++++++++++++++++
 2 files changed, 527 insertions(+), 1 deletion(-)
 create mode 100644 drivers/remoteproc/stm32_rproc_tee.c

diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index a1a5201982d4..80f0965bac95 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -36,7 +36,7 @@ qcom_wcnss_pil-y			+= qcom_wcnss_iris.o
 obj-$(CONFIG_RCAR_REMOTEPROC)		+= rcar_rproc.o
 obj-$(CONFIG_ST_REMOTEPROC)		+= st_remoteproc.o
 obj-$(CONFIG_ST_SLIM_REMOTEPROC)	+= st_slim_rproc.o
-obj-$(CONFIG_STM32_RPROC)		+= stm32_rproc.o
+obj-$(CONFIG_STM32_RPROC)		+= stm32_rproc.o stm32_rproc_tee.o
 obj-$(CONFIG_TI_K3_DSP_REMOTEPROC)	+= ti_k3_dsp_remoteproc.o ti_k3_common.o
 obj-$(CONFIG_TI_K3_M4_REMOTEPROC)	+= ti_k3_m4_remoteproc.o ti_k3_common.o
 obj-$(CONFIG_TI_K3_R5_REMOTEPROC)	+= ti_k3_r5_remoteproc.o ti_k3_common.o
diff --git a/drivers/remoteproc/stm32_rproc_tee.c b/drivers/remoteproc/stm32_rproc_tee.c
new file mode 100644
index 000000000000..1d492698265b
--- /dev/null
+++ b/drivers/remoteproc/stm32_rproc_tee.c
@@ -0,0 +1,526 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025, STMicroelectronics - All Rights Reserved
+ */
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mailbox_client.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
+#include <linux/remoteproc.h>
+#include <linux/remoteproc_tee.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/workqueue.h>
+
+#include "remoteproc_internal.h"
+
+#define MBOX_NB_VQ		2
+#define MBOX_NB_MBX		3
+
+#define STM32_MBX_VQ0		"vq0"
+#define STM32_MBX_VQ0_ID	0
+#define STM32_MBX_VQ1		"vq1"
+#define STM32_MBX_VQ1_ID	1
+#define STM32_MBX_SHUTDOWN	"shutdown"
+
+struct stm32_rproc_tee_mem {
+	char name[20];
+	void __iomem *cpu_addr;
+	phys_addr_t phy_addr;
+	u32 dev_addr;
+	size_t size;
+};
+
+struct stm32_rproc_tee_dma_ranges {
+	u32 dev_addr;
+	u32 phy_addr;
+	u32 size;
+};
+
+struct stm32_mbox {
+	const unsigned char name[10];
+	struct mbox_chan *chan;
+	struct mbox_client client;
+	struct work_struct vq_work;
+	int vq_id;
+};
+
+struct stm32_rproc_tee {
+	int wdg_irq;
+	const struct stm32_rproc_tee_dma_ranges *ranges;
+	struct stm32_mbox mb[MBOX_NB_MBX];
+	struct workqueue_struct *workqueue;
+};
+
+static const struct stm32_rproc_tee_dma_ranges stm32mp15_m4_dma_ranges[] = {
+	/* RETRAM address translation */
+	{ .dev_addr = 0x0, .phy_addr = 0x38000000, .size = 0x10000 },
+	{/* sentinel */}
+};
+
+static int stm32_rproc_tee_pa_to_da(struct rproc *rproc, phys_addr_t pa,
+				    size_t size, u64 *da)
+{
+	struct stm32_rproc_tee *ddata = rproc->priv;
+	const struct stm32_rproc_tee_dma_ranges *range;
+	struct device *dev = rproc->dev.parent;
+
+	for (range = ddata->ranges; range->phy_addr; range++) {
+		if (pa < range->phy_addr ||
+		    pa >= range->phy_addr + range->size)
+			continue;
+		if (pa + size > range->phy_addr + range->size) {
+			dev_err(dev, "range too small for %pa+0x%zx\n", &pa, size);
+			return -EINVAL;
+		}
+		*da = pa - range->phy_addr + range->dev_addr;
+		dev_dbg(dev, "pa %pa to da %llx\n", &pa, *da);
+		return 0;
+	}
+
+	*da = pa;
+
+	return 0;
+}
+
+static int stm32_rproc_tee_mem_alloc(struct rproc *rproc,
+				     struct rproc_mem_entry *mem)
+{
+	struct device *dev = rproc->dev.parent;
+	void *va;
+
+	dev_dbg(dev, "map memory: %pad+%zx\n", &mem->dma, mem->len);
+	va = (__force void *)ioremap_wc(mem->dma, mem->len);
+	if (IS_ERR_OR_NULL(va)) {
+		dev_err(dev, "Unable to map memory region: %pad+0x%zx\n",
+			&mem->dma, mem->len);
+		return -ENOMEM;
+	}
+
+	/* Update memory entry va */
+	mem->va = va;
+
+	return 0;
+}
+
+static int stm32_rproc_tee_mem_release(struct rproc *rproc,
+				       struct rproc_mem_entry *mem)
+{
+	dev_dbg(rproc->dev.parent, "unmap memory: %pa\n", &mem->dma);
+	iounmap((__force __iomem void *)mem->va);
+
+	return 0;
+}
+
+static int stm32_rproc_tee_mbox_idx(struct rproc *rproc, const unsigned char *name)
+{
+	struct stm32_rproc_tee *ddata = rproc->priv;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ddata->mb); i++) {
+		if (!strncmp(ddata->mb[i].name, name, strlen(name)))
+			return i;
+	}
+	dev_err(&rproc->dev, "mailbox %s not found\n", name);
+
+	return -EINVAL;
+}
+
+static void stm32_rproc_tee_request_shutdown(struct rproc *rproc)
+{
+	struct stm32_rproc_tee *ddata = rproc->priv;
+	int err, idx;
+
+	/* Request shutdown of the remote processor */
+	if (rproc->state != RPROC_OFFLINE && rproc->state != RPROC_CRASHED) {
+		idx = stm32_rproc_tee_mbox_idx(rproc, STM32_MBX_SHUTDOWN);
+		if (idx >= 0 && ddata->mb[idx].chan) {
+			err = mbox_send_message(ddata->mb[idx].chan, "detach");
+			if (err < 0)
+				dev_warn(&rproc->dev, "warning: remote FW shutdown without ack\n");
+		}
+	}
+}
+
+static int stm32_rproc_tee_stop(struct rproc *rproc)
+{
+	stm32_rproc_tee_request_shutdown(rproc);
+
+	return rproc_tee_stop(rproc);
+}
+
+static int stm32_rproc_tee_prepare(struct rproc *rproc)
+{
+	struct device *dev = rproc->dev.parent;
+	struct device_node *np = dev->of_node;
+	struct rproc_mem_entry *mem;
+	int index = 0, mr = 0;
+	u64 da;
+
+	/* Register associated reserved memory regions */
+	while (1) {
+		struct resource res;
+		int ret;
+
+		ret = of_reserved_mem_region_to_resource(np, mr++, &res);
+		if (ret)
+			return 0;
+
+		if (stm32_rproc_tee_pa_to_da(rproc, res.start,
+					     resource_size(&res), &da) < 0) {
+			dev_err(dev, "memory region not valid %pR\n", &res);
+			return -EINVAL;
+		}
+
+		/* No need to map vdev buffer */
+		if (strstarts(res.name, "vdev0buffer")) {
+			/* Register reserved memory for vdev buffer alloc */
+			mem = rproc_of_resm_mem_entry_init(dev, index,
+							   resource_size(&res),
+							   res.start,
+							   "vdev0buffer");
+		} else {
+			/* Register memory region */
+			mem = rproc_mem_entry_init(dev, NULL,
+						   (dma_addr_t)res.start,
+						   resource_size(&res), da,
+						   stm32_rproc_tee_mem_alloc,
+						   stm32_rproc_tee_mem_release,
+						   "%.*s",
+						   (int)(strchrnul(res.name, '@') - res.name),
+						   res.name);
+			if (mem)
+				rproc_coredump_add_segment(rproc, da,
+							   resource_size(&res));
+		}
+
+		if (!mem)
+			return -ENOMEM;
+
+		rproc_add_carveout(rproc, mem);
+		index++;
+	}
+
+	return 0;
+}
+
+static irqreturn_t stm32_rproc_tee_wdg(int irq, void *data)
+{
+	struct platform_device *pdev = data;
+	struct rproc *rproc = platform_get_drvdata(pdev);
+
+	rproc_report_crash(rproc, RPROC_WATCHDOG);
+
+	return IRQ_HANDLED;
+}
+
+static void stm32_rproc_tee_mb_vq_work(struct work_struct *work)
+{
+	struct stm32_mbox *mb = container_of(work, struct stm32_mbox, vq_work);
+	struct rproc *rproc = dev_get_drvdata(mb->client.dev);
+
+	mutex_lock(&rproc->lock);
+
+	if (rproc->state != RPROC_RUNNING && rproc->state != RPROC_ATTACHED)
+		goto unlock_mutex;
+
+	if (rproc_vq_interrupt(rproc, mb->vq_id) == IRQ_NONE)
+		dev_dbg(&rproc->dev, "no message found in vq%d\n", mb->vq_id);
+
+unlock_mutex:
+	mutex_unlock(&rproc->lock);
+}
+
+static void stm32_rproc_tee_mb_callback(struct mbox_client *cl, void *data)
+{
+	struct rproc *rproc = dev_get_drvdata(cl->dev);
+	struct stm32_mbox *mb = container_of(cl, struct stm32_mbox, client);
+	struct stm32_rproc_tee *ddata = rproc->priv;
+
+	queue_work(ddata->workqueue, &mb->vq_work);
+}
+
+static void stm32_rproc_tee_free_mbox(struct rproc *rproc)
+{
+	struct stm32_rproc_tee *ddata = rproc->priv;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(ddata->mb); i++) {
+		if (ddata->mb[i].chan)
+			mbox_free_channel(ddata->mb[i].chan);
+		ddata->mb[i].chan = NULL;
+	}
+}
+
+static const struct stm32_mbox stm32_rproc_tee_mbox[MBOX_NB_MBX] = {
+	{
+		.name = STM32_MBX_VQ0,
+		.vq_id = STM32_MBX_VQ0_ID,
+		.client = {
+			.rx_callback = stm32_rproc_tee_mb_callback,
+			.tx_block = false,
+		},
+	},
+	{
+		.name = STM32_MBX_VQ1,
+		.vq_id = STM32_MBX_VQ1_ID,
+		.client = {
+			.rx_callback = stm32_rproc_tee_mb_callback,
+			.tx_block = false,
+		},
+	},
+	{
+		.name = STM32_MBX_SHUTDOWN,
+		.vq_id = -1,
+		.client = {
+			.tx_block = true,
+			.tx_done = NULL,
+			.tx_tout = 500, /* 500 ms time out */
+		},
+	},
+};
+
+static int stm32_rproc_tee_request_mbox(struct rproc *rproc)
+{
+	struct stm32_rproc_tee *ddata = rproc->priv;
+	struct device *dev = &rproc->dev;
+	unsigned int i;
+	int j;
+	const unsigned char *name;
+	struct mbox_client *cl;
+
+	/* Initialise mailbox structure table */
+	memcpy(ddata->mb, stm32_rproc_tee_mbox, sizeof(stm32_rproc_tee_mbox));
+
+	for (i = 0; i < MBOX_NB_MBX; i++) {
+		name = ddata->mb[i].name;
+
+		cl = &ddata->mb[i].client;
+		cl->dev = dev->parent;
+
+		ddata->mb[i].chan = mbox_request_channel_byname(cl, name);
+		if (IS_ERR(ddata->mb[i].chan)) {
+			if (PTR_ERR(ddata->mb[i].chan) == -EPROBE_DEFER) {
+				dev_err_probe(dev->parent,
+					      PTR_ERR(ddata->mb[i].chan),
+					      "failed to request mailbox %s\n",
+					      name);
+				goto err_probe;
+			}
+			dev_info(dev, "mailbox %s mbox not used\n", name);
+			ddata->mb[i].chan = NULL;
+		}
+		if (ddata->mb[i].vq_id >= 0) {
+			INIT_WORK(&ddata->mb[i].vq_work,
+				  stm32_rproc_tee_mb_vq_work);
+		}
+	}
+
+	return 0;
+
+err_probe:
+	for (j = i - 1; j >= 0; j--)
+		if (ddata->mb[j].chan) {
+			mbox_free_channel(ddata->mb[j].chan);
+			ddata->mb[j].chan = NULL;
+		}
+	return -EPROBE_DEFER;
+}
+
+static void stm32_rproc_tee_kick(struct rproc *rproc, int vqid)
+{
+	struct stm32_rproc_tee *ddata = rproc->priv;
+	unsigned int i;
+	int err;
+
+	if (WARN_ON(vqid >= MBOX_NB_VQ))
+		return;
+
+	for (i = 0; i < MBOX_NB_MBX; i++) {
+		if (vqid != ddata->mb[i].vq_id)
+			continue;
+		if (!ddata->mb[i].chan)
+			return;
+		err = mbox_send_message(ddata->mb[i].chan, "kick");
+		if (err < 0)
+			dev_err(&rproc->dev, "%s: failed (%s, err:%d)\n",
+				__func__, ddata->mb[i].name, err);
+		return;
+	}
+}
+
+static const struct of_device_id stm32_rproc_tee_match[] = {
+	{
+		.compatible = "st,stm32mp15-m4-tee",
+		.data = &stm32mp15_m4_dma_ranges,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, stm32_rproc_tee_match);
+
+static int stm32_rproc_tee_parse_dt(struct platform_device *pdev,
+				    struct stm32_rproc_tee *ddata,
+				    bool *auto_boot)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	int err, irq;
+
+	irq = platform_get_irq_optional(pdev, 0);
+	if (irq == -EPROBE_DEFER)
+		return irq;
+
+	if (irq > 0) {
+		err = devm_request_irq(dev, irq, stm32_rproc_tee_wdg, 0,
+				       dev_name(dev), pdev);
+		if (err)
+			return dev_err_probe(dev, err,
+					     "failed to request wdg irq\n");
+
+		ddata->wdg_irq = irq;
+
+		if (of_property_read_bool(np, "wakeup-source")) {
+			device_init_wakeup(dev, true);
+			dev_pm_set_wake_irq(dev, irq);
+		}
+
+		dev_info(dev, "wdg irq registered\n");
+	}
+
+	*auto_boot = of_property_read_bool(np, "st,auto-boot");
+
+	return 0;
+}
+
+static int stm32_rproc_tee_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct stm32_rproc_tee *ddata;
+	struct rproc *rproc;
+	bool auto_boot;
+	u32 proc_id;
+	int ret;
+
+	ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
+	if (ret)
+		return ret;
+
+	ret = of_property_read_u32(np, "reg", &proc_id);
+	if (ret) {
+		dev_err(dev, "invalid reg on %pOF\n", np);
+		return ret;
+	}
+
+	ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
+	if (!ddata)
+		return -ENOMEM;
+
+	ret = stm32_rproc_tee_parse_dt(pdev, ddata, &auto_boot);
+	if (ret)
+		return ret;
+
+	ret = rproc_tee_register(dev, &rproc, proc_id, auto_boot);
+	if (ret)
+		return dev_err_probe(dev, ret, "signed firmware not supported by TEE\n");
+
+	rproc->ops->prepare = stm32_rproc_tee_prepare;
+	rproc->ops->stop = stm32_rproc_tee_stop;
+	rproc->ops->kick = stm32_rproc_tee_kick;
+
+	ddata = rproc->priv;
+
+	ddata->ranges = device_get_match_data(&pdev->dev);
+
+	rproc->has_iommu = false;
+	ddata->workqueue = create_workqueue(dev_name(dev));
+	if (!ddata->workqueue) {
+		dev_err(dev, "cannot create workqueue\n");
+		ret = -ENOMEM;
+		goto free_resources;
+	}
+
+	platform_set_drvdata(pdev, rproc);
+
+	ret = stm32_rproc_tee_request_mbox(rproc);
+	if (ret)
+		goto free_wkq;
+
+	return 0;
+
+free_wkq:
+	destroy_workqueue(ddata->workqueue);
+free_resources:
+	rproc_resource_cleanup(rproc);
+	if (device_may_wakeup(dev)) {
+		dev_pm_clear_wake_irq(dev);
+		device_init_wakeup(dev, false);
+	}
+	rproc_tee_unregister(dev, rproc);
+
+	return ret;
+}
+
+static void stm32_rproc_tee_remove(struct platform_device *pdev)
+{
+	struct rproc *rproc = platform_get_drvdata(pdev);
+	struct stm32_rproc_tee *ddata = rproc->priv;
+	struct device *dev = &pdev->dev;
+
+	stm32_rproc_tee_free_mbox(rproc);
+	destroy_workqueue(ddata->workqueue);
+
+	if (device_may_wakeup(dev)) {
+		dev_pm_clear_wake_irq(dev);
+		device_init_wakeup(dev, false);
+	}
+
+	rproc_tee_unregister(dev, rproc);
+}
+
+static int stm32_rproc_tee_suspend(struct device *dev)
+{
+	struct rproc *rproc = dev_get_drvdata(dev);
+	struct stm32_rproc_tee *ddata = rproc->priv;
+
+	if (device_may_wakeup(dev))
+		return enable_irq_wake(ddata->wdg_irq);
+
+	return 0;
+}
+
+static int stm32_rproc_tee_resume(struct device *dev)
+{
+	struct rproc *rproc = dev_get_drvdata(dev);
+	struct stm32_rproc_tee *ddata = rproc->priv;
+
+	if (device_may_wakeup(dev))
+		return disable_irq_wake(ddata->wdg_irq);
+
+	return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(stm32_rproc_tee_pm_ops,
+				stm32_rproc_tee_suspend, stm32_rproc_tee_resume);
+
+static struct platform_driver stm32_rproc_tee_driver = {
+	.probe = stm32_rproc_tee_probe,
+	.remove = stm32_rproc_tee_remove,
+	.driver = {
+		.name = "stm32-rproc-tee",
+		.pm = pm_ptr(&stm32_rproc_tee_pm_ops),
+		.of_match_table = stm32_rproc_tee_match,
+	},
+};
+module_platform_driver(stm32_rproc_tee_driver);
+
+MODULE_DESCRIPTION("STM32 Remote Processor TEE Control Driver");
+MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen at foss.st.com>");
+MODULE_LICENSE("GPL");
+
-- 
2.43.0



From ryan.roberts at arm.com  Wed Dec 17 07:43:41 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Wed, 17 Dec 2025 15:43:41 +0000
Subject: [PATCH v2 1/3] arm64: mm: support batch clearing of the young
 flag for large folios
In-Reply-To: <e10f876ce130134fa089befe83f30561b48b9889.1765439380.git.baolin.wang@linux.alibaba.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <e10f876ce130134fa089befe83f30561b48b9889.1765439380.git.baolin.wang@linux.alibaba.com>
Message-ID: <1beaa7de-4b31-4f19-abee-83872f868e28@arm.com>

Sorry I'm a bit late to the party...


On 11/12/2025 08:16, Baolin Wang wrote:
> Currently, contpte_ptep_test_and_clear_young() and contpte_ptep_clear_flush_young()
> only clear the young flag and flush TLBs for PTEs within the contiguous range.
> To support batch PTE operations for other sized large folios in the following
> patches, adding a new parameter to specify the number of PTEs.
> 
> While we are at it, rename the functions to maintain consistency with other
> contpte_*() functions.
> 
> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
> ---
>  arch/arm64/include/asm/pgtable.h | 12 ++++-----
>  arch/arm64/mm/contpte.c          | 44 ++++++++++++++++++++++----------
>  2 files changed, 37 insertions(+), 19 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
> index 0944e296dd4a..e03034683156 100644
> --- a/arch/arm64/include/asm/pgtable.h
> +++ b/arch/arm64/include/asm/pgtable.h
> @@ -1679,10 +1679,10 @@ extern void contpte_clear_full_ptes(struct mm_struct *mm, unsigned long addr,
>  extern pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
>  				unsigned long addr, pte_t *ptep,
>  				unsigned int nr, int full);
> -extern int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
> -				unsigned long addr, pte_t *ptep);
> -extern int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
> -				unsigned long addr, pte_t *ptep);
> +extern int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
> +				unsigned long addr, pte_t *ptep, unsigned int nr);
> +extern int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
> +				unsigned long addr, pte_t *ptep, unsigned int nr);

The "contpte_" functions are intended to be private to the arm64 arch and should
be exposed via the generic APIs. But I don't see any generic batched API for
this, so you're only actually able to pass CONT_PTES as nr. Perhaps you're
planning to define "test_and_clear_young_ptes()" and "clear_flush_young_ptes()"
in later patches?

>  extern void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
>  				pte_t *ptep, unsigned int nr);
>  extern int contpte_ptep_set_access_flags(struct vm_area_struct *vma,
> @@ -1854,7 +1854,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
>  	if (likely(!pte_valid_cont(orig_pte)))
>  		return __ptep_test_and_clear_young(vma, addr, ptep);
>  
> -	return contpte_ptep_test_and_clear_young(vma, addr, ptep);
> +	return contpte_test_and_clear_young_ptes(vma, addr, ptep, CONT_PTES);
>  }
>  
>  #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
> @@ -1866,7 +1866,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
>  	if (likely(!pte_valid_cont(orig_pte)))
>  		return __ptep_clear_flush_young(vma, addr, ptep);
>  
> -	return contpte_ptep_clear_flush_young(vma, addr, ptep);
> +	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
>  }
>  
>  #define wrprotect_ptes wrprotect_ptes
> diff --git a/arch/arm64/mm/contpte.c b/arch/arm64/mm/contpte.c
> index c0557945939c..19b122441be3 100644
> --- a/arch/arm64/mm/contpte.c
> +++ b/arch/arm64/mm/contpte.c
> @@ -488,8 +488,9 @@ pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
>  }
>  EXPORT_SYMBOL_GPL(contpte_get_and_clear_full_ptes);
>  
> -int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
> -					unsigned long addr, pte_t *ptep)
> +int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
> +					unsigned long addr, pte_t *ptep,
> +					unsigned int nr)
>  {
>  	/*
>  	 * ptep_clear_flush_young() technically requires us to clear the access
> @@ -500,39 +501,56 @@ int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
>  	 * having to unfold.
>  	 */
>  
> +	unsigned long start = addr;

Personally I wouldn't bother defining start - just reuse addr. You're
incrementing start in the below loop, so it's more appropriate to call it addr
anyway.

> +	unsigned long end = start + nr * PAGE_SIZE;
>  	int young = 0;
>  	int i;
>  
> -	ptep = contpte_align_down(ptep);
> -	addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
> +	if (pte_cont(__ptep_get(ptep + nr - 1)))
> +		end = ALIGN(end, CONT_PTE_SIZE);
>  
> -	for (i = 0; i < CONT_PTES; i++, ptep++, addr += PAGE_SIZE)
> -		young |= __ptep_test_and_clear_young(vma, addr, ptep);
> +	if (pte_cont(__ptep_get(ptep))) {
> +		start = ALIGN_DOWN(start, CONT_PTE_SIZE);
> +		ptep = contpte_align_down(ptep);
> +	}
> +
> +	nr = (end - start) / PAGE_SIZE;
> +	for (i = 0; i < nr; i++, ptep++, start += PAGE_SIZE)

Given you're now defining end, perhaps we don't need nr?

	for (; addr != end; ptep++, addr += PAGE_SIZE)
		young |= __ptep_test_and_clear_young(vma, addr, ptep);

> +		young |= __ptep_test_and_clear_young(vma, start, ptep);
>  
>  	return young;
>  }
> -EXPORT_SYMBOL_GPL(contpte_ptep_test_and_clear_young);
> +EXPORT_SYMBOL_GPL(contpte_test_and_clear_young_ptes);
>  
> -int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
> -					unsigned long addr, pte_t *ptep)
> +int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
> +				unsigned long addr, pte_t *ptep,
> +				unsigned int nr)
>  {
>  	int young;
>  
> -	young = contpte_ptep_test_and_clear_young(vma, addr, ptep);
> +	young = contpte_test_and_clear_young_ptes(vma, addr, ptep, nr);
>  
>  	if (young) {
> +		unsigned long start = addr;
> +		unsigned long end = start + nr * PAGE_SIZE;
> +
> +		if (pte_cont(__ptep_get(ptep + nr - 1)))
> +			end = ALIGN(end, CONT_PTE_SIZE);
> +
> +		if (pte_cont(__ptep_get(ptep)))
> +			start = ALIGN_DOWN(start, CONT_PTE_SIZE);
> +

We now have this pattern of expanding contpte blocks up and down in 3 places.
Perhaps create a helper?

Thanks,
Ryan

>  		/*
>  		 * See comment in __ptep_clear_flush_young(); same rationale for
>  		 * eliding the trailing DSB applies here.
>  		 */
> -		addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
> -		__flush_tlb_range_nosync(vma->vm_mm, addr, addr + CONT_PTE_SIZE,
> +		__flush_tlb_range_nosync(vma->vm_mm, start, end,
>  					 PAGE_SIZE, true, 3);
>  	}
>  
>  	return young;
>  }
> -EXPORT_SYMBOL_GPL(contpte_ptep_clear_flush_young);
> +EXPORT_SYMBOL_GPL(contpte_clear_flush_young_ptes);
>  
>  void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
>  					pte_t *ptep, unsigned int nr)



From ritesh.list at gmail.com  Wed Dec 17 07:46:14 2025
From: ritesh.list at gmail.com (Ritesh Harjani (IBM))
Date: Wed, 17 Dec 2025 21:16:14 +0530
Subject: [PATCH v6 14/14] mm: Add basic tests for lazy_mmu
In-Reply-To: <ca0da7fd-245c-4d52-8f4d-f8fce4717494@arm.com>
References: <20251215150323.2218608-1-kevin.brodsky@arm.com> <20251215150323.2218608-15-kevin.brodsky@arm.com> <20251216201403.4647a4f9861d3122ee9e90d7@linux-foundation.org> <f9550d22-8810-4145-aaa8-48961f6ea35e@arm.com> <ca0da7fd-245c-4d52-8f4d-f8fce4717494@arm.com>
Message-ID: <87a4zhkt6h.ritesh.list@gmail.com>

Ryan Roberts <ryan.roberts at arm.com> writes:

> On 17/12/2025 09:26, Kevin Brodsky wrote:
>> On 17/12/2025 05:14, Andrew Morton wrote:
>>> On Mon, 15 Dec 2025 15:03:23 +0000 Kevin Brodsky <kevin.brodsky at arm.com> wrote:
>>>
>>>> Add basic KUnit tests for the generic aspects of the lazy MMU mode:
>>>> ensure that it appears active when it should, depending on how
>>>> enable/disable and pause/resume pairs are nested.
>>> I needed this for powerpc allmodconfig;
>>>
>>> --- a/arch/powerpc/mm/book3s64/hash_tlb.c~mm-add-basic-tests-for-lazy_mmu-fix
>>> +++ a/arch/powerpc/mm/book3s64/hash_tlb.c
>>> @@ -30,6 +30,7 @@
>>>  #include <trace/events/thp.h>
>>>  
>>>  DEFINE_PER_CPU(struct ppc64_tlb_batch, ppc64_tlb_batch);
>>> +EXPORT_SYMBOL_GPL(ppc64_tlb_batch);
>>>  
>>>  /*
>>>   * A linux PTE was changed and the corresponding hash table entry
>>> @@ -154,6 +155,7 @@ void __flush_tlb_pending(struct ppc64_tl
>>>  		flush_hash_range(i, local);
>>>  	batch->index = 0;
>>>  }
>>> +EXPORT_SYMBOL_GPL(__flush_tlb_pending);
>>>  
>>>  void hash__tlb_flush(struct mmu_gather *tlb)
>>>  {
>>> _
>> 
>> Oh indeed I hadn't considered that arch_{enter,leave}_lazy_mmu_mode()
>> refer to those symbols on powerpc... Maybe a bit overkill to export
>> those just for a test module, but I'm not sure there's a good
>> alternative. Forcing LAZY_MMU_MODE_KUNIT_TEST=y is ugly as it would also
>> force KUNIT=y. Alternatively we could depend on !PPC, not pretty either.
>
> Does EXPORT_SYMBOL_IF_KUNIT() help?
>

yes, that make sense. Thanks for the suggestion!
I guess we will need a diff like this in that case -


diff --git a/arch/powerpc/mm/book3s64/hash_tlb.c b/arch/powerpc/mm/book3s64/hash_tlb.c
index fbdeb8981ae7..ec2941cec815 100644
--- a/arch/powerpc/mm/book3s64/hash_tlb.c
+++ b/arch/powerpc/mm/book3s64/hash_tlb.c
@@ -25,11 +25,12 @@
 #include <asm/tlb.h>
 #include <asm/bug.h>
 #include <asm/pte-walk.h>
-
+#include <kunit/visibility.h>
 
 #include <trace/events/thp.h>
 
 DEFINE_PER_CPU(struct ppc64_tlb_batch, ppc64_tlb_batch);
+EXPORT_SYMBOL_IF_KUNIT(ppc64_tlb_batch);
 
 /*
  * A linux PTE was changed and the corresponding hash table entry
@@ -154,6 +155,7 @@ void __flush_tlb_pending(struct ppc64_tlb_batch *batch)
                flush_hash_range(i, local);
        batch->index = 0;
 }
+EXPORT_SYMBOL_IF_KUNIT(__flush_tlb_pending);
 
 void hash__tlb_flush(struct mmu_gather *tlb)
 {
diff --git a/mm/tests/lazy_mmu_mode_kunit.c b/mm/tests/lazy_mmu_mode_kunit.c
index 2720eb995714..340d7cda9096 100644
--- a/mm/tests/lazy_mmu_mode_kunit.c
+++ b/mm/tests/lazy_mmu_mode_kunit.c
@@ -69,3 +69,4 @@ kunit_test_suite(lazy_mmu_mode_test_suite);
 
 MODULE_DESCRIPTION("Tests for the lazy MMU mode");
 MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");


-ritesh


From martin.blumenstingl at googlemail.com  Wed Dec 17 07:51:07 2025
From: martin.blumenstingl at googlemail.com (Martin Blumenstingl)
Date: Wed, 17 Dec 2025 16:51:07 +0100
Subject: [PATCH 2/4] arm64: dts: amlogic: Add S6 Reset Controller
In-Reply-To: <20251127-reset-s6-s7-s7d-v1-2-879099ad90d3@amlogic.com>
References: <20251127-reset-s6-s7-s7d-v1-0-879099ad90d3@amlogic.com> <20251127-reset-s6-s7-s7d-v1-2-879099ad90d3@amlogic.com>
Message-ID: <CAFBinCA19ws1OmfZLh+OSmiEuvY4owOKyzFpaz5KO6E8HaKmmg@mail.gmail.com>

On Thu, Nov 27, 2025 at 8:30?AM Xianwei Zhao via B4 Relay
<devnull+xianwei.zhao.amlogic.com at kernel.org> wrote:
[...]
> +#define RESET_BRG_MAIL_DMC_PIPEL       167
On the S7 SoC this reset line is called RESET_BRG_MALI_PIPL0:
- is MAIL <> MALI a typo (seems like it should be MALI)?
- and is PIPEL <> PIPL also a typo (I don't know which one is "correct")?


From andrew at lunn.ch  Wed Dec 17 07:52:25 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Wed, 17 Dec 2025 16:52:25 +0100
Subject: [PATCH 1/1] arm64: dts: mba8mx: Fix Ethernet PHY IRQ support
In-Reply-To: <20251216131529.886546-1-alexander.stein@ew.tq-group.com>
References: <20251216131529.886546-1-alexander.stein@ew.tq-group.com>
Message-ID: <a450fb06-78b3-45eb-bb21-bdd4eeb39ea6@lunn.ch>

On Tue, Dec 16, 2025 at 02:15:28PM +0100, Alexander Stein wrote:
> Ethernet PHY interrupt mode is level triggered. Adjust the mode
> accordingly.
> 
> Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>

Reviewed-by: Andrew Lunn <andrew at lunn.ch>

    Andrew


From joey.gouly at arm.com  Wed Dec 17 07:54:29 2025
From: joey.gouly at arm.com (Joey Gouly)
Date: Wed, 17 Dec 2025 15:54:29 +0000
Subject: [PATCH 17/32] KVM: arm64: gic-v5: Implement PPI interrupt
 injection
In-Reply-To: <20251212152215.675767-18-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
 <20251212152215.675767-18-sascha.bischoff@arm.com>
Message-ID: <20251217155429.GA1649600@e124191.cambridge.arm.com>

Hi Sascha,

small comment,

On Fri, Dec 12, 2025 at 03:22:41PM +0000, Sascha Bischoff wrote:
> This change introduces interrupt injection for PPIs for GICv5-based
> guests.
> 
> The lifecycle of PPIs is largely managed by the hardware for a GICv5
> system. The hypervisor injects pending state into the guest by using
> the ICH_PPI_PENDRx_EL2 registers. These are used by the hardware to
> pick a Highest Priority Pending Interrupt (HPPI) for the guest based
> on the enable state of each individual interrupt. The enable state and
> priority for each interrupt are provided by the guest itself (through
> writes to the PPI registers).
> 
> When Direct Virtual Interrupt (DVI) is set for a particular PPI, the
> hypervisor is even able to skip the injection of the pending state
> altogether - it all happens in hardware.
> 
> The result of the above is that no AP lists are required for GICv5,
> unlike for older GICs. Instead, for PPIs the ICH_PPI_* registers
> fulfil the same purpose for all 128 PPIs. Hence, as long as the
> ICH_PPI_* registers are populated prior to guest entry, and merged
> back into the KVM shadow state on exit, the PPI state is preserved,
> and interrupts can be injected.
> 
> When injecting the state of a PPI the state is merged into the KVM's
> shadow state using the set_pending_state irq_op. The directly sets the
> relevant bit in the shadow ICH_PPI_PENDRx_EL2, which is presented to
> the guest (and GICv5 hardware) on next guest entry. The
> queue_irq_unlock irq_op is required to kick the vCPU to ensure that it
> seems the new state. The result is that no AP lists are used for
> private interrupts on GICv5.
> 
> Prior to entering the guest, vgic_v5_flush_ppi_state is called from
> kvm_vgic_flush_hwstate. The effectively snapshots the shadow PPI
> pending state (twice - an entry and an exit copy) in order to track
> any changes. These changes can come from a guest consuming an
> interrupt or from a guest making an Edge-triggered interrupt pending.
> 
> When returning from running a guest, the guest's PPI state is merged
> back into KVM's shadow state in vgic_v5_merge_ppi_state from
> kvm_vgic_sync_hwstate. The Enable and Active state is synced back for
> all PPIs, and the pending state is synced back for Edge PPIs (Level is
> driven directly by the devices generating said levels). The incoming
> pending state from the guest is merged with KVM's shadow state to
> avoid losing any incoming interrupts.
> 
> Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
> ---
>  arch/arm64/kvm/vgic/vgic-v5.c | 157 ++++++++++++++++++++++++++++++++++
>  arch/arm64/kvm/vgic/vgic.c    |  35 ++++++--
>  arch/arm64/kvm/vgic/vgic.h    |  49 ++++++++---
>  include/kvm/arm_vgic.h        |   3 +
>  4 files changed, 226 insertions(+), 18 deletions(-)
> 
> diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
> index 22558080711eb..d54595fbf4586 100644
> --- a/arch/arm64/kvm/vgic/vgic-v5.c
> +++ b/arch/arm64/kvm/vgic/vgic-v5.c
> @@ -54,6 +54,163 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
>  	return 0;
>  }
>  
> +static bool vgic_v5_ppi_set_pending_state(struct kvm_vcpu *vcpu,
> +					  struct vgic_irq *irq)
> +{
> +	struct vgic_v5_cpu_if *cpu_if;
> +	const u32 id_bit = BIT_ULL(irq->intid % 64);
> +	const u32 reg = FIELD_GET(GICV5_HWIRQ_ID, irq->intid) / 64;
> +
> +	if (!vcpu || !irq)
> +		return false;
> +
> +	/* Skip injecting the state altogether */
> +	if (irq->directly_injected)
> +		return true;
> +
> +	cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> +
> +	if (irq_is_pending(irq))
> +		cpu_if->vgic_ppi_pendr[reg] |= id_bit;
> +	else
> +		cpu_if->vgic_ppi_pendr[reg] &= ~id_bit;
> +
> +	return true;
> +}
> +
> +/*
> + * For GICv5, the PPIs are mostly directly managed by the hardware. We
> + * (the hypervisor) handle the pending, active, enable state
> + * save/restore, but don't need the PPIs to be queued on a per-VCPU AP
> + * list. Therefore, sanity check the state, unlock, and return.
> + */
> +static bool vgic_v5_ppi_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq,
> +					 unsigned long flags)
> +	__releases(&irq->irq_lock)
> +{
> +	struct kvm_vcpu *vcpu;
> +
> +	lockdep_assert_held(&irq->irq_lock);
> +
> +	if (WARN_ON_ONCE(!irq_is_ppi_v5(irq->intid)))
> +		return false;
> +
> +	vcpu = irq->target_vcpu;
> +	if (WARN_ON_ONCE(!vcpu))
> +		return false;
> +
> +	raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
> +
> +	/* Directly kick the target VCPU to make sure it sees the IRQ */
> +	kvm_make_request(KVM_REQ_IRQ_PENDING, vcpu);
> +	kvm_vcpu_kick(vcpu);
> +
> +	return true;
> +}
> +
> +static struct irq_ops vgic_v5_ppi_irq_ops = {
> +	.set_pending_state = vgic_v5_ppi_set_pending_state,
> +	.queue_irq_unlock = vgic_v5_ppi_queue_irq_unlock,
> +};
> +
> +void vgic_v5_set_ppi_ops(struct vgic_irq *irq)
> +{
> +	if (WARN_ON(!irq) || WARN_ON(irq->ops))
> +		return;
> +
> +	irq->ops = &vgic_v5_ppi_irq_ops;
> +}
> +
> +/*
> + * Detect any PPIs state changes, and propagate the state with KVM's
> + * shadow structures.
> + */
> +static void vgic_v5_merge_ppi_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> +	unsigned long flags;
> +	int i, reg;
> +
> +	for (reg = 0; reg < 2; reg++) {
> +		unsigned long changed_bits;
> +		const unsigned long enabler = cpu_if->vgic_ich_ppi_enabler_exit[reg];
> +		const unsigned long activer = cpu_if->vgic_ppi_activer_exit[reg];
> +		const unsigned long pendr = cpu_if->vgic_ppi_pendr_exit[reg];
> +
> +		/*
> +		 * Track what changed across enabler, activer, pendr, but mask
> +		 * with ~DVI.
> +		 */
> +		changed_bits = cpu_if->vgic_ich_ppi_enabler_entry[reg] ^ enabler;
> +		changed_bits |= cpu_if->vgic_ppi_activer_entry[reg] ^ activer;
> +		changed_bits |= cpu_if->vgic_ppi_pendr_entry[reg] ^ pendr;
> +		changed_bits &= ~cpu_if->vgic_ppi_dvir[reg];
> +
> +		for_each_set_bit(i, &changed_bits, 64) {
> +			struct vgic_irq *irq;
> +			u32 intid;
> +
> +			intid = FIELD_PREP(GICV5_HWIRQ_TYPE, GICV5_HWIRQ_TYPE_PPI);
> +			intid |= FIELD_PREP(GICV5_HWIRQ_ID, reg * 64 + i);
> +
> +			irq = vgic_get_vcpu_irq(vcpu, intid);
> +
> +			raw_spin_lock_irqsave(&irq->irq_lock, flags);
> +			irq->enabled = !!(enabler & BIT(i));
> +			irq->active = !!(activer & BIT(i));
> +			/* This is an OR to avoid losing incoming edges! */
> +			if (irq->config == VGIC_CONFIG_EDGE)
> +				irq->pending_latch |= !!(pendr & BIT(i));
> +			raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
> +
> +			vgic_put_irq(vcpu->kvm, irq);
> +		}
> +
> +		/* Re-inject the exit state as entry state next time! */
> +		cpu_if->vgic_ich_ppi_enabler_entry[reg] = enabler;
> +		cpu_if->vgic_ppi_activer_entry[reg] = activer;
> +
> +		/*
> +		 * Pending state is a bit different. We only propagate back
> +		 * pending state for Edge interrupts. Moreover, this is OR'd
> +		 * with the incoming state to make sure we don't lose incoming
> +		 * edges. Use the (inverse) HMR to mask off all Level bits, and
> +		 * OR.
> +		 */
> +		cpu_if->vgic_ppi_pendr[reg] |= pendr & ~cpu_if->vgic_ppi_hmr[reg];
> +	}
> +}
> +
> +void vgic_v5_flush_ppi_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> +
> +	/*
> +	 * We're about to enter the guest. Copy the shadow state to the pending
> +	 * reg that will be written to the ICH_PPI_PENDRx_EL2 regs. While the
> +	 * guest is running we track any incoming changes to the pending state in
> +	 * vgic_ppi_pendr. The incoming changes are merged with the outgoing
> +	 * changes on the return path.
> +	 */
> +	cpu_if->vgic_ppi_pendr_entry[0] = cpu_if->vgic_ppi_pendr[0];
> +	cpu_if->vgic_ppi_pendr_entry[1] = cpu_if->vgic_ppi_pendr[1];
> +
> +	/*
> +	 * Make sure that we can correctly detect "edges" in the PPI
> +	 * state. There's a path where we never actually enter the guest, and
> +	 * failure to do this risks losing pending state
> +	 */
> +	cpu_if->vgic_ppi_pendr_exit[0] = cpu_if->vgic_ppi_pendr[0];
> +	cpu_if->vgic_ppi_pendr_exit[1] = cpu_if->vgic_ppi_pendr[1];
> +
> +}
> +
> +void vgic_v5_fold_irq_state(struct kvm_vcpu *vcpu)
> +{
> +	/* Sync back the guest PPI state to the KVM shadow state */
> +	vgic_v5_merge_ppi_state(vcpu);
> +}
> +
>  /*
>   * Sets/clears the corresponding bit in the ICH_PPI_DVIR register.
>   */
> diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
> index fc01c6d07fe62..e534876656ca7 100644
> --- a/arch/arm64/kvm/vgic/vgic.c
> +++ b/arch/arm64/kvm/vgic/vgic.c
> @@ -105,6 +105,15 @@ struct vgic_irq *vgic_get_vcpu_irq(struct kvm_vcpu *vcpu, u32 intid)
>  	if (WARN_ON(!vcpu))
>  		return NULL;
>  
> +	if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5) {
> +		u32 int_num = FIELD_GET(GICV5_HWIRQ_ID, intid);
> +
> +		if (irq_is_ppi_v5(intid)) {
> +			int_num = array_index_nospec(int_num, VGIC_V5_NR_PRIVATE_IRQS);
> +			return &vcpu->arch.vgic_cpu.private_irqs[int_num];
> +		}
> +	}
> +

Should the code below this be in an else {}? I don't think it will ever be true
for gic v5 since 0 is invalid for GICV5_HWIRQ_TYPE (so some high bit 29:31 will
be set), but it might be clearer?

Thanks,
Joey

>  	/* SGIs and PPIs */
>  	if (intid < VGIC_NR_PRIVATE_IRQS) {
>  		intid = array_index_nospec(intid, VGIC_NR_PRIVATE_IRQS);
> @@ -258,10 +267,12 @@ struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
>  	 * If the distributor is disabled, pending interrupts shouldn't be
>  	 * forwarded.
>  	 */
> -	if (irq->enabled && irq_is_pending(irq)) {
> -		if (unlikely(irq->target_vcpu &&
> -			     !irq->target_vcpu->kvm->arch.vgic.enabled))
> -			return NULL;
> +	if (irq_is_enabled(irq) && irq_is_pending(irq)) {
> +		if (irq->target_vcpu) {
> +			if (!vgic_is_v5(irq->target_vcpu->kvm) &&
> +			    unlikely(!irq->target_vcpu->kvm->arch.vgic.enabled))
> +				return NULL;
> +		}
>  
>  		return irq->target_vcpu;
>  	}
> @@ -1044,7 +1055,11 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
>  	if (can_access_vgic_from_kernel())
>  		vgic_save_state(vcpu);
>  
> -	vgic_fold_lr_state(vcpu);
> +	if (!vgic_is_v5(vcpu->kvm))
> +		vgic_fold_lr_state(vcpu);
> +	else
> +		vgic_v5_fold_irq_state(vcpu);
> +
>  	vgic_prune_ap_list(vcpu);
>  }
>  
> @@ -1105,13 +1120,17 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
>  
>  	DEBUG_SPINLOCK_BUG_ON(!irqs_disabled());
>  
> -	scoped_guard(raw_spinlock, &vcpu->arch.vgic_cpu.ap_list_lock)
> -		vgic_flush_lr_state(vcpu);
> +	if (!vgic_is_v5(vcpu->kvm)) {
> +		scoped_guard(raw_spinlock, &vcpu->arch.vgic_cpu.ap_list_lock)
> +			vgic_flush_lr_state(vcpu);
> +	} else {
> +		vgic_v5_flush_ppi_state(vcpu);
> +	}
>  
>  	if (can_access_vgic_from_kernel())
>  		vgic_restore_state(vcpu);
>  
> -	if (vgic_supports_direct_irqs(vcpu->kvm))
> +	if (vgic_supports_direct_irqs(vcpu->kvm) && !vgic_is_v5(vcpu->kvm))
>  		vgic_v4_commit(vcpu);
>  }
>  
> diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
> index b6e3f5e3aba18..5a77318ddb87a 100644
> --- a/arch/arm64/kvm/vgic/vgic.h
> +++ b/arch/arm64/kvm/vgic/vgic.h
> @@ -132,6 +132,28 @@ static inline bool irq_is_pending(struct vgic_irq *irq)
>  		return irq->pending_latch || irq->line_level;
>  }
>  
> +/* Requires the irq_lock to be held by the caller. */
> +static inline bool irq_is_enabled(struct vgic_irq *irq)
> +{
> +	if (irq->enabled)
> +		return true;
> +
> +	/*
> +	 * We always consider GICv5 interrupts as enabled as we can
> +	 * always inject them. The state is handled by the hardware,
> +	 * and the hardware will only signal the interrupt to the
> +	 * guest once the guest enables it.
> +	 */
> +	if (irq->target_vcpu) {
> +		u32 vgic_model = irq->target_vcpu->kvm->arch.vgic.vgic_model;
> +
> +		if (vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5)
> +			return true;
> +	}
> +
> +	return false;
> +}
> +
>  static inline bool vgic_irq_is_mapped_level(struct vgic_irq *irq)
>  {
>  	return irq->config == VGIC_CONFIG_LEVEL && irq->hw;
> @@ -306,7 +328,7 @@ static inline bool vgic_try_get_irq_ref(struct vgic_irq *irq)
>  	if (!irq)
>  		return false;
>  
> -	if (irq->intid < VGIC_MIN_LPI)
> +	if (irq->target_vcpu && !irq_is_lpi(irq->target_vcpu->kvm, irq->intid))
>  		return true;
>  
>  	return refcount_inc_not_zero(&irq->refcount);
> @@ -363,7 +385,10 @@ void vgic_debug_init(struct kvm *kvm);
>  void vgic_debug_destroy(struct kvm *kvm);
>  
>  int vgic_v5_probe(const struct gic_kvm_info *info);
> +void vgic_v5_set_ppi_ops(struct vgic_irq *irq);
>  int vgic_v5_set_ppi_dvi(struct kvm_vcpu *vcpu, u32 irq, bool dvi);
> +void vgic_v5_flush_ppi_state(struct kvm_vcpu *vcpu);
> +void vgic_v5_fold_irq_state(struct kvm_vcpu *vcpu);
>  void vgic_v5_load(struct kvm_vcpu *vcpu);
>  void vgic_v5_put(struct kvm_vcpu *vcpu);
>  void vgic_v5_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
> @@ -432,15 +457,6 @@ void vgic_its_invalidate_all_caches(struct kvm *kvm);
>  int vgic_its_inv_lpi(struct kvm *kvm, struct vgic_irq *irq);
>  int vgic_its_invall(struct kvm_vcpu *vcpu);
>  
> -bool system_supports_direct_sgis(void);
> -bool vgic_supports_direct_msis(struct kvm *kvm);
> -bool vgic_supports_direct_sgis(struct kvm *kvm);
> -
> -static inline bool vgic_supports_direct_irqs(struct kvm *kvm)
> -{
> -	return vgic_supports_direct_msis(kvm) || vgic_supports_direct_sgis(kvm);
> -}
> -
>  int vgic_v4_init(struct kvm *kvm);
>  void vgic_v4_teardown(struct kvm *kvm);
>  void vgic_v4_configure_vsgis(struct kvm *kvm);
> @@ -485,6 +501,19 @@ static inline bool vgic_is_v5(struct kvm *kvm)
>  	return kvm_vgic_global_state.type == VGIC_V5 && !vgic_is_v3_compat(kvm);
>  }
>  
> +bool system_supports_direct_sgis(void);
> +bool vgic_supports_direct_msis(struct kvm *kvm);
> +bool vgic_supports_direct_sgis(struct kvm *kvm);
> +
> +static inline bool vgic_supports_direct_irqs(struct kvm *kvm)
> +{
> +	/* GICv5 always supports direct IRQs */
> +	if (vgic_is_v5(kvm))
> +		return true;
> +
> +	return vgic_supports_direct_msis(kvm) || vgic_supports_direct_sgis(kvm);
> +}
> +
>  int vgic_its_debug_init(struct kvm_device *dev);
>  void vgic_its_debug_destroy(struct kvm_device *dev);
>  
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 20c908730fa00..5a46fe3c35b5c 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -32,6 +32,9 @@
>  #define VGIC_MIN_LPI		8192
>  #define KVM_IRQCHIP_NUM_PINS	(1020 - 32)
>  
> +/* GICv5 constants */
> +#define VGIC_V5_NR_PRIVATE_IRQS	128
> +
>  #define irq_is_ppi_legacy(irq) ((irq) >= VGIC_NR_SGIS && (irq) < VGIC_NR_PRIVATE_IRQS)
>  #define irq_is_spi_legacy(irq) ((irq) >= VGIC_NR_PRIVATE_IRQS && \
>  					(irq) <= VGIC_MAX_SPI)
> -- 
> 2.34.1


From arnd at arndb.de  Wed Dec 17 08:04:05 2025
From: arnd at arndb.de (Arnd Bergmann)
Date: Wed, 17 Dec 2025 17:04:05 +0100
Subject: [PATCH] ARM: dts: intel: Drop pxa2xx
In-Reply-To: <m2345fmkg7.fsf@free.fr>
References: <20251212203226.458694-4-robh@kernel.org> <m2345fmkg7.fsf@free.fr>
Message-ID: <35405ed3-1319-4d3a-84a5-ad67f4c823ad@app.fastmail.com>

On Fri, Dec 12, 2025, at 22:58, Robert Jarzmik wrote:
> "Rob Herring (Arm)" <robh at kernel.org> writes:
>
>> These .dtsi files are not included anywhere in the tree and 
>> can't be tested. They have not been touched since 2018 other than 
>> clean-ups.
>>
> And yet, there are used by people using pxa2xx board with an DT 
> support (like the mioa701 for which a board file was never merged).
>
> If you remove pxa25x.dtsi and pxa27x.dtsi, you might as well 
> remove all support for this architecture from the kernel, as
> these are the building blocks needed to make it work.
>
> That might be what should be done, I'll let Arnd and Daniel 
> comment on the future of PXA in the kernel.

I agree with Rob that at the very minimum, any dtsi files in the
kernel should be build-tested along with the rest, so either
we add some dts files using them soon, or we can remove pxa2xx
(and maybe pxa3xx) completely.

I already plan to remove the remaining board files for both
sa1100 and pxa soon, as nobody has picked up the task to do
any further DT conversion after we removed the majority of
the files back in 2022 and left only the ones that someone
said they'd be interested in keeping.

Robert, let me know if you or someone else is able to spend
some time on sending (warning-free) dts files for pxa2xx
machines soon. If not, I'd plan to remove whatever is there
along with the board files and drivers.

I also checked the pxa3xx Raumfeld devicetree support that
Daniel added in linux-3.7. The manufacturer's firmware
download page contains kernel images based on this work,
using a 4.19 kernel but built in 2022. If we remove pxa2xx
DT support, it would be good to find out if anyone still
plans to use something newer on that hardware, which may
happen because of CRA requirements.

    Arnd


From ryan.roberts at arm.com  Wed Dec 17 08:06:00 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Wed, 17 Dec 2025 16:06:00 +0000
Subject: [PATCH v2 1/3] arm64: mm: support batch clearing of the young
 flag for large folios
In-Reply-To: <16d6642b-6f22-4d7b-94d6-92692b63cbd9@lucifer.local>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <e10f876ce130134fa089befe83f30561b48b9889.1765439380.git.baolin.wang@linux.alibaba.com>
 <5039c6a2-09b6-4c9b-accb-26583ba120db@lucifer.local>
 <1a0001cd-c38d-403b-b3ef-d19e85acd772@linux.alibaba.com>
 <671ac450-4a59-4e26-b098-7cf65add1e75@lucifer.local>
 <37915af9-d307-4955-969e-c16ea26f7f4a@linux.alibaba.com>
 <16d6642b-6f22-4d7b-94d6-92692b63cbd9@lucifer.local>
Message-ID: <fac9dd13-0c1b-40de-a5ac-d2c4c2012385@arm.com>

On 17/12/2025 14:50, Lorenzo Stoakes wrote:
> On Wed, Dec 17, 2025 at 11:53:31AM +0800, Baolin Wang wrote:
>>
>>
>> On 2025/12/16 19:11, Lorenzo Stoakes wrote:
>>> On Tue, Dec 16, 2025 at 11:32:58AM +0800, Baolin Wang wrote:
>>>>
>>>>
>>>> On 2025/12/15 19:36, Lorenzo Stoakes wrote:
>>>>> On Thu, Dec 11, 2025 at 04:16:54PM +0800, Baolin Wang wrote:
>>>>>> Currently, contpte_ptep_test_and_clear_young() and contpte_ptep_clear_flush_young()
>>>>>> only clear the young flag and flush TLBs for PTEs within the contiguous range.
>>>>>> To support batch PTE operations for other sized large folios in the following
>>>>>> patches, adding a new parameter to specify the number of PTEs.
>>>>>>
>>>>>> While we are at it, rename the functions to maintain consistency with other
>>>>>> contpte_*() functions.
>>>>>>
>>>>>> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
>>>>>> ---
>>>>>>    arch/arm64/include/asm/pgtable.h | 12 ++++-----
>>>>>>    arch/arm64/mm/contpte.c          | 44 ++++++++++++++++++++++----------
>>>>>>    2 files changed, 37 insertions(+), 19 deletions(-)
>>>>>>
>>>>>> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
>>>>>> index 0944e296dd4a..e03034683156 100644
>>>>>> --- a/arch/arm64/include/asm/pgtable.h
>>>>>> +++ b/arch/arm64/include/asm/pgtable.h
>>>>>> @@ -1679,10 +1679,10 @@ extern void contpte_clear_full_ptes(struct mm_struct *mm, unsigned long addr,
>>>>>>    extern pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
>>>>>>    				unsigned long addr, pte_t *ptep,
>>>>>>    				unsigned int nr, int full);
>>>>>> -extern int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
>>>>>> -				unsigned long addr, pte_t *ptep);
>>>>>> -extern int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
>>>>>> -				unsigned long addr, pte_t *ptep);
>>>>>> +extern int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
>>>>>> +				unsigned long addr, pte_t *ptep, unsigned int nr);
>>>>>> +extern int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
>>>>>> +				unsigned long addr, pte_t *ptep, unsigned int nr);
>>>>>
>>>>> In core mm at least, as a convention, we strip 'extern' from header declarations
>>>>> as we go as they're not necessary.
>>>>
>>>> Sure. I can remove the 'extern'.
>>>
>>> Thanks.
>>>
>>>>
>>>>> I wonder about this naming convention also. The contpte_xxx_() prefix
>>>>> obviously implies we are operating upon PTEs in the contiguous range, now
>>>>> we are doing something... different and 'nr' is a bit vague.
>>>>>
>>>>> Is it the nr of contiguous ranges? Well in reality it's nr_pages right? But
>>>>
>>>> Yes, 'nr' here means nr_pages, which follows the convention of the
>>>> parameters in contpte_xxx_() functions.
>>>
>>> Except you're violating the convention already by doing non-contpte stuff in
>>> contpte functions?
>>
>> Nope. Sorry for my poor English, which might have caused some confusion. I
>> followed the contpte's convention, and let me try to explain it again below.
>>
>>> The confusion is between nr of contpte ranges and nr of pages, so I think we
>>> should be explicit.
>>>
>>>>
>>>>> now we're not saying they're necessarily contiguous in the sense of contpte...
>>>>>
>>>>> I wonder whether we'd be better off introducing a new function that
>>>>> explicitly has 'batch' or 'batched' in the name, and have the usual
>>>>> contpte_***() stuff and callers that need batching using a new underlying helper?
>>>>
>>>> OK. I get your point. However, this is outside the scope of my patchset.
>>>
>>> Well, no, this is review feedback that needs to be addressed, I really don't
>>> like this patch as-is.
>>>
>>> So for this to be upstreamable you really need to separate this out.
>>>
>>>>
>>>> Perhaps we can clean up all the contpte_xxx_() functions if everyone agrees
>>>> that this is confusing.
>>>
>>> I mean, unless Ryan explicitly makes a case for this being fine, I'm inclined to
>>> reject the patch unless we do this.
>>>
>>> The contpte logic is already very confusing, and this is only adding to it.
>>>
>>>>
>>>>> Obviously I defer to Ryan on all this, just my thoughts...
>>>>>
>>>>>>    extern void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
>>>>>>    				pte_t *ptep, unsigned int nr);
>>>>>>    extern int contpte_ptep_set_access_flags(struct vm_area_struct *vma,
>>>>>> @@ -1854,7 +1854,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
>>>>>>    	if (likely(!pte_valid_cont(orig_pte)))
>>>>>>    		return __ptep_test_and_clear_young(vma, addr, ptep);
>>>>>>
>>>>>> -	return contpte_ptep_test_and_clear_young(vma, addr, ptep);
>>>>>> +	return contpte_test_and_clear_young_ptes(vma, addr, ptep, CONT_PTES);
>>>>>>    }
>>>>>>
>>>>>>    #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
>>>>>> @@ -1866,7 +1866,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
>>>>>>    	if (likely(!pte_valid_cont(orig_pte)))
>>>>>>    		return __ptep_clear_flush_young(vma, addr, ptep);
>>>>>>
>>>>>> -	return contpte_ptep_clear_flush_young(vma, addr, ptep);
>>>>>> +	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
>>>>>>    }
>>>>>>
>>>>>>    #define wrprotect_ptes wrprotect_ptes
>>>>>> diff --git a/arch/arm64/mm/contpte.c b/arch/arm64/mm/contpte.c
>>>>>> index c0557945939c..19b122441be3 100644
>>>>>> --- a/arch/arm64/mm/contpte.c
>>>>>> +++ b/arch/arm64/mm/contpte.c
>>>>>> @@ -488,8 +488,9 @@ pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
>>>>>>    }
>>>>>>    EXPORT_SYMBOL_GPL(contpte_get_and_clear_full_ptes);
>>>>>>
>>>>>> -int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
>>>>>> -					unsigned long addr, pte_t *ptep)
>>>>>> +int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
>>>>>> +					unsigned long addr, pte_t *ptep,
>>>>>> +					unsigned int nr)
>>>>>>    {
>>>>>>    	/*
>>>>>>    	 * ptep_clear_flush_young() technically requires us to clear the access
>>>>>> @@ -500,39 +501,56 @@ int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
>>>>>>    	 * having to unfold.
>>>>>>    	 */
>>>>>
>>>>> Hmm shouldn't you need to update this comment now 'nr' is a thing? E.g.:
>>>>>
>>>>> "And since we only create a contig range when the range is covered by a single
>>>>> folio, we can get away with clearing young for the whole contig range here, so
>>>>> we avoid having to unfold."
>>>>
>>>> I think the original comments are still clear:
>>>> "
>>>> /*
>>>>   * ptep_clear_flush_young() technically requires us to clear the access
>>>>   * flag for a _single_ pte. However, the core-mm code actually tracks
>>>>   * access/dirty per folio, not per page. And since we only create a
>>>>   * contig range when the range is covered by a single folio, we can get
>>>>   * away with clearing young for the whole contig range here, so we avoid
>>>>   * having to unfold.
>>>>   */
>>>> "
>>>
>>> Except nr means you can span more than a single contig pte range? So this
>>> comment is no longer applicable as-is?
>>
>> The nr means consecutive (present) PTEs that map consecutive pages of the
>> same large folio in a single VMA and a single page table.
>>
>> I think this is a prerequisite. If you think it's necessary to explain it, I
>> can add it to the comments.
>>
>>> You've changed the function, the comment needs to change too.
>>>
>>>>
>>>>> However now you're allowing for large folios that are not contpte?
>>>>>
>>>>> Overall feeling pretty iffy about implementing this this way.
>>>>
>>>> Please see the above comments, which explain why we should do that.
>>>
>>> You haven't explained anything? Maybe I missed it?
>>>
>>> Can you explain clearly what nr might actually be in relation to contpte's? I'm
>>> confused even as to the utility here.
>>>
>>> Is it batched ranges of contptes? But then why are you trying to see if end is a
>>> contpte + expand the range if so?
>>
>> See below.
>>
>>>>>> +	unsigned long start = addr;
>>>>>> +	unsigned long end = start + nr * PAGE_SIZE;
>>>>>
>>>>> So now [addr, addr + nr * PAGE_SIZE) must for sure be within a single PTE
>>>>> table?
>>>>
>>>> Caller has made sure that (see folio_referenced_one()).
>>>
>>> You should comment this somehow, I hate this nested assumptions stuff 'function
>>> X which calls function Y which calls function Z makes sure that parameter A
>>> fulfils requirements B but we don't mention it anywhere'.
>>
>> Sure.
>>
>>>>>>    	int young = 0;
>>>>>>    	int i;
>>>>>>
>>>>>> -	ptep = contpte_align_down(ptep);
>>>>>> -	addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
>>>>>> +	if (pte_cont(__ptep_get(ptep + nr - 1)))
>>>>>> +		end = ALIGN(end, CONT_PTE_SIZE);
>>>>>
>>>>> OK so I guess for PTE_CONT to be set, it must be aligned to CONT_PTE_SIZE,
>>>>> with other PTE entries present there not having PTE_CONT set (Ryan - do
>>>>> correct me if I'm wrong!)
>>>>>
>>>>> I guess then no worry about running off the end of the PTE table here.
>>>>>
>>>>> I wonder about using pte_cont_addr_end() here, but I guess you are not
>>>>> intending to limit to a range here but rather capture the entire contpte
>>>>> range of the end.
>>>>
>>>> Right.
>>>>
>>>>> I don't love that now a function prefixed with contpte_... can have a
>>>>> condition where part of the input range is _not_ a contpte entry, or is
>>>>> specified partially...
>>>>
>>>> Like I said above, this is outside the scope of my patchset. If Ryan also
>>>> thinks we need to do some cleanups for all the contpte_xxx() functions in
>>>> the contpte.c file, we can send a follow-up patchset to rename all the
>>>> contpte_xxx() functions to make it clear.
>>>
>>> It's really not outside of the scope of the patch set, this is review feedback
>>> you have to address :) trying not to be a grumpy kernel dev here :>)
>>>
>>> In general in the kernel we don't accept confusing patches then defer making
>>> them not-confusing until later.
>>>
>>> We review until the series is at the correct standard to be accepted before we
>>> merge.
>>>
>>> As always I'm happy to be convinced that I'm mistaken or something's not
>>> necesary, however!
>>
>> Yes, let me try to explain it again. See below.
>>
>>>>>> -	for (i = 0; i < CONT_PTES; i++, ptep++, addr += PAGE_SIZE)
>>>>>> -		young |= __ptep_test_and_clear_young(vma, addr, ptep);
>>>>>> +	if (pte_cont(__ptep_get(ptep))) {
>>>>>> +		start = ALIGN_DOWN(start, CONT_PTE_SIZE);
>>>>>> +		ptep = contpte_align_down(ptep);
>>>>>> +	}
>>>>>> +
>>>>>> +	nr = (end - start) / PAGE_SIZE;
>>>>>
>>>>> Hm don't love this reuse of input param.
>>>>
>>>> OK. Will use another local variable instead.
>>>
>>> Thanks.
>>>
>>>>
>>>>>
>>>>>> +	for (i = 0; i < nr; i++, ptep++, start += PAGE_SIZE)
>>>>>> +		young |= __ptep_test_and_clear_young(vma, start, ptep);
>>>>>
>>>>> Again, overall find it a bit iffy that we are essentially overloading the
>>>>> code with non-contpte behaviour.
>>>>
>>>> Let me clarify further: this is the handling logic of the contpte_xxx()
>>>> functions in the contpte.c file. For example, the function
>>>> contpte_set_ptes() has a parameter 'nr', which may be greater than
>>>> CONT_PTES, meaning that it can handle multiple CONT_PTES range sizes of a
>>>> large folio.
>>>>
>>>> It might be a bit confusing, and I understand this is why you want to change
>>>> the 'contpte_' prefix to the 'batch_' prefix. Of course, we can hope Ryan
>>>> can provide some input on this.
>>>>
>>>> Thanks for reviewing.
>>>
>>> OK so we have some reeeeal confusion here. And this speaks to the patch needing
>>> work.
>>>
>>> This seems to answer what I asked above - basically - are we doing _batches_ of
>>> _contpte_ entries, or are we just accepting arbitrary large folios here and
>>> batching up operations on them, including non-contpte entries.
>>>
>>> Presumably from the above you're saying - this is dealing with batches of
>>> contpte entries.
>>>
>>> In which case this has to be made _super_ clear. Not just adding an arbitrary
>>> 'nr' parameter and letting people guess.
>>>
>>> The contpte code is _already_ confusing and somewhat surprising if you're not
>>> aware of it, we need to be going in the other direction.
>>
>> Sure. Sorry for causing confusion. I try to explain it again to make it
>> clear.
>>
>> First, it is necessary to explain how the contpte implementation in Arm64 is
>> exposed, using set_ptes() as an example.
>>
>> Arm64 defines an arch-specific implementation of set_ptes():
>> "
>> static __always_inline void set_ptes(struct mm_struct *mm, unsigned long
>> addr,
>> 				pte_t *ptep, pte_t pte, unsigned int nr)
>> {
>> 	pte = pte_mknoncont(pte);
>>
>> 	if (likely(nr == 1)) {
>> 		contpte_try_unfold(mm, addr, ptep, __ptep_get(ptep));
>> 		__set_ptes(mm, addr, ptep, pte, 1);
>> 		contpte_try_fold(mm, addr, ptep, pte);
>> 	} else {
>> 		contpte_set_ptes(mm, addr, ptep, pte, nr);
>> 	}
>> }
>> "
>>
>> Here, 'nr' refers to consecutive (present) PTEs that map consecutive pages
>> of the same large folio within a single VMA and a single page table. Based
>> on 'nr', it determines whether the PTE_CONT attribute should be set or not.
>>
>> Second, the underlying implementation of contpte_set_ptes() also calculates
>> 'end' based on 'nr' and checks whether the PTE_CONT attribute should be set.
>> For example:
>>
>> For a large folio with order = 3 (nr = 8), the PTE_CONT attribute will not
>> be set since the 'next' is not aligned with CONT_PTE_MASK.
>>
>> For a large folio with order = 4 (nr = 16), it aligns perfectly, allowing
>> the PTE_CONT attribute to be set for the entire PTE entries of the large
>> folio.
>>
>> For a large folio with order = 5 (nr = 32), this involves two ranges of
>> CONT_PTE_SIZE (16 PTEs in each range), requiring the PTE_CONT attribute to
>> be set separately for each range.
>>
>> "
>> void contpte_set_ptes(struct mm_struct *mm, unsigned long addr,
>> 					pte_t *ptep, pte_t pte, unsigned int nr)
>> {
>> 	.......
>>
>> 	end = addr + (nr << PAGE_SHIFT);
>> 	pfn = pte_pfn(pte);
>> 	prot = pte_pgprot(pte);
>>
>> 	do {
>> 		next = pte_cont_addr_end(addr, end);
>> 		nr = (next - addr) >> PAGE_SHIFT;
>> 		pte = pfn_pte(pfn, prot);
>>
>> 		if (((addr | next | (pfn << PAGE_SHIFT)) & ~CONT_PTE_MASK) == 0)
>> 			pte = pte_mkcont(pte);
>> 		else
>> 			pte = pte_mknoncont(pte);
>>
>> 		__set_ptes(mm, addr, ptep, pte, nr);
>>
>> 		addr = next;
>> 		ptep += nr;
>> 		pfn += nr;
>>
>> 	} while (addr != end);
>> }
>> "
>>
>> Third, regarding the implementation of my patch, I have followed the contpte
>> logic here by adding the 'nr' parameter to
>> contpte_ptep_test_and_clear_young() for batch processing consecutive
>> (present) PTEs. Moreover, the semantics of 'nr' remain consistent with the
>> original contpte functions, and I have not broken the existing contpte
>> implementation logic.
> 
> OK that helps a lot thanks.
> 
> So the nr will be number of PTEs that are consecutive, belong to the same folio,
> and have the same PTE bit set excluding accessed, writable, dirty, soft-dirty.

I'm not sure test_and_clear_young_ptes() would technically require all of these
constraints. I think it would be sufficient to just ensure that all the PTEs in
the batch are pte_present(). And I assume the return value is intended to
indicate if *any* of the PTEs in the batch were previously young?

The usual order for adding new batched PTE helpers is to define the generic
function along with it's spec in a comment block and provide a default
implementation that is implemented as a loop around the existing non-batched
version of the interface. Then you can convert the core-mm to use that API. And
finally you can opt arm64 into overriding the API with a more efficient
implementation.

If you were to do it in that order, it tells a better story and is easier to
follow, I think.

> 
> But since we are retrieving accessed bit state (young), isn't it a problem we're
> ignoring this bit when considering what goes into the batch?
> 
> I mean now it's going to return true even if some do not have the accessed flag
> set?

test_and_clear_young_ptes() is exploiting the fact that the kernel tracks young
(and dirty) per *folio*. So having a young and dirty bit per PTE is providing
more information than the kernel needs if a large folio is mapped across
multiple PTEs. Which is why returning the logical OR of the access bits is ok here.

> 
> I am more convinced things are correct in style at least then this way as, as
> you say, this is the approach taken in set_ptes().

I'm personally ok with the style and I believe the implementation is correct.
But it would help to reformulate the series in the order I suggest above since
then we can review against the spec of what the core-mm helper is supposed to do.

Thanks,
Ryan

> 
> Thanks, Lorenzo



From kevin.brodsky at arm.com  Wed Dec 17 08:10:40 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Wed, 17 Dec 2025 17:10:40 +0100
Subject: [PATCH v6 14/14] mm: Add basic tests for lazy_mmu
In-Reply-To: <87a4zhkt6h.ritesh.list@gmail.com>
References: <20251215150323.2218608-1-kevin.brodsky@arm.com>
 <20251215150323.2218608-15-kevin.brodsky@arm.com>
 <20251216201403.4647a4f9861d3122ee9e90d7@linux-foundation.org>
 <f9550d22-8810-4145-aaa8-48961f6ea35e@arm.com>
 <ca0da7fd-245c-4d52-8f4d-f8fce4717494@arm.com>
 <87a4zhkt6h.ritesh.list@gmail.com>
Message-ID: <799bdcb5-cb18-4b7a-b33f-bea1553f3650@arm.com>

On 17/12/2025 16:46, Ritesh Harjani (IBM) wrote:
> Ryan Roberts <ryan.roberts at arm.com> writes:
>
>> On 17/12/2025 09:26, Kevin Brodsky wrote:
>>> On 17/12/2025 05:14, Andrew Morton wrote:
>>>> On Mon, 15 Dec 2025 15:03:23 +0000 Kevin Brodsky <kevin.brodsky at arm.com> wrote:
>>>>
>>>>> Add basic KUnit tests for the generic aspects of the lazy MMU mode:
>>>>> ensure that it appears active when it should, depending on how
>>>>> enable/disable and pause/resume pairs are nested.
>>>> I needed this for powerpc allmodconfig;
>>>>
>>>> --- a/arch/powerpc/mm/book3s64/hash_tlb.c~mm-add-basic-tests-for-lazy_mmu-fix
>>>> +++ a/arch/powerpc/mm/book3s64/hash_tlb.c
>>>> @@ -30,6 +30,7 @@
>>>>  #include <trace/events/thp.h>
>>>>  
>>>>  DEFINE_PER_CPU(struct ppc64_tlb_batch, ppc64_tlb_batch);
>>>> +EXPORT_SYMBOL_GPL(ppc64_tlb_batch);
>>>>  
>>>>  /*
>>>>   * A linux PTE was changed and the corresponding hash table entry
>>>> @@ -154,6 +155,7 @@ void __flush_tlb_pending(struct ppc64_tl
>>>>  		flush_hash_range(i, local);
>>>>  	batch->index = 0;
>>>>  }
>>>> +EXPORT_SYMBOL_GPL(__flush_tlb_pending);
>>>>  
>>>>  void hash__tlb_flush(struct mmu_gather *tlb)
>>>>  {
>>>> _
>>> Oh indeed I hadn't considered that arch_{enter,leave}_lazy_mmu_mode()
>>> refer to those symbols on powerpc... Maybe a bit overkill to export
>>> those just for a test module, but I'm not sure there's a good
>>> alternative. Forcing LAZY_MMU_MODE_KUNIT_TEST=y is ugly as it would also
>>> force KUNIT=y. Alternatively we could depend on !PPC, not pretty either.
>> Does EXPORT_SYMBOL_IF_KUNIT() help?
>>
> yes, that make sense. Thanks for the suggestion!
> I guess we will need a diff like this in that case -
>
>
> diff --git a/arch/powerpc/mm/book3s64/hash_tlb.c b/arch/powerpc/mm/book3s64/hash_tlb.c
> index fbdeb8981ae7..ec2941cec815 100644
> --- a/arch/powerpc/mm/book3s64/hash_tlb.c
> +++ b/arch/powerpc/mm/book3s64/hash_tlb.c
> @@ -25,11 +25,12 @@
>  #include <asm/tlb.h>
>  #include <asm/bug.h>
>  #include <asm/pte-walk.h>
> -
> +#include <kunit/visibility.h>
>  
>  #include <trace/events/thp.h>
>  
>  DEFINE_PER_CPU(struct ppc64_tlb_batch, ppc64_tlb_batch);
> +EXPORT_SYMBOL_IF_KUNIT(ppc64_tlb_batch);
>  
>  /*
>   * A linux PTE was changed and the corresponding hash table entry
> @@ -154,6 +155,7 @@ void __flush_tlb_pending(struct ppc64_tlb_batch *batch)
>                 flush_hash_range(i, local);
>         batch->index = 0;
>  }
> +EXPORT_SYMBOL_IF_KUNIT(__flush_tlb_pending);
>  
>  void hash__tlb_flush(struct mmu_gather *tlb)
>  {
> diff --git a/mm/tests/lazy_mmu_mode_kunit.c b/mm/tests/lazy_mmu_mode_kunit.c
> index 2720eb995714..340d7cda9096 100644
> --- a/mm/tests/lazy_mmu_mode_kunit.c
> +++ b/mm/tests/lazy_mmu_mode_kunit.c
> @@ -69,3 +69,4 @@ kunit_test_suite(lazy_mmu_mode_test_suite);
>  
>  MODULE_DESCRIPTION("Tests for the lazy MMU mode");
>  MODULE_LICENSE("GPL");
> +MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");

Indeed, that's pretty much what I was about to send :)

- Kevin


From towinchenmi at gmail.com  Wed Dec 17 08:23:13 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Thu, 18 Dec 2025 00:23:13 +0800
Subject: [PATCH v9 00/21] drivers/perf: apple_m1: Add Apple A7-A11, T2 SoC
 support
Message-ID: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>

This series adds support for the CPU PMU in the older Apple A7-A11, T2
SoCs. These PMUs may have a different event layout, less counters, or
deliver their interrupts via IRQ instead of a FIQ. Since some of those
older SoCs support 32-bit EL0, counting for 32-bit EL0 also need to
be enabled by the driver where applicable.

Patch 1 adds the DT bindings.
Patch 2-7 prepares the driver to allow adding support for those
older SoCs.
Patch 8-12 adds support for the older SoCs.
Patch 13-21 are the DT changes.

Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
Changes in v9:
- Rebased on top of v6.19-rc1
- Removed non-existent "INST_A32" and "INST_T32" events from Apple A11
- Added "INST_A32" and "INST_T32" event affinities for A9 and A10
- Link to v8: https://lore.kernel.org/r/20250811-apple-cpmu-v8-0-c560ebd9ca46 at gmail.com

Changes in v8:
- Rebased on top of v6.17-rc1
- Collect Ivaylo's Tested-by
- Drop #define PMCR1_COUNT_A64_EL3_0_7
- Reword reason to not initialize PMUv3 remap in EL1
- Link to v7: https://lore.kernel.org/r/20250510-apple-cpmu-v7-0-bd505cb6c520 at gmail.com

Changes in v7:
- Fix a W=1 compile warning in apple_pmu_get_event_idx() as appearently using GENMASK()
in a function prototype causes a warning in GCC.
- Link to v6: https://lore.kernel.org/r/20250407-apple-cpmu-v6-0-ae8c2f225c1f at gmail.com

Changes in v6:
- Rebased on top of v6.15-rc1 (Conflict with FEAT_PMUv3 support for KVM on Apple Hardware)
- Add patch to skip initialization of PMUv3 remap in EL1 even though not strictly needed
- Include DT patches
- Link to v5: https://lore.kernel.org/r/20250228-apple-cpmu-v5-0-9e124cd28ed4 at gmail.com

Changes in v5:
- Slightly change "drivers/perf: apple_m1: Add Apple A11 Support", to keep things in
chronological order.
- Link to v4: https://lore.kernel.org/r/20250214-apple-cpmu-v4-0-ffca0e45147e at gmail.com

Changes in v4:
- Support per-implementation event attr group
- Fix Apple A7 event attr groups
- Link to v3: https://lore.kernel.org/r/20250213-apple-cpmu-v3-0-be7f8aded81f at gmail.com

Changes in v3:
- Configure PMC8 and PMC9 for 32-bit EL0
- Remove redundant _common suffix from shared functions
- Link to v2: https://lore.kernel.org/r/20250213-apple-cpmu-v2-0-87b361932e88 at gmail.com

Changes in v2:
- Remove unused flags parameter from apple_pmu_init_common()
- Link to v1: https://lore.kernel.org/r/20250212-apple-cpmu-v1-0-f8c7f2ac1743 at gmail.com

---
Nick Chan (21):
      dt-bindings: arm: pmu: Add Apple A7-A11 SoC CPU PMU compatibles
      drivers/perf: apple_m1: Only init PMUv3 remap when EL2 is available
      drivers/perf: apple_m1: Support per-implementation event tables
      drivers/perf: apple_m1: Support a per-implementation number of counters
      drivers/perf: apple_m1: Support configuring counters for 32-bit EL0
      drivers/perf: apple_m1: Support per-implementation PMU startup
      drivers/perf: apple_m1: Support per-implementation event attr group
      drivers/perf: apple_m1: Add Apple A7 support
      drivers/perf: apple_m1: Add Apple A8/A8X support
      drivers/perf: apple_m1: Add A9/A9X support
      drivers/perf: apple_m1: Add Apple A10/A10X/T2 Support
      drivers/perf: apple_m1: Add Apple A11 Support
      arm64: dts: apple: s5l8960x: Add CPU PMU nodes
      arm64: dts: apple: t7000: Add CPU PMU nodes
      arm64: dts: apple: t7001: Add CPU PMU nodes
      arm64: dts: apple: s800-0-3: Add CPU PMU nodes
      arm64: dts: apple: s8001: Add CPU PMU nodes
      arm64: dts: apple: t8010: Add CPU PMU nodes
      arm64: dts: apple: t8011: Add CPU PMU nodes
      arm64: dts: apple: t8012: Add CPU PMU nodes
      arm64: dts: apple: t8015: Add CPU PMU nodes

 Documentation/devicetree/bindings/arm/pmu.yaml |   6 +
 arch/arm64/boot/dts/apple/s5l8960x.dtsi        |   8 +
 arch/arm64/boot/dts/apple/s800-0-3.dtsi        |   8 +
 arch/arm64/boot/dts/apple/s8001.dtsi           |   8 +
 arch/arm64/boot/dts/apple/t7000.dtsi           |   8 +
 arch/arm64/boot/dts/apple/t7001.dtsi           |   9 +
 arch/arm64/boot/dts/apple/t8010.dtsi           |   8 +
 arch/arm64/boot/dts/apple/t8011.dtsi           |   9 +
 arch/arm64/boot/dts/apple/t8012.dtsi           |   8 +
 arch/arm64/boot/dts/apple/t8015.dtsi           |  24 +
 arch/arm64/include/asm/apple_m1_pmu.h          |   2 +
 drivers/perf/apple_m1_cpu_pmu.c                | 813 +++++++++++++++++++++++--
 12 files changed, 876 insertions(+), 35 deletions(-)
---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20250211-apple-cpmu-5a5a3da39483

Best regards,
-- 
Nick Chan <towinchenmi at gmail.com>



From towinchenmi at gmail.com  Wed Dec 17 08:23:14 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Thu, 18 Dec 2025 00:23:14 +0800
Subject: [PATCH v9 01/21] dt-bindings: arm: pmu: Add Apple A7-A11 SoC CPU
 PMU compatibles
In-Reply-To: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
References: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
Message-ID: <20251218-apple-cpmu-v9-1-4deadbe65d03@gmail.com>

Document the compatibles for Apple A7-A11 SoC CPU PMU.

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
 Documentation/devicetree/bindings/arm/pmu.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/pmu.yaml b/Documentation/devicetree/bindings/arm/pmu.yaml
index f47baaefcdacfd37472926ec6994c33603163a44..97800a991f208448aa4bc8dd59b45df2ff35b400 100644
--- a/Documentation/devicetree/bindings/arm/pmu.yaml
+++ b/Documentation/devicetree/bindings/arm/pmu.yaml
@@ -22,8 +22,14 @@ properties:
           - apm,potenza-pmu
           - apple,avalanche-pmu
           - apple,blizzard-pmu
+          - apple,cyclone-pmu
           - apple,firestorm-pmu
+          - apple,fusion-pmu
           - apple,icestorm-pmu
+          - apple,monsoon-pmu
+          - apple,mistral-pmu
+          - apple,twister-pmu
+          - apple,typhoon-pmu
           - arm,armv8-pmuv3 # Only for s/w models
           - arm,arm1136-pmu
           - arm,arm1176-pmu

-- 
2.52.0



From towinchenmi at gmail.com  Wed Dec 17 08:23:15 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Thu, 18 Dec 2025 00:23:15 +0800
Subject: [PATCH v9 02/21] drivers/perf: apple_m1: Only init PMUv3 remap
 when EL2 is available
In-Reply-To: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
References: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
Message-ID: <20251218-apple-cpmu-v9-2-4deadbe65d03@gmail.com>

The events in the Apple A7 PMU is very different from the ones in M1, and
EL2 is not available on Apple A7. Instead of assigning the wrong PMUv3
remap on A7 or declaring a new PMUv3 remap that would never be used in
practice, skip initializing PMUv3 remap altogther when EL2 is unavailable.

Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
 drivers/perf/apple_m1_cpu_pmu.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/perf/apple_m1_cpu_pmu.c b/drivers/perf/apple_m1_cpu_pmu.c
index 81b6f1a623499566ef04d04075752f34e2cb6a92..f3948528e28e0189efd0f17fde0d808930d936af 100644
--- a/drivers/perf/apple_m1_cpu_pmu.c
+++ b/drivers/perf/apple_m1_cpu_pmu.c
@@ -645,8 +645,10 @@ static int m1_pmu_init(struct arm_pmu *cpu_pmu, u32 flags)
 	cpu_pmu->reset		  = m1_pmu_reset;
 	cpu_pmu->set_event_filter = m1_pmu_set_event_filter;
 
-	cpu_pmu->map_pmuv3_event  = m1_pmu_map_pmuv3_event;
-	m1_pmu_init_pmceid(cpu_pmu);
+	if (is_hyp_mode_available()) {
+		cpu_pmu->map_pmuv3_event  = m1_pmu_map_pmuv3_event;
+		m1_pmu_init_pmceid(cpu_pmu);
+	}
 
 	bitmap_set(cpu_pmu->cntr_mask, 0, M1_PMU_NR_COUNTERS);
 	cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] = &m1_pmu_events_attr_group;

-- 
2.52.0



From towinchenmi at gmail.com  Wed Dec 17 08:23:16 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Thu, 18 Dec 2025 00:23:16 +0800
Subject: [PATCH v9 03/21] drivers/perf: apple_m1: Support
 per-implementation event tables
In-Reply-To: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
References: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
Message-ID: <20251218-apple-cpmu-v9-3-4deadbe65d03@gmail.com>

Use per-implementation event tables to allow supporting implementations
with a different list of events and event affinities.

Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
 drivers/perf/apple_m1_cpu_pmu.c | 65 +++++++++++++++++++++++++----------------
 1 file changed, 40 insertions(+), 25 deletions(-)

diff --git a/drivers/perf/apple_m1_cpu_pmu.c b/drivers/perf/apple_m1_cpu_pmu.c
index f3948528e28e0189efd0f17fde0d808930d936af..b4ab6a3e5df965b7ef450d7e533995f3cc8633fd 100644
--- a/drivers/perf/apple_m1_cpu_pmu.c
+++ b/drivers/perf/apple_m1_cpu_pmu.c
@@ -43,9 +43,6 @@
  * moment, we don't really need to distinguish between the two because we
  * know next to nothing about the events themselves, and we already have
  * per cpu-type PMU abstractions.
- *
- * If we eventually find out that the events are different across
- * implementations, we'll have to introduce per cpu-type tables.
  */
 enum m1_pmu_events {
 	M1_PMU_PERFCTR_RETIRE_UOP				= 0x1,
@@ -493,11 +490,12 @@ static void m1_pmu_write_counter(struct perf_event *event, u64 value)
 	isb();
 }
 
-static int m1_pmu_get_event_idx(struct pmu_hw_events *cpuc,
-				struct perf_event *event)
+static int apple_pmu_get_event_idx(struct pmu_hw_events *cpuc,
+				struct perf_event *event,
+				const u16 event_affinities[])
 {
 	unsigned long evtype = event->hw.config_base & M1_PMU_CFG_EVENT;
-	unsigned long affinity = m1_pmu_event_affinity[evtype];
+	unsigned long affinity = event_affinities[evtype];
 	int idx;
 
 	/*
@@ -516,6 +514,12 @@ static int m1_pmu_get_event_idx(struct pmu_hw_events *cpuc,
 	return -EAGAIN;
 }
 
+static int m1_pmu_get_event_idx(struct pmu_hw_events *cpuc,
+				struct perf_event *event)
+{
+	return apple_pmu_get_event_idx(cpuc, event, m1_pmu_event_affinity);
+}
+
 static void m1_pmu_clear_event_idx(struct pmu_hw_events *cpuc,
 				   struct perf_event *event)
 {
@@ -543,7 +547,8 @@ static void m1_pmu_stop(struct arm_pmu *cpu_pmu)
 	__m1_pmu_set_mode(PMCR0_IMODE_OFF);
 }
 
-static int m1_pmu_map_event(struct perf_event *event)
+static int apple_pmu_map_event_47(struct perf_event *event,
+				  const unsigned int (*perf_map)[])
 {
 	/*
 	 * Although the counters are 48bit wide, bit 47 is what
@@ -551,18 +556,29 @@ static int m1_pmu_map_event(struct perf_event *event)
 	 * being 47bit wide to mimick the behaviour of the ARM PMU.
 	 */
 	event->hw.flags |= ARMPMU_EVT_47BIT;
-	return armpmu_map_event(event, &m1_pmu_perf_map, NULL, M1_PMU_CFG_EVENT);
+	return armpmu_map_event(event, perf_map, NULL, M1_PMU_CFG_EVENT);
 }
 
-static int m2_pmu_map_event(struct perf_event *event)
+static int apple_pmu_map_event_63(struct perf_event *event,
+				  const unsigned int (*perf_map)[])
 {
 	/*
-	 * Same deal as the above, except that M2 has 64bit counters.
+	 * Same deal as the above, except with 64bit counters.
 	 * Which, as far as we're concerned, actually means 63 bits.
 	 * Yes, this is getting awkward.
 	 */
 	event->hw.flags |= ARMPMU_EVT_63BIT;
-	return armpmu_map_event(event, &m1_pmu_perf_map, NULL, M1_PMU_CFG_EVENT);
+	return armpmu_map_event(event, perf_map, NULL, M1_PMU_CFG_EVENT);
+}
+
+static int m1_pmu_map_event(struct perf_event *event)
+{
+	return apple_pmu_map_event_47(event, &m1_pmu_perf_map);
+}
+
+static int m2_pmu_map_event(struct perf_event *event)
+{
+	return apple_pmu_map_event_63(event, &m1_pmu_perf_map);
 }
 
 static int m1_pmu_map_pmuv3_event(unsigned int eventsel)
@@ -623,25 +639,16 @@ static int m1_pmu_set_event_filter(struct hw_perf_event *event,
 	return 0;
 }
 
-static int m1_pmu_init(struct arm_pmu *cpu_pmu, u32 flags)
+static int apple_pmu_init(struct arm_pmu *cpu_pmu)
 {
 	cpu_pmu->handle_irq	  = m1_pmu_handle_irq;
 	cpu_pmu->enable		  = m1_pmu_enable_event;
 	cpu_pmu->disable	  = m1_pmu_disable_event;
 	cpu_pmu->read_counter	  = m1_pmu_read_counter;
 	cpu_pmu->write_counter	  = m1_pmu_write_counter;
-	cpu_pmu->get_event_idx	  = m1_pmu_get_event_idx;
 	cpu_pmu->clear_event_idx  = m1_pmu_clear_event_idx;
 	cpu_pmu->start		  = m1_pmu_start;
 	cpu_pmu->stop		  = m1_pmu_stop;
-
-	if (flags & ARMPMU_EVT_47BIT)
-		cpu_pmu->map_event = m1_pmu_map_event;
-	else if (flags & ARMPMU_EVT_63BIT)
-		cpu_pmu->map_event = m2_pmu_map_event;
-	else
-		return WARN_ON(-EINVAL);
-
 	cpu_pmu->reset		  = m1_pmu_reset;
 	cpu_pmu->set_event_filter = m1_pmu_set_event_filter;
 
@@ -660,25 +667,33 @@ static int m1_pmu_init(struct arm_pmu *cpu_pmu, u32 flags)
 static int m1_pmu_ice_init(struct arm_pmu *cpu_pmu)
 {
 	cpu_pmu->name = "apple_icestorm_pmu";
-	return m1_pmu_init(cpu_pmu, ARMPMU_EVT_47BIT);
+	cpu_pmu->get_event_idx	  = m1_pmu_get_event_idx;
+	cpu_pmu->map_event	  = m1_pmu_map_event;
+	return apple_pmu_init(cpu_pmu);
 }
 
 static int m1_pmu_fire_init(struct arm_pmu *cpu_pmu)
 {
 	cpu_pmu->name = "apple_firestorm_pmu";
-	return m1_pmu_init(cpu_pmu, ARMPMU_EVT_47BIT);
+	cpu_pmu->get_event_idx	  = m1_pmu_get_event_idx;
+	cpu_pmu->map_event	  = m1_pmu_map_event;
+	return apple_pmu_init(cpu_pmu);
 }
 
 static int m2_pmu_avalanche_init(struct arm_pmu *cpu_pmu)
 {
 	cpu_pmu->name = "apple_avalanche_pmu";
-	return m1_pmu_init(cpu_pmu, ARMPMU_EVT_63BIT);
+	cpu_pmu->get_event_idx	  = m1_pmu_get_event_idx;
+	cpu_pmu->map_event	  = m2_pmu_map_event;
+	return apple_pmu_init(cpu_pmu);
 }
 
 static int m2_pmu_blizzard_init(struct arm_pmu *cpu_pmu)
 {
 	cpu_pmu->name = "apple_blizzard_pmu";
-	return m1_pmu_init(cpu_pmu, ARMPMU_EVT_63BIT);
+	cpu_pmu->get_event_idx	  = m1_pmu_get_event_idx;
+	cpu_pmu->map_event	  = m2_pmu_map_event;
+	return apple_pmu_init(cpu_pmu);
 }
 
 static const struct of_device_id m1_pmu_of_device_ids[] = {

-- 
2.52.0



From towinchenmi at gmail.com  Wed Dec 17 08:23:17 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Thu, 18 Dec 2025 00:23:17 +0800
Subject: [PATCH v9 04/21] drivers/perf: apple_m1: Support a
 per-implementation number of counters
In-Reply-To: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
References: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
Message-ID: <20251218-apple-cpmu-v9-4-4deadbe65d03@gmail.com>

Support a per-implementation number of counters to allow adding support
for implementations with less counters.

Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
 drivers/perf/apple_m1_cpu_pmu.c | 31 ++++++++++++++++++++-----------
 1 file changed, 20 insertions(+), 11 deletions(-)

diff --git a/drivers/perf/apple_m1_cpu_pmu.c b/drivers/perf/apple_m1_cpu_pmu.c
index b4ab6a3e5df965b7ef450d7e533995f3cc8633fd..b5fe04ef186f04b4af32524fe433afb79979b791 100644
--- a/drivers/perf/apple_m1_cpu_pmu.c
+++ b/drivers/perf/apple_m1_cpu_pmu.c
@@ -20,6 +20,7 @@
 #include <asm/perf_event.h>
 
 #define M1_PMU_NR_COUNTERS		10
+#define APPLE_PMU_MAX_NR_COUNTERS	10
 
 #define M1_PMU_CFG_EVENT		GENMASK(7, 0)
 
@@ -459,7 +460,7 @@ static irqreturn_t m1_pmu_handle_irq(struct arm_pmu *cpu_pmu)
 
 	regs = get_irq_regs();
 
-	for_each_set_bit(idx, cpu_pmu->cntr_mask, M1_PMU_NR_COUNTERS) {
+	for_each_set_bit(idx, cpu_pmu->cntr_mask, APPLE_PMU_MAX_NR_COUNTERS) {
 		struct perf_event *event = cpuc->events[idx];
 		struct perf_sample_data data;
 
@@ -506,7 +507,7 @@ static int apple_pmu_get_event_idx(struct pmu_hw_events *cpuc,
 	 * counting on the PMU at any given time, and by placing the
 	 * most constraining events first.
 	 */
-	for_each_set_bit(idx, &affinity, M1_PMU_NR_COUNTERS) {
+	for_each_set_bit(idx, &affinity, APPLE_PMU_MAX_NR_COUNTERS) {
 		if (!test_and_set_bit(idx, cpuc->used_mask))
 			return idx;
 	}
@@ -601,13 +602,13 @@ static void m1_pmu_init_pmceid(struct arm_pmu *pmu)
 	}
 }
 
-static void m1_pmu_reset(void *info)
+static void apple_pmu_reset(void *info, u32 counters)
 {
 	int i;
 
 	__m1_pmu_set_mode(PMCR0_IMODE_OFF);
 
-	for (i = 0; i < M1_PMU_NR_COUNTERS; i++) {
+	for (i = 0; i < counters; i++) {
 		m1_pmu_disable_counter(i);
 		m1_pmu_disable_counter_interrupt(i);
 		m1_pmu_write_hw_counter(0, i);
@@ -616,6 +617,11 @@ static void m1_pmu_reset(void *info)
 	isb();
 }
 
+static void m1_pmu_reset(void *info)
+{
+	apple_pmu_reset(info, M1_PMU_NR_COUNTERS);
+}
+
 static int m1_pmu_set_event_filter(struct hw_perf_event *event,
 				   struct perf_event_attr *attr)
 {
@@ -639,7 +645,7 @@ static int m1_pmu_set_event_filter(struct hw_perf_event *event,
 	return 0;
 }
 
-static int apple_pmu_init(struct arm_pmu *cpu_pmu)
+static int apple_pmu_init(struct arm_pmu *cpu_pmu, u32 counters)
 {
 	cpu_pmu->handle_irq	  = m1_pmu_handle_irq;
 	cpu_pmu->enable		  = m1_pmu_enable_event;
@@ -649,7 +655,6 @@ static int apple_pmu_init(struct arm_pmu *cpu_pmu)
 	cpu_pmu->clear_event_idx  = m1_pmu_clear_event_idx;
 	cpu_pmu->start		  = m1_pmu_start;
 	cpu_pmu->stop		  = m1_pmu_stop;
-	cpu_pmu->reset		  = m1_pmu_reset;
 	cpu_pmu->set_event_filter = m1_pmu_set_event_filter;
 
 	if (is_hyp_mode_available()) {
@@ -657,7 +662,7 @@ static int apple_pmu_init(struct arm_pmu *cpu_pmu)
 		m1_pmu_init_pmceid(cpu_pmu);
 	}
 
-	bitmap_set(cpu_pmu->cntr_mask, 0, M1_PMU_NR_COUNTERS);
+	bitmap_set(cpu_pmu->cntr_mask, 0, counters);
 	cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] = &m1_pmu_events_attr_group;
 	cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] = &m1_pmu_format_attr_group;
 	return 0;
@@ -669,7 +674,8 @@ static int m1_pmu_ice_init(struct arm_pmu *cpu_pmu)
 	cpu_pmu->name = "apple_icestorm_pmu";
 	cpu_pmu->get_event_idx	  = m1_pmu_get_event_idx;
 	cpu_pmu->map_event	  = m1_pmu_map_event;
-	return apple_pmu_init(cpu_pmu);
+	cpu_pmu->reset		  = m1_pmu_reset;
+	return apple_pmu_init(cpu_pmu, M1_PMU_NR_COUNTERS);
 }
 
 static int m1_pmu_fire_init(struct arm_pmu *cpu_pmu)
@@ -677,7 +683,8 @@ static int m1_pmu_fire_init(struct arm_pmu *cpu_pmu)
 	cpu_pmu->name = "apple_firestorm_pmu";
 	cpu_pmu->get_event_idx	  = m1_pmu_get_event_idx;
 	cpu_pmu->map_event	  = m1_pmu_map_event;
-	return apple_pmu_init(cpu_pmu);
+	cpu_pmu->reset		  = m1_pmu_reset;
+	return apple_pmu_init(cpu_pmu, M1_PMU_NR_COUNTERS);
 }
 
 static int m2_pmu_avalanche_init(struct arm_pmu *cpu_pmu)
@@ -685,7 +692,8 @@ static int m2_pmu_avalanche_init(struct arm_pmu *cpu_pmu)
 	cpu_pmu->name = "apple_avalanche_pmu";
 	cpu_pmu->get_event_idx	  = m1_pmu_get_event_idx;
 	cpu_pmu->map_event	  = m2_pmu_map_event;
-	return apple_pmu_init(cpu_pmu);
+	cpu_pmu->reset		  = m1_pmu_reset;
+	return apple_pmu_init(cpu_pmu, M1_PMU_NR_COUNTERS);
 }
 
 static int m2_pmu_blizzard_init(struct arm_pmu *cpu_pmu)
@@ -693,7 +701,8 @@ static int m2_pmu_blizzard_init(struct arm_pmu *cpu_pmu)
 	cpu_pmu->name = "apple_blizzard_pmu";
 	cpu_pmu->get_event_idx	  = m1_pmu_get_event_idx;
 	cpu_pmu->map_event	  = m2_pmu_map_event;
-	return apple_pmu_init(cpu_pmu);
+	cpu_pmu->reset		  = m1_pmu_reset;
+	return apple_pmu_init(cpu_pmu, M1_PMU_NR_COUNTERS);
 }
 
 static const struct of_device_id m1_pmu_of_device_ids[] = {

-- 
2.52.0



From towinchenmi at gmail.com  Wed Dec 17 08:23:18 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Thu, 18 Dec 2025 00:23:18 +0800
Subject: [PATCH v9 05/21] drivers/perf: apple_m1: Support configuring
 counters for 32-bit EL0
In-Reply-To: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
References: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
Message-ID: <20251218-apple-cpmu-v9-5-4deadbe65d03@gmail.com>

Add support for configuring counters for 32-bit EL0 to allow adding support
for implementations with 32-bit EL0.

Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
 arch/arm64/include/asm/apple_m1_pmu.h | 2 ++
 drivers/perf/apple_m1_cpu_pmu.c       | 6 ++++++
 2 files changed, 8 insertions(+)

diff --git a/arch/arm64/include/asm/apple_m1_pmu.h b/arch/arm64/include/asm/apple_m1_pmu.h
index 02e05d05851f739b985bf416f1aa3baeafd691dc..8a667e7f07a517419c22a4f930947347be8546f7 100644
--- a/arch/arm64/include/asm/apple_m1_pmu.h
+++ b/arch/arm64/include/asm/apple_m1_pmu.h
@@ -38,8 +38,10 @@
 
 #define SYS_IMP_APL_PMCR1_EL1	sys_reg(3, 1, 15, 1, 0)
 #define SYS_IMP_APL_PMCR1_EL12	sys_reg(3, 1, 15, 7, 2)
+#define PMCR1_COUNT_A32_EL0_0_7	GENMASK(7, 0)
 #define PMCR1_COUNT_A64_EL0_0_7	GENMASK(15, 8)
 #define PMCR1_COUNT_A64_EL1_0_7	GENMASK(23, 16)
+#define PMCR1_COUNT_A32_EL0_8_9	GENMASK(33, 32)
 #define PMCR1_COUNT_A64_EL0_8_9	GENMASK(41, 40)
 #define PMCR1_COUNT_A64_EL1_8_9	GENMASK(49, 48)
 
diff --git a/drivers/perf/apple_m1_cpu_pmu.c b/drivers/perf/apple_m1_cpu_pmu.c
index b5fe04ef186f04b4af32524fe433afb79979b791..fb2759069fe9e47146f0342fa46e40f3ab836926 100644
--- a/drivers/perf/apple_m1_cpu_pmu.c
+++ b/drivers/perf/apple_m1_cpu_pmu.c
@@ -348,10 +348,16 @@ static void __m1_pmu_configure_event_filter(unsigned int index, bool user,
 	case 0 ... 7:
 		user_bit = BIT(get_bit_offset(index, PMCR1_COUNT_A64_EL0_0_7));
 		kernel_bit = BIT(get_bit_offset(index, PMCR1_COUNT_A64_EL1_0_7));
+
+		if (system_supports_32bit_el0())
+			user_bit |= BIT(get_bit_offset(index, PMCR1_COUNT_A32_EL0_0_7));
 		break;
 	case 8 ... 9:
 		user_bit = BIT(get_bit_offset(index - 8, PMCR1_COUNT_A64_EL0_8_9));
 		kernel_bit = BIT(get_bit_offset(index - 8, PMCR1_COUNT_A64_EL1_8_9));
+
+		if (system_supports_32bit_el0())
+			user_bit |= BIT(get_bit_offset(index - 8, PMCR1_COUNT_A32_EL0_8_9));
 		break;
 	default:
 		BUG();

-- 
2.52.0



From towinchenmi at gmail.com  Wed Dec 17 08:23:19 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Thu, 18 Dec 2025 00:23:19 +0800
Subject: [PATCH v9 06/21] drivers/perf: apple_m1: Support
 per-implementation PMU startup
In-Reply-To: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
References: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
Message-ID: <20251218-apple-cpmu-v9-6-4deadbe65d03@gmail.com>

Support for implementations that deliver its interrupts in ways other than
FIQ will be added, which requires a per-implementation startup function.

Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
 drivers/perf/apple_m1_cpu_pmu.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/perf/apple_m1_cpu_pmu.c b/drivers/perf/apple_m1_cpu_pmu.c
index fb2759069fe9e47146f0342fa46e40f3ab836926..303c0e62432281e899a33fc197365c70078d6ac1 100644
--- a/drivers/perf/apple_m1_cpu_pmu.c
+++ b/drivers/perf/apple_m1_cpu_pmu.c
@@ -659,7 +659,6 @@ static int apple_pmu_init(struct arm_pmu *cpu_pmu, u32 counters)
 	cpu_pmu->read_counter	  = m1_pmu_read_counter;
 	cpu_pmu->write_counter	  = m1_pmu_write_counter;
 	cpu_pmu->clear_event_idx  = m1_pmu_clear_event_idx;
-	cpu_pmu->start		  = m1_pmu_start;
 	cpu_pmu->stop		  = m1_pmu_stop;
 	cpu_pmu->set_event_filter = m1_pmu_set_event_filter;
 
@@ -681,6 +680,7 @@ static int m1_pmu_ice_init(struct arm_pmu *cpu_pmu)
 	cpu_pmu->get_event_idx	  = m1_pmu_get_event_idx;
 	cpu_pmu->map_event	  = m1_pmu_map_event;
 	cpu_pmu->reset		  = m1_pmu_reset;
+	cpu_pmu->start		  = m1_pmu_start;
 	return apple_pmu_init(cpu_pmu, M1_PMU_NR_COUNTERS);
 }
 
@@ -690,6 +690,7 @@ static int m1_pmu_fire_init(struct arm_pmu *cpu_pmu)
 	cpu_pmu->get_event_idx	  = m1_pmu_get_event_idx;
 	cpu_pmu->map_event	  = m1_pmu_map_event;
 	cpu_pmu->reset		  = m1_pmu_reset;
+	cpu_pmu->start		  = m1_pmu_start;
 	return apple_pmu_init(cpu_pmu, M1_PMU_NR_COUNTERS);
 }
 
@@ -699,6 +700,7 @@ static int m2_pmu_avalanche_init(struct arm_pmu *cpu_pmu)
 	cpu_pmu->get_event_idx	  = m1_pmu_get_event_idx;
 	cpu_pmu->map_event	  = m2_pmu_map_event;
 	cpu_pmu->reset		  = m1_pmu_reset;
+	cpu_pmu->start		  = m1_pmu_start;
 	return apple_pmu_init(cpu_pmu, M1_PMU_NR_COUNTERS);
 }
 
@@ -708,6 +710,7 @@ static int m2_pmu_blizzard_init(struct arm_pmu *cpu_pmu)
 	cpu_pmu->get_event_idx	  = m1_pmu_get_event_idx;
 	cpu_pmu->map_event	  = m2_pmu_map_event;
 	cpu_pmu->reset		  = m1_pmu_reset;
+	cpu_pmu->start		  = m1_pmu_start;
 	return apple_pmu_init(cpu_pmu, M1_PMU_NR_COUNTERS);
 }
 

-- 
2.52.0



From towinchenmi at gmail.com  Wed Dec 17 08:23:20 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Thu, 18 Dec 2025 00:23:20 +0800
Subject: [PATCH v9 07/21] drivers/perf: apple_m1: Support
 per-implementation event attr group
In-Reply-To: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
References: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
Message-ID: <20251218-apple-cpmu-v9-7-4deadbe65d03@gmail.com>

To support implementations with different event numbers for cycles or
instruction events, event attr groups needs to be per-implementation.

Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
 drivers/perf/apple_m1_cpu_pmu.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/perf/apple_m1_cpu_pmu.c b/drivers/perf/apple_m1_cpu_pmu.c
index 303c0e62432281e899a33fc197365c70078d6ac1..d0362a1813788776f4210523efe33a3018cfef2a 100644
--- a/drivers/perf/apple_m1_cpu_pmu.c
+++ b/drivers/perf/apple_m1_cpu_pmu.c
@@ -668,7 +668,6 @@ static int apple_pmu_init(struct arm_pmu *cpu_pmu, u32 counters)
 	}
 
 	bitmap_set(cpu_pmu->cntr_mask, 0, counters);
-	cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] = &m1_pmu_events_attr_group;
 	cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] = &m1_pmu_format_attr_group;
 	return 0;
 }
@@ -681,6 +680,7 @@ static int m1_pmu_ice_init(struct arm_pmu *cpu_pmu)
 	cpu_pmu->map_event	  = m1_pmu_map_event;
 	cpu_pmu->reset		  = m1_pmu_reset;
 	cpu_pmu->start		  = m1_pmu_start;
+	cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] = &m1_pmu_events_attr_group;
 	return apple_pmu_init(cpu_pmu, M1_PMU_NR_COUNTERS);
 }
 
@@ -691,6 +691,7 @@ static int m1_pmu_fire_init(struct arm_pmu *cpu_pmu)
 	cpu_pmu->map_event	  = m1_pmu_map_event;
 	cpu_pmu->reset		  = m1_pmu_reset;
 	cpu_pmu->start		  = m1_pmu_start;
+	cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] = &m1_pmu_events_attr_group;
 	return apple_pmu_init(cpu_pmu, M1_PMU_NR_COUNTERS);
 }
 
@@ -701,6 +702,7 @@ static int m2_pmu_avalanche_init(struct arm_pmu *cpu_pmu)
 	cpu_pmu->map_event	  = m2_pmu_map_event;
 	cpu_pmu->reset		  = m1_pmu_reset;
 	cpu_pmu->start		  = m1_pmu_start;
+	cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] = &m1_pmu_events_attr_group;
 	return apple_pmu_init(cpu_pmu, M1_PMU_NR_COUNTERS);
 }
 
@@ -711,6 +713,7 @@ static int m2_pmu_blizzard_init(struct arm_pmu *cpu_pmu)
 	cpu_pmu->map_event	  = m2_pmu_map_event;
 	cpu_pmu->reset		  = m1_pmu_reset;
 	cpu_pmu->start		  = m1_pmu_start;
+	cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] = &m1_pmu_events_attr_group;
 	return apple_pmu_init(cpu_pmu, M1_PMU_NR_COUNTERS);
 }
 

-- 
2.52.0



From towinchenmi at gmail.com  Wed Dec 17 08:23:21 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Thu, 18 Dec 2025 00:23:21 +0800
Subject: [PATCH v9 08/21] drivers/perf: apple_m1: Add Apple A7 support
In-Reply-To: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
References: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
Message-ID: <20251218-apple-cpmu-v9-8-4deadbe65d03@gmail.com>

Add support for the CPU PMU found in the Apple A7 SoC. The PMU has 8
counters and a very different event layout compared to the M1 PMU.
Interrupts are delivered as IRQs instead of FIQs like on the M1.

Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
 drivers/perf/apple_m1_cpu_pmu.c | 190 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 190 insertions(+)

diff --git a/drivers/perf/apple_m1_cpu_pmu.c b/drivers/perf/apple_m1_cpu_pmu.c
index d0362a1813788776f4210523efe33a3018cfef2a..afcf7c951379698ceff21c1a99cca31b3a6177b1 100644
--- a/drivers/perf/apple_m1_cpu_pmu.c
+++ b/drivers/perf/apple_m1_cpu_pmu.c
@@ -19,6 +19,7 @@
 #include <asm/irq_regs.h>
 #include <asm/perf_event.h>
 
+#define A7_PMU_NR_COUNTERS		8
 #define M1_PMU_NR_COUNTERS		10
 #define APPLE_PMU_MAX_NR_COUNTERS	10
 
@@ -45,6 +46,143 @@
  * know next to nothing about the events themselves, and we already have
  * per cpu-type PMU abstractions.
  */
+
+enum a7_pmu_events {
+	A7_PMU_PERFCTR_INST_ALL					= 0x0,
+	A7_PMU_PERFCTR_UNKNOWN_1				= 0x1,
+	A7_PMU_PERFCTR_CORE_ACTIVE_CYCLE			= 0x2,
+	A7_PMU_PERFCTR_L2_TLB_MISS_INSTRUCTION			= 0x10,
+	A7_PMU_PERFCTR_L2_TLB_MISS_DATA				= 0x11,
+	A7_PMU_PERFCTR_BIU_UPSTREAM_CYCLE			= 0x19,
+	A7_PMU_PERFCTR_BIU_DOWNSTREAM_CYCLE			= 0x20,
+	A7_PMU_PERFCTR_L2C_AGENT_LD				= 0x22,
+	A7_PMU_PERFCTR_L2C_AGENT_LD_MISS			= 0x23,
+	A7_PMU_PERFCTR_L2C_AGENT_ST				= 0x24,
+	A7_PMU_PERFCTR_L2C_AGENT_ST_MISS			= 0x25,
+	A7_PMU_PERFCTR_SCHEDULE_UOP				= 0x58,
+	A7_PMU_PERFCTR_MAP_REWIND				= 0x61,
+	A7_PMU_PERFCTR_MAP_STALL				= 0x62,
+	A7_PMU_PERFCTR_FLUSH_RESTART_OTHER_NONSPEC		= 0x6e,
+	A7_PMU_PERFCTR_INST_A32					= 0x78,
+	A7_PMU_PERFCTR_INST_T32					= 0x79,
+	A7_PMU_PERFCTR_INST_A64					= 0x7a,
+	A7_PMU_PERFCTR_INST_BRANCH				= 0x7b,
+	A7_PMU_PERFCTR_INST_BRANCH_CALL				= 0x7c,
+	A7_PMU_PERFCTR_INST_BRANCH_RET				= 0x7d,
+	A7_PMU_PERFCTR_INST_BRANCH_TAKEN			= 0x7e,
+	A7_PMU_PERFCTR_INST_BRANCH_INDIR			= 0x81,
+	A7_PMU_PERFCTR_INST_BRANCH_COND				= 0x82,
+	A7_PMU_PERFCTR_INST_INT_LD				= 0x83,
+	A7_PMU_PERFCTR_INST_INT_ST				= 0x84,
+	A7_PMU_PERFCTR_INST_INT_ALU				= 0x85,
+	A7_PMU_PERFCTR_INST_SIMD_LD				= 0x86,
+	A7_PMU_PERFCTR_INST_SIMD_ST				= 0x87,
+	A7_PMU_PERFCTR_INST_SIMD_ALU				= 0x88,
+	A7_PMU_PERFCTR_INST_LDST				= 0x89,
+	A7_PMU_PERFCTR_UNKNOWN_8d				= 0x8d,
+	A7_PMU_PERFCTR_UNKNOWN_8e				= 0x8e,
+	A7_PMU_PERFCTR_UNKNOWN_8f				= 0x8f,
+	A7_PMU_PERFCTR_UNKNOWN_90				= 0x90,
+	A7_PMU_PERFCTR_UNKNOWN_93				= 0x93,
+	A7_PMU_PERFCTR_UNKNOWN_94				= 0x94,
+	A7_PMU_PERFCTR_UNKNOWN_95				= 0x95,
+	A7_PMU_PERFCTR_L1D_TLB_ACCESS				= 0x96,
+	A7_PMU_PERFCTR_L1D_TLB_MISS				= 0x97,
+	A7_PMU_PERFCTR_L1D_CACHE_MISS_ST			= 0x98,
+	A7_PMU_PERFCTR_L1D_CACHE_MISS_LD			= 0x99,
+	A7_PMU_PERFCTR_UNKNOWN_9b				= 0x9b,
+	A7_PMU_PERFCTR_LD_UNIT_UOP				= 0x9c,
+	A7_PMU_PERFCTR_ST_UNIT_UOP				= 0x9d,
+	A7_PMU_PERFCTR_L1D_CACHE_WRITEBACK			= 0x9e,
+	A7_PMU_PERFCTR_UNKNOWN_9f				= 0x9f,
+	A7_PMU_PERFCTR_LDST_X64_UOP				= 0xa7,
+	A7_PMU_PERFCTR_L1D_CACHE_MISS_LD_NONSPEC		= 0xb4,
+	A7_PMU_PERFCTR_L1D_CACHE_MISS_ST_NONSPEC		= 0xb5,
+	A7_PMU_PERFCTR_L1D_TLB_MISS_NONSPEC			= 0xb6,
+	A7_PMU_PERFCTR_ST_MEMORY_ORDER_VIOLATION_NONSPEC	= 0xb9,
+	A7_PMU_PERFCTR_BRANCH_COND_MISPRED_NONSPEC		= 0xba,
+	A7_PMU_PERFCTR_BRANCH_INDIR_MISPRED_NONSPEC		= 0xbb,
+	A7_PMU_PERFCTR_BRANCH_RET_INDIR_MISPRED_NONSPEC		= 0xbd,
+	A7_PMU_PERFCTR_BRANCH_CALL_INDIR_MISPRED_NONSPEC	= 0xbf,
+	A7_PMU_PERFCTR_BRANCH_MISPRED_NONSPEC			= 0xc0,
+	A7_PMU_PERFCTR_UNKNOWN_c1				= 0xc1,
+	A7_PMU_PERFCTR_UNKNOWN_c4				= 0xc4,
+	A7_PMU_PERFCTR_UNKNOWN_c5				= 0xc5,
+	A7_PMU_PERFCTR_UNKNOWN_c6				= 0xc6,
+	A7_PMU_PERFCTR_UNKNOWN_c8				= 0xc8,
+	A7_PMU_PERFCTR_UNKNOWN_ca				= 0xca,
+	A7_PMU_PERFCTR_UNKNOWN_cb				= 0xcb,
+	A7_PMU_PERFCTR_FED_IC_MISS_DEMAND			= 0xce,
+	A7_PMU_PERFCTR_L1I_TLB_MISS_DEMAND			= 0xcf,
+	A7_PMU_PERFCTR_UNKNOWN_f5				= 0xf5,
+	A7_PMU_PERFCTR_UNKNOWN_f6				= 0xf6,
+	A7_PMU_PERFCTR_UNKNOWN_f7				= 0xf7,
+	A7_PMU_PERFCTR_UNKNOWN_f8				= 0xf8,
+	A7_PMU_PERFCTR_UNKNOWN_fd				= 0xfd,
+	A7_PMU_PERFCTR_LAST					= M1_PMU_CFG_EVENT,
+	/*
+	 * From this point onwards, these are not actual HW events,
+	 * but attributes that get stored in hw->config_base.
+	 */
+	A7_PMU_CFG_COUNT_USER					= BIT(8),
+	A7_PMU_CFG_COUNT_KERNEL					= BIT(9),
+};
+
+static const u16 a7_pmu_event_affinity[A7_PMU_PERFCTR_LAST + 1] = {
+	[0 ... A7_PMU_PERFCTR_LAST]				= ANY_BUT_0_1,
+	[A7_PMU_PERFCTR_INST_ALL]				= ANY_BUT_0_1 | BIT(1),
+	[A7_PMU_PERFCTR_UNKNOWN_1]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_CORE_ACTIVE_CYCLE]			= ANY_BUT_0_1 | BIT(0),
+	[A7_PMU_PERFCTR_INST_A32]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_INST_T32]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_INST_A64]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_INST_BRANCH]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_INST_BRANCH_CALL]			= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_INST_BRANCH_RET]			= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_INST_BRANCH_TAKEN]			= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_INST_BRANCH_INDIR]			= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_INST_BRANCH_COND]			= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_INST_INT_LD]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_INST_INT_ST]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_INST_INT_ALU]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_INST_SIMD_LD]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_INST_SIMD_ST]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_INST_SIMD_ALU]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_INST_LDST]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_UNKNOWN_8d]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_UNKNOWN_8e]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_UNKNOWN_8f]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_UNKNOWN_90]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_UNKNOWN_93]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_UNKNOWN_94]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_UNKNOWN_95]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_L1D_CACHE_MISS_ST]			= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_L1D_CACHE_MISS_LD]			= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_UNKNOWN_9b]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_LD_UNIT_UOP]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_UNKNOWN_9f]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_L1D_CACHE_MISS_LD_NONSPEC]		= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_L1D_CACHE_MISS_ST_NONSPEC]		= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_L1D_TLB_MISS_NONSPEC]			= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_ST_MEMORY_ORDER_VIOLATION_NONSPEC]	= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_BRANCH_COND_MISPRED_NONSPEC]		= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_BRANCH_INDIR_MISPRED_NONSPEC]		= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_BRANCH_RET_INDIR_MISPRED_NONSPEC]	= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_BRANCH_CALL_INDIR_MISPRED_NONSPEC]	= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_BRANCH_MISPRED_NONSPEC]			= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_UNKNOWN_c1]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_UNKNOWN_c4]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_UNKNOWN_c5]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_UNKNOWN_c6]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_UNKNOWN_c8]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_UNKNOWN_ca]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_UNKNOWN_cb]				= ONLY_5_6_7,
+	[A7_PMU_PERFCTR_UNKNOWN_f5]				= ONLY_2_4_6,
+	[A7_PMU_PERFCTR_UNKNOWN_f6]				= ONLY_2_4_6,
+	[A7_PMU_PERFCTR_UNKNOWN_f7]				= ONLY_2_4_6,
+	[A7_PMU_PERFCTR_UNKNOWN_fd]				= ONLY_2_4_6,
+};
+
 enum m1_pmu_events {
 	M1_PMU_PERFCTR_RETIRE_UOP				= 0x1,
 	M1_PMU_PERFCTR_CORE_ACTIVE_CYCLE			= 0x2,
@@ -165,6 +303,14 @@ static const u16 m1_pmu_event_affinity[M1_PMU_PERFCTR_LAST + 1] = {
 	[M1_PMU_PERFCTR_UNKNOWN_fd]				= ONLY_2_4_6,
 };
 
+static const unsigned int a7_pmu_perf_map[PERF_COUNT_HW_MAX] = {
+	PERF_MAP_ALL_UNSUPPORTED,
+	[PERF_COUNT_HW_CPU_CYCLES]		= A7_PMU_PERFCTR_CORE_ACTIVE_CYCLE,
+	[PERF_COUNT_HW_INSTRUCTIONS]		= A7_PMU_PERFCTR_INST_ALL,
+	[PERF_COUNT_HW_BRANCH_MISSES]		= A7_PMU_PERFCTR_BRANCH_MISPRED_NONSPEC,
+	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS]	= A7_PMU_PERFCTR_INST_BRANCH
+};
+
 static const unsigned m1_pmu_perf_map[PERF_COUNT_HW_MAX] = {
 	PERF_MAP_ALL_UNSUPPORTED,
 	[PERF_COUNT_HW_CPU_CYCLES]		= M1_PMU_PERFCTR_CORE_ACTIVE_CYCLE,
@@ -199,6 +345,17 @@ static ssize_t m1_pmu_events_sysfs_show(struct device *dev,
 #define M1_PMU_EVENT_ATTR(name, config)					\
 	PMU_EVENT_ATTR_ID(name, m1_pmu_events_sysfs_show, config)
 
+static struct attribute *a7_pmu_event_attrs[] = {
+	M1_PMU_EVENT_ATTR(cycles, A7_PMU_PERFCTR_CORE_ACTIVE_CYCLE),
+	M1_PMU_EVENT_ATTR(instructions, A7_PMU_PERFCTR_INST_ALL),
+	NULL,
+};
+
+static const struct attribute_group a7_pmu_events_attr_group = {
+	.name = "events",
+	.attrs = a7_pmu_event_attrs,
+};
+
 static struct attribute *m1_pmu_event_attrs[] = {
 	M1_PMU_EVENT_ATTR(cycles, M1_PMU_PERFCTR_CORE_ACTIVE_CYCLE),
 	M1_PMU_EVENT_ATTR(instructions, M1_PMU_PERFCTR_INST_ALL),
@@ -521,6 +678,12 @@ static int apple_pmu_get_event_idx(struct pmu_hw_events *cpuc,
 	return -EAGAIN;
 }
 
+static int a7_pmu_get_event_idx(struct pmu_hw_events *cpuc,
+				struct perf_event *event)
+{
+	return apple_pmu_get_event_idx(cpuc, event, a7_pmu_event_affinity);
+}
+
 static int m1_pmu_get_event_idx(struct pmu_hw_events *cpuc,
 				struct perf_event *event)
 {
@@ -544,6 +707,11 @@ static void __m1_pmu_set_mode(u8 mode)
 	isb();
 }
 
+static void a7_pmu_start(struct arm_pmu *cpu_pmu)
+{
+	__m1_pmu_set_mode(PMCR0_IMODE_AIC);
+}
+
 static void m1_pmu_start(struct arm_pmu *cpu_pmu)
 {
 	__m1_pmu_set_mode(PMCR0_IMODE_FIQ);
@@ -578,6 +746,11 @@ static int apple_pmu_map_event_63(struct perf_event *event,
 	return armpmu_map_event(event, perf_map, NULL, M1_PMU_CFG_EVENT);
 }
 
+static int a7_pmu_map_event(struct perf_event *event)
+{
+	return apple_pmu_map_event_47(event, &a7_pmu_perf_map);
+}
+
 static int m1_pmu_map_event(struct perf_event *event)
 {
 	return apple_pmu_map_event_47(event, &m1_pmu_perf_map);
@@ -623,6 +796,11 @@ static void apple_pmu_reset(void *info, u32 counters)
 	isb();
 }
 
+static void a7_pmu_reset(void *info)
+{
+	apple_pmu_reset(info, A7_PMU_NR_COUNTERS);
+}
+
 static void m1_pmu_reset(void *info)
 {
 	apple_pmu_reset(info, M1_PMU_NR_COUNTERS);
@@ -673,6 +851,17 @@ static int apple_pmu_init(struct arm_pmu *cpu_pmu, u32 counters)
 }
 
 /* Device driver gunk */
+static int a7_pmu_cyclone_init(struct arm_pmu *cpu_pmu)
+{
+	cpu_pmu->name = "apple_cyclone_pmu";
+	cpu_pmu->get_event_idx	  = a7_pmu_get_event_idx;
+	cpu_pmu->map_event	  = a7_pmu_map_event;
+	cpu_pmu->reset		  = a7_pmu_reset;
+	cpu_pmu->start		  = a7_pmu_start;
+	cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] = &a7_pmu_events_attr_group;
+	return apple_pmu_init(cpu_pmu, A7_PMU_NR_COUNTERS);
+}
+
 static int m1_pmu_ice_init(struct arm_pmu *cpu_pmu)
 {
 	cpu_pmu->name = "apple_icestorm_pmu";
@@ -722,6 +911,7 @@ static const struct of_device_id m1_pmu_of_device_ids[] = {
 	{ .compatible = "apple,blizzard-pmu",	.data = m2_pmu_blizzard_init, },
 	{ .compatible = "apple,icestorm-pmu",	.data = m1_pmu_ice_init, },
 	{ .compatible = "apple,firestorm-pmu",	.data = m1_pmu_fire_init, },
+	{ .compatible = "apple,cyclone-pmu",	.data = a7_pmu_cyclone_init, },
 	{ },
 };
 MODULE_DEVICE_TABLE(of, m1_pmu_of_device_ids);

-- 
2.52.0



From towinchenmi at gmail.com  Wed Dec 17 08:23:22 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Thu, 18 Dec 2025 00:23:22 +0800
Subject: [PATCH v9 09/21] drivers/perf: apple_m1: Add Apple A8/A8X support
In-Reply-To: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
References: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
Message-ID: <20251218-apple-cpmu-v9-9-4deadbe65d03@gmail.com>

Add support for the CPU PMU found on the Apple A8, A8X SoCs.

Tested-by: Ivaylo Ivanov <ivo.ivanov.ivanov1 at gmail.com>
Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
 drivers/perf/apple_m1_cpu_pmu.c | 124 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 124 insertions(+)

diff --git a/drivers/perf/apple_m1_cpu_pmu.c b/drivers/perf/apple_m1_cpu_pmu.c
index afcf7c951379698ceff21c1a99cca31b3a6177b1..a95f4b717857b30284470487827954dd4b139010 100644
--- a/drivers/perf/apple_m1_cpu_pmu.c
+++ b/drivers/perf/apple_m1_cpu_pmu.c
@@ -28,6 +28,7 @@
 #define ANY_BUT_0_1			GENMASK(9, 2)
 #define ONLY_2_TO_7			GENMASK(7, 2)
 #define ONLY_2_4_6			(BIT(2) | BIT(4) | BIT(6))
+#define ONLY_3_5_7			(BIT(3) | BIT(5) | BIT(7))
 #define ONLY_5_6_7			(BIT(5) | BIT(6) | BIT(7))
 
 /*
@@ -183,6 +184,111 @@ static const u16 a7_pmu_event_affinity[A7_PMU_PERFCTR_LAST + 1] = {
 	[A7_PMU_PERFCTR_UNKNOWN_fd]				= ONLY_2_4_6,
 };
 
+enum a8_pmu_events {
+	A8_PMU_PERFCTR_UNKNOWN_1				= 0x1,
+	A8_PMU_PERFCTR_CORE_ACTIVE_CYCLE			= 0x2,
+	A8_PMU_PERFCTR_L2_TLB_MISS_INSTRUCTION			= 0xa,
+	A8_PMU_PERFCTR_L2_TLB_MISS_DATA				= 0xb,
+	A8_PMU_PERFCTR_BIU_UPSTREAM_CYCLE			= 0x13,
+	A8_PMU_PERFCTR_BIU_DOWNSTREAM_CYCLE			= 0x14,
+	A8_PMU_PERFCTR_L2C_AGENT_LD				= 0x1a,
+	A8_PMU_PERFCTR_L2C_AGENT_LD_MISS			= 0x1b,
+	A8_PMU_PERFCTR_L2C_AGENT_ST				= 0x1c,
+	A8_PMU_PERFCTR_L2C_AGENT_ST_MISS			= 0x1d,
+	A8_PMU_PERFCTR_SCHEDULE_UOP				= 0x52,
+	A8_PMU_PERFCTR_MAP_REWIND				= 0x75,
+	A8_PMU_PERFCTR_MAP_STALL				= 0x76,
+	A8_PMU_PERFCTR_MAP_INT_UOP				= 0x7b,
+	A8_PMU_PERFCTR_MAP_LDST_UOP				= 0x7c,
+	A8_PMU_PERFCTR_MAP_SIMD_UOP				= 0x7d,
+	A8_PMU_PERFCTR_FLUSH_RESTART_OTHER_NONSPEC		= 0x84,
+	A8_PMU_PERFCTR_INST_A32					= 0x8a,
+	A8_PMU_PERFCTR_INST_T32					= 0x8b,
+	A8_PMU_PERFCTR_INST_ALL					= 0x8c,
+	A8_PMU_PERFCTR_INST_BRANCH				= 0x8d,
+	A8_PMU_PERFCTR_INST_BRANCH_CALL				= 0x8e,
+	A8_PMU_PERFCTR_INST_BRANCH_RET				= 0x8f,
+	A8_PMU_PERFCTR_INST_BRANCH_TAKEN			= 0x90,
+	A8_PMU_PERFCTR_INST_BRANCH_INDIR			= 0x93,
+	A8_PMU_PERFCTR_INST_BRANCH_COND				= 0x94,
+	A8_PMU_PERFCTR_INST_INT_LD				= 0x95,
+	A8_PMU_PERFCTR_INST_INT_ST				= 0x96,
+	A8_PMU_PERFCTR_INST_INT_ALU				= 0x97,
+	A8_PMU_PERFCTR_INST_SIMD_LD				= 0x98,
+	A8_PMU_PERFCTR_INST_SIMD_ST				= 0x99,
+	A8_PMU_PERFCTR_INST_SIMD_ALU				= 0x9a,
+	A8_PMU_PERFCTR_INST_LDST				= 0x9b,
+	A8_PMU_PERFCTR_UNKNOWN_9c				= 0x9c,
+	A8_PMU_PERFCTR_UNKNOWN_9f				= 0x9f,
+	A8_PMU_PERFCTR_L1D_TLB_ACCESS				= 0xa0,
+	A8_PMU_PERFCTR_L1D_TLB_MISS				= 0xa1,
+	A8_PMU_PERFCTR_L1D_CACHE_MISS_ST			= 0xa2,
+	A8_PMU_PERFCTR_L1D_CACHE_MISS_LD			= 0xa3,
+	A8_PMU_PERFCTR_LD_UNIT_UOP				= 0xa6,
+	A8_PMU_PERFCTR_ST_UNIT_UOP				= 0xa7,
+	A8_PMU_PERFCTR_L1D_CACHE_WRITEBACK			= 0xa8,
+	A8_PMU_PERFCTR_LDST_X64_UOP				= 0xb1,
+	A8_PMU_PERFCTR_L1D_CACHE_MISS_LD_NONSPEC		= 0xbf,
+	A8_PMU_PERFCTR_L1D_CACHE_MISS_ST_NONSPEC		= 0xc0,
+	A8_PMU_PERFCTR_L1D_TLB_MISS_NONSPEC			= 0xc1,
+	A8_PMU_PERFCTR_ST_MEMORY_ORDER_VIOLATION_NONSPEC	= 0xc4,
+	A8_PMU_PERFCTR_BRANCH_COND_MISPRED_NONSPEC		= 0xc5,
+	A8_PMU_PERFCTR_BRANCH_INDIR_MISPRED_NONSPEC		= 0xc6,
+	A8_PMU_PERFCTR_BRANCH_RET_INDIR_MISPRED_NONSPEC		= 0xc8,
+	A8_PMU_PERFCTR_BRANCH_CALL_INDIR_MISPRED_NONSPEC	= 0xca,
+	A8_PMU_PERFCTR_BRANCH_MISPRED_NONSPEC			= 0xcb,
+	A8_PMU_PERFCTR_FED_IC_MISS_DEMAND			= 0xd3,
+	A8_PMU_PERFCTR_L1I_TLB_MISS_DEMAND			= 0xd4,
+	A8_PMU_PERFCTR_FETCH_RESTART				= 0xde,
+	A8_PMU_PERFCTR_UNKNOWN_f5				= 0xf5,
+	A8_PMU_PERFCTR_UNKNOWN_f6				= 0xf6,
+	A8_PMU_PERFCTR_UNKNOWN_f7				= 0xf7,
+	A8_PMU_PERFCTR_LAST					= M1_PMU_CFG_EVENT,
+
+	/*
+	 * From this point onwards, these are not actual HW events,
+	 * but attributes that get stored in hw->config_base.
+	 */
+	A8_PMU_CFG_COUNT_USER					= BIT(8),
+	A8_PMU_CFG_COUNT_KERNEL					= BIT(9),
+};
+
+static const u16 a8_pmu_event_affinity[A8_PMU_PERFCTR_LAST + 1] = {
+	[0 ... A8_PMU_PERFCTR_LAST]				= ANY_BUT_0_1,
+	[A8_PMU_PERFCTR_UNKNOWN_1]				= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_CORE_ACTIVE_CYCLE]			= ANY_BUT_0_1 | BIT(0),
+	[A8_PMU_PERFCTR_INST_A32]				= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_INST_T32]				= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_INST_ALL]				= BIT(7) | BIT(1),
+	[A8_PMU_PERFCTR_INST_BRANCH]				= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_INST_BRANCH_CALL]			= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_INST_BRANCH_RET]			= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_INST_BRANCH_TAKEN]			= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_INST_BRANCH_INDIR]			= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_INST_BRANCH_COND]			= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_INST_INT_LD]				= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_INST_INT_ST]				= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_INST_INT_ALU]				= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_INST_SIMD_LD]				= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_INST_SIMD_ST]				= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_INST_SIMD_ALU]				= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_INST_LDST]				= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_UNKNOWN_9c]				= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_UNKNOWN_9f]				= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_L1D_CACHE_MISS_LD_NONSPEC]		= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_L1D_CACHE_MISS_ST_NONSPEC]		= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_L1D_TLB_MISS_NONSPEC]			= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_ST_MEMORY_ORDER_VIOLATION_NONSPEC]	= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_BRANCH_COND_MISPRED_NONSPEC]		= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_BRANCH_INDIR_MISPRED_NONSPEC]		= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_BRANCH_RET_INDIR_MISPRED_NONSPEC]	= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_BRANCH_CALL_INDIR_MISPRED_NONSPEC]	= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_BRANCH_MISPRED_NONSPEC]			= ONLY_5_6_7,
+	[A8_PMU_PERFCTR_UNKNOWN_f5]				= ANY_BUT_0_1,
+	[A8_PMU_PERFCTR_UNKNOWN_f6]				= ONLY_3_5_7,
+	[A8_PMU_PERFCTR_UNKNOWN_f7]				= ONLY_3_5_7,
+};
+
 enum m1_pmu_events {
 	M1_PMU_PERFCTR_RETIRE_UOP				= 0x1,
 	M1_PMU_PERFCTR_CORE_ACTIVE_CYCLE			= 0x2,
@@ -684,6 +790,12 @@ static int a7_pmu_get_event_idx(struct pmu_hw_events *cpuc,
 	return apple_pmu_get_event_idx(cpuc, event, a7_pmu_event_affinity);
 }
 
+static int a8_pmu_get_event_idx(struct pmu_hw_events *cpuc,
+				struct perf_event *event)
+{
+	return apple_pmu_get_event_idx(cpuc, event, a8_pmu_event_affinity);
+}
+
 static int m1_pmu_get_event_idx(struct pmu_hw_events *cpuc,
 				struct perf_event *event)
 {
@@ -862,6 +974,17 @@ static int a7_pmu_cyclone_init(struct arm_pmu *cpu_pmu)
 	return apple_pmu_init(cpu_pmu, A7_PMU_NR_COUNTERS);
 }
 
+static int a8_pmu_typhoon_init(struct arm_pmu *cpu_pmu)
+{
+	cpu_pmu->name = "apple_typhoon_pmu";
+	cpu_pmu->get_event_idx	  = a8_pmu_get_event_idx;
+	cpu_pmu->map_event	  = m1_pmu_map_event;
+	cpu_pmu->reset		  = a7_pmu_reset;
+	cpu_pmu->start		  = a7_pmu_start;
+	cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] = &m1_pmu_events_attr_group;
+	return apple_pmu_init(cpu_pmu, A7_PMU_NR_COUNTERS);
+}
+
 static int m1_pmu_ice_init(struct arm_pmu *cpu_pmu)
 {
 	cpu_pmu->name = "apple_icestorm_pmu";
@@ -911,6 +1034,7 @@ static const struct of_device_id m1_pmu_of_device_ids[] = {
 	{ .compatible = "apple,blizzard-pmu",	.data = m2_pmu_blizzard_init, },
 	{ .compatible = "apple,icestorm-pmu",	.data = m1_pmu_ice_init, },
 	{ .compatible = "apple,firestorm-pmu",	.data = m1_pmu_fire_init, },
+	{ .compatible = "apple,typhoon-pmu",	.data = a8_pmu_typhoon_init, },
 	{ .compatible = "apple,cyclone-pmu",	.data = a7_pmu_cyclone_init, },
 	{ },
 };

-- 
2.52.0



From towinchenmi at gmail.com  Wed Dec 17 08:23:23 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Thu, 18 Dec 2025 00:23:23 +0800
Subject: [PATCH v9 10/21] drivers/perf: apple_m1: Add A9/A9X support
In-Reply-To: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
References: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
Message-ID: <20251218-apple-cpmu-v9-10-4deadbe65d03@gmail.com>

Add support for CPU PMU found in the Apple A9 and A9X SoCs.

Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
 drivers/perf/apple_m1_cpu_pmu.c | 125 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 125 insertions(+)

diff --git a/drivers/perf/apple_m1_cpu_pmu.c b/drivers/perf/apple_m1_cpu_pmu.c
index a95f4b717857b30284470487827954dd4b139010..0ef39c148dd2ed032e4d14ac01e7c7e7e088b394 100644
--- a/drivers/perf/apple_m1_cpu_pmu.c
+++ b/drivers/perf/apple_m1_cpu_pmu.c
@@ -289,6 +289,113 @@ static const u16 a8_pmu_event_affinity[A8_PMU_PERFCTR_LAST + 1] = {
 	[A8_PMU_PERFCTR_UNKNOWN_f7]				= ONLY_3_5_7,
 };
 
+
+enum a9_pmu_events {
+	A9_PMU_PERFCTR_UNKNOWN_1				= 0x1,
+	A9_PMU_PERFCTR_CORE_ACTIVE_CYCLE			= 0x2,
+	A9_PMU_PERFCTR_L2_TLB_MISS_INSTRUCTION			= 0xa,
+	A9_PMU_PERFCTR_L2_TLB_MISS_DATA				= 0xb,
+	A9_PMU_PERFCTR_L2C_AGENT_LD				= 0x1a,
+	A9_PMU_PERFCTR_L2C_AGENT_LD_MISS			= 0x1b,
+	A9_PMU_PERFCTR_L2C_AGENT_ST				= 0x1c,
+	A9_PMU_PERFCTR_L2C_AGENT_ST_MISS			= 0x1d,
+	A9_PMU_PERFCTR_SCHEDULE_UOP				= 0x52,
+	A9_PMU_PERFCTR_MAP_REWIND				= 0x75,
+	A9_PMU_PERFCTR_MAP_STALL				= 0x76,
+	A9_PMU_PERFCTR_MAP_INT_UOP				= 0x7c,
+	A9_PMU_PERFCTR_MAP_LDST_UOP				= 0x7d,
+	A9_PMU_PERFCTR_MAP_SIMD_UOP				= 0x7e,
+	A9_PMU_PERFCTR_FLUSH_RESTART_OTHER_NONSPEC		= 0x84,
+	A9_PMU_PERFCTR_INST_A32					= 0x8a,
+	A9_PMU_PERFCTR_INST_T32					= 0x8b,
+	A9_PMU_PERFCTR_INST_ALL					= 0x8c,
+	A9_PMU_PERFCTR_INST_BRANCH				= 0x8d,
+	A9_PMU_PERFCTR_INST_BRANCH_CALL				= 0x8e,
+	A9_PMU_PERFCTR_INST_BRANCH_RET				= 0x8f,
+	A9_PMU_PERFCTR_INST_BRANCH_TAKEN			= 0x90,
+	A9_PMU_PERFCTR_INST_BRANCH_INDIR			= 0x93,
+	A9_PMU_PERFCTR_INST_BRANCH_COND				= 0x94,
+	A9_PMU_PERFCTR_INST_INT_LD				= 0x95,
+	A9_PMU_PERFCTR_INST_INT_ST				= 0x96,
+	A9_PMU_PERFCTR_INST_INT_ALU				= 0x97,
+	A9_PMU_PERFCTR_INST_SIMD_LD				= 0x98,
+	A9_PMU_PERFCTR_INST_SIMD_ST				= 0x99,
+	A9_PMU_PERFCTR_INST_SIMD_ALU				= 0x9a,
+	A9_PMU_PERFCTR_INST_LDST				= 0x9b,
+	A9_PMU_PERFCTR_INST_BARRIER				= 0x9c,
+	A9_PMU_PERFCTR_UNKNOWN_9f				= 0x9f,
+	A9_PMU_PERFCTR_L1D_TLB_ACCESS				= 0xa0,
+	A9_PMU_PERFCTR_L1D_TLB_MISS				= 0xa1,
+	A9_PMU_PERFCTR_L1D_CACHE_MISS_ST			= 0xa2,
+	A9_PMU_PERFCTR_L1D_CACHE_MISS_LD			= 0xa3,
+	A9_PMU_PERFCTR_LD_UNIT_UOP				= 0xa6,
+	A9_PMU_PERFCTR_ST_UNIT_UOP				= 0xa7,
+	A9_PMU_PERFCTR_L1D_CACHE_WRITEBACK			= 0xa8,
+	A9_PMU_PERFCTR_LDST_X64_UOP				= 0xb1,
+	A9_PMU_PERFCTR_ATOMIC_OR_EXCLUSIVE_SUCC			= 0xb3,
+	A9_PMU_PERFCTR_ATOMIC_OR_EXCLUSIVE_FAIL			= 0xb4,
+	A9_PMU_PERFCTR_L1D_CACHE_MISS_LD_NONSPEC		= 0xbf,
+	A9_PMU_PERFCTR_L1D_CACHE_MISS_ST_NONSPEC		= 0xc0,
+	A9_PMU_PERFCTR_L1D_TLB_MISS_NONSPEC			= 0xc1,
+	A9_PMU_PERFCTR_ST_MEMORY_ORDER_VIOLATION_NONSPEC	= 0xc4,
+	A9_PMU_PERFCTR_BRANCH_COND_MISPRED_NONSPEC		= 0xc5,
+	A9_PMU_PERFCTR_BRANCH_INDIR_MISPRED_NONSPEC		= 0xc6,
+	A9_PMU_PERFCTR_BRANCH_RET_INDIR_MISPRED_NONSPEC		= 0xc8,
+	A9_PMU_PERFCTR_BRANCH_CALL_INDIR_MISPRED_NONSPEC	= 0xca,
+	A9_PMU_PERFCTR_BRANCH_MISPRED_NONSPEC			= 0xcb,
+	A9_PMU_PERFCTR_FED_IC_MISS_DEMAND			= 0xd3,
+	A9_PMU_PERFCTR_L1I_TLB_MISS_DEMAND			= 0xd4,
+	A9_PMU_PERFCTR_MAP_DISPATCH_BUBBLE			= 0xd6,
+	A9_PMU_PERFCTR_FETCH_RESTART				= 0xde,
+	A9_PMU_PERFCTR_ST_NT_UOP				= 0xe5,
+	A9_PMU_PERFCTR_LD_NT_UOP				= 0xe6,
+	A9_PMU_PERFCTR_UNKNOWN_f6				= 0xf6,
+	A9_PMU_PERFCTR_UNKNOWN_f7				= 0xf7,
+	A9_PMU_PERFCTR_LAST					= M1_PMU_CFG_EVENT,
+
+	/*
+	 * From this point onwards, these are not actual HW events,
+	 * but attributes that get stored in hw->config_base.
+	 */
+	A9_PMU_CFG_COUNT_USER					= BIT(8),
+	A9_PMU_CFG_COUNT_KERNEL					= BIT(9),
+};
+
+static const u16 a9_pmu_event_affinity[A9_PMU_PERFCTR_LAST + 1] = {
+	[0 ... A9_PMU_PERFCTR_LAST]				= ANY_BUT_0_1,
+	[A9_PMU_PERFCTR_UNKNOWN_1]				= BIT(7),
+	[A9_PMU_PERFCTR_CORE_ACTIVE_CYCLE]			= ANY_BUT_0_1 | BIT(0),
+	[A9_PMU_PERFCTR_INST_A32]				= BIT(7),
+	[A9_PMU_PERFCTR_INST_T32]				= BIT(7),
+	[A9_PMU_PERFCTR_INST_ALL]				= BIT(7) | BIT(1),
+	[A9_PMU_PERFCTR_INST_BRANCH]				= ONLY_5_6_7,
+	[A9_PMU_PERFCTR_INST_BRANCH_CALL]			= ONLY_5_6_7,
+	[A9_PMU_PERFCTR_INST_BRANCH_RET]			= ONLY_5_6_7,
+	[A9_PMU_PERFCTR_INST_BRANCH_TAKEN]			= ONLY_5_6_7,
+	[A9_PMU_PERFCTR_INST_BRANCH_INDIR]			= ONLY_5_6_7,
+	[A9_PMU_PERFCTR_INST_BRANCH_COND]			= ONLY_5_6_7,
+	[A9_PMU_PERFCTR_INST_INT_LD]				= ONLY_5_6_7,
+	[A9_PMU_PERFCTR_INST_INT_ST]				= ONLY_5_6_7,
+	[A9_PMU_PERFCTR_INST_INT_ALU]				= BIT(7),
+	[A9_PMU_PERFCTR_INST_SIMD_LD]				= ONLY_5_6_7,
+	[A9_PMU_PERFCTR_INST_SIMD_ST]				= ONLY_5_6_7,
+	[A9_PMU_PERFCTR_INST_SIMD_ALU]				= BIT(7),
+	[A9_PMU_PERFCTR_INST_LDST]				= ONLY_5_6_7,
+	[A9_PMU_PERFCTR_INST_BARRIER]				= ONLY_5_6_7,
+	[A9_PMU_PERFCTR_UNKNOWN_9f]				= BIT(7),
+	[A9_PMU_PERFCTR_L1D_CACHE_MISS_LD_NONSPEC]		= ONLY_5_6_7,
+	[A9_PMU_PERFCTR_L1D_CACHE_MISS_ST_NONSPEC]		= ONLY_5_6_7,
+	[A9_PMU_PERFCTR_L1D_TLB_MISS_NONSPEC]			= ONLY_5_6_7,
+	[A9_PMU_PERFCTR_ST_MEMORY_ORDER_VIOLATION_NONSPEC]	= ONLY_5_6_7,
+	[A9_PMU_PERFCTR_BRANCH_COND_MISPRED_NONSPEC]		= ONLY_5_6_7,
+	[A9_PMU_PERFCTR_BRANCH_INDIR_MISPRED_NONSPEC]		= ONLY_5_6_7,
+	[A9_PMU_PERFCTR_BRANCH_RET_INDIR_MISPRED_NONSPEC]	= ONLY_5_6_7,
+	[A9_PMU_PERFCTR_BRANCH_CALL_INDIR_MISPRED_NONSPEC]	= ONLY_5_6_7,
+	[A9_PMU_PERFCTR_BRANCH_MISPRED_NONSPEC]			= ONLY_5_6_7,
+	[A9_PMU_PERFCTR_UNKNOWN_f6]				= ONLY_3_5_7,
+	[A9_PMU_PERFCTR_UNKNOWN_f7]				= ONLY_3_5_7,
+};
+
 enum m1_pmu_events {
 	M1_PMU_PERFCTR_RETIRE_UOP				= 0x1,
 	M1_PMU_PERFCTR_CORE_ACTIVE_CYCLE			= 0x2,
@@ -796,6 +903,12 @@ static int a8_pmu_get_event_idx(struct pmu_hw_events *cpuc,
 	return apple_pmu_get_event_idx(cpuc, event, a8_pmu_event_affinity);
 }
 
+static int a9_pmu_get_event_idx(struct pmu_hw_events *cpuc,
+				struct perf_event *event)
+{
+	return apple_pmu_get_event_idx(cpuc, event, a9_pmu_event_affinity);
+}
+
 static int m1_pmu_get_event_idx(struct pmu_hw_events *cpuc,
 				struct perf_event *event)
 {
@@ -985,6 +1098,17 @@ static int a8_pmu_typhoon_init(struct arm_pmu *cpu_pmu)
 	return apple_pmu_init(cpu_pmu, A7_PMU_NR_COUNTERS);
 }
 
+static int a9_pmu_twister_init(struct arm_pmu *cpu_pmu)
+{
+	cpu_pmu->name = "apple_twister_pmu";
+	cpu_pmu->get_event_idx	  = a9_pmu_get_event_idx;
+	cpu_pmu->map_event	  = m1_pmu_map_event;
+	cpu_pmu->reset		  = a7_pmu_reset;
+	cpu_pmu->start		  = a7_pmu_start;
+	cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] = &m1_pmu_events_attr_group;
+	return apple_pmu_init(cpu_pmu, A7_PMU_NR_COUNTERS);
+}
+
 static int m1_pmu_ice_init(struct arm_pmu *cpu_pmu)
 {
 	cpu_pmu->name = "apple_icestorm_pmu";
@@ -1034,6 +1158,7 @@ static const struct of_device_id m1_pmu_of_device_ids[] = {
 	{ .compatible = "apple,blizzard-pmu",	.data = m2_pmu_blizzard_init, },
 	{ .compatible = "apple,icestorm-pmu",	.data = m1_pmu_ice_init, },
 	{ .compatible = "apple,firestorm-pmu",	.data = m1_pmu_fire_init, },
+	{ .compatible = "apple,twister-pmu",	.data = a9_pmu_twister_init, },
 	{ .compatible = "apple,typhoon-pmu",	.data = a8_pmu_typhoon_init, },
 	{ .compatible = "apple,cyclone-pmu",	.data = a7_pmu_cyclone_init, },
 	{ },

-- 
2.52.0



From towinchenmi at gmail.com  Wed Dec 17 08:23:24 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Thu, 18 Dec 2025 00:23:24 +0800
Subject: [PATCH v9 11/21] drivers/perf: apple_m1: Add Apple A10/A10X/T2
 Support
In-Reply-To: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
References: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
Message-ID: <20251218-apple-cpmu-v9-11-4deadbe65d03@gmail.com>

Add support for the CPU PMU found in the Apple A10, A10X, T2 SoCs.

Tested-by: Ivaylo Ivanov <ivo.ivanov.ivanov1 at gmail.com>
Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
 drivers/perf/apple_m1_cpu_pmu.c | 131 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 131 insertions(+)

diff --git a/drivers/perf/apple_m1_cpu_pmu.c b/drivers/perf/apple_m1_cpu_pmu.c
index 0ef39c148dd2ed032e4d14ac01e7c7e7e088b394..8c252731408224c3596b4157024a3ee885d98d9e 100644
--- a/drivers/perf/apple_m1_cpu_pmu.c
+++ b/drivers/perf/apple_m1_cpu_pmu.c
@@ -396,6 +396,119 @@ static const u16 a9_pmu_event_affinity[A9_PMU_PERFCTR_LAST + 1] = {
 	[A9_PMU_PERFCTR_UNKNOWN_f7]				= ONLY_3_5_7,
 };
 
+enum a10_pmu_events {
+	A10_PMU_PERFCTR_RETIRE_UOP				= 0x1,
+	A10_PMU_PERFCTR_CORE_ACTIVE_CYCLE			= 0x2,
+	A10_PMU_PERFCTR_L2_TLB_MISS_INSTRUCTION			= 0xa,
+	A10_PMU_PERFCTR_L2_TLB_MISS_DATA			= 0xb,
+	A10_PMU_PERFCTR_L2C_AGENT_LD				= 0x1a,
+	A10_PMU_PERFCTR_L2C_AGENT_LD_MISS			= 0x1b,
+	A10_PMU_PERFCTR_L2C_AGENT_ST				= 0x1c,
+	A10_PMU_PERFCTR_L2C_AGENT_ST_MISS			= 0x1d,
+	A10_PMU_PERFCTR_SCHEDULE_UOP				= 0x52,
+	A10_PMU_PERFCTR_MAP_REWIND				= 0x75,
+	A10_PMU_PERFCTR_MAP_STALL				= 0x76,
+	A10_PMU_PERFCTR_MAP_INT_UOP				= 0x7c,
+	A10_PMU_PERFCTR_MAP_LDST_UOP				= 0x7d,
+	A10_PMU_PERFCTR_MAP_SIMD_UOP				= 0x7e,
+	A10_PMU_PERFCTR_FLUSH_RESTART_OTHER_NONSPEC		= 0x84,
+	A10_PMU_PERFCTR_INST_A32				= 0x8a,
+	A10_PMU_PERFCTR_INST_T32				= 0x8b,
+	A10_PMU_PERFCTR_INST_ALL				= 0x8c,
+	A10_PMU_PERFCTR_INST_BRANCH				= 0x8d,
+	A10_PMU_PERFCTR_INST_BRANCH_CALL			= 0x8e,
+	A10_PMU_PERFCTR_INST_BRANCH_RET				= 0x8f,
+	A10_PMU_PERFCTR_INST_BRANCH_TAKEN			= 0x90,
+	A10_PMU_PERFCTR_INST_BRANCH_INDIR			= 0x93,
+	A10_PMU_PERFCTR_INST_BRANCH_COND			= 0x94,
+	A10_PMU_PERFCTR_INST_INT_LD				= 0x95,
+	A10_PMU_PERFCTR_INST_INT_ST				= 0x96,
+	A10_PMU_PERFCTR_INST_INT_ALU				= 0x97,
+	A10_PMU_PERFCTR_INST_SIMD_LD				= 0x98,
+	A10_PMU_PERFCTR_INST_SIMD_ST				= 0x99,
+	A10_PMU_PERFCTR_INST_SIMD_ALU				= 0x9a,
+	A10_PMU_PERFCTR_INST_LDST				= 0x9b,
+	A10_PMU_PERFCTR_INST_BARRIER				= 0x9c,
+	A10_PMU_PERFCTR_UNKNOWN_9f				= 0x9f,
+	A10_PMU_PERFCTR_L1D_TLB_ACCESS				= 0xa0,
+	A10_PMU_PERFCTR_L1D_TLB_MISS				= 0xa1,
+	A10_PMU_PERFCTR_L1D_CACHE_MISS_ST			= 0xa2,
+	A10_PMU_PERFCTR_L1D_CACHE_MISS_LD			= 0xa3,
+	A10_PMU_PERFCTR_LD_UNIT_UOP				= 0xa6,
+	A10_PMU_PERFCTR_ST_UNIT_UOP				= 0xa7,
+	A10_PMU_PERFCTR_L1D_CACHE_WRITEBACK			= 0xa8,
+	A10_PMU_PERFCTR_LDST_X64_UOP				= 0xb1,
+	A10_PMU_PERFCTR_ATOMIC_OR_EXCLUSIVE_SUCC		= 0xb3,
+	A10_PMU_PERFCTR_ATOMIC_OR_EXCLUSIVE_FAIL		= 0xb4,
+	A10_PMU_PERFCTR_L1D_CACHE_MISS_LD_NONSPEC		= 0xbf,
+	A10_PMU_PERFCTR_L1D_CACHE_MISS_ST_NONSPEC		= 0xc0,
+	A10_PMU_PERFCTR_L1D_TLB_MISS_NONSPEC			= 0xc1,
+	A10_PMU_PERFCTR_ST_MEMORY_ORDER_VIOLATION_NONSPEC	= 0xc4,
+	A10_PMU_PERFCTR_BRANCH_COND_MISPRED_NONSPEC		= 0xc5,
+	A10_PMU_PERFCTR_BRANCH_INDIR_MISPRED_NONSPEC		= 0xc6,
+	A10_PMU_PERFCTR_BRANCH_RET_INDIR_MISPRED_NONSPEC	= 0xc8,
+	A10_PMU_PERFCTR_BRANCH_CALL_INDIR_MISPRED_NONSPEC	= 0xca,
+	A10_PMU_PERFCTR_BRANCH_MISPRED_NONSPEC			= 0xcb,
+	A10_PMU_PERFCTR_FED_IC_MISS_DEMAND			= 0xd3,
+	A10_PMU_PERFCTR_L1I_TLB_MISS_DEMAND			= 0xd4,
+	A10_PMU_PERFCTR_MAP_DISPATCH_BUBBLE			= 0xd6,
+	A10_PMU_PERFCTR_L1I_CACHE_MISS_DEMAND			= 0xdb,
+	A10_PMU_PERFCTR_FETCH_RESTART				= 0xde,
+	A10_PMU_PERFCTR_ST_NT_UOP				= 0xe5,
+	A10_PMU_PERFCTR_LD_NT_UOP				= 0xe6,
+	A10_PMU_PERFCTR_UNKNOWN_f5				= 0xf5,
+	A10_PMU_PERFCTR_UNKNOWN_f6				= 0xf6,
+	A10_PMU_PERFCTR_UNKNOWN_f7				= 0xf7,
+	A10_PMU_PERFCTR_UNKNOWN_f8				= 0xf8,
+	A10_PMU_PERFCTR_UNKNOWN_fd				= 0xfd,
+	A10_PMU_PERFCTR_LAST					= M1_PMU_CFG_EVENT,
+
+	/*
+	 * From this point onwards, these are not actual HW events,
+	 * but attributes that get stored in hw->config_base.
+	 */
+	A10_PMU_CFG_COUNT_USER					= BIT(8),
+	A10_PMU_CFG_COUNT_KERNEL				= BIT(9),
+};
+
+static const u16 a10_pmu_event_affinity[A10_PMU_PERFCTR_LAST + 1] = {
+	[0 ... A10_PMU_PERFCTR_LAST]				= ANY_BUT_0_1,
+	[A10_PMU_PERFCTR_RETIRE_UOP]				= BIT(7),
+	[A10_PMU_PERFCTR_CORE_ACTIVE_CYCLE]			= ANY_BUT_0_1 | BIT(0),
+	[A10_PMU_PERFCTR_INST_A32]				= BIT(7),
+	[A10_PMU_PERFCTR_INST_T32]				= BIT(7),
+	[A10_PMU_PERFCTR_INST_ALL]				= BIT(7) | BIT(1),
+	[A10_PMU_PERFCTR_INST_BRANCH]				= ONLY_5_6_7,
+	[A10_PMU_PERFCTR_INST_BRANCH_CALL]			= ONLY_5_6_7,
+	[A10_PMU_PERFCTR_INST_BRANCH_RET]			= ONLY_5_6_7,
+	[A10_PMU_PERFCTR_INST_BRANCH_TAKEN]			= ONLY_5_6_7,
+	[A10_PMU_PERFCTR_INST_BRANCH_INDIR]			= ONLY_5_6_7,
+	[A10_PMU_PERFCTR_INST_BRANCH_COND]			= ONLY_5_6_7,
+	[A10_PMU_PERFCTR_INST_INT_LD]				= ONLY_5_6_7,
+	[A10_PMU_PERFCTR_INST_INT_ST]				= ONLY_5_6_7,
+	[A10_PMU_PERFCTR_INST_INT_ALU]				= BIT(7),
+	[A10_PMU_PERFCTR_INST_SIMD_LD]				= ONLY_5_6_7,
+	[A10_PMU_PERFCTR_INST_SIMD_ST]				= ONLY_5_6_7,
+	[A10_PMU_PERFCTR_INST_SIMD_ALU]				= BIT(7),
+	[A10_PMU_PERFCTR_INST_LDST]				= ONLY_5_6_7,
+	[A10_PMU_PERFCTR_INST_BARRIER]				= ONLY_5_6_7,
+	[A10_PMU_PERFCTR_UNKNOWN_9f]				= BIT(7),
+	[A10_PMU_PERFCTR_L1D_CACHE_MISS_LD_NONSPEC]		= ONLY_5_6_7,
+	[A10_PMU_PERFCTR_L1D_CACHE_MISS_ST_NONSPEC]		= ONLY_5_6_7,
+	[A10_PMU_PERFCTR_L1D_TLB_MISS_NONSPEC]			= ONLY_5_6_7,
+	[A10_PMU_PERFCTR_ST_MEMORY_ORDER_VIOLATION_NONSPEC]	= ONLY_5_6_7,
+	[A10_PMU_PERFCTR_BRANCH_COND_MISPRED_NONSPEC]		= ONLY_5_6_7,
+	[A10_PMU_PERFCTR_BRANCH_INDIR_MISPRED_NONSPEC]		= ONLY_5_6_7,
+	[A10_PMU_PERFCTR_BRANCH_RET_INDIR_MISPRED_NONSPEC]	= ONLY_5_6_7,
+	[A10_PMU_PERFCTR_BRANCH_CALL_INDIR_MISPRED_NONSPEC]	= ONLY_5_6_7,
+	[A10_PMU_PERFCTR_BRANCH_MISPRED_NONSPEC]		= ONLY_5_6_7,
+	[A10_PMU_PERFCTR_UNKNOWN_f5]				= ONLY_2_4_6,
+	[A10_PMU_PERFCTR_UNKNOWN_f6]				= ONLY_2_4_6,
+	[A10_PMU_PERFCTR_UNKNOWN_f7]				= ONLY_2_4_6,
+	[A10_PMU_PERFCTR_UNKNOWN_f8]				= ONLY_2_TO_7,
+	[A10_PMU_PERFCTR_UNKNOWN_fd]				= ONLY_2_4_6,
+};
+
 enum m1_pmu_events {
 	M1_PMU_PERFCTR_RETIRE_UOP				= 0x1,
 	M1_PMU_PERFCTR_CORE_ACTIVE_CYCLE			= 0x2,
@@ -909,6 +1022,12 @@ static int a9_pmu_get_event_idx(struct pmu_hw_events *cpuc,
 	return apple_pmu_get_event_idx(cpuc, event, a9_pmu_event_affinity);
 }
 
+static int a10_pmu_get_event_idx(struct pmu_hw_events *cpuc,
+				 struct perf_event *event)
+{
+	return apple_pmu_get_event_idx(cpuc, event, a10_pmu_event_affinity);
+}
+
 static int m1_pmu_get_event_idx(struct pmu_hw_events *cpuc,
 				struct perf_event *event)
 {
@@ -1109,6 +1228,17 @@ static int a9_pmu_twister_init(struct arm_pmu *cpu_pmu)
 	return apple_pmu_init(cpu_pmu, A7_PMU_NR_COUNTERS);
 }
 
+static int a10_pmu_fusion_init(struct arm_pmu *cpu_pmu)
+{
+	cpu_pmu->name = "apple_fusion_pmu";
+	cpu_pmu->get_event_idx	  = a10_pmu_get_event_idx;
+	cpu_pmu->map_event	  = m1_pmu_map_event;
+	cpu_pmu->reset		  = m1_pmu_reset;
+	cpu_pmu->start		  = a7_pmu_start;
+	cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] = &m1_pmu_events_attr_group;
+	return apple_pmu_init(cpu_pmu, M1_PMU_NR_COUNTERS);
+}
+
 static int m1_pmu_ice_init(struct arm_pmu *cpu_pmu)
 {
 	cpu_pmu->name = "apple_icestorm_pmu";
@@ -1158,6 +1288,7 @@ static const struct of_device_id m1_pmu_of_device_ids[] = {
 	{ .compatible = "apple,blizzard-pmu",	.data = m2_pmu_blizzard_init, },
 	{ .compatible = "apple,icestorm-pmu",	.data = m1_pmu_ice_init, },
 	{ .compatible = "apple,firestorm-pmu",	.data = m1_pmu_fire_init, },
+	{ .compatible = "apple,fusion-pmu",	.data = a10_pmu_fusion_init, },
 	{ .compatible = "apple,twister-pmu",	.data = a9_pmu_twister_init, },
 	{ .compatible = "apple,typhoon-pmu",	.data = a8_pmu_typhoon_init, },
 	{ .compatible = "apple,cyclone-pmu",	.data = a7_pmu_cyclone_init, },

-- 
2.52.0



From towinchenmi at gmail.com  Wed Dec 17 08:23:25 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Thu, 18 Dec 2025 00:23:25 +0800
Subject: [PATCH v9 12/21] drivers/perf: apple_m1: Add Apple A11 Support
In-Reply-To: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
References: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
Message-ID: <20251218-apple-cpmu-v9-12-4deadbe65d03@gmail.com>

Add support for the CPU PMU found attached to the performance and
efficiency cores of the Apple A11 SoCs. This PMU can deliver its
interrupt via IRQ or FIQ. Use FIQ as that is faster.

Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
 drivers/perf/apple_m1_cpu_pmu.c | 135 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 135 insertions(+)

diff --git a/drivers/perf/apple_m1_cpu_pmu.c b/drivers/perf/apple_m1_cpu_pmu.c
index 8c252731408224c3596b4157024a3ee885d98d9e..d6bbf6e43eae58caea02585541963dba1ea5a428 100644
--- a/drivers/perf/apple_m1_cpu_pmu.c
+++ b/drivers/perf/apple_m1_cpu_pmu.c
@@ -509,6 +509,111 @@ static const u16 a10_pmu_event_affinity[A10_PMU_PERFCTR_LAST + 1] = {
 	[A10_PMU_PERFCTR_UNKNOWN_fd]				= ONLY_2_4_6,
 };
 
+enum a11_pmu_events {
+	A11_PMU_PERFCTR_RETIRE_UOP				= 0x1,
+	A11_PMU_PERFCTR_CORE_ACTIVE_CYCLE			= 0x2,
+	A11_PMU_PERFCTR_L2_TLB_MISS_INSTRUCTION			= 0xa,
+	A11_PMU_PERFCTR_L2_TLB_MISS_DATA			= 0xb,
+	A11_PMU_PERFCTR_SCHEDULE_UOP				= 0x52,
+	A11_PMU_PERFCTR_MAP_REWIND				= 0x75,
+	A11_PMU_PERFCTR_MAP_STALL				= 0x76,
+	A11_PMU_PERFCTR_MAP_INT_UOP				= 0x7c,
+	A11_PMU_PERFCTR_MAP_LDST_UOP				= 0x7d,
+	A11_PMU_PERFCTR_MAP_SIMD_UOP				= 0x7e,
+	A11_PMU_PERFCTR_FLUSH_RESTART_OTHER_NONSPEC		= 0x84,
+	A11_PMU_PERFCTR_INST_ALL				= 0x8c,
+	A11_PMU_PERFCTR_INST_BRANCH				= 0x8d,
+	A11_PMU_PERFCTR_INST_BRANCH_CALL			= 0x8e,
+	A11_PMU_PERFCTR_INST_BRANCH_RET				= 0x8f,
+	A11_PMU_PERFCTR_INST_BRANCH_TAKEN			= 0x90,
+	A11_PMU_PERFCTR_INST_BRANCH_INDIR			= 0x93,
+	A11_PMU_PERFCTR_INST_BRANCH_COND			= 0x94,
+	A11_PMU_PERFCTR_INST_INT_LD				= 0x95,
+	A11_PMU_PERFCTR_INST_INT_ST				= 0x96,
+	A11_PMU_PERFCTR_INST_INT_ALU				= 0x97,
+	A11_PMU_PERFCTR_INST_SIMD_LD				= 0x98,
+	A11_PMU_PERFCTR_INST_SIMD_ST				= 0x99,
+	A11_PMU_PERFCTR_INST_SIMD_ALU				= 0x9a,
+	A11_PMU_PERFCTR_INST_LDST				= 0x9b,
+	A11_PMU_PERFCTR_INST_BARRIER				= 0x9c,
+	A11_PMU_PERFCTR_UNKNOWN_9f				= 0x9f,
+	A11_PMU_PERFCTR_L1D_TLB_ACCESS				= 0xa0,
+	A11_PMU_PERFCTR_L1D_TLB_MISS				= 0xa1,
+	A11_PMU_PERFCTR_L1D_CACHE_MISS_ST			= 0xa2,
+	A11_PMU_PERFCTR_L1D_CACHE_MISS_LD			= 0xa3,
+	A11_PMU_PERFCTR_LD_UNIT_UOP				= 0xa6,
+	A11_PMU_PERFCTR_ST_UNIT_UOP				= 0xa7,
+	A11_PMU_PERFCTR_L1D_CACHE_WRITEBACK			= 0xa8,
+	A11_PMU_PERFCTR_LDST_X64_UOP				= 0xb1,
+	A11_PMU_PERFCTR_ATOMIC_OR_EXCLUSIVE_SUCC		= 0xb3,
+	A11_PMU_PERFCTR_ATOMIC_OR_EXCLUSIVE_FAIL		= 0xb4,
+	A11_PMU_PERFCTR_L1D_CACHE_MISS_LD_NONSPEC		= 0xbf,
+	A11_PMU_PERFCTR_L1D_CACHE_MISS_ST_NONSPEC		= 0xc0,
+	A11_PMU_PERFCTR_L1D_TLB_MISS_NONSPEC			= 0xc1,
+	A11_PMU_PERFCTR_ST_MEMORY_ORDER_VIOLATION_NONSPEC	= 0xc4,
+	A11_PMU_PERFCTR_BRANCH_COND_MISPRED_NONSPEC		= 0xc5,
+	A11_PMU_PERFCTR_BRANCH_INDIR_MISPRED_NONSPEC		= 0xc6,
+	A11_PMU_PERFCTR_BRANCH_RET_INDIR_MISPRED_NONSPEC	= 0xc8,
+	A11_PMU_PERFCTR_BRANCH_CALL_INDIR_MISPRED_NONSPEC	= 0xca,
+	A11_PMU_PERFCTR_BRANCH_MISPRED_NONSPEC			= 0xcb,
+	A11_PMU_PERFCTR_FED_IC_MISS_DEMAND			= 0xd3,
+	A11_PMU_PERFCTR_L1I_TLB_MISS_DEMAND			= 0xd4,
+	A11_PMU_PERFCTR_MAP_DISPATCH_BUBBLE			= 0xd6,
+	A11_PMU_PERFCTR_L1I_CACHE_MISS_DEMAND			= 0xdb,
+	A11_PMU_PERFCTR_FETCH_RESTART				= 0xde,
+	A11_PMU_PERFCTR_ST_NT_UOP				= 0xe5,
+	A11_PMU_PERFCTR_LD_NT_UOP				= 0xe6,
+	A11_PMU_PERFCTR_UNKNOWN_f5				= 0xf5,
+	A11_PMU_PERFCTR_UNKNOWN_f6				= 0xf6,
+	A11_PMU_PERFCTR_UNKNOWN_f7				= 0xf7,
+	A11_PMU_PERFCTR_UNKNOWN_f8				= 0xf8,
+	A11_PMU_PERFCTR_UNKNOWN_fd				= 0xfd,
+	A11_PMU_PERFCTR_LAST					= M1_PMU_CFG_EVENT,
+
+	/*
+	 * From this point onwards, these are not actual HW events,
+	 * but attributes that get stored in hw->config_base.
+	 */
+	A11_PMU_CFG_COUNT_USER					= BIT(8),
+	A11_PMU_CFG_COUNT_KERNEL				= BIT(9),
+};
+
+static const u16 a11_pmu_event_affinity[A11_PMU_PERFCTR_LAST + 1] = {
+	[0 ... A11_PMU_PERFCTR_LAST]				= ANY_BUT_0_1,
+	[A11_PMU_PERFCTR_RETIRE_UOP]				= BIT(7),
+	[A11_PMU_PERFCTR_CORE_ACTIVE_CYCLE]			= ANY_BUT_0_1 | BIT(0),
+	[A11_PMU_PERFCTR_INST_ALL]				= BIT(7) | BIT(1),
+	[A11_PMU_PERFCTR_INST_BRANCH]				= ONLY_5_6_7,
+	[A11_PMU_PERFCTR_INST_BRANCH_CALL]			= ONLY_5_6_7,
+	[A11_PMU_PERFCTR_INST_BRANCH_RET]			= ONLY_5_6_7,
+	[A11_PMU_PERFCTR_INST_BRANCH_TAKEN]			= ONLY_5_6_7,
+	[A11_PMU_PERFCTR_INST_BRANCH_INDIR]			= ONLY_5_6_7,
+	[A11_PMU_PERFCTR_INST_BRANCH_COND]			= ONLY_5_6_7,
+	[A11_PMU_PERFCTR_INST_INT_LD]				= ONLY_5_6_7,
+	[A11_PMU_PERFCTR_INST_INT_ST]				= ONLY_5_6_7,
+	[A11_PMU_PERFCTR_INST_INT_ALU]				= BIT(7),
+	[A11_PMU_PERFCTR_INST_SIMD_LD]				= ONLY_5_6_7,
+	[A11_PMU_PERFCTR_INST_SIMD_ST]				= ONLY_5_6_7,
+	[A11_PMU_PERFCTR_INST_SIMD_ALU]				= BIT(7),
+	[A11_PMU_PERFCTR_INST_LDST]				= ONLY_5_6_7,
+	[A11_PMU_PERFCTR_INST_BARRIER]				= ONLY_5_6_7,
+	[A11_PMU_PERFCTR_UNKNOWN_9f]				= BIT(7),
+	[A11_PMU_PERFCTR_L1D_CACHE_MISS_LD_NONSPEC]		= ONLY_5_6_7,
+	[A11_PMU_PERFCTR_L1D_CACHE_MISS_ST_NONSPEC]		= ONLY_5_6_7,
+	[A11_PMU_PERFCTR_L1D_TLB_MISS_NONSPEC]			= ONLY_5_6_7,
+	[A11_PMU_PERFCTR_ST_MEMORY_ORDER_VIOLATION_NONSPEC]	= ONLY_5_6_7,
+	[A11_PMU_PERFCTR_BRANCH_COND_MISPRED_NONSPEC]		= ONLY_5_6_7,
+	[A11_PMU_PERFCTR_BRANCH_INDIR_MISPRED_NONSPEC]		= ONLY_5_6_7,
+	[A11_PMU_PERFCTR_BRANCH_RET_INDIR_MISPRED_NONSPEC]	= ONLY_5_6_7,
+	[A11_PMU_PERFCTR_BRANCH_CALL_INDIR_MISPRED_NONSPEC]	= ONLY_5_6_7,
+	[A11_PMU_PERFCTR_BRANCH_MISPRED_NONSPEC]		= ONLY_5_6_7,
+	[A11_PMU_PERFCTR_UNKNOWN_f5]				= ONLY_2_4_6,
+	[A11_PMU_PERFCTR_UNKNOWN_f6]				= ONLY_2_4_6,
+	[A11_PMU_PERFCTR_UNKNOWN_f7]				= ONLY_2_4_6,
+	[A11_PMU_PERFCTR_UNKNOWN_f8]				= ONLY_2_TO_7,
+	[A11_PMU_PERFCTR_UNKNOWN_fd]				= ONLY_2_4_6,
+};
+
 enum m1_pmu_events {
 	M1_PMU_PERFCTR_RETIRE_UOP				= 0x1,
 	M1_PMU_PERFCTR_CORE_ACTIVE_CYCLE			= 0x2,
@@ -1028,6 +1133,12 @@ static int a10_pmu_get_event_idx(struct pmu_hw_events *cpuc,
 	return apple_pmu_get_event_idx(cpuc, event, a10_pmu_event_affinity);
 }
 
+static int a11_pmu_get_event_idx(struct pmu_hw_events *cpuc,
+				 struct perf_event *event)
+{
+	return apple_pmu_get_event_idx(cpuc, event, a11_pmu_event_affinity);
+}
+
 static int m1_pmu_get_event_idx(struct pmu_hw_events *cpuc,
 				struct perf_event *event)
 {
@@ -1239,6 +1350,28 @@ static int a10_pmu_fusion_init(struct arm_pmu *cpu_pmu)
 	return apple_pmu_init(cpu_pmu, M1_PMU_NR_COUNTERS);
 }
 
+static int a11_pmu_monsoon_init(struct arm_pmu *cpu_pmu)
+{
+	cpu_pmu->name = "apple_monsoon_pmu";
+	cpu_pmu->get_event_idx	  = a11_pmu_get_event_idx;
+	cpu_pmu->map_event	  = m1_pmu_map_event;
+	cpu_pmu->reset		  = m1_pmu_reset;
+	cpu_pmu->start		  = m1_pmu_start;
+	cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] = &m1_pmu_events_attr_group;
+	return apple_pmu_init(cpu_pmu, M1_PMU_NR_COUNTERS);
+}
+
+static int a11_pmu_mistral_init(struct arm_pmu *cpu_pmu)
+{
+	cpu_pmu->name = "apple_mistral_pmu";
+	cpu_pmu->get_event_idx	  = a11_pmu_get_event_idx;
+	cpu_pmu->map_event	  = m1_pmu_map_event;
+	cpu_pmu->reset		  = m1_pmu_reset;
+	cpu_pmu->start		  = m1_pmu_start;
+	cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] = &m1_pmu_events_attr_group;
+	return apple_pmu_init(cpu_pmu, M1_PMU_NR_COUNTERS);
+}
+
 static int m1_pmu_ice_init(struct arm_pmu *cpu_pmu)
 {
 	cpu_pmu->name = "apple_icestorm_pmu";
@@ -1288,6 +1421,8 @@ static const struct of_device_id m1_pmu_of_device_ids[] = {
 	{ .compatible = "apple,blizzard-pmu",	.data = m2_pmu_blizzard_init, },
 	{ .compatible = "apple,icestorm-pmu",	.data = m1_pmu_ice_init, },
 	{ .compatible = "apple,firestorm-pmu",	.data = m1_pmu_fire_init, },
+	{ .compatible = "apple,monsoon-pmu",	.data = a11_pmu_monsoon_init, },
+	{ .compatible = "apple,mistral-pmu",	.data = a11_pmu_mistral_init, },
 	{ .compatible = "apple,fusion-pmu",	.data = a10_pmu_fusion_init, },
 	{ .compatible = "apple,twister-pmu",	.data = a9_pmu_twister_init, },
 	{ .compatible = "apple,typhoon-pmu",	.data = a8_pmu_typhoon_init, },

-- 
2.52.0



From towinchenmi at gmail.com  Wed Dec 17 08:23:26 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Thu, 18 Dec 2025 00:23:26 +0800
Subject: [PATCH v9 13/21] arm64: dts: apple: s5l8960x: Add CPU PMU nodes
In-Reply-To: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
References: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
Message-ID: <20251218-apple-cpmu-v9-13-4deadbe65d03@gmail.com>

Add CPU PMU nodes for Apple A7 SoC.

Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
 arch/arm64/boot/dts/apple/s5l8960x.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/boot/dts/apple/s5l8960x.dtsi b/arch/arm64/boot/dts/apple/s5l8960x.dtsi
index 462ffdd348fc893d8e1d597b11d063dc5f88bdf3..d7a9cf1bb4911805a946d64e5892c1fe4b832186 100644
--- a/arch/arm64/boot/dts/apple/s5l8960x.dtsi
+++ b/arch/arm64/boot/dts/apple/s5l8960x.dtsi
@@ -227,6 +227,14 @@ timer {
 		interrupts = <AIC_FIQ AIC_TMR_GUEST_PHYS IRQ_TYPE_LEVEL_HIGH>,
 			     <AIC_FIQ AIC_TMR_GUEST_VIRT IRQ_TYPE_LEVEL_HIGH>;
 	};
+
+	pmu {
+		compatible = "apple,cyclone-pmu";
+		interrupt-parent = <&aic>;
+		interrupts = <AIC_IRQ 178 IRQ_TYPE_LEVEL_HIGH>,
+			     <AIC_IRQ 181 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-affinity = <&cpu0 &cpu1>;
+	};
 };
 
 #include "s5l8960x-pmgr.dtsi"

-- 
2.52.0



From towinchenmi at gmail.com  Wed Dec 17 08:23:27 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Thu, 18 Dec 2025 00:23:27 +0800
Subject: [PATCH v9 14/21] arm64: dts: apple: t7000: Add CPU PMU nodes
In-Reply-To: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
References: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
Message-ID: <20251218-apple-cpmu-v9-14-4deadbe65d03@gmail.com>

Add CPU PMU nodes for Apple A8 SoC.

Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
 arch/arm64/boot/dts/apple/t7000.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/boot/dts/apple/t7000.dtsi b/arch/arm64/boot/dts/apple/t7000.dtsi
index 0342455d344474d34f7924a089bf5f5915e68d55..a416cf8204173d4e45eb7baab42302eefd0e55ab 100644
--- a/arch/arm64/boot/dts/apple/t7000.dtsi
+++ b/arch/arm64/boot/dts/apple/t7000.dtsi
@@ -282,6 +282,14 @@ timer {
 		interrupts = <AIC_FIQ AIC_TMR_GUEST_PHYS IRQ_TYPE_LEVEL_HIGH>,
 			     <AIC_FIQ AIC_TMR_GUEST_VIRT IRQ_TYPE_LEVEL_HIGH>;
 	};
+
+	pmu {
+		compatible = "apple,typhoon-pmu";
+		interrupt-parent = <&aic>;
+		interrupts = <AIC_IRQ 75 IRQ_TYPE_LEVEL_HIGH>,
+			     <AIC_IRQ 78 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-affinity = <&cpu0 &cpu1>;
+	};
 };
 
 #include "t7000-pmgr.dtsi"

-- 
2.52.0



From towinchenmi at gmail.com  Wed Dec 17 08:23:28 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Thu, 18 Dec 2025 00:23:28 +0800
Subject: [PATCH v9 15/21] arm64: dts: apple: t7001: Add CPU PMU nodes
In-Reply-To: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
References: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
Message-ID: <20251218-apple-cpmu-v9-15-4deadbe65d03@gmail.com>

Add CPU PMU nodes for Apple A8X SoC.

Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
 arch/arm64/boot/dts/apple/t7001.dtsi | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm64/boot/dts/apple/t7001.dtsi b/arch/arm64/boot/dts/apple/t7001.dtsi
index e1afb05423698223ebc15f2ae347e73fb46c7c24..b62122ea40f00a54ae42dc3cd0f864f25888489c 100644
--- a/arch/arm64/boot/dts/apple/t7001.dtsi
+++ b/arch/arm64/boot/dts/apple/t7001.dtsi
@@ -275,6 +275,15 @@ timer {
 		interrupts = <AIC_FIQ AIC_TMR_GUEST_PHYS IRQ_TYPE_LEVEL_HIGH>,
 			     <AIC_FIQ AIC_TMR_GUEST_VIRT IRQ_TYPE_LEVEL_HIGH>;
 	};
+
+	pmu {
+		compatible = "apple,typhoon-pmu";
+		interrupt-parent = <&aic>;
+		interrupts = <AIC_IRQ 75 IRQ_TYPE_LEVEL_HIGH>,
+			     <AIC_IRQ 78 IRQ_TYPE_LEVEL_HIGH>,
+			     <AIC_IRQ 81 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-affinity = <&cpu0 &cpu1 &cpu2>;
+	};
 };
 
 #include "t7001-pmgr.dtsi"

-- 
2.52.0



From towinchenmi at gmail.com  Wed Dec 17 08:23:29 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Thu, 18 Dec 2025 00:23:29 +0800
Subject: [PATCH v9 16/21] arm64: dts: apple: s800-0-3: Add CPU PMU nodes
In-Reply-To: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
References: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
Message-ID: <20251218-apple-cpmu-v9-16-4deadbe65d03@gmail.com>

Add CPU PMU nodes for Apple A9 SoC.

Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
 arch/arm64/boot/dts/apple/s800-0-3.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/boot/dts/apple/s800-0-3.dtsi b/arch/arm64/boot/dts/apple/s800-0-3.dtsi
index bb38662b7d2e0b70e18b6870b706789b1cb242af..aa372aefc995334b1489953c16251c8ff9b94d98 100644
--- a/arch/arm64/boot/dts/apple/s800-0-3.dtsi
+++ b/arch/arm64/boot/dts/apple/s800-0-3.dtsi
@@ -237,6 +237,14 @@ timer {
 		interrupts = <AIC_FIQ AIC_TMR_GUEST_PHYS IRQ_TYPE_LEVEL_HIGH>,
 			     <AIC_FIQ AIC_TMR_GUEST_VIRT IRQ_TYPE_LEVEL_HIGH>;
 	};
+
+	pmu {
+		compatible = "apple,twister-pmu";
+		interrupt-parent = <&aic>;
+		interrupts = <AIC_IRQ 76 IRQ_TYPE_LEVEL_HIGH>,
+			     <AIC_IRQ 79 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-affinity = <&cpu0 &cpu1>;
+	};
 };
 
 #include "s800-0-3-pmgr.dtsi"

-- 
2.52.0



From towinchenmi at gmail.com  Wed Dec 17 08:23:30 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Thu, 18 Dec 2025 00:23:30 +0800
Subject: [PATCH v9 17/21] arm64: dts: apple: s8001: Add CPU PMU nodes
In-Reply-To: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
References: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
Message-ID: <20251218-apple-cpmu-v9-17-4deadbe65d03@gmail.com>

Add CPU PMU nodes for Apple A9X SoC.

Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
 arch/arm64/boot/dts/apple/s8001.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/boot/dts/apple/s8001.dtsi b/arch/arm64/boot/dts/apple/s8001.dtsi
index b5b00dca6ffa4caa1d504860693da001a8ced80e..83c5c479c87fc1ae1bb7c6889aed9a71fb55d29c 100644
--- a/arch/arm64/boot/dts/apple/s8001.dtsi
+++ b/arch/arm64/boot/dts/apple/s8001.dtsi
@@ -298,6 +298,14 @@ timer {
 		interrupts = <AIC_FIQ AIC_TMR_GUEST_PHYS IRQ_TYPE_LEVEL_HIGH>,
 			     <AIC_FIQ AIC_TMR_GUEST_VIRT IRQ_TYPE_LEVEL_HIGH>;
 	};
+
+	pmu {
+		compatible = "apple,twister-pmu";
+		interrupt-parent = <&aic>;
+		interrupts = <AIC_IRQ 83 IRQ_TYPE_LEVEL_HIGH>,
+			     <AIC_IRQ 86 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-affinity = <&cpu0 &cpu1>;
+	};
 };
 
 #include "s8001-pmgr.dtsi"

-- 
2.52.0



From towinchenmi at gmail.com  Wed Dec 17 08:23:31 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Thu, 18 Dec 2025 00:23:31 +0800
Subject: [PATCH v9 18/21] arm64: dts: apple: t8010: Add CPU PMU nodes
In-Reply-To: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
References: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
Message-ID: <20251218-apple-cpmu-v9-18-4deadbe65d03@gmail.com>

Add CPU PMU nodes for Apple A10 SoC.

Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
 arch/arm64/boot/dts/apple/t8010.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/boot/dts/apple/t8010.dtsi b/arch/arm64/boot/dts/apple/t8010.dtsi
index 522b3896aa87eb290dc831cbbf2cc8e593844097..3cf1eef5cc261fa1dc699e8b5c9991e2215a6010 100644
--- a/arch/arm64/boot/dts/apple/t8010.dtsi
+++ b/arch/arm64/boot/dts/apple/t8010.dtsi
@@ -332,6 +332,14 @@ timer {
 		interrupts = <AIC_FIQ AIC_TMR_GUEST_PHYS IRQ_TYPE_LEVEL_HIGH>,
 			     <AIC_FIQ AIC_TMR_GUEST_VIRT IRQ_TYPE_LEVEL_HIGH>;
 	};
+
+	pmu {
+		compatible = "apple,fusion-pmu";
+		interrupt-parent = <&aic>;
+		interrupts = <AIC_IRQ 83 IRQ_TYPE_LEVEL_HIGH>,
+			     <AIC_IRQ 86 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-affinity = <&cpu0 &cpu1>;
+	};
 };
 
 #include "t8010-pmgr.dtsi"

-- 
2.52.0



From towinchenmi at gmail.com  Wed Dec 17 08:23:32 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Thu, 18 Dec 2025 00:23:32 +0800
Subject: [PATCH v9 19/21] arm64: dts: apple: t8011: Add CPU PMU nodes
In-Reply-To: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
References: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
Message-ID: <20251218-apple-cpmu-v9-19-4deadbe65d03@gmail.com>

Add CPU PMU nodse for Apple A10X SoC.

Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
 arch/arm64/boot/dts/apple/t8011.dtsi | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm64/boot/dts/apple/t8011.dtsi b/arch/arm64/boot/dts/apple/t8011.dtsi
index 039aa4d1e887625e7b6ad789bfd9aa032dc58d01..7f7b0230cd648eba2533f860622f683771197bff 100644
--- a/arch/arm64/boot/dts/apple/t8011.dtsi
+++ b/arch/arm64/boot/dts/apple/t8011.dtsi
@@ -329,6 +329,15 @@ timer {
 		interrupts = <AIC_FIQ AIC_TMR_GUEST_PHYS IRQ_TYPE_LEVEL_HIGH>,
 			     <AIC_FIQ AIC_TMR_GUEST_VIRT IRQ_TYPE_LEVEL_HIGH>;
 	};
+
+	pmu {
+		compatible = "apple,fusion-pmu";
+		interrupt-parent = <&aic>;
+		interrupts = <AIC_IRQ 83 IRQ_TYPE_LEVEL_HIGH>,
+			     <AIC_IRQ 86 IRQ_TYPE_LEVEL_HIGH>,
+			     <AIC_IRQ 89 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-affinity = <&cpu0 &cpu1 &cpu2>;
+	};
 };
 
 #include "t8011-pmgr.dtsi"

-- 
2.52.0



From towinchenmi at gmail.com  Wed Dec 17 08:23:33 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Thu, 18 Dec 2025 00:23:33 +0800
Subject: [PATCH v9 20/21] arm64: dts: apple: t8012: Add CPU PMU nodes
In-Reply-To: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
References: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
Message-ID: <20251218-apple-cpmu-v9-20-4deadbe65d03@gmail.com>

Add CPU PMU nodes for Apple T2 SoC.

Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
 arch/arm64/boot/dts/apple/t8012.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/boot/dts/apple/t8012.dtsi b/arch/arm64/boot/dts/apple/t8012.dtsi
index e7923814169bd4060706945561910ed1d5c2e0c8..579560de1aef8c311cbf66c60a2111e2d5ac37c5 100644
--- a/arch/arm64/boot/dts/apple/t8012.dtsi
+++ b/arch/arm64/boot/dts/apple/t8012.dtsi
@@ -297,6 +297,14 @@ timer {
 		interrupts = <AIC_FIQ AIC_TMR_GUEST_PHYS IRQ_TYPE_LEVEL_HIGH>,
 			     <AIC_FIQ AIC_TMR_GUEST_VIRT IRQ_TYPE_LEVEL_HIGH>;
 	};
+
+	pmu {
+		compatible = "apple,fusion-pmu";
+		interrupt-parent = <&aic>;
+		interrupts = <AIC_IRQ 86 IRQ_TYPE_LEVEL_HIGH>,
+			     <AIC_IRQ 89 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-affinity = <&cpu0 &cpu1>;
+	};
 };
 
 #include "t8012-pmgr.dtsi"

-- 
2.52.0



From towinchenmi at gmail.com  Wed Dec 17 08:23:34 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Thu, 18 Dec 2025 00:23:34 +0800
Subject: [PATCH v9 21/21] arm64: dts: apple: t8015: Add CPU PMU nodes
In-Reply-To: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
References: <20251218-apple-cpmu-v9-0-4deadbe65d03@gmail.com>
Message-ID: <20251218-apple-cpmu-v9-21-4deadbe65d03@gmail.com>

Add CPU PMU nodes for Apple A11 SoC.

Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
 arch/arm64/boot/dts/apple/t8015.dtsi | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/arch/arm64/boot/dts/apple/t8015.dtsi b/arch/arm64/boot/dts/apple/t8015.dtsi
index 586d3cf1f3751d9ee23262e55fd692bfee86c13f..0c1ebab56d6b36ed5362a042ecb6cecef7c97f64 100644
--- a/arch/arm64/boot/dts/apple/t8015.dtsi
+++ b/arch/arm64/boot/dts/apple/t8015.dtsi
@@ -341,6 +341,18 @@ aic: interrupt-controller at 232100000 {
 			#interrupt-cells = <3>;
 			interrupt-controller;
 			power-domains = <&ps_aic>;
+
+			affinities {
+				e-core-pmu-affinity {
+					apple,fiq-index = <AIC_CPU_PMU_E>;
+					cpus = <&cpu_e0 &cpu_e1 &cpu_e2 &cpu_e3>;
+				};
+
+				p-core-pmu-affinity {
+					apple,fiq-index = <AIC_CPU_PMU_P>;
+					cpus = <&cpu_p0 &cpu_p1>;
+				};
+			};
 		};
 
 		pmgr: power-management at 232000000 {
@@ -530,6 +542,18 @@ timer {
 		interrupts = <AIC_FIQ AIC_TMR_GUEST_PHYS IRQ_TYPE_LEVEL_HIGH>,
 			     <AIC_FIQ AIC_TMR_GUEST_VIRT IRQ_TYPE_LEVEL_HIGH>;
 	};
+
+	pmu-e {
+		compatible = "apple,mistral-pmu";
+		interrupt-parent = <&aic>;
+		interrupts = <AIC_FIQ AIC_CPU_PMU_E IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	pmu-p {
+		compatible = "apple,monsoon-pmu";
+		interrupt-parent = <&aic>;
+		interrupts = <AIC_FIQ AIC_CPU_PMU_P IRQ_TYPE_LEVEL_HIGH>;
+	};
 };
 
 #include "t8015-pmgr.dtsi"

-- 
2.52.0



From puranjay at kernel.org  Wed Dec 17 08:28:25 2025
From: puranjay at kernel.org (Puranjay Mohan)
Date: Wed, 17 Dec 2025 08:28:25 -0800
Subject: [PATCH bpf-next 0/2] bpf: Optimize recursion detection on arm64
Message-ID: <20251217162830.2597286-1-puranjay@kernel.org>

BPF programs detect recursion using a per-CPU 'active' flag in struct
bpf_prog. The trampoline currently sets/clears this flag with atomic
operations.

On some arm64 platforms (e.g., Neoverse V2 with LSE), per-CPU atomic
operations are relatively slow. Unlike x86_64 - where per-CPU updates
can avoid cross-core atomicity, arm64 LSE atomics are always atomic
across all cores, which is unnecessary overhead for strictly per-CPU
state.

This patch removes atomics from the recursion detection path on arm64.

It was discovered in [1] that per-CPU atomics that don't return a value
were extremely slow on some arm64 platforms, Catalin added a fix in
commit 535fdfc5a228 ("arm64: Use load LSE atomics for the non-return
per-CPU atomic operations") to solve this issue, but it seems to have
caused a regression on the fentry benchmark.

Using the fentry benchmark from the bpf selftests shows the following:

  ./tools/testing/selftests/bpf/bench trig-fentry

 +---------------------------------------------+------------------------+
 |               Configuration                 | Total Operations (M/s) |
 +---------------------------------------------+------------------------+
 | bpf-next/master with Catalin?s fix reverted |    40.033 ? 0.090      |
 |---------------------------------------------|------------------------|
 | bpf-next/master                             |    34.617 ? 0.018      |
 | bpf-next/master with this change            |    46.122 ? 0.020      |
 +---------------------------------------------+------------------------+

All benchmarks were run on a KVM based vm with Neoverse-V2 and 8 cpus.

This patch yields a 33% improvement in this benchmark compared to
bpf-next. Notably, reverting Catalin's fix also results in a performance
gain for this benchmark, which is interesting but expected.

For completeness, this benchmark was also run with the change enabled on
x86-64, which resulted in a 30% regression in the fentry benchmark. So,
it is only enabled on arm64.

[1] https://lore.kernel.org/all/e7d539ed-ced0-4b96-8ecd-048a5b803b85 at paulmck-laptop/

Puranjay Mohan (2):
  bpf: move recursion detection logic to helpers
  bpf: arm64: Optimize recursion detection by not using atomics

 include/linux/bpf.h      | 35 ++++++++++++++++++++++++++++++++++-
 kernel/bpf/core.c        |  3 ++-
 kernel/bpf/trampoline.c  |  8 ++++----
 kernel/trace/bpf_trace.c |  4 ++--
 4 files changed, 42 insertions(+), 8 deletions(-)


base-commit: ec439c38013550420aecc15988ae6acb670838c1
-- 
2.47.3



From puranjay at kernel.org  Wed Dec 17 08:28:26 2025
From: puranjay at kernel.org (Puranjay Mohan)
Date: Wed, 17 Dec 2025 08:28:26 -0800
Subject: [PATCH bpf-next 1/2] bpf: move recursion detection logic to helpers
In-Reply-To: <20251217162830.2597286-1-puranjay@kernel.org>
References: <20251217162830.2597286-1-puranjay@kernel.org>
Message-ID: <20251217162830.2597286-2-puranjay@kernel.org>

BPF programs detect recursion by doing atomic inc/dec on a per-cpu
active counter from the trampoline. Create two helpers for operations on
this active counter, this makes it easy to changes the recursion
detection logic in future.

This change makes no functional changes.

Signed-off-by: Puranjay Mohan <puranjay at kernel.org>
---
 include/linux/bpf.h      | 10 ++++++++++
 kernel/bpf/trampoline.c  |  8 ++++----
 kernel/trace/bpf_trace.c |  4 ++--
 3 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index bb3847caeae1..2da986136d26 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -2004,6 +2004,16 @@ struct bpf_struct_ops_common_value {
 	enum bpf_struct_ops_state state;
 };
 
+static inline bool bpf_prog_get_recursion_context(struct bpf_prog *prog)
+{
+	return this_cpu_inc_return(*(prog->active)) == 1;
+}
+
+static inline void bpf_prog_put_recursion_context(struct bpf_prog *prog)
+{
+	this_cpu_dec(*(prog->active));
+}
+
 #if defined(CONFIG_BPF_JIT) && defined(CONFIG_BPF_SYSCALL)
 /* This macro helps developer to register a struct_ops type and generate
  * type information correctly. Developers should use this macro to register
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index 976d89011b15..2a125d063e62 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -949,7 +949,7 @@ static u64 notrace __bpf_prog_enter_recur(struct bpf_prog *prog, struct bpf_tram
 
 	run_ctx->saved_run_ctx = bpf_set_run_ctx(&run_ctx->run_ctx);
 
-	if (unlikely(this_cpu_inc_return(*(prog->active)) != 1)) {
+	if (unlikely(!bpf_prog_get_recursion_context(prog))) {
 		bpf_prog_inc_misses_counter(prog);
 		if (prog->aux->recursion_detected)
 			prog->aux->recursion_detected(prog);
@@ -993,7 +993,7 @@ static void notrace __bpf_prog_exit_recur(struct bpf_prog *prog, u64 start,
 	bpf_reset_run_ctx(run_ctx->saved_run_ctx);
 
 	update_prog_stats(prog, start);
-	this_cpu_dec(*(prog->active));
+	bpf_prog_put_recursion_context(prog);
 	rcu_read_unlock_migrate();
 }
 
@@ -1029,7 +1029,7 @@ u64 notrace __bpf_prog_enter_sleepable_recur(struct bpf_prog *prog,
 
 	run_ctx->saved_run_ctx = bpf_set_run_ctx(&run_ctx->run_ctx);
 
-	if (unlikely(this_cpu_inc_return(*(prog->active)) != 1)) {
+	if (unlikely(!bpf_prog_get_recursion_context(prog))) {
 		bpf_prog_inc_misses_counter(prog);
 		if (prog->aux->recursion_detected)
 			prog->aux->recursion_detected(prog);
@@ -1044,7 +1044,7 @@ void notrace __bpf_prog_exit_sleepable_recur(struct bpf_prog *prog, u64 start,
 	bpf_reset_run_ctx(run_ctx->saved_run_ctx);
 
 	update_prog_stats(prog, start);
-	this_cpu_dec(*(prog->active));
+	bpf_prog_put_recursion_context(prog);
 	migrate_enable();
 	rcu_read_unlock_trace();
 }
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index fe28d86f7c35..6e076485bf70 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -2063,7 +2063,7 @@ void __bpf_trace_run(struct bpf_raw_tp_link *link, u64 *args)
 	struct bpf_trace_run_ctx run_ctx;
 
 	cant_sleep();
-	if (unlikely(this_cpu_inc_return(*(prog->active)) != 1)) {
+	if (unlikely(!bpf_prog_get_recursion_context(prog))) {
 		bpf_prog_inc_misses_counter(prog);
 		goto out;
 	}
@@ -2077,7 +2077,7 @@ void __bpf_trace_run(struct bpf_raw_tp_link *link, u64 *args)
 
 	bpf_reset_run_ctx(old_run_ctx);
 out:
-	this_cpu_dec(*(prog->active));
+	bpf_prog_put_recursion_context(prog);
 }
 
 #define UNPACK(...)			__VA_ARGS__
-- 
2.47.3



From puranjay at kernel.org  Wed Dec 17 08:28:27 2025
From: puranjay at kernel.org (Puranjay Mohan)
Date: Wed, 17 Dec 2025 08:28:27 -0800
Subject: [PATCH bpf-next 2/2] bpf: arm64: Optimize recursion detection by not using atomics
In-Reply-To: <20251217162830.2597286-1-puranjay@kernel.org>
References: <20251217162830.2597286-1-puranjay@kernel.org>
Message-ID: <20251217162830.2597286-3-puranjay@kernel.org>

BPF programs detect recursion using a per-CPU 'active' flag in struct
bpf_prog. The trampoline currently sets/clears this flag with atomic
operations.

On some arm64 platforms (e.g., Neoverse V2 with LSE), per-CPU atomic
operations are relatively slow. Unlike x86_64 - where per-CPU updates
can avoid cross-core atomicity, arm64 LSE atomics are always atomic
across all cores, which is unnecessary overhead for strictly per-CPU
state.

This patch removes atomics from the recursion detection path on arm64 by
changing 'active' to a per-CPU array of four u8 counters, one per
context: {NMI, hard-irq, soft-irq, normal}. The running context uses a
non-atomic increment/decrement on its element.  After increment,
recursion is detected by reading the array as a u32 and verifying that
only the expected element changed; any change in another element
indicates inter-context recursion, and a value > 1 in the same element
indicates same-context recursion.

For example, starting from {0,0,0,0}, a normal-context trigger changes
the array to {0,0,0,1}.  If an NMI arrives on the same CPU and triggers
the program, the array becomes {1,0,0,1}. When the NMI context checks
the u32 against the expected mask for normal (0x00000001), it observes
0x01000001 and correctly reports recursion. Same-context recursion is
detected analogously.

Signed-off-by: Puranjay Mohan <puranjay at kernel.org>
---
 include/linux/bpf.h | 25 ++++++++++++++++++++++++-
 kernel/bpf/core.c   |  3 ++-
 2 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 2da986136d26..654fb94bf60c 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -31,6 +31,7 @@
 #include <linux/static_call.h>
 #include <linux/memcontrol.h>
 #include <linux/cfi.h>
+#include <linux/unaligned.h>
 #include <asm/rqspinlock.h>
 
 struct bpf_verifier_env;
@@ -1746,6 +1747,8 @@ struct bpf_prog_aux {
 	struct bpf_map __rcu *st_ops_assoc;
 };
 
+#define BPF_NR_CONTEXTS        4       /* normal, softirq, hardirq, NMI */
+
 struct bpf_prog {
 	u16			pages;		/* Number of allocated pages */
 	u16			jited:1,	/* Is our filter JIT'ed? */
@@ -1772,7 +1775,7 @@ struct bpf_prog {
 		u8 tag[BPF_TAG_SIZE];
 	};
 	struct bpf_prog_stats __percpu *stats;
-	int __percpu		*active;
+	u8 __percpu		*active;	/* u8[BPF_NR_CONTEXTS] for rerecursion protection */
 	unsigned int		(*bpf_func)(const void *ctx,
 					    const struct bpf_insn *insn);
 	struct bpf_prog_aux	*aux;		/* Auxiliary fields */
@@ -2006,12 +2009,32 @@ struct bpf_struct_ops_common_value {
 
 static inline bool bpf_prog_get_recursion_context(struct bpf_prog *prog)
 {
+#ifdef CONFIG_ARM64
+	u8 rctx = interrupt_context_level();
+	u8 *active = this_cpu_ptr(prog->active);
+
+	active[rctx]++;
+	barrier();
+	if (get_unaligned_le32(active) != BIT(rctx * 8))
+		return false;
+
+	return true;
+#else
 	return this_cpu_inc_return(*(prog->active)) == 1;
+#endif
 }
 
 static inline void bpf_prog_put_recursion_context(struct bpf_prog *prog)
 {
+#ifdef CONFIG_ARM64
+	u8 rctx = interrupt_context_level();
+	u8 *active = this_cpu_ptr(prog->active);
+
+	barrier();
+	active[rctx]--;
+#else
 	this_cpu_dec(*(prog->active));
+#endif
 }
 
 #if defined(CONFIG_BPF_JIT) && defined(CONFIG_BPF_SYSCALL)
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index c66316e32563..b5063acfcf92 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -112,7 +112,8 @@ struct bpf_prog *bpf_prog_alloc_no_stats(unsigned int size, gfp_t gfp_extra_flag
 		vfree(fp);
 		return NULL;
 	}
-	fp->active = alloc_percpu_gfp(int, bpf_memcg_flags(GFP_KERNEL | gfp_extra_flags));
+	fp->active = __alloc_percpu_gfp(sizeof(u8[BPF_NR_CONTEXTS]), 8,
+					bpf_memcg_flags(GFP_KERNEL | gfp_extra_flags));
 	if (!fp->active) {
 		vfree(fp);
 		kfree(aux);
-- 
2.47.3



From ryan.roberts at arm.com  Wed Dec 17 08:39:09 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Wed, 17 Dec 2025 16:39:09 +0000
Subject: [PATCH v2 2/3] mm: rmap: support batched checks of the references
 for large folios
In-Reply-To: <545dba5e899634bc6c8ca782417d16fef3bd049f.1765439381.git.baolin.wang@linux.alibaba.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <545dba5e899634bc6c8ca782417d16fef3bd049f.1765439381.git.baolin.wang@linux.alibaba.com>
Message-ID: <cb4d7243-d8c6-4706-a254-6f5afc148910@arm.com>

On 11/12/2025 08:16, Baolin Wang wrote:
> Currently, folio_referenced_one() always checks the young flag for each PTE
> sequentially, which is inefficient for large folios. This inefficiency is
> especially noticeable when reclaiming clean file-backed large folios, where
> folio_referenced() is observed as a significant performance hotspot.
> 
> Moreover, on Arm architecture, which supports contiguous PTEs, there is already
> an optimization to clear the young flags for PTEs within a contiguous range.
> However, this is not sufficient. We can extend this to perform batched operations
> for the entire large folio (which might exceed the contiguous range: CONT_PTE_SIZE).
> 
> Introduce a new API: clear_flush_young_ptes() to facilitate batched checking
> of the young flags and flushing TLB entries, thereby improving performance
> during large folio reclamation.
> 
> Performance testing:
> Allocate 10G clean file-backed folios by mmap() in a memory cgroup, and try to
> reclaim 8G file-backed folios via the memory.reclaim interface. I can observe
> 33% performance improvement on my Arm64 32-core server (and 10%+ improvement
> on my X86 machine). Meanwhile, the hotspot folio_check_references() dropped
> from approximately 35% to around 5%.
> 
> W/o patchset:
> real	0m1.518s
> user	0m0.000s
> sys	0m1.518s
> 
> W/ patchset:
> real	0m1.018s
> user	0m0.000s
> sys	0m1.018s
> 
> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
> ---
>  arch/arm64/include/asm/pgtable.h | 11 +++++++++++
>  include/linux/mmu_notifier.h     |  9 +++++----
>  include/linux/pgtable.h          | 19 +++++++++++++++++++
>  mm/rmap.c                        | 22 ++++++++++++++++++++--
>  4 files changed, 55 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
> index e03034683156..a865bd8c46a3 100644
> --- a/arch/arm64/include/asm/pgtable.h
> +++ b/arch/arm64/include/asm/pgtable.h
> @@ -1869,6 +1869,17 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
>  	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
>  }
>  
> +#define clear_flush_young_ptes clear_flush_young_ptes
> +static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
> +					unsigned long addr, pte_t *ptep,
> +					unsigned int nr)
> +{
> +	if (likely(nr == 1))
> +		return __ptep_clear_flush_young(vma, addr, ptep);

Bug: This is broken if core-mm tries to call this for nr=1 on a pte that is part
of a contpte mapping.

The similar fastpaths are here to prevent regressing the common small folio case.

I guess here the best approach is (note no leading underscores):

	if (likely(nr == 1))
		return ptep_clear_flush_young(vma, addr, ptep);

> +
> +	return contpte_clear_flush_young_ptes(vma, addr, ptep, nr);
> +}
> +
>  #define wrprotect_ptes wrprotect_ptes
>  static __always_inline void wrprotect_ptes(struct mm_struct *mm,
>  				unsigned long addr, pte_t *ptep, unsigned int nr)
> diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h
> index d1094c2d5fb6..be594b274729 100644
> --- a/include/linux/mmu_notifier.h
> +++ b/include/linux/mmu_notifier.h
> @@ -515,16 +515,17 @@ static inline void mmu_notifier_range_init_owner(
>  	range->owner = owner;
>  }
>  
> -#define ptep_clear_flush_young_notify(__vma, __address, __ptep)		\
> +#define ptep_clear_flush_young_notify(__vma, __address, __ptep, __nr)	\

Shouldn't we rename this macro to clear_flush_young_ptes_notify()?

And potentially:

#define ptep_clear_flush_young_notify(__vma, __address, __ptep) \
	clear_flush_young_ptes_notify(__vma, __address, __ptep, 1)

if there are other non-batched users remaining.

>  ({									\
>  	int __young;							\
>  	struct vm_area_struct *___vma = __vma;				\
>  	unsigned long ___address = __address;				\
> -	__young = ptep_clear_flush_young(___vma, ___address, __ptep);	\
> +	unsigned int ___nr = __nr;					\
> +	__young = clear_flush_young_ptes(___vma, ___address, __ptep, ___nr);	\
>  	__young |= mmu_notifier_clear_flush_young(___vma->vm_mm,	\
>  						  ___address,		\
>  						  ___address +		\
> -							PAGE_SIZE);	\
> +						nr * PAGE_SIZE);	\
>  	__young;							\
>  })
>  > @@ -650,7 +651,7 @@ static inline void
mmu_notifier_subscriptions_destroy(struct mm_struct *mm)
>  
>  #define mmu_notifier_range_update_to_read_only(r) false
>  
> -#define ptep_clear_flush_young_notify ptep_clear_flush_young
> +#define ptep_clear_flush_young_notify clear_flush_young_ptes
>  #define pmdp_clear_flush_young_notify pmdp_clear_flush_young
>  #define ptep_clear_young_notify ptep_test_and_clear_young
>  #define pmdp_clear_young_notify pmdp_test_and_clear_young
> diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
> index b13b6f42be3c..c7d0fd228cb7 100644
> --- a/include/linux/pgtable.h
> +++ b/include/linux/pgtable.h
> @@ -947,6 +947,25 @@ static inline void wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
>  }
>  #endif
>  
> +#ifndef clear_flush_young_ptes

Let's have some function documentation here please.

> +static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
> +					 unsigned long addr, pte_t *ptep,
> +					 unsigned int nr)
> +{
> +	int young = 0;
> +
> +	for (;;) {

I know Lorenzo is pretty allergic to this style of looping :)

He's right of course, we should probably just do this the ideomatic way and not
worry about it looking a bit different to the others.

> +		young |= ptep_clear_flush_young(vma, addr, ptep);
> +		if (--nr == 0)
> +			break;
> +		ptep++;
> +		addr += PAGE_SIZE;
> +	}
> +
> +	return young;
> +}
> +#endif
> +
>  /*
>   * On some architectures hardware does not set page access bit when accessing
>   * memory page, it is responsibility of software setting this bit. It brings
> diff --git a/mm/rmap.c b/mm/rmap.c
> index d6799afe1114..ec232165c47d 100644
> --- a/mm/rmap.c
> +++ b/mm/rmap.c
> @@ -827,9 +827,11 @@ static bool folio_referenced_one(struct folio *folio,
>  	struct folio_referenced_arg *pra = arg;
>  	DEFINE_FOLIO_VMA_WALK(pvmw, folio, vma, address, 0);
>  	int ptes = 0, referenced = 0;
> +	unsigned int nr;
>  
>  	while (page_vma_mapped_walk(&pvmw)) {
>  		address = pvmw.address;
> +		nr = 1;
>  
>  		if (vma->vm_flags & VM_LOCKED) {
>  			ptes++;
> @@ -874,9 +876,21 @@ static bool folio_referenced_one(struct folio *folio,
>  			if (lru_gen_look_around(&pvmw))
>  				referenced++;
>  		} else if (pvmw.pte) {
> +			if (folio_test_large(folio)) {
> +				unsigned long end_addr = pmd_addr_end(address, vma->vm_end);
> +				unsigned int max_nr = (end_addr - address) >> PAGE_SHIFT;
> +				pte_t pteval = ptep_get(pvmw.pte);
> +
> +				nr = folio_pte_batch(folio, pvmw.pte, pteval, max_nr);
> +			}
> +
> +			ptes += nr;
>  			if (ptep_clear_flush_young_notify(vma, address,
> -						pvmw.pte))
> +						pvmw.pte, nr))
>  				referenced++;
> +			/* Skip the batched PTEs */
> +			pvmw.pte += nr - 1;
> +			pvmw.address += (nr - 1) * PAGE_SIZE;

The -1 part is because the walker will increment by 1 I'm guessing?

>  		} else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) {
>  			if (pmdp_clear_flush_young_notify(vma, address,
>  						pvmw.pmd))
> @@ -886,7 +900,11 @@ static bool folio_referenced_one(struct folio *folio,
>  			WARN_ON_ONCE(1);
>  		}
>  
> -		pra->mapcount--;
> +		pra->mapcount -= nr;
> +		if (ptes == pvmw.nr_pages) {
> +			page_vma_mapped_walk_done(&pvmw);
> +			break;

What's this needed for? I'm suspicious because there wasn't an equivalent here
before.

Thanks,
Ryan

> +		}
>  	}
>  
>  	if (referenced)



From bot+bpf-ci at kernel.org  Wed Dec 17 08:56:40 2025
From: bot+bpf-ci at kernel.org (bot+bpf-ci at kernel.org)
Date: Wed, 17 Dec 2025 16:56:40 +0000 (UTC)
Subject: [PATCH bpf-next 2/2] bpf: arm64: Optimize recursion detection by not using atomics
In-Reply-To: <20251217162830.2597286-3-puranjay@kernel.org>
References: <20251217162830.2597286-3-puranjay@kernel.org>
Message-ID: <f144fd46b602b74fc4c1c2664082fbe893e7ec9c274fcc5fdf13d65151749e9c@mail.kernel.org>

> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index 2da986136d26..654fb94bf60c 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h

[ ... ]

> @@ -2006,12 +2009,32 @@ struct bpf_struct_ops_common_value {
>
>  static inline bool bpf_prog_get_recursion_context(struct bpf_prog *prog)
>  {
> +#ifdef CONFIG_ARM64
> +	u8 rctx = interrupt_context_level();
> +	u8 *active = this_cpu_ptr(prog->active);
> +
> +	active[rctx]++;
> +	barrier();
> +	if (get_unaligned_le32(active) != BIT(rctx * 8))
> +		return false;
> +
> +	return true;
> +#else
>  	return this_cpu_inc_return(*(prog->active)) == 1;
> +#endif
>  }

Can preemption between the increment and check cause a counter leak on
CONFIG_PREEMPT_RCU systems? The trampoline calls this function under
rcu_read_lock_dont_migrate() which allows preemption on PREEMPT_RCU
(documented at include/linux/rcupdate.h:856).

Consider this scenario on an ARM64 system with PREEMPT_RCU:

1. Thread A increments active[0] to 1
2. Preemption occurs before Thread A reaches the check
3. Thread B on same CPU increments active[0] to 2
4. Thread B checks: sees 2 != BIT(0), returns false
5. Thread A resumes, checks: sees 2 != BIT(0), returns false
6. Both threads return false, neither runs BPF
7. Neither calls bpf_prog_put_recursion_context() (see
   __bpf_prog_enter_recur() at kernel/bpf/trampoline.c:952)
8. Counter permanently stuck at 2, all future BPF on this CPU fails

The old atomic code handled this correctly because this_cpu_inc_return()
completes atomically, ensuring Thread A reads the value 1 before Thread B
can interfere. With non-atomic operations, Thread A increments but hasn't
read the value yet, allowing Thread B to interfere and cause both threads
to see the modified value.

Is there a guarantee that same-context preemption cannot occur in the BPF
execution path on ARM64, or does this need additional synchronization?

> @@ -2006,12 +2009,32 @@ struct bpf_struct_ops_common_value {
>
>  static inline void bpf_prog_put_recursion_context(struct bpf_prog *prog)
>  {
> +#ifdef CONFIG_ARM64
> +	u8 rctx = interrupt_context_level();
> +	u8 *active = this_cpu_ptr(prog->active);
> +
> +	barrier();
> +	active[rctx]--;
> +#else
>  	this_cpu_dec(*(prog->active));
> +#endif
>  }

The barrier() is placed before the decrement. Does this provide the needed
ordering guarantee, or should there also be a barrier after the decrement
to ensure visibility?

> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> index c66316e32563..b5063acfcf92 100644
> --- a/kernel/bpf/core.c
> +++ b/kernel/bpf/core.c

[ ... ]

> @@ -112,7 +112,8 @@ struct bpf_prog *bpf_prog_alloc_no_stats(unsigned int size, gfp_t gfp_extra_flag
>  		vfree(fp);
>  		return NULL;
>  	}
> -	fp->active = alloc_percpu_gfp(int, bpf_memcg_flags(GFP_KERNEL | gfp_extra_flags));
> +	fp->active = __alloc_percpu_gfp(sizeof(u8[BPF_NR_CONTEXTS]), 8,
> +					bpf_memcg_flags(GFP_KERNEL | gfp_extra_flags));

The allocation changes to u8[4] for all architectures, but the non-ARM64
code path still uses *(prog->active) which now dereferences only the first
byte. This changes the counter from int (typically 4 bytes, range ~2^31)
to u8 (1 byte, range 256). While 256 recursion levels is sufficient in
practice, is this intentional for non-ARM64 platforms, or should they
continue using a full int-sized allocation?


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/20310266487

From nicolas.frattaroli at collabora.com  Wed Dec 17 09:03:26 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Wed, 17 Dec 2025 18:03:26 +0100
Subject: [PATCH 0/4] Make MT8196 get its Mali GPU shader_present from nvmem
Message-ID: <20251217-mt8196-shader-present-v1-0-f6f8f3aa1e93@collabora.com>

The MediaTek MT8196 SoC's Mali SHADER_PRESENT register does not list
only functional shader cores, but also those that are fused off to
improve yield.

The SHADER_PRESENT bitmask with the one fused off core omitted is to be
found in an efuse. However, the efuse address is considered
confidential, and is not public knowledge.

The MT8196 GPUEB MCU, which does the power management for the Mali GPU
on this SoC, knows and reads the efuse however, and exposes it in the
shared memory intended to communicate state to the application
processor. Reading the bitmask from this shared memory area is the
vendor's intended solution.

This series models this in the binding and implements it in the
corresponding Linux drivers:
- the mali-valhall-csf binding gets an nvmem-cells/nvmem-cell-names
  property to declare that shader-present is in a different castle
- the mt8196-gpufreq binding requires nodes to expose the shader-present
  cell
- panthor checks for the presence of the shader-present cell and uses it
  as the shader-present value if it's found, instead of the Mali GPU
  register contents
- mtk-mfg-pmdomain becomes an nvmem provider and will happily serve
  queries for the shader-present cell

While it would be preferable if we could read the efuse directly, it's
not possible as things stand, and insisting on it will just keep this
hardware from working in mainline. Running a GPU workload with a
SHADER_PRESENT bitmask that includes a faulty core results in corrupt
GPU rendering output.

Modelling the mt8196-gpufreq device as a nvmem-cell provider however is
not lying about the hardware's capabilities, as it truly does provide
access to the nvmem-cell, even if it acts as a proxy.

>From a bindings and panthor perspective, this is also generic enough to
where hypothetical other vendors doing the same thing (even with direct
efuse access) can rely on the same cell name and implementation.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
Nicolas Frattaroli (4):
      dt-bindings: gpu: mali-valhall-csf: Add shader-present nvmem cell
      dt-bindings: power: mt8196-gpufreq: Describe nvmem provider ability
      drm/panthor: Implement reading shader_present from nvmem
      pmdomain: mediatek: mtk-mfg: Expose shader_present as nvmem cell

 .../bindings/gpu/arm,mali-valhall-csf.yaml         | 14 +++++
 .../bindings/power/mediatek,mt8196-gpufreq.yaml    | 13 +++++
 drivers/gpu/drm/panthor/panthor_hw.c               | 63 +++++++++++++++++++---
 drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c       | 57 ++++++++++++++++++++
 4 files changed, 141 insertions(+), 6 deletions(-)
---
base-commit: 16f014a645fb35303b8fd3305f23f8ecd3f2f2a6
change-id: 20251217-mt8196-shader-present-e2dc3f97fc74

Best regards,
-- 
Nicolas Frattaroli <nicolas.frattaroli at collabora.com>



From nicolas.frattaroli at collabora.com  Wed Dec 17 09:03:27 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Wed, 17 Dec 2025 18:03:27 +0100
Subject: [PATCH 1/4] dt-bindings: gpu: mali-valhall-csf: Add shader-present
 nvmem cell
In-Reply-To: <20251217-mt8196-shader-present-v1-0-f6f8f3aa1e93@collabora.com>
References: <20251217-mt8196-shader-present-v1-0-f6f8f3aa1e93@collabora.com>
Message-ID: <20251217-mt8196-shader-present-v1-1-f6f8f3aa1e93@collabora.com>

On the MediaTek MT8196 SoC, the bitmask for which shader cores are
present and functional is not the one in the Mali GPU's registers, but
in an external efuse.

Add the nvmem cell properties to describe such a setup, and make them
required on MT8196.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 .../devicetree/bindings/gpu/arm,mali-valhall-csf.yaml      | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/Documentation/devicetree/bindings/gpu/arm,mali-valhall-csf.yaml b/Documentation/devicetree/bindings/gpu/arm,mali-valhall-csf.yaml
index bee9faf1d3f8..8eccd4338a2b 100644
--- a/Documentation/devicetree/bindings/gpu/arm,mali-valhall-csf.yaml
+++ b/Documentation/devicetree/bindings/gpu/arm,mali-valhall-csf.yaml
@@ -51,6 +51,14 @@ properties:
           - stacks
       - const: stacks
 
+  nvmem-cells:
+    items:
+      - description: bitmask of functional shader cores
+
+  nvmem-cell-names:
+    items:
+      - const: shader-present
+
   mali-supply: true
 
   operating-points-v2: true
@@ -108,6 +116,8 @@ allOf:
       properties:
         clocks:
           minItems: 3
+        nvmem-cells: false
+        nvmem-cell-names: false
         power-domains:
           maxItems: 1
         power-domain-names: false
@@ -133,6 +143,8 @@ allOf:
             - const: core
             - const: stacks
       required:
+        - nvmem-cells
+        - nvmem-cell-names
         - power-domains
 
 examples:
@@ -179,6 +191,8 @@ examples:
                      <GIC_SPI 605 IRQ_TYPE_LEVEL_HIGH 0>,
                      <GIC_SPI 604 IRQ_TYPE_LEVEL_HIGH 0>;
         interrupt-names = "job", "mmu", "gpu";
+        nvmem-cells = <&shader_present>;
+        nvmem-cell-names = "shader-present";
         power-domains = <&gpufreq>;
     };
 

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Wed Dec 17 09:03:28 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Wed, 17 Dec 2025 18:03:28 +0100
Subject: [PATCH 2/4] dt-bindings: power: mt8196-gpufreq: Describe nvmem
 provider ability
In-Reply-To: <20251217-mt8196-shader-present-v1-0-f6f8f3aa1e93@collabora.com>
References: <20251217-mt8196-shader-present-v1-0-f6f8f3aa1e93@collabora.com>
Message-ID: <20251217-mt8196-shader-present-v1-2-f6f8f3aa1e93@collabora.com>

On the MediaTek MT8196 SoC, the Mali GPU's "shader_present" hardware
register may also include a non-functional shader core, along with the
present shader cores. An efuse elsewhere in the SoC provides the
shader_present mask with the fused off core omitted.

However, the efuse address is not publicly disclosed. What is known
though is that the GPUEB MCU reads this efuse, and exposes its contents
in the memory it shares with the application processor.

We can therefore describe the mediatek,mt8196-gpufreq device as being an
nvmem provider for this purpose, as it does provide nvmem access in an
indirect way.

The shader-present child node is left out of the list of required
properties as we may one day be able to describe the actual efuse region
this value comes from, so the gpufreq device isn't necessarily the only
device that can provide this cell, and implementations shouldn't need to
implement this functionality once this is the case.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 .../devicetree/bindings/power/mediatek,mt8196-gpufreq.yaml  | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/Documentation/devicetree/bindings/power/mediatek,mt8196-gpufreq.yaml b/Documentation/devicetree/bindings/power/mediatek,mt8196-gpufreq.yaml
index b9e43abaf8a4..66fc59b3c8b4 100644
--- a/Documentation/devicetree/bindings/power/mediatek,mt8196-gpufreq.yaml
+++ b/Documentation/devicetree/bindings/power/mediatek,mt8196-gpufreq.yaml
@@ -74,9 +74,18 @@ properties:
   "#clock-cells":
     const: 1
 
+  "#nvmem-cell-cells":
+    const: 0
+
   "#power-domain-cells":
     const: 0
 
+  shader-present:
+    type: object
+
+dependencies:
+  shader-present: [ "#nvmem-cell-cells" ]
+
 required:
   - compatible
   - reg
@@ -113,5 +122,9 @@ examples:
                      "ccf", "fast-dvfs";
         memory-region = <&gpueb_shared_memory>;
         #clock-cells = <1>;
+        #nvmem-cell-cells = <0>;
         #power-domain-cells = <0>;
+
+        shader-present {
+        };
     };

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Wed Dec 17 09:03:29 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Wed, 17 Dec 2025 18:03:29 +0100
Subject: [PATCH 3/4] drm/panthor: Implement reading shader_present from
 nvmem
In-Reply-To: <20251217-mt8196-shader-present-v1-0-f6f8f3aa1e93@collabora.com>
References: <20251217-mt8196-shader-present-v1-0-f6f8f3aa1e93@collabora.com>
Message-ID: <20251217-mt8196-shader-present-v1-3-f6f8f3aa1e93@collabora.com>

On some platforms, notably MediaTek MT8196, the shader_present bitmask
in the Mali GPU register for it has cores enabled that may be faulty.
The true shader_present bitmask is found in an efuse instead.

Implement reading shader_present from an nvmem cell if one is present,
falling back to the Mali register if it's absent. The error codes are
trickled up through to the probe function so that probe deferral works.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/panthor/panthor_hw.c | 63 ++++++++++++++++++++++++++++++++----
 1 file changed, 57 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c
index 87ebb7ae42c4..eb44c8b108aa 100644
--- a/drivers/gpu/drm/panthor/panthor_hw.c
+++ b/drivers/gpu/drm/panthor/panthor_hw.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0 or MIT
 /* Copyright 2025 ARM Limited. All rights reserved. */
 
+#include <linux/nvmem-consumer.h>
 #include <drm/drm_print.h>
 
 #include "panthor_device.h"
@@ -109,7 +110,52 @@ static char *get_gpu_model_name(struct panthor_device *ptdev)
 	return "(Unknown Mali GPU)";
 }
 
-static void panthor_gpu_info_init(struct panthor_device *ptdev)
+static int overload_shader_present(struct panthor_device *ptdev)
+{
+	struct device *dev = ptdev->base.dev;
+	struct nvmem_cell *cell = nvmem_cell_get(dev, "shader-present");
+	ssize_t len;
+	void *buf;
+	int ret;
+
+	if (IS_ERR(cell)) {
+		/* On platforms without this cell, use the Mali register */
+		if (PTR_ERR(cell) == -ENOENT)
+			return 0;
+
+		return dev_err_probe(dev, PTR_ERR(cell),
+				     "Failed to get shader-present nvmem cell\n");
+	}
+
+	buf = nvmem_cell_read(cell, &len);
+	if (IS_ERR(buf)) {
+		ret = dev_err_probe(dev, PTR_ERR(buf),
+				    "Failed to read shader-present nvmem cell\n");
+		goto err_put_cell;
+	}
+
+	if (!len || len > 8) {
+		ret = dev_err_probe(dev, -EINVAL, "shader-present cell can't be length %ld\n",
+				    len);
+		goto err_free;
+	}
+
+	memcpy(&ptdev->gpu_info.shader_present, buf, len);
+
+	kfree(buf);
+	nvmem_cell_put(cell);
+
+	return 0;
+
+err_free:
+	kfree(buf);
+err_put_cell:
+	nvmem_cell_put(cell);
+
+	return ret;
+}
+
+static int panthor_gpu_info_init(struct panthor_device *ptdev)
 {
 	unsigned int i;
 
@@ -143,13 +189,18 @@ static void panthor_gpu_info_init(struct panthor_device *ptdev)
 		ptdev->gpu_info.tiler_present = gpu_read64(ptdev, GPU_TILER_PRESENT);
 		ptdev->gpu_info.l2_present = gpu_read64(ptdev, GPU_L2_PRESENT);
 	}
+
+	return overload_shader_present(ptdev);
 }
 
-static void panthor_hw_info_init(struct panthor_device *ptdev)
+static int panthor_hw_info_init(struct panthor_device *ptdev)
 {
 	u32 major, minor, status;
+	int ret;
 
-	panthor_gpu_info_init(ptdev);
+	ret = panthor_gpu_info_init(ptdev);
+	if (ret)
+		return ret;
 
 	major = GPU_VER_MAJOR(ptdev->gpu_info.gpu_id);
 	minor = GPU_VER_MINOR(ptdev->gpu_info.gpu_id);
@@ -172,6 +223,8 @@ static void panthor_hw_info_init(struct panthor_device *ptdev)
 		 "shader_present=0x%0llx l2_present=0x%0llx tiler_present=0x%0llx",
 		 ptdev->gpu_info.shader_present, ptdev->gpu_info.l2_present,
 		 ptdev->gpu_info.tiler_present);
+
+	return 0;
 }
 
 static int panthor_hw_bind_device(struct panthor_device *ptdev)
@@ -218,7 +271,5 @@ int panthor_hw_init(struct panthor_device *ptdev)
 	if (ret)
 		return ret;
 
-	panthor_hw_info_init(ptdev);
-
-	return 0;
+	return panthor_hw_info_init(ptdev);
 }

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Wed Dec 17 09:03:30 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Wed, 17 Dec 2025 18:03:30 +0100
Subject: [PATCH 4/4] pmdomain: mediatek: mtk-mfg: Expose shader_present as
 nvmem cell
In-Reply-To: <20251217-mt8196-shader-present-v1-0-f6f8f3aa1e93@collabora.com>
References: <20251217-mt8196-shader-present-v1-0-f6f8f3aa1e93@collabora.com>
Message-ID: <20251217-mt8196-shader-present-v1-4-f6f8f3aa1e93@collabora.com>

Implement nvmem-provider functionality in mtk-mfg-pmdomain, such that it
can expose its GF_REG_SHADER_PRESENT value in the shared memory as an
nvmem cell for panthor.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c | 57 ++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)

diff --git a/drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c b/drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c
index 9bad577b3ae4..725ebc678f1b 100644
--- a/drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c
+++ b/drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c
@@ -10,6 +10,7 @@
 #include <linux/clk-provider.h>
 #include <linux/container_of.h>
 #include <linux/iopoll.h>
+#include <linux/nvmem-provider.h>
 #include <linux/mailbox_client.h>
 #include <linux/module.h>
 #include <linux/of.h>
@@ -872,6 +873,58 @@ static int mtk_mfg_init_clk_provider(struct mtk_mfg *mfg)
 	return 0;
 }
 
+static int mtk_mfg_read_nvmem(void *priv, unsigned int offset, void *val, size_t bytes)
+{
+	struct mtk_mfg *mfg = priv;
+	u32 *buf = val;
+
+	if (bytes != 4)
+		return -EINVAL;
+
+	if (!mfg->shared_mem)
+		return -ENODEV;
+
+	if (offset + bytes >= mfg->shared_mem_size)
+		return -EINVAL;
+
+	*buf = readl(mfg->shared_mem + offset);
+
+	return 0;
+}
+
+static int mtk_mfg_init_nvmem_provider(struct mtk_mfg *mfg)
+{
+	struct device *dev = &mfg->pdev->dev;
+	struct nvmem_cell_info cell = {};
+	struct nvmem_config config = {};
+	struct nvmem_device *nvdev;
+	int ret;
+
+	config.reg_read = mtk_mfg_read_nvmem;
+	config.dev = dev;
+	config.read_only = true;
+	config.priv = mfg;
+	config.size = 4;
+	config.word_size = 4;
+
+	nvdev = devm_nvmem_register(dev, &config);
+	of_node_put(config.of_node);
+	if (IS_ERR(nvdev))
+		return dev_err_probe(dev, PTR_ERR(nvdev), "Couldn't register nvmem provider\n");
+
+	cell.name = "shader-present";
+	cell.offset = GF_REG_SHADER_PRESENT;
+	cell.bytes = 4;
+	cell.np = of_get_child_by_name(dev->of_node, cell.name);
+
+	ret = nvmem_add_one_cell(nvdev, &cell);
+	/* cell.np purposefully not put as nvmem_add_one_cell does not increase refcount */
+	if (ret)
+		return dev_err_probe(dev, ret, "Couldn't add cell %s\n", cell.name);
+
+	return 0;
+}
+
 static int mtk_mfg_probe(struct platform_device *pdev)
 {
 	struct mtk_mfg *mfg;
@@ -984,6 +1037,10 @@ static int mtk_mfg_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_power_off;
 
+	ret = mtk_mfg_init_nvmem_provider(mfg);
+	if (ret)
+		goto err_power_off;
+
 	ret = of_genpd_add_provider_simple(dev->of_node, &mfg->pd);
 	if (ret) {
 		dev_err_probe(dev, ret, "Failed to add pmdomain provider\n");

-- 
2.52.0



From maz at kernel.org  Wed Dec 17 09:13:47 2025
From: maz at kernel.org (Marc Zyngier)
Date: Wed, 17 Dec 2025 17:13:47 +0000
Subject: [PATCH 19/32] KVM: arm64: gic-v5: Init Private IRQs (PPIs) for GICv5
In-Reply-To: <20251212152215.675767-20-sascha.bischoff@arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	<20251212152215.675767-20-sascha.bischoff@arm.com>
Message-ID: <86v7i5m3p0.wl-maz@kernel.org>

On Fri, 12 Dec 2025 15:22:41 +0000,
Sascha Bischoff <Sascha.Bischoff at arm.com> wrote:
> 
> Initialise the private interrupts (PPIs, only) for GICv5. This means
> that a GICv5-style intid is generated (which encodes the PPI type in
> the top bits) instead of the 0-based index that is used for older
> GICs.
> 
> Additionally, set all of the GICv5 PPIs to use Level for the handling
> mode, with the exception of the SW_PPI which uses Edge. This matches
> the architecturally-defined set in the GICv5 specification (the CTIIRQ
> handling mode is IMPDEF, so pick Level has been picked for that).
> 
> Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
> ---
>  arch/arm64/kvm/vgic/vgic-init.c    | 41 +++++++++++++++++++++++-------
>  include/linux/irqchip/arm-gic-v5.h |  2 ++
>  2 files changed, 34 insertions(+), 9 deletions(-)
> 
> diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
> index b246cb6eae71b..51f4443cebcef 100644
> --- a/arch/arm64/kvm/vgic/vgic-init.c
> +++ b/arch/arm64/kvm/vgic/vgic-init.c
> @@ -263,13 +263,19 @@ static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu, u32 type)
>  {
>  	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>  	int i;
> +	u32 num_private_irqs;
> +
> +	if (vgic_is_v5(vcpu->kvm))
> +		num_private_irqs = VGIC_V5_NR_PRIVATE_IRQS;
> +	else
> +		num_private_irqs = VGIC_NR_PRIVATE_IRQS;

This is another case where we need to do something about
PPIs. Allocating the full complement of PPIs (all 128 of them) is
starting to be mildly visible (at 96 bytes a pop, that's 12kB of
storage per vcpu).

And 95% of that is guaranteed to be wasted... XArray anyone?

>  
>  	lockdep_assert_held(&vcpu->kvm->arch.config_lock);

It is good practice to leave this sort of assertions at the beginning
of the function.

Thanks,

	M.

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


From jackmanb at google.com  Wed Dec 17 09:19:27 2025
From: jackmanb at google.com (Brendan Jackman)
Date: Wed, 17 Dec 2025 17:19:27 +0000
Subject: [PATCH 0/2] introduce pagetable_alloc_nolock()
In-Reply-To: <d5354d96-6f28-41d7-9f66-64c254d9477b@suse.cz>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com> <916c17ba-22b1-456e-a184-cb3f60249af7@arm.com>
 <aUGOPd7gNRf1xHEc@e129823.arm.com> <100cc8da-b826-4fc2-a624-746bf6fb049d@arm.com>
 <aUKKZR0u22KOPfd7@e129823.arm.com> <d96ac977-222e-4e8d-9487-da1306198419@arm.com>
 <aUKnfU/3FREY13g1@e129823.arm.com> <d912480a-5229-4efe-9336-b31acded30f5@suse.cz>
 <DF0J58HOVLL4.2E16Q87D2UXRW@google.com> <d5354d96-6f28-41d7-9f66-64c254d9477b@suse.cz>
Message-ID: <DF0NWLWKRKYI.3PLY78UGGG2PD@google.com>

>> From 4c6b4d4cb08aee9559d02a348b9ecf799142c96f Mon Sep 17 00:00:00 2001
>> From: Brendan Jackman <jackmanb at google.com>
>> Date: Wed, 17 Dec 2025 13:26:28 +0000
>> Subject: [PATCH] mm: clarify GFP_ATOMIC/GFP_NOWAIT doc-comment
>> 
>> The current description of contexts where it's invalid to make
>> GFP_ATOMIC and GFP_NOWAIT calls is rather vague.
>> 
>> Replace this with a direct description of the actual contexts of concern
>> and refer to the RT docs where this is explained more discursively.
>> 
>> While rejigging this prose, also move the documentation of GFP_NOWAIT to
>> the GFP_NOWAIT section.
>
> There doesn't seem to be any move?

This is referring to [0] and [1].

>> diff --git a/include/linux/gfp_types.h b/include/linux/gfp_types.h
>> index 3de43b12209ee..07a378542caf2 100644
>> --- a/include/linux/gfp_types.h
>> +++ b/include/linux/gfp_types.h
>> @@ -309,8 +309,10 @@ enum {
>>   *
>>   * %GFP_ATOMIC users can not sleep and need the allocation to succeed. A lower
>>   * watermark is applied to allow access to "atomic reserves".
>> - * The current implementation doesn't support NMI and few other strict
>> - * non-preemptive contexts (e.g. raw_spin_lock). The same applies to %GFP_NOWAIT.
[0]                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
>> + * The current implementation doesn't support NMI, nor contexts that disable
>> + * preemption under PREEMPT_RT. This includes raw_spin_lock() and plain
>> + * preempt_disable() - see Documentation/core-api/real-time/differences.rst for
>> + * more info.
>
> Can we reference the "Memory allocation" section directly?

Yeah good point. I will send this as a standalone [PATCH] mail tomorrow.

>>   *
>>   * %GFP_KERNEL is typical for kernel-internal allocations. The caller requires
>>   * %ZONE_NORMAL or a lower zone for direct access but can direct reclaim.
>> @@ -321,6 +323,7 @@ enum {
>>   * %GFP_NOWAIT is for kernel allocations that should not stall for direct
>>   * reclaim, start physical IO or use any filesystem callback.  It is very
>>   * likely to fail to allocate memory, even for very small allocations.
>> + * The same restrictions on calling contexts apply as for %GFP_ATOMIC.
[1]     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^



From boris.brezillon at collabora.com  Wed Dec 17 09:20:38 2025
From: boris.brezillon at collabora.com (Boris Brezillon)
Date: Wed, 17 Dec 2025 18:20:38 +0100
Subject: [PATCH 3/4] drm/panthor: Implement reading shader_present from
 nvmem
In-Reply-To: <20251217-mt8196-shader-present-v1-3-f6f8f3aa1e93@collabora.com>
References: <20251217-mt8196-shader-present-v1-0-f6f8f3aa1e93@collabora.com>
	<20251217-mt8196-shader-present-v1-3-f6f8f3aa1e93@collabora.com>
Message-ID: <20251217182038.6779a191@fedora>

On Wed, 17 Dec 2025 18:03:29 +0100
Nicolas Frattaroli <nicolas.frattaroli at collabora.com> wrote:

> On some platforms, notably MediaTek MT8196, the shader_present bitmask
> in the Mali GPU register for it has cores enabled that may be faulty.
> The true shader_present bitmask is found in an efuse instead.
> 
> Implement reading shader_present from an nvmem cell if one is present,
> falling back to the Mali register if it's absent. The error codes are
> trickled up through to the probe function so that probe deferral works.
> 
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>

Reviewed-by: Boris Brezillon <boris.brezillon at collabora.com>

> ---
>  drivers/gpu/drm/panthor/panthor_hw.c | 63 ++++++++++++++++++++++++++++++++----
>  1 file changed, 57 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c
> index 87ebb7ae42c4..eb44c8b108aa 100644
> --- a/drivers/gpu/drm/panthor/panthor_hw.c
> +++ b/drivers/gpu/drm/panthor/panthor_hw.c
> @@ -1,6 +1,7 @@
>  // SPDX-License-Identifier: GPL-2.0 or MIT
>  /* Copyright 2025 ARM Limited. All rights reserved. */
>  
> +#include <linux/nvmem-consumer.h>
>  #include <drm/drm_print.h>
>  
>  #include "panthor_device.h"
> @@ -109,7 +110,52 @@ static char *get_gpu_model_name(struct panthor_device *ptdev)
>  	return "(Unknown Mali GPU)";
>  }
>  
> -static void panthor_gpu_info_init(struct panthor_device *ptdev)
> +static int overload_shader_present(struct panthor_device *ptdev)
> +{
> +	struct device *dev = ptdev->base.dev;
> +	struct nvmem_cell *cell = nvmem_cell_get(dev, "shader-present");
> +	ssize_t len;
> +	void *buf;
> +	int ret;
> +
> +	if (IS_ERR(cell)) {
> +		/* On platforms without this cell, use the Mali register */
> +		if (PTR_ERR(cell) == -ENOENT)
> +			return 0;
> +
> +		return dev_err_probe(dev, PTR_ERR(cell),
> +				     "Failed to get shader-present nvmem cell\n");
> +	}
> +
> +	buf = nvmem_cell_read(cell, &len);
> +	if (IS_ERR(buf)) {
> +		ret = dev_err_probe(dev, PTR_ERR(buf),
> +				    "Failed to read shader-present nvmem cell\n");
> +		goto err_put_cell;
> +	}
> +
> +	if (!len || len > 8) {
> +		ret = dev_err_probe(dev, -EINVAL, "shader-present cell can't be length %ld\n",
> +				    len);
> +		goto err_free;
> +	}
> +
> +	memcpy(&ptdev->gpu_info.shader_present, buf, len);
> +
> +	kfree(buf);
> +	nvmem_cell_put(cell);
> +
> +	return 0;
> +
> +err_free:
> +	kfree(buf);
> +err_put_cell:
> +	nvmem_cell_put(cell);
> +
> +	return ret;
> +}
> +
> +static int panthor_gpu_info_init(struct panthor_device *ptdev)
>  {
>  	unsigned int i;
>  
> @@ -143,13 +189,18 @@ static void panthor_gpu_info_init(struct panthor_device *ptdev)
>  		ptdev->gpu_info.tiler_present = gpu_read64(ptdev, GPU_TILER_PRESENT);
>  		ptdev->gpu_info.l2_present = gpu_read64(ptdev, GPU_L2_PRESENT);
>  	}
> +
> +	return overload_shader_present(ptdev);
>  }
>  
> -static void panthor_hw_info_init(struct panthor_device *ptdev)
> +static int panthor_hw_info_init(struct panthor_device *ptdev)
>  {
>  	u32 major, minor, status;
> +	int ret;
>  
> -	panthor_gpu_info_init(ptdev);
> +	ret = panthor_gpu_info_init(ptdev);
> +	if (ret)
> +		return ret;
>  
>  	major = GPU_VER_MAJOR(ptdev->gpu_info.gpu_id);
>  	minor = GPU_VER_MINOR(ptdev->gpu_info.gpu_id);
> @@ -172,6 +223,8 @@ static void panthor_hw_info_init(struct panthor_device *ptdev)
>  		 "shader_present=0x%0llx l2_present=0x%0llx tiler_present=0x%0llx",
>  		 ptdev->gpu_info.shader_present, ptdev->gpu_info.l2_present,
>  		 ptdev->gpu_info.tiler_present);
> +
> +	return 0;
>  }
>  
>  static int panthor_hw_bind_device(struct panthor_device *ptdev)
> @@ -218,7 +271,5 @@ int panthor_hw_init(struct panthor_device *ptdev)
>  	if (ret)
>  		return ret;
>  
> -	panthor_hw_info_init(ptdev);
> -
> -	return 0;
> +	return panthor_hw_info_init(ptdev);
>  }
> 



From detlev.casanova at collabora.com  Wed Dec 17 09:40:37 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 17 Dec 2025 12:40:37 -0500
Subject: [PATCH v6 00/17] media: rkvdec: Add support for VDPU381 and VDPU383 
Message-ID: <20251217174059.1341784-1-detlev.casanova@collabora.com>

These variants are found respectively in the RK3588 and RK3576 SoCs.
This patch only adds support for H264 and H265 in both variants.

As there is a considerable part of the code that can be shared with the
already supported rkvdec decoder driver, the support for these variants
is added here rather than writing a new driver.

This patch set uses the newly introduced hevc_ext_sps_[ls]t_rps v4l2
controls for HEVC.
Therefore, a patched version of userpace tools is needed for HEVC
support (added for GStreamer[1] and in an early stage for FFmpeg[2]).

The DTS changes can be found in another patch set: [3]

[1]: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/9355
[2]: https://gitlab.collabora.com/detlev/ffmpeg
[3]: https://lore.kernel.org/all/20251020212009.8852-1-detlev.casanova at collabora.com/

Changes since v5:
- Extract multicore management in separate commit
- Move variant specific functions to an ops struct
- Fix a typo and "h264" -> "hevc" copy/paste mistakes
- Move RKVDEC_*_PIXELS to rkvdec.h
- Drop VDPU383_*_PIXELS, use the the RKVDEC ones instead
- Change RKVDEC_1080P_PIXELS value to 1920 * 1088
- Long and short term ref sets extend controls:
  - Add them in visl traces
  - Reword documentation to specify SPS extension and use
  - Mention Vulkan Video API similarity
  - Specify behavior for empty array values
  - Reorder struct fields to ensure fixed compiled size
  - Remove the mention of V4L2_CTRL_FLAG_DYNAMIC_ARRAY flag

Changes since v4:
 - Add basic ext_sps_[ls]t_rps validation (flags only)
 - Add missing copyright in new common files
 - Rename num_coded_fmts, rcb_num, clk_count
 - Avoid allocating RCB config when not needed
 - Merge rkvdec_config into rkvdec_variant
 - Keep rkvdec_hevc_get_image_fmt per variant

Changes since v3:
 - Rebased on latest next (ea299a216426) + HEVC support for rk3399

Changes since v2:
 - Rebased on Kwiboo's HEVC support for rk3399
 - Include hevc_ext_sps_[ls]t_rps v4l2 controls commits
 - Remove empty lines at end of files
 - Rename RKVDEC2_ALLOC_* to RKVDEC_ALLOC_*
 - Set min_with and min_height to 64
 - Remove vdpu38x_fill_pixfmt_mp() function
 - Handle userspace not supporting hevc_ext_sps_[ls]t_rps
 - Make all config structs static const

Changes since v1:
 - Add parsing of the short and long term ref frame sets from the new v4l2
   controls
 - Add RPS cache to avoid parsing the same data again
 - Fix HEVC pixel formats selection
 - Fix multiple indentation errors

Detlev Casanova (17):
  media: uapi: HEVC: Add v4l2_ctrl_hevc_ext_sps_[ls]t_rps controls
  media: v4l2-ctrls: Add hevc_ext_sps_[ls]t_rps controls
  media: visl: Add HEVC short and long term RPS sets
  media: rkvdec: Switch to using structs instead of writel
  media: rkvdec: Move cabac tables to their own source file
  media: rkvdec: Use structs to represent the HW RPS
  media: rkvdec: Move h264 functions to common file
  media: rkvdec: Move hevc functions to common file
  media: rkvdec: Add variant specific coded formats list
  media: rkvdec: Add RCB and SRAM support
  media: rkvdec: Support per-variant interrupt handler
  media: rkvdec: Enable all clocks without naming them
  media: rkvdec: Disable multicore support
  media: rkvdec: Add H264 support for the VDPU381 variant
  media: rkvdec: Add H264 support for the VDPU383 variant
  media: rkvdec: Add HEVC support for the VDPU381 variant
  media: rkvdec: Add HEVC support for the VDPU383 variant

 .../media/v4l/ext-ctrls-codec-stateless.rst   | 120 +++
 .../media/v4l/videodev2.h.rst.exceptions      |   2 +
 .../media/v4l/vidioc-queryctrl.rst            |  12 +
 .../media/platform/rockchip/rkvdec/Kconfig    |   1 +
 .../media/platform/rockchip/rkvdec/Makefile   |  14 +-
 .../{rkvdec-hevc-data.c => rkvdec-cabac.c}    | 506 +++++++++-
 .../rockchip/rkvdec/rkvdec-h264-common.c      | 258 +++++
 .../rockchip/rkvdec/rkvdec-h264-common.h      |  89 ++
 .../platform/rockchip/rkvdec/rkvdec-h264.c    | 891 ++----------------
 .../rockchip/rkvdec/rkvdec-hevc-common.c      | 488 ++++++++++
 .../rockchip/rkvdec/rkvdec-hevc-common.h      | 108 +++
 .../platform/rockchip/rkvdec/rkvdec-hevc.c    | 257 +----
 .../platform/rockchip/rkvdec/rkvdec-rcb.c     | 178 ++++
 .../platform/rockchip/rkvdec/rkvdec-rcb.h     |  29 +
 .../platform/rockchip/rkvdec/rkvdec-regs.h    | 571 +++++++----
 .../rockchip/rkvdec/rkvdec-vdpu381-h264.c     | 469 +++++++++
 .../rockchip/rkvdec/rkvdec-vdpu381-hevc.c     | 641 +++++++++++++
 .../rockchip/rkvdec/rkvdec-vdpu381-regs.h     | 424 +++++++++
 .../rockchip/rkvdec/rkvdec-vdpu383-h264.c     | 582 ++++++++++++
 .../rockchip/rkvdec/rkvdec-vdpu383-hevc.c     | 736 +++++++++++++++
 .../rockchip/rkvdec/rkvdec-vdpu383-regs.h     | 281 ++++++
 .../platform/rockchip/rkvdec/rkvdec-vp9.c     | 231 ++---
 .../media/platform/rockchip/rkvdec/rkvdec.c   | 542 ++++++++++-
 .../media/platform/rockchip/rkvdec/rkvdec.h   |  43 +
 drivers/media/test-drivers/visl/visl-dec.c    |   7 +
 drivers/media/test-drivers/visl/visl-dec.h    |   3 +
 .../media/test-drivers/visl/visl-trace-hevc.h |  59 ++
 drivers/media/v4l2-core/v4l2-ctrls-core.c     |  28 +
 drivers/media/v4l2-core/v4l2-ctrls-defs.c     |  10 +
 include/uapi/linux/v4l2-controls.h            |  61 ++
 include/uapi/linux/videodev2.h                |   2 +
 31 files changed, 6230 insertions(+), 1413 deletions(-)
 rename drivers/media/platform/rockchip/rkvdec/{rkvdec-hevc-data.c => rkvdec-cabac.c} (86%)
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.c
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-regs.h

-- 
2.52.0



From detlev.casanova at collabora.com  Wed Dec 17 09:40:38 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 17 Dec 2025 12:40:38 -0500
Subject: [PATCH v6 01/17] media: uapi: HEVC: Add v4l2_ctrl_hevc_ext_sps_[ls]t_rps controls
In-Reply-To: <20251217174059.1341784-1-detlev.casanova@collabora.com>
References: <20251217174059.1341784-1-detlev.casanova@collabora.com>
Message-ID: <20251217174059.1341784-2-detlev.casanova@collabora.com>

Some hardware (e.g.: Rockchip's rk3588 hevc decoder) need to fully parse
the slice header, which cannot be passed with the current controls.
There is also no skip method similar as to what can be found in
verisilicon HW.

The SPS is therefore extended through these 2 new controls, providing the
long and short term reference information from the slice header for HEVC
decoding.

These now controls are similar as what is passed in the Vulkan Video API
with the StdVideoH265ShortTermRefPicSet and StdVideoH265LongTermRefPicsSps
structures embedded in the SPS struct.

Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../media/v4l/ext-ctrls-codec-stateless.rst   | 120 ++++++++++++++++++
 .../media/v4l/videodev2.h.rst.exceptions      |   2 +
 .../media/v4l/vidioc-queryctrl.rst            |  12 ++
 3 files changed, 134 insertions(+)

diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst
index 497ae74379f6..3b1e05c6eb13 100644
--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst
+++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst
@@ -2959,6 +2959,126 @@ This structure contains all loop filter related parameters. See sections
       - 0x00000004
       -
 
+``V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS (struct)``
+    Subset of the :c:type:`v4l2_ctrl_hevc_sps` control.
+    It extends it with the list of Long-term reference sets parameters.
+    These parameters are defined according to :ref:`hevc`.
+    They are described in section 7.4.3.2.1 "General sequence parameter set
+    RBSP semantics" of the specification.
+    This control is a dynamically sized 1-dimensional array.
+    The values in the array should be ignored when either
+    num_long_term_ref_pics_sps is 0 or the
+    V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT flag is not set in
+    :c:type:`v4l2_ctrl_hevc_sps`.
+
+.. c:type:: v4l2_ctrl_hevc_ext_sps_lt_rps
+
+.. cssclass:: longtable
+
+.. flat-table:: struct v4l2_ctrl_hevc_ext_sps_lt_rps
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - __u16
+      - ``lt_ref_pic_poc_lsb_sps``
+      - Long term reference picture order count as described in section 7.4.3.2.1
+        "General sequence parameter set RBSP semantics" of the specification.
+    * - __u16
+      - ``flags``
+      - See :ref:`Extended Long-Term RPS Flags <hevc_ext_sps_lt_rps_flags>`
+
+.. _hevc_ext_sps_lt_rps_flags:
+
+``Extended SPS Long-Term RPS Flags``
+
+.. cssclass:: longtable
+
+.. flat-table::
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - ``V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_USED_LT``
+      - 0x00000001
+      - Specifies if the long-term reference picture is used 7.4.3.2.1 "General sequence parameter
+        set RBSP semantics" of the specification.
+
+``V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS (struct)``
+    Subset of the :c:type:`v4l2_ctrl_hevc_sps` control.
+    It extends it with the list of Short-term reference sets parameters.
+    These parameters are defined according to :ref:`hevc`.
+    They are described in section 7.4.8 "Short-term reference picture set
+    semantics" of the specification.
+    This control is a dynamically sized 1-dimensional array.
+    The values in the array should be ignored when
+    num_short_term_ref_pic_sets is 0.
+
+.. c:type:: v4l2_ctrl_hevc_ext_sps_st_rps
+
+.. cssclass:: longtable
+
+.. flat-table:: struct v4l2_ctrl_hevc_ext_sps_st_rps
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - __u8
+      - ``delta_idx_minus1``
+      - Specifies the delta compare to the index. See details in section 7.4.8 "Short-term
+        reference picture set semantics" of the specification.
+    * - __u8
+      - ``delta_rps_sign``
+      - Sign of the delta as specified in section 7.4.8 "Short-term reference picture set
+        semantics" of the specification.
+    * - __u8
+      - ``num_negative_pics``
+      - Number of short-term RPS entries that have picture order count values less than the
+        picture order count value of the current picture.
+    * - __u8
+      - ``num_positive_pics``
+      - Number of short-term RPS entries that have picture order count values greater than the
+        picture order count value of the current picture.
+    * - __u32
+      - ``used_by_curr_pic``
+      - Bit i specifies if short-term RPS i is used by the current picture.
+    * - __u32
+      - ``use_delta_flag``
+      - Bit i specifies if short-term RPS i is included in the short-term RPS entries.
+    * - __u16
+      - ``abs_delta_rps_minus1``
+      - Absolute delta RPS as specified in section 7.4.8 "Short-term reference picture set
+        semantics" of the specification.
+    * - __u16
+      - ``delta_poc_s0_minus1[16]``
+      - Specifies the negative picture order count delta for the i-th entry in the short-term RPS.
+        See details in section 7.4.8 "Short-term reference picture set semantics" of the
+        specification.
+    * - __u16
+      - ``delta_poc_s1_minus1[16]``
+      - Specifies the positive picture order count delta for the i-th entry in the short-term RPS.
+        See details in section 7.4.8 "Short-term reference picture set semantics" of the
+        specification.
+    * - __u16
+      - ``flags``
+      - See :ref:`Extended Short-Term RPS Flags <hevc_ext_sps_st_rps_flags>`
+
+.. _hevc_ext_sps_st_rps_flags:
+
+``Extended SPS Short-Term RPS Flags``
+
+.. cssclass:: longtable
+
+.. flat-table::
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - ``V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED``
+      - 0x00000001
+      - Specifies if the short-term RPS is predicted from another short term RPS. See details in
+        section 7.4.8 "Short-term reference picture set semantics" of the specification.
+
 .. _v4l2-codec-stateless-av1:
 
 ``V4L2_CID_STATELESS_AV1_SEQUENCE (struct)``
diff --git a/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions b/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions
index c41693115db6..6182b4e2d2ee 100644
--- a/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions
+++ b/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions
@@ -150,6 +150,8 @@ replace symbol V4L2_CTRL_TYPE_H264_SCALING_MATRIX :c:type:`V4L.v4l2_ctrl_type`
 replace symbol V4L2_CTRL_TYPE_H264_PRED_WEIGHTS :c:type:`V4L.v4l2_ctrl_type`
 replace symbol V4L2_CTRL_TYPE_H264_SLICE_PARAMS :c:type:`V4L.v4l2_ctrl_type`
 replace symbol V4L2_CTRL_TYPE_H264_DECODE_PARAMS :c:type:`V4L.v4l2_ctrl_type`
+replace symbol V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS :c:type:`V4L.v4l2_ctrl_type`
+replace symbol V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS :c:type:`V4L.v4l2_ctrl_type`
 replace symbol V4L2_CTRL_TYPE_HEVC_SPS :c:type:`V4L.v4l2_ctrl_type`
 replace symbol V4L2_CTRL_TYPE_HEVC_PPS :c:type:`V4L.v4l2_ctrl_type`
 replace symbol V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS :c:type:`V4L.v4l2_ctrl_type`
diff --git a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
index c8baa9430c14..82c8b52e771c 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
@@ -531,6 +531,18 @@ See also the examples in :ref:`control`.
       - n/a
       - A struct :c:type:`v4l2_ctrl_hevc_decode_params`, containing HEVC
 	decoding parameters for stateless video decoders.
+    * - ``V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS``
+      - n/a
+      - n/a
+      - n/a
+      - A struct :c:type:`v4l2_ctrl_hevc_ext_sps_lt_rps`, containing HEVC
+	extended Long-Term RPS for stateless video decoders.
+    * - ``V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS``
+      - n/a
+      - n/a
+      - n/a
+      - A struct :c:type:`v4l2_ctrl_hevc_ext_sps_st_rps`, containing HEVC
+	extended Short-Term RPS for stateless video decoders.
     * - ``V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR``
       - n/a
       - n/a
-- 
2.52.0



From detlev.casanova at collabora.com  Wed Dec 17 09:40:39 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 17 Dec 2025 12:40:39 -0500
Subject: [PATCH v6 02/17] media: v4l2-ctrls: Add hevc_ext_sps_[ls]t_rps controls
In-Reply-To: <20251217174059.1341784-1-detlev.casanova@collabora.com>
References: <20251217174059.1341784-1-detlev.casanova@collabora.com>
Message-ID: <20251217174059.1341784-3-detlev.casanova@collabora.com>

The vdpu381 decoder found on newer Rockchip SoC need the information
from the long term and short term ref pic sets from the SPS.

So far, it wasn't included in the v4l2 API, so add it with new dynamic
sized controls.

Each element of the hevc_ext_sps_lt_rps array contains the long term ref
pic set at that index.
Each element of the hevc_ext_sps_st_rps contains the short term ref pic
set at that index, as the raw data.
It is the role of the drivers to calculate the reference sets values.

Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 drivers/media/v4l2-core/v4l2-ctrls-core.c | 28 +++++++++++
 drivers/media/v4l2-core/v4l2-ctrls-defs.c | 10 ++++
 include/uapi/linux/v4l2-controls.h        | 61 +++++++++++++++++++++++
 include/uapi/linux/videodev2.h            |  2 +
 4 files changed, 101 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c
index 209bc05883bb..f11255255c74 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-core.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c
@@ -424,6 +424,12 @@ void v4l2_ctrl_type_op_log(const struct v4l2_ctrl *ctrl)
 	case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
 		pr_cont("HEVC_SLICE_PARAMS");
 		break;
+	case V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS:
+		pr_cont("HEVC_EXT_SPS_ST_RPS");
+		break;
+	case V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS:
+		pr_cont("HEVC_EXT_SPS_LT_RPS");
+		break;
 	case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX:
 		pr_cont("HEVC_SCALING_MATRIX");
 		break;
@@ -961,6 +967,8 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
 	struct v4l2_ctrl_h264_pred_weights *p_h264_pred_weights;
 	struct v4l2_ctrl_h264_slice_params *p_h264_slice_params;
 	struct v4l2_ctrl_h264_decode_params *p_h264_dec_params;
+	struct v4l2_ctrl_hevc_ext_sps_lt_rps *p_hevc_lt_rps;
+	struct v4l2_ctrl_hevc_ext_sps_st_rps *p_hevc_st_rps;
 	struct v4l2_ctrl_hevc_sps *p_hevc_sps;
 	struct v4l2_ctrl_hevc_pps *p_hevc_pps;
 	struct v4l2_ctrl_hdr10_mastering_display *p_hdr10_mastering;
@@ -1254,6 +1262,20 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
 	case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
 		break;
 
+	case V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS:
+		p_hevc_st_rps = p;
+
+		if (p_hevc_st_rps->flags & ~V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED)
+			return -EINVAL;
+		break;
+
+	case V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS:
+		p_hevc_lt_rps = p;
+
+		if (p_hevc_lt_rps->flags & ~V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_USED_LT)
+			return -EINVAL;
+		break;
+
 	case V4L2_CTRL_TYPE_HDR10_CLL_INFO:
 		break;
 
@@ -2006,6 +2028,12 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 	case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
 		elem_size = sizeof(struct v4l2_ctrl_hevc_slice_params);
 		break;
+	case V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS:
+		elem_size = sizeof(struct v4l2_ctrl_hevc_ext_sps_st_rps);
+		break;
+	case V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS:
+		elem_size = sizeof(struct v4l2_ctrl_hevc_ext_sps_lt_rps);
+		break;
 	case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX:
 		elem_size = sizeof(struct v4l2_ctrl_hevc_scaling_matrix);
 		break;
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
index ad41f65374e2..167286c9e424 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
@@ -1233,6 +1233,8 @@ const char *v4l2_ctrl_get_name(u32 id)
 	case V4L2_CID_STATELESS_HEVC_DECODE_MODE:		return "HEVC Decode Mode";
 	case V4L2_CID_STATELESS_HEVC_START_CODE:		return "HEVC Start Code";
 	case V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS:	return "HEVC Entry Point Offsets";
+	case V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS:		return "HEVC Short Term Ref Sets";
+	case V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS:		return "HEVC Long Term Ref Sets";
 	case V4L2_CID_STATELESS_AV1_SEQUENCE:			return "AV1 Sequence Parameters";
 	case V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY:		return "AV1 Tile Group Entry";
 	case V4L2_CID_STATELESS_AV1_FRAME:			return "AV1 Frame Parameters";
@@ -1578,6 +1580,14 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
 		*type = V4L2_CTRL_TYPE_U32;
 		*flags |= V4L2_CTRL_FLAG_DYNAMIC_ARRAY;
 		break;
+	case V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS:
+		*type = V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS;
+		*flags |= V4L2_CTRL_FLAG_DYNAMIC_ARRAY;
+		break;
+	case V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS:
+		*type = V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS;
+		*flags |= V4L2_CTRL_FLAG_DYNAMIC_ARRAY;
+		break;
 	case V4L2_CID_STATELESS_VP9_COMPRESSED_HDR:
 		*type = V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR;
 		break;
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index f84ed133a6c9..e9f1fcc4f840 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -2099,6 +2099,8 @@ struct v4l2_ctrl_mpeg2_quantisation {
 #define V4L2_CID_STATELESS_HEVC_DECODE_MODE	(V4L2_CID_CODEC_STATELESS_BASE + 405)
 #define V4L2_CID_STATELESS_HEVC_START_CODE	(V4L2_CID_CODEC_STATELESS_BASE + 406)
 #define V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS (V4L2_CID_CODEC_STATELESS_BASE + 407)
+#define V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS  (V4L2_CID_CODEC_STATELESS_BASE + 408)
+#define V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS  (V4L2_CID_CODEC_STATELESS_BASE + 409)
 
 enum v4l2_stateless_hevc_decode_mode {
 	V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED,
@@ -2554,6 +2556,65 @@ struct v4l2_ctrl_hevc_scaling_matrix {
 	__u8	scaling_list_dc_coef_32x32[2];
 };
 
+#define V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED	0x1
+
+/*
+ * struct v4l2_ctrl_hevc_ext_sps_st_rps - HEVC short term RPS parameters
+ *
+ * Dynamic size 1-dimension array for short term RPS. The number of elements
+ * is v4l2_ctrl_hevc_sps::num_short_term_ref_pic_sets. It can contain up to 65 elements.
+ *
+ * @delta_idx_minus1: Specifies the delta compare to the index. See details in section 7.4.8
+ *                    "Short-term reference picture set semantics" of the specification.
+ * @delta_rps_sign: Sign of the delta as specified in section 7.4.8 "Short-term reference picture
+ *                  set semantics" of the specification.
+ * @abs_delta_rps_minus1: Absolute delta RPS as specified in section 7.4.8 "Short-term reference
+ *                        picture set semantics" of the specification.
+ * @num_negative_pics: Number of short-term RPS entries that have picture order count values less
+ *                     than the picture order count value of the current picture.
+ * @num_positive_pics: Number of short-term RPS entries that have picture order count values
+ *                     greater than the picture order count value of the current picture.
+ * @used_by_curr_pic: Bit j specifies if short-term RPS j is used by the current picture.
+ * @use_delta_flag: Bit j equals to 1 specifies that the j-th entry in the source candidate
+ *                  short-term RPS is included in this candidate short-term RPS.
+ * @delta_poc_s0_minus1: Specifies the negative picture order count delta for the i-th entry in
+ *                       the short-term RPS. See details in section 7.4.8 "Short-term reference
+ *                       picture set semantics" of the specification.
+ * @delta_poc_s1_minus1: Specifies the positive picture order count delta for the i-th entry in
+ *                       the short-term RPS. See details in section 7.4.8 "Short-term reference
+ *                       picture set semantics" of the specification.
+ * @flags: See V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_{}
+ */
+struct v4l2_ctrl_hevc_ext_sps_st_rps {
+	__u8	delta_idx_minus1;
+	__u8	delta_rps_sign;
+	__u8	num_negative_pics;
+	__u8	num_positive_pics;
+	__u32	used_by_curr_pic;
+	__u32	use_delta_flag;
+	__u16	abs_delta_rps_minus1;
+	__u16	delta_poc_s0_minus1[16];
+	__u16	delta_poc_s1_minus1[16];
+	__u16	flags;
+};
+
+#define V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_USED_LT		0x1
+
+/*
+ * struct v4l2_ctrl_hevc_ext_sps_lt_rps - HEVC long term RPS parameters
+ *
+ * Dynamic size 1-dimension array for long term RPS. The number of elements
+ * is v4l2_ctrl_hevc_sps::num_long_term_ref_pics_sps. It can contain up to 65 elements.
+ *
+ * @lt_ref_pic_poc_lsb_sps: picture order count modulo MaxPicOrderCntLsb of the i-th candidate
+ *                          long-term reference picture.
+ * @flags: See V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_{}
+ */
+struct v4l2_ctrl_hevc_ext_sps_lt_rps {
+	__u16	lt_ref_pic_poc_lsb_sps;
+	__u16	flags;
+};
+
 /* Stateless VP9 controls */
 
 #define V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED	0x1
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index add08188f068..5efaeb74ef92 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -1985,6 +1985,8 @@ enum v4l2_ctrl_type {
 	V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS	= 0x0272,
 	V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX	= 0x0273,
 	V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS	= 0x0274,
+	V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS	= 0x0275,
+	V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS	= 0x0276,
 
 	V4L2_CTRL_TYPE_AV1_SEQUENCE	    = 0x280,
 	V4L2_CTRL_TYPE_AV1_TILE_GROUP_ENTRY = 0x281,
-- 
2.52.0



From detlev.casanova at collabora.com  Wed Dec 17 09:40:40 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 17 Dec 2025 12:40:40 -0500
Subject: [PATCH v6 03/17] media: visl: Add HEVC short and long term RPS sets
In-Reply-To: <20251217174059.1341784-1-detlev.casanova@collabora.com>
References: <20251217174059.1341784-1-detlev.casanova@collabora.com>
Message-ID: <20251217174059.1341784-4-detlev.casanova@collabora.com>

Log the recently added v4l2 controls to set HEVC short and long term RPS
sets with 2 new ftrace entries.

Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 drivers/media/test-drivers/visl/visl-dec.c    |  7 +++
 drivers/media/test-drivers/visl/visl-dec.h    |  3 +
 .../media/test-drivers/visl/visl-trace-hevc.h | 59 +++++++++++++++++++
 3 files changed, 69 insertions(+)

diff --git a/drivers/media/test-drivers/visl/visl-dec.c b/drivers/media/test-drivers/visl/visl-dec.c
index d90b79de8384..6bbf93757047 100644
--- a/drivers/media/test-drivers/visl/visl-dec.c
+++ b/drivers/media/test-drivers/visl/visl-dec.c
@@ -547,6 +547,9 @@ static void visl_trace_ctrls(struct visl_ctx *ctx, struct visl_run *run)
 			trace_v4l2_hevc_dpb_entry(&run->hevc.dpram->dpb[i]);
 
 		trace_v4l2_hevc_pred_weight_table(&run->hevc.spram->pred_weight_table);
+		trace_v4l2_ctrl_hevc_ext_sps_lt_rps(run->hevc.rps_lt);
+		trace_v4l2_ctrl_hevc_ext_sps_st_rps(run->hevc.rps_st);
+
 		break;
 	case VISL_CODEC_AV1:
 		trace_v4l2_ctrl_av1_sequence(run->av1.seq);
@@ -611,6 +614,10 @@ void visl_device_run(void *priv)
 		run.hevc.spram = visl_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_SLICE_PARAMS);
 		run.hevc.sm = visl_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_SCALING_MATRIX);
 		run.hevc.dpram = visl_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_DECODE_PARAMS);
+		run.hevc.rps_lt = visl_find_control_data(ctx,
+							 V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS);
+		run.hevc.rps_st = visl_find_control_data(ctx,
+							 V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS);
 		break;
 	case VISL_CODEC_AV1:
 		run.av1.seq = visl_find_control_data(ctx, V4L2_CID_STATELESS_AV1_SEQUENCE);
diff --git a/drivers/media/test-drivers/visl/visl-dec.h b/drivers/media/test-drivers/visl/visl-dec.h
index c2c2ef3a8798..6e7562e555bb 100644
--- a/drivers/media/test-drivers/visl/visl-dec.h
+++ b/drivers/media/test-drivers/visl/visl-dec.h
@@ -7,6 +7,7 @@
 #ifndef _VISL_DEC_H_
 #define _VISL_DEC_H_
 
+#include "linux/v4l2-controls.h"
 #include "visl.h"
 
 struct visl_fwht_run {
@@ -43,6 +44,8 @@ struct visl_hevc_run {
 	const struct v4l2_ctrl_hevc_slice_params *spram;
 	const struct v4l2_ctrl_hevc_scaling_matrix *sm;
 	const struct v4l2_ctrl_hevc_decode_params *dpram;
+	const struct v4l2_ctrl_hevc_ext_sps_lt_rps *rps_lt;
+	const struct v4l2_ctrl_hevc_ext_sps_st_rps *rps_st;
 };
 
 struct visl_av1_run {
diff --git a/drivers/media/test-drivers/visl/visl-trace-hevc.h b/drivers/media/test-drivers/visl/visl-trace-hevc.h
index 837b8ec12e97..e1e702f5f4cf 100644
--- a/drivers/media/test-drivers/visl/visl-trace-hevc.h
+++ b/drivers/media/test-drivers/visl/visl-trace-hevc.h
@@ -1,4 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0+ */
+#include "linux/v4l2-controls.h"
 #if !defined(_VISL_TRACE_HEVC_H_) || defined(TRACE_HEADER_MULTI_READ)
 #define _VISL_TRACE_HEVC_H_
 
@@ -343,6 +344,54 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_decode_params_tmpl,
 	))
 );
 
+DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_ext_sps_lt_rps_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_hevc_ext_sps_lt_rps *lt),
+	TP_ARGS(lt),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_hevc_ext_sps_lt_rps, lt)),
+	TP_fast_assign(__entry->lt = *lt),
+	TP_printk("\nflags %s\n"
+		  "lt_ref_pic_poc_lsb_sps %x\n",
+		__print_flags(__entry->lt.flags, "|",
+		{V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_USED_LT, "USED_LT"}
+		  ),
+		__entry->lt.lt_ref_pic_poc_lsb_sps
+	)
+)
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_ext_sps_st_rps_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_hevc_ext_sps_st_rps *st),
+	TP_ARGS(st),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_hevc_ext_sps_st_rps, st)),
+	TP_fast_assign(__entry->st = *st),
+	TP_printk("\nflags %s\n"
+		  "delta_idx_minus1: %u\n"
+		  "delta_rps_sign: %u\n"
+		  "abs_delta_rps_minus1: %u\n"
+		  "num_negative_pics: %u\n"
+		  "num_positive_pics: %u\n"
+		  "used_by_curr_pic: %08x\n"
+		  "use_delta_flag: %08x\n"
+		  "delta_poc_s0_minus1: %s\n"
+		  "delta_poc_s1_minus1: %s\n",
+		  __print_flags(__entry->st.flags, "|",
+		    {V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED, "INTER_REF_PIC_SET_PRED"}
+		  ),
+		  __entry->st.delta_idx_minus1,
+		  __entry->st.delta_rps_sign,
+		  __entry->st.abs_delta_rps_minus1,
+		  __entry->st.num_negative_pics,
+		  __entry->st.num_positive_pics,
+		  __entry->st.used_by_curr_pic,
+		  __entry->st.use_delta_flag,
+		  __print_array(__entry->st.delta_poc_s0_minus1,
+				ARRAY_SIZE(__entry->st.delta_poc_s0_minus1),
+				sizeof(__entry->st.delta_poc_s0_minus1[0])),
+		  __print_array(__entry->st.delta_poc_s1_minus1,
+				ARRAY_SIZE(__entry->st.delta_poc_s1_minus1),
+				sizeof(__entry->st.delta_poc_s1_minus1[0]))
+	)
+)
+
 
 DECLARE_EVENT_CLASS(v4l2_hevc_dpb_entry_tmpl,
 	TP_PROTO(const struct v4l2_hevc_dpb_entry *e),
@@ -391,6 +440,16 @@ DEFINE_EVENT(v4l2_ctrl_hevc_decode_params_tmpl, v4l2_ctrl_hevc_decode_params,
 	TP_ARGS(d)
 );
 
+DEFINE_EVENT(v4l2_ctrl_hevc_ext_sps_lt_rps_tmpl, v4l2_ctrl_hevc_ext_sps_lt_rps,
+	TP_PROTO(const struct v4l2_ctrl_hevc_ext_sps_lt_rps *lt),
+	TP_ARGS(lt)
+);
+
+DEFINE_EVENT(v4l2_ctrl_hevc_ext_sps_st_rps_tmpl, v4l2_ctrl_hevc_ext_sps_st_rps,
+	TP_PROTO(const struct v4l2_ctrl_hevc_ext_sps_st_rps *st),
+	TP_ARGS(st)
+);
+
 DEFINE_EVENT(v4l2_hevc_dpb_entry_tmpl, v4l2_hevc_dpb_entry,
 	TP_PROTO(const struct v4l2_hevc_dpb_entry *e),
 	TP_ARGS(e)
-- 
2.52.0



From detlev.casanova at collabora.com  Wed Dec 17 09:40:41 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 17 Dec 2025 12:40:41 -0500
Subject: [PATCH v6 04/17] media: rkvdec: Switch to using structs instead of writel
In-Reply-To: <20251217174059.1341784-1-detlev.casanova@collabora.com>
References: <20251217174059.1341784-1-detlev.casanova@collabora.com>
Message-ID: <20251217174059.1341784-5-detlev.casanova@collabora.com>

In an effort to merge the rkvdec2 driver [1] with this one, switch from
writel() calls to using structs to represent the register mappings.

This is done in order to have all supported decoders use the same format
in the future and ease reading of the code.

Using structs also improves stability as the hardware is tested and
validated downstream using a similar method.
It was noticed, on decoders, that:
 - Some registers require to be writen in increasing order [2]
 - Some registers, even if unrelated, need to be written to their reset
   values (it was the case here for axi_ddr_[rw]data).

Using structs can also help improving performance later when, e.g.
multicore support is added on RK3588.

Performance seems to be slightly improved, but at least, not made worse.
Running fluster's JVT-AVC_V1 test suite with GStreamer on the Radxa ROCK
PI 4 SE gives the following times:

Before this patch:

- --jobs 1: Ran 129/135 tests successfully               in 77.167 secs
- --jobs 6: Ran 129/135 tests successfully               in 23.046 secs

With this patch:
- --jobs 1: Ran 129/135 tests successfully               in 70.698 secs
- --jobs 6: Ran 129/135 tests successfully               in 22.917 secs

This also shows that the fluster score hasn't changed.

[1]: https://lore.kernel.org/all/20250325213303.826925-1-detlev.casanova at collabora.com/
[2]: https://lore.kernel.org/all/20200127143009.15677-5-andrzej.p at collabora.com/

Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../platform/rockchip/rkvdec/rkvdec-h264.c    | 165 +++--
 .../platform/rockchip/rkvdec/rkvdec-hevc.c    |  63 +-
 .../platform/rockchip/rkvdec/rkvdec-regs.h    | 571 ++++++++++++------
 .../platform/rockchip/rkvdec/rkvdec-vp9.c     | 231 +++----
 .../media/platform/rockchip/rkvdec/rkvdec.c   |  10 +-
 .../media/platform/rockchip/rkvdec/rkvdec.h   |   1 +
 6 files changed, 587 insertions(+), 454 deletions(-)

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
index d14b4d173448..116e7b1076b7 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
@@ -115,6 +115,7 @@ struct rkvdec_h264_run {
 struct rkvdec_h264_ctx {
 	struct rkvdec_aux_buf priv_tbl;
 	struct rkvdec_h264_reflists reflists;
+	struct rkvdec_regs regs;
 };
 
 #define CABAC_ENTRY(ctxidx, idc0_m, idc0_n, idc1_m, idc1_n,		\
@@ -841,45 +842,41 @@ static void assemble_hw_scaling_list(struct rkvdec_ctx *ctx,
 }
 
 /*
- * dpb poc related registers table
+ * Set the ref POC in the correct register.
+ *
+ * The 32 registers are spread across 3 regions, each alternating top and bottom ref POCs:
+ *  - 1: ref 0 to 14 contain top 0 to 7 and bottoms 0 to 6
+ *  - 2: ref 15 to 29 contain top 8 to 14 and bottoms 7 to 14
+ *  - 3: ref 30 and 31 which correspond to top 15 and bottom 15 respectively.
  */
-static const u32 poc_reg_tbl_top_field[16] = {
-	RKVDEC_REG_H264_POC_REFER0(0),
-	RKVDEC_REG_H264_POC_REFER0(2),
-	RKVDEC_REG_H264_POC_REFER0(4),
-	RKVDEC_REG_H264_POC_REFER0(6),
-	RKVDEC_REG_H264_POC_REFER0(8),
-	RKVDEC_REG_H264_POC_REFER0(10),
-	RKVDEC_REG_H264_POC_REFER0(12),
-	RKVDEC_REG_H264_POC_REFER0(14),
-	RKVDEC_REG_H264_POC_REFER1(1),
-	RKVDEC_REG_H264_POC_REFER1(3),
-	RKVDEC_REG_H264_POC_REFER1(5),
-	RKVDEC_REG_H264_POC_REFER1(7),
-	RKVDEC_REG_H264_POC_REFER1(9),
-	RKVDEC_REG_H264_POC_REFER1(11),
-	RKVDEC_REG_H264_POC_REFER1(13),
-	RKVDEC_REG_H264_POC_REFER2(0)
-};
-
-static const u32 poc_reg_tbl_bottom_field[16] = {
-	RKVDEC_REG_H264_POC_REFER0(1),
-	RKVDEC_REG_H264_POC_REFER0(3),
-	RKVDEC_REG_H264_POC_REFER0(5),
-	RKVDEC_REG_H264_POC_REFER0(7),
-	RKVDEC_REG_H264_POC_REFER0(9),
-	RKVDEC_REG_H264_POC_REFER0(11),
-	RKVDEC_REG_H264_POC_REFER0(13),
-	RKVDEC_REG_H264_POC_REFER1(0),
-	RKVDEC_REG_H264_POC_REFER1(2),
-	RKVDEC_REG_H264_POC_REFER1(4),
-	RKVDEC_REG_H264_POC_REFER1(6),
-	RKVDEC_REG_H264_POC_REFER1(8),
-	RKVDEC_REG_H264_POC_REFER1(10),
-	RKVDEC_REG_H264_POC_REFER1(12),
-	RKVDEC_REG_H264_POC_REFER1(14),
-	RKVDEC_REG_H264_POC_REFER2(1)
-};
+static void set_poc_reg(struct rkvdec_regs *regs, uint32_t poc, int id, bool bottom)
+{
+	if (!bottom) {
+		switch (id) {
+		case 0 ... 7:
+			regs->h26x.ref0_14_poc[id * 2] = poc;
+			break;
+		case 8 ... 14:
+			regs->h26x.ref15_29_poc[(id - 8) * 2 + 1] = poc;
+			break;
+		case 15:
+			regs->h26x.ref30_poc = poc;
+			break;
+		}
+	} else {
+		switch (id) {
+		case 0 ... 6:
+			regs->h26x.ref0_14_poc[id * 2 + 1] = poc;
+			break;
+		case 7 ... 14:
+			regs->h26x.ref15_29_poc[(id - 7) * 2] = poc;
+			break;
+		case 15:
+			regs->h26x.ref31_poc = poc;
+			break;
+		}
+	}
+}
 
 static void config_registers(struct rkvdec_ctx *ctx,
 			     struct rkvdec_h264_run *run)
@@ -894,6 +891,7 @@ static void config_registers(struct rkvdec_ctx *ctx,
 	struct vb2_v4l2_buffer *src_buf = run->base.bufs.src;
 	struct vb2_v4l2_buffer *dst_buf = run->base.bufs.dst;
 	const struct v4l2_format *f;
+	struct rkvdec_regs *regs = &h264_ctx->regs;
 	dma_addr_t rlc_addr;
 	dma_addr_t refer_addr;
 	u32 rlc_len;
@@ -903,10 +901,11 @@ static void config_registers(struct rkvdec_ctx *ctx,
 	u32 yuv_virstride = 0;
 	u32 offset;
 	dma_addr_t dst_addr;
-	u32 reg, i;
+	u32 i;
 
-	reg = RKVDEC_MODE(RKVDEC_MODE_H264);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_SYSCTRL);
+	memset(regs, 0, sizeof(*regs));
+
+	regs->common.reg02.dec_mode = RKVDEC_MODE_H264;
 
 	f = &ctx->decoded_fmt;
 	dst_fmt = &f->fmt.pix_mp;
@@ -921,39 +920,35 @@ static void config_registers(struct rkvdec_ctx *ctx,
 	else if (sps->chroma_format_idc == 2)
 		yuv_virstride = 2 * y_virstride;
 
-	reg = RKVDEC_Y_HOR_VIRSTRIDE(hor_virstride / 16) |
-	      RKVDEC_UV_HOR_VIRSTRIDE(hor_virstride / 16) |
-	      RKVDEC_SLICE_NUM_HIGHBIT |
-	      RKVDEC_SLICE_NUM_LOWBITS(0x7ff);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_PICPAR);
+	regs->common.reg03.uv_hor_virstride = hor_virstride / 16;
+	regs->common.reg03.y_hor_virstride = hor_virstride / 16;
+	regs->common.reg03.slice_num_highbit = 1;
+	regs->common.reg03.slice_num_lowbits = 0x7ff;
 
 	/* config rlc base address */
 	rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
-	writel_relaxed(rlc_addr, rkvdec->regs + RKVDEC_REG_STRM_RLC_BASE);
-	writel_relaxed(rlc_addr, rkvdec->regs + RKVDEC_REG_RLCWRITE_BASE);
+	regs->common.strm_rlc_base = rlc_addr;
+	regs->h26x.rlcwrite_base = rlc_addr;
 
 	rlc_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
-	reg = RKVDEC_STRM_LEN(rlc_len);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_STRM_LEN);
+	regs->common.stream_len = rlc_len;
 
 	/* config cabac table */
 	offset = offsetof(struct rkvdec_h264_priv_tbl, cabac_table);
-	writel_relaxed(priv_start_addr + offset,
-		       rkvdec->regs + RKVDEC_REG_CABACTBL_PROB_BASE);
+	regs->common.cabactbl_base = priv_start_addr + offset;
 
 	/* config output base address */
 	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
-	writel_relaxed(dst_addr, rkvdec->regs + RKVDEC_REG_DECOUT_BASE);
+	regs->common.decout_base = dst_addr;
 
-	reg = RKVDEC_Y_VIRSTRIDE(y_virstride / 16);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_Y_VIRSTRIDE);
+	regs->common.reg08.y_virstride = y_virstride / 16;
 
-	reg = RKVDEC_YUV_VIRSTRIDE(yuv_virstride / 16);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_YUV_VIRSTRIDE);
+	regs->common.reg09.yuv_virstride = yuv_virstride / 16;
 
 	/* config ref pic address & poc */
 	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
 		struct vb2_buffer *vb_buf = run->ref_buf[i];
+		struct ref_base *base;
 
 		/*
 		 * If a DPB entry is unused or invalid, address of current destination
@@ -963,54 +958,36 @@ static void config_registers(struct rkvdec_ctx *ctx,
 			vb_buf = &dst_buf->vb2_buf;
 		refer_addr = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
 
-		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)
-			refer_addr |= RKVDEC_COLMV_USED_FLAG_REF;
-		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD)
-			refer_addr |= RKVDEC_FIELD_REF;
-
-		if (dpb[i].fields & V4L2_H264_TOP_FIELD_REF)
-			refer_addr |= RKVDEC_TOPFIELD_USED_REF;
-		if (dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF)
-			refer_addr |= RKVDEC_BOTFIELD_USED_REF;
-
-		writel_relaxed(dpb[i].top_field_order_cnt,
-			       rkvdec->regs +  poc_reg_tbl_top_field[i]);
-		writel_relaxed(dpb[i].bottom_field_order_cnt,
-			       rkvdec->regs + poc_reg_tbl_bottom_field[i]);
-
 		if (i < V4L2_H264_NUM_DPB_ENTRIES - 1)
-			writel_relaxed(refer_addr,
-				       rkvdec->regs + RKVDEC_REG_H264_BASE_REFER(i));
+			base = &regs->h26x.ref0_14_base[i];
 		else
-			writel_relaxed(refer_addr,
-				       rkvdec->regs + RKVDEC_REG_H264_BASE_REFER15);
-	}
+			base = &regs->h26x.ref15_base;
 
-	reg = RKVDEC_CUR_POC(dec_params->top_field_order_cnt);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC0);
+		base->field_ref = !!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD);
+		base->colmv_used_flag_ref = !!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE);
+		base->topfield_used_ref = !!(dpb[i].fields & V4L2_H264_TOP_FIELD_REF);
+		base->botfield_used_ref = !!(dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF);
+		base->base_addr = refer_addr >> 4;
 
-	reg = RKVDEC_CUR_POC(dec_params->bottom_field_order_cnt);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC1);
+		set_poc_reg(regs, dpb[i].top_field_order_cnt, i, false);
+		set_poc_reg(regs, dpb[i].bottom_field_order_cnt, i, true);
+	}
+
+	regs->h26x.cur_poc = dec_params->top_field_order_cnt;
+	regs->h26x.cur_poc1 = dec_params->bottom_field_order_cnt;
 
 	/* config hw pps address */
 	offset = offsetof(struct rkvdec_h264_priv_tbl, param_set);
-	writel_relaxed(priv_start_addr + offset,
-		       rkvdec->regs + RKVDEC_REG_PPS_BASE);
+	regs->h26x.pps_base = priv_start_addr + offset;
 
 	/* config hw rps address */
 	offset = offsetof(struct rkvdec_h264_priv_tbl, rps);
-	writel_relaxed(priv_start_addr + offset,
-		       rkvdec->regs + RKVDEC_REG_RPS_BASE);
-
-	reg = RKVDEC_AXI_DDR_RDATA(0);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_RDATA);
-
-	reg = RKVDEC_AXI_DDR_WDATA(0);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_WDATA);
+	regs->h26x.rps_base = priv_start_addr + offset;
 
 	offset = offsetof(struct rkvdec_h264_priv_tbl, err_info);
-	writel_relaxed(priv_start_addr + offset,
-		       rkvdec->regs + RKVDEC_REG_H264_ERRINFO_BASE);
+	regs->h26x.errorinfo_base = priv_start_addr + offset;
+
+	rkvdec_memcpy_toio(rkvdec->regs, regs, MIN(sizeof(*regs), 4 * rkvdec->variant->num_regs));
 }
 
 #define RKVDEC_H264_MAX_DEPTH_IN_BYTES		2
@@ -1181,8 +1158,6 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
 
 	schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000));
 
-	writel(0, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN);
-	writel(0, rkvdec->regs + RKVDEC_REG_H264_ERR_E);
 	writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND);
 	writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);
 
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
index fc7e6a260b0a..01f92fa27356 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
@@ -129,6 +129,7 @@ struct rkvdec_hevc_run {
 struct rkvdec_hevc_ctx {
 	struct rkvdec_aux_buf priv_tbl;
 	struct v4l2_ctrl_hevc_scaling_matrix scaling_matrix_cache;
+	struct rkvdec_regs regs;
 };
 
 struct scaling_factor {
@@ -548,6 +549,7 @@ static void config_registers(struct rkvdec_ctx *ctx,
 	const struct v4l2_ctrl_hevc_slice_params *sl_params = &run->slices_params[0];
 	const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb;
 	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
+	struct rkvdec_regs *regs = &hevc_ctx->regs;
 	dma_addr_t priv_start_addr = hevc_ctx->priv_tbl.dma;
 	const struct v4l2_pix_format_mplane *dst_fmt;
 	struct vb2_v4l2_buffer *src_buf = run->base.bufs.src;
@@ -564,8 +566,9 @@ static void config_registers(struct rkvdec_ctx *ctx,
 	dma_addr_t dst_addr;
 	u32 reg, i;
 
-	reg = RKVDEC_MODE(RKVDEC_MODE_HEVC);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_SYSCTRL);
+	memset(regs, 0, sizeof(*regs));
+
+	regs->common.reg02.dec_mode = RKVDEC_MODE_HEVC;
 
 	f = &ctx->decoded_fmt;
 	dst_fmt = &f->fmt.pix_mp;
@@ -580,33 +583,27 @@ static void config_registers(struct rkvdec_ctx *ctx,
 	else if (sps->chroma_format_idc == 2)
 		yuv_virstride = 2 * y_virstride;
 
-	reg = RKVDEC_Y_HOR_VIRSTRIDE(hor_virstride / 16) |
-	      RKVDEC_UV_HOR_VIRSTRIDE(hor_virstride / 16) |
-	      RKVDEC_SLICE_NUM_LOWBITS(run->num_slices);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_PICPAR);
+	regs->common.reg03.slice_num_lowbits = run->num_slices;
+	regs->common.reg03.uv_hor_virstride = hor_virstride / 16;
+	regs->common.reg03.y_hor_virstride = hor_virstride / 16;
 
 	/* config rlc base address */
 	rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
-	writel_relaxed(rlc_addr, rkvdec->regs + RKVDEC_REG_STRM_RLC_BASE);
+	regs->common.strm_rlc_base = rlc_addr;
 
 	rlc_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
-	reg = RKVDEC_STRM_LEN(round_up(rlc_len, 16) + 64);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_STRM_LEN);
+	regs->common.stream_len = round_up(rlc_len, 16) + 64;
 
 	/* config cabac table */
 	offset = offsetof(struct rkvdec_hevc_priv_tbl, cabac_table);
-	writel_relaxed(priv_start_addr + offset,
-		       rkvdec->regs + RKVDEC_REG_CABACTBL_PROB_BASE);
+	regs->common.cabactbl_base = priv_start_addr + offset;
 
 	/* config output base address */
 	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
-	writel_relaxed(dst_addr, rkvdec->regs + RKVDEC_REG_DECOUT_BASE);
-
-	reg = RKVDEC_Y_VIRSTRIDE(y_virstride / 16);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_Y_VIRSTRIDE);
+	regs->common.decout_base = dst_addr;
 
-	reg = RKVDEC_YUV_VIRSTRIDE(yuv_virstride / 16);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_YUV_VIRSTRIDE);
+	regs->common.reg08.y_virstride = y_virstride / 16;
+	regs->common.reg09.yuv_virstride = yuv_virstride / 16;
 
 	/* config ref pic address */
 	for (i = 0; i < 15; i++) {
@@ -620,33 +617,29 @@ static void config_registers(struct rkvdec_ctx *ctx,
 		}
 
 		refer_addr = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
-		writel_relaxed(refer_addr | reg,
-			       rkvdec->regs + RKVDEC_REG_H264_BASE_REFER(i));
 
-		reg = RKVDEC_POC_REFER(i < decode_params->num_active_dpb_entries ?
-			dpb[i].pic_order_cnt_val : 0);
-		writel_relaxed(reg,
-			       rkvdec->regs + RKVDEC_REG_H264_POC_REFER0(i));
+		regs->h26x.ref0_14_base[i].base_addr = refer_addr >> 4;
+		regs->h26x.ref0_14_base[i].field_ref = !!(reg & 1);
+		regs->h26x.ref0_14_base[i].topfield_used_ref = !!(reg & 2);
+		regs->h26x.ref0_14_base[i].botfield_used_ref = !!(reg & 4);
+		regs->h26x.ref0_14_base[i].colmv_used_flag_ref = !!(reg & 8);
+
+		regs->h26x.ref0_14_poc[i] = i < decode_params->num_active_dpb_entries
+					    ? dpb[i].pic_order_cnt_val
+					    : 0;
 	}
 
-	reg = RKVDEC_CUR_POC(sl_params->slice_pic_order_cnt);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC0);
+	regs->h26x.cur_poc = sl_params->slice_pic_order_cnt;
 
 	/* config hw pps address */
 	offset = offsetof(struct rkvdec_hevc_priv_tbl, param_set);
-	writel_relaxed(priv_start_addr + offset,
-		       rkvdec->regs + RKVDEC_REG_PPS_BASE);
+	regs->h26x.pps_base = priv_start_addr + offset;
 
 	/* config hw rps address */
 	offset = offsetof(struct rkvdec_hevc_priv_tbl, rps);
-	writel_relaxed(priv_start_addr + offset,
-		       rkvdec->regs + RKVDEC_REG_RPS_BASE);
-
-	reg = RKVDEC_AXI_DDR_RDATA(0);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_RDATA);
+	regs->h26x.rps_base = priv_start_addr + offset;
 
-	reg = RKVDEC_AXI_DDR_WDATA(0);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_WDATA);
+	rkvdec_memcpy_toio(rkvdec->regs, regs, MIN(sizeof(*regs), 4 * rkvdec->variant->num_regs));
 }
 
 #define RKVDEC_HEVC_MAX_DEPTH_IN_BYTES		2
@@ -784,8 +777,6 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
 
 	schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000));
 
-	writel(0, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN);
-	writel(0, rkvdec->regs + RKVDEC_REG_H264_ERR_E);
 	writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND);
 	writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);
 
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h
index c627b6b6f53a..7745ea257148 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h
@@ -3,7 +3,12 @@
 #ifndef RKVDEC_REGS_H_
 #define RKVDEC_REGS_H_
 
-/* rkvcodec registers */
+#include <linux/types.h>
+
+/*
+ * REG_INTERRUPT is accessed via writel to enable the decoder after
+ * configuring it and clear interrupt strmd_error_status
+ */
 #define RKVDEC_REG_INTERRUPT				0x004
 #define RKVDEC_INTERRUPT_DEC_E				BIT(0)
 #define RKVDEC_CONFIG_DEC_CLK_GATE_E			BIT(1)
@@ -30,198 +35,384 @@
 #define RKVDEC_SOFTRESET_RDY				BIT(22)
 #define RKVDEC_WR_DDR_ALIGN_EN				BIT(23)
 
-#define RKVDEC_REG_SYSCTRL				0x008
-#define RKVDEC_IN_ENDIAN				BIT(0)
-#define RKVDEC_IN_SWAP32_E				BIT(1)
-#define RKVDEC_IN_SWAP64_E				BIT(2)
-#define RKVDEC_STR_ENDIAN				BIT(3)
-#define RKVDEC_STR_SWAP32_E				BIT(4)
-#define RKVDEC_STR_SWAP64_E				BIT(5)
-#define RKVDEC_OUT_ENDIAN				BIT(6)
-#define RKVDEC_OUT_SWAP32_E				BIT(7)
-#define RKVDEC_OUT_CBCR_SWAP				BIT(8)
-#define RKVDEC_RLC_MODE_DIRECT_WRITE			BIT(10)
-#define RKVDEC_RLC_MODE					BIT(11)
-#define RKVDEC_STRM_START_BIT(x)			(((x) & 0x7f) << 12)
-#define RKVDEC_MODE(x)					(((x) & 0x03) << 20)
-#define RKVDEC_MODE_HEVC				0
-#define RKVDEC_MODE_H264				1
-#define RKVDEC_MODE_VP9					2
-#define RKVDEC_RPS_MODE					BIT(24)
-#define RKVDEC_STRM_MODE				BIT(25)
-#define RKVDEC_H264_STRM_LASTPKT			BIT(26)
-#define RKVDEC_H264_FIRSTSLICE_FLAG			BIT(27)
-#define RKVDEC_H264_FRAME_ORSLICE			BIT(28)
-#define RKVDEC_BUSPR_SLOT_DIS				BIT(29)
-
-#define RKVDEC_REG_PICPAR				0x00C
-#define RKVDEC_Y_HOR_VIRSTRIDE(x)			((x) & 0x1ff)
-#define RKVDEC_SLICE_NUM_HIGHBIT			BIT(11)
-#define RKVDEC_UV_HOR_VIRSTRIDE(x)			(((x) & 0x1ff) << 12)
-#define RKVDEC_SLICE_NUM_LOWBITS(x)			(((x) & 0x7ff) << 21)
-
-#define RKVDEC_REG_STRM_RLC_BASE			0x010
-
-#define RKVDEC_REG_STRM_LEN				0x014
-#define RKVDEC_STRM_LEN(x)				((x) & 0x7ffffff)
-
-#define RKVDEC_REG_CABACTBL_PROB_BASE			0x018
-#define RKVDEC_REG_DECOUT_BASE				0x01C
-
-#define RKVDEC_REG_Y_VIRSTRIDE				0x020
-#define RKVDEC_Y_VIRSTRIDE(x)				((x) & 0xfffff)
-
-#define RKVDEC_REG_YUV_VIRSTRIDE			0x024
-#define RKVDEC_YUV_VIRSTRIDE(x)				((x) & 0x1fffff)
-#define RKVDEC_REG_H264_BASE_REFER(i)			(((i) * 0x04) + 0x028)
-
-#define RKVDEC_REG_H264_BASE_REFER15			0x0C0
-#define RKVDEC_FIELD_REF				BIT(0)
-#define RKVDEC_TOPFIELD_USED_REF			BIT(1)
-#define RKVDEC_BOTFIELD_USED_REF			BIT(2)
-#define RKVDEC_COLMV_USED_FLAG_REF			BIT(3)
-
-#define RKVDEC_REG_VP9_LAST_FRAME_BASE			0x02c
-#define RKVDEC_REG_VP9_GOLDEN_FRAME_BASE		0x030
-#define RKVDEC_REG_VP9_ALTREF_FRAME_BASE		0x034
-
-#define RKVDEC_REG_VP9_CPRHEADER_OFFSET			0x028
-#define RKVDEC_VP9_CPRHEADER_OFFSET(x)			((x) & 0xffff)
-
-#define RKVDEC_REG_VP9_REFERLAST_BASE			0x02C
-#define RKVDEC_REG_VP9_REFERGOLDEN_BASE			0x030
-#define RKVDEC_REG_VP9_REFERALFTER_BASE			0x034
-
-#define RKVDEC_REG_VP9COUNT_BASE			0x038
-#define RKVDEC_VP9COUNT_UPDATE_EN			BIT(0)
-
-#define RKVDEC_REG_VP9_SEGIDLAST_BASE			0x03C
-#define RKVDEC_REG_VP9_SEGIDCUR_BASE			0x040
-#define RKVDEC_REG_VP9_FRAME_SIZE(i)			((i) * 0x04 + 0x044)
-#define RKVDEC_VP9_FRAMEWIDTH(x)			(((x) & 0xffff) << 0)
-#define RKVDEC_VP9_FRAMEHEIGHT(x)			(((x) & 0xffff) << 16)
-
-#define RKVDEC_VP9_SEGID_GRP(i)				((i) * 0x04 + 0x050)
-#define RKVDEC_SEGID_ABS_DELTA(x)			((x) & 0x1)
-#define RKVDEC_SEGID_FRAME_QP_DELTA_EN(x)		(((x) & 0x1) << 1)
-#define RKVDEC_SEGID_FRAME_QP_DELTA(x)			(((x) & 0x1ff) << 2)
-#define RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE_EN(x)	(((x) & 0x1) << 11)
-#define RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE(x)		(((x) & 0x7f) << 12)
-#define RKVDEC_SEGID_REFERINFO_EN(x)			(((x) & 0x1) << 19)
-#define RKVDEC_SEGID_REFERINFO(x)			(((x) & 0x03) << 20)
-#define RKVDEC_SEGID_FRAME_SKIP_EN(x)			(((x) & 0x1) << 22)
-
-#define RKVDEC_VP9_CPRHEADER_CONFIG			0x070
-#define RKVDEC_VP9_TX_MODE(x)				((x) & 0x07)
-#define RKVDEC_VP9_FRAME_REF_MODE(x)			(((x) & 0x03) << 3)
-
-#define RKVDEC_VP9_REF_SCALE(i)				((i) * 0x04 + 0x074)
-#define RKVDEC_VP9_REF_HOR_SCALE(x)			((x) & 0xffff)
-#define RKVDEC_VP9_REF_VER_SCALE(x)			(((x) & 0xffff) << 16)
-
-#define RKVDEC_VP9_REF_DELTAS_LASTFRAME			0x080
-#define RKVDEC_REF_DELTAS_LASTFRAME(pos, val)		(((val) & 0x7f) << ((pos) * 7))
-
-#define RKVDEC_VP9_INFO_LASTFRAME			0x084
-#define RKVDEC_MODE_DELTAS_LASTFRAME(pos, val)		(((val) & 0x7f) << ((pos) * 7))
-#define RKVDEC_SEG_EN_LASTFRAME				BIT(16)
-#define RKVDEC_LAST_SHOW_FRAME				BIT(17)
-#define RKVDEC_LAST_INTRA_ONLY				BIT(18)
-#define RKVDEC_LAST_WIDHHEIGHT_EQCUR			BIT(19)
-#define RKVDEC_COLOR_SPACE_LASTKEYFRAME(x)		(((x) & 0x07) << 20)
-
-#define RKVDEC_VP9_INTERCMD_BASE			0x088
-
-#define RKVDEC_VP9_INTERCMD_NUM				0x08C
-#define RKVDEC_INTERCMD_NUM(x)				((x) & 0xffffff)
-
-#define RKVDEC_VP9_LASTTILE_SIZE			0x090
-#define RKVDEC_LASTTILE_SIZE(x)				((x) & 0xffffff)
-
-#define RKVDEC_VP9_HOR_VIRSTRIDE(i)			((i) * 0x04 + 0x094)
-#define RKVDEC_HOR_Y_VIRSTRIDE(x)			((x) & 0x1ff)
-#define RKVDEC_HOR_UV_VIRSTRIDE(x)			(((x) & 0x1ff) << 16)
-
-#define RKVDEC_REG_H264_POC_REFER0(i)			(((i) * 0x04) + 0x064)
-#define RKVDEC_REG_H264_POC_REFER1(i)			(((i) * 0x04) + 0x0C4)
-#define RKVDEC_REG_H264_POC_REFER2(i)			(((i) * 0x04) + 0x120)
-#define RKVDEC_POC_REFER(x)				((x) & 0xffffffff)
-
-#define RKVDEC_REG_CUR_POC0				0x0A0
-#define RKVDEC_REG_CUR_POC1				0x128
-#define RKVDEC_CUR_POC(x)				((x) & 0xffffffff)
-
-#define RKVDEC_REG_RLCWRITE_BASE			0x0A4
-#define RKVDEC_REG_PPS_BASE				0x0A8
-#define RKVDEC_REG_RPS_BASE				0x0AC
-
-#define RKVDEC_REG_STRMD_ERR_EN				0x0B0
-#define RKVDEC_STRMD_ERR_EN(x)				((x) & 0xffffffff)
-
-#define RKVDEC_REG_STRMD_ERR_STA			0x0B4
-#define RKVDEC_STRMD_ERR_STA(x)				((x) & 0xfffffff)
-#define RKVDEC_COLMV_ERR_REF_PICIDX(x)			(((x) & 0x0f) << 28)
-
-#define RKVDEC_REG_STRMD_ERR_CTU			0x0B8
-#define RKVDEC_STRMD_ERR_CTU(x)				((x) & 0xff)
-#define RKVDEC_STRMD_ERR_CTU_YOFFSET(x)			(((x) & 0xff) << 8)
-#define RKVDEC_STRMFIFO_SPACE2FULL(x)			(((x) & 0x7f) << 16)
-#define RKVDEC_VP9_ERR_EN_CTU0				BIT(24)
-
-#define RKVDEC_REG_SAO_CTU_POS				0x0BC
-#define RKVDEC_SAOWR_XOFFSET(x)				((x) & 0x1ff)
-#define RKVDEC_SAOWR_YOFFSET(x)				(((x) & 0x3ff) << 16)
-
-#define RKVDEC_VP9_LAST_FRAME_YSTRIDE			0x0C0
-#define RKVDEC_VP9_GOLDEN_FRAME_YSTRIDE			0x0C4
-#define RKVDEC_VP9_ALTREF_FRAME_YSTRIDE			0x0C8
-#define RKVDEC_VP9_REF_YSTRIDE(x)			(((x) & 0xfffff) << 0)
-
-#define RKVDEC_VP9_LAST_FRAME_YUVSTRIDE			0x0CC
-#define RKVDEC_VP9_REF_YUVSTRIDE(x)			(((x) & 0x1fffff) << 0)
-
-#define RKVDEC_VP9_REF_COLMV_BASE			0x0D0
-
-#define RKVDEC_REG_PERFORMANCE_CYCLE			0x100
-#define RKVDEC_PERFORMANCE_CYCLE(x)			((x) & 0xffffffff)
-
-#define RKVDEC_REG_AXI_DDR_RDATA			0x104
-#define RKVDEC_AXI_DDR_RDATA(x)				((x) & 0xffffffff)
-
-#define RKVDEC_REG_AXI_DDR_WDATA			0x108
-#define RKVDEC_AXI_DDR_WDATA(x)				((x) & 0xffffffff)
-
-#define RKVDEC_REG_FPGADEBUG_RESET			0x10C
-#define RKVDEC_BUSIFD_RESETN				BIT(0)
-#define RKVDEC_CABAC_RESETN				BIT(1)
-#define RKVDEC_DEC_CTRL_RESETN				BIT(2)
-#define RKVDEC_TRANSD_RESETN				BIT(3)
-#define RKVDEC_INTRA_RESETN				BIT(4)
-#define RKVDEC_INTER_RESETN				BIT(5)
-#define RKVDEC_RECON_RESETN				BIT(6)
-#define RKVDEC_FILER_RESETN				BIT(7)
-
-#define RKVDEC_REG_PERFORMANCE_SEL			0x110
-#define RKVDEC_PERF_SEL_CNT0(x)				((x) & 0x3f)
-#define RKVDEC_PERF_SEL_CNT1(x)				(((x) & 0x3f) << 8)
-#define RKVDEC_PERF_SEL_CNT2(x)				(((x) & 0x3f) << 16)
-
-#define RKVDEC_REG_PERFORMANCE_CNT(i)			((i) * 0x04 + 0x114)
-#define RKVDEC_PERF_CNT(x)				((x) & 0xffffffff)
-
-#define RKVDEC_REG_H264_ERRINFO_BASE			0x12C
-
-#define RKVDEC_REG_H264_ERRINFO_NUM			0x130
-#define RKVDEC_SLICEDEC_NUM(x)				((x) & 0x3fff)
-#define RKVDEC_STRMD_DECT_ERR_FLAG			BIT(15)
-#define RKVDEC_ERR_PKT_NUM(x)				(((x) & 0x3fff) << 16)
-
-#define RKVDEC_REG_H264_ERR_E				0x134
-#define RKVDEC_H264_ERR_EN_HIGHBITS(x)			((x) & 0x3fffffff)
-
 #define RKVDEC_REG_QOS_CTRL				0x18C
 
+/*
+ * Cache configuration is not covered in the range of the register struct
+ */
 #define RKVDEC_REG_PREF_LUMA_CACHE_COMMAND		0x410
 #define RKVDEC_REG_PREF_CHR_CACHE_COMMAND		0x450
 
+/*
+ * Define the mode values
+ */
+#define RKVDEC_MODE_HEVC				0
+#define RKVDEC_MODE_H264				1
+#define RKVDEC_MODE_VP9					2
+
+/* rkvcodec registers */
+struct rkvdec_common_regs {
+	struct rkvdec_id {
+		u32 minor_ver	: 8;
+		u32 level	: 1;
+		u32 dec_support	: 3;
+		u32 profile	: 1;
+		u32 reserved0	: 1;
+		u32 codec_flag	: 1;
+		u32 reserved1	: 1;
+		u32 prod_num	: 16;
+	} reg00;
+
+	struct rkvdec_int {
+		u32 dec_e			: 1;
+		u32 dec_clkgate_e		: 1;
+		u32 reserved0			: 1;
+		u32 timeout_mode		: 1;
+		u32 dec_irq_dis			: 1;
+		u32 dec_timeout_e		: 1;
+		u32 buf_empty_en		: 1;
+		u32 stmerror_waitdecfifo_empty	: 1;
+		u32 dec_irq			: 1;
+		u32 dec_irq_raw			: 1;
+		u32 reserved2			: 2;
+		u32 dec_rdy_sta			: 1;
+		u32 dec_bus_sta			: 1;
+		u32 dec_error_sta		: 1;
+		u32 dec_timeout_sta		: 1;
+		u32 dec_empty_sta		: 1;
+		u32 colmv_ref_error_sta		: 1;
+		u32 cabu_end_sta		: 1;
+		u32 h264orvp9_error_mode	: 1;
+		u32 softrst_en_p		: 1;
+		u32 force_softreset_valid	: 1;
+		u32 softreset_rdy		: 1;
+		u32 reserved1			: 9;
+	} reg01;
+
+	struct rkvdec_sysctrl {
+		u32 in_endian			: 1;
+		u32 in_swap32_e			: 1;
+		u32 in_swap64_e			: 1;
+		u32 str_endian			: 1;
+		u32 str_swap32_e		: 1;
+		u32 str_swap64_e		: 1;
+		u32 out_endian			: 1;
+		u32 out_swap32_e		: 1;
+		u32 out_cbcr_swap		: 1;
+		u32 reserved0			: 1;
+		u32 rlc_mode_direct_write	: 1;
+		u32 rlc_mode			: 1;
+		u32 strm_start_bit		: 7;
+		u32 reserved1			: 1;
+		u32 dec_mode			: 2;
+		u32 reserved2			: 2;
+		u32 rps_mode			: 1;
+		u32 stream_mode			: 1;
+		u32 stream_lastpacket		: 1;
+		u32 firstslice_flag		: 1;
+		u32 frame_orslice		: 1;
+		u32 buspr_slot_disable		: 1;
+		u32 reserved3			: 2;
+	} reg02;
+
+	struct rkvdec_picpar {
+		u32 y_hor_virstride	: 9;
+		u32 reserved		: 2;
+		u32 slice_num_highbit	: 1;
+		u32 uv_hor_virstride	: 9;
+		u32 slice_num_lowbits	: 11;
+	} reg03;
+
+	u32 strm_rlc_base;
+	u32 stream_len;
+	u32 cabactbl_base;
+	u32 decout_base;
+
+	struct rkvdec_y_virstride {
+		u32 y_virstride	: 20;
+		u32 reserved0	: 12;
+	} reg08;
+
+	struct rkvdec_yuv_virstride {
+		u32 yuv_virstride	: 21;
+		u32 reserved0		: 11;
+	} reg09;
+} __packed;
+
+struct ref_base {
+	u32 field_ref		: 1;
+	u32 topfield_used_ref	: 1;
+	u32 botfield_used_ref	: 1;
+	u32 colmv_used_flag_ref	: 1;
+	u32 base_addr		: 28;
+};
+
+struct rkvdec_h26x_regs {
+	struct ref_base ref0_14_base[15];
+	u32 ref0_14_poc[15];
+
+	u32 cur_poc;
+	u32 rlcwrite_base;
+	u32 pps_base;
+	u32 rps_base;
+
+	u32 strmd_error_e;
+
+	struct {
+		u32 strmd_error_status		: 28;
+		u32 colmv_error_ref_picidx	: 4;
+	} reg45;
+
+	struct {
+		u32 strmd_error_ctu_xoffset	: 8;
+		u32 strmd_error_ctu_yoffset	: 8;
+		u32 streamfifo_space2full	: 7;
+		u32 reserved0			: 1;
+		u32 vp9_error_ctu0_en		: 1;
+		u32 reserved1			: 7;
+	} reg46;
+
+	struct {
+		u32 saowr_xoffet	: 9;
+		u32 reserved0		: 7;
+		u32 saowr_yoffset	: 10;
+		u32 reserved1		: 6;
+	} reg47;
+
+	struct ref_base ref15_base;
+
+	u32 ref15_29_poc[15];
+
+	u32 performance_cycle;
+	u32 axi_ddr_rdata;
+	u32 axi_ddr_wdata;
+
+	struct {
+		u32 busifd_resetn	: 1;
+		u32 cabac_resetn	: 1;
+		u32 dec_ctrl_resetn	: 1;
+		u32 transd_resetn	: 1;
+		u32 intra_resetn	: 1;
+		u32 inter_resetn	: 1;
+		u32 recon_resetn	: 1;
+		u32 filer_resetn	: 1;
+		u32 reserved0		: 24;
+	} reg67;
+
+	struct {
+		u32 perf_cnt0_sel	: 6;
+		u32 reserved0		: 2;
+		u32 perf_cnt1_sel	: 6;
+		u32 reserved1		: 2;
+		u32 perf_cnt2_sel	: 6;
+		u32 reserved2		: 10;
+	} reg68;
+
+	u32 perf_cnt0;
+	u32 perf_cnt1;
+	u32 perf_cnt2;
+	u32 ref30_poc;
+	u32 ref31_poc;
+	u32 cur_poc1;
+	u32 errorinfo_base;
+
+	struct {
+		u32 slicedec_num		: 14;
+		u32 reserved0			: 1;
+		u32 strmd_detect_error_flag	: 1;
+		u32 error_packet_num		: 14;
+		u32 reserved1			: 2;
+	} reg76;
+
+	struct {
+		u32 error_en_highbits	: 30;
+		u32 reserved		: 2;
+	} reg77;
+} __packed;
+
+struct rkvdec_vp9_regs {
+	struct cprheader_offset {
+		u32 cprheader_offset	: 16;
+		u32 reserved		: 16;
+	} reg10;
+
+	u32 refer_bases[3];
+	u32 count_base;
+	u32 segidlast_base;
+	u32 segidcur_base;
+
+	struct frame_sizes {
+		u32 framewidth		: 16;
+		u32 frameheight		: 16;
+	} reg17_19[3];
+
+	struct segid_grp {
+		u32 segid_abs_delta			: 1;
+		u32 segid_frame_qp_delta_en		: 1;
+		u32 segid_frame_qp_delta		: 9;
+		u32 segid_frame_loopfilter_value_en	: 1;
+		u32 segid_frame_loopfilter_value	: 7;
+		u32 segid_referinfo_en			: 1;
+		u32 segid_referinfo			: 2;
+		u32 segid_frame_skip_en			: 1;
+		u32 reserved				: 9;
+	} reg20_27[8];
+
+	struct cprheader_config {
+		u32 tx_mode			: 3;
+		u32 frame_reference_mode	: 2;
+		u32 reserved			: 27;
+	} reg28;
+
+	struct ref_scale {
+		u32 ref_hor_scale		: 16;
+		u32 ref_ver_scale		: 16;
+	} reg29_31[3];
+
+	struct ref_deltas_lastframe {
+		u32 ref_deltas_lastframe0	: 7;
+		u32 ref_deltas_lastframe1	: 7;
+		u32 ref_deltas_lastframe2	: 7;
+		u32 ref_deltas_lastframe3	: 7;
+		u32 reserved			: 4;
+	} reg32;
+
+	struct info_lastframe {
+		u32 mode_deltas_lastframe0		: 7;
+		u32 mode_deltas_lastframe1		: 7;
+		u32 reserved0				: 2;
+		u32 segmentation_enable_lstframe	: 1;
+		u32 last_show_frame			: 1;
+		u32 last_intra_only			: 1;
+		u32 last_widthheight_eqcur		: 1;
+		u32 color_space_lastkeyframe		: 3;
+		u32 reserved1				: 9;
+	} reg33;
+
+	u32 intercmd_base;
+
+	struct intercmd_num {
+		u32 intercmd_num	: 24;
+		u32 reserved		: 8;
+	} reg35;
+
+	struct lasttile_size {
+		u32 lasttile_size	: 24;
+		u32 reserved		: 8;
+	} reg36;
+
+	struct hor_virstride {
+		u32 y_hor_virstride	: 9;
+		u32 reserved0		: 7;
+		u32 uv_hor_virstride	: 9;
+		u32 reserved1		: 7;
+	} reg37_39[3];
+
+	u32 cur_poc;
+
+	struct rlcwrite_base {
+		u32 reserved		: 3;
+		u32 rlcwrite_base	: 29;
+	} reg41;
+
+	struct pps_base {
+		u32 reserved	: 4;
+		u32 pps_base	: 28;
+	} reg42;
+
+	struct rps_base {
+		u32 reserved	: 4;
+		u32 rps_base	: 28;
+	} reg43;
+
+	struct strmd_error_en {
+		u32 strmd_error_e	: 28;
+		u32 reserved		: 4;
+	} reg44;
+
+	u32 vp9_error_info0;
+
+	struct strmd_error_ctu {
+		u32 strmd_error_ctu_xoffset	: 8;
+		u32 strmd_error_ctu_yoffset	: 8;
+		u32 streamfifo_space2full	: 7;
+		u32 reserved0			: 1;
+		u32 error_ctu0_en		: 1;
+		u32 reserved1			: 7;
+	} reg46;
+
+	struct sao_ctu_position {
+		u32 saowr_xoffet	: 9;
+		u32 reserved0		: 7;
+		u32 saowr_yoffset	: 10;
+		u32 reserved1		: 6;
+	} reg47;
+
+	struct ystride {
+		u32 virstride	: 20;
+		u32 reserved	: 12;
+	} reg48_50[3];
+
+	struct lastref_yuvstride {
+		u32 lastref_yuv_virstride	: 21;
+		u32 reserved			: 11;
+	} reg51;
+
+	u32 refcolmv_base;
+
+	u32 reserved0[11];
+
+	u32 performance_cycle;
+	u32 axi_ddr_rdata;
+	u32 axi_ddr_wdata;
+
+	struct fpgadebug_reset {
+		u32 busifd_resetn	: 1;
+		u32 cabac_resetn	: 1;
+		u32 dec_ctrl_resetn	: 1;
+		u32 transd_resetn	: 1;
+		u32 intra_resetn	: 1;
+		u32 inter_resetn	: 1;
+		u32 recon_resetn	: 1;
+		u32 filer_resetn	: 1;
+		u32 reserved		: 24;
+	} reg67;
+
+	struct performance_sel {
+		u32 perf_cnt0_sel	: 6;
+		u32 reserved0		: 2;
+		u32 perf_cnt1_sel	: 6;
+		u32 reserved1		: 2;
+		u32 perf_cnt2_sel	: 6;
+		u32 reserved		: 10;
+	} reg68;
+
+	u32 perf_cnt0;
+	u32 perf_cnt1;
+	u32 perf_cnt2;
+
+	u32 reserved1[3];
+
+	u32 vp9_error_info1;
+
+	struct error_ctu1 {
+		u32 vp9_error_ctu1_x	: 6;
+		u32 reserved0		: 2;
+		u32 vp9_error_ctu1_y	: 6;
+		u32 reserved1		: 1;
+		u32 vp9_error_ctu1_en	: 1;
+		u32 reserved2		: 16;
+	} reg76;
+
+	u32 reserved2;
+} __packed;
+
+struct rkvdec_regs {
+	struct rkvdec_common_regs common;
+	union {
+		struct rkvdec_h26x_regs h26x;
+		struct rkvdec_vp9_regs  vp9;
+	};
+} __packed;
+
 #endif /* RKVDEC_REGS_H_ */
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
index b4bf01e839ef..0cf5a559701c 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
@@ -163,6 +163,7 @@ struct rkvdec_vp9_ctx {
 	struct v4l2_vp9_frame_context frame_context[4];
 	struct rkvdec_vp9_frame_info cur;
 	struct rkvdec_vp9_frame_info last;
+	struct rkvdec_regs regs;
 };
 
 static void write_coeff_plane(const u8 coef[6][6][3], u8 *coeff_plane)
@@ -347,38 +348,6 @@ static void init_probs(struct rkvdec_ctx *ctx,
 		init_inter_probs(ctx, run);
 }
 
-struct rkvdec_vp9_ref_reg {
-	u32 reg_frm_size;
-	u32 reg_hor_stride;
-	u32 reg_y_stride;
-	u32 reg_yuv_stride;
-	u32 reg_ref_base;
-};
-
-static struct rkvdec_vp9_ref_reg ref_regs[] = {
-	{
-		.reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(0),
-		.reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(0),
-		.reg_y_stride = RKVDEC_VP9_LAST_FRAME_YSTRIDE,
-		.reg_yuv_stride = RKVDEC_VP9_LAST_FRAME_YUVSTRIDE,
-		.reg_ref_base = RKVDEC_REG_VP9_LAST_FRAME_BASE,
-	},
-	{
-		.reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(1),
-		.reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(1),
-		.reg_y_stride = RKVDEC_VP9_GOLDEN_FRAME_YSTRIDE,
-		.reg_yuv_stride = 0,
-		.reg_ref_base = RKVDEC_REG_VP9_GOLDEN_FRAME_BASE,
-	},
-	{
-		.reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(2),
-		.reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(2),
-		.reg_y_stride = RKVDEC_VP9_ALTREF_FRAME_YSTRIDE,
-		.reg_yuv_stride = 0,
-		.reg_ref_base = RKVDEC_REG_VP9_ALTREF_FRAME_BASE,
-	}
-};
-
 static struct rkvdec_decoded_buffer *
 get_ref_buf(struct rkvdec_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp)
 {
@@ -412,18 +381,17 @@ static dma_addr_t get_mv_base_addr(struct rkvdec_decoded_buffer *buf)
 static void config_ref_registers(struct rkvdec_ctx *ctx,
 				 const struct rkvdec_vp9_run *run,
 				 struct rkvdec_decoded_buffer *ref_buf,
-				 struct rkvdec_vp9_ref_reg *ref_reg)
+				 int i)
 {
 	unsigned int aligned_pitch, aligned_height, y_len, yuv_len;
-	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
+	struct rkvdec_regs *regs = &vp9_ctx->regs;
 
 	aligned_height = round_up(ref_buf->vp9.height, 64);
-	writel_relaxed(RKVDEC_VP9_FRAMEWIDTH(ref_buf->vp9.width) |
-		       RKVDEC_VP9_FRAMEHEIGHT(ref_buf->vp9.height),
-		       rkvdec->regs + ref_reg->reg_frm_size);
+	regs->vp9.reg17_19[i].frameheight = ref_buf->vp9.height;
+	regs->vp9.reg17_19[i].framewidth = ref_buf->vp9.width;
 
-	writel_relaxed(vb2_dma_contig_plane_dma_addr(&ref_buf->base.vb.vb2_buf, 0),
-		       rkvdec->regs + ref_reg->reg_ref_base);
+	regs->vp9.refer_bases[i] = vb2_dma_contig_plane_dma_addr(&ref_buf->base.vb.vb2_buf, 0);
 
 	if (&ref_buf->base.vb == run->base.bufs.dst)
 		return;
@@ -432,59 +400,50 @@ static void config_ref_registers(struct rkvdec_ctx *ctx,
 	y_len = aligned_height * aligned_pitch;
 	yuv_len = (y_len * 3) / 2;
 
-	writel_relaxed(RKVDEC_HOR_Y_VIRSTRIDE(aligned_pitch / 16) |
-		       RKVDEC_HOR_UV_VIRSTRIDE(aligned_pitch / 16),
-		       rkvdec->regs + ref_reg->reg_hor_stride);
-	writel_relaxed(RKVDEC_VP9_REF_YSTRIDE(y_len / 16),
-		       rkvdec->regs + ref_reg->reg_y_stride);
-
-	if (!ref_reg->reg_yuv_stride)
-		return;
+	regs->vp9.reg37_39[i].y_hor_virstride = aligned_pitch / 16;
+	regs->vp9.reg37_39[i].uv_hor_virstride = aligned_pitch / 16;
+	regs->vp9.reg48_50[i].virstride = y_len / 16;
 
-	writel_relaxed(RKVDEC_VP9_REF_YUVSTRIDE(yuv_len / 16),
-		       rkvdec->regs + ref_reg->reg_yuv_stride);
+	if (!i)
+		regs->vp9.reg51.lastref_yuv_virstride = yuv_len / 16;
 }
 
 static void config_seg_registers(struct rkvdec_ctx *ctx, unsigned int segid)
 {
 	struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
+	struct rkvdec_regs *regs = &vp9_ctx->regs;
 	const struct v4l2_vp9_segmentation *seg;
-	struct rkvdec_dev *rkvdec = ctx->dev;
 	s16 feature_val;
 	int feature_id;
-	u32 val = 0;
 
 	seg = vp9_ctx->last.valid ? &vp9_ctx->last.seg : &vp9_ctx->cur.seg;
 	feature_id = V4L2_VP9_SEG_LVL_ALT_Q;
 	if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid)) {
 		feature_val = seg->feature_data[segid][feature_id];
-		val |= RKVDEC_SEGID_FRAME_QP_DELTA_EN(1) |
-		       RKVDEC_SEGID_FRAME_QP_DELTA(feature_val);
+		regs->vp9.reg20_27[segid].segid_frame_qp_delta_en = 1;
+		regs->vp9.reg20_27[segid].segid_frame_qp_delta = feature_val;
 	}
 
 	feature_id = V4L2_VP9_SEG_LVL_ALT_L;
 	if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid)) {
 		feature_val = seg->feature_data[segid][feature_id];
-		val |= RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE_EN(1) |
-		       RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE(feature_val);
+		regs->vp9.reg20_27[segid].segid_frame_loopfilter_value_en = 1;
+		regs->vp9.reg20_27[segid].segid_frame_loopfilter_value = feature_val;
 	}
 
 	feature_id = V4L2_VP9_SEG_LVL_REF_FRAME;
 	if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid)) {
 		feature_val = seg->feature_data[segid][feature_id];
-		val |= RKVDEC_SEGID_REFERINFO_EN(1) |
-		       RKVDEC_SEGID_REFERINFO(feature_val);
+		regs->vp9.reg20_27[segid].segid_referinfo_en = 1;
+		regs->vp9.reg20_27[segid].segid_referinfo = feature_val;
 	}
 
 	feature_id = V4L2_VP9_SEG_LVL_SKIP;
-	if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid))
-		val |= RKVDEC_SEGID_FRAME_SKIP_EN(1);
-
-	if (!segid &&
-	    (seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE))
-		val |= RKVDEC_SEGID_ABS_DELTA(1);
+	regs->vp9.reg20_27[segid].segid_frame_skip_en =
+		v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid);
 
-	writel_relaxed(val, rkvdec->regs + RKVDEC_VP9_SEGID_GRP(segid));
+	regs->vp9.reg20_27[segid].segid_abs_delta = !segid &&
+		(seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE);
 }
 
 static void update_dec_buf_info(struct rkvdec_decoded_buffer *buf,
@@ -521,7 +480,8 @@ static void config_registers(struct rkvdec_ctx *ctx,
 	struct rkvdec_decoded_buffer *ref_bufs[3];
 	struct rkvdec_decoded_buffer *dst, *last, *mv_ref;
 	struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
-	u32 val, last_frame_info = 0;
+	struct rkvdec_regs *regs = &vp9_ctx->regs;
+	u32 val;
 	const struct v4l2_vp9_segmentation *seg;
 	struct rkvdec_dev *rkvdec = ctx->dev;
 	dma_addr_t addr;
@@ -547,8 +507,7 @@ static void config_registers(struct rkvdec_ctx *ctx,
 			(V4L2_VP9_FRAME_FLAG_KEY_FRAME |
 			 V4L2_VP9_FRAME_FLAG_INTRA_ONLY));
 
-	writel_relaxed(RKVDEC_MODE(RKVDEC_MODE_VP9),
-		       rkvdec->regs + RKVDEC_REG_SYSCTRL);
+	regs->common.reg02.dec_mode = RKVDEC_MODE_VP9;
 
 	bit_depth = dec_params->bit_depth;
 	aligned_height = round_up(ctx->decoded_fmt.fmt.pix_mp.height, 64);
@@ -560,17 +519,14 @@ static void config_registers(struct rkvdec_ctx *ctx,
 	uv_len = y_len / 2;
 	yuv_len = y_len + uv_len;
 
-	writel_relaxed(RKVDEC_Y_HOR_VIRSTRIDE(aligned_pitch / 16) |
-		       RKVDEC_UV_HOR_VIRSTRIDE(aligned_pitch / 16),
-		       rkvdec->regs + RKVDEC_REG_PICPAR);
-	writel_relaxed(RKVDEC_Y_VIRSTRIDE(y_len / 16),
-		       rkvdec->regs + RKVDEC_REG_Y_VIRSTRIDE);
-	writel_relaxed(RKVDEC_YUV_VIRSTRIDE(yuv_len / 16),
-		       rkvdec->regs + RKVDEC_REG_YUV_VIRSTRIDE);
+	regs->common.reg03.y_hor_virstride = aligned_pitch / 16;
+	regs->common.reg03.uv_hor_virstride = aligned_pitch / 16;
+	regs->common.reg08.y_virstride = y_len / 16;
+	regs->common.reg09.yuv_virstride = yuv_len / 16;
 
 	stream_len = vb2_get_plane_payload(&run->base.bufs.src->vb2_buf, 0);
-	writel_relaxed(RKVDEC_STRM_LEN(stream_len),
-		       rkvdec->regs + RKVDEC_REG_STRM_LEN);
+
+	regs->common.stream_len = stream_len;
 
 	/*
 	 * Reset count buffer, because decoder only output intra related syntax
@@ -588,14 +544,13 @@ static void config_registers(struct rkvdec_ctx *ctx,
 		vp9_ctx->cur.segmapid++;
 
 	for (i = 0; i < ARRAY_SIZE(ref_bufs); i++)
-		config_ref_registers(ctx, run, ref_bufs[i], &ref_regs[i]);
+		config_ref_registers(ctx, run, ref_bufs[i], i);
 
 	for (i = 0; i < 8; i++)
 		config_seg_registers(ctx, i);
 
-	writel_relaxed(RKVDEC_VP9_TX_MODE(vp9_ctx->cur.tx_mode) |
-		       RKVDEC_VP9_FRAME_REF_MODE(dec_params->reference_mode),
-		       rkvdec->regs + RKVDEC_VP9_CPRHEADER_CONFIG);
+	regs->vp9.reg28.tx_mode = vp9_ctx->cur.tx_mode;
+	regs->vp9.reg28.frame_reference_mode = dec_params->reference_mode;
 
 	if (!intra_only) {
 		const struct v4l2_vp9_loop_filter *lf;
@@ -609,43 +564,56 @@ static void config_registers(struct rkvdec_ctx *ctx,
 		val = 0;
 		for (i = 0; i < ARRAY_SIZE(lf->ref_deltas); i++) {
 			delta = lf->ref_deltas[i];
-			val |= RKVDEC_REF_DELTAS_LASTFRAME(i, delta);
+			switch (i) {
+			case 0:
+				regs->vp9.reg32.ref_deltas_lastframe0 = delta;
+				break;
+			case 1:
+				regs->vp9.reg32.ref_deltas_lastframe1 = delta;
+				break;
+			case 2:
+				regs->vp9.reg32.ref_deltas_lastframe2 = delta;
+				break;
+			case 3:
+				regs->vp9.reg32.ref_deltas_lastframe3 = delta;
+				break;
+			}
 		}
 
-		writel_relaxed(val,
-			       rkvdec->regs + RKVDEC_VP9_REF_DELTAS_LASTFRAME);
-
 		for (i = 0; i < ARRAY_SIZE(lf->mode_deltas); i++) {
 			delta = lf->mode_deltas[i];
-			last_frame_info |= RKVDEC_MODE_DELTAS_LASTFRAME(i,
-									delta);
+			switch (i) {
+			case 0:
+				regs->vp9.reg33.mode_deltas_lastframe0 = delta;
+				break;
+			case 1:
+				regs->vp9.reg33.mode_deltas_lastframe1 = delta;
+				break;
+			}
 		}
 	}
 
-	if (vp9_ctx->last.valid && !intra_only &&
-	    vp9_ctx->last.seg.flags & V4L2_VP9_SEGMENTATION_FLAG_ENABLED)
-		last_frame_info |= RKVDEC_SEG_EN_LASTFRAME;
+	regs->vp9.reg33.segmentation_enable_lstframe =
+		vp9_ctx->last.valid && !intra_only &&
+		vp9_ctx->last.seg.flags & V4L2_VP9_SEGMENTATION_FLAG_ENABLED;
 
-	if (vp9_ctx->last.valid &&
-	    vp9_ctx->last.flags & V4L2_VP9_FRAME_FLAG_SHOW_FRAME)
-		last_frame_info |= RKVDEC_LAST_SHOW_FRAME;
+	regs->vp9.reg33.last_show_frame =
+		vp9_ctx->last.valid &&
+		vp9_ctx->last.flags & V4L2_VP9_FRAME_FLAG_SHOW_FRAME;
 
-	if (vp9_ctx->last.valid &&
-	    vp9_ctx->last.flags &
-	    (V4L2_VP9_FRAME_FLAG_KEY_FRAME | V4L2_VP9_FRAME_FLAG_INTRA_ONLY))
-		last_frame_info |= RKVDEC_LAST_INTRA_ONLY;
+	regs->vp9.reg33.last_intra_only =
+		vp9_ctx->last.valid &&
+		vp9_ctx->last.flags &
+		(V4L2_VP9_FRAME_FLAG_KEY_FRAME | V4L2_VP9_FRAME_FLAG_INTRA_ONLY);
 
-	if (vp9_ctx->last.valid &&
-	    last->vp9.width == dst->vp9.width &&
-	    last->vp9.height == dst->vp9.height)
-		last_frame_info |= RKVDEC_LAST_WIDHHEIGHT_EQCUR;
+	regs->vp9.reg33.last_widthheight_eqcur =
+		vp9_ctx->last.valid &&
+		last->vp9.width == dst->vp9.width &&
+		last->vp9.height == dst->vp9.height;
 
-	writel_relaxed(last_frame_info,
-		       rkvdec->regs + RKVDEC_VP9_INFO_LASTFRAME);
-
-	writel_relaxed(stream_len - dec_params->compressed_header_size -
-		       dec_params->uncompressed_header_size,
-		       rkvdec->regs + RKVDEC_VP9_LASTTILE_SIZE);
+	regs->vp9.reg36.lasttile_size =
+		stream_len - dec_params->compressed_header_size -
+		dec_params->uncompressed_header_size;
 
 	for (i = 0; !intra_only && i < ARRAY_SIZE(ref_bufs); i++) {
 		unsigned int refw = ref_bufs[i]->vp9.width;
@@ -654,29 +622,28 @@ static void config_registers(struct rkvdec_ctx *ctx,
 
 		hscale = (refw << 14) /	dst->vp9.width;
 		vscale = (refh << 14) / dst->vp9.height;
-		writel_relaxed(RKVDEC_VP9_REF_HOR_SCALE(hscale) |
-			       RKVDEC_VP9_REF_VER_SCALE(vscale),
-			       rkvdec->regs + RKVDEC_VP9_REF_SCALE(i));
+
+		regs->vp9.reg29_31[i].ref_hor_scale = hscale;
+		regs->vp9.reg29_31[i].ref_ver_scale = vscale;
 	}
 
 	addr = vb2_dma_contig_plane_dma_addr(&dst->base.vb.vb2_buf, 0);
-	writel_relaxed(addr, rkvdec->regs + RKVDEC_REG_DECOUT_BASE);
+	regs->common.decout_base = addr;
 	addr = vb2_dma_contig_plane_dma_addr(&run->base.bufs.src->vb2_buf, 0);
-	writel_relaxed(addr, rkvdec->regs + RKVDEC_REG_STRM_RLC_BASE);
-	writel_relaxed(vp9_ctx->priv_tbl.dma +
-		       offsetof(struct rkvdec_vp9_priv_tbl, probs),
-		       rkvdec->regs + RKVDEC_REG_CABACTBL_PROB_BASE);
-	writel_relaxed(vp9_ctx->count_tbl.dma,
-		       rkvdec->regs + RKVDEC_REG_VP9COUNT_BASE);
-
-	writel_relaxed(vp9_ctx->priv_tbl.dma +
-		       offsetof(struct rkvdec_vp9_priv_tbl, segmap) +
-		       (RKVDEC_VP9_MAX_SEGMAP_SIZE * vp9_ctx->cur.segmapid),
-		       rkvdec->regs + RKVDEC_REG_VP9_SEGIDCUR_BASE);
-	writel_relaxed(vp9_ctx->priv_tbl.dma +
-		       offsetof(struct rkvdec_vp9_priv_tbl, segmap) +
-		       (RKVDEC_VP9_MAX_SEGMAP_SIZE * (!vp9_ctx->cur.segmapid)),
-		       rkvdec->regs + RKVDEC_REG_VP9_SEGIDLAST_BASE);
+	regs->common.strm_rlc_base = addr;
+
+	regs->common.cabactbl_base = vp9_ctx->priv_tbl.dma +
+		offsetof(struct rkvdec_vp9_priv_tbl, probs);
+
+	regs->vp9.count_base = vp9_ctx->count_tbl.dma;
+
+	regs->vp9.segidlast_base = vp9_ctx->priv_tbl.dma +
+		offsetof(struct rkvdec_vp9_priv_tbl, segmap) +
+		(RKVDEC_VP9_MAX_SEGMAP_SIZE * (!vp9_ctx->cur.segmapid));
+
+	regs->vp9.segidcur_base = vp9_ctx->priv_tbl.dma +
+		offsetof(struct rkvdec_vp9_priv_tbl, segmap) +
+		(RKVDEC_VP9_MAX_SEGMAP_SIZE * vp9_ctx->cur.segmapid);
 
 	if (!intra_only &&
 	    !(dec_params->flags & V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT) &&
@@ -685,12 +652,14 @@ static void config_registers(struct rkvdec_ctx *ctx,
 	else
 		mv_ref = dst;
 
-	writel_relaxed(get_mv_base_addr(mv_ref),
-		       rkvdec->regs + RKVDEC_VP9_REF_COLMV_BASE);
+	regs->vp9.refcolmv_base = get_mv_base_addr(mv_ref);
 
-	writel_relaxed(ctx->decoded_fmt.fmt.pix_mp.width |
-		       (ctx->decoded_fmt.fmt.pix_mp.height << 16),
-		       rkvdec->regs + RKVDEC_REG_PERFORMANCE_CYCLE);
+	regs->vp9.performance_cycle = ctx->decoded_fmt.fmt.pix_mp.width |
+		       (ctx->decoded_fmt.fmt.pix_mp.height << 16);
+
+	regs->vp9.reg44.strmd_error_e = 0xe;
+
+	rkvdec_memcpy_toio(rkvdec->regs, regs, MIN(sizeof(*regs), rkvdec->variant->num_regs));
 }
 
 static int validate_dec_params(struct rkvdec_ctx *ctx,
@@ -823,8 +792,6 @@ static int rkvdec_vp9_run(struct rkvdec_ctx *ctx)
 	writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND);
 	writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);
 
-	writel(0xe, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN);
-
 	if (rkvdec->variant->quirks & RKVDEC_QUIRK_DISABLE_QOS)
 		rkvdec_quirks_disable_qos(ctx);
 
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index 5af9aa5ab353..776149f871b0 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -914,6 +914,15 @@ void rkvdec_quirks_disable_qos(struct rkvdec_ctx *ctx)
 	writel(reg, rkvdec->regs + RKVDEC_REG_QOS_CTRL);
 }
 
+void rkvdec_memcpy_toio(void __iomem *dst, void *src, size_t len)
+{
+#ifdef CONFIG_ARM64
+	__iowrite32_copy(dst, src, len / 4);
+#else
+	memcpy_toio(dst, src, len);
+#endif
+}
+
 static void rkvdec_device_run(void *priv)
 {
 	struct rkvdec_ctx *ctx = priv;
@@ -1227,7 +1236,6 @@ static void rkvdec_watchdog_func(struct work_struct *work)
 	if (ctx) {
 		dev_err(rkvdec->dev, "Frame processing timed out!\n");
 		writel(RKVDEC_IRQ_DIS, rkvdec->regs + RKVDEC_REG_INTERRUPT);
-		writel(0, rkvdec->regs + RKVDEC_REG_SYSCTRL);
 		rkvdec_job_finish(ctx, VB2_BUF_STATE_ERROR);
 	}
 }
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
index 566e06fa2b1e..f35f6e80ea2e 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
@@ -151,6 +151,7 @@ struct rkvdec_aux_buf {
 
 void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run);
 void rkvdec_run_postamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run);
+void rkvdec_memcpy_toio(void __iomem *dst, void *src, size_t len);
 
 void rkvdec_quirks_disable_qos(struct rkvdec_ctx *ctx);
 
-- 
2.52.0



From detlev.casanova at collabora.com  Wed Dec 17 09:40:42 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 17 Dec 2025 12:40:42 -0500
Subject: [PATCH v6 05/17] media: rkvdec: Move cabac tables to their own source file
In-Reply-To: <20251217174059.1341784-1-detlev.casanova@collabora.com>
References: <20251217174059.1341784-1-detlev.casanova@collabora.com>
Message-ID: <20251217174059.1341784-6-detlev.casanova@collabora.com>

This is in preparation to add support for new variants that will use the
same tables.

Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../media/platform/rockchip/rkvdec/Makefile   |   7 +-
 .../{rkvdec-hevc-data.c => rkvdec-cabac.c}    | 506 +++++++++++++++++-
 .../platform/rockchip/rkvdec/rkvdec-h264.c    | 501 +----------------
 .../platform/rockchip/rkvdec/rkvdec-hevc.c    |   6 +-
 4 files changed, 514 insertions(+), 506 deletions(-)
 rename drivers/media/platform/rockchip/rkvdec/{rkvdec-hevc-data.c => rkvdec-cabac.c} (86%)

diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
index a77122641d14..a8ff5e3d7bec 100644
--- a/drivers/media/platform/rockchip/rkvdec/Makefile
+++ b/drivers/media/platform/rockchip/rkvdec/Makefile
@@ -1,3 +1,8 @@
 obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC) += rockchip-vdec.o
 
-rockchip-vdec-y += rkvdec.o rkvdec-h264.o rkvdec-hevc.o rkvdec-vp9.o
+rockchip-vdec-y += \
+		   rkvdec.o \
+		   rkvdec-cabac.o \
+		   rkvdec-h264.o \
+		   rkvdec-hevc.o \
+		   rkvdec-vp9.o
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-data.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-cabac.c
similarity index 86%
rename from drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-data.c
rename to drivers/media/platform/rockchip/rkvdec/rkvdec-cabac.c
index eac4ea604949..bc87f59636ea 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-data.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-cabac.c
@@ -1,19 +1,517 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Rockchip Video Decoder driver
+ * Rockchip Video Decoder CABAC tables
  *
  * Copyright (C) 2023 Collabora, Ltd.
  *	Sebastian Fricke <sebastian.fricke at collabora.com>
+ * Copyright (C) 2019 Collabora, Ltd.
+ *	Boris Brezillon <boris.brezillon at collabora.com>
  */
 
 #include <linux/types.h>
 
-#define RKV_CABAC_TABLE_SIZE		27456
+#define CABAC_ENTRY(ctxidx, idc0_m, idc0_n, idc1_m, idc1_n,		\
+	    idc2_m, idc2_n, intra_m, intra_n)			\
+	[0][(ctxidx)] = {idc0_m, idc0_n},			\
+	[1][(ctxidx)] = {idc1_m, idc1_n},			\
+	[2][(ctxidx)] = {idc2_m, idc2_n},			\
+	[3][(ctxidx)] = {intra_m, intra_n}
 
 /*
- * This file is #include from rkvdec-hevc.c and not compiled.
+ * Constant CABAC table.
+ * Built from the tables described in section '9.3.1.1 Initialisation process
+ * for context variables' of the H264 spec.
  */
-static const u8 rkvdec_hevc_cabac_table[RKV_CABAC_TABLE_SIZE] = {
+const s8 rkvdec_h264_cabac_table[4][464][2] = {
+	/* Table 9-12 ? Values of variables m and n for ctxIdx from 0 to 10 */
+	CABAC_ENTRY(0, 20, -15, 20, -15, 20, -15, 20, -15),
+	CABAC_ENTRY(1, 2, 54, 2, 54, 2, 54, 2, 54),
+	CABAC_ENTRY(2, 3, 74, 3, 74, 3, 74, 3, 74),
+	CABAC_ENTRY(3, 20, -15, 20, -15, 20, -15, 20, -15),
+	CABAC_ENTRY(4, 2, 54, 2, 54, 2, 54, 2, 54),
+	CABAC_ENTRY(5, 3, 74, 3, 74, 3, 74, 3, 74),
+	CABAC_ENTRY(6, -28, 127, -28, 127, -28, 127, -28, 127),
+	CABAC_ENTRY(7, -23, 104, -23, 104, -23, 104, -23, 104),
+	CABAC_ENTRY(8, -6, 53, -6, 53, -6, 53, -6, 53),
+	CABAC_ENTRY(9, -1, 54, -1, 54, -1, 54, -1, 54),
+	CABAC_ENTRY(10, 7, 51, 7, 51, 7, 51, 7, 51),
+
+	/* Table 9-13 ? Values of variables m and n for ctxIdx from 11 to 23 */
+	CABAC_ENTRY(11, 23, 33, 22, 25, 29, 16, 0, 0),
+	CABAC_ENTRY(12, 23, 2, 34, 0, 25, 0, 0, 0),
+	CABAC_ENTRY(13, 21, 0, 16, 0, 14, 0, 0, 0),
+	CABAC_ENTRY(14, 1, 9, -2, 9, -10, 51, 0, 0),
+	CABAC_ENTRY(15, 0, 49, 4, 41, -3, 62, 0, 0),
+	CABAC_ENTRY(16, -37, 118, -29, 118, -27, 99, 0, 0),
+	CABAC_ENTRY(17, 5, 57, 2, 65, 26, 16, 0, 0),
+	CABAC_ENTRY(18, -13, 78, -6, 71, -4, 85, 0, 0),
+	CABAC_ENTRY(19, -11, 65, -13, 79, -24, 102, 0, 0),
+	CABAC_ENTRY(20, 1, 62, 5, 52, 5, 57, 0, 0),
+	CABAC_ENTRY(21, 12, 49, 9, 50, 6, 57, 0, 0),
+	CABAC_ENTRY(22, -4, 73, -3, 70, -17, 73, 0, 0),
+	CABAC_ENTRY(23, 17, 50, 10, 54, 14, 57, 0, 0),
+
+	/* Table 9-14 ? Values of variables m and n for ctxIdx from 24 to 39 */
+	CABAC_ENTRY(24, 18, 64, 26, 34, 20, 40, 0, 0),
+	CABAC_ENTRY(25, 9, 43, 19, 22, 20, 10, 0, 0),
+	CABAC_ENTRY(26, 29, 0, 40, 0, 29, 0, 0, 0),
+	CABAC_ENTRY(27, 26, 67, 57, 2, 54, 0, 0, 0),
+	CABAC_ENTRY(28, 16, 90, 41, 36, 37, 42, 0, 0),
+	CABAC_ENTRY(29, 9, 104, 26, 69, 12, 97, 0, 0),
+	CABAC_ENTRY(30, -46, 127, -45, 127, -32, 127, 0, 0),
+	CABAC_ENTRY(31, -20, 104, -15, 101, -22, 117, 0, 0),
+	CABAC_ENTRY(32, 1, 67, -4, 76, -2, 74, 0, 0),
+	CABAC_ENTRY(33, -13, 78, -6, 71, -4, 85, 0, 0),
+	CABAC_ENTRY(34, -11, 65, -13, 79, -24, 102, 0, 0),
+	CABAC_ENTRY(35, 1, 62, 5, 52, 5, 57, 0, 0),
+	CABAC_ENTRY(36, -6, 86, 6, 69, -6, 93, 0, 0),
+	CABAC_ENTRY(37, -17, 95, -13, 90, -14, 88, 0, 0),
+	CABAC_ENTRY(38, -6, 61, 0, 52, -6, 44, 0, 0),
+	CABAC_ENTRY(39, 9, 45, 8, 43, 4, 55, 0, 0),
+
+	/* Table 9-15 ? Values of variables m and n for ctxIdx from 40 to 53 */
+	CABAC_ENTRY(40, -3, 69, -2, 69, -11, 89, 0, 0),
+	CABAC_ENTRY(41, -6, 81, -5, 82, -15, 103, 0, 0),
+	CABAC_ENTRY(42, -11, 96, -10, 96, -21, 116, 0, 0),
+	CABAC_ENTRY(43, 6, 55, 2, 59, 19, 57, 0, 0),
+	CABAC_ENTRY(44, 7, 67, 2, 75, 20, 58, 0, 0),
+	CABAC_ENTRY(45, -5, 86, -3, 87, 4, 84, 0, 0),
+	CABAC_ENTRY(46, 2, 88, -3, 100, 6, 96, 0, 0),
+	CABAC_ENTRY(47, 0, 58, 1, 56, 1, 63, 0, 0),
+	CABAC_ENTRY(48, -3, 76, -3, 74, -5, 85, 0, 0),
+	CABAC_ENTRY(49, -10, 94, -6, 85, -13, 106, 0, 0),
+	CABAC_ENTRY(50, 5, 54, 0, 59, 5, 63, 0, 0),
+	CABAC_ENTRY(51, 4, 69, -3, 81, 6, 75, 0, 0),
+	CABAC_ENTRY(52, -3, 81, -7, 86, -3, 90, 0, 0),
+	CABAC_ENTRY(53, 0, 88, -5, 95, -1, 101, 0, 0),
+
+	/* Table 9-16 ? Values of variables m and n for ctxIdx from 54 to 59 */
+	CABAC_ENTRY(54, -7, 67, -1, 66, 3, 55, 0, 0),
+	CABAC_ENTRY(55, -5, 74, -1, 77, -4, 79, 0, 0),
+	CABAC_ENTRY(56, -4, 74, 1, 70, -2, 75, 0, 0),
+	CABAC_ENTRY(57, -5, 80, -2, 86, -12, 97, 0, 0),
+	CABAC_ENTRY(58, -7, 72, -5, 72, -7, 50, 0, 0),
+	CABAC_ENTRY(59, 1, 58, 0, 61, 1, 60, 0, 0),
+
+	/* Table 9-17 ? Values of variables m and n for ctxIdx from 60 to 69 */
+	CABAC_ENTRY(60, 0, 41, 0, 41, 0, 41, 0, 41),
+	CABAC_ENTRY(61, 0, 63, 0, 63, 0, 63, 0, 63),
+	CABAC_ENTRY(62, 0, 63, 0, 63, 0, 63, 0, 63),
+	CABAC_ENTRY(63, 0, 63, 0, 63, 0, 63, 0, 63),
+	CABAC_ENTRY(64, -9, 83, -9, 83, -9, 83, -9, 83),
+	CABAC_ENTRY(65, 4, 86, 4, 86, 4, 86, 4, 86),
+	CABAC_ENTRY(66, 0, 97, 0, 97, 0, 97, 0, 97),
+	CABAC_ENTRY(67, -7, 72, -7, 72, -7, 72, -7, 72),
+	CABAC_ENTRY(68, 13, 41, 13, 41, 13, 41, 13, 41),
+	CABAC_ENTRY(69, 3, 62, 3, 62, 3, 62, 3, 62),
+
+	/* Table 9-18 ? Values of variables m and n for ctxIdx from 70 to 104 */
+	CABAC_ENTRY(70, 0, 45, 13, 15, 7, 34, 0, 11),
+	CABAC_ENTRY(71, -4, 78, 7, 51, -9, 88, 1, 55),
+	CABAC_ENTRY(72, -3, 96, 2, 80, -20, 127, 0, 69),
+	CABAC_ENTRY(73, -27, 126, -39, 127, -36, 127, -17, 127),
+	CABAC_ENTRY(74, -28, 98, -18, 91, -17, 91, -13, 102),
+	CABAC_ENTRY(75, -25, 101, -17, 96, -14, 95, 0, 82),
+	CABAC_ENTRY(76, -23, 67, -26, 81, -25, 84, -7, 74),
+	CABAC_ENTRY(77, -28, 82, -35, 98, -25, 86, -21, 107),
+	CABAC_ENTRY(78, -20, 94, -24, 102, -12, 89, -27, 127),
+	CABAC_ENTRY(79, -16, 83, -23, 97, -17, 91, -31, 127),
+	CABAC_ENTRY(80, -22, 110, -27, 119, -31, 127, -24, 127),
+	CABAC_ENTRY(81, -21, 91, -24, 99, -14, 76, -18, 95),
+	CABAC_ENTRY(82, -18, 102, -21, 110, -18, 103, -27, 127),
+	CABAC_ENTRY(83, -13, 93, -18, 102, -13, 90, -21, 114),
+	CABAC_ENTRY(84, -29, 127, -36, 127, -37, 127, -30, 127),
+	CABAC_ENTRY(85, -7, 92, 0, 80, 11, 80, -17, 123),
+	CABAC_ENTRY(86, -5, 89, -5, 89, 5, 76, -12, 115),
+	CABAC_ENTRY(87, -7, 96, -7, 94, 2, 84, -16, 122),
+	CABAC_ENTRY(88, -13, 108, -4, 92, 5, 78, -11, 115),
+	CABAC_ENTRY(89, -3, 46, 0, 39, -6, 55, -12, 63),
+	CABAC_ENTRY(90, -1, 65, 0, 65, 4, 61, -2, 68),
+	CABAC_ENTRY(91, -1, 57, -15, 84, -14, 83, -15, 84),
+	CABAC_ENTRY(92, -9, 93, -35, 127, -37, 127, -13, 104),
+	CABAC_ENTRY(93, -3, 74, -2, 73, -5, 79, -3, 70),
+	CABAC_ENTRY(94, -9, 92, -12, 104, -11, 104, -8, 93),
+	CABAC_ENTRY(95, -8, 87, -9, 91, -11, 91, -10, 90),
+	CABAC_ENTRY(96, -23, 126, -31, 127, -30, 127, -30, 127),
+	CABAC_ENTRY(97, 5, 54, 3, 55, 0, 65, -1, 74),
+	CABAC_ENTRY(98, 6, 60, 7, 56, -2, 79, -6, 97),
+	CABAC_ENTRY(99, 6, 59, 7, 55, 0, 72, -7, 91),
+	CABAC_ENTRY(100, 6, 69, 8, 61, -4, 92, -20, 127),
+	CABAC_ENTRY(101, -1, 48, -3, 53, -6, 56, -4, 56),
+	CABAC_ENTRY(102, 0, 68, 0, 68, 3, 68, -5, 82),
+	CABAC_ENTRY(103, -4, 69, -7, 74, -8, 71, -7, 76),
+	CABAC_ENTRY(104, -8, 88, -9, 88, -13, 98, -22, 125),
+
+	/* Table 9-19 ? Values of variables m and n for ctxIdx from 105 to 165 */
+	CABAC_ENTRY(105, -2, 85, -13, 103, -4, 86, -7, 93),
+	CABAC_ENTRY(106, -6, 78, -13, 91, -12, 88, -11, 87),
+	CABAC_ENTRY(107, -1, 75, -9, 89, -5, 82, -3, 77),
+	CABAC_ENTRY(108, -7, 77, -14, 92, -3, 72, -5, 71),
+	CABAC_ENTRY(109, 2, 54, -8, 76, -4, 67, -4, 63),
+	CABAC_ENTRY(110, 5, 50, -12, 87, -8, 72, -4, 68),
+	CABAC_ENTRY(111, -3, 68, -23, 110, -16, 89, -12, 84),
+	CABAC_ENTRY(112, 1, 50, -24, 105, -9, 69, -7, 62),
+	CABAC_ENTRY(113, 6, 42, -10, 78, -1, 59, -7, 65),
+	CABAC_ENTRY(114, -4, 81, -20, 112, 5, 66, 8, 61),
+	CABAC_ENTRY(115, 1, 63, -17, 99, 4, 57, 5, 56),
+	CABAC_ENTRY(116, -4, 70, -78, 127, -4, 71, -2, 66),
+	CABAC_ENTRY(117, 0, 67, -70, 127, -2, 71, 1, 64),
+	CABAC_ENTRY(118, 2, 57, -50, 127, 2, 58, 0, 61),
+	CABAC_ENTRY(119, -2, 76, -46, 127, -1, 74, -2, 78),
+	CABAC_ENTRY(120, 11, 35, -4, 66, -4, 44, 1, 50),
+	CABAC_ENTRY(121, 4, 64, -5, 78, -1, 69, 7, 52),
+	CABAC_ENTRY(122, 1, 61, -4, 71, 0, 62, 10, 35),
+	CABAC_ENTRY(123, 11, 35, -8, 72, -7, 51, 0, 44),
+	CABAC_ENTRY(124, 18, 25, 2, 59, -4, 47, 11, 38),
+	CABAC_ENTRY(125, 12, 24, -1, 55, -6, 42, 1, 45),
+	CABAC_ENTRY(126, 13, 29, -7, 70, -3, 41, 0, 46),
+	CABAC_ENTRY(127, 13, 36, -6, 75, -6, 53, 5, 44),
+	CABAC_ENTRY(128, -10, 93, -8, 89, 8, 76, 31, 17),
+	CABAC_ENTRY(129, -7, 73, -34, 119, -9, 78, 1, 51),
+	CABAC_ENTRY(130, -2, 73, -3, 75, -11, 83, 7, 50),
+	CABAC_ENTRY(131, 13, 46, 32, 20, 9, 52, 28, 19),
+	CABAC_ENTRY(132, 9, 49, 30, 22, 0, 67, 16, 33),
+	CABAC_ENTRY(133, -7, 100, -44, 127, -5, 90, 14, 62),
+	CABAC_ENTRY(134, 9, 53, 0, 54, 1, 67, -13, 108),
+	CABAC_ENTRY(135, 2, 53, -5, 61, -15, 72, -15, 100),
+	CABAC_ENTRY(136, 5, 53, 0, 58, -5, 75, -13, 101),
+	CABAC_ENTRY(137, -2, 61, -1, 60, -8, 80, -13, 91),
+	CABAC_ENTRY(138, 0, 56, -3, 61, -21, 83, -12, 94),
+	CABAC_ENTRY(139, 0, 56, -8, 67, -21, 64, -10, 88),
+	CABAC_ENTRY(140, -13, 63, -25, 84, -13, 31, -16, 84),
+	CABAC_ENTRY(141, -5, 60, -14, 74, -25, 64, -10, 86),
+	CABAC_ENTRY(142, -1, 62, -5, 65, -29, 94, -7, 83),
+	CABAC_ENTRY(143, 4, 57, 5, 52, 9, 75, -13, 87),
+	CABAC_ENTRY(144, -6, 69, 2, 57, 17, 63, -19, 94),
+	CABAC_ENTRY(145, 4, 57, 0, 61, -8, 74, 1, 70),
+	CABAC_ENTRY(146, 14, 39, -9, 69, -5, 35, 0, 72),
+	CABAC_ENTRY(147, 4, 51, -11, 70, -2, 27, -5, 74),
+	CABAC_ENTRY(148, 13, 68, 18, 55, 13, 91, 18, 59),
+	CABAC_ENTRY(149, 3, 64, -4, 71, 3, 65, -8, 102),
+	CABAC_ENTRY(150, 1, 61, 0, 58, -7, 69, -15, 100),
+	CABAC_ENTRY(151, 9, 63, 7, 61, 8, 77, 0, 95),
+	CABAC_ENTRY(152, 7, 50, 9, 41, -10, 66, -4, 75),
+	CABAC_ENTRY(153, 16, 39, 18, 25, 3, 62, 2, 72),
+	CABAC_ENTRY(154, 5, 44, 9, 32, -3, 68, -11, 75),
+	CABAC_ENTRY(155, 4, 52, 5, 43, -20, 81, -3, 71),
+	CABAC_ENTRY(156, 11, 48, 9, 47, 0, 30, 15, 46),
+	CABAC_ENTRY(157, -5, 60, 0, 44, 1, 7, -13, 69),
+	CABAC_ENTRY(158, -1, 59, 0, 51, -3, 23, 0, 62),
+	CABAC_ENTRY(159, 0, 59, 2, 46, -21, 74, 0, 65),
+	CABAC_ENTRY(160, 22, 33, 19, 38, 16, 66, 21, 37),
+	CABAC_ENTRY(161, 5, 44, -4, 66, -23, 124, -15, 72),
+	CABAC_ENTRY(162, 14, 43, 15, 38, 17, 37, 9, 57),
+	CABAC_ENTRY(163, -1, 78, 12, 42, 44, -18, 16, 54),
+	CABAC_ENTRY(164, 0, 60, 9, 34, 50, -34, 0, 62),
+	CABAC_ENTRY(165, 9, 69, 0, 89, -22, 127, 12, 72),
+
+	/* Table 9-20 ? Values of variables m and n for ctxIdx from 166 to 226 */
+	CABAC_ENTRY(166, 11, 28, 4, 45, 4, 39, 24, 0),
+	CABAC_ENTRY(167, 2, 40, 10, 28, 0, 42, 15, 9),
+	CABAC_ENTRY(168, 3, 44, 10, 31, 7, 34, 8, 25),
+	CABAC_ENTRY(169, 0, 49, 33, -11, 11, 29, 13, 18),
+	CABAC_ENTRY(170, 0, 46, 52, -43, 8, 31, 15, 9),
+	CABAC_ENTRY(171, 2, 44, 18, 15, 6, 37, 13, 19),
+	CABAC_ENTRY(172, 2, 51, 28, 0, 7, 42, 10, 37),
+	CABAC_ENTRY(173, 0, 47, 35, -22, 3, 40, 12, 18),
+	CABAC_ENTRY(174, 4, 39, 38, -25, 8, 33, 6, 29),
+	CABAC_ENTRY(175, 2, 62, 34, 0, 13, 43, 20, 33),
+	CABAC_ENTRY(176, 6, 46, 39, -18, 13, 36, 15, 30),
+	CABAC_ENTRY(177, 0, 54, 32, -12, 4, 47, 4, 45),
+	CABAC_ENTRY(178, 3, 54, 102, -94, 3, 55, 1, 58),
+	CABAC_ENTRY(179, 2, 58, 0, 0, 2, 58, 0, 62),
+	CABAC_ENTRY(180, 4, 63, 56, -15, 6, 60, 7, 61),
+	CABAC_ENTRY(181, 6, 51, 33, -4, 8, 44, 12, 38),
+	CABAC_ENTRY(182, 6, 57, 29, 10, 11, 44, 11, 45),
+	CABAC_ENTRY(183, 7, 53, 37, -5, 14, 42, 15, 39),
+	CABAC_ENTRY(184, 6, 52, 51, -29, 7, 48, 11, 42),
+	CABAC_ENTRY(185, 6, 55, 39, -9, 4, 56, 13, 44),
+	CABAC_ENTRY(186, 11, 45, 52, -34, 4, 52, 16, 45),
+	CABAC_ENTRY(187, 14, 36, 69, -58, 13, 37, 12, 41),
+	CABAC_ENTRY(188, 8, 53, 67, -63, 9, 49, 10, 49),
+	CABAC_ENTRY(189, -1, 82, 44, -5, 19, 58, 30, 34),
+	CABAC_ENTRY(190, 7, 55, 32, 7, 10, 48, 18, 42),
+	CABAC_ENTRY(191, -3, 78, 55, -29, 12, 45, 10, 55),
+	CABAC_ENTRY(192, 15, 46, 32, 1, 0, 69, 17, 51),
+	CABAC_ENTRY(193, 22, 31, 0, 0, 20, 33, 17, 46),
+	CABAC_ENTRY(194, -1, 84, 27, 36, 8, 63, 0, 89),
+	CABAC_ENTRY(195, 25, 7, 33, -25, 35, -18, 26, -19),
+	CABAC_ENTRY(196, 30, -7, 34, -30, 33, -25, 22, -17),
+	CABAC_ENTRY(197, 28, 3, 36, -28, 28, -3, 26, -17),
+	CABAC_ENTRY(198, 28, 4, 38, -28, 24, 10, 30, -25),
+	CABAC_ENTRY(199, 32, 0, 38, -27, 27, 0, 28, -20),
+	CABAC_ENTRY(200, 34, -1, 34, -18, 34, -14, 33, -23),
+	CABAC_ENTRY(201, 30, 6, 35, -16, 52, -44, 37, -27),
+	CABAC_ENTRY(202, 30, 6, 34, -14, 39, -24, 33, -23),
+	CABAC_ENTRY(203, 32, 9, 32, -8, 19, 17, 40, -28),
+	CABAC_ENTRY(204, 31, 19, 37, -6, 31, 25, 38, -17),
+	CABAC_ENTRY(205, 26, 27, 35, 0, 36, 29, 33, -11),
+	CABAC_ENTRY(206, 26, 30, 30, 10, 24, 33, 40, -15),
+	CABAC_ENTRY(207, 37, 20, 28, 18, 34, 15, 41, -6),
+	CABAC_ENTRY(208, 28, 34, 26, 25, 30, 20, 38, 1),
+	CABAC_ENTRY(209, 17, 70, 29, 41, 22, 73, 41, 17),
+	CABAC_ENTRY(210, 1, 67, 0, 75, 20, 34, 30, -6),
+	CABAC_ENTRY(211, 5, 59, 2, 72, 19, 31, 27, 3),
+	CABAC_ENTRY(212, 9, 67, 8, 77, 27, 44, 26, 22),
+	CABAC_ENTRY(213, 16, 30, 14, 35, 19, 16, 37, -16),
+	CABAC_ENTRY(214, 18, 32, 18, 31, 15, 36, 35, -4),
+	CABAC_ENTRY(215, 18, 35, 17, 35, 15, 36, 38, -8),
+	CABAC_ENTRY(216, 22, 29, 21, 30, 21, 28, 38, -3),
+	CABAC_ENTRY(217, 24, 31, 17, 45, 25, 21, 37, 3),
+	CABAC_ENTRY(218, 23, 38, 20, 42, 30, 20, 38, 5),
+	CABAC_ENTRY(219, 18, 43, 18, 45, 31, 12, 42, 0),
+	CABAC_ENTRY(220, 20, 41, 27, 26, 27, 16, 35, 16),
+	CABAC_ENTRY(221, 11, 63, 16, 54, 24, 42, 39, 22),
+	CABAC_ENTRY(222, 9, 59, 7, 66, 0, 93, 14, 48),
+	CABAC_ENTRY(223, 9, 64, 16, 56, 14, 56, 27, 37),
+	CABAC_ENTRY(224, -1, 94, 11, 73, 15, 57, 21, 60),
+	CABAC_ENTRY(225, -2, 89, 10, 67, 26, 38, 12, 68),
+	CABAC_ENTRY(226, -9, 108, -10, 116, -24, 127, 2, 97),
+
+	/* Table 9-21 ? Values of variables m and n for ctxIdx from 227 to 275 */
+	CABAC_ENTRY(227, -6, 76, -23, 112, -24, 115, -3, 71),
+	CABAC_ENTRY(228, -2, 44, -15, 71, -22, 82, -6, 42),
+	CABAC_ENTRY(229, 0, 45, -7, 61, -9, 62, -5, 50),
+	CABAC_ENTRY(230, 0, 52, 0, 53, 0, 53, -3, 54),
+	CABAC_ENTRY(231, -3, 64, -5, 66, 0, 59, -2, 62),
+	CABAC_ENTRY(232, -2, 59, -11, 77, -14, 85, 0, 58),
+	CABAC_ENTRY(233, -4, 70, -9, 80, -13, 89, 1, 63),
+	CABAC_ENTRY(234, -4, 75, -9, 84, -13, 94, -2, 72),
+	CABAC_ENTRY(235, -8, 82, -10, 87, -11, 92, -1, 74),
+	CABAC_ENTRY(236, -17, 102, -34, 127, -29, 127, -9, 91),
+	CABAC_ENTRY(237, -9, 77, -21, 101, -21, 100, -5, 67),
+	CABAC_ENTRY(238, 3, 24, -3, 39, -14, 57, -5, 27),
+	CABAC_ENTRY(239, 0, 42, -5, 53, -12, 67, -3, 39),
+	CABAC_ENTRY(240, 0, 48, -7, 61, -11, 71, -2, 44),
+	CABAC_ENTRY(241, 0, 55, -11, 75, -10, 77, 0, 46),
+	CABAC_ENTRY(242, -6, 59, -15, 77, -21, 85, -16, 64),
+	CABAC_ENTRY(243, -7, 71, -17, 91, -16, 88, -8, 68),
+	CABAC_ENTRY(244, -12, 83, -25, 107, -23, 104, -10, 78),
+	CABAC_ENTRY(245, -11, 87, -25, 111, -15, 98, -6, 77),
+	CABAC_ENTRY(246, -30, 119, -28, 122, -37, 127, -10, 86),
+	CABAC_ENTRY(247, 1, 58, -11, 76, -10, 82, -12, 92),
+	CABAC_ENTRY(248, -3, 29, -10, 44, -8, 48, -15, 55),
+	CABAC_ENTRY(249, -1, 36, -10, 52, -8, 61, -10, 60),
+	CABAC_ENTRY(250, 1, 38, -10, 57, -8, 66, -6, 62),
+	CABAC_ENTRY(251, 2, 43, -9, 58, -7, 70, -4, 65),
+	CABAC_ENTRY(252, -6, 55, -16, 72, -14, 75, -12, 73),
+	CABAC_ENTRY(253, 0, 58, -7, 69, -10, 79, -8, 76),
+	CABAC_ENTRY(254, 0, 64, -4, 69, -9, 83, -7, 80),
+	CABAC_ENTRY(255, -3, 74, -5, 74, -12, 92, -9, 88),
+	CABAC_ENTRY(256, -10, 90, -9, 86, -18, 108, -17, 110),
+	CABAC_ENTRY(257, 0, 70, 2, 66, -4, 79, -11, 97),
+	CABAC_ENTRY(258, -4, 29, -9, 34, -22, 69, -20, 84),
+	CABAC_ENTRY(259, 5, 31, 1, 32, -16, 75, -11, 79),
+	CABAC_ENTRY(260, 7, 42, 11, 31, -2, 58, -6, 73),
+	CABAC_ENTRY(261, 1, 59, 5, 52, 1, 58, -4, 74),
+	CABAC_ENTRY(262, -2, 58, -2, 55, -13, 78, -13, 86),
+	CABAC_ENTRY(263, -3, 72, -2, 67, -9, 83, -13, 96),
+	CABAC_ENTRY(264, -3, 81, 0, 73, -4, 81, -11, 97),
+	CABAC_ENTRY(265, -11, 97, -8, 89, -13, 99, -19, 117),
+	CABAC_ENTRY(266, 0, 58, 3, 52, -13, 81, -8, 78),
+	CABAC_ENTRY(267, 8, 5, 7, 4, -6, 38, -5, 33),
+	CABAC_ENTRY(268, 10, 14, 10, 8, -13, 62, -4, 48),
+	CABAC_ENTRY(269, 14, 18, 17, 8, -6, 58, -2, 53),
+	CABAC_ENTRY(270, 13, 27, 16, 19, -2, 59, -3, 62),
+	CABAC_ENTRY(271, 2, 40, 3, 37, -16, 73, -13, 71),
+	CABAC_ENTRY(272, 0, 58, -1, 61, -10, 76, -10, 79),
+	CABAC_ENTRY(273, -3, 70, -5, 73, -13, 86, -12, 86),
+	CABAC_ENTRY(274, -6, 79, -1, 70, -9, 83, -13, 90),
+	CABAC_ENTRY(275, -8, 85, -4, 78, -10, 87, -14, 97),
+
+	/* Table 9-22 ? Values of variables m and n for ctxIdx from 277 to 337 */
+	CABAC_ENTRY(277, -13, 106, -21, 126, -22, 127, -6, 93),
+	CABAC_ENTRY(278, -16, 106, -23, 124, -25, 127, -6, 84),
+	CABAC_ENTRY(279, -10, 87, -20, 110, -25, 120, -8, 79),
+	CABAC_ENTRY(280, -21, 114, -26, 126, -27, 127, 0, 66),
+	CABAC_ENTRY(281, -18, 110, -25, 124, -19, 114, -1, 71),
+	CABAC_ENTRY(282, -14, 98, -17, 105, -23, 117, 0, 62),
+	CABAC_ENTRY(283, -22, 110, -27, 121, -25, 118, -2, 60),
+	CABAC_ENTRY(284, -21, 106, -27, 117, -26, 117, -2, 59),
+	CABAC_ENTRY(285, -18, 103, -17, 102, -24, 113, -5, 75),
+	CABAC_ENTRY(286, -21, 107, -26, 117, -28, 118, -3, 62),
+	CABAC_ENTRY(287, -23, 108, -27, 116, -31, 120, -4, 58),
+	CABAC_ENTRY(288, -26, 112, -33, 122, -37, 124, -9, 66),
+	CABAC_ENTRY(289, -10, 96, -10, 95, -10, 94, -1, 79),
+	CABAC_ENTRY(290, -12, 95, -14, 100, -15, 102, 0, 71),
+	CABAC_ENTRY(291, -5, 91, -8, 95, -10, 99, 3, 68),
+	CABAC_ENTRY(292, -9, 93, -17, 111, -13, 106, 10, 44),
+	CABAC_ENTRY(293, -22, 94, -28, 114, -50, 127, -7, 62),
+	CABAC_ENTRY(294, -5, 86, -6, 89, -5, 92, 15, 36),
+	CABAC_ENTRY(295, 9, 67, -2, 80, 17, 57, 14, 40),
+	CABAC_ENTRY(296, -4, 80, -4, 82, -5, 86, 16, 27),
+	CABAC_ENTRY(297, -10, 85, -9, 85, -13, 94, 12, 29),
+	CABAC_ENTRY(298, -1, 70, -8, 81, -12, 91, 1, 44),
+	CABAC_ENTRY(299, 7, 60, -1, 72, -2, 77, 20, 36),
+	CABAC_ENTRY(300, 9, 58, 5, 64, 0, 71, 18, 32),
+	CABAC_ENTRY(301, 5, 61, 1, 67, -1, 73, 5, 42),
+	CABAC_ENTRY(302, 12, 50, 9, 56, 4, 64, 1, 48),
+	CABAC_ENTRY(303, 15, 50, 0, 69, -7, 81, 10, 62),
+	CABAC_ENTRY(304, 18, 49, 1, 69, 5, 64, 17, 46),
+	CABAC_ENTRY(305, 17, 54, 7, 69, 15, 57, 9, 64),
+	CABAC_ENTRY(306, 10, 41, -7, 69, 1, 67, -12, 104),
+	CABAC_ENTRY(307, 7, 46, -6, 67, 0, 68, -11, 97),
+	CABAC_ENTRY(308, -1, 51, -16, 77, -10, 67, -16, 96),
+	CABAC_ENTRY(309, 7, 49, -2, 64, 1, 68, -7, 88),
+	CABAC_ENTRY(310, 8, 52, 2, 61, 0, 77, -8, 85),
+	CABAC_ENTRY(311, 9, 41, -6, 67, 2, 64, -7, 85),
+	CABAC_ENTRY(312, 6, 47, -3, 64, 0, 68, -9, 85),
+	CABAC_ENTRY(313, 2, 55, 2, 57, -5, 78, -13, 88),
+	CABAC_ENTRY(314, 13, 41, -3, 65, 7, 55, 4, 66),
+	CABAC_ENTRY(315, 10, 44, -3, 66, 5, 59, -3, 77),
+	CABAC_ENTRY(316, 6, 50, 0, 62, 2, 65, -3, 76),
+	CABAC_ENTRY(317, 5, 53, 9, 51, 14, 54, -6, 76),
+	CABAC_ENTRY(318, 13, 49, -1, 66, 15, 44, 10, 58),
+	CABAC_ENTRY(319, 4, 63, -2, 71, 5, 60, -1, 76),
+	CABAC_ENTRY(320, 6, 64, -2, 75, 2, 70, -1, 83),
+	CABAC_ENTRY(321, -2, 69, -1, 70, -2, 76, -7, 99),
+	CABAC_ENTRY(322, -2, 59, -9, 72, -18, 86, -14, 95),
+	CABAC_ENTRY(323, 6, 70, 14, 60, 12, 70, 2, 95),
+	CABAC_ENTRY(324, 10, 44, 16, 37, 5, 64, 0, 76),
+	CABAC_ENTRY(325, 9, 31, 0, 47, -12, 70, -5, 74),
+	CABAC_ENTRY(326, 12, 43, 18, 35, 11, 55, 0, 70),
+	CABAC_ENTRY(327, 3, 53, 11, 37, 5, 56, -11, 75),
+	CABAC_ENTRY(328, 14, 34, 12, 41, 0, 69, 1, 68),
+	CABAC_ENTRY(329, 10, 38, 10, 41, 2, 65, 0, 65),
+	CABAC_ENTRY(330, -3, 52, 2, 48, -6, 74, -14, 73),
+	CABAC_ENTRY(331, 13, 40, 12, 41, 5, 54, 3, 62),
+	CABAC_ENTRY(332, 17, 32, 13, 41, 7, 54, 4, 62),
+	CABAC_ENTRY(333, 7, 44, 0, 59, -6, 76, -1, 68),
+	CABAC_ENTRY(334, 7, 38, 3, 50, -11, 82, -13, 75),
+	CABAC_ENTRY(335, 13, 50, 19, 40, -2, 77, 11, 55),
+	CABAC_ENTRY(336, 10, 57, 3, 66, -2, 77, 5, 64),
+	CABAC_ENTRY(337, 26, 43, 18, 50, 25, 42, 12, 70),
+
+	/* Table 9-23 ? Values of variables m and n for ctxIdx from 338 to 398 */
+	CABAC_ENTRY(338, 14, 11, 19, -6, 17, -13, 15, 6),
+	CABAC_ENTRY(339, 11, 14, 18, -6, 16, -9, 6, 19),
+	CABAC_ENTRY(340, 9, 11, 14, 0, 17, -12, 7, 16),
+	CABAC_ENTRY(341, 18, 11, 26, -12, 27, -21, 12, 14),
+	CABAC_ENTRY(342, 21, 9, 31, -16, 37, -30, 18, 13),
+	CABAC_ENTRY(343, 23, -2, 33, -25, 41, -40, 13, 11),
+	CABAC_ENTRY(344, 32, -15, 33, -22, 42, -41, 13, 15),
+	CABAC_ENTRY(345, 32, -15, 37, -28, 48, -47, 15, 16),
+	CABAC_ENTRY(346, 34, -21, 39, -30, 39, -32, 12, 23),
+	CABAC_ENTRY(347, 39, -23, 42, -30, 46, -40, 13, 23),
+	CABAC_ENTRY(348, 42, -33, 47, -42, 52, -51, 15, 20),
+	CABAC_ENTRY(349, 41, -31, 45, -36, 46, -41, 14, 26),
+	CABAC_ENTRY(350, 46, -28, 49, -34, 52, -39, 14, 44),
+	CABAC_ENTRY(351, 38, -12, 41, -17, 43, -19, 17, 40),
+	CABAC_ENTRY(352, 21, 29, 32, 9, 32, 11, 17, 47),
+	CABAC_ENTRY(353, 45, -24, 69, -71, 61, -55, 24, 17),
+	CABAC_ENTRY(354, 53, -45, 63, -63, 56, -46, 21, 21),
+	CABAC_ENTRY(355, 48, -26, 66, -64, 62, -50, 25, 22),
+	CABAC_ENTRY(356, 65, -43, 77, -74, 81, -67, 31, 27),
+	CABAC_ENTRY(357, 43, -19, 54, -39, 45, -20, 22, 29),
+	CABAC_ENTRY(358, 39, -10, 52, -35, 35, -2, 19, 35),
+	CABAC_ENTRY(359, 30, 9, 41, -10, 28, 15, 14, 50),
+	CABAC_ENTRY(360, 18, 26, 36, 0, 34, 1, 10, 57),
+	CABAC_ENTRY(361, 20, 27, 40, -1, 39, 1, 7, 63),
+	CABAC_ENTRY(362, 0, 57, 30, 14, 30, 17, -2, 77),
+	CABAC_ENTRY(363, -14, 82, 28, 26, 20, 38, -4, 82),
+	CABAC_ENTRY(364, -5, 75, 23, 37, 18, 45, -3, 94),
+	CABAC_ENTRY(365, -19, 97, 12, 55, 15, 54, 9, 69),
+	CABAC_ENTRY(366, -35, 125, 11, 65, 0, 79, -12, 109),
+	CABAC_ENTRY(367, 27, 0, 37, -33, 36, -16, 36, -35),
+	CABAC_ENTRY(368, 28, 0, 39, -36, 37, -14, 36, -34),
+	CABAC_ENTRY(369, 31, -4, 40, -37, 37, -17, 32, -26),
+	CABAC_ENTRY(370, 27, 6, 38, -30, 32, 1, 37, -30),
+	CABAC_ENTRY(371, 34, 8, 46, -33, 34, 15, 44, -32),
+	CABAC_ENTRY(372, 30, 10, 42, -30, 29, 15, 34, -18),
+	CABAC_ENTRY(373, 24, 22, 40, -24, 24, 25, 34, -15),
+	CABAC_ENTRY(374, 33, 19, 49, -29, 34, 22, 40, -15),
+	CABAC_ENTRY(375, 22, 32, 38, -12, 31, 16, 33, -7),
+	CABAC_ENTRY(376, 26, 31, 40, -10, 35, 18, 35, -5),
+	CABAC_ENTRY(377, 21, 41, 38, -3, 31, 28, 33, 0),
+	CABAC_ENTRY(378, 26, 44, 46, -5, 33, 41, 38, 2),
+	CABAC_ENTRY(379, 23, 47, 31, 20, 36, 28, 33, 13),
+	CABAC_ENTRY(380, 16, 65, 29, 30, 27, 47, 23, 35),
+	CABAC_ENTRY(381, 14, 71, 25, 44, 21, 62, 13, 58),
+	CABAC_ENTRY(382, 8, 60, 12, 48, 18, 31, 29, -3),
+	CABAC_ENTRY(383, 6, 63, 11, 49, 19, 26, 26, 0),
+	CABAC_ENTRY(384, 17, 65, 26, 45, 36, 24, 22, 30),
+	CABAC_ENTRY(385, 21, 24, 22, 22, 24, 23, 31, -7),
+	CABAC_ENTRY(386, 23, 20, 23, 22, 27, 16, 35, -15),
+	CABAC_ENTRY(387, 26, 23, 27, 21, 24, 30, 34, -3),
+	CABAC_ENTRY(388, 27, 32, 33, 20, 31, 29, 34, 3),
+	CABAC_ENTRY(389, 28, 23, 26, 28, 22, 41, 36, -1),
+	CABAC_ENTRY(390, 28, 24, 30, 24, 22, 42, 34, 5),
+	CABAC_ENTRY(391, 23, 40, 27, 34, 16, 60, 32, 11),
+	CABAC_ENTRY(392, 24, 32, 18, 42, 15, 52, 35, 5),
+	CABAC_ENTRY(393, 28, 29, 25, 39, 14, 60, 34, 12),
+	CABAC_ENTRY(394, 23, 42, 18, 50, 3, 78, 39, 11),
+	CABAC_ENTRY(395, 19, 57, 12, 70, -16, 123, 30, 29),
+	CABAC_ENTRY(396, 22, 53, 21, 54, 21, 53, 34, 26),
+	CABAC_ENTRY(397, 22, 61, 14, 71, 22, 56, 29, 39),
+	CABAC_ENTRY(398, 11, 86, 11, 83, 25, 61, 19, 66),
+
+	/* Values of variables m and n for ctxIdx from 399 to 463 (not documented) */
+	CABAC_ENTRY(399, 12, 40, 25, 32, 21, 33, 31, 21),
+	CABAC_ENTRY(400, 11, 51, 21, 49, 19, 50, 31, 31),
+	CABAC_ENTRY(401, 14, 59, 21, 54, 17, 61, 25, 50),
+	CABAC_ENTRY(402, -4, 79, -5, 85, -3, 78, -17, 120),
+	CABAC_ENTRY(403, -7, 71, -6, 81, -8, 74, -20, 112),
+	CABAC_ENTRY(404, -5, 69, -10, 77, -9, 72, -18, 114),
+	CABAC_ENTRY(405, -9, 70, -7, 81, -10, 72, -11, 85),
+	CABAC_ENTRY(406, -8, 66, -17, 80, -18, 75, -15, 92),
+	CABAC_ENTRY(407, -10, 68, -18, 73, -12, 71, -14, 89),
+	CABAC_ENTRY(408, -19, 73, -4, 74, -11, 63, -26, 71),
+	CABAC_ENTRY(409, -12, 69, -10, 83, -5, 70, -15, 81),
+	CABAC_ENTRY(410, -16, 70, -9, 71, -17, 75, -14, 80),
+	CABAC_ENTRY(411, -15, 67, -9, 67, -14, 72, 0, 68),
+	CABAC_ENTRY(412, -20, 62, -1, 61, -16, 67, -14, 70),
+	CABAC_ENTRY(413, -19, 70, -8, 66, -8, 53, -24, 56),
+	CABAC_ENTRY(414, -16, 66, -14, 66, -14, 59, -23, 68),
+	CABAC_ENTRY(415, -22, 65, 0, 59, -9, 52, -24, 50),
+	CABAC_ENTRY(416, -20, 63, 2, 59, -11, 68, -11, 74),
+	CABAC_ENTRY(417, 9, -2, 17, -10, 9, -2, 23, -13),
+	CABAC_ENTRY(418, 26, -9, 32, -13, 30, -10, 26, -13),
+	CABAC_ENTRY(419, 33, -9, 42, -9, 31, -4, 40, -15),
+	CABAC_ENTRY(420, 39, -7, 49, -5, 33, -1, 49, -14),
+	CABAC_ENTRY(421, 41, -2, 53, 0, 33, 7, 44, 3),
+	CABAC_ENTRY(422, 45, 3, 64, 3, 31, 12, 45, 6),
+	CABAC_ENTRY(423, 49, 9, 68, 10, 37, 23, 44, 34),
+	CABAC_ENTRY(424, 45, 27, 66, 27, 31, 38, 33, 54),
+	CABAC_ENTRY(425, 36, 59, 47, 57, 20, 64, 19, 82),
+	CABAC_ENTRY(426, -6, 66, -5, 71, -9, 71, -3, 75),
+	CABAC_ENTRY(427, -7, 35, 0, 24, -7, 37, -1, 23),
+	CABAC_ENTRY(428, -7, 42, -1, 36, -8, 44, 1, 34),
+	CABAC_ENTRY(429, -8, 45, -2, 42, -11, 49, 1, 43),
+	CABAC_ENTRY(430, -5, 48, -2, 52, -10, 56, 0, 54),
+	CABAC_ENTRY(431, -12, 56, -9, 57, -12, 59, -2, 55),
+	CABAC_ENTRY(432, -6, 60, -6, 63, -8, 63, 0, 61),
+	CABAC_ENTRY(433, -5, 62, -4, 65, -9, 67, 1, 64),
+	CABAC_ENTRY(434, -8, 66, -4, 67, -6, 68, 0, 68),
+	CABAC_ENTRY(435, -8, 76, -7, 82, -10, 79, -9, 92),
+	CABAC_ENTRY(436, -5, 85, -3, 81, -3, 78, -14, 106),
+	CABAC_ENTRY(437, -6, 81, -3, 76, -8, 74, -13, 97),
+	CABAC_ENTRY(438, -10, 77, -7, 72, -9, 72, -15, 90),
+	CABAC_ENTRY(439, -7, 81, -6, 78, -10, 72, -12, 90),
+	CABAC_ENTRY(440, -17, 80, -12, 72, -18, 75, -18, 88),
+	CABAC_ENTRY(441, -18, 73, -14, 68, -12, 71, -10, 73),
+	CABAC_ENTRY(442, -4, 74, -3, 70, -11, 63, -9, 79),
+	CABAC_ENTRY(443, -10, 83, -6, 76, -5, 70, -14, 86),
+	CABAC_ENTRY(444, -9, 71, -5, 66, -17, 75, -10, 73),
+	CABAC_ENTRY(445, -9, 67, -5, 62, -14, 72, -10, 70),
+	CABAC_ENTRY(446, -1, 61, 0, 57, -16, 67, -10, 69),
+	CABAC_ENTRY(447, -8, 66, -4, 61, -8, 53, -5, 66),
+	CABAC_ENTRY(448, -14, 66, -9, 60, -14, 59, -9, 64),
+	CABAC_ENTRY(449, 0, 59, 1, 54, -9, 52, -5, 58),
+	CABAC_ENTRY(450, 2, 59, 2, 58, -11, 68, 2, 59),
+	CABAC_ENTRY(451, 21, -13, 17, -10, 9, -2, 21, -10),
+	CABAC_ENTRY(452, 33, -14, 32, -13, 30, -10, 24, -11),
+	CABAC_ENTRY(453, 39, -7, 42, -9, 31, -4, 28, -8),
+	CABAC_ENTRY(454, 46, -2, 49, -5, 33, -1, 28, -1),
+	CABAC_ENTRY(455, 51, 2, 53, 0, 33, 7, 29, 3),
+	CABAC_ENTRY(456, 60, 6, 64, 3, 31, 12, 29, 9),
+	CABAC_ENTRY(457, 61, 17, 68, 10, 37, 23, 35, 20),
+	CABAC_ENTRY(458, 55, 34, 66, 27, 31, 38, 29, 36),
+	CABAC_ENTRY(459, 42, 62, 47, 57, 20, 64, 14, 67),
+};
+
+#define RKV_HEVC_CABAC_TABLE_SIZE		27456
+
+const u8 rkvdec_hevc_cabac_table[RKV_HEVC_CABAC_TABLE_SIZE] = {
 	0x07, 0x0f, 0x48, 0x58, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0f, 0x40, 0x40, 0x40, 0x0f,
 	0x68, 0x48, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x40,
 	0x40, 0x68, 0x58, 0x60, 0x40, 0x1f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x48, 0x48, 0x60,
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
index 116e7b1076b7..989379ae3a73 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
@@ -15,6 +15,8 @@
 #include "rkvdec.h"
 #include "rkvdec-regs.h"
 
+extern const s8 rkvdec_h264_cabac_table[4][464][2];
+
 /* Size with u32 units. */
 #define RKV_CABAC_INIT_BUFFER_SIZE	(3680 + 128)
 #define RKV_RPS_SIZE			((128 + 128) / 4)
@@ -118,505 +120,6 @@ struct rkvdec_h264_ctx {
 	struct rkvdec_regs regs;
 };
 
-#define CABAC_ENTRY(ctxidx, idc0_m, idc0_n, idc1_m, idc1_n,		\
-	    idc2_m, idc2_n, intra_m, intra_n)			\
-	[0][(ctxidx)] = {idc0_m, idc0_n},			\
-	[1][(ctxidx)] = {idc1_m, idc1_n},			\
-	[2][(ctxidx)] = {idc2_m, idc2_n},			\
-	[3][(ctxidx)] = {intra_m, intra_n}
-
-/*
- * Constant CABAC table.
- * Built from the tables described in section '9.3.1.1 Initialisation process
- * for context variables' of the H264 spec.
- */
-static const s8 rkvdec_h264_cabac_table[4][464][2] = {
-	/* Table 9-12 ? Values of variables m and n for ctxIdx from 0 to 10 */
-	CABAC_ENTRY(0, 20, -15, 20, -15, 20, -15, 20, -15),
-	CABAC_ENTRY(1, 2, 54, 2, 54, 2, 54, 2, 54),
-	CABAC_ENTRY(2, 3, 74, 3, 74, 3, 74, 3, 74),
-	CABAC_ENTRY(3, 20, -15, 20, -15, 20, -15, 20, -15),
-	CABAC_ENTRY(4, 2, 54, 2, 54, 2, 54, 2, 54),
-	CABAC_ENTRY(5, 3, 74, 3, 74, 3, 74, 3, 74),
-	CABAC_ENTRY(6, -28, 127, -28, 127, -28, 127, -28, 127),
-	CABAC_ENTRY(7, -23, 104, -23, 104, -23, 104, -23, 104),
-	CABAC_ENTRY(8, -6, 53, -6, 53, -6, 53, -6, 53),
-	CABAC_ENTRY(9, -1, 54, -1, 54, -1, 54, -1, 54),
-	CABAC_ENTRY(10, 7, 51, 7, 51, 7, 51, 7, 51),
-
-	/* Table 9-13 ? Values of variables m and n for ctxIdx from 11 to 23 */
-	CABAC_ENTRY(11, 23, 33, 22, 25, 29, 16, 0, 0),
-	CABAC_ENTRY(12, 23, 2, 34, 0, 25, 0, 0, 0),
-	CABAC_ENTRY(13, 21, 0, 16, 0, 14, 0, 0, 0),
-	CABAC_ENTRY(14, 1, 9, -2, 9, -10, 51, 0, 0),
-	CABAC_ENTRY(15, 0, 49, 4, 41, -3, 62, 0, 0),
-	CABAC_ENTRY(16, -37, 118, -29, 118, -27, 99, 0, 0),
-	CABAC_ENTRY(17, 5, 57, 2, 65, 26, 16, 0, 0),
-	CABAC_ENTRY(18, -13, 78, -6, 71, -4, 85, 0, 0),
-	CABAC_ENTRY(19, -11, 65, -13, 79, -24, 102, 0, 0),
-	CABAC_ENTRY(20, 1, 62, 5, 52, 5, 57, 0, 0),
-	CABAC_ENTRY(21, 12, 49, 9, 50, 6, 57, 0, 0),
-	CABAC_ENTRY(22, -4, 73, -3, 70, -17, 73, 0, 0),
-	CABAC_ENTRY(23, 17, 50, 10, 54, 14, 57, 0, 0),
-
-	/* Table 9-14 ? Values of variables m and n for ctxIdx from 24 to 39 */
-	CABAC_ENTRY(24, 18, 64, 26, 34, 20, 40, 0, 0),
-	CABAC_ENTRY(25, 9, 43, 19, 22, 20, 10, 0, 0),
-	CABAC_ENTRY(26, 29, 0, 40, 0, 29, 0, 0, 0),
-	CABAC_ENTRY(27, 26, 67, 57, 2, 54, 0, 0, 0),
-	CABAC_ENTRY(28, 16, 90, 41, 36, 37, 42, 0, 0),
-	CABAC_ENTRY(29, 9, 104, 26, 69, 12, 97, 0, 0),
-	CABAC_ENTRY(30, -46, 127, -45, 127, -32, 127, 0, 0),
-	CABAC_ENTRY(31, -20, 104, -15, 101, -22, 117, 0, 0),
-	CABAC_ENTRY(32, 1, 67, -4, 76, -2, 74, 0, 0),
-	CABAC_ENTRY(33, -13, 78, -6, 71, -4, 85, 0, 0),
-	CABAC_ENTRY(34, -11, 65, -13, 79, -24, 102, 0, 0),
-	CABAC_ENTRY(35, 1, 62, 5, 52, 5, 57, 0, 0),
-	CABAC_ENTRY(36, -6, 86, 6, 69, -6, 93, 0, 0),
-	CABAC_ENTRY(37, -17, 95, -13, 90, -14, 88, 0, 0),
-	CABAC_ENTRY(38, -6, 61, 0, 52, -6, 44, 0, 0),
-	CABAC_ENTRY(39, 9, 45, 8, 43, 4, 55, 0, 0),
-
-	/* Table 9-15 ? Values of variables m and n for ctxIdx from 40 to 53 */
-	CABAC_ENTRY(40, -3, 69, -2, 69, -11, 89, 0, 0),
-	CABAC_ENTRY(41, -6, 81, -5, 82, -15, 103, 0, 0),
-	CABAC_ENTRY(42, -11, 96, -10, 96, -21, 116, 0, 0),
-	CABAC_ENTRY(43, 6, 55, 2, 59, 19, 57, 0, 0),
-	CABAC_ENTRY(44, 7, 67, 2, 75, 20, 58, 0, 0),
-	CABAC_ENTRY(45, -5, 86, -3, 87, 4, 84, 0, 0),
-	CABAC_ENTRY(46, 2, 88, -3, 100, 6, 96, 0, 0),
-	CABAC_ENTRY(47, 0, 58, 1, 56, 1, 63, 0, 0),
-	CABAC_ENTRY(48, -3, 76, -3, 74, -5, 85, 0, 0),
-	CABAC_ENTRY(49, -10, 94, -6, 85, -13, 106, 0, 0),
-	CABAC_ENTRY(50, 5, 54, 0, 59, 5, 63, 0, 0),
-	CABAC_ENTRY(51, 4, 69, -3, 81, 6, 75, 0, 0),
-	CABAC_ENTRY(52, -3, 81, -7, 86, -3, 90, 0, 0),
-	CABAC_ENTRY(53, 0, 88, -5, 95, -1, 101, 0, 0),
-
-	/* Table 9-16 ? Values of variables m and n for ctxIdx from 54 to 59 */
-	CABAC_ENTRY(54, -7, 67, -1, 66, 3, 55, 0, 0),
-	CABAC_ENTRY(55, -5, 74, -1, 77, -4, 79, 0, 0),
-	CABAC_ENTRY(56, -4, 74, 1, 70, -2, 75, 0, 0),
-	CABAC_ENTRY(57, -5, 80, -2, 86, -12, 97, 0, 0),
-	CABAC_ENTRY(58, -7, 72, -5, 72, -7, 50, 0, 0),
-	CABAC_ENTRY(59, 1, 58, 0, 61, 1, 60, 0, 0),
-
-	/* Table 9-17 ? Values of variables m and n for ctxIdx from 60 to 69 */
-	CABAC_ENTRY(60, 0, 41, 0, 41, 0, 41, 0, 41),
-	CABAC_ENTRY(61, 0, 63, 0, 63, 0, 63, 0, 63),
-	CABAC_ENTRY(62, 0, 63, 0, 63, 0, 63, 0, 63),
-	CABAC_ENTRY(63, 0, 63, 0, 63, 0, 63, 0, 63),
-	CABAC_ENTRY(64, -9, 83, -9, 83, -9, 83, -9, 83),
-	CABAC_ENTRY(65, 4, 86, 4, 86, 4, 86, 4, 86),
-	CABAC_ENTRY(66, 0, 97, 0, 97, 0, 97, 0, 97),
-	CABAC_ENTRY(67, -7, 72, -7, 72, -7, 72, -7, 72),
-	CABAC_ENTRY(68, 13, 41, 13, 41, 13, 41, 13, 41),
-	CABAC_ENTRY(69, 3, 62, 3, 62, 3, 62, 3, 62),
-
-	/* Table 9-18 ? Values of variables m and n for ctxIdx from 70 to 104 */
-	CABAC_ENTRY(70, 0, 45, 13, 15, 7, 34, 0, 11),
-	CABAC_ENTRY(71, -4, 78, 7, 51, -9, 88, 1, 55),
-	CABAC_ENTRY(72, -3, 96, 2, 80, -20, 127, 0, 69),
-	CABAC_ENTRY(73, -27, 126, -39, 127, -36, 127, -17, 127),
-	CABAC_ENTRY(74, -28, 98, -18, 91, -17, 91, -13, 102),
-	CABAC_ENTRY(75, -25, 101, -17, 96, -14, 95, 0, 82),
-	CABAC_ENTRY(76, -23, 67, -26, 81, -25, 84, -7, 74),
-	CABAC_ENTRY(77, -28, 82, -35, 98, -25, 86, -21, 107),
-	CABAC_ENTRY(78, -20, 94, -24, 102, -12, 89, -27, 127),
-	CABAC_ENTRY(79, -16, 83, -23, 97, -17, 91, -31, 127),
-	CABAC_ENTRY(80, -22, 110, -27, 119, -31, 127, -24, 127),
-	CABAC_ENTRY(81, -21, 91, -24, 99, -14, 76, -18, 95),
-	CABAC_ENTRY(82, -18, 102, -21, 110, -18, 103, -27, 127),
-	CABAC_ENTRY(83, -13, 93, -18, 102, -13, 90, -21, 114),
-	CABAC_ENTRY(84, -29, 127, -36, 127, -37, 127, -30, 127),
-	CABAC_ENTRY(85, -7, 92, 0, 80, 11, 80, -17, 123),
-	CABAC_ENTRY(86, -5, 89, -5, 89, 5, 76, -12, 115),
-	CABAC_ENTRY(87, -7, 96, -7, 94, 2, 84, -16, 122),
-	CABAC_ENTRY(88, -13, 108, -4, 92, 5, 78, -11, 115),
-	CABAC_ENTRY(89, -3, 46, 0, 39, -6, 55, -12, 63),
-	CABAC_ENTRY(90, -1, 65, 0, 65, 4, 61, -2, 68),
-	CABAC_ENTRY(91, -1, 57, -15, 84, -14, 83, -15, 84),
-	CABAC_ENTRY(92, -9, 93, -35, 127, -37, 127, -13, 104),
-	CABAC_ENTRY(93, -3, 74, -2, 73, -5, 79, -3, 70),
-	CABAC_ENTRY(94, -9, 92, -12, 104, -11, 104, -8, 93),
-	CABAC_ENTRY(95, -8, 87, -9, 91, -11, 91, -10, 90),
-	CABAC_ENTRY(96, -23, 126, -31, 127, -30, 127, -30, 127),
-	CABAC_ENTRY(97, 5, 54, 3, 55, 0, 65, -1, 74),
-	CABAC_ENTRY(98, 6, 60, 7, 56, -2, 79, -6, 97),
-	CABAC_ENTRY(99, 6, 59, 7, 55, 0, 72, -7, 91),
-	CABAC_ENTRY(100, 6, 69, 8, 61, -4, 92, -20, 127),
-	CABAC_ENTRY(101, -1, 48, -3, 53, -6, 56, -4, 56),
-	CABAC_ENTRY(102, 0, 68, 0, 68, 3, 68, -5, 82),
-	CABAC_ENTRY(103, -4, 69, -7, 74, -8, 71, -7, 76),
-	CABAC_ENTRY(104, -8, 88, -9, 88, -13, 98, -22, 125),
-
-	/* Table 9-19 ? Values of variables m and n for ctxIdx from 105 to 165 */
-	CABAC_ENTRY(105, -2, 85, -13, 103, -4, 86, -7, 93),
-	CABAC_ENTRY(106, -6, 78, -13, 91, -12, 88, -11, 87),
-	CABAC_ENTRY(107, -1, 75, -9, 89, -5, 82, -3, 77),
-	CABAC_ENTRY(108, -7, 77, -14, 92, -3, 72, -5, 71),
-	CABAC_ENTRY(109, 2, 54, -8, 76, -4, 67, -4, 63),
-	CABAC_ENTRY(110, 5, 50, -12, 87, -8, 72, -4, 68),
-	CABAC_ENTRY(111, -3, 68, -23, 110, -16, 89, -12, 84),
-	CABAC_ENTRY(112, 1, 50, -24, 105, -9, 69, -7, 62),
-	CABAC_ENTRY(113, 6, 42, -10, 78, -1, 59, -7, 65),
-	CABAC_ENTRY(114, -4, 81, -20, 112, 5, 66, 8, 61),
-	CABAC_ENTRY(115, 1, 63, -17, 99, 4, 57, 5, 56),
-	CABAC_ENTRY(116, -4, 70, -78, 127, -4, 71, -2, 66),
-	CABAC_ENTRY(117, 0, 67, -70, 127, -2, 71, 1, 64),
-	CABAC_ENTRY(118, 2, 57, -50, 127, 2, 58, 0, 61),
-	CABAC_ENTRY(119, -2, 76, -46, 127, -1, 74, -2, 78),
-	CABAC_ENTRY(120, 11, 35, -4, 66, -4, 44, 1, 50),
-	CABAC_ENTRY(121, 4, 64, -5, 78, -1, 69, 7, 52),
-	CABAC_ENTRY(122, 1, 61, -4, 71, 0, 62, 10, 35),
-	CABAC_ENTRY(123, 11, 35, -8, 72, -7, 51, 0, 44),
-	CABAC_ENTRY(124, 18, 25, 2, 59, -4, 47, 11, 38),
-	CABAC_ENTRY(125, 12, 24, -1, 55, -6, 42, 1, 45),
-	CABAC_ENTRY(126, 13, 29, -7, 70, -3, 41, 0, 46),
-	CABAC_ENTRY(127, 13, 36, -6, 75, -6, 53, 5, 44),
-	CABAC_ENTRY(128, -10, 93, -8, 89, 8, 76, 31, 17),
-	CABAC_ENTRY(129, -7, 73, -34, 119, -9, 78, 1, 51),
-	CABAC_ENTRY(130, -2, 73, -3, 75, -11, 83, 7, 50),
-	CABAC_ENTRY(131, 13, 46, 32, 20, 9, 52, 28, 19),
-	CABAC_ENTRY(132, 9, 49, 30, 22, 0, 67, 16, 33),
-	CABAC_ENTRY(133, -7, 100, -44, 127, -5, 90, 14, 62),
-	CABAC_ENTRY(134, 9, 53, 0, 54, 1, 67, -13, 108),
-	CABAC_ENTRY(135, 2, 53, -5, 61, -15, 72, -15, 100),
-	CABAC_ENTRY(136, 5, 53, 0, 58, -5, 75, -13, 101),
-	CABAC_ENTRY(137, -2, 61, -1, 60, -8, 80, -13, 91),
-	CABAC_ENTRY(138, 0, 56, -3, 61, -21, 83, -12, 94),
-	CABAC_ENTRY(139, 0, 56, -8, 67, -21, 64, -10, 88),
-	CABAC_ENTRY(140, -13, 63, -25, 84, -13, 31, -16, 84),
-	CABAC_ENTRY(141, -5, 60, -14, 74, -25, 64, -10, 86),
-	CABAC_ENTRY(142, -1, 62, -5, 65, -29, 94, -7, 83),
-	CABAC_ENTRY(143, 4, 57, 5, 52, 9, 75, -13, 87),
-	CABAC_ENTRY(144, -6, 69, 2, 57, 17, 63, -19, 94),
-	CABAC_ENTRY(145, 4, 57, 0, 61, -8, 74, 1, 70),
-	CABAC_ENTRY(146, 14, 39, -9, 69, -5, 35, 0, 72),
-	CABAC_ENTRY(147, 4, 51, -11, 70, -2, 27, -5, 74),
-	CABAC_ENTRY(148, 13, 68, 18, 55, 13, 91, 18, 59),
-	CABAC_ENTRY(149, 3, 64, -4, 71, 3, 65, -8, 102),
-	CABAC_ENTRY(150, 1, 61, 0, 58, -7, 69, -15, 100),
-	CABAC_ENTRY(151, 9, 63, 7, 61, 8, 77, 0, 95),
-	CABAC_ENTRY(152, 7, 50, 9, 41, -10, 66, -4, 75),
-	CABAC_ENTRY(153, 16, 39, 18, 25, 3, 62, 2, 72),
-	CABAC_ENTRY(154, 5, 44, 9, 32, -3, 68, -11, 75),
-	CABAC_ENTRY(155, 4, 52, 5, 43, -20, 81, -3, 71),
-	CABAC_ENTRY(156, 11, 48, 9, 47, 0, 30, 15, 46),
-	CABAC_ENTRY(157, -5, 60, 0, 44, 1, 7, -13, 69),
-	CABAC_ENTRY(158, -1, 59, 0, 51, -3, 23, 0, 62),
-	CABAC_ENTRY(159, 0, 59, 2, 46, -21, 74, 0, 65),
-	CABAC_ENTRY(160, 22, 33, 19, 38, 16, 66, 21, 37),
-	CABAC_ENTRY(161, 5, 44, -4, 66, -23, 124, -15, 72),
-	CABAC_ENTRY(162, 14, 43, 15, 38, 17, 37, 9, 57),
-	CABAC_ENTRY(163, -1, 78, 12, 42, 44, -18, 16, 54),
-	CABAC_ENTRY(164, 0, 60, 9, 34, 50, -34, 0, 62),
-	CABAC_ENTRY(165, 9, 69, 0, 89, -22, 127, 12, 72),
-
-	/* Table 9-20 ? Values of variables m and n for ctxIdx from 166 to 226 */
-	CABAC_ENTRY(166, 11, 28, 4, 45, 4, 39, 24, 0),
-	CABAC_ENTRY(167, 2, 40, 10, 28, 0, 42, 15, 9),
-	CABAC_ENTRY(168, 3, 44, 10, 31, 7, 34, 8, 25),
-	CABAC_ENTRY(169, 0, 49, 33, -11, 11, 29, 13, 18),
-	CABAC_ENTRY(170, 0, 46, 52, -43, 8, 31, 15, 9),
-	CABAC_ENTRY(171, 2, 44, 18, 15, 6, 37, 13, 19),
-	CABAC_ENTRY(172, 2, 51, 28, 0, 7, 42, 10, 37),
-	CABAC_ENTRY(173, 0, 47, 35, -22, 3, 40, 12, 18),
-	CABAC_ENTRY(174, 4, 39, 38, -25, 8, 33, 6, 29),
-	CABAC_ENTRY(175, 2, 62, 34, 0, 13, 43, 20, 33),
-	CABAC_ENTRY(176, 6, 46, 39, -18, 13, 36, 15, 30),
-	CABAC_ENTRY(177, 0, 54, 32, -12, 4, 47, 4, 45),
-	CABAC_ENTRY(178, 3, 54, 102, -94, 3, 55, 1, 58),
-	CABAC_ENTRY(179, 2, 58, 0, 0, 2, 58, 0, 62),
-	CABAC_ENTRY(180, 4, 63, 56, -15, 6, 60, 7, 61),
-	CABAC_ENTRY(181, 6, 51, 33, -4, 8, 44, 12, 38),
-	CABAC_ENTRY(182, 6, 57, 29, 10, 11, 44, 11, 45),
-	CABAC_ENTRY(183, 7, 53, 37, -5, 14, 42, 15, 39),
-	CABAC_ENTRY(184, 6, 52, 51, -29, 7, 48, 11, 42),
-	CABAC_ENTRY(185, 6, 55, 39, -9, 4, 56, 13, 44),
-	CABAC_ENTRY(186, 11, 45, 52, -34, 4, 52, 16, 45),
-	CABAC_ENTRY(187, 14, 36, 69, -58, 13, 37, 12, 41),
-	CABAC_ENTRY(188, 8, 53, 67, -63, 9, 49, 10, 49),
-	CABAC_ENTRY(189, -1, 82, 44, -5, 19, 58, 30, 34),
-	CABAC_ENTRY(190, 7, 55, 32, 7, 10, 48, 18, 42),
-	CABAC_ENTRY(191, -3, 78, 55, -29, 12, 45, 10, 55),
-	CABAC_ENTRY(192, 15, 46, 32, 1, 0, 69, 17, 51),
-	CABAC_ENTRY(193, 22, 31, 0, 0, 20, 33, 17, 46),
-	CABAC_ENTRY(194, -1, 84, 27, 36, 8, 63, 0, 89),
-	CABAC_ENTRY(195, 25, 7, 33, -25, 35, -18, 26, -19),
-	CABAC_ENTRY(196, 30, -7, 34, -30, 33, -25, 22, -17),
-	CABAC_ENTRY(197, 28, 3, 36, -28, 28, -3, 26, -17),
-	CABAC_ENTRY(198, 28, 4, 38, -28, 24, 10, 30, -25),
-	CABAC_ENTRY(199, 32, 0, 38, -27, 27, 0, 28, -20),
-	CABAC_ENTRY(200, 34, -1, 34, -18, 34, -14, 33, -23),
-	CABAC_ENTRY(201, 30, 6, 35, -16, 52, -44, 37, -27),
-	CABAC_ENTRY(202, 30, 6, 34, -14, 39, -24, 33, -23),
-	CABAC_ENTRY(203, 32, 9, 32, -8, 19, 17, 40, -28),
-	CABAC_ENTRY(204, 31, 19, 37, -6, 31, 25, 38, -17),
-	CABAC_ENTRY(205, 26, 27, 35, 0, 36, 29, 33, -11),
-	CABAC_ENTRY(206, 26, 30, 30, 10, 24, 33, 40, -15),
-	CABAC_ENTRY(207, 37, 20, 28, 18, 34, 15, 41, -6),
-	CABAC_ENTRY(208, 28, 34, 26, 25, 30, 20, 38, 1),
-	CABAC_ENTRY(209, 17, 70, 29, 41, 22, 73, 41, 17),
-	CABAC_ENTRY(210, 1, 67, 0, 75, 20, 34, 30, -6),
-	CABAC_ENTRY(211, 5, 59, 2, 72, 19, 31, 27, 3),
-	CABAC_ENTRY(212, 9, 67, 8, 77, 27, 44, 26, 22),
-	CABAC_ENTRY(213, 16, 30, 14, 35, 19, 16, 37, -16),
-	CABAC_ENTRY(214, 18, 32, 18, 31, 15, 36, 35, -4),
-	CABAC_ENTRY(215, 18, 35, 17, 35, 15, 36, 38, -8),
-	CABAC_ENTRY(216, 22, 29, 21, 30, 21, 28, 38, -3),
-	CABAC_ENTRY(217, 24, 31, 17, 45, 25, 21, 37, 3),
-	CABAC_ENTRY(218, 23, 38, 20, 42, 30, 20, 38, 5),
-	CABAC_ENTRY(219, 18, 43, 18, 45, 31, 12, 42, 0),
-	CABAC_ENTRY(220, 20, 41, 27, 26, 27, 16, 35, 16),
-	CABAC_ENTRY(221, 11, 63, 16, 54, 24, 42, 39, 22),
-	CABAC_ENTRY(222, 9, 59, 7, 66, 0, 93, 14, 48),
-	CABAC_ENTRY(223, 9, 64, 16, 56, 14, 56, 27, 37),
-	CABAC_ENTRY(224, -1, 94, 11, 73, 15, 57, 21, 60),
-	CABAC_ENTRY(225, -2, 89, 10, 67, 26, 38, 12, 68),
-	CABAC_ENTRY(226, -9, 108, -10, 116, -24, 127, 2, 97),
-
-	/* Table 9-21 ? Values of variables m and n for ctxIdx from 227 to 275 */
-	CABAC_ENTRY(227, -6, 76, -23, 112, -24, 115, -3, 71),
-	CABAC_ENTRY(228, -2, 44, -15, 71, -22, 82, -6, 42),
-	CABAC_ENTRY(229, 0, 45, -7, 61, -9, 62, -5, 50),
-	CABAC_ENTRY(230, 0, 52, 0, 53, 0, 53, -3, 54),
-	CABAC_ENTRY(231, -3, 64, -5, 66, 0, 59, -2, 62),
-	CABAC_ENTRY(232, -2, 59, -11, 77, -14, 85, 0, 58),
-	CABAC_ENTRY(233, -4, 70, -9, 80, -13, 89, 1, 63),
-	CABAC_ENTRY(234, -4, 75, -9, 84, -13, 94, -2, 72),
-	CABAC_ENTRY(235, -8, 82, -10, 87, -11, 92, -1, 74),
-	CABAC_ENTRY(236, -17, 102, -34, 127, -29, 127, -9, 91),
-	CABAC_ENTRY(237, -9, 77, -21, 101, -21, 100, -5, 67),
-	CABAC_ENTRY(238, 3, 24, -3, 39, -14, 57, -5, 27),
-	CABAC_ENTRY(239, 0, 42, -5, 53, -12, 67, -3, 39),
-	CABAC_ENTRY(240, 0, 48, -7, 61, -11, 71, -2, 44),
-	CABAC_ENTRY(241, 0, 55, -11, 75, -10, 77, 0, 46),
-	CABAC_ENTRY(242, -6, 59, -15, 77, -21, 85, -16, 64),
-	CABAC_ENTRY(243, -7, 71, -17, 91, -16, 88, -8, 68),
-	CABAC_ENTRY(244, -12, 83, -25, 107, -23, 104, -10, 78),
-	CABAC_ENTRY(245, -11, 87, -25, 111, -15, 98, -6, 77),
-	CABAC_ENTRY(246, -30, 119, -28, 122, -37, 127, -10, 86),
-	CABAC_ENTRY(247, 1, 58, -11, 76, -10, 82, -12, 92),
-	CABAC_ENTRY(248, -3, 29, -10, 44, -8, 48, -15, 55),
-	CABAC_ENTRY(249, -1, 36, -10, 52, -8, 61, -10, 60),
-	CABAC_ENTRY(250, 1, 38, -10, 57, -8, 66, -6, 62),
-	CABAC_ENTRY(251, 2, 43, -9, 58, -7, 70, -4, 65),
-	CABAC_ENTRY(252, -6, 55, -16, 72, -14, 75, -12, 73),
-	CABAC_ENTRY(253, 0, 58, -7, 69, -10, 79, -8, 76),
-	CABAC_ENTRY(254, 0, 64, -4, 69, -9, 83, -7, 80),
-	CABAC_ENTRY(255, -3, 74, -5, 74, -12, 92, -9, 88),
-	CABAC_ENTRY(256, -10, 90, -9, 86, -18, 108, -17, 110),
-	CABAC_ENTRY(257, 0, 70, 2, 66, -4, 79, -11, 97),
-	CABAC_ENTRY(258, -4, 29, -9, 34, -22, 69, -20, 84),
-	CABAC_ENTRY(259, 5, 31, 1, 32, -16, 75, -11, 79),
-	CABAC_ENTRY(260, 7, 42, 11, 31, -2, 58, -6, 73),
-	CABAC_ENTRY(261, 1, 59, 5, 52, 1, 58, -4, 74),
-	CABAC_ENTRY(262, -2, 58, -2, 55, -13, 78, -13, 86),
-	CABAC_ENTRY(263, -3, 72, -2, 67, -9, 83, -13, 96),
-	CABAC_ENTRY(264, -3, 81, 0, 73, -4, 81, -11, 97),
-	CABAC_ENTRY(265, -11, 97, -8, 89, -13, 99, -19, 117),
-	CABAC_ENTRY(266, 0, 58, 3, 52, -13, 81, -8, 78),
-	CABAC_ENTRY(267, 8, 5, 7, 4, -6, 38, -5, 33),
-	CABAC_ENTRY(268, 10, 14, 10, 8, -13, 62, -4, 48),
-	CABAC_ENTRY(269, 14, 18, 17, 8, -6, 58, -2, 53),
-	CABAC_ENTRY(270, 13, 27, 16, 19, -2, 59, -3, 62),
-	CABAC_ENTRY(271, 2, 40, 3, 37, -16, 73, -13, 71),
-	CABAC_ENTRY(272, 0, 58, -1, 61, -10, 76, -10, 79),
-	CABAC_ENTRY(273, -3, 70, -5, 73, -13, 86, -12, 86),
-	CABAC_ENTRY(274, -6, 79, -1, 70, -9, 83, -13, 90),
-	CABAC_ENTRY(275, -8, 85, -4, 78, -10, 87, -14, 97),
-
-	/* Table 9-22 ? Values of variables m and n for ctxIdx from 277 to 337 */
-	CABAC_ENTRY(277, -13, 106, -21, 126, -22, 127, -6, 93),
-	CABAC_ENTRY(278, -16, 106, -23, 124, -25, 127, -6, 84),
-	CABAC_ENTRY(279, -10, 87, -20, 110, -25, 120, -8, 79),
-	CABAC_ENTRY(280, -21, 114, -26, 126, -27, 127, 0, 66),
-	CABAC_ENTRY(281, -18, 110, -25, 124, -19, 114, -1, 71),
-	CABAC_ENTRY(282, -14, 98, -17, 105, -23, 117, 0, 62),
-	CABAC_ENTRY(283, -22, 110, -27, 121, -25, 118, -2, 60),
-	CABAC_ENTRY(284, -21, 106, -27, 117, -26, 117, -2, 59),
-	CABAC_ENTRY(285, -18, 103, -17, 102, -24, 113, -5, 75),
-	CABAC_ENTRY(286, -21, 107, -26, 117, -28, 118, -3, 62),
-	CABAC_ENTRY(287, -23, 108, -27, 116, -31, 120, -4, 58),
-	CABAC_ENTRY(288, -26, 112, -33, 122, -37, 124, -9, 66),
-	CABAC_ENTRY(289, -10, 96, -10, 95, -10, 94, -1, 79),
-	CABAC_ENTRY(290, -12, 95, -14, 100, -15, 102, 0, 71),
-	CABAC_ENTRY(291, -5, 91, -8, 95, -10, 99, 3, 68),
-	CABAC_ENTRY(292, -9, 93, -17, 111, -13, 106, 10, 44),
-	CABAC_ENTRY(293, -22, 94, -28, 114, -50, 127, -7, 62),
-	CABAC_ENTRY(294, -5, 86, -6, 89, -5, 92, 15, 36),
-	CABAC_ENTRY(295, 9, 67, -2, 80, 17, 57, 14, 40),
-	CABAC_ENTRY(296, -4, 80, -4, 82, -5, 86, 16, 27),
-	CABAC_ENTRY(297, -10, 85, -9, 85, -13, 94, 12, 29),
-	CABAC_ENTRY(298, -1, 70, -8, 81, -12, 91, 1, 44),
-	CABAC_ENTRY(299, 7, 60, -1, 72, -2, 77, 20, 36),
-	CABAC_ENTRY(300, 9, 58, 5, 64, 0, 71, 18, 32),
-	CABAC_ENTRY(301, 5, 61, 1, 67, -1, 73, 5, 42),
-	CABAC_ENTRY(302, 12, 50, 9, 56, 4, 64, 1, 48),
-	CABAC_ENTRY(303, 15, 50, 0, 69, -7, 81, 10, 62),
-	CABAC_ENTRY(304, 18, 49, 1, 69, 5, 64, 17, 46),
-	CABAC_ENTRY(305, 17, 54, 7, 69, 15, 57, 9, 64),
-	CABAC_ENTRY(306, 10, 41, -7, 69, 1, 67, -12, 104),
-	CABAC_ENTRY(307, 7, 46, -6, 67, 0, 68, -11, 97),
-	CABAC_ENTRY(308, -1, 51, -16, 77, -10, 67, -16, 96),
-	CABAC_ENTRY(309, 7, 49, -2, 64, 1, 68, -7, 88),
-	CABAC_ENTRY(310, 8, 52, 2, 61, 0, 77, -8, 85),
-	CABAC_ENTRY(311, 9, 41, -6, 67, 2, 64, -7, 85),
-	CABAC_ENTRY(312, 6, 47, -3, 64, 0, 68, -9, 85),
-	CABAC_ENTRY(313, 2, 55, 2, 57, -5, 78, -13, 88),
-	CABAC_ENTRY(314, 13, 41, -3, 65, 7, 55, 4, 66),
-	CABAC_ENTRY(315, 10, 44, -3, 66, 5, 59, -3, 77),
-	CABAC_ENTRY(316, 6, 50, 0, 62, 2, 65, -3, 76),
-	CABAC_ENTRY(317, 5, 53, 9, 51, 14, 54, -6, 76),
-	CABAC_ENTRY(318, 13, 49, -1, 66, 15, 44, 10, 58),
-	CABAC_ENTRY(319, 4, 63, -2, 71, 5, 60, -1, 76),
-	CABAC_ENTRY(320, 6, 64, -2, 75, 2, 70, -1, 83),
-	CABAC_ENTRY(321, -2, 69, -1, 70, -2, 76, -7, 99),
-	CABAC_ENTRY(322, -2, 59, -9, 72, -18, 86, -14, 95),
-	CABAC_ENTRY(323, 6, 70, 14, 60, 12, 70, 2, 95),
-	CABAC_ENTRY(324, 10, 44, 16, 37, 5, 64, 0, 76),
-	CABAC_ENTRY(325, 9, 31, 0, 47, -12, 70, -5, 74),
-	CABAC_ENTRY(326, 12, 43, 18, 35, 11, 55, 0, 70),
-	CABAC_ENTRY(327, 3, 53, 11, 37, 5, 56, -11, 75),
-	CABAC_ENTRY(328, 14, 34, 12, 41, 0, 69, 1, 68),
-	CABAC_ENTRY(329, 10, 38, 10, 41, 2, 65, 0, 65),
-	CABAC_ENTRY(330, -3, 52, 2, 48, -6, 74, -14, 73),
-	CABAC_ENTRY(331, 13, 40, 12, 41, 5, 54, 3, 62),
-	CABAC_ENTRY(332, 17, 32, 13, 41, 7, 54, 4, 62),
-	CABAC_ENTRY(333, 7, 44, 0, 59, -6, 76, -1, 68),
-	CABAC_ENTRY(334, 7, 38, 3, 50, -11, 82, -13, 75),
-	CABAC_ENTRY(335, 13, 50, 19, 40, -2, 77, 11, 55),
-	CABAC_ENTRY(336, 10, 57, 3, 66, -2, 77, 5, 64),
-	CABAC_ENTRY(337, 26, 43, 18, 50, 25, 42, 12, 70),
-
-	/* Table 9-23 ? Values of variables m and n for ctxIdx from 338 to 398 */
-	CABAC_ENTRY(338, 14, 11, 19, -6, 17, -13, 15, 6),
-	CABAC_ENTRY(339, 11, 14, 18, -6, 16, -9, 6, 19),
-	CABAC_ENTRY(340, 9, 11, 14, 0, 17, -12, 7, 16),
-	CABAC_ENTRY(341, 18, 11, 26, -12, 27, -21, 12, 14),
-	CABAC_ENTRY(342, 21, 9, 31, -16, 37, -30, 18, 13),
-	CABAC_ENTRY(343, 23, -2, 33, -25, 41, -40, 13, 11),
-	CABAC_ENTRY(344, 32, -15, 33, -22, 42, -41, 13, 15),
-	CABAC_ENTRY(345, 32, -15, 37, -28, 48, -47, 15, 16),
-	CABAC_ENTRY(346, 34, -21, 39, -30, 39, -32, 12, 23),
-	CABAC_ENTRY(347, 39, -23, 42, -30, 46, -40, 13, 23),
-	CABAC_ENTRY(348, 42, -33, 47, -42, 52, -51, 15, 20),
-	CABAC_ENTRY(349, 41, -31, 45, -36, 46, -41, 14, 26),
-	CABAC_ENTRY(350, 46, -28, 49, -34, 52, -39, 14, 44),
-	CABAC_ENTRY(351, 38, -12, 41, -17, 43, -19, 17, 40),
-	CABAC_ENTRY(352, 21, 29, 32, 9, 32, 11, 17, 47),
-	CABAC_ENTRY(353, 45, -24, 69, -71, 61, -55, 24, 17),
-	CABAC_ENTRY(354, 53, -45, 63, -63, 56, -46, 21, 21),
-	CABAC_ENTRY(355, 48, -26, 66, -64, 62, -50, 25, 22),
-	CABAC_ENTRY(356, 65, -43, 77, -74, 81, -67, 31, 27),
-	CABAC_ENTRY(357, 43, -19, 54, -39, 45, -20, 22, 29),
-	CABAC_ENTRY(358, 39, -10, 52, -35, 35, -2, 19, 35),
-	CABAC_ENTRY(359, 30, 9, 41, -10, 28, 15, 14, 50),
-	CABAC_ENTRY(360, 18, 26, 36, 0, 34, 1, 10, 57),
-	CABAC_ENTRY(361, 20, 27, 40, -1, 39, 1, 7, 63),
-	CABAC_ENTRY(362, 0, 57, 30, 14, 30, 17, -2, 77),
-	CABAC_ENTRY(363, -14, 82, 28, 26, 20, 38, -4, 82),
-	CABAC_ENTRY(364, -5, 75, 23, 37, 18, 45, -3, 94),
-	CABAC_ENTRY(365, -19, 97, 12, 55, 15, 54, 9, 69),
-	CABAC_ENTRY(366, -35, 125, 11, 65, 0, 79, -12, 109),
-	CABAC_ENTRY(367, 27, 0, 37, -33, 36, -16, 36, -35),
-	CABAC_ENTRY(368, 28, 0, 39, -36, 37, -14, 36, -34),
-	CABAC_ENTRY(369, 31, -4, 40, -37, 37, -17, 32, -26),
-	CABAC_ENTRY(370, 27, 6, 38, -30, 32, 1, 37, -30),
-	CABAC_ENTRY(371, 34, 8, 46, -33, 34, 15, 44, -32),
-	CABAC_ENTRY(372, 30, 10, 42, -30, 29, 15, 34, -18),
-	CABAC_ENTRY(373, 24, 22, 40, -24, 24, 25, 34, -15),
-	CABAC_ENTRY(374, 33, 19, 49, -29, 34, 22, 40, -15),
-	CABAC_ENTRY(375, 22, 32, 38, -12, 31, 16, 33, -7),
-	CABAC_ENTRY(376, 26, 31, 40, -10, 35, 18, 35, -5),
-	CABAC_ENTRY(377, 21, 41, 38, -3, 31, 28, 33, 0),
-	CABAC_ENTRY(378, 26, 44, 46, -5, 33, 41, 38, 2),
-	CABAC_ENTRY(379, 23, 47, 31, 20, 36, 28, 33, 13),
-	CABAC_ENTRY(380, 16, 65, 29, 30, 27, 47, 23, 35),
-	CABAC_ENTRY(381, 14, 71, 25, 44, 21, 62, 13, 58),
-	CABAC_ENTRY(382, 8, 60, 12, 48, 18, 31, 29, -3),
-	CABAC_ENTRY(383, 6, 63, 11, 49, 19, 26, 26, 0),
-	CABAC_ENTRY(384, 17, 65, 26, 45, 36, 24, 22, 30),
-	CABAC_ENTRY(385, 21, 24, 22, 22, 24, 23, 31, -7),
-	CABAC_ENTRY(386, 23, 20, 23, 22, 27, 16, 35, -15),
-	CABAC_ENTRY(387, 26, 23, 27, 21, 24, 30, 34, -3),
-	CABAC_ENTRY(388, 27, 32, 33, 20, 31, 29, 34, 3),
-	CABAC_ENTRY(389, 28, 23, 26, 28, 22, 41, 36, -1),
-	CABAC_ENTRY(390, 28, 24, 30, 24, 22, 42, 34, 5),
-	CABAC_ENTRY(391, 23, 40, 27, 34, 16, 60, 32, 11),
-	CABAC_ENTRY(392, 24, 32, 18, 42, 15, 52, 35, 5),
-	CABAC_ENTRY(393, 28, 29, 25, 39, 14, 60, 34, 12),
-	CABAC_ENTRY(394, 23, 42, 18, 50, 3, 78, 39, 11),
-	CABAC_ENTRY(395, 19, 57, 12, 70, -16, 123, 30, 29),
-	CABAC_ENTRY(396, 22, 53, 21, 54, 21, 53, 34, 26),
-	CABAC_ENTRY(397, 22, 61, 14, 71, 22, 56, 29, 39),
-	CABAC_ENTRY(398, 11, 86, 11, 83, 25, 61, 19, 66),
-
-	/* Values of variables m and n for ctxIdx from 399 to 463 (not documented) */
-	CABAC_ENTRY(399, 12, 40, 25, 32, 21, 33, 31, 21),
-	CABAC_ENTRY(400, 11, 51, 21, 49, 19, 50, 31, 31),
-	CABAC_ENTRY(401, 14, 59, 21, 54, 17, 61, 25, 50),
-	CABAC_ENTRY(402, -4, 79, -5, 85, -3, 78, -17, 120),
-	CABAC_ENTRY(403, -7, 71, -6, 81, -8, 74, -20, 112),
-	CABAC_ENTRY(404, -5, 69, -10, 77, -9, 72, -18, 114),
-	CABAC_ENTRY(405, -9, 70, -7, 81, -10, 72, -11, 85),
-	CABAC_ENTRY(406, -8, 66, -17, 80, -18, 75, -15, 92),
-	CABAC_ENTRY(407, -10, 68, -18, 73, -12, 71, -14, 89),
-	CABAC_ENTRY(408, -19, 73, -4, 74, -11, 63, -26, 71),
-	CABAC_ENTRY(409, -12, 69, -10, 83, -5, 70, -15, 81),
-	CABAC_ENTRY(410, -16, 70, -9, 71, -17, 75, -14, 80),
-	CABAC_ENTRY(411, -15, 67, -9, 67, -14, 72, 0, 68),
-	CABAC_ENTRY(412, -20, 62, -1, 61, -16, 67, -14, 70),
-	CABAC_ENTRY(413, -19, 70, -8, 66, -8, 53, -24, 56),
-	CABAC_ENTRY(414, -16, 66, -14, 66, -14, 59, -23, 68),
-	CABAC_ENTRY(415, -22, 65, 0, 59, -9, 52, -24, 50),
-	CABAC_ENTRY(416, -20, 63, 2, 59, -11, 68, -11, 74),
-	CABAC_ENTRY(417, 9, -2, 17, -10, 9, -2, 23, -13),
-	CABAC_ENTRY(418, 26, -9, 32, -13, 30, -10, 26, -13),
-	CABAC_ENTRY(419, 33, -9, 42, -9, 31, -4, 40, -15),
-	CABAC_ENTRY(420, 39, -7, 49, -5, 33, -1, 49, -14),
-	CABAC_ENTRY(421, 41, -2, 53, 0, 33, 7, 44, 3),
-	CABAC_ENTRY(422, 45, 3, 64, 3, 31, 12, 45, 6),
-	CABAC_ENTRY(423, 49, 9, 68, 10, 37, 23, 44, 34),
-	CABAC_ENTRY(424, 45, 27, 66, 27, 31, 38, 33, 54),
-	CABAC_ENTRY(425, 36, 59, 47, 57, 20, 64, 19, 82),
-	CABAC_ENTRY(426, -6, 66, -5, 71, -9, 71, -3, 75),
-	CABAC_ENTRY(427, -7, 35, 0, 24, -7, 37, -1, 23),
-	CABAC_ENTRY(428, -7, 42, -1, 36, -8, 44, 1, 34),
-	CABAC_ENTRY(429, -8, 45, -2, 42, -11, 49, 1, 43),
-	CABAC_ENTRY(430, -5, 48, -2, 52, -10, 56, 0, 54),
-	CABAC_ENTRY(431, -12, 56, -9, 57, -12, 59, -2, 55),
-	CABAC_ENTRY(432, -6, 60, -6, 63, -8, 63, 0, 61),
-	CABAC_ENTRY(433, -5, 62, -4, 65, -9, 67, 1, 64),
-	CABAC_ENTRY(434, -8, 66, -4, 67, -6, 68, 0, 68),
-	CABAC_ENTRY(435, -8, 76, -7, 82, -10, 79, -9, 92),
-	CABAC_ENTRY(436, -5, 85, -3, 81, -3, 78, -14, 106),
-	CABAC_ENTRY(437, -6, 81, -3, 76, -8, 74, -13, 97),
-	CABAC_ENTRY(438, -10, 77, -7, 72, -9, 72, -15, 90),
-	CABAC_ENTRY(439, -7, 81, -6, 78, -10, 72, -12, 90),
-	CABAC_ENTRY(440, -17, 80, -12, 72, -18, 75, -18, 88),
-	CABAC_ENTRY(441, -18, 73, -14, 68, -12, 71, -10, 73),
-	CABAC_ENTRY(442, -4, 74, -3, 70, -11, 63, -9, 79),
-	CABAC_ENTRY(443, -10, 83, -6, 76, -5, 70, -14, 86),
-	CABAC_ENTRY(444, -9, 71, -5, 66, -17, 75, -10, 73),
-	CABAC_ENTRY(445, -9, 67, -5, 62, -14, 72, -10, 70),
-	CABAC_ENTRY(446, -1, 61, 0, 57, -16, 67, -10, 69),
-	CABAC_ENTRY(447, -8, 66, -4, 61, -8, 53, -5, 66),
-	CABAC_ENTRY(448, -14, 66, -9, 60, -14, 59, -9, 64),
-	CABAC_ENTRY(449, 0, 59, 1, 54, -9, 52, -5, 58),
-	CABAC_ENTRY(450, 2, 59, 2, 58, -11, 68, 2, 59),
-	CABAC_ENTRY(451, 21, -13, 17, -10, 9, -2, 21, -10),
-	CABAC_ENTRY(452, 33, -14, 32, -13, 30, -10, 24, -11),
-	CABAC_ENTRY(453, 39, -7, 42, -9, 31, -4, 28, -8),
-	CABAC_ENTRY(454, 46, -2, 49, -5, 33, -1, 28, -1),
-	CABAC_ENTRY(455, 51, 2, 53, 0, 33, 7, 29, 3),
-	CABAC_ENTRY(456, 60, 6, 64, 3, 31, 12, 29, 9),
-	CABAC_ENTRY(457, 61, 17, 68, 10, 37, 23, 35, 20),
-	CABAC_ENTRY(458, 55, 34, 66, 27, 31, 38, 29, 36),
-	CABAC_ENTRY(459, 42, 62, 47, 57, 20, 64, 14, 67),
-};
-
 static void set_ps_field(u32 *buf, struct rkvdec_ps_field field, u32 value)
 {
 	u8 bit = field.offset % 32, word = field.offset / 32;
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
index 01f92fa27356..b01c1bb52a04 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
@@ -16,7 +16,6 @@
 
 #include "rkvdec.h"
 #include "rkvdec-regs.h"
-#include "rkvdec-hevc-data.c"
 
 /* Size in u8/u32 units. */
 #define RKV_SCALING_LIST_SIZE		1360
@@ -25,6 +24,9 @@
 #define RKV_RPS_SIZE			(32 / 4)
 #define RKV_RPS_LEN			600
 
+#define RKV_HEVC_CABAC_TABLE_SIZE		27456
+extern const u8 rkvdec_hevc_cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
+
 struct rkvdec_sps_pps_packet {
 	u32 info[RKV_PPS_SIZE];
 };
@@ -110,7 +112,7 @@ struct rkvdec_ps_field {
 
 /* Data structure describing auxiliary buffer format. */
 struct rkvdec_hevc_priv_tbl {
-	u8 cabac_table[RKV_CABAC_TABLE_SIZE];
+	u8 cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
 	u8 scaling_list[RKV_SCALING_LIST_SIZE];
 	struct rkvdec_sps_pps_packet param_set[RKV_PPS_LEN];
 	struct rkvdec_rps_packet rps[RKV_RPS_LEN];
-- 
2.52.0



From detlev.casanova at collabora.com  Wed Dec 17 09:40:43 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 17 Dec 2025 12:40:43 -0500
Subject: [PATCH v6 06/17] media: rkvdec: Use structs to represent the HW RPS
In-Reply-To: <20251217174059.1341784-1-detlev.casanova@collabora.com>
References: <20251217174059.1341784-1-detlev.casanova@collabora.com>
Message-ID: <20251217174059.1341784-7-detlev.casanova@collabora.com>

This is in preparation to add support for other variants of the decoder.

Moving to struct representation is mainly to prepare for multicore
support that is present in e.g. rk3588.

Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../platform/rockchip/rkvdec/rkvdec-h264.c    | 93 +++++++++++++++++--
 1 file changed, 84 insertions(+), 9 deletions(-)

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
index 989379ae3a73..cb17dfcae5ca 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
@@ -19,7 +19,6 @@ extern const s8 rkvdec_h264_cabac_table[4][464][2];
 
 /* Size with u32 units. */
 #define RKV_CABAC_INIT_BUFFER_SIZE	(3680 + 128)
-#define RKV_RPS_SIZE			((128 + 128) / 4)
 #define RKV_ERROR_INFO_SIZE		(256 * 144 * 4)
 
 #define RKVDEC_NUM_REFLIST		3
@@ -34,6 +33,40 @@ struct rkvdec_sps_pps_packet {
 	u32 info[8];
 };
 
+struct rkvdec_rps_entry {
+	u32 dpb_info0:          5;
+	u32 bottom_flag0:       1;
+	u32 view_index_off0:    1;
+	u32 dpb_info1:          5;
+	u32 bottom_flag1:       1;
+	u32 view_index_off1:    1;
+	u32 dpb_info2:          5;
+	u32 bottom_flag2:       1;
+	u32 view_index_off2:    1;
+	u32 dpb_info3:          5;
+	u32 bottom_flag3:       1;
+	u32 view_index_off3:    1;
+	u32 dpb_info4:          5;
+	u32 bottom_flag4:       1;
+	u32 view_index_off4:    1;
+	u32 dpb_info5:          5;
+	u32 bottom_flag5:       1;
+	u32 view_index_off5:    1;
+	u32 dpb_info6:          5;
+	u32 bottom_flag6:       1;
+	u32 view_index_off6:    1;
+	u32 dpb_info7:          5;
+	u32 bottom_flag7:       1;
+	u32 view_index_off7:    1;
+} __packed;
+
+struct rkvdec_rps {
+	u16 frame_num[16];
+	u32 reserved0;
+	struct rkvdec_rps_entry entries[12];
+	u32 reserved1[66];
+} __packed;
+
 struct rkvdec_ps_field {
 	u16 offset;
 	u8 len;
@@ -94,7 +127,7 @@ struct rkvdec_ps_field {
 struct rkvdec_h264_priv_tbl {
 	s8 cabac_table[4][464][2];
 	struct rkvdec_h264_scaling_list scaling_list;
-	u32 rps[RKV_RPS_SIZE];
+	struct rkvdec_rps rps;
 	struct rkvdec_sps_pps_packet param_set[256];
 	u8 err_info[RKV_ERROR_INFO_SIZE];
 };
@@ -260,6 +293,51 @@ static void lookup_ref_buf_idx(struct rkvdec_ctx *ctx,
 	}
 }
 
+static void set_dpb_info(struct rkvdec_rps_entry *entries,
+			 u8 reflist,
+			 u8 refnum,
+			 u8 info,
+			 bool bottom)
+{
+	struct rkvdec_rps_entry *entry = &entries[(reflist * 4) + refnum / 8];
+	u8 idx = refnum % 8;
+
+	switch (idx) {
+	case 0:
+		entry->dpb_info0 = info;
+		entry->bottom_flag0 = bottom;
+		break;
+	case 1:
+		entry->dpb_info1 = info;
+		entry->bottom_flag1 = bottom;
+		break;
+	case 2:
+		entry->dpb_info2 = info;
+		entry->bottom_flag2 = bottom;
+		break;
+	case 3:
+		entry->dpb_info3 = info;
+		entry->bottom_flag3 = bottom;
+		break;
+	case 4:
+		entry->dpb_info4 = info;
+		entry->bottom_flag4 = bottom;
+		break;
+	case 5:
+		entry->dpb_info5 = info;
+		entry->bottom_flag5 = bottom;
+		break;
+	case 6:
+		entry->dpb_info6 = info;
+		entry->bottom_flag6 = bottom;
+		break;
+	case 7:
+		entry->dpb_info7 = info;
+		entry->bottom_flag7 = bottom;
+		break;
+	}
+}
+
 static void assemble_hw_rps(struct rkvdec_ctx *ctx,
 			    struct v4l2_h264_reflist_builder *builder,
 			    struct rkvdec_h264_run *run)
@@ -269,11 +347,10 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx,
 	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
 	struct rkvdec_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu;
 
-	u32 *hw_rps = priv_tbl->rps;
+	struct rkvdec_rps *hw_rps = &priv_tbl->rps;
 	u32 i, j;
-	u16 *p = (u16 *)hw_rps;
 
-	memset(hw_rps, 0, sizeof(priv_tbl->rps));
+	memset(hw_rps, 0, sizeof(*hw_rps));
 
 	/*
 	 * Assign an invalid pic_num if DPB entry at that position is inactive.
@@ -285,7 +362,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx,
 		if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
 			continue;
 
-		p[i] = builder->refs[i].frame_num;
+		hw_rps->frame_num[i] = builder->refs[i].frame_num;
 	}
 
 	for (j = 0; j < RKVDEC_NUM_REFLIST; j++) {
@@ -312,9 +389,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx,
 			dpb_valid = run->ref_buf[ref->index] != NULL;
 			bottom = ref->fields == V4L2_H264_BOTTOM_FIELD_REF;
 
-			set_ps_field(hw_rps, DPB_INFO(i, j),
-				     ref->index | dpb_valid << 4);
-			set_ps_field(hw_rps, BOTTOM_FLAG(i, j), bottom);
+			set_dpb_info(hw_rps->entries, j, i, ref->index | (dpb_valid << 4), bottom);
 		}
 	}
 }
-- 
2.52.0



From detlev.casanova at collabora.com  Wed Dec 17 09:40:44 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 17 Dec 2025 12:40:44 -0500
Subject: [PATCH v6 07/17] media: rkvdec: Move h264 functions to common file
In-Reply-To: <20251217174059.1341784-1-detlev.casanova@collabora.com>
References: <20251217174059.1341784-1-detlev.casanova@collabora.com>
Message-ID: <20251217174059.1341784-8-detlev.casanova@collabora.com>

This is a preparation commit to add support for new variants of the
decoder.

The functions will later be shared with vdpu381 (rk3588) and vdpu383
(rk3576).

Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../media/platform/rockchip/rkvdec/Makefile   |   1 +
 .../rockchip/rkvdec/rkvdec-h264-common.c      | 258 +++++++++++++++
 .../rockchip/rkvdec/rkvdec-h264-common.h      |  87 +++++
 .../platform/rockchip/rkvdec/rkvdec-h264.c    | 310 +-----------------
 4 files changed, 350 insertions(+), 306 deletions(-)
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.c
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h

diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
index a8ff5e3d7bec..d2ba7a7c15e5 100644
--- a/drivers/media/platform/rockchip/rkvdec/Makefile
+++ b/drivers/media/platform/rockchip/rkvdec/Makefile
@@ -4,5 +4,6 @@ rockchip-vdec-y += \
 		   rkvdec.o \
 		   rkvdec-cabac.o \
 		   rkvdec-h264.o \
+		   rkvdec-h264-common.o \
 		   rkvdec-hevc.o \
 		   rkvdec-vp9.o
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.c
new file mode 100644
index 000000000000..e28f06394470
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.c
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip video decoder h264 common functions
+ *
+ * Copyright (C) 2025 Collabora, Ltd.
+ *	Detlev Casanova <detlev.casanova at collabora.com>
+ *
+ * Copyright (C) 2019 Collabora, Ltd.
+ *	Boris Brezillon <boris.brezillon at collabora.com>
+ *
+ * Copyright (C) 2016 Rockchip Electronics Co., Ltd.
+ *	Jeffy Chen <jeffy.chen at rock-chips.com>
+ */
+
+#include <linux/v4l2-common.h>
+#include <media/v4l2-h264.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "rkvdec.h"
+#include "rkvdec-h264-common.h"
+
+#define RKVDEC_NUM_REFLIST		3
+
+static void set_dpb_info(struct rkvdec_rps_entry *entries,
+			 u8 reflist,
+			 u8 refnum,
+			 u8 info,
+			 bool bottom)
+{
+	struct rkvdec_rps_entry *entry = &entries[(reflist * 4) + refnum / 8];
+	u8 idx = refnum % 8;
+
+	switch (idx) {
+	case 0:
+		entry->dpb_info0 = info;
+		entry->bottom_flag0 = bottom;
+		break;
+	case 1:
+		entry->dpb_info1 = info;
+		entry->bottom_flag1 = bottom;
+		break;
+	case 2:
+		entry->dpb_info2 = info;
+		entry->bottom_flag2 = bottom;
+		break;
+	case 3:
+		entry->dpb_info3 = info;
+		entry->bottom_flag3 = bottom;
+		break;
+	case 4:
+		entry->dpb_info4 = info;
+		entry->bottom_flag4 = bottom;
+		break;
+	case 5:
+		entry->dpb_info5 = info;
+		entry->bottom_flag5 = bottom;
+		break;
+	case 6:
+		entry->dpb_info6 = info;
+		entry->bottom_flag6 = bottom;
+		break;
+	case 7:
+		entry->dpb_info7 = info;
+		entry->bottom_flag7 = bottom;
+		break;
+	}
+}
+
+void lookup_ref_buf_idx(struct rkvdec_ctx *ctx,
+			struct rkvdec_h264_run *run)
+{
+	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
+	u32 i;
+
+	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
+		struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
+		const struct v4l2_h264_dpb_entry *dpb = run->decode_params->dpb;
+		struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q;
+		struct vb2_buffer *buf = NULL;
+
+		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) {
+			buf = vb2_find_buffer(cap_q, dpb[i].reference_ts);
+			if (!buf)
+				pr_debug("No buffer for reference_ts %llu",
+					 dpb[i].reference_ts);
+		}
+
+		run->ref_buf[i] = buf;
+	}
+}
+
+void assemble_hw_rps(struct v4l2_h264_reflist_builder *builder,
+		     struct rkvdec_h264_run *run,
+		     struct rkvdec_h264_reflists *reflists,
+		     struct rkvdec_rps *hw_rps)
+{
+	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
+	const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb;
+
+	u32 i, j;
+
+	memset(hw_rps, 0, sizeof(*hw_rps));
+
+	/*
+	 * Assign an invalid pic_num if DPB entry at that position is inactive.
+	 * If we assign 0 in that position hardware will treat that as a real
+	 * reference picture with pic_num 0, triggering output picture
+	 * corruption.
+	 */
+	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
+		if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
+			continue;
+
+		hw_rps->frame_num[i] = builder->refs[i].frame_num;
+	}
+
+	for (j = 0; j < RKVDEC_NUM_REFLIST; j++) {
+		for (i = 0; i < builder->num_valid; i++) {
+			struct v4l2_h264_reference *ref;
+			bool dpb_valid;
+			bool bottom;
+
+			switch (j) {
+			case 0:
+				ref = &reflists->p[i];
+				break;
+			case 1:
+				ref = &reflists->b0[i];
+				break;
+			case 2:
+				ref = &reflists->b1[i];
+				break;
+			}
+
+			if (WARN_ON(ref->index >= ARRAY_SIZE(dec_params->dpb)))
+				continue;
+
+			dpb_valid = !!(run->ref_buf[ref->index]);
+			bottom = ref->fields == V4L2_H264_BOTTOM_FIELD_REF;
+
+			set_dpb_info(hw_rps->entries, j, i, ref->index | (dpb_valid << 4), bottom);
+		}
+	}
+}
+
+void assemble_hw_scaling_list(struct rkvdec_h264_run *run,
+			      struct rkvdec_h264_scaling_list *scaling_list)
+{
+	const struct v4l2_ctrl_h264_scaling_matrix *scaling = run->scaling_matrix;
+	const struct v4l2_ctrl_h264_pps *pps = run->pps;
+
+	if (!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT))
+		return;
+
+	BUILD_BUG_ON(sizeof(scaling_list->scaling_list_4x4) !=
+		     sizeof(scaling->scaling_list_4x4));
+	BUILD_BUG_ON(sizeof(scaling_list->scaling_list_8x8) !=
+		     sizeof(scaling->scaling_list_8x8));
+
+	memcpy(scaling_list->scaling_list_4x4,
+	       scaling->scaling_list_4x4,
+	       sizeof(scaling->scaling_list_4x4));
+
+	memcpy(scaling_list->scaling_list_8x8,
+	       scaling->scaling_list_8x8,
+	       sizeof(scaling->scaling_list_8x8));
+}
+
+#define RKVDEC_H264_MAX_DEPTH_IN_BYTES		2
+
+int rkvdec_h264_adjust_fmt(struct rkvdec_ctx *ctx,
+			   struct v4l2_format *f)
+{
+	struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp;
+
+	fmt->num_planes = 1;
+	if (!fmt->plane_fmt[0].sizeimage)
+		fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height *
+					      RKVDEC_H264_MAX_DEPTH_IN_BYTES;
+	return 0;
+}
+
+enum rkvdec_image_fmt rkvdec_h264_get_image_fmt(struct rkvdec_ctx *ctx,
+						struct v4l2_ctrl *ctrl)
+{
+	const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps;
+
+	if (ctrl->id != V4L2_CID_STATELESS_H264_SPS)
+		return RKVDEC_IMG_FMT_ANY;
+
+	if (sps->bit_depth_luma_minus8 == 0) {
+		if (sps->chroma_format_idc == 2)
+			return RKVDEC_IMG_FMT_422_8BIT;
+		else
+			return RKVDEC_IMG_FMT_420_8BIT;
+	} else if (sps->bit_depth_luma_minus8 == 2) {
+		if (sps->chroma_format_idc == 2)
+			return RKVDEC_IMG_FMT_422_10BIT;
+		else
+			return RKVDEC_IMG_FMT_420_10BIT;
+	}
+
+	return RKVDEC_IMG_FMT_ANY;
+}
+
+int rkvdec_h264_validate_sps(struct rkvdec_ctx *ctx,
+			     const struct v4l2_ctrl_h264_sps *sps)
+{
+	unsigned int width, height;
+
+	if (sps->chroma_format_idc > 2)
+		/* Only 4:0:0, 4:2:0 and 4:2:2 are supported */
+		return -EINVAL;
+	if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
+		/* Luma and chroma bit depth mismatch */
+		return -EINVAL;
+	if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2)
+		/* Only 8-bit and 10-bit is supported */
+		return -EINVAL;
+
+	width = (sps->pic_width_in_mbs_minus1 + 1) * 16;
+	height = (sps->pic_height_in_map_units_minus1 + 1) * 16;
+
+	/*
+	 * When frame_mbs_only_flag is not set, this is field height,
+	 * which is half the final height (see (7-18) in the
+	 * specification)
+	 */
+	if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY))
+		height *= 2;
+
+	if (width > ctx->coded_fmt.fmt.pix_mp.width ||
+	    height > ctx->coded_fmt.fmt.pix_mp.height)
+		return -EINVAL;
+
+	return 0;
+}
+
+void rkvdec_h264_run_preamble(struct rkvdec_ctx *ctx,
+			      struct rkvdec_h264_run *run)
+{
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_H264_DECODE_PARAMS);
+	run->decode_params = ctrl ? ctrl->p_cur.p : NULL;
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_H264_SPS);
+	run->sps = ctrl ? ctrl->p_cur.p : NULL;
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_H264_PPS);
+	run->pps = ctrl ? ctrl->p_cur.p : NULL;
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_H264_SCALING_MATRIX);
+	run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL;
+
+	rkvdec_run_preamble(ctx, &run->base);
+}
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h
new file mode 100644
index 000000000000..bd0c0081365b
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Rockchip video decoder h264 common functions
+ *
+ * Copyright (C) 2025 Collabora, Ltd.
+ *	Detlev Casanova <detlev.casanova at collabora.com>
+ *
+ * Copyright (C) 2019 Collabora, Ltd.
+ *	Boris Brezillon <boris.brezillon at collabora.com>
+ *
+ * Copyright (C) 2016 Rockchip Electronics Co., Ltd.
+ *	Jeffy Chen <jeffy.chen at rock-chips.com>
+ */
+
+#include <media/v4l2-h264.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "rkvdec.h"
+
+extern const s8 rkvdec_h264_cabac_table[4][464][2];
+
+struct rkvdec_h264_scaling_list {
+	u8 scaling_list_4x4[6][16];
+	u8 scaling_list_8x8[6][64];
+	u8 padding[128];
+};
+
+struct rkvdec_h264_reflists {
+	struct v4l2_h264_reference p[V4L2_H264_REF_LIST_LEN];
+	struct v4l2_h264_reference b0[V4L2_H264_REF_LIST_LEN];
+	struct v4l2_h264_reference b1[V4L2_H264_REF_LIST_LEN];
+};
+
+struct rkvdec_h264_run {
+	struct rkvdec_run base;
+	const struct v4l2_ctrl_h264_decode_params *decode_params;
+	const struct v4l2_ctrl_h264_sps *sps;
+	const struct v4l2_ctrl_h264_pps *pps;
+	const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix;
+	struct vb2_buffer *ref_buf[V4L2_H264_NUM_DPB_ENTRIES];
+};
+
+struct rkvdec_rps_entry {
+	u32 dpb_info0:          5;
+	u32 bottom_flag0:       1;
+	u32 view_index_off0:    1;
+	u32 dpb_info1:          5;
+	u32 bottom_flag1:       1;
+	u32 view_index_off1:    1;
+	u32 dpb_info2:          5;
+	u32 bottom_flag2:       1;
+	u32 view_index_off2:    1;
+	u32 dpb_info3:          5;
+	u32 bottom_flag3:       1;
+	u32 view_index_off3:    1;
+	u32 dpb_info4:          5;
+	u32 bottom_flag4:       1;
+	u32 view_index_off4:    1;
+	u32 dpb_info5:          5;
+	u32 bottom_flag5:       1;
+	u32 view_index_off5:    1;
+	u32 dpb_info6:          5;
+	u32 bottom_flag6:       1;
+	u32 view_index_off6:    1;
+	u32 dpb_info7:          5;
+	u32 bottom_flag7:       1;
+	u32 view_index_off7:    1;
+} __packed;
+
+struct rkvdec_rps {
+	u16 frame_num[16];
+	u32 reserved0;
+	struct rkvdec_rps_entry entries[12];
+	u32 reserved1[66];
+} __packed;
+
+void lookup_ref_buf_idx(struct rkvdec_ctx *ctx, struct rkvdec_h264_run *run);
+void assemble_hw_rps(struct v4l2_h264_reflist_builder *builder,
+		     struct rkvdec_h264_run *run,
+		     struct rkvdec_h264_reflists *reflists,
+		     struct rkvdec_rps *hw_rps);
+void assemble_hw_scaling_list(struct rkvdec_h264_run *run,
+			      struct rkvdec_h264_scaling_list *scaling_list);
+int rkvdec_h264_adjust_fmt(struct rkvdec_ctx *ctx, struct v4l2_format *f);
+enum rkvdec_image_fmt rkvdec_h264_get_image_fmt(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl);
+int rkvdec_h264_validate_sps(struct rkvdec_ctx *ctx, const struct v4l2_ctrl_h264_sps *sps);
+void rkvdec_h264_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_h264_run *run);
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
index cb17dfcae5ca..e98bb69ff7f9 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
@@ -14,59 +14,16 @@
 
 #include "rkvdec.h"
 #include "rkvdec-regs.h"
-
-extern const s8 rkvdec_h264_cabac_table[4][464][2];
+#include "rkvdec-h264-common.h"
 
 /* Size with u32 units. */
 #define RKV_CABAC_INIT_BUFFER_SIZE	(3680 + 128)
 #define RKV_ERROR_INFO_SIZE		(256 * 144 * 4)
 
-#define RKVDEC_NUM_REFLIST		3
-
-struct rkvdec_h264_scaling_list {
-	u8 scaling_list_4x4[6][16];
-	u8 scaling_list_8x8[6][64];
-	u8 padding[128];
-};
-
 struct rkvdec_sps_pps_packet {
 	u32 info[8];
 };
 
-struct rkvdec_rps_entry {
-	u32 dpb_info0:          5;
-	u32 bottom_flag0:       1;
-	u32 view_index_off0:    1;
-	u32 dpb_info1:          5;
-	u32 bottom_flag1:       1;
-	u32 view_index_off1:    1;
-	u32 dpb_info2:          5;
-	u32 bottom_flag2:       1;
-	u32 view_index_off2:    1;
-	u32 dpb_info3:          5;
-	u32 bottom_flag3:       1;
-	u32 view_index_off3:    1;
-	u32 dpb_info4:          5;
-	u32 bottom_flag4:       1;
-	u32 view_index_off4:    1;
-	u32 dpb_info5:          5;
-	u32 bottom_flag5:       1;
-	u32 view_index_off5:    1;
-	u32 dpb_info6:          5;
-	u32 bottom_flag6:       1;
-	u32 view_index_off6:    1;
-	u32 dpb_info7:          5;
-	u32 bottom_flag7:       1;
-	u32 view_index_off7:    1;
-} __packed;
-
-struct rkvdec_rps {
-	u16 frame_num[16];
-	u32 reserved0;
-	struct rkvdec_rps_entry entries[12];
-	u32 reserved1[66];
-} __packed;
-
 struct rkvdec_ps_field {
 	u16 offset;
 	u8 len;
@@ -118,11 +75,6 @@ struct rkvdec_ps_field {
 #define SCALING_LIST_ADDRESS				PS_FIELD(184, 32)
 #define IS_LONG_TERM(i)				PS_FIELD(216 + (i), 1)
 
-#define DPB_OFFS(i, j)					(288 + ((j) * 32 * 7) + ((i) * 7))
-#define DPB_INFO(i, j)					PS_FIELD(DPB_OFFS(i, j), 5)
-#define BOTTOM_FLAG(i, j)				PS_FIELD(DPB_OFFS(i, j) + 5, 1)
-#define VIEW_INDEX_OFF(i, j)				PS_FIELD(DPB_OFFS(i, j) + 6, 1)
-
 /* Data structure describing auxiliary buffer format. */
 struct rkvdec_h264_priv_tbl {
 	s8 cabac_table[4][464][2];
@@ -132,21 +84,6 @@ struct rkvdec_h264_priv_tbl {
 	u8 err_info[RKV_ERROR_INFO_SIZE];
 };
 
-struct rkvdec_h264_reflists {
-	struct v4l2_h264_reference p[V4L2_H264_REF_LIST_LEN];
-	struct v4l2_h264_reference b0[V4L2_H264_REF_LIST_LEN];
-	struct v4l2_h264_reference b1[V4L2_H264_REF_LIST_LEN];
-};
-
-struct rkvdec_h264_run {
-	struct rkvdec_run base;
-	const struct v4l2_ctrl_h264_decode_params *decode_params;
-	const struct v4l2_ctrl_h264_sps *sps;
-	const struct v4l2_ctrl_h264_pps *pps;
-	const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix;
-	struct vb2_buffer *ref_buf[V4L2_H264_NUM_DPB_ENTRIES];
-};
-
 struct rkvdec_h264_ctx {
 	struct rkvdec_aux_buf priv_tbl;
 	struct rkvdec_h264_reflists reflists;
@@ -270,155 +207,6 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
 	}
 }
 
-static void lookup_ref_buf_idx(struct rkvdec_ctx *ctx,
-			       struct rkvdec_h264_run *run)
-{
-	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
-	u32 i;
-
-	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
-		struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
-		const struct v4l2_h264_dpb_entry *dpb = run->decode_params->dpb;
-		struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q;
-		struct vb2_buffer *buf = NULL;
-
-		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) {
-			buf = vb2_find_buffer(cap_q, dpb[i].reference_ts);
-			if (!buf)
-				pr_debug("No buffer for reference_ts %llu",
-					 dpb[i].reference_ts);
-		}
-
-		run->ref_buf[i] = buf;
-	}
-}
-
-static void set_dpb_info(struct rkvdec_rps_entry *entries,
-			 u8 reflist,
-			 u8 refnum,
-			 u8 info,
-			 bool bottom)
-{
-	struct rkvdec_rps_entry *entry = &entries[(reflist * 4) + refnum / 8];
-	u8 idx = refnum % 8;
-
-	switch (idx) {
-	case 0:
-		entry->dpb_info0 = info;
-		entry->bottom_flag0 = bottom;
-		break;
-	case 1:
-		entry->dpb_info1 = info;
-		entry->bottom_flag1 = bottom;
-		break;
-	case 2:
-		entry->dpb_info2 = info;
-		entry->bottom_flag2 = bottom;
-		break;
-	case 3:
-		entry->dpb_info3 = info;
-		entry->bottom_flag3 = bottom;
-		break;
-	case 4:
-		entry->dpb_info4 = info;
-		entry->bottom_flag4 = bottom;
-		break;
-	case 5:
-		entry->dpb_info5 = info;
-		entry->bottom_flag5 = bottom;
-		break;
-	case 6:
-		entry->dpb_info6 = info;
-		entry->bottom_flag6 = bottom;
-		break;
-	case 7:
-		entry->dpb_info7 = info;
-		entry->bottom_flag7 = bottom;
-		break;
-	}
-}
-
-static void assemble_hw_rps(struct rkvdec_ctx *ctx,
-			    struct v4l2_h264_reflist_builder *builder,
-			    struct rkvdec_h264_run *run)
-{
-	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
-	const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb;
-	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
-	struct rkvdec_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu;
-
-	struct rkvdec_rps *hw_rps = &priv_tbl->rps;
-	u32 i, j;
-
-	memset(hw_rps, 0, sizeof(*hw_rps));
-
-	/*
-	 * Assign an invalid pic_num if DPB entry at that position is inactive.
-	 * If we assign 0 in that position hardware will treat that as a real
-	 * reference picture with pic_num 0, triggering output picture
-	 * corruption.
-	 */
-	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
-		if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
-			continue;
-
-		hw_rps->frame_num[i] = builder->refs[i].frame_num;
-	}
-
-	for (j = 0; j < RKVDEC_NUM_REFLIST; j++) {
-		for (i = 0; i < builder->num_valid; i++) {
-			struct v4l2_h264_reference *ref;
-			bool dpb_valid;
-			bool bottom;
-
-			switch (j) {
-			case 0:
-				ref = &h264_ctx->reflists.p[i];
-				break;
-			case 1:
-				ref = &h264_ctx->reflists.b0[i];
-				break;
-			case 2:
-				ref = &h264_ctx->reflists.b1[i];
-				break;
-			}
-
-			if (WARN_ON(ref->index >= ARRAY_SIZE(dec_params->dpb)))
-				continue;
-
-			dpb_valid = run->ref_buf[ref->index] != NULL;
-			bottom = ref->fields == V4L2_H264_BOTTOM_FIELD_REF;
-
-			set_dpb_info(hw_rps->entries, j, i, ref->index | (dpb_valid << 4), bottom);
-		}
-	}
-}
-
-static void assemble_hw_scaling_list(struct rkvdec_ctx *ctx,
-				     struct rkvdec_h264_run *run)
-{
-	const struct v4l2_ctrl_h264_scaling_matrix *scaling = run->scaling_matrix;
-	const struct v4l2_ctrl_h264_pps *pps = run->pps;
-	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
-	struct rkvdec_h264_priv_tbl *tbl = h264_ctx->priv_tbl.cpu;
-
-	if (!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT))
-		return;
-
-	BUILD_BUG_ON(sizeof(tbl->scaling_list.scaling_list_4x4) !=
-		     sizeof(scaling->scaling_list_4x4));
-	BUILD_BUG_ON(sizeof(tbl->scaling_list.scaling_list_8x8) !=
-		     sizeof(scaling->scaling_list_8x8));
-
-	memcpy(tbl->scaling_list.scaling_list_4x4,
-	       scaling->scaling_list_4x4,
-	       sizeof(scaling->scaling_list_4x4));
-
-	memcpy(tbl->scaling_list.scaling_list_8x8,
-	       scaling->scaling_list_8x8,
-	       sizeof(scaling->scaling_list_8x8));
-}
-
 /*
  * Set the ref POC in the correct register.
  *
@@ -568,76 +356,6 @@ static void config_registers(struct rkvdec_ctx *ctx,
 	rkvdec_memcpy_toio(rkvdec->regs, regs, MIN(sizeof(*regs), 4 * rkvdec->variant->num_regs));
 }
 
-#define RKVDEC_H264_MAX_DEPTH_IN_BYTES		2
-
-static int rkvdec_h264_adjust_fmt(struct rkvdec_ctx *ctx,
-				  struct v4l2_format *f)
-{
-	struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp;
-
-	fmt->num_planes = 1;
-	if (!fmt->plane_fmt[0].sizeimage)
-		fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height *
-					      RKVDEC_H264_MAX_DEPTH_IN_BYTES;
-	return 0;
-}
-
-static enum rkvdec_image_fmt rkvdec_h264_get_image_fmt(struct rkvdec_ctx *ctx,
-						       struct v4l2_ctrl *ctrl)
-{
-	const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps;
-
-	if (ctrl->id != V4L2_CID_STATELESS_H264_SPS)
-		return RKVDEC_IMG_FMT_ANY;
-
-	if (sps->bit_depth_luma_minus8 == 0) {
-		if (sps->chroma_format_idc == 2)
-			return RKVDEC_IMG_FMT_422_8BIT;
-		else
-			return RKVDEC_IMG_FMT_420_8BIT;
-	} else if (sps->bit_depth_luma_minus8 == 2) {
-		if (sps->chroma_format_idc == 2)
-			return RKVDEC_IMG_FMT_422_10BIT;
-		else
-			return RKVDEC_IMG_FMT_420_10BIT;
-	}
-
-	return RKVDEC_IMG_FMT_ANY;
-}
-
-static int rkvdec_h264_validate_sps(struct rkvdec_ctx *ctx,
-				    const struct v4l2_ctrl_h264_sps *sps)
-{
-	unsigned int width, height;
-
-	if (sps->chroma_format_idc > 2)
-		/* Only 4:0:0, 4:2:0 and 4:2:2 are supported */
-		return -EINVAL;
-	if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
-		/* Luma and chroma bit depth mismatch */
-		return -EINVAL;
-	if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2)
-		/* Only 8-bit and 10-bit is supported */
-		return -EINVAL;
-
-	width = (sps->pic_width_in_mbs_minus1 + 1) * 16;
-	height = (sps->pic_height_in_map_units_minus1 + 1) * 16;
-
-	/*
-	 * When frame_mbs_only_flag is not set, this is field height,
-	 * which is half the final height (see (7-18) in the
-	 * specification)
-	 */
-	if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY))
-		height *= 2;
-
-	if (width > ctx->coded_fmt.fmt.pix_mp.width ||
-	    height > ctx->coded_fmt.fmt.pix_mp.height)
-		return -EINVAL;
-
-	return 0;
-}
-
 static int rkvdec_h264_start(struct rkvdec_ctx *ctx)
 {
 	struct rkvdec_dev *rkvdec = ctx->dev;
@@ -689,33 +407,13 @@ static void rkvdec_h264_stop(struct rkvdec_ctx *ctx)
 	kfree(h264_ctx);
 }
 
-static void rkvdec_h264_run_preamble(struct rkvdec_ctx *ctx,
-				     struct rkvdec_h264_run *run)
-{
-	struct v4l2_ctrl *ctrl;
-
-	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
-			      V4L2_CID_STATELESS_H264_DECODE_PARAMS);
-	run->decode_params = ctrl ? ctrl->p_cur.p : NULL;
-	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
-			      V4L2_CID_STATELESS_H264_SPS);
-	run->sps = ctrl ? ctrl->p_cur.p : NULL;
-	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
-			      V4L2_CID_STATELESS_H264_PPS);
-	run->pps = ctrl ? ctrl->p_cur.p : NULL;
-	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
-			      V4L2_CID_STATELESS_H264_SCALING_MATRIX);
-	run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL;
-
-	rkvdec_run_preamble(ctx, &run->base);
-}
-
 static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
 {
 	struct v4l2_h264_reflist_builder reflist_builder;
 	struct rkvdec_dev *rkvdec = ctx->dev;
 	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
 	struct rkvdec_h264_run run;
+	struct rkvdec_h264_priv_tbl *tbl = h264_ctx->priv_tbl.cpu;
 
 	rkvdec_h264_run_preamble(ctx, &run);
 
@@ -726,10 +424,10 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
 	v4l2_h264_build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0,
 				    h264_ctx->reflists.b1);
 
-	assemble_hw_scaling_list(ctx, &run);
+	assemble_hw_scaling_list(&run, &tbl->scaling_list);
 	assemble_hw_pps(ctx, &run);
 	lookup_ref_buf_idx(ctx, &run);
-	assemble_hw_rps(ctx, &reflist_builder, &run);
+	assemble_hw_rps(&reflist_builder, &run, &h264_ctx->reflists, &tbl->rps);
 	config_registers(ctx, &run);
 
 	rkvdec_run_postamble(ctx, &run.base);
-- 
2.52.0



From detlev.casanova at collabora.com  Wed Dec 17 09:40:45 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 17 Dec 2025 12:40:45 -0500
Subject: [PATCH v6 08/17] media: rkvdec: Move hevc functions to common file
In-Reply-To: <20251217174059.1341784-1-detlev.casanova@collabora.com>
References: <20251217174059.1341784-1-detlev.casanova@collabora.com>
Message-ID: <20251217174059.1341784-9-detlev.casanova@collabora.com>

This is a preparation commit to add support for new variants of the
decoder.

The functions will later be shared with vdpu381 (rk3588) and vdpu383
(rk3576).

Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../media/platform/rockchip/rkvdec/Makefile   |   1 +
 .../rockchip/rkvdec/rkvdec-hevc-common.c      | 182 ++++++++++++++++
 .../rockchip/rkvdec/rkvdec-hevc-common.h      |  48 +++++
 .../platform/rockchip/rkvdec/rkvdec-hevc.c    | 194 +-----------------
 4 files changed, 238 insertions(+), 187 deletions(-)
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h

diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
index d2ba7a7c15e5..1b4bc44be23e 100644
--- a/drivers/media/platform/rockchip/rkvdec/Makefile
+++ b/drivers/media/platform/rockchip/rkvdec/Makefile
@@ -6,4 +6,5 @@ rockchip-vdec-y += \
 		   rkvdec-h264.o \
 		   rkvdec-h264-common.o \
 		   rkvdec-hevc.o \
+		   rkvdec-hevc-common.o \
 		   rkvdec-vp9.o
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
new file mode 100644
index 000000000000..23547e2e6e1d
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip video decoder hevc common functions
+ *
+ * Copyright (C) 2025 Collabora, Ltd.
+ *      Detlev Casanova <detlev.casanova at collabora.com>
+ *
+ * Copyright (C) 2023 Collabora, Ltd.
+ *      Sebastian Fricke <sebastian.fricke at collabora.com>
+ *
+ * Copyright (C) 2019 Collabora, Ltd.
+ *	Boris Brezillon <boris.brezillon at collabora.com>
+ *
+ * Copyright (C) 2016 Rockchip Electronics Co., Ltd.
+ *	Jeffy Chen <jeffy.chen at rock-chips.com>
+ */
+
+#include <linux/v4l2-common.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "rkvdec.h"
+#include "rkvdec-hevc-common.h"
+
+/*
+ * Flip one or more matrices along their main diagonal and flatten them
+ * before writing it to the memory.
+ * Convert:
+ * ABCD         AEIM
+ * EFGH     =>  BFJN     =>     AEIMBFJNCGKODHLP
+ * IJKL         CGKO
+ * MNOP         DHLP
+ */
+static void transpose_and_flatten_matrices(u8 *output, const u8 *input,
+					   int matrices, int row_length)
+{
+	int i, j, row, x_offset, matrix_offset, rot_index, y_offset, matrix_size, new_value;
+
+	matrix_size = row_length * row_length;
+	for (i = 0; i < matrices; i++) {
+		row = 0;
+		x_offset = 0;
+		matrix_offset = i * matrix_size;
+		for (j = 0; j < matrix_size; j++) {
+			y_offset = j - (row * row_length);
+			rot_index = y_offset * row_length + x_offset;
+			new_value = *(input + i * matrix_size + j);
+			output[matrix_offset + rot_index] = new_value;
+			if ((j + 1) % row_length == 0) {
+				row += 1;
+				x_offset += 1;
+			}
+		}
+	}
+}
+
+static void assemble_scalingfactor0(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input)
+{
+	int offset = 0;
+
+	transpose_and_flatten_matrices(output, (const u8 *)input->scaling_list_4x4, 6, 4);
+	offset = 6 * 16 * sizeof(u8);
+	transpose_and_flatten_matrices(output + offset, (const u8 *)input->scaling_list_8x8, 6, 8);
+	offset += 6 * 64 * sizeof(u8);
+	transpose_and_flatten_matrices(output + offset,
+				       (const u8 *)input->scaling_list_16x16, 6, 8);
+	offset += 6 * 64 * sizeof(u8);
+	/* Add a 128 byte padding with 0s between the two 32x32 matrices */
+	transpose_and_flatten_matrices(output + offset,
+				       (const u8 *)input->scaling_list_32x32, 1, 8);
+	offset += 64 * sizeof(u8);
+	memset(output + offset, 0, 128);
+	offset += 128 * sizeof(u8);
+	transpose_and_flatten_matrices(output + offset,
+				       (const u8 *)input->scaling_list_32x32 + (64 * sizeof(u8)),
+				       1, 8);
+	offset += 64 * sizeof(u8);
+	memset(output + offset, 0, 128);
+}
+
+/*
+ * Required layout:
+ * A = scaling_list_dc_coef_16x16
+ * B = scaling_list_dc_coef_32x32
+ * 0 = Padding
+ *
+ * A, A, A, A, A, A, B, 0, 0, B, 0, 0
+ */
+static void assemble_scalingdc(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input)
+{
+	u8 list_32x32[6] = {0};
+
+	memcpy(output, input->scaling_list_dc_coef_16x16, 6 * sizeof(u8));
+	list_32x32[0] = input->scaling_list_dc_coef_32x32[0];
+	list_32x32[3] = input->scaling_list_dc_coef_32x32[1];
+	memcpy(output + 6 * sizeof(u8), list_32x32, 6 * sizeof(u8));
+}
+
+static void translate_scaling_list(struct scaling_factor *output,
+				   const struct v4l2_ctrl_hevc_scaling_matrix *input)
+{
+	assemble_scalingfactor0(output->scalingfactor0, input);
+	memcpy(output->scalingfactor1, (const u8 *)input->scaling_list_4x4, 96);
+	assemble_scalingdc(output->scalingdc, input);
+	memset(output->reserved, 0, 4 * sizeof(u8));
+}
+
+void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
+					  struct scaling_factor *scaling_factor,
+					  struct v4l2_ctrl_hevc_scaling_matrix *cache)
+{
+	const struct v4l2_ctrl_hevc_scaling_matrix *scaling = run->scaling_matrix;
+
+	if (!memcmp(cache, scaling,
+		    sizeof(struct v4l2_ctrl_hevc_scaling_matrix)))
+		return;
+
+	translate_scaling_list(scaling_factor, scaling);
+
+	memcpy(cache, scaling,
+	       sizeof(struct v4l2_ctrl_hevc_scaling_matrix));
+}
+
+struct vb2_buffer *
+get_ref_buf(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run,
+	    unsigned int dpb_idx)
+{
+	struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
+	const struct v4l2_ctrl_hevc_decode_params *decode_params = run->decode_params;
+	const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb;
+	struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q;
+	struct vb2_buffer *buf = NULL;
+
+	if (dpb_idx < decode_params->num_active_dpb_entries)
+		buf = vb2_find_buffer(cap_q, dpb[dpb_idx].timestamp);
+
+	/*
+	 * If a DPB entry is unused or invalid, the address of current destination
+	 * buffer is returned.
+	 */
+	if (!buf)
+		return &run->base.bufs.dst->vb2_buf;
+
+	return buf;
+}
+
+#define RKVDEC_HEVC_MAX_DEPTH_IN_BYTES		2
+
+int rkvdec_hevc_adjust_fmt(struct rkvdec_ctx *ctx, struct v4l2_format *f)
+{
+	struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp;
+
+	fmt->num_planes = 1;
+	if (!fmt->plane_fmt[0].sizeimage)
+		fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height *
+					      RKVDEC_HEVC_MAX_DEPTH_IN_BYTES;
+	return 0;
+}
+
+void rkvdec_hevc_run_preamble(struct rkvdec_ctx *ctx,
+			      struct rkvdec_hevc_run *run)
+{
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_HEVC_DECODE_PARAMS);
+	run->decode_params = ctrl ? ctrl->p_cur.p : NULL;
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_HEVC_SLICE_PARAMS);
+	run->slices_params = ctrl ? ctrl->p_cur.p : NULL;
+	run->num_slices = ctrl ? ctrl->new_elems : 0;
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_HEVC_SPS);
+	run->sps = ctrl ? ctrl->p_cur.p : NULL;
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_HEVC_PPS);
+	run->pps = ctrl ? ctrl->p_cur.p : NULL;
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_HEVC_SCALING_MATRIX);
+	run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL;
+
+	rkvdec_run_preamble(ctx, &run->base);
+}
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
new file mode 100644
index 000000000000..8af33bfd541c
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Rockchip video decoder hevc common functions
+ *
+ * Copyright (C) 2025 Collabora, Ltd.
+ *      Detlev Casanova <detlev.casanova at collabora.com>
+ *
+ * Copyright (C) 2023 Collabora, Ltd.
+ *      Sebastian Fricke <sebastian.fricke at collabora.com>
+ *
+ * Copyright (C) 2019 Collabora, Ltd.
+ *	Boris Brezillon <boris.brezillon at collabora.com>
+ *
+ * Copyright (C) 2016 Rockchip Electronics Co., Ltd.
+ *	Jeffy Chen <jeffy.chen at rock-chips.com>
+ */
+
+#include <media/v4l2-mem2mem.h>
+#include "rkvdec.h"
+
+#define RKV_HEVC_CABAC_TABLE_SIZE		27456
+extern const u8 rkvdec_hevc_cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
+
+struct rkvdec_hevc_run {
+	struct rkvdec_run base;
+	const struct v4l2_ctrl_hevc_slice_params *slices_params;
+	const struct v4l2_ctrl_hevc_decode_params *decode_params;
+	const struct v4l2_ctrl_hevc_sps *sps;
+	const struct v4l2_ctrl_hevc_pps *pps;
+	const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix;
+	int num_slices;
+};
+
+struct scaling_factor {
+	u8 scalingfactor0[1248];
+	u8 scalingfactor1[96];	/*4X4 TU Rotate, total 16X4*/
+	u8 scalingdc[12];	/*N1005 Vienna Meeting*/
+	u8 reserved[4];		/*16Bytes align*/
+};
+
+void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
+					  struct scaling_factor *scaling_factor,
+					  struct v4l2_ctrl_hevc_scaling_matrix *cache);
+struct vb2_buffer *get_ref_buf(struct rkvdec_ctx *ctx,
+			       struct rkvdec_hevc_run *run,
+			       unsigned int dpb_idx);
+int rkvdec_hevc_adjust_fmt(struct rkvdec_ctx *ctx, struct v4l2_format *f);
+void rkvdec_hevc_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run);
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
index b01c1bb52a04..650c20f3f4aa 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
@@ -16,6 +16,7 @@
 
 #include "rkvdec.h"
 #include "rkvdec-regs.h"
+#include "rkvdec-hevc-common.h"
 
 /* Size in u8/u32 units. */
 #define RKV_SCALING_LIST_SIZE		1360
@@ -24,9 +25,6 @@
 #define RKV_RPS_SIZE			(32 / 4)
 #define RKV_RPS_LEN			600
 
-#define RKV_HEVC_CABAC_TABLE_SIZE		27456
-extern const u8 rkvdec_hevc_cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
-
 struct rkvdec_sps_pps_packet {
 	u32 info[RKV_PPS_SIZE];
 };
@@ -113,34 +111,17 @@ struct rkvdec_ps_field {
 /* Data structure describing auxiliary buffer format. */
 struct rkvdec_hevc_priv_tbl {
 	u8 cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
-	u8 scaling_list[RKV_SCALING_LIST_SIZE];
+	struct scaling_factor scaling_list;
 	struct rkvdec_sps_pps_packet param_set[RKV_PPS_LEN];
 	struct rkvdec_rps_packet rps[RKV_RPS_LEN];
 };
 
-struct rkvdec_hevc_run {
-	struct rkvdec_run base;
-	const struct v4l2_ctrl_hevc_slice_params *slices_params;
-	const struct v4l2_ctrl_hevc_decode_params *decode_params;
-	const struct v4l2_ctrl_hevc_sps *sps;
-	const struct v4l2_ctrl_hevc_pps *pps;
-	const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix;
-	int num_slices;
-};
-
 struct rkvdec_hevc_ctx {
 	struct rkvdec_aux_buf priv_tbl;
 	struct v4l2_ctrl_hevc_scaling_matrix scaling_matrix_cache;
 	struct rkvdec_regs regs;
 };
 
-struct scaling_factor {
-	u8 scalingfactor0[1248];
-	u8 scalingfactor1[96];		/*4X4 TU Rotate, total 16X4*/
-	u8 scalingdc[12];		/*N1005 Vienna Meeting*/
-	u8 reserved[4];		/*16Bytes align*/
-};
-
 static void set_ps_field(u32 *buf, struct rkvdec_ps_field field, u32 value)
 {
 	u8 bit = field.offset % 32, word = field.offset / 32;
@@ -417,131 +398,6 @@ static void assemble_sw_rps(struct rkvdec_ctx *ctx,
 	}
 }
 
-/*
- * Flip one or more matrices along their main diagonal and flatten them
- * before writing it to the memory.
- * Convert:
- * ABCD         AEIM
- * EFGH     =>  BFJN     =>     AEIMBFJNCGKODHLP
- * IJKL         CGKO
- * MNOP         DHLP
- */
-static void transpose_and_flatten_matrices(u8 *output, const u8 *input,
-					   int matrices, int row_length)
-{
-	int i, j, row, x_offset, matrix_offset, rot_index, y_offset, matrix_size, new_value;
-
-	matrix_size = row_length * row_length;
-	for (i = 0; i < matrices; i++) {
-		row = 0;
-		x_offset = 0;
-		matrix_offset = i * matrix_size;
-		for (j = 0; j < matrix_size; j++) {
-			y_offset = j - (row * row_length);
-			rot_index = y_offset * row_length + x_offset;
-			new_value = *(input + i * matrix_size + j);
-			output[matrix_offset + rot_index] = new_value;
-			if ((j + 1) % row_length == 0) {
-				row += 1;
-				x_offset += 1;
-			}
-		}
-	}
-}
-
-static void assemble_scalingfactor0(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input)
-{
-	int offset = 0;
-
-	transpose_and_flatten_matrices(output, (const u8 *)input->scaling_list_4x4, 6, 4);
-	offset = 6 * 16 * sizeof(u8);
-	transpose_and_flatten_matrices(output + offset, (const u8 *)input->scaling_list_8x8, 6, 8);
-	offset += 6 * 64 * sizeof(u8);
-	transpose_and_flatten_matrices(output + offset,
-				       (const u8 *)input->scaling_list_16x16, 6, 8);
-	offset += 6 * 64 * sizeof(u8);
-	/* Add a 128 byte padding with 0s between the two 32x32 matrices */
-	transpose_and_flatten_matrices(output + offset,
-				       (const u8 *)input->scaling_list_32x32, 1, 8);
-	offset += 64 * sizeof(u8);
-	memset(output + offset, 0, 128);
-	offset += 128 * sizeof(u8);
-	transpose_and_flatten_matrices(output + offset,
-				       (const u8 *)input->scaling_list_32x32 + (64 * sizeof(u8)),
-				       1, 8);
-	offset += 64 * sizeof(u8);
-	memset(output + offset, 0, 128);
-}
-
-/*
- * Required layout:
- * A = scaling_list_dc_coef_16x16
- * B = scaling_list_dc_coef_32x32
- * 0 = Padding
- *
- * A, A, A, A, A, A, B, 0, 0, B, 0, 0
- */
-static void assemble_scalingdc(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input)
-{
-	u8 list_32x32[6] = {0};
-
-	memcpy(output, input->scaling_list_dc_coef_16x16, 6 * sizeof(u8));
-	list_32x32[0] = input->scaling_list_dc_coef_32x32[0];
-	list_32x32[3] = input->scaling_list_dc_coef_32x32[1];
-	memcpy(output + 6 * sizeof(u8), list_32x32, 6 * sizeof(u8));
-}
-
-static void translate_scaling_list(struct scaling_factor *output,
-				   const struct v4l2_ctrl_hevc_scaling_matrix *input)
-{
-	assemble_scalingfactor0(output->scalingfactor0, input);
-	memcpy(output->scalingfactor1, (const u8 *)input->scaling_list_4x4, 96);
-	assemble_scalingdc(output->scalingdc, input);
-	memset(output->reserved, 0, 4 * sizeof(u8));
-}
-
-static void assemble_hw_scaling_list(struct rkvdec_ctx *ctx,
-				     struct rkvdec_hevc_run *run)
-{
-	const struct v4l2_ctrl_hevc_scaling_matrix *scaling = run->scaling_matrix;
-	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
-	struct rkvdec_hevc_priv_tbl *tbl = hevc_ctx->priv_tbl.cpu;
-	u8 *dst;
-
-	if (!memcmp((void *)&hevc_ctx->scaling_matrix_cache, scaling,
-		    sizeof(struct v4l2_ctrl_hevc_scaling_matrix)))
-		return;
-
-	dst = tbl->scaling_list;
-	translate_scaling_list((struct scaling_factor *)dst, scaling);
-
-	memcpy((void *)&hevc_ctx->scaling_matrix_cache, scaling,
-	       sizeof(struct v4l2_ctrl_hevc_scaling_matrix));
-}
-
-static struct vb2_buffer *
-get_ref_buf(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run,
-	    unsigned int dpb_idx)
-{
-	struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
-	const struct v4l2_ctrl_hevc_decode_params *decode_params = run->decode_params;
-	const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb;
-	struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q;
-	struct vb2_buffer *buf = NULL;
-
-	if (dpb_idx < decode_params->num_active_dpb_entries)
-		buf = vb2_find_buffer(cap_q, dpb[dpb_idx].timestamp);
-
-	/*
-	 * If a DPB entry is unused or invalid, the address of current destination
-	 * buffer is returned.
-	 */
-	if (!buf)
-		return &run->base.bufs.dst->vb2_buf;
-
-	return buf;
-}
-
 static void config_registers(struct rkvdec_ctx *ctx,
 			     struct rkvdec_hevc_run *run)
 {
@@ -644,20 +500,6 @@ static void config_registers(struct rkvdec_ctx *ctx,
 	rkvdec_memcpy_toio(rkvdec->regs, regs, MIN(sizeof(*regs), 4 * rkvdec->variant->num_regs));
 }
 
-#define RKVDEC_HEVC_MAX_DEPTH_IN_BYTES		2
-
-static int rkvdec_hevc_adjust_fmt(struct rkvdec_ctx *ctx,
-				  struct v4l2_format *f)
-{
-	struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp;
-
-	fmt->num_planes = 1;
-	if (!fmt->plane_fmt[0].sizeimage)
-		fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height *
-					      RKVDEC_HEVC_MAX_DEPTH_IN_BYTES;
-	return 0;
-}
-
 static enum rkvdec_image_fmt rkvdec_hevc_get_image_fmt(struct rkvdec_ctx *ctx,
 						       struct v4l2_ctrl *ctrl)
 {
@@ -691,7 +533,7 @@ static int rkvdec_hevc_validate_sps(struct rkvdec_ctx *ctx,
 		/* Luma and chroma bit depth mismatch */
 		return -EINVAL;
 	if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2)
-		/* Only 8-bit and 10-bit is supported */
+		/* Only 8-bit and 10-bit are supported */
 		return -EINVAL;
 
 	if (sps->pic_width_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.width ||
@@ -737,40 +579,18 @@ static void rkvdec_hevc_stop(struct rkvdec_ctx *ctx)
 	kfree(hevc_ctx);
 }
 
-static void rkvdec_hevc_run_preamble(struct rkvdec_ctx *ctx,
-				     struct rkvdec_hevc_run *run)
-{
-	struct v4l2_ctrl *ctrl;
-
-	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
-			      V4L2_CID_STATELESS_HEVC_DECODE_PARAMS);
-	run->decode_params = ctrl ? ctrl->p_cur.p : NULL;
-	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
-			      V4L2_CID_STATELESS_HEVC_SLICE_PARAMS);
-	run->slices_params = ctrl ? ctrl->p_cur.p : NULL;
-	run->num_slices = ctrl ? ctrl->new_elems : 0;
-	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
-			      V4L2_CID_STATELESS_HEVC_SPS);
-	run->sps = ctrl ? ctrl->p_cur.p : NULL;
-	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
-			      V4L2_CID_STATELESS_HEVC_PPS);
-	run->pps = ctrl ? ctrl->p_cur.p : NULL;
-	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
-			      V4L2_CID_STATELESS_HEVC_SCALING_MATRIX);
-	run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL;
-
-	rkvdec_run_preamble(ctx, &run->base);
-}
-
 static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
 {
 	struct rkvdec_dev *rkvdec = ctx->dev;
 	struct rkvdec_hevc_run run;
+	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
+	struct rkvdec_hevc_priv_tbl *tbl = hevc_ctx->priv_tbl.cpu;
 	u32 reg;
 
 	rkvdec_hevc_run_preamble(ctx, &run);
 
-	assemble_hw_scaling_list(ctx, &run);
+	rkvdec_hevc_assemble_hw_scaling_list(&run, &tbl->scaling_list,
+					     &hevc_ctx->scaling_matrix_cache);
 	assemble_hw_pps(ctx, &run);
 	assemble_sw_rps(ctx, &run);
 	config_registers(ctx, &run);
-- 
2.52.0



From detlev.casanova at collabora.com  Wed Dec 17 09:40:46 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 17 Dec 2025 12:40:46 -0500
Subject: [PATCH v6 09/17] media: rkvdec: Add variant specific coded formats list
In-Reply-To: <20251217174059.1341784-1-detlev.casanova@collabora.com>
References: <20251217174059.1341784-1-detlev.casanova@collabora.com>
Message-ID: <20251217174059.1341784-10-detlev.casanova@collabora.com>

Prepare for adding new variants of the decoder and support specific
formats and format ops per variant.

Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../media/platform/rockchip/rkvdec/rkvdec.c   | 35 ++++++++++++-------
 .../media/platform/rockchip/rkvdec/rkvdec.h   |  2 ++
 2 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index 776149f871b0..968982f6e62c 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -373,15 +373,16 @@ static bool rkvdec_is_capable(struct rkvdec_ctx *ctx, unsigned int capability)
 static const struct rkvdec_coded_fmt_desc *
 rkvdec_enum_coded_fmt_desc(struct rkvdec_ctx *ctx, int index)
 {
+	const struct rkvdec_variant *variant = ctx->dev->variant;
 	int fmt_idx = -1;
 	unsigned int i;
 
-	for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++) {
-		if (!rkvdec_is_capable(ctx, rkvdec_coded_fmts[i].capability))
+	for (i = 0; i < variant->num_coded_fmts; i++) {
+		if (!rkvdec_is_capable(ctx, variant->coded_fmts[i].capability))
 			continue;
 		fmt_idx++;
 		if (index == fmt_idx)
-			return &rkvdec_coded_fmts[i];
+			return &variant->coded_fmts[i];
 	}
 
 	return NULL;
@@ -390,12 +391,13 @@ rkvdec_enum_coded_fmt_desc(struct rkvdec_ctx *ctx, int index)
 static const struct rkvdec_coded_fmt_desc *
 rkvdec_find_coded_fmt_desc(struct rkvdec_ctx *ctx, u32 fourcc)
 {
+	const struct rkvdec_variant *variant = ctx->dev->variant;
 	unsigned int i;
 
-	for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++) {
-		if (rkvdec_is_capable(ctx, rkvdec_coded_fmts[i].capability) &&
-		    rkvdec_coded_fmts[i].fourcc == fourcc)
-			return &rkvdec_coded_fmts[i];
+	for (i = 0; i < variant->num_coded_fmts; i++) {
+		if (rkvdec_is_capable(ctx, variant->coded_fmts[i].capability) &&
+		    variant->coded_fmts[i].fourcc == fourcc)
+			return &variant->coded_fmts[i];
 	}
 
 	return NULL;
@@ -1014,18 +1016,19 @@ static int rkvdec_add_ctrls(struct rkvdec_ctx *ctx,
 
 static int rkvdec_init_ctrls(struct rkvdec_ctx *ctx)
 {
+	const struct rkvdec_variant *variant = ctx->dev->variant;
 	unsigned int i, nctrls = 0;
 	int ret;
 
-	for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++)
-		if (rkvdec_is_capable(ctx, rkvdec_coded_fmts[i].capability))
-			nctrls += rkvdec_coded_fmts[i].ctrls->num_ctrls;
+	for (i = 0; i < variant->num_coded_fmts; i++)
+		if (rkvdec_is_capable(ctx, variant->coded_fmts[i].capability))
+			nctrls += variant->coded_fmts[i].ctrls->num_ctrls;
 
 	v4l2_ctrl_handler_init(&ctx->ctrl_hdl, nctrls);
 
-	for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++) {
-		if (rkvdec_is_capable(ctx, rkvdec_coded_fmts[i].capability)) {
-			ret = rkvdec_add_ctrls(ctx, rkvdec_coded_fmts[i].ctrls);
+	for (i = 0; i < variant->num_coded_fmts; i++) {
+		if (rkvdec_is_capable(ctx, variant->coded_fmts[i].capability)) {
+			ret = rkvdec_add_ctrls(ctx, variant->coded_fmts[i].ctrls);
 			if (ret)
 				goto err_free_handler;
 		}
@@ -1242,11 +1245,15 @@ static void rkvdec_watchdog_func(struct work_struct *work)
 
 static const struct rkvdec_variant rk3288_rkvdec_variant = {
 	.num_regs = 68,
+	.coded_fmts = rkvdec_coded_fmts,
+	.num_coded_fmts = ARRAY_SIZE(rkvdec_coded_fmts),
 	.capabilities = RKVDEC_CAPABILITY_HEVC,
 };
 
 static const struct rkvdec_variant rk3328_rkvdec_variant = {
 	.num_regs = 109,
+	.coded_fmts = rkvdec_coded_fmts,
+	.num_coded_fmts = ARRAY_SIZE(rkvdec_coded_fmts),
 	.capabilities = RKVDEC_CAPABILITY_HEVC |
 			RKVDEC_CAPABILITY_H264 |
 			RKVDEC_CAPABILITY_VP9,
@@ -1255,6 +1262,8 @@ static const struct rkvdec_variant rk3328_rkvdec_variant = {
 
 static const struct rkvdec_variant rk3399_rkvdec_variant = {
 	.num_regs = 78,
+	.coded_fmts = rkvdec_coded_fmts,
+	.num_coded_fmts = ARRAY_SIZE(rkvdec_coded_fmts),
 	.capabilities = RKVDEC_CAPABILITY_HEVC |
 			RKVDEC_CAPABILITY_H264 |
 			RKVDEC_CAPABILITY_VP9,
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
index f35f6e80ea2e..aac6cba4c623 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
@@ -71,6 +71,8 @@ vb2_to_rkvdec_decoded_buf(struct vb2_buffer *buf)
 
 struct rkvdec_variant {
 	unsigned int num_regs;
+	const struct rkvdec_coded_fmt_desc *coded_fmts;
+	size_t num_coded_fmts;
 	unsigned int capabilities;
 	unsigned int quirks;
 };
-- 
2.52.0



From detlev.casanova at collabora.com  Wed Dec 17 09:40:47 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 17 Dec 2025 12:40:47 -0500
Subject: [PATCH v6 10/17] media: rkvdec: Add RCB and SRAM support
In-Reply-To: <20251217174059.1341784-1-detlev.casanova@collabora.com>
References: <20251217174059.1341784-1-detlev.casanova@collabora.com>
Message-ID: <20251217174059.1341784-11-detlev.casanova@collabora.com>

The RCB (Rows and Cols Buffers) are a set of buffers used by other
variations of the decoder to store temporary data.

Those variation come with a dedicated SRAM area used to store those
buffers for better performances.

The buffer sizes are either the width or height of the frame being
decoded multiplied by a documented factor and can be stored either
in SRAM or RAM.
A fallback to RAM is provided if the SRAM is full (e.g.: multiple
streams are being decoded at the same time).

To manage the different kind of allocation, an enum is added to the
rkvdec_aux_buf struct to specify how the buffer was allocated, and
so, how to free it.

This commit is in preparation of other variants support.

Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../media/platform/rockchip/rkvdec/Makefile   |   1 +
 .../platform/rockchip/rkvdec/rkvdec-rcb.c     | 178 ++++++++++++++++++
 .../platform/rockchip/rkvdec/rkvdec-rcb.h     |  29 +++
 .../media/platform/rockchip/rkvdec/rkvdec.c   |  27 ++-
 .../media/platform/rockchip/rkvdec/rkvdec.h   |  13 ++
 5 files changed, 246 insertions(+), 2 deletions(-)
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h

diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
index 1b4bc44be23e..3d75103e536d 100644
--- a/drivers/media/platform/rockchip/rkvdec/Makefile
+++ b/drivers/media/platform/rockchip/rkvdec/Makefile
@@ -7,4 +7,5 @@ rockchip-vdec-y += \
 		   rkvdec-h264-common.o \
 		   rkvdec-hevc.o \
 		   rkvdec-hevc-common.o \
+		   rkvdec-rcb.o \
 		   rkvdec-vp9.o
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c
new file mode 100644
index 000000000000..320998ed2c74
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip video decoder Rows and Cols Buffers manager
+ *
+ * Copyright (C) 2025 Collabora, Ltd.
+ *  Detlev Casanova <detlev.casanova at collabora.com>
+ */
+
+#include "rkvdec.h"
+#include "rkvdec-rcb.h"
+
+#include <linux/types.h>
+#include <linux/iommu.h>
+#include <linux/genalloc.h>
+
+struct rkvdec_rcb_config {
+	struct rkvdec_aux_buf *rcb_bufs;
+	size_t rcb_count;
+};
+
+static size_t rkvdec_rcb_size(const struct rcb_size_info *size_info,
+			      unsigned int width, unsigned int height)
+{
+	return size_info->multiplier * (size_info->axis == PIC_HEIGHT ? height : width);
+}
+
+dma_addr_t rkvdec_rcb_buf_dma_addr(struct rkvdec_ctx *ctx, int id)
+{
+	return ctx->rcb_config->rcb_bufs[id].dma;
+}
+
+size_t rkvdec_rcb_buf_size(struct rkvdec_ctx *ctx, int id)
+{
+	return ctx->rcb_config->rcb_bufs[id].size;
+}
+
+int rkvdec_rcb_buf_count(struct rkvdec_ctx *ctx)
+{
+	return ctx->rcb_config->rcb_count;
+}
+
+void rkvdec_free_rcb(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_dev *dev = ctx->dev;
+	struct rkvdec_rcb_config *cfg = ctx->rcb_config;
+	unsigned long virt_addr;
+	int i;
+
+	if (!cfg)
+		return;
+
+	for (i = 0; i < cfg->rcb_count; i++) {
+		size_t rcb_size = cfg->rcb_bufs[i].size;
+
+		if (!cfg->rcb_bufs[i].cpu)
+			continue;
+
+		switch (cfg->rcb_bufs[i].type) {
+		case RKVDEC_ALLOC_SRAM:
+			virt_addr = (unsigned long)cfg->rcb_bufs[i].cpu;
+
+			if (dev->iommu_domain)
+				iommu_unmap(dev->iommu_domain, virt_addr, rcb_size);
+			gen_pool_free(dev->sram_pool, virt_addr, rcb_size);
+			break;
+		case RKVDEC_ALLOC_DMA:
+			dma_free_coherent(dev->dev,
+					  rcb_size,
+					  cfg->rcb_bufs[i].cpu,
+					  cfg->rcb_bufs[i].dma);
+			break;
+		}
+	}
+
+	if (cfg->rcb_bufs)
+		devm_kfree(dev->dev, cfg->rcb_bufs);
+
+	devm_kfree(dev->dev, cfg);
+}
+
+int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx,
+			const struct rcb_size_info *size_info,
+			size_t rcb_count)
+{
+	int ret, i;
+	u32 width, height;
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_rcb_config *cfg;
+
+	if (!size_info || !rcb_count) {
+		ctx->rcb_config = NULL;
+		return 0;
+	}
+
+	ctx->rcb_config = devm_kzalloc(rkvdec->dev, sizeof(*ctx->rcb_config), GFP_KERNEL);
+	if (!ctx->rcb_config)
+		return -ENOMEM;
+
+	cfg = ctx->rcb_config;
+
+	cfg->rcb_bufs = devm_kzalloc(rkvdec->dev, sizeof(*cfg->rcb_bufs) * rcb_count, GFP_KERNEL);
+	if (!cfg->rcb_bufs) {
+		ret = -ENOMEM;
+		goto err_alloc;
+	}
+
+	width = ctx->decoded_fmt.fmt.pix_mp.width;
+	height = ctx->decoded_fmt.fmt.pix_mp.height;
+
+	for (i = 0; i < rcb_count; i++) {
+		void *cpu = NULL;
+		dma_addr_t dma;
+		size_t rcb_size = rkvdec_rcb_size(&size_info[i], width, height);
+		enum rkvdec_alloc_type alloc_type = RKVDEC_ALLOC_SRAM;
+
+		/* Try allocating an SRAM buffer */
+		if (ctx->dev->sram_pool) {
+			if (rkvdec->iommu_domain)
+				rcb_size = ALIGN(rcb_size, 0x1000);
+
+			cpu = gen_pool_dma_zalloc_align(ctx->dev->sram_pool,
+							rcb_size,
+							&dma,
+							0x1000);
+		}
+
+		/* If an IOMMU is used, map the SRAM address through it */
+		if (cpu && rkvdec->iommu_domain) {
+			unsigned long virt_addr = (unsigned long)cpu;
+			phys_addr_t phys_addr = dma;
+
+			ret = iommu_map(rkvdec->iommu_domain, virt_addr, phys_addr,
+					rcb_size, IOMMU_READ | IOMMU_WRITE, 0);
+			if (ret) {
+				gen_pool_free(ctx->dev->sram_pool,
+					      (unsigned long)cpu,
+					      rcb_size);
+				cpu = NULL;
+				goto ram_fallback;
+			}
+
+			/*
+			 * The registers will be configured with the virtual
+			 * address so that it goes through the IOMMU
+			 */
+			dma = virt_addr;
+		}
+
+ram_fallback:
+		/* Fallback to RAM */
+		if (!cpu) {
+			cpu = dma_alloc_coherent(ctx->dev->dev,
+						 rcb_size,
+						 &dma,
+						 GFP_KERNEL);
+			alloc_type = RKVDEC_ALLOC_DMA;
+		}
+
+		if (!cpu) {
+			ret = -ENOMEM;
+			goto err_alloc;
+		}
+
+		cfg->rcb_bufs[i].cpu = cpu;
+		cfg->rcb_bufs[i].dma = dma;
+		cfg->rcb_bufs[i].size = rcb_size;
+		cfg->rcb_bufs[i].type = alloc_type;
+
+		cfg->rcb_count += 1;
+	}
+
+	return 0;
+
+err_alloc:
+	rkvdec_free_rcb(ctx);
+
+	return ret;
+}
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h
new file mode 100644
index 000000000000..30e8002555c8
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Rockchip video decoder Rows and Cols Buffers manager
+ *
+ * Copyright (C) 2025 Collabora, Ltd.
+ *  Detlev Casanova <detlev.casanova at collabora.com>
+ */
+
+#include <linux/types.h>
+
+struct rkvdec_ctx;
+
+enum rcb_axis {
+	PIC_WIDTH = 0,
+	PIC_HEIGHT = 1
+};
+
+struct rcb_size_info {
+	u8 multiplier;
+	enum rcb_axis axis;
+};
+
+int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx,
+			const struct rcb_size_info *size_info,
+			size_t rcb_count);
+dma_addr_t rkvdec_rcb_buf_dma_addr(struct rkvdec_ctx *ctx, int id);
+size_t rkvdec_rcb_buf_size(struct rkvdec_ctx *ctx, int id);
+int rkvdec_rcb_buf_count(struct rkvdec_ctx *ctx);
+void rkvdec_free_rcb(struct rkvdec_ctx *ctx);
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index 968982f6e62c..028ce8e1c4ca 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -10,6 +10,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/genalloc.h>
 #include <linux/interrupt.h>
 #include <linux/iommu.h>
 #include <linux/module.h>
@@ -28,6 +29,7 @@
 
 #include "rkvdec.h"
 #include "rkvdec-regs.h"
+#include "rkvdec-rcb.h"
 
 static bool rkvdec_image_fmt_match(enum rkvdec_image_fmt fmt1,
 				   enum rkvdec_image_fmt fmt2)
@@ -771,6 +773,7 @@ static int rkvdec_start_streaming(struct vb2_queue *q, unsigned int count)
 {
 	struct rkvdec_ctx *ctx = vb2_get_drv_priv(q);
 	const struct rkvdec_coded_fmt_desc *desc;
+	const struct rkvdec_variant *variant = ctx->dev->variant;
 	int ret;
 
 	if (V4L2_TYPE_IS_CAPTURE(q->type))
@@ -780,13 +783,22 @@ static int rkvdec_start_streaming(struct vb2_queue *q, unsigned int count)
 	if (WARN_ON(!desc))
 		return -EINVAL;
 
+	ret = rkvdec_allocate_rcb(ctx, variant->rcb_sizes, variant->num_rcb_sizes);
+	if (ret)
+		return ret;
+
 	if (desc->ops->start) {
 		ret = desc->ops->start(ctx);
 		if (ret)
-			return ret;
+			goto err_ops_start;
 	}
 
 	return 0;
+
+err_ops_start:
+	rkvdec_free_rcb(ctx);
+
+	return ret;
 }
 
 static void rkvdec_queue_cleanup(struct vb2_queue *vq, u32 state)
@@ -822,6 +834,8 @@ static void rkvdec_stop_streaming(struct vb2_queue *q)
 
 		if (desc->ops->stop)
 			desc->ops->stop(ctx);
+
+		rkvdec_free_rcb(ctx);
 	}
 
 	rkvdec_queue_cleanup(q, VB2_BUF_STATE_ERROR);
@@ -1348,6 +1362,10 @@ static int rkvdec_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	rkvdec->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0);
+	if (!rkvdec->sram_pool && rkvdec->variant->num_rcb_sizes > 0)
+		dev_info(&pdev->dev, "No sram node, RCB will be stored in RAM\n");
+
 	pm_runtime_set_autosuspend_delay(&pdev->dev, 100);
 	pm_runtime_use_autosuspend(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
@@ -1356,7 +1374,8 @@ static int rkvdec_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_disable_runtime_pm;
 
-	if (iommu_get_domain_for_dev(&pdev->dev)) {
+	rkvdec->iommu_domain = iommu_get_domain_for_dev(&pdev->dev);
+	if (rkvdec->iommu_domain) {
 		rkvdec->empty_domain = iommu_paging_domain_alloc(rkvdec->dev);
 
 		if (IS_ERR(rkvdec->empty_domain)) {
@@ -1370,6 +1389,10 @@ static int rkvdec_probe(struct platform_device *pdev)
 err_disable_runtime_pm:
 	pm_runtime_dont_use_autosuspend(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
+
+	if (rkvdec->sram_pool)
+		gen_pool_destroy(rkvdec->sram_pool);
+
 	return ret;
 }
 
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
index aac6cba4c623..77c0950a465d 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
@@ -19,6 +19,7 @@
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
 #include <media/videobuf2-core.h>
 #include <media/videobuf2-dma-contig.h>
 
@@ -29,6 +30,7 @@
 #define RKVDEC_QUIRK_DISABLE_QOS	BIT(0)
 
 struct rkvdec_ctx;
+struct rkvdec_rcb_config;
 
 struct rkvdec_ctrl_desc {
 	struct v4l2_ctrl_config cfg;
@@ -73,6 +75,8 @@ struct rkvdec_variant {
 	unsigned int num_regs;
 	const struct rkvdec_coded_fmt_desc *coded_fmts;
 	size_t num_coded_fmts;
+	const struct rcb_size_info *rcb_sizes;
+	size_t num_rcb_sizes;
 	unsigned int capabilities;
 	unsigned int quirks;
 };
@@ -125,6 +129,8 @@ struct rkvdec_dev {
 	void __iomem *regs;
 	struct mutex vdev_lock; /* serializes ioctls */
 	struct delayed_work watchdog_work;
+	struct gen_pool *sram_pool;
+	struct iommu_domain *iommu_domain;
 	struct iommu_domain *empty_domain;
 	const struct rkvdec_variant *variant;
 };
@@ -137,6 +143,7 @@ struct rkvdec_ctx {
 	struct v4l2_ctrl_handler ctrl_hdl;
 	struct rkvdec_dev *dev;
 	enum rkvdec_image_fmt image_fmt;
+	struct rkvdec_rcb_config *rcb_config;
 	void *priv;
 };
 
@@ -145,10 +152,16 @@ static inline struct rkvdec_ctx *file_to_rkvdec_ctx(struct file *filp)
 	return container_of(file_to_v4l2_fh(filp), struct rkvdec_ctx, fh);
 }
 
+enum rkvdec_alloc_type {
+	RKVDEC_ALLOC_DMA  = 0,
+	RKVDEC_ALLOC_SRAM = 1,
+};
+
 struct rkvdec_aux_buf {
 	void *cpu;
 	dma_addr_t dma;
 	size_t size;
+	enum rkvdec_alloc_type type;
 };
 
 void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run);
-- 
2.52.0



From detlev.casanova at collabora.com  Wed Dec 17 09:40:48 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 17 Dec 2025 12:40:48 -0500
Subject: [PATCH v6 11/17] media: rkvdec: Support per-variant interrupt handler
In-Reply-To: <20251217174059.1341784-1-detlev.casanova@collabora.com>
References: <20251217174059.1341784-1-detlev.casanova@collabora.com>
Message-ID: <20251217174059.1341784-12-detlev.casanova@collabora.com>

Prepare for supporting different variants with different interrupt
managers.

To support other variants specific function type later, introduce the
rkvdec_variant_ops struct.

Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../media/platform/rockchip/rkvdec/rkvdec.c   | 21 ++++++++++++++++---
 .../media/platform/rockchip/rkvdec/rkvdec.h   |  5 +++++
 2 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index 028ce8e1c4ca..87373a6d9573 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -1218,10 +1218,9 @@ static void rkvdec_iommu_restore(struct rkvdec_dev *rkvdec)
 	}
 }
 
-static irqreturn_t rkvdec_irq_handler(int irq, void *priv)
+static irqreturn_t rk3399_irq_handler(struct rkvdec_ctx *ctx)
 {
-	struct rkvdec_dev *rkvdec = priv;
-	struct rkvdec_ctx *ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev);
+	struct rkvdec_dev *rkvdec = ctx->dev;
 	enum vb2_buffer_state state;
 	u32 status;
 
@@ -1242,6 +1241,15 @@ static irqreturn_t rkvdec_irq_handler(int irq, void *priv)
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t rkvdec_irq_handler(int irq, void *priv)
+{
+	struct rkvdec_dev *rkvdec = priv;
+	struct rkvdec_ctx *ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev);
+	const struct rkvdec_variant *variant = rkvdec->variant;
+
+	return variant->ops->irq_handler(ctx);
+}
+
 static void rkvdec_watchdog_func(struct work_struct *work)
 {
 	struct rkvdec_dev *rkvdec;
@@ -1257,10 +1265,15 @@ static void rkvdec_watchdog_func(struct work_struct *work)
 	}
 }
 
+static const struct rkvdec_variant_ops rk3399_variant_ops = {
+	.irq_handler = rk3399_irq_handler,
+};
+
 static const struct rkvdec_variant rk3288_rkvdec_variant = {
 	.num_regs = 68,
 	.coded_fmts = rkvdec_coded_fmts,
 	.num_coded_fmts = ARRAY_SIZE(rkvdec_coded_fmts),
+	.ops = &rk3399_variant_ops,
 	.capabilities = RKVDEC_CAPABILITY_HEVC,
 };
 
@@ -1268,6 +1281,7 @@ static const struct rkvdec_variant rk3328_rkvdec_variant = {
 	.num_regs = 109,
 	.coded_fmts = rkvdec_coded_fmts,
 	.num_coded_fmts = ARRAY_SIZE(rkvdec_coded_fmts),
+	.ops = &rk3399_variant_ops,
 	.capabilities = RKVDEC_CAPABILITY_HEVC |
 			RKVDEC_CAPABILITY_H264 |
 			RKVDEC_CAPABILITY_VP9,
@@ -1278,6 +1292,7 @@ static const struct rkvdec_variant rk3399_rkvdec_variant = {
 	.num_regs = 78,
 	.coded_fmts = rkvdec_coded_fmts,
 	.num_coded_fmts = ARRAY_SIZE(rkvdec_coded_fmts),
+	.ops = &rk3399_variant_ops,
 	.capabilities = RKVDEC_CAPABILITY_HEVC |
 			RKVDEC_CAPABILITY_H264 |
 			RKVDEC_CAPABILITY_VP9,
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
index 77c0950a465d..12e53d591362 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
@@ -71,12 +71,17 @@ vb2_to_rkvdec_decoded_buf(struct vb2_buffer *buf)
 			    base.vb.vb2_buf);
 }
 
+struct rkvdec_variant_ops {
+	irqreturn_t (*irq_handler)(struct rkvdec_ctx *ctx);
+};
+
 struct rkvdec_variant {
 	unsigned int num_regs;
 	const struct rkvdec_coded_fmt_desc *coded_fmts;
 	size_t num_coded_fmts;
 	const struct rcb_size_info *rcb_sizes;
 	size_t num_rcb_sizes;
+	const struct rkvdec_variant_ops *ops;
 	unsigned int capabilities;
 	unsigned int quirks;
 };
-- 
2.52.0



From detlev.casanova at collabora.com  Wed Dec 17 09:40:49 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 17 Dec 2025 12:40:49 -0500
Subject: [PATCH v6 12/17] media: rkvdec: Enable all clocks without naming them
In-Reply-To: <20251217174059.1341784-1-detlev.casanova@collabora.com>
References: <20251217174059.1341784-1-detlev.casanova@collabora.com>
Message-ID: <20251217174059.1341784-13-detlev.casanova@collabora.com>

For other variants, the clock names and number will differ.

There is no need to keep track of the clock names in the driver so drop
them to avoid having a list for each variant.

Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../media/platform/rockchip/rkvdec/rkvdec.c   | 26 +++++--------------
 .../media/platform/rockchip/rkvdec/rkvdec.h   |  1 +
 2 files changed, 7 insertions(+), 20 deletions(-)

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index 87373a6d9573..9bd98b6a6be7 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -1315,15 +1315,10 @@ static const struct of_device_id of_rkvdec_match[] = {
 };
 MODULE_DEVICE_TABLE(of, of_rkvdec_match);
 
-static const char * const rkvdec_clk_names[] = {
-	"axi", "ahb", "cabac", "core"
-};
-
 static int rkvdec_probe(struct platform_device *pdev)
 {
 	const struct rkvdec_variant *variant;
 	struct rkvdec_dev *rkvdec;
-	unsigned int i;
 	int ret, irq;
 
 	variant = of_device_get_match_data(&pdev->dev);
@@ -1340,19 +1335,12 @@ static int rkvdec_probe(struct platform_device *pdev)
 	mutex_init(&rkvdec->vdev_lock);
 	INIT_DELAYED_WORK(&rkvdec->watchdog_work, rkvdec_watchdog_func);
 
-	rkvdec->clocks = devm_kcalloc(&pdev->dev, ARRAY_SIZE(rkvdec_clk_names),
-				      sizeof(*rkvdec->clocks), GFP_KERNEL);
-	if (!rkvdec->clocks)
-		return -ENOMEM;
-
-	for (i = 0; i < ARRAY_SIZE(rkvdec_clk_names); i++)
-		rkvdec->clocks[i].id = rkvdec_clk_names[i];
-
-	ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(rkvdec_clk_names),
-				rkvdec->clocks);
-	if (ret)
+	ret = devm_clk_bulk_get_all_enabled(&pdev->dev, &rkvdec->clocks);
+	if (ret < 0)
 		return ret;
 
+	rkvdec->num_clocks = ret;
+
 	rkvdec->regs = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(rkvdec->regs))
 		return PTR_ERR(rkvdec->regs);
@@ -1430,16 +1418,14 @@ static int rkvdec_runtime_resume(struct device *dev)
 {
 	struct rkvdec_dev *rkvdec = dev_get_drvdata(dev);
 
-	return clk_bulk_prepare_enable(ARRAY_SIZE(rkvdec_clk_names),
-				       rkvdec->clocks);
+	return clk_bulk_prepare_enable(rkvdec->num_clocks, rkvdec->clocks);
 }
 
 static int rkvdec_runtime_suspend(struct device *dev)
 {
 	struct rkvdec_dev *rkvdec = dev_get_drvdata(dev);
 
-	clk_bulk_disable_unprepare(ARRAY_SIZE(rkvdec_clk_names),
-				   rkvdec->clocks);
+	clk_bulk_disable_unprepare(rkvdec->num_clocks, rkvdec->clocks);
 	return 0;
 }
 #endif
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
index 12e53d591362..75a9ba988794 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
@@ -131,6 +131,7 @@ struct rkvdec_dev {
 	struct v4l2_m2m_dev *m2m_dev;
 	struct device *dev;
 	struct clk_bulk_data *clocks;
+	unsigned int num_clocks;
 	void __iomem *regs;
 	struct mutex vdev_lock; /* serializes ioctls */
 	struct delayed_work watchdog_work;
-- 
2.52.0



From detlev.casanova at collabora.com  Wed Dec 17 09:40:50 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 17 Dec 2025 12:40:50 -0500
Subject: [PATCH v6 13/17] media: rkvdec: Disable multicore support
In-Reply-To: <20251217174059.1341784-1-detlev.casanova@collabora.com>
References: <20251217174059.1341784-1-detlev.casanova@collabora.com>
Message-ID: <20251217174059.1341784-14-detlev.casanova@collabora.com>

Similarly to what is done in Hantro, avoid exposing equal video codecs to
userspace. Equal video codecs allow scheduling work between the cores.
For that kernel support is required, which does not yet exist.
Until that is implemented, avoid exposing each core separately to
userspace so that multicore can be added in the future without breaking
userspace ABI.

This currently applies only to RK3588 which has 2 equal VDPU381 decoders,
but will be applied for all SoC supported by rkvdec that has multiple DTS
nodes with the same compatible.

Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../media/platform/rockchip/rkvdec/rkvdec.c   | 47 +++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index 9bd98b6a6be7..f7353d0acdab 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -1265,6 +1265,49 @@ static void rkvdec_watchdog_func(struct work_struct *work)
 	}
 }
 
+/*
+ * Some SoCs, like RK3588 have multiple identical VDPU cores, but the
+ * kernel is currently missing support for multi-core handling. Exposing
+ * separate devices for each core to userspace is bad, since that does
+ * not allow scheduling tasks properly (and creates ABI). With this workaround
+ * the driver will only probe for the first core and early exit for the other
+ * cores. Once the driver gains multi-core support, the same technique
+ * for detecting the first core can be used to cluster all cores together.
+ */
+static int rkvdec_disable_multicore(struct rkvdec_dev *rkvdec)
+{
+	struct device_node *node = NULL;
+	const char *compatible;
+	bool is_first_core;
+	int ret;
+
+	/* Intentionally ignores the fallback strings */
+	ret = of_property_read_string(rkvdec->dev->of_node, "compatible", &compatible);
+	if (ret)
+		return ret;
+
+	/* The first compatible and available node found is considered the main core */
+	do {
+		node = of_find_compatible_node(node, NULL, compatible);
+		if (of_device_is_available(node))
+			break;
+	} while (node);
+
+	if (!node)
+		return -EINVAL;
+
+	is_first_core = (rkvdec->dev->of_node == node);
+
+	of_node_put(node);
+
+	if (!is_first_core) {
+		dev_info(rkvdec->dev, "missing multi-core support, ignoring this instance\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
 static const struct rkvdec_variant_ops rk3399_variant_ops = {
 	.irq_handler = rk3399_irq_handler,
 };
@@ -1335,6 +1378,10 @@ static int rkvdec_probe(struct platform_device *pdev)
 	mutex_init(&rkvdec->vdev_lock);
 	INIT_DELAYED_WORK(&rkvdec->watchdog_work, rkvdec_watchdog_func);
 
+	ret = rkvdec_disable_multicore(rkvdec);
+	if (ret)
+		return ret;
+
 	ret = devm_clk_bulk_get_all_enabled(&pdev->dev, &rkvdec->clocks);
 	if (ret < 0)
 		return ret;
-- 
2.52.0



From detlev.casanova at collabora.com  Wed Dec 17 09:40:51 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 17 Dec 2025 12:40:51 -0500
Subject: [PATCH v6 14/17] media: rkvdec: Add H264 support for the VDPU381 variant
In-Reply-To: <20251217174059.1341784-1-detlev.casanova@collabora.com>
References: <20251217174059.1341784-1-detlev.casanova@collabora.com>
Message-ID: <20251217174059.1341784-15-detlev.casanova@collabora.com>

This decoder variant is found in Rockchip RK3588 SoC family.

Like for rkvdec on rk3399, it supports the NV12, NV15, NV16 and NV20
output formats and level up to 5.1.

The maximum width and height have been significantly increased
supporting up to 65520 pixels for both.

Also make sure to only expose the first core and ignore the other
until mutli-core is supported.

Fluster score for JVT-AVC_V1 is 129/135.

Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../media/platform/rockchip/rkvdec/Makefile   |   1 +
 .../rockchip/rkvdec/rkvdec-h264-common.h      |   2 +
 .../rockchip/rkvdec/rkvdec-vdpu381-h264.c     | 469 ++++++++++++++++++
 .../rockchip/rkvdec/rkvdec-vdpu381-regs.h     | 424 ++++++++++++++++
 .../media/platform/rockchip/rkvdec/rkvdec.c   |  84 ++++
 .../media/platform/rockchip/rkvdec/rkvdec.h   |   8 +
 6 files changed, 988 insertions(+)
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h

diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
index 3d75103e536d..7bfd95151e40 100644
--- a/drivers/media/platform/rockchip/rkvdec/Makefile
+++ b/drivers/media/platform/rockchip/rkvdec/Makefile
@@ -8,4 +8,5 @@ rockchip-vdec-y += \
 		   rkvdec-hevc.o \
 		   rkvdec-hevc-common.o \
 		   rkvdec-rcb.o \
+		   rkvdec-vdpu381-h264.o \
 		   rkvdec-vp9.o
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h
index bd0c0081365b..3be6cea3a758 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h
@@ -74,6 +74,8 @@ struct rkvdec_rps {
 	u32 reserved1[66];
 } __packed;
 
+extern const s8 rkvdec_h264_cabac_table[4][464][2];
+
 void lookup_ref_buf_idx(struct rkvdec_ctx *ctx, struct rkvdec_h264_run *run);
 void assemble_hw_rps(struct v4l2_h264_reflist_builder *builder,
 		     struct rkvdec_h264_run *run,
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c
new file mode 100644
index 000000000000..e65a56bc9c63
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c
@@ -0,0 +1,469 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip VDPU381 Video Decoder H264 backend
+ *
+ * Copyright (C) 2024 Collabora, Ltd.
+ *  Detlev Casanova <detlev.casanova at collabora.com>
+ */
+
+#include <media/v4l2-h264.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "rkvdec.h"
+#include "rkvdec-rcb.h"
+#include "rkvdec-h264-common.h"
+#include "rkvdec-vdpu381-regs.h"
+
+struct rkvdec_sps {
+	u16 seq_parameter_set_id:			4;
+	u16 profile_idc:				8;
+	u16 constraint_set3_flag:			1;
+	u16 chroma_format_idc:				2;
+	u16 bit_depth_luma:				3;
+	u16 bit_depth_chroma:				3;
+	u16 qpprime_y_zero_transform_bypass_flag:	1;
+	u16 log2_max_frame_num_minus4:			4;
+	u16 max_num_ref_frames:				5;
+	u16 pic_order_cnt_type:				2;
+	u16 log2_max_pic_order_cnt_lsb_minus4:		4;
+	u16 delta_pic_order_always_zero_flag:		1;
+	u16 pic_width_in_mbs:				12;
+	u16 pic_height_in_mbs:				12;
+	u16 frame_mbs_only_flag:			1;
+	u16 mb_adaptive_frame_field_flag:		1;
+	u16 direct_8x8_inference_flag:			1;
+	u16 mvc_extension_enable:			1;
+	u16 num_views:					2;
+
+	u16 reserved_bits:				12;
+	u16 reserved[11];
+} __packed;
+
+struct rkvdec_pps {
+	u16 pic_parameter_set_id:				8;
+	u16 pps_seq_parameter_set_id:				5;
+	u16 entropy_coding_mode_flag:				1;
+	u16 bottom_field_pic_order_in_frame_present_flag:	1;
+	u16 num_ref_idx_l0_default_active_minus1:		5;
+	u16 num_ref_idx_l1_default_active_minus1:		5;
+	u16 weighted_pred_flag:					1;
+	u16 weighted_bipred_idc:				2;
+	u16 pic_init_qp_minus26:				7;
+	u16 pic_init_qs_minus26:				6;
+	u16 chroma_qp_index_offset:				5;
+	u16 deblocking_filter_control_present_flag:		1;
+	u16 constrained_intra_pred_flag:			1;
+	u16 redundant_pic_cnt_present:				1;
+	u16 transform_8x8_mode_flag:				1;
+	u16 second_chroma_qp_index_offset:			5;
+	u16 scaling_list_enable_flag:				1;
+	u32 scaling_list_address;
+	u16 is_longterm;
+
+	u8 reserved[3];
+} __packed;
+
+struct rkvdec_sps_pps {
+	struct rkvdec_sps sps;
+	struct rkvdec_pps pps;
+} __packed;
+
+/* Data structure describing auxiliary buffer format. */
+struct rkvdec_h264_priv_tbl {
+	s8 cabac_table[4][464][2];
+	struct rkvdec_h264_scaling_list scaling_list;
+	struct rkvdec_sps_pps param_set[256];
+	struct rkvdec_rps rps;
+};
+
+struct rkvdec_h264_ctx {
+	struct rkvdec_aux_buf priv_tbl;
+	struct rkvdec_h264_reflists reflists;
+	struct rkvdec_vdpu381_regs_h264 regs;
+};
+
+static void assemble_hw_pps(struct rkvdec_ctx *ctx,
+			    struct rkvdec_h264_run *run)
+{
+	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
+	const struct v4l2_ctrl_h264_sps *sps = run->sps;
+	const struct v4l2_ctrl_h264_pps *pps = run->pps;
+	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
+	const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb;
+	struct rkvdec_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu;
+	struct rkvdec_sps_pps *hw_ps;
+	dma_addr_t scaling_list_address;
+	u32 scaling_distance;
+	u32 i;
+
+	/*
+	 * HW read the SPS/PPS information from PPS packet index by PPS id.
+	 * offset from the base can be calculated by PPS_id * 32 (size per PPS
+	 * packet unit). so the driver copy SPS/PPS information to the exact PPS
+	 * packet unit for HW accessing.
+	 */
+	hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id];
+	memset(hw_ps, 0, sizeof(*hw_ps));
+
+	/* write sps */
+	hw_ps->sps.seq_parameter_set_id = sps->seq_parameter_set_id;
+	hw_ps->sps.profile_idc = sps->profile_idc;
+	hw_ps->sps.constraint_set3_flag = !!(sps->constraint_set_flags & (1 << 3));
+	hw_ps->sps.chroma_format_idc = sps->chroma_format_idc;
+	hw_ps->sps.bit_depth_luma = sps->bit_depth_luma_minus8;
+	hw_ps->sps.bit_depth_chroma = sps->bit_depth_chroma_minus8;
+	hw_ps->sps.qpprime_y_zero_transform_bypass_flag =
+		!!(sps->flags & V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS);
+	hw_ps->sps.log2_max_frame_num_minus4 = sps->log2_max_frame_num_minus4;
+	hw_ps->sps.max_num_ref_frames = sps->max_num_ref_frames;
+	hw_ps->sps.pic_order_cnt_type = sps->pic_order_cnt_type;
+	hw_ps->sps.log2_max_pic_order_cnt_lsb_minus4 =
+		sps->log2_max_pic_order_cnt_lsb_minus4;
+	hw_ps->sps.delta_pic_order_always_zero_flag =
+		!!(sps->flags & V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO);
+	hw_ps->sps.mvc_extension_enable = 1;
+	hw_ps->sps.num_views = 1;
+
+	/*
+	 * Use the SPS values since they are already in macroblocks
+	 * dimensions, height can be field height (halved) if
+	 * V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY is not set and also it allows
+	 * decoding smaller images into larger allocation which can be used
+	 * to implementing SVC spatial layer support.
+	 */
+	hw_ps->sps.pic_width_in_mbs = sps->pic_width_in_mbs_minus1 + 1;
+	hw_ps->sps.pic_height_in_mbs = sps->pic_height_in_map_units_minus1 + 1;
+	hw_ps->sps.frame_mbs_only_flag =
+		!!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY);
+	hw_ps->sps.mb_adaptive_frame_field_flag =
+		!!(sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD);
+	hw_ps->sps.direct_8x8_inference_flag =
+		!!(sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE);
+
+	/* write pps */
+	hw_ps->pps.pic_parameter_set_id = pps->pic_parameter_set_id;
+	hw_ps->pps.pps_seq_parameter_set_id = pps->seq_parameter_set_id;
+	hw_ps->pps.entropy_coding_mode_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE);
+	hw_ps->pps.bottom_field_pic_order_in_frame_present_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT);
+	hw_ps->pps.num_ref_idx_l0_default_active_minus1 =
+		pps->num_ref_idx_l0_default_active_minus1;
+	hw_ps->pps.num_ref_idx_l1_default_active_minus1 =
+		pps->num_ref_idx_l1_default_active_minus1;
+	hw_ps->pps.weighted_pred_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED);
+	hw_ps->pps.weighted_bipred_idc = pps->weighted_bipred_idc;
+	hw_ps->pps.pic_init_qp_minus26 = pps->pic_init_qp_minus26;
+	hw_ps->pps.pic_init_qs_minus26 = pps->pic_init_qs_minus26;
+	hw_ps->pps.chroma_qp_index_offset = pps->chroma_qp_index_offset;
+	hw_ps->pps.deblocking_filter_control_present_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT);
+	hw_ps->pps.constrained_intra_pred_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED);
+	hw_ps->pps.redundant_pic_cnt_present =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT);
+	hw_ps->pps.transform_8x8_mode_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE);
+	hw_ps->pps.second_chroma_qp_index_offset = pps->second_chroma_qp_index_offset;
+	hw_ps->pps.scaling_list_enable_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT);
+
+	/*
+	 * To be on the safe side, program the scaling matrix address
+	 */
+	scaling_distance = offsetof(struct rkvdec_h264_priv_tbl, scaling_list);
+	scaling_list_address = h264_ctx->priv_tbl.dma + scaling_distance;
+	hw_ps->pps.scaling_list_address = scaling_list_address;
+
+	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
+		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
+			hw_ps->pps.is_longterm |= (1 << i);
+	}
+}
+
+static void rkvdec_write_regs(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
+
+	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_REGS,
+			   &h264_ctx->regs.common,
+			   sizeof(h264_ctx->regs.common));
+	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_PARAMS_REGS,
+			   &h264_ctx->regs.h264_param,
+			   sizeof(h264_ctx->regs.h264_param));
+	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_ADDR_REGS,
+			   &h264_ctx->regs.common_addr,
+			   sizeof(h264_ctx->regs.common_addr));
+	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_ADDR_REGS,
+			   &h264_ctx->regs.h264_addr,
+			   sizeof(h264_ctx->regs.h264_addr));
+	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_POC_HIGHBIT_REGS,
+			   &h264_ctx->regs.h264_highpoc,
+			   sizeof(h264_ctx->regs.h264_highpoc));
+}
+
+static void config_registers(struct rkvdec_ctx *ctx,
+			     struct rkvdec_h264_run *run)
+{
+	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
+	const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb;
+	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
+	dma_addr_t priv_start_addr = h264_ctx->priv_tbl.dma;
+	const struct v4l2_pix_format_mplane *dst_fmt;
+	struct vb2_v4l2_buffer *src_buf = run->base.bufs.src;
+	struct vb2_v4l2_buffer *dst_buf = run->base.bufs.dst;
+	struct rkvdec_vdpu381_regs_h264 *regs = &h264_ctx->regs;
+	const struct v4l2_format *f;
+	dma_addr_t rlc_addr;
+	dma_addr_t dst_addr;
+	u32 hor_virstride;
+	u32 ver_virstride;
+	u32 y_virstride;
+	u32 offset;
+	u32 pixels;
+	u32 i;
+
+	memset(regs, 0, sizeof(*regs));
+
+	/* Set H264 mode */
+	regs->common.reg009.dec_mode = VDPU381_MODE_H264;
+
+	/* Set config */
+	regs->common.reg011.buf_empty_en = 1;
+	regs->common.reg011.dec_clkgate_e = 1;
+	regs->common.reg011.dec_timeout_e = 1;
+	regs->common.reg011.pix_range_detection_e = 1;
+
+	/*
+	 * Even though the scan list address can be set in RPS,
+	 * with some frames, it will try to use the address set in the register.
+	 */
+	regs->common.reg012.scanlist_addr_valid_en = 1;
+
+	/* Set IDR flag */
+	regs->common.reg013.cur_pic_is_idr =
+		!!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC);
+
+	/* Set input stream length */
+	regs->common.stream_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
+
+	/* Set max slice number */
+	regs->common.reg017.slice_num = MAX_SLICE_NUMBER;
+
+	/* Set strides */
+	f = &ctx->decoded_fmt;
+	dst_fmt = &f->fmt.pix_mp;
+	hor_virstride = dst_fmt->plane_fmt[0].bytesperline;
+	ver_virstride = dst_fmt->height;
+	y_virstride = hor_virstride * ver_virstride;
+
+	pixels = dst_fmt->height * dst_fmt->width;
+
+	regs->common.reg018.y_hor_virstride = hor_virstride / 16;
+	regs->common.reg019.uv_hor_virstride = hor_virstride / 16;
+	regs->common.reg020.y_virstride = y_virstride / 16;
+
+	/* Activate block gating */
+	regs->common.reg026.swreg_block_gating_e = 0xfffef;
+	regs->common.reg026.reg_cfg_gating_en = 1;
+
+	/* Set timeout threshold */
+	if (pixels < RKVDEC_1080P_PIXELS)
+		regs->common.timeout_threshold = RKVDEC_TIMEOUT_1080p;
+	else if (pixels < RKVDEC_4K_PIXELS)
+		regs->common.timeout_threshold = RKVDEC_TIMEOUT_4K;
+	else if (pixels < RKVDEC_8K_PIXELS)
+		regs->common.timeout_threshold = RKVDEC_TIMEOUT_8K;
+	else
+		regs->common.timeout_threshold = RKVDEC_TIMEOUT_MAX;
+
+	/* Set TOP and BOTTOM POCs */
+	regs->h264_param.cur_top_poc = dec_params->top_field_order_cnt;
+	regs->h264_param.cur_bot_poc = dec_params->bottom_field_order_cnt;
+
+	/* Set ref pic address & poc */
+	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
+		struct vb2_buffer *vb_buf = run->ref_buf[i];
+		dma_addr_t buf_dma;
+
+		/*
+		 * If a DPB entry is unused or invalid, address of current destination
+		 * buffer is returned.
+		 */
+		if (!vb_buf)
+			vb_buf = &dst_buf->vb2_buf;
+
+		buf_dma = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
+
+		/* Set reference addresses */
+		regs->h264_addr.ref_base[i] = buf_dma;
+
+		/* Set COLMV addresses */
+		regs->h264_addr.colmv_base[i] = buf_dma + ctx->colmv_offset;
+
+		struct rkvdec_vdpu381_h264_ref_info *ref_info =
+			&regs->h264_param.ref_info_regs[i / 4].ref_info[i % 4];
+
+		ref_info->ref_field =
+			!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD);
+		ref_info->ref_colmv_use_flag =
+			!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE);
+		ref_info->ref_topfield_used =
+			!!(dpb[i].fields & V4L2_H264_TOP_FIELD_REF);
+		ref_info->ref_botfield_used =
+			!!(dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF);
+
+		regs->h264_param.ref_pocs[i * 2] =
+			dpb[i].top_field_order_cnt;
+		regs->h264_param.ref_pocs[i * 2 + 1] =
+			dpb[i].bottom_field_order_cnt;
+	}
+
+	/* Set rlc base address (input stream) */
+	rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+	regs->common_addr.rlc_base = rlc_addr;
+	regs->common_addr.rlcwrite_base = rlc_addr;
+
+	/* Set output base address */
+	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
+	regs->common_addr.decout_base = dst_addr;
+	regs->common_addr.error_ref_base = dst_addr;
+
+	/* Set colmv address */
+	regs->common_addr.colmv_cur_base = dst_addr + ctx->colmv_offset;
+
+	/* Set RCB addresses */
+	for (i = 0; i < rkvdec_rcb_buf_count(ctx); i++)
+		regs->common_addr.rcb_base[i] = rkvdec_rcb_buf_dma_addr(ctx, i);
+
+	/* Set hw pps address */
+	offset = offsetof(struct rkvdec_h264_priv_tbl, param_set);
+	regs->h264_addr.pps_base = priv_start_addr + offset;
+
+	/* Set hw rps address */
+	offset = offsetof(struct rkvdec_h264_priv_tbl, rps);
+	regs->h264_addr.rps_base = priv_start_addr + offset;
+
+	/* Set cabac table */
+	offset = offsetof(struct rkvdec_h264_priv_tbl, cabac_table);
+	regs->h264_addr.cabactbl_base = priv_start_addr + offset;
+
+	offset = offsetof(struct rkvdec_h264_priv_tbl, scaling_list);
+	regs->h264_addr.scanlist_addr = priv_start_addr + offset;
+
+	rkvdec_write_regs(ctx);
+}
+
+static int rkvdec_h264_start(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_h264_priv_tbl *priv_tbl;
+	struct rkvdec_h264_ctx *h264_ctx;
+	struct v4l2_ctrl *ctrl;
+	int ret;
+
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_H264_SPS);
+	if (!ctrl)
+		return -EINVAL;
+
+	ret = rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps);
+	if (ret)
+		return ret;
+
+	h264_ctx = kzalloc(sizeof(*h264_ctx), GFP_KERNEL);
+	if (!h264_ctx)
+		return -ENOMEM;
+
+	priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl),
+				      &h264_ctx->priv_tbl.dma, GFP_KERNEL);
+	if (!priv_tbl) {
+		ret = -ENOMEM;
+		goto err_free_ctx;
+	}
+
+	h264_ctx->priv_tbl.size = sizeof(*priv_tbl);
+	h264_ctx->priv_tbl.cpu = priv_tbl;
+	memcpy(priv_tbl->cabac_table, rkvdec_h264_cabac_table,
+	       sizeof(rkvdec_h264_cabac_table));
+
+	ctx->priv = h264_ctx;
+	return 0;
+
+err_free_ctx:
+	kfree(h264_ctx);
+	return ret;
+}
+
+static void rkvdec_h264_stop(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
+	struct rkvdec_dev *rkvdec = ctx->dev;
+
+	dma_free_coherent(rkvdec->dev, h264_ctx->priv_tbl.size,
+			  h264_ctx->priv_tbl.cpu, h264_ctx->priv_tbl.dma);
+	kfree(h264_ctx);
+}
+
+static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
+{
+	struct v4l2_h264_reflist_builder reflist_builder;
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
+	struct rkvdec_h264_priv_tbl *tbl = h264_ctx->priv_tbl.cpu;
+	struct rkvdec_h264_run run;
+	u32 watchdog_time;
+
+	rkvdec_h264_run_preamble(ctx, &run);
+
+	/* Build the P/B{0,1} ref lists. */
+	v4l2_h264_init_reflist_builder(&reflist_builder, run.decode_params,
+				       run.sps, run.decode_params->dpb);
+	v4l2_h264_build_p_ref_list(&reflist_builder, h264_ctx->reflists.p);
+	v4l2_h264_build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0,
+				    h264_ctx->reflists.b1);
+
+	assemble_hw_scaling_list(&run, &tbl->scaling_list);
+	assemble_hw_pps(ctx, &run);
+	lookup_ref_buf_idx(ctx, &run);
+	assemble_hw_rps(&reflist_builder, &run, &h264_ctx->reflists, &tbl->rps);
+
+	config_registers(ctx, &run);
+
+	rkvdec_run_postamble(ctx, &run.base);
+
+	/* Set watchdog at 2 times the hardware timeout threshold */
+	u64 timeout_threshold = h264_ctx->regs.common.timeout_threshold;
+	unsigned long axi_rate = clk_get_rate(rkvdec->axi_clk);
+
+	if (axi_rate)
+		watchdog_time = 2 * (1000 * timeout_threshold) / axi_rate;
+	else
+		watchdog_time = 2000;
+	schedule_delayed_work(&rkvdec->watchdog_work,
+			      msecs_to_jiffies(watchdog_time));
+
+	/* Start decoding! */
+	writel(VDPU381_DEC_E_BIT, rkvdec->regs + VDPU381_REG_DEC_E);
+
+	return 0;
+}
+
+static int rkvdec_h264_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
+{
+	if (ctrl->id == V4L2_CID_STATELESS_H264_SPS)
+		return rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps);
+
+	return 0;
+}
+
+const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_h264_fmt_ops = {
+	.adjust_fmt = rkvdec_h264_adjust_fmt,
+	.get_image_fmt = rkvdec_h264_get_image_fmt,
+	.start = rkvdec_h264_start,
+	.stop = rkvdec_h264_stop,
+	.run = rkvdec_h264_run,
+	.try_ctrl = rkvdec_h264_try_ctrl,
+};
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h
new file mode 100644
index 000000000000..a9a2daa24048
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h
@@ -0,0 +1,424 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Rockchip VDPU381 Video Decoder driver registers description
+ *
+ * Copyright (C) 2024 Collabora, Ltd.
+ *  Detlev Casanova <detlev.casanova at collabora.com>
+ */
+
+#include <linux/types.h>
+
+#ifndef _RKVDEC_REGS_H_
+#define _RKVDEC_REGS_H_
+
+#define OFFSET_COMMON_REGS		(8 * sizeof(u32))
+#define OFFSET_CODEC_PARAMS_REGS	(64 * sizeof(u32))
+#define OFFSET_COMMON_ADDR_REGS		(128 * sizeof(u32))
+#define OFFSET_CODEC_ADDR_REGS		(160 * sizeof(u32))
+#define OFFSET_POC_HIGHBIT_REGS		(200 * sizeof(u32))
+
+#define VDPU381_MODE_HEVC	0
+#define VDPU381_MODE_H264	1
+#define VDPU381_MODE_VP9	2
+#define VDPU381_MODE_AVS2	3
+
+#define MAX_SLICE_NUMBER	0x3fff
+
+#define RKVDEC_TIMEOUT_1080p		(0xefffff)
+#define RKVDEC_TIMEOUT_4K		(0x2cfffff)
+#define RKVDEC_TIMEOUT_8K		(0x4ffffff)
+#define RKVDEC_TIMEOUT_MAX		(0xffffffff)
+
+#define VDPU381_REG_DEC_E		0x028
+#define VDPU381_DEC_E_BIT		1
+
+#define VDPU381_REG_IMPORTANT_EN	0x02c
+#define VDPU381_DEC_IRQ_DISABLE	BIT(4)
+
+#define VDPU381_REG_STA_INT		0x380
+#define VDPU381_STA_INT_DEC_RDY_STA	BIT(2)
+#define VDPU381_STA_INT_ERROR		BIT(4)
+#define VDPU381_STA_INT_TIMEOUT		BIT(5)
+#define VDPU381_STA_INT_SOFTRESET_RDY	BIT(9)
+
+/* base: OFFSET_COMMON_REGS */
+struct rkvdec_vdpu381_regs_common {
+	struct rkvdec_vdpu381_in_out {
+		u32 in_endian		: 1;
+		u32 in_swap32_e		: 1;
+		u32 in_swap64_e		: 1;
+		u32 str_endian		: 1;
+		u32 str_swap32_e	: 1;
+		u32 str_swap64_e	: 1;
+		u32 out_endian		: 1;
+		u32 out_swap32_e	: 1;
+		u32 out_cbcr_swap	: 1;
+		u32 out_swap64_e	: 1;
+		u32 reserved		: 22;
+	} reg008;
+
+	struct rkvdec_vdpu381_dec_mode {
+		u32 dec_mode	: 10;
+		u32 reserved	: 22;
+	} reg009;
+
+	struct rkvdec_vdpu381_dec_e {
+		u32 dec_e	: 1;
+		u32 reserved	: 31;
+	} reg010;
+
+	struct rkvdec_vdpu381_important_en {
+		u32 reserved			: 1;
+		u32 dec_clkgate_e		: 1;
+		u32 dec_e_strmd_clkgate_dis	: 1;
+		u32 reserved0			: 1;
+
+		u32 dec_irq_dis			: 1;
+		u32 dec_timeout_e		: 1;
+		u32 buf_empty_en		: 1;
+		u32 reserved1			: 3;
+
+		u32 dec_e_rewrite_valid		: 1;
+		u32 reserved2			: 9;
+		u32 softrst_en_p		: 1;
+		u32 force_softreset_valid	: 1;
+		u32 reserved3			: 2;
+		u32 pix_range_detection_e	: 1;
+		u32 reserved4			: 7;
+	} reg011;
+
+	struct rkvdec_vdpu381_secondary_en {
+		u32 wr_ddr_align_en		: 1;
+		u32 colmv_compress_en		: 1;
+		u32 fbc_e			: 1;
+		u32 reserved0			: 1;
+
+		u32 buspr_slot_disable		: 1;
+		u32 error_info_en		: 1;
+		u32 info_collect_en		: 1;
+		u32 wait_reset_en		: 1;
+
+		u32 scanlist_addr_valid_en	: 1;
+		u32 scale_down_en		: 1;
+		u32 error_cfg_wr_disable	: 1;
+		u32 reserved1			: 21;
+	} reg012;
+
+	struct rkvdec_vdpu381_en_mode_set {
+		u32 timeout_mode		: 1;
+		u32 req_timeout_rst_sel		: 1;
+		u32 reserved0			: 1;
+		u32 dec_commonirq_mode		: 1;
+		u32 reserved1			: 2;
+		u32 stmerror_waitdecfifo_empty	: 1;
+		u32 reserved2			: 2;
+		u32 h26x_streamd_error_mode	: 1;
+		u32 reserved3			: 2;
+		u32 allow_not_wr_unref_bframe	: 1;
+		u32 fbc_output_wr_disable	: 1;
+		u32 reserved4			: 1;
+		u32 colmv_error_mode		: 1;
+
+		u32 reserved5			: 2;
+		u32 h26x_error_mode		: 1;
+		u32 reserved6			: 2;
+		u32 ycacherd_prior		: 1;
+		u32 reserved7			: 2;
+		u32 cur_pic_is_idr		: 1;
+		u32 reserved8			: 1;
+		u32 right_auto_rst_disable	: 1;
+		u32 frame_end_err_rst_flag	: 1;
+		u32 rd_prior_mode		: 1;
+		u32 rd_ctrl_prior_mode		: 1;
+		u32 reserved9			: 1;
+		u32 filter_outbuf_mode		: 1;
+	} reg013;
+
+	struct rkvdec_vdpu381_fbc_param_set {
+		u32 fbc_force_uncompress	: 1;
+
+		u32 reserved0			: 2;
+		u32 allow_16x8_cp_flag		: 1;
+		u32 reserved1			: 2;
+
+		u32 fbc_h264_exten_4or8_flag	: 1;
+		u32 reserved2			: 25;
+	} reg014;
+
+	struct rkvdec_vdpu381_stream_param_set {
+		u32 rlc_mode_direct_write	: 1;
+		u32 rlc_mode			: 1;
+		u32 reserved0			: 3;
+
+		u32 strm_start_bit		: 7;
+		u32 reserved1			: 20;
+	} reg015;
+
+	u32 stream_len;
+
+	struct rkvdec_vdpu381_slice_number {
+		u32 slice_num	: 25;
+		u32 reserved	: 7;
+	} reg017;
+
+	struct rkvdec_vdpu381_y_hor_stride {
+		u32 y_hor_virstride	: 16;
+		u32 reserved		: 16;
+	} reg018;
+
+	struct rkvdec_vdpu381_uv_hor_stride {
+		u32 uv_hor_virstride	: 16;
+		u32 reserved		: 16;
+	} reg019;
+
+	struct rkvdec_vdpu381_y_stride {
+		u32 y_virstride		: 28;
+		u32 reserved		: 4;
+	} reg020;
+
+	struct rkvdec_vdpu381_error_ctrl_set {
+		u32 inter_error_prc_mode		: 1;
+		u32 error_intra_mode			: 1;
+		u32 error_deb_en			: 1;
+		u32 picidx_replace			: 5;
+		u32 error_spread_e			: 1;
+		u32 reserved0				: 3;
+		u32 error_inter_pred_cross_slice	: 1;
+		u32 reserved1				: 11;
+		u32 roi_error_ctu_cal_en		: 1;
+		u32 reserved2				: 7;
+	} reg021;
+
+	struct rkvdec_vdpu381_err_roi_ctu_offset_start {
+		u32 roi_x_ctu_offset_st	: 12;
+		u32 reserved0		: 4;
+		u32 roi_y_ctu_offset_st	: 12;
+		u32 reserved1		: 4;
+	} reg022;
+
+	struct rkvdec_vdpu381_err_roi_ctu_offset_end {
+		u32 roi_x_ctu_offset_end	: 12;
+		u32 reserved0			: 4;
+		u32 roi_y_ctu_offset_end	: 12;
+		u32 reserved1			: 4;
+	} reg023;
+
+	struct rkvdec_vdpu381_cabac_error_en_lowbits {
+		u32 cabac_err_en_lowbits	: 32;
+	} reg024;
+
+	struct rkvdec_vdpu381_cabac_error_en_highbits {
+		u32 cabac_err_en_highbits	: 30;
+		u32 reserved			: 2;
+	} reg025;
+
+	struct rkvdec_vdpu381_block_gating_en {
+		u32 swreg_block_gating_e	: 20;
+		u32 reserved			: 11;
+		u32 reg_cfg_gating_en		: 1;
+	} reg026;
+
+	struct SW027_CORE_SAFE_PIXELS {
+		u32 core_safe_x_pixels	: 16;
+		u32 core_safe_y_pixels	: 16;
+	} reg027;
+
+	struct rkvdec_vdpu381_multiply_core_ctrl {
+		u32 swreg_vp9_wr_prob_idx	: 3;
+		u32 reserved0			: 1;
+		u32 swreg_vp9_rd_prob_idx	: 3;
+		u32 reserved1			: 1;
+
+		u32 swreg_ref_req_advance_flag	: 1;
+		u32 sw_colmv_req_advance_flag	: 1;
+		u32 sw_poc_only_highbit_flag	: 1;
+		u32 sw_poc_arb_flag		: 1;
+
+		u32 reserved2			: 4;
+		u32 sw_film_idx			: 10;
+		u32 reserved3			: 2;
+		u32 sw_pu_req_mismatch_dis	: 1;
+		u32 sw_colmv_req_mismatch_dis	: 1;
+		u32 reserved4			: 2;
+	} reg028;
+
+	struct SW029_SCALE_DOWN_CTRL {
+		u32 scale_down_hor_ratio	: 2;
+		u32 reserved0			: 6;
+		u32 scale_down_vrz_ratio	: 2;
+		u32 reserved1			: 22;
+	} reg029;
+
+	struct SW032_Y_SCALE_DOWN_TILE8x8_HOR_STRIDE {
+		u32 y_scale_down_hor_stride	: 20;
+		u32 reserved0			: 12;
+	} reg030;
+
+	struct SW031_UV_SCALE_DOWN_TILE8x8_HOR_STRIDE {
+		u32 uv_scale_down_hor_stride	: 20;
+		u32 reserved0			: 12;
+	} reg031;
+
+	u32 timeout_threshold;
+} __packed;
+
+/* base: OFFSET_COMMON_ADDR_REGS */
+struct rkvdec_vdpu381_regs_common_addr {
+	u32 rlc_base;
+	u32 rlcwrite_base;
+	u32 decout_base;
+	u32 colmv_cur_base;
+	u32 error_ref_base;
+	u32 rcb_base[10];
+} __packed;
+
+struct rkvdec_vdpu381_h26x_set {
+	u32 h26x_frame_orslice		: 1;
+	u32 h26x_rps_mode		: 1;
+	u32 h26x_stream_mode		: 1;
+	u32 h26x_stream_lastpacket	: 1;
+	u32 h264_firstslice_flag	: 1;
+	u32 reserved			: 27;
+} __packed;
+
+/* base: OFFSET_CODEC_PARAMS_REGS */
+struct rkvdec_vdpu381_regs_h264_params {
+	struct rkvdec_vdpu381_h26x_set reg064;
+
+	u32 cur_top_poc;
+	u32 cur_bot_poc;
+	u32 ref_pocs[32];
+
+	struct rkvdec_vdpu381_h264_info {
+		struct rkvdec_vdpu381_h264_ref_info {
+			u32 ref_field		: 1;
+			u32 ref_topfield_used	: 1;
+			u32 ref_botfield_used	: 1;
+			u32 ref_colmv_use_flag	: 1;
+			u32 ref_reserved	: 4;
+		} __packed ref_info[4];
+	} __packed ref_info_regs[4];
+
+	u32 reserved_103_111[9];
+
+	struct rkvdec_vdpu381_error_ref_info {
+		u32 avs2_ref_error_field	: 1;
+		u32 avs2_ref_error_topfield	: 1;
+		u32 ref_error_topfield_used	: 1;
+		u32 ref_error_botfield_used	: 1;
+		u32 reserved			: 28;
+	} reg112;
+} __packed;
+
+struct rkvdec_vdpu381_regs_hevc_params {
+	struct rkvdec_vdpu381_h26x_set reg064;
+
+	u32 cur_top_poc;
+	u32 cur_bot_poc;
+
+	u32 reg067_082_ref_poc[16];
+
+	u32 reserved_083_098[16];
+
+	struct rkvdec_vdpu381_hevc_ref_valid {
+		u32 hevc_ref_valid_0    : 1;
+		u32 hevc_ref_valid_1    : 1;
+		u32 hevc_ref_valid_2    : 1;
+		u32 hevc_ref_valid_3    : 1;
+		u32 reserve0            : 4;
+		u32 hevc_ref_valid_4    : 1;
+		u32 hevc_ref_valid_5    : 1;
+		u32 hevc_ref_valid_6    : 1;
+		u32 hevc_ref_valid_7    : 1;
+		u32 reserve1            : 4;
+		u32 hevc_ref_valid_8    : 1;
+		u32 hevc_ref_valid_9    : 1;
+		u32 hevc_ref_valid_10   : 1;
+		u32 hevc_ref_valid_11   : 1;
+		u32 reserve2            : 4;
+		u32 hevc_ref_valid_12   : 1;
+		u32 hevc_ref_valid_13   : 1;
+		u32 hevc_ref_valid_14   : 1;
+		u32 reserve3            : 5;
+	} reg099;
+
+	u32 reserved_100_102[3];
+
+	struct rkvdec_vdpu381_hevc_mvc0 {
+		u32 ref_pic_layer_same_with_cur : 16;
+		u32 reserve                     : 16;
+	} reg103;
+
+	struct rkvdec_vdpu381_hevc_mvc1 {
+		u32 poc_lsb_not_present_flag        : 1;
+		u32 num_direct_ref_layers           : 6;
+		u32 reserve0                        : 1;
+
+		u32 num_reflayer_pics               : 6;
+		u32 default_ref_layers_active_flag  : 1;
+		u32 max_one_active_ref_layer_flag   : 1;
+
+		u32 poc_reset_info_present_flag     : 1;
+		u32 vps_poc_lsb_aligned_flag        : 1;
+		u32 mvc_poc15_valid_flag            : 1;
+		u32 reserve1                        : 13;
+	} reg104;
+
+	u32 reserved_105_111[7];
+
+	struct rkvdec_vdpu381_hevc_ref_info {
+		u32 avs2_ref_error_field        : 1;
+		u32 avs2_ref_error_topfield     : 1;
+		u32 ref_error_topfield_used     : 1;
+		u32 ref_error_botfield_used     : 1;
+		u32 reserve                     : 28;
+	} reg112;
+
+} __packed;
+
+/* base: OFFSET_CODEC_ADDR_REGS */
+struct rkvdec_vdpu381_regs_h26x_addr {
+	u32 reserved_160;
+	u32 pps_base;
+	u32 reserved_162;
+	u32 rps_base;
+	u32 ref_base[16];
+	u32 scanlist_addr;
+	u32 colmv_base[16];
+	u32 cabactbl_base;
+} __packed;
+
+struct rkvdec_vdpu381_regs_h26x_highpoc {
+	struct rkvdec_vdpu381_ref_poc_highbit {
+		u32 ref0_poc_highbit	: 4;
+		u32 ref1_poc_highbit	: 4;
+		u32 ref2_poc_highbit	: 4;
+		u32 ref3_poc_highbit	: 4;
+		u32 ref4_poc_highbit	: 4;
+		u32 ref5_poc_highbit	: 4;
+		u32 ref6_poc_highbit	: 4;
+		u32 ref7_poc_highbit	: 4;
+	} reg200[4];
+	struct rkvdec_vdpu381_cur_poc_highbit {
+		u32 cur_poc_highbit	: 4;
+		u32 reserved		: 28;
+	} reg204;
+} __packed;
+
+struct rkvdec_vdpu381_regs_h264 {
+	struct rkvdec_vdpu381_regs_common		common;
+	struct rkvdec_vdpu381_regs_h264_params		h264_param;
+	struct rkvdec_vdpu381_regs_common_addr		common_addr;
+	struct rkvdec_vdpu381_regs_h26x_addr		h264_addr;
+	struct rkvdec_vdpu381_regs_h26x_highpoc		h264_highpoc;
+} __packed;
+
+struct rkvdec_vdpu381_regs_hevc {
+	struct rkvdec_vdpu381_regs_common		common;
+	struct rkvdec_vdpu381_regs_hevc_params		hevc_param;
+	struct rkvdec_vdpu381_regs_common_addr		common_addr;
+	struct rkvdec_vdpu381_regs_h26x_addr		hevc_addr;
+	struct rkvdec_vdpu381_regs_h26x_highpoc		hevc_highpoc;
+} __packed;
+
+#endif /* __RKVDEC_REGS_H__ */
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index f7353d0acdab..1ddae1b23434 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -29,6 +29,7 @@
 
 #include "rkvdec.h"
 #include "rkvdec-regs.h"
+#include "rkvdec-vdpu381-regs.h"
 #include "rkvdec-rcb.h"
 
 static bool rkvdec_image_fmt_match(enum rkvdec_image_fmt fmt1,
@@ -90,6 +91,9 @@ static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx,
 {
 	v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat,
 			    pix_mp->width, pix_mp->height);
+
+	ctx->colmv_offset = pix_mp->plane_fmt[0].sizeimage;
+
 	pix_mp->plane_fmt[0].sizeimage += 128 *
 		DIV_ROUND_UP(pix_mp->width, 16) *
 		DIV_ROUND_UP(pix_mp->height, 16);
@@ -367,6 +371,26 @@ static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = {
 	}
 };
 
+static const struct rkvdec_coded_fmt_desc vdpu381_coded_fmts[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_H264_SLICE,
+		.frmsize = {
+			.min_width = 64,
+			.max_width =  65520,
+			.step_width = 64,
+			.min_height = 64,
+			.max_height =  65520,
+			.step_height = 16,
+		},
+		.ctrls = &rkvdec_h264_ctrls,
+		.ops = &rkvdec_vdpu381_h264_fmt_ops,
+		.num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts),
+		.decoded_fmts = rkvdec_h264_decoded_fmts,
+		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
+		.capability = RKVDEC_CAPABILITY_H264,
+	},
+};
+
 static bool rkvdec_is_capable(struct rkvdec_ctx *ctx, unsigned int capability)
 {
 	return (ctx->dev->variant->capabilities & capability) == capability;
@@ -1241,6 +1265,35 @@ static irqreturn_t rk3399_irq_handler(struct rkvdec_ctx *ctx)
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t vdpu381_irq_handler(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	enum vb2_buffer_state state;
+	bool need_reset = 0;
+	u32 status;
+
+	status = readl(rkvdec->regs + VDPU381_REG_STA_INT);
+	writel(0, rkvdec->regs + VDPU381_REG_STA_INT);
+
+	if (status & VDPU381_STA_INT_DEC_RDY_STA) {
+		state = VB2_BUF_STATE_DONE;
+	} else {
+		state = VB2_BUF_STATE_ERROR;
+		if (status & (VDPU381_STA_INT_SOFTRESET_RDY |
+			      VDPU381_STA_INT_TIMEOUT |
+			      VDPU381_STA_INT_ERROR))
+			rkvdec_iommu_restore(rkvdec);
+	}
+
+	if (need_reset)
+		rkvdec_iommu_restore(rkvdec);
+
+	if (cancel_delayed_work(&rkvdec->watchdog_work))
+		rkvdec_job_finish(ctx, state);
+
+	return IRQ_HANDLED;
+}
+
 static irqreturn_t rkvdec_irq_handler(int irq, void *priv)
 {
 	struct rkvdec_dev *rkvdec = priv;
@@ -1308,6 +1361,19 @@ static int rkvdec_disable_multicore(struct rkvdec_dev *rkvdec)
 	return 0;
 }
 
+static const struct rcb_size_info vdpu381_rcb_sizes[] = {
+	{6,	PIC_WIDTH},	// intrar
+	{1,	PIC_WIDTH},	// transdr (Is actually 0.4*pic_width)
+	{1,	PIC_HEIGHT},	// transdc (Is actually 0.1*pic_height)
+	{3,	PIC_WIDTH},	// streamdr
+	{6,	PIC_WIDTH},	// interr
+	{3,	PIC_HEIGHT},	// interc
+	{22,	PIC_WIDTH},	// dblkr
+	{6,	PIC_WIDTH},	// saor
+	{11,	PIC_WIDTH},	// fbcr
+	{67,	PIC_HEIGHT},	// filtc col
+};
+
 static const struct rkvdec_variant_ops rk3399_variant_ops = {
 	.irq_handler = rk3399_irq_handler,
 };
@@ -1341,6 +1407,19 @@ static const struct rkvdec_variant rk3399_rkvdec_variant = {
 			RKVDEC_CAPABILITY_VP9,
 };
 
+static const struct rkvdec_variant_ops vdpu381_variant_ops = {
+	.irq_handler = vdpu381_irq_handler,
+};
+
+static const struct rkvdec_variant rk3588_vdpu381_variant = {
+	.coded_fmts = vdpu381_coded_fmts,
+	.num_coded_fmts = ARRAY_SIZE(vdpu381_coded_fmts),
+	.rcb_sizes = vdpu381_rcb_sizes,
+	.num_rcb_sizes = ARRAY_SIZE(vdpu381_rcb_sizes),
+	.ops = &vdpu381_variant_ops,
+	.capabilities = RKVDEC_CAPABILITY_H264,
+};
+
 static const struct of_device_id of_rkvdec_match[] = {
 	{
 		.compatible = "rockchip,rk3288-vdec",
@@ -1354,6 +1433,10 @@ static const struct of_device_id of_rkvdec_match[] = {
 		.compatible = "rockchip,rk3399-vdec",
 		.data = &rk3399_rkvdec_variant,
 	},
+	{
+		.compatible = "rockchip,rk3588-vdec",
+		.data = &rk3588_vdpu381_variant,
+	},
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, of_rkvdec_match);
@@ -1387,6 +1470,7 @@ static int rkvdec_probe(struct platform_device *pdev)
 		return ret;
 
 	rkvdec->num_clocks = ret;
+	rkvdec->axi_clk = devm_clk_get(&pdev->dev, "axi");
 
 	rkvdec->regs = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(rkvdec->regs))
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
index 75a9ba988794..1ad9a4fc31db 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
@@ -29,6 +29,10 @@
 
 #define RKVDEC_QUIRK_DISABLE_QOS	BIT(0)
 
+#define RKVDEC_1080P_PIXELS		(1920 * 1088)
+#define RKVDEC_4K_PIXELS		(4096 * 2304)
+#define RKVDEC_8K_PIXELS		(7680 * 4320)
+
 struct rkvdec_ctx;
 struct rkvdec_rcb_config;
 
@@ -132,6 +136,7 @@ struct rkvdec_dev {
 	struct device *dev;
 	struct clk_bulk_data *clocks;
 	unsigned int num_clocks;
+	struct clk *axi_clk;
 	void __iomem *regs;
 	struct mutex vdev_lock; /* serializes ioctls */
 	struct delayed_work watchdog_work;
@@ -150,6 +155,7 @@ struct rkvdec_ctx {
 	struct rkvdec_dev *dev;
 	enum rkvdec_image_fmt image_fmt;
 	struct rkvdec_rcb_config *rcb_config;
+	u32 colmv_offset;
 	void *priv;
 };
 
@@ -180,4 +186,6 @@ extern const struct rkvdec_coded_fmt_ops rkvdec_h264_fmt_ops;
 extern const struct rkvdec_coded_fmt_ops rkvdec_hevc_fmt_ops;
 extern const struct rkvdec_coded_fmt_ops rkvdec_vp9_fmt_ops;
 
+extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_h264_fmt_ops;
+
 #endif /* RKVDEC_H_ */
-- 
2.52.0



From detlev.casanova at collabora.com  Wed Dec 17 09:40:52 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 17 Dec 2025 12:40:52 -0500
Subject: [PATCH v6 15/17] media: rkvdec: Add H264 support for the VDPU383 variant
In-Reply-To: <20251217174059.1341784-1-detlev.casanova@collabora.com>
References: <20251217174059.1341784-1-detlev.casanova@collabora.com>
Message-ID: <20251217174059.1341784-16-detlev.casanova@collabora.com>

This variant is used on the RK3576 SoC.

The moving vectors size requirements are slightly different so support
for a colmv_size function per variant is added.

Also, the link registers are used to start the decoder and read IRQ status.
Per variant support for named register sections is added.

The fluster score is 128/135 for JVT-AVC_V1, with MPS_MW_A failing in
addition to the usual ones.
The other test suites are not supported yet.

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../media/platform/rockchip/rkvdec/Makefile   |   1 +
 .../rockchip/rkvdec/rkvdec-vdpu383-h264.c     | 582 ++++++++++++++++++
 .../rockchip/rkvdec/rkvdec-vdpu383-regs.h     | 281 +++++++++
 .../media/platform/rockchip/rkvdec/rkvdec.c   | 118 +++-
 .../media/platform/rockchip/rkvdec/rkvdec.h   |   8 +
 5 files changed, 984 insertions(+), 6 deletions(-)
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-regs.h

diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
index 7bfd95151e40..a58d4aede2fe 100644
--- a/drivers/media/platform/rockchip/rkvdec/Makefile
+++ b/drivers/media/platform/rockchip/rkvdec/Makefile
@@ -9,4 +9,5 @@ rockchip-vdec-y += \
 		   rkvdec-hevc-common.o \
 		   rkvdec-rcb.o \
 		   rkvdec-vdpu381-h264.o \
+		   rkvdec-vdpu383-h264.o \
 		   rkvdec-vp9.o
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c
new file mode 100644
index 000000000000..d8419085bdd8
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c
@@ -0,0 +1,582 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip Video Decoder VDPU383 H264 backend
+ *
+ * Copyright (C) 2024 Collabora, Ltd.
+ *  Detlev Casanova <detlev.casanova at collabora.com>
+ */
+
+#include <media/v4l2-h264.h>
+#include <media/v4l2-mem2mem.h>
+
+#include <linux/iopoll.h>
+
+#include "rkvdec-rcb.h"
+#include "rkvdec-vdpu383-regs.h"
+#include "rkvdec-h264-common.h"
+
+struct rkvdec_sps {
+	u16 seq_parameter_set_id:			4;
+	u16 profile_idc:				8;
+	u16 constraint_set3_flag:			1;
+	u16 chroma_format_idc:				2;
+	u16 bit_depth_luma:				3;
+	u16 bit_depth_chroma:				3;
+	u16 qpprime_y_zero_transform_bypass_flag:	1;
+	u16 log2_max_frame_num_minus4:			4;
+	u16 max_num_ref_frames:				5;
+	u16 pic_order_cnt_type:				2;
+	u16 log2_max_pic_order_cnt_lsb_minus4:		4;
+	u16 delta_pic_order_always_zero_flag:		1;
+
+	u16 pic_width_in_mbs:				16;
+	u16 pic_height_in_mbs:				16;
+
+	u16 frame_mbs_only_flag:			1;
+	u16 mb_adaptive_frame_field_flag:		1;
+	u16 direct_8x8_inference_flag:			1;
+	u16 mvc_extension_enable:			1;
+	u16 num_views:					2;
+	u16 view_id0:                                   10;
+	u16 view_id1:                                   10;
+} __packed;
+
+struct rkvdec_pps {
+	u32 pic_parameter_set_id:				8;
+	u32 pps_seq_parameter_set_id:				5;
+	u32 entropy_coding_mode_flag:				1;
+	u32 bottom_field_pic_order_in_frame_present_flag:	1;
+	u32 num_ref_idx_l0_default_active_minus1:		5;
+	u32 num_ref_idx_l1_default_active_minus1:		5;
+	u32 weighted_pred_flag:					1;
+	u32 weighted_bipred_idc:				2;
+	u32 pic_init_qp_minus26:				7;
+	u32 pic_init_qs_minus26:				6;
+	u32 chroma_qp_index_offset:				5;
+	u32 deblocking_filter_control_present_flag:		1;
+	u32 constrained_intra_pred_flag:			1;
+	u32 redundant_pic_cnt_present:				1;
+	u32 transform_8x8_mode_flag:				1;
+	u32 second_chroma_qp_index_offset:			5;
+	u32 scaling_list_enable_flag:				1;
+	u32 is_longterm:					16;
+	u32 voidx:						16;
+
+	// dpb
+	u32 pic_field_flag:                                     1;
+	u32 pic_associated_flag:                                1;
+	u32 cur_top_field:					32;
+	u32 cur_bot_field:					32;
+
+	u32 top_field_order_cnt0:				32;
+	u32 bot_field_order_cnt0:				32;
+	u32 top_field_order_cnt1:				32;
+	u32 bot_field_order_cnt1:				32;
+	u32 top_field_order_cnt2:				32;
+	u32 bot_field_order_cnt2:				32;
+	u32 top_field_order_cnt3:				32;
+	u32 bot_field_order_cnt3:				32;
+	u32 top_field_order_cnt4:				32;
+	u32 bot_field_order_cnt4:				32;
+	u32 top_field_order_cnt5:				32;
+	u32 bot_field_order_cnt5:				32;
+	u32 top_field_order_cnt6:				32;
+	u32 bot_field_order_cnt6:				32;
+	u32 top_field_order_cnt7:				32;
+	u32 bot_field_order_cnt7:				32;
+	u32 top_field_order_cnt8:				32;
+	u32 bot_field_order_cnt8:				32;
+	u32 top_field_order_cnt9:				32;
+	u32 bot_field_order_cnt9:				32;
+	u32 top_field_order_cnt10:				32;
+	u32 bot_field_order_cnt10:				32;
+	u32 top_field_order_cnt11:				32;
+	u32 bot_field_order_cnt11:				32;
+	u32 top_field_order_cnt12:				32;
+	u32 bot_field_order_cnt12:				32;
+	u32 top_field_order_cnt13:				32;
+	u32 bot_field_order_cnt13:				32;
+	u32 top_field_order_cnt14:				32;
+	u32 bot_field_order_cnt14:				32;
+	u32 top_field_order_cnt15:				32;
+	u32 bot_field_order_cnt15:				32;
+
+	u32 ref_field_flags:					16;
+	u32 ref_topfield_used:					16;
+	u32 ref_botfield_used:					16;
+	u32 ref_colmv_use_flag:					16;
+
+	u32 reserved0:						30;
+	u32 reserved[3];
+} __packed;
+
+struct rkvdec_sps_pps {
+	struct rkvdec_sps sps;
+	struct rkvdec_pps pps;
+} __packed;
+
+/* Data structure describing auxiliary buffer format. */
+struct rkvdec_h264_priv_tbl {
+	s8 cabac_table[4][464][2];
+	struct rkvdec_h264_scaling_list scaling_list;
+	struct rkvdec_sps_pps param_set[256];
+	struct rkvdec_rps rps;
+} __packed;
+
+struct rkvdec_h264_ctx {
+	struct rkvdec_aux_buf priv_tbl;
+	struct rkvdec_h264_reflists reflists;
+	struct vdpu383_regs_h26x regs;
+};
+
+static void set_field_order_cnt(struct rkvdec_sps_pps *hw_ps, int id, u32 top, u32 bottom)
+{
+	switch (id) {
+	case 0:
+		hw_ps->pps.top_field_order_cnt0 = top;
+		hw_ps->pps.bot_field_order_cnt0 = bottom;
+		break;
+	case 1:
+		hw_ps->pps.top_field_order_cnt1 = top;
+		hw_ps->pps.bot_field_order_cnt1 = bottom;
+		break;
+	case 2:
+		hw_ps->pps.top_field_order_cnt2 = top;
+		hw_ps->pps.bot_field_order_cnt2 = bottom;
+		break;
+	case 3:
+		hw_ps->pps.top_field_order_cnt3 = top;
+		hw_ps->pps.bot_field_order_cnt3 = bottom;
+		break;
+	case 4:
+		hw_ps->pps.top_field_order_cnt4 = top;
+		hw_ps->pps.bot_field_order_cnt4 = bottom;
+		break;
+	case 5:
+		hw_ps->pps.top_field_order_cnt5 = top;
+		hw_ps->pps.bot_field_order_cnt5 = bottom;
+		break;
+	case 6:
+		hw_ps->pps.top_field_order_cnt6 = top;
+		hw_ps->pps.bot_field_order_cnt6 = bottom;
+		break;
+	case 7:
+		hw_ps->pps.top_field_order_cnt7 = top;
+		hw_ps->pps.bot_field_order_cnt7 = bottom;
+		break;
+	case 8:
+		hw_ps->pps.top_field_order_cnt8 = top;
+		hw_ps->pps.bot_field_order_cnt8 = bottom;
+		break;
+	case 9:
+		hw_ps->pps.top_field_order_cnt9 = top;
+		hw_ps->pps.bot_field_order_cnt9 = bottom;
+		break;
+	case 10:
+		hw_ps->pps.top_field_order_cnt10 = top;
+		hw_ps->pps.bot_field_order_cnt10 = bottom;
+		break;
+	case 11:
+		hw_ps->pps.top_field_order_cnt11 = top;
+		hw_ps->pps.bot_field_order_cnt11 = bottom;
+		break;
+	case 12:
+		hw_ps->pps.top_field_order_cnt12 = top;
+		hw_ps->pps.bot_field_order_cnt12 = bottom;
+		break;
+	case 13:
+		hw_ps->pps.top_field_order_cnt13 = top;
+		hw_ps->pps.bot_field_order_cnt13 = bottom;
+		break;
+	case 14:
+		hw_ps->pps.top_field_order_cnt14 = top;
+		hw_ps->pps.bot_field_order_cnt14 = bottom;
+		break;
+	case 15:
+		hw_ps->pps.top_field_order_cnt15 = top;
+		hw_ps->pps.bot_field_order_cnt15 = bottom;
+		break;
+	}
+}
+
+static void assemble_hw_pps(struct rkvdec_ctx *ctx,
+			    struct rkvdec_h264_run *run)
+{
+	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
+	const struct v4l2_ctrl_h264_sps *sps = run->sps;
+	const struct v4l2_ctrl_h264_pps *pps = run->pps;
+	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
+	const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb;
+	struct rkvdec_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu;
+	struct rkvdec_sps_pps *hw_ps;
+	u32 pic_width, pic_height;
+	u32 i;
+
+	/*
+	 * HW read the SPS/PPS information from PPS packet index by PPS id.
+	 * offset from the base can be calculated by PPS_id * 32 (size per PPS
+	 * packet unit). so the driver copy SPS/PPS information to the exact PPS
+	 * packet unit for HW accessing.
+	 */
+	hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id];
+	memset(hw_ps, 0, sizeof(*hw_ps));
+
+	/* write sps */
+	hw_ps->sps.seq_parameter_set_id = sps->seq_parameter_set_id;
+	hw_ps->sps.profile_idc = sps->profile_idc;
+	hw_ps->sps.constraint_set3_flag = !!(sps->constraint_set_flags & (1 << 3));
+	hw_ps->sps.chroma_format_idc = sps->chroma_format_idc;
+	hw_ps->sps.bit_depth_luma = sps->bit_depth_luma_minus8;
+	hw_ps->sps.bit_depth_chroma = sps->bit_depth_chroma_minus8;
+	hw_ps->sps.qpprime_y_zero_transform_bypass_flag =
+		!!(sps->flags & V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS);
+	hw_ps->sps.log2_max_frame_num_minus4 = sps->log2_max_frame_num_minus4;
+	hw_ps->sps.max_num_ref_frames = sps->max_num_ref_frames;
+	hw_ps->sps.pic_order_cnt_type = sps->pic_order_cnt_type;
+	hw_ps->sps.log2_max_pic_order_cnt_lsb_minus4 =
+		sps->log2_max_pic_order_cnt_lsb_minus4;
+	hw_ps->sps.delta_pic_order_always_zero_flag =
+		!!(sps->flags & V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO);
+	hw_ps->sps.mvc_extension_enable = 0;
+	hw_ps->sps.num_views = 0;
+
+	/*
+	 * Use the SPS values since they are already in macroblocks
+	 * dimensions, height can be field height (halved) if
+	 * V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY is not set and also it allows
+	 * decoding smaller images into larger allocation which can be used
+	 * to implementing SVC spatial layer support.
+	 */
+	pic_width = 16 * (sps->pic_width_in_mbs_minus1 + 1);
+	pic_height = 16 * (sps->pic_height_in_map_units_minus1 + 1);
+	if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY))
+		pic_height *= 2;
+	if (!!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC))
+		pic_height /= 2;
+
+	hw_ps->sps.pic_width_in_mbs = pic_width;
+	hw_ps->sps.pic_height_in_mbs = pic_height;
+
+	hw_ps->sps.frame_mbs_only_flag =
+		!!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY);
+	hw_ps->sps.mb_adaptive_frame_field_flag =
+		!!(sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD);
+	hw_ps->sps.direct_8x8_inference_flag =
+		!!(sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE);
+
+	/* write pps */
+	hw_ps->pps.pic_parameter_set_id = pps->pic_parameter_set_id;
+	hw_ps->pps.pps_seq_parameter_set_id = pps->seq_parameter_set_id;
+	hw_ps->pps.entropy_coding_mode_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE);
+	hw_ps->pps.bottom_field_pic_order_in_frame_present_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT);
+	hw_ps->pps.num_ref_idx_l0_default_active_minus1 =
+		pps->num_ref_idx_l0_default_active_minus1;
+	hw_ps->pps.num_ref_idx_l1_default_active_minus1 =
+		pps->num_ref_idx_l1_default_active_minus1;
+	hw_ps->pps.weighted_pred_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED);
+	hw_ps->pps.weighted_bipred_idc = pps->weighted_bipred_idc;
+	hw_ps->pps.pic_init_qp_minus26 = pps->pic_init_qp_minus26;
+	hw_ps->pps.pic_init_qs_minus26 = pps->pic_init_qs_minus26;
+	hw_ps->pps.chroma_qp_index_offset = pps->chroma_qp_index_offset;
+	hw_ps->pps.deblocking_filter_control_present_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT);
+	hw_ps->pps.constrained_intra_pred_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED);
+	hw_ps->pps.redundant_pic_cnt_present =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT);
+	hw_ps->pps.transform_8x8_mode_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE);
+	hw_ps->pps.second_chroma_qp_index_offset = pps->second_chroma_qp_index_offset;
+	hw_ps->pps.scaling_list_enable_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT);
+
+	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
+		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
+			hw_ps->pps.is_longterm |= (1 << i);
+
+		set_field_order_cnt(hw_ps, i, dpb[i].top_field_order_cnt,
+				    dpb[i].bottom_field_order_cnt);
+
+		hw_ps->pps.ref_field_flags |=
+			(!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD)) << i;
+		hw_ps->pps.ref_colmv_use_flag |=
+			(!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) << i;
+		hw_ps->pps.ref_topfield_used |=
+			(!!(dpb[i].fields & V4L2_H264_TOP_FIELD_REF)) << i;
+		hw_ps->pps.ref_botfield_used |=
+			(!!(dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF)) << i;
+	}
+
+	hw_ps->pps.pic_field_flag =
+		!!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC);
+	hw_ps->pps.pic_associated_flag =
+		!!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD);
+
+	hw_ps->pps.cur_top_field = dec_params->top_field_order_cnt;
+	hw_ps->pps.cur_bot_field = dec_params->bottom_field_order_cnt;
+}
+
+static void rkvdec_write_regs(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
+
+	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_COMMON_REGS,
+			   &h264_ctx->regs.common,
+			   sizeof(h264_ctx->regs.common));
+	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_COMMON_ADDR_REGS,
+			   &h264_ctx->regs.common_addr,
+			   sizeof(h264_ctx->regs.common_addr));
+	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_CODEC_PARAMS_REGS,
+			   &h264_ctx->regs.h26x_params,
+			   sizeof(h264_ctx->regs.h26x_params));
+	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_CODEC_ADDR_REGS,
+			   &h264_ctx->regs.h26x_addr,
+			   sizeof(h264_ctx->regs.h26x_addr));
+}
+
+static void config_registers(struct rkvdec_ctx *ctx,
+			     struct rkvdec_h264_run *run)
+{
+	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
+	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
+	dma_addr_t priv_start_addr = h264_ctx->priv_tbl.dma;
+	const struct v4l2_pix_format_mplane *dst_fmt;
+	struct vb2_v4l2_buffer *src_buf = run->base.bufs.src;
+	struct vb2_v4l2_buffer *dst_buf = run->base.bufs.dst;
+	struct vdpu383_regs_h26x *regs = &h264_ctx->regs;
+	const struct v4l2_format *f;
+	dma_addr_t rlc_addr;
+	dma_addr_t dst_addr;
+	u32 hor_virstride;
+	u32 ver_virstride;
+	u32 y_virstride;
+	u32 offset;
+	u32 pixels;
+	u32 i;
+
+	memset(regs, 0, sizeof(*regs));
+
+	/* Set H264 mode */
+	regs->common.reg008_dec_mode = VDPU383_MODE_H264;
+
+	/* Set input stream length */
+	regs->h26x_params.reg066_stream_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
+
+	/* Set strides */
+	f = &ctx->decoded_fmt;
+	dst_fmt = &f->fmt.pix_mp;
+	hor_virstride = dst_fmt->plane_fmt[0].bytesperline;
+	ver_virstride = dst_fmt->height;
+	y_virstride = hor_virstride * ver_virstride;
+
+	pixels = dst_fmt->height * dst_fmt->width;
+
+	regs->h26x_params.reg068_hor_virstride = hor_virstride / 16;
+	regs->h26x_params.reg069_raster_uv_hor_virstride = hor_virstride / 16;
+	regs->h26x_params.reg070_y_virstride = y_virstride / 16;
+
+	/* Activate block gating */
+	regs->common.reg010.strmd_auto_gating_e      = 1;
+	regs->common.reg010.inter_auto_gating_e      = 1;
+	regs->common.reg010.intra_auto_gating_e      = 1;
+	regs->common.reg010.transd_auto_gating_e     = 1;
+	regs->common.reg010.recon_auto_gating_e      = 1;
+	regs->common.reg010.filterd_auto_gating_e    = 1;
+	regs->common.reg010.bus_auto_gating_e        = 1;
+	regs->common.reg010.ctrl_auto_gating_e       = 1;
+	regs->common.reg010.rcb_auto_gating_e        = 1;
+	regs->common.reg010.err_prc_auto_gating_e    = 1;
+
+	/* Set timeout threshold */
+	if (pixels < RKVDEC_1080P_PIXELS)
+		regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_1080p;
+	else if (pixels < RKVDEC_4K_PIXELS)
+		regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_4K;
+	else if (pixels < RKVDEC_8K_PIXELS)
+		regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_8K;
+	else
+		regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_MAX;
+
+	regs->common.reg016.error_proc_disable = 1;
+
+	/* Set ref pic address & poc */
+	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
+		struct vb2_buffer *vb_buf = run->ref_buf[i];
+		dma_addr_t buf_dma;
+
+		/*
+		 * If a DPB entry is unused or invalid, address of current destination
+		 * buffer is returned.
+		 */
+		if (!vb_buf)
+			vb_buf = &dst_buf->vb2_buf;
+
+		buf_dma = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
+
+		/* Set reference addresses */
+		regs->h26x_addr.reg170_185_ref_base[i] = buf_dma;
+		regs->h26x_addr.reg195_210_payload_st_ref_base[i] = buf_dma;
+
+		/* Set COLMV addresses */
+		regs->h26x_addr.reg217_232_colmv_ref_base[i] = buf_dma + ctx->colmv_offset;
+	}
+
+	/* Set rlc base address (input stream) */
+	rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+	regs->common_addr.reg128_strm_base = rlc_addr;
+
+	/* Set output base address */
+	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
+	regs->h26x_addr.reg168_decout_base = dst_addr;
+	regs->h26x_addr.reg169_error_ref_base = dst_addr;
+	regs->h26x_addr.reg192_payload_st_cur_base = dst_addr;
+
+	/* Set colmv address */
+	regs->h26x_addr.reg216_colmv_cur_base = dst_addr + ctx->colmv_offset;
+
+	/* Set RCB addresses */
+	for (i = 0; i < rkvdec_rcb_buf_count(ctx); i++) {
+		regs->common_addr.reg140_162_rcb_info[i].offset = rkvdec_rcb_buf_dma_addr(ctx, i);
+		regs->common_addr.reg140_162_rcb_info[i].size = rkvdec_rcb_buf_size(ctx, i);
+	}
+
+	/* Set hw pps address */
+	offset = offsetof(struct rkvdec_h264_priv_tbl, param_set);
+	regs->common_addr.reg131_gbl_base = priv_start_addr + offset;
+	regs->h26x_params.reg067_global_len = sizeof(struct rkvdec_sps_pps) / 16;
+
+	/* Set hw rps address */
+	offset = offsetof(struct rkvdec_h264_priv_tbl, rps);
+	regs->common_addr.reg129_rps_base = priv_start_addr + offset;
+
+	/* Set cabac table */
+	offset = offsetof(struct rkvdec_h264_priv_tbl, cabac_table);
+	regs->common_addr.reg130_cabactbl_base = priv_start_addr + offset;
+
+	/* Set scaling list address */
+	offset = offsetof(struct rkvdec_h264_priv_tbl, scaling_list);
+	regs->common_addr.reg132_scanlist_addr = priv_start_addr + offset;
+
+	rkvdec_write_regs(ctx);
+}
+
+static int rkvdec_h264_start(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_h264_priv_tbl *priv_tbl;
+	struct rkvdec_h264_ctx *h264_ctx;
+	struct v4l2_ctrl *ctrl;
+	int ret;
+
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_H264_SPS);
+	if (!ctrl)
+		return -EINVAL;
+
+	ret = rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps);
+	if (ret)
+		return ret;
+
+	h264_ctx = kzalloc(sizeof(*h264_ctx), GFP_KERNEL);
+	if (!h264_ctx)
+		return -ENOMEM;
+
+	priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl),
+				      &h264_ctx->priv_tbl.dma, GFP_KERNEL);
+	if (!priv_tbl) {
+		ret = -ENOMEM;
+		goto err_free_ctx;
+	}
+
+	h264_ctx->priv_tbl.size = sizeof(*priv_tbl);
+	h264_ctx->priv_tbl.cpu = priv_tbl;
+	memcpy(priv_tbl->cabac_table, rkvdec_h264_cabac_table,
+	       sizeof(rkvdec_h264_cabac_table));
+
+	ctx->priv = h264_ctx;
+
+	return 0;
+
+err_free_ctx:
+	kfree(h264_ctx);
+	return ret;
+}
+
+static void rkvdec_h264_stop(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
+	struct rkvdec_dev *rkvdec = ctx->dev;
+
+	dma_free_coherent(rkvdec->dev, h264_ctx->priv_tbl.size,
+			  h264_ctx->priv_tbl.cpu, h264_ctx->priv_tbl.dma);
+	kfree(h264_ctx);
+}
+
+static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
+{
+	struct v4l2_h264_reflist_builder reflist_builder;
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
+	struct rkvdec_h264_run run;
+	struct rkvdec_h264_priv_tbl *tbl = h264_ctx->priv_tbl.cpu;
+	u32 watchdog_time;
+	u64 timeout_threshold;
+	unsigned long axi_rate;
+
+	rkvdec_h264_run_preamble(ctx, &run);
+
+	/* Build the P/B{0,1} ref lists. */
+	v4l2_h264_init_reflist_builder(&reflist_builder, run.decode_params,
+				       run.sps, run.decode_params->dpb);
+	v4l2_h264_build_p_ref_list(&reflist_builder, h264_ctx->reflists.p);
+	v4l2_h264_build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0,
+				    h264_ctx->reflists.b1);
+
+	assemble_hw_scaling_list(&run, &tbl->scaling_list);
+	assemble_hw_pps(ctx, &run);
+	lookup_ref_buf_idx(ctx, &run);
+	assemble_hw_rps(&reflist_builder, &run, &h264_ctx->reflists, &tbl->rps);
+
+	config_registers(ctx, &run);
+
+	rkvdec_run_postamble(ctx, &run.base);
+
+	/* Set watchdog at 2 times the hardware timeout threshold */
+	timeout_threshold = h264_ctx->regs.common.reg013_core_timeout_threshold;
+	axi_rate = clk_get_rate(rkvdec->axi_clk);
+
+	if (axi_rate)
+		watchdog_time = 2 * (1000 * timeout_threshold) / axi_rate;
+	else
+		watchdog_time = 2000;
+	schedule_delayed_work(&rkvdec->watchdog_work,
+			      msecs_to_jiffies(watchdog_time));
+
+	/* Start decoding! */
+	writel(timeout_threshold, rkvdec->link + VDPU383_LINK_TIMEOUT_THRESHOLD);
+	writel(0, rkvdec->link + VDPU383_LINK_IP_ENABLE);
+	writel(VDPU383_DEC_E_BIT, rkvdec->link + VDPU383_LINK_DEC_ENABLE);
+
+	return 0;
+}
+
+static int rkvdec_h264_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
+{
+	if (ctrl->id == V4L2_CID_STATELESS_H264_SPS)
+		return rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps);
+
+	return 0;
+}
+
+const struct rkvdec_coded_fmt_ops rkvdec_vdpu383_h264_fmt_ops = {
+	.adjust_fmt = rkvdec_h264_adjust_fmt,
+	.get_image_fmt = rkvdec_h264_get_image_fmt,
+	.start = rkvdec_h264_start,
+	.stop = rkvdec_h264_stop,
+	.run = rkvdec_h264_run,
+	.try_ctrl = rkvdec_h264_try_ctrl,
+};
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-regs.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-regs.h
new file mode 100644
index 000000000000..bc1c2b4272b0
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-regs.h
@@ -0,0 +1,281 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Rockchip Video Decoder VDPU383 driver registers description
+ *
+ * Copyright (C) 2025 Collabora, Ltd.
+ *  Detlev Casanova <detlev.casanova at collabora.com>
+ */
+
+#ifndef _RKVDEC_VDPU838_REGS_H_
+#define _RKVDEC_VDPU838_REGS_H_
+
+#include <linux/types.h>
+
+#define VDPU383_OFFSET_COMMON_REGS		(8 * sizeof(u32))
+#define VDPU383_OFFSET_CODEC_PARAMS_REGS	(64 * sizeof(u32))
+#define VDPU383_OFFSET_COMMON_ADDR_REGS		(128 * sizeof(u32))
+#define VDPU383_OFFSET_CODEC_ADDR_REGS		(168 * sizeof(u32))
+#define VDPU383_OFFSET_POC_HIGHBIT_REGS		(200 * sizeof(u32))
+
+#define VDPU383_MODE_HEVC	0
+#define VDPU383_MODE_H264	1
+
+#define VDPU383_TIMEOUT_1080p		(0xffffff)
+#define VDPU383_TIMEOUT_4K		(0x2cfffff)
+#define VDPU383_TIMEOUT_8K		(0x4ffffff)
+#define VDPU383_TIMEOUT_MAX		(0xffffffff)
+
+#define VDPU383_LINK_TIMEOUT_THRESHOLD	0x54
+
+#define VDPU383_LINK_IP_ENABLE		0x58
+#define VDPU383_IP_CRU_MODE		BIT(24)
+
+#define VDPU383_LINK_DEC_ENABLE		0x40
+#define VDPU383_DEC_E_BIT		BIT(0)
+
+#define VDPU383_LINK_INT_EN		0x048
+#define VDPU383_INT_EN_IRQ		BIT(0)
+#define VDPU383_INT_EN_LINE_IRQ		BIT(1)
+
+#define VDPU383_LINK_STA_INT		0x04c
+#define VDPU383_STA_INT_DEC_RDY_STA	BIT(0)
+#define VDPU383_STA_INT_SOFTRESET_RDY	(BIT(10) | BIT(11))
+#define VDPU383_STA_INT_ALL		0x3ff
+
+struct vdpu383_regs_common {
+	u32 reg008_dec_mode;
+
+	struct swreg9_important_en {
+		u32 fbc_e			: 1;
+		u32 tile_e			: 1;
+		u32 reserve0			: 2;
+		u32 buf_empty_en		: 1;
+		u32 scale_down_en		: 1;
+		u32 reserve1			: 1;
+		u32 pix_range_det_e		: 1;
+		u32 av1_fgs_en			: 1;
+		u32 reserve2			: 7;
+		u32 line_irq_en			: 1;
+		u32 out_cbcr_swap		: 1;
+		u32 fbc_force_uncompress	: 1;
+		u32 fbc_sparse_mode		: 1;
+		u32 reserve3			: 12;
+	} reg009;
+
+	struct swreg010_block_gating_en {
+		u32 strmd_auto_gating_e		: 1;
+		u32 inter_auto_gating_e		: 1;
+		u32 intra_auto_gating_e		: 1;
+		u32 transd_auto_gating_e	: 1;
+		u32 recon_auto_gating_e		: 1;
+		u32 filterd_auto_gating_e	: 1;
+		u32 bus_auto_gating_e		: 1;
+		u32 ctrl_auto_gating_e		: 1;
+		u32 rcb_auto_gating_e		: 1;
+		u32 err_prc_auto_gating_e	: 1;
+		u32 reserve0			: 22;
+	} reg010;
+
+	struct swreg011_cfg_para {
+		u32 reserve0			: 9;
+		u32 dec_timeout_dis		: 1;
+		u32 reserve1			: 22;
+	} reg011;
+
+	struct swreg012_cache_hash_mask {
+		u32 reserve0			: 7;
+		u32 cache_hash_mask		: 25;
+	} reg012;
+
+	u32 reg013_core_timeout_threshold;
+
+	struct swreg014_line_irq_ctrl {
+		u32 dec_line_irq_step		: 16;
+		u32 dec_line_offset_y_st	: 16;
+	} reg014;
+
+	struct swreg015_irq_sta {
+		u32 rkvdec_frame_rdy_sta	: 1;
+		u32 rkvdec_strm_error_sta	: 1;
+		u32 rkvdec_core_timeout_sta	: 1;
+		u32 rkvdec_ip_timeout_sta	: 1;
+		u32 rkvdec_bus_error_sta	: 1;
+		u32 rkvdec_buffer_empty_sta	: 1;
+		u32 rkvdec_colmv_ref_error_sta	: 1;
+		u32 rkvdec_error_spread_sta	: 1;
+		u32 create_core_timeout_sta	: 1;
+		u32 wlast_miss_match_sta	: 1;
+		u32 rkvdec_core_rst_rdy_sta	: 1;
+		u32 rkvdec_ip_rst_rdy_sta	: 1;
+		u32 force_busidle_rdy_sta	: 1;
+		u32 ltb_pause_rdy_sta		: 1;
+		u32 ltb_end_flag		: 1;
+		u32 unsupport_decmode_error_sta	: 1;
+		u32 wmask_bits			: 15;
+		u32 reserve0			: 1;
+	} reg015;
+
+	struct swreg016_error_ctrl_set {
+		u32 error_proc_disable		: 1;
+		u32 reserve0			: 7;
+		u32 error_spread_disable	: 1;
+		u32 reserve1			: 15;
+		u32 roi_error_ctu_cal_en	: 1;
+		u32 reserve2			: 7;
+	} reg016;
+
+	struct swreg017_err_roi_ctu_offset_start {
+		u32 roi_x_ctu_offset_st		: 12;
+		u32 reserve0			: 4;
+		u32 roi_y_ctu_offset_st		: 12;
+		u32 reserve1			: 4;
+	} reg017;
+
+	struct swreg018_err_roi_ctu_offset_end {
+		u32 roi_x_ctu_offset_end	: 12;
+		u32 reserve0			: 4;
+		u32 roi_y_ctu_offset_end	: 12;
+		u32 reserve1			: 4;
+	} reg018;
+
+	struct swreg019_error_ref_info {
+		u32 avs2_ref_error_field	: 1;
+		u32 avs2_ref_error_topfield	: 1;
+		u32 ref_error_topfield_used	: 1;
+		u32 ref_error_botfield_used	: 1;
+		u32 reserve0			: 28;
+	} reg019;
+
+	u32 reg020_cabac_error_en_lowbits;
+	u32 reg021_cabac_error_en_highbits;
+
+	u32 reg022_reserved;
+
+	struct swreg023_invalid_pixel_fill {
+		u32 fill_y			: 10;
+		u32 fill_u			: 10;
+		u32 fill_v			: 10;
+		u32 reserve0			: 2;
+	} reg023;
+
+	u32 reg024_026_reserved[3];
+
+	struct swreg027_align_en {
+		u32 reserve0			: 4;
+		u32 ctu_align_wr_en		: 1;
+		u32 reserve1			: 27;
+	} reg027;
+
+	struct swreg028_debug_perf_latency_ctrl0 {
+		u32 axi_perf_work_e		: 1;
+		u32 reserve0			: 2;
+		u32 axi_cnt_type		: 1;
+		u32 rd_latency_id		: 8;
+		u32 reserve1			: 4;
+		u32 rd_latency_thr		: 12;
+		u32 reserve2			: 4;
+	} reg028;
+
+	struct swreg029_debug_perf_latency_ctrl1 {
+		u32 addr_align_type		: 2;
+		u32 ar_cnt_id_type		: 1;
+		u32 aw_cnt_id_type		: 1;
+		u32 ar_count_id			: 8;
+		u32 reserve0			: 4;
+		u32 aw_count_id			: 8;
+		u32 rd_band_width_mode		: 1;
+		u32 reserve1			: 7;
+	} reg029;
+
+	struct swreg030_qos_ctrl {
+		u32 axi_wr_qos_level		: 4;
+		u32 reserve0			: 4;
+		u32 axi_wr_qos			: 4;
+		u32 reserve1			: 4;
+		u32 axi_rd_qos_level		: 4;
+		u32 reserve2			: 4;
+		u32 axi_rd_qos			: 4;
+		u32 reserve3			: 4;
+	} reg030;
+};
+
+struct vdpu383_regs_common_addr {
+	u32 reg128_strm_base;
+	u32 reg129_rps_base;
+	u32 reg130_cabactbl_base;
+	u32 reg131_gbl_base;
+	u32 reg132_scanlist_addr;
+	u32 reg133_scale_down_base;
+	u32 reg134_fgs_base;
+	u32 reg135_139_reserved[5];
+
+	struct rcb_info {
+	u32 offset;
+	u32 size;
+	} reg140_162_rcb_info[11];
+};
+
+struct vdpu383_regs_h26x_addr {
+	u32 reg168_decout_base;
+	u32 reg169_error_ref_base;
+	u32 reg170_185_ref_base[16];
+	u32 reg186_191_reserved[6];
+	u32 reg192_payload_st_cur_base;
+	u32 reg193_fbc_payload_offset;
+	u32 reg194_payload_st_error_ref_base;
+	u32 reg195_210_payload_st_ref_base[16];
+	u32 reg211_215_reserved[5];
+	u32 reg216_colmv_cur_base;
+	u32 reg217_232_colmv_ref_base[16];
+};
+
+struct vdpu383_regs_h26x_params {
+	u32 reg064_start_decoder;
+	u32 reg065_strm_start_bit;
+	u32 reg066_stream_len;
+	u32 reg067_global_len;
+	u32 reg068_hor_virstride;
+	u32 reg069_raster_uv_hor_virstride;
+	u32 reg070_y_virstride;
+	u32 reg071_scl_ref_hor_virstride;
+	u32 reg072_scl_ref_raster_uv_hor_virstride;
+	u32 reg073_scl_ref_virstride;
+	u32 reg074_fgs_ref_hor_virstride;
+	u32 reg075_079_reserved[5];
+	u32 reg080_error_ref_hor_virstride;
+	u32 reg081_error_ref_raster_uv_hor_virstride;
+	u32 reg082_error_ref_virstride;
+	u32 reg083_ref0_hor_virstride;
+	u32 reg084_ref0_raster_uv_hor_virstride;
+	u32 reg085_ref0_virstride;
+	u32 reg086_ref1_hor_virstride;
+	u32 reg087_ref1_raster_uv_hor_virstride;
+	u32 reg088_ref1_virstride;
+	u32 reg089_ref2_hor_virstride;
+	u32 reg090_ref2_raster_uv_hor_virstride;
+	u32 reg091_ref2_virstride;
+	u32 reg092_ref3_hor_virstride;
+	u32 reg093_ref3_raster_uv_hor_virstride;
+	u32 reg094_ref3_virstride;
+	u32 reg095_ref4_hor_virstride;
+	u32 reg096_ref4_raster_uv_hor_virstride;
+	u32 reg097_ref4_virstride;
+	u32 reg098_ref5_hor_virstride;
+	u32 reg099_ref5_raster_uv_hor_virstride;
+	u32 reg100_ref5_virstride;
+	u32 reg101_ref6_hor_virstride;
+	u32 reg102_ref6_raster_uv_hor_virstride;
+	u32 reg103_ref6_virstride;
+	u32 reg104_ref7_hor_virstride;
+	u32 reg105_ref7_raster_uv_hor_virstride;
+	u32 reg106_ref7_virstride;
+};
+
+struct vdpu383_regs_h26x {
+	struct vdpu383_regs_common		common;		/* 8-30 */
+	struct vdpu383_regs_h26x_params		h26x_params;	/* 64-74, 80-106 */
+	struct vdpu383_regs_common_addr		common_addr;	/* 128-134, 140-161 */
+	struct vdpu383_regs_h26x_addr		h26x_addr;	/* 168-185, 192-210, 216-232 */
+} __packed;
+
+#endif /* __RKVDEC_VDPU838_REGS_H__ */
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index 1ddae1b23434..ceb56516bd90 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -9,6 +9,7 @@
  * Copyright (C) 2011 Samsung Electronics Co., Ltd.
  */
 
+#include <linux/hw_bitfield.h>
 #include <linux/clk.h>
 #include <linux/genalloc.h>
 #include <linux/interrupt.h>
@@ -30,6 +31,7 @@
 #include "rkvdec.h"
 #include "rkvdec-regs.h"
 #include "rkvdec-vdpu381-regs.h"
+#include "rkvdec-vdpu383-regs.h"
 #include "rkvdec-rcb.h"
 
 static bool rkvdec_image_fmt_match(enum rkvdec_image_fmt fmt1,
@@ -86,17 +88,27 @@ static bool rkvdec_is_valid_fmt(struct rkvdec_ctx *ctx, u32 fourcc,
 	return false;
 }
 
+static u32 rkvdec_colmv_size(u16 width, u16 height)
+{
+	return 128 * DIV_ROUND_UP(width, 16) * DIV_ROUND_UP(height, 16);
+}
+
+static u32 vdpu383_colmv_size(u16 width, u16 height)
+{
+	return ALIGN(width, 64) * ALIGN(height, 16);
+}
+
 static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx,
 				       struct v4l2_pix_format_mplane *pix_mp)
 {
+	const struct rkvdec_variant *variant = ctx->dev->variant;
+
 	v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat,
 			    pix_mp->width, pix_mp->height);
 
 	ctx->colmv_offset = pix_mp->plane_fmt[0].sizeimage;
 
-	pix_mp->plane_fmt[0].sizeimage += 128 *
-		DIV_ROUND_UP(pix_mp->width, 16) *
-		DIV_ROUND_UP(pix_mp->height, 16);
+	pix_mp->plane_fmt[0].sizeimage += variant->ops->colmv_size(pix_mp->width, pix_mp->height);
 }
 
 static void rkvdec_reset_fmt(struct rkvdec_ctx *ctx, struct v4l2_format *f,
@@ -391,6 +403,26 @@ static const struct rkvdec_coded_fmt_desc vdpu381_coded_fmts[] = {
 	},
 };
 
+static const struct rkvdec_coded_fmt_desc vdpu383_coded_fmts[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_H264_SLICE,
+		.frmsize = {
+			.min_width = 64,
+			.max_width =  65520,
+			.step_width = 64,
+			.min_height = 64,
+			.max_height =  65520,
+			.step_height = 16,
+		},
+		.ctrls = &rkvdec_h264_ctrls,
+		.ops = &rkvdec_vdpu383_h264_fmt_ops,
+		.num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts),
+		.decoded_fmts = rkvdec_h264_decoded_fmts,
+		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
+		.capability = RKVDEC_CAPABILITY_H264,
+	},
+};
+
 static bool rkvdec_is_capable(struct rkvdec_ctx *ctx, unsigned int capability)
 {
 	return (ctx->dev->variant->capabilities & capability) == capability;
@@ -1294,6 +1326,35 @@ static irqreturn_t vdpu381_irq_handler(struct rkvdec_ctx *ctx)
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t vdpu383_irq_handler(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	enum vb2_buffer_state state;
+	bool need_reset = 0;
+	u32 status;
+
+	status = readl(rkvdec->link + VDPU383_LINK_STA_INT);
+	writel(FIELD_PREP_WM16(VDPU383_STA_INT_ALL, 0), rkvdec->link + VDPU383_LINK_STA_INT);
+	/* On vdpu383, the interrupts must be disabled */
+	writel(FIELD_PREP_WM16(VDPU383_INT_EN_IRQ | VDPU383_INT_EN_LINE_IRQ, 0),
+	       rkvdec->link + VDPU383_LINK_INT_EN);
+
+	if (status & VDPU383_STA_INT_DEC_RDY_STA) {
+		state = VB2_BUF_STATE_DONE;
+	} else {
+		state = VB2_BUF_STATE_ERROR;
+		rkvdec_iommu_restore(rkvdec);
+	}
+
+	if (need_reset)
+		rkvdec_iommu_restore(rkvdec);
+
+	if (cancel_delayed_work(&rkvdec->watchdog_work))
+		rkvdec_job_finish(ctx, state);
+
+	return IRQ_HANDLED;
+}
+
 static irqreturn_t rkvdec_irq_handler(int irq, void *priv)
 {
 	struct rkvdec_dev *rkvdec = priv;
@@ -1374,8 +1435,22 @@ static const struct rcb_size_info vdpu381_rcb_sizes[] = {
 	{67,	PIC_HEIGHT},	// filtc col
 };
 
+static const struct rcb_size_info vdpu383_rcb_sizes[] = {
+	{6,	PIC_WIDTH},	// streamd
+	{6,	PIC_WIDTH},	// streamd_tile
+	{12,	PIC_WIDTH},	// inter
+	{12,	PIC_WIDTH},	// inter_tile
+	{16,	PIC_WIDTH},	// intra
+	{10,	PIC_WIDTH},	// intra_tile
+	{120,	PIC_WIDTH},	// filterd
+	{120,	PIC_WIDTH},	// filterd_protect
+	{120,	PIC_WIDTH},	// filterd_tile_row
+	{180,	PIC_HEIGHT},	// filterd_tile_col
+};
+
 static const struct rkvdec_variant_ops rk3399_variant_ops = {
 	.irq_handler = rk3399_irq_handler,
+	.colmv_size = rkvdec_colmv_size,
 };
 
 static const struct rkvdec_variant rk3288_rkvdec_variant = {
@@ -1409,6 +1484,7 @@ static const struct rkvdec_variant rk3399_rkvdec_variant = {
 
 static const struct rkvdec_variant_ops vdpu381_variant_ops = {
 	.irq_handler = vdpu381_irq_handler,
+	.colmv_size = rkvdec_colmv_size,
 };
 
 static const struct rkvdec_variant rk3588_vdpu381_variant = {
@@ -1417,6 +1493,22 @@ static const struct rkvdec_variant rk3588_vdpu381_variant = {
 	.rcb_sizes = vdpu381_rcb_sizes,
 	.num_rcb_sizes = ARRAY_SIZE(vdpu381_rcb_sizes),
 	.ops = &vdpu381_variant_ops,
+	.named_regs = true,
+	.capabilities = RKVDEC_CAPABILITY_H264,
+};
+
+static const struct rkvdec_variant_ops vdpu383_variant_ops = {
+	.irq_handler = vdpu383_irq_handler,
+	.colmv_size = vdpu383_colmv_size,
+};
+
+static const struct rkvdec_variant rk3576_vdpu383_variant = {
+	.coded_fmts = vdpu383_coded_fmts,
+	.num_coded_fmts = ARRAY_SIZE(vdpu383_coded_fmts),
+	.rcb_sizes = vdpu383_rcb_sizes,
+	.num_rcb_sizes = ARRAY_SIZE(vdpu383_rcb_sizes),
+	.ops = &vdpu383_variant_ops,
+	.named_regs = true,
 	.capabilities = RKVDEC_CAPABILITY_H264,
 };
 
@@ -1437,6 +1529,10 @@ static const struct of_device_id of_rkvdec_match[] = {
 		.compatible = "rockchip,rk3588-vdec",
 		.data = &rk3588_vdpu381_variant,
 	},
+	{
+		.compatible = "rockchip,rk3576-vdec",
+		.data = &rk3576_vdpu383_variant,
+	},
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, of_rkvdec_match);
@@ -1472,9 +1568,19 @@ static int rkvdec_probe(struct platform_device *pdev)
 	rkvdec->num_clocks = ret;
 	rkvdec->axi_clk = devm_clk_get(&pdev->dev, "axi");
 
-	rkvdec->regs = devm_platform_ioremap_resource(pdev, 0);
-	if (IS_ERR(rkvdec->regs))
-		return PTR_ERR(rkvdec->regs);
+	if (rkvdec->variant->named_regs) {
+		rkvdec->regs = devm_platform_ioremap_resource_byname(pdev, "function");
+		if (IS_ERR(rkvdec->regs))
+			return PTR_ERR(rkvdec->regs);
+
+		rkvdec->link = devm_platform_ioremap_resource_byname(pdev, "link");
+		if (IS_ERR(rkvdec->link))
+			return PTR_ERR(rkvdec->link);
+	} else {
+		rkvdec->regs = devm_platform_ioremap_resource(pdev, 0);
+		if (IS_ERR(rkvdec->regs))
+			return PTR_ERR(rkvdec->regs);
+	}
 
 	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
 	if (ret) {
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
index 1ad9a4fc31db..2f924c924828 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
@@ -77,6 +77,7 @@ vb2_to_rkvdec_decoded_buf(struct vb2_buffer *buf)
 
 struct rkvdec_variant_ops {
 	irqreturn_t (*irq_handler)(struct rkvdec_ctx *ctx);
+	u32 (*colmv_size)(u16 width, u16 height);
 };
 
 struct rkvdec_variant {
@@ -86,6 +87,7 @@ struct rkvdec_variant {
 	const struct rcb_size_info *rcb_sizes;
 	size_t num_rcb_sizes;
 	const struct rkvdec_variant_ops *ops;
+	bool named_regs;
 	unsigned int capabilities;
 	unsigned int quirks;
 };
@@ -138,6 +140,7 @@ struct rkvdec_dev {
 	unsigned int num_clocks;
 	struct clk *axi_clk;
 	void __iomem *regs;
+	void __iomem *link;
 	struct mutex vdev_lock; /* serializes ioctls */
 	struct delayed_work watchdog_work;
 	struct gen_pool *sram_pool;
@@ -182,10 +185,15 @@ void rkvdec_memcpy_toio(void __iomem *dst, void *src, size_t len);
 
 void rkvdec_quirks_disable_qos(struct rkvdec_ctx *ctx);
 
+/* RKVDEC ops */
 extern const struct rkvdec_coded_fmt_ops rkvdec_h264_fmt_ops;
 extern const struct rkvdec_coded_fmt_ops rkvdec_hevc_fmt_ops;
 extern const struct rkvdec_coded_fmt_ops rkvdec_vp9_fmt_ops;
 
+/* VDPU381 ops */
 extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_h264_fmt_ops;
 
+/* VDPU383 ops */
+extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu383_h264_fmt_ops;
+
 #endif /* RKVDEC_H_ */
-- 
2.52.0



From detlev.casanova at collabora.com  Wed Dec 17 09:40:53 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 17 Dec 2025 12:40:53 -0500
Subject: [PATCH v6 16/17] media: rkvdec: Add HEVC support for the VDPU381 variant
In-Reply-To: <20251217174059.1341784-1-detlev.casanova@collabora.com>
References: <20251217174059.1341784-1-detlev.casanova@collabora.com>
Message-ID: <20251217174059.1341784-17-detlev.casanova@collabora.com>

The VDPU381 supports HEVC decoding up to 7680x4320 at 30fps.
It could double that when using both decoder cores.

It support YUV420 (8 and 10 bits) as well as AFBC (not implemented
here)

The fluster score is 146/147 for JCT-VC-HEVC_V1, tested on ROCK 5B.
None of the other test suites works.

Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../media/platform/rockchip/rkvdec/Kconfig    |   1 +
 .../media/platform/rockchip/rkvdec/Makefile   |   1 +
 .../rockchip/rkvdec/rkvdec-hevc-common.c      | 349 +++++++++-
 .../rockchip/rkvdec/rkvdec-hevc-common.h      |  73 +-
 .../rockchip/rkvdec/rkvdec-vdpu381-hevc.c     | 642 ++++++++++++++++++
 .../media/platform/rockchip/rkvdec/rkvdec.c   |  86 ++-
 .../media/platform/rockchip/rkvdec/rkvdec.h   |   3 +
 7 files changed, 1140 insertions(+), 15 deletions(-)
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c

diff --git a/drivers/media/platform/rockchip/rkvdec/Kconfig b/drivers/media/platform/rockchip/rkvdec/Kconfig
index 5f3bdd848a2c..3303b0ce3280 100644
--- a/drivers/media/platform/rockchip/rkvdec/Kconfig
+++ b/drivers/media/platform/rockchip/rkvdec/Kconfig
@@ -8,6 +8,7 @@ config VIDEO_ROCKCHIP_VDEC
 	select VIDEOBUF2_VMALLOC
 	select V4L2_MEM2MEM_DEV
 	select V4L2_H264
+	select V4L2_HEVC
 	select V4L2_VP9
 	help
 	  Support for the Rockchip Video Decoder IP present on Rockchip SoCs,
diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
index a58d4aede2fe..e30fdd7d51c3 100644
--- a/drivers/media/platform/rockchip/rkvdec/Makefile
+++ b/drivers/media/platform/rockchip/rkvdec/Makefile
@@ -9,5 +9,6 @@ rockchip-vdec-y += \
 		   rkvdec-hevc-common.o \
 		   rkvdec-rcb.o \
 		   rkvdec-vdpu381-h264.o \
+		   rkvdec-vdpu381-hevc.o \
 		   rkvdec-vdpu383-h264.o \
 		   rkvdec-vp9.o
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
index 23547e2e6e1d..4096b9e1aa65 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
@@ -21,6 +21,127 @@
 #include "rkvdec.h"
 #include "rkvdec-hevc-common.h"
 
+#define RKVDEC_HEVC_MAX_DEPTH_IN_BYTES		2
+
+/* Store the Short term ref pic set calculated values */
+struct calculated_rps_st_set {
+	u8 num_delta_pocs;
+	u8 num_negative_pics;
+	u8 num_positive_pics;
+	u8 used_by_curr_pic_s0[16];
+	u8 used_by_curr_pic_s1[16];
+	s32 delta_poc_s0[16];
+	s32 delta_poc_s1[16];
+};
+
+void compute_tiles_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size,
+			   u16 width, u16 height, s32 pic_in_cts_width,
+			   s32 pic_in_cts_height, u16 *column_width, u16 *row_height)
+{
+	const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+	int i;
+
+	for (i = 0; i < pps->num_tile_columns_minus1 + 1; i++)
+		column_width[i] = ((i + 1) * pic_in_cts_width) /
+				  (pps->num_tile_columns_minus1 + 1) -
+				  (i * pic_in_cts_width) /
+				  (pps->num_tile_columns_minus1 + 1);
+
+	for (i = 0; i < pps->num_tile_rows_minus1 + 1; i++)
+		row_height[i] = ((i + 1) * pic_in_cts_height) /
+				(pps->num_tile_rows_minus1 + 1) -
+				(i * pic_in_cts_height) /
+				(pps->num_tile_rows_minus1 + 1);
+}
+
+void compute_tiles_non_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size,
+			       u16 width, u16 height, s32 pic_in_cts_width,
+			       s32 pic_in_cts_height, u16 *column_width, u16 *row_height)
+{
+	const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+	s32 sum = 0;
+	int i;
+
+	for (i = 0; i < pps->num_tile_columns_minus1; i++) {
+		column_width[i] = pps->column_width_minus1[i] + 1;
+		sum += column_width[i];
+	}
+	column_width[i] = pic_in_cts_width - sum;
+
+	sum = 0;
+	for (i = 0; i < pps->num_tile_rows_minus1; i++) {
+		row_height[i] = pps->row_height_minus1[i] + 1;
+		sum += row_height[i];
+	}
+	row_height[i] = pic_in_cts_height - sum;
+}
+
+static void set_ref_poc(struct rkvdec_rps_short_term_ref_set *set, int poc, int value, int flag)
+{
+	switch (poc) {
+	case 0:
+		set->delta_poc0 = value;
+		set->used_flag0 = flag;
+		break;
+	case 1:
+		set->delta_poc1 = value;
+		set->used_flag1 = flag;
+		break;
+	case 2:
+		set->delta_poc2 = value;
+		set->used_flag2 = flag;
+		break;
+	case 3:
+		set->delta_poc3 = value;
+		set->used_flag3 = flag;
+		break;
+	case 4:
+		set->delta_poc4 = value;
+		set->used_flag4 = flag;
+		break;
+	case 5:
+		set->delta_poc5 = value;
+		set->used_flag5 = flag;
+		break;
+	case 6:
+		set->delta_poc6 = value;
+		set->used_flag6 = flag;
+		break;
+	case 7:
+		set->delta_poc7 = value;
+		set->used_flag7 = flag;
+		break;
+	case 8:
+		set->delta_poc8 = value;
+		set->used_flag8 = flag;
+		break;
+	case 9:
+		set->delta_poc9 = value;
+		set->used_flag9 = flag;
+		break;
+	case 10:
+		set->delta_poc10 = value;
+		set->used_flag10 = flag;
+		break;
+	case 11:
+		set->delta_poc11 = value;
+		set->used_flag11 = flag;
+		break;
+	case 12:
+		set->delta_poc12 = value;
+		set->used_flag12 = flag;
+		break;
+	case 13:
+		set->delta_poc13 = value;
+		set->used_flag13 = flag;
+		break;
+	case 14:
+		set->delta_poc14 = value;
+		set->used_flag14 = flag;
+		break;
+	}
+}
+
 /*
  * Flip one or more matrices along their main diagonal and flatten them
  * before writing it to the memory.
@@ -105,7 +226,7 @@ static void translate_scaling_list(struct scaling_factor *output,
 }
 
 void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
-					  struct scaling_factor *scaling_factor,
+					  struct scaling_factor *scaling_list,
 					  struct v4l2_ctrl_hevc_scaling_matrix *cache)
 {
 	const struct v4l2_ctrl_hevc_scaling_matrix *scaling = run->scaling_matrix;
@@ -114,15 +235,220 @@ void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
 		    sizeof(struct v4l2_ctrl_hevc_scaling_matrix)))
 		return;
 
-	translate_scaling_list(scaling_factor, scaling);
+	translate_scaling_list(scaling_list, scaling);
 
 	memcpy(cache, scaling,
 	       sizeof(struct v4l2_ctrl_hevc_scaling_matrix));
 }
 
-struct vb2_buffer *
-get_ref_buf(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run,
-	    unsigned int dpb_idx)
+static void rkvdec_hevc_assemble_hw_lt_rps(struct rkvdec_hevc_run *run, struct rkvdec_rps *rps)
+{
+	const struct v4l2_ctrl_hevc_sps *sps = run->sps;
+
+	if (!run->ext_sps_lt_rps)
+		return;
+
+	for (int i = 0; i < sps->num_long_term_ref_pics_sps; i++) {
+		rps->refs[i].lt_ref_pic_poc_lsb =
+			run->ext_sps_lt_rps[i].lt_ref_pic_poc_lsb_sps;
+		rps->refs[i].used_by_curr_pic_lt_flag =
+			!!(run->ext_sps_lt_rps[i].flags & V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_USED_LT);
+	}
+}
+
+static void rkvdec_hevc_assemble_hw_st_rps(struct rkvdec_hevc_run *run, struct rkvdec_rps *rps,
+					   struct calculated_rps_st_set *calculated_rps_st_sets)
+{
+	const struct v4l2_ctrl_hevc_sps *sps = run->sps;
+
+	for (int i = 0; i < sps->num_short_term_ref_pic_sets; i++) {
+		int poc = 0;
+		int j = 0;
+		const struct calculated_rps_st_set *set = &calculated_rps_st_sets[i];
+
+		rps->short_term_ref_sets[i].num_negative = set->num_negative_pics;
+		rps->short_term_ref_sets[i].num_positive = set->num_positive_pics;
+
+		for (; j < set->num_negative_pics; j++) {
+			set_ref_poc(&rps->short_term_ref_sets[i], j,
+				    set->delta_poc_s0[j], set->used_by_curr_pic_s0[j]);
+		}
+		poc = j;
+
+		for (j = 0; j < set->num_positive_pics; j++) {
+			set_ref_poc(&rps->short_term_ref_sets[i], poc + j,
+				    set->delta_poc_s1[j], set->used_by_curr_pic_s1[j]);
+		}
+	}
+}
+
+/*
+ * Compute the short term ref pic set parameters based on its reference short term ref pic
+ */
+static void st_ref_pic_set_prediction(struct rkvdec_hevc_run *run, int idx,
+				      struct calculated_rps_st_set *calculated_rps_st_sets)
+{
+	const struct v4l2_ctrl_hevc_ext_sps_st_rps *rps_data = &run->ext_sps_st_rps[idx];
+	struct calculated_rps_st_set *st_rps = &calculated_rps_st_sets[idx];
+	struct calculated_rps_st_set *ref_rps;
+	u8 st_rps_idx = idx;
+	u8 ref_rps_idx = 0;
+	s16 delta_rps = 0;
+	u8 use_delta_flag[16] = { 0 };
+	u8 used_by_curr_pic_flag[16] = { 0 };
+	int i, j;
+	int dPoc;
+
+	ref_rps_idx = st_rps_idx - (rps_data->delta_idx_minus1 + 1); /* 7-59 */
+	delta_rps = (1 - 2 * rps_data->delta_rps_sign) *
+		   (rps_data->abs_delta_rps_minus1 + 1); /* 7-60 */
+
+	ref_rps = &calculated_rps_st_sets[ref_rps_idx];
+
+	for (j = 0; j <= ref_rps->num_delta_pocs; j++) {
+		used_by_curr_pic_flag[j] = !!(rps_data->used_by_curr_pic & (1 << j));
+		use_delta_flag[j] = !!(rps_data->use_delta_flag & (1 << j));
+	}
+
+	/* 7-61: calculate num_negative_pics, delta_poc_s0 and used_by_curr_pic_s0 */
+	i = 0;
+	for (j = (ref_rps->num_positive_pics - 1); j >= 0; j--) {
+		dPoc = ref_rps->delta_poc_s1[j] + delta_rps;
+		if (dPoc < 0 && use_delta_flag[ref_rps->num_negative_pics + j]) {
+			st_rps->delta_poc_s0[i] = dPoc;
+			st_rps->used_by_curr_pic_s0[i++] =
+				used_by_curr_pic_flag[ref_rps->num_negative_pics + j];
+		}
+	}
+	if (delta_rps < 0 && use_delta_flag[ref_rps->num_delta_pocs]) {
+		st_rps->delta_poc_s0[i] = delta_rps;
+		st_rps->used_by_curr_pic_s0[i++] = used_by_curr_pic_flag[ref_rps->num_delta_pocs];
+	}
+	for (j = 0; j < ref_rps->num_negative_pics; j++) {
+		dPoc = ref_rps->delta_poc_s0[j] + delta_rps;
+		if (dPoc < 0 && use_delta_flag[j]) {
+			st_rps->delta_poc_s0[i] = dPoc;
+			st_rps->used_by_curr_pic_s0[i++] = used_by_curr_pic_flag[j];
+		}
+	}
+	st_rps->num_negative_pics = i;
+
+	/* 7-62: calculate num_positive_pics, delta_poc_s1 and used_by_curr_pic_s1 */
+	i = 0;
+	for (j = (ref_rps->num_negative_pics - 1); j >= 0; j--) {
+		dPoc = ref_rps->delta_poc_s0[j] + delta_rps;
+		if (dPoc > 0 && use_delta_flag[j]) {
+			st_rps->delta_poc_s1[i] = dPoc;
+			st_rps->used_by_curr_pic_s1[i++] = used_by_curr_pic_flag[j];
+		}
+	}
+	if (delta_rps > 0 && use_delta_flag[ref_rps->num_delta_pocs]) {
+		st_rps->delta_poc_s1[i] = delta_rps;
+		st_rps->used_by_curr_pic_s1[i++] = used_by_curr_pic_flag[ref_rps->num_delta_pocs];
+	}
+	for (j = 0; j < ref_rps->num_positive_pics; j++) {
+		dPoc = ref_rps->delta_poc_s1[j] + delta_rps;
+		if (dPoc > 0 && use_delta_flag[ref_rps->num_negative_pics + j]) {
+			st_rps->delta_poc_s1[i] = dPoc;
+			st_rps->used_by_curr_pic_s1[i++] =
+				used_by_curr_pic_flag[ref_rps->num_negative_pics + j];
+		}
+	}
+	st_rps->num_positive_pics = i;
+
+	st_rps->num_delta_pocs = st_rps->num_positive_pics + st_rps->num_negative_pics;
+}
+
+/*
+ * Compute the short term ref pic set parameters based on the control's data.
+ */
+static void st_ref_pic_set_calculate(struct rkvdec_hevc_run *run, int idx,
+				     struct calculated_rps_st_set *calculated_rps_st_sets)
+{
+	const struct v4l2_ctrl_hevc_ext_sps_st_rps *rps_data = &run->ext_sps_st_rps[idx];
+	struct calculated_rps_st_set *st_rps = &calculated_rps_st_sets[idx];
+	int j, i = 0;
+
+	/* 7-63 */
+	st_rps->num_negative_pics = rps_data->num_negative_pics;
+	/* 7-64 */
+	st_rps->num_positive_pics = rps_data->num_positive_pics;
+
+	for (i = 0; i < st_rps->num_negative_pics; i++) {
+		/* 7-65 */
+		st_rps->used_by_curr_pic_s0[i] = !!(rps_data->used_by_curr_pic & (1 << i));
+
+		if (i == 0) {
+			/* 7-67 */
+			st_rps->delta_poc_s0[i] = -(rps_data->delta_poc_s0_minus1[i] + 1);
+		} else {
+			/* 7-69 */
+			st_rps->delta_poc_s0[i] =
+				st_rps->delta_poc_s0[i - 1] -
+				(rps_data->delta_poc_s0_minus1[i] + 1);
+		}
+	}
+
+	for (j = 0; j < st_rps->num_positive_pics; j++) {
+		/* 7-66 */
+		st_rps->used_by_curr_pic_s1[j] = !!(rps_data->used_by_curr_pic & (1 << (i + j)));
+
+		if (j == 0) {
+			/* 7-68 */
+			st_rps->delta_poc_s1[j] = rps_data->delta_poc_s1_minus1[j] + 1;
+		} else {
+			/* 7-70 */
+			st_rps->delta_poc_s1[j] =
+				st_rps->delta_poc_s1[j - 1] +
+				(rps_data->delta_poc_s1_minus1[j] + 1);
+		}
+	}
+
+	/* 7-71 */
+	st_rps->num_delta_pocs = st_rps->num_positive_pics + st_rps->num_negative_pics;
+}
+
+static void rkvdec_hevc_prepare_hw_st_rps(struct rkvdec_hevc_run *run, struct rkvdec_rps *rps,
+					  struct v4l2_ctrl_hevc_ext_sps_st_rps *cache)
+{
+	int idx;
+
+	if (!run->ext_sps_st_rps)
+		return;
+
+	if (!memcmp(cache, run->ext_sps_st_rps, sizeof(struct v4l2_ctrl_hevc_ext_sps_st_rps)))
+		return;
+
+	struct calculated_rps_st_set *calculated_rps_st_sets =
+		kzalloc(sizeof(struct calculated_rps_st_set) *
+			run->sps->num_short_term_ref_pic_sets, GFP_KERNEL);
+
+	for (idx = 0; idx < run->sps->num_short_term_ref_pic_sets; idx++) {
+		const struct v4l2_ctrl_hevc_ext_sps_st_rps *rps_data = &run->ext_sps_st_rps[idx];
+
+		if (rps_data->flags & V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED)
+			st_ref_pic_set_prediction(run, idx, calculated_rps_st_sets);
+		else
+			st_ref_pic_set_calculate(run, idx, calculated_rps_st_sets);
+	}
+
+	rkvdec_hevc_assemble_hw_st_rps(run, rps, calculated_rps_st_sets);
+
+	kfree(calculated_rps_st_sets);
+
+	memcpy(cache, run->ext_sps_st_rps, sizeof(struct v4l2_ctrl_hevc_ext_sps_st_rps));
+}
+
+void rkvdec_hevc_assemble_hw_rps(struct rkvdec_hevc_run *run, struct rkvdec_rps *rps,
+				 struct v4l2_ctrl_hevc_ext_sps_st_rps *st_cache)
+{
+	rkvdec_hevc_prepare_hw_st_rps(run, rps, st_cache);
+	rkvdec_hevc_assemble_hw_lt_rps(run, rps);
+}
+
+struct vb2_buffer *get_ref_buf(struct rkvdec_ctx *ctx,
+			       struct rkvdec_hevc_run *run,
+			       unsigned int dpb_idx)
 {
 	struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
 	const struct v4l2_ctrl_hevc_decode_params *decode_params = run->decode_params;
@@ -143,8 +469,6 @@ get_ref_buf(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run,
 	return buf;
 }
 
-#define RKVDEC_HEVC_MAX_DEPTH_IN_BYTES		2
-
 int rkvdec_hevc_adjust_fmt(struct rkvdec_ctx *ctx, struct v4l2_format *f)
 {
 	struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp;
@@ -178,5 +502,16 @@ void rkvdec_hevc_run_preamble(struct rkvdec_ctx *ctx,
 			      V4L2_CID_STATELESS_HEVC_SCALING_MATRIX);
 	run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL;
 
+	if (ctx->has_sps_st_rps) {
+		ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+				      V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS);
+		run->ext_sps_st_rps = ctrl ? ctrl->p_cur.p : NULL;
+	}
+	if (ctx->has_sps_lt_rps) {
+		ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+				      V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS);
+		run->ext_sps_lt_rps = ctrl ? ctrl->p_cur.p : NULL;
+	}
+
 	rkvdec_run_preamble(ctx, &run->base);
 }
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
index 8af33bfd541c..4d345faae6b1 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
@@ -16,19 +16,70 @@
  */
 
 #include <media/v4l2-mem2mem.h>
+#include <linux/types.h>
 #include "rkvdec.h"
 
 #define RKV_HEVC_CABAC_TABLE_SIZE		27456
 extern const u8 rkvdec_hevc_cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
 
+struct rkvdec_rps_refs {
+	u16 lt_ref_pic_poc_lsb;
+	u16 used_by_curr_pic_lt_flag	: 1;
+	u16 reserved			: 15;
+} __packed;
+
+struct rkvdec_rps_short_term_ref_set {
+	u32 num_negative	: 4;
+	u32 num_positive	: 4;
+	u32 delta_poc0		: 16;
+	u32 used_flag0		: 1;
+	u32 delta_poc1		: 16;
+	u32 used_flag1		: 1;
+	u32 delta_poc2		: 16;
+	u32 used_flag2		: 1;
+	u32 delta_poc3		: 16;
+	u32 used_flag3		: 1;
+	u32 delta_poc4		: 16;
+	u32 used_flag4		: 1;
+	u32 delta_poc5		: 16;
+	u32 used_flag5		: 1;
+	u32 delta_poc6		: 16;
+	u32 used_flag6		: 1;
+	u32 delta_poc7		: 16;
+	u32 used_flag7		: 1;
+	u32 delta_poc8		: 16;
+	u32 used_flag8		: 1;
+	u32 delta_poc9		: 16;
+	u32 used_flag9		: 1;
+	u32 delta_poc10		: 16;
+	u32 used_flag10		: 1;
+	u32 delta_poc11		: 16;
+	u32 used_flag11		: 1;
+	u32 delta_poc12		: 16;
+	u32 used_flag12		: 1;
+	u32 delta_poc13		: 16;
+	u32 used_flag13		: 1;
+	u32 delta_poc14		: 16;
+	u32 used_flag14		: 1;
+	u32 reserved_bits	: 25;
+	u32 reserved[3];
+} __packed;
+
+struct rkvdec_rps {
+	struct rkvdec_rps_refs refs[32];
+	struct rkvdec_rps_short_term_ref_set short_term_ref_sets[64];
+} __packed;
+
 struct rkvdec_hevc_run {
-	struct rkvdec_run base;
-	const struct v4l2_ctrl_hevc_slice_params *slices_params;
-	const struct v4l2_ctrl_hevc_decode_params *decode_params;
-	const struct v4l2_ctrl_hevc_sps *sps;
-	const struct v4l2_ctrl_hevc_pps *pps;
-	const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix;
-	int num_slices;
+	struct rkvdec_run				base;
+	const struct v4l2_ctrl_hevc_decode_params	*decode_params;
+	const struct v4l2_ctrl_hevc_slice_params	*slices_params;
+	const struct v4l2_ctrl_hevc_sps			*sps;
+	const struct v4l2_ctrl_hevc_pps			*pps;
+	const struct v4l2_ctrl_hevc_scaling_matrix	*scaling_matrix;
+	const struct v4l2_ctrl_hevc_ext_sps_st_rps	*ext_sps_st_rps;
+	const struct v4l2_ctrl_hevc_ext_sps_lt_rps	*ext_sps_lt_rps;
+	int						num_slices;
 };
 
 struct scaling_factor {
@@ -38,6 +89,14 @@ struct scaling_factor {
 	u8 reserved[4];		/*16Bytes align*/
 };
 
+void compute_tiles_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size,
+			   u16 width, u16 height, s32 pic_in_cts_width,
+			   s32 pic_in_cts_height, u16 *column_width, u16 *row_height);
+void compute_tiles_non_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size,
+			       u16 width, u16 height, s32 pic_in_cts_width,
+			       s32 pic_in_cts_height, u16 *column_width, u16 *row_height);
+void rkvdec_hevc_assemble_hw_rps(struct rkvdec_hevc_run *run, struct rkvdec_rps *rps,
+				 struct v4l2_ctrl_hevc_ext_sps_st_rps *st_cache);
 void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
 					  struct scaling_factor *scaling_factor,
 					  struct v4l2_ctrl_hevc_scaling_matrix *cache);
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
new file mode 100644
index 000000000000..dcca81c6e6f7
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
@@ -0,0 +1,642 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip VDPU381 HEVC backend
+ *
+ * Copyright (C) 2025 Collabora, Ltd.
+ *  Detlev Casanova <detlev.casanova at collabora.com>
+ */
+
+#include <media/v4l2-mem2mem.h>
+
+#include "rkvdec.h"
+#include "rkvdec-rcb.h"
+#include "rkvdec-hevc-common.h"
+#include "rkvdec-vdpu381-regs.h"
+
+// SPS
+struct rkvdec_hevc_sps {
+	u16 video_parameters_set_id			: 4;
+	u16 seq_parameters_set_id_sps			: 4;
+	u16 chroma_format_idc				: 2;
+	u16 width					: 16;
+	u16 height					: 16;
+	u16 bit_depth_luma				: 4;
+	u16 bit_depth_chroma				: 4;
+	u16 max_pic_order_count_lsb			: 5;
+	u16 diff_max_min_luma_coding_block_size		: 2;
+	u16 min_luma_coding_block_size			: 3;
+	u16 min_transform_block_size			: 3;
+	u16 diff_max_min_transform_block_size		: 2;
+	u16 max_transform_hierarchy_depth_inter		: 3;
+	u16 max_transform_hierarchy_depth_intra		: 3;
+	u16 scaling_list_enabled_flag			: 1;
+	u16 amp_enabled_flag				: 1;
+	u16 sample_adaptive_offset_enabled_flag		: 1;
+	u16 pcm_enabled_flag				: 1;
+	u16 pcm_sample_bit_depth_luma			: 4;
+	u16 pcm_sample_bit_depth_chroma			: 4;
+	u16 pcm_loop_filter_disabled_flag		: 1;
+	u16 diff_max_min_pcm_luma_coding_block_size	: 3;
+	u16 min_pcm_luma_coding_block_size		: 3;
+	u16 num_short_term_ref_pic_sets			: 7;
+	u16 long_term_ref_pics_present_flag		: 1;
+	u16 num_long_term_ref_pics_sps			: 6;
+	u16 sps_temporal_mvp_enabled_flag		: 1;
+	u16 strong_intra_smoothing_enabled_flag		: 1;
+	u16 reserved_0					: 7;
+	u16 sps_max_dec_pic_buffering_minus1		: 4;
+	u16 reserved_0_2				: 3;
+	u16 reserved_f					: 8;
+} __packed;
+
+//PPS
+struct rkvdec_hevc_pps {
+	u16 picture_parameters_set_id			: 6;
+	u16 seq_parameters_set_id_pps			: 4;
+	u16 dependent_slice_segments_enabled_flag	: 1;
+	u16 output_flag_present_flag			: 1;
+	u16 num_extra_slice_header_bits			: 13;
+	u16 sign_data_hiding_enabled_flag		: 1;
+	u16 cabac_init_present_flag			: 1;
+	u16 num_ref_idx_l0_default_active		: 4;
+	u16 num_ref_idx_l1_default_active		: 4;
+	u16 init_qp_minus26				: 7;
+	u16 constrained_intra_pred_flag			: 1;
+	u16 transform_skip_enabled_flag			: 1;
+	u16 cu_qp_delta_enabled_flag			: 1;
+	u16 log2_min_cb_size				: 3;
+	u16 pps_cb_qp_offset				: 5;
+	u16 pps_cr_qp_offset				: 5;
+	u16 pps_slice_chroma_qp_offsets_present_flag	: 1;
+	u16 weighted_pred_flag				: 1;
+	u16 weighted_bipred_flag			: 1;
+	u16 transquant_bypass_enabled_flag		: 1;
+	u16 tiles_enabled_flag				: 1;
+	u16 entropy_coding_sync_enabled_flag		: 1;
+	u16 pps_loop_filter_across_slices_enabled_flag	: 1;
+	u16 loop_filter_across_tiles_enabled_flag	: 1;
+	u16 deblocking_filter_override_enabled_flag	: 1;
+	u16 pps_deblocking_filter_disabled_flag		: 1;
+	u16 pps_beta_offset_div2			: 4;
+	u16 pps_tc_offset_div2				: 4;
+	u16 lists_modification_present_flag		: 1;
+	u16 log2_parallel_merge_level			: 3;
+	u16 slice_segment_header_extension_present_flag	: 1;
+	u16 zeroes					: 3;
+	u16 num_tile_columns				: 5;
+	u16 num_tile_rows				: 5;
+	u16 sps_pps_mode				: 4;
+	u16 reserved_bits				: 14;
+	u16 reserved;
+} __packed;
+
+struct rkvdec_hevc_tile {
+	u16 value0	: 12;
+	u16 value1	: 12;
+} __packed;
+
+struct rkvdec_sps_pps_packet {
+	struct rkvdec_hevc_sps sps;
+	struct rkvdec_hevc_pps pps;
+	struct rkvdec_hevc_tile column_width[10];
+	struct rkvdec_hevc_tile row_height[11];
+	u32 zeroes[3];
+	u32 zeroes_bits		: 6;
+	u32 padding_bits	: 2;
+	u32 padding;
+} __packed;
+
+struct rkvdec_hevc_priv_tbl {
+	struct rkvdec_sps_pps_packet param_set[64];
+	struct rkvdec_rps rps;
+	struct scaling_factor scaling_list;
+	u8 cabac_table[27456];
+};
+
+struct rkvdec_hevc_ctx {
+	struct rkvdec_aux_buf			priv_tbl;
+	struct v4l2_ctrl_hevc_scaling_matrix	scaling_matrix_cache;
+	struct v4l2_ctrl_hevc_ext_sps_st_rps	st_cache;
+	struct rkvdec_vdpu381_regs_hevc		regs;
+};
+
+static void assemble_hw_pps(struct rkvdec_ctx *ctx,
+			    struct rkvdec_hevc_run *run)
+{
+	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
+	const struct v4l2_ctrl_hevc_sps *sps = run->sps;
+	const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+	struct rkvdec_hevc_priv_tbl *priv_tbl = hevc_ctx->priv_tbl.cpu;
+	struct rkvdec_sps_pps_packet *hw_ps;
+	bool tiles_enabled;
+	s32 max_cu_width;
+	s32 pic_in_cts_width;
+	s32 pic_in_cts_height;
+	u16 log2_min_cb_size, width, height;
+	u16 column_width[20];
+	u16 row_height[22];
+	u8 pcm_enabled;
+	u32 i;
+
+	/*
+	 * HW read the SPS/PPS information from PPS packet index by PPS id.
+	 * offset from the base can be calculated by PPS_id * 32 (size per PPS
+	 * packet unit). so the driver copy SPS/PPS information to the exact PPS
+	 * packet unit for HW accessing.
+	 */
+	hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id];
+	memset(hw_ps, 0, sizeof(*hw_ps));
+
+	/* write sps */
+	hw_ps->sps.video_parameters_set_id = sps->video_parameter_set_id;
+	hw_ps->sps.seq_parameters_set_id_sps = sps->seq_parameter_set_id;
+	hw_ps->sps.chroma_format_idc = sps->chroma_format_idc;
+
+	log2_min_cb_size = sps->log2_min_luma_coding_block_size_minus3 + 3;
+	width = sps->pic_width_in_luma_samples;
+	height = sps->pic_height_in_luma_samples;
+	hw_ps->sps.width = width;
+	hw_ps->sps.height = height;
+	hw_ps->sps.bit_depth_luma = sps->bit_depth_luma_minus8 + 8;
+	hw_ps->sps.bit_depth_chroma = sps->bit_depth_chroma_minus8 + 8;
+	hw_ps->sps.max_pic_order_count_lsb = sps->log2_max_pic_order_cnt_lsb_minus4 + 4;
+	hw_ps->sps.diff_max_min_luma_coding_block_size =
+		sps->log2_diff_max_min_luma_coding_block_size;
+	hw_ps->sps.min_luma_coding_block_size = sps->log2_min_luma_coding_block_size_minus3 + 3;
+	hw_ps->sps.min_transform_block_size = sps->log2_min_luma_transform_block_size_minus2 + 2;
+	hw_ps->sps.diff_max_min_transform_block_size =
+		sps->log2_diff_max_min_luma_transform_block_size;
+	hw_ps->sps.max_transform_hierarchy_depth_inter = sps->max_transform_hierarchy_depth_inter;
+	hw_ps->sps.max_transform_hierarchy_depth_intra = sps->max_transform_hierarchy_depth_intra;
+	hw_ps->sps.scaling_list_enabled_flag =
+		!!(sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED);
+	hw_ps->sps.amp_enabled_flag = !!(sps->flags & V4L2_HEVC_SPS_FLAG_AMP_ENABLED);
+	hw_ps->sps.sample_adaptive_offset_enabled_flag =
+		!!(sps->flags & V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET);
+
+	pcm_enabled = !!(sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED);
+	hw_ps->sps.pcm_enabled_flag = pcm_enabled;
+	hw_ps->sps.pcm_sample_bit_depth_luma =
+		pcm_enabled ? sps->pcm_sample_bit_depth_luma_minus1 + 1 : 0;
+	hw_ps->sps.pcm_sample_bit_depth_chroma =
+		pcm_enabled ? sps->pcm_sample_bit_depth_chroma_minus1 + 1 : 0;
+	hw_ps->sps.pcm_loop_filter_disabled_flag =
+		!!(sps->flags & V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED);
+	hw_ps->sps.diff_max_min_pcm_luma_coding_block_size =
+		sps->log2_diff_max_min_pcm_luma_coding_block_size;
+	hw_ps->sps.min_pcm_luma_coding_block_size =
+		pcm_enabled ? sps->log2_min_pcm_luma_coding_block_size_minus3 + 3 : 0;
+	hw_ps->sps.num_short_term_ref_pic_sets = sps->num_short_term_ref_pic_sets;
+	hw_ps->sps.long_term_ref_pics_present_flag =
+		!!(sps->flags & V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT);
+	hw_ps->sps.num_long_term_ref_pics_sps = sps->num_long_term_ref_pics_sps;
+	hw_ps->sps.sps_temporal_mvp_enabled_flag =
+		!!(sps->flags & V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED);
+	hw_ps->sps.strong_intra_smoothing_enabled_flag =
+		!!(sps->flags & V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED);
+	hw_ps->sps.sps_max_dec_pic_buffering_minus1 = sps->sps_max_dec_pic_buffering_minus1;
+	hw_ps->sps.reserved_f = 0xff;
+
+	/* write pps */
+	hw_ps->pps.picture_parameters_set_id = pps->pic_parameter_set_id;
+	hw_ps->pps.seq_parameters_set_id_pps = sps->seq_parameter_set_id;
+	hw_ps->pps.dependent_slice_segments_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED);
+	hw_ps->pps.output_flag_present_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT);
+	hw_ps->pps.num_extra_slice_header_bits = pps->num_extra_slice_header_bits;
+	hw_ps->pps.sign_data_hiding_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED);
+	hw_ps->pps.cabac_init_present_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT);
+	hw_ps->pps.num_ref_idx_l0_default_active = pps->num_ref_idx_l0_default_active_minus1 + 1;
+	hw_ps->pps.num_ref_idx_l1_default_active = pps->num_ref_idx_l1_default_active_minus1 + 1;
+	hw_ps->pps.init_qp_minus26 = pps->init_qp_minus26;
+	hw_ps->pps.constrained_intra_pred_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED);
+	hw_ps->pps.transform_skip_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED);
+	hw_ps->pps.cu_qp_delta_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED);
+	hw_ps->pps.log2_min_cb_size = log2_min_cb_size +
+				      sps->log2_diff_max_min_luma_coding_block_size -
+				      pps->diff_cu_qp_delta_depth;
+	hw_ps->pps.pps_cb_qp_offset = pps->pps_cb_qp_offset;
+	hw_ps->pps.pps_cr_qp_offset = pps->pps_cr_qp_offset;
+	hw_ps->pps.pps_slice_chroma_qp_offsets_present_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT);
+	hw_ps->pps.weighted_pred_flag = !!(pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED);
+	hw_ps->pps.weighted_bipred_flag = !!(pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED);
+	hw_ps->pps.transquant_bypass_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED);
+
+	tiles_enabled = !!(pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED);
+	hw_ps->pps.tiles_enabled_flag = tiles_enabled;
+	hw_ps->pps.entropy_coding_sync_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED);
+	hw_ps->pps.pps_loop_filter_across_slices_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED);
+	hw_ps->pps.loop_filter_across_tiles_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED);
+	hw_ps->pps.deblocking_filter_override_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED);
+	hw_ps->pps.pps_deblocking_filter_disabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER);
+	hw_ps->pps.pps_beta_offset_div2 = pps->pps_beta_offset_div2;
+	hw_ps->pps.pps_tc_offset_div2 = pps->pps_tc_offset_div2;
+	hw_ps->pps.lists_modification_present_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT);
+	hw_ps->pps.log2_parallel_merge_level = pps->log2_parallel_merge_level_minus2 + 2;
+	hw_ps->pps.slice_segment_header_extension_present_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT);
+	hw_ps->pps.num_tile_columns = tiles_enabled ? pps->num_tile_columns_minus1 + 1 : 0;
+	hw_ps->pps.num_tile_rows = tiles_enabled ? pps->num_tile_rows_minus1 + 1 : 0;
+	hw_ps->pps.sps_pps_mode = 0;
+	hw_ps->pps.reserved_bits = 0x3fff;
+	hw_ps->pps.reserved = 0xffff;
+
+	// Setup tiles information
+	memset(column_width, 0, sizeof(column_width));
+	memset(row_height, 0, sizeof(row_height));
+
+	max_cu_width = 1 << (sps->log2_diff_max_min_luma_coding_block_size + log2_min_cb_size);
+	pic_in_cts_width = (width + max_cu_width - 1) / max_cu_width;
+	pic_in_cts_height = (height + max_cu_width - 1) / max_cu_width;
+
+	if (pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED) {
+		if (pps->flags & V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING) {
+			compute_tiles_uniform(run, log2_min_cb_size, width, height,
+					      pic_in_cts_width, pic_in_cts_height,
+					      column_width, row_height);
+		} else {
+			compute_tiles_non_uniform(run, log2_min_cb_size, width, height,
+						  pic_in_cts_width, pic_in_cts_height,
+						  column_width, row_height);
+		}
+	} else {
+		column_width[0] = (width + max_cu_width - 1) / max_cu_width;
+		row_height[0] = (height + max_cu_width - 1) / max_cu_width;
+	}
+
+	for (i = 0; i < 20; i++) {
+		if (column_width[i] > 0)
+			column_width[i]--;
+
+		if (i & 1)
+			hw_ps->column_width[i / 2].value1 = column_width[i];
+		else
+			hw_ps->column_width[i / 2].value0 = column_width[i];
+	}
+
+	for (i = 0; i < 22; i++) {
+		if (row_height[i] > 0)
+			row_height[i]--;
+
+		if (i & 1)
+			hw_ps->row_height[i / 2].value1 = row_height[i];
+		else
+			hw_ps->row_height[i / 2].value0 = row_height[i];
+	}
+
+	hw_ps->padding = 0xffffffff;
+	hw_ps->padding_bits = 0x3;
+}
+
+static void set_ref_valid(struct rkvdec_vdpu381_regs_hevc *regs, int id, u32 valid)
+{
+	switch (id) {
+	case 0:
+		regs->hevc_param.reg099.hevc_ref_valid_0 = valid;
+		break;
+	case 1:
+		regs->hevc_param.reg099.hevc_ref_valid_1 = valid;
+		break;
+	case 2:
+		regs->hevc_param.reg099.hevc_ref_valid_2 = valid;
+		break;
+	case 3:
+		regs->hevc_param.reg099.hevc_ref_valid_3 = valid;
+		break;
+	case 4:
+		regs->hevc_param.reg099.hevc_ref_valid_4 = valid;
+		break;
+	case 5:
+		regs->hevc_param.reg099.hevc_ref_valid_5 = valid;
+		break;
+	case 6:
+		regs->hevc_param.reg099.hevc_ref_valid_6 = valid;
+		break;
+	case 7:
+		regs->hevc_param.reg099.hevc_ref_valid_7 = valid;
+		break;
+	case 8:
+		regs->hevc_param.reg099.hevc_ref_valid_8 = valid;
+		break;
+	case 9:
+		regs->hevc_param.reg099.hevc_ref_valid_9 = valid;
+		break;
+	case 10:
+		regs->hevc_param.reg099.hevc_ref_valid_10 = valid;
+		break;
+	case 11:
+		regs->hevc_param.reg099.hevc_ref_valid_11 = valid;
+		break;
+	case 12:
+		regs->hevc_param.reg099.hevc_ref_valid_12 = valid;
+		break;
+	case 13:
+		regs->hevc_param.reg099.hevc_ref_valid_13 = valid;
+		break;
+	case 14:
+		regs->hevc_param.reg099.hevc_ref_valid_14 = valid;
+		break;
+	}
+}
+
+static void rkvdec_write_regs(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
+
+	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_REGS,
+			   &hevc_ctx->regs.common,
+			   sizeof(hevc_ctx->regs.common));
+	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_PARAMS_REGS,
+			   &hevc_ctx->regs.hevc_param,
+			   sizeof(hevc_ctx->regs.hevc_param));
+	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_ADDR_REGS,
+			   &hevc_ctx->regs.common_addr,
+			   sizeof(hevc_ctx->regs.common_addr));
+	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_ADDR_REGS,
+			   &hevc_ctx->regs.hevc_addr,
+			   sizeof(hevc_ctx->regs.hevc_addr));
+	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_POC_HIGHBIT_REGS,
+			   &hevc_ctx->regs.hevc_highpoc,
+			   sizeof(hevc_ctx->regs.hevc_highpoc));
+}
+
+static void config_registers(struct rkvdec_ctx *ctx,
+			     struct rkvdec_hevc_run *run)
+{
+	const struct v4l2_ctrl_hevc_decode_params *dec_params = run->decode_params;
+	const struct v4l2_hevc_dpb_entry *dpb = dec_params->dpb;
+	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
+	struct rkvdec_vdpu381_regs_hevc *regs = &hevc_ctx->regs;
+	dma_addr_t priv_start_addr = hevc_ctx->priv_tbl.dma;
+	const struct v4l2_pix_format_mplane *dst_fmt;
+	struct vb2_v4l2_buffer *src_buf = run->base.bufs.src;
+	struct vb2_v4l2_buffer *dst_buf = run->base.bufs.dst;
+	const struct v4l2_format *f;
+	dma_addr_t rlc_addr;
+	u32 hor_virstride = 0;
+	u32 ver_virstride = 0;
+	u32 y_virstride = 0;
+	u32 offset;
+	u32 pixels;
+	dma_addr_t dst_addr;
+	u32 i;
+
+	memset(regs, 0, sizeof(*regs));
+
+	/* Set HEVC mode */
+	regs->common.reg009.dec_mode = VDPU381_MODE_HEVC;
+
+	/* Set config */
+	regs->common.reg011.buf_empty_en = 1;
+	regs->common.reg011.dec_clkgate_e = 1;
+	regs->common.reg011.dec_timeout_e = 1;
+	regs->common.reg011.pix_range_detection_e = 1;
+
+	/* Set IDR flag */
+	regs->common.reg013.cur_pic_is_idr =
+		!!(dec_params->flags & V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC);
+
+	/* Set input stream length */
+	regs->common.stream_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
+
+	/* Set max slice number */
+	regs->common.reg017.slice_num = 1;
+
+	/* Set strides */
+	f = &ctx->decoded_fmt;
+	dst_fmt = &f->fmt.pix_mp;
+	hor_virstride = dst_fmt->plane_fmt[0].bytesperline;
+	ver_virstride = dst_fmt->height;
+	y_virstride = hor_virstride * ver_virstride;
+	pixels = dst_fmt->height * dst_fmt->width;
+
+	regs->common.reg018.y_hor_virstride = hor_virstride / 16;
+	regs->common.reg019.uv_hor_virstride = hor_virstride / 16;
+	regs->common.reg020.y_virstride = y_virstride / 16;
+
+	/* Activate block gating */
+	regs->common.reg026.swreg_block_gating_e = 0xfffef;
+	regs->common.reg026.reg_cfg_gating_en = 1;
+
+	/* Set timeout threshold */
+	if (pixels < RKVDEC_1080P_PIXELS)
+		regs->common.timeout_threshold = RKVDEC_TIMEOUT_1080p;
+	else if (pixels < RKVDEC_4K_PIXELS)
+		regs->common.timeout_threshold = RKVDEC_TIMEOUT_4K;
+	else if (pixels < RKVDEC_8K_PIXELS)
+		regs->common.timeout_threshold = RKVDEC_TIMEOUT_8K;
+
+	/* Set POC val */
+	regs->hevc_param.cur_top_poc = dec_params->pic_order_cnt_val;
+
+	/* Set ref pic address & poc */
+	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
+		struct vb2_buffer *vb_buf = get_ref_buf(ctx, run, i);
+		dma_addr_t buf_dma = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
+		u32 valid = !!(dec_params->num_active_dpb_entries > i);
+
+		/* Set reference addresses */
+		regs->hevc_addr.ref_base[i] = buf_dma;
+
+		/* Set COLMV addresses */
+		regs->hevc_addr.colmv_base[i] = buf_dma + ctx->colmv_offset;
+
+		regs->hevc_param.reg067_082_ref_poc[i] =
+			dpb[i].pic_order_cnt_val;
+
+		set_ref_valid(regs, i, valid);
+		regs->hevc_param.reg103.ref_pic_layer_same_with_cur |= 1 << i;
+	}
+
+	/* Set rlc base address (input stream) */
+	rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+	regs->common_addr.rlc_base = rlc_addr;
+	regs->common_addr.rlcwrite_base = rlc_addr;
+
+	/* Set output base address */
+	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
+	regs->common_addr.decout_base = dst_addr;
+	regs->common_addr.error_ref_base = dst_addr;
+
+	/* Set colmv address */
+	regs->common_addr.colmv_cur_base = dst_addr + ctx->colmv_offset;
+
+	/* Set RCB addresses */
+	for (i = 0; i < rkvdec_rcb_buf_count(ctx); i++)
+		regs->common_addr.rcb_base[i] = rkvdec_rcb_buf_dma_addr(ctx, i);
+
+	/* Set hw pps address */
+	offset = offsetof(struct rkvdec_hevc_priv_tbl, param_set);
+	regs->hevc_addr.pps_base = priv_start_addr + offset;
+
+	/* Set hw rps address */
+	offset = offsetof(struct rkvdec_hevc_priv_tbl, rps);
+	regs->hevc_addr.rps_base = priv_start_addr + offset;
+
+	/* Set cabac table */
+	offset = offsetof(struct rkvdec_hevc_priv_tbl, cabac_table);
+	regs->hevc_addr.cabactbl_base = priv_start_addr + offset;
+
+	/* Set scaling matrix */
+	offset = offsetof(struct rkvdec_hevc_priv_tbl, scaling_list);
+	regs->hevc_addr.scanlist_addr = priv_start_addr + offset;
+
+	rkvdec_write_regs(ctx);
+}
+
+static enum rkvdec_image_fmt rkvdec_hevc_get_image_fmt(struct rkvdec_ctx *ctx,
+						       struct v4l2_ctrl *ctrl)
+{
+	const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps;
+
+	if (ctrl->id != V4L2_CID_STATELESS_HEVC_SPS)
+		return RKVDEC_IMG_FMT_ANY;
+
+	if (sps->bit_depth_luma_minus8 == 0)
+		return RKVDEC_IMG_FMT_420_8BIT;
+	else if (sps->bit_depth_luma_minus8 == 2)
+		return RKVDEC_IMG_FMT_420_10BIT;
+
+	return RKVDEC_IMG_FMT_ANY;
+}
+
+static int rkvdec_hevc_validate_sps(struct rkvdec_ctx *ctx,
+				    const struct v4l2_ctrl_hevc_sps *sps)
+{
+	if (sps->chroma_format_idc != 1)
+		/* Only 4:2:0 is supported */
+		return -EINVAL;
+
+	if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
+		/* Luma and chroma bit depth mismatch */
+		return -EINVAL;
+
+	if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2)
+		/* Only 8-bit and 10-bit are supported */
+		return -EINVAL;
+
+	if (sps->pic_width_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.width ||
+	    sps->pic_height_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.height)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int rkvdec_hevc_start(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_hevc_priv_tbl *priv_tbl;
+	struct rkvdec_hevc_ctx *hevc_ctx;
+	struct v4l2_ctrl *ctrl;
+	int ret;
+
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_HEVC_SPS);
+	if (!ctrl)
+		return -EINVAL;
+
+	ret = rkvdec_hevc_validate_sps(ctx, ctrl->p_new.p_hevc_sps);
+	if (ret)
+		return ret;
+
+	hevc_ctx = kzalloc(sizeof(*hevc_ctx), GFP_KERNEL);
+	if (!hevc_ctx)
+		return -ENOMEM;
+
+	priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl),
+				      &hevc_ctx->priv_tbl.dma, GFP_KERNEL);
+	if (!priv_tbl) {
+		ret = -ENOMEM;
+		goto err_free_ctx;
+	}
+
+	hevc_ctx->priv_tbl.size = sizeof(*priv_tbl);
+	hevc_ctx->priv_tbl.cpu = priv_tbl;
+	memcpy(priv_tbl->cabac_table, rkvdec_hevc_cabac_table,
+	       sizeof(rkvdec_hevc_cabac_table));
+
+	ctx->priv = hevc_ctx;
+	return 0;
+
+err_free_ctx:
+	kfree(hevc_ctx);
+	return ret;
+}
+
+static void rkvdec_hevc_stop(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
+	struct rkvdec_dev *rkvdec = ctx->dev;
+
+	dma_free_coherent(rkvdec->dev, hevc_ctx->priv_tbl.size,
+			  hevc_ctx->priv_tbl.cpu, hevc_ctx->priv_tbl.dma);
+	kfree(hevc_ctx);
+}
+
+static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_hevc_run run;
+	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
+	struct rkvdec_hevc_priv_tbl *tbl = hevc_ctx->priv_tbl.cpu;
+
+	rkvdec_hevc_run_preamble(ctx, &run);
+
+	/*
+	 * On vdpu381, not setting the long and short term ref sets will just output wrong frames.
+	 * Let's just warn about it and let the decoder run anyway.
+	 */
+	if ((!ctx->has_sps_lt_rps && run.sps->num_long_term_ref_pics_sps) ||
+		(!ctx->has_sps_st_rps && run.sps->num_short_term_ref_pic_sets)) {
+		dev_warn_ratelimited(rkvdec->dev, "Long and short term RPS not set\n");
+	}
+
+	rkvdec_hevc_assemble_hw_scaling_list(&run,
+					     &tbl->scaling_list,
+					     &hevc_ctx->scaling_matrix_cache);
+	assemble_hw_pps(ctx, &run);
+	rkvdec_hevc_assemble_hw_rps(&run, &tbl->rps, &hevc_ctx->st_cache);
+
+	config_registers(ctx, &run);
+
+	rkvdec_run_postamble(ctx, &run.base);
+
+	schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000));
+
+	/* Start decoding! */
+	writel(VDPU381_DEC_E_BIT, rkvdec->regs + VDPU381_REG_DEC_E);
+
+	return 0;
+}
+
+static int rkvdec_hevc_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
+{
+	if (ctrl->id == V4L2_CID_STATELESS_HEVC_SPS)
+		return rkvdec_hevc_validate_sps(ctx, ctrl->p_new.p_hevc_sps);
+
+	return 0;
+}
+
+const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_hevc_fmt_ops = {
+	.adjust_fmt = rkvdec_hevc_adjust_fmt,
+	.start = rkvdec_hevc_start,
+	.stop = rkvdec_hevc_stop,
+	.run = rkvdec_hevc_run,
+	.try_ctrl = rkvdec_hevc_try_ctrl,
+	.get_image_fmt = rkvdec_hevc_get_image_fmt,
+};
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index ceb56516bd90..7bb98c98a82b 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -154,6 +154,16 @@ static int rkvdec_s_ctrl(struct v4l2_ctrl *ctrl)
 	enum rkvdec_image_fmt image_fmt;
 	struct vb2_queue *vq;
 
+	if (ctrl->id == V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS) {
+		ctx->has_sps_st_rps |= !!(ctrl->has_changed);
+		return 0;
+	}
+
+	if (ctrl->id == V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS) {
+		ctx->has_sps_lt_rps |= !!(ctrl->has_changed);
+		return 0;
+	}
+
 	/* Check if this change requires a capture format reset */
 	if (!desc->ops->get_image_fmt)
 		return 0;
@@ -285,6 +295,62 @@ static const struct rkvdec_ctrls rkvdec_h264_ctrls = {
 	.num_ctrls = ARRAY_SIZE(rkvdec_h264_ctrl_descs),
 };
 
+static const struct rkvdec_ctrl_desc vdpu38x_hevc_ctrl_descs[] = {
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_SPS,
+		.cfg.ops = &rkvdec_ctrl_ops,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_PPS,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_MODE,
+		.cfg.min = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
+		.cfg.max = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
+		.cfg.def = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_START_CODE,
+		.cfg.min = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
+		.cfg.def = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
+		.cfg.max = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
+	},
+	{
+		.cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
+		.cfg.min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
+		.cfg.max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
+		.cfg.menu_skip_mask =
+			BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE),
+		.cfg.def = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
+	},
+	{
+		.cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
+		.cfg.min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
+		.cfg.max = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS,
+		.cfg.ops = &rkvdec_ctrl_ops,
+		.cfg.dims = { 65 },
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS,
+		.cfg.ops = &rkvdec_ctrl_ops,
+		.cfg.dims = { 65 },
+	},
+};
+
+static const struct rkvdec_ctrls vdpu38x_hevc_ctrls = {
+	.ctrls = vdpu38x_hevc_ctrl_descs,
+	.num_ctrls = ARRAY_SIZE(vdpu38x_hevc_ctrl_descs),
+};
+
 static const struct rkvdec_decoded_fmt_desc rkvdec_h264_decoded_fmts[] = {
 	{
 		.fourcc = V4L2_PIX_FMT_NV12,
@@ -401,6 +467,23 @@ static const struct rkvdec_coded_fmt_desc vdpu381_coded_fmts[] = {
 		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
 		.capability = RKVDEC_CAPABILITY_H264,
 	},
+	{
+		.fourcc = V4L2_PIX_FMT_HEVC_SLICE,
+		.frmsize = {
+			.min_width = 64,
+			.max_width = 65472,
+			.step_width = 64,
+			.min_height = 64,
+			.max_height = 65472,
+			.step_height = 16,
+		},
+		.ctrls = &vdpu38x_hevc_ctrls,
+		.ops = &rkvdec_vdpu381_hevc_fmt_ops,
+		.num_decoded_fmts = ARRAY_SIZE(rkvdec_hevc_decoded_fmts),
+		.decoded_fmts = rkvdec_hevc_decoded_fmts,
+		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
+		.capability = RKVDEC_CAPABILITY_HEVC,
+	},
 };
 
 static const struct rkvdec_coded_fmt_desc vdpu383_coded_fmts[] = {
@@ -1494,7 +1577,8 @@ static const struct rkvdec_variant rk3588_vdpu381_variant = {
 	.num_rcb_sizes = ARRAY_SIZE(vdpu381_rcb_sizes),
 	.ops = &vdpu381_variant_ops,
 	.named_regs = true,
-	.capabilities = RKVDEC_CAPABILITY_H264,
+	.capabilities = RKVDEC_CAPABILITY_H264 |
+			RKVDEC_CAPABILITY_HEVC,
 };
 
 static const struct rkvdec_variant_ops vdpu383_variant_ops = {
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
index 2f924c924828..44ff50ec6d85 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
@@ -160,6 +160,8 @@ struct rkvdec_ctx {
 	struct rkvdec_rcb_config *rcb_config;
 	u32 colmv_offset;
 	void *priv;
+	u8 has_sps_st_rps: 1;
+	u8 has_sps_lt_rps: 1;
 };
 
 static inline struct rkvdec_ctx *file_to_rkvdec_ctx(struct file *filp)
@@ -192,6 +194,7 @@ extern const struct rkvdec_coded_fmt_ops rkvdec_vp9_fmt_ops;
 
 /* VDPU381 ops */
 extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_h264_fmt_ops;
+extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_hevc_fmt_ops;
 
 /* VDPU383 ops */
 extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu383_h264_fmt_ops;
-- 
2.52.0



From detlev.casanova at collabora.com  Wed Dec 17 09:40:54 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 17 Dec 2025 12:40:54 -0500
Subject: [PATCH v6 17/17] media: rkvdec: Add HEVC support for the VDPU383 variant
In-Reply-To: <20251217174059.1341784-1-detlev.casanova@collabora.com>
References: <20251217174059.1341784-1-detlev.casanova@collabora.com>
Message-ID: <20251217174059.1341784-18-detlev.casanova@collabora.com>

The VDPU383 decoder is used on the RK3576 SoC and has support for HEVC.

This patch also moves some functions to a common rkvdec-hevc-common.c
file and adds a specific scaling matrix flatten function.

The fluster score for JCT-VC-HEVC_V1 is 146/147.

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../media/platform/rockchip/rkvdec/Makefile   |   1 +
 .../rockchip/rkvdec/rkvdec-hevc-common.c      |  59 +-
 .../rockchip/rkvdec/rkvdec-hevc-common.h      |   3 +-
 .../platform/rockchip/rkvdec/rkvdec-hevc.c    |   2 +-
 .../rockchip/rkvdec/rkvdec-vdpu381-hevc.c     |   3 +-
 .../rockchip/rkvdec/rkvdec-vdpu383-hevc.c     | 736 ++++++++++++++++++
 .../media/platform/rockchip/rkvdec/rkvdec.c   |  94 ++-
 .../media/platform/rockchip/rkvdec/rkvdec.h   |   2 +
 8 files changed, 851 insertions(+), 49 deletions(-)
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c

diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
index e30fdd7d51c3..e629d571e4d8 100644
--- a/drivers/media/platform/rockchip/rkvdec/Makefile
+++ b/drivers/media/platform/rockchip/rkvdec/Makefile
@@ -11,4 +11,5 @@ rockchip-vdec-y += \
 		   rkvdec-vdpu381-h264.o \
 		   rkvdec-vdpu381-hevc.o \
 		   rkvdec-vdpu383-h264.o \
+		   rkvdec-vdpu383-hevc.o \
 		   rkvdec-vp9.o
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
index 4096b9e1aa65..40849cee3a0d 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
@@ -142,56 +142,26 @@ static void set_ref_poc(struct rkvdec_rps_short_term_ref_set *set, int poc, int
 	}
 }
 
-/*
- * Flip one or more matrices along their main diagonal and flatten them
- * before writing it to the memory.
- * Convert:
- * ABCD         AEIM
- * EFGH     =>  BFJN     =>     AEIMBFJNCGKODHLP
- * IJKL         CGKO
- * MNOP         DHLP
- */
-static void transpose_and_flatten_matrices(u8 *output, const u8 *input,
-					   int matrices, int row_length)
-{
-	int i, j, row, x_offset, matrix_offset, rot_index, y_offset, matrix_size, new_value;
-
-	matrix_size = row_length * row_length;
-	for (i = 0; i < matrices; i++) {
-		row = 0;
-		x_offset = 0;
-		matrix_offset = i * matrix_size;
-		for (j = 0; j < matrix_size; j++) {
-			y_offset = j - (row * row_length);
-			rot_index = y_offset * row_length + x_offset;
-			new_value = *(input + i * matrix_size + j);
-			output[matrix_offset + rot_index] = new_value;
-			if ((j + 1) % row_length == 0) {
-				row += 1;
-				x_offset += 1;
-			}
-		}
-	}
-}
-
-static void assemble_scalingfactor0(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input)
+static void assemble_scalingfactor0(struct rkvdec_ctx *ctx, u8 *output,
+				    const struct v4l2_ctrl_hevc_scaling_matrix *input)
 {
+	const struct rkvdec_variant *variant = ctx->dev->variant;
 	int offset = 0;
 
-	transpose_and_flatten_matrices(output, (const u8 *)input->scaling_list_4x4, 6, 4);
+	variant->ops->flatten_matrices(output, (const u8 *)input->scaling_list_4x4, 6, 4);
 	offset = 6 * 16 * sizeof(u8);
-	transpose_and_flatten_matrices(output + offset, (const u8 *)input->scaling_list_8x8, 6, 8);
+	variant->ops->flatten_matrices(output + offset, (const u8 *)input->scaling_list_8x8, 6, 8);
 	offset += 6 * 64 * sizeof(u8);
-	transpose_and_flatten_matrices(output + offset,
-				       (const u8 *)input->scaling_list_16x16, 6, 8);
+	variant->ops->flatten_matrices(output + offset, (const u8 *)input->scaling_list_16x16,
+				       6, 8);
 	offset += 6 * 64 * sizeof(u8);
 	/* Add a 128 byte padding with 0s between the two 32x32 matrices */
-	transpose_and_flatten_matrices(output + offset,
-				       (const u8 *)input->scaling_list_32x32, 1, 8);
+	variant->ops->flatten_matrices(output + offset, (const u8 *)input->scaling_list_32x32,
+				       1, 8);
 	offset += 64 * sizeof(u8);
 	memset(output + offset, 0, 128);
 	offset += 128 * sizeof(u8);
-	transpose_and_flatten_matrices(output + offset,
+	variant->ops->flatten_matrices(output + offset,
 				       (const u8 *)input->scaling_list_32x32 + (64 * sizeof(u8)),
 				       1, 8);
 	offset += 64 * sizeof(u8);
@@ -216,16 +186,17 @@ static void assemble_scalingdc(u8 *output, const struct v4l2_ctrl_hevc_scaling_m
 	memcpy(output + 6 * sizeof(u8), list_32x32, 6 * sizeof(u8));
 }
 
-static void translate_scaling_list(struct scaling_factor *output,
+static void translate_scaling_list(struct rkvdec_ctx *ctx, struct scaling_factor *output,
 				   const struct v4l2_ctrl_hevc_scaling_matrix *input)
 {
-	assemble_scalingfactor0(output->scalingfactor0, input);
+	assemble_scalingfactor0(ctx, output->scalingfactor0, input);
 	memcpy(output->scalingfactor1, (const u8 *)input->scaling_list_4x4, 96);
 	assemble_scalingdc(output->scalingdc, input);
 	memset(output->reserved, 0, 4 * sizeof(u8));
 }
 
-void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
+void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_ctx *ctx,
+					  struct rkvdec_hevc_run *run,
 					  struct scaling_factor *scaling_list,
 					  struct v4l2_ctrl_hevc_scaling_matrix *cache)
 {
@@ -235,7 +206,7 @@ void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
 		    sizeof(struct v4l2_ctrl_hevc_scaling_matrix)))
 		return;
 
-	translate_scaling_list(scaling_list, scaling);
+	translate_scaling_list(ctx, scaling_list, scaling);
 
 	memcpy(cache, scaling,
 	       sizeof(struct v4l2_ctrl_hevc_scaling_matrix));
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
index 4d345faae6b1..1881f36df9b8 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
@@ -97,7 +97,8 @@ void compute_tiles_non_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size
 			       s32 pic_in_cts_height, u16 *column_width, u16 *row_height);
 void rkvdec_hevc_assemble_hw_rps(struct rkvdec_hevc_run *run, struct rkvdec_rps *rps,
 				 struct v4l2_ctrl_hevc_ext_sps_st_rps *st_cache);
-void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
+void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_ctx *ctx,
+					  struct rkvdec_hevc_run *run,
 					  struct scaling_factor *scaling_factor,
 					  struct v4l2_ctrl_hevc_scaling_matrix *cache);
 struct vb2_buffer *get_ref_buf(struct rkvdec_ctx *ctx,
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
index 650c20f3f4aa..4af405ec5baf 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
@@ -589,7 +589,7 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
 
 	rkvdec_hevc_run_preamble(ctx, &run);
 
-	rkvdec_hevc_assemble_hw_scaling_list(&run, &tbl->scaling_list,
+	rkvdec_hevc_assemble_hw_scaling_list(ctx, &run, &tbl->scaling_list,
 					     &hevc_ctx->scaling_matrix_cache);
 	assemble_hw_pps(ctx, &run);
 	assemble_sw_rps(ctx, &run);
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
index dcca81c6e6f7..fa665b3bc711 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
@@ -606,8 +606,7 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
 		dev_warn_ratelimited(rkvdec->dev, "Long and short term RPS not set\n");
 	}
 
-	rkvdec_hevc_assemble_hw_scaling_list(&run,
-					     &tbl->scaling_list,
+	rkvdec_hevc_assemble_hw_scaling_list(ctx, &run, &tbl->scaling_list,
 					     &hevc_ctx->scaling_matrix_cache);
 	assemble_hw_pps(ctx, &run);
 	rkvdec_hevc_assemble_hw_rps(&run, &tbl->rps, &hevc_ctx->st_cache);
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c
new file mode 100644
index 000000000000..1926d58d5cac
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c
@@ -0,0 +1,736 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip VDPU383 HEVC backend
+ *
+ * Copyright (C) 2025 Collabora, Ltd.
+ *  Detlev Casanova <detlev.casanova at collabora.com>
+ */
+
+#include <media/v4l2-mem2mem.h>
+
+#include "rkvdec.h"
+#include "rkvdec-rcb.h"
+#include "rkvdec-hevc-common.h"
+#include "rkvdec-vdpu383-regs.h"
+
+struct rkvdec_hevc_sps_pps {
+	// SPS
+	u16 video_parameters_set_id			: 4;
+	u16 seq_parameters_set_id_sps			: 4;
+	u16 chroma_format_idc				: 2;
+	u16 width					: 16;
+	u16 height					: 16;
+	u16 bit_depth_luma				: 3;
+	u16 bit_depth_chroma				: 3;
+	u16 max_pic_order_count_lsb			: 5;
+	u16 diff_max_min_luma_coding_block_size		: 2;
+	u16 min_luma_coding_block_size			: 3;
+	u16 min_transform_block_size			: 3;
+	u16 diff_max_min_transform_block_size		: 2;
+	u16 max_transform_hierarchy_depth_inter		: 3;
+	u16 max_transform_hierarchy_depth_intra		: 3;
+	u16 scaling_list_enabled_flag			: 1;
+	u16 amp_enabled_flag				: 1;
+	u16 sample_adaptive_offset_enabled_flag		: 1;
+	u16 pcm_enabled_flag				: 1;
+	u16 pcm_sample_bit_depth_luma			: 4;
+	u16 pcm_sample_bit_depth_chroma			: 4;
+	u16 pcm_loop_filter_disabled_flag		: 1;
+	u16 diff_max_min_pcm_luma_coding_block_size	: 3;
+	u16 min_pcm_luma_coding_block_size		: 3;
+	u16 num_short_term_ref_pic_sets			: 7;
+	u16 long_term_ref_pics_present_flag		: 1;
+	u16 num_long_term_ref_pics_sps			: 6;
+	u16 sps_temporal_mvp_enabled_flag		: 1;
+	u16 strong_intra_smoothing_enabled_flag		: 1;
+	u16 reserved0					: 7;
+	u16 sps_max_dec_pic_buffering_minus1		: 4;
+	u16 separate_colour_plane_flag			: 1;
+	u16 high_precision_offsets_enabled_flag		: 1;
+	u16 persistent_rice_adaptation_enabled_flag	: 1;
+
+	// PPS
+	u16 picture_parameters_set_id			: 6;
+	u16 seq_parameters_set_id_pps			: 4;
+	u16 dependent_slice_segments_enabled_flag	: 1;
+	u16 output_flag_present_flag			: 1;
+	u16 num_extra_slice_header_bits			: 13;
+	u16 sign_data_hiding_enabled_flag		: 1;
+	u16 cabac_init_present_flag			: 1;
+	u16 num_ref_idx_l0_default_active		: 4;
+	u16 num_ref_idx_l1_default_active		: 4;
+	u16 init_qp_minus26				: 7;
+	u16 constrained_intra_pred_flag			: 1;
+	u16 transform_skip_enabled_flag			: 1;
+	u16 cu_qp_delta_enabled_flag			: 1;
+	u16 log2_min_cb_size				: 3;
+	u16 pps_cb_qp_offset				: 5;
+	u16 pps_cr_qp_offset				: 5;
+	u16 pps_slice_chroma_qp_offsets_present_flag	: 1;
+	u16 weighted_pred_flag				: 1;
+	u16 weighted_bipred_flag			: 1;
+	u16 transquant_bypass_enabled_flag		: 1;
+	u16 tiles_enabled_flag				: 1;
+	u16 entropy_coding_sync_enabled_flag		: 1;
+	u16 pps_loop_filter_across_slices_enabled_flag	: 1;
+	u16 loop_filter_across_tiles_enabled_flag	: 1;
+	u16 deblocking_filter_override_enabled_flag	: 1;
+	u16 pps_deblocking_filter_disabled_flag		: 1;
+	u16 pps_beta_offset_div2			: 4;
+	u16 pps_tc_offset_div2				: 4;
+	u16 lists_modification_present_flag		: 1;
+	u16 log2_parallel_merge_level			: 3;
+	u16 slice_segment_header_extension_present_flag	: 1;
+	u16 reserved1					: 3;
+
+	// pps extensions
+	u16 log2_max_transform_skip_block_size		: 2;
+	u16 cross_component_prediction_enabled_flag	: 1;
+	u16 chroma_qp_offset_list_enabled_flag		: 1;
+	u16 log2_min_cu_chroma_qp_delta_size		: 3;
+	u16 cb_qp_offset_list0				: 5;
+	u16 cb_qp_offset_list1				: 5;
+	u16 cb_qp_offset_list2				: 5;
+	u16 cb_qp_offset_list3				: 5;
+	u16 cb_qp_offset_list4				: 5;
+	u16 cb_qp_offset_list5				: 5;
+	u16 cb_cr_offset_list0				: 5;
+	u16 cb_cr_offset_list1				: 5;
+	u16 cb_cr_offset_list2				: 5;
+	u16 cb_cr_offset_list3				: 5;
+	u16 cb_cr_offset_list4				: 5;
+	u16 cb_cr_offset_list5				: 5;
+	u16 chroma_qp_offset_list_len_minus1		: 3;
+
+	/* mvc0 && mvc1 */
+	u16 mvc_ff					: 16;
+	u16 mvc_00					: 9;
+
+	/* poc info */
+	u16 reserved2					: 3;
+	u32 current_poc					: 32;
+	u32 ref_pic_poc0				: 32;
+	u32 ref_pic_poc1				: 32;
+	u32 ref_pic_poc2				: 32;
+	u32 ref_pic_poc3				: 32;
+	u32 ref_pic_poc4				: 32;
+	u32 ref_pic_poc5				: 32;
+	u32 ref_pic_poc6				: 32;
+	u32 ref_pic_poc7				: 32;
+	u32 ref_pic_poc8				: 32;
+	u32 ref_pic_poc9				: 32;
+	u32 ref_pic_poc10				: 32;
+	u32 ref_pic_poc11				: 32;
+	u32 ref_pic_poc12				: 32;
+	u32 ref_pic_poc13				: 32;
+	u32 ref_pic_poc14				: 32;
+	u32 reserved3					: 32;
+	u32 ref_is_valid				: 15;
+	u32 reserved4					: 1;
+
+	/* tile info*/
+	u16 num_tile_columns				: 5;
+	u16 num_tile_rows				: 5;
+	u32 column_width0				: 24;
+	u32 column_width1				: 24;
+	u32 column_width2				: 24;
+	u32 column_width3				: 24;
+	u32 column_width4				: 24;
+	u32 column_width5				: 24;
+	u32 column_width6				: 24;
+	u32 column_width7				: 24;
+	u32 column_width8				: 24;
+	u32 column_width9				: 24;
+	u32 row_height0					: 24;
+	u32 row_height1					: 24;
+	u32 row_height2					: 24;
+	u32 row_height3					: 24;
+	u32 row_height4					: 24;
+	u32 row_height5					: 24;
+	u32 row_height6					: 24;
+	u32 row_height7					: 24;
+	u32 row_height8					: 24;
+	u32 row_height9					: 24;
+	u32 row_height10				: 24;
+	u32 reserved5					: 2;
+	u32 padding;
+} __packed;
+
+struct rkvdec_hevc_priv_tbl {
+	struct rkvdec_hevc_sps_pps param_set;
+	struct rkvdec_rps rps;
+	struct scaling_factor scaling_list;
+	u8 cabac_table[27456];
+}  __packed;
+
+struct rkvdec_hevc_ctx {
+	struct rkvdec_aux_buf			priv_tbl;
+	struct v4l2_ctrl_hevc_scaling_matrix	scaling_matrix_cache;
+	struct v4l2_ctrl_hevc_ext_sps_st_rps	st_cache;
+	struct vdpu383_regs_h26x		regs;
+};
+
+static void set_column_row(struct rkvdec_hevc_sps_pps *hw_ps, u16 column, u16 row, int i)
+{
+	int shift = (i & 1) ? 12 : 0;
+
+	switch (i / 2) {
+	case 0:
+		hw_ps->column_width0 |= column << shift;
+		hw_ps->row_height0 |= row << shift;
+		break;
+	case 1:
+		hw_ps->column_width1 |= column << shift;
+		hw_ps->row_height1 |= row << shift;
+		break;
+	case 2:
+		hw_ps->column_width2 |= column << shift;
+		hw_ps->row_height2 |= row << shift;
+		break;
+	case 3:
+		hw_ps->column_width3 |= column << shift;
+		hw_ps->row_height3 |= row << shift;
+		break;
+	case 4:
+		hw_ps->column_width4 |= column << shift;
+		hw_ps->row_height4 |= row << shift;
+		break;
+	case 5:
+		hw_ps->column_width5 |= column << shift;
+		hw_ps->row_height5 |= row << shift;
+		break;
+	case 6:
+		hw_ps->column_width6 |= column << shift;
+		hw_ps->row_height6 |= row << shift;
+		break;
+	case 7:
+		hw_ps->column_width7 |= column << shift;
+		hw_ps->row_height7 |= row << shift;
+		break;
+	case 8:
+		hw_ps->column_width8 |= column << shift;
+		hw_ps->row_height8 |= row << shift;
+		break;
+	case 9:
+		hw_ps->column_width9 |= column << shift;
+		hw_ps->row_height9 |= row << shift;
+		break;
+	case 10:
+		hw_ps->row_height10 |= row << shift;
+		break;
+	}
+}
+
+static void set_pps_ref_pic_poc(struct rkvdec_hevc_sps_pps *hw_ps, u32 poc, int i)
+{
+	switch (i) {
+	case 0:
+		hw_ps->ref_pic_poc0 = poc;
+		break;
+	case 1:
+		hw_ps->ref_pic_poc1 = poc;
+		break;
+	case 2:
+		hw_ps->ref_pic_poc2 = poc;
+		break;
+	case 3:
+		hw_ps->ref_pic_poc3 = poc;
+		break;
+	case 4:
+		hw_ps->ref_pic_poc4 = poc;
+		break;
+	case 5:
+		hw_ps->ref_pic_poc5 = poc;
+		break;
+	case 6:
+		hw_ps->ref_pic_poc6 = poc;
+		break;
+	case 7:
+		hw_ps->ref_pic_poc7 = poc;
+		break;
+	case 8:
+		hw_ps->ref_pic_poc8 = poc;
+		break;
+	case 9:
+		hw_ps->ref_pic_poc9 = poc;
+		break;
+	case 10:
+		hw_ps->ref_pic_poc10 = poc;
+		break;
+	case 11:
+		hw_ps->ref_pic_poc11 = poc;
+		break;
+	case 12:
+		hw_ps->ref_pic_poc12 = poc;
+		break;
+	case 13:
+		hw_ps->ref_pic_poc13 = poc;
+		break;
+	case 14:
+		hw_ps->ref_pic_poc14 = poc;
+		break;
+	}
+}
+
+static void assemble_hw_pps(struct rkvdec_ctx *ctx,
+			    struct rkvdec_hevc_run *run)
+{
+	struct rkvdec_hevc_ctx *h264_ctx = ctx->priv;
+	const struct v4l2_ctrl_hevc_sps *sps = run->sps;
+	const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+	const struct v4l2_ctrl_hevc_decode_params *dec_params = run->decode_params;
+	struct rkvdec_hevc_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu;
+	struct rkvdec_hevc_sps_pps *hw_ps;
+	bool tiles_enabled;
+	s32 max_cu_width;
+	s32 pic_in_cts_width;
+	s32 pic_in_cts_height;
+	u16 log2_min_cb_size, width, height;
+	u16 column_width[22];
+	u16 row_height[22];
+	u8 pcm_enabled;
+	u32 i;
+
+	/*
+	 * HW read the SPS/PPS information from PPS packet index by PPS id.
+	 * offset from the base can be calculated by PPS_id * 32 (size per PPS
+	 * packet unit). so the driver copy SPS/PPS information to the exact PPS
+	 * packet unit for HW accessing.
+	 */
+	hw_ps = &priv_tbl->param_set;
+	memset(hw_ps, 0, sizeof(*hw_ps));
+
+	/* write sps */
+	hw_ps->video_parameters_set_id = sps->video_parameter_set_id;
+	hw_ps->seq_parameters_set_id_sps = sps->seq_parameter_set_id;
+	hw_ps->chroma_format_idc = sps->chroma_format_idc;
+
+	log2_min_cb_size = sps->log2_min_luma_coding_block_size_minus3 + 3;
+	width = sps->pic_width_in_luma_samples;
+	height = sps->pic_height_in_luma_samples;
+	hw_ps->width = width;
+	hw_ps->height = height;
+	hw_ps->bit_depth_luma = sps->bit_depth_luma_minus8 + 8;
+	hw_ps->bit_depth_chroma = sps->bit_depth_chroma_minus8 + 8;
+	hw_ps->max_pic_order_count_lsb = sps->log2_max_pic_order_cnt_lsb_minus4 + 4;
+	hw_ps->diff_max_min_luma_coding_block_size = sps->log2_diff_max_min_luma_coding_block_size;
+	hw_ps->min_luma_coding_block_size = sps->log2_min_luma_coding_block_size_minus3 + 3;
+	hw_ps->min_transform_block_size = sps->log2_min_luma_transform_block_size_minus2 + 2;
+	hw_ps->diff_max_min_transform_block_size =
+		sps->log2_diff_max_min_luma_transform_block_size;
+	hw_ps->max_transform_hierarchy_depth_inter = sps->max_transform_hierarchy_depth_inter;
+	hw_ps->max_transform_hierarchy_depth_intra = sps->max_transform_hierarchy_depth_intra;
+	hw_ps->scaling_list_enabled_flag =
+		!!(sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED);
+	hw_ps->amp_enabled_flag = !!(sps->flags & V4L2_HEVC_SPS_FLAG_AMP_ENABLED);
+	hw_ps->sample_adaptive_offset_enabled_flag =
+		!!(sps->flags & V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET);
+
+	pcm_enabled = !!(sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED);
+	hw_ps->pcm_enabled_flag = pcm_enabled;
+	hw_ps->pcm_sample_bit_depth_luma =
+		pcm_enabled ? sps->pcm_sample_bit_depth_luma_minus1 + 1 : 0;
+	hw_ps->pcm_sample_bit_depth_chroma =
+		pcm_enabled ? sps->pcm_sample_bit_depth_chroma_minus1 + 1 : 0;
+	hw_ps->pcm_loop_filter_disabled_flag =
+		!!(sps->flags & V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED);
+	hw_ps->diff_max_min_pcm_luma_coding_block_size =
+		sps->log2_diff_max_min_pcm_luma_coding_block_size;
+	hw_ps->min_pcm_luma_coding_block_size =
+		pcm_enabled ? sps->log2_min_pcm_luma_coding_block_size_minus3 + 3 : 0;
+	hw_ps->num_short_term_ref_pic_sets = sps->num_short_term_ref_pic_sets;
+	hw_ps->long_term_ref_pics_present_flag =
+		!!(sps->flags & V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT);
+	hw_ps->num_long_term_ref_pics_sps = sps->num_long_term_ref_pics_sps;
+	hw_ps->sps_temporal_mvp_enabled_flag =
+		!!(sps->flags & V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED);
+	hw_ps->strong_intra_smoothing_enabled_flag =
+		!!(sps->flags & V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED);
+	hw_ps->sps_max_dec_pic_buffering_minus1 = sps->sps_max_dec_pic_buffering_minus1;
+
+	/* write pps */
+	hw_ps->picture_parameters_set_id = pps->pic_parameter_set_id;
+	hw_ps->seq_parameters_set_id_pps = sps->seq_parameter_set_id;
+	hw_ps->dependent_slice_segments_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED);
+	hw_ps->output_flag_present_flag = !!(pps->flags & V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT);
+	hw_ps->num_extra_slice_header_bits = pps->num_extra_slice_header_bits;
+	hw_ps->sign_data_hiding_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED);
+	hw_ps->cabac_init_present_flag = !!(pps->flags & V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT);
+	hw_ps->num_ref_idx_l0_default_active = pps->num_ref_idx_l0_default_active_minus1 + 1;
+	hw_ps->num_ref_idx_l1_default_active = pps->num_ref_idx_l1_default_active_minus1 + 1;
+	hw_ps->init_qp_minus26 = pps->init_qp_minus26;
+	hw_ps->constrained_intra_pred_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED);
+	hw_ps->transform_skip_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED);
+	hw_ps->cu_qp_delta_enabled_flag = !!(pps->flags & V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED);
+	hw_ps->log2_min_cb_size = log2_min_cb_size +
+				  sps->log2_diff_max_min_luma_coding_block_size -
+				  pps->diff_cu_qp_delta_depth;
+	hw_ps->pps_cb_qp_offset = pps->pps_cb_qp_offset;
+	hw_ps->pps_cr_qp_offset = pps->pps_cr_qp_offset;
+	hw_ps->pps_slice_chroma_qp_offsets_present_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT);
+	hw_ps->weighted_pred_flag = !!(pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED);
+	hw_ps->weighted_bipred_flag = !!(pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED);
+	hw_ps->transquant_bypass_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED);
+	tiles_enabled = !!(pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED);
+	hw_ps->tiles_enabled_flag = tiles_enabled;
+	hw_ps->entropy_coding_sync_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED);
+	hw_ps->pps_loop_filter_across_slices_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED);
+	hw_ps->loop_filter_across_tiles_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED);
+	hw_ps->deblocking_filter_override_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED);
+	hw_ps->pps_deblocking_filter_disabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER);
+	hw_ps->pps_beta_offset_div2 = pps->pps_beta_offset_div2;
+	hw_ps->pps_tc_offset_div2 = pps->pps_tc_offset_div2;
+	hw_ps->lists_modification_present_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT);
+	hw_ps->log2_parallel_merge_level = pps->log2_parallel_merge_level_minus2 + 2;
+	hw_ps->slice_segment_header_extension_present_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT);
+	hw_ps->num_tile_columns = tiles_enabled ? pps->num_tile_columns_minus1 + 1 : 1;
+	hw_ps->num_tile_rows = tiles_enabled ? pps->num_tile_rows_minus1 + 1 : 1;
+	hw_ps->mvc_ff = 0xffff;
+
+	// Setup tiles information
+	memset(column_width, 0, sizeof(column_width));
+	memset(row_height, 0, sizeof(row_height));
+
+	max_cu_width = 1 << (sps->log2_diff_max_min_luma_coding_block_size + log2_min_cb_size);
+	pic_in_cts_width = (width + max_cu_width - 1) / max_cu_width;
+	pic_in_cts_height = (height + max_cu_width - 1) / max_cu_width;
+
+	if (tiles_enabled) {
+		if (pps->flags & V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING) {
+			compute_tiles_uniform(run, log2_min_cb_size, width, height,
+					      pic_in_cts_width, pic_in_cts_height,
+					      column_width, row_height);
+		} else {
+			compute_tiles_non_uniform(run, log2_min_cb_size, width, height,
+						  pic_in_cts_width, pic_in_cts_height,
+						  column_width, row_height);
+		}
+	} else {
+		column_width[0] = (width + max_cu_width - 1) / max_cu_width;
+		row_height[0] = (height + max_cu_width - 1) / max_cu_width;
+	}
+
+	for (i = 0; i < 22; i++)
+		set_column_row(hw_ps, column_width[i], row_height[i], i);
+
+	// Setup POC information
+	hw_ps->current_poc = dec_params->pic_order_cnt_val;
+
+	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
+		u32 valid = !!(dec_params->num_active_dpb_entries > i);
+
+		set_pps_ref_pic_poc(hw_ps, dec_params->dpb[i].pic_order_cnt_val, i);
+		hw_ps->ref_is_valid |= valid << i;
+	}
+}
+
+static void rkvdec_write_regs(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_hevc_ctx *h265_ctx = ctx->priv;
+
+	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_COMMON_REGS,
+			   &h265_ctx->regs.common,
+			   sizeof(h265_ctx->regs.common));
+	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_COMMON_ADDR_REGS,
+			   &h265_ctx->regs.common_addr,
+			   sizeof(h265_ctx->regs.common_addr));
+	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_CODEC_PARAMS_REGS,
+			   &h265_ctx->regs.h26x_params,
+			   sizeof(h265_ctx->regs.h26x_params));
+	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_CODEC_ADDR_REGS,
+			   &h265_ctx->regs.h26x_addr,
+			   sizeof(h265_ctx->regs.h26x_addr));
+}
+
+static void config_registers(struct rkvdec_ctx *ctx,
+			     struct rkvdec_hevc_run *run)
+{
+	const struct v4l2_ctrl_hevc_decode_params *dec_params = run->decode_params;
+	struct rkvdec_hevc_ctx *h265_ctx = ctx->priv;
+	const struct v4l2_ctrl_hevc_sps *sps = run->sps;
+	dma_addr_t priv_start_addr = h265_ctx->priv_tbl.dma;
+	const struct v4l2_pix_format_mplane *dst_fmt;
+	struct vb2_v4l2_buffer *src_buf = run->base.bufs.src;
+	struct vb2_v4l2_buffer *dst_buf = run->base.bufs.dst;
+	struct vdpu383_regs_h26x *regs = &h265_ctx->regs;
+	const struct v4l2_format *f;
+	dma_addr_t rlc_addr;
+	dma_addr_t dst_addr;
+	u32 hor_virstride;
+	u32 ver_virstride;
+	u32 y_virstride;
+	u32 offset;
+	u32 pixels;
+	u32 i;
+
+	memset(regs, 0, sizeof(*regs));
+
+	/* Set HEVC mode */
+	regs->common.reg008_dec_mode = VDPU383_MODE_HEVC;
+
+	/* Set input stream length */
+	regs->h26x_params.reg066_stream_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
+
+	/* Set strides */
+	f = &ctx->decoded_fmt;
+	dst_fmt = &f->fmt.pix_mp;
+	hor_virstride = dst_fmt->plane_fmt[0].bytesperline;
+	ver_virstride = dst_fmt->height;
+	y_virstride = hor_virstride * ver_virstride;
+
+	pixels = dst_fmt->height * dst_fmt->width;
+
+	regs->h26x_params.reg068_hor_virstride = hor_virstride / 16;
+	regs->h26x_params.reg069_raster_uv_hor_virstride = hor_virstride / 16;
+	regs->h26x_params.reg070_y_virstride = y_virstride / 16;
+
+	/* Activate block gating */
+	regs->common.reg010.strmd_auto_gating_e      = 1;
+	regs->common.reg010.inter_auto_gating_e      = 1;
+	regs->common.reg010.intra_auto_gating_e      = 1;
+	regs->common.reg010.transd_auto_gating_e     = 1;
+	regs->common.reg010.recon_auto_gating_e      = 1;
+	regs->common.reg010.filterd_auto_gating_e    = 1;
+	regs->common.reg010.bus_auto_gating_e	     = 1;
+	regs->common.reg010.ctrl_auto_gating_e       = 1;
+	regs->common.reg010.rcb_auto_gating_e	     = 1;
+	regs->common.reg010.err_prc_auto_gating_e    = 1;
+
+	/* Set timeout threshold */
+	if (pixels < RKVDEC_1080P_PIXELS)
+		regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_1080p;
+	else if (pixels < RKVDEC_4K_PIXELS)
+		regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_4K;
+	else if (pixels < RKVDEC_8K_PIXELS)
+		regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_8K;
+	else
+		regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_MAX;
+
+	regs->common.reg016.error_proc_disable = 1;
+
+	/* Set ref pic address & poc */
+	for (i = 0; i < ARRAY_SIZE(dec_params->dpb) - 1; i++) {
+		struct vb2_buffer *vb_buf = get_ref_buf(ctx, run, i);
+		dma_addr_t buf_dma;
+
+		buf_dma = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
+
+		/* Set reference addresses */
+		regs->h26x_addr.reg170_185_ref_base[i] = buf_dma;
+		regs->h26x_addr.reg195_210_payload_st_ref_base[i] = buf_dma;
+
+		/* Set COLMV addresses */
+		regs->h26x_addr.reg217_232_colmv_ref_base[i] = buf_dma + ctx->colmv_offset;
+	}
+
+	/* Set rlc base address (input stream) */
+	rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+	regs->common_addr.reg128_strm_base = rlc_addr;
+
+	/* Set output base address */
+	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
+	regs->h26x_addr.reg168_decout_base = dst_addr;
+	regs->h26x_addr.reg169_error_ref_base = dst_addr;
+	regs->h26x_addr.reg192_payload_st_cur_base = dst_addr;
+
+	/* Set colmv address */
+	regs->h26x_addr.reg216_colmv_cur_base = dst_addr + ctx->colmv_offset;
+
+	/* Set RCB addresses */
+	for (i = 0; i < rkvdec_rcb_buf_count(ctx); i++) {
+		regs->common_addr.reg140_162_rcb_info[i].offset = rkvdec_rcb_buf_dma_addr(ctx, i);
+		regs->common_addr.reg140_162_rcb_info[i].size = rkvdec_rcb_buf_size(ctx, i);
+	}
+
+	if (sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED) {
+		/* Set scaling matrix */
+		offset = offsetof(struct rkvdec_hevc_priv_tbl, scaling_list);
+		regs->common_addr.reg132_scanlist_addr = priv_start_addr + offset;
+	}
+
+	/* Set hw pps address */
+	offset = offsetof(struct rkvdec_hevc_priv_tbl, param_set);
+	regs->common_addr.reg131_gbl_base = priv_start_addr + offset;
+	regs->h26x_params.reg067_global_len = sizeof(struct rkvdec_hevc_sps_pps) / 16;
+
+	/* Set hw rps address */
+	offset = offsetof(struct rkvdec_hevc_priv_tbl, rps);
+	regs->common_addr.reg129_rps_base = priv_start_addr + offset;
+
+	/* Set cabac table */
+	offset = offsetof(struct rkvdec_hevc_priv_tbl, cabac_table);
+	regs->common_addr.reg130_cabactbl_base = priv_start_addr + offset;
+
+	rkvdec_write_regs(ctx);
+}
+
+static enum rkvdec_image_fmt rkvdec_hevc_get_image_fmt(struct rkvdec_ctx *ctx,
+						       struct v4l2_ctrl *ctrl)
+{
+	const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps;
+
+	if (ctrl->id != V4L2_CID_STATELESS_HEVC_SPS)
+		return RKVDEC_IMG_FMT_ANY;
+
+	if (sps->bit_depth_luma_minus8 == 0)
+		return RKVDEC_IMG_FMT_420_8BIT;
+	else if (sps->bit_depth_luma_minus8 == 2)
+		return RKVDEC_IMG_FMT_420_10BIT;
+
+	return RKVDEC_IMG_FMT_ANY;
+}
+
+static int rkvdec_hevc_validate_sps(struct rkvdec_ctx *ctx,
+				    const struct v4l2_ctrl_hevc_sps *sps)
+{
+	if (sps->chroma_format_idc != 1)
+		/* Only 4:2:0 is supported */
+		return -EINVAL;
+
+	if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
+		/* Luma and chroma bit depth mismatch */
+		return -EINVAL;
+
+	if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2)
+		/* Only 8-bit and 10-bit are supported */
+		return -EINVAL;
+
+	if (sps->pic_width_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.width ||
+	    sps->pic_height_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.height)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int rkvdec_hevc_start(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_hevc_priv_tbl *priv_tbl;
+	struct rkvdec_hevc_ctx *hevc_ctx;
+	struct v4l2_ctrl *ctrl;
+	int ret;
+
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_HEVC_SPS);
+	if (!ctrl)
+		return -EINVAL;
+
+	ret = rkvdec_hevc_validate_sps(ctx, ctrl->p_new.p_hevc_sps);
+	if (ret)
+		return ret;
+
+	hevc_ctx = kzalloc(sizeof(*hevc_ctx), GFP_KERNEL);
+	if (!hevc_ctx)
+		return -ENOMEM;
+
+	priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl),
+				      &hevc_ctx->priv_tbl.dma, GFP_KERNEL);
+	if (!priv_tbl) {
+		ret = -ENOMEM;
+		goto err_free_ctx;
+	}
+
+	hevc_ctx->priv_tbl.size = sizeof(*priv_tbl);
+	hevc_ctx->priv_tbl.cpu = priv_tbl;
+	memcpy(priv_tbl->cabac_table, rkvdec_hevc_cabac_table,
+	       sizeof(rkvdec_hevc_cabac_table));
+
+	ctx->priv = hevc_ctx;
+	return 0;
+
+err_free_ctx:
+	kfree(hevc_ctx);
+	return ret;
+}
+
+static void rkvdec_hevc_stop(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
+	struct rkvdec_dev *rkvdec = ctx->dev;
+
+	dma_free_coherent(rkvdec->dev, hevc_ctx->priv_tbl.size,
+			  hevc_ctx->priv_tbl.cpu, hevc_ctx->priv_tbl.dma);
+	kfree(hevc_ctx);
+}
+
+static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_hevc_run run;
+	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
+	struct rkvdec_hevc_priv_tbl *tbl = hevc_ctx->priv_tbl.cpu;
+	u32 watchdog_time;
+	u64 timeout_threshold;
+	unsigned long axi_rate;
+
+	rkvdec_hevc_run_preamble(ctx, &run);
+
+	/*
+	 * On vdpu383, not setting the long and short term ref sets leads to IOMMU page faults.
+	 * To be on the safe side for this new v4l2 control, write an error in the log and mark
+	 * the buffer as failed by returning an error here.
+	 */
+	if ((!ctx->has_sps_lt_rps && run.sps->num_long_term_ref_pics_sps) ||
+		(!ctx->has_sps_st_rps && run.sps->num_short_term_ref_pic_sets)) {
+		dev_err_ratelimited(rkvdec->dev, "Long and short term RPS not set\n");
+		return -EINVAL;
+	}
+
+	rkvdec_hevc_assemble_hw_scaling_list(ctx, &run, &tbl->scaling_list,
+					     &hevc_ctx->scaling_matrix_cache);
+	assemble_hw_pps(ctx, &run);
+	rkvdec_hevc_assemble_hw_rps(&run, &tbl->rps, &hevc_ctx->st_cache);
+
+	config_registers(ctx, &run);
+
+	rkvdec_run_postamble(ctx, &run.base);
+
+	/* Set watchdog at 2 times the hardware timeout threshold */
+	timeout_threshold = hevc_ctx->regs.common.reg013_core_timeout_threshold;
+	axi_rate = clk_get_rate(rkvdec->axi_clk);
+
+	if (axi_rate)
+		watchdog_time = 2 * (1000 * timeout_threshold) / axi_rate;
+	else
+		watchdog_time = 2000;
+	schedule_delayed_work(&rkvdec->watchdog_work,
+			      msecs_to_jiffies(watchdog_time));
+
+	/* Start decoding! */
+	writel(timeout_threshold, rkvdec->link + VDPU383_LINK_TIMEOUT_THRESHOLD);
+	writel(VDPU383_IP_CRU_MODE, rkvdec->link + VDPU383_LINK_IP_ENABLE);
+	writel(VDPU383_DEC_E_BIT, rkvdec->link + VDPU383_LINK_DEC_ENABLE);
+
+	return 0;
+}
+
+static int rkvdec_hevc_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
+{
+	if (ctrl->id == V4L2_CID_STATELESS_HEVC_SPS)
+		return rkvdec_hevc_validate_sps(ctx, ctrl->p_new.p_hevc_sps);
+
+	return 0;
+}
+
+const struct rkvdec_coded_fmt_ops rkvdec_vdpu383_hevc_fmt_ops = {
+	.adjust_fmt = rkvdec_hevc_adjust_fmt,
+	.start = rkvdec_hevc_start,
+	.stop = rkvdec_hevc_stop,
+	.run = rkvdec_hevc_run,
+	.try_ctrl = rkvdec_hevc_try_ctrl,
+	.get_image_fmt = rkvdec_hevc_get_image_fmt,
+};
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index 7bb98c98a82b..1280224602d5 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -504,6 +504,22 @@ static const struct rkvdec_coded_fmt_desc vdpu383_coded_fmts[] = {
 		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
 		.capability = RKVDEC_CAPABILITY_H264,
 	},
+	{
+		.fourcc = V4L2_PIX_FMT_HEVC_SLICE,
+		.frmsize = {
+			.min_width = 64,
+			.max_width = 65472,
+			.step_width = 64,
+			.min_height = 64,
+			.max_height = 65472,
+			.step_height = 16,
+		},
+		.ctrls = &vdpu38x_hevc_ctrls,
+		.ops = &rkvdec_vdpu383_hevc_fmt_ops,
+		.num_decoded_fmts = ARRAY_SIZE(rkvdec_hevc_decoded_fmts),
+		.decoded_fmts = rkvdec_hevc_decoded_fmts,
+		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
+	},
 };
 
 static bool rkvdec_is_capable(struct rkvdec_ctx *ctx, unsigned int capability)
@@ -1447,6 +1463,78 @@ static irqreturn_t rkvdec_irq_handler(int irq, void *priv)
 	return variant->ops->irq_handler(ctx);
 }
 
+/*
+ * Flip one or more matrices along their main diagonal and flatten them
+ * before writing it to the memory.
+ * Convert:
+ * ABCD         AEIM
+ * EFGH     =>  BFJN     =>     AEIMBFJNCGKODHLP
+ * IJKL         CGKO
+ * MNOP         DHLP
+ */
+static void transpose_and_flatten_matrices(u8 *output, const u8 *input,
+					   int matrices, int row_length)
+{
+	int i, j, row, x_offset, matrix_offset, rot_index, y_offset, matrix_size, new_value;
+
+	matrix_size = row_length * row_length;
+	for (i = 0; i < matrices; i++) {
+		row = 0;
+		x_offset = 0;
+		matrix_offset = i * matrix_size;
+		for (j = 0; j < matrix_size; j++) {
+			y_offset = j - (row * row_length);
+			rot_index = y_offset * row_length + x_offset;
+			new_value = *(input + i * matrix_size + j);
+			output[matrix_offset + rot_index] = new_value;
+			if ((j + 1) % row_length == 0) {
+				row += 1;
+				x_offset += 1;
+			}
+		}
+	}
+}
+
+/*
+ * VDPU383 needs a specific order:
+ * The 8x8 flatten matrix is based on 4x4 blocks.
+ * Each 4x4 block is written separately in order.
+ *
+ * Base data    =>  Transposed    VDPU383 transposed
+ *
+ * ABCDEFGH         AIQYaiqy      AIQYBJRZ
+ * IJKLMNOP         BJRZbjrz      CKS0DLT1
+ * QRSTUVWX         CKS0cks6      aiqybjrz
+ * YZ012345     =>  DLT1dlt7      cks6dlt7
+ * abcdefgh         EMU2emu8      EMU2FNV3
+ * ijklmnop         FNV3fnv9      GOW4HPX5
+ * qrstuvwx         GOW4gow#      emu8fnv9
+ * yz6789#$         HPX5hpx$      gow#hpx$
+ *
+ * As the function reads block of 4x4 it can be used for both 4x4 and 8x8 matrices.
+ *
+ */
+static void vdpu383_flatten_matrices(u8 *output, const u8 *input, int matrices, int row_length)
+{
+	u8 block;
+	int i, j, matrix_offset, matrix_size, new_value, input_idx, line_offset, block_offset;
+
+	matrix_size = row_length * row_length;
+	for (i = 0; i < matrices; i++) {
+		matrix_offset = i * matrix_size;
+		for (j = 0; j < matrix_size; j++) {
+			block = j / 16;
+			line_offset = (j % 16) / 4;
+			block_offset = (block & 1) * 32 + (block & 2) * 2;
+			input_idx = ((j % 4) * row_length) + line_offset + block_offset;
+
+			new_value = *(input + i * matrix_size + input_idx);
+
+			output[matrix_offset + j] = new_value;
+		}
+	}
+}
+
 static void rkvdec_watchdog_func(struct work_struct *work)
 {
 	struct rkvdec_dev *rkvdec;
@@ -1534,6 +1622,7 @@ static const struct rcb_size_info vdpu383_rcb_sizes[] = {
 static const struct rkvdec_variant_ops rk3399_variant_ops = {
 	.irq_handler = rk3399_irq_handler,
 	.colmv_size = rkvdec_colmv_size,
+	.flatten_matrices = transpose_and_flatten_matrices,
 };
 
 static const struct rkvdec_variant rk3288_rkvdec_variant = {
@@ -1568,6 +1657,7 @@ static const struct rkvdec_variant rk3399_rkvdec_variant = {
 static const struct rkvdec_variant_ops vdpu381_variant_ops = {
 	.irq_handler = vdpu381_irq_handler,
 	.colmv_size = rkvdec_colmv_size,
+	.flatten_matrices = transpose_and_flatten_matrices,
 };
 
 static const struct rkvdec_variant rk3588_vdpu381_variant = {
@@ -1584,6 +1674,7 @@ static const struct rkvdec_variant rk3588_vdpu381_variant = {
 static const struct rkvdec_variant_ops vdpu383_variant_ops = {
 	.irq_handler = vdpu383_irq_handler,
 	.colmv_size = vdpu383_colmv_size,
+	.flatten_matrices = vdpu383_flatten_matrices,
 };
 
 static const struct rkvdec_variant rk3576_vdpu383_variant = {
@@ -1593,7 +1684,8 @@ static const struct rkvdec_variant rk3576_vdpu383_variant = {
 	.num_rcb_sizes = ARRAY_SIZE(vdpu383_rcb_sizes),
 	.ops = &vdpu383_variant_ops,
 	.named_regs = true,
-	.capabilities = RKVDEC_CAPABILITY_H264,
+	.capabilities = RKVDEC_CAPABILITY_H264 |
+			RKVDEC_CAPABILITY_HEVC,
 };
 
 static const struct of_device_id of_rkvdec_match[] = {
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
index 44ff50ec6d85..0b80be04d354 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
@@ -78,6 +78,7 @@ vb2_to_rkvdec_decoded_buf(struct vb2_buffer *buf)
 struct rkvdec_variant_ops {
 	irqreturn_t (*irq_handler)(struct rkvdec_ctx *ctx);
 	u32 (*colmv_size)(u16 width, u16 height);
+	void (*flatten_matrices)(u8 *output, const u8 *input, int matrices, int row_length);
 };
 
 struct rkvdec_variant {
@@ -198,5 +199,6 @@ extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_hevc_fmt_ops;
 
 /* VDPU383 ops */
 extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu383_h264_fmt_ops;
+extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu383_hevc_fmt_ops;
 
 #endif /* RKVDEC_H_ */
-- 
2.52.0



From ahmed.tiba at arm.com  Wed Dec 17 09:49:27 2025
From: ahmed.tiba at arm.com (Ahmed Tiba)
Date: Wed, 17 Dec 2025 17:49:27 +0000
Subject: [PATCH 10/12] dt-bindings: ras: document estatus provider
In-Reply-To: <cd04e23a-9523-4d25-8240-29a0dffa0e75@kernel.org>
References: <cd04e23a-9523-4d25-8240-29a0dffa0e75@kernel.org>
Message-ID: <20251217174933.1938909-1-ahmed.tiba@arm.com>

On 17/12/2025 12:41, Krzysztof Kozlowski wrote:
> What is ras? There is no such directory so some description would be
> useful. Usually you do not get your own directory per binding.

Would it make sense to move it under `Documentation/devicetree/bindings/firmware`
and expand the description so it spells out that
Arm RAS refers to reliability, availability and serviceability firmware.

> Do not describe what the binding does. Describe the hardware or firmware.

I'll reword that section.

> Again ras - what's that? Your patch or binding must explain that.

I'll add that explanation to the description.

> Why is this flexible?

Some platforms only expose the CPER status buffer, while others also expose a
doorbell that firmware expects to toggle before writing the next record.
I'll keep `reg` at 1-2 entries but make the description clear about which
region is optional.

> Does not match reg.

`reg-names` will only be allowed when both regions are present,
and in that case it must list `"status", "ack"`
so the entries line up with `reg`.
If only the status buffer exists, the property stays omitted.


> What OS is doing should not really matter. Either you have the interrupt
> or not.

I?ll trim the wording so it just states that firmware
may assert an interrupt when a new record is ready.


> That's OS policy, not suitable for binding.

I?ll drop `poll-interval` from the binding and let the driver fall back
to a fixed polling interval when no interrupt is wired.

> This is implied by the compatible, no?

I?ll drop `arm,sea-notify` so the compatible alone defines the behaviour.

> Drop all this.

I?ll delete the `allOf` clauses once the policy properties are gone.

> I do not see any schema referenced.

I?ll switch from `unevaluatedProperties` to `additionalProperties: false`.

> Node names should be generic. See also an explanation and list of
> examples (not exhaustive) in DT specification:
> https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation
> If you cannot find a name matching your device, please check in kernel
> sources for similar cases or you can grow the spec (via pull request to
> DT spec repo).

I?ll rename the example node to `estatus at fe800000`
so it describes the firmware error-status block rather than using the driver name.

> Use proper defines.

I?ll update the example to use `GIC_SPI` and the `IRQ_TYPE_*` macros for the interrupt specifier.

Best regards,
Ahmed


From puranjay at kernel.org  Wed Dec 17 10:13:29 2025
From: puranjay at kernel.org (Puranjay Mohan)
Date: Wed, 17 Dec 2025 18:13:29 +0000
Subject: [PATCH bpf-next 2/2] bpf: arm64: Optimize recursion detection by
 not using atomics
In-Reply-To: <f144fd46b602b74fc4c1c2664082fbe893e7ec9c274fcc5fdf13d65151749e9c@mail.kernel.org>
References: <20251217162830.2597286-3-puranjay@kernel.org> <f144fd46b602b74fc4c1c2664082fbe893e7ec9c274fcc5fdf13d65151749e9c@mail.kernel.org>
Message-ID: <CANk7y0h4JO2-tp9HjRHjcQdTOgmRSsw0rxmK-=G89AVY92U8Jw@mail.gmail.com>

On Wed, Dec 17, 2025 at 4:56?PM <bot+bpf-ci at kernel.org> wrote:
>
> > diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> > index 2da986136d26..654fb94bf60c 100644
> > --- a/include/linux/bpf.h
> > +++ b/include/linux/bpf.h
>
> [ ... ]
>
> > @@ -2006,12 +2009,32 @@ struct bpf_struct_ops_common_value {
> >
> >  static inline bool bpf_prog_get_recursion_context(struct bpf_prog *prog)
> >  {
> > +#ifdef CONFIG_ARM64
> > +     u8 rctx = interrupt_context_level();
> > +     u8 *active = this_cpu_ptr(prog->active);
> > +
> > +     active[rctx]++;
> > +     barrier();
> > +     if (get_unaligned_le32(active) != BIT(rctx * 8))
> > +             return false;
> > +
> > +     return true;
> > +#else
> >       return this_cpu_inc_return(*(prog->active)) == 1;
> > +#endif
> >  }
>
> Can preemption between the increment and check cause a counter leak on
> CONFIG_PREEMPT_RCU systems? The trampoline calls this function under
> rcu_read_lock_dont_migrate() which allows preemption on PREEMPT_RCU
> (documented at include/linux/rcupdate.h:856).
>
> Consider this scenario on an ARM64 system with PREEMPT_RCU:
>
> 1. Thread A increments active[0] to 1
> 2. Preemption occurs before Thread A reaches the check
> 3. Thread B on same CPU increments active[0] to 2
> 4. Thread B checks: sees 2 != BIT(0), returns false
> 5. Thread A resumes, checks: sees 2 != BIT(0), returns false
> 6. Both threads return false, neither runs BPF
> 7. Neither calls bpf_prog_put_recursion_context() (see
>    __bpf_prog_enter_recur() at kernel/bpf/trampoline.c:952)
> 8. Counter permanently stuck at 2, all future BPF on this CPU fails

Step 7 is incorrect. Looking at the JIT-generated code, the exit
function is ALWAYS called, regardless of whether the enter function
returns 0 or a start time:

  // x86 JIT at arch/x86/net/bpf_jit_comp.c:2998-3050
  call bpf_trampoline_enter()    // Line 2998
  test rax, rax                   // Line 3006
  je skip_exec                    // Conditional jump
  ... BPF program execution ...   // Lines 3011-3023
  skip_exec:                      // Line 3037 (jump lands here)
  call bpf_trampoline_exit()      // Line 3049 - ALWAYS executed

  The bpf_trampoline_exit() call is after the skip_exec label, so it
executes in both cases.

What Actually Happens:

  Initial state: active[0] = 0

  Thread A (normal context, rctx=0):
  1. active[0]++ ? active[0] = 1
  2. Preempted before barrier()

  Thread B (scheduled on same CPU, normal context, rctx=0):
  3. active[0]++ ? active[0] = 2
  4. barrier()
  5. get_unaligned_le32(active) ? reads 0x00000002
  6. Check: 0x00000002 != BIT(0) = 0x00000001 ? returns false
  7. __bpf_prog_enter_recur returns 0
  8. JIT checks return value, skips BPF execution
  9. JIT ALWAYS calls __bpf_prog_exit_recur (see
arch/arm64/net/bpf_jit_comp.c:2362)
  10. bpf_prog_put_recursion_context(prog) executes
  11. barrier(), active[0]-- ? active[0] = 1

  Thread A resumes:
  12. barrier()
  13. get_unaligned_le32(active) ? reads 0x00000001 (Thread B already
decremented!)
  14. Check: 0x00000001 == BIT(0) = 0x00000001 ? returns true ?
  15. __bpf_prog_enter_recur returns start_time
  16. BPF program executes
  17. __bpf_prog_exit_recur called
  18. bpf_prog_put_recursion_context(prog) executes
  19. barrier(), active[0]-- ? active[0] = 0 ?

  Final State

  - Counter returns to 0 ?
  - No leak ?
  - Thread B detected interference and aborted ?
  - Thread A executed successfully ?
  - Only ONE thread executed the BPF program ?


Now that I think of it, there is another race condition that leads to
NEITHER program running:

Consider this scenario on an arm64 system with PREEMPT_RCU:

1. Thread A increments active[0] from 0 to 1
2. Thread A is preempted before reaching barrier()
3. Thread B (same CPU, same context) increments active[0] from 1 to 2
4. Thread B executes barrier() and checks: sees 2 != BIT(0), returns false
5. Thread A resumes, executes barrier() and checks: sees 2 != BIT(0),
returns false
6. Both threads return false to __bpf_prog_enter_recur()
7. Both skip BPF program execution
8. Both call bpf_prog_put_recursion_context() and decrement: 2->1->0
9. Neither BPF program executes, but the counter correctly returns to 0

This means the patch is changing the behaviour in case of recursion
from "One program gets to run" to
"At most one program gets to run", but given the performance benefits,
I think we can accept this change.
I am not sure what would change in reality if we allow both BPF
programs to be skipped in case of high interleaving
like above.

> The old atomic code handled this correctly because this_cpu_inc_return()
> completes atomically, ensuring Thread A reads the value 1 before Thread B
> can interfere. With non-atomic operations, Thread A increments but hasn't
> read the value yet, allowing Thread B to interfere and cause both threads
> to see the modified value.
>
> Is there a guarantee that same-context preemption cannot occur in the BPF
> execution path on ARM64, or does this need additional synchronization?
>
> > @@ -2006,12 +2009,32 @@ struct bpf_struct_ops_common_value {
> >
> >  static inline void bpf_prog_put_recursion_context(struct bpf_prog *prog)
> >  {
> > +#ifdef CONFIG_ARM64
> > +     u8 rctx = interrupt_context_level();
> > +     u8 *active = this_cpu_ptr(prog->active);
> > +
> > +     barrier();
> > +     active[rctx]--;
> > +#else
> >       this_cpu_dec(*(prog->active));
> > +#endif
> >  }
>
> The barrier() is placed before the decrement. Does this provide the needed
> ordering guarantee, or should there also be a barrier after the decrement
> to ensure visibility?
>
> > diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> > index c66316e32563..b5063acfcf92 100644
> > --- a/kernel/bpf/core.c
> > +++ b/kernel/bpf/core.c
>
> [ ... ]
>
> > @@ -112,7 +112,8 @@ struct bpf_prog *bpf_prog_alloc_no_stats(unsigned int size, gfp_t gfp_extra_flag
> >               vfree(fp);
> >               return NULL;
> >       }
> > -     fp->active = alloc_percpu_gfp(int, bpf_memcg_flags(GFP_KERNEL | gfp_extra_flags));
> > +     fp->active = __alloc_percpu_gfp(sizeof(u8[BPF_NR_CONTEXTS]), 8,
> > +                                     bpf_memcg_flags(GFP_KERNEL | gfp_extra_flags));
>
> The allocation changes to u8[4] for all architectures, but the non-ARM64
> code path still uses *(prog->active) which now dereferences only the first
> byte. This changes the counter from int (typically 4 bytes, range ~2^31)
> to u8 (1 byte, range 256). While 256 recursion levels is sufficient in
> practice, is this intentional for non-ARM64 platforms, or should they
> continue using a full int-sized allocation?

This was intentional so that we don't add another #ifdef here, 256
recursion levels are more than enough.
But to keep the previous recursion levels, I could change the non
ARM64 code to do something like:

this_cpu_dec(*(int __percpu *)(prog->active));

I can do this in the next version.

Thanks,
Puranjay


From Harini.T at amd.com  Wed Dec 17 10:14:30 2025
From: Harini.T at amd.com (T, Harini)
Date: Wed, 17 Dec 2025 18:14:30 +0000
Subject: [PATCH 2/4] rtc: zynqmp: rework read_offset
In-Reply-To: <353422a2-ba6e-4600-9326-e0cee2098062@vaisala.com>
References: <20251201-zynqmp-rtc-updates-v1-0-33875c1e385b@vaisala.com>
 <20251201-zynqmp-rtc-updates-v1-2-33875c1e385b@vaisala.com>
 <LV5PR12MB98047B0A754AFFFB01163E0992A3A@LV5PR12MB9804.namprd12.prod.outlook.com>
 <353422a2-ba6e-4600-9326-e0cee2098062@vaisala.com>
Message-ID: <LV5PR12MB980448D3F4109DC0775A56AA92ABA@LV5PR12MB9804.namprd12.prod.outlook.com>

[Public]

Hi,

> -----Original Message-----
> From: Tomas Melin <tomas.melin at vaisala.com>
> Sent: Wednesday, December 10, 2025 5:35 PM
> To: T, Harini <Harini.T at amd.com>; Alexandre Belloni
> <alexandre.belloni at bootlin.com>; Simek, Michal <michal.simek at amd.com>
> Cc: linux-rtc at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux-
> kernel at vger.kernel.org
> Subject: Re: [PATCH 2/4] rtc: zynqmp: rework read_offset
>
> Caution: This message originated from an External Source. Use proper caution
> when opening attachments, clicking links, or responding.
>
>
> Hi,
>
> On 09/12/2025 19:28, T, Harini wrote:
> > [Public]
> >
> > Hi,
> >
> >> -----Original Message-----
> >> From: Tomas Melin <tomas.melin at vaisala.com>
> >> Sent: Monday, December 1, 2025 6:20 PM
> >> To: Alexandre Belloni <alexandre.belloni at bootlin.com>; Simek, Michal
> >> <michal.simek at amd.com>
> >> Cc: linux-rtc at vger.kernel.org; linux-arm-kernel at lists.infradead.org;
> >> linux- kernel at vger.kernel.org; Tomas Melin <tomas.melin at vaisala.com>
> >> Subject: [PATCH 2/4] rtc: zynqmp: rework read_offset
> >>
> >> Caution: This message originated from an External Source. Use proper
> >> caution when opening attachments, clicking links, or responding.
> >>
> >>
> >> read_offset() was using static frequency for determining the tick
> >> offset. It was also using remainder from do_div() operation as
> >> tick_mult value which caused the offset to be incorrect.
> >>
> >> At the same time, rework function to improve readability.
> >>
> >> Signed-off-by: Tomas Melin <tomas.melin at vaisala.com>
> >> ---
> >>  drivers/rtc/rtc-zynqmp.c | 25 ++++++++++++++++---------
> >>  1 file changed, 16 insertions(+), 9 deletions(-)
> >>
> >> diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c
> >> index
> >>
> 856bc1678e7d31144f320ae9f75fc58c742a2a64..7af5f6f99538f961a53ff56
> bfc6
> >> 56c907611b900 100644
> >> --- a/drivers/rtc/rtc-zynqmp.c
> >> +++ b/drivers/rtc/rtc-zynqmp.c
> >> @@ -178,21 +178,28 @@ static void xlnx_init_rtc(struct xlnx_rtc_dev
> >> *xrtcdev)  static int xlnx_rtc_read_offset(struct device *dev, long *offset)  {
> >>         struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
> >> -       unsigned long long rtc_ppb = RTC_PPB;
> >> -       unsigned int tick_mult = do_div(rtc_ppb, xrtcdev->freq);
> >> -       unsigned int calibval;
> >> +       unsigned int calibval, fract_data, fract_part;
> > Prefer one variable assignment per line for readability.
> This is after all quite common practice, and in a function like this where several
> variables are needed, I would argue that this is more readable than the
> alternative. Is there some convention I'm not aware of?
There is no such mandatory convention. It's up to the RTC maintainer.
>
> >> +       int max_tick, tick_mult;
> > It would be better to explain why tick_mult is changed to int in the commit
> message.
> This is part of the refactoring, mixing signed and unsigned variables in
> operations is more risky than having same type.
I agree. But tick_mult is int in read_offset and unsigned in set_offset.
It would be better if both uses int to maintain consistency during the math operations.
>
> >> +       int freq = xrtcdev->freq;
> > Please follow reverse xmas tree variable ordering.
> Ok fixing this and other occurances.
>
> >>         long offset_val;
> >>
> >> +       /* ticks to reach RTC_PPB */
> > The comment is misleading. Its tick_mult is nanoseconds per tick, not a tick
> count.
> Perhaps the comment was not well formulated. I suggest changing to
> /* Tick to offset multiplier */
>  as that it what it is primarily used for. Would that be okay for You?
Yeah
>
> Thanks,
> Tomas
>
> >> +       tick_mult = DIV_ROUND_CLOSEST(RTC_PPB, freq);
> >> +
> >>         calibval = readl(xrtcdev->reg_base + RTC_CALIB_RD);
> >>         /* Offset with seconds ticks */
> >> -       offset_val = calibval & RTC_TICK_MASK;
> >> -       offset_val = offset_val - RTC_CALIB_DEF;
> >> -       offset_val = offset_val * tick_mult;
> >> +       max_tick = calibval & RTC_TICK_MASK;
> >> +       offset_val = max_tick - freq;
> >> +       /* Convert to ppb */
> >> +       offset_val *= tick_mult;
> >>
> >>         /* Offset with fractional ticks */
> >> -       if (calibval & RTC_FR_EN)
> >> -               offset_val += ((calibval & RTC_FR_MASK) >> RTC_FR_DATSHIFT)
> >> -                       * (tick_mult / RTC_FR_MAX_TICKS);
> >> +       if (calibval & RTC_FR_EN) {
> >> +               fract_data = (calibval & RTC_FR_MASK) >> RTC_FR_DATSHIFT;
> >> +               fract_part = DIV_ROUND_UP(tick_mult, RTC_FR_MAX_TICKS);
> >> +               offset_val += (fract_part * fract_data);
> >> +       }
> >> +
> >>         *offset = offset_val;
> >>
> >>         return 0;
> >>
> >> --
> >> 2.47.3
> >>
> > Regards,
> > Harini T
> >
>

Regards,
Harini T

From yeoreum.yun at arm.com  Wed Dec 17 10:20:05 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Wed, 17 Dec 2025 18:20:05 +0000
Subject: [PATCH v2 0/2] fix wrong usage of memory allocation APIs under PREEMPT_RT in arm64
Message-ID: <20251217182007.2345700-1-yeoreum.yun@arm.com>

Under PREEMPT_RT, calling generic memory allocation/free APIs
(e.x) __get_free_pages(), pgtable_alloc(), free_pages() and etc
with preemption disabled is not allowed, but allow only nolock() APIs series
because it may acquire a spin lock that becomes sleepable on RT,
potentially causing a sleep during page allocation
(See Documentation/core-api/real-time/differences.rst, Memory allocation section).

However, In arm64, __linear_map_split_to_ptes() and
__kpti_install_ng_mappings() called by stopper thread via stop_machine()
use generic memory allocation/free APIs.

This patchset fixes this problem and based on v6.19-rc1

Patch History
==============
from v1 to v2:
  - drop pagetable_alloc_nolock()
  - following @Ryan Roberts suggestion.
  - https://lore.kernel.org/all/20251212161832.2067134-1-yeoreum.yun at arm.com/


 arch/arm64/mm/mmu.c | 235 ++++++++++++++++++++++++++++++++++----------
 1 file changed, 183 insertions(+), 52 deletions(-)

--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



From yeoreum.yun at arm.com  Wed Dec 17 10:20:06 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Wed, 17 Dec 2025 18:20:06 +0000
Subject: [PATCH v2 1/2] arm64: mmu: don't allocate page while spliting linear mapping
In-Reply-To: <20251217182007.2345700-1-yeoreum.yun@arm.com>
References: <20251217182007.2345700-1-yeoreum.yun@arm.com>
Message-ID: <20251217182007.2345700-2-yeoreum.yun@arm.com>

Current linear_map_split_to_ptes() allocate the pagetable
while split linear mapping to ptes by stop_machine() with GFP_ATOMIC.

This is fine for non-PREEMPR_RT case.
However It's a problem in PREEMPR_RT case since
generic memory allocation/free APIs (e.x) pgtable_alloc(), __get_free_pages and etc
couldn't be called in non-preemptible context except _nolock() APIs
since generic memory allocation/free APIs are *sleepable* for using *spin_lock()*

IOW, calling a pgtable_alloc() even with GFP_ATOMIC
doesn't allow in __linear_map_split_to_pte() executed by stopper thread
where preemption is disabled in PREEMPR_RT.

To address this, divide linear_map_maybe_split_ptes:
  - collect number of pages to require for spliting.
  - allocate the required number of pages for spliting.
  - with pre-allocate page, split the linear map.

Fixes: 3df6979d222b ("arm64: mm: split linear mapping if BBML2 unsupported on secondary CPUs")
Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
---
 arch/arm64/mm/mmu.c | 213 +++++++++++++++++++++++++++++++++++---------
 1 file changed, 170 insertions(+), 43 deletions(-)

diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 9ae7ce00a7ef..e4e6c7e0a016 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -527,18 +527,28 @@ static void early_create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys,
 		panic("Failed to create page tables\n");
 }
 
-static phys_addr_t __pgd_pgtable_alloc(struct mm_struct *mm, gfp_t gfp,
-				       enum pgtable_type pgtable_type)
-{
-	/* Page is zeroed by init_clear_pgtable() so don't duplicate effort. */
-	struct ptdesc *ptdesc = pagetable_alloc(gfp & ~__GFP_ZERO, 0);
-	phys_addr_t pa;
-
-	if (!ptdesc)
-		return INVALID_PHYS_ADDR;
+enum split_modes {
+	SPLIT_ALLOC,
+	SPLIT_PREALLOC,
+	SPLIT_COLLECT,
+};
 
-	pa = page_to_phys(ptdesc_page(ptdesc));
+struct split_args {
+	enum split_modes mode;
+	union {
+		struct {
+			unsigned long nr;
+			unsigned long i;
+			struct page **pages;
+		};
+		gfp_t gfp;
+	};
+};
 
+static __always_inline void __pgd_pgtable_init(struct mm_struct *mm,
+					       struct ptdesc *ptdesc,
+					       enum pgtable_type pgtable_type)
+{
 	switch (pgtable_type) {
 	case TABLE_PTE:
 		BUG_ON(!pagetable_pte_ctor(mm, ptdesc));
@@ -554,19 +564,56 @@ static phys_addr_t __pgd_pgtable_alloc(struct mm_struct *mm, gfp_t gfp,
 		break;
 	}
 
+}
+
+static phys_addr_t __pgd_pgtable_alloc(struct mm_struct *mm, gfp_t gfp,
+				       enum pgtable_type pgtable_type)
+{
+	/* Page is zeroed by init_clear_pgtable() so don't duplicate effort. */
+	struct ptdesc *ptdesc = pagetable_alloc(gfp & ~__GFP_ZERO, 0);
+	phys_addr_t pa;
+
+	if (!ptdesc)
+		return INVALID_PHYS_ADDR;
+
+	pa = page_to_phys(ptdesc_page(ptdesc));
+
+	__pgd_pgtable_init(mm, ptdesc, pgtable_type);
+
 	return pa;
 }
 
+static phys_addr_t __pgd_pgtable_prealloc(struct mm_struct *mm,
+					  struct split_args *split_args,
+					  enum pgtable_type pgtable_type)
+{
+	struct page *page;
+
+	BUG_ON(split_args->i >= split_args->nr);
+
+	page = split_args->pages[split_args->i++];
+	if (!page)
+		return INVALID_PHYS_ADDR;
+
+	__pgd_pgtable_init(mm, page_ptdesc(page), pgtable_type);
+
+	return page_to_phys(page);
+}
+
 static phys_addr_t
-pgd_pgtable_alloc_init_mm_gfp(enum pgtable_type pgtable_type, gfp_t gfp)
+pgd_pgtable_alloc_split(enum pgtable_type pgtable_type,
+		        struct split_args *split_args)
 {
-	return __pgd_pgtable_alloc(&init_mm, gfp, pgtable_type);
+	if (split_args->mode == SPLIT_ALLOC)
+		return __pgd_pgtable_alloc(&init_mm, split_args->gfp, pgtable_type);
+
+	return __pgd_pgtable_prealloc(&init_mm, split_args, pgtable_type);
 }
 
 static phys_addr_t __maybe_unused
 pgd_pgtable_alloc_init_mm(enum pgtable_type pgtable_type)
 {
-	return pgd_pgtable_alloc_init_mm_gfp(pgtable_type, GFP_PGTABLE_KERNEL);
+	return __pgd_pgtable_alloc(&init_mm, GFP_PGTABLE_KERNEL, pgtable_type);
 }
 
 static phys_addr_t
@@ -584,7 +631,9 @@ static void split_contpte(pte_t *ptep)
 		__set_pte(ptep, pte_mknoncont(__ptep_get(ptep)));
 }
 
-static int split_pmd(pmd_t *pmdp, pmd_t pmd, gfp_t gfp, bool to_cont)
+static int split_pmd(pmd_t *pmdp, pmd_t pmd,
+		     struct split_args *split_args,
+		     bool to_cont)
 {
 	pmdval_t tableprot = PMD_TYPE_TABLE | PMD_TABLE_UXN | PMD_TABLE_AF;
 	unsigned long pfn = pmd_pfn(pmd);
@@ -593,7 +642,7 @@ static int split_pmd(pmd_t *pmdp, pmd_t pmd, gfp_t gfp, bool to_cont)
 	pte_t *ptep;
 	int i;
 
-	pte_phys = pgd_pgtable_alloc_init_mm_gfp(TABLE_PTE, gfp);
+	pte_phys = pgd_pgtable_alloc_split(TABLE_PTE, split_args);
 	if (pte_phys == INVALID_PHYS_ADDR)
 		return -ENOMEM;
 	ptep = (pte_t *)phys_to_virt(pte_phys);
@@ -628,7 +677,9 @@ static void split_contpmd(pmd_t *pmdp)
 		set_pmd(pmdp, pmd_mknoncont(pmdp_get(pmdp)));
 }
 
-static int split_pud(pud_t *pudp, pud_t pud, gfp_t gfp, bool to_cont)
+static int split_pud(pud_t *pudp, pud_t pud,
+		    struct split_args *split_args,
+		    bool to_cont)
 {
 	pudval_t tableprot = PUD_TYPE_TABLE | PUD_TABLE_UXN | PUD_TABLE_AF;
 	unsigned int step = PMD_SIZE >> PAGE_SHIFT;
@@ -638,7 +689,7 @@ static int split_pud(pud_t *pudp, pud_t pud, gfp_t gfp, bool to_cont)
 	pmd_t *pmdp;
 	int i;
 
-	pmd_phys = pgd_pgtable_alloc_init_mm_gfp(TABLE_PMD, gfp);
+	pmd_phys = pgd_pgtable_alloc_split(TABLE_PMD, split_args);
 	if (pmd_phys == INVALID_PHYS_ADDR)
 		return -ENOMEM;
 	pmdp = (pmd_t *)phys_to_virt(pmd_phys);
@@ -672,6 +723,10 @@ static int split_kernel_leaf_mapping_locked(unsigned long addr)
 	pmd_t *pmdp, pmd;
 	pte_t *ptep, pte;
 	int ret = 0;
+	struct split_args split_args = {
+		.mode = SPLIT_ALLOC,
+		.gfp = GFP_PGTABLE_KERNEL,
+	};
 
 	/*
 	 * PGD: If addr is PGD aligned then addr already describes a leaf
@@ -707,7 +762,7 @@ static int split_kernel_leaf_mapping_locked(unsigned long addr)
 	if (!pud_present(pud))
 		goto out;
 	if (pud_leaf(pud)) {
-		ret = split_pud(pudp, pud, GFP_PGTABLE_KERNEL, true);
+		ret = split_pud(pudp, pud, &split_args, true);
 		if (ret)
 			goto out;
 	}
@@ -732,7 +787,7 @@ static int split_kernel_leaf_mapping_locked(unsigned long addr)
 		 */
 		if (ALIGN_DOWN(addr, PMD_SIZE) == addr)
 			goto out;
-		ret = split_pmd(pmdp, pmd, GFP_PGTABLE_KERNEL, true);
+		ret = split_pmd(pmdp, pmd, &split_args, true);
 		if (ret)
 			goto out;
 	}
@@ -831,12 +886,17 @@ int split_kernel_leaf_mapping(unsigned long start, unsigned long end)
 static int split_to_ptes_pud_entry(pud_t *pudp, unsigned long addr,
 				   unsigned long next, struct mm_walk *walk)
 {
-	gfp_t gfp = *(gfp_t *)walk->private;
+	struct split_args *split_args = (struct split_args *)walk->private;
 	pud_t pud = pudp_get(pudp);
 	int ret = 0;
 
-	if (pud_leaf(pud))
-		ret = split_pud(pudp, pud, gfp, false);
+	if (!pud_leaf(pud))
+		return 0;
+
+	if (split_args->mode == SPLIT_COLLECT)
+		split_args->nr++;
+	else
+		ret = split_pud(pudp, pud, split_args, false);
 
 	return ret;
 }
@@ -844,22 +904,29 @@ static int split_to_ptes_pud_entry(pud_t *pudp, unsigned long addr,
 static int split_to_ptes_pmd_entry(pmd_t *pmdp, unsigned long addr,
 				   unsigned long next, struct mm_walk *walk)
 {
-	gfp_t gfp = *(gfp_t *)walk->private;
+	struct split_args *split_args = (struct split_args *)walk->private;
 	pmd_t pmd = pmdp_get(pmdp);
-	int ret = 0;
+	int ret;
 
-	if (pmd_leaf(pmd)) {
-		if (pmd_cont(pmd))
-			split_contpmd(pmdp);
-		ret = split_pmd(pmdp, pmd, gfp, false);
+	if (!pmd_leaf(pmd))
+		return 0;
 
-		/*
-		 * We have split the pmd directly to ptes so there is no need to
-		 * visit each pte to check if they are contpte.
-		 */
-		walk->action = ACTION_CONTINUE;
+	if (split_args->mode == SPLIT_COLLECT) {
+		split_args->nr++;
+		return 0;
 	}
 
+	if (pmd_cont(pmd))
+		split_contpmd(pmdp);
+	ret = split_pmd(pmdp, pmd, split_args, false);
+
+	/*
+	 * We have split the pmd directly to ptes so there is no need to
+	 * visit each pte to check if they are contpte.
+	 */
+	walk->action = ACTION_CONTINUE;
+
+
 	return ret;
 }
 
@@ -880,13 +947,15 @@ static const struct mm_walk_ops split_to_ptes_ops = {
 	.pte_entry	= split_to_ptes_pte_entry,
 };
 
-static int range_split_to_ptes(unsigned long start, unsigned long end, gfp_t gfp)
+static int range_split_to_ptes(unsigned long start, unsigned long end,
+		 	       struct split_args *split_args)
 {
 	int ret;
 
 	arch_enter_lazy_mmu_mode();
 	ret = walk_kernel_page_table_range_lockless(start, end,
-					&split_to_ptes_ops, NULL, &gfp);
+						    &split_to_ptes_ops, NULL,
+						    split_args);
 	arch_leave_lazy_mmu_mode();
 
 	return ret;
@@ -903,7 +972,7 @@ static void __init init_idmap_kpti_bbml2_flag(void)
 	smp_mb();
 }
 
-static int __init linear_map_split_to_ptes(void *__unused)
+static int __init linear_map_split_to_ptes(void *data)
 {
 	/*
 	 * Repainting the linear map must be done by CPU0 (the boot CPU) because
@@ -911,6 +980,7 @@ static int __init linear_map_split_to_ptes(void *__unused)
 	 * be held in a waiting area with the idmap active.
 	 */
 	if (!smp_processor_id()) {
+		struct split_args *split_args = data;
 		unsigned long lstart = _PAGE_OFFSET(vabits_actual);
 		unsigned long lend = PAGE_END;
 		unsigned long kstart = (unsigned long)lm_alias(_stext);
@@ -928,12 +998,13 @@ static int __init linear_map_split_to_ptes(void *__unused)
 		 * PTE. The kernel alias remains static throughout runtime so
 		 * can continue to be safely mapped with large mappings.
 		 */
-		ret = range_split_to_ptes(lstart, kstart, GFP_ATOMIC);
+		ret = range_split_to_ptes(lstart, lend, split_args);
 		if (!ret)
-			ret = range_split_to_ptes(kend, lend, GFP_ATOMIC);
+			ret = range_split_to_ptes(kstart, kend, split_args);
 		if (ret)
 			panic("Failed to split linear map\n");
-		flush_tlb_kernel_range(lstart, lend);
+		if (split_args->mode != SPLIT_COLLECT)
+			flush_tlb_kernel_range(lstart, lend);
 
 		/*
 		 * Relies on dsb in flush_tlb_kernel_range() to avoid reordering
@@ -963,10 +1034,61 @@ static int __init linear_map_split_to_ptes(void *__unused)
 
 void __init linear_map_maybe_split_to_ptes(void)
 {
-	if (linear_map_requires_bbml2 && !system_supports_bbml2_noabort()) {
-		init_idmap_kpti_bbml2_flag();
-		stop_machine(linear_map_split_to_ptes, NULL, cpu_online_mask);
+	struct page **pages = NULL;
+	struct split_args split_args;
+	int order;
+	int nr_populated;
+	int err;
+
+	if (!linear_map_requires_bbml2 || system_supports_bbml2_noabort())
+		return;
+
+	/*
+	 * Phase 1: Collect required extra pages to split.
+	 */
+	split_args.mode = SPLIT_COLLECT;
+	split_args.nr = 0;
+
+	init_idmap_kpti_bbml2_flag();
+	stop_machine(linear_map_split_to_ptes, &split_args, cpu_online_mask);
+
+	/*
+	 * Phase 2: Allocate necessary pages to split.
+	 */
+	if (split_args.nr == 0) {
+		err = 0;
+		split_args.mode = SPLIT_ALLOC;
+	} else {
+		err = -ENOMEM;
+		order = order_base_2(PAGE_ALIGN(split_args.nr *
+					sizeof(struct page *)) >> PAGE_SHIFT);
+
+		pages = (struct page **)__get_free_pages(GFP_ATOMIC | __GFP_ZERO, order);
+		if (!pages)
+			goto error;
+
+		nr_populated = alloc_pages_bulk(GFP_ATOMIC | __GFP_ZERO, split_args.nr, pages);
+		if (nr_populated < split_args.nr)
+			goto error;
+
+		err = 0;
+		split_args.mode = SPLIT_PREALLOC;
+		split_args.i = 0;
+		split_args.pages = pages;
 	}
+
+	/*
+	 * Phase 3: Split linear map.
+	 */
+	init_idmap_kpti_bbml2_flag();
+	stop_machine(linear_map_split_to_ptes, &split_args, cpu_online_mask);
+
+error:
+	if (pages)
+		free_pages((unsigned long)pages, order);
+
+	if (err)
+		panic("Failed to split linear map: %d\n", err);
 }
 
 /*
@@ -1087,6 +1209,11 @@ bool arch_kfence_init_pool(void)
 	unsigned long start = (unsigned long)__kfence_pool;
 	unsigned long end = start + KFENCE_POOL_SIZE;
 	int ret;
+	struct split_args split_args = {
+		.mode = SPLIT_ALLOC,
+		.gfp = GFP_PGTABLE_KERNEL,
+	};
+
 
 	/* Exit early if we know the linear map is already pte-mapped. */
 	if (!split_leaf_mapping_possible())
@@ -1097,7 +1224,7 @@ bool arch_kfence_init_pool(void)
 		return true;
 
 	mutex_lock(&pgtable_split_lock);
-	ret = range_split_to_ptes(start, end, GFP_PGTABLE_KERNEL);
+	ret = range_split_to_ptes(start, end, &split_args);
 	mutex_unlock(&pgtable_split_lock);
 
 	/*
-- 
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



From yeoreum.yun at arm.com  Wed Dec 17 10:20:07 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Wed, 17 Dec 2025 18:20:07 +0000
Subject: [PATCH v2 2/2] arm64: mmu: avoid allocating pages while installing ng-mapping for KPTI
In-Reply-To: <20251217182007.2345700-1-yeoreum.yun@arm.com>
References: <20251217182007.2345700-1-yeoreum.yun@arm.com>
Message-ID: <20251217182007.2345700-3-yeoreum.yun@arm.com>

The current __kpti_install_ng_mappings() allocates a temporary PGD
while installing the NG mapping for KPTI under stop_machine(),
using GFP_ATOMIC.

This is fine in the non-PREEMPT_RT case. However, it becomes a problem
under PREEMPT_RT because generic memory allocation/free APIs
(e.g., pgtable_alloc(), __get_free_pages(), etc.) cannot be invoked
in a non-preemptible context, except for the *_nolock() variants.
These generic allocators may sleep due to their use of spin_lock().

In other words, calling __get_free_pages(), even with GFP_ATOMIC,
is not allowed in __kpti_install_ng_mappings(), which is executed by
the stopper thread where preemption is disabled under PREEMPT_RT.

To address this, preallocate the page needed for the temporary PGD
before invoking __kpti_install_ng_mappings() via stop_machine().

Fixes: 47546a1912fc ("arm64: mm: install KPTI nG mappings with MMU enabled")
Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
---
 arch/arm64/mm/mmu.c | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index e4e6c7e0a016..69d9651de0cd 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -1360,7 +1360,7 @@ static phys_addr_t __init kpti_ng_pgd_alloc(enum pgtable_type type)
 	return kpti_ng_temp_alloc;
 }
 
-static int __init __kpti_install_ng_mappings(void *__unused)
+static int __init __kpti_install_ng_mappings(void *data)
 {
 	typedef void (kpti_remap_fn)(int, int, phys_addr_t, unsigned long);
 	extern kpti_remap_fn idmap_kpti_install_ng_mappings;
@@ -1368,10 +1368,9 @@ static int __init __kpti_install_ng_mappings(void *__unused)
 
 	int cpu = smp_processor_id();
 	int levels = CONFIG_PGTABLE_LEVELS;
-	int order = order_base_2(levels);
 	u64 kpti_ng_temp_pgd_pa = 0;
 	pgd_t *kpti_ng_temp_pgd;
-	u64 alloc = 0;
+	u64 alloc = *(u64 *)data;
 
 	if (levels == 5 && !pgtable_l5_enabled())
 		levels = 4;
@@ -1382,8 +1381,6 @@ static int __init __kpti_install_ng_mappings(void *__unused)
 
 	if (!cpu) {
 		int ret;
-
-		alloc = __get_free_pages(GFP_ATOMIC | __GFP_ZERO, order);
 		kpti_ng_temp_pgd = (pgd_t *)(alloc + (levels - 1) * PAGE_SIZE);
 		kpti_ng_temp_alloc = kpti_ng_temp_pgd_pa = __pa(kpti_ng_temp_pgd);
 
@@ -1414,16 +1411,17 @@ static int __init __kpti_install_ng_mappings(void *__unused)
 	remap_fn(cpu, num_online_cpus(), kpti_ng_temp_pgd_pa, KPTI_NG_TEMP_VA);
 	cpu_uninstall_idmap();
 
-	if (!cpu) {
-		free_pages(alloc, order);
+	if (!cpu)
 		arm64_use_ng_mappings = true;
-	}
 
 	return 0;
 }
 
 void __init kpti_install_ng_mappings(void)
 {
+	int order = order_base_2(CONFIG_PGTABLE_LEVELS);
+	u64 alloc;
+
 	/* Check whether KPTI is going to be used */
 	if (!arm64_kernel_unmapped_at_el0())
 		return;
@@ -1436,8 +1434,14 @@ void __init kpti_install_ng_mappings(void)
 	if (arm64_use_ng_mappings)
 		return;
 
+	alloc = __get_free_pages(GFP_ATOMIC | __GFP_ZERO, order);
+	if (!alloc)
+		panic("Failed to alloc page tables\n");
+
 	init_idmap_kpti_bbml2_flag();
-	stop_machine(__kpti_install_ng_mappings, NULL, cpu_online_mask);
+	stop_machine(__kpti_install_ng_mappings, &alloc, cpu_online_mask);
+
+	free_pages(alloc, order);
 }
 
 static pgprot_t __init kernel_exec_prot(void)
-- 
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



From yonghong.song at linux.dev  Wed Dec 17 10:23:59 2025
From: yonghong.song at linux.dev (Yonghong Song)
Date: Wed, 17 Dec 2025 10:23:59 -0800
Subject: [PATCH bpf-next 2/2] bpf: arm64: Optimize recursion detection by
 not using atomics
In-Reply-To: <f144fd46b602b74fc4c1c2664082fbe893e7ec9c274fcc5fdf13d65151749e9c@mail.kernel.org>
References: <20251217162830.2597286-3-puranjay@kernel.org>
 <f144fd46b602b74fc4c1c2664082fbe893e7ec9c274fcc5fdf13d65151749e9c@mail.kernel.org>
Message-ID: <51466fd3-c837-46a6-af50-28a8336fd8cd@linux.dev>



On 12/17/25 8:56 AM, bot+bpf-ci at kernel.org wrote:
>> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
>> index 2da986136d26..654fb94bf60c 100644
>> --- a/include/linux/bpf.h
>> +++ b/include/linux/bpf.h
> [ ... ]
>
>> @@ -2006,12 +2009,32 @@ struct bpf_struct_ops_common_value {
>>
>>   static inline bool bpf_prog_get_recursion_context(struct bpf_prog *prog)
>>   {
>> +#ifdef CONFIG_ARM64
>> +	u8 rctx = interrupt_context_level();
>> +	u8 *active = this_cpu_ptr(prog->active);
>> +
>> +	active[rctx]++;
>> +	barrier();
>> +	if (get_unaligned_le32(active) != BIT(rctx * 8))
>> +		return false;
>> +
>> +	return true;
>> +#else
>>   	return this_cpu_inc_return(*(prog->active)) == 1;
>> +#endif
>>   }
> Can preemption between the increment and check cause a counter leak on
> CONFIG_PREEMPT_RCU systems? The trampoline calls this function under
> rcu_read_lock_dont_migrate() which allows preemption on PREEMPT_RCU
> (documented at include/linux/rcupdate.h:856).
>
> Consider this scenario on an ARM64 system with PREEMPT_RCU:
>
> 1. Thread A increments active[0] to 1
> 2. Preemption occurs before Thread A reaches the check
> 3. Thread B on same CPU increments active[0] to 2
> 4. Thread B checks: sees 2 != BIT(0), returns false
> 5. Thread A resumes, checks: sees 2 != BIT(0), returns false
> 6. Both threads return false, neither runs BPF
> 7. Neither calls bpf_prog_put_recursion_context() (see
>     __bpf_prog_enter_recur() at kernel/bpf/trampoline.c:952)
> 8. Counter permanently stuck at 2, all future BPF on this CPU fails
>
> The old atomic code handled this correctly because this_cpu_inc_return()
> completes atomically, ensuring Thread A reads the value 1 before Thread B
> can interfere. With non-atomic operations, Thread A increments but hasn't
> read the value yet, allowing Thread B to interfere and cause both threads
> to see the modified value.
>
> Is there a guarantee that same-context preemption cannot occur in the BPF
> execution path on ARM64, or does this need additional synchronization?

AI is correct here. See below for another thread:
   https://lore.kernel.org/bpf/20251217093326.1745307-1-chen.dylane at linux.dev/T/#m906fd4502fbbedd4609c586122a393363003312a
where preempt_disable is necessary to prevent the above scenario.

But adding preempt_disable may impact the overall system-level performance.

Does this patch can improve performance for *all* ARM64 cpu versions?
Do you have numbers to show how much performance improvement?

>
>> @@ -2006,12 +2009,32 @@ struct bpf_struct_ops_common_value {
>>
>>   static inline void bpf_prog_put_recursion_context(struct bpf_prog *prog)
>>   {
>> +#ifdef CONFIG_ARM64
>> +	u8 rctx = interrupt_context_level();
>> +	u8 *active = this_cpu_ptr(prog->active);
>> +
>> +	barrier();
>> +	active[rctx]--;
>> +#else
>>   	this_cpu_dec(*(prog->active));
>> +#endif
>>   }
[...]


From Harini.T at amd.com  Wed Dec 17 10:33:00 2025
From: Harini.T at amd.com (T, Harini)
Date: Wed, 17 Dec 2025 18:33:00 +0000
Subject: [PATCH 3/4] rtc: zynqmp: rework set_offset
In-Reply-To: <d02fda5e-47d4-4613-9a21-ed81bc957146@vaisala.com>
References: <20251201-zynqmp-rtc-updates-v1-0-33875c1e385b@vaisala.com>
 <20251201-zynqmp-rtc-updates-v1-3-33875c1e385b@vaisala.com>
 <LV5PR12MB98045BF8A85640F924BCFD4492A3A@LV5PR12MB9804.namprd12.prod.outlook.com>
 <d02fda5e-47d4-4613-9a21-ed81bc957146@vaisala.com>
Message-ID: <LV5PR12MB98041CC1F14EC5C526C4C16092ABA@LV5PR12MB9804.namprd12.prod.outlook.com>

[Public]

Hi,

> -----Original Message-----
> From: Tomas Melin <tomas.melin at vaisala.com>
> Sent: Wednesday, December 10, 2025 5:48 PM
> To: T, Harini <Harini.T at amd.com>; Alexandre Belloni
> <alexandre.belloni at bootlin.com>; Simek, Michal <michal.simek at amd.com>
> Cc: linux-rtc at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux-
> kernel at vger.kernel.org
> Subject: Re: [PATCH 3/4] rtc: zynqmp: rework set_offset
>
> Caution: This message originated from an External Source. Use proper caution
> when opening attachments, clicking links, or responding.
>
>
> Hi,
>
> On 09/12/2025 21:03, T, Harini wrote:
> > [Public]
> >
> > Hi,
> >
> >> -----Original Message-----
> >> From: Tomas Melin <tomas.melin at vaisala.com>
> >> Sent: Monday, December 1, 2025 6:20 PM
> >> To: Alexandre Belloni <alexandre.belloni at bootlin.com>; Simek, Michal
> >> <michal.simek at amd.com>
> >> Cc: linux-rtc at vger.kernel.org; linux-arm-kernel at lists.infradead.org;
> >> linux- kernel at vger.kernel.org; Tomas Melin <tomas.melin at vaisala.com>
> >> Subject: [PATCH 3/4] rtc: zynqmp: rework set_offset
> >>
> >> Caution: This message originated from an External Source. Use proper
> >> caution when opening attachments, clicking links, or responding.
> >>
> >>
> >> set_offset was using remainder of do_div as tick_mult which resulted
> >> in wrong offset. Calibration value also assumed builtin calibration default.
> >> Update fract_offset to correctly calculate the value for negative
> >> offset and replace the for loop with division.
> >>
> >> Signed-off-by: Tomas Melin <tomas.melin at vaisala.com>
> >> ---
> >>  drivers/rtc/rtc-zynqmp.c | 29 +++++++++++------------------
> >>  1 file changed, 11 insertions(+), 18 deletions(-)
> >>
> >> diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c
> >> index
> >>
> 7af5f6f99538f961a53ff56bfc656c907611b900..3bc8831ba2c4c4c701a495
> 06b6
> >> 7ae6174f3ade3d 100644
> >> --- a/drivers/rtc/rtc-zynqmp.c
> >> +++ b/drivers/rtc/rtc-zynqmp.c
> >> @@ -208,13 +208,13 @@ static int xlnx_rtc_read_offset(struct device
> >> *dev, long *offset)  static int xlnx_rtc_set_offset(struct device *dev, long
> offset)  {
> >>         struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
> >> -       unsigned long long rtc_ppb = RTC_PPB;
> >> -       unsigned int tick_mult = do_div(rtc_ppb, xrtcdev->freq);
> >> +       unsigned int calibval, tick_mult, fract_part;
> > tick_mult is mentioned as int in previous patch and unsigned here. Justify
> the type in commit description.
> >>         unsigned char fract_tick = 0;
> >> -       unsigned int calibval;
> >> -       short int  max_tick;
> >> -       int fract_offset;
> >> +       int freq = xrtcdev->freq;
> >> +       int max_tick, fract_offset;
> > Please follow reverse xmas tree variable ordering.
> > Also keep the frac_* variables uniform in both set and read offset functions.
> Agreed, I will use same name of variables and types in next version.
>
> >>
> >> +       /* ticks to reach RTC_PPB */
> > The comment is misleading. Its tick_mult is nanoseconds per tick, not a tick
> count.
> Answered in patch 2/4.
> >> +       tick_mult = DIV_ROUND_CLOSEST(RTC_PPB, xrtcdev->freq);
> > We can first validate offset and then calculate tick_mult to reduce
> > CPU instructions incase of invalid inputs
> In this patch it would in theory apply, but when looking at patch 4/4 You will
> notice that we need to first calculate the helpers so offset is then performed as
> soon as possible.
>
> >>         if (offset < RTC_MIN_OFFSET || offset > RTC_MAX_OFFSET)
> >>                 return -ERANGE;
> >>
> >> @@ -223,29 +223,22 @@ static int xlnx_rtc_set_offset(struct device
> >> *dev, long offset)
> >>
> >>         /* Number fractional ticks for given offset */
> >>         if (fract_offset) {
> >> +               /* round up here so we stay below a full tick */
> >> +               fract_part = DIV_ROUND_UP(tick_mult,
> >> + RTC_FR_MAX_TICKS);
> >>                 if (fract_offset < 0) {
> >> -                       fract_offset = fract_offset + tick_mult;
> >> +                       fract_offset += (fract_part *
> >> + RTC_FR_MAX_TICKS);
> > It would be better to add comment to explain on the negative offset
> > borrowing logic
> I will add comment about this.
>
>
> >>                         max_tick--;
> >>                 }
> >> -               if (fract_offset > (tick_mult / RTC_FR_MAX_TICKS)) {
> >> -                       for (fract_tick = 1; fract_tick < 16; fract_tick++) {
> >> -                               if (fract_offset <=
> >> -                                   (fract_tick *
> >> -                                    (tick_mult / RTC_FR_MAX_TICKS)))
> >> -                                       break;
> >> -                       }
> >> -               }
> >> +               fract_tick = fract_offset / fract_part;
> > Its better to use DIV_ROUND_UP()
> Please explain why, that would change the end result from what is is now.
The truncating division is acceptable as-is. Given the hardware's discrete
4-bit fractional field (16 levels), the quantization error from truncation
is negligible compared to the fundamental hardware precision limit. If you
want to optimize, DIV_ROUND_CLOSEST() would minimize average error, but it's
not required for correctness.
>
> Thanks,
> Tomas
>
> >>         }
> >>
> >>         /* Zynqmp RTC uses second and fractional tick
> >>          * counters for compensation
> >>          */
> >> -       calibval = max_tick + RTC_CALIB_DEF;
> >> +       calibval = max_tick + freq;
> >>
> >>         if (fract_tick)
> >> -               calibval |= RTC_FR_EN;
> >> -
> >> -       calibval |= (fract_tick << RTC_FR_DATSHIFT);
> >> +               calibval |= (RTC_FR_EN | (fract_tick <<
> >> + RTC_FR_DATSHIFT));
> >>
> >>         writel(calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
> >>
> >>
> >> --
> >> 2.47.3
> >>
> >
> > Regards,
> > Harini T

Regards,
Harini T

From puranjay at kernel.org  Wed Dec 17 10:44:04 2025
From: puranjay at kernel.org (Puranjay Mohan)
Date: Wed, 17 Dec 2025 18:44:04 +0000
Subject: [PATCH bpf-next 2/2] bpf: arm64: Optimize recursion detection by
 not using atomics
In-Reply-To: <51466fd3-c837-46a6-af50-28a8336fd8cd@linux.dev>
References: <20251217162830.2597286-3-puranjay@kernel.org> <f144fd46b602b74fc4c1c2664082fbe893e7ec9c274fcc5fdf13d65151749e9c@mail.kernel.org>
 <51466fd3-c837-46a6-af50-28a8336fd8cd@linux.dev>
Message-ID: <CANk7y0irgYcHLH_e9ozjX3wTeDb3GH-PA+6UiLRSBFzpYs8eVQ@mail.gmail.com>

On Wed, Dec 17, 2025 at 6:24?PM Yonghong Song <yonghong.song at linux.dev> wrote:
>
>
>
> On 12/17/25 8:56 AM, bot+bpf-ci at kernel.org wrote:
> >> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> >> index 2da986136d26..654fb94bf60c 100644
> >> --- a/include/linux/bpf.h
> >> +++ b/include/linux/bpf.h
> > [ ... ]
> >
> >> @@ -2006,12 +2009,32 @@ struct bpf_struct_ops_common_value {
> >>
> >>   static inline bool bpf_prog_get_recursion_context(struct bpf_prog *prog)
> >>   {
> >> +#ifdef CONFIG_ARM64
> >> +    u8 rctx = interrupt_context_level();
> >> +    u8 *active = this_cpu_ptr(prog->active);
> >> +
> >> +    active[rctx]++;
> >> +    barrier();
> >> +    if (get_unaligned_le32(active) != BIT(rctx * 8))
> >> +            return false;
> >> +
> >> +    return true;
> >> +#else
> >>      return this_cpu_inc_return(*(prog->active)) == 1;
> >> +#endif
> >>   }
> > Can preemption between the increment and check cause a counter leak on
> > CONFIG_PREEMPT_RCU systems? The trampoline calls this function under
> > rcu_read_lock_dont_migrate() which allows preemption on PREEMPT_RCU
> > (documented at include/linux/rcupdate.h:856).
> >
> > Consider this scenario on an ARM64 system with PREEMPT_RCU:
> >
> > 1. Thread A increments active[0] to 1
> > 2. Preemption occurs before Thread A reaches the check
> > 3. Thread B on same CPU increments active[0] to 2
> > 4. Thread B checks: sees 2 != BIT(0), returns false
> > 5. Thread A resumes, checks: sees 2 != BIT(0), returns false
> > 6. Both threads return false, neither runs BPF
> > 7. Neither calls bpf_prog_put_recursion_context() (see
> >     __bpf_prog_enter_recur() at kernel/bpf/trampoline.c:952)
> > 8. Counter permanently stuck at 2, all future BPF on this CPU fails
> >
> > The old atomic code handled this correctly because this_cpu_inc_return()
> > completes atomically, ensuring Thread A reads the value 1 before Thread B
> > can interfere. With non-atomic operations, Thread A increments but hasn't
> > read the value yet, allowing Thread B to interfere and cause both threads
> > to see the modified value.
> >
> > Is there a guarantee that same-context preemption cannot occur in the BPF
> > execution path on ARM64, or does this need additional synchronization?
>
> AI is correct here. See below for another thread:
>    https://lore.kernel.org/bpf/20251217093326.1745307-1-chen.dylane at linux.dev/T/#m906fd4502fbbedd4609c586122a393363003312a
> where preempt_disable is necessary to prevent the above scenario.

See my other reply, the above scenario presented by AI is wrong
because step 7 is wrong.

> But adding preempt_disable may impact the overall system-level performance.
>
> Does this patch can improve performance for *all* ARM64 cpu versions?
> Do you have numbers to show how much performance improvement?

This should improve performance on all arm64 CPUs because atomics are
expensive because they are atomic across all cpus.

I see a 33% improvement in the fentry trigger benchmark, but I can do
more benchmarking.

> >
> >> @@ -2006,12 +2009,32 @@ struct bpf_struct_ops_common_value {
> >>
> >>   static inline void bpf_prog_put_recursion_context(struct bpf_prog *prog)
> >>   {
> >> +#ifdef CONFIG_ARM64
> >> +    u8 rctx = interrupt_context_level();
> >> +    u8 *active = this_cpu_ptr(prog->active);
> >> +
> >> +    barrier();
> >> +    active[rctx]--;
> >> +#else
> >>      this_cpu_dec(*(prog->active));
> >> +#endif
> >>   }
> [...]


From alexei.starovoitov at gmail.com  Wed Dec 17 10:46:21 2025
From: alexei.starovoitov at gmail.com (Alexei Starovoitov)
Date: Wed, 17 Dec 2025 10:46:21 -0800
Subject: [PATCH bpf-next 2/2] bpf: arm64: Optimize recursion detection by
 not using atomics
In-Reply-To: <CANk7y0h4JO2-tp9HjRHjcQdTOgmRSsw0rxmK-=G89AVY92U8Jw@mail.gmail.com>
References: <20251217162830.2597286-3-puranjay@kernel.org> <f144fd46b602b74fc4c1c2664082fbe893e7ec9c274fcc5fdf13d65151749e9c@mail.kernel.org>
 <CANk7y0h4JO2-tp9HjRHjcQdTOgmRSsw0rxmK-=G89AVY92U8Jw@mail.gmail.com>
Message-ID: <CAADnVQ+E6Tgcf1E5x-wk_TA+Lz83cA=SL8EZUGL70bQpywwexg@mail.gmail.com>

On Wed, Dec 17, 2025 at 10:13?AM Puranjay Mohan <puranjay at kernel.org> wrote:
>
> On Wed, Dec 17, 2025 at 4:56?PM <bot+bpf-ci at kernel.org> wrote:
> >
> > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> > > index 2da986136d26..654fb94bf60c 100644
> > > --- a/include/linux/bpf.h
> > > +++ b/include/linux/bpf.h
> >
> > [ ... ]
> >
> > > @@ -2006,12 +2009,32 @@ struct bpf_struct_ops_common_value {
> > >
> > >  static inline bool bpf_prog_get_recursion_context(struct bpf_prog *prog)
> > >  {
> > > +#ifdef CONFIG_ARM64
> > > +     u8 rctx = interrupt_context_level();
> > > +     u8 *active = this_cpu_ptr(prog->active);
> > > +
> > > +     active[rctx]++;
> > > +     barrier();
> > > +     if (get_unaligned_le32(active) != BIT(rctx * 8))
> > > +             return false;
> > > +
> > > +     return true;
> > > +#else
> > >       return this_cpu_inc_return(*(prog->active)) == 1;
> > > +#endif
> > >  }
> >
> > Can preemption between the increment and check cause a counter leak on
> > CONFIG_PREEMPT_RCU systems? The trampoline calls this function under
> > rcu_read_lock_dont_migrate() which allows preemption on PREEMPT_RCU
> > (documented at include/linux/rcupdate.h:856).
> >
> > Consider this scenario on an ARM64 system with PREEMPT_RCU:
> >
> > 1. Thread A increments active[0] to 1
> > 2. Preemption occurs before Thread A reaches the check
> > 3. Thread B on same CPU increments active[0] to 2
> > 4. Thread B checks: sees 2 != BIT(0), returns false
> > 5. Thread A resumes, checks: sees 2 != BIT(0), returns false
> > 6. Both threads return false, neither runs BPF
> > 7. Neither calls bpf_prog_put_recursion_context() (see
> >    __bpf_prog_enter_recur() at kernel/bpf/trampoline.c:952)
> > 8. Counter permanently stuck at 2, all future BPF on this CPU fails
>
> Step 7 is incorrect. Looking at the JIT-generated code, the exit
> function is ALWAYS called, regardless of whether the enter function
> returns 0 or a start time:
>
>   // x86 JIT at arch/x86/net/bpf_jit_comp.c:2998-3050
>   call bpf_trampoline_enter()    // Line 2998
>   test rax, rax                   // Line 3006
>   je skip_exec                    // Conditional jump
>   ... BPF program execution ...   // Lines 3011-3023
>   skip_exec:                      // Line 3037 (jump lands here)
>   call bpf_trampoline_exit()      // Line 3049 - ALWAYS executed
>
>   The bpf_trampoline_exit() call is after the skip_exec label, so it
> executes in both cases.
>
> What Actually Happens:
>
>   Initial state: active[0] = 0
>
>   Thread A (normal context, rctx=0):
>   1. active[0]++ ? active[0] = 1
>   2. Preempted before barrier()
>
>   Thread B (scheduled on same CPU, normal context, rctx=0):
>   3. active[0]++ ? active[0] = 2
>   4. barrier()
>   5. get_unaligned_le32(active) ? reads 0x00000002
>   6. Check: 0x00000002 != BIT(0) = 0x00000001 ? returns false
>   7. __bpf_prog_enter_recur returns 0
>   8. JIT checks return value, skips BPF execution
>   9. JIT ALWAYS calls __bpf_prog_exit_recur (see
> arch/arm64/net/bpf_jit_comp.c:2362)
>   10. bpf_prog_put_recursion_context(prog) executes
>   11. barrier(), active[0]-- ? active[0] = 1
>
>   Thread A resumes:
>   12. barrier()
>   13. get_unaligned_le32(active) ? reads 0x00000001 (Thread B already
> decremented!)
>   14. Check: 0x00000001 == BIT(0) = 0x00000001 ? returns true ?
>   15. __bpf_prog_enter_recur returns start_time
>   16. BPF program executes
>   17. __bpf_prog_exit_recur called
>   18. bpf_prog_put_recursion_context(prog) executes
>   19. barrier(), active[0]-- ? active[0] = 0 ?
>
>   Final State
>
>   - Counter returns to 0 ?
>   - No leak ?
>   - Thread B detected interference and aborted ?
>   - Thread A executed successfully ?
>   - Only ONE thread executed the BPF program ?
>
>
> Now that I think of it, there is another race condition that leads to
> NEITHER program running:
>
> Consider this scenario on an arm64 system with PREEMPT_RCU:
>
> 1. Thread A increments active[0] from 0 to 1
> 2. Thread A is preempted before reaching barrier()
> 3. Thread B (same CPU, same context) increments active[0] from 1 to 2
> 4. Thread B executes barrier() and checks: sees 2 != BIT(0), returns false
> 5. Thread A resumes, executes barrier() and checks: sees 2 != BIT(0),
> returns false
> 6. Both threads return false to __bpf_prog_enter_recur()
> 7. Both skip BPF program execution
> 8. Both call bpf_prog_put_recursion_context() and decrement: 2->1->0
> 9. Neither BPF program executes, but the counter correctly returns to 0
>
> This means the patch is changing the behaviour in case of recursion
> from "One program gets to run" to
> "At most one program gets to run", but given the performance benefits,
> I think we can accept this change.

Agree. It's fine, but we can mitigate it, but doing this rctx trick
only when RCU is not preemptable. Which pretty much would mean
that PREEMPT_RT will use atomic and !RT will use rctx
and this 'no prog executes' will not happen.

> I am not sure what would change in reality if we allow both BPF
> programs to be skipped in case of high interleaving
> like above.
>
> > The old atomic code handled this correctly because this_cpu_inc_return()
> > completes atomically, ensuring Thread A reads the value 1 before Thread B
> > can interfere. With non-atomic operations, Thread A increments but hasn't
> > read the value yet, allowing Thread B to interfere and cause both threads
> > to see the modified value.
> >
> > Is there a guarantee that same-context preemption cannot occur in the BPF
> > execution path on ARM64, or does this need additional synchronization?
> >
> > > @@ -2006,12 +2009,32 @@ struct bpf_struct_ops_common_value {
> > >
> > >  static inline void bpf_prog_put_recursion_context(struct bpf_prog *prog)
> > >  {
> > > +#ifdef CONFIG_ARM64
> > > +     u8 rctx = interrupt_context_level();
> > > +     u8 *active = this_cpu_ptr(prog->active);
> > > +
> > > +     barrier();
> > > +     active[rctx]--;
> > > +#else
> > >       this_cpu_dec(*(prog->active));
> > > +#endif
> > >  }
> >
> > The barrier() is placed before the decrement. Does this provide the needed
> > ordering guarantee, or should there also be a barrier after the decrement
> > to ensure visibility?
> >
> > > diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> > > index c66316e32563..b5063acfcf92 100644
> > > --- a/kernel/bpf/core.c
> > > +++ b/kernel/bpf/core.c
> >
> > [ ... ]
> >
> > > @@ -112,7 +112,8 @@ struct bpf_prog *bpf_prog_alloc_no_stats(unsigned int size, gfp_t gfp_extra_flag
> > >               vfree(fp);
> > >               return NULL;
> > >       }
> > > -     fp->active = alloc_percpu_gfp(int, bpf_memcg_flags(GFP_KERNEL | gfp_extra_flags));
> > > +     fp->active = __alloc_percpu_gfp(sizeof(u8[BPF_NR_CONTEXTS]), 8,
> > > +                                     bpf_memcg_flags(GFP_KERNEL | gfp_extra_flags));
> >
> > The allocation changes to u8[4] for all architectures, but the non-ARM64
> > code path still uses *(prog->active) which now dereferences only the first
> > byte. This changes the counter from int (typically 4 bytes, range ~2^31)
> > to u8 (1 byte, range 256). While 256 recursion levels is sufficient in
> > practice, is this intentional for non-ARM64 platforms, or should they
> > continue using a full int-sized allocation?
>
> This was intentional so that we don't add another #ifdef here, 256
> recursion levels are more than enough.

256 will be fine for !RT.
So suggestion above will address this concern as well when 256+ tasks
are racing concurrently on this cpu.


From alexei.starovoitov at gmail.com  Wed Dec 17 10:47:38 2025
From: alexei.starovoitov at gmail.com (Alexei Starovoitov)
Date: Wed, 17 Dec 2025 10:47:38 -0800
Subject: [PATCH bpf-next 2/2] bpf: arm64: Optimize recursion detection by
 not using atomics
In-Reply-To: <CANk7y0irgYcHLH_e9ozjX3wTeDb3GH-PA+6UiLRSBFzpYs8eVQ@mail.gmail.com>
References: <20251217162830.2597286-3-puranjay@kernel.org> <f144fd46b602b74fc4c1c2664082fbe893e7ec9c274fcc5fdf13d65151749e9c@mail.kernel.org>
 <51466fd3-c837-46a6-af50-28a8336fd8cd@linux.dev> <CANk7y0irgYcHLH_e9ozjX3wTeDb3GH-PA+6UiLRSBFzpYs8eVQ@mail.gmail.com>
Message-ID: <CAADnVQKHXDcTFB5sJJH6mQpymCY7K10zGSKssQetDc-tfy8eZw@mail.gmail.com>

On Wed, Dec 17, 2025 at 10:44?AM Puranjay Mohan <puranjay at kernel.org> wrote:
>
> On Wed, Dec 17, 2025 at 6:24?PM Yonghong Song <yonghong.song at linux.dev> wrote:
> >
> >
> >
> > On 12/17/25 8:56 AM, bot+bpf-ci at kernel.org wrote:
> > >> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> > >> index 2da986136d26..654fb94bf60c 100644
> > >> --- a/include/linux/bpf.h
> > >> +++ b/include/linux/bpf.h
> > > [ ... ]
> > >
> > >> @@ -2006,12 +2009,32 @@ struct bpf_struct_ops_common_value {
> > >>
> > >>   static inline bool bpf_prog_get_recursion_context(struct bpf_prog *prog)
> > >>   {
> > >> +#ifdef CONFIG_ARM64
> > >> +    u8 rctx = interrupt_context_level();
> > >> +    u8 *active = this_cpu_ptr(prog->active);
> > >> +
> > >> +    active[rctx]++;
> > >> +    barrier();
> > >> +    if (get_unaligned_le32(active) != BIT(rctx * 8))
> > >> +            return false;
> > >> +
> > >> +    return true;
> > >> +#else
> > >>      return this_cpu_inc_return(*(prog->active)) == 1;
> > >> +#endif
> > >>   }
> > > Can preemption between the increment and check cause a counter leak on
> > > CONFIG_PREEMPT_RCU systems? The trampoline calls this function under
> > > rcu_read_lock_dont_migrate() which allows preemption on PREEMPT_RCU
> > > (documented at include/linux/rcupdate.h:856).
> > >
> > > Consider this scenario on an ARM64 system with PREEMPT_RCU:
> > >
> > > 1. Thread A increments active[0] to 1
> > > 2. Preemption occurs before Thread A reaches the check
> > > 3. Thread B on same CPU increments active[0] to 2
> > > 4. Thread B checks: sees 2 != BIT(0), returns false
> > > 5. Thread A resumes, checks: sees 2 != BIT(0), returns false
> > > 6. Both threads return false, neither runs BPF
> > > 7. Neither calls bpf_prog_put_recursion_context() (see
> > >     __bpf_prog_enter_recur() at kernel/bpf/trampoline.c:952)
> > > 8. Counter permanently stuck at 2, all future BPF on this CPU fails
> > >
> > > The old atomic code handled this correctly because this_cpu_inc_return()
> > > completes atomically, ensuring Thread A reads the value 1 before Thread B
> > > can interfere. With non-atomic operations, Thread A increments but hasn't
> > > read the value yet, allowing Thread B to interfere and cause both threads
> > > to see the modified value.
> > >
> > > Is there a guarantee that same-context preemption cannot occur in the BPF
> > > execution path on ARM64, or does this need additional synchronization?
> >
> > AI is correct here. See below for another thread:
> >    https://lore.kernel.org/bpf/20251217093326.1745307-1-chen.dylane at linux.dev/T/#m906fd4502fbbedd4609c586122a393363003312a
> > where preempt_disable is necessary to prevent the above scenario.
>
> See my other reply, the above scenario presented by AI is wrong
> because step 7 is wrong.

yep. preempt_disable is not necessary here. perf buffers being
reused is a different issue.


From puranjay12 at gmail.com  Wed Dec 17 10:56:30 2025
From: puranjay12 at gmail.com (Puranjay Mohan)
Date: Wed, 17 Dec 2025 18:56:30 +0000
Subject: [PATCH bpf-next 2/2] bpf: arm64: Optimize recursion detection by
 not using atomics
In-Reply-To: <CAADnVQ+E6Tgcf1E5x-wk_TA+Lz83cA=SL8EZUGL70bQpywwexg@mail.gmail.com>
References: <20251217162830.2597286-3-puranjay@kernel.org> <f144fd46b602b74fc4c1c2664082fbe893e7ec9c274fcc5fdf13d65151749e9c@mail.kernel.org>
 <CANk7y0h4JO2-tp9HjRHjcQdTOgmRSsw0rxmK-=G89AVY92U8Jw@mail.gmail.com> <CAADnVQ+E6Tgcf1E5x-wk_TA+Lz83cA=SL8EZUGL70bQpywwexg@mail.gmail.com>
Message-ID: <CANk7y0jNj0SDOBr=3n_0jhQbLzaj--yVUF4oDA-ManQG-=bkhw@mail.gmail.com>

On Wed, Dec 17, 2025 at 6:46?PM Alexei Starovoitov
<alexei.starovoitov at gmail.com> wrote:
>
> On Wed, Dec 17, 2025 at 10:13?AM Puranjay Mohan <puranjay at kernel.org> wrote:
> >
> > On Wed, Dec 17, 2025 at 4:56?PM <bot+bpf-ci at kernel.org> wrote:
> > >
> > > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> > > > index 2da986136d26..654fb94bf60c 100644
> > > > --- a/include/linux/bpf.h
> > > > +++ b/include/linux/bpf.h
> > >
> > > [ ... ]
> > >
> > > > @@ -2006,12 +2009,32 @@ struct bpf_struct_ops_common_value {
> > > >
> > > >  static inline bool bpf_prog_get_recursion_context(struct bpf_prog *prog)
> > > >  {
> > > > +#ifdef CONFIG_ARM64
> > > > +     u8 rctx = interrupt_context_level();
> > > > +     u8 *active = this_cpu_ptr(prog->active);
> > > > +
> > > > +     active[rctx]++;
> > > > +     barrier();
> > > > +     if (get_unaligned_le32(active) != BIT(rctx * 8))
> > > > +             return false;
> > > > +
> > > > +     return true;
> > > > +#else
> > > >       return this_cpu_inc_return(*(prog->active)) == 1;
> > > > +#endif
> > > >  }
> > >
> > > Can preemption between the increment and check cause a counter leak on
> > > CONFIG_PREEMPT_RCU systems? The trampoline calls this function under
> > > rcu_read_lock_dont_migrate() which allows preemption on PREEMPT_RCU
> > > (documented at include/linux/rcupdate.h:856).
> > >
> > > Consider this scenario on an ARM64 system with PREEMPT_RCU:
> > >
> > > 1. Thread A increments active[0] to 1
> > > 2. Preemption occurs before Thread A reaches the check
> > > 3. Thread B on same CPU increments active[0] to 2
> > > 4. Thread B checks: sees 2 != BIT(0), returns false
> > > 5. Thread A resumes, checks: sees 2 != BIT(0), returns false
> > > 6. Both threads return false, neither runs BPF
> > > 7. Neither calls bpf_prog_put_recursion_context() (see
> > >    __bpf_prog_enter_recur() at kernel/bpf/trampoline.c:952)
> > > 8. Counter permanently stuck at 2, all future BPF on this CPU fails
> >
> > Step 7 is incorrect. Looking at the JIT-generated code, the exit
> > function is ALWAYS called, regardless of whether the enter function
> > returns 0 or a start time:
> >
> >   // x86 JIT at arch/x86/net/bpf_jit_comp.c:2998-3050
> >   call bpf_trampoline_enter()    // Line 2998
> >   test rax, rax                   // Line 3006
> >   je skip_exec                    // Conditional jump
> >   ... BPF program execution ...   // Lines 3011-3023
> >   skip_exec:                      // Line 3037 (jump lands here)
> >   call bpf_trampoline_exit()      // Line 3049 - ALWAYS executed
> >
> >   The bpf_trampoline_exit() call is after the skip_exec label, so it
> > executes in both cases.
> >
> > What Actually Happens:
> >
> >   Initial state: active[0] = 0
> >
> >   Thread A (normal context, rctx=0):
> >   1. active[0]++ ? active[0] = 1
> >   2. Preempted before barrier()
> >
> >   Thread B (scheduled on same CPU, normal context, rctx=0):
> >   3. active[0]++ ? active[0] = 2
> >   4. barrier()
> >   5. get_unaligned_le32(active) ? reads 0x00000002
> >   6. Check: 0x00000002 != BIT(0) = 0x00000001 ? returns false
> >   7. __bpf_prog_enter_recur returns 0
> >   8. JIT checks return value, skips BPF execution
> >   9. JIT ALWAYS calls __bpf_prog_exit_recur (see
> > arch/arm64/net/bpf_jit_comp.c:2362)
> >   10. bpf_prog_put_recursion_context(prog) executes
> >   11. barrier(), active[0]-- ? active[0] = 1
> >
> >   Thread A resumes:
> >   12. barrier()
> >   13. get_unaligned_le32(active) ? reads 0x00000001 (Thread B already
> > decremented!)
> >   14. Check: 0x00000001 == BIT(0) = 0x00000001 ? returns true ?
> >   15. __bpf_prog_enter_recur returns start_time
> >   16. BPF program executes
> >   17. __bpf_prog_exit_recur called
> >   18. bpf_prog_put_recursion_context(prog) executes
> >   19. barrier(), active[0]-- ? active[0] = 0 ?
> >
> >   Final State
> >
> >   - Counter returns to 0 ?
> >   - No leak ?
> >   - Thread B detected interference and aborted ?
> >   - Thread A executed successfully ?
> >   - Only ONE thread executed the BPF program ?
> >
> >
> > Now that I think of it, there is another race condition that leads to
> > NEITHER program running:
> >
> > Consider this scenario on an arm64 system with PREEMPT_RCU:
> >
> > 1. Thread A increments active[0] from 0 to 1
> > 2. Thread A is preempted before reaching barrier()
> > 3. Thread B (same CPU, same context) increments active[0] from 1 to 2
> > 4. Thread B executes barrier() and checks: sees 2 != BIT(0), returns false
> > 5. Thread A resumes, executes barrier() and checks: sees 2 != BIT(0),
> > returns false
> > 6. Both threads return false to __bpf_prog_enter_recur()
> > 7. Both skip BPF program execution
> > 8. Both call bpf_prog_put_recursion_context() and decrement: 2->1->0
> > 9. Neither BPF program executes, but the counter correctly returns to 0
> >
> > This means the patch is changing the behaviour in case of recursion
> > from "One program gets to run" to
> > "At most one program gets to run", but given the performance benefits,
> > I think we can accept this change.
>
> Agree. It's fine, but we can mitigate it, but doing this rctx trick
> only when RCU is not preemptable. Which pretty much would mean
> that PREEMPT_RT will use atomic and !RT will use rctx
> and this 'no prog executes' will not happen.


The issue is also with sleepable programs, they use
rcu_read_lock_trace() and can end up with
'no prog executes' scenario.

What do you think is the best approach for them?


From ryan.roberts at arm.com  Wed Dec 17 11:03:02 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Wed, 17 Dec 2025 19:03:02 +0000
Subject: [PATCH v2 2/2] arm64: mmu: avoid allocating pages while
 installing ng-mapping for KPTI
In-Reply-To: <20251217182007.2345700-3-yeoreum.yun@arm.com>
References: <20251217182007.2345700-1-yeoreum.yun@arm.com>
 <20251217182007.2345700-3-yeoreum.yun@arm.com>
Message-ID: <731e3f48-e0a3-4c89-a13a-65ef37faa443@arm.com>

On 17/12/2025 18:20, Yeoreum Yun wrote:
> The current __kpti_install_ng_mappings() allocates a temporary PGD
> while installing the NG mapping for KPTI under stop_machine(),
> using GFP_ATOMIC.
> 
> This is fine in the non-PREEMPT_RT case. However, it becomes a problem
> under PREEMPT_RT because generic memory allocation/free APIs
> (e.g., pgtable_alloc(), __get_free_pages(), etc.) cannot be invoked
> in a non-preemptible context, except for the *_nolock() variants.
> These generic allocators may sleep due to their use of spin_lock().
> 
> In other words, calling __get_free_pages(), even with GFP_ATOMIC,
> is not allowed in __kpti_install_ng_mappings(), which is executed by
> the stopper thread where preemption is disabled under PREEMPT_RT.
> 
> To address this, preallocate the page needed for the temporary PGD
> before invoking __kpti_install_ng_mappings() via stop_machine().
> 
> Fixes: 47546a1912fc ("arm64: mm: install KPTI nG mappings with MMU enabled")
> Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
> ---
>  arch/arm64/mm/mmu.c | 22 +++++++++++++---------
>  1 file changed, 13 insertions(+), 9 deletions(-)
> 
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index e4e6c7e0a016..69d9651de0cd 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -1360,7 +1360,7 @@ static phys_addr_t __init kpti_ng_pgd_alloc(enum pgtable_type type)
>  	return kpti_ng_temp_alloc;
>  }
>  
> -static int __init __kpti_install_ng_mappings(void *__unused)
> +static int __init __kpti_install_ng_mappings(void *data)
>  {
>  	typedef void (kpti_remap_fn)(int, int, phys_addr_t, unsigned long);
>  	extern kpti_remap_fn idmap_kpti_install_ng_mappings;
> @@ -1368,10 +1368,9 @@ static int __init __kpti_install_ng_mappings(void *__unused)
>  
>  	int cpu = smp_processor_id();
>  	int levels = CONFIG_PGTABLE_LEVELS;
> -	int order = order_base_2(levels);
>  	u64 kpti_ng_temp_pgd_pa = 0;
>  	pgd_t *kpti_ng_temp_pgd;
> -	u64 alloc = 0;
> +	u64 alloc = *(u64 *)data;
>  
>  	if (levels == 5 && !pgtable_l5_enabled())
>  		levels = 4;
> @@ -1382,8 +1381,6 @@ static int __init __kpti_install_ng_mappings(void *__unused)
>  
>  	if (!cpu) {
>  		int ret;
> -
> -		alloc = __get_free_pages(GFP_ATOMIC | __GFP_ZERO, order);
>  		kpti_ng_temp_pgd = (pgd_t *)(alloc + (levels - 1) * PAGE_SIZE);
>  		kpti_ng_temp_alloc = kpti_ng_temp_pgd_pa = __pa(kpti_ng_temp_pgd);
>  
> @@ -1414,16 +1411,17 @@ static int __init __kpti_install_ng_mappings(void *__unused)
>  	remap_fn(cpu, num_online_cpus(), kpti_ng_temp_pgd_pa, KPTI_NG_TEMP_VA);
>  	cpu_uninstall_idmap();
>  
> -	if (!cpu) {
> -		free_pages(alloc, order);
> +	if (!cpu)
>  		arm64_use_ng_mappings = true;
> -	}
>  
>  	return 0;
>  }
>  
>  void __init kpti_install_ng_mappings(void)
>  {
> +	int order = order_base_2(CONFIG_PGTABLE_LEVELS);
> +	u64 alloc;
> +
>  	/* Check whether KPTI is going to be used */
>  	if (!arm64_kernel_unmapped_at_el0())
>  		return;
> @@ -1436,8 +1434,14 @@ void __init kpti_install_ng_mappings(void)
>  	if (arm64_use_ng_mappings)
>  		return;
>  
> +	alloc = __get_free_pages(GFP_ATOMIC | __GFP_ZERO, order);

I don't think this requires GFP_ATOMIC now?

With that removed:

Reviewed-by: Ryan Roberts <ryan.roberts at arm.com>

> +	if (!alloc)
> +		panic("Failed to alloc page tables\n");
> +
>  	init_idmap_kpti_bbml2_flag();
> -	stop_machine(__kpti_install_ng_mappings, NULL, cpu_online_mask);
> +	stop_machine(__kpti_install_ng_mappings, &alloc, cpu_online_mask);
> +
> +	free_pages(alloc, order);
>  }
>  
>  static pgprot_t __init kernel_exec_prot(void)



From Harini.T at amd.com  Wed Dec 17 11:03:30 2025
From: Harini.T at amd.com (T, Harini)
Date: Wed, 17 Dec 2025 19:03:30 +0000
Subject: [PATCH 4/4] rtc: zynqmp: use dynamic max and min offset ranges
In-Reply-To: <ea85c8d6-ead8-4fda-905d-909968de5056@vaisala.com>
References: <20251201-zynqmp-rtc-updates-v1-0-33875c1e385b@vaisala.com>
 <20251201-zynqmp-rtc-updates-v1-4-33875c1e385b@vaisala.com>
 <LV5PR12MB98046A63E80D7A7FA299366E92A3A@LV5PR12MB9804.namprd12.prod.outlook.com>
 <ea85c8d6-ead8-4fda-905d-909968de5056@vaisala.com>
Message-ID: <LV5PR12MB98042BB367DAEC6C9BD9D96392ABA@LV5PR12MB9804.namprd12.prod.outlook.com>

[Public]

Hi,

> -----Original Message-----
> From: Tomas Melin <tomas.melin at vaisala.com>
> Sent: Wednesday, December 10, 2025 5:55 PM
> To: T, Harini <Harini.T at amd.com>; Alexandre Belloni
> <alexandre.belloni at bootlin.com>; Simek, Michal <michal.simek at amd.com>
> Cc: linux-rtc at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux-
> kernel at vger.kernel.org
> Subject: Re: [PATCH 4/4] rtc: zynqmp: use dynamic max and min offset ranges
>
> Caution: This message originated from an External Source. Use proper caution
> when opening attachments, clicking links, or responding.
>
>
> Hi,
>
> On 09/12/2025 21:28, T, Harini wrote:
> > [Public]
> >
> > Hi,
> >
> >> -----Original Message-----
> >> From: Tomas Melin <tomas.melin at vaisala.com>
> >> Sent: Monday, December 1, 2025 6:20 PM
> >> To: Alexandre Belloni <alexandre.belloni at bootlin.com>; Simek, Michal
> >> <michal.simek at amd.com>
> >> Cc: linux-rtc at vger.kernel.org; linux-arm-kernel at lists.infradead.org;
> >> linux- kernel at vger.kernel.org; Tomas Melin <tomas.melin at vaisala.com>
> >> Subject: [PATCH 4/4] rtc: zynqmp: use dynamic max and min offset
> >> ranges
> >>
> >> Caution: This message originated from an External Source. Use proper
> >> caution when opening attachments, clicking links, or responding.
> >>
> >>
> >> Maximum and minimum offsets in ppb that can be handled are dependent
> >> on the rtc clock frequency and what can fit in the 16-bit register field.
> >>
> >> Signed-off-by: Tomas Melin <tomas.melin at vaisala.com>
> >> ---
> >>  drivers/rtc/rtc-zynqmp.c | 8 +++-----
> >>  1 file changed, 3 insertions(+), 5 deletions(-)
> >>
> >> diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c
> >> index
> >>
> 3bc8831ba2c4c4c701a49506b67ae6174f3ade3d..0cebc99b15a6de2440a6
> 0afc
> >> 2bd1769eccfa84b3 100644
> >> --- a/drivers/rtc/rtc-zynqmp.c
> >> +++ b/drivers/rtc/rtc-zynqmp.c
> >> @@ -44,8 +44,6 @@
> >>  #define RTC_FR_MASK            0xF0000
> >>  #define RTC_FR_MAX_TICKS       16
> >>  #define RTC_PPB                        1000000000LL
> >> -#define RTC_MIN_OFFSET         -32768000
> >> -#define RTC_MAX_OFFSET         32767000
> >>
> >>  struct xlnx_rtc_dev {
> >>         struct rtc_device       *rtc;
> >> @@ -215,12 +213,12 @@ static int xlnx_rtc_set_offset(struct device
> >> *dev, long offset)
> >>
> >>         /* ticks to reach RTC_PPB */
> >>         tick_mult = DIV_ROUND_CLOSEST(RTC_PPB, xrtcdev->freq);
> >> -       if (offset < RTC_MIN_OFFSET || offset > RTC_MAX_OFFSET)
> >> -               return -ERANGE;
> >> -
> >>         /* Number ticks for given offset */
> >>         max_tick = div_s64_rem(offset, tick_mult, &fract_offset);
> >>
> >> +       if (freq + max_tick > RTC_TICK_MASK || (freq + max_tick < 1))
> > The check 'freq + max_tick < 1' should be '<2' to prevent writing 0 to the
> calibration register when fract_offset < 0 causes max_tick--.
> > Example: freq=32767, max_tick=-32766 passes (sum=1), but after
> decrement becomes calibval=0.
> calibval=0 is not documented as invalid calibration value. AFAIS it would mean
> a frequency of 1Hz. Can You provide more info on this?
>
You're right - calibval=0 is hardware-spec compliant and produces 1Hz
operation. The patch is correct as-is with '< 1'.
There's no issue with allowing calibval=0 from a hardware perspective.
> Thanks,
> Tomas
>
>
> >> +               return -ERANGE;
> >> +
> >>         /* Number fractional ticks for given offset */
> >>         if (fract_offset) {
> >>                 /* round up here so we stay below a full tick */
> >>
> >> --
> >> 2.47.3
> >>
> >
> > Thanks,
> > Harini T
> >
Regards,
Harini T

From yeoreum.yun at arm.com  Wed Dec 17 11:09:00 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Wed, 17 Dec 2025 19:09:00 +0000
Subject: [PATCH v2 2/2] arm64: mmu: avoid allocating pages while
 installing ng-mapping for KPTI
In-Reply-To: <731e3f48-e0a3-4c89-a13a-65ef37faa443@arm.com>
References: <20251217182007.2345700-1-yeoreum.yun@arm.com>
 <20251217182007.2345700-3-yeoreum.yun@arm.com>
 <731e3f48-e0a3-4c89-a13a-65ef37faa443@arm.com>
Message-ID: <aUL/zJlJFRz2/Ybt@e129823.arm.com>

Hi Ryanc,

[...]
> > -	if (!cpu) {
> > -		free_pages(alloc, order);
> > +	if (!cpu)
> >  		arm64_use_ng_mappings = true;
> > -	}
> >
> >  	return 0;
> >  }
> >
> >  void __init kpti_install_ng_mappings(void)
> >  {
> > +	int order = order_base_2(CONFIG_PGTABLE_LEVELS);
> > +	u64 alloc;
> > +
> >  	/* Check whether KPTI is going to be used */
> >  	if (!arm64_kernel_unmapped_at_el0())
> >  		return;
> > @@ -1436,8 +1434,14 @@ void __init kpti_install_ng_mappings(void)
> >  	if (arm64_use_ng_mappings)
> >  		return;
> >
> > +	alloc = __get_free_pages(GFP_ATOMIC | __GFP_ZERO, order);
>
> I don't think this requires GFP_ATOMIC now?
>
> With that removed:
>
> Reviewed-by: Ryan Roberts <ryan.roberts at arm.com>

I think it would be better to use only __GFP_HIGH in here since
when kpti_install_ng_mappings() is called, "kswpd" doesn't created yet.
and to allocate page with assurance, It would be good to use
min_reserved to.

Am I missing something?

Thanks.

[...]

--
Sincerely,
Yeoreum Yun


From alexandre.belloni at bootlin.com  Wed Dec 17 11:17:15 2025
From: alexandre.belloni at bootlin.com (Alexandre Belloni)
Date: Wed, 17 Dec 2025 20:17:15 +0100
Subject: [PATCH 2/4] rtc: zynqmp: rework read_offset
In-Reply-To: <LV5PR12MB980448D3F4109DC0775A56AA92ABA@LV5PR12MB9804.namprd12.prod.outlook.com>
References: <20251201-zynqmp-rtc-updates-v1-0-33875c1e385b@vaisala.com>
 <20251201-zynqmp-rtc-updates-v1-2-33875c1e385b@vaisala.com>
 <LV5PR12MB98047B0A754AFFFB01163E0992A3A@LV5PR12MB9804.namprd12.prod.outlook.com>
 <353422a2-ba6e-4600-9326-e0cee2098062@vaisala.com>
 <LV5PR12MB980448D3F4109DC0775A56AA92ABA@LV5PR12MB9804.namprd12.prod.outlook.com>
Message-ID: <202512171917155dba6723@mail.local>

On 17/12/2025 18:14:30+0000, T, Harini wrote:
> [Public]
> 
> Hi,
> 
> > -----Original Message-----
> > From: Tomas Melin <tomas.melin at vaisala.com>
> > Sent: Wednesday, December 10, 2025 5:35 PM
> > To: T, Harini <Harini.T at amd.com>; Alexandre Belloni
> > <alexandre.belloni at bootlin.com>; Simek, Michal <michal.simek at amd.com>
> > Cc: linux-rtc at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux-
> > kernel at vger.kernel.org
> > Subject: Re: [PATCH 2/4] rtc: zynqmp: rework read_offset
> >
> > Caution: This message originated from an External Source. Use proper caution
> > when opening attachments, clicking links, or responding.
> >
> >
> > Hi,
> >
> > On 09/12/2025 19:28, T, Harini wrote:
> > > [Public]
> > >
> > > Hi,
> > >
> > >> -----Original Message-----
> > >> From: Tomas Melin <tomas.melin at vaisala.com>
> > >> Sent: Monday, December 1, 2025 6:20 PM
> > >> To: Alexandre Belloni <alexandre.belloni at bootlin.com>; Simek, Michal
> > >> <michal.simek at amd.com>
> > >> Cc: linux-rtc at vger.kernel.org; linux-arm-kernel at lists.infradead.org;
> > >> linux- kernel at vger.kernel.org; Tomas Melin <tomas.melin at vaisala.com>
> > >> Subject: [PATCH 2/4] rtc: zynqmp: rework read_offset
> > >>
> > >> Caution: This message originated from an External Source. Use proper
> > >> caution when opening attachments, clicking links, or responding.
> > >>
> > >>
> > >> read_offset() was using static frequency for determining the tick
> > >> offset. It was also using remainder from do_div() operation as
> > >> tick_mult value which caused the offset to be incorrect.
> > >>
> > >> At the same time, rework function to improve readability.
> > >>
> > >> Signed-off-by: Tomas Melin <tomas.melin at vaisala.com>
> > >> ---
> > >>  drivers/rtc/rtc-zynqmp.c | 25 ++++++++++++++++---------
> > >>  1 file changed, 16 insertions(+), 9 deletions(-)
> > >>
> > >> diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c
> > >> index
> > >>
> > 856bc1678e7d31144f320ae9f75fc58c742a2a64..7af5f6f99538f961a53ff56
> > bfc6
> > >> 56c907611b900 100644
> > >> --- a/drivers/rtc/rtc-zynqmp.c
> > >> +++ b/drivers/rtc/rtc-zynqmp.c
> > >> @@ -178,21 +178,28 @@ static void xlnx_init_rtc(struct xlnx_rtc_dev
> > >> *xrtcdev)  static int xlnx_rtc_read_offset(struct device *dev, long *offset)  {
> > >>         struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
> > >> -       unsigned long long rtc_ppb = RTC_PPB;
> > >> -       unsigned int tick_mult = do_div(rtc_ppb, xrtcdev->freq);
> > >> -       unsigned int calibval;
> > >> +       unsigned int calibval, fract_data, fract_part;
> > > Prefer one variable assignment per line for readability.
> > This is after all quite common practice, and in a function like this where several
> > variables are needed, I would argue that this is more readable than the
> > alternative. Is there some convention I'm not aware of?
> There is no such mandatory convention. It's up to the RTC maintainer.

I don't mind having multiple variable declarations on a single line.



-- 
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From royluo at google.com  Wed Dec 17 11:17:34 2025
From: royluo at google.com (Roy Luo)
Date: Wed, 17 Dec 2025 11:17:34 -0800
Subject: [PATCH v9 2/2] usb: dwc3: Add Google Tensor SoC DWC3 glue driver
In-Reply-To: <2025121728-reliably-crabgrass-2601@gregkh>
References: <20251205-controller-v9-0-9f158b18f979@google.com>
 <20251205-controller-v9-2-9f158b18f979@google.com> <2025120553-suffrage-divisive-5890@gregkh>
 <CA+zupgzL7v5MZDpxKDQQCqAZaqTdHbiG9-xTr+8RnigMFZJ_7Q@mail.gmail.com> <2025121728-reliably-crabgrass-2601@gregkh>
Message-ID: <CA+zupgxZCyNonfNPbGnFymGGOQuaWR1TsL+hujTbH4DEcfEt9Q@mail.gmail.com>

On Wed, Dec 17, 2025 at 5:24?AM Greg Kroah-Hartman
<gregkh at linuxfoundation.org> wrote:
>
> On Thu, Dec 04, 2025 at 11:14:39PM -0800, Roy Luo wrote:
> > On Thu, Dec 4, 2025 at 10:05?PM Greg Kroah-Hartman
> > <gregkh at linuxfoundation.org> wrote:
> > >
> > > On Fri, Dec 05, 2025 at 02:26:38AM +0000, Roy Luo wrote:
> > > > +config USB_DWC3_GOOGLE
> > > > +     tristate "Google Platform"
> > > > +     depends on ARCH_GOOGLE || COMPILE_TEST
> > >
> > > There is no ARCH_GOOGLE in the tree now, so how is this supposed to
> > > work?  Shouldn't tools that check for "invalid config options" trigger
> > > on this?
> > >
> > > thanks,
> > >
> > > greg k-h
> >
> > Hi Greg,
> >
> > The menuconfig looks like the following and it doesn't complain:
> > | Symbol: ARCH_GOOGLE [=ARCH_GOOGLE]
> > | Type  : unknown
> > |
> > | Symbol: PHY_GOOGLE_USB [=y]
> > | Type  : tristate
> > | Defined at drivers/phy/Kconfig:104
> > |     Prompt: Google Tensor SoC USB PHY driver
> > |     Depends on: ARCH_GOOGLE || COMPILE_TEST [=y]
> >
> > According to Kconfig documentation [1], the unknown symbol
> > would simply be evaluated as an "n", which is what we want.
> > "Convert the symbol into an expression. Boolean and tristate
> > symbols are simply converted into the respective expression
> > values. All other symbol types result in ?n?."
> >
> > In a different Kconfig documentation, an environment variable
> > "KCONFIG_WARN_UNKNOWN_SYMBOLS" is there to detect
> > undefined symbols in the "config input", but I can't find one that
> > catches undefined symbols in the Kconfig tree itself.
> >
> > That is, the tool seems to allow this.
> > However, if this turns out to be a major problem. I think we
> > can either:
> > - Remove ARCH_GOOGLE and leave COMPILE_TEST as
> >   the only dependency. Then add ARCH_GOOGLE back
> >   later once it's in the tree.
>
> Please do this.  I do not want to take patches that purposfully add
> dependencies on config options that might, or might not, appear in the
> future.  Please just remove all of the dependancies for now, as they are
> not needed, right?
>
> thanks,
>
> greg k-h

Greg,

Yes, we can remove ARCH_GOOGLE for now.
To clarify, we're not removing all of the dependencies, we still want
to keep COMPILE_TEST for build tests, right?
Please let me know if you think otherwise.

Thanks,
Roy


From Frank.li at nxp.com  Wed Dec 17 11:19:24 2025
From: Frank.li at nxp.com (Frank Li)
Date: Wed, 17 Dec 2025 14:19:24 -0500
Subject: [PATCH v2 0/4] s32g: Use a syscon for GPR
In-Reply-To: <aUGlMP7J19L_AHF2@stanley.mountain>
References: <cover.1765806521.git.dan.carpenter@linaro.org>
 <aUAvwRmIZBC0W6ql@lizhi-Precision-Tower-5810>
 <aUBUkuLf7NHtLSl1@stanley.mountain>
 <aUBha2/xiZsIF/o5@lizhi-Precision-Tower-5810>
 <aUBrV2_Iv4oTPkC4@stanley.mountain>
 <aUB4pFEwmMBzW52T@lizhi-Precision-Tower-5810>
 <aUEQkuzSZXFs5nqr@stanley.mountain>
 <aUFvvmDUai9QrhZ2@lizhi-Precision-Tower-5810>
 <aUGlMP7J19L_AHF2@stanley.mountain>
Message-ID: <aUMCPKicgsoICAJ0@lizhi-Precision-Tower-5810>

On Tue, Dec 16, 2025 at 09:30:08PM +0300, Dan Carpenter wrote:
> On Tue, Dec 16, 2025 at 09:42:06AM -0500, Frank Li wrote:
> > > >
> > > > Why not implement standard phy interface,
> > > > phy_set_mode_ext(PHY_MODE_ETHERNET, RGMII);
> > > >
> > > > For example:  drivers/pci/controller/dwc/pci-imx6.c
> > > >
> > > > In legency platform, it use syscon to set some registers. It becomes mess
> > > > when more platform added.  And it becomes hard to convert because avoid
> > > > break compatibltiy now.
> > > >
> > > > It doesn't become worse since new platforms switched to use standard
> > > > inteface, (phy, reset ...).
> > > >
> > >
> > > This happens below that layer, this is just saying where the registers
> > > are found.  The GMAC_0_CTRL_STS is just one register in the GPR region,
> > > most of the others are unrelated to PHY.
> >
> > The other register should work as other function's providor with mfd.
> >
>
> Syscons are a really standard way to do register accesses.

It is quite like back door. Many clock/reset also use phandle to node to
controller by raw register read/write.

> The
> pci-imx6.c driver you mentioned earlier does it that way...

It is not preferred when we tried to add new one. Give me some time to look
for original threads.

> The only
> thing which my code does differently is I put the offset into the
> phandle, but that's not so unusual and it's arguably a cleaner way
> because now both the base address and offset are in the same file.

It is not big deal about offset. The key is if use phande to direct access
other module's register.

Frank
>
> regards,
> dan carpenter
>


From shenwei.wang at nxp.com  Wed Dec 17 11:45:10 2025
From: shenwei.wang at nxp.com (Shenwei Wang)
Date: Wed, 17 Dec 2025 19:45:10 +0000
Subject: [PATCH v6 1/5] dt-bindings: remoteproc: imx_rproc: Add "rpmsg"
 subnode support
In-Reply-To: <20251217005758.GA3452672-robh@kernel.org>
References: <20251212194341.966387-1-shenwei.wang@nxp.com>
 <20251212194341.966387-2-shenwei.wang@nxp.com>
 <20251217005758.GA3452672-robh@kernel.org>
Message-ID: <PAXPR04MB9185E86CB81C111DAB5B329D89ABA@PAXPR04MB9185.eurprd04.prod.outlook.com>



> -----Original Message-----
> Subject: [EXT] Re: [PATCH v6 1/5] dt-bindings: remoteproc: imx_rproc: Add
> "rpmsg" subnode support
> On Fri, Dec 12, 2025 at 01:43:37PM -0600, Shenwei Wang wrote:
> > Remote processors may announce multiple devices (e.g., I2C, GPIO) over
> > an RPMSG channel.
> 
> Which channel does that happen on?

It runs on the RPMSG  Control channel.

> 
> > These devices may require corresponding device tree nodes, especially
> > when acting as providers, to supply phandles for their consumers.
> >
> > Define an RPMSG node to work as a container for a group of RPMSG
> > channels under the imx_rproc node.
> >
> > Each subnode within "rpmsg" represents an individual RPMSG channel.
> > The name of each subnode corresponds to the channel name as defined by
> > the remote processor.
> >
> > All remote devices associated with a given channel are defined as
> > child nodes under the corresponding channel node.
> >
> > Signed-off-by: Shenwei Wang <shenwei.wang at nxp.com>
> > ---
> >  .../devicetree/bindings/gpio/gpio-rpmsg.yaml  | 49 +++++++++++++++++
> >  .../bindings/remoteproc/fsl,imx-rproc.yaml    | 54 +++++++++++++++++++
> >  2 files changed, 103 insertions(+)
> >  create mode 100644
> > Documentation/devicetree/bindings/gpio/gpio-rpmsg.yaml
> >
> > diff --git a/Documentation/devicetree/bindings/gpio/gpio-rpmsg.yaml
> > b/Documentation/devicetree/bindings/gpio/gpio-rpmsg.yaml
> > new file mode 100644
> > index 000000000000..b3e1a5dbf731
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/gpio/gpio-rpmsg.yaml
> > @@ -0,0 +1,49 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
> > +---
> > +
> > +title: Generic GPIO driver over RPMSG
> 
> The driver doesn't go over RPMSG. It's a GPIO provider or protocol.
> 

Yes, it might be clearer to phrase it as 'Generic RPMSG GPIO Controller,' since this is 
a GPIO controller driver that operates over the RPMsg bus.

> > +
> > +maintainers:
> > +  - Shenwei Wang <shenwei.wang at nxp.com>
> > +
> > +description:
> > +  On an AMP platform, some GPIO controllers are exposed by the remote
> > +processor
> > +  through the RPMSG bus. The RPMSG GPIO transport protocol defines
> > +the packet
> > +  structure and communication flow between Linux and the remote
> > +firmware. Those
> > +  controllers are managed via this transport protocol.
> 
> Got a reference to where any of this is defined?

Will add a ref to the gpio-rpmsg.rst doc.

> 
> > +
> > +properties:
> > +  compatible:
> > +    oneOf:
> > +      - items:
> > +          - enum:
> > +              - fsl,rpmsg-gpio
> > +          - const: rpmsg-gpio
> > +      - const: rpmsg-gpio
> > +
> > +  reg:
> > +    maxItems: 1
> 
> I still don't understand how 'reg' is determined. You may have explained it
> previously, but *this* patch needs to make me understand.
> 

I see. Will add a description for this item.

> > +
> > +  "#gpio-cells":
> > +    const: 2
> > +
> > +  gpio-controller: true
> >        memory-region = <&vdev0buffer>, <&vdev0vring0>, <&vdev0vring1>,
> <&rsc_table>;
> >        syscon = <&src>;
> > +
> > +      rpmsg {
> 
> What's the purpose of this node? Is it going to contain things other than "rpmsg io
> channels"?

It represents the RPMSG bus between Linux and the remote processor, and will eventually 
host additional channels such as rpmsg-i2c-channel and rpmsg-pwm-channel.

Thanks,
Shenwei

> 
> > +        rpmsg-io-channel {
> > +          #address-cells = <1>;
> > +          #size-cells = <0>;
> > +
> > +          gpio at 0 {
> > +            compatible = "rpmsg-gpio";
> > +            reg = <0>;
> > +            gpio-controller;
> > +            #gpio-cells = <2>;
> > +            #interrupt-cells = <2>;
> > +            interrupt-controller;
> > +            interrupt-parent = <&rpmsg_gpioa>;
> > +          };
> > +
> > +          gpio at 1 {
> > +            compatible = "rpmsg-gpio";
> > +            reg = <1>;
> > +            gpio-controller;
> > +            #gpio-cells = <2>;
> > +            #interrupt-cells = <2>;
> > +            interrupt-controller;
> > +            interrupt-parent = <&rpmsg_gpiob>;
> > +          };
> > +        };
> > +      };
> >      };
> >  ...
> > --
> > 2.43.0
> >


From yonghong.song at linux.dev  Wed Dec 17 11:45:14 2025
From: yonghong.song at linux.dev (Yonghong Song)
Date: Wed, 17 Dec 2025 11:45:14 -0800
Subject: [PATCH bpf-next 2/2] bpf: arm64: Optimize recursion detection by
 not using atomics
In-Reply-To: <CANk7y0irgYcHLH_e9ozjX3wTeDb3GH-PA+6UiLRSBFzpYs8eVQ@mail.gmail.com>
References: <20251217162830.2597286-3-puranjay@kernel.org>
 <f144fd46b602b74fc4c1c2664082fbe893e7ec9c274fcc5fdf13d65151749e9c@mail.kernel.org>
 <51466fd3-c837-46a6-af50-28a8336fd8cd@linux.dev>
 <CANk7y0irgYcHLH_e9ozjX3wTeDb3GH-PA+6UiLRSBFzpYs8eVQ@mail.gmail.com>
Message-ID: <26a8d10a-eede-4ebc-b51a-5c08ea02dda5@linux.dev>



On 12/17/25 10:44 AM, Puranjay Mohan wrote:
> On Wed, Dec 17, 2025 at 6:24?PM Yonghong Song <yonghong.song at linux.dev> wrote:
>>
>>
>> On 12/17/25 8:56 AM, bot+bpf-ci at kernel.org wrote:
>>>> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
>>>> index 2da986136d26..654fb94bf60c 100644
>>>> --- a/include/linux/bpf.h
>>>> +++ b/include/linux/bpf.h
>>> [ ... ]
>>>
>>>> @@ -2006,12 +2009,32 @@ struct bpf_struct_ops_common_value {
>>>>
>>>>    static inline bool bpf_prog_get_recursion_context(struct bpf_prog *prog)
>>>>    {
>>>> +#ifdef CONFIG_ARM64
>>>> +    u8 rctx = interrupt_context_level();
>>>> +    u8 *active = this_cpu_ptr(prog->active);
>>>> +
>>>> +    active[rctx]++;
>>>> +    barrier();
>>>> +    if (get_unaligned_le32(active) != BIT(rctx * 8))
>>>> +            return false;
>>>> +
>>>> +    return true;
>>>> +#else
>>>>       return this_cpu_inc_return(*(prog->active)) == 1;
>>>> +#endif
>>>>    }
>>> Can preemption between the increment and check cause a counter leak on
>>> CONFIG_PREEMPT_RCU systems? The trampoline calls this function under
>>> rcu_read_lock_dont_migrate() which allows preemption on PREEMPT_RCU
>>> (documented at include/linux/rcupdate.h:856).
>>>
>>> Consider this scenario on an ARM64 system with PREEMPT_RCU:
>>>
>>> 1. Thread A increments active[0] to 1
>>> 2. Preemption occurs before Thread A reaches the check
>>> 3. Thread B on same CPU increments active[0] to 2
>>> 4. Thread B checks: sees 2 != BIT(0), returns false
>>> 5. Thread A resumes, checks: sees 2 != BIT(0), returns false
>>> 6. Both threads return false, neither runs BPF
>>> 7. Neither calls bpf_prog_put_recursion_context() (see
>>>      __bpf_prog_enter_recur() at kernel/bpf/trampoline.c:952)
>>> 8. Counter permanently stuck at 2, all future BPF on this CPU fails
>>>
>>> The old atomic code handled this correctly because this_cpu_inc_return()
>>> completes atomically, ensuring Thread A reads the value 1 before Thread B
>>> can interfere. With non-atomic operations, Thread A increments but hasn't
>>> read the value yet, allowing Thread B to interfere and cause both threads
>>> to see the modified value.
>>>
>>> Is there a guarantee that same-context preemption cannot occur in the BPF
>>> execution path on ARM64, or does this need additional synchronization?
>> AI is correct here. See below for another thread:
>>     https://lore.kernel.org/bpf/20251217093326.1745307-1-chen.dylane at linux.dev/T/#m906fd4502fbbedd4609c586122a393363003312a
>> where preempt_disable is necessary to prevent the above scenario.
> See my other reply, the above scenario presented by AI is wrong
> because step 7 is wrong.

Thanks for explanation. I missed the case that bpf_trampoline_exit()
is always executed. In such cases, the active[rctx] counter will be
always corrected.

>
>> But adding preempt_disable may impact the overall system-level performance.
>>
>> Does this patch can improve performance for *all* ARM64 cpu versions?
>> Do you have numbers to show how much performance improvement?
> This should improve performance on all arm64 CPUs because atomics are
> expensive because they are atomic across all cpus.

Good to know. Thanks!

>
> I see a 33% improvement in the fentry trigger benchmark, but I can do
> more benchmarking.
>
>>>> @@ -2006,12 +2009,32 @@ struct bpf_struct_ops_common_value {
>>>>
>>>>    static inline void bpf_prog_put_recursion_context(struct bpf_prog *prog)
>>>>    {
>>>> +#ifdef CONFIG_ARM64
>>>> +    u8 rctx = interrupt_context_level();
>>>> +    u8 *active = this_cpu_ptr(prog->active);
>>>> +
>>>> +    barrier();
>>>> +    active[rctx]--;
>>>> +#else
>>>>       this_cpu_dec(*(prog->active));
>>>> +#endif
>>>>    }
>> [...]



From mathieu.poirier at linaro.org  Wed Dec 17 12:05:32 2025
From: mathieu.poirier at linaro.org (Mathieu Poirier)
Date: Wed, 17 Dec 2025 13:05:32 -0700
Subject: [PATCH v2] remoteproc: imx_dsp_rproc: Fix multiple start/stop
 operations
In-Reply-To: <CAEnQRZC0WU+MGfZ5z3yJCz==MBCcFG4BUwNs2v1ABOMkiRbPrw@mail.gmail.com>
References: <20251210154906.99210-1-daniel.baluta@nxp.com>
 <aUHZaapZ1IAs_mRE@p14s>
 <CAEnQRZC0WU+MGfZ5z3yJCz==MBCcFG4BUwNs2v1ABOMkiRbPrw@mail.gmail.com>
Message-ID: <aUMNDPDgN7ACvry9@p14s>

On Wed, Dec 17, 2025 at 02:57:24PM +0200, Daniel Baluta wrote:
> On Wed, Dec 17, 2025 at 12:13?AM Mathieu Poirier
> <mathieu.poirier at linaro.org> wrote:
> >
> > Good day,
> >
> > On Wed, Dec 10, 2025 at 05:49:06PM +0200, Daniel Baluta wrote:
> > > After commit 67a7bc7f0358 ("remoteproc: Use of reserved_mem_region_*
> > > functions for "memory-region"") following commands with
> > > imx-dsp-rproc started to fail:
> > >
> > > $ echo zephyr.elf > /sys/class/remoteproc/remoteproc0/firmware
> > > $ echo start > /sys/class/remoteproc/remoteproc0/state
> > > $ echo stop > /sys/class/remoteproc/remoteproc0/state
> > > $ echo start > /sys/class/remoteproc/remoteproc0/state #! This fails
> > > -sh: echo: write error: Device or resource busy
> > >
> > > This happens because aforementioned commit replaced devm_ioremap_wc with
> > > devm_ioremap_resource_wc which will "reserve" the memory region with the
> > > first start and then will fail at the second start if the memory
> > > region is already reserved.
> > >
> > > Even partially reverting the faulty commit won't fix the
> > > underlying issue because we map the address in prepare() but we never
> > > unmap it at unprepare(), so we will keep leaking memory regions.
> > >
> > > So, lets use alloc() and release() callbacks for memory carveout
> > > handling. This will nicely map() the memory region at prepare() time
> > > and unmap() it at unprepare().
> > >
> > > Fixes: 67a7bc7f0358 ("remoteproc: Use of_reserved_mem_region_* functions for "memory-region"")
> > > Signed-off-by: Daniel Baluta <daniel.baluta at nxp.com>
> > > ---
> > > Changes since v1:
> > >  * https://lore.kernel.org/imx/091a4f29-5435-428a-9a1c-ef82465211cb at nxp.com/T/#t
> > >  * took a different approach and instead of partially reverting the
> > >   faulty patch, used alloc() and release() callbacks to handle memory
> > >   region mapping.
> > >  drivers/remoteproc/imx_dsp_rproc.c | 50 ++++++++++++++++++++----------
> > >  1 file changed, 33 insertions(+), 17 deletions(-)
> > >
> > > diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c
> > > index 5130a35214c9..83468558e634 100644
> > > --- a/drivers/remoteproc/imx_dsp_rproc.c
> > > +++ b/drivers/remoteproc/imx_dsp_rproc.c
> > > @@ -644,6 +644,32 @@ static void imx_dsp_rproc_free_mbox(struct imx_dsp_rproc *priv)
> > >       mbox_free_channel(priv->rxdb_ch);
> > >  }
> > >
> > > +static int imx_dsp_rproc_mem_alloc(struct rproc *rproc,
> > > +                                struct rproc_mem_entry *mem)
> > > +{
> > > +     struct device *dev = rproc->dev.parent;
> > > +     void *va;
> > > +
> > > +     va = ioremap_wc(mem->dma, mem->len);
> > > +     if (!va) {
> > > +             dev_err(dev, "Unable to map memory region: %pa+%zx\n",
> > > +                     &mem->dma, mem->len);
> > > +             return -ENOMEM;
> > > +     }
> > > +
> > > +     mem->va = va;
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +static int imx_dsp_rproc_mem_release(struct rproc *rproc,
> > > +                                  struct rproc_mem_entry *mem)
> > > +{
> > > +     iounmap(mem->va);
> > > +
> > > +     return 0;
> > > +}
> > > +
> > >  /**
> > >   * imx_dsp_rproc_add_carveout() - request mailbox channels
> > >   * @priv: private data pointer
> > > @@ -659,7 +685,6 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv)
> > >       struct device *dev = rproc->dev.parent;
> > >       struct device_node *np = dev->of_node;
> > >       struct rproc_mem_entry *mem;
> > > -     void __iomem *cpu_addr;
> > >       int a, i = 0;
> > >       u64 da;
> > >
> > > @@ -673,15 +698,10 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv)
> > >               if (imx_dsp_rproc_sys_to_da(priv, att->sa, att->size, &da))
> > >                       return -EINVAL;
> > >
> > > -             cpu_addr = devm_ioremap_wc(dev, att->sa, att->size);
> > > -             if (!cpu_addr) {
> > > -                     dev_err(dev, "failed to map memory %p\n", &att->sa);
> > > -                     return -ENOMEM;
> > > -             }
> > > -
> > >               /* Register memory region */
> > > -             mem = rproc_mem_entry_init(dev, (void __force *)cpu_addr, (dma_addr_t)att->sa,
> > > -                                        att->size, da, NULL, NULL, "dsp_mem");
> > > +             mem = rproc_mem_entry_init(dev, NULL, (dma_addr_t)att->sa,
> > > +                                        att->size, da, imx_dsp_rproc_mem_alloc,
> > > +                                        imx_dsp_rproc_mem_release, "dsp_mem");
> >
> > Was there a reason you kept those here rather than moving them to probe() as
> > Iuliana suggested?  Note that I would be fine with this solution since this is
> > how it was before, but if we have to go through a refactoring we may as well
> > take those things into account.
> 
> Tried moving imx_dsp_rproc_add_carveout at probe() time but it doesn't work
> because stop() will clean the carveout list and then the next start() will fail.
> 
> at probe()
> imx_dsp_rproc_add_carveout
> -> rproc_add_carveout (adds allocated carveout to the list).
> 
> at start():
>    -> first start OK
> 
> at stop()
>    -> rproc_shutdown
>        -> rproc_stop
>        -> rproc_resource_cleanup ;//cleans up careveout allocations
> 
> at next start()
>      -> CRASH

I have applied this patch.

Thanks,
Mathieu



From dianders at google.com  Wed Dec 17 12:14:25 2025
From: dianders at google.com (Doug Anderson)
Date: Wed, 17 Dec 2025 12:14:25 -0800
Subject: [PATCH v9 2/2] usb: dwc3: Add Google Tensor SoC DWC3 glue driver
In-Reply-To: <CA+zupgxZCyNonfNPbGnFymGGOQuaWR1TsL+hujTbH4DEcfEt9Q@mail.gmail.com>
References: <20251205-controller-v9-0-9f158b18f979@google.com>
 <20251205-controller-v9-2-9f158b18f979@google.com> <2025120553-suffrage-divisive-5890@gregkh>
 <CA+zupgzL7v5MZDpxKDQQCqAZaqTdHbiG9-xTr+8RnigMFZJ_7Q@mail.gmail.com>
 <2025121728-reliably-crabgrass-2601@gregkh> <CA+zupgxZCyNonfNPbGnFymGGOQuaWR1TsL+hujTbH4DEcfEt9Q@mail.gmail.com>
Message-ID: <CAD=FV=U63F-wxwKDo9be6_X2P2zp6aTBjNghZRbXX1rn4jFNyg@mail.gmail.com>

Hi,

On Wed, Dec 17, 2025 at 11:18?AM Roy Luo <royluo at google.com> wrote:
>
> On Wed, Dec 17, 2025 at 5:24?AM Greg Kroah-Hartman
> <gregkh at linuxfoundation.org> wrote:
> >
> > On Thu, Dec 04, 2025 at 11:14:39PM -0800, Roy Luo wrote:
> > > On Thu, Dec 4, 2025 at 10:05?PM Greg Kroah-Hartman
> > > <gregkh at linuxfoundation.org> wrote:
> > > >
> > > > On Fri, Dec 05, 2025 at 02:26:38AM +0000, Roy Luo wrote:
> > > > > +config USB_DWC3_GOOGLE
> > > > > +     tristate "Google Platform"
> > > > > +     depends on ARCH_GOOGLE || COMPILE_TEST
> > > >
> > > > There is no ARCH_GOOGLE in the tree now, so how is this supposed to
> > > > work?  Shouldn't tools that check for "invalid config options" trigger
> > > > on this?
> > > >
> > > > thanks,
> > > >
> > > > greg k-h
> > >
> > > Hi Greg,
> > >
> > > The menuconfig looks like the following and it doesn't complain:
> > > | Symbol: ARCH_GOOGLE [=ARCH_GOOGLE]
> > > | Type  : unknown
> > > |
> > > | Symbol: PHY_GOOGLE_USB [=y]
> > > | Type  : tristate
> > > | Defined at drivers/phy/Kconfig:104
> > > |     Prompt: Google Tensor SoC USB PHY driver
> > > |     Depends on: ARCH_GOOGLE || COMPILE_TEST [=y]
> > >
> > > According to Kconfig documentation [1], the unknown symbol
> > > would simply be evaluated as an "n", which is what we want.
> > > "Convert the symbol into an expression. Boolean and tristate
> > > symbols are simply converted into the respective expression
> > > values. All other symbol types result in ?n?."
> > >
> > > In a different Kconfig documentation, an environment variable
> > > "KCONFIG_WARN_UNKNOWN_SYMBOLS" is there to detect
> > > undefined symbols in the "config input", but I can't find one that
> > > catches undefined symbols in the Kconfig tree itself.
> > >
> > > That is, the tool seems to allow this.
> > > However, if this turns out to be a major problem. I think we
> > > can either:
> > > - Remove ARCH_GOOGLE and leave COMPILE_TEST as
> > >   the only dependency. Then add ARCH_GOOGLE back
> > >   later once it's in the tree.
> >
> > Please do this.  I do not want to take patches that purposfully add
> > dependencies on config options that might, or might not, appear in the
> > future.  Please just remove all of the dependancies for now, as they are
> > not needed, right?
> >
> > thanks,
> >
> > greg k-h
>
> Greg,
>
> Yes, we can remove ARCH_GOOGLE for now.
> To clarify, we're not removing all of the dependencies, we still want
> to keep COMPILE_TEST for build tests, right?
> Please let me know if you think otherwise.

I think you'd just remove all of them. Normally COMPILE_TEST just
allows folks to compile stuff even when they don't want the ARCH. We
can can add ARCH_GOOGLE back in later once the config exists.

-Doug


From jonathanh at nvidia.com  Wed Dec 17 12:31:09 2025
From: jonathanh at nvidia.com (Jon Hunter)
Date: Wed, 17 Dec 2025 20:31:09 +0000
Subject: [PATCH V7 3/4] dt-bindings: iommu: Add NVIDIA Tegra CMDQV support
In-Reply-To: <20251215064819.3345361-4-amhetre@nvidia.com>
References: <20251215064819.3345361-1-amhetre@nvidia.com>
 <20251215064819.3345361-4-amhetre@nvidia.com>
Message-ID: <fbde672b-611a-4d81-ac05-44e434bf70ae@nvidia.com>



On 15/12/2025 06:48, Ashish Mhetre wrote:
> The Command Queue Virtualization (CMDQV) hardware is part of the
> SMMUv3 implementation on NVIDIA Tegra SoCs. It assists in
> virtualizing the command queue for the SMMU.
> 
> Add a new device tree binding document for nvidia,tegra264-cmdqv.
> 
> Also update the arm,smmu-v3 binding to include an optional nvidia,cmdqv
> property. This property is a phandle to the CMDQV device node, allowing
> the SMMU driver to associate with its corresponding CMDQV instance.
> Restrict this property usage to Nvidia Tegra264 only.
> 
> Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
> Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
> ---
>   .../bindings/iommu/arm,smmu-v3.yaml           | 30 ++++++++++++-
>   .../bindings/iommu/nvidia,tegra264-cmdqv.yaml | 42 +++++++++++++++++++
>   2 files changed, 70 insertions(+), 2 deletions(-)
>   create mode 100644 Documentation/devicetree/bindings/iommu/nvidia,tegra264-cmdqv.yaml
> 
> diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
> index 75fcf4cb52d9..1c03482e4c61 100644
> --- a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
> +++ b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
> @@ -20,7 +20,12 @@ properties:
>     $nodename:
>       pattern: "^iommu@[0-9a-f]*"
>     compatible:
> -    const: arm,smmu-v3
> +    oneOf:
> +      - const: arm,smmu-v3
> +      - items:
> +          - enum:
> +              - nvidia,tegra264-smmu
> +          - const: arm,smmu-v3
>   
>     reg:
>       maxItems: 1
> @@ -58,6 +63,15 @@ properties:
>   
>     msi-parent: true
>   
> +  nvidia,cmdqv:
> +    description: |
> +      A phandle to its pairing CMDQV extension for an implementation on NVIDIA
> +      Tegra SoC.
> +
> +      If this property is absent, CMDQ-Virtualization won't be used and SMMU
> +      will only use its own CMDQ.
> +    $ref: /schemas/types.yaml#/definitions/phandle
> +
>     hisilicon,broken-prefetch-cmd:
>       type: boolean
>       description: Avoid sending CMD_PREFETCH_* commands to the SMMU.
> @@ -69,6 +83,17 @@ properties:
>         register access with page 0 offsets. Set for Cavium ThunderX2 silicon that
>         doesn't support SMMU page1 register space.
>   
> +allOf:
> +  - if:
> +      not:
> +        properties:
> +          compatible:
> +            contains:
> +              const: nvidia,tegra264-smmu
> +    then:
> +      properties:
> +        nvidia,cmdqv: false
> +
>   required:
>     - compatible
>     - reg
> @@ -82,7 +107,7 @@ examples:
>       #include <dt-bindings/interrupt-controller/irq.h>
>   
>       iommu at 2b400000 {
> -            compatible = "arm,smmu-v3";
> +            compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
>               reg = <0x2b400000 0x20000>;
>               interrupts = <GIC_SPI 74 IRQ_TYPE_EDGE_RISING>,
>                            <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>,
> @@ -92,4 +117,5 @@ examples:
>               dma-coherent;
>               #iommu-cells = <1>;
>               msi-parent = <&its 0xff0000>;
> +            nvidia,cmdqv = <&cmdqv>;

So I believe that this is a generic example for arm,smmu-v3, and so I am 
not sure we want to be adding all these NVIDIA specific bits here. What 
would be more appropriate is to add another example under the existing 
example specifically for Tegra264.

Jon

-- 
nvpublic



From robh at kernel.org  Wed Dec 17 12:41:14 2025
From: robh at kernel.org (Rob Herring)
Date: Wed, 17 Dec 2025 14:41:14 -0600
Subject: [PATCH] arm64: dts: xilinx: Drop "label" property on dlg,slg7xl45106
In-Reply-To: <aa064ecf-1714-4d40-8658-19952392cae8@amd.com>
References: <20251216175914.2791200-1-robh@kernel.org> <aa064ecf-1714-4d40-8658-19952392cae8@amd.com>
Message-ID: <CAL_JsqKdrN5UpUWQVQXpJjbTy1gN9_FhhwOoX6zVpG+zZVAptA@mail.gmail.com>

On Wed, Dec 17, 2025 at 6:39?AM Michal Simek <michal.simek at amd.com> wrote:
> On 12/16/25 18:59, Rob Herring (Arm) wrote:
> > The "label" property is not documented for the dlg,slg7xl45106. Nor is
> > it common to use for GPIO controllers. So drop it.
> >
>
> Correct it is not documented but it is at least used in Linux also by
> drivers/gpio/gpio-mmio.c:810:   err = device_property_read_string(dev, "label",
> &label);
>
> which is also not documented in DT binding.

It really should be for all GPIO providers or none of them. IMO, it
should be none of them as we already have "gpio-line-names" which is
essentially per line labels. I can't see why anyone should care about
a label for the controller.

> I don't have a problem with it because I can't see it used anywhere.
>
> But there are other devices where label is the part of binding. And IMHO this
> should be more generic property.

"label" is the generic property. Not sure what you are suggesting here.

Rob


From jonathanh at nvidia.com  Wed Dec 17 12:42:31 2025
From: jonathanh at nvidia.com (Jon Hunter)
Date: Wed, 17 Dec 2025 20:42:31 +0000
Subject: [PATCH V7 4/4] arm64: dts: nvidia: Add nodes for CMDQV
In-Reply-To: <20251215064819.3345361-5-amhetre@nvidia.com>
References: <20251215064819.3345361-1-amhetre@nvidia.com>
 <20251215064819.3345361-5-amhetre@nvidia.com>
Message-ID: <325a9641-a3cb-4137-8cca-99597ca2caa0@nvidia.com>


On 15/12/2025 06:48, Ashish Mhetre wrote:
> The Command Queue Virtualization (CMDQV) hardware is part of the
> SMMUv3 implementation on NVIDIA Tegra SoCs. It assists in
> virtualizing the command queue for the SMMU.
> 
> Update SMMU compatible strings to use nvidia,tegra264-smmu to enable
> CMDQV support. Add device tree nodes for the CMDQV hardware and enable
> them on the tegra264-p3834 platform where SMMUs are enabled. Each SMMU
> instance is paired with its corresponding CMDQV instance via the
> nvidia,cmdqv property.
> 
> Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
> ---
>   .../arm64/boot/dts/nvidia/tegra264-p3834.dtsi |  8 +++
>   arch/arm64/boot/dts/nvidia/tegra264.dtsi      | 50 +++++++++++++++++--
>   2 files changed, 53 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi b/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
> index 06795c82427a..7e2c3e66c2ab 100644
> --- a/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
> +++ b/arch/arm64/boot/dts/nvidia/tegra264-p3834.dtsi
> @@ -23,8 +23,16 @@ iommu at 5000000 {
>   			status = "okay";
>   		};
>   
> +		cmdqv at 5200000 {
> +			status = "okay";
> +		};
> +
>   		iommu at 6000000 {
>   			status = "okay";
>   		};
> +
> +		cmdqv at 6200000 {
> +			status = "okay";
> +		};
>   	};
>   };
> diff --git a/arch/arm64/boot/dts/nvidia/tegra264.dtsi b/arch/arm64/boot/dts/nvidia/tegra264.dtsi
> index f137565da804..9eb7058e3149 100644
> --- a/arch/arm64/boot/dts/nvidia/tegra264.dtsi
> +++ b/arch/arm64/boot/dts/nvidia/tegra264.dtsi
> @@ -3361,7 +3361,7 @@ bus at 8100000000 {
>   			 <0x02 0x00000000 0xd0 0x00000000 0x08 0x80000000>; /* ECAM, prefetchable memory, I/O */
>   
>   		smmu1: iommu at 5000000 {
> -			compatible = "arm,smmu-v3";
> +			compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
>   			reg = <0x00 0x5000000 0x0 0x200000>;
>   			interrupts = <GIC_SPI 12 IRQ_TYPE_EDGE_RISING>,
>   				     <GIC_SPI 13 IRQ_TYPE_EDGE_RISING>;
> @@ -3370,10 +3370,18 @@ smmu1: iommu at 5000000 {
>   
>   			#iommu-cells = <1>;
>   			dma-coherent;
> +			nvidia,cmdqv = <&cmdqv1>;
> +		};
> +
> +		cmdqv1: cmdqv at 5200000 {
> +			compatible = "nvidia,tegra264-cmdqv";
> +			reg = <0x00 0x5200000 0x0 0x830000>;
> +			interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
> +			status = "disabled";
>   		};
>   
>   		smmu2: iommu at 6000000 {
> -			compatible = "arm,smmu-v3";
> +			compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
>   			reg = <0x00 0x6000000 0x0 0x200000>;
>   			interrupts = <GIC_SPI 1 IRQ_TYPE_EDGE_RISING>,
>   				     <GIC_SPI 2 IRQ_TYPE_EDGE_RISING>;
> @@ -3382,6 +3390,14 @@ smmu2: iommu at 6000000 {
>   
>   			#iommu-cells = <1>;
>   			dma-coherent;
> +			nvidia,cmdqv = <&cmdqv2>;
> +		};
> +
> +		cmdqv2: cmdqv at 6200000 {
> +			compatible = "nvidia,tegra264-cmdqv";
> +			reg = <0x00 0x6200000 0x0 0x830000>;
> +			interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
> +			status = "disabled";
>   		};
>   
>   		mc: memory-controller at 8020000 {
> @@ -3437,7 +3453,7 @@ emc: external-memory-controller at 8800000 {
>   		};
>   
>   		smmu0: iommu at a000000 {
> -			compatible = "arm,smmu-v3";
> +			compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
>   			reg = <0x00 0xa000000 0x0 0x200000>;
>   			interrupts = <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>,
>   				     <GIC_SPI 22 IRQ_TYPE_EDGE_RISING>;
> @@ -3446,10 +3462,18 @@ smmu0: iommu at a000000 {
>   
>   			#iommu-cells = <1>;
>   			dma-coherent;
> +			nvidia,cmdqv = <&cmdqv0>;
> +		};
> +
> +		cmdqv0: cmdqv at a200000 {
> +			compatible = "nvidia,tegra264-cmdqv";
> +			reg = <0x00 0xa200000 0x0 0x830000>;
> +			interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
> +			status = "disabled";
>   		};
>   
>   		smmu4: iommu at b000000 {
> -			compatible = "arm,smmu-v3";
> +			compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
>   			reg = <0x00 0xb000000 0x0 0x200000>;
>   			interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
>   				     <GIC_SPI 31 IRQ_TYPE_EDGE_RISING>;
> @@ -3458,6 +3482,14 @@ smmu4: iommu at b000000 {
>   
>   			#iommu-cells = <1>;
>   			dma-coherent;
> +			nvidia,cmdqv = <&cmdqv4>;
> +		};
> +
> +		cmdqv4: cmdqv at b200000 {
> +			compatible = "nvidia,tegra264-cmdqv";
> +			reg = <0x00 0xb200000 0x0 0x830000>;
> +			interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
> +			status = "disabled";
>   		};
>   
>   		i2c14: i2c at c410000 {
> @@ -3690,7 +3722,7 @@ bus at 8800000000 {
>   		ranges = <0x00 0x00000000 0x88 0x00000000 0x01 0x00000000>;
>   
>   		smmu3: iommu at 6000000 {
> -			compatible = "arm,smmu-v3";
> +			compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
>   			reg = <0x00 0x6000000 0x0 0x200000>;
>   			interrupts = <GIC_SPI 225 IRQ_TYPE_EDGE_RISING>,
>   				     <GIC_SPI 226 IRQ_TYPE_EDGE_RISING>;
> @@ -3699,6 +3731,14 @@ smmu3: iommu at 6000000 {
>   
>   			#iommu-cells = <1>;
>   			dma-coherent;
> +			nvidia,cmdqv = <&cmdqv3>;
> +		};
> +
> +		cmdqv3: cmdqv at 6200000 {
> +			compatible = "nvidia,tegra264-cmdqv";
> +			reg = <0x00 0x6200000 0x0 0x830000>;
> +			interrupts = <GIC_SPI 232 IRQ_TYPE_LEVEL_HIGH>;
> +			status = "disabled";
>   		};
>   
>   		hda at 90b0000 {

Looks good to me.

Reviewed-by: Jon Hunter <jonathanh at nvidia.com>

Jon

-- 
nvpublic



From jonathanh at nvidia.com  Wed Dec 17 12:43:08 2025
From: jonathanh at nvidia.com (Jon Hunter)
Date: Wed, 17 Dec 2025 20:43:08 +0000
Subject: [PATCH V7 2/4] iommu/arm-smmu-v3: Add device-tree support for
 CMDQV driver
In-Reply-To: <20251215064819.3345361-3-amhetre@nvidia.com>
References: <20251215064819.3345361-1-amhetre@nvidia.com>
 <20251215064819.3345361-3-amhetre@nvidia.com>
Message-ID: <23df682e-6d08-4827-994e-1bbd89e5c903@nvidia.com>



On 15/12/2025 06:48, Ashish Mhetre wrote:
> Add device tree support to the CMDQV driver to enable usage on Tegra264
> SoCs. The implementation parses the nvidia,cmdqv phandle from the SMMU
> device tree node to associate each SMMU with its corresponding CMDQV
> instance based on compatible string.
> 
> Reviewed-by: Nicolin Chen <nicolinc at nvidia.com>
> Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
> ---
>   drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 32 +++++++++++++++++++++
>   1 file changed, 32 insertions(+)
> 
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index dad3c0cb800b..0cd0013200f3 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -4530,6 +4530,35 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
>   	return 0;
>   }
>   
> +#ifdef CONFIG_TEGRA241_CMDQV
> +static void tegra_cmdqv_dt_probe(struct device_node *smmu_node,
> +				 struct arm_smmu_device *smmu)
> +{
> +	struct platform_device *pdev;
> +	struct device_node *np;
> +
> +	np = of_parse_phandle(smmu_node, "nvidia,cmdqv", 0);
> +	if (!np)
> +		return;
> +
> +	/* Tegra241 CMDQV driver is responsible for put_device() */
> +	pdev = of_find_device_by_node(np);
> +	of_node_put(np);
> +	if (!pdev)
> +		return;
> +
> +	smmu->impl_dev = &pdev->dev;
> +	smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
> +	dev_info(smmu->dev, "found companion CMDQV device: %s\n",
> +		 dev_name(smmu->impl_dev));

This seems a bit noisy. dev_dbg?

> +}
> +#else
> +static void tegra_cmdqv_dt_probe(struct device_node *smmu_node,
> +				 struct arm_smmu_device *smmu)
> +{
> +}
> +#endif
> +
>   #ifdef CONFIG_ACPI
>   #ifdef CONFIG_TEGRA241_CMDQV
>   static void acpi_smmu_dsdt_probe_tegra241_cmdqv(struct acpi_iort_node *node,
> @@ -4635,6 +4664,9 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev,
>   	if (of_dma_is_coherent(dev->of_node))
>   		smmu->features |= ARM_SMMU_FEAT_COHERENCY;
>   
> +	if (of_device_is_compatible(dev->of_node, "nvidia,tegra264-smmu"))
> +		tegra_cmdqv_dt_probe(dev->of_node, smmu);
> +
>   	return ret;
>   }
>   

-- 
nvpublic



From Sascha.Bischoff at arm.com  Wed Dec 17 12:46:22 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Wed, 17 Dec 2025 20:46:22 +0000
Subject: [PATCH 29/32] irqchip/gic-v5: Check if impl is virt capable
In-Reply-To: <aUF9hwjBuUKA73U8@lpieralisi>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	 <20251212152215.675767-30-sascha.bischoff@arm.com>
	 <aUF9hwjBuUKA73U8@lpieralisi>
Message-ID: <759a11630bad887e5cda36aae91d270e2017454b.camel@arm.com>

On Tue, 2025-12-16 at 16:40 +0100, Lorenzo Pieralisi wrote:
> On Fri, Dec 12, 2025 at 03:22:45PM +0000, Sascha Bischoff wrote:
> > Now that there is support for creating a GICv5-based guest with
> > KVM,
> 
> The only comment I have is - as discussed, this patch is not really
> dependent on GICv5 KVM support - ie, if IRS_IDR0.VIRT == b0 there
> isn't
> a chance GIC v3 legacy support is implemented either, maybe it is
> worth
> clarifying that.

I've now explicitly called that out.

> Otherwise LGTM:
> 
> Reviewed-by: Lorenzo Pieralisi <lpieralisi at kernel.org>

Done, thanks!

Sascha

> 
> > check that the hardware itself supports virtualisation, skipping
> > the
> > setting of struct gic_kvm_info if not.
> > 
> > Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
> > ---
> > ?drivers/irqchip/irq-gic-v5-irs.c?? | 4 ++++
> > ?drivers/irqchip/irq-gic-v5.c?????? | 5 +++++
> > ?include/linux/irqchip/arm-gic-v5.h | 4 ++++
> > ?3 files changed, 13 insertions(+)
> 
> 
> > 
> > diff --git a/drivers/irqchip/irq-gic-v5-irs.c
> > b/drivers/irqchip/irq-gic-v5-irs.c
> > index ce2732d649a3e..eebf9f219ac8c 100644
> > --- a/drivers/irqchip/irq-gic-v5-irs.c
> > +++ b/drivers/irqchip/irq-gic-v5-irs.c
> > @@ -744,6 +744,10 @@ static int __init gicv5_irs_init(struct
> > device_node *node)
> > ?	 */
> > ?	if (list_empty(&irs_nodes)) {
> > ?
> > +		idr = irs_readl_relaxed(irs_data, GICV5_IRS_IDR0);
> > +		gicv5_global_data.virt_capable =
> > +			!!FIELD_GET(GICV5_IRS_IDR0_VIRT, idr);
> > +
> > ?		idr = irs_readl_relaxed(irs_data, GICV5_IRS_IDR1);
> > ?		irs_setup_pri_bits(idr);
> > ?
> > diff --git a/drivers/irqchip/irq-gic-v5.c b/drivers/irqchip/irq-
> > gic-v5.c
> > index 41ef286c4d781..f5b17a2557aa1 100644
> > --- a/drivers/irqchip/irq-gic-v5.c
> > +++ b/drivers/irqchip/irq-gic-v5.c
> > @@ -1064,6 +1064,11 @@ static struct gic_kvm_info gic_v5_kvm_info
> > __initdata;
> > ?
> > ?static void __init gic_of_setup_kvm_info(struct device_node *node)
> > ?{
> > +	if (!gicv5_global_data.virt_capable) {
> > +		pr_info("GIC implementation is not virtualization
> > capable\n");
> > +		return;
> > +	}
> > +
> > ?	gic_v5_kvm_info.type = GIC_V5;
> > ?
> > ?	/* GIC Virtual CPU interface maintenance interrupt */
> > diff --git a/include/linux/irqchip/arm-gic-v5.h
> > b/include/linux/irqchip/arm-gic-v5.h
> > index 9607b36f021ee..36f4c0e8ef8e9 100644
> > --- a/include/linux/irqchip/arm-gic-v5.h
> > +++ b/include/linux/irqchip/arm-gic-v5.h
> > @@ -45,6 +45,7 @@
> > ?/*
> > ? * IRS registers and tables structures
> > ? */
> > +#define GICV5_IRS_IDR0			0x0000
> > ?#define GICV5_IRS_IDR1			0x0004
> > ?#define GICV5_IRS_IDR2			0x0008
> > ?#define GICV5_IRS_IDR5			0x0014
> > @@ -65,6 +66,8 @@
> > ?#define GICV5_IRS_IST_STATUSR		0x0194
> > ?#define GICV5_IRS_MAP_L2_ISTR		0x01c0
> > ?
> > +#define GICV5_IRS_IDR0_VIRT		BIT(6)
> > +
> > ?#define GICV5_IRS_IDR1_PRIORITY_BITS	GENMASK(22, 20)
> > ?#define GICV5_IRS_IDR1_IAFFID_BITS	GENMASK(19, 16)
> > ?
> > @@ -280,6 +283,7 @@ struct gicv5_chip_data {
> > ?	u8			cpuif_pri_bits;
> > ?	u8			cpuif_id_bits;
> > ?	u8			irs_pri_bits;
> > +	bool			virt_capable;
> > ?	struct {
> > ?		__le64 *l1ist_addr;
> > ?		u32 l2_size;
> > -- 
> > 2.34.1


From rosenp at gmail.com  Wed Dec 17 12:49:44 2025
From: rosenp at gmail.com (Rosen Penev)
Date: Wed, 17 Dec 2025 12:49:44 -0800
Subject: [PATCH] i2c: exynos5: simplify probe with devm
Message-ID: <20251217204944.10862-1-rosenp@gmail.com>

Cleans up probe a little bit and separates preparation from enablement.

Also use devm for i2c_add_adapter to get rid of the remove function.

Fix return code for failed clk_get_prepared. It returns PTR_ERR.

Signed-off-by: Rosen Penev <rosenp at gmail.com>
---
 drivers/i2c/busses/i2c-exynos5.c | 41 ++++++++------------------------
 1 file changed, 10 insertions(+), 31 deletions(-)

diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c
index 9c1c5f3c09f6..fcc062910497 100644
--- a/drivers/i2c/busses/i2c-exynos5.c
+++ b/drivers/i2c/busses/i2c-exynos5.c
@@ -903,23 +903,20 @@ static int exynos5_i2c_probe(struct platform_device *pdev)
 	i2c->adap.retries = 3;
 
 	i2c->dev = &pdev->dev;
-	i2c->clk = devm_clk_get(&pdev->dev, "hsi2c");
-	if (IS_ERR(i2c->clk)) {
-		dev_err(&pdev->dev, "cannot get clock\n");
-		return -ENOENT;
-	}
+	i2c->clk = devm_clk_get_prepared(&pdev->dev, "hsi2c");
+	if (IS_ERR(i2c->clk))
+		return dev_err_probe(&pdev->dev, PTR_ERR(i2c->clk), "cannot get clock\n");
 
-	i2c->pclk = devm_clk_get_optional(&pdev->dev, "hsi2c_pclk");
-	if (IS_ERR(i2c->pclk)) {
+	i2c->pclk = devm_clk_get_optional_prepared(&pdev->dev, "hsi2c_pclk");
+	if (IS_ERR(i2c->pclk))
 		return dev_err_probe(&pdev->dev, PTR_ERR(i2c->pclk),
 				     "cannot get pclk");
-	}
 
-	ret = clk_prepare_enable(i2c->pclk);
+	ret = clk_enable(i2c->pclk);
 	if (ret)
 		return ret;
 
-	ret = clk_prepare_enable(i2c->clk);
+	ret = clk_enable(i2c->clk);
 	if (ret)
 		goto err_pclk;
 
@@ -958,35 +955,18 @@ static int exynos5_i2c_probe(struct platform_device *pdev)
 
 	exynos5_i2c_reset(i2c);
 
-	ret = i2c_add_adapter(&i2c->adap);
-	if (ret < 0)
-		goto err_clk;
+	ret = devm_i2c_add_adapter(&pdev->dev, &i2c->adap);
 
 	platform_set_drvdata(pdev, i2c);
 
-	clk_disable(i2c->clk);
-	clk_disable(i2c->pclk);
-
-	return 0;
-
  err_clk:
-	clk_disable_unprepare(i2c->clk);
+	clk_disable(i2c->clk);
 
  err_pclk:
-	clk_disable_unprepare(i2c->pclk);
+	clk_disable(i2c->pclk);
 	return ret;
 }
 
-static void exynos5_i2c_remove(struct platform_device *pdev)
-{
-	struct exynos5_i2c *i2c = platform_get_drvdata(pdev);
-
-	i2c_del_adapter(&i2c->adap);
-
-	clk_unprepare(i2c->clk);
-	clk_unprepare(i2c->pclk);
-}
-
 static int exynos5_i2c_suspend_noirq(struct device *dev)
 {
 	struct exynos5_i2c *i2c = dev_get_drvdata(dev);
@@ -1036,7 +1016,6 @@ static const struct dev_pm_ops exynos5_i2c_dev_pm_ops = {
 
 static struct platform_driver exynos5_i2c_driver = {
 	.probe		= exynos5_i2c_probe,
-	.remove		= exynos5_i2c_remove,
 	.driver		= {
 		.name	= "exynos5-hsi2c",
 		.pm	= pm_sleep_ptr(&exynos5_i2c_dev_pm_ops),
-- 
2.52.0



From Sascha.Bischoff at arm.com  Wed Dec 17 12:50:37 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Wed, 17 Dec 2025 20:50:37 +0000
Subject: [PATCH 16/32] KVM: arm64: gic: Introduce irq_queue and
 set_pending_state to irq_ops
In-Reply-To: <865xa5o3ip.wl-maz@kernel.org>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	 <20251212152215.675767-17-sascha.bischoff@arm.com>
	 <865xa5o3ip.wl-maz@kernel.org>
Message-ID: <26bbc034a355fed965261beaa93b9a3895918504.camel@arm.com>

On Wed, 2025-12-17 at 09:34 +0000, Marc Zyngier wrote:
> On Fri, 12 Dec 2025 15:22:40 +0000,
> Sascha Bischoff <Sascha.Bischoff at arm.com> wrote:
> > 
> > There are times when the default behaviour of vgic_queue_irq_unlock
> > is
> > undesirable. This is because some GICs, such a GICv5 which is the
> > main
> > driver for this change, handle the majority of the interrupt
> > lifecycle
> > in hardware. In this case, there is no need for a per-VCPU AP list
> > as
> > the interrupt can be made pending directly. This is done either via
> > the ICH_PPI_x_EL2 registers for PPIs, or with the VDPEND system
> > instruction for SPIs and LPIs.
> > 
> > The queue_irq_unlock function is made overridable using a new
> > function
> > pointer in struct irq_ops. In kvm_vgic_inject_irq,
> > vgic_queue_irq_unlock is overridden if the function pointer is
> > non-null.
> > 
> > Additionally, a new function is added via a function pointer -
> > set_pending_state. The intent is for this to be used to directly
> > set
> > the pending state in hardware.
> > 
> > Both of these new irq_ops are unused in this change - it is purely
> > providing the infrastructure itself. The subsequent PPI injection
> > changes provide a demonstration of their usage.
> > 
> > Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
> > ---
> > ?arch/arm64/kvm/vgic/vgic.c |? 9 ++++++++-
> > ?include/kvm/arm_vgic.h???? | 15 +++++++++++++++
> > ?2 files changed, 23 insertions(+), 1 deletion(-)
> > 
> > diff --git a/arch/arm64/kvm/vgic/vgic.c
> > b/arch/arm64/kvm/vgic/vgic.c
> > index 1fe3dcc997860..fc01c6d07fe62 100644
> > --- a/arch/arm64/kvm/vgic/vgic.c
> > +++ b/arch/arm64/kvm/vgic/vgic.c
> > @@ -547,7 +547,14 @@ int kvm_vgic_inject_irq(struct kvm *kvm,
> > struct kvm_vcpu *vcpu,
> > ?	else
> > ?		irq->pending_latch = true;
> > ?
> > -	vgic_queue_irq_unlock(kvm, irq, flags);
> > +	if (irq->ops && irq->ops->set_pending_state)
> > +		WARN_ON_ONCE(!irq->ops->set_pending_state(vcpu,
> > irq));
> > +
> > +	if (irq->ops && irq->ops->queue_irq_unlock)
> > +		WARN_ON_ONCE(!irq->ops->queue_irq_unlock(kvm, irq,
> > flags));
> > +	else
> > +		vgic_queue_irq_unlock(kvm, irq, flags);
> 
> I find it slightly dubious to WARN() in one case but not the other.

Yeah, noted. That goes away as I have...

> 
> More importantly, why isn't the per-irq queue_unlock operation tucked
> into the vgic_queue_irq_unlock() primitive? We have 16 call sites for
> this function, and it is odd that only the injection primitive would
> benefit from this.

...now tucked this into vgic_queue_irq_unlock() as you suggest. You're
quite right in that it should be a more general thing, and it is broken
otherwise.

Thanks,
Sascha

> 
> Thanks,
> 
> 	M.
> 


From Sascha.Bischoff at arm.com  Wed Dec 17 13:10:11 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Wed, 17 Dec 2025 21:10:11 +0000
Subject: [PATCH 17/32] KVM: arm64: gic-v5: Implement PPI interrupt
 injection
In-Reply-To: <864ippo0tf.wl-maz@kernel.org>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	 <20251212152215.675767-18-sascha.bischoff@arm.com>
	 <864ippo0tf.wl-maz@kernel.org>
Message-ID: <f5da546092337838fa7624ff405cbb14a08205c0.camel@arm.com>

On Wed, 2025-12-17 at 10:33 +0000, Marc Zyngier wrote:
> On Fri, 12 Dec 2025 15:22:41 +0000,
> Sascha Bischoff <Sascha.Bischoff at arm.com> wrote:
> > 
> > This change introduces interrupt injection for PPIs for GICv5-based
> > guests.
> > 
> > The lifecycle of PPIs is largely managed by the hardware for a
> > GICv5
> > system. The hypervisor injects pending state into the guest by
> > using
> > the ICH_PPI_PENDRx_EL2 registers. These are used by the hardware to
> > pick a Highest Priority Pending Interrupt (HPPI) for the guest
> > based
> > on the enable state of each individual interrupt. The enable state
> > and
> > priority for each interrupt are provided by the guest itself
> > (through
> > writes to the PPI registers).
> > 
> > When Direct Virtual Interrupt (DVI) is set for a particular PPI,
> > the
> > hypervisor is even able to skip the injection of the pending state
> > altogether - it all happens in hardware.
> > 
> > The result of the above is that no AP lists are required for GICv5,
> > unlike for older GICs. Instead, for PPIs the ICH_PPI_* registers
> > fulfil the same purpose for all 128 PPIs. Hence, as long as the
> > ICH_PPI_* registers are populated prior to guest entry, and merged
> > back into the KVM shadow state on exit, the PPI state is preserved,
> > and interrupts can be injected.
> > 
> > When injecting the state of a PPI the state is merged into the
> > KVM's
> > shadow state using the set_pending_state irq_op. The directly sets
> > the
> > relevant bit in the shadow ICH_PPI_PENDRx_EL2, which is presented
> > to
> > the guest (and GICv5 hardware) on next guest entry. The
> > queue_irq_unlock irq_op is required to kick the vCPU to ensure that
> > it
> > seems the new state. The result is that no AP lists are used for
> > private interrupts on GICv5.
> > 
> > Prior to entering the guest, vgic_v5_flush_ppi_state is called from
> > kvm_vgic_flush_hwstate. The effectively snapshots the shadow PPI
> > pending state (twice - an entry and an exit copy) in order to track
> > any changes. These changes can come from a guest consuming an
> > interrupt or from a guest making an Edge-triggered interrupt
> > pending.
> > 
> > When returning from running a guest, the guest's PPI state is
> > merged
> > back into KVM's shadow state in vgic_v5_merge_ppi_state from
> > kvm_vgic_sync_hwstate. The Enable and Active state is synced back
> > for
> > all PPIs, and the pending state is synced back for Edge PPIs (Level
> > is
> > driven directly by the devices generating said levels). The
> > incoming
> > pending state from the guest is merged with KVM's shadow state to
> > avoid losing any incoming interrupts.
> > 
> > Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
> > ---
> > ?arch/arm64/kvm/vgic/vgic-v5.c | 157
> > ++++++++++++++++++++++++++++++++++
> > ?arch/arm64/kvm/vgic/vgic.c??? |? 35 ++++++--
> > ?arch/arm64/kvm/vgic/vgic.h??? |? 49 ++++++++---
> > ?include/kvm/arm_vgic.h??????? |?? 3 +
> > ?4 files changed, 226 insertions(+), 18 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/vgic/vgic-v5.c
> > b/arch/arm64/kvm/vgic/vgic-v5.c
> > index 22558080711eb..d54595fbf4586 100644
> > --- a/arch/arm64/kvm/vgic/vgic-v5.c
> > +++ b/arch/arm64/kvm/vgic/vgic-v5.c
> > @@ -54,6 +54,163 @@ int vgic_v5_probe(const struct gic_kvm_info
> > *info)
> > ?	return 0;
> > ?}
> > ?
> > +static bool vgic_v5_ppi_set_pending_state(struct kvm_vcpu *vcpu,
> > +					? struct vgic_irq *irq)
> > +{
> > +	struct vgic_v5_cpu_if *cpu_if;
> > +	const u32 id_bit = BIT_ULL(irq->intid % 64);
> 
> Try that with intid==32...

Fixed!

> 
> > +	const u32 reg = FIELD_GET(GICV5_HWIRQ_ID, irq->intid) /
> > 64;
> > +
> > +	if (!vcpu || !irq)
> > +		return false;
> > +
> > +	/* Skip injecting the state altogether */
> > +	if (irq->directly_injected)
> > +		return true;
> 
> It is unclear to me under which circumstances we could end-up here.
> Wouldn't that be a bug?

I guess that depends on how GICv5-aware we want things like the Arch
Timer to be. To address your first point, this has been encountered via
the kvm_timer_update_irq() path, whereby the Arch Timer injects the
current state as part of kvm_timer_vcpu_load_gic().

There are two obvious options here IMO:

1. Skip the injection in the Arch Timer for a GICv5-based guest, or
2. Skip it deeper into the vgic_v5 code to minimise the impact to other
parts of the code line (what I did here).

We already need to handle some special cases in the Arch Timer code for
different GICs, so I guess that adding one more wouldn't be too
controversial? 

> 
> > +
> > +	cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> > +
> > +	if (irq_is_pending(irq))
> > +		cpu_if->vgic_ppi_pendr[reg] |= id_bit;
> > +	else
> > +		cpu_if->vgic_ppi_pendr[reg] &= ~id_bit;
> > +
> > +	return true;
> > +}
> > +
> > +/*
> > + * For GICv5, the PPIs are mostly directly managed by the
> > hardware. We
> > + * (the hypervisor) handle the pending, active, enable state
> > + * save/restore, but don't need the PPIs to be queued on a per-
> > VCPU AP
> > + * list. Therefore, sanity check the state, unlock, and return.
> > + */
> > +static bool vgic_v5_ppi_queue_irq_unlock(struct kvm *kvm, struct
> > vgic_irq *irq,
> > +					 unsigned long flags)
> > +	__releases(&irq->irq_lock)
> > +{
> > +	struct kvm_vcpu *vcpu;
> > +
> > +	lockdep_assert_held(&irq->irq_lock);
> > +
> > +	if (WARN_ON_ONCE(!irq_is_ppi_v5(irq->intid)))
> > +		return false;
> > +
> > +	vcpu = irq->target_vcpu;
> > +	if (WARN_ON_ONCE(!vcpu))
> > +		return false;
> 
> Errr... You're returning with the lock held, making a bad bug even
> worse!

Have rejigged things to avoid that for both of those returns!

> 
> > +
> > +	raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
> > +
> > +	/* Directly kick the target VCPU to make sure it sees the
> > IRQ */
> > +	kvm_make_request(KVM_REQ_IRQ_PENDING, vcpu);
> > +	kvm_vcpu_kick(vcpu);
> > +
> > +	return true;
> > +}
> > +
> > +static struct irq_ops vgic_v5_ppi_irq_ops = {
> > +	.set_pending_state = vgic_v5_ppi_set_pending_state,
> > +	.queue_irq_unlock = vgic_v5_ppi_queue_irq_unlock,
> > +};
> > +
> > +void vgic_v5_set_ppi_ops(struct vgic_irq *irq)
> > +{
> > +	if (WARN_ON(!irq) || WARN_ON(irq->ops))
> > +		return;
> > +
> > +	irq->ops = &vgic_v5_ppi_irq_ops;
> 
> Is there any locking requirement here?

Hmm, there probably should be. Right now, this is called from
vgic_allocate_private_irqs_locked(), onyl, which has the
arch.config_lock, but doesn't take any per-irq locks as it is creating
them.

I think that the most correct thing to do is to explicitly lock each
IRQ while we change the ops (scoped_guard()). It is slow, but not on
the critical path (unlike what you've pointed out for the PPI locking
elsewhere). That at least allows this to be re-used from a more generic
context if ever required.

> 
> > +}
> > +
> > +/*
> > + * Detect any PPIs state changes, and propagate the state with
> > KVM's
> > + * shadow structures.
> > + */
> > +static void vgic_v5_merge_ppi_state(struct kvm_vcpu *vcpu)
> 
> Since this is only called from vgic_v5_fold_irq_state(), do yourself
> a
> favour and call it that.

Done. This is an artifact of the changes yet to be posted, but for this
series that's unhelpful.

> 
> > +{
> > +	struct vgic_v5_cpu_if *cpu_if = &vcpu-
> > >arch.vgic_cpu.vgic_v5;
> > +	unsigned long flags;
> > +	int i, reg;
> > +
> > +	for (reg = 0; reg < 2; reg++) {
> > +		unsigned long changed_bits;
> > +		const unsigned long enabler = cpu_if-
> > >vgic_ich_ppi_enabler_exit[reg];
> > +		const unsigned long activer = cpu_if-
> > >vgic_ppi_activer_exit[reg];
> > +		const unsigned long pendr = cpu_if-
> > >vgic_ppi_pendr_exit[reg];
> > +
> > +		/*
> > +		 * Track what changed across enabler, activer,
> > pendr, but mask
> > +		 * with ~DVI.
> > +		 */
> > +		changed_bits = cpu_if-
> > >vgic_ich_ppi_enabler_entry[reg] ^ enabler;
> > +		changed_bits |= cpu_if-
> > >vgic_ppi_activer_entry[reg] ^ activer;
> > +		changed_bits |= cpu_if->vgic_ppi_pendr_entry[reg]
> > ^ pendr;
> > +		changed_bits &= ~cpu_if->vgic_ppi_dvir[reg];
> > +
> > +		for_each_set_bit(i, &changed_bits, 64) {
> > +			struct vgic_irq *irq;
> > +			u32 intid;
> > +
> > +			intid = FIELD_PREP(GICV5_HWIRQ_TYPE,
> > GICV5_HWIRQ_TYPE_PPI);
> > +			intid |= FIELD_PREP(GICV5_HWIRQ_ID, reg *
> > 64 + i);
> > +
> > +			irq = vgic_get_vcpu_irq(vcpu, intid);
> > +
> > +			raw_spin_lock_irqsave(&irq->irq_lock,
> > flags);
> 
> Consider using a scoped_guard() for this.

Done.

> 
> > +			irq->enabled = !!(enabler & BIT(i));
> > +			irq->active = !!(activer & BIT(i));
> > +			/* This is an OR to avoid losing incoming
> > edges! */
> > +			if (irq->config == VGIC_CONFIG_EDGE)
> > +				irq->pending_latch |= !!(pendr &
> > BIT(i));
> > +			raw_spin_unlock_irqrestore(&irq->irq_lock,
> > flags);
> > +
> > +			vgic_put_irq(vcpu->kvm, irq);
> > +		}
> > +
> > +		/* Re-inject the exit state as entry state next
> > time! */
> > +		cpu_if->vgic_ich_ppi_enabler_entry[reg] = enabler;
> > +		cpu_if->vgic_ppi_activer_entry[reg] = activer;
> > +
> > +		/*
> > +		 * Pending state is a bit different. We only
> > propagate back
> > +		 * pending state for Edge interrupts. Moreover,
> > this is OR'd
> > +		 * with the incoming state to make sure we don't
> > lose incoming
> > +		 * edges. Use the (inverse) HMR to mask off all
> > Level bits, and
> > +		 * OR.
> > +		 */
> > +		cpu_if->vgic_ppi_pendr[reg] |= pendr & ~cpu_if-
> > >vgic_ppi_hmr[reg];
> > +	}
> > +}
> > +
> > +void vgic_v5_flush_ppi_state(struct kvm_vcpu *vcpu)
> > +{
> > +	struct vgic_v5_cpu_if *cpu_if = &vcpu-
> > >arch.vgic_cpu.vgic_v5;
> > +
> > +	/*
> > +	 * We're about to enter the guest. Copy the shadow state
> > to the pending
> > +	 * reg that will be written to the ICH_PPI_PENDRx_EL2
> > regs. While the
> > +	 * guest is running we track any incoming changes to the
> > pending state in
> > +	 * vgic_ppi_pendr. The incoming changes are merged with
> > the outgoing
> > +	 * changes on the return path.
> > +	 */
> > +	cpu_if->vgic_ppi_pendr_entry[0] = cpu_if-
> > >vgic_ppi_pendr[0];
> > +	cpu_if->vgic_ppi_pendr_entry[1] = cpu_if-
> > >vgic_ppi_pendr[1];
> > +
> > +	/*
> > +	 * Make sure that we can correctly detect "edges" in the
> > PPI
> > +	 * state. There's a path where we never actually enter the
> > guest, and
> > +	 * failure to do this risks losing pending state
> > +	 */
> > +	cpu_if->vgic_ppi_pendr_exit[0] = cpu_if-
> > >vgic_ppi_pendr[0];
> > +	cpu_if->vgic_ppi_pendr_exit[1] = cpu_if-
> > >vgic_ppi_pendr[1];
> 
> I find it a bit objectionable that this entry/exit stuff is kept on a
> per vcpu basis. Given that we cannot be preempted between flush and
> fold, the intermediate bookkeeping should probably live in a per-CPU
> structure.

OK, I shall try and re-work this for v2.

> 
> > +
> > +}
> > +
> > +void vgic_v5_fold_irq_state(struct kvm_vcpu *vcpu)
> > +{
> > +	/* Sync back the guest PPI state to the KVM shadow state
> > */
> > +	vgic_v5_merge_ppi_state(vcpu);
> > +}
> > +
> > ?/*
> > ? * Sets/clears the corresponding bit in the ICH_PPI_DVIR register.
> > ? */
> > diff --git a/arch/arm64/kvm/vgic/vgic.c
> > b/arch/arm64/kvm/vgic/vgic.c
> > index fc01c6d07fe62..e534876656ca7 100644
> > --- a/arch/arm64/kvm/vgic/vgic.c
> > +++ b/arch/arm64/kvm/vgic/vgic.c
> > @@ -105,6 +105,15 @@ struct vgic_irq *vgic_get_vcpu_irq(struct
> > kvm_vcpu *vcpu, u32 intid)
> > ?	if (WARN_ON(!vcpu))
> > ?		return NULL;
> > ?
> > +	if (vcpu->kvm->arch.vgic.vgic_model ==
> > KVM_DEV_TYPE_ARM_VGIC_V5) {
> > +		u32 int_num = FIELD_GET(GICV5_HWIRQ_ID, intid);
> > +
> > +		if (irq_is_ppi_v5(intid)) {
> > +			int_num = array_index_nospec(int_num,
> > VGIC_V5_NR_PRIVATE_IRQS);
> > +			return &vcpu-
> > >arch.vgic_cpu.private_irqs[int_num];
> > +		}
> > +	}
> > +
> > ?	/* SGIs and PPIs */
> > ?	if (intid < VGIC_NR_PRIVATE_IRQS) {
> > ?		intid = array_index_nospec(intid,
> > VGIC_NR_PRIVATE_IRQS);
> > @@ -258,10 +267,12 @@ struct kvm_vcpu *vgic_target_oracle(struct
> > vgic_irq *irq)
> > ?	 * If the distributor is disabled, pending interrupts
> > shouldn't be
> > ?	 * forwarded.
> > ?	 */
> > -	if (irq->enabled && irq_is_pending(irq)) {
> > -		if (unlikely(irq->target_vcpu &&
> > -			???? !irq->target_vcpu->kvm-
> > >arch.vgic.enabled))
> > -			return NULL;
> > +	if (irq_is_enabled(irq) && irq_is_pending(irq)) {
> > +		if (irq->target_vcpu) {
> > +			if (!vgic_is_v5(irq->target_vcpu->kvm) &&
> > +			??? unlikely(!irq->target_vcpu->kvm-
> > >arch.vgic.enabled))
> > +				return NULL;
> > +		}
> > ?
> > ?		return irq->target_vcpu;
> > ?	}
> > @@ -1044,7 +1055,11 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu
> > *vcpu)
> > ?	if (can_access_vgic_from_kernel())
> > ?		vgic_save_state(vcpu);
> > ?
> > -	vgic_fold_lr_state(vcpu);
> > +	if (!vgic_is_v5(vcpu->kvm))
> > +		vgic_fold_lr_state(vcpu);
> > +	else
> > +		vgic_v5_fold_irq_state(vcpu);
> > +
> 
> This is gross. We already have this:
> 
> static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
> {
> 	if (kvm_vgic_global_state.type == VGIC_V2)
> 		vgic_v2_fold_lr_state(vcpu);
> 	else
> 		vgic_v3_fold_lr_state(vcpu);
> }
> 
> Rename it to vgic_fold_state(), drop the inline, make it a switch(),
> and hook the v5 stuff in it.

Will do, but a switch doesn't quite work. The logic is a combination of
host global_state (GICv2, GICv3, GICv5) and vgic_model (vgic_v2_,
vgic_v3, vgic_v5) which has some overlap. Alas the logic effectively
becomes:

static void vgic_fold_state(struct kvm_vcpu *vcpu)
{
        if (vgic_is_v5(vcpu->kvm)) /* GICv5 native */
                vgic_v5_fold_ppi_state(vcpu);
        else if(kvm_vgic_global_state.type == VGIC_V2) /* GICv2 native
*/
                vgic_v2_fold_lr_state(vcpu);
        else /* GICv3 native or GICv2-on-GICv3 or GICv3-on-GICv5 */
                vgic_v3_fold_lr_state(vcpu);
}

Please do correct me if I am misunderstanding the GICv2/GICv3 side of
things there, but the fact that v2-on-v3 and v5-on-v3 work differently
makes this sort of logic quite meh.

> 
> > ?	vgic_prune_ap_list(vcpu);
> 
> Are you actually pruning the ap_list() on v5? What is there the first
> place?

There's nothing to do for GICv5. It isn't harmful to call it as it
won't do anything, but it is of course slow. I've added a check to skip
it for vgic_v5. Let me know if you've prefer me to check in
vgic_prune_ap_list() itself.

> 
> > ?}
> > ?
> > @@ -1105,13 +1120,17 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu
> > *vcpu)
> > ?
> > ?	DEBUG_SPINLOCK_BUG_ON(!irqs_disabled());
> > ?
> > -	scoped_guard(raw_spinlock, &vcpu-
> > >arch.vgic_cpu.ap_list_lock)
> > -		vgic_flush_lr_state(vcpu);
> > +	if (!vgic_is_v5(vcpu->kvm)) {
> > +		scoped_guard(raw_spinlock, &vcpu-
> > >arch.vgic_cpu.ap_list_lock)
> > +			vgic_flush_lr_state(vcpu);
> > +	} else {
> > +		vgic_v5_flush_ppi_state(vcpu);
> > +	}
> 
> Same thing here. Move everything into the common helper, including
> the
> lock management.

Have moved these to a common helper.

> 
> > ?
> > ?	if (can_access_vgic_from_kernel())
> > ?		vgic_restore_state(vcpu);
> > ?
> > -	if (vgic_supports_direct_irqs(vcpu->kvm))
> > +	if (vgic_supports_direct_irqs(vcpu->kvm) &&
> > !vgic_is_v5(vcpu->kvm))
> > ?		vgic_v4_commit(vcpu);
> 
> nit: swap the two terms of the conjunction, making it more readable
> (for me...). Or move the conditions into vgic_v4_commit().

Done (the former).

> 
> > ?}
> > ?
> > diff --git a/arch/arm64/kvm/vgic/vgic.h
> > b/arch/arm64/kvm/vgic/vgic.h
> > index b6e3f5e3aba18..5a77318ddb87a 100644
> > --- a/arch/arm64/kvm/vgic/vgic.h
> > +++ b/arch/arm64/kvm/vgic/vgic.h
> > @@ -132,6 +132,28 @@ static inline bool irq_is_pending(struct
> > vgic_irq *irq)
> > ?		return irq->pending_latch || irq->line_level;
> > ?}
> > ?
> > +/* Requires the irq_lock to be held by the caller. */
> > +static inline bool irq_is_enabled(struct vgic_irq *irq)
> > +{
> > +	if (irq->enabled)
> > +		return true;
> > +
> > +	/*
> > +	 * We always consider GICv5 interrupts as enabled as we
> > can
> > +	 * always inject them. The state is handled by the
> > hardware,
> > +	 * and the hardware will only signal the interrupt to the
> > +	 * guest once the guest enables it.
> > +	 */
> > +	if (irq->target_vcpu) {
> 
> Under which circumstances is target_vcpu NULL for PPIs?

It never should be with a PPI. Other interrupts types, however, might
have a NULL target_vcpu, and this is common code to all vgics. It is a
poor attempt at avoiding a null pointer.

Effectively, for GICv5 we can consider all interrupts enabled from an
injection point of view - we can always inject interrupt state. The
guest won't see it unless it has enabled the interrupt.

This definitely does need some re-working - I don't like it. I think
the main issue is that it (and I) am somewhat conflating the ability to
inject new interrupt state with the guest's enable state.

I'm more than open to ideas here (see below about potentially adding a
struct kvm* to struct vgic_irq).
 
> 
> > +		u32 vgic_model = irq->target_vcpu->kvm-
> > >arch.vgic.vgic_model;
> > +
> > +		if (vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5)
> > +			return true;
> > +	}
> > +
> > +	return false;
> > +}
> > +
> > ?static inline bool vgic_irq_is_mapped_level(struct vgic_irq *irq)
> > ?{
> > ?	return irq->config == VGIC_CONFIG_LEVEL && irq->hw;
> > @@ -306,7 +328,7 @@ static inline bool vgic_try_get_irq_ref(struct
> > vgic_irq *irq)
> > ?	if (!irq)
> > ?		return false;
> > ?
> > -	if (irq->intid < VGIC_MIN_LPI)
> > +	if (irq->target_vcpu && !irq_is_lpi(irq->target_vcpu->kvm,
> > irq->intid))
> > ?		return true;
> 
> This change is rather obscure, and doesn't do what you think it does.
> 
> What has target_vcpu to do with anything? For example, a GICv3 SPI
> that has its target_vcpu set to NULL (just point its IROUTER register
> to a non-existent vcpu) would end-up using the refcount path,
> something that isn't expected at all.
> 
> You should make clear what the refcounting rules are for GICv5, and
> use that, instead of using odd side-effects.

This stems from trying to figure out the interrupt type here, which
changes based on vgic. I I'm thinking that a more sane way to handle
this and the above enable issues is to have an explicit struct kvm *kvm
in struct vgic_irq.

Absolutely agreed that I've broken what I don't understand with this
change. Thanks for catching it.

Thanks,
Sascha

> 
> > ?
> > ?	return refcount_inc_not_zero(&irq->refcount);
> > @@ -363,7 +385,10 @@ void vgic_debug_init(struct kvm *kvm);
> > ?void vgic_debug_destroy(struct kvm *kvm);
> > ?
> > ?int vgic_v5_probe(const struct gic_kvm_info *info);
> > +void vgic_v5_set_ppi_ops(struct vgic_irq *irq);
> > ?int vgic_v5_set_ppi_dvi(struct kvm_vcpu *vcpu, u32 irq, bool dvi);
> > +void vgic_v5_flush_ppi_state(struct kvm_vcpu *vcpu);
> > +void vgic_v5_fold_irq_state(struct kvm_vcpu *vcpu);
> > ?void vgic_v5_load(struct kvm_vcpu *vcpu);
> > ?void vgic_v5_put(struct kvm_vcpu *vcpu);
> > ?void vgic_v5_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr
> > *vmcr);
> > @@ -432,15 +457,6 @@ void vgic_its_invalidate_all_caches(struct kvm
> > *kvm);
> > ?int vgic_its_inv_lpi(struct kvm *kvm, struct vgic_irq *irq);
> > ?int vgic_its_invall(struct kvm_vcpu *vcpu);
> > ?
> > -bool system_supports_direct_sgis(void);
> > -bool vgic_supports_direct_msis(struct kvm *kvm);
> > -bool vgic_supports_direct_sgis(struct kvm *kvm);
> > -
> > -static inline bool vgic_supports_direct_irqs(struct kvm *kvm)
> > -{
> > -	return vgic_supports_direct_msis(kvm) ||
> > vgic_supports_direct_sgis(kvm);
> > -}
> > -
> > ?int vgic_v4_init(struct kvm *kvm);
> > ?void vgic_v4_teardown(struct kvm *kvm);
> > ?void vgic_v4_configure_vsgis(struct kvm *kvm);
> > @@ -485,6 +501,19 @@ static inline bool vgic_is_v5(struct kvm *kvm)
> > ?	return kvm_vgic_global_state.type == VGIC_V5 &&
> > !vgic_is_v3_compat(kvm);
> > ?}
> > ?
> > +bool system_supports_direct_sgis(void);
> > +bool vgic_supports_direct_msis(struct kvm *kvm);
> > +bool vgic_supports_direct_sgis(struct kvm *kvm);
> > +
> > +static inline bool vgic_supports_direct_irqs(struct kvm *kvm)
> > +{
> > +	/* GICv5 always supports direct IRQs */
> > +	if (vgic_is_v5(kvm))
> > +		return true;
> > +
> > +	return vgic_supports_direct_msis(kvm) ||
> > vgic_supports_direct_sgis(kvm);
> > +}
> > +
> > ?int vgic_its_debug_init(struct kvm_device *dev);
> > ?void vgic_its_debug_destroy(struct kvm_device *dev);
> > ?
> > diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> > index 20c908730fa00..5a46fe3c35b5c 100644
> > --- a/include/kvm/arm_vgic.h
> > +++ b/include/kvm/arm_vgic.h
> > @@ -32,6 +32,9 @@
> > ?#define VGIC_MIN_LPI		8192
> > ?#define KVM_IRQCHIP_NUM_PINS	(1020 - 32)
> > ?
> > +/* GICv5 constants */
> > +#define VGIC_V5_NR_PRIVATE_IRQS	128
> > +
> > ?#define irq_is_ppi_legacy(irq) ((irq) >= VGIC_NR_SGIS && (irq) <
> > VGIC_NR_PRIVATE_IRQS)
> > ?#define irq_is_spi_legacy(irq) ((irq) >= VGIC_NR_PRIVATE_IRQS && \
> > ?					(irq) <= VGIC_MAX_SPI)
> 
> Thanks,
> 
> 	M.
> 


From yonghong.song at linux.dev  Wed Dec 17 13:31:58 2025
From: yonghong.song at linux.dev (Yonghong Song)
Date: Wed, 17 Dec 2025 13:31:58 -0800
Subject: [PATCH bpf-next 2/2] bpf: arm64: Optimize recursion detection by
 not using atomics
In-Reply-To: <CANk7y0jNj0SDOBr=3n_0jhQbLzaj--yVUF4oDA-ManQG-=bkhw@mail.gmail.com>
References: <20251217162830.2597286-3-puranjay@kernel.org>
 <f144fd46b602b74fc4c1c2664082fbe893e7ec9c274fcc5fdf13d65151749e9c@mail.kernel.org>
 <CANk7y0h4JO2-tp9HjRHjcQdTOgmRSsw0rxmK-=G89AVY92U8Jw@mail.gmail.com>
 <CAADnVQ+E6Tgcf1E5x-wk_TA+Lz83cA=SL8EZUGL70bQpywwexg@mail.gmail.com>
 <CANk7y0jNj0SDOBr=3n_0jhQbLzaj--yVUF4oDA-ManQG-=bkhw@mail.gmail.com>
Message-ID: <a0c04178-2159-4475-9be8-93320ffc2138@linux.dev>



On 12/17/25 10:56 AM, Puranjay Mohan wrote:
> On Wed, Dec 17, 2025 at 6:46?PM Alexei Starovoitov
> <alexei.starovoitov at gmail.com> wrote:
>> On Wed, Dec 17, 2025 at 10:13?AM Puranjay Mohan <puranjay at kernel.org> wrote:
>>> On Wed, Dec 17, 2025 at 4:56?PM <bot+bpf-ci at kernel.org> wrote:
>>>>> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
>>>>> index 2da986136d26..654fb94bf60c 100644
>>>>> --- a/include/linux/bpf.h
>>>>> +++ b/include/linux/bpf.h
>>>> [ ... ]
>>>>
>>>>> @@ -2006,12 +2009,32 @@ struct bpf_struct_ops_common_value {
>>>>>
>>>>>   static inline bool bpf_prog_get_recursion_context(struct bpf_prog *prog)
>>>>>   {
>>>>> +#ifdef CONFIG_ARM64
>>>>> +     u8 rctx = interrupt_context_level();
>>>>> +     u8 *active = this_cpu_ptr(prog->active);
>>>>> +
>>>>> +     active[rctx]++;
>>>>> +     barrier();
>>>>> +     if (get_unaligned_le32(active) != BIT(rctx * 8))
>>>>> +             return false;
>>>>> +
>>>>> +     return true;
>>>>> +#else
>>>>>        return this_cpu_inc_return(*(prog->active)) == 1;
>>>>> +#endif
>>>>>   }
>>>> Can preemption between the increment and check cause a counter leak on
>>>> CONFIG_PREEMPT_RCU systems? The trampoline calls this function under
>>>> rcu_read_lock_dont_migrate() which allows preemption on PREEMPT_RCU
>>>> (documented at include/linux/rcupdate.h:856).
>>>>
>>>> Consider this scenario on an ARM64 system with PREEMPT_RCU:
>>>>
>>>> 1. Thread A increments active[0] to 1
>>>> 2. Preemption occurs before Thread A reaches the check
>>>> 3. Thread B on same CPU increments active[0] to 2
>>>> 4. Thread B checks: sees 2 != BIT(0), returns false
>>>> 5. Thread A resumes, checks: sees 2 != BIT(0), returns false
>>>> 6. Both threads return false, neither runs BPF
>>>> 7. Neither calls bpf_prog_put_recursion_context() (see
>>>>     __bpf_prog_enter_recur() at kernel/bpf/trampoline.c:952)
>>>> 8. Counter permanently stuck at 2, all future BPF on this CPU fails
>>> Step 7 is incorrect. Looking at the JIT-generated code, the exit
>>> function is ALWAYS called, regardless of whether the enter function
>>> returns 0 or a start time:
>>>
>>>    // x86 JIT at arch/x86/net/bpf_jit_comp.c:2998-3050
>>>    call bpf_trampoline_enter()    // Line 2998
>>>    test rax, rax                   // Line 3006
>>>    je skip_exec                    // Conditional jump
>>>    ... BPF program execution ...   // Lines 3011-3023
>>>    skip_exec:                      // Line 3037 (jump lands here)
>>>    call bpf_trampoline_exit()      // Line 3049 - ALWAYS executed
>>>
>>>    The bpf_trampoline_exit() call is after the skip_exec label, so it
>>> executes in both cases.
>>>
>>> What Actually Happens:
>>>
>>>    Initial state: active[0] = 0
>>>
>>>    Thread A (normal context, rctx=0):
>>>    1. active[0]++ ? active[0] = 1
>>>    2. Preempted before barrier()
>>>
>>>    Thread B (scheduled on same CPU, normal context, rctx=0):
>>>    3. active[0]++ ? active[0] = 2
>>>    4. barrier()
>>>    5. get_unaligned_le32(active) ? reads 0x00000002
>>>    6. Check: 0x00000002 != BIT(0) = 0x00000001 ? returns false
>>>    7. __bpf_prog_enter_recur returns 0
>>>    8. JIT checks return value, skips BPF execution
>>>    9. JIT ALWAYS calls __bpf_prog_exit_recur (see
>>> arch/arm64/net/bpf_jit_comp.c:2362)
>>>    10. bpf_prog_put_recursion_context(prog) executes
>>>    11. barrier(), active[0]-- ? active[0] = 1
>>>
>>>    Thread A resumes:
>>>    12. barrier()
>>>    13. get_unaligned_le32(active) ? reads 0x00000001 (Thread B already
>>> decremented!)
>>>    14. Check: 0x00000001 == BIT(0) = 0x00000001 ? returns true ?
>>>    15. __bpf_prog_enter_recur returns start_time
>>>    16. BPF program executes
>>>    17. __bpf_prog_exit_recur called
>>>    18. bpf_prog_put_recursion_context(prog) executes
>>>    19. barrier(), active[0]-- ? active[0] = 0 ?
>>>
>>>    Final State
>>>
>>>    - Counter returns to 0 ?
>>>    - No leak ?
>>>    - Thread B detected interference and aborted ?
>>>    - Thread A executed successfully ?
>>>    - Only ONE thread executed the BPF program ?
>>>
>>>
>>> Now that I think of it, there is another race condition that leads to
>>> NEITHER program running:
>>>
>>> Consider this scenario on an arm64 system with PREEMPT_RCU:
>>>
>>> 1. Thread A increments active[0] from 0 to 1
>>> 2. Thread A is preempted before reaching barrier()
>>> 3. Thread B (same CPU, same context) increments active[0] from 1 to 2
>>> 4. Thread B executes barrier() and checks: sees 2 != BIT(0), returns false
>>> 5. Thread A resumes, executes barrier() and checks: sees 2 != BIT(0),
>>> returns false
>>> 6. Both threads return false to __bpf_prog_enter_recur()
>>> 7. Both skip BPF program execution
>>> 8. Both call bpf_prog_put_recursion_context() and decrement: 2->1->0
>>> 9. Neither BPF program executes, but the counter correctly returns to 0
>>>
>>> This means the patch is changing the behaviour in case of recursion
>>> from "One program gets to run" to
>>> "At most one program gets to run", but given the performance benefits,
>>> I think we can accept this change.
>> Agree. It's fine, but we can mitigate it, but doing this rctx trick
>> only when RCU is not preemptable. Which pretty much would mean
>> that PREEMPT_RT will use atomic and !RT will use rctx
>> and this 'no prog executes' will not happen.
>
> The issue is also with sleepable programs, they use
> rcu_read_lock_trace() and can end up with
> 'no prog executes' scenario.
>
> What do you think is the best approach for them?

For sleepable programs, maybe we can use the original approach like
   return this_cpu_inc_return(*(prog->active)) == 1;
?
This should solve the 'no prog execution' issue.




From Sascha.Bischoff at arm.com  Wed Dec 17 13:42:51 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Wed, 17 Dec 2025 21:42:51 +0000
Subject: [PATCH 13/32] KVM: arm64: gic-v5: Add vgic-v5 save/restore hyp
 interface
In-Reply-To: <863459nz8n.wl-maz@kernel.org>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	 <20251212152215.675767-14-sascha.bischoff@arm.com>
	 <863459nz8n.wl-maz@kernel.org>
Message-ID: <060952cae62cb09a16c46f6881c046a2170e8375.camel@arm.com>

On Wed, 2025-12-17 at 11:07 +0000, Marc Zyngier wrote:
> On Fri, 12 Dec 2025 15:22:39 +0000,
> Sascha Bischoff <Sascha.Bischoff at arm.com> wrote:
> > 
> > Introduce hyp functions to save/restore the following GICv5 state:
> > 
> > * ICC_ICSR_EL1
> > * ICH_APR_EL2
> > * ICH_PPI_ACTIVERx_EL2
> > * ICH_PPI_DVIRx_EL2
> > * ICH_PPI_ENABLERx_EL2
> > * ICH_PPI_PENDRRx_EL2
> > * ICH_PPI_PRIORITYRx_EL2
> > * ICH_VMCR_EL2
> > 
> > All of these are saved/restored to/from the KVM vgic_v5 CPUIF
> > shadow
> > state.
> > 
> > The ICSR must be save/restored as this register is shared between
> > host
> > and guest. Therefore, to avoid leaking host state to the guest,
> > this
> > must be saved and restored. Moreover, as this can by used by the
> > host
> > at any time, it must be save/restored eagerly. Note: the host state
> > is
> > not preserved as the host should only use this register when
> > preemption is disabled.
> > 
> > As part of restoring the ICH_VMCR_EL2 and ICH_APR_EL2, GICv3-compat
> > mode is also disabled by setting the ICH_VCTLR_EL2.V3 bit to 0. The
> > correspoinding GICv3-compat mode enable is part of the VMCR & APR
> > restore for a GICv3 guest as it only takes effect when actually
> > running a guest.
> > 
> > Co-authored-by: Timothy Hayes <timothy.hayes at arm.com>
> > Signed-off-by: Timothy Hayes <timothy.hayes at arm.com>
> > Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
> > ---
> > ?arch/arm64/include/asm/kvm_asm.h?? |?? 4 +
> > ?arch/arm64/include/asm/kvm_hyp.h?? |?? 8 ++
> > ?arch/arm64/kvm/hyp/nvhe/Makefile?? |?? 2 +-
> > ?arch/arm64/kvm/hyp/nvhe/hyp-main.c |? 32 ++++++
> > ?arch/arm64/kvm/hyp/vgic-v5.c?????? | 155
> > +++++++++++++++++++++++++++++
> > ?arch/arm64/kvm/hyp/vhe/Makefile??? |?? 2 +-
> > ?include/kvm/arm_vgic.h???????????? |? 28 ++++++
> > ?7 files changed, 229 insertions(+), 2 deletions(-)
> > ?create mode 100644 arch/arm64/kvm/hyp/vgic-v5.c
> > 
> > diff --git a/arch/arm64/include/asm/kvm_asm.h
> > b/arch/arm64/include/asm/kvm_asm.h
> > index a1ad12c72ebf1..5f669299fb956 100644
> > --- a/arch/arm64/include/asm/kvm_asm.h
> > +++ b/arch/arm64/include/asm/kvm_asm.h
> > @@ -89,6 +89,10 @@ enum __kvm_host_smccc_func {
> > ?	__KVM_HOST_SMCCC_FUNC___pkvm_vcpu_load,
> > ?	__KVM_HOST_SMCCC_FUNC___pkvm_vcpu_put,
> > ?	__KVM_HOST_SMCCC_FUNC___pkvm_tlb_flush_vmid,
> > +	__KVM_HOST_SMCCC_FUNC___vgic_v5_save_vmcr_aprs,
> 
> As we recently found out with v2/v3, delaying saving VMCR (and
> therefore lobbing it with the APRs) is a bad idea if you need to look
> at it from inside the run loop.
> 
> In general, please align the behaviour with the existing
> infrastructure as often as possible. We can always optimise things
> later once GICv5 becomes relevant.

Done, and noted!


> > +	__KVM_HOST_SMCCC_FUNC___vgic_v5_restore_vmcr_aprs,
> > +	__KVM_HOST_SMCCC_FUNC___vgic_v5_save_ppi_state,
> > +	__KVM_HOST_SMCCC_FUNC___vgic_v5_restore_ppi_state,
> > ?};
> > ?
> > ?#define DECLARE_KVM_VHE_SYM(sym)	extern char sym[]
> > diff --git a/arch/arm64/include/asm/kvm_hyp.h
> > b/arch/arm64/include/asm/kvm_hyp.h
> > index 76ce2b94bd97e..f6cf59a719ac6 100644
> > --- a/arch/arm64/include/asm/kvm_hyp.h
> > +++ b/arch/arm64/include/asm/kvm_hyp.h
> > @@ -87,6 +87,14 @@ void __vgic_v3_save_aprs(struct vgic_v3_cpu_if
> > *cpu_if);
> > ?void __vgic_v3_restore_vmcr_aprs(struct vgic_v3_cpu_if *cpu_if);
> > ?int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);
> > ?
> > +/* GICv5 */
> > +void __vgic_v5_save_vmcr_aprs(struct vgic_v5_cpu_if *cpu_if);
> > +void __vgic_v5_restore_vmcr_aprs(struct vgic_v5_cpu_if *cpu_if);
> > +void __vgic_v5_save_ppi_state(struct vgic_v5_cpu_if *cpu_if);
> > +void __vgic_v5_restore_ppi_state(struct vgic_v5_cpu_if *cpu_if);
> > +void __vgic_v5_save_icsr(struct vgic_v5_cpu_if *cpu_if);
> > +void __vgic_v5_restore_icsr(struct vgic_v5_cpu_if *cpu_if);
> > +
> > ?#ifdef __KVM_NVHE_HYPERVISOR__
> > ?void __timer_enable_traps(struct kvm_vcpu *vcpu);
> > ?void __timer_disable_traps(struct kvm_vcpu *vcpu);
> > diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile
> > b/arch/arm64/kvm/hyp/nvhe/Makefile
> > index a244ec25f8c5b..d860fbe9bc476 100644
> > --- a/arch/arm64/kvm/hyp/nvhe/Makefile
> > +++ b/arch/arm64/kvm/hyp/nvhe/Makefile
> > @@ -26,7 +26,7 @@ hyp-obj-y := timer-sr.o sysreg-sr.o debug-sr.o
> > switch.o tlb.o hyp-init.o host.o
> > ?	 hyp-main.o hyp-smp.o psci-relay.o early_alloc.o
> > page_alloc.o \
> > ?	 cache.o setup.o mm.o mem_protect.o sys_regs.o pkvm.o
> > stacktrace.o ffa.o
> > ?hyp-obj-y += ../vgic-v3-sr.o ../aarch32.o ../vgic-v2-cpuif-proxy.o
> > ../entry.o \
> > -	 ../fpsimd.o ../hyp-entry.o ../exception.o ../pgtable.o
> > +	 ../fpsimd.o ../hyp-entry.o ../exception.o ../pgtable.o
> > ../vgic-v5.o
> > ?hyp-obj-y += ../../../kernel/smccc-call.o
> > ?hyp-obj-$(CONFIG_LIST_HARDENED) += list_debug.o
> > ?hyp-obj-y += $(lib-objs)
> > diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > index a7c689152f686..6bc5a4f75fd01 100644
> > --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > @@ -586,6 +586,34 @@ static void handle___pkvm_teardown_vm(struct
> > kvm_cpu_context *host_ctxt)
> > ?	cpu_reg(host_ctxt, 1) = __pkvm_teardown_vm(handle);
> > ?}
> > ?
> > +static void handle___vgic_v5_save_vmcr_aprs(struct kvm_cpu_context
> > *host_ctxt)
> > +{
> > +	DECLARE_REG(struct vgic_v5_cpu_if *, cpu_if, host_ctxt,
> > 1);
> > +
> > +	__vgic_v5_save_vmcr_aprs(kern_hyp_va(cpu_if));
> > +}
> > +
> > +static void handle___vgic_v5_restore_vmcr_aprs(struct
> > kvm_cpu_context *host_ctxt)
> > +{
> > +	DECLARE_REG(struct vgic_v5_cpu_if *, cpu_if, host_ctxt,
> > 1);
> > +
> > +	__vgic_v5_restore_vmcr_aprs(kern_hyp_va(cpu_if));
> > +}
> > +
> > +static void handle___vgic_v5_save_ppi_state(struct kvm_cpu_context
> > *host_ctxt)
> > +{
> > +	DECLARE_REG(struct vgic_v5_cpu_if *, cpu_if, host_ctxt,
> > 1);
> > +
> > +	__vgic_v5_save_ppi_state(kern_hyp_va(cpu_if));
> > +}
> > +
> > +static void handle___vgic_v5_restore_ppi_state(struct
> > kvm_cpu_context *host_ctxt)
> > +{
> > +	DECLARE_REG(struct vgic_v5_cpu_if *, cpu_if, host_ctxt,
> > 1);
> > +
> > +	__vgic_v5_restore_ppi_state(kern_hyp_va(cpu_if));
> > +}
> > +
> > ?typedef void (*hcall_t)(struct kvm_cpu_context *);
> > ?
> > ?#define HANDLE_FUNC(x)	[__KVM_HOST_SMCCC_FUNC_##x] =
> > (hcall_t)handle_##x
> > @@ -627,6 +655,10 @@ static const hcall_t host_hcall[] = {
> > ?	HANDLE_FUNC(__pkvm_vcpu_load),
> > ?	HANDLE_FUNC(__pkvm_vcpu_put),
> > ?	HANDLE_FUNC(__pkvm_tlb_flush_vmid),
> > +	HANDLE_FUNC(__vgic_v5_save_vmcr_aprs),
> > +	HANDLE_FUNC(__vgic_v5_restore_vmcr_aprs),
> > +	HANDLE_FUNC(__vgic_v5_save_ppi_state),
> > +	HANDLE_FUNC(__vgic_v5_restore_ppi_state),
> > ?};
> > ?
> > ?static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
> > diff --git a/arch/arm64/kvm/hyp/vgic-v5.c
> > b/arch/arm64/kvm/hyp/vgic-v5.c
> > new file mode 100644
> > index 0000000000000..11b67ae09e326
> > --- /dev/null
> > +++ b/arch/arm64/kvm/hyp/vgic-v5.c
> 
> maz at valley-girl:~/hot-poop/arm-platforms$ find . -name vgic-v5.c
> ./arch/arm64/kvm/vgic/vgic-v5.c
> ./arch/arm64/kvm/hyp/vgic-v5.c
> 
> It doesn't look like much, but that's *very* annoying. Which is why
> we
> have vgic-v3.c on one side, and vgic-v3-sr.c on the other. Consider
> doing the same thing here.

Have done this.

> > @@ -0,0 +1,155 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Copyright (C) 2025 - ARM Ltd
> > + */
> > +
> > +#include <hyp/adjust_pc.h>
> > +
> > +#include <linux/compiler.h>
> > +#include <linux/irqchip/arm-gic-v5.h>
> > +#include <linux/kvm_host.h>
> > +
> > +#include <asm/kvm_emulate.h>
> > +#include <asm/kvm_hyp.h>
> > +#include <asm/kvm_mmu.h>
> > +
> > +void __vgic_v5_save_vmcr_aprs(struct vgic_v5_cpu_if *cpu_if)
> > +{
> > +	cpu_if->vgic_vmcr = read_sysreg_s(SYS_ICH_VMCR_EL2);
> > +	cpu_if->vgic_apr = read_sysreg_s(SYS_ICH_APR_EL2);
> > +}
> > +
> > +static void? __vgic_v5_compat_mode_disable(void)
> > +{
> > +	sysreg_clear_set_s(SYS_ICH_VCTLR_EL2, ICH_VCTLR_EL2_V3,
> > 0);
> > +	isb();
> > +}
> > +
> > +void __vgic_v5_restore_vmcr_aprs(struct vgic_v5_cpu_if *cpu_if)
> > +{
> > +	__vgic_v5_compat_mode_disable();
> > +
> > +	write_sysreg_s(cpu_if->vgic_vmcr, SYS_ICH_VMCR_EL2);
> > +	write_sysreg_s(cpu_if->vgic_apr, SYS_ICH_APR_EL2);
> > +}
> > +
> > +void __vgic_v5_save_ppi_state(struct vgic_v5_cpu_if *cpu_if)
> > +{
> > +	cpu_if->vgic_ppi_activer_exit[0] =
> > +		read_sysreg_s(SYS_ICH_PPI_ACTIVER0_EL2);
> > +	cpu_if->vgic_ppi_activer_exit[1] =
> > +		read_sysreg_s(SYS_ICH_PPI_ACTIVER1_EL2);
> 
> Please don't break assignments. Long lines are fine.

Noted!

> > +
> > +	cpu_if->vgic_ich_ppi_enabler_exit[0] =
> > +		read_sysreg_s(SYS_ICH_PPI_ENABLER0_EL2);
> > +	cpu_if->vgic_ich_ppi_enabler_exit[1] =
> > +		read_sysreg_s(SYS_ICH_PPI_ENABLER1_EL2);
> > +
> > +	cpu_if->vgic_ppi_pendr_exit[0] =
> > read_sysreg_s(SYS_ICH_PPI_PENDR0_EL2);
> > +	cpu_if->vgic_ppi_pendr_exit[1] =
> > read_sysreg_s(SYS_ICH_PPI_PENDR1_EL2);
> > +
> > +	cpu_if->vgic_ppi_priorityr[0] =
> > +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR0_EL2);
> > +	cpu_if->vgic_ppi_priorityr[1] =
> > +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR1_EL2);
> > +	cpu_if->vgic_ppi_priorityr[2] =
> > +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR2_EL2);
> > +	cpu_if->vgic_ppi_priorityr[3] =
> > +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR3_EL2);
> > +	cpu_if->vgic_ppi_priorityr[4] =
> > +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR4_EL2);
> > +	cpu_if->vgic_ppi_priorityr[5] =
> > +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR5_EL2);
> > +	cpu_if->vgic_ppi_priorityr[6] =
> > +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR6_EL2);
> > +	cpu_if->vgic_ppi_priorityr[7] =
> > +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR7_EL2);
> > +	cpu_if->vgic_ppi_priorityr[8] =
> > +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR8_EL2);
> > +	cpu_if->vgic_ppi_priorityr[9] =
> > +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR9_EL2);
> > +	cpu_if->vgic_ppi_priorityr[10] =
> > +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR10_EL2);
> > +	cpu_if->vgic_ppi_priorityr[11] =
> > +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR11_EL2);
> > +	cpu_if->vgic_ppi_priorityr[12] =
> > +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR12_EL2);
> > +	cpu_if->vgic_ppi_priorityr[13] =
> > +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR13_EL2);
> > +	cpu_if->vgic_ppi_priorityr[14] =
> > +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR14_EL2);
> > +	cpu_if->vgic_ppi_priorityr[15] =
> > +		read_sysreg_s(SYS_ICH_PPI_PRIORITYR15_EL2);
> 
> There is clearly scope for optimisation here. The most likely case is
> that we will only care about a handful of PPIs, all grouped in the
> first 4 registers. That's a good reason to track the PPIs that the
> guest can see.
> 

Agreed. Will most likely save this optimisation for a future round.
Once everything is back to a working state again!

> > +
> > +	/* Now that we are done, disable DVI */
> > +	write_sysreg_s(0, SYS_ICH_PPI_DVIR0_EL2);
> > +	write_sysreg_s(0, SYS_ICH_PPI_DVIR1_EL2);
> > +}
> > +
> > +void __vgic_v5_restore_ppi_state(struct vgic_v5_cpu_if *cpu_if)
> > +{
> > +	 /* Now enable DVI so that the guest's interrupt config
> > takes over */
> > +	 write_sysreg_s(cpu_if->vgic_ppi_dvir[0],
> > SYS_ICH_PPI_DVIR0_EL2);
> > +	 write_sysreg_s(cpu_if->vgic_ppi_dvir[1],
> > SYS_ICH_PPI_DVIR1_EL2);
> > +
> > +	 write_sysreg_s(cpu_if->vgic_ppi_activer_entry[0],
> > +			SYS_ICH_PPI_ACTIVER0_EL2);
> > +	 write_sysreg_s(cpu_if->vgic_ppi_activer_entry[1],
> > +			SYS_ICH_PPI_ACTIVER1_EL2);
> > +
> > +	 write_sysreg_s(cpu_if->vgic_ich_ppi_enabler_entry[0],
> > +			SYS_ICH_PPI_ENABLER0_EL2);
> > +	 write_sysreg_s(cpu_if->vgic_ich_ppi_enabler_entry[1],
> > +			SYS_ICH_PPI_ENABLER1_EL2);
> > +
> > +	 /* Update the pending state of the NON-DVI'd PPIs, only
> > */
> > +	 write_sysreg_s(cpu_if->vgic_ppi_pendr_entry[0] &
> > +				~cpu_if->vgic_ppi_dvir[0],
> 
> Again, don't insert line breaks in logical operations.
> 

Done.

> > +			SYS_ICH_PPI_PENDR0_EL2);
> > +	 write_sysreg_s(cpu_if->vgic_ppi_pendr_entry[1] &
> > +				~cpu_if->vgic_ppi_dvir[1],
> > +			SYS_ICH_PPI_PENDR1_EL2);
> > +
> > +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[0],
> > +			SYS_ICH_PPI_PRIORITYR0_EL2);
> > +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[1],
> > +			SYS_ICH_PPI_PRIORITYR1_EL2);
> > +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[2],
> > +			SYS_ICH_PPI_PRIORITYR2_EL2);
> > +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[3],
> > +			SYS_ICH_PPI_PRIORITYR3_EL2);
> > +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[4],
> > +			SYS_ICH_PPI_PRIORITYR4_EL2);
> > +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[5],
> > +			SYS_ICH_PPI_PRIORITYR5_EL2);
> > +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[6],
> > +			SYS_ICH_PPI_PRIORITYR6_EL2);
> > +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[7],
> > +			SYS_ICH_PPI_PRIORITYR7_EL2);
> > +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[8],
> > +			SYS_ICH_PPI_PRIORITYR8_EL2);
> > +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[9],
> > +			SYS_ICH_PPI_PRIORITYR9_EL2);
> > +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[10],
> > +			SYS_ICH_PPI_PRIORITYR10_EL2);
> > +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[11],
> > +			SYS_ICH_PPI_PRIORITYR11_EL2);
> > +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[12],
> > +			SYS_ICH_PPI_PRIORITYR12_EL2);
> > +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[13],
> > +			SYS_ICH_PPI_PRIORITYR13_EL2);
> > +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[14],
> > +			SYS_ICH_PPI_PRIORITYR14_EL2);
> > +	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[15],
> > +			SYS_ICH_PPI_PRIORITYR15_EL2);
> > +}
> > +
> > +void __vgic_v5_save_icsr(struct vgic_v5_cpu_if *cpu_if)
> > +{
> > +	cpu_if->vgic_icsr = read_sysreg_s(SYS_ICC_ICSR_EL1);
> > +}
> > +
> > +void __vgic_v5_restore_icsr(struct vgic_v5_cpu_if *cpu_if)
> > +{
> > +	write_sysreg_s(cpu_if->vgic_icsr, SYS_ICC_ICSR_EL1);
> > +}
> > diff --git a/arch/arm64/kvm/hyp/vhe/Makefile
> > b/arch/arm64/kvm/hyp/vhe/Makefile
> > index afc4aed9231ac..fcf5e68ab591c 100644
> > --- a/arch/arm64/kvm/hyp/vhe/Makefile
> > +++ b/arch/arm64/kvm/hyp/vhe/Makefile
> > @@ -10,4 +10,4 @@ CFLAGS_switch.o += -Wno-override-init
> > ?
> > ?obj-y := timer-sr.o sysreg-sr.o debug-sr.o switch.o tlb.o
> > ?obj-y += ../vgic-v3-sr.o ../aarch32.o ../vgic-v2-cpuif-proxy.o
> > ../entry.o \
> > -	 ../fpsimd.o ../hyp-entry.o ../exception.o
> > +	 ../fpsimd.o ../hyp-entry.o ../exception.o ../vgic-v5.o
> > diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> > index fbbaef4ad2114..525c8b83e83c9 100644
> > --- a/include/kvm/arm_vgic.h
> > +++ b/include/kvm/arm_vgic.h
> > @@ -359,7 +359,35 @@ struct vgic_v3_cpu_if {
> > ?};
> > ?
> > ?struct vgic_v5_cpu_if {
> > +	u64	vgic_apr;
> > +	u64	vgic_vmcr;
> > +
> > +	/* PPI register state */
> > ?	u64	vgic_ppi_hmr[2];
> > +	u64	vgic_ppi_dvir[2];
> > +	u64	vgic_ppi_priorityr[16];
> > +
> > +	/* The pending state of the guest. This is merged with the
> > exit state */
> > +	u64	vgic_ppi_pendr[2];
> > +
> > +	/* The state flushed to the regs when entering the guest
> > */
> > +	u64	vgic_ppi_activer_entry[2];
> > +	u64	vgic_ich_ppi_enabler_entry[2];
> > +	u64	vgic_ppi_pendr_entry[2];
> > +
> > +	/* The saved state of the regs when leaving the guest */
> > +	u64	vgic_ppi_activer_exit[2];
> > +	u64	vgic_ich_ppi_enabler_exit[2];
> > +	u64	vgic_ppi_pendr_exit[2];
> 
> See my comment on patch 17, requesting to make these entry/exit
> states
> per CPU, and not per vcpu.
> 

Yeah, I'll look into this for sure. It makes sense to do it that way.
This means that when we're outside of the guest, all of that mess
disappears, and the per-vcpu state just reflects what we're going to
present to the guest on next entry.

Thanks as always,
Sascha

> > +
> > +	/*
> > +	 * The ICSR is re-used across host and guest, and hence it
> > needs to be
> > +	 * saved/restored. Only one copy is required as the host
> > should block
> > +	 * preemption between executing GIC CDRCFG and acccessing
> > the
> > +	 * ICC_ICSR_EL1. A guest, of course, can never guarantee
> > this, and hence
> > +	 * it is the hyp's responsibility to keep the state
> > constistent.
> > +	 */
> > +	u64	vgic_icsr;
> > ?};
> > ?
> > ?struct vgic_cpu {
> 
> Thanks,
> 
> 	M.
> 


From alain.volmat at foss.st.com  Wed Dec 17 13:51:30 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Wed, 17 Dec 2025 22:51:30 +0100
Subject: [PATCH 0/4] spi: stm32: stability & performance enhancements
Message-ID: <20251217-stm32-spi-enhancements-v1-0-943348b8ff66@foss.st.com>

The series fixes a stability issue when dealing with <8bpw
transfers, as well as enforce an error if the DMA information
provided within the DT are incorrect.

Performance enhancement is also provided by allowing a polling
mode which is triggered when the transfer is so short that
polling mode transfer would lead to faster transfer than
if it was done in a interrupt driven manner.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
Alain Volmat (3):
      spi: stm32: perform small transfer in polling mode
      spi: stm32: properly fail on dma_request_chan error
      ARM: dts: stm32: add spi1 sleep state pinctrl on stm32mp157c-ev1

Deepak Kumar (1):
      spi: stm32: fix Overrun issue at < 8bpw

 arch/arm/boot/dts/st/stm32mp157c-ev1.dts |   3 +-
 drivers/spi/spi-stm32.c                  | 106 +++++++++++++++++++++++++++----
 2 files changed, 96 insertions(+), 13 deletions(-)
---
base-commit: 865a1f17d5e41c0b34929afcab0afa6bdb90d33e
change-id: 20251213-stm32-spi-enhancements-29da9bc29133

Best regards,
-- 
Alain Volmat <alain.volmat at foss.st.com>



From alain.volmat at foss.st.com  Wed Dec 17 13:51:32 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Wed, 17 Dec 2025 22:51:32 +0100
Subject: [PATCH 2/4] spi: stm32: perform small transfer in polling mode
In-Reply-To: <20251217-stm32-spi-enhancements-v1-0-943348b8ff66@foss.st.com>
References: <20251217-stm32-spi-enhancements-v1-0-943348b8ff66@foss.st.com>
Message-ID: <20251217-stm32-spi-enhancements-v1-2-943348b8ff66@foss.st.com>

In case of interrupt based transfer, when the transfer is very
small, relying on interrupts leads to lower performances than if
the transfer were done using polling on the registers.

Add a module parameter "polling_limit_us" to indicate the threshold
in us from which a transfer would be done polling the registers rather
than relying on interrupts.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 drivers/spi/spi-stm32.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 77 insertions(+)

diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c
index 80986bd251d2..353ea5b93e0a 100644
--- a/drivers/spi/spi-stm32.c
+++ b/drivers/spi/spi-stm32.c
@@ -202,6 +202,10 @@
 #define STM32_SPI_HOST_MODE(stm32_spi) (!(stm32_spi)->device_mode)
 #define STM32_SPI_DEVICE_MODE(stm32_spi) ((stm32_spi)->device_mode)
 
+static unsigned int polling_limit_us = 30;
+module_param(polling_limit_us, uint, 0664);
+MODULE_PARM_DESC(polling_limit_us, "maximum time in us to run a transfer in polling mode\n");
+
 /**
  * struct stm32_spi_reg - stm32 SPI register & bitfield desc
  * @reg:		register offset
@@ -266,6 +270,7 @@ struct stm32_spi;
  * @dma_rx_cb: routine to call after DMA RX channel operation is complete
  * @dma_tx_cb: routine to call after DMA TX channel operation is complete
  * @transfer_one_irq: routine to configure interrupts for driver
+ * @transfer_one_poll: routine to perform a transfer via register polling
  * @irq_handler_event: Interrupt handler for SPI controller events
  * @irq_handler_thread: thread of interrupt handler for SPI controller
  * @baud_rate_div_min: minimum baud rate divisor
@@ -291,6 +296,7 @@ struct stm32_spi_cfg {
 	void (*dma_rx_cb)(void *data);
 	void (*dma_tx_cb)(void *data);
 	int (*transfer_one_irq)(struct stm32_spi *spi);
+	int (*transfer_one_poll)(struct stm32_spi *spi);
 	irqreturn_t (*irq_handler_event)(int irq, void *dev_id);
 	irqreturn_t (*irq_handler_thread)(int irq, void *dev_id);
 	unsigned int baud_rate_div_min;
@@ -1355,6 +1361,55 @@ static int stm32fx_spi_transfer_one_irq(struct stm32_spi *spi)
 	return 1;
 }
 
+/**
+ * stm32h7_spi_transfer_one_poll - transfer a single spi_transfer by direct
+ *				   register access without interrupt usage
+ * @spi: pointer to the spi controller data structure
+ *
+ * It must returns 0 if the transfer is finished or 1 if the transfer is still
+ * in progress.
+ */
+static int stm32h7_spi_transfer_one_poll(struct stm32_spi *spi)
+{
+	unsigned long flags;
+	u32 sr;
+
+	spin_lock_irqsave(&spi->lock, flags);
+
+	stm32_spi_enable(spi);
+
+	/* Be sure to have data in fifo before starting data transfer */
+	if (spi->tx_buf)
+		stm32h7_spi_write_txfifo(spi);
+
+	if (STM32_SPI_HOST_MODE(spi))
+		stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_CSTART);
+
+	sr = readl_relaxed(spi->base + STM32H7_SPI_SR);
+	/* Keep writing / reading while waiting for the end of transfer */
+	while (spi->tx_len || spi->rx_len || !(sr & STM32H7_SPI_SR_EOT)) {
+		if (spi->rx_len && (sr & (STM32H7_SPI_SR_RXP | STM32H7_SPI_SR_RXWNE |
+					  STM32H7_SPI_SR_RXPLVL)))
+			stm32h7_spi_read_rxfifo(spi);
+
+		if (spi->tx_len && (sr & STM32H7_SPI_SR_TXP))
+			stm32h7_spi_write_txfifo(spi);
+
+		sr = readl_relaxed(spi->base + STM32H7_SPI_SR);
+
+		/* Clear suspension bit if necessary */
+		if (sr & STM32H7_SPI_SR_SUSP)
+			writel_relaxed(sr & STM32H7_SPI_SR_SUSP, spi->base + STM32H7_SPI_IFCR);
+	}
+
+	spin_unlock_irqrestore(&spi->lock, flags);
+
+	stm32h7_spi_disable(spi);
+	spi_finalize_current_transfer(spi->ctrl);
+
+	return 0;
+}
+
 /**
  * stm32h7_spi_transfer_one_irq - transfer a single spi_transfer using
  *				  interrupts
@@ -2026,6 +2081,24 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi,
 	return ret;
 }
 
+/**
+ * stm32_spi_can_poll - detect if poll based transfer is appropriate
+ * @spi: pointer to the spi controller data structure
+ *
+ * Returns true is poll is more appropriate, false otherwise.
+ */
+static bool stm32_spi_can_poll(struct stm32_spi *spi)
+{
+	unsigned long hz_per_byte, byte_limit;
+
+	/* Evaluate the transfer time and use polling if applicable */
+	hz_per_byte = polling_limit_us ?
+		      DIV_ROUND_UP(8 * USEC_PER_SEC, polling_limit_us) : 0;
+	byte_limit = hz_per_byte ? spi->cur_speed / hz_per_byte : 1;
+
+	return (spi->cur_xferlen < byte_limit) ? true : false;
+}
+
 /**
  * stm32_spi_transfer_one - transfer a single spi_transfer
  * @ctrl: controller interface
@@ -2058,6 +2131,8 @@ static int stm32_spi_transfer_one(struct spi_controller *ctrl,
 
 	if (spi->cur_usedma)
 		return stm32_spi_transfer_one_dma(spi, transfer);
+	else if (spi->cfg->transfer_one_poll && stm32_spi_can_poll(spi))
+		return spi->cfg->transfer_one_poll(spi);
 	else
 		return spi->cfg->transfer_one_irq(spi);
 }
@@ -2216,6 +2291,7 @@ static const struct stm32_spi_cfg stm32h7_spi_cfg = {
 	 * SPI access hence handling is performed within the SPI interrupt
 	 */
 	.transfer_one_irq = stm32h7_spi_transfer_one_irq,
+	.transfer_one_poll = stm32h7_spi_transfer_one_poll,
 	.irq_handler_thread = stm32h7_spi_irq_thread,
 	.baud_rate_div_min = STM32H7_SPI_MBR_DIV_MIN,
 	.baud_rate_div_max = STM32H7_SPI_MBR_DIV_MAX,
@@ -2245,6 +2321,7 @@ static const struct stm32_spi_cfg stm32mp25_spi_cfg = {
 	 * SPI access hence handling is performed within the SPI interrupt
 	 */
 	.transfer_one_irq = stm32h7_spi_transfer_one_irq,
+	.transfer_one_poll = stm32h7_spi_transfer_one_poll,
 	.irq_handler_thread = stm32h7_spi_irq_thread,
 	.baud_rate_div_min = STM32H7_SPI_MBR_DIV_MIN,
 	.baud_rate_div_max = STM32H7_SPI_MBR_DIV_MAX,

-- 
2.34.1



From alain.volmat at foss.st.com  Wed Dec 17 13:51:31 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Wed, 17 Dec 2025 22:51:31 +0100
Subject: [PATCH 1/4] spi: stm32: fix Overrun issue at < 8bpw
In-Reply-To: <20251217-stm32-spi-enhancements-v1-0-943348b8ff66@foss.st.com>
References: <20251217-stm32-spi-enhancements-v1-0-943348b8ff66@foss.st.com>
Message-ID: <20251217-stm32-spi-enhancements-v1-1-943348b8ff66@foss.st.com>

From: Deepak Kumar <deepak.kumar01 at st.com>

When SPI communication is suspended by hardware automatically, it could
happen that few bits of next frame are already clocked out due to
internal synchronization delay.

To achieve a safe suspension, we need to ensure that each word must be
at least 8 SPI clock cycles long. That's why, if bpw is less than 8
bits, we need to use midi to reach 8 SPI clock cycles at least.

This will ensure that each word achieve safe suspension and prevent
overrun condition.

Signed-off-by: Deepak Kumar <deepak.kumar01 at st.com>
Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 drivers/spi/spi-stm32.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c
index 2c804c1aef98..80986bd251d2 100644
--- a/drivers/spi/spi-stm32.c
+++ b/drivers/spi/spi-stm32.c
@@ -1906,11 +1906,12 @@ static void stm32h7_spi_data_idleness(struct stm32_spi *spi, struct spi_transfer
 	cfg2_clrb |= STM32H7_SPI_CFG2_MIDI;
 	if ((len > 1) && (spi->cur_midi > 0)) {
 		u32 sck_period_ns = DIV_ROUND_UP(NSEC_PER_SEC, spi->cur_speed);
-		u32 midi = min_t(u32,
-				 DIV_ROUND_UP(spi->cur_midi, sck_period_ns),
-				 FIELD_GET(STM32H7_SPI_CFG2_MIDI,
-				 STM32H7_SPI_CFG2_MIDI));
+		u32 midi = DIV_ROUND_UP(spi->cur_midi, sck_period_ns);
 
+		if ((spi->cur_bpw + midi) < 8)
+			midi = 8 - spi->cur_bpw;
+
+		midi = min_t(u32, midi, FIELD_MAX(STM32H7_SPI_CFG2_MIDI));
 
 		dev_dbg(spi->dev, "period=%dns, midi=%d(=%dns)\n",
 			sck_period_ns, midi, midi * sck_period_ns);

-- 
2.34.1



From alain.volmat at foss.st.com  Wed Dec 17 13:51:33 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Wed, 17 Dec 2025 22:51:33 +0100
Subject: [PATCH 3/4] spi: stm32: properly fail on dma_request_chan error
In-Reply-To: <20251217-stm32-spi-enhancements-v1-0-943348b8ff66@foss.st.com>
References: <20251217-stm32-spi-enhancements-v1-0-943348b8ff66@foss.st.com>
Message-ID: <20251217-stm32-spi-enhancements-v1-3-943348b8ff66@foss.st.com>

Correct handling of the dma_request_chan call in order to avoid
misleading warn message if no DMA is provided within the device-tree
and moreover fail if dma_request_chan has returned a valid error.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 drivers/spi/spi-stm32.c | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c
index 353ea5b93e0a..8f8968383ad0 100644
--- a/drivers/spi/spi-stm32.c
+++ b/drivers/spi/spi-stm32.c
@@ -2484,11 +2484,13 @@ static int stm32_spi_probe(struct platform_device *pdev)
 	spi->dma_tx = dma_request_chan(spi->dev, "tx");
 	if (IS_ERR(spi->dma_tx)) {
 		ret = PTR_ERR(spi->dma_tx);
-		spi->dma_tx = NULL;
-		if (ret == -EPROBE_DEFER)
+		if (ret == -ENODEV) {
+			dev_info(&pdev->dev, "tx dma disabled\n");
+			spi->dma_tx = NULL;
+		} else {
+			dev_err_probe(&pdev->dev, ret, "failed to request tx dma channel\n");
 			goto err_clk_disable;
-
-		dev_warn(&pdev->dev, "failed to request tx dma channel\n");
+		}
 	} else {
 		ctrl->dma_tx = spi->dma_tx;
 	}
@@ -2496,11 +2498,13 @@ static int stm32_spi_probe(struct platform_device *pdev)
 	spi->dma_rx = dma_request_chan(spi->dev, "rx");
 	if (IS_ERR(spi->dma_rx)) {
 		ret = PTR_ERR(spi->dma_rx);
-		spi->dma_rx = NULL;
-		if (ret == -EPROBE_DEFER)
+		if (ret == -ENODEV) {
+			dev_info(&pdev->dev, "rx dma disabled\n");
+			spi->dma_rx = NULL;
+		} else {
+			dev_err_probe(&pdev->dev, ret, "failed to request rx dma channel\n");
 			goto err_dma_release;
-
-		dev_warn(&pdev->dev, "failed to request rx dma channel\n");
+		}
 	} else {
 		ctrl->dma_rx = spi->dma_rx;
 	}

-- 
2.34.1



From alain.volmat at foss.st.com  Wed Dec 17 13:51:34 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Wed, 17 Dec 2025 22:51:34 +0100
Subject: [PATCH 4/4] ARM: dts: stm32: add spi1 sleep state pinctrl on
 stm32mp157c-ev1
In-Reply-To: <20251217-stm32-spi-enhancements-v1-0-943348b8ff66@foss.st.com>
References: <20251217-stm32-spi-enhancements-v1-0-943348b8ff66@foss.st.com>
Message-ID: <20251217-stm32-spi-enhancements-v1-4-943348b8ff66@foss.st.com>

Add the sleep state of the spi1 instance on stm32mp157c-ev1.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 arch/arm/boot/dts/st/stm32mp157c-ev1.dts | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/st/stm32mp157c-ev1.dts b/arch/arm/boot/dts/st/stm32mp157c-ev1.dts
index 8f99c30f1af1..4e46d58bf61f 100644
--- a/arch/arm/boot/dts/st/stm32mp157c-ev1.dts
+++ b/arch/arm/boot/dts/st/stm32mp157c-ev1.dts
@@ -296,8 +296,9 @@ &sdmmc3 {
 };
 
 &spi1 {
-	pinctrl-names = "default";
+	pinctrl-names = "default", "sleep";
 	pinctrl-0 = <&spi1_pins_a>;
+	pinctrl-1 = <&spi1_sleep_pins_a>;
 	status = "disabled";
 };
 

-- 
2.34.1



From patchwork-bot+bluetooth at kernel.org  Wed Dec 17 13:50:08 2025
From: patchwork-bot+bluetooth at kernel.org (patchwork-bot+bluetooth at kernel.org)
Date: Wed, 17 Dec 2025 21:50:08 +0000
Subject: [PATCH v2] Bluetooth: hci_bcm4377: Use generic power management
In-Reply-To: <20251210232115.547729-1-vaibhavgupta40@gmail.com>
References: <20251210232115.547729-1-vaibhavgupta40@gmail.com>
Message-ID: <176600820854.2253459.7299265804546328634.git-patchwork-notify@kernel.org>

Hello:

This patch was applied to bluetooth/bluetooth-next.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz at intel.com>:

On Wed, 10 Dec 2025 23:21:09 +0000 you wrote:
> Switch to the generic PCI power management framework and remove legacy
> callbacks like .suspend() and .resume(). With the generic framework, the
> standard PCI related work like:
>         - pci_save/restore_state()
>         - pci_enable/disable_device()
>         - pci_set_power_state()
> is handled by the PCI core and this driver should implement only
> hci_bcm4377 specific operations in its respective callback functions.
> 
> [...]

Here is the summary with links:
  - [v2] Bluetooth: hci_bcm4377: Use generic power management
    https://git.kernel.org/bluetooth/bluetooth-next/c/0ad59c87f41c

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html




From patchwork-bot+bluetooth at kernel.org  Wed Dec 17 13:50:09 2025
From: patchwork-bot+bluetooth at kernel.org (patchwork-bot+bluetooth at kernel.org)
Date: Wed, 17 Dec 2025 21:50:09 +0000
Subject: [PATCH] Bluetooth: btmtksdio: Use pm_ptr instead of #ifdef
 CONFIG_PM
In-Reply-To: <20251217112033.3309281-3-u.kleine-koenig@baylibre.com>
References: <20251217112033.3309281-3-u.kleine-koenig@baylibre.com>
Message-ID: <176600820978.2253459.8850743046203821977.git-patchwork-notify@kernel.org>

Hello:

This patch was applied to bluetooth/bluetooth-next.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz at intel.com>:

On Wed, 17 Dec 2025 12:20:33 +0100 you wrote:
> This increases build coverage and allows to drop an #ifdef.
> 
> Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig at baylibre.com>
> ---
> Hello,
> 
> I found the patch opportunity while looking in this driver for a different
> reason.
> 
> [...]

Here is the summary with links:
  - Bluetooth: btmtksdio: Use pm_ptr instead of #ifdef CONFIG_PM
    https://git.kernel.org/bluetooth/bluetooth-next/c/fd52b1d0ad7d

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html




From andrew at codeconstruct.com.au  Wed Dec 17 14:00:51 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Thu, 18 Dec 2025 08:30:51 +1030
Subject: [PATCH RFC 01/16] dt-bindings: hwmon: Convert
 aspeed,ast2400-pwm-tacho to DT schema
In-Reply-To: <CAL_JsqJUaKKsJ8BCNbVXe4vLVsQ2Av7VuWqf9DnUKHeLzLb8NQ@mail.gmail.com>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
	 <20251211-dev-dt-warnings-all-v1-1-21b18b9ada77@codeconstruct.com.au>
	 <CAL_JsqJUaKKsJ8BCNbVXe4vLVsQ2Av7VuWqf9DnUKHeLzLb8NQ@mail.gmail.com>
Message-ID: <d6046a94820cda6bfcc3953d6c737152a9f0cf37.camel@codeconstruct.com.au>

On Wed, 2025-12-17 at 09:37 -0600, Rob Herring wrote:
> On Thu, Dec 11, 2025 at 2:46?AM Andrew Jeffery
> <andrew at codeconstruct.com.au> wrote:
> > 
> > From: "Rob Herring (Arm)" <robh at kernel.org>
> > 
> > Convert the ASpeed fan controller binding to DT schema format.
> > 
> > The '#cooling-cells' value used is 1 rather than 2. '#size-cells' is 0
> > rather 1.
> 
> Okay, I can't figure out why I thought '#cooling-cells' needed to be 1
> here. I don't see that anywhere in the tree. The driver for sure only
> supports 2, so anything that's not is an error in any case.

Yeah, I'd started doing some digging to understand your statement about
it needing to be 1 but hadn't got to the bottom of it.

If it can be 2 then great, I can fix up the #size-cells and resend.

Andrew


From puranjay12 at gmail.com  Wed Dec 17 14:29:23 2025
From: puranjay12 at gmail.com (Puranjay Mohan)
Date: Wed, 17 Dec 2025 22:29:23 +0000
Subject: [PATCH bpf-next 2/2] bpf: arm64: Optimize recursion detection by
 not using atomics
In-Reply-To: <a0c04178-2159-4475-9be8-93320ffc2138@linux.dev>
References: <20251217162830.2597286-3-puranjay@kernel.org> <f144fd46b602b74fc4c1c2664082fbe893e7ec9c274fcc5fdf13d65151749e9c@mail.kernel.org>
 <CANk7y0h4JO2-tp9HjRHjcQdTOgmRSsw0rxmK-=G89AVY92U8Jw@mail.gmail.com>
 <CAADnVQ+E6Tgcf1E5x-wk_TA+Lz83cA=SL8EZUGL70bQpywwexg@mail.gmail.com>
 <CANk7y0jNj0SDOBr=3n_0jhQbLzaj--yVUF4oDA-ManQG-=bkhw@mail.gmail.com> <a0c04178-2159-4475-9be8-93320ffc2138@linux.dev>
Message-ID: <CANk7y0hs2E6SVuxt1oHRFek0TD4y0DVP63755K5jxGd9BM3VwQ@mail.gmail.com>

On Wed, Dec 17, 2025 at 9:32?PM Yonghong Song <yonghong.song at linux.dev> wrote:
>
>
>
> On 12/17/25 10:56 AM, Puranjay Mohan wrote:
> > On Wed, Dec 17, 2025 at 6:46?PM Alexei Starovoitov
> > <alexei.starovoitov at gmail.com> wrote:
> >> On Wed, Dec 17, 2025 at 10:13?AM Puranjay Mohan <puranjay at kernel.org> wrote:
> >>> On Wed, Dec 17, 2025 at 4:56?PM <bot+bpf-ci at kernel.org> wrote:
> >>>>> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> >>>>> index 2da986136d26..654fb94bf60c 100644
> >>>>> --- a/include/linux/bpf.h
> >>>>> +++ b/include/linux/bpf.h
> >>>> [ ... ]
> >>>>
> >>>>> @@ -2006,12 +2009,32 @@ struct bpf_struct_ops_common_value {
> >>>>>
> >>>>>   static inline bool bpf_prog_get_recursion_context(struct bpf_prog *prog)
> >>>>>   {
> >>>>> +#ifdef CONFIG_ARM64
> >>>>> +     u8 rctx = interrupt_context_level();
> >>>>> +     u8 *active = this_cpu_ptr(prog->active);
> >>>>> +
> >>>>> +     active[rctx]++;
> >>>>> +     barrier();
> >>>>> +     if (get_unaligned_le32(active) != BIT(rctx * 8))
> >>>>> +             return false;
> >>>>> +
> >>>>> +     return true;
> >>>>> +#else
> >>>>>        return this_cpu_inc_return(*(prog->active)) == 1;
> >>>>> +#endif
> >>>>>   }
> >>>> Can preemption between the increment and check cause a counter leak on
> >>>> CONFIG_PREEMPT_RCU systems? The trampoline calls this function under
> >>>> rcu_read_lock_dont_migrate() which allows preemption on PREEMPT_RCU
> >>>> (documented at include/linux/rcupdate.h:856).
> >>>>
> >>>> Consider this scenario on an ARM64 system with PREEMPT_RCU:
> >>>>
> >>>> 1. Thread A increments active[0] to 1
> >>>> 2. Preemption occurs before Thread A reaches the check
> >>>> 3. Thread B on same CPU increments active[0] to 2
> >>>> 4. Thread B checks: sees 2 != BIT(0), returns false
> >>>> 5. Thread A resumes, checks: sees 2 != BIT(0), returns false
> >>>> 6. Both threads return false, neither runs BPF
> >>>> 7. Neither calls bpf_prog_put_recursion_context() (see
> >>>>     __bpf_prog_enter_recur() at kernel/bpf/trampoline.c:952)
> >>>> 8. Counter permanently stuck at 2, all future BPF on this CPU fails
> >>> Step 7 is incorrect. Looking at the JIT-generated code, the exit
> >>> function is ALWAYS called, regardless of whether the enter function
> >>> returns 0 or a start time:
> >>>
> >>>    // x86 JIT at arch/x86/net/bpf_jit_comp.c:2998-3050
> >>>    call bpf_trampoline_enter()    // Line 2998
> >>>    test rax, rax                   // Line 3006
> >>>    je skip_exec                    // Conditional jump
> >>>    ... BPF program execution ...   // Lines 3011-3023
> >>>    skip_exec:                      // Line 3037 (jump lands here)
> >>>    call bpf_trampoline_exit()      // Line 3049 - ALWAYS executed
> >>>
> >>>    The bpf_trampoline_exit() call is after the skip_exec label, so it
> >>> executes in both cases.
> >>>
> >>> What Actually Happens:
> >>>
> >>>    Initial state: active[0] = 0
> >>>
> >>>    Thread A (normal context, rctx=0):
> >>>    1. active[0]++ ? active[0] = 1
> >>>    2. Preempted before barrier()
> >>>
> >>>    Thread B (scheduled on same CPU, normal context, rctx=0):
> >>>    3. active[0]++ ? active[0] = 2
> >>>    4. barrier()
> >>>    5. get_unaligned_le32(active) ? reads 0x00000002
> >>>    6. Check: 0x00000002 != BIT(0) = 0x00000001 ? returns false
> >>>    7. __bpf_prog_enter_recur returns 0
> >>>    8. JIT checks return value, skips BPF execution
> >>>    9. JIT ALWAYS calls __bpf_prog_exit_recur (see
> >>> arch/arm64/net/bpf_jit_comp.c:2362)
> >>>    10. bpf_prog_put_recursion_context(prog) executes
> >>>    11. barrier(), active[0]-- ? active[0] = 1
> >>>
> >>>    Thread A resumes:
> >>>    12. barrier()
> >>>    13. get_unaligned_le32(active) ? reads 0x00000001 (Thread B already
> >>> decremented!)
> >>>    14. Check: 0x00000001 == BIT(0) = 0x00000001 ? returns true ?
> >>>    15. __bpf_prog_enter_recur returns start_time
> >>>    16. BPF program executes
> >>>    17. __bpf_prog_exit_recur called
> >>>    18. bpf_prog_put_recursion_context(prog) executes
> >>>    19. barrier(), active[0]-- ? active[0] = 0 ?
> >>>
> >>>    Final State
> >>>
> >>>    - Counter returns to 0 ?
> >>>    - No leak ?
> >>>    - Thread B detected interference and aborted ?
> >>>    - Thread A executed successfully ?
> >>>    - Only ONE thread executed the BPF program ?
> >>>
> >>>
> >>> Now that I think of it, there is another race condition that leads to
> >>> NEITHER program running:
> >>>
> >>> Consider this scenario on an arm64 system with PREEMPT_RCU:
> >>>
> >>> 1. Thread A increments active[0] from 0 to 1
> >>> 2. Thread A is preempted before reaching barrier()
> >>> 3. Thread B (same CPU, same context) increments active[0] from 1 to 2
> >>> 4. Thread B executes barrier() and checks: sees 2 != BIT(0), returns false
> >>> 5. Thread A resumes, executes barrier() and checks: sees 2 != BIT(0),
> >>> returns false
> >>> 6. Both threads return false to __bpf_prog_enter_recur()
> >>> 7. Both skip BPF program execution
> >>> 8. Both call bpf_prog_put_recursion_context() and decrement: 2->1->0
> >>> 9. Neither BPF program executes, but the counter correctly returns to 0
> >>>
> >>> This means the patch is changing the behaviour in case of recursion
> >>> from "One program gets to run" to
> >>> "At most one program gets to run", but given the performance benefits,
> >>> I think we can accept this change.
> >> Agree. It's fine, but we can mitigate it, but doing this rctx trick
> >> only when RCU is not preemptable. Which pretty much would mean
> >> that PREEMPT_RT will use atomic and !RT will use rctx
> >> and this 'no prog executes' will not happen.
> >
> > The issue is also with sleepable programs, they use
> > rcu_read_lock_trace() and can end up with
> > 'no prog executes' scenario.
> >
> > What do you think is the best approach for them?
>
> For sleepable programs, maybe we can use the original approach like
>    return this_cpu_inc_return(*(prog->active)) == 1;
> ?
> This should solve the 'no prog execution' issue.


I tried putting preempt_disable/enable() around inc+read in entry and
dec in exit:

New data, a little different config, so ignore exact values.

This patch:                           56.524M/s
This patch with preempt_disable():    53.856M/s
bpf-next/master:                      43.067M/s
bpf-next/master without Catalin fix:  51.862M/s


This is still very good and covers the sleepable case as well. So let's do this?

Thanks,
Puranjay


From andrew at codeconstruct.com.au  Wed Dec 17 14:53:50 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Thu, 18 Dec 2025 09:23:50 +1030
Subject: [PATCH v5 2/2] ARM: dts: aspeed: add device tree for ASRock
 Rack ALTRAD8 BMC
In-Reply-To: <20251211165700.29206-3-rebecca@bsdio.com>
References: <20251211165700.29206-1-rebecca@bsdio.com>
	 <20251211165700.29206-3-rebecca@bsdio.com>
Message-ID: <ee0acf89f82555a1c0705fba5818875811a3a27e.camel@codeconstruct.com.au>

Hi Rebecca,

On Thu, 2025-12-11 at 09:56 -0700, Rebecca Cran wrote:
> The ALTRAD8 BMC is an Aspeed AST2500-based BMC for the ASRock Rack
> ALTRAD8UD-1L2T and ALTRAD8UD2-1L2Q boards.
> 
> Signed-off-by: Rebecca Cran <rebecca at bsdio.com>
> ---
> diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts
> b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts
> new file mode 100644
> index 000000000000..4898ddede1c2
> --- /dev/null
> +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts
> @@ -0,0 +1,624 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/dts-v1/;
> +
> +#include "aspeed-g5.dtsi"
> +#include <dt-bindings/gpio/aspeed-gpio.h>
> +#include <dt-bindings/leds/common.h>
> +#include <dt-bindings/i2c/i2c.h>
> +
> +/ {
> +	model = "ASRock ALTRAD8 BMC";
> +	compatible = "asrock,altrad8-bmc", "aspeed,ast2500";
> +
> +	aliases {
> +		serial4 = &uart5;
> +		i2c50 = &nvme1;
> +		i2c51 = &pcie4;
> +		i2c52 = &pcie5;
> +		i2c53 = &pcie6;
> +		i2c54 = &pcie7;
> +		i2c55 = &nvme3;
> +		i2c56 = &nvme2;
> +		i2c57 = &nvme0;
> +		i2c58 = &nvme4;
> +		i2c59 = &nvme5;
> +		i2c60 = &nvme6;
> +		i2c61 = &nvme7;
> +		i2c62 = &nvme8;
> +		i2c63 = &nvme9;
> +		i2c64 = &nvme10;
> +		i2c65 = &nvme11;
> +	};
> +
> +	chosen {
> +		stdout-path = "uart5:115200n8";
> +	};
> +
> +	iio-hwmon {
> +		compatible = "iio-hwmon";
> +		io-channels =	<&adc 0>, <&adc 1>, <&adc 2>, <&adc
> 3>,
> +				<&adc 4> ,<&adc 5>, <&adc 6>, <&adc
> 7>,
> +				<&adc 8>, <&adc 9>, <&adc 10>, <&adc
> 11>,
> +				<&adc 12>, <&adc 13>, <&adc 14>,
> <&adc 15>;
> +	};
> +

*snip*

> +&adc {
> +	status = "okay";

Please add the necessary pinctrl properties to request the ADC lines as
used for the iio-hwmon bridge. This ensures their exclusive use so they
can't otherwise be muxed as e.g. GPIOs and produce surprising system
behaviour.

> +};
> +

*snip*

> +&pinctrl {
> +	aspeed,external-nodes = <&gfx &lhc>;

This property is now set in aspeed-g5.dtsi so it's unnecessary to do so
here in the dts. I also have a cleanup at [1] that impacts it, so the
less we can propagate the problem the better

[1]: https://lore.kernel.org/all/20251211-dev-dt-warnings-all-v1-0-21b18b9ada77 at codeconstruct.com.au/

Otherwise the patch looks okay to me.

Andrew


From andrew at codeconstruct.com.au  Wed Dec 17 14:59:44 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Thu, 18 Dec 2025 09:29:44 +1030
Subject: [PATCH] arm: dts: aspeed: add an alt 128M flash layout
In-Reply-To: <20251211-alt-128-layout-v1-1-100f57d2bc4a@nvidia.com>
References: <20251211-alt-128-layout-v1-1-100f57d2bc4a@nvidia.com>
Message-ID: <61f561d95af86a46f1e1075df39e1ce0f1324098.camel@codeconstruct.com.au>

On Thu, 2025-12-11 at 13:35 -0800, Marc Olberding wrote:
> Add a 128M layout for the BMC flash chip we didn't boot from.
> Including
> this allows the user to write to each partition on the alternate spi
> chip. This dtsi follows the existing standard of using the same
> layout
> as non alt version and prepending `alt` to each partition's name.
> 
> Testing: Include this in msx4 and cat size, offsets and name
> ```
> for devdir in /sys/class/mtd/mtd*; do
> > ??? [[ -d $devdir && -r $devdir/name ]] || continue
> > ??? name=$(<"$devdir/name")
> > ??? [[ $name == alt* ]] || continue
> > 
> > ??? size=$(<"$devdir/size")
> > ??? offset=0
> > ??? [[ -r $devdir/offset ]] && offset=$(<"$devdir/offset")
> > 
> > ??? dev=$(basename "$devdir")
> > ??? printf "%s name=%s offset=0x%X size=0x%X\n" "$dev" "$name" \
> > ?????? "$offset" "$size"
> > done
> mtd10 name=alt-rofs offset=0xA00000 size=0x5600000
> mtd11 name=alt-rwfs offset=0x6000000 size=0x2000000
> mtd7 name=alt-u-boot offset=0x0 size=0xE0000
> mtd8 name=alt-u-boot-env offset=0xE0000 size=0x20000
> mtd9 name=alt-kernel offset=0x100000 size=0x900000
> ```
> 
> Also ran dtbs_check on an existing dts with this included.
> 
> Signed-off-by: Marc Olberding <molberding at nvidia.com>
> ---
> Add a layout for an alternate 128M flash layout. This is
> useful for the aspeed ast2500[2] and ast2600[1] SoCs,
> where it has the ability to boot from one of two spi chips,
> nominally the primary and backup SPIs. Adding a layout allows
> userspace
> to flash the alternate spi by partition and switch over to it,
> allowing
> lower downtime for firmware flash, or for updating the primary
> flash from the golden backup flash. This is already an established
> scheme for the 32M and 64M layouts, where the layout is the same
> but each partition has `alt` prepended to its name. This allows
> userspace to just prepend alt to the images in the update process
> to specify which flash chip to update.
> 
> References:
> 
> [1] https://www.aspeedtech.com/server_ast2600/
> [2] https://www.aspeedtech.com/server_ast2500/
> ---
> ?.../dts/aspeed/openbmc-flash-layout-128-alt.dtsi?? | 32
> ++++++++++++++++++++++
> ?1 file changed, 32 insertions(+)

This may be fine, but please add it in a series that also introduces a
board that consumes it.

Andrew


From coltonlewis at google.com  Wed Dec 17 15:03:41 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Wed, 17 Dec 2025 23:03:41 +0000
Subject: [PATCH v5 14/24] KVM: arm64: Write fast path PMU register handlers
In-Reply-To: <aUH7oC41XaEMsXf_@kernel.org> (message from Oliver Upton on Tue,
 16 Dec 2025 16:38:56 -0800)
Message-ID: <gsnt34583e42.fsf@coltonlewis-kvm.c.googlers.com>

Oliver Upton <oupton at kernel.org> writes:

> On Tue, Dec 09, 2025 at 08:51:11PM +0000, Colton Lewis wrote:
>> diff --git a/arch/arm64/include/asm/arm_pmuv3.h  
>> b/arch/arm64/include/asm/arm_pmuv3.h
>> index 3e25c0313263c..41ec6730ebc62 100644
>> --- a/arch/arm64/include/asm/arm_pmuv3.h
>> +++ b/arch/arm64/include/asm/arm_pmuv3.h
>> @@ -39,6 +39,16 @@ static inline unsigned long read_pmevtypern(int n)
>>   	return 0;
>>   }

>> +static inline void write_pmxevcntr(u64 val)
>> +{
>> +	write_sysreg(val, pmxevcntr_el0);
>> +}
>> +
>> +static inline u64 read_pmxevcntr(void)
>> +{
>> +	return read_sysreg(pmxevcntr_el0);
>> +}
>> +
>>   static inline unsigned long read_pmmir(void)
>>   {
>>   	return read_cpuid(PMMIR_EL1);
>> @@ -105,21 +115,41 @@ static inline void write_pmcntenset(u64 val)
>>   	write_sysreg(val, pmcntenset_el0);
>>   }

>> +static inline u64 read_pmcntenset(void)
>> +{
>> +	return read_sysreg(pmcntenset_el0);
>> +}
>> +
>>   static inline void write_pmcntenclr(u64 val)
>>   {
>>   	write_sysreg(val, pmcntenclr_el0);
>>   }

>> +static inline u64 read_pmcntenclr(void)
>> +{
>> +	return read_sysreg(pmcntenclr_el0);
>> +}
>> +
>>   static inline void write_pmintenset(u64 val)
>>   {
>>   	write_sysreg(val, pmintenset_el1);
>>   }

>> +static inline u64 read_pmintenset(void)
>> +{
>> +	return read_sysreg(pmintenset_el1);
>> +}
>> +
>>   static inline void write_pmintenclr(u64 val)
>>   {
>>   	write_sysreg(val, pmintenclr_el1);
>>   }

>> +static inline u64 read_pmintenclr(void)
>> +{
>> +	return read_sysreg(pmintenclr_el1);
>> +}
>> +
>>   static inline void write_pmccfiltr(u64 val)
>>   {
>>   	write_sysreg(val, pmccfiltr_el0);
>> @@ -160,11 +190,16 @@ static inline u64 read_pmovsclr(void)
>>   	return read_sysreg(pmovsclr_el0);
>>   }

>> -static inline void write_pmuserenr(u32 val)
>> +static inline void write_pmuserenr(u64 val)
>>   {
>>   	write_sysreg(val, pmuserenr_el0);
>>   }

>> +static inline u64 read_pmuserenr(void)
>> +{
>> +	return read_sysreg(pmuserenr_el0);
>> +}
>> +
>>   static inline void write_pmuacr(u64 val)
>>   {
>>   	write_sysreg_s(val, SYS_PMUACR_EL1);

> I wouldn't bother with adding accessors to the PMUv3 driver header, this
> gets a bit confusing when the 32-bit counterpart lacks matching  
> definitions.
> Additionally, the part of KVM you're modifying is very much an
> "internal" part meant to run in a not-quite-kernel context.

> Considering this, I'd prefer KVM directly accessed the PMU registers to
> avoid the possibility of taking some instrumented codepath in the
> future.

Will do.

>> +	if (!kvm_vcpu_pmu_is_partitioned(vcpu)
>> +	    || pmu_access_el0_disabled(vcpu))

> Always put operators on the preceding line for line continuations.

> Also, don't call pmu_access_el0_disabled() from here. It can potentially
> do a full emulated exception entry even though the vCPU is in an
> extremely inconsistent state (i.e. haven't returned to kernel context
> yet). Isn't the current value for PMUSERENR_EL0 on the CPU instead of in
> the vCPU's saved context anyway?

> The fast-path accessors really need to be *just* accessors, reading
> state from the CPU in the unfortunate situation that a TPM trap has been
> forced upon us.

Understood.

>> +	case SYS_PMXEVCNTR_EL0:
>> +		idx = FIELD_GET(PMSELR_EL0_SEL, read_pmselr());
>> +
>> +		if (pmu_access_event_counter_el0_disabled(vcpu))
>> +			return false;
>> +
>> +		if (!pmu_counter_idx_valid(vcpu, idx))
>> +			return false;
>> +
>> +		ret = handle_pmu_reg(vcpu, &p, PMEVCNTR0_EL0 + idx, rt, val,
>> +				     &read_pmxevcntr, &write_pmxevcntr);
>> +		break;

> It is a bit odd to handle the muxing for finding the in-memory value yet
> using the selector-based register for hardware.

Agreed

>> +	case SYS_PMEVCNTRn_EL0(0) ... SYS_PMEVCNTRn_EL0(30):
>> +		idx = ((p.CRm & 3) << 3) | (p.Op2 & 7);
>> +
>> +		if (pmu_access_event_counter_el0_disabled(vcpu))
>> +			return false;
>> +
>> +		if (!pmu_counter_idx_valid(vcpu, idx))
>> +			return false;
>> +
>> +		if (p.is_write) {
>> +			write_pmevcntrn(idx, val);
>> +			__vcpu_assign_sys_reg(vcpu, PMEVCNTR0_EL0 + idx, val);
>> +		} else {
>> +			vcpu_set_reg(vcpu, rt, read_pmevcntrn(idx));
>> +		}
>> +
>> +		ret = true;
>> +		break;

> Can't both of these cases share a helper once you've worked out the
> index? Same for PMEVTYPERn_EL0.

Agreed

>> +	default:
>> +		ret = false;
>> +	}
>> +
>> +	if (ret)
>> +		__kvm_skip_instr(vcpu);
>> +
>> +	return ret;
>> +}
>> +
>>   static inline bool kvm_hyp_handle_sysreg(struct kvm_vcpu *vcpu, u64  
>> *exit_code)
>>   {
>>   	if (cpus_have_final_cap(ARM64_WORKAROUND_CAVIUM_TX2_219_TVM) &&
>> @@ -785,6 +983,9 @@ static inline bool kvm_hyp_handle_sysreg(struct  
>> kvm_vcpu *vcpu, u64 *exit_code)
>>   	if (kvm_handle_cntxct(vcpu))
>>   		return true;

>> +	if (kvm_hyp_handle_pmu_regs(vcpu))
>> +		return true;
>> +

> Since the whole partitioned PMU feature is constrained to VHE-only you
> should call this from kvm_hyp_handle_sysreg_vhe().

Will do.

>> +
>> +bool check_pmu_access_disabled(struct kvm_vcpu *vcpu, u64 flags)
>> +{
>> +	u64 reg = __vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>> +	bool enabled = (reg & flags) || vcpu_mode_priv(vcpu);
>> +
>> +	if (!enabled)
>> +		kvm_inject_undefined(vcpu);
>> +
>> +	return !enabled;
>> +}
>> +
>> +bool pmu_access_el0_disabled(struct kvm_vcpu *vcpu)
>> +{
>> +	return check_pmu_access_disabled(vcpu, ARMV8_PMU_USERENR_EN);
>> +}
>> +
>> +bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx)
>> +{
>> +	u64 pmcr, val;
>> +
>> +	pmcr = kvm_vcpu_read_pmcr(vcpu);
>> +	val = FIELD_GET(ARMV8_PMU_PMCR_N, pmcr);
>> +	if (idx >= val && idx != ARMV8_PMU_CYCLE_IDX) {
>> +		kvm_inject_undefined(vcpu);
>> +		return false;
>> +	}
>> +
>> +	return true;
>> +}
>> +
>> +bool pmu_access_cycle_counter_el0_disabled(struct kvm_vcpu *vcpu)
>> +{
>> +	return check_pmu_access_disabled(vcpu, ARMV8_PMU_USERENR_CR |  
>> ARMV8_PMU_USERENR_EN);
>> +}
>> +
>> +bool pmu_access_event_counter_el0_disabled(struct kvm_vcpu *vcpu)
>> +{
>> +	return check_pmu_access_disabled(vcpu, ARMV8_PMU_USERENR_ER |  
>> ARMV8_PMU_USERENR_EN);
>> +}

> Refactorings need to happen in a separate patch.

Will do

> Thanks,
> Oliver


From coltonlewis at google.com  Wed Dec 17 15:05:26 2025
From: coltonlewis at google.com (Colton Lewis)
Date: Wed, 17 Dec 2025 23:05:26 +0000
Subject: [PATCH v5 18/24] KVM: arm64: Enforce PMU event filter at vcpu_load()
In-Reply-To: <aUH_7yYZsmFlRvEc@kernel.org> (message from Oliver Upton on Tue,
 16 Dec 2025 16:57:19 -0800)
Message-ID: <gsntzf7g1zgp.fsf@coltonlewis-kvm.c.googlers.com>

Oliver Upton <oupton at kernel.org> writes:

> Re-reading this patch...

> On Tue, Dec 09, 2025 at 08:51:15PM +0000, Colton Lewis wrote:
>> The KVM API for event filtering says that counters do not count when
>> blocked by the event filter. To enforce that, the event filter must be
>> rechecked on every load since it might have changed since the last
>> time the guest wrote a value.

> Just directly state that this is guarding against userspace programming
> an unsupported event ID.

Sure

>> +static void kvm_pmu_apply_event_filter(struct kvm_vcpu *vcpu)
>> +{
>> +	struct arm_pmu *pmu = vcpu->kvm->arch.arm_pmu;
>> +	u64 evtyper_set = ARMV8_PMU_EXCLUDE_EL0 |
>> +		ARMV8_PMU_EXCLUDE_EL1;
>> +	u64 evtyper_clr = ARMV8_PMU_INCLUDE_EL2;
>> +	u8 i;
>> +	u64 val;
>> +	u64 evsel;
>> +
>> +	if (!pmu)
>> +		return;
>> +
>> +	for (i = 0; i < pmu->hpmn_max; i++) {

> Iterate the bitmask of counters and you'll handle the cycle counter 'for
> free'.

Will do.

> <snip>

>> +		val = __vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i);
>> +		evsel = val & kvm_pmu_event_mask(vcpu->kvm);
>> +
>> +		if (vcpu->kvm->arch.pmu_filter &&
>> +		    !test_bit(evsel, vcpu->kvm->arch.pmu_filter))
>> +			val |= evtyper_set;
>> +
>> +		val &= ~evtyper_clr;
>> +		write_pmevtypern(i, val);

> </snip>

> This all needs to be shared with writethrough_pmevtyper() instead of
> open-coding the same thing.

Will do.

> Thanks,
> Oliver


From iuliana.prodan at nxp.com  Wed Dec 17 15:06:27 2025
From: iuliana.prodan at nxp.com (Iuliana Prodan)
Date: Thu, 18 Dec 2025 01:06:27 +0200
Subject: [PATCH] remoteproc: imx_dsp_rproc: only reset carveout memory at
 RPROC_OFFLINE state
In-Reply-To: <20251216074216.447193-1-shengjiu.wang@nxp.com>
References: <20251216074216.447193-1-shengjiu.wang@nxp.com>
Message-ID: <ad45e803-1235-4320-a87b-a60b18df2cf0@nxp.com>

On 12/16/2025 9:42 AM, Shengjiu Wang wrote:
> Don't need to reset memory at suspend and resume stage, because some
> memory is used to save the software state for resume, if it is cleared,
> the resume operation can fail.
> 
> Fixes: c4c432dfb00f ("remoteproc: imx_dsp_rproc: Add support of recovery and coredump process")
> Signed-off-by: Shengjiu Wang <shengjiu.wang at nxp.com>

Reviewed-by: Iuliana Prodan <iuliana.prodan at nxp.com>

Thanks,
Iulia

> ---
>   drivers/remoteproc/imx_dsp_rproc.c | 8 +++++---
>   1 file changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c
> index d03017d6b214..ac8aa71aa56c 100644
> --- a/drivers/remoteproc/imx_dsp_rproc.c
> +++ b/drivers/remoteproc/imx_dsp_rproc.c
> @@ -984,9 +984,11 @@ static int imx_dsp_rproc_load(struct rproc *rproc, const struct firmware *fw)
>   	 * Clear buffers after pm rumtime for internal ocram is not
>   	 * accessible if power and clock are not enabled.
>   	 */
> -	list_for_each_entry(carveout, &rproc->carveouts, node) {
> -		if (carveout->va)
> -			memset(carveout->va, 0, carveout->len);
> +	if (rproc->state == RPROC_OFFLINE) {
> +		list_for_each_entry(carveout, &rproc->carveouts, node) {
> +			if (carveout->va)
> +				memset(carveout->va, 0, carveout->len);
> +		}
>   	}
>   
>   	ret = imx_dsp_rproc_elf_load_segments(rproc, fw);



From molberding at nvidia.com  Wed Dec 17 15:13:33 2025
From: molberding at nvidia.com (Marc Olberding)
Date: Wed, 17 Dec 2025 15:13:33 -0800
Subject: [PATCH] arm: dts: aspeed: add an alt 128M flash layout
In-Reply-To: <61f561d95af86a46f1e1075df39e1ce0f1324098.camel@codeconstruct.com.au>
References: <20251211-alt-128-layout-v1-1-100f57d2bc4a@nvidia.com>
 <61f561d95af86a46f1e1075df39e1ce0f1324098.camel@codeconstruct.com.au>
Message-ID: <aUM5HcEs0OVrDO1w@molberding.nvidia.com>

On Thu, Dec 18, 2025 at 09:29:44AM +1030, Andrew Jeffery wrote:
> On Thu, 2025-12-11 at 13:35 -0800, Marc Olberding wrote:
> > Add a 128M layout for the BMC flash chip we didn't boot from.
> > Including
> > this allows the user to write to each partition on the alternate spi
> > chip. This dtsi follows the existing standard of using the same
> > layout
> > as non alt version and prepending `alt` to each partition's name.
> > 
... 
> This may be fine, but please add it in a series that also introduces a
> board that consumes it.
> 
> Andrew

Ack, I wasn't sure how to handle this, since the MSX4 hasn't merged to
master for upstream yet, its just been merged into the openbmc tree.
I can either just hold off on this patch or update the msx4 series.
I'm assuming that including this in a patch targetted to the openbmc tree
is a nonstarter. Any thoughts here?

Thanks,
Marc


From jonas at kwiboo.se  Wed Dec 17 15:15:58 2025
From: jonas at kwiboo.se (Jonas Karlman)
Date: Thu, 18 Dec 2025 00:15:58 +0100
Subject: [PATCH v6 04/17] media: rkvdec: Switch to using structs instead
 of writel
In-Reply-To: <20251217174059.1341784-5-detlev.casanova@collabora.com>
References: <20251217174059.1341784-1-detlev.casanova@collabora.com>
 <20251217174059.1341784-5-detlev.casanova@collabora.com>
Message-ID: <1e8fdb44-f695-4387-a5c5-25278c9248a9@kwiboo.se>

Hi Detlev,

On 12/17/2025 6:40 PM, Detlev Casanova wrote:
> In an effort to merge the rkvdec2 driver [1] with this one, switch from
> writel() calls to using structs to represent the register mappings.
> 
> This is done in order to have all supported decoders use the same format
> in the future and ease reading of the code.
> 
> Using structs also improves stability as the hardware is tested and
> validated downstream using a similar method.
> It was noticed, on decoders, that:
>  - Some registers require to be writen in increasing order [2]
>  - Some registers, even if unrelated, need to be written to their reset
>    values (it was the case here for axi_ddr_[rw]data).
> 
> Using structs can also help improving performance later when, e.g.
> multicore support is added on RK3588.
> 
> Performance seems to be slightly improved, but at least, not made worse.
> Running fluster's JVT-AVC_V1 test suite with GStreamer on the Radxa ROCK
> PI 4 SE gives the following times:
> 
> Before this patch:
> 
> - --jobs 1: Ran 129/135 tests successfully               in 77.167 secs
> - --jobs 6: Ran 129/135 tests successfully               in 23.046 secs
> 
> With this patch:
> - --jobs 1: Ran 129/135 tests successfully               in 70.698 secs
> - --jobs 6: Ran 129/135 tests successfully               in 22.917 secs
> 
> This also shows that the fluster score hasn't changed.
> 
> [1]: https://lore.kernel.org/all/20250325213303.826925-1-detlev.casanova at collabora.com/
> [2]: https://lore.kernel.org/all/20200127143009.15677-5-andrzej.p at collabora.com/
> 
> Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
> Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
> ---
>  .../platform/rockchip/rkvdec/rkvdec-h264.c    | 165 +++--
>  .../platform/rockchip/rkvdec/rkvdec-hevc.c    |  63 +-
>  .../platform/rockchip/rkvdec/rkvdec-regs.h    | 571 ++++++++++++------
>  .../platform/rockchip/rkvdec/rkvdec-vp9.c     | 231 +++----
>  .../media/platform/rockchip/rkvdec/rkvdec.c   |  10 +-
>  .../media/platform/rockchip/rkvdec/rkvdec.h   |   1 +
>  6 files changed, 587 insertions(+), 454 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
> index d14b4d173448..116e7b1076b7 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
> @@ -115,6 +115,7 @@ struct rkvdec_h264_run {
>  struct rkvdec_h264_ctx {
>  	struct rkvdec_aux_buf priv_tbl;
>  	struct rkvdec_h264_reflists reflists;
> +	struct rkvdec_regs regs;
>  };
>  
>  #define CABAC_ENTRY(ctxidx, idc0_m, idc0_n, idc1_m, idc1_n,		\
> @@ -841,45 +842,41 @@ static void assemble_hw_scaling_list(struct rkvdec_ctx *ctx,
>  }
>  
>  /*
> - * dpb poc related registers table
> + * Set the ref POC in the correct register.
> + *
> + * The 32 registers are spread across 3 regions, each alternating top and bottom ref POCs:
> + *  - 1: ref 0 to 14 contain top 0 to 7 and bottoms 0 to 6
> + *  - 2: ref 15 to 29 contain top 8 to 14 and bottoms 7 to 14
> + *  - 3: ref 30 and 31 which correspond to top 15 and bottom 15 respectively.
>   */
> -static const u32 poc_reg_tbl_top_field[16] = {
> -	RKVDEC_REG_H264_POC_REFER0(0),
> -	RKVDEC_REG_H264_POC_REFER0(2),
> -	RKVDEC_REG_H264_POC_REFER0(4),
> -	RKVDEC_REG_H264_POC_REFER0(6),
> -	RKVDEC_REG_H264_POC_REFER0(8),
> -	RKVDEC_REG_H264_POC_REFER0(10),
> -	RKVDEC_REG_H264_POC_REFER0(12),
> -	RKVDEC_REG_H264_POC_REFER0(14),
> -	RKVDEC_REG_H264_POC_REFER1(1),
> -	RKVDEC_REG_H264_POC_REFER1(3),
> -	RKVDEC_REG_H264_POC_REFER1(5),
> -	RKVDEC_REG_H264_POC_REFER1(7),
> -	RKVDEC_REG_H264_POC_REFER1(9),
> -	RKVDEC_REG_H264_POC_REFER1(11),
> -	RKVDEC_REG_H264_POC_REFER1(13),
> -	RKVDEC_REG_H264_POC_REFER2(0)
> -};
> -
> -static const u32 poc_reg_tbl_bottom_field[16] = {
> -	RKVDEC_REG_H264_POC_REFER0(1),
> -	RKVDEC_REG_H264_POC_REFER0(3),
> -	RKVDEC_REG_H264_POC_REFER0(5),
> -	RKVDEC_REG_H264_POC_REFER0(7),
> -	RKVDEC_REG_H264_POC_REFER0(9),
> -	RKVDEC_REG_H264_POC_REFER0(11),
> -	RKVDEC_REG_H264_POC_REFER0(13),
> -	RKVDEC_REG_H264_POC_REFER1(0),
> -	RKVDEC_REG_H264_POC_REFER1(2),
> -	RKVDEC_REG_H264_POC_REFER1(4),
> -	RKVDEC_REG_H264_POC_REFER1(6),
> -	RKVDEC_REG_H264_POC_REFER1(8),
> -	RKVDEC_REG_H264_POC_REFER1(10),
> -	RKVDEC_REG_H264_POC_REFER1(12),
> -	RKVDEC_REG_H264_POC_REFER1(14),
> -	RKVDEC_REG_H264_POC_REFER2(1)
> -};
> +static void set_poc_reg(struct rkvdec_regs *regs, uint32_t poc, int id, bool bottom)
> +{
> +	if (!bottom) {
> +		switch (id) {
> +		case 0 ... 7:
> +			regs->h26x.ref0_14_poc[id * 2] = poc;
> +			break;
> +		case 8 ... 14:
> +			regs->h26x.ref15_29_poc[(id - 8) * 2 + 1] = poc;
> +			break;
> +		case 15:
> +			regs->h26x.ref30_poc = poc;
> +			break;
> +		}
> +	} else {
> +		switch (id) {
> +		case 0 ... 6:
> +			regs->h26x.ref0_14_poc[id * 2 + 1] = poc;
> +			break;
> +		case 7 ... 14:
> +			regs->h26x.ref15_29_poc[(id - 7) * 2] = poc;
> +			break;
> +		case 15:
> +			regs->h26x.ref31_poc = poc;
> +			break;
> +		}
> +	}
> +}
>  
>  static void config_registers(struct rkvdec_ctx *ctx,
>  			     struct rkvdec_h264_run *run)
> @@ -894,6 +891,7 @@ static void config_registers(struct rkvdec_ctx *ctx,
>  	struct vb2_v4l2_buffer *src_buf = run->base.bufs.src;
>  	struct vb2_v4l2_buffer *dst_buf = run->base.bufs.dst;
>  	const struct v4l2_format *f;
> +	struct rkvdec_regs *regs = &h264_ctx->regs;
>  	dma_addr_t rlc_addr;
>  	dma_addr_t refer_addr;
>  	u32 rlc_len;
> @@ -903,10 +901,11 @@ static void config_registers(struct rkvdec_ctx *ctx,
>  	u32 yuv_virstride = 0;
>  	u32 offset;
>  	dma_addr_t dst_addr;
> -	u32 reg, i;
> +	u32 i;
>  
> -	reg = RKVDEC_MODE(RKVDEC_MODE_H264);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_SYSCTRL);
> +	memset(regs, 0, sizeof(*regs));
> +
> +	regs->common.reg02.dec_mode = RKVDEC_MODE_H264;
>  
>  	f = &ctx->decoded_fmt;
>  	dst_fmt = &f->fmt.pix_mp;
> @@ -921,39 +920,35 @@ static void config_registers(struct rkvdec_ctx *ctx,
>  	else if (sps->chroma_format_idc == 2)
>  		yuv_virstride = 2 * y_virstride;
>  
> -	reg = RKVDEC_Y_HOR_VIRSTRIDE(hor_virstride / 16) |
> -	      RKVDEC_UV_HOR_VIRSTRIDE(hor_virstride / 16) |
> -	      RKVDEC_SLICE_NUM_HIGHBIT |
> -	      RKVDEC_SLICE_NUM_LOWBITS(0x7ff);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_PICPAR);
> +	regs->common.reg03.uv_hor_virstride = hor_virstride / 16;
> +	regs->common.reg03.y_hor_virstride = hor_virstride / 16;
> +	regs->common.reg03.slice_num_highbit = 1;
> +	regs->common.reg03.slice_num_lowbits = 0x7ff;
>  
>  	/* config rlc base address */
>  	rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
> -	writel_relaxed(rlc_addr, rkvdec->regs + RKVDEC_REG_STRM_RLC_BASE);
> -	writel_relaxed(rlc_addr, rkvdec->regs + RKVDEC_REG_RLCWRITE_BASE);
> +	regs->common.strm_rlc_base = rlc_addr;
> +	regs->h26x.rlcwrite_base = rlc_addr;
>  
>  	rlc_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
> -	reg = RKVDEC_STRM_LEN(rlc_len);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_STRM_LEN);
> +	regs->common.stream_len = rlc_len;
>  
>  	/* config cabac table */
>  	offset = offsetof(struct rkvdec_h264_priv_tbl, cabac_table);
> -	writel_relaxed(priv_start_addr + offset,
> -		       rkvdec->regs + RKVDEC_REG_CABACTBL_PROB_BASE);
> +	regs->common.cabactbl_base = priv_start_addr + offset;
>  
>  	/* config output base address */
>  	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
> -	writel_relaxed(dst_addr, rkvdec->regs + RKVDEC_REG_DECOUT_BASE);
> +	regs->common.decout_base = dst_addr;
>  
> -	reg = RKVDEC_Y_VIRSTRIDE(y_virstride / 16);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_Y_VIRSTRIDE);
> +	regs->common.reg08.y_virstride = y_virstride / 16;
>  
> -	reg = RKVDEC_YUV_VIRSTRIDE(yuv_virstride / 16);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_YUV_VIRSTRIDE);
> +	regs->common.reg09.yuv_virstride = yuv_virstride / 16;
>  
>  	/* config ref pic address & poc */
>  	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
>  		struct vb2_buffer *vb_buf = run->ref_buf[i];
> +		struct ref_base *base;
>  
>  		/*
>  		 * If a DPB entry is unused or invalid, address of current destination
> @@ -963,54 +958,36 @@ static void config_registers(struct rkvdec_ctx *ctx,
>  			vb_buf = &dst_buf->vb2_buf;
>  		refer_addr = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
>  
> -		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)
> -			refer_addr |= RKVDEC_COLMV_USED_FLAG_REF;
> -		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD)
> -			refer_addr |= RKVDEC_FIELD_REF;
> -
> -		if (dpb[i].fields & V4L2_H264_TOP_FIELD_REF)
> -			refer_addr |= RKVDEC_TOPFIELD_USED_REF;
> -		if (dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF)
> -			refer_addr |= RKVDEC_BOTFIELD_USED_REF;
> -
> -		writel_relaxed(dpb[i].top_field_order_cnt,
> -			       rkvdec->regs +  poc_reg_tbl_top_field[i]);
> -		writel_relaxed(dpb[i].bottom_field_order_cnt,
> -			       rkvdec->regs + poc_reg_tbl_bottom_field[i]);
> -
>  		if (i < V4L2_H264_NUM_DPB_ENTRIES - 1)
> -			writel_relaxed(refer_addr,
> -				       rkvdec->regs + RKVDEC_REG_H264_BASE_REFER(i));
> +			base = &regs->h26x.ref0_14_base[i];
>  		else
> -			writel_relaxed(refer_addr,
> -				       rkvdec->regs + RKVDEC_REG_H264_BASE_REFER15);
> -	}
> +			base = &regs->h26x.ref15_base;
>  
> -	reg = RKVDEC_CUR_POC(dec_params->top_field_order_cnt);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC0);
> +		base->field_ref = !!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD);
> +		base->colmv_used_flag_ref = !!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE);
> +		base->topfield_used_ref = !!(dpb[i].fields & V4L2_H264_TOP_FIELD_REF);
> +		base->botfield_used_ref = !!(dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF);
> +		base->base_addr = refer_addr >> 4;

Please set before ref fields to be consistent with hevc.

>  
> -	reg = RKVDEC_CUR_POC(dec_params->bottom_field_order_cnt);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC1);
> +		set_poc_reg(regs, dpb[i].top_field_order_cnt, i, false);
> +		set_poc_reg(regs, dpb[i].bottom_field_order_cnt, i, true);
> +	}
> +
> +	regs->h26x.cur_poc = dec_params->top_field_order_cnt;
> +	regs->h26x.cur_poc1 = dec_params->bottom_field_order_cnt;
>  
>  	/* config hw pps address */
>  	offset = offsetof(struct rkvdec_h264_priv_tbl, param_set);
> -	writel_relaxed(priv_start_addr + offset,
> -		       rkvdec->regs + RKVDEC_REG_PPS_BASE);
> +	regs->h26x.pps_base = priv_start_addr + offset;
>  
>  	/* config hw rps address */
>  	offset = offsetof(struct rkvdec_h264_priv_tbl, rps);
> -	writel_relaxed(priv_start_addr + offset,
> -		       rkvdec->regs + RKVDEC_REG_RPS_BASE);
> -
> -	reg = RKVDEC_AXI_DDR_RDATA(0);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_RDATA);
> -
> -	reg = RKVDEC_AXI_DDR_WDATA(0);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_WDATA);
> +	regs->h26x.rps_base = priv_start_addr + offset;
>  
>  	offset = offsetof(struct rkvdec_h264_priv_tbl, err_info);
> -	writel_relaxed(priv_start_addr + offset,
> -		       rkvdec->regs + RKVDEC_REG_H264_ERRINFO_BASE);
> +	regs->h26x.errorinfo_base = priv_start_addr + offset;
> +
> +	rkvdec_memcpy_toio(rkvdec->regs, regs, MIN(sizeof(*regs), 4 * rkvdec->variant->num_regs));

Should this use sizeof(u32) instead of 4 ?

>  }
>  
>  #define RKVDEC_H264_MAX_DEPTH_IN_BYTES		2
> @@ -1181,8 +1158,6 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
>  
>  	schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000));
>  
> -	writel(0, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN);
> -	writel(0, rkvdec->regs + RKVDEC_REG_H264_ERR_E);
>  	writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND);
>  	writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);
>  
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
> index fc7e6a260b0a..01f92fa27356 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
> @@ -129,6 +129,7 @@ struct rkvdec_hevc_run {
>  struct rkvdec_hevc_ctx {
>  	struct rkvdec_aux_buf priv_tbl;
>  	struct v4l2_ctrl_hevc_scaling_matrix scaling_matrix_cache;
> +	struct rkvdec_regs regs;
>  };
>  
>  struct scaling_factor {
> @@ -548,6 +549,7 @@ static void config_registers(struct rkvdec_ctx *ctx,
>  	const struct v4l2_ctrl_hevc_slice_params *sl_params = &run->slices_params[0];
>  	const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb;
>  	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
> +	struct rkvdec_regs *regs = &hevc_ctx->regs;
>  	dma_addr_t priv_start_addr = hevc_ctx->priv_tbl.dma;
>  	const struct v4l2_pix_format_mplane *dst_fmt;
>  	struct vb2_v4l2_buffer *src_buf = run->base.bufs.src;
> @@ -564,8 +566,9 @@ static void config_registers(struct rkvdec_ctx *ctx,
>  	dma_addr_t dst_addr;
>  	u32 reg, i;
>  
> -	reg = RKVDEC_MODE(RKVDEC_MODE_HEVC);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_SYSCTRL);
> +	memset(regs, 0, sizeof(*regs));
> +
> +	regs->common.reg02.dec_mode = RKVDEC_MODE_HEVC;
>  
>  	f = &ctx->decoded_fmt;
>  	dst_fmt = &f->fmt.pix_mp;
> @@ -580,33 +583,27 @@ static void config_registers(struct rkvdec_ctx *ctx,
>  	else if (sps->chroma_format_idc == 2)
>  		yuv_virstride = 2 * y_virstride;
>  
> -	reg = RKVDEC_Y_HOR_VIRSTRIDE(hor_virstride / 16) |
> -	      RKVDEC_UV_HOR_VIRSTRIDE(hor_virstride / 16) |
> -	      RKVDEC_SLICE_NUM_LOWBITS(run->num_slices);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_PICPAR);
> +	regs->common.reg03.slice_num_lowbits = run->num_slices;
> +	regs->common.reg03.uv_hor_virstride = hor_virstride / 16;
> +	regs->common.reg03.y_hor_virstride = hor_virstride / 16;
>  
>  	/* config rlc base address */
>  	rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
> -	writel_relaxed(rlc_addr, rkvdec->regs + RKVDEC_REG_STRM_RLC_BASE);
> +	regs->common.strm_rlc_base = rlc_addr;
>  
>  	rlc_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
> -	reg = RKVDEC_STRM_LEN(round_up(rlc_len, 16) + 64);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_STRM_LEN);
> +	regs->common.stream_len = round_up(rlc_len, 16) + 64;
>  
>  	/* config cabac table */
>  	offset = offsetof(struct rkvdec_hevc_priv_tbl, cabac_table);
> -	writel_relaxed(priv_start_addr + offset,
> -		       rkvdec->regs + RKVDEC_REG_CABACTBL_PROB_BASE);
> +	regs->common.cabactbl_base = priv_start_addr + offset;
>  
>  	/* config output base address */
>  	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
> -	writel_relaxed(dst_addr, rkvdec->regs + RKVDEC_REG_DECOUT_BASE);
> -
> -	reg = RKVDEC_Y_VIRSTRIDE(y_virstride / 16);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_Y_VIRSTRIDE);
> +	regs->common.decout_base = dst_addr;
>  
> -	reg = RKVDEC_YUV_VIRSTRIDE(yuv_virstride / 16);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_YUV_VIRSTRIDE);
> +	regs->common.reg08.y_virstride = y_virstride / 16;
> +	regs->common.reg09.yuv_virstride = yuv_virstride / 16;
>  
>  	/* config ref pic address */
>  	for (i = 0; i < 15; i++) {
> @@ -620,33 +617,29 @@ static void config_registers(struct rkvdec_ctx *ctx,
>  		}
>  
>  		refer_addr = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
> -		writel_relaxed(refer_addr | reg,
> -			       rkvdec->regs + RKVDEC_REG_H264_BASE_REFER(i));
>  
> -		reg = RKVDEC_POC_REFER(i < decode_params->num_active_dpb_entries ?
> -			dpb[i].pic_order_cnt_val : 0);
> -		writel_relaxed(reg,
> -			       rkvdec->regs + RKVDEC_REG_H264_POC_REFER0(i));
> +		regs->h26x.ref0_14_base[i].base_addr = refer_addr >> 4;
> +		regs->h26x.ref0_14_base[i].field_ref = !!(reg & 1);
> +		regs->h26x.ref0_14_base[i].topfield_used_ref = !!(reg & 2);
> +		regs->h26x.ref0_14_base[i].botfield_used_ref = !!(reg & 4);
> +		regs->h26x.ref0_14_base[i].colmv_used_flag_ref = !!(reg & 8);
> +
> +		regs->h26x.ref0_14_poc[i] = i < decode_params->num_active_dpb_entries
> +					    ? dpb[i].pic_order_cnt_val
> +					    : 0;
>  	}
>  
> -	reg = RKVDEC_CUR_POC(sl_params->slice_pic_order_cnt);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC0);
> +	regs->h26x.cur_poc = sl_params->slice_pic_order_cnt;
>  
>  	/* config hw pps address */
>  	offset = offsetof(struct rkvdec_hevc_priv_tbl, param_set);
> -	writel_relaxed(priv_start_addr + offset,
> -		       rkvdec->regs + RKVDEC_REG_PPS_BASE);
> +	regs->h26x.pps_base = priv_start_addr + offset;
>  
>  	/* config hw rps address */
>  	offset = offsetof(struct rkvdec_hevc_priv_tbl, rps);
> -	writel_relaxed(priv_start_addr + offset,
> -		       rkvdec->regs + RKVDEC_REG_RPS_BASE);
> -
> -	reg = RKVDEC_AXI_DDR_RDATA(0);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_RDATA);
> +	regs->h26x.rps_base = priv_start_addr + offset;
>  
> -	reg = RKVDEC_AXI_DDR_WDATA(0);
> -	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_WDATA);
> +	rkvdec_memcpy_toio(rkvdec->regs, regs, MIN(sizeof(*regs), 4 * rkvdec->variant->num_regs));

Same here regarding sizeof(u32)

>  }
>  
>  #define RKVDEC_HEVC_MAX_DEPTH_IN_BYTES		2
> @@ -784,8 +777,6 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
>  
>  	schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000));
>  
> -	writel(0, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN);
> -	writel(0, rkvdec->regs + RKVDEC_REG_H264_ERR_E);
>  	writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND);
>  	writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);
>  
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h
> index c627b6b6f53a..7745ea257148 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h
> @@ -3,7 +3,12 @@
>  #ifndef RKVDEC_REGS_H_
>  #define RKVDEC_REGS_H_
>  
> -/* rkvcodec registers */
> +#include <linux/types.h>
> +
> +/*
> + * REG_INTERRUPT is accessed via writel to enable the decoder after
> + * configuring it and clear interrupt strmd_error_status
> + */
>  #define RKVDEC_REG_INTERRUPT				0x004
>  #define RKVDEC_INTERRUPT_DEC_E				BIT(0)
>  #define RKVDEC_CONFIG_DEC_CLK_GATE_E			BIT(1)
> @@ -30,198 +35,384 @@
>  #define RKVDEC_SOFTRESET_RDY				BIT(22)
>  #define RKVDEC_WR_DDR_ALIGN_EN				BIT(23)
>  
> -#define RKVDEC_REG_SYSCTRL				0x008
> -#define RKVDEC_IN_ENDIAN				BIT(0)
> -#define RKVDEC_IN_SWAP32_E				BIT(1)
> -#define RKVDEC_IN_SWAP64_E				BIT(2)
> -#define RKVDEC_STR_ENDIAN				BIT(3)
> -#define RKVDEC_STR_SWAP32_E				BIT(4)
> -#define RKVDEC_STR_SWAP64_E				BIT(5)
> -#define RKVDEC_OUT_ENDIAN				BIT(6)
> -#define RKVDEC_OUT_SWAP32_E				BIT(7)
> -#define RKVDEC_OUT_CBCR_SWAP				BIT(8)
> -#define RKVDEC_RLC_MODE_DIRECT_WRITE			BIT(10)
> -#define RKVDEC_RLC_MODE					BIT(11)
> -#define RKVDEC_STRM_START_BIT(x)			(((x) & 0x7f) << 12)
> -#define RKVDEC_MODE(x)					(((x) & 0x03) << 20)
> -#define RKVDEC_MODE_HEVC				0
> -#define RKVDEC_MODE_H264				1
> -#define RKVDEC_MODE_VP9					2
> -#define RKVDEC_RPS_MODE					BIT(24)
> -#define RKVDEC_STRM_MODE				BIT(25)
> -#define RKVDEC_H264_STRM_LASTPKT			BIT(26)
> -#define RKVDEC_H264_FIRSTSLICE_FLAG			BIT(27)
> -#define RKVDEC_H264_FRAME_ORSLICE			BIT(28)
> -#define RKVDEC_BUSPR_SLOT_DIS				BIT(29)
> -
> -#define RKVDEC_REG_PICPAR				0x00C
> -#define RKVDEC_Y_HOR_VIRSTRIDE(x)			((x) & 0x1ff)
> -#define RKVDEC_SLICE_NUM_HIGHBIT			BIT(11)
> -#define RKVDEC_UV_HOR_VIRSTRIDE(x)			(((x) & 0x1ff) << 12)
> -#define RKVDEC_SLICE_NUM_LOWBITS(x)			(((x) & 0x7ff) << 21)
> -
> -#define RKVDEC_REG_STRM_RLC_BASE			0x010
> -
> -#define RKVDEC_REG_STRM_LEN				0x014
> -#define RKVDEC_STRM_LEN(x)				((x) & 0x7ffffff)
> -
> -#define RKVDEC_REG_CABACTBL_PROB_BASE			0x018
> -#define RKVDEC_REG_DECOUT_BASE				0x01C
> -
> -#define RKVDEC_REG_Y_VIRSTRIDE				0x020
> -#define RKVDEC_Y_VIRSTRIDE(x)				((x) & 0xfffff)
> -
> -#define RKVDEC_REG_YUV_VIRSTRIDE			0x024
> -#define RKVDEC_YUV_VIRSTRIDE(x)				((x) & 0x1fffff)
> -#define RKVDEC_REG_H264_BASE_REFER(i)			(((i) * 0x04) + 0x028)
> -
> -#define RKVDEC_REG_H264_BASE_REFER15			0x0C0
> -#define RKVDEC_FIELD_REF				BIT(0)
> -#define RKVDEC_TOPFIELD_USED_REF			BIT(1)
> -#define RKVDEC_BOTFIELD_USED_REF			BIT(2)
> -#define RKVDEC_COLMV_USED_FLAG_REF			BIT(3)
> -
> -#define RKVDEC_REG_VP9_LAST_FRAME_BASE			0x02c
> -#define RKVDEC_REG_VP9_GOLDEN_FRAME_BASE		0x030
> -#define RKVDEC_REG_VP9_ALTREF_FRAME_BASE		0x034
> -
> -#define RKVDEC_REG_VP9_CPRHEADER_OFFSET			0x028
> -#define RKVDEC_VP9_CPRHEADER_OFFSET(x)			((x) & 0xffff)
> -
> -#define RKVDEC_REG_VP9_REFERLAST_BASE			0x02C
> -#define RKVDEC_REG_VP9_REFERGOLDEN_BASE			0x030
> -#define RKVDEC_REG_VP9_REFERALFTER_BASE			0x034
> -
> -#define RKVDEC_REG_VP9COUNT_BASE			0x038
> -#define RKVDEC_VP9COUNT_UPDATE_EN			BIT(0)
> -
> -#define RKVDEC_REG_VP9_SEGIDLAST_BASE			0x03C
> -#define RKVDEC_REG_VP9_SEGIDCUR_BASE			0x040
> -#define RKVDEC_REG_VP9_FRAME_SIZE(i)			((i) * 0x04 + 0x044)
> -#define RKVDEC_VP9_FRAMEWIDTH(x)			(((x) & 0xffff) << 0)
> -#define RKVDEC_VP9_FRAMEHEIGHT(x)			(((x) & 0xffff) << 16)
> -
> -#define RKVDEC_VP9_SEGID_GRP(i)				((i) * 0x04 + 0x050)
> -#define RKVDEC_SEGID_ABS_DELTA(x)			((x) & 0x1)
> -#define RKVDEC_SEGID_FRAME_QP_DELTA_EN(x)		(((x) & 0x1) << 1)
> -#define RKVDEC_SEGID_FRAME_QP_DELTA(x)			(((x) & 0x1ff) << 2)
> -#define RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE_EN(x)	(((x) & 0x1) << 11)
> -#define RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE(x)		(((x) & 0x7f) << 12)
> -#define RKVDEC_SEGID_REFERINFO_EN(x)			(((x) & 0x1) << 19)
> -#define RKVDEC_SEGID_REFERINFO(x)			(((x) & 0x03) << 20)
> -#define RKVDEC_SEGID_FRAME_SKIP_EN(x)			(((x) & 0x1) << 22)
> -
> -#define RKVDEC_VP9_CPRHEADER_CONFIG			0x070
> -#define RKVDEC_VP9_TX_MODE(x)				((x) & 0x07)
> -#define RKVDEC_VP9_FRAME_REF_MODE(x)			(((x) & 0x03) << 3)
> -
> -#define RKVDEC_VP9_REF_SCALE(i)				((i) * 0x04 + 0x074)
> -#define RKVDEC_VP9_REF_HOR_SCALE(x)			((x) & 0xffff)
> -#define RKVDEC_VP9_REF_VER_SCALE(x)			(((x) & 0xffff) << 16)
> -
> -#define RKVDEC_VP9_REF_DELTAS_LASTFRAME			0x080
> -#define RKVDEC_REF_DELTAS_LASTFRAME(pos, val)		(((val) & 0x7f) << ((pos) * 7))
> -
> -#define RKVDEC_VP9_INFO_LASTFRAME			0x084
> -#define RKVDEC_MODE_DELTAS_LASTFRAME(pos, val)		(((val) & 0x7f) << ((pos) * 7))
> -#define RKVDEC_SEG_EN_LASTFRAME				BIT(16)
> -#define RKVDEC_LAST_SHOW_FRAME				BIT(17)
> -#define RKVDEC_LAST_INTRA_ONLY				BIT(18)
> -#define RKVDEC_LAST_WIDHHEIGHT_EQCUR			BIT(19)
> -#define RKVDEC_COLOR_SPACE_LASTKEYFRAME(x)		(((x) & 0x07) << 20)
> -
> -#define RKVDEC_VP9_INTERCMD_BASE			0x088
> -
> -#define RKVDEC_VP9_INTERCMD_NUM				0x08C
> -#define RKVDEC_INTERCMD_NUM(x)				((x) & 0xffffff)
> -
> -#define RKVDEC_VP9_LASTTILE_SIZE			0x090
> -#define RKVDEC_LASTTILE_SIZE(x)				((x) & 0xffffff)
> -
> -#define RKVDEC_VP9_HOR_VIRSTRIDE(i)			((i) * 0x04 + 0x094)
> -#define RKVDEC_HOR_Y_VIRSTRIDE(x)			((x) & 0x1ff)
> -#define RKVDEC_HOR_UV_VIRSTRIDE(x)			(((x) & 0x1ff) << 16)
> -
> -#define RKVDEC_REG_H264_POC_REFER0(i)			(((i) * 0x04) + 0x064)
> -#define RKVDEC_REG_H264_POC_REFER1(i)			(((i) * 0x04) + 0x0C4)
> -#define RKVDEC_REG_H264_POC_REFER2(i)			(((i) * 0x04) + 0x120)
> -#define RKVDEC_POC_REFER(x)				((x) & 0xffffffff)
> -
> -#define RKVDEC_REG_CUR_POC0				0x0A0
> -#define RKVDEC_REG_CUR_POC1				0x128
> -#define RKVDEC_CUR_POC(x)				((x) & 0xffffffff)
> -
> -#define RKVDEC_REG_RLCWRITE_BASE			0x0A4
> -#define RKVDEC_REG_PPS_BASE				0x0A8
> -#define RKVDEC_REG_RPS_BASE				0x0AC
> -
> -#define RKVDEC_REG_STRMD_ERR_EN				0x0B0
> -#define RKVDEC_STRMD_ERR_EN(x)				((x) & 0xffffffff)
> -
> -#define RKVDEC_REG_STRMD_ERR_STA			0x0B4
> -#define RKVDEC_STRMD_ERR_STA(x)				((x) & 0xfffffff)
> -#define RKVDEC_COLMV_ERR_REF_PICIDX(x)			(((x) & 0x0f) << 28)
> -
> -#define RKVDEC_REG_STRMD_ERR_CTU			0x0B8
> -#define RKVDEC_STRMD_ERR_CTU(x)				((x) & 0xff)
> -#define RKVDEC_STRMD_ERR_CTU_YOFFSET(x)			(((x) & 0xff) << 8)
> -#define RKVDEC_STRMFIFO_SPACE2FULL(x)			(((x) & 0x7f) << 16)
> -#define RKVDEC_VP9_ERR_EN_CTU0				BIT(24)
> -
> -#define RKVDEC_REG_SAO_CTU_POS				0x0BC
> -#define RKVDEC_SAOWR_XOFFSET(x)				((x) & 0x1ff)
> -#define RKVDEC_SAOWR_YOFFSET(x)				(((x) & 0x3ff) << 16)
> -
> -#define RKVDEC_VP9_LAST_FRAME_YSTRIDE			0x0C0
> -#define RKVDEC_VP9_GOLDEN_FRAME_YSTRIDE			0x0C4
> -#define RKVDEC_VP9_ALTREF_FRAME_YSTRIDE			0x0C8
> -#define RKVDEC_VP9_REF_YSTRIDE(x)			(((x) & 0xfffff) << 0)
> -
> -#define RKVDEC_VP9_LAST_FRAME_YUVSTRIDE			0x0CC
> -#define RKVDEC_VP9_REF_YUVSTRIDE(x)			(((x) & 0x1fffff) << 0)
> -
> -#define RKVDEC_VP9_REF_COLMV_BASE			0x0D0
> -
> -#define RKVDEC_REG_PERFORMANCE_CYCLE			0x100
> -#define RKVDEC_PERFORMANCE_CYCLE(x)			((x) & 0xffffffff)
> -
> -#define RKVDEC_REG_AXI_DDR_RDATA			0x104
> -#define RKVDEC_AXI_DDR_RDATA(x)				((x) & 0xffffffff)
> -
> -#define RKVDEC_REG_AXI_DDR_WDATA			0x108
> -#define RKVDEC_AXI_DDR_WDATA(x)				((x) & 0xffffffff)
> -
> -#define RKVDEC_REG_FPGADEBUG_RESET			0x10C
> -#define RKVDEC_BUSIFD_RESETN				BIT(0)
> -#define RKVDEC_CABAC_RESETN				BIT(1)
> -#define RKVDEC_DEC_CTRL_RESETN				BIT(2)
> -#define RKVDEC_TRANSD_RESETN				BIT(3)
> -#define RKVDEC_INTRA_RESETN				BIT(4)
> -#define RKVDEC_INTER_RESETN				BIT(5)
> -#define RKVDEC_RECON_RESETN				BIT(6)
> -#define RKVDEC_FILER_RESETN				BIT(7)
> -
> -#define RKVDEC_REG_PERFORMANCE_SEL			0x110
> -#define RKVDEC_PERF_SEL_CNT0(x)				((x) & 0x3f)
> -#define RKVDEC_PERF_SEL_CNT1(x)				(((x) & 0x3f) << 8)
> -#define RKVDEC_PERF_SEL_CNT2(x)				(((x) & 0x3f) << 16)
> -
> -#define RKVDEC_REG_PERFORMANCE_CNT(i)			((i) * 0x04 + 0x114)
> -#define RKVDEC_PERF_CNT(x)				((x) & 0xffffffff)
> -
> -#define RKVDEC_REG_H264_ERRINFO_BASE			0x12C
> -
> -#define RKVDEC_REG_H264_ERRINFO_NUM			0x130
> -#define RKVDEC_SLICEDEC_NUM(x)				((x) & 0x3fff)
> -#define RKVDEC_STRMD_DECT_ERR_FLAG			BIT(15)
> -#define RKVDEC_ERR_PKT_NUM(x)				(((x) & 0x3fff) << 16)
> -
> -#define RKVDEC_REG_H264_ERR_E				0x134
> -#define RKVDEC_H264_ERR_EN_HIGHBITS(x)			((x) & 0x3fffffff)
> -
>  #define RKVDEC_REG_QOS_CTRL				0x18C
>  
> +/*
> + * Cache configuration is not covered in the range of the register struct
> + */
>  #define RKVDEC_REG_PREF_LUMA_CACHE_COMMAND		0x410
>  #define RKVDEC_REG_PREF_CHR_CACHE_COMMAND		0x450
>  
> +/*
> + * Define the mode values
> + */
> +#define RKVDEC_MODE_HEVC				0
> +#define RKVDEC_MODE_H264				1
> +#define RKVDEC_MODE_VP9					2
> +
> +/* rkvcodec registers */
> +struct rkvdec_common_regs {
> +	struct rkvdec_id {
> +		u32 minor_ver	: 8;
> +		u32 level	: 1;
> +		u32 dec_support	: 3;
> +		u32 profile	: 1;
> +		u32 reserved0	: 1;
> +		u32 codec_flag	: 1;
> +		u32 reserved1	: 1;
> +		u32 prod_num	: 16;
> +	} reg00;
> +
> +	struct rkvdec_int {
> +		u32 dec_e			: 1;
> +		u32 dec_clkgate_e		: 1;
> +		u32 reserved0			: 1;

This is dec_e_strmd_clkgate_dis on rk3328.

> +		u32 timeout_mode		: 1;
> +		u32 dec_irq_dis			: 1;
> +		u32 dec_timeout_e		: 1;
> +		u32 buf_empty_en		: 1;
> +		u32 stmerror_waitdecfifo_empty	: 1;
> +		u32 dec_irq			: 1;
> +		u32 dec_irq_raw			: 1;
> +		u32 reserved2			: 2;
> +		u32 dec_rdy_sta			: 1;
> +		u32 dec_bus_sta			: 1;
> +		u32 dec_error_sta		: 1;
> +		u32 dec_timeout_sta		: 1;
> +		u32 dec_empty_sta		: 1;
> +		u32 colmv_ref_error_sta		: 1;
> +		u32 cabu_end_sta		: 1;
> +		u32 h264orvp9_error_mode	: 1;
> +		u32 softrst_en_p		: 1;
> +		u32 force_softreset_valid	: 1;
> +		u32 softreset_rdy		: 1;

This is missing following from e.g. rk3328:

		u32 wr_ddr_align_en		: 1;
		u32 scl_down_en			: 1;
		u32 allow_not_wr_unref_bframe	: 1;

> +		u32 reserved1			: 9;
> +	} reg01;
> +
> +	struct rkvdec_sysctrl {
> +		u32 in_endian			: 1;
> +		u32 in_swap32_e			: 1;
> +		u32 in_swap64_e			: 1;
> +		u32 str_endian			: 1;
> +		u32 str_swap32_e		: 1;
> +		u32 str_swap64_e		: 1;
> +		u32 out_endian			: 1;
> +		u32 out_swap32_e		: 1;
> +		u32 out_cbcr_swap		: 1;
> +		u32 reserved0			: 1;
> +		u32 rlc_mode_direct_write	: 1;
> +		u32 rlc_mode			: 1;
> +		u32 strm_start_bit		: 7;
> +		u32 reserved1			: 1;
> +		u32 dec_mode			: 2;
> +		u32 reserved2			: 2;
> +		u32 rps_mode			: 1;
> +		u32 stream_mode			: 1;
> +		u32 stream_lastpacket		: 1;
> +		u32 firstslice_flag		: 1;
> +		u32 frame_orslice		: 1;
> +		u32 buspr_slot_disable		: 1;
> +		u32 reserved3			: 2;

This is colmv_mode and ycacherd_prior on rk3328.

> +	} reg02;
> +
> +	struct rkvdec_picpar {
> +		u32 y_hor_virstride	: 9;
> +		u32 reserved		: 2;
> +		u32 slice_num_highbit	: 1;
> +		u32 uv_hor_virstride	: 9;
> +		u32 slice_num_lowbits	: 11;
> +	} reg03;
> +
> +	u32 strm_rlc_base;
> +	u32 stream_len;
> +	u32 cabactbl_base;
> +	u32 decout_base;
> +
> +	struct rkvdec_y_virstride {
> +		u32 y_virstride	: 20;
> +		u32 reserved0	: 12;
> +	} reg08;
> +
> +	struct rkvdec_yuv_virstride {
> +		u32 yuv_virstride	: 21;
> +		u32 reserved0		: 11;
> +	} reg09;
> +} __packed;
> +
> +struct ref_base {
> +	u32 field_ref		: 1;
> +	u32 topfield_used_ref	: 1;
> +	u32 botfield_used_ref	: 1;
> +	u32 colmv_used_flag_ref	: 1;

This is called colmv_use_flag in TRM.

> +	u32 base_addr		: 28;

Maybe this could be a union to not have to >> 4 the base addr?

> +};
> +
> +struct rkvdec_h26x_regs {
> +	struct ref_base ref0_14_base[15];
> +	u32 ref0_14_poc[15];
> +
> +	u32 cur_poc;
> +	u32 rlcwrite_base;
> +	u32 pps_base;
> +	u32 rps_base;
> +
> +	u32 strmd_error_e;
> +
> +	struct {
> +		u32 strmd_error_status		: 28;
> +		u32 colmv_error_ref_picidx	: 4;
> +	} reg45;
> +
> +	struct {
> +		u32 strmd_error_ctu_xoffset	: 8;
> +		u32 strmd_error_ctu_yoffset	: 8;
> +		u32 streamfifo_space2full	: 7;
> +		u32 reserved0			: 1;
> +		u32 vp9_error_ctu0_en		: 1;
> +		u32 reserved1			: 7;
> +	} reg46;
> +
> +	struct {
> +		u32 saowr_xoffet	: 9;
> +		u32 reserved0		: 7;
> +		u32 saowr_yoffset	: 10;
> +		u32 reserved1		: 6;
> +	} reg47;
> +
> +	struct ref_base ref15_base;
> +
> +	u32 ref15_29_poc[15];
> +
> +	u32 performance_cycle;
> +	u32 axi_ddr_rdata;
> +	u32 axi_ddr_wdata;
> +
> +	struct {
> +		u32 busifd_resetn	: 1;
> +		u32 cabac_resetn	: 1;
> +		u32 dec_ctrl_resetn	: 1;
> +		u32 transd_resetn	: 1;
> +		u32 intra_resetn	: 1;
> +		u32 inter_resetn	: 1;
> +		u32 recon_resetn	: 1;
> +		u32 filer_resetn	: 1;
> +		u32 reserved0		: 24;
> +	} reg67;
> +
> +	struct {
> +		u32 perf_cnt0_sel	: 6;
> +		u32 reserved0		: 2;
> +		u32 perf_cnt1_sel	: 6;
> +		u32 reserved1		: 2;
> +		u32 perf_cnt2_sel	: 6;
> +		u32 reserved2		: 10;
> +	} reg68;
> +
> +	u32 perf_cnt0;
> +	u32 perf_cnt1;
> +	u32 perf_cnt2;
> +	u32 ref30_poc;
> +	u32 ref31_poc;
> +	u32 cur_poc1;
> +	u32 errorinfo_base;
> +
> +	struct {
> +		u32 slicedec_num		: 14;
> +		u32 reserved0			: 1;
> +		u32 strmd_detect_error_flag	: 1;
> +		u32 error_packet_num		: 14;
> +		u32 reserved1			: 2;
> +	} reg76;
> +
> +	struct {
> +		u32 error_en_highbits	: 30;

rk3328 has 29:28 as strmd_error_en:
- strmd_error_en[0]: HEVC, H264 slice end error enable
- strmd_error_en[1]: HEVC, H264, VP9 frame end error enable

> +		u32 reserved		: 2;
> +	} reg77;

rk3328 also has following for h264, hevc and vp9:
- reg78_colmv_cur_base
- reg79_colmv_ref0_base
  ...
- reg94_colmv_ref15_base

reg95_scanlist_addr (h264 and hevc)
- 31:4: scanlist_addr
- 0: scanlist_addr_valid_en

- reg96_sd_decout_base
- reg97_sd_y_virstride
- reg98_sd_hor_stride
- reg99_qos_ctrl
- reg100_PERF_*
  ...
- reg107_PERF_*
- reg108_qos1

Not sure we need to define all these here.

> +} __packed;
> +
> +struct rkvdec_vp9_regs {
> +	struct cprheader_offset {
> +		u32 cprheader_offset	: 16;
> +		u32 reserved		: 16;
> +	} reg10;
> +
> +	u32 refer_bases[3];
> +	u32 count_base;
> +	u32 segidlast_base;
> +	u32 segidcur_base;
> +
> +	struct frame_sizes {
> +		u32 framewidth		: 16;
> +		u32 frameheight		: 16;
> +	} reg17_19[3];
> +
> +	struct segid_grp {
> +		u32 segid_abs_delta			: 1;
> +		u32 segid_frame_qp_delta_en		: 1;
> +		u32 segid_frame_qp_delta		: 9;
> +		u32 segid_frame_loopfilter_value_en	: 1;
> +		u32 segid_frame_loopfilter_value	: 7;
> +		u32 segid_referinfo_en			: 1;
> +		u32 segid_referinfo			: 2;
> +		u32 segid_frame_skip_en			: 1;
> +		u32 reserved				: 9;
> +	} reg20_27[8];
> +
> +	struct cprheader_config {
> +		u32 tx_mode			: 3;
> +		u32 frame_reference_mode	: 2;
> +		u32 reserved			: 27;
> +	} reg28;
> +
> +	struct ref_scale {
> +		u32 ref_hor_scale		: 16;
> +		u32 ref_ver_scale		: 16;
> +	} reg29_31[3];
> +
> +	struct ref_deltas_lastframe {
> +		u32 ref_deltas_lastframe0	: 7;
> +		u32 ref_deltas_lastframe1	: 7;
> +		u32 ref_deltas_lastframe2	: 7;
> +		u32 ref_deltas_lastframe3	: 7;
> +		u32 reserved			: 4;
> +	} reg32;
> +
> +	struct info_lastframe {
> +		u32 mode_deltas_lastframe0		: 7;
> +		u32 mode_deltas_lastframe1		: 7;
> +		u32 reserved0				: 2;
> +		u32 segmentation_enable_lstframe	: 1;
> +		u32 last_show_frame			: 1;
> +		u32 last_intra_only			: 1;
> +		u32 last_widthheight_eqcur		: 1;
> +		u32 color_space_lastkeyframe		: 3;
> +		u32 reserved1				: 9;
> +	} reg33;
> +
> +	u32 intercmd_base;
> +
> +	struct intercmd_num {
> +		u32 intercmd_num	: 24;
> +		u32 reserved		: 8;
> +	} reg35;
> +
> +	struct lasttile_size {
> +		u32 lasttile_size	: 24;
> +		u32 reserved		: 8;
> +	} reg36;
> +
> +	struct hor_virstride {
> +		u32 y_hor_virstride	: 9;
> +		u32 reserved0		: 7;
> +		u32 uv_hor_virstride	: 9;
> +		u32 reserved1		: 7;
> +	} reg37_39[3];
> +
> +	u32 cur_poc;
> +
> +	struct rlcwrite_base {
> +		u32 reserved		: 3;
> +		u32 rlcwrite_base	: 29;
> +	} reg41;
> +
> +	struct pps_base {
> +		u32 reserved	: 4;
> +		u32 pps_base	: 28;
> +	} reg42;
> +
> +	struct rps_base {
> +		u32 reserved	: 4;
> +		u32 rps_base	: 28;
> +	} reg43;
> +
> +	struct strmd_error_en {
> +		u32 strmd_error_e	: 28;
> +		u32 reserved		: 4;
> +	} reg44;
> +
> +	u32 vp9_error_info0;
> +
> +	struct strmd_error_ctu {
> +		u32 strmd_error_ctu_xoffset	: 8;
> +		u32 strmd_error_ctu_yoffset	: 8;
> +		u32 streamfifo_space2full	: 7;
> +		u32 reserved0			: 1;
> +		u32 error_ctu0_en		: 1;
> +		u32 reserved1			: 7;
> +	} reg46;
> +
> +	struct sao_ctu_position {
> +		u32 saowr_xoffet	: 9;
> +		u32 reserved0		: 7;
> +		u32 saowr_yoffset	: 10;
> +		u32 reserved1		: 6;
> +	} reg47;
> +
> +	struct ystride {
> +		u32 virstride	: 20;
> +		u32 reserved	: 12;
> +	} reg48_50[3];
> +
> +	struct lastref_yuvstride {
> +		u32 lastref_yuv_virstride	: 21;
> +		u32 reserved			: 11;
> +	} reg51;
> +
> +	u32 refcolmv_base;
> +
> +	u32 reserved0[11];
> +
> +	u32 performance_cycle;
> +	u32 axi_ddr_rdata;
> +	u32 axi_ddr_wdata;
> +
> +	struct fpgadebug_reset {
> +		u32 busifd_resetn	: 1;
> +		u32 cabac_resetn	: 1;
> +		u32 dec_ctrl_resetn	: 1;
> +		u32 transd_resetn	: 1;
> +		u32 intra_resetn	: 1;
> +		u32 inter_resetn	: 1;
> +		u32 recon_resetn	: 1;
> +		u32 filer_resetn	: 1;
> +		u32 reserved		: 24;
> +	} reg67;
> +
> +	struct performance_sel {
> +		u32 perf_cnt0_sel	: 6;
> +		u32 reserved0		: 2;
> +		u32 perf_cnt1_sel	: 6;
> +		u32 reserved1		: 2;
> +		u32 perf_cnt2_sel	: 6;
> +		u32 reserved		: 10;
> +	} reg68;
> +
> +	u32 perf_cnt0;
> +	u32 perf_cnt1;
> +	u32 perf_cnt2;
> +
> +	u32 reserved1[3];
> +
> +	u32 vp9_error_info1;
> +
> +	struct error_ctu1 {
> +		u32 vp9_error_ctu1_x	: 6;
> +		u32 reserved0		: 2;
> +		u32 vp9_error_ctu1_y	: 6;
> +		u32 reserved1		: 1;
> +		u32 vp9_error_ctu1_en	: 1;
> +		u32 reserved2		: 16;
> +	} reg76;
> +
> +	u32 reserved2;
> +} __packed;
> +
> +struct rkvdec_regs {
> +	struct rkvdec_common_regs common;
> +	union {
> +		struct rkvdec_h26x_regs h26x;
> +		struct rkvdec_vp9_regs  vp9;
> +	};
> +} __packed;
> +
>  #endif /* RKVDEC_REGS_H_ */
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
> index b4bf01e839ef..0cf5a559701c 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
> @@ -163,6 +163,7 @@ struct rkvdec_vp9_ctx {
>  	struct v4l2_vp9_frame_context frame_context[4];
>  	struct rkvdec_vp9_frame_info cur;
>  	struct rkvdec_vp9_frame_info last;
> +	struct rkvdec_regs regs;
>  };
>  
>  static void write_coeff_plane(const u8 coef[6][6][3], u8 *coeff_plane)
> @@ -347,38 +348,6 @@ static void init_probs(struct rkvdec_ctx *ctx,
>  		init_inter_probs(ctx, run);
>  }
>  
> -struct rkvdec_vp9_ref_reg {
> -	u32 reg_frm_size;
> -	u32 reg_hor_stride;
> -	u32 reg_y_stride;
> -	u32 reg_yuv_stride;
> -	u32 reg_ref_base;
> -};
> -
> -static struct rkvdec_vp9_ref_reg ref_regs[] = {
> -	{
> -		.reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(0),
> -		.reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(0),
> -		.reg_y_stride = RKVDEC_VP9_LAST_FRAME_YSTRIDE,
> -		.reg_yuv_stride = RKVDEC_VP9_LAST_FRAME_YUVSTRIDE,
> -		.reg_ref_base = RKVDEC_REG_VP9_LAST_FRAME_BASE,
> -	},
> -	{
> -		.reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(1),
> -		.reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(1),
> -		.reg_y_stride = RKVDEC_VP9_GOLDEN_FRAME_YSTRIDE,
> -		.reg_yuv_stride = 0,
> -		.reg_ref_base = RKVDEC_REG_VP9_GOLDEN_FRAME_BASE,
> -	},
> -	{
> -		.reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(2),
> -		.reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(2),
> -		.reg_y_stride = RKVDEC_VP9_ALTREF_FRAME_YSTRIDE,
> -		.reg_yuv_stride = 0,
> -		.reg_ref_base = RKVDEC_REG_VP9_ALTREF_FRAME_BASE,
> -	}
> -};
> -
>  static struct rkvdec_decoded_buffer *
>  get_ref_buf(struct rkvdec_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp)
>  {
> @@ -412,18 +381,17 @@ static dma_addr_t get_mv_base_addr(struct rkvdec_decoded_buffer *buf)
>  static void config_ref_registers(struct rkvdec_ctx *ctx,
>  				 const struct rkvdec_vp9_run *run,
>  				 struct rkvdec_decoded_buffer *ref_buf,
> -				 struct rkvdec_vp9_ref_reg *ref_reg)
> +				 int i)
>  {
>  	unsigned int aligned_pitch, aligned_height, y_len, yuv_len;
> -	struct rkvdec_dev *rkvdec = ctx->dev;
> +	struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
> +	struct rkvdec_regs *regs = &vp9_ctx->regs;
>  
>  	aligned_height = round_up(ref_buf->vp9.height, 64);
> -	writel_relaxed(RKVDEC_VP9_FRAMEWIDTH(ref_buf->vp9.width) |
> -		       RKVDEC_VP9_FRAMEHEIGHT(ref_buf->vp9.height),
> -		       rkvdec->regs + ref_reg->reg_frm_size);
> +	regs->vp9.reg17_19[i].frameheight = ref_buf->vp9.height;
> +	regs->vp9.reg17_19[i].framewidth = ref_buf->vp9.width;
>  
> -	writel_relaxed(vb2_dma_contig_plane_dma_addr(&ref_buf->base.vb.vb2_buf, 0),
> -		       rkvdec->regs + ref_reg->reg_ref_base);
> +	regs->vp9.refer_bases[i] = vb2_dma_contig_plane_dma_addr(&ref_buf->base.vb.vb2_buf, 0);
>  
>  	if (&ref_buf->base.vb == run->base.bufs.dst)
>  		return;
> @@ -432,59 +400,50 @@ static void config_ref_registers(struct rkvdec_ctx *ctx,
>  	y_len = aligned_height * aligned_pitch;
>  	yuv_len = (y_len * 3) / 2;
>  
> -	writel_relaxed(RKVDEC_HOR_Y_VIRSTRIDE(aligned_pitch / 16) |
> -		       RKVDEC_HOR_UV_VIRSTRIDE(aligned_pitch / 16),
> -		       rkvdec->regs + ref_reg->reg_hor_stride);
> -	writel_relaxed(RKVDEC_VP9_REF_YSTRIDE(y_len / 16),
> -		       rkvdec->regs + ref_reg->reg_y_stride);
> -
> -	if (!ref_reg->reg_yuv_stride)
> -		return;
> +	regs->vp9.reg37_39[i].y_hor_virstride = aligned_pitch / 16;
> +	regs->vp9.reg37_39[i].uv_hor_virstride = aligned_pitch / 16;
> +	regs->vp9.reg48_50[i].virstride = y_len / 16;
>  
> -	writel_relaxed(RKVDEC_VP9_REF_YUVSTRIDE(yuv_len / 16),
> -		       rkvdec->regs + ref_reg->reg_yuv_stride);
> +	if (!i)
> +		regs->vp9.reg51.lastref_yuv_virstride = yuv_len / 16;
>  }
>  
>  static void config_seg_registers(struct rkvdec_ctx *ctx, unsigned int segid)
>  {
>  	struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
> +	struct rkvdec_regs *regs = &vp9_ctx->regs;
>  	const struct v4l2_vp9_segmentation *seg;
> -	struct rkvdec_dev *rkvdec = ctx->dev;
>  	s16 feature_val;
>  	int feature_id;
> -	u32 val = 0;
>  
>  	seg = vp9_ctx->last.valid ? &vp9_ctx->last.seg : &vp9_ctx->cur.seg;
>  	feature_id = V4L2_VP9_SEG_LVL_ALT_Q;
>  	if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid)) {
>  		feature_val = seg->feature_data[segid][feature_id];
> -		val |= RKVDEC_SEGID_FRAME_QP_DELTA_EN(1) |
> -		       RKVDEC_SEGID_FRAME_QP_DELTA(feature_val);
> +		regs->vp9.reg20_27[segid].segid_frame_qp_delta_en = 1;
> +		regs->vp9.reg20_27[segid].segid_frame_qp_delta = feature_val;
>  	}
>  
>  	feature_id = V4L2_VP9_SEG_LVL_ALT_L;
>  	if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid)) {
>  		feature_val = seg->feature_data[segid][feature_id];
> -		val |= RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE_EN(1) |
> -		       RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE(feature_val);
> +		regs->vp9.reg20_27[segid].segid_frame_loopfilter_value_en = 1;
> +		regs->vp9.reg20_27[segid].segid_frame_loopfilter_value = feature_val;
>  	}
>  
>  	feature_id = V4L2_VP9_SEG_LVL_REF_FRAME;
>  	if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid)) {
>  		feature_val = seg->feature_data[segid][feature_id];
> -		val |= RKVDEC_SEGID_REFERINFO_EN(1) |
> -		       RKVDEC_SEGID_REFERINFO(feature_val);
> +		regs->vp9.reg20_27[segid].segid_referinfo_en = 1;
> +		regs->vp9.reg20_27[segid].segid_referinfo = feature_val;
>  	}
>  
>  	feature_id = V4L2_VP9_SEG_LVL_SKIP;
> -	if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid))
> -		val |= RKVDEC_SEGID_FRAME_SKIP_EN(1);
> -
> -	if (!segid &&
> -	    (seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE))
> -		val |= RKVDEC_SEGID_ABS_DELTA(1);
> +	regs->vp9.reg20_27[segid].segid_frame_skip_en =
> +		v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid);
>  
> -	writel_relaxed(val, rkvdec->regs + RKVDEC_VP9_SEGID_GRP(segid));
> +	regs->vp9.reg20_27[segid].segid_abs_delta = !segid &&
> +		(seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE);
>  }
>  
>  static void update_dec_buf_info(struct rkvdec_decoded_buffer *buf,
> @@ -521,7 +480,8 @@ static void config_registers(struct rkvdec_ctx *ctx,
>  	struct rkvdec_decoded_buffer *ref_bufs[3];
>  	struct rkvdec_decoded_buffer *dst, *last, *mv_ref;
>  	struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
> -	u32 val, last_frame_info = 0;
> +	struct rkvdec_regs *regs = &vp9_ctx->regs;
> +	u32 val;
>  	const struct v4l2_vp9_segmentation *seg;
>  	struct rkvdec_dev *rkvdec = ctx->dev;
>  	dma_addr_t addr;
> @@ -547,8 +507,7 @@ static void config_registers(struct rkvdec_ctx *ctx,
>  			(V4L2_VP9_FRAME_FLAG_KEY_FRAME |
>  			 V4L2_VP9_FRAME_FLAG_INTRA_ONLY));
>  
> -	writel_relaxed(RKVDEC_MODE(RKVDEC_MODE_VP9),
> -		       rkvdec->regs + RKVDEC_REG_SYSCTRL);
> +	regs->common.reg02.dec_mode = RKVDEC_MODE_VP9;
>  
>  	bit_depth = dec_params->bit_depth;
>  	aligned_height = round_up(ctx->decoded_fmt.fmt.pix_mp.height, 64);
> @@ -560,17 +519,14 @@ static void config_registers(struct rkvdec_ctx *ctx,
>  	uv_len = y_len / 2;
>  	yuv_len = y_len + uv_len;
>  
> -	writel_relaxed(RKVDEC_Y_HOR_VIRSTRIDE(aligned_pitch / 16) |
> -		       RKVDEC_UV_HOR_VIRSTRIDE(aligned_pitch / 16),
> -		       rkvdec->regs + RKVDEC_REG_PICPAR);
> -	writel_relaxed(RKVDEC_Y_VIRSTRIDE(y_len / 16),
> -		       rkvdec->regs + RKVDEC_REG_Y_VIRSTRIDE);
> -	writel_relaxed(RKVDEC_YUV_VIRSTRIDE(yuv_len / 16),
> -		       rkvdec->regs + RKVDEC_REG_YUV_VIRSTRIDE);
> +	regs->common.reg03.y_hor_virstride = aligned_pitch / 16;
> +	regs->common.reg03.uv_hor_virstride = aligned_pitch / 16;
> +	regs->common.reg08.y_virstride = y_len / 16;
> +	regs->common.reg09.yuv_virstride = yuv_len / 16;
>  
>  	stream_len = vb2_get_plane_payload(&run->base.bufs.src->vb2_buf, 0);
> -	writel_relaxed(RKVDEC_STRM_LEN(stream_len),
> -		       rkvdec->regs + RKVDEC_REG_STRM_LEN);
> +
> +	regs->common.stream_len = stream_len;
>  
>  	/*
>  	 * Reset count buffer, because decoder only output intra related syntax
> @@ -588,14 +544,13 @@ static void config_registers(struct rkvdec_ctx *ctx,
>  		vp9_ctx->cur.segmapid++;
>  
>  	for (i = 0; i < ARRAY_SIZE(ref_bufs); i++)
> -		config_ref_registers(ctx, run, ref_bufs[i], &ref_regs[i]);
> +		config_ref_registers(ctx, run, ref_bufs[i], i);
>  
>  	for (i = 0; i < 8; i++)
>  		config_seg_registers(ctx, i);
>  
> -	writel_relaxed(RKVDEC_VP9_TX_MODE(vp9_ctx->cur.tx_mode) |
> -		       RKVDEC_VP9_FRAME_REF_MODE(dec_params->reference_mode),
> -		       rkvdec->regs + RKVDEC_VP9_CPRHEADER_CONFIG);
> +	regs->vp9.reg28.tx_mode = vp9_ctx->cur.tx_mode;
> +	regs->vp9.reg28.frame_reference_mode = dec_params->reference_mode;
>  
>  	if (!intra_only) {
>  		const struct v4l2_vp9_loop_filter *lf;
> @@ -609,43 +564,56 @@ static void config_registers(struct rkvdec_ctx *ctx,
>  		val = 0;
>  		for (i = 0; i < ARRAY_SIZE(lf->ref_deltas); i++) {
>  			delta = lf->ref_deltas[i];
> -			val |= RKVDEC_REF_DELTAS_LASTFRAME(i, delta);
> +			switch (i) {
> +			case 0:
> +				regs->vp9.reg32.ref_deltas_lastframe0 = delta;
> +				break;
> +			case 1:
> +				regs->vp9.reg32.ref_deltas_lastframe1 = delta;
> +				break;
> +			case 2:
> +				regs->vp9.reg32.ref_deltas_lastframe2 = delta;
> +				break;
> +			case 3:
> +				regs->vp9.reg32.ref_deltas_lastframe3 = delta;
> +				break;
> +			}
>  		}
>  
> -		writel_relaxed(val,
> -			       rkvdec->regs + RKVDEC_VP9_REF_DELTAS_LASTFRAME);
> -
>  		for (i = 0; i < ARRAY_SIZE(lf->mode_deltas); i++) {
>  			delta = lf->mode_deltas[i];
> -			last_frame_info |= RKVDEC_MODE_DELTAS_LASTFRAME(i,
> -									delta);
> +			switch (i) {
> +			case 0:
> +				regs->vp9.reg33.mode_deltas_lastframe0 = delta;
> +				break;
> +			case 1:
> +				regs->vp9.reg33.mode_deltas_lastframe1 = delta;
> +				break;
> +			}
>  		}
>  	}
>  
> -	if (vp9_ctx->last.valid && !intra_only &&
> -	    vp9_ctx->last.seg.flags & V4L2_VP9_SEGMENTATION_FLAG_ENABLED)
> -		last_frame_info |= RKVDEC_SEG_EN_LASTFRAME;
> +	regs->vp9.reg33.segmentation_enable_lstframe =
> +		vp9_ctx->last.valid && !intra_only &&
> +		vp9_ctx->last.seg.flags & V4L2_VP9_SEGMENTATION_FLAG_ENABLED;
>  
> -	if (vp9_ctx->last.valid &&
> -	    vp9_ctx->last.flags & V4L2_VP9_FRAME_FLAG_SHOW_FRAME)
> -		last_frame_info |= RKVDEC_LAST_SHOW_FRAME;
> +	regs->vp9.reg33.last_show_frame =
> +		vp9_ctx->last.valid &&
> +		vp9_ctx->last.flags & V4L2_VP9_FRAME_FLAG_SHOW_FRAME;
>  
> -	if (vp9_ctx->last.valid &&
> -	    vp9_ctx->last.flags &
> -	    (V4L2_VP9_FRAME_FLAG_KEY_FRAME | V4L2_VP9_FRAME_FLAG_INTRA_ONLY))
> -		last_frame_info |= RKVDEC_LAST_INTRA_ONLY;
> +	regs->vp9.reg33.last_intra_only =
> +		vp9_ctx->last.valid &&
> +		vp9_ctx->last.flags &
> +		(V4L2_VP9_FRAME_FLAG_KEY_FRAME | V4L2_VP9_FRAME_FLAG_INTRA_ONLY);
>  
> -	if (vp9_ctx->last.valid &&
> -	    last->vp9.width == dst->vp9.width &&
> -	    last->vp9.height == dst->vp9.height)
> -		last_frame_info |= RKVDEC_LAST_WIDHHEIGHT_EQCUR;
> +	regs->vp9.reg33.last_widthheight_eqcur =
> +		vp9_ctx->last.valid &&
> +		last->vp9.width == dst->vp9.width &&
> +		last->vp9.height == dst->vp9.height;
>  
> -	writel_relaxed(last_frame_info,
> -		       rkvdec->regs + RKVDEC_VP9_INFO_LASTFRAME);
> -
> -	writel_relaxed(stream_len - dec_params->compressed_header_size -
> -		       dec_params->uncompressed_header_size,
> -		       rkvdec->regs + RKVDEC_VP9_LASTTILE_SIZE);
> +	regs->vp9.reg36.lasttile_size =
> +		stream_len - dec_params->compressed_header_size -
> +		dec_params->uncompressed_header_size;
>  
>  	for (i = 0; !intra_only && i < ARRAY_SIZE(ref_bufs); i++) {
>  		unsigned int refw = ref_bufs[i]->vp9.width;
> @@ -654,29 +622,28 @@ static void config_registers(struct rkvdec_ctx *ctx,
>  
>  		hscale = (refw << 14) /	dst->vp9.width;
>  		vscale = (refh << 14) / dst->vp9.height;
> -		writel_relaxed(RKVDEC_VP9_REF_HOR_SCALE(hscale) |
> -			       RKVDEC_VP9_REF_VER_SCALE(vscale),
> -			       rkvdec->regs + RKVDEC_VP9_REF_SCALE(i));
> +
> +		regs->vp9.reg29_31[i].ref_hor_scale = hscale;
> +		regs->vp9.reg29_31[i].ref_ver_scale = vscale;
>  	}
>  
>  	addr = vb2_dma_contig_plane_dma_addr(&dst->base.vb.vb2_buf, 0);
> -	writel_relaxed(addr, rkvdec->regs + RKVDEC_REG_DECOUT_BASE);
> +	regs->common.decout_base = addr;
>  	addr = vb2_dma_contig_plane_dma_addr(&run->base.bufs.src->vb2_buf, 0);
> -	writel_relaxed(addr, rkvdec->regs + RKVDEC_REG_STRM_RLC_BASE);
> -	writel_relaxed(vp9_ctx->priv_tbl.dma +
> -		       offsetof(struct rkvdec_vp9_priv_tbl, probs),
> -		       rkvdec->regs + RKVDEC_REG_CABACTBL_PROB_BASE);
> -	writel_relaxed(vp9_ctx->count_tbl.dma,
> -		       rkvdec->regs + RKVDEC_REG_VP9COUNT_BASE);
> -
> -	writel_relaxed(vp9_ctx->priv_tbl.dma +
> -		       offsetof(struct rkvdec_vp9_priv_tbl, segmap) +
> -		       (RKVDEC_VP9_MAX_SEGMAP_SIZE * vp9_ctx->cur.segmapid),
> -		       rkvdec->regs + RKVDEC_REG_VP9_SEGIDCUR_BASE);
> -	writel_relaxed(vp9_ctx->priv_tbl.dma +
> -		       offsetof(struct rkvdec_vp9_priv_tbl, segmap) +
> -		       (RKVDEC_VP9_MAX_SEGMAP_SIZE * (!vp9_ctx->cur.segmapid)),
> -		       rkvdec->regs + RKVDEC_REG_VP9_SEGIDLAST_BASE);
> +	regs->common.strm_rlc_base = addr;
> +
> +	regs->common.cabactbl_base = vp9_ctx->priv_tbl.dma +
> +		offsetof(struct rkvdec_vp9_priv_tbl, probs);
> +
> +	regs->vp9.count_base = vp9_ctx->count_tbl.dma;
> +
> +	regs->vp9.segidlast_base = vp9_ctx->priv_tbl.dma +
> +		offsetof(struct rkvdec_vp9_priv_tbl, segmap) +
> +		(RKVDEC_VP9_MAX_SEGMAP_SIZE * (!vp9_ctx->cur.segmapid));
> +
> +	regs->vp9.segidcur_base = vp9_ctx->priv_tbl.dma +
> +		offsetof(struct rkvdec_vp9_priv_tbl, segmap) +
> +		(RKVDEC_VP9_MAX_SEGMAP_SIZE * vp9_ctx->cur.segmapid);
>  
>  	if (!intra_only &&
>  	    !(dec_params->flags & V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT) &&
> @@ -685,12 +652,14 @@ static void config_registers(struct rkvdec_ctx *ctx,
>  	else
>  		mv_ref = dst;
>  
> -	writel_relaxed(get_mv_base_addr(mv_ref),
> -		       rkvdec->regs + RKVDEC_VP9_REF_COLMV_BASE);
> +	regs->vp9.refcolmv_base = get_mv_base_addr(mv_ref);
>  
> -	writel_relaxed(ctx->decoded_fmt.fmt.pix_mp.width |
> -		       (ctx->decoded_fmt.fmt.pix_mp.height << 16),
> -		       rkvdec->regs + RKVDEC_REG_PERFORMANCE_CYCLE);
> +	regs->vp9.performance_cycle = ctx->decoded_fmt.fmt.pix_mp.width |
> +		       (ctx->decoded_fmt.fmt.pix_mp.height << 16);
> +
> +	regs->vp9.reg44.strmd_error_e = 0xe;
> +
> +	rkvdec_memcpy_toio(rkvdec->regs, regs, MIN(sizeof(*regs), rkvdec->variant->num_regs));

This is missing the 4 * on num_regs.

Btw, please add me to cc for next version :-)

Regards,
Jonas

>  }
>  
>  static int validate_dec_params(struct rkvdec_ctx *ctx,
> @@ -823,8 +792,6 @@ static int rkvdec_vp9_run(struct rkvdec_ctx *ctx)
>  	writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND);
>  	writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);
>  
> -	writel(0xe, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN);
> -
>  	if (rkvdec->variant->quirks & RKVDEC_QUIRK_DISABLE_QOS)
>  		rkvdec_quirks_disable_qos(ctx);
>  
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> index 5af9aa5ab353..776149f871b0 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> @@ -914,6 +914,15 @@ void rkvdec_quirks_disable_qos(struct rkvdec_ctx *ctx)
>  	writel(reg, rkvdec->regs + RKVDEC_REG_QOS_CTRL);
>  }
>  
> +void rkvdec_memcpy_toio(void __iomem *dst, void *src, size_t len)
> +{
> +#ifdef CONFIG_ARM64
> +	__iowrite32_copy(dst, src, len / 4);
> +#else
> +	memcpy_toio(dst, src, len);
> +#endif
> +}
> +
>  static void rkvdec_device_run(void *priv)
>  {
>  	struct rkvdec_ctx *ctx = priv;
> @@ -1227,7 +1236,6 @@ static void rkvdec_watchdog_func(struct work_struct *work)
>  	if (ctx) {
>  		dev_err(rkvdec->dev, "Frame processing timed out!\n");
>  		writel(RKVDEC_IRQ_DIS, rkvdec->regs + RKVDEC_REG_INTERRUPT);
> -		writel(0, rkvdec->regs + RKVDEC_REG_SYSCTRL);
>  		rkvdec_job_finish(ctx, VB2_BUF_STATE_ERROR);
>  	}
>  }
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> index 566e06fa2b1e..f35f6e80ea2e 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> @@ -151,6 +151,7 @@ struct rkvdec_aux_buf {
>  
>  void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run);
>  void rkvdec_run_postamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run);
> +void rkvdec_memcpy_toio(void __iomem *dst, void *src, size_t len);
>  
>  void rkvdec_quirks_disable_qos(struct rkvdec_ctx *ctx);
>  



From mathieu.poirier at linaro.org  Wed Dec 17 15:19:04 2025
From: mathieu.poirier at linaro.org (Mathieu Poirier)
Date: Wed, 17 Dec 2025 16:19:04 -0700
Subject: [PATCH v4 4/5] remoteproc: imx_rproc: Add support for System
 Manager API
In-Reply-To: <20251216-imx95-rproc-2025-12-15-v4-4-bf1064ea8daf@nxp.com>
References: <20251216-imx95-rproc-2025-12-15-v4-0-bf1064ea8daf@nxp.com>
 <20251216-imx95-rproc-2025-12-15-v4-4-bf1064ea8daf@nxp.com>
Message-ID: <aUM6aGbSH9ICOL5f@p14s>

On Tue, Dec 16, 2025 at 09:51:02AM +0800, Peng Fan (OSS) wrote:
> From: Peng Fan <peng.fan at nxp.com>
> 
> i.MX95 features a Cortex-M33 core, six Cortex-A55 cores, and
> one Cortex-M7 core. The System Control Management Interface(SCMI)
> firmware runs on the M33 core. The i.MX95 SCMI firmware named System
> Manager(SM) includes vendor extension protocols, Logical Machine
> Management(LMM) protocol and CPU protocol and etc.
> 
> Depending on SM configuration, M7 can be used as follows:
>  (1) M7 in a separate Logical Machine (LM) from A55 cores, that Linux
>      can't control
>  (2) M7 in a separate LM from A55 cores that Linux can control using LMM
>      protocol.
>  (3) M7 runs in same Logical Machine as A55 cores, so Linux can control it
>      using CPU protocol
> 
> So extend the driver to using LMM and CPU protocol to manage the M7 core.
>  - Compare linux LM ID(got using scmi_imx_lmm_info) and M7 LM ID(the ID
>    is fixed as 1 in SM firmware if M7 is in a separate LM),
>    if Linux LM ID equals M7 LM ID(linux and M7 in same LM), use CPU
>    protocol to start/stop. Otherwise, use LMM protocol to start/stop.
>    Whether using CPU or LMM protocol to start/stop, the M7 status
>    detection could use CPU protocol to detect started or not. So
>    in imx_rproc_detect_mode, use scmi_imx_cpu_started to check the
>    status of M7.
>  - For above case (1) and (2), Use SCMI_IMX_LMM_POWER_ON to detect whether
>    the M7 LM is under control of A55 LM.
>  - For above case , after using SCMI_IMX_LMM_POWER_ON to check
>    permission, SCMI_IMX_LMM_SHUTDOWN API should be called to shutdown
>    the M7 LM to save power only when M7 LM is going to be started by
>    remoteproc framework. Otherwise bypass SCMI_IMX_LMM_SHUTDOWN API if
>    M7 LM is started before booting Linux.
> 
> Current setup relies on pre-Linux software(U-Boot) to do M7 TCM ECC
> initialization. In future, we could add the support in Linux to decouple
> U-Boot and Linux.
> 
> Signed-off-by: Peng Fan <peng.fan at nxp.com>
> ---
>  drivers/remoteproc/Kconfig     |   2 +
>  drivers/remoteproc/imx_rproc.c | 193 +++++++++++++++++++++++++++++++++++++++++
>  drivers/remoteproc/imx_rproc.h |   3 +
>  3 files changed, 198 insertions(+)
> 
> diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
> index 48a0d3a69ed08057716f1e7ea950899f60bbe0cf..ee54436fea5ad08a9c198ce74d44ce7a9aa206de 100644
> --- a/drivers/remoteproc/Kconfig
> +++ b/drivers/remoteproc/Kconfig
> @@ -27,6 +27,8 @@ config IMX_REMOTEPROC
>  	tristate "i.MX remoteproc support"
>  	depends on ARCH_MXC
>  	depends on HAVE_ARM_SMCCC
> +	depends on IMX_SCMI_CPU_DRV || !IMX_SCMI_CPU_DRV
> +	depends on IMX_SCMI_LMM_DRV || !IMX_SCMI_LMM_DRV
>  	select MAILBOX
>  	help
>  	  Say y here to support iMX's remote processors via the remote
> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
> index 35585235c683e6327c3e6db65d5d33253ffba327..55e555f2b5dd63e7d82996437e792a8152c91521 100644
> --- a/drivers/remoteproc/imx_rproc.c
> +++ b/drivers/remoteproc/imx_rproc.c
> @@ -8,6 +8,7 @@
>  #include <linux/clk.h>
>  #include <linux/err.h>
>  #include <linux/firmware/imx/sci.h>
> +#include <linux/firmware/imx/sm.h>
>  #include <linux/interrupt.h>
>  #include <linux/kernel.h>
>  #include <linux/mailbox_client.h>
> @@ -22,6 +23,7 @@
>  #include <linux/reboot.h>
>  #include <linux/regmap.h>
>  #include <linux/remoteproc.h>
> +#include <linux/scmi_imx_protocol.h>
>  #include <linux/workqueue.h>
>  
>  #include "imx_rproc.h"
> @@ -92,8 +94,12 @@ struct imx_rproc_mem {
>  #define ATT_CORE_MASK   0xffff
>  #define ATT_CORE(I)     BIT((I))
>  
> +/* Linux has permission to handle the Logical Machine of remote cores */
> +#define IMX_RPROC_FLAGS_SM_LMM_AVAIL	BIT(0)
> +
>  static int imx_rproc_xtr_mbox_init(struct rproc *rproc, bool tx_block);
>  static void imx_rproc_free_mbox(void *data);
> +static int imx_rproc_sm_detect_mode(struct rproc *rproc);
>  
>  struct imx_rproc {
>  	struct device			*dev;
> @@ -117,6 +123,11 @@ struct imx_rproc {
>  	u32				core_index;
>  	struct dev_pm_domain_list	*pd_list;
>  	const struct imx_rproc_plat_ops	*ops;
> +	/*
> +	 * For i.MX System Manager based systems
> +	 * BIT 0: IMX_RPROC_FLAGS_SM_LMM_AVAIL(RPROC LM is under Linux control )
> +	 */
> +	u32				flags;
>  };
>  
>  static const struct imx_rproc_att imx_rproc_att_imx93[] = {
> @@ -313,6 +324,44 @@ static int imx_rproc_scu_api_start(struct rproc *rproc)
>  	return imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, true, priv->entry);
>  }
>  
> +static int imx_rproc_sm_cpu_start(struct rproc *rproc)
> +{
> +	struct imx_rproc *priv = rproc->priv;
> +	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
> +	int ret;
> +
> +	ret = scmi_imx_cpu_reset_vector_set(dcfg->cpuid, 0, true, false, false);
> +	if (ret) {
> +		dev_err(priv->dev, "Failed to set reset vector cpuid(%u): %d\n", dcfg->cpuid, ret);
> +		return ret;
> +	}
> +
> +	return scmi_imx_cpu_start(dcfg->cpuid, true);
> +}
> +
> +static int imx_rproc_sm_lmm_start(struct rproc *rproc)
> +{
> +	struct imx_rproc *priv = rproc->priv;
> +	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
> +	struct device *dev = priv->dev;
> +	int ret;
> +
> +	ret = scmi_imx_lmm_reset_vector_set(dcfg->lmid, dcfg->cpuid, 0, 0);
> +	if (ret) {
> +		dev_err(dev, "Failed to set reset vector lmid(%u), cpuid(%u): %d\n",
> +			dcfg->lmid, dcfg->cpuid, ret);
> +		return ret;
> +	}
> +
> +	ret = scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_BOOT, 0);
> +	if (ret) {
> +		dev_err(dev, "Failed to boot lmm(%d): %d\n", dcfg->lmid, ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
>  static int imx_rproc_start(struct rproc *rproc)
>  {
>  	struct imx_rproc *priv = rproc->priv;
> @@ -369,6 +418,25 @@ static int imx_rproc_scu_api_stop(struct rproc *rproc)
>  	return imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, false, priv->entry);
>  }
>  
> +static int imx_rproc_sm_cpu_stop(struct rproc *rproc)
> +{
> +	struct imx_rproc *priv = rproc->priv;
> +	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
> +
> +	return scmi_imx_cpu_start(dcfg->cpuid, false);
> +}
> +
> +static int imx_rproc_sm_lmm_stop(struct rproc *rproc)
> +{
> +	struct imx_rproc *priv = rproc->priv;
> +	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
> +
> +	if (!(priv->flags & IMX_RPROC_FLAGS_SM_LMM_AVAIL))
> +		return -EACCES;
> +
> +	return scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_SHUTDOWN, 0);
> +}
> +
>  static int imx_rproc_stop(struct rproc *rproc)
>  {
>  	struct imx_rproc *priv = rproc->priv;
> @@ -485,6 +553,33 @@ static int imx_rproc_mem_release(struct rproc *rproc,
>  	return 0;
>  }
>  
> +static int imx_rproc_sm_lmm_prepare(struct rproc *rproc)
> +{
> +	struct imx_rproc *priv = rproc->priv;
> +	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
> +	int ret;
> +
> +	/*
> +	 * IMX_RPROC_FLAGS_SM_LMM_AVAIL not set indicates Linux is not able
> +	 * to start/stop rproc LM, then if rproc is not in detached state,
> +	 * prepare should fail. If in detached state, this is in rproc_attach()
> +	 * path.
> +	 */
> +	if (!(priv->flags & IMX_RPROC_FLAGS_SM_LMM_AVAIL))
> +		return rproc->state == RPROC_DETACHED ? 0 : -EACCES;
> +
> +	/* Power on the Logical Machine to make sure TCM is available. */
> +	ret = scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_POWER_ON, 0);
> +	if (ret) {
> +		dev_err(priv->dev, "Failed to power on lmm(%d): %d\n", dcfg->lmid, ret);
> +		return ret;
> +	}
> +
> +	dev_info(priv->dev, "lmm(%d) powered on by Linux\n", dcfg->lmid);
> +
> +	return 0;
> +}
> +
>  static int imx_rproc_prepare(struct rproc *rproc)
>  {
>  	struct imx_rproc *priv = rproc->priv;
> @@ -980,6 +1075,104 @@ static int imx_rproc_scu_api_detect_mode(struct rproc *rproc)
>  	return 0;
>  }
>  
> +static const struct imx_rproc_plat_ops imx_rproc_ops_sm_lmm = {
> +	.detect_mode	= imx_rproc_sm_detect_mode,
> +	.prepare	= imx_rproc_sm_lmm_prepare,
> +	.start		= imx_rproc_sm_lmm_start,
> +	.stop		= imx_rproc_sm_lmm_stop,
> +};
> +
> +static const struct imx_rproc_plat_ops imx_rproc_ops_sm_cpu = {
> +	.detect_mode	= imx_rproc_sm_detect_mode,
> +	.start		= imx_rproc_sm_cpu_start,
> +	.stop		= imx_rproc_sm_cpu_stop,
> +};

Why are these not at the bottom of the file with the rest of the
imx_rproc_plat_ops?  That way you wouldn't have to declare
imx_rproc_sm_detect_mode() at the top of the file...

> +
> +static int imx_rproc_sm_lmm_check(struct rproc *rproc, bool started)
> +{
> +	struct imx_rproc *priv = rproc->priv;
> +	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
> +	struct device *dev = priv->dev;
> +	int ret;
> +
> +	/*
> +	 * Use power on to do permission check. If rproc is in different LM,
> +	 * and linux has permission to handle the LM, set IMX_RPROC_FLAGS_SM_LMM_AVAIL.
> +	 */
> +	ret = scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_POWER_ON, 0);
> +	if (ret) {
> +		if (ret == -EACCES) {
> +			/*
> +			 * rproc LM is booted before Linux and not under Linux Control, so only
> +			 * do IPC between RPROC and Linux, not return failure
> +			 */
> +			dev_info(dev, "lmm(%d) not under Linux Control\n", dcfg->lmid);
> +			return 0;
> +		}
> +
> +		dev_err(dev, "power on lmm(%d) failed: %d\n", dcfg->lmid, ret);
> +		return ret;
> +	}
> +
> +	priv->flags |= IMX_RPROC_FLAGS_SM_LMM_AVAIL;
> +
> +	/* rproc was started before boot Linux and under control of Linux, directly return */
> +	if (started)
> +		return 0;
> +
> +	/* else shutdown the LM to save power */
> +	ret = scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_SHUTDOWN, 0);
> +	if (ret) {
> +		priv->flags &= ~IMX_RPROC_FLAGS_SM_LMM_AVAIL;
> +		dev_err(dev, "shutdown lmm(%d) failed: %d\n", dcfg->lmid, ret);
> +		return ret;
> +	}

If you move this call to scmi_imx_lmm_operation() (and the error check) before
setting priv->flags, you won't have to reset it in the error path.

Let's see how the next revision goes...

Thanks,
Mathieu

> +
> +	return 0;
> +}
> +
> +static int imx_rproc_sm_detect_mode(struct rproc *rproc)
> +{
> +	struct imx_rproc *priv = rproc->priv;
> +	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
> +	struct device *dev = priv->dev;
> +	struct scmi_imx_lmm_info info;
> +	bool started = false;
> +	int ret;
> +
> +	ret = scmi_imx_cpu_started(dcfg->cpuid, &started);
> +	if (ret) {
> +		dev_err(dev, "Failed to detect cpu(%d) status: %d\n", dcfg->cpuid, ret);
> +		return ret;
> +	}
> +
> +	if (started)
> +		priv->rproc->state = RPROC_DETACHED;
> +
> +	/* Get current Linux Logical Machine ID */
> +	ret = scmi_imx_lmm_info(LMM_ID_DISCOVER, &info);
> +	if (ret) {
> +		dev_err(dev, "Failed to get current LMM ID err: %d\n", ret);
> +		return ret;
> +	}
> +
> +	/*
> +	 * Check whether rproc is in the same LM as host core(running Linux)
> +	 * If yes, use CPU protocol API to manage rproc.
> +	 * If no, use Logical Machine API to manage rproc.
> +	 */
> +	if (dcfg->lmid == info.lmid) {
> +		priv->ops = &imx_rproc_ops_sm_cpu;
> +		dev_info(dev, "Using CPU Protocol OPS\n");
> +		return 0;
> +	}
> +
> +	priv->ops = &imx_rproc_ops_sm_lmm;
> +	dev_info(dev, "Using LMM Protocol OPS\n");
> +
> +	return imx_rproc_sm_lmm_check(rproc, started);
> +}
> +
>  static int imx_rproc_detect_mode(struct imx_rproc *priv)
>  {
>  	/*
> diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h
> index 37417568a0ade2ae4d6a4e3d0f139ea52b185254..d37e6f90548cec727b4aeb874680b42af85bdbb4 100644
> --- a/drivers/remoteproc/imx_rproc.h
> +++ b/drivers/remoteproc/imx_rproc.h
> @@ -38,6 +38,9 @@ struct imx_rproc_dcfg {
>  	size_t				att_size;
>  	u32				flags;
>  	const struct imx_rproc_plat_ops	*ops;
> +	/* For System Manager(SM) based SoCs */
> +	u32				cpuid; /* ID of the remote core */
> +	u32				lmid;  /* ID of the Logcial Machine */
>  };
>  
>  #endif /* _IMX_RPROC_H */
> 
> -- 
> 2.37.1
> 


From andrew at codeconstruct.com.au  Wed Dec 17 15:22:16 2025
From: andrew at codeconstruct.com.au (Andrew Jeffery)
Date: Thu, 18 Dec 2025 09:52:16 +1030
Subject: [PATCH] arm: dts: aspeed: add an alt 128M flash layout
In-Reply-To: <aUM5HcEs0OVrDO1w@molberding.nvidia.com>
References: <20251211-alt-128-layout-v1-1-100f57d2bc4a@nvidia.com>
	 <61f561d95af86a46f1e1075df39e1ce0f1324098.camel@codeconstruct.com.au>
	 <aUM5HcEs0OVrDO1w@molberding.nvidia.com>
Message-ID: <bc0904e4742cd04fb49b2d39ee2c0f72f28c1c4a.camel@codeconstruct.com.au>

On Wed, 2025-12-17 at 15:13 -0800, Marc Olberding wrote:
> On Thu, Dec 18, 2025 at 09:29:44AM +1030, Andrew Jeffery wrote:
> > On Thu, 2025-12-11 at 13:35 -0800, Marc Olberding wrote:
> > > Add a 128M layout for the BMC flash chip we didn't boot from.
> > > Including
> > > this allows the user to write to each partition on the alternate spi
> > > chip. This dtsi follows the existing standard of using the same
> > > layout
> > > as non alt version and prepending `alt` to each partition's name.
> > > 
> ... 
> > This may be fine, but please add it in a series that also introduces a
> > board that consumes it.
> > 
> > Andrew
> 
> Ack, I wasn't sure how to handle this, since the MSX4 hasn't merged to
> master for upstream yet, its just been merged into the openbmc tree.

I've applied it:

https://git.kernel.org/pub/scm/linux/kernel/git/bmc/linux.git/commit/?h=aspeed/arm/dt&id=f28674fab34f07fff9612c3f390d3699bfe8ed90

It will be part of v6.20 (via pull-request to the SoC tree).

> I can either just hold off on this patch or update the msx4 series.
> I'm assuming that including this in a patch targetted to the openbmc tree
> is a nonstarter. Any thoughts here?

Send patches based on the bmc tree's aspeed/arm/dt branch (i.e. the
branch containing the commit linked above). Your work is going to land
there anyway, so no need to strictly base your work on Linus' master
branch (though this is generally reasonable when there are no other
dependencies).

Andrew


From nicolinc at nvidia.com  Wed Dec 17 15:24:25 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Wed, 17 Dec 2025 15:24:25 -0800
Subject: [PATCH v8 0/7] iommu/arm-smmu-v3: Introduce an RCU-protected invalidation array
Message-ID: <cover.1766013662.git.nicolinc@nvidia.com>

This is a work based on Jason's design and algorithm. This implementation
follows his initial draft and revising as well.

The new arm_smmu_invs array is an RCU-protected array, mutated when device
attach to the domain, iterated when an invalidation is required for IOPTE
changes in this domain. This keeps the current invalidation efficiency of
a smb_mb() followed by a conditional rwlock replacing the atomic/spinlock
combination.

A new data structure is defined for the array and its entry, representing
invalidation operations, such as S1_ASID, S2_VMID, and ATS. The algorithm
adds and deletes array entries efficiently and also keeps the array sorted
so as to group similar invalidations into batches.

During an invalidation, a new invalidation function iterates domain->invs,
and converts each entry to the corresponding invalidation command(s). This
new function is fully compatible with all the existing use cases, allowing
a simple rework/replacement.

Some races to keep in mind:

1) A domain can be shared across SMMU instances. When an SMMU instance is
   removed, the updated invs array has to be sync-ed via synchronize_rcu()
   to prevent an concurrent invalidation routine that is accessing the old
   array from issuing commands to the removed SMMU instance.

2) When there are concurrent IOPTE changes (followed by invalidations) and
   a domain attachment, the new attachment must not become out of sync at
   the HW level, meaning that an STE store and invalidation array load must
   be sequenced by the CPU's memory model.

3) When an ATS-enabled device attaches to a blocking domain, the core code
   requires a hard fence to ensure all ATS invalidations to the device are
   completed. Relying on RCU alone requires calling synchronize_rcu() that
   can be too slow. Instead, when ATS is in use, hold a conditional rwlock
   till all concurrent invalidations are finished.

Related future work and dependent projects:

 * NVIDIA is building systems with > 10 SMMU instances where > 8 are being
   used concurrently in a single VM. So having 8 copies of an identical S2
   page table is not efficient. Instead, all vSMMU instances should check
   compatibility on a shared S2 iopt, to eliminate 7 copies.

   Previous attempt based on the list/spinlock design:
     iommu/arm-smmu-v3: Allocate vmid per vsmmu instead of s2_parent
     https://lore.kernel.org/all/cover.1744692494.git.nicolinc at nvidia.com/
   now can adopt this invs array, avoiding adding complex lists/locks.

 * The guest support for BTM requires temporarily invalidating two ASIDs
   for a single instance. When it renumbers ASIDs this can now be done via
   the invs array.

 * SVA with multiple devices being used by a single process (NVIDIA today
   has 4-8) sequentially iterates the invalidations through all instances.
   This ignores the HW concurrency available in each instance. It would be
   nice to not spin on each sync but go forward and issue batches to other
   instances also. Reducing to a single SVA domain shared across instances
   is required to look at this.

This is on Github:
https://github.com/nicolinc/iommufd/commits/arm_smmu_invs-v8

Changelog
v8:
 * Update comments for smp_mb() in arm_smmu_install_new/old_domain_invs()
v7:
 https://lore.kernel.org/all/cover.1765850465.git.nicolinc at nvidia.com/
 * Rebase on v6.19-rc1
 * Fix has_ats in arm_smmu_invs_merge()
 * Fix a re-attach case with a different ats_enabled
 * Constify the inv parameter in arm_smmu_inv_is_ats()
 * Update kunit test data to be closer to real-world use cases
 * Clean up SVA domain's invs in arm_smmu_blocking_set_dev_pasid()
v6:
 https://lore.kernel.org/all/cover.1764119291.git.nicolinc at nvidia.com/
 * Fix typo in kdocs
 * Fix arm_smmu_domain_free() in SVA
 * Add arm_smmu_master_build_inv() helper
 * Add max_invs and __counted_by(max_invs)
 * Return NULL if arm_smmu_invs_alloc() fails
 * Sort master->streams instead of fwspec->ids
 * s/flush_fn/free_fn (prepare for future patches)
 * s/arm_smmu_invs_flush_iotlb_tags/arm_smmu_inv_flush_iotlb_tag
 * Define arm_smmu_invs macros and helpers to reduce duplications
 * Save num_trashes in "struct arm_smmu_invs" (to avoid a re-scan)
 * Move smp_mb() in install() to PATCH-6 that adds the pairing barrier
   and description
v5:
 https://lore.kernel.org/all/cover.1762588839.git.nicolinc at nvidia.com/
 * Add Reviewed/Acked-by from Jason and Balbir
 * Add two inline comments
 * Move cmp after the trash entry validation
 * Batch commands in arm_smmu_inv_size_too_big case
 * Replace kfree_rcu() with kfree() in arm_smmu_domain_free()
v4:
 https://lore.kernel.org/all/cover.1761590851.git.nicolinc at nvidia.com/
 * Fix build errors with CONFIG_KUNIT=n
 * Fix uninitialized cmp in arm_smmu_invs_unref()
 * Add missing "__rcu" in struct arm_smmu_inv_state
 * Add missing rcu_derference_protected() in arm_smmu_domain_free()
 * Bisect two paths for the conditional lock in arm_smmu_domain_inv_range()
   to fix a sparse waring
v3:
 https://lore.kernel.org/all/cover.1760555863.git.nicolinc at nvidia.com/
 * Add Reviewed/Acked-by from Jason and Balbir
 * Rebase on v6.18-rc1
 * Drop arm_smmu_invs_dbg()
 * Improve kdocs and inline/commit comments
 * Rename arm_smmu_invs_cmp to arm_smmu_inv_cmp
 * Rename arm_smmu_invs_merge_cmp to arm_smmu_invs_cmp
 * Call arm_smmu_invs_flush_iotlb_tags() from arm_smmu_invs_unref()
 * Unconditionally trim the invs->num_invs inside arm_smmu_invs_unref(),
   and simplify arm_smmu_install_old_domain_invs().
v2:
 https://lore.kernel.org/all/cover.1757373449.git.nicolinc at nvidia.com/
 * Rebase on v6.17-rc5
 * Improve kdocs and inline comments
 * Add arm_smmu_invs_dbg() for tracing
 * Use users refcount to replace todel flag
 * Initialize num_invs in arm_smmu_invs_alloc()
 * Add a struct arm_smmu_inv_state to group invs pointers
 * Add in struct arm_smmu_invs two flags (has_ats and old)
 * Rename master->invs to master->build_invs, and sort the array
 * Rework arm_smmu_domain_inv_range() and arm_smmu_invs_end_batch()
 * Copy entries by struct arm_smmu_inv in arm_smmu_master_build_invs()
 * Add arm_smmu_invs_flush_iotlb_tags() for IOTLB flush by last device
 * Rework three invs mutation helpers, and prioritize use the in-place
   mutation for detach
 * Take writer's lock unconditionally but keep it short, and only take
   reader's lock conditionally on a has_ats flag
v1:
 https://lore.kernel.org/all/cover.1755131672.git.nicolinc at nvidia.com/

Thanks
Nicolin

Jason Gunthorpe (1):
  iommu/arm-smmu-v3: Introduce a per-domain arm_smmu_invs array

Nicolin Chen (6):
  iommu/arm-smmu-v3: Explicitly set smmu_domain->stage for SVA
  iommu/arm-smmu-v3: Add an inline arm_smmu_domain_free()
  iommu/arm-smmu-v3: Pre-allocate a per-master invalidation array
  iommu/arm-smmu-v3: Populate smmu_domain->invs when attaching masters
  iommu/arm-smmu-v3: Add arm_smmu_invs based arm_smmu_domain_inv_range()
  iommu/arm-smmu-v3: Perform per-domain invalidations using
    arm_smmu_invs

 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   | 143 ++-
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c   |  35 +-
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  |  92 ++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 920 +++++++++++++++---
 4 files changed, 1010 insertions(+), 180 deletions(-)

-- 
2.43.0



From nicolinc at nvidia.com  Wed Dec 17 15:24:26 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Wed, 17 Dec 2025 15:24:26 -0800
Subject: [PATCH v8 1/7] iommu/arm-smmu-v3: Explicitly set smmu_domain->stage for SVA
In-Reply-To: <cover.1766013662.git.nicolinc@nvidia.com>
References: <cover.1766013662.git.nicolinc@nvidia.com>
Message-ID: <df4b8cbc0d67a0bfcccb09be868e0da5f0cbb743.1766013662.git.nicolinc@nvidia.com>

Both the ARM_SMMU_DOMAIN_S1 case and the SVA case use ASID, requiring ASID
based invalidation commands to flush the TLB.

Define an ARM_SMMU_DOMAIN_SVA to make the SVA case clear to share the same
path with the ARM_SMMU_DOMAIN_S1 case, which will be a part of the routine
to build a new per-domain invalidation array.

There is no function change.

Suggested-by: Jason Gunthorpe <jgg at nvidia.com>
Acked-by: Balbir Singh <balbirs at nvidia.com>
Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h     | 1 +
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 1 +
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c     | 3 +++
 3 files changed, 5 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index ae23aacc3840..5c0b38595d20 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -858,6 +858,7 @@ struct arm_smmu_master {
 enum arm_smmu_domain_stage {
 	ARM_SMMU_DOMAIN_S1 = 0,
 	ARM_SMMU_DOMAIN_S2,
+	ARM_SMMU_DOMAIN_SVA,
 };
 
 struct arm_smmu_domain {
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index 59a480974d80..6097f1f540d8 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -346,6 +346,7 @@ struct iommu_domain *arm_smmu_sva_domain_alloc(struct device *dev,
 	 * ARM_SMMU_FEAT_RANGE_INV is present
 	 */
 	smmu_domain->domain.pgsize_bitmap = PAGE_SIZE;
+	smmu_domain->stage = ARM_SMMU_DOMAIN_SVA;
 	smmu_domain->smmu = smmu;
 
 	ret = xa_alloc(&arm_smmu_asid_xa, &asid, smmu_domain,
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index d16d35c78c06..9d9f24a08062 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -3065,6 +3065,9 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev,
 		arm_smmu_install_ste_for_dev(master, &target);
 		arm_smmu_clear_cd(master, IOMMU_NO_PASID);
 		break;
+	default:
+		WARN_ON(true);
+		break;
 	}
 
 	arm_smmu_attach_commit(&state);
-- 
2.43.0



From nicolinc at nvidia.com  Wed Dec 17 15:24:27 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Wed, 17 Dec 2025 15:24:27 -0800
Subject: [PATCH v8 2/7] iommu/arm-smmu-v3: Add an inline arm_smmu_domain_free()
In-Reply-To: <cover.1766013662.git.nicolinc@nvidia.com>
References: <cover.1766013662.git.nicolinc@nvidia.com>
Message-ID: <b516338bdde0bc6f06e2719b9292ffa260085a67.1766013662.git.nicolinc@nvidia.com>

There will be a bit more things to free than smmu_domain itself. So keep a
simple inline function in the header to share aross files.

Suggested-by: Jason Gunthorpe <jgg at nvidia.com>
Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
Acked-by: Balbir Singh <balbirs at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h     | 5 +++++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 5 +++--
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c     | 4 ++--
 3 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index 5c0b38595d20..96a23ca633cb 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -954,6 +954,11 @@ extern struct mutex arm_smmu_asid_lock;
 
 struct arm_smmu_domain *arm_smmu_domain_alloc(void);
 
+static inline void arm_smmu_domain_free(struct arm_smmu_domain *smmu_domain)
+{
+	kfree(smmu_domain);
+}
+
 void arm_smmu_clear_cd(struct arm_smmu_master *master, ioasid_t ssid);
 struct arm_smmu_cd *arm_smmu_get_cd_ptr(struct arm_smmu_master *master,
 					u32 ssid);
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index 6097f1f540d8..440ad8cc07de 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -197,7 +197,8 @@ static void arm_smmu_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
 
 static void arm_smmu_mmu_notifier_free(struct mmu_notifier *mn)
 {
-	kfree(container_of(mn, struct arm_smmu_domain, mmu_notifier));
+	arm_smmu_domain_free(
+		container_of(mn, struct arm_smmu_domain, mmu_notifier));
 }
 
 static const struct mmu_notifier_ops arm_smmu_mmu_notifier_ops = {
@@ -365,6 +366,6 @@ struct iommu_domain *arm_smmu_sva_domain_alloc(struct device *dev,
 err_asid:
 	xa_erase(&arm_smmu_asid_xa, smmu_domain->cd.asid);
 err_free:
-	kfree(smmu_domain);
+	arm_smmu_domain_free(smmu_domain);
 	return ERR_PTR(ret);
 }
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 9d9f24a08062..e9759e8af0c0 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2492,7 +2492,7 @@ static void arm_smmu_domain_free_paging(struct iommu_domain *domain)
 			ida_free(&smmu->vmid_map, cfg->vmid);
 	}
 
-	kfree(smmu_domain);
+	arm_smmu_domain_free(smmu_domain);
 }
 
 static int arm_smmu_domain_finalise_s1(struct arm_smmu_device *smmu,
@@ -3359,7 +3359,7 @@ arm_smmu_domain_alloc_paging_flags(struct device *dev, u32 flags,
 	return &smmu_domain->domain;
 
 err_free:
-	kfree(smmu_domain);
+	arm_smmu_domain_free(smmu_domain);
 	return ERR_PTR(ret);
 }
 
-- 
2.43.0



From nicolinc at nvidia.com  Wed Dec 17 15:24:29 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Wed, 17 Dec 2025 15:24:29 -0800
Subject: [PATCH v8 4/7] iommu/arm-smmu-v3: Pre-allocate a per-master invalidation array
In-Reply-To: <cover.1766013662.git.nicolinc@nvidia.com>
References: <cover.1766013662.git.nicolinc@nvidia.com>
Message-ID: <d6565a84698d93d6a2842b32bed492f87179af5e.1766013662.git.nicolinc@nvidia.com>

When a master is attached from an old domain to a new domain, it needs to
build an invalidation array to delete and add the array entries from/onto
the invalidation arrays of those two domains, passed via the to_merge and
to_unref arguments into arm_smmu_invs_merge/unref() respectively.

Since the master->num_streams might differ across masters, a memory would
have to be allocated when building an to_merge/to_unref array which might
fail with -ENOMEM.

On the other hand, an attachment to arm_smmu_blocked_domain must not fail
so it's the best to avoid any memory allocation in that path.

Pre-allocate a fixed size invalidation array for every master. This array
will be used as a scratch to fill dynamically when building a to_merge or
to_unref invs array. Sort fwspec->ids in an ascending order to fit to the
arm_smmu_invs_merge() function.

Co-developed-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h |  8 ++++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 41 +++++++++++++++++++--
 2 files changed, 45 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index a9441dc9070e..f98774962012 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -930,6 +930,14 @@ struct arm_smmu_master {
 	struct arm_smmu_device		*smmu;
 	struct device			*dev;
 	struct arm_smmu_stream		*streams;
+	/*
+	 * Scratch memory for a to_merge or to_unref array to build a per-domain
+	 * invalidation array. It'll be pre-allocated with enough enries for all
+	 * possible build scenarios. It can be used by only one caller at a time
+	 * until the arm_smmu_invs_merge/unref() finishes. Must be locked by the
+	 * iommu_group mutex.
+	 */
+	struct arm_smmu_invs		*build_invs;
 	struct arm_smmu_vmaster		*vmaster; /* use smmu->streams_mutex */
 	/* Locked by the iommu core using the group mutex */
 	struct arm_smmu_ctx_desc_cfg	cd_table;
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 39e89176fa87..cc85e7a10ea8 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -3709,12 +3709,22 @@ static int arm_smmu_init_sid_strtab(struct arm_smmu_device *smmu, u32 sid)
 	return 0;
 }
 
+static int arm_smmu_stream_id_cmp(const void *_l, const void *_r)
+{
+	const typeof_member(struct arm_smmu_stream, id) *l = _l;
+	const typeof_member(struct arm_smmu_stream, id) *r = _r;
+
+	return cmp_int(*l, *r);
+}
+
 static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
 				  struct arm_smmu_master *master)
 {
 	int i;
 	int ret = 0;
 	struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(master->dev);
+	bool ats_supported = dev_is_pci(master->dev) &&
+			     pci_ats_supported(to_pci_dev(master->dev));
 
 	master->streams = kcalloc(fwspec->num_ids, sizeof(*master->streams),
 				  GFP_KERNEL);
@@ -3722,14 +3732,35 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
 		return -ENOMEM;
 	master->num_streams = fwspec->num_ids;
 
-	mutex_lock(&smmu->streams_mutex);
+	if (!ats_supported) {
+		/* Base case has 1 ASID entry or maximum 2 VMID entries */
+		master->build_invs = arm_smmu_invs_alloc(2);
+	} else {
+		/* ATS case adds num_ids of entries, on top of the base case */
+		master->build_invs = arm_smmu_invs_alloc(2 + fwspec->num_ids);
+	}
+	if (!master->build_invs) {
+		kfree(master->streams);
+		return -ENOMEM;
+	}
+
 	for (i = 0; i < fwspec->num_ids; i++) {
 		struct arm_smmu_stream *new_stream = &master->streams[i];
-		struct rb_node *existing;
-		u32 sid = fwspec->ids[i];
 
-		new_stream->id = sid;
+		new_stream->id = fwspec->ids[i];
 		new_stream->master = master;
+	}
+
+	/* Put the ids into order for sorted to_merge/to_unref arrays */
+	sort_nonatomic(master->streams, master->num_streams,
+		       sizeof(master->streams[0]), arm_smmu_stream_id_cmp,
+		       NULL);
+
+	mutex_lock(&smmu->streams_mutex);
+	for (i = 0; i < fwspec->num_ids; i++) {
+		struct arm_smmu_stream *new_stream = &master->streams[i];
+		struct rb_node *existing;
+		u32 sid = new_stream->id;
 
 		ret = arm_smmu_init_sid_strtab(smmu, sid);
 		if (ret)
@@ -3759,6 +3790,7 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
 		for (i--; i >= 0; i--)
 			rb_erase(&master->streams[i].node, &smmu->streams);
 		kfree(master->streams);
+		kfree(master->build_invs);
 	}
 	mutex_unlock(&smmu->streams_mutex);
 
@@ -3780,6 +3812,7 @@ static void arm_smmu_remove_master(struct arm_smmu_master *master)
 	mutex_unlock(&smmu->streams_mutex);
 
 	kfree(master->streams);
+	kfree(master->build_invs);
 }
 
 static struct iommu_device *arm_smmu_probe_device(struct device *dev)
-- 
2.43.0



From nicolinc at nvidia.com  Wed Dec 17 15:24:28 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Wed, 17 Dec 2025 15:24:28 -0800
Subject: [PATCH v8 3/7] iommu/arm-smmu-v3: Introduce a per-domain arm_smmu_invs array
In-Reply-To: <cover.1766013662.git.nicolinc@nvidia.com>
References: <cover.1766013662.git.nicolinc@nvidia.com>
Message-ID: <8c94c5194871ee1a0f3a6b49e18818b88f51226d.1766013662.git.nicolinc@nvidia.com>

From: Jason Gunthorpe <jgg at nvidia.com>

Create a new data structure to hold an array of invalidations that need to
be performed for the domain based on what masters are attached, to replace
the single smmu pointer and linked list of masters in the current design.

Each array entry holds one of the invalidation actions - S1_ASID, S2_VMID,
ATS or their variant with information to feed invalidation commands to HW.
It is structured so that multiple SMMUs can participate in the same array,
removing one key limitation of the current system.

To maximize performance, a sorted array is used as the data structure. It
allows grouping SYNCs together to parallelize invalidations. For instance,
it will group all the ATS entries after the ASID/VMID entry, so they will
all be pushed to the PCI devices in parallel with one SYNC.

To minimize the locking cost on the invalidation fast path (reader of the
invalidation array), the array is managed with RCU.

Provide a set of APIs to add/delete entries to/from an array, which cover
cannot-fail attach cases, e.g. attaching to arm_smmu_blocked_domain. Also
add kunit coverage for those APIs.

Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
Co-developed-by: Nicolin Chen <nicolinc at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  98 +++++++
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  |  92 +++++++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 258 ++++++++++++++++++
 3 files changed, 448 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index 96a23ca633cb..a9441dc9070e 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -649,6 +649,93 @@ struct arm_smmu_cmdq_batch {
 	int				num;
 };
 
+/*
+ * The order here also determines the sequence in which commands are sent to the
+ * command queue. E.g. TLBI must be done before ATC_INV.
+ */
+enum arm_smmu_inv_type {
+	INV_TYPE_S1_ASID,
+	INV_TYPE_S2_VMID,
+	INV_TYPE_S2_VMID_S1_CLEAR,
+	INV_TYPE_ATS,
+	INV_TYPE_ATS_FULL,
+};
+
+struct arm_smmu_inv {
+	struct arm_smmu_device *smmu;
+	u8 type;
+	u8 size_opcode;
+	u8 nsize_opcode;
+	u32 id; /* ASID or VMID or SID */
+	union {
+		size_t pgsize; /* ARM_SMMU_FEAT_RANGE_INV */
+		u32 ssid; /* INV_TYPE_ATS */
+	};
+
+	refcount_t users; /* users=0 to mark as a trash to be purged */
+};
+
+static inline bool arm_smmu_inv_is_ats(const struct arm_smmu_inv *inv)
+{
+	return inv->type == INV_TYPE_ATS || inv->type == INV_TYPE_ATS_FULL;
+}
+
+/**
+ * struct arm_smmu_invs - Per-domain invalidation array
+ * @max_invs: maximum capacity of the flexible array
+ * @num_invs: number of invalidations in the flexible array. May be smaller than
+ *            @max_invs after a tailing trash entry is excluded, but must not be
+ *            greater than @max_invs
+ * @num_trashes: number of trash entries in the array for arm_smmu_invs_purge().
+ *               Must not be greater than @num_invs
+ * @rwlock: optional rwlock to fench ATS operations
+ * @has_ats: flag if the array contains an INV_TYPE_ATS or INV_TYPE_ATS_FULL
+ * @rcu: rcu head for kfree_rcu()
+ * @inv: flexible invalidation array
+ *
+ * The arm_smmu_invs is an RCU data structure. During a ->attach_dev callback,
+ * arm_smmu_invs_merge(), arm_smmu_invs_unref() and arm_smmu_invs_purge() will
+ * be used to allocate a new copy of an old array for addition and deletion in
+ * the old domain's and new domain's invs arrays.
+ *
+ * The arm_smmu_invs_unref() mutates a given array, by internally reducing the
+ * users counts of some given entries. This exists to support a no-fail routine
+ * like attaching to an IOMMU_DOMAIN_BLOCKED. And it could pair with a followup
+ * arm_smmu_invs_purge() call to generate a new clean array.
+ *
+ * Concurrent invalidation thread will push every invalidation described in the
+ * array into the command queue for each invalidation event. It is designed like
+ * this to optimize the invalidation fast path by avoiding locks.
+ *
+ * A domain can be shared across SMMU instances. When an instance gets removed,
+ * it would delete all the entries that belong to that SMMU instance. Then, a
+ * synchronize_rcu() would have to be called to sync the array, to prevent any
+ * concurrent invalidation thread accessing the old array from issuing commands
+ * to the command queue of a removed SMMU instance.
+ */
+struct arm_smmu_invs {
+	size_t max_invs;
+	size_t num_invs;
+	size_t num_trashes;
+	rwlock_t rwlock;
+	bool has_ats;
+	struct rcu_head rcu;
+	struct arm_smmu_inv inv[] __counted_by(max_invs);
+};
+
+static inline struct arm_smmu_invs *arm_smmu_invs_alloc(size_t num_invs)
+{
+	struct arm_smmu_invs *new_invs;
+
+	new_invs = kzalloc(struct_size(new_invs, inv, num_invs), GFP_KERNEL);
+	if (!new_invs)
+		return NULL;
+	new_invs->max_invs = num_invs;
+	new_invs->num_invs = num_invs;
+	rwlock_init(&new_invs->rwlock);
+	return new_invs;
+}
+
 struct arm_smmu_evtq {
 	struct arm_smmu_queue		q;
 	struct iopf_queue		*iopf;
@@ -875,6 +962,8 @@ struct arm_smmu_domain {
 
 	struct iommu_domain		domain;
 
+	struct arm_smmu_invs __rcu	*invs;
+
 	/* List of struct arm_smmu_master_domain */
 	struct list_head		devices;
 	spinlock_t			devices_lock;
@@ -923,6 +1012,13 @@ void arm_smmu_make_cdtable_ste(struct arm_smmu_ste *target,
 void arm_smmu_make_sva_cd(struct arm_smmu_cd *target,
 			  struct arm_smmu_master *master, struct mm_struct *mm,
 			  u16 asid);
+
+struct arm_smmu_invs *arm_smmu_invs_merge(struct arm_smmu_invs *invs,
+					  struct arm_smmu_invs *to_merge);
+void arm_smmu_invs_unref(struct arm_smmu_invs *invs,
+			 struct arm_smmu_invs *to_unref,
+			 void (*free_fn)(struct arm_smmu_inv *inv));
+struct arm_smmu_invs *arm_smmu_invs_purge(struct arm_smmu_invs *invs);
 #endif
 
 struct arm_smmu_master_domain {
@@ -956,6 +1052,8 @@ struct arm_smmu_domain *arm_smmu_domain_alloc(void);
 
 static inline void arm_smmu_domain_free(struct arm_smmu_domain *smmu_domain)
 {
+	/* No concurrency with invalidation is possible at this point */
+	kfree(rcu_dereference_protected(smmu_domain->invs, true));
 	kfree(smmu_domain);
 }
 
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
index d2671bfd3798..238bfd328b5b 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
@@ -567,6 +567,97 @@ static void arm_smmu_v3_write_cd_test_sva_release(struct kunit *test)
 						      NUM_EXPECTED_SYNCS(2));
 }
 
+static void arm_smmu_v3_invs_test_verify(struct kunit *test,
+					 struct arm_smmu_invs *invs, int num,
+					 const int *ids, const int *users)
+{
+	KUNIT_EXPECT_EQ(test, invs->num_invs, num);
+	while (num--) {
+		KUNIT_EXPECT_EQ(test, invs->inv[num].id, ids[num]);
+		KUNIT_EXPECT_EQ(test, refcount_read(&invs->inv[num].users),
+				users[num]);
+	}
+}
+
+static struct arm_smmu_invs invs1 = {
+	.num_invs = 3,
+	.inv = { { .type = INV_TYPE_S2_VMID, .id = 1, },
+		 { .type = INV_TYPE_S2_VMID_S1_CLEAR, .id = 1, },
+		 { .type = INV_TYPE_ATS, .id = 3, }, },
+};
+
+static struct arm_smmu_invs invs2 = {
+	.num_invs = 3,
+	.inv = { { .type = INV_TYPE_S2_VMID, .id = 1, }, /* duplicated */
+		 { .type = INV_TYPE_ATS, .id = 4, },
+		 { .type = INV_TYPE_ATS, .id = 5, }, },
+};
+
+static struct arm_smmu_invs invs3 = {
+	.num_invs = 3,
+	.inv = { { .type = INV_TYPE_S2_VMID, .id = 1, }, /* duplicated */
+		 { .type = INV_TYPE_ATS, .id = 5, }, /* recover a trash */
+		 { .type = INV_TYPE_ATS, .id = 6, }, },
+};
+
+static void arm_smmu_v3_invs_test(struct kunit *test)
+{
+	const int results1[2][3] = { { 1, 1, 3, }, { 1, 1, 1, }, };
+	const int results2[2][5] = { { 1, 1, 3, 4, 5, }, { 2, 1, 1, 1, 1, }, };
+	const int results3[2][3] = { { 1, 1, 3, }, { 1, 1, 1, }, };
+	const int results4[2][5] = { { 1, 1, 3, 5, 6, }, { 2, 1, 1, 1, 1, }, };
+	const int results5[2][5] = { { 1, 1, 3, 5, 6, }, { 1, 0, 0, 1, 1, }, };
+	const int results6[2][3] = { { 1, 5, 6, }, { 1, 1, 1, }, };
+	struct arm_smmu_invs *test_a, *test_b;
+
+	/* New array */
+	test_a = arm_smmu_invs_alloc(0);
+	KUNIT_EXPECT_EQ(test, test_a->num_invs, 0);
+
+	/* Test1: merge invs1 (new array) */
+	test_b = arm_smmu_invs_merge(test_a, &invs1);
+	kfree(test_a);
+	arm_smmu_v3_invs_test_verify(test, test_b, ARRAY_SIZE(results1[0]),
+				     results1[0], results1[1]);
+
+	/* Test2: merge invs2 (new array) */
+	test_a = arm_smmu_invs_merge(test_b, &invs2);
+	kfree(test_b);
+	arm_smmu_v3_invs_test_verify(test, test_a, ARRAY_SIZE(results2[0]),
+				     results2[0], results2[1]);
+
+	/* Test3: unref invs2 (same array) */
+	arm_smmu_invs_unref(test_a, &invs2, NULL);
+	arm_smmu_v3_invs_test_verify(test, test_a, ARRAY_SIZE(results3[0]),
+				     results3[0], results3[1]);
+	KUNIT_EXPECT_EQ(test, test_a->num_trashes, 0);
+
+	/* Test4: merge invs3 (new array) */
+	test_b = arm_smmu_invs_merge(test_a, &invs3);
+	kfree(test_a);
+	arm_smmu_v3_invs_test_verify(test, test_b, ARRAY_SIZE(results4[0]),
+				     results4[0], results4[1]);
+
+	/* Test5: unref invs1 (same array) */
+	arm_smmu_invs_unref(test_b, &invs1, NULL);
+	arm_smmu_v3_invs_test_verify(test, test_b, ARRAY_SIZE(results5[0]),
+				     results5[0], results5[1]);
+	KUNIT_EXPECT_EQ(test, test_b->num_trashes, 2);
+
+	/* Test6: purge test_b (new array) */
+	test_a = arm_smmu_invs_purge(test_b);
+	kfree(test_b);
+	arm_smmu_v3_invs_test_verify(test, test_a, ARRAY_SIZE(results6[0]),
+				     results6[0], results6[1]);
+
+	/* Test7: unref invs3 (same array) */
+	arm_smmu_invs_unref(test_a, &invs3, NULL);
+	KUNIT_EXPECT_EQ(test, test_a->num_invs, 0);
+	KUNIT_EXPECT_EQ(test, test_a->num_trashes, 0);
+
+	kfree(test_a);
+}
+
 static struct kunit_case arm_smmu_v3_test_cases[] = {
 	KUNIT_CASE(arm_smmu_v3_write_ste_test_bypass_to_abort),
 	KUNIT_CASE(arm_smmu_v3_write_ste_test_abort_to_bypass),
@@ -590,6 +681,7 @@ static struct kunit_case arm_smmu_v3_test_cases[] = {
 	KUNIT_CASE(arm_smmu_v3_write_ste_test_s2_to_s1_stall),
 	KUNIT_CASE(arm_smmu_v3_write_cd_test_sva_clear),
 	KUNIT_CASE(arm_smmu_v3_write_cd_test_sva_release),
+	KUNIT_CASE(arm_smmu_v3_invs_test),
 	{},
 };
 
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index e9759e8af0c0..39e89176fa87 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -26,6 +26,7 @@
 #include <linux/pci.h>
 #include <linux/pci-ats.h>
 #include <linux/platform_device.h>
+#include <linux/sort.h>
 #include <linux/string_choices.h>
 #include <kunit/visibility.h>
 #include <uapi/linux/iommufd.h>
@@ -1015,6 +1016,255 @@ static void arm_smmu_page_response(struct device *dev, struct iopf_fault *unused
 	 */
 }
 
+/* Invalidation array manipulation functions */
+static inline struct arm_smmu_inv *
+arm_smmu_invs_iter_next(struct arm_smmu_invs *invs, size_t next, size_t *idx)
+{
+	while (true) {
+		if (next >= invs->num_invs) {
+			*idx = next;
+			return NULL;
+		}
+		if (!refcount_read(&invs->inv[next].users)) {
+			next++;
+			continue;
+		}
+		*idx = next;
+		return &invs->inv[next];
+	}
+}
+
+/**
+ * arm_smmu_invs_for_each_entry - Iterate over all non-trash entries in invs
+ * @invs: the base invalidation array
+ * @idx: a stack variable of 'size_t', to store the array index
+ * @cur: a stack variable of 'struct arm_smmu_inv *'
+ */
+#define arm_smmu_invs_for_each_entry(invs, idx, cur)                           \
+	for (cur = arm_smmu_invs_iter_next(invs, 0, &(idx)); cur;              \
+	     cur = arm_smmu_invs_iter_next(invs, idx + 1, &(idx)))
+
+static int arm_smmu_inv_cmp(const struct arm_smmu_inv *inv_l,
+			    const struct arm_smmu_inv *inv_r)
+{
+	if (inv_l->smmu != inv_r->smmu)
+		return cmp_int((uintptr_t)inv_l->smmu, (uintptr_t)inv_r->smmu);
+	if (inv_l->type != inv_r->type)
+		return cmp_int(inv_l->type, inv_r->type);
+	return cmp_int(inv_l->id, inv_r->id);
+}
+
+static inline int arm_smmu_invs_iter_next_cmp(struct arm_smmu_invs *invs_l,
+					      size_t next_l, size_t *idx_l,
+					      struct arm_smmu_invs *invs_r,
+					      size_t next_r, size_t *idx_r)
+{
+	struct arm_smmu_inv *cur_l =
+		arm_smmu_invs_iter_next(invs_l, next_l, idx_l);
+
+	/*
+	 * We have to update the idx_r manually, because the invs_r cannot call
+	 * arm_smmu_invs_iter_next() as the invs_r never sets any users counter.
+	 */
+	*idx_r = next_r;
+
+	/*
+	 * Compare of two sorted arrays items. If one side is past the end of
+	 * the array, return the other side to let it run out the iteration.
+	 *
+	 * If the left entry is empty, return 1 to pick the right entry.
+	 * If the right entry is empty, return -1 to pick the left entry.
+	 */
+	if (!cur_l)
+		return 1;
+	if (next_r >= invs_r->num_invs)
+		return -1;
+	return arm_smmu_inv_cmp(cur_l, &invs_r->inv[next_r]);
+}
+
+/**
+ * arm_smmu_invs_for_each_entry - Iterate over two sorted arrays computing for
+ *                                arm_smmu_invs_merge() or arm_smmu_invs_unref()
+ * @invs_l: the base invalidation array
+ * @idx_l: a stack variable of 'size_t', to store the base array index
+ * @invs_r: the build_invs array as to_merge or to_unref
+ * @idx_r: a stack variable of 'size_t', to store the build_invs index
+ * @cmp: a stack variable of 'int', to store return value (-1, 0, or 1)
+ */
+#define arm_smmu_invs_for_each_cmp(invs_l, idx_l, invs_r, idx_r, cmp)          \
+	for (idx_l = idx_r = 0,                                                \
+	     cmp = arm_smmu_invs_iter_next_cmp(invs_l, 0, &(idx_l),            \
+					       invs_r, 0, &(idx_r));           \
+	     idx_l < invs_l->num_invs || idx_r < invs_r->num_invs;             \
+	     cmp = arm_smmu_invs_iter_next_cmp(                                \
+		     invs_l, idx_l + (cmp <= 0 ? 1 : 0), &(idx_l),             \
+		     invs_r, idx_r + (cmp >= 0 ? 1 : 0), &(idx_r)))
+
+/**
+ * arm_smmu_invs_merge() - Merge @to_merge into @invs and generate a new array
+ * @invs: the base invalidation array
+ * @to_merge: an array of invlidations to merge
+ *
+ * Return: a newly allocated array on success, or ERR_PTR
+ *
+ * This function must be locked and serialized with arm_smmu_invs_unref() and
+ * arm_smmu_invs_purge(), but do not lockdep on any lock for KUNIT test.
+ *
+ * Both @invs and @to_merge must be sorted, to ensure the returned array will be
+ * sorted as well.
+ *
+ * Caller is resposible for freeing the @invs and the returned new one.
+ *
+ * Entries marked as trash will be purged in the returned array.
+ */
+VISIBLE_IF_KUNIT
+struct arm_smmu_invs *arm_smmu_invs_merge(struct arm_smmu_invs *invs,
+					  struct arm_smmu_invs *to_merge)
+{
+	struct arm_smmu_invs *new_invs;
+	struct arm_smmu_inv *new;
+	size_t num_invs = 0;
+	size_t i, j;
+	int cmp;
+
+	arm_smmu_invs_for_each_cmp(invs, i, to_merge, j, cmp)
+		num_invs++;
+
+	new_invs = arm_smmu_invs_alloc(num_invs);
+	if (!new_invs)
+		return ERR_PTR(-ENOMEM);
+
+	new = new_invs->inv;
+	arm_smmu_invs_for_each_cmp(invs, i, to_merge, j, cmp) {
+		if (cmp < 0) {
+			*new = invs->inv[i];
+		} else if (cmp == 0) {
+			*new = invs->inv[i];
+			refcount_inc(&new->users);
+		} else {
+			*new = to_merge->inv[j];
+			refcount_set(&new->users, 1);
+		}
+
+		/*
+		 * Check that the new array is sorted. This also validates that
+		 * to_merge is sorted.
+		 */
+		if (new != new_invs->inv)
+			WARN_ON_ONCE(arm_smmu_inv_cmp(new - 1, new) == 1);
+		if (arm_smmu_inv_is_ats(new))
+			new_invs->has_ats = true;
+		new++;
+	}
+
+	WARN_ON(new != new_invs->inv + new_invs->num_invs);
+
+	return new_invs;
+}
+EXPORT_SYMBOL_IF_KUNIT(arm_smmu_invs_merge);
+
+/**
+ * arm_smmu_invs_unref() - Find in @invs for all entries in @to_unref, decrease
+ *                         the user counts without deletions
+ * @invs: the base invalidation array
+ * @to_unref: an array of invlidations to decrease their user counts
+ * @free_fn: A callback function to invoke, when an entry's user count reduces
+ *           to 0
+ *
+ * Return: the number of trash entries in the array, for arm_smmu_invs_purge()
+ *
+ * This function will not fail. Any entry with users=0 will be marked as trash.
+ * All tailing trash entries in the array will be dropped. And the size of the
+ * array will be trimmed properly. All trash entries in-between will remain in
+ * the @invs until being completely deleted by the next arm_smmu_invs_merge()
+ * or an arm_smmu_invs_purge() function call.
+ *
+ * This function must be locked and serialized with arm_smmu_invs_merge() and
+ * arm_smmu_invs_purge(), but do not lockdep on any mutex for KUNIT test.
+ *
+ * Note that the final @invs->num_invs might not reflect the actual number of
+ * invalidations due to trash entries. Any reader should take the read lock to
+ * iterate each entry and check its users counter till the last entry.
+ */
+VISIBLE_IF_KUNIT
+void arm_smmu_invs_unref(struct arm_smmu_invs *invs,
+			 struct arm_smmu_invs *to_unref,
+			 void (*free_fn)(struct arm_smmu_inv *inv))
+{
+	unsigned long flags;
+	size_t num_invs = 0;
+	size_t i, j;
+	int cmp;
+
+	arm_smmu_invs_for_each_cmp(invs, i, to_unref, j, cmp) {
+		if (cmp < 0) {
+			/* not found in to_unref, leave alone */
+			num_invs = i + 1;
+		} else if (cmp == 0) {
+			/* same item */
+			if (!refcount_dec_and_test(&invs->inv[i].users)) {
+				num_invs = i + 1;
+				continue;
+			}
+
+			/* KUNIT test doesn't pass in a free_fn */
+			if (free_fn)
+				free_fn(&invs->inv[i]);
+			invs->num_trashes++;
+		} else {
+			/* item in to_unref is not in invs or already a trash */
+			WARN_ON(true);
+		}
+	}
+
+	/* Exclude any tailing trash */
+	invs->num_trashes -= invs->num_invs - num_invs;
+
+	/* The lock is required to fence concurrent ATS operations. */
+	write_lock_irqsave(&invs->rwlock, flags);
+	WRITE_ONCE(invs->num_invs, num_invs); /* Remove tailing trash entries */
+	write_unlock_irqrestore(&invs->rwlock, flags);
+}
+EXPORT_SYMBOL_IF_KUNIT(arm_smmu_invs_unref);
+
+/**
+ * arm_smmu_invs_purge() - Purge all the trash entries in the @invs
+ * @invs: the base invalidation array
+ *
+ * Return: a newly allocated array on success removing all the trash entries, or
+ *         NULL if there is no trash entry in the array or there is a bug
+ *
+ * This function must be locked and serialized with arm_smmu_invs_merge() and
+ * arm_smmu_invs_unref(), but do not lockdep on any lock for KUNIT test.
+ *
+ * Caller is resposible for freeing the @invs and the returned new one.
+ */
+VISIBLE_IF_KUNIT
+struct arm_smmu_invs *arm_smmu_invs_purge(struct arm_smmu_invs *invs)
+{
+	struct arm_smmu_invs *new_invs;
+	struct arm_smmu_inv *inv;
+	size_t i, num_invs = 0;
+
+	if (WARN_ON(invs->num_invs < invs->num_trashes))
+		return NULL;
+	if (!invs->num_invs || !invs->num_trashes)
+		return NULL;
+
+	new_invs = arm_smmu_invs_alloc(invs->num_invs - invs->num_trashes);
+	if (!new_invs)
+		return ERR_PTR(-ENOMEM);
+
+	arm_smmu_invs_for_each_entry(invs, i, inv) {
+		new_invs->inv[num_invs] = *inv;
+		num_invs++;
+	}
+
+	WARN_ON(num_invs != new_invs->num_invs);
+	return new_invs;
+}
+EXPORT_SYMBOL_IF_KUNIT(arm_smmu_invs_purge);
+
 /* Context descriptor manipulation functions */
 void arm_smmu_tlb_inv_asid(struct arm_smmu_device *smmu, u16 asid)
 {
@@ -2462,13 +2712,21 @@ static bool arm_smmu_enforce_cache_coherency(struct iommu_domain *domain)
 struct arm_smmu_domain *arm_smmu_domain_alloc(void)
 {
 	struct arm_smmu_domain *smmu_domain;
+	struct arm_smmu_invs *new_invs;
 
 	smmu_domain = kzalloc(sizeof(*smmu_domain), GFP_KERNEL);
 	if (!smmu_domain)
 		return ERR_PTR(-ENOMEM);
 
+	new_invs = arm_smmu_invs_alloc(0);
+	if (!new_invs) {
+		kfree(smmu_domain);
+		return ERR_PTR(-ENOMEM);
+	}
+
 	INIT_LIST_HEAD(&smmu_domain->devices);
 	spin_lock_init(&smmu_domain->devices_lock);
+	rcu_assign_pointer(smmu_domain->invs, new_invs);
 
 	return smmu_domain;
 }
-- 
2.43.0



From nicolinc at nvidia.com  Wed Dec 17 15:24:32 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Wed, 17 Dec 2025 15:24:32 -0800
Subject: [PATCH v8 7/7] iommu/arm-smmu-v3: Perform per-domain invalidations using arm_smmu_invs
In-Reply-To: <cover.1766013662.git.nicolinc@nvidia.com>
References: <cover.1766013662.git.nicolinc@nvidia.com>
Message-ID: <be2867c39f19e8710e0bd2c274050e88cee5afc5.1766013662.git.nicolinc@nvidia.com>

Replace the old invalidation functions with arm_smmu_domain_inv_range() in
all the existing invalidation routines. And deprecate the old functions.

The new arm_smmu_domain_inv_range() handles the CMDQ_MAX_TLBI_OPS as well,
so drop it in the SVA function.

Since arm_smmu_cmdq_batch_add_range() has only one caller now, and it must
be given a valid size, add a WARN_ON_ONCE to catch any missed case.

Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |   7 -
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c   |  29 +--
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 165 +-----------------
 3 files changed, 11 insertions(+), 190 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index c3fee7f14480..4f104c1baa67 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -1079,13 +1079,6 @@ int arm_smmu_set_pasid(struct arm_smmu_master *master,
 		       struct arm_smmu_domain *smmu_domain, ioasid_t pasid,
 		       struct arm_smmu_cd *cd, struct iommu_domain *old);
 
-void arm_smmu_tlb_inv_asid(struct arm_smmu_device *smmu, u16 asid);
-void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,
-				 size_t granule, bool leaf,
-				 struct arm_smmu_domain *smmu_domain);
-int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain,
-			    unsigned long iova, size_t size);
-
 void arm_smmu_domain_inv_range(struct arm_smmu_domain *smmu_domain,
 			       unsigned long iova, size_t size,
 			       unsigned int granule, bool leaf);
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index 440ad8cc07de..f1f8e01a7e91 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -122,15 +122,6 @@ void arm_smmu_make_sva_cd(struct arm_smmu_cd *target,
 }
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_make_sva_cd);
 
-/*
- * Cloned from the MAX_TLBI_OPS in arch/arm64/include/asm/tlbflush.h, this
- * is used as a threshold to replace per-page TLBI commands to issue in the
- * command queue with an address-space TLBI command, when SMMU w/o a range
- * invalidation feature handles too many per-page TLBI commands, which will
- * otherwise result in a soft lockup.
- */
-#define CMDQ_MAX_TLBI_OPS		(1 << (PAGE_SHIFT - 3))
-
 static void arm_smmu_mm_arch_invalidate_secondary_tlbs(struct mmu_notifier *mn,
 						struct mm_struct *mm,
 						unsigned long start,
@@ -146,21 +137,8 @@ static void arm_smmu_mm_arch_invalidate_secondary_tlbs(struct mmu_notifier *mn,
 	 * range. So do a simple translation here by calculating size correctly.
 	 */
 	size = end - start;
-	if (!(smmu_domain->smmu->features & ARM_SMMU_FEAT_RANGE_INV)) {
-		if (size >= CMDQ_MAX_TLBI_OPS * PAGE_SIZE)
-			size = 0;
-	} else {
-		if (size == ULONG_MAX)
-			size = 0;
-	}
-
-	if (!size)
-		arm_smmu_tlb_inv_asid(smmu_domain->smmu, smmu_domain->cd.asid);
-	else
-		arm_smmu_tlb_inv_range_asid(start, size, smmu_domain->cd.asid,
-					    PAGE_SIZE, false, smmu_domain);
 
-	arm_smmu_atc_inv_domain(smmu_domain, start, size);
+	arm_smmu_domain_inv_range(smmu_domain, start, size, PAGE_SIZE, false);
 }
 
 static void arm_smmu_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
@@ -191,8 +169,7 @@ static void arm_smmu_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
 	}
 	spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
 
-	arm_smmu_tlb_inv_asid(smmu_domain->smmu, smmu_domain->cd.asid);
-	arm_smmu_atc_inv_domain(smmu_domain, 0, 0);
+	arm_smmu_domain_inv(smmu_domain);
 }
 
 static void arm_smmu_mmu_notifier_free(struct mmu_notifier *mn)
@@ -302,7 +279,7 @@ static void arm_smmu_sva_domain_free(struct iommu_domain *domain)
 	/*
 	 * Ensure the ASID is empty in the iommu cache before allowing reuse.
 	 */
-	arm_smmu_tlb_inv_asid(smmu_domain->smmu, smmu_domain->cd.asid);
+	arm_smmu_domain_inv(smmu_domain);
 
 	/*
 	 * Notice that the arm_smmu_mm_arch_invalidate_secondary_tlbs op can
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 788c20a9aa76..d7c492ee0936 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1266,16 +1266,6 @@ struct arm_smmu_invs *arm_smmu_invs_purge(struct arm_smmu_invs *invs)
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_invs_purge);
 
 /* Context descriptor manipulation functions */
-void arm_smmu_tlb_inv_asid(struct arm_smmu_device *smmu, u16 asid)
-{
-	struct arm_smmu_cmdq_ent cmd = {
-		.opcode	= smmu->features & ARM_SMMU_FEAT_E2H ?
-			CMDQ_OP_TLBI_EL2_ASID : CMDQ_OP_TLBI_NH_ASID,
-		.tlbi.asid = asid,
-	};
-
-	arm_smmu_cmdq_issue_cmd_with_sync(smmu, &cmd);
-}
 
 /*
  * Based on the value of ent report which bits of the STE the HW will access. It
@@ -2430,74 +2420,10 @@ static int arm_smmu_atc_inv_master(struct arm_smmu_master *master,
 	return arm_smmu_cmdq_batch_submit(master->smmu, &cmds);
 }
 
-int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain,
-			    unsigned long iova, size_t size)
-{
-	struct arm_smmu_master_domain *master_domain;
-	int i;
-	unsigned long flags;
-	struct arm_smmu_cmdq_ent cmd = {
-		.opcode = CMDQ_OP_ATC_INV,
-	};
-	struct arm_smmu_cmdq_batch cmds;
-
-	if (!(smmu_domain->smmu->features & ARM_SMMU_FEAT_ATS))
-		return 0;
-
-	/*
-	 * Ensure that we've completed prior invalidation of the main TLBs
-	 * before we read 'nr_ats_masters' in case of a concurrent call to
-	 * arm_smmu_enable_ats():
-	 *
-	 *	// unmap()			// arm_smmu_enable_ats()
-	 *	TLBI+SYNC			atomic_inc(&nr_ats_masters);
-	 *	smp_mb();			[...]
-	 *	atomic_read(&nr_ats_masters);	pci_enable_ats() // writel()
-	 *
-	 * Ensures that we always see the incremented 'nr_ats_masters' count if
-	 * ATS was enabled at the PCI device before completion of the TLBI.
-	 */
-	smp_mb();
-	if (!atomic_read(&smmu_domain->nr_ats_masters))
-		return 0;
-
-	arm_smmu_cmdq_batch_init(smmu_domain->smmu, &cmds, &cmd);
-
-	spin_lock_irqsave(&smmu_domain->devices_lock, flags);
-	list_for_each_entry(master_domain, &smmu_domain->devices,
-			    devices_elm) {
-		struct arm_smmu_master *master = master_domain->master;
-
-		if (!master->ats_enabled)
-			continue;
-
-		if (master_domain->nested_ats_flush) {
-			/*
-			 * If a S2 used as a nesting parent is changed we have
-			 * no option but to completely flush the ATC.
-			 */
-			arm_smmu_atc_inv_to_cmd(IOMMU_NO_PASID, 0, 0, &cmd);
-		} else {
-			arm_smmu_atc_inv_to_cmd(master_domain->ssid, iova, size,
-						&cmd);
-		}
-
-		for (i = 0; i < master->num_streams; i++) {
-			cmd.atc.sid = master->streams[i].id;
-			arm_smmu_cmdq_batch_add(smmu_domain->smmu, &cmds, &cmd);
-		}
-	}
-	spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
-
-	return arm_smmu_cmdq_batch_submit(smmu_domain->smmu, &cmds);
-}
-
 /* IO_PGTABLE API */
 static void arm_smmu_tlb_inv_context(void *cookie)
 {
 	struct arm_smmu_domain *smmu_domain = cookie;
-	struct arm_smmu_device *smmu = smmu_domain->smmu;
-	struct arm_smmu_cmdq_ent cmd;
 
 	/*
 	 * NOTE: when io-pgtable is in non-strict mode, we may get here with
@@ -2506,14 +2432,7 @@ static void arm_smmu_tlb_inv_context(void *cookie)
 	 * insertion to guarantee those are observed before the TLBI. Do be
 	 * careful, 007.
 	 */
-	if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
-		arm_smmu_tlb_inv_asid(smmu, smmu_domain->cd.asid);
-	} else {
-		cmd.opcode	= CMDQ_OP_TLBI_S12_VMALL;
-		cmd.tlbi.vmid	= smmu_domain->s2_cfg.vmid;
-		arm_smmu_cmdq_issue_cmd_with_sync(smmu, &cmd);
-	}
-	arm_smmu_atc_inv_domain(smmu_domain, 0, 0);
+	arm_smmu_domain_inv(smmu_domain);
 }
 
 static void arm_smmu_cmdq_batch_add_range(struct arm_smmu_device *smmu,
@@ -2525,7 +2444,7 @@ static void arm_smmu_cmdq_batch_add_range(struct arm_smmu_device *smmu,
 	unsigned long end = iova + size, num_pages = 0, tg = pgsize;
 	size_t inv_range = granule;
 
-	if (!size)
+	if (WARN_ON_ONCE(!size))
 		return;
 
 	if (smmu->features & ARM_SMMU_FEAT_RANGE_INV) {
@@ -2580,76 +2499,6 @@ static void arm_smmu_cmdq_batch_add_range(struct arm_smmu_device *smmu,
 	}
 }
 
-static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd,
-				     unsigned long iova, size_t size,
-				     size_t granule,
-				     struct arm_smmu_domain *smmu_domain)
-{
-	struct arm_smmu_device *smmu = smmu_domain->smmu;
-	struct arm_smmu_cmdq_batch cmds;
-	size_t pgsize;
-
-	/* Get the leaf page size */
-	pgsize = __ffs(smmu_domain->domain.pgsize_bitmap);
-
-	arm_smmu_cmdq_batch_init(smmu, &cmds, cmd);
-	arm_smmu_cmdq_batch_add_range(smmu, &cmds, cmd, iova, size, granule,
-				      pgsize);
-	arm_smmu_cmdq_batch_submit(smmu, &cmds);
-}
-
-static void arm_smmu_tlb_inv_range_domain(unsigned long iova, size_t size,
-					  size_t granule, bool leaf,
-					  struct arm_smmu_domain *smmu_domain)
-{
-	struct arm_smmu_cmdq_ent cmd = {
-		.tlbi = {
-			.leaf	= leaf,
-		},
-	};
-
-	if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
-		cmd.opcode	= smmu_domain->smmu->features & ARM_SMMU_FEAT_E2H ?
-				  CMDQ_OP_TLBI_EL2_VA : CMDQ_OP_TLBI_NH_VA;
-		cmd.tlbi.asid	= smmu_domain->cd.asid;
-	} else {
-		cmd.opcode	= CMDQ_OP_TLBI_S2_IPA;
-		cmd.tlbi.vmid	= smmu_domain->s2_cfg.vmid;
-	}
-	__arm_smmu_tlb_inv_range(&cmd, iova, size, granule, smmu_domain);
-
-	if (smmu_domain->nest_parent) {
-		/*
-		 * When the S2 domain changes all the nested S1 ASIDs have to be
-		 * flushed too.
-		 */
-		cmd.opcode = CMDQ_OP_TLBI_NH_ALL;
-		arm_smmu_cmdq_issue_cmd_with_sync(smmu_domain->smmu, &cmd);
-	}
-
-	/*
-	 * Unfortunately, this can't be leaf-only since we may have
-	 * zapped an entire table.
-	 */
-	arm_smmu_atc_inv_domain(smmu_domain, iova, size);
-}
-
-void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,
-				 size_t granule, bool leaf,
-				 struct arm_smmu_domain *smmu_domain)
-{
-	struct arm_smmu_cmdq_ent cmd = {
-		.opcode	= smmu_domain->smmu->features & ARM_SMMU_FEAT_E2H ?
-			  CMDQ_OP_TLBI_EL2_VA : CMDQ_OP_TLBI_NH_VA,
-		.tlbi = {
-			.asid	= asid,
-			.leaf	= leaf,
-		},
-	};
-
-	__arm_smmu_tlb_inv_range(&cmd, iova, size, granule, smmu_domain);
-}
-
 static bool arm_smmu_inv_size_too_big(struct arm_smmu_device *smmu, size_t size,
 				      size_t granule)
 {
@@ -2850,7 +2699,9 @@ static void arm_smmu_tlb_inv_page_nosync(struct iommu_iotlb_gather *gather,
 static void arm_smmu_tlb_inv_walk(unsigned long iova, size_t size,
 				  size_t granule, void *cookie)
 {
-	arm_smmu_tlb_inv_range_domain(iova, size, granule, false, cookie);
+	struct arm_smmu_domain *smmu_domain = cookie;
+
+	arm_smmu_domain_inv_range(smmu_domain, iova, size, granule, false);
 }
 
 static const struct iommu_flush_ops arm_smmu_flush_ops = {
@@ -4145,9 +3996,9 @@ static void arm_smmu_iotlb_sync(struct iommu_domain *domain,
 	if (!gather->pgsize)
 		return;
 
-	arm_smmu_tlb_inv_range_domain(gather->start,
-				      gather->end - gather->start + 1,
-				      gather->pgsize, true, smmu_domain);
+	arm_smmu_domain_inv_range(smmu_domain, gather->start,
+				  gather->end - gather->start + 1,
+				  gather->pgsize, true);
 }
 
 static phys_addr_t
-- 
2.43.0



From nicolinc at nvidia.com  Wed Dec 17 15:24:30 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Wed, 17 Dec 2025 15:24:30 -0800
Subject: [PATCH v8 5/7] iommu/arm-smmu-v3: Populate smmu_domain->invs when attaching masters
In-Reply-To: <cover.1766013662.git.nicolinc@nvidia.com>
References: <cover.1766013662.git.nicolinc@nvidia.com>
Message-ID: <79cd18a1a959ee2e54683e8c465b799d49ec48b5.1766013662.git.nicolinc@nvidia.com>

Update the invs array with the invalidations required by each domain type
during attachment operations.

Only an SVA domain or a paging domain will have an invs array:
 a. SVA domain will add an INV_TYPE_S1_ASID per SMMU and an INV_TYPE_ATS
    per SID

 b. Non-nesting-parent paging domain with no ATS-enabled master will add
    a single INV_TYPE_S1_ASID or INV_TYPE_S2_VMID per SMMU

 c. Non-nesting-parent paging domain with ATS-enabled master(s) will do
    (b) and add an INV_TYPE_ATS per SID

 d. Nesting-parent paging domain will add an INV_TYPE_S2_VMID followed by
    an INV_TYPE_S2_VMID_S1_CLEAR per vSMMU. For an ATS-enabled master, it
    will add an INV_TYPE_ATS_FULL per SID

 Note that case #d prepares for a future implementation of VMID allocation
 which requires a followup series for S2 domain sharing. So when a nesting
 parent domain is attached through a vSMMU instance using a nested domain.
 VMID will be allocated per vSMMU instance v.s. currectly per S2 domain.

The per-domain invalidation is not needed until the domain is attached to
a master (when it starts to possibly use TLB). This will make it possible
to attach the domain to multiple SMMUs and avoid unnecessary invalidation
overhead during teardown if no STEs/CDs refer to the domain. It also means
that when the last device is detached, the old domain must flush its ASID
or VMID, since any new iommu_unmap() call would not trigger invalidations
given an empty domain->invs array.

Introduce some arm_smmu_invs helper functions for building scratch arrays,
preparing and installing old/new domain's invalidation arrays.

Co-developed-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h |  17 ++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 253 +++++++++++++++++++-
 2 files changed, 269 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index f98774962012..f8dc96476c43 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -1101,6 +1101,21 @@ static inline bool arm_smmu_master_canwbs(struct arm_smmu_master *master)
 	       IOMMU_FWSPEC_PCI_RC_CANWBS;
 }
 
+/**
+ * struct arm_smmu_inv_state - Per-domain invalidation array state
+ * @invs_ptr: points to the domain->invs (unwinding nesting/etc.) or is NULL if
+ *            no change should be made
+ * @old_invs: the original invs array
+ * @new_invs: for new domain, this is the new invs array to update domain->invs;
+ *            for old domain, this is the master->build_invs to pass in as the
+ *            to_unref argument to an arm_smmu_invs_unref() call
+ */
+struct arm_smmu_inv_state {
+	struct arm_smmu_invs __rcu **invs_ptr;
+	struct arm_smmu_invs *old_invs;
+	struct arm_smmu_invs *new_invs;
+};
+
 struct arm_smmu_attach_state {
 	/* Inputs */
 	struct iommu_domain *old_domain;
@@ -1110,6 +1125,8 @@ struct arm_smmu_attach_state {
 	ioasid_t ssid;
 	/* Resulting state */
 	struct arm_smmu_vmaster *vmaster;
+	struct arm_smmu_inv_state old_domain_invst;
+	struct arm_smmu_inv_state new_domain_invst;
 	bool ats_enabled;
 };
 
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index cc85e7a10ea8..9a2281b5d9da 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -3068,6 +3068,116 @@ static void arm_smmu_disable_iopf(struct arm_smmu_master *master,
 		iopf_queue_remove_device(master->smmu->evtq.iopf, master->dev);
 }
 
+static struct arm_smmu_inv *
+arm_smmu_master_build_inv(struct arm_smmu_master *master,
+			  enum arm_smmu_inv_type type, u32 id, ioasid_t ssid,
+			  size_t pgsize)
+{
+	struct arm_smmu_invs *build_invs = master->build_invs;
+	struct arm_smmu_inv *cur, inv = {
+		.smmu = master->smmu,
+		.type = type,
+		.id = id,
+		.pgsize = pgsize,
+	};
+
+	if (WARN_ON(build_invs->num_invs >= build_invs->max_invs))
+		return NULL;
+	cur = &build_invs->inv[build_invs->num_invs];
+	build_invs->num_invs++;
+
+	*cur = inv;
+	switch (type) {
+	case INV_TYPE_S1_ASID:
+		if (master->smmu->features & ARM_SMMU_FEAT_E2H) {
+			cur->size_opcode = CMDQ_OP_TLBI_EL2_VA;
+			cur->nsize_opcode = CMDQ_OP_TLBI_EL2_ASID;
+		} else {
+			cur->size_opcode = CMDQ_OP_TLBI_NH_VA;
+			cur->nsize_opcode = CMDQ_OP_TLBI_NH_ASID;
+		}
+		break;
+	case INV_TYPE_S2_VMID:
+		cur->size_opcode = CMDQ_OP_TLBI_S2_IPA;
+		cur->nsize_opcode = CMDQ_OP_TLBI_S12_VMALL;
+		break;
+	case INV_TYPE_S2_VMID_S1_CLEAR:
+		cur->size_opcode = cur->nsize_opcode = CMDQ_OP_TLBI_NH_ALL;
+		break;
+	case INV_TYPE_ATS:
+	case INV_TYPE_ATS_FULL:
+		cur->size_opcode = cur->nsize_opcode = CMDQ_OP_ATC_INV;
+		break;
+	}
+
+	return cur;
+}
+
+/*
+ * Use the preallocated scratch array at master->build_invs, to build a to_merge
+ * or to_unref array, to pass into a following arm_smmu_invs_merge/unref() call.
+ *
+ * Do not free the returned invs array. It is reused, and will be overwritten by
+ * the next arm_smmu_master_build_invs() call.
+ */
+static struct arm_smmu_invs *
+arm_smmu_master_build_invs(struct arm_smmu_master *master, bool ats_enabled,
+			   ioasid_t ssid, struct arm_smmu_domain *smmu_domain)
+{
+	const bool nesting = smmu_domain->nest_parent;
+	size_t pgsize = 0, i;
+
+	iommu_group_mutex_assert(master->dev);
+
+	master->build_invs->num_invs = 0;
+
+	/* Range-based invalidation requires the leaf pgsize for calculation */
+	if (master->smmu->features & ARM_SMMU_FEAT_RANGE_INV)
+		pgsize = __ffs(smmu_domain->domain.pgsize_bitmap);
+
+	switch (smmu_domain->stage) {
+	case ARM_SMMU_DOMAIN_SVA:
+	case ARM_SMMU_DOMAIN_S1:
+		if (!arm_smmu_master_build_inv(master, INV_TYPE_S1_ASID,
+					       smmu_domain->cd.asid,
+					       IOMMU_NO_PASID, pgsize))
+			return NULL;
+		break;
+	case ARM_SMMU_DOMAIN_S2:
+		if (!arm_smmu_master_build_inv(master, INV_TYPE_S2_VMID,
+					       smmu_domain->s2_cfg.vmid,
+					       IOMMU_NO_PASID, pgsize))
+			return NULL;
+		break;
+	default:
+		WARN_ON(true);
+		return NULL;
+	}
+
+	/* All the nested S1 ASIDs have to be flushed when S2 parent changes */
+	if (nesting) {
+		if (!arm_smmu_master_build_inv(
+			    master, INV_TYPE_S2_VMID_S1_CLEAR,
+			    smmu_domain->s2_cfg.vmid, IOMMU_NO_PASID, 0))
+			return NULL;
+	}
+
+	for (i = 0; ats_enabled && i < master->num_streams; i++) {
+		/*
+		 * If an S2 used as a nesting parent is changed we have no
+		 * option but to completely flush the ATC.
+		 */
+		if (!arm_smmu_master_build_inv(
+			    master, nesting ? INV_TYPE_ATS_FULL : INV_TYPE_ATS,
+			    master->streams[i].id, ssid, 0))
+			return NULL;
+	}
+
+	/* Note this build_invs must have been sorted */
+
+	return master->build_invs;
+}
+
 static void arm_smmu_remove_master_domain(struct arm_smmu_master *master,
 					  struct iommu_domain *domain,
 					  ioasid_t ssid)
@@ -3097,6 +3207,131 @@ static void arm_smmu_remove_master_domain(struct arm_smmu_master *master,
 	kfree(master_domain);
 }
 
+/*
+ * During attachment, the updates of the two domain->invs arrays are sequenced:
+ *  1. new domain updates its invs array, merging master->build_invs
+ *  2. new domain starts to include the master during its invalidation
+ *  3. master updates its STE switching from the old domain to the new domain
+ *  4. old domain still includes the master during its invalidation
+ *  5. old domain updates its invs array, unreferencing master->build_invs
+ *
+ * For 1 and 5, prepare the two updated arrays in advance, handling any changes
+ * that can possibly failure. So the actual update of either 1 or 5 won't fail.
+ * arm_smmu_asid_lock ensures that the old invs in the domains are intact while
+ * we are sequencing to update them.
+ */
+static int arm_smmu_attach_prepare_invs(struct arm_smmu_attach_state *state,
+					struct arm_smmu_domain *new_smmu_domain)
+{
+	struct arm_smmu_domain *old_smmu_domain =
+		to_smmu_domain_devices(state->old_domain);
+	struct arm_smmu_master *master = state->master;
+	ioasid_t ssid = state->ssid;
+
+	/*
+	 * At this point a NULL domain indicates the domain doesn't use the
+	 * IOTLB, see to_smmu_domain_devices().
+	 */
+	if (new_smmu_domain) {
+		struct arm_smmu_inv_state *invst = &state->new_domain_invst;
+		struct arm_smmu_invs *build_invs;
+
+		invst->invs_ptr = &new_smmu_domain->invs;
+		invst->old_invs = rcu_dereference_protected(
+			new_smmu_domain->invs,
+			lockdep_is_held(&arm_smmu_asid_lock));
+		build_invs = arm_smmu_master_build_invs(
+			master, state->ats_enabled, ssid, new_smmu_domain);
+		if (!build_invs)
+			return -EINVAL;
+
+		invst->new_invs =
+			arm_smmu_invs_merge(invst->old_invs, build_invs);
+		if (IS_ERR(invst->new_invs))
+			return PTR_ERR(invst->new_invs);
+	}
+
+	if (old_smmu_domain) {
+		struct arm_smmu_inv_state *invst = &state->old_domain_invst;
+
+		invst->invs_ptr = &old_smmu_domain->invs;
+		/* A re-attach case might have a different ats_enabled state */
+		if (new_smmu_domain == old_smmu_domain)
+			invst->old_invs = state->new_domain_invst.new_invs;
+		else
+			invst->old_invs = rcu_dereference_protected(
+				old_smmu_domain->invs,
+				lockdep_is_held(&arm_smmu_asid_lock));
+		/* For old_smmu_domain, new_invs points to master->build_invs */
+		invst->new_invs = arm_smmu_master_build_invs(
+			master, master->ats_enabled, ssid, old_smmu_domain);
+	}
+
+	return 0;
+}
+
+/* Must be installed before arm_smmu_install_ste_for_dev() */
+static void
+arm_smmu_install_new_domain_invs(struct arm_smmu_attach_state *state)
+{
+	struct arm_smmu_inv_state *invst = &state->new_domain_invst;
+
+	if (!invst->invs_ptr)
+		return;
+
+	rcu_assign_pointer(*invst->invs_ptr, invst->new_invs);
+	kfree_rcu(invst->old_invs, rcu);
+}
+
+/*
+ * When an array entry's users count reaches zero, it means the ASID/VMID is no
+ * longer being invalidated by map/unmap and must be cleaned. The rule is that
+ * all ASIDs/VMIDs not in an invalidation array are left cleared in the IOTLB.
+ */
+static void arm_smmu_inv_flush_iotlb_tag(struct arm_smmu_inv *inv)
+{
+	struct arm_smmu_cmdq_ent cmd = {};
+
+	switch (inv->type) {
+	case INV_TYPE_S1_ASID:
+		cmd.tlbi.asid = inv->id;
+		break;
+	case INV_TYPE_S2_VMID:
+		/* S2_VMID using nsize_opcode covers S2_VMID_S1_CLEAR */
+		cmd.tlbi.vmid = inv->id;
+		break;
+	default:
+		return;
+	}
+
+	cmd.opcode = inv->nsize_opcode;
+	arm_smmu_cmdq_issue_cmd_with_sync(inv->smmu, &cmd);
+}
+
+/* Should be installed after arm_smmu_install_ste_for_dev() */
+static void
+arm_smmu_install_old_domain_invs(struct arm_smmu_attach_state *state)
+{
+	struct arm_smmu_inv_state *invst = &state->old_domain_invst;
+	struct arm_smmu_invs *old_invs = invst->old_invs;
+	struct arm_smmu_invs *new_invs;
+
+	lockdep_assert_held(&arm_smmu_asid_lock);
+
+	if (!invst->invs_ptr)
+		return;
+
+	arm_smmu_invs_unref(old_invs, invst->new_invs,
+			    arm_smmu_inv_flush_iotlb_tag);
+
+	new_invs = arm_smmu_invs_purge(old_invs);
+	if (!new_invs)
+		return;
+
+	rcu_assign_pointer(*invst->invs_ptr, new_invs);
+	kfree_rcu(old_invs, rcu);
+}
+
 /*
  * Start the sequence to attach a domain to a master. The sequence contains three
  * steps:
@@ -3154,12 +3389,16 @@ int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state,
 				     arm_smmu_ats_supported(master);
 	}
 
+	ret = arm_smmu_attach_prepare_invs(state, smmu_domain);
+	if (ret)
+		return ret;
+
 	if (smmu_domain) {
 		if (new_domain->type == IOMMU_DOMAIN_NESTED) {
 			ret = arm_smmu_attach_prepare_vmaster(
 				state, to_smmu_nested_domain(new_domain));
 			if (ret)
-				return ret;
+				goto err_unprepare_invs;
 		}
 
 		master_domain = kzalloc(sizeof(*master_domain), GFP_KERNEL);
@@ -3207,6 +3446,8 @@ int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state,
 			atomic_inc(&smmu_domain->nr_ats_masters);
 		list_add(&master_domain->devices_elm, &smmu_domain->devices);
 		spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
+
+		arm_smmu_install_new_domain_invs(state);
 	}
 
 	if (!state->ats_enabled && master->ats_enabled) {
@@ -3226,6 +3467,8 @@ int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state,
 	kfree(master_domain);
 err_free_vmaster:
 	kfree(state->vmaster);
+err_unprepare_invs:
+	kfree(state->new_domain_invst.new_invs);
 	return ret;
 }
 
@@ -3257,6 +3500,7 @@ void arm_smmu_attach_commit(struct arm_smmu_attach_state *state)
 	}
 
 	arm_smmu_remove_master_domain(master, state->old_domain, state->ssid);
+	arm_smmu_install_old_domain_invs(state);
 	master->ats_enabled = state->ats_enabled;
 }
 
@@ -3438,12 +3682,19 @@ static int arm_smmu_blocking_set_dev_pasid(struct iommu_domain *new_domain,
 {
 	struct arm_smmu_domain *smmu_domain = to_smmu_domain(old_domain);
 	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
+	struct arm_smmu_attach_state state = {
+		.master = master,
+		.old_domain = old_domain,
+		.ssid = pasid,
+	};
 
 	mutex_lock(&arm_smmu_asid_lock);
+	arm_smmu_attach_prepare_invs(&state, NULL);
 	arm_smmu_clear_cd(master, pasid);
 	if (master->ats_enabled)
 		arm_smmu_atc_inv_master(master, pasid);
 	arm_smmu_remove_master_domain(master, &smmu_domain->domain, pasid);
+	arm_smmu_install_old_domain_invs(&state);
 	mutex_unlock(&arm_smmu_asid_lock);
 
 	/*
-- 
2.43.0



From nicolinc at nvidia.com  Wed Dec 17 15:24:31 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Wed, 17 Dec 2025 15:24:31 -0800
Subject: [PATCH v8 6/7] iommu/arm-smmu-v3: Add arm_smmu_invs based arm_smmu_domain_inv_range()
In-Reply-To: <cover.1766013662.git.nicolinc@nvidia.com>
References: <cover.1766013662.git.nicolinc@nvidia.com>
Message-ID: <d96b106c424b82e1bb4d5d67a47596997dafd78a.1766013662.git.nicolinc@nvidia.com>

Each smmu_domain now has an arm_smmu_invs that specifies the invalidation
steps to perform after any change the IOPTEs. This includes supports for
basic ASID/VMID, the special case for nesting, and ATC invalidations.

Introduce a new arm_smmu_domain_inv helper iterating smmu_domain->invs to
convert the invalidation array to commands. Any invalidation request with
no size specified means an entire flush over a range based one.

Take advantage of the sorted array to compatible batch operations together
to the same SMMU. For instance, ATC invaliations for multiple SIDs can be
pushed as a batch.

ATC invalidations must be completed before the driver disables ATS. Or the
device is permitted to ignore any racing invalidation that would cause an
SMMU timeout. The sequencing is done with a rwlock where holding the write
side of the rwlock means that there are no outstanding ATC invalidations.
If ATS is not used the rwlock is ignored, similar to the existing code.

Co-developed-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h |   9 +
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 258 +++++++++++++++++++-
 2 files changed, 254 insertions(+), 13 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index f8dc96476c43..c3fee7f14480 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -1086,6 +1086,15 @@ void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,
 int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain,
 			    unsigned long iova, size_t size);
 
+void arm_smmu_domain_inv_range(struct arm_smmu_domain *smmu_domain,
+			       unsigned long iova, size_t size,
+			       unsigned int granule, bool leaf);
+
+static inline void arm_smmu_domain_inv(struct arm_smmu_domain *smmu_domain)
+{
+	arm_smmu_domain_inv_range(smmu_domain, 0, 0, 0, false);
+}
+
 void __arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu,
 			      struct arm_smmu_cmdq *cmdq);
 int arm_smmu_init_one_queue(struct arm_smmu_device *smmu,
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 9a2281b5d9da..788c20a9aa76 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2516,23 +2516,19 @@ static void arm_smmu_tlb_inv_context(void *cookie)
 	arm_smmu_atc_inv_domain(smmu_domain, 0, 0);
 }
 
-static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd,
-				     unsigned long iova, size_t size,
-				     size_t granule,
-				     struct arm_smmu_domain *smmu_domain)
+static void arm_smmu_cmdq_batch_add_range(struct arm_smmu_device *smmu,
+					  struct arm_smmu_cmdq_batch *cmds,
+					  struct arm_smmu_cmdq_ent *cmd,
+					  unsigned long iova, size_t size,
+					  size_t granule, size_t pgsize)
 {
-	struct arm_smmu_device *smmu = smmu_domain->smmu;
-	unsigned long end = iova + size, num_pages = 0, tg = 0;
+	unsigned long end = iova + size, num_pages = 0, tg = pgsize;
 	size_t inv_range = granule;
-	struct arm_smmu_cmdq_batch cmds;
 
 	if (!size)
 		return;
 
 	if (smmu->features & ARM_SMMU_FEAT_RANGE_INV) {
-		/* Get the leaf page size */
-		tg = __ffs(smmu_domain->domain.pgsize_bitmap);
-
 		num_pages = size >> tg;
 
 		/* Convert page size of 12,14,16 (log2) to 1,2,3 */
@@ -2552,8 +2548,6 @@ static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd,
 			num_pages++;
 	}
 
-	arm_smmu_cmdq_batch_init(smmu, &cmds, cmd);
-
 	while (iova < end) {
 		if (smmu->features & ARM_SMMU_FEAT_RANGE_INV) {
 			/*
@@ -2581,9 +2575,26 @@ static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd,
 		}
 
 		cmd->tlbi.addr = iova;
-		arm_smmu_cmdq_batch_add(smmu, &cmds, cmd);
+		arm_smmu_cmdq_batch_add(smmu, cmds, cmd);
 		iova += inv_range;
 	}
+}
+
+static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd,
+				     unsigned long iova, size_t size,
+				     size_t granule,
+				     struct arm_smmu_domain *smmu_domain)
+{
+	struct arm_smmu_device *smmu = smmu_domain->smmu;
+	struct arm_smmu_cmdq_batch cmds;
+	size_t pgsize;
+
+	/* Get the leaf page size */
+	pgsize = __ffs(smmu_domain->domain.pgsize_bitmap);
+
+	arm_smmu_cmdq_batch_init(smmu, &cmds, cmd);
+	arm_smmu_cmdq_batch_add_range(smmu, &cmds, cmd, iova, size, granule,
+				      pgsize);
 	arm_smmu_cmdq_batch_submit(smmu, &cmds);
 }
 
@@ -2639,6 +2650,193 @@ void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,
 	__arm_smmu_tlb_inv_range(&cmd, iova, size, granule, smmu_domain);
 }
 
+static bool arm_smmu_inv_size_too_big(struct arm_smmu_device *smmu, size_t size,
+				      size_t granule)
+{
+	size_t max_tlbi_ops;
+
+	/* 0 size means invalidate all */
+	if (!size || size == SIZE_MAX)
+		return true;
+
+	if (smmu->features & ARM_SMMU_FEAT_RANGE_INV)
+		return false;
+
+	/*
+	 * Borrowed from the MAX_TLBI_OPS in arch/arm64/include/asm/tlbflush.h,
+	 * this is used as a threshold to replace "size_opcode" commands with a
+	 * single "nsize_opcode" command, when SMMU doesn't implement the range
+	 * invalidation feature, where there can be too many per-granule TLBIs,
+	 * resulting in a soft lockup.
+	 */
+	max_tlbi_ops = 1 << (ilog2(granule) - 3);
+	return size >= max_tlbi_ops * granule;
+}
+
+/* Used by non INV_TYPE_ATS* invalidations */
+static void arm_smmu_inv_to_cmdq_batch(struct arm_smmu_inv *inv,
+				       struct arm_smmu_cmdq_batch *cmds,
+				       struct arm_smmu_cmdq_ent *cmd,
+				       unsigned long iova, size_t size,
+				       unsigned int granule)
+{
+	if (arm_smmu_inv_size_too_big(inv->smmu, size, granule)) {
+		cmd->opcode = inv->nsize_opcode;
+		arm_smmu_cmdq_batch_add(inv->smmu, cmds, cmd);
+		return;
+	}
+
+	cmd->opcode = inv->size_opcode;
+	arm_smmu_cmdq_batch_add_range(inv->smmu, cmds, cmd, iova, size, granule,
+				      inv->pgsize);
+}
+
+static inline bool arm_smmu_invs_end_batch(struct arm_smmu_inv *cur,
+					   struct arm_smmu_inv *next)
+{
+	/* Changing smmu means changing command queue */
+	if (cur->smmu != next->smmu)
+		return true;
+	/* The batch for S2 TLBI must be done before nested S1 ASIDs */
+	if (cur->type != INV_TYPE_S2_VMID_S1_CLEAR &&
+	    next->type == INV_TYPE_S2_VMID_S1_CLEAR)
+		return true;
+	/* ATS must be after a sync of the S1/S2 invalidations */
+	if (!arm_smmu_inv_is_ats(cur) && arm_smmu_inv_is_ats(next))
+		return true;
+	return false;
+}
+
+static void __arm_smmu_domain_inv_range(struct arm_smmu_invs *invs,
+					unsigned long iova, size_t size,
+					unsigned int granule, bool leaf)
+{
+	struct arm_smmu_cmdq_batch cmds = {};
+	struct arm_smmu_inv *cur;
+	struct arm_smmu_inv *end;
+
+	cur = invs->inv;
+	end = cur + READ_ONCE(invs->num_invs);
+	/* Skip any leading entry marked as a trash */
+	for (; cur != end; cur++)
+		if (refcount_read(&cur->users))
+			break;
+	while (cur != end) {
+		struct arm_smmu_device *smmu = cur->smmu;
+		struct arm_smmu_cmdq_ent cmd = {
+			/*
+			 * Pick size_opcode to run arm_smmu_get_cmdq(). This can
+			 * be changed to nsize_opcode, which would result in the
+			 * same CMDQ pointer.
+			 */
+			.opcode = cur->size_opcode,
+		};
+		struct arm_smmu_inv *next;
+
+		if (!cmds.num)
+			arm_smmu_cmdq_batch_init(smmu, &cmds, &cmd);
+
+		switch (cur->type) {
+		case INV_TYPE_S1_ASID:
+			cmd.tlbi.asid = cur->id;
+			cmd.tlbi.leaf = leaf;
+			arm_smmu_inv_to_cmdq_batch(cur, &cmds, &cmd, iova, size,
+						   granule);
+			break;
+		case INV_TYPE_S2_VMID:
+			cmd.tlbi.vmid = cur->id;
+			cmd.tlbi.leaf = leaf;
+			arm_smmu_inv_to_cmdq_batch(cur, &cmds, &cmd, iova, size,
+						   granule);
+			break;
+		case INV_TYPE_S2_VMID_S1_CLEAR:
+			/* CMDQ_OP_TLBI_S12_VMALL already flushed S1 entries */
+			if (arm_smmu_inv_size_too_big(cur->smmu, size, granule))
+				continue;
+			cmd.tlbi.vmid = cur->id;
+			arm_smmu_cmdq_batch_add(smmu, &cmds, &cmd);
+			break;
+		case INV_TYPE_ATS:
+			arm_smmu_atc_inv_to_cmd(cur->ssid, iova, size, &cmd);
+			cmd.atc.sid = cur->id;
+			arm_smmu_cmdq_batch_add(smmu, &cmds, &cmd);
+			break;
+		case INV_TYPE_ATS_FULL:
+			arm_smmu_atc_inv_to_cmd(IOMMU_NO_PASID, 0, 0, &cmd);
+			cmd.atc.sid = cur->id;
+			arm_smmu_cmdq_batch_add(smmu, &cmds, &cmd);
+			break;
+		default:
+			WARN_ON_ONCE(1);
+			continue;
+		}
+
+		/* Skip any trash entry in-between */
+		for (next = cur + 1; next != end; next++)
+			if (refcount_read(&next->users))
+				break;
+
+		if (cmds.num &&
+		    (next == end || arm_smmu_invs_end_batch(cur, next))) {
+			arm_smmu_cmdq_batch_submit(smmu, &cmds);
+			cmds.num = 0;
+		}
+		cur = next;
+	}
+}
+
+void arm_smmu_domain_inv_range(struct arm_smmu_domain *smmu_domain,
+			       unsigned long iova, size_t size,
+			       unsigned int granule, bool leaf)
+{
+	struct arm_smmu_invs *invs;
+
+	/*
+	 * An invalidation request must follow some IOPTE change and then load
+	 * an invalidation array. In the meantime, a domain attachment mutates
+	 * the array and then stores an STE/CD asking SMMU HW to acquire those
+	 * changed IOPTEs. In other word, these two are interdependent and can
+	 * race.
+	 *
+	 * In a race, the RCU design (with its underlying memory barriers) can
+	 * ensure the invalidation array to always get updated before loaded.
+	 *
+	 * smp_mb() is used here, paired with the smp_mb() following the array
+	 * update in a concurrent attach, to ensure:
+	 *  - HW sees the new IOPTEs if it walks after STE installation
+	 *  - Invalidation thread sees the updated array with the new ASID.
+	 *
+	 *  [CPU0]                        | [CPU1]
+	 *                                |
+	 *  change IOPTEs and TLB flush:  |
+	 *  arm_smmu_domain_inv_range() { | arm_smmu_install_new_domain_invs {
+	 *    ...                         |   rcu_assign_pointer(new_invs);
+	 *    smp_mb(); // ensure IOPTEs  |   smp_mb(); // ensure new_invs
+	 *    ...                         |   kfree_rcu(old_invs, rcu);
+	 *    // load invalidation array  | }
+	 *    invs = rcu_dereference();   | arm_smmu_install_ste_for_dev {
+	 *                                |   STE = TTB0 // read new IOPTEs
+	 */
+	smp_mb();
+
+	rcu_read_lock();
+	invs = rcu_dereference(smmu_domain->invs);
+
+	/*
+	 * Avoid locking unless ATS is being used. No ATC invalidation can be
+	 * going on after a domain is detached.
+	 */
+	if (invs->has_ats) {
+		read_lock(&invs->rwlock);
+		__arm_smmu_domain_inv_range(invs, iova, size, granule, leaf);
+		read_unlock(&invs->rwlock);
+	} else {
+		__arm_smmu_domain_inv_range(invs, iova, size, granule, leaf);
+	}
+
+	rcu_read_unlock();
+}
+
 static void arm_smmu_tlb_inv_page_nosync(struct iommu_iotlb_gather *gather,
 					 unsigned long iova, size_t granule,
 					 void *cookie)
@@ -3280,6 +3478,23 @@ arm_smmu_install_new_domain_invs(struct arm_smmu_attach_state *state)
 		return;
 
 	rcu_assign_pointer(*invst->invs_ptr, invst->new_invs);
+	/*
+	 * We are committed to updating the STE. Ensure the invalidation array
+	 * is visible to concurrent map/unmap threads, and acquire any racing
+	 * IOPTE updates.
+	 *
+	 *  [CPU0]                        | [CPU1]
+	 *                                |
+	 *  change IOPTEs and TLB flush:  |
+	 *  arm_smmu_domain_inv_range() { | arm_smmu_install_new_domain_invs {
+	 *    ...                         |   rcu_assign_pointer(new_invs);
+	 *    smp_mb(); // ensure IOPTEs  |   smp_mb(); // ensure new_invs
+	 *    ...                         |   kfree_rcu(old_invs, rcu);
+	 *    // load invalidation array  | }
+	 *    invs = rcu_dereference();   | arm_smmu_install_ste_for_dev {
+	 *                                |   STE = TTB0 // read new IOPTEs
+	 */
+	smp_mb();
 	kfree_rcu(invst->old_invs, rcu);
 }
 
@@ -3329,6 +3544,23 @@ arm_smmu_install_old_domain_invs(struct arm_smmu_attach_state *state)
 		return;
 
 	rcu_assign_pointer(*invst->invs_ptr, new_invs);
+	/*
+	 * We are committed to updating the STE. Ensure the invalidation array
+	 * is visible to concurrent map/unmap threads, and acquire any racing
+	 * IOPTE updates.
+	 *
+	 *  [CPU0]                        | [CPU1]
+	 *                                |
+	 *  change IOPTEs and TLB flush:  |
+	 *  arm_smmu_domain_inv_range() { | arm_smmu_install_old_domain_invs {
+	 *    ...                         |   rcu_assign_pointer(new_invs);
+	 *    smp_mb(); // ensure IOPTEs  |   smp_mb(); // ensure new_invs
+	 *    ...                         |   kfree_rcu(old_invs, rcu);
+	 *    // load invalidation array  | }
+	 *    invs = rcu_dereference();   | arm_smmu_install_ste_for_dev {
+	 *                                |   STE = TTB0 // read new IOPTEs
+	 */
+	smp_mb();
 	kfree_rcu(old_invs, rcu);
 }
 
-- 
2.43.0



From jonas at kwiboo.se  Wed Dec 17 15:27:32 2025
From: jonas at kwiboo.se (Jonas Karlman)
Date: Thu, 18 Dec 2025 00:27:32 +0100
Subject: [PATCH v6 10/17] media: rkvdec: Add RCB and SRAM support
In-Reply-To: <20251217174059.1341784-11-detlev.casanova@collabora.com>
References: <20251217174059.1341784-1-detlev.casanova@collabora.com>
 <20251217174059.1341784-11-detlev.casanova@collabora.com>
Message-ID: <7431a691-64b3-4b03-85e3-a6162587f6c9@kwiboo.se>

Hi Detlev,

On 12/17/2025 6:40 PM, Detlev Casanova wrote:
> The RCB (Rows and Cols Buffers) are a set of buffers used by other
> variations of the decoder to store temporary data.
> 
> Those variation come with a dedicated SRAM area used to store those
> buffers for better performances.
> 
> The buffer sizes are either the width or height of the frame being
> decoded multiplied by a documented factor and can be stored either
> in SRAM or RAM.
> A fallback to RAM is provided if the SRAM is full (e.g.: multiple
> streams are being decoded at the same time).
> 
> To manage the different kind of allocation, an enum is added to the
> rkvdec_aux_buf struct to specify how the buffer was allocated, and
> so, how to free it.
> 
> This commit is in preparation of other variants support.
> 
> Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
> ---
>  .../media/platform/rockchip/rkvdec/Makefile   |   1 +
>  .../platform/rockchip/rkvdec/rkvdec-rcb.c     | 178 ++++++++++++++++++
>  .../platform/rockchip/rkvdec/rkvdec-rcb.h     |  29 +++
>  .../media/platform/rockchip/rkvdec/rkvdec.c   |  27 ++-
>  .../media/platform/rockchip/rkvdec/rkvdec.h   |  13 ++
>  5 files changed, 246 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c
>  create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
> index 1b4bc44be23e..3d75103e536d 100644
> --- a/drivers/media/platform/rockchip/rkvdec/Makefile
> +++ b/drivers/media/platform/rockchip/rkvdec/Makefile
> @@ -7,4 +7,5 @@ rockchip-vdec-y += \
>  		   rkvdec-h264-common.o \
>  		   rkvdec-hevc.o \
>  		   rkvdec-hevc-common.o \
> +		   rkvdec-rcb.o \
>  		   rkvdec-vp9.o
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c
> new file mode 100644
> index 000000000000..320998ed2c74
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c
> @@ -0,0 +1,178 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Rockchip video decoder Rows and Cols Buffers manager
> + *
> + * Copyright (C) 2025 Collabora, Ltd.
> + *  Detlev Casanova <detlev.casanova at collabora.com>
> + */
> +
> +#include "rkvdec.h"
> +#include "rkvdec-rcb.h"
> +
> +#include <linux/types.h>
> +#include <linux/iommu.h>
> +#include <linux/genalloc.h>
> +
> +struct rkvdec_rcb_config {
> +	struct rkvdec_aux_buf *rcb_bufs;
> +	size_t rcb_count;
> +};
> +
> +static size_t rkvdec_rcb_size(const struct rcb_size_info *size_info,
> +			      unsigned int width, unsigned int height)
> +{
> +	return size_info->multiplier * (size_info->axis == PIC_HEIGHT ? height : width);
> +}
> +
> +dma_addr_t rkvdec_rcb_buf_dma_addr(struct rkvdec_ctx *ctx, int id)
> +{
> +	return ctx->rcb_config->rcb_bufs[id].dma;
> +}
> +
> +size_t rkvdec_rcb_buf_size(struct rkvdec_ctx *ctx, int id)
> +{
> +	return ctx->rcb_config->rcb_bufs[id].size;
> +}
> +
> +int rkvdec_rcb_buf_count(struct rkvdec_ctx *ctx)
> +{
> +	return ctx->rcb_config->rcb_count;
> +}
> +
> +void rkvdec_free_rcb(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_dev *dev = ctx->dev;
> +	struct rkvdec_rcb_config *cfg = ctx->rcb_config;
> +	unsigned long virt_addr;
> +	int i;
> +
> +	if (!cfg)
> +		return;
> +
> +	for (i = 0; i < cfg->rcb_count; i++) {
> +		size_t rcb_size = cfg->rcb_bufs[i].size;
> +
> +		if (!cfg->rcb_bufs[i].cpu)
> +			continue;
> +
> +		switch (cfg->rcb_bufs[i].type) {
> +		case RKVDEC_ALLOC_SRAM:
> +			virt_addr = (unsigned long)cfg->rcb_bufs[i].cpu;
> +
> +			if (dev->iommu_domain)
> +				iommu_unmap(dev->iommu_domain, virt_addr, rcb_size);
> +			gen_pool_free(dev->sram_pool, virt_addr, rcb_size);
> +			break;
> +		case RKVDEC_ALLOC_DMA:
> +			dma_free_coherent(dev->dev,
> +					  rcb_size,
> +					  cfg->rcb_bufs[i].cpu,
> +					  cfg->rcb_bufs[i].dma);
> +			break;
> +		}
> +	}
> +
> +	if (cfg->rcb_bufs)
> +		devm_kfree(dev->dev, cfg->rcb_bufs);
> +
> +	devm_kfree(dev->dev, cfg);
> +}
> +
> +int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx,
> +			const struct rcb_size_info *size_info,
> +			size_t rcb_count)
> +{
> +	int ret, i;
> +	u32 width, height;
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	struct rkvdec_rcb_config *cfg;
> +
> +	if (!size_info || !rcb_count) {
> +		ctx->rcb_config = NULL;
> +		return 0;
> +	}
> +
> +	ctx->rcb_config = devm_kzalloc(rkvdec->dev, sizeof(*ctx->rcb_config), GFP_KERNEL);
> +	if (!ctx->rcb_config)
> +		return -ENOMEM;
> +
> +	cfg = ctx->rcb_config;
> +
> +	cfg->rcb_bufs = devm_kzalloc(rkvdec->dev, sizeof(*cfg->rcb_bufs) * rcb_count, GFP_KERNEL);
> +	if (!cfg->rcb_bufs) {
> +		ret = -ENOMEM;
> +		goto err_alloc;
> +	}
> +
> +	width = ctx->decoded_fmt.fmt.pix_mp.width;
> +	height = ctx->decoded_fmt.fmt.pix_mp.height;
> +
> +	for (i = 0; i < rcb_count; i++) {
> +		void *cpu = NULL;
> +		dma_addr_t dma;
> +		size_t rcb_size = rkvdec_rcb_size(&size_info[i], width, height);
> +		enum rkvdec_alloc_type alloc_type = RKVDEC_ALLOC_SRAM;
> +
> +		/* Try allocating an SRAM buffer */
> +		if (ctx->dev->sram_pool) {
> +			if (rkvdec->iommu_domain)
> +				rcb_size = ALIGN(rcb_size, 0x1000);

Maybe SZ_4K instead of 0x1000 ?

> +
> +			cpu = gen_pool_dma_zalloc_align(ctx->dev->sram_pool,
> +							rcb_size,
> +							&dma,
> +							0x1000);

Same here ?

Regards,
Jonas

> +		}
> +
> +		/* If an IOMMU is used, map the SRAM address through it */
> +		if (cpu && rkvdec->iommu_domain) {
> +			unsigned long virt_addr = (unsigned long)cpu;
> +			phys_addr_t phys_addr = dma;
> +
> +			ret = iommu_map(rkvdec->iommu_domain, virt_addr, phys_addr,
> +					rcb_size, IOMMU_READ | IOMMU_WRITE, 0);
> +			if (ret) {
> +				gen_pool_free(ctx->dev->sram_pool,
> +					      (unsigned long)cpu,
> +					      rcb_size);
> +				cpu = NULL;
> +				goto ram_fallback;
> +			}
> +
> +			/*
> +			 * The registers will be configured with the virtual
> +			 * address so that it goes through the IOMMU
> +			 */
> +			dma = virt_addr;
> +		}
> +
> +ram_fallback:
> +		/* Fallback to RAM */
> +		if (!cpu) {
> +			cpu = dma_alloc_coherent(ctx->dev->dev,
> +						 rcb_size,
> +						 &dma,
> +						 GFP_KERNEL);
> +			alloc_type = RKVDEC_ALLOC_DMA;
> +		}
> +
> +		if (!cpu) {
> +			ret = -ENOMEM;
> +			goto err_alloc;
> +		}
> +
> +		cfg->rcb_bufs[i].cpu = cpu;
> +		cfg->rcb_bufs[i].dma = dma;
> +		cfg->rcb_bufs[i].size = rcb_size;
> +		cfg->rcb_bufs[i].type = alloc_type;
> +
> +		cfg->rcb_count += 1;
> +	}
> +
> +	return 0;
> +
> +err_alloc:
> +	rkvdec_free_rcb(ctx);
> +
> +	return ret;
> +}
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h
> new file mode 100644
> index 000000000000..30e8002555c8
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h
> @@ -0,0 +1,29 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Rockchip video decoder Rows and Cols Buffers manager
> + *
> + * Copyright (C) 2025 Collabora, Ltd.
> + *  Detlev Casanova <detlev.casanova at collabora.com>
> + */
> +
> +#include <linux/types.h>
> +
> +struct rkvdec_ctx;
> +
> +enum rcb_axis {
> +	PIC_WIDTH = 0,
> +	PIC_HEIGHT = 1
> +};
> +
> +struct rcb_size_info {
> +	u8 multiplier;
> +	enum rcb_axis axis;
> +};
> +
> +int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx,
> +			const struct rcb_size_info *size_info,
> +			size_t rcb_count);
> +dma_addr_t rkvdec_rcb_buf_dma_addr(struct rkvdec_ctx *ctx, int id);
> +size_t rkvdec_rcb_buf_size(struct rkvdec_ctx *ctx, int id);
> +int rkvdec_rcb_buf_count(struct rkvdec_ctx *ctx);
> +void rkvdec_free_rcb(struct rkvdec_ctx *ctx);
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> index 968982f6e62c..028ce8e1c4ca 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> @@ -10,6 +10,7 @@
>   */
>  
>  #include <linux/clk.h>
> +#include <linux/genalloc.h>
>  #include <linux/interrupt.h>
>  #include <linux/iommu.h>
>  #include <linux/module.h>
> @@ -28,6 +29,7 @@
>  
>  #include "rkvdec.h"
>  #include "rkvdec-regs.h"
> +#include "rkvdec-rcb.h"
>  
>  static bool rkvdec_image_fmt_match(enum rkvdec_image_fmt fmt1,
>  				   enum rkvdec_image_fmt fmt2)
> @@ -771,6 +773,7 @@ static int rkvdec_start_streaming(struct vb2_queue *q, unsigned int count)
>  {
>  	struct rkvdec_ctx *ctx = vb2_get_drv_priv(q);
>  	const struct rkvdec_coded_fmt_desc *desc;
> +	const struct rkvdec_variant *variant = ctx->dev->variant;
>  	int ret;
>  
>  	if (V4L2_TYPE_IS_CAPTURE(q->type))
> @@ -780,13 +783,22 @@ static int rkvdec_start_streaming(struct vb2_queue *q, unsigned int count)
>  	if (WARN_ON(!desc))
>  		return -EINVAL;
>  
> +	ret = rkvdec_allocate_rcb(ctx, variant->rcb_sizes, variant->num_rcb_sizes);
> +	if (ret)
> +		return ret;
> +
>  	if (desc->ops->start) {
>  		ret = desc->ops->start(ctx);
>  		if (ret)
> -			return ret;
> +			goto err_ops_start;
>  	}
>  
>  	return 0;
> +
> +err_ops_start:
> +	rkvdec_free_rcb(ctx);
> +
> +	return ret;
>  }
>  
>  static void rkvdec_queue_cleanup(struct vb2_queue *vq, u32 state)
> @@ -822,6 +834,8 @@ static void rkvdec_stop_streaming(struct vb2_queue *q)
>  
>  		if (desc->ops->stop)
>  			desc->ops->stop(ctx);
> +
> +		rkvdec_free_rcb(ctx);
>  	}
>  
>  	rkvdec_queue_cleanup(q, VB2_BUF_STATE_ERROR);
> @@ -1348,6 +1362,10 @@ static int rkvdec_probe(struct platform_device *pdev)
>  		return ret;
>  	}
>  
> +	rkvdec->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0);
> +	if (!rkvdec->sram_pool && rkvdec->variant->num_rcb_sizes > 0)
> +		dev_info(&pdev->dev, "No sram node, RCB will be stored in RAM\n");
> +
>  	pm_runtime_set_autosuspend_delay(&pdev->dev, 100);
>  	pm_runtime_use_autosuspend(&pdev->dev);
>  	pm_runtime_enable(&pdev->dev);
> @@ -1356,7 +1374,8 @@ static int rkvdec_probe(struct platform_device *pdev)
>  	if (ret)
>  		goto err_disable_runtime_pm;
>  
> -	if (iommu_get_domain_for_dev(&pdev->dev)) {
> +	rkvdec->iommu_domain = iommu_get_domain_for_dev(&pdev->dev);
> +	if (rkvdec->iommu_domain) {
>  		rkvdec->empty_domain = iommu_paging_domain_alloc(rkvdec->dev);
>  
>  		if (IS_ERR(rkvdec->empty_domain)) {
> @@ -1370,6 +1389,10 @@ static int rkvdec_probe(struct platform_device *pdev)
>  err_disable_runtime_pm:
>  	pm_runtime_dont_use_autosuspend(&pdev->dev);
>  	pm_runtime_disable(&pdev->dev);
> +
> +	if (rkvdec->sram_pool)
> +		gen_pool_destroy(rkvdec->sram_pool);
> +
>  	return ret;
>  }
>  
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> index aac6cba4c623..77c0950a465d 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> @@ -19,6 +19,7 @@
>  #include <media/v4l2-ctrls.h>
>  #include <media/v4l2-device.h>
>  #include <media/v4l2-ioctl.h>
> +#include <media/v4l2-mem2mem.h>
>  #include <media/videobuf2-core.h>
>  #include <media/videobuf2-dma-contig.h>
>  
> @@ -29,6 +30,7 @@
>  #define RKVDEC_QUIRK_DISABLE_QOS	BIT(0)
>  
>  struct rkvdec_ctx;
> +struct rkvdec_rcb_config;
>  
>  struct rkvdec_ctrl_desc {
>  	struct v4l2_ctrl_config cfg;
> @@ -73,6 +75,8 @@ struct rkvdec_variant {
>  	unsigned int num_regs;
>  	const struct rkvdec_coded_fmt_desc *coded_fmts;
>  	size_t num_coded_fmts;
> +	const struct rcb_size_info *rcb_sizes;
> +	size_t num_rcb_sizes;
>  	unsigned int capabilities;
>  	unsigned int quirks;
>  };
> @@ -125,6 +129,8 @@ struct rkvdec_dev {
>  	void __iomem *regs;
>  	struct mutex vdev_lock; /* serializes ioctls */
>  	struct delayed_work watchdog_work;
> +	struct gen_pool *sram_pool;
> +	struct iommu_domain *iommu_domain;
>  	struct iommu_domain *empty_domain;
>  	const struct rkvdec_variant *variant;
>  };
> @@ -137,6 +143,7 @@ struct rkvdec_ctx {
>  	struct v4l2_ctrl_handler ctrl_hdl;
>  	struct rkvdec_dev *dev;
>  	enum rkvdec_image_fmt image_fmt;
> +	struct rkvdec_rcb_config *rcb_config;
>  	void *priv;
>  };
>  
> @@ -145,10 +152,16 @@ static inline struct rkvdec_ctx *file_to_rkvdec_ctx(struct file *filp)
>  	return container_of(file_to_v4l2_fh(filp), struct rkvdec_ctx, fh);
>  }
>  
> +enum rkvdec_alloc_type {
> +	RKVDEC_ALLOC_DMA  = 0,
> +	RKVDEC_ALLOC_SRAM = 1,
> +};
> +
>  struct rkvdec_aux_buf {
>  	void *cpu;
>  	dma_addr_t dma;
>  	size_t size;
> +	enum rkvdec_alloc_type type;
>  };
>  
>  void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run);



From mh at probably.group  Wed Dec 17 15:31:18 2025
From: mh at probably.group (=?utf-8?B?Ik1hcnRpbiBIb2xvdnNrw70gKFByb2JhYmx5IE5vdGhpbmcgcy5yLm8u?= =?utf-8?B?KSI=?=)
Date: Thu, 18 Dec 2025 00:31:18 +0100
Subject: [PATCH] arm64: dts: rockchip: enable dual 2.5GbE on Rock 5T
In-Reply-To: <176580661874.1441131.12947657582985645446.b4-ty@sntech.de>
References: <96516D1F-9787-47FE-A67E-4745D11D9207@probably.group>
 <176580661874.1441131.12947657582985645446.b4-ty@sntech.de>
Message-ID: <7A2ADADA-3FD8-4AAE-B7D8-9137399FBE6E@probably.group>

Perfect, thanks a lot!

> On 15. 12. 2025, at 14:51, Heiko Stuebner <heiko at sntech.de> wrote:
> 
> 
> On Fri, 12 Dec 2025 17:23:35 +0100, "Martin Holovsk? (Probably Nothing s.r.o. )" wrote:
>> The Radxa Rock 5T board features two RTL8125B 2.5GbE Ethernet controllers
>> connected via PCIe lanes pcie2x1l0 (fe170000) and pcie2x1l2 (fe190000).
>> Currently only one interface is functional because the PCIe controller
>> nodes lack the necessary reset GPIO configuration.
>> 
>> Without the reset-gpios property, the RTL8125B PHYs remain in reset state
>> and are not enumerated by the PCIe bus. This results in only one Ethernet
>> interface being detected, or none at all depending on U-Boot initialization.
>> 
>> [...]
> 
> Applied, thanks!
> 
> [1/1] arm64: dts: rockchip: enable dual 2.5GbE on Rock 5T
>      commit: 96029ffeccf677b1e4baa98f30909a83a485b6d7
> 
> I've resorted both the pcie phandles as well as the pinctrl entries
> pcie2-0 comes before pcie2-1 etc :-) .
> 
> Best regards,
> -- 
> Heiko Stuebner <heiko at sntech.de>



From puranjay at kernel.org  Wed Dec 17 15:35:55 2025
From: puranjay at kernel.org (Puranjay Mohan)
Date: Wed, 17 Dec 2025 15:35:55 -0800
Subject: [PATCH bpf-next v2 0/2] bpf: Optimize recursion detection on arm64
Message-ID: <20251217233608.2374187-1-puranjay@kernel.org>

V1: https://lore.kernel.org/all/20251217162830.2597286-1-puranjay at kernel.org/
Changes in V1->V2:
- Patch 2:
	- Put preempt_enable()/disable() around RMW accesses to mitigate
	  race conditions. Because on CONFIG_PREEMPT_RCU and sleepable
	  bpf programs, preemption can cause no prog to execute.

BPF programs detect recursion using a per-CPU 'active' flag in struct
bpf_prog. The trampoline currently sets/clears this flag with atomic
operations.

On some arm64 platforms (e.g., Neoverse V2 with LSE), per-CPU atomic
operations are relatively slow. Unlike x86_64 - where per-CPU updates
can avoid cross-core atomicity, arm64 LSE atomics are always atomic
across all cores, which is unnecessary overhead for strictly per-CPU
state.

This patch removes atomics from the recursion detection path on arm64.

It was discovered in [1] that per-CPU atomics that don't return a value
were extremely slow on some arm64 platforms, Catalin added a fix in
commit 535fdfc5a228 ("arm64: Use load LSE atomics for the non-return
per-CPU atomic operations") to solve this issue, but it seems to have
caused a regression on the fentry benchmark.

Using the fentry benchmark from the bpf selftests shows the following:

  ./tools/testing/selftests/bpf/bench trig-fentry

 +---------------------------------------------+------------------------+
 |               Configuration                 | Total Operations (M/s) |
 +---------------------------------------------+------------------------+
 | bpf-next/master with Catalin?s fix reverted |         51.862         |
 |---------------------------------------------|------------------------|
 | bpf-next/master                             |         43.067         |
 | bpf-next/master with this change            |         53.856         |
 +---------------------------------------------+------------------------+

All benchmarks were run on a KVM based vm with Neoverse-V2 and 8 cpus.

This patch yields a 25% improvement in this benchmark compared to
bpf-next. Notably, reverting Catalin's fix also results in a performance
gain for this benchmark, which is interesting but expected.

For completeness, this benchmark was also run with the change enabled on
x86-64, which resulted in a 30% regression in the fentry benchmark. So,
it is only enabled on arm64.

[1] https://lore.kernel.org/all/e7d539ed-ced0-4b96-8ecd-048a5b803b85 at paulmck-laptop/

Puranjay Mohan (2):
  bpf: move recursion detection logic to helpers
  bpf: arm64: Optimize recursion detection by not using atomics

 include/linux/bpf.h      | 39 ++++++++++++++++++++++++++++++++++++++-
 kernel/bpf/core.c        |  3 ++-
 kernel/bpf/trampoline.c  |  8 ++++----
 kernel/trace/bpf_trace.c |  4 ++--
 4 files changed, 46 insertions(+), 8 deletions(-)


base-commit: ec439c38013550420aecc15988ae6acb670838c1
-- 
2.47.3



From puranjay at kernel.org  Wed Dec 17 15:35:56 2025
From: puranjay at kernel.org (Puranjay Mohan)
Date: Wed, 17 Dec 2025 15:35:56 -0800
Subject: [PATCH bpf-next v2 1/2] bpf: move recursion detection logic to helpers
In-Reply-To: <20251217233608.2374187-1-puranjay@kernel.org>
References: <20251217233608.2374187-1-puranjay@kernel.org>
Message-ID: <20251217233608.2374187-2-puranjay@kernel.org>

BPF programs detect recursion by doing atomic inc/dec on a per-cpu
active counter from the trampoline. Create two helpers for operations on
this active counter, this makes it easy to changes the recursion
detection logic in future.

This change makes no functional changes.

Signed-off-by: Puranjay Mohan <puranjay at kernel.org>
---
 include/linux/bpf.h      | 10 ++++++++++
 kernel/bpf/trampoline.c  |  8 ++++----
 kernel/trace/bpf_trace.c |  4 ++--
 3 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index bb3847caeae1..2da986136d26 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -2004,6 +2004,16 @@ struct bpf_struct_ops_common_value {
 	enum bpf_struct_ops_state state;
 };
 
+static inline bool bpf_prog_get_recursion_context(struct bpf_prog *prog)
+{
+	return this_cpu_inc_return(*(prog->active)) == 1;
+}
+
+static inline void bpf_prog_put_recursion_context(struct bpf_prog *prog)
+{
+	this_cpu_dec(*(prog->active));
+}
+
 #if defined(CONFIG_BPF_JIT) && defined(CONFIG_BPF_SYSCALL)
 /* This macro helps developer to register a struct_ops type and generate
  * type information correctly. Developers should use this macro to register
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index 976d89011b15..2a125d063e62 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -949,7 +949,7 @@ static u64 notrace __bpf_prog_enter_recur(struct bpf_prog *prog, struct bpf_tram
 
 	run_ctx->saved_run_ctx = bpf_set_run_ctx(&run_ctx->run_ctx);
 
-	if (unlikely(this_cpu_inc_return(*(prog->active)) != 1)) {
+	if (unlikely(!bpf_prog_get_recursion_context(prog))) {
 		bpf_prog_inc_misses_counter(prog);
 		if (prog->aux->recursion_detected)
 			prog->aux->recursion_detected(prog);
@@ -993,7 +993,7 @@ static void notrace __bpf_prog_exit_recur(struct bpf_prog *prog, u64 start,
 	bpf_reset_run_ctx(run_ctx->saved_run_ctx);
 
 	update_prog_stats(prog, start);
-	this_cpu_dec(*(prog->active));
+	bpf_prog_put_recursion_context(prog);
 	rcu_read_unlock_migrate();
 }
 
@@ -1029,7 +1029,7 @@ u64 notrace __bpf_prog_enter_sleepable_recur(struct bpf_prog *prog,
 
 	run_ctx->saved_run_ctx = bpf_set_run_ctx(&run_ctx->run_ctx);
 
-	if (unlikely(this_cpu_inc_return(*(prog->active)) != 1)) {
+	if (unlikely(!bpf_prog_get_recursion_context(prog))) {
 		bpf_prog_inc_misses_counter(prog);
 		if (prog->aux->recursion_detected)
 			prog->aux->recursion_detected(prog);
@@ -1044,7 +1044,7 @@ void notrace __bpf_prog_exit_sleepable_recur(struct bpf_prog *prog, u64 start,
 	bpf_reset_run_ctx(run_ctx->saved_run_ctx);
 
 	update_prog_stats(prog, start);
-	this_cpu_dec(*(prog->active));
+	bpf_prog_put_recursion_context(prog);
 	migrate_enable();
 	rcu_read_unlock_trace();
 }
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index fe28d86f7c35..6e076485bf70 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -2063,7 +2063,7 @@ void __bpf_trace_run(struct bpf_raw_tp_link *link, u64 *args)
 	struct bpf_trace_run_ctx run_ctx;
 
 	cant_sleep();
-	if (unlikely(this_cpu_inc_return(*(prog->active)) != 1)) {
+	if (unlikely(!bpf_prog_get_recursion_context(prog))) {
 		bpf_prog_inc_misses_counter(prog);
 		goto out;
 	}
@@ -2077,7 +2077,7 @@ void __bpf_trace_run(struct bpf_raw_tp_link *link, u64 *args)
 
 	bpf_reset_run_ctx(old_run_ctx);
 out:
-	this_cpu_dec(*(prog->active));
+	bpf_prog_put_recursion_context(prog);
 }
 
 #define UNPACK(...)			__VA_ARGS__
-- 
2.47.3



From puranjay at kernel.org  Wed Dec 17 15:35:57 2025
From: puranjay at kernel.org (Puranjay Mohan)
Date: Wed, 17 Dec 2025 15:35:57 -0800
Subject: [PATCH bpf-next v2 2/2] bpf: arm64: Optimize recursion detection by not using atomics
In-Reply-To: <20251217233608.2374187-1-puranjay@kernel.org>
References: <20251217233608.2374187-1-puranjay@kernel.org>
Message-ID: <20251217233608.2374187-3-puranjay@kernel.org>

BPF programs detect recursion using a per-CPU 'active' flag in struct
bpf_prog. The trampoline currently sets/clears this flag with atomic
operations.

On some arm64 platforms (e.g., Neoverse V2 with LSE), per-CPU atomic
operations are relatively slow. Unlike x86_64 - where per-CPU updates
can avoid cross-core atomicity, arm64 LSE atomics are always atomic
across all cores, which is unnecessary overhead for strictly per-CPU
state.

This patch removes atomics from the recursion detection path on arm64 by
changing 'active' to a per-CPU array of four u8 counters, one per
context: {NMI, hard-irq, soft-irq, normal}. The running context uses a
non-atomic increment/decrement on its element.  After increment,
recursion is detected by reading the array as a u32 and verifying that
only the expected element changed; any change in another element
indicates inter-context recursion, and a value > 1 in the same element
indicates same-context recursion.

For example, starting from {0,0,0,0}, a normal-context trigger changes
the array to {0,0,0,1}.  If an NMI arrives on the same CPU and triggers
the program, the array becomes {1,0,0,1}. When the NMI context checks
the u32 against the expected mask for normal (0x00000001), it observes
0x01000001 and correctly reports recursion. Same-context recursion is
detected analogously.

Signed-off-by: Puranjay Mohan <puranjay at kernel.org>
---
 include/linux/bpf.h | 33 ++++++++++++++++++++++++++++++---
 kernel/bpf/core.c   |  3 ++-
 2 files changed, 32 insertions(+), 4 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 2da986136d26..5ca2a761d9a1 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -31,6 +31,7 @@
 #include <linux/static_call.h>
 #include <linux/memcontrol.h>
 #include <linux/cfi.h>
+#include <linux/unaligned.h>
 #include <asm/rqspinlock.h>
 
 struct bpf_verifier_env;
@@ -1746,6 +1747,8 @@ struct bpf_prog_aux {
 	struct bpf_map __rcu *st_ops_assoc;
 };
 
+#define BPF_NR_CONTEXTS        4       /* normal, softirq, hardirq, NMI */
+
 struct bpf_prog {
 	u16			pages;		/* Number of allocated pages */
 	u16			jited:1,	/* Is our filter JIT'ed? */
@@ -1772,7 +1775,7 @@ struct bpf_prog {
 		u8 tag[BPF_TAG_SIZE];
 	};
 	struct bpf_prog_stats __percpu *stats;
-	int __percpu		*active;
+	u8 __percpu		*active;	/* u8[BPF_NR_CONTEXTS] for rerecursion protection */
 	unsigned int		(*bpf_func)(const void *ctx,
 					    const struct bpf_insn *insn);
 	struct bpf_prog_aux	*aux;		/* Auxiliary fields */
@@ -2006,12 +2009,36 @@ struct bpf_struct_ops_common_value {
 
 static inline bool bpf_prog_get_recursion_context(struct bpf_prog *prog)
 {
-	return this_cpu_inc_return(*(prog->active)) == 1;
+#ifdef CONFIG_ARM64
+	u8 rctx = interrupt_context_level();
+	u8 *active = this_cpu_ptr(prog->active);
+	u32 val;
+
+	preempt_disable();
+	active[rctx]++;
+	val = get_unaligned_le32(active);
+	preempt_enable();
+	if (val != BIT(rctx * 8))
+		return false;
+
+	return true;
+#else
+	return this_cpu_inc_return(*(int __percpu *)(prog->active)) == 1;
+#endif
 }
 
 static inline void bpf_prog_put_recursion_context(struct bpf_prog *prog)
 {
-	this_cpu_dec(*(prog->active));
+#ifdef CONFIG_ARM64
+	u8 rctx = interrupt_context_level();
+	u8 *active = this_cpu_ptr(prog->active);
+
+	preempt_disable();
+	active[rctx]--;
+	preempt_enable();
+#else
+	this_cpu_dec(*(int __percpu *)(prog->active));
+#endif
 }
 
 #if defined(CONFIG_BPF_JIT) && defined(CONFIG_BPF_SYSCALL)
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index c66316e32563..b5063acfcf92 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -112,7 +112,8 @@ struct bpf_prog *bpf_prog_alloc_no_stats(unsigned int size, gfp_t gfp_extra_flag
 		vfree(fp);
 		return NULL;
 	}
-	fp->active = alloc_percpu_gfp(int, bpf_memcg_flags(GFP_KERNEL | gfp_extra_flags));
+	fp->active = __alloc_percpu_gfp(sizeof(u8[BPF_NR_CONTEXTS]), 8,
+					bpf_memcg_flags(GFP_KERNEL | gfp_extra_flags));
 	if (!fp->active) {
 		vfree(fp);
 		kfree(aux);
-- 
2.47.3



From jonas at kwiboo.se  Wed Dec 17 15:37:20 2025
From: jonas at kwiboo.se (Jonas Karlman)
Date: Thu, 18 Dec 2025 00:37:20 +0100
Subject: [PATCH v6 09/17] media: rkvdec: Add variant specific coded
 formats list
In-Reply-To: <20251217174059.1341784-10-detlev.casanova@collabora.com>
References: <20251217174059.1341784-1-detlev.casanova@collabora.com>
 <20251217174059.1341784-10-detlev.casanova@collabora.com>
Message-ID: <47729359-6eb4-494d-9e21-4a3c34cba324@kwiboo.se>

Hi Detlev,

On 12/17/2025 6:40 PM, Detlev Casanova wrote:
> Prepare for adding new variants of the decoder and support specific
> formats and format ops per variant.
> 
> Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
> ---
>  .../media/platform/rockchip/rkvdec/rkvdec.c   | 35 ++++++++++++-------
>  .../media/platform/rockchip/rkvdec/rkvdec.h   |  2 ++
>  2 files changed, 24 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> index 776149f871b0..968982f6e62c 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> @@ -373,15 +373,16 @@ static bool rkvdec_is_capable(struct rkvdec_ctx *ctx, unsigned int capability)
>  static const struct rkvdec_coded_fmt_desc *
>  rkvdec_enum_coded_fmt_desc(struct rkvdec_ctx *ctx, int index)
>  {
> +	const struct rkvdec_variant *variant = ctx->dev->variant;
>  	int fmt_idx = -1;
>  	unsigned int i;
>  
> -	for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++) {
> -		if (!rkvdec_is_capable(ctx, rkvdec_coded_fmts[i].capability))
> +	for (i = 0; i < variant->num_coded_fmts; i++) {
> +		if (!rkvdec_is_capable(ctx, variant->coded_fmts[i].capability))
>  			continue;
>  		fmt_idx++;
>  		if (index == fmt_idx)
> -			return &rkvdec_coded_fmts[i];
> +			return &variant->coded_fmts[i];
>  	}
>  
>  	return NULL;
> @@ -390,12 +391,13 @@ rkvdec_enum_coded_fmt_desc(struct rkvdec_ctx *ctx, int index)
>  static const struct rkvdec_coded_fmt_desc *
>  rkvdec_find_coded_fmt_desc(struct rkvdec_ctx *ctx, u32 fourcc)
>  {
> +	const struct rkvdec_variant *variant = ctx->dev->variant;
>  	unsigned int i;
>  
> -	for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++) {
> -		if (rkvdec_is_capable(ctx, rkvdec_coded_fmts[i].capability) &&
> -		    rkvdec_coded_fmts[i].fourcc == fourcc)
> -			return &rkvdec_coded_fmts[i];
> +	for (i = 0; i < variant->num_coded_fmts; i++) {
> +		if (rkvdec_is_capable(ctx, variant->coded_fmts[i].capability) &&
> +		    variant->coded_fmts[i].fourcc == fourcc)
> +			return &variant->coded_fmts[i];
>  	}
>  
>  	return NULL;
> @@ -1014,18 +1016,19 @@ static int rkvdec_add_ctrls(struct rkvdec_ctx *ctx,
>  
>  static int rkvdec_init_ctrls(struct rkvdec_ctx *ctx)
>  {
> +	const struct rkvdec_variant *variant = ctx->dev->variant;
>  	unsigned int i, nctrls = 0;
>  	int ret;
>  
> -	for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++)
> -		if (rkvdec_is_capable(ctx, rkvdec_coded_fmts[i].capability))
> -			nctrls += rkvdec_coded_fmts[i].ctrls->num_ctrls;
> +	for (i = 0; i < variant->num_coded_fmts; i++)
> +		if (rkvdec_is_capable(ctx, variant->coded_fmts[i].capability))
> +			nctrls += variant->coded_fmts[i].ctrls->num_ctrls;
>  
>  	v4l2_ctrl_handler_init(&ctx->ctrl_hdl, nctrls);
>  
> -	for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++) {
> -		if (rkvdec_is_capable(ctx, rkvdec_coded_fmts[i].capability)) {
> -			ret = rkvdec_add_ctrls(ctx, rkvdec_coded_fmts[i].ctrls);
> +	for (i = 0; i < variant->num_coded_fmts; i++) {
> +		if (rkvdec_is_capable(ctx, variant->coded_fmts[i].capability)) {
> +			ret = rkvdec_add_ctrls(ctx, variant->coded_fmts[i].ctrls);
>  			if (ret)
>  				goto err_free_handler;
>  		}
> @@ -1242,11 +1245,15 @@ static void rkvdec_watchdog_func(struct work_struct *work)
>  
>  static const struct rkvdec_variant rk3288_rkvdec_variant = {
>  	.num_regs = 68,
> +	.coded_fmts = rkvdec_coded_fmts,
> +	.num_coded_fmts = ARRAY_SIZE(rkvdec_coded_fmts),
>  	.capabilities = RKVDEC_CAPABILITY_HEVC,

Looks like we could drop the capabilities flags handling now that we
use a per variant coded_fmts ?

Maybe a rk3288_coded_fmts should be added and used here, or in a cleanup
patch that drops the capabilities flag handling.

Regards,
Jonas

>  };
>  
>  static const struct rkvdec_variant rk3328_rkvdec_variant = {
>  	.num_regs = 109,
> +	.coded_fmts = rkvdec_coded_fmts,
> +	.num_coded_fmts = ARRAY_SIZE(rkvdec_coded_fmts),
>  	.capabilities = RKVDEC_CAPABILITY_HEVC |
>  			RKVDEC_CAPABILITY_H264 |
>  			RKVDEC_CAPABILITY_VP9,
> @@ -1255,6 +1262,8 @@ static const struct rkvdec_variant rk3328_rkvdec_variant = {
>  
>  static const struct rkvdec_variant rk3399_rkvdec_variant = {
>  	.num_regs = 78,
> +	.coded_fmts = rkvdec_coded_fmts,
> +	.num_coded_fmts = ARRAY_SIZE(rkvdec_coded_fmts),
>  	.capabilities = RKVDEC_CAPABILITY_HEVC |
>  			RKVDEC_CAPABILITY_H264 |
>  			RKVDEC_CAPABILITY_VP9,
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> index f35f6e80ea2e..aac6cba4c623 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> @@ -71,6 +71,8 @@ vb2_to_rkvdec_decoded_buf(struct vb2_buffer *buf)
>  
>  struct rkvdec_variant {
>  	unsigned int num_regs;
> +	const struct rkvdec_coded_fmt_desc *coded_fmts;
> +	size_t num_coded_fmts;
>  	unsigned int capabilities;
>  	unsigned int quirks;
>  };



From jonas at kwiboo.se  Wed Dec 17 15:56:32 2025
From: jonas at kwiboo.se (Jonas Karlman)
Date: Thu, 18 Dec 2025 00:56:32 +0100
Subject: [PATCH v6 14/17] media: rkvdec: Add H264 support for the VDPU381
 variant
In-Reply-To: <20251217174059.1341784-15-detlev.casanova@collabora.com>
References: <20251217174059.1341784-1-detlev.casanova@collabora.com>
 <20251217174059.1341784-15-detlev.casanova@collabora.com>
Message-ID: <0b08a231-5560-471e-8d8d-0431f3ada0ac@kwiboo.se>

Hi Detlev,

On 12/17/2025 6:40 PM, Detlev Casanova wrote:
> This decoder variant is found in Rockchip RK3588 SoC family.
> 
> Like for rkvdec on rk3399, it supports the NV12, NV15, NV16 and NV20
> output formats and level up to 5.1.
> 
> The maximum width and height have been significantly increased
> supporting up to 65520 pixels for both.
> 
> Also make sure to only expose the first core and ignore the other
> until mutli-core is supported.
> 
> Fluster score for JVT-AVC_V1 is 129/135.
> 
> Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
> ---
>  .../media/platform/rockchip/rkvdec/Makefile   |   1 +
>  .../rockchip/rkvdec/rkvdec-h264-common.h      |   2 +
>  .../rockchip/rkvdec/rkvdec-vdpu381-h264.c     | 469 ++++++++++++++++++
>  .../rockchip/rkvdec/rkvdec-vdpu381-regs.h     | 424 ++++++++++++++++
>  .../media/platform/rockchip/rkvdec/rkvdec.c   |  84 ++++
>  .../media/platform/rockchip/rkvdec/rkvdec.h   |   8 +
>  6 files changed, 988 insertions(+)
>  create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c
>  create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h
> 

[snip]

> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> index f7353d0acdab..1ddae1b23434 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> @@ -29,6 +29,7 @@
>  
>  #include "rkvdec.h"
>  #include "rkvdec-regs.h"
> +#include "rkvdec-vdpu381-regs.h"
>  #include "rkvdec-rcb.h"
>  
>  static bool rkvdec_image_fmt_match(enum rkvdec_image_fmt fmt1,
> @@ -90,6 +91,9 @@ static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx,
>  {
>  	v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat,
>  			    pix_mp->width, pix_mp->height);
> +
> +	ctx->colmv_offset = pix_mp->plane_fmt[0].sizeimage;
> +
>  	pix_mp->plane_fmt[0].sizeimage += 128 *
>  		DIV_ROUND_UP(pix_mp->width, 16) *
>  		DIV_ROUND_UP(pix_mp->height, 16);
> @@ -367,6 +371,26 @@ static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = {
>  	}
>  };
>  
> +static const struct rkvdec_coded_fmt_desc vdpu381_coded_fmts[] = {
> +	{
> +		.fourcc = V4L2_PIX_FMT_H264_SLICE,
> +		.frmsize = {
> +			.min_width = 64,
> +			.max_width =  65520,
> +			.step_width = 64,
> +			.min_height = 64,
> +			.max_height =  65520,
> +			.step_height = 16,
> +		},
> +		.ctrls = &rkvdec_h264_ctrls,
> +		.ops = &rkvdec_vdpu381_h264_fmt_ops,
> +		.num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts),
> +		.decoded_fmts = rkvdec_h264_decoded_fmts,
> +		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
> +		.capability = RKVDEC_CAPABILITY_H264,
> +	},
> +};
> +
>  static bool rkvdec_is_capable(struct rkvdec_ctx *ctx, unsigned int capability)
>  {
>  	return (ctx->dev->variant->capabilities & capability) == capability;
> @@ -1241,6 +1265,35 @@ static irqreturn_t rk3399_irq_handler(struct rkvdec_ctx *ctx)
>  	return IRQ_HANDLED;
>  }
>  
> +static irqreturn_t vdpu381_irq_handler(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	enum vb2_buffer_state state;
> +	bool need_reset = 0;
> +	u32 status;
> +
> +	status = readl(rkvdec->regs + VDPU381_REG_STA_INT);
> +	writel(0, rkvdec->regs + VDPU381_REG_STA_INT);
> +
> +	if (status & VDPU381_STA_INT_DEC_RDY_STA) {
> +		state = VB2_BUF_STATE_DONE;
> +	} else {
> +		state = VB2_BUF_STATE_ERROR;
> +		if (status & (VDPU381_STA_INT_SOFTRESET_RDY |
> +			      VDPU381_STA_INT_TIMEOUT |
> +			      VDPU381_STA_INT_ERROR))
> +			rkvdec_iommu_restore(rkvdec);
> +	}
> +
> +	if (need_reset)
> +		rkvdec_iommu_restore(rkvdec);
> +
> +	if (cancel_delayed_work(&rkvdec->watchdog_work))
> +		rkvdec_job_finish(ctx, state);
> +
> +	return IRQ_HANDLED;
> +}
> +
>  static irqreturn_t rkvdec_irq_handler(int irq, void *priv)
>  {
>  	struct rkvdec_dev *rkvdec = priv;
> @@ -1308,6 +1361,19 @@ static int rkvdec_disable_multicore(struct rkvdec_dev *rkvdec)
>  	return 0;
>  }
>  
> +static const struct rcb_size_info vdpu381_rcb_sizes[] = {
> +	{6,	PIC_WIDTH},	// intrar
> +	{1,	PIC_WIDTH},	// transdr (Is actually 0.4*pic_width)
> +	{1,	PIC_HEIGHT},	// transdc (Is actually 0.1*pic_height)
> +	{3,	PIC_WIDTH},	// streamdr
> +	{6,	PIC_WIDTH},	// interr
> +	{3,	PIC_HEIGHT},	// interc
> +	{22,	PIC_WIDTH},	// dblkr
> +	{6,	PIC_WIDTH},	// saor
> +	{11,	PIC_WIDTH},	// fbcr
> +	{67,	PIC_HEIGHT},	// filtc col
> +};

This feel a little bit out of place, should it be moved just above
vdpu381_variant_ops and after rk3399_rkvdec_variant ?

> +
>  static const struct rkvdec_variant_ops rk3399_variant_ops = {
>  	.irq_handler = rk3399_irq_handler,
>  };
> @@ -1341,6 +1407,19 @@ static const struct rkvdec_variant rk3399_rkvdec_variant = {
>  			RKVDEC_CAPABILITY_VP9,
>  };
>  
> +static const struct rkvdec_variant_ops vdpu381_variant_ops = {
> +	.irq_handler = vdpu381_irq_handler,
> +};
> +
> +static const struct rkvdec_variant rk3588_vdpu381_variant = {

Are we expecting other soc use vdpu381 ? Or are there some reason why
some of the structs are just named vdpu381 and this one both rk3588 and
vdpu381 ?

Regards,
Jonas

> +	.coded_fmts = vdpu381_coded_fmts,
> +	.num_coded_fmts = ARRAY_SIZE(vdpu381_coded_fmts),
> +	.rcb_sizes = vdpu381_rcb_sizes,
> +	.num_rcb_sizes = ARRAY_SIZE(vdpu381_rcb_sizes),
> +	.ops = &vdpu381_variant_ops,
> +	.capabilities = RKVDEC_CAPABILITY_H264,
> +};
> +
>  static const struct of_device_id of_rkvdec_match[] = {
>  	{
>  		.compatible = "rockchip,rk3288-vdec",
> @@ -1354,6 +1433,10 @@ static const struct of_device_id of_rkvdec_match[] = {
>  		.compatible = "rockchip,rk3399-vdec",
>  		.data = &rk3399_rkvdec_variant,
>  	},
> +	{
> +		.compatible = "rockchip,rk3588-vdec",
> +		.data = &rk3588_vdpu381_variant,
> +	},
>  	{ /* sentinel */ }
>  };
>  MODULE_DEVICE_TABLE(of, of_rkvdec_match);
> @@ -1387,6 +1470,7 @@ static int rkvdec_probe(struct platform_device *pdev)
>  		return ret;
>  
>  	rkvdec->num_clocks = ret;
> +	rkvdec->axi_clk = devm_clk_get(&pdev->dev, "axi");
>  
>  	rkvdec->regs = devm_platform_ioremap_resource(pdev, 0);
>  	if (IS_ERR(rkvdec->regs))
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> index 75a9ba988794..1ad9a4fc31db 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> @@ -29,6 +29,10 @@
>  
>  #define RKVDEC_QUIRK_DISABLE_QOS	BIT(0)
>  
> +#define RKVDEC_1080P_PIXELS		(1920 * 1088)
> +#define RKVDEC_4K_PIXELS		(4096 * 2304)
> +#define RKVDEC_8K_PIXELS		(7680 * 4320)
> +
>  struct rkvdec_ctx;
>  struct rkvdec_rcb_config;
>  
> @@ -132,6 +136,7 @@ struct rkvdec_dev {
>  	struct device *dev;
>  	struct clk_bulk_data *clocks;
>  	unsigned int num_clocks;
> +	struct clk *axi_clk;
>  	void __iomem *regs;
>  	struct mutex vdev_lock; /* serializes ioctls */
>  	struct delayed_work watchdog_work;
> @@ -150,6 +155,7 @@ struct rkvdec_ctx {
>  	struct rkvdec_dev *dev;
>  	enum rkvdec_image_fmt image_fmt;
>  	struct rkvdec_rcb_config *rcb_config;
> +	u32 colmv_offset;
>  	void *priv;
>  };
>  
> @@ -180,4 +186,6 @@ extern const struct rkvdec_coded_fmt_ops rkvdec_h264_fmt_ops;
>  extern const struct rkvdec_coded_fmt_ops rkvdec_hevc_fmt_ops;
>  extern const struct rkvdec_coded_fmt_ops rkvdec_vp9_fmt_ops;
>  
> +extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_h264_fmt_ops;
> +
>  #endif /* RKVDEC_H_ */



From jonas at kwiboo.se  Wed Dec 17 16:18:07 2025
From: jonas at kwiboo.se (Jonas Karlman)
Date: Thu, 18 Dec 2025 01:18:07 +0100
Subject: [PATCH v6 15/17] media: rkvdec: Add H264 support for the VDPU383
 variant
In-Reply-To: <20251217174059.1341784-16-detlev.casanova@collabora.com>
References: <20251217174059.1341784-1-detlev.casanova@collabora.com>
 <20251217174059.1341784-16-detlev.casanova@collabora.com>
Message-ID: <3b8cce03-5f70-4462-89fe-4a54dd7f5bca@kwiboo.se>

Hi Detlev,

On 12/17/2025 6:40 PM, Detlev Casanova wrote:
> This variant is used on the RK3576 SoC.
> 
> The moving vectors size requirements are slightly different so support
> for a colmv_size function per variant is added.
> 
> Also, the link registers are used to start the decoder and read IRQ status.
> Per variant support for named register sections is added.
> 
> The fluster score is 128/135 for JVT-AVC_V1, with MPS_MW_A failing in
> addition to the usual ones.
> The other test suites are not supported yet.
> 
> Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
> ---
>  .../media/platform/rockchip/rkvdec/Makefile   |   1 +
>  .../rockchip/rkvdec/rkvdec-vdpu383-h264.c     | 582 ++++++++++++++++++
>  .../rockchip/rkvdec/rkvdec-vdpu383-regs.h     | 281 +++++++++
>  .../media/platform/rockchip/rkvdec/rkvdec.c   | 118 +++-
>  .../media/platform/rockchip/rkvdec/rkvdec.h   |   8 +
>  5 files changed, 984 insertions(+), 6 deletions(-)
>  create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c
>  create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-regs.h
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
> index 7bfd95151e40..a58d4aede2fe 100644
> --- a/drivers/media/platform/rockchip/rkvdec/Makefile
> +++ b/drivers/media/platform/rockchip/rkvdec/Makefile
> @@ -9,4 +9,5 @@ rockchip-vdec-y += \
>  		   rkvdec-hevc-common.o \
>  		   rkvdec-rcb.o \
>  		   rkvdec-vdpu381-h264.o \
> +		   rkvdec-vdpu383-h264.o \
>  		   rkvdec-vp9.o
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c
> new file mode 100644
> index 000000000000..d8419085bdd8
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c

[snip]

> +static int rkvdec_h264_start(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	struct rkvdec_h264_priv_tbl *priv_tbl;
> +	struct rkvdec_h264_ctx *h264_ctx;
> +	struct v4l2_ctrl *ctrl;
> +	int ret;
> +
> +	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> +			      V4L2_CID_STATELESS_H264_SPS);
> +	if (!ctrl)
> +		return -EINVAL;
> +
> +	ret = rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps);
> +	if (ret)
> +		return ret;

I recall some older mail thread that we should not have to validate sps
in start ops. It is validated in try_ctrl and is expected to always be
in a valid state.

This can most likely be dropped, it was removed from the HEVC start ops.

> +
> +	h264_ctx = kzalloc(sizeof(*h264_ctx), GFP_KERNEL);
> +	if (!h264_ctx)
> +		return -ENOMEM;
> +
> +	priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl),
> +				      &h264_ctx->priv_tbl.dma, GFP_KERNEL);
> +	if (!priv_tbl) {
> +		ret = -ENOMEM;
> +		goto err_free_ctx;
> +	}
> +
> +	h264_ctx->priv_tbl.size = sizeof(*priv_tbl);
> +	h264_ctx->priv_tbl.cpu = priv_tbl;
> +	memcpy(priv_tbl->cabac_table, rkvdec_h264_cabac_table,
> +	       sizeof(rkvdec_h264_cabac_table));
> +
> +	ctx->priv = h264_ctx;
> +
> +	return 0;
> +
> +err_free_ctx:
> +	kfree(h264_ctx);
> +	return ret;
> +}
> +
> +static void rkvdec_h264_stop(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +
> +	dma_free_coherent(rkvdec->dev, h264_ctx->priv_tbl.size,
> +			  h264_ctx->priv_tbl.cpu, h264_ctx->priv_tbl.dma);
> +	kfree(h264_ctx);
> +}
> +
> +static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
> +{
> +	struct v4l2_h264_reflist_builder reflist_builder;
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
> +	struct rkvdec_h264_run run;
> +	struct rkvdec_h264_priv_tbl *tbl = h264_ctx->priv_tbl.cpu;
> +	u32 watchdog_time;
> +	u64 timeout_threshold;
> +	unsigned long axi_rate;
> +
> +	rkvdec_h264_run_preamble(ctx, &run);
> +
> +	/* Build the P/B{0,1} ref lists. */
> +	v4l2_h264_init_reflist_builder(&reflist_builder, run.decode_params,
> +				       run.sps, run.decode_params->dpb);
> +	v4l2_h264_build_p_ref_list(&reflist_builder, h264_ctx->reflists.p);
> +	v4l2_h264_build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0,
> +				    h264_ctx->reflists.b1);
> +
> +	assemble_hw_scaling_list(&run, &tbl->scaling_list);
> +	assemble_hw_pps(ctx, &run);
> +	lookup_ref_buf_idx(ctx, &run);
> +	assemble_hw_rps(&reflist_builder, &run, &h264_ctx->reflists, &tbl->rps);
> +
> +	config_registers(ctx, &run);
> +
> +	rkvdec_run_postamble(ctx, &run.base);
> +
> +	/* Set watchdog at 2 times the hardware timeout threshold */
> +	timeout_threshold = h264_ctx->regs.common.reg013_core_timeout_threshold;
> +	axi_rate = clk_get_rate(rkvdec->axi_clk);
> +
> +	if (axi_rate)
> +		watchdog_time = 2 * (1000 * timeout_threshold) / axi_rate;
> +	else
> +		watchdog_time = 2000;
> +	schedule_delayed_work(&rkvdec->watchdog_work,
> +			      msecs_to_jiffies(watchdog_time));
> +
> +	/* Start decoding! */
> +	writel(timeout_threshold, rkvdec->link + VDPU383_LINK_TIMEOUT_THRESHOLD);
> +	writel(0, rkvdec->link + VDPU383_LINK_IP_ENABLE);
> +	writel(VDPU383_DEC_E_BIT, rkvdec->link + VDPU383_LINK_DEC_ENABLE);
> +
> +	return 0;
> +}
> +
> +static int rkvdec_h264_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
> +{
> +	if (ctrl->id == V4L2_CID_STATELESS_H264_SPS)
> +		return rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps);
> +
> +	return 0;
> +}
> +
> +const struct rkvdec_coded_fmt_ops rkvdec_vdpu383_h264_fmt_ops = {
> +	.adjust_fmt = rkvdec_h264_adjust_fmt,
> +	.get_image_fmt = rkvdec_h264_get_image_fmt,
> +	.start = rkvdec_h264_start,
> +	.stop = rkvdec_h264_stop,
> +	.run = rkvdec_h264_run,
> +	.try_ctrl = rkvdec_h264_try_ctrl,
> +};

[snip]

> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> index 1ddae1b23434..ceb56516bd90 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> @@ -9,6 +9,7 @@
>   * Copyright (C) 2011 Samsung Electronics Co., Ltd.
>   */
>  
> +#include <linux/hw_bitfield.h>
>  #include <linux/clk.h>
>  #include <linux/genalloc.h>
>  #include <linux/interrupt.h>
> @@ -30,6 +31,7 @@
>  #include "rkvdec.h"
>  #include "rkvdec-regs.h"
>  #include "rkvdec-vdpu381-regs.h"
> +#include "rkvdec-vdpu383-regs.h"
>  #include "rkvdec-rcb.h"
>  
>  static bool rkvdec_image_fmt_match(enum rkvdec_image_fmt fmt1,
> @@ -86,17 +88,27 @@ static bool rkvdec_is_valid_fmt(struct rkvdec_ctx *ctx, u32 fourcc,
>  	return false;
>  }
>  
> +static u32 rkvdec_colmv_size(u16 width, u16 height)
> +{
> +	return 128 * DIV_ROUND_UP(width, 16) * DIV_ROUND_UP(height, 16);
> +}
> +
> +static u32 vdpu383_colmv_size(u16 width, u16 height)
> +{
> +	return ALIGN(width, 64) * ALIGN(height, 16);
> +}
> +
>  static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx,
>  				       struct v4l2_pix_format_mplane *pix_mp)
>  {
> +	const struct rkvdec_variant *variant = ctx->dev->variant;
> +
>  	v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat,
>  			    pix_mp->width, pix_mp->height);
>  
>  	ctx->colmv_offset = pix_mp->plane_fmt[0].sizeimage;
>  
> -	pix_mp->plane_fmt[0].sizeimage += 128 *
> -		DIV_ROUND_UP(pix_mp->width, 16) *
> -		DIV_ROUND_UP(pix_mp->height, 16);
> +	pix_mp->plane_fmt[0].sizeimage += variant->ops->colmv_size(pix_mp->width, pix_mp->height);

nit: The rest of this function use line breake to keep line lengt below
or around 80 chars, this long line feel out of place.

Maybe:

	pix_mp->plane_fmt[0].sizeimage +=
		variant->ops->colmv_size(pix_mp->width, pix_mp->height);

>  }
>  
>  static void rkvdec_reset_fmt(struct rkvdec_ctx *ctx, struct v4l2_format *f,
> @@ -391,6 +403,26 @@ static const struct rkvdec_coded_fmt_desc vdpu381_coded_fmts[] = {
>  	},
>  };
>  
> +static const struct rkvdec_coded_fmt_desc vdpu383_coded_fmts[] = {
> +	{
> +		.fourcc = V4L2_PIX_FMT_H264_SLICE,
> +		.frmsize = {
> +			.min_width = 64,
> +			.max_width =  65520,
> +			.step_width = 64,
> +			.min_height = 64,
> +			.max_height =  65520,
> +			.step_height = 16,
> +		},
> +		.ctrls = &rkvdec_h264_ctrls,
> +		.ops = &rkvdec_vdpu383_h264_fmt_ops,
> +		.num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts),
> +		.decoded_fmts = rkvdec_h264_decoded_fmts,
> +		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
> +		.capability = RKVDEC_CAPABILITY_H264,
> +	},
> +};
> +
>  static bool rkvdec_is_capable(struct rkvdec_ctx *ctx, unsigned int capability)
>  {
>  	return (ctx->dev->variant->capabilities & capability) == capability;
> @@ -1294,6 +1326,35 @@ static irqreturn_t vdpu381_irq_handler(struct rkvdec_ctx *ctx)
>  	return IRQ_HANDLED;
>  }
>  
> +static irqreturn_t vdpu383_irq_handler(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	enum vb2_buffer_state state;
> +	bool need_reset = 0;
> +	u32 status;
> +
> +	status = readl(rkvdec->link + VDPU383_LINK_STA_INT);
> +	writel(FIELD_PREP_WM16(VDPU383_STA_INT_ALL, 0), rkvdec->link + VDPU383_LINK_STA_INT);
> +	/* On vdpu383, the interrupts must be disabled */
> +	writel(FIELD_PREP_WM16(VDPU383_INT_EN_IRQ | VDPU383_INT_EN_LINE_IRQ, 0),
> +	       rkvdec->link + VDPU383_LINK_INT_EN);
> +
> +	if (status & VDPU383_STA_INT_DEC_RDY_STA) {
> +		state = VB2_BUF_STATE_DONE;
> +	} else {
> +		state = VB2_BUF_STATE_ERROR;
> +		rkvdec_iommu_restore(rkvdec);
> +	}
> +
> +	if (need_reset)
> +		rkvdec_iommu_restore(rkvdec);
> +
> +	if (cancel_delayed_work(&rkvdec->watchdog_work))
> +		rkvdec_job_finish(ctx, state);
> +
> +	return IRQ_HANDLED;
> +}
> +
>  static irqreturn_t rkvdec_irq_handler(int irq, void *priv)
>  {
>  	struct rkvdec_dev *rkvdec = priv;
> @@ -1374,8 +1435,22 @@ static const struct rcb_size_info vdpu381_rcb_sizes[] = {
>  	{67,	PIC_HEIGHT},	// filtc col
>  };
>  
> +static const struct rcb_size_info vdpu383_rcb_sizes[] = {
> +	{6,	PIC_WIDTH},	// streamd
> +	{6,	PIC_WIDTH},	// streamd_tile
> +	{12,	PIC_WIDTH},	// inter
> +	{12,	PIC_WIDTH},	// inter_tile
> +	{16,	PIC_WIDTH},	// intra
> +	{10,	PIC_WIDTH},	// intra_tile
> +	{120,	PIC_WIDTH},	// filterd
> +	{120,	PIC_WIDTH},	// filterd_protect
> +	{120,	PIC_WIDTH},	// filterd_tile_row
> +	{180,	PIC_HEIGHT},	// filterd_tile_col
> +};
> +
>  static const struct rkvdec_variant_ops rk3399_variant_ops = {
>  	.irq_handler = rk3399_irq_handler,
> +	.colmv_size = rkvdec_colmv_size,
>  };
>  
>  static const struct rkvdec_variant rk3288_rkvdec_variant = {
> @@ -1409,6 +1484,7 @@ static const struct rkvdec_variant rk3399_rkvdec_variant = {
>  
>  static const struct rkvdec_variant_ops vdpu381_variant_ops = {
>  	.irq_handler = vdpu381_irq_handler,
> +	.colmv_size = rkvdec_colmv_size,
>  };
>  
>  static const struct rkvdec_variant rk3588_vdpu381_variant = {
> @@ -1417,6 +1493,22 @@ static const struct rkvdec_variant rk3588_vdpu381_variant = {
>  	.rcb_sizes = vdpu381_rcb_sizes,
>  	.num_rcb_sizes = ARRAY_SIZE(vdpu381_rcb_sizes),
>  	.ops = &vdpu381_variant_ops,
> +	.named_regs = true,

Why is this added here in this patch ? Should probably be added in prior
patch with the lookup for link regs added in this patch ?

> +	.capabilities = RKVDEC_CAPABILITY_H264,
> +};
> +
> +static const struct rkvdec_variant_ops vdpu383_variant_ops = {
> +	.irq_handler = vdpu383_irq_handler,
> +	.colmv_size = vdpu383_colmv_size,
> +};
> +
> +static const struct rkvdec_variant rk3576_vdpu383_variant = {
> +	.coded_fmts = vdpu383_coded_fmts,
> +	.num_coded_fmts = ARRAY_SIZE(vdpu383_coded_fmts),
> +	.rcb_sizes = vdpu383_rcb_sizes,
> +	.num_rcb_sizes = ARRAY_SIZE(vdpu383_rcb_sizes),
> +	.ops = &vdpu383_variant_ops,
> +	.named_regs = true,
>  	.capabilities = RKVDEC_CAPABILITY_H264,
>  };
>  
> @@ -1437,6 +1529,10 @@ static const struct of_device_id of_rkvdec_match[] = {
>  		.compatible = "rockchip,rk3588-vdec",
>  		.data = &rk3588_vdpu381_variant,
>  	},
> +	{
> +		.compatible = "rockchip,rk3576-vdec",
> +		.data = &rk3576_vdpu383_variant,
> +	},
>  	{ /* sentinel */ }
>  };
>  MODULE_DEVICE_TABLE(of, of_rkvdec_match);
> @@ -1472,9 +1568,19 @@ static int rkvdec_probe(struct platform_device *pdev)
>  	rkvdec->num_clocks = ret;
>  	rkvdec->axi_clk = devm_clk_get(&pdev->dev, "axi");
>  
> -	rkvdec->regs = devm_platform_ioremap_resource(pdev, 0);
> -	if (IS_ERR(rkvdec->regs))
> -		return PTR_ERR(rkvdec->regs);
> +	if (rkvdec->variant->named_regs) {
> +		rkvdec->regs = devm_platform_ioremap_resource_byname(pdev, "function");
> +		if (IS_ERR(rkvdec->regs))
> +			return PTR_ERR(rkvdec->regs);
> +
> +		rkvdec->link = devm_platform_ioremap_resource_byname(pdev, "link");
> +		if (IS_ERR(rkvdec->link))
> +			return PTR_ERR(rkvdec->link);
> +	} else {
> +		rkvdec->regs = devm_platform_ioremap_resource(pdev, 0);
> +		if (IS_ERR(rkvdec->regs))
> +			return PTR_ERR(rkvdec->regs);
> +	}
>  
>  	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
>  	if (ret) {
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> index 1ad9a4fc31db..2f924c924828 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> @@ -77,6 +77,7 @@ vb2_to_rkvdec_decoded_buf(struct vb2_buffer *buf)
>  
>  struct rkvdec_variant_ops {
>  	irqreturn_t (*irq_handler)(struct rkvdec_ctx *ctx);
> +	u32 (*colmv_size)(u16 width, u16 height);
>  };
>  
>  struct rkvdec_variant {
> @@ -86,6 +87,7 @@ struct rkvdec_variant {
>  	const struct rcb_size_info *rcb_sizes;
>  	size_t num_rcb_sizes;
>  	const struct rkvdec_variant_ops *ops;
> +	bool named_regs;

nit: Maybe use_named_regs or similar ?

Maybe this should be inverted as I suspect all new variants are expected
to use named regs ?

>  	unsigned int capabilities;
>  	unsigned int quirks;
>  };
> @@ -138,6 +140,7 @@ struct rkvdec_dev {
>  	unsigned int num_clocks;
>  	struct clk *axi_clk;
>  	void __iomem *regs;
> +	void __iomem *link;
>  	struct mutex vdev_lock; /* serializes ioctls */
>  	struct delayed_work watchdog_work;
>  	struct gen_pool *sram_pool;
> @@ -182,10 +185,15 @@ void rkvdec_memcpy_toio(void __iomem *dst, void *src, size_t len);
>  
>  void rkvdec_quirks_disable_qos(struct rkvdec_ctx *ctx);
>  
> +/* RKVDEC ops */
>  extern const struct rkvdec_coded_fmt_ops rkvdec_h264_fmt_ops;
>  extern const struct rkvdec_coded_fmt_ops rkvdec_hevc_fmt_ops;
>  extern const struct rkvdec_coded_fmt_ops rkvdec_vp9_fmt_ops;
>  
> +/* VDPU381 ops */

nit: This comment and the one above should be added in prior patch.

Regards,
Jonas

>  extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_h264_fmt_ops;
>  
> +/* VDPU383 ops */
> +extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu383_h264_fmt_ops;
> +
>  #endif /* RKVDEC_H_ */



From jonas at kwiboo.se  Wed Dec 17 16:47:05 2025
From: jonas at kwiboo.se (Jonas Karlman)
Date: Thu, 18 Dec 2025 01:47:05 +0100
Subject: [PATCH v6 16/17] media: rkvdec: Add HEVC support for the VDPU381
 variant
In-Reply-To: <20251217174059.1341784-17-detlev.casanova@collabora.com>
References: <20251217174059.1341784-1-detlev.casanova@collabora.com>
 <20251217174059.1341784-17-detlev.casanova@collabora.com>
Message-ID: <6e0ad3a4-068b-4ab7-8e12-eb51c62eb73c@kwiboo.se>

Hi Detlev,

On 12/17/2025 6:40 PM, Detlev Casanova wrote:
> The VDPU381 supports HEVC decoding up to 7680x4320 at 30fps.
> It could double that when using both decoder cores.
> 
> It support YUV420 (8 and 10 bits) as well as AFBC (not implemented
> here)
> 
> The fluster score is 146/147 for JCT-VC-HEVC_V1, tested on ROCK 5B.
> None of the other test suites works.
> 
> Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
> Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
> ---
>  .../media/platform/rockchip/rkvdec/Kconfig    |   1 +
>  .../media/platform/rockchip/rkvdec/Makefile   |   1 +
>  .../rockchip/rkvdec/rkvdec-hevc-common.c      | 349 +++++++++-
>  .../rockchip/rkvdec/rkvdec-hevc-common.h      |  73 +-
>  .../rockchip/rkvdec/rkvdec-vdpu381-hevc.c     | 642 ++++++++++++++++++
>  .../media/platform/rockchip/rkvdec/rkvdec.c   |  86 ++-
>  .../media/platform/rockchip/rkvdec/rkvdec.h   |   3 +
>  7 files changed, 1140 insertions(+), 15 deletions(-)
>  create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/Kconfig b/drivers/media/platform/rockchip/rkvdec/Kconfig
> index 5f3bdd848a2c..3303b0ce3280 100644
> --- a/drivers/media/platform/rockchip/rkvdec/Kconfig
> +++ b/drivers/media/platform/rockchip/rkvdec/Kconfig
> @@ -8,6 +8,7 @@ config VIDEO_ROCKCHIP_VDEC
>  	select VIDEOBUF2_VMALLOC
>  	select V4L2_MEM2MEM_DEV
>  	select V4L2_H264
> +	select V4L2_HEVC

Should this be a separate fix or is this something needed after this
patch ?

>  	select V4L2_VP9
>  	help
>  	  Support for the Rockchip Video Decoder IP present on Rockchip SoCs,
> diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
> index a58d4aede2fe..e30fdd7d51c3 100644
> --- a/drivers/media/platform/rockchip/rkvdec/Makefile
> +++ b/drivers/media/platform/rockchip/rkvdec/Makefile
> @@ -9,5 +9,6 @@ rockchip-vdec-y += \
>  		   rkvdec-hevc-common.o \
>  		   rkvdec-rcb.o \
>  		   rkvdec-vdpu381-h264.o \
> +		   rkvdec-vdpu381-hevc.o \
>  		   rkvdec-vdpu383-h264.o \
>  		   rkvdec-vp9.o
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
> index 23547e2e6e1d..4096b9e1aa65 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
> @@ -21,6 +21,127 @@
>  #include "rkvdec.h"
>  #include "rkvdec-hevc-common.h"
>  
> +#define RKVDEC_HEVC_MAX_DEPTH_IN_BYTES		2
> +
> +/* Store the Short term ref pic set calculated values */
> +struct calculated_rps_st_set {
> +	u8 num_delta_pocs;
> +	u8 num_negative_pics;
> +	u8 num_positive_pics;
> +	u8 used_by_curr_pic_s0[16];
> +	u8 used_by_curr_pic_s1[16];
> +	s32 delta_poc_s0[16];
> +	s32 delta_poc_s1[16];
> +};
> +
> +void compute_tiles_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size,
> +			   u16 width, u16 height, s32 pic_in_cts_width,
> +			   s32 pic_in_cts_height, u16 *column_width, u16 *row_height)
> +{
> +	const struct v4l2_ctrl_hevc_pps *pps = run->pps;
> +	int i;
> +
> +	for (i = 0; i < pps->num_tile_columns_minus1 + 1; i++)
> +		column_width[i] = ((i + 1) * pic_in_cts_width) /
> +				  (pps->num_tile_columns_minus1 + 1) -
> +				  (i * pic_in_cts_width) /
> +				  (pps->num_tile_columns_minus1 + 1);
> +
> +	for (i = 0; i < pps->num_tile_rows_minus1 + 1; i++)
> +		row_height[i] = ((i + 1) * pic_in_cts_height) /
> +				(pps->num_tile_rows_minus1 + 1) -
> +				(i * pic_in_cts_height) /
> +				(pps->num_tile_rows_minus1 + 1);
> +}
> +
> +void compute_tiles_non_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size,
> +			       u16 width, u16 height, s32 pic_in_cts_width,
> +			       s32 pic_in_cts_height, u16 *column_width, u16 *row_height)
> +{
> +	const struct v4l2_ctrl_hevc_pps *pps = run->pps;
> +	s32 sum = 0;
> +	int i;
> +
> +	for (i = 0; i < pps->num_tile_columns_minus1; i++) {
> +		column_width[i] = pps->column_width_minus1[i] + 1;
> +		sum += column_width[i];
> +	}
> +	column_width[i] = pic_in_cts_width - sum;
> +
> +	sum = 0;
> +	for (i = 0; i < pps->num_tile_rows_minus1; i++) {
> +		row_height[i] = pps->row_height_minus1[i] + 1;
> +		sum += row_height[i];
> +	}
> +	row_height[i] = pic_in_cts_height - sum;
> +}

Would probably be good if the existing rkvdec hevc also is changed to
used these two tiles helpers.

> +
> +static void set_ref_poc(struct rkvdec_rps_short_term_ref_set *set, int poc, int value, int flag)
> +{
> +	switch (poc) {
> +	case 0:
> +		set->delta_poc0 = value;
> +		set->used_flag0 = flag;
> +		break;
> +	case 1:
> +		set->delta_poc1 = value;
> +		set->used_flag1 = flag;
> +		break;
> +	case 2:
> +		set->delta_poc2 = value;
> +		set->used_flag2 = flag;
> +		break;
> +	case 3:
> +		set->delta_poc3 = value;
> +		set->used_flag3 = flag;
> +		break;
> +	case 4:
> +		set->delta_poc4 = value;
> +		set->used_flag4 = flag;
> +		break;
> +	case 5:
> +		set->delta_poc5 = value;
> +		set->used_flag5 = flag;
> +		break;
> +	case 6:
> +		set->delta_poc6 = value;
> +		set->used_flag6 = flag;
> +		break;
> +	case 7:
> +		set->delta_poc7 = value;
> +		set->used_flag7 = flag;
> +		break;
> +	case 8:
> +		set->delta_poc8 = value;
> +		set->used_flag8 = flag;
> +		break;
> +	case 9:
> +		set->delta_poc9 = value;
> +		set->used_flag9 = flag;
> +		break;
> +	case 10:
> +		set->delta_poc10 = value;
> +		set->used_flag10 = flag;
> +		break;
> +	case 11:
> +		set->delta_poc11 = value;
> +		set->used_flag11 = flag;
> +		break;
> +	case 12:
> +		set->delta_poc12 = value;
> +		set->used_flag12 = flag;
> +		break;
> +	case 13:
> +		set->delta_poc13 = value;
> +		set->used_flag13 = flag;
> +		break;
> +	case 14:
> +		set->delta_poc14 = value;
> +		set->used_flag14 = flag;
> +		break;
> +	}
> +}
> +
>  /*
>   * Flip one or more matrices along their main diagonal and flatten them
>   * before writing it to the memory.
> @@ -105,7 +226,7 @@ static void translate_scaling_list(struct scaling_factor *output,
>  }
>  
>  void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
> -					  struct scaling_factor *scaling_factor,
> +					  struct scaling_factor *scaling_list,
>  					  struct v4l2_ctrl_hevc_scaling_matrix *cache)
>  {
>  	const struct v4l2_ctrl_hevc_scaling_matrix *scaling = run->scaling_matrix;
> @@ -114,15 +235,220 @@ void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
>  		    sizeof(struct v4l2_ctrl_hevc_scaling_matrix)))
>  		return;
>  
> -	translate_scaling_list(scaling_factor, scaling);
> +	translate_scaling_list(scaling_list, scaling);

nit: Any reason for this rename ? Maybe move code style cleanup to a
prerequisite patch ?

>  
>  	memcpy(cache, scaling,
>  	       sizeof(struct v4l2_ctrl_hevc_scaling_matrix));
>  }
>  
> -struct vb2_buffer *
> -get_ref_buf(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run,
> -	    unsigned int dpb_idx)

nit: It does not seem to be a change introduced here, please move code
style cleanup to a separate patch.

> +static void rkvdec_hevc_assemble_hw_lt_rps(struct rkvdec_hevc_run *run, struct rkvdec_rps *rps)
> +{
> +	const struct v4l2_ctrl_hevc_sps *sps = run->sps;
> +
> +	if (!run->ext_sps_lt_rps)
> +		return;
> +
> +	for (int i = 0; i < sps->num_long_term_ref_pics_sps; i++) {
> +		rps->refs[i].lt_ref_pic_poc_lsb =
> +			run->ext_sps_lt_rps[i].lt_ref_pic_poc_lsb_sps;
> +		rps->refs[i].used_by_curr_pic_lt_flag =
> +			!!(run->ext_sps_lt_rps[i].flags & V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_USED_LT);
> +	}
> +}
> +
> +static void rkvdec_hevc_assemble_hw_st_rps(struct rkvdec_hevc_run *run, struct rkvdec_rps *rps,
> +					   struct calculated_rps_st_set *calculated_rps_st_sets)
> +{
> +	const struct v4l2_ctrl_hevc_sps *sps = run->sps;
> +
> +	for (int i = 0; i < sps->num_short_term_ref_pic_sets; i++) {
> +		int poc = 0;
> +		int j = 0;
> +		const struct calculated_rps_st_set *set = &calculated_rps_st_sets[i];
> +
> +		rps->short_term_ref_sets[i].num_negative = set->num_negative_pics;
> +		rps->short_term_ref_sets[i].num_positive = set->num_positive_pics;
> +
> +		for (; j < set->num_negative_pics; j++) {
> +			set_ref_poc(&rps->short_term_ref_sets[i], j,
> +				    set->delta_poc_s0[j], set->used_by_curr_pic_s0[j]);
> +		}
> +		poc = j;
> +
> +		for (j = 0; j < set->num_positive_pics; j++) {
> +			set_ref_poc(&rps->short_term_ref_sets[i], poc + j,
> +				    set->delta_poc_s1[j], set->used_by_curr_pic_s1[j]);
> +		}
> +	}
> +}
> +
> +/*
> + * Compute the short term ref pic set parameters based on its reference short term ref pic
> + */
> +static void st_ref_pic_set_prediction(struct rkvdec_hevc_run *run, int idx,
> +				      struct calculated_rps_st_set *calculated_rps_st_sets)
> +{
> +	const struct v4l2_ctrl_hevc_ext_sps_st_rps *rps_data = &run->ext_sps_st_rps[idx];
> +	struct calculated_rps_st_set *st_rps = &calculated_rps_st_sets[idx];
> +	struct calculated_rps_st_set *ref_rps;
> +	u8 st_rps_idx = idx;
> +	u8 ref_rps_idx = 0;
> +	s16 delta_rps = 0;
> +	u8 use_delta_flag[16] = { 0 };
> +	u8 used_by_curr_pic_flag[16] = { 0 };
> +	int i, j;
> +	int dPoc;
> +
> +	ref_rps_idx = st_rps_idx - (rps_data->delta_idx_minus1 + 1); /* 7-59 */
> +	delta_rps = (1 - 2 * rps_data->delta_rps_sign) *
> +		   (rps_data->abs_delta_rps_minus1 + 1); /* 7-60 */
> +
> +	ref_rps = &calculated_rps_st_sets[ref_rps_idx];
> +
> +	for (j = 0; j <= ref_rps->num_delta_pocs; j++) {
> +		used_by_curr_pic_flag[j] = !!(rps_data->used_by_curr_pic & (1 << j));
> +		use_delta_flag[j] = !!(rps_data->use_delta_flag & (1 << j));
> +	}
> +
> +	/* 7-61: calculate num_negative_pics, delta_poc_s0 and used_by_curr_pic_s0 */
> +	i = 0;
> +	for (j = (ref_rps->num_positive_pics - 1); j >= 0; j--) {
> +		dPoc = ref_rps->delta_poc_s1[j] + delta_rps;
> +		if (dPoc < 0 && use_delta_flag[ref_rps->num_negative_pics + j]) {
> +			st_rps->delta_poc_s0[i] = dPoc;
> +			st_rps->used_by_curr_pic_s0[i++] =
> +				used_by_curr_pic_flag[ref_rps->num_negative_pics + j];
> +		}
> +	}
> +	if (delta_rps < 0 && use_delta_flag[ref_rps->num_delta_pocs]) {
> +		st_rps->delta_poc_s0[i] = delta_rps;
> +		st_rps->used_by_curr_pic_s0[i++] = used_by_curr_pic_flag[ref_rps->num_delta_pocs];
> +	}
> +	for (j = 0; j < ref_rps->num_negative_pics; j++) {
> +		dPoc = ref_rps->delta_poc_s0[j] + delta_rps;
> +		if (dPoc < 0 && use_delta_flag[j]) {
> +			st_rps->delta_poc_s0[i] = dPoc;
> +			st_rps->used_by_curr_pic_s0[i++] = used_by_curr_pic_flag[j];
> +		}
> +	}
> +	st_rps->num_negative_pics = i;
> +
> +	/* 7-62: calculate num_positive_pics, delta_poc_s1 and used_by_curr_pic_s1 */
> +	i = 0;
> +	for (j = (ref_rps->num_negative_pics - 1); j >= 0; j--) {
> +		dPoc = ref_rps->delta_poc_s0[j] + delta_rps;
> +		if (dPoc > 0 && use_delta_flag[j]) {
> +			st_rps->delta_poc_s1[i] = dPoc;
> +			st_rps->used_by_curr_pic_s1[i++] = used_by_curr_pic_flag[j];
> +		}
> +	}
> +	if (delta_rps > 0 && use_delta_flag[ref_rps->num_delta_pocs]) {
> +		st_rps->delta_poc_s1[i] = delta_rps;
> +		st_rps->used_by_curr_pic_s1[i++] = used_by_curr_pic_flag[ref_rps->num_delta_pocs];
> +	}
> +	for (j = 0; j < ref_rps->num_positive_pics; j++) {
> +		dPoc = ref_rps->delta_poc_s1[j] + delta_rps;
> +		if (dPoc > 0 && use_delta_flag[ref_rps->num_negative_pics + j]) {
> +			st_rps->delta_poc_s1[i] = dPoc;
> +			st_rps->used_by_curr_pic_s1[i++] =
> +				used_by_curr_pic_flag[ref_rps->num_negative_pics + j];
> +		}
> +	}
> +	st_rps->num_positive_pics = i;
> +
> +	st_rps->num_delta_pocs = st_rps->num_positive_pics + st_rps->num_negative_pics;
> +}
> +
> +/*
> + * Compute the short term ref pic set parameters based on the control's data.
> + */
> +static void st_ref_pic_set_calculate(struct rkvdec_hevc_run *run, int idx,
> +				     struct calculated_rps_st_set *calculated_rps_st_sets)
> +{
> +	const struct v4l2_ctrl_hevc_ext_sps_st_rps *rps_data = &run->ext_sps_st_rps[idx];
> +	struct calculated_rps_st_set *st_rps = &calculated_rps_st_sets[idx];
> +	int j, i = 0;
> +
> +	/* 7-63 */
> +	st_rps->num_negative_pics = rps_data->num_negative_pics;
> +	/* 7-64 */
> +	st_rps->num_positive_pics = rps_data->num_positive_pics;
> +
> +	for (i = 0; i < st_rps->num_negative_pics; i++) {
> +		/* 7-65 */
> +		st_rps->used_by_curr_pic_s0[i] = !!(rps_data->used_by_curr_pic & (1 << i));
> +
> +		if (i == 0) {
> +			/* 7-67 */
> +			st_rps->delta_poc_s0[i] = -(rps_data->delta_poc_s0_minus1[i] + 1);
> +		} else {
> +			/* 7-69 */
> +			st_rps->delta_poc_s0[i] =
> +				st_rps->delta_poc_s0[i - 1] -
> +				(rps_data->delta_poc_s0_minus1[i] + 1);
> +		}
> +	}
> +
> +	for (j = 0; j < st_rps->num_positive_pics; j++) {
> +		/* 7-66 */
> +		st_rps->used_by_curr_pic_s1[j] = !!(rps_data->used_by_curr_pic & (1 << (i + j)));
> +
> +		if (j == 0) {
> +			/* 7-68 */
> +			st_rps->delta_poc_s1[j] = rps_data->delta_poc_s1_minus1[j] + 1;
> +		} else {
> +			/* 7-70 */
> +			st_rps->delta_poc_s1[j] =
> +				st_rps->delta_poc_s1[j - 1] +
> +				(rps_data->delta_poc_s1_minus1[j] + 1);
> +		}
> +	}
> +
> +	/* 7-71 */
> +	st_rps->num_delta_pocs = st_rps->num_positive_pics + st_rps->num_negative_pics;
> +}
> +
> +static void rkvdec_hevc_prepare_hw_st_rps(struct rkvdec_hevc_run *run, struct rkvdec_rps *rps,
> +					  struct v4l2_ctrl_hevc_ext_sps_st_rps *cache)
> +{
> +	int idx;
> +
> +	if (!run->ext_sps_st_rps)
> +		return;
> +
> +	if (!memcmp(cache, run->ext_sps_st_rps, sizeof(struct v4l2_ctrl_hevc_ext_sps_st_rps)))
> +		return;
> +
> +	struct calculated_rps_st_set *calculated_rps_st_sets =
> +		kzalloc(sizeof(struct calculated_rps_st_set) *
> +			run->sps->num_short_term_ref_pic_sets, GFP_KERNEL);
> +
> +	for (idx = 0; idx < run->sps->num_short_term_ref_pic_sets; idx++) {
> +		const struct v4l2_ctrl_hevc_ext_sps_st_rps *rps_data = &run->ext_sps_st_rps[idx];
> +
> +		if (rps_data->flags & V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED)
> +			st_ref_pic_set_prediction(run, idx, calculated_rps_st_sets);
> +		else
> +			st_ref_pic_set_calculate(run, idx, calculated_rps_st_sets);
> +	}
> +
> +	rkvdec_hevc_assemble_hw_st_rps(run, rps, calculated_rps_st_sets);
> +
> +	kfree(calculated_rps_st_sets);
> +
> +	memcpy(cache, run->ext_sps_st_rps, sizeof(struct v4l2_ctrl_hevc_ext_sps_st_rps));
> +}
> +
> +void rkvdec_hevc_assemble_hw_rps(struct rkvdec_hevc_run *run, struct rkvdec_rps *rps,
> +				 struct v4l2_ctrl_hevc_ext_sps_st_rps *st_cache)
> +{
> +	rkvdec_hevc_prepare_hw_st_rps(run, rps, st_cache);
> +	rkvdec_hevc_assemble_hw_lt_rps(run, rps);
> +}
> +
> +struct vb2_buffer *get_ref_buf(struct rkvdec_ctx *ctx,
> +			       struct rkvdec_hevc_run *run,
> +			       unsigned int dpb_idx)

nit: Any reason why formating of this function declaration is changed ?

>  {
>  	struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
>  	const struct v4l2_ctrl_hevc_decode_params *decode_params = run->decode_params;
> @@ -143,8 +469,6 @@ get_ref_buf(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run,
>  	return buf;
>  }
>  
> -#define RKVDEC_HEVC_MAX_DEPTH_IN_BYTES		2
> -
>  int rkvdec_hevc_adjust_fmt(struct rkvdec_ctx *ctx, struct v4l2_format *f)
>  {
>  	struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp;
> @@ -178,5 +502,16 @@ void rkvdec_hevc_run_preamble(struct rkvdec_ctx *ctx,
>  			      V4L2_CID_STATELESS_HEVC_SCALING_MATRIX);
>  	run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL;
>  
> +	if (ctx->has_sps_st_rps) {
> +		ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> +				      V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS);
> +		run->ext_sps_st_rps = ctrl ? ctrl->p_cur.p : NULL;
> +	}
> +	if (ctx->has_sps_lt_rps) {
> +		ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> +				      V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS);
> +		run->ext_sps_lt_rps = ctrl ? ctrl->p_cur.p : NULL;
> +	}
> +
>  	rkvdec_run_preamble(ctx, &run->base);
>  }
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
> index 8af33bfd541c..4d345faae6b1 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
> @@ -16,19 +16,70 @@
>   */
>  
>  #include <media/v4l2-mem2mem.h>
> +#include <linux/types.h>
>  #include "rkvdec.h"
>  
>  #define RKV_HEVC_CABAC_TABLE_SIZE		27456
>  extern const u8 rkvdec_hevc_cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
>  
> +struct rkvdec_rps_refs {
> +	u16 lt_ref_pic_poc_lsb;
> +	u16 used_by_curr_pic_lt_flag	: 1;
> +	u16 reserved			: 15;
> +} __packed;
> +
> +struct rkvdec_rps_short_term_ref_set {
> +	u32 num_negative	: 4;
> +	u32 num_positive	: 4;
> +	u32 delta_poc0		: 16;
> +	u32 used_flag0		: 1;
> +	u32 delta_poc1		: 16;
> +	u32 used_flag1		: 1;
> +	u32 delta_poc2		: 16;
> +	u32 used_flag2		: 1;
> +	u32 delta_poc3		: 16;
> +	u32 used_flag3		: 1;
> +	u32 delta_poc4		: 16;
> +	u32 used_flag4		: 1;
> +	u32 delta_poc5		: 16;
> +	u32 used_flag5		: 1;
> +	u32 delta_poc6		: 16;
> +	u32 used_flag6		: 1;
> +	u32 delta_poc7		: 16;
> +	u32 used_flag7		: 1;
> +	u32 delta_poc8		: 16;
> +	u32 used_flag8		: 1;
> +	u32 delta_poc9		: 16;
> +	u32 used_flag9		: 1;
> +	u32 delta_poc10		: 16;
> +	u32 used_flag10		: 1;
> +	u32 delta_poc11		: 16;
> +	u32 used_flag11		: 1;
> +	u32 delta_poc12		: 16;
> +	u32 used_flag12		: 1;
> +	u32 delta_poc13		: 16;
> +	u32 used_flag13		: 1;
> +	u32 delta_poc14		: 16;
> +	u32 used_flag14		: 1;
> +	u32 reserved_bits	: 25;
> +	u32 reserved[3];
> +} __packed;
> +
> +struct rkvdec_rps {
> +	struct rkvdec_rps_refs refs[32];
> +	struct rkvdec_rps_short_term_ref_set short_term_ref_sets[64];
> +} __packed;
> +
>  struct rkvdec_hevc_run {
> -	struct rkvdec_run base;
> -	const struct v4l2_ctrl_hevc_slice_params *slices_params;
> -	const struct v4l2_ctrl_hevc_decode_params *decode_params;
> -	const struct v4l2_ctrl_hevc_sps *sps;
> -	const struct v4l2_ctrl_hevc_pps *pps;
> -	const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix;
> -	int num_slices;
> +	struct rkvdec_run				base;
> +	const struct v4l2_ctrl_hevc_decode_params	*decode_params;
> +	const struct v4l2_ctrl_hevc_slice_params	*slices_params;
> +	const struct v4l2_ctrl_hevc_sps			*sps;
> +	const struct v4l2_ctrl_hevc_pps			*pps;
> +	const struct v4l2_ctrl_hevc_scaling_matrix	*scaling_matrix;
> +	const struct v4l2_ctrl_hevc_ext_sps_st_rps	*ext_sps_st_rps;
> +	const struct v4l2_ctrl_hevc_ext_sps_lt_rps	*ext_sps_lt_rps;
> +	int						num_slices;

nit: Any reason for this format change in code ? Does not match other structs.

>  };
>  
>  struct scaling_factor {
> @@ -38,6 +89,14 @@ struct scaling_factor {
>  	u8 reserved[4];		/*16Bytes align*/
>  };
>  
> +void compute_tiles_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size,
> +			   u16 width, u16 height, s32 pic_in_cts_width,
> +			   s32 pic_in_cts_height, u16 *column_width, u16 *row_height);
> +void compute_tiles_non_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size,
> +			       u16 width, u16 height, s32 pic_in_cts_width,
> +			       s32 pic_in_cts_height, u16 *column_width, u16 *row_height);
> +void rkvdec_hevc_assemble_hw_rps(struct rkvdec_hevc_run *run, struct rkvdec_rps *rps,
> +				 struct v4l2_ctrl_hevc_ext_sps_st_rps *st_cache);
>  void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
>  					  struct scaling_factor *scaling_factor,
>  					  struct v4l2_ctrl_hevc_scaling_matrix *cache);
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
> new file mode 100644
> index 000000000000..dcca81c6e6f7
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
> @@ -0,0 +1,642 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Rockchip VDPU381 HEVC backend
> + *
> + * Copyright (C) 2025 Collabora, Ltd.
> + *  Detlev Casanova <detlev.casanova at collabora.com>
> + */
> +
> +#include <media/v4l2-mem2mem.h>
> +
> +#include "rkvdec.h"
> +#include "rkvdec-rcb.h"
> +#include "rkvdec-hevc-common.h"
> +#include "rkvdec-vdpu381-regs.h"
> +
> +// SPS
> +struct rkvdec_hevc_sps {
> +	u16 video_parameters_set_id			: 4;
> +	u16 seq_parameters_set_id_sps			: 4;
> +	u16 chroma_format_idc				: 2;
> +	u16 width					: 16;
> +	u16 height					: 16;
> +	u16 bit_depth_luma				: 4;
> +	u16 bit_depth_chroma				: 4;
> +	u16 max_pic_order_count_lsb			: 5;
> +	u16 diff_max_min_luma_coding_block_size		: 2;
> +	u16 min_luma_coding_block_size			: 3;
> +	u16 min_transform_block_size			: 3;
> +	u16 diff_max_min_transform_block_size		: 2;
> +	u16 max_transform_hierarchy_depth_inter		: 3;
> +	u16 max_transform_hierarchy_depth_intra		: 3;
> +	u16 scaling_list_enabled_flag			: 1;
> +	u16 amp_enabled_flag				: 1;
> +	u16 sample_adaptive_offset_enabled_flag		: 1;
> +	u16 pcm_enabled_flag				: 1;
> +	u16 pcm_sample_bit_depth_luma			: 4;
> +	u16 pcm_sample_bit_depth_chroma			: 4;
> +	u16 pcm_loop_filter_disabled_flag		: 1;
> +	u16 diff_max_min_pcm_luma_coding_block_size	: 3;
> +	u16 min_pcm_luma_coding_block_size		: 3;
> +	u16 num_short_term_ref_pic_sets			: 7;
> +	u16 long_term_ref_pics_present_flag		: 1;
> +	u16 num_long_term_ref_pics_sps			: 6;
> +	u16 sps_temporal_mvp_enabled_flag		: 1;
> +	u16 strong_intra_smoothing_enabled_flag		: 1;
> +	u16 reserved_0					: 7;
> +	u16 sps_max_dec_pic_buffering_minus1		: 4;
> +	u16 reserved_0_2				: 3;
> +	u16 reserved_f					: 8;
> +} __packed;
> +
> +//PPS
> +struct rkvdec_hevc_pps {
> +	u16 picture_parameters_set_id			: 6;
> +	u16 seq_parameters_set_id_pps			: 4;
> +	u16 dependent_slice_segments_enabled_flag	: 1;
> +	u16 output_flag_present_flag			: 1;
> +	u16 num_extra_slice_header_bits			: 13;
> +	u16 sign_data_hiding_enabled_flag		: 1;
> +	u16 cabac_init_present_flag			: 1;
> +	u16 num_ref_idx_l0_default_active		: 4;
> +	u16 num_ref_idx_l1_default_active		: 4;
> +	u16 init_qp_minus26				: 7;
> +	u16 constrained_intra_pred_flag			: 1;
> +	u16 transform_skip_enabled_flag			: 1;
> +	u16 cu_qp_delta_enabled_flag			: 1;
> +	u16 log2_min_cb_size				: 3;
> +	u16 pps_cb_qp_offset				: 5;
> +	u16 pps_cr_qp_offset				: 5;
> +	u16 pps_slice_chroma_qp_offsets_present_flag	: 1;
> +	u16 weighted_pred_flag				: 1;
> +	u16 weighted_bipred_flag			: 1;
> +	u16 transquant_bypass_enabled_flag		: 1;
> +	u16 tiles_enabled_flag				: 1;
> +	u16 entropy_coding_sync_enabled_flag		: 1;
> +	u16 pps_loop_filter_across_slices_enabled_flag	: 1;
> +	u16 loop_filter_across_tiles_enabled_flag	: 1;
> +	u16 deblocking_filter_override_enabled_flag	: 1;
> +	u16 pps_deblocking_filter_disabled_flag		: 1;
> +	u16 pps_beta_offset_div2			: 4;
> +	u16 pps_tc_offset_div2				: 4;
> +	u16 lists_modification_present_flag		: 1;
> +	u16 log2_parallel_merge_level			: 3;
> +	u16 slice_segment_header_extension_present_flag	: 1;
> +	u16 zeroes					: 3;
> +	u16 num_tile_columns				: 5;
> +	u16 num_tile_rows				: 5;
> +	u16 sps_pps_mode				: 4;
> +	u16 reserved_bits				: 14;
> +	u16 reserved;
> +} __packed;
> +
> +struct rkvdec_hevc_tile {
> +	u16 value0	: 12;
> +	u16 value1	: 12;
> +} __packed;
> +
> +struct rkvdec_sps_pps_packet {
> +	struct rkvdec_hevc_sps sps;
> +	struct rkvdec_hevc_pps pps;
> +	struct rkvdec_hevc_tile column_width[10];
> +	struct rkvdec_hevc_tile row_height[11];
> +	u32 zeroes[3];
> +	u32 zeroes_bits		: 6;
> +	u32 padding_bits	: 2;
> +	u32 padding;
> +} __packed;
> +
> +struct rkvdec_hevc_priv_tbl {
> +	struct rkvdec_sps_pps_packet param_set[64];
> +	struct rkvdec_rps rps;
> +	struct scaling_factor scaling_list;
> +	u8 cabac_table[27456];
> +};
> +
> +struct rkvdec_hevc_ctx {
> +	struct rkvdec_aux_buf			priv_tbl;
> +	struct v4l2_ctrl_hevc_scaling_matrix	scaling_matrix_cache;
> +	struct v4l2_ctrl_hevc_ext_sps_st_rps	st_cache;
> +	struct rkvdec_vdpu381_regs_hevc		regs;
> +};
> +
> +static void assemble_hw_pps(struct rkvdec_ctx *ctx,
> +			    struct rkvdec_hevc_run *run)
> +{
> +	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
> +	const struct v4l2_ctrl_hevc_sps *sps = run->sps;
> +	const struct v4l2_ctrl_hevc_pps *pps = run->pps;
> +	struct rkvdec_hevc_priv_tbl *priv_tbl = hevc_ctx->priv_tbl.cpu;
> +	struct rkvdec_sps_pps_packet *hw_ps;
> +	bool tiles_enabled;
> +	s32 max_cu_width;
> +	s32 pic_in_cts_width;
> +	s32 pic_in_cts_height;
> +	u16 log2_min_cb_size, width, height;
> +	u16 column_width[20];
> +	u16 row_height[22];
> +	u8 pcm_enabled;
> +	u32 i;
> +
> +	/*
> +	 * HW read the SPS/PPS information from PPS packet index by PPS id.
> +	 * offset from the base can be calculated by PPS_id * 32 (size per PPS
> +	 * packet unit). so the driver copy SPS/PPS information to the exact PPS
> +	 * packet unit for HW accessing.
> +	 */
> +	hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id];
> +	memset(hw_ps, 0, sizeof(*hw_ps));
> +
> +	/* write sps */
> +	hw_ps->sps.video_parameters_set_id = sps->video_parameter_set_id;
> +	hw_ps->sps.seq_parameters_set_id_sps = sps->seq_parameter_set_id;
> +	hw_ps->sps.chroma_format_idc = sps->chroma_format_idc;
> +
> +	log2_min_cb_size = sps->log2_min_luma_coding_block_size_minus3 + 3;
> +	width = sps->pic_width_in_luma_samples;
> +	height = sps->pic_height_in_luma_samples;
> +	hw_ps->sps.width = width;
> +	hw_ps->sps.height = height;
> +	hw_ps->sps.bit_depth_luma = sps->bit_depth_luma_minus8 + 8;
> +	hw_ps->sps.bit_depth_chroma = sps->bit_depth_chroma_minus8 + 8;
> +	hw_ps->sps.max_pic_order_count_lsb = sps->log2_max_pic_order_cnt_lsb_minus4 + 4;
> +	hw_ps->sps.diff_max_min_luma_coding_block_size =
> +		sps->log2_diff_max_min_luma_coding_block_size;
> +	hw_ps->sps.min_luma_coding_block_size = sps->log2_min_luma_coding_block_size_minus3 + 3;
> +	hw_ps->sps.min_transform_block_size = sps->log2_min_luma_transform_block_size_minus2 + 2;
> +	hw_ps->sps.diff_max_min_transform_block_size =
> +		sps->log2_diff_max_min_luma_transform_block_size;
> +	hw_ps->sps.max_transform_hierarchy_depth_inter = sps->max_transform_hierarchy_depth_inter;
> +	hw_ps->sps.max_transform_hierarchy_depth_intra = sps->max_transform_hierarchy_depth_intra;
> +	hw_ps->sps.scaling_list_enabled_flag =
> +		!!(sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED);
> +	hw_ps->sps.amp_enabled_flag = !!(sps->flags & V4L2_HEVC_SPS_FLAG_AMP_ENABLED);
> +	hw_ps->sps.sample_adaptive_offset_enabled_flag =
> +		!!(sps->flags & V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET);
> +
> +	pcm_enabled = !!(sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED);
> +	hw_ps->sps.pcm_enabled_flag = pcm_enabled;
> +	hw_ps->sps.pcm_sample_bit_depth_luma =
> +		pcm_enabled ? sps->pcm_sample_bit_depth_luma_minus1 + 1 : 0;
> +	hw_ps->sps.pcm_sample_bit_depth_chroma =
> +		pcm_enabled ? sps->pcm_sample_bit_depth_chroma_minus1 + 1 : 0;
> +	hw_ps->sps.pcm_loop_filter_disabled_flag =
> +		!!(sps->flags & V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED);
> +	hw_ps->sps.diff_max_min_pcm_luma_coding_block_size =
> +		sps->log2_diff_max_min_pcm_luma_coding_block_size;
> +	hw_ps->sps.min_pcm_luma_coding_block_size =
> +		pcm_enabled ? sps->log2_min_pcm_luma_coding_block_size_minus3 + 3 : 0;
> +	hw_ps->sps.num_short_term_ref_pic_sets = sps->num_short_term_ref_pic_sets;
> +	hw_ps->sps.long_term_ref_pics_present_flag =
> +		!!(sps->flags & V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT);
> +	hw_ps->sps.num_long_term_ref_pics_sps = sps->num_long_term_ref_pics_sps;
> +	hw_ps->sps.sps_temporal_mvp_enabled_flag =
> +		!!(sps->flags & V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED);
> +	hw_ps->sps.strong_intra_smoothing_enabled_flag =
> +		!!(sps->flags & V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED);
> +	hw_ps->sps.sps_max_dec_pic_buffering_minus1 = sps->sps_max_dec_pic_buffering_minus1;
> +	hw_ps->sps.reserved_f = 0xff;
> +
> +	/* write pps */
> +	hw_ps->pps.picture_parameters_set_id = pps->pic_parameter_set_id;
> +	hw_ps->pps.seq_parameters_set_id_pps = sps->seq_parameter_set_id;
> +	hw_ps->pps.dependent_slice_segments_enabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED);
> +	hw_ps->pps.output_flag_present_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT);
> +	hw_ps->pps.num_extra_slice_header_bits = pps->num_extra_slice_header_bits;
> +	hw_ps->pps.sign_data_hiding_enabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED);
> +	hw_ps->pps.cabac_init_present_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT);
> +	hw_ps->pps.num_ref_idx_l0_default_active = pps->num_ref_idx_l0_default_active_minus1 + 1;
> +	hw_ps->pps.num_ref_idx_l1_default_active = pps->num_ref_idx_l1_default_active_minus1 + 1;
> +	hw_ps->pps.init_qp_minus26 = pps->init_qp_minus26;
> +	hw_ps->pps.constrained_intra_pred_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED);
> +	hw_ps->pps.transform_skip_enabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED);
> +	hw_ps->pps.cu_qp_delta_enabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED);
> +	hw_ps->pps.log2_min_cb_size = log2_min_cb_size +
> +				      sps->log2_diff_max_min_luma_coding_block_size -
> +				      pps->diff_cu_qp_delta_depth;
> +	hw_ps->pps.pps_cb_qp_offset = pps->pps_cb_qp_offset;
> +	hw_ps->pps.pps_cr_qp_offset = pps->pps_cr_qp_offset;
> +	hw_ps->pps.pps_slice_chroma_qp_offsets_present_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT);
> +	hw_ps->pps.weighted_pred_flag = !!(pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED);
> +	hw_ps->pps.weighted_bipred_flag = !!(pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED);
> +	hw_ps->pps.transquant_bypass_enabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED);
> +
> +	tiles_enabled = !!(pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED);
> +	hw_ps->pps.tiles_enabled_flag = tiles_enabled;
> +	hw_ps->pps.entropy_coding_sync_enabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED);
> +	hw_ps->pps.pps_loop_filter_across_slices_enabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED);
> +	hw_ps->pps.loop_filter_across_tiles_enabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED);
> +	hw_ps->pps.deblocking_filter_override_enabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED);
> +	hw_ps->pps.pps_deblocking_filter_disabled_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER);
> +	hw_ps->pps.pps_beta_offset_div2 = pps->pps_beta_offset_div2;
> +	hw_ps->pps.pps_tc_offset_div2 = pps->pps_tc_offset_div2;
> +	hw_ps->pps.lists_modification_present_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT);
> +	hw_ps->pps.log2_parallel_merge_level = pps->log2_parallel_merge_level_minus2 + 2;
> +	hw_ps->pps.slice_segment_header_extension_present_flag =
> +		!!(pps->flags & V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT);
> +	hw_ps->pps.num_tile_columns = tiles_enabled ? pps->num_tile_columns_minus1 + 1 : 0;
> +	hw_ps->pps.num_tile_rows = tiles_enabled ? pps->num_tile_rows_minus1 + 1 : 0;
> +	hw_ps->pps.sps_pps_mode = 0;
> +	hw_ps->pps.reserved_bits = 0x3fff;
> +	hw_ps->pps.reserved = 0xffff;
> +
> +	// Setup tiles information
> +	memset(column_width, 0, sizeof(column_width));
> +	memset(row_height, 0, sizeof(row_height));
> +
> +	max_cu_width = 1 << (sps->log2_diff_max_min_luma_coding_block_size + log2_min_cb_size);
> +	pic_in_cts_width = (width + max_cu_width - 1) / max_cu_width;
> +	pic_in_cts_height = (height + max_cu_width - 1) / max_cu_width;
> +
> +	if (pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED) {
> +		if (pps->flags & V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING) {
> +			compute_tiles_uniform(run, log2_min_cb_size, width, height,
> +					      pic_in_cts_width, pic_in_cts_height,
> +					      column_width, row_height);
> +		} else {
> +			compute_tiles_non_uniform(run, log2_min_cb_size, width, height,
> +						  pic_in_cts_width, pic_in_cts_height,
> +						  column_width, row_height);
> +		}
> +	} else {
> +		column_width[0] = (width + max_cu_width - 1) / max_cu_width;
> +		row_height[0] = (height + max_cu_width - 1) / max_cu_width;
> +	}
> +
> +	for (i = 0; i < 20; i++) {
> +		if (column_width[i] > 0)
> +			column_width[i]--;
> +
> +		if (i & 1)
> +			hw_ps->column_width[i / 2].value1 = column_width[i];
> +		else
> +			hw_ps->column_width[i / 2].value0 = column_width[i];
> +	}
> +
> +	for (i = 0; i < 22; i++) {
> +		if (row_height[i] > 0)
> +			row_height[i]--;
> +
> +		if (i & 1)
> +			hw_ps->row_height[i / 2].value1 = row_height[i];
> +		else
> +			hw_ps->row_height[i / 2].value0 = row_height[i];
> +	}
> +
> +	hw_ps->padding = 0xffffffff;
> +	hw_ps->padding_bits = 0x3;
> +}
> +
> +static void set_ref_valid(struct rkvdec_vdpu381_regs_hevc *regs, int id, u32 valid)
> +{
> +	switch (id) {
> +	case 0:
> +		regs->hevc_param.reg099.hevc_ref_valid_0 = valid;
> +		break;
> +	case 1:
> +		regs->hevc_param.reg099.hevc_ref_valid_1 = valid;
> +		break;
> +	case 2:
> +		regs->hevc_param.reg099.hevc_ref_valid_2 = valid;
> +		break;
> +	case 3:
> +		regs->hevc_param.reg099.hevc_ref_valid_3 = valid;
> +		break;
> +	case 4:
> +		regs->hevc_param.reg099.hevc_ref_valid_4 = valid;
> +		break;
> +	case 5:
> +		regs->hevc_param.reg099.hevc_ref_valid_5 = valid;
> +		break;
> +	case 6:
> +		regs->hevc_param.reg099.hevc_ref_valid_6 = valid;
> +		break;
> +	case 7:
> +		regs->hevc_param.reg099.hevc_ref_valid_7 = valid;
> +		break;
> +	case 8:
> +		regs->hevc_param.reg099.hevc_ref_valid_8 = valid;
> +		break;
> +	case 9:
> +		regs->hevc_param.reg099.hevc_ref_valid_9 = valid;
> +		break;
> +	case 10:
> +		regs->hevc_param.reg099.hevc_ref_valid_10 = valid;
> +		break;
> +	case 11:
> +		regs->hevc_param.reg099.hevc_ref_valid_11 = valid;
> +		break;
> +	case 12:
> +		regs->hevc_param.reg099.hevc_ref_valid_12 = valid;
> +		break;
> +	case 13:
> +		regs->hevc_param.reg099.hevc_ref_valid_13 = valid;
> +		break;
> +	case 14:
> +		regs->hevc_param.reg099.hevc_ref_valid_14 = valid;
> +		break;
> +	}
> +}
> +
> +static void rkvdec_write_regs(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
> +
> +	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_REGS,
> +			   &hevc_ctx->regs.common,
> +			   sizeof(hevc_ctx->regs.common));
> +	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_PARAMS_REGS,
> +			   &hevc_ctx->regs.hevc_param,
> +			   sizeof(hevc_ctx->regs.hevc_param));
> +	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_ADDR_REGS,
> +			   &hevc_ctx->regs.common_addr,
> +			   sizeof(hevc_ctx->regs.common_addr));
> +	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_ADDR_REGS,
> +			   &hevc_ctx->regs.hevc_addr,
> +			   sizeof(hevc_ctx->regs.hevc_addr));
> +	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_POC_HIGHBIT_REGS,
> +			   &hevc_ctx->regs.hevc_highpoc,
> +			   sizeof(hevc_ctx->regs.hevc_highpoc));
> +}
> +
> +static void config_registers(struct rkvdec_ctx *ctx,
> +			     struct rkvdec_hevc_run *run)
> +{
> +	const struct v4l2_ctrl_hevc_decode_params *dec_params = run->decode_params;
> +	const struct v4l2_hevc_dpb_entry *dpb = dec_params->dpb;
> +	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
> +	struct rkvdec_vdpu381_regs_hevc *regs = &hevc_ctx->regs;
> +	dma_addr_t priv_start_addr = hevc_ctx->priv_tbl.dma;
> +	const struct v4l2_pix_format_mplane *dst_fmt;
> +	struct vb2_v4l2_buffer *src_buf = run->base.bufs.src;
> +	struct vb2_v4l2_buffer *dst_buf = run->base.bufs.dst;
> +	const struct v4l2_format *f;
> +	dma_addr_t rlc_addr;
> +	u32 hor_virstride = 0;
> +	u32 ver_virstride = 0;
> +	u32 y_virstride = 0;
> +	u32 offset;
> +	u32 pixels;
> +	dma_addr_t dst_addr;
> +	u32 i;
> +
> +	memset(regs, 0, sizeof(*regs));
> +
> +	/* Set HEVC mode */
> +	regs->common.reg009.dec_mode = VDPU381_MODE_HEVC;
> +
> +	/* Set config */
> +	regs->common.reg011.buf_empty_en = 1;
> +	regs->common.reg011.dec_clkgate_e = 1;
> +	regs->common.reg011.dec_timeout_e = 1;
> +	regs->common.reg011.pix_range_detection_e = 1;
> +
> +	/* Set IDR flag */
> +	regs->common.reg013.cur_pic_is_idr =
> +		!!(dec_params->flags & V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC);
> +
> +	/* Set input stream length */
> +	regs->common.stream_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
> +
> +	/* Set max slice number */
> +	regs->common.reg017.slice_num = 1;
> +
> +	/* Set strides */
> +	f = &ctx->decoded_fmt;
> +	dst_fmt = &f->fmt.pix_mp;
> +	hor_virstride = dst_fmt->plane_fmt[0].bytesperline;
> +	ver_virstride = dst_fmt->height;
> +	y_virstride = hor_virstride * ver_virstride;
> +	pixels = dst_fmt->height * dst_fmt->width;
> +
> +	regs->common.reg018.y_hor_virstride = hor_virstride / 16;
> +	regs->common.reg019.uv_hor_virstride = hor_virstride / 16;
> +	regs->common.reg020.y_virstride = y_virstride / 16;
> +
> +	/* Activate block gating */
> +	regs->common.reg026.swreg_block_gating_e = 0xfffef;
> +	regs->common.reg026.reg_cfg_gating_en = 1;
> +
> +	/* Set timeout threshold */
> +	if (pixels < RKVDEC_1080P_PIXELS)
> +		regs->common.timeout_threshold = RKVDEC_TIMEOUT_1080p;
> +	else if (pixels < RKVDEC_4K_PIXELS)
> +		regs->common.timeout_threshold = RKVDEC_TIMEOUT_4K;
> +	else if (pixels < RKVDEC_8K_PIXELS)
> +		regs->common.timeout_threshold = RKVDEC_TIMEOUT_8K;
> +
> +	/* Set POC val */
> +	regs->hevc_param.cur_top_poc = dec_params->pic_order_cnt_val;
> +
> +	/* Set ref pic address & poc */
> +	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
> +		struct vb2_buffer *vb_buf = get_ref_buf(ctx, run, i);
> +		dma_addr_t buf_dma = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
> +		u32 valid = !!(dec_params->num_active_dpb_entries > i);
> +
> +		/* Set reference addresses */
> +		regs->hevc_addr.ref_base[i] = buf_dma;
> +
> +		/* Set COLMV addresses */
> +		regs->hevc_addr.colmv_base[i] = buf_dma + ctx->colmv_offset;
> +
> +		regs->hevc_param.reg067_082_ref_poc[i] =
> +			dpb[i].pic_order_cnt_val;
> +
> +		set_ref_valid(regs, i, valid);
> +		regs->hevc_param.reg103.ref_pic_layer_same_with_cur |= 1 << i;
> +	}
> +
> +	/* Set rlc base address (input stream) */
> +	rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
> +	regs->common_addr.rlc_base = rlc_addr;
> +	regs->common_addr.rlcwrite_base = rlc_addr;
> +
> +	/* Set output base address */
> +	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
> +	regs->common_addr.decout_base = dst_addr;
> +	regs->common_addr.error_ref_base = dst_addr;
> +
> +	/* Set colmv address */
> +	regs->common_addr.colmv_cur_base = dst_addr + ctx->colmv_offset;
> +
> +	/* Set RCB addresses */
> +	for (i = 0; i < rkvdec_rcb_buf_count(ctx); i++)
> +		regs->common_addr.rcb_base[i] = rkvdec_rcb_buf_dma_addr(ctx, i);
> +
> +	/* Set hw pps address */
> +	offset = offsetof(struct rkvdec_hevc_priv_tbl, param_set);
> +	regs->hevc_addr.pps_base = priv_start_addr + offset;
> +
> +	/* Set hw rps address */
> +	offset = offsetof(struct rkvdec_hevc_priv_tbl, rps);
> +	regs->hevc_addr.rps_base = priv_start_addr + offset;
> +
> +	/* Set cabac table */
> +	offset = offsetof(struct rkvdec_hevc_priv_tbl, cabac_table);
> +	regs->hevc_addr.cabactbl_base = priv_start_addr + offset;
> +
> +	/* Set scaling matrix */
> +	offset = offsetof(struct rkvdec_hevc_priv_tbl, scaling_list);
> +	regs->hevc_addr.scanlist_addr = priv_start_addr + offset;
> +
> +	rkvdec_write_regs(ctx);
> +}
> +
> +static enum rkvdec_image_fmt rkvdec_hevc_get_image_fmt(struct rkvdec_ctx *ctx,
> +						       struct v4l2_ctrl *ctrl)
> +{
> +	const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps;
> +
> +	if (ctrl->id != V4L2_CID_STATELESS_HEVC_SPS)
> +		return RKVDEC_IMG_FMT_ANY;
> +
> +	if (sps->bit_depth_luma_minus8 == 0)
> +		return RKVDEC_IMG_FMT_420_8BIT;
> +	else if (sps->bit_depth_luma_minus8 == 2)
> +		return RKVDEC_IMG_FMT_420_10BIT;
> +
> +	return RKVDEC_IMG_FMT_ANY;
> +}

There should not be a need for a dedicated version of this function.

You should probably move the existing rkvdec_hevc_get_image_fmt to
common and use that version instead ?

> +
> +static int rkvdec_hevc_validate_sps(struct rkvdec_ctx *ctx,
> +				    const struct v4l2_ctrl_hevc_sps *sps)
> +{
> +	if (sps->chroma_format_idc != 1)
> +		/* Only 4:2:0 is supported */
> +		return -EINVAL;
> +
> +	if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
> +		/* Luma and chroma bit depth mismatch */
> +		return -EINVAL;
> +
> +	if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2)
> +		/* Only 8-bit and 10-bit are supported */
> +		return -EINVAL;
> +
> +	if (sps->pic_width_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.width ||
> +	    sps->pic_height_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.height)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static int rkvdec_hevc_start(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	struct rkvdec_hevc_priv_tbl *priv_tbl;
> +	struct rkvdec_hevc_ctx *hevc_ctx;
> +	struct v4l2_ctrl *ctrl;
> +	int ret;
> +
> +	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> +			      V4L2_CID_STATELESS_HEVC_SPS);
> +	if (!ctrl)
> +		return -EINVAL;
> +
> +	ret = rkvdec_hevc_validate_sps(ctx, ctrl->p_new.p_hevc_sps);
> +	if (ret)
> +		return ret;

Same note as for h264, this validate sps should not be needed here.

> +
> +	hevc_ctx = kzalloc(sizeof(*hevc_ctx), GFP_KERNEL);
> +	if (!hevc_ctx)
> +		return -ENOMEM;
> +
> +	priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl),
> +				      &hevc_ctx->priv_tbl.dma, GFP_KERNEL);
> +	if (!priv_tbl) {
> +		ret = -ENOMEM;
> +		goto err_free_ctx;
> +	}
> +
> +	hevc_ctx->priv_tbl.size = sizeof(*priv_tbl);
> +	hevc_ctx->priv_tbl.cpu = priv_tbl;
> +	memcpy(priv_tbl->cabac_table, rkvdec_hevc_cabac_table,
> +	       sizeof(rkvdec_hevc_cabac_table));
> +
> +	ctx->priv = hevc_ctx;
> +	return 0;
> +
> +err_free_ctx:
> +	kfree(hevc_ctx);
> +	return ret;
> +}
> +
> +static void rkvdec_hevc_stop(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +
> +	dma_free_coherent(rkvdec->dev, hevc_ctx->priv_tbl.size,
> +			  hevc_ctx->priv_tbl.cpu, hevc_ctx->priv_tbl.dma);
> +	kfree(hevc_ctx);
> +}
> +
> +static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	struct rkvdec_hevc_run run;
> +	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
> +	struct rkvdec_hevc_priv_tbl *tbl = hevc_ctx->priv_tbl.cpu;
> +
> +	rkvdec_hevc_run_preamble(ctx, &run);
> +
> +	/*
> +	 * On vdpu381, not setting the long and short term ref sets will just output wrong frames.
> +	 * Let's just warn about it and let the decoder run anyway.
> +	 */
> +	if ((!ctx->has_sps_lt_rps && run.sps->num_long_term_ref_pics_sps) ||
> +		(!ctx->has_sps_st_rps && run.sps->num_short_term_ref_pic_sets)) {
> +		dev_warn_ratelimited(rkvdec->dev, "Long and short term RPS not set\n");
> +	}
> +
> +	rkvdec_hevc_assemble_hw_scaling_list(&run,
> +					     &tbl->scaling_list,
> +					     &hevc_ctx->scaling_matrix_cache);
> +	assemble_hw_pps(ctx, &run);
> +	rkvdec_hevc_assemble_hw_rps(&run, &tbl->rps, &hevc_ctx->st_cache);
> +
> +	config_registers(ctx, &run);
> +
> +	rkvdec_run_postamble(ctx, &run.base);
> +
> +	schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000));
> +
> +	/* Start decoding! */
> +	writel(VDPU381_DEC_E_BIT, rkvdec->regs + VDPU381_REG_DEC_E);
> +
> +	return 0;
> +}
> +
> +static int rkvdec_hevc_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
> +{
> +	if (ctrl->id == V4L2_CID_STATELESS_HEVC_SPS)
> +		return rkvdec_hevc_validate_sps(ctx, ctrl->p_new.p_hevc_sps);
> +
> +	return 0;
> +}
> +
> +const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_hevc_fmt_ops = {
> +	.adjust_fmt = rkvdec_hevc_adjust_fmt,
> +	.start = rkvdec_hevc_start,
> +	.stop = rkvdec_hevc_stop,
> +	.run = rkvdec_hevc_run,
> +	.try_ctrl = rkvdec_hevc_try_ctrl,
> +	.get_image_fmt = rkvdec_hevc_get_image_fmt,
> +};
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> index ceb56516bd90..7bb98c98a82b 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> @@ -154,6 +154,16 @@ static int rkvdec_s_ctrl(struct v4l2_ctrl *ctrl)
>  	enum rkvdec_image_fmt image_fmt;
>  	struct vb2_queue *vq;
>  
> +	if (ctrl->id == V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS) {
> +		ctx->has_sps_st_rps |= !!(ctrl->has_changed);
> +		return 0;
> +	}
> +
> +	if (ctrl->id == V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS) {
> +		ctx->has_sps_lt_rps |= !!(ctrl->has_changed);
> +		return 0;
> +	}
> +
>  	/* Check if this change requires a capture format reset */
>  	if (!desc->ops->get_image_fmt)
>  		return 0;
> @@ -285,6 +295,62 @@ static const struct rkvdec_ctrls rkvdec_h264_ctrls = {
>  	.num_ctrls = ARRAY_SIZE(rkvdec_h264_ctrl_descs),
>  };
>  
> +static const struct rkvdec_ctrl_desc vdpu38x_hevc_ctrl_descs[] = {
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_SPS,
> +		.cfg.ops = &rkvdec_ctrl_ops,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_PPS,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_MODE,
> +		.cfg.min = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
> +		.cfg.max = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
> +		.cfg.def = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_START_CODE,
> +		.cfg.min = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
> +		.cfg.def = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
> +		.cfg.max = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
> +		.cfg.min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
> +		.cfg.max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
> +		.cfg.menu_skip_mask =
> +			BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE),
> +		.cfg.def = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
> +		.cfg.min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
> +		.cfg.max = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS,
> +		.cfg.ops = &rkvdec_ctrl_ops,
> +		.cfg.dims = { 65 },
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS,
> +		.cfg.ops = &rkvdec_ctrl_ops,
> +		.cfg.dims = { 65 },
> +	},
> +};
> +
> +static const struct rkvdec_ctrls vdpu38x_hevc_ctrls = {
> +	.ctrls = vdpu38x_hevc_ctrl_descs,
> +	.num_ctrls = ARRAY_SIZE(vdpu38x_hevc_ctrl_descs),
> +};

These new hevc struct seem out of place, maybe move closer to existing
hevc structs ?

> +
>  static const struct rkvdec_decoded_fmt_desc rkvdec_h264_decoded_fmts[] = {
>  	{
>  		.fourcc = V4L2_PIX_FMT_NV12,
> @@ -401,6 +467,23 @@ static const struct rkvdec_coded_fmt_desc vdpu381_coded_fmts[] = {
>  		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
>  		.capability = RKVDEC_CAPABILITY_H264,
>  	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_HEVC_SLICE,
> +		.frmsize = {
> +			.min_width = 64,
> +			.max_width = 65472,
> +			.step_width = 64,
> +			.min_height = 64,
> +			.max_height = 65472,
> +			.step_height = 16,
> +		},
> +		.ctrls = &vdpu38x_hevc_ctrls,
> +		.ops = &rkvdec_vdpu381_hevc_fmt_ops,
> +		.num_decoded_fmts = ARRAY_SIZE(rkvdec_hevc_decoded_fmts),
> +		.decoded_fmts = rkvdec_hevc_decoded_fmts,
> +		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
> +		.capability = RKVDEC_CAPABILITY_HEVC,
> +	},

Please move HEVC before H264 to be consistent with dec_mode reg and
existing order in coded_fmts for other variants.

>  };
>  
>  static const struct rkvdec_coded_fmt_desc vdpu383_coded_fmts[] = {
> @@ -1494,7 +1577,8 @@ static const struct rkvdec_variant rk3588_vdpu381_variant = {
>  	.num_rcb_sizes = ARRAY_SIZE(vdpu381_rcb_sizes),
>  	.ops = &vdpu381_variant_ops,
>  	.named_regs = true,
> -	.capabilities = RKVDEC_CAPABILITY_H264,
> +	.capabilities = RKVDEC_CAPABILITY_H264 |
> +			RKVDEC_CAPABILITY_HEVC,

We should be albe to drop the capabilities flags now, else please order
in consistent order as exising variants.

>  };
>  
>  static const struct rkvdec_variant_ops vdpu383_variant_ops = {
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> index 2f924c924828..44ff50ec6d85 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> @@ -160,6 +160,8 @@ struct rkvdec_ctx {
>  	struct rkvdec_rcb_config *rcb_config;
>  	u32 colmv_offset;
>  	void *priv;
> +	u8 has_sps_st_rps: 1;
> +	u8 has_sps_lt_rps: 1;
>  };
>  
>  static inline struct rkvdec_ctx *file_to_rkvdec_ctx(struct file *filp)
> @@ -192,6 +194,7 @@ extern const struct rkvdec_coded_fmt_ops rkvdec_vp9_fmt_ops;
>  
>  /* VDPU381 ops */
>  extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_h264_fmt_ops;
> +extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_hevc_fmt_ops;
>  
>  /* VDPU383 ops */
>  extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu383_h264_fmt_ops;



From rostedt at kernel.org  Wed Dec 17 17:07:12 2025
From: rostedt at kernel.org (Steven Rostedt)
Date: Wed, 17 Dec 2025 20:07:12 -0500
Subject: [PATCHv5 bpf-next 3/9] ftrace: Export some of hash related
 functions
In-Reply-To: <20251215211402.353056-4-jolsa@kernel.org>
References: <20251215211402.353056-1-jolsa@kernel.org>
	<20251215211402.353056-4-jolsa@kernel.org>
Message-ID: <20251217200712.606a9a7a@robin>

On Mon, 15 Dec 2025 22:13:56 +0100
Jiri Olsa <jolsa at kernel.org> wrote:

> index 505b7d3f5641..c0a72fcae1f6 100644
> --- a/include/linux/ftrace.h
> +++ b/include/linux/ftrace.h
> @@ -82,6 +82,7 @@ static inline void early_trace_init(void) { }
>  
>  struct module;
>  struct ftrace_hash;
> +struct ftrace_func_entry;
>  
>  #if defined(CONFIG_FUNCTION_TRACER) && defined(CONFIG_MODULES) && \
>  	defined(CONFIG_DYNAMIC_FTRACE)
> @@ -405,6 +406,14 @@ enum ftrace_ops_cmd {
>  typedef int (*ftrace_ops_func_t)(struct ftrace_ops *op, enum ftrace_ops_cmd cmd);
>  
>  #ifdef CONFIG_DYNAMIC_FTRACE
> +
> +#define FTRACE_HASH_DEFAULT_BITS 10
> +
> +struct ftrace_hash *alloc_ftrace_hash(int size_bits);
> +void free_ftrace_hash(struct ftrace_hash *hash);
> +struct ftrace_func_entry *add_hash_entry_direct(struct ftrace_hash *hash,

As this is no longer static and is exported to other users within the
kernel, it should be renamed to: add_ftrace_hash_entry_direct()
to keep the namespace unique.

-- Steve

> +						unsigned long ip, unsigned long direct);
> +
>  /* The hash used to know what functions callbacks trace */
>  struct ftrace_ops_hash {
>  	struct ftrace_hash __rcu	*notrace_hash;


From ck.hu at mediatek.com  Wed Dec 17 17:13:25 2025
From: ck.hu at mediatek.com (=?utf-8?B?Q0sgSHUgKOiDoeS/iuWFiSk=?=)
Date: Thu, 18 Dec 2025 01:13:25 +0000
Subject: [PATCH v7 1/2] drm/mediatek: Adjust bandwidth limit for DP
In-Reply-To: <f4e8ba2e9f9a8e5fd4b35afe25b9874c64c6ea17.camel@mediatek.com>
References: <20251104085957.1175-1-liankun.yang@mediatek.com>
	 <20251104085957.1175-2-liankun.yang@mediatek.com>
	 <18cd9c74699b5afe4d0bff9a6c325389d2881e29.camel@mediatek.com>
	 <dfd8767809d52efee2e7592e4b45cfd2425334b8.camel@mediatek.com>
	 <54b075b4ff6b9aa7cd916bb65e34e5edae3642dc.camel@mediatek.com>
	 <f4e8ba2e9f9a8e5fd4b35afe25b9874c64c6ea17.camel@mediatek.com>
Message-ID: <1fdb12e5f06c3087ebf0c0296f6b1cad45c237af.camel@mediatek.com>

On Mon, 2025-12-01 at 06:39 +0000, LIANKUN YANG (???) wrote:
> On Wed, 2025-11-26 at 03:11 +0000, CK Hu (???) wrote:
> > On Mon, 2025-11-24 at 09:14 +0000, LIANKUN YANG (???) wrote:
> > > On Wed, 2025-11-19 at 09:18 +0000, CK Hu (???) wrote:
> > > > On Tue, 2025-11-04 at 16:55 +0800, Liankun Yang wrote:
> > > > > By adjusting the order of link training and relocating it to
> > > > > HPD,
> > > > > link training can identify the usability of each lane in the
> > > > > current link.
> > > > > 
> > > > > It also supports handling signal instability and weakness due
> > > > > to
> > > > > environmental issues, enabling the acquisition of a stable
> > > > > bandwidth
> > > > > for the current link. Subsequently, DP work can proceed based
> > > > > on
> > > > > the actual maximum bandwidth.
> > > > > 
> > > > > It should training in the hpd event thread.
> > > > > Check the mode with lane count and link rate of training.
> > > > > 
> > > > > If we're eDP and capabilities were already parsed we can skip
> > > > > reading again because eDP panels aren't hotpluggable hence the
> > > > > caps and training information won't ever change in a boot life
> > > > > 
> > > > > Therefore, bridge typec judgment is required for edp training
> > > > > in
> > > > > atomic_enable function.
> > > > > 
> > > > > The `mtk_dp_aux_panel_poweron` function fails to align.
> > > > > Within the `mtk_dp_hpd_event_thread`, if DP is disconnected,
> > > > > the `mtk_dp_aux_panel_poweron` function will write from `aux`
> > > > > to
> > > > > `DPRX`,
> > > > > causing a failure and thus preventing symmetry.
> > > > 
> > > > I'm curious about another case.
> > > > In your description, when DP plug out and plug in, DRM core would
> > > > not
> > > > call mtk_dp_bridge_atomic_enable(), right?
> > > > If so, when I plug out DP, and plug in another DP panel which
> > > > support
> > > > smaller resolution,
> > > > then mtk_dp_bridge_atomic_enable() is not called and below call
> > > > sequence would not happen:
> > > > 
> > > > mtk_dp_bridge_atomic_enable() -> mtk_dp_video_enable() ->
> > > > mtk_dp_set_tx_out() -> mtk_dp_setup_tu()
> > > > 
> > > > In mtk_dp_setup_tu, it would set sram_read_start according to
> > > > lane_count.
> > > > But the call sequence would not happen when new plug in, the
> > > > sram_read_start would be old value which may incorrect.
> > > > If think that when plug in and plug out, it should disable DP and
> > > > then enable DP again.
> > > > If DRM core does not do this, I think we should modify DRM core
> > > > or
> > > > you should reconfig the whole DP when plug in, not only training.
> > > > 
> > > > Regards,
> > > > CK
> > > > 
> > > 
> > > Hi CK
> > > 
> > > When DP plug out, DRM core will call
> > > mtk_dp_bridge_atomic_disable().
> > > When DP plug in, DRM core will call mtk_dp_bridge_atomic_enable().
> > 
> > 
> > When DP plug in, DRM core will call mtk_dp_bridge_atomic_enable(),
> > and mtk_dp_bridge_atomic_enable would call mtk_dp_training().
> > So it's not necessary to call mtk_dp_training() in
> > mtk_dp_hpd_event_thread().
> > 
> > Regards,
> > CK
> > 
> 
> Hi CK.
> 
> This shows the current timings after the DP cable is plugged in,
> as well as the modified timings.
> 
> current timings:		Fix timings:
> 
> mtk_dp_hpd_event_thread()	mtk_dp_hpd_event_thread()
> 				(including DP link training) 
> 	|				|
>        ...			       ...
> mtk_dp_bridge_mode_valid()	mtk_dp_bridge_mode_valid()
> 	|
>        ...			       ...
> mtk_dp_bridge_atomic_check()	mtk_dp_bridge_atomic_check()
> 	|
>        ...			       ...
> mtk_dp_bridge_atomic_enable()	mtk_dp_bridge_atomic_enable()
> (including DP link training)
> 
> 
> PS:
> 1. "..." represents ommited steps;
> 
> 2. `mtk_dp_bridge_mode_valid()` calculates the bandwidth using the
> current lane count and link rate, and then filters each mode to
> determine if it supports returning a status.
> 
> 3. In the `drm_display_mode_to_videomode(&crtc_state->adjusted_mode,
> &mtk_dp->info.vm);` function, within the `mtk_dp_bridge_atomic_check()`
> function, `adjusted_mode` sets the currently selected display mode for
> the DRM.
> 
> 4. DP link training tests the signal conditions of the link between
> DPTX and DPRX, and selects the lane count and link rate that meet
> the signal conditions.
> 
> 5. For example, the platform support DP 4lane 5.4G,
> but panel A support DP 2lane 5.4G.
> 
>    This is a time sequence:
> 
>    a).Plug in panel A. According to the platform, it can output 4K
>    60Hz.
>    b). Timing mode set 4K 60Hz(Including in mtk_dp_bridge_atomic_check
>    function).
>    c). Atomic enable(Based on panel A ability, training pass 2lane
>    5.4G).
>    d). Finally, due to 2lane 5.4G bandwidth limitation, the platform
>    cannot output 4K 60Hz, resulting in a black sreen.
> 
>    If apply this patch.
> 
>    a). Plug in panel A.
>    b). Training pass 2lane 5.4G
>    c). Timing mode set 2K 60Hz(Based on the 2lane 5.4G bandwidth limit
>    and including in mtk_dp_bridge_atomic_check function).
>    d). Atomic enable for output screen.

The original title does not show exactly what this patch do.
This patch does not only adjust bandwidth limit, it also fix some bugs.
I prefer the title to be "Move DP training to hotplug thread"

Regards,
CK

> 
> Best Regards
> Liankun.
> 
> > > 
> > > If DP plug in, sram_read_start will be recalculate based on the
> > > lane
> > > count.
> > > 
> > > Regards
> > > Liankun.
> > > 
> > > > 
> > > > > 
> > > > > Signed-off-by: Liankun Yang <liankun.yang at mediatek.com>
> > > > > ---
> > > > > ---
> > > > >  drivers/gpu/drm/mediatek/mtk_dp.c | 20 ++++++++++++++++++++
> > > > >  1 file changed, 20 insertions(+)
> > > > > 
> > > > > diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c
> > > > > b/drivers/gpu/drm/mediatek/mtk_dp.c
> > > > > index bef6eeb30d3e..0ba2c208811c 100644
> > > > > --- a/drivers/gpu/drm/mediatek/mtk_dp.c
> > > > > +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
> > > > > @@ -1976,6 +1976,7 @@ static irqreturn_t
> > > > > mtk_dp_hpd_event_thread(int hpd, void *dev)
> > > > >  	struct mtk_dp *mtk_dp = dev;
> > > > >  	unsigned long flags;
> > > > >  	u32 status;
> > > > > +	int ret;
> > > > >  
> > > > >  	if (mtk_dp->need_debounce && mtk_dp-
> > > > > > train_info.cable_plugged_in)
> > > > > 
> > > > >  		msleep(100);
> > > > > @@ -1994,9 +1995,28 @@ static irqreturn_t
> > > > > mtk_dp_hpd_event_thread(int hpd, void *dev)
> > > > >  			memset(&mtk_dp->info.audio_cur_cfg, 0,
> > > > >  			       sizeof(mtk_dp-
> > > > > > info.audio_cur_cfg));
> > > > >  
> > > > > +			mtk_dp->enabled = false;
> > > > > +			/* power off aux */
> > > > > +			mtk_dp_update_bits(mtk_dp,
> > > > > MTK_DP_TOP_PWR_STATE,
> > > > > +					   DP_PWR_STATE_BANDGAP
> > > > > _TPLL,
> > > > > +					   DP_PWR_STATE_MASK);
> > > > > +
> > > > >  			mtk_dp->need_debounce = false;
> > > > >  			mod_timer(&mtk_dp->debounce_timer,
> > > > >  				  jiffies +
> > > > > msecs_to_jiffies(100) - 1);
> > > > > +		} else {
> > > > > +			mtk_dp_aux_panel_poweron(mtk_dp, true);
> > > > > +
> > > > > +			ret =
> > > > > mtk_dp_parse_capabilities(mtk_dp);
> > > > > +			if (ret)
> > > > > +				drm_err(mtk_dp->drm_dev, "Can't
> > > > > parse
> > > > > capabilities\n");
> > > > > +
> > > > > +			/* Training */
> > > > > +			ret = mtk_dp_training(mtk_dp);
> > > > > +			if (ret)
> > > > > +				drm_err(mtk_dp->drm_dev,
> > > > > "Training
> > > > > failed, %d\n", ret);
> > > > > +
> > > > > +			mtk_dp->enabled = true;
> > > > >  		}
> > > > >  	}
> > > > >  
> > > > 
> > > > 
> > 
> > 


From royluo at google.com  Wed Dec 17 17:34:37 2025
From: royluo at google.com (Roy Luo)
Date: Wed, 17 Dec 2025 17:34:37 -0800
Subject: [PATCH v9 2/2] usb: dwc3: Add Google Tensor SoC DWC3 glue driver
In-Reply-To: <CAD=FV=U63F-wxwKDo9be6_X2P2zp6aTBjNghZRbXX1rn4jFNyg@mail.gmail.com>
References: <20251205-controller-v9-0-9f158b18f979@google.com>
 <20251205-controller-v9-2-9f158b18f979@google.com> <2025120553-suffrage-divisive-5890@gregkh>
 <CA+zupgzL7v5MZDpxKDQQCqAZaqTdHbiG9-xTr+8RnigMFZJ_7Q@mail.gmail.com>
 <2025121728-reliably-crabgrass-2601@gregkh> <CA+zupgxZCyNonfNPbGnFymGGOQuaWR1TsL+hujTbH4DEcfEt9Q@mail.gmail.com>
 <CAD=FV=U63F-wxwKDo9be6_X2P2zp6aTBjNghZRbXX1rn4jFNyg@mail.gmail.com>
Message-ID: <CA+zupgyG4Nov0=jihSApp_3_0hy6YNZMkfOp6Q4-zmERFm10Ag@mail.gmail.com>

On Wed, Dec 17, 2025 at 12:14?PM Doug Anderson <dianders at google.com> wrote:
>
> Hi,
>
> On Wed, Dec 17, 2025 at 11:18?AM Roy Luo <royluo at google.com> wrote:
> >
> > On Wed, Dec 17, 2025 at 5:24?AM Greg Kroah-Hartman
> > <gregkh at linuxfoundation.org> wrote:
> > >
> > > On Thu, Dec 04, 2025 at 11:14:39PM -0800, Roy Luo wrote:
> > > > On Thu, Dec 4, 2025 at 10:05?PM Greg Kroah-Hartman
> > > > <gregkh at linuxfoundation.org> wrote:
> > > > >
> > > > > On Fri, Dec 05, 2025 at 02:26:38AM +0000, Roy Luo wrote:
> > > > > > +config USB_DWC3_GOOGLE
> > > > > > +     tristate "Google Platform"
> > > > > > +     depends on ARCH_GOOGLE || COMPILE_TEST
> > > > >
> > > > > There is no ARCH_GOOGLE in the tree now, so how is this supposed to
> > > > > work?  Shouldn't tools that check for "invalid config options" trigger
> > > > > on this?
> > > > >
> > > > > thanks,
> > > > >
> > > > > greg k-h
> > > >
> > > > Hi Greg,
> > > >
> > > > The menuconfig looks like the following and it doesn't complain:
> > > > | Symbol: ARCH_GOOGLE [=ARCH_GOOGLE]
> > > > | Type  : unknown
> > > > |
> > > > | Symbol: PHY_GOOGLE_USB [=y]
> > > > | Type  : tristate
> > > > | Defined at drivers/phy/Kconfig:104
> > > > |     Prompt: Google Tensor SoC USB PHY driver
> > > > |     Depends on: ARCH_GOOGLE || COMPILE_TEST [=y]
> > > >
> > > > According to Kconfig documentation [1], the unknown symbol
> > > > would simply be evaluated as an "n", which is what we want.
> > > > "Convert the symbol into an expression. Boolean and tristate
> > > > symbols are simply converted into the respective expression
> > > > values. All other symbol types result in ?n?."
> > > >
> > > > In a different Kconfig documentation, an environment variable
> > > > "KCONFIG_WARN_UNKNOWN_SYMBOLS" is there to detect
> > > > undefined symbols in the "config input", but I can't find one that
> > > > catches undefined symbols in the Kconfig tree itself.
> > > >
> > > > That is, the tool seems to allow this.
> > > > However, if this turns out to be a major problem. I think we
> > > > can either:
> > > > - Remove ARCH_GOOGLE and leave COMPILE_TEST as
> > > >   the only dependency. Then add ARCH_GOOGLE back
> > > >   later once it's in the tree.
> > >
> > > Please do this.  I do not want to take patches that purposfully add
> > > dependencies on config options that might, or might not, appear in the
> > > future.  Please just remove all of the dependancies for now, as they are
> > > not needed, right?
> > >
> > > thanks,
> > >
> > > greg k-h
> >
> > Greg,
> >
> > Yes, we can remove ARCH_GOOGLE for now.
> > To clarify, we're not removing all of the dependencies, we still want
> > to keep COMPILE_TEST for build tests, right?
> > Please let me know if you think otherwise.
>
> I think you'd just remove all of them. Normally COMPILE_TEST just
> allows folks to compile stuff even when they don't want the ARCH. We
> can can add ARCH_GOOGLE back in later once the config exists.
>
> -Doug

Doug,

Thanks for chiming in. I'm hesitant to remove COMPILE_TEST
because Greg specifically requested its inclusion in v7 [1].
Also it seems beneficial to get some build coverage before
ARCH_GOOGLE is officially added to the tree.
Greg, could you clarify?

[1] https://lore.kernel.org/linux-usb/2025112144-claw-recolor-49c3 at gregkh/

Thanks,
Roy


From rostedt at kernel.org  Wed Dec 17 17:39:09 2025
From: rostedt at kernel.org (Steven Rostedt)
Date: Wed, 17 Dec 2025 20:39:09 -0500
Subject: [PATCHv5 bpf-next 4/9] ftrace: Add update_ftrace_direct_add
 function
In-Reply-To: <20251215211402.353056-5-jolsa@kernel.org>
References: <20251215211402.353056-1-jolsa@kernel.org>
	<20251215211402.353056-5-jolsa@kernel.org>
Message-ID: <20251217203909.474ae959@robin>

On Mon, 15 Dec 2025 22:13:57 +0100
Jiri Olsa <jolsa at kernel.org> wrote:


> +/**
> + * hash_add - adds two struct ftrace_hash and returns the result
> + * @a: struct ftrace_hash object
> + * @b: struct ftrace_hash object
> + *
> + * Returns struct ftrace_hash object on success, NULL on error.
> + */
> +static struct ftrace_hash *hash_add(struct ftrace_hash *a, struct ftrace_hash *b)
> +{
> +	struct ftrace_func_entry *entry;
> +	struct ftrace_hash *add;
> +	int size, i;
> +
> +	size = hash_count(a) + hash_count(b);
> +	if (size > 32)
> +		size = 32;
> +
> +	add = alloc_and_copy_ftrace_hash(fls(size), a);
> +	if (!add)
> +		goto error;

You can just return NULL here, as add is NULL.

> +
> +	size = 1 << b->size_bits;
> +	for (i = 0; i < size; i++) {
> +		hlist_for_each_entry(entry, &b->buckets[i], hlist) {
> +			if (add_hash_entry_direct(add, entry->ip, entry->direct) == NULL)
> +				goto error;

Could remove the error and have:

			if (add_hash_entry_direct(add, entry->ip, entry->direct) == NULL) {
				free_ftrace_hash(add);
				return NULL;
			}


> +		}
> +	}
> +	return add;
> +
> + error:
> +	free_ftrace_hash(add);
> +	return NULL;
> +}
> +

Non static functions require a kerneldoc header.

> +int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash)
> +{
> +	struct ftrace_hash *old_direct_functions = NULL, *new_direct_functions;
> +	struct ftrace_hash *old_filter_hash, *new_filter_hash = NULL;

BTW, I prefer to not double up on variables. That is to have each on
their own lines. Makes it easier to read for me.

> +	struct ftrace_func_entry *entry;
> +	int i, size, err = -EINVAL;

Even here.

> +	bool reg;
> +
> +	if (!hash_count(hash))
> +		return -EINVAL;
> +
> +	mutex_lock(&direct_mutex);
> +
> +	/* Make sure requested entries are not already registered. */
> +	size = 1 << hash->size_bits;
> +	for (i = 0; i < size; i++) {

If you want, you can remove the i declaration and use for(int i = 0; ... here.

> +		hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
> +			if (__ftrace_lookup_ip(direct_functions, entry->ip))
> +				goto out_unlock;
> +		}
> +	}
> +
> +	old_filter_hash = ops->func_hash ? ops->func_hash->filter_hash : NULL;
> +
> +	/* If there's nothing in filter_hash we need to register the ops. */
> +	reg = hash_count(old_filter_hash) == 0;
> +	if (reg) {
> +		if (ops->func || ops->trampoline)
> +			goto out_unlock;
> +		if (ops->flags & FTRACE_OPS_FL_ENABLED)
> +			goto out_unlock;
> +	}
> +
> +	err = -ENOMEM;
> +	new_filter_hash = hash_add(old_filter_hash, hash);
> +	if (!new_filter_hash)
> +		goto out_unlock;
> +
> +	new_direct_functions = hash_add(direct_functions, hash);
> +	if (!new_direct_functions)
> +		goto out_unlock;
> +
> +	old_direct_functions = direct_functions;
> +	rcu_assign_pointer(direct_functions, new_direct_functions);
> +
> +	if (reg) {
> +		ops->func = call_direct_funcs;
> +		ops->flags |= MULTI_FLAGS;
> +		ops->trampoline = FTRACE_REGS_ADDR;
> +		ops->local_hash.filter_hash = new_filter_hash;
> +
> +		err = register_ftrace_function_nolock(ops);
> +		if (err) {
> +			/* restore old filter on error */
> +			ops->local_hash.filter_hash = old_filter_hash;
> +
> +			/* cleanup for possible another register call */
> +			ops->func = NULL;
> +			ops->trampoline = 0;
> +		} else {
> +			new_filter_hash = old_filter_hash;
> +		}
> +	} else {
> +		err = ftrace_update_ops(ops, new_filter_hash, EMPTY_HASH);
> +		/*
> +		 * new_filter_hash is dup-ed, so we need to release it anyway,
> +		 * old_filter_hash either stays on error or is already released
> +		 */
> +	}
> +
> +	if (err) {
> +		/* reset direct_functions and free the new one */
> +		rcu_assign_pointer(direct_functions, old_direct_functions);
> +		old_direct_functions = new_direct_functions;
> +	}
> +
> + out_unlock:
> +	mutex_unlock(&direct_mutex);
> +
> +	if (old_direct_functions && old_direct_functions != EMPTY_HASH)
> +		call_rcu_tasks(&old_direct_functions->rcu, register_ftrace_direct_cb);
> +	if (new_filter_hash)

free_ftrace_hash() checks for NULL, so you don't need the above if statement.

> +		free_ftrace_hash(new_filter_hash);
> +
> +	return err;

-- Steve

> +}
> +
>  #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
>  
>  /**



From rostedt at kernel.org  Wed Dec 17 17:48:14 2025
From: rostedt at kernel.org (Steven Rostedt)
Date: Wed, 17 Dec 2025 20:48:14 -0500
Subject: [PATCHv5 bpf-next 5/9] ftrace: Add update_ftrace_direct_del
 function
In-Reply-To: <20251215211402.353056-6-jolsa@kernel.org>
References: <20251215211402.353056-1-jolsa@kernel.org>
	<20251215211402.353056-6-jolsa@kernel.org>
Message-ID: <20251217204814.38756224@robin>

On Mon, 15 Dec 2025 22:13:58 +0100
Jiri Olsa <jolsa at kernel.org> wrote:
> +/**
> + * hash_sub - substracts @b from @a and returns the result
> + * @a: struct ftrace_hash object
> + * @b: struct ftrace_hash object
> + *
> + * Returns struct ftrace_hash object on success, NULL on error.
> + */
> +static struct ftrace_hash *hash_sub(struct ftrace_hash *a, struct ftrace_hash *b)
> +{
> +	struct ftrace_func_entry *entry, *del;
> +	struct ftrace_hash *sub;
> +	int size, i;
> +
> +	sub = alloc_and_copy_ftrace_hash(a->size_bits, a);
> +	if (!sub)
> +		goto error;

Again, this can be just return NULL;

> +
> +	size = 1 << b->size_bits;
> +	for (i = 0; i < size; i++) {

You can make this for (int i = 0; ...) too.

> +		hlist_for_each_entry(entry, &b->buckets[i], hlist) {
> +			del = __ftrace_lookup_ip(sub, entry->ip);
> +			if (WARN_ON_ONCE(!del))
> +				goto error;

And you can remove the error label here too:

			if (WARN_ON_ONCE(!del)) {
				free_ftrace_hash(sub);
				return NULL;
			}


> +			remove_hash_entry(sub, del);
> +			kfree(del);
> +		}
> +	}
> +	return sub;
> +
> + error:
> +	free_ftrace_hash(sub);
> +	return NULL;
> +}
> +
> +int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash)
> +{
> +	struct ftrace_hash *old_direct_functions = NULL, *new_direct_functions;
> +	struct ftrace_hash *old_filter_hash, *new_filter_hash = NULL;
> +	struct ftrace_func_entry *del, *entry;

One variable per line.

> +	unsigned long size, i;
> +	int err = -EINVAL;
> +
> +	if (!hash_count(hash))
> +		return -EINVAL;
> +	if (check_direct_multi(ops))
> +		return -EINVAL;
> +	if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
> +		return -EINVAL;
> +	if (direct_functions == EMPTY_HASH)
> +		return -EINVAL;
> +
> +	mutex_lock(&direct_mutex);
> +
> +	old_filter_hash = ops->func_hash ? ops->func_hash->filter_hash : NULL;
> +
> +	if (!hash_count(old_filter_hash))
> +		goto out_unlock;
> +
> +	/* Make sure requested entries are already registered. */
> +	size = 1 << hash->size_bits;
> +	for (i = 0; i < size; i++) {

	for (int i = 0; ...) 

-- Steve

> +		hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
> +			del = __ftrace_lookup_ip(direct_functions, entry->ip);
> +			if (!del || del->direct != entry->direct)
> +				goto out_unlock;
> +		}
> +	}
> +
> +	err = -ENOMEM;
> +	new_filter_hash = hash_sub(old_filter_hash, hash);
> +	if (!new_filter_hash)
> +		goto out_unlock;
> +
> +	new_direct_functions = hash_sub(direct_functions, hash);
> +	if (!new_direct_functions)
> +		goto out_unlock;
> +
> +	/* If there's nothing left, we need to unregister the ops. */
> +	if (ftrace_hash_empty(new_filter_hash)) {
> +		err = unregister_ftrace_function(ops);
> +		if (!err) {
> +			/* cleanup for possible another register call */
> +			ops->func = NULL;
> +			ops->trampoline = 0;
> +			ftrace_free_filter(ops);
> +			ops->func_hash->filter_hash = NULL;
> +		}
> +	} else {
> +		err = ftrace_update_ops(ops, new_filter_hash, EMPTY_HASH);
> +		/*
> +		 * new_filter_hash is dup-ed, so we need to release it anyway,
> +		 * old_filter_hash either stays on error or is already released
> +		 */
> +	}
> +
> +	if (err) {
> +		/* free the new_direct_functions */
> +		old_direct_functions = new_direct_functions;
> +	} else {
> +		rcu_assign_pointer(direct_functions, new_direct_functions);
> +	}
> +
> + out_unlock:
> +	mutex_unlock(&direct_mutex);
> +
> +	if (old_direct_functions && old_direct_functions != EMPTY_HASH)
> +		call_rcu_tasks(&old_direct_functions->rcu, register_ftrace_direct_cb);
> +	free_ftrace_hash(new_filter_hash);
> +
> +	return err;
> +}
> +
>  #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
>  
>  /**



From puranjay at kernel.org  Wed Dec 17 18:52:32 2025
From: puranjay at kernel.org (Puranjay Mohan)
Date: Thu, 18 Dec 2025 02:52:32 +0000
Subject: [PATCH bpf-next v2 0/2] bpf: Optimize recursion detection on arm64
In-Reply-To: <20251217233608.2374187-1-puranjay@kernel.org>
References: <20251217233608.2374187-1-puranjay@kernel.org>
Message-ID: <CANk7y0hG8wQc2krKbMz1GUPsWdNWa353EzdAykv0nrE4ot4imA@mail.gmail.com>

On Wed, Dec 17, 2025 at 11:36?PM Puranjay Mohan <puranjay at kernel.org> wrote:
>
> V1: https://lore.kernel.org/all/20251217162830.2597286-1-puranjay at kernel.org/
> Changes in V1->V2:
> - Patch 2:
>         - Put preempt_enable()/disable() around RMW accesses to mitigate
>           race conditions. Because on CONFIG_PREEMPT_RCU and sleepable
>           bpf programs, preemption can cause no prog to execute.
>
> BPF programs detect recursion using a per-CPU 'active' flag in struct
> bpf_prog. The trampoline currently sets/clears this flag with atomic
> operations.
>
> On some arm64 platforms (e.g., Neoverse V2 with LSE), per-CPU atomic
> operations are relatively slow. Unlike x86_64 - where per-CPU updates
> can avoid cross-core atomicity, arm64 LSE atomics are always atomic
> across all cores, which is unnecessary overhead for strictly per-CPU
> state.
>
> This patch removes atomics from the recursion detection path on arm64.
>
> It was discovered in [1] that per-CPU atomics that don't return a value
> were extremely slow on some arm64 platforms, Catalin added a fix in
> commit 535fdfc5a228 ("arm64: Use load LSE atomics for the non-return
> per-CPU atomic operations") to solve this issue, but it seems to have
> caused a regression on the fentry benchmark.
>
> Using the fentry benchmark from the bpf selftests shows the following:
>
>   ./tools/testing/selftests/bpf/bench trig-fentry
>
>  +---------------------------------------------+------------------------+
>  |               Configuration                 | Total Operations (M/s) |
>  +---------------------------------------------+------------------------+
>  | bpf-next/master with Catalin?s fix reverted |         51.862         |
>  |---------------------------------------------|------------------------|
>  | bpf-next/master                             |         43.067         |
>  | bpf-next/master with this change            |         53.856         |
>  +---------------------------------------------+------------------------+
>
> All benchmarks were run on a KVM based vm with Neoverse-V2 and 8 cpus.
>


Here is some more data about other attach types:

+-----------------+-----------+-----------+----------+
|     Metric      |  Before   |   After   | % Diff   |
+-----------------+-----------+-----------+----------+
| fentry          |   43.149  |   53.948  | +25.03%  |
| fentry.s        |   41.831  |   50.937  | +21.76%  |
| rawtp           |   50.834  |   58.731  | +15.53%  |
| fexit           |   31.118  |   34.360  | +10.42%  |
| tp              |   39.536  |   41.632  |  +5.30%  |
| syscall-count   |    8.053  |    8.305  |  +3.13%  |
| fmodret         |   33.940  |   34.769  |  +2.44%  |
| kprobe          |    9.970  |    9.998  |  +0.28%  |
| usermode-count  |  224.886  |  224.839  |  -0.02%  |
| kernel-count    |  154.229  |  153.043  |  -0.77%  |
+-----------------+-----------+-----------+----------+


From manikandan.m at microchip.com  Wed Dec 17 20:05:19 2025
From: manikandan.m at microchip.com (Manikandan Muralidharan)
Date: Thu, 18 Dec 2025 09:35:19 +0530
Subject: [PATCH v2 1/3] dt-bindings: mfd: atmel,hlcdc: Add sama7d65 compatible string
Message-ID: <20251218040521.463937-1-manikandan.m@microchip.com>

Add LCD compatible string for sama7d65.

Signed-off-by: Manikandan Muralidharan <manikandan.m at microchip.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 Documentation/devicetree/bindings/mfd/atmel,hlcdc.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/mfd/atmel,hlcdc.yaml b/Documentation/devicetree/bindings/mfd/atmel,hlcdc.yaml
index 4aa36903e755..dfee8707bac2 100644
--- a/Documentation/devicetree/bindings/mfd/atmel,hlcdc.yaml
+++ b/Documentation/devicetree/bindings/mfd/atmel,hlcdc.yaml
@@ -25,6 +25,7 @@ properties:
       - atmel,sama5d4-hlcdc
       - microchip,sam9x60-hlcdc
       - microchip,sam9x75-xlcdc
+      - microchip,sama7d65-xlcdc
 
   reg:
     maxItems: 1

base-commit: e8c28e16c3ebd142938aee296032c6b802a5a1d4
-- 
2.25.1



From manikandan.m at microchip.com  Wed Dec 17 20:05:20 2025
From: manikandan.m at microchip.com (Manikandan Muralidharan)
Date: Thu, 18 Dec 2025 09:35:20 +0530
Subject: [PATCH v2 2/3] mfd: atmel-hlcdc: Add compatible for sama7d65 XLCD controller
In-Reply-To: <20251218040521.463937-1-manikandan.m@microchip.com>
References: <20251218040521.463937-1-manikandan.m@microchip.com>
Message-ID: <20251218040521.463937-2-manikandan.m@microchip.com>

From: Ryan Wanner <Ryan.Wanner at microchip.com>

Add compatible for sama7d65 XLCD controller.

Signed-off-by: Ryan Wanner <Ryan.Wanner at microchip.com>
Signed-off-by: Manikandan Muralidharan <manikandan.m at microchip.com>
---
changes in v2:
- isolate this change into a dedicated patch
---
 drivers/mfd/atmel-hlcdc.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mfd/atmel-hlcdc.c b/drivers/mfd/atmel-hlcdc.c
index 4c4e35d404f3..c3f3d39bf584 100644
--- a/drivers/mfd/atmel-hlcdc.c
+++ b/drivers/mfd/atmel-hlcdc.c
@@ -140,6 +140,7 @@ static const struct of_device_id atmel_hlcdc_match[] = {
 	{ .compatible = "atmel,sama5d4-hlcdc" },
 	{ .compatible = "microchip,sam9x60-hlcdc" },
 	{ .compatible = "microchip,sam9x75-xlcdc" },
+	{ .compatible = "microchip,sama7d65-xlcdc" },
 	{ /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, atmel_hlcdc_match);
-- 
2.25.1



From manikandan.m at microchip.com  Wed Dec 17 20:05:21 2025
From: manikandan.m at microchip.com (Manikandan Muralidharan)
Date: Thu, 18 Dec 2025 09:35:21 +0530
Subject: [PATCH v2 3/3] drm: atmel-hlcdc: add LCD controller layer definition for sama7d65
In-Reply-To: <20251218040521.463937-1-manikandan.m@microchip.com>
References: <20251218040521.463937-1-manikandan.m@microchip.com>
Message-ID: <20251218040521.463937-3-manikandan.m@microchip.com>

From: Ryan Wanner <Ryan.Wanner at microchip.com>

Add the LCD controller layer definition and atmel_hlcdc_of_match
entry for sama7d65.

Signed-off-by: Ryan Wanner <Ryan.Wanner at microchip.com>
Signed-off-by: Manikandan Muralidharan <manikandan.m at microchip.com>
---
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | 81 ++++++++++++++++++++
 1 file changed, 81 insertions(+)

diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
index dd70894c8f38..3d57a7182c98 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
@@ -566,6 +566,83 @@ static const struct atmel_hlcdc_dc_desc atmel_xlcdc_dc_sam9x75 = {
 	.ops = &atmel_xlcdc_ops,
 };
 
+static const struct atmel_hlcdc_layer_desc atmel_xlcdc_sama7d65_layers[] = {
+	{
+		.name = "base",
+		.formats = &atmel_hlcdc_plane_rgb_formats,
+		.regs_offset = 0x60,
+		.id = 0,
+		.type = ATMEL_HLCDC_BASE_LAYER,
+		.cfgs_offset = 0x1c,
+		.layout = {
+			.xstride = { 2 },
+			.default_color = 3,
+			.general_config = 4,
+			.disc_pos = 5,
+			.disc_size = 6,
+		},
+		.clut_offset = 0x700,
+	},
+	{
+		.name = "overlay1",
+		.formats = &atmel_hlcdc_plane_rgb_formats,
+		.regs_offset = 0x160,
+		.id = 1,
+		.type = ATMEL_HLCDC_OVERLAY_LAYER,
+		.cfgs_offset = 0x1c,
+		.layout = {
+			.pos = 2,
+			.size = 3,
+			.xstride = { 4 },
+			.pstride = { 5 },
+			.default_color = 6,
+			.chroma_key = 7,
+			.chroma_key_mask = 8,
+			.general_config = 9,
+		},
+		.clut_offset = 0xb00,
+	},
+	{
+		.name = "high-end-overlay",
+		.formats = &atmel_hlcdc_plane_rgb_and_yuv_formats,
+		.regs_offset = 0x360,
+		.id = 2,
+		.type = ATMEL_HLCDC_OVERLAY_LAYER,
+		.cfgs_offset = 0x30,
+		.layout = {
+			.pos = 2,
+			.size = 3,
+			.memsize = 4,
+			.xstride = { 5, 7 },
+			.pstride = { 6, 8 },
+			.default_color = 9,
+			.chroma_key = 10,
+			.chroma_key_mask = 11,
+			.general_config = 12,
+			.csc = 16,
+			.scaler_config = 23,
+			.vxs_config = 30,
+			.hxs_config = 31,
+		},
+		.clut_offset = 0x1300,
+	},
+};
+
+static const struct atmel_hlcdc_dc_desc atmel_xlcdc_dc_sama7d65 = {
+	.min_width = 0,
+	.min_height = 0,
+	.max_width = 2048,
+	.max_height = 2048,
+	.max_spw = 0x3ff,
+	.max_vpw = 0x3ff,
+	.max_hpw = 0x3ff,
+	.fixed_clksrc = true,
+	.is_xlcdc = true,
+	.nlayers = ARRAY_SIZE(atmel_xlcdc_sama7d65_layers),
+	.layers = atmel_xlcdc_sama7d65_layers,
+	.ops = &atmel_xlcdc_ops,
+};
+
 static const struct of_device_id atmel_hlcdc_of_match[] = {
 	{
 		.compatible = "atmel,at91sam9n12-hlcdc",
@@ -595,6 +672,10 @@ static const struct of_device_id atmel_hlcdc_of_match[] = {
 		.compatible = "microchip,sam9x75-xlcdc",
 		.data = &atmel_xlcdc_dc_sam9x75,
 	},
+	{
+		.compatible = "microchip,sama7d65-xlcdc",
+		.data = &atmel_xlcdc_dc_sama7d65,
+	},
 	{ /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, atmel_hlcdc_of_match);
-- 
2.25.1



From peng.fan at oss.nxp.com  Wed Dec 17 21:17:34 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Thu, 18 Dec 2025 13:17:34 +0800
Subject: [PATCH v5 0/5] remoteproc: imx_rproc: Support i.MX95
Message-ID: <20251218-imx95-rproc-2025-12-18-v5-0-b56a27d4158f@nxp.com>

This patchset is pick up a previous patchset [1] with rebased on
next-20251030, and some changes applied.
 - Add runtime ops to separate cpu ops and lmm ops
 - added more comments
 - moved some check imx_sm_rproc_detect_mode() from imx_rproc_sm_prepare().

No changes to the dt-binding patch, so R-b/A-b are kept.
More info could be found in commit message of each patch and below.

[1]https://lore.kernel.org/linux-remoteproc/20250821-imx95-rproc-1-v5-0-e93191dfac51 at nxp.com/

i.MX95 features a Cortex-M33 core, six Cortex-A55 cores, and
one Cortex-M7 core. The System Control Management Interface(SCMI)
firmware runs on the M33 core. The i.MX95 SCMI firmware named System
Manager(SM) includes vendor extension protocols, Logical Machine
Management(LMM) protocol and CPU protocol and etc.

There are three cases for M7:
(1) M7 in a separate Logical Machine(LM) that Linux couldn't control it.
(2) M7 in a separate Logical Machine that Linux could control it using
    LMM protocol
(3) M7 runs in same Logical Machine as A55, so Linux could control it
    using CPU protocol

In patch 3, Use LMM and CPU protocol to manage M7. More info could be
found in the patch commit log
    Current setup relies on pre-Linux software(U-Boot) to do
M7 TCM ECC initialization. In future, we could add the support in Linux

Patchset was tested with below boot images when the patchset based on next-20251030:
imx-boot-variant-rpmsg-imx95-19x19-lpddr5-evk-sd.bin-flash_lpboot_sm_a55 (Use LMM protocol)
imx-boot-variant-alt-imx95-19x19-lpddr5-evk-sd.bin-flash_alt (Use CPU protocol)
imx-boot-imx95-19x19-lpddr5-evk-sd.bin-flash_all (M7 not under A55 control)

Also tested i.MX8MP/8ULP-EVK.

Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
Changes in v5:
- Add R-b from Daniel for patch 4
- Patch 4, per Mathieu's comments:
  Move imx_rproc_ops_sm_lmm and imx_rproc_ops_sm_cpu to bottom of the file.
  Set IMX_RPROC_FLAGS_SM_LMM_AVAIL when scmi_imx_lmm_operation(shutdown)
  pass or m7 is started before Linux.
- Link to v4: https://lore.kernel.org/r/20251216-imx95-rproc-2025-12-15-v4-0-bf1064ea8daf at nxp.com

Changes in V4:
- Rebased to 6.19-rc1 to resolve conflicts.
- Address Frank's comment patch 4 regarding "if (ret != 0)" -> "if (ret)"
- Link to v3: https://lore.kernel.org/linux-remoteproc/20251122-imx95-rproc-2025-11-20-v3-0-9ae6ee619a78 at nxp.com/#t

Changes in v3:
- Add R-b for patch 2,3,5
- Patch 4:
  Rename imx_rproc_ops_sm to imx_rproc_ops_sm_lmm.
  Add more comments in code
  Simplify if check in imx_rproc_sm_lmm_prepare()
  Update commit log
  Use dev_err for failure path
- Link to v2: https://lore.kernel.org/linux-remoteproc/20251031-imx95-rproc-2025-10-31-v2-0-758b2e547a55 at nxp.com/T/#t

Changes in v2:
- Patch 2: Change to const pointer for ops, update commit log and add R-b from Frank
- Patch 3: New patch, introduce prepare ops
- Patch 4: Rename imx_rproc_sm_prepare to imx_rproc_sm_lmm_prepare
           drop IMX_RPROC_FLAGS_SM_CPU_OP and IMX_RPROC_FLAGS_SM_LMM_OP
           Add a bool for dcfg->lmid and info->lmid check.
           Provide separate plat ops for lmm and cpu setup.
           Move LM permission check to a separate function.
- Patch 5: Drop macro IMX95_M7_CPUID and IMX95_M7_LMID
- Link to v1: https://lore.kernel.org/r/20251028-imx95-rproc-2025-10-28-v1-0-ce9e7db9edcb at nxp.com

---
Peng Fan (5):
      dt-bindings: remoteproc: fsl,imx-rproc: Add support for i.MX95
      remoteproc: imx_rproc: Add runtime ops copy to support dynamic behavior
      remoteproc: imx_rproc: Introduce prepare ops for imx_rproc_dcfg
      remoteproc: imx_rproc: Add support for System Manager API
      remoteproc: imx_rproc: Add support for i.MX95

 .../bindings/remoteproc/fsl,imx-rproc.yaml         |   1 +
 drivers/remoteproc/Kconfig                         |   2 +
 drivers/remoteproc/imx_rproc.c                     | 250 +++++++++++++++++++--
 drivers/remoteproc/imx_rproc.h                     |   4 +
 4 files changed, 244 insertions(+), 13 deletions(-)
---
base-commit: 12b95d29eb979e5c4f4f31bb05817bc935c52050
change-id: 20251218-imx95-rproc-2025-12-18-644d2e105017

Best regards,
-- 
Peng Fan <peng.fan at nxp.com>



From peng.fan at oss.nxp.com  Wed Dec 17 21:17:35 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Thu, 18 Dec 2025 13:17:35 +0800
Subject: [PATCH v5 1/5] dt-bindings: remoteproc: fsl,imx-rproc: Add support
 for i.MX95
In-Reply-To: <20251218-imx95-rproc-2025-12-18-v5-0-b56a27d4158f@nxp.com>
References: <20251218-imx95-rproc-2025-12-18-v5-0-b56a27d4158f@nxp.com>
Message-ID: <20251218-imx95-rproc-2025-12-18-v5-1-b56a27d4158f@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

Add compatible string for the Cortex-M7 core in i.MX95

Reviewed-by: Frank Li <Frank.Li at nxp.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
index 57d75acb0b5e52ca49d1361176fdebc18a0bf7a2..ce8ec0119469c8fc0979a192b6e3d3a03108d7d2 100644
--- a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
+++ b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
@@ -28,6 +28,7 @@ properties:
       - fsl,imx8qxp-cm4
       - fsl,imx8ulp-cm33
       - fsl,imx93-cm33
+      - fsl,imx95-cm7
 
   clocks:
     maxItems: 1

-- 
2.37.1



From peng.fan at oss.nxp.com  Wed Dec 17 21:17:36 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Thu, 18 Dec 2025 13:17:36 +0800
Subject: [PATCH v5 2/5] remoteproc: imx_rproc: Add runtime ops copy to
 support dynamic behavior
In-Reply-To: <20251218-imx95-rproc-2025-12-18-v5-0-b56a27d4158f@nxp.com>
References: <20251218-imx95-rproc-2025-12-18-v5-0-b56a27d4158f@nxp.com>
Message-ID: <20251218-imx95-rproc-2025-12-18-v5-2-b56a27d4158f@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

Structure imx_rproc_dcfg contains a const pointer to imx_rproc_plat_ops,
which defines the start/stop/detect_mode operations for a remote processor.
To preserve the const correctness of the static configuration while
allowing runtime modification of ops behavior, introduce a new
imx_rproc_plat_ops member in struct imx_rproc named `ops`.

During initialization, dcfg->ops is assigned to priv->ops.
Enable the driver to safely override ops at runtime without affecting the
original const configuration.

Improve flexibility for platforms that require dynamic operation switching
(e.g. i.MX95 Logical Machine ops and CPU ops).

Reviewed-by: Frank Li <Frank.Li at nxp.com>
Reviewed-by: Daniel Baluta <daniel.baluta at nxp.com>
Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 drivers/remoteproc/imx_rproc.c | 27 +++++++++++++--------------
 1 file changed, 13 insertions(+), 14 deletions(-)

diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index 33f21ab24c921135319728ead3d24f1833ea1d64..78659c8fb84d95f3d258c21af76cefea1c82850e 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -116,6 +116,7 @@ struct imx_rproc {
 	u32				entry;		/* cpu start address */
 	u32				core_index;
 	struct dev_pm_domain_list	*pd_list;
+	const struct imx_rproc_plat_ops	*ops;
 };
 
 static const struct imx_rproc_att imx_rproc_att_imx93[] = {
@@ -315,7 +316,6 @@ static int imx_rproc_scu_api_start(struct rproc *rproc)
 static int imx_rproc_start(struct rproc *rproc)
 {
 	struct imx_rproc *priv = rproc->priv;
-	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
 	struct device *dev = priv->dev;
 	int ret;
 
@@ -323,10 +323,10 @@ static int imx_rproc_start(struct rproc *rproc)
 	if (ret)
 		return ret;
 
-	if (!dcfg->ops || !dcfg->ops->start)
+	if (!priv->ops || !priv->ops->start)
 		return -EOPNOTSUPP;
 
-	ret = dcfg->ops->start(rproc);
+	ret = priv->ops->start(rproc);
 	if (ret)
 		dev_err(dev, "Failed to enable remote core!\n");
 
@@ -372,14 +372,13 @@ static int imx_rproc_scu_api_stop(struct rproc *rproc)
 static int imx_rproc_stop(struct rproc *rproc)
 {
 	struct imx_rproc *priv = rproc->priv;
-	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
 	struct device *dev = priv->dev;
 	int ret;
 
-	if (!dcfg->ops || !dcfg->ops->stop)
+	if (!priv->ops || !priv->ops->stop)
 		return -EOPNOTSUPP;
 
-	ret = dcfg->ops->stop(rproc);
+	ret = priv->ops->stop(rproc);
 	if (ret)
 		dev_err(dev, "Failed to stop remote core\n");
 	else
@@ -584,12 +583,11 @@ static int imx_rproc_scu_api_detach(struct rproc *rproc)
 static int imx_rproc_detach(struct rproc *rproc)
 {
 	struct imx_rproc *priv = rproc->priv;
-	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
 
-	if (!dcfg->ops || !dcfg->ops->detach)
+	if (!priv->ops || !priv->ops->detach)
 		return -EOPNOTSUPP;
 
-	return dcfg->ops->detach(rproc);
+	return priv->ops->detach(rproc);
 }
 
 static struct resource_table *imx_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz)
@@ -979,18 +977,16 @@ static int imx_rproc_scu_api_detect_mode(struct rproc *rproc)
 
 static int imx_rproc_detect_mode(struct imx_rproc *priv)
 {
-	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
-
 	/*
 	 * To i.MX{7,8} ULP, Linux is under control of RTOS, no need
-	 * dcfg->ops or dcfg->ops->detect_mode, it is state RPROC_DETACHED.
+	 * priv->ops or priv->ops->detect_mode, it is state RPROC_DETACHED.
 	 */
-	if (!dcfg->ops || !dcfg->ops->detect_mode) {
+	if (!priv->ops || !priv->ops->detect_mode) {
 		priv->rproc->state = RPROC_DETACHED;
 		return 0;
 	}
 
-	return dcfg->ops->detect_mode(priv->rproc);
+	return priv->ops->detect_mode(priv->rproc);
 }
 
 static int imx_rproc_sys_off_handler(struct sys_off_data *data)
@@ -1040,6 +1036,9 @@ static int imx_rproc_probe(struct platform_device *pdev)
 	priv->dcfg = dcfg;
 	priv->dev = dev;
 
+	if (dcfg->ops)
+		priv->ops = dcfg->ops;
+
 	dev_set_drvdata(dev, rproc);
 	priv->workqueue = create_workqueue(dev_name(dev));
 	if (!priv->workqueue) {

-- 
2.37.1



From peng.fan at oss.nxp.com  Wed Dec 17 21:17:37 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Thu, 18 Dec 2025 13:17:37 +0800
Subject: [PATCH v5 3/5] remoteproc: imx_rproc: Introduce prepare ops for
 imx_rproc_dcfg
In-Reply-To: <20251218-imx95-rproc-2025-12-18-v5-0-b56a27d4158f@nxp.com>
References: <20251218-imx95-rproc-2025-12-18-v5-0-b56a27d4158f@nxp.com>
Message-ID: <20251218-imx95-rproc-2025-12-18-v5-3-b56a27d4158f@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

Allow each platform to provide its own prepare operations, preparing
for i.MX95 LMM and CPU ops support.

No functional changes.

Reviewed-by: Daniel Baluta <daniel.baluta at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 drivers/remoteproc/imx_rproc.c | 5 +++++
 drivers/remoteproc/imx_rproc.h | 1 +
 2 files changed, 6 insertions(+)

diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index 78659c8fb84d95f3d258c21af76cefea1c82850e..b0857a1a9660503ee7cd5473c06dacb5262286b8 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -527,6 +527,11 @@ static int imx_rproc_prepare(struct rproc *rproc)
 		rproc_coredump_add_segment(rproc, da, resource_size(&res));
 		rproc_add_carveout(rproc, mem);
 	}
+
+	if (priv->ops && priv->ops->prepare)
+		return priv->ops->prepare(rproc);
+
+	return 0;
 }
 
 static int imx_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h
index 1b2d9f4d6d19dcdc215be97f7e2ab3488281916a..37417568a0ade2ae4d6a4e3d0f139ea52b185254 100644
--- a/drivers/remoteproc/imx_rproc.h
+++ b/drivers/remoteproc/imx_rproc.h
@@ -24,6 +24,7 @@ struct imx_rproc_plat_ops {
 	int (*stop)(struct rproc *rproc);
 	int (*detach)(struct rproc *rproc);
 	int (*detect_mode)(struct rproc *rproc);
+	int (*prepare)(struct rproc *rproc);
 };
 
 struct imx_rproc_dcfg {

-- 
2.37.1



From peng.fan at oss.nxp.com  Wed Dec 17 21:17:38 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Thu, 18 Dec 2025 13:17:38 +0800
Subject: [PATCH v5 4/5] remoteproc: imx_rproc: Add support for System
 Manager API
In-Reply-To: <20251218-imx95-rproc-2025-12-18-v5-0-b56a27d4158f@nxp.com>
References: <20251218-imx95-rproc-2025-12-18-v5-0-b56a27d4158f@nxp.com>
Message-ID: <20251218-imx95-rproc-2025-12-18-v5-4-b56a27d4158f@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

i.MX95 features a Cortex-M33 core, six Cortex-A55 cores, and
one Cortex-M7 core. The System Control Management Interface(SCMI)
firmware runs on the M33 core. The i.MX95 SCMI firmware named System
Manager(SM) includes vendor extension protocols, Logical Machine
Management(LMM) protocol and CPU protocol and etc.

Depending on SM configuration, M7 can be used as follows:
 (1) M7 in a separate Logical Machine (LM) from A55 cores, that Linux
     can't control
 (2) M7 in a separate LM from A55 cores that Linux can control using LMM
     protocol.
 (3) M7 runs in same Logical Machine as A55 cores, so Linux can control it
     using CPU protocol

So extend the driver to using LMM and CPU protocol to manage the M7 core.
 - Compare linux LM ID(got using scmi_imx_lmm_info) and M7 LM ID(the ID
   is fixed as 1 in SM firmware if M7 is in a separate LM),
   if Linux LM ID equals M7 LM ID(linux and M7 in same LM), use CPU
   protocol to start/stop. Otherwise, use LMM protocol to start/stop.
   Whether using CPU or LMM protocol to start/stop, the M7 status
   detection could use CPU protocol to detect started or not. So
   in imx_rproc_detect_mode, use scmi_imx_cpu_started to check the
   status of M7.
 - For above case (1) and (2), Use SCMI_IMX_LMM_POWER_ON to detect whether
   the M7 LM is under control of A55 LM.
 - For above case , after using SCMI_IMX_LMM_POWER_ON to check
   permission, SCMI_IMX_LMM_SHUTDOWN API should be called to shutdown
   the M7 LM to save power only when M7 LM is going to be started by
   remoteproc framework. Otherwise bypass SCMI_IMX_LMM_SHUTDOWN API if
   M7 LM is started before booting Linux.

Current setup relies on pre-Linux software(U-Boot) to do M7 TCM ECC
initialization. In future, we could add the support in Linux to decouple
U-Boot and Linux.

Reviewed-by: Daniel Baluta <daniel.baluta at nxp.com>
Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 drivers/remoteproc/Kconfig     |   2 +
 drivers/remoteproc/imx_rproc.c | 198 +++++++++++++++++++++++++++++++++++++++++
 drivers/remoteproc/imx_rproc.h |   3 +
 3 files changed, 203 insertions(+)

diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 48a0d3a69ed08057716f1e7ea950899f60bbe0cf..ee54436fea5ad08a9c198ce74d44ce7a9aa206de 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -27,6 +27,8 @@ config IMX_REMOTEPROC
 	tristate "i.MX remoteproc support"
 	depends on ARCH_MXC
 	depends on HAVE_ARM_SMCCC
+	depends on IMX_SCMI_CPU_DRV || !IMX_SCMI_CPU_DRV
+	depends on IMX_SCMI_LMM_DRV || !IMX_SCMI_LMM_DRV
 	select MAILBOX
 	help
 	  Say y here to support iMX's remote processors via the remote
diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index b0857a1a9660503ee7cd5473c06dacb5262286b8..ae3183ad996462ad0815889a2291d320ce7a1e8f 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -8,6 +8,7 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/firmware/imx/sci.h>
+#include <linux/firmware/imx/sm.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/mailbox_client.h>
@@ -22,6 +23,7 @@
 #include <linux/reboot.h>
 #include <linux/regmap.h>
 #include <linux/remoteproc.h>
+#include <linux/scmi_imx_protocol.h>
 #include <linux/workqueue.h>
 
 #include "imx_rproc.h"
@@ -92,9 +94,16 @@ struct imx_rproc_mem {
 #define ATT_CORE_MASK   0xffff
 #define ATT_CORE(I)     BIT((I))
 
+/* Linux has permission to handle the Logical Machine of remote cores */
+#define IMX_RPROC_FLAGS_SM_LMM_AVAIL	BIT(0)
+
 static int imx_rproc_xtr_mbox_init(struct rproc *rproc, bool tx_block);
 static void imx_rproc_free_mbox(void *data);
 
+/* Forward declarations for platform operations */
+static const struct imx_rproc_plat_ops imx_rproc_ops_sm_lmm;
+static const struct imx_rproc_plat_ops imx_rproc_ops_sm_cpu;
+
 struct imx_rproc {
 	struct device			*dev;
 	struct regmap			*regmap;
@@ -117,6 +126,11 @@ struct imx_rproc {
 	u32				core_index;
 	struct dev_pm_domain_list	*pd_list;
 	const struct imx_rproc_plat_ops	*ops;
+	/*
+	 * For i.MX System Manager based systems
+	 * BIT 0: IMX_RPROC_FLAGS_SM_LMM_AVAIL(RPROC LM is under Linux control )
+	 */
+	u32				flags;
 };
 
 static const struct imx_rproc_att imx_rproc_att_imx93[] = {
@@ -313,6 +327,44 @@ static int imx_rproc_scu_api_start(struct rproc *rproc)
 	return imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, true, priv->entry);
 }
 
+static int imx_rproc_sm_cpu_start(struct rproc *rproc)
+{
+	struct imx_rproc *priv = rproc->priv;
+	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+	int ret;
+
+	ret = scmi_imx_cpu_reset_vector_set(dcfg->cpuid, 0, true, false, false);
+	if (ret) {
+		dev_err(priv->dev, "Failed to set reset vector cpuid(%u): %d\n", dcfg->cpuid, ret);
+		return ret;
+	}
+
+	return scmi_imx_cpu_start(dcfg->cpuid, true);
+}
+
+static int imx_rproc_sm_lmm_start(struct rproc *rproc)
+{
+	struct imx_rproc *priv = rproc->priv;
+	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+	struct device *dev = priv->dev;
+	int ret;
+
+	ret = scmi_imx_lmm_reset_vector_set(dcfg->lmid, dcfg->cpuid, 0, 0);
+	if (ret) {
+		dev_err(dev, "Failed to set reset vector lmid(%u), cpuid(%u): %d\n",
+			dcfg->lmid, dcfg->cpuid, ret);
+		return ret;
+	}
+
+	ret = scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_BOOT, 0);
+	if (ret) {
+		dev_err(dev, "Failed to boot lmm(%d): %d\n", dcfg->lmid, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
 static int imx_rproc_start(struct rproc *rproc)
 {
 	struct imx_rproc *priv = rproc->priv;
@@ -369,6 +421,25 @@ static int imx_rproc_scu_api_stop(struct rproc *rproc)
 	return imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, false, priv->entry);
 }
 
+static int imx_rproc_sm_cpu_stop(struct rproc *rproc)
+{
+	struct imx_rproc *priv = rproc->priv;
+	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+
+	return scmi_imx_cpu_start(dcfg->cpuid, false);
+}
+
+static int imx_rproc_sm_lmm_stop(struct rproc *rproc)
+{
+	struct imx_rproc *priv = rproc->priv;
+	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+
+	if (!(priv->flags & IMX_RPROC_FLAGS_SM_LMM_AVAIL))
+		return -EACCES;
+
+	return scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_SHUTDOWN, 0);
+}
+
 static int imx_rproc_stop(struct rproc *rproc)
 {
 	struct imx_rproc *priv = rproc->priv;
@@ -485,6 +556,33 @@ static int imx_rproc_mem_release(struct rproc *rproc,
 	return 0;
 }
 
+static int imx_rproc_sm_lmm_prepare(struct rproc *rproc)
+{
+	struct imx_rproc *priv = rproc->priv;
+	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+	int ret;
+
+	/*
+	 * IMX_RPROC_FLAGS_SM_LMM_AVAIL not set indicates Linux is not able
+	 * to start/stop rproc LM, then if rproc is not in detached state,
+	 * prepare should fail. If in detached state, this is in rproc_attach()
+	 * path.
+	 */
+	if (!(priv->flags & IMX_RPROC_FLAGS_SM_LMM_AVAIL))
+		return rproc->state == RPROC_DETACHED ? 0 : -EACCES;
+
+	/* Power on the Logical Machine to make sure TCM is available. */
+	ret = scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_POWER_ON, 0);
+	if (ret) {
+		dev_err(priv->dev, "Failed to power on lmm(%d): %d\n", dcfg->lmid, ret);
+		return ret;
+	}
+
+	dev_info(priv->dev, "lmm(%d) powered on by Linux\n", dcfg->lmid);
+
+	return 0;
+}
+
 static int imx_rproc_prepare(struct rproc *rproc)
 {
 	struct imx_rproc *priv = rproc->priv;
@@ -980,6 +1078,93 @@ static int imx_rproc_scu_api_detect_mode(struct rproc *rproc)
 	return 0;
 }
 
+static int imx_rproc_sm_lmm_check(struct rproc *rproc, bool started)
+{
+	struct imx_rproc *priv = rproc->priv;
+	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+	struct device *dev = priv->dev;
+	int ret;
+
+	/*
+	 * Use power on to do permission check. If rproc is in different LM,
+	 * and linux has permission to handle the LM, set IMX_RPROC_FLAGS_SM_LMM_AVAIL.
+	 */
+	ret = scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_POWER_ON, 0);
+	if (ret) {
+		if (ret == -EACCES) {
+			/*
+			 * rproc LM is booted before Linux and not under Linux Control, so only
+			 * do IPC between RPROC and Linux, not return failure
+			 */
+			dev_info(dev, "lmm(%d) not under Linux Control\n", dcfg->lmid);
+			return 0;
+		}
+
+		dev_err(dev, "power on lmm(%d) failed: %d\n", dcfg->lmid, ret);
+		return ret;
+	}
+
+
+	/* rproc was started before boot Linux and under control of Linux, directly return */
+	if (started) {
+		priv->flags |= IMX_RPROC_FLAGS_SM_LMM_AVAIL;
+		return 0;
+	}
+
+	/* else shutdown the LM to save power */
+	ret = scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_SHUTDOWN, 0);
+	if (ret) {
+		dev_err(dev, "shutdown lmm(%d) failed: %d\n", dcfg->lmid, ret);
+		return ret;
+	}
+
+	priv->flags |= IMX_RPROC_FLAGS_SM_LMM_AVAIL;
+
+	return 0;
+}
+
+static int imx_rproc_sm_detect_mode(struct rproc *rproc)
+{
+	struct imx_rproc *priv = rproc->priv;
+	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+	struct device *dev = priv->dev;
+	struct scmi_imx_lmm_info info;
+	bool started = false;
+	int ret;
+
+	ret = scmi_imx_cpu_started(dcfg->cpuid, &started);
+	if (ret) {
+		dev_err(dev, "Failed to detect cpu(%d) status: %d\n", dcfg->cpuid, ret);
+		return ret;
+	}
+
+	if (started)
+		priv->rproc->state = RPROC_DETACHED;
+
+	/* Get current Linux Logical Machine ID */
+	ret = scmi_imx_lmm_info(LMM_ID_DISCOVER, &info);
+	if (ret) {
+		dev_err(dev, "Failed to get current LMM ID err: %d\n", ret);
+		return ret;
+	}
+
+	/*
+	 * Check whether rproc is in the same LM as host core(running Linux)
+	 * If yes, use CPU protocol API to manage rproc.
+	 * If no, use Logical Machine API to manage rproc.
+	 */
+	if (dcfg->lmid == info.lmid) {
+		priv->ops = &imx_rproc_ops_sm_cpu;
+		dev_info(dev, "Using CPU Protocol OPS\n");
+		return 0;
+	}
+
+	priv->ops = &imx_rproc_ops_sm_lmm;
+	dev_info(dev, "Using LMM Protocol OPS\n");
+
+	return imx_rproc_sm_lmm_check(rproc, started);
+}
+
 static int imx_rproc_detect_mode(struct imx_rproc *priv)
 {
 	/*
@@ -1155,6 +1340,19 @@ static const struct imx_rproc_plat_ops imx_rproc_ops_scu_api = {
 	.detect_mode	= imx_rproc_scu_api_detect_mode,
 };
 
+static const struct imx_rproc_plat_ops imx_rproc_ops_sm_lmm = {
+	.detect_mode	= imx_rproc_sm_detect_mode,
+	.prepare	= imx_rproc_sm_lmm_prepare,
+	.start		= imx_rproc_sm_lmm_start,
+	.stop		= imx_rproc_sm_lmm_stop,
+};
+
+static const struct imx_rproc_plat_ops imx_rproc_ops_sm_cpu = {
+	.detect_mode	= imx_rproc_sm_detect_mode,
+	.start		= imx_rproc_sm_cpu_start,
+	.stop		= imx_rproc_sm_cpu_stop,
+};
+
 static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn_mmio = {
 	.src_reg	= IMX7D_SRC_SCR,
 	.src_mask	= IMX7D_M4_RST_MASK,
diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h
index 37417568a0ade2ae4d6a4e3d0f139ea52b185254..d37e6f90548cec727b4aeb874680b42af85bdbb4 100644
--- a/drivers/remoteproc/imx_rproc.h
+++ b/drivers/remoteproc/imx_rproc.h
@@ -38,6 +38,9 @@ struct imx_rproc_dcfg {
 	size_t				att_size;
 	u32				flags;
 	const struct imx_rproc_plat_ops	*ops;
+	/* For System Manager(SM) based SoCs */
+	u32				cpuid; /* ID of the remote core */
+	u32				lmid;  /* ID of the Logcial Machine */
 };
 
 #endif /* _IMX_RPROC_H */

-- 
2.37.1



From peng.fan at oss.nxp.com  Wed Dec 17 21:17:39 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Thu, 18 Dec 2025 13:17:39 +0800
Subject: [PATCH v5 5/5] remoteproc: imx_rproc: Add support for i.MX95
In-Reply-To: <20251218-imx95-rproc-2025-12-18-v5-0-b56a27d4158f@nxp.com>
References: <20251218-imx95-rproc-2025-12-18-v5-0-b56a27d4158f@nxp.com>
Message-ID: <20251218-imx95-rproc-2025-12-18-v5-5-b56a27d4158f@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

Add imx_rproc_cfg_imx95_m7 and address(TCM and DDR) mapping.
Add i.MX95 of_device_id entry.

Reviewed-by: Daniel Baluta <daniel.baluta at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 drivers/remoteproc/imx_rproc.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index ae3183ad996462ad0815889a2291d320ce7a1e8f..61e3f1affee54181bf35110e4ad565edba4c7d06 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -133,6 +133,18 @@ struct imx_rproc {
 	u32				flags;
 };
 
+static const struct imx_rproc_att imx_rproc_att_imx95_m7[] = {
+	/* dev addr , sys addr  , size	    , flags */
+	/* TCM CODE NON-SECURE */
+	{ 0x00000000, 0x203C0000, 0x00040000, ATT_OWN | ATT_IOMEM },
+
+	/* TCM SYS NON-SECURE*/
+	{ 0x20000000, 0x20400000, 0x00040000, ATT_OWN | ATT_IOMEM },
+
+	/* DDR */
+	{ 0x80000000, 0x80000000, 0x50000000, 0 },
+};
+
 static const struct imx_rproc_att imx_rproc_att_imx93[] = {
 	/* dev addr , sys addr  , size	    , flags */
 	/* TCM CODE NON-SECURE */
@@ -1436,6 +1448,15 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx93 = {
 	.flags		= IMX_RPROC_NEED_CLKS,
 };
 
+static const struct imx_rproc_dcfg imx_rproc_cfg_imx95_m7 = {
+	.att		= imx_rproc_att_imx95_m7,
+	.att_size	= ARRAY_SIZE(imx_rproc_att_imx95_m7),
+	.ops		= &imx_rproc_ops_sm_lmm,
+	/* Must align with System Manager Firmware */
+	.cpuid		= 1, /* Use 1 as cpu id for M7 core */
+	.lmid		= 1, /* Use 1 as Logical Machine ID where M7 resides */
+};
+
 static const struct of_device_id imx_rproc_of_match[] = {
 	{ .compatible = "fsl,imx7ulp-cm4", .data = &imx_rproc_cfg_imx7ulp },
 	{ .compatible = "fsl,imx7d-cm4", .data = &imx_rproc_cfg_imx7d },
@@ -1450,6 +1471,7 @@ static const struct of_device_id imx_rproc_of_match[] = {
 	{ .compatible = "fsl,imx8qm-cm4", .data = &imx_rproc_cfg_imx8qm },
 	{ .compatible = "fsl,imx8ulp-cm33", .data = &imx_rproc_cfg_imx8ulp },
 	{ .compatible = "fsl,imx93-cm33", .data = &imx_rproc_cfg_imx93 },
+	{ .compatible = "fsl,imx95-cm7", .data = &imx_rproc_cfg_imx95_m7 },
 	{},
 };
 MODULE_DEVICE_TABLE(of, imx_rproc_of_match);

-- 
2.37.1



From peng.fan at oss.nxp.com  Wed Dec 17 21:22:30 2025
From: peng.fan at oss.nxp.com (Peng Fan)
Date: Thu, 18 Dec 2025 13:22:30 +0800
Subject: [PATCH v4 4/5] remoteproc: imx_rproc: Add support for System
 Manager API
In-Reply-To: <aUM6aGbSH9ICOL5f@p14s>
References: <20251216-imx95-rproc-2025-12-15-v4-0-bf1064ea8daf@nxp.com>
 <20251216-imx95-rproc-2025-12-15-v4-4-bf1064ea8daf@nxp.com>
 <aUM6aGbSH9ICOL5f@p14s>
Message-ID: <aUOPloYtbZHCV6iw@shlinux89>

Hi Mathieu,
On Wed, Dec 17, 2025 at 04:19:04PM -0700, Mathieu Poirier wrote:
>On Tue, Dec 16, 2025 at 09:51:02AM +0800, Peng Fan (OSS) wrote:
>
>Why are these not at the bottom of the file with the rest of the
>imx_rproc_plat_ops?  That way you wouldn't have to declare
>imx_rproc_sm_detect_mode() at the top of the file...
>
>> +
>> +static int imx_rproc_sm_lmm_check(struct rproc *rproc, bool started)
>> +	if (ret) {
>> +		priv->flags &= ~IMX_RPROC_FLAGS_SM_LMM_AVAIL;
>> +		dev_err(dev, "shutdown lmm(%d) failed: %d\n", dcfg->lmid, ret);
>> +		return ret;
>> +	}
>
>If you move this call to scmi_imx_lmm_operation() (and the error check) before
>setting priv->flags, you won't have to reset it in the error path.
>
>Let's see how the next revision goes...

Thanks for the review.

V5 has been sent out just now with both comments addressed:
- Moved the SM LMM functions to the bottom of the file with the
  rest of imx_rproc_plat_ops
- Moved the scmi_imx_lmm_operation() call before setting priv->flags
  to simplify error handling

Thanks,
Peng

>
>Thanks,
>Mathieu
>
>> +
>> +	return 0;
>> +}
>> +
>> +static int imx_rproc_sm_detect_mode(struct rproc *rproc)
>> +{
>> +	struct imx_rproc *priv = rproc->priv;
>> +	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
>> +	struct device *dev = priv->dev;
>> +	struct scmi_imx_lmm_info info;
>> +	bool started = false;
>> +	int ret;
>> +
>> +	ret = scmi_imx_cpu_started(dcfg->cpuid, &started);
>> +	if (ret) {
>> +		dev_err(dev, "Failed to detect cpu(%d) status: %d\n", dcfg->cpuid, ret);
>> +		return ret;
>> +	}
>> +
>> +	if (started)
>> +		priv->rproc->state = RPROC_DETACHED;
>> +
>> +	/* Get current Linux Logical Machine ID */
>> +	ret = scmi_imx_lmm_info(LMM_ID_DISCOVER, &info);
>> +	if (ret) {
>> +		dev_err(dev, "Failed to get current LMM ID err: %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	/*
>> +	 * Check whether rproc is in the same LM as host core(running Linux)
>> +	 * If yes, use CPU protocol API to manage rproc.
>> +	 * If no, use Logical Machine API to manage rproc.
>> +	 */
>> +	if (dcfg->lmid == info.lmid) {
>> +		priv->ops = &imx_rproc_ops_sm_cpu;
>> +		dev_info(dev, "Using CPU Protocol OPS\n");
>> +		return 0;
>> +	}
>> +
>> +	priv->ops = &imx_rproc_ops_sm_lmm;
>> +	dev_info(dev, "Using LMM Protocol OPS\n");
>> +
>> +	return imx_rproc_sm_lmm_check(rproc, started);
>> +}
>> +
>>  static int imx_rproc_detect_mode(struct imx_rproc *priv)
>>  {
>>  	/*
>> diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h
>> index 37417568a0ade2ae4d6a4e3d0f139ea52b185254..d37e6f90548cec727b4aeb874680b42af85bdbb4 100644
>> --- a/drivers/remoteproc/imx_rproc.h
>> +++ b/drivers/remoteproc/imx_rproc.h
>> @@ -38,6 +38,9 @@ struct imx_rproc_dcfg {
>>  	size_t				att_size;
>>  	u32				flags;
>>  	const struct imx_rproc_plat_ops	*ops;
>> +	/* For System Manager(SM) based SoCs */
>> +	u32				cpuid; /* ID of the remote core */
>> +	u32				lmid;  /* ID of the Logcial Machine */
>>  };
>>  
>>  #endif /* _IMX_RPROC_H */
>> 
>> -- 
>> 2.37.1
>> 


From lei.xu at nxp.com  Wed Dec 17 21:56:28 2025
From: lei.xu at nxp.com (Lei Xu)
Date: Wed, 17 Dec 2025 21:56:28 -0800
Subject: [PATCH v2 1/2] dt-bindings: arm: fsl: Add compatible for i.MX95
 15x15 FRDM board
In-Reply-To: <20251217-127-v2-0-67cb12e56242@nxp.com>
References: <20251217-127-v2-0-67cb12e56242@nxp.com>
Message-ID: <20251217-127-v2-1-67cb12e56242@nxp.com>

Introduce a new DT compatible string for the NXP i.MX95 15x15 FRDM
development board, a compact and cost-effective platform based on
the i.MX95 applications processor.

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
Signed-off-by: Lei Xu <lei.xu at nxp.com>
---
 Documentation/devicetree/bindings/arm/fsl.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
index 68a2d5fecc43..4b6188d39be6 100644
--- a/Documentation/devicetree/bindings/arm/fsl.yaml
+++ b/Documentation/devicetree/bindings/arm/fsl.yaml
@@ -1432,6 +1432,7 @@ properties:
         items:
           - enum:
               - fsl,imx95-15x15-evk       # i.MX95 15x15 EVK Board
+              - fsl,imx95-15x15-frdm      # i.MX95 15x15 FRDM Board
               - fsl,imx95-19x19-evk       # i.MX95 19x19 EVK Board
               - toradex,verdin-imx95-19x19-evk  # i.MX95 Verdin Evaluation Kit (EVK)
           - const: fsl,imx95

-- 
2.34.1



From lei.xu at nxp.com  Wed Dec 17 21:56:27 2025
From: lei.xu at nxp.com (Lei Xu)
Date: Wed, 17 Dec 2025 21:56:27 -0800
Subject: [PATCH v2 0/2] Add device tree support for NXP i.MX95 15x15 FRDM
 board
Message-ID: <20251217-127-v2-0-67cb12e56242@nxp.com>

The NXP i.MX95 15x15 FRDM board is a compact and cost-effective
development board based on the i.MX95 applications processor.

This patch set adds device tree support for the board:
 - Patch 1 introduces the DT compatible string.
 - Patch 2 provides the complete device tree description.

Signed-off-by: Lei Xu <lei.xu at nxp.com>
---
Changes in v2:
- Switched from 'xceiver-supply' to CAN PHY nodes using 'phys'.
- Added CAN PHY nodes for flexcan2/5 with shared silent-gpio, removed reg_can_stby.
- Updated MSI/IOMMU mapping comment to match the i.MX95 15x15 FRDM board.

Link to v1: https://lore.kernel.org/r/20251207-127-v1-0-5a2eeb69f150 at nxp.com

---
Lei Xu (2):
      dt-bindings: arm: fsl: Add compatible for i.MX95 15x15 FRDM board
      arm64: dts: freescale: imx95: Add support for i.MX95 15x15 FRDM board

 Documentation/devicetree/bindings/arm/fsl.yaml     |   1 +
 arch/arm64/boot/dts/freescale/Makefile             |   1 +
 arch/arm64/boot/dts/freescale/imx95-15x15-frdm.dts | 963 +++++++++++++++++++++
 3 files changed, 965 insertions(+)
---
base-commit: 6987d58a9cbc5bd57c983baa514474a86c945d56
change-id: 20251207-127-4e8551e8bdaf

Best regards,
-- 
Lei Xu <lei.xu at nxp.com>



From lei.xu at nxp.com  Wed Dec 17 21:56:29 2025
From: lei.xu at nxp.com (Lei Xu)
Date: Wed, 17 Dec 2025 21:56:29 -0800
Subject: [PATCH v2 2/2] arm64: dts: freescale: imx95: Add support for
 i.MX95 15x15 FRDM board
In-Reply-To: <20251217-127-v2-0-67cb12e56242@nxp.com>
References: <20251217-127-v2-0-67cb12e56242@nxp.com>
Message-ID: <20251217-127-v2-2-67cb12e56242@nxp.com>

The i.MX95 15x15 FRDM board is a compact and cost-effective development
platform based on the i.MX95 applications processor.

Add device tree support for this board, including:
 - LPUART1 and LPUART5
 - NETC
 - USB
 - PCIe
 - uSDHC1, uSDHC2 and uSDHC3
 - FlexCAN2 and FlexCAN5
 - LPI2C2, LPI2C3, LPI2C4 and their child nodes
 - Watchdog3

Signed-off-by: Lei Xu <lei.xu at nxp.com>
---
Changes in v2:
- Switched from 'xceiver-supply' to CAN PHY nodes using 'phys'.
- Added CAN PHY nodes for flexcan2/5 with shared silent-gpio, removed reg_can_stby.
- Updated MSI/IOMMU mapping comment to match the i.MX95 15x15 FRDM board.
---
 arch/arm64/boot/dts/freescale/Makefile             |   1 +
 arch/arm64/boot/dts/freescale/imx95-15x15-frdm.dts | 963 +++++++++++++++++++++
 2 files changed, 964 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index f30d3fd724d0..71308d19d35e 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -400,6 +400,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx93-tqma9352-mba93xxla.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx93-var-som-symphony.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx943-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx95-15x15-evk.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx95-15x15-frdm.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx95-19x19-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx95-19x19-evk-sof.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx95-toradex-smarc-dev.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx95-15x15-frdm.dts b/arch/arm64/boot/dts/freescale/imx95-15x15-frdm.dts
new file mode 100644
index 000000000000..414ebdacc3cb
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx95-15x15-frdm.dts
@@ -0,0 +1,963 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2025 NXP
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/phy/phy-imx8-pcie.h>
+#include <dt-bindings/pwm/pwm.h>
+#include <dt-bindings/usb/pd.h>
+#include "imx95.dtsi"
+
+#define BRD_SM_CTRL_SD3_WAKE		0x8000	/*!< PCAL6408A-0 */
+#define BRD_SM_CTRL_PCIE1_WAKE		0x8001	/*!< PCAL6408A-4 */
+#define BRD_SM_CTRL_BT_WAKE		0x8002	/*!< PCAL6408A-5 */
+#define BRD_SM_CTRL_PCIE2_WAKE		0x8003	/*!< PCAL6408A-6 */
+#define BRD_SM_CTRL_BUTTON		0x8004	/*!< PCAL6408A-7 */
+
+/ {
+	compatible = "fsl,imx95-15x15-frdm", "fsl,imx95";
+	model = "NXP i.MX95 15X15 FRDM board";
+
+	aliases {
+		ethernet0 = &enetc_port0;
+		ethernet1 = &enetc_port1;
+		gpio0 = &gpio1;
+		gpio1 = &gpio2;
+		gpio2 = &gpio3;
+		gpio3 = &gpio4;
+		gpio4 = &gpio5;
+		i2c0 = &lpi2c1;
+		i2c1 = &lpi2c2;
+		i2c2 = &lpi2c3;
+		i2c3 = &lpi2c4;
+		i2c4 = &lpi2c5;
+		i2c5 = &lpi2c6;
+		i2c6 = &lpi2c7;
+		i2c7 = &lpi2c8;
+		mmc0 = &usdhc1;
+		mmc1 = &usdhc2;
+		mmc2 = &usdhc3;
+		serial0 = &lpuart1;
+		serial4 = &lpuart5;
+	};
+
+	chosen {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		stdout-path = &lpuart1;
+	};
+
+	dmic: dmic {
+		compatible = "dmic-codec";
+		#sound-dai-cells = <0>;
+		num-channels = <2>;
+	};
+
+	flexcan2_phy: can-phy {
+		compatible = "nxp,tja1051";
+		#phy-cells = <0>;
+		max-bitrate = <5000000>;
+		/*
+		 * Shared SILENT GPIO: CAN PHYs enter silent mode
+		 * together (hardware design).
+		 */
+		silent-gpios = <&pcal6524 7 GPIO_ACTIVE_HIGH>;
+	};
+
+	flexcan5_phy: can-phy {
+		compatible = "nxp,tja1051";
+		#phy-cells = <0>;
+		max-bitrate = <5000000>;
+		silent-gpios = <&pcal6524 7 GPIO_ACTIVE_HIGH>;
+	};
+
+	reg_1p8v: regulator-1p8v {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <1800000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-name = "+V1.8_SW";
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "+V3.3_SW";
+	};
+
+	reg_5p0v: regulator-5p0v {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <5000000>;
+		regulator-min-microvolt = <5000000>;
+		regulator-name = "+V5.0_SW";
+	};
+
+	reg_ext_3v3: regulator-ext-3v3 {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "VCCEXT_3V3";
+	};
+
+	reg_ext_5v: regulator-ext-5v {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-max-microvolt = <5000000>;
+		regulator-min-microvolt = <5000000>;
+		regulator-name = "VCCEXT_5V";
+		gpio = <&pcal6524 12 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_m2_ekey_pwr: regulator-m2-pwr {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "M.2-power-ekey";
+		gpio = <&pcal6524 16 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_m2_mkey_pwr: regulator-m2-mkey-pwr {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "M.2-mkey-power";
+		gpio = <&pcal6524 14 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_usdhc2_vmmc: regulator-usdhc2 {
+		compatible = "regulator-fixed";
+		off-on-delay-us = <12000>;
+		pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
+		pinctrl-names = "default";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "VDD_SD2_3V3";
+		gpio = <&gpio3 7 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_usdhc3_vmmc: regulator-usdhc3 {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "WLAN_EN";
+		vin-supply = <&reg_m2_ekey_pwr>;
+		gpio = <&pcal6524 9 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		/*
+		 * IW612 wifi chip needs more delay than other wifi chips to complete
+		 * the host interface initialization after power up, otherwise the
+		 * internal state of IW612 may be unstable, resulting in the failure of
+		 * the SDIO3.0 switch voltage.
+		 */
+		startup-delay-us = <20000>;
+	};
+
+	reg_usb_vbus: regulator-vbus {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <5000000>;
+		regulator-min-microvolt = <5000000>;
+		regulator-name = "USB_VBUS";
+		gpio = <&pcal6524 15 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_vref_1v8: regulator-adc-vref {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <1800000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-name = "vref_1v8";
+	};
+
+	reserved-memory {
+		ranges;
+		#address-cells = <2>;
+		#size-cells = <2>;
+
+		linux_cma: linux,cma {
+			compatible = "shared-dma-pool";
+			alloc-ranges = <0 0x80000000 0 0x7F000000>;
+			reusable;
+			size = <0 0x3c000000>;
+			linux,cma-default;
+		};
+
+		vdev0vring0: memory at 88000000 {
+			reg = <0 0x88000000 0 0x8000>;
+			no-map;
+		};
+
+		vdev0vring1: memory at 88008000 {
+			reg = <0 0x88008000 0 0x8000>;
+			no-map;
+		};
+
+		vdev1vring0: memory at 88010000 {
+			reg = <0 0x88010000 0 0x8000>;
+			no-map;
+		};
+
+		vdev1vring1: memory at 88018000 {
+			reg = <0 0x88018000 0 0x8000>;
+			no-map;
+		};
+
+		vdevbuffer: memory at 88020000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x88020000 0 0x100000>;
+			no-map;
+		};
+
+		rsc_table: memory at 88220000 {
+			reg = <0 0x88220000 0 0x1000>;
+			no-map;
+		};
+
+		vpu_boot: memory at a0000000 {
+			reg = <0 0xa0000000 0 0x100000>;
+			no-map;
+		};
+	};
+
+	sound-micfil {
+		compatible = "fsl,imx-audio-card";
+		model = "micfil-audio";
+
+		pri-dai-link {
+			link-name = "micfil hifi";
+			format = "i2s";
+
+			cpu {
+				sound-dai = <&micfil>;
+			};
+			codec {
+				sound-dai = <&dmic>;
+			};
+		};
+	};
+
+	usdhc3_pwrseq: usdhc3-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&pcal6524 8 GPIO_ACTIVE_LOW>;
+	};
+
+	memory at 80000000 {
+		reg = <0x0 0x80000000 0 0x80000000>;
+		device_type = "memory";
+	};
+};
+
+&adc1 {
+	vref-supply = <&reg_vref_1v8>;
+	status = "okay";
+};
+
+&enetc_port0 {
+	phy-handle = <&ethphy0>;
+	phy-mode = "rgmii-id";
+	pinctrl-0 = <&pinctrl_enetc0>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&enetc_port1 {
+	phy-handle = <&ethphy1>;
+	phy-mode = "rgmii-id";
+	pinctrl-0 = <&pinctrl_enetc1>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&flexcan2 {
+	pinctrl-0 = <&pinctrl_flexcan2>;
+	pinctrl-names = "default";
+	phys = <&flexcan2_phy>;
+	status = "okay";
+};
+
+&flexcan5 {
+	pinctrl-0 = <&pinctrl_flexcan5>;
+	pinctrl-names = "default";
+	phys = <&flexcan5_phy>;
+	status = "okay";
+};
+
+&lpi2c2 {
+	clock-frequency = <400000>;
+	pinctrl-0 = <&pinctrl_lpi2c2>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	pcal6524: gpio at 22 {
+		compatible = "nxp,pcal6524";
+		reg = <0x22>;
+		#interrupt-cells = <2>;
+		interrupt-controller;
+		interrupt-parent = <&gpio5>;
+		interrupts = <14 IRQ_TYPE_LEVEL_LOW>;
+		#gpio-cells = <2>;
+		gpio-controller;
+		pinctrl-0 = <&pinctrl_pcal6524>;
+		pinctrl-names = "default";
+		gpio-line-names = "ENET1 PHY reset",
+				  "ENET2 PHY reset",
+				  "SPI3/GPIO select",
+				  "UART3/GPIO select",
+				  "CAN2&5/GPIO select",
+				  "PWM/GPIO select",
+				  "Watch dog enable",
+				  "CAN1&2&5 silent",
+				  "SDIO_nRST",
+				  "WL_nDISABLE1",
+				  "WL_nDISABLE2",
+				  "M.2 Mkey NC06",
+				  "EXT_5V0_PWR_EN",
+				  "EXT_3V3_PWR_EN",
+				  "Mkey power control",
+				  "USB2 power control",
+				  "Ekey power control",
+				  "MIPI-DSICSI reset",
+				  "MIPI-DSI IO2",
+				  "MIPI-CSI reset",
+				  "LVDS TP reset",
+				  "LVDS BL enable",
+				  "LVDS BL power enable",
+				  "IT6263 reset";
+
+		lpspi-gpio-sel-hog {
+			gpio-hog;
+			gpios = <2 GPIO_ACTIVE_HIGH>;
+			output-low;
+		};
+
+		lpuart-gpio-sel-hog {
+			gpio-hog;
+			gpios = <3 GPIO_ACTIVE_HIGH>;
+			output-low;
+		};
+
+		can-gpio-sel-hog {
+			gpio-hog;
+			gpios = <4 GPIO_ACTIVE_HIGH>;
+			output-low;
+		};
+
+		pwm-gpio-sel-hog {
+			gpio-hog;
+			gpios = <5 GPIO_ACTIVE_HIGH>;
+			output-high;
+		};
+	};
+};
+
+&lpi2c3 {
+	clock-frequency = <400000>;
+	pinctrl-0 = <&pinctrl_lpi2c3>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	ptn5110: tcpc at 50 {
+		compatible = "nxp,ptn5110", "tcpci";
+		reg = <0x50>;
+		interrupt-parent = <&gpio5>;
+		interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-0 = <&pinctrl_ptn5110>;
+		pinctrl-names = "default";
+
+		typec_con: connector {
+			compatible = "usb-c-connector";
+			data-role = "dual";
+			label = "USB-C";
+			op-sink-microwatt = <15000000>;
+			power-role = "dual";
+			self-powered;
+			sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)
+				     PDO_VAR(5000, 20000, 3000)>;
+			source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
+			try-power-role = "sink";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+
+					typec_con_hs: endpoint {
+						remote-endpoint = <&usb3_data_hs>;
+					};
+				};
+
+				port at 1 {
+					reg = <1>;
+
+					typec_con_ss: endpoint {
+						remote-endpoint = <&usb3_data_ss>;
+					};
+				};
+			};
+		};
+	};
+};
+
+&lpi2c4 {
+	clock-frequency = <400000>;
+	pinctrl-0 = <&pinctrl_lpi2c4>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	pca9632: led-controller at 62 {
+		compatible = "nxp,pca9632";
+		reg = <0x62>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		nxp,inverted-out;
+
+		led_backlight0: led at 0 {
+			reg = <0>;
+			color = <LED_COLOR_ID_WHITE>;
+			function = LED_FUNCTION_BACKLIGHT;
+			function-enumerator = <0>;
+		};
+
+		led_backlight1: led at 1 {
+			reg = <1>;
+			color = <LED_COLOR_ID_WHITE>;
+			function = LED_FUNCTION_BACKLIGHT;
+			function-enumerator = <1>;
+		};
+	};
+};
+
+&lpuart1 {
+	pinctrl-0 = <&pinctrl_uart1>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&lpuart5 {
+	pinctrl-0 = <&pinctrl_uart5>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	bluetooth {
+		compatible = "nxp,88w8987-bt";
+	};
+};
+
+&micfil {
+	assigned-clocks = <&scmi_clk IMX95_CLK_AUDIOPLL1_VCO>,
+			  <&scmi_clk IMX95_CLK_AUDIOPLL2_VCO>,
+			  <&scmi_clk IMX95_CLK_AUDIOPLL1>,
+			  <&scmi_clk IMX95_CLK_AUDIOPLL2>,
+			  <&scmi_clk IMX95_CLK_PDM>;
+	assigned-clock-parents = <0>, <0>, <0>, <0>,
+				 <&scmi_clk IMX95_CLK_AUDIOPLL1>;
+	assigned-clock-rates = <3932160000>,
+			       <3612672000>, <393216000>,
+			       <361267200>, <49152000>;
+	#sound-dai-cells = <0>;
+	pinctrl-0 = <&pinctrl_pdm>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&mu7 {
+	status = "okay";
+};
+
+&netc_blk_ctrl {
+	status = "okay";
+};
+
+/* Configure MSI and IOMMU mappings specific to the i.MX95 15x15 FRDM board. */
+&netc_bus0 {
+	msi-map = <0x0 &its 0x60 0x1>,	//ENETC0 PF
+		  <0x10 &its 0x61 0x1>, //ENETC0 VF0
+		  <0x20 &its 0x62 0x1>, //ENETC0 VF1
+		  <0x40 &its 0x63 0x1>, //ENETC1 PF
+		  <0x50 &its 0x65 0x1>, //ENETC1 VF0
+		  <0x60 &its 0x66 0x1>, //ENETC1 VF1
+		  <0x80 &its 0x64 0x1>, //ENETC2 PF
+		  <0xc0 &its 0x67 0x1>; //NETC Timer
+	iommu-map = <0x0 &smmu 0x20 0x1>,
+		    <0x10 &smmu 0x21 0x1>,
+		    <0x20 &smmu 0x22 0x1>,
+		    <0x40 &smmu 0x23 0x1>,
+		    <0x50 &smmu 0x25 0x1>,
+		    <0x60 &smmu 0x26 0x1>,
+		    <0x80 &smmu 0x24 0x1>,
+		    <0xc0 &smmu 0x27 0x1>;
+};
+
+&netc_emdio {
+	pinctrl-0 = <&pinctrl_emdio>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	ethphy0: ethernet-phy at 1 {
+		reg = <1>;
+		reset-assert-us = <10000>;
+		reset-deassert-us = <80000>;
+		reset-gpios = <&pcal6524 0 GPIO_ACTIVE_LOW>;
+	};
+
+	ethphy1: ethernet-phy at 2 {
+		reg = <2>;
+		reset-assert-us = <10000>;
+		reset-deassert-us = <80000>;
+		reset-gpios = <&pcal6524 1 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&netc_timer {
+	status = "okay";
+};
+
+&netcmix_blk_ctrl {
+	status = "okay";
+};
+
+&pcie0 {
+	pinctrl-0 = <&pinctrl_pcie0>;
+	pinctrl-names = "default";
+	reset-gpio = <&gpio5 13 GPIO_ACTIVE_LOW>;
+	supports-clkreq;
+	vpcie-supply = <&reg_m2_mkey_pwr>;
+	status = "okay";
+};
+
+&scmi_iomuxc {
+	pinctrl_emdio: emdiogrp {
+		fsl,pins = <
+			IMX95_PAD_ENET2_MDC__NETCMIX_TOP_NETC_MDC		0x50e
+			IMX95_PAD_ENET2_MDIO__NETCMIX_TOP_NETC_MDIO		0x90e
+		>;
+	};
+
+	pinctrl_enetc0: enetc0grp {
+		fsl,pins = <
+			IMX95_PAD_ENET1_TD3__NETCMIX_TOP_ETH0_RGMII_TD3		0x50e
+			IMX95_PAD_ENET1_TD2__NETCMIX_TOP_ETH0_RGMII_TD2		0x50e
+			IMX95_PAD_ENET1_TD1__NETCMIX_TOP_ETH0_RGMII_TD1		0x50e
+			IMX95_PAD_ENET1_TD0__NETCMIX_TOP_ETH0_RGMII_TD0		0x50e
+			IMX95_PAD_ENET1_TX_CTL__NETCMIX_TOP_ETH0_RGMII_TX_CTL	0x57e
+			IMX95_PAD_ENET1_TXC__NETCMIX_TOP_ETH0_RGMII_TX_CLK	0x58e
+			IMX95_PAD_ENET1_RX_CTL__NETCMIX_TOP_ETH0_RGMII_RX_CTL	0x57e
+			IMX95_PAD_ENET1_RXC__NETCMIX_TOP_ETH0_RGMII_RX_CLK	0x58e
+			IMX95_PAD_ENET1_RD0__NETCMIX_TOP_ETH0_RGMII_RD0		0x57e
+			IMX95_PAD_ENET1_RD1__NETCMIX_TOP_ETH0_RGMII_RD1		0x57e
+			IMX95_PAD_ENET1_RD2__NETCMIX_TOP_ETH0_RGMII_RD2		0x57e
+			IMX95_PAD_ENET1_RD3__NETCMIX_TOP_ETH0_RGMII_RD3		0x57e
+		>;
+	};
+
+	pinctrl_enetc1: enetc1grp {
+		fsl,pins = <
+			IMX95_PAD_ENET2_TD3__NETCMIX_TOP_ETH1_RGMII_TD3		0x50e
+			IMX95_PAD_ENET2_TD2__NETCMIX_TOP_ETH1_RGMII_TD2		0x50e
+			IMX95_PAD_ENET2_TD1__NETCMIX_TOP_ETH1_RGMII_TD1		0x50e
+			IMX95_PAD_ENET2_TD0__NETCMIX_TOP_ETH1_RGMII_TD0		0x50e
+			IMX95_PAD_ENET2_TX_CTL__NETCMIX_TOP_ETH1_RGMII_TX_CTL	0x57e
+			IMX95_PAD_ENET2_TXC__NETCMIX_TOP_ETH1_RGMII_TX_CLK	0x58e
+			IMX95_PAD_ENET2_RX_CTL__NETCMIX_TOP_ETH1_RGMII_RX_CTL	0x57e
+			IMX95_PAD_ENET2_RXC__NETCMIX_TOP_ETH1_RGMII_RX_CLK	0x58e
+			IMX95_PAD_ENET2_RD0__NETCMIX_TOP_ETH1_RGMII_RD0		0x57e
+			IMX95_PAD_ENET2_RD1__NETCMIX_TOP_ETH1_RGMII_RD1		0x57e
+			IMX95_PAD_ENET2_RD2__NETCMIX_TOP_ETH1_RGMII_RD2		0x57e
+			IMX95_PAD_ENET2_RD3__NETCMIX_TOP_ETH1_RGMII_RD3		0x57e
+		>;
+	};
+
+	pinctrl_flexcan2: flexcan2grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO25__CAN2_TX				0x39e
+			IMX95_PAD_GPIO_IO27__CAN2_RX				0x39e
+		>;
+	};
+
+	pinctrl_flexcan5: flexcan5grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO22__CAN5_TX				0x39e
+			IMX95_PAD_GPIO_IO23__CAN5_RX				0x39e
+		>;
+	};
+
+	pinctrl_lpi2c1: lpi2c1grp {
+		fsl,pins = <
+			IMX95_PAD_I2C1_SCL__AONMIX_TOP_LPI2C1_SCL		0x40000b9e
+			IMX95_PAD_I2C1_SDA__AONMIX_TOP_LPI2C1_SDA		0x40000b9e
+		>;
+	};
+
+	pinctrl_lpi2c2: lpi2c2grp {
+		fsl,pins = <
+			IMX95_PAD_I2C2_SCL__AONMIX_TOP_LPI2C2_SCL		0x40000b9e
+			IMX95_PAD_I2C2_SDA__AONMIX_TOP_LPI2C2_SDA		0x40000b9e
+		>;
+	};
+
+	pinctrl_lpi2c3: lpi2c3grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO28__LPI2C3_SDA				0x40000b9e
+			IMX95_PAD_GPIO_IO29__LPI2C3_SCL				0x40000b9e
+		>;
+	};
+
+	pinctrl_lpi2c4: lpi2c4grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO30__LPI2C4_SDA				0x40000b9e
+			IMX95_PAD_GPIO_IO31__LPI2C4_SCL				0x40000b9e
+		>;
+	};
+
+	pinctrl_pcal6524: pcal6524grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO34__GPIO5_IO_BIT14			0x31e
+		>;
+	};
+
+	pinctrl_pcie0: pcie0grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO32__HSIOMIX_TOP_PCIE1_CLKREQ_B		0x40000b1e
+			IMX95_PAD_GPIO_IO33__GPIO5_IO_BIT13			0x31e
+		>;
+	};
+
+	pinctrl_pdm: pdmgrp {
+		fsl,pins = <
+			IMX95_PAD_PDM_CLK__AONMIX_TOP_PDM_CLK				0x31e
+			IMX95_PAD_PDM_BIT_STREAM0__AONMIX_TOP_PDM_BIT_STREAM_BIT0	0x31e
+		>;
+	};
+
+	pinctrl_ptn5110: ptn5110grp {
+		fsl,pins = <
+			IMX95_PAD_XSPI1_DATA3__GPIO5_IO_BIT3			0x31e
+		>;
+	};
+
+	pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
+		fsl,pins = <
+			IMX95_PAD_SD2_RESET_B__GPIO3_IO_BIT7			0x31e
+		>;
+	};
+
+	pinctrl_uart1: uart1grp {
+		fsl,pins = <
+			IMX95_PAD_UART1_RXD__AONMIX_TOP_LPUART1_RX		0x31e
+			IMX95_PAD_UART1_TXD__AONMIX_TOP_LPUART1_TX		0x31e
+		>;
+	};
+
+	pinctrl_uart5: uart5grp {
+		fsl,pins = <
+			IMX95_PAD_DAP_TDO_TRACESWO__LPUART5_TX			0x31e
+			IMX95_PAD_DAP_TDI__LPUART5_RX				0x31e
+			IMX95_PAD_DAP_TMS_SWDIO__LPUART5_RTS_B			0x31e
+			IMX95_PAD_DAP_TCLK_SWCLK__LPUART5_CTS_B			0x31e
+		>;
+	};
+
+	pinctrl_usdhc1: usdhc1grp {
+		fsl,pins = <
+			IMX95_PAD_SD1_CLK__USDHC1_CLK				0x158e
+			IMX95_PAD_SD1_CMD__USDHC1_CMD				0x138e
+			IMX95_PAD_SD1_DATA0__USDHC1_DATA0			0x138e
+			IMX95_PAD_SD1_DATA1__USDHC1_DATA1			0x138e
+			IMX95_PAD_SD1_DATA2__USDHC1_DATA2			0x138e
+			IMX95_PAD_SD1_DATA3__USDHC1_DATA3			0x138e
+			IMX95_PAD_SD1_DATA4__USDHC1_DATA4			0x138e
+			IMX95_PAD_SD1_DATA5__USDHC1_DATA5			0x138e
+			IMX95_PAD_SD1_DATA6__USDHC1_DATA6			0x138e
+			IMX95_PAD_SD1_DATA7__USDHC1_DATA7			0x138e
+			IMX95_PAD_SD1_STROBE__USDHC1_STROBE			0x158e
+		>;
+	};
+
+	pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp {
+		fsl,pins = <
+			IMX95_PAD_SD1_CLK__USDHC1_CLK				0x158e
+			IMX95_PAD_SD1_CMD__USDHC1_CMD				0x138e
+			IMX95_PAD_SD1_DATA0__USDHC1_DATA0			0x138e
+			IMX95_PAD_SD1_DATA1__USDHC1_DATA1			0x138e
+			IMX95_PAD_SD1_DATA2__USDHC1_DATA2			0x138e
+			IMX95_PAD_SD1_DATA3__USDHC1_DATA3			0x138e
+			IMX95_PAD_SD1_DATA4__USDHC1_DATA4			0x138e
+			IMX95_PAD_SD1_DATA5__USDHC1_DATA5			0x138e
+			IMX95_PAD_SD1_DATA6__USDHC1_DATA6			0x138e
+			IMX95_PAD_SD1_DATA7__USDHC1_DATA7			0x138e
+			IMX95_PAD_SD1_STROBE__USDHC1_STROBE			0x158e
+		>;
+	};
+
+	pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp {
+		fsl,pins = <
+			IMX95_PAD_SD1_CLK__USDHC1_CLK				0x15fe
+			IMX95_PAD_SD1_CMD__USDHC1_CMD				0x13fe
+			IMX95_PAD_SD1_DATA0__USDHC1_DATA0			0x13fe
+			IMX95_PAD_SD1_DATA1__USDHC1_DATA1			0x13fe
+			IMX95_PAD_SD1_DATA2__USDHC1_DATA2			0x13fe
+			IMX95_PAD_SD1_DATA3__USDHC1_DATA3			0x13fe
+			IMX95_PAD_SD1_DATA4__USDHC1_DATA4			0x13fe
+			IMX95_PAD_SD1_DATA5__USDHC1_DATA5			0x13fe
+			IMX95_PAD_SD1_DATA6__USDHC1_DATA6			0x13fe
+			IMX95_PAD_SD1_DATA7__USDHC1_DATA7			0x13fe
+			IMX95_PAD_SD1_STROBE__USDHC1_STROBE			0x15fe
+		>;
+	};
+
+	pinctrl_usdhc2_gpio: usdhc2gpiogrp {
+		fsl,pins = <
+			IMX95_PAD_SD2_CD_B__GPIO3_IO_BIT0			0x31e
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			IMX95_PAD_SD2_CLK__USDHC2_CLK				0x158e
+			IMX95_PAD_SD2_CMD__USDHC2_CMD				0x138e
+			IMX95_PAD_SD2_DATA0__USDHC2_DATA0			0x138e
+			IMX95_PAD_SD2_DATA1__USDHC2_DATA1			0x138e
+			IMX95_PAD_SD2_DATA2__USDHC2_DATA2			0x138e
+			IMX95_PAD_SD2_DATA3__USDHC2_DATA3			0x138e
+			IMX95_PAD_SD2_VSELECT__USDHC2_VSELECT			0x51e
+		>;
+	};
+
+	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+		fsl,pins = <
+			IMX95_PAD_SD2_CLK__USDHC2_CLK				0x158e
+			IMX95_PAD_SD2_CMD__USDHC2_CMD				0x138e
+			IMX95_PAD_SD2_DATA0__USDHC2_DATA0			0x138e
+			IMX95_PAD_SD2_DATA1__USDHC2_DATA1			0x138e
+			IMX95_PAD_SD2_DATA2__USDHC2_DATA2			0x138e
+			IMX95_PAD_SD2_DATA3__USDHC2_DATA3			0x138e
+			IMX95_PAD_SD2_VSELECT__USDHC2_VSELECT			0x51e
+		>;
+	};
+
+	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+		fsl,pins = <
+			IMX95_PAD_SD2_CLK__USDHC2_CLK				0x158e
+			IMX95_PAD_SD2_CMD__USDHC2_CMD				0x138e
+			IMX95_PAD_SD2_DATA0__USDHC2_DATA0			0x138e
+			IMX95_PAD_SD2_DATA1__USDHC2_DATA1			0x138e
+			IMX95_PAD_SD2_DATA2__USDHC2_DATA2			0x138e
+			IMX95_PAD_SD2_DATA3__USDHC2_DATA3			0x138e
+			IMX95_PAD_SD2_VSELECT__USDHC2_VSELECT			0x51e
+		>;
+	};
+
+	pinctrl_usdhc3: usdhc3grp {
+		fsl,pins = <
+			IMX95_PAD_SD3_CLK__USDHC3_CLK				0x158e
+			IMX95_PAD_SD3_CMD__USDHC3_CMD				0x138e
+			IMX95_PAD_SD3_DATA0__USDHC3_DATA0			0x138e
+			IMX95_PAD_SD3_DATA1__USDHC3_DATA1			0x138e
+			IMX95_PAD_SD3_DATA2__USDHC3_DATA2			0x138e
+			IMX95_PAD_SD3_DATA3__USDHC3_DATA3			0x138e
+		>;
+	};
+
+	pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp {
+		fsl,pins = <
+			IMX95_PAD_SD3_CLK__USDHC3_CLK				0x158e
+			IMX95_PAD_SD3_CMD__USDHC3_CMD				0x138e
+			IMX95_PAD_SD3_DATA0__USDHC3_DATA0			0x138e
+			IMX95_PAD_SD3_DATA1__USDHC3_DATA1			0x138e
+			IMX95_PAD_SD3_DATA2__USDHC3_DATA2			0x138e
+			IMX95_PAD_SD3_DATA3__USDHC3_DATA3			0x138e
+		>;
+	};
+
+	pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp {
+		fsl,pins = <
+			IMX95_PAD_SD3_CLK__USDHC3_CLK				0x15fe
+			IMX95_PAD_SD3_CMD__USDHC3_CMD				0x13fe
+			IMX95_PAD_SD3_DATA0__USDHC3_DATA0			0x13fe
+			IMX95_PAD_SD3_DATA1__USDHC3_DATA1			0x13fe
+			IMX95_PAD_SD3_DATA2__USDHC3_DATA2			0x13fe
+			IMX95_PAD_SD3_DATA3__USDHC3_DATA3			0x13fe
+		>;
+	};
+};
+
+&scmi_misc {
+	nxp,ctrl-ids = <BRD_SM_CTRL_SD3_WAKE		1
+			BRD_SM_CTRL_PCIE1_WAKE		1
+			BRD_SM_CTRL_BT_WAKE		1
+			BRD_SM_CTRL_PCIE2_WAKE		1
+			BRD_SM_CTRL_BUTTON		1>;
+};
+
+&thermal_zones {
+	pf09-thermal {
+		polling-delay = <2000>;
+		polling-delay-passive = <250>;
+		thermal-sensors = <&scmi_sensor 2>;
+
+		trips {
+			pf09_alert: trip0 {
+				hysteresis = <2000>;
+				temperature = <140000>;
+				type = "passive";
+			};
+
+			pf09_crit: trip1 {
+				hysteresis = <2000>;
+				temperature = <155000>;
+				type = "critical";
+			};
+		};
+	};
+
+	pf53arm-thermal {
+		polling-delay = <2000>;
+		polling-delay-passive = <250>;
+		thermal-sensors = <&scmi_sensor 4>;
+
+		cooling-maps {
+			map0 {
+				cooling-device = <&A55_0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+					<&A55_1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+					<&A55_2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+					<&A55_3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+					<&A55_4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+					<&A55_5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				trip = <&pf5301_alert>;
+			};
+		};
+
+		trips {
+			pf5301_alert: trip0 {
+				hysteresis = <2000>;
+				temperature = <140000>;
+				type = "passive";
+			};
+
+			pf5301_crit: trip1 {
+				hysteresis = <2000>;
+				temperature = <155000>;
+				type = "critical";
+			};
+		};
+	};
+
+	pf53soc-thermal {
+		polling-delay = <2000>;
+		polling-delay-passive = <250>;
+		thermal-sensors = <&scmi_sensor 3>;
+
+		trips {
+			pf5302_alert: trip0 {
+				hysteresis = <2000>;
+				temperature = <140000>;
+				type = "passive";
+			};
+
+			pf5302_crit: trip1 {
+				hysteresis = <2000>;
+				temperature = <155000>;
+				type = "critical";
+			};
+		};
+	};
+};
+
+&usb2 {
+	disable-over-current;
+	dr_mode = "host";
+	vbus-supply = <&reg_usb_vbus>;
+	status = "okay";
+};
+
+&usb3 {
+	status = "okay";
+};
+
+&usb3_dwc3 {
+	adp-disable;
+	dr_mode = "otg";
+	hnp-disable;
+	role-switch-default-mode = "peripheral";
+	srp-disable;
+	usb-role-switch;
+	snps,dis-u1-entry-quirk;
+	snps,dis-u2-entry-quirk;
+	status = "okay";
+
+	port {
+		usb3_data_hs: endpoint {
+			remote-endpoint = <&typec_con_hs>;
+		};
+	};
+};
+
+&usb3_phy {
+	orientation-switch;
+	fsl,phy-pcs-tx-deemph-3p5db-attenuation-db = <17>;
+	fsl,phy-pcs-tx-swing-full-percent = <100>;
+	fsl,phy-tx-preemp-amp-tune-microamp = <600>;
+	fsl,phy-tx-vboost-level-microvolt = <1156>;
+	fsl,phy-tx-vref-tune-percent = <100>;
+	status = "okay";
+
+	port {
+		usb3_data_ss: endpoint {
+			remote-endpoint = <&typec_con_ss>;
+		};
+	};
+};
+
+&usdhc1 {
+	bus-width = <8>;
+	non-removable;
+	no-sd;
+	no-sdio;
+	pinctrl-0 = <&pinctrl_usdhc1>;
+	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
+	pinctrl-3 = <&pinctrl_usdhc1>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
+	fsl,tuning-step = <1>;
+	status = "okay";
+};
+
+&usdhc2 {
+	bus-width = <4>;
+	cd-gpios = <&gpio3 00 GPIO_ACTIVE_LOW>;
+	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-3 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	fsl,tuning-step = <1>;
+	status = "okay";
+};
+
+&usdhc3 {
+	bus-width = <4>;
+	keep-power-in-suspend;
+	mmc-pwrseq = <&usdhc3_pwrseq>;
+	non-removable;
+	pinctrl-0 = <&pinctrl_usdhc3>;
+	pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
+	pinctrl-3 = <&pinctrl_usdhc3>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
+	vmmc-supply = <&reg_usdhc3_vmmc>;
+	wakeup-source;
+	status = "okay";
+};
+
+&wdog3 {
+	status = "okay";
+};

-- 
2.34.1



From manivannan.sadhasivam at oss.qualcomm.com  Wed Dec 17 22:06:01 2025
From: manivannan.sadhasivam at oss.qualcomm.com (Manivannan Sadhasivam)
Date: Thu, 18 Dec 2025 11:36:01 +0530
Subject: [PATCH] PCI: meson: Remove meson_pcie_link_up() timeout,
 message, speed check
In-Reply-To: <20251103221930.1831376-1-helgaas@kernel.org>
References: <20251103221930.1831376-1-helgaas@kernel.org>
Message-ID: <176603796183.17581.9416209133990924154.b4-ty@kernel.org>


On Mon, 03 Nov 2025 16:19:26 -0600, Bjorn Helgaas wrote:
> Previously meson_pcie_link_up() only returned true if the link was in the
> L0 state.  This was incorrect because hardware autonomously manages
> transitions between L0, L0s, and L1 while both components on the link stay
> in D0.  Those states should all be treated as "link is active".
> 
> Returning false when the device was in L0s or L1 broke config accesses
> because dw_pcie_other_conf_map_bus() fails if the link is down, which
> caused errors like this:
> 
> [...]

Applied, thanks!

[1/1] PCI: meson: Remove meson_pcie_link_up() timeout, message, speed check
      commit: 11647fc772e977c981259a63c4a2b7e2c312ea22

Best regards,
-- 
Manivannan Sadhasivam <mani at kernel.org>



From hkelam at marvell.com  Wed Dec 17 22:21:42 2025
From: hkelam at marvell.com (Hariprasad Kelam)
Date: Thu, 18 Dec 2025 11:51:42 +0530
Subject: [PATCH net] net: stmmac: fix the crash issue for zero copy
 XDP_TX action
In-Reply-To: <AS8PR04MB849779A6392D543049A3F5BE88ABA@AS8PR04MB8497.eurprd04.prod.outlook.com>
References: <20251204071332.1907111-1-wei.fang@nxp.com>
 <aUKPHdtAPDnMqB7X@test-OptiPlex-Tower-Plus-7010>
 <AS8PR04MB849779A6392D543049A3F5BE88ABA@AS8PR04MB8497.eurprd04.prod.outlook.com>
Message-ID: <aUOddielBMkrmwhd@test-OptiPlex-Tower-Plus-7010>

On 2025-12-17 at 18:19:19, Wei Fang (wei.fang at nxp.com) wrote:
> > > -	res = stmmac_xdp_xmit_xdpf(priv, queue, xdpf, false);
> > > -	if (res == STMMAC_XDP_TX)
> > > +	/* For zero copy XDP_TX action, dma_map is true */
> > > +	res = stmmac_xdp_xmit_xdpf(priv, queue, xdpf, zc);
> > 	Seems stmmac_xdp_xmit_xdpf is using dma_map_single if we pass zc is
> > true.
> >         Ideally in case of zc, driver can use page_pool_get_dma_addr, may be
> > you
> >         need pass zc param as false. Please check
> > 
> 
> No, the memory type of xdpf->data is MEM_TYPE_PAGE_ORDER0 rather
> than MEM_TYPE_PAGE_POOL, so we should use dma_map_single().
> Otherwise, it will lead to invalid mappings and cause the crash.
> 
>
 ACK, found below code bit confusing
		case STMMAC_XDP_CONSUMED:
 			xsk_buff_free(buf->xdp);
+			fallthrough;
+		case STMMAC_XSK_CONSUMED:
 			rx_dropped++; 
              
     Ideally in case of STMMAC_XSK_CONSUMED, driver needs to call xsk_buff_free.
     And in case of STMMAC_XDP_CONSUMED, driver needs to call xdp_return_frame.
     May be you can move all buffer free logic to stmmac_rx_zc with above suggested
     changes.


From jie.gan at oss.qualcomm.com  Wed Dec 17 22:22:50 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Thu, 18 Dec 2025 14:22:50 +0800
Subject: [PATCH v4 1/3] coresight: tpda: add sysfs nodes for tpda
 cross-trigger configuration
In-Reply-To: <20251028-configure_tpda_reg-v4-1-23000805d21d@oss.qualcomm.com>
References: <20251028-configure_tpda_reg-v4-0-23000805d21d@oss.qualcomm.com>
 <20251028-configure_tpda_reg-v4-1-23000805d21d@oss.qualcomm.com>
Message-ID: <ea84b279-8d55-4707-b6cf-85006da27456@oss.qualcomm.com>



On 10/28/2025 10:02 AM, Jie Gan wrote:
> From: Tao Zhang <tao.zhang at oss.qualcomm.com>
> 
> Introduce sysfs nodes to configure cross-trigger parameters for TPDA.
> These registers define the characteristics of cross-trigger packets,
> including generation frequency and flag values.
> 
> Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
> Reviewed-by: James Clark <james.clark at linaro.org>
> Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
> ---
>   .../ABI/testing/sysfs-bus-coresight-devices-tpda   |  43 ++++
>   drivers/hwtracing/coresight/coresight-tpda.c       | 230 +++++++++++++++++++++
>   drivers/hwtracing/coresight/coresight-tpda.h       |  27 ++-
>   3 files changed, 299 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
> new file mode 100644
> index 000000000000..80e4b05a1ab4
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda

Gentle reminder.

Do I need update the date and the kernelVersion of the sysfs 
node?(target 7.0?)

Thanks,
Jie


> @@ -0,0 +1,43 @@
> +What:		/sys/bus/coresight/devices/<tpda-name>/trig_async_enable
> +Date:		October 2025
> +KernelVersion:	6.19
> +Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
> +Description:
> +		(RW) Enable/disable cross trigger synchronization sequence interface.
> +
> +What:		/sys/bus/coresight/devices/<tpda-name>/trig_flag_ts_enable
> +Date:		October 2025
> +KernelVersion:	6.19
> +Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
> +Description:
> +		(RW) Enable/disable cross trigger FLAG packet request interface.
> +
> +What:		/sys/bus/coresight/devices/<tpda-name>/trig_freq_enable
> +Date:		October 2025
> +KernelVersion:	6.19
> +Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
> +Description:
> +		(RW) Enable/disable cross trigger FREQ packet request interface.
> +
> +What:		/sys/bus/coresight/devices/<tpda-name>/freq_ts_enable
> +Date:		October 2025
> +KernelVersion:	6.19
> +Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
> +Description:
> +		(RW) Enable/disable the timestamp for all FREQ packets.
> +
> +What:		/sys/bus/coresight/devices/<tpda-name>/global_flush_req
> +Date:		October 2025
> +KernelVersion:	6.19
> +Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
> +Description:
> +		(RW) Set global (all ports) flush request bit. The bit remains set until a
> +		global flush request sequence completes.
> +
> +What:		/sys/bus/coresight/devices/<tpda-name>/cmbchan_mode
> +Date:		October 2025
> +KernelVersion:	6.19
> +Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
> +Description:
> +		(RW) Configure the CMB/MCMB channel mode for all enabled ports.
> +		Value 0 means raw channel mapping mode. Value 1 means channel pair marking mode.
> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
> index 333b3cb23685..a9a27bcc65a1 100644
> --- a/drivers/hwtracing/coresight/coresight-tpda.c
> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
> @@ -147,9 +147,37 @@ static void tpda_enable_pre_port(struct tpda_drvdata *drvdata)
>   	u32 val;
>   
>   	val = readl_relaxed(drvdata->base + TPDA_CR);
> +	val &= ~TPDA_CR_MID;
>   	val &= ~TPDA_CR_ATID;
>   	val |= FIELD_PREP(TPDA_CR_ATID, drvdata->atid);
> +	if (drvdata->trig_async)
> +		val |= TPDA_CR_SRIE;
> +	else
> +		val &= ~TPDA_CR_SRIE;
> +	if (drvdata->trig_flag_ts)
> +		val |= TPDA_CR_FLRIE;
> +	else
> +		val &= ~TPDA_CR_FLRIE;
> +	if (drvdata->trig_freq)
> +		val |= TPDA_CR_FRIE;
> +	else
> +		val &= ~TPDA_CR_FRIE;
> +	if (drvdata->freq_ts)
> +		val |= TPDA_CR_FREQTS;
> +	else
> +		val &= ~TPDA_CR_FREQTS;
> +	if (drvdata->cmbchan_mode)
> +		val |= TPDA_CR_CMBCHANMODE;
> +	else
> +		val &= ~TPDA_CR_CMBCHANMODE;
>   	writel_relaxed(val, drvdata->base + TPDA_CR);
> +
> +	/*
> +	 * If FLRIE bit is set, set the master and channel
> +	 * id as zero
> +	 */
> +	if (drvdata->trig_flag_ts)
> +		writel_relaxed(0x0, drvdata->base + TPDA_FPID_CR);
>   }
>   
>   static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
> @@ -265,6 +293,206 @@ static const struct coresight_ops tpda_cs_ops = {
>   	.link_ops	= &tpda_link_ops,
>   };
>   
> +static ssize_t trig_async_enable_show(struct device *dev,
> +				      struct device_attribute *attr,
> +				      char *buf)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +
> +	return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_async);
> +}
> +
> +static ssize_t trig_async_enable_store(struct device *dev,
> +				       struct device_attribute *attr,
> +				       const char *buf,
> +				       size_t size)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	unsigned long val;
> +
> +	if (kstrtoul(buf, 0, &val))
> +		return -EINVAL;
> +
> +	guard(spinlock)(&drvdata->spinlock);
> +	drvdata->trig_async = !!val;
> +
> +	return size;
> +}
> +static DEVICE_ATTR_RW(trig_async_enable);
> +
> +static ssize_t trig_flag_ts_enable_show(struct device *dev,
> +					struct device_attribute *attr,
> +					char *buf)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +
> +	return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_flag_ts);
> +}
> +
> +static ssize_t trig_flag_ts_enable_store(struct device *dev,
> +					 struct device_attribute *attr,
> +					 const char *buf,
> +					 size_t size)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	unsigned long val;
> +
> +	if (kstrtoul(buf, 0, &val))
> +		return -EINVAL;
> +
> +	guard(spinlock)(&drvdata->spinlock);
> +	drvdata->trig_flag_ts = !!val;
> +
> +	return size;
> +}
> +static DEVICE_ATTR_RW(trig_flag_ts_enable);
> +
> +static ssize_t trig_freq_enable_show(struct device *dev,
> +				     struct device_attribute *attr,
> +				     char *buf)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +
> +	return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_freq);
> +}
> +
> +static ssize_t trig_freq_enable_store(struct device *dev,
> +				      struct device_attribute *attr,
> +				      const char *buf,
> +				      size_t size)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	unsigned long val;
> +
> +	if (kstrtoul(buf, 0, &val))
> +		return -EINVAL;
> +
> +	guard(spinlock)(&drvdata->spinlock);
> +	drvdata->trig_freq = !!val;
> +
> +	return size;
> +}
> +static DEVICE_ATTR_RW(trig_freq_enable);
> +
> +static ssize_t freq_ts_enable_show(struct device *dev,
> +				   struct device_attribute *attr,
> +				   char *buf)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +
> +	return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->freq_ts);
> +}
> +
> +static ssize_t freq_ts_enable_store(struct device *dev,
> +				    struct device_attribute *attr,
> +				    const char *buf,
> +				    size_t size)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	unsigned long val;
> +
> +	if (kstrtoul(buf, 0, &val))
> +		return -EINVAL;
> +
> +	guard(spinlock)(&drvdata->spinlock);
> +	drvdata->freq_ts = !!val;
> +
> +	return size;
> +}
> +static DEVICE_ATTR_RW(freq_ts_enable);
> +
> +static ssize_t global_flush_req_show(struct device *dev,
> +				     struct device_attribute *attr,
> +				     char *buf)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	unsigned long val;
> +
> +	if (!drvdata->csdev->refcnt)
> +		return -EINVAL;
> +
> +	guard(spinlock)(&drvdata->spinlock);
> +	CS_UNLOCK(drvdata->base);
> +	val = readl_relaxed(drvdata->base + TPDA_CR);
> +	CS_LOCK(drvdata->base);
> +	/* Only read value for bit 0 */
> +	val &= BIT(0);
> +
> +	return sysfs_emit(buf, "%lu\n", val);
> +}
> +
> +static ssize_t global_flush_req_store(struct device *dev,
> +				      struct device_attribute *attr,
> +				      const char *buf,
> +				      size_t size)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	unsigned long val;
> +
> +	if (kstrtoul(buf, 0, &val))
> +		return -EINVAL;
> +
> +	if (!drvdata->csdev->refcnt || !val)
> +		return -EINVAL;
> +
> +	guard(spinlock)(&drvdata->spinlock);
> +	CS_UNLOCK(drvdata->base);
> +	val = readl_relaxed(drvdata->base + TPDA_CR);
> +	/* Only set bit 0 */
> +	val |= BIT(0);
> +	writel_relaxed(val, drvdata->base + TPDA_CR);
> +	CS_LOCK(drvdata->base);
> +
> +	return size;
> +}
> +static DEVICE_ATTR_RW(global_flush_req);
> +
> +static ssize_t cmbchan_mode_show(struct device *dev,
> +				 struct device_attribute *attr,
> +				 char *buf)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +
> +	return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->cmbchan_mode);
> +}
> +
> +static ssize_t cmbchan_mode_store(struct device *dev,
> +				  struct device_attribute *attr,
> +				  const char *buf,
> +				  size_t size)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	unsigned long val;
> +
> +	if (kstrtoul(buf, 0, &val))
> +		return -EINVAL;
> +
> +	guard(spinlock)(&drvdata->spinlock);
> +	drvdata->cmbchan_mode = !!val;
> +
> +	return size;
> +}
> +static DEVICE_ATTR_RW(cmbchan_mode);
> +
> +static struct attribute *tpda_attrs[] = {
> +	&dev_attr_trig_async_enable.attr,
> +	&dev_attr_trig_flag_ts_enable.attr,
> +	&dev_attr_trig_freq_enable.attr,
> +	&dev_attr_freq_ts_enable.attr,
> +	&dev_attr_global_flush_req.attr,
> +	&dev_attr_cmbchan_mode.attr,
> +	NULL,
> +};
> +
> +static struct attribute_group tpda_attr_grp = {
> +	.attrs = tpda_attrs,
> +};
> +
> +static const struct attribute_group *tpda_attr_grps[] = {
> +	&tpda_attr_grp,
> +	NULL,
> +};
> +
>   static int tpda_init_default_data(struct tpda_drvdata *drvdata)
>   {
>   	int atid;
> @@ -280,6 +508,7 @@ static int tpda_init_default_data(struct tpda_drvdata *drvdata)
>   		return atid;
>   
>   	drvdata->atid = atid;
> +	drvdata->freq_ts = true;
>   	return 0;
>   }
>   
> @@ -323,6 +552,7 @@ static int tpda_probe(struct amba_device *adev, const struct amba_id *id)
>   	desc.ops = &tpda_cs_ops;
>   	desc.pdata = adev->dev.platform_data;
>   	desc.dev = &adev->dev;
> +	desc.groups = tpda_attr_grps;
>   	desc.access = CSDEV_ACCESS_IOMEM(base);
>   	drvdata->csdev = coresight_register(&desc);
>   	if (IS_ERR(drvdata->csdev))
> diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h
> index c6af3d2da3ef..0be625fb52fd 100644
> --- a/drivers/hwtracing/coresight/coresight-tpda.h
> +++ b/drivers/hwtracing/coresight/coresight-tpda.h
> @@ -1,6 +1,6 @@
>   /* SPDX-License-Identifier: GPL-2.0 */
>   /*
> - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
> + * Copyright (c) 2023,2025 Qualcomm Innovation Center, Inc. All rights reserved.
>    */
>   
>   #ifndef _CORESIGHT_CORESIGHT_TPDA_H
> @@ -8,6 +8,19 @@
>   
>   #define TPDA_CR			(0x000)
>   #define TPDA_Pn_CR(n)		(0x004 + (n * 4))
> +#define TPDA_FPID_CR		(0x084)
> +
> +/* Cross trigger FREQ packets timestamp bit */
> +#define TPDA_CR_FREQTS		BIT(2)
> +/* Cross trigger FREQ packet request bit */
> +#define TPDA_CR_FRIE		BIT(3)
> +/* Cross trigger FLAG packet request interface bit */
> +#define TPDA_CR_FLRIE		BIT(4)
> +/* Cross trigger synchronization bit */
> +#define TPDA_CR_SRIE		BIT(5)
> +/* Packetize CMB/MCMB traffic bit */
> +#define TPDA_CR_CMBCHANMODE	BIT(20)
> +
>   /* Aggregator port enable bit */
>   #define TPDA_Pn_CR_ENA		BIT(0)
>   /* Aggregator port CMB data set element size bit */
> @@ -19,6 +32,8 @@
>   
>   /* Bits 6 ~ 12 is for atid value */
>   #define TPDA_CR_ATID		GENMASK(12, 6)
> +/* Bits 13 ~ 19 is for mid value */
> +#define TPDA_CR_MID		GENMASK(19, 13)
>   
>   /**
>    * struct tpda_drvdata - specifics associated to an TPDA component
> @@ -29,6 +44,11 @@
>    * @enable:     enable status of the component.
>    * @dsb_esize   Record the DSB element size.
>    * @cmb_esize   Record the CMB element size.
> + * @trig_async:	Enable/disable cross trigger synchronization sequence interface.
> + * @trig_flag_ts: Enable/disable cross trigger FLAG packet request interface.
> + * @trig_freq:	Enable/disable cross trigger FREQ packet request interface.
> + * @freq_ts:	Enable/disable the timestamp for all FREQ packets.
> + * @cmbchan_mode: Configure the CMB/MCMB channel mode.
>    */
>   struct tpda_drvdata {
>   	void __iomem		*base;
> @@ -38,6 +58,11 @@ struct tpda_drvdata {
>   	u8			atid;
>   	u32			dsb_esize;
>   	u32			cmb_esize;
> +	bool			trig_async;
> +	bool			trig_flag_ts;
> +	bool			trig_freq;
> +	bool			freq_ts;
> +	bool			cmbchan_mode;
>   };
>   
>   #endif  /* _CORESIGHT_CORESIGHT_TPDA_H */
> 



From mh at probably.group  Wed Dec 17 22:27:06 2025
From: mh at probably.group (=?utf-8?B?Ik1hcnRpbiBIb2xvdnNrw70gKFByb2JhYmx5IE5vdGhpbmcgcy5yLm8u?= =?utf-8?B?KSI=?=)
Date: Thu, 18 Dec 2025 07:27:06 +0100
Subject: [PATCH v2] arm64: dts: rockchip: enable both 2.5GbE ports on Rock 5T
In-Reply-To: <96516D1F-9787-47FE-A67E-4745D11D9207@probably.group>
References: <96516D1F-9787-47FE-A67E-4745D11D9207@probably.group>
Message-ID: <034BDB37-34FB-441F-B79E-1631CA501576@probably.group>

The Radxa Rock 5T board features two RTL8125B 2.5GbE Ethernet controllers
connected via PCIe lanes pcie2x1l0 (fe170000) and pcie2x1l2 (fe190000).
Currently only one interface is functional because the PCIe controller
nodes lack the necessary reset GPIO configuration.

Without the reset-gpios property, the RTL8125B PHYs remain in reset state
and are not enumerated by the PCIe bus. This results in only one Ethernet
interface being detected, or none at all depending on U-Boot initialization.

This patch adds the missing configuration for both PCIe controllers:
- Enables both pcie2x1l0 and pcie2x1l2 nodes (status = "okay")
- Configures reset GPIOs (GPIO4_PA5 and GPIO3_PB0 respectively)
- Adds corresponding pinctrl definitions

With this change, both 2.5GbE interfaces are properly detected and
functional on the Rock 5T.

Tested on Radxa Rock 5T v1.2 running Linux 6.12.

Signed-off-by: Martin Holovsky <mh at probably.group>
---
Changes in v2:
- Sorted pcie nodes alphanumerically
- Sorted pinctrl nodes alphanumerically
- Added Signed-off-by line

 .../boot/dts/rockchip/rk3588-rock-5t.dts      | 28 +++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts
index 0dd90c744380..aeb8e0d42f09 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts
@@ -68,10 +68,24 @@ &pcie2x1l1 {
 	reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>;
 	status = "okay";
 };
 
+&pcie2x1l0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_0_rst>;
+	reset-gpios = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+&pcie2x1l2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_2_rst>;
+	reset-gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
 &pcie30phy {
 	data-lanes = <1 1 2 2>;
 };
@@ -101,6 +115,14 @@ pcie2 {
+		pcie2_0_rst: pcie2-0-rst {
+			rockchip,pins = <4 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
 		pcie2_1_rst: pcie2-1-rst {
 			rockchip,pins = <4 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
 		};
+
+		pcie2_2_rst: pcie2-2-rst {
+			rockchip,pins = <3 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
 		pcie2_0_vcc3v3_en: pcie2-0-vcc-en {
 			rockchip,pins = <2 RK_PC0 RK_FUNC_GPIO &pcfg_pull_none>;
 		};
-- 
2.52.0

From gregkh at linuxfoundation.org  Wed Dec 17 22:27:33 2025
From: gregkh at linuxfoundation.org (Greg Kroah-Hartman)
Date: Thu, 18 Dec 2025 07:27:33 +0100
Subject: [PATCH v9 2/2] usb: dwc3: Add Google Tensor SoC DWC3 glue driver
In-Reply-To: <CA+zupgyG4Nov0=jihSApp_3_0hy6YNZMkfOp6Q4-zmERFm10Ag@mail.gmail.com>
References: <20251205-controller-v9-0-9f158b18f979@google.com>
 <20251205-controller-v9-2-9f158b18f979@google.com>
 <2025120553-suffrage-divisive-5890@gregkh>
 <CA+zupgzL7v5MZDpxKDQQCqAZaqTdHbiG9-xTr+8RnigMFZJ_7Q@mail.gmail.com>
 <2025121728-reliably-crabgrass-2601@gregkh>
 <CA+zupgxZCyNonfNPbGnFymGGOQuaWR1TsL+hujTbH4DEcfEt9Q@mail.gmail.com>
 <CAD=FV=U63F-wxwKDo9be6_X2P2zp6aTBjNghZRbXX1rn4jFNyg@mail.gmail.com>
 <CA+zupgyG4Nov0=jihSApp_3_0hy6YNZMkfOp6Q4-zmERFm10Ag@mail.gmail.com>
Message-ID: <2025121847-swifter-pug-a1f7@gregkh>

On Wed, Dec 17, 2025 at 05:34:37PM -0800, Roy Luo wrote:
> On Wed, Dec 17, 2025 at 12:14?PM Doug Anderson <dianders at google.com> wrote:
> >
> > Hi,
> >
> > On Wed, Dec 17, 2025 at 11:18?AM Roy Luo <royluo at google.com> wrote:
> > >
> > > On Wed, Dec 17, 2025 at 5:24?AM Greg Kroah-Hartman
> > > <gregkh at linuxfoundation.org> wrote:
> > > >
> > > > On Thu, Dec 04, 2025 at 11:14:39PM -0800, Roy Luo wrote:
> > > > > On Thu, Dec 4, 2025 at 10:05?PM Greg Kroah-Hartman
> > > > > <gregkh at linuxfoundation.org> wrote:
> > > > > >
> > > > > > On Fri, Dec 05, 2025 at 02:26:38AM +0000, Roy Luo wrote:
> > > > > > > +config USB_DWC3_GOOGLE
> > > > > > > +     tristate "Google Platform"
> > > > > > > +     depends on ARCH_GOOGLE || COMPILE_TEST
> > > > > >
> > > > > > There is no ARCH_GOOGLE in the tree now, so how is this supposed to
> > > > > > work?  Shouldn't tools that check for "invalid config options" trigger
> > > > > > on this?
> > > > > >
> > > > > > thanks,
> > > > > >
> > > > > > greg k-h
> > > > >
> > > > > Hi Greg,
> > > > >
> > > > > The menuconfig looks like the following and it doesn't complain:
> > > > > | Symbol: ARCH_GOOGLE [=ARCH_GOOGLE]
> > > > > | Type  : unknown
> > > > > |
> > > > > | Symbol: PHY_GOOGLE_USB [=y]
> > > > > | Type  : tristate
> > > > > | Defined at drivers/phy/Kconfig:104
> > > > > |     Prompt: Google Tensor SoC USB PHY driver
> > > > > |     Depends on: ARCH_GOOGLE || COMPILE_TEST [=y]
> > > > >
> > > > > According to Kconfig documentation [1], the unknown symbol
> > > > > would simply be evaluated as an "n", which is what we want.
> > > > > "Convert the symbol into an expression. Boolean and tristate
> > > > > symbols are simply converted into the respective expression
> > > > > values. All other symbol types result in ?n?."
> > > > >
> > > > > In a different Kconfig documentation, an environment variable
> > > > > "KCONFIG_WARN_UNKNOWN_SYMBOLS" is there to detect
> > > > > undefined symbols in the "config input", but I can't find one that
> > > > > catches undefined symbols in the Kconfig tree itself.
> > > > >
> > > > > That is, the tool seems to allow this.
> > > > > However, if this turns out to be a major problem. I think we
> > > > > can either:
> > > > > - Remove ARCH_GOOGLE and leave COMPILE_TEST as
> > > > >   the only dependency. Then add ARCH_GOOGLE back
> > > > >   later once it's in the tree.
> > > >
> > > > Please do this.  I do not want to take patches that purposfully add
> > > > dependencies on config options that might, or might not, appear in the
> > > > future.  Please just remove all of the dependancies for now, as they are
> > > > not needed, right?
> > > >
> > > > thanks,
> > > >
> > > > greg k-h
> > >
> > > Greg,
> > >
> > > Yes, we can remove ARCH_GOOGLE for now.
> > > To clarify, we're not removing all of the dependencies, we still want
> > > to keep COMPILE_TEST for build tests, right?
> > > Please let me know if you think otherwise.
> >
> > I think you'd just remove all of them. Normally COMPILE_TEST just
> > allows folks to compile stuff even when they don't want the ARCH. We
> > can can add ARCH_GOOGLE back in later once the config exists.
> >
> > -Doug
> 
> Doug,
> 
> Thanks for chiming in. I'm hesitant to remove COMPILE_TEST
> because Greg specifically requested its inclusion in v7 [1].
> Also it seems beneficial to get some build coverage before
> ARCH_GOOGLE is officially added to the tree.
> Greg, could you clarify?

I wanted it in because it would not build without it on a non "google"
system.  But now, as that option isn't there, just don't have any
dependency, as it's obviously not needed.

thanks,

greg k-h


From linu.cherian at arm.com  Wed Dec 17 22:30:53 2025
From: linu.cherian at arm.com (Linu Cherian)
Date: Thu, 18 Dec 2025 12:00:53 +0530
Subject: [PATCH v1 03/13] arm64: mm: Implicitly invalidate user ASID
 based on TLBI operation
In-Reply-To: <20251216144601.2106412-4-ryan.roberts@arm.com>
References: <20251216144601.2106412-1-ryan.roberts@arm.com>
 <20251216144601.2106412-4-ryan.roberts@arm.com>
Message-ID: <aUOfnXnGVROEXH4r@a079125.arm.com>

Ryan,

On Tue, Dec 16, 2025 at 02:45:48PM +0000, Ryan Roberts wrote:
> When kpti is enabled, separate ASIDs are used for userspace and
> kernelspace, requiring ASID-qualified TLB invalidation by virtual
> address to invalidate both of them.
> 
> Push the logic for invalidating the two ASIDs down into the low-level
> tlbi-op-specific functions and remove the burden from the caller to
> handle the kpti-specific behaviour.
> 
> Co-developed-by: Will Deacon <will at kernel.org>
> Signed-off-by: Will Deacon <will at kernel.org>
> Signed-off-by: Ryan Roberts <ryan.roberts at arm.com>
> ---
>  arch/arm64/include/asm/tlbflush.h | 27 ++++++++++-----------------
>  1 file changed, 10 insertions(+), 17 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
> index c5111d2afc66..31f43d953ce2 100644
> --- a/arch/arm64/include/asm/tlbflush.h
> +++ b/arch/arm64/include/asm/tlbflush.h
> @@ -110,6 +110,7 @@ typedef void (*tlbi_op)(u64 arg);
>  static __always_inline void vae1is(u64 arg)
>  {
>  	__tlbi(vae1is, arg);
> +	__tlbi_user(vae1is, arg);
>  }
>  
>  static __always_inline void vae2is(u64 arg)
> @@ -126,6 +127,7 @@ static __always_inline void vale1(u64 arg)
>  static __always_inline void vale1is(u64 arg)
>  {
>  	__tlbi(vale1is, arg);
> +	__tlbi_user(vale1is, arg);
>  }
>  
>  static __always_inline void vale2is(u64 arg)
> @@ -162,11 +164,6 @@ static __always_inline void __tlbi_level(tlbi_op op, u64 addr, u32 level)
>  	op(arg);
>  }
>  
> -#define __tlbi_user_level(op, arg, level) do {				\
> -	if (arm64_kernel_unmapped_at_el0())				\
> -		__tlbi_level(op, (arg | USER_ASID_FLAG), level);	\
> -} while (0)
> -
>  /*
>   * This macro creates a properly formatted VA operand for the TLB RANGE. The
>   * value bit assignments are:
> @@ -435,8 +432,6 @@ static inline void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch)
>   * @stride:	Flush granularity
>   * @asid:	The ASID of the task (0 for IPA instructions)
>   * @tlb_level:	Translation Table level hint, if known
> - * @tlbi_user:	If 'true', call an additional __tlbi_user()
> - *              (typically for user ASIDs). 'flase' for IPA instructions
>   * @lpa2:	If 'true', the lpa2 scheme is used as set out below
>   *
>   * When the CPU does not support TLB range operations, flush the TLB
> @@ -462,6 +457,7 @@ static inline void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch)
>  static __always_inline void rvae1is(u64 arg)
>  {
>  	__tlbi(rvae1is, arg);
> +	__tlbi_user(rvae1is, arg);
>  }
>  
>  static __always_inline void rvale1(u64 arg)
> @@ -473,6 +469,7 @@ static __always_inline void rvale1(u64 arg)
>  static __always_inline void rvale1is(u64 arg)
>  {
>  	__tlbi(rvale1is, arg);
> +	__tlbi_user(rvale1is, arg);
>  }
>  
>  static __always_inline void rvaale1is(u64 arg)
> @@ -491,7 +488,7 @@ static __always_inline void __tlbi_range(tlbi_op op, u64 arg)
>  }
>  
>  #define __flush_tlb_range_op(op, start, pages, stride,			\
> -				asid, tlb_level, tlbi_user, lpa2)	\
> +				asid, tlb_level, lpa2)			\
>  do {									\
>  	typeof(start) __flush_start = start;				\
>  	typeof(pages) __flush_pages = pages;				\
> @@ -506,8 +503,6 @@ do {									\
>  		    (lpa2 && __flush_start != ALIGN(__flush_start, SZ_64K))) {	\
>  			addr = __TLBI_VADDR(__flush_start, asid);	\
>  			__tlbi_level(op, addr, tlb_level);		\
> -			if (tlbi_user)					\
> -				__tlbi_user_level(op, addr, tlb_level);	\
>  			__flush_start += stride;			\
>  			__flush_pages -= stride >> PAGE_SHIFT;		\
>  			continue;					\
> @@ -518,8 +513,6 @@ do {									\
>  			addr = __TLBI_VADDR_RANGE(__flush_start >> shift, asid, \
>  						scale, num, tlb_level);	\
>  			__tlbi_range(r##op, addr);			\
> -			if (tlbi_user)					\
> -				__tlbi_user(r##op, addr);		\
>  			__flush_start += __TLBI_RANGE_PAGES(num, scale) << PAGE_SHIFT; \
>  			__flush_pages -= __TLBI_RANGE_PAGES(num, scale);\


There are more __tlbi_user invocations in __flush_tlb_mm, __local_flush_tlb_page_nonotify_nosync
and __flush_tlb_page_nosync in this file. Should we not address them as well as 
part of this ?

--
Linu Cherian.


From amhetre at nvidia.com  Wed Dec 17 22:32:25 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Thu, 18 Dec 2025 12:02:25 +0530
Subject: [PATCH V7 2/4] iommu/arm-smmu-v3: Add device-tree support for
 CMDQV driver
In-Reply-To: <23df682e-6d08-4827-994e-1bbd89e5c903@nvidia.com>
References: <20251215064819.3345361-1-amhetre@nvidia.com>
 <20251215064819.3345361-3-amhetre@nvidia.com>
 <23df682e-6d08-4827-994e-1bbd89e5c903@nvidia.com>
Message-ID: <5e9a0ce1-a0ba-4a31-be95-99f349ec6028@nvidia.com>


On 12/18/2025 2:13 AM, Jon Hunter wrote:
>
>
> On 15/12/2025 06:48, Ashish Mhetre wrote:
>> Add device tree support to the CMDQV driver to enable usage on Tegra264
>> SoCs. The implementation parses the nvidia,cmdqv phandle from the SMMU
>> device tree node to associate each SMMU with its corresponding CMDQV
>> instance based on compatible string.
>>
>> Reviewed-by: Nicolin Chen <nicolinc at nvidia.com>
>> Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
>> ---
>> ? drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 32 +++++++++++++++++++++
>> ? 1 file changed, 32 insertions(+)
>>
>> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c 
>> b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> index dad3c0cb800b..0cd0013200f3 100644
>> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> @@ -4530,6 +4530,35 @@ static int arm_smmu_device_hw_probe(struct 
>> arm_smmu_device *smmu)
>> ????? return 0;
>> ? }
>> ? +#ifdef CONFIG_TEGRA241_CMDQV
>> +static void tegra_cmdqv_dt_probe(struct device_node *smmu_node,
>> +???????????????? struct arm_smmu_device *smmu)
>> +{
>> +??? struct platform_device *pdev;
>> +??? struct device_node *np;
>> +
>> +??? np = of_parse_phandle(smmu_node, "nvidia,cmdqv", 0);
>> +??? if (!np)
>> +??????? return;
>> +
>> +??? /* Tegra241 CMDQV driver is responsible for put_device() */
>> +??? pdev = of_find_device_by_node(np);
>> +??? of_node_put(np);
>> +??? if (!pdev)
>> +??????? return;
>> +
>> +??? smmu->impl_dev = &pdev->dev;
>> +??? smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
>> +??? dev_info(smmu->dev, "found companion CMDQV device: %s\n",
>> +???????? dev_name(smmu->impl_dev));
>
> This seems a bit noisy. dev_dbg?
>

This info print is similar to what is there in ACPI path as well.
It's only a single print per SMMU at boot time. Should I still change
it to dev_dbg?

>> +}
>> +#else
>> +static void tegra_cmdqv_dt_probe(struct device_node *smmu_node,
>> +???????????????? struct arm_smmu_device *smmu)
>> +{
>> +}
>> +#endif
>> +
>> ? #ifdef CONFIG_ACPI
>> ? #ifdef CONFIG_TEGRA241_CMDQV
>> ? static void acpi_smmu_dsdt_probe_tegra241_cmdqv(struct 
>> acpi_iort_node *node,
>> @@ -4635,6 +4664,9 @@ static int arm_smmu_device_dt_probe(struct 
>> platform_device *pdev,
>> ????? if (of_dma_is_coherent(dev->of_node))
>> ????????? smmu->features |= ARM_SMMU_FEAT_COHERENCY;
>> ? +??? if (of_device_is_compatible(dev->of_node, 
>> "nvidia,tegra264-smmu"))
>> +??????? tegra_cmdqv_dt_probe(dev->of_node, smmu);
>> +
>> ????? return ret;
>> ? }
>


From wei.fang at nxp.com  Wed Dec 17 22:36:47 2025
From: wei.fang at nxp.com (Wei Fang)
Date: Thu, 18 Dec 2025 06:36:47 +0000
Subject: [PATCH net] net: stmmac: fix the crash issue for zero copy XDP_TX
 action
In-Reply-To: <aUOddielBMkrmwhd@test-OptiPlex-Tower-Plus-7010>
References: <20251204071332.1907111-1-wei.fang@nxp.com>
 <aUKPHdtAPDnMqB7X@test-OptiPlex-Tower-Plus-7010>
 <AS8PR04MB849779A6392D543049A3F5BE88ABA@AS8PR04MB8497.eurprd04.prod.outlook.com>
 <aUOddielBMkrmwhd@test-OptiPlex-Tower-Plus-7010>
Message-ID: <PAXPR04MB8510499B65301187736D511088A8A@PAXPR04MB8510.eurprd04.prod.outlook.com>

> On 2025-12-17 at 18:19:19, Wei Fang (wei.fang at nxp.com) wrote:
> > > > -	res = stmmac_xdp_xmit_xdpf(priv, queue, xdpf, false);
> > > > -	if (res == STMMAC_XDP_TX)
> > > > +	/* For zero copy XDP_TX action, dma_map is true */
> > > > +	res = stmmac_xdp_xmit_xdpf(priv, queue, xdpf, zc);
> > > 	Seems stmmac_xdp_xmit_xdpf is using dma_map_single if we pass zc is
> > > true.
> > >         Ideally in case of zc, driver can use
> > > page_pool_get_dma_addr, may be you
> > >         need pass zc param as false. Please check
> > >
> >
> > No, the memory type of xdpf->data is MEM_TYPE_PAGE_ORDER0 rather than
> > MEM_TYPE_PAGE_POOL, so we should use dma_map_single().
> > Otherwise, it will lead to invalid mappings and cause the crash.
> >
> >
>  ACK, found below code bit confusing
> 		case STMMAC_XDP_CONSUMED:
>  			xsk_buff_free(buf->xdp);
> +			fallthrough;
> +		case STMMAC_XSK_CONSUMED:
>  			rx_dropped++;
> 
>      Ideally in case of STMMAC_XSK_CONSUMED, driver needs to call
> xsk_buff_free.
>      And in case of STMMAC_XDP_CONSUMED, driver needs to call
> xdp_return_frame.
>      May be you can move all buffer free logic to stmmac_rx_zc with above
> suggested
>      changes.

For zero copy, the xdp_buff is freed by xdp_convert_buff_to_frame()
when converting the xdp_xdp to xdp_frame. So STMMAC_XSK_CONSUMED
means the xdp_buff has been freed, it tells stmmac_rx_zc() no to free a
xdp_buff that has been freed.

I have added a comment for STMMAC_XSK_CONSUMED, see

+       } else if (res == STMMAC_XDP_CONSUMED && zc) {
+               /* xdp has been freed by xdp_convert_buff_to_frame(),
+                * no need to call xsk_buff_free() again, so return
+                * STMMAC_XSK_CONSUMED.
+                */
+               res = STMMAC_XSK_CONSUMED;
+               xdp_return_frame(xdpf);
+       }



From pankaj.gupta at nxp.com  Wed Dec 17 22:46:23 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Thu, 18 Dec 2025 12:16:23 +0530
Subject: [PATCH v22 0/7] firmware: imx: driver for NXP secure-enclave
Message-ID: <20251218-imx-se-if-v22-0-07418c872509@nxp.com>

The NXP's i.MX EdgeLock Enclave, a HW IP creating an embedded secure
enclave within the SoC boundary to enable features like
- HSM
- SHE
- V2X

Communicates via message unit with linux kernel. This driver is
enables communication ensuring well defined message sequence protocol
between Application Core and enclave's firmware.

Driver configures multiple misc-device on the MU, for multiple
user-space applications can communicate on single MU.

It exists on some i.MX processors. e.g. i.MX8ULP, i.MX93 etc.

-------
Changes in v22:
3/7 & 5/7
- reverted to previous change of using "__free(kfree)", by declare-and-initialize __free() vars next to their allocations.

1/7
- rename the se_fw.c to se_ctrl.c

2/7, 4/7, 5/7 & 7/7
- No changes.

Reference:
- Link to v21: https://lore.kernel.org/r/20251212-imx-se-if-v21-0-ee7d6052d848 at nxp.com

Changes in v21:
3/7
- smatch warning fixes.
- Added "COMPILE_TEST" into "depends on IMX_MBOX && ARCH_MXC && ARM64"
- removed "__free(kfree)" & added kfree();

5/7
- removed "__free(kfree)" & added kfree();

1/2, 2/7, 4/7, & 7/7
- No changes

Reference:
- Link to v20: https://lore.kernel.org/r/20251203-imx-se-if-v20-0-a04a25c4255f at nxp.com

Changes in v20:
5/7:
- adds a func "se_chk_tx_msg_hdr", to check the validity of the in-coming message from usersapce.

1/2, 2/7, 3/7, 4/7, 6/7 & 7/7
- No changes

Reference:
- Link to v19: https://lore.kernel.org/r/20250927-imx-se-if-v19-0-d1e7e960c118 at nxp.com

Changes in v19:

1/7
- Added 9 lines to the Introduction from line 73-82.

3/7
-  Update the commit message for " For i.MX9x SoC(s) there is at least one
dedicated ELE MU(s) for each world - Linux(one or more) and OP-TEE OS (one or
more), that needs to be shared between them.."

Reference:
- Link to v18: https://lore.kernel.org/r/20250619-imx-se-if-v18-0-c98391ba446d at nxp.com

Changes in v18:

1/7
- Wrap both diagrams above in literal code block by using double-colon

3/7 & 5/7
- Collected Frank's R-b tag.

2/7, 4/7, 6/7 & 7/7
- No changes

Reference:
- Link to v17: https://lore.kernel.org/r/20250426-imx-se-if-v17-0-0c85155a50d1 at nxp.com

Changes in v17:
- Changes to 3/7 & 5/7: to wrap code text at 80 character whereever possible.

Reference:
- Link to v16: https://lore.kernel.org/r/20250409-imx-se-if-v16-0-5394e5f3417e at nxp.com

Changes in v16:
- commit 3/7 and 4/7 are moved to end commits making them as 6/7 and 7/7 respectively.
- No change in 1/7 & 2/7.

7/7
- Collected Frank's R-b tag.

6/7
- commit message is updated to wrap at 75 characters.

5/7
- func add_b_desc_to_pending_list, removed the initialization of b_desc to
  NULL.
- variable timeout in func ele_msg_rcv(), is renamed to timeout_ms.
- struct se_if_priv, member variable se_rcv_msg_timeout, is renamed to
  se_rcv_msg_timeout_ms.
- in func load_firmware, move the label exit after dma_free_coherent.

4/7
- commit message is updated to wrap at 75 characters.

3/7
- ele_debug_dump, updated the assignment of keep_logging.
- ele_fw_authenticate function definition is updated to take two address
  as arguments.

Reference:
- Link to v15: https://lore.kernel.org/r/20250407-imx-se-if-v15-0-e3382cecda01 at nxp.com

Changes in v15:
- Patch 3/6 is split into two:
  - 3/7: arm64: dts: imx8ulp-evk: add reserved memory property
  - 4/7: arm64: dts: imx8ulp: add nxp secure enclave firmware
- No change in 1/7 & 2/7.

7/7
- removed the se_intance_id structure member variable.
- replace variable name from wait to timeout.
- used 'goto' to follow the common exit path calling "release_firmware(fw);" in case of error path.
- removed TBD string.
- Used ARRAY_SIZE(pending_lists).
- moved init_device_context after init_misc_device_context.
- defined err as long to avoid force convert in func
- added se_rcv_msg_timeout to priv, to control probe/suspend/resume per interface.

6/7
- removed the se_intance_id structure member variable.
- Added dev_ctx to the structure se_clbk_handle, too.
- Collected Frank's R-b tag.

5/7
- removed the se_intance_id structure member variable.
- since added se_if_probe_cleanup to devm, se_if_remove() is redundant. hence removed it.
- rename se_add_msg_chksum to se_get_msg_chksum
- added check if msg-size is 4 byte aligned.
- Fixed multiline comments.
- ele_debug_dump api is updated as part of comment disposition like single setting of flag "keep_logging" & adding if (ret).
- moved dev_err to dev_dbg, for imem save/restore functions.
- moved func get_se_if_name, from 7/7 to here.

3/7
- Updated the commit message.
- split the current patch into two:
  -- 3/7 for board dts, and
  -- 4/7 for chip dts

Reference:
- Link to v14: https://lore.kernel.org/r/20250327-imx-se-if-v14-0-2219448932e4 at nxp.com

Changes in v14:

- Patch 5/5 is split into two:
  - firmware: drivers: imx: adds miscdev
  - Introduce dev-ctx dedicated to private.
    -- Base patch before enabling misc-device context, to have the send-receive path, based on device context.
- No change in 1/6 & 2/6.
- Copied change logs from individual commits.

6/6
- moved definition of func se_load_firmware, from 4/6 patch to this patch.
- split init_device_context to init_misc_device_context.
- Different value of se_rcv_msg_timeout is required to be set. Receiving the response of 4K RSA operation can to take upto 3 minutes.
  This long value cannot be set during Linux: boot-up and suspend-resume.
  Hence, it will be set to default small-value during Linux: boot-up and suspend-resume.
- func se_dev_ctx_cpy_out_data(), in either case: do_cpy true or false, the clean-up needs to be done and it is implemented like wise.
  Once do_cpy is false, no need to continue copy to user buffer. But continue to do clean-up. hence cannot return.
  And every dev-ctx operation is done after taking the lock. Hence, two operations with same dev-ctx is not possible in parallel.
- func "init_device_context", for 0th misc dev_ctx, which is created at the time of probe, the device memory management is required. hence there is a difference.
- func "init_device_context", dev_er is replaced with return dev_err_probe.
- func "init_device_context", devm_add_action is replaced by devm_add_action_reset.
- removed type-cast from func se_ioctl_get_se_soc_info_handler().
- used scoped_cond_guard(mutex, _intr, return -EBUSY, &<mutex_lock>)
- combined dev_err & dev_dbg to one dev_err in se_if_fops_read().
- removed the structure member "se_shared_mem_mgmt->secure_mem".

4/6
- trimmed the ele_fetch_soc_info.
- removed the function ptr "se_info->se_fetch_soc_info" and replaced with ele_fetch_soc_info.
- moved definition of func se_load_firmware, to 6/6 patch.
- Different SoC, different ways to fetch soc_info. Generic function declaration for ele_fetch_soc_info() is needed. Hence wrapping ele_get_info() in it.
- Updated Kconfig help text for assertive tone.
- func ele_debug_dump is updated, to remove constructing the format string.
- removed the macro usage for SOC_ID_MASK.
- used low case hex number.
- Condition will never occur, where msg_len satisfy the following condition "msg_len % 4 != 0". Err msg is added if it occurs.
- Function description is added to se_add_msg_crc.
- timeout is added to function ele_msg_rcv, in 5/5 patch.
- local variable "header" is initialized with "tx_msg" and replaced "return err" with "return tx_msg_sz" in func ele_msg_send().
- replace function name from "exception_for_size" to "check_hdr_exception_for_sz"
- replaced "return ret > 0 ? 0 : -1;" with "return ret > 0 ? 0 : ret;" in func "se_save_imem_state".
- func "se_restore_imem_state", to return if the condition is false to proceed.
- removed casting by (void *).
- removed devm_kasprintf and done direct allocatiion for attr->soc_id = "i.MX8ULP" & attr->soc_id = "i.MX8ULP", & attr->family.
- Followed Reverse christmas tree order, whereever missing.
- There is no return if ele_fw_authenticate fails. Execution flow continue forward and execute the fucn dma_free_coherent().
- The loop is not for retry. The loop is needed to load secondary fw followed by loading primary fw, first. This is the case when ELE also got reset.
- dev_err_probe is corrected in func "se_if_request_channel".

3/6
-

Reference:
- Link to v13: https://lore.kernel.org/r/20250311-imx-se-if-v13-0-9cc6d8fd6d1c at nxp.com

Changes in v13:

5/5
- Updated the commit message for imperative mood.
- Remove the usage of macros- NODE_NAME, GET_ASCII_TO_U8, GET_IDX_FROM_DEV_NODE_NAME.
- Clean-up the return path by replacing "ret = -<err>; return ret;" with "return -<err>;"
- Clean-up the return path by replacing "ret = -<err>; goto exit;" with "return -<err>;"
- Removed goto statements from the entire driver, where there is no common code at function's exit.
- Fixes the check-patch erros reported with flag "--strict"
- Replaced devm_add_action, with devm_add_action_or_reset
- Removed the un-necesary and obvious code comments.
- Removed dev_probe_err at the exit of function se_if_probe().

4/5
- Clean-up the return path by replacing "ret = -<err>; return ret;" with "return -<err>;"
- Clean-up the return path by replacing "ret = -<err>; goto exit;" with "return -<err>;"
- Removed goto statements from the entire driver, where there is no common code at function's exit.
- fixes the check-patch erros reported with flag "--strict"
- removed the un-necesary and obvious code comments.
- variable received msg timeout to be different at boot-up & suspend/resume and send/recv ioctlis.

3/5
- compatible string is modified from "fsl,imx8ulp-se" to "fsl,imx8ulp-se-ele-hsm".
- updated the alias name.

2/5
- compatible string is modified from "fsl,imx8ulp-se" to "fsl,imx8ulp-se-ele-hsm".
- compatible string is modified from "fsl,imx93-se" to "fsl,imx93-se-ele-hsm".
- compatible string is modified from "fsl,imx95-se" to "fsl,imx95-se-ele-hsm".
- Mis-understood the +1 from Conor. Hence dropped the Reviewed-by tag.
- Collected Rob's R-b tag on v7 (https://lore.kernel.org/all/172589152997.4184616.5889493628960272898.robh at kernel.org/)

1/5
- No change

Reference:
- Link to v12: https://lore.kernel.org/r/20250120-imx-se-if-v12-0-c5ec9754570c at nxp.com

Changes in v12:

5/5
- increased the wait-timeout.

4/5
- rename flag "handle_susp_resm" to "imem_mgmt"
- moved the buffer allocation ot load_fw->imem.buf, to se_probe_if.
- setting imem state at initialization.

3/5
- No change

2/5
- No change

1/5
- No change

Reference:
- Link to v11: https://lore.kernel.org/r/20241220-imx-se-if-v11-0-0c7e65d7ae7b at nxp.com

Changes in v11:

5/5
- devname is constructed by concatinating get_se_if_name(se_if_id) & se_if_instance_id.
- ele_rcv_msg(), is updated to add the wait_interruptible_timeout for the non-NVM-Daemon message exchanges, such that in case of no response from FW,
  Linux donot hangs.
- added a new helper function get_se_if_name(), to return the secure-enclave interface owner's name string.
- added a new helper function get_se_soc_id(), to return the secure-enclave's SoC id.

4/5
- moved the se_if_node_info member "soc_register", to the struct "se_if_node_info_list"; as soc registration done once, not per interface.
- moved the se_if_node_info member "se_fetch_soc_info", to the struct "se_if_node_info_list"; as soc info fetching is done once, not per interface.
- Added two member variable se_if_id and se_if_instance_id to struct se_if_defines.
- removed the member "se_name" from struct "se_if_node_info". Rather, it will constructed by concatinating get_se_if_name(se_if_id) & se_if_instance_id.
- moved the static global variable "se_version", to the newly created structure "struct se_var_info".
- moved the member "struct se_fw_load_info load_fw" of "se_if_node_info_list", to the newly created structure "struct se_var_info".
- Replaced RUNTIME_PM_OPS with SET_SYSTEM_SLEEP_PM_OPS, in power-managment ops.

3/5
- No change

2/5
- No change

1/5
- No change

Reference:
- Link to v10: https://lore.kernel.org/r/20241104-imx-se-if-v10-0-bf06083cc97f at nxp.com

v10: firmware: imx: driver for NXP secure-enclave

Changes in v10:
5/5
- replaced the u8, u16, u32, u64, with __u8, __u16, __u32, __u64 in
  'include/uapi/linux/se_ioctl.h'.

4/5
- No change

3/5
- No change

2/5
- No change

1/5
- No change

Reference:
- Link to v9: https://lore.kernel.org/r/20241016-imx-se-if-v9-0-fd8fa0c04eab at nxp.com

Changes in v9:

4/5
- change se_if_remove function signature, required after rebase to v6.12-rc1.
- move the info->macros to a structure "struct se_if_defines if_defs".
- Removed "info" from "struct se_if_defines if_defs".
- Moved "mem_pool" from "struct se_if_defines if_defs" to "priv".
- Fetching "info" using container-of.

5/5
- Fetching "info" using container-of.
- Fixed issue reported by sparse.

Reference:
- Link to v8: https://lore.kernel.org/r/20241015-imx-se-if-v8-0-915438e267d3 at nxp.com

Changes in v8:

5/5
- Remove the check for SE_IF_CTX_OPENED.
- replaced dev_ctx->priv-dev, priv->dev, whereever possible.
- func "if_misc_deregister" moved before func "init_device_context".
- func "init_device_context" before func "se_ioctl_cmd_snd_rcv_rsp_handler".
- func "se_if_fops_write" and "se_if_fops_read", are moved after func "se_ioctl_get_mu_info".
- non static functions "se_dev_ctx_cpy_out_data, se_dev_ctx_shared_mem_cleanup & init_device_context" are moved static and local scope.
- Removed back & forth between the two structs "struct se_if_device_ctx *dev_ctx" and "struct se_shared_mem_mgmt_info *se_shared_mem_mgmt"
- removed the NULL check for bdesc.
- fops_open, is corrected for acquiring the fops_lock.
- Fops_close, mutex unlock is removed. Infact check for waiting_rsp_clbk_hdl.dev_ctx, is removed.
- sema_init(&dev_ctx->fops_lock, 1);, replaced with Mutex.
- structure member se_notify, is removed.

4/5
- removed initializing err to zero in func ele_fetch_soc_info(),
- replaced 'return 0', with 'goto exit', if the condition (!priv->mem_pool) is true.
- replaced "struct *dev" with "struct se_if_priv *priv", in base_message API(s) and others.
- Created a separate structure "struct se_if_defines" to maintain interface's fixed values like cmd_tag, rsp_tag, success_tag etc.
- removed the macros "WORD_SZ", "SOC_VER_MASK", "DEFAULT_IMX_SOC_VER", "RESERVED_DMA_POOL".
- Added handling for "ctrl+c", by postponing the interrupt, till the response to the "command in flight" is received.
- Removed the mutext lock "se_if_lock".
- furnction prototype for "se_save_imem_state" and "se_restore_imem_state", is changed to pass "imem" by reference.
- Added a new structure "struct se_fw_load_info", dedicated to contain FW loading relevant info. It is a member of struct info_list.
- split "imem_mgmt_file_in_rfs" into two "prim_fw_nm_in_rfs" and "seco_fw_nm_in_rfs", to be part of "struct se_fw_load_info".
- moved the function "se_load_firmware" prior to func "if_mbox_free_channel".
- function "se_load_firmware" is updated to use "request_firmware", instead of "request_firmware_no_wait".
- function "se_load_firmware" is updated to load "primary" fw image, if the imem_state is not BAD. Then load the "secondary FW" image.
- Added a new mutex_lock in the function "se_load_firmware", for ensuring FW loading done once, when there are multiple application are in play.
- instead of "wait_queue_head_t wq", used "sruct completion".
- add devm_add_action with action as se_if_probe_cleanup.

Reference:
- Link to v7: https://lore.kernel.org/r/20240904-imx-se-if-v7-0-5afd2ab74264 at nxp.com

Changes in v7:

5/5
- struct se_clbk_handle, is added with a member struct se_if_device_ctx *dev_ctx.
- func call to ele_miscdev_msg_rcv() & ele_miscdev_msg_send(), are removed.
- func se_ioctl_cmd_snd_rcv_rsp_handler(), is modified to remove the func call to ele_miscdev_msg_rcv() & ele_miscdev_msg_send()
- func se_ioctl_cmd_snd_rcv_rsp_handler is callig func ele_msg_send_rcv(), instead.
- Mutext "se_cmd_if_lock", handling is removed from this patch.
- func ele_miscdev_msg_send() is replaced with func ele_msg_send(), in fops_write.
- func ele_miscdev_msg_rcv() is replaced with func ele_msg_rcv(), in fops_read.
- fops_open is modified to create the new dev_ctx instance (using func init_device_context()), which is not registered as miscdev.
- Only one dev_ctx is registered as miscdev and its reference is stored in the struct se_if_priv, as priv_dev_ctx.
- Separate func cleanup_se_shared_mem() & func init_se_shared_mem(), for shared memory handling part of struct dev_ctx.
- Input param for func(s) ele_msg_rcv(), ele_msg_send() & ele_msg_send_rcv(), is replaced from struct se_if_priv to struct se_if_device_ctx.

4/5
- A new structure is defined name struct "se_clbk_handle", to contain members processed in mailbox call-back function.
- "struct se_if_priv" is modified to contain the two structures of "se_clbk_handle" - waiting_rsp_clbk_hdl & cmd_receiver_clbk_hdl.
- func ele_msg_rcv() is modified to take a new additional input reference param "struct se_clbk_handle *se_clbk_hdl".
- func ele_msg_send() is modified to take a new additional input tx_msg_sz.
- func ele_msg_send_rcv(), is modified to take 2 more inputs - tx_msg_sz & exp_rx_msg_sz.
- func se_val_rsp_hdr_n_status(), is modified to take input of rx_msg buffer, instead of header value, as input param.
- each caller of the func ele_msg_send_rcv(), is sending these two additional input params.
- func se_if_callback(), is modified to work on two structures of "se_clbk_handle" - waiting_rsp_clbk_hdl & cmd_receiver_clbk_hdl.
- Variable "max_dev_ctx", is removed from info & priv struture, as well its usage.
- New member variable "se_img_file_to_load", is added to structure "priv".
- Other member variables - rx_msg(ptr), rx_msg_sz, completion done & list of dev_ctxs, is removed from priv struture, along with their usage.
- func se_resume(), updated to wakeup the two "wq", part of "struct se_clbk_handle": priv->waiting_rsp_clbk_hdl & priv->cmd_receiver_clbk_hdl.

3/5
- Node name is changed from senclave-firmware at 0 to "secure-enclave"

2/5
- Node name is changed to "secure-enclave".

Reference:
- Link to v6: https://lore.kernel.org/r/20240722-imx-se-if-v6-0-ee26a87b824a at nxp.com

Changes in v6:

5/5
- replaced scope_gaurd with gaurd.

4/5
- replaced scope_gaurd with gaurd.
- remove reading the regs property from dtb.
- Added NULL check for priv data fetched from device, as a sanity check, for ele_base_msg apis)

3/5
- replace firmware with senclave-firmware.

2/5
- replace firmware with senclave-firmware.
- drop description for mbox
- Replaced "items:" with maxItems:1 for "memory-region"
- Replaced "items:" with maxItems:1 for "sram"
- remove regs property.
- remove "$nodename"

Reference:
- Link to v5: https://lore.kernel.org/r/20240712-imx-se-if-v5-0-66a79903a872 at nxp.com

Changes in v5:

2/5
- updated the description of mboxes
- updated the description & items for mbox-names.
- updated the description of memory-region
- move "additional properties: false" after allOf block.
- removed other example except one.

4/5
- Corrected the indentation in Kconfig.
- info members:mbox_tx_name & mbox_rx_name, are replaced with macros.

5/5
- Replaced "for  secure enclaves", with "for secure enclaves"
- Replaced "user space" with "userspace".
- End the line "[include]<linux/firmware/imx/ele_mu_ioctl.h>" with a period.

Reference:
- Link to v4: https://lore.kernel.org/r/20240705-imx-se-if-v4-0-52d000e18a1d at nxp.com

Changes in v4:

1/5
a. Removed - from EdgeLock Enclave.

b. Removed , after "Each of the above feature,"

c. replace "can exists" with "can exist".

d.
-messaging units(MU) per SE. Each co-existing 'se' can have one or multiple exclusive
-MU(s), dedicated to itself. None of the MU is shared between two SEs.
+messaging units(MU) per SE. Each co-existing SE can have one or multiple exclusive
+MUs, dedicated to itself. None of the MU is shared between two SEs.
 Communication of the MU is realized using the Linux mailbox driver.

e.
-All those SE interfaces 'se-if' that is/are dedicated to a particular SE, will be
-enumerated and provisioned under the very single 'SE' node.
+Although MU(s) is/are not shared between SE(s). But for SoC like i.MX95 which has
+multiple SE(s) like HSM, V2X-HSM, V2X-SHE; all the SE(s) and their interfaces 'se-if'
+that is/are dedicated to a particular SE will be enumerated and provisioned using the
+single compatible node("fsl,imx95-se").

f. Removed ",". Replaced for "Each 'se-if'," with "Each se-if'.

g. removed ","
-  This layer is responsible for ensuring the communication protocol, that is defined
+  This layer is responsible for ensuring the communication protocol that is defined

h. removed "-"
-  - FW can handle one command-message at a time.
+  - FW can handle one command message at a time.

i.
-  Using these multiple device contexts, that are getting multiplexed over a single MU,
-  user-space application(s) can call fops like write/read to send the command-message,
-  and read back the command-response-message to/from Firmware.
-  fops like read & write uses the above defined service layer API(s) to communicate with
+  Using these multiple device contexts that are getting multiplexed over a single MU,
+  userspace application(s) can call fops like write/read to send the command message,
+  and read back the command response message to/from Firmware.
+  fops like read & write use the above defined service layer API(s) to communicate with
   Firmware.

j. Uppercase for word "Linux".

2/5
a. Rephrased the description to remove list of phandles.

b. Moved required before allOf:
+required:
+  - compatible
+  - reg
+  - mboxes
+  - mbox-names
+
+additionalProperties: false
+
 allOf:

c. replaced not: required: with properties: <property-name>: false.
   # memory-region
-      not:
-        required:
-          - memory-region
+      properties:
+        memory-region: false

   # sram
-    else:
-      not:
-        required:
-          - sram

d. Reduced examples. keeping example of i.MX95.
e. node-name is changed to "firmware@<hex>"

3/5
- node name changed to "firmware@<hex>".

4/5
- used sizeof(*s_info)
- return early, rather than doing goto exit, in ele_get_info().
- Use upper_32_bits() and lower_32_bits()
- use rx_msg here instead of priv->rx_msg
- Moved the status check to validate_rsp_hdr. Rename the function to "se_val_rsp_hdr_n_status"
- typecasting removed header = (struct se_msg_hdr *) msg;
- Converted the API name with prefix imx_ele_* or imx_se_*, to ele_* and se_*, respectively.
- Removed the functions definition & declaration for: free_phybuf_mem_pool() & get_phybuf_mem_pool()
- removed the mbox_free_channel() calls from clean-up.
- Flag "priv->flags" is removed.
- Converted the int se_if_probe_cleanup() to void se_if_probe_cleanup().
- Replaced NULL initialization of structure members: priv->cmd_receiver_dev & priv->waiting_rsp_dev , with comments.
- Removed the function's declaration get_phy_buf_mem_pool1

5/5
Changes to Documentation/ABI/testing/se-cdev.
a. Removed "-" from "secure-enclave" and "file-descriptor".

b. Removed "-" from "shared-library"

c. Replaced "get" with "getting".

d. Added description for the new IOCTL "send command and receive command response"

e. Replaced "wakeup_intruptible" with "wait_event_interruptible"

f. Removed ";"

g. Removd "," from "mailbox_lock,"

h. Replaced "free" with "frees"

i. In mailbox callback function, checking the buffer size before
copying.

Reference:
- Link to v3: https://lore.kernel.org/r/20240617-imx-se-if-v3-0-a7d28dea5c4a at nxp.com

Changes in v3:
5/5:
- Initialize tx_msg with NULL.
- memdup_user() returns an error pointer, not NULL. correct it by adding check for err_ptr.
- new IOCTL is added to send & recieve the message.
- replaced the while loop till list is empty, with list_for_each_entry.
- replaced __list_del_entry, with list_del.
- Removed the dev_err message from copy to user.
- Removed the casting of void *.
- corrected the typcasting in copy to user.
- removed un-necessary goto statement.
- Removed dead code for clean-up of memory.
- Removed un-mapping of secured memory
- Passing se_if_priv structure to init_device_context.
- Updated the below check to replace io.length with round_up(io.length).
	if (shared_mem->size < shared_mem->pos|| io.length >= shared_mem->size - shared_mem->pos)
- Created a function to cleanup the list of shared memory buffers.
- Used list_for_each_entry_safe(). created a separate functions: se_dev_ctx_cpy_out_data() & se_dev_ctx_shared_mem_cleanup()

4/5
- Changed the compatible string to replace "-ele", to "-se".
- Declaration of imx_se_node_info, is done as const in the whole file
- Remove the unused macros from ele_base_msg.h
- Remove the function declaration get_phy_buf_mem_pool1, from the header file.
- Replace the use of dmam_alloc_coherent to dma_alloc_coherent
- Check for function pointer, before calling the fucntion pointer in imx_fetch_se_soc_info
- Removed the unused flag for SE_MU_IO_FLAGS_USE_SEC_MEM.
-  Removed the unused macros WORD_SZ
- instead of struct device *dev, struct se_if_priv *priv, is used as argument to the funtions:se_save_imem_state, se_restore_imem_state, imx_fetch_se_soc_info
- Removed ret from validate_rsp_hdr.
- changed the prefix of the funtion: plat_add_msg_crc and plat_fill_cmd_msg_hdr.
- indentation correction for info structures.
- remove the check for priv not null from se_if_probe_cleanup
- Removed the casting of void *.
- se_load_firmware function is corrected for not freeing the buffer when allocation fails.
- Checking if get_imx_se_node_info() can return NULL, in se_if_probe()
- imem.size has type u32. return value from se_save_imem_state() will be assigned to imem.size in case of success only.
- removed the flag un-setting in case of failure. priv->flags &= (~RESERVED_DMA_POOL);
- removed the function call for devm_of_platform_populate(dev);
- Checking for not-NULL,  before calling the funtion pointer se_fetch_soc_info.
- Removed the checking for reserved memory flag, before freeing up the reserved memory, in se_probe_if_cleanup.

3/5
- Changed the compatible string to replace "-ele", to "-se".

2/5
- to fix the warning error, replaced the "-ele" & "-v2x" in compatible string, to "-se".
- Added an example for ele at 0 for compatible string "fsl,imx95-se"

Reference
- Link to v2: https://lore.kernel.org/r/20240523-imx-se-if-v2-0-5a6fd189a539 at nxp.com

Changes in v2:

4/4
- Split this patch into two: 1. base driver & 2. Miscdev
- Initialize the return variable "err" as 0, before calling 'return err', in the file ele_common.c
- Fix the usage of un-iniitialized pointer variable, by initializing them with NULL, in ele_base_msg.c.
- Fix initializing the ret variable, to return the correct error code in case of issue.
- replaced dmam_alloc_coherent with dma_alloc_coherent.
- Replace the use of ELE_GET_INFO_READ_SZ, with sizeof(soc_info).
- Replaced -1 with -EPERM
- Removed the safety check on func-input param, in ele_get_info().
- fix the assigning data[1] with lower 32 address, rather than zero, for ele_fw_authenticate API.
- Correctly initializing the function's return error code, for file  ele_base_msg.c.
- replaced 'return' with 'goto'.
- Use length in bytes.
- Corrected the structure se_msg_hdr.
- Moved setting of rx_msg  to priv, into the function imx_ele_msg_send_rcv
- Will add lockdep_assert_held, to receive path, in v2.
- corrected the spacing at "ret  = validate_rsp_hdr"
- FIELD_GET() used for RES_STATUS
- Re-write the structure soc_info, matching the information provided in response to this api.
- The "|" goes to the end of the previous line.
- Moved the locking and unlocking of the command lock to the caller of the function.
- removed the safety check for device private data.
- Structure memory reference, used to read message header.
- In the interrupt call back function, remove assigning waiting_rsp_dev to NULL, in case of response message rcv from FW.
- do while removed.
- replaced BIT(1) for RESERVED_DMA_POOL, to BIT(0)
- The backslash is removed while assigning the file name with absolute path to structure variable.fw_name_in_rfs =.
- Update the 'if' condition by removing "idx < 0".
- mbox_request_channel_byname() uses a "char" for the name not a u8. Corrected.
- devm managed resources, are not cleaned now, in function se_probe_if_cleanup
- Used dev_err_probe().
- Used %pe to print error string.
- remove "__maybe_unused" for "struct platform_device *enum_plat_dev __maybe_unused;"
- used FIELD_GET(), for  RES_STATUS. Removed the use of MSG_TAG, MSG_COMMAND, MSG_SIZE, MSG_VER.
- Depricated the used of member of struct se_if_priv, bool no_dev_ctx_used;
- Moved the text explaing the synchronization logic via mutexes, from patch 1/4 to se_ctrl.h.
- removed the type casting of info_list = (struct imx_se_node_info_list *) device_get_match_data(dev->parent);
- Used static variable priv->soc_rev in the se_ctrl.c, replaced the following condition: if (info_list->soc_rev) to if (priv->soc_rev) for checking if this flow is already executed or not.
- imx_fetch_soc_info will return failure if the get_info function fails.
- Removed devm_free from imx_fetch_soc_info too.

3/3
- Made changes to move all the properties to parent node, without any child node.

2/4
- Use Hex pattern string.
- Move the properties to parent node, with no child node.
- Add i.MX95-ele to compatible nodes to fix the warning "/example-2/v2x: failed to match any schema with compatible: ['fsl,imx95-v2x']"

1/1
- Corrected the spelling from creats to creates.
- drop the braces around the plural 's' for interfaces
- written se in upper case SE.
- Replace "multiple message(s)" with messages.
- Removed too much details about locks.

Testing
- make CHECK_DTBS=y freescale/imx8ulp-evk.dtb;
- make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j8  dt_binding_check DT_SCHEMA_FILES=fsl,imx-se.yaml
- make C=1 CHECK=scripts/coccicheck drivers/firmware/imx/*.* W=1 > r.txt
- ./scripts/checkpatch.pl --git <>..HEAD
- Tested the Image and .dtb, on the i.MX8ULP.

Reference
- Link to v1: https://lore.kernel.org/r/20240510-imx-se-if-v1-0-27c5a674916d at nxp.com

---
Pankaj Gupta (7):
      Documentation/firmware: add imx/se to other_interfaces
      dt-bindings: arm: fsl: add imx-se-fw binding doc
      firmware: imx: add driver for NXP EdgeLock Enclave
      firmware: imx: device context dedicated to priv
      firmware: drivers: imx: adds miscdev
      arm64: dts: imx8ulp: add secure enclave node
      arm64: dts: imx8ulp-evk: add reserved memory property

 Documentation/ABI/testing/se-cdev                  |   43 +
 .../devicetree/bindings/firmware/fsl,imx-se.yaml   |   91 ++
 .../driver-api/firmware/other_interfaces.rst       |  131 +++
 arch/arm64/boot/dts/freescale/imx8ulp-evk.dts      |   12 +-
 arch/arm64/boot/dts/freescale/imx8ulp.dtsi         |   11 +-
 drivers/firmware/imx/Kconfig                       |   13 +
 drivers/firmware/imx/Makefile                      |    2 +
 drivers/firmware/imx/ele_base_msg.c                |  298 +++++
 drivers/firmware/imx/ele_base_msg.h                |  115 ++
 drivers/firmware/imx/ele_common.c                  |  373 +++++++
 drivers/firmware/imx/ele_common.h                  |   51 +
 drivers/firmware/imx/se_ctrl.c                     | 1162 ++++++++++++++++++++
 drivers/firmware/imx/se_ctrl.h                     |  128 +++
 include/linux/firmware/imx/se_api.h                |   14 +
 include/uapi/linux/se_ioctl.h                      |   97 ++
 15 files changed, 2538 insertions(+), 3 deletions(-)
---
base-commit: 4a26e7032d7d57c998598c08a034872d6f0d3945
change-id: 20240507-imx-se-if-a40055093dc6

Best regards,
-- 
Pankaj Gupta <pankaj.gupta at nxp.com>



From pankaj.gupta at nxp.com  Wed Dec 17 22:46:24 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Thu, 18 Dec 2025 12:16:24 +0530
Subject: [PATCH v22 1/7] Documentation/firmware: add imx/se to
 other_interfaces
In-Reply-To: <20251218-imx-se-if-v22-0-07418c872509@nxp.com>
References: <20251218-imx-se-if-v22-0-07418c872509@nxp.com>
Message-ID: <20251218-imx-se-if-v22-1-07418c872509@nxp.com>

Documents i.MX SoC's Service layer and C_DEV driver for selected SoC(s)
that contains the NXP hardware IP(s) for Secure Enclaves(se) like:
- NXP EdgeLock Enclave on i.MX93 & i.MX8ULP

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
---
Changes from v21 to v22
- rename the se_fw.c to se_ctrl.c
---
 .../driver-api/firmware/other_interfaces.rst       | 131 +++++++++++++++++++++
 1 file changed, 131 insertions(+)

diff --git a/Documentation/driver-api/firmware/other_interfaces.rst b/Documentation/driver-api/firmware/other_interfaces.rst
index 06ac89adaafb..cbd425c5a11d 100644
--- a/Documentation/driver-api/firmware/other_interfaces.rst
+++ b/Documentation/driver-api/firmware/other_interfaces.rst
@@ -49,3 +49,134 @@ of the requests on to a secure monitor (EL3).
 
 .. kernel-doc:: drivers/firmware/stratix10-svc.c
    :export:
+
+NXP Secure Enclave Firmware Interface
+=====================================
+
+Introduction
+------------
+The NXP's i.MX HW IP like EdgeLock Enclave, V2X etc., creates an embedded secure
+enclave within the SoC boundary to enable features like
+ - Hardware Security Module (HSM)
+ - Security Hardware Extension (SHE)
+ - Vehicular to Anything (V2X)
+
+Each of the above feature is enabled through dedicated NXP H/W IP on the SoC.
+On a single SoC, multiple hardware IP (or can say more than one secure enclave)
+can exist.
+
+NXP SoCs enabled with the such secure enclaves(SEs) IPs are:
+i.MX93, i.MX8ULP
+
+To communicate with one or more co-existing SE(s) on SoC, there is/are dedicated
+messaging units(MU) per SE. Each co-existing SE can have one or multiple exclusive
+MUs, dedicated to itself. None of the MU is shared between two SEs. Communication
+of the MU is realized using the mailbox driver. Each secure enclave can cater to
+multiple clients by virtue of these exclusive MUs. Also, they can distinguish
+transactions originating from these clients based on the MU used and core security
+state. The communication between the clients and secure enclaves is in form of
+command/response mechanism. Each client could expose specific set of secure enclave
+features to the higher layers, based on the commands supported by that client. For
+example, the secure enclave could simultaneously support an OPTEE TA and Linux
+middleware as clients. Each of these clients can expose specific set of secure
+enclave features based on the command set supported by them.
+
+NXP Secure Enclave(SE) Interface
+--------------------------------
+Although MU(s) is/are not shared between SE(s). But for SoC like i.MX95 which has
+multiple SE(s) like HSM, V2X-HSM, V2X-SHE; all the SE(s) and their interfaces 'se-if'
+that is/are dedicated to a particular SE will be enumerated and provisioned using the
+single compatible node("fsl,imx95-se").
+
+Each 'se-if' comprise of twp layers:
+- (C_DEV Layer) User-Space software-access interface.
+- (Service Layer) OS-level software-access interface.
+
+::
+   +--------------------------------------------+
+   |            Character Device(C_DEV)         |
+   |                                            |
+   |   +---------+ +---------+     +---------+  |
+   |   | misc #1 | | misc #2 | ... | misc #n |  |
+   |   |  dev    | |  dev    |     | dev     |  |
+   |   +---------+ +---------+     +---------+  |
+   |        +-------------------------+         |
+   |        | Misc. Dev Synchr. Logic |         |
+   |        +-------------------------+         |
+   |                                            |
+   +--------------------------------------------+
+
+   +--------------------------------------------+
+   |               Service Layer                |
+   |                                            |
+   |      +-----------------------------+       |
+   |      | Message Serialization Logic |       |
+   |      +-----------------------------+       |
+   |          +---------------+                 |
+   |          |  imx-mailbox  |                 |
+   |          |   mailbox.c   |                 |
+   |          +---------------+                 |
+   |                                            |
+   +--------------------------------------------+
+
+- service layer:
+  This layer is responsible for ensuring the communication protocol that is defined
+  for communication with firmware.
+
+  FW Communication protocol ensures two things:
+  - Serializing the messages to be sent over an MU.
+
+  - FW can handle one command message at a time.
+
+- c_dev:
+  This layer offers character device contexts, created as '/dev/<se>_mux_chx'.
+  Using these multiple device contexts that are getting multiplexed over a single MU,
+  userspace application(s) can call fops like write/read to send the command message,
+  and read back the command response message to/from Firmware.
+  fops like read & write use the above defined service layer API(s) to communicate with
+  Firmware.
+
+  Misc-device(/dev/<se>_mux_chn) synchronization protocol:
+::
+
+                                Non-Secure               +   Secure
+                                                         |
+                                                         |
+                +-----------+      +-------------+       |
+                | se_ctrl.c +<---->+imx-mailbox.c|       |
+                |           |      |  mailbox.c  +<-->+------+    +------+
+                +-----+-----+      +-------------+    | MU X +<-->+ ELE |
+                      |                               +------+    +------+
+                      +----------------+                 |
+                      |                |                 |
+                      v                v                 |
+                  logical           logical              |
+                  receiver          waiter               |
+                     +                 +                 |
+                     |                 |                 |
+                     |                 |                 |
+                     |            +----+------+          |
+                     |            |           |          |
+                     |            |           |          |
+              device_ctx     device_ctx     device_ctx   |
+                                                         |
+                User 0        User 1       User Y        |
+                +------+      +------+     +------+      |
+                |misc.c|      |misc.c|     |misc.c|      |
+ kernel space   +------+      +------+     +------+      |
+                                                         |
+ +------------------------------------------------------ |
+                    |             |           |          |
+ userspace     /dev/ele_muXch0    |           |          |
+                          /dev/ele_muXch1     |          |
+                                        /dev/ele_muXchY  |
+                                                         |
+
+When a user sends a command to the firmware, it registers its device_ctx
+as waiter of a response from firmware.
+
+Enclave's Firmware owns the storage management, over Linux filesystem.
+For this c_dev provisions a dedicated slave device called "receiver".
+
+.. kernel-doc:: drivers/firmware/imx/se_ctrl.c
+   :export:

-- 
2.43.0



From pankaj.gupta at nxp.com  Wed Dec 17 22:46:25 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Thu, 18 Dec 2025 12:16:25 +0530
Subject: [PATCH v22 2/7] dt-bindings: arm: fsl: add imx-se-fw binding doc
In-Reply-To: <20251218-imx-se-if-v22-0-07418c872509@nxp.com>
References: <20251218-imx-se-if-v22-0-07418c872509@nxp.com>
Message-ID: <20251218-imx-se-if-v22-2-07418c872509@nxp.com>

The NXP security hardware IP(s) like: i.MX EdgeLock Enclave, V2X etc.,
creates an embedded secure enclave within the SoC boundary to enable
features like:
- HSM
- SHE
- V2X

Secure-Enclave(s) communication interface are typically via message
unit, i.e., based on mailbox linux kernel driver. This driver enables
communication ensuring well defined message sequence protocol between
Application Core and enclave's firmware.

Driver configures multiple misc-device on the MU, for multiple
user-space applications, to be able to communicate over single MU.

It exists on some i.MX processors. e.g. i.MX8ULP, i.MX93 etc.

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
---
 .../devicetree/bindings/firmware/fsl,imx-se.yaml   | 91 ++++++++++++++++++++++
 1 file changed, 91 insertions(+)

diff --git a/Documentation/devicetree/bindings/firmware/fsl,imx-se.yaml b/Documentation/devicetree/bindings/firmware/fsl,imx-se.yaml
new file mode 100644
index 000000000000..fa81adbf9b80
--- /dev/null
+++ b/Documentation/devicetree/bindings/firmware/fsl,imx-se.yaml
@@ -0,0 +1,91 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/firmware/fsl,imx-se.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP i.MX HW Secure Enclave(s) EdgeLock Enclave
+
+maintainers:
+  - Pankaj Gupta <pankaj.gupta at nxp.com>
+
+description: |
+  NXP's SoC may contain one or multiple embedded secure-enclave HW
+  IP(s) like i.MX EdgeLock Enclave, V2X etc. These NXP's HW IP(s)
+  enables features like
+    - Hardware Security Module (HSM),
+    - Security Hardware Extension (SHE), and
+    - Vehicular to Anything (V2X)
+
+  Communication interface to the secure-enclaves(se) is based on the
+  messaging unit(s).
+
+properties:
+  compatible:
+    enum:
+      - fsl,imx8ulp-se-ele-hsm
+      - fsl,imx93-se-ele-hsm
+      - fsl,imx95-se-ele-hsm
+
+  mboxes:
+    items:
+      - description: mailbox phandle to send message to se firmware
+      - description: mailbox phandle to receive message from se firmware
+
+  mbox-names:
+    items:
+      - const: tx
+      - const: rx
+
+  memory-region:
+    maxItems: 1
+
+  sram:
+    maxItems: 1
+
+required:
+  - compatible
+  - mboxes
+  - mbox-names
+
+allOf:
+  # memory-region
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - fsl,imx8ulp-se-ele-hsm
+              - fsl,imx93-se-ele-hsm
+    then:
+      required:
+        - memory-region
+    else:
+      properties:
+        memory-region: false
+
+  # sram
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - fsl,imx8ulp-se-ele-hsm
+    then:
+      required:
+        - sram
+
+    else:
+      properties:
+        sram: false
+
+additionalProperties: false
+
+examples:
+  - |
+    secure-enclave {
+      compatible = "fsl,imx95-se-ele-hsm";
+      mboxes = <&ele_mu0 0 0>, <&ele_mu0 1 0>;
+      mbox-names = "tx", "rx";
+    };
+...

-- 
2.43.0



From pankaj.gupta at nxp.com  Wed Dec 17 22:46:26 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Thu, 18 Dec 2025 12:16:26 +0530
Subject: [PATCH v22 3/7] firmware: imx: add driver for NXP EdgeLock Enclave
In-Reply-To: <20251218-imx-se-if-v22-0-07418c872509@nxp.com>
References: <20251218-imx-se-if-v22-0-07418c872509@nxp.com>
Message-ID: <20251218-imx-se-if-v22-3-07418c872509@nxp.com>

Add driver for enabling MU based communication interface to secure-enclave.

NXP hardware IP(s) for secure-enclaves like Edgelock Enclave(ELE), are
embedded in the SoC to support the features like HSM, SHE & V2X, using
message based communication interface.

The secure enclave FW communicates with Linux over single or multiple
dedicated messaging unit(MU) based interface(s).
Exists on i.MX SoC(s) like i.MX8ULP, i.MX93, i.MX95 etc.

For i.MX9x SoC(s) there is at least one dedicated ELE MU(s) for each
world - Linux(one or more) and OPTEE-OS (one or more).

Other dependent kernel drivers will be:
- NVMEM: that supports non-volatile devices like EFUSES,
         managed by NXP's secure-enclave.

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
Changes from v21 to v22:
- reverted to previous change of using "__free(kfree)", by
  declare-and-initialize __free() vars next to their allocations.
---
 drivers/firmware/imx/Kconfig        |  13 ++
 drivers/firmware/imx/Makefile       |   2 +
 drivers/firmware/imx/ele_base_msg.c | 270 ++++++++++++++++++++++++
 drivers/firmware/imx/ele_base_msg.h |  95 +++++++++
 drivers/firmware/imx/ele_common.c   | 335 +++++++++++++++++++++++++++++
 drivers/firmware/imx/ele_common.h   |  45 ++++
 drivers/firmware/imx/se_ctrl.c      | 408 ++++++++++++++++++++++++++++++++++++
 drivers/firmware/imx/se_ctrl.h      |  86 ++++++++
 include/linux/firmware/imx/se_api.h |  14 ++
 9 files changed, 1268 insertions(+)

diff --git a/drivers/firmware/imx/Kconfig b/drivers/firmware/imx/Kconfig
index 127ad752acf8..1f89dd140113 100644
--- a/drivers/firmware/imx/Kconfig
+++ b/drivers/firmware/imx/Kconfig
@@ -55,3 +55,16 @@ config IMX_SCMI_MISC_DRV
 	  core that could provide misc functions such as board control.
 
 	  This driver can also be built as a module.
+
+config IMX_SEC_ENCLAVE
+	tristate "i.MX Embedded Secure Enclave - EdgeLock Enclave Firmware driver."
+	depends on (IMX_MBOX && ARCH_MXC && ARM64) || COMPILE_TEST
+	select FW_LOADER
+	default m if ARCH_MXC
+
+	help
+	  Exposes APIs supported by the iMX Secure Enclave HW IP called:
+	  - EdgeLock Enclave Firmware (for i.MX8ULP, i.MX93),
+	    like base, HSM, V2X & SHE using the SAB protocol via the shared Messaging
+	    Unit. This driver exposes these interfaces via a set of file descriptors
+	    allowing to configure shared memory, send and receive messages.
diff --git a/drivers/firmware/imx/Makefile b/drivers/firmware/imx/Makefile
index 3bbaffa6e347..4412b15846b1 100644
--- a/drivers/firmware/imx/Makefile
+++ b/drivers/firmware/imx/Makefile
@@ -4,3 +4,5 @@ obj-$(CONFIG_IMX_SCU)		+= imx-scu.o misc.o imx-scu-irq.o rm.o imx-scu-soc.o
 obj-${CONFIG_IMX_SCMI_CPU_DRV}	+= sm-cpu.o
 obj-${CONFIG_IMX_SCMI_MISC_DRV}	+= sm-misc.o
 obj-${CONFIG_IMX_SCMI_LMM_DRV}	+= sm-lmm.o
+sec_enclave-objs		= se_ctrl.o ele_common.o ele_base_msg.o
+obj-${CONFIG_IMX_SEC_ENCLAVE}	+= sec_enclave.o
diff --git a/drivers/firmware/imx/ele_base_msg.c b/drivers/firmware/imx/ele_base_msg.c
new file mode 100644
index 000000000000..da50686786f2
--- /dev/null
+++ b/drivers/firmware/imx/ele_base_msg.c
@@ -0,0 +1,270 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 NXP
+ */
+
+#include <linux/types.h>
+
+#include <linux/cleanup.h>
+#include <linux/completion.h>
+#include <linux/dma-mapping.h>
+#include <linux/genalloc.h>
+
+#include "ele_base_msg.h"
+#include "ele_common.h"
+
+#define FW_DBG_DUMP_FIXED_STR		"ELE"
+
+int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info)
+{
+	dma_addr_t get_info_addr = 0;
+	u32 *get_info_data = NULL;
+	int ret = 0;
+
+	if (!priv)
+		return -EINVAL;
+
+	memset(s_info, 0x0, sizeof(*s_info));
+
+	struct se_api_msg *tx_msg __free(kfree) =
+		kzalloc(ELE_GET_INFO_REQ_MSG_SZ, GFP_KERNEL);
+	if (!tx_msg)
+		return -ENOMEM;
+
+	struct se_api_msg *rx_msg __free(kfree) =
+		kzalloc(ELE_GET_INFO_RSP_MSG_SZ, GFP_KERNEL);
+	if (!rx_msg)
+		return -ENOMEM;
+
+	if (priv->mem_pool)
+		get_info_data = gen_pool_dma_alloc(priv->mem_pool,
+						   ELE_GET_INFO_BUFF_SZ,
+						   &get_info_addr);
+	else
+		get_info_data = dma_alloc_coherent(priv->dev,
+						   ELE_GET_INFO_BUFF_SZ,
+						   &get_info_addr,
+						   GFP_KERNEL);
+	if (!get_info_data) {
+		dev_dbg(priv->dev,
+			"%s: Failed to allocate get_info_addr.", __func__);
+		return -ENOMEM;
+	}
+
+	ret = se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
+				  ELE_GET_INFO_REQ, ELE_GET_INFO_REQ_MSG_SZ,
+				  true);
+	if (ret)
+		goto exit;
+
+	tx_msg->data[0] = upper_32_bits(get_info_addr);
+	tx_msg->data[1] = lower_32_bits(get_info_addr);
+	tx_msg->data[2] = sizeof(*s_info);
+	ret = ele_msg_send_rcv(priv, tx_msg, ELE_GET_INFO_REQ_MSG_SZ, rx_msg,
+			       ELE_GET_INFO_RSP_MSG_SZ);
+	if (ret < 0)
+		goto exit;
+
+	ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_GET_INFO_REQ,
+				      ELE_GET_INFO_RSP_MSG_SZ, true);
+
+	memcpy(s_info, get_info_data, sizeof(*s_info));
+exit:
+	if (priv->mem_pool)
+		gen_pool_free(priv->mem_pool, (unsigned long)get_info_data,
+			      ELE_GET_INFO_BUFF_SZ);
+	else
+		dma_free_coherent(priv->dev, ELE_GET_INFO_BUFF_SZ,
+				  get_info_data, get_info_addr);
+
+	return ret;
+}
+
+int ele_fetch_soc_info(struct se_if_priv *priv, void *data)
+{
+	return ele_get_info(priv, data);
+}
+
+int ele_ping(struct se_if_priv *priv)
+{
+	int ret = 0;
+
+	if (!priv)
+		return -EINVAL;
+
+	struct se_api_msg *tx_msg __free(kfree) = kzalloc(ELE_PING_REQ_SZ,
+							  GFP_KERNEL);
+	if (!tx_msg)
+		return -ENOMEM;
+
+	struct se_api_msg *rx_msg __free(kfree) = kzalloc(ELE_PING_RSP_SZ,
+							  GFP_KERNEL);
+	if (!rx_msg)
+		return -ENOMEM;
+
+	ret = se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
+				  ELE_PING_REQ, ELE_PING_REQ_SZ, true);
+	if (ret) {
+		dev_err(priv->dev, "Error: se_fill_cmd_msg_hdr failed.");
+		return ret;
+	}
+
+	ret = ele_msg_send_rcv(priv, tx_msg, ELE_PING_REQ_SZ, rx_msg,
+			       ELE_PING_RSP_SZ);
+	if (ret < 0)
+		return ret;
+
+	ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_PING_REQ,
+				      ELE_PING_RSP_SZ, true);
+
+	return ret;
+}
+
+int ele_service_swap(struct se_if_priv *priv,
+		     phys_addr_t addr,
+		     u32 addr_size, u16 flag)
+{
+	int ret = 0;
+
+	if (!priv)
+		return -EINVAL;
+
+	struct se_api_msg *tx_msg __free(kfree)	=
+		kzalloc(ELE_SERVICE_SWAP_REQ_MSG_SZ, GFP_KERNEL);
+	if (!tx_msg)
+		return -ENOMEM;
+
+	struct se_api_msg *rx_msg __free(kfree) =
+		kzalloc(ELE_SERVICE_SWAP_RSP_MSG_SZ, GFP_KERNEL);
+	if (!rx_msg)
+		return -ENOMEM;
+
+	ret = se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
+				  ELE_SERVICE_SWAP_REQ,
+				  ELE_SERVICE_SWAP_REQ_MSG_SZ, true);
+	if (ret)
+		return ret;
+
+	tx_msg->data[0] = flag;
+	tx_msg->data[1] = addr_size;
+	tx_msg->data[2] = ELE_NONE_VAL;
+	tx_msg->data[3] = lower_32_bits(addr);
+	tx_msg->data[4] = se_get_msg_chksum((u32 *)&tx_msg[0],
+					    ELE_SERVICE_SWAP_REQ_MSG_SZ);
+	if (!tx_msg->data[4])
+		return -EINVAL;
+
+	ret = ele_msg_send_rcv(priv, tx_msg, ELE_SERVICE_SWAP_REQ_MSG_SZ,
+			       rx_msg, ELE_SERVICE_SWAP_RSP_MSG_SZ);
+	if (ret < 0)
+		return ret;
+
+	ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_SERVICE_SWAP_REQ,
+				      ELE_SERVICE_SWAP_RSP_MSG_SZ, true);
+	if (ret)
+		return ret;
+
+	if (flag == ELE_IMEM_EXPORT)
+		ret = rx_msg->data[1];
+	else
+		ret = 0;
+
+	return ret;
+}
+
+int ele_fw_authenticate(struct se_if_priv *priv, phys_addr_t contnr_addr,
+			phys_addr_t img_addr)
+{
+	int ret = 0;
+
+	if (!priv)
+		return -EINVAL;
+
+	struct se_api_msg *tx_msg __free(kfree)	=
+		kzalloc(ELE_FW_AUTH_REQ_SZ, GFP_KERNEL);
+	if (!tx_msg)
+		return -ENOMEM;
+
+	struct se_api_msg *rx_msg __free(kfree) =
+		kzalloc(ELE_FW_AUTH_RSP_MSG_SZ, GFP_KERNEL);
+	if (!rx_msg)
+		return -ENOMEM;
+
+	ret = se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
+				  ELE_FW_AUTH_REQ, ELE_FW_AUTH_REQ_SZ, true);
+	if (ret)
+		return ret;
+
+	tx_msg->data[0] = lower_32_bits(contnr_addr);
+	tx_msg->data[1] = upper_32_bits(contnr_addr);
+	tx_msg->data[2] = img_addr;
+
+	ret = ele_msg_send_rcv(priv, tx_msg, ELE_FW_AUTH_REQ_SZ, rx_msg,
+			       ELE_FW_AUTH_RSP_MSG_SZ);
+	if (ret < 0)
+		return ret;
+
+	ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_FW_AUTH_REQ,
+				      ELE_FW_AUTH_RSP_MSG_SZ, true);
+
+	return ret;
+}
+
+int ele_debug_dump(struct se_if_priv *priv)
+{
+	bool keep_logging;
+	int msg_ex_cnt;
+	int ret = 0;
+	int i;
+
+	if (!priv)
+		return -EINVAL;
+
+	struct se_api_msg *tx_msg __free(kfree) = kzalloc(ELE_DEBUG_DUMP_REQ_SZ,
+							  GFP_KERNEL);
+	if (!tx_msg)
+		return -ENOMEM;
+
+	struct se_api_msg *rx_msg __free(kfree)	= kzalloc(ELE_DEBUG_DUMP_RSP_SZ,
+							  GFP_KERNEL);
+	if (!rx_msg)
+		return -ENOMEM;
+
+	ret = se_fill_cmd_msg_hdr(priv, &tx_msg->header, ELE_DEBUG_DUMP_REQ,
+				  ELE_DEBUG_DUMP_REQ_SZ, true);
+	if (ret)
+		return ret;
+
+	msg_ex_cnt = 0;
+	do {
+		memset(rx_msg, 0x0, ELE_DEBUG_DUMP_RSP_SZ);
+
+		ret = ele_msg_send_rcv(priv, tx_msg, ELE_DEBUG_DUMP_REQ_SZ,
+				       rx_msg, ELE_DEBUG_DUMP_RSP_SZ);
+		if (ret < 0)
+			return ret;
+
+		ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_DEBUG_DUMP_REQ,
+					      ELE_DEBUG_DUMP_RSP_SZ, true);
+		if (ret) {
+			dev_err(priv->dev, "Dump_Debug_Buffer Error: %x.", ret);
+			break;
+		}
+		keep_logging = (rx_msg->header.size >= (ELE_DEBUG_DUMP_RSP_SZ >> 2) &&
+				msg_ex_cnt < ELE_MAX_DBG_DMP_PKT);
+
+		rx_msg->header.size -= 2;
+
+		if (rx_msg->header.size > 4)
+			rx_msg->header.size--;
+
+		for (i = 0; i < rx_msg->header.size; i += 2)
+			dev_info(priv->dev, "%s%02x_%02x: 0x%08x 0x%08x",
+				 FW_DBG_DUMP_FIXED_STR,	msg_ex_cnt, i,
+				 rx_msg->data[i + 1], rx_msg->data[i + 2]);
+
+		msg_ex_cnt++;
+	} while (keep_logging);
+
+	return ret;
+}
diff --git a/drivers/firmware/imx/ele_base_msg.h b/drivers/firmware/imx/ele_base_msg.h
new file mode 100644
index 000000000000..8e5b015e99a2
--- /dev/null
+++ b/drivers/firmware/imx/ele_base_msg.h
@@ -0,0 +1,95 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2025 NXP
+ *
+ * Header file for the EdgeLock Enclave Base API(s).
+ */
+
+#ifndef ELE_BASE_MSG_H
+#define ELE_BASE_MSG_H
+
+#include <linux/device.h>
+#include <linux/types.h>
+
+#include "se_ctrl.h"
+
+#define ELE_NONE_VAL			0x0
+
+#define ELE_GET_INFO_REQ		0xda
+#define ELE_GET_INFO_REQ_MSG_SZ		0x10
+#define ELE_GET_INFO_RSP_MSG_SZ		0x08
+
+#define MAX_UID_SIZE                     (16)
+#define DEV_GETINFO_ROM_PATCH_SHA_SZ     (32)
+#define DEV_GETINFO_FW_SHA_SZ            (32)
+#define DEV_GETINFO_OEM_SRKH_SZ          (64)
+#define DEV_GETINFO_MIN_VER_MASK	0xff
+#define DEV_GETINFO_MAJ_VER_MASK	0xff00
+#define ELE_DEV_INFO_EXTRA_SZ		0x60
+
+struct dev_info {
+	u8  cmd;
+	u8  ver;
+	u16 length;
+	u16 soc_id;
+	u16 soc_rev;
+	u16 lmda_val;
+	u8  ssm_state;
+	u8  dev_atts_api_ver;
+	u8  uid[MAX_UID_SIZE];
+	u8  sha_rom_patch[DEV_GETINFO_ROM_PATCH_SHA_SZ];
+	u8  sha_fw[DEV_GETINFO_FW_SHA_SZ];
+};
+
+struct dev_addn_info {
+	u8  oem_srkh[DEV_GETINFO_OEM_SRKH_SZ];
+	u8  trng_state;
+	u8  csal_state;
+	u8  imem_state;
+	u8  reserved2;
+};
+
+struct ele_dev_info {
+	struct dev_info d_info;
+	struct dev_addn_info d_addn_info;
+};
+
+#define ELE_GET_INFO_BUFF_SZ		(sizeof(struct ele_dev_info) \
+						+ ELE_DEV_INFO_EXTRA_SZ)
+
+#define GET_SERIAL_NUM_FROM_UID(x, uid_word_sz) \
+	(((u64)(((u32 *)(x))[(uid_word_sz) - 1]) << 32) | ((u32 *)(x))[0])
+
+#define ELE_MAX_DBG_DMP_PKT		50
+#define ELE_DEBUG_DUMP_REQ		0x21
+#define ELE_DEBUG_DUMP_REQ_SZ		0x4
+#define ELE_DEBUG_DUMP_RSP_SZ		0x5c
+
+#define ELE_PING_REQ			0x01
+#define ELE_PING_REQ_SZ			0x04
+#define ELE_PING_RSP_SZ			0x08
+
+#define ELE_SERVICE_SWAP_REQ		0xdf
+#define ELE_SERVICE_SWAP_REQ_MSG_SZ	0x18
+#define ELE_SERVICE_SWAP_RSP_MSG_SZ	0x0c
+#define ELE_IMEM_SIZE			0x10000
+#define ELE_IMEM_STATE_OK		0xca
+#define ELE_IMEM_STATE_BAD		0xfe
+#define ELE_IMEM_STATE_WORD		0x27
+#define ELE_IMEM_STATE_MASK		0x00ff0000
+#define ELE_IMEM_EXPORT			0x1
+#define ELE_IMEM_IMPORT			0x2
+
+#define ELE_FW_AUTH_REQ			0x02
+#define ELE_FW_AUTH_REQ_SZ		0x10
+#define ELE_FW_AUTH_RSP_MSG_SZ		0x08
+
+int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info);
+int ele_fetch_soc_info(struct se_if_priv *priv, void *data);
+int ele_ping(struct se_if_priv *priv);
+int ele_service_swap(struct se_if_priv *priv, phys_addr_t addr,
+		     u32 addr_size, u16 flag);
+int ele_fw_authenticate(struct se_if_priv *priv, phys_addr_t contnr_addr,
+			phys_addr_t img_addr);
+int ele_debug_dump(struct se_if_priv *priv);
+#endif
diff --git a/drivers/firmware/imx/ele_common.c b/drivers/firmware/imx/ele_common.c
new file mode 100644
index 000000000000..a7150ff8e3b9
--- /dev/null
+++ b/drivers/firmware/imx/ele_common.c
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 NXP
+ */
+
+#include "ele_base_msg.h"
+#include "ele_common.h"
+
+/*
+ * se_get_msg_chksum() - to calculate checksum word by word.
+ *
+ * @msg : reference to the input msg-data.
+ * @msg_len : reference to the input msg-data length in bytes.
+ *            Includes extra 4 bytes (or 1 words) chksum.
+ *
+ * This function returns the checksum calculated by ORing word by word.
+ *
+ * Return:
+ *  0: if the input length is not 4 byte aligned, or num of words < 5.
+ *  chksum: calculated word by word.
+ */
+u32 se_get_msg_chksum(u32 *msg, u32 msg_len)
+{
+	u32 nb_words = msg_len / (u32)sizeof(u32);
+	u32 chksum = 0;
+	u32 i;
+
+	if (nb_words < 5)
+		return chksum;
+
+	if (msg_len % SE_MSG_WORD_SZ) {
+		pr_err("Msg-len is not 4-byte aligned.");
+		return chksum;
+	}
+
+	/* nb_words include one checksum word, so skip it. */
+	nb_words--;
+
+	for (i = 0; i < nb_words; i++)
+		chksum ^= *(msg + i);
+
+	return chksum;
+}
+
+int ele_msg_rcv(struct se_if_priv *priv, struct se_clbk_handle *se_clbk_hdl)
+{
+	unsigned long timeout;
+	int ret;
+
+	do {
+		timeout = MAX_SCHEDULE_TIMEOUT;
+
+		ret = wait_for_completion_interruptible_timeout(&se_clbk_hdl->done, timeout);
+		if (ret == -ERESTARTSYS) {
+			if (priv->waiting_rsp_clbk_hdl.rx_msg) {
+				priv->waiting_rsp_clbk_hdl.signal_rcvd = true;
+				continue;
+			}
+			ret = -EINTR;
+			break;
+		}
+		ret = se_clbk_hdl->rx_msg_sz;
+		break;
+	} while (ret < 0);
+
+	return ret;
+}
+
+int ele_msg_send(struct se_if_priv *priv,
+		 void *tx_msg,
+		 int tx_msg_sz)
+{
+	struct se_msg_hdr *header = tx_msg;
+	int err;
+
+	/*
+	 * Check that the size passed as argument matches the size
+	 * carried in the message.
+	 */
+	if (header->size << 2 != tx_msg_sz) {
+		dev_err(priv->dev,
+			"User buf hdr: 0x%x, sz mismatced with input-sz (%d != %d).",
+			*(u32 *)header, header->size << 2, tx_msg_sz);
+		return -EINVAL;
+	}
+
+	err = mbox_send_message(priv->tx_chan, tx_msg);
+	if (err < 0) {
+		dev_err(priv->dev, "Error: mbox_send_message failure.\n");
+		return err;
+	}
+
+	return tx_msg_sz;
+}
+
+/* API used for send/receive blocking call. */
+int ele_msg_send_rcv(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz,
+		     void *rx_msg, int exp_rx_msg_sz)
+{
+	int err;
+
+	guard(mutex)(&priv->se_if_cmd_lock);
+
+	priv->waiting_rsp_clbk_hdl.rx_msg_sz = exp_rx_msg_sz;
+	priv->waiting_rsp_clbk_hdl.rx_msg = rx_msg;
+
+	err = ele_msg_send(priv, tx_msg, tx_msg_sz);
+	if (err < 0)
+		return err;
+
+	err = ele_msg_rcv(priv, &priv->waiting_rsp_clbk_hdl);
+
+	if (priv->waiting_rsp_clbk_hdl.signal_rcvd) {
+		err = -EINTR;
+		priv->waiting_rsp_clbk_hdl.signal_rcvd = false;
+		dev_err(priv->dev, "Err[0x%x]:Interrupted by signal.\n", err);
+	}
+
+	return err;
+}
+
+static bool check_hdr_exception_for_sz(struct se_if_priv *priv,
+				       struct se_msg_hdr *header)
+{
+	/*
+	 * List of API(s) header that can be accepte variable length
+	 * response buffer.
+	 */
+	if (header->command == ELE_DEBUG_DUMP_REQ &&
+	    header->ver == priv->if_defs->base_api_ver &&
+	    header->size >= 0 && header->size <= ELE_DEBUG_DUMP_RSP_SZ)
+		return true;
+
+	return false;
+}
+
+/*
+ * Callback called by mailbox FW, when data is received.
+ */
+void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg)
+{
+	struct se_clbk_handle *se_clbk_hdl;
+	struct device *dev = mbox_cl->dev;
+	struct se_msg_hdr *header;
+	struct se_if_priv *priv;
+	u32 rx_msg_sz;
+
+	priv = dev_get_drvdata(dev);
+
+	/* The function can be called with NULL msg */
+	if (!msg) {
+		dev_err(dev, "Message is invalid\n");
+		return;
+	}
+
+	header = msg;
+	rx_msg_sz = header->size << 2;
+
+	/* Incoming command: wake up the receiver if any. */
+	if (header->tag == priv->if_defs->cmd_tag) {
+		se_clbk_hdl = &priv->cmd_receiver_clbk_hdl;
+		dev_dbg(dev, "Selecting cmd receiver for mesg header:0x%x.",
+			*(u32 *)header);
+
+		/*
+		 * Pre-allocated buffer of MAX_NVM_MSG_LEN
+		 * as the NVM command are initiated by FW.
+		 * Size is revealed as part of this call function.
+		 */
+		if (rx_msg_sz > MAX_NVM_MSG_LEN) {
+			dev_err(dev,
+				"CMD-RCVER NVM: hdr(0x%x) with different sz(%d != %d).\n",
+				*(u32 *)header, rx_msg_sz, se_clbk_hdl->rx_msg_sz);
+
+			se_clbk_hdl->rx_msg_sz = MAX_NVM_MSG_LEN;
+		}
+		se_clbk_hdl->rx_msg_sz = rx_msg_sz;
+
+	} else if (header->tag == priv->if_defs->rsp_tag) {
+		se_clbk_hdl = &priv->waiting_rsp_clbk_hdl;
+		dev_dbg(dev, "Selecting resp waiter for mesg header:0x%x.",
+			*(u32 *)header);
+
+		if (rx_msg_sz != se_clbk_hdl->rx_msg_sz &&
+		    check_hdr_exception_for_sz(priv, header)) {
+			dev_err(dev,
+				"Rsp to CMD: hdr(0x%x) with different sz(%d != %d).\n",
+				*(u32 *)header, rx_msg_sz, se_clbk_hdl->rx_msg_sz);
+
+			se_clbk_hdl->rx_msg_sz = min(rx_msg_sz, se_clbk_hdl->rx_msg_sz);
+		}
+	} else {
+		dev_err(dev, "Failed to select a device for message: %.8x\n",
+			*((u32 *)header));
+		return;
+	}
+
+	memcpy(se_clbk_hdl->rx_msg, msg, se_clbk_hdl->rx_msg_sz);
+
+	/* Allow user to read */
+	complete(&se_clbk_hdl->done);
+}
+
+int se_val_rsp_hdr_n_status(struct se_if_priv *priv, struct se_api_msg *msg,
+			    u8 msg_id, u8 sz, bool is_base_api)
+{
+	struct se_msg_hdr *header = &msg->header;
+	u32 status;
+
+	if (header->tag != priv->if_defs->rsp_tag) {
+		dev_err(priv->dev, "MSG[0x%x] Hdr: Resp tag mismatch. (0x%x != 0x%x)",
+			msg_id, header->tag, priv->if_defs->rsp_tag);
+		return -EINVAL;
+	}
+
+	if (header->command != msg_id) {
+		dev_err(priv->dev, "MSG Header: Cmd id mismatch. (0x%x != 0x%x)",
+			header->command, msg_id);
+		return -EINVAL;
+	}
+
+	if ((sz % 4) || (header->size != (sz >> 2) &&
+			 !check_hdr_exception_for_sz(priv, header))) {
+		dev_err(priv->dev, "MSG[0x%x] Hdr: Cmd size mismatch. (0x%x != 0x%x)",
+			msg_id, header->size, (sz >> 2));
+		return -EINVAL;
+	}
+
+	if (is_base_api && header->ver != priv->if_defs->base_api_ver) {
+		dev_err(priv->dev,
+			"MSG[0x%x] Hdr: Base API Vers mismatch. (0x%x != 0x%x)",
+			msg_id, header->ver, priv->if_defs->base_api_ver);
+		return -EINVAL;
+	} else if (!is_base_api && header->ver != priv->if_defs->fw_api_ver) {
+		dev_err(priv->dev,
+			"MSG[0x%x] Hdr: FW API Vers mismatch. (0x%x != 0x%x)",
+			msg_id, header->ver, priv->if_defs->fw_api_ver);
+		return -EINVAL;
+	}
+
+	status = RES_STATUS(msg->data[0]);
+	if (status != priv->if_defs->success_tag) {
+		dev_err(priv->dev, "Command Id[%x], Response Failure = 0x%x",
+			header->command, status);
+		return -EPERM;
+	}
+
+	return 0;
+}
+
+int se_save_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem)
+{
+	struct ele_dev_info s_info = {0};
+	int ret;
+
+	ret = ele_get_info(priv, &s_info);
+	if (ret) {
+		dev_err(priv->dev, "Failed to get info from ELE.\n");
+		return ret;
+	}
+
+	/* Check for the imem-state before continue to save imem state. */
+	if (s_info.d_addn_info.imem_state == ELE_IMEM_STATE_BAD)
+		return -EIO;
+
+	/*
+	 * EXPORT command will save encrypted IMEM to given address,
+	 * so later in resume, IMEM can be restored from the given
+	 * address.
+	 *
+	 * Size must be at least 64 kB.
+	 */
+	ret = ele_service_swap(priv, imem->phyaddr, ELE_IMEM_SIZE, ELE_IMEM_EXPORT);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to export IMEM.");
+		imem->size = 0;
+	} else {
+		dev_dbg(priv->dev,
+			"Exported %d bytes of encrypted IMEM.",
+			ret);
+		imem->size = ret;
+	}
+
+	return ret > 0 ? 0 : ret;
+}
+
+int se_restore_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem)
+{
+	struct ele_dev_info s_info;
+	int ret;
+
+	/* get info from ELE */
+	ret = ele_get_info(priv, &s_info);
+	if (ret) {
+		dev_err(priv->dev, "Failed to get info from ELE.");
+		return ret;
+	}
+	imem->state = s_info.d_addn_info.imem_state;
+
+	/* Check for the imem-state and imem-size before continue to
+	 * restore imem state.
+	 */
+	if (s_info.d_addn_info.imem_state != ELE_IMEM_STATE_BAD || !imem->size)
+		return -EIO;
+
+	/*
+	 * IMPORT command will restore IMEM from the given
+	 * address, here size is the actual size returned by ELE
+	 * during the export operation
+	 */
+	ret = ele_service_swap(priv, imem->phyaddr, imem->size, ELE_IMEM_IMPORT);
+	if (ret) {
+		dev_err(priv->dev, "Failed to import IMEM");
+		return ret;
+	}
+
+	/*
+	 * After importing IMEM, check if IMEM state is equal to 0xCA
+	 * to ensure IMEM is fully loaded and
+	 * ELE functionality can be used.
+	 */
+	ret = ele_get_info(priv, &s_info);
+	if (ret) {
+		dev_err(priv->dev, "Failed to get info from ELE.");
+		return ret;
+	}
+	imem->state = s_info.d_addn_info.imem_state;
+
+	if (s_info.d_addn_info.imem_state == ELE_IMEM_STATE_OK)
+		dev_dbg(priv->dev, "Successfully restored IMEM.");
+	else
+		dev_err(priv->dev, "Failed to restore IMEM.");
+
+	return ret;
+}
diff --git a/drivers/firmware/imx/ele_common.h b/drivers/firmware/imx/ele_common.h
new file mode 100644
index 000000000000..96e987ef6f88
--- /dev/null
+++ b/drivers/firmware/imx/ele_common.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2025 NXP
+ */
+
+#ifndef __ELE_COMMON_H__
+#define __ELE_COMMON_H__
+
+#include "se_ctrl.h"
+
+#define ELE_SUCCESS_IND			0xD6
+
+#define IMX_ELE_FW_DIR                 "imx/ele/"
+
+u32 se_get_msg_chksum(u32 *msg, u32 msg_len);
+
+int ele_msg_rcv(struct se_if_priv *priv, struct se_clbk_handle *se_clbk_hdl);
+
+int ele_msg_send(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz);
+
+int ele_msg_send_rcv(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz,
+		     void *rx_msg, int exp_rx_msg_sz);
+
+void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg);
+
+int se_val_rsp_hdr_n_status(struct se_if_priv *priv, struct se_api_msg *msg,
+			    u8 msg_id, u8 sz, bool is_base_api);
+
+/* Fill a command message header with a given command ID and length in bytes. */
+static inline int se_fill_cmd_msg_hdr(struct se_if_priv *priv, struct se_msg_hdr *hdr,
+				      u8 cmd, u32 len, bool is_base_api)
+{
+	hdr->tag = priv->if_defs->cmd_tag;
+	hdr->ver = (is_base_api) ? priv->if_defs->base_api_ver : priv->if_defs->fw_api_ver;
+	hdr->command = cmd;
+	hdr->size = len >> 2;
+
+	return 0;
+}
+
+int se_save_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem);
+
+int se_restore_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem);
+
+#endif /*__ELE_COMMON_H__ */
diff --git a/drivers/firmware/imx/se_ctrl.c b/drivers/firmware/imx/se_ctrl.c
new file mode 100644
index 000000000000..1c91b4698465
--- /dev/null
+++ b/drivers/firmware/imx/se_ctrl.c
@@ -0,0 +1,408 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 NXP
+ */
+
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/firmware.h>
+#include <linux/firmware/imx/se_api.h>
+#include <linux/genalloc.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/miscdevice.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/sys_soc.h>
+
+#include "ele_base_msg.h"
+#include "ele_common.h"
+#include "se_ctrl.h"
+
+#define MAX_SOC_INFO_DATA_SZ		256
+#define MBOX_TX_NAME			"tx"
+#define MBOX_RX_NAME			"rx"
+
+#define SE_TYPE_STR_DBG			"dbg"
+#define SE_TYPE_STR_HSM			"hsm"
+
+#define SE_TYPE_ID_DBG			0x1
+#define SE_TYPE_ID_HSM			0x2
+
+struct se_fw_img_name {
+	const u8 *prim_fw_nm_in_rfs;
+	const u8 *seco_fw_nm_in_rfs;
+};
+
+struct se_fw_load_info {
+	const struct se_fw_img_name *se_fw_img_nm;
+	bool is_fw_tobe_loaded;
+	bool imem_mgmt;
+	struct se_imem_buf imem;
+};
+
+struct se_var_info {
+	u16 soc_rev;
+	struct se_fw_load_info load_fw;
+};
+
+/* contains fixed information */
+struct se_soc_info {
+	const u16 soc_id;
+	const bool soc_register;
+	const struct se_fw_img_name se_fw_img_nm;
+};
+
+struct se_if_node {
+	struct se_soc_info *se_info;
+	u8 *pool_name;
+	bool reserved_dma_ranges;
+	struct se_if_defines if_defs;
+};
+
+/* common for all the SoC. */
+static struct se_var_info var_se_info;
+
+static struct se_soc_info se_imx8ulp_info = {
+	.soc_id = SOC_ID_OF_IMX8ULP,
+	.soc_register = true,
+	.se_fw_img_nm = {
+		.prim_fw_nm_in_rfs = IMX_ELE_FW_DIR
+			"mx8ulpa2-ahab-container.img",
+		.seco_fw_nm_in_rfs = IMX_ELE_FW_DIR
+			"mx8ulpa2ext-ahab-container.img",
+	},
+};
+
+static struct se_if_node imx8ulp_se_ele_hsm = {
+	.se_info = &se_imx8ulp_info,
+	.pool_name = "sram",
+	.reserved_dma_ranges = true,
+	.if_defs = {
+		.se_if_type = SE_TYPE_ID_HSM,
+		.cmd_tag = 0x17,
+		.rsp_tag = 0xe1,
+		.success_tag = ELE_SUCCESS_IND,
+		.base_api_ver = MESSAGING_VERSION_6,
+		.fw_api_ver = MESSAGING_VERSION_7,
+	},
+};
+
+static struct se_soc_info se_imx93_info = {
+	.soc_id = SOC_ID_OF_IMX93,
+};
+
+static struct se_if_node imx93_se_ele_hsm = {
+	.se_info = &se_imx93_info,
+	.reserved_dma_ranges = true,
+	.if_defs = {
+		.se_if_type = SE_TYPE_ID_HSM,
+		.cmd_tag = 0x17,
+		.rsp_tag = 0xe1,
+		.success_tag = ELE_SUCCESS_IND,
+		.base_api_ver = MESSAGING_VERSION_6,
+		.fw_api_ver = MESSAGING_VERSION_7,
+	},
+};
+
+static const struct of_device_id se_match[] = {
+	{ .compatible = "fsl,imx8ulp-se-ele-hsm", .data = &imx8ulp_se_ele_hsm},
+	{ .compatible = "fsl,imx93-se-ele-hsm", .data = &imx93_se_ele_hsm},
+	{},
+};
+
+char *get_se_if_name(u8 se_if_id)
+{
+	switch (se_if_id) {
+	case SE_TYPE_ID_DBG: return SE_TYPE_STR_DBG;
+	case SE_TYPE_ID_HSM: return SE_TYPE_STR_HSM;
+	}
+
+	return NULL;
+}
+
+static struct se_fw_load_info *get_load_fw_instance(struct se_if_priv *priv)
+{
+	return &var_se_info.load_fw;
+}
+
+static int get_se_soc_info(struct se_if_priv *priv, const struct se_soc_info *se_info)
+{
+	struct se_fw_load_info *load_fw = get_load_fw_instance(priv);
+	struct soc_device_attribute *attr;
+	u8 data[MAX_SOC_INFO_DATA_SZ];
+	struct ele_dev_info *s_info;
+	struct soc_device *sdev;
+	int err = 0;
+
+	/*
+	 * This function should be called once.
+	 * Check if the se_soc_rev is zero to continue.
+	 */
+	if (var_se_info.soc_rev)
+		return err;
+
+	err = ele_fetch_soc_info(priv, &data);
+	if (err < 0)
+		return dev_err_probe(priv->dev, err, "Failed to fetch SoC Info.");
+	s_info = (void *)data;
+	var_se_info.soc_rev = s_info->d_info.soc_rev;
+	load_fw->imem.state = s_info->d_addn_info.imem_state;
+
+	if (!se_info->soc_register)
+		return 0;
+
+	attr = devm_kzalloc(priv->dev, sizeof(*attr), GFP_KERNEL);
+	if (!attr)
+		return -ENOMEM;
+
+	if (FIELD_GET(DEV_GETINFO_MIN_VER_MASK, var_se_info.soc_rev))
+		attr->revision = devm_kasprintf(priv->dev, GFP_KERNEL, "%x.%x",
+						FIELD_GET(DEV_GETINFO_MIN_VER_MASK,
+							  var_se_info.soc_rev),
+						FIELD_GET(DEV_GETINFO_MAJ_VER_MASK,
+							  var_se_info.soc_rev));
+	else
+		attr->revision = devm_kasprintf(priv->dev, GFP_KERNEL, "%x",
+						FIELD_GET(DEV_GETINFO_MAJ_VER_MASK,
+							  var_se_info.soc_rev));
+
+	switch (se_info->soc_id) {
+	case SOC_ID_OF_IMX8ULP:
+		attr->soc_id = "i.MX8ULP";
+		break;
+	case SOC_ID_OF_IMX93:
+		attr->soc_id = "i.MX93";
+		break;
+	}
+
+	err = of_property_read_string(of_root, "model", &attr->machine);
+	if (err)
+		return -EINVAL;
+
+	attr->family = "Freescale i.MX";
+
+	attr->serial_number = devm_kasprintf(priv->dev,
+					     GFP_KERNEL, "%016llX",
+					     GET_SERIAL_NUM_FROM_UID(s_info->d_info.uid,
+								     MAX_UID_SIZE >> 2));
+
+	sdev = soc_device_register(attr);
+	if (IS_ERR(sdev))
+		return PTR_ERR(sdev);
+
+	return 0;
+}
+
+/* interface for managed res to free a mailbox channel */
+static void if_mbox_free_channel(void *mbox_chan)
+{
+	mbox_free_channel(mbox_chan);
+}
+
+static int se_if_request_channel(struct device *dev, struct mbox_chan **chan,
+				 struct mbox_client *cl, const char *name)
+{
+	struct mbox_chan *t_chan;
+	int ret = 0;
+
+	t_chan = mbox_request_channel_byname(cl, name);
+	if (IS_ERR(t_chan))
+		return dev_err_probe(dev, PTR_ERR(t_chan),
+				     "Failed to request %s channel.", name);
+
+	ret = devm_add_action_or_reset(dev, if_mbox_free_channel, t_chan);
+	if (ret)
+		return dev_err_probe(dev, -EPERM,
+				     "Failed to add-action for removal of mbox: %s\n",
+				     name);
+	*chan = t_chan;
+
+	return ret;
+}
+
+static void se_if_probe_cleanup(void *plat_dev)
+{
+	struct platform_device *pdev = plat_dev;
+	struct se_fw_load_info *load_fw;
+	struct device *dev = &pdev->dev;
+	struct se_if_priv *priv;
+
+	priv = dev_get_drvdata(dev);
+	load_fw = get_load_fw_instance(priv);
+
+	/*
+	 * In se_if_request_channel(), passed the clean-up functional
+	 * pointer reference as action to devm_add_action_or_reset().
+	 * No need to free the mbox channels here.
+	 */
+
+	/*
+	 * free the buffer in se remove, previously allocated
+	 * in se probe to store encrypted IMEM
+	 */
+	if (load_fw && load_fw->imem.buf) {
+		dmam_free_coherent(dev, ELE_IMEM_SIZE, load_fw->imem.buf,
+				   load_fw->imem.phyaddr);
+		load_fw->imem.buf = NULL;
+	}
+
+	/*
+	 * No need to check, if reserved memory is allocated
+	 * before calling for its release. Or clearing the
+	 * un-set bit.
+	 */
+	of_reserved_mem_device_release(dev);
+}
+
+static int se_if_probe(struct platform_device *pdev)
+{
+	const struct se_soc_info *se_info;
+	const struct se_if_node *if_node;
+	struct se_fw_load_info *load_fw;
+	struct device *dev = &pdev->dev;
+	struct se_if_priv *priv;
+	int ret;
+
+	if_node = device_get_match_data(dev);
+	if (!if_node)
+		return -EINVAL;
+
+	se_info = if_node->se_info;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = dev;
+	priv->if_defs = &if_node->if_defs;
+	dev_set_drvdata(dev, priv);
+
+	ret = devm_add_action_or_reset(dev, se_if_probe_cleanup, pdev);
+	if (ret)
+		return ret;
+
+	/* Mailbox client configuration */
+	priv->se_mb_cl.dev		= dev;
+	priv->se_mb_cl.tx_block		= false;
+	priv->se_mb_cl.knows_txdone	= true;
+	priv->se_mb_cl.rx_callback	= se_if_rx_callback;
+
+	ret = se_if_request_channel(dev, &priv->tx_chan, &priv->se_mb_cl, MBOX_TX_NAME);
+	if (ret)
+		return ret;
+
+	ret = se_if_request_channel(dev, &priv->rx_chan, &priv->se_mb_cl, MBOX_RX_NAME);
+	if (ret)
+		return ret;
+
+	mutex_init(&priv->se_if_cmd_lock);
+
+	init_completion(&priv->waiting_rsp_clbk_hdl.done);
+	init_completion(&priv->cmd_receiver_clbk_hdl.done);
+
+	if (if_node->pool_name) {
+		priv->mem_pool = of_gen_pool_get(dev->of_node, if_node->pool_name, 0);
+		if (!priv->mem_pool)
+			return dev_err_probe(dev, -ENOMEM,
+					     "Unable to get sram pool = %s.",
+					     if_node->pool_name);
+	}
+
+	if (if_node->reserved_dma_ranges) {
+		ret = of_reserved_mem_device_init(dev);
+		if (ret)
+			return dev_err_probe(dev, ret,
+					    "Failed to init reserved memory region.");
+	}
+
+	if (if_node->if_defs.se_if_type == SE_TYPE_ID_HSM) {
+		ret = get_se_soc_info(priv, se_info);
+		if (ret)
+			return dev_err_probe(dev, ret, "Failed to fetch SoC Info.");
+	}
+
+	/* By default, there is no pending FW to be loaded.*/
+	if (se_info->se_fw_img_nm.seco_fw_nm_in_rfs) {
+		load_fw = get_load_fw_instance(priv);
+		load_fw->se_fw_img_nm = &se_info->se_fw_img_nm;
+		load_fw->is_fw_tobe_loaded = true;
+
+		if (load_fw->se_fw_img_nm->prim_fw_nm_in_rfs) {
+			/* allocate buffer where SE store encrypted IMEM */
+			load_fw->imem.buf = dmam_alloc_coherent(priv->dev, ELE_IMEM_SIZE,
+								&load_fw->imem.phyaddr,
+								GFP_KERNEL);
+			if (!load_fw->imem.buf)
+				return dev_err_probe(dev, -ENOMEM,
+						     "dmam-alloc-failed: To store encr-IMEM.");
+			load_fw->imem_mgmt = true;
+		}
+	}
+	dev_info(dev, "i.MX secure-enclave: %s0 interface to firmware, configured.",
+		 get_se_if_name(priv->if_defs->se_if_type));
+
+	return ret;
+}
+
+static int se_suspend(struct device *dev)
+{
+	struct se_if_priv *priv = dev_get_drvdata(dev);
+	struct se_fw_load_info *load_fw;
+	int ret = 0;
+
+	load_fw = get_load_fw_instance(priv);
+
+	if (load_fw->imem_mgmt) {
+		ret = se_save_imem_state(priv, &load_fw->imem);
+		if (ret)
+			dev_err(dev, "Failure saving IMEM state[0x%x]", ret);
+	}
+
+	return 0;
+}
+
+static int se_resume(struct device *dev)
+{
+	struct se_if_priv *priv = dev_get_drvdata(dev);
+	struct se_fw_load_info *load_fw;
+	int ret = 0;
+
+	load_fw = get_load_fw_instance(priv);
+
+	if (load_fw->imem_mgmt) {
+		se_restore_imem_state(priv, &load_fw->imem);
+		if (ret)
+			dev_err(dev, "Failure restoring IMEM state[0x%x]", ret);
+	}
+
+	return 0;
+}
+
+static const struct dev_pm_ops se_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(se_suspend, se_resume)
+};
+
+static struct platform_driver se_driver = {
+	.driver = {
+		.name = "fsl-se",
+		.of_match_table = se_match,
+		.pm = &se_pm,
+	},
+	.probe = se_if_probe,
+};
+MODULE_DEVICE_TABLE(of, se_match);
+
+module_platform_driver(se_driver);
+MODULE_AUTHOR("Pankaj Gupta <pankaj.gupta at nxp.com>");
+MODULE_DESCRIPTION("iMX Secure Enclave Driver.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/imx/se_ctrl.h b/drivers/firmware/imx/se_ctrl.h
new file mode 100644
index 000000000000..b15c4022a46c
--- /dev/null
+++ b/drivers/firmware/imx/se_ctrl.h
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2025 NXP
+ */
+
+#ifndef SE_MU_H
+#define SE_MU_H
+
+#include <linux/miscdevice.h>
+#include <linux/semaphore.h>
+#include <linux/mailbox_client.h>
+
+#define MAX_FW_LOAD_RETRIES		50
+#define SE_MSG_WORD_SZ			0x4
+
+#define RES_STATUS(x)			FIELD_GET(0x000000ff, x)
+#define MAX_NVM_MSG_LEN			(256)
+#define MESSAGING_VERSION_6		0x6
+#define MESSAGING_VERSION_7		0x7
+
+struct se_clbk_handle {
+	struct completion done;
+	bool signal_rcvd;
+	u32 rx_msg_sz;
+	/*
+	 * Assignment of the rx_msg buffer to held till the
+	 * received content as part callback function, is copied.
+	 */
+	struct se_api_msg *rx_msg;
+};
+
+struct se_imem_buf {
+	u8 *buf;
+	phys_addr_t phyaddr;
+	u32 size;
+	u32 state;
+};
+
+/* Header of the messages exchange with the EdgeLock Enclave */
+struct se_msg_hdr {
+	u8 ver;
+	u8 size;
+	u8 command;
+	u8 tag;
+}  __packed;
+
+#define SE_MU_HDR_SZ	4
+
+struct se_api_msg {
+	struct se_msg_hdr header;
+	u32 data[];
+};
+
+struct se_if_defines {
+	const u8 se_if_type;
+	u8 cmd_tag;
+	u8 rsp_tag;
+	u8 success_tag;
+	u8 base_api_ver;
+	u8 fw_api_ver;
+};
+
+struct se_if_priv {
+	struct device *dev;
+
+	struct se_clbk_handle cmd_receiver_clbk_hdl;
+	/*
+	 * Update to the waiting_rsp_dev, to be protected
+	 * under se_if_cmd_lock.
+	 */
+	struct se_clbk_handle waiting_rsp_clbk_hdl;
+	/*
+	 * prevent new command to be sent on the se interface while previous
+	 * command is still processing. (response is awaited)
+	 */
+	struct mutex se_if_cmd_lock;
+
+	struct mbox_client se_mb_cl;
+	struct mbox_chan *tx_chan, *rx_chan;
+
+	struct gen_pool *mem_pool;
+	const struct se_if_defines *if_defs;
+};
+
+char *get_se_if_name(u8 se_if_id);
+#endif
diff --git a/include/linux/firmware/imx/se_api.h b/include/linux/firmware/imx/se_api.h
new file mode 100644
index 000000000000..b1c4c9115d7b
--- /dev/null
+++ b/include/linux/firmware/imx/se_api.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2025 NXP
+ */
+
+#ifndef __SE_API_H__
+#define __SE_API_H__
+
+#include <linux/types.h>
+
+#define SOC_ID_OF_IMX8ULP		0x084d
+#define SOC_ID_OF_IMX93			0x9300
+
+#endif /* __SE_API_H__ */

-- 
2.43.0



From pankaj.gupta at nxp.com  Wed Dec 17 22:46:27 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Thu, 18 Dec 2025 12:16:27 +0530
Subject: [PATCH v22 4/7] firmware: imx: device context dedicated to priv
In-Reply-To: <20251218-imx-se-if-v22-0-07418c872509@nxp.com>
References: <20251218-imx-se-if-v22-0-07418c872509@nxp.com>
Message-ID: <20251218-imx-se-if-v22-4-07418c872509@nxp.com>

Add priv_dev_ctx to prepare enabling misc-device context based send-receive
path, to communicate with FW.

No functionality change.

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/firmware/imx/ele_base_msg.c | 14 +++++-----
 drivers/firmware/imx/ele_common.c   | 51 +++++++++++++++++++++----------------
 drivers/firmware/imx/ele_common.h   |  8 +++---
 drivers/firmware/imx/se_ctrl.c      | 29 +++++++++++++++++++++
 drivers/firmware/imx/se_ctrl.h      |  9 +++++++
 5 files changed, 78 insertions(+), 33 deletions(-)

diff --git a/drivers/firmware/imx/ele_base_msg.c b/drivers/firmware/imx/ele_base_msg.c
index da50686786f2..475ba98be199 100644
--- a/drivers/firmware/imx/ele_base_msg.c
+++ b/drivers/firmware/imx/ele_base_msg.c
@@ -60,8 +60,8 @@ int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info)
 	tx_msg->data[0] = upper_32_bits(get_info_addr);
 	tx_msg->data[1] = lower_32_bits(get_info_addr);
 	tx_msg->data[2] = sizeof(*s_info);
-	ret = ele_msg_send_rcv(priv, tx_msg, ELE_GET_INFO_REQ_MSG_SZ, rx_msg,
-			       ELE_GET_INFO_RSP_MSG_SZ);
+	ret = ele_msg_send_rcv(priv->priv_dev_ctx, tx_msg, ELE_GET_INFO_REQ_MSG_SZ,
+			       rx_msg, ELE_GET_INFO_RSP_MSG_SZ);
 	if (ret < 0)
 		goto exit;
 
@@ -109,8 +109,8 @@ int ele_ping(struct se_if_priv *priv)
 		return ret;
 	}
 
-	ret = ele_msg_send_rcv(priv, tx_msg, ELE_PING_REQ_SZ, rx_msg,
-			       ELE_PING_RSP_SZ);
+	ret = ele_msg_send_rcv(priv->priv_dev_ctx, tx_msg, ELE_PING_REQ_SZ,
+			       rx_msg, ELE_PING_RSP_SZ);
 	if (ret < 0)
 		return ret;
 
@@ -154,7 +154,7 @@ int ele_service_swap(struct se_if_priv *priv,
 	if (!tx_msg->data[4])
 		return -EINVAL;
 
-	ret = ele_msg_send_rcv(priv, tx_msg, ELE_SERVICE_SWAP_REQ_MSG_SZ,
+	ret = ele_msg_send_rcv(priv->priv_dev_ctx, tx_msg, ELE_SERVICE_SWAP_REQ_MSG_SZ,
 			       rx_msg, ELE_SERVICE_SWAP_RSP_MSG_SZ);
 	if (ret < 0)
 		return ret;
@@ -199,7 +199,7 @@ int ele_fw_authenticate(struct se_if_priv *priv, phys_addr_t contnr_addr,
 	tx_msg->data[1] = upper_32_bits(contnr_addr);
 	tx_msg->data[2] = img_addr;
 
-	ret = ele_msg_send_rcv(priv, tx_msg, ELE_FW_AUTH_REQ_SZ, rx_msg,
+	ret = ele_msg_send_rcv(priv->priv_dev_ctx, tx_msg, ELE_FW_AUTH_REQ_SZ, rx_msg,
 			       ELE_FW_AUTH_RSP_MSG_SZ);
 	if (ret < 0)
 		return ret;
@@ -239,7 +239,7 @@ int ele_debug_dump(struct se_if_priv *priv)
 	do {
 		memset(rx_msg, 0x0, ELE_DEBUG_DUMP_RSP_SZ);
 
-		ret = ele_msg_send_rcv(priv, tx_msg, ELE_DEBUG_DUMP_REQ_SZ,
+		ret = ele_msg_send_rcv(priv->priv_dev_ctx, tx_msg, ELE_DEBUG_DUMP_REQ_SZ,
 				       rx_msg, ELE_DEBUG_DUMP_RSP_SZ);
 		if (ret < 0)
 			return ret;
diff --git a/drivers/firmware/imx/ele_common.c b/drivers/firmware/imx/ele_common.c
index a7150ff8e3b9..fcd0f561d72d 100644
--- a/drivers/firmware/imx/ele_common.c
+++ b/drivers/firmware/imx/ele_common.c
@@ -42,7 +42,7 @@ u32 se_get_msg_chksum(u32 *msg, u32 msg_len)
 	return chksum;
 }
 
-int ele_msg_rcv(struct se_if_priv *priv, struct se_clbk_handle *se_clbk_hdl)
+int ele_msg_rcv(struct se_if_device_ctx *dev_ctx, struct se_clbk_handle *se_clbk_hdl)
 {
 	unsigned long timeout;
 	int ret;
@@ -52,8 +52,8 @@ int ele_msg_rcv(struct se_if_priv *priv, struct se_clbk_handle *se_clbk_hdl)
 
 		ret = wait_for_completion_interruptible_timeout(&se_clbk_hdl->done, timeout);
 		if (ret == -ERESTARTSYS) {
-			if (priv->waiting_rsp_clbk_hdl.rx_msg) {
-				priv->waiting_rsp_clbk_hdl.signal_rcvd = true;
+			if (dev_ctx->priv->waiting_rsp_clbk_hdl.dev_ctx) {
+				dev_ctx->priv->waiting_rsp_clbk_hdl.signal_rcvd = true;
 				continue;
 			}
 			ret = -EINTR;
@@ -66,7 +66,7 @@ int ele_msg_rcv(struct se_if_priv *priv, struct se_clbk_handle *se_clbk_hdl)
 	return ret;
 }
 
-int ele_msg_send(struct se_if_priv *priv,
+int ele_msg_send(struct se_if_device_ctx *dev_ctx,
 		 void *tx_msg,
 		 int tx_msg_sz)
 {
@@ -78,15 +78,16 @@ int ele_msg_send(struct se_if_priv *priv,
 	 * carried in the message.
 	 */
 	if (header->size << 2 != tx_msg_sz) {
-		dev_err(priv->dev,
-			"User buf hdr: 0x%x, sz mismatced with input-sz (%d != %d).",
-			*(u32 *)header, header->size << 2, tx_msg_sz);
+		dev_err(dev_ctx->priv->dev,
+			"%s: User buf hdr: 0x%x, sz mismatced with input-sz (%d != %d).",
+			dev_ctx->devname, *(u32 *)header, header->size << 2, tx_msg_sz);
 		return -EINVAL;
 	}
 
-	err = mbox_send_message(priv->tx_chan, tx_msg);
+	err = mbox_send_message(dev_ctx->priv->tx_chan, tx_msg);
 	if (err < 0) {
-		dev_err(priv->dev, "Error: mbox_send_message failure.\n");
+		dev_err(dev_ctx->priv->dev,
+			"%s: Error: mbox_send_message failure.", dev_ctx->devname);
 		return err;
 	}
 
@@ -94,27 +95,31 @@ int ele_msg_send(struct se_if_priv *priv,
 }
 
 /* API used for send/receive blocking call. */
-int ele_msg_send_rcv(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz,
-		     void *rx_msg, int exp_rx_msg_sz)
+int ele_msg_send_rcv(struct se_if_device_ctx *dev_ctx, void *tx_msg,
+		     int tx_msg_sz, void *rx_msg, int exp_rx_msg_sz)
 {
+	struct se_if_priv *priv = dev_ctx->priv;
 	int err;
 
 	guard(mutex)(&priv->se_if_cmd_lock);
 
+	priv->waiting_rsp_clbk_hdl.dev_ctx = dev_ctx;
 	priv->waiting_rsp_clbk_hdl.rx_msg_sz = exp_rx_msg_sz;
 	priv->waiting_rsp_clbk_hdl.rx_msg = rx_msg;
 
-	err = ele_msg_send(priv, tx_msg, tx_msg_sz);
+	err = ele_msg_send(dev_ctx, tx_msg, tx_msg_sz);
 	if (err < 0)
 		return err;
 
-	err = ele_msg_rcv(priv, &priv->waiting_rsp_clbk_hdl);
+	err = ele_msg_rcv(dev_ctx, &priv->waiting_rsp_clbk_hdl);
 
 	if (priv->waiting_rsp_clbk_hdl.signal_rcvd) {
 		err = -EINTR;
 		priv->waiting_rsp_clbk_hdl.signal_rcvd = false;
-		dev_err(priv->dev, "Err[0x%x]:Interrupted by signal.\n", err);
+		dev_err(priv->dev, "%s: Err[0x%x]:Interrupted by signal.",
+			dev_ctx->devname, err);
 	}
+	priv->waiting_rsp_clbk_hdl.dev_ctx = NULL;
 
 	return err;
 }
@@ -159,8 +164,8 @@ void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg)
 	/* Incoming command: wake up the receiver if any. */
 	if (header->tag == priv->if_defs->cmd_tag) {
 		se_clbk_hdl = &priv->cmd_receiver_clbk_hdl;
-		dev_dbg(dev, "Selecting cmd receiver for mesg header:0x%x.",
-			*(u32 *)header);
+		dev_dbg(dev, "Selecting cmd receiver:%s for mesg header:0x%x.",
+			se_clbk_hdl->dev_ctx->devname,  *(u32 *)header);
 
 		/*
 		 * Pre-allocated buffer of MAX_NVM_MSG_LEN
@@ -169,8 +174,9 @@ void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg)
 		 */
 		if (rx_msg_sz > MAX_NVM_MSG_LEN) {
 			dev_err(dev,
-				"CMD-RCVER NVM: hdr(0x%x) with different sz(%d != %d).\n",
-				*(u32 *)header, rx_msg_sz, se_clbk_hdl->rx_msg_sz);
+				"%s: CMD-RCVER NVM: hdr(0x%x) with different sz(%d != %d).\n",
+				se_clbk_hdl->dev_ctx->devname, *(u32 *)header,
+				rx_msg_sz, se_clbk_hdl->rx_msg_sz);
 
 			se_clbk_hdl->rx_msg_sz = MAX_NVM_MSG_LEN;
 		}
@@ -178,14 +184,15 @@ void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg)
 
 	} else if (header->tag == priv->if_defs->rsp_tag) {
 		se_clbk_hdl = &priv->waiting_rsp_clbk_hdl;
-		dev_dbg(dev, "Selecting resp waiter for mesg header:0x%x.",
-			*(u32 *)header);
+		dev_dbg(dev, "Selecting resp waiter:%s for mesg header:0x%x.",
+			se_clbk_hdl->dev_ctx->devname, *(u32 *)header);
 
 		if (rx_msg_sz != se_clbk_hdl->rx_msg_sz &&
 		    check_hdr_exception_for_sz(priv, header)) {
 			dev_err(dev,
-				"Rsp to CMD: hdr(0x%x) with different sz(%d != %d).\n",
-				*(u32 *)header, rx_msg_sz, se_clbk_hdl->rx_msg_sz);
+				"%s: Rsp to CMD: hdr(0x%x) with different sz(%d != %d).\n",
+				se_clbk_hdl->dev_ctx->devname, *(u32 *)header,
+				rx_msg_sz, se_clbk_hdl->rx_msg_sz);
 
 			se_clbk_hdl->rx_msg_sz = min(rx_msg_sz, se_clbk_hdl->rx_msg_sz);
 		}
diff --git a/drivers/firmware/imx/ele_common.h b/drivers/firmware/imx/ele_common.h
index 96e987ef6f88..5bac14439d7d 100644
--- a/drivers/firmware/imx/ele_common.h
+++ b/drivers/firmware/imx/ele_common.h
@@ -14,12 +14,12 @@
 
 u32 se_get_msg_chksum(u32 *msg, u32 msg_len);
 
-int ele_msg_rcv(struct se_if_priv *priv, struct se_clbk_handle *se_clbk_hdl);
+int ele_msg_rcv(struct se_if_device_ctx *dev_ctx, struct se_clbk_handle *se_clbk_hdl);
 
-int ele_msg_send(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz);
+int ele_msg_send(struct se_if_device_ctx *dev_ctx, void *tx_msg, int tx_msg_sz);
 
-int ele_msg_send_rcv(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz,
-		     void *rx_msg, int exp_rx_msg_sz);
+int ele_msg_send_rcv(struct se_if_device_ctx *dev_ctx, void *tx_msg,
+		     int tx_msg_sz, void *rx_msg, int exp_rx_msg_sz);
 
 void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg);
 
diff --git a/drivers/firmware/imx/se_ctrl.c b/drivers/firmware/imx/se_ctrl.c
index 1c91b4698465..63562a4d9a3e 100644
--- a/drivers/firmware/imx/se_ctrl.c
+++ b/drivers/firmware/imx/se_ctrl.c
@@ -203,6 +203,29 @@ static int get_se_soc_info(struct se_if_priv *priv, const struct se_soc_info *se
 	return 0;
 }
 
+static int init_misc_device_context(struct se_if_priv *priv, int ch_id,
+				    struct se_if_device_ctx **new_dev_ctx)
+{
+	struct se_if_device_ctx *dev_ctx;
+	int ret = 0;
+
+	dev_ctx = devm_kzalloc(priv->dev, sizeof(*dev_ctx), GFP_KERNEL);
+
+	if (!dev_ctx)
+		return -ENOMEM;
+
+	dev_ctx->devname = devm_kasprintf(priv->dev, GFP_KERNEL, "%s0_ch%d",
+					  get_se_if_name(priv->if_defs->se_if_type),
+					  ch_id);
+	if (!dev_ctx->devname)
+		return -ENOMEM;
+
+	dev_ctx->priv = priv;
+	*new_dev_ctx = dev_ctx;
+
+	return ret;
+}
+
 /* interface for managed res to free a mailbox channel */
 static void if_mbox_free_channel(void *mbox_chan)
 {
@@ -325,6 +348,12 @@ static int se_if_probe(struct platform_device *pdev)
 					    "Failed to init reserved memory region.");
 	}
 
+	ret = init_misc_device_context(priv, 0, &priv->priv_dev_ctx);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed[0x%x] to create device contexts.",
+				     ret);
+
 	if (if_node->if_defs.se_if_type == SE_TYPE_ID_HSM) {
 		ret = get_se_soc_info(priv, se_info);
 		if (ret)
diff --git a/drivers/firmware/imx/se_ctrl.h b/drivers/firmware/imx/se_ctrl.h
index b15c4022a46c..b5e7705e2f26 100644
--- a/drivers/firmware/imx/se_ctrl.h
+++ b/drivers/firmware/imx/se_ctrl.h
@@ -19,6 +19,7 @@
 #define MESSAGING_VERSION_7		0x7
 
 struct se_clbk_handle {
+	struct se_if_device_ctx *dev_ctx;
 	struct completion done;
 	bool signal_rcvd;
 	u32 rx_msg_sz;
@@ -36,6 +37,12 @@ struct se_imem_buf {
 	u32 state;
 };
 
+/* Private struct for each char device instance. */
+struct se_if_device_ctx {
+	struct se_if_priv *priv;
+	const char *devname;
+};
+
 /* Header of the messages exchange with the EdgeLock Enclave */
 struct se_msg_hdr {
 	u8 ver;
@@ -80,6 +87,8 @@ struct se_if_priv {
 
 	struct gen_pool *mem_pool;
 	const struct se_if_defines *if_defs;
+
+	struct se_if_device_ctx *priv_dev_ctx;
 };
 
 char *get_se_if_name(u8 se_if_id);

-- 
2.43.0



From pankaj.gupta at nxp.com  Wed Dec 17 22:46:28 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Thu, 18 Dec 2025 12:16:28 +0530
Subject: [PATCH v22 5/7] firmware: drivers: imx: adds miscdev
In-Reply-To: <20251218-imx-se-if-v22-0-07418c872509@nxp.com>
References: <20251218-imx-se-if-v22-0-07418c872509@nxp.com>
Message-ID: <20251218-imx-se-if-v22-5-07418c872509@nxp.com>

Adds the driver for communication interface to secure-enclave, that
enables exchanging messages with NXP secure enclave HW IP(s)
like EdgeLock Enclave, from:
- User-Space Applications via character driver.

ABI documentation for the NXP secure-enclave driver.

User-space library using this driver:
- i.MX Secure Enclave library:
  -- URL: https://github.com/nxp-imx/imx-secure-enclave.git,
- i.MX Secure Middle-Ware:
  -- URL: https://github.com/nxp-imx/imx-smw.git

Following checks are performed on the incoming msg-header,
to block exchanging invalid arbitrary commands:
- maximum allowed words,
- check if command-tag & response-tag are valid
- version,
- command id validation check, to allow limited base-line API(s)
  and restrict following:
  - exchanging power management commands.
  - reset requests.
  - BBSM configuration requests.
  - re-initializing the FW.
  - RNG init
  - CAAM resource release management
  - SE's internal memory management.
from user-space.

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
changes from v21 to v22
- reverted to previous change of using "__free(kfree)", by
  declare-and-initialize __free() vars next to their allocations.
---
 Documentation/ABI/testing/se-cdev   |  43 +++
 drivers/firmware/imx/ele_base_msg.c |  28 ++
 drivers/firmware/imx/ele_base_msg.h |  20 +
 drivers/firmware/imx/ele_common.c   |  37 +-
 drivers/firmware/imx/ele_common.h   |   6 +
 drivers/firmware/imx/se_ctrl.c      | 743 +++++++++++++++++++++++++++++++++++-
 drivers/firmware/imx/se_ctrl.h      |  33 ++
 include/uapi/linux/se_ioctl.h       |  97 +++++
 8 files changed, 995 insertions(+), 12 deletions(-)

diff --git a/Documentation/ABI/testing/se-cdev b/Documentation/ABI/testing/se-cdev
new file mode 100644
index 000000000000..dad39ffd245a
--- /dev/null
+++ b/Documentation/ABI/testing/se-cdev
@@ -0,0 +1,43 @@
+What:		/dev/<se>_mu[0-9]+_ch[0-9]+
+Date:		Mar 2025
+KernelVersion:	6.8
+Contact:	linux-imx at nxp.com, pankaj.gupta at nxp.com
+Description:
+		NXP offers multiple hardware IP(s) for secure enclaves like EdgeLock-
+		Enclave(ELE), SECO. The character device file descriptors
+		/dev/<se>_mu*_ch* are the interface between userspace NXP's secure-
+		enclave shared library and the kernel driver.
+
+		The ioctl(2)-based ABI is defined and documented in
+		[include]<linux/firmware/imx/ele_mu_ioctl.h>.
+		ioctl(s) are used primarily for:
+			- shared memory management
+			- allocation of I/O buffers
+			- getting mu info
+			- setting a dev-ctx as receiver to receive all the commands from FW
+			- getting SoC info
+			- send command and receive command response
+
+		The following file operations are supported:
+
+		open(2)
+		  Currently the only useful flags are O_RDWR.
+
+		read(2)
+		  Every read() from the opened character device context is waiting on
+		  wait_event_interruptible, that gets set by the registered mailbox callback
+		  function, indicating a message received from the firmware on message-
+		  unit.
+
+		write(2)
+		  Every write() to the opened character device context needs to acquire
+		  mailbox_lock before sending message on to the message unit.
+
+		close(2)
+		  Stops and frees up the I/O contexts that were associated
+		  with the file descriptor.
+
+Users:		https://github.com/nxp-imx/imx-secure-enclave.git,
+		https://github.com/nxp-imx/imx-smw.git
+		crypto/skcipher,
+		drivers/nvmem/imx-ocotp-ele.c
diff --git a/drivers/firmware/imx/ele_base_msg.c b/drivers/firmware/imx/ele_base_msg.c
index 475ba98be199..23f68076b85c 100644
--- a/drivers/firmware/imx/ele_base_msg.c
+++ b/drivers/firmware/imx/ele_base_msg.c
@@ -15,6 +15,34 @@
 
 #define FW_DBG_DUMP_FIXED_STR		"ELE"
 
+int ele_uapi_allowed_base_cmd(struct se_if_priv *priv,
+			      struct se_msg_hdr *header)
+{
+	switch (header->command) {
+	case ELE_PING_REQ: return 0;
+	case ELE_DEBUG_DUMP_REQ: return 0;
+	case ELE_OEM_AUTH_CONTAINER_REQ: return 0;
+	case ELE_OEM_VERIFY_IMAGE_REQ: return 0;
+	case ELE_OEM_REL_CONTAINER_REQ: return 0;
+	case ELE_FW_LIFE_CYCLE_REQ: return 0;
+	case ELE_READ_FUSE_REQ: return 0;
+	case ELE_GET_FW_VERS_REQ: return 0;
+	case ELE_RETURN_LIFE_CYCLE_REQ: return 0;
+	case ELE_GET_EVENT_REQ: return 0;
+	case ELE_COMMIT_REQ: return 0;
+	case ELE_GEN_KEY_BLOB_REQ: return 0;
+	case ELE_GET_FW_STATUS_REQ: return 0;
+	case ELE_XIP_DECRYPT_REQ: return 0;
+	case ELE_WRITE_FUSE: return 0;
+	case ELE_GET_INFO_REQ: return 0;
+	case ELE_DEV_ATTEST_REQ: return 0;
+	case ELE_WRITE_SHADOW_FUSE_REQ: return 0;
+	case ELE_READ_SHADOW_FUSE_REQ: return 0;
+	default:
+		return -EACCES;
+	}
+}
+
 int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info)
 {
 	dma_addr_t get_info_addr = 0;
diff --git a/drivers/firmware/imx/ele_base_msg.h b/drivers/firmware/imx/ele_base_msg.h
index 8e5b015e99a2..f8fabac331fd 100644
--- a/drivers/firmware/imx/ele_base_msg.h
+++ b/drivers/firmware/imx/ele_base_msg.h
@@ -15,6 +15,24 @@
 
 #define ELE_NONE_VAL			0x0
 
+
+#define ELE_OEM_AUTH_CONTAINER_REQ	0x87
+#define ELE_OEM_VERIFY_IMAGE_REQ	0x88
+#define ELE_OEM_REL_CONTAINER_REQ	0x89
+#define ELE_FW_LIFE_CYCLE_REQ		0x95
+#define ELE_READ_FUSE_REQ		0x97
+#define ELE_GET_FW_VERS_REQ		0x9d
+#define ELE_RETURN_LIFE_CYCLE_REQ	0xa0
+#define ELE_GET_EVENT_REQ		0xa2
+#define ELE_COMMIT_REQ			0xa8
+#define ELE_GEN_KEY_BLOB_REQ		0xaf
+#define ELE_GET_FW_STATUS_REQ		0xc5
+#define ELE_XIP_DECRYPT_REQ		0xc6
+#define ELE_WRITE_FUSE                  0xd6
+#define ELE_DEV_ATTEST_REQ              0xdb
+#define ELE_WRITE_SHADOW_FUSE_REQ       0xf2
+#define ELE_READ_SHADOW_FUSE_REQ        0xf3
+
 #define ELE_GET_INFO_REQ		0xda
 #define ELE_GET_INFO_REQ_MSG_SZ		0x10
 #define ELE_GET_INFO_RSP_MSG_SZ		0x08
@@ -92,4 +110,6 @@ int ele_service_swap(struct se_if_priv *priv, phys_addr_t addr,
 int ele_fw_authenticate(struct se_if_priv *priv, phys_addr_t contnr_addr,
 			phys_addr_t img_addr);
 int ele_debug_dump(struct se_if_priv *priv);
+int ele_uapi_allowed_base_cmd(struct se_if_priv *priv,
+			      struct se_msg_hdr *header);
 #endif
diff --git a/drivers/firmware/imx/ele_common.c b/drivers/firmware/imx/ele_common.c
index fcd0f561d72d..78440f62bf92 100644
--- a/drivers/firmware/imx/ele_common.c
+++ b/drivers/firmware/imx/ele_common.c
@@ -6,6 +6,23 @@
 #include "ele_base_msg.h"
 #include "ele_common.h"
 
+int se_chk_tx_msg_hdr(struct se_if_priv *priv, struct se_msg_hdr *header)
+{
+	if (!header->size || header->size > MAX_WORD_SIZE)
+		return -EINVAL;
+
+	if (header->tag != priv->if_defs->cmd_tag &&
+	    header->tag != priv->if_defs->rsp_tag)
+		return -EINVAL;
+
+	if (header->ver == priv->if_defs->base_api_ver)
+		return ele_uapi_allowed_base_cmd(priv, header);
+	else if (header->ver == priv->if_defs->fw_api_ver)
+		return 0;
+
+	return -EINVAL;
+}
+
 /*
  * se_get_msg_chksum() - to calculate checksum word by word.
  *
@@ -42,15 +59,22 @@ u32 se_get_msg_chksum(u32 *msg, u32 msg_len)
 	return chksum;
 }
 
+void set_se_rcv_msg_timeout(struct se_if_priv *priv, u32 timeout_ms)
+{
+	priv->se_rcv_msg_timeout_ms = timeout_ms;
+}
+
 int ele_msg_rcv(struct se_if_device_ctx *dev_ctx, struct se_clbk_handle *se_clbk_hdl)
 {
-	unsigned long timeout;
+	unsigned long timeout_ms;
 	int ret;
 
 	do {
-		timeout = MAX_SCHEDULE_TIMEOUT;
+		timeout_ms = MAX_SCHEDULE_TIMEOUT;
+		if (dev_ctx->priv->cmd_receiver_clbk_hdl.dev_ctx != dev_ctx)
+			timeout_ms = msecs_to_jiffies(dev_ctx->priv->se_rcv_msg_timeout_ms);
 
-		ret = wait_for_completion_interruptible_timeout(&se_clbk_hdl->done, timeout);
+		ret = wait_for_completion_interruptible_timeout(&se_clbk_hdl->done, timeout_ms);
 		if (ret == -ERESTARTSYS) {
 			if (dev_ctx->priv->waiting_rsp_clbk_hdl.dev_ctx) {
 				dev_ctx->priv->waiting_rsp_clbk_hdl.signal_rcvd = true;
@@ -59,6 +83,13 @@ int ele_msg_rcv(struct se_if_device_ctx *dev_ctx, struct se_clbk_handle *se_clbk
 			ret = -EINTR;
 			break;
 		}
+		if (ret == 0) {
+			ret = -ETIMEDOUT;
+			dev_err(dev_ctx->priv->dev,
+				"Fatal Error: SE interface: %s0, hangs indefinitely.\n",
+				get_se_if_name(dev_ctx->priv->if_defs->se_if_type));
+			break;
+		}
 		ret = se_clbk_hdl->rx_msg_sz;
 		break;
 	} while (ret < 0);
diff --git a/drivers/firmware/imx/ele_common.h b/drivers/firmware/imx/ele_common.h
index 5bac14439d7d..bdc13d1b715d 100644
--- a/drivers/firmware/imx/ele_common.h
+++ b/drivers/firmware/imx/ele_common.h
@@ -12,6 +12,11 @@
 
 #define IMX_ELE_FW_DIR                 "imx/ele/"
 
+#define MAX_WORD_SIZE			0x20
+#define SE_RCV_MSG_DEFAULT_TIMEOUT	5000
+#define SE_RCV_MSG_LONG_TIMEOUT		5000000
+
+void set_se_rcv_msg_timeout(struct se_if_priv *priv, u32 val);
 u32 se_get_msg_chksum(u32 *msg, u32 msg_len);
 
 int ele_msg_rcv(struct se_if_device_ctx *dev_ctx, struct se_clbk_handle *se_clbk_hdl);
@@ -42,4 +47,5 @@ int se_save_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem);
 
 int se_restore_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem);
 
+int se_chk_tx_msg_hdr(struct se_if_priv *priv, struct se_msg_hdr *header);
 #endif /*__ELE_COMMON_H__ */
diff --git a/drivers/firmware/imx/se_ctrl.c b/drivers/firmware/imx/se_ctrl.c
index 63562a4d9a3e..07f38e5465ee 100644
--- a/drivers/firmware/imx/se_ctrl.c
+++ b/drivers/firmware/imx/se_ctrl.c
@@ -3,6 +3,7 @@
  * Copyright 2025 NXP
  */
 
+#include <linux/cleanup.h>
 #include <linux/completion.h>
 #include <linux/delay.h>
 #include <linux/dev_printk.h>
@@ -23,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/sys_soc.h>
+#include <uapi/linux/se_ioctl.h>
 
 #include "ele_base_msg.h"
 #include "ele_common.h"
@@ -32,12 +34,6 @@
 #define MBOX_TX_NAME			"tx"
 #define MBOX_RX_NAME			"rx"
 
-#define SE_TYPE_STR_DBG			"dbg"
-#define SE_TYPE_STR_HSM			"hsm"
-
-#define SE_TYPE_ID_DBG			0x1
-#define SE_TYPE_ID_HSM			0x2
-
 struct se_fw_img_name {
 	const u8 *prim_fw_nm_in_rfs;
 	const u8 *seco_fw_nm_in_rfs;
@@ -130,6 +126,13 @@ char *get_se_if_name(u8 se_if_id)
 	return NULL;
 }
 
+static u32 get_se_soc_id(struct se_if_priv *priv)
+{
+	const struct se_soc_info *se_info = device_get_match_data(priv->dev);
+
+	return se_info->soc_id;
+}
+
 static struct se_fw_load_info *get_load_fw_instance(struct se_if_priv *priv)
 {
 	return &var_se_info.load_fw;
@@ -203,8 +206,213 @@ static int get_se_soc_info(struct se_if_priv *priv, const struct se_soc_info *se
 	return 0;
 }
 
+static int load_firmware(struct se_if_priv *priv, const u8 *se_img_file_to_load)
+{
+	const struct firmware *fw = NULL;
+	phys_addr_t se_fw_phyaddr;
+	u8 *se_fw_buf;
+	int ret;
+
+	if (!se_img_file_to_load) {
+		dev_err(priv->dev, "FW image is not provided.");
+		return -EINVAL;
+	}
+	ret = request_firmware(&fw, se_img_file_to_load, priv->dev);
+	if (ret)
+		return ret;
+
+	dev_info(priv->dev, "loading firmware %s.", se_img_file_to_load);
+
+	/* allocate buffer to store the SE FW */
+	se_fw_buf = dma_alloc_coherent(priv->dev, fw->size, &se_fw_phyaddr, GFP_KERNEL);
+	if (!se_fw_buf) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	memcpy(se_fw_buf, fw->data, fw->size);
+	ret = ele_fw_authenticate(priv, se_fw_phyaddr, se_fw_phyaddr);
+	if (ret < 0) {
+		dev_err(priv->dev,
+			"Error %pe: Authenticate & load SE firmware %s.",
+			ERR_PTR(ret), se_img_file_to_load);
+		ret = -EPERM;
+	}
+	dma_free_coherent(priv->dev, fw->size, se_fw_buf, se_fw_phyaddr);
+exit:
+	release_firmware(fw);
+
+	return ret;
+}
+
+static int se_load_firmware(struct se_if_priv *priv)
+{
+	struct se_fw_load_info *load_fw = get_load_fw_instance(priv);
+	int ret = 0;
+
+	if (!load_fw->is_fw_tobe_loaded)
+		return 0;
+
+	if (load_fw->imem.state == ELE_IMEM_STATE_BAD) {
+		ret = load_firmware(priv, load_fw->se_fw_img_nm->prim_fw_nm_in_rfs);
+		if (ret) {
+			dev_err(priv->dev, "Failed to load boot firmware.");
+			return -EPERM;
+		}
+	}
+
+	ret = load_firmware(priv, load_fw->se_fw_img_nm->seco_fw_nm_in_rfs);
+	if (ret) {
+		dev_err(priv->dev, "Failed to load runtime firmware.");
+		return -EPERM;
+	}
+
+	load_fw->is_fw_tobe_loaded = false;
+
+	return ret;
+}
+
+static int init_se_shared_mem(struct se_if_device_ctx *dev_ctx)
+{
+	struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
+	struct se_if_priv *priv = dev_ctx->priv;
+
+	INIT_LIST_HEAD(&se_shared_mem_mgmt->pending_out);
+	INIT_LIST_HEAD(&se_shared_mem_mgmt->pending_in);
+
+	/*
+	 * Allocate some memory for data exchanges with S40x.
+	 * This will be used for data not requiring secure memory.
+	 */
+	se_shared_mem_mgmt->non_secure_mem.ptr =
+			dma_alloc_coherent(priv->dev, MAX_DATA_SIZE_PER_USER,
+					   &se_shared_mem_mgmt->non_secure_mem.dma_addr,
+					   GFP_KERNEL);
+	if (!se_shared_mem_mgmt->non_secure_mem.ptr)
+		return -ENOMEM;
+
+	se_shared_mem_mgmt->non_secure_mem.size = MAX_DATA_SIZE_PER_USER;
+	se_shared_mem_mgmt->non_secure_mem.pos = 0;
+
+	return 0;
+}
+
+static void cleanup_se_shared_mem(struct se_if_device_ctx *dev_ctx)
+{
+	struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
+	struct se_if_priv *priv = dev_ctx->priv;
+
+	/* Free non-secure shared buffer. */
+	dma_free_coherent(priv->dev, MAX_DATA_SIZE_PER_USER,
+			  se_shared_mem_mgmt->non_secure_mem.ptr,
+			  se_shared_mem_mgmt->non_secure_mem.dma_addr);
+
+	se_shared_mem_mgmt->non_secure_mem.ptr = NULL;
+	se_shared_mem_mgmt->non_secure_mem.dma_addr = 0;
+	se_shared_mem_mgmt->non_secure_mem.size = 0;
+	se_shared_mem_mgmt->non_secure_mem.pos = 0;
+}
+
+/* Need to copy the output data to user-device context.
+ */
+static int se_dev_ctx_cpy_out_data(struct se_if_device_ctx *dev_ctx)
+{
+	struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
+	struct se_if_priv *priv = dev_ctx->priv;
+	struct se_buf_desc *b_desc, *temp;
+	bool do_cpy = true;
+
+	list_for_each_entry_safe(b_desc, temp, &se_shared_mem_mgmt->pending_out, link) {
+		if (b_desc->usr_buf_ptr && b_desc->shared_buf_ptr && do_cpy) {
+			dev_dbg(priv->dev, "Copying output data to user.");
+			if (do_cpy && copy_to_user(b_desc->usr_buf_ptr,
+						   b_desc->shared_buf_ptr,
+						   b_desc->size)) {
+				dev_err(priv->dev, "Failure copying output data to user.");
+				do_cpy = false;
+			}
+		}
+
+		if (b_desc->shared_buf_ptr)
+			memset(b_desc->shared_buf_ptr, 0, b_desc->size);
+
+		list_del(&b_desc->link);
+		kfree(b_desc);
+	}
+
+	return do_cpy ? 0 : -EFAULT;
+}
+
+/*
+ * Clean the used Shared Memory space,
+ * whether its Input Data copied from user buffers, or
+ * Data received from FW.
+ */
+static void se_dev_ctx_shared_mem_cleanup(struct se_if_device_ctx *dev_ctx)
+{
+	struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
+	struct list_head *pending_lists[] = {&se_shared_mem_mgmt->pending_in,
+						&se_shared_mem_mgmt->pending_out};
+	struct se_buf_desc *b_desc, *temp;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pending_lists); i++) {
+		list_for_each_entry_safe(b_desc, temp, pending_lists[i], link) {
+			if (b_desc->shared_buf_ptr)
+				memset(b_desc->shared_buf_ptr, 0, b_desc->size);
+
+			list_del(&b_desc->link);
+			kfree(b_desc);
+		}
+	}
+	se_shared_mem_mgmt->non_secure_mem.pos = 0;
+}
+
+static int add_b_desc_to_pending_list(void *shared_ptr_with_pos,
+				      struct se_ioctl_setup_iobuf *io,
+				      struct se_if_device_ctx *dev_ctx)
+{
+	struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
+	struct se_buf_desc *b_desc;
+
+	b_desc = kzalloc(sizeof(*b_desc), GFP_KERNEL);
+	if (!b_desc)
+		return -ENOMEM;
+
+	b_desc->shared_buf_ptr = shared_ptr_with_pos;
+	b_desc->usr_buf_ptr = io->user_buf;
+	b_desc->size = io->length;
+
+	if (io->flags & SE_IO_BUF_FLAGS_IS_INPUT) {
+		/*
+		 * buffer is input:
+		 * add an entry in the "pending input buffers" list so
+		 * that copied data can be cleaned from shared memory
+		 * later.
+		 */
+		list_add_tail(&b_desc->link, &se_shared_mem_mgmt->pending_in);
+	} else {
+		/*
+		 * buffer is output:
+		 * add an entry in the "pending out buffers" list so data
+		 * can be copied to user space when receiving Secure-Enclave
+		 * response.
+		 */
+		list_add_tail(&b_desc->link, &se_shared_mem_mgmt->pending_out);
+	}
+
+	return 0;
+}
+
+/* interface for managed res to unregister a character device */
+static void if_misc_deregister(void *miscdevice)
+{
+	misc_deregister(miscdevice);
+}
+
 static int init_misc_device_context(struct se_if_priv *priv, int ch_id,
-				    struct se_if_device_ctx **new_dev_ctx)
+				    struct se_if_device_ctx **new_dev_ctx,
+				    const struct file_operations *se_if_fops)
 {
 	struct se_if_device_ctx *dev_ctx;
 	int ret = 0;
@@ -220,12 +428,518 @@ static int init_misc_device_context(struct se_if_priv *priv, int ch_id,
 	if (!dev_ctx->devname)
 		return -ENOMEM;
 
+	mutex_init(&dev_ctx->fops_lock);
+
+	dev_ctx->priv = priv;
+	*new_dev_ctx = dev_ctx;
+
+	dev_ctx->miscdev = devm_kzalloc(priv->dev, sizeof(*dev_ctx->miscdev), GFP_KERNEL);
+	if (!dev_ctx->miscdev) {
+		*new_dev_ctx = NULL;
+		return -ENOMEM;
+	}
+
+	dev_ctx->miscdev->name = dev_ctx->devname;
+	dev_ctx->miscdev->minor = MISC_DYNAMIC_MINOR;
+	dev_ctx->miscdev->fops = se_if_fops;
+	dev_ctx->miscdev->parent = priv->dev;
+	ret = misc_register(dev_ctx->miscdev);
+	if (ret)
+		return dev_err_probe(priv->dev, ret, "Failed to register misc device.");
+
+	ret = devm_add_action_or_reset(priv->dev, if_misc_deregister, dev_ctx->miscdev);
+	if (ret)
+		return dev_err_probe(priv->dev, ret,
+				     "Failed to add action to the misc-dev.");
+	return ret;
+}
+
+static int init_device_context(struct se_if_priv *priv, int ch_id,
+			       struct se_if_device_ctx **new_dev_ctx)
+{
+	struct se_if_device_ctx *dev_ctx;
+	int ret = 0;
+
+	dev_ctx = kzalloc(sizeof(*dev_ctx), GFP_KERNEL);
+
+	if (!dev_ctx)
+		return -ENOMEM;
+
+	dev_ctx->devname = kasprintf(GFP_KERNEL, "%s0_ch%d",
+				     get_se_if_name(priv->if_defs->se_if_type),
+				     ch_id);
+	if (!dev_ctx->devname) {
+		kfree(dev_ctx);
+		return -ENOMEM;
+	}
+
+	mutex_init(&dev_ctx->fops_lock);
 	dev_ctx->priv = priv;
 	*new_dev_ctx = dev_ctx;
 
+	list_add_tail(&dev_ctx->link, &priv->dev_ctx_list);
+	priv->active_devctx_count++;
+
+	ret = init_se_shared_mem(dev_ctx);
+	if (ret < 0) {
+		kfree(dev_ctx->devname);
+		kfree(dev_ctx);
+		*new_dev_ctx = NULL;
+	}
+
 	return ret;
 }
 
+static int se_ioctl_cmd_snd_rcv_rsp_handler(struct se_if_device_ctx *dev_ctx,
+					    u64 arg)
+{
+	struct se_ioctl_cmd_snd_rcv_rsp_info cmd_snd_rcv_rsp_info = {0};
+	struct se_if_priv *priv = dev_ctx->priv;
+	int err = 0;
+
+	if (copy_from_user(&cmd_snd_rcv_rsp_info, (u8 __user *)arg,
+			   sizeof(cmd_snd_rcv_rsp_info))) {
+		dev_err(priv->dev,
+			"%s: Failed to copy cmd_snd_rcv_rsp_info from user.",
+			dev_ctx->devname);
+		err = -EFAULT;
+		goto exit;
+	}
+
+	if (cmd_snd_rcv_rsp_info.tx_buf_sz < SE_MU_HDR_SZ) {
+		dev_err(priv->dev, "%s: User buffer too small(%d < %d)",
+			dev_ctx->devname, cmd_snd_rcv_rsp_info.tx_buf_sz, SE_MU_HDR_SZ);
+		err = -ENOSPC;
+		goto exit;
+	}
+
+	err = se_chk_tx_msg_hdr(priv, (struct se_msg_hdr *)cmd_snd_rcv_rsp_info.tx_buf);
+	if (err)
+		goto exit;
+
+	struct se_api_msg *rx_msg __free(kfree) =
+		kzalloc(cmd_snd_rcv_rsp_info.rx_buf_sz, GFP_KERNEL);
+	if (!rx_msg) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	struct se_api_msg *tx_msg __free(kfree) =
+		memdup_user(cmd_snd_rcv_rsp_info.tx_buf,
+			    cmd_snd_rcv_rsp_info.tx_buf_sz);
+	if (IS_ERR(tx_msg)) {
+		err = PTR_ERR(tx_msg);
+		goto exit;
+	}
+
+	if (tx_msg->header.tag != priv->if_defs->cmd_tag) {
+		err = -EINVAL;
+		goto exit;
+	}
+
+	if (tx_msg->header.ver == priv->if_defs->fw_api_ver &&
+	    get_load_fw_instance(priv)->is_fw_tobe_loaded) {
+		err = se_load_firmware(priv);
+		if (err) {
+			dev_err(priv->dev, "Could not send msg as FW is not loaded.");
+			err = -EPERM;
+			goto exit;
+		}
+	}
+	set_se_rcv_msg_timeout(priv, SE_RCV_MSG_LONG_TIMEOUT);
+
+	err = ele_msg_send_rcv(dev_ctx, tx_msg, cmd_snd_rcv_rsp_info.tx_buf_sz,
+			       rx_msg, cmd_snd_rcv_rsp_info.rx_buf_sz);
+	if (err < 0)
+		goto exit;
+
+	dev_dbg(priv->dev, "%s: %s %s.", dev_ctx->devname, __func__,
+		"message received, start transmit to user");
+
+	/* We may need to copy the output data to user before
+	 * delivering the completion message.
+	 */
+	err = se_dev_ctx_cpy_out_data(dev_ctx);
+	if (err < 0)
+		goto exit;
+
+	/* Copy data from the buffer */
+	print_hex_dump_debug("to user ", DUMP_PREFIX_OFFSET, 4, 4, rx_msg,
+			     cmd_snd_rcv_rsp_info.rx_buf_sz, false);
+
+	if (copy_to_user(cmd_snd_rcv_rsp_info.rx_buf, rx_msg,
+			 cmd_snd_rcv_rsp_info.rx_buf_sz)) {
+		dev_err(priv->dev, "%s: Failed to copy to user.", dev_ctx->devname);
+		err = -EFAULT;
+	}
+
+exit:
+
+	/* shared memory is allocated before this IOCTL */
+	se_dev_ctx_shared_mem_cleanup(dev_ctx);
+
+	if (copy_to_user((void __user *)arg, &cmd_snd_rcv_rsp_info,
+			 sizeof(cmd_snd_rcv_rsp_info))) {
+		dev_err(priv->dev, "%s: Failed to copy cmd_snd_rcv_rsp_info from user.",
+			dev_ctx->devname);
+		err = -EFAULT;
+	}
+
+	kfree(tx_msg);
+	kfree(rx_msg);
+	return err;
+}
+
+static int se_ioctl_get_mu_info(struct se_if_device_ctx *dev_ctx,
+				u64 arg)
+{
+	struct se_if_priv *priv = dev_ctx->priv;
+	struct se_ioctl_get_if_info if_info;
+	struct se_if_node *if_node;
+	int err = 0;
+
+	if_node = container_of(priv->if_defs, typeof(*if_node), if_defs);
+
+	if_info.se_if_id = 0;
+	if_info.interrupt_idx = 0;
+	if_info.tz = 0;
+	if_info.did = 0;
+	if_info.cmd_tag = priv->if_defs->cmd_tag;
+	if_info.rsp_tag = priv->if_defs->rsp_tag;
+	if_info.success_tag = priv->if_defs->success_tag;
+	if_info.base_api_ver = priv->if_defs->base_api_ver;
+	if_info.fw_api_ver = priv->if_defs->fw_api_ver;
+
+	dev_dbg(priv->dev, "%s: info [se_if_id: %d, irq_idx: %d, tz: 0x%x, did: 0x%x].",
+		dev_ctx->devname, if_info.se_if_id, if_info.interrupt_idx, if_info.tz,
+		if_info.did);
+
+	if (copy_to_user((u8 __user *)arg, &if_info, sizeof(if_info))) {
+		dev_err(priv->dev, "%s: Failed to copy mu info to user.",
+			dev_ctx->devname);
+		err = -EFAULT;
+	}
+
+	return err;
+}
+
+/*
+ * Copy a buffer of data to/from the user and return the address to use in
+ * messages
+ */
+static int se_ioctl_setup_iobuf_handler(struct se_if_device_ctx *dev_ctx,
+					u64 arg)
+{
+	struct se_shared_mem *shared_mem = NULL;
+	struct se_ioctl_setup_iobuf io = {0};
+	int err = 0;
+	u32 pos;
+
+	if (copy_from_user(&io, (u8 __user *)arg, sizeof(io))) {
+		dev_err(dev_ctx->priv->dev, "%s: Failed copy iobuf config from user.",
+			dev_ctx->devname);
+		return -EFAULT;
+	}
+
+	dev_dbg(dev_ctx->priv->dev, "%s: io [buf: %p(%d) flag: %x].", dev_ctx->devname,
+		io.user_buf, io.length, io.flags);
+
+	if (io.length == 0 || !io.user_buf) {
+		/*
+		 * Accept NULL pointers since some buffers are optional
+		 * in FW commands. In this case we should return 0 as
+		 * pointer to be embedded into the message.
+		 * Skip all data copy part of code below.
+		 */
+		io.ele_addr = 0;
+		goto copy;
+	}
+
+	/* No specific requirement for this buffer. */
+	shared_mem = &dev_ctx->se_shared_mem_mgmt.non_secure_mem;
+
+	/* Check there is enough space in the shared memory. */
+	dev_dbg(dev_ctx->priv->dev, "%s: req_size = %d, max_size= %d, curr_pos = %d",
+		dev_ctx->devname, round_up(io.length, 8u), shared_mem->size,
+		shared_mem->pos);
+
+	if (shared_mem->size < shared_mem->pos ||
+	    round_up(io.length, 8u) > (shared_mem->size - shared_mem->pos)) {
+		dev_err(dev_ctx->priv->dev, "%s: Not enough space in shared memory.",
+			dev_ctx->devname);
+		return -ENOMEM;
+	}
+
+	/* Allocate space in shared memory. 8 bytes aligned. */
+	pos = shared_mem->pos;
+	shared_mem->pos += round_up(io.length, 8u);
+	io.ele_addr = (u64)shared_mem->dma_addr + pos;
+
+	memset(shared_mem->ptr + pos, 0, io.length);
+	if ((io.flags & SE_IO_BUF_FLAGS_IS_INPUT) ||
+	    (io.flags & SE_IO_BUF_FLAGS_IS_IN_OUT)) {
+		/*
+		 * buffer is input:
+		 * copy data from user space to this allocated buffer.
+		 */
+		if (copy_from_user(shared_mem->ptr + pos, io.user_buf, io.length)) {
+			dev_err(dev_ctx->priv->dev,
+				"%s: Failed copy data to shared memory.",
+				dev_ctx->devname);
+			return -EFAULT;
+		}
+	}
+
+	err = add_b_desc_to_pending_list(shared_mem->ptr + pos, &io, dev_ctx);
+	if (err < 0)
+		dev_err(dev_ctx->priv->dev, "%s: Failed to allocate/link b_desc.",
+			dev_ctx->devname);
+
+copy:
+	/* Provide the EdgeLock Enclave address to user space only if success.*/
+	if (copy_to_user((u8 __user *)arg, &io, sizeof(io))) {
+		dev_err(dev_ctx->priv->dev, "%s: Failed to copy iobuff setup to user.",
+			dev_ctx->devname);
+		err = -EFAULT;
+	}
+
+	return err;
+}
+
+/* IOCTL to provide SoC information */
+static int se_ioctl_get_se_soc_info_handler(struct se_if_device_ctx *dev_ctx, u64 arg)
+{
+	struct se_ioctl_get_soc_info soc_info;
+	int err = -EINVAL;
+
+	soc_info.soc_id = get_se_soc_id(dev_ctx->priv);
+	soc_info.soc_rev = var_se_info.soc_rev;
+
+	err = copy_to_user((u8 __user *)arg, (u8 *)(&soc_info), sizeof(soc_info));
+	if (err) {
+		dev_err(dev_ctx->priv->dev, "%s: Failed to copy soc info to user.",
+			dev_ctx->devname);
+		err = -EFAULT;
+	}
+
+	return err;
+}
+
+/*
+ * File operations for user-space
+ */
+
+/* Write a message to the MU. */
+static ssize_t se_if_fops_write(struct file *fp, const char __user *buf,
+				size_t size, loff_t *ppos)
+{
+	struct se_if_device_ctx *dev_ctx = fp->private_data;
+	struct se_if_priv *priv = dev_ctx->priv;
+	int err;
+
+	dev_dbg(priv->dev, "%s: write from buf (%p)%zu, ppos=%lld.", dev_ctx->devname,
+		buf, size, ((ppos) ? *ppos : 0));
+
+	scoped_cond_guard(mutex_intr, return -EBUSY, &dev_ctx->fops_lock) {
+		if (dev_ctx != priv->cmd_receiver_clbk_hdl.dev_ctx)
+			return -EINVAL;
+
+		err = se_chk_tx_msg_hdr(priv, (struct se_msg_hdr *)buf);
+		if (err)
+			return err;
+
+		if (size < SE_MU_HDR_SZ) {
+			dev_err(priv->dev, "%s: User buffer too small(%zu < %d).",
+				dev_ctx->devname, size, SE_MU_HDR_SZ);
+			return -ENOSPC;
+		}
+
+		struct se_api_msg *tx_msg __free(kfree) = memdup_user(buf, size);
+		if (IS_ERR(tx_msg))
+			return PTR_ERR(tx_msg);
+
+		print_hex_dump_debug("from user ", DUMP_PREFIX_OFFSET, 4, 4,
+				     tx_msg, size, false);
+
+		err = ele_msg_send(dev_ctx, tx_msg, size);
+
+		return err;
+	}
+}
+
+/*
+ * Read a message from the MU.
+ * Blocking until a message is available.
+ */
+static ssize_t se_if_fops_read(struct file *fp, char __user *buf, size_t size,
+			       loff_t *ppos)
+{
+	struct se_if_device_ctx *dev_ctx = fp->private_data;
+	struct se_if_priv *priv = dev_ctx->priv;
+	int err;
+
+	dev_dbg(priv->dev, "%s: read to buf %p(%zu), ppos=%lld.", dev_ctx->devname,
+		buf, size, ((ppos) ? *ppos : 0));
+
+	scoped_cond_guard(mutex_intr, return -EBUSY, &dev_ctx->fops_lock) {
+		if (dev_ctx != priv->cmd_receiver_clbk_hdl.dev_ctx) {
+			err = -EINVAL;
+			goto exit;
+		}
+
+		err = ele_msg_rcv(dev_ctx, &priv->cmd_receiver_clbk_hdl);
+		if (err < 0) {
+			dev_err(priv->dev, "%s: Err[0x%x]:Interrupted by signal."
+				"Current active dev-ctx count = %d.",
+				dev_ctx->devname, err, dev_ctx->priv->active_devctx_count);
+			goto exit;
+		}
+
+		/* We may need to copy the output data to user before
+		 * delivering the completion message.
+		 */
+		err = se_dev_ctx_cpy_out_data(dev_ctx);
+		if (err < 0)
+			goto exit;
+
+		/* Copy data from the buffer */
+		print_hex_dump_debug("to user ", DUMP_PREFIX_OFFSET, 4, 4,
+				     priv->cmd_receiver_clbk_hdl.rx_msg,
+				     priv->cmd_receiver_clbk_hdl.rx_msg_sz,
+				     false);
+
+		if (copy_to_user(buf, priv->cmd_receiver_clbk_hdl.rx_msg,
+				 priv->cmd_receiver_clbk_hdl.rx_msg_sz)) {
+			dev_err(priv->dev, "%s: Failed to copy to user.",
+				dev_ctx->devname);
+			err = -EFAULT;
+		} else {
+			err = priv->cmd_receiver_clbk_hdl.rx_msg_sz;
+		}
+exit:
+		priv->cmd_receiver_clbk_hdl.rx_msg_sz = 0;
+
+		se_dev_ctx_shared_mem_cleanup(dev_ctx);
+
+		return err;
+	}
+}
+
+/* Open a character device. */
+static int se_if_fops_open(struct inode *nd, struct file *fp)
+{
+	struct miscdevice *miscdev = fp->private_data;
+	struct se_if_device_ctx *misc_dev_ctx;
+	struct se_if_device_ctx *dev_ctx;
+	struct se_if_priv *priv;
+	int err = 0;
+
+	priv = dev_get_drvdata(miscdev->parent);
+	misc_dev_ctx = priv->priv_dev_ctx;
+
+	scoped_cond_guard(mutex_intr, return -EBUSY, &misc_dev_ctx->fops_lock) {
+		priv->dev_ctx_mono_count++;
+		err = init_device_context(priv,
+					  priv->dev_ctx_mono_count ?
+					  priv->dev_ctx_mono_count
+					  : priv->dev_ctx_mono_count++,
+					  &dev_ctx);
+		if (err)
+			dev_err(priv->dev, "Failed[0x%x] to create dev-ctx.", err);
+		else
+			fp->private_data = dev_ctx;
+
+		return err;
+	}
+}
+
+/* Close a character device. */
+static int se_if_fops_close(struct inode *nd, struct file *fp)
+{
+	struct se_if_device_ctx *dev_ctx = fp->private_data;
+	struct se_if_priv *priv = dev_ctx->priv;
+
+	scoped_cond_guard(mutex_intr, return -EBUSY, &dev_ctx->fops_lock) {
+		/* check if this device was registered as command receiver. */
+		if (priv->cmd_receiver_clbk_hdl.dev_ctx == dev_ctx) {
+			priv->cmd_receiver_clbk_hdl.dev_ctx = NULL;
+			kfree(priv->cmd_receiver_clbk_hdl.rx_msg);
+			priv->cmd_receiver_clbk_hdl.rx_msg = NULL;
+		}
+
+		se_dev_ctx_shared_mem_cleanup(dev_ctx);
+		cleanup_se_shared_mem(dev_ctx);
+
+		priv->active_devctx_count--;
+		list_del(&dev_ctx->link);
+
+		kfree(dev_ctx->devname);
+		kfree(dev_ctx);
+	}
+
+	return 0;
+}
+
+/* IOCTL entry point of a character device */
+static long se_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
+{
+	struct se_if_device_ctx *dev_ctx = fp->private_data;
+	struct se_if_priv *priv = dev_ctx->priv;
+	long err;
+
+	/* Prevent race during change of device context */
+	scoped_cond_guard(mutex_intr, return -EBUSY, &dev_ctx->fops_lock) {
+		switch (cmd) {
+		case SE_IOCTL_ENABLE_CMD_RCV:
+			if (!priv->cmd_receiver_clbk_hdl.dev_ctx) {
+				if (!priv->cmd_receiver_clbk_hdl.rx_msg) {
+					priv->cmd_receiver_clbk_hdl.rx_msg =
+						kzalloc(MAX_NVM_MSG_LEN,
+							GFP_KERNEL);
+					if (!priv->cmd_receiver_clbk_hdl.rx_msg) {
+						err = -ENOMEM;
+						break;
+					}
+				}
+				priv->cmd_receiver_clbk_hdl.rx_msg_sz = MAX_NVM_MSG_LEN;
+				priv->cmd_receiver_clbk_hdl.dev_ctx = dev_ctx;
+				err = 0;
+			} else {
+				err = -EBUSY;
+			}
+			break;
+		case SE_IOCTL_GET_MU_INFO:
+			err = se_ioctl_get_mu_info(dev_ctx, arg);
+			break;
+		case SE_IOCTL_SETUP_IOBUF:
+			err = se_ioctl_setup_iobuf_handler(dev_ctx, arg);
+			break;
+		case SE_IOCTL_GET_SOC_INFO:
+			err = se_ioctl_get_se_soc_info_handler(dev_ctx, arg);
+			break;
+		case SE_IOCTL_CMD_SEND_RCV_RSP:
+			err = se_ioctl_cmd_snd_rcv_rsp_handler(dev_ctx, arg);
+			break;
+		default:
+			err = -EINVAL;
+			dev_dbg(priv->dev, "%s: IOCTL %.8x not supported.",
+				dev_ctx->devname, cmd);
+		}
+	}
+
+	return err;
+}
+
+/* Char driver setup */
+static const struct file_operations se_if_fops = {
+	.open		= se_if_fops_open,
+	.owner		= THIS_MODULE,
+	.release	= se_if_fops_close,
+	.unlocked_ioctl = se_ioctl,
+	.read		= se_if_fops_read,
+	.write		= se_if_fops_write,
+};
+
 /* interface for managed res to free a mailbox channel */
 static void if_mbox_free_channel(void *mbox_chan)
 {
@@ -246,7 +960,7 @@ static int se_if_request_channel(struct device *dev, struct mbox_chan **chan,
 	ret = devm_add_action_or_reset(dev, if_mbox_free_channel, t_chan);
 	if (ret)
 		return dev_err_probe(dev, -EPERM,
-				     "Failed to add-action for removal of mbox: %s\n",
+				     "Failed to add-action for removal of mbox: %s.",
 				     name);
 	*chan = t_chan;
 
@@ -255,6 +969,7 @@ static int se_if_request_channel(struct device *dev, struct mbox_chan **chan,
 
 static void se_if_probe_cleanup(void *plat_dev)
 {
+	struct se_if_device_ctx *dev_ctx, *t_dev_ctx;
 	struct platform_device *pdev = plat_dev;
 	struct se_fw_load_info *load_fw;
 	struct device *dev = &pdev->dev;
@@ -279,6 +994,13 @@ static void se_if_probe_cleanup(void *plat_dev)
 		load_fw->imem.buf = NULL;
 	}
 
+	if (priv->dev_ctx_mono_count) {
+		list_for_each_entry_safe(dev_ctx, t_dev_ctx, &priv->dev_ctx_list, link) {
+			list_del(&dev_ctx->link);
+			priv->active_devctx_count--;
+		}
+	}
+
 	/*
 	 * No need to check, if reserved memory is allocated
 	 * before calling for its release. Or clearing the
@@ -319,6 +1041,7 @@ static int se_if_probe(struct platform_device *pdev)
 	priv->se_mb_cl.tx_block		= false;
 	priv->se_mb_cl.knows_txdone	= true;
 	priv->se_mb_cl.rx_callback	= se_if_rx_callback;
+	set_se_rcv_msg_timeout(priv, SE_RCV_MSG_DEFAULT_TIMEOUT);
 
 	ret = se_if_request_channel(dev, &priv->tx_chan, &priv->se_mb_cl, MBOX_TX_NAME);
 	if (ret)
@@ -340,6 +1063,7 @@ static int se_if_probe(struct platform_device *pdev)
 					     "Unable to get sram pool = %s.",
 					     if_node->pool_name);
 	}
+	INIT_LIST_HEAD(&priv->dev_ctx_list);
 
 	if (if_node->reserved_dma_ranges) {
 		ret = of_reserved_mem_device_init(dev);
@@ -348,7 +1072,7 @@ static int se_if_probe(struct platform_device *pdev)
 					    "Failed to init reserved memory region.");
 	}
 
-	ret = init_misc_device_context(priv, 0, &priv->priv_dev_ctx);
+	ret = init_misc_device_context(priv, 0, &priv->priv_dev_ctx, &se_if_fops);
 	if (ret)
 		return dev_err_probe(dev, ret,
 				     "Failed[0x%x] to create device contexts.",
@@ -389,6 +1113,7 @@ static int se_suspend(struct device *dev)
 	struct se_fw_load_info *load_fw;
 	int ret = 0;
 
+	set_se_rcv_msg_timeout(priv, SE_RCV_MSG_DEFAULT_TIMEOUT);
 	load_fw = get_load_fw_instance(priv);
 
 	if (load_fw->imem_mgmt) {
diff --git a/drivers/firmware/imx/se_ctrl.h b/drivers/firmware/imx/se_ctrl.h
index b5e7705e2f26..5fcdcfe3e8e5 100644
--- a/drivers/firmware/imx/se_ctrl.h
+++ b/drivers/firmware/imx/se_ctrl.h
@@ -14,6 +14,7 @@
 #define SE_MSG_WORD_SZ			0x4
 
 #define RES_STATUS(x)			FIELD_GET(0x000000ff, x)
+#define MAX_DATA_SIZE_PER_USER		(65 * 1024)
 #define MAX_NVM_MSG_LEN			(256)
 #define MESSAGING_VERSION_6		0x6
 #define MESSAGING_VERSION_7		0x7
@@ -37,10 +38,38 @@ struct se_imem_buf {
 	u32 state;
 };
 
+struct se_buf_desc {
+	u8 *shared_buf_ptr;
+	void __user *usr_buf_ptr;
+	u32 size;
+	struct list_head link;
+};
+
+struct se_shared_mem {
+	dma_addr_t dma_addr;
+	u32 size;
+	u32 pos;
+	u8 *ptr;
+};
+
+struct se_shared_mem_mgmt_info {
+	struct list_head pending_in;
+	struct list_head pending_out;
+
+	struct se_shared_mem non_secure_mem;
+};
+
 /* Private struct for each char device instance. */
 struct se_if_device_ctx {
 	struct se_if_priv *priv;
+	struct miscdevice *miscdev;
 	const char *devname;
+
+	/* process one file operation at a time. */
+	struct mutex fops_lock;
+
+	struct se_shared_mem_mgmt_info se_shared_mem_mgmt;
+	struct list_head link;
 };
 
 /* Header of the messages exchange with the EdgeLock Enclave */
@@ -89,6 +118,10 @@ struct se_if_priv {
 	const struct se_if_defines *if_defs;
 
 	struct se_if_device_ctx *priv_dev_ctx;
+	struct list_head dev_ctx_list;
+	u32 active_devctx_count;
+	u32 dev_ctx_mono_count;
+	u32 se_rcv_msg_timeout_ms;
 };
 
 char *get_se_if_name(u8 se_if_id);
diff --git a/include/uapi/linux/se_ioctl.h b/include/uapi/linux/se_ioctl.h
new file mode 100644
index 000000000000..0c948bdc8c26
--- /dev/null
+++ b/include/uapi/linux/se_ioctl.h
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause*/
+/*
+ * Copyright 2025 NXP
+ */
+
+#ifndef SE_IOCTL_H
+#define SE_IOCTL_H
+
+#include <linux/types.h>
+
+#define SE_TYPE_STR_DBG			"dbg"
+#define SE_TYPE_STR_HSM			"hsm"
+#define SE_TYPE_ID_UNKWN		0x0
+#define SE_TYPE_ID_DBG			0x1
+#define SE_TYPE_ID_HSM			0x2
+/* IOCTL definitions. */
+
+struct se_ioctl_setup_iobuf {
+	void __user *user_buf;
+	__u32 length;
+	__u32 flags;
+	__u64 ele_addr;
+};
+
+struct se_ioctl_shared_mem_cfg {
+	__u32 base_offset;
+	__u32 size;
+};
+
+struct se_ioctl_get_if_info {
+	__u8 se_if_id;
+	__u8 interrupt_idx;
+	__u8 tz;
+	__u8 did;
+	__u8 cmd_tag;
+	__u8 rsp_tag;
+	__u8 success_tag;
+	__u8 base_api_ver;
+	__u8 fw_api_ver;
+};
+
+struct se_ioctl_cmd_snd_rcv_rsp_info {
+	__u32 __user *tx_buf;
+	int tx_buf_sz;
+	__u32 __user *rx_buf;
+	int rx_buf_sz;
+};
+
+struct se_ioctl_get_soc_info {
+	__u16 soc_id;
+	__u16 soc_rev;
+};
+
+/* IO Buffer Flags */
+#define SE_IO_BUF_FLAGS_IS_OUTPUT	(0x00u)
+#define SE_IO_BUF_FLAGS_IS_INPUT	(0x01u)
+#define SE_IO_BUF_FLAGS_USE_SEC_MEM	(0x02u)
+#define SE_IO_BUF_FLAGS_USE_SHORT_ADDR	(0x04u)
+#define SE_IO_BUF_FLAGS_IS_IN_OUT	(0x10u)
+
+/* IOCTLS */
+#define SE_IOCTL			0x0A /* like MISC_MAJOR. */
+
+/*
+ * ioctl to designated the current fd as logical-reciever.
+ * This is ioctl is send when the nvm-daemon, a slave to the
+ * firmware is started by the user.
+ */
+#define SE_IOCTL_ENABLE_CMD_RCV	_IO(SE_IOCTL, 0x01)
+
+/*
+ * ioctl to get the buffer allocated from the memory, which is shared
+ * between kernel and FW.
+ * Post allocation, the kernel tagged the allocated memory with:
+ *  Output
+ *  Input
+ *  Input-Output
+ *  Short address
+ *  Secure-memory
+ */
+#define SE_IOCTL_SETUP_IOBUF	_IOWR(SE_IOCTL, 0x03, struct se_ioctl_setup_iobuf)
+
+/*
+ * ioctl to get the mu information, that is used to exchange message
+ * with FW, from user-spaced.
+ */
+#define SE_IOCTL_GET_MU_INFO	_IOR(SE_IOCTL, 0x04, struct se_ioctl_get_if_info)
+/*
+ * ioctl to get SoC Info from user-space.
+ */
+#define SE_IOCTL_GET_SOC_INFO      _IOR(SE_IOCTL, 0x06, struct se_ioctl_get_soc_info)
+
+/*
+ * ioctl to send command and receive response from user-space.
+ */
+#define SE_IOCTL_CMD_SEND_RCV_RSP _IOWR(SE_IOCTL, 0x07, struct se_ioctl_cmd_snd_rcv_rsp_info)
+#endif

-- 
2.43.0



From pankaj.gupta at nxp.com  Wed Dec 17 22:46:29 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Thu, 18 Dec 2025 12:16:29 +0530
Subject: [PATCH v22 6/7] arm64: dts: imx8ulp: add secure enclave node
In-Reply-To: <20251218-imx-se-if-v22-0-07418c872509@nxp.com>
References: <20251218-imx-se-if-v22-0-07418c872509@nxp.com>
Message-ID: <20251218-imx-se-if-v22-6-07418c872509@nxp.com>

Add support for NXP secure enclave called EdgeLock Enclave firmware (se-fw)
for imx8ulp-evk.

Add label sram0 for sram at 2201f000 and add secure-enclave node

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
 arch/arm64/boot/dts/freescale/imx8ulp.dtsi | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8ulp.dtsi b/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
index 13b01f3aa2a4..10a4779dd24c 100644
--- a/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
- * Copyright 2021 NXP
+ * Copyright 2021, 2025 NXP
  */
 
 #include <dt-bindings/clock/imx8ulp-clock.h>
@@ -154,7 +154,7 @@ sosc: clock-sosc {
 		#clock-cells = <0>;
 	};
 
-	sram at 2201f000 {
+	sram0: sram at 2201f000 {
 		compatible = "mmio-sram";
 		reg = <0x0 0x2201f000 0x0 0x1000>;
 
@@ -186,6 +186,13 @@ scmi_sensor: protocol at 15 {
 				#thermal-sensor-cells = <1>;
 			};
 		};
+
+		hsm0: secure-enclave {
+			 compatible = "fsl,imx8ulp-se-ele-hsm";
+			 mbox-names = "tx", "rx";
+			 mboxes = <&s4muap 0 0>, <&s4muap 1 0>;
+			 sram = <&sram0>;
+		 };
 	};
 
 	cm33: remoteproc-cm33 {

-- 
2.43.0



From pankaj.gupta at nxp.com  Wed Dec 17 22:46:30 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Thu, 18 Dec 2025 12:16:30 +0530
Subject: [PATCH v22 7/7] arm64: dts: imx8ulp-evk: add reserved memory
 property
In-Reply-To: <20251218-imx-se-if-v22-0-07418c872509@nxp.com>
References: <20251218-imx-se-if-v22-0-07418c872509@nxp.com>
Message-ID: <20251218-imx-se-if-v22-7-07418c872509@nxp.com>

Reserve 1MB of DDR memory region due to EdgeLock Enclave's hardware
limitation restricting access to DDR addresses from 0x80000000
to 0xafffffff.

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
 arch/arm64/boot/dts/freescale/imx8ulp-evk.dts | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8ulp-evk.dts b/arch/arm64/boot/dts/freescale/imx8ulp-evk.dts
index 290a49bea2f7..10aaf02f8ea7 100644
--- a/arch/arm64/boot/dts/freescale/imx8ulp-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8ulp-evk.dts
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
- * Copyright 2021 NXP
+ * Copyright 2021, 2025 NXP
  */
 
 /dts-v1/;
@@ -37,6 +37,12 @@ linux,cma {
 			linux,cma-default;
 		};
 
+		ele_reserved: memory at 90000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x90000000 0 0x100000>;
+			no-map;
+		};
+
 		m33_reserved: noncacheable-section at a8600000 {
 			reg = <0 0xa8600000 0 0x1000000>;
 			no-map;
@@ -259,6 +265,10 @@ &usdhc0 {
 	status = "okay";
 };
 
+&hsm0 {
+	memory-region = <&ele_reserved>;
+};
+
 &fec {
 	pinctrl-names = "default", "sleep";
 	pinctrl-0 = <&pinctrl_enet>;

-- 
2.43.0



From krzk at kernel.org  Wed Dec 17 22:48:26 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 18 Dec 2025 07:48:26 +0100
Subject: [PATCH 10/12] dt-bindings: ras: document estatus provider
In-Reply-To: <20251217174933.1938909-1-ahmed.tiba@arm.com>
References: <cd04e23a-9523-4d25-8240-29a0dffa0e75@kernel.org>
 <20251217174933.1938909-1-ahmed.tiba@arm.com>
Message-ID: <2a2baef6-c294-4c31-bec2-10fbaa3f7941@kernel.org>

On 17/12/2025 18:49, Ahmed Tiba wrote:
> On 17/12/2025 12:41, Krzysztof Kozlowski wrote:
>> What is ras? There is no such directory so some description would be
>> useful. Usually you do not get your own directory per binding.
> 
> Would it make sense to move it under `Documentation/devicetree/bindings/firmware`
> and expand the description so it spells out that
> Arm RAS refers to reliability, availability and serviceability firmware.
> 
>> Do not describe what the binding does. Describe the hardware or firmware.
> 
> I'll reword that section.
> 
>> Again ras - what's that? Your patch or binding must explain that.

You cut almost entire context, so I don't know what these parts are
referring to.

Please follow standard mailing list reply style. I am not reading the
rest and I still expect to implement my feedback fully.

Best regards,
Krzysztof


From amhetre at nvidia.com  Wed Dec 17 23:03:52 2025
From: amhetre at nvidia.com (Ashish Mhetre)
Date: Thu, 18 Dec 2025 12:33:52 +0530
Subject: [PATCH V7 3/4] dt-bindings: iommu: Add NVIDIA Tegra CMDQV support
In-Reply-To: <fbde672b-611a-4d81-ac05-44e434bf70ae@nvidia.com>
References: <20251215064819.3345361-1-amhetre@nvidia.com>
 <20251215064819.3345361-4-amhetre@nvidia.com>
 <fbde672b-611a-4d81-ac05-44e434bf70ae@nvidia.com>
Message-ID: <38364cfe-8fc9-4ed7-9034-4e67584ee965@nvidia.com>


On 12/18/2025 2:01 AM, Jon Hunter wrote:
>
>
> On 15/12/2025 06:48, Ashish Mhetre wrote:
>> The Command Queue Virtualization (CMDQV) hardware is part of the
>> SMMUv3 implementation on NVIDIA Tegra SoCs. It assists in
>> virtualizing the command queue for the SMMU.
>>
>> Add a new device tree binding document for nvidia,tegra264-cmdqv.
>>
>> Also update the arm,smmu-v3 binding to include an optional nvidia,cmdqv
>> property. This property is a phandle to the CMDQV device node, allowing
>> the SMMU driver to associate with its corresponding CMDQV instance.
>> Restrict this property usage to Nvidia Tegra264 only.
>>
>> Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
>> Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
>> ---
>> ? .../bindings/iommu/arm,smmu-v3.yaml?????????? | 30 ++++++++++++-
>> ? .../bindings/iommu/nvidia,tegra264-cmdqv.yaml | 42 +++++++++++++++++++
>> ? 2 files changed, 70 insertions(+), 2 deletions(-)
>> ? create mode 100644 
>> Documentation/devicetree/bindings/iommu/nvidia,tegra264-cmdqv.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml 
>> b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
>> index 75fcf4cb52d9..1c03482e4c61 100644
>> --- a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
>> +++ b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
>> @@ -20,7 +20,12 @@ properties:
>> ??? $nodename:
>> ????? pattern: "^iommu@[0-9a-f]*"
>> ??? compatible:
>> -??? const: arm,smmu-v3
>> +??? oneOf:
>> +????? - const: arm,smmu-v3
>> +????? - items:
>> +????????? - enum:
>> +????????????? - nvidia,tegra264-smmu
>> +????????? - const: arm,smmu-v3
>> ? ??? reg:
>> ????? maxItems: 1
>> @@ -58,6 +63,15 @@ properties:
>> ? ??? msi-parent: true
>> ? +? nvidia,cmdqv:
>> +??? description: |
>> +????? A phandle to its pairing CMDQV extension for an implementation 
>> on NVIDIA
>> +????? Tegra SoC.
>> +
>> +????? If this property is absent, CMDQ-Virtualization won't be used 
>> and SMMU
>> +????? will only use its own CMDQ.
>> +??? $ref: /schemas/types.yaml#/definitions/phandle
>> +
>> ??? hisilicon,broken-prefetch-cmd:
>> ????? type: boolean
>> ????? description: Avoid sending CMD_PREFETCH_* commands to the SMMU.
>> @@ -69,6 +83,17 @@ properties:
>> ??????? register access with page 0 offsets. Set for Cavium ThunderX2 
>> silicon that
>> ??????? doesn't support SMMU page1 register space.
>> ? +allOf:
>> +? - if:
>> +????? not:
>> +??????? properties:
>> +????????? compatible:
>> +??????????? contains:
>> +????????????? const: nvidia,tegra264-smmu
>> +??? then:
>> +????? properties:
>> +??????? nvidia,cmdqv: false
>> +
>> ? required:
>> ??? - compatible
>> ??? - reg
>> @@ -82,7 +107,7 @@ examples:
>> ????? #include <dt-bindings/interrupt-controller/irq.h>
>> ? ????? iommu at 2b400000 {
>> -??????????? compatible = "arm,smmu-v3";
>> +??????????? compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
>> ????????????? reg = <0x2b400000 0x20000>;
>> ????????????? interrupts = <GIC_SPI 74 IRQ_TYPE_EDGE_RISING>,
>> ?????????????????????????? <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>,
>> @@ -92,4 +117,5 @@ examples:
>> ????????????? dma-coherent;
>> ????????????? #iommu-cells = <1>;
>> ????????????? msi-parent = <&its 0xff0000>;
>> +??????????? nvidia,cmdqv = <&cmdqv>;
>
> So I believe that this is a generic example for arm,smmu-v3, and so I 
> am not sure we want to be adding all these NVIDIA specific bits here. 
> What would be more appropriate is to add another example under the 
> existing example specifically for Tegra264.
>
> Jon
>

Yeah, makes sense. However, I checked arm-smmu.yaml (v2) binding docs
and we had separate Nvidia specific compatible and property
(nvidia,memory-controller) there as well. But we didn't have a separate
example for showing this compatible and property. So, I wonder if we
even need to update the generic smmuv3 example for cmdqv property or
add a new example?
Can you all please share your inputs on this?
If required, I'll update the patch will the change below:


diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml 
b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
index 1c03482e4c61..6b07ca9928a7 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
@@ -107,7 +107,7 @@ examples:
 ? ? ?#include <dt-bindings/interrupt-controller/irq.h>

 ? ? ?iommu at 2b400000 {
-? ? ? ? ? ? compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
+? ? ? ? ? ? compatible = "arm,smmu-v3";
 ? ? ? ? ? ? ?reg = <0x2b400000 0x20000>;
 ? ? ? ? ? ? ?interrupts = <GIC_SPI 74 IRQ_TYPE_EDGE_RISING>,
 ? ? ? ? ? ? ? ? ? ? ? ? ? <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>,
@@ -117,5 +117,26 @@ examples:
 ? ? ? ? ? ? ?dma-coherent;
 ? ? ? ? ? ? ?#iommu-cells = <1>;
 ? ? ? ? ? ? ?msi-parent = <&its 0xff0000>;
+? ? };
+
+? - |+
+? ? /* Example for NVIDIA Tegra264 with CMDQV extension */
+? ? #include <dt-bindings/interrupt-controller/arm-gic.h>
+? ? #include <dt-bindings/interrupt-controller/irq.h>
+
+? ? iommu at 5000000 {
+? ? ? ? ? ? compatible = "nvidia,tegra264-smmu", "arm,smmu-v3";
+? ? ? ? ? ? reg = <0x5000000 0x200000>;
+? ? ? ? ? ? interrupts = <GIC_SPI 12 IRQ_TYPE_EDGE_RISING>,
+? ? ? ? ? ? ? ? ? ? ? ? ?<GIC_SPI 13 IRQ_TYPE_EDGE_RISING>;
+? ? ? ? ? ? interrupt-names = "eventq", "gerror";
+? ? ? ? ? ? dma-coherent;
+? ? ? ? ? ? #iommu-cells = <1>;
 ? ? ? ? ? ? ?nvidia,cmdqv = <&cmdqv>;
 ? ? ?};
+
+? ? cmdqv: cmdqv at 5200000 {
+? ? ? ? ? ? compatible = "nvidia,tegra264-cmdqv";
+? ? ? ? ? ? reg = <0x5200000 0x830000>;
+? ? ? ? ? ? interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+? ? };

Thanks,
Ashish Mhetre


From linu.cherian at arm.com  Wed Dec 17 23:05:41 2025
From: linu.cherian at arm.com (Linu Cherian)
Date: Thu, 18 Dec 2025 12:35:41 +0530
Subject: [PATCH v1 03/13] arm64: mm: Implicitly invalidate user ASID
 based on TLBI operation
In-Reply-To: <aUOfnXnGVROEXH4r@a079125.arm.com>
References: <20251216144601.2106412-1-ryan.roberts@arm.com>
 <20251216144601.2106412-4-ryan.roberts@arm.com>
 <aUOfnXnGVROEXH4r@a079125.arm.com>
Message-ID: <aUOnxYvmXwOJL4yU@a079125.arm.com>



On Thu, Dec 18, 2025 at 12:00:57PM +0530, Linu Cherian wrote:
> Ryan,
> 
> On Tue, Dec 16, 2025 at 02:45:48PM +0000, Ryan Roberts wrote:
> > When kpti is enabled, separate ASIDs are used for userspace and
> > kernelspace, requiring ASID-qualified TLB invalidation by virtual
> > address to invalidate both of them.
> > 
> > Push the logic for invalidating the two ASIDs down into the low-level
> > tlbi-op-specific functions and remove the burden from the caller to
> > handle the kpti-specific behaviour.
> > 
> > Co-developed-by: Will Deacon <will at kernel.org>
> > Signed-off-by: Will Deacon <will at kernel.org>
> > Signed-off-by: Ryan Roberts <ryan.roberts at arm.com>
> > ---
> >  arch/arm64/include/asm/tlbflush.h | 27 ++++++++++-----------------
> >  1 file changed, 10 insertions(+), 17 deletions(-)
> > 
> > diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
> > index c5111d2afc66..31f43d953ce2 100644
> > --- a/arch/arm64/include/asm/tlbflush.h
> > +++ b/arch/arm64/include/asm/tlbflush.h
> > @@ -110,6 +110,7 @@ typedef void (*tlbi_op)(u64 arg);
> >  static __always_inline void vae1is(u64 arg)
> >  {
> >  	__tlbi(vae1is, arg);
> > +	__tlbi_user(vae1is, arg);
> >  }
> >  
> >  static __always_inline void vae2is(u64 arg)
> > @@ -126,6 +127,7 @@ static __always_inline void vale1(u64 arg)
> >  static __always_inline void vale1is(u64 arg)
> >  {
> >  	__tlbi(vale1is, arg);
> > +	__tlbi_user(vale1is, arg);
> >  }
> >  
> >  static __always_inline void vale2is(u64 arg)
> > @@ -162,11 +164,6 @@ static __always_inline void __tlbi_level(tlbi_op op, u64 addr, u32 level)
> >  	op(arg);
> >  }
> >  
> > -#define __tlbi_user_level(op, arg, level) do {				\
> > -	if (arm64_kernel_unmapped_at_el0())				\
> > -		__tlbi_level(op, (arg | USER_ASID_FLAG), level);	\
> > -} while (0)
> > -
> >  /*
> >   * This macro creates a properly formatted VA operand for the TLB RANGE. The
> >   * value bit assignments are:
> > @@ -435,8 +432,6 @@ static inline void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch)
> >   * @stride:	Flush granularity
> >   * @asid:	The ASID of the task (0 for IPA instructions)
> >   * @tlb_level:	Translation Table level hint, if known
> > - * @tlbi_user:	If 'true', call an additional __tlbi_user()
> > - *              (typically for user ASIDs). 'flase' for IPA instructions
> >   * @lpa2:	If 'true', the lpa2 scheme is used as set out below
> >   *
> >   * When the CPU does not support TLB range operations, flush the TLB
> > @@ -462,6 +457,7 @@ static inline void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch)
> >  static __always_inline void rvae1is(u64 arg)
> >  {
> >  	__tlbi(rvae1is, arg);
> > +	__tlbi_user(rvae1is, arg);
> >  }
> >  
> >  static __always_inline void rvale1(u64 arg)
> > @@ -473,6 +469,7 @@ static __always_inline void rvale1(u64 arg)
> >  static __always_inline void rvale1is(u64 arg)
> >  {
> >  	__tlbi(rvale1is, arg);
> > +	__tlbi_user(rvale1is, arg);
> >  }
> >  
> >  static __always_inline void rvaale1is(u64 arg)
> > @@ -491,7 +488,7 @@ static __always_inline void __tlbi_range(tlbi_op op, u64 arg)
> >  }
> >  
> >  #define __flush_tlb_range_op(op, start, pages, stride,			\
> > -				asid, tlb_level, tlbi_user, lpa2)	\
> > +				asid, tlb_level, lpa2)			\
> >  do {									\
> >  	typeof(start) __flush_start = start;				\
> >  	typeof(pages) __flush_pages = pages;				\
> > @@ -506,8 +503,6 @@ do {									\
> >  		    (lpa2 && __flush_start != ALIGN(__flush_start, SZ_64K))) {	\
> >  			addr = __TLBI_VADDR(__flush_start, asid);	\
> >  			__tlbi_level(op, addr, tlb_level);		\
> > -			if (tlbi_user)					\
> > -				__tlbi_user_level(op, addr, tlb_level);	\
> >  			__flush_start += stride;			\
> >  			__flush_pages -= stride >> PAGE_SHIFT;		\
> >  			continue;					\
> > @@ -518,8 +513,6 @@ do {									\
> >  			addr = __TLBI_VADDR_RANGE(__flush_start >> shift, asid, \
> >  						scale, num, tlb_level);	\
> >  			__tlbi_range(r##op, addr);			\
> > -			if (tlbi_user)					\
> > -				__tlbi_user(r##op, addr);		\
> >  			__flush_start += __TLBI_RANGE_PAGES(num, scale) << PAGE_SHIFT; \
> >  			__flush_pages -= __TLBI_RANGE_PAGES(num, scale);\
> 
> 
> There are more __tlbi_user invocations in __flush_tlb_mm, __local_flush_tlb_page_nonotify_nosync
> and __flush_tlb_page_nosync in this file. Should we not address them as well as 
> part of this ?
> 

I see that except __flush_tlb_mm, the others got addressed in subsequent patches.
Should we hint this in the commit message ?


From krzk at kernel.org  Wed Dec 17 23:06:52 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 18 Dec 2025 08:06:52 +0100
Subject: [PATCH v9 2/2] usb: dwc3: Add Google Tensor SoC DWC3 glue driver
In-Reply-To: <CA+zupgyG4Nov0=jihSApp_3_0hy6YNZMkfOp6Q4-zmERFm10Ag@mail.gmail.com>
References: <20251205-controller-v9-0-9f158b18f979@google.com>
 <20251205-controller-v9-2-9f158b18f979@google.com>
 <2025120553-suffrage-divisive-5890@gregkh>
 <CA+zupgzL7v5MZDpxKDQQCqAZaqTdHbiG9-xTr+8RnigMFZJ_7Q@mail.gmail.com>
 <2025121728-reliably-crabgrass-2601@gregkh>
 <CA+zupgxZCyNonfNPbGnFymGGOQuaWR1TsL+hujTbH4DEcfEt9Q@mail.gmail.com>
 <CAD=FV=U63F-wxwKDo9be6_X2P2zp6aTBjNghZRbXX1rn4jFNyg@mail.gmail.com>
 <CA+zupgyG4Nov0=jihSApp_3_0hy6YNZMkfOp6Q4-zmERFm10Ag@mail.gmail.com>
Message-ID: <067e0b1f-ffb6-4f38-b4ac-8abdf46518ea@kernel.org>

On 18/12/2025 02:34, Roy Luo wrote:
> On Wed, Dec 17, 2025 at 12:14?PM Doug Anderson <dianders at google.com> wrote:
>>
>> Hi,
>>
>> On Wed, Dec 17, 2025 at 11:18?AM Roy Luo <royluo at google.com> wrote:
>>>
>>> On Wed, Dec 17, 2025 at 5:24?AM Greg Kroah-Hartman
>>> <gregkh at linuxfoundation.org> wrote:
>>>>
>>>> On Thu, Dec 04, 2025 at 11:14:39PM -0800, Roy Luo wrote:
>>>>> On Thu, Dec 4, 2025 at 10:05?PM Greg Kroah-Hartman
>>>>> <gregkh at linuxfoundation.org> wrote:
>>>>>>
>>>>>> On Fri, Dec 05, 2025 at 02:26:38AM +0000, Roy Luo wrote:
>>>>>>> +config USB_DWC3_GOOGLE
>>>>>>> +     tristate "Google Platform"
>>>>>>> +     depends on ARCH_GOOGLE || COMPILE_TEST
>>>>>>
>>>>>> There is no ARCH_GOOGLE in the tree now, so how is this supposed to
>>>>>> work?  Shouldn't tools that check for "invalid config options" trigger
>>>>>> on this?
>>>>>>
>>>>>> thanks,
>>>>>>
>>>>>> greg k-h
>>>>>
>>>>> Hi Greg,
>>>>>
>>>>> The menuconfig looks like the following and it doesn't complain:
>>>>> | Symbol: ARCH_GOOGLE [=ARCH_GOOGLE]
>>>>> | Type  : unknown
>>>>> |
>>>>> | Symbol: PHY_GOOGLE_USB [=y]
>>>>> | Type  : tristate
>>>>> | Defined at drivers/phy/Kconfig:104
>>>>> |     Prompt: Google Tensor SoC USB PHY driver
>>>>> |     Depends on: ARCH_GOOGLE || COMPILE_TEST [=y]
>>>>>
>>>>> According to Kconfig documentation [1], the unknown symbol
>>>>> would simply be evaluated as an "n", which is what we want.
>>>>> "Convert the symbol into an expression. Boolean and tristate
>>>>> symbols are simply converted into the respective expression
>>>>> values. All other symbol types result in ?n?."
>>>>>
>>>>> In a different Kconfig documentation, an environment variable
>>>>> "KCONFIG_WARN_UNKNOWN_SYMBOLS" is there to detect
>>>>> undefined symbols in the "config input", but I can't find one that
>>>>> catches undefined symbols in the Kconfig tree itself.
>>>>>
>>>>> That is, the tool seems to allow this.
>>>>> However, if this turns out to be a major problem. I think we
>>>>> can either:
>>>>> - Remove ARCH_GOOGLE and leave COMPILE_TEST as
>>>>>   the only dependency. Then add ARCH_GOOGLE back
>>>>>   later once it's in the tree.
>>>>
>>>> Please do this.  I do not want to take patches that purposfully add
>>>> dependencies on config options that might, or might not, appear in the
>>>> future.  Please just remove all of the dependancies for now, as they are
>>>> not needed, right?
>>>>
>>>> thanks,
>>>>
>>>> greg k-h
>>>
>>> Greg,
>>>
>>> Yes, we can remove ARCH_GOOGLE for now.
>>> To clarify, we're not removing all of the dependencies, we still want
>>> to keep COMPILE_TEST for build tests, right?
>>> Please let me know if you think otherwise.
>>
>> I think you'd just remove all of them. Normally COMPILE_TEST just
>> allows folks to compile stuff even when they don't want the ARCH. We
>> can can add ARCH_GOOGLE back in later once the config exists.
>>
>> -Doug
> 
> Doug,
> 
> Thanks for chiming in. I'm hesitant to remove COMPILE_TEST
> because Greg specifically requested its inclusion in v7 [1].


What? No, that's not what Greg requested. Your COMPILE_TEST in current
form helps nothing in build testing. It makes absolutely no sense at all.

> Also it seems beneficial to get some build coverage before
> ARCH_GOOGLE is officially added to the tree.

And COMPILE_TEST like you wrote it does not give you that. Please first
read how this function works.

> Greg, could you clarify?

Can you first look at Linux kernel sources to see how this is properly
written?

> 
> [1] https://lore.kernel.org/linux-usb/2025112144-claw-recolor-49c3 at gregkh/
> 
> Thanks,
> Roy


Best regards,
Krzysztof


From baolin.wang at linux.alibaba.com  Wed Dec 17 23:15:16 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Thu, 18 Dec 2025 15:15:16 +0800
Subject: [PATCH v2 1/3] arm64: mm: support batch clearing of the young
 flag for large folios
In-Reply-To: <1beaa7de-4b31-4f19-abee-83872f868e28@arm.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <e10f876ce130134fa089befe83f30561b48b9889.1765439380.git.baolin.wang@linux.alibaba.com>
 <1beaa7de-4b31-4f19-abee-83872f868e28@arm.com>
Message-ID: <96c0adcc-abfd-4a44-be93-1c6bd7942d6d@linux.alibaba.com>



On 2025/12/17 23:43, Ryan Roberts wrote:
> Sorry I'm a bit late to the party...

Never mind. It's not late and comments are always welcome :)

> On 11/12/2025 08:16, Baolin Wang wrote:
>> Currently, contpte_ptep_test_and_clear_young() and contpte_ptep_clear_flush_young()
>> only clear the young flag and flush TLBs for PTEs within the contiguous range.
>> To support batch PTE operations for other sized large folios in the following
>> patches, adding a new parameter to specify the number of PTEs.
>>
>> While we are at it, rename the functions to maintain consistency with other
>> contpte_*() functions.
>>
>> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
>> ---
>>   arch/arm64/include/asm/pgtable.h | 12 ++++-----
>>   arch/arm64/mm/contpte.c          | 44 ++++++++++++++++++++++----------
>>   2 files changed, 37 insertions(+), 19 deletions(-)
>>
>> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
>> index 0944e296dd4a..e03034683156 100644
>> --- a/arch/arm64/include/asm/pgtable.h
>> +++ b/arch/arm64/include/asm/pgtable.h
>> @@ -1679,10 +1679,10 @@ extern void contpte_clear_full_ptes(struct mm_struct *mm, unsigned long addr,
>>   extern pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
>>   				unsigned long addr, pte_t *ptep,
>>   				unsigned int nr, int full);
>> -extern int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
>> -				unsigned long addr, pte_t *ptep);
>> -extern int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
>> -				unsigned long addr, pte_t *ptep);
>> +extern int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
>> +				unsigned long addr, pte_t *ptep, unsigned int nr);
>> +extern int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
>> +				unsigned long addr, pte_t *ptep, unsigned int nr);
> 
> The "contpte_" functions are intended to be private to the arm64 arch and should
> be exposed via the generic APIs. But I don't see any generic batched API for
> this, so you're only actually able to pass CONT_PTES as nr. Perhaps you're
> planning to define "test_and_clear_young_ptes()" and "clear_flush_young_ptes()"
> in later patches?

Right. This is a preparation patch, and will be used in patch 2.

>>   extern void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
>>   				pte_t *ptep, unsigned int nr);
>>   extern int contpte_ptep_set_access_flags(struct vm_area_struct *vma,
>> @@ -1854,7 +1854,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
>>   	if (likely(!pte_valid_cont(orig_pte)))
>>   		return __ptep_test_and_clear_young(vma, addr, ptep);
>>   
>> -	return contpte_ptep_test_and_clear_young(vma, addr, ptep);
>> +	return contpte_test_and_clear_young_ptes(vma, addr, ptep, CONT_PTES);
>>   }
>>   
>>   #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
>> @@ -1866,7 +1866,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
>>   	if (likely(!pte_valid_cont(orig_pte)))
>>   		return __ptep_clear_flush_young(vma, addr, ptep);
>>   
>> -	return contpte_ptep_clear_flush_young(vma, addr, ptep);
>> +	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
>>   }
>>   
>>   #define wrprotect_ptes wrprotect_ptes
>> diff --git a/arch/arm64/mm/contpte.c b/arch/arm64/mm/contpte.c
>> index c0557945939c..19b122441be3 100644
>> --- a/arch/arm64/mm/contpte.c
>> +++ b/arch/arm64/mm/contpte.c
>> @@ -488,8 +488,9 @@ pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
>>   }
>>   EXPORT_SYMBOL_GPL(contpte_get_and_clear_full_ptes);
>>   
>> -int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
>> -					unsigned long addr, pte_t *ptep)
>> +int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
>> +					unsigned long addr, pte_t *ptep,
>> +					unsigned int nr)
>>   {
>>   	/*
>>   	 * ptep_clear_flush_young() technically requires us to clear the access
>> @@ -500,39 +501,56 @@ int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
>>   	 * having to unfold.
>>   	 */
>>   
>> +	unsigned long start = addr;
> 
> Personally I wouldn't bother defining start - just reuse addr. You're
> incrementing start in the below loop, so it's more appropriate to call it addr
> anyway.

OK.

>> +	unsigned long end = start + nr * PAGE_SIZE;
>>   	int young = 0;
>>   	int i;
>>   
>> -	ptep = contpte_align_down(ptep);
>> -	addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
>> +	if (pte_cont(__ptep_get(ptep + nr - 1)))
>> +		end = ALIGN(end, CONT_PTE_SIZE);
>>   
>> -	for (i = 0; i < CONT_PTES; i++, ptep++, addr += PAGE_SIZE)
>> -		young |= __ptep_test_and_clear_young(vma, addr, ptep);
>> +	if (pte_cont(__ptep_get(ptep))) {
>> +		start = ALIGN_DOWN(start, CONT_PTE_SIZE);
>> +		ptep = contpte_align_down(ptep);
>> +	}
>> +
>> +	nr = (end - start) / PAGE_SIZE;
>> +	for (i = 0; i < nr; i++, ptep++, start += PAGE_SIZE)
> 
> Given you're now defining end, perhaps we don't need nr?
> 
> 	for (; addr != end; ptep++, addr += PAGE_SIZE)
> 		young |= __ptep_test_and_clear_young(vma, addr, ptep);

Yes, good point.

>> +		young |= __ptep_test_and_clear_young(vma, start, ptep);
>>   
>>   	return young;
>>   }
>> -EXPORT_SYMBOL_GPL(contpte_ptep_test_and_clear_young);
>> +EXPORT_SYMBOL_GPL(contpte_test_and_clear_young_ptes);
>>   
>> -int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
>> -					unsigned long addr, pte_t *ptep)
>> +int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
>> +				unsigned long addr, pte_t *ptep,
>> +				unsigned int nr)
>>   {
>>   	int young;
>>   
>> -	young = contpte_ptep_test_and_clear_young(vma, addr, ptep);
>> +	young = contpte_test_and_clear_young_ptes(vma, addr, ptep, nr);
>>   
>>   	if (young) {
>> +		unsigned long start = addr;
>> +		unsigned long end = start + nr * PAGE_SIZE;
>> +
>> +		if (pte_cont(__ptep_get(ptep + nr - 1)))
>> +			end = ALIGN(end, CONT_PTE_SIZE);
>> +
>> +		if (pte_cont(__ptep_get(ptep)))
>> +			start = ALIGN_DOWN(start, CONT_PTE_SIZE);
>> +
> 
> We now have this pattern of expanding contpte blocks up and down in 3 places.
> Perhaps create a helper?

Sounds reasonable. How about the following helper?

static pte_t *contpte_align_addr_ptep(unsigned long *start, unsigned 
long *end,
                                         pte_t *ptep, unsigned int nr)
{
         unsigned long end_addr = *start + nr * PAGE_SIZE;

         if (pte_cont(__ptep_get(ptep + nr - 1)))
                 *end = ALIGN(end_addr, CONT_PTE_SIZE);

         if (pte_cont(__ptep_get(ptep))) {
                 *start = ALIGN_DOWN(*start, CONT_PTE_SIZE);
                 ptep = contpte_align_down(ptep);
         }

         return ptep;
}


From shengjiu.wang at nxp.com  Wed Dec 17 23:17:50 2025
From: shengjiu.wang at nxp.com (Shengjiu Wang)
Date: Thu, 18 Dec 2025 15:17:50 +0800
Subject: [PATCH v2] remoteproc: imx_dsp_rproc: only reset carveout memory at RPROC_OFFLINE state
Message-ID: <20251218071750.2692132-1-shengjiu.wang@nxp.com>

Do not reset memory at suspend and resume stage, because some
memory is used to save the software state for resume, if it is cleared,
the resume operation can fail.

Fixes: c4c432dfb00f ("remoteproc: imx_dsp_rproc: Add support of recovery and coredump process")
Signed-off-by: Shengjiu Wang <shengjiu.wang at nxp.com>
Reviewed-by: Daniel Baluta <daniel.baluta at nxp.com>
Reviewed-by: Iuliana Prodan <iuliana.prodan at nxp.com>
---
changes in v2:
- refine commit message.

 drivers/remoteproc/imx_dsp_rproc.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c
index d03017d6b214..ac8aa71aa56c 100644
--- a/drivers/remoteproc/imx_dsp_rproc.c
+++ b/drivers/remoteproc/imx_dsp_rproc.c
@@ -984,9 +984,11 @@ static int imx_dsp_rproc_load(struct rproc *rproc, const struct firmware *fw)
 	 * Clear buffers after pm rumtime for internal ocram is not
 	 * accessible if power and clock are not enabled.
 	 */
-	list_for_each_entry(carveout, &rproc->carveouts, node) {
-		if (carveout->va)
-			memset(carveout->va, 0, carveout->len);
+	if (rproc->state == RPROC_OFFLINE) {
+		list_for_each_entry(carveout, &rproc->carveouts, node) {
+			if (carveout->va)
+				memset(carveout->va, 0, carveout->len);
+		}
 	}
 
 	ret = imx_dsp_rproc_elf_load_segments(rproc, fw);
-- 
2.34.1



From jens.wiklander at linaro.org  Wed Dec 17 23:21:27 2025
From: jens.wiklander at linaro.org (Jens Wiklander)
Date: Thu, 18 Dec 2025 08:21:27 +0100
Subject: [PATCH v2 00/17] tee: Use bus callbacks instead of driver callbacks
In-Reply-To: <cover.1765791463.git.u.kleine-koenig@baylibre.com>
References: <cover.1765791463.git.u.kleine-koenig@baylibre.com>
Message-ID: <CAHUa44FrDZbvRvfN8obf80_k=Eqxe9YxHpjaE5jU7nkxPUwfag@mail.gmail.com>

Hi,

On Mon, Dec 15, 2025 at 3:17?PM Uwe Kleine-K?nig
<u.kleine-koenig at baylibre.com> wrote:
>
> Hello,
>
> the objective of this series is to make tee driver stop using callbacks
> in struct device_driver. These were superseded by bus methods in 2006
> (commit 594c8281f905 ("[PATCH] Add bus_type probe, remove, shutdown
> methods.")) but nobody cared to convert all subsystems accordingly.
>
> Here the tee drivers are converted. The first commit is somewhat
> unrelated, but simplifies the conversion (and the drivers). It
> introduces driver registration helpers that care about setting the bus
> and owner. (The latter is missing in all drivers, so by using these
> helpers the drivers become more correct.)
>
> v1 of this series is available at
> https://lore.kernel.org/all/cover.1765472125.git.u.kleine-koenig at baylibre.com
>
> Changes since v1:
>
>  - rebase to v6.19-rc1 (no conflicts)
>  - add tags received so far
>  - fix whitespace issues pointed out by Sumit Garg
>  - fix shutdown callback to shutdown and not remove
>
> As already noted in v1's cover letter, this series should go in during a
> single merge window as there are runtime warnings when the series is
> only applied partially. Sumit Garg suggested to apply the whole series
> via Jens Wiklander's tree.
> If this is done the dependencies in this series are honored, in case the
> plan changes: Patches #4 - #17 depend on the first two.
>
> Note this series is only build tested.
>
> Uwe Kleine-K?nig (17):
>   tee: Add some helpers to reduce boilerplate for tee client drivers
>   tee: Add probe, remove and shutdown bus callbacks to tee_client_driver
>   tee: Adapt documentation to cover recent additions
>   hwrng: optee - Make use of module_tee_client_driver()
>   hwrng: optee - Make use of tee bus methods
>   rtc: optee: Migrate to use tee specific driver registration function
>   rtc: optee: Make use of tee bus methods
>   efi: stmm: Make use of module_tee_client_driver()
>   efi: stmm: Make use of tee bus methods
>   firmware: arm_scmi: optee: Make use of module_tee_client_driver()
>   firmware: arm_scmi: Make use of tee bus methods
>   firmware: tee_bnxt: Make use of module_tee_client_driver()
>   firmware: tee_bnxt: Make use of tee bus methods
>   KEYS: trusted: Migrate to use tee specific driver registration
>     function
>   KEYS: trusted: Make use of tee bus methods
>   tpm/tpm_ftpm_tee: Make use of tee specific driver registration
>   tpm/tpm_ftpm_tee: Make use of tee bus methods
>
>  Documentation/driver-api/tee.rst             | 18 +----
>  drivers/char/hw_random/optee-rng.c           | 26 ++----
>  drivers/char/tpm/tpm_ftpm_tee.c              | 31 +++++---
>  drivers/firmware/arm_scmi/transports/optee.c | 32 +++-----
>  drivers/firmware/broadcom/tee_bnxt_fw.c      | 30 ++-----
>  drivers/firmware/efi/stmm/tee_stmm_efi.c     | 25 ++----
>  drivers/rtc/rtc-optee.c                      | 27 ++-----
>  drivers/tee/tee_core.c                       | 84 ++++++++++++++++++++
>  include/linux/tee_drv.h                      | 12 +++
>  security/keys/trusted-keys/trusted_tee.c     | 17 ++--
>  10 files changed, 164 insertions(+), 138 deletions(-)
>
> base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
> --
> 2.47.3
>

Thank you for the nice cleanup, Uwe.

I've applied patch 1-3 to the branch tee_bus_callback_for_6.20 in my
tree at https://git.kernel.org/pub/scm/linux/kernel/git/jenswi/linux-tee.git/

The branch is based on v6.19-rc1, and I'll try to keep it stable for
others to depend on, if needed. Let's see if we can agree on taking
the remaining patches via that branch.

Cheers,
Jens


From broonie at kernel.org  Wed Dec 17 23:36:46 2025
From: broonie at kernel.org (Mark Brown)
Date: Thu, 18 Dec 2025 07:36:46 +0000
Subject: [PATCH] spi: mt65xx: Use IRQF_ONESHOT with threaded IRQ
In-Reply-To: <20251217101131.1975131-1-fshao@chromium.org>
References: <20251217101131.1975131-1-fshao@chromium.org>
Message-ID: <176604340641.24947.388406077684218935.b4-ty@kernel.org>

On Wed, 17 Dec 2025 18:10:47 +0800, Fei Shao wrote:
> This driver is migrated to use threaded IRQ since commit 5972eb05ca32
> ("spi: spi-mt65xx: Use threaded interrupt for non-SPIMEM transfer"), and
> we almost always want to disable the interrupt line to avoid excess
> interrupts while the threaded handler is processing SPI transfer.
> Use IRQF_ONESHOT for that purpose.
> 
> In practice, we see MediaTek devices show SPI transfer timeout errors
> when communicating with ChromeOS EC in certain scenarios, and with
> IRQF_ONESHOT, the issue goes away.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next

Thanks!

[1/1] spi: mt65xx: Use IRQF_ONESHOT with threaded IRQ
      commit: 8c04b77f87e6e321ae6acd28ce1de5553916153f

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark



From baolin.wang at linux.alibaba.com  Wed Dec 17 23:47:07 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Thu, 18 Dec 2025 15:47:07 +0800
Subject: [PATCH v2 2/3] mm: rmap: support batched checks of the references
 for large folios
In-Reply-To: <cb4d7243-d8c6-4706-a254-6f5afc148910@arm.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <545dba5e899634bc6c8ca782417d16fef3bd049f.1765439381.git.baolin.wang@linux.alibaba.com>
 <cb4d7243-d8c6-4706-a254-6f5afc148910@arm.com>
Message-ID: <89cdd927-fc88-42cf-b8a1-2fbd736d5f7c@linux.alibaba.com>



On 2025/12/18 00:39, Ryan Roberts wrote:
> On 11/12/2025 08:16, Baolin Wang wrote:
>> Currently, folio_referenced_one() always checks the young flag for each PTE
>> sequentially, which is inefficient for large folios. This inefficiency is
>> especially noticeable when reclaiming clean file-backed large folios, where
>> folio_referenced() is observed as a significant performance hotspot.
>>
>> Moreover, on Arm architecture, which supports contiguous PTEs, there is already
>> an optimization to clear the young flags for PTEs within a contiguous range.
>> However, this is not sufficient. We can extend this to perform batched operations
>> for the entire large folio (which might exceed the contiguous range: CONT_PTE_SIZE).
>>
>> Introduce a new API: clear_flush_young_ptes() to facilitate batched checking
>> of the young flags and flushing TLB entries, thereby improving performance
>> during large folio reclamation.
>>
>> Performance testing:
>> Allocate 10G clean file-backed folios by mmap() in a memory cgroup, and try to
>> reclaim 8G file-backed folios via the memory.reclaim interface. I can observe
>> 33% performance improvement on my Arm64 32-core server (and 10%+ improvement
>> on my X86 machine). Meanwhile, the hotspot folio_check_references() dropped
>> from approximately 35% to around 5%.
>>
>> W/o patchset:
>> real	0m1.518s
>> user	0m0.000s
>> sys	0m1.518s
>>
>> W/ patchset:
>> real	0m1.018s
>> user	0m0.000s
>> sys	0m1.018s
>>
>> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
>> ---
>>   arch/arm64/include/asm/pgtable.h | 11 +++++++++++
>>   include/linux/mmu_notifier.h     |  9 +++++----
>>   include/linux/pgtable.h          | 19 +++++++++++++++++++
>>   mm/rmap.c                        | 22 ++++++++++++++++++++--
>>   4 files changed, 55 insertions(+), 6 deletions(-)
>>
>> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
>> index e03034683156..a865bd8c46a3 100644
>> --- a/arch/arm64/include/asm/pgtable.h
>> +++ b/arch/arm64/include/asm/pgtable.h
>> @@ -1869,6 +1869,17 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
>>   	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
>>   }
>>   
>> +#define clear_flush_young_ptes clear_flush_young_ptes
>> +static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
>> +					unsigned long addr, pte_t *ptep,
>> +					unsigned int nr)
>> +{
>> +	if (likely(nr == 1))
>> +		return __ptep_clear_flush_young(vma, addr, ptep);
> 
> Bug: This is broken if core-mm tries to call this for nr=1 on a pte that is part
> of a contpte mapping.
> 
> The similar fastpaths are here to prevent regressing the common small folio case.

Thanks for catching this. I had considered this before, but I still 
missed it.

> I guess here the best approach is (note no leading underscores):
> 
> 	if (likely(nr == 1))
> 		return ptep_clear_flush_young(vma, addr, ptep);

However, I prefer to use pte_cont() to check it. Later, I plan to clean 
up the ptep_clear_flush_young().

	if (nr == 1 && !pte_cont(__ptep_get(ptep))
		return __ptep_clear_flush_young(vma, addr, ptep);

>> +
>> +	return contpte_clear_flush_young_ptes(vma, addr, ptep, nr);
>> +}
>> +
>>   #define wrprotect_ptes wrprotect_ptes
>>   static __always_inline void wrprotect_ptes(struct mm_struct *mm,
>>   				unsigned long addr, pte_t *ptep, unsigned int nr)
>> diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h
>> index d1094c2d5fb6..be594b274729 100644
>> --- a/include/linux/mmu_notifier.h
>> +++ b/include/linux/mmu_notifier.h
>> @@ -515,16 +515,17 @@ static inline void mmu_notifier_range_init_owner(
>>   	range->owner = owner;
>>   }
>>   
>> -#define ptep_clear_flush_young_notify(__vma, __address, __ptep)		\
>> +#define ptep_clear_flush_young_notify(__vma, __address, __ptep, __nr)	\
> 
> Shouldn't we rename this macro to clear_flush_young_ptes_notify()?
> 
> And potentially:
> 
> #define ptep_clear_flush_young_notify(__vma, __address, __ptep) \
> 	clear_flush_young_ptes_notify(__vma, __address, __ptep, 1)
> 
> if there are other non-batched users remaining.

There are no other non-batched users now, so seems there is no need to 
add another redundant API.

>>   ({									\
>>   	int __young;							\
>>   	struct vm_area_struct *___vma = __vma;				\
>>   	unsigned long ___address = __address;				\
>> -	__young = ptep_clear_flush_young(___vma, ___address, __ptep);	\
>> +	unsigned int ___nr = __nr;					\
>> +	__young = clear_flush_young_ptes(___vma, ___address, __ptep, ___nr);	\
>>   	__young |= mmu_notifier_clear_flush_young(___vma->vm_mm,	\
>>   						  ___address,		\
>>   						  ___address +		\
>> -							PAGE_SIZE);	\
>> +						nr * PAGE_SIZE);	\
>>   	__young;							\
>>   })
>>   > @@ -650,7 +651,7 @@ static inline void
> mmu_notifier_subscriptions_destroy(struct mm_struct *mm)
>>   
>>   #define mmu_notifier_range_update_to_read_only(r) false
>>   
>> -#define ptep_clear_flush_young_notify ptep_clear_flush_young
>> +#define ptep_clear_flush_young_notify clear_flush_young_ptes
>>   #define pmdp_clear_flush_young_notify pmdp_clear_flush_young
>>   #define ptep_clear_young_notify ptep_test_and_clear_young
>>   #define pmdp_clear_young_notify pmdp_test_and_clear_young
>> diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
>> index b13b6f42be3c..c7d0fd228cb7 100644
>> --- a/include/linux/pgtable.h
>> +++ b/include/linux/pgtable.h
>> @@ -947,6 +947,25 @@ static inline void wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
>>   }
>>   #endif
>>   
>> +#ifndef clear_flush_young_ptes
> 
> Let's have some function documentation here please.

Sure. Will do.

>> +static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
>> +					 unsigned long addr, pte_t *ptep,
>> +					 unsigned int nr)
>> +{
>> +	int young = 0;
>> +
>> +	for (;;) {
> 
> I know Lorenzo is pretty allergic to this style of looping :)
> 
> He's right of course, we should probably just do this the ideomatic way and not
> worry about it looking a bit different to the others.

Let me use the 'while (--nr) { }' instead.

> 
>> +		young |= ptep_clear_flush_young(vma, addr, ptep);
>> +		if (--nr == 0)
>> +			break;
>> +		ptep++;
>> +		addr += PAGE_SIZE;
>> +	}
>> +
>> +	return young;
>> +}
>> +#endif
>> +
>>   /*
>>    * On some architectures hardware does not set page access bit when accessing
>>    * memory page, it is responsibility of software setting this bit. It brings
>> diff --git a/mm/rmap.c b/mm/rmap.c
>> index d6799afe1114..ec232165c47d 100644
>> --- a/mm/rmap.c
>> +++ b/mm/rmap.c
>> @@ -827,9 +827,11 @@ static bool folio_referenced_one(struct folio *folio,
>>   	struct folio_referenced_arg *pra = arg;
>>   	DEFINE_FOLIO_VMA_WALK(pvmw, folio, vma, address, 0);
>>   	int ptes = 0, referenced = 0;
>> +	unsigned int nr;
>>   
>>   	while (page_vma_mapped_walk(&pvmw)) {
>>   		address = pvmw.address;
>> +		nr = 1;
>>   
>>   		if (vma->vm_flags & VM_LOCKED) {
>>   			ptes++;
>> @@ -874,9 +876,21 @@ static bool folio_referenced_one(struct folio *folio,
>>   			if (lru_gen_look_around(&pvmw))
>>   				referenced++;
>>   		} else if (pvmw.pte) {
>> +			if (folio_test_large(folio)) {
>> +				unsigned long end_addr = pmd_addr_end(address, vma->vm_end);
>> +				unsigned int max_nr = (end_addr - address) >> PAGE_SHIFT;
>> +				pte_t pteval = ptep_get(pvmw.pte);
>> +
>> +				nr = folio_pte_batch(folio, pvmw.pte, pteval, max_nr);
>> +			}
>> +
>> +			ptes += nr;
>>   			if (ptep_clear_flush_young_notify(vma, address,
>> -						pvmw.pte))
>> +						pvmw.pte, nr))
>>   				referenced++;
>> +			/* Skip the batched PTEs */
>> +			pvmw.pte += nr - 1;
>> +			pvmw.address += (nr - 1) * PAGE_SIZE;
> 
> The -1 part is because the walker will increment by 1 I'm guessing?

Right.

> 
>>   		} else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) {
>>   			if (pmdp_clear_flush_young_notify(vma, address,
>>   						pvmw.pmd))
>> @@ -886,7 +900,11 @@ static bool folio_referenced_one(struct folio *folio,
>>   			WARN_ON_ONCE(1);
>>   		}
>>   
>> -		pra->mapcount--;
>> +		pra->mapcount -= nr;
>> +		if (ptes == pvmw.nr_pages) {
>> +			page_vma_mapped_walk_done(&pvmw);
>> +			break;
> 
> What's this needed for? I'm suspicious because there wasn't an equivalent here
> before.

If we are sure that we batched the entire folio, we can just optimize 
and stop right here.

Thanks for reviewing.


From vbabka at suse.cz  Wed Dec 17 23:47:44 2025
From: vbabka at suse.cz (Vlastimil Babka)
Date: Thu, 18 Dec 2025 08:47:44 +0100
Subject: [PATCH 0/2] introduce pagetable_alloc_nolock()
In-Reply-To: <DF0NWLWKRKYI.3PLY78UGGG2PD@google.com>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com>
 <916c17ba-22b1-456e-a184-cb3f60249af7@arm.com>
 <aUGOPd7gNRf1xHEc@e129823.arm.com>
 <100cc8da-b826-4fc2-a624-746bf6fb049d@arm.com>
 <aUKKZR0u22KOPfd7@e129823.arm.com>
 <d96ac977-222e-4e8d-9487-da1306198419@arm.com>
 <aUKnfU/3FREY13g1@e129823.arm.com>
 <d912480a-5229-4efe-9336-b31acded30f5@suse.cz>
 <DF0J58HOVLL4.2E16Q87D2UXRW@google.com>
 <d5354d96-6f28-41d7-9f66-64c254d9477b@suse.cz>
 <DF0NWLWKRKYI.3PLY78UGGG2PD@google.com>
Message-ID: <7b2673cb-1f0e-4a5a-84e3-0ae10437308d@suse.cz>

On 12/17/25 18:19, Brendan Jackman wrote:
>>> From 4c6b4d4cb08aee9559d02a348b9ecf799142c96f Mon Sep 17 00:00:00 2001
>>> From: Brendan Jackman <jackmanb at google.com>
>>> Date: Wed, 17 Dec 2025 13:26:28 +0000
>>> Subject: [PATCH] mm: clarify GFP_ATOMIC/GFP_NOWAIT doc-comment
>>> 
>>> The current description of contexts where it's invalid to make
>>> GFP_ATOMIC and GFP_NOWAIT calls is rather vague.
>>> 
>>> Replace this with a direct description of the actual contexts of concern
>>> and refer to the RT docs where this is explained more discursively.
>>> 
>>> While rejigging this prose, also move the documentation of GFP_NOWAIT to
>>> the GFP_NOWAIT section.
>>
>> There doesn't seem to be any move?
> 
> This is referring to [0] and [1].

Oh I missed [0]. Thanks!

>>> diff --git a/include/linux/gfp_types.h b/include/linux/gfp_types.h
>>> index 3de43b12209ee..07a378542caf2 100644
>>> --- a/include/linux/gfp_types.h
>>> +++ b/include/linux/gfp_types.h
>>> @@ -309,8 +309,10 @@ enum {
>>>   *
>>>   * %GFP_ATOMIC users can not sleep and need the allocation to succeed. A lower
>>>   * watermark is applied to allow access to "atomic reserves".
>>> - * The current implementation doesn't support NMI and few other strict
>>> - * non-preemptive contexts (e.g. raw_spin_lock). The same applies to %GFP_NOWAIT.
> [0]                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
>>> + * The current implementation doesn't support NMI, nor contexts that disable
>>> + * preemption under PREEMPT_RT. This includes raw_spin_lock() and plain
>>> + * preempt_disable() - see Documentation/core-api/real-time/differences.rst for
>>> + * more info.
>>
>> Can we reference the "Memory allocation" section directly?
> 
> Yeah good point. I will send this as a standalone [PATCH] mail tomorrow.
> 
>>>   *
>>>   * %GFP_KERNEL is typical for kernel-internal allocations. The caller requires
>>>   * %ZONE_NORMAL or a lower zone for direct access but can direct reclaim.
>>> @@ -321,6 +323,7 @@ enum {
>>>   * %GFP_NOWAIT is for kernel allocations that should not stall for direct
>>>   * reclaim, start physical IO or use any filesystem callback.  It is very
>>>   * likely to fail to allocate memory, even for very small allocations.
>>> + * The same restrictions on calling contexts apply as for %GFP_ATOMIC.
> [1]     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 



From vbabka at suse.cz  Wed Dec 17 23:51:52 2025
From: vbabka at suse.cz (Vlastimil Babka)
Date: Thu, 18 Dec 2025 08:51:52 +0100
Subject: [PATCH v2 2/2] arm64: mmu: avoid allocating pages while
 installing ng-mapping for KPTI
In-Reply-To: <731e3f48-e0a3-4c89-a13a-65ef37faa443@arm.com>
References: <20251217182007.2345700-1-yeoreum.yun@arm.com>
 <20251217182007.2345700-3-yeoreum.yun@arm.com>
 <731e3f48-e0a3-4c89-a13a-65ef37faa443@arm.com>
Message-ID: <586d24f9-a54d-4c14-bd25-fed18423d709@suse.cz>

On 12/17/25 20:03, Ryan Roberts wrote:
> On 17/12/2025 18:20, Yeoreum Yun wrote:
>> The current __kpti_install_ng_mappings() allocates a temporary PGD
>> while installing the NG mapping for KPTI under stop_machine(),
>> using GFP_ATOMIC.
>> 
>> This is fine in the non-PREEMPT_RT case. However, it becomes a problem
>> under PREEMPT_RT because generic memory allocation/free APIs
>> (e.g., pgtable_alloc(), __get_free_pages(), etc.) cannot be invoked
>> in a non-preemptible context, except for the *_nolock() variants.
>> These generic allocators may sleep due to their use of spin_lock().
>> 
>> In other words, calling __get_free_pages(), even with GFP_ATOMIC,
>> is not allowed in __kpti_install_ng_mappings(), which is executed by
>> the stopper thread where preemption is disabled under PREEMPT_RT.
>> 
>> To address this, preallocate the page needed for the temporary PGD
>> before invoking __kpti_install_ng_mappings() via stop_machine().
>> 
>> Fixes: 47546a1912fc ("arm64: mm: install KPTI nG mappings with MMU enabled")
>> Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
>> ---
>>  arch/arm64/mm/mmu.c | 22 +++++++++++++---------
>>  1 file changed, 13 insertions(+), 9 deletions(-)
>> 
>> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
>> index e4e6c7e0a016..69d9651de0cd 100644
>> --- a/arch/arm64/mm/mmu.c
>> +++ b/arch/arm64/mm/mmu.c
>> @@ -1360,7 +1360,7 @@ static phys_addr_t __init kpti_ng_pgd_alloc(enum pgtable_type type)
>>  	return kpti_ng_temp_alloc;
>>  }
>>  
>> -static int __init __kpti_install_ng_mappings(void *__unused)
>> +static int __init __kpti_install_ng_mappings(void *data)
>>  {
>>  	typedef void (kpti_remap_fn)(int, int, phys_addr_t, unsigned long);
>>  	extern kpti_remap_fn idmap_kpti_install_ng_mappings;
>> @@ -1368,10 +1368,9 @@ static int __init __kpti_install_ng_mappings(void *__unused)
>>  
>>  	int cpu = smp_processor_id();
>>  	int levels = CONFIG_PGTABLE_LEVELS;
>> -	int order = order_base_2(levels);
>>  	u64 kpti_ng_temp_pgd_pa = 0;
>>  	pgd_t *kpti_ng_temp_pgd;
>> -	u64 alloc = 0;
>> +	u64 alloc = *(u64 *)data;
>>  
>>  	if (levels == 5 && !pgtable_l5_enabled())
>>  		levels = 4;
>> @@ -1382,8 +1381,6 @@ static int __init __kpti_install_ng_mappings(void *__unused)
>>  
>>  	if (!cpu) {
>>  		int ret;
>> -
>> -		alloc = __get_free_pages(GFP_ATOMIC | __GFP_ZERO, order);
>>  		kpti_ng_temp_pgd = (pgd_t *)(alloc + (levels - 1) * PAGE_SIZE);
>>  		kpti_ng_temp_alloc = kpti_ng_temp_pgd_pa = __pa(kpti_ng_temp_pgd);
>>  
>> @@ -1414,16 +1411,17 @@ static int __init __kpti_install_ng_mappings(void *__unused)
>>  	remap_fn(cpu, num_online_cpus(), kpti_ng_temp_pgd_pa, KPTI_NG_TEMP_VA);
>>  	cpu_uninstall_idmap();
>>  
>> -	if (!cpu) {
>> -		free_pages(alloc, order);
>> +	if (!cpu)
>>  		arm64_use_ng_mappings = true;
>> -	}
>>  
>>  	return 0;
>>  }
>>  
>>  void __init kpti_install_ng_mappings(void)
>>  {
>> +	int order = order_base_2(CONFIG_PGTABLE_LEVELS);
>> +	u64 alloc;
>> +
>>  	/* Check whether KPTI is going to be used */
>>  	if (!arm64_kernel_unmapped_at_el0())
>>  		return;
>> @@ -1436,8 +1434,14 @@ void __init kpti_install_ng_mappings(void)
>>  	if (arm64_use_ng_mappings)
>>  		return;
>>  
>> +	alloc = __get_free_pages(GFP_ATOMIC | __GFP_ZERO, order);
> 
> I don't think this requires GFP_ATOMIC now?

Do you mean it's fine to use GFP_KERNEL now, or still not, and you mean that
GFP_NOWAIT is sufficient?

> With that removed:
> 
> Reviewed-by: Ryan Roberts <ryan.roberts at arm.com>
> 
>> +	if (!alloc)
>> +		panic("Failed to alloc page tables\n");
>> +
>>  	init_idmap_kpti_bbml2_flag();
>> -	stop_machine(__kpti_install_ng_mappings, NULL, cpu_online_mask);
>> +	stop_machine(__kpti_install_ng_mappings, &alloc, cpu_online_mask);
>> +
>> +	free_pages(alloc, order);
>>  }
>>  
>>  static pgprot_t __init kernel_exec_prot(void)
> 



From david at kernel.org  Wed Dec 17 23:52:10 2025
From: david at kernel.org (David Hildenbrand (Red Hat))
Date: Thu, 18 Dec 2025 08:52:10 +0100
Subject: [PATCH 0/2] introduce pagetable_alloc_nolock()
In-Reply-To: <d5354d96-6f28-41d7-9f66-64c254d9477b@suse.cz>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com>
 <916c17ba-22b1-456e-a184-cb3f60249af7@arm.com>
 <aUGOPd7gNRf1xHEc@e129823.arm.com>
 <100cc8da-b826-4fc2-a624-746bf6fb049d@arm.com>
 <aUKKZR0u22KOPfd7@e129823.arm.com>
 <d96ac977-222e-4e8d-9487-da1306198419@arm.com>
 <aUKnfU/3FREY13g1@e129823.arm.com>
 <d912480a-5229-4efe-9336-b31acded30f5@suse.cz>
 <DF0J58HOVLL4.2E16Q87D2UXRW@google.com>
 <d5354d96-6f28-41d7-9f66-64c254d9477b@suse.cz>
Message-ID: <1e4c889c-f594-4d1c-92cb-e94af04acc91@kernel.org>


>>
>> Link: https://lore.kernel.org/all/d912480a-5229-4efe-9336-b31acded30f5 at suse.cz/
>> Signed-off-by: Brendan Jackman <jackmanb at google.com>
> 
> Acked-by: Vlastimil Babka <vbabka at suse.cz>

Clarifies things for me

Acked-by: David Hildenbrand (Red Hat) <david at kernel.org>

-- 
Cheers

David


From baolin.wang at linux.alibaba.com  Wed Dec 17 23:56:45 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Thu, 18 Dec 2025 15:56:45 +0800
Subject: [PATCH v2 1/3] arm64: mm: support batch clearing of the young
 flag for large folios
In-Reply-To: <fac9dd13-0c1b-40de-a5ac-d2c4c2012385@arm.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <e10f876ce130134fa089befe83f30561b48b9889.1765439380.git.baolin.wang@linux.alibaba.com>
 <5039c6a2-09b6-4c9b-accb-26583ba120db@lucifer.local>
 <1a0001cd-c38d-403b-b3ef-d19e85acd772@linux.alibaba.com>
 <671ac450-4a59-4e26-b098-7cf65add1e75@lucifer.local>
 <37915af9-d307-4955-969e-c16ea26f7f4a@linux.alibaba.com>
 <16d6642b-6f22-4d7b-94d6-92692b63cbd9@lucifer.local>
 <fac9dd13-0c1b-40de-a5ac-d2c4c2012385@arm.com>
Message-ID: <a8b5e3b7-e702-4f57-9fab-289cb34345dc@linux.alibaba.com>



On 2025/12/18 00:06, Ryan Roberts wrote:
> On 17/12/2025 14:50, Lorenzo Stoakes wrote:
>> On Wed, Dec 17, 2025 at 11:53:31AM +0800, Baolin Wang wrote:
>>>
>>>
>>> On 2025/12/16 19:11, Lorenzo Stoakes wrote:
>>>> On Tue, Dec 16, 2025 at 11:32:58AM +0800, Baolin Wang wrote:
>>>>>
>>>>>
>>>>> On 2025/12/15 19:36, Lorenzo Stoakes wrote:
>>>>>> On Thu, Dec 11, 2025 at 04:16:54PM +0800, Baolin Wang wrote:
>>>>>>> Currently, contpte_ptep_test_and_clear_young() and contpte_ptep_clear_flush_young()
>>>>>>> only clear the young flag and flush TLBs for PTEs within the contiguous range.
>>>>>>> To support batch PTE operations for other sized large folios in the following
>>>>>>> patches, adding a new parameter to specify the number of PTEs.
>>>>>>>
>>>>>>> While we are at it, rename the functions to maintain consistency with other
>>>>>>> contpte_*() functions.
>>>>>>>
>>>>>>> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
>>>>>>> ---
>>>>>>>     arch/arm64/include/asm/pgtable.h | 12 ++++-----
>>>>>>>     arch/arm64/mm/contpte.c          | 44 ++++++++++++++++++++++----------
>>>>>>>     2 files changed, 37 insertions(+), 19 deletions(-)
>>>>>>>
>>>>>>> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
>>>>>>> index 0944e296dd4a..e03034683156 100644
>>>>>>> --- a/arch/arm64/include/asm/pgtable.h
>>>>>>> +++ b/arch/arm64/include/asm/pgtable.h
>>>>>>> @@ -1679,10 +1679,10 @@ extern void contpte_clear_full_ptes(struct mm_struct *mm, unsigned long addr,
>>>>>>>     extern pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
>>>>>>>     				unsigned long addr, pte_t *ptep,
>>>>>>>     				unsigned int nr, int full);
>>>>>>> -extern int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
>>>>>>> -				unsigned long addr, pte_t *ptep);
>>>>>>> -extern int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
>>>>>>> -				unsigned long addr, pte_t *ptep);
>>>>>>> +extern int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
>>>>>>> +				unsigned long addr, pte_t *ptep, unsigned int nr);
>>>>>>> +extern int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
>>>>>>> +				unsigned long addr, pte_t *ptep, unsigned int nr);
>>>>>>
>>>>>> In core mm at least, as a convention, we strip 'extern' from header declarations
>>>>>> as we go as they're not necessary.
>>>>>
>>>>> Sure. I can remove the 'extern'.
>>>>
>>>> Thanks.
>>>>
>>>>>
>>>>>> I wonder about this naming convention also. The contpte_xxx_() prefix
>>>>>> obviously implies we are operating upon PTEs in the contiguous range, now
>>>>>> we are doing something... different and 'nr' is a bit vague.
>>>>>>
>>>>>> Is it the nr of contiguous ranges? Well in reality it's nr_pages right? But
>>>>>
>>>>> Yes, 'nr' here means nr_pages, which follows the convention of the
>>>>> parameters in contpte_xxx_() functions.
>>>>
>>>> Except you're violating the convention already by doing non-contpte stuff in
>>>> contpte functions?
>>>
>>> Nope. Sorry for my poor English, which might have caused some confusion. I
>>> followed the contpte's convention, and let me try to explain it again below.
>>>
>>>> The confusion is between nr of contpte ranges and nr of pages, so I think we
>>>> should be explicit.
>>>>
>>>>>
>>>>>> now we're not saying they're necessarily contiguous in the sense of contpte...
>>>>>>
>>>>>> I wonder whether we'd be better off introducing a new function that
>>>>>> explicitly has 'batch' or 'batched' in the name, and have the usual
>>>>>> contpte_***() stuff and callers that need batching using a new underlying helper?
>>>>>
>>>>> OK. I get your point. However, this is outside the scope of my patchset.
>>>>
>>>> Well, no, this is review feedback that needs to be addressed, I really don't
>>>> like this patch as-is.
>>>>
>>>> So for this to be upstreamable you really need to separate this out.
>>>>
>>>>>
>>>>> Perhaps we can clean up all the contpte_xxx_() functions if everyone agrees
>>>>> that this is confusing.
>>>>
>>>> I mean, unless Ryan explicitly makes a case for this being fine, I'm inclined to
>>>> reject the patch unless we do this.
>>>>
>>>> The contpte logic is already very confusing, and this is only adding to it.
>>>>
>>>>>
>>>>>> Obviously I defer to Ryan on all this, just my thoughts...
>>>>>>
>>>>>>>     extern void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
>>>>>>>     				pte_t *ptep, unsigned int nr);
>>>>>>>     extern int contpte_ptep_set_access_flags(struct vm_area_struct *vma,
>>>>>>> @@ -1854,7 +1854,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
>>>>>>>     	if (likely(!pte_valid_cont(orig_pte)))
>>>>>>>     		return __ptep_test_and_clear_young(vma, addr, ptep);
>>>>>>>
>>>>>>> -	return contpte_ptep_test_and_clear_young(vma, addr, ptep);
>>>>>>> +	return contpte_test_and_clear_young_ptes(vma, addr, ptep, CONT_PTES);
>>>>>>>     }
>>>>>>>
>>>>>>>     #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
>>>>>>> @@ -1866,7 +1866,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
>>>>>>>     	if (likely(!pte_valid_cont(orig_pte)))
>>>>>>>     		return __ptep_clear_flush_young(vma, addr, ptep);
>>>>>>>
>>>>>>> -	return contpte_ptep_clear_flush_young(vma, addr, ptep);
>>>>>>> +	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
>>>>>>>     }
>>>>>>>
>>>>>>>     #define wrprotect_ptes wrprotect_ptes
>>>>>>> diff --git a/arch/arm64/mm/contpte.c b/arch/arm64/mm/contpte.c
>>>>>>> index c0557945939c..19b122441be3 100644
>>>>>>> --- a/arch/arm64/mm/contpte.c
>>>>>>> +++ b/arch/arm64/mm/contpte.c
>>>>>>> @@ -488,8 +488,9 @@ pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
>>>>>>>     }
>>>>>>>     EXPORT_SYMBOL_GPL(contpte_get_and_clear_full_ptes);
>>>>>>>
>>>>>>> -int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
>>>>>>> -					unsigned long addr, pte_t *ptep)
>>>>>>> +int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
>>>>>>> +					unsigned long addr, pte_t *ptep,
>>>>>>> +					unsigned int nr)
>>>>>>>     {
>>>>>>>     	/*
>>>>>>>     	 * ptep_clear_flush_young() technically requires us to clear the access
>>>>>>> @@ -500,39 +501,56 @@ int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
>>>>>>>     	 * having to unfold.
>>>>>>>     	 */
>>>>>>
>>>>>> Hmm shouldn't you need to update this comment now 'nr' is a thing? E.g.:
>>>>>>
>>>>>> "And since we only create a contig range when the range is covered by a single
>>>>>> folio, we can get away with clearing young for the whole contig range here, so
>>>>>> we avoid having to unfold."
>>>>>
>>>>> I think the original comments are still clear:
>>>>> "
>>>>> /*
>>>>>    * ptep_clear_flush_young() technically requires us to clear the access
>>>>>    * flag for a _single_ pte. However, the core-mm code actually tracks
>>>>>    * access/dirty per folio, not per page. And since we only create a
>>>>>    * contig range when the range is covered by a single folio, we can get
>>>>>    * away with clearing young for the whole contig range here, so we avoid
>>>>>    * having to unfold.
>>>>>    */
>>>>> "
>>>>
>>>> Except nr means you can span more than a single contig pte range? So this
>>>> comment is no longer applicable as-is?
>>>
>>> The nr means consecutive (present) PTEs that map consecutive pages of the
>>> same large folio in a single VMA and a single page table.
>>>
>>> I think this is a prerequisite. If you think it's necessary to explain it, I
>>> can add it to the comments.
>>>
>>>> You've changed the function, the comment needs to change too.
>>>>
>>>>>
>>>>>> However now you're allowing for large folios that are not contpte?
>>>>>>
>>>>>> Overall feeling pretty iffy about implementing this this way.
>>>>>
>>>>> Please see the above comments, which explain why we should do that.
>>>>
>>>> You haven't explained anything? Maybe I missed it?
>>>>
>>>> Can you explain clearly what nr might actually be in relation to contpte's? I'm
>>>> confused even as to the utility here.
>>>>
>>>> Is it batched ranges of contptes? But then why are you trying to see if end is a
>>>> contpte + expand the range if so?
>>>
>>> See below.
>>>
>>>>>>> +	unsigned long start = addr;
>>>>>>> +	unsigned long end = start + nr * PAGE_SIZE;
>>>>>>
>>>>>> So now [addr, addr + nr * PAGE_SIZE) must for sure be within a single PTE
>>>>>> table?
>>>>>
>>>>> Caller has made sure that (see folio_referenced_one()).
>>>>
>>>> You should comment this somehow, I hate this nested assumptions stuff 'function
>>>> X which calls function Y which calls function Z makes sure that parameter A
>>>> fulfils requirements B but we don't mention it anywhere'.
>>>
>>> Sure.
>>>
>>>>>>>     	int young = 0;
>>>>>>>     	int i;
>>>>>>>
>>>>>>> -	ptep = contpte_align_down(ptep);
>>>>>>> -	addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
>>>>>>> +	if (pte_cont(__ptep_get(ptep + nr - 1)))
>>>>>>> +		end = ALIGN(end, CONT_PTE_SIZE);
>>>>>>
>>>>>> OK so I guess for PTE_CONT to be set, it must be aligned to CONT_PTE_SIZE,
>>>>>> with other PTE entries present there not having PTE_CONT set (Ryan - do
>>>>>> correct me if I'm wrong!)
>>>>>>
>>>>>> I guess then no worry about running off the end of the PTE table here.
>>>>>>
>>>>>> I wonder about using pte_cont_addr_end() here, but I guess you are not
>>>>>> intending to limit to a range here but rather capture the entire contpte
>>>>>> range of the end.
>>>>>
>>>>> Right.
>>>>>
>>>>>> I don't love that now a function prefixed with contpte_... can have a
>>>>>> condition where part of the input range is _not_ a contpte entry, or is
>>>>>> specified partially...
>>>>>
>>>>> Like I said above, this is outside the scope of my patchset. If Ryan also
>>>>> thinks we need to do some cleanups for all the contpte_xxx() functions in
>>>>> the contpte.c file, we can send a follow-up patchset to rename all the
>>>>> contpte_xxx() functions to make it clear.
>>>>
>>>> It's really not outside of the scope of the patch set, this is review feedback
>>>> you have to address :) trying not to be a grumpy kernel dev here :>)
>>>>
>>>> In general in the kernel we don't accept confusing patches then defer making
>>>> them not-confusing until later.
>>>>
>>>> We review until the series is at the correct standard to be accepted before we
>>>> merge.
>>>>
>>>> As always I'm happy to be convinced that I'm mistaken or something's not
>>>> necesary, however!
>>>
>>> Yes, let me try to explain it again. See below.
>>>
>>>>>>> -	for (i = 0; i < CONT_PTES; i++, ptep++, addr += PAGE_SIZE)
>>>>>>> -		young |= __ptep_test_and_clear_young(vma, addr, ptep);
>>>>>>> +	if (pte_cont(__ptep_get(ptep))) {
>>>>>>> +		start = ALIGN_DOWN(start, CONT_PTE_SIZE);
>>>>>>> +		ptep = contpte_align_down(ptep);
>>>>>>> +	}
>>>>>>> +
>>>>>>> +	nr = (end - start) / PAGE_SIZE;
>>>>>>
>>>>>> Hm don't love this reuse of input param.
>>>>>
>>>>> OK. Will use another local variable instead.
>>>>
>>>> Thanks.
>>>>
>>>>>
>>>>>>
>>>>>>> +	for (i = 0; i < nr; i++, ptep++, start += PAGE_SIZE)
>>>>>>> +		young |= __ptep_test_and_clear_young(vma, start, ptep);
>>>>>>
>>>>>> Again, overall find it a bit iffy that we are essentially overloading the
>>>>>> code with non-contpte behaviour.
>>>>>
>>>>> Let me clarify further: this is the handling logic of the contpte_xxx()
>>>>> functions in the contpte.c file. For example, the function
>>>>> contpte_set_ptes() has a parameter 'nr', which may be greater than
>>>>> CONT_PTES, meaning that it can handle multiple CONT_PTES range sizes of a
>>>>> large folio.
>>>>>
>>>>> It might be a bit confusing, and I understand this is why you want to change
>>>>> the 'contpte_' prefix to the 'batch_' prefix. Of course, we can hope Ryan
>>>>> can provide some input on this.
>>>>>
>>>>> Thanks for reviewing.
>>>>
>>>> OK so we have some reeeeal confusion here. And this speaks to the patch needing
>>>> work.
>>>>
>>>> This seems to answer what I asked above - basically - are we doing _batches_ of
>>>> _contpte_ entries, or are we just accepting arbitrary large folios here and
>>>> batching up operations on them, including non-contpte entries.
>>>>
>>>> Presumably from the above you're saying - this is dealing with batches of
>>>> contpte entries.
>>>>
>>>> In which case this has to be made _super_ clear. Not just adding an arbitrary
>>>> 'nr' parameter and letting people guess.
>>>>
>>>> The contpte code is _already_ confusing and somewhat surprising if you're not
>>>> aware of it, we need to be going in the other direction.
>>>
>>> Sure. Sorry for causing confusion. I try to explain it again to make it
>>> clear.
>>>
>>> First, it is necessary to explain how the contpte implementation in Arm64 is
>>> exposed, using set_ptes() as an example.
>>>
>>> Arm64 defines an arch-specific implementation of set_ptes():
>>> "
>>> static __always_inline void set_ptes(struct mm_struct *mm, unsigned long
>>> addr,
>>> 				pte_t *ptep, pte_t pte, unsigned int nr)
>>> {
>>> 	pte = pte_mknoncont(pte);
>>>
>>> 	if (likely(nr == 1)) {
>>> 		contpte_try_unfold(mm, addr, ptep, __ptep_get(ptep));
>>> 		__set_ptes(mm, addr, ptep, pte, 1);
>>> 		contpte_try_fold(mm, addr, ptep, pte);
>>> 	} else {
>>> 		contpte_set_ptes(mm, addr, ptep, pte, nr);
>>> 	}
>>> }
>>> "
>>>
>>> Here, 'nr' refers to consecutive (present) PTEs that map consecutive pages
>>> of the same large folio within a single VMA and a single page table. Based
>>> on 'nr', it determines whether the PTE_CONT attribute should be set or not.
>>>
>>> Second, the underlying implementation of contpte_set_ptes() also calculates
>>> 'end' based on 'nr' and checks whether the PTE_CONT attribute should be set.
>>> For example:
>>>
>>> For a large folio with order = 3 (nr = 8), the PTE_CONT attribute will not
>>> be set since the 'next' is not aligned with CONT_PTE_MASK.
>>>
>>> For a large folio with order = 4 (nr = 16), it aligns perfectly, allowing
>>> the PTE_CONT attribute to be set for the entire PTE entries of the large
>>> folio.
>>>
>>> For a large folio with order = 5 (nr = 32), this involves two ranges of
>>> CONT_PTE_SIZE (16 PTEs in each range), requiring the PTE_CONT attribute to
>>> be set separately for each range.
>>>
>>> "
>>> void contpte_set_ptes(struct mm_struct *mm, unsigned long addr,
>>> 					pte_t *ptep, pte_t pte, unsigned int nr)
>>> {
>>> 	.......
>>>
>>> 	end = addr + (nr << PAGE_SHIFT);
>>> 	pfn = pte_pfn(pte);
>>> 	prot = pte_pgprot(pte);
>>>
>>> 	do {
>>> 		next = pte_cont_addr_end(addr, end);
>>> 		nr = (next - addr) >> PAGE_SHIFT;
>>> 		pte = pfn_pte(pfn, prot);
>>>
>>> 		if (((addr | next | (pfn << PAGE_SHIFT)) & ~CONT_PTE_MASK) == 0)
>>> 			pte = pte_mkcont(pte);
>>> 		else
>>> 			pte = pte_mknoncont(pte);
>>>
>>> 		__set_ptes(mm, addr, ptep, pte, nr);
>>>
>>> 		addr = next;
>>> 		ptep += nr;
>>> 		pfn += nr;
>>>
>>> 	} while (addr != end);
>>> }
>>> "
>>>
>>> Third, regarding the implementation of my patch, I have followed the contpte
>>> logic here by adding the 'nr' parameter to
>>> contpte_ptep_test_and_clear_young() for batch processing consecutive
>>> (present) PTEs. Moreover, the semantics of 'nr' remain consistent with the
>>> original contpte functions, and I have not broken the existing contpte
>>> implementation logic.
>>
>> OK that helps a lot thanks.
>>
>> So the nr will be number of PTEs that are consecutive, belong to the same folio,
>> and have the same PTE bit set excluding accessed, writable, dirty, soft-dirty.
> 
> I'm not sure test_and_clear_young_ptes() would technically require all of these
> constraints. I think it would be sufficient to just ensure that all the PTEs in
> the batch are pte_present(). And I assume the return value is intended to
> indicate if *any* of the PTEs in the batch were previously young?

Agree.

> The usual order for adding new batched PTE helpers is to define the generic
> function along with it's spec in a comment block and provide a default
> implementation that is implemented as a loop around the existing non-batched
> version of the interface. Then you can convert the core-mm to use that API. And
> finally you can opt arm64 into overriding the API with a more efficient
> implementation.
> 
> If you were to do it in that order, it tells a better story and is easier to
> follow, I think.

Good point. Let me rearrange the patch set.

> 
>>
>> But since we are retrieving accessed bit state (young), isn't it a problem we're
>> ignoring this bit when considering what goes into the batch?
>>
>> I mean now it's going to return true even if some do not have the accessed flag
>> set?
> 
> test_and_clear_young_ptes() is exploiting the fact that the kernel tracks young
> (and dirty) per *folio*. So having a young and dirty bit per PTE is providing
> more information than the kernel needs if a large folio is mapped across
> multiple PTEs. Which is why returning the logical OR of the access bits is ok here.

Right. Agree.

>> I am more convinced things are correct in style at least then this way as, as
>> you say, this is the approach taken in set_ptes().
> 
> I'm personally ok with the style and I believe the implementation is correct.
> But it would help to reformulate the series in the order I suggest above since
> then we can review against the spec of what the core-mm helper is supposed to do.

Sure. Thanks for reviewing.


From manivannan.sadhasivam at oss.qualcomm.com  Wed Dec 17 23:57:06 2025
From: manivannan.sadhasivam at oss.qualcomm.com (Manivannan Sadhasivam)
Date: Thu, 18 Dec 2025 13:27:06 +0530
Subject: [PATCH] PCI: j721e: Add config guards for Cadence Host and
 Endpoint library APIs
In-Reply-To: <20251117113246.1460644-1-s-vadapalli@ti.com>
References: <20251117113246.1460644-1-s-vadapalli@ti.com>
Message-ID: <176604462693.840440.17361297043510952220.b4-ty@kernel.org>


On Mon, 17 Nov 2025 17:02:06 +0530, Siddharth Vadapalli wrote:
> Commit under Fixes enabled loadable module support for the driver under
> the assumption that it shall be the sole user of the Cadence Host and
> Endpoint library APIs. This assumption guarantees that we won't end up
> in a case where the driver is built-in and the library support is built
> as a loadable module.
> 
> With the introduction of [1], this assumption is no longer valid. The
> SG2042 driver could be built as a loadable module, implying that the
> Cadence Host library is also selected as a loadable module. However, the
> pci-j721e.c driver could be built-in as indicated by CONFIG_PCI_J721E=y
> due to which the Cadence Endpoint library is built-in. Despite the
> library drivers being built as specified by their respective consumers,
> since the 'pci-j721e.c' driver has references to the Cadence Host
> library APIs as well, we run into a build error as reported at [0].
> 
> [...]

Applied, thanks!

[1/1] PCI: j721e: Add config guards for Cadence Host and Endpoint library APIs
      commit: 4b361b1e92be255ff923453fe8db74086cc7cf66

Best regards,
-- 
Manivannan Sadhasivam <mani at kernel.org>



From broonie at kernel.org  Thu Dec 18 00:00:57 2025
From: broonie at kernel.org (Mark Brown)
Date: Thu, 18 Dec 2025 08:00:57 +0000
Subject: [PATCH 3/4] spi: stm32: properly fail on dma_request_chan error
In-Reply-To: <20251217-stm32-spi-enhancements-v1-3-943348b8ff66@foss.st.com>
References: <20251217-stm32-spi-enhancements-v1-0-943348b8ff66@foss.st.com>
 <20251217-stm32-spi-enhancements-v1-3-943348b8ff66@foss.st.com>
Message-ID: <129a4deb-ec9c-41f0-910c-57cd43d17fcd@sirena.org.uk>

On Wed, Dec 17, 2025 at 10:51:33PM +0100, Alain Volmat wrote:
> Correct handling of the dma_request_chan call in order to avoid
> misleading warn message if no DMA is provided within the device-tree
> and moreover fail if dma_request_chan has returned a valid error.

Bug fixes should go at the start of serieses to avoid spurious
dependencies on new or cleanup changes.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251218/29af7afe/attachment.sig>

From mani at kernel.org  Thu Dec 18 00:05:37 2025
From: mani at kernel.org (Manivannan Sadhasivam)
Date: Thu, 18 Dec 2025 13:35:37 +0530
Subject: [PATCH v2 1/4] PCI: rockchip: limit RK3399 to 2.5 GT/s to
 prevent damage
In-Reply-To: <eaa9c75ca02a53f8bcc293b8bc73d013e26ec253.1763415706.git.geraldogabriel@gmail.com>
References: <cover.1763415705.git.geraldogabriel@gmail.com>
 <eaa9c75ca02a53f8bcc293b8bc73d013e26ec253.1763415706.git.geraldogabriel@gmail.com>
Message-ID: <qncj72c3owrw7rvnj6jit2sbn4ojyr3kztcjailfxtdboan6sy@ddh5g7v4fcvt>

On Mon, Nov 17, 2025 at 06:47:05PM -0300, Geraldo Nascimento wrote:
> Shawn Lin from Rockchip has reiterated that there may be danger in using
> their PCIe with 5.0 GT/s speeds. Warn the user if they make a DT change
> from the default and drive at 2.5 GT/s only, even if the DT
> max-link-speed property is invalid or inexistent.
> 
> This change is corroborated by RK3399 official datasheet [1], which
> says maximum link speed for this platform is 2.5 GT/s.
> 
> [1] https://opensource.rock-chips.com/images/d/d7/Rockchip_RK3399_Datasheet_V2.1-20200323.pdf
> 
> Fixes: 956cd99b35a8 ("PCI: rockchip: Separate common code from RC driver")
> Link: https://lore.kernel.org/all/ffd05070-9879-4468-94e3-b88968b4c21b at rock-chips.com/
> Cc: stable at vger.kernel.org
> Reported-by: Dragan Simic <dsimic at manjaro.org>
> Reported-by: Shawn Lin <shawn.lin at rock-chips.com>
> Reviewed-by: Dragan Simic <dsimic at manjaro.org>
> Signed-off-by: Geraldo Nascimento <geraldogabriel at gmail.com>
> ---
>  drivers/pci/controller/pcie-rockchip.c | 10 ++++++++--
>  1 file changed, 8 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/pci/controller/pcie-rockchip.c b/drivers/pci/controller/pcie-rockchip.c
> index 0f88da378805..992ccf4b139e 100644
> --- a/drivers/pci/controller/pcie-rockchip.c
> +++ b/drivers/pci/controller/pcie-rockchip.c
> @@ -66,8 +66,14 @@ int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip)
>  	}
>  
>  	rockchip->link_gen = of_pci_get_max_link_speed(node);
> -	if (rockchip->link_gen < 0 || rockchip->link_gen > 2)
> -		rockchip->link_gen = 2;
> +	if (rockchip->link_gen < 0 || rockchip->link_gen > 2) {
> +		rockchip->link_gen = 1;
> +		dev_warn(dev, "invalid max-link-speed, set to 2.5 GT/s\n");
> +	}
> +	else if (rockchip->link_gen == 2) {
> +		rockchip->link_gen = 1;
> +		dev_warn(dev, "5.0 GT/s is dangerous, set to 2.5 GT/s\n");

What does 'danger' really mean here? Link instability or something else?

Error messages should be precise and not fearmongering.

- Mani

-- 
????????? ????????


From yuanfang.zhang at oss.qualcomm.com  Thu Dec 18 00:09:40 2025
From: yuanfang.zhang at oss.qualcomm.com (Yuanfang Zhang)
Date: Thu, 18 Dec 2025 00:09:40 -0800
Subject: [PATCH v2 00/12] coresight: Add CPU cluster funnel/replicator/tmc
 support
Message-ID: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>

This patch series adds support for CoreSight components local to CPU clusters,
including funnel, replicator, and TMC, which reside within CPU cluster power
domains. These components require special handling due to power domain
constraints.

Unlike system-level CoreSight devices, these components share the CPU cluster's
power domain. When the cluster enters low-power mode (LPM), their registers
become inaccessible. Notably, `pm_runtime_get` alone cannot bring the cluster
out of LPM, making standard register access unreliable.

To address this, the series introduces:
- Identifying cluster-bound devices via a new `qcom,cpu-bound-components`
  device tree property.
- Implementing deferred probing: if associated CPUs are offline during
  probe, initialization is deferred until a CPU hotplug notifier detects
  the CPU coming online.
- Utilizing `smp_call_function_single()` to ensure register accesses
  (initialization, enablement, sysfs reads) are always executed on a
  powered CPU within the target cluster.
- Extending the CoreSight link `enable` callback to pass the `cs_mode`.
  This allows drivers to distinguish between SysFS and Perf modes and
  apply mode-specific logic.

Jie Gan (1):
  arm64: dts: qcom: hamoa: add Coresight nodes for APSS debug block

Yuanfang Zhang (11):
  dt-bindings: arm: coresight: Add 'qcom,cpu-bound-components' property
  coresight: Pass trace mode to link enable callback
  coresight-funnel: Support CPU cluster funnel initialization
  coresight-funnel: Defer probe when associated CPUs are offline
  coresight-replicator: Support CPU cluster replicator initialization
  coresight-replicator: Defer probe when associated CPUs are offline
  coresight-replicator: Update management interface for CPU-bound devices
  coresight-tmc: Support probe and initialization for CPU cluster TMCs
  coresight-tmc-etf: Refactor enable function for CPU cluster ETF support
  coresight-tmc: Update management interface for CPU-bound TMCs
  coresight-tmc: Defer probe when associated CPUs are offline

Verification:

This series has been verified on sm8750.

Test steps for delay probe:

1. limit the system to enable at most 6 CPU cores during boot.
2. echo 1 >/sys/bus/cpu/devices/cpu6/online.
3. check whether ETM6 and ETM7 have been probed.

Test steps for sysfs mode:

echo 1 >/sys/bus/coresight/devices/tmc_etf0/enable_sink
echo 1 >/sys/bus/coresight/devices/etm0/enable_source
echo 1 >/sys/bus/coresight/devices/etm6/enable_source
echo 0 >/sys/bus/coresight/devices/etm0/enable_source
echo 0 >/sys/bus/coresight/devicse/etm6/enable_source
echo 0 >/sys/bus/coresight/devices/tmc_etf0/enable_sink

echo 1 >/sys/bus/coresight/devices/tmc_etf1/enable_sink
echo 1 >/sys/bus/coresight/devcies/etm0/enable_source
cat /dev/tmc_etf1 >/tmp/etf1.bin
echo 0 >/sys/bus/coresight/devices/etm0/enable_source
echo 0 >/sys/bus/coresight/devices/tmc_etf1/enable_sink

echo 1 >/sys/bus/coresight/devices/tmc_etf2/enable_sink
echo 1 >/sys/bus/coresight/devices/etm6/enable_source
cat /dev/tmc_etf2 >/tmp/etf2.bin
echo 0 >/sys/bus/coresight/devices/etm6/enable_source
echo 0 >/sys/bus/coresight/devices/tmc_etf2/enable_sink

Test steps for sysfs node:

cat /sys/bus/coresight/devices/tmc_etf*/mgmt/*

cat /sys/bus/coresight/devices/funnel*/funnel_ctrl

cat /sys/bus/coresight/devices/replicator*/mgmt/*

Test steps for perf mode:

perf record -a -e cs_etm//k -- sleep 5

Signed-off-by: Yuanfang Zhang <yuanfang.zhang at oss.qualcomm.com>
---
Changes in v2:
- Use the qcom,cpu-bound-components device tree property to identify devices
  bound to a cluster.
- Refactor commit message.
- Introduce a supported_cpus field in the drvdata structure to record the CPUs
  that belong to the cluster where the local component resides.
- Link to v1: https://lore.kernel.org/r/20251027-cpu_cluster_component_pm-v1-0-31355ac588c2 at oss.qualcomm.com

---
Jie Gan (1):
      arm64: dts: qcom: hamoa: Add CoreSight nodes for APSS debug block

Yuanfang Zhang (11):
      dt-bindings: arm: coresight: Add 'qcom,cpu-bound-components' property
      coresight-funnel: Support CPU cluster funnel initialization
      coresight-funnel: Defer probe when associated CPUs are offline
      coresight-replicator: Support CPU cluster replicator initialization
      coresight-replicator: Defer probe when associated CPUs are offline
      coresight-replicator: Update management interface for CPU-bound devices
      coresight-tmc: Support probe and initialization for CPU cluster TMCs
      coresight-tmc-etf: Refactor enable function for CPU cluster ETF support
      coresight-tmc: Update management interface for CPU-bound TMCs
      coresight-tmc: Defer probe when associated CPUs are offline
      coresight: Pass trace mode to link enable callback

 .../bindings/arm/arm,coresight-dynamic-funnel.yaml |   5 +
 .../arm/arm,coresight-dynamic-replicator.yaml      |   5 +
 .../devicetree/bindings/arm/arm,coresight-tmc.yaml |   5 +
 arch/arm64/boot/dts/qcom/hamoa.dtsi                | 926 +++++++++++++++++++++
 arch/arm64/boot/dts/qcom/purwa.dtsi                |  12 +
 drivers/hwtracing/coresight/coresight-core.c       |   7 +-
 drivers/hwtracing/coresight/coresight-funnel.c     | 258 +++++-
 drivers/hwtracing/coresight/coresight-replicator.c | 341 +++++++-
 drivers/hwtracing/coresight/coresight-tmc-core.c   | 387 +++++++--
 drivers/hwtracing/coresight/coresight-tmc-etf.c    | 106 ++-
 drivers/hwtracing/coresight/coresight-tmc.h        |  10 +
 drivers/hwtracing/coresight/coresight-tnoc.c       |   3 +-
 drivers/hwtracing/coresight/coresight-tpda.c       |   3 +-
 include/linux/coresight.h                          |   3 +-
 14 files changed, 1902 insertions(+), 169 deletions(-)
---
base-commit: 008d3547aae5bc86fac3eda317489169c3fda112
change-id: 20251016-cpu_cluster_component_pm-ce518f510433

Best regards,
-- 
Yuanfang Zhang <yuanfang.zhang at oss.qualcomm.com>



From yuanfang.zhang at oss.qualcomm.com  Thu Dec 18 00:09:42 2025
From: yuanfang.zhang at oss.qualcomm.com (Yuanfang Zhang)
Date: Thu, 18 Dec 2025 00:09:42 -0800
Subject: [PATCH v2 02/12] coresight-funnel: Support CPU cluster funnel
 initialization
In-Reply-To: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
References: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
Message-ID: <20251218-cpu_cluster_component_pm-v2-2-2335a6ae62a0@oss.qualcomm.com>

Funnels associated with CPU clusters reside in the cluster's power domain.
Unlike dynamic funnels (which are typically system-wide), these per-cluster
funnels are only accessible when the cluster is powered on. Standard
runtime PM may not suffice to wake up a cluster from low-power states,
making direct register access unreliable.

Enhance the funnel driver to support these per-cluster devices:

1. Safe Initialization:
   - Identify CPU cluster funnels via "qcom,cpu-bound-components".
   - Use smp_call_function_single() to perform hardware initialization
     (claim tag clearing) on a CPU within the cluster.
   - Refactor the probe flow to encapsulate device registration in
     funnel_add_coresight_dev().

2. Cross-CPU Enablement:
   - Update funnel_enable() to use smp_call_function_single() when
     enabling the hardware on a cluster-bound funnel.

3. Debug Interface Support:
   - Update funnel_ctrl_show() to safely read the control register via
     cross-CPU calls when necessary.

This ensures that funnel operations remain safe and functional even when
the associated CPU cluster is in aggressive low-power states.

Signed-off-by: Yuanfang Zhang <yuanfang.zhang at oss.qualcomm.com>
---
 drivers/hwtracing/coresight/coresight-funnel.c | 183 ++++++++++++++++++++-----
 1 file changed, 152 insertions(+), 31 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c
index 3b248e54471a38f501777fe162fea850d1c851b3..a1264df84ab4c625c63dfbb9b7710b983a10c6b4 100644
--- a/drivers/hwtracing/coresight/coresight-funnel.c
+++ b/drivers/hwtracing/coresight/coresight-funnel.c
@@ -15,6 +15,7 @@
 #include <linux/slab.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
+#include <linux/pm_domain.h>
 #include <linux/pm_runtime.h>
 #include <linux/coresight.h>
 #include <linux/amba/bus.h>
@@ -40,6 +41,7 @@ DEFINE_CORESIGHT_DEVLIST(funnel_devs, "funnel");
  * @csdev:	component vitals needed by the framework.
  * @priority:	port selection order.
  * @spinlock:	serialize enable/disable operations.
+ * @supported_cpus:	Represent the CPUs related to this funnel.
  */
 struct funnel_drvdata {
 	void __iomem		*base;
@@ -48,6 +50,13 @@ struct funnel_drvdata {
 	struct coresight_device	*csdev;
 	unsigned long		priority;
 	raw_spinlock_t		spinlock;
+	struct cpumask		*supported_cpus;
+};
+
+struct funnel_smp_arg {
+	struct funnel_drvdata *drvdata;
+	int port;
+	int rc;
 };
 
 static int dynamic_funnel_enable_hw(struct funnel_drvdata *drvdata, int port)
@@ -76,6 +85,33 @@ static int dynamic_funnel_enable_hw(struct funnel_drvdata *drvdata, int port)
 	return rc;
 }
 
+static void funnel_enable_hw_smp_call(void *info)
+{
+	struct funnel_smp_arg *arg = info;
+
+	arg->rc = dynamic_funnel_enable_hw(arg->drvdata, arg->port);
+}
+
+static int funnel_enable_hw(struct funnel_drvdata *drvdata, int port)
+{
+	int cpu, ret;
+	struct funnel_smp_arg arg = { 0 };
+
+	if (!drvdata->supported_cpus)
+		return dynamic_funnel_enable_hw(drvdata, port);
+
+	arg.drvdata = drvdata;
+	arg.port = port;
+
+	for_each_cpu(cpu, drvdata->supported_cpus) {
+		ret = smp_call_function_single(cpu,
+					       funnel_enable_hw_smp_call, &arg, 1);
+		if (!ret)
+			return arg.rc;
+	}
+	return ret;
+}
+
 static int funnel_enable(struct coresight_device *csdev,
 			 struct coresight_connection *in,
 			 struct coresight_connection *out)
@@ -86,19 +122,24 @@ static int funnel_enable(struct coresight_device *csdev,
 	bool first_enable = false;
 
 	raw_spin_lock_irqsave(&drvdata->spinlock, flags);
-	if (in->dest_refcnt == 0) {
-		if (drvdata->base)
-			rc = dynamic_funnel_enable_hw(drvdata, in->dest_port);
-		if (!rc)
-			first_enable = true;
-	}
-	if (!rc)
+
+	if (in->dest_refcnt == 0)
+		first_enable = true;
+	else
 		in->dest_refcnt++;
+
 	raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
-	if (first_enable)
-		dev_dbg(&csdev->dev, "FUNNEL inport %d enabled\n",
-			in->dest_port);
+	if (first_enable) {
+		if (drvdata->base)
+			rc = funnel_enable_hw(drvdata, in->dest_port);
+		if (!rc) {
+			in->dest_refcnt++;
+			dev_dbg(&csdev->dev, "FUNNEL inport %d enabled\n",
+				in->dest_port);
+		}
+	}
+
 	return rc;
 }
 
@@ -188,15 +229,39 @@ static u32 get_funnel_ctrl_hw(struct funnel_drvdata *drvdata)
 	return functl;
 }
 
+static void get_funnel_ctrl_smp_call(void *info)
+{
+	struct funnel_smp_arg *arg = info;
+
+	arg->rc = get_funnel_ctrl_hw(arg->drvdata);
+}
+
 static ssize_t funnel_ctrl_show(struct device *dev,
 			     struct device_attribute *attr, char *buf)
 {
 	u32 val;
+	int cpu, ret;
 	struct funnel_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	struct funnel_smp_arg arg = { 0 };
 
 	pm_runtime_get_sync(dev->parent);
-
-	val = get_funnel_ctrl_hw(drvdata);
+	if (!drvdata->supported_cpus) {
+		val = get_funnel_ctrl_hw(drvdata);
+	} else {
+		arg.drvdata = drvdata;
+		for_each_cpu(cpu, drvdata->supported_cpus) {
+			ret = smp_call_function_single(cpu,
+						       get_funnel_ctrl_smp_call, &arg, 1);
+			if (!ret)
+				break;
+		}
+		if (!ret) {
+			val =  arg.rc;
+		} else {
+			pm_runtime_put(dev->parent);
+			return ret;
+		}
+	}
 
 	pm_runtime_put(dev->parent);
 
@@ -211,22 +276,68 @@ static struct attribute *coresight_funnel_attrs[] = {
 };
 ATTRIBUTE_GROUPS(coresight_funnel);
 
+static void funnel_clear_self_claim_tag(struct funnel_drvdata *drvdata)
+{
+	struct csdev_access access = CSDEV_ACCESS_IOMEM(drvdata->base);
+
+	coresight_clear_self_claim_tag(&access);
+}
+
+static void funnel_init_on_cpu(void *info)
+{
+	struct funnel_drvdata *drvdata = info;
+
+	funnel_clear_self_claim_tag(drvdata);
+}
+
+static int funnel_add_coresight_dev(struct device *dev)
+{
+	struct coresight_desc desc = { 0 };
+	struct funnel_drvdata *drvdata = dev_get_drvdata(dev);
+
+	if (drvdata->base) {
+		desc.groups = coresight_funnel_groups;
+		desc.access = CSDEV_ACCESS_IOMEM(drvdata->base);
+	}
+
+	desc.name = coresight_alloc_device_name(&funnel_devs, dev);
+	if (!desc.name)
+		return -ENOMEM;
+
+	desc.type = CORESIGHT_DEV_TYPE_LINK;
+	desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG;
+	desc.ops = &funnel_cs_ops;
+	desc.pdata = dev->platform_data;
+	desc.dev = dev;
+
+	drvdata->csdev = coresight_register(&desc);
+	if (IS_ERR(drvdata->csdev))
+		return PTR_ERR(drvdata->csdev);
+	return 0;
+}
+
+static struct cpumask *funnel_get_supported_cpus(struct device *dev)
+{
+	struct generic_pm_domain *pd;
+
+	pd = pd_to_genpd(dev->pm_domain);
+	if (pd)
+		return pd->cpus;
+
+	return NULL;
+}
+
 static int funnel_probe(struct device *dev, struct resource *res)
 {
 	void __iomem *base;
 	struct coresight_platform_data *pdata = NULL;
 	struct funnel_drvdata *drvdata;
-	struct coresight_desc desc = { 0 };
-	int ret;
+	int cpu, ret;
 
 	if (is_of_node(dev_fwnode(dev)) &&
 	    of_device_is_compatible(dev->of_node, "arm,coresight-funnel"))
 		dev_warn_once(dev, "Uses OBSOLETE CoreSight funnel binding\n");
 
-	desc.name = coresight_alloc_device_name(&funnel_devs, dev);
-	if (!desc.name)
-		return -ENOMEM;
-
 	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
 	if (!drvdata)
 		return -ENOMEM;
@@ -244,9 +355,6 @@ static int funnel_probe(struct device *dev, struct resource *res)
 		if (IS_ERR(base))
 			return PTR_ERR(base);
 		drvdata->base = base;
-		desc.groups = coresight_funnel_groups;
-		desc.access = CSDEV_ACCESS_IOMEM(base);
-		coresight_clear_self_claim_tag(&desc.access);
 	}
 
 	dev_set_drvdata(dev, drvdata);
@@ -258,23 +366,36 @@ static int funnel_probe(struct device *dev, struct resource *res)
 	dev->platform_data = pdata;
 
 	raw_spin_lock_init(&drvdata->spinlock);
-	desc.type = CORESIGHT_DEV_TYPE_LINK;
-	desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG;
-	desc.ops = &funnel_cs_ops;
-	desc.pdata = pdata;
-	desc.dev = dev;
-	drvdata->csdev = coresight_register(&desc);
-	if (IS_ERR(drvdata->csdev))
-		return PTR_ERR(drvdata->csdev);
 
-	return 0;
+	if (fwnode_property_present(dev_fwnode(dev), "qcom,cpu-bound-components")) {
+		drvdata->supported_cpus = funnel_get_supported_cpus(dev);
+		if (!drvdata->supported_cpus)
+			return -EINVAL;
+
+		cpus_read_lock();
+		for_each_cpu(cpu, drvdata->supported_cpus) {
+			ret = smp_call_function_single(cpu,
+						       funnel_init_on_cpu, drvdata, 1);
+			if (!ret)
+				break;
+		}
+		cpus_read_unlock();
+
+		if (ret)
+			return 0;
+	} else if (res) {
+		funnel_clear_self_claim_tag(drvdata);
+	}
+
+	return funnel_add_coresight_dev(dev);
 }
 
 static int funnel_remove(struct device *dev)
 {
 	struct funnel_drvdata *drvdata = dev_get_drvdata(dev);
 
-	coresight_unregister(drvdata->csdev);
+	if (drvdata->csdev)
+		coresight_unregister(drvdata->csdev);
 
 	return 0;
 }

-- 
2.34.1



From yuanfang.zhang at oss.qualcomm.com  Thu Dec 18 00:09:41 2025
From: yuanfang.zhang at oss.qualcomm.com (Yuanfang Zhang)
Date: Thu, 18 Dec 2025 00:09:41 -0800
Subject: [PATCH v2 01/12] dt-bindings: arm: coresight: Add
 'qcom,cpu-bound-components' property
In-Reply-To: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
References: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
Message-ID: <20251218-cpu_cluster_component_pm-v2-1-2335a6ae62a0@oss.qualcomm.com>

Introduce the `qcom,cpu-bound-components` boolean property for CoreSight
components (TMC, Funnel, and Replicator).

This property indicates that the component is physically located within a
CPU cluster power domain. Such components share the power state of the
cluster and may require special handling (e.g., cross-CPU register
access) compared to system-wide components.

Signed-off-by: Yuanfang Zhang <yuanfang.zhang at oss.qualcomm.com>
---
 .../devicetree/bindings/arm/arm,coresight-dynamic-funnel.yaml        | 5 +++++
 .../devicetree/bindings/arm/arm,coresight-dynamic-replicator.yaml    | 5 +++++
 Documentation/devicetree/bindings/arm/arm,coresight-tmc.yaml         | 5 +++++
 3 files changed, 15 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/arm,coresight-dynamic-funnel.yaml b/Documentation/devicetree/bindings/arm/arm,coresight-dynamic-funnel.yaml
index b74db15e5f8af2226b817f6af5f533b1bfc74736..a4c7333e8359da9035a9fed999ec99159e00a1d9 100644
--- a/Documentation/devicetree/bindings/arm/arm,coresight-dynamic-funnel.yaml
+++ b/Documentation/devicetree/bindings/arm/arm,coresight-dynamic-funnel.yaml
@@ -57,6 +57,11 @@ properties:
   power-domains:
     maxItems: 1
 
+  qcom,cpu-bound-components:
+    type: boolean
+    description:
+      Indicates whether the funnel is located physically within cpu cluster.
+
   label:
     description:
       Description of a coresight device.
diff --git a/Documentation/devicetree/bindings/arm/arm,coresight-dynamic-replicator.yaml b/Documentation/devicetree/bindings/arm/arm,coresight-dynamic-replicator.yaml
index 17ea936b796fd42bb885e539201276a11e91028c..2c6e78f02ed84d95bb4366e4c4bbd1b3953efa32 100644
--- a/Documentation/devicetree/bindings/arm/arm,coresight-dynamic-replicator.yaml
+++ b/Documentation/devicetree/bindings/arm/arm,coresight-dynamic-replicator.yaml
@@ -67,6 +67,11 @@ properties:
       Indicates that the replicator will lose register context when AMBA clock
       is removed which is observed in some replicator designs.
 
+  qcom,cpu-bound-components:
+    type: boolean
+    description:
+      Indicates whether the replicator is located physically within cpu cluster.
+
   in-ports:
     $ref: /schemas/graph.yaml#/properties/ports
     additionalProperties: false
diff --git a/Documentation/devicetree/bindings/arm/arm,coresight-tmc.yaml b/Documentation/devicetree/bindings/arm/arm,coresight-tmc.yaml
index 96dd5b5f771a39138df9adde0c9c9a6f5583d9da..8c4f2244a5c74dc8654892305025a4e6bccbce07 100644
--- a/Documentation/devicetree/bindings/arm/arm,coresight-tmc.yaml
+++ b/Documentation/devicetree/bindings/arm/arm,coresight-tmc.yaml
@@ -86,6 +86,11 @@ properties:
     $ref: /schemas/types.yaml#/definitions/uint32
     maximum: 15
 
+  qcom,cpu-bound-components:
+    type: boolean
+    description:
+      indicates whether the TMC-ETF is located physically within cpu cluster.
+
   in-ports:
     $ref: /schemas/graph.yaml#/properties/ports
     additionalProperties: false

-- 
2.34.1



From yuanfang.zhang at oss.qualcomm.com  Thu Dec 18 00:09:43 2025
From: yuanfang.zhang at oss.qualcomm.com (Yuanfang Zhang)
Date: Thu, 18 Dec 2025 00:09:43 -0800
Subject: [PATCH v2 03/12] coresight-funnel: Defer probe when associated
 CPUs are offline
In-Reply-To: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
References: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
Message-ID: <20251218-cpu_cluster_component_pm-v2-3-2335a6ae62a0@oss.qualcomm.com>

Per-cluster funnels rely on the associated CPU cluster being online to
securely access registers during initialization. If all CPUs in the
cluster are offline during probe, these operations fail.

Support deferred initialization for these devices:

1. Track funnels that fail to probe due to offline CPUs in a global
   list.
2. Register a CPU hotplug notifier (funnel_online_cpu) to detect when
   a relevant CPU comes online.
3. Upon CPU online, retry the hardware initialization and registration
   with the CoreSight framework.

Signed-off-by: Yuanfang Zhang <yuanfang.zhang at oss.qualcomm.com>
---
 drivers/hwtracing/coresight/coresight-funnel.c | 62 +++++++++++++++++++++++---
 1 file changed, 57 insertions(+), 5 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c
index a1264df84ab4c625c63dfbb9b7710b983a10c6b4..5d114ce1109f4f9a8b108110bdae258f216881d8 100644
--- a/drivers/hwtracing/coresight/coresight-funnel.c
+++ b/drivers/hwtracing/coresight/coresight-funnel.c
@@ -32,6 +32,9 @@
 #define FUNNEL_ENSx_MASK	0xff
 
 DEFINE_CORESIGHT_DEVLIST(funnel_devs, "funnel");
+static LIST_HEAD(funnel_delay_probe);
+static enum cpuhp_state hp_online;
+static DEFINE_SPINLOCK(delay_lock);
 
 /**
  * struct funnel_drvdata - specifics associated to a funnel component
@@ -42,6 +45,8 @@ DEFINE_CORESIGHT_DEVLIST(funnel_devs, "funnel");
  * @priority:	port selection order.
  * @spinlock:	serialize enable/disable operations.
  * @supported_cpus:	Represent the CPUs related to this funnel.
+ * @dev:	pointer to the device associated with this funnel.
+ * @link:	list node for adding this funnel to the delayed probe list.
  */
 struct funnel_drvdata {
 	void __iomem		*base;
@@ -51,6 +56,8 @@ struct funnel_drvdata {
 	unsigned long		priority;
 	raw_spinlock_t		spinlock;
 	struct cpumask		*supported_cpus;
+	struct device		*dev;
+	struct list_head	link;
 };
 
 struct funnel_smp_arg {
@@ -371,7 +378,7 @@ static int funnel_probe(struct device *dev, struct resource *res)
 		drvdata->supported_cpus = funnel_get_supported_cpus(dev);
 		if (!drvdata->supported_cpus)
 			return -EINVAL;
-
+		drvdata->dev = dev;
 		cpus_read_lock();
 		for_each_cpu(cpu, drvdata->supported_cpus) {
 			ret = smp_call_function_single(cpu,
@@ -379,10 +386,15 @@ static int funnel_probe(struct device *dev, struct resource *res)
 			if (!ret)
 				break;
 		}
-		cpus_read_unlock();
 
-		if (ret)
+		if (ret) {
+			scoped_guard(spinlock,  &delay_lock)
+				list_add(&drvdata->link, &funnel_delay_probe);
+			cpus_read_unlock();
 			return 0;
+		}
+
+		cpus_read_unlock();
 	} else if (res) {
 		funnel_clear_self_claim_tag(drvdata);
 	}
@@ -394,9 +406,12 @@ static int funnel_remove(struct device *dev)
 {
 	struct funnel_drvdata *drvdata = dev_get_drvdata(dev);
 
-	if (drvdata->csdev)
+	if (drvdata->csdev) {
 		coresight_unregister(drvdata->csdev);
-
+	} else {
+		scoped_guard(spinlock,  &delay_lock)
+			list_del(&drvdata->link);
+	}
 	return 0;
 }
 
@@ -533,8 +548,41 @@ static struct amba_driver dynamic_funnel_driver = {
 	.id_table	= dynamic_funnel_ids,
 };
 
+static int funnel_online_cpu(unsigned int cpu)
+{
+	struct funnel_drvdata *drvdata, *tmp;
+	int ret;
+
+	list_for_each_entry_safe(drvdata, tmp, &funnel_delay_probe, link) {
+		if (cpumask_test_cpu(cpu, drvdata->supported_cpus)) {
+			scoped_guard(spinlock,  &delay_lock)
+				list_del(&drvdata->link);
+
+			ret = pm_runtime_resume_and_get(drvdata->dev);
+			if (ret < 0)
+				return 0;
+
+			funnel_clear_self_claim_tag(drvdata);
+			funnel_add_coresight_dev(drvdata->dev);
+			pm_runtime_put(drvdata->dev);
+		}
+	}
+	return 0;
+}
+
 static int __init funnel_init(void)
 {
+	int ret;
+
+	ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
+					"arm/coresight-funnel:online",
+					funnel_online_cpu, NULL);
+
+	if (ret > 0)
+		hp_online = ret;
+	else
+		return ret;
+
 	return coresight_init_driver("funnel", &dynamic_funnel_driver, &funnel_driver,
 				     THIS_MODULE);
 }
@@ -542,6 +590,10 @@ static int __init funnel_init(void)
 static void __exit funnel_exit(void)
 {
 	coresight_remove_driver(&dynamic_funnel_driver, &funnel_driver);
+	if (hp_online) {
+		cpuhp_remove_state_nocalls(hp_online);
+		hp_online = 0;
+	}
 }
 
 module_init(funnel_init);

-- 
2.34.1



From yuanfang.zhang at oss.qualcomm.com  Thu Dec 18 00:09:44 2025
From: yuanfang.zhang at oss.qualcomm.com (Yuanfang Zhang)
Date: Thu, 18 Dec 2025 00:09:44 -0800
Subject: [PATCH v2 04/12] coresight-replicator: Support CPU cluster
 replicator initialization
In-Reply-To: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
References: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
Message-ID: <20251218-cpu_cluster_component_pm-v2-4-2335a6ae62a0@oss.qualcomm.com>

Replicators associated with CPU clusters reside in the cluster's power
domain. Unlike system-wide replicators, their registers are only
accessible when the cluster is powered on. Standard runtime PM may not
suffice to wake up a cluster from low-power states, making direct
register access unreliable during initialization or operation.

Enhance the replicator driver to support these per-cluster devices:

1. Safe Initialization:
   - Identify per-cluster replicators via device properties.
   - Use smp_call_function_single() to perform hardware initialization
     (reset and claim tag clearing) on a CPU within the cluster.
   - Refactor the probe flow to encapsulate device registration in
     replicator_add_coresight_dev().

2. Cross-CPU Enablement:
   - Update replicator_enable() to use smp_call_function_single()
     when enabling the hardware on a cluster-bound replicator.

3. Claim/Disclaim Handling:
   - Introduce replicator_claim/disclaim_device_unlocked() to manage
     device access safely before full framework registration.

This ensures that replicator operations remain robust even when the
associated CPU cluster is in low-power states, while maintaining
compatibility with existing system-level replicators.

Signed-off-by: Yuanfang Zhang <yuanfang.zhang at oss.qualcomm.com>
---
 drivers/hwtracing/coresight/coresight-replicator.c | 200 +++++++++++++++++----
 1 file changed, 167 insertions(+), 33 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c
index e6472658235dc479cec91ac18f3737f76f8c74f0..c11da452559c73af6709b39d03b646cb4779736f 100644
--- a/drivers/hwtracing/coresight/coresight-replicator.c
+++ b/drivers/hwtracing/coresight/coresight-replicator.c
@@ -13,6 +13,7 @@
 #include <linux/io.h>
 #include <linux/err.h>
 #include <linux/slab.h>
+#include <linux/pm_domain.h>
 #include <linux/pm_runtime.h>
 #include <linux/property.h>
 #include <linux/clk.h>
@@ -35,6 +36,7 @@ DEFINE_CORESIGHT_DEVLIST(replicator_devs, "replicator");
  * @csdev:	component vitals needed by the framework
  * @spinlock:	serialize enable/disable operations.
  * @check_idfilter_val: check if the context is lost upon clock removal.
+ * @supported_cpus:	Represent the CPUs related to this funnel.
  */
 struct replicator_drvdata {
 	void __iomem		*base;
@@ -43,18 +45,61 @@ struct replicator_drvdata {
 	struct coresight_device	*csdev;
 	raw_spinlock_t		spinlock;
 	bool			check_idfilter_val;
+	struct cpumask		*supported_cpus;
 };
 
-static void dynamic_replicator_reset(struct replicator_drvdata *drvdata)
+struct replicator_smp_arg {
+	struct replicator_drvdata *drvdata;
+	int outport;
+	int rc;
+};
+
+static void replicator_clear_self_claim_tag(struct replicator_drvdata *drvdata)
+{
+	struct csdev_access access = CSDEV_ACCESS_IOMEM(drvdata->base);
+
+	coresight_clear_self_claim_tag(&access);
+}
+
+static int replicator_claim_device_unlocked(struct replicator_drvdata *drvdata)
+{
+	struct coresight_device *csdev = drvdata->csdev;
+	struct csdev_access access = CSDEV_ACCESS_IOMEM(drvdata->base);
+	u32 claim_tag;
+
+	if (csdev)
+		return coresight_claim_device_unlocked(csdev);
+
+	writel_relaxed(CORESIGHT_CLAIM_SELF_HOSTED, drvdata->base + CORESIGHT_CLAIMSET);
+
+	claim_tag = readl_relaxed(drvdata->base + CORESIGHT_CLAIMCLR);
+	if (claim_tag != CORESIGHT_CLAIM_SELF_HOSTED) {
+		coresight_clear_self_claim_tag_unlocked(&access);
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static void replicator_disclaim_device_unlocked(struct replicator_drvdata *drvdata)
 {
 	struct coresight_device *csdev = drvdata->csdev;
+	struct csdev_access access = CSDEV_ACCESS_IOMEM(drvdata->base);
+
+	if (csdev)
+		return coresight_disclaim_device_unlocked(csdev);
 
+	coresight_clear_self_claim_tag_unlocked(&access);
+}
+
+static void dynamic_replicator_reset(struct replicator_drvdata *drvdata)
+{
 	CS_UNLOCK(drvdata->base);
 
-	if (!coresight_claim_device_unlocked(csdev)) {
+	if (!replicator_claim_device_unlocked(drvdata)) {
 		writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER0);
 		writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER1);
-		coresight_disclaim_device_unlocked(csdev);
+		replicator_disclaim_device_unlocked(drvdata);
 	}
 
 	CS_LOCK(drvdata->base);
@@ -116,6 +161,34 @@ static int dynamic_replicator_enable(struct replicator_drvdata *drvdata,
 	return rc;
 }
 
+static void replicator_enable_hw_smp_call(void *info)
+{
+	struct replicator_smp_arg *arg = info;
+
+	arg->rc = dynamic_replicator_enable(arg->drvdata, 0, arg->outport);
+}
+
+static int replicator_enable_hw(struct replicator_drvdata *drvdata,
+				int inport, int outport)
+{
+	int cpu, ret;
+	struct replicator_smp_arg arg = { 0 };
+
+	if (!drvdata->supported_cpus)
+		return dynamic_replicator_enable(drvdata, 0, outport);
+
+	arg.drvdata = drvdata;
+	arg.outport = outport;
+
+	for_each_cpu(cpu, drvdata->supported_cpus) {
+		ret = smp_call_function_single(cpu, replicator_enable_hw_smp_call, &arg, 1);
+		if (!ret)
+			return arg.rc;
+	}
+
+	return ret;
+}
+
 static int replicator_enable(struct coresight_device *csdev,
 			     struct coresight_connection *in,
 			     struct coresight_connection *out)
@@ -126,19 +199,24 @@ static int replicator_enable(struct coresight_device *csdev,
 	bool first_enable = false;
 
 	raw_spin_lock_irqsave(&drvdata->spinlock, flags);
-	if (out->src_refcnt == 0) {
-		if (drvdata->base)
-			rc = dynamic_replicator_enable(drvdata, in->dest_port,
-						       out->src_port);
-		if (!rc)
-			first_enable = true;
-	}
-	if (!rc)
+
+	if (out->src_refcnt == 0)
+		first_enable = true;
+	else
 		out->src_refcnt++;
 	raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
-	if (first_enable)
-		dev_dbg(&csdev->dev, "REPLICATOR enabled\n");
+	if (first_enable) {
+		if (drvdata->base)
+			rc = replicator_enable_hw(drvdata, in->dest_port,
+						  out->src_port);
+		if (!rc) {
+			out->src_refcnt++;
+			dev_dbg(&csdev->dev, "REPLICATOR enabled\n");
+			return rc;
+		}
+	}
+
 	return rc;
 }
 
@@ -217,23 +295,69 @@ static const struct attribute_group *replicator_groups[] = {
 	NULL,
 };
 
+static int replicator_add_coresight_dev(struct device *dev)
+{
+	struct coresight_desc desc = { 0 };
+	struct replicator_drvdata *drvdata = dev_get_drvdata(dev);
+
+	if (drvdata->base) {
+		desc.groups = replicator_groups;
+		desc.access = CSDEV_ACCESS_IOMEM(drvdata->base);
+	}
+
+	desc.name = coresight_alloc_device_name(&replicator_devs, dev);
+	if (!desc.name)
+		return -ENOMEM;
+
+	desc.type = CORESIGHT_DEV_TYPE_LINK;
+	desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
+	desc.ops = &replicator_cs_ops;
+	desc.pdata = dev->platform_data;
+	desc.dev = dev;
+
+	drvdata->csdev = coresight_register(&desc);
+	if (IS_ERR(drvdata->csdev))
+		return PTR_ERR(drvdata->csdev);
+
+	return 0;
+}
+
+static void replicator_init_hw(struct replicator_drvdata *drvdata)
+{
+	replicator_clear_self_claim_tag(drvdata);
+	replicator_reset(drvdata);
+}
+
+static void replicator_init_on_cpu(void *info)
+{
+	struct replicator_drvdata *drvdata = info;
+
+	replicator_init_hw(drvdata);
+}
+
+static struct cpumask *replicator_get_supported_cpus(struct device *dev)
+{
+	struct generic_pm_domain *pd;
+
+	pd = pd_to_genpd(dev->pm_domain);
+	if (pd)
+		return pd->cpus;
+
+	return NULL;
+}
+
 static int replicator_probe(struct device *dev, struct resource *res)
 {
 	struct coresight_platform_data *pdata = NULL;
 	struct replicator_drvdata *drvdata;
-	struct coresight_desc desc = { 0 };
 	void __iomem *base;
-	int ret;
+	int cpu, ret;
 
 	if (is_of_node(dev_fwnode(dev)) &&
 	    of_device_is_compatible(dev->of_node, "arm,coresight-replicator"))
 		dev_warn_once(dev,
 			      "Uses OBSOLETE CoreSight replicator binding\n");
 
-	desc.name = coresight_alloc_device_name(&replicator_devs, dev);
-	if (!desc.name)
-		return -ENOMEM;
-
 	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
 	if (!drvdata)
 		return -ENOMEM;
@@ -251,9 +375,6 @@ static int replicator_probe(struct device *dev, struct resource *res)
 		if (IS_ERR(base))
 			return PTR_ERR(base);
 		drvdata->base = base;
-		desc.groups = replicator_groups;
-		desc.access = CSDEV_ACCESS_IOMEM(base);
-		coresight_clear_self_claim_tag(&desc.access);
 	}
 
 	if (fwnode_property_present(dev_fwnode(dev),
@@ -268,25 +389,38 @@ static int replicator_probe(struct device *dev, struct resource *res)
 	dev->platform_data = pdata;
 
 	raw_spin_lock_init(&drvdata->spinlock);
-	desc.type = CORESIGHT_DEV_TYPE_LINK;
-	desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
-	desc.ops = &replicator_cs_ops;
-	desc.pdata = dev->platform_data;
-	desc.dev = dev;
 
-	drvdata->csdev = coresight_register(&desc);
-	if (IS_ERR(drvdata->csdev))
-		return PTR_ERR(drvdata->csdev);
+	if (fwnode_property_present(dev_fwnode(dev), "qcom,cpu-bound-components")) {
+		drvdata->supported_cpus = replicator_get_supported_cpus(dev);
+		if (!drvdata->supported_cpus)
+			return -EINVAL;
+
+		cpus_read_lock();
+		for_each_cpu(cpu, drvdata->supported_cpus) {
+			ret = smp_call_function_single(cpu,
+						       replicator_init_on_cpu, drvdata, 1);
+			if (!ret)
+				break;
+		}
+		cpus_read_unlock();
 
-	replicator_reset(drvdata);
-	return 0;
+		if (ret)
+			return 0;
+	} else if (res) {
+		replicator_init_hw(drvdata);
+	}
+
+	ret = replicator_add_coresight_dev(dev);
+
+	return ret;
 }
 
 static int replicator_remove(struct device *dev)
 {
 	struct replicator_drvdata *drvdata = dev_get_drvdata(dev);
 
-	coresight_unregister(drvdata->csdev);
+	if (drvdata->csdev)
+		coresight_unregister(drvdata->csdev);
 	return 0;
 }
 

-- 
2.34.1



From yuanfang.zhang at oss.qualcomm.com  Thu Dec 18 00:09:45 2025
From: yuanfang.zhang at oss.qualcomm.com (Yuanfang Zhang)
Date: Thu, 18 Dec 2025 00:09:45 -0800
Subject: [PATCH v2 05/12] coresight-replicator: Defer probe when associated
 CPUs are offline
In-Reply-To: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
References: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
Message-ID: <20251218-cpu_cluster_component_pm-v2-5-2335a6ae62a0@oss.qualcomm.com>

Per-cluster replicators rely on the associated CPU cluster being online
to securely access registers during initialization. If all CPUs in the
cluster are offline during probe, these operations fail.

Support deferred initialization for these devices:
1. Track replicators that fail to probe due to offline CPUs in a global
   list.
2. Register a CPU hotplug notifier (`replicator_online_cpu`) to detect
   when a relevant CPU comes online.
3. Upon CPU online, retry the hardware initialization and registration
   with the CoreSight framework.

Signed-off-by: Yuanfang Zhang <yuanfang.zhang at oss.qualcomm.com>
---
 drivers/hwtracing/coresight/coresight-replicator.c | 65 ++++++++++++++++++++--
 1 file changed, 61 insertions(+), 4 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c
index c11da452559c73af6709b39d03b646cb4779736f..f8d13894098f1e414fb0da8d6eeb1da4f0d55a8c 100644
--- a/drivers/hwtracing/coresight/coresight-replicator.c
+++ b/drivers/hwtracing/coresight/coresight-replicator.c
@@ -26,6 +26,9 @@
 #define REPLICATOR_IDFILTER1		0x004
 
 DEFINE_CORESIGHT_DEVLIST(replicator_devs, "replicator");
+static LIST_HEAD(replicator_delay_probe);
+static enum cpuhp_state hp_online;
+static DEFINE_SPINLOCK(delay_lock);
 
 /**
  * struct replicator_drvdata - specifics associated to a replicator component
@@ -37,6 +40,8 @@ DEFINE_CORESIGHT_DEVLIST(replicator_devs, "replicator");
  * @spinlock:	serialize enable/disable operations.
  * @check_idfilter_val: check if the context is lost upon clock removal.
  * @supported_cpus:	Represent the CPUs related to this funnel.
+ * @dev:	pointer to the device associated with this replicator.
+ * @link:	link to the delay_probed list.
  */
 struct replicator_drvdata {
 	void __iomem		*base;
@@ -46,6 +51,8 @@ struct replicator_drvdata {
 	raw_spinlock_t		spinlock;
 	bool			check_idfilter_val;
 	struct cpumask		*supported_cpus;
+	struct device		*dev;
+	struct list_head	link;
 };
 
 struct replicator_smp_arg {
@@ -394,7 +401,7 @@ static int replicator_probe(struct device *dev, struct resource *res)
 		drvdata->supported_cpus = replicator_get_supported_cpus(dev);
 		if (!drvdata->supported_cpus)
 			return -EINVAL;
-
+		drvdata->dev = dev;
 		cpus_read_lock();
 		for_each_cpu(cpu, drvdata->supported_cpus) {
 			ret = smp_call_function_single(cpu,
@@ -402,10 +409,15 @@ static int replicator_probe(struct device *dev, struct resource *res)
 			if (!ret)
 				break;
 		}
-		cpus_read_unlock();
 
-		if (ret)
+		if (ret) {
+			scoped_guard(spinlock,  &delay_lock)
+				list_add(&drvdata->link, &replicator_delay_probe);
+			cpus_read_unlock();
 			return 0;
+		}
+
+		cpus_read_unlock();
 	} else if (res) {
 		replicator_init_hw(drvdata);
 	}
@@ -419,8 +431,13 @@ static int replicator_remove(struct device *dev)
 {
 	struct replicator_drvdata *drvdata = dev_get_drvdata(dev);
 
-	if (drvdata->csdev)
+	if (drvdata->csdev) {
 		coresight_unregister(drvdata->csdev);
+	} else {
+		scoped_guard(spinlock,  &delay_lock)
+			list_del(&drvdata->link);
+	}
+
 	return 0;
 }
 
@@ -552,8 +569,44 @@ static struct amba_driver dynamic_replicator_driver = {
 	.id_table	= dynamic_replicator_ids,
 };
 
+static int replicator_online_cpu(unsigned int cpu)
+{
+	struct replicator_drvdata *drvdata, *tmp;
+	int ret;
+
+	spin_lock(&delay_lock);
+	list_for_each_entry_safe(drvdata, tmp, &replicator_delay_probe, link) {
+		if (cpumask_test_cpu(cpu, drvdata->supported_cpus)) {
+			list_del(&drvdata->link);
+			spin_unlock(&delay_lock);
+			ret = pm_runtime_resume_and_get(drvdata->dev);
+			if (ret < 0)
+				return 0;
+
+			replicator_clear_self_claim_tag(drvdata);
+			replicator_reset(drvdata);
+			replicator_add_coresight_dev(drvdata->dev);
+			pm_runtime_put(drvdata->dev);
+			spin_lock(&delay_lock);
+		}
+	}
+	spin_unlock(&delay_lock);
+	return 0;
+}
+
 static int __init replicator_init(void)
 {
+	int ret;
+
+	ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
+					"arm/coresight-replicator:online",
+					replicator_online_cpu, NULL);
+
+	if (ret > 0)
+		hp_online = ret;
+	else
+		return ret;
+
 	return coresight_init_driver("replicator", &dynamic_replicator_driver, &replicator_driver,
 				     THIS_MODULE);
 }
@@ -561,6 +614,10 @@ static int __init replicator_init(void)
 static void __exit replicator_exit(void)
 {
 	coresight_remove_driver(&dynamic_replicator_driver, &replicator_driver);
+	if (hp_online) {
+		cpuhp_remove_state_nocalls(hp_online);
+		hp_online = 0;
+	}
 }
 
 module_init(replicator_init);

-- 
2.34.1



From yuanfang.zhang at oss.qualcomm.com  Thu Dec 18 00:09:46 2025
From: yuanfang.zhang at oss.qualcomm.com (Yuanfang Zhang)
Date: Thu, 18 Dec 2025 00:09:46 -0800
Subject: [PATCH v2 06/12] coresight-replicator: Update management interface
 for CPU-bound devices
In-Reply-To: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
References: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
Message-ID: <20251218-cpu_cluster_component_pm-v2-6-2335a6ae62a0@oss.qualcomm.com>

Standard system replicators allow direct register access from any CPU.
However, replicators associated with specific CPU clusters share the
cluster's power domain and require access via a CPU within that domain.

Replace the standard `coresight_simple_reg*` accessors with custom
handlers (`coresight_replicator_reg*`) to support these devices:
- For cluster-bound replicators (indicated by `supported_cpus`), use
  `smp_call_function_single()` to read registers on an associated CPU.
- For standard replicators, retain the direct access behavior.

This ensures correct operation for per-cluster replicators while
maintaining compatibility for existing system-level devices.

Signed-off-by: Yuanfang Zhang <yuanfang.zhang at oss.qualcomm.com>
---
 drivers/hwtracing/coresight/coresight-replicator.c | 61 +++++++++++++++++++++-
 1 file changed, 59 insertions(+), 2 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c
index f8d13894098f1e414fb0da8d6eeb1da4f0d55a8c..a9f22d0e15de21aa06c8d1e193e5db06091efd75 100644
--- a/drivers/hwtracing/coresight/coresight-replicator.c
+++ b/drivers/hwtracing/coresight/coresight-replicator.c
@@ -58,6 +58,7 @@ struct replicator_drvdata {
 struct replicator_smp_arg {
 	struct replicator_drvdata *drvdata;
 	int outport;
+	u32 offset;
 	int rc;
 };
 
@@ -286,9 +287,65 @@ static const struct coresight_ops replicator_cs_ops = {
 	.link_ops	= &replicator_link_ops,
 };
 
+static void replicator_read_register_smp_call(void *info)
+{
+	struct replicator_smp_arg *arg = info;
+
+	arg->rc = readl_relaxed(arg->drvdata->base + arg->offset);
+}
+
+static ssize_t coresight_replicator_reg32_show(struct device *dev,
+					       struct device_attribute *attr,
+					       char *buf)
+{
+	struct replicator_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	struct cs_off_attribute *cs_attr = container_of(attr, struct cs_off_attribute, attr);
+	unsigned long flags;
+	struct replicator_smp_arg arg = { 0 };
+	u32 val;
+	int ret, cpu;
+
+	pm_runtime_get_sync(dev->parent);
+
+	if (!drvdata->supported_cpus) {
+		raw_spin_lock_irqsave(&drvdata->spinlock, flags);
+		val = readl_relaxed(drvdata->base + cs_attr->off);
+		raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	} else {
+		arg.drvdata = drvdata;
+		arg.offset = cs_attr->off;
+		for_each_cpu(cpu, drvdata->supported_cpus) {
+			ret = smp_call_function_single(cpu,
+						       replicator_read_register_smp_call,
+						       &arg, 1);
+			if (!ret)
+				break;
+		}
+		if (!ret) {
+			val = arg.rc;
+		} else {
+			pm_runtime_put_sync(dev->parent);
+			return ret;
+		}
+	}
+
+	pm_runtime_put_sync(dev->parent);
+
+	return sysfs_emit(buf, "0x%x\n", val);
+}
+
+#define coresight_replicator_reg32(name, offset)				\
+	(&((struct cs_off_attribute[]) {				\
+	   {								\
+		__ATTR(name, 0444, coresight_replicator_reg32_show, NULL),	\
+		offset							\
+	   }								\
+	})[0].attr.attr)
+
 static struct attribute *replicator_mgmt_attrs[] = {
-	coresight_simple_reg32(idfilter0, REPLICATOR_IDFILTER0),
-	coresight_simple_reg32(idfilter1, REPLICATOR_IDFILTER1),
+	coresight_replicator_reg32(idfilter0, REPLICATOR_IDFILTER0),
+	coresight_replicator_reg32(idfilter1, REPLICATOR_IDFILTER1),
 	NULL,
 };
 

-- 
2.34.1



From yuanfang.zhang at oss.qualcomm.com  Thu Dec 18 00:09:48 2025
From: yuanfang.zhang at oss.qualcomm.com (Yuanfang Zhang)
Date: Thu, 18 Dec 2025 00:09:48 -0800
Subject: [PATCH v2 08/12] coresight-tmc-etf: Refactor enable function for
 CPU cluster ETF support
In-Reply-To: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
References: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
Message-ID: <20251218-cpu_cluster_component_pm-v2-8-2335a6ae62a0@oss.qualcomm.com>

TMC-ETF devices associated with specific CPU clusters share the cluster's
power domain. Accessing their registers requires the cluster to be powered
on, which can only be guaranteed by running code on a CPU within that
cluster.

Refactor the enablement logic to support this requirement:
1. Split `tmc_etf_enable_hw` and `tmc_etb_enable_hw` into local and
   SMP-aware variants:
   - `*_local`: Performs the actual register access.
   - `*_smp_call`: Wrapper for `smp_call_function_single`.
   - The main entry point now detects if the device is CPU-bound and uses
     `smp_call_function_single` to execute the local variant on an
     appropriate CPU if necessary.

2. Adjust locking in `tmc_enable_etf_sink_sysfs` and `tmc_enable_etf_link`:
   - Drop the spinlock before calling `tmc_etf_enable_hw`. This is
     necessary because `smp_call_function_single` (used for cross-CPU
     calls) may require interrupts enabled or might sleep/wait, which is
     unsafe under a spinlock.
   - Re-acquire the lock afterwards to update driver state.

Signed-off-by: Yuanfang Zhang <yuanfang.zhang at oss.qualcomm.com>
---
 drivers/hwtracing/coresight/coresight-tmc-etf.c | 87 ++++++++++++++++++++++---
 1 file changed, 77 insertions(+), 10 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index 8882b1c4cdc05353fb2efd6a9ba862943048f0ff..11357788e9d93c53980e99e0ef78450e393f4059 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -47,7 +47,7 @@ static int __tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
 	return rc;
 }
 
-static int tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
+static int tmc_etb_enable_hw_local(struct tmc_drvdata *drvdata)
 {
 	int rc = coresight_claim_device(drvdata->csdev);
 
@@ -60,6 +60,36 @@ static int tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
 	return rc;
 }
 
+struct tmc_smp_arg {
+	struct tmc_drvdata *drvdata;
+	int rc;
+};
+
+static void tmc_etb_enable_hw_smp_call(void *info)
+{
+	struct tmc_smp_arg *arg = info;
+
+	arg->rc = tmc_etb_enable_hw_local(arg->drvdata);
+}
+
+static int tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
+{
+	int cpu, ret;
+	struct tmc_smp_arg arg = { 0 };
+
+	if (!drvdata->supported_cpus)
+		return tmc_etb_enable_hw_local(drvdata);
+
+	arg.drvdata = drvdata;
+	for_each_cpu(cpu, drvdata->supported_cpus) {
+		ret = smp_call_function_single(cpu,
+					       tmc_etb_enable_hw_smp_call, &arg, 1);
+		if (!ret)
+			return arg.rc;
+	}
+	return ret;
+}
+
 static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata)
 {
 	char *bufp;
@@ -130,7 +160,7 @@ static int __tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
 	return rc;
 }
 
-static int tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
+static int tmc_etf_enable_hw_local(struct tmc_drvdata *drvdata)
 {
 	int rc = coresight_claim_device(drvdata->csdev);
 
@@ -143,6 +173,32 @@ static int tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
 	return rc;
 }
 
+static void tmc_etf_enable_hw_smp_call(void *info)
+{
+	struct tmc_smp_arg *arg = info;
+
+	arg->rc = tmc_etf_enable_hw_local(arg->drvdata);
+}
+
+static int tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
+{
+	int cpu, ret;
+	struct tmc_smp_arg arg = { 0 };
+
+	if (!drvdata->supported_cpus)
+		return tmc_etf_enable_hw_local(drvdata);
+
+	arg.drvdata = drvdata;
+
+	for_each_cpu(cpu, drvdata->supported_cpus) {
+		ret = smp_call_function_single(cpu,
+					       tmc_etf_enable_hw_smp_call, &arg, 1);
+		if (!ret)
+			return arg.rc;
+	}
+	return ret;
+}
+
 static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata)
 {
 	struct coresight_device *csdev = drvdata->csdev;
@@ -228,7 +284,11 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev)
 		used = true;
 		drvdata->buf = buf;
 	}
+	raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
 	ret = tmc_etb_enable_hw(drvdata);
+
+	raw_spin_lock_irqsave(&drvdata->spinlock, flags);
 	if (!ret) {
 		coresight_set_mode(csdev, CS_MODE_SYSFS);
 		csdev->refcnt++;
@@ -291,7 +351,11 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev,
 			break;
 		}
 
-		ret  = tmc_etb_enable_hw(drvdata);
+		if (drvdata->supported_cpus &&
+		    !cpumask_test_cpu(smp_processor_id(), drvdata->supported_cpus))
+			break;
+
+		ret  = tmc_etb_enable_hw_local(drvdata);
 		if (!ret) {
 			/* Associate with monitored process. */
 			drvdata->pid = pid;
@@ -376,19 +440,22 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
 		return -EBUSY;
 	}
 
-	if (csdev->refcnt == 0) {
+	if (csdev->refcnt == 0)
+		first_enable = true;
+
+	if (!first_enable)
+		csdev->refcnt++;
+
+	raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+	if (first_enable) {
 		ret = tmc_etf_enable_hw(drvdata);
 		if (!ret) {
 			coresight_set_mode(csdev, CS_MODE_SYSFS);
-			first_enable = true;
+			csdev->refcnt++;
+			dev_dbg(&csdev->dev, "TMC-ETF enabled\n");
 		}
 	}
-	if (!ret)
-		csdev->refcnt++;
-	raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
-	if (first_enable)
-		dev_dbg(&csdev->dev, "TMC-ETF enabled\n");
 	return ret;
 }
 

-- 
2.34.1



From yuanfang.zhang at oss.qualcomm.com  Thu Dec 18 00:09:47 2025
From: yuanfang.zhang at oss.qualcomm.com (Yuanfang Zhang)
Date: Thu, 18 Dec 2025 00:09:47 -0800
Subject: [PATCH v2 07/12] coresight-tmc: Support probe and initialization
 for CPU cluster TMCs
In-Reply-To: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
References: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
Message-ID: <20251218-cpu_cluster_component_pm-v2-7-2335a6ae62a0@oss.qualcomm.com>

TMC instances associated with CPU clusters reside in the cluster's power
domain. Unlike system-level TMCs, their registers are only accessible
when the cluster is powered on. Standard runtime PM may not suffice to
wake up a cluster from low-power states during probe, making direct
register access unreliable.

Refactor the probe sequence to handle these per-cluster devices safely:

1. Identify per-cluster TMCs using the "qcom,cpu-bound-components"
   property.
2. For such devices, use `smp_call_function_single()` to perform
   hardware initialization (`tmc_init_hw_config`) on a CPU within the
   cluster. This ensures the domain is powered during access.
3. Factor out the device registration logic into `tmc_add_coresight_dev()`.
   This allows common registration code to be shared between the standard
   probe path and the deferred probe path (used when the associated CPUs
   are initially offline).

This change ensures reliable initialization for per-cluster TMCs while
maintaining backward compatibility for standard system-level TMCs.

Signed-off-by: Yuanfang Zhang <yuanfang.zhang at oss.qualcomm.com>
---
 drivers/hwtracing/coresight/coresight-tmc-core.c | 195 +++++++++++++++--------
 drivers/hwtracing/coresight/coresight-tmc.h      |   6 +
 2 files changed, 132 insertions(+), 69 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c
index 36599c431be6203e871fdcb8de569cc6701c52bb..0e1b5956398d3cefdd938a8a8404076eb4850b44 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-core.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-core.c
@@ -21,6 +21,7 @@
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
 #include <linux/spinlock.h>
+#include <linux/pm_domain.h>
 #include <linux/pm_runtime.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
@@ -769,56 +770,14 @@ static void register_crash_dev_interface(struct tmc_drvdata *drvdata,
 			"Valid crash tracedata found\n");
 }
 
-static int __tmc_probe(struct device *dev, struct resource *res)
+static int tmc_add_coresight_dev(struct device *dev)
 {
-	int ret = 0;
-	u32 devid;
-	void __iomem *base;
-	struct coresight_platform_data *pdata = NULL;
-	struct tmc_drvdata *drvdata;
+	struct tmc_drvdata *drvdata = dev_get_drvdata(dev);
 	struct coresight_desc desc = { 0 };
 	struct coresight_dev_list *dev_list = NULL;
+	int ret = 0;
 
-	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
-	if (!drvdata)
-		return -ENOMEM;
-
-	dev_set_drvdata(dev, drvdata);
-
-	ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk);
-	if (ret)
-		return ret;
-
-	ret = -ENOMEM;
-
-	/* Validity for the resource is already checked by the AMBA core */
-	base = devm_ioremap_resource(dev, res);
-	if (IS_ERR(base)) {
-		ret = PTR_ERR(base);
-		goto out;
-	}
-
-	drvdata->base = base;
-	desc.access = CSDEV_ACCESS_IOMEM(base);
-
-	raw_spin_lock_init(&drvdata->spinlock);
-
-	devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID);
-	drvdata->config_type = BMVAL(devid, 6, 7);
-	drvdata->memwidth = tmc_get_memwidth(devid);
-	/* This device is not associated with a session */
-	drvdata->pid = -1;
-	drvdata->etr_mode = ETR_MODE_AUTO;
-
-	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
-		drvdata->size = tmc_etr_get_default_buffer_size(dev);
-		drvdata->max_burst_size = tmc_etr_get_max_burst_size(dev);
-	} else {
-		drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4;
-	}
-
-	tmc_get_reserved_region(dev);
-
+	desc.access = CSDEV_ACCESS_IOMEM(drvdata->base);
 	desc.dev = dev;
 
 	switch (drvdata->config_type) {
@@ -834,9 +793,9 @@ static int __tmc_probe(struct device *dev, struct resource *res)
 		desc.type = CORESIGHT_DEV_TYPE_SINK;
 		desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_SYSMEM;
 		desc.ops = &tmc_etr_cs_ops;
-		ret = tmc_etr_setup_caps(dev, devid, &desc.access);
+		ret = tmc_etr_setup_caps(dev, drvdata->devid, &desc.access);
 		if (ret)
-			goto out;
+			return ret;
 		idr_init(&drvdata->idr);
 		mutex_init(&drvdata->idr_mutex);
 		dev_list = &etr_devs;
@@ -851,44 +810,141 @@ static int __tmc_probe(struct device *dev, struct resource *res)
 		break;
 	default:
 		pr_err("%s: Unsupported TMC config\n", desc.name);
-		ret = -EINVAL;
-		goto out;
+		return -EINVAL;
 	}
 
 	desc.name = coresight_alloc_device_name(dev_list, dev);
-	if (!desc.name) {
-		ret = -ENOMEM;
+	if (!desc.name)
+		return -ENOMEM;
+
+	drvdata->desc_name = desc.name;
+
+	desc.pdata = dev->platform_data;
+
+	drvdata->csdev = coresight_register(&desc);
+	if (IS_ERR(drvdata->csdev))
+		return PTR_ERR(drvdata->csdev);
+
+	drvdata->miscdev.name = desc.name;
+	drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
+	drvdata->miscdev.fops = &tmc_fops;
+	ret = misc_register(&drvdata->miscdev);
+	if (ret)
+		coresight_unregister(drvdata->csdev);
+
+	return ret;
+}
+
+static void tmc_clear_self_claim_tag(struct tmc_drvdata *drvdata)
+{
+	struct csdev_access access = CSDEV_ACCESS_IOMEM(drvdata->base);
+
+	coresight_clear_self_claim_tag(&access);
+}
+
+static void tmc_init_hw_config(struct tmc_drvdata *drvdata)
+{
+	u32 devid;
+
+	devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID);
+	drvdata->config_type = BMVAL(devid, 6, 7);
+	drvdata->memwidth = tmc_get_memwidth(devid);
+	drvdata->devid = devid;
+	drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4;
+	tmc_clear_self_claim_tag(drvdata);
+}
+
+static void tmc_init_on_cpu(void *info)
+{
+	struct tmc_drvdata *drvdata = info;
+
+	tmc_init_hw_config(drvdata);
+}
+
+static struct cpumask *tmc_get_supported_cpus(struct device *dev)
+{
+	struct generic_pm_domain *pd;
+
+	pd = pd_to_genpd(dev->pm_domain);
+	if (pd)
+		return pd->cpus;
+
+	return NULL;
+}
+
+static int __tmc_probe(struct device *dev, struct resource *res)
+{
+	int cpu, ret = 0;
+	void __iomem *base;
+	struct coresight_platform_data *pdata = NULL;
+	struct tmc_drvdata *drvdata;
+
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, drvdata);
+
+	ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk);
+	if (ret)
+		return ret;
+
+	ret = -ENOMEM;
+
+	/* Validity for the resource is already checked by the AMBA core */
+	base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(base)) {
+		ret = PTR_ERR(base);
 		goto out;
 	}
 
+	drvdata->base = base;
+
+	raw_spin_lock_init(&drvdata->spinlock);
+	/* This device is not associated with a session */
+	drvdata->pid = -1;
+	drvdata->etr_mode = ETR_MODE_AUTO;
+	tmc_get_reserved_region(dev);
+
 	pdata = coresight_get_platform_data(dev);
 	if (IS_ERR(pdata)) {
 		ret = PTR_ERR(pdata);
 		goto out;
 	}
 	dev->platform_data = pdata;
-	desc.pdata = pdata;
 
-	coresight_clear_self_claim_tag(&desc.access);
-	drvdata->csdev = coresight_register(&desc);
-	if (IS_ERR(drvdata->csdev)) {
-		ret = PTR_ERR(drvdata->csdev);
-		goto out;
+	if (fwnode_property_present(dev_fwnode(dev), "qcom,cpu-bound-components")) {
+		drvdata->supported_cpus = tmc_get_supported_cpus(dev);
+		if (!drvdata->supported_cpus)
+			return -EINVAL;
+
+		cpus_read_lock();
+		for_each_cpu(cpu, drvdata->supported_cpus) {
+			ret = smp_call_function_single(cpu,
+						       tmc_init_on_cpu, drvdata, 1);
+			if (!ret)
+				break;
+		}
+		cpus_read_unlock();
+		if (ret) {
+			ret = 0;
+			goto out;
+		}
+	} else {
+		tmc_init_hw_config(drvdata);
 	}
 
-	drvdata->miscdev.name = desc.name;
-	drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
-	drvdata->miscdev.fops = &tmc_fops;
-	ret = misc_register(&drvdata->miscdev);
-	if (ret) {
-		coresight_unregister(drvdata->csdev);
-		goto out;
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+		drvdata->size = tmc_etr_get_default_buffer_size(dev);
+		drvdata->max_burst_size = tmc_etr_get_max_burst_size(dev);
 	}
 
+	ret = tmc_add_coresight_dev(dev);
+
 out:
 	if (is_tmc_crashdata_valid(drvdata) &&
 	    !tmc_prepare_crashdata(drvdata))
-		register_crash_dev_interface(drvdata, desc.name);
+		register_crash_dev_interface(drvdata, drvdata->desc_name);
 	return ret;
 }
 
@@ -934,10 +990,12 @@ static void __tmc_remove(struct device *dev)
 	 * etb fops in this case, device is there until last file
 	 * handler to this device is closed.
 	 */
-	misc_deregister(&drvdata->miscdev);
+	if (!drvdata->supported_cpus)
+		misc_deregister(&drvdata->miscdev);
 	if (drvdata->crashdev.fops)
 		misc_deregister(&drvdata->crashdev);
-	coresight_unregister(drvdata->csdev);
+	if (drvdata->csdev)
+		coresight_unregister(drvdata->csdev);
 }
 
 static void tmc_remove(struct amba_device *adev)
@@ -992,7 +1050,6 @@ static void tmc_platform_remove(struct platform_device *pdev)
 
 	if (WARN_ON(!drvdata))
 		return;
-
 	__tmc_remove(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 }
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 95473d1310323425b7d136cbd46f118faa7256be..b104b7bf82d2a7a99382636e41d3718cf258d820 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -243,6 +243,9 @@ struct tmc_resrv_buf {
  *		(after crash) by default.
  * @crash_mdata: Reserved memory for storing tmc crash metadata.
  *		 Used by ETR/ETF.
+ * @supported_cpus:	Represent the CPUs related to this TMC.
+ * @devid:	TMC variant ID inferred from the device configuration register.
+ * @desc_name:	Name to be used while creating crash interface.
  */
 struct tmc_drvdata {
 	struct clk		*atclk;
@@ -273,6 +276,9 @@ struct tmc_drvdata {
 	struct etr_buf		*perf_buf;
 	struct tmc_resrv_buf	resrv_buf;
 	struct tmc_resrv_buf	crash_mdata;
+	struct cpumask		*supported_cpus;
+	u32			devid;
+	const char		*desc_name;
 };
 
 struct etr_buf_operations {

-- 
2.34.1



From yuanfang.zhang at oss.qualcomm.com  Thu Dec 18 00:09:49 2025
From: yuanfang.zhang at oss.qualcomm.com (Yuanfang Zhang)
Date: Thu, 18 Dec 2025 00:09:49 -0800
Subject: [PATCH v2 09/12] coresight-tmc: Update management interface for
 CPU-bound TMCs
In-Reply-To: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
References: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
Message-ID: <20251218-cpu_cluster_component_pm-v2-9-2335a6ae62a0@oss.qualcomm.com>

The current TMC management interface (sysfs attributes) assumes that
device registers can be accessed directly from any CPU. However, for
TMCs associated with specific CPU clusters, registers must be accessed
from a CPU within that cluster.

Replace the standard `coresight_simple_reg*` handlers with custom
accessors (`coresight_tmc_reg*`). These new handlers check if the TMC
is bound to a specific set of CPUs:
- If bound, they use `smp_call_function_single()` to read the register
  on an appropriate CPU.
- If not bound (global TMC), they fall back to direct access.

This ensures correct register reads for per-cluster TMC devices while
maintaining backward compatibility for global TMCs.

Signed-off-by: Yuanfang Zhang <yuanfang.zhang at oss.qualcomm.com>
---
 drivers/hwtracing/coresight/coresight-tmc-core.c | 137 ++++++++++++++++++++---
 1 file changed, 123 insertions(+), 14 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c
index 0e1b5956398d3cefdd938a8a8404076eb4850b44..5b9f2e57c78f42f0f1460d8a8dcbac72b5f6085e 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-core.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-core.c
@@ -458,21 +458,130 @@ static enum tmc_mem_intf_width tmc_get_memwidth(u32 devid)
 	return memwidth;
 }
 
+struct tmc_smp_arg {
+	struct tmc_drvdata *drvdata;
+	u32 offset;
+	int rc;
+};
+
+static void tmc_read_reg_smp_call(void *info)
+{
+	struct tmc_smp_arg *arg = info;
+
+	arg->rc = readl_relaxed(arg->drvdata->base + arg->offset);
+}
+
+static u32 cpu_tmc_read_reg(struct tmc_drvdata *drvdata, u32 offset)
+{
+	struct tmc_smp_arg arg = {
+		.drvdata = drvdata,
+		.offset = offset,
+	};
+	int cpu, ret = 0;
+
+	for_each_cpu(cpu, drvdata->supported_cpus) {
+		ret = smp_call_function_single(cpu,
+					       tmc_read_reg_smp_call, &arg, 1);
+		if (!ret)
+			return arg.rc;
+	}
+
+	return ret;
+}
+
+static ssize_t coresight_tmc_reg32_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	struct cs_off_attribute *cs_attr = container_of(attr, struct cs_off_attribute, attr);
+	int ret;
+	u32 val;
+
+	ret = pm_runtime_resume_and_get(dev->parent);
+	if (ret < 0)
+		return ret;
+
+	if (!drvdata->supported_cpus)
+		val = readl_relaxed(drvdata->base + cs_attr->off);
+	else
+		val = cpu_tmc_read_reg(drvdata, cs_attr->off);
+
+	pm_runtime_put(dev->parent);
+
+	if (ret < 0)
+		return ret;
+	else
+		return sysfs_emit(buf, "0x%x\n", val);
+}
+
+static ssize_t coresight_tmc_reg64_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	struct cs_pair_attribute *cs_attr = container_of(attr, struct cs_pair_attribute, attr);
+	int ret;
+	u64 val;
+
+	ret = pm_runtime_resume_and_get(dev->parent);
+	if (ret < 0)
+		return ret;
+	if (!drvdata->supported_cpus) {
+		val = readl_relaxed(drvdata->base + cs_attr->lo_off) |
+			((u64)readl_relaxed(drvdata->base + cs_attr->hi_off) << 32);
+	} else {
+		ret = cpu_tmc_read_reg(drvdata, cs_attr->lo_off);
+
+		if (ret < 0)
+			goto out;
+
+		val = ret;
+
+		ret = cpu_tmc_read_reg(drvdata, cs_attr->hi_off);
+		if (ret < 0)
+			goto out;
+
+		val |= ((u64)ret << 32);
+	}
+
+out:
+	pm_runtime_put_sync(dev->parent);
+	if (ret < 0)
+		return ret;
+	else
+		return sysfs_emit(buf, "0x%llx\n", val);
+}
+
+#define coresight_tmc_reg32(name, offset)				\
+	(&((struct cs_off_attribute[]) {				\
+	   {								\
+		__ATTR(name, 0444, coresight_tmc_reg32_show, NULL),	\
+		offset							\
+	   }								\
+	})[0].attr.attr)
+#define coresight_tmc_reg64(name, lo_off, hi_off)			\
+	(&((struct cs_pair_attribute[]) {				\
+	   {								\
+		__ATTR(name, 0444, coresight_tmc_reg64_show, NULL),	\
+		lo_off, hi_off						\
+	   }								\
+	})[0].attr.attr)
 static struct attribute *coresight_tmc_mgmt_attrs[] = {
-	coresight_simple_reg32(rsz, TMC_RSZ),
-	coresight_simple_reg32(sts, TMC_STS),
-	coresight_simple_reg64(rrp, TMC_RRP, TMC_RRPHI),
-	coresight_simple_reg64(rwp, TMC_RWP, TMC_RWPHI),
-	coresight_simple_reg32(trg, TMC_TRG),
-	coresight_simple_reg32(ctl, TMC_CTL),
-	coresight_simple_reg32(ffsr, TMC_FFSR),
-	coresight_simple_reg32(ffcr, TMC_FFCR),
-	coresight_simple_reg32(mode, TMC_MODE),
-	coresight_simple_reg32(pscr, TMC_PSCR),
-	coresight_simple_reg32(devid, CORESIGHT_DEVID),
-	coresight_simple_reg64(dba, TMC_DBALO, TMC_DBAHI),
-	coresight_simple_reg32(axictl, TMC_AXICTL),
-	coresight_simple_reg32(authstatus, TMC_AUTHSTATUS),
+	coresight_tmc_reg32(rsz, TMC_RSZ),
+	coresight_tmc_reg32(sts, TMC_STS),
+	coresight_tmc_reg64(rrp, TMC_RRP, TMC_RRPHI),
+	coresight_tmc_reg64(rwp, TMC_RWP, TMC_RWPHI),
+	coresight_tmc_reg32(trg, TMC_TRG),
+	coresight_tmc_reg32(ctl, TMC_CTL),
+	coresight_tmc_reg32(ffsr, TMC_FFSR),
+	coresight_tmc_reg32(ffcr, TMC_FFCR),
+	coresight_tmc_reg32(mode, TMC_MODE),
+	coresight_tmc_reg32(pscr, TMC_PSCR),
+	coresight_tmc_reg32(devid, CORESIGHT_DEVID),
+	coresight_tmc_reg64(dba, TMC_DBALO, TMC_DBAHI),
+	coresight_tmc_reg32(axictl, TMC_AXICTL),
+	coresight_tmc_reg32(authstatus, TMC_AUTHSTATUS),
 	NULL,
 };
 

-- 
2.34.1



From yuanfang.zhang at oss.qualcomm.com  Thu Dec 18 00:09:50 2025
From: yuanfang.zhang at oss.qualcomm.com (Yuanfang Zhang)
Date: Thu, 18 Dec 2025 00:09:50 -0800
Subject: [PATCH v2 10/12] coresight-tmc: Defer probe when associated CPUs
 are offline
In-Reply-To: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
References: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
Message-ID: <20251218-cpu_cluster_component_pm-v2-10-2335a6ae62a0@oss.qualcomm.com>

On some platforms, the TMC driver may probe before the associated CPUs
are online. This prevents the driver from securely accessing the
hardware or configuring it via smp_call_function_single(), which
requires the target CPU to be available.

To address this, defer the hardware initialization if the associated
CPUs are offline:
1. Track such deferred devices in a global list.
2. Register a CPU hotplug callback (`tmc_online_cpu`) to detect when
   a relevant CPU comes online.
3. Upon CPU online, retry the hardware initialization and registration
   for the waiting TMC devices.

Signed-off-by: Yuanfang Zhang <yuanfang.zhang at oss.qualcomm.com>
---
 drivers/hwtracing/coresight/coresight-tmc-core.c | 59 +++++++++++++++++++++++-
 drivers/hwtracing/coresight/coresight-tmc.h      |  4 ++
 2 files changed, 61 insertions(+), 2 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c
index 5b9f2e57c78f42f0f1460d8a8dcbac72b5f6085e..9182fa8e4074a7c9739494b2f5d59be2e96f1d3d 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-core.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-core.c
@@ -36,6 +36,9 @@
 DEFINE_CORESIGHT_DEVLIST(etb_devs, "tmc_etb");
 DEFINE_CORESIGHT_DEVLIST(etf_devs, "tmc_etf");
 DEFINE_CORESIGHT_DEVLIST(etr_devs, "tmc_etr");
+static LIST_HEAD(tmc_delay_probe);
+static enum cpuhp_state hp_online;
+static DEFINE_SPINLOCK(delay_lock);
 
 int tmc_wait_for_tmcready(struct tmc_drvdata *drvdata)
 {
@@ -1027,6 +1030,8 @@ static int __tmc_probe(struct device *dev, struct resource *res)
 		if (!drvdata->supported_cpus)
 			return -EINVAL;
 
+		drvdata->dev = dev;
+
 		cpus_read_lock();
 		for_each_cpu(cpu, drvdata->supported_cpus) {
 			ret = smp_call_function_single(cpu,
@@ -1034,11 +1039,16 @@ static int __tmc_probe(struct device *dev, struct resource *res)
 			if (!ret)
 				break;
 		}
-		cpus_read_unlock();
+
 		if (ret) {
+			scoped_guard(spinlock,  &delay_lock)
+				list_add(&drvdata->link, &tmc_delay_probe);
+			cpus_read_unlock();
 			ret = 0;
 			goto out;
 		}
+
+		cpus_read_unlock();
 	} else {
 		tmc_init_hw_config(drvdata);
 	}
@@ -1103,8 +1113,12 @@ static void __tmc_remove(struct device *dev)
 		misc_deregister(&drvdata->miscdev);
 	if (drvdata->crashdev.fops)
 		misc_deregister(&drvdata->crashdev);
-	if (drvdata->csdev)
+	if (drvdata->csdev) {
 		coresight_unregister(drvdata->csdev);
+	} else {
+		scoped_guard(spinlock,  &delay_lock)
+			list_del(&drvdata->link);
+	}
 }
 
 static void tmc_remove(struct amba_device *adev)
@@ -1215,14 +1229,55 @@ static struct platform_driver tmc_platform_driver = {
 	},
 };
 
+static int tmc_online_cpu(unsigned int cpu)
+{
+	struct tmc_drvdata *drvdata, *tmp;
+	int ret;
+
+	spin_lock(&delay_lock);
+	list_for_each_entry_safe(drvdata, tmp, &tmc_delay_probe, link) {
+		if (cpumask_test_cpu(cpu, drvdata->supported_cpus)) {
+			list_del(&drvdata->link);
+
+			spin_unlock(&delay_lock);
+			ret = pm_runtime_resume_and_get(drvdata->dev);
+			if (ret < 0)
+				return 0;
+
+			tmc_init_hw_config(drvdata);
+			tmc_clear_self_claim_tag(drvdata);
+			tmc_add_coresight_dev(drvdata->dev);
+			pm_runtime_put(drvdata->dev);
+			spin_lock(&delay_lock);
+		}
+	}
+	spin_unlock(&delay_lock);
+	return 0;
+}
+
 static int __init tmc_init(void)
 {
+	int ret;
+
+	ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
+					"arm/coresight-tmc:online",
+					tmc_online_cpu, NULL);
+
+	if (ret > 0)
+		hp_online = ret;
+	else
+		return ret;
+
 	return coresight_init_driver("tmc", &tmc_driver, &tmc_platform_driver, THIS_MODULE);
 }
 
 static void __exit tmc_exit(void)
 {
 	coresight_remove_driver(&tmc_driver, &tmc_platform_driver);
+	if (hp_online) {
+		cpuhp_remove_state_nocalls(hp_online);
+		hp_online = 0;
+	}
 }
 module_init(tmc_init);
 module_exit(tmc_exit);
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index b104b7bf82d2a7a99382636e41d3718cf258d820..2583bc4f556195cd814e674dc66f08909dea61b2 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -246,6 +246,8 @@ struct tmc_resrv_buf {
  * @supported_cpus:	Represent the CPUs related to this TMC.
  * @devid:	TMC variant ID inferred from the device configuration register.
  * @desc_name:	Name to be used while creating crash interface.
+ * @dev:	pointer to the device associated with this TMC.
+ * @link:	link to the delay_probed list.
  */
 struct tmc_drvdata {
 	struct clk		*atclk;
@@ -279,6 +281,8 @@ struct tmc_drvdata {
 	struct cpumask		*supported_cpus;
 	u32			devid;
 	const char		*desc_name;
+	struct device		*dev;
+	struct list_head	link;
 };
 
 struct etr_buf_operations {

-- 
2.34.1



From yuanfang.zhang at oss.qualcomm.com  Thu Dec 18 00:09:51 2025
From: yuanfang.zhang at oss.qualcomm.com (Yuanfang Zhang)
Date: Thu, 18 Dec 2025 00:09:51 -0800
Subject: [PATCH v2 11/12] coresight: Pass trace mode to link enable
 callback
In-Reply-To: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
References: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
Message-ID: <20251218-cpu_cluster_component_pm-v2-11-2335a6ae62a0@oss.qualcomm.com>

Currently, the link enable callback does not receive the CoreSight mode
(enum cs_mode). This prevents link drivers from knowing whether they are
being enabled for SysFS or Perf.

This distinction is crucial because Perf mode runs in atomic context,
where certain operations (like smp_call_function_single()) are unsafe.
Without knowing the mode, drivers cannot conditionally avoid these
unsafe calls.

Update the `enable` callback in `struct coresight_ops_link` to accept
`enum cs_mode`. This allows drivers to implement mode-specific logic,
such as using atomic-safe enablement sequences when running in Perf
mode. Update all call sites and driver implementations accordingly.

Signed-off-by: Yuanfang Zhang <yuanfang.zhang at oss.qualcomm.com>
---
 drivers/hwtracing/coresight/coresight-core.c       |  7 ++++---
 drivers/hwtracing/coresight/coresight-funnel.c     | 21 +++++++++++++++++++-
 drivers/hwtracing/coresight/coresight-replicator.c | 23 +++++++++++++++++++++-
 drivers/hwtracing/coresight/coresight-tmc-etf.c    | 19 +++++++++++++++++-
 drivers/hwtracing/coresight/coresight-tnoc.c       |  3 ++-
 drivers/hwtracing/coresight/coresight-tpda.c       |  3 ++-
 include/linux/coresight.h                          |  3 ++-
 7 files changed, 70 insertions(+), 9 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index c660cf8adb1c7cafff8f85e501f056e4e151e372..1863bdb57281b4fd405cf966d565c581506ea270 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -314,7 +314,8 @@ static void coresight_disable_sink(struct coresight_device *csdev)
 static int coresight_enable_link(struct coresight_device *csdev,
 				 struct coresight_device *parent,
 				 struct coresight_device *child,
-				 struct coresight_device *source)
+				 struct coresight_device *source,
+				 enum cs_mode mode)
 {
 	int link_subtype;
 	struct coresight_connection *inconn, *outconn;
@@ -331,7 +332,7 @@ static int coresight_enable_link(struct coresight_device *csdev,
 	if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && IS_ERR(outconn))
 		return PTR_ERR(outconn);
 
-	return link_ops(csdev)->enable(csdev, inconn, outconn);
+	return link_ops(csdev)->enable(csdev, inconn, outconn, mode);
 }
 
 static void coresight_disable_link(struct coresight_device *csdev,
@@ -550,7 +551,7 @@ int coresight_enable_path(struct coresight_path *path, enum cs_mode mode)
 		case CORESIGHT_DEV_TYPE_LINK:
 			parent = list_prev_entry(nd, link)->csdev;
 			child = list_next_entry(nd, link)->csdev;
-			ret = coresight_enable_link(csdev, parent, child, source);
+			ret = coresight_enable_link(csdev, parent, child, source, mode);
 			if (ret)
 				goto err_disable_helpers;
 			break;
diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c
index 5d114ce1109f4f9a8b108110bdae258f216881d8..c50522c2854c7193a8c30b1a603abe566a1c1ccf 100644
--- a/drivers/hwtracing/coresight/coresight-funnel.c
+++ b/drivers/hwtracing/coresight/coresight-funnel.c
@@ -121,7 +121,8 @@ static int funnel_enable_hw(struct funnel_drvdata *drvdata, int port)
 
 static int funnel_enable(struct coresight_device *csdev,
 			 struct coresight_connection *in,
-			 struct coresight_connection *out)
+			 struct coresight_connection *out,
+			 enum cs_mode mode)
 {
 	int rc = 0;
 	struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -135,6 +136,23 @@ static int funnel_enable(struct coresight_device *csdev,
 	else
 		in->dest_refcnt++;
 
+	if (mode == CS_MODE_PERF) {
+		if (first_enable) {
+			if (drvdata->supported_cpus &&
+			    !cpumask_test_cpu(smp_processor_id(), drvdata->supported_cpus)) {
+				raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+				return -EINVAL;
+			}
+
+			if (drvdata->base)
+				rc = dynamic_funnel_enable_hw(drvdata, in->dest_port);
+			if (!rc)
+				in->dest_refcnt++;
+		}
+		raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		return rc;
+	}
+
 	raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
 	if (first_enable) {
@@ -183,6 +201,7 @@ static void funnel_disable(struct coresight_device *csdev,
 			dynamic_funnel_disable_hw(drvdata, in->dest_port);
 		last_disable = true;
 	}
+
 	raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
 	if (last_disable)
diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c
index a9f22d0e15de21aa06c8d1e193e5db06091efd75..cc7d3916b8b9d5d342d6cde0487722eeb8dee78b 100644
--- a/drivers/hwtracing/coresight/coresight-replicator.c
+++ b/drivers/hwtracing/coresight/coresight-replicator.c
@@ -199,7 +199,8 @@ static int replicator_enable_hw(struct replicator_drvdata *drvdata,
 
 static int replicator_enable(struct coresight_device *csdev,
 			     struct coresight_connection *in,
-			     struct coresight_connection *out)
+			     struct coresight_connection *out,
+			     enum cs_mode mode)
 {
 	int rc = 0;
 	struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -212,6 +213,25 @@ static int replicator_enable(struct coresight_device *csdev,
 		first_enable = true;
 	else
 		out->src_refcnt++;
+
+	if (mode == CS_MODE_PERF) {
+		if (first_enable) {
+			if (drvdata->supported_cpus &&
+			    !cpumask_test_cpu(smp_processor_id(), drvdata->supported_cpus)) {
+				raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+				return -EINVAL;
+			}
+
+			if (drvdata->base)
+				rc = dynamic_replicator_enable(drvdata, in->dest_port,
+							       out->src_port);
+			if (!rc)
+				out->src_refcnt++;
+		}
+		raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		return rc;
+	}
+
 	raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
 	if (first_enable) {
@@ -272,6 +292,7 @@ static void replicator_disable(struct coresight_device *csdev,
 						   out->src_port);
 		last_disable = true;
 	}
+
 	raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
 	if (last_disable)
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index 11357788e9d93c53980e99e0ef78450e393f4059..f1b8264b4e5c8a8d38778c25515cbf557c0993b7 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -427,7 +427,8 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev)
 
 static int tmc_enable_etf_link(struct coresight_device *csdev,
 			       struct coresight_connection *in,
-			       struct coresight_connection *out)
+			       struct coresight_connection *out,
+			       enum cs_mode mode)
 {
 	int ret = 0;
 	unsigned long flags;
@@ -446,6 +447,22 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
 	if (!first_enable)
 		csdev->refcnt++;
 
+	if (mode == CS_MODE_PERF) {
+		if (first_enable) {
+			if (drvdata->supported_cpus &&
+			    !cpumask_test_cpu(smp_processor_id(), drvdata->supported_cpus)) {
+				raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+				return -EINVAL;
+			}
+
+			ret = tmc_etf_enable_hw_local(drvdata);
+			if (!ret)
+				csdev->refcnt++;
+		}
+		raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		return ret;
+	}
+
 	raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
 	if (first_enable) {
 		ret = tmc_etf_enable_hw(drvdata);
diff --git a/drivers/hwtracing/coresight/coresight-tnoc.c b/drivers/hwtracing/coresight/coresight-tnoc.c
index ff9a0a9cfe96e5f5e3077c750ea2f890cdd50d94..48e9e685b9439d92bdaae9e40d3b3bc2d1ac1cd2 100644
--- a/drivers/hwtracing/coresight/coresight-tnoc.c
+++ b/drivers/hwtracing/coresight/coresight-tnoc.c
@@ -73,7 +73,8 @@ static void trace_noc_enable_hw(struct trace_noc_drvdata *drvdata)
 }
 
 static int trace_noc_enable(struct coresight_device *csdev, struct coresight_connection *inport,
-			    struct coresight_connection *outport)
+			    struct coresight_connection *outport,
+			    enum cs_mode mode)
 {
 	struct trace_noc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
index 3a3825d27f861585ca1d847929747f8096004089..e6f52abc5b023a997c36d74c0e3b1a3de8236ba2 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.c
+++ b/drivers/hwtracing/coresight/coresight-tpda.c
@@ -190,7 +190,8 @@ static int __tpda_enable(struct tpda_drvdata *drvdata, int port)
 
 static int tpda_enable(struct coresight_device *csdev,
 		       struct coresight_connection *in,
-		       struct coresight_connection *out)
+		       struct coresight_connection *out,
+		       enum cs_mode mode)
 {
 	struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 	int ret = 0;
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index 2b48be97fcd0d7ea2692206692bd33f35ba4ec79..218eb1d1dcef61f5d98ebbfff38370192b8a6e45 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -383,7 +383,8 @@ struct coresight_ops_sink {
 struct coresight_ops_link {
 	int (*enable)(struct coresight_device *csdev,
 		      struct coresight_connection *in,
-		      struct coresight_connection *out);
+		      struct coresight_connection *out,
+		      enum cs_mode mode);
 	void (*disable)(struct coresight_device *csdev,
 			struct coresight_connection *in,
 			struct coresight_connection *out);

-- 
2.34.1



From yuanfang.zhang at oss.qualcomm.com  Thu Dec 18 00:09:52 2025
From: yuanfang.zhang at oss.qualcomm.com (yuanfang Zhang)
Date: Thu, 18 Dec 2025 00:09:52 -0800
Subject: [PATCH v2 12/12] arm64: dts: qcom: hamoa: Add CoreSight nodes for
 APSS debug block
In-Reply-To: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
References: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
Message-ID: <20251218-cpu_cluster_component_pm-v2-12-2335a6ae62a0@oss.qualcomm.com>

From: Jie Gan <jie.gan at oss.qualcomm.com>

The APSS debug block is built with CoreSight devices like ETM,
replicator, funnel and TMC ETF. Add dt nodes for these devices to enable
ETM trace.

Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
Co-developed-by: Yuanfang Zhang <yuanfang.zhang at oss.qualcomm.com>
Signed-off-by: Yuanfang Zhang <yuanfang.zhang at oss.qualcomm.com>
---
 arch/arm64/boot/dts/qcom/hamoa.dtsi | 926 ++++++++++++++++++++++++++++++++++++
 arch/arm64/boot/dts/qcom/purwa.dtsi |  12 +
 2 files changed, 938 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/hamoa.dtsi b/arch/arm64/boot/dts/qcom/hamoa.dtsi
index a17900eacb20396a9792efcfcd6ce6dd877435d1..8c3de8bf058daa681db040c4a9a38253863e6c78 100644
--- a/arch/arm64/boot/dts/qcom/hamoa.dtsi
+++ b/arch/arm64/boot/dts/qcom/hamoa.dtsi
@@ -305,6 +305,210 @@ eud_in: endpoint {
 		};
 	};
 
+	etm-0 {
+		compatible = "arm,coresight-etm4x-sysreg";
+
+		clocks = <&aoss_qmp>;
+		clock-names = "apb_pclk";
+		cpu = <&cpu0>;
+		qcom,skip-power-up;
+
+		out-ports {
+			port {
+				etm0_out: endpoint {
+					remote-endpoint = <&ncc0_0_rep_in>;
+				};
+			};
+		};
+	};
+
+	etm-1 {
+		compatible = "arm,coresight-etm4x-sysreg";
+
+		clocks = <&aoss_qmp>;
+		clock-names = "apb_pclk";
+		cpu = <&cpu1>;
+		qcom,skip-power-up;
+
+		out-ports {
+			port {
+				etm1_out: endpoint {
+					remote-endpoint = <&ncc0_1_rep_in>;
+				};
+			};
+		};
+	};
+
+	etm-2 {
+		compatible = "arm,coresight-etm4x-sysreg";
+
+		clocks = <&aoss_qmp>;
+		clock-names = "apb_pclk";
+		cpu = <&cpu2>;
+		qcom,skip-power-up;
+
+		out-ports {
+			port {
+				etm2_out: endpoint {
+					remote-endpoint = <&ncc0_2_rep_in>;
+				};
+			};
+		};
+	};
+
+	etm-3 {
+		compatible = "arm,coresight-etm4x-sysreg";
+
+		clocks = <&aoss_qmp>;
+		clock-names = "apb_pclk";
+		cpu = <&cpu3>;
+		qcom,skip-power-up;
+
+		out-ports {
+			port {
+				etm3_out: endpoint {
+					remote-endpoint = <&ncc0_3_rep_in>;
+				};
+			};
+		};
+	};
+
+	etm-4 {
+		compatible = "arm,coresight-etm4x-sysreg";
+
+		clocks = <&aoss_qmp>;
+		clock-names = "apb_pclk";
+		cpu = <&cpu4>;
+		qcom,skip-power-up;
+
+		out-ports {
+			port {
+				etm4_out: endpoint {
+					remote-endpoint = <&ncc1_0_rep_in>;
+				};
+			};
+		};
+	};
+
+	etm-5 {
+		compatible = "arm,coresight-etm4x-sysreg";
+
+		clocks = <&aoss_qmp>;
+		clock-names = "apb_pclk";
+		cpu = <&cpu5>;
+		qcom,skip-power-up;
+
+		out-ports {
+			port {
+				etm5_out: endpoint {
+					remote-endpoint = <&ncc1_1_rep_in>;
+				};
+			};
+		};
+	};
+
+	etm-6 {
+		compatible = "arm,coresight-etm4x-sysreg";
+
+		clocks = <&aoss_qmp>;
+		clock-names = "apb_pclk";
+		cpu = <&cpu6>;
+		qcom,skip-power-up;
+
+		out-ports {
+			port {
+				etm6_out: endpoint {
+					remote-endpoint = <&ncc1_2_rep_in>;
+				};
+			};
+		};
+	};
+
+	etm-7 {
+		compatible = "arm,coresight-etm4x-sysreg";
+
+		clocks = <&aoss_qmp>;
+		clock-names = "apb_pclk";
+		cpu = <&cpu7>;
+		qcom,skip-power-up;
+
+		out-ports {
+			port {
+				etm7_out: endpoint {
+					remote-endpoint = <&ncc1_3_rep_in>;
+				};
+			};
+		};
+	};
+
+	etm8: etm-8 {
+		compatible = "arm,coresight-etm4x-sysreg";
+
+		clocks = <&aoss_qmp>;
+		clock-names = "apb_pclk";
+		cpu = <&cpu8>;
+		qcom,skip-power-up;
+
+		out-ports {
+			port {
+				etm8_out: endpoint {
+					remote-endpoint = <&ncc2_0_rep_in>;
+				};
+			};
+		};
+	};
+
+	etm9: etm-9 {
+		compatible = "arm,coresight-etm4x-sysreg";
+
+		clocks = <&aoss_qmp>;
+		clock-names = "apb_pclk";
+		cpu = <&cpu9>;
+		qcom,skip-power-up;
+
+		out-ports {
+			port {
+				etm9_out: endpoint {
+					remote-endpoint = <&ncc2_1_rep_in>;
+				};
+			};
+		};
+	};
+
+	etm10: etm-10 {
+		compatible = "arm,coresight-etm4x-sysreg";
+
+		clocks = <&aoss_qmp>;
+		clock-names = "apb_pclk";
+		cpu = <&cpu10>;
+		qcom,skip-power-up;
+
+		out-ports {
+			port {
+				etm10_out: endpoint {
+					remote-endpoint = <&ncc2_2_rep_in>;
+				};
+			};
+		};
+	};
+
+	etm11: etm-11 {
+		compatible = "arm,coresight-etm4x-sysreg";
+
+		clocks = <&aoss_qmp>;
+		clock-names = "apb_pclk";
+		cpu = <&cpu11>;
+		qcom,skip-power-up;
+
+		out-ports {
+			port {
+				etm11_out: endpoint {
+					remote-endpoint = <&ncc2_3_rep_in>;
+				};
+			};
+		};
+	};
+
 	firmware {
 		scm: scm {
 			compatible = "qcom,scm-x1e80100", "qcom,scm";
@@ -6864,6 +7068,14 @@ funnel1_in2: endpoint {
 					};
 				};
 
+				port at 4 {
+					reg = <4>;
+
+					funnel1_in4: endpoint {
+						remote-endpoint = <&apss_funnel_out>;
+					};
+				};
+
 				port at 5 {
 					reg = <5>;
 
@@ -8154,6 +8366,720 @@ ddr_funnel1_out: endpoint {
 			};
 		};
 
+		apss_funnel: funnel at 12080000 {
+			compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
+			reg = <0x0 0x12080000 0x0 0x1000>;
+
+			clocks = <&aoss_qmp>;
+			clock-names = "apb_pclk";
+
+			in-ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+
+					apss_funnel_in0: endpoint {
+						remote-endpoint = <&ncc0_etf_out>;
+					};
+				};
+
+				port at 1 {
+					reg = <1>;
+
+					apss_funnel_in1: endpoint {
+						remote-endpoint = <&ncc1_etf_out>;
+					};
+				};
+
+				port at 2 {
+					reg = <2>;
+
+					apss_funnel_in2: endpoint {
+						remote-endpoint = <&ncc2_etf_out>;
+					};
+				};
+			};
+
+			out-ports {
+				port {
+					apss_funnel_out: endpoint {
+						remote-endpoint = <&funnel1_in4>;
+					};
+				};
+			};
+		};
+
+		funnel at 13401000 {
+			compatible = "arm,primecell";
+			arm,primecell-periphid = <0x000bb908>;
+			reg = <0x0 0x13401000 0x0 0x1000>;
+
+			clocks = <&aoss_qmp>;
+			clock-names = "apb_pclk";
+			power-domains = <&cluster_pd0>;
+			qcom,cpu-bound-components;
+
+			in-ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 2 {
+					reg = <2>;
+
+					ncc0_2_funnel_in2: endpoint {
+						remote-endpoint = <&ncc0_1_funnel_out>;
+					};
+				};
+			};
+
+			out-ports {
+				port {
+					ncc0_2_funnel_out: endpoint {
+						remote-endpoint = <&ncc0_etf_in>;
+					};
+				};
+			};
+		};
+
+		tmc at 13409000 {
+			compatible = "arm,primecell";
+			arm,primecell-periphid = <0x000bb961>;
+			reg = <0x0 0x13409000 0x0 0x1000>;
+
+			clocks = <&aoss_qmp>;
+			clock-names = "apb_pclk";
+			power-domains = <&cluster_pd0>;
+			qcom,cpu-bound-components;
+
+			in-ports {
+				port {
+					ncc0_etf_in: endpoint {
+						remote-endpoint = <&ncc0_2_funnel_out>;
+					};
+				};
+			};
+
+			out-ports {
+				port {
+					ncc0_etf_out: endpoint {
+						remote-endpoint = <&apss_funnel_in0>;
+					};
+				};
+			};
+		};
+
+		replicator at 13490000 {
+			compatible = "arm,primecell";
+			arm,primecell-periphid = <0x000bb909>;
+			reg = <0x0 0x13490000 0x0 0x1000>;
+
+			clocks = <&aoss_qmp>;
+			clock-names = "apb_pclk";
+			power-domains = <&cluster_pd0>;
+			qcom,cpu-bound-components;
+
+			in-ports {
+				port {
+					ncc0_0_rep_in: endpoint {
+						remote-endpoint = <&etm0_out>;
+					};
+				};
+			};
+
+			out-ports {
+				port {
+					ncc0_0_rep_out: endpoint {
+						remote-endpoint = <&ncc0_1_funnel_in0>;
+					};
+				};
+			};
+		};
+
+		replicator at 134a0000 {
+			compatible = "arm,primecell";
+			arm,primecell-periphid = <0x000bb909>;
+			reg = <0x0 0x134a0000 0x0 0x1000>;
+
+			clocks = <&aoss_qmp>;
+			clock-names = "apb_pclk";
+			power-domains = <&cluster_pd0>;
+			qcom,cpu-bound-components;
+
+			in-ports {
+				port {
+					ncc0_1_rep_in: endpoint {
+						remote-endpoint = <&etm1_out>;
+					};
+				};
+			};
+
+			out-ports {
+				port {
+					ncc0_1_rep_out: endpoint {
+						remote-endpoint = <&ncc0_1_funnel_in1>;
+					};
+				};
+			};
+		};
+
+		replicator at 134b0000 {
+			compatible = "arm,primecell";
+			arm,primecell-periphid = <0x000bb909>;
+			reg = <0x0 0x134b0000 0x0 0x1000>;
+
+			clocks = <&aoss_qmp>;
+			clock-names = "apb_pclk";
+			power-domains = <&cluster_pd0>;
+			qcom,cpu-bound-components;
+
+			in-ports {
+				port {
+					ncc0_2_rep_in: endpoint {
+						remote-endpoint = <&etm2_out>;
+					};
+				};
+			};
+
+			out-ports {
+				port {
+					ncc0_2_rep_out: endpoint {
+						remote-endpoint = <&ncc0_1_funnel_in2>;
+					};
+				};
+			};
+		};
+
+		replicator at 134c0000 {
+			compatible = "arm,primecell";
+			arm,primecell-periphid = <0x000bb909>;
+			reg = <0x0 0x134c0000 0x0 0x1000>;
+
+			clocks = <&aoss_qmp>;
+			clock-names = "apb_pclk";
+			power-domains = <&cluster_pd0>;
+			qcom,cpu-bound-components;
+
+			in-ports {
+				port {
+					ncc0_3_rep_in: endpoint {
+						remote-endpoint = <&etm3_out>;
+					};
+				};
+			};
+
+			out-ports {
+				port {
+					ncc0_3_rep_out: endpoint {
+						remote-endpoint = <&ncc0_1_funnel_in3>;
+					};
+				};
+			};
+		};
+
+		funnel at 134d0000 {
+			compatible = "arm,primecell";
+			arm,primecell-periphid = <0x000bb908>;
+			reg = <0x0 0x134d0000 0x0 0x1000>;
+
+			clocks = <&aoss_qmp>;
+			clock-names = "apb_pclk";
+			power-domains = <&cluster_pd0>;
+			qcom,cpu-bound-components;
+
+			in-ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+
+					ncc0_1_funnel_in0: endpoint {
+						remote-endpoint = <&ncc0_0_rep_out>;
+					};
+				};
+
+				port at 1 {
+					reg = <1>;
+
+					ncc0_1_funnel_in1: endpoint {
+						remote-endpoint = <&ncc0_1_rep_out>;
+					};
+				};
+
+				port at 2 {
+					reg = <2>;
+
+					ncc0_1_funnel_in2: endpoint {
+						remote-endpoint = <&ncc0_2_rep_out>;
+					};
+				};
+
+				port at 3 {
+					reg = <3>;
+
+					ncc0_1_funnel_in3: endpoint {
+						remote-endpoint = <&ncc0_3_rep_out>;
+					};
+				};
+			};
+
+			out-ports {
+				port {
+					ncc0_1_funnel_out: endpoint {
+						remote-endpoint = <&ncc0_2_funnel_in2>;
+					};
+				};
+			};
+		};
+
+		funnel at 13901000 {
+			compatible = "arm,primecell";
+			arm,primecell-periphid = <0x000bb908>;
+			reg = <0x0 0x13901000 0x0 0x1000>;
+
+			clocks = <&aoss_qmp>;
+			clock-names = "apb_pclk";
+			power-domains = <&cluster_pd1>;
+			qcom,cpu-bound-components;
+
+			in-ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 2 {
+					reg = <2>;
+
+					ncc1_2_funnel_in2: endpoint {
+						remote-endpoint = <&ncc1_1_funnel_out>;
+					};
+				};
+			};
+
+			out-ports {
+				port {
+					ncc1_2_funnel_out: endpoint {
+						remote-endpoint = <&ncc1_etf_in>;
+					};
+				};
+			};
+		};
+
+		tmc at 13909000 {
+			compatible = "arm,primecell";
+			arm,primecell-periphid = <0x000bb961>;
+			reg = <0x0 0x13909000 0x0 0x1000>;
+
+			clocks = <&aoss_qmp>;
+			clock-names = "apb_pclk";
+			power-domains = <&cluster_pd1>;
+			qcom,cpu-bound-components;
+
+			in-ports {
+				port {
+					ncc1_etf_in: endpoint {
+						remote-endpoint = <&ncc1_2_funnel_out>;
+					};
+				};
+			};
+
+			out-ports {
+				port {
+					ncc1_etf_out: endpoint {
+						remote-endpoint = <&apss_funnel_in1>;
+					};
+				};
+			};
+		};
+
+		replicator at 13990000 {
+			compatible = "arm,primecell";
+			arm,primecell-periphid = <0x000bb909>;
+			reg = <0x0 0x13990000 0x0 0x1000>;
+
+			clocks = <&aoss_qmp>;
+			clock-names = "apb_pclk";
+			power-domains = <&cluster_pd1>;
+			qcom,cpu-bound-components;
+
+			in-ports {
+				port {
+					ncc1_0_rep_in: endpoint {
+						remote-endpoint = <&etm4_out>;
+					};
+				};
+			};
+
+			out-ports {
+				port {
+					ncc1_0_rep_out: endpoint {
+						remote-endpoint = <&ncc1_1_funnel_in0>;
+					};
+				};
+			};
+		};
+
+		replicator at 139a0000 {
+			compatible = "arm,primecell";
+			arm,primecell-periphid = <0x000bb909>;
+			reg = <0x0 0x139a0000 0x0 0x1000>;
+
+			clocks = <&aoss_qmp>;
+			clock-names = "apb_pclk";
+			power-domains = <&cluster_pd1>;
+			qcom,cpu-bound-components;
+
+			in-ports {
+				port {
+					ncc1_1_rep_in: endpoint {
+						remote-endpoint = <&etm5_out>;
+					};
+				};
+			};
+
+			out-ports {
+				port {
+					ncc1_1_rep_out: endpoint {
+						remote-endpoint = <&ncc1_1_funnel_in1>;
+					};
+				};
+			};
+		};
+
+		replicator at 139b0000 {
+			compatible = "arm,primecell";
+			arm,primecell-periphid = <0x000bb909>;
+			reg = <0x0 0x139b0000 0x0 0x1000>;
+
+			clocks = <&aoss_qmp>;
+			clock-names = "apb_pclk";
+			power-domains = <&cluster_pd1>;
+			qcom,cpu-bound-components;
+
+			in-ports {
+				port {
+					ncc1_2_rep_in: endpoint {
+						remote-endpoint = <&etm6_out>;
+					};
+				};
+			};
+
+			out-ports {
+				port {
+					ncc1_2_rep_out: endpoint {
+						remote-endpoint = <&ncc1_1_funnel_in2>;
+					};
+				};
+			};
+		};
+
+		replicator at 139c0000 {
+			compatible = "arm,primecell";
+			arm,primecell-periphid = <0x000bb909>;
+			reg = <0x0 0x139c0000 0x0 0x1000>;
+
+			clocks = <&aoss_qmp>;
+			clock-names = "apb_pclk";
+			power-domains = <&cluster_pd1>;
+			qcom,cpu-bound-components;
+
+			in-ports {
+				port {
+					ncc1_3_rep_in: endpoint {
+						remote-endpoint = <&etm7_out>;
+					};
+				};
+			};
+
+			out-ports {
+				port {
+					ncc1_3_rep_out: endpoint {
+						remote-endpoint = <&ncc1_1_funnel_in3>;
+					};
+				};
+			};
+		};
+
+		funnel at 139d0000 {
+			compatible = "arm,primecell";
+			arm,primecell-periphid = <0x000bb908>;
+			reg = <0x0 0x139d0000 0x0 0x1000>;
+
+			clocks = <&aoss_qmp>;
+			clock-names = "apb_pclk";
+			power-domains = <&cluster_pd1>;
+			qcom,cpu-bound-components;
+
+			in-ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+
+					ncc1_1_funnel_in0: endpoint {
+						remote-endpoint = <&ncc1_0_rep_out>;
+					};
+				};
+
+				port at 1 {
+					reg = <1>;
+
+					ncc1_1_funnel_in1: endpoint {
+						remote-endpoint = <&ncc1_1_rep_out>;
+					};
+				};
+
+				port at 2 {
+					reg = <2>;
+
+					ncc1_1_funnel_in2: endpoint {
+						remote-endpoint = <&ncc1_2_rep_out>;
+					};
+				};
+
+				port at 3 {
+					reg = <3>;
+
+					ncc1_1_funnel_in3: endpoint {
+						remote-endpoint = <&ncc1_3_rep_out>;
+					};
+				};
+			};
+
+			out-ports {
+				port {
+					ncc1_1_funnel_out: endpoint {
+						remote-endpoint = <&ncc1_2_funnel_in2>;
+					};
+				};
+			};
+		};
+
+		cluster2_funnel_l2: funnel at 13e01000 {
+			compatible = "arm,primecell";
+			arm,primecell-periphid = <0x000bb908>;
+			reg = <0x0 0x13e01000 0x0 0x1000>;
+
+			clocks = <&aoss_qmp>;
+			clock-names = "apb_pclk";
+			power-domains = <&cluster_pd2>;
+			qcom,cpu-bound-components;
+
+			in-ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 2 {
+					reg = <2>;
+
+					ncc2_2_funnel_in2: endpoint {
+						remote-endpoint = <&ncc2_1_funnel_out>;
+					};
+				};
+			};
+
+			out-ports {
+				port {
+					ncc2_2_funnel_out: endpoint {
+						remote-endpoint = <&ncc2_etf_in>;
+					};
+				};
+			};
+		};
+
+		cluster2_etf: tmc at 13e09000 {
+			compatible = "arm,primecell";
+			arm,primecell-periphid = <0x000bb961>;
+			reg = <0x0 0x13e09000 0x0 0x1000>;
+
+			clocks = <&aoss_qmp>;
+			clock-names = "apb_pclk";
+			power-domains = <&cluster_pd2>;
+			qcom,cpu-bound-components;
+
+			in-ports {
+				port {
+					ncc2_etf_in: endpoint {
+						remote-endpoint = <&ncc2_2_funnel_out>;
+					};
+				};
+			};
+
+			out-ports {
+				port {
+					ncc2_etf_out: endpoint {
+						remote-endpoint = <&apss_funnel_in2>;
+					};
+				};
+			};
+		};
+
+		cluster2_rep_2_0: replicator at 13e90000 {
+			compatible = "arm,primecell";
+			arm,primecell-periphid = <0x000bb909>;
+			reg = <0x0 0x13e90000 0x0 0x1000>;
+
+			clocks = <&aoss_qmp>;
+			clock-names = "apb_pclk";
+			power-domains = <&cluster_pd2>;
+			qcom,cpu-bound-components;
+
+			in-ports {
+				port {
+					ncc2_0_rep_in: endpoint {
+						remote-endpoint = <&etm8_out>;
+					};
+				};
+			};
+
+			out-ports {
+				port {
+					ncc2_0_rep_out: endpoint {
+						remote-endpoint = <&ncc2_1_funnel_in0>;
+					};
+				};
+			};
+		};
+
+		cluster2_rep_2_1: replicator at 13ea0000 {
+			compatible = "arm,primecell";
+			arm,primecell-periphid = <0x000bb909>;
+			reg = <0x0 0x13ea0000 0x0 0x1000>;
+
+			clocks = <&aoss_qmp>;
+			clock-names = "apb_pclk";
+			power-domains = <&cluster_pd2>;
+			qcom,cpu-bound-components;
+
+			in-ports {
+				port {
+					ncc2_1_rep_in: endpoint {
+						remote-endpoint = <&etm9_out>;
+					};
+				};
+			};
+
+			out-ports {
+				port {
+					ncc2_1_rep_out: endpoint {
+						remote-endpoint = <&ncc2_1_funnel_in1>;
+					};
+				};
+			};
+		};
+
+		cluster2_rep_2_2: replicator at 13eb0000 {
+			compatible = "arm,primecell";
+			arm,primecell-periphid = <0x000bb909>;
+			reg = <0x0 0x13eb0000 0x0 0x1000>;
+
+			clocks = <&aoss_qmp>;
+			clock-names = "apb_pclk";
+			power-domains = <&cluster_pd2>;
+			qcom,cpu-bound-components;
+
+			in-ports {
+				port {
+					ncc2_2_rep_in: endpoint {
+						remote-endpoint = <&etm10_out>;
+					};
+				};
+			};
+
+			out-ports {
+				port {
+					ncc2_2_rep_out: endpoint {
+						remote-endpoint = <&ncc2_1_funnel_in2>;
+					};
+				};
+			};
+		};
+
+		cluster2_rep_2_3: replicator at 13ec0000 {
+			compatible = "arm,primecell";
+			arm,primecell-periphid = <0x000bb909>;
+			reg = <0x0 0x13ec0000 0x0 0x1000>;
+
+			clocks = <&aoss_qmp>;
+			clock-names = "apb_pclk";
+			power-domains = <&cluster_pd2>;
+			qcom,cpu-bound-components;
+
+			in-ports {
+				port {
+					ncc2_3_rep_in: endpoint {
+						remote-endpoint = <&etm11_out>;
+					};
+				};
+			};
+
+			out-ports {
+				port {
+					ncc2_3_rep_out: endpoint {
+						remote-endpoint = <&ncc2_1_funnel_in3>;
+					};
+				};
+			};
+		};
+
+		cluster2_funnel_l1: funnel at 13ed0000 {
+			compatible = "arm,primecell";
+			arm,primecell-periphid = <0x000bb908>;
+			reg = <0x0 0x13ed0000 0x0 0x1000>;
+
+			clocks = <&aoss_qmp>;
+			clock-names = "apb_pclk";
+			power-domains = <&cluster_pd2>;
+			qcom,cpu-bound-components;
+
+			in-ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+
+					ncc2_1_funnel_in0: endpoint {
+						remote-endpoint = <&ncc2_0_rep_out>;
+					};
+				};
+
+				port at 1 {
+					reg = <1>;
+
+					ncc2_1_funnel_in1: endpoint {
+						remote-endpoint = <&ncc2_1_rep_out>;
+					};
+				};
+
+				port at 2 {
+					reg = <2>;
+
+					ncc2_1_funnel_in2: endpoint {
+						remote-endpoint = <&ncc2_2_rep_out>;
+					};
+				};
+
+				port at 3 {
+					reg = <3>;
+
+					ncc2_1_funnel_in3: endpoint {
+						remote-endpoint = <&ncc2_3_rep_out>;
+					};
+				};
+			};
+
+			out-ports {
+				port {
+					ncc2_1_funnel_out: endpoint {
+						remote-endpoint = <&ncc2_2_funnel_in2>;
+					};
+				};
+			};
+		};
+
 		apps_smmu: iommu at 15000000 {
 			compatible = "qcom,x1e80100-smmu-500", "qcom,smmu-500", "arm,mmu-500";
 			reg = <0 0x15000000 0 0x100000>;
diff --git a/arch/arm64/boot/dts/qcom/purwa.dtsi b/arch/arm64/boot/dts/qcom/purwa.dtsi
index 2cecd2dd0de8c39f0702d6983bead2bc2adccf9b..38f2df9e42b60b5f22decfb464381bce214d414d 100644
--- a/arch/arm64/boot/dts/qcom/purwa.dtsi
+++ b/arch/arm64/boot/dts/qcom/purwa.dtsi
@@ -21,6 +21,18 @@
 /delete-node/ &gpu_speed_bin;
 /delete-node/ &pcie3_phy;
 /delete-node/ &thermal_zones;
+/delete-node/ &etm8;
+/delete-node/ &etm9;
+/delete-node/ &etm10;
+/delete-node/ &etm11;
+/delete-node/ &cluster2_funnel_l1;
+/delete-node/ &cluster2_funnel_l2;
+/delete-node/ &cluster2_etf;
+/delete-node/ &cluster2_rep_2_0;
+/delete-node/ &cluster2_rep_2_1;
+/delete-node/ &cluster2_rep_2_2;
+/delete-node/ &cluster2_rep_2_3;
+/delete-node/ &apss_funnel_in2;
 
 &gcc {
 	compatible = "qcom,x1p42100-gcc", "qcom,x1e80100-gcc";

-- 
2.34.1



From devnull+fnkl.kernel.gmail.com at kernel.org  Thu Dec 18 00:11:26 2025
From: devnull+fnkl.kernel.gmail.com at kernel.org (Sasha Finkelstein via B4 Relay)
Date: Thu, 18 Dec 2025 09:11:26 +0100
Subject: [PATCH] Input: apple_z2: Fix reading incorrect reports after
 exiting sleep
Message-ID: <20251218-z2-init-fix-v1-1-48e3aa239caf@gmail.com>

From: Sasha Finkelstein <fnkl.kernel at gmail.com>

Under certain conditions (more prevalent after a suspend/resume cycle),
the touchscreen controller can send the "boot complete" interrupt before
it actually finished booting. In those cases, attempting to read touch
data resuls in a stream of "not ready" messages being read and
interpreted as a touch report. Check that the response is in fact a
touch report and discard it otherwise.

Reported-by: pitust <piotr at stelmaszek.com>
Closes: https://oftc.catirclogs.org/asahi/2025-12-17#34878715;
Fixes: 471a92f8a21a ("Input: apple_z2 - add a driver for Apple Z2 touchscreens")
Signed-off-by: Sasha Finkelstein <fnkl.kernel at gmail.com>
---
 drivers/input/touchscreen/apple_z2.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/input/touchscreen/apple_z2.c b/drivers/input/touchscreen/apple_z2.c
index 0de161eae59a..271ababf0ad5 100644
--- a/drivers/input/touchscreen/apple_z2.c
+++ b/drivers/input/touchscreen/apple_z2.c
@@ -21,6 +21,7 @@
 #define APPLE_Z2_TOUCH_STARTED           3
 #define APPLE_Z2_TOUCH_MOVED             4
 #define APPLE_Z2_CMD_READ_INTERRUPT_DATA 0xEB
+#define APPLE_Z2_REPLY_INTERRUPT_DATA    0xE1
 #define APPLE_Z2_HBPP_CMD_BLOB           0x3001
 #define APPLE_Z2_FW_MAGIC                0x5746325A
 #define LOAD_COMMAND_INIT_PAYLOAD        0
@@ -142,6 +143,9 @@ static int apple_z2_read_packet(struct apple_z2 *z2)
 	if (error)
 		return error;
 
+	if (z2->rx_buf[0] != APPLE_Z2_REPLY_INTERRUPT_DATA)
+		return 0;
+
 	pkt_len = (get_unaligned_le16(z2->rx_buf + 1) + 8) & 0xfffffffc;
 
 	error = spi_read(z2->spidev, z2->rx_buf, pkt_len);

---
base-commit: ea1013c1539270e372fc99854bc6e4d94eaeff66
change-id: 20251217-z2-init-fix-3b14ef4c6890

Best regards,
-- 
Sasha Finkelstein <fnkl.kernel at gmail.com>




From mani at kernel.org  Thu Dec 18 00:11:55 2025
From: mani at kernel.org (Manivannan Sadhasivam)
Date: Thu, 18 Dec 2025 13:41:55 +0530
Subject: [PATCH] PCI: xilinx: Fix INTx IRQ domain leak when MSI
 allocation fails
In-Reply-To: <20251119033301.518-1-vulab@iscas.ac.cn>
References: <20251119033301.518-1-vulab@iscas.ac.cn>
Message-ID: <oelexrnhxsvscyxsrsl2gh25kvfqclxnrah6x27anjj3knuqg7@yexgfqzba6fr>

On Wed, Nov 19, 2025 at 11:33:01AM +0800, Haotian Zhang wrote:
> In xilinx_pcie_init_irq_domain(), if xilinx_allocate_msi_domains()
> fails after pcie->leg_domain has been successfully created via
> irq_domain_create_linear(), the function returns directly without
> cleaning up the allocated IRQ domain, resulting in a resource leak.
> 
> Add irq_domain_remove() call in the error path to properly release the
> IRQ domain before returning the error.
> 
> Fixes: 699ca3016268 ("PCI: xilinx: Check for __get_free_pages() failure")

Is this the correct tag?

- Mani

> Signed-off-by: Haotian Zhang <vulab at iscas.ac.cn>
> ---
>  drivers/pci/controller/pcie-xilinx.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/pci/controller/pcie-xilinx.c b/drivers/pci/controller/pcie-xilinx.c
> index 937ea6ae1ac4..e8cf320f3764 100644
> --- a/drivers/pci/controller/pcie-xilinx.c
> +++ b/drivers/pci/controller/pcie-xilinx.c
> @@ -480,8 +480,10 @@ static int xilinx_pcie_init_irq_domain(struct xilinx_pcie *pcie)
>  		phys_addr_t pa = ALIGN_DOWN(virt_to_phys(pcie), SZ_4K);
>  
>  		ret = xilinx_allocate_msi_domains(pcie);
> -		if (ret)
> +		if (ret) {
> +			irq_domain_remove(pcie->leg_domain);
>  			return ret;
> +		}
>  
>  		pcie_write(pcie, upper_32_bits(pa), XILINX_PCIE_REG_MSIBASE1);
>  		pcie_write(pcie, lower_32_bits(pa), XILINX_PCIE_REG_MSIBASE2);
> -- 
> 2.50.1.windows.1
> 

-- 
????????? ????????


From Sascha.Bischoff at arm.com  Thu Dec 18 00:17:19 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Thu, 18 Dec 2025 08:17:19 +0000
Subject: [PATCH 18/32] KVM: arm64: gic-v5: Check for pending PPIs
In-Reply-To: <20251217120035.GA1628893@e124191.cambridge.arm.com>
References: <20251212152215.675767-1-sascha.bischoff@arm.com>
	 <20251212152215.675767-19-sascha.bischoff@arm.com>
	 <20251217114932.GA1626516@e124191.cambridge.arm.com>
	 <20251217120035.GA1628893@e124191.cambridge.arm.com>
Message-ID: <20f13c1b0bd1c3954075d29aa099697f0afa6f2f.camel@arm.com>

On Wed, 2025-12-17 at 12:00 +0000, Joey Gouly wrote:
> On Wed, Dec 17, 2025 at 11:49:32AM +0000, Joey Gouly wrote:
> > Hi Sascha,
> > 
> > On Fri, Dec 12, 2025 at 03:22:41PM +0000, Sascha Bischoff wrote:
> > > This change allows KVM to check for pending PPI interrupts. This
> > > has
> > > two main components:
> > > 
> > > First of all, the effective priority mask is calculated.? This is
> > > a
> > > combination of the priority mask in the VPEs ICC_PCR_EL1.PRIORITY
> > > and
> > > the currently running priority as determined from the VPE's
> > > ICH_APR_EL1. If an interrupt's prioirity is greater than or equal
> > > to
> > > the effective priority mask, it can be signalled. Otherwise, it
> > > cannot.
> > > 
> > > Secondly, any Enabled and Pending PPIs must be checked against
> > > this
> > > compound priority mask. The reqires the PPI priorities to by
> > > synced
> > > back to the KVM shadow state - this is skipped in general
> > > operation as
> > > it isn't required and is rather expensive. If any Enabled and
> > > Pending
> > > PPIs are of sufficient priority to be signalled, then there are
> > > pending PPIs. Else, there are not.? This ensures that a VPE is
> > > not
> > > woken when it cannot actually process the pending interrupts.
> > > 
> > > Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
> > > ---
> > > ?arch/arm64/kvm/vgic/vgic-v5.c | 123
> > > ++++++++++++++++++++++++++++++++++
> > > ?arch/arm64/kvm/vgic/vgic.c??? |? 10 ++-
> > > ?arch/arm64/kvm/vgic/vgic.h??? |?? 1 +
> > > ?3 files changed, 131 insertions(+), 3 deletions(-)
> > > 
> > > diff --git a/arch/arm64/kvm/vgic/vgic-v5.c
> > > b/arch/arm64/kvm/vgic/vgic-v5.c
> > > index d54595fbf4586..35740e88b3591 100644
> > > --- a/arch/arm64/kvm/vgic/vgic-v5.c
> > > +++ b/arch/arm64/kvm/vgic/vgic-v5.c
> > > @@ -54,6 +54,31 @@ int vgic_v5_probe(const struct gic_kvm_info
> > > *info)
> > > ?	return 0;
> > > ?}
> > > ?
> > > +static u32 vgic_v5_get_effective_priority_mask(struct kvm_vcpu
> > > *vcpu)
> > > +{
> > > +	struct vgic_v5_cpu_if *cpu_if = &vcpu-
> > > >arch.vgic_cpu.vgic_v5;
> > > +	unsigned highest_ap, priority_mask;
> > > +
> > > +	/*
> > > +	 * Counting the number of trailing zeros gives the
> > > current
> > > +	 * active priority. Explicitly use the 32-bit version
> > > here as
> > > +	 * we have 32 priorities. 0x20 then means that there are
> > > no
> > > +	 * active priorities.
> > > +	 */
> > > +	highest_ap = __builtin_ctz(cpu_if->vgic_apr);
> > 
> > __builtin_ctz(0) is undefined
> > (https://gcc.gnu.org/onlinedocs/gcc/Bit-Operation-Builtins.html)
> > 
> > Looking at __vgic_v3_clear_highest_active_priority(), it handles
> > that like this:
> > 
> > 	c0 = ap0 ? __ffs(ap0) : 32;
> 
> Sorry forgot ffs() was 1-based, so:
> 
> 	highest_ap = cpu_if->vgic_apr ? __builtin_ctz(cpu_if-
> >vgic_apr) : 32;
> 
> Thanks,
> Joey

Thanks. Have made this change as I think it addresses Marc's concern
too!

Sascha

> 
> > 
> > Thanks,
> > Joey
> > 
> > > +
> > > +	/*
> > > +	 * An interrupt is of sufficient priority if it is equal
> > > to or
> > > +	 * greater than the priority mask. Add 1 to the priority
> > > mask
> > > +	 * (i.e., lower priority) to match the APR logic before
> > > taking
> > > +	 * the min. This gives us the lowest priority that is
> > > masked.
> > > +	 */
> > > +	priority_mask = FIELD_GET(FEAT_GCIE_ICH_VMCR_EL2_VPMR,
> > > cpu_if->vgic_vmcr);
> > > +	priority_mask = min(highest_ap, priority_mask + 1);
> > > +
> > > +	return priority_mask;
> > > +}
> > > +
> > > ?static bool vgic_v5_ppi_set_pending_state(struct kvm_vcpu *vcpu,
> > > ?					? struct vgic_irq *irq)
> > > ?{
> > > @@ -121,6 +146,104 @@ void vgic_v5_set_ppi_ops(struct vgic_irq
> > > *irq)
> > > ?	irq->ops = &vgic_v5_ppi_irq_ops;
> > > ?}
> > > ?
> > > +
> > > +/*
> > > + * Sync back the PPI priorities to the vgic_irq shadow state
> > > + */
> > > +static void vgic_v5_sync_ppi_priorities(struct kvm_vcpu *vcpu)
> > > +{
> > > +	struct vgic_v5_cpu_if *cpu_if = &vcpu-
> > > >arch.vgic_cpu.vgic_v5;
> > > +	unsigned long flags;
> > > +	int i, reg;
> > > +
> > > +	/* We have 16 PPI Priority regs */
> > > +	for (reg = 0; reg < 16; reg++) {
> > > +		const unsigned long priorityr = cpu_if-
> > > >vgic_ppi_priorityr[reg];
> > > +
> > > +		for (i = 0; i < 8; ++i) {
> > > +			struct vgic_irq *irq;
> > > +			u32 intid;
> > > +			u8 priority;
> > > +
> > > +			priority = (priorityr >> (i * 8)) &
> > > 0x1f;
> > > +
> > > +			intid = FIELD_PREP(GICV5_HWIRQ_TYPE,
> > > GICV5_HWIRQ_TYPE_PPI);
> > > +			intid |= FIELD_PREP(GICV5_HWIRQ_ID, reg
> > > * 8 + i);
> > > +
> > > +			irq = vgic_get_vcpu_irq(vcpu, intid);
> > > +			raw_spin_lock_irqsave(&irq->irq_lock,
> > > flags);
> > > +
> > > +			irq->priority = priority;
> > > +
> > > +			raw_spin_unlock_irqrestore(&irq-
> > > >irq_lock, flags);
> > > +			vgic_put_irq(vcpu->kvm, irq);
> > > +		}
> > > +	}
> > > +}
> > > +
> > > +bool vgic_v5_has_pending_ppi(struct kvm_vcpu *vcpu)
> > > +{
> > > +	struct vgic_v5_cpu_if *cpu_if = &vcpu-
> > > >arch.vgic_cpu.vgic_v5;
> > > +	unsigned long flags;
> > > +	int i, reg;
> > > +	unsigned int priority_mask;
> > > +
> > > +	/* If no pending bits are set, exit early */
> > > +	if (likely(!cpu_if->vgic_ppi_pendr[0] && !cpu_if-
> > > >vgic_ppi_pendr[1]))
> > > +		return false;
> > > +
> > > +	priority_mask =
> > > vgic_v5_get_effective_priority_mask(vcpu);
> > > +
> > > +	/* If the combined priority mask is 0, nothing can be
> > > signalled! */
> > > +	if (!priority_mask)
> > > +		return false;
> > > +
> > > +	/* The shadow priority is only updated on demand, sync
> > > it across first */
> > > +	vgic_v5_sync_ppi_priorities(vcpu);
> > > +
> > > +	for (reg = 0; reg < 2; reg++) {
> > > +		unsigned long possible_bits;
> > > +		const unsigned long enabler = cpu_if-
> > > >vgic_ich_ppi_enabler_exit[reg];
> > > +		const unsigned long pendr = cpu_if-
> > > >vgic_ppi_pendr_exit[reg];
> > > +		bool has_pending = false;
> > > +
> > > +		/* Check all interrupts that are enabled and
> > > pending */
> > > +		possible_bits = enabler & pendr;
> > > +
> > > +		/*
> > > +		 * Optimisation: pending and enabled with no
> > > active priorities
> > > +		 */
> > > +		if (possible_bits && priority_mask > 0x1f)
> > > +			return true;
> > > +
> > > +		for_each_set_bit(i, &possible_bits, 64) {
> > > +			struct vgic_irq *irq;
> > > +			u32 intid;
> > > +
> > > +			intid = FIELD_PREP(GICV5_HWIRQ_TYPE,
> > > GICV5_HWIRQ_TYPE_PPI);
> > > +			intid |= FIELD_PREP(GICV5_HWIRQ_ID, reg
> > > * 64 + i);
> > > +
> > > +			irq = vgic_get_vcpu_irq(vcpu, intid);
> > > +			raw_spin_lock_irqsave(&irq->irq_lock,
> > > flags);
> > > +
> > > +			/*
> > > +			 * We know that the interrupt is enabled
> > > and pending, so
> > > +			 * only check the priority.
> > > +			 */
> > > +			if (irq->priority <= priority_mask)
> > > +				has_pending = true;
> > > +
> > > +			raw_spin_unlock_irqrestore(&irq-
> > > >irq_lock, flags);
> > > +			vgic_put_irq(vcpu->kvm, irq);
> > > +
> > > +			if (has_pending)
> > > +				return true;
> > > +		}
> > > +	}
> > > +
> > > +	return false;
> > > +}
> > > +
> > > ?/*
> > > ? * Detect any PPIs state changes, and propagate the state with
> > > KVM's
> > > ? * shadow structures.
> > > diff --git a/arch/arm64/kvm/vgic/vgic.c
> > > b/arch/arm64/kvm/vgic/vgic.c
> > > index e534876656ca7..5d18a03cc11d5 100644
> > > --- a/arch/arm64/kvm/vgic/vgic.c
> > > +++ b/arch/arm64/kvm/vgic/vgic.c
> > > @@ -1174,11 +1174,15 @@ int kvm_vgic_vcpu_pending_irq(struct
> > > kvm_vcpu *vcpu)
> > > ?	unsigned long flags;
> > > ?	struct vgic_vmcr vmcr;
> > > ?
> > > -	if (!vcpu->kvm->arch.vgic.enabled)
> > > +	if (!vcpu->kvm->arch.vgic.enabled && !vgic_is_v5(vcpu-
> > > >kvm))
> > > ?		return false;
> > > ?
> > > -	if (vcpu->arch.vgic_cpu.vgic_v3.its_vpe.pending_last)
> > > -		return true;
> > > +	if (vcpu->kvm->arch.vgic.vgic_model ==
> > > KVM_DEV_TYPE_ARM_VGIC_V5) {
> > > +		return vgic_v5_has_pending_ppi(vcpu);
> > > +	} else {
> > > +		if (vcpu-
> > > >arch.vgic_cpu.vgic_v3.its_vpe.pending_last)
> > > +			return true;
> > > +	}
> > > ?
> > > ?	vgic_get_vmcr(vcpu, &vmcr);
> > > ?
> > > diff --git a/arch/arm64/kvm/vgic/vgic.h
> > > b/arch/arm64/kvm/vgic/vgic.h
> > > index 5a77318ddb87a..4b3a1e7ca3fb4 100644
> > > --- a/arch/arm64/kvm/vgic/vgic.h
> > > +++ b/arch/arm64/kvm/vgic/vgic.h
> > > @@ -387,6 +387,7 @@ void vgic_debug_destroy(struct kvm *kvm);
> > > ?int vgic_v5_probe(const struct gic_kvm_info *info);
> > > ?void vgic_v5_set_ppi_ops(struct vgic_irq *irq);
> > > ?int vgic_v5_set_ppi_dvi(struct kvm_vcpu *vcpu, u32 irq, bool
> > > dvi);
> > > +bool vgic_v5_has_pending_ppi(struct kvm_vcpu *vcpu);
> > > ?void vgic_v5_flush_ppi_state(struct kvm_vcpu *vcpu);
> > > ?void vgic_v5_fold_irq_state(struct kvm_vcpu *vcpu);
> > > ?void vgic_v5_load(struct kvm_vcpu *vcpu);
> > > -- 
> > > 2.34.1


From broonie at kernel.org  Thu Dec 18 00:21:37 2025
From: broonie at kernel.org (Mark Brown)
Date: Thu, 18 Dec 2025 08:21:37 +0000
Subject: [PATCH] spi: stm32-qspi: Remove unneeded semicolon
In-Reply-To: <20251217023721.1684244-1-nichen@iscas.ac.cn>
References: <20251217023721.1684244-1-nichen@iscas.ac.cn>
Message-ID: <176604609753.49312.11376425894198542181.b4-ty@kernel.org>

On Wed, 17 Dec 2025 10:37:21 +0800, Chen Ni wrote:
> Remove unnecessary semicolons reported by Coccinelle/coccicheck and the
> semantic patch at scripts/coccinelle/misc/semicolon.cocci.
> 
> 

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next

Thanks!

[1/1] spi: stm32-qspi: Remove unneeded semicolon
      commit: 7f7b350e4a65446f5d52ea8ae99e12eac8a972db

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark



From broonie at kernel.org  Thu Dec 18 00:21:39 2025
From: broonie at kernel.org (Mark Brown)
Date: Thu, 18 Dec 2025 08:21:39 +0000
Subject: [PATCH] spi: stm32-ospi: Remove unneeded semicolon
In-Reply-To: <20251216043210.1521722-1-nichen@iscas.ac.cn>
References: <20251216043210.1521722-1-nichen@iscas.ac.cn>
Message-ID: <176604609931.49312.660104330580864155.b4-ty@kernel.org>

On Tue, 16 Dec 2025 12:32:10 +0800, Chen Ni wrote:
> Remove unnecessary semicolons reported by Coccinelle/coccicheck and the
> semantic patch at scripts/coccinelle/misc/semicolon.cocci.
> 
> 

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next

Thanks!

[1/1] spi: stm32-ospi: Remove unneeded semicolon
      commit: d8ce99b0d384830b0eb6b907f5a428309c70af82

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark



From daniel at zonque.org  Thu Dec 18 00:21:29 2025
From: daniel at zonque.org (Daniel)
Date: Thu, 18 Dec 2025 09:21:29 +0100
Subject: [PATCH] ARM: dts: intel: Drop pxa2xx
In-Reply-To: <35405ed3-1319-4d3a-84a5-ad67f4c823ad@app.fastmail.com>
References: <20251212203226.458694-4-robh@kernel.org> <m2345fmkg7.fsf@free.fr>
 <35405ed3-1319-4d3a-84a5-ad67f4c823ad@app.fastmail.com>
Message-ID: <700e5050-aebe-4ca4-b02d-8ffacccf7045@zonque.org>

Hi,

On 12/17/25 17:04, Arnd Bergmann wrote:
> On Fri, Dec 12, 2025, at 22:58, Robert Jarzmik wrote:
>> "Rob Herring (Arm)" <robh at kernel.org> writes:
>>
>>> These .dtsi files are not included anywhere in the tree and 
>>> can't be tested. They have not been touched since 2018 other than 
>>> clean-ups.
>>>
>> And yet, there are used by people using pxa2xx board with an DT 
>> support (like the mioa701 for which a board file was never merged).
>>
>> If you remove pxa25x.dtsi and pxa27x.dtsi, you might as well 
>> remove all support for this architecture from the kernel, as
>> these are the building blocks needed to make it work.
>>
>> That might be what should be done, I'll let Arnd and Daniel 
>> comment on the future of PXA in the kernel.
> 
> I agree with Rob that at the very minimum, any dtsi files in the
> kernel should be build-tested along with the rest, so either
> we add some dts files using them soon, or we can remove pxa2xx
> (and maybe pxa3xx) completely.

PXA3xx is in use by the Raumfeld boards, and I would really like to keep
them around.

For PXA2xx I'm torn. I don't have the capacity and hardware to work on
those, but I don't know how many users are out there with out-of-tree
dts files.

> I already plan to remove the remaining board files for both
> sa1100 and pxa soon, as nobody has picked up the task to do
> any further DT conversion after we removed the majority of
> the files back in 2022 and left only the ones that someone
> said they'd be interested in keeping.
>
> Robert, let me know if you or someone else is able to spend
> some time on sending (warning-free) dts files for pxa2xx
> machines soon. If not, I'd plan to remove whatever is there
> along with the board files and drivers.
> 
> I also checked the pxa3xx Raumfeld devicetree support that
> Daniel added in linux-3.7. The manufacturer's firmware
> download page contains kernel images based on this work,
> using a 4.19 kernel but built in 2022. If we remove pxa2xx
> DT support, it would be good to find out if anyone still
> plans to use something newer on that hardware, which may
> happen because of CRA requirements.

As I said, I would like to not close the door on this one if possible.


Thanks,
Daniel



From david at kernel.org  Thu Dec 18 00:23:38 2025
From: david at kernel.org (David Hildenbrand (Red Hat))
Date: Thu, 18 Dec 2025 09:23:38 +0100
Subject: [PATCH v2 1/2] arm64: mmu: don't allocate page while spliting
 linear mapping
In-Reply-To: <20251217182007.2345700-2-yeoreum.yun@arm.com>
References: <20251217182007.2345700-1-yeoreum.yun@arm.com>
 <20251217182007.2345700-2-yeoreum.yun@arm.com>
Message-ID: <15777c12-d732-42e6-83da-61b3dca3764c@kernel.org>

On 12/17/25 19:20, Yeoreum Yun wrote:
> Current linear_map_split_to_ptes() allocate the pagetable
> while split linear mapping to ptes by stop_machine() with GFP_ATOMIC.
> 
> This is fine for non-PREEMPR_RT case.
> However It's a problem in PREEMPR_RT case since
> generic memory allocation/free APIs (e.x) pgtable_alloc(), __get_free_pages and etc
> couldn't be called in non-preemptible context except _nolock() APIs
> since generic memory allocation/free APIs are *sleepable* for using *spin_lock()*
> 
> IOW, calling a pgtable_alloc() even with GFP_ATOMIC
> doesn't allow in __linear_map_split_to_pte() executed by stopper thread
> where preemption is disabled in PREEMPR_RT.
> 
> To address this, divide linear_map_maybe_split_ptes:
>    - collect number of pages to require for spliting.

COLLECT step

>    - allocate the required number of pages for spliting.

PREALLOC step

>    - with pre-allocate page, split the linear map.

SPLIT step

The steps you have below are confusing :)

> +enum split_modes {

Is it a "mode" or a "step" ?

enum split_step {
	SPLIT_STEP_COLLECT,
	...
};


But reading the code below I am lost how these modes apply here.

I guess what you mean is something like

enum split_mode {
	SPLIT_MODE_ALLOC, /* ... from the buddy. */
	SPLIT_MODE_PREALLOCATED, /* ... from preallocated buffer. */
	SPLIT_MODE_COLLECT, /* collect required page tables. */
};

But why is SPLIT_MODE_ALLOC vs. SPLIT_MODE_PREALLOCATED required?

Can't we just test if there is something in the preallocated buffer, and 
if not, simply allocate?

IOW, all you need is "collect vs. alloc", and the buffer information 
tells you how to allocate.

> +	SPLIT_ALLOC,
> +	SPLIT_PREALLOC,
> +	SPLIT_COLLECT,
> +};
>   
> -	pa = page_to_phys(ptdesc_page(ptdesc));
> +struct split_args {
> +	enum split_modes mode;
> +	union {
> +		struct {
> +			unsigned long nr;
> +			unsigned long i;
> +			struct page **pages;
> +		};
> +		gfp_t gfp;
> +	};
> +};
>   
> +static __always_inline void __pgd_pgtable_init(struct mm_struct *mm,
> +					       struct ptdesc *ptdesc,
> +					       enum pgtable_type pgtable_type)
> +{
>   	switch (pgtable_type) {
>   	case TABLE_PTE:
>   		BUG_ON(!pagetable_pte_ctor(mm, ptdesc));
> @@ -554,19 +564,56 @@ static phys_addr_t __pgd_pgtable_alloc(struct mm_struct *mm, gfp_t gfp,
>   		break;
>   	}
>   
> +}
> +
> +static phys_addr_t __pgd_pgtable_alloc(struct mm_struct *mm, gfp_t gfp,
> +				       enum pgtable_type pgtable_type)
> +{
> +	/* Page is zeroed by init_clear_pgtable() so don't duplicate effort. */
> +	struct ptdesc *ptdesc = pagetable_alloc(gfp & ~__GFP_ZERO, 0);
> +	phys_addr_t pa;
> +
> +	if (!ptdesc)
> +		return INVALID_PHYS_ADDR;
> +
> +	pa = page_to_phys(ptdesc_page(ptdesc));
> +
> +	__pgd_pgtable_init(mm, ptdesc, pgtable_type);
> +
>   	return pa;
>   }
>   
> +static phys_addr_t __pgd_pgtable_prealloc(struct mm_struct *mm,
> +					  struct split_args *split_args,
> +					  enum pgtable_type pgtable_type)

The function is called "_prealloc" but actually it simply grabs a 
preallocated page. Confusing.


Should this function be called something like 
"__pgd_pgtable_get_preallocated()". Not sure.

> +{
> +	struct page *page;
> +
> +	BUG_ON(split_args->i >= split_args->nr);

No BUG_ON().

> +
> +	page = split_args->pages[split_args->i++];
> +	if (!page)
> +		return INVALID_PHYS_ADDR;
> +
> +	__pgd_pgtable_init(mm, page_ptdesc(page), pgtable_type);
> +
> +	return page_to_phys(page);
> +}
> +
>   static phys_addr_t
> -pgd_pgtable_alloc_init_mm_gfp(enum pgtable_type pgtable_type, gfp_t gfp)
> +pgd_pgtable_alloc_split(enum pgtable_type pgtable_type,
> +		        struct split_args *split_args)
>   {
> -	return __pgd_pgtable_alloc(&init_mm, gfp, pgtable_type);
> +	if (split_args->mode == SPLIT_ALLOC)
> +		return __pgd_pgtable_alloc(&init_mm, split_args->gfp, pgtable_type);
> +
> +	return __pgd_pgtable_prealloc(&init_mm, split_args, pgtable_type);
>   }
>   
>   static phys_addr_t __maybe_unused
>   pgd_pgtable_alloc_init_mm(enum pgtable_type pgtable_type)
>   {
> -	return pgd_pgtable_alloc_init_mm_gfp(pgtable_type, GFP_PGTABLE_KERNEL);
> +	return __pgd_pgtable_alloc(&init_mm, GFP_PGTABLE_KERNEL, pgtable_type);
>   }
>   
>   static phys_addr_t
> @@ -584,7 +631,9 @@ static void split_contpte(pte_t *ptep)
>   		__set_pte(ptep, pte_mknoncont(__ptep_get(ptep)));
>   }
>   
> -static int split_pmd(pmd_t *pmdp, pmd_t pmd, gfp_t gfp, bool to_cont)
> +static int split_pmd(pmd_t *pmdp, pmd_t pmd,
> +		     struct split_args *split_args,
> +		     bool to_cont)
>   {
>   	pmdval_t tableprot = PMD_TYPE_TABLE | PMD_TABLE_UXN | PMD_TABLE_AF;
>   	unsigned long pfn = pmd_pfn(pmd);
> @@ -593,7 +642,7 @@ static int split_pmd(pmd_t *pmdp, pmd_t pmd, gfp_t gfp, bool to_cont)
>   	pte_t *ptep;
>   	int i;
>   
> -	pte_phys = pgd_pgtable_alloc_init_mm_gfp(TABLE_PTE, gfp);
> +	pte_phys = pgd_pgtable_alloc_split(TABLE_PTE, split_args);
>   	if (pte_phys == INVALID_PHYS_ADDR)
>   		return -ENOMEM;
>   	ptep = (pte_t *)phys_to_virt(pte_phys);
> @@ -628,7 +677,9 @@ static void split_contpmd(pmd_t *pmdp)
>   		set_pmd(pmdp, pmd_mknoncont(pmdp_get(pmdp)));
>   }
>   
> -static int split_pud(pud_t *pudp, pud_t pud, gfp_t gfp, bool to_cont)
> +static int split_pud(pud_t *pudp, pud_t pud,
> +		    struct split_args *split_args,
> +		    bool to_cont)
>   {
>   	pudval_t tableprot = PUD_TYPE_TABLE | PUD_TABLE_UXN | PUD_TABLE_AF;
>   	unsigned int step = PMD_SIZE >> PAGE_SHIFT;
> @@ -638,7 +689,7 @@ static int split_pud(pud_t *pudp, pud_t pud, gfp_t gfp, bool to_cont)
>   	pmd_t *pmdp;
>   	int i;
>   
> -	pmd_phys = pgd_pgtable_alloc_init_mm_gfp(TABLE_PMD, gfp);
> +	pmd_phys = pgd_pgtable_alloc_split(TABLE_PMD, split_args);
>   	if (pmd_phys == INVALID_PHYS_ADDR)
>   		return -ENOMEM;
>   	pmdp = (pmd_t *)phys_to_virt(pmd_phys);
> @@ -672,6 +723,10 @@ static int split_kernel_leaf_mapping_locked(unsigned long addr)
>   	pmd_t *pmdp, pmd;
>   	pte_t *ptep, pte;
>   	int ret = 0;
> +	struct split_args split_args = {
> +		.mode = SPLIT_ALLOC,
> +		.gfp = GFP_PGTABLE_KERNEL,
> +	};
>   
>   	/*
>   	 * PGD: If addr is PGD aligned then addr already describes a leaf
> @@ -707,7 +762,7 @@ static int split_kernel_leaf_mapping_locked(unsigned long addr)
>   	if (!pud_present(pud))
>   		goto out;
>   	if (pud_leaf(pud)) {
> -		ret = split_pud(pudp, pud, GFP_PGTABLE_KERNEL, true);
> +		ret = split_pud(pudp, pud, &split_args, true);
>   		if (ret)
>   			goto out;
>   	}
> @@ -732,7 +787,7 @@ static int split_kernel_leaf_mapping_locked(unsigned long addr)
>   		 */
>   		if (ALIGN_DOWN(addr, PMD_SIZE) == addr)
>   			goto out;
> -		ret = split_pmd(pmdp, pmd, GFP_PGTABLE_KERNEL, true);
> +		ret = split_pmd(pmdp, pmd, &split_args, true);
>   		if (ret)
>   			goto out;
>   	}
> @@ -831,12 +886,17 @@ int split_kernel_leaf_mapping(unsigned long start, unsigned long end)
>   static int split_to_ptes_pud_entry(pud_t *pudp, unsigned long addr,
>   				   unsigned long next, struct mm_walk *walk)
>   {
> -	gfp_t gfp = *(gfp_t *)walk->private;
> +	struct split_args *split_args = (struct split_args *)walk->private;
>   	pud_t pud = pudp_get(pudp);
>   	int ret = 0;
>   
> -	if (pud_leaf(pud))
> -		ret = split_pud(pudp, pud, gfp, false);
> +	if (!pud_leaf(pud))
> +		return 0;
> +
> +	if (split_args->mode == SPLIT_COLLECT)
> +		split_args->nr++;
> +	else
> +		ret = split_pud(pudp, pud, split_args, false);
>   
>   	return ret;
>   }
> @@ -844,22 +904,29 @@ static int split_to_ptes_pud_entry(pud_t *pudp, unsigned long addr,
>   static int split_to_ptes_pmd_entry(pmd_t *pmdp, unsigned long addr,
>   				   unsigned long next, struct mm_walk *walk)
>   {
> -	gfp_t gfp = *(gfp_t *)walk->private;
> +	struct split_args *split_args = (struct split_args *)walk->private;
>   	pmd_t pmd = pmdp_get(pmdp);
> -	int ret = 0;
> +	int ret;
>   
> -	if (pmd_leaf(pmd)) {
> -		if (pmd_cont(pmd))
> -			split_contpmd(pmdp);
> -		ret = split_pmd(pmdp, pmd, gfp, false);
> +	if (!pmd_leaf(pmd))
> +		return 0;
>   
> -		/*
> -		 * We have split the pmd directly to ptes so there is no need to
> -		 * visit each pte to check if they are contpte.
> -		 */
> -		walk->action = ACTION_CONTINUE;
> +	if (split_args->mode == SPLIT_COLLECT) {
> +		split_args->nr++;
> +		return 0;
>   	}
>   
> +	if (pmd_cont(pmd))
> +		split_contpmd(pmdp);
> +	ret = split_pmd(pmdp, pmd, split_args, false);
> +
> +	/*
> +	 * We have split the pmd directly to ptes so there is no need to
> +	 * visit each pte to check if they are contpte.
> +	 */
> +	walk->action = ACTION_CONTINUE;
> +
> +
>   	return ret;
>   }
>   
> @@ -880,13 +947,15 @@ static const struct mm_walk_ops split_to_ptes_ops = {
>   	.pte_entry	= split_to_ptes_pte_entry,
>   };
>   
> -static int range_split_to_ptes(unsigned long start, unsigned long end, gfp_t gfp)
> +static int range_split_to_ptes(unsigned long start, unsigned long end,
> +		 	       struct split_args *split_args)
>   {
>   	int ret;
>   
>   	arch_enter_lazy_mmu_mode();
>   	ret = walk_kernel_page_table_range_lockless(start, end,
> -					&split_to_ptes_ops, NULL, &gfp);
> +						    &split_to_ptes_ops, NULL,
> +						    split_args);
>   	arch_leave_lazy_mmu_mode();
>   
>   	return ret;
> @@ -903,7 +972,7 @@ static void __init init_idmap_kpti_bbml2_flag(void)
>   	smp_mb();
>   }
>   
> -static int __init linear_map_split_to_ptes(void *__unused)
> +static int __init linear_map_split_to_ptes(void *data)
>   {
>   	/*
>   	 * Repainting the linear map must be done by CPU0 (the boot CPU) because
> @@ -911,6 +980,7 @@ static int __init linear_map_split_to_ptes(void *__unused)
>   	 * be held in a waiting area with the idmap active.
>   	 */
>   	if (!smp_processor_id()) {
> +		struct split_args *split_args = data;
>   		unsigned long lstart = _PAGE_OFFSET(vabits_actual);
>   		unsigned long lend = PAGE_END;
>   		unsigned long kstart = (unsigned long)lm_alias(_stext);
> @@ -928,12 +998,13 @@ static int __init linear_map_split_to_ptes(void *__unused)
>   		 * PTE. The kernel alias remains static throughout runtime so
>   		 * can continue to be safely mapped with large mappings.
>   		 */
> -		ret = range_split_to_ptes(lstart, kstart, GFP_ATOMIC);
> +		ret = range_split_to_ptes(lstart, lend, split_args);
>   		if (!ret)
> -			ret = range_split_to_ptes(kend, lend, GFP_ATOMIC);
> +			ret = range_split_to_ptes(kstart, kend, split_args);
>   		if (ret)
>   			panic("Failed to split linear map\n");
> -		flush_tlb_kernel_range(lstart, lend);
> +		if (split_args->mode != SPLIT_COLLECT)
> +			flush_tlb_kernel_range(lstart, lend);
>   
>   		/*
>   		 * Relies on dsb in flush_tlb_kernel_range() to avoid reordering
> @@ -963,10 +1034,61 @@ static int __init linear_map_split_to_ptes(void *__unused)
>   
>   void __init linear_map_maybe_split_to_ptes(void)
>   {
> -	if (linear_map_requires_bbml2 && !system_supports_bbml2_noabort()) {
> -		init_idmap_kpti_bbml2_flag();
> -		stop_machine(linear_map_split_to_ptes, NULL, cpu_online_mask);
> +	struct page **pages = NULL;
> +	struct split_args split_args;
> +	int order;
> +	int nr_populated;
> +	int err;
> +
> +	if (!linear_map_requires_bbml2 || system_supports_bbml2_noabort())
> +		return;
> +
> +	/*
> +	 * Phase 1: Collect required extra pages to split.
> +	 */
> +	split_args.mode = SPLIT_COLLECT;
> +	split_args.nr = 0;
> +
> +	init_idmap_kpti_bbml2_flag();
> +	stop_machine(linear_map_split_to_ptes, &split_args, cpu_online_mask);
> +
> +	/*
> +	 * Phase 2: Allocate necessary pages to split.
> +	 */
> +	if (split_args.nr == 0) {
> +		err = 0;
> +		split_args.mode = SPLIT_ALLOC;
> +	} else {
> +		err = -ENOMEM;
> +		order = order_base_2(PAGE_ALIGN(split_args.nr *
> +					sizeof(struct page *)) >> PAGE_SHIFT);
> +
> +		pages = (struct page **)__get_free_pages(GFP_ATOMIC | __GFP_ZERO, order);
> +		if (!pages)
> +			goto error;
> +
> +		nr_populated = alloc_pages_bulk(GFP_ATOMIC | __GFP_ZERO, split_args.nr, pages);
> +		if (nr_populated < split_args.nr)
> +			goto error;

That is prone to cause trouble in the future once we allocate memdescs 
separately.

Can we simply call pagetable_alloc() in a loop here instead for the time 
being? A future-proof bulk allocation can be done later separately.

-- 
Cheers

David


From ryan.roberts at arm.com  Thu Dec 18 00:32:06 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Thu, 18 Dec 2025 08:32:06 +0000
Subject: [PATCH v2 2/2] arm64: mmu: avoid allocating pages while
 installing ng-mapping for KPTI
In-Reply-To: <586d24f9-a54d-4c14-bd25-fed18423d709@suse.cz>
References: <20251217182007.2345700-1-yeoreum.yun@arm.com>
 <20251217182007.2345700-3-yeoreum.yun@arm.com>
 <731e3f48-e0a3-4c89-a13a-65ef37faa443@arm.com>
 <586d24f9-a54d-4c14-bd25-fed18423d709@suse.cz>
Message-ID: <d4dce109-8e02-488b-8ede-ef568f7262be@arm.com>

On 18/12/2025 07:51, Vlastimil Babka wrote:
> On 12/17/25 20:03, Ryan Roberts wrote:
>> On 17/12/2025 18:20, Yeoreum Yun wrote:
>>> The current __kpti_install_ng_mappings() allocates a temporary PGD
>>> while installing the NG mapping for KPTI under stop_machine(),
>>> using GFP_ATOMIC.
>>>
>>> This is fine in the non-PREEMPT_RT case. However, it becomes a problem
>>> under PREEMPT_RT because generic memory allocation/free APIs
>>> (e.g., pgtable_alloc(), __get_free_pages(), etc.) cannot be invoked
>>> in a non-preemptible context, except for the *_nolock() variants.
>>> These generic allocators may sleep due to their use of spin_lock().
>>>
>>> In other words, calling __get_free_pages(), even with GFP_ATOMIC,
>>> is not allowed in __kpti_install_ng_mappings(), which is executed by
>>> the stopper thread where preemption is disabled under PREEMPT_RT.
>>>
>>> To address this, preallocate the page needed for the temporary PGD
>>> before invoking __kpti_install_ng_mappings() via stop_machine().
>>>
>>> Fixes: 47546a1912fc ("arm64: mm: install KPTI nG mappings with MMU enabled")
>>> Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
>>> ---
>>>  arch/arm64/mm/mmu.c | 22 +++++++++++++---------
>>>  1 file changed, 13 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
>>> index e4e6c7e0a016..69d9651de0cd 100644
>>> --- a/arch/arm64/mm/mmu.c
>>> +++ b/arch/arm64/mm/mmu.c
>>> @@ -1360,7 +1360,7 @@ static phys_addr_t __init kpti_ng_pgd_alloc(enum pgtable_type type)
>>>  	return kpti_ng_temp_alloc;
>>>  }
>>>  
>>> -static int __init __kpti_install_ng_mappings(void *__unused)
>>> +static int __init __kpti_install_ng_mappings(void *data)
>>>  {
>>>  	typedef void (kpti_remap_fn)(int, int, phys_addr_t, unsigned long);
>>>  	extern kpti_remap_fn idmap_kpti_install_ng_mappings;
>>> @@ -1368,10 +1368,9 @@ static int __init __kpti_install_ng_mappings(void *__unused)
>>>  
>>>  	int cpu = smp_processor_id();
>>>  	int levels = CONFIG_PGTABLE_LEVELS;
>>> -	int order = order_base_2(levels);
>>>  	u64 kpti_ng_temp_pgd_pa = 0;
>>>  	pgd_t *kpti_ng_temp_pgd;
>>> -	u64 alloc = 0;
>>> +	u64 alloc = *(u64 *)data;
>>>  
>>>  	if (levels == 5 && !pgtable_l5_enabled())
>>>  		levels = 4;
>>> @@ -1382,8 +1381,6 @@ static int __init __kpti_install_ng_mappings(void *__unused)
>>>  
>>>  	if (!cpu) {
>>>  		int ret;
>>> -
>>> -		alloc = __get_free_pages(GFP_ATOMIC | __GFP_ZERO, order);
>>>  		kpti_ng_temp_pgd = (pgd_t *)(alloc + (levels - 1) * PAGE_SIZE);
>>>  		kpti_ng_temp_alloc = kpti_ng_temp_pgd_pa = __pa(kpti_ng_temp_pgd);
>>>  
>>> @@ -1414,16 +1411,17 @@ static int __init __kpti_install_ng_mappings(void *__unused)
>>>  	remap_fn(cpu, num_online_cpus(), kpti_ng_temp_pgd_pa, KPTI_NG_TEMP_VA);
>>>  	cpu_uninstall_idmap();
>>>  
>>> -	if (!cpu) {
>>> -		free_pages(alloc, order);
>>> +	if (!cpu)
>>>  		arm64_use_ng_mappings = true;
>>> -	}
>>>  
>>>  	return 0;
>>>  }
>>>  
>>>  void __init kpti_install_ng_mappings(void)
>>>  {
>>> +	int order = order_base_2(CONFIG_PGTABLE_LEVELS);
>>> +	u64 alloc;
>>> +
>>>  	/* Check whether KPTI is going to be used */
>>>  	if (!arm64_kernel_unmapped_at_el0())
>>>  		return;
>>> @@ -1436,8 +1434,14 @@ void __init kpti_install_ng_mappings(void)
>>>  	if (arm64_use_ng_mappings)
>>>  		return;
>>>  
>>> +	alloc = __get_free_pages(GFP_ATOMIC | __GFP_ZERO, order);
>>
>> I don't think this requires GFP_ATOMIC now?
> 
> Do you mean it's fine to use GFP_KERNEL now, or still not, and you mean that
> GFP_NOWAIT is sufficient?

I mean it's fine to use "GFP_KERNEL | __GFP_ZERO"; this context can sleep so we
don't want to dip into the reserves - we can sleep and reclaim if needed.

> 
>> With that removed:
>>
>> Reviewed-by: Ryan Roberts <ryan.roberts at arm.com>
>>
>>> +	if (!alloc)
>>> +		panic("Failed to alloc page tables\n");
>>> +
>>>  	init_idmap_kpti_bbml2_flag();
>>> -	stop_machine(__kpti_install_ng_mappings, NULL, cpu_online_mask);
>>> +	stop_machine(__kpti_install_ng_mappings, &alloc, cpu_online_mask);
>>> +
>>> +	free_pages(alloc, order);
>>>  }
>>>  
>>>  static pgprot_t __init kernel_exec_prot(void)
>>
> 



From ryan.roberts at arm.com  Thu Dec 18 00:34:01 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Thu, 18 Dec 2025 08:34:01 +0000
Subject: [PATCH v2 2/2] arm64: mmu: avoid allocating pages while
 installing ng-mapping for KPTI
In-Reply-To: <aUL/zJlJFRz2/Ybt@e129823.arm.com>
References: <20251217182007.2345700-1-yeoreum.yun@arm.com>
 <20251217182007.2345700-3-yeoreum.yun@arm.com>
 <731e3f48-e0a3-4c89-a13a-65ef37faa443@arm.com>
 <aUL/zJlJFRz2/Ybt@e129823.arm.com>
Message-ID: <72aaa252-6ee6-4353-84ee-b6e10e9920c6@arm.com>

On 17/12/2025 19:09, Yeoreum Yun wrote:
> Hi Ryanc,
> 
> [...]
>>> -	if (!cpu) {
>>> -		free_pages(alloc, order);
>>> +	if (!cpu)
>>>  		arm64_use_ng_mappings = true;
>>> -	}
>>>
>>>  	return 0;
>>>  }
>>>
>>>  void __init kpti_install_ng_mappings(void)
>>>  {
>>> +	int order = order_base_2(CONFIG_PGTABLE_LEVELS);
>>> +	u64 alloc;
>>> +
>>>  	/* Check whether KPTI is going to be used */
>>>  	if (!arm64_kernel_unmapped_at_el0())
>>>  		return;
>>> @@ -1436,8 +1434,14 @@ void __init kpti_install_ng_mappings(void)
>>>  	if (arm64_use_ng_mappings)
>>>  		return;
>>>
>>> +	alloc = __get_free_pages(GFP_ATOMIC | __GFP_ZERO, order);
>>
>> I don't think this requires GFP_ATOMIC now?
>>
>> With that removed:
>>
>> Reviewed-by: Ryan Roberts <ryan.roberts at arm.com>
> 
> I think it would be better to use only __GFP_HIGH in here since
> when kpti_install_ng_mappings() is called, "kswpd" doesn't created yet.
> and to allocate page with assurance, It would be good to use
> min_reserved to.
> 
> Am I missing something?

Personally I think we should just use "GFP_KERNEL | __GFP_ZERO". Anything else
would make this allocation look special, which it is not. If we fail to allocate
at this point in boot, we have bigger problems.

> 
> Thanks.
> 
> [...]
> 
> --
> Sincerely,
> Yeoreum Yun



From yeoreum.yun at arm.com  Thu Dec 18 00:37:07 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Thu, 18 Dec 2025 08:37:07 +0000
Subject: [PATCH v2 2/2] arm64: mmu: avoid allocating pages while
 installing ng-mapping for KPTI
In-Reply-To: <72aaa252-6ee6-4353-84ee-b6e10e9920c6@arm.com>
References: <20251217182007.2345700-1-yeoreum.yun@arm.com>
 <20251217182007.2345700-3-yeoreum.yun@arm.com>
 <731e3f48-e0a3-4c89-a13a-65ef37faa443@arm.com>
 <aUL/zJlJFRz2/Ybt@e129823.arm.com>
 <72aaa252-6ee6-4353-84ee-b6e10e9920c6@arm.com>
Message-ID: <aUO9M/oN+nx3nfW+@e129823.arm.com>

[...]
> > I think it would be better to use only __GFP_HIGH in here since
> > when kpti_install_ng_mappings() is called, "kswpd" doesn't created yet.
> > and to allocate page with assurance, It would be good to use
> > min_reserved to.
> >
> > Am I missing something?
>
> Personally I think we should just use "GFP_KERNEL | __GFP_ZERO". Anything else
> would make this allocation look special, which it is not. If we fail to allocate
> at this point in boot, we have bigger problems.

But I'm not sure *HOW effective* to use GFP_KERNEL in here.
Since it's before the any filesystem inited.
IOW, in this context, almost there would be no *page cache*
and I think it seems meaningless to use "GFP_KERNEL" and "direct
reclaim"

So to get success for allocation, __GFP_HIGH | _GFP_ZERO seems much
better.

Thanks


--
Sincerely,
Yeoreum Yun


From alain.volmat at foss.st.com  Thu Dec 18 00:38:40 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Thu, 18 Dec 2025 09:38:40 +0100
Subject: [PATCH 3/4] spi: stm32: properly fail on dma_request_chan error
In-Reply-To: <129a4deb-ec9c-41f0-910c-57cd43d17fcd@sirena.org.uk>
References: <20251217-stm32-spi-enhancements-v1-0-943348b8ff66@foss.st.com>
 <20251217-stm32-spi-enhancements-v1-3-943348b8ff66@foss.st.com>
 <129a4deb-ec9c-41f0-910c-57cd43d17fcd@sirena.org.uk>
Message-ID: <20251218083840.GA1530150@gnbcxd0016.gnb.st.com>

Hi Mark,

On Thu, Dec 18, 2025 at 08:00:57AM +0000, Mark Brown wrote:
> On Wed, Dec 17, 2025 at 10:51:33PM +0100, Alain Volmat wrote:
> > Correct handling of the dma_request_chan call in order to avoid
> > misleading warn message if no DMA is provided within the device-tree
> > and moreover fail if dma_request_chan has returned a valid error.
> 
> Bug fixes should go at the start of serieses to avoid spurious
> dependencies on new or cleanup changes.

Actually I wasn't thinking about requiring this commit to go into
stable branches. Without commit, the driver will still work even if
there is an issue to request a dma channel since it will fallback to
interrupt based transfers.
This commit makes the error visible now, ensuring that if the
device-tree indicates that a DMA should be used, it will either be used
or probe will fail.

Alain


From tomi.valkeinen at ideasonboard.com  Thu Dec 18 00:39:37 2025
From: tomi.valkeinen at ideasonboard.com (Tomi Valkeinen)
Date: Thu, 18 Dec 2025 10:39:37 +0200
Subject: [PATCH] dmaengine: xilinx_dma: Add support for residue on direct
 AXIDMA S2MM
Message-ID: <20251218-xilinx-dma-residue-fix-v1-1-7cd221d69d6b@ideasonboard.com>

AXIDMA IP supports reporting the amount of bytes transferred on the S2MM
channel in direct mode (i.e. non-SG), but the driver does not. Thus the
driver always reports that all of the buffer was filled.

Add xilinx_dma_get_residue_axidma_direct_s2mm() which gets the residue
amount for direct AXIDMA for S2MM direction.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
---
 drivers/dma/xilinx/xilinx_dma.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index fabff602065f..64b3fba4e44f 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -1021,6 +1021,24 @@ static u32 xilinx_dma_get_residue(struct xilinx_dma_chan *chan,
 	return residue;
 }
 
+static u32
+xilinx_dma_get_residue_axidma_direct_s2mm(struct xilinx_dma_chan *chan,
+					  struct xilinx_dma_tx_descriptor *desc)
+{
+	struct xilinx_axidma_tx_segment *seg;
+	struct xilinx_axidma_desc_hw *hw;
+	u32 finished_len;
+
+	finished_len = dma_ctrl_read(chan, XILINX_DMA_REG_BTT);
+
+	seg = list_first_entry(&desc->segments, struct xilinx_axidma_tx_segment,
+			       node);
+
+	hw = &seg->hw;
+
+	return hw->control - finished_len;
+}
+
 /**
  * xilinx_dma_chan_handle_cyclic - Cyclic dma callback
  * @chan: Driver specific dma channel
@@ -1732,6 +1750,9 @@ static void xilinx_dma_complete_descriptor(struct xilinx_dma_chan *chan)
 		if (chan->has_sg && chan->xdev->dma_config->dmatype !=
 		    XDMA_TYPE_VDMA)
 			desc->residue = xilinx_dma_get_residue(chan, desc);
+		else if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA &&
+			 chan->direction == DMA_DEV_TO_MEM && !chan->has_sg)
+			desc->residue = xilinx_dma_get_residue_axidma_direct_s2mm(chan, desc);
 		else
 			desc->residue = 0;
 		desc->err = chan->err;

---
base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
change-id: 20251218-xilinx-dma-residue-fix-f6e4f97ffe61

Best regards,
-- 
Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>



From leon at kernel.org  Thu Dec 18 00:40:02 2025
From: leon at kernel.org (Leon Romanovsky)
Date: Thu, 18 Dec 2025 10:40:02 +0200
Subject: [PATCH v5 09/14] parisc: Convert DMA map_page to map_phys
 interface [qemu test failure]
In-Reply-To: <b184f1bf-96dc-4546-8512-9cba5ecb58f7@roeck-us.net>
References: <20251015-remove-map-page-v5-0-3bbfe3a25cdf@kernel.org>
 <20251015-remove-map-page-v5-9-3bbfe3a25cdf@kernel.org>
 <b184f1bf-96dc-4546-8512-9cba5ecb58f7@roeck-us.net>
Message-ID: <20251218084002.GD39046@unreal>

On Wed, Dec 17, 2025 at 04:17:38AM -0800, Guenter Roeck wrote:
> Hi,
> 
> On Wed, Oct 15, 2025 at 12:12:55PM +0300, Leon Romanovsky wrote:
> > From: Leon Romanovsky <leonro at nvidia.com>
> > 
> > Perform mechanical conversion from .map_page to .map_phys callback.
> > 
> > Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
> > Signed-off-by: Leon Romanovsky <leonro at nvidia.com>
> 
> This patch causes all my 32-bit parisc qemu tests with C3700 machine
> to fail. Network interface tests fail, and all boot attempts from
> any kind of hard drive (scsi, usb) fail with this patch in the tree.

Thanks for the report. I have a fix ready; I'll clean it up and send it out
by EOD.

> 
> Guenter


From tomasz.jaworski at torqly.pl  Thu Dec 18 00:41:00 2025
From: tomasz.jaworski at torqly.pl (Tomasz Jaworski)
Date: Thu, 18 Dec 2025 08:41:00 GMT
Subject: =?UTF-8?Q?Ulga_na_sk=C5=82adki_ZUS?=
Message-ID: <20251218084500-0.1.tu.d9iig.0.cnjfo24rna@torqly.pl>

Dzie? dobry, 

chcia?bym wskaza? Pa?stwu mo?liwo?? zarz?dzania benefitami w ?atwy spos?b, poprzez nasze intuicyjne narz?dzie, jakim jest karta lunchowa. 

Nasze karty oferuj? wygod?, oszcz?dno?ci i zdrowe wybory ?ywieniowe. Dofinansowanie posi?k?w jest korzystne dla obu stron. Karty lunch to dla pracodawcy realne oszcz?dno?ci w postaci zwolnienia z ZUS do 450 z? miesi?cznie na pracownika. 

Kart? mo?na do?adowa? dowoln? kwot?, a niewykorzystane ?rodki nie przepadaj?, lecz przechodz? na kolejny miesi?c. 

Mog? przedstawi? ofert?, kt?ra pozwoli zoptymalizowa? koszty i zapewni? pracownikom po??dany benefit?


Pozdrawiam
Tomasz Jaworski


From david at kernel.org  Thu Dec 18 00:46:10 2025
From: david at kernel.org (David Hildenbrand (Red Hat))
Date: Thu, 18 Dec 2025 09:46:10 +0100
Subject: [PATCH v2 2/2] arm64: mmu: avoid allocating pages while
 installing ng-mapping for KPTI
In-Reply-To: <aUO9M/oN+nx3nfW+@e129823.arm.com>
References: <20251217182007.2345700-1-yeoreum.yun@arm.com>
 <20251217182007.2345700-3-yeoreum.yun@arm.com>
 <731e3f48-e0a3-4c89-a13a-65ef37faa443@arm.com>
 <aUL/zJlJFRz2/Ybt@e129823.arm.com>
 <72aaa252-6ee6-4353-84ee-b6e10e9920c6@arm.com>
 <aUO9M/oN+nx3nfW+@e129823.arm.com>
Message-ID: <201d0fa3-2ebe-4df2-926c-9e11607a6f07@kernel.org>

On 12/18/25 09:37, Yeoreum Yun wrote:
> [...]
>>> I think it would be better to use only __GFP_HIGH in here since
>>> when kpti_install_ng_mappings() is called, "kswpd" doesn't created yet.
>>> and to allocate page with assurance, It would be good to use
>>> min_reserved to.
>>>
>>> Am I missing something?
>>
>> Personally I think we should just use "GFP_KERNEL | __GFP_ZERO". Anything else
>> would make this allocation look special, which it is not. If we fail to allocate
>> at this point in boot, we have bigger problems.
> 
> But I'm not sure *HOW effective* to use GFP_KERNEL in here.
> Since it's before the any filesystem inited.
> IOW, in this context, almost there would be no *page cache*
> and I think it seems meaningless to use "GFP_KERNEL" and "direct
> reclaim"
> 
> So to get success for allocation, __GFP_HIGH | _GFP_ZERO seems much
> better.

Unless there is a real reason to confuse readers why this is very 
special, just go with "GFP_KERNEL | __GFP_ZERO", really.

In particular if it doesn't matter in practice? Or does it and we are 
not getting your point?

-- 
Cheers

David


From jonathanh at nvidia.com  Thu Dec 18 00:48:32 2025
From: jonathanh at nvidia.com (Jon Hunter)
Date: Thu, 18 Dec 2025 08:48:32 +0000
Subject: [PATCH V7 2/4] iommu/arm-smmu-v3: Add device-tree support for
 CMDQV driver
In-Reply-To: <5e9a0ce1-a0ba-4a31-be95-99f349ec6028@nvidia.com>
References: <20251215064819.3345361-1-amhetre@nvidia.com>
 <20251215064819.3345361-3-amhetre@nvidia.com>
 <23df682e-6d08-4827-994e-1bbd89e5c903@nvidia.com>
 <5e9a0ce1-a0ba-4a31-be95-99f349ec6028@nvidia.com>
Message-ID: <e7d3e95f-a885-4b13-ab4d-bc82793c5396@nvidia.com>


On 18/12/2025 06:32, Ashish Mhetre wrote:
> 
> On 12/18/2025 2:13 AM, Jon Hunter wrote:
>>
>>
>> On 15/12/2025 06:48, Ashish Mhetre wrote:
>>> Add device tree support to the CMDQV driver to enable usage on Tegra264
>>> SoCs. The implementation parses the nvidia,cmdqv phandle from the SMMU
>>> device tree node to associate each SMMU with its corresponding CMDQV
>>> instance based on compatible string.
>>>
>>> Reviewed-by: Nicolin Chen <nicolinc at nvidia.com>
>>> Signed-off-by: Ashish Mhetre <amhetre at nvidia.com>
>>> ---
>>> ? drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 32 +++++++++++++++++++++
>>> ? 1 file changed, 32 insertions(+)
>>>
>>> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/ 
>>> iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>>> index dad3c0cb800b..0cd0013200f3 100644
>>> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>>> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>>> @@ -4530,6 +4530,35 @@ static int arm_smmu_device_hw_probe(struct 
>>> arm_smmu_device *smmu)
>>> ????? return 0;
>>> ? }
>>> ? +#ifdef CONFIG_TEGRA241_CMDQV
>>> +static void tegra_cmdqv_dt_probe(struct device_node *smmu_node,
>>> +???????????????? struct arm_smmu_device *smmu)
>>> +{
>>> +??? struct platform_device *pdev;
>>> +??? struct device_node *np;
>>> +
>>> +??? np = of_parse_phandle(smmu_node, "nvidia,cmdqv", 0);
>>> +??? if (!np)
>>> +??????? return;
>>> +
>>> +??? /* Tegra241 CMDQV driver is responsible for put_device() */
>>> +??? pdev = of_find_device_by_node(np);
>>> +??? of_node_put(np);
>>> +??? if (!pdev)
>>> +??????? return;
>>> +
>>> +??? smmu->impl_dev = &pdev->dev;
>>> +??? smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
>>> +??? dev_info(smmu->dev, "found companion CMDQV device: %s\n",
>>> +???????? dev_name(smmu->impl_dev));
>>
>> This seems a bit noisy. dev_dbg?
>>
> 
> This info print is similar to what is there in ACPI path as well.
> It's only a single print per SMMU at boot time. Should I still change
> it to dev_dbg?

Yes, I would.

Jon

-- 
nvpublic



From broonie at kernel.org  Thu Dec 18 00:57:36 2025
From: broonie at kernel.org (Mark Brown)
Date: Thu, 18 Dec 2025 08:57:36 +0000
Subject: [PATCH 3/4] spi: stm32: properly fail on dma_request_chan error
In-Reply-To: <20251218083840.GA1530150@gnbcxd0016.gnb.st.com>
References: <20251217-stm32-spi-enhancements-v1-0-943348b8ff66@foss.st.com>
 <20251217-stm32-spi-enhancements-v1-3-943348b8ff66@foss.st.com>
 <129a4deb-ec9c-41f0-910c-57cd43d17fcd@sirena.org.uk>
 <20251218083840.GA1530150@gnbcxd0016.gnb.st.com>
Message-ID: <6c153ddd-a586-4138-b3c4-793278d93305@sirena.org.uk>

On Thu, Dec 18, 2025 at 09:38:40AM +0100, Alain Volmat wrote:
> On Thu, Dec 18, 2025 at 08:00:57AM +0000, Mark Brown wrote:

> > Bug fixes should go at the start of serieses to avoid spurious
> > dependencies on new or cleanup changes.

> Actually I wasn't thinking about requiring this commit to go into
> stable branches. Without commit, the driver will still work even if
> there is an issue to request a dma channel since it will fallback to
> interrupt based transfers.
> This commit makes the error visible now, ensuring that if the
> device-tree indicates that a DMA should be used, it will either be used
> or probe will fail.

I'd not send it to stable either (admittedly I generally stopped tagging
stuff for stable entirely) but I will apply it for v6.19.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251218/0585e96f/attachment.sig>

From alain.volmat at foss.st.com  Thu Dec 18 01:01:47 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Thu, 18 Dec 2025 10:01:47 +0100
Subject: [PATCH 3/4] spi: stm32: properly fail on dma_request_chan error
In-Reply-To: <6c153ddd-a586-4138-b3c4-793278d93305@sirena.org.uk>
References: <20251217-stm32-spi-enhancements-v1-0-943348b8ff66@foss.st.com>
 <20251217-stm32-spi-enhancements-v1-3-943348b8ff66@foss.st.com>
 <129a4deb-ec9c-41f0-910c-57cd43d17fcd@sirena.org.uk>
 <20251218083840.GA1530150@gnbcxd0016.gnb.st.com>
 <6c153ddd-a586-4138-b3c4-793278d93305@sirena.org.uk>
Message-ID: <20251218090147.GA1530303@gnbcxd0016.gnb.st.com>

On Thu, Dec 18, 2025 at 08:57:36AM +0000, Mark Brown wrote:
> On Thu, Dec 18, 2025 at 09:38:40AM +0100, Alain Volmat wrote:
> > On Thu, Dec 18, 2025 at 08:00:57AM +0000, Mark Brown wrote:
> 
> > > Bug fixes should go at the start of serieses to avoid spurious
> > > dependencies on new or cleanup changes.
> 
> > Actually I wasn't thinking about requiring this commit to go into
> > stable branches. Without commit, the driver will still work even if
> > there is an issue to request a dma channel since it will fallback to
> > interrupt based transfers.
> > This commit makes the error visible now, ensuring that if the
> > device-tree indicates that a DMA should be used, it will either be used
> > or probe will fail.
> 
> I'd not send it to stable either (admittedly I generally stopped tagging
> stuff for stable entirely) but I will apply it for v6.19.

Alright. Thanks. Let me send a v2, putting this patch in front of the
serie.


From nicolas.ferre at microchip.com  Thu Dec 18 01:05:11 2025
From: nicolas.ferre at microchip.com (Nicolas Ferre)
Date: Thu, 18 Dec 2025 10:05:11 +0100
Subject: [PATCH v2 1/3] dt-bindings: mfd: atmel,hlcdc: Add sama7d65
 compatible string
In-Reply-To: <20251218040521.463937-1-manikandan.m@microchip.com>
References: <20251218040521.463937-1-manikandan.m@microchip.com>
Message-ID: <c60323c4-a938-4ceb-b0f4-82166ebfb2ad@microchip.com>

On 18/12/2025 at 05:05, Manikandan Muralidharan wrote:
> Add LCD compatible string for sama7d65.
> 
> Signed-off-by: Manikandan Muralidharan <manikandan.m at microchip.com>
> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Acked-by: Nicolas Ferre <nicolas.ferre at microchip.com>
> ---
>   Documentation/devicetree/bindings/mfd/atmel,hlcdc.yaml | 1 +
>   1 file changed, 1 insertion(+)
> 
> diff --git a/Documentation/devicetree/bindings/mfd/atmel,hlcdc.yaml b/Documentation/devicetree/bindings/mfd/atmel,hlcdc.yaml
> index 4aa36903e755..dfee8707bac2 100644
> --- a/Documentation/devicetree/bindings/mfd/atmel,hlcdc.yaml
> +++ b/Documentation/devicetree/bindings/mfd/atmel,hlcdc.yaml
> @@ -25,6 +25,7 @@ properties:
>         - atmel,sama5d4-hlcdc
>         - microchip,sam9x60-hlcdc
>         - microchip,sam9x75-xlcdc
> +      - microchip,sama7d65-xlcdc
>   
>     reg:
>       maxItems: 1
> 
> base-commit: e8c28e16c3ebd142938aee296032c6b802a5a1d4



From nicolas.ferre at microchip.com  Thu Dec 18 01:05:24 2025
From: nicolas.ferre at microchip.com (Nicolas Ferre)
Date: Thu, 18 Dec 2025 10:05:24 +0100
Subject: [PATCH v2 2/3] mfd: atmel-hlcdc: Add compatible for sama7d65 XLCD
 controller
In-Reply-To: <20251218040521.463937-2-manikandan.m@microchip.com>
References: <20251218040521.463937-1-manikandan.m@microchip.com>
 <20251218040521.463937-2-manikandan.m@microchip.com>
Message-ID: <66b2bbd4-a758-4a20-981f-07fcdb116412@microchip.com>

On 18/12/2025 at 05:05, Manikandan Muralidharan wrote:
> From: Ryan Wanner <Ryan.Wanner at microchip.com>
> 
> Add compatible for sama7d65 XLCD controller.
> 
> Signed-off-by: Ryan Wanner <Ryan.Wanner at microchip.com>
> Signed-off-by: Manikandan Muralidharan <manikandan.m at microchip.com>

Acked-by: Nicolas Ferre <nicolas.ferre at microchip.com>
> ---
> changes in v2:
> - isolate this change into a dedicated patch
> ---
>   drivers/mfd/atmel-hlcdc.c | 1 +
>   1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/mfd/atmel-hlcdc.c b/drivers/mfd/atmel-hlcdc.c
> index 4c4e35d404f3..c3f3d39bf584 100644
> --- a/drivers/mfd/atmel-hlcdc.c
> +++ b/drivers/mfd/atmel-hlcdc.c
> @@ -140,6 +140,7 @@ static const struct of_device_id atmel_hlcdc_match[] = {
>   	{ .compatible = "atmel,sama5d4-hlcdc" },
>   	{ .compatible = "microchip,sam9x60-hlcdc" },
>   	{ .compatible = "microchip,sam9x75-xlcdc" },
> +	{ .compatible = "microchip,sama7d65-xlcdc" },
>   	{ /* sentinel */ },
>   };
>   MODULE_DEVICE_TABLE(of, atmel_hlcdc_match);



From nicolas.ferre at microchip.com  Thu Dec 18 01:06:13 2025
From: nicolas.ferre at microchip.com (Nicolas Ferre)
Date: Thu, 18 Dec 2025 10:06:13 +0100
Subject: [PATCH v2 3/3] drm: atmel-hlcdc: add LCD controller layer
 definition for sama7d65
In-Reply-To: <20251218040521.463937-3-manikandan.m@microchip.com>
References: <20251218040521.463937-1-manikandan.m@microchip.com>
 <20251218040521.463937-3-manikandan.m@microchip.com>
Message-ID: <83faf871-0e54-4ea1-9490-e27026211eac@microchip.com>

On 18/12/2025 at 05:05, Manikandan Muralidharan wrote:
> From: Ryan Wanner <Ryan.Wanner at microchip.com>
> 
> Add the LCD controller layer definition and atmel_hlcdc_of_match
> entry for sama7d65.
> 
> Signed-off-by: Ryan Wanner <Ryan.Wanner at microchip.com>
> Signed-off-by: Manikandan Muralidharan <manikandan.m at microchip.com>

Acked-by: Nicolas Ferre <nicolas.ferre at microchip.com>
Thanks Ryan and Manikandan! Best regards,
   Nicolas



From m.tretter at pengutronix.de  Thu Dec 18 01:09:07 2025
From: m.tretter at pengutronix.de (Michael Tretter)
Date: Thu, 18 Dec 2025 10:09:07 +0100
Subject: [PATCH v2 0/2] media: staging: imx: fix multiple video input
In-Reply-To: <20251107-media-imx-fixes-v2-0-07d949964194@pengutronix.de>
References: <20251107-media-imx-fixes-v2-0-07d949964194@pengutronix.de>
Message-ID: <aUPEs4wUHgAyMrPX@pengutronix.de>

On Fri, 07 Nov 2025 11:34:32 +0100, Michael Tretter wrote:
> If the IMX media pipeline is configured to receive multiple video
> inputs, the second input stream may be broken on start. This happens if
> the IMX CSI hardware has to be reconfigured for the second stream, while
> the first stream is already running.
> 
> The IMX CSI driver configures the IMX CSI in the link_validate callback.
> The media pipeline is only validated on the first start. Thus, any later
> start of the media pipeline skips the validation and directly starts
> streaming. This may leave the hardware in an inconsistent state compared
> to the driver configuration. Moving the hardware configuration to the
> stream start to make sure that the hardware is configured correctly.
> 
> Patch 1 removes the caching of the upstream mbus_config in
> csi_link_validate and explicitly request the mbus_config in csi_start,
> to get rid of this implicit dependency.
> 
> Patch 2 actually moves the hardware register setting from
> csi_link_validate to csi_start to fix the skipped hardware
> reconfiguration.

Gentle ping.

Michael

> 
> Signed-off-by: Michael Tretter <michael.tretter at pengutronix.de>
> ---
> Changes in v2:
> - Document changed locking in commit message
> - Link to v1: https://lore.kernel.org/r/20251105-media-imx-fixes-v1-0-99e48b4f5cbc at pengutronix.de
> 
> ---
> Michael Tretter (2):
>       media: staging: imx: request mbus_config in csi_start
>       media: staging: imx: configure src_mux in csi_start
> 
>  drivers/staging/media/imx/imx-media-csi.c | 84 ++++++++++++++++++-------------
>  1 file changed, 48 insertions(+), 36 deletions(-)
> ---
> base-commit: 27afd6e066cfd80ddbe22a4a11b99174ac89cced
> change-id: 20251105-media-imx-fixes-acef77c7ba12


From yeoreum.yun at arm.com  Thu Dec 18 01:08:28 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Thu, 18 Dec 2025 09:08:28 +0000
Subject: [PATCH v2 1/2] arm64: mmu: don't allocate page while spliting
 linear mapping
In-Reply-To: <15777c12-d732-42e6-83da-61b3dca3764c@kernel.org>
References: <20251217182007.2345700-1-yeoreum.yun@arm.com>
 <20251217182007.2345700-2-yeoreum.yun@arm.com>
 <15777c12-d732-42e6-83da-61b3dca3764c@kernel.org>
Message-ID: <aUPEjPvJdS/QxGyt@e129823.arm.com>

Hi David,

> > Current linear_map_split_to_ptes() allocate the pagetable
> > while split linear mapping to ptes by stop_machine() with GFP_ATOMIC.
> >
> > This is fine for non-PREEMPR_RT case.
> > However It's a problem in PREEMPR_RT case since
> > generic memory allocation/free APIs (e.x) pgtable_alloc(), __get_free_pages and etc
> > couldn't be called in non-preemptible context except _nolock() APIs
> > since generic memory allocation/free APIs are *sleepable* for using *spin_lock()*
> >
> > IOW, calling a pgtable_alloc() even with GFP_ATOMIC
> > doesn't allow in __linear_map_split_to_pte() executed by stopper thread
> > where preemption is disabled in PREEMPR_RT.
> >
> > To address this, divide linear_map_maybe_split_ptes:
> >    - collect number of pages to require for spliting.
>
> COLLECT step
>
> >    - allocate the required number of pages for spliting.
>
> PREALLOC step
>
> >    - with pre-allocate page, split the linear map.
>
> SPLIT step
>
> The steps you have below are confusing :)
>
> > +enum split_modes {
>
> Is it a "mode" or a "step" ?
>
> enum split_step {
> 	SPLIT_STEP_COLLECT,
> 	...
> };
>
>
> But reading the code below I am lost how these modes apply here.
>
> I guess what you mean is something like
>
> enum split_mode {
> 	SPLIT_MODE_ALLOC, /* ... from the buddy. */
> 	SPLIT_MODE_PREALLOCATED, /* ... from preallocated buffer. */
> 	SPLIT_MODE_COLLECT, /* collect required page tables. */
> };

Sorry for *bad* naming from me.
Yes. your suggestion is much clearer. I'll change with this.

>
> But why is SPLIT_MODE_ALLOC vs. SPLIT_MODE_PREALLOCATED required?
>
> Can't we just test if there is something in the preallocated buffer, and if
> not, simply allocate?
>
> IOW, all you need is "collect vs. alloc", and the buffer information tells
> you how to allocate.

Agree. since it already check the "number of pgtable" before allocation
in linear_map_split_to_ptes(), That's would be better.

>
> > +	SPLIT_ALLOC,
> > +	SPLIT_PREALLOC,
> > +	SPLIT_COLLECT,
> > +};
> > -	pa = page_to_phys(ptdesc_page(ptdesc));
> > +struct split_args {
> > +	enum split_modes mode;
> > +	union {
> > +		struct {
> > +			unsigned long nr;
> > +			unsigned long i;
> > +			struct page **pages;
> > +		};
> > +		gfp_t gfp;
> > +	};
> > +};
> > +static __always_inline void __pgd_pgtable_init(struct mm_struct *mm,
> > +					       struct ptdesc *ptdesc,
> > +					       enum pgtable_type pgtable_type)
> > +{
> >   	switch (pgtable_type) {
> >   	case TABLE_PTE:
> >   		BUG_ON(!pagetable_pte_ctor(mm, ptdesc));
> > @@ -554,19 +564,56 @@ static phys_addr_t __pgd_pgtable_alloc(struct mm_struct *mm, gfp_t gfp,
> >   		break;
> >   	}
> > +}
> > +
> > +static phys_addr_t __pgd_pgtable_alloc(struct mm_struct *mm, gfp_t gfp,
> > +				       enum pgtable_type pgtable_type)
> > +{
> > +	/* Page is zeroed by init_clear_pgtable() so don't duplicate effort. */
> > +	struct ptdesc *ptdesc = pagetable_alloc(gfp & ~__GFP_ZERO, 0);
> > +	phys_addr_t pa;
> > +
> > +	if (!ptdesc)
> > +		return INVALID_PHYS_ADDR;
> > +
> > +	pa = page_to_phys(ptdesc_page(ptdesc));
> > +
> > +	__pgd_pgtable_init(mm, ptdesc, pgtable_type);
> > +
> >   	return pa;
> >   }
> > +static phys_addr_t __pgd_pgtable_prealloc(struct mm_struct *mm,
> > +					  struct split_args *split_args,
> > +					  enum pgtable_type pgtable_type)
>
> The function is called "_prealloc" but actually it simply grabs a
> preallocated page. Confusing.
>
>
> Should this function be called something like
> "__pgd_pgtable_get_preallocated()". Not sure.

Sorry to make a confuse. I think this name would be better.
I'll fix.


> > +{
> > +	struct page *page;
> > +
> > +	BUG_ON(split_args->i >= split_args->nr);
>
> No BUG_ON().

Okay. as keep only two mode:
    - COLLECT
    - ALLOC

I'll remove this.

> > +
> > +	page = split_args->pages[split_args->i++];
> > +	if (!page)
> > +		return INVALID_PHYS_ADDR;
> > +
> > +	__pgd_pgtable_init(mm, page_ptdesc(page), pgtable_type);
> > +
> > +	return page_to_phys(page);
> > +}
> > +
> >   static phys_addr_t
> > -pgd_pgtable_alloc_init_mm_gfp(enum pgtable_type pgtable_type, gfp_t gfp)
> > +pgd_pgtable_alloc_split(enum pgtable_type pgtable_type,
> > +		        struct split_args *split_args)
> >   {
> > -	return __pgd_pgtable_alloc(&init_mm, gfp, pgtable_type);
> > +	if (split_args->mode == SPLIT_ALLOC)
> > +		return __pgd_pgtable_alloc(&init_mm, split_args->gfp, pgtable_type);
> > +
> > +	return __pgd_pgtable_prealloc(&init_mm, split_args, pgtable_type);
> >   }
> >   static phys_addr_t __maybe_unused
> >   pgd_pgtable_alloc_init_mm(enum pgtable_type pgtable_type)
> >   {
> > -	return pgd_pgtable_alloc_init_mm_gfp(pgtable_type, GFP_PGTABLE_KERNEL);
> > +	return __pgd_pgtable_alloc(&init_mm, GFP_PGTABLE_KERNEL, pgtable_type);
> >   }
> >   static phys_addr_t
> > @@ -584,7 +631,9 @@ static void split_contpte(pte_t *ptep)
> >   		__set_pte(ptep, pte_mknoncont(__ptep_get(ptep)));
> >   }
> > -static int split_pmd(pmd_t *pmdp, pmd_t pmd, gfp_t gfp, bool to_cont)
> > +static int split_pmd(pmd_t *pmdp, pmd_t pmd,
> > +		     struct split_args *split_args,
> > +		     bool to_cont)
> >   {
> >   	pmdval_t tableprot = PMD_TYPE_TABLE | PMD_TABLE_UXN | PMD_TABLE_AF;
> >   	unsigned long pfn = pmd_pfn(pmd);
> > @@ -593,7 +642,7 @@ static int split_pmd(pmd_t *pmdp, pmd_t pmd, gfp_t gfp, bool to_cont)
> >   	pte_t *ptep;
> >   	int i;
> > -	pte_phys = pgd_pgtable_alloc_init_mm_gfp(TABLE_PTE, gfp);
> > +	pte_phys = pgd_pgtable_alloc_split(TABLE_PTE, split_args);
> >   	if (pte_phys == INVALID_PHYS_ADDR)
> >   		return -ENOMEM;
> >   	ptep = (pte_t *)phys_to_virt(pte_phys);
> > @@ -628,7 +677,9 @@ static void split_contpmd(pmd_t *pmdp)
> >   		set_pmd(pmdp, pmd_mknoncont(pmdp_get(pmdp)));
> >   }
> > -static int split_pud(pud_t *pudp, pud_t pud, gfp_t gfp, bool to_cont)
> > +static int split_pud(pud_t *pudp, pud_t pud,
> > +		    struct split_args *split_args,
> > +		    bool to_cont)
> >   {
> >   	pudval_t tableprot = PUD_TYPE_TABLE | PUD_TABLE_UXN | PUD_TABLE_AF;
> >   	unsigned int step = PMD_SIZE >> PAGE_SHIFT;
> > @@ -638,7 +689,7 @@ static int split_pud(pud_t *pudp, pud_t pud, gfp_t gfp, bool to_cont)
> >   	pmd_t *pmdp;
> >   	int i;
> > -	pmd_phys = pgd_pgtable_alloc_init_mm_gfp(TABLE_PMD, gfp);
> > +	pmd_phys = pgd_pgtable_alloc_split(TABLE_PMD, split_args);
> >   	if (pmd_phys == INVALID_PHYS_ADDR)
> >   		return -ENOMEM;
> >   	pmdp = (pmd_t *)phys_to_virt(pmd_phys);
> > @@ -672,6 +723,10 @@ static int split_kernel_leaf_mapping_locked(unsigned long addr)
> >   	pmd_t *pmdp, pmd;
> >   	pte_t *ptep, pte;
> >   	int ret = 0;
> > +	struct split_args split_args = {
> > +		.mode = SPLIT_ALLOC,
> > +		.gfp = GFP_PGTABLE_KERNEL,
> > +	};
> >   	/*
> >   	 * PGD: If addr is PGD aligned then addr already describes a leaf
> > @@ -707,7 +762,7 @@ static int split_kernel_leaf_mapping_locked(unsigned long addr)
> >   	if (!pud_present(pud))
> >   		goto out;
> >   	if (pud_leaf(pud)) {
> > -		ret = split_pud(pudp, pud, GFP_PGTABLE_KERNEL, true);
> > +		ret = split_pud(pudp, pud, &split_args, true);
> >   		if (ret)
> >   			goto out;
> >   	}
> > @@ -732,7 +787,7 @@ static int split_kernel_leaf_mapping_locked(unsigned long addr)
> >   		 */
> >   		if (ALIGN_DOWN(addr, PMD_SIZE) == addr)
> >   			goto out;
> > -		ret = split_pmd(pmdp, pmd, GFP_PGTABLE_KERNEL, true);
> > +		ret = split_pmd(pmdp, pmd, &split_args, true);
> >   		if (ret)
> >   			goto out;
> >   	}
> > @@ -831,12 +886,17 @@ int split_kernel_leaf_mapping(unsigned long start, unsigned long end)
> >   static int split_to_ptes_pud_entry(pud_t *pudp, unsigned long addr,
> >   				   unsigned long next, struct mm_walk *walk)
> >   {
> > -	gfp_t gfp = *(gfp_t *)walk->private;
> > +	struct split_args *split_args = (struct split_args *)walk->private;
> >   	pud_t pud = pudp_get(pudp);
> >   	int ret = 0;
> > -	if (pud_leaf(pud))
> > -		ret = split_pud(pudp, pud, gfp, false);
> > +	if (!pud_leaf(pud))
> > +		return 0;
> > +
> > +	if (split_args->mode == SPLIT_COLLECT)
> > +		split_args->nr++;
> > +	else
> > +		ret = split_pud(pudp, pud, split_args, false);
> >   	return ret;
> >   }
> > @@ -844,22 +904,29 @@ static int split_to_ptes_pud_entry(pud_t *pudp, unsigned long addr,
> >   static int split_to_ptes_pmd_entry(pmd_t *pmdp, unsigned long addr,
> >   				   unsigned long next, struct mm_walk *walk)
> >   {
> > -	gfp_t gfp = *(gfp_t *)walk->private;
> > +	struct split_args *split_args = (struct split_args *)walk->private;
> >   	pmd_t pmd = pmdp_get(pmdp);
> > -	int ret = 0;
> > +	int ret;
> > -	if (pmd_leaf(pmd)) {
> > -		if (pmd_cont(pmd))
> > -			split_contpmd(pmdp);
> > -		ret = split_pmd(pmdp, pmd, gfp, false);
> > +	if (!pmd_leaf(pmd))
> > +		return 0;
> > -		/*
> > -		 * We have split the pmd directly to ptes so there is no need to
> > -		 * visit each pte to check if they are contpte.
> > -		 */
> > -		walk->action = ACTION_CONTINUE;
> > +	if (split_args->mode == SPLIT_COLLECT) {
> > +		split_args->nr++;
> > +		return 0;
> >   	}
> > +	if (pmd_cont(pmd))
> > +		split_contpmd(pmdp);
> > +	ret = split_pmd(pmdp, pmd, split_args, false);
> > +
> > +	/*
> > +	 * We have split the pmd directly to ptes so there is no need to
> > +	 * visit each pte to check if they are contpte.
> > +	 */
> > +	walk->action = ACTION_CONTINUE;
> > +
> > +
> >   	return ret;
> >   }
> > @@ -880,13 +947,15 @@ static const struct mm_walk_ops split_to_ptes_ops = {
> >   	.pte_entry	= split_to_ptes_pte_entry,
> >   };
> > -static int range_split_to_ptes(unsigned long start, unsigned long end, gfp_t gfp)
> > +static int range_split_to_ptes(unsigned long start, unsigned long end,
> > +		 	       struct split_args *split_args)
> >   {
> >   	int ret;
> >   	arch_enter_lazy_mmu_mode();
> >   	ret = walk_kernel_page_table_range_lockless(start, end,
> > -					&split_to_ptes_ops, NULL, &gfp);
> > +						    &split_to_ptes_ops, NULL,
> > +						    split_args);
> >   	arch_leave_lazy_mmu_mode();
> >   	return ret;
> > @@ -903,7 +972,7 @@ static void __init init_idmap_kpti_bbml2_flag(void)
> >   	smp_mb();
> >   }
> > -static int __init linear_map_split_to_ptes(void *__unused)
> > +static int __init linear_map_split_to_ptes(void *data)
> >   {
> >   	/*
> >   	 * Repainting the linear map must be done by CPU0 (the boot CPU) because
> > @@ -911,6 +980,7 @@ static int __init linear_map_split_to_ptes(void *__unused)
> >   	 * be held in a waiting area with the idmap active.
> >   	 */
> >   	if (!smp_processor_id()) {
> > +		struct split_args *split_args = data;
> >   		unsigned long lstart = _PAGE_OFFSET(vabits_actual);
> >   		unsigned long lend = PAGE_END;
> >   		unsigned long kstart = (unsigned long)lm_alias(_stext);
> > @@ -928,12 +998,13 @@ static int __init linear_map_split_to_ptes(void *__unused)
> >   		 * PTE. The kernel alias remains static throughout runtime so
> >   		 * can continue to be safely mapped with large mappings.
> >   		 */
> > -		ret = range_split_to_ptes(lstart, kstart, GFP_ATOMIC);
> > +		ret = range_split_to_ptes(lstart, lend, split_args);
> >   		if (!ret)
> > -			ret = range_split_to_ptes(kend, lend, GFP_ATOMIC);
> > +			ret = range_split_to_ptes(kstart, kend, split_args);
> >   		if (ret)
> >   			panic("Failed to split linear map\n");
> > -		flush_tlb_kernel_range(lstart, lend);
> > +		if (split_args->mode != SPLIT_COLLECT)
> > +			flush_tlb_kernel_range(lstart, lend);
> >   		/*
> >   		 * Relies on dsb in flush_tlb_kernel_range() to avoid reordering
> > @@ -963,10 +1034,61 @@ static int __init linear_map_split_to_ptes(void *__unused)
> >   void __init linear_map_maybe_split_to_ptes(void)
> >   {
> > -	if (linear_map_requires_bbml2 && !system_supports_bbml2_noabort()) {
> > -		init_idmap_kpti_bbml2_flag();
> > -		stop_machine(linear_map_split_to_ptes, NULL, cpu_online_mask);
> > +	struct page **pages = NULL;
> > +	struct split_args split_args;
> > +	int order;
> > +	int nr_populated;
> > +	int err;
> > +
> > +	if (!linear_map_requires_bbml2 || system_supports_bbml2_noabort())
> > +		return;
> > +
> > +	/*
> > +	 * Phase 1: Collect required extra pages to split.
> > +	 */
> > +	split_args.mode = SPLIT_COLLECT;
> > +	split_args.nr = 0;
> > +
> > +	init_idmap_kpti_bbml2_flag();
> > +	stop_machine(linear_map_split_to_ptes, &split_args, cpu_online_mask);
> > +
> > +	/*
> > +	 * Phase 2: Allocate necessary pages to split.
> > +	 */
> > +	if (split_args.nr == 0) {
> > +		err = 0;
> > +		split_args.mode = SPLIT_ALLOC;
> > +	} else {
> > +		err = -ENOMEM;
> > +		order = order_base_2(PAGE_ALIGN(split_args.nr *
> > +					sizeof(struct page *)) >> PAGE_SHIFT);
> > +
> > +		pages = (struct page **)__get_free_pages(GFP_ATOMIC | __GFP_ZERO, order);
> > +		if (!pages)
> > +			goto error;
> > +
> > +		nr_populated = alloc_pages_bulk(GFP_ATOMIC | __GFP_ZERO, split_args.nr, pages);
> > +		if (nr_populated < split_args.nr)
> > +			goto error;
>
> That is prone to cause trouble in the future once we allocate memdescs
> separately.
>
> Can we simply call pagetable_alloc() in a loop here instead for the time
> being? A future-proof bulk allocation can be done later separately.

I miss the future plan.
Yes, I'll change to pagetable_alloc().

Thanks!

--
Sincerely,
Yeoreum Yun


From manali.shukla at amd.com  Thu Dec 18 01:19:34 2025
From: manali.shukla at amd.com (Manali Shukla)
Date: Thu, 18 Dec 2025 14:49:34 +0530
Subject: [PATCH v6 00/44] KVM: x86: Add support for mediated vPMUs
In-Reply-To: <20251208153738.GC3707837@noisy.programming.kicks-ass.net>
References: <20251206001720.468579-1-seanjc@google.com>
 <20251208153738.GC3707837@noisy.programming.kicks-ass.net>
Message-ID: <f6408786-8b40-4ded-8a20-307fe0133e98@amd.com>

On 12/8/2025 9:07 PM, Peter Zijlstra wrote:
> On Fri, Dec 05, 2025 at 04:16:36PM -0800, Sean Christopherson wrote:
>> My hope/plan is that the perf changes will go through the tip tree with a
>> stable tag/branch, and the KVM changes will go the kvm-x86 tree.
> 
>> Kan Liang (7):
>>   perf: Skip pmu_ctx based on event_type
>>   perf: Add generic exclude_guest support
>>   perf: Add APIs to create/release mediated guest vPMUs
>>   perf: Clean up perf ctx time
>>   perf: Add a EVENT_GUEST flag
>>   perf: Add APIs to load/put guest mediated PMU context
>>   perf/x86/intel: Support PERF_PMU_CAP_MEDIATED_VPMU
>>
>> Mingwei Zhang (3):
>>   perf/x86/core: Plumb mediated PMU capability from x86_pmu to
>>     x86_pmu_cap
>>
>> Sandipan Das (3):
>>   perf/x86/core: Do not set bit width for unavailable counters
>>   perf/x86/amd: Support PERF_PMU_CAP_MEDIATED_VPMU for AMD host
>>
>> Sean Christopherson (19):
>>   perf: Move security_perf_event_free() call to __free_event()
>>   perf/x86/core: Register a new vector for handling mediated guest PMIs
>>   perf/x86/core: Add APIs to switch to/from mediated PMI vector (for
>>     KVM)
> 
> That all looks to be in decent shape; lets go get this merged. There is
> the nit on patch 4 and I think a number of the exports want to be
> EXPORT_SYMBOL_FOR_KVM() instead, but we can do that on top.
> 
> I'll queue these patches after rc1.

I have tested this series on AMD EPYC 9745 (Turin, 128-Core Processor)
with 12 hours of perf_fuzzer runs across multiple configurations. No new
failures were observed.

Test Platform:
--------------
Hardware: AMD EPYC 9745 128-Core Processor (Turin)
Test Duration: 12 hours of perf_fuzzer per configuration

Configuration 1: enable_mediated_pmu=Y
---------------------------------------
SVM guests:
  -cpu host
  -cpu host,-perfmon-v2
  -cpu host,-perfctr-core

SEV-ES guest:
  -cpu host

SEV-SNP guest:
  -cpu host

Configuration 2: enable_mediated_pmu=N
---------------------------------------
SVM guest:
  -cpu EPYC-Genoa-v2,+pmu
  -cpu EPYC-Genoa-v2,+pmu,-perfmon-v2
  -cpu EPYC-Genoa-v2,+pmu,-perfctr-core

SEV-ES guest:
  -cpu EPYC-Genoa-v2,+pmu

SEV-SNP guest:
  -cpu EPYC-Genoa-v2,+pmu

KVM Unit Tests (KUT):
---------------------
Tested all combinations of:
  - enable_mediated_pmu={0,1}
  - force_emulation_prefix={0,1}

CPU configurations tested:
  -cpu host
  -cpu host,-perfmon-v2
  -cpu host,-perfctr-core

All KUT tests passed as expected across all combinations.

Tested-by: Manali Shukla <manali.shukla at amd.com>

-Manali



From suzuki.poulose at arm.com  Thu Dec 18 01:19:53 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Thu, 18 Dec 2025 09:19:53 +0000
Subject: [PATCH v4 1/3] coresight: tpda: add sysfs nodes for tpda
 cross-trigger configuration
In-Reply-To: <ea84b279-8d55-4707-b6cf-85006da27456@oss.qualcomm.com>
References: <20251028-configure_tpda_reg-v4-0-23000805d21d@oss.qualcomm.com>
 <20251028-configure_tpda_reg-v4-1-23000805d21d@oss.qualcomm.com>
 <ea84b279-8d55-4707-b6cf-85006da27456@oss.qualcomm.com>
Message-ID: <0ac7f4e3-fec2-4554-99e7-53cf015febbe@arm.com>

On 18/12/2025 06:22, Jie Gan wrote:
> 
> 
> On 10/28/2025 10:02 AM, Jie Gan wrote:
>> From: Tao Zhang <tao.zhang at oss.qualcomm.com>
>>
>> Introduce sysfs nodes to configure cross-trigger parameters for TPDA.
>> These registers define the characteristics of cross-trigger packets,
>> including generation frequency and flag values.
>>
>> Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
>> Reviewed-by: James Clark <james.clark at linaro.org>
>> Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> ---
>> ? .../ABI/testing/sysfs-bus-coresight-devices-tpda?? |? 43 ++++
>> ? drivers/hwtracing/coresight/coresight-tpda.c?????? | 230 +++++++++++ 
>> ++++++++++
>> ? drivers/hwtracing/coresight/coresight-tpda.h?????? |? 27 ++-
>> ? 3 files changed, 299 insertions(+), 1 deletion(-)
>>
>> diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices- 
>> tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
>> new file mode 100644
>> index 000000000000..80e4b05a1ab4
>> --- /dev/null
>> +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
> 
> Gentle reminder.
> 
> Do I need update the date and the kernelVersion of the sysfs node? 
> (target 7.0?)

Leave it with me, I can fix it up. Apologies for missing this out.

Suzuki


> 
> Thanks,
> Jie
> 
> 
>> @@ -0,0 +1,43 @@
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/trig_async_enable
>> +Date:??????? October 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Enable/disable cross trigger synchronization sequence 
>> interface.
>> +
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/trig_flag_ts_enable
>> +Date:??????? October 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Enable/disable cross trigger FLAG packet request interface.
>> +
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/trig_freq_enable
>> +Date:??????? October 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Enable/disable cross trigger FREQ packet request interface.
>> +
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/freq_ts_enable
>> +Date:??????? October 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Enable/disable the timestamp for all FREQ packets.
>> +
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/global_flush_req
>> +Date:??????? October 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Set global (all ports) flush request bit. The bit 
>> remains set until a
>> +??????? global flush request sequence completes.
>> +
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/cmbchan_mode
>> +Date:??????? October 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Configure the CMB/MCMB channel mode for all enabled ports.
>> +??????? Value 0 means raw channel mapping mode. Value 1 means channel 
>> pair marking mode.
>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/ 
>> hwtracing/coresight/coresight-tpda.c
>> index 333b3cb23685..a9a27bcc65a1 100644
>> --- a/drivers/hwtracing/coresight/coresight-tpda.c
>> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
>> @@ -147,9 +147,37 @@ static void tpda_enable_pre_port(struct 
>> tpda_drvdata *drvdata)
>> ????? u32 val;
>> ????? val = readl_relaxed(drvdata->base + TPDA_CR);
>> +??? val &= ~TPDA_CR_MID;
>> ????? val &= ~TPDA_CR_ATID;
>> ????? val |= FIELD_PREP(TPDA_CR_ATID, drvdata->atid);
>> +??? if (drvdata->trig_async)
>> +??????? val |= TPDA_CR_SRIE;
>> +??? else
>> +??????? val &= ~TPDA_CR_SRIE;
>> +??? if (drvdata->trig_flag_ts)
>> +??????? val |= TPDA_CR_FLRIE;
>> +??? else
>> +??????? val &= ~TPDA_CR_FLRIE;
>> +??? if (drvdata->trig_freq)
>> +??????? val |= TPDA_CR_FRIE;
>> +??? else
>> +??????? val &= ~TPDA_CR_FRIE;
>> +??? if (drvdata->freq_ts)
>> +??????? val |= TPDA_CR_FREQTS;
>> +??? else
>> +??????? val &= ~TPDA_CR_FREQTS;
>> +??? if (drvdata->cmbchan_mode)
>> +??????? val |= TPDA_CR_CMBCHANMODE;
>> +??? else
>> +??????? val &= ~TPDA_CR_CMBCHANMODE;
>> ????? writel_relaxed(val, drvdata->base + TPDA_CR);
>> +
>> +??? /*
>> +???? * If FLRIE bit is set, set the master and channel
>> +???? * id as zero
>> +???? */
>> +??? if (drvdata->trig_flag_ts)
>> +??????? writel_relaxed(0x0, drvdata->base + TPDA_FPID_CR);
>> ? }
>> ? static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
>> @@ -265,6 +293,206 @@ static const struct coresight_ops tpda_cs_ops = {
>> ????? .link_ops??? = &tpda_link_ops,
>> ? };
>> +static ssize_t trig_async_enable_show(struct device *dev,
>> +????????????????????? struct device_attribute *attr,
>> +????????????????????? char *buf)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +
>> +??? return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_async);
>> +}
>> +
>> +static ssize_t trig_async_enable_store(struct device *dev,
>> +?????????????????????? struct device_attribute *attr,
>> +?????????????????????? const char *buf,
>> +?????????????????????? size_t size)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +??? unsigned long val;
>> +
>> +??? if (kstrtoul(buf, 0, &val))
>> +??????? return -EINVAL;
>> +
>> +??? guard(spinlock)(&drvdata->spinlock);
>> +??? drvdata->trig_async = !!val;
>> +
>> +??? return size;
>> +}
>> +static DEVICE_ATTR_RW(trig_async_enable);
>> +
>> +static ssize_t trig_flag_ts_enable_show(struct device *dev,
>> +??????????????????? struct device_attribute *attr,
>> +??????????????????? char *buf)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +
>> +??? return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_flag_ts);
>> +}
>> +
>> +static ssize_t trig_flag_ts_enable_store(struct device *dev,
>> +???????????????????? struct device_attribute *attr,
>> +???????????????????? const char *buf,
>> +???????????????????? size_t size)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +??? unsigned long val;
>> +
>> +??? if (kstrtoul(buf, 0, &val))
>> +??????? return -EINVAL;
>> +
>> +??? guard(spinlock)(&drvdata->spinlock);
>> +??? drvdata->trig_flag_ts = !!val;
>> +
>> +??? return size;
>> +}
>> +static DEVICE_ATTR_RW(trig_flag_ts_enable);
>> +
>> +static ssize_t trig_freq_enable_show(struct device *dev,
>> +???????????????????? struct device_attribute *attr,
>> +???????????????????? char *buf)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +
>> +??? return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_freq);
>> +}
>> +
>> +static ssize_t trig_freq_enable_store(struct device *dev,
>> +????????????????????? struct device_attribute *attr,
>> +????????????????????? const char *buf,
>> +????????????????????? size_t size)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +??? unsigned long val;
>> +
>> +??? if (kstrtoul(buf, 0, &val))
>> +??????? return -EINVAL;
>> +
>> +??? guard(spinlock)(&drvdata->spinlock);
>> +??? drvdata->trig_freq = !!val;
>> +
>> +??? return size;
>> +}
>> +static DEVICE_ATTR_RW(trig_freq_enable);
>> +
>> +static ssize_t freq_ts_enable_show(struct device *dev,
>> +?????????????????? struct device_attribute *attr,
>> +?????????????????? char *buf)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +
>> +??? return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->freq_ts);
>> +}
>> +
>> +static ssize_t freq_ts_enable_store(struct device *dev,
>> +??????????????????? struct device_attribute *attr,
>> +??????????????????? const char *buf,
>> +??????????????????? size_t size)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +??? unsigned long val;
>> +
>> +??? if (kstrtoul(buf, 0, &val))
>> +??????? return -EINVAL;
>> +
>> +??? guard(spinlock)(&drvdata->spinlock);
>> +??? drvdata->freq_ts = !!val;
>> +
>> +??? return size;
>> +}
>> +static DEVICE_ATTR_RW(freq_ts_enable);
>> +
>> +static ssize_t global_flush_req_show(struct device *dev,
>> +???????????????????? struct device_attribute *attr,
>> +???????????????????? char *buf)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +??? unsigned long val;
>> +
>> +??? if (!drvdata->csdev->refcnt)
>> +??????? return -EINVAL;
>> +
>> +??? guard(spinlock)(&drvdata->spinlock);
>> +??? CS_UNLOCK(drvdata->base);
>> +??? val = readl_relaxed(drvdata->base + TPDA_CR);
>> +??? CS_LOCK(drvdata->base);
>> +??? /* Only read value for bit 0 */
>> +??? val &= BIT(0);
>> +
>> +??? return sysfs_emit(buf, "%lu\n", val);
>> +}
>> +
>> +static ssize_t global_flush_req_store(struct device *dev,
>> +????????????????????? struct device_attribute *attr,
>> +????????????????????? const char *buf,
>> +????????????????????? size_t size)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +??? unsigned long val;
>> +
>> +??? if (kstrtoul(buf, 0, &val))
>> +??????? return -EINVAL;
>> +
>> +??? if (!drvdata->csdev->refcnt || !val)
>> +??????? return -EINVAL;
>> +
>> +??? guard(spinlock)(&drvdata->spinlock);
>> +??? CS_UNLOCK(drvdata->base);
>> +??? val = readl_relaxed(drvdata->base + TPDA_CR);
>> +??? /* Only set bit 0 */
>> +??? val |= BIT(0);
>> +??? writel_relaxed(val, drvdata->base + TPDA_CR);
>> +??? CS_LOCK(drvdata->base);
>> +
>> +??? return size;
>> +}
>> +static DEVICE_ATTR_RW(global_flush_req);
>> +
>> +static ssize_t cmbchan_mode_show(struct device *dev,
>> +???????????????? struct device_attribute *attr,
>> +???????????????? char *buf)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +
>> +??? return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->cmbchan_mode);
>> +}
>> +
>> +static ssize_t cmbchan_mode_store(struct device *dev,
>> +????????????????? struct device_attribute *attr,
>> +????????????????? const char *buf,
>> +????????????????? size_t size)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +??? unsigned long val;
>> +
>> +??? if (kstrtoul(buf, 0, &val))
>> +??????? return -EINVAL;
>> +
>> +??? guard(spinlock)(&drvdata->spinlock);
>> +??? drvdata->cmbchan_mode = !!val;
>> +
>> +??? return size;
>> +}
>> +static DEVICE_ATTR_RW(cmbchan_mode);
>> +
>> +static struct attribute *tpda_attrs[] = {
>> +??? &dev_attr_trig_async_enable.attr,
>> +??? &dev_attr_trig_flag_ts_enable.attr,
>> +??? &dev_attr_trig_freq_enable.attr,
>> +??? &dev_attr_freq_ts_enable.attr,
>> +??? &dev_attr_global_flush_req.attr,
>> +??? &dev_attr_cmbchan_mode.attr,
>> +??? NULL,
>> +};
>> +
>> +static struct attribute_group tpda_attr_grp = {
>> +??? .attrs = tpda_attrs,
>> +};
>> +
>> +static const struct attribute_group *tpda_attr_grps[] = {
>> +??? &tpda_attr_grp,
>> +??? NULL,
>> +};
>> +
>> ? static int tpda_init_default_data(struct tpda_drvdata *drvdata)
>> ? {
>> ????? int atid;
>> @@ -280,6 +508,7 @@ static int tpda_init_default_data(struct 
>> tpda_drvdata *drvdata)
>> ????????? return atid;
>> ????? drvdata->atid = atid;
>> +??? drvdata->freq_ts = true;
>> ????? return 0;
>> ? }
>> @@ -323,6 +552,7 @@ static int tpda_probe(struct amba_device *adev, 
>> const struct amba_id *id)
>> ????? desc.ops = &tpda_cs_ops;
>> ????? desc.pdata = adev->dev.platform_data;
>> ????? desc.dev = &adev->dev;
>> +??? desc.groups = tpda_attr_grps;
>> ????? desc.access = CSDEV_ACCESS_IOMEM(base);
>> ????? drvdata->csdev = coresight_register(&desc);
>> ????? if (IS_ERR(drvdata->csdev))
>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/ 
>> hwtracing/coresight/coresight-tpda.h
>> index c6af3d2da3ef..0be625fb52fd 100644
>> --- a/drivers/hwtracing/coresight/coresight-tpda.h
>> +++ b/drivers/hwtracing/coresight/coresight-tpda.h
>> @@ -1,6 +1,6 @@
>> ? /* SPDX-License-Identifier: GPL-2.0 */
>> ? /*
>> - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights 
>> reserved.
>> + * Copyright (c) 2023,2025 Qualcomm Innovation Center, Inc. All 
>> rights reserved.
>> ?? */
>> ? #ifndef _CORESIGHT_CORESIGHT_TPDA_H
>> @@ -8,6 +8,19 @@
>> ? #define TPDA_CR??????????? (0x000)
>> ? #define TPDA_Pn_CR(n)??????? (0x004 + (n * 4))
>> +#define TPDA_FPID_CR??????? (0x084)
>> +
>> +/* Cross trigger FREQ packets timestamp bit */
>> +#define TPDA_CR_FREQTS??????? BIT(2)
>> +/* Cross trigger FREQ packet request bit */
>> +#define TPDA_CR_FRIE??????? BIT(3)
>> +/* Cross trigger FLAG packet request interface bit */
>> +#define TPDA_CR_FLRIE??????? BIT(4)
>> +/* Cross trigger synchronization bit */
>> +#define TPDA_CR_SRIE??????? BIT(5)
>> +/* Packetize CMB/MCMB traffic bit */
>> +#define TPDA_CR_CMBCHANMODE??? BIT(20)
>> +
>> ? /* Aggregator port enable bit */
>> ? #define TPDA_Pn_CR_ENA??????? BIT(0)
>> ? /* Aggregator port CMB data set element size bit */
>> @@ -19,6 +32,8 @@
>> ? /* Bits 6 ~ 12 is for atid value */
>> ? #define TPDA_CR_ATID??????? GENMASK(12, 6)
>> +/* Bits 13 ~ 19 is for mid value */
>> +#define TPDA_CR_MID??????? GENMASK(19, 13)
>> ? /**
>> ?? * struct tpda_drvdata - specifics associated to an TPDA component
>> @@ -29,6 +44,11 @@
>> ?? * @enable:???? enable status of the component.
>> ?? * @dsb_esize?? Record the DSB element size.
>> ?? * @cmb_esize?? Record the CMB element size.
>> + * @trig_async:??? Enable/disable cross trigger synchronization 
>> sequence interface.
>> + * @trig_flag_ts: Enable/disable cross trigger FLAG packet request 
>> interface.
>> + * @trig_freq:??? Enable/disable cross trigger FREQ packet request 
>> interface.
>> + * @freq_ts:??? Enable/disable the timestamp for all FREQ packets.
>> + * @cmbchan_mode: Configure the CMB/MCMB channel mode.
>> ?? */
>> ? struct tpda_drvdata {
>> ????? void __iomem??????? *base;
>> @@ -38,6 +58,11 @@ struct tpda_drvdata {
>> ????? u8??????????? atid;
>> ????? u32??????????? dsb_esize;
>> ????? u32??????????? cmb_esize;
>> +??? bool??????????? trig_async;
>> +??? bool??????????? trig_flag_ts;
>> +??? bool??????????? trig_freq;
>> +??? bool??????????? freq_ts;
>> +??? bool??????????? cmbchan_mode;
>> ? };
>> ? #endif? /* _CORESIGHT_CORESIGHT_TPDA_H */
>>
> 



From m.tretter at pengutronix.de  Thu Dec 18 01:23:50 2025
From: m.tretter at pengutronix.de (Michael Tretter)
Date: Thu, 18 Dec 2025 10:23:50 +0100
Subject: [PATCH v2 2/3] media: imx-csi: explicitly start media pipeline on
 pad 0
In-Reply-To: <20251218-media-imx-cleanup-v2-0-9e3e3c269f7f@pengutronix.de>
References: <20251218-media-imx-cleanup-v2-0-9e3e3c269f7f@pengutronix.de>
Message-ID: <20251218-media-imx-cleanup-v2-2-9e3e3c269f7f@pengutronix.de>

entity->pads is an array that contains all the pads of an entity.

Calling __media_pipeline_start() or __media_pipeline_stop() on the pads,
implicitly starts the pipeline with the first pad in this array as
origin.

Explicitly use the first pad to start the pipeline to make this more
obvious to the reader.

Reviewed-by: Frank Li <Frank.Li at nxp.com>
Reviewed-by: Philipp Zabel <p.zabel at pengutronix.de>
Signed-off-by: Michael Tretter <m.tretter at pengutronix.de>
---
Changes in v2:
- move struct media_pad *pad; before int ret = 0; for better read
---
 drivers/staging/media/imx/imx-media-utils.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c
index f520529a7cfe..bd9af147a801 100644
--- a/drivers/staging/media/imx/imx-media-utils.c
+++ b/drivers/staging/media/imx/imx-media-utils.c
@@ -754,6 +754,7 @@ int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
 				  bool on)
 {
 	struct v4l2_subdev *sd;
+	struct media_pad *pad;
 	int ret = 0;
 
 	if (!is_media_entity_v4l2_subdev(entity))
@@ -762,17 +763,19 @@ int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
 
 	mutex_lock(&imxmd->md.graph_mutex);
 
+	pad = &entity->pads[0];
+
 	if (on) {
-		ret = __media_pipeline_start(entity->pads, &vdev->pipe);
+		ret = __media_pipeline_start(pad, &vdev->pipe);
 		if (ret)
 			goto out;
 		ret = v4l2_subdev_call(sd, video, s_stream, 1);
 		if (ret)
-			__media_pipeline_stop(entity->pads);
+			__media_pipeline_stop(pad);
 	} else {
 		v4l2_subdev_call(sd, video, s_stream, 0);
-		if (media_pad_pipeline(entity->pads))
-			__media_pipeline_stop(entity->pads);
+		if (media_pad_pipeline(pad))
+			__media_pipeline_stop(pad);
 	}
 
 out:

-- 
2.47.3



From m.tretter at pengutronix.de  Thu Dec 18 01:23:48 2025
From: m.tretter at pengutronix.de (Michael Tretter)
Date: Thu, 18 Dec 2025 10:23:48 +0100
Subject: [PATCH v2 0/3] media: imx-csi: cleanup media pipeline start
Message-ID: <20251218-media-imx-cleanup-v2-0-9e3e3c269f7f@pengutronix.de>

The imx media device currently assumes that there is only a single media
pipeline. However, the media graph has multiple imx capture devices.
These may be started separately on media pipelines if they don't cause
conflicts in the media graph.

Move the media pipeline from the media device to the capture devices to
properly track and handle multiple media pipelines for the imx-csi.
Refactor the code to start the media pipeline from the driver to help
the reader.

Signed-off-by: Michael Tretter <m.tretter at pengutronix.de>
---
Changes in v2:
- Improve code readability in Patch 2
- Update commit message of Patch 3 as suggested by Frank Li
- Link to v1: https://patch.msgid.link/20251107-media-imx-cleanup-v1-0-f82a693c28f4 at pengutronix.de

---
Michael Tretter (3):
      media: imx-csi: move media_pipeline to video device
      media: imx-csi: explicitly start media pipeline on pad 0
      media: imx-csi: use media_pad_is_streaming helper

 drivers/staging/media/imx/imx-media-capture.c |  8 ++++----
 drivers/staging/media/imx/imx-media-utils.c   | 12 ++++++++----
 drivers/staging/media/imx/imx-media.h         |  7 ++++---
 3 files changed, 16 insertions(+), 11 deletions(-)
---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20251107-media-imx-cleanup-9022d941ae44

Best regards,
-- 
Michael Tretter <m.tretter at pengutronix.de>



From m.tretter at pengutronix.de  Thu Dec 18 01:23:49 2025
From: m.tretter at pengutronix.de (Michael Tretter)
Date: Thu, 18 Dec 2025 10:23:49 +0100
Subject: [PATCH v2 1/3] media: imx-csi: move media_pipeline to video device
In-Reply-To: <20251218-media-imx-cleanup-v2-0-9e3e3c269f7f@pengutronix.de>
References: <20251218-media-imx-cleanup-v2-0-9e3e3c269f7f@pengutronix.de>
Message-ID: <20251218-media-imx-cleanup-v2-1-9e3e3c269f7f@pengutronix.de>

The imx-media driver has a single imx_media_device. Attaching the
media_pipeline to the imx_media_device prevents the execution of
multiple media pipelines on the device. This should be possible as long
as the media_pipelines don't use the same pads or pads that be
configured while the other media pipeline is streaming.

Move the media_pipeline to the imx_media_video_dev to be able to
construct media pipelines per imx capture device.

If different media pipelines in the media device conflict, the
validation will fail. Thus, the pipeline will fail to start and signal
an error to user space.

Reviewed-by: Frank Li <Frank.Li at nxp.com>
Reviewed-by: Philipp Zabel <p.zabel at pengutronix.de>
Signed-off-by: Michael Tretter <m.tretter at pengutronix.de>
---
Changes in v2:
- none
---
 drivers/staging/media/imx/imx-media-capture.c | 8 ++++----
 drivers/staging/media/imx/imx-media-utils.c   | 3 ++-
 drivers/staging/media/imx/imx-media.h         | 7 ++++---
 3 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/staging/media/imx/imx-media-capture.c b/drivers/staging/media/imx/imx-media-capture.c
index e9cef7af000a..bfd71d25facc 100644
--- a/drivers/staging/media/imx/imx-media-capture.c
+++ b/drivers/staging/media/imx/imx-media-capture.c
@@ -722,8 +722,8 @@ static int capture_start_streaming(struct vb2_queue *vq, unsigned int count)
 		goto return_bufs;
 	}
 
-	ret = imx_media_pipeline_set_stream(priv->md, &priv->src_sd->entity,
-					    true);
+	ret = imx_media_pipeline_set_stream(priv->md, &priv->vdev,
+					    &priv->src_sd->entity, true);
 	if (ret) {
 		dev_err(priv->dev, "pipeline start failed with %d\n", ret);
 		goto return_bufs;
@@ -749,8 +749,8 @@ static void capture_stop_streaming(struct vb2_queue *vq)
 	unsigned long flags;
 	int ret;
 
-	ret = imx_media_pipeline_set_stream(priv->md, &priv->src_sd->entity,
-					    false);
+	ret = imx_media_pipeline_set_stream(priv->md, &priv->vdev,
+					    &priv->src_sd->entity, false);
 	if (ret)
 		dev_warn(priv->dev, "pipeline stop failed with %d\n", ret);
 
diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c
index 1b5af8945e6b..f520529a7cfe 100644
--- a/drivers/staging/media/imx/imx-media-utils.c
+++ b/drivers/staging/media/imx/imx-media-utils.c
@@ -749,6 +749,7 @@ EXPORT_SYMBOL_GPL(imx_media_pipeline_subdev);
  * Turn current pipeline streaming on/off starting from entity.
  */
 int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
+				  struct imx_media_video_dev *vdev,
 				  struct media_entity *entity,
 				  bool on)
 {
@@ -762,7 +763,7 @@ int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
 	mutex_lock(&imxmd->md.graph_mutex);
 
 	if (on) {
-		ret = __media_pipeline_start(entity->pads, &imxmd->pipe);
+		ret = __media_pipeline_start(entity->pads, &vdev->pipe);
 		if (ret)
 			goto out;
 		ret = v4l2_subdev_call(sd, video, s_stream, 1);
diff --git a/drivers/staging/media/imx/imx-media.h b/drivers/staging/media/imx/imx-media.h
index f095d9134fee..8b65f79b125f 100644
--- a/drivers/staging/media/imx/imx-media.h
+++ b/drivers/staging/media/imx/imx-media.h
@@ -104,6 +104,9 @@ struct imx_media_buffer {
 struct imx_media_video_dev {
 	struct video_device *vfd;
 
+	/* the pipeline object */
+	struct media_pipeline pipe;
+
 	/* the user format */
 	struct v4l2_pix_format fmt;
 	/* the compose rectangle */
@@ -145,9 +148,6 @@ struct imx_media_dev {
 	struct media_device md;
 	struct v4l2_device  v4l2_dev;
 
-	/* the pipeline object */
-	struct media_pipeline pipe;
-
 	struct mutex mutex; /* protect elements below */
 
 	/* master video device list */
@@ -223,6 +223,7 @@ int imx_media_alloc_dma_buf(struct device *dev,
 			    int size);
 
 int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
+				  struct imx_media_video_dev *vdev,
 				  struct media_entity *entity,
 				  bool on);
 

-- 
2.47.3



From m.tretter at pengutronix.de  Thu Dec 18 01:23:51 2025
From: m.tretter at pengutronix.de (Michael Tretter)
Date: Thu, 18 Dec 2025 10:23:51 +0100
Subject: [PATCH v2 3/3] media: imx-csi: use media_pad_is_streaming helper
In-Reply-To: <20251218-media-imx-cleanup-v2-0-9e3e3c269f7f@pengutronix.de>
References: <20251218-media-imx-cleanup-v2-0-9e3e3c269f7f@pengutronix.de>
Message-ID: <20251218-media-imx-cleanup-v2-3-9e3e3c269f7f@pengutronix.de>

The media_pad_is_streaming() helper is explicitly intended to check
whether a pad has been started with media_pipeline_start(). Use it
instead of relying on the implicit assumption that a pad with a
pipeline is streaming.

Reviewed-by: Philipp Zabel <p.zabel at pengutronix.de>
Signed-off-by: Michael Tretter <m.tretter at pengutronix.de>
---
Changes in v2:
- Update commit message as suggested by Frank Li
---
 drivers/staging/media/imx/imx-media-utils.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c
index bd9af147a801..1a2e5e40c99c 100644
--- a/drivers/staging/media/imx/imx-media-utils.c
+++ b/drivers/staging/media/imx/imx-media-utils.c
@@ -774,7 +774,7 @@ int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
 			__media_pipeline_stop(pad);
 	} else {
 		v4l2_subdev_call(sd, video, s_stream, 0);
-		if (media_pad_pipeline(pad))
+		if (media_pad_is_streaming(pad))
 			__media_pipeline_stop(pad);
 	}
 

-- 
2.47.3



From mhocko at suse.com  Thu Dec 18 01:30:33 2025
From: mhocko at suse.com (Michal Hocko)
Date: Thu, 18 Dec 2025 10:30:33 +0100
Subject: [PATCH 2/2] arm64: mmu: use pagetable_alloc_nolock() while
 stop_machine()
In-Reply-To: <20251212161832.2067134-3-yeoreum.yun@arm.com>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com>
 <20251212161832.2067134-3-yeoreum.yun@arm.com>
Message-ID: <aUPJuZINNuNxddRX@tiehlicka>

On Fri 12-12-25 16:18:32, Yeoreum Yun wrote:
> linear_map_split_to_ptes() and __kpti_install_ng_mappings()
> are called as callback of stop_machine().
> That means these functions context are preemption disabled.
> 
> Unfortunately, under PREEMPT_RT, the pagetable_alloc() or
> __get_free_pages() couldn't be called in this context
> since spin lock that becomes sleepable on RT,
> potentially causing a sleep during page allocation.
> 
> To address this, pagetable_alloc_nolock().

As you cannot tolerate allocation failure and this is pretty much
permanent allocation (AFAIU) why don't you use a static allocation?

-- 
Michal Hocko
SUSE Labs


From yeoreum.yun at arm.com  Thu Dec 18 01:31:00 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Thu, 18 Dec 2025 09:31:00 +0000
Subject: [PATCH v2 2/2] arm64: mmu: avoid allocating pages while
 installing ng-mapping for KPTI
In-Reply-To: <201d0fa3-2ebe-4df2-926c-9e11607a6f07@kernel.org>
References: <20251217182007.2345700-1-yeoreum.yun@arm.com>
 <20251217182007.2345700-3-yeoreum.yun@arm.com>
 <731e3f48-e0a3-4c89-a13a-65ef37faa443@arm.com>
 <aUL/zJlJFRz2/Ybt@e129823.arm.com>
 <72aaa252-6ee6-4353-84ee-b6e10e9920c6@arm.com>
 <aUO9M/oN+nx3nfW+@e129823.arm.com>
 <201d0fa3-2ebe-4df2-926c-9e11607a6f07@kernel.org>
Message-ID: <aUPJ1N99LEVZ77co@e129823.arm.com>

Hi David,

> On 12/18/25 09:37, Yeoreum Yun wrote:
> > [...]
> > > > I think it would be better to use only __GFP_HIGH in here since
> > > > when kpti_install_ng_mappings() is called, "kswpd" doesn't created yet.
> > > > and to allocate page with assurance, It would be good to use
> > > > min_reserved to.
> > > >
> > > > Am I missing something?
> > >
> > > Personally I think we should just use "GFP_KERNEL | __GFP_ZERO". Anything else
> > > would make this allocation look special, which it is not. If we fail to allocate
> > > at this point in boot, we have bigger problems.
> >
> > But I'm not sure *HOW effective* to use GFP_KERNEL in here.
> > Since it's before the any filesystem inited.
> > IOW, in this context, almost there would be no *page cache*
> > and I think it seems meaningless to use "GFP_KERNEL" and "direct
> > reclaim"
> >
> > So to get success for allocation, __GFP_HIGH | _GFP_ZERO seems much
> > better.
>
> Unless there is a real reason to confuse readers why this is very special,
> just go with "GFP_KERNEL | __GFP_ZERO", really.
>
> In particular if it doesn't matter in practice? Or does it and we are not
> getting your point?

My worries was
    - kpti_install_ng_mappings() is called while in "smp_init()" which is
      before creating the kswapd thread via module_init().
      Just wondered whether it allows to call wakeup_kswapd() before
      kswapd is created.

    - Similar reason kcompactd too.

    - Just wonder how much direct reclaim is effecitve since
      when kpti_install_ng_mappings() called before each
      filesystem initialised where not much of page cache in usage.

TBH (1) and (2) seems fine since each wakeup function checks
the waitqueue. but because of (3),
I think not GFP_KERNEL but __GFP_HIGH | __GFP_DIRECT_RECLAIM | __GFP_ZERO (?)

Am I missing?

--
Sincerely,
Yeoreum Yun


From suzuki.poulose at arm.com  Thu Dec 18 01:32:12 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Thu, 18 Dec 2025 09:32:12 +0000
Subject: [PATCH v2 00/12] coresight: Add CPU cluster funnel/replicator/tmc
 support
In-Reply-To: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
References: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
Message-ID: <47191600-260a-46aa-9af8-dff2b08dc2e8@arm.com>

Cc: Sudeep

On 18/12/2025 08:09, Yuanfang Zhang wrote:
> This patch series adds support for CoreSight components local to CPU clusters,
> including funnel, replicator, and TMC, which reside within CPU cluster power
> domains. These components require special handling due to power domain
> constraints.
> 
> Unlike system-level CoreSight devices, these components share the CPU cluster's
> power domain. When the cluster enters low-power mode (LPM), their registers
> become inaccessible. Notably, `pm_runtime_get` alone cannot bring the cluster
> out of LPM, making standard register access unreliable.

Why ? AFAIU, we have ways to tie the power-domain to that of the cluster
and that can auto-magically keep the cluster power ON as long as you
want to use them.

Suzuki


> 
> To address this, the series introduces:
> - Identifying cluster-bound devices via a new `qcom,cpu-bound-components`
>    device tree property.
> - Implementing deferred probing: if associated CPUs are offline during
>    probe, initialization is deferred until a CPU hotplug notifier detects
>    the CPU coming online.
> - Utilizing `smp_call_function_single()` to ensure register accesses
>    (initialization, enablement, sysfs reads) are always executed on a
>    powered CPU within the target cluster.
> - Extending the CoreSight link `enable` callback to pass the `cs_mode`.
>    This allows drivers to distinguish between SysFS and Perf modes and
>    apply mode-specific logic.
> 
> Jie Gan (1):
>    arm64: dts: qcom: hamoa: add Coresight nodes for APSS debug block
> 
> Yuanfang Zhang (11):
>    dt-bindings: arm: coresight: Add 'qcom,cpu-bound-components' property
>    coresight: Pass trace mode to link enable callback
>    coresight-funnel: Support CPU cluster funnel initialization
>    coresight-funnel: Defer probe when associated CPUs are offline
>    coresight-replicator: Support CPU cluster replicator initialization
>    coresight-replicator: Defer probe when associated CPUs are offline
>    coresight-replicator: Update management interface for CPU-bound devices
>    coresight-tmc: Support probe and initialization for CPU cluster TMCs
>    coresight-tmc-etf: Refactor enable function for CPU cluster ETF support
>    coresight-tmc: Update management interface for CPU-bound TMCs
>    coresight-tmc: Defer probe when associated CPUs are offline
> 
> Verification:
> 
> This series has been verified on sm8750.
> 
> Test steps for delay probe:
> 
> 1. limit the system to enable at most 6 CPU cores during boot.
> 2. echo 1 >/sys/bus/cpu/devices/cpu6/online.
> 3. check whether ETM6 and ETM7 have been probed.
> 
> Test steps for sysfs mode:
> 
> echo 1 >/sys/bus/coresight/devices/tmc_etf0/enable_sink
> echo 1 >/sys/bus/coresight/devices/etm0/enable_source
> echo 1 >/sys/bus/coresight/devices/etm6/enable_source
> echo 0 >/sys/bus/coresight/devices/etm0/enable_source
> echo 0 >/sys/bus/coresight/devicse/etm6/enable_source
> echo 0 >/sys/bus/coresight/devices/tmc_etf0/enable_sink
> 
> echo 1 >/sys/bus/coresight/devices/tmc_etf1/enable_sink
> echo 1 >/sys/bus/coresight/devcies/etm0/enable_source
> cat /dev/tmc_etf1 >/tmp/etf1.bin
> echo 0 >/sys/bus/coresight/devices/etm0/enable_source
> echo 0 >/sys/bus/coresight/devices/tmc_etf1/enable_sink
> 
> echo 1 >/sys/bus/coresight/devices/tmc_etf2/enable_sink
> echo 1 >/sys/bus/coresight/devices/etm6/enable_source
> cat /dev/tmc_etf2 >/tmp/etf2.bin
> echo 0 >/sys/bus/coresight/devices/etm6/enable_source
> echo 0 >/sys/bus/coresight/devices/tmc_etf2/enable_sink
> 
> Test steps for sysfs node:
> 
> cat /sys/bus/coresight/devices/tmc_etf*/mgmt/*
> 
> cat /sys/bus/coresight/devices/funnel*/funnel_ctrl
> 
> cat /sys/bus/coresight/devices/replicator*/mgmt/*
> 
> Test steps for perf mode:
> 
> perf record -a -e cs_etm//k -- sleep 5
> 
> Signed-off-by: Yuanfang Zhang <yuanfang.zhang at oss.qualcomm.com>
> ---
> Changes in v2:
> - Use the qcom,cpu-bound-components device tree property to identify devices
>    bound to a cluster.
> - Refactor commit message.
> - Introduce a supported_cpus field in the drvdata structure to record the CPUs
>    that belong to the cluster where the local component resides.
> - Link to v1: https://lore.kernel.org/r/20251027-cpu_cluster_component_pm-v1-0-31355ac588c2 at oss.qualcomm.com
> 
> ---
> Jie Gan (1):
>        arm64: dts: qcom: hamoa: Add CoreSight nodes for APSS debug block
> 
> Yuanfang Zhang (11):
>        dt-bindings: arm: coresight: Add 'qcom,cpu-bound-components' property
>        coresight-funnel: Support CPU cluster funnel initialization
>        coresight-funnel: Defer probe when associated CPUs are offline
>        coresight-replicator: Support CPU cluster replicator initialization
>        coresight-replicator: Defer probe when associated CPUs are offline
>        coresight-replicator: Update management interface for CPU-bound devices
>        coresight-tmc: Support probe and initialization for CPU cluster TMCs
>        coresight-tmc-etf: Refactor enable function for CPU cluster ETF support
>        coresight-tmc: Update management interface for CPU-bound TMCs
>        coresight-tmc: Defer probe when associated CPUs are offline
>        coresight: Pass trace mode to link enable callback
> 
>   .../bindings/arm/arm,coresight-dynamic-funnel.yaml |   5 +
>   .../arm/arm,coresight-dynamic-replicator.yaml      |   5 +
>   .../devicetree/bindings/arm/arm,coresight-tmc.yaml |   5 +
>   arch/arm64/boot/dts/qcom/hamoa.dtsi                | 926 +++++++++++++++++++++
>   arch/arm64/boot/dts/qcom/purwa.dtsi                |  12 +
>   drivers/hwtracing/coresight/coresight-core.c       |   7 +-
>   drivers/hwtracing/coresight/coresight-funnel.c     | 258 +++++-
>   drivers/hwtracing/coresight/coresight-replicator.c | 341 +++++++-
>   drivers/hwtracing/coresight/coresight-tmc-core.c   | 387 +++++++--
>   drivers/hwtracing/coresight/coresight-tmc-etf.c    | 106 ++-
>   drivers/hwtracing/coresight/coresight-tmc.h        |  10 +
>   drivers/hwtracing/coresight/coresight-tnoc.c       |   3 +-
>   drivers/hwtracing/coresight/coresight-tpda.c       |   3 +-
>   include/linux/coresight.h                          |   3 +-
>   14 files changed, 1902 insertions(+), 169 deletions(-)
> ---
> base-commit: 008d3547aae5bc86fac3eda317489169c3fda112
> change-id: 20251016-cpu_cluster_component_pm-ce518f510433
> 
> Best regards,



From broonie at kernel.org  Thu Dec 18 01:32:40 2025
From: broonie at kernel.org (Mark Brown)
Date: Thu, 18 Dec 2025 09:32:40 +0000
Subject: [PATCH v6 0/2] Add support for NXP XSPI
In-Reply-To: <20251125-xspi-v6-0-22b22de50cda@nxp.com>
References: <20251125-xspi-v6-0-22b22de50cda@nxp.com>
Message-ID: <176605036072.87569.17728068603081639345.b4-ty@kernel.org>

On Tue, 25 Nov 2025 15:42:17 +0800, Haibo Chen wrote:
> XSPI is a flexible SPI host controller which supports up to
> 2 external devices (2 CS). It support Single/Dual/Quad/Octal
> mode data transfer.
> 
> The difference between XSPI and Flexspi is XSPI support
> multiple independent execution environments (EENVs) for HW
> virtualization with some limitations. Each EENV has its own
> interrupt and its own set of programming registers that exists
> in a specific offset range in the XSPI memory map.
> The main environment (EENV0) address space contains all of the
> registers for controlling EENV0 plus all of the general XSPI
> control and programming registers. The register mnemonics for
> the user environments (EENV1 to EENV4) have "_SUB_n" appended
> to the mnemonic for the corresponding main-environment register.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next

Thanks!

[1/2] dt-bindings: spi: Document imx94 xspi
      (no commit info)
[2/2] spi: add driver for NXP XSPI controller
      commit: 29c8c00d9f9db5fb659b6f05f9e8964afc13f3e2

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark



From broonie at kernel.org  Thu Dec 18 01:32:46 2025
From: broonie at kernel.org (Mark Brown)
Date: Thu, 18 Dec 2025 09:32:46 +0000
Subject: [PATCH v7 0/2] Add support for NXP XSPI
In-Reply-To: <20251216-xspi-v7-0-282525220979@nxp.com>
References: <20251216-xspi-v7-0-282525220979@nxp.com>
Message-ID: <176605036628.87569.2326741752652519619.b4-ty@kernel.org>

On Tue, 16 Dec 2025 11:20:12 +0800, Haibo Chen wrote:
> XSPI is a flexible SPI host controller which supports up to
> 2 external devices (2 CS). It support Single/Dual/Quad/Octal
> mode data transfer.
> 
> The difference between XSPI and Flexspi is XSPI support
> multiple independent execution environments (EENVs) for HW
> virtualization with some limitations. Each EENV has its own
> interrupt and its own set of programming registers that exists
> in a specific offset range in the XSPI memory map.
> The main environment (EENV0) address space contains all of the
> registers for controlling EENV0 plus all of the general XSPI
> control and programming registers. The register mnemonics for
> the user environments (EENV1 to EENV4) have "_SUB_n" appended
> to the mnemonic for the corresponding main-environment register.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next

Thanks!

[1/2] spi: dt-bindings: nxp,imx94-xspi: Document imx94 xspi
      commit: 64ba616741bcfc4c7ef1ed856179328300ca0422
[2/2] spi: add driver for NXP XSPI controller
      commit: 29c8c00d9f9db5fb659b6f05f9e8964afc13f3e2

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark



From yeoreum.yun at arm.com  Thu Dec 18 01:36:08 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Thu, 18 Dec 2025 09:36:08 +0000
Subject: [PATCH 2/2] arm64: mmu: use pagetable_alloc_nolock() while
 stop_machine()
In-Reply-To: <aUPJuZINNuNxddRX@tiehlicka>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com>
 <20251212161832.2067134-3-yeoreum.yun@arm.com>
 <aUPJuZINNuNxddRX@tiehlicka>
Message-ID: <aUPLCPAyxkPeBaoD@e129823.arm.com>

Hi,
> On Fri 12-12-25 16:18:32, Yeoreum Yun wrote:
> > linear_map_split_to_ptes() and __kpti_install_ng_mappings()
> > are called as callback of stop_machine().
> > That means these functions context are preemption disabled.
> >
> > Unfortunately, under PREEMPT_RT, the pagetable_alloc() or
> > __get_free_pages() couldn't be called in this context
> > since spin lock that becomes sleepable on RT,
> > potentially causing a sleep during page allocation.
> >
> > To address this, pagetable_alloc_nolock().
>
> As you cannot tolerate allocation failure and this is pretty much
> permanent allocation (AFAIU) why don't you use a static allocation?

Because of when bbl2_noabort is supported, that pages doesn't need to.
If static alloc, that would be a waste in the system where bbl2_noabort
is supported.

When I tested, these extra pages are more than 40 in my FVP.
So, it would be better dynamic allocation and I think since it's quite a
early time, it's probably not failed that's why former code runs as it
is.

--
Sincerely,
Yeoreum Yun


From jie.gan at oss.qualcomm.com  Thu Dec 18 01:39:49 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Thu, 18 Dec 2025 17:39:49 +0800
Subject: [PATCH v1] dt-binding: Update oss email address for Coresight
 documents
In-Reply-To: <175684936304.1217220.3167248149687349464.robh@kernel.org>
References: <20250902042143.1010-1-jie.gan@oss.qualcomm.com>
 <175684936304.1217220.3167248149687349464.robh@kernel.org>
Message-ID: <6a6fe308-d2ab-4cdf-a7d8-d322d915cbc2@oss.qualcomm.com>



On 9/3/2025 5:42 AM, Rob Herring (Arm) wrote:
> 
> On Tue, 02 Sep 2025 12:21:43 +0800, Jie Gan wrote:
>> Update the OSS email addresses across all Coresight documents, as the
>> previous addresses have been deprecated.
>>
>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> ---
>>   .../sysfs-bus-coresight-devices-dummy-source  |  4 +-
>>   .../testing/sysfs-bus-coresight-devices-tpdm  | 56 +++++++++----------
>>   .../arm/arm,coresight-dummy-sink.yaml         |  2 +-
>>   .../arm/arm,coresight-dummy-source.yaml       |  2 +-
>>   .../bindings/arm/qcom,coresight-ctcu.yaml     |  6 +-
>>   .../arm/qcom,coresight-remote-etm.yaml        |  4 +-
>>   .../bindings/arm/qcom,coresight-tnoc.yaml     |  2 +-
>>   .../bindings/arm/qcom,coresight-tpda.yaml     |  4 +-
>>   .../bindings/arm/qcom,coresight-tpdm.yaml     |  4 +-
>>   9 files changed, 42 insertions(+), 42 deletions(-)
>>
> 
> Acked-by: Rob Herring (Arm) <robh at kernel.org>

Gentle reminder

> 



From david at kernel.org  Thu Dec 18 01:41:03 2025
From: david at kernel.org (David Hildenbrand (Red Hat))
Date: Thu, 18 Dec 2025 10:41:03 +0100
Subject: [PATCH v2 2/2] arm64: mmu: avoid allocating pages while
 installing ng-mapping for KPTI
In-Reply-To: <aUPJ1N99LEVZ77co@e129823.arm.com>
References: <20251217182007.2345700-1-yeoreum.yun@arm.com>
 <20251217182007.2345700-3-yeoreum.yun@arm.com>
 <731e3f48-e0a3-4c89-a13a-65ef37faa443@arm.com>
 <aUL/zJlJFRz2/Ybt@e129823.arm.com>
 <72aaa252-6ee6-4353-84ee-b6e10e9920c6@arm.com>
 <aUO9M/oN+nx3nfW+@e129823.arm.com>
 <201d0fa3-2ebe-4df2-926c-9e11607a6f07@kernel.org>
 <aUPJ1N99LEVZ77co@e129823.arm.com>
Message-ID: <10ad7480-4e8a-43c1-9e18-db72e63dbe98@kernel.org>

On 12/18/25 10:31, Yeoreum Yun wrote:
> Hi David,
> 
>> On 12/18/25 09:37, Yeoreum Yun wrote:
>>> [...]
>>>>> I think it would be better to use only __GFP_HIGH in here since
>>>>> when kpti_install_ng_mappings() is called, "kswpd" doesn't created yet.
>>>>> and to allocate page with assurance, It would be good to use
>>>>> min_reserved to.
>>>>>
>>>>> Am I missing something?
>>>>
>>>> Personally I think we should just use "GFP_KERNEL | __GFP_ZERO". Anything else
>>>> would make this allocation look special, which it is not. If we fail to allocate
>>>> at this point in boot, we have bigger problems.
>>>
>>> But I'm not sure *HOW effective* to use GFP_KERNEL in here.
>>> Since it's before the any filesystem inited.
>>> IOW, in this context, almost there would be no *page cache*
>>> and I think it seems meaningless to use "GFP_KERNEL" and "direct
>>> reclaim"
>>>
>>> So to get success for allocation, __GFP_HIGH | _GFP_ZERO seems much
>>> better.
>>
>> Unless there is a real reason to confuse readers why this is very special,
>> just go with "GFP_KERNEL | __GFP_ZERO", really.
>>
>> In particular if it doesn't matter in practice? Or does it and we are not
>> getting your point?
> 
> My worries was
>      - kpti_install_ng_mappings() is called while in "smp_init()" which is
>        before creating the kswapd thread via module_init().
>        Just wondered whether it allows to call wakeup_kswapd() before
>        kswapd is created.

The buddy should really be able to deal with that, no?

> 
>      - Similar reason kcompactd too.

Same as well.

We cannot expect alloc API users to know about these hidden details to 
work around them :)

> 
>      - Just wonder how much direct reclaim is effecitve since
>        when kpti_install_ng_mappings() called before each
>        filesystem initialised where not much of page cache in usage.

Right, but do you really think we would ever trigger that path?

The default should always be GFP_KERNEL unless we have for very good 
reason special demands.

So, do you think in practice there is real value in NOT using GFP_KERNEL? :)

-- 
Cheers

David


From pankaj.gupta at nxp.com  Thu Dec 18 01:45:45 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Thu, 18 Dec 2025 09:45:45 +0000
Subject: [PATCH v22 5/7] firmware: drivers: imx: adds miscdev
In-Reply-To: <20251218-imx-se-if-v22-5-07418c872509@nxp.com>
References: <20251218-imx-se-if-v22-0-07418c872509@nxp.com>
 <20251218-imx-se-if-v22-5-07418c872509@nxp.com>
Message-ID: <DU2PR04MB8599D0CC5EFE125D4B29AA9895A8A@DU2PR04MB8599.eurprd04.prod.outlook.com>

> +static int se_ioctl_cmd_snd_rcv_rsp_handler(struct se_if_device_ctx
> *dev_ctx,
> +					    u64 arg)
> +{
> +	struct se_ioctl_cmd_snd_rcv_rsp_info cmd_snd_rcv_rsp_info = {0};
> +	struct se_if_priv *priv = dev_ctx->priv;
> +	int err = 0;
> +
> +	if (copy_from_user(&cmd_snd_rcv_rsp_info, (u8 __user *)arg,
> +			   sizeof(cmd_snd_rcv_rsp_info))) {
> +		dev_err(priv->dev,
> +			"%s: Failed to copy cmd_snd_rcv_rsp_info from user.",
> +			dev_ctx->devname);
> +		err = -EFAULT;
> +		goto exit;
> +	}
> +
> +	if (cmd_snd_rcv_rsp_info.tx_buf_sz < SE_MU_HDR_SZ) {
> +		dev_err(priv->dev, "%s: User buffer too small(%d < %d)",
> +			dev_ctx->devname, cmd_snd_rcv_rsp_info.tx_buf_sz,
> SE_MU_HDR_SZ);
> +		err = -ENOSPC;
> +		goto exit;
> +	}
> +
> +	err = se_chk_tx_msg_hdr(priv, (struct se_msg_hdr
> *)cmd_snd_rcv_rsp_info.tx_buf);
> +	if (err)
> +		goto exit;
> +
> +	struct se_api_msg *rx_msg __free(kfree) =
> +		kzalloc(cmd_snd_rcv_rsp_info.rx_buf_sz, GFP_KERNEL);
> +	if (!rx_msg) {
> +		err = -ENOMEM;
> +		goto exit;
> +	}
> +
> +	struct se_api_msg *tx_msg __free(kfree) =
> +		memdup_user(cmd_snd_rcv_rsp_info.tx_buf,
> +			    cmd_snd_rcv_rsp_info.tx_buf_sz);
> +	if (IS_ERR(tx_msg)) {
> +		err = PTR_ERR(tx_msg);
> +		goto exit;
> +	}
> +
> +	if (tx_msg->header.tag != priv->if_defs->cmd_tag) {
> +		err = -EINVAL;
> +		goto exit;
> +	}
> +
> +	if (tx_msg->header.ver == priv->if_defs->fw_api_ver &&
> +	    get_load_fw_instance(priv)->is_fw_tobe_loaded) {
> +		err = se_load_firmware(priv);
> +		if (err) {
> +			dev_err(priv->dev, "Could not send msg as FW is not
> loaded.");
> +			err = -EPERM;
> +			goto exit;
> +		}
> +	}
> +	set_se_rcv_msg_timeout(priv, SE_RCV_MSG_LONG_TIMEOUT);
> +
> +	err = ele_msg_send_rcv(dev_ctx, tx_msg,
> cmd_snd_rcv_rsp_info.tx_buf_sz,
> +			       rx_msg, cmd_snd_rcv_rsp_info.rx_buf_sz);
> +	if (err < 0)
> +		goto exit;
> +
> +	dev_dbg(priv->dev, "%s: %s %s.", dev_ctx->devname, __func__,
> +		"message received, start transmit to user");
> +
> +	/* We may need to copy the output data to user before
> +	 * delivering the completion message.
> +	 */
> +	err = se_dev_ctx_cpy_out_data(dev_ctx);
> +	if (err < 0)
> +		goto exit;
> +
> +	/* Copy data from the buffer */
> +	print_hex_dump_debug("to user ", DUMP_PREFIX_OFFSET, 4, 4,
> rx_msg,
> +			     cmd_snd_rcv_rsp_info.rx_buf_sz, false);
> +
> +	if (copy_to_user(cmd_snd_rcv_rsp_info.rx_buf, rx_msg,
> +			 cmd_snd_rcv_rsp_info.rx_buf_sz)) {
> +		dev_err(priv->dev, "%s: Failed to copy to user.", dev_ctx-
> >devname);
> +		err = -EFAULT;
> +	}
> +
> +exit:
> +
> +	/* shared memory is allocated before this IOCTL */
> +	se_dev_ctx_shared_mem_cleanup(dev_ctx);
> +
> +	if (copy_to_user((void __user *)arg, &cmd_snd_rcv_rsp_info,
> +			 sizeof(cmd_snd_rcv_rsp_info))) {
> +		dev_err(priv->dev, "%s: Failed to copy cmd_snd_rcv_rsp_info
> from user.",
> +			dev_ctx->devname);
> +		err = -EFAULT;
> +	}
> +
> +	kfree(tx_msg);
> +	kfree(rx_msg);

This needs to be removed.
Will fix this in v23.

> +	return err;
> +}

From dsimic at manjaro.org  Thu Dec 18 01:47:06 2025
From: dsimic at manjaro.org (Dragan Simic)
Date: Thu, 18 Dec 2025 10:47:06 +0100
Subject: =?utf-8?q?Re=3A?= [PATCH v2 1/4] =?utf-8?q?PCI=3A?==?utf-8?q?_rockchip=3A?= 
 limit RK3399 to =?utf-8?q?2=2E5?= GT/s to prevent damage
In-Reply-To: <qncj72c3owrw7rvnj6jit2sbn4ojyr3kztcjailfxtdboan6sy@ddh5g7v4fcvt>
References: <cover.1763415705.git.geraldogabriel@gmail.com>
 <eaa9c75ca02a53f8bcc293b8bc73d013e26ec253.1763415706.git.geraldogabriel@gmail.com> <qncj72c3owrw7rvnj6jit2sbn4ojyr3kztcjailfxtdboan6sy@ddh5g7v4fcvt>
Message-ID: <3ea8ac20-6332-0c0c-645b-36ca4231c109@manjaro.org>

Heello Manivannan and Geraldo,

On Thursday, December 18, 2025 09:05 CET, Manivannan Sadhasivam <mani at kernel.org> wrote:
> On Mon, Nov 17, 2025 at 06:47:05PM -0300, Geraldo Nascimento wrote:
> > Shawn Lin from Rockchip has reiterated that there may be danger in using
> > their PCIe with 5.0 GT/s speeds. Warn the user if they make a DT change
> > from the default and drive at 2.5 GT/s only, even if the DT
> > max-link-speed property is invalid or inexistent.
> > 
> > This change is corroborated by RK3399 official datasheet [1], which
> > says maximum link speed for this platform is 2.5 GT/s.
> > 
> > [1] https://opensource.rock-chips.com/images/d/d7/Rockchip_RK3399_Datasheet_V2.1-20200323.pdf
> > 
> > Fixes: 956cd99b35a8 ("PCI: rockchip: Separate common code from RC driver")
> > Link: https://lore.kernel.org/all/ffd05070-9879-4468-94e3-b88968b4c21b at rock-chips.com/
> > Cc: stable at vger.kernel.org
> > Reported-by: Dragan Simic <dsimic at manjaro.org>
> > Reported-by: Shawn Lin <shawn.lin at rock-chips.com>
> > Reviewed-by: Dragan Simic <dsimic at manjaro.org>
> > Signed-off-by: Geraldo Nascimento <geraldogabriel at gmail.com>
> > ---
> >  drivers/pci/controller/pcie-rockchip.c | 10 ++++++++--
> >  1 file changed, 8 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/pci/controller/pcie-rockchip.c b/drivers/pci/controller/pcie-rockchip.c
> > index 0f88da378805..992ccf4b139e 100644
> > --- a/drivers/pci/controller/pcie-rockchip.c
> > +++ b/drivers/pci/controller/pcie-rockchip.c
> > @@ -66,8 +66,14 @@ int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip)
> >  	}
> >  
> >  	rockchip->link_gen = of_pci_get_max_link_speed(node);
> > -	if (rockchip->link_gen < 0 || rockchip->link_gen > 2)
> > -		rockchip->link_gen = 2;
> > +	if (rockchip->link_gen < 0 || rockchip->link_gen > 2) {
> > +		rockchip->link_gen = 1;
> > +		dev_warn(dev, "invalid max-link-speed, set to 2.5 GT/s\n");
> > +	}
> > +	else if (rockchip->link_gen == 2) {
> > +		rockchip->link_gen = 1;
> > +		dev_warn(dev, "5.0 GT/s is dangerous, set to 2.5 GT/s\n");
> 
> What does 'danger' really mean here? Link instability or something else?
> Error messages should be precise and not fearmongering.

I agree that the original wording is a bit suboptimal, and I'd suggest
to Geraldo that the produced warning message is changed to

  "5.0 GT/s may cause data corruption, limited to to 2.5 GT/s\n"

or something similar, to better reflect the actual underlying issue.



From hayashi.kunihiko at socionext.com  Thu Dec 18 01:52:36 2025
From: hayashi.kunihiko at socionext.com (Kunihiko Hayashi)
Date: Thu, 18 Dec 2025 18:52:36 +0900
Subject: [PATCH] dt-bindings: usb: Add Socionext Uniphier DWC3 controller
In-Reply-To: <CAL_Jsq+sXky33rD1-DkLvWdNcUEBNAty8t2NzvHFx-2ZK1cCSQ@mail.gmail.com>
References: <20251215212507.3317805-1-robh@kernel.org>
 <0775e913-e531-44b5-b191-7ce0cf4d1e3a@socionext.com>
 <CAL_Jsq+sXky33rD1-DkLvWdNcUEBNAty8t2NzvHFx-2ZK1cCSQ@mail.gmail.com>
Message-ID: <e773f4ef-1772-47d5-bce8-9b97979391a5@socionext.com>

On 2025/12/17 1:38, Rob Herring wrote:
> On Mon, Dec 15, 2025 at 7:22?PM Kunihiko Hayashi
> <hayashi.kunihiko at socionext.com> wrote:
>>
>> Hi Rob,
>>
>> On 2025/12/16 6:25, Rob Herring (Arm) wrote:
>>> The Socionext Uniphier DWC3 controller binding is already in use, but
>>> undocumented. It's a straight-forward binding similar to other DWC3
>>> bindings.
>>
>> After being pointed out by Krzysztof at OSSJapan, I've checked the
>> bindings
>> and was preparing some additions or fixes to resolve the warning.
>>
>> It's almost the same as my proposal, however, I add a little.
>>
>>>
>>> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
>>> ---
>>>    .../bindings/usb/socionext,uniphier-dwc3.yaml | 89 +++++++++++++++++++
>>>    1 file changed, 89 insertions(+)
>>>    create mode 100644
>>> Documentation/devicetree/bindings/usb/socionext,uniphier-dwc3.yaml
>>>
>>> diff --git
>>> a/Documentation/devicetree/bindings/usb/socionext,uniphier-dwc3.yaml
>>> b/Documentation/devicetree/bindings/usb/socionext,uniphier-dwc3.yaml
>>> new file mode 100644
>>> index 000000000000..892ae3458c1b
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/usb/socionext,uniphier-dwc3.yaml
>>> @@ -0,0 +1,89 @@
>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>>> +%YAML 1.2
>>> +---
>>> +$id: http://devicetree.org/schemas/usb/socionext,uniphier-dwc3.yaml#
>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>> +
>>> +title: Socionext Uniphier SuperSpeed DWC3 USB SoC controller
>>> +
>>> +maintainers:
>>> +  - Kunihiko Hayashi <hayashi.kunihiko at socionext.com>
>>> +  - Masami Hiramatsu <mhiramat at kernel.org>
>>> +
>>> +select:
>>> +  properties:
>>> +    compatible:
>>> +      contains:
>>> +        const: socionext,uniphier-dwc3
>>> +  required:
>>> +    - compatible
>>> +
>>> +properties:
>>> +  compatible:
>>> +    items:
>>> +      - const: socionext,uniphier-dwc3
>>> +      - const: snps,dwc3
>>> +
>>> +  reg:
>>> +    maxItems: 1
>>> +
>>> +  interrupts:
>>> +    minItems: 1
>>> +    items:
>>> +      - description: Host or single combined interrupt
>>> +      - description: Peripheral interrupt
>>> +
>>> +  interrupt-names:
>>> +    minItems: 1
>>> +    items:
>>> +      - enum:
>>> +          - dwc_usb3
>>> +          - host
>>> +      - const: peripheral
>> There's no problem, but how about the following description
>> following snps,dwc3.yaml?
>>
>>     interrupt-names:
>>       oneOf:
>>         - const: dwc_usb3
>>         - items:
>>             enum: [host, peripheral]
> 
> That allows for 'peripheral, host' or just 'peripheral'. Mine would
> seemingly allow 'dwc_usb3, host', but snps,dwc3.yaml will prevent
> that.

I see. The property combinations are complex, so
I'll follow your suggestion from the currnet .dts files.
  
>>
>>> +
>>> +  clocks:
>>> +    maxItems: 3
>>> +
>>> +  clock-names:
>>> +    items:
>>> +      - const: ref
>>> +      - const: bus_early
>>> +      - const: suspend
>>> +
>>> +  phys:
>>> +    description: 1 to 4 HighSpeed PHYs followed by 1 or 2 SuperSpeed
>>> PHYs
>>> +    minItems: 2
>>> +    maxItems: 6
>>
>> Since Pro4 only has one PHY, so:
>>       minItems: 1
> 
> Ah, I only checked arm64. Will fix> 
> If there's other arm32 warnings, I'm not looking at those. So fixes
> appreciated there.

Yes, I'll address the arm32 warnings.

Thank you,

---
Best Regards
Kunihiko Hayashi


From diederik at cknow-tech.com  Thu Dec 18 02:01:16 2025
From: diederik at cknow-tech.com (Diederik de Haas)
Date: Thu, 18 Dec 2025 11:01:16 +0100
Subject: [PATCH v2 1/4] PCI: rockchip: limit RK3399 to 2.5 GT/s to
 prevent damage
In-Reply-To: <3ea8ac20-6332-0c0c-645b-36ca4231c109@manjaro.org>
References: <cover.1763415705.git.geraldogabriel@gmail.com>
 <eaa9c75ca02a53f8bcc293b8bc73d013e26ec253.1763415706.git.geraldogabriel@gmail.com> <qncj72c3owrw7rvnj6jit2sbn4ojyr3kztcjailfxtdboan6sy@ddh5g7v4fcvt> <3ea8ac20-6332-0c0c-645b-36ca4231c109@manjaro.org>
Message-ID: <DF197NIRHLIJ.3LIG9GJGJQLQX@cknow-tech.com>

On Thu Dec 18, 2025 at 10:47 AM CET, Dragan Simic wrote:
> Heello Manivannan and Geraldo,
>
> On Thursday, December 18, 2025 09:05 CET, Manivannan Sadhasivam <mani at kernel.org> wrote:
>> On Mon, Nov 17, 2025 at 06:47:05PM -0300, Geraldo Nascimento wrote:
>> > Shawn Lin from Rockchip has reiterated that there may be danger in using
>> > their PCIe with 5.0 GT/s speeds. Warn the user if they make a DT change
>> > from the default and drive at 2.5 GT/s only, even if the DT
>> > max-link-speed property is invalid or inexistent.
>> > 
>> > This change is corroborated by RK3399 official datasheet [1], which
>> > says maximum link speed for this platform is 2.5 GT/s.
>> > 
>> > [1] https://opensource.rock-chips.com/images/d/d7/Rockchip_RK3399_Datasheet_V2.1-20200323.pdf
>> > 
>> > Fixes: 956cd99b35a8 ("PCI: rockchip: Separate common code from RC driver")
>> > Link: https://lore.kernel.org/all/ffd05070-9879-4468-94e3-b88968b4c21b at rock-chips.com/
>> > Cc: stable at vger.kernel.org
>> > Reported-by: Dragan Simic <dsimic at manjaro.org>
>> > Reported-by: Shawn Lin <shawn.lin at rock-chips.com>
>> > Reviewed-by: Dragan Simic <dsimic at manjaro.org>
>> > Signed-off-by: Geraldo Nascimento <geraldogabriel at gmail.com>
>> > ---
>> >  drivers/pci/controller/pcie-rockchip.c | 10 ++++++++--
>> >  1 file changed, 8 insertions(+), 2 deletions(-)
>> > 
>> > diff --git a/drivers/pci/controller/pcie-rockchip.c b/drivers/pci/controller/pcie-rockchip.c
>> > index 0f88da378805..992ccf4b139e 100644
>> > --- a/drivers/pci/controller/pcie-rockchip.c
>> > +++ b/drivers/pci/controller/pcie-rockchip.c
>> > @@ -66,8 +66,14 @@ int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip)
>> >  	}
>> >  
>> >  	rockchip->link_gen = of_pci_get_max_link_speed(node);
>> > -	if (rockchip->link_gen < 0 || rockchip->link_gen > 2)
>> > -		rockchip->link_gen = 2;
>> > +	if (rockchip->link_gen < 0 || rockchip->link_gen > 2) {
>> > +		rockchip->link_gen = 1;
>> > +		dev_warn(dev, "invalid max-link-speed, set to 2.5 GT/s\n");
>> > +	}
>> > +	else if (rockchip->link_gen == 2) {
>> > +		rockchip->link_gen = 1;
>> > +		dev_warn(dev, "5.0 GT/s is dangerous, set to 2.5 GT/s\n");
>> 
>> What does 'danger' really mean here? Link instability or something else?
>> Error messages should be precise and not fearmongering.
>
> I agree that the original wording is a bit suboptimal, and I'd suggest
> to Geraldo that the produced warning message is changed to
>
>   "5.0 GT/s may cause data corruption, limited to to 2.5 GT/s\n"
>
> or something similar, to better reflect the actual underlying issue.

s/limited to to/therefore limit speed to/ ?

Cheers,
  Diederik


From yeoreum.yun at arm.com  Thu Dec 18 02:07:39 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Thu, 18 Dec 2025 10:07:39 +0000
Subject: [PATCH v2 2/2] arm64: mmu: avoid allocating pages while
 installing ng-mapping for KPTI
In-Reply-To: <10ad7480-4e8a-43c1-9e18-db72e63dbe98@kernel.org>
References: <20251217182007.2345700-1-yeoreum.yun@arm.com>
 <20251217182007.2345700-3-yeoreum.yun@arm.com>
 <731e3f48-e0a3-4c89-a13a-65ef37faa443@arm.com>
 <aUL/zJlJFRz2/Ybt@e129823.arm.com>
 <72aaa252-6ee6-4353-84ee-b6e10e9920c6@arm.com>
 <aUO9M/oN+nx3nfW+@e129823.arm.com>
 <201d0fa3-2ebe-4df2-926c-9e11607a6f07@kernel.org>
 <aUPJ1N99LEVZ77co@e129823.arm.com>
 <10ad7480-4e8a-43c1-9e18-db72e63dbe98@kernel.org>
Message-ID: <aUPSa67xnQk/x56R@e129823.arm.com>

Hi David,

> On 12/18/25 10:31, Yeoreum Yun wrote:
> > Hi David,
> >
> > > On 12/18/25 09:37, Yeoreum Yun wrote:
> > > > [...]
> > > > > > I think it would be better to use only __GFP_HIGH in here since
> > > > > > when kpti_install_ng_mappings() is called, "kswpd" doesn't created yet.
> > > > > > and to allocate page with assurance, It would be good to use
> > > > > > min_reserved to.
> > > > > >
> > > > > > Am I missing something?
> > > > >
> > > > > Personally I think we should just use "GFP_KERNEL | __GFP_ZERO". Anything else
> > > > > would make this allocation look special, which it is not. If we fail to allocate
> > > > > at this point in boot, we have bigger problems.
> > > >
> > > > But I'm not sure *HOW effective* to use GFP_KERNEL in here.
> > > > Since it's before the any filesystem inited.
> > > > IOW, in this context, almost there would be no *page cache*
> > > > and I think it seems meaningless to use "GFP_KERNEL" and "direct
> > > > reclaim"
> > > >
> > > > So to get success for allocation, __GFP_HIGH | _GFP_ZERO seems much
> > > > better.
> > >
> > > Unless there is a real reason to confuse readers why this is very special,
> > > just go with "GFP_KERNEL | __GFP_ZERO", really.
> > >
> > > In particular if it doesn't matter in practice? Or does it and we are not
> > > getting your point?
> >
> > My worries was
> >      - kpti_install_ng_mappings() is called while in "smp_init()" which is
> >        before creating the kswapd thread via module_init().
> >        Just wondered whether it allows to call wakeup_kswapd() before
> >        kswapd is created.
>
> The buddy should really be able to deal with that, no?
>
> >
> >      - Similar reason kcompactd too.
>
> Same as well.

Nope. buddy handles them. It was a past :)

>
> We cannot expect alloc API users to know about these hidden details to work
> around them :)
>
> >
> >      - Just wonder how much direct reclaim is effecitve since
> >        when kpti_install_ng_mappings() called before each
> >        filesystem initialised where not much of page cache in usage.
>
> Right, but do you really think we would ever trigger that path?
>
> The default should always be GFP_KERNEL unless we have for very good reason
> special demands.
>
> So, do you think in practice there is real value in NOT using GFP_KERNEL? :)

In the *practical view*. Absoultely NOT
since I don't think it reaches those codes.

Okay. I'll change with GFP_KERNEL | __GFP_ZERO.

Thanks!

--
Sincerely,
Yeoreum Yun


From dsimic at manjaro.org  Thu Dec 18 02:13:10 2025
From: dsimic at manjaro.org (Dragan Simic)
Date: Thu, 18 Dec 2025 11:13:10 +0100
Subject: =?utf-8?q?Re=3A?= [PATCH v2 1/4] =?utf-8?q?PCI=3A?==?utf-8?q?_rockchip=3A?= 
 limit RK3399 to =?utf-8?q?2=2E5?= GT/s to prevent damage
In-Reply-To: <DF197NIRHLIJ.3LIG9GJGJQLQX@cknow-tech.com>
References: <cover.1763415705.git.geraldogabriel@gmail.com>
 <eaa9c75ca02a53f8bcc293b8bc73d013e26ec253.1763415706.git.geraldogabriel@gmail.com> <qncj72c3owrw7rvnj6jit2sbn4ojyr3kztcjailfxtdboan6sy@ddh5g7v4fcvt> <3ea8ac20-6332-0c0c-645b-36ca4231c109@manjaro.org> <DF197NIRHLIJ.3LIG9GJGJQLQX@cknow-tech.com>
Message-ID: <656e9b4e-c350-f808-701e-e49e8dad7062@manjaro.org>

Hello Diederik,

On Thursday, December 18, 2025 11:01 CET, "Diederik de Haas" <diederik at cknow-tech.com> wrote:
> On Thu Dec 18, 2025 at 10:47 AM CET, Dragan Simic wrote:
> > On Thursday, December 18, 2025 09:05 CET, Manivannan Sadhasivam <mani at kernel.org> wrote:
> >> On Mon, Nov 17, 2025 at 06:47:05PM -0300, Geraldo Nascimento wrote:
> >> > Shawn Lin from Rockchip has reiterated that there may be danger in using
> >> > their PCIe with 5.0 GT/s speeds. Warn the user if they make a DT change
> >> > from the default and drive at 2.5 GT/s only, even if the DT
> >> > max-link-speed property is invalid or inexistent.
> >> > 
> >> > This change is corroborated by RK3399 official datasheet [1], which
> >> > says maximum link speed for this platform is 2.5 GT/s.
> >> > 
> >> > [1] https://opensource.rock-chips.com/images/d/d7/Rockchip_RK3399_Datasheet_V2.1-20200323.pdf
> >> > 
> >> > Fixes: 956cd99b35a8 ("PCI: rockchip: Separate common code from RC driver")
> >> > Link: https://lore.kernel.org/all/ffd05070-9879-4468-94e3-b88968b4c21b at rock-chips.com/
> >> > Cc: stable at vger.kernel.org
> >> > Reported-by: Dragan Simic <dsimic at manjaro.org>
> >> > Reported-by: Shawn Lin <shawn.lin at rock-chips.com>
> >> > Reviewed-by: Dragan Simic <dsimic at manjaro.org>
> >> > Signed-off-by: Geraldo Nascimento <geraldogabriel at gmail.com>
> >> > ---
> >> >  drivers/pci/controller/pcie-rockchip.c | 10 ++++++++--
> >> >  1 file changed, 8 insertions(+), 2 deletions(-)
> >> > 
> >> > diff --git a/drivers/pci/controller/pcie-rockchip.c b/drivers/pci/controller/pcie-rockchip.c
> >> > index 0f88da378805..992ccf4b139e 100644
> >> > --- a/drivers/pci/controller/pcie-rockchip.c
> >> > +++ b/drivers/pci/controller/pcie-rockchip.c
> >> > @@ -66,8 +66,14 @@ int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip)
> >> >  	}
> >> >  
> >> >  	rockchip->link_gen = of_pci_get_max_link_speed(node);
> >> > -	if (rockchip->link_gen < 0 || rockchip->link_gen > 2)
> >> > -		rockchip->link_gen = 2;
> >> > +	if (rockchip->link_gen < 0 || rockchip->link_gen > 2) {
> >> > +		rockchip->link_gen = 1;
> >> > +		dev_warn(dev, "invalid max-link-speed, set to 2.5 GT/s\n");
> >> > +	}
> >> > +	else if (rockchip->link_gen == 2) {
> >> > +		rockchip->link_gen = 1;
> >> > +		dev_warn(dev, "5.0 GT/s is dangerous, set to 2.5 GT/s\n");
> >> 
> >> What does 'danger' really mean here? Link instability or something else?
> >> Error messages should be precise and not fearmongering.
> >
> > I agree that the original wording is a bit suboptimal, and I'd suggest
> > to Geraldo that the produced warning message is changed to
> >
> >   "5.0 GT/s may cause data corruption, limited to to 2.5 GT/s\n"
> >
> > or something similar, to better reflect the actual underlying issue.
> 
> s/limited to to/therefore limit speed to/ ?

That would work well in a book or an article, while slightly terse
wording is usually preferred in the messages produced by the kernel,
or in log messages in general.  Such an approach compacts as much
information as possible in as few words as possible, while still
remaining (mostly) grammatically correct.



From lpieralisi at kernel.org  Thu Dec 18 02:14:26 2025
From: lpieralisi at kernel.org (Lorenzo Pieralisi)
Date: Thu, 18 Dec 2025 11:14:26 +0100
Subject: [PATCH v2 0/7] irqchip/gic-v5: Code first ACPI boot support
Message-ID: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org>

The ACPI and ACPI IORT specifications were updated to support bindings
required to describe GICv5 based systems.

The ACPI specification GICv5 bindings ECR [1] were approved and the
required changes merged in the ACPICA upstream repository[5].

The Arm IORT specification [2] has been updated to include GICv5 IWB
specific bindings in revision E.g.

Implement kernel code that - based on the aforementioned bindings - adds
support for GICv5 ACPI probing.

ACPICA changes supporting the bindings are posted with the series; they
were cherry-picked from the upcoming ACPICA Linuxised release patches
and they should _not_ be merged in any upstream branch because the
full set of Linuxised ACPICA changes will be subsequently posted in
order to be merged, I added the two ACPICA patches to make the series
self-contained.

The ACPI bindings were prototyped in edk2 - code available in these
branches [3][4].

===========================
Kernel implementation notes
===========================

IRS and ITS probing is triggered using the standard irqchip ACPI probing
mechanism - there is no significant difference compared to previous GIC
versions other.

The only difference that is worth noting is that GICv3/4 systems include a
single MADT component describing the interrupt controller (ie GIC distributor)
whereas GICv5 systems include one or more IRSes. The probing code is
implemented so that an MADT IRS detection triggers probing for all IRSes
in one go.

The IWB driver probes like any other ACPI device. IORT code is updated so
that a deviceID for the IWB can be detected.

The only major change compared to GICv3/4 systems is the GSI namespace that
is split between PPI/SPI IRQs and IWB backed IRQs.

The main GSI handle - to map an IRQ - has to detect whether to look-up
using the top level GSI domain or an IWB domain in that the two IRQ
namespaces are decoupled.

IORT code implements the logic to retrieve an IWB domain by looking up its
IWB frame id, as described in [1].

Most important implementation detail worth noting is that - at this stage -
ACPI code is not capable of handling devices probe order IRQ dependency on
the interrupt controller driver their IRQ is routed to.

This is not an issue on GICv3/4 systems in that the full GIC hierarchy
probes earlier than any other device, so by the time IRQs mappings have to
be carried out (ie acpi_register_gsi()) the GIC drivers have already
probed.

On GICv5 systems, the IWB is modelled as a device and its device driver
probes at device_initcall time. That's when the IWB IRQ domain is actually
registered - which poses problems for devices whose IRQs are IWB routed and
require to resolve the IRQ mapping before the IWB driver has a chance to
probe.

Work on resolving devices<->IWB probe order dependency has started in
parallel with this series and will be posted shortly.

For PPI/SPI/LPI backed IRQs the probe dependency is not a problem because
in GICv5 systems the IRSes and ITSes probe early so their IRQ domain are
set in place before devices require IRQ mappings.

ACPICA patches are a Linuxised version of ACPICA GICv5 upstream changes
[5] and should not be considered for merging because they would conflict
with the full ACPICA release changes patchset that will be posted later
in this dev cycle (owing to patch dependencies in the ACPICA commit
history) they are there so that the patch series is self-contained.

[1] https://github.com/tianocore/edk2/issues/11148
[2] https://developer.arm.com/documentation/den0049/eg
[3] https://github.com/LeviYeoReum/edk2/tree/levi/gicv5_patch
[4] https://github.com/LeviYeoReum/edk2-platforms/tree/levi/gicv5_patch
[5] https://github.com/acpica/acpica/commits/master/

Signed-off-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
---
Changes in v2:
- Cherry-picked ACPICA upstream changes
- Minor editorial changes
- Removed the "not for merging" tag because now ACPI specs are approved
- Rebased against v6.19-rc1
- Link to v1: https://lore.kernel.org/r/20251028-gicv5-host-acpi-v1-0-01a862feb5ca at kernel.org

---
Jose Marinho (2):
      ACPICA: Add GICv5 MADT structures
      ACPICA: Add Arm IORT IWB node definitions

Lorenzo Pieralisi (5):
      irqdomain: Add parent field to struct irqchip_fwid
      PCI/MSI: Make the pci_msi_map_rid_ctlr_node() interface firmware agnostic
      irqchip/gic-v5: Add ACPI IRS probing
      irqchip/gic-v5: Add ACPI ITS probing
      irqchip/gic-v5: Add ACPI IWB probing

 drivers/acpi/arm64/iort.c                | 190 +++++++++++++++++++-----
 drivers/acpi/bus.c                       |   3 +
 drivers/irqchip/irq-gic-its-msi-parent.c |  43 +++---
 drivers/irqchip/irq-gic-v5-irs.c         | 246 ++++++++++++++++++++++++-------
 drivers/irqchip/irq-gic-v5-its.c         | 132 ++++++++++++++++-
 drivers/irqchip/irq-gic-v5-iwb.c         |  42 ++++--
 drivers/irqchip/irq-gic-v5.c             | 138 ++++++++++++++---
 drivers/pci/msi/irqdomain.c              |  24 ++-
 include/acpi/actbl2.h                    |  56 ++++++-
 include/linux/acpi.h                     |   1 +
 include/linux/acpi_iort.h                |  11 +-
 include/linux/irqchip/arm-gic-v5.h       |   8 +
 include/linux/irqdomain.h                |  30 +++-
 include/linux/msi.h                      |   3 +-
 kernel/irq/irqdomain.c                   |  14 +-
 15 files changed, 784 insertions(+), 157 deletions(-)
---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20251022-gicv5-host-acpi-d59d6c1d3d07

Best regards,
-- 
Lorenzo Pieralisi <lpieralisi at kernel.org>



From lpieralisi at kernel.org  Thu Dec 18 02:14:27 2025
From: lpieralisi at kernel.org (Lorenzo Pieralisi)
Date: Thu, 18 Dec 2025 11:14:27 +0100
Subject: [PATCH v2 1/7] ACPICA: Add GICv5 MADT structures
In-Reply-To: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org>
References: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org>
Message-ID: <20251218-gicv5-host-acpi-v2-1-eec76cd1d40b@kernel.org>

From: Jose Marinho <jose.marinho at arm.com>

The GICv5 adds the following MADT structures:
- IRS
- ITS Config Frame
- ITS Translate Frame

The ACPI spec ECR is at https://github.com/tianocore/edk2/issues/11148

Link: https://github.com/acpica/acpica/commit/69cca52d
Signed-off-by: Jose Marinho <jose.marinho at arm.com>
Signed-off-by: Bob Moore <robert.moore at intel.com>
Signed-off-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
---
 include/acpi/actbl2.h | 49 +++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 45 insertions(+), 4 deletions(-)

diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
index f726bce3eb84..fdabc6c64a9c 100644
--- a/include/acpi/actbl2.h
+++ b/include/acpi/actbl2.h
@@ -1167,7 +1167,10 @@ enum acpi_madt_type {
 	ACPI_MADT_TYPE_IMSIC = 25,
 	ACPI_MADT_TYPE_APLIC = 26,
 	ACPI_MADT_TYPE_PLIC = 27,
-	ACPI_MADT_TYPE_RESERVED = 28,	/* 28 to 0x7F are reserved */
+	ACPI_MADT_TYPE_GICV5_IRS = 28,
+	ACPI_MADT_TYPE_GICV5_ITS = 29,
+	ACPI_MADT_TYPE_GICV5_ITS_TRANSLATE = 30,
+	ACPI_MADT_TYPE_RESERVED = 31,	/* 31 to 0x7F are reserved */
 	ACPI_MADT_TYPE_OEM_RESERVED = 0x80	/* 0x80 to 0xFF are reserved for OEM use */
 };
 
@@ -1289,7 +1292,7 @@ struct acpi_madt_local_x2apic_nmi {
 	u8 reserved[3];		/* reserved - must be zero */
 };
 
-/* 11: Generic interrupt - GICC (ACPI 5.0 + ACPI 6.0 + ACPI 6.3 + ACPI 6.5 changes) */
+/* 11: Generic interrupt - GICC (ACPI 5.0 + ACPI 6.0 + ACPI 6.3 + ACPI 6.5 + ACPI 6.7 changes) */
 
 struct acpi_madt_generic_interrupt {
 	struct acpi_subtable_header header;
@@ -1310,6 +1313,8 @@ struct acpi_madt_generic_interrupt {
 	u8 reserved2[1];
 	u16 spe_interrupt;	/* ACPI 6.3 */
 	u16 trbe_interrupt;	/* ACPI 6.5 */
+	u16 iaffid;		/* ACPI 6.7 */
+	u32 irs_id;
 };
 
 /* Masks for Flags field above */
@@ -1332,7 +1337,7 @@ struct acpi_madt_generic_distributor {
 	u8 reserved2[3];	/* reserved - must be zero */
 };
 
-/* Values for Version field above */
+/* Values for Version field above and Version field in acpi_madt_gicv5_irs */
 
 enum acpi_madt_gic_version {
 	ACPI_MADT_GIC_VERSION_NONE = 0,
@@ -1340,7 +1345,8 @@ enum acpi_madt_gic_version {
 	ACPI_MADT_GIC_VERSION_V2 = 2,
 	ACPI_MADT_GIC_VERSION_V3 = 3,
 	ACPI_MADT_GIC_VERSION_V4 = 4,
-	ACPI_MADT_GIC_VERSION_RESERVED = 5	/* 5 and greater are reserved */
+	ACPI_MADT_GIC_VERSION_V5 = 5,
+	ACPI_MADT_GIC_VERSION_RESERVED = 6	/* 6 and greater are reserved */
 };
 
 /* 13: Generic MSI Frame (ACPI 5.1) */
@@ -1611,6 +1617,41 @@ struct acpi_madt_plic {
 	u32 gsi_base;
 };
 
+/* 28: Arm GICv5 IRS (ACPI 6.7) */
+struct acpi_madt_gicv5_irs {
+	struct acpi_subtable_header header;
+	u8 version;
+	u8 reserved;
+	u32 irs_id;
+	u32 flags;
+	u32 reserved2;
+	u64 config_base_address;
+	u64 setlpi_base_address;
+};
+
+#define ACPI_MADT_IRS_NON_COHERENT      (1)
+
+/* 29: Arm GICv5 ITS Config Frame (ACPI 6.7) */
+struct acpi_madt_gicv5_translator {
+	struct acpi_subtable_header header;
+	u8 flags;
+	u8 reserved;		/* reserved - must be zero */
+	u32 translator_id;
+	u64 base_address;
+};
+
+#define ACPI_MADT_GICV5_ITS_NON_COHERENT      (1)
+
+/* 30: Arm GICv5 ITS Translate Frame (ACPI 6.7) */
+struct acpi_madt_gicv5_translate_frame {
+	struct acpi_subtable_header header;
+	u16 reserved;		/* reserved - must be zero */
+	u32 linked_translator_id;
+	u32 translate_frame_id;
+	u32 reserved2;
+	u64 base_address;
+};
+
 /* 80: OEM data */
 
 struct acpi_madt_oem_data {

-- 
2.50.1



From krzk at kernel.org  Thu Dec 18 02:15:06 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 18 Dec 2025 11:15:06 +0100
Subject: [PATCH v2 1/4] dt-bindings: pwm: allwinner: add h616 pwm
 compatible
In-Reply-To: <20251217082504.80226-2-richard.genoud@bootlin.com>
References: <20251217082504.80226-1-richard.genoud@bootlin.com>
 <20251217082504.80226-2-richard.genoud@bootlin.com>
Message-ID: <52ac76fc-4362-4b5a-ae28-29b874f78399@kernel.org>

On 17/12/2025 09:25, Richard Genoud wrote:
> Allwinner H616 PWM block is quite different from the A10 or H6, but at
> the end, it uses the same clocks as the H6; so the sun4i pwm binding can
> be used.
> It has 6 channels than can generate PWM waveforms or clocks if bypass is
> enabled.
> 
> Suggested-by: Krzysztof Kozlowski <krzk at kernel.org>

Hm? Where did I suggest anything about adding clock cells or documenting
this allwinner device?


Best regards,
Krzysztof


From lpieralisi at kernel.org  Thu Dec 18 02:14:28 2025
From: lpieralisi at kernel.org (Lorenzo Pieralisi)
Date: Thu, 18 Dec 2025 11:14:28 +0100
Subject: [PATCH v2 2/7] ACPICA: Add Arm IORT IWB node definitions
In-Reply-To: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org>
References: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org>
Message-ID: <20251218-gicv5-host-acpi-v2-2-eec76cd1d40b@kernel.org>

From: Jose Marinho <jose.marinho at arm.com>

The IORT IUWB node is defined in IORT issue E.g
See https://developer.arm.com/documentation/den0049/eg

Link: https://github.com/acpica/acpica/commit/a90dc2f5
Signed-off-by: Jose Marinho <jose.marinho at arm.com>
Signed-off-by: Bob Moore <robert.moore at intel.com>
Signed-off-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
---
 include/acpi/actbl2.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
index fdabc6c64a9c..ba1a36d23e32 100644
--- a/include/acpi/actbl2.h
+++ b/include/acpi/actbl2.h
@@ -680,6 +680,7 @@ enum acpi_iort_node_type {
 	ACPI_IORT_NODE_SMMU_V3 = 0x04,
 	ACPI_IORT_NODE_PMCG = 0x05,
 	ACPI_IORT_NODE_RMR = 0x06,
+	ACPI_IORT_NODE_IWB = 0x07,
 };
 
 struct acpi_iort_id_mapping {
@@ -858,6 +859,12 @@ struct acpi_iort_rmr_desc {
 	u32 reserved;
 };
 
+struct acpi_iort_iwb {
+	u64 base_address;
+	u16 iwb_index;		/* Unique IWB identifier matching with the IWB GSI namespace. */
+	char device_name[];	/* Path of the IWB namespace object */
+};
+
 /*******************************************************************************
  *
  * IVRS - I/O Virtualization Reporting Structure

-- 
2.50.1



From lpieralisi at kernel.org  Thu Dec 18 02:14:29 2025
From: lpieralisi at kernel.org (Lorenzo Pieralisi)
Date: Thu, 18 Dec 2025 11:14:29 +0100
Subject: [PATCH v2 3/7] irqdomain: Add parent field to struct irqchip_fwid
In-Reply-To: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org>
References: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org>
Message-ID: <20251218-gicv5-host-acpi-v2-3-eec76cd1d40b@kernel.org>

The GICv5 driver IRQ domain hierarchy requires adding a parent field to
struct irqchip_fwid so that core code can reference a fwnode_handle parent
for a given fwnode.

Add a parent field to struct irqchip_fwid and update the related kernel API
functions to initialize and handle it.

Signed-off-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
Cc: Thomas Gleixner <tglx at linutronix.de>
Cc: Marc Zyngier <maz at kernel.org>
---
 include/linux/irqdomain.h | 30 ++++++++++++++++++++++++++----
 kernel/irq/irqdomain.c    | 14 +++++++++++++-
 2 files changed, 39 insertions(+), 5 deletions(-)

diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 62f81bbeb490..b9df84b447a1 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -257,7 +257,8 @@ static inline void irq_domain_set_pm_device(struct irq_domain *d, struct device
 
 #ifdef CONFIG_IRQ_DOMAIN
 struct fwnode_handle *__irq_domain_alloc_fwnode(unsigned int type, int id,
-						const char *name, phys_addr_t *pa);
+						const char *name, phys_addr_t *pa,
+						struct fwnode_handle *parent);
 
 enum {
 	IRQCHIP_FWNODE_REAL,
@@ -267,18 +268,39 @@ enum {
 
 static inline struct fwnode_handle *irq_domain_alloc_named_fwnode(const char *name)
 {
-	return __irq_domain_alloc_fwnode(IRQCHIP_FWNODE_NAMED, 0, name, NULL);
+	return __irq_domain_alloc_fwnode(IRQCHIP_FWNODE_NAMED, 0, name, NULL, NULL);
+}
+
+static inline
+struct fwnode_handle *irq_domain_alloc_named_fwnode_parent(const char *name,
+							   struct fwnode_handle *parent)
+{
+	return __irq_domain_alloc_fwnode(IRQCHIP_FWNODE_NAMED, 0, name, NULL, parent);
 }
 
 static inline struct fwnode_handle *irq_domain_alloc_named_id_fwnode(const char *name, int id)
 {
 	return __irq_domain_alloc_fwnode(IRQCHIP_FWNODE_NAMED_ID, id, name,
-					 NULL);
+					 NULL, NULL);
+}
+
+static inline
+struct fwnode_handle *irq_domain_alloc_named_id_fwnode_parent(const char *name, int id,
+							      struct fwnode_handle *parent)
+{
+	return __irq_domain_alloc_fwnode(IRQCHIP_FWNODE_NAMED_ID, id, name,
+					 NULL, parent);
 }
 
 static inline struct fwnode_handle *irq_domain_alloc_fwnode(phys_addr_t *pa)
 {
-	return __irq_domain_alloc_fwnode(IRQCHIP_FWNODE_REAL, 0, NULL, pa);
+	return __irq_domain_alloc_fwnode(IRQCHIP_FWNODE_REAL, 0, NULL, pa, NULL);
+}
+
+static inline struct fwnode_handle *irq_domain_alloc_fwnode_parent(phys_addr_t *pa,
+								   struct fwnode_handle *parent)
+{
+	return __irq_domain_alloc_fwnode(IRQCHIP_FWNODE_REAL, 0, NULL, pa, parent);
 }
 
 void irq_domain_free_fwnode(struct fwnode_handle *fwnode);
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 2652c4cfd877..baf77cd167c4 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -33,6 +33,7 @@ static void irq_domain_free_one_irq(struct irq_domain *domain, unsigned int virq
 
 struct irqchip_fwid {
 	struct fwnode_handle	fwnode;
+	struct fwnode_handle	*parent;
 	unsigned int		type;
 	char			*name;
 	phys_addr_t		*pa;
@@ -53,8 +54,16 @@ static const char *irqchip_fwnode_get_name(const struct fwnode_handle *fwnode)
 	return fwid->name;
 }
 
+static struct fwnode_handle *irqchip_fwnode_get_parent(const struct fwnode_handle *fwnode)
+{
+	struct irqchip_fwid *fwid = container_of(fwnode, struct irqchip_fwid, fwnode);
+
+	return fwid->parent;
+}
+
 const struct fwnode_operations irqchip_fwnode_ops = {
 	.get_name = irqchip_fwnode_get_name,
+	.get_parent = irqchip_fwnode_get_parent,
 };
 EXPORT_SYMBOL_GPL(irqchip_fwnode_ops);
 
@@ -65,6 +74,7 @@ EXPORT_SYMBOL_GPL(irqchip_fwnode_ops);
  * @id:		Optional user provided id if name != NULL
  * @name:	Optional user provided domain name
  * @pa:		Optional user-provided physical address
+ * @parent:	Optional parent fwnode_handle
  *
  * Allocate a struct irqchip_fwid, and return a pointer to the embedded
  * fwnode_handle (or NULL on failure).
@@ -76,7 +86,8 @@ EXPORT_SYMBOL_GPL(irqchip_fwnode_ops);
  */
 struct fwnode_handle *__irq_domain_alloc_fwnode(unsigned int type, int id,
 						const char *name,
-						phys_addr_t *pa)
+						phys_addr_t *pa,
+						struct fwnode_handle *parent)
 {
 	struct irqchip_fwid *fwid;
 	char *n;
@@ -104,6 +115,7 @@ struct fwnode_handle *__irq_domain_alloc_fwnode(unsigned int type, int id,
 	fwid->type = type;
 	fwid->name = n;
 	fwid->pa = pa;
+	fwid->parent = parent;
 	fwnode_init(&fwid->fwnode, &irqchip_fwnode_ops);
 	return &fwid->fwnode;
 }

-- 
2.50.1



From lpieralisi at kernel.org  Thu Dec 18 02:14:30 2025
From: lpieralisi at kernel.org (Lorenzo Pieralisi)
Date: Thu, 18 Dec 2025 11:14:30 +0100
Subject: [PATCH v2 4/7] PCI/MSI: Make the pci_msi_map_rid_ctlr_node()
 interface firmware agnostic
In-Reply-To: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org>
References: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org>
Message-ID: <20251218-gicv5-host-acpi-v2-4-eec76cd1d40b@kernel.org>

To support booting with OF and ACPI seamlessly, GIC ITS parent code
requires the PCI/MSI irqdomain layer to implement a function to retrieve
an MSI controller fwnode and map an RID in a firmware agnostic way
(ie pci_msi_map_rid_ctlr_node()).

Convert pci_msi_map_rid_ctlr_node() to an OF agnostic interface
(fwnode_handle based) and update the GIC ITS MSI parent code to reflect
the pci_msi_map_rid_ctlr_node() change.

Signed-off-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
Cc: Thomas Gleixner <tglx at linutronix.de>
Cc: Bjorn Helgaas <bhelgaas at google.com>
Cc: Marc Zyngier <maz at kernel.org>
---
 drivers/irqchip/irq-gic-its-msi-parent.c |  8 ++++----
 drivers/pci/msi/irqdomain.c              | 22 +++++++++++++++++-----
 include/linux/msi.h                      |  3 ++-
 3 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/drivers/irqchip/irq-gic-its-msi-parent.c b/drivers/irqchip/irq-gic-its-msi-parent.c
index 12f45228c867..4d1ad1ee005d 100644
--- a/drivers/irqchip/irq-gic-its-msi-parent.c
+++ b/drivers/irqchip/irq-gic-its-msi-parent.c
@@ -104,7 +104,7 @@ static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev,
 static int its_v5_pci_msi_prepare(struct irq_domain *domain, struct device *dev,
 				  int nvec, msi_alloc_info_t *info)
 {
-	struct device_node *msi_node = NULL;
+	struct fwnode_handle *msi_node = NULL;
 	struct msi_domain_info *msi_info;
 	struct pci_dev *pdev;
 	phys_addr_t pa;
@@ -116,15 +116,15 @@ static int its_v5_pci_msi_prepare(struct irq_domain *domain, struct device *dev,
 
 	pdev = to_pci_dev(dev);
 
-	rid = pci_msi_map_rid_ctlr_node(pdev, &msi_node);
+	rid = pci_msi_map_rid_ctlr_node(domain->parent, pdev, &msi_node);
 	if (!msi_node)
 		return -ENODEV;
 
-	ret = its_translate_frame_address(msi_node, &pa);
+	ret = its_translate_frame_address(to_of_node(msi_node), &pa);
 	if (ret)
 		return -ENODEV;
 
-	of_node_put(msi_node);
+	fwnode_handle_put(msi_node);
 
 	/* ITS specific DeviceID */
 	info->scratchpad[0].ul = rid;
diff --git a/drivers/pci/msi/irqdomain.c b/drivers/pci/msi/irqdomain.c
index a329060287b5..3136341e802c 100644
--- a/drivers/pci/msi/irqdomain.c
+++ b/drivers/pci/msi/irqdomain.c
@@ -376,23 +376,35 @@ u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev)
 }
 
 /**
- * pci_msi_map_rid_ctlr_node - Get the MSI controller node and MSI requester id (RID)
+ * pci_msi_map_rid_ctlr_node - Get the MSI controller fwnode_handle and MSI requester id (RID)
+ * @domain:	The interrupt domain
  * @pdev:	The PCI device
- * @node:	Pointer to store the MSI controller device node
+ * @node:	Pointer to store the MSI controller fwnode_handle
  *
- * Use the firmware data to find the MSI controller node for @pdev.
+ * Use the firmware data to find the MSI controller fwnode_handle for @pdev.
  * If found map the RID and initialize @node with it. @node value must
  * be set to NULL on entry.
  *
  * Returns: The RID.
  */
-u32 pci_msi_map_rid_ctlr_node(struct pci_dev *pdev, struct device_node **node)
+u32 pci_msi_map_rid_ctlr_node(struct irq_domain *domain, struct pci_dev *pdev,
+			      struct fwnode_handle **node)
 {
+	struct device_node *of_node;
 	u32 rid = pci_dev_id(pdev);
 
 	pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid);
 
-	return of_msi_xlate(&pdev->dev, node, rid);
+	of_node = irq_domain_get_of_node(domain);
+	if (of_node) {
+		struct device_node *msi_ctlr_node = NULL;
+
+		rid = of_msi_xlate(&pdev->dev, &msi_ctlr_node, rid);
+		if (msi_ctlr_node)
+			*node = of_fwnode_handle(msi_ctlr_node);
+	}
+
+	return rid;
 }
 
 /**
diff --git a/include/linux/msi.h b/include/linux/msi.h
index 8003e3218c46..8ddb05d5c96a 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -702,7 +702,8 @@ void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
 void pci_msi_mask_irq(struct irq_data *data);
 void pci_msi_unmask_irq(struct irq_data *data);
 u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev);
-u32 pci_msi_map_rid_ctlr_node(struct pci_dev *pdev, struct device_node **node);
+u32 pci_msi_map_rid_ctlr_node(struct irq_domain *domain, struct pci_dev *pdev,
+			      struct fwnode_handle **node);
 struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev);
 void pci_msix_prepare_desc(struct irq_domain *domain, msi_alloc_info_t *arg,
 			   struct msi_desc *desc);

-- 
2.50.1



From lpieralisi at kernel.org  Thu Dec 18 02:14:31 2025
From: lpieralisi at kernel.org (Lorenzo Pieralisi)
Date: Thu, 18 Dec 2025 11:14:31 +0100
Subject: [PATCH v2 5/7] irqchip/gic-v5: Add ACPI IRS probing
In-Reply-To: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org>
References: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org>
Message-ID: <20251218-gicv5-host-acpi-v2-5-eec76cd1d40b@kernel.org>

On ARM64 ACPI systems GICv5 IRSes are described in MADT sub-entries.

Add the required plumbing to parse MADT IRS firmware table entries and
probe the IRS components in ACPI.

Refactor the OF based probe so that common code paths can be reused for
ACPI as well in the process.

Augment the irqdomain_ops.translate() for PPI and SPI IRQs in order to
provide support for their ACPI based firmware translation.

Implement an irqchip ACPI based callback to initialize the global GSI
domain upon an MADT IRS detection.

The IRQCHIP_ACPI_DECLARE() entry in the top level GICv5 driver is only used
to trigger the IRS probing (ie the global GSI domain is initialized once on
the first call on multi-IRS systems); IRS probing takes place by calling
acpi_table_parse_madt() in the IRS sub-driver, that probes all IRSes
in sequence.

Add a new ACPI interrupt model so that it can be detected at runtime and
distinguished from previous GIC architecture models.

Signed-off-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
Cc: Thomas Gleixner <tglx at linutronix.de>
Cc: "Rafael J. Wysocki" <rafael at kernel.org>
Cc: Marc Zyngier <maz at kernel.org>
---
 drivers/acpi/bus.c                 |   3 +
 drivers/irqchip/irq-gic-v5-irs.c   | 239 +++++++++++++++++++++++++++++--------
 drivers/irqchip/irq-gic-v5.c       | 134 ++++++++++++++++++---
 include/linux/acpi.h               |   1 +
 include/linux/irqchip/arm-gic-v5.h |   1 +
 5 files changed, 308 insertions(+), 70 deletions(-)

diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index a984ccd4a2a0..e4f4059c4f1d 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -1197,6 +1197,9 @@ static int __init acpi_bus_init_irq(void)
 	case ACPI_IRQ_MODEL_GIC:
 		message = "GIC";
 		break;
+	case ACPI_IRQ_MODEL_GIC_V5:
+		message = "GICv5";
+		break;
 	case ACPI_IRQ_MODEL_PLATFORM:
 		message = "platform specific model";
 		break;
diff --git a/drivers/irqchip/irq-gic-v5-irs.c b/drivers/irqchip/irq-gic-v5-irs.c
index ce2732d649a3..07c3df5692af 100644
--- a/drivers/irqchip/irq-gic-v5-irs.c
+++ b/drivers/irqchip/irq-gic-v5-irs.c
@@ -5,6 +5,7 @@
 
 #define pr_fmt(fmt)	"GICv5 IRS: " fmt
 
+#include <linux/acpi.h>
 #include <linux/kmemleak.h>
 #include <linux/log2.h>
 #include <linux/of.h>
@@ -545,15 +546,15 @@ int gicv5_irs_register_cpu(int cpuid)
 
 static void __init gicv5_irs_init_bases(struct gicv5_irs_chip_data *irs_data,
 					void __iomem *irs_base,
-					struct fwnode_handle *handle)
+					struct fwnode_handle *handle,
+					bool noncoherent)
 {
-	struct device_node *np = to_of_node(handle);
 	u32 cr0, cr1;
 
 	irs_data->fwnode = handle;
 	irs_data->irs_base = irs_base;
 
-	if (of_property_read_bool(np, "dma-noncoherent")) {
+	if (noncoherent) {
 		/*
 		 * A non-coherent IRS implies that some cache levels cannot be
 		 * used coherently by the cores and GIC. Our only option is to mark
@@ -678,49 +679,13 @@ static void irs_setup_pri_bits(u32 idr1)
 	}
 }
 
-static int __init gicv5_irs_init(struct device_node *node)
+static int __init gicv5_irs_init(struct gicv5_irs_chip_data *irs_data)
 {
-	struct gicv5_irs_chip_data *irs_data;
-	void __iomem *irs_base;
-	u32 idr, spi_count;
-	u8 iaffid_bits;
-	int ret;
+	u32 spi_count, idr = irs_readl_relaxed(irs_data, GICV5_IRS_IDR2);
 
-	irs_data = kzalloc(sizeof(*irs_data), GFP_KERNEL);
-	if (!irs_data)
-		return -ENOMEM;
-
-	raw_spin_lock_init(&irs_data->spi_config_lock);
-
-	ret = of_property_match_string(node, "reg-names", "ns-config");
-	if (ret < 0) {
-		pr_err("%pOF: ns-config reg-name not present\n", node);
-		goto out_err;
-	}
-
-	irs_base = of_io_request_and_map(node, ret, of_node_full_name(node));
-	if (IS_ERR(irs_base)) {
-		pr_err("%pOF: unable to map GICv5 IRS registers\n", node);
-		ret = PTR_ERR(irs_base);
-		goto out_err;
-	}
-
-	gicv5_irs_init_bases(irs_data, irs_base, &node->fwnode);
-
-	idr = irs_readl_relaxed(irs_data, GICV5_IRS_IDR1);
-	iaffid_bits = FIELD_GET(GICV5_IRS_IDR1_IAFFID_BITS, idr) + 1;
-
-	ret = gicv5_irs_of_init_affinity(node, irs_data, iaffid_bits);
-	if (ret) {
-		pr_err("Failed to parse CPU IAFFIDs from the device tree!\n");
-		goto out_iomem;
-	}
-
-	idr = irs_readl_relaxed(irs_data, GICV5_IRS_IDR2);
 	if (WARN(!FIELD_GET(GICV5_IRS_IDR2_LPI, idr),
 		 "LPI support not available - no IPIs, can't proceed\n")) {
-		ret = -ENODEV;
-		goto out_iomem;
+		return -ENODEV;
 	}
 
 	idr = irs_readl_relaxed(irs_data, GICV5_IRS_IDR7);
@@ -729,14 +694,6 @@ static int __init gicv5_irs_init(struct device_node *node)
 	idr = irs_readl_relaxed(irs_data, GICV5_IRS_IDR6);
 	irs_data->spi_range = FIELD_GET(GICV5_IRS_IDR6_SPI_IRS_RANGE, idr);
 
-	if (irs_data->spi_range) {
-		pr_info("%s detected SPI range [%u-%u]\n",
-						of_node_full_name(node),
-						irs_data->spi_min,
-						irs_data->spi_min +
-						irs_data->spi_range - 1);
-	}
-
 	/*
 	 * Do the global setting only on the first IRS.
 	 * Global properties (iaffid_bits, global spi count) are guaranteed to
@@ -760,6 +717,60 @@ static int __init gicv5_irs_init(struct device_node *node)
 	list_add_tail(&irs_data->entry, &irs_nodes);
 
 	return 0;
+}
+
+static int __init gicv5_irs_of_init(struct device_node *node)
+{
+	struct gicv5_irs_chip_data *irs_data;
+	void __iomem *irs_base;
+	u8 iaffid_bits;
+	u32 idr;
+	int ret;
+
+	irs_data = kzalloc(sizeof(*irs_data), GFP_KERNEL);
+	if (!irs_data)
+		return -ENOMEM;
+
+	raw_spin_lock_init(&irs_data->spi_config_lock);
+
+	ret = of_property_match_string(node, "reg-names", "ns-config");
+	if (ret < 0) {
+		pr_err("%pOF: ns-config reg-name not present\n", node);
+		goto out_err;
+	}
+
+	irs_base = of_io_request_and_map(node, ret, of_node_full_name(node));
+	if (IS_ERR(irs_base)) {
+		pr_err("%pOF: unable to map GICv5 IRS registers\n", node);
+		ret = PTR_ERR(irs_base);
+		goto out_err;
+	}
+
+	gicv5_irs_init_bases(irs_data, irs_base, &node->fwnode,
+			     of_property_read_bool(node, "dma-noncoherent"));
+
+	idr = irs_readl_relaxed(irs_data, GICV5_IRS_IDR1);
+	iaffid_bits = FIELD_GET(GICV5_IRS_IDR1_IAFFID_BITS, idr) + 1;
+
+	ret = gicv5_irs_of_init_affinity(node, irs_data, iaffid_bits);
+	if (ret) {
+		pr_err("Failed to parse CPU IAFFIDs from the device tree!\n");
+		goto out_iomem;
+	}
+
+	ret = gicv5_irs_init(irs_data);
+	if (ret)
+		goto out_iomem;
+
+	if (irs_data->spi_range) {
+		pr_info("%s detected SPI range [%u-%u]\n",
+						of_node_full_name(node),
+						irs_data->spi_min,
+						irs_data->spi_min +
+						irs_data->spi_range - 1);
+	}
+
+	return ret;
 
 out_iomem:
 	iounmap(irs_base);
@@ -818,10 +829,136 @@ int __init gicv5_irs_of_probe(struct device_node *parent)
 		if (!of_device_is_compatible(np, "arm,gic-v5-irs"))
 			continue;
 
-		ret = gicv5_irs_init(np);
+		ret = gicv5_irs_of_init(np);
 		if (ret)
 			pr_err("Failed to init IRS %s\n", np->full_name);
 	}
 
 	return list_empty(&irs_nodes) ? -ENODEV : 0;
 }
+
+#ifdef CONFIG_ACPI
+
+#define ACPI_GICV5_IRS_MEM_SIZE (SZ_64K)
+static struct gicv5_irs_chip_data *current_irs_data __initdata;
+static int current_irsid __initdata = -1;
+static u8 current_iaffid_bits __initdata;
+
+static int __init gic_acpi_parse_iaffid(union acpi_subtable_headers *header,
+					const unsigned long end)
+{
+	struct acpi_madt_generic_interrupt *gicc = (struct acpi_madt_generic_interrupt *)header;
+	int cpu;
+
+	if (!(gicc->flags & (ACPI_MADT_ENABLED | ACPI_MADT_GICC_ONLINE_CAPABLE)))
+		return 0;
+
+	if (gicc->irs_id == current_irsid) {
+		cpu = get_logical_index(gicc->arm_mpidr);
+
+		if (gicc->iaffid & ~GENMASK(current_iaffid_bits - 1, 0)) {
+			pr_warn("CPU %d iaffid 0x%x exceeds IRS iaffid bits\n", cpu, gicc->iaffid);
+			return 0;
+		}
+
+		// Bind the IAFFID and the CPU
+		per_cpu(cpu_iaffid, cpu).iaffid = gicc->iaffid;
+		per_cpu(cpu_iaffid, cpu).valid = true;
+		pr_debug("Processed IAFFID %u for CPU%d", per_cpu(cpu_iaffid, cpu).iaffid, cpu);
+
+		// We also know that the CPU is connected to this IRS
+		per_cpu(per_cpu_irs_data, cpu) = current_irs_data;
+	}
+
+	return 0;
+}
+
+static int __init gicv5_irs_acpi_init_affinity(u32 irsid, struct gicv5_irs_chip_data *irs_data)
+{
+	u32 idr;
+
+	current_irsid = irsid;
+	current_irs_data = irs_data;
+
+	idr = irs_readl_relaxed(irs_data, GICV5_IRS_IDR1);
+	current_iaffid_bits = FIELD_GET(GICV5_IRS_IDR1_IAFFID_BITS, idr) + 1;
+
+	acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT, gic_acpi_parse_iaffid, 0);
+
+	return 0;
+}
+
+static struct resource * __init gic_request_region(resource_size_t base, resource_size_t size,
+						   const char *name)
+{
+	struct resource *r = request_mem_region(base, size, name);
+
+	if (!r)
+		pr_warn_once(FW_BUG "%s region %pa has overlapping address\n", name, &base);
+
+	return r;
+}
+
+static int __init gic_acpi_parse_madt_irs(union acpi_subtable_headers *header,
+					  const unsigned long end)
+{
+	struct acpi_madt_gicv5_irs *irs = (struct acpi_madt_gicv5_irs *)header;
+	struct gicv5_irs_chip_data *irs_data;
+	void __iomem *irs_base;
+	struct resource *r;
+	int ret;
+
+	// Per-IRS data structure
+	irs_data = kzalloc(sizeof(*irs_data), GFP_KERNEL);
+	if (!irs_data)
+		return -ENOMEM;
+
+	// This spinlock is used for SPI config changes
+	raw_spin_lock_init(&irs_data->spi_config_lock);
+
+	irs_base = ioremap(irs->config_base_address, ACPI_GICV5_IRS_MEM_SIZE);
+	if (!irs_base) {
+		pr_err("Unable to map GIC IRS registers\n");
+		ret = -ENOMEM;
+		goto out_free;
+	}
+
+	r = gic_request_region(irs->config_base_address, ACPI_GICV5_IRS_MEM_SIZE, "GICv5 IRS");
+	if (!r) {
+		ret = -EBUSY;
+		goto out_map;
+	}
+
+	gicv5_irs_init_bases(irs_data, irs_base, NULL, irs->flags & ACPI_MADT_IRS_NON_COHERENT);
+
+	gicv5_irs_acpi_init_affinity(irs->irs_id, irs_data);
+
+	ret = gicv5_irs_init(irs_data);
+	if (ret)
+		goto out_release;
+
+	if (irs_data->spi_range) {
+		pr_info("%s @%llx detected SPI range [%u-%u]\n", "IRS", irs->config_base_address,
+									irs_data->spi_min,
+									irs_data->spi_min +
+									irs_data->spi_range - 1);
+	}
+
+	return 0;
+
+out_release:
+	release_mem_region(r->start, resource_size(r));
+out_map:
+	iounmap(irs_base);
+out_free:
+	kfree(irs_data);
+	return ret;
+}
+
+int __init gicv5_irs_acpi_probe(void)
+{
+	acpi_table_parse_madt(ACPI_MADT_TYPE_GICV5_IRS, gic_acpi_parse_madt_irs, 0);
+
+	return list_empty(&irs_nodes) ? -ENODEV : 0;
+}
+#endif
diff --git a/drivers/irqchip/irq-gic-v5.c b/drivers/irqchip/irq-gic-v5.c
index 41ef286c4d78..23fd551c4347 100644
--- a/drivers/irqchip/irq-gic-v5.c
+++ b/drivers/irqchip/irq-gic-v5.c
@@ -579,16 +579,36 @@ static __always_inline int gicv5_irq_domain_translate(struct irq_domain *d,
 						      unsigned int *type,
 						      const u8 hwirq_type)
 {
-	if (!is_of_node(fwspec->fwnode))
-		return -EINVAL;
+	unsigned int hwirq_trigger;
+	u8 fwspec_irq_type;
 
-	if (fwspec->param_count < 3)
-		return -EINVAL;
+	if (is_of_node(fwspec->fwnode)) {
 
-	if (fwspec->param[0] != hwirq_type)
-		return -EINVAL;
+		if (fwspec->param_count < 3)
+			return -EINVAL;
 
-	*hwirq = fwspec->param[1];
+		fwspec_irq_type = fwspec->param[0];
+
+		if (fwspec->param[0] != hwirq_type)
+			return -EINVAL;
+
+		*hwirq = fwspec->param[1];
+		hwirq_trigger = fwspec->param[2];
+	}
+
+	if (is_fwnode_irqchip(fwspec->fwnode)) {
+
+		if (fwspec->param_count != 2)
+			return -EINVAL;
+
+		fwspec_irq_type = FIELD_GET(GICV5_HWIRQ_TYPE, fwspec->param[0]);
+
+		if (fwspec_irq_type != hwirq_type)
+			return -EINVAL;
+
+		*hwirq = FIELD_GET(GICV5_HWIRQ_ID, fwspec->param[0]);
+		hwirq_trigger = fwspec->param[1];
+	}
 
 	switch (hwirq_type) {
 	case GICV5_HWIRQ_TYPE_PPI:
@@ -600,7 +620,7 @@ static __always_inline int gicv5_irq_domain_translate(struct irq_domain *d,
 							 IRQ_TYPE_EDGE_RISING;
 		break;
 	case GICV5_HWIRQ_TYPE_SPI:
-		*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
+		*type = hwirq_trigger & IRQ_TYPE_SENSE_MASK;
 		break;
 	default:
 		BUILD_BUG_ON(1);
@@ -660,10 +680,18 @@ static void gicv5_irq_domain_free(struct irq_domain *domain, unsigned int virq,
 static int gicv5_irq_ppi_domain_select(struct irq_domain *d, struct irq_fwspec *fwspec,
 				       enum irq_domain_bus_token bus_token)
 {
+	u32 hwirq_type;
+
 	if (fwspec->fwnode != d->fwnode)
 		return 0;
 
-	if (fwspec->param[0] != GICV5_HWIRQ_TYPE_PPI)
+	if (is_of_node(fwspec->fwnode))
+		hwirq_type = fwspec->param[0];
+
+	if (is_fwnode_irqchip(fwspec->fwnode))
+		hwirq_type = FIELD_GET(GICV5_HWIRQ_TYPE, fwspec->param[0]);
+
+	if (hwirq_type != GICV5_HWIRQ_TYPE_PPI)
 		return 0;
 
 	return (d == gicv5_global_data.ppi_domain);
@@ -718,10 +746,18 @@ static int gicv5_irq_spi_domain_alloc(struct irq_domain *domain, unsigned int vi
 static int gicv5_irq_spi_domain_select(struct irq_domain *d, struct irq_fwspec *fwspec,
 				       enum irq_domain_bus_token bus_token)
 {
+	u32 hwirq_type;
+
 	if (fwspec->fwnode != d->fwnode)
 		return 0;
 
-	if (fwspec->param[0] != GICV5_HWIRQ_TYPE_SPI)
+	if (is_of_node(fwspec->fwnode))
+		hwirq_type = fwspec->param[0];
+
+	if (is_fwnode_irqchip(fwspec->fwnode))
+		hwirq_type = FIELD_GET(GICV5_HWIRQ_TYPE, fwspec->param[0]);
+
+	if (hwirq_type != GICV5_HWIRQ_TYPE_SPI)
 		return 0;
 
 	return (d == gicv5_global_data.spi_domain);
@@ -1082,16 +1118,12 @@ static inline void __init gic_of_setup_kvm_info(struct device_node *node)
 }
 #endif // CONFIG_KVM
 
-static int __init gicv5_of_init(struct device_node *node, struct device_node *parent)
+static int __init gicv5_init_common(struct fwnode_handle *parent_domain)
 {
-	int ret = gicv5_irs_of_probe(node);
+	int ret = gicv5_init_domains(parent_domain);
 	if (ret)
 		return ret;
 
-	ret = gicv5_init_domains(of_fwnode_handle(node));
-	if (ret)
-		goto out_irs;
-
 	gicv5_set_cpuif_pribits();
 	gicv5_set_cpuif_idbits();
 
@@ -1113,18 +1145,82 @@ static int __init gicv5_of_init(struct device_node *node, struct device_node *pa
 	gicv5_smp_init();
 
 	gicv5_irs_its_probe();
-
-	gic_of_setup_kvm_info(node);
-
 	return 0;
 
 out_int:
 	gicv5_cpu_disable_interrupts();
 out_dom:
 	gicv5_free_domains();
+	return ret;
+}
+
+static int __init gicv5_of_init(struct device_node *node, struct device_node *parent)
+{
+	int ret = gicv5_irs_of_probe(node);
+	if (ret)
+		return ret;
+
+	ret = gicv5_init_common(of_fwnode_handle(node));
+	if (ret)
+		goto out_irs;
+
+	gic_of_setup_kvm_info(node);
+
+	return 0;
 out_irs:
 	gicv5_irs_remove();
 
 	return ret;
 }
 IRQCHIP_DECLARE(gic_v5, "arm,gic-v5", gicv5_of_init);
+
+#ifdef CONFIG_ACPI
+static bool __init acpi_validate_gic_table(struct acpi_subtable_header *header,
+					   struct acpi_probe_entry *ape)
+{
+	struct acpi_madt_gicv5_irs *irs = (struct acpi_madt_gicv5_irs *)header;
+
+	return (irs->version == ape->driver_data);
+}
+
+static struct fwnode_handle *gsi_domain_handle;
+
+static struct fwnode_handle *gic_v5_get_gsi_domain_id(u32 gsi)
+{
+	return gsi_domain_handle;
+}
+
+static int __init gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end)
+{
+	struct acpi_madt_gicv5_irs *irs = (struct acpi_madt_gicv5_irs *)header;
+	int ret;
+
+	if (gsi_domain_handle)
+		return 0;
+
+	gsi_domain_handle = irq_domain_alloc_fwnode(&irs->config_base_address);
+	if (!gsi_domain_handle)
+		return -ENOMEM;
+
+	ret = gicv5_irs_acpi_probe();
+	if (ret)
+		goto out_fwnode;
+
+	ret = gicv5_init_common(gsi_domain_handle);
+	if (ret)
+		goto out_irs;
+
+	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC_V5, gic_v5_get_gsi_domain_id);
+
+	return 0;
+
+out_irs:
+	gicv5_irs_remove();
+out_fwnode:
+	irq_domain_free_fwnode(gsi_domain_handle);
+	return ret;
+}
+IRQCHIP_ACPI_DECLARE(gic_v5, ACPI_MADT_TYPE_GICV5_IRS,
+		     acpi_validate_gic_table, ACPI_MADT_GIC_VERSION_V5,
+		     gic_acpi_init);
+#endif
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index fbf0c3a65f59..3a412dcebc29 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -107,6 +107,7 @@ enum acpi_irq_model_id {
 	ACPI_IRQ_MODEL_IOSAPIC,
 	ACPI_IRQ_MODEL_PLATFORM,
 	ACPI_IRQ_MODEL_GIC,
+	ACPI_IRQ_MODEL_GIC_V5,
 	ACPI_IRQ_MODEL_LPIC,
 	ACPI_IRQ_MODEL_RINTC,
 	ACPI_IRQ_MODEL_COUNT
diff --git a/include/linux/irqchip/arm-gic-v5.h b/include/linux/irqchip/arm-gic-v5.h
index 68ddcdb1cec5..ff5b1a4931d7 100644
--- a/include/linux/irqchip/arm-gic-v5.h
+++ b/include/linux/irqchip/arm-gic-v5.h
@@ -344,6 +344,7 @@ void __init gicv5_init_lpi_domain(void);
 void __init gicv5_free_lpi_domain(void);
 
 int gicv5_irs_of_probe(struct device_node *parent);
+int gicv5_irs_acpi_probe(void);
 void gicv5_irs_remove(void);
 int gicv5_irs_enable(void);
 void gicv5_irs_its_probe(void);

-- 
2.50.1



From lpieralisi at kernel.org  Thu Dec 18 02:14:32 2025
From: lpieralisi at kernel.org (Lorenzo Pieralisi)
Date: Thu, 18 Dec 2025 11:14:32 +0100
Subject: [PATCH v2 6/7] irqchip/gic-v5: Add ACPI ITS probing
In-Reply-To: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org>
References: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org>
Message-ID: <20251218-gicv5-host-acpi-v2-6-eec76cd1d40b@kernel.org>

On ACPI ARM64 systems the GICv5 ITS configuration and translate frames
are described in the MADT table.

Refactor the current GICv5 ITS driver code to share common functions
between ACPI and OF and implement ACPI probing in the GICv5 ITS driver.

Add iort_msi_xlate() to map a device ID and retrieve an MSI controller
fwnode node for ACPI systems and update pci_msi_map_rid_ctlr_node() to
use it in its ACPI code path.

Add the required functions to IORT code for deviceID retrieval and IRQ
domain registration and look-up so that the GICv5 ITS driver in an
ACPI based system can be successfully probed.

Signed-off-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
Cc: Thomas Gleixner <tglx at linutronix.de>
Cc: Hanjun Guo <guohanjun at huawei.com>
Cc: Sudeep Holla <sudeep.holla at arm.com>
Cc: Marc Zyngier <maz at kernel.org>
---
 drivers/acpi/arm64/iort.c                |  95 +++++++++++++++++-----
 drivers/irqchip/irq-gic-its-msi-parent.c |  39 ++++-----
 drivers/irqchip/irq-gic-v5-irs.c         |   7 +-
 drivers/irqchip/irq-gic-v5-its.c         | 132 ++++++++++++++++++++++++++++++-
 drivers/pci/msi/irqdomain.c              |   2 +
 include/linux/acpi_iort.h                |  10 ++-
 include/linux/irqchip/arm-gic-v5.h       |   1 +
 7 files changed, 241 insertions(+), 45 deletions(-)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 65f0f56ad753..17dbe66da804 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -595,45 +595,45 @@ u32 iort_msi_map_id(struct device *dev, u32 input_id)
 }
 
 /**
- * iort_pmsi_get_dev_id() - Get the device id for a device
+ * iort_msi_xlate() - Map a MSI input ID for a device
  * @dev: The device for which the mapping is to be done.
- * @dev_id: The device ID found.
+ * @input_id: The device input ID.
+ * @fwnode: Pointer to store the fwnode.
  *
- * Returns: 0 for successful find a dev id, -ENODEV on error
+ * Returns: mapped MSI ID on success, input ID otherwise
+ *	    On success, the fwnode pointer is initialized to the MSI
+ *	    controller fwnode handle.
  */
-int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id)
+u32 iort_msi_xlate(struct device *dev, u32 input_id, struct fwnode_handle **fwnode)
 {
-	int i, index;
+	struct acpi_iort_its_group *its;
 	struct acpi_iort_node *node;
+	u32 dev_id;
 
 	node = iort_find_dev_node(dev);
 	if (!node)
-		return -ENODEV;
+		return input_id;
 
-	index = iort_get_id_mapping_index(node);
-	/* if there is a valid index, go get the dev_id directly */
-	if (index >= 0) {
-		if (iort_node_get_id(node, dev_id, index))
-			return 0;
-	} else {
-		for (i = 0; i < node->mapping_count; i++) {
-			if (iort_node_map_platform_id(node, dev_id,
-						      IORT_MSI_TYPE, i))
-				return 0;
-		}
-	}
+	node = iort_node_map_id(node, input_id, &dev_id, IORT_MSI_TYPE);
+	if (!node)
+		return input_id;
 
-	return -ENODEV;
+	/* Move to ITS specific data */
+	its = (struct acpi_iort_its_group *)node->node_data;
+
+	*fwnode = iort_find_domain_token(its->identifiers[0]);
+
+	return dev_id;
 }
 
-static int __maybe_unused iort_find_its_base(u32 its_id, phys_addr_t *base)
+int iort_its_translate_pa(struct fwnode_handle *node, phys_addr_t *base)
 {
 	struct iort_its_msi_chip *its_msi_chip;
 	int ret = -ENODEV;
 
 	spin_lock(&iort_msi_chip_lock);
 	list_for_each_entry(its_msi_chip, &iort_msi_chip_list, list) {
-		if (its_msi_chip->translation_id == its_id) {
+		if (its_msi_chip->fw_node == node) {
 			*base = its_msi_chip->base_addr;
 			ret = 0;
 			break;
@@ -644,6 +644,59 @@ static int __maybe_unused iort_find_its_base(u32 its_id, phys_addr_t *base)
 	return ret;
 }
 
+static int __maybe_unused iort_find_its_base(u32 its_id, phys_addr_t *base)
+{
+	struct fwnode_handle *fwnode = iort_find_domain_token(its_id);
+
+	if (!fwnode)
+		return -ENODEV;
+
+	return iort_its_translate_pa(fwnode, base);
+}
+
+/**
+ * iort_pmsi_get_msi_info() - Get the device id and translate frame PA for a device
+ * @dev: The device for which the mapping is to be done.
+ * @dev_id: The device ID found.
+ * @pa: optional pointer to store translate frame address.
+ *
+ * Returns: 0 for successful devid and pa retrieval, -ENODEV on error
+ */
+int iort_pmsi_get_msi_info(struct device *dev, u32 *dev_id, phys_addr_t *pa)
+{
+	struct acpi_iort_node *node, *parent = NULL;
+	struct acpi_iort_its_group *its;
+	int i, index;
+
+	node = iort_find_dev_node(dev);
+	if (!node)
+		return -ENODEV;
+
+	index = iort_get_id_mapping_index(node);
+	/* if there is a valid index, go get the dev_id directly */
+	if (index >= 0) {
+		parent = iort_node_get_id(node, dev_id, index);
+	} else {
+		for (i = 0; i < node->mapping_count; i++) {
+			parent = iort_node_map_platform_id(node, dev_id,
+						      IORT_MSI_TYPE, i);
+			if (parent)
+				break;
+		}
+	}
+
+	if (parent && pa) {
+		int ret;
+
+		its = (struct acpi_iort_its_group *)node->node_data;
+		ret = iort_find_its_base(its->identifiers[0], pa);
+		if (ret)
+			return ret;
+	}
+
+	return parent ? 0 : -ENODEV;
+}
+
 /**
  * iort_dev_find_its_id() - Find the ITS identifier for a device
  * @dev: The device.
diff --git a/drivers/irqchip/irq-gic-its-msi-parent.c b/drivers/irqchip/irq-gic-its-msi-parent.c
index 4d1ad1ee005d..a832cdb2e697 100644
--- a/drivers/irqchip/irq-gic-its-msi-parent.c
+++ b/drivers/irqchip/irq-gic-its-msi-parent.c
@@ -19,18 +19,24 @@
 				 MSI_FLAG_PCI_MSIX      |	\
 				 MSI_FLAG_MULTI_PCI_MSI)
 
-static int its_translate_frame_address(struct device_node *msi_node, phys_addr_t *pa)
+static int its_translate_frame_address(struct fwnode_handle *msi_node, phys_addr_t *pa)
 {
 	struct resource res;
 	int ret;
 
-	ret = of_property_match_string(msi_node, "reg-names", "ns-translate");
-	if (ret < 0)
-		return ret;
+	if (is_of_node(msi_node)) {
+		struct device_node *msi_np = to_of_node(msi_node);
 
-	ret = of_address_to_resource(msi_node, ret, &res);
-	if (ret)
-		return ret;
+		ret = of_property_match_string(msi_np, "reg-names", "ns-translate");
+		if (ret < 0)
+			return ret;
+
+		ret = of_address_to_resource(msi_np, ret, &res);
+		if (ret)
+			return ret;
+	} else {
+		ret = iort_its_translate_pa(msi_node, &res.start);
+	}
 
 	*pa = res.start;
 	return 0;
@@ -120,7 +126,7 @@ static int its_v5_pci_msi_prepare(struct irq_domain *domain, struct device *dev,
 	if (!msi_node)
 		return -ENODEV;
 
-	ret = its_translate_frame_address(to_of_node(msi_node), &pa);
+	ret = its_translate_frame_address(msi_node, &pa);
 	if (ret)
 		return -ENODEV;
 
@@ -161,7 +167,7 @@ static int of_pmsi_get_msi_info(struct irq_domain *domain, struct device *dev, u
 				ret = -EINVAL;
 
 			if (!ret && pa)
-				ret = its_translate_frame_address(it.node, pa);
+				ret = its_translate_frame_address(of_fwnode_handle(it.node), pa);
 
 			if (!ret)
 				*dev_id = args;
@@ -176,11 +182,6 @@ static int of_pmsi_get_msi_info(struct irq_domain *domain, struct device *dev, u
 	return of_map_id(dev->of_node, dev->id, "msi-map", "msi-map-mask", &msi_ctrl, dev_id);
 }
 
-int __weak iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id)
-{
-	return -1;
-}
-
 static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
 			    int nvec, msi_alloc_info_t *info)
 {
@@ -191,7 +192,7 @@ static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
 	if (dev->of_node)
 		ret = of_pmsi_get_msi_info(domain->parent, dev, &dev_id, NULL);
 	else
-		ret = iort_pmsi_get_dev_id(dev, &dev_id);
+		ret = iort_pmsi_get_msi_info(dev, &dev_id, NULL);
 	if (ret)
 		return ret;
 
@@ -214,10 +215,10 @@ static int its_v5_pmsi_prepare(struct irq_domain *domain, struct device *dev,
 	u32 dev_id;
 	int ret;
 
-	if (!dev->of_node)
-		return -ENODEV;
-
-	ret = of_pmsi_get_msi_info(domain->parent, dev, &dev_id, &pa);
+	if (dev->of_node)
+		ret = of_pmsi_get_msi_info(domain->parent, dev, &dev_id, &pa);
+	else
+		ret = iort_pmsi_get_msi_info(dev, &dev_id, &pa);
 	if (ret)
 		return ret;
 
diff --git a/drivers/irqchip/irq-gic-v5-irs.c b/drivers/irqchip/irq-gic-v5-irs.c
index 07c3df5692af..a3a0b270b5be 100644
--- a/drivers/irqchip/irq-gic-v5-irs.c
+++ b/drivers/irqchip/irq-gic-v5-irs.c
@@ -816,8 +816,11 @@ void __init gicv5_irs_its_probe(void)
 {
 	struct gicv5_irs_chip_data *irs_data;
 
-	list_for_each_entry(irs_data, &irs_nodes, entry)
-		gicv5_its_of_probe(to_of_node(irs_data->fwnode));
+	if (acpi_disabled)
+		list_for_each_entry(irs_data, &irs_nodes, entry)
+			gicv5_its_of_probe(to_of_node(irs_data->fwnode));
+	else
+		gicv5_its_acpi_probe();
 }
 
 int __init gicv5_irs_of_probe(struct device_node *parent)
diff --git a/drivers/irqchip/irq-gic-v5-its.c b/drivers/irqchip/irq-gic-v5-its.c
index 554485f0be1f..751ccd88549a 100644
--- a/drivers/irqchip/irq-gic-v5-its.c
+++ b/drivers/irqchip/irq-gic-v5-its.c
@@ -5,6 +5,8 @@
 
 #define pr_fmt(fmt)	"GICv5 ITS: " fmt
 
+#include <linux/acpi.h>
+#include <linux/acpi_iort.h>
 #include <linux/bitmap.h>
 #include <linux/iommu.h>
 #include <linux/init.h>
@@ -1115,7 +1117,7 @@ static int gicv5_its_init_domain(struct gicv5_its_chip_data *its, struct irq_dom
 }
 
 static int __init gicv5_its_init_bases(void __iomem *its_base, struct fwnode_handle *handle,
-				       struct irq_domain *parent_domain)
+				       struct irq_domain *parent_domain, bool noncoherent)
 {
 	struct device_node *np = to_of_node(handle);
 	struct gicv5_its_chip_data *its_node;
@@ -1208,7 +1210,8 @@ static int __init gicv5_its_init(struct device_node *node)
 	}
 
 	ret = gicv5_its_init_bases(its_base, of_fwnode_handle(node),
-				   gicv5_global_data.lpi_domain);
+				   gicv5_global_data.lpi_domain,
+				   of_property_read_bool(node, "dma-noncoherent"));
 	if (ret)
 		goto out_unmap;
 
@@ -1231,3 +1234,128 @@ void __init gicv5_its_of_probe(struct device_node *parent)
 			pr_err("Failed to init ITS %s\n", np->full_name);
 	}
 }
+
+#ifdef CONFIG_ACPI
+
+#define ACPI_GICV5_ITS_MEM_SIZE (SZ_64K)
+
+static struct acpi_madt_gicv5_translator *current_its_entry __initdata;
+static struct fwnode_handle *current_its_fwnode __initdata;
+
+static int __init gic_acpi_parse_madt_its_translate(union acpi_subtable_headers *header,
+						    const unsigned long end)
+{
+	struct acpi_madt_gicv5_translate_frame *its_frame;
+	struct fwnode_handle *msi_dom_handle;
+	struct resource res = {};
+	int err;
+
+	its_frame = (struct acpi_madt_gicv5_translate_frame *)header;
+	if (its_frame->linked_translator_id != current_its_entry->translator_id)
+		return 0;
+
+	res.start = its_frame->base_address;
+	res.end = its_frame->base_address + ACPI_GICV5_ITS_MEM_SIZE - 1;
+	res.flags = IORESOURCE_MEM;
+
+	msi_dom_handle = irq_domain_alloc_fwnode_parent(&res.start, current_its_fwnode);
+	if (!msi_dom_handle) {
+		pr_err("ITS@%pa: Unable to allocate GICv5 ITS translate domain token\n",
+		       &res.start);
+		return -ENOMEM;
+	}
+
+	err = iort_register_domain_token(its_frame->translate_frame_id, res.start,
+					 msi_dom_handle);
+	if (err) {
+		pr_err("ITS@%pa: Unable to register GICv5 ITS domain token (ITS TRANSLATE FRAME ID %d) to IORT\n",
+		       &res.start, its_frame->translate_frame_id);
+		irq_domain_free_fwnode(msi_dom_handle);
+		return err;
+	}
+
+	return 0;
+}
+
+static int __init gic_acpi_free_madt_its_translate(union acpi_subtable_headers *header,
+						   const unsigned long end)
+{
+	struct acpi_madt_gicv5_translate_frame *its_frame;
+	struct fwnode_handle *msi_dom_handle;
+
+	its_frame = (struct acpi_madt_gicv5_translate_frame *)header;
+	if (its_frame->linked_translator_id != current_its_entry->translator_id)
+		return 0;
+
+	msi_dom_handle = iort_find_domain_token(its_frame->translate_frame_id);
+	if (!msi_dom_handle)
+		return 0;
+
+	iort_deregister_domain_token(its_frame->translate_frame_id);
+	irq_domain_free_fwnode(msi_dom_handle);
+
+	return 0;
+}
+
+static int __init gic_acpi_parse_madt_its(union acpi_subtable_headers *header,
+					  const unsigned long end)
+{
+	struct acpi_madt_gicv5_translator *its_entry;
+	struct fwnode_handle *dom_handle;
+	struct resource res = {};
+	void __iomem *its_base;
+	int err;
+
+	its_entry = (struct acpi_madt_gicv5_translator *)header;
+	res.start = its_entry->base_address;
+	res.end = its_entry->base_address + ACPI_GICV5_ITS_MEM_SIZE - 1;
+	res.flags = IORESOURCE_MEM;
+
+	if (!request_mem_region(res.start, resource_size(&res), "GICv5 ITS"))
+		return -EBUSY;
+
+	dom_handle = irq_domain_alloc_fwnode(&res.start);
+	if (!dom_handle) {
+		pr_err("ITS@%pa: Unable to allocate GICv5 ITS domain token\n",
+		       &res.start);
+		err = -ENOMEM;
+		goto out_rel_res;
+	}
+
+	current_its_entry = its_entry;
+	current_its_fwnode = dom_handle;
+
+	acpi_table_parse_madt(ACPI_MADT_TYPE_GICV5_ITS_TRANSLATE,
+			      gic_acpi_parse_madt_its_translate, 0);
+
+	its_base = ioremap(res.start, ACPI_GICV5_ITS_MEM_SIZE);
+	if (!its_base) {
+		err = -ENOMEM;
+		goto out_unregister;
+	}
+
+	err = gicv5_its_init_bases(its_base, dom_handle, gicv5_global_data.lpi_domain,
+				   its_entry->flags & ACPI_MADT_GICV5_ITS_NON_COHERENT);
+	if (err)
+		goto out_unmap;
+
+	return 0;
+
+out_unmap:
+	iounmap(its_base);
+out_unregister:
+	acpi_table_parse_madt(ACPI_MADT_TYPE_GICV5_ITS_TRANSLATE,
+			      gic_acpi_free_madt_its_translate, 0);
+	irq_domain_free_fwnode(dom_handle);
+out_rel_res:
+	release_mem_region(res.start, resource_size(&res));
+	return err;
+}
+
+void __init gicv5_its_acpi_probe(void)
+{
+	acpi_table_parse_madt(ACPI_MADT_TYPE_GICV5_ITS, gic_acpi_parse_madt_its, 0);
+}
+#else
+void __init gicv5_its_acpi_probe(void) { }
+#endif
diff --git a/drivers/pci/msi/irqdomain.c b/drivers/pci/msi/irqdomain.c
index 3136341e802c..25fcc2114803 100644
--- a/drivers/pci/msi/irqdomain.c
+++ b/drivers/pci/msi/irqdomain.c
@@ -402,6 +402,8 @@ u32 pci_msi_map_rid_ctlr_node(struct irq_domain *domain, struct pci_dev *pdev,
 		rid = of_msi_xlate(&pdev->dev, &msi_ctlr_node, rid);
 		if (msi_ctlr_node)
 			*node = of_fwnode_handle(msi_ctlr_node);
+	} else {
+		rid = iort_msi_xlate(&pdev->dev, rid, node);
 	}
 
 	return rid;
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index d4ed5622cf2b..2d22268677a9 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -27,12 +27,14 @@ int iort_register_domain_token(int trans_id, phys_addr_t base,
 			       struct fwnode_handle *fw_node);
 void iort_deregister_domain_token(int trans_id);
 struct fwnode_handle *iort_find_domain_token(int trans_id);
-int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id);
 
 #ifdef CONFIG_ACPI_IORT
 u32 iort_msi_map_id(struct device *dev, u32 id);
+u32 iort_msi_xlate(struct device *dev, u32 id, struct fwnode_handle **node);
+int iort_its_translate_pa(struct fwnode_handle *node, phys_addr_t *base);
 struct irq_domain *iort_get_device_domain(struct device *dev, u32 id,
 					  enum irq_domain_bus_token bus_token);
+int iort_pmsi_get_msi_info(struct device *dev, u32 *dev_id, phys_addr_t *pa);
 void acpi_configure_pmsi_domain(struct device *dev);
 void iort_get_rmr_sids(struct fwnode_handle *iommu_fwnode,
 		       struct list_head *head);
@@ -46,9 +48,15 @@ phys_addr_t acpi_iort_dma_get_max_cpu_address(void);
 #else
 static inline u32 iort_msi_map_id(struct device *dev, u32 id)
 { return id; }
+static inline u32 iort_msi_xlate(struct device *dev, u32 id, struct fwnode_handle **node)
+{ return id; }
+static inline int iort_its_translate_pa(struct fwnode_handle *node, phys_addr_t *base)
+{ return -ENODEV; }
 static inline struct irq_domain *iort_get_device_domain(
 	struct device *dev, u32 id, enum irq_domain_bus_token bus_token)
 { return NULL; }
+static inline int iort_pmsi_get_msi_info(struct device *dev, u32 *dev_id, phys_addr_t *pa)
+{ return -ENODEV; }
 static inline void acpi_configure_pmsi_domain(struct device *dev) { }
 static inline
 void iort_get_rmr_sids(struct fwnode_handle *iommu_fwnode, struct list_head *head) { }
diff --git a/include/linux/irqchip/arm-gic-v5.h b/include/linux/irqchip/arm-gic-v5.h
index ff5b1a4931d7..334b6986435c 100644
--- a/include/linux/irqchip/arm-gic-v5.h
+++ b/include/linux/irqchip/arm-gic-v5.h
@@ -392,4 +392,5 @@ int gicv5_alloc_lpi(void);
 void gicv5_free_lpi(u32 lpi);
 
 void __init gicv5_its_of_probe(struct device_node *parent);
+void __init gicv5_its_acpi_probe(void);
 #endif

-- 
2.50.1



From lpieralisi at kernel.org  Thu Dec 18 02:14:33 2025
From: lpieralisi at kernel.org (Lorenzo Pieralisi)
Date: Thu, 18 Dec 2025 11:14:33 +0100
Subject: [PATCH v2 7/7] irqchip/gic-v5: Add ACPI IWB probing
In-Reply-To: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org>
References: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org>
Message-ID: <20251218-gicv5-host-acpi-v2-7-eec76cd1d40b@kernel.org>

To probe an IWB in an ACPI based system it is required:

- to implement the IORT functions handling the IWB IORT node and create
  functions to retrieve IWB firmware information
- to augment the driver to match the DSDT ACPI "ARMH0003" device and
  retrieve the IWB wire and trigger mask from the GSI interrupt descriptor
  in the IWB msi_domain_ops.msi_translate() function

Make the required driver changes to enable IWB probing in ACPI systems.

The GICv5 GSI format requires special handling for IWB routed IRQs.

Add IWB GSI detection to the top level driver gic_v5_get_gsi_domain_id()
function so that the correct IRQ domain for a GSI can be detected by
parsing the GSI and check whether it is an IWB-backed IRQ or not.

Signed-off-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
Cc: Thomas Gleixner <tglx at linutronix.de>
Cc: Hanjun Guo <guohanjun at huawei.com>
Cc: Sudeep Holla <sudeep.holla at arm.com>
Cc: Marc Zyngier <maz at kernel.org>
---
 drivers/acpi/arm64/iort.c          | 95 ++++++++++++++++++++++++++++++++------
 drivers/irqchip/irq-gic-v5-iwb.c   | 42 +++++++++++++----
 drivers/irqchip/irq-gic-v5.c       |  4 ++
 include/linux/acpi_iort.h          |  1 +
 include/linux/irqchip/arm-gic-v5.h |  6 +++
 5 files changed, 123 insertions(+), 25 deletions(-)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 17dbe66da804..4b0b753db738 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -264,39 +264,47 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
 	struct device *dev = context;
 	acpi_status status = AE_NOT_FOUND;
 
-	if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) {
+	if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT ||
+	    node->type == ACPI_IORT_NODE_IWB) {
 		struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
-		struct acpi_device *adev;
 		struct acpi_iort_named_component *ncomp;
-		struct device *nc_dev = dev;
+		struct acpi_iort_iwb *iwb;
+		struct device *cdev = dev;
+		struct acpi_device *adev;
+		const char *device_name;
 
 		/*
 		 * Walk the device tree to find a device with an
 		 * ACPI companion; there is no point in scanning
-		 * IORT for a device matching a named component if
+		 * IORT for a device matching a named component or IWB if
 		 * the device does not have an ACPI companion to
 		 * start with.
 		 */
 		do {
-			adev = ACPI_COMPANION(nc_dev);
+			adev = ACPI_COMPANION(cdev);
 			if (adev)
 				break;
 
-			nc_dev = nc_dev->parent;
-		} while (nc_dev);
+			cdev = cdev->parent;
+		} while (cdev);
 
 		if (!adev)
 			goto out;
 
 		status = acpi_get_name(adev->handle, ACPI_FULL_PATHNAME, &buf);
 		if (ACPI_FAILURE(status)) {
-			dev_warn(nc_dev, "Can't get device full path name\n");
+			dev_warn(cdev, "Can't get device full path name\n");
 			goto out;
 		}
 
-		ncomp = (struct acpi_iort_named_component *)node->node_data;
-		status = !strcmp(ncomp->device_name, buf.pointer) ?
-							AE_OK : AE_NOT_FOUND;
+		if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) {
+			ncomp = (struct acpi_iort_named_component *)node->node_data;
+			device_name = ncomp->device_name;
+		} else {
+			iwb = (struct acpi_iort_iwb *)node->node_data;
+			device_name = iwb->device_name;
+		}
+		status = !strcmp(device_name, buf.pointer) ?  AE_OK : AE_NOT_FOUND;
 		acpi_os_free(buf.pointer);
 	} else if (node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
 		struct acpi_iort_root_complex *pci_rc;
@@ -317,12 +325,28 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
 	return status;
 }
 
+static acpi_status iort_match_iwb_callback(struct acpi_iort_node *node, void *context)
+{
+	acpi_status status = AE_NOT_FOUND;
+	u32 *id = context;
+
+	if (node->type == ACPI_IORT_NODE_IWB) {
+		struct acpi_iort_iwb *iwb;
+
+		iwb = (struct acpi_iort_iwb *)node->node_data;
+		status = iwb->iwb_index == *id ? AE_OK : AE_NOT_FOUND;
+	}
+
+	return status;
+}
+
 static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
 		       u32 *rid_out, bool check_overlap)
 {
 	/* Single mapping does not care for input id */
 	if (map->flags & ACPI_IORT_ID_SINGLE_MAPPING) {
 		if (type == ACPI_IORT_NODE_NAMED_COMPONENT ||
+		    type == ACPI_IORT_NODE_IWB		   ||
 		    type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
 			*rid_out = map->output_base;
 			return 0;
@@ -392,6 +416,7 @@ static struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
 
 	if (map->flags & ACPI_IORT_ID_SINGLE_MAPPING) {
 		if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT ||
+		    node->type == ACPI_IORT_NODE_IWB ||
 		    node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX ||
 		    node->type == ACPI_IORT_NODE_SMMU_V3 ||
 		    node->type == ACPI_IORT_NODE_PMCG) {
@@ -562,9 +587,14 @@ static struct acpi_iort_node *iort_find_dev_node(struct device *dev)
 			return node;
 		/*
 		 * if not, then it should be a platform device defined in
-		 * DSDT/SSDT (with Named Component node in IORT)
+		 * DSDT/SSDT (with Named Component node in IORT) or an
+		 * IWB device in the DSDT/SSDT.
 		 */
-		return iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
+		node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
+				      iort_match_node_callback, dev);
+		if (node)
+			return node;
+		return iort_scan_node(ACPI_IORT_NODE_IWB,
 				      iort_match_node_callback, dev);
 	}
 
@@ -756,6 +786,35 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 id,
 	return irq_find_matching_fwnode(handle, bus_token);
 }
 
+struct fwnode_handle *iort_iwb_handle(u32 iwb_id)
+{
+	struct fwnode_handle *fwnode;
+	struct acpi_iort_node *node;
+	struct acpi_device *device;
+	struct acpi_iort_iwb *iwb;
+	acpi_status status;
+	acpi_handle handle;
+
+	/* find its associated IWB node */
+	node = iort_scan_node(ACPI_IORT_NODE_IWB, iort_match_iwb_callback, &iwb_id);
+	if (!node)
+		return NULL;
+
+	iwb = (struct acpi_iort_iwb *)node->node_data;
+	status = acpi_get_handle(NULL, iwb->device_name, &handle);
+	if (ACPI_FAILURE(status))
+		return NULL;
+
+	device = acpi_get_acpi_dev(handle);
+	if (!device)
+		return NULL;
+
+	fwnode = acpi_fwnode_handle(device);
+	acpi_put_acpi_dev(device);
+
+	return fwnode;
+}
+
 static void iort_set_device_domain(struct device *dev,
 				   struct acpi_iort_node *node)
 {
@@ -816,8 +875,14 @@ static struct irq_domain *iort_get_platform_device_domain(struct device *dev)
 	/* find its associated iort node */
 	node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
 			      iort_match_node_callback, dev);
-	if (!node)
-		return NULL;
+	if (!node) {
+		/* find its associated iort node */
+		node = iort_scan_node(ACPI_IORT_NODE_IWB,
+				      iort_match_node_callback, dev);
+
+		if (!node)
+			return NULL;
+	}
 
 	/* then find its msi parent node */
 	for (i = 0; i < node->mapping_count; i++) {
diff --git a/drivers/irqchip/irq-gic-v5-iwb.c b/drivers/irqchip/irq-gic-v5-iwb.c
index ad9fdc14d1c6..c7d5fd34d053 100644
--- a/drivers/irqchip/irq-gic-v5-iwb.c
+++ b/drivers/irqchip/irq-gic-v5-iwb.c
@@ -4,6 +4,7 @@
  */
 #define pr_fmt(fmt)	"GICv5 IWB: " fmt
 
+#include <linux/acpi.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/msi.h>
@@ -136,18 +137,31 @@ static int gicv5_iwb_irq_domain_translate(struct irq_domain *d, struct irq_fwspe
 					  irq_hw_number_t *hwirq,
 					  unsigned int *type)
 {
-	if (!is_of_node(fwspec->fwnode))
-		return -EINVAL;
+	if (is_of_node(fwspec->fwnode)) {
 
-	if (fwspec->param_count < 2)
-		return -EINVAL;
+		if (fwspec->param_count < 2)
+			return -EINVAL;
 
-	/*
-	 * param[0] is be the wire
-	 * param[1] is the interrupt type
-	 */
-	*hwirq = fwspec->param[0];
-	*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
+		/*
+		 * param[0] is be the wire
+		 * param[1] is the interrupt type
+		 */
+		*hwirq = fwspec->param[0];
+		*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
+	}
+
+	if (is_acpi_device_node(fwspec->fwnode)) {
+
+		if (fwspec->param_count < 2)
+			return -EINVAL;
+
+		/*
+		 * Extract the wire from param[0]
+		 * param[1] is the interrupt type
+		 */
+		*hwirq = FIELD_GET(GICV5_GSI_IWB_WIRE, fwspec->param[0]);
+		*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
+	}
 
 	return 0;
 }
@@ -265,10 +279,18 @@ static const struct of_device_id gicv5_iwb_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, gicv5_iwb_of_match);
 
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id iwb_acpi_match[] = {
+	{ "ARMH0003", 0 },
+	{}
+};
+#endif
+
 static struct platform_driver gicv5_iwb_platform_driver = {
 	.driver = {
 		.name			= "GICv5 IWB",
 		.of_match_table		= gicv5_iwb_of_match,
+		.acpi_match_table	= ACPI_PTR(iwb_acpi_match),
 		.suppress_bind_attrs	= true,
 	},
 	.probe				= gicv5_iwb_device_probe,
diff --git a/drivers/irqchip/irq-gic-v5.c b/drivers/irqchip/irq-gic-v5.c
index 23fd551c4347..da867dd2e77d 100644
--- a/drivers/irqchip/irq-gic-v5.c
+++ b/drivers/irqchip/irq-gic-v5.c
@@ -5,6 +5,7 @@
 
 #define pr_fmt(fmt)	"GICv5: " fmt
 
+#include <linux/acpi_iort.h>
 #include <linux/cpuhotplug.h>
 #include <linux/idr.h>
 #include <linux/irqdomain.h>
@@ -1187,6 +1188,9 @@ static struct fwnode_handle *gsi_domain_handle;
 
 static struct fwnode_handle *gic_v5_get_gsi_domain_id(u32 gsi)
 {
+	if (FIELD_GET(GICV5_GSI_IC_TYPE, gsi) == GICV5_GSI_IWB_TYPE)
+		return iort_iwb_handle(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi));
+
 	return gsi_domain_handle;
 }
 
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index 2d22268677a9..17bb3374f4ca 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -27,6 +27,7 @@ int iort_register_domain_token(int trans_id, phys_addr_t base,
 			       struct fwnode_handle *fw_node);
 void iort_deregister_domain_token(int trans_id);
 struct fwnode_handle *iort_find_domain_token(int trans_id);
+struct fwnode_handle *iort_iwb_handle(u32 iwb_id);
 
 #ifdef CONFIG_ACPI_IORT
 u32 iort_msi_map_id(struct device *dev, u32 id);
diff --git a/include/linux/irqchip/arm-gic-v5.h b/include/linux/irqchip/arm-gic-v5.h
index 334b6986435c..3da1ad80fc9d 100644
--- a/include/linux/irqchip/arm-gic-v5.h
+++ b/include/linux/irqchip/arm-gic-v5.h
@@ -265,6 +265,12 @@
 
 #define GICV5_IWB_WENABLE_STATUSR_IDLE		BIT(0)
 
+#define GICV5_GSI_IC_TYPE			GENMASK(31, 29)
+#define GICV5_GSI_IWB_TYPE			0x7
+
+#define GICV5_GSI_IWB_FRAME_ID			GENMASK(28, 16)
+#define GICV5_GSI_IWB_WIRE			GENMASK(15, 0)
+
 /*
  * Global Data structures and functions
  */

-- 
2.50.1



From thomas.richard at bootlin.com  Thu Dec 18 02:17:06 2025
From: thomas.richard at bootlin.com (Thomas Richard)
Date: Thu, 18 Dec 2025 11:17:06 +0100
Subject: [PATCH v3 2/4] firmware: ti_sci: handle IRQ restore in
 BOARDCFG_MANAGED mode during resume
In-Reply-To: <20251217052938.fpgclxhmyydvw7ce@lcpd911>
References: <20251205-ti-sci-jacinto-s2r-restore-irq-v3-0-d06963974ad4@bootlin.com>
 <20251205-ti-sci-jacinto-s2r-restore-irq-v3-2-d06963974ad4@bootlin.com>
 <bcc7a3da-3cb5-451b-98eb-4f7896c615a1@ti.com>
 <20251217052938.fpgclxhmyydvw7ce@lcpd911>
Message-ID: <9ed481c4-0a47-4616-97f6-89f58e423eed@bootlin.com>

On 12/17/25 6:29 AM, Dhruva Gole wrote:
> On Dec 16, 2025 at 08:17:24 +0530, Kumar, Udit wrote:
>>
>> On 12/5/2025 7:58 PM, Thomas Richard (TI.com) wrote:
>>> In BOARDCFG_MANAGED mode, the firmware cannot restore IRQs during
>>> resume. This responsibility is delegated to the ti_sci driver,
>>> which maintains an internal list of all requested IRQs. This list
>>> is updated on each set/free operation, and all IRQs are restored
>>> during the resume_noirq() phase.
>>>
>>> Signed-off-by: Thomas Richard (TI.com) <thomas.richard at bootlin.com>

[...]

>>> +
>>> +	hash_for_each_possible_safe(info->irqs, this_irq, tmp_node, node,
>>> +				    ti_sci_irq_hash(&irq_desc)) {
>>> +		if (ti_sci_irq_equal(&irq_desc, &this_irq->desc)) {
>>> +			hlist_del(&this_irq->node);
>>> +			kfree(this_irq);
>>> +			return 0;
>>
>>
>> IMO,? you can restrict saving of irq and list management to fw having
>>
>> BOARDCFG_MANAGED capability.
>>
>> Dhurva ?
> 
> Yes I agree with Udit, we should gate hash operations by firmware capability.
> Everywhere else you'll need to make it conditional accordingly.

ack

> 
> Also, how much is the IRQ count usually? If IRQ count is typically small (< 50),
> then won't a simple linked list be more efficient than a hash table? The
> code becomes a bit more readable too that way IMO.
> Take a call based on if there's really that many IRQs that LL's become
> less practical.
> 

I tested a TI kernel on J721S2 and I got 60 entries. I guess we can
expect this number to grow with the next SOCs. But maybe the test does
not reflect the usual cases.

Best Regards,
Thomas




From krzk at kernel.org  Thu Dec 18 02:17:57 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 18 Dec 2025 11:17:57 +0100
Subject: [PATCH v8 5/8] dt-bindings: arm: add an interrupt property for
 Coresight CTCU
In-Reply-To: <dfa43a63-ca14-4dd7-a7ab-acd95748a8b9@oss.qualcomm.com>
References: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
 <20251211-enable-byte-cntr-for-ctcu-v8-5-3e12ff313191@oss.qualcomm.com>
 <20251211133723.GA859302-robh@kernel.org>
 <dfa43a63-ca14-4dd7-a7ab-acd95748a8b9@oss.qualcomm.com>
Message-ID: <a9537dc9-c767-4909-8b1c-6e939ce4f3fc@kernel.org>

On 12/12/2025 02:12, Jie Gan wrote:
> 
> 
> On 12/11/2025 9:37 PM, Rob Herring wrote:
>> On Thu, Dec 11, 2025 at 02:10:44PM +0800, Jie Gan wrote:
>>> Add an interrupt property to CTCU device. The interrupt will be triggered
>>> when the data size in the ETR buffer exceeds the threshold of the
>>> BYTECNTRVAL register. Programming a threshold in the BYTECNTRVAL register
>>> of CTCU device will enable the interrupt.
>>>
>>> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
>>> Reviewed-by: Mike Leach <mike.leach at linaro.org>
>>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>>> ---
>>>   .../devicetree/bindings/arm/qcom,coresight-ctcu.yaml    | 17 +++++++++++++++++
>>>   1 file changed, 17 insertions(+)
>>>
>>> diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
>>> index c969c16c21ef..90f88cc6cd3e 100644
>>> --- a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
>>> +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
>>> @@ -39,6 +39,16 @@ properties:
>>>       items:
>>>         - const: apb
>>>   
>>> +  interrupts:
>>> +    items:
>>> +      - description: Byte cntr interrupt for the first etr device
>>> +      - description: Byte cntr interrupt for the second etr device
>>> +
>>> +  interrupt-names:
>>> +    items:
>>> +      - const: etrirq0
>>> +      - const: etrirq1
>>
>> Names are kind of pointless when it is just foo<index>.
> 
> Hi Rob,
> 
> I was naming them as etr0/etr1. Are these names acceptable?

Obviously irq is redundant, but how does etr0 solves the problem of
calling it foo0?

I don't think you really read Rob's comment.

> The interrupts are assigned exclusively to a specific ETR device.
> 
> But Suzuki is concerned that this might cause confusion because the ETR 
> device is named randomly in the driver. Suzuki suggested using ?port-0? 
> and ?port-1? and would also like to hear your feedback on these names.

There is no confusion here. Writing bindings luckily clarifies this what
the indices in the array mean.

> 
> Usually, the probe sequence follows the order of the addresses. In our 
> specification, ?ETR0? is always probed before ?ETR1? because its address 
> is lower.

How is this even relevant? You are answering to something completely
different, so I don't think you really tried to understand review.



Best regards,
Krzysztof


From thomas.richard at bootlin.com  Thu Dec 18 02:19:39 2025
From: thomas.richard at bootlin.com (Thomas Richard)
Date: Thu, 18 Dec 2025 11:19:39 +0100
Subject: [PATCH v3 4/4] firmware: ti_sci: restore clock context during
 resume in BOARDCFG_MANAGED mode
In-Reply-To: <20251217060727.idneboxj7kwslie2@lcpd911>
References: <20251205-ti-sci-jacinto-s2r-restore-irq-v3-0-d06963974ad4@bootlin.com>
 <20251205-ti-sci-jacinto-s2r-restore-irq-v3-4-d06963974ad4@bootlin.com>
 <20251217060727.idneboxj7kwslie2@lcpd911>
Message-ID: <e8c4d832-3146-4fad-a0f6-0e2df77e83c0@bootlin.com>

On 12/17/25 7:07 AM, Dhruva Gole wrote:
> On Dec 05, 2025 at 15:28:26 +0100, Thomas Richard (TI.com) wrote:
>> In BOARDCFG_MANAGED mode, the firmware cannot restore the clock rates and
>> the clock parents. This responsibility is therefore delegated to the ti_sci
>> driver, which uses clk_restore_context() to trigger the context_restore()
>> operation for all registered clocks, including those managed by the sci-clk
>> driver. The sci-clk driver implements the context_restore() operation to
>> ensure rates and clock parents are correctly restored.
>>
>> Signed-off-by: Thomas Richard (TI.com) <thomas.richard at bootlin.com>
>> ---
>>  drivers/firmware/ti_sci.c | 3 +++
>>  1 file changed, 3 insertions(+)
>>
>> diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
>> index 8d94745376e2a..6ef687e481c49 100644
>> --- a/drivers/firmware/ti_sci.c
>> +++ b/drivers/firmware/ti_sci.c
>> @@ -9,6 +9,7 @@
>>  #define pr_fmt(fmt) "%s: " fmt, __func__
>>  
>>  #include <linux/bitmap.h>
>> +#include <linux/clk.h>
>>  #include <linux/cpu.h>
>>  #include <linux/debugfs.h>
>>  #include <linux/export.h>
>> @@ -3980,6 +3981,8 @@ static int ti_sci_resume_noirq(struct device *dev)
>>  				if (ret)
>>  					return ret;
>>  			}
>> +
>> +			clk_restore_context();
> 
> Here as well, make it conditional to only BOARDCFG_MANAGED. Other
> platforms/ firmwares have lived without this for a while now, and it's
> evident that we don't always need this.

It is already conditionally done to only BOARDCFG_MANAGED.

> 
> Thinking more about this, I think we're over using this BOARDCFG_MANAGED
> mode a bit much. We should really just come up with new FW caps for
> this, one for clk_restore , other for the previous IRQ restore patch.
> 
> That's the only way I can see this scaling. In future if we ever need
> more devices that may actually be BOARDCFG_MANAGED, but don't need the
> IRQ or clock restoration then the current approach won't work.
> 
> MODE should only be passed in the prepare_sleep, where it makes sense.
> Using it for anything else just does not feel clean to me.

Fair point. Restoring clocks and IRQs is more related to the fact that
DM-Firmware on Jacinto platforms does not have suspend-resume support
than the BOARDCFG_MANAGED mode. I guess we could imagine in the future
having suspend-resume support in Jacinto DM-Firmware, so no need to
restore clocks and IRQs anymore, but the mode remains BOARDCFG_MANAGED.

Best Regards,
Thomas



From ahmed.tiba at arm.com  Thu Dec 18 02:22:36 2025
From: ahmed.tiba at arm.com (Ahmed Tiba)
Date: Thu, 18 Dec 2025 10:22:36 +0000
Subject: [PATCH 10/12] dt-bindings: ras: document estatus provider
In-Reply-To: <2a2baef6-c294-4c31-bec2-10fbaa3f7941@kernel.org>
References: <2a2baef6-c294-4c31-bec2-10fbaa3f7941@kernel.org>
Message-ID: <20251218102238.2235329-1-ahmed.tiba@arm.com>

On 18/12/2025 07:48, Krzysztof Kozlowski wrote:
> Please follow standard mailing list reply style. I am not reading the
> rest and I still expect to implement my feedback fully.

Apologies for the poor reply formatting.

I will resend my reply with proper inline formatting and full
context preserved, and follow up with a new revision implementing
your feedback.

Thanks.
Ahmed


From vulab at iscas.ac.cn  Thu Dec 18 02:23:14 2025
From: vulab at iscas.ac.cn (Haotian Zhang)
Date: Thu, 18 Dec 2025 18:23:14 +0800
Subject: [PATCH v2] PCI: xilinx: Fix INTx IRQ domain leak when MSI allocation fails
In-Reply-To: <20251119033301.518-1-vulab@iscas.ac.cn>
References: <20251119033301.518-1-vulab@iscas.ac.cn>
Message-ID: <20251218102314.1474-1-vulab@iscas.ac.cn>

In xilinx_pcie_init_irq_domain(), if xilinx_allocate_msi_domains()
fails after pcie->leg_domain has been successfully created via
irq_domain_create_linear(), the function returns directly without
cleaning up the allocated IRQ domain, resulting in a resource leak.

Add irq_domain_remove() call in the error path to properly release the
IRQ domain before returning the error.

Fixes: 313b64c3ae52 ("PCI: xilinx: Convert to MSI domains")
Suggested-by: Manivannan Sadhasivam <mani at kernel.org>
Signed-off-by: Haotian Zhang <vulab at iscas.ac.cn>
---
Changes in v2:
  - Correct the Fixes tag to point to the commit that introduced the
    legacy IRQ domain leak on MSI allocation failure.
---
 drivers/pci/controller/pcie-xilinx.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/pcie-xilinx.c b/drivers/pci/controller/pcie-xilinx.c
index 937ea6ae1ac4..e8cf320f3764 100644
--- a/drivers/pci/controller/pcie-xilinx.c
+++ b/drivers/pci/controller/pcie-xilinx.c
@@ -480,8 +480,10 @@ static int xilinx_pcie_init_irq_domain(struct xilinx_pcie *pcie)
 		phys_addr_t pa = ALIGN_DOWN(virt_to_phys(pcie), SZ_4K);
 
 		ret = xilinx_allocate_msi_domains(pcie);
-		if (ret)
+		if (ret) {
+			irq_domain_remove(pcie->leg_domain);
 			return ret;
+		}
 
 		pcie_write(pcie, upper_32_bits(pa), XILINX_PCIE_REG_MSIBASE1);
 		pcie_write(pcie, lower_32_bits(pa), XILINX_PCIE_REG_MSIBASE2);
-- 
2.50.1.windows.1



From arnaud.pouliquen at foss.st.com  Thu Dec 18 02:29:46 2025
From: arnaud.pouliquen at foss.st.com (Arnaud POULIQUEN)
Date: Thu, 18 Dec 2025 11:29:46 +0100
Subject: [PATCH v6 1/5] dt-bindings: remoteproc: imx_rproc: Add "rpmsg"
 subnode support
In-Reply-To: <20251212194341.966387-2-shenwei.wang@nxp.com>
References: <20251212194341.966387-1-shenwei.wang@nxp.com>
 <20251212194341.966387-2-shenwei.wang@nxp.com>
Message-ID: <f53639e8-feef-438a-9b1a-c349fc17d0c6@foss.st.com>

Hello Shenwei,


On 12/12/25 20:43, Shenwei Wang wrote:
> Remote processors may announce multiple devices (e.g., I2C, GPIO) over
> an RPMSG channel. These devices may require corresponding device tree
> nodes, especially when acting as providers, to supply phandles for their
> consumers.
> 
> Define an RPMSG node to work as a container for a group of RPMSG channels
> under the imx_rproc node.
> 
> Each subnode within "rpmsg" represents an individual RPMSG channel. The
> name of each subnode corresponds to the channel name as defined by the
> remote processor.
> 
> All remote devices associated with a given channel are defined as child
> nodes under the corresponding channel node.
> 
> Signed-off-by: Shenwei Wang <shenwei.wang at nxp.com>
> ---
>   .../devicetree/bindings/gpio/gpio-rpmsg.yaml  | 49 +++++++++++++++++
>   .../bindings/remoteproc/fsl,imx-rproc.yaml    | 54 +++++++++++++++++++
>   2 files changed, 103 insertions(+)
>   create mode 100644 Documentation/devicetree/bindings/gpio/gpio-rpmsg.yaml
> 
> diff --git a/Documentation/devicetree/bindings/gpio/gpio-rpmsg.yaml b/Documentation/devicetree/bindings/gpio/gpio-rpmsg.yaml
> new file mode 100644
> index 000000000000..b3e1a5dbf731
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/gpio/gpio-rpmsg.yaml
> @@ -0,0 +1,49 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/gpio/gpio-rpmsg.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Generic GPIO driver over RPMSG
> +
> +maintainers:
> +  - Shenwei Wang <shenwei.wang at nxp.com>
> +
> +description:
> +  On an AMP platform, some GPIO controllers are exposed by the remote processor
> +  through the RPMSG bus. The RPMSG GPIO transport protocol defines the packet
> +  structure and communication flow between Linux and the remote firmware. Those
> +  controllers are managed via this transport protocol.
> +
> +properties:
> +  compatible:
> +    oneOf:
> +      - items:
> +          - enum:
> +              - fsl,rpmsg-gpio
> +          - const: rpmsg-gpio
> +      - const: rpmsg-gpio
> +
> +  reg:
> +    maxItems: 1
> +
> +  "#gpio-cells":
> +    const: 2
> +
> +  gpio-controller: true
> +
> +  interrupt-controller: true
> +
> +  "#interrupt-cells":
> +    const: 2
> +
> +required:
> +  - compatible
> +  - reg
> +  - "#gpio-cells"
> +  - "#interrupt-cells"
> +
> +allOf:
> +  - $ref: /schemas/gpio/gpio.yaml#
> +
> +unevaluatedProperties: false
> diff --git a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
> index 57d75acb0b5e..fd8e5a61a459 100644
> --- a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
> +++ b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
> @@ -84,6 +84,33 @@ properties:
>         This property is to specify the resource id of the remote processor in SoC
>         which supports SCFW
>   
> +  rpmsg:
> +    type: object
> +    additionalProperties: false
> +    description:
> +      Present a group of RPMSG channel devices.
> +
> +    properties:
> +      rpmsg-io-channel:
> +        type: object
> +        additionalProperties: false
> +        properties:
> +          '#address-cells':
> +            const: 1
> +
> +          '#size-cells':
> +            const: 0
> +
> +        patternProperties:
> +          "gpio@[0-9a-f]+$":
> +            type: object
> +            $ref: /schemas/gpio/gpio-rpmsg.yaml#
> +            unevaluatedProperties: false
> +
> +        required:
> +          - '#address-cells'
> +          - '#size-cells'
> +
>   required:
>     - compatible
>   
> @@ -146,5 +173,32 @@ examples:
>                   &mu 3 1>;
>         memory-region = <&vdev0buffer>, <&vdev0vring0>, <&vdev0vring1>, <&rsc_table>;
>         syscon = <&src>;
> +
> +      rpmsg {
> +        rpmsg-io-channel {
> +          #address-cells = <1>;
> +          #size-cells = <0>;
> +
> +          gpio at 0 {
> +            compatible = "rpmsg-gpio";
> +            reg = <0>;
> +            gpio-controller;
> +            #gpio-cells = <2>;
> +            #interrupt-cells = <2>;
> +            interrupt-controller;
> +            interrupt-parent = <&rpmsg_gpioa>;


"rpmsg_gpioa" seems not defined, or I missed something?

Regards,
Arnaud

> +          };
> +
> +          gpio at 1 {
> +            compatible = "rpmsg-gpio";
> +            reg = <1>;
> +            gpio-controller;
> +            #gpio-cells = <2>;
> +            #interrupt-cells = <2>;
> +            interrupt-controller;
> +            interrupt-parent = <&rpmsg_gpiob>;
> +          };
> +        };
> +      };
>       };
>   ...



From ahmed.tiba at arm.com  Thu Dec 18 02:31:38 2025
From: ahmed.tiba at arm.com (Ahmed Tiba)
Date: Thu, 18 Dec 2025 10:31:38 +0000
Subject: [PATCH 10/12] dt-bindings: ras: document estatus provider
In-Reply-To: <2a2baef6-c294-4c31-bec2-10fbaa3f7941@kernel.org>
References: <2a2baef6-c294-4c31-bec2-10fbaa3f7941@kernel.org>
Message-ID: <20251218103139.2238844-1-ahmed.tiba@arm.com>

On 17/12/2025 12:41, Krzysztof Kozlowski wrote:
>> Add a binding for firmware-first CPER providers described via
>> DeviceTree. It covers the shared status block, optional acknowledgment
>> registers, interrupt versus polling modes and the SEA notification
>> flag so non-ACPI platforms can describe their error sources.
>>
>> Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>
>> ---
>>  .../devicetree/bindings/ras/arm,ras-ffh.yaml  | 95 +++++++++++++++++++
>>  MAINTAINERS                                   |  1 +
>>  2 files changed, 96 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/ras/arm,ras-ffh.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/ras/arm,ras-ffh.yaml b/Documentation/devicetree/>bindings/ras/arm,ras-ffh.yaml
>> new file mode 100644
>> index 000000000000..0d2acbf8e8a8
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/ras/arm,ras-ffh.yaml
>
> What is ras? There is no such directory so some description would be
> useful. Usually you do not get your own directory per binding.

For the next revision I will move the schema under
`Documentation/devicetree/bindings/firmware/` and expand the description to
spell out that Arm Reliability, Availability and Serviceability (RAS) firmware
exposes this FFH CPER provider.

>> @@ -0,0 +1,95 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/ras/arm,ras-ffh.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Arm Firmware-First Handler (FFH) CPER provider
>> +
>> +maintainers:
>> +  - Ahmed Tiba <ahmed.tiba at arm.com>
>> +
>> +description: |
>> +  Some Arm platforms describe a firmware-first error handler that exposes a
>> +  Common Platform Error Record (CPER) buffer directly via DeviceTree. The OS
>> +  maps the buffer to consume the error records, and firmware signals that a new
>> +  record is ready either by asserting an interrupt or by relying on a periodic
>> +  poll. This binding describes the buffer and the associated notification
>
> Do not describe what the binding does. Describe the hardware or firmware.

I'll reword the description so it focuses on the firmware-managed CPER buffer,
optional doorbell register and optional interrupt rather than describing how
the binding is consumed.

>> +  signal. If firmware delivers the error via Synchronous External Abort (SEA),
>> +  the optional sea-notify flag marks the source accordingly.
>> +
>> +properties:
>> +  compatible:
>> +    const: arm,ras-ffh
>
> Again ras - what's that? Your patch or binding must explain that.

That updated description will explicitly expand the Arm RAS acronym so the
compatible string is self-explanatory.

>> +
>> +  reg:
>> +    minItems: 1
>
> Why is this flexible?

I'll keep `reg` describing the CPER status buffer, cap it at two entries, and
document the second entry as the optional doorbell register that some firmware
requires before reusing the buffer.

>> +    items:
>> +      - description: CPER status block exposed by firmware
>> +      - description:
>> +          Optional 32- or 64-bit acknowledgment register. Firmware watches this
>> +          register and expects bit 0 to be written to 1 once the OS consumes the
>> +          status buffer so it can reuse the record.
>> +
>> +  reg-names:
>> +    items:
>> +      - const: status
>> +      - const: ack
>
> Does not match reg.

`reg-names` will remain optional, but when provided the first entry will be
restricted to `"status"` and the second (if present) to `"ack"`, matching the
single optional region permitted in `reg`.

>> +
>> +  interrupts:
>> +    maxItems: 1
>> +    description:
>> +      Optional interrupt used to signal that a new status record is ready. If
>> +      omitted, the OS relies on the polling interval property.
>
> What OS is doing should not really matter. Either you have the interrupt
> or not.

I'll trim the wording so it just states that firmware may assert an interrupt
when a new record is ready.

>> +
>> +  poll-interval:
>> +    $ref: /schemas/types.yaml#/definitions/uint32
>> +    minimum: 1
>> +    description:
>> +      Optional polling interval, in milliseconds, for platforms that cannot
>> +      route an interrupt.
>
> That's OS policy, not suitable for binding.

I'll drop `poll-interval` from the binding so the driver can fall back to its
fixed interval when no interrupt is wired.

>> +
>> +  arm,sea-notify:
>> +    type: boolean
>> +    description:
>> +      Set if the platform delivers these errors as Synchronous External Aborts.
>
> This is implied by the compatible, no?

I'll drop `arm,sea-notify` so the compatible alone defines the behaviour.

>> +
>> +required:
>> +  - compatible
>> +  - reg
>> +
>> +allOf:
>> +  - if:
>> +      properties:
>> +        poll-interval: false
>> +    then:
>> +      required:
>> +        - interrupts
>> +  - if:
>> +      properties:
>> +        interrupts: false
>> +    then:
>> +      required:
>> +        - poll-interval
>> +  - if:
>> +      properties:
>> +        reg:
>> +          minItems: 2
>> +    then:
>> +      required:
>> +        - reg-names
>
>Drop all this.

I'll drop this block entirely.

>> +
>> +unevaluatedProperties: false
>
> I do not see any schema referenced.

I'll switch to `additionalProperties: false` so we rely solely on the schema
referenced by `$schema` while still rejecting unknown properties.

>> +
>> +examples:
>> +  - |
>> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
>> +
>> +    ras-ffh at fe800000 {
>
> Node names should be generic. See also an explanation and list of
> examples (not exhaustive) in DT specification:
> https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.> html#generic-names-recommendation
> If you cannot find a name matching your device, please check in kernel
> sources for similar cases or you can grow the spec (via pull request to
> DT spec repo).

I'll rename the example node to the generic `error-handler at fe800000` so it
describes the shared error-status block instead of the driver name.

>> +        compatible = "arm,ras-ffh";
>> +        reg = <0xfe800000 0x1000>,
>> +              <0xfe810000 0x4>;
>> +        reg-names = "status", "ack";
>> +        interrupts = <0 32 IRQ_TYPE_LEVEL_HIGH>;
>
> Use proper defines.

I'll also switch the example interrupt listing to `GIC_SPI` and `IRQ_TYPE_*`
macros.



Best regards,
Ahmed


From suzuki.poulose at arm.com  Thu Dec 18 02:35:21 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Thu, 18 Dec 2025 10:35:21 +0000
Subject: [PATCH v1] dt-binding: Update oss email address for Coresight documents
In-Reply-To: <20250902042143.1010-1-jie.gan@oss.qualcomm.com>
References: <20250902042143.1010-1-jie.gan@oss.qualcomm.com>
Message-ID: <176605409291.630972.15776682739253158062.b4-ty@arm.com>


On Tue, 02 Sep 2025 12:21:43 +0800, Jie Gan wrote:
> Update the OSS email addresses across all Coresight documents, as the
> previous addresses have been deprecated.
> 
> 

Applied, thanks!

[1/1] dt-binding: Update oss email address for Coresight documents
      https://git.kernel.org/coresight/c/7009646d937f

Best regards,
-- 
Suzuki K Poulose <suzuki.poulose at arm.com>


From jonathan.cameron at huawei.com  Thu Dec 18 02:35:46 2025
From: jonathan.cameron at huawei.com (Jonathan Cameron)
Date: Thu, 18 Dec 2025 10:35:46 +0000
Subject: [RFC PATCH 01/38] arm64: mpam: Context switch the MPAM
 registers
In-Reply-To: <20251205215901.17772-2-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
	<20251205215901.17772-2-james.morse@arm.com>
Message-ID: <20251218103546.000070fd@huawei.com>

On Fri, 5 Dec 2025 21:58:24 +0000
James Morse <james.morse at arm.com> wrote:

> MPAM allows traffic in the SoC to be labeled by the OS, these labels
> are used to apply policy in caches and bandwidth regulators, and to
> monitor traffic in the SoC. The label is made up of a PARTID and PMG
> value. The x86 equivalent calls these CLOSID and RMID, but they don't
> map precisely.
> 
> MPAM has two CPU system registers that is used to hold the PARTID and PMG
> values that traffic generated at each exception level will use. These can be
> set per-task by the resctrl file system. (resctrl is the defacto interface
> for controlling this stuff).
> 
> Add a helper to switch this.
> 
> struct task_struct's separate CLOSID and RMID fields are insufficient
> to implement resctrl using MPAM, as resctrl can change the PARTID (CLOSID)
> and PMG (sort of like the RMID) separately. On x86, the rmid is an
> independent number, so a race that writes a mismatched  closid and rmid
> into hardware is benign. On arm64, the pmg bits extend the partid.
> (i.e. partid-5 has a pmg-0 that is not the same as partid-6's pmg-0).
> In this case, mismatching the values will 'dirty' a pmg value that
> resctrl believes is clean, and is not tracking with its 'limbo' code.
> 
> To avoid this, the partid and pmg are always read and written as a pair.
> Instead of making struct task_struct's closid and rmid fields an
> endian-unsafe union, add the value to struct thread_info and always use
> READ_ONCE()/WRITE_ONCE() when accessing this field.
> 
> Resctrl allows a per-cpu 'default' value to be set, this overrides the
> values when scheduling a task in the default control-group, which has
> PARTID 0. The way 'code data prioritisation' gets emulated means the
> register value for the default group needs to be a variable.
> 
> The current system register value is kept in a per-cpu variable to
> avoid writing to the system register if the value isn't going to change.
> Writes to this register may reset the hardware state for regulating
> bandwidth.
> 
> Finally, there is no reason to context switch these registers unless
> there is a driver changing the values in struct task_struct. Hide
> the whole thing behind a static key. This also allows the driver to
> disable MPAM in response to errors reported by hardware. Move the
> existing static key to belong to the arch code, as in the future
> the MPAM driver may become a loadable module.
> 
> All this should depend on whether there is an MPAM driver, hide
> it behind CONFIG_MPAM.
> 
> CC: Amit Singh Tomar <amitsinght at marvell.com>
> Signed-off-by: James Morse <james.morse at arm.com>

> diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/mpam.h
> new file mode 100644
> index 000000000000..86a55176f884
> --- /dev/null
> +++ b/arch/arm64/include/asm/mpam.h
> @@ -0,0 +1,74 @@
...

> +/*
> + * The resctrl filesystem writes to the partid/pmg values for threads and CPUs,
> + * which may race with reads in __mpam_sched_in(). Ensure only one of the old
> + * or new values are used. Particular care should be taken with the pmg field
> + * as __mpam_sched_in() may read a partid and pmg that don't match, causing
> + * this value to be stored with cache allocations, despite being considered
> + * 'free' by resctrl.
> + *
> + * A value in struct thread_info is used instead of struct task_struct as the
> + * cpu's u64 register format is used, but struct task_struct has two u32'.

This comment probably wants to provide a little more info if it is to be useful,

Is it a reference to the closid and rmid fields under CONFIG_X86_CPU_RESCTRL?
I'm not immediately understanding why that matters given you could slap
a union on it without (I think) resulting in anything else moving.

Now having it in thread_info moves it into arch header territory so
might make sense for that reason.

> + */
> +static inline u64 mpam_get_regval(struct task_struct *tsk)
> +{
> +#ifdef CONFIG_ARM64_MPAM
> +	return READ_ONCE(task_thread_info(tsk)->mpam_partid_pmg);
> +#else
> +	return 0;
> +#endif
> +}



From jonathan.cameron at huawei.com  Thu Dec 18 02:38:45 2025
From: jonathan.cameron at huawei.com (Jonathan Cameron)
Date: Thu, 18 Dec 2025 10:38:45 +0000
Subject: [RFC PATCH 03/38] arm64: mpam: Advertise the CPUs MPAM limits
 to the driver
In-Reply-To: <20251205215901.17772-4-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
	<20251205215901.17772-4-james.morse@arm.com>
Message-ID: <20251218103845.000053b3@huawei.com>

On Fri, 5 Dec 2025 21:58:26 +0000
James Morse <james.morse at arm.com> wrote:

> Requestors need to populate the MPAM fields for any traffic they send
> on the interconnect. For the CPUs these values are taken from the
> corresponding MPAMy_ELx register. Each requestor may have a limit on
> the largest PARTID or PMG value that can be used. The MPAM driver has
> to determine the system-wide minimum supported PARTID and PMG values.
> 
> To do this, the driver needs to be told what each requestor's
> limit is.

Trivial but this commit message line wrap isn't very consistent.

> 
> CPUs are special, but this infrastructure is also needed for the
> SMMU and GIC ITS. Call the helper to tell the MPAM driver what the
> CPUs can do.
> 
> The return value can be ignored by the arch code as it runs well
> before the MPAM driver starts probing.
> 
> Signed-off-by: James Morse <james.morse at arm.com>




From leo.yan at arm.com  Thu Dec 18 02:40:27 2025
From: leo.yan at arm.com (Leo Yan)
Date: Thu, 18 Dec 2025 10:40:27 +0000
Subject: [PATCH v2 00/12] coresight: Add CPU cluster
 funnel/replicator/tmc support
In-Reply-To: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
References: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
Message-ID: <20251218104027.GA1790402@e132581.arm.com>

Hi,

On Thu, Dec 18, 2025 at 12:09:40AM -0800, Coresight ML wrote:

[...]

> - Utilizing `smp_call_function_single()` to ensure register accesses
>   (initialization, enablement, sysfs reads) are always executed on a
>   powered CPU within the target cluster.

This is concerned as Mike suggested earlier.

Let me convert to a common question: how does the Linux kernel manage
a power domain shared by multiple hardware modules?

A general solution is to bind a power domain (let's say PD1) to both
module A (MOD_A) and module B (MOD_B).  Each time before accessing MOD_A
or MOD_B, PD1 must be powered on first via the pm_runtime APIs, with
its refcount increased accordingly.

My understanding is the problem in your case is that the driver fails to
create a relationship between the funnel/replicator modules and the
cluster power domain.  Instead, you are trying to use the CPUs in the
same cluster as a delegate for power operations - when you want to
access MOD_B, your wake up MOD_A which sharing the same power domain,
only to turn on the PD_A in order to access MOD_B.

Have you discussed with the firmware and hardware engineers whether it
is feasible to provide explicit power and clock control interfaces for
the funnel and replicator modules?  I can imagine the cluster power
domain's design might differ from other device power domains, but
should not the hardware provide a sane design that allows software to
control power for the access logic within it?

General speaking, using smp_call_function_single() makes sense if only
when accessing logics within the CPU boundary.

P.s., currently you can use "taskset" as a temporary solution without
any code change, something like:

  taskset -c 0 echo 1 > /sys/bus/coresight/devices/etm0/enable_source

Thanks,
Leo


From richard.genoud at bootlin.com  Thu Dec 18 02:41:23 2025
From: richard.genoud at bootlin.com (Richard GENOUD)
Date: Thu, 18 Dec 2025 11:41:23 +0100
Subject: [PATCH v2 1/4] dt-bindings: pwm: allwinner: add h616 pwm
 compatible
In-Reply-To: <52ac76fc-4362-4b5a-ae28-29b874f78399@kernel.org>
References: <20251217082504.80226-1-richard.genoud@bootlin.com>
 <20251217082504.80226-2-richard.genoud@bootlin.com>
 <52ac76fc-4362-4b5a-ae28-29b874f78399@kernel.org>
Message-ID: <2a0f82e9-0a8b-45ec-9d8f-d4842ce120ad@bootlin.com>

Le 18/12/2025 ? 11:15, Krzysztof Kozlowski a ?crit?:
> On 17/12/2025 09:25, Richard Genoud wrote:
>> Allwinner H616 PWM block is quite different from the A10 or H6, but at
>> the end, it uses the same clocks as the H6; so the sun4i pwm binding can
>> be used.
>> It has 6 channels than can generate PWM waveforms or clocks if bypass is
>> enabled.
>>
>> Suggested-by: Krzysztof Kozlowski <krzk at kernel.org>
> 
> Hm? Where did I suggest anything about adding clock cells or documenting
> this allwinner device?
Hum, indeed.
The suggestion, as I understood it, was to re-use the sun4i PWM binding, 
which is why this patch exists now. But I agree, the suggestion wasn't 
on the content itself.
Sorry if it's misleading.

> 
> 
> Best regards,
> Krzysztof

Regards,
Richard


From jonathan.cameron at huawei.com  Thu Dec 18 02:44:33 2025
From: jonathan.cameron at huawei.com (Jonathan Cameron)
Date: Thu, 18 Dec 2025 10:44:33 +0000
Subject: [RFC PATCH 05/38] arm64: mpam: Add helpers to change a task or
 cpu's MPAM PARTID/PMG values
In-Reply-To: <20251205215901.17772-6-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
	<20251205215901.17772-6-james.morse@arm.com>
Message-ID: <20251218104433.00002196@huawei.com>

On Fri, 5 Dec 2025 21:58:28 +0000
James Morse <james.morse at arm.com> wrote:

> Care must be taken when modifying the PARTID and PMG of a task in any
> per-task structure as writing these values may race with the task being
> scheduled in, and reading the modified values.
> 
> Add helpers to set the task properties, and the CPU default value.
> These use WRITE_ONCE() that pairs with the READ_ONCE() in mpam_get_regval()
> to avoid causing torn values.
> 
> CC: Dave Martin <Dave.Martin at arm.com>
> CC: Ben Horgan <ben.horgan at arm.com>
> Signed-off-by: James Morse <james.morse at arm.com>
> ---
>  arch/arm64/include/asm/mpam.h | 30 ++++++++++++++++++++++++++++++
>  1 file changed, 30 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/mpam.h
> index 86a55176f884..2960ffaf6574 100644
> --- a/arch/arm64/include/asm/mpam.h
> +++ b/arch/arm64/include/asm/mpam.h
> @@ -5,6 +5,7 @@
>  #define __ASM__MPAM_H
>  
>  #include <linux/bitops.h>
> +#include <linux/bitfield.h>
>  #include <linux/init.h>
>  #include <linux/jump_label.h>
>  #include <linux/percpu.h>
> @@ -37,6 +38,35 @@ extern u64 arm64_mpam_global_default;
>   * A value in struct thread_info is used instead of struct task_struct as the
>   * cpu's u64 register format is used, but struct task_struct has two u32'.
>   */
I'd be tempted to reorder this so the comment ends up near at least
one use of task_thread_info(tsk)->mpam_partid_pmg. Otherwise it is even
less obvious what it is referring to.

Easiest might be to put the mpam_get_regval() before the mpam_set_task_partid_pmg()


> +static inline void mpam_set_cpu_defaults(int cpu, u16 partid_d, u16 partid_i,
> +					 u8 pmg_d, u8 pmg_i)
> +{
> +	u64 default_val;
> +
> +	default_val = FIELD_PREP(MPAM0_EL1_PARTID_D, partid_d);
> +	default_val |= FIELD_PREP(MPAM0_EL1_PARTID_I, partid_i);
> +	default_val |= FIELD_PREP(MPAM0_EL1_PMG_D, pmg_d);
> +	default_val |= FIELD_PREP(MPAM0_EL1_PMG_I, pmg_i);
> +
> +	WRITE_ONCE(per_cpu(arm64_mpam_default, cpu), default_val);
> +}
> +
> +static inline void mpam_set_task_partid_pmg(struct task_struct *tsk,
> +					    u16 partid_d, u16 partid_i,
> +					    u8 pmg_d, u8 pmg_i)
> +{
> +#ifdef CONFIG_ARM64_MPAM
> +	u64 regval;
> +
> +	regval = FIELD_PREP(MPAM0_EL1_PARTID_D, partid_d);
> +	regval |= FIELD_PREP(MPAM0_EL1_PARTID_I, partid_i);
> +	regval |= FIELD_PREP(MPAM0_EL1_PMG_D, pmg_d);
> +	regval |= FIELD_PREP(MPAM0_EL1_PMG_I, pmg_i);

Maybe a macro or helper to build regval given this replicates the block in
mpam_set_cpu_defaults.  Obviously ignore if this changes in later patches!

> +
> +	WRITE_ONCE(task_thread_info(tsk)->mpam_partid_pmg, regval);
> +#endif
> +}
> +
>  static inline u64 mpam_get_regval(struct task_struct *tsk)
>  {
>  #ifdef CONFIG_ARM64_MPAM



From arnaud.pouliquen at foss.st.com  Thu Dec 18 02:45:10 2025
From: arnaud.pouliquen at foss.st.com (Arnaud POULIQUEN)
Date: Thu, 18 Dec 2025 11:45:10 +0100
Subject: [PATCH v6 3/5] docs: driver-api: gpio: generic gpio driver over
 rpmsg bus
In-Reply-To: <20251212194341.966387-4-shenwei.wang@nxp.com>
References: <20251212194341.966387-1-shenwei.wang@nxp.com>
 <20251212194341.966387-4-shenwei.wang@nxp.com>
Message-ID: <86f7f157-d25f-48cb-806c-c8dc914033f1@foss.st.com>

Hello Shenwei,

On 12/12/25 20:43, Shenwei Wang wrote:
> Describes the gpio rpmsg transport protocol over the rpmsg bus between
> the cores.
> 
> Signed-off-by: Shenwei Wang <shenwei.wang at nxp.com>
> ---
>   Documentation/driver-api/gpio/gpio-rpmsg.rst | 232 +++++++++++++++++++
>   Documentation/driver-api/gpio/index.rst      |   1 +
>   2 files changed, 233 insertions(+)
>   create mode 100644 Documentation/driver-api/gpio/gpio-rpmsg.rst
> 
> diff --git a/Documentation/driver-api/gpio/gpio-rpmsg.rst b/Documentation/driver-api/gpio/gpio-rpmsg.rst
> new file mode 100644
> index 000000000000..c78d10a9a85c
> --- /dev/null
> +++ b/Documentation/driver-api/gpio/gpio-rpmsg.rst
> @@ -0,0 +1,232 @@
> +.. SPDX-License-Identifier: GPL-2.0-or-later
> +
> +GPIO RPMSG Protocol
> +===================
> +
> +The GPIO RPMSG transport protocol is used for communication and interaction
> +with GPIO controllers located on remote cores on the RPMSG bus.
> +
> +Message Format
> +--------------
> +
> +The RPMSG message consists of a 14-byte packet with the following layout:
> +
> +.. code-block:: none
> +
> +   +-----+-------+--------+-----+-----+------------+-----+-----+-----+----+
> +   |0x00 |0x01   |0x02    |0x03 |0x04 |0x05..0x09  |0x0A |0x0B |0x0C |0x0D|
> +   | ID  |vendor |version |type |cmd  |reserved[5] |line |port |  data    |
> +   +-----+-------+--------+-----+-----+------------+-----+-----+-----+----+
> +
> +- **ID (Message Identification Code)**: Always be 0x5. Indicates the GPIO message.
> +
> +- **Vendor**: Vendor ID number.
> +  - 0: Reserved
> +  - 1: NXP

These two fields above seem useless for the rpmsg-gpio. Is there any 
reason to keep them?

> +
> +- **Version**: Vendor-specific version number (such as software release).
> +
> +- **Type (Message Type)**: The message type can be one of:
> +
> +  - 0: GPIO_RPMSG_SETUP
> +  - 1: GPIO_RPMSG_REPLY
> +  - 2: GPIO_RPMSG_NOTIFY
> +
> +- **Cmd**: Command code, used for GPIO_RPMSG_SETUP messages.
> +
> +- **reserved[5]**: Reserved bytes. Should always be 0.
> +
> +- **line**: The GPIO line index.
> +
> +- **port**: The GPIO controller index.

The description of port and line should be OS-agnostic.
The notion of a GPIO controller index makes sense from a Linux 
perspective, but here you should provide a hardware description.
Additionally, I suggest reversing the order of port and line, as a line 
is an instance within a port.

Suggested definitions:
   **port**: The GPIO port(bank) index.
   **line**: The GPIO line(pin) index of the port.


> +
> +- **data**: See details in the command description below.
> +
> +GPIO Commands
> +-------------
> +
> +Commands are specified in the **Cmd** field for **GPIO_RPMSG_SETUP** (Type=0) messages.
> +
> +The SETUP message is always sent from Linux to the remote firmware. Each
> +SETUP corresponds to a single REPLY message. The GPIO driver should
> +serialize messages and determine whether a REPLY message is required. If a
> +REPLY message is expected but not received within the specified timeout
> +period (currently 1 second in the Linux driver), the driver should return
> +-ETIMEOUT.
> +
> +GPIO_RPMSG_INPUT_INIT (Cmd=0)
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +**Request:**
> +
> +.. code-block:: none
> +
> +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> +   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
> +   | 5   | 1   | 0   | 0   | 0   |  0        |line |port | val | wk |
> +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> +
> +- **val**: Interrupt trigger type.
> +
> +  - 0: Interrupt disabled
> +  - 1: Rising edge trigger
> +  - 2: Falling edge trigger
> +  - 3: Both edge trigger
> +  - 4: Low level trigger
> +  - 5: High level trigger
> +
> +- **wk**: Wakeup enable.
> +
> +  The remote system should always aim to stay in a power-efficient state by
> +  shutting down or clock-gating the GPIO blocks that aren't in use. Since
> +  the remoteproc driver is responsibe for managing the power states of the

s/responsibe/responsible

> +  remote firmware, the GPIO driver does not require to konow the firmware's

s/konow/know/

> +  running states.
> +
> +  When the wakeup bit is set, the remote firmware should configure the line
> +  as a wakeup source. The firmware should send the notification message to
> +  Linux after it is woken from the GPIO line.

What about the other direction? The remote could also need to disable 
message from Linux, right?
In such case the remote might need a message to get the GPIO value on 
wake-up.

> +
> +  - 0: Disable wakeup from GPIO
> +  - 1: Enable wakeup from GPIO
> +
> +**Reply:**
> +
> +.. code-block:: none
> +
> +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> +   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
> +   | 5   | 1   | 0   | 1   | 1   |  0        |line |port | err | 0  |
> +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> +
> +- **err**: Error code from the remote core.
> +
> +  - 0: Success
> +  - 1: General error (early remote software only returns this unclassified error)
> +  - 2: Not supported (A command is not supported by the remote firmware)
> +  - 3: Resource not available (The resource is not allocated to the Linux)
> +  - 4: Resource busy (The resource is already used)
> +  - 5: Parameter error
> +
> +GPIO_RPMSG_OUTPUT_INIT (Cmd=1)
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Does this means that we can not change the output level during runtime?
else this should be renamed GPIO_RPMSG_OUTPUT_SET

> +
> +**Request:**
> +
> +.. code-block:: none
> +
> +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> +   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
> +   | 5   | 1   | 0   | 0   | 1   |  0        |line |port | val | 0  |
> +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> +
> +- **val**: Output level.
> +
> +  - 0: Low
> +  - 1: High
> +
> +**Reply:**
> +
> +.. code-block:: none
> +
> +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> +   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
> +   | 5   | 1   | 0   | 1   | 1   |  0        |line |port | err | 0  |
> +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> +
> +- **err**: See above for definitions.
> +
> +GPIO_RPMSG_INPUT_GET (Cmd=2)
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +**Request:**
> +
> +.. code-block:: none
> +
> +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> +   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
> +   | 5   | 1   | 0   | 0   | 2   |  0        |line |port | 0   | 0  |
> +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> +
> +**Reply:**
> +
> +.. code-block:: none
> +
> +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+-----+
> +   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D |
> +   | 5   | 1   | 0   | 1   | 2   |  0        |line |port | err |level|
> +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+-----+
> +
> +- **err**: See above for definitions.
> +
> +- **level**: Input level.
> +
> +  - 0: Low
> +  - 1: High
> +
> +GPIO_RPMSG_GET_DIRECTION (Cmd=3)
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +**Request:**
> +
> +.. code-block:: none
> +
> +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> +   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
> +   | 5   | 1   | 0   | 0   | 3   |  0        |line |port | 0   | 0  |
> +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> +
> +**Reply:**
> +
> +.. code-block:: none
> +
> +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+-----+
> +   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D |
> +   | 5   | 1   | 0   | 1   | 3   |  0        |line |port | err | dir |
> +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+-----+
> +
> +- **err**: See above for definitions.
> +
> +- **dir**: Direction.
> +
> +  - 0: Output
> +  - 1: Input

So here if I well understand, the list of GPIO are defined in DT and
This command should be use to check the direction during the probe.
Could you document its usage?

> +
> +Notification Message
> +--------------------
> +
> +Notifications are sent with **Type=2 (GPIO_RPMSG_NOTIFY)**:
> +
> +When a GPIO line asserts an interrupt on the remote processor, the firmware
> +should immediately mask the corresponding interrupt source and send a
> +notification message to the Linux. Upon completion of the interrupt
> +handling on the Linux side, the driver should issue a
> +**GPIO_RPMSG_INPUT_INIT** command to the firmware to unmask the interrupt.
> +
> +A Notification message can arrive between a SETUP and its REPLY message,
> +and the driver is expected to handle this scenario.
> +
> +.. code-block:: none
> +
> +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> +   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
> +   | 5   | 1   | 0   | 2   | 0   |  0        |line |port | 0   | 0  |
> +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> +
> +- **line**: The GPIO line index.
> +- **port**: The GPIO controller index.
> +
> +The reply message for the notification is optional. The remote firmware can
> +implement it to simulate the interrupt acknowledgment behavior.
> +
> +The notification reply is sent with the byte index 0x4=1.
> +
> +.. code-block:: none
> +
> +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> +   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
> +   | 5   | 1   | 0   | 2   | 1   |  0        |line |port | 0   | 0  |
> +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> +
> +- **line**: The GPIO line index.
> +- **port**: The GPIO controller index.

The type seems strange here, it is a reply but tagged as notification, 
what about adding a type 4 GPIO_RPMSG_NOTIFY_REPLY ?


It might be useful to specify the GPIO level as parameter, especially 
for  "3: Both edge trigger"

Thanks,
Arnaud

> diff --git a/Documentation/driver-api/gpio/index.rst b/Documentation/driver-api/gpio/index.rst
> index bee58f709b9a..e5eb1f82f01f 100644
> --- a/Documentation/driver-api/gpio/index.rst
> +++ b/Documentation/driver-api/gpio/index.rst
> @@ -16,6 +16,7 @@ Contents:
>      drivers-on-gpio
>      bt8xxgpio
>      pca953x
> +   gpio-rpmsg
>   
>   Core
>   ====



From alain.volmat at foss.st.com  Thu Dec 18 02:48:26 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Thu, 18 Dec 2025 11:48:26 +0100
Subject: [PATCH v2 0/4] spi: stm32: stability & performance enhancements
Message-ID: <20251218-stm32-spi-enhancements-v2-0-3b69901ca9fe@foss.st.com>

The series fixes a stability issue when dealing with <8bpw
transfers, as well as enforce an error if the DMA information
provided within the DT are incorrect.

Performance enhancement is also provided by allowing a polling
mode which is triggered when the transfer is so short that
polling mode transfer would lead to faster transfer than
if it was done in a interrupt driven manner.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
Changes in v2:
- reordered commits, putting fix commits first in the series.
- no changes done in commits.
- Link to v1: https://lore.kernel.org/r/20251217-stm32-spi-enhancements-v1-0-943348b8ff66 at foss.st.com

---
Alain Volmat (3):
      spi: stm32: properly fail on dma_request_chan error
      spi: stm32: perform small transfer in polling mode
      ARM: dts: stm32: add spi1 sleep state pinctrl on stm32mp157c-ev1

Deepak Kumar (1):
      spi: stm32: fix Overrun issue at < 8bpw

 arch/arm/boot/dts/st/stm32mp157c-ev1.dts |   3 +-
 drivers/spi/spi-stm32.c                  | 106 +++++++++++++++++++++++++++----
 2 files changed, 96 insertions(+), 13 deletions(-)
---
base-commit: 865a1f17d5e41c0b34929afcab0afa6bdb90d33e
change-id: 20251213-stm32-spi-enhancements-29da9bc29133

Best regards,
-- 
Alain Volmat <alain.volmat at foss.st.com>



From alain.volmat at foss.st.com  Thu Dec 18 02:48:28 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Thu, 18 Dec 2025 11:48:28 +0100
Subject: [PATCH v2 2/4] spi: stm32: fix Overrun issue at < 8bpw
In-Reply-To: <20251218-stm32-spi-enhancements-v2-0-3b69901ca9fe@foss.st.com>
References: <20251218-stm32-spi-enhancements-v2-0-3b69901ca9fe@foss.st.com>
Message-ID: <20251218-stm32-spi-enhancements-v2-2-3b69901ca9fe@foss.st.com>

From: Deepak Kumar <deepak.kumar01 at st.com>

When SPI communication is suspended by hardware automatically, it could
happen that few bits of next frame are already clocked out due to
internal synchronization delay.

To achieve a safe suspension, we need to ensure that each word must be
at least 8 SPI clock cycles long. That's why, if bpw is less than 8
bits, we need to use midi to reach 8 SPI clock cycles at least.

This will ensure that each word achieve safe suspension and prevent
overrun condition.

Signed-off-by: Deepak Kumar <deepak.kumar01 at st.com>
Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 drivers/spi/spi-stm32.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c
index 40651b6050f6..ced6d7b215b9 100644
--- a/drivers/spi/spi-stm32.c
+++ b/drivers/spi/spi-stm32.c
@@ -1906,11 +1906,12 @@ static void stm32h7_spi_data_idleness(struct stm32_spi *spi, struct spi_transfer
 	cfg2_clrb |= STM32H7_SPI_CFG2_MIDI;
 	if ((len > 1) && (spi->cur_midi > 0)) {
 		u32 sck_period_ns = DIV_ROUND_UP(NSEC_PER_SEC, spi->cur_speed);
-		u32 midi = min_t(u32,
-				 DIV_ROUND_UP(spi->cur_midi, sck_period_ns),
-				 FIELD_GET(STM32H7_SPI_CFG2_MIDI,
-				 STM32H7_SPI_CFG2_MIDI));
+		u32 midi = DIV_ROUND_UP(spi->cur_midi, sck_period_ns);
 
+		if ((spi->cur_bpw + midi) < 8)
+			midi = 8 - spi->cur_bpw;
+
+		midi = min_t(u32, midi, FIELD_MAX(STM32H7_SPI_CFG2_MIDI));
 
 		dev_dbg(spi->dev, "period=%dns, midi=%d(=%dns)\n",
 			sck_period_ns, midi, midi * sck_period_ns);

-- 
2.34.1



From alain.volmat at foss.st.com  Thu Dec 18 02:48:27 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Thu, 18 Dec 2025 11:48:27 +0100
Subject: [PATCH v2 1/4] spi: stm32: properly fail on dma_request_chan error
In-Reply-To: <20251218-stm32-spi-enhancements-v2-0-3b69901ca9fe@foss.st.com>
References: <20251218-stm32-spi-enhancements-v2-0-3b69901ca9fe@foss.st.com>
Message-ID: <20251218-stm32-spi-enhancements-v2-1-3b69901ca9fe@foss.st.com>

Correct handling of the dma_request_chan call in order to avoid
misleading warn message if no DMA is provided within the device-tree
and moreover fail if dma_request_chan has returned a valid error.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 drivers/spi/spi-stm32.c | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c
index 2c804c1aef98..40651b6050f6 100644
--- a/drivers/spi/spi-stm32.c
+++ b/drivers/spi/spi-stm32.c
@@ -2406,11 +2406,13 @@ static int stm32_spi_probe(struct platform_device *pdev)
 	spi->dma_tx = dma_request_chan(spi->dev, "tx");
 	if (IS_ERR(spi->dma_tx)) {
 		ret = PTR_ERR(spi->dma_tx);
-		spi->dma_tx = NULL;
-		if (ret == -EPROBE_DEFER)
+		if (ret == -ENODEV) {
+			dev_info(&pdev->dev, "tx dma disabled\n");
+			spi->dma_tx = NULL;
+		} else {
+			dev_err_probe(&pdev->dev, ret, "failed to request tx dma channel\n");
 			goto err_clk_disable;
-
-		dev_warn(&pdev->dev, "failed to request tx dma channel\n");
+		}
 	} else {
 		ctrl->dma_tx = spi->dma_tx;
 	}
@@ -2418,11 +2420,13 @@ static int stm32_spi_probe(struct platform_device *pdev)
 	spi->dma_rx = dma_request_chan(spi->dev, "rx");
 	if (IS_ERR(spi->dma_rx)) {
 		ret = PTR_ERR(spi->dma_rx);
-		spi->dma_rx = NULL;
-		if (ret == -EPROBE_DEFER)
+		if (ret == -ENODEV) {
+			dev_info(&pdev->dev, "rx dma disabled\n");
+			spi->dma_rx = NULL;
+		} else {
+			dev_err_probe(&pdev->dev, ret, "failed to request rx dma channel\n");
 			goto err_dma_release;
-
-		dev_warn(&pdev->dev, "failed to request rx dma channel\n");
+		}
 	} else {
 		ctrl->dma_rx = spi->dma_rx;
 	}

-- 
2.34.1



From alain.volmat at foss.st.com  Thu Dec 18 02:48:30 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Thu, 18 Dec 2025 11:48:30 +0100
Subject: [PATCH v2 4/4] ARM: dts: stm32: add spi1 sleep state pinctrl on
 stm32mp157c-ev1
In-Reply-To: <20251218-stm32-spi-enhancements-v2-0-3b69901ca9fe@foss.st.com>
References: <20251218-stm32-spi-enhancements-v2-0-3b69901ca9fe@foss.st.com>
Message-ID: <20251218-stm32-spi-enhancements-v2-4-3b69901ca9fe@foss.st.com>

Add the sleep state of the spi1 instance on stm32mp157c-ev1.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 arch/arm/boot/dts/st/stm32mp157c-ev1.dts | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/st/stm32mp157c-ev1.dts b/arch/arm/boot/dts/st/stm32mp157c-ev1.dts
index 8f99c30f1af1..4e46d58bf61f 100644
--- a/arch/arm/boot/dts/st/stm32mp157c-ev1.dts
+++ b/arch/arm/boot/dts/st/stm32mp157c-ev1.dts
@@ -296,8 +296,9 @@ &sdmmc3 {
 };
 
 &spi1 {
-	pinctrl-names = "default";
+	pinctrl-names = "default", "sleep";
 	pinctrl-0 = <&spi1_pins_a>;
+	pinctrl-1 = <&spi1_sleep_pins_a>;
 	status = "disabled";
 };
 

-- 
2.34.1



From alain.volmat at foss.st.com  Thu Dec 18 02:48:29 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Thu, 18 Dec 2025 11:48:29 +0100
Subject: [PATCH v2 3/4] spi: stm32: perform small transfer in polling mode
In-Reply-To: <20251218-stm32-spi-enhancements-v2-0-3b69901ca9fe@foss.st.com>
References: <20251218-stm32-spi-enhancements-v2-0-3b69901ca9fe@foss.st.com>
Message-ID: <20251218-stm32-spi-enhancements-v2-3-3b69901ca9fe@foss.st.com>

In case of interrupt based transfer, when the transfer is very
small, relying on interrupts leads to lower performances than if
the transfer were done using polling on the registers.

Add a module parameter "polling_limit_us" to indicate the threshold
in us from which a transfer would be done polling the registers rather
than relying on interrupts.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 drivers/spi/spi-stm32.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 77 insertions(+)

diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c
index ced6d7b215b9..8f8968383ad0 100644
--- a/drivers/spi/spi-stm32.c
+++ b/drivers/spi/spi-stm32.c
@@ -202,6 +202,10 @@
 #define STM32_SPI_HOST_MODE(stm32_spi) (!(stm32_spi)->device_mode)
 #define STM32_SPI_DEVICE_MODE(stm32_spi) ((stm32_spi)->device_mode)
 
+static unsigned int polling_limit_us = 30;
+module_param(polling_limit_us, uint, 0664);
+MODULE_PARM_DESC(polling_limit_us, "maximum time in us to run a transfer in polling mode\n");
+
 /**
  * struct stm32_spi_reg - stm32 SPI register & bitfield desc
  * @reg:		register offset
@@ -266,6 +270,7 @@ struct stm32_spi;
  * @dma_rx_cb: routine to call after DMA RX channel operation is complete
  * @dma_tx_cb: routine to call after DMA TX channel operation is complete
  * @transfer_one_irq: routine to configure interrupts for driver
+ * @transfer_one_poll: routine to perform a transfer via register polling
  * @irq_handler_event: Interrupt handler for SPI controller events
  * @irq_handler_thread: thread of interrupt handler for SPI controller
  * @baud_rate_div_min: minimum baud rate divisor
@@ -291,6 +296,7 @@ struct stm32_spi_cfg {
 	void (*dma_rx_cb)(void *data);
 	void (*dma_tx_cb)(void *data);
 	int (*transfer_one_irq)(struct stm32_spi *spi);
+	int (*transfer_one_poll)(struct stm32_spi *spi);
 	irqreturn_t (*irq_handler_event)(int irq, void *dev_id);
 	irqreturn_t (*irq_handler_thread)(int irq, void *dev_id);
 	unsigned int baud_rate_div_min;
@@ -1355,6 +1361,55 @@ static int stm32fx_spi_transfer_one_irq(struct stm32_spi *spi)
 	return 1;
 }
 
+/**
+ * stm32h7_spi_transfer_one_poll - transfer a single spi_transfer by direct
+ *				   register access without interrupt usage
+ * @spi: pointer to the spi controller data structure
+ *
+ * It must returns 0 if the transfer is finished or 1 if the transfer is still
+ * in progress.
+ */
+static int stm32h7_spi_transfer_one_poll(struct stm32_spi *spi)
+{
+	unsigned long flags;
+	u32 sr;
+
+	spin_lock_irqsave(&spi->lock, flags);
+
+	stm32_spi_enable(spi);
+
+	/* Be sure to have data in fifo before starting data transfer */
+	if (spi->tx_buf)
+		stm32h7_spi_write_txfifo(spi);
+
+	if (STM32_SPI_HOST_MODE(spi))
+		stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_CSTART);
+
+	sr = readl_relaxed(spi->base + STM32H7_SPI_SR);
+	/* Keep writing / reading while waiting for the end of transfer */
+	while (spi->tx_len || spi->rx_len || !(sr & STM32H7_SPI_SR_EOT)) {
+		if (spi->rx_len && (sr & (STM32H7_SPI_SR_RXP | STM32H7_SPI_SR_RXWNE |
+					  STM32H7_SPI_SR_RXPLVL)))
+			stm32h7_spi_read_rxfifo(spi);
+
+		if (spi->tx_len && (sr & STM32H7_SPI_SR_TXP))
+			stm32h7_spi_write_txfifo(spi);
+
+		sr = readl_relaxed(spi->base + STM32H7_SPI_SR);
+
+		/* Clear suspension bit if necessary */
+		if (sr & STM32H7_SPI_SR_SUSP)
+			writel_relaxed(sr & STM32H7_SPI_SR_SUSP, spi->base + STM32H7_SPI_IFCR);
+	}
+
+	spin_unlock_irqrestore(&spi->lock, flags);
+
+	stm32h7_spi_disable(spi);
+	spi_finalize_current_transfer(spi->ctrl);
+
+	return 0;
+}
+
 /**
  * stm32h7_spi_transfer_one_irq - transfer a single spi_transfer using
  *				  interrupts
@@ -2026,6 +2081,24 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi,
 	return ret;
 }
 
+/**
+ * stm32_spi_can_poll - detect if poll based transfer is appropriate
+ * @spi: pointer to the spi controller data structure
+ *
+ * Returns true is poll is more appropriate, false otherwise.
+ */
+static bool stm32_spi_can_poll(struct stm32_spi *spi)
+{
+	unsigned long hz_per_byte, byte_limit;
+
+	/* Evaluate the transfer time and use polling if applicable */
+	hz_per_byte = polling_limit_us ?
+		      DIV_ROUND_UP(8 * USEC_PER_SEC, polling_limit_us) : 0;
+	byte_limit = hz_per_byte ? spi->cur_speed / hz_per_byte : 1;
+
+	return (spi->cur_xferlen < byte_limit) ? true : false;
+}
+
 /**
  * stm32_spi_transfer_one - transfer a single spi_transfer
  * @ctrl: controller interface
@@ -2058,6 +2131,8 @@ static int stm32_spi_transfer_one(struct spi_controller *ctrl,
 
 	if (spi->cur_usedma)
 		return stm32_spi_transfer_one_dma(spi, transfer);
+	else if (spi->cfg->transfer_one_poll && stm32_spi_can_poll(spi))
+		return spi->cfg->transfer_one_poll(spi);
 	else
 		return spi->cfg->transfer_one_irq(spi);
 }
@@ -2216,6 +2291,7 @@ static const struct stm32_spi_cfg stm32h7_spi_cfg = {
 	 * SPI access hence handling is performed within the SPI interrupt
 	 */
 	.transfer_one_irq = stm32h7_spi_transfer_one_irq,
+	.transfer_one_poll = stm32h7_spi_transfer_one_poll,
 	.irq_handler_thread = stm32h7_spi_irq_thread,
 	.baud_rate_div_min = STM32H7_SPI_MBR_DIV_MIN,
 	.baud_rate_div_max = STM32H7_SPI_MBR_DIV_MAX,
@@ -2245,6 +2321,7 @@ static const struct stm32_spi_cfg stm32mp25_spi_cfg = {
 	 * SPI access hence handling is performed within the SPI interrupt
 	 */
 	.transfer_one_irq = stm32h7_spi_transfer_one_irq,
+	.transfer_one_poll = stm32h7_spi_transfer_one_poll,
 	.irq_handler_thread = stm32h7_spi_irq_thread,
 	.baud_rate_div_min = STM32H7_SPI_MBR_DIV_MIN,
 	.baud_rate_div_max = STM32H7_SPI_MBR_DIV_MAX,

-- 
2.34.1



From arnaud.pouliquen at foss.st.com  Thu Dec 18 03:03:40 2025
From: arnaud.pouliquen at foss.st.com (Arnaud POULIQUEN)
Date: Thu, 18 Dec 2025 12:03:40 +0100
Subject: [PATCH v6 2/5] remoteproc: imx_rproc: Populate devices under
 "rpmsg" subnode
In-Reply-To: <20251212194341.966387-3-shenwei.wang@nxp.com>
References: <20251212194341.966387-1-shenwei.wang@nxp.com>
 <20251212194341.966387-3-shenwei.wang@nxp.com>
Message-ID: <805c9dd5-50ca-4e2f-8fe8-b8a601fe4428@foss.st.com>

Hello,

On 12/12/25 20:43, Shenwei Wang wrote:
> Register the RPMsg channel driver and populate remote devices defined
> under the "rpmsg" subnode upon receiving their notification messages.
> 
> The following illustrates the expected DTS layout structure:
> 
> 	cm33: remoteproc-cm33 {
> 		compatible = "fsl,imx8ulp-cm33";
> 
> 		rpmsg {
> 			rpmsg-io-channel {
> 				gpio at 0 {
> 					compatible = "fsl,imx-rpmsg-gpio";
> 					reg = <0>;
> 				};
> 
> 				gpio at 1 {
> 					compatible = "fsl,imx-rpmsg-gpio";
> 					reg = <1>;
> 				};
> 
> 				...
> 			};
> 
> 			...
> 		};
> 	};
> 
> Signed-off-by: Shenwei Wang <shenwei.wang at nxp.com>
> ---
>   drivers/remoteproc/imx_rproc.c   | 143 +++++++++++++++++++++++++++++++
>   include/linux/rpmsg/rpdev_info.h |  33 +++++++
>   2 files changed, 176 insertions(+)
>   create mode 100644 include/linux/rpmsg/rpdev_info.h
> 
> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
> index 33f21ab24c92..65ee16fd66d1 100644
> --- a/drivers/remoteproc/imx_rproc.c
> +++ b/drivers/remoteproc/imx_rproc.c
> @@ -15,6 +15,8 @@
>   #include <linux/module.h>
>   #include <linux/of.h>
>   #include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
>   #include <linux/of_reserved_mem.h>
>   #include <linux/platform_device.h>
>   #include <linux/pm_domain.h>
> @@ -22,6 +24,8 @@
>   #include <linux/reboot.h>
>   #include <linux/regmap.h>
>   #include <linux/remoteproc.h>
> +#include <linux/rpmsg.h>
> +#include <linux/rpmsg/rpdev_info.h>
>   #include <linux/workqueue.h>
>   
>   #include "imx_rproc.h"
> @@ -1016,6 +1020,141 @@ static void imx_rproc_destroy_workqueue(void *data)
>   	destroy_workqueue(workqueue);
>   }
>   
> +struct imx_rpmsg_driver {
> +	struct rpmsg_driver rpdrv;
> +	const char *compat;
> +	void *driver_data;
> +};
> +
> +static const char *channel_device_map[][2] = {
> +	{"rpmsg-io-channel", "rpmsg-gpio"},
> +};
> +
> +static int imx_rpmsg_endpoint_cb(struct rpmsg_device *rpdev, void *data,
> +				 int len, void *priv, u32 src)
> +{
> +	struct rpdev_platform_info *drvdata;
> +
> +	drvdata = dev_get_drvdata(&rpdev->dev);
> +	if (drvdata && drvdata->rx_callback)
> +		return drvdata->rx_callback(rpdev, data, len, priv, src);
> +
> +	return 0;
> +}
> +
> +static void imx_rpmsg_endpoint_remove(struct rpmsg_device *rpdev)
> +{
> +	of_platform_depopulate(&rpdev->dev);
> +}
> +
> +static int imx_rpmsg_endpoint_probe(struct rpmsg_device *rpdev)
> +{
> +	struct rpdev_platform_info *drvdata;
> +	struct imx_rpmsg_driver *imx_rpdrv;
> +	struct device *dev = &rpdev->dev;
> +	struct of_dev_auxdata *auxdata;
> +	struct rpmsg_driver *rpdrv;
> +
> +	rpdrv = container_of(dev->driver, struct rpmsg_driver, drv);
> +	imx_rpdrv = container_of(rpdrv, struct imx_rpmsg_driver, rpdrv);
> +
> +	if (!imx_rpdrv->driver_data)
> +		return -EINVAL;
> +
> +	drvdata = devm_kmemdup(dev, imx_rpdrv->driver_data, sizeof(*drvdata), GFP_KERNEL);
> +	if (!drvdata)
> +		return -ENOMEM;
> +
> +	auxdata = devm_kzalloc(dev, sizeof(*auxdata) * 2, GFP_KERNEL);
> +	if (!auxdata)
> +		return -ENOMEM;
> +
> +	drvdata->rpdev = rpdev;
> +	auxdata[0].compatible = devm_kstrdup(dev, imx_rpdrv->compat, GFP_KERNEL);
> +	auxdata[0].platform_data = drvdata;
> +	dev_set_drvdata(dev, drvdata);
> +
> +	of_platform_populate(drvdata->channel_node, NULL, auxdata, dev);
> +
> +	return 0;
> +}
> +
> +static const char *imx_of_rpmsg_is_in_map(const char *name)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(channel_device_map); i++) {
> +		if (strcmp(name, channel_device_map[i][0]) == 0)
> +			return channel_device_map[i][1];
> +	}
> +
> +	return NULL;
> +}
> +
> +static int imx_of_rpmsg_register_rpdriver(struct device_node *channel,
> +					  struct device *dev,
> +					  const char *name,
> +					  const char *compat)
> +{
> +	struct rpdev_platform_info *driver_data;
> +	struct imx_rpmsg_driver *rp_driver;
> +	struct rpmsg_device_id *rpdev_id;
> +
> +	/* rpmsg_device_id is a NULL terminated array */
> +	rpdev_id = devm_kzalloc(dev, sizeof(*rpdev_id) * 2, GFP_KERNEL);
> +	if (!rpdev_id)
> +		return -ENOMEM;
> +
> +	strscpy(rpdev_id[0].name, name, RPMSG_NAME_SIZE);
> +
> +	rp_driver = devm_kzalloc(dev, sizeof(*rp_driver), GFP_KERNEL);
> +	if (!rp_driver)
> +		return -ENOMEM;
> +
> +	driver_data = devm_kzalloc(dev, sizeof(*driver_data), GFP_KERNEL);
> +	if (!driver_data)
> +		return -ENOMEM;
> +
> +	driver_data->rproc_name = dev->of_node->name;
> +	driver_data->channel_node = channel;
> +
> +	rp_driver->rpdrv.drv.name = name;
> +	rp_driver->rpdrv.id_table = rpdev_id;
> +	rp_driver->rpdrv.probe = imx_rpmsg_endpoint_probe;
> +	rp_driver->rpdrv.remove = imx_rpmsg_endpoint_remove;
> +	rp_driver->rpdrv.callback = imx_rpmsg_endpoint_cb;
> +	rp_driver->driver_data = driver_data;
> +	rp_driver->compat = compat;
> +
> +	register_rpmsg_driver(&rp_driver->rpdrv);


I still believe that creating a dependency between remoteproc and rpmsg 
is not suitable.

Please correct me if I?m wrong, but since you define gpio at 0 and gpio at 1 
in your device tree, you call register_rpmsg_driver() twice, creating 
two instances of the same driver. To differentiate both, you fill the 
rpdrv.id_table with the node names "gpio at 0" and "gpio at 1".

In a topology with two remote processors, each needing rpmsg-gpio, the 
same situation would not work because you would have two "gpio at 0" entries.

What about using the ns-announcement mechanism on the remote side to 
address GPIO port/bank instances?

In the rpmsg-gpio driver, you could define:

static struct rpmsg_device_id rpmsg_gpio_id_table[] = {
     { .name = "rpmsg-gpio" },
     { .name = "rpmsg_gpio-0" },
     { .name = "rpmsg_gpio-1" },
     { .name = "rpmsg_gpio-2" },
     { .name = "rpmsg_gpio-3" },
     { },
};

Then the match between the device tree and the rpmsg bus could be done 
in the rpmsg-gpio driver by matching the rpmsg name with the compatible 
property plus the reg value.

Example device tree snippet:

cm33: remoteproc-cm33 {
     compatible = "fsl,imx8ulp-cm33";

     rpmsg {
         rpmsg-io-channel {
             gpio at 0 {
                 compatible = "rpmsg_gpio";
                 reg = <0>;
             };

             gpio at 1 {
                 compatible = "rpmsg_gpio";
                 reg = <1>;
             };

             ...
         };

         ...
     };
};

With this approach, rpmsg management could be handled entirely within 
the rpmsg-gpio driver, avoiding the need to register multiple instances 
of the rpmsg_gpio driver.

Regards,
Arnaud

> +
> +	return 0;
> +}
> +
> +static int rproc_of_rpmsg_node_init(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	const char *compat;
> +	int ret;
> +
> +	struct device_node *np __free(device_node) = of_get_child_by_name(dev->of_node, "rpmsg");
> +	if (!np)
> +		return 0;
> +
> +	for_each_child_of_node_scoped(np, child) {
> +		compat = imx_of_rpmsg_is_in_map(child->name);
> +		if (!compat)
> +			ret = of_platform_default_populate(child, NULL, dev);
> +		else
> +			ret = imx_of_rpmsg_register_rpdriver(child, dev, child->name, compat);
> +
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
>   static int imx_rproc_probe(struct platform_device *pdev)
>   {
>   	struct device *dev = &pdev->dev;
> @@ -1114,6 +1253,10 @@ static int imx_rproc_probe(struct platform_device *pdev)
>   		goto err_put_pm;
>   	}
>   
> +	ret = rproc_of_rpmsg_node_init(pdev);
> +	if (ret < 0)
> +		dev_info(dev, "populating 'rpmsg' node failed\n");
> +
>   	return 0;
>   
>   err_put_pm:
> diff --git a/include/linux/rpmsg/rpdev_info.h b/include/linux/rpmsg/rpdev_info.h
> new file mode 100644
> index 000000000000..13e020cd028b
> --- /dev/null
> +++ b/include/linux/rpmsg/rpdev_info.h
> @@ -0,0 +1,33 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright 2025 NXP */
> +
> +/*
> + * @file linux/rpdev_info.h
> + *
> + * @brief Global header file for RPDEV Info
> + *
> + * @ingroup RPMSG
> + */
> +#ifndef __LINUX_RPDEV_INFO_H__
> +#define __LINUX_RPDEV_INFO_H__
> +
> +#define MAX_DEV_PER_CHANNEL    10
> +
> +/**
> + * rpdev_platform_info - store the platform information of rpdev
> + * @rproc_name: the name of the remote proc.
> + * @rpdev: rpmsg channel device
> + * @device_node: pointer to the device node of the rpdev.
> + * @rx_callback: rx callback handler of the rpdev.
> + * @channel_devices: an array of the devices related to the rpdev.
> + */
> +struct rpdev_platform_info {
> +	const char *rproc_name;
> +	struct rpmsg_device *rpdev;
> +	struct device_node *channel_node;
> +	int (*rx_callback)(struct rpmsg_device *rpdev, void *data,
> +			   int len, void *priv, u32 src);
> +	void *channel_devices[MAX_DEV_PER_CHANNEL];
> +};
> +
> +#endif /* __LINUX_RPDEV_INFO_H__ */



From suzuki.poulose at arm.com  Thu Dec 18 03:10:07 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Thu, 18 Dec 2025 11:10:07 +0000
Subject: [PATCH v4 1/3] coresight: tpda: add sysfs nodes for tpda
 cross-trigger configuration
In-Reply-To: <20251028-configure_tpda_reg-v4-1-23000805d21d@oss.qualcomm.com>
References: <20251028-configure_tpda_reg-v4-0-23000805d21d@oss.qualcomm.com>
 <20251028-configure_tpda_reg-v4-1-23000805d21d@oss.qualcomm.com>
Message-ID: <a785ced7-95ae-444b-b8ca-b40aecb35230@arm.com>

On 28/10/2025 02:02, Jie Gan wrote:
> From: Tao Zhang <tao.zhang at oss.qualcomm.com>
> 
> Introduce sysfs nodes to configure cross-trigger parameters for TPDA.
> These registers define the characteristics of cross-trigger packets,
> including generation frequency and flag values.
> 
> Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
> Reviewed-by: James Clark <james.clark at linaro.org>
> Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
> ---
>   .../ABI/testing/sysfs-bus-coresight-devices-tpda   |  43 ++++
>   drivers/hwtracing/coresight/coresight-tpda.c       | 230 +++++++++++++++++++++
>   drivers/hwtracing/coresight/coresight-tpda.h       |  27 ++-
>   3 files changed, 299 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
> new file mode 100644
> index 000000000000..80e4b05a1ab4
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
> @@ -0,0 +1,43 @@
> +What:		/sys/bus/coresight/devices/<tpda-name>/trig_async_enable
> +Date:		October 2025
> +KernelVersion:	6.19
> +Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
> +Description:
> +		(RW) Enable/disable cross trigger synchronization sequence interface.
> +
> +What:		/sys/bus/coresight/devices/<tpda-name>/trig_flag_ts_enable
> +Date:		October 2025
> +KernelVersion:	6.19
> +Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
> +Description:
> +		(RW) Enable/disable cross trigger FLAG packet request interface.
> +
> +What:		/sys/bus/coresight/devices/<tpda-name>/trig_freq_enable
> +Date:		October 2025
> +KernelVersion:	6.19
> +Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
> +Description:
> +		(RW) Enable/disable cross trigger FREQ packet request interface.
> +
> +What:		/sys/bus/coresight/devices/<tpda-name>/freq_ts_enable
> +Date:		October 2025
> +KernelVersion:	6.19
> +Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
> +Description:
> +		(RW) Enable/disable the timestamp for all FREQ packets.
> +
> +What:		/sys/bus/coresight/devices/<tpda-name>/global_flush_req
> +Date:		October 2025
> +KernelVersion:	6.19
> +Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
> +Description:
> +		(RW) Set global (all ports) flush request bit. The bit remains set until a
> +		global flush request sequence completes.
> +
> +What:		/sys/bus/coresight/devices/<tpda-name>/cmbchan_mode
> +Date:		October 2025
> +KernelVersion:	6.19
> +Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
> +Description:
> +		(RW) Configure the CMB/MCMB channel mode for all enabled ports.
> +		Value 0 means raw channel mapping mode. Value 1 means channel pair marking mode.
> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
> index 333b3cb23685..a9a27bcc65a1 100644
> --- a/drivers/hwtracing/coresight/coresight-tpda.c
> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
> @@ -147,9 +147,37 @@ static void tpda_enable_pre_port(struct tpda_drvdata *drvdata)
>   	u32 val;
>   
>   	val = readl_relaxed(drvdata->base + TPDA_CR);
> +	val &= ~TPDA_CR_MID;
>   	val &= ~TPDA_CR_ATID;

See, below.

>   	val |= FIELD_PREP(TPDA_CR_ATID, drvdata->atid);
> +	if (drvdata->trig_async)
> +		val |= TPDA_CR_SRIE;
> +	else
> +		val &= ~TPDA_CR_SRIE;
> +	if (drvdata->trig_flag_ts)
> +		val |= TPDA_CR_FLRIE;
> +	else
> +		val &= ~TPDA_CR_FLRIE;
> +	if (drvdata->trig_freq)
> +		val |= TPDA_CR_FRIE;
> +	else
> +		val &= ~TPDA_CR_FRIE;
> +	if (drvdata->freq_ts)
> +		val |= TPDA_CR_FREQTS;
> +	else
> +		val &= ~TPDA_CR_FREQTS;
> +	if (drvdata->cmbchan_mode)
> +		val |= TPDA_CR_CMBCHANMODE;
> +	else
> +		val &= ~TPDA_CR_CMBCHANMODE;

Could we clear all of the bits that are configurable in one go in the
beginning and set the appropriate ones based on the setting ? i.e.:

Do we really need to retain any values ? And if not, why not start
with a fresh set of values and avoid the read ?

>   	writel_relaxed(val, drvdata->base + TPDA_CR);
> +
> +	/*
> +	 * If FLRIE bit is set, set the master and channel
> +	 * id as zero
> +	 */
> +	if (drvdata->trig_flag_ts)
> +		writel_relaxed(0x0, drvdata->base + TPDA_FPID_CR);
>   }
>   
>   static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
> @@ -265,6 +293,206 @@ static const struct coresight_ops tpda_cs_ops = {
>   	.link_ops	= &tpda_link_ops,
>   };
>   
> +static ssize_t trig_async_enable_show(struct device *dev,
> +				      struct device_attribute *attr,
> +				      char *buf)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +
> +	return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_async);
> +}
> +
> +static ssize_t trig_async_enable_store(struct device *dev,
> +				       struct device_attribute *attr,
> +				       const char *buf,
> +				       size_t size)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	unsigned long val;
> +
> +	if (kstrtoul(buf, 0, &val))
> +		return -EINVAL;
> +
> +	guard(spinlock)(&drvdata->spinlock);
> +	drvdata->trig_async = !!val;
> +



> +	return size;
> +}
> +static DEVICE_ATTR_RW(trig_async_enable);

...

> +static DEVICE_ATTR_RW(trig_flag_ts_enable);

...

> +static DEVICE_ATTR_RW(trig_freq_enable);

...
> +static DEVICE_ATTR_RW(freq_ts_enable);

These attribute are boolean and looks like we could save some space on
code by using dev_ext_attribute.
see tpdm_simple_dataset_rw()/tpdm_simple_dataset_ro() . You could

#define TPDA_TRIG_ASYNC		0
#define TPDA_TRIG_FLAG_TS 	1
#define TPDA_TRIG_FREQ		2


tpda_trig_sysfs_show/store()

  bool *ptr;
  switch (eattr->var) {
  case TPDA_TRIG_ASYNC:
	ptr = &drvdata->trig_async;
	break;
  case TPDA_TRIG_FLAG_TS:
	ptr = &drvdata->trig_flag_ts;
	break;
...
	
  }



> +
> +static ssize_t global_flush_req_show(struct device *dev,
> +				     struct device_attribute *attr,
> +				     char *buf)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	unsigned long val;
> +
> +	if (!drvdata->csdev->refcnt)
> +		return -EINVAL;
> +
> +	guard(spinlock)(&drvdata->spinlock);
> +	CS_UNLOCK(drvdata->base);
> +	val = readl_relaxed(drvdata->base + TPDA_CR);
> +	CS_LOCK(drvdata->base);
> +	/* Only read value for bit 0 */
> +	val &= BIT(0);
> +
> +	return sysfs_emit(buf, "%lu\n", val);
> +}
> +
> +static ssize_t global_flush_req_store(struct device *dev,
> +				      struct device_attribute *attr,
> +				      const char *buf,
> +				      size_t size)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	unsigned long val;
> +
> +	if (kstrtoul(buf, 0, &val))
> +		return -EINVAL;
> +
> +	if (!drvdata->csdev->refcnt || !val)
> +		return -EINVAL;
> +
> +	guard(spinlock)(&drvdata->spinlock);
> +	CS_UNLOCK(drvdata->base);
> +	val = readl_relaxed(drvdata->base + TPDA_CR);
> +	/* Only set bit 0 */
> +	val |= BIT(0);

What is BIT 0 ? Please document it

> +	writel_relaxed(val, drvdata->base + TPDA_CR);
> +	CS_LOCK(drvdata->base);
> +
> +	return size;
> +}
> +static DEVICE_ATTR_RW(global_flush_req);



> +
> +static ssize_t cmbchan_mode_show(struct device *dev,
> +				 struct device_attribute *attr,
> +				 char *buf)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +
> +	return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->cmbchan_mode);
> +}
> +
> +static ssize_t cmbchan_mode_store(struct device *dev,
> +				  struct device_attribute *attr,
> +				  const char *buf,
> +				  size_t size)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	unsigned long val;
> +
> +	if (kstrtoul(buf, 0, &val))
> +		return -EINVAL;
> +
> +	guard(spinlock)(&drvdata->spinlock);
> +	drvdata->cmbchan_mode = !!val;
> +
> +	return size;
> +}
> +static DEVICE_ATTR_RW(cmbchan_mode);

Even this could go to the dev_ext_attribute magic and reuse a single 
show/store.

> +
> +static struct attribute *tpda_attrs[] = {
> +	&dev_attr_trig_async_enable.attr,
> +	&dev_attr_trig_flag_ts_enable.attr,
> +	&dev_attr_trig_freq_enable.attr,
> +	&dev_attr_freq_ts_enable.attr,
> +	&dev_attr_global_flush_req.attr,
> +	&dev_attr_cmbchan_mode.attr,
> +	NULL,
> +};

> diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h
> index c6af3d2da3ef..0be625fb52fd 100644
> --- a/drivers/hwtracing/coresight/coresight-tpda.h
> +++ b/drivers/hwtracing/coresight/coresight-tpda.h
> @@ -1,6 +1,6 @@
>   /* SPDX-License-Identifier: GPL-2.0 */
>   /*
> - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
> + * Copyright (c) 2023,2025 Qualcomm Innovation Center, Inc. All rights reserved.
>    */
>   
>   #ifndef _CORESIGHT_CORESIGHT_TPDA_H
> @@ -8,6 +8,19 @@
>   
>   #define TPDA_CR			(0x000)
>   #define TPDA_Pn_CR(n)		(0x004 + (n * 4))
> +#define TPDA_FPID_CR		(0x084)
> +
> +/* Cross trigger FREQ packets timestamp bit */
> +#define TPDA_CR_FREQTS		BIT(2)
> +/* Cross trigger FREQ packet request bit */
> +#define TPDA_CR_FRIE		BIT(3)
> +/* Cross trigger FLAG packet request interface bit */
> +#define TPDA_CR_FLRIE		BIT(4)
> +/* Cross trigger synchronization bit */
> +#define TPDA_CR_SRIE		BIT(5)
> +/* Packetize CMB/MCMB traffic bit */
> +#define TPDA_CR_CMBCHANMODE	BIT(20)
> +

Why are these not clubbed with the other TPDA_CR_ defintions ?

>   /* Aggregator port enable bit */
>   #define TPDA_Pn_CR_ENA		BIT(0)
>   /* Aggregator port CMB data set element size bit */
> @@ -19,6 +32,8 @@
>   
>   /* Bits 6 ~ 12 is for atid value */
>   #define TPDA_CR_ATID		GENMASK(12, 6)
> +/* Bits 13 ~ 19 is for mid value */
> +#define TPDA_CR_MID		GENMASK(19, 13)
>   
>   /**
>    * struct tpda_drvdata - specifics associated to an TPDA component
> @@ -29,6 +44,11 @@
>    * @enable:     enable status of the component.
>    * @dsb_esize   Record the DSB element size.
>    * @cmb_esize   Record the CMB element size.
> + * @trig_async:	Enable/disable cross trigger synchronization sequence interface.
> + * @trig_flag_ts: Enable/disable cross trigger FLAG packet request interface.
> + * @trig_freq:	Enable/disable cross trigger FREQ packet request interface.
> + * @freq_ts:	Enable/disable the timestamp for all FREQ packets.
> + * @cmbchan_mode: Configure the CMB/MCMB channel mode.
>    */
>   struct tpda_drvdata {
>   	void __iomem		*base;
> @@ -38,6 +58,11 @@ struct tpda_drvdata {
>   	u8			atid;
>   	u32			dsb_esize;
>   	u32			cmb_esize;
> +	bool			trig_async;
> +	bool			trig_flag_ts;
> +	bool			trig_freq;
> +	bool			freq_ts;
> +	bool			cmbchan_mode;
>   };
>   
>   #endif  /* _CORESIGHT_CORESIGHT_TPDA_H */

Suzuki



From suzuki.poulose at arm.com  Thu Dec 18 03:20:17 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Thu, 18 Dec 2025 11:20:17 +0000
Subject: [PATCH v4 1/3] coresight: tpda: add sysfs nodes for tpda
 cross-trigger configuration
In-Reply-To: <a785ced7-95ae-444b-b8ca-b40aecb35230@arm.com>
References: <20251028-configure_tpda_reg-v4-0-23000805d21d@oss.qualcomm.com>
 <20251028-configure_tpda_reg-v4-1-23000805d21d@oss.qualcomm.com>
 <a785ced7-95ae-444b-b8ca-b40aecb35230@arm.com>
Message-ID: <a95dc8ee-0b65-4ab6-966f-b15c31f6c6dc@arm.com>

On 18/12/2025 11:10, Suzuki K Poulose wrote:
> On 28/10/2025 02:02, Jie Gan wrote:
>> From: Tao Zhang <tao.zhang at oss.qualcomm.com>
>>
>> Introduce sysfs nodes to configure cross-trigger parameters for TPDA.
>> These registers define the characteristics of cross-trigger packets,
>> including generation frequency and flag values.
>>
>> Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
>> Reviewed-by: James Clark <james.clark at linaro.org>
>> Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> ---
>> ? .../ABI/testing/sysfs-bus-coresight-devices-tpda?? |? 43 ++++
>> ? drivers/hwtracing/coresight/coresight-tpda.c?????? | 230 +++++++++++ 
>> ++++++++++
>> ? drivers/hwtracing/coresight/coresight-tpda.h?????? |? 27 ++-
>> ? 3 files changed, 299 insertions(+), 1 deletion(-)
>>
>> diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices- 
>> tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
>> new file mode 100644
>> index 000000000000..80e4b05a1ab4
>> --- /dev/null
>> +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
>> @@ -0,0 +1,43 @@
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/trig_async_enable
>> +Date:??????? October 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Enable/disable cross trigger synchronization sequence 
>> interface.
>> +
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/trig_flag_ts_enable
>> +Date:??????? October 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Enable/disable cross trigger FLAG packet request interface.
>> +
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/trig_freq_enable
>> +Date:??????? October 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Enable/disable cross trigger FREQ packet request interface.
>> +
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/freq_ts_enable
>> +Date:??????? October 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Enable/disable the timestamp for all FREQ packets.
>> +
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/global_flush_req
>> +Date:??????? October 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Set global (all ports) flush request bit. The bit 
>> remains set until a
>> +??????? global flush request sequence completes.
>> +
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/cmbchan_mode
>> +Date:??????? October 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Configure the CMB/MCMB channel mode for all enabled ports.
>> +??????? Value 0 means raw channel mapping mode. Value 1 means channel 
>> pair marking mode.
>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/ 
>> hwtracing/coresight/coresight-tpda.c
>> index 333b3cb23685..a9a27bcc65a1 100644
>> --- a/drivers/hwtracing/coresight/coresight-tpda.c
>> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
>> @@ -147,9 +147,37 @@ static void tpda_enable_pre_port(struct 
>> tpda_drvdata *drvdata)
>> ????? u32 val;
>> ????? val = readl_relaxed(drvdata->base + TPDA_CR);
>> +??? val &= ~TPDA_CR_MID;
>> ????? val &= ~TPDA_CR_ATID;
> 
> See, below.
> 
>> ????? val |= FIELD_PREP(TPDA_CR_ATID, drvdata->atid);
>> +??? if (drvdata->trig_async)
>> +??????? val |= TPDA_CR_SRIE;
>> +??? else
>> +??????? val &= ~TPDA_CR_SRIE;
>> +??? if (drvdata->trig_flag_ts)
>> +??????? val |= TPDA_CR_FLRIE;
>> +??? else
>> +??????? val &= ~TPDA_CR_FLRIE;
>> +??? if (drvdata->trig_freq)
>> +??????? val |= TPDA_CR_FRIE;
>> +??? else
>> +??????? val &= ~TPDA_CR_FRIE;
>> +??? if (drvdata->freq_ts)
>> +??????? val |= TPDA_CR_FREQTS;
>> +??? else
>> +??????? val &= ~TPDA_CR_FREQTS;
>> +??? if (drvdata->cmbchan_mode)
>> +??????? val |= TPDA_CR_CMBCHANMODE;
>> +??? else
>> +??????? val &= ~TPDA_CR_CMBCHANMODE;
> 
> Could we clear all of the bits that are configurable in one go in the
> beginning and set the appropriate ones based on the setting ? i.e.:
> 
> Do we really need to retain any values ? And if not, why not start
> with a fresh set of values and avoid the read ?
> 
>> ????? writel_relaxed(val, drvdata->base + TPDA_CR);
>> +
>> +??? /*
>> +???? * If FLRIE bit is set, set the master and channel
>> +???? * id as zero
>> +???? */
>> +??? if (drvdata->trig_flag_ts)
>> +??????? writel_relaxed(0x0, drvdata->base + TPDA_FPID_CR);
>> ? }
>> ? static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
>> @@ -265,6 +293,206 @@ static const struct coresight_ops tpda_cs_ops = {
>> ????? .link_ops??? = &tpda_link_ops,
>> ? };
>> +static ssize_t trig_async_enable_show(struct device *dev,
>> +????????????????????? struct device_attribute *attr,
>> +????????????????????? char *buf)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +
>> +??? return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_async);
>> +}
>> +
>> +static ssize_t trig_async_enable_store(struct device *dev,
>> +?????????????????????? struct device_attribute *attr,
>> +?????????????????????? const char *buf,
>> +?????????????????????? size_t size)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +??? unsigned long val;
>> +
>> +??? if (kstrtoul(buf, 0, &val))
>> +??????? return -EINVAL;
>> +
>> +??? guard(spinlock)(&drvdata->spinlock);
>> +??? drvdata->trig_async = !!val;
>> +
> 
> 
> 
>> +??? return size;
>> +}
>> +static DEVICE_ATTR_RW(trig_async_enable);
> 
> ...
> 
>> +static DEVICE_ATTR_RW(trig_flag_ts_enable);
> 
> ...
> 
>> +static DEVICE_ATTR_RW(trig_freq_enable);
> 
> ...
>> +static DEVICE_ATTR_RW(freq_ts_enable);
> 
> These attribute are boolean and looks like we could save some space on
> code by using dev_ext_attribute.
> see tpdm_simple_dataset_rw()/tpdm_simple_dataset_ro() . You could
> 
> #define TPDA_TRIG_ASYNC??????? 0
> #define TPDA_TRIG_FLAG_TS???? 1
> #define TPDA_TRIG_FREQ??????? 2
> 
> 
> tpda_trig_sysfs_show/store()
> 
>  ?bool *ptr;
>  ?switch (eattr->var) {
>  ?case TPDA_TRIG_ASYNC:
>  ????ptr = &drvdata->trig_async;
>  ????break;
>  ?case TPDA_TRIG_FLAG_TS:
>  ????ptr = &drvdata->trig_flag_ts;
>  ????break;
> ...
> 
>  ?}
> 
> 
> 

-->8--

Cut here

>> +
>> +static ssize_t global_flush_req_show(struct device *dev,
>> +???????????????????? struct device_attribute *attr,
>> +???????????????????? char *buf)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +??? unsigned long val;
>> +
>> +??? if (!drvdata->csdev->refcnt)
>> +??????? return -EINVAL;
>> +
>> +??? guard(spinlock)(&drvdata->spinlock);
>> +??? CS_UNLOCK(drvdata->base);
>> +??? val = readl_relaxed(drvdata->base + TPDA_CR);
>> +??? CS_LOCK(drvdata->base);
>> +??? /* Only read value for bit 0 */
>> +??? val &= BIT(0);
>> +
>> +??? return sysfs_emit(buf, "%lu\n", val);
>> +}
>> +
>> +static ssize_t global_flush_req_store(struct device *dev,
>> +????????????????????? struct device_attribute *attr,
>> +????????????????????? const char *buf,
>> +????????????????????? size_t size)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +??? unsigned long val;
>> +
>> +??? if (kstrtoul(buf, 0, &val))
>> +??????? return -EINVAL;
>> +
>> +??? if (!drvdata->csdev->refcnt || !val)
>> +??????? return -EINVAL;
>> +
>> +??? guard(spinlock)(&drvdata->spinlock);
>> +??? CS_UNLOCK(drvdata->base);
>> +??? val = readl_relaxed(drvdata->base + TPDA_CR);
>> +??? /* Only set bit 0 */
>> +??? val |= BIT(0);
> 
> What is BIT 0 ? Please document it
> 
>> +??? writel_relaxed(val, drvdata->base + TPDA_CR);
>> +??? CS_LOCK(drvdata->base);
>> +
>> +??? return size;
>> +}

Also this, global_flush_req seems to be a separate change from the rest 
of the additions in the patch. Why not split it into a separate patch
with appropriate description of what this is for ?

Suzuki


From jonathan.cameron at huawei.com  Thu Dec 18 03:30:14 2025
From: jonathan.cameron at huawei.com (Jonathan Cameron)
Date: Thu, 18 Dec 2025 11:30:14 +0000
Subject: [RFC PATCH 07/38] arm_mpam: resctrl: Add boilerplate cpuhp and
 domain allocation
In-Reply-To: <20251205215901.17772-8-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
	<20251205215901.17772-8-james.morse@arm.com>
Message-ID: <20251218113014.00002691@huawei.com>

On Fri, 5 Dec 2025 21:58:30 +0000
James Morse <james.morse at arm.com> wrote:

> resctrl has its own data structures to describe its resources. We
> can't use these directly as we play tricks with the 'MBA' resource,
> picking the MPAM controls or monitors that best apply. We may export
> the same component as both L3 and MBA.
> 
> Add mpam_resctrl_exports[] as the array of class->resctrl mappings we
> are exporting, and add the cpuhp hooks that allocated and free the
> resctrl domain structures.
> 
> While we're here, plumb in a few other obvious things.
> 
> CONFIG_ARM_CPU_RESCTRL is used to allow this code to be built
> even though it can't yet be linked against resctrl.
> 
> Signed-off-by: James Morse <james.morse at arm.com>
Hi,

A few code flow related comments. Fairly trivial stuff but I think
some parts of this can be made more readable / maintainable with
minor reorganization.

Jonathan


> diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
> index 2996ad93fc3e..efaf7633bc35 100644
> --- a/drivers/resctrl/mpam_devices.c
> +++ b/drivers/resctrl/mpam_devices.c
...

> @@ -2516,6 +2522,12 @@ static void mpam_enable_once(void)
>  	mutex_unlock(&mpam_list_lock);
>  	cpus_read_unlock();
>  
> +	if (!err) {
> +		err = mpam_resctrl_setup();
> +		if (err)
> +			pr_err("Failed to initialise resctrl: %d\n", err);
> +	}
> +
>  	if (err) {
>  		mpam_disable_reason = "Failed to enable.";
>  		schedule_work(&mpam_broken_work);

I'd be tempted to move this to an error handling block via a goto
making this bit
	if (err)
		goto err_disable_mpam;

	err = mpam_resctrl_setup();
	if (err) {
		pr_err();
		goto err_dsiable_mpam;
	}

Up to you though. Personally I like all my good paths as straight line
code with the errors handled in if (err) as that consistency really helps
readability.  

> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
> new file mode 100644
> index 000000000000..320cebbd37ce
> --- /dev/null
> +++ b/drivers/resctrl/mpam_resctrl.c
> @@ -0,0 +1,329 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (C) 2025 Arm Ltd.
> +
> +#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__
> +
> +#include <linux/arm_mpam.h>
> +#include <linux/cacheinfo.h>
> +#include <linux/cpu.h>
> +#include <linux/cpumask.h>
> +#include <linux/errno.h>
> +#include <linux/list.h>
> +#include <linux/printk.h>
> +#include <linux/rculist.h>
> +#include <linux/resctrl.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
> +
> +#include <asm/mpam.h>
> +
> +#include "mpam_internal.h"


> +static struct mpam_resctrl_dom *
> +mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
> +{
> +	int err;
> +	struct mpam_resctrl_dom *dom;
> +	struct rdt_mon_domain *mon_d;
> +	struct rdt_ctrl_domain *ctrl_d;
> +	struct mpam_class *class = res->class;
> +	struct mpam_component *comp_iter, *ctrl_comp;
> +	struct rdt_resource *r = &res->resctrl_res;
> +
> +	lockdep_assert_held(&domain_list_lock);
> +
> +	ctrl_comp = NULL;
> +	guard(srcu)(&mpam_srcu);
> +	list_for_each_entry_srcu(comp_iter, &class->components, class_list,
> +				 srcu_read_lock_held(&mpam_srcu)) {
> +		if (cpumask_test_cpu(cpu, &comp_iter->affinity)) {
> +			ctrl_comp = comp_iter;
> +			break;
> +		}
> +	}
> +
> +	/* class has no component for this CPU */
> +	if (WARN_ON_ONCE(!ctrl_comp))
> +		return ERR_PTR(-EINVAL);
> +
> +	dom = kzalloc_node(sizeof(*dom), GFP_KERNEL, cpu_to_node(cpu));
> +	if (!dom)
> +		return ERR_PTR(-ENOMEM);
> +
> +	if (exposed_alloc_capable) {
> +		dom->ctrl_comp = ctrl_comp;
> +
> +		ctrl_d = &dom->resctrl_ctrl_dom;
> +		mpam_resctrl_domain_hdr_init(cpu, ctrl_comp, &ctrl_d->hdr);
> +		ctrl_d->hdr.type = RESCTRL_CTRL_DOMAIN;
> +		/* TODO: this list should be sorted */
> +		list_add_tail_rcu(&ctrl_d->hdr.list, &r->ctrl_domains);
> +		err = resctrl_online_ctrl_domain(r, ctrl_d);
> +		if (err) {
> +			dom = ERR_PTR(err);
> +			goto offline_ctrl_domain;
> +		}
> +	} else {
> +		pr_debug("Skipped control domain online - no controls\n");
> +	}
> +
> +	if (exposed_mon_capable) {
> +		mon_d = &dom->resctrl_mon_dom;
> +		mpam_resctrl_domain_hdr_init(cpu, ctrl_comp, &mon_d->hdr);
> +		mon_d->hdr.type = RESCTRL_MON_DOMAIN;
> +		/* TODO: this list should be sorted */
> +		list_add_tail_rcu(&mon_d->hdr.list, &r->mon_domains);
> +		err = resctrl_online_mon_domain(r, mon_d);
> +		if (err) {
> +			dom = ERR_PTR(err);
> +			goto offline_mon_hdr;
> +		}
> +	} else {
> +		pr_debug("Skipped monitor domain online - no monitors\n");
> +	}
> +	goto out;

To keep flow simple, return here.  I thought maybe there was more stuff
that was always done (added in later patches) but not seeing that.
If there were then it would be a fairly strong indicator that a different
code structure makes more sense - probably with some helper functions.

> +
> +offline_mon_hdr:
> +	mpam_resctrl_offline_domain_hdr(cpu, &mon_d->hdr);
> +offline_ctrl_domain:
> +	resctrl_offline_ctrl_domain(r, ctrl_d);
> +out:
> +	return dom;
> +}
> +
> +static struct mpam_resctrl_dom *
> +mpam_resctrl_get_domain_from_cpu(int cpu, struct mpam_resctrl_res *res)
> +{
> +	struct mpam_resctrl_dom *dom;
> +	struct rdt_ctrl_domain *ctrl_d;
> +
> +	lockdep_assert_cpus_held();
> +
> +	list_for_each_entry_rcu(ctrl_d, &res->resctrl_res.ctrl_domains,
> +				hdr.list) {
> +		dom = container_of(ctrl_d, struct mpam_resctrl_dom,
> +				   resctrl_ctrl_dom);

I'm lazy so haven't checked for more code here in later patches, but
if not, why not iterate the list to access the domain directly rather
than jumping through the rdt_ctrl_domain?

Something along lines of:
	
	list_for_each_entry_rcu(dom, &res->resctrl_res.ctrl_domains,
				resctrl_ctrl_dom.hdr.list) {
	}

> +
> +		if (cpumask_test_cpu(cpu, &dom->ctrl_comp->affinity))
> +			return dom;
> +	}
> +
> +	return NULL;
> +}
> +
> +int mpam_resctrl_online_cpu(unsigned int cpu)
> +{
> +	int i;
> +	struct mpam_resctrl_dom *dom;
> +	struct mpam_resctrl_res *res;
> +
> +	guard(mutex)(&domain_list_lock);
> +	for (i = 0; i < RDT_NUM_RESOURCES; i++) {

I'd narrow the scope for dom and res to inside the loop.
Maybe put the iterator in the for loop init (now considered
acceptable in kernel code)

Similar applies in various other places.  No that important
for functions that more or less just consist of a loop though.

> +		res = &mpam_resctrl_controls[i];
> +		if (!res->class)
> +			continue;	// dummy_resource;
> +
> +		dom = mpam_resctrl_get_domain_from_cpu(cpu, res);
> +		if (!dom)
> +			dom = mpam_resctrl_alloc_domain(cpu, res);
> +		if (IS_ERR(dom))
> +			return PTR_ERR(dom);
> +	}
> +
> +	resctrl_online_cpu(cpu);
> +
> +	return 0;
> +}

> +int mpam_resctrl_setup(void)
> +{
> +	int err = 0;
> +	enum resctrl_res_level i;
> +	struct mpam_resctrl_res *res;
> +
> +	cpus_read_lock();
> +	for (i = 0; i < RDT_NUM_RESOURCES; i++) {
> +		res = &mpam_resctrl_controls[i];
> +		INIT_LIST_HEAD_RCU(&res->resctrl_res.ctrl_domains);
> +		INIT_LIST_HEAD_RCU(&res->resctrl_res.mon_domains);
> +		res->resctrl_res.rid = i;
> +	}
> +
> +	/* TODO: pick MPAM classes to map to resctrl resources */
> +
> +	/* Initialise the resctrl structures from the classes */
> +	for (i = 0; i < RDT_NUM_RESOURCES; i++) {
> +		res = &mpam_resctrl_controls[i];
> +		if (!res->class)
> +			continue;	// dummy resource
> +
> +		err = mpam_resctrl_control_init(res, i);
> +		if (err) {
> +			pr_debug("Failed to initialise rid %u\n", i);
> +			break;
> +		}
> +	}
> +	cpus_read_unlock();
> +
> +	if (err || (!exposed_alloc_capable && !exposed_mon_capable)) {
> +		if (err)
> +			pr_debug("Internal error %d - resctrl not supported\n",
> +				 err);
> +		else
> +			pr_debug("No alloc(%u) or monitor(%u) found - resctrl not supported\n",
> +				 exposed_alloc_capable, exposed_mon_capable);
> +		err = -EOPNOTSUPP;

return -EOPNOTSUPP; here to make the code flow simpler.
Mind you nice to avoid eating err if it is set and the sharing here doesn't seem
all that useful so perhaps just make this:

	if (err) {
		pr_debug("Internal error %d - resctrl not supported\n", err);
		return err;
	}

	if (!exposed_alloc_capable && !exposed_mon_capable) {
		pr_debug("No alloc(%u) or monitor(%u) found - resctrl not supported\n",
			 exposed_alloc_capable, exposed_mon_capable);
		return -EOPNOTSUPP;
	}


> +	}
> +
> +	if (!err) {
> +		if (!is_power_of_2(mpam_pmg_max + 1)) {
> +			/*
> +			 * If not all the partid*pmg values are valid indexes,
> +			 * resctrl may allocate pmg that don't exist. This
> +			 * should cause an error interrupt.
> +			 */
> +			pr_warn("Number of PMG is not a power of 2! resctrl may misbehave");
> +		}
> +
> +		/* TODO: call resctrl_init() */
> +	}
> +
> +	return err;
> +}


From sudeep.holla at arm.com  Thu Dec 18 03:33:05 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Thu, 18 Dec 2025 11:33:05 +0000
Subject: [PATCH v2 00/12] coresight: Add CPU cluster
 funnel/replicator/tmc support
In-Reply-To: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
References: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
Message-ID: <20251218-careful-ruby-wildebeest-a8babd@sudeepholla>

On Thu, Dec 18, 2025 at 12:09:40AM -0800, Yuanfang Zhang wrote:
> This patch series adds support for CoreSight components local to CPU clusters,
> including funnel, replicator, and TMC, which reside within CPU cluster power
> domains. These components require special handling due to power domain
> constraints.
> 

Could you clarify why PSCI-based power domains associated with clusters in
domain-idle-states cannot address these requirements, given that PSCI CPU-idle
OSI mode was originally intended to support them? My understanding of this
patch series is that OSI mode is unable to do so, which, if accurate, appears
to be a flaw that should be corrected.

> Unlike system-level CoreSight devices, these components share the CPU cluster's
> power domain. When the cluster enters low-power mode (LPM), their registers
> become inaccessible. Notably, `pm_runtime_get` alone cannot bring the cluster
> out of LPM, making standard register access unreliable.
> 

Are these devices the only ones on the system that are uniquely bound to
cluster-level power domains? If not, what additional devices share this
dependency so that we can understand how they are managed in comparison?

> To address this, the series introduces:
> - Identifying cluster-bound devices via a new `qcom,cpu-bound-components`
>   device tree property.

Really, no please.

-- 
Regards,
Sudeep


From sudeep.holla at arm.com  Thu Dec 18 03:37:10 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Thu, 18 Dec 2025 11:37:10 +0000
Subject: [PATCH v2 01/12] dt-bindings: arm: coresight: Add
 'qcom,cpu-bound-components' property
In-Reply-To: <20251218-cpu_cluster_component_pm-v2-1-2335a6ae62a0@oss.qualcomm.com>
References: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
 <20251218-cpu_cluster_component_pm-v2-1-2335a6ae62a0@oss.qualcomm.com>
Message-ID: <20251218-silky-skylark-of-purring-20faa5@sudeepholla>

On Thu, Dec 18, 2025 at 12:09:41AM -0800, Yuanfang Zhang wrote:
> Introduce the `qcom,cpu-bound-components` boolean property for CoreSight
> components (TMC, Funnel, and Replicator).
> 
> This property indicates that the component is physically located within a
> CPU cluster power domain. Such components share the power state of the
> cluster and may require special handling (e.g., cross-CPU register
> access) compared to system-wide components.
> 

NACK, and the rationale expressed as a question:

If unique compatibles were required to determine the power domains to which
devices belong, we would have accumulated numerous additional compatibles for
every IP block used on new systems with even slightly different power-domain
configurations?a scenario that occurs frequently. Why, then, is such a
requirement considered necessary in this case?

-- 
Regards,
Sudeep


From jonathan.cameron at huawei.com  Thu Dec 18 03:38:15 2025
From: jonathan.cameron at huawei.com (Jonathan Cameron)
Date: Thu, 18 Dec 2025 11:38:15 +0000
Subject: [RFC PATCH 08/38] arm_mpam: resctrl: Pick the caches we will
 use as resctrl resources
In-Reply-To: <20251205215901.17772-9-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
	<20251205215901.17772-9-james.morse@arm.com>
Message-ID: <20251218113815.000055e7@huawei.com>

On Fri, 5 Dec 2025 21:58:31 +0000
James Morse <james.morse at arm.com> wrote:

> Systems with MPAM support may have a variety of control types at any
> point of their system layout. We can only expose certain types of
> control, and only if they exist at particular locations.
> 
> Start with the well-know caches. These have to be depth 2 or 3
> and support MPAM's cache portion bitmap controls, with a number
> of portions fewer than resctrl's limit.

Another one that is a bit random on wrap point.  Probably worth tidying
up formatting of all the commit messages so fussy people like me stop
moaning ;)

Otherwise trivial stuff inline.
> 
> Signed-off-by: James Morse <james.morse at arm.com>
> ---
>  drivers/resctrl/mpam_resctrl.c | 91 +++++++++++++++++++++++++++++++++-
>  1 file changed, 89 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
> index 320cebbd37ce..ceaf11af4fc1 100644
> --- a/drivers/resctrl/mpam_resctrl.c
> +++ b/drivers/resctrl/mpam_resctrl.c
> @@ -60,10 +60,96 @@ struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l)
>  	return &mpam_resctrl_controls[l].resctrl_res;
>  }
>  
> +static bool cache_has_usable_cpor(struct mpam_class *class)
> +{
> +	struct mpam_props *cprops = &class->props;
> +
> +	if (!mpam_has_feature(mpam_feat_cpor_part, cprops))
> +		return false;
> +
> +	/* resctrl uses u32 for all bitmap configurations */
> +	return (class->props.cpbm_wd <= 32);

For me those brackets aren't adding anything. It's not like
anyone forgets precedence wrt return vs operators.

> +}
> +
> +/* Test whether we can export MPAM_CLASS_CACHE:{2,3}? */
> +static void mpam_resctrl_pick_caches(void)
> +{
> +	struct mpam_class *class;
> +	struct mpam_resctrl_res *res;
> +
> +	lockdep_assert_cpus_held();
> +
> +	guard(srcu)(&mpam_srcu);
> +	list_for_each_entry_srcu(class, &mpam_classes, classes_list,
> +				 srcu_read_lock_held(&mpam_srcu)) {
> +		if (class->type != MPAM_CLASS_CACHE) {
> +			pr_debug("class %u is not a cache\n", class->level);

Lots of things aren't caches and seems unlikely that is a case that will
make people wonder why pick caches didn't happen. So maybe this debug
print is excessive?

> +			continue;
> +		}
> +
> +		if (class->level != 2 && class->level != 3) {
> +			pr_debug("class %u is not L2 or L3\n", class->level);
> +			continue;
> +		}
> +
> +		if (!cache_has_usable_cpor(class)) {
> +			pr_debug("class %u cache misses CPOR\n", class->level);
> +			continue;
> +		}
> +
> +		if (!cpumask_equal(&class->affinity, cpu_possible_mask)) {
> +			pr_debug("class %u has missing CPUs\n", class->level);
> +			pr_debug("class %u mask %*pb != %*pb\n", class->level,
> +				 cpumask_pr_args(&class->affinity),
> +				 cpumask_pr_args(cpu_possible_mask));

Unless this is getting more complex in later patches, doesn't seem like
			pr_debug("class %u has missing CPUs, mask %*pb != %*pb\n",
is too much to put on one line.

					 
> +			continue;
> +		}
> +
> +		if (class->level == 2)
> +			res = &mpam_resctrl_controls[RDT_RESOURCE_L2];
> +		else
> +			res = &mpam_resctrl_controls[RDT_RESOURCE_L3];
> +		res->class = class;
> +		exposed_alloc_capable = true;
> +	}
> +}
> +
>  static int mpam_resctrl_control_init(struct mpam_resctrl_res *res,
>  				     enum resctrl_res_level type)
>  {
> -	/* TODO: initialise the resctrl resources */
> +	struct mpam_class *class = res->class;
> +	struct rdt_resource *r = &res->resctrl_res;
> +
> +	switch (res->resctrl_res.rid) {

	switch (r->rid) { ?

> +	case RDT_RESOURCE_L2:
> +	case RDT_RESOURCE_L3:
> +		r->alloc_capable = true;
> +		r->schema_fmt = RESCTRL_SCHEMA_BITMAP;
> +		r->cache.arch_has_sparse_bitmasks = true;
> +
> +		r->cache.cbm_len = class->props.cpbm_wd;
> +		/* mpam_devices will reject empty bitmaps */
> +		r->cache.min_cbm_bits = 1;
> +
> +		if (r->rid == RDT_RESOURCE_L2) {
> +			r->name = "L2";
> +			r->ctrl_scope = RESCTRL_L2_CACHE;
> +		} else {
> +			r->name = "L3";
> +			r->ctrl_scope = RESCTRL_L3_CACHE;
> +		}
> +
> +		/*
> +		 * Which bits are shared with other ...things...
> +		 * Unknown devices use partid-0 which uses all the bitmap
> +		 * fields. Until we configured the SMMU and GIC not to do this
> +		 * 'all the bits' is the correct answer here.
> +		 */
> +		r->cache.shareable_bits = resctrl_get_default_ctrl(r);
> +		break;
> +	default:
> +		break;
> +	}
>  
>  	return 0;
>  }
> @@ -286,7 +372,8 @@ int mpam_resctrl_setup(void)
>  		res->resctrl_res.rid = i;
>  	}
>  
> -	/* TODO: pick MPAM classes to map to resctrl resources */
> +	/* Find some classes to use for controls */
> +	mpam_resctrl_pick_caches();
>  
>  	/* Initialise the resctrl structures from the classes */
>  	for (i = 0; i < RDT_NUM_RESOURCES; i++) {



From f.pflug at pengutronix.de  Thu Dec 18 03:39:21 2025
From: f.pflug at pengutronix.de (Fabian Pflug)
Date: Thu, 18 Dec 2025 12:39:21 +0100
Subject: [PATCH v4 1/2] dt-bindings: arm: fsl: add i.MX93 11x11 FRDM board
In-Reply-To: <20251218-fpg-nxp-imx93-frdm-v4-0-cd3a9f6ac89a@pengutronix.de>
References: <20251218-fpg-nxp-imx93-frdm-v4-0-cd3a9f6ac89a@pengutronix.de>
Message-ID: <20251218-fpg-nxp-imx93-frdm-v4-1-cd3a9f6ac89a@pengutronix.de>

Add DT compatible string for NXP i.MX93 11x11 FRDM board.

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
Reviewed-by: Daniel Baluta <daniel.baluta at nxp.com>
Signed-off-by: Fabian Pflug <f.pflug at pengutronix.de>
---
 Documentation/devicetree/bindings/arm/fsl.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
index 68a2d5fecc43b..eab81799b0793 100644
--- a/Documentation/devicetree/bindings/arm/fsl.yaml
+++ b/Documentation/devicetree/bindings/arm/fsl.yaml
@@ -1419,6 +1419,7 @@ properties:
           - enum:
               - fsl,imx93-9x9-qsb         # i.MX93 9x9 QSB Board
               - fsl,imx93-11x11-evk       # i.MX93 11x11 EVK Board
+              - fsl,imx93-11x11-frdm      # i.MX93 11x11 FRDM Board
               - fsl,imx93-14x14-evk       # i.MX93 14x14 EVK Board
           - const: fsl,imx93
 

-- 
2.47.3



From f.pflug at pengutronix.de  Thu Dec 18 03:39:22 2025
From: f.pflug at pengutronix.de (Fabian Pflug)
Date: Thu, 18 Dec 2025 12:39:22 +0100
Subject: [PATCH v4 2/2] arm64: dts: freescale: add support for NXP i.MX93
 FRDM
In-Reply-To: <20251218-fpg-nxp-imx93-frdm-v4-0-cd3a9f6ac89a@pengutronix.de>
References: <20251218-fpg-nxp-imx93-frdm-v4-0-cd3a9f6ac89a@pengutronix.de>
Message-ID: <20251218-fpg-nxp-imx93-frdm-v4-2-cd3a9f6ac89a@pengutronix.de>

The FRDM i.MX 93 development board is a low-cost and compact development
board featuring the i.MX93 applications processor.

It features:
- Dual Cortex-A55
- 2 GB LPDDR4X / LPDDR4
- 32 GB eMMC5.1
- MicroSD slot
- GbE RJ45 x 2
- USB2.0 1x Type C, 1x Type A

This file is based upon the one provided by nxp in their own kernel and
yocto meta layer for the device, but adapted for mainline.

Signed-off-by: Haidong Zheng <haidong.zheng at nxp.com>
Signed-off-by: Danwei Luo <danwei.luo at nxp.com>
Signed-off-by: Lei Xu <lei.xu at nxp.com>
Signed-off-by: Fabian Pflug <f.pflug at pengutronix.de>
---
 arch/arm64/boot/dts/freescale/Makefile             |   1 +
 arch/arm64/boot/dts/freescale/imx93-11x11-frdm.dts | 620 +++++++++++++++++++++
 2 files changed, 621 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index f30d3fd724d0c..c08e23545d4b6 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -376,6 +376,7 @@ imx93-9x9-qsb-i3c-dtbs += imx93-9x9-qsb.dtb imx93-9x9-qsb-i3c.dtbo
 dtb-$(CONFIG_ARCH_MXC) += imx93-9x9-qsb-i3c.dtb
 
 dtb-$(CONFIG_ARCH_MXC) += imx93-11x11-evk.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx93-11x11-frdm.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx93-14x14-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx93-kontron-bl-osm-s.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx93-phyboard-nash.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-frdm.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-frdm.dts
new file mode 100644
index 0000000000000..066c5139842bd
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx93-11x11-frdm.dts
@@ -0,0 +1,620 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/dts-v1/;
+
+#include <dt-bindings/usb/pd.h>
+#include "imx93.dtsi"
+
+/ {
+	compatible = "fsl,imx93-11x11-frdm", "fsl,imx93";
+	model = "NXP i.MX93 11X11 FRDM board";
+
+	aliases {
+		ethernet0 = &fec;
+		ethernet1 = &eqos;
+		i2c0 = &lpi2c1;
+		i2c1 = &lpi2c2;
+		i2c2 = &lpi2c3;
+		mmc0 = &usdhc1; /* EMMC */
+		mmc1 = &usdhc2; /* uSD */
+		rtc0 = &pcf2131;
+		serial0 = &lpuart1;
+	};
+
+	chosen {
+		stdout-path = &lpuart1;
+	};
+
+	reg_usdhc2_vmmc: regulator-usdhc2 {
+		compatible = "regulator-fixed";
+		off-on-delay-us = <12000>;
+		pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
+		pinctrl-names = "default";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-name = "VSD_3V3";
+		vin-supply = <&buck4>;
+		gpio = <&gpio3 7 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reserved-memory {
+		ranges;
+		#address-cells = <2>;
+		#size-cells = <2>;
+
+		linux,cma {
+			compatible = "shared-dma-pool";
+			alloc-ranges = <0 0x80000000 0 0x30000000>;
+			reusable;
+			size = <0 0x10000000>;
+			linux,cma-default;
+		};
+
+		rsc_table: rsc-table at 2021e000 {
+			reg = <0 0x2021e000 0 0x1000>;
+			no-map;
+		};
+
+		vdev0vring0: vdev0vring0 at a4000000 {
+			reg = <0 0xa4000000 0 0x8000>;
+			no-map;
+		};
+
+		vdev0vring1: vdev0vring1 at a4008000 {
+			reg = <0 0xa4008000 0 0x8000>;
+			no-map;
+		};
+
+		vdev1vring0: vdev1vring0 at a4010000 {
+			reg = <0 0xa4010000 0 0x8000>;
+			no-map;
+		};
+
+		vdev1vring1: vdev1vring1 at a4018000 {
+			reg = <0 0xa4018000 0 0x8000>;
+			no-map;
+		};
+
+		vdevbuffer: vdevbuffer at a4020000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0xa4020000 0 0x100000>;
+			no-map;
+		};
+	};
+};
+
+&adc1 {
+	vref-supply = <&buck5>;
+	status = "okay";
+};
+
+&mu1 {
+	status = "okay";
+};
+
+&cm33 {
+	mboxes = <&mu1 0 1>,
+		 <&mu1 1 1>,
+		 <&mu1 3 1>;
+	mbox-names = "tx", "rx", "rxdb";
+	memory-region = <&vdevbuffer>, <&vdev0vring0>, <&vdev0vring1>,
+			<&vdev1vring0>, <&vdev1vring1>, <&rsc_table>;
+	status = "okay";
+};
+
+&eqos {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&pinctrl_eqos>;
+	pinctrl-1 = <&pinctrl_eqos_sleep>;
+	phy-handle = <&ethphy1>;
+	phy-mode = "rgmii-id";
+	status = "okay";
+
+	mdio {
+		compatible = "snps,dwmac-mdio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-frequency = <5000000>;
+
+		ethphy1: ethernet-phy at 1 {
+			reg = <1>;
+			reset-assert-us = <10000>;
+			reset-deassert-us = <80000>;
+			reset-gpios = <&pcal6524 15 GPIO_ACTIVE_LOW>;
+			realtek,clkout-disable;
+		};
+	};
+};
+
+&fec {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&pinctrl_fec>;
+	pinctrl-1 = <&pinctrl_fec_sleep>;
+	phy-mode = "rgmii-id";
+	phy-handle = <&ethphy2>;
+	fsl,magic-packet;
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-frequency = <5000000>;
+
+		ethphy2: ethernet-phy at 2 {
+			reg = <2>;
+			reset-assert-us = <10000>;
+			reset-deassert-us = <80000>;
+			reset-gpios = <&pcal6524 16 GPIO_ACTIVE_LOW>;
+			realtek,clkout-disable;
+		};
+	};
+};
+
+&lpi2c1 {
+	clock-frequency = <400000>;
+	pinctrl-0 = <&pinctrl_lpi2c1>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&lpi2c2 {
+	clock-frequency = <400000>;
+	pinctrl-0 = <&pinctrl_lpi2c2>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	pcal6524: gpio at 22 {
+		compatible = "nxp,pcal6524";
+		reg = <0x22>;
+		#interrupt-cells = <2>;
+		interrupt-controller;
+		interrupt-parent = <&gpio3>;
+		interrupts = <27 IRQ_TYPE_LEVEL_LOW>;
+		#gpio-cells = <2>;
+		gpio-controller;
+		pinctrl-0 = <&pinctrl_pcal6524>;
+		pinctrl-names = "default";
+		/* does not boot with supplier set, because it is the bucks interrupt parent */
+		/* vcc-supply = <&buck4>; */
+	};
+
+	pmic at 25 {
+		compatible = "nxp,pca9451a";
+		reg = <0x25>;
+		interrupt-parent = <&pcal6524>;
+		interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
+
+		regulators {
+
+			buck1: BUCK1 {
+				regulator-name = "VDD_SOC_0V8";
+				regulator-min-microvolt = <610000>;
+				regulator-max-microvolt = <950000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-ramp-delay = <3125>;
+			};
+
+			buck2: BUCK2 {
+				regulator-name = "LPD4_x_VDDQ_0V6";
+				regulator-min-microvolt = <600000>;
+				regulator-max-microvolt = <670000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-ramp-delay = <3125>;
+			};
+
+			buck4: BUCK4 {
+				regulator-name = "VDD_3V3";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			buck5: BUCK5 {
+				regulator-name = "VDD_1V8";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			buck6: BUCK6 {
+				regulator-name = "LPD4_x_VDD2_1V1";
+				regulator-min-microvolt = <1060000>;
+				regulator-max-microvolt = <1140000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			ldo1: LDO1 {
+				regulator-name = "NVCC_BBSM_1V8";
+				regulator-min-microvolt = <1620000>;
+				regulator-max-microvolt = <1980000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			ldo4: LDO4 {
+				regulator-name = "VDD_ANA_0V8";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <840000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			ldo5: LDO5 {
+				regulator-name = "NVCC_SD";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+		};
+	};
+
+	eeprom: eeprom at 50 {
+		compatible = "atmel,24c256";
+		reg = <0x50>;
+		pagesize = <64>;
+		vcc-supply = <&buck4>;
+	};
+};
+
+&lpi2c3 {
+	clock-frequency = <400000>;
+	pinctrl-0 = <&pinctrl_lpi2c3>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	ptn5110: tcpc at 50 {
+		compatible = "nxp,ptn5110", "tcpci";
+		reg = <0x50>;
+		interrupt-parent = <&gpio3>;
+		interrupts = <27 IRQ_TYPE_LEVEL_LOW>;
+
+		typec1_con: connector {
+			compatible = "usb-c-connector";
+			data-role = "dual";
+			label = "USB-C";
+			op-sink-microwatt = <15000000>;
+			power-role = "dual";
+			self-powered;
+			sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)
+					PDO_VAR(5000, 20000, 3000)>;
+			source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
+			try-power-role = "sink";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+
+					typec1_dr_sw: endpoint {
+						remote-endpoint = <&usb1_drd_sw>;
+					};
+				};
+			};
+		};
+	};
+
+	pcf2131: rtc at 53 {
+		compatible = "nxp,pcf2131";
+		reg = <0x53>;
+		interrupt-parent = <&pcal6524>;
+		interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
+	};
+};
+
+&lpuart1 { /* console */
+	pinctrl-0 = <&pinctrl_uart1>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&usbotg1 {
+	adp-disable;
+	disable-over-current;
+	dr_mode = "otg";
+	hnp-disable;
+	srp-disable;
+	usb-role-switch;
+	samsung,picophy-dc-vol-level-adjust = <7>;
+	samsung,picophy-pre-emp-curr-control = <3>;
+	status = "okay";
+
+	port {
+		usb1_drd_sw: endpoint {
+			remote-endpoint = <&typec1_dr_sw>;
+		};
+	};
+};
+
+&usbotg2 {
+	disable-over-current;
+	dr_mode = "host";
+	samsung,picophy-dc-vol-level-adjust = <7>;
+	samsung,picophy-pre-emp-curr-control = <3>;
+	status = "okay";
+};
+
+&usdhc1 {
+	bus-width = <8>;
+	non-removable;
+	pinctrl-0 = <&pinctrl_usdhc1>;
+	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	vmmc-supply = <&buck4>;
+	status = "okay";
+};
+
+&usdhc2 {
+	bus-width = <4>;
+	cd-gpios = <&gpio3 00 GPIO_ACTIVE_LOW>;
+	no-mmc;
+	no-sdio;
+	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-3 = <&pinctrl_usdhc2_sleep>, <&pinctrl_usdhc2_gpio_sleep>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	status = "okay";
+};
+
+&wdog3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_wdog>;
+	fsl,ext-reset-output;
+	status = "okay";
+};
+
+&iomuxc {
+
+	pinctrl_eqos: eqosgrp {
+		fsl,pins = <
+			MX93_PAD_ENET1_MDC__ENET_QOS_MDC			0x57e
+			MX93_PAD_ENET1_MDIO__ENET_QOS_MDIO			0x57e
+			MX93_PAD_ENET1_RD0__ENET_QOS_RGMII_RD0			0x57e
+			MX93_PAD_ENET1_RD1__ENET_QOS_RGMII_RD1			0x57e
+			MX93_PAD_ENET1_RD2__ENET_QOS_RGMII_RD2			0x57e
+			MX93_PAD_ENET1_RD3__ENET_QOS_RGMII_RD3			0x57e
+			MX93_PAD_ENET1_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK	0x58e
+			MX93_PAD_ENET1_RX_CTL__ENET_QOS_RGMII_RX_CTL		0x57e
+			MX93_PAD_ENET1_TD0__ENET_QOS_RGMII_TD0			0x57e
+			MX93_PAD_ENET1_TD1__ENET_QOS_RGMII_TD1			0x57e
+			MX93_PAD_ENET1_TD2__ENET_QOS_RGMII_TD2			0x57e
+			MX93_PAD_ENET1_TD3__ENET_QOS_RGMII_TD3			0x57e
+			MX93_PAD_ENET1_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK	0x58e
+			MX93_PAD_ENET1_TX_CTL__ENET_QOS_RGMII_TX_CTL		0x57e
+		>;
+	};
+
+	pinctrl_eqos_sleep: eqossleepgrp {
+		fsl,pins = <
+			MX93_PAD_ENET1_MDC__GPIO4_IO00			0x31e
+			MX93_PAD_ENET1_MDIO__GPIO4_IO01			0x31e
+			MX93_PAD_ENET1_RD0__GPIO4_IO10			0x31e
+			MX93_PAD_ENET1_RD1__GPIO4_IO11			0x31e
+			MX93_PAD_ENET1_RD2__GPIO4_IO12			0x31e
+			MX93_PAD_ENET1_RD3__GPIO4_IO13			0x31e
+			MX93_PAD_ENET1_RXC__GPIO4_IO09			0x31e
+			MX93_PAD_ENET1_RX_CTL__GPIO4_IO08		0x31e
+			MX93_PAD_ENET1_TD0__GPIO4_IO05			0x31e
+			MX93_PAD_ENET1_TD1__GPIO4_IO04			0x31e
+			MX93_PAD_ENET1_TD2__GPIO4_IO03			0x31e
+			MX93_PAD_ENET1_TD3__GPIO4_IO02			0x31e
+			MX93_PAD_ENET1_TXC__GPIO4_IO07			0x31e
+			MX93_PAD_ENET1_TX_CTL__GPIO4_IO06		0x31e
+		>;
+	};
+
+	pinctrl_fec: fecgrp {
+		fsl,pins = <
+			MX93_PAD_ENET2_MDC__ENET1_MDC			0x57e
+			MX93_PAD_ENET2_MDIO__ENET1_MDIO			0x57e
+			MX93_PAD_ENET2_RD0__ENET1_RGMII_RD0		0x57e
+			MX93_PAD_ENET2_RD1__ENET1_RGMII_RD1		0x57e
+			MX93_PAD_ENET2_RD2__ENET1_RGMII_RD2		0x57e
+			MX93_PAD_ENET2_RD3__ENET1_RGMII_RD3		0x57e
+			MX93_PAD_ENET2_RXC__ENET1_RGMII_RXC		0x58e
+			MX93_PAD_ENET2_RX_CTL__ENET1_RGMII_RX_CTL	0x57e
+			MX93_PAD_ENET2_TD0__ENET1_RGMII_TD0		0x57e
+			MX93_PAD_ENET2_TD1__ENET1_RGMII_TD1		0x57e
+			MX93_PAD_ENET2_TD2__ENET1_RGMII_TD2		0x57e
+			MX93_PAD_ENET2_TD3__ENET1_RGMII_TD3		0x57e
+			MX93_PAD_ENET2_TXC__ENET1_RGMII_TXC		0x58e
+			MX93_PAD_ENET2_TX_CTL__ENET1_RGMII_TX_CTL	0x57e
+		>;
+	};
+
+	pinctrl_fec_sleep: fecsleepgrp {
+		fsl,pins = <
+			MX93_PAD_ENET2_MDC__GPIO4_IO14			0x51e
+			MX93_PAD_ENET2_MDIO__GPIO4_IO15			0x51e
+			MX93_PAD_ENET2_RD0__GPIO4_IO24			0x51e
+			MX93_PAD_ENET2_RD1__GPIO4_IO25			0x51e
+			MX93_PAD_ENET2_RD2__GPIO4_IO26			0x51e
+			MX93_PAD_ENET2_RD3__GPIO4_IO27			0x51e
+			MX93_PAD_ENET2_RXC__GPIO4_IO23			0x51e
+			MX93_PAD_ENET2_RX_CTL__GPIO4_IO22		0x51e
+			MX93_PAD_ENET2_TD0__GPIO4_IO19			0x51e
+			MX93_PAD_ENET2_TD1__GPIO4_IO18			0x51e
+			MX93_PAD_ENET2_TD2__GPIO4_IO17			0x51e
+			MX93_PAD_ENET2_TD3__GPIO4_IO16			0x51e
+			MX93_PAD_ENET2_TXC__GPIO4_IO21			0x51e
+			MX93_PAD_ENET2_TX_CTL__GPIO4_IO20		0x51e
+		>;
+	};
+
+	pinctrl_flexcan2: flexcan2grp {
+		fsl,pins = <
+			MX93_PAD_GPIO_IO25__CAN2_TX			0x139e
+			MX93_PAD_GPIO_IO27__CAN2_RX			0x139e
+		>;
+	};
+
+	pinctrl_lpi2c1: lpi2c1grp {
+		fsl,pins = <
+			MX93_PAD_I2C1_SCL__LPI2C1_SCL			0x40000b9e
+			MX93_PAD_I2C1_SDA__LPI2C1_SDA			0x40000b9e
+		>;
+	};
+
+	pinctrl_lpi2c2: lpi2c2grp {
+		fsl,pins = <
+			MX93_PAD_I2C2_SCL__LPI2C2_SCL			0x40000b9e
+			MX93_PAD_I2C2_SDA__LPI2C2_SDA			0x40000b9e
+		>;
+	};
+
+	pinctrl_lpi2c3: lpi2c3grp {
+		fsl,pins = <
+			MX93_PAD_GPIO_IO28__LPI2C3_SDA			0x40000b9e
+			MX93_PAD_GPIO_IO29__LPI2C3_SCL			0x40000b9e
+		>;
+	};
+
+	pinctrl_pcal6524: pcal6524grp {
+		fsl,pins = <
+			MX93_PAD_CCM_CLKO2__GPIO3_IO27			0x31e
+		>;
+	};
+
+	pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
+		fsl,pins = <
+			MX93_PAD_SD2_RESET_B__GPIO3_IO07		0x31e
+		>;
+	};
+
+	pinctrl_uart1: uart1grp {
+		fsl,pins = <
+			MX93_PAD_UART1_RXD__LPUART1_RX			0x31e
+			MX93_PAD_UART1_TXD__LPUART1_TX			0x31e
+		>;
+	};
+
+	/* need to config the SION for data and cmd pad, refer to ERR052021 */
+	pinctrl_usdhc1: usdhc1grp {
+		fsl,pins = <
+			MX93_PAD_SD1_CLK__USDHC1_CLK		0x1582
+			MX93_PAD_SD1_CMD__USDHC1_CMD		0x40001382
+			MX93_PAD_SD1_DATA0__USDHC1_DATA0	0x40001382
+			MX93_PAD_SD1_DATA1__USDHC1_DATA1	0x40001382
+			MX93_PAD_SD1_DATA2__USDHC1_DATA2	0x40001382
+			MX93_PAD_SD1_DATA3__USDHC1_DATA3	0x40001382
+			MX93_PAD_SD1_DATA4__USDHC1_DATA4	0x40001382
+			MX93_PAD_SD1_DATA5__USDHC1_DATA5	0x40001382
+			MX93_PAD_SD1_DATA6__USDHC1_DATA6	0x40001382
+			MX93_PAD_SD1_DATA7__USDHC1_DATA7	0x40001382
+			MX93_PAD_SD1_STROBE__USDHC1_STROBE	0x1582
+		>;
+	};
+
+	/* need to config the SION for data and cmd pad, refer to ERR052021 */
+	pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp {
+		fsl,pins = <
+			MX93_PAD_SD1_CLK__USDHC1_CLK		0x158e
+			MX93_PAD_SD1_CMD__USDHC1_CMD		0x4000138e
+			MX93_PAD_SD1_DATA0__USDHC1_DATA0	0x4000138e
+			MX93_PAD_SD1_DATA1__USDHC1_DATA1	0x4000138e
+			MX93_PAD_SD1_DATA2__USDHC1_DATA2	0x4000138e
+			MX93_PAD_SD1_DATA3__USDHC1_DATA3	0x4000138e
+			MX93_PAD_SD1_DATA4__USDHC1_DATA4	0x4000138e
+			MX93_PAD_SD1_DATA5__USDHC1_DATA5	0x4000138e
+			MX93_PAD_SD1_DATA6__USDHC1_DATA6	0x4000138e
+			MX93_PAD_SD1_DATA7__USDHC1_DATA7	0x4000138e
+			MX93_PAD_SD1_STROBE__USDHC1_STROBE	0x158e
+		>;
+	};
+
+	/* need to config the SION for data and cmd pad, refer to ERR052021 */
+	pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp {
+		fsl,pins = <
+			MX93_PAD_SD1_CLK__USDHC1_CLK		0x15fe
+			MX93_PAD_SD1_CMD__USDHC1_CMD		0x400013fe
+			MX93_PAD_SD1_DATA0__USDHC1_DATA0	0x400013fe
+			MX93_PAD_SD1_DATA1__USDHC1_DATA1	0x400013fe
+			MX93_PAD_SD1_DATA2__USDHC1_DATA2	0x400013fe
+			MX93_PAD_SD1_DATA3__USDHC1_DATA3	0x400013fe
+			MX93_PAD_SD1_DATA4__USDHC1_DATA4	0x400013fe
+			MX93_PAD_SD1_DATA5__USDHC1_DATA5	0x400013fe
+			MX93_PAD_SD1_DATA6__USDHC1_DATA6	0x400013fe
+			MX93_PAD_SD1_DATA7__USDHC1_DATA7	0x400013fe
+			MX93_PAD_SD1_STROBE__USDHC1_STROBE	0x15fe
+		>;
+	};
+
+	pinctrl_usdhc2_gpio: usdhc2gpiogrp {
+		fsl,pins = <
+			MX93_PAD_SD2_CD_B__GPIO3_IO00		0x31e
+		>;
+	};
+
+	pinctrl_usdhc2_gpio_sleep: usdhc2gpiosleepgrp {
+		fsl,pins = <
+			MX93_PAD_SD2_CD_B__GPIO3_IO00		0x51e
+		>;
+	};
+
+	/* need to config the SION for data and cmd pad, refer to ERR052021 */
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			MX93_PAD_SD2_CLK__USDHC2_CLK		0x1582
+			MX93_PAD_SD2_CMD__USDHC2_CMD		0x40001382
+			MX93_PAD_SD2_DATA0__USDHC2_DATA0	0x40001382
+			MX93_PAD_SD2_DATA1__USDHC2_DATA1	0x40001382
+			MX93_PAD_SD2_DATA2__USDHC2_DATA2	0x40001382
+			MX93_PAD_SD2_DATA3__USDHC2_DATA3	0x40001382
+			MX93_PAD_SD2_VSELECT__USDHC2_VSELECT	0x51e
+		>;
+	};
+
+	/* need to config the SION for data and cmd pad, refer to ERR052021 */
+	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+		fsl,pins = <
+			MX93_PAD_SD2_CLK__USDHC2_CLK		0x158e
+			MX93_PAD_SD2_CMD__USDHC2_CMD		0x4000138e
+			MX93_PAD_SD2_DATA0__USDHC2_DATA0	0x4000138e
+			MX93_PAD_SD2_DATA1__USDHC2_DATA1	0x4000138e
+			MX93_PAD_SD2_DATA2__USDHC2_DATA2	0x4000138e
+			MX93_PAD_SD2_DATA3__USDHC2_DATA3	0x4000138e
+			MX93_PAD_SD2_VSELECT__USDHC2_VSELECT	0x51e
+		>;
+	};
+
+	/* need to config the SION for data and cmd pad, refer to ERR052021 */
+	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+		fsl,pins = <
+			MX93_PAD_SD2_CLK__USDHC2_CLK		0x15fe
+			MX93_PAD_SD2_CMD__USDHC2_CMD		0x400013fe
+			MX93_PAD_SD2_DATA0__USDHC2_DATA0	0x400013fe
+			MX93_PAD_SD2_DATA1__USDHC2_DATA1	0x400013fe
+			MX93_PAD_SD2_DATA2__USDHC2_DATA2	0x400013fe
+			MX93_PAD_SD2_DATA3__USDHC2_DATA3	0x400013fe
+			MX93_PAD_SD2_VSELECT__USDHC2_VSELECT	0x51e
+		>;
+	};
+
+	pinctrl_usdhc2_sleep: usdhc2-sleepgrp {
+		fsl,pins = <
+			MX93_PAD_SD2_CLK__GPIO3_IO01		0x51e
+			MX93_PAD_SD2_CMD__GPIO3_IO02		0x51e
+			MX93_PAD_SD2_DATA0__GPIO3_IO03		0x51e
+			MX93_PAD_SD2_DATA1__GPIO3_IO04		0x51e
+			MX93_PAD_SD2_DATA2__GPIO3_IO05		0x51e
+			MX93_PAD_SD2_DATA3__GPIO3_IO06		0x51e
+			MX93_PAD_SD2_VSELECT__GPIO3_IO19	0x51e
+		>;
+	};
+
+	pinctrl_wdog: wdoggrp {
+		fsl,pins = <
+			MX93_PAD_WDOG_ANY__WDOG1_WDOG_ANY	0x31e
+		>;
+	};
+};

-- 
2.47.3



From f.pflug at pengutronix.de  Thu Dec 18 03:39:20 2025
From: f.pflug at pengutronix.de (Fabian Pflug)
Date: Thu, 18 Dec 2025 12:39:20 +0100
Subject: [PATCH v4 0/2] Add devicetree for NXP i.MX93 FRDM board
Message-ID: <20251218-fpg-nxp-imx93-frdm-v4-0-cd3a9f6ac89a@pengutronix.de>

I could not test all features of the board, therefore a lot of stuff is
omitted from the devicetree. but this is enough to have the board boot
via eMMC or SD-Card, debug via debug USB connector and have a network
connection.

The FRDM i.MX 93 development board is a low-cost and compact development
board featuring the i.MX93 applications processor.

It features:
- Dual Cortex-A55
- 2 GB LPDDR4X / LPDDR4
- 32 GB eMMC5.1
- MicroSD slot
- GbE RJ45 x 2
- USB2.0 1x Type C, 1x Type A

This file is based upon the one provided by nxp in their own kernel and
yocto meta layer for the device, but adapted for mainline.

Signed-off-by: Fabian Pflug <f.pflug at pengutronix.de>
---
Changes in v4:
- remove it6263 block in i2c1, since it is not finished
- remove usdhc3 pwrsequence, since WLAN is not tested on my board
- remove eee-broken-1000t on phy2, since it is not broken
- update min/max-microvlt on buck converters
- Link to v3: https://lore.kernel.org/r/20251022-fpg-nxp-imx93-frdm-v3-0-03ec40a1ccc0 at pengutronix.de

Changes in v3:
- Add Signed-off for original NXP contributors.
- Fixed whitespace errors (Thanks Francesco Valla)
- Added mu1 with status okay (Thanks Francesco Valla)
- Removed address cells from lpi2c3 (Thanks Frank Li)
- Configure pin for watchdog (Thanks Peng Fan)
- Updated regulator config
- Configure i2c0
- Link to v2: https://lore.kernel.org/r/20250526-fpg-nxp-imx93-frdm-v2-0-e5ad0efaec33 at pengutronix.de

Changes in v2:
- 1/2: remove CAN node, as it has not been tested.
- 1/2: ran dt-format (Thanks Frank Li)
	But also reordered some nodes afterwards again to have
	regulator-min before regulator-max, have the pinmux at the end
	of the file, and have the regulator-name as the first node
	inside the regulators.
	Re-added comments, that were deleted.
- 1/2: changes subjet to ar64:dts (Thanks Fabio Estevan)
- 1/2: removed reg_vdd_12v (Tanks Fabio Estevan)
- 1/2: added aliases for rtc, emmc, serial (Thanks Fabio Estevan)
- reordered the series to have documentation before dts. (Thanks
  Krzystof Kozlowski)
- Link to v1: https://lore.kernel.org/r/20250523-fpg-nxp-imx93-frdm-v1-0-546b2d342855 at pengutronix.de

---
Fabian Pflug (2):
      dt-bindings: arm: fsl: add i.MX93 11x11 FRDM board
      arm64: dts: freescale: add support for NXP i.MX93 FRDM

 Documentation/devicetree/bindings/arm/fsl.yaml     |   1 +
 arch/arm64/boot/dts/freescale/Makefile             |   1 +
 arch/arm64/boot/dts/freescale/imx93-11x11-frdm.dts | 620 +++++++++++++++++++++
 3 files changed, 622 insertions(+)
---
base-commit: ea1013c1539270e372fc99854bc6e4d94eaeff66
change-id: 20250523-fpg-nxp-imx93-frdm-5cc180a1fda9

Best regards,
-- 
Fabian Pflug <f.pflug at pengutronix.de>



From jonathan.cameron at huawei.com  Thu Dec 18 03:47:26 2025
From: jonathan.cameron at huawei.com (Jonathan Cameron)
Date: Thu, 18 Dec 2025 11:47:26 +0000
Subject: [RFC PATCH 11/38] arm_mpam: resctrl: Implement helpers to
 update configuration
In-Reply-To: <20251205215901.17772-12-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
	<20251205215901.17772-12-james.morse@arm.com>
Message-ID: <20251218114726.0000651e@huawei.com>

On Fri, 5 Dec 2025 21:58:34 +0000
James Morse <james.morse at arm.com> wrote:

> resctrl has two helpers for updating the configuration.
> resctrl_arch_update_one() updates a single value, and is used by the
> software-controller to apply feedback to the bandwidth controls,
> it has to be called on one of the CPUs in the resctrl:domain.
> 
> resctrl_arch_update_domains() copies multiple staged configurations,
> it can be called from anywhere.
> 
> Both helpers should update any changes to the underlying hardware.
> 
> Imlpement resctrl_arch_update_domains() to use

Implement

> resctrl_arch_update_one(). Neither need to be called on a specific
> CPU as the mpam driver will send IPIs as needed.
> 
> Signed-off-by: James Morse <james.morse at arm.com>
> ---
>  drivers/resctrl/mpam_resctrl.c | 71 ++++++++++++++++++++++++++++++++++
>  1 file changed, 71 insertions(+)
> 
> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
> index a26eb1f3efd0..ae0d17857b78 100644
> --- a/drivers/resctrl/mpam_resctrl.c
> +++ b/drivers/resctrl/mpam_resctrl.c

> +int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid)
> +{
> +	int err = 0;
> +	enum resctrl_conf_type t;
> +	struct rdt_ctrl_domain *d;
> +	struct resctrl_staged_config *cfg;
> +
> +	lockdep_assert_cpus_held();
> +	lockdep_assert_irqs_enabled();
> +
> +	list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
> +		for (t = 0; t < CDP_NUM_TYPES; t++) {
> +			cfg = &d->staged_config[t];
> +			if (!cfg->have_new_ctrl)
> +				continue;
> +
> +			err = resctrl_arch_update_one(r, d, closid, t,
> +						      cfg->new_ctrl);
> +			if (err)
> +				return err;
> +		}
> +	}
> +
> +	return err;

If it stays this simple in later patches
	return 0;

to make it clear this is the good path. Also can then avoid initializing
err at the top.


> +}
> +
>  void resctrl_arch_reset_all_ctrls(struct rdt_resource *r)
>  {
>  	struct mpam_resctrl_res *res;



From jonathan.cameron at huawei.com  Thu Dec 18 03:58:15 2025
From: jonathan.cameron at huawei.com (Jonathan Cameron)
Date: Thu, 18 Dec 2025 11:58:15 +0000
Subject: [RFC PATCH 13/38] arm_mpam: resctrl: Add CDP emulation
In-Reply-To: <20251205215901.17772-14-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
	<20251205215901.17772-14-james.morse@arm.com>
Message-ID: <20251218115815.00003f2c@huawei.com>

On Fri, 5 Dec 2025 21:58:36 +0000
James Morse <james.morse at arm.com> wrote:

> Intel RDT's CDP feature allows the cache to use a different control value
> depending on whether the accesses was for instruction fetch or a data
> access. MPAM's equivalent feature is the other way up: the CPU assigns a
> different partid label to traffic depending on whether it was instruction
> fetch or a data access, which causes the cache to use a different control
> value based solely on the partid.
> 
> MPAM can emulate CDP, with the side effect that the alternative partid is
> seen by all MSC, it can't be enabled per-MSC.
> 
> Add the resctrl hooks to turn this on or off. Add the helpers that
> match a closid against a task, which need to be aware that the value
> written to hardware is not the same as the one resctrl is using.
> 
> Update the 'arm64_mpam_global_default' variable the arch code uses
> during context switch to know when the per-cpu value should be used
> instead.
> 
> Awkwardly, the MB controls don't implement CDP. To emulate this, the
> MPAM equivalent needs programming twice by the resctrl glue, as
> resctrl expects the bandwidth controls to be applied independently for
> both data and isntruction-fetch.
> 
> CC: Dave Martin <Dave.Martin at arm.com>
> CC: Ben Horgan <ben.horgan at arm.com>
> CC: Amit Singh Tomar <amitsinght at marvell.com>
> Signed-off-by: James Morse <james.morse at arm.com>
More trivial stuff. It is clearly that kind of a day.

> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
> index c2650abb99ec..d5f75ed67e46 100644
> --- a/drivers/resctrl/mpam_resctrl.c
> +++ b/drivers/resctrl/mpam_resctrl.c


> +int resctrl_arch_set_cdp_enabled(enum resctrl_res_level ignored, bool enable)
> +{
> +	u32 partid_i, partid_d;
> +
> +	cdp_enabled = enable;
> +	partid_i = partid_d = RESCTRL_RESERVED_CLOSID;


I'd do these at the declarations.  The kernel style guide does also
say not to do multiple assignments on one line. Obviously this
one is fairly obviously fine but none the less...

> +
> +	if (enable) {
> +		u32 partid = RESCTRL_RESERVED_CLOSID;
> +
> +		partid_d = resctrl_get_config_index(partid, CDP_CODE);
> +		partid_i = resctrl_get_config_index(partid, CDP_DATA);
> +	}
> +
> +	mpam_set_task_partid_pmg(current, partid_d, partid_i, 0, 0);
> +	WRITE_ONCE(arm64_mpam_global_default, mpam_get_regval(current));
> +
> +	resctrl_reset_task_closids();
> +
> +	return 0;
> +}


> @@ -272,6 +369,7 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
>  int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
>  			    u32 closid, enum resctrl_conf_type t, u32 cfg_val)
>  {
> +	int err;
>  	u32 partid;
>  	struct mpam_config cfg;
>  	struct mpam_props *cprops;
> @@ -311,7 +409,22 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
>  		return -EINVAL;
>  	}
>  
> -	return mpam_apply_config(dom->ctrl_comp, partid, &cfg);
> +	/*
> +	 * When CDP is enabled, but the resource doesn't support it, we need to
> +	 * apply the same configuration to the other partid.
> +	 */
> +	if (mpam_resctrl_hide_cdp(r->rid)) {
> +		partid = resctrl_get_config_index(closid, CDP_CODE);
> +		err = mpam_apply_config(dom->ctrl_comp, partid, &cfg);
> +		if (err)
> +			return err;
> +
> +		partid = resctrl_get_config_index(closid, CDP_DATA);
> +		return mpam_apply_config(dom->ctrl_comp, partid, &cfg);

Given you returned, maybe drop the else which will reduce the diff
as well as a bonus.  Definitely drop this blank line.

> +
> +	} else {
> +		return mpam_apply_config(dom->ctrl_comp, partid, &cfg);
> +	}
>  }




From daniel.baluta at gmail.com  Thu Dec 18 04:02:47 2025
From: daniel.baluta at gmail.com (Daniel Baluta)
Date: Thu, 18 Dec 2025 14:02:47 +0200
Subject: [PATCH v2 1/2] dt-bindings: arm: fsl: Add compatible for i.MX95
 15x15 FRDM board
In-Reply-To: <20251217-127-v2-1-67cb12e56242@nxp.com>
References: <20251217-127-v2-0-67cb12e56242@nxp.com> <20251217-127-v2-1-67cb12e56242@nxp.com>
Message-ID: <CAEnQRZCNm+8qRNCxW5v2FcEgKPRUvOa6UcQPrZWgC-ijN5+34Q@mail.gmail.com>

On Thu, Dec 18, 2025 at 7:57?AM Lei Xu <lei.xu at nxp.com> wrote:
>
> Introduce a new DT compatible string for the NXP i.MX95 15x15 FRDM
> development board, a compact and cost-effective platform based on
> the i.MX95 applications processor.
>
> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
> Signed-off-by: Lei Xu <lei.xu at nxp.com>


Reviewed-by: Daniel Baluta <daniel.baluta at nxp.com>


From t.remmet at phytec.de  Thu Dec 18 04:00:06 2025
From: t.remmet at phytec.de (Teresa Remmet)
Date: Thu, 18 Dec 2025 13:00:06 +0100
Subject: [PATCH] arm64: boot: dts: imx8mm-phycore-som: Update eth phy
 impedance
Message-ID: <20251218-wip-t-remmet-phytec-de-bspimx8m-3841_upstream-v1-1-2ea15181aaf2@phytec.de>

Update the DP83867 ethernet phy impedance settings to
to optimize signal quality and reduce potential signal integrity issues.

Signed-off-by: Teresa Remmet <t.remmet at phytec.de>
---
 arch/arm64/boot/dts/freescale/imx8mm-phycore-som.dtsi | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mm-phycore-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-phycore-som.dtsi
index 3d66c6701342..b764f7734868 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-phycore-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm-phycore-som.dtsi
@@ -83,6 +83,7 @@ ethphy0: ethernet-phy at 0 {
 			enet-phy-lane-no-swap;
 			ti,clk-output-sel = <DP83867_CLK_O_SEL_OFF>;
 			ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
+			ti,min-output-impedance;
 			ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
 			ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
 			reg = <0>;

---
base-commit: ea1013c1539270e372fc99854bc6e4d94eaeff66
change-id: 20251218-wip-t-remmet-phytec-de-bspimx8m-3841_upstream-b63c70f9a49e

Best regards,
-- 
Teresa Remmet <t.remmet at phytec.de>



From ryan.roberts at arm.com  Thu Dec 18 04:02:14 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Thu, 18 Dec 2025 12:02:14 +0000
Subject: [PATCH 2/2] arm64: mmu: use pagetable_alloc_nolock() while
 stop_machine()
In-Reply-To: <aUPLCPAyxkPeBaoD@e129823.arm.com>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com>
 <20251212161832.2067134-3-yeoreum.yun@arm.com> <aUPJuZINNuNxddRX@tiehlicka>
 <aUPLCPAyxkPeBaoD@e129823.arm.com>
Message-ID: <0d08b4bf-35c5-4c63-964b-ef886b8262d9@arm.com>

On 18/12/2025 09:36, Yeoreum Yun wrote:
> Hi,
>> On Fri 12-12-25 16:18:32, Yeoreum Yun wrote:
>>> linear_map_split_to_ptes() and __kpti_install_ng_mappings()
>>> are called as callback of stop_machine().
>>> That means these functions context are preemption disabled.
>>>
>>> Unfortunately, under PREEMPT_RT, the pagetable_alloc() or
>>> __get_free_pages() couldn't be called in this context
>>> since spin lock that becomes sleepable on RT,
>>> potentially causing a sleep during page allocation.
>>>
>>> To address this, pagetable_alloc_nolock().
>>
>> As you cannot tolerate allocation failure and this is pretty much
>> permanent allocation (AFAIU) why don't you use a static allocation?
> 
> Because of when bbl2_noabort is supported, that pages doesn't need to.
> If static alloc, that would be a waste in the system where bbl2_noabort
> is supported.
> 
> When I tested, these extra pages are more than 40 in my FVP.
> So, it would be better dynamic allocation and I think since it's quite a
> early time, it's probably not failed that's why former code runs as it
> is.

The required allocation size is also a function of the size of the installed RAM
so a static worst case allocation would consume all the RAM on small systems.

> 
> --
> Sincerely,
> Yeoreum Yun



From konrad.dybcio at oss.qualcomm.com  Thu Dec 18 04:02:32 2025
From: konrad.dybcio at oss.qualcomm.com (Konrad Dybcio)
Date: Thu, 18 Dec 2025 13:02:32 +0100
Subject: [PATCH] iommu/arm-smmu: add actlr settings for mdss and fastrpc
In-Reply-To: <9b4c895a-c822-40e6-bb92-8fdcd09c82d3@oss.qualcomm.com>
References: <20251105075307.1658329-1-charan.kalla@oss.qualcomm.com>
 <eb596f7a-e13b-4edd-8ee7-05424ea3d9e5@oss.qualcomm.com>
 <c4b1df46-e4b6-4d95-971c-7aaf33bd35f1@oss.qualcomm.com>
 <02d7c0a9-0d24-4fd8-980a-da9d7307588a@oss.qualcomm.com>
 <9b4c895a-c822-40e6-bb92-8fdcd09c82d3@oss.qualcomm.com>
Message-ID: <bfdb1125-3dcc-496e-8380-80ba669dfe20@oss.qualcomm.com>

On 11/27/25 12:14 PM, Bibek Kumar Patro wrote:
> 
> 
> On 11/12/2025 7:32 PM, Konrad Dybcio wrote:
>> On 11/11/25 3:02 PM, Charan Teja Kalla wrote:
>>>
>>>
>>> On 11/5/2025 2:44 PM, Konrad Dybcio wrote:
>>>>> +??? { .compatible = "qcom,fastrpc-compute-cb",
>>>>> +??????????? .data = (const void *) (PREFETCH_DEEP | CPRE | CMTLB) },
>>>> This will be globally applied to all smmu-v2 targets with fastrpc,
>>>> starting from MSM8996 ending at Kaanapali and everything inbetween
>>>>
>>>> Are these settings always valid?
>>> Oops, you are correct...this settings are not always applicable it seems.
>>>
>>> Example: lpass compute and cdsp compute node uses the
>>> "qcom,fastrpc-compute-cb", but it is for the later that ACTLR settings
>>> are valid.
>>>
>>> Then for these cases, should we be extending the actlr match array with
>>> additional compatible string and then add them in all the device nodes
>>> that require actlr setting? example:
>>>
>>> @@ -3119,7 +3119,8 @@ fastrpc {
>>> ?????? compute-cb at 1 {
>>> -???????? compatible = "qcom,fastrpc-compute-cb";
>>> +???????? compatible = "qcom,fastrpc-compute-cb",
>>> +????????????????????? "qcom,fastrpc-compute-cb-actlr";
>>
>> dt-bindings (and especially compatible strings) must not be altered solely
>> to work around a driver being suboptimal
>>
>> But because you reported that these settings can change both between
>> platforms and instances of the same devices on these platforms, we could
>> possibly reconsider adding ACTRL settings to the consumer device nodes
>> where they stray away from the otherwise seemingly reasonable baseline
>> we have in the driver so far..
>>
> 
> During initial discussion of ACTLR design phase, It was concluded that
> prefetch alike QoS settings are not hardware definitions, and device
> tree would not be the right place to store such configurable/tunable
> settings [1]. So it might be contradicting to add it in consumer nodes.
> 
> For fastrpc client, there are 2 hiccups:
> 1. For a particular SoC, Different SIDs of compute client are using the
> ?? same compatible? "qcom,fastrpc-compute-cb" but can have different
> ?? prefetch settings <refer table below> e.g. CDSP and ADSP have same
> ?? compat string "qcom,fastrpc-compute-cb" with different labels.
> 
> e.g.
> fastrpc {
> ??????? compatible = "qcom,fastrpc";
> ??????? qcom,glink-channels = "fastrpcglink-apps-dsp";
> ??????? label = "adsp"; /*---different label: adsp---*/
> ??????? compute-cb at 3 {
> ??????????????? compatible = "qcom,fastrpc-compute-cb";
> ??????????????? reg = <3>;
> ??????? /*---Prefetch Default---*/
> ??????????????? iommus = <&apps_smmu 0x1003 0x80>,
> ???????????????????????? <&apps_smmu 0x1063 0x0>;
> ??????????????? dma-coherent;
> fastrpc {
> ??????? compatible = "qcom,fastrpc";
> ??????? qcom,glink-channels = "fastrpcglink-apps-dsp";
> ??????? label = "cdsp"; /*---Different Label: cdsp---*/
> ??????? qcom,non-secure-domain;
> ??????? #address-cells = <1>;
> ??????? #size-cells = <0>;
> ??????? compute-cb at 1 {
> ??????????????? compatible = "qcom,fastrpc-compute-cb";
> ??????????????? reg = <1>;
> ??????? /*---Prefetch DEEP----*/
> ??????????????? iommus = <&apps_smmu 0x1961 0x0>,
> ???????????????????????? <&apps_smmu 0x0c01 0x20>,
> ???????????????????????? <&apps_smmu 0x19c1 0x10>;
> 
> 2. Different SoCs having the same compatible string and same label but
> ?? different prefetch settings.
> ?? e.g:
> ?? in below table sm6550, sm8250 and sm8550
> ?? compat string = "qcom,fastrpc-compute-cb" and label = "cdsp"
> ?? but prefetch settings are different
> 
> As per my idea both the above cases could be resolved by compat string addition,
> case 1 : compatible = "qcom,fastrpc-compute-cb-cdsp";
> case 2 : compatible = "qcom,sm8550-fastrpc-compute-cb-cdsp"
> 
> This discrpeancy is not applicable for other clients, except fastrpc.
> One way both the above cases could be resolved by additional fastrpc
> compat string with below format:
> compatible = "qcom,<soc_name>-fastrpc-compute-cb-<label_name>"
> 
> e.g: "qcom,sm8550-fastrpc-compute-cb-cdsp", "qcom,sm6550-fastrpc-compute-cb-adsp"
> 
> This should handle both case 1 & case 2.
> 
> But as you mentioned previously this might need change alteration of DT bindings addition which might not be allowed or favoured always.
> 
> [1]: https://lore.kernel.org/all/a01e7e60-6ead-4a9e-ba90-22a8a6bbd03f at quicinc.com/
> 
>> Or we could introduce some more bespoke matching logic.
>>
>> I would like to know more about the scope of this issue, i.e. the matrix
>> of (soc, device, actlr_val) that needs special handling.
>>
> 
> +---------+-----------------------------------------------+----------+
> | SoC???? | Description?????????????????????????????????? | Prefetch |
> +---------+-----------------------------------------------+----------+
> | sc7180? | qcom,fastrpc-compute-cb | label = cdsp??????? | DEEP???? |
> |???????? | qcom,fastrpc-compute-cb | label = adsp??????? | DEFAULT? |
> +---------+-----------------------------------------------+----------+
> | sc7280? | qcom,fastrpc-compute-cb | label = cdsp??????? | DEEP???? |
> |???????? | qcom,fastrpc-compute-cb | label = adsp??????? | DEFAULT? |
> +---------+-----------------------------------------------+----------+
> | sm6115? | qcom,fastrpc-compute-cb | label = cdsp??????? | DEFAULT? |
> |???????? | qcom,fastrpc-compute-cb | label = adsp??????? | DEFAULT? |
> +---------+-----------------------------------------------+----------+
> | sm6125? | qcom,fastrpc-compute-cb (NA upstream)???????? |????????? |
> +---------+-----------------------------------------------+----------+
> | sm6350? | qcom,fastrpc-compute-cb | label = cdsp??????? | SHALLOW? |
> |???????? | qcom,fastrpc-compute-cb | label = adsp??????? | SHALLOW? |
> +---------+-----------------------------------------------+----------+
> | sm8250? | qcom,fastrpc-compute-cb | label = cdsp??????? | DEFAULT? |
> |???????? | qcom,fastrpc-compute-cb | label = adsp??????? | DEFAULT? |
> |???????? | qcom,fastrpc-compute-cb | label = sdsp??????? | DEFAULT? |
> +---------+-----------------------------------------------+----------+
> | sm8350? | qcom,fastrpc-compute-cb | label = cdsp??????? | DEEP???? |
> |???????? | qcom,fastrpc-compute-cb | label = adsp??????? | DEFAULT? |
> |???????? | qcom,fastrpc-compute-cb | label = sdsp??????? | DEFAULT? |
> +---------+-----------------------------------------------+----------+
> | sm8450? | qcom,fastrpc-compute-cb | label = cdsp??????? | DEEP???? |
> |???????? | qcom,fastrpc-compute-cb | label = adsp??????? | DEFAULT? |
> |???????? | qcom,fastrpc-compute-cb | label = sdsp??????? | DEFAULT? |
> +---------+-----------------------------------------------+----------+
> | sm8550? | qcom,fastrpc-compute-cb | label = cdsp??????? | DEEP???? |
> |???????? | qcom,fastrpc-compute-cb | label = adsp??????? | DEFAULT? |
> +---------+-----------------------------------------------+----------+
> | sm8650? | qcom,fastrpc-compute-cb | label = cdsp??????? | DEEP???? |
> |???????? | qcom,fastrpc-compute-cb | label = adsp??????? | DEFAULT? |
> +---------+-----------------------------------------------+----------+

Thanks for the detailed explanation. It feel quite impossible to keep
track of all this in the current model.

On the other hand, the approach where a third OF cell is introduced
isn't my favorite thing in the world, and that seems to be the general
sentiment.

FWIW downstream solves this by carrying the list of <sid mask val> under
the SMMU node. Perhaps that could be reconsidered, either as a storage
for all the values, or as storage for non-default overrides.. Krzysztof,
Bjorn, opinions?

Konrad


From konrad.dybcio at oss.qualcomm.com  Thu Dec 18 04:06:43 2025
From: konrad.dybcio at oss.qualcomm.com (Konrad Dybcio)
Date: Thu, 18 Dec 2025 13:06:43 +0100
Subject: [PATCH v18 0/5] iommu/arm-smmu: introduction of ACTLR
 implementation for Qualcomm SoCs
In-Reply-To: <1db3d7f5-0cdf-449c-bbc3-dc40c89ab27f@oss.qualcomm.com>
References: <20241212151402.159102-1-quic_bibekkum@quicinc.com>
 <CALE0LRupg93WsBVc62Lqt-T9qmK5MdEYoScxyP7=ttKJYXAsUA@mail.gmail.com>
 <33826089-54b5-47bc-8a5b-6004c7a276b8@oss.qualcomm.com>
 <5a1aaf4a-c5d5-42e1-9044-d12a6c231904@oss.qualcomm.com>
 <1db3d7f5-0cdf-449c-bbc3-dc40c89ab27f@oss.qualcomm.com>
Message-ID: <ba257b17-b026-4a12-aa3e-dab66a7aeaba@oss.qualcomm.com>

On 11/13/25 2:55 PM, Charan Teja Kalla wrote:
> 
> 
> On 11/12/2025 7:04 PM, Konrad Dybcio wrote:
>>> Hi Eric,
>>>
>>> If a device has multiple SIDs, all serving the same functionality and grouped under the same "iommus" field, for example:
>>>
>>> iommus = <&apps_smmu, 0x2141, 0x0>,
>>> ????????? <&apps_smmu, 0x25c1, 0x0>,
>>> ????????? <&apps_smmu, 0x2161, 0x0>;
>>>
>>> In this case, all the SIDs will be associated with the same context bank. Even if the three SIDs have different ACTLR settings, since SMMU_CB_ACTLR is per CB setting, all SIDs attached to that bank will share the same ACTLR configuration. This is why we designed it to be "per device / per compatible".
>> Does that suggest the settings may be slightly suboptimal?

I don't understand your question

> Or it is limitation to use the ACTLR?
> 
>> There's some work being done to allow more granular association of
>> the passed SIDs:
>>
>> https://lore.kernel.org/linux-arm-msm/20250928171718.436440-1-
>> charan.kalla at oss.qualcomm.com/
> Sorry, I am unable to link this limitation for actlr setting with the
> work. Can you elaborate please?

Because your email client is misconfigured and it broke the line.. If
it's thunderbird, pretty sure we have a "change these configs" type
section on go/upstream, please take a look

> IIUC, unless the SIDs are totally separated per actlr settings and
> attached to CB(which are limited), this can't be achieved...but may be a
> question here to check is it really a __valid__ to associate a different
> actlr settings SID to use the same CB?

The last question you asked is certainly a valid one

But I was wondering if iommu-map could be useful to resolve this, where
we choose an abstract set of function IDs and then handle the IOMMU
configuration manually, based on the func_id-delimited sets:

iommu-map = <FUNC_ID0 &iommu_phandle CELL0 ... CELLN-1>,
	    <FUNC_ID0 &iommu_phandle CELL0 ... CELLN-1>,
	    <FUNC_ID1 &iommu_phandle CELL0 ... CELLN-1>,
	    <FUNC_ID2 &iommu_phandle CELL0 ... CELLN-1>;

But perhaps that's more useful from the driver-that-handles-the-device
perspective

Konrad


From ryan.roberts at arm.com  Thu Dec 18 04:08:03 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Thu, 18 Dec 2025 12:08:03 +0000
Subject: [PATCH v2 2/3] mm: rmap: support batched checks of the references
 for large folios
In-Reply-To: <89cdd927-fc88-42cf-b8a1-2fbd736d5f7c@linux.alibaba.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <545dba5e899634bc6c8ca782417d16fef3bd049f.1765439381.git.baolin.wang@linux.alibaba.com>
 <cb4d7243-d8c6-4706-a254-6f5afc148910@arm.com>
 <89cdd927-fc88-42cf-b8a1-2fbd736d5f7c@linux.alibaba.com>
Message-ID: <0caffb55-f242-4b01-b60a-c8749aadf661@arm.com>

>>> ? +#define clear_flush_young_ptes clear_flush_young_ptes
>>> +static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
>>> +??????????????????? unsigned long addr, pte_t *ptep,
>>> +??????????????????? unsigned int nr)
>>> +{
>>> +??? if (likely(nr == 1))
>>> +??????? return __ptep_clear_flush_young(vma, addr, ptep);
>>
>> Bug: This is broken if core-mm tries to call this for nr=1 on a pte that is part
>> of a contpte mapping.
>>
>> The similar fastpaths are here to prevent regressing the common small folio case.
> 
> Thanks for catching this. I had considered this before, but I still missed it.
> 
>> I guess here the best approach is (note no leading underscores):
>>
>> ????if (likely(nr == 1))
>> ??????? return ptep_clear_flush_young(vma, addr, ptep);
> 
> However, I prefer to use pte_cont() to check it. Later, I plan to clean up the
> ptep_clear_flush_young().
> 
> ????if (nr == 1 && !pte_cont(__ptep_get(ptep))
> ??????? return __ptep_clear_flush_young(vma, addr, ptep);

Sure. That would follow the pattern in clear_young_dirty_ptes(). Please use the
likely() hint as is done everywhere else:

	if (likely(nr == 1 && !pte_cont(__ptep_get(ptep))))

I notice that ptep_test_and_clear_young() and ptep_clear_flush_young() are both
testing aginst pte_valid_cont(). These could probably be relaxed to pte_cont()
since it is implicit the the pte must be valid?



From leon at kernel.org  Thu Dec 18 04:11:35 2025
From: leon at kernel.org (Leon Romanovsky)
Date: Thu, 18 Dec 2025 14:11:35 +0200
Subject: [PATCH v5 09/14] parisc: Convert DMA map_page to map_phys interface [qemu
 test failure]
In-Reply-To: <20251218084002.GD39046@unreal>
References: <20251015-remove-map-page-v5-0-3bbfe3a25cdf@kernel.org>
 <20251015-remove-map-page-v5-9-3bbfe3a25cdf@kernel.org>
 <b184f1bf-96dc-4546-8512-9cba5ecb58f7@roeck-us.net>
 <20251218084002.GD39046@unreal>
Message-ID: <77e73a01-9f7e-475b-a810-278f931910ed@app.fastmail.com>



On Thu, Dec 18, 2025, at 10:40, Leon Romanovsky wrote:
> On Wed, Dec 17, 2025 at 04:17:38AM -0800, Guenter Roeck wrote:
>> Hi,
>> 
>> On Wed, Oct 15, 2025 at 12:12:55PM +0300, Leon Romanovsky wrote:
>> > From: Leon Romanovsky <leonro at nvidia.com>
>> > 
>> > Perform mechanical conversion from .map_page to .map_phys callback.
>> > 
>> > Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
>> > Signed-off-by: Leon Romanovsky <leonro at nvidia.com>
>> 
>> This patch causes all my 32-bit parisc qemu tests with C3700 machine
>> to fail. Network interface tests fail, and all boot attempts from
>> any kind of hard drive (scsi, usb) fail with this patch in the tree.
>
> Thanks for the report. I have a fix ready; I'll clean it up and send it out
> by EOD.

The fix is available here
https://lore.kernel.org/all/20251218-fix-parisc-conversion-v1-1-4a04d26b0168 at nvidia.com/T/#u

Thanks

>
>> 
>> Guenter


From will at kernel.org  Thu Dec 18 04:13:25 2025
From: will at kernel.org (Will Deacon)
Date: Thu, 18 Dec 2025 12:13:25 +0000
Subject: [PATCH 11/12] ras: add DeviceTree estatus provider driver
In-Reply-To: <20251217112845.1814119-12-ahmed.tiba@arm.com>
References: <20251217112845.1814119-1-ahmed.tiba@arm.com>
 <20251217112845.1814119-12-ahmed.tiba@arm.com>
Message-ID: <aUPv5UfBByVoLbRV@willie-the-truck>

On Wed, Dec 17, 2025 at 11:28:44AM +0000, Ahmed Tiba wrote:
> Introduce a platform driver that maps the CPER status block described
> in DeviceTree, feeds it into the estatus core and handles either IRQ- or
> poll-driven notifications. Arm64 gains a FIX_ESTATUS_IRQ slot so the
> driver can safely map the shared buffer while copying records.
> 
> Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>
> ---
>  MAINTAINERS                     |   1 +
>  arch/arm64/include/asm/fixmap.h |   5 +
>  drivers/ras/Kconfig             |  14 ++
>  drivers/ras/Makefile            |   1 +
>  drivers/ras/estatus-dt.c        | 318 ++++++++++++++++++++++++++++++++
>  include/linux/estatus.h         |   3 +-
>  6 files changed, 341 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/ras/estatus-dt.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 6b2ef2ddc0c7..5567d5e82053 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -21761,6 +21761,7 @@ RAS ERROR STATUS
>  M:	Ahmed Tiba <ahmed.tiba at arm.com>
>  S:	Maintained
>  F:	Documentation/devicetree/bindings/ras/arm,ras-ffh.yaml
> +F:	drivers/ras/estatus-dt.c
>  F:	drivers/firmware/efi/estatus.c
>  F:	include/linux/estatus.h
>  
> diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h
> index 65555284446e..85ffba87bab9 100644
> --- a/arch/arm64/include/asm/fixmap.h
> +++ b/arch/arm64/include/asm/fixmap.h
> @@ -64,6 +64,11 @@ enum fixed_addresses {
>  #endif
>  #endif /* CONFIG_ACPI_APEI_GHES */
>  
> +#ifdef CONFIG_RAS_ESTATUS_DT
> +	/* Used for ESTATUS mapping from assorted contexts */
> +	FIX_ESTATUS_IRQ,
> +#endif /* CONFIG_RAS_ESTATUS_DT */

Why do we need this in addition to the four existing GHES slots? The DT
code doesn't use it and I was assuming that the ACPI code would continue
to use the existing irq; is that not the case?

Will


From mhocko at suse.com  Thu Dec 18 04:17:25 2025
From: mhocko at suse.com (Michal Hocko)
Date: Thu, 18 Dec 2025 13:17:25 +0100
Subject: [PATCH 2/2] arm64: mmu: use pagetable_alloc_nolock() while
 stop_machine()
In-Reply-To: <0d08b4bf-35c5-4c63-964b-ef886b8262d9@arm.com>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com>
 <20251212161832.2067134-3-yeoreum.yun@arm.com>
 <aUPJuZINNuNxddRX@tiehlicka>
 <aUPLCPAyxkPeBaoD@e129823.arm.com>
 <0d08b4bf-35c5-4c63-964b-ef886b8262d9@arm.com>
Message-ID: <aUPw1YFNLf7ONqe9@tiehlicka>

On Thu 18-12-25 12:02:14, Ryan Roberts wrote:
> On 18/12/2025 09:36, Yeoreum Yun wrote:
> > Hi,
> >> On Fri 12-12-25 16:18:32, Yeoreum Yun wrote:
> >>> linear_map_split_to_ptes() and __kpti_install_ng_mappings()
> >>> are called as callback of stop_machine().
> >>> That means these functions context are preemption disabled.
> >>>
> >>> Unfortunately, under PREEMPT_RT, the pagetable_alloc() or
> >>> __get_free_pages() couldn't be called in this context
> >>> since spin lock that becomes sleepable on RT,
> >>> potentially causing a sleep during page allocation.
> >>>
> >>> To address this, pagetable_alloc_nolock().
> >>
> >> As you cannot tolerate allocation failure and this is pretty much
> >> permanent allocation (AFAIU) why don't you use a static allocation?
> > 
> > Because of when bbl2_noabort is supported, that pages doesn't need to.
> > If static alloc, that would be a waste in the system where bbl2_noabort
> > is supported.
> > 
> > When I tested, these extra pages are more than 40 in my FVP.
> > So, it would be better dynamic allocation and I think since it's quite a
> > early time, it's probably not failed that's why former code runs as it
> > is.
> 
> The required allocation size is also a function of the size of the installed RAM
> so a static worst case allocation would consume all the RAM on small systems.

Understood. But is it possible to pre-allocate early on so that the
allocation itself doesn't have to happen from a constrained context.
-- 
Michal Hocko
SUSE Labs


From ryan.roberts at arm.com  Thu Dec 18 04:20:13 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Thu, 18 Dec 2025 12:20:13 +0000
Subject: [PATCH v2 1/3] arm64: mm: support batch clearing of the young
 flag for large folios
In-Reply-To: <96c0adcc-abfd-4a44-be93-1c6bd7942d6d@linux.alibaba.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <e10f876ce130134fa089befe83f30561b48b9889.1765439380.git.baolin.wang@linux.alibaba.com>
 <1beaa7de-4b31-4f19-abee-83872f868e28@arm.com>
 <96c0adcc-abfd-4a44-be93-1c6bd7942d6d@linux.alibaba.com>
Message-ID: <d3b40df8-e5cf-42aa-8205-de624024fad1@arm.com>

On 18/12/2025 07:15, Baolin Wang wrote:
> 
> 
> On 2025/12/17 23:43, Ryan Roberts wrote:
>> Sorry I'm a bit late to the party...
> 
> Never mind. It's not late and comments are always welcome :)
> 
>> On 11/12/2025 08:16, Baolin Wang wrote:
>>> Currently, contpte_ptep_test_and_clear_young() and
>>> contpte_ptep_clear_flush_young()
>>> only clear the young flag and flush TLBs for PTEs within the contiguous range.
>>> To support batch PTE operations for other sized large folios in the following
>>> patches, adding a new parameter to specify the number of PTEs.
>>>
>>> While we are at it, rename the functions to maintain consistency with other
>>> contpte_*() functions.
>>>
>>> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
>>> ---
>>> ? arch/arm64/include/asm/pgtable.h | 12 ++++-----
>>> ? arch/arm64/mm/contpte.c????????? | 44 ++++++++++++++++++++++----------
>>> ? 2 files changed, 37 insertions(+), 19 deletions(-)
>>>
>>> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
>>> index 0944e296dd4a..e03034683156 100644
>>> --- a/arch/arm64/include/asm/pgtable.h
>>> +++ b/arch/arm64/include/asm/pgtable.h
>>> @@ -1679,10 +1679,10 @@ extern void contpte_clear_full_ptes(struct mm_struct
>>> *mm, unsigned long addr,
>>> ? extern pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
>>> ????????????????? unsigned long addr, pte_t *ptep,
>>> ????????????????? unsigned int nr, int full);
>>> -extern int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
>>> -??????????????? unsigned long addr, pte_t *ptep);
>>> -extern int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
>>> -??????????????? unsigned long addr, pte_t *ptep);
>>> +extern int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
>>> +??????????????? unsigned long addr, pte_t *ptep, unsigned int nr);
>>> +extern int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
>>> +??????????????? unsigned long addr, pte_t *ptep, unsigned int nr);
>>
>> The "contpte_" functions are intended to be private to the arm64 arch and should
>> be exposed via the generic APIs. But I don't see any generic batched API for
>> this, so you're only actually able to pass CONT_PTES as nr. Perhaps you're
>> planning to define "test_and_clear_young_ptes()" and "clear_flush_young_ptes()"
>> in later patches?
> 
> Right. This is a preparation patch, and will be used in patch 2.
> 
>>> ? extern void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
>>> ????????????????? pte_t *ptep, unsigned int nr);
>>> ? extern int contpte_ptep_set_access_flags(struct vm_area_struct *vma,
>>> @@ -1854,7 +1854,7 @@ static inline int ptep_test_and_clear_young(struct
>>> vm_area_struct *vma,
>>> ????? if (likely(!pte_valid_cont(orig_pte)))
>>> ????????? return __ptep_test_and_clear_young(vma, addr, ptep);
>>> ? -??? return contpte_ptep_test_and_clear_young(vma, addr, ptep);
>>> +??? return contpte_test_and_clear_young_ptes(vma, addr, ptep, CONT_PTES);
>>> ? }
>>> ? ? #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
>>> @@ -1866,7 +1866,7 @@ static inline int ptep_clear_flush_young(struct
>>> vm_area_struct *vma,
>>> ????? if (likely(!pte_valid_cont(orig_pte)))
>>> ????????? return __ptep_clear_flush_young(vma, addr, ptep);
>>> ? -??? return contpte_ptep_clear_flush_young(vma, addr, ptep);
>>> +??? return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
>>> ? }
>>> ? ? #define wrprotect_ptes wrprotect_ptes
>>> diff --git a/arch/arm64/mm/contpte.c b/arch/arm64/mm/contpte.c
>>> index c0557945939c..19b122441be3 100644
>>> --- a/arch/arm64/mm/contpte.c
>>> +++ b/arch/arm64/mm/contpte.c
>>> @@ -488,8 +488,9 @@ pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
>>> ? }
>>> ? EXPORT_SYMBOL_GPL(contpte_get_and_clear_full_ptes);
>>> ? -int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
>>> -??????????????????? unsigned long addr, pte_t *ptep)
>>> +int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
>>> +??????????????????? unsigned long addr, pte_t *ptep,
>>> +??????????????????? unsigned int nr)
>>> ? {
>>> ????? /*
>>> ?????? * ptep_clear_flush_young() technically requires us to clear the access
>>> @@ -500,39 +501,56 @@ int contpte_ptep_test_and_clear_young(struct
>>> vm_area_struct *vma,
>>> ?????? * having to unfold.
>>> ?????? */
>>> ? +??? unsigned long start = addr;
>>
>> Personally I wouldn't bother defining start - just reuse addr. You're
>> incrementing start in the below loop, so it's more appropriate to call it addr
>> anyway.
> 
> OK.
> 
>>> +??? unsigned long end = start + nr * PAGE_SIZE;
>>> ????? int young = 0;
>>> ????? int i;
>>> ? -??? ptep = contpte_align_down(ptep);
>>> -??? addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
>>> +??? if (pte_cont(__ptep_get(ptep + nr - 1)))
>>> +??????? end = ALIGN(end, CONT_PTE_SIZE);
>>> ? -??? for (i = 0; i < CONT_PTES; i++, ptep++, addr += PAGE_SIZE)
>>> -??????? young |= __ptep_test_and_clear_young(vma, addr, ptep);
>>> +??? if (pte_cont(__ptep_get(ptep))) {
>>> +??????? start = ALIGN_DOWN(start, CONT_PTE_SIZE);
>>> +??????? ptep = contpte_align_down(ptep);
>>> +??? }
>>> +
>>> +??? nr = (end - start) / PAGE_SIZE;
>>> +??? for (i = 0; i < nr; i++, ptep++, start += PAGE_SIZE)
>>
>> Given you're now defining end, perhaps we don't need nr?
>>
>> ????for (; addr != end; ptep++, addr += PAGE_SIZE)
>> ??????? young |= __ptep_test_and_clear_young(vma, addr, ptep);
> 
> Yes, good point.
> 
>>> +??????? young |= __ptep_test_and_clear_young(vma, start, ptep);
>>> ? ????? return young;
>>> ? }
>>> -EXPORT_SYMBOL_GPL(contpte_ptep_test_and_clear_young);
>>> +EXPORT_SYMBOL_GPL(contpte_test_and_clear_young_ptes);
>>> ? -int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
>>> -??????????????????? unsigned long addr, pte_t *ptep)
>>> +int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
>>> +??????????????? unsigned long addr, pte_t *ptep,
>>> +??????????????? unsigned int nr)
>>> ? {
>>> ????? int young;
>>> ? -??? young = contpte_ptep_test_and_clear_young(vma, addr, ptep);
>>> +??? young = contpte_test_and_clear_young_ptes(vma, addr, ptep, nr);
>>> ? ????? if (young) {
>>> +??????? unsigned long start = addr;
>>> +??????? unsigned long end = start + nr * PAGE_SIZE;
>>> +
>>> +??????? if (pte_cont(__ptep_get(ptep + nr - 1)))
>>> +??????????? end = ALIGN(end, CONT_PTE_SIZE);
>>> +
>>> +??????? if (pte_cont(__ptep_get(ptep)))
>>> +??????????? start = ALIGN_DOWN(start, CONT_PTE_SIZE);
>>> +
>>
>> We now have this pattern of expanding contpte blocks up and down in 3 places.
>> Perhaps create a helper?
> 
> Sounds reasonable. How about the following helper?
> 
> static pte_t *contpte_align_addr_ptep(unsigned long *start, unsigned long *end,
> ??????????????????????????????????????? pte_t *ptep, unsigned int nr)
> {
> ??????? unsigned long end_addr = *start + nr * PAGE_SIZE;
> 
> ??????? if (pte_cont(__ptep_get(ptep + nr - 1)))

I think this is safe but calling it out to check; you're not checking that the
pte is valid, so theoretically you could have a swap-entry here with whatever
overlays the contiguous bit set. So then you would incorrectly extend.

But I think it is safe because the expectation is that core-mm has already
checked that the whole range is present?

> ??????????????? *end = ALIGN(end_addr, CONT_PTE_SIZE);
> 
> ??????? if (pte_cont(__ptep_get(ptep))) {
> ??????????????? *start = ALIGN_DOWN(*start, CONT_PTE_SIZE);
> ??????????????? ptep = contpte_align_down(ptep);
> ??????? }
> 
> ??????? return ptep;
> }

Looks good.



From yeoreum.yun at arm.com  Thu Dec 18 04:24:54 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Thu, 18 Dec 2025 12:24:54 +0000
Subject: [PATCH 2/2] arm64: mmu: use pagetable_alloc_nolock() while
 stop_machine()
In-Reply-To: <aUPw1YFNLf7ONqe9@tiehlicka>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com>
 <20251212161832.2067134-3-yeoreum.yun@arm.com>
 <aUPJuZINNuNxddRX@tiehlicka>
 <aUPLCPAyxkPeBaoD@e129823.arm.com>
 <0d08b4bf-35c5-4c63-964b-ef886b8262d9@arm.com>
 <aUPw1YFNLf7ONqe9@tiehlicka>
Message-ID: <aUPyllWslvMakLMx@e129823.arm.com>

> On Thu 18-12-25 12:02:14, Ryan Roberts wrote:
> > On 18/12/2025 09:36, Yeoreum Yun wrote:
> > > Hi,
> > >> On Fri 12-12-25 16:18:32, Yeoreum Yun wrote:
> > >>> linear_map_split_to_ptes() and __kpti_install_ng_mappings()
> > >>> are called as callback of stop_machine().
> > >>> That means these functions context are preemption disabled.
> > >>>
> > >>> Unfortunately, under PREEMPT_RT, the pagetable_alloc() or
> > >>> __get_free_pages() couldn't be called in this context
> > >>> since spin lock that becomes sleepable on RT,
> > >>> potentially causing a sleep during page allocation.
> > >>>
> > >>> To address this, pagetable_alloc_nolock().
> > >>
> > >> As you cannot tolerate allocation failure and this is pretty much
> > >> permanent allocation (AFAIU) why don't you use a static allocation?
> > >
> > > Because of when bbl2_noabort is supported, that pages doesn't need to.
> > > If static alloc, that would be a waste in the system where bbl2_noabort
> > > is supported.
> > >
> > > When I tested, these extra pages are more than 40 in my FVP.
> > > So, it would be better dynamic allocation and I think since it's quite a
> > > early time, it's probably not failed that's why former code runs as it
> > > is.
> >
> > The required allocation size is also a function of the size of the installed RAM
> > so a static worst case allocation would consume all the RAM on small systems.
>
> Understood. But is it possible to pre-allocate early on so that the
> allocation itself doesn't have to happen from a constrained context.

That's the same suggestion from Ryan
(https://lore.kernel.org/all/100cc8da-b826-4fc2-a624-746bf6fb049d at arm.com/)

And here is the v2 which have accepted his suggestion :)
(But soon respin):
https://lore.kernel.org/all/20251217182007.2345700-1-yeoreum.yun at arm.com/

Thanks ;)

--
Sincerely,
Yeoreum Yun


From konrad.dybcio at oss.qualcomm.com  Thu Dec 18 04:36:44 2025
From: konrad.dybcio at oss.qualcomm.com (Konrad Dybcio)
Date: Thu, 18 Dec 2025 13:36:44 +0100
Subject: [PATCH 3/3] clk: qcom: camcc: Add camera clock controller driver
 for SM8750 SoC
In-Reply-To: <20251202-sm8750_camcc-v1-3-b3f7ef6723f1@oss.qualcomm.com>
References: <20251202-sm8750_camcc-v1-0-b3f7ef6723f1@oss.qualcomm.com>
 <20251202-sm8750_camcc-v1-3-b3f7ef6723f1@oss.qualcomm.com>
Message-ID: <69ac0e2b-82d5-43d2-816d-d3ac31963077@oss.qualcomm.com>

On 12/2/25 11:26 AM, Taniya Das wrote:
> Add support for the Camera Clock Controller (CAMCC) on the SM8750
> platform.
> 
> The CAMCC block on SM8750 includes both the primary camera clock
> controller and the Camera BIST clock controller, which provides the
> functional MCLK required for camera operations.
> 
> Signed-off-by: Taniya Das <taniya.das at oss.qualcomm.com>
> ---

Reviewed-by: Konrad Dybcio <konrad.dybcio at oss.qualcomm.com>

Konrad


From mripard at kernel.org  Thu Dec 18 04:50:37 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Thu, 18 Dec 2025 13:50:37 +0100
Subject: [PATCH v3 01/22] drm/bridge: add of_drm_find_and_get_bridge()
In-Reply-To: <DF0KBN5Y22XW.2RE8HKDFY87XK@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-1-b5165fab8058@bootlin.com>
 <0ba037c65f9cadd51082abf2b7857ba7@kernel.org>
 <DF0KBN5Y22XW.2RE8HKDFY87XK@bootlin.com>
Message-ID: <20251218-shiny-rugged-bug-d1d3e8@houat>

Hi,

On Wed, Dec 17, 2025 at 03:31:01PM +0100, Luca Ceresoli wrote:
> On Wed Dec 17, 2025 at 11:15 AM CET, Maxime Ripard wrote:
> > On Tue, 16 Dec 2025 18:58:34 +0100, Luca Ceresoli wrote:
> >> of_drm_find_bridge() does not increment the refcount for the returned
> >> bridge, but that is required now. However converting it and all its users
> >> is not realistically doable at once given the large amount of (direct and
> >> indirect) callers and the complexity of some.
> >>
> >>
> >> [ ... ]
> >
> > Reviewed-by: Maxime Ripard <mripard at kernel.org>
> 
> Thank you for the prompt review!
> 
> All patches are reviewed now except patch 18 which has no reply. I'm just
> pointing out in case it's something you missed.

Yes, I couldn't really understand the implications of that one, so I'll
leave the review to the maintainers.

Maxime
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 273 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251218/4a8dafd1/attachment.sig>

From kylebonnici at proton.me  Thu Dec 18 04:51:01 2025
From: kylebonnici at proton.me (kylebonnici)
Date: Thu, 18 Dec 2025 12:51:01 +0000
Subject: [PATCH] Coding Style: Format arch/arm/boot/dts/xilinx
Message-ID: <20251218125034.248-1-kylebonnici@proton.me>

From: Kyle Bonnici <kylebonnici at hotmail.com>

- Convert hex value to lowercase
- align property values to ' = '
- clean up whitespaces
- fix indentation
- add new line between nodes

The changes are generated using the dts-linter.

This is just a sample of what the above tool can fix and this change is
intended to start the conversation on how I should suggest fixes to this repo
Without sending one big PR.

Also, this is my first attempt at such a submission. Hopefully I did not miss
Anything fundamental in the submission process.

Signed-off-by: Kyle Bonnici <kylebonnici at proton.me>
---
 arch/arm/boot/dts/xilinx/zynq-7000.dtsi       | 72 +++++++++++--------
 arch/arm/boot/dts/xilinx/zynq-cc108.dts       | 11 ++-
 arch/arm/boot/dts/xilinx/zynq-ebaz4205.dts    |  1 +
 arch/arm/boot/dts/xilinx/zynq-parallella.dts  |  7 +-
 arch/arm/boot/dts/xilinx/zynq-zc702.dts       | 17 +++++
 arch/arm/boot/dts/xilinx/zynq-zc706.dts       | 13 ++++
 arch/arm/boot/dts/xilinx/zynq-zc770-xm010.dts | 10 +++
 arch/arm/boot/dts/xilinx/zynq-zc770-xm011.dts |  5 ++
 arch/arm/boot/dts/xilinx/zynq-zc770-xm012.dts |  6 ++
 arch/arm/boot/dts/xilinx/zynq-zc770-xm013.dts |  8 +++
 arch/arm/boot/dts/xilinx/zynq-zed.dts         |  7 ++
 .../boot/dts/xilinx/zynq-zturn-common.dtsi    |  5 +-
 12 files changed, 126 insertions(+), 36 deletions(-)

diff --git a/arch/arm/boot/dts/xilinx/zynq-7000.dtsi b/arch/arm/boot/dts/xilinx/zynq-7000.dtsi
index 153b8d93cbee..dd8a6528e8a7 100644
--- a/arch/arm/boot/dts/xilinx/zynq-7000.dtsi
+++ b/arch/arm/boot/dts/xilinx/zynq-7000.dtsi
@@ -27,10 +27,9 @@ cpu0: cpu at 0 {
 			clock-latency = <1000>;
 			cpu0-supply = <&regulator_vccpint>;
 			operating-points = <
-				/* kHz    uV */
-				666667  1000000
-				333334  1000000
-			>;
+					    /* kHz    uV */
+					    666667 1000000
+					    333334 1000000>;
 		};
 
 		cpu1: cpu at 1 {
@@ -78,17 +77,21 @@ out-ports {
 			/* replicator output ports */
 			port at 0 {
 				reg = <0>;
+
 				replicator_out_port0: endpoint {
 					remote-endpoint = <&tpiu_in_port>;
 				};
 			};
+
 			port at 1 {
 				reg = <1>;
+
 				replicator_out_port1: endpoint {
 					remote-endpoint = <&etb_in_port>;
 				};
 			};
 		};
+
 		in-ports {
 			/* replicator input port */
 			port {
@@ -179,13 +182,13 @@ intc: interrupt-controller at f8f01000 {
 			compatible = "arm,cortex-a9-gic";
 			#interrupt-cells = <3>;
 			interrupt-controller;
-			reg = <0xF8F01000 0x1000>,
-			      <0xF8F00100 0x100>;
+			reg = <0xf8f01000 0x1000>,
+			      <0xf8f00100 0x100>;
 		};
 
 		L2: cache-controller at f8f02000 {
 			compatible = "arm,pl310-cache";
-			reg = <0xF8F02000 0x1000>;
+			reg = <0xf8f02000 0x1000>;
 			interrupts = <0 2 4>;
 			arm,data-latency = <3 2 2>;
 			arm,tag-latency = <2 2 2>;
@@ -204,6 +207,7 @@ ocm: sram at fffc0000 {
 			#address-cells = <1>;
 			#size-cells = <1>;
 			ranges = <0 0xfffc0000 0x10000>;
+
 			ocm-sram at 0 {
 				reg = <0x0 0x10000>;
 			};
@@ -214,7 +218,7 @@ uart0: serial at e0000000 {
 			status = "disabled";
 			clocks = <&clkc 23>, <&clkc 40>;
 			clock-names = "uart_clk", "pclk";
-			reg = <0xE0000000 0x1000>;
+			reg = <0xe0000000 0x1000>;
 			interrupts = <0 27 4>;
 		};
 
@@ -223,7 +227,7 @@ uart1: serial at e0001000 {
 			status = "disabled";
 			clocks = <&clkc 24>, <&clkc 41>;
 			clock-names = "uart_clk", "pclk";
-			reg = <0xE0001000 0x1000>;
+			reg = <0xe0001000 0x1000>;
 			interrupts = <0 50 4>;
 		};
 
@@ -304,6 +308,7 @@ nfc0: nand-controller at 0,0 {
 				reg = <0 0 0x1000000>;
 				status = "disabled";
 			};
+
 			nor0: flash at 1,0 {
 				status = "disabled";
 				compatible = "cfi-flash";
@@ -336,24 +341,26 @@ slcr: slcr at f8000000 {
 			#address-cells = <1>;
 			#size-cells = <1>;
 			compatible = "xlnx,zynq-slcr", "syscon", "simple-mfd";
-			reg = <0xF8000000 0x1000>;
+			reg = <0xf8000000 0x1000>;
 			ranges;
+
 			clkc: clkc at 100 {
 				bootph-all;
 				#clock-cells = <1>;
 				compatible = "xlnx,ps7-clkc";
 				fclk-enable = <0>;
 				clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x",
-						"cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x",
-						"dci", "lqspi", "smc", "pcap", "gem0", "gem1",
-						"fclk0", "fclk1", "fclk2", "fclk3", "can0", "can1",
-						"sdio0", "sdio1", "uart0", "uart1", "spi0", "spi1",
-						"dma", "usb0_aper", "usb1_aper", "gem0_aper",
-						"gem1_aper", "sdio0_aper", "sdio1_aper",
-						"spi0_aper", "spi1_aper", "can0_aper", "can1_aper",
-						"i2c0_aper", "i2c1_aper", "uart0_aper", "uart1_aper",
-						"gpio_aper", "lqspi_aper", "smc_aper", "swdt",
-						"dbg_trc", "dbg_apb";
+						     "cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x",
+						     "ddr3x", "dci", "lqspi", "smc", "pcap", "gem0",
+						     "gem1", "fclk0", "fclk1", "fclk2", "fclk3",
+						     "can0", "can1", "sdio0", "sdio1", "uart0",
+						     "uart1", "spi0", "spi1", "dma", "usb0_aper",
+						     "usb1_aper", "gem0_aper", "gem1_aper",
+						     "sdio0_aper", "sdio1_aper", "spi0_aper",
+						     "spi1_aper", "can0_aper", "can1_aper",
+						     "i2c0_aper", "i2c1_aper", "uart0_aper",
+						     "uart1_aper", "gpio_aper", "lqspi_aper",
+						     "smc_aper", "swdt", "dbg_trc", "dbg_apb";
 				reg = <0x100 0x100>;
 			};
 
@@ -380,10 +387,10 @@ dmac_s: dma-controller at f8003000 {
 			 * "dma4", "dma5", "dma6", "dma7";
 			 */
 			interrupts = <0 13 4>,
-			             <0 14 4>, <0 15 4>,
-			             <0 16 4>, <0 17 4>,
-			             <0 40 4>, <0 41 4>,
-			             <0 42 4>, <0 43 4>;
+				     <0 14 4>, <0 15 4>,
+				     <0 16 4>, <0 17 4>,
+				     <0 40 4>, <0 41 4>,
+				     <0 42 4>, <0 43 4>;
 			#dma-cells = <1>;
 			clocks = <&clkc 27>;
 			clock-names = "apb_pclk";
@@ -412,7 +419,7 @@ ttc0: timer at f8001000 {
 			interrupts = <0 10 4>, <0 11 4>, <0 12 4>;
 			compatible = "cdns,ttc";
 			clocks = <&clkc 6>;
-			reg = <0xF8001000 0x1000>;
+			reg = <0xf8001000 0x1000>;
 		};
 
 		ttc1: timer at f8002000 {
@@ -420,7 +427,7 @@ ttc1: timer at f8002000 {
 			interrupts = <0 37 4>, <0 38 4>, <0 39 4>;
 			compatible = "cdns,ttc";
 			clocks = <&clkc 6>;
-			reg = <0xF8002000 0x1000>;
+			reg = <0xf8002000 0x1000>;
 		};
 
 		scutimer: timer at f8f00600 {
@@ -466,6 +473,7 @@ etb at f8801000 {
 			reg = <0xf8801000 0x1000>;
 			clocks = <&clkc 27>, <&clkc 46>, <&clkc 47>;
 			clock-names = "apb_pclk", "dbg_trc", "dbg_apb";
+
 			in-ports {
 				port {
 					etb_in_port: endpoint {
@@ -480,6 +488,7 @@ tpiu at f8803000 {
 			reg = <0xf8803000 0x1000>;
 			clocks = <&clkc 27>, <&clkc 46>, <&clkc 47>;
 			clock-names = "apb_pclk", "dbg_trc", "dbg_apb";
+
 			in-ports {
 				port {
 					tpiu_in_port: endpoint {
@@ -499,8 +508,7 @@ funnel at f8804000 {
 			out-ports {
 				port {
 					funnel_out_port: endpoint {
-						remote-endpoint =
-							<&replicator_in_port0>;
+						remote-endpoint = <&replicator_in_port0>;
 					};
 				};
 			};
@@ -512,6 +520,7 @@ in-ports {
 				/* funnel input ports */
 				port at 0 {
 					reg = <0>;
+
 					funnel0_in_port0: endpoint {
 						remote-endpoint = <&ptm0_out_port>;
 					};
@@ -519,6 +528,7 @@ funnel0_in_port0: endpoint {
 
 				port at 1 {
 					reg = <1>;
+
 					funnel0_in_port1: endpoint {
 						remote-endpoint = <&ptm1_out_port>;
 					};
@@ -526,8 +536,8 @@ funnel0_in_port1: endpoint {
 
 				port at 2 {
 					reg = <2>;
-					funnel0_in_port2: endpoint {
-					};
+
+					funnel0_in_port2: endpoint {};
 				};
 				/* The other input ports are not connect to anything */
 			};
@@ -539,6 +549,7 @@ ptm at f889c000 {
 			clocks = <&clkc 27>, <&clkc 46>, <&clkc 47>;
 			clock-names = "apb_pclk", "dbg_trc", "dbg_apb";
 			cpu = <&cpu0>;
+
 			out-ports {
 				port {
 					ptm0_out_port: endpoint {
@@ -554,6 +565,7 @@ ptm at f889d000 {
 			clocks = <&clkc 27>, <&clkc 46>, <&clkc 47>;
 			clock-names = "apb_pclk", "dbg_trc", "dbg_apb";
 			cpu = <&cpu1>;
+
 			out-ports {
 				port {
 					ptm1_out_port: endpoint {
diff --git a/arch/arm/boot/dts/xilinx/zynq-cc108.dts b/arch/arm/boot/dts/xilinx/zynq-cc108.dts
index f5525c048426..25828ba9fa16 100644
--- a/arch/arm/boot/dts/xilinx/zynq-cc108.dts
+++ b/arch/arm/boot/dts/xilinx/zynq-cc108.dts
@@ -55,6 +55,7 @@ ethernet_phy: ethernet-phy at 1 {
 &qspi {
 	status = "okay";
 	num-cs = <1>;
+
 	flash at 0 { /* 16 MB */
 		compatible = "jedec,spi-nor";
 		reg = <0x0>;
@@ -63,26 +64,32 @@ flash at 0 { /* 16 MB */
 		spi-rx-bus-width = <4>;
 		#address-cells = <1>;
 		#size-cells = <1>;
+
 		partition at 0 {
 			label = "qspi-fsbl-uboot-bs";
 			reg = <0x0 0x400000>; /* 4MB */
 		};
+
 		partition at 400000 {
 			label = "qspi-linux";
 			reg = <0x400000 0x400000>; /* 4MB */
 		};
+
 		partition at 800000 {
 			label = "qspi-rootfs";
 			reg = <0x800000 0x400000>; /* 4MB */
 		};
+
 		partition at c00000 {
 			label = "qspi-devicetree";
 			reg = <0xc00000 0x100000>; /* 1MB */
 		};
+
 		partition at d00000 {
 			label = "qspi-scratch";
 			reg = <0xd00000 0x200000>; /* 2MB */
 		};
+
 		partition at f00000 {
 			label = "qspi-uboot-env";
 			reg = <0xf00000 0x100000>; /* 1MB */
@@ -92,8 +99,8 @@ partition at f00000 {
 
 &sdhci1 {
 	status = "okay";
-	broken-cd ;
-	wp-inverted ;
+	broken-cd;
+	wp-inverted;
 };
 
 &uart0 {
diff --git a/arch/arm/boot/dts/xilinx/zynq-ebaz4205.dts b/arch/arm/boot/dts/xilinx/zynq-ebaz4205.dts
index 14f644156a6f..d4c07d28ec25 100644
--- a/arch/arm/boot/dts/xilinx/zynq-ebaz4205.dts
+++ b/arch/arm/boot/dts/xilinx/zynq-ebaz4205.dts
@@ -53,6 +53,7 @@ &nfc0 {
 
 	#address-cells = <1>;
 	#size-cells = <0>;
+
 	nand at 0 {
 		reg = <0>;
 	};
diff --git a/arch/arm/boot/dts/xilinx/zynq-parallella.dts b/arch/arm/boot/dts/xilinx/zynq-parallella.dts
index 366af4fcf8d9..e498feaa7ca4 100644
--- a/arch/arm/boot/dts/xilinx/zynq-parallella.dts
+++ b/arch/arm/boot/dts/xilinx/zynq-parallella.dts
@@ -44,10 +44,10 @@ &gem0 {
 	ethernet_phy: ethernet-phy at 0 {
 		/* Marvell 88E1318 */
 		compatible = "ethernet-phy-id0141.0e90",
-		             "ethernet-phy-ieee802.3-c22";
+			     "ethernet-phy-ieee802.3-c22";
 		reg = <0>;
 		marvell,reg-init = <0x3 0x10 0xff00 0x1e>,
-		                   <0x3 0x11 0xfff0 0xa>;
+				   <0x3 0x11 0xfff0 0xa>;
 	};
 };
 
@@ -63,13 +63,16 @@ dcd1 {
 				regulator-name = "VDD_DSP";
 				regulator-always-on;
 			};
+
 			dcd2 {
 				regulator-name = "1P35V";
 				regulator-always-on;
 			};
+
 			ldo1 {
 				regulator-name = "VDD_ADJ";
 			};
+
 			ldo2 {
 				regulator-name = "VDD_GPIO";
 				regulator-always-on;
diff --git a/arch/arm/boot/dts/xilinx/zynq-zc702.dts b/arch/arm/boot/dts/xilinx/zynq-zc702.dts
index 6955637c5b1a..63eded827b37 100644
--- a/arch/arm/boot/dts/xilinx/zynq-zc702.dts
+++ b/arch/arm/boot/dts/xilinx/zynq-zc702.dts
@@ -34,6 +34,7 @@ chosen {
 	gpio-keys {
 		compatible = "gpio-keys";
 		autorepeat;
+
 		switch-14 {
 			label = "sw14";
 			gpios = <&gpio0 12 0>;
@@ -41,6 +42,7 @@ switch-14 {
 			wakeup-source;
 			autorepeat;
 		};
+
 		switch-13 {
 			label = "sw13";
 			gpios = <&gpio0 14 0>;
@@ -112,6 +114,7 @@ i2c at 0 {
 			#address-cells = <1>;
 			#size-cells = <0>;
 			reg = <0>;
+
 			si570: clock-generator at 5d {
 				#clock-cells = <0>;
 				compatible = "silabs,si570";
@@ -126,6 +129,7 @@ i2c at 1 {
 			#address-cells = <1>;
 			#size-cells = <0>;
 			reg = <1>;
+
 			adv7511: hdmi-tx at 39 {
 				compatible = "adi,adv7511";
 				reg = <0x39>;
@@ -141,6 +145,7 @@ i2c at 2 {
 			#address-cells = <1>;
 			#size-cells = <0>;
 			reg = <2>;
+
 			eeprom: eeprom at 54 {
 				compatible = "atmel,24c08";
 				reg = <0x54>;
@@ -151,6 +156,7 @@ i2c at 3 {
 			#address-cells = <1>;
 			#size-cells = <0>;
 			reg = <3>;
+
 			gpio at 21 {
 				compatible = "ti,tca6416";
 				reg = <0x21>;
@@ -163,6 +169,7 @@ i2c at 4 {
 			#address-cells = <1>;
 			#size-cells = <0>;
 			reg = <4>;
+
 			rtc: rtc at 51 {
 				compatible = "nxp,pcf8563";
 				reg = <0x51>;
@@ -173,14 +180,17 @@ i2c at 7 {
 			#address-cells = <1>;
 			#size-cells = <0>;
 			reg = <7>;
+
 			hwmon at 34 {
 				compatible = "ti,ucd9248";
 				reg = <0x34>;
 			};
+
 			hwmon at 35 {
 				compatible = "ti,ucd9248";
 				reg = <0x35>;
 			};
+
 			hwmon at 36 {
 				compatible = "ti,ucd9248";
 				reg = <0x36>;
@@ -396,32 +406,39 @@ &qspi {
 	bootph-all;
 	status = "okay";
 	num-cs = <1>;
+
 	flash at 0 {
 		compatible = "jedec,spi-nor";
 		reg = <0x0>;
 		spi-tx-bus-width = <1>;
 		spi-rx-bus-width = <4>;
 		spi-max-frequency = <50000000>;
+
 		partitions {
 			compatible = "fixed-partitions";
 			#address-cells = <1>;
 			#size-cells = <1>;
+
 			partition at 0 {
 				label = "qspi-fsbl-uboot";
 				reg = <0x0 0x100000>;
 			};
+
 			partition at 100000 {
 				label = "qspi-linux";
 				reg = <0x100000 0x500000>;
 			};
+
 			partition at 600000 {
 				label = "qspi-device-tree";
 				reg = <0x600000 0x20000>;
 			};
+
 			partition at 620000 {
 				label = "qspi-rootfs";
 				reg = <0x620000 0x5e0000>;
 			};
+
 			partition at c00000 {
 				label = "qspi-bitstream";
 				reg = <0xc00000 0x400000>;
diff --git a/arch/arm/boot/dts/xilinx/zynq-zc706.dts b/arch/arm/boot/dts/xilinx/zynq-zc706.dts
index 3b803c698473..d6447e544d8f 100644
--- a/arch/arm/boot/dts/xilinx/zynq-zc706.dts
+++ b/arch/arm/boot/dts/xilinx/zynq-zc706.dts
@@ -73,6 +73,7 @@ i2c at 0 {
 			#address-cells = <1>;
 			#size-cells = <0>;
 			reg = <0>;
+
 			si570: clock-generator at 5d {
 				#clock-cells = <0>;
 				compatible = "silabs,si570";
@@ -87,6 +88,7 @@ i2c at 1 {
 			#address-cells = <1>;
 			#size-cells = <0>;
 			reg = <1>;
+
 			adv7511: hdmi-tx at 39 {
 				compatible = "adi,adv7511";
 				reg = <0x39>;
@@ -102,6 +104,7 @@ i2c at 2 {
 			#address-cells = <1>;
 			#size-cells = <0>;
 			reg = <2>;
+
 			eeprom: eeprom at 54 {
 				compatible = "atmel,24c08";
 				reg = <0x54>;
@@ -112,6 +115,7 @@ i2c at 3 {
 			#address-cells = <1>;
 			#size-cells = <0>;
 			reg = <3>;
+
 			gpio at 21 {
 				compatible = "ti,tca6416";
 				reg = <0x21>;
@@ -124,6 +128,7 @@ i2c at 4 {
 			#address-cells = <1>;
 			#size-cells = <0>;
 			reg = <4>;
+
 			rtc: rtc at 51 {
 				compatible = "nxp,pcf8563";
 				reg = <0x51>;
@@ -134,6 +139,7 @@ i2c at 7 {
 			#address-cells = <1>;
 			#size-cells = <0>;
 			reg = <7>;
+
 			ucd90120 at 65 {
 				compatible = "ti,ucd90120";
 				reg = <0x65>;
@@ -309,6 +315,7 @@ &qspi {
 	bootph-all;
 	status = "okay";
 	num-cs = <2>;
+
 	flash at 0 {
 		compatible = "jedec,spi-nor";
 		reg = <0>, <1>;
@@ -316,26 +323,32 @@ flash at 0 {
 		spi-tx-bus-width = <1>;
 		spi-rx-bus-width = <4>;
 		spi-max-frequency = <50000000>;
+
 		partitions {
 			compatible = "fixed-partitions";
 			#address-cells = <1>;
 			#size-cells = <1>;
+
 			partition at 0 {
 				label = "qspi-fsbl-uboot";
 				reg = <0x0 0x100000>;
 			};
+
 			partition at 100000 {
 				label = "qspi-linux";
 				reg = <0x100000 0x500000>;
 			};
+
 			partition at 600000 {
 				label = "qspi-device-tree";
 				reg = <0x600000 0x20000>;
 			};
+
 			partition at 620000 {
 				label = "qspi-rootfs";
 				reg = <0x620000 0x5e0000>;
 			};
+
 			partition at c00000 {
 				label = "qspi-bitstream";
 				reg = <0xc00000 0x400000>;
diff --git a/arch/arm/boot/dts/xilinx/zynq-zc770-xm010.dts b/arch/arm/boot/dts/xilinx/zynq-zc770-xm010.dts
index 5fe799c3c7cf..4929a5aa1678 100644
--- a/arch/arm/boot/dts/xilinx/zynq-zc770-xm010.dts
+++ b/arch/arm/boot/dts/xilinx/zynq-zc770-xm010.dts
@@ -62,32 +62,39 @@ eeprom: eeprom at 52 {
 &qspi {
 	status = "okay";
 	num-cs = <1>;
+
 	flash at 0 {
 		compatible = "jedec,spi-nor";
 		reg = <0x0>;
 		spi-tx-bus-width = <1>;
 		spi-rx-bus-width = <4>;
 		spi-max-frequency = <50000000>;
+
 		partitions {
 			compatible = "fixed-partitions";
 			#address-cells = <1>;
 			#size-cells = <1>;
+
 			partition at 0 {
 				label = "qspi-fsbl-uboot";
 				reg = <0x0 0x100000>;
 			};
+
 			partition at 100000 {
 				label = "qspi-linux";
 				reg = <0x100000 0x500000>;
 			};
+
 			partition at 600000 {
 				label = "qspi-device-tree";
 				reg = <0x600000 0x20000>;
 			};
+
 			partition at 620000 {
 				label = "qspi-rootfs";
 				reg = <0x620000 0x5e0000>;
 			};
+
 			partition at c00000 {
 				label = "qspi-bitstream";
 				reg = <0xc00000 0x400000>;
@@ -104,14 +111,17 @@ &spi1 {
 	status = "okay";
 	num-cs = <4>;
 	is-decoded-cs = <0>;
+
 	flash at 1 {
 		compatible = "sst25wf080", "jedec,spi-nor";
 		reg = <1>;
 		spi-max-frequency = <1000000>;
+
 		partitions {
 			compatible = "fixed-partitions";
 			#address-cells = <1>;
 			#size-cells = <1>;
+
 			partition at 0 {
 				label = "data";
 				reg = <0x0 0x100000>;
diff --git a/arch/arm/boot/dts/xilinx/zynq-zc770-xm011.dts b/arch/arm/boot/dts/xilinx/zynq-zc770-xm011.dts
index f9a086fe66d3..d4e739772d7b 100644
--- a/arch/arm/boot/dts/xilinx/zynq-zc770-xm011.dts
+++ b/arch/arm/boot/dts/xilinx/zynq-zc770-xm011.dts
@@ -51,20 +51,25 @@ &nfc0 {
 	status = "okay";
 	#address-cells = <1>;
 	#size-cells = <0>;
+
 	nand at 0 {
 		reg = <0>;
+
 		partitions {
 			compatible = "fixed-partitions";
 			#address-cells = <1>;
 			#size-cells = <1>;
+
 			partition at 0 {
 				label = "nand-fsbl-uboot";
 				reg = <0x0 0x1000000>;
 			};
+
 			partition at 1000000 {
 				label = "nand-linux";
 				reg = <0x1000000 0x2000000>;
 			};
+
 			partition at 3000000 {
 				label = "nand-rootfs";
 				reg = <0x3000000 0x200000>;
diff --git a/arch/arm/boot/dts/xilinx/zynq-zc770-xm012.dts b/arch/arm/boot/dts/xilinx/zynq-zc770-xm012.dts
index 24520e7d3965..32422aed77a3 100644
--- a/arch/arm/boot/dts/xilinx/zynq-zc770-xm012.dts
+++ b/arch/arm/boot/dts/xilinx/zynq-zc770-xm012.dts
@@ -56,26 +56,32 @@ eeprom1: eeprom at 52 {
 &nor0 {
 	status = "okay";
 	bank-width = <1>;
+
 	partitions {
 		compatible = "fixed-partitions";
 		#address-cells = <1>;
 		#size-cells = <1>;
+
 		partition at 0 {
 			label = "nor-fsbl-uboot";
 			reg = <0x0 0x100000>;
 		};
+
 		partition at 100000 {
 			label = "nor-linux";
 			reg = <0x100000 0x500000>;
 		};
+
 		partition at 600000 {
 			label = "nor-device-tree";
 			reg = <0x600000 0x20000>;
 		};
+
 		partition at 620000 {
 			label = "nor-rootfs";
 			reg = <0x620000 0x5e0000>;
 		};
+
 		partition at c00000 {
 			label = "nor-bitstream";
 			reg = <0xc00000 0x400000>;
diff --git a/arch/arm/boot/dts/xilinx/zynq-zc770-xm013.dts b/arch/arm/boot/dts/xilinx/zynq-zc770-xm013.dts
index 103e87ea7253..9c94421bf650 100644
--- a/arch/arm/boot/dts/xilinx/zynq-zc770-xm013.dts
+++ b/arch/arm/boot/dts/xilinx/zynq-zc770-xm013.dts
@@ -61,6 +61,7 @@ si570: clock-generator at 55 {
 &qspi {
 	status = "okay";
 	num-cs = <2>;
+
 	flash at 0 {
 		compatible = "jedec,spi-nor";
 		reg = <0>, <1>;
@@ -68,26 +69,32 @@ flash at 0 {
 		spi-tx-bus-width = <1>;
 		spi-rx-bus-width = <4>;
 		spi-max-frequency = <50000000>;
+
 		partitions {
 			compatible = "fixed-partitions";
 			#address-cells = <1>;
 			#size-cells = <1>;
+
 			partition at 0 {
 				label = "qspi-fsbl-uboot";
 				reg = <0x0 0x100000>;
 			};
+
 			partition at 100000 {
 				label = "qspi-linux";
 				reg = <0x100000 0x500000>;
 			};
+
 			partition at 600000 {
 				label = "qspi-device-tree";
 				reg = <0x600000 0x20000>;
 			};
+
 			partition at 620000 {
 				label = "qspi-rootfs";
 				reg = <0x620000 0x5e0000>;
 			};
+
 			partition at c00000 {
 				label = "qspi-bitstream";
 				reg = <0xc00000 0x400000>;
@@ -100,6 +107,7 @@ &spi0 {
 	status = "okay";
 	num-cs = <4>;
 	is-decoded-cs = <0>;
+
 	eeprom: eeprom at 2 {
 		compatible = "atmel,at25";
 		reg = <2>;
diff --git a/arch/arm/boot/dts/xilinx/zynq-zed.dts b/arch/arm/boot/dts/xilinx/zynq-zed.dts
index 52ba569b2b9f..dd46d71e3f36 100644
--- a/arch/arm/boot/dts/xilinx/zynq-zed.dts
+++ b/arch/arm/boot/dts/xilinx/zynq-zed.dts
@@ -51,6 +51,7 @@ &qspi {
 	bootph-all;
 	status = "okay";
 	num-cs = <1>;
+
 	flash at 0 {
 		compatible = "jedec,spi-nor";
 		reg = <0>;
@@ -58,26 +59,32 @@ flash at 0 {
 		spi-rx-bus-width = <4>;
 		spi-max-frequency = <50000000>;
 		m25p,fast-read;
+
 		partitions {
 			compatible = "fixed-partitions";
 			#address-cells = <1>;
 			#size-cells = <1>;
+
 			partition at 0 {
 				label = "qspi-fsbl-uboot";
 				reg = <0x0 0x100000>;
 			};
+
 			partition at 100000 {
 				label = "qspi-linux";
 				reg = <0x100000 0x500000>;
 			};
+
 			partition at 600000 {
 				label = "qspi-device-tree";
 				reg = <0x600000 0x20000>;
 			};
+
 			partition at 620000 {
 				label = "qspi-rootfs";
 				reg = <0x620000 0x5e0000>;
 			};
+
 			partition at c00000 {
 				label = "qspi-bitstream";
 				reg = <0xc00000 0x400000>;
diff --git a/arch/arm/boot/dts/xilinx/zynq-zturn-common.dtsi b/arch/arm/boot/dts/xilinx/zynq-zturn-common.dtsi
index defef9c8da13..57e6cda1a798 100644
--- a/arch/arm/boot/dts/xilinx/zynq-zturn-common.dtsi
+++ b/arch/arm/boot/dts/xilinx/zynq-zturn-common.dtsi
@@ -33,6 +33,7 @@ chosen {
 
 	gpio-leds {
 		compatible = "gpio-leds";
+
 		usr-led1 {
 			label = "usr-led1";
 			gpios = <&gpio0 0x0 0x1>;
@@ -49,6 +50,7 @@ usr-led2 {
 	gpio-keys {
 		compatible = "gpio-keys";
 		autorepeat;
+
 		key {
 			label = "K1";
 			gpios = <&gpio0 0x32 0x1>;
@@ -73,8 +75,7 @@ &gem0 {
 	phy-mode = "rgmii-id";
 	phy-handle = <&ethernet_phy>;
 
-	ethernet_phy: ethernet-phy at 0 {
-	};
+	ethernet_phy: ethernet-phy at 0 {};
 };
 
 &sdhci0 {
-- 
2.50.1 (Apple Git-155)




From a.fatoum at pengutronix.de  Thu Dec 18 04:52:37 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Thu, 18 Dec 2025 13:52:37 +0100
Subject: [PATCH v4 0/2] Add devicetree for NXP i.MX93 FRDM board
In-Reply-To: <20251218-fpg-nxp-imx93-frdm-v4-0-cd3a9f6ac89a@pengutronix.de>
References: <20251218-fpg-nxp-imx93-frdm-v4-0-cd3a9f6ac89a@pengutronix.de>
Message-ID: <9a96f664-00ba-4589-b3b8-a04355c0ad0b@pengutronix.de>

Hello Fabian,

On 12/18/25 12:39 PM, Fabian Pflug wrote:
> Signed-off-by: Fabian Pflug <f.pflug at pengutronix.de>
> ---
> Changes in v4:
> - remove it6263 block in i2c1, since it is not finished
> - remove usdhc3 pwrsequence, since WLAN is not tested on my board
> - remove eee-broken-1000t on phy2, since it is not broken
> - update min/max-microvlt on buck converters

I know you changed this due to reviewer feedback, but it was wrong
advice. The Linux driver already has information about the minimum and
maximum range support for the PMIC, what you need to write here is the
actual board-level constraints.

I don't think the board will like VDD_3V3 at 1.62V or VDD_1V8 at 3.4V.
For the fixed voltage rails just set min = max = fixed voltage.

Thanks,
Ahmad

> - Link to v3: https://lore.kernel.org/r/20251022-fpg-nxp-imx93-frdm-v3-0-03ec40a1ccc0 at pengutronix.de
> 
> Changes in v3:
> - Add Signed-off for original NXP contributors.
> - Fixed whitespace errors (Thanks Francesco Valla)
> - Added mu1 with status okay (Thanks Francesco Valla)
> - Removed address cells from lpi2c3 (Thanks Frank Li)
> - Configure pin for watchdog (Thanks Peng Fan)
> - Updated regulator config
> - Configure i2c0
> - Link to v2: https://lore.kernel.org/r/20250526-fpg-nxp-imx93-frdm-v2-0-e5ad0efaec33 at pengutronix.de
> 
> Changes in v2:
> - 1/2: remove CAN node, as it has not been tested.
> - 1/2: ran dt-format (Thanks Frank Li)
> 	But also reordered some nodes afterwards again to have
> 	regulator-min before regulator-max, have the pinmux at the end
> 	of the file, and have the regulator-name as the first node
> 	inside the regulators.
> 	Re-added comments, that were deleted.
> - 1/2: changes subjet to ar64:dts (Thanks Fabio Estevan)
> - 1/2: removed reg_vdd_12v (Tanks Fabio Estevan)
> - 1/2: added aliases for rtc, emmc, serial (Thanks Fabio Estevan)
> - reordered the series to have documentation before dts. (Thanks
>   Krzystof Kozlowski)
> - Link to v1: https://lore.kernel.org/r/20250523-fpg-nxp-imx93-frdm-v1-0-546b2d342855 at pengutronix.de
> 
> ---
> Fabian Pflug (2):
>       dt-bindings: arm: fsl: add i.MX93 11x11 FRDM board
>       arm64: dts: freescale: add support for NXP i.MX93 FRDM
> 
>  Documentation/devicetree/bindings/arm/fsl.yaml     |   1 +
>  arch/arm64/boot/dts/freescale/Makefile             |   1 +
>  arch/arm64/boot/dts/freescale/imx93-11x11-frdm.dts | 620 +++++++++++++++++++++
>  3 files changed, 622 insertions(+)
> ---
> base-commit: ea1013c1539270e372fc99854bc6e4d94eaeff66
> change-id: 20250523-fpg-nxp-imx93-frdm-5cc180a1fda9
> 
> Best regards,

-- 
Pengutronix e.K.                  |                             |
Steuerwalder Str. 21              | http://www.pengutronix.de/  |
31137 Hildesheim, Germany         | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686  | Fax:   +49-5121-206917-5555 |



From nicolas.frattaroli at collabora.com  Thu Dec 18 04:54:50 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 18 Dec 2025 13:54:50 +0100
Subject: [PATCH v4 00/25] MediaTek UFS Cleanup and MT8196 Enablement
Message-ID: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>

In this series, the existing MediaTek UFS binding is expanded and
completed to correctly describe not just the existing compatibles, but
also to introduce a new compatible in the from of the MT8196 SoC.

The resets, which until now were completely absent from both the UFS
host controller binding and the UFS PHY binding, are introduced to both.
This also means the driver's undocumented and, in mainline, unused reset
logic is reworked. In particular, the PHY reset is no longer a reset of
the host controller node, but of the PHY node.

This means the host controller can reset the PHY through the common PHY
framework.

The resets remain optional.

Additionally, a massive number of driver cleanups are introduced. These
were prompted by me inspecting the driver more closely as I was
adjusting it to correspond to the binding.

The driver still implements vendor properties that are undocumented in
the binding. I did not touch most of those, as I neither want to
convince the bindings maintainers that they are needed without knowing
precisely what they're for, nor do I want to argue with the driver
authors when removing them.

Due to the "Marie Kondo with a chainsaw" nature of the driver cleanup
patches, I humbly request that reviewers do not comment on displeasing
code they see in the context portion of a patch before they've read the
whole patch series, as that displeasing code may in fact be reworked in
a subsequent patch of this series. Please keep comments focused on the
changed lines of the diff; I know there's more that can be done, but it
doesn't necessarily need to be part of this series.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
Changes in v4:
- bindings: Redo the supply situation, as the avdd pins don't describe
  the vcc(q2) card supplies.
- bindings: format clock in mt8196 example more tersely.
- phy: use devm_reset_control_get_optional_exclusive directly
- driver: get and enable/disable the aforementioned avdd supplies.
- Link to v3: https://lore.kernel.org/r/20251023-mt8196-ufs-v3-0-0f04b4a795ff at collabora.com

Changes in v3:
- Split mediatek,ufs bindings change into two patches, one for
  completing the existing binding, one for the MT8196
- Add over a dozen driver cleanup patches
- Add explicit support for the MT8196 compatible to the driver
- Note: next-20251023, on which I based this, currently has a broken
  build due to an unrelated OPP core change that was merged with no
  build testing. I can't use next-20251022 either, as that lacks the
  recent mediatek UFS changes. It is what it is.
- Link to v2: https://lore.kernel.org/r/20251016-mt8196-ufs-v2-0-c373834c4e7a at collabora.com

Changes in v2:
- Reorder define in mtk_sip_svc.h
- Use bulk reset APIs in UFS host driver
- Link to v1: https://lore.kernel.org/r/20251014-mt8196-ufs-v1-0-195dceb83bc8 at collabora.com

---
Nicolas Frattaroli (25):
      dt-bindings: phy: Add mediatek,mt8196-ufsphy variant
      dt-bindings: ufs: mediatek,ufs: Complete the binding
      dt-bindings: ufs: mediatek,ufs: Add mt8196 variant
      scsi: ufs: mediatek: Move MTK_SIP_UFS_CONTROL to mtk_sip_svc.h
      phy: mediatek: ufs: Add support for resets
      scsi: ufs: mediatek: Rework resets
      scsi: ufs: mediatek: Rework 0.9V regulator
      scsi: ufs: mediatek: Rework init function
      scsi: ufs: mediatek: Rework the crypt-boost stuff
      scsi: ufs: mediatek: Handle misc host voltage regulators
      scsi: ufs: mediatek: Rework probe function
      scsi: ufs: mediatek: Remove vendor kernel quirks cruft
      scsi: ufs: mediatek: Use the common PHY framework
      scsi: ufs: mediatek: Switch to newer PM ops helpers
      scsi: ufs: mediatek: Remove mediatek,ufs-broken-rtc property
      scsi: ufs: mediatek: Rework _ufs_mtk_clk_scale error paths
      scsi: ufs: mediatek: Add vendor prefix to clk-scale-up-vcore-min
      scsi: ufs: mediatek: Clean up logging prints
      scsi: ufs: mediatek: Rework ufs_mtk_wait_idle_state
      scsi: ufs: mediatek: Don't acquire dvfsrc-vcore twice
      scsi: ufs: mediatek: Rework hardware version reading
      scsi: ufs: mediatek: Back up idle timer in per-instance struct
      scsi: ufs: mediatek: Make scale_us in setup_clk_gating const
      scsi: ufs: mediatek: Remove ret local from link_startup_notify
      scsi: ufs: mediatek: Add MT8196 compatible, update copyright

 .../devicetree/bindings/phy/mediatek,ufs-phy.yaml  |  16 +
 .../devicetree/bindings/ufs/mediatek,ufs.yaml      | 173 +++-
 drivers/phy/mediatek/phy-mtk-ufs.c                 |  71 ++
 drivers/ufs/host/ufs-mediatek-sip.h                |   9 -
 drivers/ufs/host/ufs-mediatek.c                    | 996 +++++++++------------
 drivers/ufs/host/ufs-mediatek.h                    |  19 +-
 include/linux/soc/mediatek/mtk_sip_svc.h           |   3 +
 7 files changed, 690 insertions(+), 597 deletions(-)
---
base-commit: 3e7f562e20ee87a25e104ef4fce557d39d62fa85
change-id: 20251014-mt8196-ufs-cec4b9a97e53

Best regards,
-- 
Nicolas Frattaroli <nicolas.frattaroli at collabora.com>



From nicolas.frattaroli at collabora.com  Thu Dec 18 04:54:51 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 18 Dec 2025 13:54:51 +0100
Subject: [PATCH v4 01/25] dt-bindings: phy: Add mediatek,mt8196-ufsphy
 variant
In-Reply-To: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
Message-ID: <20251218-mt8196-ufs-v4-1-ddec7a369dd2@collabora.com>

The MediaTek MT8196 SoC includes an M-PHY compatible with the already
existing mt8183 binding.

However, one omission from the original binding was that all of these
variants may have an optional reset.

Add the new compatible, and also the resets property, with an example.

Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
Reviewed-by: Peter Wang <peter.wang at mediatek.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 .../devicetree/bindings/phy/mediatek,ufs-phy.yaml        | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/Documentation/devicetree/bindings/phy/mediatek,ufs-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,ufs-phy.yaml
index 6e2edd43fc2a..ee71dfa4e0c0 100644
--- a/Documentation/devicetree/bindings/phy/mediatek,ufs-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/mediatek,ufs-phy.yaml
@@ -27,6 +27,7 @@ properties:
       - items:
           - enum:
               - mediatek,mt8195-ufsphy
+              - mediatek,mt8196-ufsphy
           - const: mediatek,mt8183-ufsphy
       - const: mediatek,mt8183-ufsphy
 
@@ -43,6 +44,10 @@ properties:
       - const: unipro
       - const: mp
 
+  resets:
+    items:
+      - description: Optional UFS M-PHY reset.
+
   "#phy-cells":
     const: 0
 
@@ -66,5 +71,16 @@ examples:
         clock-names = "unipro", "mp";
         #phy-cells = <0>;
     };
+  - |
+    #include <dt-bindings/reset/mediatek,mt8196-resets.h>
+    ufs-phy at 16800000 {
+        compatible = "mediatek,mt8196-ufsphy", "mediatek,mt8183-ufsphy";
+        reg = <0x16800000 0x10000>;
+        clocks = <&ufs_ao_clk 3>,
+                 <&ufs_ao_clk 5>;
+        clock-names = "unipro", "mp";
+        resets = <&ufs_ao_clk MT8196_UFSAO_RST0_UFS_MPHY>;
+        #phy-cells = <0>;
+    };
 
 ...

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 18 04:54:52 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 18 Dec 2025 13:54:52 +0100
Subject: [PATCH v4 02/25] dt-bindings: ufs: mediatek,ufs: Complete the
 binding
In-Reply-To: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
Message-ID: <20251218-mt8196-ufs-v4-2-ddec7a369dd2@collabora.com>

As it stands, the mediatek,ufs.yaml binding is startlingly incomplete.
Its one example, which is the only real "user" of this binding in
mainline, uses the deprecated freq-table-hz property.

The resets, of which there are three optional ones, are completely
absent.

The clock description for MT8195 is incomplete, as is the one for
MT8192. It's not known if the one clock binding for MT8183 is even
correct, but I do not have access to the necessary code and
documentation to find this out myself.

The power supply situation is not much better; the binding describes one
required power supply, but it's the UFS card supply, not any of the
supplies feeding the controller silicon.

No second example is present in the binding, making verification
difficult.

Disallow freq-table-hz and move to operating-points-v2. It's fine to
break compatibility here, as the binding is currently unused and would
be impossible to correctly use in its current state.

Add the three resets and the corresponding reset-names property. These
resets appear to be optional, i.e. not required for the functioning of
the device.

Move the list of clock names out of the if condition, and expand it for
the confirmed clocks I could find by cross-referencing several clock
drivers. For MT8195, increase the minimum number of clocks to include
the crypt and rx_symbol ones, as they're internal to the SoC and should
always be present, and should therefore not be omitted.

MT8192 gets to have at least 3 clocks, as these were the ones I could
quickly confirm from a glance at various trees. I can't say this was an
exhaustive search though, but it's better than the current situation.

Properly document all supplies, with which pin name on the SoCs they
supply. Complete the example with them.

Also add a MT8195 example to the binding, using supply labels that I am
pretty sure would be the right ones for e.g. the Radxa NIO 12L.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 .../devicetree/bindings/ufs/mediatek,ufs.yaml      | 117 ++++++++++++++++++---
 1 file changed, 100 insertions(+), 17 deletions(-)

diff --git a/Documentation/devicetree/bindings/ufs/mediatek,ufs.yaml b/Documentation/devicetree/bindings/ufs/mediatek,ufs.yaml
index 15c347f5e660..e0aef3e5f56b 100644
--- a/Documentation/devicetree/bindings/ufs/mediatek,ufs.yaml
+++ b/Documentation/devicetree/bindings/ufs/mediatek,ufs.yaml
@@ -19,11 +19,28 @@ properties:
 
   clocks:
     minItems: 1
-    maxItems: 8
+    maxItems: 13
 
   clock-names:
     minItems: 1
-    maxItems: 8
+    items:
+      - const: ufs
+      - const: ufs_aes
+      - const: ufs_tick
+      - const: unipro_sysclk
+      - const: unipro_tick
+      - const: unipro_mp_bclk
+      - const: ufs_tx_symbol
+      - const: ufs_mem_sub
+      - const: crypt_mux
+      - const: crypt_lp
+      - const: crypt_perf
+      - const: ufs_rx_symbol0
+      - const: ufs_rx_symbol1
+
+  operating-points-v2: true
+
+  freq-table-hz: false
 
   phys:
     maxItems: 1
@@ -31,8 +48,36 @@ properties:
   reg:
     maxItems: 1
 
+  resets:
+    items:
+      - description: reset for the UniPro layer
+      - description: reset for the cryptography engine
+      - description: reset for the host controller
+
+  reset-names:
+    items:
+      - const: unipro
+      - const: crypto
+      - const: hci
+
+  avdd09-supply:
+    description: Phandle to the 0.9V supply powering the AVDD09_UFS pin
+
+  avdd12-supply:
+    description: Phandle to the 1.2V supply powering the AVDD12_UFS pin
+
+  avdd12-ckbuf-supply:
+    description: Phandle to the 1.2V supply powering the AVDD12_CKBUF_UFS pin
+
+  avdd18-supply:
+    description: Phandle to the 1.8V supply powering the AVDD18_UFS pin
+
   vcc-supply: true
 
+  vccq-supply: true
+
+  vccq2-supply: true
+
   mediatek,ufs-disable-mcq:
     $ref: /schemas/types.yaml#/definitions/flag
     description: The mask to disable MCQ (Multi-Circular Queue) for UFS host.
@@ -54,29 +99,41 @@ allOf:
       properties:
         compatible:
           contains:
-            enum:
-              - mediatek,mt8195-ufshci
+            const: mediatek,mt8183-ufshci
     then:
       properties:
         clocks:
-          minItems: 8
+          maxItems: 1
         clock-names:
           items:
             - const: ufs
-            - const: ufs_aes
-            - const: ufs_tick
-            - const: unipro_sysclk
-            - const: unipro_tick
-            - const: unipro_mp_bclk
-            - const: ufs_tx_symbol
-            - const: ufs_mem_sub
-    else:
+        avdd12-ckbuf-supply: false
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: mediatek,mt8192-ufshci
+    then:
       properties:
         clocks:
-          maxItems: 1
+          minItems: 3
+          maxItems: 3
+        clocks-names:
+          minItems: 3
+          maxItems: 3
+        avdd09-supply: false
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: mediatek,mt8195-ufshci
+    then:
+      properties:
+        clocks:
+          minItems: 13
         clock-names:
-          items:
-            - const: ufs
+          minItems: 13
+        avdd09-supply: false
 
 examples:
   - |
@@ -95,8 +152,34 @@ examples:
 
             clocks = <&infracfg_ao CLK_INFRA_UFS>;
             clock-names = "ufs";
-            freq-table-hz = <0 0>;
 
             vcc-supply = <&mt_pmic_vemc_ldo_reg>;
         };
     };
+  - |
+    ufshci at 11270000 {
+        compatible = "mediatek,mt8195-ufshci";
+        reg = <0x11270000 0x2300>;
+        interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
+        phys = <&ufsphy>;
+        clocks = <&infracfg_ao 63>, <&infracfg_ao 64>, <&infracfg_ao 65>,
+                 <&infracfg_ao 54>, <&infracfg_ao 55>,
+                 <&infracfg_ao 56>, <&infracfg_ao 90>,
+                 <&infracfg_ao 93>, <&topckgen 60>, <&topckgen 152>,
+                 <&topckgen 125>, <&topckgen 212>, <&topckgen 215>;
+        clock-names = "ufs", "ufs_aes", "ufs_tick",
+                      "unipro_sysclk", "unipro_tick",
+                      "unipro_mp_bclk", "ufs_tx_symbol",
+                      "ufs_mem_sub", "crypt_mux", "crypt_lp",
+                      "crypt_perf", "ufs_rx_symbol0", "ufs_rx_symbol1";
+
+        operating-points-v2 = <&ufs_opp_table>;
+
+        avdd12-supply = <&mt6359_vrf12_ldo_reg>;
+        avdd12-ckbuf-supply = <&mt6359_vbbck_ldo_reg>;
+        avdd18-supply = <&mt6359_vio18_ldo_reg>;
+        vcc-supply = <&mt6359_vemc_1_ldo_reg>;
+        vccq2-supply = <&mt6359_vufs_ldo_reg>;
+
+        mediatek,ufs-disable-mcq;
+    };

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 18 04:54:53 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 18 Dec 2025 13:54:53 +0100
Subject: [PATCH v4 03/25] dt-bindings: ufs: mediatek,ufs: Add mt8196
 variant
In-Reply-To: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
Message-ID: <20251218-mt8196-ufs-v4-3-ddec7a369dd2@collabora.com>

The MediaTek MT8196 SoC's UFS controller uses three additional clocks
compared to the MT8195, and a different set of supplies. It is therefore
not compatible with the MT8195.

While it does have a AVDD09_UFS_1 pin in addition to the AVDD09_UFS pin,
it appears that these two pins are commoned together, as the board
schematic I have access to uses the same supply for both, and the
downstream driver does not distinguish between the two supplies either.

Add a compatible for it, and modify the binding correspondingly.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 .../devicetree/bindings/ufs/mediatek,ufs.yaml      | 58 +++++++++++++++++++++-
 1 file changed, 57 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/ufs/mediatek,ufs.yaml b/Documentation/devicetree/bindings/ufs/mediatek,ufs.yaml
index e0aef3e5f56b..a82119ecbfe8 100644
--- a/Documentation/devicetree/bindings/ufs/mediatek,ufs.yaml
+++ b/Documentation/devicetree/bindings/ufs/mediatek,ufs.yaml
@@ -16,10 +16,11 @@ properties:
       - mediatek,mt8183-ufshci
       - mediatek,mt8192-ufshci
       - mediatek,mt8195-ufshci
+      - mediatek,mt8196-ufshci
 
   clocks:
     minItems: 1
-    maxItems: 13
+    maxItems: 16
 
   clock-names:
     minItems: 1
@@ -37,6 +38,9 @@ properties:
       - const: crypt_perf
       - const: ufs_rx_symbol0
       - const: ufs_rx_symbol1
+      - const: ufs_sel
+      - const: ufs_sel_min_src
+      - const: ufs_sel_max_src
 
   operating-points-v2: true
 
@@ -131,9 +135,27 @@ allOf:
       properties:
         clocks:
           minItems: 13
+          maxItems: 13
         clock-names:
           minItems: 13
+          maxItems: 13
         avdd09-supply: false
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: mediatek,mt8196-ufshci
+    then:
+      properties:
+        clocks:
+          minItems: 16
+          maxItems: 16
+        clock-names:
+          minItems: 16
+          maxItems: 16
+        avdd18-supply: false
+      required:
+        - operating-points-v2
 
 examples:
   - |
@@ -183,3 +205,37 @@ examples:
 
         mediatek,ufs-disable-mcq;
     };
+  - |
+    #include <dt-bindings/reset/mediatek,mt8196-resets.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    ufshci at 16810000 {
+        compatible = "mediatek,mt8196-ufshci";
+        reg = <0x16810000 0x2a00>;
+        interrupts = <GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH>;
+
+        clocks = <&ufs_ao_clk 6>, <&ufs_ao_clk 7>, <&clk26m>, <&ufs_ao_clk 3>,
+                 <&clk26m>, <&ufs_ao_clk 4>, <&ufs_ao_clk 0>,
+                 <&topckgen 7>, <&topckgen 41>, <&topckgen 105>, <&topckgen 83>,
+                 <&ufs_ao_clk 1>, <&ufs_ao_clk 2>, <&topckgen 42>,
+                 <&topckgen 84>, <&topckgen 102>;
+        clock-names = "ufs", "ufs_aes", "ufs_tick", "unipro_sysclk",
+                      "unipro_tick", "unipro_mp_bclk", "ufs_tx_symbol",
+                      "ufs_mem_sub", "crypt_mux", "crypt_lp", "crypt_perf",
+                      "ufs_rx_symbol0", "ufs_rx_symbol1", "ufs_sel",
+                      "ufs_sel_min_src", "ufs_sel_max_src";
+
+        operating-points-v2 = <&ufs_opp_table>;
+
+        phys = <&ufsphy>;
+
+        avdd09-supply = <&mt6363_vsram_modem>;
+        vcc-supply = <&mt6363_vemc>;
+        vccq-supply = <&mt6363_vufs12>;
+
+        resets = <&ufs_ao_clk MT8196_UFSAO_RST1_UFS_UNIPRO>,
+                 <&ufs_ao_clk MT8196_UFSAO_RST1_UFS_CRYPTO>,
+                 <&ufs_ao_clk MT8196_UFSAO_RST1_UFSHCI>;
+        reset-names = "unipro", "crypto", "hci";
+        mediatek,ufs-disable-mcq;
+    };

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 18 04:54:54 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 18 Dec 2025 13:54:54 +0100
Subject: [PATCH v4 04/25] scsi: ufs: mediatek: Move MTK_SIP_UFS_CONTROL to
 mtk_sip_svc.h
In-Reply-To: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
Message-ID: <20251218-mt8196-ufs-v4-4-ddec7a369dd2@collabora.com>

SMC commands used by multiple drivers need to live in a shared header
file somewhere to avoid code duplication. In order to rework the MPHY
reset control to be in the phy-mtk-ufs.c driver, both ufs-mediatek and
the phy driver need access to this command.

Move it to mtk_sip_svc.h, where other such command definitions already
live.

Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
Reviewed-by: Peter Wang <peter.wang at mediatek.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/ufs/host/ufs-mediatek-sip.h      | 1 -
 include/linux/soc/mediatek/mtk_sip_svc.h | 3 +++
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/ufs/host/ufs-mediatek-sip.h b/drivers/ufs/host/ufs-mediatek-sip.h
index 7d17aedf6fb8..d627dfb4a766 100644
--- a/drivers/ufs/host/ufs-mediatek-sip.h
+++ b/drivers/ufs/host/ufs-mediatek-sip.h
@@ -11,7 +11,6 @@
 /*
  * SiP (Slicon Partner) commands
  */
-#define MTK_SIP_UFS_CONTROL               MTK_SIP_SMC_CMD(0x276)
 #define UFS_MTK_SIP_VA09_PWR_CTRL         BIT(0)
 #define UFS_MTK_SIP_DEVICE_RESET          BIT(1)
 #define UFS_MTK_SIP_CRYPTO_CTRL           BIT(2)
diff --git a/include/linux/soc/mediatek/mtk_sip_svc.h b/include/linux/soc/mediatek/mtk_sip_svc.h
index abe24a73ee19..7265ff2a6e2a 100644
--- a/include/linux/soc/mediatek/mtk_sip_svc.h
+++ b/include/linux/soc/mediatek/mtk_sip_svc.h
@@ -22,6 +22,9 @@
 	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, MTK_SIP_SMC_CONVENTION, \
 			   ARM_SMCCC_OWNER_SIP, fn_id)
 
+/* UFS related SMC call */
+#define MTK_SIP_UFS_CONTROL		MTK_SIP_SMC_CMD(0x276)
+
 /* DVFSRC SMC calls */
 #define MTK_SIP_DVFSRC_VCOREFS_CONTROL	MTK_SIP_SMC_CMD(0x506)
 

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 18 04:54:55 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 18 Dec 2025 13:54:55 +0100
Subject: [PATCH v4 05/25] phy: mediatek: ufs: Add support for resets
In-Reply-To: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
Message-ID: <20251218-mt8196-ufs-v4-5-ddec7a369dd2@collabora.com>

The MediaTek UFS PHY supports PHY resets. Until now, they've been
implemented in the UFS host driver. Since they were never documented in
the UFS HCI node's DT bindings, and no mainline DT uses it, it's fine if
it's moved to the correct location, which is the PHY driver.

Implement the MPHY reset logic in this driver and expose it through the
phy subsystem's reset op. The reset itself is optional, as judging by
other mainline devices that use this hardware, it's not required for the
device to function.

If no reset is present, the reset op returns -EOPNOTSUPP, which means
that the ufshci driver can detect it's present and not double sleep in
its own reset function, where it will call the phy reset.

Reviewed-by: Philipp Zabel <p.zabel at pengutronix.de>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
Reviewed-by: Peter Wang <peter.wang at mediatek.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/phy/mediatek/phy-mtk-ufs.c | 71 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)

diff --git a/drivers/phy/mediatek/phy-mtk-ufs.c b/drivers/phy/mediatek/phy-mtk-ufs.c
index 0cb5a25b1b7a..48f8e4dbf928 100644
--- a/drivers/phy/mediatek/phy-mtk-ufs.c
+++ b/drivers/phy/mediatek/phy-mtk-ufs.c
@@ -4,6 +4,7 @@
  * Author: Stanley Chu <stanley.chu at mediatek.com>
  */
 
+#include <linux/arm-smccc.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/io.h>
@@ -11,6 +12,8 @@
 #include <linux/module.h>
 #include <linux/phy/phy.h>
 #include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/soc/mediatek/mtk_sip_svc.h>
 
 #include "phy-mtk-io.h"
 
@@ -36,9 +39,17 @@
 
 #define UFSPHY_CLKS_CNT    2
 
+#define UFS_MTK_SIP_MPHY_CTRL       BIT(8)
+
+enum ufs_mtk_mphy_op {
+	UFS_MPHY_BACKUP = 0,
+	UFS_MPHY_RESTORE
+};
+
 struct ufs_mtk_phy {
 	struct device *dev;
 	void __iomem *mmio;
+	struct reset_control *reset;
 	struct clk_bulk_data clks[UFSPHY_CLKS_CNT];
 };
 
@@ -141,9 +152,59 @@ static int ufs_mtk_phy_power_off(struct phy *generic_phy)
 	return 0;
 }
 
+static int ufs_mtk_phy_ctrl(struct ufs_mtk_phy *phy, enum ufs_mtk_mphy_op op)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_smc(MTK_SIP_UFS_CONTROL, UFS_MTK_SIP_MPHY_CTRL, op,
+		      0, 0, 0, 0, 0, &res);
+
+	switch (res.a0) {
+	case SMCCC_RET_NOT_SUPPORTED:
+		return -EOPNOTSUPP;
+	case SMCCC_RET_INVALID_PARAMETER:
+		return -EINVAL;
+	default:
+		return 0;
+	}
+}
+
+static int ufs_mtk_phy_reset(struct phy *generic_phy)
+{
+	struct ufs_mtk_phy *phy = get_ufs_mtk_phy(generic_phy);
+	int ret;
+
+	if (!phy->reset)
+		return -EOPNOTSUPP;
+
+	ret = reset_control_assert(phy->reset);
+	if (ret)
+		return ret;
+
+	usleep_range(100, 110);
+
+	ret = reset_control_deassert(phy->reset);
+	if (ret)
+		return ret;
+
+	/*
+	 * To avoid double-sleep and other unintended side-effects in the ufshci
+	 * driver, don't return the phy_ctrl retval here, but just return -EPROTO.
+	 */
+	ret = ufs_mtk_phy_ctrl(phy, UFS_MPHY_RESTORE);
+	if (ret) {
+		dev_err(phy->dev, "UFS_MPHY_RESTORE SMC command failed: %pe\n",
+			ERR_PTR(ret));
+		return -EPROTO;
+	}
+
+	return 0;
+}
+
 static const struct phy_ops ufs_mtk_phy_ops = {
 	.power_on       = ufs_mtk_phy_power_on,
 	.power_off      = ufs_mtk_phy_power_off,
+	.reset          = ufs_mtk_phy_reset,
 	.owner          = THIS_MODULE,
 };
 
@@ -163,8 +224,18 @@ static int ufs_mtk_phy_probe(struct platform_device *pdev)
 	if (IS_ERR(phy->mmio))
 		return PTR_ERR(phy->mmio);
 
+	phy->reset = devm_reset_control_get_optional_exclusive(dev, NULL);
+	if (IS_ERR(phy->reset))
+		return dev_err_probe(dev, PTR_ERR(phy->reset), "Failed to get reset\n");
+
 	phy->dev = dev;
 
+	if (phy->reset) {
+		ret = ufs_mtk_phy_ctrl(phy, UFS_MPHY_BACKUP);
+		if (ret)
+			return dev_err_probe(dev, ret, "Failed to back up MPHY\n");
+	}
+
 	ret = ufs_mtk_phy_clk_init(phy);
 	if (ret)
 		return ret;

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 18 04:54:56 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 18 Dec 2025 13:54:56 +0100
Subject: [PATCH v4 06/25] scsi: ufs: mediatek: Rework resets
In-Reply-To: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
Message-ID: <20251218-mt8196-ufs-v4-6-ddec7a369dd2@collabora.com>

Rework the reset control getting in the driver's probe function to use
the bulk reset APIs. Use the optional variant instead of defaulting to
NULL if the resets fail, so that absent resets can be distinguished from
erroneous resets.

Also remove all remnants of the MPHY reset ever having lived in this
driver.

Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
Reviewed-by: Peter Wang <peter.wang at mediatek.com>
Reviewed-by: Philipp Zabel <p.zabel at pengutronix.de>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/ufs/host/ufs-mediatek-sip.h |  8 ----
 drivers/ufs/host/ufs-mediatek.c     | 78 ++++++++++++++++++-------------------
 drivers/ufs/host/ufs-mediatek.h     |  7 ++--
 3 files changed, 42 insertions(+), 51 deletions(-)

diff --git a/drivers/ufs/host/ufs-mediatek-sip.h b/drivers/ufs/host/ufs-mediatek-sip.h
index d627dfb4a766..256598cc3b5b 100644
--- a/drivers/ufs/host/ufs-mediatek-sip.h
+++ b/drivers/ufs/host/ufs-mediatek-sip.h
@@ -31,11 +31,6 @@ enum ufs_mtk_vcc_num {
 	UFS_VCC_MAX
 };
 
-enum ufs_mtk_mphy_op {
-	UFS_MPHY_BACKUP = 0,
-	UFS_MPHY_RESTORE
-};
-
 /*
  * SMC call wrapper function
  */
@@ -84,9 +79,6 @@ static inline void _ufs_mtk_smc(struct ufs_mtk_smc_arg s)
 #define ufs_mtk_device_pwr_ctrl(on, ufs_version, res) \
 	ufs_mtk_smc(UFS_MTK_SIP_DEVICE_PWR_CTRL, &(res), on, ufs_version)
 
-#define ufs_mtk_mphy_ctrl(op, res) \
-	ufs_mtk_smc(UFS_MTK_SIP_MPHY_CTRL, &(res), op)
-
 #define ufs_mtk_mtcmos_ctrl(op, res) \
 	ufs_mtk_smc(UFS_MTK_SIP_MTCMOS_CTRL, &(res), op)
 
diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index ecbbf52bf734..d1554701793e 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -93,6 +93,12 @@ static const char *const ufs_uic_dl_err_str[] = {
 	"PA_INIT"
 };
 
+static const char *const ufs_reset_names[] = {
+	"unipro",
+	"crypto",
+	"hci",
+};
+
 static bool ufs_mtk_is_boost_crypt_enabled(struct ufs_hba *hba)
 {
 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
@@ -203,49 +209,45 @@ static void ufs_mtk_crypto_enable(struct ufs_hba *hba)
 static void ufs_mtk_host_reset(struct ufs_hba *hba)
 {
 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
-	struct arm_smccc_res res;
-
-	reset_control_assert(host->hci_reset);
-	reset_control_assert(host->crypto_reset);
-	reset_control_assert(host->unipro_reset);
-	reset_control_assert(host->mphy_reset);
-
-	usleep_range(100, 110);
+	int ret;
 
-	reset_control_deassert(host->unipro_reset);
-	reset_control_deassert(host->crypto_reset);
-	reset_control_deassert(host->hci_reset);
-	reset_control_deassert(host->mphy_reset);
+	ret = reset_control_bulk_assert(MTK_UFS_NUM_RESETS, host->resets);
+	if (ret)
+		dev_warn(hba->dev, "Host reset assert failed: %pe\n", ERR_PTR(ret));
 
-	/* restore mphy setting aftre mphy reset */
-	if (host->mphy_reset)
-		ufs_mtk_mphy_ctrl(UFS_MPHY_RESTORE, res);
-}
+	ret = phy_reset(host->mphy);
 
-static void ufs_mtk_init_reset_control(struct ufs_hba *hba,
-				       struct reset_control **rc,
-				       char *str)
-{
-	*rc = devm_reset_control_get(hba->dev, str);
-	if (IS_ERR(*rc)) {
-		dev_info(hba->dev, "Failed to get reset control %s: %ld\n",
-			 str, PTR_ERR(*rc));
-		*rc = NULL;
+	/*
+	 * Only sleep if MPHY doesn't have a reset implemented (which already
+	 * sleeps) or the PHY reset function failed somehow, just to be safe
+	 */
+	if (ret) {
+		usleep_range(100, 110);
+		if (ret != -EOPNOTSUPP)
+			dev_warn(hba->dev, "PHY reset failed: %pe\n", ERR_PTR(ret));
 	}
+
+	ret = reset_control_bulk_deassert(MTK_UFS_NUM_RESETS, host->resets);
+	if (ret)
+		dev_warn(hba->dev, "Host reset deassert failed: %pe\n", ERR_PTR(ret));
 }
 
-static void ufs_mtk_init_reset(struct ufs_hba *hba)
+static int ufs_mtk_init_reset(struct ufs_hba *hba)
 {
 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
+	int ret, i;
+
+	for (i = 0; i < MTK_UFS_NUM_RESETS; i++)
+		host->resets[i].id = ufs_reset_names[i];
 
-	ufs_mtk_init_reset_control(hba, &host->hci_reset,
-				   "hci_rst");
-	ufs_mtk_init_reset_control(hba, &host->unipro_reset,
-				   "unipro_rst");
-	ufs_mtk_init_reset_control(hba, &host->crypto_reset,
-				   "crypto_rst");
-	ufs_mtk_init_reset_control(hba, &host->mphy_reset,
-				   "mphy_rst");
+	ret = devm_reset_control_bulk_get_optional_exclusive(hba->dev, MTK_UFS_NUM_RESETS,
+							     host->resets);
+	if (ret) {
+		dev_err(hba->dev, "Failed to get resets: %pe\n", ERR_PTR(ret));
+		return ret;
+	}
+
+	return 0;
 }
 
 static int ufs_mtk_hce_enable_notify(struct ufs_hba *hba,
@@ -1247,11 +1249,9 @@ static int ufs_mtk_init(struct ufs_hba *hba)
 	if (err)
 		goto out_variant_clear;
 
-	ufs_mtk_init_reset(hba);
-
-	/* backup mphy setting if mphy can reset */
-	if (host->mphy_reset)
-		ufs_mtk_mphy_ctrl(UFS_MPHY_BACKUP, res);
+	err = ufs_mtk_init_reset(hba);
+	if (err)
+		goto out_variant_clear;
 
 	/* Enable runtime autosuspend */
 	hba->caps |= UFSHCD_CAP_RPM_AUTOSUSPEND;
diff --git a/drivers/ufs/host/ufs-mediatek.h b/drivers/ufs/host/ufs-mediatek.h
index 9747277f11e8..4fce29d131d1 100644
--- a/drivers/ufs/host/ufs-mediatek.h
+++ b/drivers/ufs/host/ufs-mediatek.h
@@ -7,12 +7,14 @@
 #define _UFS_MEDIATEK_H
 
 #include <linux/bitops.h>
+#include <linux/reset.h>
 
 /*
  * MCQ define and struct
  */
 #define UFSHCD_MAX_Q_NR 8
 #define MTK_MCQ_INVALID_IRQ	0xFFFF
+#define MTK_UFS_NUM_RESETS 3
 
 /* REG_UFS_MMIO_OPT_CTRL_0 160h */
 #define EHS_EN                  BIT(0)
@@ -175,10 +177,7 @@ struct ufs_mtk_mcq_intr_info {
 struct ufs_mtk_host {
 	struct phy *mphy;
 	struct regulator *reg_va09;
-	struct reset_control *hci_reset;
-	struct reset_control *unipro_reset;
-	struct reset_control *crypto_reset;
-	struct reset_control *mphy_reset;
+	struct reset_control_bulk_data resets[MTK_UFS_NUM_RESETS];
 	struct ufs_hba *hba;
 	struct ufs_mtk_crypt_cfg *crypt;
 	struct ufs_mtk_clk mclk;

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 18 04:54:57 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 18 Dec 2025 13:54:57 +0100
Subject: [PATCH v4 07/25] scsi: ufs: mediatek: Rework 0.9V regulator
In-Reply-To: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
Message-ID: <20251218-mt8196-ufs-v4-7-ddec7a369dd2@collabora.com>

The mediatek UFS host driver does some pretty bad stuff with regards to
the 0.9V regulator. Instead of just checking for the presence of the
regulator, it adds a cap if it's there, and then checks for the cap. It
also sleeps to stabilise the supply after enabling the regulator, which
is something that should be done by the regulator framework with the
appropriate delay properties in the DTS instead of random sleeps in the
driver code.

Rework this code and rename it to the avdd09 name I've chosen in the
binding for this supply name, instead of the downstream "va09" name that
isn't used by the datasheets for any of these chips.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/ufs/host/ufs-mediatek.c | 153 ++++++++++++++++++++++++++--------------
 drivers/ufs/host/ufs-mediatek.h |   3 +-
 2 files changed, 101 insertions(+), 55 deletions(-)

diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index d1554701793e..a7aab2332ef2 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -38,6 +38,10 @@ static void _ufs_mtk_clk_scale(struct ufs_hba *hba, bool scale_up);
 #define MAX_SUPP_MAC 64
 #define MCQ_QUEUE_OFFSET(c) ((((c) >> 16) & 0xFF) * 0x200)
 
+struct ufs_mtk_soc_data {
+	bool has_avdd09;
+};
+
 static const struct ufs_dev_quirk ufs_mtk_dev_fixups[] = {
 	{ .wmanufacturerid = UFS_ANY_VENDOR,
 	  .model = UFS_ANY_MODEL,
@@ -48,13 +52,6 @@ static const struct ufs_dev_quirk ufs_mtk_dev_fixups[] = {
 	{}
 };
 
-static const struct of_device_id ufs_mtk_of_match[] = {
-	{ .compatible = "mediatek,mt8183-ufshci" },
-	{ .compatible = "mediatek,mt8195-ufshci" },
-	{},
-};
-MODULE_DEVICE_TABLE(of, ufs_mtk_of_match);
-
 /*
  * Details of UIC Errors
  */
@@ -106,13 +103,6 @@ static bool ufs_mtk_is_boost_crypt_enabled(struct ufs_hba *hba)
 	return host->caps & UFS_MTK_CAP_BOOST_CRYPT_ENGINE;
 }
 
-static bool ufs_mtk_is_va09_supported(struct ufs_hba *hba)
-{
-	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
-
-	return host->caps & UFS_MTK_CAP_VA09_PWR_CTRL;
-}
-
 static bool ufs_mtk_is_broken_vcc(struct ufs_hba *hba)
 {
 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
@@ -506,44 +496,70 @@ static int ufs_mtk_wait_link_state(struct ufs_hba *hba, u32 state,
 	return -ETIMEDOUT;
 }
 
+static int ufs_mtk_09v_off(struct ufs_mtk_host *host)
+{
+	struct arm_smccc_res res;
+	int ret;
+
+	if (!host->reg_avdd09)
+		return 0;
+
+	ufs_mtk_va09_pwr_ctrl(res, 0);
+	ret = regulator_disable(host->reg_avdd09);
+	if (ret) {
+		dev_err(host->hba->dev, "Failed to disable avdd09-supply: %pe\n",
+			ERR_PTR(ret));
+		ufs_mtk_va09_pwr_ctrl(res, 1);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int ufs_mtk_09v_on(struct ufs_mtk_host *host)
+{
+	struct arm_smccc_res res;
+	int ret;
+
+	if (!host->reg_avdd09)
+		return 0;
+
+	ret = regulator_enable(host->reg_avdd09);
+	if (ret) {
+		dev_err(host->hba->dev, "Failed to enable avdd09-supply: %pe\n",
+			ERR_PTR(ret));
+		return ret;
+	}
+
+	ufs_mtk_va09_pwr_ctrl(res, 1);
+
+	return 0;
+}
+
 static int ufs_mtk_mphy_power_on(struct ufs_hba *hba, bool on)
 {
 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
 	struct phy *mphy = host->mphy;
-	struct arm_smccc_res res;
-	int ret = 0;
+	int ret;
 
-	if (!mphy || !(on ^ host->mphy_powered_on))
+	if (!mphy || on == host->mphy_powered_on)
 		return 0;
 
 	if (on) {
-		if (ufs_mtk_is_va09_supported(hba)) {
-			ret = regulator_enable(host->reg_va09);
-			if (ret < 0)
-				goto out;
-			/* wait 200 us to stablize VA09 */
-			usleep_range(200, 210);
-			ufs_mtk_va09_pwr_ctrl(res, 1);
-		}
+		ret = ufs_mtk_09v_on(host);
+		if (ret)
+			return ret;
 		phy_power_on(mphy);
 	} else {
 		phy_power_off(mphy);
-		if (ufs_mtk_is_va09_supported(hba)) {
-			ufs_mtk_va09_pwr_ctrl(res, 0);
-			ret = regulator_disable(host->reg_va09);
-		}
-	}
-out:
-	if (ret) {
-		dev_info(hba->dev,
-			 "failed to %s va09: %d\n",
-			 on ? "enable" : "disable",
-			 ret);
-	} else {
-		host->mphy_powered_on = on;
+		ret = ufs_mtk_09v_off(host);
+		if (ret)
+			return ret;
 	}
 
-	return ret;
+	host->mphy_powered_on = on;
+
+	return 0;
 }
 
 static int ufs_mtk_get_host_clk(struct device *dev, const char *name,
@@ -678,17 +694,6 @@ static void ufs_mtk_init_boost_crypt(struct ufs_hba *hba)
 	return;
 }
 
-static void ufs_mtk_init_va09_pwr_ctrl(struct ufs_hba *hba)
-{
-	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
-
-	host->reg_va09 = regulator_get(hba->dev, "va09");
-	if (IS_ERR(host->reg_va09))
-		dev_info(hba->dev, "failed to get va09");
-	else
-		host->caps |= UFS_MTK_CAP_VA09_PWR_CTRL;
-}
-
 static void ufs_mtk_init_host_caps(struct ufs_hba *hba)
 {
 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
@@ -697,9 +702,6 @@ static void ufs_mtk_init_host_caps(struct ufs_hba *hba)
 	if (of_property_read_bool(np, "mediatek,ufs-boost-crypt"))
 		ufs_mtk_init_boost_crypt(hba);
 
-	if (of_property_read_bool(np, "mediatek,ufs-support-va09"))
-		ufs_mtk_init_va09_pwr_ctrl(hba);
-
 	if (of_property_read_bool(np, "mediatek,ufs-disable-ah8"))
 		host->caps |= UFS_MTK_CAP_DISABLE_AH8;
 
@@ -1205,6 +1207,35 @@ static void ufs_mtk_init_mcq_irq(struct ufs_hba *hba)
 	host->mcq_nr_intr = 0;
 }
 
+/**
+ * ufs_mtk_get_supplies - acquire variant-specific supplies
+ * @host: pointer to driver's private &struct ufs_mtk_host instance
+ *
+ * Returns 0 on success, negative errno on error.
+ */
+static int ufs_mtk_get_supplies(struct ufs_mtk_host *host)
+{
+	struct device *dev = host->hba->dev;
+	const struct ufs_mtk_soc_data *data = of_device_get_match_data(dev);
+
+	if (!data || !data->has_avdd09)
+		return 0;
+
+	host->reg_avdd09 = devm_regulator_get_optional(dev, "avdd09");
+	if (IS_ERR(host->reg_avdd09)) {
+		if (PTR_ERR(host->reg_avdd09) == -ENODEV) {
+			host->reg_avdd09 = NULL;
+			return 0;
+		}
+
+		dev_err(dev, "Failed to get avdd09 regulator: %pe\n",
+			host->reg_avdd09);
+		return PTR_ERR(host->reg_avdd09);
+	}
+
+	return 0;
+}
+
 /**
  * ufs_mtk_init - find other essential mmio bases
  * @hba: host controller instance
@@ -1288,6 +1319,10 @@ static int ufs_mtk_init(struct ufs_hba *hba)
 
 	ufs_mtk_init_clocks(hba);
 
+	err = ufs_mtk_get_supplies(host);
+	if (err)
+		goto out_variant_clear;
+
 	/*
 	 * ufshcd_vops_init() is invoked after
 	 * ufshcd_setup_clock(true) in ufshcd_hba_init() thus
@@ -2336,6 +2371,18 @@ static const struct ufs_hba_variant_ops ufs_hba_mtk_vops = {
 	.config_scsi_dev     = ufs_mtk_config_scsi_dev,
 };
 
+static const struct ufs_mtk_soc_data mt8183_data = {
+	.has_avdd09 = true,
+};
+
+static const struct of_device_id ufs_mtk_of_match[] = {
+	{ .compatible = "mediatek,mt8183-ufshci", .data = &mt8183_data },
+	{ .compatible = "mediatek,mt8192-ufshci" },
+	{ .compatible = "mediatek,mt8195-ufshci" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ufs_mtk_of_match);
+
 /**
  * ufs_mtk_probe - probe routine of the driver
  * @pdev: pointer to Platform device handle
diff --git a/drivers/ufs/host/ufs-mediatek.h b/drivers/ufs/host/ufs-mediatek.h
index 4fce29d131d1..24c8941f6b86 100644
--- a/drivers/ufs/host/ufs-mediatek.h
+++ b/drivers/ufs/host/ufs-mediatek.h
@@ -125,7 +125,6 @@ enum {
  */
 enum ufs_mtk_host_caps {
 	UFS_MTK_CAP_BOOST_CRYPT_ENGINE         = 1 << 0,
-	UFS_MTK_CAP_VA09_PWR_CTRL              = 1 << 1,
 	UFS_MTK_CAP_DISABLE_AH8                = 1 << 2,
 	UFS_MTK_CAP_BROKEN_VCC                 = 1 << 3,
 
@@ -176,7 +175,7 @@ struct ufs_mtk_mcq_intr_info {
 
 struct ufs_mtk_host {
 	struct phy *mphy;
-	struct regulator *reg_va09;
+	struct regulator *reg_avdd09;
 	struct reset_control_bulk_data resets[MTK_UFS_NUM_RESETS];
 	struct ufs_hba *hba;
 	struct ufs_mtk_crypt_cfg *crypt;

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 18 04:54:58 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 18 Dec 2025 13:54:58 +0100
Subject: [PATCH v4 08/25] scsi: ufs: mediatek: Rework init function
In-Reply-To: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
Message-ID: <20251218-mt8196-ufs-v4-8-ddec7a369dd2@collabora.com>

Printing an error message on ENOMEM is pointless. The print will not
work because there is no memory.

Adding an of_match_device to the init function is pointless. Why would a
different device with a different probe function ever use the same init
function? Get rid of it.

zero-initialising an error variable just so you can then goto a bare
return statement with that error variable to signal success is also
pointless, just return directly, there's no unwind being done.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/ufs/host/ufs-mediatek.c | 19 ++++---------------
 1 file changed, 4 insertions(+), 15 deletions(-)

diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index a7aab2332ef2..131f71145a12 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -1248,29 +1248,19 @@ static int ufs_mtk_get_supplies(struct ufs_mtk_host *host)
  */
 static int ufs_mtk_init(struct ufs_hba *hba)
 {
-	const struct of_device_id *id;
 	struct device *dev = hba->dev;
 	struct ufs_mtk_host *host;
 	struct Scsi_Host *shost = hba->host;
-	int err = 0;
+	int err;
 	struct arm_smccc_res res;
 
 	host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
-	if (!host) {
-		err = -ENOMEM;
-		dev_info(dev, "%s: no memory for mtk ufs host\n", __func__);
-		goto out;
-	}
+	if (!host)
+		return -ENOMEM;
 
 	host->hba = hba;
 	ufshcd_set_variant(hba, host);
 
-	id = of_match_device(ufs_mtk_of_match, dev);
-	if (!id) {
-		err = -EINVAL;
-		goto out;
-	}
-
 	/* Initialize host capability */
 	ufs_mtk_init_host_caps(hba);
 
@@ -1344,11 +1334,10 @@ static int ufs_mtk_init(struct ufs_hba *hba)
 
 	ufs_mtk_get_hw_ip_version(hba);
 
-	goto out;
+	return 0;
 
 out_variant_clear:
 	ufshcd_set_variant(hba, NULL);
-out:
 	return err;
 }
 

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 18 04:54:59 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 18 Dec 2025 13:54:59 +0100
Subject: [PATCH v4 09/25] scsi: ufs: mediatek: Rework the crypt-boost stuff
In-Reply-To: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
Message-ID: <20251218-mt8196-ufs-v4-9-ddec7a369dd2@collabora.com>

I don't know whether the crypt-boost functionality as it is currently
implemented is even appropriate for mainline. It might be better done in
some generic way. But what I do know is that I can rework the code to
make it less obtuse.

Prefix the boost stuff with the appropriate vendor prefix, remove the
pointless clock wrappers, and rework the function.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/ufs/host/ufs-mediatek.c | 91 +++++++++++++++--------------------------
 1 file changed, 32 insertions(+), 59 deletions(-)

diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index 131f71145a12..9c0ac72d6e43 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -562,21 +562,6 @@ static int ufs_mtk_mphy_power_on(struct ufs_hba *hba, bool on)
 	return 0;
 }
 
-static int ufs_mtk_get_host_clk(struct device *dev, const char *name,
-				struct clk **clk_out)
-{
-	struct clk *clk;
-	int err = 0;
-
-	clk = devm_clk_get(dev, name);
-	if (IS_ERR(clk))
-		err = PTR_ERR(clk);
-	else
-		*clk_out = clk;
-
-	return err;
-}
-
 static void ufs_mtk_boost_crypt(struct ufs_hba *hba, bool boost)
 {
 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
@@ -633,65 +618,53 @@ static void ufs_mtk_boost_crypt(struct ufs_hba *hba, bool boost)
 	clk_disable_unprepare(cfg->clk_crypt_mux);
 }
 
-static int ufs_mtk_init_host_clk(struct ufs_hba *hba, const char *name,
-				 struct clk **clk)
-{
-	int ret;
-
-	ret = ufs_mtk_get_host_clk(hba->dev, name, clk);
-	if (ret) {
-		dev_info(hba->dev, "%s: failed to get %s: %d", __func__,
-			 name, ret);
-	}
-
-	return ret;
-}
-
-static void ufs_mtk_init_boost_crypt(struct ufs_hba *hba)
+static int ufs_mtk_init_boost_crypt(struct ufs_hba *hba)
 {
 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
 	struct ufs_mtk_crypt_cfg *cfg;
 	struct device *dev = hba->dev;
-	struct regulator *reg;
-	u32 volt;
+	int ret;
 
-	host->crypt = devm_kzalloc(dev, sizeof(*(host->crypt)),
-				   GFP_KERNEL);
-	if (!host->crypt)
-		goto disable_caps;
+	cfg = devm_kzalloc(dev, sizeof(*cfg), GFP_KERNEL);
+	if (!cfg)
+		return -ENOMEM;
 
-	reg = devm_regulator_get_optional(dev, "dvfsrc-vcore");
-	if (IS_ERR(reg)) {
-		dev_info(dev, "failed to get dvfsrc-vcore: %ld",
-			 PTR_ERR(reg));
-		goto disable_caps;
+	cfg->reg_vcore = devm_regulator_get_optional(dev, "dvfsrc-vcore");
+	if (IS_ERR(cfg->reg_vcore)) {
+		dev_err(dev, "Failed to get dvfsrc-vcore: %pe", cfg->reg_vcore);
+		return PTR_ERR(cfg->reg_vcore);
 	}
 
-	if (of_property_read_u32(dev->of_node, "boost-crypt-vcore-min",
-				 &volt)) {
-		dev_info(dev, "failed to get boost-crypt-vcore-min");
-		goto disable_caps;
+	ret = of_property_read_u32(dev->of_node, "mediatek,boost-crypt-vcore-min",
+				   &cfg->vcore_volt);
+	if (ret) {
+		dev_err(dev, "Failed to get mediatek,boost-crypt-vcore-min: %pe\n",
+			ERR_PTR(ret));
+		return ret;
 	}
 
-	cfg = host->crypt;
-	if (ufs_mtk_init_host_clk(hba, "crypt_mux",
-				  &cfg->clk_crypt_mux))
-		goto disable_caps;
+	cfg->clk_crypt_mux = devm_clk_get(dev, "crypt_mux");
+	if (IS_ERR(cfg->clk_crypt_mux)) {
+		dev_err(dev, "Failed to get clock crypt_mux: %pe\n", cfg->clk_crypt_mux);
+		return PTR_ERR(cfg->clk_crypt_mux);
+	}
 
-	if (ufs_mtk_init_host_clk(hba, "crypt_lp",
-				  &cfg->clk_crypt_lp))
-		goto disable_caps;
+	cfg->clk_crypt_lp = devm_clk_get(dev, "crypt_lp");
+	if (IS_ERR(cfg->clk_crypt_lp)) {
+		dev_err(dev, "Failed to get clock crypt_lp: %pe\n", cfg->clk_crypt_lp);
+		return PTR_ERR(cfg->clk_crypt_lp);
+	}
 
-	if (ufs_mtk_init_host_clk(hba, "crypt_perf",
-				  &cfg->clk_crypt_perf))
-		goto disable_caps;
+	cfg->clk_crypt_perf = devm_clk_get(dev, "crypt_perf");
+	if (IS_ERR(cfg->clk_crypt_perf)) {
+		dev_err(dev, "Failed to get clock crypt_perf: %pe\n", cfg->clk_crypt_perf);
+		return PTR_ERR(cfg->clk_crypt_perf);
+	}
 
-	cfg->reg_vcore = reg;
-	cfg->vcore_volt = volt;
+	host->crypt = cfg;
 	host->caps |= UFS_MTK_CAP_BOOST_CRYPT_ENGINE;
 
-disable_caps:
-	return;
+	return 0;
 }
 
 static void ufs_mtk_init_host_caps(struct ufs_hba *hba)

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 18 04:55:00 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 18 Dec 2025 13:55:00 +0100
Subject: [PATCH v4 10/25] scsi: ufs: mediatek: Handle misc host voltage
 regulators
In-Reply-To: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
Message-ID: <20251218-mt8196-ufs-v4-10-ddec7a369dd2@collabora.com>

MediaTek SoCs handled by this driver contain a per-SoC specific set of
miscellaneous supplies. These feed parts of the UFS controller silicon
inside the SoC, as opposed to the UFS card.

Add the necessary driver code to acquire these supplies using the
regulator bulk API, and disable/enable them during suspend/resume.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/ufs/host/ufs-mediatek.c | 61 ++++++++++++++++++++++++++++++++++++++---
 drivers/ufs/host/ufs-mediatek.h |  2 ++
 2 files changed, 59 insertions(+), 4 deletions(-)

diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index 9c0ac72d6e43..10d6b69e91a5 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -40,6 +40,8 @@ static void _ufs_mtk_clk_scale(struct ufs_hba *hba, bool scale_up);
 
 struct ufs_mtk_soc_data {
 	bool has_avdd09;
+	u8 num_reg_names;
+	const char *const *reg_names;
 };
 
 static const struct ufs_dev_quirk ufs_mtk_dev_fixups[] = {
@@ -1190,8 +1192,37 @@ static int ufs_mtk_get_supplies(struct ufs_mtk_host *host)
 {
 	struct device *dev = host->hba->dev;
 	const struct ufs_mtk_soc_data *data = of_device_get_match_data(dev);
+	int ret;
 
-	if (!data || !data->has_avdd09)
+	if (!data)
+		return 0;
+
+	if (data->num_reg_names) {
+		host->reg_misc = devm_kcalloc(dev, data->num_reg_names,
+					      sizeof(*host->reg_misc), GFP_KERNEL);
+		if (!host->reg_misc)
+			return -ENOMEM;
+
+		regulator_bulk_set_supply_names(host->reg_misc, data->reg_names,
+						data->num_reg_names);
+
+		ret = devm_regulator_bulk_get(dev, data->num_reg_names, host->reg_misc);
+		if (ret) {
+			dev_err(dev, "Failed to get misc regulators: %pe\n", ERR_PTR(ret));
+			return ret;
+		}
+
+		host->num_reg_misc = data->num_reg_names;
+
+		ret = regulator_bulk_enable(host->num_reg_misc, host->reg_misc);
+		if (ret) {
+			dev_err(dev, "Failed to turn on misc regulators: %pe\n",
+				ERR_PTR(ret));
+			return ret;
+		}
+	}
+
+	if (!data->has_avdd09)
 		return 0;
 
 	host->reg_avdd09 = devm_regulator_get_optional(dev, "avdd09");
@@ -1833,7 +1864,9 @@ static int ufs_mtk_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op,
 		_ufs_mtk_clk_scale(hba, false);
 	}
 
-	return 0;
+	err = regulator_bulk_disable(host->num_reg_misc, host->reg_misc);
+
+	return err;
 fail:
 	/*
 	 * Set link as off state enforcedly to trigger
@@ -1850,6 +1883,10 @@ static int ufs_mtk_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
 	struct arm_smccc_res res;
 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
 
+	err = regulator_bulk_enable(host->num_reg_misc, host->reg_misc);
+	if (err)
+		return err;
+
 	if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL)
 		ufs_mtk_dev_vreg_set_lpm(hba, false);
 
@@ -2333,14 +2370,30 @@ static const struct ufs_hba_variant_ops ufs_hba_mtk_vops = {
 	.config_scsi_dev     = ufs_mtk_config_scsi_dev,
 };
 
+static const char *const ufs_mtk_regs_avdd12_avdd18[] = {
+	"avdd12", "avdd18"
+};
+
+static const char *const ufs_mtk_regs_avdd12_ckbuf_avdd18[] = {
+	"avdd12", "avdd12-ckbuf", "avdd18"
+};
+
 static const struct ufs_mtk_soc_data mt8183_data = {
 	.has_avdd09 = true,
+	.reg_names = ufs_mtk_regs_avdd12_avdd18,
+	.num_reg_names = ARRAY_SIZE(ufs_mtk_regs_avdd12_avdd18),
+};
+
+static const struct ufs_mtk_soc_data mt8192_8195_data = {
+	.has_avdd09 = false,
+	.reg_names = ufs_mtk_regs_avdd12_ckbuf_avdd18,
+	.num_reg_names = ARRAY_SIZE(ufs_mtk_regs_avdd12_ckbuf_avdd18),
 };
 
 static const struct of_device_id ufs_mtk_of_match[] = {
 	{ .compatible = "mediatek,mt8183-ufshci", .data = &mt8183_data },
-	{ .compatible = "mediatek,mt8192-ufshci" },
-	{ .compatible = "mediatek,mt8195-ufshci" },
+	{ .compatible = "mediatek,mt8192-ufshci", .data = &mt8192_8195_data },
+	{ .compatible = "mediatek,mt8195-ufshci", .data = &mt8192_8195_data },
 	{},
 };
 MODULE_DEVICE_TABLE(of, ufs_mtk_of_match);
diff --git a/drivers/ufs/host/ufs-mediatek.h b/drivers/ufs/host/ufs-mediatek.h
index 24c8941f6b86..cb32fc987864 100644
--- a/drivers/ufs/host/ufs-mediatek.h
+++ b/drivers/ufs/host/ufs-mediatek.h
@@ -176,6 +176,8 @@ struct ufs_mtk_mcq_intr_info {
 struct ufs_mtk_host {
 	struct phy *mphy;
 	struct regulator *reg_avdd09;
+	struct regulator_bulk_data *reg_misc;
+	u8 num_reg_misc;
 	struct reset_control_bulk_data resets[MTK_UFS_NUM_RESETS];
 	struct ufs_hba *hba;
 	struct ufs_mtk_crypt_cfg *crypt;

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 18 04:55:01 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 18 Dec 2025 13:55:01 +0100
Subject: [PATCH v4 11/25] scsi: ufs: mediatek: Rework probe function
In-Reply-To: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
Message-ID: <20251218-mt8196-ufs-v4-11-ddec7a369dd2@collabora.com>

Remove the ti,syscon-reset cruft.

Make PHY mandatory. All the compatibles supported by the binding make it
mandatory.

Entertain this driver's insistence on playing with the PHY's RPM, but at
least fix the part where it doesn't increase the reference count, which
would lead to use-after-free.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/ufs/host/ufs-mediatek.c | 87 +++++++++++++++--------------------------
 1 file changed, 32 insertions(+), 55 deletions(-)

diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index 10d6b69e91a5..cc6a3a4c9704 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -2406,74 +2406,49 @@ MODULE_DEVICE_TABLE(of, ufs_mtk_of_match);
  */
 static int ufs_mtk_probe(struct platform_device *pdev)
 {
-	int err;
-	struct device *dev = &pdev->dev, *phy_dev = NULL;
-	struct device_node *reset_node, *phy_node = NULL;
-	struct platform_device *reset_pdev, *phy_pdev = NULL;
-	struct device_link *link;
-	struct ufs_hba *hba;
+	struct platform_device *phy_pdev;
+	struct device *dev = &pdev->dev;
+	struct device_node *phy_node;
 	struct ufs_mtk_host *host;
+	struct device *phy_dev;
+	struct ufs_hba *hba;
+	int err;
 
-	reset_node = of_find_compatible_node(NULL, NULL,
-					     "ti,syscon-reset");
-	if (!reset_node) {
-		dev_notice(dev, "find ti,syscon-reset fail\n");
-		goto skip_reset;
-	}
-	reset_pdev = of_find_device_by_node(reset_node);
-	if (!reset_pdev) {
-		dev_notice(dev, "find reset_pdev fail\n");
-		goto skip_reset;
-	}
-	link = device_link_add(dev, &reset_pdev->dev,
-		DL_FLAG_AUTOPROBE_CONSUMER);
-	put_device(&reset_pdev->dev);
-	if (!link) {
-		dev_notice(dev, "add reset device_link fail\n");
-		goto skip_reset;
-	}
-	/* supplier is not probed */
-	if (link->status == DL_STATE_DORMANT) {
-		err = -EPROBE_DEFER;
-		goto out;
-	}
-
-skip_reset:
 	/* find phy node */
 	phy_node = of_parse_phandle(dev->of_node, "phys", 0);
+	if (!phy_node)
+		return dev_err_probe(dev, -ENOENT, "No PHY node found\n");
 
-	if (phy_node) {
-		phy_pdev = of_find_device_by_node(phy_node);
-		if (!phy_pdev)
-			goto skip_phy;
-		phy_dev = &phy_pdev->dev;
+	phy_pdev = of_find_device_by_node(phy_node);
+	of_node_put(phy_node);
+	if (!phy_pdev)
+		return dev_err_probe(dev, -ENODEV, "No PHY device found\n");
 
-		pm_runtime_set_active(phy_dev);
-		pm_runtime_enable(phy_dev);
-		pm_runtime_get_sync(phy_dev);
+	phy_dev = &phy_pdev->dev;
 
-		put_device(phy_dev);
-		dev_info(dev, "phys node found\n");
-	} else {
-		dev_notice(dev, "phys node not found\n");
+	err = pm_runtime_set_active(phy_dev);
+	if (err) {
+		dev_err_probe(dev, err, "Failed to activate PHY RPM\n");
+		goto err_put_phy;
+	}
+	pm_runtime_enable(phy_dev);
+	err = pm_runtime_get_sync(phy_dev);
+	if (err) {
+		dev_err_probe(dev, err, "Failed to power on PHY\n");
+		goto err_put_phy;
 	}
 
-skip_phy:
 	/* perform generic probe */
 	err = ufshcd_pltfrm_init(pdev, &ufs_hba_mtk_vops);
 	if (err) {
-		dev_err(dev, "probe failed %d\n", err);
-		goto out;
+		dev_err_probe(dev, err, "Generic platform probe failed\n");
+		goto err_put_phy;
 	}
 
 	hba = platform_get_drvdata(pdev);
-	if (!hba)
-		goto out;
 
-	if (phy_node && phy_dev) {
-		host = ufshcd_get_variant(hba);
-		host->phy_dev = phy_dev;
-	}
+	host = ufshcd_get_variant(hba);
+	host->phy_dev = phy_dev;
 
 	/*
 	 * Because the default power setting of VSx (the upper layer of
@@ -2482,9 +2457,11 @@ static int ufs_mtk_probe(struct platform_device *pdev)
 	 */
 	ufs_mtk_dev_vreg_set_lpm(hba, false);
 
-out:
-	of_node_put(phy_node);
-	of_node_put(reset_node);
+	return 0;
+
+err_put_phy:
+	put_device(phy_dev);
+
 	return err;
 }
 

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 18 04:55:02 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 18 Dec 2025 13:55:02 +0100
Subject: [PATCH v4 12/25] scsi: ufs: mediatek: Remove vendor kernel quirks
 cruft
In-Reply-To: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
Message-ID: <20251218-mt8196-ufs-v4-12-ddec7a369dd2@collabora.com>

Both ufs_mtk_vreg_fix_vcc and ufs_mtk_vreg_fix_vccqx look like they are
vendor kernel hacks to work around existing downstream device trees.
Mainline does not need or want them, so remove them.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/ufs/host/ufs-mediatek.c | 69 -----------------------------------------
 1 file changed, 69 deletions(-)

diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index cc6a3a4c9704..6385ebcc9142 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -1019,73 +1019,6 @@ static void ufs_mtk_init_clocks(struct ufs_hba *hba)
 	}
 }
 
-#define MAX_VCC_NAME 30
-static int ufs_mtk_vreg_fix_vcc(struct ufs_hba *hba)
-{
-	struct ufs_vreg_info *info = &hba->vreg_info;
-	struct device_node *np = hba->dev->of_node;
-	struct device *dev = hba->dev;
-	char vcc_name[MAX_VCC_NAME];
-	struct arm_smccc_res res;
-	int err, ver;
-
-	if (info->vcc)
-		return 0;
-
-	if (of_property_read_bool(np, "mediatek,ufs-vcc-by-num")) {
-		ufs_mtk_get_vcc_num(res);
-		if (res.a1 > UFS_VCC_NONE && res.a1 < UFS_VCC_MAX)
-			snprintf(vcc_name, MAX_VCC_NAME, "vcc-opt%lu", res.a1);
-		else
-			return -ENODEV;
-	} else if (of_property_read_bool(np, "mediatek,ufs-vcc-by-ver")) {
-		ver = (hba->dev_info.wspecversion & 0xF00) >> 8;
-		snprintf(vcc_name, MAX_VCC_NAME, "vcc-ufs%u", ver);
-	} else {
-		return 0;
-	}
-
-	err = ufshcd_populate_vreg(dev, vcc_name, &info->vcc, false);
-	if (err)
-		return err;
-
-	err = ufshcd_get_vreg(dev, info->vcc);
-	if (err)
-		return err;
-
-	err = regulator_enable(info->vcc->reg);
-	if (!err) {
-		info->vcc->enabled = true;
-		dev_info(dev, "%s: %s enabled\n", __func__, vcc_name);
-	}
-
-	return err;
-}
-
-static void ufs_mtk_vreg_fix_vccqx(struct ufs_hba *hba)
-{
-	struct ufs_vreg_info *info = &hba->vreg_info;
-	struct ufs_vreg **vreg_on, **vreg_off;
-
-	if (hba->dev_info.wspecversion >= 0x0300) {
-		vreg_on = &info->vccq;
-		vreg_off = &info->vccq2;
-	} else {
-		vreg_on = &info->vccq2;
-		vreg_off = &info->vccq;
-	}
-
-	if (*vreg_on)
-		(*vreg_on)->always_on = true;
-
-	if (*vreg_off) {
-		regulator_disable((*vreg_off)->reg);
-		devm_kfree(hba->dev, (*vreg_off)->name);
-		devm_kfree(hba->dev, *vreg_off);
-		*vreg_off = NULL;
-	}
-}
-
 static void ufs_mtk_setup_clk_gating(struct ufs_hba *hba)
 {
 	unsigned long flags;
@@ -2005,8 +1938,6 @@ static void ufs_mtk_fixup_dev_quirks(struct ufs_hba *hba)
 		hba->dev_quirks &= ~UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM;
 	}
 
-	ufs_mtk_vreg_fix_vcc(hba);
-	ufs_mtk_vreg_fix_vccqx(hba);
 	ufs_mtk_fix_ahit(hba);
 	ufs_mtk_fix_clock_scaling(hba);
 }

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 18 04:55:03 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 18 Dec 2025 13:55:03 +0100
Subject: [PATCH v4 13/25] scsi: ufs: mediatek: Use the common PHY framework
In-Reply-To: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
Message-ID: <20251218-mt8196-ufs-v4-13-ddec7a369dd2@collabora.com>

There is no need to reinvent the PHY framework, especially not its OF
parsing.

Change the code to simply use the PHY framework to acquire the device's
PHY in the ufshcd init, so that it's device linked to the right device.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/ufs/host/ufs-mediatek.c | 133 ++++++++++++----------------------------
 drivers/ufs/host/ufs-mediatek.h |   1 -
 2 files changed, 40 insertions(+), 94 deletions(-)

diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index 6385ebcc9142..b3fb87bd1c75 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -293,44 +293,6 @@ static int ufs_mtk_hce_enable_notify(struct ufs_hba *hba,
 	return 0;
 }
 
-static int ufs_mtk_bind_mphy(struct ufs_hba *hba)
-{
-	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
-	struct device *dev = hba->dev;
-	struct device_node *np = dev->of_node;
-	int err = 0;
-
-	host->mphy = devm_of_phy_get_by_index(dev, np, 0);
-
-	if (host->mphy == ERR_PTR(-EPROBE_DEFER)) {
-		/*
-		 * UFS driver might be probed before the phy driver does.
-		 * In that case we would like to return EPROBE_DEFER code.
-		 */
-		err = -EPROBE_DEFER;
-		dev_info(dev,
-			 "%s: required phy hasn't probed yet. err = %d\n",
-			__func__, err);
-	} else if (IS_ERR(host->mphy)) {
-		err = PTR_ERR(host->mphy);
-		if (err != -ENODEV) {
-			dev_info(dev, "%s: PHY get failed %d\n", __func__,
-				 err);
-		}
-	}
-
-	if (err)
-		host->mphy = NULL;
-	/*
-	 * Allow unbound mphy because not every platform needs specific
-	 * mphy control.
-	 */
-	if (err == -ENODEV)
-		err = 0;
-
-	return err;
-}
-
 static int ufs_mtk_setup_ref_clk(struct ufs_hba *hba, bool on)
 {
 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
@@ -1203,13 +1165,21 @@ static int ufs_mtk_init(struct ufs_hba *hba)
 
 	ufs_mtk_init_mcq_irq(hba);
 
-	err = ufs_mtk_bind_mphy(hba);
-	if (err)
+	host->mphy = devm_phy_get(dev, NULL);
+	if (IS_ERR(host->mphy)) {
+		err = dev_err_probe(dev, PTR_ERR(host->mphy), "Failed to get PHY\n");
+		goto out_variant_clear;
+	}
+
+	err = phy_init(host->mphy);
+	if (err) {
+		dev_err_probe(dev, err, "Failed to initialize PHY\n");
 		goto out_variant_clear;
+	}
 
 	err = ufs_mtk_init_reset(hba);
 	if (err)
-		goto out_variant_clear;
+		goto out_phy_exit;
 
 	/* Enable runtime autosuspend */
 	hba->caps |= UFSHCD_CAP_RPM_AUTOSUSPEND;
@@ -1248,7 +1218,7 @@ static int ufs_mtk_init(struct ufs_hba *hba)
 
 	err = ufs_mtk_get_supplies(host);
 	if (err)
-		goto out_variant_clear;
+		goto out_phy_exit;
 
 	/*
 	 * ufshcd_vops_init() is invoked after
@@ -1273,11 +1243,22 @@ static int ufs_mtk_init(struct ufs_hba *hba)
 
 	return 0;
 
+out_phy_exit:
+	phy_exit(host->mphy);
 out_variant_clear:
 	ufshcd_set_variant(hba, NULL);
 	return err;
 }
 
+static void ufs_mtk_exit(struct ufs_hba *hba)
+{
+	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
+
+	ufs_mtk_mphy_power_on(hba, false);
+
+	phy_exit(host->mphy);
+}
+
 static bool ufs_mtk_pmc_via_fastauto(struct ufs_hba *hba,
 				     struct ufs_pa_layer_attr *dev_req_params)
 {
@@ -2279,6 +2260,7 @@ static const struct ufs_hba_variant_ops ufs_hba_mtk_vops = {
 	.name                = "mediatek.ufshci",
 	.max_num_rtt         = MTK_MAX_NUM_RTT,
 	.init                = ufs_mtk_init,
+	.exit                = ufs_mtk_exit,
 	.get_ufs_hci_version = ufs_mtk_get_ufs_hci_version,
 	.setup_clocks        = ufs_mtk_setup_clocks,
 	.hce_enable_notify   = ufs_mtk_hce_enable_notify,
@@ -2337,50 +2319,17 @@ MODULE_DEVICE_TABLE(of, ufs_mtk_of_match);
  */
 static int ufs_mtk_probe(struct platform_device *pdev)
 {
-	struct platform_device *phy_pdev;
 	struct device *dev = &pdev->dev;
-	struct device_node *phy_node;
-	struct ufs_mtk_host *host;
-	struct device *phy_dev;
 	struct ufs_hba *hba;
-	int err;
-
-	/* find phy node */
-	phy_node = of_parse_phandle(dev->of_node, "phys", 0);
-	if (!phy_node)
-		return dev_err_probe(dev, -ENOENT, "No PHY node found\n");
-
-	phy_pdev = of_find_device_by_node(phy_node);
-	of_node_put(phy_node);
-	if (!phy_pdev)
-		return dev_err_probe(dev, -ENODEV, "No PHY device found\n");
-
-	phy_dev = &phy_pdev->dev;
-
-	err = pm_runtime_set_active(phy_dev);
-	if (err) {
-		dev_err_probe(dev, err, "Failed to activate PHY RPM\n");
-		goto err_put_phy;
-	}
-	pm_runtime_enable(phy_dev);
-	err = pm_runtime_get_sync(phy_dev);
-	if (err) {
-		dev_err_probe(dev, err, "Failed to power on PHY\n");
-		goto err_put_phy;
-	}
+	int ret;
 
 	/* perform generic probe */
-	err = ufshcd_pltfrm_init(pdev, &ufs_hba_mtk_vops);
-	if (err) {
-		dev_err_probe(dev, err, "Generic platform probe failed\n");
-		goto err_put_phy;
-	}
+	ret = ufshcd_pltfrm_init(pdev, &ufs_hba_mtk_vops);
+	if (ret)
+		return dev_err_probe(dev, ret, "Generic platform probe failed\n");
 
 	hba = platform_get_drvdata(pdev);
 
-	host = ufshcd_get_variant(hba);
-	host->phy_dev = phy_dev;
-
 	/*
 	 * Because the default power setting of VSx (the upper layer of
 	 * VCCQ/VCCQ2) is HWLP, we need to prevent VCCQ/VCCQ2 from
@@ -2389,18 +2338,11 @@ static int ufs_mtk_probe(struct platform_device *pdev)
 	ufs_mtk_dev_vreg_set_lpm(hba, false);
 
 	return 0;
-
-err_put_phy:
-	put_device(phy_dev);
-
-	return err;
 }
 
 /**
  * ufs_mtk_remove - set driver_data of the device to NULL
  * @pdev: pointer to platform device handle
- *
- * Always return 0
  */
 static void ufs_mtk_remove(struct platform_device *pdev)
 {
@@ -2460,9 +2402,8 @@ static int ufs_mtk_system_resume(struct device *dev)
 static int ufs_mtk_runtime_suspend(struct device *dev)
 {
 	struct ufs_hba *hba = dev_get_drvdata(dev);
-	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
 	struct arm_smccc_res res;
-	int ret = 0;
+	int ret;
 
 	ret = ufshcd_runtime_suspend(dev);
 	if (ret)
@@ -2473,8 +2414,11 @@ static int ufs_mtk_runtime_suspend(struct device *dev)
 	if (ufs_mtk_is_rtff_mtcmos(hba))
 		ufs_mtk_mtcmos_ctrl(false, res);
 
-	if (host->phy_dev)
-		pm_runtime_put_sync(host->phy_dev);
+	ret = ufs_mtk_mphy_power_on(hba, false);
+	if (ret) {
+		dev_err(dev, "Failed to power off PHY: %pe\n", ERR_PTR(ret));
+		return ret;
+	}
 
 	return 0;
 }
@@ -2482,14 +2426,17 @@ static int ufs_mtk_runtime_suspend(struct device *dev)
 static int ufs_mtk_runtime_resume(struct device *dev)
 {
 	struct ufs_hba *hba = dev_get_drvdata(dev);
-	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
 	struct arm_smccc_res res;
+	int ret;
 
 	if (ufs_mtk_is_rtff_mtcmos(hba))
 		ufs_mtk_mtcmos_ctrl(true, res);
 
-	if (host->phy_dev)
-		pm_runtime_get_sync(host->phy_dev);
+	ret = ufs_mtk_mphy_power_on(hba, true);
+	if (ret) {
+		dev_err(dev, "Failed to power on PHY: %pe\n", ERR_PTR(ret));
+		return ret;
+	}
 
 	ufs_mtk_dev_vreg_set_lpm(hba, false);
 
diff --git a/drivers/ufs/host/ufs-mediatek.h b/drivers/ufs/host/ufs-mediatek.h
index cb32fc987864..bf8122af69f0 100644
--- a/drivers/ufs/host/ufs-mediatek.h
+++ b/drivers/ufs/host/ufs-mediatek.h
@@ -197,7 +197,6 @@ struct ufs_mtk_host {
 	bool is_mcq_intr_enabled;
 	int mcq_nr_intr;
 	struct ufs_mtk_mcq_intr_info mcq_intr_info[UFSHCD_MAX_Q_NR];
-	struct device *phy_dev;
 };
 
 /* MTK delay of autosuspend: 500 ms */

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 18 04:55:04 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 18 Dec 2025 13:55:04 +0100
Subject: [PATCH v4 14/25] scsi: ufs: mediatek: Switch to newer PM ops
 helpers
In-Reply-To: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
Message-ID: <20251218-mt8196-ufs-v4-14-ddec7a369dd2@collabora.com>

SET_SYSTEM_SLEEP_PM_OPS and SET_RUNTIME_PM_OPS are deprecated.

Switch to the non-deprecated variants, and pm_ptr, removing the
ifdeffery in the process. This allows the compiler visibility into those
functions.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/ufs/host/ufs-mediatek.c | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index b3fb87bd1c75..89e3fa5d7d10 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -2349,7 +2349,6 @@ static void ufs_mtk_remove(struct platform_device *pdev)
 	ufshcd_pltfrm_remove(pdev);
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int ufs_mtk_system_suspend(struct device *dev)
 {
 	struct ufs_hba *hba = dev_get_drvdata(dev);
@@ -2396,9 +2395,7 @@ static int ufs_mtk_system_resume(struct device *dev)
 
 	return ret;
 }
-#endif
 
-#ifdef CONFIG_PM
 static int ufs_mtk_runtime_suspend(struct device *dev)
 {
 	struct ufs_hba *hba = dev_get_drvdata(dev);
@@ -2442,13 +2439,10 @@ static int ufs_mtk_runtime_resume(struct device *dev)
 
 	return ufshcd_runtime_resume(dev);
 }
-#endif
 
 static const struct dev_pm_ops ufs_mtk_pm_ops = {
-	SET_SYSTEM_SLEEP_PM_OPS(ufs_mtk_system_suspend,
-				ufs_mtk_system_resume)
-	SET_RUNTIME_PM_OPS(ufs_mtk_runtime_suspend,
-			   ufs_mtk_runtime_resume, NULL)
+	SYSTEM_SLEEP_PM_OPS(ufs_mtk_system_suspend, ufs_mtk_system_resume)
+	RUNTIME_PM_OPS(ufs_mtk_runtime_suspend, ufs_mtk_runtime_resume, NULL)
 	.prepare	 = ufshcd_suspend_prepare,
 	.complete	 = ufshcd_resume_complete,
 };
@@ -2458,7 +2452,7 @@ static struct platform_driver ufs_mtk_pltform = {
 	.remove = ufs_mtk_remove,
 	.driver = {
 		.name   = "ufshcd-mtk",
-		.pm     = &ufs_mtk_pm_ops,
+		.pm     = pm_ptr(&ufs_mtk_pm_ops),
 		.of_match_table = ufs_mtk_of_match,
 	},
 };

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 18 04:55:05 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 18 Dec 2025 13:55:05 +0100
Subject: [PATCH v4 15/25] scsi: ufs: mediatek: Remove
 mediatek,ufs-broken-rtc property
In-Reply-To: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
Message-ID: <20251218-mt8196-ufs-v4-15-ddec7a369dd2@collabora.com>

This flag property was never described in the binding, and its
capability wrapper seems pointless.

If one of the MediaTek SoCs needs the ufshcd quirk applied, then this
can be done per-compatible, without needing to give the device tree
author the option to forget to set it.

Remove it and the associated capability flag wrapping code.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/ufs/host/ufs-mediatek.c | 5 -----
 drivers/ufs/host/ufs-mediatek.h | 2 --
 2 files changed, 7 deletions(-)

diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index 89e3fa5d7d10..ffd52b8c295a 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -657,9 +657,6 @@ static void ufs_mtk_init_host_caps(struct ufs_hba *hba)
 	if (of_property_read_bool(np, "mediatek,ufs-rtff-mtcmos"))
 		host->caps |= UFS_MTK_CAP_RTFF_MTCMOS;
 
-	if (of_property_read_bool(np, "mediatek,ufs-broken-rtc"))
-		host->caps |= UFS_MTK_CAP_MCQ_BROKEN_RTC;
-
 	dev_info(hba->dev, "caps: 0x%x", host->caps);
 }
 
@@ -1203,8 +1200,6 @@ static int ufs_mtk_init(struct ufs_hba *hba)
 	hba->quirks |= UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL;
 
 	hba->quirks |= UFSHCD_QUIRK_MCQ_BROKEN_INTR;
-	if (host->caps & UFS_MTK_CAP_MCQ_BROKEN_RTC)
-		hba->quirks |= UFSHCD_QUIRK_MCQ_BROKEN_RTC;
 
 	hba->vps->wb_flush_threshold = UFS_WB_BUF_REMAIN_PERCENT(80);
 
diff --git a/drivers/ufs/host/ufs-mediatek.h b/drivers/ufs/host/ufs-mediatek.h
index bf8122af69f0..5f096ed3f850 100644
--- a/drivers/ufs/host/ufs-mediatek.h
+++ b/drivers/ufs/host/ufs-mediatek.h
@@ -138,8 +138,6 @@ enum ufs_mtk_host_caps {
 	UFS_MTK_CAP_DISABLE_MCQ                = 1 << 8,
 	/* Control MTCMOS with RTFF */
 	UFS_MTK_CAP_RTFF_MTCMOS                = 1 << 9,
-
-	UFS_MTK_CAP_MCQ_BROKEN_RTC             = 1 << 10,
 };
 
 struct ufs_mtk_crypt_cfg {

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 18 04:55:06 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 18 Dec 2025 13:55:06 +0100
Subject: [PATCH v4 16/25] scsi: ufs: mediatek: Rework _ufs_mtk_clk_scale
 error paths
In-Reply-To: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
Message-ID: <20251218-mt8196-ufs-v4-16-ddec7a369dd2@collabora.com>

Errors should be printed at the correct log level. Additionally, it
looks like some "goto out"'s were omitted in the scale up case, which
looks like a mistake, as the scale down branch of the code does use
them.

Rework the error messages to make them nicer and at the correct
verbosity, and add the missing gotos.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/ufs/host/ufs-mediatek.c | 41 +++++++++++++++++++----------------------
 1 file changed, 19 insertions(+), 22 deletions(-)

diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index ffd52b8c295a..d72b6ab05a23 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -1985,16 +1985,16 @@ static void _ufs_mtk_clk_scale(struct ufs_hba *hba, bool scale_up)
 
 	ret = clk_prepare_enable(clki->clk);
 	if (ret) {
-		dev_info(hba->dev,
-			 "clk_prepare_enable() fail, ret: %d\n", ret);
+		dev_err(hba->dev, "%s: Failed to enable clock: %pe\n", __func__, ERR_PTR(ret));
 		return;
 	}
 
 	if (clk_fde_scale) {
 		ret = clk_prepare_enable(fde_clki->clk);
 		if (ret) {
-			dev_info(hba->dev,
-				 "fde clk_prepare_enable() fail, ret: %d\n", ret);
+			dev_err(hba->dev, "%s: Failed to enable FDE clock: %pe\n",
+				__func__, ERR_PTR(ret));
+			clk_disable_unprepare(clki->clk);
 			return;
 		}
 	}
@@ -2003,51 +2003,48 @@ static void _ufs_mtk_clk_scale(struct ufs_hba *hba, bool scale_up)
 		if (clk_bind_vcore) {
 			ret = regulator_set_voltage(reg, volt, INT_MAX);
 			if (ret) {
-				dev_info(hba->dev,
-					"Failed to set vcore to %d\n", volt);
+				dev_err(hba->dev, "Failed to set vcore to %d\n", volt);
 				goto out;
 			}
 		}
 
 		ret = clk_set_parent(clki->clk, mclk->ufs_sel_max_clki->clk);
 		if (ret) {
-			dev_info(hba->dev, "Failed to set clk mux, ret = %d\n",
-				ret);
+			dev_err(hba->dev, "%s: Failed to set clock mux: %pe\n",
+				__func__, ERR_PTR(ret));
+			goto out;
 		}
 
 		if (clk_fde_scale) {
-			ret = clk_set_parent(fde_clki->clk,
-				mclk->ufs_fde_max_clki->clk);
+			ret = clk_set_parent(fde_clki->clk, mclk->ufs_fde_max_clki->clk);
 			if (ret) {
-				dev_info(hba->dev,
-					"Failed to set fde clk mux, ret = %d\n",
-					ret);
+				dev_err(hba->dev, "%s: Failed to set fde clock mux: %pe\n",
+					__func__, ERR_PTR(ret));
+				goto out;
 			}
 		}
 	} else {
 		if (clk_fde_scale) {
-			ret = clk_set_parent(fde_clki->clk,
-				mclk->ufs_fde_min_clki->clk);
+			ret = clk_set_parent(fde_clki->clk, mclk->ufs_fde_min_clki->clk);
 			if (ret) {
-				dev_info(hba->dev,
-					"Failed to set fde clk mux, ret = %d\n",
-					ret);
+				dev_err(hba->dev, "%s: Failed to set fde clock mux: %pe\n",
+					__func__, ERR_PTR(ret));
 				goto out;
 			}
 		}
 
 		ret = clk_set_parent(clki->clk, mclk->ufs_sel_min_clki->clk);
 		if (ret) {
-			dev_info(hba->dev, "Failed to set clk mux, ret = %d\n",
-				ret);
+			dev_err(hba->dev, "%s: Failed to set clock mux: %pe\n",
+				__func__, ERR_PTR(ret));
 			goto out;
 		}
 
 		if (clk_bind_vcore) {
 			ret = regulator_set_voltage(reg, 0, INT_MAX);
 			if (ret) {
-				dev_info(hba->dev,
-					"failed to set vcore to MIN\n");
+				dev_err(hba->dev, "%s: Failed to set vcore to minimum: %pe\n",
+					__func__, ERR_PTR(ret));
 			}
 		}
 	}

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 18 04:55:07 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 18 Dec 2025 13:55:07 +0100
Subject: [PATCH v4 17/25] scsi: ufs: mediatek: Add vendor prefix to
 clk-scale-up-vcore-min
In-Reply-To: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
Message-ID: <20251218-mt8196-ufs-v4-17-ddec7a369dd2@collabora.com>

Device Tree properties other than the standard properties must be
prefixed with the vendor's name. The "clk-scale-up-vcore-min" property,
which this driver uses, and the binding did not previously document,
lacked a vendor prefix.

Add the missing "mediatek," vendor prefix and clean up the error print.
No judgements are made regarding the use the property itself, it may
turn out to be implementing something that it should do through a
different way (e.g. OPPs).

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/ufs/host/ufs-mediatek.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index d72b6ab05a23..a598019cb9ea 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -960,9 +960,9 @@ static void ufs_mtk_init_clocks(struct ufs_hba *hba)
 		return;
 	}
 
-	if (of_property_read_u32(dev->of_node, "clk-scale-up-vcore-min",
+	if (of_property_read_u32(dev->of_node, "mediatek,clk-scale-up-vcore-min",
 				 &volt)) {
-		dev_info(dev, "failed to get clk-scale-up-vcore-min");
+		dev_err(dev, "Failed to get mediatek,clk-scale-up-vcore-min\n");
 		return;
 	}
 

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 18 04:55:08 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 18 Dec 2025 13:55:08 +0100
Subject: [PATCH v4 18/25] scsi: ufs: mediatek: Clean up logging prints
In-Reply-To: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
Message-ID: <20251218-mt8196-ufs-v4-18-ddec7a369dd2@collabora.com>

The Linux kernel's log buffer provides many levels of verbosity,
associated with different semantic meanings. Care should be taken to
only log useful information to the info level, and log errors to the
error level.

The MediaTek UFS driver does not do this. It freely logs verbose debug
information to the info level, errors to the info level, and sometimes
errors to the warning level.

Adjust all the wrapped kprintf invocations to rectify this situation.
Use user-friendly %pe format codes for printing errors where possible.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/ufs/host/ufs-mediatek.c | 99 ++++++++++++++++++-----------------------
 1 file changed, 43 insertions(+), 56 deletions(-)

diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index a598019cb9ea..8c9daf005e12 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -192,8 +192,8 @@ static void ufs_mtk_crypto_enable(struct ufs_hba *hba)
 
 	ufs_mtk_crypto_ctrl(res, 1);
 	if (res.a0) {
-		dev_info(hba->dev, "%s: crypto enable failed, err: %lu\n",
-			 __func__, res.a0);
+		dev_err(hba->dev, "%s: crypto enable failed with error %lu, disabling\n",
+			__func__, res.a0);
 		hba->caps &= ~UFSHCD_CAP_CRYPTO;
 	}
 }
@@ -542,40 +542,38 @@ static void ufs_mtk_boost_crypt(struct ufs_hba *hba, bool boost)
 
 	ret = clk_prepare_enable(cfg->clk_crypt_mux);
 	if (ret) {
-		dev_info(hba->dev, "clk_prepare_enable(): %d\n",
-			 ret);
+		dev_err(hba->dev, "%s: Failed to enable clk_crypt_mux: %pe\n",
+			__func__, ERR_PTR(ret));
 		return;
 	}
 
 	if (boost) {
 		ret = regulator_set_voltage(reg, volt, INT_MAX);
 		if (ret) {
-			dev_info(hba->dev,
-				 "failed to set vcore to %d\n", volt);
+			dev_err(hba->dev, "%s: Failed to set vcore to %d: %pe\n",
+				__func__, volt, ERR_PTR(ret));
 			goto out;
 		}
 
-		ret = clk_set_parent(cfg->clk_crypt_mux,
-				     cfg->clk_crypt_perf);
+		ret = clk_set_parent(cfg->clk_crypt_mux, cfg->clk_crypt_perf);
 		if (ret) {
-			dev_info(hba->dev,
-				 "failed to set clk_crypt_perf\n");
+			dev_err(hba->dev, "%s: Failed to reparent clk_crypt_perf: %pe\n",
+				__func__, ERR_PTR(ret));
 			regulator_set_voltage(reg, 0, INT_MAX);
 			goto out;
 		}
 	} else {
-		ret = clk_set_parent(cfg->clk_crypt_mux,
-				     cfg->clk_crypt_lp);
+		ret = clk_set_parent(cfg->clk_crypt_mux, cfg->clk_crypt_lp);
 		if (ret) {
-			dev_info(hba->dev,
-				 "failed to set clk_crypt_lp\n");
+			dev_err(hba->dev, "%s: Failed to reparent clk_crypt_lp: %pe\n",
+				__func__, ERR_PTR(ret));
 			goto out;
 		}
 
 		ret = regulator_set_voltage(reg, 0, INT_MAX);
 		if (ret) {
-			dev_info(hba->dev,
-				 "failed to set vcore to MIN\n");
+			dev_err(hba->dev, "%s: Failed to set vcore to minimum: %pe\n",
+				__func__, ERR_PTR(ret));
 		}
 	}
 out:
@@ -765,10 +763,8 @@ static int ufs_mtk_setup_clocks(struct ufs_hba *hba, bool on,
 		if (clk_pwr_off) {
 			ufs_mtk_pwr_ctrl(hba, false);
 		} else {
-			dev_warn(hba->dev, "Clock is not turned off, hba->ahit = 0x%x, AHIT = 0x%x\n",
-				hba->ahit,
-				ufshcd_readl(hba,
-					REG_AUTO_HIBERNATE_IDLE_TIMER));
+			dev_warn(hba->dev, "Clock isn't off, hba->ahit = 0x%x, AHIT = 0x%x\n",
+				 hba->ahit, ufshcd_readl(hba, REG_AUTO_HIBERNATE_IDLE_TIMER));
 		}
 		ufs_mtk_mcq_disable_irq(hba);
 	} else if (on && status == POST_CHANGE) {
@@ -812,11 +808,11 @@ static void ufs_mtk_mcq_set_irq_affinity(struct ufs_hba *hba, unsigned int cpu)
 	_cpu = (cpu == 0) ? 3 : cpu;
 	ret = irq_set_affinity(irq, cpumask_of(_cpu));
 	if (ret) {
-		dev_err(hba->dev, "set irq %d affinity to CPU %d failed\n",
+		dev_err(hba->dev, "setting irq %d affinity to CPU %d failed\n",
 			irq, _cpu);
 		return;
 	}
-	dev_info(hba->dev, "set irq %d affinity to CPU: %d\n", irq, _cpu);
+	dev_dbg(hba->dev, "set irq %d affinity to CPU %d\n", irq, _cpu);
 }
 
 static bool ufs_mtk_is_legacy_chipset(struct ufs_hba *hba, u32 hw_ip_ver)
@@ -832,7 +828,8 @@ static bool ufs_mtk_is_legacy_chipset(struct ufs_hba *hba, u32 hw_ip_ver)
 	default:
 		break;
 	}
-	dev_info(hba->dev, "legacy IP version - 0x%x, is legacy : %d", hw_ip_ver, is_legacy);
+	dev_dbg(hba->dev, "IP version 0x%x, legacy = %s", hw_ip_ver,
+		str_true_false(is_legacy));
 
 	return is_legacy;
 }
@@ -937,15 +934,12 @@ static void ufs_mtk_init_clocks(struct ufs_hba *hba)
 		}
 	}
 
-	list_for_each_entry(clki, head, list) {
-		dev_info(hba->dev, "clk \"%s\" present", clki->name);
-	}
+	list_for_each_entry(clki, head, list)
+		dev_dbg(hba->dev, "clk \"%s\" present", clki->name);
 
 	if (!ufs_mtk_is_clk_scale_ready(hba)) {
 		hba->caps &= ~UFSHCD_CAP_CLK_SCALING;
-		dev_info(hba->dev,
-			 "%s: Clk-scaling not ready. Feature disabled.",
-			 __func__);
+		dev_info(hba->dev, "%s: Clock scaling unavailable", __func__);
 		return;
 	}
 
@@ -955,8 +949,8 @@ static void ufs_mtk_init_clocks(struct ufs_hba *hba)
 	 */
 	reg = devm_regulator_get_optional(dev, "dvfsrc-vcore");
 	if (IS_ERR(reg)) {
-		dev_info(dev, "failed to get dvfsrc-vcore: %ld",
-			 PTR_ERR(reg));
+		if (PTR_ERR(reg) != -ENODEV)
+			dev_err(dev, "Failed to get dvfsrc-vcore: %pe\n", reg);
 		return;
 	}
 
@@ -970,12 +964,9 @@ static void ufs_mtk_init_clocks(struct ufs_hba *hba)
 	host->mclk.vcore_volt = volt;
 
 	/* If default boot is max gear, request vcore */
-	if (reg && volt && host->clk_scale_up) {
-		if (regulator_set_voltage(reg, volt, INT_MAX)) {
-			dev_info(hba->dev,
-				"Failed to set vcore to %d\n", volt);
-		}
-	}
+	if (reg && volt && host->clk_scale_up)
+		if (regulator_set_voltage(reg, volt, INT_MAX))
+			dev_err(hba->dev, "Failed to set vcore to %d\n", volt);
 }
 
 static void ufs_mtk_setup_clk_gating(struct ufs_hba *hba)
@@ -1062,7 +1053,7 @@ static void ufs_mtk_init_mcq_irq(struct ufs_hba *hba)
 		}
 		host->mcq_intr_info[i].hba = hba;
 		host->mcq_intr_info[i].irq = irq;
-		dev_info(hba->dev, "get platform mcq irq: %d, %d\n", i, irq);
+		dev_dbg(hba->dev, "get platform mcq irq: %d, %d\n", i, irq);
 	}
 
 	return;
@@ -1325,10 +1316,8 @@ static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba,
 		host_params.desired_working_mode = UFS_PWM_MODE;
 
 	ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params);
-	if (ret) {
-		pr_info("%s: failed to determine capabilities\n",
-			__func__);
-	}
+	if (ret)
+		dev_warn(hba->dev, "%s: failed to determine capabilities\n", __func__);
 
 	if (ufs_mtk_pmc_via_fastauto(hba, dev_req_params)) {
 		ufs_mtk_adjust_sync_length(hba);
@@ -1374,10 +1363,9 @@ static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba,
 		ret = ufshcd_uic_change_pwr_mode(hba,
 					FASTAUTO_MODE << 4 | FASTAUTO_MODE);
 
-		if (ret) {
-			dev_err(hba->dev, "%s: HSG1B FASTAUTO failed ret=%d\n",
-				__func__, ret);
-		}
+		if (ret)
+			dev_err(hba->dev, "%s: HSG1B FASTAUTO failed: %pe\n",
+				__func__, ERR_PTR(ret));
 	}
 
 	/* if already configured to the requested pwr_mode, skip adapt */
@@ -1427,7 +1415,7 @@ static int ufs_mtk_auto_hibern8_disable(struct ufs_hba *hba)
 
 out:
 	if (ret) {
-		dev_warn(hba->dev, "exit h8 state fail, ret=%d\n", ret);
+		dev_err(hba->dev, "Failed to exit h8 state: %pe\n", ERR_PTR(ret));
 
 		ufshcd_force_error_recovery(hba);
 
@@ -1589,7 +1577,7 @@ static int ufs_mtk_device_reset(struct ufs_hba *hba)
 	/* Some devices may need time to respond to rst_n */
 	usleep_range(10000, 15000);
 
-	dev_info(hba->dev, "device reset done\n");
+	dev_dbg(hba->dev, "device reset done\n");
 
 	return 0;
 }
@@ -1625,12 +1613,12 @@ static int ufs_mtk_link_set_hpm(struct ufs_hba *hba)
 	/* Check link state to make sure exit h8 success */
 	err = ufs_mtk_wait_idle_state(hba, 5);
 	if (err) {
-		dev_warn(hba->dev, "wait idle fail, err=%d\n", err);
+		dev_err(hba->dev, "Failed to wait for idle: %pe\n", ERR_PTR(err));
 		return err;
 	}
 	err = ufs_mtk_wait_link_state(hba, VS_LINK_UP, 100);
 	if (err) {
-		dev_warn(hba->dev, "exit h8 state fail, err=%d\n", err);
+		dev_err(hba->dev, "Failed to wait for link to be up: %pe\n", ERR_PTR(err));
 		return err;
 	}
 	ufshcd_set_link_active(hba);
@@ -1929,20 +1917,19 @@ static void ufs_mtk_event_notify(struct ufs_hba *hba,
 
 	/* Print details of UIC Errors */
 	if (evt <= UFS_EVT_DME_ERR) {
-		dev_info(hba->dev,
-			 "Host UIC Error Code (%s): %08x\n",
-			 ufs_uic_err_str[evt], val);
+		dev_err(hba->dev, "Host UIC Error Code (%s): %08x\n",
+			ufs_uic_err_str[evt], val);
 		reg = val;
 	}
 
 	if (evt == UFS_EVT_PA_ERR) {
 		for_each_set_bit(bit, &reg, ARRAY_SIZE(ufs_uic_pa_err_str))
-			dev_info(hba->dev, "%s\n", ufs_uic_pa_err_str[bit]);
+			dev_err(hba->dev, "%s\n", ufs_uic_pa_err_str[bit]);
 	}
 
 	if (evt == UFS_EVT_DL_ERR) {
 		for_each_set_bit(bit, &reg, ARRAY_SIZE(ufs_uic_dl_err_str))
-			dev_info(hba->dev, "%s\n", ufs_uic_dl_err_str[bit]);
+			dev_err(hba->dev, "%s\n", ufs_uic_dl_err_str[bit]);
 	}
 }
 
@@ -2147,7 +2134,7 @@ static int ufs_mtk_mcq_config_resource(struct ufs_hba *hba)
 
 	/* fail mcq initialization if interrupt is not filled properly */
 	if (!host->mcq_nr_intr) {
-		dev_info(hba->dev, "IRQs not ready. MCQ disabled.");
+		dev_err(hba->dev, "IRQs not ready. MCQ disabled.");
 		return -EINVAL;
 	}
 

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 18 04:55:09 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 18 Dec 2025 13:55:09 +0100
Subject: [PATCH v4 19/25] scsi: ufs: mediatek: Rework
 ufs_mtk_wait_idle_state
In-Reply-To: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
Message-ID: <20251218-mt8196-ufs-v4-19-ddec7a369dd2@collabora.com>

While ufs_mtk_wait_idle state has some code smells for me (the
VS_HCE_BASE early exit seems racey at best), it can still benefit from
some general cleanup to make the code flow less convoluted.

Use the iopoll helpers, for one, and specifically the one that sleeps
and does not busy delay, as it's being done for up to 5ms.

The register read is split out to a helper function that branches
between new and old style flow.

Every called uses the same 5ms timeout value, so there is no point in
making this a parameter. Just assume a 5ms timeout in the function.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/ufs/host/ufs-mediatek.c | 71 +++++++++++++++++------------------------
 1 file changed, 30 insertions(+), 41 deletions(-)

diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index 8c9daf005e12..b07776f45acb 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -10,6 +10,7 @@
 #include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
@@ -380,51 +381,39 @@ static void ufs_mtk_dbg_sel(struct ufs_hba *hba)
 	}
 }
 
-static int ufs_mtk_wait_idle_state(struct ufs_hba *hba,
-			    unsigned long retry_ms)
+static u32 ufs_mtk_read_state(struct ufs_hba *hba, bool old_style)
 {
-	u64 timeout, time_checked;
-	u32 val, sm;
-	bool wait_idle;
-	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
-
-	/* cannot use plain ktime_get() in suspend */
-	timeout = ktime_get_mono_fast_ns() + retry_ms * 1000000UL;
-
-	/* wait a specific time after check base */
-	udelay(10);
-	wait_idle = false;
+	u32 val;
 
-	do {
-		time_checked = ktime_get_mono_fast_ns();
-		if (host->legacy_ip_ver || host->ip_ver < IP_VER_MT6899) {
-			ufs_mtk_dbg_sel(hba);
-			val = ufshcd_readl(hba, REG_UFS_PROBE);
-		} else {
-			val = ufshcd_readl(hba, REG_UFS_UFS_MMIO_OTSD_CTRL);
-			val = val >> 16;
-		}
+	if (old_style) {
+		ufs_mtk_dbg_sel(hba);
+		val = ufshcd_readl(hba, REG_UFS_PROBE);
+	} else {
+		val = ufshcd_readl(hba, REG_UFS_UFS_MMIO_OTSD_CTRL) >> 16;
+	}
 
-		sm = val & 0x1f;
+	return FIELD_GET(0x1f, val);
+}
 
-		/*
-		 * if state is in H8 enter and H8 enter confirm
-		 * wait until return to idle state.
-		 */
-		if ((sm >= VS_HIB_ENTER) && (sm <= VS_HIB_EXIT)) {
-			wait_idle = true;
-			udelay(50);
-			continue;
-		} else if (!wait_idle)
-			break;
+static int ufs_mtk_wait_idle_state(struct ufs_hba *hba)
+{
+	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
+	bool old_style = (host->legacy_ip_ver || host->ip_ver < IP_VER_MT6899);
+	u32 val;
+	int ret;
 
-		if (wait_idle && (sm == VS_HCE_BASE))
-			break;
-	} while (time_checked < timeout);
+	/* If the device is already in the base state after 10us, don't wait. */
+	udelay(10);
+	if (ufs_mtk_read_state(hba, old_style) == VS_HCE_BASE)
+		return 0;
 
-	if (wait_idle && sm != VS_HCE_BASE) {
-		dev_info(hba->dev, "wait idle tmo: 0x%x\n", val);
-		return -ETIMEDOUT;
+	/* Poll to wait for idle */
+	ret = read_poll_timeout(ufs_mtk_read_state, val,
+				(val < VS_HIB_ENTER || val > VS_HIB_EXIT), 50,
+				5 * USEC_PER_MSEC, false, hba, old_style);
+	if (ret) {
+		dev_err(hba->dev, "Timed out waiting for idle state, val = 0x%x\n", val);
+		return ret;
 	}
 
 	return 0;
@@ -1407,7 +1396,7 @@ static int ufs_mtk_auto_hibern8_disable(struct ufs_hba *hba)
 	ufshcd_writel(hba, 0, REG_AUTO_HIBERNATE_IDLE_TIMER);
 
 	/* wait host return to idle state when auto-hibern8 off */
-	ret = ufs_mtk_wait_idle_state(hba, 5);
+	ret = ufs_mtk_wait_idle_state(hba);
 	if (ret)
 		goto out;
 
@@ -1611,7 +1600,7 @@ static int ufs_mtk_link_set_hpm(struct ufs_hba *hba)
 		return err;
 
 	/* Check link state to make sure exit h8 success */
-	err = ufs_mtk_wait_idle_state(hba, 5);
+	err = ufs_mtk_wait_idle_state(hba);
 	if (err) {
 		dev_err(hba->dev, "Failed to wait for idle: %pe\n", ERR_PTR(err));
 		return err;

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 18 04:55:10 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 18 Dec 2025 13:55:10 +0100
Subject: [PATCH v4 20/25] scsi: ufs: mediatek: Don't acquire dvfsrc-vcore
 twice
In-Reply-To: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
Message-ID: <20251218-mt8196-ufs-v4-20-ddec7a369dd2@collabora.com>

As part of its featureset, the ufs-mediatek driver needs to play with an
optional dvfsrc-vcore regulator for some of them.

However, it currently does this by acquiring two different references to
it in two different places, needlessly duplicating logic.

Move reg_vcore to the host struct, acquire it in the same function as
avdd09 is acquired, and rework the users of reg_vcore.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/ufs/host/ufs-mediatek.c | 73 +++++++++++++++++++----------------------
 drivers/ufs/host/ufs-mediatek.h |  3 +-
 2 files changed, 34 insertions(+), 42 deletions(-)

diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index b07776f45acb..a54c3aeb7bab 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -519,15 +519,13 @@ static void ufs_mtk_boost_crypt(struct ufs_hba *hba, bool boost)
 {
 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
 	struct ufs_mtk_crypt_cfg *cfg;
-	struct regulator *reg;
 	int volt, ret;
 
-	if (!ufs_mtk_is_boost_crypt_enabled(hba))
+	if (!ufs_mtk_is_boost_crypt_enabled(hba) || !host->reg_vcore)
 		return;
 
 	cfg = host->crypt;
 	volt = cfg->vcore_volt;
-	reg = cfg->reg_vcore;
 
 	ret = clk_prepare_enable(cfg->clk_crypt_mux);
 	if (ret) {
@@ -537,7 +535,7 @@ static void ufs_mtk_boost_crypt(struct ufs_hba *hba, bool boost)
 	}
 
 	if (boost) {
-		ret = regulator_set_voltage(reg, volt, INT_MAX);
+		ret = regulator_set_voltage(host->reg_vcore, volt, INT_MAX);
 		if (ret) {
 			dev_err(hba->dev, "%s: Failed to set vcore to %d: %pe\n",
 				__func__, volt, ERR_PTR(ret));
@@ -548,7 +546,7 @@ static void ufs_mtk_boost_crypt(struct ufs_hba *hba, bool boost)
 		if (ret) {
 			dev_err(hba->dev, "%s: Failed to reparent clk_crypt_perf: %pe\n",
 				__func__, ERR_PTR(ret));
-			regulator_set_voltage(reg, 0, INT_MAX);
+			regulator_set_voltage(host->reg_vcore, 0, INT_MAX);
 			goto out;
 		}
 	} else {
@@ -559,7 +557,7 @@ static void ufs_mtk_boost_crypt(struct ufs_hba *hba, bool boost)
 			goto out;
 		}
 
-		ret = regulator_set_voltage(reg, 0, INT_MAX);
+		ret = regulator_set_voltage(host->reg_vcore, 0, INT_MAX);
 		if (ret) {
 			dev_err(hba->dev, "%s: Failed to set vcore to minimum: %pe\n",
 				__func__, ERR_PTR(ret));
@@ -576,16 +574,13 @@ static int ufs_mtk_init_boost_crypt(struct ufs_hba *hba)
 	struct device *dev = hba->dev;
 	int ret;
 
+	if (!host->reg_vcore)
+		return 0;
+
 	cfg = devm_kzalloc(dev, sizeof(*cfg), GFP_KERNEL);
 	if (!cfg)
 		return -ENOMEM;
 
-	cfg->reg_vcore = devm_regulator_get_optional(dev, "dvfsrc-vcore");
-	if (IS_ERR(cfg->reg_vcore)) {
-		dev_err(dev, "Failed to get dvfsrc-vcore: %pe", cfg->reg_vcore);
-		return PTR_ERR(cfg->reg_vcore);
-	}
-
 	ret = of_property_read_u32(dev->of_node, "mediatek,boost-crypt-vcore-min",
 				   &cfg->vcore_volt);
 	if (ret) {
@@ -891,7 +886,6 @@ static void ufs_mtk_init_clocks(struct ufs_hba *hba)
 	struct list_head *head = &hba->clk_list_head;
 	struct ufs_clk_info *clki, *clki_tmp;
 	struct device *dev = hba->dev;
-	struct regulator *reg;
 	u32 volt;
 
 	/*
@@ -932,16 +926,8 @@ static void ufs_mtk_init_clocks(struct ufs_hba *hba)
 		return;
 	}
 
-	/*
-	 * Default get vcore if dts have these settings.
-	 * No matter clock scaling support or not. (may disable by customer)
-	 */
-	reg = devm_regulator_get_optional(dev, "dvfsrc-vcore");
-	if (IS_ERR(reg)) {
-		if (PTR_ERR(reg) != -ENODEV)
-			dev_err(dev, "Failed to get dvfsrc-vcore: %pe\n", reg);
+	if (!host->reg_vcore)
 		return;
-	}
 
 	if (of_property_read_u32(dev->of_node, "mediatek,clk-scale-up-vcore-min",
 				 &volt)) {
@@ -949,12 +935,11 @@ static void ufs_mtk_init_clocks(struct ufs_hba *hba)
 		return;
 	}
 
-	host->mclk.reg_vcore = reg;
 	host->mclk.vcore_volt = volt;
 
 	/* If default boot is max gear, request vcore */
-	if (reg && volt && host->clk_scale_up)
-		if (regulator_set_voltage(reg, volt, INT_MAX))
+	if (volt && host->clk_scale_up)
+		if (regulator_set_voltage(host->reg_vcore, volt, INT_MAX))
 			dev_err(hba->dev, "Failed to set vcore to %d\n", volt);
 }
 
@@ -1066,6 +1051,17 @@ static int ufs_mtk_get_supplies(struct ufs_mtk_host *host)
 	const struct ufs_mtk_soc_data *data = of_device_get_match_data(dev);
 	int ret;
 
+	host->reg_vcore = devm_regulator_get_optional(dev, "dvfsrc-vcore");
+	if (IS_ERR(host->reg_vcore)) {
+		if (PTR_ERR(host->reg_vcore) != -ENODEV) {
+			dev_err(dev, "Failed to get dvfsrc-vcore supply: %pe\n",
+				host->reg_vcore);
+			return PTR_ERR(host->reg_vcore);
+		}
+
+		host->reg_vcore = NULL;
+	}
+
 	if (!data)
 		return 0;
 
@@ -1099,14 +1095,13 @@ static int ufs_mtk_get_supplies(struct ufs_mtk_host *host)
 
 	host->reg_avdd09 = devm_regulator_get_optional(dev, "avdd09");
 	if (IS_ERR(host->reg_avdd09)) {
-		if (PTR_ERR(host->reg_avdd09) == -ENODEV) {
-			host->reg_avdd09 = NULL;
-			return 0;
+		if (PTR_ERR(host->reg_avdd09) != -ENODEV) {
+			dev_err(dev, "Failed to get avdd09 regulator: %pe\n",
+				host->reg_avdd09);
+			return PTR_ERR(host->reg_avdd09);
 		}
 
-		dev_err(dev, "Failed to get avdd09 regulator: %pe\n",
-			host->reg_avdd09);
-		return PTR_ERR(host->reg_avdd09);
+		host->reg_avdd09 = NULL;
 	}
 
 	return 0;
@@ -1137,6 +1132,10 @@ static int ufs_mtk_init(struct ufs_hba *hba)
 	host->hba = hba;
 	ufshcd_set_variant(hba, host);
 
+	err = ufs_mtk_get_supplies(host);
+	if (err)
+		goto out_variant_clear;
+
 	/* Initialize host capability */
 	ufs_mtk_init_host_caps(hba);
 
@@ -1191,10 +1190,6 @@ static int ufs_mtk_init(struct ufs_hba *hba)
 
 	ufs_mtk_init_clocks(hba);
 
-	err = ufs_mtk_get_supplies(host);
-	if (err)
-		goto out_phy_exit;
-
 	/*
 	 * ufshcd_vops_init() is invoked after
 	 * ufshcd_setup_clock(true) in ufshcd_hba_init() thus
@@ -1940,7 +1935,6 @@ static void _ufs_mtk_clk_scale(struct ufs_hba *hba, bool scale_up)
 	struct ufs_mtk_clk *mclk = &host->mclk;
 	struct ufs_clk_info *clki = mclk->ufs_sel_clki;
 	struct ufs_clk_info *fde_clki = mclk->ufs_fde_clki;
-	struct regulator *reg;
 	int volt, ret = 0;
 	bool clk_bind_vcore = false;
 	bool clk_fde_scale = false;
@@ -1951,9 +1945,8 @@ static void _ufs_mtk_clk_scale(struct ufs_hba *hba, bool scale_up)
 	if (!clki || !fde_clki)
 		return;
 
-	reg = host->mclk.reg_vcore;
 	volt = host->mclk.vcore_volt;
-	if (reg && volt != 0)
+	if (host->reg_vcore && volt)
 		clk_bind_vcore = true;
 
 	if (mclk->ufs_fde_max_clki && mclk->ufs_fde_min_clki)
@@ -1977,7 +1970,7 @@ static void _ufs_mtk_clk_scale(struct ufs_hba *hba, bool scale_up)
 
 	if (scale_up) {
 		if (clk_bind_vcore) {
-			ret = regulator_set_voltage(reg, volt, INT_MAX);
+			ret = regulator_set_voltage(host->reg_vcore, volt, INT_MAX);
 			if (ret) {
 				dev_err(hba->dev, "Failed to set vcore to %d\n", volt);
 				goto out;
@@ -2017,7 +2010,7 @@ static void _ufs_mtk_clk_scale(struct ufs_hba *hba, bool scale_up)
 		}
 
 		if (clk_bind_vcore) {
-			ret = regulator_set_voltage(reg, 0, INT_MAX);
+			ret = regulator_set_voltage(host->reg_vcore, 0, INT_MAX);
 			if (ret) {
 				dev_err(hba->dev, "%s: Failed to set vcore to minimum: %pe\n",
 					__func__, ERR_PTR(ret));
diff --git a/drivers/ufs/host/ufs-mediatek.h b/drivers/ufs/host/ufs-mediatek.h
index 5f096ed3f850..9586fe9c0441 100644
--- a/drivers/ufs/host/ufs-mediatek.h
+++ b/drivers/ufs/host/ufs-mediatek.h
@@ -141,7 +141,6 @@ enum ufs_mtk_host_caps {
 };
 
 struct ufs_mtk_crypt_cfg {
-	struct regulator *reg_vcore;
 	struct clk *clk_crypt_perf;
 	struct clk *clk_crypt_mux;
 	struct clk *clk_crypt_lp;
@@ -155,7 +154,6 @@ struct ufs_mtk_clk {
 	struct ufs_clk_info *ufs_fde_clki; /* Mux */
 	struct ufs_clk_info *ufs_fde_max_clki; /* Max src */
 	struct ufs_clk_info *ufs_fde_min_clki; /* Min src */
-	struct regulator *reg_vcore;
 	int vcore_volt;
 };
 
@@ -174,6 +172,7 @@ struct ufs_mtk_mcq_intr_info {
 struct ufs_mtk_host {
 	struct phy *mphy;
 	struct regulator *reg_avdd09;
+	struct regulator *reg_vcore;
 	struct regulator_bulk_data *reg_misc;
 	u8 num_reg_misc;
 	struct reset_control_bulk_data resets[MTK_UFS_NUM_RESETS];

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 18 04:55:11 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 18 Dec 2025 13:55:11 +0100
Subject: [PATCH v4 21/25] scsi: ufs: mediatek: Rework hardware version
 reading
In-Reply-To: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
Message-ID: <20251218-mt8196-ufs-v4-21-ddec7a369dd2@collabora.com>

Split assignment to the host struct out from the read function, and
utilise bitfield helpers to simplify the code. Also move the debug print
out of the legacy version helper, which means it no longer has to take a
struct ufs_hba as an input, and can be rewritten as a pure function.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/ufs/host/ufs-mediatek.c | 65 +++++++++++++++++++++--------------------
 1 file changed, 33 insertions(+), 32 deletions(-)

diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index a54c3aeb7bab..4e545cc414ac 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -799,50 +799,47 @@ static void ufs_mtk_mcq_set_irq_affinity(struct ufs_hba *hba, unsigned int cpu)
 	dev_dbg(hba->dev, "set irq %d affinity to CPU %d\n", irq, _cpu);
 }
 
-static bool ufs_mtk_is_legacy_chipset(struct ufs_hba *hba, u32 hw_ip_ver)
+static bool __pure ufs_mtk_is_legacy_chipset(u32 hw_ip_ver)
 {
-	bool is_legacy = false;
-
 	switch (hw_ip_ver) {
 	case IP_LEGACY_VER_MT6893:
 	case IP_LEGACY_VER_MT6781:
 		/* can add other legacy chipset ID here accordingly */
-		is_legacy = true;
-		break;
-	default:
-		break;
+		return true;
 	}
-	dev_dbg(hba->dev, "IP version 0x%x, legacy = %s", hw_ip_ver,
-		str_true_false(is_legacy));
 
-	return is_legacy;
+	return false;
 }
 
-/*
- * HW version format has been changed from 01MMmmmm to 1MMMmmmm, since
- * project MT6878. In order to perform correct version comparison,
- * version number is changed by SW for the following projects.
- * IP_VER_MT6983	0x00360000 to 0x10360000
- * IP_VER_MT6897	0x01440000 to 0x10440000
- * IP_VER_MT6989	0x01450000 to 0x10450000
- * IP_VER_MT6991	0x01460000 to 0x10460000
+#define MTK_UFS_VER_PREFIX_M (0xFF << 24)
+
+/**
+ * ufs_mtk_get_hw_ip_version - read and return adjusted hardware version
+ * @hba: pointer to this device's &struct ufs_hba
+ *
+ * Reads, transforms and returns the hardware version.
+ *
+ * Since MT6878, the versioning scheme was changed from 01MMmmmm to 1MMMmmmm.
+ * In order to support version comparisons across these different versioning
+ * schemes, this function transforms the older style to the newer one.
+ *
+ * For example:
+ *  MT6983 is transformed from 0x00360000 to 0x10360000
+ *  MT6897 is transformed from 0x01440000 to 0x10440000
+ *  MT6989 is transformed from 0x01450000 to 0x10450000
+ *  MT6991 is transformed from 0x01460000 to 0x10460000
+ *
+ * Returns a u32 representing the hardware version.
  */
-static void ufs_mtk_get_hw_ip_version(struct ufs_hba *hba)
+static u32 ufs_mtk_get_hw_ip_version(struct ufs_hba *hba)
 {
-	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
-	u32 hw_ip_ver;
+	u32 version = ufshcd_readl(hba, REG_UFS_MTK_IP_VER);
+	u32 prefix = FIELD_GET(MTK_UFS_VER_PREFIX_M, version);
 
-	hw_ip_ver = ufshcd_readl(hba, REG_UFS_MTK_IP_VER);
+	if (prefix <= 1)
+		FIELD_MODIFY(MTK_UFS_VER_PREFIX_M, &version, BIT(28));
 
-	if (((hw_ip_ver & (0xFF << 24)) == (0x1 << 24)) ||
-	    ((hw_ip_ver & (0xFF << 24)) == 0)) {
-		hw_ip_ver &= ~(0xFF << 24);
-		hw_ip_ver |= (0x1 << 28);
-	}
-
-	host->ip_ver = hw_ip_ver;
-
-	host->legacy_ip_ver = ufs_mtk_is_legacy_chipset(hba, hw_ip_ver);
+	return version;
 }
 
 static void ufs_mtk_get_controller_version(struct ufs_hba *hba)
@@ -1209,7 +1206,11 @@ static int ufs_mtk_init(struct ufs_hba *hba)
 
 	ufs_mtk_setup_clocks(hba, true, POST_CHANGE);
 
-	ufs_mtk_get_hw_ip_version(hba);
+	host->ip_ver = ufs_mtk_get_hw_ip_version(hba);
+	host->legacy_ip_ver = ufs_mtk_is_legacy_chipset(host->ip_ver);
+
+	dev_dbg(hba->dev, "IP version 0x%x, legacy = %s", host->ip_ver,
+		str_true_false(host->legacy_ip_ver));
 
 	return 0;
 

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 18 04:55:12 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 18 Dec 2025 13:55:12 +0100
Subject: [PATCH v4 22/25] scsi: ufs: mediatek: Back up idle timer in
 per-instance struct
In-Reply-To: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
Message-ID: <20251218-mt8196-ufs-v4-22-ddec7a369dd2@collabora.com>

The MediaTek UFS driver uses a function-scope static variable to back up
a hardware register across a power change in the
ufs_mtk_pwr_change_notify function. This is dangerous, as it's only
correct if only ever one instance of the driver is loaded, which isn't
true if there's more than one device on a SoC that needs it, or it
otherwise gets loaded a second time.

Back it up into a member of the host struct instead, as this struct is
per-instance. Rework the function to not use a pointless "ret" local as
well.

Fixes: f5ca8d0c7a63 ("scsi: ufs: host: mediatek: Disable auto-hibern8 during power mode changes")
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/ufs/host/ufs-mediatek.c | 20 ++++++++------------
 drivers/ufs/host/ufs-mediatek.h |  1 +
 2 files changed, 9 insertions(+), 12 deletions(-)

diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index 4e545cc414ac..147beb46a447 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -1416,28 +1416,24 @@ static int ufs_mtk_pwr_change_notify(struct ufs_hba *hba,
 				const struct ufs_pa_layer_attr *dev_max_params,
 				struct ufs_pa_layer_attr *dev_req_params)
 {
-	int ret = 0;
-	static u32 reg;
+	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
 
 	switch (stage) {
 	case PRE_CHANGE:
 		if (ufshcd_is_auto_hibern8_supported(hba)) {
-			reg = ufshcd_readl(hba, REG_AUTO_HIBERNATE_IDLE_TIMER);
+			host->hibernate_idle_timer = ufshcd_readl(
+				hba, REG_AUTO_HIBERNATE_IDLE_TIMER);
 			ufs_mtk_auto_hibern8_disable(hba);
 		}
-		ret = ufs_mtk_pre_pwr_change(hba, dev_max_params,
-					     dev_req_params);
-		break;
+		return ufs_mtk_pre_pwr_change(hba, dev_max_params, dev_req_params);
 	case POST_CHANGE:
 		if (ufshcd_is_auto_hibern8_supported(hba))
-			ufshcd_writel(hba, reg, REG_AUTO_HIBERNATE_IDLE_TIMER);
-		break;
-	default:
-		ret = -EINVAL;
-		break;
+			ufshcd_writel(hba, host->hibernate_idle_timer,
+				      REG_AUTO_HIBERNATE_IDLE_TIMER);
+		return 0;
 	}
 
-	return ret;
+	return -EINVAL;
 }
 
 static int ufs_mtk_unipro_set_lpm(struct ufs_hba *hba, bool lpm)
diff --git a/drivers/ufs/host/ufs-mediatek.h b/drivers/ufs/host/ufs-mediatek.h
index 9586fe9c0441..59fc432c84b5 100644
--- a/drivers/ufs/host/ufs-mediatek.h
+++ b/drivers/ufs/host/ufs-mediatek.h
@@ -189,6 +189,7 @@ struct ufs_mtk_host {
 	u16 ref_clk_gating_wait_us;
 	u32 ip_ver;
 	bool legacy_ip_ver;
+	u32 hibernate_idle_timer;
 
 	bool mcq_set_intr;
 	bool is_mcq_intr_enabled;

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 18 04:55:13 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 18 Dec 2025 13:55:13 +0100
Subject: [PATCH v4 23/25] scsi: ufs: mediatek: Make scale_us in
 setup_clk_gating const
In-Reply-To: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
Message-ID: <20251218-mt8196-ufs-v4-23-ddec7a369dd2@collabora.com>

The scale_us values are constant, and should be declared as such. Do
this, and use ARRAY_SIZE instead of a fixed <= comparison before
accessing members of the array, to avoid possible future mistakes.

This results in the same assembly with clang, so there is no functional
change, but it makes me feel better.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/ufs/host/ufs-mediatek.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index 147beb46a447..7c5d30a79456 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -942,10 +942,10 @@ static void ufs_mtk_init_clocks(struct ufs_hba *hba)
 
 static void ufs_mtk_setup_clk_gating(struct ufs_hba *hba)
 {
+	const u32 scale_us[] = {1, 10, 100, 1000, 10000, 100000};
 	unsigned long flags;
 	u32 ah_ms = 10;
 	u32 ah_scale, ah_timer;
-	u32 scale_us[] = {1, 10, 100, 1000, 10000, 100000};
 
 	if (ufshcd_is_clkgating_allowed(hba)) {
 		if (ufshcd_is_auto_hibern8_supported(hba) && hba->ahit) {
@@ -953,7 +953,7 @@ static void ufs_mtk_setup_clk_gating(struct ufs_hba *hba)
 					  hba->ahit);
 			ah_timer = FIELD_GET(UFSHCI_AHIBERN8_TIMER_MASK,
 					  hba->ahit);
-			if (ah_scale <= 5)
+			if (ah_scale < ARRAY_SIZE(scale_us))
 				ah_ms = ah_timer * scale_us[ah_scale] / 1000;
 		}
 

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 18 04:55:14 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 18 Dec 2025 13:55:14 +0100
Subject: [PATCH v4 24/25] scsi: ufs: mediatek: Remove ret local from
 link_startup_notify
In-Reply-To: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
Message-ID: <20251218-mt8196-ufs-v4-24-ddec7a369dd2@collabora.com>

Remove the "ret" local variable from ufs_mtk_link_startup_notify, as
it's pointless; in all cases it is assigned, it is returned right after
without being read first.

Rework the code to just return directly, and get rid of the default
branch while at it.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/ufs/host/ufs-mediatek.c | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index 7c5d30a79456..bec726ea15b7 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -1518,21 +1518,15 @@ static void ufs_mtk_post_link(struct ufs_hba *hba)
 static int ufs_mtk_link_startup_notify(struct ufs_hba *hba,
 				       enum ufs_notify_change_status stage)
 {
-	int ret = 0;
-
 	switch (stage) {
 	case PRE_CHANGE:
-		ret = ufs_mtk_pre_link(hba);
-		break;
+		return ufs_mtk_pre_link(hba);
 	case POST_CHANGE:
 		ufs_mtk_post_link(hba);
-		break;
-	default:
-		ret = -EINVAL;
-		break;
+		return 0;
 	}
 
-	return ret;
+	return -EINVAL;
 }
 
 static int ufs_mtk_device_reset(struct ufs_hba *hba)

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Thu Dec 18 04:55:15 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Thu, 18 Dec 2025 13:55:15 +0100
Subject: [PATCH v4 25/25] scsi: ufs: mediatek: Add MT8196 compatible,
 update copyright
In-Reply-To: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
Message-ID: <20251218-mt8196-ufs-v4-25-ddec7a369dd2@collabora.com>

THe MT8196's UFS controller has a new compatible. Add the necessary
struct definitions to support it.

Also update the copyrights and authors, without tabs following spaces to
avoid checkpatch errors, to list myself as having contributed to this
driver after the preceding rework patches.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/ufs/host/ufs-mediatek.c | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index bec726ea15b7..09be752c3c0f 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -1,9 +1,11 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (C) 2019 MediaTek Inc.
+ * Copyright (C) 2025 Collabora Ltd.
  * Authors:
- *	Stanley Chu <stanley.chu at mediatek.com>
- *	Peter Wang <peter.wang at mediatek.com>
+ *      Stanley Chu <stanley.chu at mediatek.com>
+ *      Peter Wang <peter.wang at mediatek.com>
+ *      Nicolas Frattaroli <nicolas.frattaroli at collabora.com> (Major cleanups)
  */
 
 #include <linux/arm-smccc.h>
@@ -2243,6 +2245,10 @@ static const char *const ufs_mtk_regs_avdd12_ckbuf_avdd18[] = {
 	"avdd12", "avdd12-ckbuf", "avdd18"
 };
 
+static const char *const ufs_mtk_regs_avdd12_ckbuf[] = {
+	"avdd12", "avdd12-ckbuf"
+};
+
 static const struct ufs_mtk_soc_data mt8183_data = {
 	.has_avdd09 = true,
 	.reg_names = ufs_mtk_regs_avdd12_avdd18,
@@ -2255,10 +2261,17 @@ static const struct ufs_mtk_soc_data mt8192_8195_data = {
 	.num_reg_names = ARRAY_SIZE(ufs_mtk_regs_avdd12_ckbuf_avdd18),
 };
 
+static const struct ufs_mtk_soc_data mt8196_data = {
+	.has_avdd09 = true,
+	.reg_names = ufs_mtk_regs_avdd12_ckbuf,
+	.num_reg_names = ARRAY_SIZE(ufs_mtk_regs_avdd12_ckbuf),
+};
+
 static const struct of_device_id ufs_mtk_of_match[] = {
 	{ .compatible = "mediatek,mt8183-ufshci", .data = &mt8183_data },
 	{ .compatible = "mediatek,mt8192-ufshci", .data = &mt8192_8195_data },
 	{ .compatible = "mediatek,mt8195-ufshci", .data = &mt8192_8195_data },
+	{ .compatible = "mediatek,mt8196-ufshci", .data = &mt8196_data },
 	{},
 };
 MODULE_DEVICE_TABLE(of, ufs_mtk_of_match);

-- 
2.52.0



From f.pflug at pengutronix.de  Thu Dec 18 05:11:07 2025
From: f.pflug at pengutronix.de (Fabian Pflug)
Date: Thu, 18 Dec 2025 14:11:07 +0100
Subject: [PATCH v4 0/2] Add devicetree for NXP i.MX93 FRDM board
In-Reply-To: <9a96f664-00ba-4589-b3b8-a04355c0ad0b@pengutronix.de>
References: <20251218-fpg-nxp-imx93-frdm-v4-0-cd3a9f6ac89a@pengutronix.de>
	 <9a96f664-00ba-4589-b3b8-a04355c0ad0b@pengutronix.de>
Message-ID: <e15437918fc2e162eec92985e8f11f8e0de91246.camel@pengutronix.de>

Hello Ahmad,

On Thu, 2025-12-18 at 13:52 +0100, Ahmad Fatoum wrote:
> Hello Fabian,
> 
> On 12/18/25 12:39 PM, Fabian Pflug wrote:
> > Signed-off-by: Fabian Pflug <f.pflug at pengutronix.de>
> > ---
> > Changes in v4:
> > - remove it6263 block in i2c1, since it is not finished
> > - remove usdhc3 pwrsequence, since WLAN is not tested on my board
> > - remove eee-broken-1000t on phy2, since it is not broken
> > - update min/max-microvlt on buck converters
> 
> I know you changed this due to reviewer feedback, but it was wrong
> advice. The Linux driver already has information about the minimum and
> maximum range support for the PMIC, what you need to write here is the
> actual board-level constraints.

Yeah, I know, that why I only updated the other two rails and changed to minimum for CPU 0.64 to 0.61V for core.
And 1.06 to 1.14V for DRAM, as it is the settings allowed by the CPU.

VCC3.3 and VCC1.8 were not changed, due to them being connected to multiple devices and I did not want to make them
flexible, as it would be a hassle in the drivers.

Kind regards
Fabian

> 
> I don't think the board will like VDD_3V3 at 1.62V or VDD_1V8 at 3.4V.
> For the fixed voltage rails just set min = max = fixed voltage.
> 
> Thanks,
> Ahmad
> 
> > - Link to v3: https://lore.kernel.org/r/20251022-fpg-nxp-imx93-frdm-v3-0-03ec40a1ccc0 at pengutronix.de
> > 
> > Changes in v3:
> > - Add Signed-off for original NXP contributors.
> > - Fixed whitespace errors (Thanks Francesco Valla)
> > - Added mu1 with status okay (Thanks Francesco Valla)
> > - Removed address cells from lpi2c3 (Thanks Frank Li)
> > - Configure pin for watchdog (Thanks Peng Fan)
> > - Updated regulator config
> > - Configure i2c0
> > - Link to v2: https://lore.kernel.org/r/20250526-fpg-nxp-imx93-frdm-v2-0-e5ad0efaec33 at pengutronix.de
> > 
> > Changes in v2:
> > - 1/2: remove CAN node, as it has not been tested.
> > - 1/2: ran dt-format (Thanks Frank Li)
> > 	But also reordered some nodes afterwards again to have
> > 	regulator-min before regulator-max, have the pinmux at the end
> > 	of the file, and have the regulator-name as the first node
> > 	inside the regulators.
> > 	Re-added comments, that were deleted.
> > - 1/2: changes subjet to ar64:dts (Thanks Fabio Estevan)
> > - 1/2: removed reg_vdd_12v (Tanks Fabio Estevan)
> > - 1/2: added aliases for rtc, emmc, serial (Thanks Fabio Estevan)
> > - reordered the series to have documentation before dts. (Thanks
> > ? Krzystof Kozlowski)
> > - Link to v1: https://lore.kernel.org/r/20250523-fpg-nxp-imx93-frdm-v1-0-546b2d342855 at pengutronix.de
> > 
> > ---
> > Fabian Pflug (2):
> > ????? dt-bindings: arm: fsl: add i.MX93 11x11 FRDM board
> > ????? arm64: dts: freescale: add support for NXP i.MX93 FRDM
> > 
> > ?Documentation/devicetree/bindings/arm/fsl.yaml???? |?? 1 +
> > ?arch/arm64/boot/dts/freescale/Makefile???????????? |?? 1 +
> > ?arch/arm64/boot/dts/freescale/imx93-11x11-frdm.dts | 620 +++++++++++++++++++++
> > ?3 files changed, 622 insertions(+)
> > ---
> > base-commit: ea1013c1539270e372fc99854bc6e4d94eaeff66
> > change-id: 20250523-fpg-nxp-imx93-frdm-5cc180a1fda9
> > 
> > Best regards,


From mani at kernel.org  Thu Dec 18 05:14:27 2025
From: mani at kernel.org (Manivannan Sadhasivam)
Date: Thu, 18 Dec 2025 18:44:27 +0530
Subject: [PATCH v2] PCI: xilinx: Fix INTx IRQ domain leak when MSI
 allocation fails
In-Reply-To: <20251218102314.1474-1-vulab@iscas.ac.cn>
References: <20251119033301.518-1-vulab@iscas.ac.cn>
 <20251218102314.1474-1-vulab@iscas.ac.cn>
Message-ID: <hxxoboh4z7wrstodn3g263zj334sybearuj53myhmzmnocywij@w3rkiu7xiaxi>

On Thu, Dec 18, 2025 at 06:23:14PM +0800, Haotian Zhang wrote:
> In xilinx_pcie_init_irq_domain(), if xilinx_allocate_msi_domains()
> fails after pcie->leg_domain has been successfully created via
> irq_domain_create_linear(), the function returns directly without
> cleaning up the allocated IRQ domain, resulting in a resource leak.
> 
> Add irq_domain_remove() call in the error path to properly release the
> IRQ domain before returning the error.
> 
> Fixes: 313b64c3ae52 ("PCI: xilinx: Convert to MSI domains")
> Suggested-by: Manivannan Sadhasivam <mani at kernel.org>

Sorry, I didn't suggest this change ;)

> Signed-off-by: Haotian Zhang <vulab at iscas.ac.cn>
> ---
> Changes in v2:
>   - Correct the Fixes tag to point to the commit that introduced the
>     legacy IRQ domain leak on MSI allocation failure.
> ---
>  drivers/pci/controller/pcie-xilinx.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/pci/controller/pcie-xilinx.c b/drivers/pci/controller/pcie-xilinx.c
> index 937ea6ae1ac4..e8cf320f3764 100644
> --- a/drivers/pci/controller/pcie-xilinx.c
> +++ b/drivers/pci/controller/pcie-xilinx.c
> @@ -480,8 +480,10 @@ static int xilinx_pcie_init_irq_domain(struct xilinx_pcie *pcie)
>  		phys_addr_t pa = ALIGN_DOWN(virt_to_phys(pcie), SZ_4K);
>  
>  		ret = xilinx_allocate_msi_domains(pcie);
> -		if (ret)
> +		if (ret) {
> +			irq_domain_remove(pcie->leg_domain);
>  			return ret;
> +		}

Looks like this domain is not removed in the further failure path. You need to
rename xilinx_free_msi_domains() to xilinx_free_irq_domains() and remove this
domain in that function as well.

- Mani

-- 
????????? ????????


From jonathan.cameron at huawei.com  Thu Dec 18 05:20:59 2025
From: jonathan.cameron at huawei.com (Jonathan Cameron)
Date: Thu, 18 Dec 2025 13:20:59 +0000
Subject: [RFC PATCH 18/38] arm_mpam: resctrl: Add support for csu
 counters
In-Reply-To: <20251205215901.17772-19-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
	<20251205215901.17772-19-james.morse@arm.com>
Message-ID: <20251218132059.00001a0d@huawei.com>

On Fri, 5 Dec 2025 21:58:41 +0000
James Morse <james.morse at arm.com> wrote:

> resctrl exposes a counter via a file named llc_occupancy. This isn't really
> a counter as its value goes up and down, this is a snapshot of the cache
> storage usage monitor.
> 
> Add some picking code to find a cache as close as possible to the L3 that
> supports the CSU monitor.
> 
> If there is an L3, but it doesn't have any controls, force the L3 resource
> to exist. The existing topology_matches_l3() and
> mpam_resctrl_domain_hdr_init() code will ensure this looks like the L3,
> even if the class belongs to a later cache.
> 
> Signed-off-by: James Morse <james.morse at arm.com>

More triviality from me.  I'll take a separate look at whether this actually
works for all the systems we care about.  It feels like maybe a top level
MPAM to resctl mapping document might be useful as people are going to fall
into traps around these various heuristics, particularly as more exciting
topologies arrive in the future. 


> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
> index fe830524639e..fc1f054f187e 100644
> --- a/drivers/resctrl/mpam_resctrl.c
> +++ b/drivers/resctrl/mpam_resctrl.c

>  /*
>   * Calculate the worst-case percentage change from each implemented step
>   * in the control.
> @@ -499,6 +531,64 @@ static void mpam_resctrl_pick_mba(void)
>  	}
>  }
>  
> +static void counter_update_class(enum resctrl_event_id evt_id,
> +				 struct mpam_class *class)
> +{
> +	struct mpam_class *existing_class = mpam_resctrl_counters[evt_id].class;
> +
> +	if (existing_class) {
> +		if (class->level == 3) {
> +			pr_debug("Existing class is L3 - L3 wins\n");
> +			return;

As returned the else isn't adding anything much.

> +		} else if (existing_class->level < class->level) {
> +			pr_debug("Existing class is closer to L3, %u versus %u - closer is better\n",
> +				 existing_class->level, class->level);
> +			return;
> +		}
> +	}
> +
> +	mpam_resctrl_counters[evt_id].class = class;
> +	exposed_mon_capable = true;
> +}




From andrea.porta at suse.com  Thu Dec 18 05:25:56 2025
From: andrea.porta at suse.com (Andrea della Porta)
Date: Thu, 18 Dec 2025 14:25:56 +0100
Subject: [PATCH v2] arm64: broadcom: bcm2712: Drop rp1 overlay
In-Reply-To: <20251211193854.1778221-1-robh@kernel.org>
References: <20251211193854.1778221-1-robh@kernel.org>
Message-ID: <aUQA5IKqqsrElzKP@apocalypse>

Hi Rob,

On 13:38 Thu 11 Dec     , Rob Herring (Arm) wrote:
> It's a requirement that DT overlays be applied at build time in order to
> validate them as overlays are not validated on their own, but the
> rp1.dtbo is not applied to anything. The rp1.dtso overlay doesn't work
> on its own as there are additional settings needed as seen in
> bcm2712-rpi-5-b.dts. In addition, the 'rp1_nexus' node is applied to the
> wrong place in the DT as it should be under a PCIe root port rather than
> the host bridge. There's also a duplicate overlay in drivers/misc/rp1/.
> 
> For these reasons, just drop the overlay to fix the warning until all
> these issues can be fixed.
> 
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> ---
> The missing applying of rp1.dtbo is now a warning in v6.19-rc1. This
> should be sent to Linus ASAP.
> 
> v2:
>  - Drop the overlay instead of trying to rework. The addition of
>    ethernet0 alias complicates that.
> ---
>  arch/arm64/boot/dts/broadcom/Makefile | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/broadcom/Makefile b/arch/arm64/boot/dts/broadcom/Makefile
> index 83d45afc6588..031875a277d7 100644
> --- a/arch/arm64/boot/dts/broadcom/Makefile
> +++ b/arch/arm64/boot/dts/broadcom/Makefile
> @@ -14,8 +14,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-400.dtb \
>  			      bcm2837-rpi-3-b.dtb \
>  			      bcm2837-rpi-3-b-plus.dtb \
>  			      bcm2837-rpi-cm3-io3.dtb \
> -			      bcm2837-rpi-zero-2-w.dtb \
> -			      rp1.dtbo
> +			      bcm2837-rpi-zero-2-w.dtb

I'm preparing a rework patch that drops the overlay too, it will fix this warning
and the other concerns about RP1 DT hierarchy. Anyway, since this warning seems
to annoy a lot of people, feel free to apply it in the meantime and I'll adapt
accordingly, hence:

Reviewed-by: Andrea della Porta <andrea.porta at suse.com>

Thanks,
Andrea

>  
>  subdir-y	+= bcmbca
>  subdir-y	+= northstar2
> -- 
> 2.51.0
> 


From ludovic.desroches at microchip.com  Thu Dec 18 05:26:01 2025
From: ludovic.desroches at microchip.com (Ludovic Desroches)
Date: Thu, 18 Dec 2025 14:26:01 +0100
Subject: [PATCH v2 3/8] drm/atmel-hlcdc: use drmm_simple_encoder_alloc()
In-Reply-To: <20251218-lcd_cleanup_mainline-v2-0-df837aba878f@microchip.com>
References: <20251218-lcd_cleanup_mainline-v2-0-df837aba878f@microchip.com>
Message-ID: <20251218-lcd_cleanup_mainline-v2-3-df837aba878f@microchip.com>

Simplify the code using drmm_simple_encoder_alloc to handle allocation
and initialization at once.

Signed-off-by: Ludovic Desroches <ludovic.desroches at microchip.com>
Reviewed-by: Manikandan Muralidharan <manikandan.m at microchip.com>
---
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 27 ++++++++----------------
 1 file changed, 9 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
index 0b8a86afb0965ca3085dd5524983a0072199ec0b..1f43e0feeedae54321a17efc266654e72e8b9d8e 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
@@ -73,22 +73,19 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint)
 	struct drm_bridge *bridge;
 	int ret;
 
-	ep = of_graph_get_endpoint_by_regs(dev->dev->of_node, 0, endpoint);
-	if (!ep)
-		return -ENODEV;
-
 	ret = drm_of_find_panel_or_bridge(dev->dev->of_node, 0, endpoint,
 					  &panel, &bridge);
-	if (ret) {
-		of_node_put(ep);
+	if (ret)
 		return ret;
-	}
 
-	output = devm_kzalloc(dev->dev, sizeof(*output), GFP_KERNEL);
-	if (!output) {
-		of_node_put(ep);
-		return -ENOMEM;
-	}
+	output = drmm_simple_encoder_alloc(dev, struct atmel_hlcdc_rgb_output,
+					   encoder, DRM_MODE_ENCODER_NONE);
+	if (IS_ERR(output))
+		return PTR_ERR(output);
+
+	ep = of_graph_get_endpoint_by_regs(dev->dev->of_node, 0, endpoint);
+	if (!ep)
+		return -ENODEV;
 
 	output->bus_fmt = atmel_hlcdc_of_bus_fmt(ep);
 	of_node_put(ep);
@@ -97,10 +94,6 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint)
 		return -EINVAL;
 	}
 
-	ret = drm_simple_encoder_init(dev, &output->encoder,
-				      DRM_MODE_ENCODER_NONE);
-	if (ret)
-		return ret;
 
 	output->encoder.possible_crtcs = 0x1;
 
@@ -120,8 +113,6 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint)
 			drm_panel_bridge_remove(bridge);
 	}
 
-	drm_encoder_cleanup(&output->encoder);
-
 	return ret;
 }
 

-- 
2.51.0



From ludovic.desroches at microchip.com  Thu Dec 18 05:25:58 2025
From: ludovic.desroches at microchip.com (Ludovic Desroches)
Date: Thu, 18 Dec 2025 14:25:58 +0100
Subject: [PATCH v2 0/8] drm/atmel-hlcdc: make more use of helpers
Message-ID: <20251218-lcd_cleanup_mainline-v2-0-df837aba878f@microchip.com>

Hi,

This set of patches is mostly about using available helpers when
possible to simplify the code and ease the maintenance.

There is a dependency on "drm/panel: simple: restore connector_type
fallback", otherwise the atmel-hlcdc driver may fail during the probe.

Signed-off-by: Ludovic Desroches <ludovic.desroches at microchip.com>
---
Changes in v2:
- Fix patch 5 warning about uninitialized use of ret.
- Link to v1: https://lore.kernel.org/r/20251121-lcd_cleanup_mainline-v1-0-2587e6fe4d67 at microchip.com

---
Ludovic Desroches (8):
      drm/atmel-hlcdc: use managed device resources for the display controller
      drm/atmel-hlcdc: add support for the nomodeset kernel parameter
      drm/atmel-hlcdc: use drmm_simple_encoder_alloc()
      drm/atmel-hlcdc: use drm_crtc_mask()
      drm/atmel-hlcdc: use devm_drm_of_get_bridge()
      drm/atmel-hlcdc: use drmm_crtc_alloc_with_planes()
      drm/atmel-hlcdc: use drmm_universal_plane_alloc()
      drm/atmel-hlcdc: destroy properly the plane state in the reset callback

 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c   | 32 ++---------
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c     | 40 +++++++------
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h     |  1 +
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 50 +++++-----------
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c  | 73 +++++++++++-------------
 5 files changed, 75 insertions(+), 121 deletions(-)
---
base-commit: 88cbd8ac379cf5ce68b7efcfd4d1484a6871ee0b
change-id: 20251121-lcd_cleanup_mainline-b6acc75b5a09

Best regards,
-- 
Ludovic Desroches <ludovic.desroches at microchip.com>



From ludovic.desroches at microchip.com  Thu Dec 18 05:26:02 2025
From: ludovic.desroches at microchip.com (Ludovic Desroches)
Date: Thu, 18 Dec 2025 14:26:02 +0100
Subject: [PATCH v2 4/8] drm/atmel-hlcdc: use drm_crtc_mask()
In-Reply-To: <20251218-lcd_cleanup_mainline-v2-0-df837aba878f@microchip.com>
References: <20251218-lcd_cleanup_mainline-v2-0-df837aba878f@microchip.com>
Message-ID: <20251218-lcd_cleanup_mainline-v2-4-df837aba878f@microchip.com>

Prefer using the drm_crtc_mask() helper instead of a raw value. It
involves reordering components initialization as we need a valid crtc.

Signed-off-by: Ludovic Desroches <ludovic.desroches at microchip.com>
Reviewed-by: Manikandan Muralidharan <manikandan.m at microchip.com>
---
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c     | 12 ++++++------
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c |  4 +++-
 2 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
index 8ff582a394794aacf84f9e23fd59f123445926a3..d1f5451ebfeaf81c382b49d0c1a6c3c32e44866b 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
@@ -723,12 +723,6 @@ static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev)
 
 	drm_mode_config_init(dev);
 
-	ret = atmel_hlcdc_create_outputs(dev);
-	if (ret) {
-		drm_err(dev, "failed to create HLCDC outputs: %d\n", ret);
-		return ret;
-	}
-
 	ret = atmel_hlcdc_create_planes(dev);
 	if (ret) {
 		drm_err(dev, "failed to create planes: %d\n", ret);
@@ -741,6 +735,12 @@ static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev)
 		return ret;
 	}
 
+	ret = atmel_hlcdc_create_outputs(dev);
+	if (ret) {
+		drm_err(dev, "failed to create HLCDC outputs: %d\n", ret);
+		return ret;
+	}
+
 	dev->mode_config.min_width = dc->desc->min_width;
 	dev->mode_config.min_height = dc->desc->min_height;
 	dev->mode_config.max_width = dc->desc->max_width;
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
index 1f43e0feeedae54321a17efc266654e72e8b9d8e..e582315f70a119f2b39057ff112bc427117b85f5 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
@@ -71,6 +71,8 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint)
 	struct device_node *ep;
 	struct drm_panel *panel;
 	struct drm_bridge *bridge;
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	struct drm_crtc *crtc = dc->crtc;
 	int ret;
 
 	ret = drm_of_find_panel_or_bridge(dev->dev->of_node, 0, endpoint,
@@ -95,7 +97,6 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint)
 	}
 
 
-	output->encoder.possible_crtcs = 0x1;
 
 	if (panel) {
 		bridge = drm_panel_bridge_add_typed(panel,
@@ -103,6 +104,7 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint)
 		if (IS_ERR(bridge))
 			return PTR_ERR(bridge);
 	}
+	output->encoder.possible_crtcs = drm_crtc_mask(crtc);
 
 	if (bridge) {
 		ret = drm_bridge_attach(&output->encoder, bridge, NULL, 0);

-- 
2.51.0



From ludovic.desroches at microchip.com  Thu Dec 18 05:26:03 2025
From: ludovic.desroches at microchip.com (Ludovic Desroches)
Date: Thu, 18 Dec 2025 14:26:03 +0100
Subject: [PATCH v2 5/8] drm/atmel-hlcdc: use devm_drm_of_get_bridge()
In-Reply-To: <20251218-lcd_cleanup_mainline-v2-0-df837aba878f@microchip.com>
References: <20251218-lcd_cleanup_mainline-v2-0-df837aba878f@microchip.com>
Message-ID: <20251218-lcd_cleanup_mainline-v2-5-df837aba878f@microchip.com>

Get rid of drm_of_find_panel_or_bridge() as it is deprecated and use
devm_drm_of_get_bridge() instead.

Signed-off-by: Ludovic Desroches <ludovic.desroches at microchip.com>
---
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 25 +++++-------------------
 1 file changed, 5 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
index e582315f70a119f2b39057ff112bc427117b85f5..e8aea905fb10d20d89c0cfd7937039b44d8a55b7 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
@@ -69,16 +69,14 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint)
 {
 	struct atmel_hlcdc_rgb_output *output;
 	struct device_node *ep;
-	struct drm_panel *panel;
 	struct drm_bridge *bridge;
 	struct atmel_hlcdc_dc *dc = dev->dev_private;
 	struct drm_crtc *crtc = dc->crtc;
-	int ret;
+	int ret = 0;
 
-	ret = drm_of_find_panel_or_bridge(dev->dev->of_node, 0, endpoint,
-					  &panel, &bridge);
-	if (ret)
-		return ret;
+	bridge = devm_drm_of_get_bridge(dev->dev, dev->dev->of_node, 0, endpoint);
+	if (IS_ERR(bridge))
+		return PTR_ERR(bridge);
 
 	output = drmm_simple_encoder_alloc(dev, struct atmel_hlcdc_rgb_output,
 					   encoder, DRM_MODE_ENCODER_NONE);
@@ -97,23 +95,10 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint)
 	}
 
 
-
-	if (panel) {
-		bridge = drm_panel_bridge_add_typed(panel,
-						    DRM_MODE_CONNECTOR_Unknown);
-		if (IS_ERR(bridge))
-			return PTR_ERR(bridge);
-	}
 	output->encoder.possible_crtcs = drm_crtc_mask(crtc);
 
-	if (bridge) {
+	if (bridge)
 		ret = drm_bridge_attach(&output->encoder, bridge, NULL, 0);
-		if (!ret)
-			return 0;
-
-		if (panel)
-			drm_panel_bridge_remove(bridge);
-	}
 
 	return ret;
 }

-- 
2.51.0



From ludovic.desroches at microchip.com  Thu Dec 18 05:26:04 2025
From: ludovic.desroches at microchip.com (Ludovic Desroches)
Date: Thu, 18 Dec 2025 14:26:04 +0100
Subject: [PATCH v2 6/8] drm/atmel-hlcdc: use drmm_crtc_alloc_with_planes()
In-Reply-To: <20251218-lcd_cleanup_mainline-v2-0-df837aba878f@microchip.com>
References: <20251218-lcd_cleanup_mainline-v2-0-df837aba878f@microchip.com>
Message-ID: <20251218-lcd_cleanup_mainline-v2-6-df837aba878f@microchip.com>

Use drmm_crtc_alloc_with_planes() to simplify the code. As we no longer
have to take care about cleanup, we can get rid of
atmel_hlcdc_crtc_destroy().

Signed-off-by: Ludovic Desroches <ludovic.desroches at microchip.com>
Reviewed-by: Manikandan Muralidharan <manikandan.m at microchip.com>
---
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c | 32 +++++---------------------
 1 file changed, 6 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
index e0efc7309b1b256520eff29462431476f8589255..b075f291847f9eb91e07b7844382871f38ed5f81 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
@@ -509,14 +509,6 @@ static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = {
 	.atomic_disable = atmel_hlcdc_crtc_atomic_disable,
 };
 
-static void atmel_hlcdc_crtc_destroy(struct drm_crtc *c)
-{
-	struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
-
-	drm_crtc_cleanup(c);
-	kfree(crtc);
-}
-
 static void atmel_hlcdc_crtc_finish_page_flip(struct atmel_hlcdc_crtc *crtc)
 {
 	struct drm_device *dev = crtc->base.dev;
@@ -607,7 +599,6 @@ static void atmel_hlcdc_crtc_disable_vblank(struct drm_crtc *c)
 static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = {
 	.page_flip = drm_atomic_helper_page_flip,
 	.set_config = drm_atomic_helper_set_config,
-	.destroy = atmel_hlcdc_crtc_destroy,
 	.reset = atmel_hlcdc_crtc_reset,
 	.atomic_duplicate_state =  atmel_hlcdc_crtc_duplicate_state,
 	.atomic_destroy_state = atmel_hlcdc_crtc_destroy_state,
@@ -620,15 +611,8 @@ int atmel_hlcdc_crtc_create(struct drm_device *dev)
 	struct atmel_hlcdc_plane *primary = NULL, *cursor = NULL;
 	struct atmel_hlcdc_dc *dc = dev->dev_private;
 	struct atmel_hlcdc_crtc *crtc;
-	int ret;
 	int i;
 
-	crtc = kzalloc(sizeof(*crtc), GFP_KERNEL);
-	if (!crtc)
-		return -ENOMEM;
-
-	crtc->dc = dc;
-
 	for (i = 0; i < ATMEL_HLCDC_MAX_LAYERS; i++) {
 		if (!dc->layers[i])
 			continue;
@@ -646,13 +630,13 @@ int atmel_hlcdc_crtc_create(struct drm_device *dev)
 			break;
 		}
 	}
+	crtc = drmm_crtc_alloc_with_planes(dev, struct atmel_hlcdc_crtc, base,
+					   &primary->base, &cursor->base, &atmel_hlcdc_crtc_funcs,
+					   NULL);
+	if (IS_ERR(crtc))
+		return PTR_ERR(crtc);
 
-	ret = drm_crtc_init_with_planes(dev, &crtc->base, &primary->base,
-					&cursor->base, &atmel_hlcdc_crtc_funcs,
-					NULL);
-	if (ret < 0)
-		goto fail;
-
+	crtc->dc = dc;
 	crtc->id = drm_crtc_index(&crtc->base);
 
 	for (i = 0; i < ATMEL_HLCDC_MAX_LAYERS; i++) {
@@ -674,8 +658,4 @@ int atmel_hlcdc_crtc_create(struct drm_device *dev)
 	dc->crtc = &crtc->base;
 
 	return 0;
-
-fail:
-	atmel_hlcdc_crtc_destroy(&crtc->base);
-	return ret;
 }

-- 
2.51.0



From ludovic.desroches at microchip.com  Thu Dec 18 05:26:05 2025
From: ludovic.desroches at microchip.com (Ludovic Desroches)
Date: Thu, 18 Dec 2025 14:26:05 +0100
Subject: [PATCH v2 7/8] drm/atmel-hlcdc: use drmm_universal_plane_alloc()
In-Reply-To: <20251218-lcd_cleanup_mainline-v2-0-df837aba878f@microchip.com>
References: <20251218-lcd_cleanup_mainline-v2-0-df837aba878f@microchip.com>
Message-ID: <20251218-lcd_cleanup_mainline-v2-7-df837aba878f@microchip.com>

Use the drmm_universal_plane_alloc() helper to simplify the code. Using
it, we no longer need to register the destroy callback for
drm_plane_funcs.

Signed-off-by: Ludovic Desroches <ludovic.desroches at microchip.com>
Reviewed-by: Manikandan Muralidharan <manikandan.m at microchip.com>
---
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 21 +++++++--------------
 1 file changed, 7 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
index 92132be9823f1e705d266f9547702ea9530bd043..c1f3aaae29fb9f6b947f81e2fb4e7a61e10ac5d9 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
@@ -1225,7 +1225,6 @@ static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p,
 static const struct drm_plane_funcs layer_plane_funcs = {
 	.update_plane = drm_atomic_helper_update_plane,
 	.disable_plane = drm_atomic_helper_disable_plane,
-	.destroy = drm_plane_cleanup,
 	.reset = atmel_hlcdc_plane_reset,
 	.atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
 	.atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
@@ -1239,12 +1238,6 @@ static int atmel_hlcdc_plane_create(struct drm_device *dev,
 	enum drm_plane_type type;
 	int ret;
 
-	plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
-	if (!plane)
-		return -ENOMEM;
-
-	atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap);
-
 	if (desc->type == ATMEL_HLCDC_BASE_LAYER)
 		type = DRM_PLANE_TYPE_PRIMARY;
 	else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
@@ -1252,13 +1245,13 @@ static int atmel_hlcdc_plane_create(struct drm_device *dev,
 	else
 		type = DRM_PLANE_TYPE_OVERLAY;
 
-	ret = drm_universal_plane_init(dev, &plane->base, 0,
-				       &layer_plane_funcs,
-				       desc->formats->formats,
-				       desc->formats->nformats,
-				       NULL, type, NULL);
-	if (ret)
-		return ret;
+	plane = drmm_universal_plane_alloc(dev, struct atmel_hlcdc_plane, base, 0,
+					   &layer_plane_funcs, desc->formats->formats,
+					   desc->formats->nformats, NULL, type, NULL);
+	if (IS_ERR(plane))
+		return PTR_ERR(plane);
+
+	atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap);
 
 	drm_plane_helper_add(&plane->base,
 			     &atmel_hlcdc_layer_plane_helper_funcs);

-- 
2.51.0



From ludovic.desroches at microchip.com  Thu Dec 18 05:26:06 2025
From: ludovic.desroches at microchip.com (Ludovic Desroches)
Date: Thu, 18 Dec 2025 14:26:06 +0100
Subject: [PATCH v2 8/8] drm/atmel-hlcdc: destroy properly the plane state
 in the reset callback
In-Reply-To: <20251218-lcd_cleanup_mainline-v2-0-df837aba878f@microchip.com>
References: <20251218-lcd_cleanup_mainline-v2-0-df837aba878f@microchip.com>
Message-ID: <20251218-lcd_cleanup_mainline-v2-8-df837aba878f@microchip.com>

If there is a plane state to destroy when doing a plane reset, destroy
it using the atmel_hlcdc_plane_destroy_state() function. So we call
__drm_atomic_helper_plane_destroy_state() and avoid code duplication.

Signed-off-by: Ludovic Desroches <ludovic.desroches at microchip.com>
---
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 52 ++++++++++++-------------
 1 file changed, 26 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
index c1f3aaae29fb9f6b947f81e2fb4e7a61e10ac5d9..81dc730362322a4bae9b48dca97b06baa1e331e7 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
@@ -1155,32 +1155,6 @@ static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane *p,
 	return -ENOMEM;
 }
 
-static void atmel_hlcdc_plane_reset(struct drm_plane *p)
-{
-	struct atmel_hlcdc_plane_state *state;
-
-	if (p->state) {
-		state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
-
-		if (state->base.fb)
-			drm_framebuffer_put(state->base.fb);
-
-		kfree(state);
-		p->state = NULL;
-	}
-
-	state = kzalloc(sizeof(*state), GFP_KERNEL);
-	if (state) {
-		if (atmel_hlcdc_plane_alloc_dscrs(p, state)) {
-			kfree(state);
-			drm_err(p->dev,
-				"Failed to allocate initial plane state\n");
-			return;
-		}
-		__drm_atomic_helper_plane_reset(p, &state->base);
-	}
-}
-
 static struct drm_plane_state *
 atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
 {
@@ -1222,6 +1196,32 @@ static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p,
 	kfree(state);
 }
 
+static void atmel_hlcdc_plane_reset(struct drm_plane *p)
+{
+	struct atmel_hlcdc_plane_state *state;
+	struct atmel_hlcdc_dc *dc = p->dev->dev_private;
+	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+
+	if (p->state) {
+		atmel_hlcdc_plane_atomic_destroy_state(p, p->state);
+		p->state = NULL;
+	}
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (state) {
+		if (atmel_hlcdc_plane_alloc_dscrs(p, state)) {
+			kfree(state);
+			drm_err(p->dev,
+				"Failed to allocate initial plane state\n");
+			return;
+		}
+		__drm_atomic_helper_plane_reset(p, &state->base);
+	}
+
+	if (plane->layer.desc->layout.csc)
+		dc->desc->ops->lcdc_csc_init(plane, plane->layer.desc);
+}
+
 static const struct drm_plane_funcs layer_plane_funcs = {
 	.update_plane = drm_atomic_helper_update_plane,
 	.disable_plane = drm_atomic_helper_disable_plane,

-- 
2.51.0



From ludovic.desroches at microchip.com  Thu Dec 18 05:25:59 2025
From: ludovic.desroches at microchip.com (Ludovic Desroches)
Date: Thu, 18 Dec 2025 14:25:59 +0100
Subject: [PATCH v2 1/8] drm/atmel-hlcdc: use managed device resources for
 the display controller
In-Reply-To: <20251218-lcd_cleanup_mainline-v2-0-df837aba878f@microchip.com>
References: <20251218-lcd_cleanup_mainline-v2-0-df837aba878f@microchip.com>
Message-ID: <20251218-lcd_cleanup_mainline-v2-1-df837aba878f@microchip.com>

Take benefit of managed device resources to reduce the risk of memory
leak and to simplify error paths.

Signed-off-by: Ludovic Desroches <ludovic.desroches at microchip.com>
Reviewed-by: Manikandan Muralidharan <manikandan.m at microchip.com>
---
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | 25 ++++++++++++-------------
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h |  1 +
 2 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
index dd70894c8f38e7303e06167594ac289cb345b510..8ed029381c555db10d596efc8d52753c47767633 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
@@ -751,11 +751,16 @@ static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev)
 	return 0;
 }
 
+static struct atmel_hlcdc_dc *atmel_hlcdc_dc_of_dev(struct drm_device *dev)
+{
+	return container_of(dev, struct atmel_hlcdc_dc, dev);
+}
+
 static int atmel_hlcdc_dc_load(struct drm_device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev->dev);
 	const struct of_device_id *match;
-	struct atmel_hlcdc_dc *dc;
+	struct atmel_hlcdc_dc *dc = atmel_hlcdc_dc_of_dev(dev);
 	int ret;
 
 	match = of_match_node(atmel_hlcdc_of_match, dev->dev->parent->of_node);
@@ -769,10 +774,6 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev)
 		return -EINVAL;
 	}
 
-	dc = devm_kzalloc(dev->dev, sizeof(*dc), GFP_KERNEL);
-	if (!dc)
-		return -ENOMEM;
-
 	dc->desc = match->data;
 	dc->hlcdc = dev_get_drvdata(dev->dev->parent);
 	dev->dev_private = dc;
@@ -853,16 +854,18 @@ static const struct drm_driver atmel_hlcdc_dc_driver = {
 
 static int atmel_hlcdc_dc_drm_probe(struct platform_device *pdev)
 {
+	struct atmel_hlcdc_dc *dc;
 	struct drm_device *ddev;
 	int ret;
 
-	ddev = drm_dev_alloc(&atmel_hlcdc_dc_driver, &pdev->dev);
-	if (IS_ERR(ddev))
-		return PTR_ERR(ddev);
+	dc = devm_drm_dev_alloc(&pdev->dev, &atmel_hlcdc_dc_driver, struct atmel_hlcdc_dc, dev);
+	if (IS_ERR(dc))
+		return PTR_ERR(dc);
+	ddev = &dc->dev;
 
 	ret = atmel_hlcdc_dc_load(ddev);
 	if (ret)
-		goto err_put;
+		return ret;
 
 	ret = drm_dev_register(ddev, 0);
 	if (ret)
@@ -875,9 +878,6 @@ static int atmel_hlcdc_dc_drm_probe(struct platform_device *pdev)
 err_unload:
 	atmel_hlcdc_dc_unload(ddev);
 
-err_put:
-	drm_dev_put(ddev);
-
 	return ret;
 }
 
@@ -887,7 +887,6 @@ static void atmel_hlcdc_dc_drm_remove(struct platform_device *pdev)
 
 	drm_dev_unregister(ddev);
 	atmel_hlcdc_dc_unload(ddev);
-	drm_dev_put(ddev);
 }
 
 static void atmel_hlcdc_dc_drm_shutdown(struct platform_device *pdev)
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
index 53d47f01db0bd4d906b73f9f2a46f2ef7326d8c6..26b26185cf34ac1678f385982caabd2dbbc22630 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
@@ -350,6 +350,7 @@ struct atmel_hlcdc_dc {
 	struct dma_pool *dscrpool;
 	struct atmel_hlcdc *hlcdc;
 	struct drm_crtc *crtc;
+	struct drm_device dev;
 	struct atmel_hlcdc_layer *layers[ATMEL_HLCDC_MAX_LAYERS];
 	struct {
 		u32 imr;

-- 
2.51.0



From ludovic.desroches at microchip.com  Thu Dec 18 05:26:00 2025
From: ludovic.desroches at microchip.com (Ludovic Desroches)
Date: Thu, 18 Dec 2025 14:26:00 +0100
Subject: [PATCH v2 2/8] drm/atmel-hlcdc: add support for the nomodeset
 kernel parameter
In-Reply-To: <20251218-lcd_cleanup_mainline-v2-0-df837aba878f@microchip.com>
References: <20251218-lcd_cleanup_mainline-v2-0-df837aba878f@microchip.com>
Message-ID: <20251218-lcd_cleanup_mainline-v2-2-df837aba878f@microchip.com>

According to Documentation/admin-guide/kernel-parameters.txt, this
parameter can be used to disable kernel modesetting.

Signed-off-by: Ludovic Desroches <ludovic.desroches at microchip.com>
Reviewed-by: Dharma Balasubiramani <dharma.b at microchip.com>
Reviewed-by: Manikandan Muralidharan <manikandan.m at microchip.com>
---
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
index 8ed029381c555db10d596efc8d52753c47767633..8ff582a394794aacf84f9e23fd59f123445926a3 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
@@ -858,6 +858,9 @@ static int atmel_hlcdc_dc_drm_probe(struct platform_device *pdev)
 	struct drm_device *ddev;
 	int ret;
 
+	if (drm_firmware_drivers_only())
+		return -ENODEV;
+
 	dc = devm_drm_dev_alloc(&pdev->dev, &atmel_hlcdc_dc_driver, struct atmel_hlcdc_dc, dev);
 	if (IS_ERR(dc))
 		return PTR_ERR(dc);

-- 
2.51.0



From jonathan.cameron at huawei.com  Thu Dec 18 05:36:11 2025
From: jonathan.cameron at huawei.com (Jonathan Cameron)
Date: Thu, 18 Dec 2025 13:36:11 +0000
Subject: [RFC PATCH 19/38] arm_mpam: resctrl: pick classes for use as
 mbm counters
In-Reply-To: <20251205215901.17772-20-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
	<20251205215901.17772-20-james.morse@arm.com>
Message-ID: <20251218133611.00000a3c@huawei.com>

On Fri, 5 Dec 2025 21:58:42 +0000
James Morse <james.morse at arm.com> wrote:

> resctrl has two types of counters, NUMA-local and global. MPAM has only
> bandwidth counters, but the position of the MSC may mean it counts
> NUMA-local, or global traffic.
> 
> But the topology information is not available.
> 
> Apply a heuristic: the L2 or L3 supports bandwidth monitors, these are
> probably NUMA-local. If the memory controller supports bandwidth
> monitors, they are probably global.
> 
> This also allows us to assert that we don't have the same class
> backing two different resctrl events.
> 
> Because the class or component backing the event may not be 'the L3',
> it is necessary for mpam_resctrl_get_domain_from_cpu() to search
> the monitor domains too. This matters the most for 'monitor only'
> systems, where 'the L3' control domains may be empty, and the
> ctrl_comp pointer NULL.
> 
> resctrl expects there to be enough monitors for every possible control
> and monitor group to have one. Such a system gets called 'free running'
> as the monitors can be programmed once and left running.
> Any other platform will need to emulate ABMC.
> 
> Signed-off-by: James Morse <james.morse at arm.com>
> ---

> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
> index fc1f054f187e..9978eb48c1f4 100644
> --- a/drivers/resctrl/mpam_resctrl.c
> +++ b/drivers/resctrl/mpam_resctrl.c

> @@ -586,7 +614,37 @@ static void mpam_resctrl_pick_counters(void)
>  				return;
>  			}
>  		}
> +
> +		has_mbwu = class_has_usable_mbwu(class);
> +		if (has_mbwu && topology_matches_l3(class)) {

Might get reused in later patches. If not
		if (class_has_usable_mbwu(class) && topology_matches_l3(class))

> +			pr_debug("class %u has usable MBWU, and matches L3 topology",
> +				 class->level);
> +
> +			/*
> +			 * MBWU counters may be 'local' or 'total' depending on
> +			 * where they are in the topology. Counters on caches
> +			 * are assumed to be local. If it's on the memory
> +			 * controller, its assumed to be global.
> +			 */
> +			switch (class->type) {
> +			case MPAM_CLASS_CACHE:
> +				counter_update_class(QOS_L3_MBM_LOCAL_EVENT_ID,
> +						     class);
> +				break;
> +			case MPAM_CLASS_MEMORY:
> +				counter_update_class(QOS_L3_MBM_TOTAL_EVENT_ID,
> +						     class);
> +				break;
> +			default:
> +				break;
> +			}
> +		}
>  	}
> +
> +	/* Allocation of MBWU monitors assumes that the class is unique... */
> +	if (mpam_resctrl_counters[QOS_L3_MBM_LOCAL_EVENT_ID].class)
> +		WARN_ON_ONCE(mpam_resctrl_counters[QOS_L3_MBM_LOCAL_EVENT_ID].class ==
> +			     mpam_resctrl_counters[QOS_L3_MBM_TOTAL_EVENT_ID].class);
>  }

>  
> +/*
> + * We know all the monitors are associated with the L3, even if there are no
> + * controls and therefore no control component. Find the cache-id for the CPU
> + * and use that to search for existing resctrl domains.
> + * This relies on mpam_resctrl_pick_domain_id() using the L3 cache-id
> + * for anything that is not a cache.
> + */
> +static struct mpam_resctrl_dom *mpam_resctrl_get_mon_domain_from_cpu(int cpu)
> +{
> +	u32 cache_id;
> +	struct rdt_mon_domain *mon_d;
> +	struct mpam_resctrl_dom *dom;
> +	struct mpam_resctrl_res *l3 = &mpam_resctrl_controls[RDT_RESOURCE_L3];
> +
> +	if (!l3->class)
> +		return NULL;
> +	/* TODO: how does this order with cacheinfo updates under cpuhp? */
> +	cache_id = get_cpu_cacheinfo_id(cpu, 3);
> +	if (cache_id == ~0)
> +		return NULL;
> +
> +	list_for_each_entry(mon_d, &l3->resctrl_res.mon_domains, hdr.list) {
> +		dom = container_of(mon_d, struct mpam_resctrl_dom, resctrl_mon_dom);

Similar comment to one on earlier patch. Can make the list iterator directly
provide dom as that's what it's actually a list of, not rdt_mon_domain structures.

> +
> +		if (mon_d->hdr.id == cache_id)
> +			return dom;
> +	}
> +
> +	return NULL;
> +}
> +
>  static struct mpam_resctrl_dom *
>  mpam_resctrl_get_domain_from_cpu(int cpu, struct mpam_resctrl_res *res)
>  {
>  	struct mpam_resctrl_dom *dom;
>  	struct rdt_ctrl_domain *ctrl_d;
> +	struct rdt_resource *r = &res->resctrl_res;

Push back to original patch.   

>  
>  	lockdep_assert_cpus_held();
>  
> -	list_for_each_entry_rcu(ctrl_d, &res->resctrl_res.ctrl_domains,
> -				hdr.list) {
> +	list_for_each_entry_rcu(ctrl_d, &r->ctrl_domains, hdr.list) {
>  		dom = container_of(ctrl_d, struct mpam_resctrl_dom,
>  				   resctrl_ctrl_dom);
>  




From konrad.dybcio at oss.qualcomm.com  Thu Dec 18 05:39:34 2025
From: konrad.dybcio at oss.qualcomm.com (Konrad Dybcio)
Date: Thu, 18 Dec 2025 14:39:34 +0100
Subject: [PATCH v7 5/5] arm64: dts: qcom: monaco-evk-camera: Add DT
 overlay
In-Reply-To: <5bd29b5f-6fcf-428d-b451-698d92f0883e@linaro.org>
References: <20251216062223.2474216-1-quic_nihalkum@quicinc.com>
 <20251216062223.2474216-6-quic_nihalkum@quicinc.com>
 <5bd29b5f-6fcf-428d-b451-698d92f0883e@linaro.org>
Message-ID: <9964bf4b-a6ed-4429-8c70-520cd19781e9@oss.qualcomm.com>

On 12/16/25 8:35 AM, Vladimir Zapolskiy wrote:
> On 12/16/25 08:22, Nihal Kumar Gupta wrote:
>> Monaco EVK board does not include a camera sensor in its default hardware
>> configuration. Introducing a device tree overlay to support optional
>> integration of the IMX577 sensor via CSIPHY1.
>>
>> Camera reset is handled through an I2C expander, and power is enabled
>> via TLMM GPIO74.
>>
>> An example media-ctl pipeline for the imx577 is:

[...]

> If only one of 3 defined from 4/5 regulators is used, do you really wish
> to describle all 3 in advance? You may consider to remove 2 currently unused
> GPIO controlled regulator descriptions, and squash this change with 4/5.

This is useful, if only to surely park them when unused.

Konrad


From andrea.porta at suse.com  Thu Dec 18 05:43:08 2025
From: andrea.porta at suse.com (Andrea della Porta)
Date: Thu, 18 Dec 2025 14:43:08 +0100
Subject: [RFC PATCH] arm64: broadcom: bcm2712: Rework rp1 overlay handling
In-Reply-To: <aTgrHEoxl7J8_BuU@apocalypse>
References: <20251117211503.728354-2-robh@kernel.org>
 <aTgrHEoxl7J8_BuU@apocalypse>
Message-ID: <aUQE7NbplmY_Qtp6@apocalypse>

Hi Rob,

On 14:58 Tue 09 Dec     , Andrea della Porta wrote:
> Hi Rob,
> sorry for the delay...
> 
> On 15:15 Mon 17 Nov     , Rob Herring (Arm) wrote:
> > It's a requirement that DT overlays be applied at build time in order to
> > validate them as overlays are not validated on their own.
> > 
> > Simply adding a build time target is possible, but it's also not desirable
> > to have targets which include the overlay contents and apply the same
> > overlay.
> > 
> > Rework the targets such that there are 2 overlays: the existing RP1 overlay
> > and the board specific configuration of the RP1 (bcm2712-rpi-5-b.dtso).
> > 
> > Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> > ---
> > The missing applying of rp1.dtbo will soon be a warning[1].
> > 
> > The comment in bcm2712-rpi-5-b.dts(o) needs updating or removing. The RP1
> > driver or userspace handling of the overlay probably needs updating to
> > handle the 2 overlays. IIRC, I think we can apply overlays to overlays
> > which may be useful here. If not, adding that to the tools should be
> > possible.
> > 
> > [1] https://lore.kernel.org/all/20251114222759.4181152-1-robh at kernel.org/
> > ---
> >  arch/arm64/boot/dts/broadcom/Makefile                 | 10 ++++++++--
> >  ...m2712-d-rpi-5-b.dts => bcm2712-d-rpi-5-b-base.dts} |  2 +-
> >  .../{bcm2712-rpi-5-b.dts => bcm2712-rpi-5-b.dtso}     | 11 +++++------
> >  3 files changed, 14 insertions(+), 9 deletions(-)
> >  rename arch/arm64/boot/dts/broadcom/{bcm2712-d-rpi-5-b.dts => bcm2712-d-rpi-5-b-base.dts} (95%)
> >  rename arch/arm64/boot/dts/broadcom/{bcm2712-rpi-5-b.dts => bcm2712-rpi-5-b.dtso} (92%)
> > 
> > diff --git a/arch/arm64/boot/dts/broadcom/Makefile b/arch/arm64/boot/dts/broadcom/Makefile
> > index 83d45afc6588..4957edec9d9f 100644
> > --- a/arch/arm64/boot/dts/broadcom/Makefile
> > +++ b/arch/arm64/boot/dts/broadcom/Makefile
> > @@ -6,9 +6,9 @@ DTC_FLAGS := -@
> >  dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-400.dtb \
> >  			      bcm2711-rpi-4-b.dtb \
> >  			      bcm2711-rpi-cm4-io.dtb \
> > -			      bcm2712-rpi-5-b.dtb \
> > +			      bcm2712-rpi-5-b.dtbo \
> >  			      bcm2712-rpi-5-b-ovl-rp1.dtb \
> > -			      bcm2712-d-rpi-5-b.dtb \
> > +			      bcm2712-d-rpi-5-b-base.dtb \
> >  			      bcm2837-rpi-2-b.dtb \
> >  			      bcm2837-rpi-3-a-plus.dtb \
> >  			      bcm2837-rpi-3-b.dtb \
> > @@ -17,6 +17,12 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-400.dtb \
> >  			      bcm2837-rpi-zero-2-w.dtb \
> >  			      rp1.dtbo
> >  
> > +bcm2712-rpi-5-b-dtbs := bcm2712-rpi-5-b-ovl-rp1.dtb rp1.dtbo bcm2712-rpi-5-b.dtbo
> > +dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-5-b.dtb
> > +
> > +bcm2712-d-rpi-5-b-dtbs := bcm2712-d-rpi-5-b-base.dtb rp1.dtbo bcm2712-rpi-5-b.dtbo
> > +dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-d-rpi-5-b.dtb
> > +
> >  subdir-y	+= bcmbca
> >  subdir-y	+= northstar2
> >  subdir-y	+= stingray
> > diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-d-rpi-5-b.dts b/arch/arm64/boot/dts/broadcom/bcm2712-d-rpi-5-b-base.dts
> > similarity index 95%
> > rename from arch/arm64/boot/dts/broadcom/bcm2712-d-rpi-5-b.dts
> > rename to arch/arm64/boot/dts/broadcom/bcm2712-d-rpi-5-b-base.dts
> > index 7de24d60bcd1..48a0ae118839 100644
> > --- a/arch/arm64/boot/dts/broadcom/bcm2712-d-rpi-5-b.dts
> > +++ b/arch/arm64/boot/dts/broadcom/bcm2712-d-rpi-5-b-base.dts
> > @@ -1,7 +1,7 @@
> >  // SPDX-License-Identifier: (GPL-2.0 OR MIT)
> >  /dts-v1/;
> >  
> > -#include "bcm2712-rpi-5-b.dts"
> > +#include "bcm2712-rpi-5-b-ovl-rp1.dts"
> >  
> >  &gio_aon {
> >  	brcm,gpio-bank-widths = <15 6>;
> > diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dtso
> > similarity index 92%
> > rename from arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
> > rename to arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dtso
> > index b8f256545022..89d099c00035 100644
> > --- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
> > +++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dtso
> > @@ -15,19 +15,18 @@
> >   */
> >  
> >  /dts-v1/;
> > +/plugin/;
> >  
> > -#include "bcm2712-rpi-5-b-ovl-rp1.dts"
> > -
> > -&pcie2 {
> > -	#include "rp1-nexus.dtsi"
> > -};
> > +#include <dt-bindings/gpio/gpio.h>
> 
> Sounds reasonable to me, please let me have a full round of tests to check for
> any issue with the driver and I'll come back with feedback.

Just a heads up, since you've posted this new revision [1] and that I'm currently
reworking RP1 overlay (in order to drop it), I assume that this patch is no longer
relevant and I'll avoid testing it.

Thanks,
Andrea

[1] - https://lore.kernel.org/all/aUQA5IKqqsrElzKP at apocalypse/

> 
> >  
> >  &rp1_eth {
> >  	status = "okay";
> >  	phy-mode = "rgmii-id";
> >  	phy-handle = <&phy1>;
> > +        #address-cells = <1>;
> > +        #size-cells = <0>;
> 
> I think this should go in a separate patch.
> 
> >  
> > -	mdio {
> > +	mdio at 1 {
> 
> Ditto.
> 
> Many thanks,
> Andrea
> 
> >  		reg = <0x1>;
> >  		reset-gpios = <&rp1_gpio 32 GPIO_ACTIVE_LOW>;
> >  		reset-delay-us = <5000>;
> > -- 
> > 2.51.0
> > 


From jonathan.cameron at huawei.com  Thu Dec 18 05:42:40 2025
From: jonathan.cameron at huawei.com (Jonathan Cameron)
Date: Thu, 18 Dec 2025 13:42:40 +0000
Subject: [RFC PATCH 21/38] arm_mpam: resctrl: Pre-allocate assignable
 monitors
In-Reply-To: <20251205215901.17772-22-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
	<20251205215901.17772-22-james.morse@arm.com>
Message-ID: <20251218134240.00000a96@huawei.com>

On Fri, 5 Dec 2025 21:58:44 +0000
James Morse <james.morse at arm.com> wrote:

> When there are not enough monitors, MPAM is able to emulate ABMC by making
> a smaller number of monitors assignable. These monitors still need to be
> allocated from the driver, and mapped to whichever control/monitor group
> resctrl wants to use them with.
> 
> Add a second array to hold the monitor values indexed by resctrl's
> cntr_id.
> 
> When CDP is in use, two monitors are needed so the available number of
> counters halves. Platforms with one monitor will have zero monitors
> when CDP is in use.
> 
> Signed-off-by: James Morse <james.morse at arm.com>

> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
> index de5220fed97d..f607feaf0126 100644
> --- a/drivers/resctrl/mpam_resctrl.c
> +++ b/drivers/resctrl/mpam_resctrl.c

> @@ -806,6 +863,41 @@ static int mpam_resctrl_pick_domain_id(int cpu, struct mpam_component *comp)
>  	return comp->comp_id;
>  }
>  
> +/*
> + * This must run after all event counters have been picked so that any free
> + * running counters have already been allocated.
> + */
> +static int mpam_resctrl_monitor_init_abmc(struct mpam_resctrl_mon *mon)
> +{
> +	struct mpam_resctrl_res *res = &mpam_resctrl_controls[RDT_RESOURCE_L3];
> +	size_t array_size = resctrl_arch_system_num_rmid_idx() * sizeof(int);
> +	int *rmid_array __free(kfree) = kmalloc(array_size, GFP_KERNEL);

kcalloc?  Given you call it an array I assume it is one.  Will zero though
and if you really care about optimizing that out add a comment.

Move this...

> +	struct rdt_resource *l3 = &res->resctrl_res;
> +	struct mpam_class *class = mon->class;
> +	u16 num_mbwu_mon;
> +
> +	if (mon->mbwu_idx_to_mon) {
> +		pr_debug("monitors free running\n");
> +		return 0;
> +	}

Down to here.  See cleanup.h notes that summarize how much Linus doesn't want
people not declaring these inline because of how much it hurts readability.

> +
> +	if (!rmid_array) {
> +		pr_debug("Failed to allocate RMID array\n");
> +		return -ENOMEM;
> +	}
> +	memset(rmid_array, -1, array_size);
> +
> +	num_mbwu_mon = class->props.num_mbwu_mon;
> +	mon->assigned_counters = __alloc_mbwu_array(mon->class, num_mbwu_mon);
> +	if (IS_ERR(mon->assigned_counters))
> +		return PTR_ERR(mon->assigned_counters);
> +	mon->mbwu_idx_to_mon = no_free_ptr(rmid_array);
> +
> +	mpam_resctrl_monitor_sync_abmc_vals(l3);
> +
> +	return 0;
> +}
> +
>  static void mpam_resctrl_monitor_init(struct mpam_resctrl_mon *mon,
>  				      enum resctrl_event_id type)
>  {
> @@ -847,6 +939,16 @@ static void mpam_resctrl_monitor_init(struct mpam_resctrl_mon *mon,
>  		 * space.
>  		 */
>  		l3->mon.num_rmid = 1;
> +
> +		switch (type) {
> +		case QOS_L3_MBM_LOCAL_EVENT_ID:
> +		case QOS_L3_MBM_TOTAL_EVENT_ID:
> +			mpam_resctrl_monitor_init_abmc(mon);
> +
> +			return;
> +		default:
> +			return;
> +		}
>  	}
>  }
>  



From ahmed.tiba at arm.com  Thu Dec 18 05:42:47 2025
From: ahmed.tiba at arm.com (Ahmed Tiba)
Date: Thu, 18 Dec 2025 13:42:47 +0000
Subject: [PATCH 11/12] ras: add DeviceTree estatus provider driver
In-Reply-To: <aUPv5UfBByVoLbRV@willie-the-truck>
References: <aUPv5UfBByVoLbRV@willie-the-truck>
Message-ID: <20251218134311.2309421-1-ahmed.tiba@arm.com>

On Thu, 18 Dec 2025 12:13:25PM +0000, Will Deacon wrote:
>> Introduce a platform driver that maps the CPER status block described
>> in DeviceTree, feeds it into the estatus core and handles either IRQ- or
>> poll-driven notifications. Arm64 gains a FIX_ESTATUS_IRQ slot so the
>> driver can safely map the shared buffer while copying records.
>>
>> Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>
>> ---
>>  MAINTAINERS                     |   1 +
>>  arch/arm64/include/asm/fixmap.h |   5 +
>>  drivers/ras/Kconfig             |  14 ++
>>  drivers/ras/Makefile            |   1 +
>>  drivers/ras/estatus-dt.c        | 318 ++++++++++++++++++++++++++++++++
>>  include/linux/estatus.h         |   3 +-
>>  6 files changed, 341 insertions(+), 1 deletion(-)
>>  create mode 100644 drivers/ras/estatus-dt.c
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 6b2ef2ddc0c7..5567d5e82053 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -21761,6 +21761,7 @@ RAS ERROR STATUS
>>  M:   Ahmed Tiba <ahmed.tiba at arm.com>
>>  S:   Maintained
>>  F:   Documentation/devicetree/bindings/ras/arm,ras-ffh.yaml
>> +F:   drivers/ras/estatus-dt.c
>>  F:   drivers/firmware/efi/estatus.c
>>  F:   include/linux/estatus.h
>> 
>> diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h
>> index 65555284446e..85ffba87bab9 100644
>> --- a/arch/arm64/include/asm/fixmap.h
>> +++ b/arch/arm64/include/asm/fixmap.h
>> @@ -64,6 +64,11 @@ enum fixed_addresses {
>>  #endif
>>  #endif /* CONFIG_ACPI_APEI_GHES */
>> 
>> +#ifdef CONFIG_RAS_ESTATUS_DT
>> +     /* Used for ESTATUS mapping from assorted contexts */
>> +     FIX_ESTATUS_IRQ,
>> +#endif /* CONFIG_RAS_ESTATUS_DT */
>
> Why do we need this in addition to the four existing GHES slots? The DT
> code doesn't use it and I was assuming that the ACPI code would continue
> to use the existing irq; is that not the case?


We still need a dedicated slot when only the DT provider is built.
All four GHES slots are defined as part of the ACPI implementation,
so they are not present in a DT-only configuration.

The estatus core always requests a fixmap index from each provider
before copying a CPER record. As a result, the DT driver must supply
its own slot to return a valid enum value to satisfy the common code.

The ACPI/GHES path continues to use the existing four slots exactly as
before. This change simply ensures that the DT provider does not depend
on ACPI being enabled solely to satisfy the estatus core interface.

Best regards,
Ahmed


From jonathan.cameron at huawei.com  Thu Dec 18 05:49:53 2025
From: jonathan.cameron at huawei.com (Jonathan Cameron)
Date: Thu, 18 Dec 2025 13:49:53 +0000
Subject: [RFC PATCH 24/38] arm_mpam: resctrl: Allow resctrl to allocate
 monitors
In-Reply-To: <20251205215901.17772-25-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
	<20251205215901.17772-25-james.morse@arm.com>
Message-ID: <20251218134953.000064b1@huawei.com>

On Fri, 5 Dec 2025 21:58:47 +0000
James Morse <james.morse at arm.com> wrote:

> When resctrl wants to read a domain's 'QOS_L3_OCCUP', it needs
> to allocate a monitor on the corresponding resource. Monitors are
> allocated by class instead of component.
> 
> MBM monitors are much more complicated, if there are enough monitors,
> they will be pre-allocated and free-running. If ABMC is in use instead
> then 'some' are pre-allocated in a different way, and need assigning.
> 
> Add helpers to allocate a CSU monitor. These helper return an out
> of range value for MBM counters.
> 
> Allocating a montitor context is expected to block until hardware
> resources become available. This only makes sense for QOS_L3_OCCUP
> as unallocated MBM counters are losing data.
> 
> Signed-off-by: James Morse <james.morse at arm.com>
> ---
> Since ABMC got merged it may be possible to remove the monitor alloc
> call for MBM counters from resctrl as this work is now done by ABMC's
> assign call.
> ---
>  drivers/resctrl/mpam_internal.h | 14 ++++++-
>  drivers/resctrl/mpam_resctrl.c  | 68 +++++++++++++++++++++++++++++++++
>  include/linux/arm_mpam.h        |  4 ++
>  3 files changed, 85 insertions(+), 1 deletion(-)
> 

> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
> index 22ad5dd3c383..a2b238d47117 100644
> --- a/drivers/resctrl/mpam_resctrl.c
> +++ b/drivers/resctrl/mpam_resctrl.c

> +
> +void resctrl_arch_mon_ctx_free(struct rdt_resource *r,
> +			       enum resctrl_event_id evtid, void *arch_mon_ctx)
> +{
> +	u32 mon_idx = *(u32 *)arch_mon_ctx;
> +
> +	kfree(arch_mon_ctx);
> +	arch_mon_ctx = NULL;

Why is this useful?  Updating the local pointer copy which is not
used again. Maybe I need more coffee.

> +
> +	resctrl_arch_mon_ctx_free_no_wait(evtid, mon_idx);
> +}


From a.fatoum at pengutronix.de  Thu Dec 18 05:53:02 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Thu, 18 Dec 2025 14:53:02 +0100
Subject: [PATCH v4 0/2] Add devicetree for NXP i.MX93 FRDM board
In-Reply-To: <e15437918fc2e162eec92985e8f11f8e0de91246.camel@pengutronix.de>
References: <20251218-fpg-nxp-imx93-frdm-v4-0-cd3a9f6ac89a@pengutronix.de>
 <9a96f664-00ba-4589-b3b8-a04355c0ad0b@pengutronix.de>
 <e15437918fc2e162eec92985e8f11f8e0de91246.camel@pengutronix.de>
Message-ID: <5925c749-1288-4d61-b17f-ac2e1c6c463d@pengutronix.de>

Hi,

On 12/18/25 2:11 PM, Fabian Pflug wrote:
> Hello Ahmad,
> 
> On Thu, 2025-12-18 at 13:52 +0100, Ahmad Fatoum wrote:
>> Hello Fabian,
>>
>> On 12/18/25 12:39 PM, Fabian Pflug wrote:
>>> Signed-off-by: Fabian Pflug <f.pflug at pengutronix.de>
>>> ---
>>> Changes in v4:
>>> - remove it6263 block in i2c1, since it is not finished
>>> - remove usdhc3 pwrsequence, since WLAN is not tested on my board
>>> - remove eee-broken-1000t on phy2, since it is not broken
>>> - update min/max-microvlt on buck converters
>>
>> I know you changed this due to reviewer feedback, but it was wrong
>> advice. The Linux driver already has information about the minimum and
>> maximum range support for the PMIC, what you need to write here is the
>> actual board-level constraints.
> 
> Yeah, I know, that why I only updated the other two rails and changed to minimum for CPU 0.64 to 0.61V for core.
> And 1.06 to 1.14V for DRAM, as it is the settings allowed by the CPU.
> 
> VCC3.3 and VCC1.8 were not changed, due to them being connected to multiple devices and I did not want to make them
> flexible, as it would be a hassle in the drivers.

Ah, good. I read this change log here, checked v3 and then saw you
applied the feedback on the first regulator and assumed you did so for
the others mentioned there as well...

0.61 is the minimum in suspend for VDD_SOC, so that's ok.
For DRAM, that's minimum/maximum operating range so ok too.

Thanks for the clarification,
Ahmad

> 
> Kind regards
> Fabian
> 
>>
>> I don't think the board will like VDD_3V3 at 1.62V or VDD_1V8 at 3.4V.
>> For the fixed voltage rails just set min = max = fixed voltage.
>>
>> Thanks,
>> Ahmad
>>
>>> - Link to v3: https://lore.kernel.org/r/20251022-fpg-nxp-imx93-frdm-v3-0-03ec40a1ccc0 at pengutronix.de
>>>
>>> Changes in v3:
>>> - Add Signed-off for original NXP contributors.
>>> - Fixed whitespace errors (Thanks Francesco Valla)
>>> - Added mu1 with status okay (Thanks Francesco Valla)
>>> - Removed address cells from lpi2c3 (Thanks Frank Li)
>>> - Configure pin for watchdog (Thanks Peng Fan)
>>> - Updated regulator config
>>> - Configure i2c0
>>> - Link to v2: https://lore.kernel.org/r/20250526-fpg-nxp-imx93-frdm-v2-0-e5ad0efaec33 at pengutronix.de
>>>
>>> Changes in v2:
>>> - 1/2: remove CAN node, as it has not been tested.
>>> - 1/2: ran dt-format (Thanks Frank Li)
>>> 	But also reordered some nodes afterwards again to have
>>> 	regulator-min before regulator-max, have the pinmux at the end
>>> 	of the file, and have the regulator-name as the first node
>>> 	inside the regulators.
>>> 	Re-added comments, that were deleted.
>>> - 1/2: changes subjet to ar64:dts (Thanks Fabio Estevan)
>>> - 1/2: removed reg_vdd_12v (Tanks Fabio Estevan)
>>> - 1/2: added aliases for rtc, emmc, serial (Thanks Fabio Estevan)
>>> - reordered the series to have documentation before dts. (Thanks
>>> ? Krzystof Kozlowski)
>>> - Link to v1: https://lore.kernel.org/r/20250523-fpg-nxp-imx93-frdm-v1-0-546b2d342855 at pengutronix.de
>>>
>>> ---
>>> Fabian Pflug (2):
>>> ????? dt-bindings: arm: fsl: add i.MX93 11x11 FRDM board
>>> ????? arm64: dts: freescale: add support for NXP i.MX93 FRDM
>>>
>>> ?Documentation/devicetree/bindings/arm/fsl.yaml???? |?? 1 +
>>> ?arch/arm64/boot/dts/freescale/Makefile???????????? |?? 1 +
>>> ?arch/arm64/boot/dts/freescale/imx93-11x11-frdm.dts | 620 +++++++++++++++++++++
>>> ?3 files changed, 622 insertions(+)
>>> ---
>>> base-commit: ea1013c1539270e372fc99854bc6e4d94eaeff66
>>> change-id: 20250523-fpg-nxp-imx93-frdm-5cc180a1fda9
>>>
>>> Best regards,
> 

-- 
Pengutronix e.K.                  |                             |
Steuerwalder Str. 21              | http://www.pengutronix.de/  |
31137 Hildesheim, Germany         | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686  | Fax:   +49-5121-206917-5555 |



From jonathan.cameron at huawei.com  Thu Dec 18 05:53:17 2025
From: jonathan.cameron at huawei.com (Jonathan Cameron)
Date: Thu, 18 Dec 2025 13:53:17 +0000
Subject: [RFC PATCH 25/38] arm_mpam: resctrl: Add
 resctrl_arch_rmid_read() and resctrl_arch_reset_rmid()
In-Reply-To: <20251205215901.17772-26-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
	<20251205215901.17772-26-james.morse@arm.com>
Message-ID: <20251218135317.000004ba@huawei.com>

On Fri, 5 Dec 2025 21:58:48 +0000
James Morse <james.morse at arm.com> wrote:

> resctrl uses resctrl_arch_rmid_read() to read counters. CDP emulation
> means the counter may need reading in three different ways. The same
> goes for reset.
> 
> The helpers behind the resctrl_arch_ functions will be re-used for the
> ABMC equivalent functions.
> 
> Add the rounding helper for checking monitor values while we're here.
> 
> Signed-off-by: James Morse <james.morse at arm.com>
> ---
>  drivers/resctrl/mpam_resctrl.c | 154 +++++++++++++++++++++++++++++++++
>  include/linux/arm_mpam.h       |   5 ++
>  2 files changed, 159 insertions(+)
> 
> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
> index a2b238d47117..dc8a819d0976 100644
> --- a/drivers/resctrl/mpam_resctrl.c
> +++ b/drivers/resctrl/mpam_resctrl.c
> @@ -355,6 +355,160 @@ void resctrl_arch_mon_ctx_free(struct rdt_resource *r,
>  	resctrl_arch_mon_ctx_free_no_wait(evtid, mon_idx);
>  }
>  
> +static int
> +__read_mon(struct mpam_resctrl_mon *mon, struct mpam_component *mon_comp,
> +	   enum mpam_device_features mon_type,
> +	   int mon_idx,
> +	   enum resctrl_conf_type cdp_type, u32 closid, u32 rmid, u64 *val)
> +{
> +	struct mon_cfg cfg = { };
> +
> +	if (!mpam_is_enabled())
> +		return -EINVAL;
> +
> +	/* Shift closid to account for CDP */
> +	closid = resctrl_get_config_index(closid, cdp_type);
> +
> +	if (mon_idx == USE_PRE_ALLOCATED) {
> +		int mbwu_idx = resctrl_arch_rmid_idx_encode(closid, rmid);
> +		mon_idx = mon->mbwu_idx_to_mon[mbwu_idx];
> +		if (mon_idx == -1) {
> +			if (mpam_resctrl_abmc_enabled()) {
> +				/* Report Unassigned */
> +				return -ENOENT;
> +			}
> +			/* Report Unavailable */
> +			return -EINVAL;
> +		}
> +	}
> +
> +	cfg.mon = mon_idx;
> +	cfg.match_pmg = true;
> +	cfg.partid = closid;
> +	cfg.pmg = rmid;
Maybe use
	cfg = (struct mon_cfg) {
		.mon = ...

and drop the earlier initialization.

	};
> +
> +	if (irqs_disabled()) {
> +		/* Check if we can access this domain without an IPI */
> +		return -EIO;
> +	}
> +
> +	return mpam_msmon_read(mon_comp, &cfg, mon_type, val);
> +}
> +
> +static int read_mon_cdp_safe(struct mpam_resctrl_mon *mon, struct mpam_component *mon_comp,
> +			     enum mpam_device_features mon_type,
> +			     int mon_idx, u32 closid, u32 rmid, u64 *val)
> +{
> +	if (cdp_enabled) {
> +		u64 code_val = 0, data_val = 0;
> +		int err;
> +
> +		err = __read_mon(mon, mon_comp, mon_type, mon_idx,
> +				 CDP_CODE, closid, rmid, &code_val);
> +		if (err)
> +			return err;
> +
> +		err = __read_mon(mon, mon_comp, mon_type, mon_idx,
> +				 CDP_DATA, closid, rmid, &data_val);
> +		if (!err)
> +			*val += code_val + data_val;

I'd stick to out of line error handling and just spend a couple more lines
for readability.
		if (err)
			return err;

		*val += ..
		return 0;

> +		return err;
> +	}
> +
> +	return __read_mon(mon, mon_comp, mon_type, mon_idx,
> +			  CDP_NONE, closid, rmid, val);
> +}




From alexandre.belloni at bootlin.com  Thu Dec 18 05:53:32 2025
From: alexandre.belloni at bootlin.com (Alexandre Belloni)
Date: Thu, 18 Dec 2025 14:53:32 +0100
Subject: [PATCH v2 00/17] tee: Use bus callbacks instead of driver
 callbacks
In-Reply-To: <CAHUa44FrDZbvRvfN8obf80_k=Eqxe9YxHpjaE5jU7nkxPUwfag@mail.gmail.com>
References: <cover.1765791463.git.u.kleine-koenig@baylibre.com>
 <CAHUa44FrDZbvRvfN8obf80_k=Eqxe9YxHpjaE5jU7nkxPUwfag@mail.gmail.com>
Message-ID: <20251218135332f323fa91@mail.local>

On 18/12/2025 08:21:27+0100, Jens Wiklander wrote:
> Hi,
> 
> On Mon, Dec 15, 2025 at 3:17?PM Uwe Kleine-K?nig
> <u.kleine-koenig at baylibre.com> wrote:
> >
> > Hello,
> >
> > the objective of this series is to make tee driver stop using callbacks
> > in struct device_driver. These were superseded by bus methods in 2006
> > (commit 594c8281f905 ("[PATCH] Add bus_type probe, remove, shutdown
> > methods.")) but nobody cared to convert all subsystems accordingly.
> >
> > Here the tee drivers are converted. The first commit is somewhat
> > unrelated, but simplifies the conversion (and the drivers). It
> > introduces driver registration helpers that care about setting the bus
> > and owner. (The latter is missing in all drivers, so by using these
> > helpers the drivers become more correct.)
> >
> > v1 of this series is available at
> > https://lore.kernel.org/all/cover.1765472125.git.u.kleine-koenig at baylibre.com
> >
> > Changes since v1:
> >
> >  - rebase to v6.19-rc1 (no conflicts)
> >  - add tags received so far
> >  - fix whitespace issues pointed out by Sumit Garg
> >  - fix shutdown callback to shutdown and not remove
> >
> > As already noted in v1's cover letter, this series should go in during a
> > single merge window as there are runtime warnings when the series is
> > only applied partially. Sumit Garg suggested to apply the whole series
> > via Jens Wiklander's tree.
> > If this is done the dependencies in this series are honored, in case the
> > plan changes: Patches #4 - #17 depend on the first two.
> >
> > Note this series is only build tested.
> >
> > Uwe Kleine-K?nig (17):
> >   tee: Add some helpers to reduce boilerplate for tee client drivers
> >   tee: Add probe, remove and shutdown bus callbacks to tee_client_driver
> >   tee: Adapt documentation to cover recent additions
> >   hwrng: optee - Make use of module_tee_client_driver()
> >   hwrng: optee - Make use of tee bus methods
> >   rtc: optee: Migrate to use tee specific driver registration function
> >   rtc: optee: Make use of tee bus methods
> >   efi: stmm: Make use of module_tee_client_driver()
> >   efi: stmm: Make use of tee bus methods
> >   firmware: arm_scmi: optee: Make use of module_tee_client_driver()
> >   firmware: arm_scmi: Make use of tee bus methods
> >   firmware: tee_bnxt: Make use of module_tee_client_driver()
> >   firmware: tee_bnxt: Make use of tee bus methods
> >   KEYS: trusted: Migrate to use tee specific driver registration
> >     function
> >   KEYS: trusted: Make use of tee bus methods
> >   tpm/tpm_ftpm_tee: Make use of tee specific driver registration
> >   tpm/tpm_ftpm_tee: Make use of tee bus methods
> >
> >  Documentation/driver-api/tee.rst             | 18 +----
> >  drivers/char/hw_random/optee-rng.c           | 26 ++----
> >  drivers/char/tpm/tpm_ftpm_tee.c              | 31 +++++---
> >  drivers/firmware/arm_scmi/transports/optee.c | 32 +++-----
> >  drivers/firmware/broadcom/tee_bnxt_fw.c      | 30 ++-----
> >  drivers/firmware/efi/stmm/tee_stmm_efi.c     | 25 ++----
> >  drivers/rtc/rtc-optee.c                      | 27 ++-----
> >  drivers/tee/tee_core.c                       | 84 ++++++++++++++++++++
> >  include/linux/tee_drv.h                      | 12 +++
> >  security/keys/trusted-keys/trusted_tee.c     | 17 ++--
> >  10 files changed, 164 insertions(+), 138 deletions(-)
> >
> > base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
> > --
> > 2.47.3
> >
> 
> Thank you for the nice cleanup, Uwe.
> 
> I've applied patch 1-3 to the branch tee_bus_callback_for_6.20 in my
> tree at https://git.kernel.org/pub/scm/linux/kernel/git/jenswi/linux-tee.git/
> 
> The branch is based on v6.19-rc1, and I'll try to keep it stable for
> others to depend on, if needed. Let's see if we can agree on taking
> the remaining patches via that branch.

6 and 7 can go through your branch.

-- 
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From jonathan.cameron at huawei.com  Thu Dec 18 05:55:08 2025
From: jonathan.cameron at huawei.com (Jonathan Cameron)
Date: Thu, 18 Dec 2025 13:55:08 +0000
Subject: [RFC PATCH 28/38] arm64: mpam: Select ARCH_HAS_CPU_RESCTRL
In-Reply-To: <20251205215901.17772-29-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
	<20251205215901.17772-29-james.morse@arm.com>
Message-ID: <20251218135508.00005d49@huawei.com>

On Fri, 5 Dec 2025 21:58:51 +0000
James Morse <james.morse at arm.com> wrote:

> Enough MPAM support is present to enable ARCH_HAS_CPU_RESCTRL.
> Let it rip^Wlink!
> 
> ARCH_HAS_CPU_RESCTRL indicates resctrl can be enabled. It is enabled
> by the arch code sipmly because it has 'arch' in its name.

simply

> 
> This removes ARM_CPU_RESCTRL as a mimic of X86_CPU_RESCTRL.
> While here, move the ACPI dependency to the driver's Kconfig file.
> 
> Signed-off-by: James Morse <james.morse at arm.com>



From jonathan.cameron at huawei.com  Thu Dec 18 06:04:01 2025
From: jonathan.cameron at huawei.com (Jonathan Cameron)
Date: Thu, 18 Dec 2025 14:04:01 +0000
Subject: [RFC PATCH 34/38] arm_mpam: Add quirk framework
In-Reply-To: <20251205215901.17772-35-james.morse@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
	<20251205215901.17772-35-james.morse@arm.com>
Message-ID: <20251218140401.000062ce@huawei.com>

On Fri, 5 Dec 2025 21:58:57 +0000
James Morse <james.morse at arm.com> wrote:

> From: Shanker Donthineni <sdonthineni at nvidia.com>
> 
> The MPAM specification includes the MPAMF_IIDR, which serves to
> uniquely identify the MSC implementation through a combination of
> implementer details, product ID, variant, and revision. Certain
> hardware issues/errata can be resolved using software workarounds.
> 
> Introduce a quirk framework to allow workarounds to be enabled based
> on the MPAMF_IIDR value.
> 
> Signed-off-by: Shanker Donthineni <sdonthineni at nvidia.com>
> [ morse: Stash the IIDR so this doesn't need an IPI, enable quirks only
>   once, move the description to the callback so it can be pr_once()d, add
>   an enum of workarounds for popular errata. Add macros for making lists
>   of product/revision/vendor half readable ]
> Signed-off-by: James Morse <james.morse at arm.com>
> ---
>  drivers/resctrl/mpam_devices.c  | 27 +++++++++++++++++++++++++++
>  drivers/resctrl/mpam_internal.h | 26 ++++++++++++++++++++++++++
>  2 files changed, 53 insertions(+)
> 
> diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
> index 741e14e1e6cf..f0f6f9b55ad4 100644
> --- a/drivers/resctrl/mpam_devices.c
> +++ b/drivers/resctrl/mpam_devices.c
> @@ -630,6 +630,25 @@ static struct mpam_msc_ris *mpam_get_or_create_ris(struct mpam_msc *msc,
>  	return ERR_PTR(-ENOENT);
>  }
>  
> +static const struct mpam_quirk mpam_quirks[] = {
> +	{ NULL }, /* Sentinel */

Drop the trailing , given I assume whole point is nothing after this?

> +};
> +
> +static void mpam_enable_quirks(struct mpam_msc *msc)
> +{
> +	const struct mpam_quirk *quirk;
> +
> +	for (quirk = &mpam_quirks[0]; quirk->iidr_mask; quirk++) {
> +		if (quirk->iidr != (msc->iidr & quirk->iidr_mask))
> +			continue;
> +
> +		if (quirk->init)
> +			quirk->init(msc, quirk);

I'm curious why you don't return a bool from this and call
mpam_set_quirk() if that's not indicating it should not be set.
Seems a bit odd to push the tracking that is relevant to the generic
framework (mpam_set_quirk) down into the particular quirk inits.

> +		else
> +			mpam_set_quirk(quirk->workaround, msc);
> +	}
> +}

> diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
> index d381906545ed..de3e5faa12b2 100644
> --- a/drivers/resctrl/mpam_internal.h
> +++ b/drivers/resctrl/mpam_internal.h
> @@ -88,6 +88,8 @@ struct mpam_msc {
>  	u8			pmg_max;
>  	unsigned long		ris_idxs;
>  	u32			ris_max;
> +	u32			iidr;
> +	u16			quirks;
>  
>  	/*
>  	 * error_irq_lock is taken when registering/unregistering the error
> @@ -215,6 +217,29 @@ struct mpam_props {
>  #define mpam_set_feature(_feat, x)	set_bit(_feat, (x)->features)
>  #define mpam_clear_feature(_feat, x)	clear_bit(_feat, (x)->features)
>  
> +/* Workaround bits for msc->quirks */
> +enum mpam_device_quirks {
> +	MPAM_QUIRK_LAST,

Dropping this comma should make it harder for anyone to stick an entry
after this.


From alchark at gmail.com  Thu Dec 18 06:05:39 2025
From: alchark at gmail.com (Alexey Charkov)
Date: Thu, 18 Dec 2025 18:05:39 +0400
Subject: [PATCH v2] arm64: dts: rockchip: enable UFS controller on
 FriendlyElec NanoPi M5
In-Reply-To: <20251201-nanopi-m5-ufs-v2-1-ece9c0ee17c4@gmail.com>
References: <20251201-nanopi-m5-ufs-v2-1-ece9c0ee17c4@gmail.com>
Message-ID: <CABjd4Ywc-L0jvXwk253MDZwgN3srY6WQ5EhoKZ6wb+Hae376_A@mail.gmail.com>

Hi Heiko,

On Mon, Dec 1, 2025 at 3:35?PM Alexey Charkov <alchark at gmail.com> wrote:
>
> The NanoPi M5 board supports pluggable UFS modules using the UFSHC
> inside its Rockchip RK3576 SoC.
>
> Enable the respective devicetree node and add its supply regulators.
>
> Link: https://wiki.friendlyelec.com/wiki/images/9/97/NanoPi_M5_LP5_2411_SCH.pdf
> Signed-off-by: Alexey Charkov <alchark at gmail.com>
> ---
> Changes in v2:
> - Describe UFS supply regulators
> - Add link to schematic
> - Link to v1: https://lore.kernel.org/r/20251127-nanopi-m5-ufs-v1-1-0d28d157712c at gmail.com
> ---
>  arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts | 27 +++++++++++++++++++++++
>  1 file changed, 27 insertions(+)

Would you mind pulling this one, or do you have any reservations?
There hasn't been any discussion, but it looks like a pretty simple
change, runtime tested and schema-tested.

Best regards,
Alexey


From michal.simek at amd.com  Thu Dec 18 06:15:26 2025
From: michal.simek at amd.com (Michal Simek)
Date: Thu, 18 Dec 2025 15:15:26 +0100
Subject: [PATCH] arm64: dts: xilinx: Drop "label" property on
 dlg,slg7xl45106
In-Reply-To: <CAL_JsqKdrN5UpUWQVQXpJjbTy1gN9_FhhwOoX6zVpG+zZVAptA@mail.gmail.com>
References: <20251216175914.2791200-1-robh@kernel.org>
 <aa064ecf-1714-4d40-8658-19952392cae8@amd.com>
 <CAL_JsqKdrN5UpUWQVQXpJjbTy1gN9_FhhwOoX6zVpG+zZVAptA@mail.gmail.com>
Message-ID: <29b45cc2-e0df-4411-bfb9-cfe51ec4ec67@amd.com>



On 12/17/25 21:41, Rob Herring wrote:
> On Wed, Dec 17, 2025 at 6:39?AM Michal Simek <michal.simek at amd.com> wrote:
>> On 12/16/25 18:59, Rob Herring (Arm) wrote:
>>> The "label" property is not documented for the dlg,slg7xl45106. Nor is
>>> it common to use for GPIO controllers. So drop it.
>>>
>>
>> Correct it is not documented but it is at least used in Linux also by
>> drivers/gpio/gpio-mmio.c:810:   err = device_property_read_string(dev, "label",
>> &label);
>>
>> which is also not documented in DT binding.
> 
> It really should be for all GPIO providers or none of them. IMO, it
> should be none of them as we already have "gpio-line-names" which is
> essentially per line labels. I can't see why anyone should care about
> a label for the controller.
> 
>> I don't have a problem with it because I can't see it used anywhere.
>>
>> But there are other devices where label is the part of binding. And IMHO this
>> should be more generic property.
> 
> "label" is the generic property. Not sure what you are suggesting here.

That schema should allow to define label in every node or some class of devices.

Thanks,
Michal


From sudeep.holla at arm.com  Thu Dec 18 06:20:01 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Thu, 18 Dec 2025 14:20:01 +0000
Subject: [PATCH] firmware: arm_ffa: Correct 32-bit response handling in NOTIFICATION_INFO_GET
Message-ID: <20251218142001.2457111-1-sudeep.holla@arm.com>

The FF-A specification allows NOTIFICATION_INFO_GET to return either a
64-bit (FFA_FN64_SUCCESS) or a 32-bit (FFA_SUCCESS) response, depending on
whether the firmware chooses the SMC64 or SMC32 calling convention.

The driver previously detected the response format by checking ret.a0, but
still interpreted the returned ID lists (x3..x17 or w3..w7) as if they always
followed the 64-bit SMC64 layout. In the SMC32 case, the upper 32 bits of
each argument register are undefined by the calling convention, meaning the
driver could read stale or garbage values when parsing notification IDs.

This resulted in incorrectly decoded partition/VCPU IDs whenever the FF-A
firmware used an SMC32 return path.

Fix the issue by:

- Introducing logic to map list indices to the correct u16 offsets,
  depending on whether the response width matches the kernel word size
  or is a 32-bit response on a 64-bit kernel.
- Ensuring that the packed ID list is parsed using the proper layout,
  avoiding reads from undefined upper halves in the SMC32 case.

With this change, NOTIFICATION_INFO_GET now correctly interprets ID list
entries regardless of the response width, aligning the driver with the FF-A
specification.

Fixes: 3522be48d82b ("firmware: arm_ffa: Implement the NOTIFICATION_INFO_GET interface")
Reported-by: Sourav Mohapatra <sourav.mohapatra at arm.com>
Signed-off-by: Sudeep Holla <sudeep.holla at arm.com>
---
 drivers/firmware/arm_ffa/driver.c | 33 +++++++++++++++++++++++++++----
 1 file changed, 29 insertions(+), 4 deletions(-)

diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
index c3f7062d6159..911a1d49498d 100644
--- a/drivers/firmware/arm_ffa/driver.c
+++ b/drivers/firmware/arm_ffa/driver.c
@@ -981,10 +981,27 @@ static void __do_sched_recv_cb(u16 part_id, u16 vcpu, bool is_per_vcpu)
 	}
 }
 
+/*
+ * Map logical ID index to the u16 index within the packed ID list.
+ *
+ * For native responses (FF-A width == kernel word size), IDs are
+ * tightly packed: idx -> idx.
+ *
+ * For 32-bit responses on a 64-bit kernel, each 64-bit register
+ * contributes 4 x u16 values but only the lower 2 are defined; the
+ * upper 2 are garbage. This mapping skips those upper halves:
+ *   0,1,2,3,4,5,... -> 0,1,4,5,8,9,...
+ */
+static int list_idx_to_u16_idx(int idx, bool is_native_resp)
+{
+	return is_native_resp ? idx : idx + 2 * (idx >> 1);
+}
+
 static void ffa_notification_info_get(void)
 {
-	int idx, list, max_ids, lists_cnt, ids_processed, ids_count[MAX_IDS_64];
-	bool is_64b_resp;
+	int ids_processed, ids_count[MAX_IDS_64];
+	int idx, list, max_ids, lists_cnt;
+	bool is_64b_resp, is_native_resp;
 	ffa_value_t ret;
 	u64 id_list;
 
@@ -1001,6 +1018,7 @@ static void ffa_notification_info_get(void)
 		}
 
 		is_64b_resp = (ret.a0 == FFA_FN64_SUCCESS);
+		is_native_resp = (ret.a0 == FFA_FN_NATIVE(SUCCESS));
 
 		ids_processed = 0;
 		lists_cnt = FIELD_GET(NOTIFICATION_INFO_GET_ID_COUNT, ret.a2);
@@ -1017,12 +1035,16 @@ static void ffa_notification_info_get(void)
 
 		/* Process IDs */
 		for (list = 0; list < lists_cnt; list++) {
+			int u16_idx;
 			u16 vcpu_id, part_id, *packed_id_list = (u16 *)&ret.a3;
 
 			if (ids_processed >= max_ids - 1)
 				break;
 
-			part_id = packed_id_list[ids_processed++];
+			u16_idx = list_idx_to_u16_idx(ids_processed,
+						      is_native_resp);
+			part_id = packed_id_list[u16_idx];
+			ids_processed++;
 
 			if (ids_count[list] == 1) { /* Global Notification */
 				__do_sched_recv_cb(part_id, 0, false);
@@ -1034,7 +1056,10 @@ static void ffa_notification_info_get(void)
 				if (ids_processed >= max_ids - 1)
 					break;
 
-				vcpu_id = packed_id_list[ids_processed++];
+				u16_idx = list_idx_to_u16_idx(ids_processed,
+							      is_native_resp);
+				vcpu_id = packed_id_list[u16_idx];
+				ids_processed++;
 
 				__do_sched_recv_cb(part_id, vcpu_id, true);
 			}
-- 
2.34.1



From ryan.roberts at arm.com  Thu Dec 18 06:22:05 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Thu, 18 Dec 2025 14:22:05 +0000
Subject: [PATCH v2 1/2] arm64: mmu: don't allocate page while spliting
 linear mapping
In-Reply-To: <20251217182007.2345700-2-yeoreum.yun@arm.com>
References: <20251217182007.2345700-1-yeoreum.yun@arm.com>
 <20251217182007.2345700-2-yeoreum.yun@arm.com>
Message-ID: <73ced1db-a2e2-49ea-927e-9fc4a30e771e@arm.com>

On 17/12/2025 18:20, Yeoreum Yun wrote:
> Current linear_map_split_to_ptes() allocate the pagetable
> while split linear mapping to ptes by stop_machine() with GFP_ATOMIC.
> 
> This is fine for non-PREEMPR_RT case.
> However It's a problem in PREEMPR_RT case since
> generic memory allocation/free APIs (e.x) pgtable_alloc(), __get_free_pages and etc
> couldn't be called in non-preemptible context except _nolock() APIs
> since generic memory allocation/free APIs are *sleepable* for using *spin_lock()*
> 
> IOW, calling a pgtable_alloc() even with GFP_ATOMIC
> doesn't allow in __linear_map_split_to_pte() executed by stopper thread
> where preemption is disabled in PREEMPR_RT.
> 
> To address this, divide linear_map_maybe_split_ptes:
>   - collect number of pages to require for spliting.
>   - allocate the required number of pages for spliting.
>   - with pre-allocate page, split the linear map.

Thanks for working on this fix!

First some high level comments: I'm not a huge fan of the approach with the
different modes to modify behaviour.

For the first step of figuring out the number of pages required; there is no
need to be inside stop_machine() for that. Can should be able to just walk the
linear map without any locking since it is created once and remains static, with
the exception of hotplug, but that is not enabled yet.

I think it would be cleaner to just create separate walker callbacks rather than
repurpose the existing walker.

Then you could simply change the gfp flag to a callback function pointer and
pass the desired allocator as a function pointer. This would match the existing
patterns used in mmu.c today.

The preallocated page list could be stored in a global static variable and you
could create an allocation function that just strims a page from that list. See
kpti_ng_pgd_alloc() for an existing example. That assumes a contiguous block,
but you could generalize it to hold a list of struct pages and reuse it for both
cases?


> 
> Fixes: 3df6979d222b ("arm64: mm: split linear mapping if BBML2 unsupported on secondary CPUs")
> Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
> ---
>  arch/arm64/mm/mmu.c | 213 +++++++++++++++++++++++++++++++++++---------
>  1 file changed, 170 insertions(+), 43 deletions(-)
> 
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index 9ae7ce00a7ef..e4e6c7e0a016 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -527,18 +527,28 @@ static void early_create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys,
>  		panic("Failed to create page tables\n");
>  }
>  
> -static phys_addr_t __pgd_pgtable_alloc(struct mm_struct *mm, gfp_t gfp,
> -				       enum pgtable_type pgtable_type)
> -{
> -	/* Page is zeroed by init_clear_pgtable() so don't duplicate effort. */
> -	struct ptdesc *ptdesc = pagetable_alloc(gfp & ~__GFP_ZERO, 0);
> -	phys_addr_t pa;
> -
> -	if (!ptdesc)
> -		return INVALID_PHYS_ADDR;
> +enum split_modes {
> +	SPLIT_ALLOC,
> +	SPLIT_PREALLOC,
> +	SPLIT_COLLECT,
> +};
>  
> -	pa = page_to_phys(ptdesc_page(ptdesc));
> +struct split_args {
> +	enum split_modes mode;
> +	union {
> +		struct {
> +			unsigned long nr;
> +			unsigned long i;
> +			struct page **pages;
> +		};
> +		gfp_t gfp;
> +	};
> +};
>  
> +static __always_inline void __pgd_pgtable_init(struct mm_struct *mm,
> +					       struct ptdesc *ptdesc,
> +					       enum pgtable_type pgtable_type)
> +{
>  	switch (pgtable_type) {
>  	case TABLE_PTE:
>  		BUG_ON(!pagetable_pte_ctor(mm, ptdesc));
> @@ -554,19 +564,56 @@ static phys_addr_t __pgd_pgtable_alloc(struct mm_struct *mm, gfp_t gfp,
>  		break;
>  	}
>  
> +}
> +
> +static phys_addr_t __pgd_pgtable_alloc(struct mm_struct *mm, gfp_t gfp,
> +				       enum pgtable_type pgtable_type)
> +{
> +	/* Page is zeroed by init_clear_pgtable() so don't duplicate effort. */
> +	struct ptdesc *ptdesc = pagetable_alloc(gfp & ~__GFP_ZERO, 0);
> +	phys_addr_t pa;
> +
> +	if (!ptdesc)
> +		return INVALID_PHYS_ADDR;
> +
> +	pa = page_to_phys(ptdesc_page(ptdesc));
> +
> +	__pgd_pgtable_init(mm, ptdesc, pgtable_type);
> +
>  	return pa;
>  }
>  
> +static phys_addr_t __pgd_pgtable_prealloc(struct mm_struct *mm,
> +					  struct split_args *split_args,
> +					  enum pgtable_type pgtable_type)
> +{
> +	struct page *page;
> +
> +	BUG_ON(split_args->i >= split_args->nr);
> +
> +	page = split_args->pages[split_args->i++];
> +	if (!page)
> +		return INVALID_PHYS_ADDR;
> +
> +	__pgd_pgtable_init(mm, page_ptdesc(page), pgtable_type);
> +
> +	return page_to_phys(page);
> +}
> +
>  static phys_addr_t
> -pgd_pgtable_alloc_init_mm_gfp(enum pgtable_type pgtable_type, gfp_t gfp)
> +pgd_pgtable_alloc_split(enum pgtable_type pgtable_type,
> +		        struct split_args *split_args)
>  {
> -	return __pgd_pgtable_alloc(&init_mm, gfp, pgtable_type);
> +	if (split_args->mode == SPLIT_ALLOC)
> +		return __pgd_pgtable_alloc(&init_mm, split_args->gfp, pgtable_type);
> +
> +	return __pgd_pgtable_prealloc(&init_mm, split_args, pgtable_type);
>  }
>  
>  static phys_addr_t __maybe_unused
>  pgd_pgtable_alloc_init_mm(enum pgtable_type pgtable_type)
>  {
> -	return pgd_pgtable_alloc_init_mm_gfp(pgtable_type, GFP_PGTABLE_KERNEL);
> +	return __pgd_pgtable_alloc(&init_mm, GFP_PGTABLE_KERNEL, pgtable_type);
>  }
>  
>  static phys_addr_t
> @@ -584,7 +631,9 @@ static void split_contpte(pte_t *ptep)
>  		__set_pte(ptep, pte_mknoncont(__ptep_get(ptep)));
>  }
>  
> -static int split_pmd(pmd_t *pmdp, pmd_t pmd, gfp_t gfp, bool to_cont)
> +static int split_pmd(pmd_t *pmdp, pmd_t pmd,
> +		     struct split_args *split_args,
> +		     bool to_cont)
>  {
>  	pmdval_t tableprot = PMD_TYPE_TABLE | PMD_TABLE_UXN | PMD_TABLE_AF;
>  	unsigned long pfn = pmd_pfn(pmd);
> @@ -593,7 +642,7 @@ static int split_pmd(pmd_t *pmdp, pmd_t pmd, gfp_t gfp, bool to_cont)
>  	pte_t *ptep;
>  	int i;
>  
> -	pte_phys = pgd_pgtable_alloc_init_mm_gfp(TABLE_PTE, gfp);
> +	pte_phys = pgd_pgtable_alloc_split(TABLE_PTE, split_args);
>  	if (pte_phys == INVALID_PHYS_ADDR)
>  		return -ENOMEM;
>  	ptep = (pte_t *)phys_to_virt(pte_phys);
> @@ -628,7 +677,9 @@ static void split_contpmd(pmd_t *pmdp)
>  		set_pmd(pmdp, pmd_mknoncont(pmdp_get(pmdp)));
>  }
>  
> -static int split_pud(pud_t *pudp, pud_t pud, gfp_t gfp, bool to_cont)
> +static int split_pud(pud_t *pudp, pud_t pud,
> +		    struct split_args *split_args,
> +		    bool to_cont)
>  {
>  	pudval_t tableprot = PUD_TYPE_TABLE | PUD_TABLE_UXN | PUD_TABLE_AF;
>  	unsigned int step = PMD_SIZE >> PAGE_SHIFT;
> @@ -638,7 +689,7 @@ static int split_pud(pud_t *pudp, pud_t pud, gfp_t gfp, bool to_cont)
>  	pmd_t *pmdp;
>  	int i;
>  
> -	pmd_phys = pgd_pgtable_alloc_init_mm_gfp(TABLE_PMD, gfp);
> +	pmd_phys = pgd_pgtable_alloc_split(TABLE_PMD, split_args);
>  	if (pmd_phys == INVALID_PHYS_ADDR)
>  		return -ENOMEM;
>  	pmdp = (pmd_t *)phys_to_virt(pmd_phys);
> @@ -672,6 +723,10 @@ static int split_kernel_leaf_mapping_locked(unsigned long addr)
>  	pmd_t *pmdp, pmd;
>  	pte_t *ptep, pte;
>  	int ret = 0;
> +	struct split_args split_args = {
> +		.mode = SPLIT_ALLOC,
> +		.gfp = GFP_PGTABLE_KERNEL,
> +	};
>  
>  	/*
>  	 * PGD: If addr is PGD aligned then addr already describes a leaf
> @@ -707,7 +762,7 @@ static int split_kernel_leaf_mapping_locked(unsigned long addr)
>  	if (!pud_present(pud))
>  		goto out;
>  	if (pud_leaf(pud)) {
> -		ret = split_pud(pudp, pud, GFP_PGTABLE_KERNEL, true);
> +		ret = split_pud(pudp, pud, &split_args, true);
>  		if (ret)
>  			goto out;
>  	}
> @@ -732,7 +787,7 @@ static int split_kernel_leaf_mapping_locked(unsigned long addr)
>  		 */
>  		if (ALIGN_DOWN(addr, PMD_SIZE) == addr)
>  			goto out;
> -		ret = split_pmd(pmdp, pmd, GFP_PGTABLE_KERNEL, true);
> +		ret = split_pmd(pmdp, pmd, &split_args, true);
>  		if (ret)
>  			goto out;
>  	}
> @@ -831,12 +886,17 @@ int split_kernel_leaf_mapping(unsigned long start, unsigned long end)
>  static int split_to_ptes_pud_entry(pud_t *pudp, unsigned long addr,
>  				   unsigned long next, struct mm_walk *walk)
>  {
> -	gfp_t gfp = *(gfp_t *)walk->private;
> +	struct split_args *split_args = (struct split_args *)walk->private;

no need for the casting here; it's a void *.

>  	pud_t pud = pudp_get(pudp);
>  	int ret = 0;
>  
> -	if (pud_leaf(pud))
> -		ret = split_pud(pudp, pud, gfp, false);
> +	if (!pud_leaf(pud))
> +		return 0;
> +
> +	if (split_args->mode == SPLIT_COLLECT)
> +		split_args->nr++;

bug: you're incrementing this for the pmd table that you would have inserted,
but because you're not actually splitting, split_to_ptes_pmd_entry() will never
be called for the 512 pte tables you also need. So you need:

		nr += 1 + PTRS_PER_PMD;

I'm guessing you didn't test this as the BUG would have triggered when you ran
out of preallocated memory?

> +	else
> +		ret = split_pud(pudp, pud, split_args, false);
>  
>  	return ret;
>  }
> @@ -844,22 +904,29 @@ static int split_to_ptes_pud_entry(pud_t *pudp, unsigned long addr,
>  static int split_to_ptes_pmd_entry(pmd_t *pmdp, unsigned long addr,
>  				   unsigned long next, struct mm_walk *walk)
>  {
> -	gfp_t gfp = *(gfp_t *)walk->private;
> +	struct split_args *split_args = (struct split_args *)walk->private;
>  	pmd_t pmd = pmdp_get(pmdp);
> -	int ret = 0;
> +	int ret;
>  
> -	if (pmd_leaf(pmd)) {
> -		if (pmd_cont(pmd))
> -			split_contpmd(pmdp);
> -		ret = split_pmd(pmdp, pmd, gfp, false);
> +	if (!pmd_leaf(pmd))
> +		return 0;
>  
> -		/*
> -		 * We have split the pmd directly to ptes so there is no need to
> -		 * visit each pte to check if they are contpte.
> -		 */
> -		walk->action = ACTION_CONTINUE;
> +	if (split_args->mode == SPLIT_COLLECT) {
> +		split_args->nr++;
> +		return 0;
>  	}
>  
> +	if (pmd_cont(pmd))
> +		split_contpmd(pmdp);
> +	ret = split_pmd(pmdp, pmd, split_args, false);
> +
> +	/*
> +	 * We have split the pmd directly to ptes so there is no need to
> +	 * visit each pte to check if they are contpte.
> +	 */
> +	walk->action = ACTION_CONTINUE;
> +
> +
>  	return ret;
>  }
>  
> @@ -880,13 +947,15 @@ static const struct mm_walk_ops split_to_ptes_ops = {
>  	.pte_entry	= split_to_ptes_pte_entry,
>  };
>  
> -static int range_split_to_ptes(unsigned long start, unsigned long end, gfp_t gfp)
> +static int range_split_to_ptes(unsigned long start, unsigned long end,
> +		 	       struct split_args *split_args)
>  {
>  	int ret;
>  
>  	arch_enter_lazy_mmu_mode();
>  	ret = walk_kernel_page_table_range_lockless(start, end,
> -					&split_to_ptes_ops, NULL, &gfp);
> +						    &split_to_ptes_ops, NULL,
> +						    split_args);
>  	arch_leave_lazy_mmu_mode();
>  
>  	return ret;
> @@ -903,7 +972,7 @@ static void __init init_idmap_kpti_bbml2_flag(void)
>  	smp_mb();
>  }
>  
> -static int __init linear_map_split_to_ptes(void *__unused)
> +static int __init linear_map_split_to_ptes(void *data)
>  {
>  	/*
>  	 * Repainting the linear map must be done by CPU0 (the boot CPU) because
> @@ -911,6 +980,7 @@ static int __init linear_map_split_to_ptes(void *__unused)
>  	 * be held in a waiting area with the idmap active.
>  	 */
>  	if (!smp_processor_id()) {
> +		struct split_args *split_args = data;
>  		unsigned long lstart = _PAGE_OFFSET(vabits_actual);
>  		unsigned long lend = PAGE_END;
>  		unsigned long kstart = (unsigned long)lm_alias(_stext);
> @@ -928,12 +998,13 @@ static int __init linear_map_split_to_ptes(void *__unused)
>  		 * PTE. The kernel alias remains static throughout runtime so
>  		 * can continue to be safely mapped with large mappings.
>  		 */
> -		ret = range_split_to_ptes(lstart, kstart, GFP_ATOMIC);
> +		ret = range_split_to_ptes(lstart, lend, split_args);
>  		if (!ret)
> -			ret = range_split_to_ptes(kend, lend, GFP_ATOMIC);
> +			ret = range_split_to_ptes(kstart, kend, split_args);
>  		if (ret)
>  			panic("Failed to split linear map\n");
> -		flush_tlb_kernel_range(lstart, lend);
> +		if (split_args->mode != SPLIT_COLLECT)
> +			flush_tlb_kernel_range(lstart, lend);
>  
>  		/*
>  		 * Relies on dsb in flush_tlb_kernel_range() to avoid reordering
> @@ -963,10 +1034,61 @@ static int __init linear_map_split_to_ptes(void *__unused)
>  
>  void __init linear_map_maybe_split_to_ptes(void)
>  {
> -	if (linear_map_requires_bbml2 && !system_supports_bbml2_noabort()) {
> -		init_idmap_kpti_bbml2_flag();
> -		stop_machine(linear_map_split_to_ptes, NULL, cpu_online_mask);
> +	struct page **pages = NULL;
> +	struct split_args split_args;
> +	int order;
> +	int nr_populated;
> +	int err;
> +
> +	if (!linear_map_requires_bbml2 || system_supports_bbml2_noabort())
> +		return;
> +
> +	/*
> +	 * Phase 1: Collect required extra pages to split.
> +	 */
> +	split_args.mode = SPLIT_COLLECT;
> +	split_args.nr = 0;
> +
> +	init_idmap_kpti_bbml2_flag();
> +	stop_machine(linear_map_split_to_ptes, &split_args, cpu_online_mask);

This doesn't require stop_machine().

> +
> +	/*
> +	 * Phase 2: Allocate necessary pages to split.
> +	 */
> +	if (split_args.nr == 0) {
> +		err = 0;
> +		split_args.mode = SPLIT_ALLOC;

How would we hit this condition? If everything is already split why not just
exit early?

> +	} else {
> +		err = -ENOMEM;
> +		order = order_base_2(PAGE_ALIGN(split_args.nr *
> +					sizeof(struct page *)) >> PAGE_SHIFT);
> +
> +		pages = (struct page **)__get_free_pages(GFP_ATOMIC | __GFP_ZERO, order);

As per the other patch, I'd prefer to see GFP_KERNEL | __GFP_ZERO here.

Let's make this a list of struct ptdesc * though.


> +		if (!pages)
> +			goto error;
> +
> +		nr_populated = alloc_pages_bulk(GFP_ATOMIC | __GFP_ZERO, split_args.nr, pages);

Just GFP_KERNEL. No need for __GFP_ZERO as they will all be fully overwritten
with PTEs.

I'd prefer to use pagetable_alloc(GFP_KERNEL, 0) in a loop since that will
return a proper ptdesc.

> +		if (nr_populated < split_args.nr)
> +			goto error;
> +
> +		err = 0;
> +		split_args.mode = SPLIT_PREALLOC;
> +		split_args.i = 0;
> +		split_args.pages = pages;
>  	}
> +
> +	/*
> +	 * Phase 3: Split linear map.
> +	 */
> +	init_idmap_kpti_bbml2_flag();
> +	stop_machine(linear_map_split_to_ptes, &split_args, cpu_online_mask);
> +
> +error:
> +	if (pages)
> +		free_pages((unsigned long)pages, order);

It's possible (but unlikely) that another CPU caused a split between figuring
out the required number of tables and actually doing the full split. In this
case, you would have preallocated pages left over that you will need to free here.

Thanks,
Ryan

> +
> +	if (err)
> +		panic("Failed to split linear map: %d\n", err);
>  }
>  
>  /*
> @@ -1087,6 +1209,11 @@ bool arch_kfence_init_pool(void)
>  	unsigned long start = (unsigned long)__kfence_pool;
>  	unsigned long end = start + KFENCE_POOL_SIZE;
>  	int ret;
> +	struct split_args split_args = {
> +		.mode = SPLIT_ALLOC,
> +		.gfp = GFP_PGTABLE_KERNEL,
> +	};
> +
>  
>  	/* Exit early if we know the linear map is already pte-mapped. */
>  	if (!split_leaf_mapping_possible())
> @@ -1097,7 +1224,7 @@ bool arch_kfence_init_pool(void)
>  		return true;
>  
>  	mutex_lock(&pgtable_split_lock);
> -	ret = range_split_to_ptes(start, end, GFP_PGTABLE_KERNEL);
> +	ret = range_split_to_ptes(start, end, &split_args);
>  	mutex_unlock(&pgtable_split_lock);
>  
>  	/*



From luca.ceresoli at bootlin.com  Thu Dec 18 06:23:35 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Thu, 18 Dec 2025 15:23:35 +0100
Subject: [PATCH v3 01/22] drm/bridge: add of_drm_find_and_get_bridge()
In-Reply-To: <20251218-shiny-rugged-bug-d1d3e8@houat>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-1-b5165fab8058@bootlin.com> <0ba037c65f9cadd51082abf2b7857ba7@kernel.org> <DF0KBN5Y22XW.2RE8HKDFY87XK@bootlin.com> <20251218-shiny-rugged-bug-d1d3e8@houat>
Message-ID: <DF1ESI44XZ00.I0EK3DH2Y7LR@bootlin.com>

Hi Maxime,

On Thu Dec 18, 2025 at 1:50 PM CET, Maxime Ripard wrote:
> Hi,
>
> On Wed, Dec 17, 2025 at 03:31:01PM +0100, Luca Ceresoli wrote:
>> On Wed Dec 17, 2025 at 11:15 AM CET, Maxime Ripard wrote:
>> > On Tue, 16 Dec 2025 18:58:34 +0100, Luca Ceresoli wrote:
>> >> of_drm_find_bridge() does not increment the refcount for the returned
>> >> bridge, but that is required now. However converting it and all its users
>> >> is not realistically doable at once given the large amount of (direct and
>> >> indirect) callers and the complexity of some.
>> >>
>> >>
>> >> [ ... ]
>> >
>> > Reviewed-by: Maxime Ripard <mripard at kernel.org>
>>
>> Thank you for the prompt review!
>>
>> All patches are reviewed now except patch 18 which has no reply. I'm just
>> pointing out in case it's something you missed.
>
> Yes, I couldn't really understand the implications of that one, so I'll
> leave the review to the maintainers.

OK, make sense, it's not a trivial patch to review.

Patches 1-4,6 contain the core changes and they are all reviewed, which is
the most important part to me. Everything else is just "a bunch of driver
conversions" and they can flow in over time. I'm also sending more such
driver conversions in separate series, for other drivers.

Luca

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From ben.horgan at arm.com  Thu Dec 18 06:52:58 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Thu, 18 Dec 2025 14:52:58 +0000
Subject: [RFC PATCH 01/38] arm64: mpam: Context switch the MPAM registers
In-Reply-To: <20251218103546.000070fd@huawei.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-2-james.morse@arm.com>
 <20251218103546.000070fd@huawei.com>
Message-ID: <a1786f34-66b8-4620-b619-79e6013882e4@arm.com>

Hi Jonathan,

On 12/18/25 10:35, Jonathan Cameron wrote:
> On Fri, 5 Dec 2025 21:58:24 +0000
> James Morse <james.morse at arm.com> wrote:
> 
>> MPAM allows traffic in the SoC to be labeled by the OS, these labels
>> are used to apply policy in caches and bandwidth regulators, and to
>> monitor traffic in the SoC. The label is made up of a PARTID and PMG
>> value. The x86 equivalent calls these CLOSID and RMID, but they don't
>> map precisely.
>>
>> MPAM has two CPU system registers that is used to hold the PARTID and PMG
>> values that traffic generated at each exception level will use. These can be
>> set per-task by the resctrl file system. (resctrl is the defacto interface
>> for controlling this stuff).
>>
>> Add a helper to switch this.
>>
>> struct task_struct's separate CLOSID and RMID fields are insufficient
>> to implement resctrl using MPAM, as resctrl can change the PARTID (CLOSID)
>> and PMG (sort of like the RMID) separately. On x86, the rmid is an
>> independent number, so a race that writes a mismatched  closid and rmid
>> into hardware is benign. On arm64, the pmg bits extend the partid.
>> (i.e. partid-5 has a pmg-0 that is not the same as partid-6's pmg-0).
>> In this case, mismatching the values will 'dirty' a pmg value that
>> resctrl believes is clean, and is not tracking with its 'limbo' code.
>>
>> To avoid this, the partid and pmg are always read and written as a pair.
>> Instead of making struct task_struct's closid and rmid fields an
>> endian-unsafe union, add the value to struct thread_info and always use
>> READ_ONCE()/WRITE_ONCE() when accessing this field.
>>
>> Resctrl allows a per-cpu 'default' value to be set, this overrides the
>> values when scheduling a task in the default control-group, which has
>> PARTID 0. The way 'code data prioritisation' gets emulated means the
>> register value for the default group needs to be a variable.
>>
>> The current system register value is kept in a per-cpu variable to
>> avoid writing to the system register if the value isn't going to change.
>> Writes to this register may reset the hardware state for regulating
>> bandwidth.
>>
>> Finally, there is no reason to context switch these registers unless
>> there is a driver changing the values in struct task_struct. Hide
>> the whole thing behind a static key. This also allows the driver to
>> disable MPAM in response to errors reported by hardware. Move the
>> existing static key to belong to the arch code, as in the future
>> the MPAM driver may become a loadable module.
>>
>> All this should depend on whether there is an MPAM driver, hide
>> it behind CONFIG_MPAM.
>>
>> CC: Amit Singh Tomar <amitsinght at marvell.com>
>> Signed-off-by: James Morse <james.morse at arm.com>
> 
>> diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/mpam.h
>> new file mode 100644
>> index 000000000000..86a55176f884
>> --- /dev/null
>> +++ b/arch/arm64/include/asm/mpam.h
>> @@ -0,0 +1,74 @@
> ...
> 
>> +/*
>> + * The resctrl filesystem writes to the partid/pmg values for threads and CPUs,
>> + * which may race with reads in __mpam_sched_in(). Ensure only one of the old
>> + * or new values are used. Particular care should be taken with the pmg field
>> + * as __mpam_sched_in() may read a partid and pmg that don't match, causing
>> + * this value to be stored with cache allocations, despite being considered
>> + * 'free' by resctrl.
>> + *
>> + * A value in struct thread_info is used instead of struct task_struct as the
>> + * cpu's u64 register format is used, but struct task_struct has two u32'.
> 
> This comment probably wants to provide a little more info if it is to be useful,
> 
> Is it a reference to the closid and rmid fields under CONFIG_X86_CPU_RESCTRL?
> I'm not immediately understanding why that matters given you could slap
> a union on it without (I think) resulting in anything else moving.

Yes, the fields referred to are those closid and rmid. As James writes
in the commit message a union is an alternative, but it would be endian
unsafe. Unlikely to matter but lets not break things.

I'm replying for James as he is otherwise engaged. Thanks for the review
of this series and all your review on the previous MPAM series.

> 
> Now having it in thread_info moves it into arch header territory so
> might make sense for that reason.
> 
>> + */
>> +static inline u64 mpam_get_regval(struct task_struct *tsk)
>> +{
>> +#ifdef CONFIG_ARM64_MPAM
>> +	return READ_ONCE(task_thread_info(tsk)->mpam_partid_pmg);
>> +#else
>> +	return 0;
>> +#endif
>> +}
> 

Thanks,

Ben



From shenwei.wang at nxp.com  Thu Dec 18 06:53:55 2025
From: shenwei.wang at nxp.com (Shenwei Wang)
Date: Thu, 18 Dec 2025 14:53:55 +0000
Subject: [PATCH v6 1/5] dt-bindings: remoteproc: imx_rproc: Add "rpmsg"
 subnode support
In-Reply-To: <f53639e8-feef-438a-9b1a-c349fc17d0c6@foss.st.com>
References: <20251212194341.966387-1-shenwei.wang@nxp.com>
 <20251212194341.966387-2-shenwei.wang@nxp.com>
 <f53639e8-feef-438a-9b1a-c349fc17d0c6@foss.st.com>
Message-ID: <PAXPR04MB918536F2859B9A57A0BAE84E89A8A@PAXPR04MB9185.eurprd04.prod.outlook.com>



> -----Original Message-----
> From: Arnaud POULIQUEN <arnaud.pouliquen at foss.st.com>
> Sent: Thursday, December 18, 2025 4:30 AM
> To: Shenwei Wang <shenwei.wang at nxp.com>; Linus Walleij
> <linusw at kernel.org>; Bartosz Golaszewski <brgl at kernel.org>; Rob Herring
> <robh at kernel.org>; Krzysztof Kozlowski <krzk+dt at kernel.org>; Conor Dooley
> <conor+dt at kernel.org>; Bjorn Andersson <andersson at kernel.org>; Mathieu
> Poirier <mathieu.poirier at linaro.org>; Shawn Guo <shawnguo at kernel.org>;
> Sascha Hauer <s.hauer at pengutronix.de>; Jonathan Corbet <corbet at lwn.net>
> Cc: Pengutronix Kernel Team <kernel at pengutronix.de>; Fabio Estevam
> <festevam at gmail.com>; Peng Fan <peng.fan at nxp.com>; linux-
> gpio at vger.kernel.org; devicetree at vger.kernel.org; linux-
> kernel at vger.kernel.org; linux-remoteproc at vger.kernel.org; imx at lists.linux.dev;
> linux-arm-kernel at lists.infradead.org; linux-doc at vger.kernel.org; dl-linux-imx
> <linux-imx at nxp.com>
> Subject: [EXT] Re: [PATCH v6 1/5] dt-bindings: remoteproc: imx_rproc: Add
> "rpmsg" subnode support
>         syscon = <&src>;
> > +
> > +      rpmsg {
> > +        rpmsg-io-channel {
> > +          #address-cells = <1>;
> > +          #size-cells = <0>;
> > +
> > +          gpio at 0 {
> > +            compatible = "rpmsg-gpio";
> > +            reg = <0>;
> > +            gpio-controller;
> > +            #gpio-cells = <2>;
> > +            #interrupt-cells = <2>;
> > +            interrupt-controller;
> > +            interrupt-parent = <&rpmsg_gpioa>;
> 
> 
> "rpmsg_gpioa" seems not defined, or I missed something?
> 

That's just a reference alias in the DTS example, so you can ignore it. I can also remove 
it in the next version to avoid any confusion.

Regards,
Shenwei

> Regards,
> Arnaud
> 
> > +          };
> > +
> > +          gpio at 1 {
> > +            compatible = "rpmsg-gpio";
> > +            reg = <1>;
> > +            gpio-controller;
> > +            #gpio-cells = <2>;
> > +            #interrupt-cells = <2>;
> > +            interrupt-controller;
> > +            interrupt-parent = <&rpmsg_gpiob>;
> > +          };
> > +        };
> > +      };
> >       };
> >   ...



From ben.horgan at arm.com  Thu Dec 18 06:55:23 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Thu, 18 Dec 2025 14:55:23 +0000
Subject: [RFC PATCH 01/38] arm64: mpam: Context switch the MPAM registers
In-Reply-To: <a1786f34-66b8-4620-b619-79e6013882e4@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-2-james.morse@arm.com>
 <20251218103546.000070fd@huawei.com>
 <a1786f34-66b8-4620-b619-79e6013882e4@arm.com>
Message-ID: <c205297d-0f6e-4238-bd6a-3cab498c6a45@arm.com>



On 12/18/25 14:52, Ben Horgan wrote:
> Hi Jonathan,
> 
> On 12/18/25 10:35, Jonathan Cameron wrote:
>> On Fri, 5 Dec 2025 21:58:24 +0000
>> James Morse <james.morse at arm.com> wrote:
>>
>>> MPAM allows traffic in the SoC to be labeled by the OS, these labels
>>> are used to apply policy in caches and bandwidth regulators, and to
>>> monitor traffic in the SoC. The label is made up of a PARTID and PMG
>>> value. The x86 equivalent calls these CLOSID and RMID, but they don't
>>> map precisely.
>>>
>>> MPAM has two CPU system registers that is used to hold the PARTID and PMG
>>> values that traffic generated at each exception level will use. These can be
>>> set per-task by the resctrl file system. (resctrl is the defacto interface
>>> for controlling this stuff).
>>>
>>> Add a helper to switch this.
>>>
>>> struct task_struct's separate CLOSID and RMID fields are insufficient
>>> to implement resctrl using MPAM, as resctrl can change the PARTID (CLOSID)
>>> and PMG (sort of like the RMID) separately. On x86, the rmid is an
>>> independent number, so a race that writes a mismatched  closid and rmid
>>> into hardware is benign. On arm64, the pmg bits extend the partid.
>>> (i.e. partid-5 has a pmg-0 that is not the same as partid-6's pmg-0).
>>> In this case, mismatching the values will 'dirty' a pmg value that
>>> resctrl believes is clean, and is not tracking with its 'limbo' code.
>>>
>>> To avoid this, the partid and pmg are always read and written as a pair.
>>> Instead of making struct task_struct's closid and rmid fields an
>>> endian-unsafe union, add the value to struct thread_info and always use
>>> READ_ONCE()/WRITE_ONCE() when accessing this field.
>>>
>>> Resctrl allows a per-cpu 'default' value to be set, this overrides the
>>> values when scheduling a task in the default control-group, which has
>>> PARTID 0. The way 'code data prioritisation' gets emulated means the
>>> register value for the default group needs to be a variable.
>>>
>>> The current system register value is kept in a per-cpu variable to
>>> avoid writing to the system register if the value isn't going to change.
>>> Writes to this register may reset the hardware state for regulating
>>> bandwidth.
>>>
>>> Finally, there is no reason to context switch these registers unless
>>> there is a driver changing the values in struct task_struct. Hide
>>> the whole thing behind a static key. This also allows the driver to
>>> disable MPAM in response to errors reported by hardware. Move the
>>> existing static key to belong to the arch code, as in the future
>>> the MPAM driver may become a loadable module.
>>>
>>> All this should depend on whether there is an MPAM driver, hide
>>> it behind CONFIG_MPAM.
>>>
>>> CC: Amit Singh Tomar <amitsinght at marvell.com>
>>> Signed-off-by: James Morse <james.morse at arm.com>
>>
>>> diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/mpam.h
>>> new file mode 100644
>>> index 000000000000..86a55176f884
>>> --- /dev/null
>>> +++ b/arch/arm64/include/asm/mpam.h
>>> @@ -0,0 +1,74 @@
>> ...
>>
>>> +/*
>>> + * The resctrl filesystem writes to the partid/pmg values for threads and CPUs,
>>> + * which may race with reads in __mpam_sched_in(). Ensure only one of the old
>>> + * or new values are used. Particular care should be taken with the pmg field
>>> + * as __mpam_sched_in() may read a partid and pmg that don't match, causing
>>> + * this value to be stored with cache allocations, despite being considered
>>> + * 'free' by resctrl.
>>> + *
>>> + * A value in struct thread_info is used instead of struct task_struct as the
>>> + * cpu's u64 register format is used, but struct task_struct has two u32'.
>>
>> This comment probably wants to provide a little more info if it is to be useful,
>>
>> Is it a reference to the closid and rmid fields under CONFIG_X86_CPU_RESCTRL?
>> I'm not immediately understanding why that matters given you could slap
>> a union on it without (I think) resulting in anything else moving.
> 
> Yes, the fields referred to are those closid and rmid. As James writes
> in the commit message a union is an alternative, but it would be endian
> unsafe. Unlikely to matter but lets not break things.

Meant to say... I'll add clarification in this vein to the comment.

> 
> I'm replying for James as he is otherwise engaged. Thanks for the review
> of this series and all your review on the previous MPAM series.
> 
>>
>> Now having it in thread_info moves it into arch header territory so
>> might make sense for that reason.
>>
>>> + */
>>> +static inline u64 mpam_get_regval(struct task_struct *tsk)
>>> +{
>>> +#ifdef CONFIG_ARM64_MPAM
>>> +	return READ_ONCE(task_thread_info(tsk)->mpam_partid_pmg);
>>> +#else
>>> +	return 0;
>>> +#endif
>>> +}
>>
> 
> Thanks,
> 
> Ben
> 

-- 
Thanks,

Ben



From yeoreum.yun at arm.com  Thu Dec 18 07:01:26 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Thu, 18 Dec 2025 15:01:26 +0000
Subject: [PATCH v2 1/2] arm64: mmu: don't allocate page while spliting
 linear mapping
In-Reply-To: <73ced1db-a2e2-49ea-927e-9fc4a30e771e@arm.com>
References: <20251217182007.2345700-1-yeoreum.yun@arm.com>
 <20251217182007.2345700-2-yeoreum.yun@arm.com>
 <73ced1db-a2e2-49ea-927e-9fc4a30e771e@arm.com>
Message-ID: <aUQXRpLzKbl+I3Gu@e129823.arm.com>

Hi Ryan,

> On 17/12/2025 18:20, Yeoreum Yun wrote:
> > Current linear_map_split_to_ptes() allocate the pagetable
> > while split linear mapping to ptes by stop_machine() with GFP_ATOMIC.
> >
> > This is fine for non-PREEMPR_RT case.
> > However It's a problem in PREEMPR_RT case since
> > generic memory allocation/free APIs (e.x) pgtable_alloc(), __get_free_pages and etc
> > couldn't be called in non-preemptible context except _nolock() APIs
> > since generic memory allocation/free APIs are *sleepable* for using *spin_lock()*
> >
> > IOW, calling a pgtable_alloc() even with GFP_ATOMIC
> > doesn't allow in __linear_map_split_to_pte() executed by stopper thread
> > where preemption is disabled in PREEMPR_RT.
> >
> > To address this, divide linear_map_maybe_split_ptes:
> >   - collect number of pages to require for spliting.
> >   - allocate the required number of pages for spliting.
> >   - with pre-allocate page, split the linear map.
>
> Thanks for working on this fix!
>
> First some high level comments: I'm not a huge fan of the approach with the
> different modes to modify behaviour.
>
> For the first step of figuring out the number of pages required; there is no
> need to be inside stop_machine() for that. Can should be able to just walk the
> linear map without any locking since it is created once and remains static, with
> the exception of hotplug, but that is not enabled yet.
>
> I think it would be cleaner to just create separate walker callbacks rather than
> repurpose the existing walker.

Okay. I'll repsin with separate walker.

>
> Then you could simply change the gfp flag to a callback function pointer and
> pass the desired allocator as a function pointer. This would match the existing
> patterns used in mmu.c today.
>
> The preallocated page list could be stored in a global static variable and you
> could create an allocation function that just strims a page from that list. See
> kpti_ng_pgd_alloc() for an existing example. That assumes a contiguous block,
> but you could generalize it to hold a list of struct pages and reuse it for both
> cases?

If we use walker callbacks, I think it not only pass the callback
function, but it need to pass the gfp flag too since split_xxx() is
called by another functions. (i.e) set_memory_xxx()

I think I can remove the mode with the suggestion of @David
but, I think it would be still use split_args with information of
gfp and preallocate buffer.
>
> >
> > Fixes: 3df6979d222b ("arm64: mm: split linear mapping if BBML2 unsupported on secondary CPUs")
> > Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
> > ---
> >  arch/arm64/mm/mmu.c | 213 +++++++++++++++++++++++++++++++++++---------
> >  1 file changed, 170 insertions(+), 43 deletions(-)
> >
> > diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> > index 9ae7ce00a7ef..e4e6c7e0a016 100644
> > --- a/arch/arm64/mm/mmu.c
> > +++ b/arch/arm64/mm/mmu.c
> > @@ -527,18 +527,28 @@ static void early_create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys,
> >  		panic("Failed to create page tables\n");
> >  }
> >
> > -static phys_addr_t __pgd_pgtable_alloc(struct mm_struct *mm, gfp_t gfp,
> > -				       enum pgtable_type pgtable_type)
> > -{
> > -	/* Page is zeroed by init_clear_pgtable() so don't duplicate effort. */
> > -	struct ptdesc *ptdesc = pagetable_alloc(gfp & ~__GFP_ZERO, 0);
> > -	phys_addr_t pa;
> > -
> > -	if (!ptdesc)
> > -		return INVALID_PHYS_ADDR;
> > +enum split_modes {
> > +	SPLIT_ALLOC,
> > +	SPLIT_PREALLOC,
> > +	SPLIT_COLLECT,
> > +};
> >
> > -	pa = page_to_phys(ptdesc_page(ptdesc));
> > +struct split_args {
> > +	enum split_modes mode;
> > +	union {
> > +		struct {
> > +			unsigned long nr;
> > +			unsigned long i;
> > +			struct page **pages;
> > +		};
> > +		gfp_t gfp;
> > +	};
> > +};
> >
> > +static __always_inline void __pgd_pgtable_init(struct mm_struct *mm,
> > +					       struct ptdesc *ptdesc,
> > +					       enum pgtable_type pgtable_type)
> > +{
> >  	switch (pgtable_type) {
> >  	case TABLE_PTE:
> >  		BUG_ON(!pagetable_pte_ctor(mm, ptdesc));
> > @@ -554,19 +564,56 @@ static phys_addr_t __pgd_pgtable_alloc(struct mm_struct *mm, gfp_t gfp,
> >  		break;
> >  	}
> >
> > +}
> > +
> > +static phys_addr_t __pgd_pgtable_alloc(struct mm_struct *mm, gfp_t gfp,
> > +				       enum pgtable_type pgtable_type)
> > +{
> > +	/* Page is zeroed by init_clear_pgtable() so don't duplicate effort. */
> > +	struct ptdesc *ptdesc = pagetable_alloc(gfp & ~__GFP_ZERO, 0);
> > +	phys_addr_t pa;
> > +
> > +	if (!ptdesc)
> > +		return INVALID_PHYS_ADDR;
> > +
> > +	pa = page_to_phys(ptdesc_page(ptdesc));
> > +
> > +	__pgd_pgtable_init(mm, ptdesc, pgtable_type);
> > +
> >  	return pa;
> >  }
> >
> > +static phys_addr_t __pgd_pgtable_prealloc(struct mm_struct *mm,
> > +					  struct split_args *split_args,
> > +					  enum pgtable_type pgtable_type)
> > +{
> > +	struct page *page;
> > +
> > +	BUG_ON(split_args->i >= split_args->nr);
> > +
> > +	page = split_args->pages[split_args->i++];
> > +	if (!page)
> > +		return INVALID_PHYS_ADDR;
> > +
> > +	__pgd_pgtable_init(mm, page_ptdesc(page), pgtable_type);
> > +
> > +	return page_to_phys(page);
> > +}
> > +
> >  static phys_addr_t
> > -pgd_pgtable_alloc_init_mm_gfp(enum pgtable_type pgtable_type, gfp_t gfp)
> > +pgd_pgtable_alloc_split(enum pgtable_type pgtable_type,
> > +		        struct split_args *split_args)
> >  {
> > -	return __pgd_pgtable_alloc(&init_mm, gfp, pgtable_type);
> > +	if (split_args->mode == SPLIT_ALLOC)
> > +		return __pgd_pgtable_alloc(&init_mm, split_args->gfp, pgtable_type);
> > +
> > +	return __pgd_pgtable_prealloc(&init_mm, split_args, pgtable_type);
> >  }
> >
> >  static phys_addr_t __maybe_unused
> >  pgd_pgtable_alloc_init_mm(enum pgtable_type pgtable_type)
> >  {
> > -	return pgd_pgtable_alloc_init_mm_gfp(pgtable_type, GFP_PGTABLE_KERNEL);
> > +	return __pgd_pgtable_alloc(&init_mm, GFP_PGTABLE_KERNEL, pgtable_type);
> >  }
> >
> >  static phys_addr_t
> > @@ -584,7 +631,9 @@ static void split_contpte(pte_t *ptep)
> >  		__set_pte(ptep, pte_mknoncont(__ptep_get(ptep)));
> >  }
> >
> > -static int split_pmd(pmd_t *pmdp, pmd_t pmd, gfp_t gfp, bool to_cont)
> > +static int split_pmd(pmd_t *pmdp, pmd_t pmd,
> > +		     struct split_args *split_args,
> > +		     bool to_cont)
> >  {
> >  	pmdval_t tableprot = PMD_TYPE_TABLE | PMD_TABLE_UXN | PMD_TABLE_AF;
> >  	unsigned long pfn = pmd_pfn(pmd);
> > @@ -593,7 +642,7 @@ static int split_pmd(pmd_t *pmdp, pmd_t pmd, gfp_t gfp, bool to_cont)
> >  	pte_t *ptep;
> >  	int i;
> >
> > -	pte_phys = pgd_pgtable_alloc_init_mm_gfp(TABLE_PTE, gfp);
> > +	pte_phys = pgd_pgtable_alloc_split(TABLE_PTE, split_args);
> >  	if (pte_phys == INVALID_PHYS_ADDR)
> >  		return -ENOMEM;
> >  	ptep = (pte_t *)phys_to_virt(pte_phys);
> > @@ -628,7 +677,9 @@ static void split_contpmd(pmd_t *pmdp)
> >  		set_pmd(pmdp, pmd_mknoncont(pmdp_get(pmdp)));
> >  }
> >
> > -static int split_pud(pud_t *pudp, pud_t pud, gfp_t gfp, bool to_cont)
> > +static int split_pud(pud_t *pudp, pud_t pud,
> > +		    struct split_args *split_args,
> > +		    bool to_cont)
> >  {
> >  	pudval_t tableprot = PUD_TYPE_TABLE | PUD_TABLE_UXN | PUD_TABLE_AF;
> >  	unsigned int step = PMD_SIZE >> PAGE_SHIFT;
> > @@ -638,7 +689,7 @@ static int split_pud(pud_t *pudp, pud_t pud, gfp_t gfp, bool to_cont)
> >  	pmd_t *pmdp;
> >  	int i;
> >
> > -	pmd_phys = pgd_pgtable_alloc_init_mm_gfp(TABLE_PMD, gfp);
> > +	pmd_phys = pgd_pgtable_alloc_split(TABLE_PMD, split_args);
> >  	if (pmd_phys == INVALID_PHYS_ADDR)
> >  		return -ENOMEM;
> >  	pmdp = (pmd_t *)phys_to_virt(pmd_phys);
> > @@ -672,6 +723,10 @@ static int split_kernel_leaf_mapping_locked(unsigned long addr)
> >  	pmd_t *pmdp, pmd;
> >  	pte_t *ptep, pte;
> >  	int ret = 0;
> > +	struct split_args split_args = {
> > +		.mode = SPLIT_ALLOC,
> > +		.gfp = GFP_PGTABLE_KERNEL,
> > +	};
> >
> >  	/*
> >  	 * PGD: If addr is PGD aligned then addr already describes a leaf
> > @@ -707,7 +762,7 @@ static int split_kernel_leaf_mapping_locked(unsigned long addr)
> >  	if (!pud_present(pud))
> >  		goto out;
> >  	if (pud_leaf(pud)) {
> > -		ret = split_pud(pudp, pud, GFP_PGTABLE_KERNEL, true);
> > +		ret = split_pud(pudp, pud, &split_args, true);
> >  		if (ret)
> >  			goto out;
> >  	}
> > @@ -732,7 +787,7 @@ static int split_kernel_leaf_mapping_locked(unsigned long addr)
> >  		 */
> >  		if (ALIGN_DOWN(addr, PMD_SIZE) == addr)
> >  			goto out;
> > -		ret = split_pmd(pmdp, pmd, GFP_PGTABLE_KERNEL, true);
> > +		ret = split_pmd(pmdp, pmd, &split_args, true);
> >  		if (ret)
> >  			goto out;
> >  	}
> > @@ -831,12 +886,17 @@ int split_kernel_leaf_mapping(unsigned long start, unsigned long end)
> >  static int split_to_ptes_pud_entry(pud_t *pudp, unsigned long addr,
> >  				   unsigned long next, struct mm_walk *walk)
> >  {
> > -	gfp_t gfp = *(gfp_t *)walk->private;
> > +	struct split_args *split_args = (struct split_args *)walk->private;
>
> no need for the casting here; it's a void *.

Right. I'll remove it.

>
> >  	pud_t pud = pudp_get(pudp);
> >  	int ret = 0;
> >
> > -	if (pud_leaf(pud))
> > -		ret = split_pud(pudp, pud, gfp, false);
> > +	if (!pud_leaf(pud))
> > +		return 0;
> > +
> > +	if (split_args->mode == SPLIT_COLLECT)
> > +		split_args->nr++;
>
> bug: you're incrementing this for the pmd table that you would have inserted,
> but because you're not actually splitting, split_to_ptes_pmd_entry() will never
> be called for the 512 pte tables you also need. So you need:
>
> 		nr += 1 + PTRS_PER_PMD;
>
> I'm guessing you didn't test this as the BUG would have triggered when you ran
> out of preallocated memory?
>

Good catch! Yes. This is definitely bug.
The reason why I didn't hit the but there is no "block pud" in my enviroment.

> > +	else
> > +		ret = split_pud(pudp, pud, split_args, false);
> >
> >  	return ret;
> >  }
> > @@ -844,22 +904,29 @@ static int split_to_ptes_pud_entry(pud_t *pudp, unsigned long addr,
> >  static int split_to_ptes_pmd_entry(pmd_t *pmdp, unsigned long addr,
> >  				   unsigned long next, struct mm_walk *walk)
> >  {
> > -	gfp_t gfp = *(gfp_t *)walk->private;
> > +	struct split_args *split_args = (struct split_args *)walk->private;
> >  	pmd_t pmd = pmdp_get(pmdp);
> > -	int ret = 0;
> > +	int ret;
> >
> > -	if (pmd_leaf(pmd)) {
> > -		if (pmd_cont(pmd))
> > -			split_contpmd(pmdp);
> > -		ret = split_pmd(pmdp, pmd, gfp, false);
> > +	if (!pmd_leaf(pmd))
> > +		return 0;
> >
> > -		/*
> > -		 * We have split the pmd directly to ptes so there is no need to
> > -		 * visit each pte to check if they are contpte.
> > -		 */
> > -		walk->action = ACTION_CONTINUE;
> > +	if (split_args->mode == SPLIT_COLLECT) {
> > +		split_args->nr++;
> > +		return 0;
> >  	}
> >
> > +	if (pmd_cont(pmd))
> > +		split_contpmd(pmdp);
> > +	ret = split_pmd(pmdp, pmd, split_args, false);
> > +
> > +	/*
> > +	 * We have split the pmd directly to ptes so there is no need to
> > +	 * visit each pte to check if they are contpte.
> > +	 */
> > +	walk->action = ACTION_CONTINUE;
> > +
> > +
> >  	return ret;
> >  }
> >
> > @@ -880,13 +947,15 @@ static const struct mm_walk_ops split_to_ptes_ops = {
> >  	.pte_entry	= split_to_ptes_pte_entry,
> >  };
> >
> > -static int range_split_to_ptes(unsigned long start, unsigned long end, gfp_t gfp)
> > +static int range_split_to_ptes(unsigned long start, unsigned long end,
> > +		 	       struct split_args *split_args)
> >  {
> >  	int ret;
> >
> >  	arch_enter_lazy_mmu_mode();
> >  	ret = walk_kernel_page_table_range_lockless(start, end,
> > -					&split_to_ptes_ops, NULL, &gfp);
> > +						    &split_to_ptes_ops, NULL,
> > +						    split_args);
> >  	arch_leave_lazy_mmu_mode();
> >
> >  	return ret;
> > @@ -903,7 +972,7 @@ static void __init init_idmap_kpti_bbml2_flag(void)
> >  	smp_mb();
> >  }
> >
> > -static int __init linear_map_split_to_ptes(void *__unused)
> > +static int __init linear_map_split_to_ptes(void *data)
> >  {
> >  	/*
> >  	 * Repainting the linear map must be done by CPU0 (the boot CPU) because
> > @@ -911,6 +980,7 @@ static int __init linear_map_split_to_ptes(void *__unused)
> >  	 * be held in a waiting area with the idmap active.
> >  	 */
> >  	if (!smp_processor_id()) {
> > +		struct split_args *split_args = data;
> >  		unsigned long lstart = _PAGE_OFFSET(vabits_actual);
> >  		unsigned long lend = PAGE_END;
> >  		unsigned long kstart = (unsigned long)lm_alias(_stext);
> > @@ -928,12 +998,13 @@ static int __init linear_map_split_to_ptes(void *__unused)
> >  		 * PTE. The kernel alias remains static throughout runtime so
> >  		 * can continue to be safely mapped with large mappings.
> >  		 */
> > -		ret = range_split_to_ptes(lstart, kstart, GFP_ATOMIC);
> > +		ret = range_split_to_ptes(lstart, lend, split_args);
> >  		if (!ret)
> > -			ret = range_split_to_ptes(kend, lend, GFP_ATOMIC);
> > +			ret = range_split_to_ptes(kstart, kend, split_args);
> >  		if (ret)
> >  			panic("Failed to split linear map\n");
> > -		flush_tlb_kernel_range(lstart, lend);
> > +		if (split_args->mode != SPLIT_COLLECT)
> > +			flush_tlb_kernel_range(lstart, lend);
> >
> >  		/*
> >  		 * Relies on dsb in flush_tlb_kernel_range() to avoid reordering
> > @@ -963,10 +1034,61 @@ static int __init linear_map_split_to_ptes(void *__unused)
> >
> >  void __init linear_map_maybe_split_to_ptes(void)
> >  {
> > -	if (linear_map_requires_bbml2 && !system_supports_bbml2_noabort()) {
> > -		init_idmap_kpti_bbml2_flag();
> > -		stop_machine(linear_map_split_to_ptes, NULL, cpu_online_mask);
> > +	struct page **pages = NULL;
> > +	struct split_args split_args;
> > +	int order;
> > +	int nr_populated;
> > +	int err;
> > +
> > +	if (!linear_map_requires_bbml2 || system_supports_bbml2_noabort())
> > +		return;
> > +
> > +	/*
> > +	 * Phase 1: Collect required extra pages to split.
> > +	 */
> > +	split_args.mode = SPLIT_COLLECT;
> > +	split_args.nr = 0;
> > +
> > +	init_idmap_kpti_bbml2_flag();
> > +	stop_machine(linear_map_split_to_ptes, &split_args, cpu_online_mask);
>
> This doesn't require stop_machine().

Yes. I'll separate with new walker as you suggest.

>
> > +
> > +	/*
> > +	 * Phase 2: Allocate necessary pages to split.
> > +	 */
> > +	if (split_args.nr == 0) {
> > +		err = 0;
> > +		split_args.mode = SPLIT_ALLOC;
>
> How would we hit this condition? If everything is already split why not just
> exit early?

I'm thinking about if all of pages map with CONTPTE only then
it need to be splited, but would you let me know whether It wouldn't be possible
for cross checking?

>
> > +	} else {
> > +		err = -ENOMEM;
> > +		order = order_base_2(PAGE_ALIGN(split_args.nr *
> > +					sizeof(struct page *)) >> PAGE_SHIFT);
> > +
> > +		pages = (struct page **)__get_free_pages(GFP_ATOMIC | __GFP_ZERO, order);
>
> As per the other patch, I'd prefer to see GFP_KERNEL | __GFP_ZERO here.
>
> Let's make this a list of struct ptdesc * though.

Agree. I'll change it.

>
> > +		if (!pages)
> > +			goto error;
> > +
> > +		nr_populated = alloc_pages_bulk(GFP_ATOMIC | __GFP_ZERO, split_args.nr, pages);
>
> Just GFP_KERNEL. No need for __GFP_ZERO as they will all be fully overwritten
> with PTEs.
>
> I'd prefer to use pagetable_alloc(GFP_KERNEL, 0) in a loop since that will
> return a proper ptdesc.

Okay.

>
> > +		if (nr_populated < split_args.nr)
> > +			goto error;
> > +
> > +		err = 0;
> > +		split_args.mode = SPLIT_PREALLOC;
> > +		split_args.i = 0;
> > +		split_args.pages = pages;
> >  	}
> > +
> > +	/*
> > +	 * Phase 3: Split linear map.
> > +	 */
> > +	init_idmap_kpti_bbml2_flag();
> > +	stop_machine(linear_map_split_to_ptes, &split_args, cpu_online_mask);
> > +
> > +error:
> > +	if (pages)
> > +		free_pages((unsigned long)pages, order);
>
> It's possible (but unlikely) that another CPU caused a split between figuring
> out the required number of tables and actually doing the full split. In this
> case, you would have preallocated pages left over that you will need to free here.

You're right. I've overlooked this case.
I'll handle it.


Thanks for your review!

--
Sincerely,
Yeoreum Yun


From shenwei.wang at nxp.com  Thu Dec 18 07:11:08 2025
From: shenwei.wang at nxp.com (Shenwei Wang)
Date: Thu, 18 Dec 2025 15:11:08 +0000
Subject: [PATCH v6 2/5] remoteproc: imx_rproc: Populate devices under
 "rpmsg" subnode
In-Reply-To: <805c9dd5-50ca-4e2f-8fe8-b8a601fe4428@foss.st.com>
References: <20251212194341.966387-1-shenwei.wang@nxp.com>
 <20251212194341.966387-3-shenwei.wang@nxp.com>
 <805c9dd5-50ca-4e2f-8fe8-b8a601fe4428@foss.st.com>
Message-ID: <PAXPR04MB91856F8FFE868B753A38326189A8A@PAXPR04MB9185.eurprd04.prod.outlook.com>



> -----Original Message-----
> From: Arnaud POULIQUEN <arnaud.pouliquen at foss.st.com>
> Sent: Thursday, December 18, 2025 5:04 AM
> To: Shenwei Wang <shenwei.wang at nxp.com>; Linus Walleij
> <linusw at kernel.org>; Bartosz Golaszewski <brgl at kernel.org>; Rob Herring
> <robh at kernel.org>; Krzysztof Kozlowski <krzk+dt at kernel.org>; Conor Dooley
> <conor+dt at kernel.org>; Bjorn Andersson <andersson at kernel.org>; Mathieu
> Poirier <mathieu.poirier at linaro.org>; Shawn Guo <shawnguo at kernel.org>;
> Sascha Hauer <s.hauer at pengutronix.de>; Jonathan Corbet <corbet at lwn.net>
> Cc: Pengutronix Kernel Team <kernel at pengutronix.de>; Fabio Estevam
> <festevam at gmail.com>; Peng Fan <peng.fan at nxp.com>; linux-
> gpio at vger.kernel.org; devicetree at vger.kernel.org; linux-
> kernel at vger.kernel.org; linux-remoteproc at vger.kernel.org; imx at lists.linux.dev;
> linux-arm-kernel at lists.infradead.org; linux-doc at vger.kernel.org; dl-linux-imx
> <linux-imx at nxp.com>
> Subject: [EXT] Re: [PATCH v6 2/5] remoteproc: imx_rproc: Populate devices
> under "rpmsg" subnode
> 
> > +     rp_driver->rpdrv.drv.name = name;
> > +     rp_driver->rpdrv.id_table = rpdev_id;
> > +     rp_driver->rpdrv.probe = imx_rpmsg_endpoint_probe;
> > +     rp_driver->rpdrv.remove = imx_rpmsg_endpoint_remove;
> > +     rp_driver->rpdrv.callback = imx_rpmsg_endpoint_cb;
> > +     rp_driver->driver_data = driver_data;
> > +     rp_driver->compat = compat;
> > +
> > +     register_rpmsg_driver(&rp_driver->rpdrv);
> 
> 
> I still believe that creating a dependency between remoteproc and rpmsg is not
> suitable.
> 
> Please correct me if I?m wrong, but since you define gpio at 0 and gpio at 1 in your
> device tree, you call register_rpmsg_driver() twice, creating two instances of the
> same driver. To differentiate both, you fill the rpdrv.id_table with the node
> names "gpio at 0" and "gpio at 1".
> 

Nope. The function of register_rpmsg_driver is invoked only once per channel.

> In a topology with two remote processors, each needing rpmsg-gpio, the same
> situation would not work because you would have two "gpio at 0" entries.
> 

No, it?s working. The gpio-rpmsg driver is designed to support multiple instances. In fact, that?s the reason 
we added the "rpmsg" bus node under the rproc node. 
Please note that you cannot use duplicate labels within the same channel. 

> What about using the ns-announcement mechanism on the remote side to
> address GPIO port/bank instances?
> 
> In the rpmsg-gpio driver, you could define:
> 
> static struct rpmsg_device_id rpmsg_gpio_id_table[] = {
>      { .name = "rpmsg-gpio" },
>      { .name = "rpmsg_gpio-0" },
>      { .name = "rpmsg_gpio-1" },
>      { .name = "rpmsg_gpio-2" },
>      { .name = "rpmsg_gpio-3" },
>      { },
> };
> 

These definitions are redundant. 
The current implementation already supports multiple instances without requiring this 
information to be hardcoded into the driver source.

Regards,
Shenwei

> Then the match between the device tree and the rpmsg bus could be done in the
> rpmsg-gpio driver by matching the rpmsg name with the compatible property plus
> the reg value.
> 
> Example device tree snippet:
> 
> cm33: remoteproc-cm33 {
>      compatible = "fsl,imx8ulp-cm33";
> 
>      rpmsg {
>          rpmsg-io-channel {
>              gpio at 0 {
>                  compatible = "rpmsg_gpio";
>                  reg = <0>;
>              };
> 
>              gpio at 1 {
>                  compatible = "rpmsg_gpio";
>                  reg = <1>;
>              };
> 
>              ...
>          };
> 
>          ...
>      };
> };
> 
> With this approach, rpmsg management could be handled entirely within the
> rpmsg-gpio driver, avoiding the need to register multiple instances of the
> rpmsg_gpio driver.
> 
> Regards,
> Arnaud
> 
> > +
> > +     return 0;
> > +}
> > +
> > +static int rproc_of_rpmsg_node_init(struct platform_device *pdev) {
> > +     struct device *dev = &pdev->dev;
> > +     const char *compat;
> > +     int ret;
> > +
> > +     struct device_node *np __free(device_node) = of_get_child_by_name(dev-
> >of_node, "rpmsg");
> > +     if (!np)
> > +             return 0;
> > +
> > +     for_each_child_of_node_scoped(np, child) {
> > +             compat = imx_of_rpmsg_is_in_map(child->name);
> > +             if (!compat)
> > +                     ret = of_platform_default_populate(child, NULL, dev);
> > +             else
> > +                     ret = imx_of_rpmsg_register_rpdriver(child, dev,
> > + child->name, compat);
> > +
> > +             if (ret < 0)
> > +                     return ret;
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> >   static int imx_rproc_probe(struct platform_device *pdev)
> >   {
> >       struct device *dev = &pdev->dev; @@ -1114,6 +1253,10 @@ static
> > int imx_rproc_probe(struct platform_device *pdev)
> >               goto err_put_pm;
> >       }
> >
> > +     ret = rproc_of_rpmsg_node_init(pdev);
> > +     if (ret < 0)
> > +             dev_info(dev, "populating 'rpmsg' node failed\n");
> > +
> >       return 0;
> >
> >   err_put_pm:
> > diff --git a/include/linux/rpmsg/rpdev_info.h
> > b/include/linux/rpmsg/rpdev_info.h
> > new file mode 100644
> > index 000000000000..13e020cd028b
> > --- /dev/null
> > +++ b/include/linux/rpmsg/rpdev_info.h
> > @@ -0,0 +1,33 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/* Copyright 2025 NXP */
> > +
> > +/*
> > + * @file linux/rpdev_info.h
> > + *
> > + * @brief Global header file for RPDEV Info
> > + *
> > + * @ingroup RPMSG
> > + */
> > +#ifndef __LINUX_RPDEV_INFO_H__
> > +#define __LINUX_RPDEV_INFO_H__
> > +
> > +#define MAX_DEV_PER_CHANNEL    10
> > +
> > +/**
> > + * rpdev_platform_info - store the platform information of rpdev
> > + * @rproc_name: the name of the remote proc.
> > + * @rpdev: rpmsg channel device
> > + * @device_node: pointer to the device node of the rpdev.
> > + * @rx_callback: rx callback handler of the rpdev.
> > + * @channel_devices: an array of the devices related to the rpdev.
> > + */
> > +struct rpdev_platform_info {
> > +     const char *rproc_name;
> > +     struct rpmsg_device *rpdev;
> > +     struct device_node *channel_node;
> > +     int (*rx_callback)(struct rpmsg_device *rpdev, void *data,
> > +                        int len, void *priv, u32 src);
> > +     void *channel_devices[MAX_DEV_PER_CHANNEL];
> > +};
> > +
> > +#endif /* __LINUX_RPDEV_INFO_H__ */


From rostedt at goodmis.org  Thu Dec 18 07:19:42 2025
From: rostedt at goodmis.org (Steven Rostedt)
Date: Thu, 18 Dec 2025 10:19:42 -0500
Subject: [PATCHv5 bpf-next 6/9] ftrace: Add update_ftrace_direct_mod
 function
In-Reply-To: <20251215211402.353056-7-jolsa@kernel.org>
References: <20251215211402.353056-1-jolsa@kernel.org>
	<20251215211402.353056-7-jolsa@kernel.org>
Message-ID: <20251218101942.0716efd6@gandalf.local.home>

On Mon, 15 Dec 2025 22:13:59 +0100
Jiri Olsa <jolsa at kernel.org> wrote:

> diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
> index 48dc0de5f2ce..95a38fb18ed7 100644
> --- a/kernel/trace/ftrace.c
> +++ b/kernel/trace/ftrace.c
> @@ -6489,6 +6489,78 @@ int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash)
>  	return err;
>  }
>  

Kerneldoc needed.

> +int update_ftrace_direct_mod(struct ftrace_ops *ops, struct ftrace_hash *hash, bool do_direct_lock)
> +{
> +	struct ftrace_func_entry *entry, *tmp;
> +	static struct ftrace_ops tmp_ops = {
> +		.func		= ftrace_stub,
> +		.flags		= FTRACE_OPS_FL_STUB,
> +	};
> +	struct ftrace_hash *orig_hash;
> +	unsigned long size, i;
> +	int err = -EINVAL;
> +
> +	if (!hash_count(hash))
> +		return -EINVAL;
> +	if (check_direct_multi(ops))
> +		return -EINVAL;
> +	if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
> +		return -EINVAL;
> +	if (direct_functions == EMPTY_HASH)
> +		return -EINVAL;
> +
> +	if (do_direct_lock)
> +		mutex_lock(&direct_mutex);

This optional taking of the direct_mutex lock needs some serious rationale
and documentation.

> +
> +	orig_hash = ops->func_hash ? ops->func_hash->filter_hash : NULL;
> +	if (!orig_hash)
> +		goto unlock;
> +
> +	/* Enable the tmp_ops to have the same functions as the direct ops */
> +	ftrace_ops_init(&tmp_ops);
> +	tmp_ops.func_hash = ops->func_hash;
> +
> +	err = register_ftrace_function_nolock(&tmp_ops);
> +	if (err)
> +		goto unlock;
> +
> +	/*
> +	 * Call __ftrace_hash_update_ipmodify() here, so that we can call
> +	 * ops->ops_func for the ops. This is needed because the above
> +	 * register_ftrace_function_nolock() worked on tmp_ops.
> +	 */
> +	err = __ftrace_hash_update_ipmodify(ops, orig_hash, orig_hash, true);
> +	if (err)
> +		goto out;
> +
> +	/*
> +	 * Now the ftrace_ops_list_func() is called to do the direct callers.
> +	 * We can safely change the direct functions attached to each entry.
> +	 */
> +	mutex_lock(&ftrace_lock);

I'm going to need some time staring at this code. It looks like it may be
relying on some internals here.

-- Steve


> +
> +	size = 1 << hash->size_bits;
> +	for (i = 0; i < size; i++) {
> +		hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
> +			tmp = __ftrace_lookup_ip(direct_functions, entry->ip);
> +			if (!tmp)
> +				continue;
> +			tmp->direct = entry->direct;
> +		}
> +	}
> +
> +	mutex_unlock(&ftrace_lock);
> +
> +out:
> +	/* Removing the tmp_ops will add the updated direct callers to the functions */
> +	unregister_ftrace_function(&tmp_ops);
> +
> +unlock:
> +	if (do_direct_lock)
> +		mutex_unlock(&direct_mutex);
> +	return err;
> +}
> +
>  #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
>  
>  /**



From will at kernel.org  Thu Dec 18 07:19:17 2025
From: will at kernel.org (Will Deacon)
Date: Thu, 18 Dec 2025 15:19:17 +0000
Subject: [PATCH 11/12] ras: add DeviceTree estatus provider driver
In-Reply-To: <20251218134311.2309421-1-ahmed.tiba@arm.com>
References: <aUPv5UfBByVoLbRV@willie-the-truck>
 <20251218134311.2309421-1-ahmed.tiba@arm.com>
Message-ID: <aUQbdZHkzumTnwVP@willie-the-truck>

On Thu, Dec 18, 2025 at 01:42:47PM +0000, Ahmed Tiba wrote:
> On Thu, 18 Dec 2025 12:13:25PM +0000, Will Deacon wrote:
> >> Introduce a platform driver that maps the CPER status block described
> >> in DeviceTree, feeds it into the estatus core and handles either IRQ- or
> >> poll-driven notifications. Arm64 gains a FIX_ESTATUS_IRQ slot so the
> >> driver can safely map the shared buffer while copying records.
> >>
> >> Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>
> >> ---
> >>  MAINTAINERS                     |   1 +
> >>  arch/arm64/include/asm/fixmap.h |   5 +
> >>  drivers/ras/Kconfig             |  14 ++
> >>  drivers/ras/Makefile            |   1 +
> >>  drivers/ras/estatus-dt.c        | 318 ++++++++++++++++++++++++++++++++
> >>  include/linux/estatus.h         |   3 +-
> >>  6 files changed, 341 insertions(+), 1 deletion(-)
> >>  create mode 100644 drivers/ras/estatus-dt.c
> >>
> >> diff --git a/MAINTAINERS b/MAINTAINERS
> >> index 6b2ef2ddc0c7..5567d5e82053 100644
> >> --- a/MAINTAINERS
> >> +++ b/MAINTAINERS
> >> @@ -21761,6 +21761,7 @@ RAS ERROR STATUS
> >>  M:   Ahmed Tiba <ahmed.tiba at arm.com>
> >>  S:   Maintained
> >>  F:   Documentation/devicetree/bindings/ras/arm,ras-ffh.yaml
> >> +F:   drivers/ras/estatus-dt.c
> >>  F:   drivers/firmware/efi/estatus.c
> >>  F:   include/linux/estatus.h
> >> 
> >> diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h
> >> index 65555284446e..85ffba87bab9 100644
> >> --- a/arch/arm64/include/asm/fixmap.h
> >> +++ b/arch/arm64/include/asm/fixmap.h
> >> @@ -64,6 +64,11 @@ enum fixed_addresses {
> >>  #endif
> >>  #endif /* CONFIG_ACPI_APEI_GHES */
> >> 
> >> +#ifdef CONFIG_RAS_ESTATUS_DT
> >> +     /* Used for ESTATUS mapping from assorted contexts */
> >> +     FIX_ESTATUS_IRQ,
> >> +#endif /* CONFIG_RAS_ESTATUS_DT */
> >
> > Why do we need this in addition to the four existing GHES slots? The DT
> > code doesn't use it and I was assuming that the ACPI code would continue
> > to use the existing irq; is that not the case?
> 
> 
> We still need a dedicated slot when only the DT provider is built.
> All four GHES slots are defined as part of the ACPI implementation,
> so they are not present in a DT-only configuration.
> 
> The estatus core always requests a fixmap index from each provider
> before copying a CPER record. As a result, the DT driver must supply
> its own slot to return a valid enum value to satisfy the common code.

Sorry, but I still don't follow this. The DT code doesn't use the fixmap,
does it? It looks like it maps the buffer ahead of time using
devm_ioremap_resource() and then the accessors don't use the fixmap
index at all, hence the horrible '(void)fixmap_idx;' cast which presumably
stops the compiler from complaining about an unused variable.

Will


From alexander.stein at ew.tq-group.com  Thu Dec 18 07:20:50 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Thu, 18 Dec 2025 16:20:50 +0100
Subject: [PATCH 3/6] arm64: dts: imx8qm-ss-hsio: Wire up DMA IRQ for PCIe
In-Reply-To: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
References: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
Message-ID: <20251218152058.1521806-4-alexander.stein@ew.tq-group.com>

IRQ mapping is already present. Add the missing DMA interrupt. This is
similar to commit 0b4c46f9ad79c ("arm64: dts: imx8qm-ss-hsio: Wire up
DMA IRQ for PCIe")

Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 arch/arm64/boot/dts/freescale/imx8qm-ss-hsio.dtsi | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8qm-ss-hsio.dtsi b/arch/arm64/boot/dts/freescale/imx8qm-ss-hsio.dtsi
index bd6e0aa27efe9..f2c94cdb682b9 100644
--- a/arch/arm64/boot/dts/freescale/imx8qm-ss-hsio.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8qm-ss-hsio.dtsi
@@ -20,8 +20,9 @@ pcie0: pciea: pcie at 5f000000 {
 		ranges = <0x81000000 0 0x00000000 0x4ff80000 0 0x00010000>,
 			 <0x82000000 0 0x40000000 0x40000000 0 0x0ff00000>;
 		#interrupt-cells = <1>;
-		interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "msi";
+		interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "msi", "dma";
 		#address-cells = <3>;
 		#size-cells = <2>;
 		clocks = <&pciea_lpcg IMX_LPCG_CLK_6>,
-- 
2.43.0



From alexander.stein at ew.tq-group.com  Thu Dec 18 07:20:49 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Thu, 18 Dec 2025 16:20:49 +0100
Subject: [PATCH 2/6] dt-bindings: usb: cdns,usb3: support USB devices in DT
In-Reply-To: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
References: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
Message-ID: <20251218152058.1521806-3-alexander.stein@ew.tq-group.com>

Reference usb-hxci.yaml in host mode in order to support on-board USB
hubs.

Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 Documentation/devicetree/bindings/usb/cdns,usb3.yaml | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/Documentation/devicetree/bindings/usb/cdns,usb3.yaml b/Documentation/devicetree/bindings/usb/cdns,usb3.yaml
index f454ddd9bbaa6..1f7f0adc3b1ed 100644
--- a/Documentation/devicetree/bindings/usb/cdns,usb3.yaml
+++ b/Documentation/devicetree/bindings/usb/cdns,usb3.yaml
@@ -85,6 +85,17 @@ required:
 
 allOf:
   - $ref: usb-drd.yaml#
+  - if:
+      properties:
+        dr_mode:
+          const: peripheral
+
+      required:
+        - dr_mode
+    then:
+      $ref: usb.yaml#
+    else:
+      $ref: usb-xhci.yaml#
 
 unevaluatedProperties: false
 
-- 
2.43.0



From alexander.stein at ew.tq-group.com  Thu Dec 18 07:20:48 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Thu, 18 Dec 2025 16:20:48 +0100
Subject: [PATCH 1/6] dt-bindings: clk: rs9: add clock-output-names property
In-Reply-To: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
References: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
Message-ID: <20251218152058.1521806-2-alexander.stein@ew.tq-group.com>

Add "clock-output-names" which is a standard property for clock
providers.

Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 .../bindings/clock/renesas,9series.yaml       | 37 +++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/Documentation/devicetree/bindings/clock/renesas,9series.yaml b/Documentation/devicetree/bindings/clock/renesas,9series.yaml
index af6319697b1c0..5590f04147612 100644
--- a/Documentation/devicetree/bindings/clock/renesas,9series.yaml
+++ b/Documentation/devicetree/bindings/clock/renesas,9series.yaml
@@ -52,6 +52,10 @@ properties:
     items:
       - description: XTal input clock
 
+  clock-output-names:
+    minItems: 1
+    maxItems: 8
+
   renesas,out-amplitude-microvolt:
     enum: [ 600000, 700000, 800000, 900000 ]
     description: Output clock signal amplitude
@@ -83,6 +87,38 @@ required:
 
 additionalProperties: false
 
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - renesas,9fgv0241
+    then:
+      properties:
+        clock-output-names:
+          maxItems: 2
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - renesas,9fgv0441
+    then:
+      properties:
+        clock-output-names:
+          maxItems: 4
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - renesas,9fgv0841
+    then:
+      properties:
+        clock-output-names:
+          maxItems: 8
+
 examples:
   - |
     /* 25MHz reference crystal */
@@ -101,6 +137,7 @@ examples:
             compatible = "renesas,9fgv0241";
             reg = <0x6a>;
             #clock-cells = <1>;
+            clock-output-names = "DIF0";
 
             clocks = <&ref25m>;
 
-- 
2.43.0



From alexander.stein at ew.tq-group.com  Thu Dec 18 07:20:51 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Thu, 18 Dec 2025 16:20:51 +0100
Subject: [PATCH 4/6] dt-bindings: arm: fsl: add bindings for TQMa8x
In-Reply-To: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
References: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
Message-ID: <20251218152058.1521806-5-alexander.stein@ew.tq-group.com>

TQMa8x is a SOM family using NXP i.MX8QM CPU family
MBa8x is an evaluation mainboard for this SOM.

Signed-off-by: Markus Niebel <Markus.Niebel at tq-group.com>
Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 Documentation/devicetree/bindings/arm/fsl.yaml | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
index dfe9fa5c4dbc4..6384b36b6f385 100644
--- a/Documentation/devicetree/bindings/arm/fsl.yaml
+++ b/Documentation/devicetree/bindings/arm/fsl.yaml
@@ -1401,6 +1401,16 @@ properties:
               - const: tq,imx8dxp-tqma8xdps         # TQ-Systems GmbH TQMa8XDPS SOM
               - const: fsl,imx8dxp
 
+      - description:
+          TQMa8x is a series of SOM featuring NXP i.MX8 system-on-chip
+          variants. It is designed to be clicked on different carrier boards
+          MBa8x is the starterkit
+        items:
+          - enum:
+              - tq,imx8qm-tqma8qm-mba8x   # TQ-Systems GmbH TQMa8QM SOM on MBa8x
+          - const: tq,imx8qm-tqma8qm      # TQ-Systems GmbH TQMa8QM SOM
+          - const: fsl,imx8qm
+
       - description: i.MX8ULP based Boards
         items:
           - enum:
-- 
2.43.0



From alexander.stein at ew.tq-group.com  Thu Dec 18 07:20:47 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Thu, 18 Dec 2025 16:20:47 +0100
Subject: [PATCH 0/6] Support TQMa8QM
Message-ID: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>

Hi,

this series adds support for TQ's TQMa8QM. The first 3 patches are prepatory:
1. Add support for clock-output-names for clk-renesas-pcie. This is necessary
as clk-imx8qxp-lpcg.c (driver for phyx1 phyx2 clock gating) reqiures that
property on the parent clock.

2. Add support for USB devices in cdns USB3 host controller, namely
onboard-devices as USB hubs. Implemented similarily to snps,dwc3-common.yaml.

3. Add DMA IRQ for PCIe controller. Similar to commit 0b4c46f9ad79c
("arm64: dts: imx8qm-ss-hsio: Wire up DMA IRQ for PCIe") which was only tested
on imx8qxp which just has one PCIe controller.

4 & 5. Device bindings and platform DT

6. Workaround for missing "ERR050104: Arm/A53: Cache coherency issue"
workaround. See [1] for details. Split into separate commit for easy revert
once an errata workaround has been integrated.

Best regards,
Alexander

[1] https://lore.kernel.org/all/20230420112952.28340-1-iivanov at suse.de/

Alexander Stein (6):
  dt-bindings: clk: rs9: add clock-output-names property
  dt-bindings: usb: cdns,usb3: support USB devices in DT
  arm64: dts: imx8qm-ss-hsio: Wire up DMA IRQ for PCIe
  dt-bindings: arm: fsl: add bindings for TQMa8x
  arm64: dts: Add TQ imx8qm based board
  arm64: dts: imx8qm-tqma8qm-mba8x: Disable Cortex-A72 cluster

 .../devicetree/bindings/arm/fsl.yaml          |  10 +
 .../bindings/clock/renesas,9series.yaml       |  37 +
 .../devicetree/bindings/usb/cdns,usb3.yaml    |  11 +
 arch/arm64/boot/dts/freescale/Makefile        |   1 +
 .../boot/dts/freescale/imx8qm-ss-hsio.dtsi    |   5 +-
 .../dts/freescale/imx8qm-tqma8qm-mba8x.dts    | 869 ++++++++++++++++++
 .../boot/dts/freescale/imx8qm-tqma8qm.dtsi    | 322 +++++++
 7 files changed, 1253 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm64/boot/dts/freescale/imx8qm-tqma8qm-mba8x.dts
 create mode 100644 arch/arm64/boot/dts/freescale/imx8qm-tqma8qm.dtsi

-- 
2.43.0



From geert at linux-m68k.org  Thu Dec 18 07:26:10 2025
From: geert at linux-m68k.org (Geert Uytterhoeven)
Date: Thu, 18 Dec 2025 16:26:10 +0100
Subject: [PATCH 1/6] dt-bindings: clk: rs9: add clock-output-names property
In-Reply-To: <20251218152058.1521806-2-alexander.stein@ew.tq-group.com>
References: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com> <20251218152058.1521806-2-alexander.stein@ew.tq-group.com>
Message-ID: <CAMuHMdWEJ-eYwUTnotsTVEtKrujYVsEB4kFVjRYh3wXZvyjfGQ@mail.gmail.com>

Hi Alexander,

On Thu, 18 Dec 2025 at 16:21, Alexander Stein
<alexander.stein at ew.tq-group.com> wrote:
> Add "clock-output-names" which is a standard property for clock
> providers.

Why? Isn't that property sort of deprecated?

Will be replying to the cover letter next...

> Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds


From geert at linux-m68k.org  Thu Dec 18 07:28:39 2025
From: geert at linux-m68k.org (Geert Uytterhoeven)
Date: Thu, 18 Dec 2025 16:28:39 +0100
Subject: [PATCH 0/6] Support TQMa8QM
In-Reply-To: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
References: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
Message-ID: <CAMuHMdUkghCNb96J38hbEZ8Jct6m2MPvnPumGp-y_dPfPW9eAg@mail.gmail.com>

Hi Alexander,

On Thu, 18 Dec 2025 at 16:22, Alexander Stein
<alexander.stein at ew.tq-group.com> wrote:
> this series adds support for TQ's TQMa8QM. The first 3 patches are prepatory:
> 1. Add support for clock-output-names for clk-renesas-pcie. This is necessary
> as clk-imx8qxp-lpcg.c (driver for phyx1 phyx2 clock gating) reqiures that
> property on the parent clock.

Hmm, clock consumers should have no business with the names used by
clock providers, even less so whether those names are specified in DT
or not.

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds


From Frank.li at nxp.com  Thu Dec 18 07:35:08 2025
From: Frank.li at nxp.com (Frank Li)
Date: Thu, 18 Dec 2025 10:35:08 -0500
Subject: [PATCH v2 3/3] media: imx-csi: use media_pad_is_streaming helper
In-Reply-To: <20251218-media-imx-cleanup-v2-3-9e3e3c269f7f@pengutronix.de>
References: <20251218-media-imx-cleanup-v2-0-9e3e3c269f7f@pengutronix.de>
 <20251218-media-imx-cleanup-v2-3-9e3e3c269f7f@pengutronix.de>
Message-ID: <aUQfLLVHSHD2RIDT@lizhi-Precision-Tower-5810>

On Thu, Dec 18, 2025 at 10:23:51AM +0100, Michael Tretter wrote:
> The media_pad_is_streaming() helper is explicitly intended to check
> whether a pad has been started with media_pipeline_start(). Use it
> instead of relying on the implicit assumption that a pad with a
> pipeline is streaming.
>
> Reviewed-by: Philipp Zabel <p.zabel at pengutronix.de>
> Signed-off-by: Michael Tretter <m.tretter at pengutronix.de>

Reviewed-by: Frank Li <Frank.Li at nxp.com>

 ---
> Changes in v2:
> - Update commit message as suggested by Frank Li
> ---
>  drivers/staging/media/imx/imx-media-utils.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c
> index bd9af147a801..1a2e5e40c99c 100644
> --- a/drivers/staging/media/imx/imx-media-utils.c
> +++ b/drivers/staging/media/imx/imx-media-utils.c
> @@ -774,7 +774,7 @@ int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
>  			__media_pipeline_stop(pad);
>  	} else {
>  		v4l2_subdev_call(sd, video, s_stream, 0);
> -		if (media_pad_pipeline(pad))
> +		if (media_pad_is_streaming(pad))
>  			__media_pipeline_stop(pad);
>  	}
>
>
> --
> 2.47.3
>


From shenwei.wang at nxp.com  Thu Dec 18 07:36:37 2025
From: shenwei.wang at nxp.com (Shenwei Wang)
Date: Thu, 18 Dec 2025 15:36:37 +0000
Subject: [PATCH v6 3/5] docs: driver-api: gpio: generic gpio driver over
 rpmsg bus
In-Reply-To: <86f7f157-d25f-48cb-806c-c8dc914033f1@foss.st.com>
References: <20251212194341.966387-1-shenwei.wang@nxp.com>
 <20251212194341.966387-4-shenwei.wang@nxp.com>
 <86f7f157-d25f-48cb-806c-c8dc914033f1@foss.st.com>
Message-ID: <PAXPR04MB9185A82D9E6FFCA1D1D45BDE89A8A@PAXPR04MB9185.eurprd04.prod.outlook.com>



> -----Original Message-----
> From: Arnaud POULIQUEN <arnaud.pouliquen at foss.st.com>
> Sent: Thursday, December 18, 2025 4:45 AM
> To: Shenwei Wang <shenwei.wang at nxp.com>; Linus Walleij
> <linusw at kernel.org>; Bartosz Golaszewski <brgl at kernel.org>; Rob Herring
> <robh at kernel.org>; Krzysztof Kozlowski <krzk+dt at kernel.org>; Conor Dooley
> <conor+dt at kernel.org>; Bjorn Andersson <andersson at kernel.org>; Mathieu
> Poirier <mathieu.poirier at linaro.org>; Shawn Guo <shawnguo at kernel.org>;
> Sascha Hauer <s.hauer at pengutronix.de>; Jonathan Corbet <corbet at lwn.net>
> Cc: Pengutronix Kernel Team <kernel at pengutronix.de>; Fabio Estevam
> <festevam at gmail.com>; Peng Fan <peng.fan at nxp.com>; linux-
> gpio at vger.kernel.org; devicetree at vger.kernel.org; linux-
> kernel at vger.kernel.org; linux-remoteproc at vger.kernel.org; imx at lists.linux.dev;
> linux-arm-kernel at lists.infradead.org; linux-doc at vger.kernel.org; dl-linux-imx
> <linux-imx at nxp.com>
> Subject: [EXT] Re: [PATCH v6 3/5] docs: driver-api: gpio: generic gpio driver over
> rpmsg bus
> > +
> > + +-----+-------+--------+-----+-----+------------+-----+-----+-----+-
> > + ---+
> > +
> > +- **ID (Message Identification Code)**: Always be 0x5. Indicates the GPIO
> message.
> > +
> > +- **Vendor**: Vendor ID number.
> > +  - 0: Reserved
> > +  - 1: NXP
> 
> These two fields above seem useless for the rpmsg-gpio. Is there any reason to
> keep them?
> 

They are not used so far.
And they are reserved for implementing workarounds that might be required by 
different vendors or different firmware versions.

> > +
> > +- **Version**: Vendor-specific version number (such as software release).
> > +
> > +- **Type (Message Type)**: The message type can be one of:
> > +
> > +  - 0: GPIO_RPMSG_SETUP
> > +  - 1: GPIO_RPMSG_REPLY
> > +  - 2: GPIO_RPMSG_NOTIFY
> > +
> > +- **Cmd**: Command code, used for GPIO_RPMSG_SETUP messages.
> > +
> > +- **reserved[5]**: Reserved bytes. Should always be 0.
> > +
> > +- **line**: The GPIO line index.
> > +
> > +- **port**: The GPIO controller index.
> 
> The description of port and line should be OS-agnostic.
> The notion of a GPIO controller index makes sense from a Linux perspective, but
> here you should provide a hardware description.
> Additionally, I suggest reversing the order of port and line, as a line is an instance
> within a port.
> 
> Suggested definitions:
>    **port**: The GPIO port(bank) index.
>    **line**: The GPIO line(pin) index of the port.
> 

Okay, I?ll use your suggested descriptions in the next version. 
However, I?ll keep the current byte order since it?s the only implementation we?ve been able to test.

> 
> > +
> > +- **data**: See details in the command description below.
> > +
> > +GPIO Commands
> > +-------------
> > +
> > +Commands are specified in the **Cmd** field for **GPIO_RPMSG_SETUP**
> (Type=0) messages.
> > +
> > +The SETUP message is always sent from Linux to the remote firmware.
> > +Each SETUP corresponds to a single REPLY message. The GPIO driver
> > +should serialize messages and determine whether a REPLY message is
> > +required. If a REPLY message is expected but not received within the
> > +specified timeout period (currently 1 second in the Linux driver),
> > +the driver should return -ETIMEOUT.
> > +
> > +GPIO_RPMSG_INPUT_INIT (Cmd=0)
> > +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > +
> > +**Request:**
> > +
> > +.. code-block:: none
> > +
> > +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> > +   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
> > +   | 5   | 1   | 0   | 0   | 0   |  0        |line |port | val | wk |
> > +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> > +
> > +- **val**: Interrupt trigger type.
> > +
> > +  - 0: Interrupt disabled
> > +  - 1: Rising edge trigger
> > +  - 2: Falling edge trigger
> > +  - 3: Both edge trigger
> > +  - 4: Low level trigger
> > +  - 5: High level trigger
> > +
> > +- **wk**: Wakeup enable.
> > +
> > +  The remote system should always aim to stay in a power-efficient
> > + state by  shutting down or clock-gating the GPIO blocks that aren't
> > + in use. Since  the remoteproc driver is responsibe for managing the
> > + power states of the
> 
> s/responsibe/responsible
> 
> > +  remote firmware, the GPIO driver does not require to konow the
> > + firmware's
> 
> s/konow/know/
> 
> > +  running states.
> > +
> > +  When the wakeup bit is set, the remote firmware should configure
> > + the line  as a wakeup source. The firmware should send the
> > + notification message to  Linux after it is woken from the GPIO line.
> 
> What about the other direction? The remote could also need to disable message
> from Linux, right?

There are no restrictions on that.

> In such case the remote might need a message to get the GPIO value on wake-
> up.
> 

The remote is actually managing the GPIO controller. It can get any information 
regarding the GPIO controller if it wants. 

> > +
> > +  - 0: Disable wakeup from GPIO
> > +  - 1: Enable wakeup from GPIO
> > +
> > +**Reply:**
> > +
> > +.. code-block:: none
> > +
> > +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> > +   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
> > +   | 5   | 1   | 0   | 1   | 1   |  0        |line |port | err | 0  |
> > +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> > +
> > +- **err**: Error code from the remote core.
> > +
> > +  - 0: Success
> > +  - 1: General error (early remote software only returns this
> > + unclassified error)
> > +  - 2: Not supported (A command is not supported by the remote
> > + firmware)
> > +  - 3: Resource not available (The resource is not allocated to the
> > + Linux)
> > +  - 4: Resource busy (The resource is already used)
> > +  - 5: Parameter error
> > +
> > +GPIO_RPMSG_OUTPUT_INIT (Cmd=1)
> > +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 
> Does this means that we can not change the output level during runtime?
> else this should be renamed GPIO_RPMSG_OUTPUT_SET
> 

No. You can run the INIT cmd multiple times.

> > +
> > +**Request:**
> > +
> > +.. code-block:: none
> > +
> > +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> > +   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
> > +   | 5   | 1   | 0   | 0   | 1   |  0        |line |port | val | 0  |
> > +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> > +
> > +- **val**: Output level.
> > +
> > +  - 0: Low
> > +  - 1: High
> > +
> > +**Reply:**
> > +
> > +.. code-block:: none
> > +
> > +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> > +   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
> > +   | 5   | 1   | 0   | 1   | 1   |  0        |line |port | err | 0  |
> > +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> > +
> > +- **err**: See above for definitions.
> > +
> > +GPIO_RPMSG_INPUT_GET (Cmd=2)
> > +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > +
> > +**Request:**
> > +
> > +.. code-block:: none
> > +
> > +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> > +   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
> > +   | 5   | 1   | 0   | 0   | 2   |  0        |line |port | 0   | 0  |
> > +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> > +
> > +**Reply:**
> > +
> > +.. code-block:: none
> > +
> > +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+-----+
> > +   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D |
> > +   | 5   | 1   | 0   | 1   | 2   |  0        |line |port | err |level|
> > +
> > + +-----+-----+-----+-----+-----+-----------+-----+-----+-----+-----+
> > +
> > +- **err**: See above for definitions.
> > +
> > +- **level**: Input level.
> > +
> > +  - 0: Low
> > +  - 1: High
> > +
> > +GPIO_RPMSG_GET_DIRECTION (Cmd=3)
> > +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > +
> > +**Request:**
> > +
> > +.. code-block:: none
> > +
> > +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> > +   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
> > +   | 5   | 1   | 0   | 0   | 3   |  0        |line |port | 0   | 0  |
> > +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> > +
> > +**Reply:**
> > +
> > +.. code-block:: none
> > +
> > +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+-----+
> > +   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D |
> > +   | 5   | 1   | 0   | 1   | 3   |  0        |line |port | err | dir |
> > +
> > + +-----+-----+-----+-----+-----+-----------+-----+-----+-----+-----+
> > +
> > +- **err**: See above for definitions.
> > +
> > +- **dir**: Direction.
> > +
> > +  - 0: Output
> > +  - 1: Input
> 
> So here if I well understand, the list of GPIO are defined in DT and This command
> should be use to check the direction during the probe.
> Could you document its usage?
> 

As the cmd name suggests, it?s used to retrieve the current GPIO line direction. This cmd
can run during the probe phase as well as at other times.

> > +
> > +Notification Message
> > +--------------------
> > +
> > +Notifications are sent with **Type=2 (GPIO_RPMSG_NOTIFY)**:
> > +
> > +When a GPIO line asserts an interrupt on the remote processor, the
> > +firmware should immediately mask the corresponding interrupt source
> > +and send a notification message to the Linux. Upon completion of the
> > +interrupt handling on the Linux side, the driver should issue a
> > +**GPIO_RPMSG_INPUT_INIT** command to the firmware to unmask the
> interrupt.
> > +
> > +A Notification message can arrive between a SETUP and its REPLY
> > +message, and the driver is expected to handle this scenario.
> > +
> > +.. code-block:: none
> > +
> > +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> > +   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
> > +   | 5   | 1   | 0   | 2   | 0   |  0        |line |port | 0   | 0  |
> > +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> > +
> > +- **line**: The GPIO line index.
> > +- **port**: The GPIO controller index.
> > +
> > +The reply message for the notification is optional. The remote
> > +firmware can implement it to simulate the interrupt acknowledgment
> behavior.
> > +
> > +The notification reply is sent with the byte index 0x4=1.
> > +
> > +.. code-block:: none
> > +
> > +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> > +   |0x00 |0x01 |0x02 |0x03 |0x04 |0x05..0x09 |0x0A |0x0B |0x0C |0x0D|
> > +   | 5   | 1   | 0   | 2   | 1   |  0        |line |port | 0   | 0  |
> > +   +-----+-----+-----+-----+-----+-----------+-----+-----+-----+----+
> > +
> > +- **line**: The GPIO line index.
> > +- **port**: The GPIO controller index.
> 
> The type seems strange here, it is a reply but tagged as notification, what about
> adding a type 4 GPIO_RPMSG_NOTIFY_REPLY ?
> 

Seems reasonable. I will update it in next version.

> 
> It might be useful to specify the GPIO level as parameter, especially for  "3: Both
> edge trigger"
> 

Okay. Will add a "triggered event type" as a parameter in the notification message in the next version.

Regards,
Shenwei

> Thanks,
> Arnaud
> 
> > diff --git a/Documentation/driver-api/gpio/index.rst
> > b/Documentation/driver-api/gpio/index.rst
> > index bee58f709b9a..e5eb1f82f01f 100644
> > --- a/Documentation/driver-api/gpio/index.rst
> > +++ b/Documentation/driver-api/gpio/index.rst
> > @@ -16,6 +16,7 @@ Contents:
> >      drivers-on-gpio
> >      bt8xxgpio
> >      pca953x
> > +   gpio-rpmsg
> >
> >   Core
> >   ====


From Frank.li at nxp.com  Thu Dec 18 07:37:32 2025
From: Frank.li at nxp.com (Frank Li)
Date: Thu, 18 Dec 2025 10:37:32 -0500
Subject: [PATCH v5 4/5] remoteproc: imx_rproc: Add support for System
 Manager API
In-Reply-To: <20251218-imx95-rproc-2025-12-18-v5-4-b56a27d4158f@nxp.com>
References: <20251218-imx95-rproc-2025-12-18-v5-0-b56a27d4158f@nxp.com>
 <20251218-imx95-rproc-2025-12-18-v5-4-b56a27d4158f@nxp.com>
Message-ID: <aUQfvLm5m8KsRPm2@lizhi-Precision-Tower-5810>

On Thu, Dec 18, 2025 at 01:17:38PM +0800, Peng Fan (OSS) wrote:
> From: Peng Fan <peng.fan at nxp.com>
>
> i.MX95 features a Cortex-M33 core, six Cortex-A55 cores, and
> one Cortex-M7 core. The System Control Management Interface(SCMI)
> firmware runs on the M33 core. The i.MX95 SCMI firmware named System
> Manager(SM) includes vendor extension protocols, Logical Machine
> Management(LMM) protocol and CPU protocol and etc.
>
> Depending on SM configuration, M7 can be used as follows:
>  (1) M7 in a separate Logical Machine (LM) from A55 cores, that Linux
>      can't control
>  (2) M7 in a separate LM from A55 cores that Linux can control using LMM
>      protocol.
>  (3) M7 runs in same Logical Machine as A55 cores, so Linux can control it
>      using CPU protocol
>
> So extend the driver to using LMM and CPU protocol to manage the M7 core.
>  - Compare linux LM ID(got using scmi_imx_lmm_info) and M7 LM ID(the ID
>    is fixed as 1 in SM firmware if M7 is in a separate LM),
>    if Linux LM ID equals M7 LM ID(linux and M7 in same LM), use CPU
>    protocol to start/stop. Otherwise, use LMM protocol to start/stop.
>    Whether using CPU or LMM protocol to start/stop, the M7 status
>    detection could use CPU protocol to detect started or not. So
>    in imx_rproc_detect_mode, use scmi_imx_cpu_started to check the
>    status of M7.
>  - For above case (1) and (2), Use SCMI_IMX_LMM_POWER_ON to detect whether
>    the M7 LM is under control of A55 LM.
>  - For above case , after using SCMI_IMX_LMM_POWER_ON to check
>    permission, SCMI_IMX_LMM_SHUTDOWN API should be called to shutdown
>    the M7 LM to save power only when M7 LM is going to be started by
>    remoteproc framework. Otherwise bypass SCMI_IMX_LMM_SHUTDOWN API if
>    M7 LM is started before booting Linux.
>
> Current setup relies on pre-Linux software(U-Boot) to do M7 TCM ECC
> initialization. In future, we could add the support in Linux to decouple
> U-Boot and Linux.
>
> Reviewed-by: Daniel Baluta <daniel.baluta at nxp.com>
> Signed-off-by: Peng Fan <peng.fan at nxp.com>

Reviewed-by: Frank Li <Frank.Li at nxp.com>

> ---
>  drivers/remoteproc/Kconfig     |   2 +
>  drivers/remoteproc/imx_rproc.c | 198 +++++++++++++++++++++++++++++++++++++++++
>  drivers/remoteproc/imx_rproc.h |   3 +
>  3 files changed, 203 insertions(+)
>
> diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
> index 48a0d3a69ed08057716f1e7ea950899f60bbe0cf..ee54436fea5ad08a9c198ce74d44ce7a9aa206de 100644
> --- a/drivers/remoteproc/Kconfig
> +++ b/drivers/remoteproc/Kconfig
> @@ -27,6 +27,8 @@ config IMX_REMOTEPROC
>  	tristate "i.MX remoteproc support"
>  	depends on ARCH_MXC
>  	depends on HAVE_ARM_SMCCC
> +	depends on IMX_SCMI_CPU_DRV || !IMX_SCMI_CPU_DRV
> +	depends on IMX_SCMI_LMM_DRV || !IMX_SCMI_LMM_DRV
>  	select MAILBOX
>  	help
>  	  Say y here to support iMX's remote processors via the remote
> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
> index b0857a1a9660503ee7cd5473c06dacb5262286b8..ae3183ad996462ad0815889a2291d320ce7a1e8f 100644
> --- a/drivers/remoteproc/imx_rproc.c
> +++ b/drivers/remoteproc/imx_rproc.c
> @@ -8,6 +8,7 @@
>  #include <linux/clk.h>
>  #include <linux/err.h>
>  #include <linux/firmware/imx/sci.h>
> +#include <linux/firmware/imx/sm.h>
>  #include <linux/interrupt.h>
>  #include <linux/kernel.h>
>  #include <linux/mailbox_client.h>
> @@ -22,6 +23,7 @@
>  #include <linux/reboot.h>
>  #include <linux/regmap.h>
>  #include <linux/remoteproc.h>
> +#include <linux/scmi_imx_protocol.h>
>  #include <linux/workqueue.h>
>
>  #include "imx_rproc.h"
> @@ -92,9 +94,16 @@ struct imx_rproc_mem {
>  #define ATT_CORE_MASK   0xffff
>  #define ATT_CORE(I)     BIT((I))
>
> +/* Linux has permission to handle the Logical Machine of remote cores */
> +#define IMX_RPROC_FLAGS_SM_LMM_AVAIL	BIT(0)
> +
>  static int imx_rproc_xtr_mbox_init(struct rproc *rproc, bool tx_block);
>  static void imx_rproc_free_mbox(void *data);
>
> +/* Forward declarations for platform operations */
> +static const struct imx_rproc_plat_ops imx_rproc_ops_sm_lmm;
> +static const struct imx_rproc_plat_ops imx_rproc_ops_sm_cpu;
> +
>  struct imx_rproc {
>  	struct device			*dev;
>  	struct regmap			*regmap;
> @@ -117,6 +126,11 @@ struct imx_rproc {
>  	u32				core_index;
>  	struct dev_pm_domain_list	*pd_list;
>  	const struct imx_rproc_plat_ops	*ops;
> +	/*
> +	 * For i.MX System Manager based systems
> +	 * BIT 0: IMX_RPROC_FLAGS_SM_LMM_AVAIL(RPROC LM is under Linux control )
> +	 */
> +	u32				flags;
>  };
>
>  static const struct imx_rproc_att imx_rproc_att_imx93[] = {
> @@ -313,6 +327,44 @@ static int imx_rproc_scu_api_start(struct rproc *rproc)
>  	return imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, true, priv->entry);
>  }
>
> +static int imx_rproc_sm_cpu_start(struct rproc *rproc)
> +{
> +	struct imx_rproc *priv = rproc->priv;
> +	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
> +	int ret;
> +
> +	ret = scmi_imx_cpu_reset_vector_set(dcfg->cpuid, 0, true, false, false);
> +	if (ret) {
> +		dev_err(priv->dev, "Failed to set reset vector cpuid(%u): %d\n", dcfg->cpuid, ret);
> +		return ret;
> +	}
> +
> +	return scmi_imx_cpu_start(dcfg->cpuid, true);
> +}
> +
> +static int imx_rproc_sm_lmm_start(struct rproc *rproc)
> +{
> +	struct imx_rproc *priv = rproc->priv;
> +	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
> +	struct device *dev = priv->dev;
> +	int ret;
> +
> +	ret = scmi_imx_lmm_reset_vector_set(dcfg->lmid, dcfg->cpuid, 0, 0);
> +	if (ret) {
> +		dev_err(dev, "Failed to set reset vector lmid(%u), cpuid(%u): %d\n",
> +			dcfg->lmid, dcfg->cpuid, ret);
> +		return ret;
> +	}
> +
> +	ret = scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_BOOT, 0);
> +	if (ret) {
> +		dev_err(dev, "Failed to boot lmm(%d): %d\n", dcfg->lmid, ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
>  static int imx_rproc_start(struct rproc *rproc)
>  {
>  	struct imx_rproc *priv = rproc->priv;
> @@ -369,6 +421,25 @@ static int imx_rproc_scu_api_stop(struct rproc *rproc)
>  	return imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, false, priv->entry);
>  }
>
> +static int imx_rproc_sm_cpu_stop(struct rproc *rproc)
> +{
> +	struct imx_rproc *priv = rproc->priv;
> +	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
> +
> +	return scmi_imx_cpu_start(dcfg->cpuid, false);
> +}
> +
> +static int imx_rproc_sm_lmm_stop(struct rproc *rproc)
> +{
> +	struct imx_rproc *priv = rproc->priv;
> +	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
> +
> +	if (!(priv->flags & IMX_RPROC_FLAGS_SM_LMM_AVAIL))
> +		return -EACCES;
> +
> +	return scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_SHUTDOWN, 0);
> +}
> +
>  static int imx_rproc_stop(struct rproc *rproc)
>  {
>  	struct imx_rproc *priv = rproc->priv;
> @@ -485,6 +556,33 @@ static int imx_rproc_mem_release(struct rproc *rproc,
>  	return 0;
>  }
>
> +static int imx_rproc_sm_lmm_prepare(struct rproc *rproc)
> +{
> +	struct imx_rproc *priv = rproc->priv;
> +	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
> +	int ret;
> +
> +	/*
> +	 * IMX_RPROC_FLAGS_SM_LMM_AVAIL not set indicates Linux is not able
> +	 * to start/stop rproc LM, then if rproc is not in detached state,
> +	 * prepare should fail. If in detached state, this is in rproc_attach()
> +	 * path.
> +	 */
> +	if (!(priv->flags & IMX_RPROC_FLAGS_SM_LMM_AVAIL))
> +		return rproc->state == RPROC_DETACHED ? 0 : -EACCES;
> +
> +	/* Power on the Logical Machine to make sure TCM is available. */
> +	ret = scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_POWER_ON, 0);
> +	if (ret) {
> +		dev_err(priv->dev, "Failed to power on lmm(%d): %d\n", dcfg->lmid, ret);
> +		return ret;
> +	}
> +
> +	dev_info(priv->dev, "lmm(%d) powered on by Linux\n", dcfg->lmid);
> +
> +	return 0;
> +}
> +
>  static int imx_rproc_prepare(struct rproc *rproc)
>  {
>  	struct imx_rproc *priv = rproc->priv;
> @@ -980,6 +1078,93 @@ static int imx_rproc_scu_api_detect_mode(struct rproc *rproc)
>  	return 0;
>  }
>
> +static int imx_rproc_sm_lmm_check(struct rproc *rproc, bool started)
> +{
> +	struct imx_rproc *priv = rproc->priv;
> +	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
> +	struct device *dev = priv->dev;
> +	int ret;
> +
> +	/*
> +	 * Use power on to do permission check. If rproc is in different LM,
> +	 * and linux has permission to handle the LM, set IMX_RPROC_FLAGS_SM_LMM_AVAIL.
> +	 */
> +	ret = scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_POWER_ON, 0);
> +	if (ret) {
> +		if (ret == -EACCES) {
> +			/*
> +			 * rproc LM is booted before Linux and not under Linux Control, so only
> +			 * do IPC between RPROC and Linux, not return failure
> +			 */
> +			dev_info(dev, "lmm(%d) not under Linux Control\n", dcfg->lmid);
> +			return 0;
> +		}
> +
> +		dev_err(dev, "power on lmm(%d) failed: %d\n", dcfg->lmid, ret);
> +		return ret;
> +	}
> +
> +
> +	/* rproc was started before boot Linux and under control of Linux, directly return */
> +	if (started) {
> +		priv->flags |= IMX_RPROC_FLAGS_SM_LMM_AVAIL;
> +		return 0;
> +	}
> +
> +	/* else shutdown the LM to save power */
> +	ret = scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_SHUTDOWN, 0);
> +	if (ret) {
> +		dev_err(dev, "shutdown lmm(%d) failed: %d\n", dcfg->lmid, ret);
> +		return ret;
> +	}
> +
> +	priv->flags |= IMX_RPROC_FLAGS_SM_LMM_AVAIL;
> +
> +	return 0;
> +}
> +
> +static int imx_rproc_sm_detect_mode(struct rproc *rproc)
> +{
> +	struct imx_rproc *priv = rproc->priv;
> +	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
> +	struct device *dev = priv->dev;
> +	struct scmi_imx_lmm_info info;
> +	bool started = false;
> +	int ret;
> +
> +	ret = scmi_imx_cpu_started(dcfg->cpuid, &started);
> +	if (ret) {
> +		dev_err(dev, "Failed to detect cpu(%d) status: %d\n", dcfg->cpuid, ret);
> +		return ret;
> +	}
> +
> +	if (started)
> +		priv->rproc->state = RPROC_DETACHED;
> +
> +	/* Get current Linux Logical Machine ID */
> +	ret = scmi_imx_lmm_info(LMM_ID_DISCOVER, &info);
> +	if (ret) {
> +		dev_err(dev, "Failed to get current LMM ID err: %d\n", ret);
> +		return ret;
> +	}
> +
> +	/*
> +	 * Check whether rproc is in the same LM as host core(running Linux)
> +	 * If yes, use CPU protocol API to manage rproc.
> +	 * If no, use Logical Machine API to manage rproc.
> +	 */
> +	if (dcfg->lmid == info.lmid) {
> +		priv->ops = &imx_rproc_ops_sm_cpu;
> +		dev_info(dev, "Using CPU Protocol OPS\n");
> +		return 0;
> +	}
> +
> +	priv->ops = &imx_rproc_ops_sm_lmm;
> +	dev_info(dev, "Using LMM Protocol OPS\n");
> +
> +	return imx_rproc_sm_lmm_check(rproc, started);
> +}
> +
>  static int imx_rproc_detect_mode(struct imx_rproc *priv)
>  {
>  	/*
> @@ -1155,6 +1340,19 @@ static const struct imx_rproc_plat_ops imx_rproc_ops_scu_api = {
>  	.detect_mode	= imx_rproc_scu_api_detect_mode,
>  };
>
> +static const struct imx_rproc_plat_ops imx_rproc_ops_sm_lmm = {
> +	.detect_mode	= imx_rproc_sm_detect_mode,
> +	.prepare	= imx_rproc_sm_lmm_prepare,
> +	.start		= imx_rproc_sm_lmm_start,
> +	.stop		= imx_rproc_sm_lmm_stop,
> +};
> +
> +static const struct imx_rproc_plat_ops imx_rproc_ops_sm_cpu = {
> +	.detect_mode	= imx_rproc_sm_detect_mode,
> +	.start		= imx_rproc_sm_cpu_start,
> +	.stop		= imx_rproc_sm_cpu_stop,
> +};
> +
>  static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn_mmio = {
>  	.src_reg	= IMX7D_SRC_SCR,
>  	.src_mask	= IMX7D_M4_RST_MASK,
> diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h
> index 37417568a0ade2ae4d6a4e3d0f139ea52b185254..d37e6f90548cec727b4aeb874680b42af85bdbb4 100644
> --- a/drivers/remoteproc/imx_rproc.h
> +++ b/drivers/remoteproc/imx_rproc.h
> @@ -38,6 +38,9 @@ struct imx_rproc_dcfg {
>  	size_t				att_size;
>  	u32				flags;
>  	const struct imx_rproc_plat_ops	*ops;
> +	/* For System Manager(SM) based SoCs */
> +	u32				cpuid; /* ID of the remote core */
> +	u32				lmid;  /* ID of the Logcial Machine */
>  };
>
>  #endif /* _IMX_RPROC_H */
>
> --
> 2.37.1
>


From jonathan.cameron at huawei.com  Thu Dec 18 07:38:05 2025
From: jonathan.cameron at huawei.com (Jonathan Cameron)
Date: Thu, 18 Dec 2025 15:38:05 +0000
Subject: [RFC PATCH 01/38] arm64: mpam: Context switch the MPAM
 registers
In-Reply-To: <c205297d-0f6e-4238-bd6a-3cab498c6a45@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
	<20251205215901.17772-2-james.morse@arm.com>
	<20251218103546.000070fd@huawei.com>
	<a1786f34-66b8-4620-b619-79e6013882e4@arm.com>
	<c205297d-0f6e-4238-bd6a-3cab498c6a45@arm.com>
Message-ID: <20251218153805.000073b9@huawei.com>

On Thu, 18 Dec 2025 14:55:23 +0000
Ben Horgan <ben.horgan at arm.com> wrote:

> On 12/18/25 14:52, Ben Horgan wrote:
> > Hi Jonathan,
> > 
> > On 12/18/25 10:35, Jonathan Cameron wrote:  
> >> On Fri, 5 Dec 2025 21:58:24 +0000
> >> James Morse <james.morse at arm.com> wrote:
> >>  
> >>> MPAM allows traffic in the SoC to be labeled by the OS, these labels
> >>> are used to apply policy in caches and bandwidth regulators, and to
> >>> monitor traffic in the SoC. The label is made up of a PARTID and PMG
> >>> value. The x86 equivalent calls these CLOSID and RMID, but they don't
> >>> map precisely.
> >>>
> >>> MPAM has two CPU system registers that is used to hold the PARTID and PMG
> >>> values that traffic generated at each exception level will use. These can be
> >>> set per-task by the resctrl file system. (resctrl is the defacto interface
> >>> for controlling this stuff).
> >>>
> >>> Add a helper to switch this.
> >>>
> >>> struct task_struct's separate CLOSID and RMID fields are insufficient
> >>> to implement resctrl using MPAM, as resctrl can change the PARTID (CLOSID)
> >>> and PMG (sort of like the RMID) separately. On x86, the rmid is an
> >>> independent number, so a race that writes a mismatched  closid and rmid
> >>> into hardware is benign. On arm64, the pmg bits extend the partid.
> >>> (i.e. partid-5 has a pmg-0 that is not the same as partid-6's pmg-0).
> >>> In this case, mismatching the values will 'dirty' a pmg value that
> >>> resctrl believes is clean, and is not tracking with its 'limbo' code.
> >>>
> >>> To avoid this, the partid and pmg are always read and written as a pair.
> >>> Instead of making struct task_struct's closid and rmid fields an
> >>> endian-unsafe union, add the value to struct thread_info and always use
> >>> READ_ONCE()/WRITE_ONCE() when accessing this field.
> >>>
> >>> Resctrl allows a per-cpu 'default' value to be set, this overrides the
> >>> values when scheduling a task in the default control-group, which has
> >>> PARTID 0. The way 'code data prioritisation' gets emulated means the
> >>> register value for the default group needs to be a variable.
> >>>
> >>> The current system register value is kept in a per-cpu variable to
> >>> avoid writing to the system register if the value isn't going to change.
> >>> Writes to this register may reset the hardware state for regulating
> >>> bandwidth.
> >>>
> >>> Finally, there is no reason to context switch these registers unless
> >>> there is a driver changing the values in struct task_struct. Hide
> >>> the whole thing behind a static key. This also allows the driver to
> >>> disable MPAM in response to errors reported by hardware. Move the
> >>> existing static key to belong to the arch code, as in the future
> >>> the MPAM driver may become a loadable module.
> >>>
> >>> All this should depend on whether there is an MPAM driver, hide
> >>> it behind CONFIG_MPAM.
> >>>
> >>> CC: Amit Singh Tomar <amitsinght at marvell.com>
> >>> Signed-off-by: James Morse <james.morse at arm.com>  
> >>  
> >>> diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/mpam.h
> >>> new file mode 100644
> >>> index 000000000000..86a55176f884
> >>> --- /dev/null
> >>> +++ b/arch/arm64/include/asm/mpam.h
> >>> @@ -0,0 +1,74 @@  
> >> ...
> >>  
> >>> +/*
> >>> + * The resctrl filesystem writes to the partid/pmg values for threads and CPUs,
> >>> + * which may race with reads in __mpam_sched_in(). Ensure only one of the old
> >>> + * or new values are used. Particular care should be taken with the pmg field
> >>> + * as __mpam_sched_in() may read a partid and pmg that don't match, causing
> >>> + * this value to be stored with cache allocations, despite being considered
> >>> + * 'free' by resctrl.
> >>> + *
> >>> + * A value in struct thread_info is used instead of struct task_struct as the
> >>> + * cpu's u64 register format is used, but struct task_struct has two u32'.  
> >>
> >> This comment probably wants to provide a little more info if it is to be useful,
> >>
> >> Is it a reference to the closid and rmid fields under CONFIG_X86_CPU_RESCTRL?
> >> I'm not immediately understanding why that matters given you could slap
> >> a union on it without (I think) resulting in anything else moving.  
> > 
> > Yes, the fields referred to are those closid and rmid. As James writes
> > in the commit message a union is an alternative, but it would be endian
> > unsafe. Unlikely to matter but lets not break things.  
> 
> Meant to say... I'll add clarification in this vein to the comment.

Goes to show I didn't read the patch description.  Oops.

I'm probably just being slow today, but why would it be endian unsafe?
I didn't think the alternative would be to assume the two uses of the storage
were valid at the same time but rather just to reuse the space (which would
have 64bit alignment anyway).  For that matter we could just put a u64 in
under a separate ifdef CONFIG_...

Obviously if the code made use of the access to closid / rmid for arm64
systems it would be a problem.

Anyway just expanding on the comment a bit should do the job with no
need for any other changes.

Thanks,

Jonathan


> 
> > 
> > I'm replying for James as he is otherwise engaged. Thanks for the review
> > of this series and all your review on the previous MPAM series.
> >   
> >>
> >> Now having it in thread_info moves it into arch header territory so
> >> might make sense for that reason.
> >>  
> >>> + */
> >>> +static inline u64 mpam_get_regval(struct task_struct *tsk)
> >>> +{
> >>> +#ifdef CONFIG_ARM64_MPAM
> >>> +	return READ_ONCE(task_thread_info(tsk)->mpam_partid_pmg);
> >>> +#else
> >>> +	return 0;
> >>> +#endif
> >>> +}  
> >>  
> > 
> > Thanks,
> > 
> > Ben
> >   
> 



From rostedt at goodmis.org  Thu Dec 18 07:41:19 2025
From: rostedt at goodmis.org (Steven Rostedt)
Date: Thu, 18 Dec 2025 10:41:19 -0500
Subject: [PATCHv5 bpf-next 6/9] ftrace: Add update_ftrace_direct_mod
 function
In-Reply-To: <20251218101942.0716efd6@gandalf.local.home>
References: <20251215211402.353056-1-jolsa@kernel.org>
	<20251215211402.353056-7-jolsa@kernel.org>
	<20251218101942.0716efd6@gandalf.local.home>
Message-ID: <20251218104119.311adc09@gandalf.local.home>

On Thu, 18 Dec 2025 10:19:42 -0500
Steven Rostedt <rostedt at goodmis.org> wrote:

> On Mon, 15 Dec 2025 22:13:59 +0100
> Jiri Olsa <jolsa at kernel.org> wrote:
> 
> > diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
> > index 48dc0de5f2ce..95a38fb18ed7 100644
> > --- a/kernel/trace/ftrace.c
> > +++ b/kernel/trace/ftrace.c
> > @@ -6489,6 +6489,78 @@ int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash)
> >  	return err;
> >  }
> >    
> 
> Kerneldoc needed.
> 
> > +int update_ftrace_direct_mod(struct ftrace_ops *ops, struct ftrace_hash *hash, bool do_direct_lock)
> > +{
> > +	struct ftrace_func_entry *entry, *tmp;
> > +	static struct ftrace_ops tmp_ops = {
> > +		.func		= ftrace_stub,
> > +		.flags		= FTRACE_OPS_FL_STUB,
> > +	};
> > +	struct ftrace_hash *orig_hash;
> > +	unsigned long size, i;
> > +	int err = -EINVAL;
> > +
> > +	if (!hash_count(hash))
> > +		return -EINVAL;
> > +	if (check_direct_multi(ops))
> > +		return -EINVAL;
> > +	if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
> > +		return -EINVAL;
> > +	if (direct_functions == EMPTY_HASH)
> > +		return -EINVAL;
> > +
> > +	if (do_direct_lock)
> > +		mutex_lock(&direct_mutex);  
> 
> This optional taking of the direct_mutex lock needs some serious rationale
> and documentation.
> 
> > +
> > +	orig_hash = ops->func_hash ? ops->func_hash->filter_hash : NULL;
> > +	if (!orig_hash)
> > +		goto unlock;
> > +
> > +	/* Enable the tmp_ops to have the same functions as the direct ops */

Add to the comments here:

	 * In order to modify the direct callers, all the functions need to
	 * first be calling the ftrace_ops_list_func() and not be connected
	 * to any direct callers. To do that, create a temporary ops that
	 * attach to the same functions as the direct ops, and attach that
	 * first. Then when adding the direct ops, it will use the
	 * ftrace_ops_list_func(), and this can safely modify what the
	 * direct ops call.

Or something like that. I want this code to be as clear as day to what it
is doing. In a year or two, we will forget, and this will be very confusing
to newcomers.

> > +	ftrace_ops_init(&tmp_ops);
> > +	tmp_ops.func_hash = ops->func_hash;
> > +
> > +	err = register_ftrace_function_nolock(&tmp_ops);
> > +	if (err)
> > +		goto unlock;
> > +
> > +	/*
> > +	 * Call __ftrace_hash_update_ipmodify() here, so that we can call
> > +	 * ops->ops_func for the ops. This is needed because the above
> > +	 * register_ftrace_function_nolock() worked on tmp_ops.
> > +	 */
> > +	err = __ftrace_hash_update_ipmodify(ops, orig_hash, orig_hash, true);
> > +	if (err)
> > +		goto out;
> > +
> > +	/*
> > +	 * Now the ftrace_ops_list_func() is called to do the direct callers.
> > +	 * We can safely change the direct functions attached to each entry.
> > +	 */
> > +	mutex_lock(&ftrace_lock);  
> 
> I'm going to need some time staring at this code. It looks like it may be
> relying on some internals here.
> 
> -- Steve
> 
> 
> > +

I would add a comment here:

	/* Now update the direct functions to point to the new callbacks */

-- Steve

> > +	size = 1 << hash->size_bits;
> > +	for (i = 0; i < size; i++) {
> > +		hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
> > +			tmp = __ftrace_lookup_ip(direct_functions, entry->ip);
> > +			if (!tmp)
> > +				continue;
> > +			tmp->direct = entry->direct;
> > +		}
> > +	}
> > +
> > +	mutex_unlock(&ftrace_lock);
> > +
> > +out:
> > +	/* Removing the tmp_ops will add the updated direct callers to the functions */
> > +	unregister_ftrace_function(&tmp_ops);
> > +
> > +unlock:
> > +	if (do_direct_lock)
> > +		mutex_unlock(&direct_mutex);
> > +	return err;
> > +}
> > +
> >  #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
> >  
> >  /**  



From Frank.li at nxp.com  Thu Dec 18 07:39:35 2025
From: Frank.li at nxp.com (Frank Li)
Date: Thu, 18 Dec 2025 10:39:35 -0500
Subject: [PATCH v2] remoteproc: imx_dsp_rproc: only reset carveout memory
 at RPROC_OFFLINE state
In-Reply-To: <20251218071750.2692132-1-shengjiu.wang@nxp.com>
References: <20251218071750.2692132-1-shengjiu.wang@nxp.com>
Message-ID: <aUQgNwrBbEzkzXlq@lizhi-Precision-Tower-5810>

On Thu, Dec 18, 2025 at 03:17:50PM +0800, Shengjiu Wang wrote:
> Do not reset memory at suspend and resume stage, because some
> memory is used to save the software state for resume, if it is cleared,
> the resume operation can fail.
>
> Fixes: c4c432dfb00f ("remoteproc: imx_dsp_rproc: Add support of recovery and coredump process")
> Signed-off-by: Shengjiu Wang <shengjiu.wang at nxp.com>
> Reviewed-by: Daniel Baluta <daniel.baluta at nxp.com>
> Reviewed-by: Iuliana Prodan <iuliana.prodan at nxp.com>
> ---
> changes in v2:
> - refine commit message.
Reviewed-by: Frank Li <Frank.Li at nxp.com>
>
>  drivers/remoteproc/imx_dsp_rproc.c | 8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c
> index d03017d6b214..ac8aa71aa56c 100644
> --- a/drivers/remoteproc/imx_dsp_rproc.c
> +++ b/drivers/remoteproc/imx_dsp_rproc.c
> @@ -984,9 +984,11 @@ static int imx_dsp_rproc_load(struct rproc *rproc, const struct firmware *fw)
>  	 * Clear buffers after pm rumtime for internal ocram is not
>  	 * accessible if power and clock are not enabled.
>  	 */
> -	list_for_each_entry(carveout, &rproc->carveouts, node) {
> -		if (carveout->va)
> -			memset(carveout->va, 0, carveout->len);
> +	if (rproc->state == RPROC_OFFLINE) {
> +		list_for_each_entry(carveout, &rproc->carveouts, node) {
> +			if (carveout->va)
> +				memset(carveout->va, 0, carveout->len);
> +		}
>  	}
>
>  	ret = imx_dsp_rproc_elf_load_segments(rproc, fw);
> --
> 2.34.1
>


From Frank.li at nxp.com  Thu Dec 18 07:41:12 2025
From: Frank.li at nxp.com (Frank Li)
Date: Thu, 18 Dec 2025 10:41:12 -0500
Subject: [PATCH 1/3] soc: imx: Use device-managed APIs for i.MX9
In-Reply-To: <20251217-soc-imx9-fix-v1-1-0c763c2dbe29@nxp.com>
References: <20251217-soc-imx9-fix-v1-0-0c763c2dbe29@nxp.com>
 <20251217-soc-imx9-fix-v1-1-0c763c2dbe29@nxp.com>
Message-ID: <aUQgmApH5fTmOXkq@lizhi-Precision-Tower-5810>

On Wed, Dec 17, 2025 at 08:42:07PM +0800, Peng Fan (OSS) wrote:
> From: Peng Fan <peng.fan at nxp.com>
>
> Use device-managed APi to simplify code.
>
> Signed-off-by: Peng Fan <peng.fan at nxp.com>
> ---

Reviewed-by: Frank Li <Frank.Li at nxp.com>

>  drivers/soc/imx/soc-imx9.c | 28 +++++++++-------------------
>  1 file changed, 9 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/soc/imx/soc-imx9.c b/drivers/soc/imx/soc-imx9.c
> index b46d22cf0212c3f40f61ec5be85ca11e5d3207ac..0b1c59c7ddb244549bfeedc47ae6e8d83c20b39b 100644
> --- a/drivers/soc/imx/soc-imx9.c
> +++ b/drivers/soc/imx/soc-imx9.c
> @@ -18,6 +18,7 @@
>
>  static int imx9_soc_probe(struct platform_device *pdev)
>  {
> +	struct device *dev = &pdev->dev;
>  	struct soc_device_attribute *attr;
>  	struct arm_smccc_res res;
>  	struct soc_device *sdev;
> @@ -25,17 +26,17 @@ static int imx9_soc_probe(struct platform_device *pdev)
>  	u64 uid127_64, uid63_0;
>  	int err;
>
> -	attr = kzalloc(sizeof(*attr), GFP_KERNEL);
> +	attr = devm_kzalloc(dev, sizeof(*attr), GFP_KERNEL);
>  	if (!attr)
>  		return -ENOMEM;
>
>  	err = of_property_read_string(of_root, "model", &attr->machine);
>  	if (err) {
>  		pr_err("%s: missing model property: %d\n", __func__, err);
> -		goto attr;
> +		return err;
>  	}
>
> -	attr->family = kasprintf(GFP_KERNEL, "Freescale i.MX");
> +	attr->family = devm_kasprintf(dev, GFP_KERNEL, "Freescale i.MX");
>
>  	/*
>  	 * Retrieve the soc id, rev & uid info:
> @@ -47,39 +48,28 @@ static int imx9_soc_probe(struct platform_device *pdev)
>  	arm_smccc_smc(IMX_SIP_GET_SOC_INFO, 0, 0, 0, 0, 0, 0, 0, &res);
>  	if (res.a0 != SMCCC_RET_SUCCESS) {
>  		pr_err("%s: SMC failed: 0x%lx\n", __func__, res.a0);
> -		err = -EINVAL;
> -		goto family;
> +		return -EINVAL;
>  	}
>
>  	soc_id = SOC_ID(res.a1);
>  	rev_major = SOC_REV_MAJOR(res.a1);
>  	rev_minor = SOC_REV_MINOR(res.a1);
>
> -	attr->soc_id = kasprintf(GFP_KERNEL, "i.MX%2x", soc_id);
> -	attr->revision = kasprintf(GFP_KERNEL, "%d.%d", rev_major, rev_minor);
> +	attr->soc_id = devm_kasprintf(dev, GFP_KERNEL, "i.MX%2x", soc_id);
> +	attr->revision = devm_kasprintf(dev, GFP_KERNEL, "%d.%d", rev_major, rev_minor);
>
>  	uid127_64 = res.a2;
>  	uid63_0 = res.a3;
> -	attr->serial_number = kasprintf(GFP_KERNEL, "%016llx%016llx", uid127_64, uid63_0);
> +	attr->serial_number = devm_kasprintf(dev, GFP_KERNEL, "%016llx%016llx", uid127_64, uid63_0);
>
>  	sdev = soc_device_register(attr);
>  	if (IS_ERR(sdev)) {
>  		err = PTR_ERR(sdev);
>  		pr_err("%s failed to register SoC as a device: %d\n", __func__, err);
> -		goto serial_number;
> +		return err;
>  	}
>
>  	return 0;
> -
> -serial_number:
> -	kfree(attr->serial_number);
> -	kfree(attr->revision);
> -	kfree(attr->soc_id);
> -family:
> -	kfree(attr->family);
> -attr:
> -	kfree(attr);
> -	return err;
>  }
>
>  static __maybe_unused const struct of_device_id imx9_soc_match[] = {
>
> --
> 2.37.1
>


From ryan.roberts at arm.com  Thu Dec 18 07:42:29 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Thu, 18 Dec 2025 15:42:29 +0000
Subject: [PATCH v2 1/2] arm64: mmu: don't allocate page while spliting
 linear mapping
In-Reply-To: <aUQXRpLzKbl+I3Gu@e129823.arm.com>
References: <20251217182007.2345700-1-yeoreum.yun@arm.com>
 <20251217182007.2345700-2-yeoreum.yun@arm.com>
 <73ced1db-a2e2-49ea-927e-9fc4a30e771e@arm.com>
 <aUQXRpLzKbl+I3Gu@e129823.arm.com>
Message-ID: <73644c65-57fd-4d0c-9179-167277214f26@arm.com>

On 18/12/2025 15:01, Yeoreum Yun wrote:
> Hi Ryan,
> 
>> On 17/12/2025 18:20, Yeoreum Yun wrote:
>>> Current linear_map_split_to_ptes() allocate the pagetable
>>> while split linear mapping to ptes by stop_machine() with GFP_ATOMIC.
>>>
>>> This is fine for non-PREEMPR_RT case.
>>> However It's a problem in PREEMPR_RT case since
>>> generic memory allocation/free APIs (e.x) pgtable_alloc(), __get_free_pages and etc
>>> couldn't be called in non-preemptible context except _nolock() APIs
>>> since generic memory allocation/free APIs are *sleepable* for using *spin_lock()*
>>>
>>> IOW, calling a pgtable_alloc() even with GFP_ATOMIC
>>> doesn't allow in __linear_map_split_to_pte() executed by stopper thread
>>> where preemption is disabled in PREEMPR_RT.
>>>
>>> To address this, divide linear_map_maybe_split_ptes:
>>>   - collect number of pages to require for spliting.
>>>   - allocate the required number of pages for spliting.
>>>   - with pre-allocate page, split the linear map.
>>
>> Thanks for working on this fix!
>>
>> First some high level comments: I'm not a huge fan of the approach with the
>> different modes to modify behaviour.
>>
>> For the first step of figuring out the number of pages required; there is no
>> need to be inside stop_machine() for that. Can should be able to just walk the
>> linear map without any locking since it is created once and remains static, with
>> the exception of hotplug, but that is not enabled yet.
>>
>> I think it would be cleaner to just create separate walker callbacks rather than
>> repurpose the existing walker.
> 
> Okay. I'll repsin with separate walker.
> 
>>
>> Then you could simply change the gfp flag to a callback function pointer and
>> pass the desired allocator as a function pointer. This would match the existing
>> patterns used in mmu.c today.
>>
>> The preallocated page list could be stored in a global static variable and you
>> could create an allocation function that just strims a page from that list. See
>> kpti_ng_pgd_alloc() for an existing example. That assumes a contiguous block,
>> but you could generalize it to hold a list of struct pages and reuse it for both
>> cases?
> 
> If we use walker callbacks, I think it not only pass the callback
> function, but it need to pass the gfp flag too since split_xxx() is
> called by another functions. (i.e) set_memory_xxx()
> 
> I think I can remove the mode with the suggestion of @David
> but, I think it would be still use split_args with information of
> gfp and preallocate buffer.

I don't think that's necessary; all other users pass GFP_PGTABLE_KERNEL, so we
just need one allocator function that allocates with GFP_PGTABLE_KERNEL and
another allocator function that allocates from the prealloc'ed list. Then the
user passes the function they want to use.

That would work, I think?

>>
>>>
>>> Fixes: 3df6979d222b ("arm64: mm: split linear mapping if BBML2 unsupported on secondary CPUs")
>>> Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
>>> ---
>>>  arch/arm64/mm/mmu.c | 213 +++++++++++++++++++++++++++++++++++---------
>>>  1 file changed, 170 insertions(+), 43 deletions(-)
>>>
>>> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
>>> index 9ae7ce00a7ef..e4e6c7e0a016 100644
>>> --- a/arch/arm64/mm/mmu.c
>>> +++ b/arch/arm64/mm/mmu.c
>>> @@ -527,18 +527,28 @@ static void early_create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys,
>>>  		panic("Failed to create page tables\n");
>>>  }
>>>
>>> -static phys_addr_t __pgd_pgtable_alloc(struct mm_struct *mm, gfp_t gfp,
>>> -				       enum pgtable_type pgtable_type)
>>> -{
>>> -	/* Page is zeroed by init_clear_pgtable() so don't duplicate effort. */
>>> -	struct ptdesc *ptdesc = pagetable_alloc(gfp & ~__GFP_ZERO, 0);
>>> -	phys_addr_t pa;
>>> -
>>> -	if (!ptdesc)
>>> -		return INVALID_PHYS_ADDR;
>>> +enum split_modes {
>>> +	SPLIT_ALLOC,
>>> +	SPLIT_PREALLOC,
>>> +	SPLIT_COLLECT,
>>> +};
>>>
>>> -	pa = page_to_phys(ptdesc_page(ptdesc));
>>> +struct split_args {
>>> +	enum split_modes mode;
>>> +	union {
>>> +		struct {
>>> +			unsigned long nr;
>>> +			unsigned long i;
>>> +			struct page **pages;
>>> +		};
>>> +		gfp_t gfp;
>>> +	};
>>> +};
>>>
>>> +static __always_inline void __pgd_pgtable_init(struct mm_struct *mm,
>>> +					       struct ptdesc *ptdesc,
>>> +					       enum pgtable_type pgtable_type)
>>> +{
>>>  	switch (pgtable_type) {
>>>  	case TABLE_PTE:
>>>  		BUG_ON(!pagetable_pte_ctor(mm, ptdesc));
>>> @@ -554,19 +564,56 @@ static phys_addr_t __pgd_pgtable_alloc(struct mm_struct *mm, gfp_t gfp,
>>>  		break;
>>>  	}
>>>
>>> +}
>>> +
>>> +static phys_addr_t __pgd_pgtable_alloc(struct mm_struct *mm, gfp_t gfp,
>>> +				       enum pgtable_type pgtable_type)
>>> +{
>>> +	/* Page is zeroed by init_clear_pgtable() so don't duplicate effort. */
>>> +	struct ptdesc *ptdesc = pagetable_alloc(gfp & ~__GFP_ZERO, 0);
>>> +	phys_addr_t pa;
>>> +
>>> +	if (!ptdesc)
>>> +		return INVALID_PHYS_ADDR;
>>> +
>>> +	pa = page_to_phys(ptdesc_page(ptdesc));
>>> +
>>> +	__pgd_pgtable_init(mm, ptdesc, pgtable_type);
>>> +
>>>  	return pa;
>>>  }
>>>
>>> +static phys_addr_t __pgd_pgtable_prealloc(struct mm_struct *mm,
>>> +					  struct split_args *split_args,
>>> +					  enum pgtable_type pgtable_type)
>>> +{
>>> +	struct page *page;
>>> +
>>> +	BUG_ON(split_args->i >= split_args->nr);
>>> +
>>> +	page = split_args->pages[split_args->i++];
>>> +	if (!page)
>>> +		return INVALID_PHYS_ADDR;
>>> +
>>> +	__pgd_pgtable_init(mm, page_ptdesc(page), pgtable_type);
>>> +
>>> +	return page_to_phys(page);
>>> +}
>>> +
>>>  static phys_addr_t
>>> -pgd_pgtable_alloc_init_mm_gfp(enum pgtable_type pgtable_type, gfp_t gfp)
>>> +pgd_pgtable_alloc_split(enum pgtable_type pgtable_type,
>>> +		        struct split_args *split_args)
>>>  {
>>> -	return __pgd_pgtable_alloc(&init_mm, gfp, pgtable_type);
>>> +	if (split_args->mode == SPLIT_ALLOC)
>>> +		return __pgd_pgtable_alloc(&init_mm, split_args->gfp, pgtable_type);
>>> +
>>> +	return __pgd_pgtable_prealloc(&init_mm, split_args, pgtable_type);
>>>  }
>>>
>>>  static phys_addr_t __maybe_unused
>>>  pgd_pgtable_alloc_init_mm(enum pgtable_type pgtable_type)
>>>  {
>>> -	return pgd_pgtable_alloc_init_mm_gfp(pgtable_type, GFP_PGTABLE_KERNEL);
>>> +	return __pgd_pgtable_alloc(&init_mm, GFP_PGTABLE_KERNEL, pgtable_type);
>>>  }
>>>
>>>  static phys_addr_t
>>> @@ -584,7 +631,9 @@ static void split_contpte(pte_t *ptep)
>>>  		__set_pte(ptep, pte_mknoncont(__ptep_get(ptep)));
>>>  }
>>>
>>> -static int split_pmd(pmd_t *pmdp, pmd_t pmd, gfp_t gfp, bool to_cont)
>>> +static int split_pmd(pmd_t *pmdp, pmd_t pmd,
>>> +		     struct split_args *split_args,
>>> +		     bool to_cont)
>>>  {
>>>  	pmdval_t tableprot = PMD_TYPE_TABLE | PMD_TABLE_UXN | PMD_TABLE_AF;
>>>  	unsigned long pfn = pmd_pfn(pmd);
>>> @@ -593,7 +642,7 @@ static int split_pmd(pmd_t *pmdp, pmd_t pmd, gfp_t gfp, bool to_cont)
>>>  	pte_t *ptep;
>>>  	int i;
>>>
>>> -	pte_phys = pgd_pgtable_alloc_init_mm_gfp(TABLE_PTE, gfp);
>>> +	pte_phys = pgd_pgtable_alloc_split(TABLE_PTE, split_args);
>>>  	if (pte_phys == INVALID_PHYS_ADDR)
>>>  		return -ENOMEM;
>>>  	ptep = (pte_t *)phys_to_virt(pte_phys);
>>> @@ -628,7 +677,9 @@ static void split_contpmd(pmd_t *pmdp)
>>>  		set_pmd(pmdp, pmd_mknoncont(pmdp_get(pmdp)));
>>>  }
>>>
>>> -static int split_pud(pud_t *pudp, pud_t pud, gfp_t gfp, bool to_cont)
>>> +static int split_pud(pud_t *pudp, pud_t pud,
>>> +		    struct split_args *split_args,
>>> +		    bool to_cont)
>>>  {
>>>  	pudval_t tableprot = PUD_TYPE_TABLE | PUD_TABLE_UXN | PUD_TABLE_AF;
>>>  	unsigned int step = PMD_SIZE >> PAGE_SHIFT;
>>> @@ -638,7 +689,7 @@ static int split_pud(pud_t *pudp, pud_t pud, gfp_t gfp, bool to_cont)
>>>  	pmd_t *pmdp;
>>>  	int i;
>>>
>>> -	pmd_phys = pgd_pgtable_alloc_init_mm_gfp(TABLE_PMD, gfp);
>>> +	pmd_phys = pgd_pgtable_alloc_split(TABLE_PMD, split_args);
>>>  	if (pmd_phys == INVALID_PHYS_ADDR)
>>>  		return -ENOMEM;
>>>  	pmdp = (pmd_t *)phys_to_virt(pmd_phys);
>>> @@ -672,6 +723,10 @@ static int split_kernel_leaf_mapping_locked(unsigned long addr)
>>>  	pmd_t *pmdp, pmd;
>>>  	pte_t *ptep, pte;
>>>  	int ret = 0;
>>> +	struct split_args split_args = {
>>> +		.mode = SPLIT_ALLOC,
>>> +		.gfp = GFP_PGTABLE_KERNEL,
>>> +	};
>>>
>>>  	/*
>>>  	 * PGD: If addr is PGD aligned then addr already describes a leaf
>>> @@ -707,7 +762,7 @@ static int split_kernel_leaf_mapping_locked(unsigned long addr)
>>>  	if (!pud_present(pud))
>>>  		goto out;
>>>  	if (pud_leaf(pud)) {
>>> -		ret = split_pud(pudp, pud, GFP_PGTABLE_KERNEL, true);
>>> +		ret = split_pud(pudp, pud, &split_args, true);
>>>  		if (ret)
>>>  			goto out;
>>>  	}
>>> @@ -732,7 +787,7 @@ static int split_kernel_leaf_mapping_locked(unsigned long addr)
>>>  		 */
>>>  		if (ALIGN_DOWN(addr, PMD_SIZE) == addr)
>>>  			goto out;
>>> -		ret = split_pmd(pmdp, pmd, GFP_PGTABLE_KERNEL, true);
>>> +		ret = split_pmd(pmdp, pmd, &split_args, true);
>>>  		if (ret)
>>>  			goto out;
>>>  	}
>>> @@ -831,12 +886,17 @@ int split_kernel_leaf_mapping(unsigned long start, unsigned long end)
>>>  static int split_to_ptes_pud_entry(pud_t *pudp, unsigned long addr,
>>>  				   unsigned long next, struct mm_walk *walk)
>>>  {
>>> -	gfp_t gfp = *(gfp_t *)walk->private;
>>> +	struct split_args *split_args = (struct split_args *)walk->private;
>>
>> no need for the casting here; it's a void *.
> 
> Right. I'll remove it.
> 
>>
>>>  	pud_t pud = pudp_get(pudp);
>>>  	int ret = 0;
>>>
>>> -	if (pud_leaf(pud))
>>> -		ret = split_pud(pudp, pud, gfp, false);
>>> +	if (!pud_leaf(pud))
>>> +		return 0;
>>> +
>>> +	if (split_args->mode == SPLIT_COLLECT)
>>> +		split_args->nr++;
>>
>> bug: you're incrementing this for the pmd table that you would have inserted,
>> but because you're not actually splitting, split_to_ptes_pmd_entry() will never
>> be called for the 512 pte tables you also need. So you need:
>>
>> 		nr += 1 + PTRS_PER_PMD;
>>
>> I'm guessing you didn't test this as the BUG would have triggered when you ran
>> out of preallocated memory?
>>
> 
> Good catch! Yes. This is definitely bug.
> The reason why I didn't hit the but there is no "block pud" in my enviroment.
> 
>>> +	else
>>> +		ret = split_pud(pudp, pud, split_args, false);
>>>
>>>  	return ret;
>>>  }
>>> @@ -844,22 +904,29 @@ static int split_to_ptes_pud_entry(pud_t *pudp, unsigned long addr,
>>>  static int split_to_ptes_pmd_entry(pmd_t *pmdp, unsigned long addr,
>>>  				   unsigned long next, struct mm_walk *walk)
>>>  {
>>> -	gfp_t gfp = *(gfp_t *)walk->private;
>>> +	struct split_args *split_args = (struct split_args *)walk->private;
>>>  	pmd_t pmd = pmdp_get(pmdp);
>>> -	int ret = 0;
>>> +	int ret;
>>>
>>> -	if (pmd_leaf(pmd)) {
>>> -		if (pmd_cont(pmd))
>>> -			split_contpmd(pmdp);
>>> -		ret = split_pmd(pmdp, pmd, gfp, false);
>>> +	if (!pmd_leaf(pmd))
>>> +		return 0;
>>>
>>> -		/*
>>> -		 * We have split the pmd directly to ptes so there is no need to
>>> -		 * visit each pte to check if they are contpte.
>>> -		 */
>>> -		walk->action = ACTION_CONTINUE;
>>> +	if (split_args->mode == SPLIT_COLLECT) {
>>> +		split_args->nr++;
>>> +		return 0;
>>>  	}
>>>
>>> +	if (pmd_cont(pmd))
>>> +		split_contpmd(pmdp);
>>> +	ret = split_pmd(pmdp, pmd, split_args, false);
>>> +
>>> +	/*
>>> +	 * We have split the pmd directly to ptes so there is no need to
>>> +	 * visit each pte to check if they are contpte.
>>> +	 */
>>> +	walk->action = ACTION_CONTINUE;
>>> +
>>> +
>>>  	return ret;
>>>  }
>>>
>>> @@ -880,13 +947,15 @@ static const struct mm_walk_ops split_to_ptes_ops = {
>>>  	.pte_entry	= split_to_ptes_pte_entry,
>>>  };
>>>
>>> -static int range_split_to_ptes(unsigned long start, unsigned long end, gfp_t gfp)
>>> +static int range_split_to_ptes(unsigned long start, unsigned long end,
>>> +		 	       struct split_args *split_args)
>>>  {
>>>  	int ret;
>>>
>>>  	arch_enter_lazy_mmu_mode();
>>>  	ret = walk_kernel_page_table_range_lockless(start, end,
>>> -					&split_to_ptes_ops, NULL, &gfp);
>>> +						    &split_to_ptes_ops, NULL,
>>> +						    split_args);
>>>  	arch_leave_lazy_mmu_mode();
>>>
>>>  	return ret;
>>> @@ -903,7 +972,7 @@ static void __init init_idmap_kpti_bbml2_flag(void)
>>>  	smp_mb();
>>>  }
>>>
>>> -static int __init linear_map_split_to_ptes(void *__unused)
>>> +static int __init linear_map_split_to_ptes(void *data)
>>>  {
>>>  	/*
>>>  	 * Repainting the linear map must be done by CPU0 (the boot CPU) because
>>> @@ -911,6 +980,7 @@ static int __init linear_map_split_to_ptes(void *__unused)
>>>  	 * be held in a waiting area with the idmap active.
>>>  	 */
>>>  	if (!smp_processor_id()) {
>>> +		struct split_args *split_args = data;
>>>  		unsigned long lstart = _PAGE_OFFSET(vabits_actual);
>>>  		unsigned long lend = PAGE_END;
>>>  		unsigned long kstart = (unsigned long)lm_alias(_stext);
>>> @@ -928,12 +998,13 @@ static int __init linear_map_split_to_ptes(void *__unused)
>>>  		 * PTE. The kernel alias remains static throughout runtime so
>>>  		 * can continue to be safely mapped with large mappings.
>>>  		 */
>>> -		ret = range_split_to_ptes(lstart, kstart, GFP_ATOMIC);
>>> +		ret = range_split_to_ptes(lstart, lend, split_args);
>>>  		if (!ret)
>>> -			ret = range_split_to_ptes(kend, lend, GFP_ATOMIC);
>>> +			ret = range_split_to_ptes(kstart, kend, split_args);
>>>  		if (ret)
>>>  			panic("Failed to split linear map\n");
>>> -		flush_tlb_kernel_range(lstart, lend);
>>> +		if (split_args->mode != SPLIT_COLLECT)
>>> +			flush_tlb_kernel_range(lstart, lend);
>>>
>>>  		/*
>>>  		 * Relies on dsb in flush_tlb_kernel_range() to avoid reordering
>>> @@ -963,10 +1034,61 @@ static int __init linear_map_split_to_ptes(void *__unused)
>>>
>>>  void __init linear_map_maybe_split_to_ptes(void)
>>>  {
>>> -	if (linear_map_requires_bbml2 && !system_supports_bbml2_noabort()) {
>>> -		init_idmap_kpti_bbml2_flag();
>>> -		stop_machine(linear_map_split_to_ptes, NULL, cpu_online_mask);
>>> +	struct page **pages = NULL;
>>> +	struct split_args split_args;
>>> +	int order;
>>> +	int nr_populated;
>>> +	int err;
>>> +
>>> +	if (!linear_map_requires_bbml2 || system_supports_bbml2_noabort())
>>> +		return;
>>> +
>>> +	/*
>>> +	 * Phase 1: Collect required extra pages to split.
>>> +	 */
>>> +	split_args.mode = SPLIT_COLLECT;
>>> +	split_args.nr = 0;
>>> +
>>> +	init_idmap_kpti_bbml2_flag();
>>> +	stop_machine(linear_map_split_to_ptes, &split_args, cpu_online_mask);
>>
>> This doesn't require stop_machine().
> 
> Yes. I'll separate with new walker as you suggest.
> 
>>
>>> +
>>> +	/*
>>> +	 * Phase 2: Allocate necessary pages to split.
>>> +	 */
>>> +	if (split_args.nr == 0) {
>>> +		err = 0;
>>> +		split_args.mode = SPLIT_ALLOC;
>>
>> How would we hit this condition? If everything is already split why not just
>> exit early?
> 
> I'm thinking about if all of pages map with CONTPTE only then
> it need to be splited, but would you let me know whether It wouldn't be possible
> for cross checking?

Ahh, yes good point!

> 
>>
>>> +	} else {
>>> +		err = -ENOMEM;
>>> +		order = order_base_2(PAGE_ALIGN(split_args.nr *
>>> +					sizeof(struct page *)) >> PAGE_SHIFT);
>>> +
>>> +		pages = (struct page **)__get_free_pages(GFP_ATOMIC | __GFP_ZERO, order);
>>
>> As per the other patch, I'd prefer to see GFP_KERNEL | __GFP_ZERO here.
>>
>> Let's make this a list of struct ptdesc * though.
> 
> Agree. I'll change it.
> 
>>
>>> +		if (!pages)
>>> +			goto error;
>>> +
>>> +		nr_populated = alloc_pages_bulk(GFP_ATOMIC | __GFP_ZERO, split_args.nr, pages);
>>
>> Just GFP_KERNEL. No need for __GFP_ZERO as they will all be fully overwritten
>> with PTEs.
>>
>> I'd prefer to use pagetable_alloc(GFP_KERNEL, 0) in a loop since that will
>> return a proper ptdesc.
> 
> Okay.
> 
>>
>>> +		if (nr_populated < split_args.nr)
>>> +			goto error;
>>> +
>>> +		err = 0;
>>> +		split_args.mode = SPLIT_PREALLOC;
>>> +		split_args.i = 0;
>>> +		split_args.pages = pages;
>>>  	}
>>> +
>>> +	/*
>>> +	 * Phase 3: Split linear map.
>>> +	 */
>>> +	init_idmap_kpti_bbml2_flag();
>>> +	stop_machine(linear_map_split_to_ptes, &split_args, cpu_online_mask);
>>> +
>>> +error:
>>> +	if (pages)
>>> +		free_pages((unsigned long)pages, order);
>>
>> It's possible (but unlikely) that another CPU caused a split between figuring
>> out the required number of tables and actually doing the full split. In this
>> case, you would have preallocated pages left over that you will need to free here.
> 
> You're right. I've overlooked this case.
> I'll handle it.
> 
> 
> Thanks for your review!
> 
> --
> Sincerely,
> Yeoreum Yun



From mchehab+huawei at kernel.org  Thu Dec 18 07:42:42 2025
From: mchehab+huawei at kernel.org (Mauro Carvalho Chehab)
Date: Thu, 18 Dec 2025 16:42:42 +0100
Subject: [PATCH 02/12] ras: add estatus core implementation
In-Reply-To: <20251217112845.1814119-3-ahmed.tiba@arm.com>
References: <20251217112845.1814119-1-ahmed.tiba@arm.com>
 <20251217112845.1814119-3-ahmed.tiba@arm.com>
Message-ID: <6vlj35rmfm7dzjdngxibaygcgmcj3h2ibhuqnoeqqrsrxmsqbt@qpqnm5xndok6>

On Wed, Dec 17, 2025 at 11:28:35AM +0000, Ahmed Tiba wrote:
> Add estatus.c, hook it into the EFI Makefile, and register
> the MAINTAINERS entry for the new code. The implementation provides the
> memory-pool helpers, notifier plumbing, and utility functions that the
> GHES and DeviceTree providers will reuse in later commits.
> 
> Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>
> ---
>  MAINTAINERS                    |   1 +
>  drivers/firmware/efi/Makefile  |   1 +
>  drivers/firmware/efi/estatus.c | 560 +++++++++++++++++++++++++++++++++

If I'm understanding this patch series, you will be basically moving more than
half of the code from drivers/acpi/apei/ghes.c to drivers/firmware/efi/estatus.c:

 drivers/acpi/apei/ghes.c                   | 1292 ++-------------
 drivers/firmware/efi/estatus.c             | 1056 ++++++++++++

 $ wc drivers/acpi/apei/ghes.c drivers/firmware/efi/estatus.c -l
  894 drivers/acpi/apei/ghes.c
 1056 drivers/firmware/efi/estatus.c
 1950 total

The way you're doing of adding things first, and then removing on
separate patches is error prone, makes it hard to review and 
it becomes a lot harder to identify whose are the original authors
of the code.

This will cause undetected conflicts with already-submitted patches
that are under review.

You should instead be moving function per function as-is. Then,
adjust the code to make it more generic.

Regards,
Mauro

>  3 files changed, 562 insertions(+)
>  create mode 100644 drivers/firmware/efi/estatus.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 501b6d300aa5..67d79d4e612d 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -21760,6 +21760,7 @@ F:	drivers/rapidio/
>  RAS ERROR STATUS
>  M:	Ahmed Tiba <ahmed.tiba at arm.com>
>  S:	Maintained
> +F:	drivers/firmware/efi/estatus.c
>  F:	include/linux/estatus.h
>  
>  RAS INFRASTRUCTURE
> diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile
> index 8efbcf699e4f..03708d915bcf 100644
> --- a/drivers/firmware/efi/Makefile
> +++ b/drivers/firmware/efi/Makefile
> @@ -20,6 +20,7 @@ obj-$(CONFIG_EFI_PARAMS_FROM_FDT)	+= fdtparams.o
>  obj-$(CONFIG_EFI_ESRT)			+= esrt.o
>  obj-$(CONFIG_EFI_VARS_PSTORE)		+= efi-pstore.o
>  obj-$(CONFIG_UEFI_CPER)			+= cper.o cper_cxl.o
> +obj-$(CONFIG_RAS_ESTATUS_CORE)		+= estatus.o
>  obj-$(CONFIG_EFI_RUNTIME_WRAPPERS)	+= runtime-wrappers.o
>  subdir-$(CONFIG_EFI_STUB)		+= libstub
>  obj-$(CONFIG_EFI_BOOTLOADER_CONTROL)	+= efibc.o
> diff --git a/drivers/firmware/efi/estatus.c b/drivers/firmware/efi/estatus.c
> new file mode 100644
> index 000000000000..8dae5c73ce27
> --- /dev/null
> +++ b/drivers/firmware/efi/estatus.c
> @@ -0,0 +1,560 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Firmware-first RAS: Generic Error Status Core
> + *
> + * Copyright (C) 2025 ARM Ltd.
> + * Author: Ahmed Tiba <ahmed.tiba at arm.com>
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/cper.h>
> +#include <linux/ratelimit.h>
> +#include <linux/vmalloc.h>
> +#include <linux/llist.h>
> +#include <linux/genalloc.h>
> +#include <linux/pci.h>
> +#include <linux/pfn.h>
> +#include <linux/aer.h>
> +#include <linux/nmi.h>
> +#include <linux/sched/clock.h>
> +#include <linux/uuid.h>
> +#include <linux/kconfig.h>
> +#include <linux/ras.h>
> +#include <linux/mutex.h>
> +#include <linux/notifier.h>
> +#include <linux/workqueue.h>
> +#include <linux/task_work.h>
> +#include <ras/ras_event.h>
> +
> +#include <linux/estatus.h>
> +#include <asm/fixmap.h>
> +
> +void estatus_pool_region_free(unsigned long addr, u32 size);
> +
> +static void estatus_log_hw_error(char level, const char *seq_tag,
> +				 const char *name)
> +{
> +	switch (level) {
> +	case '0':
> +		pr_emerg("%sHardware error from %s\n", seq_tag, name);
> +		break;
> +	case '1':
> +		pr_alert("%sHardware error from %s\n", seq_tag, name);
> +		break;
> +	case '2':
> +		pr_crit("%sHardware error from %s\n", seq_tag, name);
> +		break;
> +	case '3':
> +		pr_err("%sHardware error from %s\n", seq_tag, name);
> +		break;
> +	case '4':
> +		pr_warn("%sHardware error from %s\n", seq_tag, name);
> +		break;
> +	case '5':
> +		pr_notice("%sHardware error from %s\n", seq_tag, name);
> +		break;
> +	case '6':
> +		pr_info("%sHardware error from %s\n", seq_tag, name);
> +		break;
> +	default:
> +		pr_debug("%sHardware error from %s\n", seq_tag, name);
> +		break;
> +	}
> +}
> +
> +static inline u32 estatus_len(struct acpi_hest_generic_status *estatus)
> +{
> +	if (estatus->raw_data_length)
> +		return estatus->raw_data_offset + estatus->raw_data_length;
> +
> +	return sizeof(*estatus) + estatus->data_length;
> +}
> +
> +#define ESTATUS_PFX	"ESTATUS: "
> +
> +#define ESTATUS_ESOURCE_PREALLOC_MAX_SIZE_SIZE	65536
> +
> +#define ESTATUS_POOL_MIN_ALLOC_ORDER 3
> +
> +/* This is just an estimation for memory pool allocation */
> +#define ESTATUS_CACHE_AVG_SIZE	512
> +
> +#define ESTATUS_CACHES_SIZE	4
> +
> +#define ESTATUS_IN_CACHE_MAX_NSEC	10000000000ULL
> +/* Prevent too many caches are allocated because of RCU */
> +#define ESTATUS_CACHE_ALLOCED_MAX	(ESTATUS_CACHES_SIZE * 3 / 2)
> +
> +#define ESTATUS_CACHE_LEN(estatus_len)			\
> +	(sizeof(struct estatus_cache) + (estatus_len))
> +#define ESTATUS_FROM_CACHE(cache)			\
> +	((struct acpi_hest_generic_status *)		\
> +	 ((struct estatus_cache *)(cache) + 1))
> +
> +#define ESTATUS_NODE_LEN(estatus_len)			\
> +	(sizeof(struct estatus_node) + (estatus_len))
> +#define ESTATUS_FROM_NODE(node)				\
> +	((struct acpi_hest_generic_status *)		\
> +	 ((struct estatus_node *)(node) + 1))
> +
> +#define ESTATUS_VENDOR_ENTRY_LEN(gdata_len)		\
> +	(sizeof(struct estatus_vendor_record_entry) + (gdata_len))
> +#define ESTATUS_GDATA_FROM_VENDOR_ENTRY(vendor_entry)	\
> +	((struct acpi_hest_generic_data *)		\
> +	((struct estatus_vendor_record_entry *)(vendor_entry) + 1))
> +
> +static ATOMIC_NOTIFIER_HEAD(estatus_report_chain);
> +
> +struct estatus_vendor_record_entry {
> +	struct work_struct work;
> +	int error_severity;
> +	char vendor_record[];
> +};
> +
> +static struct estatus_cache __rcu *estatus_caches[ESTATUS_CACHES_SIZE];
> +static atomic_t estatus_cache_alloced;
> +
> +static int estatus_panic_timeout __read_mostly = 30;
> +
> +static struct gen_pool *estatus_pool;
> +static DEFINE_MUTEX(estatus_pool_mutex);
> +
> +static inline const char *estatus_source_name(struct estatus_source *source)
> +{
> +	if (source->ops && source->ops->get_name)
> +		return source->ops->get_name(source);
> +
> +	return "unknown";
> +}
> +
> +static inline size_t estatus_source_max_len(struct estatus_source *source)
> +{
> +	if (source->ops && source->ops->get_max_len)
> +		return source->ops->get_max_len(source);
> +
> +	return 0;
> +}
> +
> +static inline enum estatus_notify_mode
> +estatus_source_notify_mode(struct estatus_source *source)
> +{
> +	if (source->ops && source->ops->get_notify_mode)
> +		return source->ops->get_notify_mode(source);
> +
> +	return ESTATUS_NOTIFY_ASYNC;
> +}
> +
> +static inline int estatus_source_get_phys(struct estatus_source *source,
> +					  phys_addr_t *addr)
> +{
> +	if (!source->ops || !source->ops->get_phys)
> +		return -EOPNOTSUPP;
> +
> +	return source->ops->get_phys(source, addr);
> +}
> +
> +static inline int estatus_source_read(struct estatus_source *source,
> +				      phys_addr_t addr, void *buf, size_t len,
> +				      enum fixed_addresses fixmap_idx)
> +{
> +	if (!source->ops || !source->ops->read)
> +		return -EOPNOTSUPP;
> +
> +	return source->ops->read(source, addr, buf, len, fixmap_idx);
> +}
> +
> +static inline int estatus_source_write(struct estatus_source *source,
> +				       phys_addr_t addr, const void *buf,
> +				       size_t len,
> +				       enum fixed_addresses fixmap_idx)
> +{
> +	if (!source->ops || !source->ops->write)
> +		return -EOPNOTSUPP;
> +
> +	return source->ops->write(source, addr, buf, len, fixmap_idx);
> +}
> +
> +static inline void estatus_source_ack(struct estatus_source *source)
> +{
> +	if (source->ops && source->ops->ack)
> +		source->ops->ack(source);
> +}
> +
> +int estatus_pool_init(unsigned int num_ghes)
> +{
> +	unsigned long addr, len;
> +	int rc = 0;
> +
> +	mutex_lock(&estatus_pool_mutex);
> +	if (estatus_pool)
> +		goto out_unlock;
> +
> +	estatus_pool = gen_pool_create(ESTATUS_POOL_MIN_ALLOC_ORDER, -1);
> +	if (!estatus_pool) {
> +		rc = -ENOMEM;
> +		goto out_unlock;
> +	}
> +
> +	if (!num_ghes)
> +		num_ghes = 1;
> +
> +	len = ESTATUS_CACHE_AVG_SIZE * ESTATUS_CACHE_ALLOCED_MAX;
> +	len += (num_ghes * ESTATUS_ESOURCE_PREALLOC_MAX_SIZE_SIZE);
> +
> +	addr = (unsigned long)vmalloc(PAGE_ALIGN(len));
> +	if (!addr) {
> +		rc = -ENOMEM;
> +		goto err_pool_alloc;
> +	}
> +
> +	rc = gen_pool_add(estatus_pool, addr, PAGE_ALIGN(len), -1);
> +	if (rc)
> +		goto err_pool_add;
> +
> +out_unlock:
> +	mutex_unlock(&estatus_pool_mutex);
> +	return rc;
> +
> +err_pool_add:
> +	vfree((void *)addr);
> +err_pool_alloc:
> +	gen_pool_destroy(estatus_pool);
> +	estatus_pool = NULL;
> +	goto out_unlock;
> +}
> +
> +/**
> + * estatus_pool_region_free - free previously allocated memory
> + *				   from the estatus_pool.
> + * @addr: address of memory to free.
> + * @size: size of memory to free.
> + *
> + * Returns none.
> + */
> +void estatus_pool_region_free(unsigned long addr, u32 size)
> +{
> +	gen_pool_free(estatus_pool, addr, size);
> +}
> +EXPORT_SYMBOL_GPL(estatus_pool_region_free);
> +
> +/* Check the top-level record header has an appropriate size. */
> +static int __estatus_check_estatus(struct estatus_source *source,
> +				   struct acpi_hest_generic_status *estatus)
> +{
> +	u32 len = estatus_len(estatus);
> +	size_t max_len = estatus_source_max_len(source);
> +
> +	if (len < sizeof(*estatus)) {
> +		pr_warn_ratelimited(FW_WARN ESTATUS_PFX "Truncated error status block!\n");
> +		return -EIO;
> +	}
> +
> +	if (max_len && len > max_len) {
> +		pr_warn_ratelimited(FW_WARN ESTATUS_PFX "Invalid error status block length!\n");
> +		return -EIO;
> +	}
> +
> +	if (cper_estatus_check_header(estatus)) {
> +		pr_warn_ratelimited(FW_WARN ESTATUS_PFX "Invalid CPER header!\n");
> +		return -EIO;
> +	}
> +
> +	return 0;
> +}
> +
> +/* Read the CPER block, returning its address, and header in estatus. */
> +static int __estatus_peek_estatus(struct estatus_source *source,
> +				  struct acpi_hest_generic_status *estatus,
> +				  phys_addr_t *buf_paddr,
> +				  enum fixed_addresses fixmap_idx)
> +{
> +	int rc;
> +
> +	rc = estatus_source_get_phys(source, buf_paddr);
> +	if (rc) {
> +		*buf_paddr = 0;
> +		pr_warn_ratelimited(FW_WARN ESTATUS_PFX
> +				    "Failed to get error status block address for provider %s: %d\n",
> +				    estatus_source_name(source), rc);
> +		return rc;
> +	}
> +
> +	if (!*buf_paddr)
> +		return -ENOENT;
> +
> +	rc = estatus_source_read(source, *buf_paddr, estatus,
> +				 sizeof(*estatus), fixmap_idx);
> +	if (rc)
> +		return rc;
> +
> +	if (!estatus->block_status) {
> +		*buf_paddr = 0;
> +		return -ENOENT;
> +	}
> +
> +	return 0;
> +}
> +
> +static int __estatus_read_estatus(struct estatus_source *source,
> +				  struct acpi_hest_generic_status *estatus,
> +				  phys_addr_t buf_paddr,
> +				  enum fixed_addresses fixmap_idx,
> +				  size_t buf_len)
> +{
> +	int rc;
> +
> +	rc = estatus_source_read(source, buf_paddr, estatus, buf_len,
> +				 fixmap_idx);
> +	if (rc)
> +		return rc;
> +
> +	if (cper_estatus_check(estatus)) {
> +		pr_warn_ratelimited(FW_WARN ESTATUS_PFX
> +				    "Failed to read error status block for provider %s!\n",
> +				    estatus_source_name(source));
> +		return -EIO;
> +	}
> +
> +	return 0;
> +}
> +
> +static int estatus_read_estatus(struct estatus_source *source,
> +				struct acpi_hest_generic_status *estatus,
> +				phys_addr_t *buf_paddr,
> +				enum fixed_addresses fixmap_idx)
> +{
> +	int rc;
> +
> +	rc = __estatus_peek_estatus(source, estatus, buf_paddr, fixmap_idx);
> +	if (rc)
> +		return rc;
> +
> +	rc = __estatus_check_estatus(source, estatus);
> +	if (rc)
> +		return rc;
> +
> +	return __estatus_read_estatus(source, estatus, *buf_paddr,
> +				      fixmap_idx, estatus_len(estatus));
> +}
> +
> +static void estatus_clear_estatus(struct estatus_source *source,
> +				  struct acpi_hest_generic_status *estatus,
> +				  phys_addr_t buf_paddr,
> +				  enum fixed_addresses fixmap_idx)
> +{
> +	int rc;
> +
> +	estatus->block_status = 0;
> +
> +	if (!buf_paddr)
> +		return;
> +
> +	rc = estatus_source_write(source, buf_paddr, estatus,
> +				  sizeof(estatus->block_status), fixmap_idx);
> +	if (rc)
> +		pr_warn_ratelimited(FW_WARN ESTATUS_PFX
> +				    "Failed to clear error status block for provider %s: %d\n",
> +				    estatus_source_name(source), rc);
> +
> +	estatus_source_ack(source);
> +}
> +
> +static inline int estatus_severity(int severity)
> +{
> +	switch (severity) {
> +	case CPER_SEV_INFORMATIONAL:
> +		return ESTATUS_SEV_NO;
> +	case CPER_SEV_CORRECTED:
> +		return ESTATUS_SEV_CORRECTED;
> +	case CPER_SEV_RECOVERABLE:
> +		return ESTATUS_SEV_RECOVERABLE;
> +	case CPER_SEV_FATAL:
> +		return ESTATUS_SEV_PANIC;
> +	default:
> +		/* Unknown, go panic */
> +		return ESTATUS_SEV_PANIC;
> +	}
> +}
> +
> +static void __estatus_print_estatus(const char *pfx,
> +				    struct estatus_source *source,
> +				    const struct acpi_hest_generic_status *estatus)
> +{
> +	static atomic_t seqno;
> +	unsigned int curr_seqno;
> +	char pfx_seq[64];
> +	char seq_tag[64];
> +	const char *name = estatus_source_name(source);
> +	const char *level = pfx;
> +	char level_char = '4';
> +
> +	if (!level) {
> +		if (estatus_severity(estatus->error_severity) <=
> +		    ESTATUS_SEV_CORRECTED)
> +			level = KERN_WARNING;
> +		else
> +			level = KERN_ERR;
> +	}
> +
> +	if (level[0] == KERN_SOH_ASCII && level[1])
> +		level_char = level[1];
> +	else if (estatus_severity(estatus->error_severity) > ESTATUS_SEV_CORRECTED)
> +		level_char = '3';
> +
> +	curr_seqno = atomic_inc_return(&seqno);
> +	snprintf(seq_tag, sizeof(seq_tag), "{%u}" HW_ERR, curr_seqno);
> +	snprintf(pfx_seq, sizeof(pfx_seq), "%s%s", level, seq_tag);
> +	estatus_log_hw_error(level_char, seq_tag, name);
> +	cper_estatus_print(pfx_seq, estatus);
> +}
> +
> +static int estatus_print_estatus(const char *pfx,
> +				 struct estatus_source *source,
> +				 const struct acpi_hest_generic_status *estatus)
> +{
> +	/* Not more than 2 messages every 5 seconds */
> +	static DEFINE_RATELIMIT_STATE(ratelimit_corrected, 5 * HZ, 2);
> +	static DEFINE_RATELIMIT_STATE(ratelimit_uncorrected, 5 * HZ, 2);
> +	struct ratelimit_state *ratelimit;
> +
> +	if (estatus_severity(estatus->error_severity) <= ESTATUS_SEV_CORRECTED)
> +		ratelimit = &ratelimit_corrected;
> +	else
> +		ratelimit = &ratelimit_uncorrected;
> +	if (__ratelimit(ratelimit)) {
> +		__estatus_print_estatus(pfx, source, estatus);
> +		return 1;
> +	}
> +	return 0;
> +}
> +
> +/*
> + * GHES error status reporting throttle, to report more kinds of
> + * errors, instead of just most frequently occurred errors.
> + */
> +static int estatus_cached(struct acpi_hest_generic_status *estatus)
> +{
> +	u32 len;
> +	int i, cached = 0;
> +	unsigned long long now;
> +	struct estatus_cache *cache;
> +	struct acpi_hest_generic_status *cache_estatus;
> +
> +	len = estatus_len(estatus);
> +	rcu_read_lock();
> +	for (i = 0; i < ESTATUS_CACHES_SIZE; i++) {
> +		cache = rcu_dereference(estatus_caches[i]);
> +		if (!cache)
> +			continue;
> +		if (len != cache->estatus_len)
> +			continue;
> +		cache_estatus = ESTATUS_FROM_CACHE(cache);
> +		if (memcmp(estatus, cache_estatus, len))
> +			continue;
> +		atomic_inc(&cache->count);
> +		now = sched_clock();
> +		if (now - cache->time_in < ESTATUS_IN_CACHE_MAX_NSEC)
> +			cached = 1;
> +		break;
> +	}
> +	rcu_read_unlock();
> +	return cached;
> +}
> +
> +static struct estatus_cache *estatus_cache_alloc(struct estatus_source *source,
> +						 struct acpi_hest_generic_status *estatus)
> +{
> +	int alloced;
> +	u32 len, cache_len;
> +	struct estatus_cache *cache;
> +	struct acpi_hest_generic_status *cache_estatus;
> +
> +	alloced = atomic_add_return(1, &estatus_cache_alloced);
> +	if (alloced > ESTATUS_CACHE_ALLOCED_MAX) {
> +		atomic_dec(&estatus_cache_alloced);
> +		return NULL;
> +	}
> +	len = estatus_len(estatus);
> +	cache_len = ESTATUS_CACHE_LEN(len);
> +	cache = (void *)gen_pool_alloc(estatus_pool, cache_len);
> +	if (!cache) {
> +		atomic_dec(&estatus_cache_alloced);
> +		return NULL;
> +	}
> +	cache_estatus = ESTATUS_FROM_CACHE(cache);
> +	memcpy(cache_estatus, estatus, len);
> +	cache->estatus_len = len;
> +	atomic_set(&cache->count, 0);
> +	cache->source = source;
> +	cache->time_in = sched_clock();
> +	return cache;
> +}
> +
> +static void estatus_cache_rcu_free(struct rcu_head *head)
> +{
> +	struct estatus_cache *cache;
> +	u32 len;
> +
> +	cache = container_of(head, struct estatus_cache, rcu);
> +	len = estatus_len(ESTATUS_FROM_CACHE(cache));
> +	len = ESTATUS_CACHE_LEN(len);
> +	gen_pool_free(estatus_pool, (unsigned long)cache, len);
> +	atomic_dec(&estatus_cache_alloced);
> +}
> +
> +static void estatus_cache_add(struct estatus_source *source,
> +			      struct acpi_hest_generic_status *estatus)
> +{
> +	unsigned long long now, duration, period, max_period = 0;
> +	struct estatus_cache *cache, *new_cache;
> +	struct estatus_cache __rcu *victim;
> +	int i, slot = -1, count;
> +
> +	new_cache = estatus_cache_alloc(source, estatus);
> +	if (!new_cache)
> +		return;
> +
> +	rcu_read_lock();
> +	now = sched_clock();
> +	for (i = 0; i < ESTATUS_CACHES_SIZE; i++) {
> +		cache = rcu_dereference(estatus_caches[i]);
> +		if (!cache) {
> +			slot = i;
> +			break;
> +		}
> +		duration = now - cache->time_in;
> +		if (duration >= ESTATUS_IN_CACHE_MAX_NSEC) {
> +			slot = i;
> +			break;
> +		}
> +		count = atomic_read(&cache->count);
> +		period = duration;
> +		do_div(period, (count + 1));
> +		if (period > max_period) {
> +			max_period = period;
> +			slot = i;
> +		}
> +	}
> +	rcu_read_unlock();
> +
> +	if (slot != -1) {
> +		/*
> +		 * Use release semantics to ensure that estatus_cached()
> +		 * running on another CPU will see the updated cache fields if
> +		 * it can see the new value of the pointer.
> +		 */
> +		victim = xchg_release(&estatus_caches[slot],
> +				      RCU_INITIALIZER(new_cache));
> +
> +		/*
> +		 * At this point, victim may point to a cached item different
> +		 * from the one based on which we selected the slot. Instead of
> +		 * going to the loop again to pick another slot, let's just
> +		 * drop the other item anyway: this may cause a false cache
> +		 * miss later on, but that won't cause any problems.
> +		 */
> +		if (victim)
> +			call_rcu(&unrcu_pointer(victim)->rcu,
> +				 estatus_cache_rcu_free);
> +	}
> +}
> -- 
> 2.43.0
> 

-- 
Thanks,
Mauro


From Frank.li at nxp.com  Thu Dec 18 07:43:11 2025
From: Frank.li at nxp.com (Frank Li)
Date: Thu, 18 Dec 2025 10:43:11 -0500
Subject: [PATCH 2/3] soc: imx: Use dev_err_probe() for i.MX9
In-Reply-To: <20251217-soc-imx9-fix-v1-2-0c763c2dbe29@nxp.com>
References: <20251217-soc-imx9-fix-v1-0-0c763c2dbe29@nxp.com>
 <20251217-soc-imx9-fix-v1-2-0c763c2dbe29@nxp.com>
Message-ID: <aUQhDwPP1nNAPG0b@lizhi-Precision-Tower-5810>

On Wed, Dec 17, 2025 at 08:42:08PM +0800, Peng Fan (OSS) wrote:
> From: Peng Fan <peng.fan at nxp.com>
>
> Use dev_err_probe() to simplify code. No functional changes.
>
> Signed-off-by: Peng Fan <peng.fan at nxp.com>
> ---

Reviewed-by: Frank Li <Frank.Li at nxp.com>

>  drivers/soc/imx/soc-imx9.c | 20 +++++++-------------
>  1 file changed, 7 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/soc/imx/soc-imx9.c b/drivers/soc/imx/soc-imx9.c
> index 0b1c59c7ddb244549bfeedc47ae6e8d83c20b39b..d9a686299c5f710bb9988c55ed601fc9d9f19229 100644
> --- a/drivers/soc/imx/soc-imx9.c
> +++ b/drivers/soc/imx/soc-imx9.c
> @@ -31,10 +31,8 @@ static int imx9_soc_probe(struct platform_device *pdev)
>  		return -ENOMEM;
>
>  	err = of_property_read_string(of_root, "model", &attr->machine);
> -	if (err) {
> -		pr_err("%s: missing model property: %d\n", __func__, err);
> -		return err;
> -	}
> +	if (err)
> +		return dev_err_probe(dev, err, "%s: missing model property\n", __func__);
>
>  	attr->family = devm_kasprintf(dev, GFP_KERNEL, "Freescale i.MX");
>
> @@ -46,10 +44,8 @@ static int imx9_soc_probe(struct platform_device *pdev)
>  	 * res.a3: uid[63:0];
>  	 */
>  	arm_smccc_smc(IMX_SIP_GET_SOC_INFO, 0, 0, 0, 0, 0, 0, 0, &res);
> -	if (res.a0 != SMCCC_RET_SUCCESS) {
> -		pr_err("%s: SMC failed: 0x%lx\n", __func__, res.a0);
> -		return -EINVAL;
> -	}
> +	if (res.a0 != SMCCC_RET_SUCCESS)
> +		return dev_err_probe(dev, -EINVAL, "%s: SMC failed: 0x%lx\n", __func__, res.a0);
>
>  	soc_id = SOC_ID(res.a1);
>  	rev_major = SOC_REV_MAJOR(res.a1);
> @@ -63,11 +59,9 @@ static int imx9_soc_probe(struct platform_device *pdev)
>  	attr->serial_number = devm_kasprintf(dev, GFP_KERNEL, "%016llx%016llx", uid127_64, uid63_0);
>
>  	sdev = soc_device_register(attr);
> -	if (IS_ERR(sdev)) {
> -		err = PTR_ERR(sdev);
> -		pr_err("%s failed to register SoC as a device: %d\n", __func__, err);
> -		return err;
> -	}
> +	if (IS_ERR(sdev))
> +		return dev_err_probe(dev, PTR_ERR(sdev),
> +				     "%s failed to register SoC as a device\n", __func__);
>
>  	return 0;
>  }
>
> --
> 2.37.1
>


From alexander.stein at ew.tq-group.com  Thu Dec 18 07:44:08 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Thu, 18 Dec 2025 16:44:08 +0100
Subject: [PATCH 6/6] arm64: dts: imx8qm-tqma8qm-mba8x: Disable Cortex-A72 cluster
In-Reply-To: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
References: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
Message-ID: <20251218154412.1524249-2-alexander.stein@ew.tq-group.com>

Due to missing workaround for "ERR050104: Arm/A53: Cache coherency issue"
disable the whole Cortex-A72 cluster.

Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 .../dts/freescale/imx8qm-tqma8qm-mba8x.dts    | 39 -------------------
 .../boot/dts/freescale/imx8qm-tqma8qm.dtsi    | 13 +++++--
 2 files changed, 10 insertions(+), 42 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8qm-tqma8qm-mba8x.dts b/arch/arm64/boot/dts/freescale/imx8qm-tqma8qm-mba8x.dts
index ba19c3c17c496..4a5ab14ddc550 100644
--- a/arch/arm64/boot/dts/freescale/imx8qm-tqma8qm-mba8x.dts
+++ b/arch/arm64/boot/dts/freescale/imx8qm-tqma8qm-mba8x.dts
@@ -296,45 +296,6 @@ map3 {
 				};
 			};
 		};
-
-		cpu1-thermal {
-			trips {
-				soc_active1_0: trip-active0 {
-					temperature = <40000>;
-					hysteresis = <5000>;
-					type = "active";
-				};
-
-				soc_active1_1: trip-active1 {
-					temperature = <48000>;
-					hysteresis = <3000>;
-					type = "active";
-				};
-
-				soc_active1_2: trip-active2 {
-					temperature = <60000>;
-					hysteresis = <10000>;
-					type = "active";
-				};
-			};
-
-			cooling-maps {
-				map1 {
-					trip = <&soc_active1_0>;
-					cooling-device = <&fan0 1 1>;
-				};
-
-				map2 {
-					trip = <&soc_active1_1>;
-					cooling-device = <&fan0 2 2>;
-				};
-
-				map3 {
-					trip = <&soc_active1_2>;
-					cooling-device = <&fan0 3 3>;
-				};
-			};
-		};
 	};
 };
 
diff --git a/arch/arm64/boot/dts/freescale/imx8qm-tqma8qm.dtsi b/arch/arm64/boot/dts/freescale/imx8qm-tqma8qm.dtsi
index 718c792259a65..57d06817aab63 100644
--- a/arch/arm64/boot/dts/freescale/imx8qm-tqma8qm.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8qm-tqma8qm.dtsi
@@ -11,6 +11,13 @@ / {
 	model = "TQ-Systems i.MX8QM TQMa8QM";
 	compatible = "tq,imx8qm-tqma8qm", "fsl,imx8qm";
 
+	/* Due to missing workaround for ERR050104 */
+	cpus {
+		/delete-node/ cpu-map;
+		/delete-node/ cpu at 100;
+		/delete-node/ cpu at 101;
+	};
+
 	memory at 80000000 {
 		device_type = "memory";
 		/*
@@ -171,6 +178,8 @@ &mu2_m0 {
 };
 
 &thermal_zones {
+	/delete-node/ cpu1-thermal;
+
 	pmic0-thermal {
 		polling-delay-passive = <250>;
 		polling-delay = <2000>;
@@ -196,9 +205,7 @@ map0 {
 					<&A53_0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
 					<&A53_1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
 					<&A53_2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-					<&A53_3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-					<&A72_0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-					<&A72_1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+					<&A53_3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
 			};
 		};
 	};
-- 
2.43.0



From Frank.li at nxp.com  Thu Dec 18 07:44:46 2025
From: Frank.li at nxp.com (Frank Li)
Date: Thu, 18 Dec 2025 10:44:46 -0500
Subject: [PATCH 3/3] soc: imx: Spport i.MX9[4,52]
In-Reply-To: <20251217-soc-imx9-fix-v1-3-0c763c2dbe29@nxp.com>
References: <20251217-soc-imx9-fix-v1-0-0c763c2dbe29@nxp.com>
 <20251217-soc-imx9-fix-v1-3-0c763c2dbe29@nxp.com>
Message-ID: <aUQhbjs8WF9cYmPL@lizhi-Precision-Tower-5810>

On Wed, Dec 17, 2025 at 08:42:09PM +0800, Peng Fan (OSS) wrote:
> From: Peng Fan <peng.fan at nxp.com>
>
> Add i.MX9[4,52] machine compatible to allow soc device could be created.
>
> SOC_ID is 16bit format data:
>  - i.MX943: 0x9430
>  - i.MX952: 0x9520
> Update SOC_ID macro to get the accurate data.
>
> Co-developed-by: Jacky Bai <ping.bai at nxp.com>
> Signed-off-by: Jacky Bai <ping.bai at nxp.com>
> Signed-off-by: Peng Fan <peng.fan at nxp.com>
> ---
>  drivers/soc/imx/soc-imx9.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/soc/imx/soc-imx9.c b/drivers/soc/imx/soc-imx9.c
> index d9a686299c5f710bb9988c55ed601fc9d9f19229..d67bc7402b10e2966ff77cbf3b15c087540bd377 100644
> --- a/drivers/soc/imx/soc-imx9.c
> +++ b/drivers/soc/imx/soc-imx9.c
> @@ -12,7 +12,7 @@
>  #include <linux/sys_soc.h>
>
>  #define IMX_SIP_GET_SOC_INFO	0xc2000006
> -#define SOC_ID(x)		(((x) & 0xFFFF) >> 8)
> +#define SOC_ID(x)		(((x) & 0xFF) ? ((x) & 0xFFFF) >> 4 : ((x) & 0xFFFF) >> 8)
>  #define SOC_REV_MAJOR(x)	((((x) >> 28) & 0xF) - 0x9)
>  #define SOC_REV_MINOR(x)	(((x) >> 24) & 0xF)
>
> @@ -68,7 +68,9 @@ static int imx9_soc_probe(struct platform_device *pdev)
>
>  static __maybe_unused const struct of_device_id imx9_soc_match[] = {
>  	{ .compatible = "fsl,imx93", },
> +	{ .compatible = "fsl,imx94", },
>  	{ .compatible = "fsl,imx95", },
> +	{ .compatible = "fsl,imx952", },

Does bind doc already applied?

Frank

>  	{ }
>  };
>
>
> --
> 2.37.1
>


From alexander.stein at ew.tq-group.com  Thu Dec 18 07:44:07 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Thu, 18 Dec 2025 16:44:07 +0100
Subject: [PATCH 5/6] arm64: dts: Add TQ imx8qm based board
In-Reply-To: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
References: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
Message-ID: <20251218154412.1524249-1-alexander.stein@ew.tq-group.com>

* TQMa8QM on MBa8x

Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 arch/arm64/boot/dts/freescale/Makefile        |   1 +
 .../dts/freescale/imx8qm-tqma8qm-mba8x.dts    | 908 ++++++++++++++++++
 .../boot/dts/freescale/imx8qm-tqma8qm.dtsi    | 315 ++++++
 3 files changed, 1224 insertions(+)
 create mode 100644 arch/arm64/boot/dts/freescale/imx8qm-tqma8qm-mba8x.dts
 create mode 100644 arch/arm64/boot/dts/freescale/imx8qm-tqma8qm.dtsi

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index dabc84be0c2e8..72f151a0cccfd 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -344,6 +344,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8qm-apalis-v1.1-eval-v1.2.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8qm-apalis-v1.1-ixora-v1.1.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8qm-apalis-v1.1-ixora-v1.2.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8qm-mek.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8qm-tqma8qm-mba8x.dtb
 
 imx8qm-mek-ov5640-csi0-dtbs := imx8qm-mek.dtb imx8qm-mek-ov5640-csi0.dtbo
 dtb-${CONFIG_ARCH_MXC} += imx8qm-mek-ov5640-csi0.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx8qm-tqma8qm-mba8x.dts b/arch/arm64/boot/dts/freescale/imx8qm-tqma8qm-mba8x.dts
new file mode 100644
index 0000000000000..ba19c3c17c496
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8qm-tqma8qm-mba8x.dts
@@ -0,0 +1,908 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT)
+/*
+ * Copyright (c) 2019-2025 TQ-Systems GmbH <linux at ew.tq-group.com>,
+ * D-82229 Seefeld, Germany.
+ * Author: Alexander Stein
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/net/ti-dp83867.h>
+#include <dt-bindings/pwm/pwm.h>
+
+#include "imx8qm-tqma8qm.dtsi"
+
+/ {
+	model = "TQ-Systems i.MX8QM TQMa8QM on MBa8x";
+	compatible = "tq,imx8qm-tqma8qm-mba8x", "tq,imx8qm-tqma8qm", "fsl,imx8qm";
+
+	aliases {
+		rtc0 = &pcf85063;
+		rtc1 = &rtc;
+	};
+
+	chosen {
+		stdout-path = &lpuart0;
+	};
+
+	adc {
+		compatible = "iio-hwmon";
+		io-channels = <&adc0 0>, <&adc0 1>, <&adc0 2>;
+	};
+
+	clk_xtal25: clk-xtal25 {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <25000000>;
+	};
+
+	fan0: pwm-fan {
+		compatible = "pwm-fan";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_pwmfan>;
+		fan-supply = <&reg_pwm_fan>;
+		#cooling-cells = <2>;
+		/* typical 25 kHz -> 40.000 nsec */
+		pwms = <&lsio_pwm3 0 40000 PWM_POLARITY_INVERTED>;
+		cooling-levels = <0 32 64 128 196 240>;
+		pulses-per-revolution = <2>;
+		interrupt-parent = <&lsio_gpio2>;
+		interrupts = <20 IRQ_TYPE_EDGE_FALLING>;
+		status = "disabled";
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpiokeys>;
+		autorepeat;
+
+		switch-1 {
+			label = "SWITCH_A";
+			linux,code = <BTN_0>;
+			gpios = <&lsio_gpio2 11 GPIO_ACTIVE_LOW>;
+			wakeup-source;
+		};
+
+		switch-2 {
+			label = "SWITCH_B";
+			linux,code = <BTN_1>;
+			gpios = <&lsio_gpio1 0 GPIO_ACTIVE_LOW>;
+			wakeup-source;
+		};
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpioled>;
+
+		user-led0 {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_HEARTBEAT;
+			gpios = <&lsio_gpio5 20 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+
+		user-led1 {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_STATUS;
+			gpios = <&lsio_gpio5 19 GPIO_ACTIVE_HIGH>;
+			default-state = "on";
+		};
+	};
+
+	reg_mba8x_v3v3: regulator-mba8x-v3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "V_3V3_MB";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	reg_mba8x_12v: regulator-mba8x-12v {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_reg_mba8x_12v>;
+		regulator-name = "MBa8x-V12";
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+		enable-active-high;
+		gpio = <&lsio_gpio1 2 GPIO_ACTIVE_HIGH>;
+	};
+
+	reg_pwm_fan: regulator-pwm-fan {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_regpwmfan>;
+		regulator-name = "FAN_PWR";
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+		gpio = <&lsio_gpio2 12 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		vin-supply = <&reg_mba8x_12v>;
+	};
+
+	reg_usb_phy: regulator-usb-phy {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <3000000>;
+		regulator-min-microvolt = <3000000>;
+		regulator-name = "usb-phy-dummy";
+	};
+
+	reg_v1v5_pcie: regulator-v1v5-pcie {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_reg_pcie_v1v5>;
+		regulator-name = "V_1V5_MPCIE";
+		regulator-min-microvolt = <1500000>;
+		regulator-max-microvolt = <1500000>;
+		vin-supply = <&reg_mba8x_v3v3>;
+		enable-active-high;
+		gpio = <&lsio_gpio0 31 GPIO_ACTIVE_HIGH>;
+		regulator-always-on;
+	};
+
+	reg_vref_v1v8: regulator-vref-v1v8 {
+		compatible = "regulator-fixed";
+		regulator-name = "VREF_V1V8";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-always-on;
+	};
+
+	reg_v1v8: regulator-v1v8 {
+		compatible = "regulator-fixed";
+		regulator-name = "MBa8x-V1V8";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-always-on;
+	};
+
+	reg_v3v3_pcie: regulator-v3v3-pcie {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_reg_pcie_v3v3>;
+		regulator-name = "V_3V3_MPCIE";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		vin-supply = <&reg_mba8x_v3v3>;
+		enable-active-high;
+		gpio = <&lsio_gpio1 1 GPIO_ACTIVE_HIGH>;
+		regulator-always-on;
+	};
+
+	reg_v3v3_sd: regulator-v3v3-sd {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_reg_v3v3_sd>;
+		regulator-name = "V3V3_SD";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		vin-supply = <&reg_mba8x_v3v3>;
+		gpio = <&lsio_gpio4 7 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-boot-on;
+		off-on-delay-us = <200000>;
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		decoder_boot: decoder-boot at 84000000 {
+			reg = <0 0x84000000 0 0x2000000>;
+			no-map;
+		};
+
+		encoder1_boot: encoder1-boot at 86000000 {
+			reg = <0 0x86000000 0 0x200000>;
+			no-map;
+		};
+
+		encoder2_boot: encoder2-boot at 86200000 {
+			reg = <0 0x86200000 0 0x200000>;
+			no-map;
+		};
+
+		decoder_rpc: decoder-rpc at 92000000 {
+			reg = <0 0x92000000 0 0x100000>;
+			no-map;
+		};
+
+		encoder1_rpc: encoder1-rpc at 92100000 {
+			reg = <0 0x92100000 0 0x700000>;
+			no-map;
+		};
+
+		encoder2_rpc: encoder1-rpc at 92800000 {
+			reg = <0 0x92800000 0 0x700000>;
+			no-map;
+		};
+
+		/*
+		 * global autoconfigured region for contiguous allocations
+		 * must not exceed memory size and region
+		 */
+		linux,cma {
+			compatible = "shared-dma-pool";
+			reusable;
+			size = <0 0x3c000000>;
+			alloc-ranges = <0 0x96000000 0 0x3c000000>;
+			linux,cma-default;
+		};
+	};
+
+	sound {
+		compatible = "fsl,imx-audio-tlv320aic32x4";
+		model = "tqm-tlv320aic32";
+		ssi-controller = <&sai1>;
+		audio-codec = <&tlv320aic3x04>;
+		audio-routing =
+			"IN3_L", "Mic Jack",
+			"Mic Jack", "Mic Bias",
+			"IN1_L", "Line In Jack",
+			"IN1_R", "Line In Jack",
+			"Line Out Jack", "LOL",
+			"Line Out Jack", "LOR";
+	};
+
+	sound-hdmi {
+		compatible = "fsl,imx-audio-hdmi";
+		model = "imx-audio-dp";
+		audio-cpu = <&sai5>;
+		hdmi-out;
+	};
+
+	thermal-zones {
+		cpu0-thermal {
+			trips {
+				soc_active0_0: trip-active0 {
+					temperature = <40000>;
+					hysteresis = <5000>;
+					type = "active";
+				};
+
+				soc_active0_1: trip-active1 {
+					temperature = <48000>;
+					hysteresis = <3000>;
+					type = "active";
+				};
+
+				soc_active0_2: trip-active2 {
+					temperature = <60000>;
+					hysteresis = <10000>;
+					type = "active";
+				};
+			};
+
+			cooling-maps {
+				map1 {
+					trip = <&soc_active0_0>;
+					cooling-device = <&fan0 1 1>;
+				};
+
+				map2 {
+					trip = <&soc_active0_1>;
+					cooling-device = <&fan0 2 2>;
+				};
+
+				map3 {
+					trip = <&soc_active0_2>;
+					cooling-device = <&fan0 3 3>;
+				};
+			};
+		};
+
+		cpu1-thermal {
+			trips {
+				soc_active1_0: trip-active0 {
+					temperature = <40000>;
+					hysteresis = <5000>;
+					type = "active";
+				};
+
+				soc_active1_1: trip-active1 {
+					temperature = <48000>;
+					hysteresis = <3000>;
+					type = "active";
+				};
+
+				soc_active1_2: trip-active2 {
+					temperature = <60000>;
+					hysteresis = <10000>;
+					type = "active";
+				};
+			};
+
+			cooling-maps {
+				map1 {
+					trip = <&soc_active1_0>;
+					cooling-device = <&fan0 1 1>;
+				};
+
+				map2 {
+					trip = <&soc_active1_1>;
+					cooling-device = <&fan0 2 2>;
+				};
+
+				map3 {
+					trip = <&soc_active1_2>;
+					cooling-device = <&fan0 3 3>;
+				};
+			};
+		};
+	};
+};
+
+&fec1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_fec1>;
+	phy-mode = "rgmii-id";
+	phy-handle = <&ethphy0>;
+	nvmem-cells = <&fec_mac0>;
+	nvmem-cell-names = "mac-address";
+	fsl,magic-packet;
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy0: ethernet-phy at 0 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_ethphy0>;
+			ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
+			ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
+			ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
+			ti,dp83867-rxctrl-strap-quirk;
+			ti,clk-output-sel = <DP83867_CLK_O_SEL_OFF>;
+			reset-gpios = <&lsio_gpio2 6 GPIO_ACTIVE_LOW>;
+			reset-assert-us = <500000>;
+			reset-deassert-us = <50000>;
+			enet-phy-lane-no-swap;
+			interrupt-parent = <&lsio_gpio2>;
+			interrupts = <8 IRQ_TYPE_LEVEL_LOW>;
+		};
+	};
+};
+
+&fec2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_fec2>;
+	phy-mode = "rgmii-id";
+	phy-handle = <&ethphy3>;
+	nvmem-cells = <&fec_mac1>;
+	nvmem-cell-names = "mac-address";
+	fsl,magic-packet;
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy3: ethernet-phy at 3 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <3>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_ethphy3>;
+			ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
+			ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
+			ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
+			ti,dp83867-rxctrl-strap-quirk;
+			ti,clk-output-sel = <DP83867_CLK_O_SEL_OFF>;
+			reset-gpios = <&lsio_gpio2 4 GPIO_ACTIVE_LOW>;
+			reset-assert-us = <500000>;
+			reset-deassert-us = <50000>;
+			enet-phy-lane-no-swap;
+		};
+	};
+};
+
+&flexcan1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_flexcan1>;
+	xceiver-supply = <&reg_mba8x_v3v3>;
+	status = "okay";
+};
+
+&flexcan2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_flexcan2>;
+	xceiver-supply = <&reg_mba8x_v3v3>;
+	status = "okay";
+};
+
+&hsio_phy {
+	fsl,hsio-cfg = "pciea-pcieb-sata";
+	fsl,refclk-pad-mode = "input";
+	status = "okay";
+};
+
+/* no refclock gating */
+&hsio_refa_clk {
+	status = "disabled";
+};
+
+&hsio_refb_clk {
+	status = "disabled";
+};
+
+&i2c1 {
+	tlv320aic3x04: audio-codec at 18 {
+		compatible = "ti,tlv320aic32x4";
+		reg = <0x18>;
+		clocks = <&mclkout0_lpcg IMX_LPCG_CLK_0>;
+		clock-names = "mclk";
+		assigned-clocks = <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_PLL>,
+				<&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_SLV_BUS>,
+				<&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_MST_BUS>,
+				<&mclkout0_lpcg IMX_LPCG_CLK_0>;
+		assigned-clock-rates = <786432000>, <49152000>, <12288000>, <12288000>;
+		ldoin-supply = <&reg_mba8x_v3v3>;
+		iov-supply = <&reg_v1v8>;
+	};
+
+	sensor1: temperature-sensor at 1c {
+		compatible = "nxp,se97b", "jedec,jc-42.4-temp";
+		reg = <0x1c>;
+	};
+
+	eeprom2: eeprom at 54 {
+		compatible = "nxp,se97b", "atmel,24c02";
+		reg = <0x54>;
+		pagesize = <16>;
+		vcc-supply = <&reg_mba8x_v3v3>;
+	};
+
+	pcieclk: clock-generator at 68 {
+		compatible = "renesas,9fgv0441";
+		reg = <0x68>;
+		clocks = <&clk_xtal25>;
+		#clock-cells = <1>;
+		clock-output-names = "DIF0", "DIF1", "DIF2", "DIF3";
+	};
+};
+
+&lpspi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_lpspi0 &pinctrl_lpspi0_cs>;
+	cs-gpios = <&lsio_gpio3 5 GPIO_ACTIVE_LOW>, <&lsio_gpio3 6 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&lpspi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_lpspi1 &pinctrl_lpspi1_cs>;
+	cs-gpios = <&lsio_gpio3 24 GPIO_ACTIVE_LOW>, <&lsio_gpio3 25 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&lpspi2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_lpspi2 &pinctrl_lpspi2_cs>;
+	cs-gpios = <&lsio_gpio3 10 GPIO_ACTIVE_LOW>, <&lsio_gpio3 11 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&lpuart0 { /* console */
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_lpuart0>;
+	status = "okay";
+};
+
+&lpuart1 { /* X62 pin header */
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_lpuart1>;
+	status = "okay";
+};
+
+&lpuart2 { /* mikroBUS */
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_lpuart2>;
+	status = "okay";
+};
+
+&lsio_gpio2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_gpio2>;
+	gpio-line-names = "", "", "", "",
+			  "", "PCIE0_DISABLE#", "", "";
+
+	pcie0-wdisable1-hog {
+		gpio-hog;
+		gpios = <5 0>;
+		output-high;
+		line-name = "PCIE0_DISABLE#";
+	};
+
+	pcie-clk-pd-hog {
+		gpio-hog;
+		gpios = <10 0>;
+		output-high;
+		line-name = "PCIE_CLK_PD#";
+	};
+};
+
+&lsio_pwm3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_lsio_pwm3>;
+	status = "okay";
+};
+
+&pciea {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pciea>;
+	phys = <&hsio_phy 0 PHY_TYPE_PCIE 0>;
+	phy-names = "pcie-phy";
+	reset-gpio = <&lsio_gpio4 29 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&pcieb {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pcieb>;
+	phys = <&hsio_phy 1 PHY_TYPE_PCIE 1>;
+	phy-names = "pcie-phy";
+	reset-gpio = <&lsio_gpio5 0 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&phyx1_lpcg {
+	clocks = <&pcieclk 0>, <&hsio_per_clk>,
+		 <&pcieclk 0>, <&hsio_per_clk>;
+};
+
+&phyx2_lpcg {
+	clocks = <&pcieclk 0>, <&hsio_per_clk>,
+		 <&pcieclk 0>, <&hsio_per_clk>;
+};
+
+&sai1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_sai1>;
+	assigned-clocks = <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_PLL>,
+			  <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_SLV_BUS>,
+			  <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_MST_BUS>,
+			  <&sai1_lpcg IMX_LPCG_CLK_0>;
+	assigned-clock-rates = <786432000>, <49152000>, <12288000>, <49152000>;
+	status = "okay";
+};
+
+&sai5 {
+	status = "okay";
+};
+
+&sai5_lpcg {
+	status = "okay";
+};
+
+&usbphy1 {
+	phy-3p0-supply = <&reg_usb_phy>;
+	status = "okay";
+};
+
+&usbotg1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usbotg1>;
+	srp-disable;
+	hnp-disable;
+	adp-disable;
+	power-active-high;
+	over-current-active-low;
+	dr_mode = "otg";
+	status = "okay";
+};
+
+&usb3_phy {
+	status = "okay";
+};
+
+&usbotg3 {
+	/* over-current disabled by default */
+	status = "okay";
+};
+
+&usbotg3_cdns3 {
+	dr_mode = "host";
+	#address-cells = <1>;
+	#size-cells = <0>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usbhub>;
+	status = "okay";
+
+	hub_2_0: hub at 1 {
+		compatible = "usb451,8142";
+		reg = <1>;
+		peer-hub = <&hub_3_0>;
+		reset-gpios = <&lsio_gpio2 7 GPIO_ACTIVE_LOW>;
+		vdd-supply = <&reg_mba8x_v3v3>;
+	};
+
+	hub_3_0: hub at 2 {
+		compatible = "usb451,8140";
+		reg = <2>;
+		peer-hub = <&hub_2_0>;
+		reset-gpios = <&lsio_gpio2 7 GPIO_ACTIVE_LOW>;
+		vdd-supply = <&reg_mba8x_v3v3>;
+	};
+};
+
+&usdhc2 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+	bus-width = <4>;
+	cd-gpios = <&lsio_gpio5 22 GPIO_ACTIVE_LOW>;
+	wp-gpios = <&lsio_gpio5 21 GPIO_ACTIVE_HIGH>;
+	vmmc-supply = <&reg_v3v3_sd>;
+	no-mmc;
+	no-sdio;
+	status = "okay";
+};
+
+&iomuxc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_gpio>;
+
+	pinctrl_adc0: adc0grp {
+		fsl,pins = <IMX8QM_ADC_IN1_DMA_ADC0_IN1		0x02000060>,
+			   <IMX8QM_ADC_IN2_DMA_ADC0_IN2		0x02000060>;
+	};
+
+	pinctrl_ethphy0: ethphy0grp {
+		fsl,pins = <IMX8QM_ESAI1_SCKR_LSIO_GPIO2_IO06	0x00000041>,
+			   <IMX8QM_ESAI1_TX0_LSIO_GPIO2_IO08	0x00000021>;
+	};
+
+	pinctrl_ethphy3: ethphy3grp {
+		fsl,pins = <IMX8QM_ESAI1_FSR_LSIO_GPIO2_IO04	0x00000041>;
+	};
+
+	pinctrl_fec1: fec1grp {
+		fsl,pins = <IMX8QM_COMP_CTL_GPIO_1V8_3V3_ENET_ENETB_PAD		0x000014a0>,
+			   <IMX8QM_ENET0_MDC_CONN_ENET0_MDC			0x06000041>,
+			   <IMX8QM_ENET0_MDIO_CONN_ENET0_MDIO			0x06000041>,
+			   <IMX8QM_ENET0_RGMII_TX_CTL_CONN_ENET0_RGMII_TX_CTL	0x00000041>,
+			   <IMX8QM_ENET0_RGMII_TXC_CONN_ENET0_RGMII_TXC		0x00000041>,
+			   <IMX8QM_ENET0_RGMII_TXD0_CONN_ENET0_RGMII_TXD0	0x00000041>,
+			   <IMX8QM_ENET0_RGMII_TXD1_CONN_ENET0_RGMII_TXD1	0x00000041>,
+			   <IMX8QM_ENET0_RGMII_TXD2_CONN_ENET0_RGMII_TXD2	0x00000041>,
+			   <IMX8QM_ENET0_RGMII_TXD3_CONN_ENET0_RGMII_TXD3	0x00000041>,
+			   <IMX8QM_ENET0_RGMII_RXC_CONN_ENET0_RGMII_RXC		0x00000040>,
+			   <IMX8QM_ENET0_RGMII_RX_CTL_CONN_ENET0_RGMII_RX_CTL	0x00000040>,
+			   <IMX8QM_ENET0_RGMII_RXD0_CONN_ENET0_RGMII_RXD0	0x00000040>,
+			   <IMX8QM_ENET0_RGMII_RXD1_CONN_ENET0_RGMII_RXD1	0x00000040>,
+			   <IMX8QM_ENET0_RGMII_RXD2_CONN_ENET0_RGMII_RXD2	0x00000040>,
+			   <IMX8QM_ENET0_RGMII_RXD3_CONN_ENET0_RGMII_RXD3	0x00000040>;
+	};
+
+	pinctrl_fec2: fec2grp {
+		fsl,pins = <IMX8QM_COMP_CTL_GPIO_1V8_3V3_ENET_ENETA_PAD		0x000014a0>,
+			   <IMX8QM_ENET1_MDC_CONN_ENET1_MDC			0x06000041>,
+			   <IMX8QM_ENET1_MDIO_CONN_ENET1_MDIO			0x06000041>,
+			   <IMX8QM_ENET1_RGMII_TX_CTL_CONN_ENET1_RGMII_TX_CTL	0x00000041>,
+			   <IMX8QM_ENET1_RGMII_TXC_CONN_ENET1_RGMII_TXC		0x00000041>,
+			   <IMX8QM_ENET1_RGMII_TXD0_CONN_ENET1_RGMII_TXD0	0x00000041>,
+			   <IMX8QM_ENET1_RGMII_TXD1_CONN_ENET1_RGMII_TXD1	0x00000041>,
+			   <IMX8QM_ENET1_RGMII_TXD2_CONN_ENET1_RGMII_TXD2	0x00000041>,
+			   <IMX8QM_ENET1_RGMII_TXD3_CONN_ENET1_RGMII_TXD3	0x00000041>,
+			   <IMX8QM_ENET1_RGMII_RXC_CONN_ENET1_RGMII_RXC		0x00000040>,
+			   <IMX8QM_ENET1_RGMII_RX_CTL_CONN_ENET1_RGMII_RX_CTL	0x00000040>,
+			   <IMX8QM_ENET1_RGMII_RXD0_CONN_ENET1_RGMII_RXD0	0x00000040>,
+			   <IMX8QM_ENET1_RGMII_RXD1_CONN_ENET1_RGMII_RXD1	0x00000040>,
+			   <IMX8QM_ENET1_RGMII_RXD2_CONN_ENET1_RGMII_RXD2	0x00000040>,
+			   <IMX8QM_ENET1_RGMII_RXD3_CONN_ENET1_RGMII_RXD3	0x00000040>;
+	};
+
+	pinctrl_flexcan1: flexcan0grp {
+		fsl,pins = <IMX8QM_FLEXCAN0_TX_DMA_FLEXCAN0_TX	0x00000021>,
+			   <IMX8QM_FLEXCAN0_RX_DMA_FLEXCAN0_RX	0x00000021>;
+	};
+
+	pinctrl_flexcan2: flexcan1grp {
+		fsl,pins = <IMX8QM_FLEXCAN1_TX_DMA_FLEXCAN1_TX	0x00000021>,
+			   <IMX8QM_FLEXCAN1_RX_DMA_FLEXCAN1_RX	0x00000021>;
+	};
+
+	pinctrl_gpio: pingpiogrp {
+		fsl,pins = /* GPIO0_05 on X62:26 */
+			   <IMX8QM_SIM0_GPIO0_00_LSIO_GPIO0_IO05	0x00000021>,
+			   /* GPIO1_14 on X64:21 */
+			   <IMX8QM_LVDS1_I2C1_SCL_LSIO_GPIO1_IO14	0x00000021>,
+			   /* GPIO1_15 on X64:23 */
+			   <IMX8QM_LVDS1_I2C1_SDA_LSIO_GPIO1_IO15	0x00000021>,
+			   /* GPIO2_17 on X63:37 */
+			   <IMX8QM_SPI3_SCK_LSIO_GPIO2_IO17		0x00000021>,
+			   /* GPIO2_21 on X63:39 */
+			   <IMX8QM_SPI3_CS1_LSIO_GPIO2_IO21		0x00000021>,
+			   /* GPIO4_12 on X61:24 */
+			   <IMX8QM_USDHC2_CD_B_LSIO_GPIO4_IO12		0x00000021>,
+			   /* GPIO4_11 on X61:26 */
+			   <IMX8QM_USDHC2_WP_LSIO_GPIO4_IO11		0x00000021>,
+			   /* GPIO4_10 on X61:28 */
+			   <IMX8QM_USDHC2_VSELECT_LSIO_GPIO4_IO10	0x00000021>,
+			   /* GPIO4_09 on X61:30 */
+			   <IMX8QM_USDHC2_RESET_B_LSIO_GPIO4_IO09	0x00000021>,
+			   /* GPIO5_23 on X62:24 */
+			   <IMX8QM_USDHC1_STROBE_LSIO_GPIO5_IO23	0x00000021>,
+			   /* GPIO5_24 on X61:15 */
+			   <IMX8QM_USDHC2_CLK_LSIO_GPIO5_IO24		0x00000021>,
+			   /* GPIO5_25 on X61:17 */
+			   <IMX8QM_USDHC2_CMD_LSIO_GPIO5_IO25		0x00000021>,
+			   /* GPIO5_26 on X61:19 */
+			   <IMX8QM_USDHC2_DATA0_LSIO_GPIO5_IO26		0x00000021>,
+			   /* GPIO5_27 on X61:21 */
+			   <IMX8QM_USDHC2_DATA1_LSIO_GPIO5_IO27		0x00000021>,
+			   /* GPIO5_28 on X61:23 */
+			   <IMX8QM_USDHC2_DATA2_LSIO_GPIO5_IO28		0x00000021>,
+			   /* GPIO5_29 on X61:25 */
+			   <IMX8QM_USDHC2_DATA3_LSIO_GPIO5_IO29		0x00000021>;
+	};
+
+	pinctrl_gpio2: gpio2grp {
+		fsl,pins = <IMX8QM_ESAI1_FST_LSIO_GPIO2_IO05		0x00000021>,
+			   <IMX8QM_ESAI1_TX2_RX3_LSIO_GPIO2_IO10	0x00000021>;
+	};
+
+	pinctrl_gpiokeys: gpiokeysgrp {
+		fsl,pins = <IMX8QM_ESAI1_TX3_RX2_LSIO_GPIO2_IO11	0x00000021>,
+			   <IMX8QM_SCU_GPIO0_04_LSIO_GPIO1_IO00		0x00000021>;
+	};
+
+	pinctrl_gpioled: gpioledgrp {
+		fsl,pins = <IMX8QM_USDHC1_DATA4_LSIO_GPIO5_IO19		0x00000021>,
+			   <IMX8QM_USDHC1_DATA5_LSIO_GPIO5_IO20		0x00000021>;
+	};
+
+	pinctrl_lpspi0: lpspi0grp {
+		fsl,pins = <IMX8QM_SPI0_SCK_DMA_SPI0_SCK		0x0600004d>,
+			   <IMX8QM_SPI0_SDO_DMA_SPI0_SDO		0x0600004d>,
+			   <IMX8QM_SPI0_SDI_DMA_SPI0_SDI		0x0600004d>;
+	};
+
+	pinctrl_lpspi0_cs: lpspi0csgrp {
+		fsl,pins = <IMX8QM_SPI0_CS0_LSIO_GPIO3_IO05		0x00000021>,
+			   <IMX8QM_SPI0_CS1_LSIO_GPIO3_IO06		0x00000021>;
+	};
+
+	pinctrl_lpspi1: lpspi1grp {
+		fsl,pins = <IMX8QM_ADC_IN3_DMA_SPI1_SCK			0x0600004d>,
+			   <IMX8QM_ADC_IN4_DMA_SPI1_SDO			0x0600004d>,
+			   <IMX8QM_ADC_IN5_DMA_SPI1_SDI			0x0600004d>;
+	};
+
+	pinctrl_lpspi1_cs: lpspi1csgrp {
+		fsl,pins = <IMX8QM_ADC_IN6_LSIO_GPIO3_IO24		0x00000021>,
+			   <IMX8QM_ADC_IN7_LSIO_GPIO3_IO25		0x00000021>;
+	};
+
+	pinctrl_lpspi2: lpspi2grp {
+		fsl,pins = <IMX8QM_SPI2_SCK_DMA_SPI2_SCK		0x0600004d>,
+			   <IMX8QM_SPI2_SDO_DMA_SPI2_SDO		0x0600004d>,
+			   <IMX8QM_SPI2_SDI_DMA_SPI2_SDI		0x0600004d>;
+	};
+
+	pinctrl_lpspi2_cs: lpspi2sgrp {
+		fsl,pins = <IMX8QM_SPI2_CS0_LSIO_GPIO3_IO10		0x00000021>,
+			   <IMX8QM_SPI2_CS1_LSIO_GPIO3_IO11		0x00000021>;
+	};
+
+	pinctrl_lpuart0: lpuart0grp {
+		fsl,pins = <IMX8QM_UART0_RX_DMA_UART0_RX		0x06000021>,
+			   <IMX8QM_UART0_TX_DMA_UART0_TX		0x06000021>,
+			   <IMX8QM_UART0_CTS_B_DMA_UART0_CTS_B		0x00000021>,
+			   <IMX8QM_UART0_RTS_B_DMA_UART0_RTS_B		0x00000021>;
+	};
+
+	pinctrl_lpuart1: lpuart1grp {
+		fsl,pins = <IMX8QM_UART1_RX_DMA_UART1_RX		0x06000021>,
+			   <IMX8QM_UART1_TX_DMA_UART1_TX		0x06000021>,
+			   <IMX8QM_UART1_CTS_B_DMA_UART1_CTS_B		0x00000021>,
+			   <IMX8QM_UART1_RTS_B_DMA_UART1_RTS_B		0x00000021>;
+	};
+
+	pinctrl_lpuart2: lpuart2grp {
+		fsl,pins = <IMX8QM_LVDS0_I2C1_SDA_DMA_UART2_RX		0x06000021>,
+			   <IMX8QM_LVDS0_I2C1_SCL_DMA_UART2_TX		0x06000021>;
+	};
+
+	pinctrl_lsio_pwm3: lsiopwm3grp {
+		fsl,pins = <IMX8QM_GPT0_COMPARE_LSIO_PWM3_OUT		0x00000021>;
+	};
+
+	pinctrl_pciea: pcieagrp {
+		fsl,pins = <IMX8QM_PCIE_CTRL0_PERST_B_LSIO_GPIO4_IO29		0x06000021>,
+			   <IMX8QM_PCIE_CTRL0_CLKREQ_B_HSIO_PCIE0_CLKREQ_B	0x06000021>,
+			   <IMX8QM_PCIE_CTRL0_WAKE_B_LSIO_GPIO4_IO28		0x04000021>;
+	};
+
+	pinctrl_pcieb: pciebgrp {
+		fsl,pins = <IMX8QM_PCIE_CTRL1_PERST_B_LSIO_GPIO5_IO00		0x06000021>,
+			   <IMX8QM_PCIE_CTRL1_CLKREQ_B_HSIO_PCIE1_CLKREQ_B	0x06000021>,
+			   <IMX8QM_PCIE_CTRL1_WAKE_B_LSIO_GPIO4_IO31		0x04000021>;
+	};
+
+	pinctrl_pwmfan: pwmfangrp {
+		fsl,pins = <IMX8QM_SPI3_CS0_LSIO_GPIO2_IO20		0x30>;
+	};
+
+	pinctrl_reg_mba8x_12v: mba12vgrp {
+		fsl,pins = <IMX8QM_SCU_GPIO0_06_LSIO_GPIO1_IO02		0x00000021>;
+	};
+
+	pinctrl_reg_pcie_v1v5: regpcie1v5grp {
+		fsl,pins = <IMX8QM_SCU_GPIO0_03_LSIO_GPIO0_IO31		0x00000021>;
+	};
+
+	pinctrl_reg_pcie_v3v3: regpcie3v3grp {
+		fsl,pins = <IMX8QM_SCU_GPIO0_05_LSIO_GPIO1_IO01		0x00000021>;
+	};
+
+	pinctrl_regpwmfan: regpwmfangrp {
+		fsl,pins = <IMX8QM_ESAI1_TX4_RX1_LSIO_GPIO2_IO12	0x00000021>;
+	};
+
+	pinctrl_reg_v3v3_sd: reg3v3sdgrp {
+		fsl,pins = <IMX8QM_USDHC1_RESET_B_LSIO_GPIO4_IO07	0x00000021>;
+	};
+
+	pinctrl_sai1: sai1grp {
+		fsl,pins = <IMX8QM_SAI1_RXD_AUD_SAI1_RXD		0x06000041>,
+			   <IMX8QM_SAI1_RXC_AUD_SAI1_RXC		0x06000041>,
+			   <IMX8QM_SAI1_RXFS_AUD_SAI1_RXFS		0x06000041>,
+			   <IMX8QM_SAI1_TXD_AUD_SAI1_TXD		0x06000061>,
+			   <IMX8QM_SAI1_TXC_AUD_SAI1_TXC		0x06000041>,
+			   <IMX8QM_MCLK_OUT0_AUD_ACM_MCLK_OUT0		0x0600004d>;
+	};
+
+	pinctrl_usbotg1: usbotg1grp {
+		fsl,pins = <IMX8QM_USB_SS3_TC2_CONN_USB_OTG1_OC		0x00000021>,
+			   <IMX8QM_USB_SS3_TC0_CONN_USB_OTG1_PWR	0x00000021>;
+	};
+
+	pinctrl_usbhub: usbhubgrp {
+		fsl,pins = <IMX8QM_ESAI1_SCKT_LSIO_GPIO2_IO07		0x00000021>;
+	};
+
+	pinctrl_usdhc2_gpio: usdhc2-gpiogrp {
+		fsl,pins = <IMX8QM_USDHC1_DATA6_LSIO_GPIO5_IO21		0x00000021>,
+			   <IMX8QM_USDHC1_DATA7_LSIO_GPIO5_IO22		0x00000021>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <IMX8QM_USDHC1_CLK_CONN_USDHC1_CLK		0x06000041>,
+			   <IMX8QM_USDHC1_CMD_CONN_USDHC1_CMD		0x00000021>,
+			   <IMX8QM_USDHC1_DATA0_CONN_USDHC1_DATA0	0x00000021>,
+			   <IMX8QM_USDHC1_DATA1_CONN_USDHC1_DATA1	0x00000021>,
+			   <IMX8QM_USDHC1_DATA2_CONN_USDHC1_DATA2	0x00000021>,
+			   <IMX8QM_USDHC1_DATA3_CONN_USDHC1_DATA3	0x00000021>,
+			   <IMX8QM_USDHC1_VSELECT_CONN_USDHC1_VSELECT	0x00000021>;
+	};
+
+	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+		fsl,pins = <IMX8QM_USDHC1_CLK_CONN_USDHC1_CLK		0x06000041>,
+			   <IMX8QM_USDHC1_CMD_CONN_USDHC1_CMD		0x00000021>,
+			   <IMX8QM_USDHC1_DATA0_CONN_USDHC1_DATA0	0x00000021>,
+			   <IMX8QM_USDHC1_DATA1_CONN_USDHC1_DATA1	0x00000021>,
+			   <IMX8QM_USDHC1_DATA2_CONN_USDHC1_DATA2	0x00000021>,
+			   <IMX8QM_USDHC1_DATA3_CONN_USDHC1_DATA3	0x00000021>,
+			   <IMX8QM_USDHC1_VSELECT_CONN_USDHC1_VSELECT	0x00000021>;
+	};
+
+	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+		fsl,pins = <IMX8QM_USDHC1_CLK_CONN_USDHC1_CLK		0x06000041>,
+			   <IMX8QM_USDHC1_CMD_CONN_USDHC1_CMD		0x00000021>,
+			   <IMX8QM_USDHC1_DATA0_CONN_USDHC1_DATA0	0x00000021>,
+			   <IMX8QM_USDHC1_DATA1_CONN_USDHC1_DATA1	0x00000021>,
+			   <IMX8QM_USDHC1_DATA2_CONN_USDHC1_DATA2	0x00000021>,
+			   <IMX8QM_USDHC1_DATA3_CONN_USDHC1_DATA3	0x00000021>,
+			   <IMX8QM_USDHC1_VSELECT_CONN_USDHC1_VSELECT	0x00000021>;
+	};
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8qm-tqma8qm.dtsi b/arch/arm64/boot/dts/freescale/imx8qm-tqma8qm.dtsi
new file mode 100644
index 0000000000000..718c792259a65
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8qm-tqma8qm.dtsi
@@ -0,0 +1,315 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT)
+/*
+ * Copyright (c) 2019-2025 TQ-Systems GmbH <linux at ew.tq-group.com>,
+ * D-82229 Seefeld, Germany.
+ * Author: Alexander Stein
+ */
+
+#include "imx8qm.dtsi"
+
+/ {
+	model = "TQ-Systems i.MX8QM TQMa8QM";
+	compatible = "tq,imx8qm-tqma8qm", "fsl,imx8qm";
+
+	memory at 80000000 {
+		device_type = "memory";
+		/*
+		 * DRAM base addr, size : 1024 MiB DRAM
+		 * should be corrected by bootloader
+		 */
+		reg = <0x00000000 0x80000000 0 0x40000000>;
+	};
+
+	reg_tqma8x_v3v3: regulator-tqma8x-v3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "V_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	/* SW7 controlled by SCU */
+	reg_1v8_io1: regulator-v1v8-io1 {
+		compatible = "regulator-fixed";
+		regulator-name = "V_1V8_IO1";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-always-on;
+	};
+
+	/* LDO4 controlled by SCU */
+	reg_3v3_emmc: regulator-v3v3-emmc {
+		compatible = "regulator-fixed";
+		regulator-name = "V_3V3_EMMC";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+};
+
+&acm {
+	status = "okay";
+};
+
+&adc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_adc0>;
+	vref-supply = <&reg_vref_v1v8>;
+	status = "okay";
+};
+
+/* TQMa8QM only uses industrial grade, reduce trip points accordingly */
+&cpu_alert0 {
+	temperature = <95000>;
+};
+
+&cpu_crit0 {
+	temperature = <100000>;
+};
+
+&cpu_alert1 {
+	temperature = <95000>;
+};
+
+&cpu_crit1 {
+	temperature = <100000>;
+};
+
+&gpu_alert0 {
+	temperature = <95000>;
+};
+
+&gpu_crit0 {
+	temperature = <100000>;
+};
+
+&gpu_alert1 {
+	temperature = <95000>;
+};
+
+&gpu_crit1 {
+	temperature = <100000>;
+};
+
+&drc_alert0 {
+	temperature = <95000>;
+};
+
+&drc_crit0 {
+	temperature = <100000>;
+};
+/* end of temperature grade adjustments */
+
+&flexspi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_flexspi0>;
+	status = "okay";
+
+	flash0: flash at 0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <66000000>;
+		spi-tx-bus-width = <4>;
+		spi-rx-bus-width = <4>;
+		vcc-supply = <&reg_1v8_io1>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+		};
+	};
+};
+
+&i2c1 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default", "gpio";
+	pinctrl-0 = <&pinctrl_lpi2c1>;
+	pinctrl-1 = <&pinctrl_lpi2c1gpio>;
+	scl-gpios = <&lsio_gpio0 14 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	sda-gpios = <&lsio_gpio0 15 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	status = "okay";
+
+	/* NXP SE97BTP with temperature sensor + eeprom */
+	se97: temperature-sensor at 1b {
+		compatible = "nxp,se97b", "jedec,jc-42.4-temp";
+		reg = <0x1b>;
+	};
+
+	pcf85063: rtc at 51 {
+		compatible = "nxp,pcf85063a";
+		reg = <0x51>;
+		quartz-load-femtofarads = <7000>;
+	};
+
+	at24c02: eeprom at 53 {
+		compatible = "nxp,se97b", "atmel,24c02";
+		reg = <0x53>;
+		pagesize = <16>;
+		read-only;
+		vcc-supply = <&reg_tqma8x_v3v3>;
+	};
+
+	m24c64: eeprom at 57 {
+		compatible = "atmel,24c64";
+		reg = <0x57>;
+		pagesize = <32>;
+		vcc-supply = <&reg_tqma8x_v3v3>;
+	};
+};
+
+&mu_m0 {
+	status = "okay";
+};
+
+&mu1_m0 {
+	status = "okay";
+};
+
+&mu2_m0 {
+	status = "okay";
+};
+
+&thermal_zones {
+	pmic0-thermal {
+		polling-delay-passive = <250>;
+		polling-delay = <2000>;
+		thermal-sensors = <&tsens IMX_SC_R_PMIC_0>;
+
+		trips {
+			pmic_alert0: trip0 {
+				temperature = <110000>;
+				hysteresis = <2000>;
+				type = "passive";
+			};
+			pmic_crit0: trip1 {
+				temperature = <125000>;
+				hysteresis = <2000>;
+				type = "critical";
+			};
+		};
+
+		cooling-maps {
+			map0 {
+				trip = <&pmic_alert0>;
+				cooling-device =
+					<&A53_0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+					<&A53_1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+					<&A53_2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+					<&A53_3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+					<&A72_0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+					<&A72_1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+			};
+		};
+	};
+};
+
+&usdhc1 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc1>;
+	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
+	bus-width = <8>;
+	vmmc-supply = <&reg_3v3_emmc>;
+	vqmmc-supply = <&reg_1v8_io1>;
+	no-sd;
+	no-sdio;
+	non-removable;
+	status = "okay";
+};
+
+&vpu {
+	compatible = "nxp,imx8qm-vpu";
+	status = "okay";
+};
+
+&vpu_core0 {
+	memory-region = <&decoder_boot>, <&decoder_rpc>;
+	status = "okay";
+};
+
+&vpu_core1 {
+	memory-region = <&encoder1_boot>, <&encoder1_rpc>;
+	status = "okay";
+};
+
+&vpu_core2 {
+	memory-region = <&encoder2_boot>, <&encoder2_rpc>;
+	status = "okay";
+};
+
+&iomuxc {
+	pinctrl_lpi2c1: lpi2c1grp {
+		fsl,pins = <IMX8QM_GPT0_CAPTURE_DMA_I2C1_SDA	0x0600004d>,
+			   <IMX8QM_GPT0_CLK_DMA_I2C1_SCL	0x0600004d>;
+	};
+
+	pinctrl_lpi2c1gpio: lpi2c1gpiogrp {
+		fsl,pins = <IMX8QM_GPT0_CAPTURE_LSIO_GPIO0_IO15	0x0600004d>,
+			   <IMX8QM_GPT0_CLK_LSIO_GPIO0_IO14	0x0600004d>;
+	};
+
+	pinctrl_usdhc1: usdhc1grp {
+		fsl,pins = <IMX8QM_EMMC0_CLK_CONN_EMMC0_CLK		0x06000041>,
+			   <IMX8QM_EMMC0_CMD_CONN_EMMC0_CMD		0x00000021>,
+			   <IMX8QM_EMMC0_DATA0_CONN_EMMC0_DATA0		0x00000021>,
+			   <IMX8QM_EMMC0_DATA1_CONN_EMMC0_DATA1		0x00000021>,
+			   <IMX8QM_EMMC0_DATA2_CONN_EMMC0_DATA2		0x00000021>,
+			   <IMX8QM_EMMC0_DATA3_CONN_EMMC0_DATA3		0x00000021>,
+			   <IMX8QM_EMMC0_DATA4_CONN_EMMC0_DATA4		0x00000021>,
+			   <IMX8QM_EMMC0_DATA5_CONN_EMMC0_DATA5		0x00000021>,
+			   <IMX8QM_EMMC0_DATA6_CONN_EMMC0_DATA6		0x00000021>,
+			   <IMX8QM_EMMC0_DATA7_CONN_EMMC0_DATA7		0x00000021>,
+			   <IMX8QM_EMMC0_STROBE_CONN_EMMC0_STROBE	0x00000041>,
+			   <IMX8QM_EMMC0_RESET_B_CONN_EMMC0_RESET_B	0x00000021>;
+	};
+
+	pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp {
+		fsl,pins = <IMX8QM_EMMC0_CLK_CONN_EMMC0_CLK		0x06000040>,
+			   <IMX8QM_EMMC0_CMD_CONN_EMMC0_CMD		0x00000021>,
+			   <IMX8QM_EMMC0_DATA0_CONN_EMMC0_DATA0		0x00000021>,
+			   <IMX8QM_EMMC0_DATA1_CONN_EMMC0_DATA1		0x00000021>,
+			   <IMX8QM_EMMC0_DATA2_CONN_EMMC0_DATA2		0x00000021>,
+			   <IMX8QM_EMMC0_DATA3_CONN_EMMC0_DATA3		0x00000021>,
+			   <IMX8QM_EMMC0_DATA4_CONN_EMMC0_DATA4		0x00000021>,
+			   <IMX8QM_EMMC0_DATA5_CONN_EMMC0_DATA5		0x00000021>,
+			   <IMX8QM_EMMC0_DATA6_CONN_EMMC0_DATA6		0x00000021>,
+			   <IMX8QM_EMMC0_DATA7_CONN_EMMC0_DATA7		0x00000021>,
+			   <IMX8QM_EMMC0_STROBE_CONN_EMMC0_STROBE	0x00000041>,
+			   <IMX8QM_EMMC0_RESET_B_CONN_EMMC0_RESET_B	0x00000021>;
+	};
+
+	pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp {
+		fsl,pins = <IMX8QM_EMMC0_CLK_CONN_EMMC0_CLK		0x06000040>,
+			   <IMX8QM_EMMC0_CMD_CONN_EMMC0_CMD		0x00000021>,
+			   <IMX8QM_EMMC0_DATA0_CONN_EMMC0_DATA0		0x00000021>,
+			   <IMX8QM_EMMC0_DATA1_CONN_EMMC0_DATA1		0x00000021>,
+			   <IMX8QM_EMMC0_DATA2_CONN_EMMC0_DATA2		0x00000021>,
+			   <IMX8QM_EMMC0_DATA3_CONN_EMMC0_DATA3		0x00000021>,
+			   <IMX8QM_EMMC0_DATA4_CONN_EMMC0_DATA4		0x00000021>,
+			   <IMX8QM_EMMC0_DATA5_CONN_EMMC0_DATA5		0x00000021>,
+			   <IMX8QM_EMMC0_DATA6_CONN_EMMC0_DATA6		0x00000021>,
+			   <IMX8QM_EMMC0_DATA7_CONN_EMMC0_DATA7		0x00000021>,
+			   <IMX8QM_EMMC0_STROBE_CONN_EMMC0_STROBE	0x00000041>,
+			   <IMX8QM_EMMC0_RESET_B_CONN_EMMC0_RESET_B	0x00000021>;
+	};
+
+	pinctrl_flexspi0: flexspi0grp {
+		fsl,pins = <IMX8QM_QSPI0A_DATA0_LSIO_QSPI0A_DATA0	0x0000004d>,
+			   <IMX8QM_QSPI0A_DATA1_LSIO_QSPI0A_DATA1	0x0000004d>,
+			   <IMX8QM_QSPI0A_DATA2_LSIO_QSPI0A_DATA2	0x0000004d>,
+			   <IMX8QM_QSPI0A_DATA3_LSIO_QSPI0A_DATA3	0x0000004d>,
+			   <IMX8QM_QSPI0A_DQS_LSIO_QSPI0A_DQS		0x0000004d>,
+			   <IMX8QM_QSPI0A_SS0_B_LSIO_QSPI0A_SS0_B	0x0000004d>,
+			   <IMX8QM_QSPI0A_SS1_B_LSIO_QSPI0A_SS1_B	0x0000004d>,
+			   <IMX8QM_QSPI0A_SCLK_LSIO_QSPI0A_SCLK		0x0000004d>,
+			   <IMX8QM_QSPI0B_SCLK_LSIO_QSPI0B_SCLK		0x0000004d>,
+			   <IMX8QM_QSPI0B_DATA0_LSIO_QSPI0B_DATA0	0x0000004d>,
+			   <IMX8QM_QSPI0B_DATA1_LSIO_QSPI0B_DATA1	0x0000004d>,
+			   <IMX8QM_QSPI0B_DATA2_LSIO_QSPI0B_DATA2	0x0000004d>,
+			   <IMX8QM_QSPI0B_DATA3_LSIO_QSPI0B_DATA3	0x0000004d>,
+			   <IMX8QM_QSPI0B_DQS_LSIO_QSPI0B_DQS		0x0000004d>,
+			   <IMX8QM_QSPI0B_SS0_B_LSIO_QSPI0B_SS0_B	0x0000004d>,
+			   <IMX8QM_QSPI0B_SS1_B_LSIO_QSPI0B_SS1_B	0x0000004d>;
+	};
+};
-- 
2.43.0



From linu.cherian at arm.com  Thu Dec 18 07:47:39 2025
From: linu.cherian at arm.com (Linu Cherian)
Date: Thu, 18 Dec 2025 21:17:39 +0530
Subject: [PATCH v1 03/13] arm64: mm: Implicitly invalidate user ASID
 based on TLBI operation
In-Reply-To: <aUOnxYvmXwOJL4yU@a079125.arm.com>
References: <20251216144601.2106412-1-ryan.roberts@arm.com>
 <20251216144601.2106412-4-ryan.roberts@arm.com>
 <aUOfnXnGVROEXH4r@a079125.arm.com>
 <aUOnxYvmXwOJL4yU@a079125.arm.com>
Message-ID: <aUQiG_GYHCkZoPZA@a079125.arm.com>



On Thu, Dec 18, 2025 at 12:35:41PM +0530, Linu Cherian wrote:
> 
> 
> On Thu, Dec 18, 2025 at 12:00:57PM +0530, Linu Cherian wrote:
> > Ryan,
> > 
> > On Tue, Dec 16, 2025 at 02:45:48PM +0000, Ryan Roberts wrote:
> > > When kpti is enabled, separate ASIDs are used for userspace and
> > > kernelspace, requiring ASID-qualified TLB invalidation by virtual
> > > address to invalidate both of them.
> > > 
> > > Push the logic for invalidating the two ASIDs down into the low-level
> > > tlbi-op-specific functions and remove the burden from the caller to
> > > handle the kpti-specific behaviour.
> > > 
> > > Co-developed-by: Will Deacon <will at kernel.org>
> > > Signed-off-by: Will Deacon <will at kernel.org>
> > > Signed-off-by: Ryan Roberts <ryan.roberts at arm.com>
> > > ---
> > >  arch/arm64/include/asm/tlbflush.h | 27 ++++++++++-----------------
> > >  1 file changed, 10 insertions(+), 17 deletions(-)
> > > 
> > > diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
> > > index c5111d2afc66..31f43d953ce2 100644
> > > --- a/arch/arm64/include/asm/tlbflush.h
> > > +++ b/arch/arm64/include/asm/tlbflush.h
> > > @@ -110,6 +110,7 @@ typedef void (*tlbi_op)(u64 arg);
> > >  static __always_inline void vae1is(u64 arg)
> > >  {
> > >  	__tlbi(vae1is, arg);
> > > +	__tlbi_user(vae1is, arg);
> > >  }
> > >  
> > >  static __always_inline void vae2is(u64 arg)
> > > @@ -126,6 +127,7 @@ static __always_inline void vale1(u64 arg)
> > >  static __always_inline void vale1is(u64 arg)
> > >  {
> > >  	__tlbi(vale1is, arg);
> > > +	__tlbi_user(vale1is, arg);
> > >  }
> > >  
> > >  static __always_inline void vale2is(u64 arg)
> > > @@ -162,11 +164,6 @@ static __always_inline void __tlbi_level(tlbi_op op, u64 addr, u32 level)
> > >  	op(arg);
> > >  }
> > >  
> > > -#define __tlbi_user_level(op, arg, level) do {				\
> > > -	if (arm64_kernel_unmapped_at_el0())				\
> > > -		__tlbi_level(op, (arg | USER_ASID_FLAG), level);	\
> > > -} while (0)
> > > -
> > >  /*
> > >   * This macro creates a properly formatted VA operand for the TLB RANGE. The
> > >   * value bit assignments are:
> > > @@ -435,8 +432,6 @@ static inline void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch)
> > >   * @stride:	Flush granularity
> > >   * @asid:	The ASID of the task (0 for IPA instructions)
> > >   * @tlb_level:	Translation Table level hint, if known
> > > - * @tlbi_user:	If 'true', call an additional __tlbi_user()
> > > - *              (typically for user ASIDs). 'flase' for IPA instructions
> > >   * @lpa2:	If 'true', the lpa2 scheme is used as set out below
> > >   *
> > >   * When the CPU does not support TLB range operations, flush the TLB
> > > @@ -462,6 +457,7 @@ static inline void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch)
> > >  static __always_inline void rvae1is(u64 arg)
> > >  {
> > >  	__tlbi(rvae1is, arg);
> > > +	__tlbi_user(rvae1is, arg);
> > >  }
> > >  
> > >  static __always_inline void rvale1(u64 arg)
> > > @@ -473,6 +469,7 @@ static __always_inline void rvale1(u64 arg)
> > >  static __always_inline void rvale1is(u64 arg)
> > >  {
> > >  	__tlbi(rvale1is, arg);
> > > +	__tlbi_user(rvale1is, arg);
> > >  }
> > >  
> > >  static __always_inline void rvaale1is(u64 arg)
> > > @@ -491,7 +488,7 @@ static __always_inline void __tlbi_range(tlbi_op op, u64 arg)
> > >  }
> > >  
> > >  #define __flush_tlb_range_op(op, start, pages, stride,			\
> > > -				asid, tlb_level, tlbi_user, lpa2)	\
> > > +				asid, tlb_level, lpa2)			\
> > >  do {									\
> > >  	typeof(start) __flush_start = start;				\
> > >  	typeof(pages) __flush_pages = pages;				\
> > > @@ -506,8 +503,6 @@ do {									\
> > >  		    (lpa2 && __flush_start != ALIGN(__flush_start, SZ_64K))) {	\
> > >  			addr = __TLBI_VADDR(__flush_start, asid);	\
> > >  			__tlbi_level(op, addr, tlb_level);		\
> > > -			if (tlbi_user)					\
> > > -				__tlbi_user_level(op, addr, tlb_level);	\
> > >  			__flush_start += stride;			\
> > >  			__flush_pages -= stride >> PAGE_SHIFT;		\
> > >  			continue;					\
> > > @@ -518,8 +513,6 @@ do {									\
> > >  			addr = __TLBI_VADDR_RANGE(__flush_start >> shift, asid, \
> > >  						scale, num, tlb_level);	\
> > >  			__tlbi_range(r##op, addr);			\
> > > -			if (tlbi_user)					\
> > > -				__tlbi_user(r##op, addr);		\
> > >  			__flush_start += __TLBI_RANGE_PAGES(num, scale) << PAGE_SHIFT; \
> > >  			__flush_pages -= __TLBI_RANGE_PAGES(num, scale);\
> > 
> > 
> > There are more __tlbi_user invocations in __flush_tlb_mm, __local_flush_tlb_page_nonotify_nosync
> > and __flush_tlb_page_nosync in this file. Should we not address them as well as 
> > part of this ?
> > 
> 
> I see that except __flush_tlb_mm, the others got addressed in subsequent patches.
> Should we hint this in the commit message ?

Please ignore this comment, somehow the commit message gave me an impression that
all the invocations of __tlbi_user is going to get updated.




From festevam at gmail.com  Thu Dec 18 07:47:33 2025
From: festevam at gmail.com (Fabio Estevam)
Date: Thu, 18 Dec 2025 12:47:33 -0300
Subject: [PATCH 5/6] arm64: dts: Add TQ imx8qm based board
In-Reply-To: <20251218154412.1524249-1-alexander.stein@ew.tq-group.com>
References: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com> <20251218154412.1524249-1-alexander.stein@ew.tq-group.com>
Message-ID: <CAOMZO5CmP_rdFA=PqGSmKDU+ObzifHFDjwYMD3J67bjs0h_sfw@mail.gmail.com>

On Thu, Dec 18, 2025 at 12:45?PM Alexander Stein
<alexander.stein at ew.tq-group.com> wrote:
>
> * TQMa8QM on MBa8x

This commit log should be improved by explaining the SoM and base
board in more detail, providing a URL, etc.


From andreas at kemnade.info  Thu Dec 18 07:46:20 2025
From: andreas at kemnade.info (Andreas Kemnade)
Date: Thu, 18 Dec 2025 16:46:20 +0100
Subject: [PATCH v2 03/20] drm/tilcdc: Remove simulate_vesa_sync flag
In-Reply-To: <DF0K3BRQKOSI.10X5SMXI1YM60@bootlin.com>
References: <20251211-feature_tilcdc-v2-0-f48bac3cd33e@bootlin.com>
	<20251211-feature_tilcdc-v2-3-f48bac3cd33e@bootlin.com>
	<DF0K3BRQKOSI.10X5SMXI1YM60@bootlin.com>
Message-ID: <20251218164620.40c0599d@kemnade.info>

On Wed, 17 Dec 2025 15:20:09 +0100
"Luca Ceresoli" <luca.ceresoli at bootlin.com> wrote:

[...]
> > Signed-off-by: Kory Maincent (TI.com) <kory.maincent at bootlin.com>  
> 
> Code looks good. Based on your testing, which covered both boards currently
> setting simulate_vesa_sync and boards not setting it:
> 
> Reviewed-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
> 
> Still it would be good to have this series, and especially this patch,
> tested by someone having access to other TI boards.
> 
Just that I do not mix up anything:

grep tilcdc only gives:

am335x-base0033.dts:		compatible = "ti,tilcdc,slave";
am335x-guardian.dts:		compatible = "ti,tilcdc,panel";
am335x-pdu001.dts:		compatible = "ti,tilcdc,panel";
am335x-pepper.dts:		compatible = "ti,tilcdc,panel";
am335x-sbc-t335.dts:		compatible = "ti,tilcdc,panel";
am335x-sl50.dts:		compatible = "ti,tilcdc,panel";
am33xx-l4.dtsi:				compatible = "ti,am33xx-tilcdc";

so only am33xx affected? And no omap3/4/5. So apparently nothing
I can test.
@Roger: I suspect you have more of these boards than me.

Regards,
Andreas


From krzk at kernel.org  Thu Dec 18 07:49:19 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 18 Dec 2025 16:49:19 +0100
Subject: [PATCH 1/6] dt-bindings: clk: rs9: add clock-output-names
 property
In-Reply-To: <CAMuHMdWEJ-eYwUTnotsTVEtKrujYVsEB4kFVjRYh3wXZvyjfGQ@mail.gmail.com>
References: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
 <20251218152058.1521806-2-alexander.stein@ew.tq-group.com>
 <CAMuHMdWEJ-eYwUTnotsTVEtKrujYVsEB4kFVjRYh3wXZvyjfGQ@mail.gmail.com>
Message-ID: <5f375fff-a371-4674-ad4a-64127e2a4a79@kernel.org>

On 18/12/2025 16:26, Geert Uytterhoeven wrote:
> Hi Alexander,
> 
> On Thu, 18 Dec 2025 at 16:21, Alexander Stein
> <alexander.stein at ew.tq-group.com> wrote:
>> Add "clock-output-names" which is a standard property for clock
>> providers.
> 
> Why? Isn't that property sort of deprecated?
> 
> Will be replying to the cover letter next...
> 

Yeah, the name is pretty pointless here and its presence in several
drivers is legacy and incorrect choice.

Best regards,
Krzysztof


From gregkh at linuxfoundation.org  Thu Dec 18 07:49:31 2025
From: gregkh at linuxfoundation.org (Greg Kroah-Hartman)
Date: Thu, 18 Dec 2025 16:49:31 +0100
Subject: [PATCH 5/6] arm64: dts: Add TQ imx8qm based board
In-Reply-To: <20251218154412.1524249-1-alexander.stein@ew.tq-group.com>
References: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
 <20251218154412.1524249-1-alexander.stein@ew.tq-group.com>
Message-ID: <2025121810-tactless-pegboard-feb5@gregkh>

On Thu, Dec 18, 2025 at 04:44:07PM +0100, Alexander Stein wrote:
> * TQMa8QM on MBa8x

I do not understand this changelog text at all, sorry.

Please be more verbose.

thanks,

greg k-h


From ben.horgan at arm.com  Thu Dec 18 07:54:48 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Thu, 18 Dec 2025 15:54:48 +0000
Subject: [RFC PATCH 01/38] arm64: mpam: Context switch the MPAM registers
In-Reply-To: <20251218153805.000073b9@huawei.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-2-james.morse@arm.com>
 <20251218103546.000070fd@huawei.com>
 <a1786f34-66b8-4620-b619-79e6013882e4@arm.com>
 <c205297d-0f6e-4238-bd6a-3cab498c6a45@arm.com>
 <20251218153805.000073b9@huawei.com>
Message-ID: <ab557985-7c1d-4536-b7f7-fe7dba4f6ccc@arm.com>



On 12/18/25 15:38, Jonathan Cameron wrote:
> On Thu, 18 Dec 2025 14:55:23 +0000
> Ben Horgan <ben.horgan at arm.com> wrote:
> 
>> On 12/18/25 14:52, Ben Horgan wrote:
>>> Hi Jonathan,
>>>
>>> On 12/18/25 10:35, Jonathan Cameron wrote:  
>>>> On Fri, 5 Dec 2025 21:58:24 +0000
>>>> James Morse <james.morse at arm.com> wrote:
>>>>  
>>>>> MPAM allows traffic in the SoC to be labeled by the OS, these labels
>>>>> are used to apply policy in caches and bandwidth regulators, and to
>>>>> monitor traffic in the SoC. The label is made up of a PARTID and PMG
>>>>> value. The x86 equivalent calls these CLOSID and RMID, but they don't
>>>>> map precisely.
>>>>>
>>>>> MPAM has two CPU system registers that is used to hold the PARTID and PMG
>>>>> values that traffic generated at each exception level will use. These can be
>>>>> set per-task by the resctrl file system. (resctrl is the defacto interface
>>>>> for controlling this stuff).
>>>>>
>>>>> Add a helper to switch this.
>>>>>
>>>>> struct task_struct's separate CLOSID and RMID fields are insufficient
>>>>> to implement resctrl using MPAM, as resctrl can change the PARTID (CLOSID)
>>>>> and PMG (sort of like the RMID) separately. On x86, the rmid is an
>>>>> independent number, so a race that writes a mismatched  closid and rmid
>>>>> into hardware is benign. On arm64, the pmg bits extend the partid.
>>>>> (i.e. partid-5 has a pmg-0 that is not the same as partid-6's pmg-0).
>>>>> In this case, mismatching the values will 'dirty' a pmg value that
>>>>> resctrl believes is clean, and is not tracking with its 'limbo' code.
>>>>>
>>>>> To avoid this, the partid and pmg are always read and written as a pair.
>>>>> Instead of making struct task_struct's closid and rmid fields an
>>>>> endian-unsafe union, add the value to struct thread_info and always use
>>>>> READ_ONCE()/WRITE_ONCE() when accessing this field.
>>>>>
>>>>> Resctrl allows a per-cpu 'default' value to be set, this overrides the
>>>>> values when scheduling a task in the default control-group, which has
>>>>> PARTID 0. The way 'code data prioritisation' gets emulated means the
>>>>> register value for the default group needs to be a variable.
>>>>>
>>>>> The current system register value is kept in a per-cpu variable to
>>>>> avoid writing to the system register if the value isn't going to change.
>>>>> Writes to this register may reset the hardware state for regulating
>>>>> bandwidth.
>>>>>
>>>>> Finally, there is no reason to context switch these registers unless
>>>>> there is a driver changing the values in struct task_struct. Hide
>>>>> the whole thing behind a static key. This also allows the driver to
>>>>> disable MPAM in response to errors reported by hardware. Move the
>>>>> existing static key to belong to the arch code, as in the future
>>>>> the MPAM driver may become a loadable module.
>>>>>
>>>>> All this should depend on whether there is an MPAM driver, hide
>>>>> it behind CONFIG_MPAM.
>>>>>
>>>>> CC: Amit Singh Tomar <amitsinght at marvell.com>
>>>>> Signed-off-by: James Morse <james.morse at arm.com>  
>>>>  
>>>>> diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/mpam.h
>>>>> new file mode 100644
>>>>> index 000000000000..86a55176f884
>>>>> --- /dev/null
>>>>> +++ b/arch/arm64/include/asm/mpam.h
>>>>> @@ -0,0 +1,74 @@  
>>>> ...
>>>>  
>>>>> +/*
>>>>> + * The resctrl filesystem writes to the partid/pmg values for threads and CPUs,
>>>>> + * which may race with reads in __mpam_sched_in(). Ensure only one of the old
>>>>> + * or new values are used. Particular care should be taken with the pmg field
>>>>> + * as __mpam_sched_in() may read a partid and pmg that don't match, causing
>>>>> + * this value to be stored with cache allocations, despite being considered
>>>>> + * 'free' by resctrl.
>>>>> + *
>>>>> + * A value in struct thread_info is used instead of struct task_struct as the
>>>>> + * cpu's u64 register format is used, but struct task_struct has two u32'.  
>>>>
>>>> This comment probably wants to provide a little more info if it is to be useful,
>>>>
>>>> Is it a reference to the closid and rmid fields under CONFIG_X86_CPU_RESCTRL?
>>>> I'm not immediately understanding why that matters given you could slap
>>>> a union on it without (I think) resulting in anything else moving.  
>>>
>>> Yes, the fields referred to are those closid and rmid. As James writes
>>> in the commit message a union is an alternative, but it would be endian
>>> unsafe. Unlikely to matter but lets not break things.  
>>
>> Meant to say... I'll add clarification in this vein to the comment.
> 
> Goes to show I didn't read the patch description.  Oops.
> 
> I'm probably just being slow today, but why would it be endian unsafe?
> I didn't think the alternative would be to assume the two uses of the storage
> were valid at the same time but rather just to reuse the space (which would
> have 64bit alignment anyway).  For that matter we could just put a u64 in
> under a separate ifdef CONFIG_...
> 
> Obviously if the code made use of the access to closid / rmid for arm64
> systems it would be a problem.

Yes, I think it would only be unsafe if closid / rmid were accessed, but
if they're not, just reusing the spot is cleaner. I assume James' point
is that as we can't use what we've already got it's ok just to do
something new.

> 
> Anyway just expanding on the comment a bit should do the job with no
> need for any other changes.
> 
> Thanks,
> 
> Jonathan
> 
> 
>>
>>>
>>> I'm replying for James as he is otherwise engaged. Thanks for the review
>>> of this series and all your review on the previous MPAM series.
>>>   
>>>>
>>>> Now having it in thread_info moves it into arch header territory so
>>>> might make sense for that reason.
>>>>  
>>>>> + */
>>>>> +static inline u64 mpam_get_regval(struct task_struct *tsk)
>>>>> +{
>>>>> +#ifdef CONFIG_ARM64_MPAM
>>>>> +	return READ_ONCE(task_thread_info(tsk)->mpam_partid_pmg);
>>>>> +#else
>>>>> +	return 0;
>>>>> +#endif
>>>>> +}  
>>>>  
>>>
>>> Thanks,
>>>
>>> Ben
>>>   
>>
> 

Thanks,

Ben



From yeoreum.yun at arm.com  Thu Dec 18 07:54:40 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Thu, 18 Dec 2025 15:54:40 +0000
Subject: [PATCH v2 1/2] arm64: mmu: don't allocate page while spliting
 linear mapping
In-Reply-To: <73644c65-57fd-4d0c-9179-167277214f26@arm.com>
References: <20251217182007.2345700-1-yeoreum.yun@arm.com>
 <20251217182007.2345700-2-yeoreum.yun@arm.com>
 <73ced1db-a2e2-49ea-927e-9fc4a30e771e@arm.com>
 <aUQXRpLzKbl+I3Gu@e129823.arm.com>
 <73644c65-57fd-4d0c-9179-167277214f26@arm.com>
Message-ID: <aUQjwKClvatP7zFP@e129823.arm.com>

> On 18/12/2025 15:01, Yeoreum Yun wrote:
> > Hi Ryan,
> >
> >> On 17/12/2025 18:20, Yeoreum Yun wrote:
> >>> Current linear_map_split_to_ptes() allocate the pagetable
> >>> while split linear mapping to ptes by stop_machine() with GFP_ATOMIC.
> >>>
> >>> This is fine for non-PREEMPR_RT case.
> >>> However It's a problem in PREEMPR_RT case since
> >>> generic memory allocation/free APIs (e.x) pgtable_alloc(), __get_free_pages and etc
> >>> couldn't be called in non-preemptible context except _nolock() APIs
> >>> since generic memory allocation/free APIs are *sleepable* for using *spin_lock()*
> >>>
> >>> IOW, calling a pgtable_alloc() even with GFP_ATOMIC
> >>> doesn't allow in __linear_map_split_to_pte() executed by stopper thread
> >>> where preemption is disabled in PREEMPR_RT.
> >>>
> >>> To address this, divide linear_map_maybe_split_ptes:
> >>>   - collect number of pages to require for spliting.
> >>>   - allocate the required number of pages for spliting.
> >>>   - with pre-allocate page, split the linear map.
> >>
> >> Thanks for working on this fix!
> >>
> >> First some high level comments: I'm not a huge fan of the approach with the
> >> different modes to modify behaviour.
> >>
> >> For the first step of figuring out the number of pages required; there is no
> >> need to be inside stop_machine() for that. Can should be able to just walk the
> >> linear map without any locking since it is created once and remains static, with
> >> the exception of hotplug, but that is not enabled yet.
> >>
> >> I think it would be cleaner to just create separate walker callbacks rather than
> >> repurpose the existing walker.
> >
> > Okay. I'll repsin with separate walker.
> >
> >>
> >> Then you could simply change the gfp flag to a callback function pointer and
> >> pass the desired allocator as a function pointer. This would match the existing
> >> patterns used in mmu.c today.
> >>
> >> The preallocated page list could be stored in a global static variable and you
> >> could create an allocation function that just strims a page from that list. See
> >> kpti_ng_pgd_alloc() for an existing example. That assumes a contiguous block,
> >> but you could generalize it to hold a list of struct pages and reuse it for both
> >> cases?
> >
> > If we use walker callbacks, I think it not only pass the callback
> > function, but it need to pass the gfp flag too since split_xxx() is
> > called by another functions. (i.e) set_memory_xxx()
> >
> > I think I can remove the mode with the suggestion of @David
> > but, I think it would be still use split_args with information of
> > gfp and preallocate buffer.
>
> I don't think that's necessary; all other users pass GFP_PGTABLE_KERNEL, so we
> just need one allocator function that allocates with GFP_PGTABLE_KERNEL and
> another allocator function that allocates from the prealloc'ed list. Then the
> user passes the function they want to use.
>
> That would work, I think?

True. I forgot I removed GFP_ATOMIC myself for pgtable alloc.
Okay. then I'll move the preallocated buffer information to global
and just pass function pointer then.

Thanks


--
Sincerely,
Yeoreum Yun


From Frank.Li at nxp.com  Thu Dec 18 07:56:20 2025
From: Frank.Li at nxp.com (Frank Li)
Date: Thu, 18 Dec 2025 10:56:20 -0500
Subject: [PATCH v2 0/8] dmaengine: Add new API to combine onfiguration and
 descriptor preparation
Message-ID: <20251218-dma_prep_config-v2-0-c07079836128@nxp.com>

Previously, configuration and preparation required two separate calls. This
works well when configuration is done only once during initialization.

However, in cases where the burst length or source/destination address must
be adjusted for each transfer, calling two functions is verbose.

	if (dmaengine_slave_config(chan, &sconf)) {
		dev_err(dev, "DMA slave config fail\n");
		return -EIO;
	}

	tx = dmaengine_prep_slave_single(chan, dma_local, len, dir, flags);

After new API added

	tx = dmaengine_prep_config_single(chan, dma_local, len, dir, flags, &sconf);

Additional, prevous two calls requires additional locking to ensure both
steps complete atomically.

    mutex_lock()
    dmaengine_slave_config()
    dmaengine_prep_slave_single()
    mutex_unlock()

after new API added, mutex lock can be moved. See patch
     nvmet: pci-epf: Use dmaengine_prep_config_single_safe() API

Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
Changes in v2:
- Use name dmaengine_prep_config_single() and dmaengine_prep_config_sg()
- Add _safe version to avoid confuse, which needn't additional mutex.
- Update document/
- Update commit message. add () for function name. Use upcase for subject.
- Add more explain for remove lock.
- Link to v1: https://lore.kernel.org/r/20251208-dma_prep_config-v1-0-53490c5e1e2a at nxp.com

---
Frank Li (8):
      dmaengine: Add API to combine configuration and preparation (sg and single)
      PCI: endpoint: pci-epf-test: Use dmaenigne_prep_config_single() to simplify code
      dmaengine: dw-edma: Use new .device_prep_config_sg() callback
      dmaengine: dw-edma: Pass dma_slave_config to dw_edma_device_transfer()
      nvmet: pci-epf: Remove unnecessary dmaengine_terminate_sync() on each DMA transfer
      nvmet: pci-epf: Use dmaengine_prep_config_single_safe() API
      PCI: epf-mhi: Use dmaengine_prep_config_single() to simplify code
      crypto: atmel: Use dmaengine_prep_config_single() API

 Documentation/driver-api/dmaengine/client.rst |   9 +++
 drivers/crypto/atmel-aes.c                    |  10 +--
 drivers/dma/dw-edma/dw-edma-core.c            |  36 ++++++---
 drivers/nvme/target/pci-epf.c                 |  21 ++----
 drivers/pci/endpoint/functions/pci-epf-mhi.c  |  52 ++++---------
 drivers/pci/endpoint/functions/pci-epf-test.c |   8 +-
 include/linux/dmaengine.h                     | 103 ++++++++++++++++++++++++--
 7 files changed, 156 insertions(+), 83 deletions(-)
---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20251204-dma_prep_config-654170d245a2

Best regards,
--
Frank Li <Frank.Li at nxp.com>



From Frank.Li at nxp.com  Thu Dec 18 07:56:21 2025
From: Frank.Li at nxp.com (Frank Li)
Date: Thu, 18 Dec 2025 10:56:21 -0500
Subject: [PATCH v2 1/8] dmaengine: Add API to combine configuration and
 preparation (sg and single)
In-Reply-To: <20251218-dma_prep_config-v2-0-c07079836128@nxp.com>
References: <20251218-dma_prep_config-v2-0-c07079836128@nxp.com>
Message-ID: <20251218-dma_prep_config-v2-1-c07079836128@nxp.com>

Previously, configuration and preparation required two separate calls. This
works well when configuration is done only once during initialization.

However, in cases where the burst length or source/destination address must
be adjusted for each transfer, calling two functions is verbose and
requires additional locking to ensure both steps complete atomically.

Add a new API dmaengine_prep_config_single() and dmaengine_prep_config_sg()
and callback device_prep_config_sg() that combines configuration and
preparation into a single operation. If the configuration argument is
passed as NULL, fall back to the existing implementation.

Add a new API dmaengine_prep_config_single_safe() and
dmaengine_prep_config_sg_safe() for re-entrancy, which require driver
implement callback device_prep_config_sg().

Tested-by: Niklas Cassel <cassel at kernel.org>
Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
change in v2
- add () for function
- use short name device_prep_sg(), remove "slave" and "config". the 'slave'
is reduntant. after remove slave, the function name is difference existed
one, so remove _config suffix.
---
 Documentation/driver-api/dmaengine/client.rst |   9 +++
 include/linux/dmaengine.h                     | 103 ++++++++++++++++++++++++--
 2 files changed, 105 insertions(+), 7 deletions(-)

diff --git a/Documentation/driver-api/dmaengine/client.rst b/Documentation/driver-api/dmaengine/client.rst
index d491e385d61a98b8a804cd823caf254a2dc62cf4..02c45b7d7a779421411eb9c68325cdedafcfe3b1 100644
--- a/Documentation/driver-api/dmaengine/client.rst
+++ b/Documentation/driver-api/dmaengine/client.rst
@@ -80,6 +80,10 @@ The details of these operations are:
 
   - slave_sg: DMA a list of scatter gather buffers from/to a peripheral
 
+  - config_sg: Similar with slave_sg, just pass down dma_slave_config
+    struct to avoid call dmaengine_slave_config() every time if need
+    adjust burst length or FIFO address.
+
   - peripheral_dma_vec: DMA an array of scatter gather buffers from/to a
     peripheral. Similar to slave_sg, but uses an array of dma_vec
     structures instead of a scatterlist.
@@ -106,6 +110,11 @@ The details of these operations are:
 		unsigned int sg_len, enum dma_data_direction direction,
 		unsigned long flags);
 
+     struct dma_async_tx_descriptor *dmaengine_prep_config_sg(
+		struct dma_chan *chan, struct scatterlist *sgl,
+		unsigned int sg_len, enum dma_transfer_direction dir,
+		unsigned long flags, struct dma_slave_config *config);
+
      struct dma_async_tx_descriptor *dmaengine_prep_peripheral_dma_vec(
 		struct dma_chan *chan, const struct dma_vec *vecs,
 		size_t nents, enum dma_data_direction direction,
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 99efe2b9b4ea9844ca6161208362ef18ef111d96..276dca760f95e1131f5ff5bf69752c4c9cb1bcad 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -835,6 +835,8 @@ struct dma_filter {
  *	where the address and size of each segment is located in one entry of
  *	the dma_vec array.
  * @device_prep_slave_sg: prepares a slave dma operation
+ *	(Deprecated, use @device_prep_config_sg)
+ * @device_prep_config_sg: prepares a slave DMA operation with dma_slave_config
  * @device_prep_dma_cyclic: prepare a cyclic dma operation suitable for audio.
  *	The function takes a buffer of size buf_len. The callback function will
  *	be called after period_len bytes have been transferred.
@@ -934,6 +936,11 @@ struct dma_device {
 		struct dma_chan *chan, struct scatterlist *sgl,
 		unsigned int sg_len, enum dma_transfer_direction direction,
 		unsigned long flags, void *context);
+	struct dma_async_tx_descriptor *(*device_prep_config_sg)(
+		struct dma_chan *chan, struct scatterlist *sgl,
+		unsigned int sg_len, enum dma_transfer_direction direction,
+		unsigned long flags, struct dma_slave_config *config,
+		void *context);
 	struct dma_async_tx_descriptor *(*device_prep_dma_cyclic)(
 		struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
 		size_t period_len, enum dma_transfer_direction direction,
@@ -974,22 +981,85 @@ static inline bool is_slave_direction(enum dma_transfer_direction direction)
 	       (direction == DMA_DEV_TO_DEV);
 }
 
-static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_single(
-	struct dma_chan *chan, dma_addr_t buf, size_t len,
-	enum dma_transfer_direction dir, unsigned long flags)
+/*
+ * Re-entrancy and locking considerations for callers:
+ *
+ * dmaengine_prep_config_single(sg)_safe() is re-entrant and requires the
+ * DMA engine driver to implement device_prep_config_sg(). It returns NULL
+ * if device_prep_config_sg() is not implemented.
+ *
+ * The unsafe variant (without the _safe suffix) falls back to calling
+ * dmaengine_slave_config() and dmaengine_prep_slave_sg() separately.
+ * In this case, additional locking may be required, depending on the
+ * DMA consumer's usage.
+ */
+static inline struct dma_async_tx_descriptor *
+dmaengine_prep_config_sg_safe(struct dma_chan *chan, struct scatterlist *sgl,
+	unsigned int sg_len, enum dma_transfer_direction dir,
+	unsigned long flags, struct dma_slave_config *config)
+{
+	if (!chan || !chan->device || !chan->device->device_prep_config_sg)
+		return NULL;
+
+	return chan->device->device_prep_config_sg(chan, sgl, sg_len,
+						   dir, flags, config, NULL);
+}
+
+static inline struct dma_async_tx_descriptor *
+dmaengine_prep_config_single_safe(struct dma_chan *chan, dma_addr_t buf,
+	size_t len, enum dma_transfer_direction dir, unsigned long flags,
+	struct dma_slave_config *config)
 {
 	struct scatterlist sg;
+
 	sg_init_table(&sg, 1);
 	sg_dma_address(&sg) = buf;
 	sg_dma_len(&sg) = len;
 
-	if (!chan || !chan->device || !chan->device->device_prep_slave_sg)
+	if (!chan || !chan->device || !chan->device->device_prep_config_sg)
+		return NULL;
+
+	return chan->device->device_prep_config_sg(chan, &sg, 1, dir,
+						   flags, config, NULL);
+}
+
+static inline struct dma_async_tx_descriptor *
+dmaengine_prep_config_single(struct dma_chan *chan, dma_addr_t buf, size_t len,
+	enum dma_transfer_direction dir, unsigned long flags,
+	struct dma_slave_config *config)
+{
+	struct scatterlist sg;
+
+	sg_init_table(&sg, 1);
+	sg_dma_address(&sg) = buf;
+	sg_dma_len(&sg) = len;
+
+	if (!chan || !chan->device)
+		return NULL;
+
+	if (chan->device->device_prep_config_sg)
+		return dmaengine_prep_config_sg_safe(chan, &sg, 1, dir,
+						     flags, config);
+
+	if (config)
+		if (dmaengine_slave_config(chan, config))
+			return NULL;
+
+	if (!chan->device->device_prep_slave_sg)
 		return NULL;
 
 	return chan->device->device_prep_slave_sg(chan, &sg, 1,
 						  dir, flags, NULL);
 }
 
+static inline struct dma_async_tx_descriptor *
+dmaengine_prep_slave_single(struct dma_chan *chan, dma_addr_t buf, size_t len,
+			    enum dma_transfer_direction dir,
+			    unsigned long flags)
+{
+	return dmaengine_prep_config_single(chan, buf, len, dir, flags, NULL);
+}
+
 /**
  * dmaengine_prep_peripheral_dma_vec() - Prepare a DMA scatter-gather descriptor
  * @chan: The channel to be used for this descriptor
@@ -1009,17 +1079,36 @@ static inline struct dma_async_tx_descriptor *dmaengine_prep_peripheral_dma_vec(
 							    dir, flags);
 }
 
-static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_sg(
+static inline struct dma_async_tx_descriptor *dmaengine_prep_config_sg(
 	struct dma_chan *chan, struct scatterlist *sgl,	unsigned int sg_len,
-	enum dma_transfer_direction dir, unsigned long flags)
+	enum dma_transfer_direction dir, unsigned long flags,
+	struct dma_slave_config *config)
 {
-	if (!chan || !chan->device || !chan->device->device_prep_slave_sg)
+	if (!chan || !chan->device)
+		return NULL;
+
+	if (chan->device->device_prep_config_sg)
+		return dmaengine_prep_config_sg_safe(chan, sgl, sg_len,
+					dir, flags, config);
+
+	if (config)
+		if (dmaengine_slave_config(chan, config))
+			return NULL;
+
+	if (!chan->device->device_prep_slave_sg)
 		return NULL;
 
 	return chan->device->device_prep_slave_sg(chan, sgl, sg_len,
 						  dir, flags, NULL);
 }
 
+static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_sg(
+	struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len,
+	enum dma_transfer_direction dir, unsigned long flags)
+{
+	return dmaengine_prep_config_sg(chan, sgl, sg_len, dir, flags, NULL);
+}
+
 #ifdef CONFIG_RAPIDIO_DMA_ENGINE
 struct rio_dma_ext;
 static inline struct dma_async_tx_descriptor *dmaengine_prep_rio_sg(

-- 
2.34.1



From Frank.Li at nxp.com  Thu Dec 18 07:56:22 2025
From: Frank.Li at nxp.com (Frank Li)
Date: Thu, 18 Dec 2025 10:56:22 -0500
Subject: [PATCH v2 2/8] PCI: endpoint: pci-epf-test: Use
 dmaenigne_prep_config_single() to simplify code
In-Reply-To: <20251218-dma_prep_config-v2-0-c07079836128@nxp.com>
References: <20251218-dma_prep_config-v2-0-c07079836128@nxp.com>
Message-ID: <20251218-dma_prep_config-v2-2-c07079836128@nxp.com>

Use dmaenigne_prep_config_single() to simplify code.

No functional change.

Tested-by: Niklas Cassel <cassel at kernel.org>
Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/pci/endpoint/functions/pci-epf-test.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index debd235253c5ba54eb8f06d13261c407ee3768ec..95b046c678da7ca4a0d9616acdd544251dc05aac 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -162,12 +162,8 @@ static int pci_epf_test_data_transfer(struct pci_epf_test *epf_test,
 		else
 			sconf.src_addr = dma_remote;
 
-		if (dmaengine_slave_config(chan, &sconf)) {
-			dev_err(dev, "DMA slave config fail\n");
-			return -EIO;
-		}
-		tx = dmaengine_prep_slave_single(chan, dma_local, len, dir,
-						 flags);
+		tx = dmaengine_prep_config_single(chan, dma_local, len,
+						  dir, flags, &sconf);
 	} else {
 		tx = dmaengine_prep_dma_memcpy(chan, dma_dst, dma_src, len,
 					       flags);

-- 
2.34.1



From Frank.Li at nxp.com  Thu Dec 18 07:56:23 2025
From: Frank.Li at nxp.com (Frank Li)
Date: Thu, 18 Dec 2025 10:56:23 -0500
Subject: [PATCH v2 3/8] dmaengine: dw-edma: Use new
 .device_prep_config_sg() callback
In-Reply-To: <20251218-dma_prep_config-v2-0-c07079836128@nxp.com>
References: <20251218-dma_prep_config-v2-0-c07079836128@nxp.com>
Message-ID: <20251218-dma_prep_config-v2-3-c07079836128@nxp.com>

Use the new .device_prep_config_sg() callback to combine configuration and
descriptor preparation.

No functional changes.

Tested-by: Niklas Cassel <cassel at kernel.org>
Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/dma/dw-edma/dw-edma-core.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 8e5f7defa6b678eefe0f312ebc59f654677c744f..e005b7bdaee156a3f4573b4734f50e3e47553dd2 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -532,10 +532,11 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
 }
 
 static struct dma_async_tx_descriptor *
-dw_edma_device_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
-			     unsigned int len,
-			     enum dma_transfer_direction direction,
-			     unsigned long flags, void *context)
+dw_edma_device_prep_config_sg(struct dma_chan *dchan, struct scatterlist *sgl,
+			      unsigned int len,
+			      enum dma_transfer_direction direction,
+			      unsigned long flags,
+			      struct dma_slave_config *config, void *context)
 {
 	struct dw_edma_transfer xfer;
 
@@ -546,6 +547,9 @@ dw_edma_device_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
 	xfer.flags = flags;
 	xfer.type = EDMA_XFER_SCATTER_GATHER;
 
+	if (config)
+		dw_edma_device_config(dchan, config);
+
 	return dw_edma_device_transfer(&xfer);
 }
 
@@ -815,7 +819,7 @@ static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc)
 	dma->device_terminate_all = dw_edma_device_terminate_all;
 	dma->device_issue_pending = dw_edma_device_issue_pending;
 	dma->device_tx_status = dw_edma_device_tx_status;
-	dma->device_prep_slave_sg = dw_edma_device_prep_slave_sg;
+	dma->device_prep_config_sg = dw_edma_device_prep_config_sg;
 	dma->device_prep_dma_cyclic = dw_edma_device_prep_dma_cyclic;
 	dma->device_prep_interleaved_dma = dw_edma_device_prep_interleaved_dma;
 

-- 
2.34.1



From Frank.Li at nxp.com  Thu Dec 18 07:56:24 2025
From: Frank.Li at nxp.com (Frank Li)
Date: Thu, 18 Dec 2025 10:56:24 -0500
Subject: [PATCH v2 4/8] dmaengine: dw-edma: Pass dma_slave_config to
 dw_edma_device_transfer()
In-Reply-To: <20251218-dma_prep_config-v2-0-c07079836128@nxp.com>
References: <20251218-dma_prep_config-v2-0-c07079836128@nxp.com>
Message-ID: <20251218-dma_prep_config-v2-4-c07079836128@nxp.com>

Pass dma_slave_config to dw_edma_device_transfer() to support atomic
configuration and descriptor preparation when a non-NULL config is
provided to device_prep_config_sg().

Tested-by: Niklas Cassel <cassel at kernel.org>
Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/dma/dw-edma/dw-edma-core.c | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index e005b7bdaee156a3f4573b4734f50e3e47553dd2..1863254bf61eb892cb0cf8934e53b40d32027dfa 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -230,6 +230,15 @@ static int dw_edma_device_config(struct dma_chan *dchan,
 	return 0;
 }
 
+static struct dma_slave_config *
+dw_edma_device_get_config(struct dma_chan *dchan,
+			  struct dma_slave_config *config)
+{
+	struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
+
+	return config ? config : &chan->config;
+}
+
 static int dw_edma_device_pause(struct dma_chan *dchan)
 {
 	struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
@@ -348,7 +357,8 @@ dw_edma_device_tx_status(struct dma_chan *dchan, dma_cookie_t cookie,
 }
 
 static struct dma_async_tx_descriptor *
-dw_edma_device_transfer(struct dw_edma_transfer *xfer)
+dw_edma_device_transfer(struct dw_edma_transfer *xfer,
+			struct dma_slave_config *config)
 {
 	struct dw_edma_chan *chan = dchan2dw_edma_chan(xfer->dchan);
 	enum dma_transfer_direction dir = xfer->direction;
@@ -427,8 +437,8 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
 		src_addr = xfer->xfer.il->src_start;
 		dst_addr = xfer->xfer.il->dst_start;
 	} else {
-		src_addr = chan->config.src_addr;
-		dst_addr = chan->config.dst_addr;
+		src_addr = config->src_addr;
+		dst_addr = config->dst_addr;
 	}
 
 	if (dir == DMA_DEV_TO_MEM)
@@ -550,7 +560,7 @@ dw_edma_device_prep_config_sg(struct dma_chan *dchan, struct scatterlist *sgl,
 	if (config)
 		dw_edma_device_config(dchan, config);
 
-	return dw_edma_device_transfer(&xfer);
+	return dw_edma_device_transfer(&xfer, dw_edma_device_get_config(dchan, config));
 }
 
 static struct dma_async_tx_descriptor *
@@ -569,7 +579,7 @@ dw_edma_device_prep_dma_cyclic(struct dma_chan *dchan, dma_addr_t paddr,
 	xfer.flags = flags;
 	xfer.type = EDMA_XFER_CYCLIC;
 
-	return dw_edma_device_transfer(&xfer);
+	return dw_edma_device_transfer(&xfer, dw_edma_device_get_config(dchan, NULL));
 }
 
 static struct dma_async_tx_descriptor *
@@ -585,7 +595,7 @@ dw_edma_device_prep_interleaved_dma(struct dma_chan *dchan,
 	xfer.flags = flags;
 	xfer.type = EDMA_XFER_INTERLEAVED;
 
-	return dw_edma_device_transfer(&xfer);
+	return dw_edma_device_transfer(&xfer, dw_edma_device_get_config(dchan, NULL));
 }
 
 static void dw_hdma_set_callback_result(struct virt_dma_desc *vd,

-- 
2.34.1



From Frank.Li at nxp.com  Thu Dec 18 07:56:25 2025
From: Frank.Li at nxp.com (Frank Li)
Date: Thu, 18 Dec 2025 10:56:25 -0500
Subject: [PATCH v2 5/8] nvmet: pci-epf: Remove unnecessary
 dmaengine_terminate_sync() on each DMA transfer
In-Reply-To: <20251218-dma_prep_config-v2-0-c07079836128@nxp.com>
References: <20251218-dma_prep_config-v2-0-c07079836128@nxp.com>
Message-ID: <20251218-dma_prep_config-v2-5-c07079836128@nxp.com>

dmaengine_terminate_sync() cancels all pending requests. Calling it for
every DMA transfer is unnecessary and counterproductive. This function is
generally intended for cleanup paths such as module removal, device close,
or unbind operations.

Remove the redundant calls for success path and keep it only at error path.

Tested-by: Niklas Cassel <cassel at kernel.org>
Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
This one also fix stress test failure after remove mutex and use new API
dmaengine_prep_slave_sg_config().
---
 drivers/nvme/target/pci-epf.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c
index f858a6c9d7cb90670037a957cebdcbf17dddc43b..56b1c6a7706a9e2dd9d8aaf17b440129b948486c 100644
--- a/drivers/nvme/target/pci-epf.c
+++ b/drivers/nvme/target/pci-epf.c
@@ -420,10 +420,9 @@ static int nvmet_pci_epf_dma_transfer(struct nvmet_pci_epf *nvme_epf,
 	if (dma_sync_wait(chan, cookie) != DMA_COMPLETE) {
 		dev_err(dev, "DMA transfer failed\n");
 		ret = -EIO;
+		dmaengine_terminate_sync(chan);
 	}
 
-	dmaengine_terminate_sync(chan);
-
 unmap:
 	dma_unmap_single(dma_dev, dma_addr, seg->length, dir);
 

-- 
2.34.1



From Frank.Li at nxp.com  Thu Dec 18 07:56:26 2025
From: Frank.Li at nxp.com (Frank Li)
Date: Thu, 18 Dec 2025 10:56:26 -0500
Subject: [PATCH v2 6/8] nvmet: pci-epf: Use
 dmaengine_prep_config_single_safe() API
In-Reply-To: <20251218-dma_prep_config-v2-0-c07079836128@nxp.com>
References: <20251218-dma_prep_config-v2-0-c07079836128@nxp.com>
Message-ID: <20251218-dma_prep_config-v2-6-c07079836128@nxp.com>

Use the new dmaengine_prep_config_single_safe() API to combine the
configuration and descriptor preparation into a single call.

Since dmaengine_prep_config_single_safe() performs the configuration and
preparation atomically and dw edma driver implement prep_config_sg() call
back, so dmaengine_prep_config_single() is reentriable, the mutex can be
removed.

Tested-by: Niklas Cassel <cassel at kernel.org>
Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/nvme/target/pci-epf.c | 18 ++++--------------
 1 file changed, 4 insertions(+), 14 deletions(-)

diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c
index 56b1c6a7706a9e2dd9d8aaf17b440129b948486c..8b5ea5d4c79dfd461b767cfd4033a9e4604c94b1 100644
--- a/drivers/nvme/target/pci-epf.c
+++ b/drivers/nvme/target/pci-epf.c
@@ -388,22 +388,15 @@ static int nvmet_pci_epf_dma_transfer(struct nvmet_pci_epf *nvme_epf,
 		return -EINVAL;
 	}
 
-	mutex_lock(lock);
-
 	dma_dev = dmaengine_get_dma_device(chan);
 	dma_addr = dma_map_single(dma_dev, seg->buf, seg->length, dir);
 	ret = dma_mapping_error(dma_dev, dma_addr);
 	if (ret)
-		goto unlock;
-
-	ret = dmaengine_slave_config(chan, &sconf);
-	if (ret) {
-		dev_err(dev, "Failed to configure DMA channel\n");
-		goto unmap;
-	}
+		return ret;
 
-	desc = dmaengine_prep_slave_single(chan, dma_addr, seg->length,
-					   sconf.direction, DMA_CTRL_ACK);
+	desc = dmaengine_prep_config_single_safe(chan, dma_addr, seg->length,
+						 sconf.direction,
+						 DMA_CTRL_ACK, &sconf);
 	if (!desc) {
 		dev_err(dev, "Failed to prepare DMA\n");
 		ret = -EIO;
@@ -426,9 +419,6 @@ static int nvmet_pci_epf_dma_transfer(struct nvmet_pci_epf *nvme_epf,
 unmap:
 	dma_unmap_single(dma_dev, dma_addr, seg->length, dir);
 
-unlock:
-	mutex_unlock(lock);
-
 	return ret;
 }
 

-- 
2.34.1



From Frank.Li at nxp.com  Thu Dec 18 07:56:27 2025
From: Frank.Li at nxp.com (Frank Li)
Date: Thu, 18 Dec 2025 10:56:27 -0500
Subject: [PATCH v2 7/8] PCI: epf-mhi: Use dmaengine_prep_config_single() to
 simplify code
In-Reply-To: <20251218-dma_prep_config-v2-0-c07079836128@nxp.com>
References: <20251218-dma_prep_config-v2-0-c07079836128@nxp.com>
Message-ID: <20251218-dma_prep_config-v2-7-c07079836128@nxp.com>

Use dmaengine_prep_config_single() to simplify
pci_epf_mhi_edma_read[_sync]() and pci_epf_mhi_edma_write[_sync]().

No functional change.

Tested-by: Niklas Cassel <cassel at kernel.org>
Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
Keep mutex lock because sync with other function.
---
 drivers/pci/endpoint/functions/pci-epf-mhi.c | 52 +++++++++-------------------
 1 file changed, 16 insertions(+), 36 deletions(-)

diff --git a/drivers/pci/endpoint/functions/pci-epf-mhi.c b/drivers/pci/endpoint/functions/pci-epf-mhi.c
index 6643a88c7a0ce38161bc6253c09d29f1c36ba394..0bf51fd467395182161555f83aa78f3839e36773 100644
--- a/drivers/pci/endpoint/functions/pci-epf-mhi.c
+++ b/drivers/pci/endpoint/functions/pci-epf-mhi.c
@@ -328,12 +328,6 @@ static int pci_epf_mhi_edma_read(struct mhi_ep_cntrl *mhi_cntrl,
 	config.direction = DMA_DEV_TO_MEM;
 	config.src_addr = buf_info->host_addr;
 
-	ret = dmaengine_slave_config(chan, &config);
-	if (ret) {
-		dev_err(dev, "Failed to configure DMA channel\n");
-		goto err_unlock;
-	}
-
 	dst_addr = dma_map_single(dma_dev, buf_info->dev_addr, buf_info->size,
 				  DMA_FROM_DEVICE);
 	ret = dma_mapping_error(dma_dev, dst_addr);
@@ -342,9 +336,10 @@ static int pci_epf_mhi_edma_read(struct mhi_ep_cntrl *mhi_cntrl,
 		goto err_unlock;
 	}
 
-	desc = dmaengine_prep_slave_single(chan, dst_addr, buf_info->size,
-					   DMA_DEV_TO_MEM,
-					   DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
+	desc = dmaengine_prep_config_single(chan, dst_addr, buf_info->size,
+					    DMA_DEV_TO_MEM,
+					    DMA_CTRL_ACK | DMA_PREP_INTERRUPT,
+					    &config);
 	if (!desc) {
 		dev_err(dev, "Failed to prepare DMA\n");
 		ret = -EIO;
@@ -399,12 +394,6 @@ static int pci_epf_mhi_edma_write(struct mhi_ep_cntrl *mhi_cntrl,
 	config.direction = DMA_MEM_TO_DEV;
 	config.dst_addr = buf_info->host_addr;
 
-	ret = dmaengine_slave_config(chan, &config);
-	if (ret) {
-		dev_err(dev, "Failed to configure DMA channel\n");
-		goto err_unlock;
-	}
-
 	src_addr = dma_map_single(dma_dev, buf_info->dev_addr, buf_info->size,
 				  DMA_TO_DEVICE);
 	ret = dma_mapping_error(dma_dev, src_addr);
@@ -413,9 +402,10 @@ static int pci_epf_mhi_edma_write(struct mhi_ep_cntrl *mhi_cntrl,
 		goto err_unlock;
 	}
 
-	desc = dmaengine_prep_slave_single(chan, src_addr, buf_info->size,
-					   DMA_MEM_TO_DEV,
-					   DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
+	desc = dmaengine_prep_config_single(chan, src_addr, buf_info->size,
+					    DMA_MEM_TO_DEV,
+					    DMA_CTRL_ACK | DMA_PREP_INTERRUPT,
+					    &config);
 	if (!desc) {
 		dev_err(dev, "Failed to prepare DMA\n");
 		ret = -EIO;
@@ -502,12 +492,6 @@ static int pci_epf_mhi_edma_read_async(struct mhi_ep_cntrl *mhi_cntrl,
 	config.direction = DMA_DEV_TO_MEM;
 	config.src_addr = buf_info->host_addr;
 
-	ret = dmaengine_slave_config(chan, &config);
-	if (ret) {
-		dev_err(dev, "Failed to configure DMA channel\n");
-		goto err_unlock;
-	}
-
 	dst_addr = dma_map_single(dma_dev, buf_info->dev_addr, buf_info->size,
 				  DMA_FROM_DEVICE);
 	ret = dma_mapping_error(dma_dev, dst_addr);
@@ -516,9 +500,10 @@ static int pci_epf_mhi_edma_read_async(struct mhi_ep_cntrl *mhi_cntrl,
 		goto err_unlock;
 	}
 
-	desc = dmaengine_prep_slave_single(chan, dst_addr, buf_info->size,
-					   DMA_DEV_TO_MEM,
-					   DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
+	desc = dmaengine_prep_config_single(chan, dst_addr, buf_info->size,
+					    DMA_DEV_TO_MEM,
+					    DMA_CTRL_ACK | DMA_PREP_INTERRUPT,
+					    &config);
 	if (!desc) {
 		dev_err(dev, "Failed to prepare DMA\n");
 		ret = -EIO;
@@ -581,12 +566,6 @@ static int pci_epf_mhi_edma_write_async(struct mhi_ep_cntrl *mhi_cntrl,
 	config.direction = DMA_MEM_TO_DEV;
 	config.dst_addr = buf_info->host_addr;
 
-	ret = dmaengine_slave_config(chan, &config);
-	if (ret) {
-		dev_err(dev, "Failed to configure DMA channel\n");
-		goto err_unlock;
-	}
-
 	src_addr = dma_map_single(dma_dev, buf_info->dev_addr, buf_info->size,
 				  DMA_TO_DEVICE);
 	ret = dma_mapping_error(dma_dev, src_addr);
@@ -595,9 +574,10 @@ static int pci_epf_mhi_edma_write_async(struct mhi_ep_cntrl *mhi_cntrl,
 		goto err_unlock;
 	}
 
-	desc = dmaengine_prep_slave_single(chan, src_addr, buf_info->size,
-					   DMA_MEM_TO_DEV,
-					   DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
+	desc = dmaengine_prep_config_single(chan, src_addr, buf_info->size,
+					    DMA_MEM_TO_DEV,
+					    DMA_CTRL_ACK | DMA_PREP_INTERRUPT,
+					    &config);
 	if (!desc) {
 		dev_err(dev, "Failed to prepare DMA\n");
 		ret = -EIO;

-- 
2.34.1



From Frank.Li at nxp.com  Thu Dec 18 07:56:28 2025
From: Frank.Li at nxp.com (Frank Li)
Date: Thu, 18 Dec 2025 10:56:28 -0500
Subject: [PATCH v2 8/8] crypto: atmel: Use dmaengine_prep_config_single()
 API
In-Reply-To: <20251218-dma_prep_config-v2-0-c07079836128@nxp.com>
References: <20251218-dma_prep_config-v2-0-c07079836128@nxp.com>
Message-ID: <20251218-dma_prep_config-v2-8-c07079836128@nxp.com>

Using new API dmaengine_prep_config_single() to simple code.

No functional change.

Tested-by: Niklas Cassel <cassel at kernel.org>
Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/crypto/atmel-aes.c | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c
index 3a2684208dda9ee45d71b4bc2958be293a4fb6fe..e300672ffd7185b0f5bf356c2376681537047def 100644
--- a/drivers/crypto/atmel-aes.c
+++ b/drivers/crypto/atmel-aes.c
@@ -795,7 +795,6 @@ static int atmel_aes_dma_transfer_start(struct atmel_aes_dev *dd,
 	struct dma_slave_config config;
 	dma_async_tx_callback callback;
 	struct atmel_aes_dma *dma;
-	int err;
 
 	memset(&config, 0, sizeof(config));
 	config.src_addr_width = addr_width;
@@ -820,12 +819,9 @@ static int atmel_aes_dma_transfer_start(struct atmel_aes_dev *dd,
 		return -EINVAL;
 	}
 
-	err = dmaengine_slave_config(dma->chan, &config);
-	if (err)
-		return err;
-
-	desc = dmaengine_prep_slave_sg(dma->chan, dma->sg, dma->sg_len, dir,
-				       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	desc = dmaengine_prep_config_sg(dma->chan, dma->sg, dma->sg_len, dir,
+					DMA_PREP_INTERRUPT | DMA_CTRL_ACK,
+					&config);
 	if (!desc)
 		return -ENOMEM;
 

-- 
2.34.1



From andersson at kernel.org  Thu Dec 18 07:58:13 2025
From: andersson at kernel.org (Bjorn Andersson)
Date: Thu, 18 Dec 2025 09:58:13 -0600
Subject: [PATCH v6 4/5] gpio: rpmsg: add generic rpmsg GPIO driver
In-Reply-To: <20251212194341.966387-5-shenwei.wang@nxp.com>
References: <20251212194341.966387-1-shenwei.wang@nxp.com>
 <20251212194341.966387-5-shenwei.wang@nxp.com>
Message-ID: <mnpg4xanzl45lal72c6kgog7qmqgk2zcp734eqdpk3gsonq63f@vlewh6jgdjy4>

On Fri, Dec 12, 2025 at 01:43:40PM -0600, Shenwei Wang wrote:
> On an AMP platform, the system may include two processors:

We have many examples where there's N systems and it's certainly not
unreasonable to have multiple remote processors expose GPIOs in this
fashion.

> 	- An MCU running an RTOS
> 	- An MPU running Linux
> 
> These processors communicate via the RPMSG protocol.
> The driver implements the standard GPIO interface, allowing
> the Linux side to control GPIO controllers which reside in
> the remote processor via RPMSG protocol.
> 
> Cc: Bartosz Golaszewski <brgl at bgdev.pl>
> Cc: Andrew Lunn <andrew at lunn.ch>
> Signed-off-by: Shenwei Wang <shenwei.wang at nxp.com>
> ---
>  drivers/gpio/Kconfig      |  16 ++
>  drivers/gpio/Makefile     |   1 +
>  drivers/gpio/gpio-rpmsg.c | 490 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 507 insertions(+)
>  create mode 100644 drivers/gpio/gpio-rpmsg.c
> 
> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> index bd185482a7fd..7a72b5dbd4a9 100644
> --- a/drivers/gpio/Kconfig
> +++ b/drivers/gpio/Kconfig
> @@ -1883,6 +1883,22 @@ config GPIO_SODAVILLE
>  
>  endmenu
>  
> +menu "RPMSG GPIO drivers"
> +	depends on RPMSG
> +
> +config GPIO_RPMSG
> +	tristate "Generic RPMSG GPIO support"
> +	select GPIOLIB_IRQCHIP
> +	default REMOTEPROC
> +	help
> +	  Say yes here to support the generic GPIO functions over the RPMSG
> +	  bus. Currently supported devices: i.MX7ULP, i.MX8ULP, i.MX8x,and
> +	  i.MX9x.
> +
> +	  If unsure, say N.
> +
> +endmenu
> +
>  menu "SPI GPIO expanders"
>  	depends on SPI_MASTER
>  
> diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
> index 2421a8fd3733..b1373ec274c8 100644
> --- a/drivers/gpio/Makefile
> +++ b/drivers/gpio/Makefile
> @@ -156,6 +156,7 @@ obj-$(CONFIG_GPIO_RDC321X)		+= gpio-rdc321x.o
>  obj-$(CONFIG_GPIO_REALTEK_OTTO)		+= gpio-realtek-otto.o
>  obj-$(CONFIG_GPIO_REG)			+= gpio-reg.o
>  obj-$(CONFIG_GPIO_ROCKCHIP)	+= gpio-rockchip.o
> +obj-$(CONFIG_GPIO_RPMSG)		+= gpio-rpmsg.o
>  obj-$(CONFIG_GPIO_RTD)			+= gpio-rtd.o
>  obj-$(CONFIG_ARCH_SA1100)		+= gpio-sa1100.o
>  obj-$(CONFIG_GPIO_SAMA5D2_PIOBU)	+= gpio-sama5d2-piobu.o
> diff --git a/drivers/gpio/gpio-rpmsg.c b/drivers/gpio/gpio-rpmsg.c
> new file mode 100644
> index 000000000000..cf10e2958374
> --- /dev/null
> +++ b/drivers/gpio/gpio-rpmsg.c
> @@ -0,0 +1,490 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright 2025 NXP
> + *
> + * The driver exports a standard gpiochip interface to control
> + * the GPIO controllers via RPMSG on a remote processor.
> + */
> +#include <linux/completion.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/gpio/driver.h>
> +#include <linux/init.h>
> +#include <linux/irqdomain.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/rpmsg.h>
> +#include <linux/rpmsg/rpdev_info.h>
> +
> +#define RPMSG_GPIO_ID		5
> +#define RPMSG_VENDOR		1
> +#define RPMSG_VERSION		0
> +
> +#define GPIOS_PER_PORT		32
> +#define RPMSG_TIMEOUT		1000
> +
> +enum gpio_input_trigger_type {
> +	GPIO_RPMSG_TRI_IGNORE,

These aren't enumerations, they are well defined constants of the
protocol. I think #define is better.

> +	GPIO_RPMSG_TRI_RISING,
> +	GPIO_RPMSG_TRI_FALLING,
> +	GPIO_RPMSG_TRI_BOTH_EDGE,
> +	GPIO_RPMSG_TRI_LOW_LEVEL,
> +	GPIO_RPMSG_TRI_HIGH_LEVEL,
> +};
> +
> +enum gpio_rpmsg_header_type {
> +	GPIO_RPMSG_SETUP,
> +	GPIO_RPMSG_REPLY,
> +	GPIO_RPMSG_NOTIFY,
> +};
> +
> +enum gpio_rpmsg_header_cmd {
> +	GPIO_RPMSG_INPUT_INIT,
> +	GPIO_RPMSG_OUTPUT_INIT,
> +	GPIO_RPMSG_INPUT_GET,
> +	GPIO_RPMSG_DIRECTION_GET,
> +};
> +
> +struct gpio_rpmsg_head {
> +	u8 id;		/* Message ID Code */
> +	u8 vendor;	/* Vendor ID number */
> +	u8 version;	/* Vendor-specific version number */
> +	u8 type;	/* Message type */
> +	u8 cmd;		/* Command code */
> +	u8 reserved[5];
> +} __packed;
> +
> +struct gpio_rpmsg_packet {
> +	struct gpio_rpmsg_head header;
> +	u8 pin_idx;
> +	u8 port_idx;
> +	union {
> +		u8 event;
> +		u8 retcode;
> +		u8 value;
> +	} out;
> +	union {
> +		u8 wakeup;
> +		u8 value;
> +	} in;
> +} __packed __aligned(8);
> +
> +struct gpio_rpmsg_pin {
> +	u8 irq_shutdown;
> +	u8 irq_unmask;
> +	u8 irq_mask;
> +	u32 irq_wake_enable;
> +	u32 irq_type;
> +	struct gpio_rpmsg_packet msg;
> +};
> +
> +struct gpio_rpmsg_info {
> +	struct rpmsg_device *rpdev;
> +	struct gpio_rpmsg_packet *notify_msg;
> +	struct gpio_rpmsg_packet *reply_msg;
> +	struct completion cmd_complete;
> +	struct mutex lock;
> +	void **port_store;
> +};
> +
> +struct rpmsg_gpio_port {
> +	struct gpio_chip gc;
> +	struct gpio_rpmsg_pin gpio_pins[GPIOS_PER_PORT];
> +	struct gpio_rpmsg_info info;
> +	int idx;
> +};
> +
> +static int gpio_send_message(struct rpmsg_gpio_port *port,
> +			     struct gpio_rpmsg_packet *msg,
> +			     bool sync)
> +{
> +	struct gpio_rpmsg_info *info = &port->info;
> +	int err;
> +
> +	if (!info->rpdev) {
> +		pr_err("rpmsg channel doesn't exist, is remote core ready?\n");

How is this possible? You're creating and destroying the platform_device
based on the presence of the rpmsg channel/endpoint, in what case would
you end up here without a valid rpdev?

And if this is to deal with the race during removal, I guess the error
message is wrong and rpdev might go away before you access it below?

> +		return -EINVAL;
> +	}
> +
> +	reinit_completion(&info->cmd_complete);
> +	err = rpmsg_send(info->rpdev->ept, (void *)msg,
> +			 sizeof(struct gpio_rpmsg_packet));
> +	if (err) {
> +		dev_err(&info->rpdev->dev, "rpmsg_send failed: %d\n", err);
> +		return err;
> +	}
> +
> +	if (sync) {
> +		err = wait_for_completion_timeout(&info->cmd_complete,
> +						  msecs_to_jiffies(RPMSG_TIMEOUT));
> +		if (!err) {
> +			dev_err(&info->rpdev->dev, "rpmsg_send timeout!\n");
> +			return -ETIMEDOUT;
> +		}
> +
> +		if (info->reply_msg->out.retcode != 0) {
> +			dev_err(&info->rpdev->dev, "remote core replies an error: %d!\n",
> +				info->reply_msg->out.retcode);
> +			return -EINVAL;
> +		}
> +
> +		/* copy the reply message */
> +		memcpy(&port->gpio_pins[info->reply_msg->pin_idx].msg,
> +		       info->reply_msg, sizeof(*info->reply_msg));
> +	}
> +
> +	return 0;
> +}
> +
> +static struct gpio_rpmsg_packet *gpio_setup_msg_header(struct rpmsg_gpio_port *port,
> +						       unsigned int offset,
> +						       u8 cmd)
> +{
> +	struct gpio_rpmsg_packet *msg = &port->gpio_pins[offset].msg;
> +
> +	memset(msg, 0, sizeof(struct gpio_rpmsg_packet));
> +	msg->header.id = RPMSG_GPIO_ID;
> +	msg->header.vendor = RPMSG_VENDOR;
> +	msg->header.version = RPMSG_VERSION;
> +	msg->header.type = GPIO_RPMSG_SETUP;
> +	msg->header.cmd = cmd;
> +	msg->pin_idx = offset;
> +	msg->port_idx = port->idx;
> +
> +	return msg;
> +};
> +
> +static int rpmsg_gpio_get(struct gpio_chip *gc, unsigned int gpio)
> +{
> +	struct rpmsg_gpio_port *port = gpiochip_get_data(gc);
> +	struct gpio_rpmsg_packet *msg = NULL;

There's no reason to initialize msg here, the first reference is an
assignment.

> +	int ret;
> +
> +	guard(mutex)(&port->info.lock);
> +
> +	msg = gpio_setup_msg_header(port, gpio, GPIO_RPMSG_INPUT_GET);
> +
> +	ret = gpio_send_message(port, msg, true);
> +	if (!ret)
> +		ret = !!port->gpio_pins[gpio].msg.in.value;
> +
> +	return ret;
> +}
> +
> +static int rpmsg_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio)
> +{
> +	struct rpmsg_gpio_port *port = gpiochip_get_data(gc);
> +	struct gpio_rpmsg_packet *msg = NULL;
> +	int ret;
> +
> +	guard(mutex)(&port->info.lock);
> +
> +	msg = gpio_setup_msg_header(port, gpio, GPIO_RPMSG_DIRECTION_GET);
> +
> +	ret = gpio_send_message(port, msg, true);
> +	if (!ret)
> +		ret = !!port->gpio_pins[gpio].msg.in.value;
> +
> +	return ret;
> +}
> +
> +static int rpmsg_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio)
> +{
> +	struct rpmsg_gpio_port *port = gpiochip_get_data(gc);
> +	struct gpio_rpmsg_packet *msg = NULL;
> +
> +	guard(mutex)(&port->info.lock);
> +
> +	msg = gpio_setup_msg_header(port, gpio, GPIO_RPMSG_INPUT_INIT);
> +
> +	return gpio_send_message(port, msg, true);
> +}
> +
> +static int rpmsg_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
> +{
> +	struct rpmsg_gpio_port *port = gpiochip_get_data(gc);
> +	struct gpio_rpmsg_packet *msg = NULL;
> +
> +	guard(mutex)(&port->info.lock);
> +
> +	msg = gpio_setup_msg_header(port, gpio, GPIO_RPMSG_OUTPUT_INIT);
> +	msg->out.value = val;
> +
> +	return gpio_send_message(port, msg, true);
> +}
> +
> +static int rpmsg_gpio_direction_output(struct gpio_chip *gc,
> +				       unsigned int gpio,
> +				       int val)
> +{
> +
> +	return rpmsg_gpio_set(gc, gpio, val);
> +}
> +
> +static int gpio_rpmsg_irq_set_type(struct irq_data *d, u32 type)
> +{
> +	struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
> +	u32 gpio_idx = d->hwirq;
> +	int edge = 0;
> +	int ret = 0;
> +
> +	switch (type) {
> +	case IRQ_TYPE_EDGE_RISING:
> +		edge = GPIO_RPMSG_TRI_RISING;
> +		irq_set_handler_locked(d, handle_simple_irq);
> +		break;
> +	case IRQ_TYPE_EDGE_FALLING:
> +		edge = GPIO_RPMSG_TRI_FALLING;
> +		irq_set_handler_locked(d, handle_simple_irq);
> +		break;
> +	case IRQ_TYPE_EDGE_BOTH:
> +		edge = GPIO_RPMSG_TRI_BOTH_EDGE;
> +		irq_set_handler_locked(d, handle_simple_irq);
> +		break;
> +	case IRQ_TYPE_LEVEL_LOW:
> +		edge = GPIO_RPMSG_TRI_LOW_LEVEL;
> +		irq_set_handler_locked(d, handle_level_irq);
> +		break;
> +	case IRQ_TYPE_LEVEL_HIGH:
> +		edge = GPIO_RPMSG_TRI_HIGH_LEVEL;
> +		irq_set_handler_locked(d, handle_level_irq);
> +		break;
> +	default:
> +		ret = -EINVAL;
> +		irq_set_handler_locked(d, handle_bad_irq);
> +		break;
> +	}
> +
> +	port->gpio_pins[gpio_idx].irq_type = edge;
> +
> +	return ret;
> +}
> +
> +static int gpio_rpmsg_irq_set_wake(struct irq_data *d, u32 enable)
> +{
> +	struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
> +	u32 gpio_idx = d->hwirq;
> +
> +	port->gpio_pins[gpio_idx].irq_wake_enable = enable;
> +
> +	return 0;
> +}
> +
> +/*
> + * This function will be called at:
> + *  - one interrupt setup.
> + *  - the end of one interrupt happened
> + * The gpio over rpmsg driver will not write the real register, so save
> + * all infos before this function and then send all infos to M core in this
> + * step.
> + */
> +static void gpio_rpmsg_unmask_irq(struct irq_data *d)
> +{
> +	struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
> +	u32 gpio_idx = d->hwirq;
> +
> +	port->gpio_pins[gpio_idx].irq_unmask = 1;
> +}
> +
> +static void gpio_rpmsg_mask_irq(struct irq_data *d)
> +{
> +	struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
> +	u32 gpio_idx = d->hwirq;
> +	/*
> +	 * No need to implement the callback at A core side.
> +	 * M core will mask interrupt after a interrupt occurred, and then
> +	 * sends a notify to A core.
> +	 * After A core dealt with the notify, A core will send a rpmsg to
> +	 * M core to unmask this interrupt again.

There's nothing in this scheme that dictates that we have A cores and M
cores, or that we have a single core system on both sides, or that they
are Arm cores, please describe things in terms of Linux system and
"remote system".

> +	 */
> +	port->gpio_pins[gpio_idx].irq_mask = 1;
> +}
> +
> +static void gpio_rpmsg_irq_shutdown(struct irq_data *d)
> +{
> +	struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
> +	u32 gpio_idx = d->hwirq;
> +
> +	port->gpio_pins[gpio_idx].irq_shutdown = 1;
> +}
> +
> +static void gpio_rpmsg_irq_bus_lock(struct irq_data *d)
> +{
> +	struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
> +
> +	mutex_lock(&port->info.lock);
> +}
> +
> +static void gpio_rpmsg_irq_bus_sync_unlock(struct irq_data *d)
> +{
> +	struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
> +	struct gpio_rpmsg_packet *msg = NULL;
> +	u32 gpio_idx = d->hwirq;
> +
> +	if (!port)
> +		return;
> +
> +	/*
> +	 * For mask irq, do nothing here.
> +	 * M core will mask interrupt after a interrupt occurred, and then
> +	 * sends a notify to A core.
> +	 * After A core dealt with the notify, A core will send a rpmsg to
> +	 * M core to unmask this interrupt again.
> +	 */
> +
> +	if (port->gpio_pins[gpio_idx].irq_mask && !port->gpio_pins[gpio_idx].irq_unmask) {
> +		port->gpio_pins[gpio_idx].irq_mask = 0;
> +		mutex_unlock(&port->info.lock);
> +		return;
> +	}
> +
> +	msg = gpio_setup_msg_header(port, gpio_idx, GPIO_RPMSG_INPUT_INIT);
> +
> +	if (port->gpio_pins[gpio_idx].irq_shutdown) {
> +		msg->out.event = GPIO_RPMSG_TRI_IGNORE;
> +		msg->in.wakeup = 0;
> +		port->gpio_pins[gpio_idx].irq_shutdown = 0;
> +	} else {
> +		 /* if not set irq type, then use low level as trigger type */
> +		msg->out.event = port->gpio_pins[gpio_idx].irq_type;
> +		if (!msg->out.event)
> +			msg->out.event = GPIO_RPMSG_TRI_LOW_LEVEL;
> +		if (port->gpio_pins[gpio_idx].irq_unmask) {
> +			msg->in.wakeup = 0;
> +			port->gpio_pins[gpio_idx].irq_unmask = 0;
> +		} else /* irq set wake */
> +			msg->in.wakeup = port->gpio_pins[gpio_idx].irq_wake_enable;
> +	}
> +
> +	gpio_send_message(port, msg, false);
> +	mutex_unlock(&port->info.lock);
> +}
> +
> +static const struct irq_chip gpio_rpmsg_irq_chip = {
> +	.irq_mask = gpio_rpmsg_mask_irq,
> +	.irq_unmask = gpio_rpmsg_unmask_irq,
> +	.irq_set_wake = gpio_rpmsg_irq_set_wake,
> +	.irq_set_type = gpio_rpmsg_irq_set_type,
> +	.irq_shutdown = gpio_rpmsg_irq_shutdown,
> +	.irq_bus_lock = gpio_rpmsg_irq_bus_lock,
> +	.irq_bus_sync_unlock = gpio_rpmsg_irq_bus_sync_unlock,
> +	.flags = IRQCHIP_IMMUTABLE,
> +};
> +
> +static int rpmsg_gpio_callback(struct rpmsg_device *rpdev,
> +			       void *data, int len, void *priv, u32 src)
> +{
> +	struct gpio_rpmsg_packet *msg = (struct gpio_rpmsg_packet *)data;
> +	struct rpmsg_gpio_port *port = NULL;
> +	struct rpdev_platform_info *drvdata;
> +
> +	drvdata = dev_get_drvdata(&rpdev->dev);
> +	if (msg)
> +		port = drvdata->channel_devices[msg->port_idx];
> +
> +	if (!port)
> +		return -ENODEV;
> +
> +	if (msg->header.type == GPIO_RPMSG_REPLY) {
> +		port->info.reply_msg = msg;

As soon as you return from this function, the msg buffer is put back
into the virtqueue, so you can't just stash a reference to it here and
hope that it's still available when gpio_send_message() tries to read
it.

> +		complete(&port->info.cmd_complete);
> +	} else if (msg->header.type == GPIO_RPMSG_NOTIFY) {
> +		port->info.notify_msg = msg;

Ditto.

Although notify_msg is assigned, but I never see any further access to
it.

> +		generic_handle_domain_irq_safe(port->gc.irq.domain, msg->pin_idx);
> +	} else
> +		dev_err(&rpdev->dev, "wrong command type!\n");
> +
> +	return 0;
> +}
> +
> +static void rpmsg_gpio_remove_action(void *data)
> +{
> +	struct rpmsg_gpio_port *port = data;
> +
> +	port->info.port_store[port->idx] = NULL;
> +}
> +
> +static int rpmsg_gpio_probe(struct platform_device *pdev)
> +{
> +	struct rpdev_platform_info *pltdata = pdev->dev.platform_data;
> +	struct rpmsg_gpio_port *port;
> +	struct gpio_irq_chip *girq;
> +	struct gpio_chip *gc;
> +	int ret;
> +
> +	if (!pltdata)
> +		return -EPROBE_DEFER;

EPROBE_DEFER would imply that if we try again a bit later, platform_data
is suddenly non-NULL, that seems unlikely.

> +
> +	port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
> +	if (!port)
> +		return -ENOMEM;
> +
> +	ret = device_property_read_u32(&pdev->dev, "reg", &port->idx);
> +	if (ret)
> +		return ret;
> +
> +	if (port->idx > MAX_DEV_PER_CHANNEL)
> +		return -EINVAL;
> +
> +	ret = devm_mutex_init(&pdev->dev, &port->info.lock);
> +	if (ret)
> +		return ret;
> +
> +	init_completion(&port->info.cmd_complete);
> +	port->info.rpdev = pltdata->rpdev;
> +	port->info.port_store = pltdata->channel_devices;
> +	port->info.port_store[port->idx] = port;
> +	if (!pltdata->rx_callback)
> +		pltdata->rx_callback = rpmsg_gpio_callback;

What happens if you rmmod your rpmsg gpio driver and then trigger an
interrupt?

> +
> +	gc = &port->gc;
> +	gc->owner = THIS_MODULE;
> +	gc->parent = &pdev->dev;
> +	gc->label = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s-gpio%d",
> +				   pltdata->rproc_name, port->idx);
> +	gc->ngpio = GPIOS_PER_PORT;
> +	gc->base = -1;
> +
> +	gc->direction_input = rpmsg_gpio_direction_input;
> +	gc->direction_output = rpmsg_gpio_direction_output;
> +	gc->get_direction = rpmsg_gpio_get_direction;
> +	gc->get = rpmsg_gpio_get;
> +	gc->set = rpmsg_gpio_set;
> +
> +	platform_set_drvdata(pdev, port);
> +	girq = &gc->irq;
> +	gpio_irq_chip_set_chip(girq, &gpio_rpmsg_irq_chip);
> +	girq->parent_handler = NULL;
> +	girq->num_parents = 0;
> +	girq->parents = NULL;
> +	girq->chip->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s-gpio%d",
> +					  pltdata->rproc_name, port->idx);
> +
> +	ret = devm_add_action_or_reset(&pdev->dev, rpmsg_gpio_remove_action, port);
> +	if (ret)
> +		return ret;
> +
> +	return devm_gpiochip_add_data(&pdev->dev, gc, port);
> +}
> +
> +static const struct of_device_id rpmsg_gpio_dt_ids[] = {
> +	{ .compatible = "rpmsg-gpio" },
> +	{ /* sentinel */ }
> +};
> +
> +static struct platform_driver rpmsg_gpio_driver = {

It's an "rpmsg gpio driver", but it's a platform_driver...

I don't think this is the correct design, but if it is then this needs
to be well documented.

Same thing as platform_data forms a strong ABI between some other driver
and this platform_driver, this needs to be well documented (but should
be avoided).

Regards,
Bjorn

> +	.driver	= {
> +		.name = "gpio-rpmsg",
> +		.of_match_table = rpmsg_gpio_dt_ids,
> +	},
> +	.probe = rpmsg_gpio_probe,
> +};
> +
> +module_platform_driver(rpmsg_gpio_driver);
> +
> +MODULE_AUTHOR("Shenwei Wang <shenwei.wang at nxp.com>");
> +MODULE_DESCRIPTION("generic rpmsg gpio driver");
> +MODULE_LICENSE("GPL");
> -- 
> 2.43.0
> 


From rostedt at goodmis.org  Thu Dec 18 08:06:02 2025
From: rostedt at goodmis.org (Steven Rostedt)
Date: Thu, 18 Dec 2025 11:06:02 -0500
Subject: [PATCHv5 bpf-next 8/9] ftrace: Factor ftrace_ops ops_func
 interface
In-Reply-To: <20251215211402.353056-9-jolsa@kernel.org>
References: <20251215211402.353056-1-jolsa@kernel.org>
	<20251215211402.353056-9-jolsa@kernel.org>
Message-ID: <20251218110602.2e8d4663@gandalf.local.home>

On Mon, 15 Dec 2025 22:14:01 +0100
Jiri Olsa <jolsa at kernel.org> wrote:

> We are going to remove "ftrace_ops->private == bpf_trampoline" setup
> in following changes.
> 
> Adding ip argument to ftrace_ops_func_t callback function, so we can
> use it to look up the trampoline.
> 
> Signed-off-by: Jiri Olsa <jolsa at kernel.org>

This mostly touches bpf code so:

Acked-by: Steven Rostedt (Google) <rostedt at goodmis.org>

-- Steve


From mchehab+huawei at kernel.org  Thu Dec 18 08:04:53 2025
From: mchehab+huawei at kernel.org (Mauro Carvalho Chehab)
Date: Thu, 18 Dec 2025 17:04:53 +0100
Subject: [PATCH 03/12] ras: add estatus vendor handling and processing
In-Reply-To: <20251217112845.1814119-4-ahmed.tiba@arm.com>
References: <20251217112845.1814119-1-ahmed.tiba@arm.com>
	<20251217112845.1814119-4-ahmed.tiba@arm.com>
Message-ID: <20251218170453.23be9049@foz.lan>

Em Wed, 17 Dec 2025 11:28:36 +0000
Ahmed Tiba <ahmed.tiba at arm.com> escreveu:

> Teach the estatus core how to walk CPER records and expose the vendor
> record notification path. This adds the section iteration helpers,
> the logging helpers that mirror the GHES behaviour, and the deferred
> work used to hand vendor GUIDs to interested drivers. No users switch
> over yet; this simply moves the common logic out of GHES so the next
> patches can wire it up.
> 
> Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>

...

> +static bool estatus_handle_arm_hw_error(estatus_generic_data *gdata, int sev, bool sync)

Huh?

This is a CPER record from GHES. Why are you moving CPER code out
of ghes.c, placing in a file named estatus.c? Doesn't make much
sense on my eyes...

Same applies to to other GHES CPER record types.


Thanks,
Mauro


From krzk at kernel.org  Thu Dec 18 08:06:11 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 18 Dec 2025 17:06:11 +0100
Subject: [PATCH v5 3/4] clk: samsung: Implement automatic clock gating
 mode for CMUs
In-Reply-To: <20251114-automatic-clocks-v5-3-efb9202ffcd7@linaro.org>
References: <20251114-automatic-clocks-v5-0-efb9202ffcd7@linaro.org>
 <20251114-automatic-clocks-v5-3-efb9202ffcd7@linaro.org>
Message-ID: <e402ac33-c23a-46a1-b67e-097eb2ea7752@kernel.org>

On 14/11/2025 15:16, Peter Griffin wrote:
> Update exynos_arm64_init_clocks() so that it enables the automatic clock
> mode bits in the CMU option register if the auto_clock_gate flag and
> option_offset fields are set for the CMU. To ensure compatibility with
> older DTs (that specified an incorrect CMU reg size), detect this and
> fallback to manual clock gate mode as the auto clock mode feature depends
> on registers in this area.
> 
> The CMU option register bits are global and effect every clock component in
> the CMU, as such clearing the GATE_ENABLE_HWACG bit and setting GATE_MANUAL
> bit on every gate register is only required if auto_clock_gate is false.
> 
> Additionally if auto_clock_gate is enabled the dynamic root clock gating
> and memclk registers will be configured in the corresponding CMUs sysreg
> bank. These registers are exposed via syscon, so the register
> samsung_clk_save/restore paths are updated to also take a regmap.
> 
> As many gates for various Samsung SoCs are already exposed in the Samsung
> clock drivers a new samsung_auto_clk_gate_ops is implemented. This uses
> some CMU debug registers to report whether clocks are enabled or disabled
> when operating in automatic mode. This allows
> /sys/kernel/debug/clk/clk_summary to still dump the entire clock tree and
> correctly report the status of each clock in the system.
> 
> Signed-off-by: Peter Griffin <peter.griffin at linaro.org>
> ---
> Changes in v3:
> - Add missing 'np' func param to kerneldoc in samsung_cmu_register_clocks
> (0-DAY CI)
> 
> Changes in v2:
> - Fallback to manual clock gate mode for old DTs with incorrect CMU size
> (added samsung_is_auto_capable()) (Krzysztof)
> - Rename OPT_UNKNOWN bit to OPT_EN_LAYER2_CTRL (Andre)
> - Rename OPT_EN_MEM_PM_GATING to OPT_EN_MEM_PWR_GATING (Andre)
> - Reverse Option bit definitions LSB -> MSB (Krzysztof)
> - Update kerneldoc init_clk_regs comment (Andre)
> - Fix space on various comments (Andre)
> - Fix regmap typo on samsung_clk_save/restore calls (Andre)
> - Include error code in pr_err message (Andre)
> - Add macros for dcrg and memclk (Andre)
> - Avoid confusing !IS_ERR_OR_NULL(ctx->sysreg) test (Krzysztof)
> - Update kerneldoc to mention drcg_offset & memclk_offset are in sysreg (Andre)
> - Fix 0-DAY CI randconfig warning (0-DAY CI)
> - Update clk-s5pv210 and clk-s3c64xx.c samsung_clk_sleep_init call sites (Peter)
> ---

This does not apply, please rebase entire set:

Patch failed at 0001 clk: samsung: Implement automatic clock gating mode
for CMUs
error: patch failed: drivers/clk/samsung/clk.c:289
error: drivers/clk/samsung/clk.c: patch does not apply


Best regards,
Krzysztof


From krzk at kernel.org  Thu Dec 18 08:10:45 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 18 Dec 2025 17:10:45 +0100
Subject: (subset) [PATCH v9 0/7] Add DDR4 memory-controller bindings
 and factorise LPDDR and DDR bindings
In-Reply-To: <20251118-b4-ddr-bindings-v9-0-a033ac5144da@gmail.com>
References: <20251118-b4-ddr-bindings-v9-0-a033ac5144da@gmail.com>
Message-ID: <176607424544.18448.1362838186917250806.b4-ty@kernel.org>


On Tue, 18 Nov 2025 16:07:56 +0100, Cl?ment Le Goffic wrote:
> Introduce DDR4 bindings, which is the first DDR type to be added.
> As the DDR and LPDDR use the same properties, factorise them in a
> sdram-props bindings file and rename lpddr-channel into sdram-channel.
> 
> Changes in v9:
> - In the ddr4 compatible pattern :
>     s/ddrX-YYYY,AAAA...,ZZ/ddrX-YYYY,AAAA...-ZZ/
>     The comma before the "ZZ" part has been replaced with a minus.
> - Add information about how the compatible is constructed in the patch 2:
>   "dt-bindings: memory: introduce DDR4"
> - Add Krzysztof Kozlowski's trailer on patch 1
> - Link to v8: https://lore.kernel.org/r/20250930-b4-ddr-bindings-v8-0-fe4d8c015a50 at gmail.com
> 
> [...]

Applied, thanks!

[1/7] dt-bindings: memory: factorise LPDDR props into SDRAM props
      https://git.kernel.org/krzk/linux-mem-ctrl/c/dffaa1beea9e7a0d902fc4e25e137afcf1297267
[2/7] dt-bindings: memory: introduce DDR4
      https://git.kernel.org/krzk/linux-mem-ctrl/c/b5c1a217552c3513977a9f1138b05de0bada8a52
[3/7] dt-bindings: memory: factorise LPDDR channel binding into SDRAM channel
      https://git.kernel.org/krzk/linux-mem-ctrl/c/6ab3581ab19fa348b93c85a793e45cd8a80912a8
[4/7] dt-binding: memory: add DDR4 channel compatible
      https://git.kernel.org/krzk/linux-mem-ctrl/c/36ecc8346747b600892e3040e1d0ecb1e939c6e8
[5/7] dt-bindings: memory: SDRAM channel: standardise node name
      https://git.kernel.org/krzk/linux-mem-ctrl/c/9805f2cfc883018f7bf84c84e3af3786c37dac7b

Best regards,
-- 
Krzysztof Kozlowski <krzk at kernel.org>



From yuanfang.zhang at oss.qualcomm.com  Thu Dec 18 08:18:31 2025
From: yuanfang.zhang at oss.qualcomm.com (yuanfang zhang)
Date: Fri, 19 Dec 2025 00:18:31 +0800
Subject: [PATCH v2 00/12] coresight: Add CPU cluster funnel/replicator/tmc
 support
In-Reply-To: <47191600-260a-46aa-9af8-dff2b08dc2e8@arm.com>
References: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
 <47191600-260a-46aa-9af8-dff2b08dc2e8@arm.com>
Message-ID: <8cb8fad9-c54e-43a3-a769-5452119cc2a1@oss.qualcomm.com>



On 12/18/2025 5:32 PM, Suzuki K Poulose wrote:
> Cc: Sudeep
> 
> On 18/12/2025 08:09, Yuanfang Zhang wrote:
>> This patch series adds support for CoreSight components local to CPU clusters,
>> including funnel, replicator, and TMC, which reside within CPU cluster power
>> domains. These components require special handling due to power domain
>> constraints.
>>
>> Unlike system-level CoreSight devices, these components share the CPU cluster's
>> power domain. When the cluster enters low-power mode (LPM), their registers
>> become inaccessible. Notably, `pm_runtime_get` alone cannot bring the cluster
>> out of LPM, making standard register access unreliable.
> 
> Why ? AFAIU, we have ways to tie the power-domain to that of the cluster
> and that can auto-magically keep the cluster power ON as long as you
> want to use them.
> 
> Suzuki
> 
Hi Suzuki

Runtime PM for CPU devices works little different, it is mostly used to manage hierarchical
CPU topology (PSCI OSI mode) to talk with genpd framework to manage the last CPU handling in
cluster.
It doesn?t really send IPI to wakeup CPU device (It don?t have .power_on/.power_off) callback
implemented which gets invoked from .runtime_resume callback. This behavior is aligned with
the upstream Kernel.

Yuanfang

> 
>>
>> To address this, the series introduces:
>> - Identifying cluster-bound devices via a new `qcom,cpu-bound-components`
>> ?? device tree property.
>> - Implementing deferred probing: if associated CPUs are offline during
>> ?? probe, initialization is deferred until a CPU hotplug notifier detects
>> ?? the CPU coming online.
>> - Utilizing `smp_call_function_single()` to ensure register accesses
>> ?? (initialization, enablement, sysfs reads) are always executed on a
>> ?? powered CPU within the target cluster.
>> - Extending the CoreSight link `enable` callback to pass the `cs_mode`.
>> ?? This allows drivers to distinguish between SysFS and Perf modes and
>> ?? apply mode-specific logic.
>>
>> Jie Gan (1):
>> ?? arm64: dts: qcom: hamoa: add Coresight nodes for APSS debug block
>>
>> Yuanfang Zhang (11):
>> ?? dt-bindings: arm: coresight: Add 'qcom,cpu-bound-components' property
>> ?? coresight: Pass trace mode to link enable callback
>> ?? coresight-funnel: Support CPU cluster funnel initialization
>> ?? coresight-funnel: Defer probe when associated CPUs are offline
>> ?? coresight-replicator: Support CPU cluster replicator initialization
>> ?? coresight-replicator: Defer probe when associated CPUs are offline
>> ?? coresight-replicator: Update management interface for CPU-bound devices
>> ?? coresight-tmc: Support probe and initialization for CPU cluster TMCs
>> ?? coresight-tmc-etf: Refactor enable function for CPU cluster ETF support
>> ?? coresight-tmc: Update management interface for CPU-bound TMCs
>> ?? coresight-tmc: Defer probe when associated CPUs are offline
>>
>> Verification:
>>
>> This series has been verified on sm8750.
>>
>> Test steps for delay probe:
>>
>> 1. limit the system to enable at most 6 CPU cores during boot.
>> 2. echo 1 >/sys/bus/cpu/devices/cpu6/online.
>> 3. check whether ETM6 and ETM7 have been probed.
>>
>> Test steps for sysfs mode:
>>
>> echo 1 >/sys/bus/coresight/devices/tmc_etf0/enable_sink
>> echo 1 >/sys/bus/coresight/devices/etm0/enable_source
>> echo 1 >/sys/bus/coresight/devices/etm6/enable_source
>> echo 0 >/sys/bus/coresight/devices/etm0/enable_source
>> echo 0 >/sys/bus/coresight/devicse/etm6/enable_source
>> echo 0 >/sys/bus/coresight/devices/tmc_etf0/enable_sink
>>
>> echo 1 >/sys/bus/coresight/devices/tmc_etf1/enable_sink
>> echo 1 >/sys/bus/coresight/devcies/etm0/enable_source
>> cat /dev/tmc_etf1 >/tmp/etf1.bin
>> echo 0 >/sys/bus/coresight/devices/etm0/enable_source
>> echo 0 >/sys/bus/coresight/devices/tmc_etf1/enable_sink
>>
>> echo 1 >/sys/bus/coresight/devices/tmc_etf2/enable_sink
>> echo 1 >/sys/bus/coresight/devices/etm6/enable_source
>> cat /dev/tmc_etf2 >/tmp/etf2.bin
>> echo 0 >/sys/bus/coresight/devices/etm6/enable_source
>> echo 0 >/sys/bus/coresight/devices/tmc_etf2/enable_sink
>>
>> Test steps for sysfs node:
>>
>> cat /sys/bus/coresight/devices/tmc_etf*/mgmt/*
>>
>> cat /sys/bus/coresight/devices/funnel*/funnel_ctrl
>>
>> cat /sys/bus/coresight/devices/replicator*/mgmt/*
>>
>> Test steps for perf mode:
>>
>> perf record -a -e cs_etm//k -- sleep 5
>>
>> Signed-off-by: Yuanfang Zhang <yuanfang.zhang at oss.qualcomm.com>
>> ---
>> Changes in v2:
>> - Use the qcom,cpu-bound-components device tree property to identify devices
>> ?? bound to a cluster.
>> - Refactor commit message.
>> - Introduce a supported_cpus field in the drvdata structure to record the CPUs
>> ?? that belong to the cluster where the local component resides.
>> - Link to v1: https://lore.kernel.org/r/20251027-cpu_cluster_component_pm-v1-0-31355ac588c2 at oss.qualcomm.com
>>
>> ---
>> Jie Gan (1):
>> ?????? arm64: dts: qcom: hamoa: Add CoreSight nodes for APSS debug block
>>
>> Yuanfang Zhang (11):
>> ?????? dt-bindings: arm: coresight: Add 'qcom,cpu-bound-components' property
>> ?????? coresight-funnel: Support CPU cluster funnel initialization
>> ?????? coresight-funnel: Defer probe when associated CPUs are offline
>> ?????? coresight-replicator: Support CPU cluster replicator initialization
>> ?????? coresight-replicator: Defer probe when associated CPUs are offline
>> ?????? coresight-replicator: Update management interface for CPU-bound devices
>> ?????? coresight-tmc: Support probe and initialization for CPU cluster TMCs
>> ?????? coresight-tmc-etf: Refactor enable function for CPU cluster ETF support
>> ?????? coresight-tmc: Update management interface for CPU-bound TMCs
>> ?????? coresight-tmc: Defer probe when associated CPUs are offline
>> ?????? coresight: Pass trace mode to link enable callback
>>
>> ? .../bindings/arm/arm,coresight-dynamic-funnel.yaml |?? 5 +
>> ? .../arm/arm,coresight-dynamic-replicator.yaml????? |?? 5 +
>> ? .../devicetree/bindings/arm/arm,coresight-tmc.yaml |?? 5 +
>> ? arch/arm64/boot/dts/qcom/hamoa.dtsi??????????????? | 926 +++++++++++++++++++++
>> ? arch/arm64/boot/dts/qcom/purwa.dtsi??????????????? |? 12 +
>> ? drivers/hwtracing/coresight/coresight-core.c?????? |?? 7 +-
>> ? drivers/hwtracing/coresight/coresight-funnel.c???? | 258 +++++-
>> ? drivers/hwtracing/coresight/coresight-replicator.c | 341 +++++++-
>> ? drivers/hwtracing/coresight/coresight-tmc-core.c?? | 387 +++++++--
>> ? drivers/hwtracing/coresight/coresight-tmc-etf.c??? | 106 ++-
>> ? drivers/hwtracing/coresight/coresight-tmc.h??????? |? 10 +
>> ? drivers/hwtracing/coresight/coresight-tnoc.c?????? |?? 3 +-
>> ? drivers/hwtracing/coresight/coresight-tpda.c?????? |?? 3 +-
>> ? include/linux/coresight.h????????????????????????? |?? 3 +-
>> ? 14 files changed, 1902 insertions(+), 169 deletions(-)
>> ---
>> base-commit: 008d3547aae5bc86fac3eda317489169c3fda112
>> change-id: 20251016-cpu_cluster_component_pm-ce518f510433
>>
>> Best regards,
> 



From rebecca at bsdio.com  Thu Dec 18 08:18:12 2025
From: rebecca at bsdio.com (Rebecca Cran)
Date: Thu, 18 Dec 2025 09:18:12 -0700
Subject: [PATCH v6 0/2] Add device tree for ASRock Rack ALTRAD8 BMC
Message-ID: <20251218161816.38155-1-rebecca@bsdio.com>

The ASRock Rack ALTRAD8 BMC is an Aspeed AST2500-based BMC for the
ALTRAD8UD-1L2T and ALTRAD8UD2-1L2Q boards with an Ampere Altra
processor. The BMC runs OpenBMC.

These patches add a device tree and binding for the BMC.

**Changes between v5 and v6**

- Removed aspeed,external-nodes property.
- Added pinctrl properties to adc node to request the ADC lines used
  for iio-hwmon bridge.

**Testing**

Ran `make ARCH=arm CHECK_DTBS=y aspeed/aspeed-bmc-asrock-altrad8.dtb`.

Rebecca Cran (2):
  dt-bindings: arm: aspeed: add ASRock Rack ALTRAD8 board
  ARM: dts: aspeed: add device tree for ASRock Rack ALTRAD8 BMC

 Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml |   1 +
 arch/arm/boot/dts/aspeed/Makefile                        |   1 +
 arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts   | 637 ++++++++++++++++++++
 3 files changed, 639 insertions(+)
 create mode 100644 arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts

-- 
2.47.3



From rebecca at bsdio.com  Thu Dec 18 08:18:13 2025
From: rebecca at bsdio.com (Rebecca Cran)
Date: Thu, 18 Dec 2025 09:18:13 -0700
Subject: [PATCH v6 1/2] dt-bindings: arm: aspeed: add ASRock Rack ALTRAD8 board
In-Reply-To: <20251218161816.38155-1-rebecca@bsdio.com>
References: <20251218161816.38155-1-rebecca@bsdio.com>
Message-ID: <20251218161816.38155-2-rebecca@bsdio.com>

Document ASRock Rack ALTRAD8 (ALTRAD8UD-1L2T and ALTRAD8UD2-1L2Q)
compatibles.

Signed-off-by: Rebecca Cran <rebecca at bsdio.com>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
Tested-by: Tan Siewert <tan.siewert at hetzner.com>
Reviewed-by: Tan Siewert <tan.siewert at hetzner.com>
---
 Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
index 9298c1a75dd1..aefad2d02993 100644
--- a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
+++ b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
@@ -34,6 +34,7 @@ properties:
               - amd,ethanolx-bmc
               - ampere,mtjade-bmc
               - aspeed,ast2500-evb
+              - asrock,altrad8-bmc
               - asrock,e3c246d4i-bmc
               - asrock,e3c256d4i-bmc
               - asrock,romed8hm3-bmc
-- 
2.47.3



From rebecca at bsdio.com  Thu Dec 18 08:18:14 2025
From: rebecca at bsdio.com (Rebecca Cran)
Date: Thu, 18 Dec 2025 09:18:14 -0700
Subject: [PATCH v6 2/2] ARM: dts: aspeed: add device tree for ASRock Rack ALTRAD8 BMC
In-Reply-To: <20251218161816.38155-1-rebecca@bsdio.com>
References: <20251218161816.38155-1-rebecca@bsdio.com>
Message-ID: <20251218161816.38155-3-rebecca@bsdio.com>

The ALTRAD8 BMC is an Aspeed AST2500-based BMC for the ASRock Rack
ALTRAD8UD-1L2T and ALTRAD8UD2-1L2Q boards.

Signed-off-by: Rebecca Cran <rebecca at bsdio.com>
Tested-by: Tan Siewert <tan.siewert at hetzner.com>
Reviewed-by: Tan Siewert <tan.siewert at hetzner.com>
---
 arch/arm/boot/dts/aspeed/Makefile                      |   1 +
 arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts | 637 ++++++++++++++++++++
 2 files changed, 638 insertions(+)

diff --git a/arch/arm/boot/dts/aspeed/Makefile b/arch/arm/boot/dts/aspeed/Makefile
index 9adf9278dc94..f073f126ddac 100644
--- a/arch/arm/boot/dts/aspeed/Makefile
+++ b/arch/arm/boot/dts/aspeed/Makefile
@@ -9,6 +9,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \
 	aspeed-bmc-ampere-mtjefferson.dtb \
 	aspeed-bmc-ampere-mtmitchell.dtb \
 	aspeed-bmc-arm-stardragon4800-rep2.dtb \
+	aspeed-bmc-asrock-altrad8.dtb \
 	aspeed-bmc-asrock-e3c246d4i.dtb \
 	aspeed-bmc-asrock-e3c256d4i.dtb \
 	aspeed-bmc-asrock-romed8hm3.dtb \
diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts
new file mode 100644
index 000000000000..d4028312bdf2
--- /dev/null
+++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-altrad8.dts
@@ -0,0 +1,637 @@
+// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+
+#include "aspeed-g5.dtsi"
+#include <dt-bindings/gpio/aspeed-gpio.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/i2c/i2c.h>
+
+/ {
+	model = "ASRock ALTRAD8 BMC";
+	compatible = "asrock,altrad8-bmc", "aspeed,ast2500";
+
+	aliases {
+		serial4 = &uart5;
+		i2c50 = &nvme1;
+		i2c51 = &pcie4;
+		i2c52 = &pcie5;
+		i2c53 = &pcie6;
+		i2c54 = &pcie7;
+		i2c55 = &nvme3;
+		i2c56 = &nvme2;
+		i2c57 = &nvme0;
+		i2c58 = &nvme4;
+		i2c59 = &nvme5;
+		i2c60 = &nvme6;
+		i2c61 = &nvme7;
+		i2c62 = &nvme8;
+		i2c63 = &nvme9;
+		i2c64 = &nvme10;
+		i2c65 = &nvme11;
+	};
+
+	chosen {
+		stdout-path = "uart5:115200n8";
+	};
+
+	iio-hwmon {
+		compatible = "iio-hwmon";
+		io-channels =	<&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>,
+				<&adc 4> ,<&adc 5>, <&adc 6>, <&adc 7>,
+				<&adc 8>, <&adc 9>, <&adc 10>, <&adc 11>,
+				<&adc 12>, <&adc 13>, <&adc 14>, <&adc 15>;
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		led-system-fault {
+			gpios = <&gpio ASPEED_GPIO(G,3) GPIO_ACTIVE_LOW>;
+			label = "platform:red:fault";
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_FAULT;
+		};
+
+		led-heartbeat {
+			gpios = <&gpio ASPEED_GPIO(G,0) GPIO_ACTIVE_LOW>;
+			label = "platform:green:heartbeat";
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_INDICATOR;
+			linux,default-trigger = "timer";
+		};
+
+		led-fan1-fault {
+			retain-state-shutdown;
+			default-state = "off";
+			gpios = <&io_expander0 0 GPIO_ACTIVE_LOW>;
+			label = "fan1:red:fault";
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_FAULT;
+		};
+
+		led-fan2-fault {
+			retain-state-shutdown;
+			default-state = "off";
+			gpios = <&io_expander0 1 GPIO_ACTIVE_LOW>;
+			label = "fan2:red:fault";
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_FAULT;
+		};
+
+		led-fan3-fault {
+			retain-state-shutdown;
+			default-state = "off";
+			gpios = <&io_expander0 2 GPIO_ACTIVE_LOW>;
+			label = "fan3:red:fault";
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_FAULT;
+		};
+
+		led-fan4-fault {
+			retain-state-shutdown;
+			default-state = "off";
+			gpios = <&io_expander0 3 GPIO_ACTIVE_LOW>;
+			label = "fan4:red:fault";
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_FAULT;
+		};
+
+		led-fan5-fault {
+			retain-state-shutdown;
+			default-state = "off";
+			gpios = <&io_expander0 4 GPIO_ACTIVE_LOW>;
+			label = "fan5:red:fault";
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_FAULT;
+		};
+	};
+
+	memory at 80000000 {
+		reg = <0x80000000 0x20000000>;
+	};
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		gfx_memory: framebuffer {
+			compatible = "shared-dma-pool";
+			size = <0x01000000>;
+			alignment = <0x01000000>;
+			reusable;
+		};
+
+		vga_memory: framebuffer at 9f000000 {
+			no-map;
+			reg = <0x9f000000 0x01000000>; /* 16M */
+		};
+
+		video_engine_memory: jpegbuffer {
+			compatible = "shared-dma-pool";
+			size = <0x02000000>;	/* 32M */
+			alignment = <0x01000000>;
+			reusable;
+		};
+	};
+};
+
+&adc {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_adc0_default
+		&pinctrl_adc1_default
+		&pinctrl_adc2_default
+		&pinctrl_adc3_default
+		&pinctrl_adc4_default
+		&pinctrl_adc5_default
+		&pinctrl_adc6_default
+		&pinctrl_adc7_default
+		&pinctrl_adc8_default
+		&pinctrl_adc9_default
+		&pinctrl_adc10_default
+		&pinctrl_adc11_default
+		&pinctrl_adc12_default
+		&pinctrl_adc13_default
+		&pinctrl_adc14_default
+		&pinctrl_adc15_default>;
+};
+
+&fmc {
+	status = "okay";
+
+	flash at 0 {
+		label = "bmc";
+		m25p,fast-read;
+		spi-max-frequency = <50000000>;
+		status = "okay";
+#include "openbmc-flash-layout-64.dtsi"
+	};
+};
+
+&gfx {
+	memory-region = <&gfx_memory>;
+	status = "okay";
+};
+
+&gpio {
+	gpio-line-names =
+	/*A0-A7*/	"","","","bmc-ready","","","","",
+	/*B0-B7*/	"i2c-backup-sel","","","","","","","host0-shd-ack-n",
+	/*C0-C7*/	"","","","","","","","",
+	/*D0-D7*/	"button-power-n","control-power-n","button-reset-n",
+			"host0-sysreset-n","","","power-chassis-good","",
+	/*E0-E7*/	"","s0-vrd1-vddq0123-fault-n",
+			"s0-vrd1-vddq4567-fault-n","s0-vrd0-vddc-fault-n",
+			"s0-vrd3-p0v75-fault-n","","","",
+	/*F0-F7*/	"","","ps-atx-on-n","","","","","",
+	/*G0-G7*/	"led-bmc-heartbeat-n","button-identify-n","",
+			"led-system-fault-n","uboot-ready","bmc-salt2-n","","",
+	/*H0-H7*/	"ps-pwr-ok","","","","","","","",
+	/*I0-I7*/	"","","","","","","","",
+	/*J0-J7*/	"s0-hightemp-n","","","","","","","",
+	/*K0-K7*/	"","","","","","","","",
+	/*L0-L7*/	"","","","","","","","",
+	/*M0-M7*/	"cpld-disable-bmc-n","","","","","s0-spi-auth-fail-n","","",
+	/*N0-N7*/	"","","","","","","","",
+	/*O0-O7*/	"","","","","","","","",
+	/*P0-P7*/	"","","","","","","","",
+	/*Q0-Q7*/	"","","","","","","led-identify-n",
+			"chassis-intrusion-n",
+	/*R0-R7*/	"","","ext-hightemp-n","spi0-program-sel","",
+			"output-hwm-bat-en","","",
+	/*S0-S7*/	"s0-vr-hot-n","","input-salt2-n","bmc-sysreset-n","","","","",
+	/*T0-T7*/	"","","","","","","","",
+	/*U0-U7*/	"","","","","","","","",
+	/*V0-V7*/	"","","","","","","","",
+	/*W0-W7*/	"","","","","","","","",
+	/*X0-X7*/	"","","","","","","","",
+	/*Y0-Y7*/	"","","","","","","","",
+	/*Z0-Z7*/	"","","","s0-rtc-lock","","","","",
+	/*AA0-AA7*/	"s0-rtc-int-n","","","","","pmbus-sel-n","","",
+	/*AB0-AB7*/	"host0-reboot-ack-n","s0-sys-auth-failure-n",
+			"","","","","","",
+	/*AC0-AC7*/	"s0-fault-alert","host0-ready","s0-overtemp-n",
+			"","bmc-ok","host0-special-boot","presence-cpu0",
+			"host0-shd-req-n";
+
+	status = "okay";
+};
+
+&i2c0 {
+	status = "okay";
+
+	ipmb at 10 {
+		compatible = "ipmb-dev";
+		reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>;
+		i2c-protocol;
+	};
+
+};
+
+&i2c1 {
+	status = "okay";
+
+	i2c-mux1 at 73 {
+		compatible = "nxp,pca9548";
+		reg = <0x73>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		nvme1: i2c at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+		};
+
+		pcie4: i2c at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+		};
+
+		pcie5: i2c at 2 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2>;
+		};
+
+		pcie6: i2c at 3 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <3>;
+		};
+
+		pcie7: i2c at 4 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <4>;
+		};
+
+		nvme3: i2c at 5 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <5>;
+		};
+
+		nvme2: i2c at 6 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <6>;
+		};
+
+		nvme0: i2c at 7 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <7>;
+		};
+	};
+
+	i2c-mux2 at 75 {
+		compatible = "nxp,pca9548";
+		reg = <0x75>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		nvme4: i2c at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+		};
+
+		nvme5: i2c at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+		};
+
+		nvme6: i2c at 2 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2>;
+		};
+
+		nvme7: i2c at 3 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <3>;
+		};
+
+		nvme8: i2c at 4 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <4>;
+		};
+
+		nvme9: i2c at 5 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <5>;
+		};
+
+		nvme10: i2c at 6 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <6>;
+		};
+
+		nvme11: i2c at 7 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <7>;
+		};
+	};
+};
+
+&i2c2 {
+	status = "okay";
+
+	smpro at 4f {
+		compatible = "ampere,smpro";
+		reg = <0x4f>;
+	};
+};
+
+&i2c3 {
+	status = "okay";
+
+	// PSU FRU
+	eeprom at 38 {
+		compatible = "atmel,24c02";
+		reg = <0x38>;
+	};
+};
+
+&i2c4 {
+	status = "okay";
+
+	temperature-sensor at 29 {
+		compatible = "nuvoton,nct7802";
+		reg = <0x29>;
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		channel at 0 { /* LTD */
+			reg = <0>;
+			status = "okay";
+		};
+
+		channel at 1 { /* RTD1 */
+			reg = <1>;
+			sensor-type = "temperature";
+			temperature-mode = "thermistor";
+		};
+
+		channel at 2 { /* RTD2 */
+			reg = <2>;
+			sensor-type = "temperature";
+			temperature-mode = "thermal-diode";
+		};
+	};
+
+	temperature-sensor at 4c {
+		compatible = "nuvoton,w83773g";
+		reg = <0x4c>;
+	};
+};
+
+&i2c5 {
+	status = "okay";
+};
+
+&i2c6 {
+	status = "okay";
+
+	rtc at 6f {
+		compatible = "isil,isl1208";
+		reg = <0x6f>;
+	};
+};
+
+&i2c7 {
+	status = "okay";
+
+	// BMC FRU
+	eeprom at 57 {
+		compatible = "atmel,24c128";
+		reg = <0x57>;
+
+		nvmem-layout {
+			compatible = "fixed-layout";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			eth1_macaddress: macaddress at 3f80 {
+				reg = <0x3f80 6>;
+			};
+
+			// The offset for eth0 really is at 0x3f88.
+			// eth0 and eth1 are swapped from what might be
+			// expected.
+			eth0_macaddress: macaddress at 3f88 {
+				reg = <0x3f88 6>;
+			};
+		};
+	};
+};
+
+&i2c8 {
+	status = "okay";
+
+	io_expander0: gpio at 1c {
+		compatible = "nxp,pca9557";
+		reg = <0x1c>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+};
+
+&i2c9 {
+	status = "okay";
+};
+
+&i2c10 {
+	status = "okay";
+};
+
+&i2c11 {
+	status = "okay";
+};
+
+// Bus for accessing the SCP EEPROM
+&i2c12 {
+	status = "okay";
+};
+
+&i2c13 {
+	status = "okay";
+
+	ssif-bmc at 10 {
+		compatible = "ssif-bmc";
+		reg = <0x10>;
+	};
+};
+
+// Connected to host Intel X550 (ALTRAD8UD-1L2T) or
+// Broadcom BCM57414 (ALTRAD8UD2-1L2Q) interface.
+// Unconnected on ALTRAD8UD-1L
+&mac0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_rmii1_default>;
+	clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+		 <&syscon ASPEED_CLK_MAC1RCLK>;
+	clock-names = "MACCLK", "RCLK";
+	use-ncsi;
+	nvmem-cells = <&eth0_macaddress>;
+	nvmem-cell-names = "mac-address";
+
+	status = "okay";
+};
+
+// Connected to Realtek RTL8211E
+&mac1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>;
+
+	nvmem-cells = <&eth1_macaddress>;
+	nvmem-cell-names = "mac-address";
+
+	status = "okay";
+};
+
+&pwm_tacho {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pwm0_default
+			&pinctrl_pwm1_default
+			&pinctrl_pwm2_default
+			&pinctrl_pwm3_default
+			&pinctrl_pwm4_default
+			&pinctrl_pwm5_default
+			&pinctrl_pwm6_default
+			&pinctrl_pwm7_default>;
+
+	status = "okay";
+
+	fan at 0 {
+		reg = <0x00>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x00 0x08>;
+	};
+
+	fan at 1 {
+		reg = <0x01>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x01 0x09>;
+	};
+
+	fan at 2 {
+		reg = <0x02>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x02 0x0a>;
+	};
+
+	fan at 3 {
+		reg = <0x03>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x03 0x0b>;
+	};
+
+	fan at 4 {
+		reg = <0x04>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x04 0x0c>;
+	};
+
+	fan at 5 {
+		reg = <0x05>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x05 0x0d>;
+	};
+
+	fan at 6 {
+		reg = <0x06>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x06 0x0e>;
+	};
+
+	fan at 7 {
+		reg = <0x07>;
+		aspeed,fan-tach-ch = /bits/ 8 <0x07 0x0f>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_spi1_default>;
+
+	status = "okay";
+
+	// Host BIOS/UEFI EEPROM
+	flash at 0 {
+		m25p,fast-read;
+		label = "pnor";
+		spi-max-frequency = <100000000>;
+		status = "okay";
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			tfa at 400000 {
+				reg = <0x400000 0x200000>;
+				label = "pnor-tfa";
+			};
+
+			uefi at 600000 {
+				reg = <0x600000 0x1A00000>;
+				label = "pnor-uefi";
+			};
+		};
+	};
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_txd1_default
+			 &pinctrl_rxd1_default
+			 &pinctrl_ncts1_default
+			 &pinctrl_nrts1_default>;
+
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_txd2_default
+			&pinctrl_rxd2_default>;
+
+	status = "okay";
+};
+
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_txd3_default
+			&pinctrl_rxd3_default>;
+
+	status = "okay";
+};
+
+&uart4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_txd4_default
+			&pinctrl_rxd4_default>;
+
+	status = "okay";
+};
+
+// The BMC's uart
+&uart5 {
+	status = "okay";
+};
+
+&vhub {
+	status = "okay";
+};
+
+&video {
+	memory-region = <&video_engine_memory>;
+
+	status = "okay";
+};
-- 
2.47.3



From laurentiumihalcea111 at gmail.com  Thu Dec 18 08:20:05 2025
From: laurentiumihalcea111 at gmail.com (Laurentiu Mihalcea)
Date: Thu, 18 Dec 2025 08:20:05 -0800
Subject: [PATCH v2 1/2] dt-bindings: arm: fsl: Add compatible for i.MX95
 15x15 FRDM board
In-Reply-To: <20251217-127-v2-1-67cb12e56242@nxp.com>
References: <20251217-127-v2-0-67cb12e56242@nxp.com>
 <20251217-127-v2-1-67cb12e56242@nxp.com>
Message-ID: <55d6fb81-5309-463e-a624-dc80f960aa24@gmail.com>


On 12/17/2025 9:56 PM, Lei Xu wrote:
> Introduce a new DT compatible string for the NXP i.MX95 15x15 FRDM
> development board, a compact and cost-effective platform based on
> the i.MX95 applications processor.
>
> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
> Signed-off-by: Lei Xu <lei.xu at nxp.com>
> ---
>  Documentation/devicetree/bindings/arm/fsl.yaml | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
> index 68a2d5fecc43..4b6188d39be6 100644
> --- a/Documentation/devicetree/bindings/arm/fsl.yaml
> +++ b/Documentation/devicetree/bindings/arm/fsl.yaml
> @@ -1432,6 +1432,7 @@ properties:
>          items:
>            - enum:
>                - fsl,imx95-15x15-evk       # i.MX95 15x15 EVK Board
> +              - fsl,imx95-15x15-frdm      # i.MX95 15x15 FRDM Board
>                - fsl,imx95-19x19-evk       # i.MX95 19x19 EVK Board
>                - toradex,verdin-imx95-19x19-evk  # i.MX95 Verdin Evaluation Kit (EVK)
>            - const: fsl,imx95


Reviewed-by: Laurentiu Mihalcea <laurentiu.mihalcea at nxp.com>



From m.felsch at pengutronix.de  Thu Dec 18 08:19:53 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Thu, 18 Dec 2025 17:19:53 +0100
Subject: [PATCH 2/2] arm64: dts: imx93-phyboard-segin: Add peb-av-02
 overlay
In-Reply-To: <09a773bb51331940e76fbeb5e8128c183bf6d621.camel@phytec.de>
References: <20251202-v6-18-topic-imx93-phyboard-segin-av-02-display-v1-0-9c14be6c7478@pengutronix.de>
 <20251202-v6-18-topic-imx93-phyboard-segin-av-02-display-v1-2-9c14be6c7478@pengutronix.de>
 <15bb2331-713a-4b6a-ae9a-4870066e84dc@norik.com>
 <20251215170750.j2l6gnbocmhdloe6@pengutronix.de>
 <09a773bb51331940e76fbeb5e8128c183bf6d621.camel@phytec.de>
Message-ID: <20251218161953.wjiruxqmib7lchol@pengutronix.de>

On 25-12-16, Christoph Stoidner wrote:
> Hi Marco,
> 
> On Mo, 2025-12-15 at 18:07 +0100, Marco Felsch wrote:
> > Hi Primoz,
> > 
> > On 25-12-03, Primoz Fiser wrote:

...

> > > > +	touchscreen at 38 {
> > > > +		compatible = "edt,edt-ft5406";
> > > > +		reg = <0x38>;
> > > > +		pinctrl-names = "default";
> > > > +		pinctrl-0 = <&pinctrl_touchscreen>;
> > > > +		interrupt-parent = <&gpio4>;
> > > > +		interrupts = <12 IRQ_TYPE_EDGE_FALLING>;
> > > > +		reset-gpios = <&gpio4 1 GPIO_ACTIVE_LOW>;
> > > > +		touchscreen-size-x = <1792>;
> > > > +		touchscreen-size-y = <1024>;
> > > 
> > > Please add "wakeup-source" property here like in the downstream
> > > commit.
> > > 
> > > With this in place, panel touch can be used to wake up the board
> > > from sleep.
> > 
> > Is this a required feature? Touchscreens with no certain
> > low-power mode handlig (e.g. reduced scanning time) can draw much
> > power
> > in suspend.
> > 
> > I can add it if Phytec is aware of this fact and still wants to have
> > thsi feature.
> 
> Yes, please add this "wakeup-source" property again. This feature?
> shall?work on our platform by default. And one who wants to avoid
> touchscreen as wakeup-source can modify the device-tree or disable?
> it?for wakeup via policy/sysfs.

Okay, I added the property for the v2.

Regards,
  Marco


From krzk at kernel.org  Thu Dec 18 08:21:22 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 18 Dec 2025 17:21:22 +0100
Subject: [PATCH v6 1/2] dt-bindings: arm: aspeed: add ASRock Rack ALTRAD8
 board
In-Reply-To: <20251218161816.38155-2-rebecca@bsdio.com>
References: <20251218161816.38155-1-rebecca@bsdio.com>
 <20251218161816.38155-2-rebecca@bsdio.com>
Message-ID: <5aa36c56-798a-40cc-b0b8-be3f7c92136f@kernel.org>

On 18/12/2025 17:18, Rebecca Cran wrote:
> Document ASRock Rack ALTRAD8 (ALTRAD8UD-1L2T and ALTRAD8UD2-1L2Q)
> compatibles.
> 
> Signed-off-by: Rebecca Cran <rebecca at bsdio.com>
> Acked-by: Conor Dooley <conor.dooley at microchip.com>
> Tested-by: Tan Siewert <tan.siewert at hetzner.com>

How was the binding tested?


Best regards,
Krzysztof


From Ryan.Wanner at microchip.com  Thu Dec 18 08:23:12 2025
From: Ryan.Wanner at microchip.com (Ryan.Wanner at microchip.com)
Date: Thu, 18 Dec 2025 16:23:12 +0000
Subject: [PATCH v4 11/31] clk: at91: clk-usb: add support for
 clk_parent_data
In-Reply-To: <27aab227-01e3-4074-8aab-38623b4d9808@tuxon.dev>
References: <cover.1758226719.git.Ryan.Wanner@microchip.com>
 <6979b3734462c97381159f3968a3f22b6193e04d.1758226719.git.Ryan.Wanner@microchip.com>
 <27aab227-01e3-4074-8aab-38623b4d9808@tuxon.dev>
Message-ID: <14ea374c-2889-4bc5-b0c9-fb5b5498593e@microchip.com>

On 10/20/25 12:17, Claudiu Beznea wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
> Hi, Ryan,
> 
> On 9/19/25 00:15, Ryan.Wanner at microchip.com wrote:
>> From: Claudiu Beznea <claudiu.beznea at tuxon.dev>
>>
>> Add support for clk_parent_data in usb clock driver.
>>
>> All the SoC based drivers that rely on clk-usb were adapted
>> to the new API change. The switch itself for SoCs will be done
>> in subsequent patches.
>>
>> Remove the use of __clk_get_hw() for the slow clocks.
>>
>> Signed-off-by: Claudiu Beznea <claudiu.beznea at tuxon.dev>
>> [ryan.wanner at microchip: Add SAMA7D65 and SAM9X75 SoCs to the changes.
>> Change how the main_xtal and slcks are initialized so they match the
>> parent_data API]
>> Signed-off-by: Ryan Wanner <Ryan.Wanner at microchip.com>
>> ---
>>  drivers/clk/at91/at91rm9200.c  |  2 +-
>>  drivers/clk/at91/at91sam9260.c |  2 +-
>>  drivers/clk/at91/at91sam9g45.c |  2 +-
>>  drivers/clk/at91/at91sam9n12.c |  2 +-
>>  drivers/clk/at91/at91sam9x5.c  |  2 +-
>>  drivers/clk/at91/clk-usb.c     | 41 ++++++++++++++++++++++------------
>>  drivers/clk/at91/dt-compat.c   |  6 ++---
>>  drivers/clk/at91/pmc.h         | 11 +++++----
>>  drivers/clk/at91/sam9x60.c     |  2 +-
>>  drivers/clk/at91/sam9x7.c      | 21 +++++++++--------
>>  drivers/clk/at91/sama5d2.c     |  2 +-
>>  drivers/clk/at91/sama5d3.c     |  2 +-
>>  drivers/clk/at91/sama5d4.c     |  2 +-
>>  drivers/clk/at91/sama7d65.c    | 24 +++++++++++---------
>>  14 files changed, 72 insertions(+), 49 deletions(-)
>>
> 
> [ ... ]
> 
>> @@ -882,10 +885,10 @@ static void __init sam9x7_pmc_setup(struct device_node *np)
>>
>>       sam9x7_pmc->chws[PMC_MCK] = hw;
>>
>> -     parent_names[0] = "plla_divpmcck";
>> -     parent_names[1] = "upll_divpmcck";
>> -     parent_names[2] = "main_osc";
>> -     usbck_hw = sam9x60_clk_register_usb(regmap, "usbck", parent_names, 3);
>> +     parent_data[0] = AT91_CLK_PD_HW(sam9x7_plls[PLL_ID_PLLA][PLL_COMPID_DIV0].hw);
>> +     parent_data[1] = AT91_CLK_PD_HW(sam9x7_plls[PLL_ID_UPLL][PLL_COMPID_DIV0].hw);
>> +     parent_data[2] = AT91_CLK_PD_HW(main_osc_hw);
>> +     usbck_hw = sam9x60_clk_register_usb(regmap, "usbck", NULL, parent_data, 3);
> 
> sam9x60_clk_register_usb() could be converted to use parent_hws member of
> struct clk_init_data instead of parent_data.

So this would mean that I would pass in an array of the plls as
parent_hws, and use that to load the clk_init_data struct instead of
filling the array of parent_data as it is changed to in this patch set?

And this would be functionally the same since parent_data points to
clk_hw?>


From andrew at lunn.ch  Thu Dec 18 08:24:14 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Thu, 18 Dec 2025 17:24:14 +0100
Subject: [PATCH 5/6] arm64: dts: Add TQ imx8qm based board
In-Reply-To: <20251218154412.1524249-1-alexander.stein@ew.tq-group.com>
References: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
 <20251218154412.1524249-1-alexander.stein@ew.tq-group.com>
Message-ID: <e9d1495f-0d61-4e23-89c9-f06373b52bc0@lunn.ch>

> +&fec1 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_fec1>;
> +	phy-mode = "rgmii-id";
> +	phy-handle = <&ethphy0>;
> +	nvmem-cells = <&fec_mac0>;
> +	nvmem-cell-names = "mac-address";
> +	fsl,magic-packet;

I might be repeating myself here...

Have you tested WoL? Does it work? Or is this just copy/paste from an
example?

We have a lot of DT blobs which suggest WoL should work, but it does
not. It is something we need to improve.

Thanks
	Andrew


From rostedt at goodmis.org  Thu Dec 18 08:26:08 2025
From: rostedt at goodmis.org (Steven Rostedt)
Date: Thu, 18 Dec 2025 11:26:08 -0500
Subject: [PATCHv5 bpf-next 9/9] bpf,x86: Use single ftrace_ops for
 direct calls
In-Reply-To: <20251215211402.353056-10-jolsa@kernel.org>
References: <20251215211402.353056-1-jolsa@kernel.org>
	<20251215211402.353056-10-jolsa@kernel.org>
Message-ID: <20251218112608.11a14a4a@gandalf.local.home>

On Mon, 15 Dec 2025 22:14:02 +0100
Jiri Olsa <jolsa at kernel.org> wrote:

> Using single ftrace_ops for direct calls update instead of allocating
> ftrace_ops object for each trampoline.
> 
> With single ftrace_ops object we can use update_ftrace_direct_* api
> that allows multiple ip sites updates on single ftrace_ops object.
> 
> Adding HAVE_SINGLE_FTRACE_DIRECT_OPS config option to be enabled on
> each arch that supports this.
> 
> At the moment we can enable this only on x86 arch, because arm relies
> on ftrace_ops object representing just single trampoline image (stored
> in ftrace_ops::direct_call). Ach that do not support this will continue

My back "Ach" and doesn't support me well. ;-)

> to use *_ftrace_direct api.
> 
> Signed-off-by: Jiri Olsa <jolsa at kernel.org>
> ---
>  arch/x86/Kconfig        |   1 +
>  kernel/bpf/trampoline.c | 195 ++++++++++++++++++++++++++++++++++------
>  kernel/trace/Kconfig    |   3 +
>  kernel/trace/ftrace.c   |   7 +-
>  4 files changed, 177 insertions(+), 29 deletions(-)
> 
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index 17a107cc5244..d0c36e49e66e 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -335,6 +335,7 @@ config X86
>  	select SCHED_SMT			if SMP
>  	select ARCH_SUPPORTS_SCHED_CLUSTER	if SMP
>  	select ARCH_SUPPORTS_SCHED_MC		if SMP
> +	select HAVE_SINGLE_FTRACE_DIRECT_OPS	if X86_64 && DYNAMIC_FTRACE_WITH_DIRECT_CALLS

You can remove the "&& DYNAMIC_FTRACE_WITH_DIRECT_CALLS" part by having the
config depend on it (see below).

>  
>  config INSTRUCTION_DECODER
>  	def_bool y
> diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
> index 17af2aad8382..02371db3db3e 100644
> --- a/kernel/bpf/trampoline.c
> +++ b/kernel/bpf/trampoline.c
> @@ -33,12 +33,40 @@ static DEFINE_MUTEX(trampoline_mutex);
>  #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
>  static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mutex);
>  
> +#ifdef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS

Make this:

 #ifdef CONFIG_SINGLE_FTRACE_DIRECT_OPS

for the suggested modification in the Kconfig below.

> +static struct bpf_trampoline *direct_ops_ip_lookup(struct ftrace_ops *ops, unsigned long ip)
> +{
> +	struct hlist_head *head_ip;
> +	struct bpf_trampoline *tr;
> +
> +	mutex_lock(&trampoline_mutex);

	guard(mutex)(&trampoline_mutex);

> +	head_ip = &trampoline_ip_table[hash_64(ip, TRAMPOLINE_HASH_BITS)];
> +	hlist_for_each_entry(tr, head_ip, hlist_ip) {
> +		if (tr->ip == ip)

			return NULL;

> +			goto out;
> +	}


> +	tr = NULL;
> +out:
> +	mutex_unlock(&trampoline_mutex);

No need for the above

> +	return tr;
> +}
> +#else
> +static struct bpf_trampoline *direct_ops_ip_lookup(struct ftrace_ops *ops, unsigned long ip)
> +{
> +	return ops->private;
> +}
> +#endif /* CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS */
> +
>  static int bpf_tramp_ftrace_ops_func(struct ftrace_ops *ops, unsigned long ip,
>  				     enum ftrace_ops_cmd cmd)
>  {
> -	struct bpf_trampoline *tr = ops->private;
> +	struct bpf_trampoline *tr;
>  	int ret = 0;
>  
> +	tr = direct_ops_ip_lookup(ops, ip);
> +	if (!tr)
> +		return -EINVAL;
> +
>  	if (cmd == FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_SELF) {
>  		/* This is called inside register_ftrace_direct_multi(), so
>  		 * tr->mutex is already locked.
> @@ -137,6 +165,139 @@ void bpf_image_ksym_del(struct bpf_ksym *ksym)
>  			   PAGE_SIZE, true, ksym->name);
>  }
>  
> +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
> +#ifdef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS

Replace the above two with:

 #ifdef CONFIG_SINGLE_FTRACE_DIRECT_OPS

> +/*
> + * We have only single direct_ops which contains all the direct call
> + * sites and is the only global ftrace_ops for all trampolines.
> + *
> + * We use 'update_ftrace_direct_*' api for attachment.
> + */
> +struct ftrace_ops direct_ops = {
> +	.ops_func = bpf_tramp_ftrace_ops_func,
> +};
> +
> +static int direct_ops_alloc(struct bpf_trampoline *tr)
> +{
> +	tr->fops = &direct_ops;
> +	return 0;
> +}
> +
> +static void direct_ops_free(struct bpf_trampoline *tr) { }
> +
> +static struct ftrace_hash *hash_from_ip(struct bpf_trampoline *tr, void *ptr)
> +{
> +	unsigned long ip, addr = (unsigned long) ptr;
> +	struct ftrace_hash *hash;
> +
> +	ip = ftrace_location(tr->ip);
> +	if (!ip)
> +		return NULL;
> +	hash = alloc_ftrace_hash(FTRACE_HASH_DEFAULT_BITS);
> +	if (!hash)
> +		return NULL;
> +	if (bpf_trampoline_use_jmp(tr->flags))
> +		addr = ftrace_jmp_set(addr);
> +	if (!add_hash_entry_direct(hash, ip, addr)) {
> +		free_ftrace_hash(hash);
> +		return NULL;
> +	}
> +	return hash;
> +}
> +
> +static int direct_ops_add(struct bpf_trampoline *tr, void *addr)
> +{
> +	struct ftrace_hash *hash = hash_from_ip(tr, addr);
> +	int err = -ENOMEM;
> +
> +	if (hash)
> +		err = update_ftrace_direct_add(tr->fops, hash);
> +	free_ftrace_hash(hash);
> +	return err;
> +}

I think these functions would be cleaner as:

{
	struct ftrace_hash *hash = hash_from_ip(tr, addr);
	int err;

	if (!hash)
		return -ENOMEM;

	err = update_ftrace_direct_*(tr->fops, hash);
	free_ftrace_hash(hash);
	return err;
}


> +
> +static int direct_ops_del(struct bpf_trampoline *tr, void *addr)
> +{
> +	struct ftrace_hash *hash = hash_from_ip(tr, addr);
> +	int err = -ENOMEM;
> +
> +	if (hash)
> +		err = update_ftrace_direct_del(tr->fops, hash);
> +	free_ftrace_hash(hash);
> +	return err;
> +}
> +
> +static int direct_ops_mod(struct bpf_trampoline *tr, void *addr, bool lock_direct_mutex)
> +{
> +	struct ftrace_hash *hash = hash_from_ip(tr, addr);
> +	int err = -ENOMEM;
> +
> +	if (hash)
> +		err = update_ftrace_direct_mod(tr->fops, hash, lock_direct_mutex);
> +	free_ftrace_hash(hash);
> +	return err;
> +}
> +#else
> +/*
> + * We allocate ftrace_ops object for each trampoline and it contains
> + * call site specific for that trampoline.
> + *
> + * We use *_ftrace_direct api for attachment.
> + */
> +static int direct_ops_alloc(struct bpf_trampoline *tr)
> +{
> +	tr->fops = kzalloc(sizeof(struct ftrace_ops), GFP_KERNEL);
> +	if (!tr->fops)
> +		return -ENOMEM;
> +	tr->fops->private = tr;
> +	tr->fops->ops_func = bpf_tramp_ftrace_ops_func;
> +	return 0;
> +}
> +
> +static void direct_ops_free(struct bpf_trampoline *tr)
> +{
> +	if (tr->fops) {
> +		ftrace_free_filter(tr->fops);
> +		kfree(tr->fops);
> +	}
> +}

Why not:

static void direct_ops_free(struct bpf_trampoline *tr)
{
	if (!tr->fops)
		return;

	ftrace_free_filter(tr->fops);
	kfree(tr->fops);
}

 ?

> +
> +static int direct_ops_add(struct bpf_trampoline *tr, void *ptr)
> +{
> +	unsigned long addr = (unsigned long) ptr;
> +	struct ftrace_ops *ops = tr->fops;
> +	int ret;
> +
> +	if (bpf_trampoline_use_jmp(tr->flags))
> +		addr = ftrace_jmp_set(addr);
> +
> +	ret = ftrace_set_filter_ip(ops, tr->ip, 0, 1);
> +	if (ret)
> +		return ret;
> +	return register_ftrace_direct(ops, addr);
> +}
> +
> +static int direct_ops_del(struct bpf_trampoline *tr, void *addr)
> +{
> +	return unregister_ftrace_direct(tr->fops, (long)addr, false);
> +}
> +
> +static int direct_ops_mod(struct bpf_trampoline *tr, void *ptr, bool lock_direct_mutex)
> +{
> +	unsigned long addr = (unsigned long) ptr;
> +	struct ftrace_ops *ops = tr->fops;
> +
> +	if (bpf_trampoline_use_jmp(tr->flags))
> +		addr = ftrace_jmp_set(addr);
> +	if (lock_direct_mutex)
> +		return modify_ftrace_direct(ops, addr);
> +	return modify_ftrace_direct_nolock(ops, addr);
> +}
> +#endif /* CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS */
> +#else
> +static void direct_ops_free(struct bpf_trampoline *tr) { }

This is somewhat inconsistent with direct_ops_alloc() that has:

#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
	if (direct_ops_alloc(tr)) {
		kfree(tr);
		tr = NULL;
		goto out;
	}
#endif

Now, if you wrap the direct_ops_free() too, we can remove the
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
part with my kconfig suggestion. Otherwise keep the kconfig as is, but I
would add a stub function for direct_ops_alloc() too.

> +#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
> +
>  static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
>  {
>  	struct bpf_trampoline *tr;
> @@ -155,14 +316,11 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
>  	if (!tr)
>  		goto out;
>  #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
> -	tr->fops = kzalloc(sizeof(struct ftrace_ops), GFP_KERNEL);
> -	if (!tr->fops) {
> +	if (direct_ops_alloc(tr)) {
>  		kfree(tr);
>  		tr = NULL;
>  		goto out;
>  	}
> -	tr->fops->private = tr;
> -	tr->fops->ops_func = bpf_tramp_ftrace_ops_func;
>  #endif
>  
>  	tr->key = key;
> @@ -206,7 +364,7 @@ static int unregister_fentry(struct bpf_trampoline *tr, u32 orig_flags,
>  	int ret;
>  
>  	if (tr->func.ftrace_managed)
> -		ret = unregister_ftrace_direct(tr->fops, (long)old_addr, false);
> +		ret = direct_ops_del(tr, old_addr);

Doesn't this need a wrapper too?

>  	else
>  		ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr, NULL);
>  
> @@ -220,15 +378,7 @@ static int modify_fentry(struct bpf_trampoline *tr, u32 orig_flags,
>  	int ret;
>  
>  	if (tr->func.ftrace_managed) {
> -		unsigned long addr = (unsigned long) new_addr;
> -
> -		if (bpf_trampoline_use_jmp(tr->flags))
> -			addr = ftrace_jmp_set(addr);
> -
> -		if (lock_direct_mutex)
> -			ret = modify_ftrace_direct(tr->fops, addr);
> -		else
> -			ret = modify_ftrace_direct_nolock(tr->fops, addr);
> +		ret = direct_ops_mod(tr, new_addr, lock_direct_mutex);

and this.

>  	} else {
>  		ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr,
>  						   new_addr);
> @@ -251,15 +401,7 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
>  	}
>  
>  	if (tr->func.ftrace_managed) {
> -		unsigned long addr = (unsigned long) new_addr;
> -
> -		if (bpf_trampoline_use_jmp(tr->flags))
> -			addr = ftrace_jmp_set(addr);
> -
> -		ret = ftrace_set_filter_ip(tr->fops, (unsigned long)ip, 0, 1);
> -		if (ret)
> -			return ret;
> -		ret = register_ftrace_direct(tr->fops, addr);
> +		ret = direct_ops_add(tr, new_addr);

Ditto.

>  	} else {
>  		ret = bpf_trampoline_update_fentry(tr, 0, NULL, new_addr);
>  	}
> @@ -910,10 +1052,7 @@ void bpf_trampoline_put(struct bpf_trampoline *tr)
>  	 */
>  	hlist_del(&tr->hlist_key);
>  	hlist_del(&tr->hlist_ip);
> -	if (tr->fops) {
> -		ftrace_free_filter(tr->fops);
> -		kfree(tr->fops);
> -	}
> +	direct_ops_free(tr);
>  	kfree(tr);
>  out:
>  	mutex_unlock(&trampoline_mutex);
> diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
> index 4661b9e606e0..1ad2e307c834 100644
> --- a/kernel/trace/Kconfig
> +++ b/kernel/trace/Kconfig
> @@ -50,6 +50,9 @@ config HAVE_DYNAMIC_FTRACE_WITH_REGS
>  config HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
>  	bool
>  
> +config HAVE_SINGLE_FTRACE_DIRECT_OPS
> +	bool
> +

Now you could add:

  config SINGLE_FTRACE_DIRECT_OPS
	bool
	default y
	depends on HAVE_SINGLE_FTRACE_DIRECT_OPS && DYNAMIC_FTRACE_WITH_DIRECT_CALLS

-- Steve


>  config HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS
>  	bool 
>  
> diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
> index c2054fe80de7..a0789727b971 100644
> --- a/kernel/trace/ftrace.c
> +++ b/kernel/trace/ftrace.c
> @@ -2605,8 +2605,13 @@ unsigned long ftrace_find_rec_direct(unsigned long ip)
>  static void call_direct_funcs(unsigned long ip, unsigned long pip,
>  			      struct ftrace_ops *ops, struct ftrace_regs *fregs)
>  {
> -	unsigned long addr = READ_ONCE(ops->direct_call);
> +	unsigned long addr;
>  
> +#ifdef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS
> +	addr = ftrace_find_rec_direct(ip);
> +#else
> +	addr = READ_ONCE(ops->direct_call);
> +#endif
>  	if (!addr)
>  		return;
>  



From laurentiumihalcea111 at gmail.com  Thu Dec 18 08:26:34 2025
From: laurentiumihalcea111 at gmail.com (Laurentiu Mihalcea)
Date: Thu, 18 Dec 2025 08:26:34 -0800
Subject: [PATCH v2 2/2] arm64: dts: freescale: imx95: Add support for
 i.MX95 15x15 FRDM board
In-Reply-To: <20251217-127-v2-2-67cb12e56242@nxp.com>
References: <20251217-127-v2-0-67cb12e56242@nxp.com>
 <20251217-127-v2-2-67cb12e56242@nxp.com>
Message-ID: <3e449b21-5ffb-4a6a-b0c4-e9f381334883@gmail.com>


On 12/17/2025 9:56 PM, Lei Xu wrote:
> The i.MX95 15x15 FRDM board is a compact and cost-effective development
> platform based on the i.MX95 applications processor.
>
> Add device tree support for this board, including:
>  - LPUART1 and LPUART5
>  - NETC
>  - USB
>  - PCIe
>  - uSDHC1, uSDHC2 and uSDHC3
>  - FlexCAN2 and FlexCAN5
>  - LPI2C2, LPI2C3, LPI2C4 and their child nodes
>  - Watchdog3
>
> Signed-off-by: Lei Xu <lei.xu at nxp.com>
> ---
> Changes in v2:
> - Switched from 'xceiver-supply' to CAN PHY nodes using 'phys'.
> - Added CAN PHY nodes for flexcan2/5 with shared silent-gpio, removed reg_can_stby.
> - Updated MSI/IOMMU mapping comment to match the i.MX95 15x15 FRDM board.
> ---
>  arch/arm64/boot/dts/freescale/Makefile             |   1 +
>  arch/arm64/boot/dts/freescale/imx95-15x15-frdm.dts | 963 +++++++++++++++++++++
>  2 files changed, 964 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
> index f30d3fd724d0..71308d19d35e 100644
> --- a/arch/arm64/boot/dts/freescale/Makefile
> +++ b/arch/arm64/boot/dts/freescale/Makefile
> @@ -400,6 +400,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx93-tqma9352-mba93xxla.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx93-var-som-symphony.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx943-evk.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx95-15x15-evk.dtb
> +dtb-$(CONFIG_ARCH_MXC) += imx95-15x15-frdm.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx95-19x19-evk.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx95-19x19-evk-sof.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx95-toradex-smarc-dev.dtb
> diff --git a/arch/arm64/boot/dts/freescale/imx95-15x15-frdm.dts b/arch/arm64/boot/dts/freescale/imx95-15x15-frdm.dts
> new file mode 100644
> index 000000000000..414ebdacc3cb
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx95-15x15-frdm.dts
> @@ -0,0 +1,963 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright 2025 NXP
> + */
> +
> +/dts-v1/;
> +
> +#include <dt-bindings/leds/common.h>
> +#include <dt-bindings/phy/phy-imx8-pcie.h>
> +#include <dt-bindings/pwm/pwm.h>
> +#include <dt-bindings/usb/pd.h>
> +#include "imx95.dtsi"
> +
> +#define BRD_SM_CTRL_SD3_WAKE		0x8000	/*!< PCAL6408A-0 */
> +#define BRD_SM_CTRL_PCIE1_WAKE		0x8001	/*!< PCAL6408A-4 */
> +#define BRD_SM_CTRL_BT_WAKE		0x8002	/*!< PCAL6408A-5 */
> +#define BRD_SM_CTRL_PCIE2_WAKE		0x8003	/*!< PCAL6408A-6 */
> +#define BRD_SM_CTRL_BUTTON		0x8004	/*!< PCAL6408A-7 */
> +
> +/ {
> +	compatible = "fsl,imx95-15x15-frdm", "fsl,imx95";
> +	model = "NXP i.MX95 15X15 FRDM board";
> +
> +	aliases {
> +		ethernet0 = &enetc_port0;
> +		ethernet1 = &enetc_port1;
> +		gpio0 = &gpio1;
> +		gpio1 = &gpio2;
> +		gpio2 = &gpio3;
> +		gpio3 = &gpio4;
> +		gpio4 = &gpio5;
> +		i2c0 = &lpi2c1;
> +		i2c1 = &lpi2c2;
> +		i2c2 = &lpi2c3;
> +		i2c3 = &lpi2c4;
> +		i2c4 = &lpi2c5;
> +		i2c5 = &lpi2c6;
> +		i2c6 = &lpi2c7;
> +		i2c7 = &lpi2c8;
> +		mmc0 = &usdhc1;
> +		mmc1 = &usdhc2;
> +		mmc2 = &usdhc3;
> +		serial0 = &lpuart1;
> +		serial4 = &lpuart5;
> +	};
> +
> +	


(snip)


> +
> +	sound-micfil {
> +		compatible = "fsl,imx-audio-card";
> +		model = "micfil-audio";
> +
> +		pri-dai-link {
> +			link-name = "micfil hifi";
> +			format = "i2s";
> +
> +			cpu {
> +				sound-dai = <&micfil>;
> +			};


please add a space in between the definitions of the cpu and codec nodes. With that:


Reviewed-by: Laurentiu Mihalcea <laurentiu.mihalcea at nxp.com>


> +			codec {
> +				sound-dai = <&dmic>;
> +			};
> +		};
> +	};
> +
> +	usdhc3_pwrseq: usdhc3-pwrseq {
> +		compatible = "mmc-pwrseq-simple";
> +		reset-gpios = <&pcal6524 8 GPIO_ACTIVE_LOW>;
> +	};


From jens.wiklander at linaro.org  Thu Dec 18 08:29:11 2025
From: jens.wiklander at linaro.org (Jens Wiklander)
Date: Thu, 18 Dec 2025 17:29:11 +0100
Subject: [PATCH v2 00/17] tee: Use bus callbacks instead of driver callbacks
In-Reply-To: <20251218135332f323fa91@mail.local>
References: <cover.1765791463.git.u.kleine-koenig@baylibre.com>
 <CAHUa44FrDZbvRvfN8obf80_k=Eqxe9YxHpjaE5jU7nkxPUwfag@mail.gmail.com> <20251218135332f323fa91@mail.local>
Message-ID: <CAHUa44GpW5aO26GDyL9RZub9vVYvVcJ7etwO0yXBN_mUi0W4AA@mail.gmail.com>

On Thu, Dec 18, 2025 at 2:53?PM Alexandre Belloni
<alexandre.belloni at bootlin.com> wrote:
>
> On 18/12/2025 08:21:27+0100, Jens Wiklander wrote:
> > Hi,
> >
> > On Mon, Dec 15, 2025 at 3:17?PM Uwe Kleine-K?nig
> > <u.kleine-koenig at baylibre.com> wrote:
> > >
> > > Hello,
> > >
> > > the objective of this series is to make tee driver stop using callbacks
> > > in struct device_driver. These were superseded by bus methods in 2006
> > > (commit 594c8281f905 ("[PATCH] Add bus_type probe, remove, shutdown
> > > methods.")) but nobody cared to convert all subsystems accordingly.
> > >
> > > Here the tee drivers are converted. The first commit is somewhat
> > > unrelated, but simplifies the conversion (and the drivers). It
> > > introduces driver registration helpers that care about setting the bus
> > > and owner. (The latter is missing in all drivers, so by using these
> > > helpers the drivers become more correct.)
> > >
> > > v1 of this series is available at
> > > https://lore.kernel.org/all/cover.1765472125.git.u.kleine-koenig at baylibre.com
> > >
> > > Changes since v1:
> > >
> > >  - rebase to v6.19-rc1 (no conflicts)
> > >  - add tags received so far
> > >  - fix whitespace issues pointed out by Sumit Garg
> > >  - fix shutdown callback to shutdown and not remove
> > >
> > > As already noted in v1's cover letter, this series should go in during a
> > > single merge window as there are runtime warnings when the series is
> > > only applied partially. Sumit Garg suggested to apply the whole series
> > > via Jens Wiklander's tree.
> > > If this is done the dependencies in this series are honored, in case the
> > > plan changes: Patches #4 - #17 depend on the first two.
> > >
> > > Note this series is only build tested.
> > >
> > > Uwe Kleine-K?nig (17):
> > >   tee: Add some helpers to reduce boilerplate for tee client drivers
> > >   tee: Add probe, remove and shutdown bus callbacks to tee_client_driver
> > >   tee: Adapt documentation to cover recent additions
> > >   hwrng: optee - Make use of module_tee_client_driver()
> > >   hwrng: optee - Make use of tee bus methods
> > >   rtc: optee: Migrate to use tee specific driver registration function
> > >   rtc: optee: Make use of tee bus methods
> > >   efi: stmm: Make use of module_tee_client_driver()
> > >   efi: stmm: Make use of tee bus methods
> > >   firmware: arm_scmi: optee: Make use of module_tee_client_driver()
> > >   firmware: arm_scmi: Make use of tee bus methods
> > >   firmware: tee_bnxt: Make use of module_tee_client_driver()
> > >   firmware: tee_bnxt: Make use of tee bus methods
> > >   KEYS: trusted: Migrate to use tee specific driver registration
> > >     function
> > >   KEYS: trusted: Make use of tee bus methods
> > >   tpm/tpm_ftpm_tee: Make use of tee specific driver registration
> > >   tpm/tpm_ftpm_tee: Make use of tee bus methods
> > >
> > >  Documentation/driver-api/tee.rst             | 18 +----
> > >  drivers/char/hw_random/optee-rng.c           | 26 ++----
> > >  drivers/char/tpm/tpm_ftpm_tee.c              | 31 +++++---
> > >  drivers/firmware/arm_scmi/transports/optee.c | 32 +++-----
> > >  drivers/firmware/broadcom/tee_bnxt_fw.c      | 30 ++-----
> > >  drivers/firmware/efi/stmm/tee_stmm_efi.c     | 25 ++----
> > >  drivers/rtc/rtc-optee.c                      | 27 ++-----
> > >  drivers/tee/tee_core.c                       | 84 ++++++++++++++++++++
> > >  include/linux/tee_drv.h                      | 12 +++
> > >  security/keys/trusted-keys/trusted_tee.c     | 17 ++--
> > >  10 files changed, 164 insertions(+), 138 deletions(-)
> > >
> > > base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
> > > --
> > > 2.47.3
> > >
> >
> > Thank you for the nice cleanup, Uwe.
> >
> > I've applied patch 1-3 to the branch tee_bus_callback_for_6.20 in my
> > tree at https://git.kernel.org/pub/scm/linux/kernel/git/jenswi/linux-tee.git/
> >
> > The branch is based on v6.19-rc1, and I'll try to keep it stable for
> > others to depend on, if needed. Let's see if we can agree on taking
> > the remaining patches via that branch.
>
> 6 and 7 can go through your branch.

Good, I've added them to my branch now.

Thanks,
Jens


From smostafa at google.com  Thu Dec 18 08:40:01 2025
From: smostafa at google.com (Mostafa Saleh)
Date: Thu, 18 Dec 2025 16:40:01 +0000
Subject: [PATCH rc v4 1/4] iommu/arm-smmu-v3: Add update_safe bits to fix
 STE update sequence
In-Reply-To: <58f5af553fa7c3b5fd16f1eb13a81ae428f85678.1765945258.git.nicolinc@nvidia.com>
References: <cover.1765945258.git.nicolinc@nvidia.com>
 <58f5af553fa7c3b5fd16f1eb13a81ae428f85678.1765945258.git.nicolinc@nvidia.com>
Message-ID: <aUQuYdFKYlFeQGCg@google.com>

On Tue, Dec 16, 2025 at 08:25:59PM -0800, Nicolin Chen wrote:
> From: Jason Gunthorpe <jgg at nvidia.com>
> 
> C_BAD_STE was observed when updating nested STE from an S1-bypass mode to
> an S1DSS-bypass mode. As both modes enabled S2, the used bit is slightly
> different than the normal S1-bypass and S1DSS-bypass modes. As a result,
> fields like MEV and EATS in S2's used list marked the word1 as a critical
> word that requested a STE.V=0. This breaks a hitless update.
> 
> However, both MEV and EATS aren't critical in terms of STE update. One
> controls the merge of the events and the other controls the ATS that is
> managed by the driver at the same time via pci_enable_ats().
> 
> Add an arm_smmu_get_ste_update_safe() to allow STE update algorithm to
> relax those fields, avoiding the STE update breakages.
> 
> After this change, entry_set has no caller checking its return value, so
> change it to void.
> 
> Note that this change is required by both MEV and EATS fields, which were
> introduced in different kernel versions. So add get_update_safe() first.
> MEV and EATS will be added to arm_smmu_get_ste_update_safe() separately.
> 
> Fixes: 1e8be08d1c91 ("iommu/arm-smmu-v3: Support IOMMU_DOMAIN_NESTED")
> Cc: stable at vger.kernel.org
> Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
> Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
> Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
> ---
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  2 ++
>  .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  | 18 ++++++++++---
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 27 ++++++++++++++-----
>  3 files changed, 37 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> index ae23aacc3840..a6c976fa9df2 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> @@ -900,6 +900,7 @@ struct arm_smmu_entry_writer {
>  
>  struct arm_smmu_entry_writer_ops {
>  	void (*get_used)(const __le64 *entry, __le64 *used);
> +	void (*get_update_safe)(__le64 *safe_bits);
>  	void (*sync)(struct arm_smmu_entry_writer *writer);
>  };
>  
> @@ -911,6 +912,7 @@ void arm_smmu_make_s2_domain_ste(struct arm_smmu_ste *target,
>  
>  #if IS_ENABLED(CONFIG_KUNIT)
>  void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits);
> +void arm_smmu_get_ste_update_safe(__le64 *safe_bits);
>  void arm_smmu_write_entry(struct arm_smmu_entry_writer *writer, __le64 *cur,
>  			  const __le64 *target);
>  void arm_smmu_get_cd_used(const __le64 *ent, __le64 *used_bits);
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> index d2671bfd3798..5db14718fdd6 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> @@ -38,13 +38,16 @@ enum arm_smmu_test_master_feat {
>  static bool arm_smmu_entry_differs_in_used_bits(const __le64 *entry,
>  						const __le64 *used_bits,
>  						const __le64 *target,
> +						const __le64 *safe,
>  						unsigned int length)
>  {
>  	bool differs = false;
>  	unsigned int i;
>  
>  	for (i = 0; i < length; i++) {
> -		if ((entry[i] & used_bits[i]) != target[i])
> +		__le64 used = used_bits[i] & ~safe[i];
> +
> +		if ((entry[i] & used) != (target[i] & used))
>  			differs = true;

I have been looking at this, as before, target was not masked at all, so
I'd expect it would be only masked with (~safe[i]) and not used.

But I think that is OK, as we only care about the used bits in the cur
entry and how it's different from target, and target is either the
acutal target or the initial STE so it musn't have any unused bits set.
So that should be fine I believe,

Reviewed-by: Mostafa Saleh <smostafa at google.com>

Thanks,
Mostafa

>  	}
>  	return differs;
> @@ -56,12 +59,17 @@ arm_smmu_test_writer_record_syncs(struct arm_smmu_entry_writer *writer)
>  	struct arm_smmu_test_writer *test_writer =
>  		container_of(writer, struct arm_smmu_test_writer, writer);
>  	__le64 *entry_used_bits;
> +	__le64 *safe;
>  
>  	entry_used_bits = kunit_kzalloc(
>  		test_writer->test, sizeof(*entry_used_bits) * NUM_ENTRY_QWORDS,
>  		GFP_KERNEL);
>  	KUNIT_ASSERT_NOT_NULL(test_writer->test, entry_used_bits);
>  
> +	safe = kunit_kzalloc(test_writer->test,
> +			     sizeof(*safe) * NUM_ENTRY_QWORDS, GFP_KERNEL);
> +	KUNIT_ASSERT_NOT_NULL(test_writer->test, safe);
> +
>  	pr_debug("STE value is now set to: ");
>  	print_hex_dump_debug("    ", DUMP_PREFIX_NONE, 16, 8,
>  			     test_writer->entry,
> @@ -79,14 +87,17 @@ arm_smmu_test_writer_record_syncs(struct arm_smmu_entry_writer *writer)
>  		 * configuration.
>  		 */
>  		writer->ops->get_used(test_writer->entry, entry_used_bits);
> +		if (writer->ops->get_update_safe)
> +			writer->ops->get_update_safe(safe);
>  		KUNIT_EXPECT_FALSE(
>  			test_writer->test,
>  			arm_smmu_entry_differs_in_used_bits(
>  				test_writer->entry, entry_used_bits,
> -				test_writer->init_entry, NUM_ENTRY_QWORDS) &&
> +				test_writer->init_entry, safe,
> +				NUM_ENTRY_QWORDS) &&
>  				arm_smmu_entry_differs_in_used_bits(
>  					test_writer->entry, entry_used_bits,
> -					test_writer->target_entry,
> +					test_writer->target_entry, safe,
>  					NUM_ENTRY_QWORDS));
>  	}
>  }
> @@ -106,6 +117,7 @@ arm_smmu_v3_test_debug_print_used_bits(struct arm_smmu_entry_writer *writer,
>  static const struct arm_smmu_entry_writer_ops test_ste_ops = {
>  	.sync = arm_smmu_test_writer_record_syncs,
>  	.get_used = arm_smmu_get_ste_used,
> +	.get_update_safe = arm_smmu_get_ste_update_safe,
>  };
>  
>  static const struct arm_smmu_entry_writer_ops test_cd_ops = {
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index d16d35c78c06..8dbf4ad5b51e 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -1082,6 +1082,12 @@ void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits)
>  }
>  EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_used);
>  
> +VISIBLE_IF_KUNIT
> +void arm_smmu_get_ste_update_safe(__le64 *safe_bits)
> +{
> +}
> +EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_update_safe);
> +
>  /*
>   * Figure out if we can do a hitless update of entry to become target. Returns a
>   * bit mask where 1 indicates that qword needs to be set disruptively.
> @@ -1094,13 +1100,22 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
>  {
>  	__le64 target_used[NUM_ENTRY_QWORDS] = {};
>  	__le64 cur_used[NUM_ENTRY_QWORDS] = {};
> +	__le64 safe[NUM_ENTRY_QWORDS] = {};
>  	u8 used_qword_diff = 0;
>  	unsigned int i;
>  
>  	writer->ops->get_used(entry, cur_used);
>  	writer->ops->get_used(target, target_used);
> +	if (writer->ops->get_update_safe)
> +		writer->ops->get_update_safe(safe);
>  
>  	for (i = 0; i != NUM_ENTRY_QWORDS; i++) {
> +		/*
> +		 * Safe is only used for bits that are used by both entries,
> +		 * otherwise it is sequenced according to the unused entry.
> +		 */
> +		safe[i] &= target_used[i] & cur_used[i];
> +
>  		/*
>  		 * Check that masks are up to date, the make functions are not
>  		 * allowed to set a bit to 1 if the used function doesn't say it
> @@ -1109,6 +1124,7 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
>  		WARN_ON_ONCE(target[i] & ~target_used[i]);
>  
>  		/* Bits can change because they are not currently being used */
> +		cur_used[i] &= ~safe[i];
>  		unused_update[i] = (entry[i] & cur_used[i]) |
>  				   (target[i] & ~cur_used[i]);
>  		/*
> @@ -1121,7 +1137,7 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
>  	return used_qword_diff;
>  }
>  
> -static bool entry_set(struct arm_smmu_entry_writer *writer, __le64 *entry,
> +static void entry_set(struct arm_smmu_entry_writer *writer, __le64 *entry,
>  		      const __le64 *target, unsigned int start,
>  		      unsigned int len)
>  {
> @@ -1137,7 +1153,6 @@ static bool entry_set(struct arm_smmu_entry_writer *writer, __le64 *entry,
>  
>  	if (changed)
>  		writer->ops->sync(writer);
> -	return changed;
>  }
>  
>  /*
> @@ -1207,12 +1222,9 @@ void arm_smmu_write_entry(struct arm_smmu_entry_writer *writer, __le64 *entry,
>  		entry_set(writer, entry, target, 0, 1);
>  	} else {
>  		/*
> -		 * No inuse bit changed. Sanity check that all unused bits are 0
> -		 * in the entry. The target was already sanity checked by
> -		 * compute_qword_diff().
> +		 * No inuse bit changed, though safe bits may have changed.
>  		 */
> -		WARN_ON_ONCE(
> -			entry_set(writer, entry, target, 0, NUM_ENTRY_QWORDS));
> +		entry_set(writer, entry, target, 0, NUM_ENTRY_QWORDS);
>  	}
>  }
>  EXPORT_SYMBOL_IF_KUNIT(arm_smmu_write_entry);
> @@ -1543,6 +1555,7 @@ static void arm_smmu_ste_writer_sync_entry(struct arm_smmu_entry_writer *writer)
>  static const struct arm_smmu_entry_writer_ops arm_smmu_ste_writer_ops = {
>  	.sync = arm_smmu_ste_writer_sync_entry,
>  	.get_used = arm_smmu_get_ste_used,
> +	.get_update_safe = arm_smmu_get_ste_update_safe,
>  };
>  
>  static void arm_smmu_write_ste(struct arm_smmu_master *master, u32 sid,
> -- 
> 2.43.0
> 


From smostafa at google.com  Thu Dec 18 08:40:30 2025
From: smostafa at google.com (Mostafa Saleh)
Date: Thu, 18 Dec 2025 16:40:30 +0000
Subject: [PATCH rc v4 2/4] iommu/arm-smmu-v3: Mark STE MEV safe when
 computing the update sequence
In-Reply-To: <83f991cbbb1331213aabe7c1fc5f725e79f60ecd.1765945258.git.nicolinc@nvidia.com>
References: <cover.1765945258.git.nicolinc@nvidia.com>
 <83f991cbbb1331213aabe7c1fc5f725e79f60ecd.1765945258.git.nicolinc@nvidia.com>
Message-ID: <aUQufkkJYrOp0erD@google.com>

On Tue, Dec 16, 2025 at 08:26:00PM -0800, Nicolin Chen wrote:
> From: Jason Gunthorpe <jgg at nvidia.com>
> 
> Nested CD tables set the MEV bit to try to reduce multi-fault spamming on
> the hypervisor. Since MEV is in STE word 1 this causes a breaking update
> sequence that is not required and impacts real workloads.
> 
> For the purposes of STE updates the value of MEV doesn't matter, if it is
> set/cleared early or late it just results in a change to the fault reports
> that must be supported by the kernel anyhow. The spec says:
> 
>  Note: Software must expect, and be able to deal with, coalesced fault
>  records even when MEV == 0.
> 
> So mark STE MEV safe when computing the update sequence, to avoid creating
> a breaking update.
> 
> Fixes: da0c56520e88 ("iommu/arm-smmu-v3: Set MEV bit in nested STE for DoS mitigations")
> Cc: stable at vger.kernel.org
> Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
> Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
> Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
> ---
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 10 ++++++++++
>  1 file changed, 10 insertions(+)

Reviewed-by: Mostafa Saleh <smostafa at google.com>

Thanks,
Mostafa

> 
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index 8dbf4ad5b51e..12a9669bcc83 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -1085,6 +1085,16 @@ EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_used);
>  VISIBLE_IF_KUNIT
>  void arm_smmu_get_ste_update_safe(__le64 *safe_bits)
>  {
> +	/*
> +	 * MEV does not meaningfully impact the operation of the HW, it only
> +	 * changes how many fault events are generated, thus we can relax it
> +	 * when computing the ordering. The spec notes the device can act like
> +	 * MEV=1 anyhow:
> +	 *
> +	 *  Note: Software must expect, and be able to deal with, coalesced
> +	 *  fault records even when MEV == 0.
> +	 */
> +	safe_bits[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
>  }
>  EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_update_safe);
>  
> -- 
> 2.43.0
> 


From thesnowfield at sakurapi.org  Thu Dec 18 08:40:21 2025
From: thesnowfield at sakurapi.org (Chiyuki Akatsuki)
Date: Fri, 19 Dec 2025 00:40:21 +0800
Subject: [PATCH RESEND] arm64: dts: rockchip: Fix wifi interrupts flag on Sakura Pi RK3308B
In-Reply-To: <20251217091808.38253-2-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251217091808.38253-2-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <20251218164021.495-1-thesnowfield@sakurapi.org>

Thanks for the patch.

Confirmed that the interrupt flags should use IRQ_TYPE_LEVEL_xxx,
and tested on the SakuraPi RK3308B board, works fine.

Acked-by: Chiyuki Akatsuki <thesnowfield at sakurapi.org>



From m.felsch at pengutronix.de  Thu Dec 18 08:42:09 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Thu, 18 Dec 2025 17:42:09 +0100
Subject: [PATCH] ARM: dts: nxp/imx6: Drop unused .dtsi
In-Reply-To: <CAL_JsqLfVemq9k3x5J1pTz--Z+VYLeEQrFdbtdS7Pc-HkRui=w@mail.gmail.com>
References: <20251212203226.458694-5-robh@kernel.org>
 <20251213181324.u32ztfblkknfpz44@pengutronix.de>
 <CAL_JsqK9OREenZjBHrDh7AqsyUXYOzTOhY4e0qHGzYkX8tacWQ@mail.gmail.com>
 <20251214185750.tzt6jf4zg5gtex63@pengutronix.de>
 <CAL_JsqLfVemq9k3x5J1pTz--Z+VYLeEQrFdbtdS7Pc-HkRui=w@mail.gmail.com>
Message-ID: <20251218164209.6ombc6g4gy7tuwcz@pengutronix.de>

On 25-12-15, Rob Herring wrote:
> On Sun, Dec 14, 2025 at 12:58?PM Marco Felsch <m.felsch at pengutronix.de> wrote:
> >
> > On 25-12-14, Rob Herring wrote:
> > > On Sat, Dec 13, 2025 at 12:13?PM Marco Felsch <m.felsch at pengutronix.de> wrote:
> > > >
> > > > Hi Rob,
> > > >
> > > > On 25-12-12, Rob Herring (Arm) wrote:
> > > > > These .dtsi files are not included anywhere in the tree and can't be
> > > > > tested.
> > > >
> > > > not in the tree but by other projects, please see below.
> > > >
> > > > > Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> > > > > ---
> > > > >  .../dts/nxp/imx/imx6dl-kontron-samx6i.dtsi    | 12 -----
> > > > >  .../dts/nxp/imx/imx6q-kontron-samx6i.dtsi     | 12 -----
> > > > >  .../boot/dts/nxp/imx/imx6qdl-pico-dwarf.dtsi  | 45 ----------------
> > > > >  .../boot/dts/nxp/imx/imx6qdl-pico-nymph.dtsi  | 54 -------------------
> > > > >  4 files changed, 123 deletions(-)
> > > > >  delete mode 100644 arch/arm/boot/dts/nxp/imx/imx6dl-kontron-samx6i.dtsi
> > > > >  delete mode 100644 arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi
> > > > >  delete mode 100644 arch/arm/boot/dts/nxp/imx/imx6qdl-pico-dwarf.dtsi
> > > > >  delete mode 100644 arch/arm/boot/dts/nxp/imx/imx6qdl-pico-nymph.dtsi
> > > > >
> > > > > diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-kontron-samx6i.dtsi b/arch/arm/boot/dts/nxp/imx/imx6dl-kontron-samx6i.dtsi
> > > > > deleted file mode 100644
> > > > > index 5a9b819d7ee8..000000000000
> > > > > --- a/arch/arm/boot/dts/nxp/imx/imx6dl-kontron-samx6i.dtsi
> > > > > +++ /dev/null
> > > > > @@ -1,12 +0,0 @@
> > > > > -// SPDX-License-Identifier: GPL-2.0 OR X11
> > > > > -/*
> > > > > - * Copyright 2019 (C) Pengutronix, Marco Felsch <kernel at pengutronix.de>
> > > > > - */
> > > > > -
> > > > > -#include "imx6dl.dtsi"
> > > > > -#include "imx6qdl-kontron-samx6i.dtsi"
> > > > > -
> > > > > -/ {
> > > > > -     model = "Kontron SMARC-sAMX6i Dual-Lite/Solo";
> > > > > -     compatible = "kontron,imx6dl-samx6i", "fsl,imx6dl";
> > > > > -};
> > > > > diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi b/arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi
> > > > > deleted file mode 100644
> > > > > index e76963436079..000000000000
> > > > > --- a/arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi
> > > > > +++ /dev/null
> > > > > @@ -1,12 +0,0 @@
> > > > > -// SPDX-License-Identifier: GPL-2.0 OR X11
> > > > > -/*
> > > > > - * Copyright 2019 (C) Pengutronix, Marco Felsch <kernel at pengutronix.de>
> > > > > - */
> > > > > -
> > > > > -#include "imx6q.dtsi"
> > > > > -#include "imx6qdl-kontron-samx6i.dtsi"
> > > > > -
> > > > > -/ {
> > > > > -     model = "Kontron SMARC-sAMX6i Quad/Dual";
> > > > > -     compatible = "kontron,imx6q-samx6i", "fsl,imx6q";
> > > > > -};
> > > >
> > > > I can't speak for the other two .dtsi files but both kontron .dtsi files
> > > > are used by barebox:
> > > >
> > > >  - https://elixir.bootlin.com/barebox/v2025.11.0/source/arch/arm/dts/imx6dl-samx6i.dts#L8
> > > >  - https://elixir.bootlin.com/barebox/v2025.11.0/source/arch/arm/dts/imx6q-samx6i.dts#L8
> > > >
> > > > Removing them here will cause a regression for barebox.
> > >
> > > Please upstream something that uses the .dtsi. Other than the
> > > undocumented barebox property, no reason these can't be.
> >
> > My intention wasn't to point to the barebox-only
> > "barebox,disable-deep-probe" property. I was refering to the include
> > line.
> >
> > The two .dtsi files we're talking about are SoM .dtsi files. We don't
> > have access to the Kontron EVK baseboard which uses this SoM.
> >
> > I've added a few Kontron devs which may can add the missing baseboard
> > support.
> >
> > +Cc: frieder.schrempf at kontron.de
> > +Cc: annette.kobou at kontron.de
> > +Cc: oualid.derouiche at kontron.de
> > +Cc: eberhard.stoll at kontron.de
> >
> > I could also add the imx6dl-samx6i.dts and imx6q-samx6i.dts like we do
> > in barebox. But as said, this would be a devicetree for a SoM which
> > makes sense for the bootloader but not for the kernel.
> 
> Why not? People use the kernel as a bootloader. There's also some

Using the kernel as bootloader is a good point, which I didn't had in my
mind!

I will add the som.dts, please don't remove the kontron dtsi files yet.

> discussions about splitting SoMs and baseboards into overlays for
> baseboards (and also even into SoC base DT plus overlay for boards).

Do you have pointers?

Regards,
  Marco


> 
> Rob
> 

-- 
#gernperDu 
#CallMeByMyFirstName

Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | https://www.pengutronix.de/ |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-9    |


From smostafa at google.com  Thu Dec 18 08:42:40 2025
From: smostafa at google.com (Mostafa Saleh)
Date: Thu, 18 Dec 2025 16:42:40 +0000
Subject: [PATCH rc v4 3/4] iommu/arm-smmu-v3: Mark STE EATS safe when
 computing the update sequence
In-Reply-To: <adf08c3b9f289188aca4fe80e506dca7aa48aa19.1765945258.git.nicolinc@nvidia.com>
References: <cover.1765945258.git.nicolinc@nvidia.com>
 <adf08c3b9f289188aca4fe80e506dca7aa48aa19.1765945258.git.nicolinc@nvidia.com>
Message-ID: <aUQvAKjVUT1L3N7j@google.com>

On Tue, Dec 16, 2025 at 08:26:01PM -0800, Nicolin Chen wrote:
> From: Jason Gunthorpe <jgg at nvidia.com>
> 
> If a VM wants to toggle EATS off at the same time as changing the CFG, the
> hypervisor will see EATS change to 0 and insert a V=0 breaking update into
> the STE even though the VM did not ask for that.
> 
> In bare metal, EATS is ignored by CFG=ABORT/BYPASS, which is why this does
> not cause a problem until we have nested where CFG is always a variation of
> S2 trans that does use EATS.
> 
> Relax the rules for EATS sequencing, we don't need it to be exact because
> the enclosing code will always disable ATS at the PCI device if we are
> changing EATS. This ensures there are no ATS transactions that can race
> with an EATS change so we don't need to carefully sequence these bits.
> 
> Fixes: 1e8be08d1c91 ("iommu/arm-smmu-v3: Support IOMMU_DOMAIN_NESTED")
> Cc: stable at vger.kernel.org
> Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
> Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
> Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
> ---
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index 12a9669bcc83..a3b29ad20a82 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -1095,6 +1095,15 @@ void arm_smmu_get_ste_update_safe(__le64 *safe_bits)
>  	 *  fault records even when MEV == 0.
>  	 */
>  	safe_bits[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
> +
> +	/*
> +	 * EATS is used to reject and control the ATS behavior of the device. If
> +	 * we are changing it away from 0 then we already trust the device to
> +	 * use ATS properly and we have sequenced the device's ATS enable in PCI
> +	 * config space to prevent it from issuing ATS while we are changing
> +	 * EATS.
> +	 */

I am not sure about this one, Is it only about trusting the device?

I?d be worried about cases where we switch domains, that means that
briefly the HW observers EATS=1 while it was not intended, especially
that EATS is in a different DWORD from S2TTB and CDptr. With all the
IOMMUFD/VFIO stuff it makes it harder to reason about. But I can?t
come up with an example to break this.

Thanks,
Mostafa

> +	safe_bits[1] |= cpu_to_le64(STRTAB_STE_1_EATS);
>  }
>  EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_update_safe);
>  
> -- 
> 2.43.0
> 


From tan.siewert at hetzner.com  Thu Dec 18 08:44:05 2025
From: tan.siewert at hetzner.com (Tan Siewert)
Date: Thu, 18 Dec 2025 17:44:05 +0100
Subject: [PATCH v6 1/2] dt-bindings: arm: aspeed: add ASRock Rack ALTRAD8
 board
In-Reply-To: <5aa36c56-798a-40cc-b0b8-be3f7c92136f@kernel.org>
References: <20251218161816.38155-1-rebecca@bsdio.com>
 <20251218161816.38155-2-rebecca@bsdio.com>
 <5aa36c56-798a-40cc-b0b8-be3f7c92136f@kernel.org>
Message-ID: <b10a233e-02c3-4b02-8f11-098f6fb8197c@hetzner.com>

On 18.12.25 17:21, Krzysztof Kozlowski wrote:
> On 18/12/2025 17:18, Rebecca Cran wrote:
>> Document ASRock Rack ALTRAD8 (ALTRAD8UD-1L2T and ALTRAD8UD2-1L2Q)
>> compatibles.
>>
>> Signed-off-by: Rebecca Cran <rebecca at bsdio.com>
>> Acked-by: Conor Dooley <conor.dooley at microchip.com>
>> Tested-by: Tan Siewert <tan.siewert at hetzner.com>
> 
> How was the binding tested?

My bad for sending the wrong trailing header in v4. Tested-by should've 
been only on the dts instead of the dt-bindings+dts. Either way, `make 
dt_binding_check` was what I did to check if there are any errors 
produced for `asrock,altrad8-bmc`.

-- Tan

> 
> 
> Best regards,
> Krzysztof
> 


From smostafa at google.com  Thu Dec 18 08:47:38 2025
From: smostafa at google.com (Mostafa Saleh)
Date: Thu, 18 Dec 2025 16:47:38 +0000
Subject: [PATCH rc v4 4/4] iommu/arm-smmu-v3-test: Add nested
 s1bypass/s1dssbypass coverage
In-Reply-To: <6fcdd663d62dcab4005401bac2d23d18dd28e0c4.1765945258.git.nicolinc@nvidia.com>
References: <cover.1765945258.git.nicolinc@nvidia.com>
 <6fcdd663d62dcab4005401bac2d23d18dd28e0c4.1765945258.git.nicolinc@nvidia.com>
Message-ID: <aUQwKot1Ao0lE-C1@google.com>

On Tue, Dec 16, 2025 at 08:26:02PM -0800, Nicolin Chen wrote:
> STE in a nested case requires both S1 and S2 fields. And this makes the use
> case different from the existing one.
> 
> Add coverage for previously failed cases shifting between S2-only and S1+S2
> STEs.
> 
> Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
> Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
> ---
>  .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  | 46 +++++++++++++++++++
>  1 file changed, 46 insertions(+)
> 
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> index 5db14718fdd6..8255a02f4efa 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> @@ -33,8 +33,12 @@ static struct mm_struct sva_mm = {
>  enum arm_smmu_test_master_feat {
>  	ARM_SMMU_MASTER_TEST_ATS = BIT(0),
>  	ARM_SMMU_MASTER_TEST_STALL = BIT(1),
> +	ARM_SMMU_MASTER_TEST_NESTED = BIT(2),
>  };
>  
> +static void arm_smmu_test_make_s2_ste(struct arm_smmu_ste *ste,
> +				      enum arm_smmu_test_master_feat feat);
> +
>  static bool arm_smmu_entry_differs_in_used_bits(const __le64 *entry,
>  						const __le64 *used_bits,
>  						const __le64 *target,
> @@ -197,6 +201,17 @@ static void arm_smmu_test_make_cdtable_ste(struct arm_smmu_ste *ste,
>  	};
>  
>  	arm_smmu_make_cdtable_ste(ste, &master, ats_enabled, s1dss);
> +	if (feat & ARM_SMMU_MASTER_TEST_NESTED) {
> +		struct arm_smmu_ste s2ste;
> +		int i;
> +
> +		arm_smmu_test_make_s2_ste(&s2ste, ARM_SMMU_MASTER_TEST_ATS);

Shouldn't that be conditional on "ats_enabled", I see the callers of the
new tests already set ARM_SMMU_MASTER_TEST_ATS.

Thanks,
Mostafa

> +		ste->data[0] |= cpu_to_le64(
> +			FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_NESTED));
> +		ste->data[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
> +		for (i = 2; i < NUM_ENTRY_QWORDS; i++)
> +			ste->data[i] = s2ste.data[i];
> +	}
>  }
>  
>  static void arm_smmu_v3_write_ste_test_bypass_to_abort(struct kunit *test)
> @@ -554,6 +569,35 @@ static void arm_smmu_v3_write_ste_test_s2_to_s1_stall(struct kunit *test)
>  						       NUM_EXPECTED_SYNCS(3));
>  }
>  
> +static void
> +arm_smmu_v3_write_ste_test_nested_s1dssbypass_to_s1bypass(struct kunit *test)
> +{
> +	struct arm_smmu_ste s1_ste;
> +	struct arm_smmu_ste s2_ste;
> +
> +	arm_smmu_test_make_cdtable_ste(
> +		&s1_ste, STRTAB_STE_1_S1DSS_BYPASS, fake_cdtab_dma_addr,
> +		ARM_SMMU_MASTER_TEST_ATS | ARM_SMMU_MASTER_TEST_NESTED);
> +	arm_smmu_test_make_s2_ste(&s2_ste, 0);
> +	/* Expect an additional sync to unset ignored bits: EATS and MEV */
> +	arm_smmu_v3_test_ste_expect_hitless_transition(test, &s1_ste, &s2_ste,
> +						       NUM_EXPECTED_SYNCS(3));
> +}
> +
> +static void
> +arm_smmu_v3_write_ste_test_nested_s1bypass_to_s1dssbypass(struct kunit *test)
> +{
> +	struct arm_smmu_ste s1_ste;
> +	struct arm_smmu_ste s2_ste;
> +
> +	arm_smmu_test_make_cdtable_ste(
> +		&s1_ste, STRTAB_STE_1_S1DSS_BYPASS, fake_cdtab_dma_addr,
> +		ARM_SMMU_MASTER_TEST_ATS | ARM_SMMU_MASTER_TEST_NESTED);
> +	arm_smmu_test_make_s2_ste(&s2_ste, 0);
> +	arm_smmu_v3_test_ste_expect_hitless_transition(test, &s2_ste, &s1_ste,
> +						       NUM_EXPECTED_SYNCS(2));
> +}
> +
>  static void arm_smmu_v3_write_cd_test_sva_clear(struct kunit *test)
>  {
>  	struct arm_smmu_cd cd = {};
> @@ -600,6 +644,8 @@ static struct kunit_case arm_smmu_v3_test_cases[] = {
>  	KUNIT_CASE(arm_smmu_v3_write_cd_test_s1_change_asid),
>  	KUNIT_CASE(arm_smmu_v3_write_ste_test_s1_to_s2_stall),
>  	KUNIT_CASE(arm_smmu_v3_write_ste_test_s2_to_s1_stall),
> +	KUNIT_CASE(arm_smmu_v3_write_ste_test_nested_s1dssbypass_to_s1bypass),
> +	KUNIT_CASE(arm_smmu_v3_write_ste_test_nested_s1bypass_to_s1dssbypass),
>  	KUNIT_CASE(arm_smmu_v3_write_cd_test_sva_clear),
>  	KUNIT_CASE(arm_smmu_v3_write_cd_test_sva_release),
>  	{},
> -- 
> 2.43.0
> 


From suzuki.poulose at arm.com  Thu Dec 18 09:04:07 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Thu, 18 Dec 2025 17:04:07 +0000
Subject: [PATCH v2 00/12] coresight: Add CPU cluster funnel/replicator/tmc
 support
In-Reply-To: <8cb8fad9-c54e-43a3-a769-5452119cc2a1@oss.qualcomm.com>
References: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
 <47191600-260a-46aa-9af8-dff2b08dc2e8@arm.com>
 <8cb8fad9-c54e-43a3-a769-5452119cc2a1@oss.qualcomm.com>
Message-ID: <3d4dd3d0-fca0-45ac-a833-e8f7f5d1aa95@arm.com>

On 18/12/2025 16:18, yuanfang zhang wrote:
> 
> 
> On 12/18/2025 5:32 PM, Suzuki K Poulose wrote:
>> Cc: Sudeep
>>
>> On 18/12/2025 08:09, Yuanfang Zhang wrote:
>>> This patch series adds support for CoreSight components local to CPU clusters,
>>> including funnel, replicator, and TMC, which reside within CPU cluster power
>>> domains. These components require special handling due to power domain
>>> constraints.
>>>
>>> Unlike system-level CoreSight devices, these components share the CPU cluster's
>>> power domain. When the cluster enters low-power mode (LPM), their registers
>>> become inaccessible. Notably, `pm_runtime_get` alone cannot bring the cluster
>>> out of LPM, making standard register access unreliable.
>>
>> Why ? AFAIU, we have ways to tie the power-domain to that of the cluster
>> and that can auto-magically keep the cluster power ON as long as you
>> want to use them.
>>
>> Suzuki
>>
> Hi Suzuki
> 
> Runtime PM for CPU devices works little different, it is mostly used to manage hierarchical
> CPU topology (PSCI OSI mode) to talk with genpd framework to manage the last CPU handling in
> cluster.
> It doesn?t really send IPI to wakeup CPU device (It don?t have .power_on/.power_off) callback
> implemented which gets invoked from .runtime_resume callback. This behavior is aligned with
> the upstream Kernel.

Why does it need to wake up the CPU ? The firmware can power up the
cluster right? Anyways, to me this all looks like working around a
firmware issue. I will let you sort this out with Sudeep's response
, as I am not an expert on the cluster powermanagement and standards.

Suzuki



> 
> Yuanfang
> 
>>
>>>
>>> To address this, the series introduces:
>>> - Identifying cluster-bound devices via a new `qcom,cpu-bound-components`
>>>  ?? device tree property.
>>> - Implementing deferred probing: if associated CPUs are offline during
>>>  ?? probe, initialization is deferred until a CPU hotplug notifier detects
>>>  ?? the CPU coming online.
>>> - Utilizing `smp_call_function_single()` to ensure register accesses
>>>  ?? (initialization, enablement, sysfs reads) are always executed on a
>>>  ?? powered CPU within the target cluster.
>>> - Extending the CoreSight link `enable` callback to pass the `cs_mode`.
>>>  ?? This allows drivers to distinguish between SysFS and Perf modes and
>>>  ?? apply mode-specific logic.
>>>
>>> Jie Gan (1):
>>>  ?? arm64: dts: qcom: hamoa: add Coresight nodes for APSS debug block
>>>
>>> Yuanfang Zhang (11):
>>>  ?? dt-bindings: arm: coresight: Add 'qcom,cpu-bound-components' property
>>>  ?? coresight: Pass trace mode to link enable callback
>>>  ?? coresight-funnel: Support CPU cluster funnel initialization
>>>  ?? coresight-funnel: Defer probe when associated CPUs are offline
>>>  ?? coresight-replicator: Support CPU cluster replicator initialization
>>>  ?? coresight-replicator: Defer probe when associated CPUs are offline
>>>  ?? coresight-replicator: Update management interface for CPU-bound devices
>>>  ?? coresight-tmc: Support probe and initialization for CPU cluster TMCs
>>>  ?? coresight-tmc-etf: Refactor enable function for CPU cluster ETF support
>>>  ?? coresight-tmc: Update management interface for CPU-bound TMCs
>>>  ?? coresight-tmc: Defer probe when associated CPUs are offline
>>>
>>> Verification:
>>>
>>> This series has been verified on sm8750.
>>>
>>> Test steps for delay probe:
>>>
>>> 1. limit the system to enable at most 6 CPU cores during boot.
>>> 2. echo 1 >/sys/bus/cpu/devices/cpu6/online.
>>> 3. check whether ETM6 and ETM7 have been probed.
>>>
>>> Test steps for sysfs mode:
>>>
>>> echo 1 >/sys/bus/coresight/devices/tmc_etf0/enable_sink
>>> echo 1 >/sys/bus/coresight/devices/etm0/enable_source
>>> echo 1 >/sys/bus/coresight/devices/etm6/enable_source
>>> echo 0 >/sys/bus/coresight/devices/etm0/enable_source
>>> echo 0 >/sys/bus/coresight/devicse/etm6/enable_source
>>> echo 0 >/sys/bus/coresight/devices/tmc_etf0/enable_sink
>>>
>>> echo 1 >/sys/bus/coresight/devices/tmc_etf1/enable_sink
>>> echo 1 >/sys/bus/coresight/devcies/etm0/enable_source
>>> cat /dev/tmc_etf1 >/tmp/etf1.bin
>>> echo 0 >/sys/bus/coresight/devices/etm0/enable_source
>>> echo 0 >/sys/bus/coresight/devices/tmc_etf1/enable_sink
>>>
>>> echo 1 >/sys/bus/coresight/devices/tmc_etf2/enable_sink
>>> echo 1 >/sys/bus/coresight/devices/etm6/enable_source
>>> cat /dev/tmc_etf2 >/tmp/etf2.bin
>>> echo 0 >/sys/bus/coresight/devices/etm6/enable_source
>>> echo 0 >/sys/bus/coresight/devices/tmc_etf2/enable_sink
>>>
>>> Test steps for sysfs node:
>>>
>>> cat /sys/bus/coresight/devices/tmc_etf*/mgmt/*
>>>
>>> cat /sys/bus/coresight/devices/funnel*/funnel_ctrl
>>>
>>> cat /sys/bus/coresight/devices/replicator*/mgmt/*
>>>
>>> Test steps for perf mode:
>>>
>>> perf record -a -e cs_etm//k -- sleep 5
>>>
>>> Signed-off-by: Yuanfang Zhang <yuanfang.zhang at oss.qualcomm.com>
>>> ---
>>> Changes in v2:
>>> - Use the qcom,cpu-bound-components device tree property to identify devices
>>>  ?? bound to a cluster.
>>> - Refactor commit message.
>>> - Introduce a supported_cpus field in the drvdata structure to record the CPUs
>>>  ?? that belong to the cluster where the local component resides.
>>> - Link to v1: https://lore.kernel.org/r/20251027-cpu_cluster_component_pm-v1-0-31355ac588c2 at oss.qualcomm.com
>>>
>>> ---
>>> Jie Gan (1):
>>>  ?????? arm64: dts: qcom: hamoa: Add CoreSight nodes for APSS debug block
>>>
>>> Yuanfang Zhang (11):
>>>  ?????? dt-bindings: arm: coresight: Add 'qcom,cpu-bound-components' property
>>>  ?????? coresight-funnel: Support CPU cluster funnel initialization
>>>  ?????? coresight-funnel: Defer probe when associated CPUs are offline
>>>  ?????? coresight-replicator: Support CPU cluster replicator initialization
>>>  ?????? coresight-replicator: Defer probe when associated CPUs are offline
>>>  ?????? coresight-replicator: Update management interface for CPU-bound devices
>>>  ?????? coresight-tmc: Support probe and initialization for CPU cluster TMCs
>>>  ?????? coresight-tmc-etf: Refactor enable function for CPU cluster ETF support
>>>  ?????? coresight-tmc: Update management interface for CPU-bound TMCs
>>>  ?????? coresight-tmc: Defer probe when associated CPUs are offline
>>>  ?????? coresight: Pass trace mode to link enable callback
>>>
>>>  ? .../bindings/arm/arm,coresight-dynamic-funnel.yaml |?? 5 +
>>>  ? .../arm/arm,coresight-dynamic-replicator.yaml????? |?? 5 +
>>>  ? .../devicetree/bindings/arm/arm,coresight-tmc.yaml |?? 5 +
>>>  ? arch/arm64/boot/dts/qcom/hamoa.dtsi??????????????? | 926 +++++++++++++++++++++
>>>  ? arch/arm64/boot/dts/qcom/purwa.dtsi??????????????? |? 12 +
>>>  ? drivers/hwtracing/coresight/coresight-core.c?????? |?? 7 +-
>>>  ? drivers/hwtracing/coresight/coresight-funnel.c???? | 258 +++++-
>>>  ? drivers/hwtracing/coresight/coresight-replicator.c | 341 +++++++-
>>>  ? drivers/hwtracing/coresight/coresight-tmc-core.c?? | 387 +++++++--
>>>  ? drivers/hwtracing/coresight/coresight-tmc-etf.c??? | 106 ++-
>>>  ? drivers/hwtracing/coresight/coresight-tmc.h??????? |? 10 +
>>>  ? drivers/hwtracing/coresight/coresight-tnoc.c?????? |?? 3 +-
>>>  ? drivers/hwtracing/coresight/coresight-tpda.c?????? |?? 3 +-
>>>  ? include/linux/coresight.h????????????????????????? |?? 3 +-
>>>  ? 14 files changed, 1902 insertions(+), 169 deletions(-)
>>> ---
>>> base-commit: 008d3547aae5bc86fac3eda317489169c3fda112
>>> change-id: 20251016-cpu_cluster_component_pm-ce518f510433
>>>
>>> Best regards,
>>
> 



From ajd at linux.ibm.com  Thu Dec 18 09:09:32 2025
From: ajd at linux.ibm.com (Andrew Donnellan)
Date: Fri, 19 Dec 2025 04:09:32 +1100
Subject: [PATCH v18 00/12] Support page table check on PowerPC
Message-ID: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>

[I will be leaving IBM in about a month from now, and will also be on leave
for most of that time starting tomorrow. I've cc'd my personal email, which
I am going to use for any kernel development I do after I leave, and also
Srish Srinivasan, who will be taking over some of my work.]

Support page table check on PowerPC. Page table check tracks the usage of
of page table entries at each level to ensure that anonymous mappings have
at most one writable consumer, and likewise that file-backed mappings are
not simultaneously also anonymous mappings.

In order to support this infrastructure, a number of helpers or stubs must be
defined or updated for all powerpc platforms. Additionally, we separate
set_pte_at() and set_pte_at_unchecked(), to allow for internal, uninstrumented
mappings.

On some PowerPC platforms, implementing {pte,pmd,pud}_user_accessible_page()
requires the address. We revert previous changes that removed the address
parameter from various interfaces, and add it to some other interfaces,
in order to allow this.

For now, we don't allow page table check alongside HUGETLB_PAGE, due to the
arch-specific complexity of set_huge_page_at(). (I'm sure I could figure
this out, but I have to get this version on this list before I leave my job.)

This series was initially written by Rohan McLure, who has left IBM and
is no longer working on powerpc.

v18:
 * Rebase on mm-new
 * Add instrumentation for pudp_invalidate()
 * Add cleanup patch to use pte_advance_pfn()
 * Move p{m,u}d_user_accessible_page() to a more sensible place in the code
 * Disable when HUGETLB_PAGE is enabled

v17:
 * Rebase on mm-new to fix build failure on commit 3f3806eff23f ("riscv: use an
   atomic xchg in pudp_huge_get_and_clear()")
 * Remove patch 10 ("powerpc: mm: Add pud_pfn() stub"), as the original
   reasoning for the stub is now wrong (pud_pfn() is now used more broadly in
   generic code, and commit 35a76f5c0863 ("mm/arch: provide pud_pfn()
   fallback") now provides a generic fallback. This fixes the build failure on
   some powerpc platforms (0day)
Link: https://lore.kernel.org/all/20250909091335.183439-1-ajd at linux.ibm.com/

v16:
 * Rebase on mainline
Link: https://lore.kernel.org/all/20250813062614.51759-1-ajd at linux.ibm.com/

v15:
 * Rebase on mainline, including commit 91e40668e70a
   ("mm/page_table_check: Batch-check pmds/puds just like ptes") and
   associated arm64 changes
 * Clarify/fix some commit messages
 * Fix handling of address in a loop in __page_table_check_ptes_set()
Link: https://lore.kernel.org/all/20250625063753.77511-1-ajd at linux.ibm.com/

v14:
 * Fix a call to page_table_check_pud_set() that was missed (akpm)
Link: https://lore.kernel.org/all/20250411054354.511145-1-ajd at linux.ibm.com/

v13:
 * Rebase on mainline
 * Don't use set_pte_at_unchecked() for early boot purposes (Pasha)
Link: https://lore.kernel.org/linuxppc-dev/20250211161404.850215-1-ajd at linux.ibm.com/

v12:
 * Rename commits that revert changes to instead reflect that we are
   reinstating old behaviour due to it providing more flexibility
 * Add return line to pud_pfn() stub
 * Instrument ptep_get_and_clear() for nohash
Link: https://lore.kernel.org/linuxppc-dev/20240402051154.476244-1-rmclure at linux.ibm.com/

v11:
 * The pud_pfn() stub, which previously had no legitimate users on any
   powerpc platform, now has users in Book3s64 with transparent pages.
   Include a stub of the same name for each platform that does not
   define their own.
 * Drop patch that standardised use of p*d_leaf(), as already included
   upstream in v6.9.
 * Provide fallback definitions of p{m,u}d_user_accessible_page() that
   do not reference p*d_leaf(), p*d_pte(), as they are defined after
   powerpc/mm headers by linux/mm headers.
 * Ensure that set_pte_at_unchecked() has the same checks as
   set_pte_at().
Link: https://lore.kernel.org/linuxppc-dev/20240328045535.194800-14-rmclure at linux.ibm.com/ 

v10:
 * Revert patches that removed address and mm parameters from page table
   check routines, including consuming code from arm64, x86_64 and
   riscv.
 * Implement *_user_accessible_page() routines in terms of pte_user()
   where available (64-bit, book3s) but otherwise by checking the
   address (on platforms where the pte does not imply whether the
   mapping is for user or kernel)
 * Internal set_pte_at() calls replaced with set_pte_at_unchecked(), which
   is identical, but prevents double instrumentation.
Link: https://lore.kernel.org/linuxppc-dev/20240313042118.230397-9-rmclure at linux.ibm.com/T/

v9:
 * Adapt to using the set_ptes() API, using __set_pte_at() where we need
   must avoid instrumentation.
 * Use the logic of *_access_permitted() for implementing
   *_user_accessible_page(), which are required routines for page table
   check.
 * Even though we no longer need p{m,u,4}d_leaf(), still default
   implement these to assist in refactoring out extant
   p{m,u,4}_is_leaf().
 * Add p{m,u}_pte() stubs where asm-generic does not provide them, as
   page table check wants all *user_accessible_page() variants, and we
   would like to default implement the variants in terms of
   pte_user_accessible_page().
 * Avoid the ugly pmdp_collapse_flush() macro nonsense! Just instrument
   its constituent calls instead for radix and hash.
Link: https://lore.kernel.org/linuxppc-dev/20231130025404.37179-2-rmclure at linux.ibm.com/

v8:
 * Fix linux/page_table_check.h include in asm/pgtable.h breaking
   32-bit.
Link: https://lore.kernel.org/linuxppc-dev/20230215231153.2147454-1-rmclure at linux.ibm.com/

v7:
 * Remove use of extern in set_pte prototypes
 * Clean up pmdp_collapse_flush macro
 * Replace set_pte_at with static inline function
 * Fix commit message for patch 7
Link: https://lore.kernel.org/linuxppc-dev/20230215020155.1969194-1-rmclure at linux.ibm.com/

v6:
 * Support huge pages and p{m,u}d accounting.
 * Remove instrumentation from set_pte from kernel internal pages.
 * 64s: Implement pmdp_collapse_flush in terms of __pmdp_collapse_flush
   as access to the mm_struct * is required.
Link: https://lore.kernel.org/linuxppc-dev/20230214015939.1853438-1-rmclure at linux.ibm.com/

v5: https://lore.kernel.org/linuxppc-dev/20221118002146.25979-1-rmclure at linux.ibm.com/

---
Andrew Donnellan (2):
      arm64/mm: Add addr parameter to __set_ptes_anysz()
      arm64/mm: Add addr parameter to __ptep_get_and_clear_anysz()

Rohan McLure (10):
      mm/page_table_check: Reinstate address parameter in [__]page_table_check_pud[s]_set()
      mm/page_table_check: Reinstate address parameter in [__]page_table_check_pmd[s]_set()
      mm/page_table_check: Provide addr parameter to page_table_check_ptes_set()
      mm/page_table_check: Reinstate address parameter in [__]page_table_check_pud_clear()
      mm/page_table_check: Reinstate address parameter in [__]page_table_check_pmd_clear()
      mm/page_table_check: Reinstate address parameter in [__]page_table_check_pte_clear()
      mm: Provide address parameter to p{te,md,ud}_user_accessible_page()
      powerpc/mm: Implement *_user_accessible_page() for ptes
      powerpc/mm: Use set_pte_at_unchecked() for internal usages
      powerpc/mm: Support page table check

 arch/arm64/include/asm/pgtable.h             | 46 +++++++++----------
 arch/arm64/mm/hugetlbpage.c                  | 17 +++----
 arch/powerpc/Kconfig                         |  1 +
 arch/powerpc/include/asm/book3s/32/pgtable.h | 12 ++++-
 arch/powerpc/include/asm/book3s/64/pgtable.h | 62 +++++++++++++++++++++----
 arch/powerpc/include/asm/nohash/pgtable.h    | 13 +++++-
 arch/powerpc/include/asm/pgtable.h           | 10 ++++
 arch/powerpc/mm/book3s64/hash_pgtable.c      |  4 ++
 arch/powerpc/mm/book3s64/pgtable.c           | 25 ++++++----
 arch/powerpc/mm/book3s64/radix_pgtable.c     |  9 ++--
 arch/powerpc/mm/pgtable.c                    | 12 +++++
 arch/riscv/include/asm/pgtable.h             | 22 ++++-----
 arch/x86/include/asm/pgtable.h               | 22 ++++-----
 include/linux/page_table_check.h             | 69 ++++++++++++++++------------
 include/linux/pgtable.h                      | 10 ++--
 mm/page_table_check.c                        | 41 +++++++++--------
 16 files changed, 245 insertions(+), 130 deletions(-)
---
base-commit: c224625ec6f8a0476ffffc09807f4d717ba9cc93
change-id: 20251105-pgtable_check_v18rebase-2a8f88819994


--
Andrew Donnellan    OzLabs, ADL Canberra
ajd at linux.ibm.com   IBM Australia Limited



From ajd at linux.ibm.com  Thu Dec 18 09:09:34 2025
From: ajd at linux.ibm.com (Andrew Donnellan)
Date: Fri, 19 Dec 2025 04:09:34 +1100
Subject: [PATCH v18 02/12] arm64/mm: Add addr parameter to
 __ptep_get_and_clear_anysz()
In-Reply-To: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
References: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
Message-ID: <20251219-pgtable_check_v18rebase-v18-2-755bc151a50b@linux.ibm.com>

To provide support for page table check on powerpc, we need to reinstate the
address parameter in several functions, including
page_table_check_{pte,pmd,pud}_clear().

In preparation for this, add the addr parameter to arm64's
__ptep_get_and_clear_anysz() and change its callsites accordingly.

Signed-off-by: Andrew Donnellan <ajd at linux.ibm.com>
---
v15: new patch
---
 arch/arm64/include/asm/pgtable.h | 5 +++--
 arch/arm64/mm/hugetlbpage.c      | 7 ++++---
 2 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 52f3ea07427cef399e68bea0dbab39d03ea83060..29f7ae7011a820687f5b1e2fdc782eb37f85fc1b 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -1332,6 +1332,7 @@ static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma,
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG */
 
 static inline pte_t __ptep_get_and_clear_anysz(struct mm_struct *mm,
+					       unsigned long address,
 					       pte_t *ptep,
 					       unsigned long pgsize)
 {
@@ -1359,7 +1360,7 @@ static inline pte_t __ptep_get_and_clear_anysz(struct mm_struct *mm,
 static inline pte_t __ptep_get_and_clear(struct mm_struct *mm,
 				       unsigned long address, pte_t *ptep)
 {
-	return __ptep_get_and_clear_anysz(mm, ptep, PAGE_SIZE);
+	return __ptep_get_and_clear_anysz(mm, address, ptep, PAGE_SIZE);
 }
 
 static inline void __clear_full_ptes(struct mm_struct *mm, unsigned long addr,
@@ -1398,7 +1399,7 @@ static inline pte_t __get_and_clear_full_ptes(struct mm_struct *mm,
 static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
 					    unsigned long address, pmd_t *pmdp)
 {
-	return pte_pmd(__ptep_get_and_clear_anysz(mm, (pte_t *)pmdp, PMD_SIZE));
+	return pte_pmd(__ptep_get_and_clear_anysz(mm, address, (pte_t *)pmdp, PMD_SIZE));
 }
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c
index 1003b502075208d4252c27ffdacb1aaf4928639b..bcc28031eb7aa4ba175b5552f5449e69c6af5e61 100644
--- a/arch/arm64/mm/hugetlbpage.c
+++ b/arch/arm64/mm/hugetlbpage.c
@@ -159,11 +159,12 @@ static pte_t get_clear_contig(struct mm_struct *mm,
 	pte_t pte, tmp_pte;
 	bool present;
 
-	pte = __ptep_get_and_clear_anysz(mm, ptep, pgsize);
+	pte = __ptep_get_and_clear_anysz(mm, addr, ptep, pgsize);
 	present = pte_present(pte);
 	while (--ncontig) {
 		ptep++;
-		tmp_pte = __ptep_get_and_clear_anysz(mm, ptep, pgsize);
+		addr += pgsize;
+		tmp_pte = __ptep_get_and_clear_anysz(mm, addr, ptep, pgsize);
 		if (present) {
 			if (pte_dirty(tmp_pte))
 				pte = pte_mkdirty(pte);
@@ -207,7 +208,7 @@ static void clear_flush(struct mm_struct *mm,
 	unsigned long i, saddr = addr;
 
 	for (i = 0; i < ncontig; i++, addr += pgsize, ptep++)
-		__ptep_get_and_clear_anysz(mm, ptep, pgsize);
+		__ptep_get_and_clear_anysz(mm, addr, ptep, pgsize);
 
 	if (mm == &init_mm)
 		flush_tlb_kernel_range(saddr, addr);

-- 
2.52.0



From ajd at linux.ibm.com  Thu Dec 18 09:09:33 2025
From: ajd at linux.ibm.com (Andrew Donnellan)
Date: Fri, 19 Dec 2025 04:09:33 +1100
Subject: [PATCH v18 01/12] arm64/mm: Add addr parameter to
 __set_ptes_anysz()
In-Reply-To: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
References: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
Message-ID: <20251219-pgtable_check_v18rebase-v18-1-755bc151a50b@linux.ibm.com>

To provide support for page table check on powerpc, we need to reinstate the
address parameter in several functions, including
page_table_check_{ptes,pmds,puds}_set().

In preparation for this, add the addr parameter to arm64's __set_ptes_anysz()
and change its callsites accordingly.

Signed-off-by: Andrew Donnellan <ajd at linux.ibm.com>
---
v15: new patch
v16: rebase
---
 arch/arm64/include/asm/pgtable.h | 19 ++++++++-----------
 arch/arm64/mm/hugetlbpage.c      | 10 +++++-----
 2 files changed, 13 insertions(+), 16 deletions(-)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 445e18e92221c98eef717888aeac71d1d6b1da06..52f3ea07427cef399e68bea0dbab39d03ea83060 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -673,8 +673,8 @@ static inline pgprot_t pud_pgprot(pud_t pud)
 	return __pgprot(pud_val(pfn_pud(pfn, __pgprot(0))) ^ pud_val(pud));
 }
 
-static inline void __set_ptes_anysz(struct mm_struct *mm, pte_t *ptep,
-				    pte_t pte, unsigned int nr,
+static inline void __set_ptes_anysz(struct mm_struct *mm, unsigned long addr,
+				    pte_t *ptep, pte_t pte, unsigned int nr,
 				    unsigned long pgsize)
 {
 	unsigned long stride = pgsize >> PAGE_SHIFT;
@@ -709,26 +709,23 @@ static inline void __set_ptes_anysz(struct mm_struct *mm, pte_t *ptep,
 	__set_pte_complete(pte);
 }
 
-static inline void __set_ptes(struct mm_struct *mm,
-			      unsigned long __always_unused addr,
+static inline void __set_ptes(struct mm_struct *mm, unsigned long addr,
 			      pte_t *ptep, pte_t pte, unsigned int nr)
 {
-	__set_ptes_anysz(mm, ptep, pte, nr, PAGE_SIZE);
+	__set_ptes_anysz(mm, addr, ptep, pte, nr, PAGE_SIZE);
 }
 
-static inline void __set_pmds(struct mm_struct *mm,
-			      unsigned long __always_unused addr,
+static inline void __set_pmds(struct mm_struct *mm, unsigned long addr,
 			      pmd_t *pmdp, pmd_t pmd, unsigned int nr)
 {
-	__set_ptes_anysz(mm, (pte_t *)pmdp, pmd_pte(pmd), nr, PMD_SIZE);
+	__set_ptes_anysz(mm, addr, (pte_t *)pmdp, pmd_pte(pmd), nr, PMD_SIZE);
 }
 #define set_pmd_at(mm, addr, pmdp, pmd) __set_pmds(mm, addr, pmdp, pmd, 1)
 
-static inline void __set_puds(struct mm_struct *mm,
-			      unsigned long __always_unused addr,
+static inline void __set_puds(struct mm_struct *mm, unsigned long addr,
 			      pud_t *pudp, pud_t pud, unsigned int nr)
 {
-	__set_ptes_anysz(mm, (pte_t *)pudp, pud_pte(pud), nr, PUD_SIZE);
+	__set_ptes_anysz(mm, addr, (pte_t *)pudp, pud_pte(pud), nr, PUD_SIZE);
 }
 #define set_pud_at(mm, addr, pudp, pud) __set_puds(mm, addr, pudp, pud, 1)
 
diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c
index 1d90a7e753336d86314fee0f753e8779d6a6bc12..1003b502075208d4252c27ffdacb1aaf4928639b 100644
--- a/arch/arm64/mm/hugetlbpage.c
+++ b/arch/arm64/mm/hugetlbpage.c
@@ -225,8 +225,8 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
 	ncontig = num_contig_ptes(sz, &pgsize);
 
 	if (!pte_present(pte)) {
-		for (i = 0; i < ncontig; i++, ptep++)
-			__set_ptes_anysz(mm, ptep, pte, 1, pgsize);
+		for (i = 0; i < ncontig; i++, ptep++, addr += pgsize)
+			__set_ptes_anysz(mm, addr, ptep, pte, 1, pgsize);
 		return;
 	}
 
@@ -234,7 +234,7 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
 	if (pte_cont(pte) && pte_valid(__ptep_get(ptep)))
 		clear_flush(mm, addr, ptep, pgsize, ncontig);
 
-	__set_ptes_anysz(mm, ptep, pte, ncontig, pgsize);
+	__set_ptes_anysz(mm, addr, ptep, pte, ncontig, pgsize);
 }
 
 pte_t *huge_pte_alloc(struct mm_struct *mm, struct vm_area_struct *vma,
@@ -449,7 +449,7 @@ int huge_ptep_set_access_flags(struct vm_area_struct *vma,
 	if (pte_young(orig_pte))
 		pte = pte_mkyoung(pte);
 
-	__set_ptes_anysz(mm, ptep, pte, ncontig, pgsize);
+	__set_ptes_anysz(mm, addr, ptep, pte, ncontig, pgsize);
 	return 1;
 }
 
@@ -473,7 +473,7 @@ void huge_ptep_set_wrprotect(struct mm_struct *mm,
 	pte = get_clear_contig_flush(mm, addr, ptep, pgsize, ncontig);
 	pte = pte_wrprotect(pte);
 
-	__set_ptes_anysz(mm, ptep, pte, ncontig, pgsize);
+	__set_ptes_anysz(mm, addr, ptep, pte, ncontig, pgsize);
 }
 
 pte_t huge_ptep_clear_flush(struct vm_area_struct *vma,

-- 
2.52.0



From ajd at linux.ibm.com  Thu Dec 18 09:09:35 2025
From: ajd at linux.ibm.com (Andrew Donnellan)
Date: Fri, 19 Dec 2025 04:09:35 +1100
Subject: [PATCH v18 03/12] mm/page_table_check: Reinstate address parameter
 in [__]page_table_check_pud[s]_set()
In-Reply-To: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
References: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
Message-ID: <20251219-pgtable_check_v18rebase-v18-3-755bc151a50b@linux.ibm.com>

From: Rohan McLure <rmclure at linux.ibm.com>

This reverts commit 6d144436d954 ("mm/page_table_check: remove unused
parameter in [__]page_table_check_pud_set").

Reinstate previously unused parameters for the purpose of supporting
powerpc platforms, as many do not encode user/kernel ownership of the
page in the pte, but instead in the address of the access.

Apply this to __page_table_check_puds_set(), page_table_check_puds_set() and
the page_table_check_pud_set() wrapper macro.

[ajd at linux.ibm.com: rebase on riscv + arm64 changes, update commit message]
Signed-off-by: Rohan McLure <rmclure at linux.ibm.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin at soleen.com>
Acked-by: Ingo Molnar <mingo at kernel.org>  # x86
Acked-by: Alexandre Ghiti <alexghiti at rivosinc.com> # riscv
Signed-off-by: Andrew Donnellan <ajd at linux.ibm.com>
---
v13: remove inaccurate comment on riscv in the commit message
v14: fix an x86 usage I missed (found by akpm)
v15: rebase, amend commit message
---
 arch/arm64/include/asm/pgtable.h |  3 ++-
 arch/riscv/include/asm/pgtable.h |  4 ++--
 arch/x86/include/asm/pgtable.h   |  4 ++--
 include/linux/page_table_check.h | 12 ++++++------
 mm/page_table_check.c            |  4 ++--
 5 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 29f7ae7011a820687f5b1e2fdc782eb37f85fc1b..87ed9b1c011e167125a7f29a3388eca4c7bd9f29 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -688,7 +688,8 @@ static inline void __set_ptes_anysz(struct mm_struct *mm, unsigned long addr,
 		break;
 #ifndef __PAGETABLE_PMD_FOLDED
 	case PUD_SIZE:
-		page_table_check_puds_set(mm, (pud_t *)ptep, pte_pud(pte), nr);
+		page_table_check_puds_set(mm, addr, (pud_t *)ptep,
+					  pte_pud(pte), nr);
 		break;
 #endif
 	default:
diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
index 8bd36ac842eba94ec6af140ab81bd75d32ad1ff8..c4ea70903fedac7c055fb4cf530000a533c27ade 100644
--- a/arch/riscv/include/asm/pgtable.h
+++ b/arch/riscv/include/asm/pgtable.h
@@ -951,7 +951,7 @@ static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
 static inline void set_pud_at(struct mm_struct *mm, unsigned long addr,
 				pud_t *pudp, pud_t pud)
 {
-	page_table_check_pud_set(mm, pudp, pud);
+	page_table_check_pud_set(mm, addr, pudp, pud);
 	return __set_pte_at(mm, (pte_t *)pudp, pud_pte(pud));
 }
 
@@ -1114,7 +1114,7 @@ static inline void update_mmu_cache_pud(struct vm_area_struct *vma,
 static inline pud_t pudp_establish(struct vm_area_struct *vma,
 				   unsigned long address, pud_t *pudp, pud_t pud)
 {
-	page_table_check_pud_set(vma->vm_mm, pudp, pud);
+	page_table_check_pud_set(vma->vm_mm, address, pudp, pud);
 	return __pud(atomic_long_xchg((atomic_long_t *)pudp, pud_val(pud)));
 }
 
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index 2842fa1f7a2ce2346c51f76470a0902155d7d00d..2b540c563d8ddc5ed28e583de6a409c0e1bd97aa 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -1221,7 +1221,7 @@ static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
 static inline void set_pud_at(struct mm_struct *mm, unsigned long addr,
 			      pud_t *pudp, pud_t pud)
 {
-	page_table_check_pud_set(mm, pudp, pud);
+	page_table_check_pud_set(mm, addr, pudp, pud);
 	native_set_pud(pudp, pud);
 }
 
@@ -1372,7 +1372,7 @@ static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
 static inline pud_t pudp_establish(struct vm_area_struct *vma,
 		unsigned long address, pud_t *pudp, pud_t pud)
 {
-	page_table_check_pud_set(vma->vm_mm, pudp, pud);
+	page_table_check_pud_set(vma->vm_mm, address, pudp, pud);
 	if (IS_ENABLED(CONFIG_SMP)) {
 		return xchg(pudp, pud);
 	} else {
diff --git a/include/linux/page_table_check.h b/include/linux/page_table_check.h
index 289620d4aad3a03a0c3b27b08066fb27250cd10a..0bf18b884a1265fa98eb04d2e3dbd63d02e706f3 100644
--- a/include/linux/page_table_check.h
+++ b/include/linux/page_table_check.h
@@ -21,8 +21,8 @@ void __page_table_check_ptes_set(struct mm_struct *mm, pte_t *ptep, pte_t pte,
 		unsigned int nr);
 void __page_table_check_pmds_set(struct mm_struct *mm, pmd_t *pmdp, pmd_t pmd,
 		unsigned int nr);
-void __page_table_check_puds_set(struct mm_struct *mm, pud_t *pudp, pud_t pud,
-		unsigned int nr);
+void __page_table_check_puds_set(struct mm_struct *mm, unsigned long addr,
+		pud_t *pudp, pud_t pud, unsigned int nr);
 void __page_table_check_pte_clear_range(struct mm_struct *mm,
 					unsigned long addr,
 					pmd_t pmd);
@@ -86,12 +86,12 @@ static inline void page_table_check_pmds_set(struct mm_struct *mm,
 }
 
 static inline void page_table_check_puds_set(struct mm_struct *mm,
-		pud_t *pudp, pud_t pud, unsigned int nr)
+		unsigned long addr, pud_t *pudp, pud_t pud, unsigned int nr)
 {
 	if (static_branch_likely(&page_table_check_disabled))
 		return;
 
-	__page_table_check_puds_set(mm, pudp, pud, nr);
+	__page_table_check_puds_set(mm, addr, pudp, pud, nr);
 }
 
 static inline void page_table_check_pte_clear_range(struct mm_struct *mm,
@@ -137,7 +137,7 @@ static inline void page_table_check_pmds_set(struct mm_struct *mm,
 }
 
 static inline void page_table_check_puds_set(struct mm_struct *mm,
-		pud_t *pudp, pud_t pud, unsigned int nr)
+		unsigned long addr, pud_t *pudp, pud_t pud, unsigned int nr)
 {
 }
 
@@ -150,6 +150,6 @@ static inline void page_table_check_pte_clear_range(struct mm_struct *mm,
 #endif /* CONFIG_PAGE_TABLE_CHECK */
 
 #define page_table_check_pmd_set(mm, pmdp, pmd)	page_table_check_pmds_set(mm, pmdp, pmd, 1)
-#define page_table_check_pud_set(mm, pudp, pud)	page_table_check_puds_set(mm, pudp, pud, 1)
+#define page_table_check_pud_set(mm, addr, pudp, pud)	page_table_check_puds_set(mm, addr, pudp, pud, 1)
 
 #endif /* __LINUX_PAGE_TABLE_CHECK_H */
diff --git a/mm/page_table_check.c b/mm/page_table_check.c
index 741884645ab0fdd49425098681d62070c343152b..a48f835216a1f50ffd088477ae7e80896be43bc6 100644
--- a/mm/page_table_check.c
+++ b/mm/page_table_check.c
@@ -243,8 +243,8 @@ void __page_table_check_pmds_set(struct mm_struct *mm, pmd_t *pmdp, pmd_t pmd,
 }
 EXPORT_SYMBOL(__page_table_check_pmds_set);
 
-void __page_table_check_puds_set(struct mm_struct *mm, pud_t *pudp, pud_t pud,
-		unsigned int nr)
+void __page_table_check_puds_set(struct mm_struct *mm, unsigned long addr,
+		pud_t *pudp, pud_t pud,	unsigned int nr)
 {
 	unsigned long stride = PUD_SIZE >> PAGE_SHIFT;
 	unsigned int i;

-- 
2.52.0



From ajd at linux.ibm.com  Thu Dec 18 09:09:36 2025
From: ajd at linux.ibm.com (Andrew Donnellan)
Date: Fri, 19 Dec 2025 04:09:36 +1100
Subject: [PATCH v18 04/12] mm/page_table_check: Reinstate address parameter
 in [__]page_table_check_pmd[s]_set()
In-Reply-To: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
References: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
Message-ID: <20251219-pgtable_check_v18rebase-v18-4-755bc151a50b@linux.ibm.com>

From: Rohan McLure <rmclure at linux.ibm.com>

This reverts commit a3b837130b58 ("mm/page_table_check: remove unused
parameter in [__]page_table_check_pmd_set").

Reinstate previously unused parameters for the purpose of supporting
powerpc platforms, as many do not encode user/kernel ownership of the
page in the pte, but instead in the address of the access.

Apply this to __page_table_check_pmds_set(), page_table_check_pmd_set(), and
the page_table_check_pmd_set() wrapper macro.

[ajd at linux.ibm.com: rebase on arm64 + riscv changes, update commit message]
Signed-off-by: Rohan McLure <rmclure at linux.ibm.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin at soleen.com>
Acked-by: Ingo Molnar <mingo at kernel.org>  # x86
Acked-by: Alexandre Ghiti <alexghiti at rivosinc.com> # riscv
Signed-off-by: Andrew Donnellan <ajd at linux.ibm.com>
---
v13: remove inaccurate comment on riscv in the commit message
v14: rebase
v15: rebase, amend commit message
---
 arch/arm64/include/asm/pgtable.h |  5 +++--
 arch/riscv/include/asm/pgtable.h |  4 ++--
 arch/x86/include/asm/pgtable.h   |  4 ++--
 include/linux/page_table_check.h | 12 ++++++------
 mm/page_table_check.c            |  4 ++--
 5 files changed, 15 insertions(+), 14 deletions(-)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 87ed9b1c011e167125a7f29a3388eca4c7bd9f29..4b580d6246f5a1c8f859bf79665419bbcd8c7cd3 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -684,7 +684,8 @@ static inline void __set_ptes_anysz(struct mm_struct *mm, unsigned long addr,
 		page_table_check_ptes_set(mm, ptep, pte, nr);
 		break;
 	case PMD_SIZE:
-		page_table_check_pmds_set(mm, (pmd_t *)ptep, pte_pmd(pte), nr);
+		page_table_check_pmds_set(mm, addr, (pmd_t *)ptep,
+					  pte_pmd(pte), nr);
 		break;
 #ifndef __PAGETABLE_PMD_FOLDED
 	case PUD_SIZE:
@@ -1489,7 +1490,7 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm,
 static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
 		unsigned long address, pmd_t *pmdp, pmd_t pmd)
 {
-	page_table_check_pmd_set(vma->vm_mm, pmdp, pmd);
+	page_table_check_pmd_set(vma->vm_mm, address, pmdp, pmd);
 	return __pmd(xchg_relaxed(&pmd_val(*pmdp), pmd_val(pmd)));
 }
 #endif
diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
index c4ea70903fedac7c055fb4cf530000a533c27ade..3fea1d07f7470a04fdc9a6f581d21667e35e0e2a 100644
--- a/arch/riscv/include/asm/pgtable.h
+++ b/arch/riscv/include/asm/pgtable.h
@@ -944,7 +944,7 @@ static inline pmd_t pmd_swp_clear_soft_dirty(pmd_t pmd)
 static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
 				pmd_t *pmdp, pmd_t pmd)
 {
-	page_table_check_pmd_set(mm, pmdp, pmd);
+	page_table_check_pmd_set(mm, addr, pmdp, pmd);
 	return __set_pte_at(mm, (pte_t *)pmdp, pmd_pte(pmd));
 }
 
@@ -1015,7 +1015,7 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm,
 static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
 				unsigned long address, pmd_t *pmdp, pmd_t pmd)
 {
-	page_table_check_pmd_set(vma->vm_mm, pmdp, pmd);
+	page_table_check_pmd_set(vma->vm_mm, address, pmdp, pmd);
 	return __pmd(atomic_long_xchg((atomic_long_t *)pmdp, pmd_val(pmd)));
 }
 
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index 2b540c563d8ddc5ed28e583de6a409c0e1bd97aa..7fd876f8d828ea70def7adc51cc17e70d3046e35 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -1214,7 +1214,7 @@ static inline pud_t native_local_pudp_get_and_clear(pud_t *pudp)
 static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
 			      pmd_t *pmdp, pmd_t pmd)
 {
-	page_table_check_pmd_set(mm, pmdp, pmd);
+	page_table_check_pmd_set(mm, addr, pmdp, pmd);
 	set_pmd(pmdp, pmd);
 }
 
@@ -1357,7 +1357,7 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm,
 static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
 		unsigned long address, pmd_t *pmdp, pmd_t pmd)
 {
-	page_table_check_pmd_set(vma->vm_mm, pmdp, pmd);
+	page_table_check_pmd_set(vma->vm_mm, address, pmdp, pmd);
 	if (IS_ENABLED(CONFIG_SMP)) {
 		return xchg(pmdp, pmd);
 	} else {
diff --git a/include/linux/page_table_check.h b/include/linux/page_table_check.h
index 0bf18b884a1265fa98eb04d2e3dbd63d02e706f3..cf7c28d8d468c026cb5278435a64fbcf0fe9260e 100644
--- a/include/linux/page_table_check.h
+++ b/include/linux/page_table_check.h
@@ -19,8 +19,8 @@ void __page_table_check_pmd_clear(struct mm_struct *mm, pmd_t pmd);
 void __page_table_check_pud_clear(struct mm_struct *mm, pud_t pud);
 void __page_table_check_ptes_set(struct mm_struct *mm, pte_t *ptep, pte_t pte,
 		unsigned int nr);
-void __page_table_check_pmds_set(struct mm_struct *mm, pmd_t *pmdp, pmd_t pmd,
-		unsigned int nr);
+void __page_table_check_pmds_set(struct mm_struct *mm, unsigned long addr,
+		pmd_t *pmdp, pmd_t pmd, unsigned int nr);
 void __page_table_check_puds_set(struct mm_struct *mm, unsigned long addr,
 		pud_t *pudp, pud_t pud, unsigned int nr);
 void __page_table_check_pte_clear_range(struct mm_struct *mm,
@@ -77,12 +77,12 @@ static inline void page_table_check_ptes_set(struct mm_struct *mm,
 }
 
 static inline void page_table_check_pmds_set(struct mm_struct *mm,
-		pmd_t *pmdp, pmd_t pmd, unsigned int nr)
+		unsigned long addr, pmd_t *pmdp, pmd_t pmd, unsigned int nr)
 {
 	if (static_branch_likely(&page_table_check_disabled))
 		return;
 
-	__page_table_check_pmds_set(mm, pmdp, pmd, nr);
+	__page_table_check_pmds_set(mm, addr, pmdp, pmd, nr);
 }
 
 static inline void page_table_check_puds_set(struct mm_struct *mm,
@@ -132,7 +132,7 @@ static inline void page_table_check_ptes_set(struct mm_struct *mm,
 }
 
 static inline void page_table_check_pmds_set(struct mm_struct *mm,
-		pmd_t *pmdp, pmd_t pmd, unsigned int nr)
+		unsigned long addr, pmd_t *pmdp, pmd_t pmd, unsigned int nr)
 {
 }
 
@@ -149,7 +149,7 @@ static inline void page_table_check_pte_clear_range(struct mm_struct *mm,
 
 #endif /* CONFIG_PAGE_TABLE_CHECK */
 
-#define page_table_check_pmd_set(mm, pmdp, pmd)	page_table_check_pmds_set(mm, pmdp, pmd, 1)
+#define page_table_check_pmd_set(mm, addr, pmdp, pmd)	page_table_check_pmds_set(mm, addr, pmdp, pmd, 1)
 #define page_table_check_pud_set(mm, addr, pudp, pud)	page_table_check_puds_set(mm, addr, pudp, pud, 1)
 
 #endif /* __LINUX_PAGE_TABLE_CHECK_H */
diff --git a/mm/page_table_check.c b/mm/page_table_check.c
index a48f835216a1f50ffd088477ae7e80896be43bc6..86dc4e4d1dad12fe5d9d86905234b009257586d5 100644
--- a/mm/page_table_check.c
+++ b/mm/page_table_check.c
@@ -225,8 +225,8 @@ static inline void page_table_check_pmd_flags(pmd_t pmd)
 	}
 }
 
-void __page_table_check_pmds_set(struct mm_struct *mm, pmd_t *pmdp, pmd_t pmd,
-		unsigned int nr)
+void __page_table_check_pmds_set(struct mm_struct *mm, unsigned long addr,
+		pmd_t *pmdp, pmd_t pmd, unsigned int nr)
 {
 	unsigned long stride = PMD_SIZE >> PAGE_SHIFT;
 	unsigned int i;

-- 
2.52.0



From ajd at linux.ibm.com  Thu Dec 18 09:09:37 2025
From: ajd at linux.ibm.com (Andrew Donnellan)
Date: Fri, 19 Dec 2025 04:09:37 +1100
Subject: [PATCH v18 05/12] mm/page_table_check: Provide addr parameter to
 page_table_check_ptes_set()
In-Reply-To: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
References: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
Message-ID: <20251219-pgtable_check_v18rebase-v18-5-755bc151a50b@linux.ibm.com>

From: Rohan McLure <rmclure at linux.ibm.com>

To provide support for powerpc platforms, provide an addr parameter to
the __page_table_check_ptes_set() and page_table_check_ptes_set() routines.
This parameter is needed on some powerpc platforms which do not encode whether
a mapping is for user or kernel in the pte. On such platforms, this can be
inferred from the addr parameter.

[ajd at linux.ibm.com: rebase on arm64 + riscv changes, update commit message]
Signed-off-by: Rohan McLure <rmclure at linux.ibm.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin at soleen.com>
Acked-by: Alexandre Ghiti <alexghiti at rivosinc.com> # riscv
Signed-off-by: Andrew Donnellan <ajd at linux.ibm.com>
---
v15: rebase, amend commit message
---
 arch/arm64/include/asm/pgtable.h |  2 +-
 arch/riscv/include/asm/pgtable.h |  2 +-
 include/linux/page_table_check.h | 12 +++++++-----
 include/linux/pgtable.h          |  2 +-
 mm/page_table_check.c            |  4 ++--
 5 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 4b580d6246f5a1c8f859bf79665419bbcd8c7cd3..d1dd0266bb0c946442df88594cc39e958185af0a 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -681,7 +681,7 @@ static inline void __set_ptes_anysz(struct mm_struct *mm, unsigned long addr,
 
 	switch (pgsize) {
 	case PAGE_SIZE:
-		page_table_check_ptes_set(mm, ptep, pte, nr);
+		page_table_check_ptes_set(mm, addr, ptep, pte, nr);
 		break;
 	case PMD_SIZE:
 		page_table_check_pmds_set(mm, addr, (pmd_t *)ptep,
diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
index 3fea1d07f7470a04fdc9a6f581d21667e35e0e2a..89abba40e3e426c00e6964bdf135042777319588 100644
--- a/arch/riscv/include/asm/pgtable.h
+++ b/arch/riscv/include/asm/pgtable.h
@@ -631,7 +631,7 @@ static inline void __set_pte_at(struct mm_struct *mm, pte_t *ptep, pte_t pteval)
 static inline void set_ptes(struct mm_struct *mm, unsigned long addr,
 		pte_t *ptep, pte_t pteval, unsigned int nr)
 {
-	page_table_check_ptes_set(mm, ptep, pteval, nr);
+	page_table_check_ptes_set(mm, addr, ptep, pteval, nr);
 
 	for (;;) {
 		__set_pte_at(mm, ptep, pteval);
diff --git a/include/linux/page_table_check.h b/include/linux/page_table_check.h
index cf7c28d8d468c026cb5278435a64fbcf0fe9260e..66e10923841691a59620da8d17f7bb7b09e6a6d3 100644
--- a/include/linux/page_table_check.h
+++ b/include/linux/page_table_check.h
@@ -17,8 +17,8 @@ void __page_table_check_zero(struct page *page, unsigned int order);
 void __page_table_check_pte_clear(struct mm_struct *mm, pte_t pte);
 void __page_table_check_pmd_clear(struct mm_struct *mm, pmd_t pmd);
 void __page_table_check_pud_clear(struct mm_struct *mm, pud_t pud);
-void __page_table_check_ptes_set(struct mm_struct *mm, pte_t *ptep, pte_t pte,
-		unsigned int nr);
+void __page_table_check_ptes_set(struct mm_struct *mm, unsigned long addr,
+		pte_t *ptep, pte_t pte, unsigned int nr);
 void __page_table_check_pmds_set(struct mm_struct *mm, unsigned long addr,
 		pmd_t *pmdp, pmd_t pmd, unsigned int nr);
 void __page_table_check_puds_set(struct mm_struct *mm, unsigned long addr,
@@ -68,12 +68,13 @@ static inline void page_table_check_pud_clear(struct mm_struct *mm, pud_t pud)
 }
 
 static inline void page_table_check_ptes_set(struct mm_struct *mm,
-		pte_t *ptep, pte_t pte, unsigned int nr)
+					     unsigned long addr, pte_t *ptep,
+					     pte_t pte, unsigned int nr)
 {
 	if (static_branch_likely(&page_table_check_disabled))
 		return;
 
-	__page_table_check_ptes_set(mm, ptep, pte, nr);
+	__page_table_check_ptes_set(mm, addr, ptep, pte, nr);
 }
 
 static inline void page_table_check_pmds_set(struct mm_struct *mm,
@@ -127,7 +128,8 @@ static inline void page_table_check_pud_clear(struct mm_struct *mm, pud_t pud)
 }
 
 static inline void page_table_check_ptes_set(struct mm_struct *mm,
-		pte_t *ptep, pte_t pte, unsigned int nr)
+					     unsigned long addr, pte_t *ptep,
+					     pte_t pte, unsigned int nr)
 {
 }
 
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index 2f0dd3a4ace1acd665f229d4ea2a67187fd4d2b9..496873f44f67b73fc32940c956fd5265b748faad 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -429,7 +429,7 @@ static inline pte_t pte_advance_pfn(pte_t pte, unsigned long nr)
 static inline void set_ptes(struct mm_struct *mm, unsigned long addr,
 		pte_t *ptep, pte_t pte, unsigned int nr)
 {
-	page_table_check_ptes_set(mm, ptep, pte, nr);
+	page_table_check_ptes_set(mm, addr, ptep, pte, nr);
 
 	for (;;) {
 		set_pte(ptep, pte);
diff --git a/mm/page_table_check.c b/mm/page_table_check.c
index 86dc4e4d1dad12fe5d9d86905234b009257586d5..2871d9c453682ba922b2fcf532cb6a7d867ad952 100644
--- a/mm/page_table_check.c
+++ b/mm/page_table_check.c
@@ -196,8 +196,8 @@ static void page_table_check_pte_flags(pte_t pte)
 	}
 }
 
-void __page_table_check_ptes_set(struct mm_struct *mm, pte_t *ptep, pte_t pte,
-		unsigned int nr)
+void __page_table_check_ptes_set(struct mm_struct *mm, unsigned long addr,
+				 pte_t *ptep, pte_t pte, unsigned int nr)
 {
 	unsigned int i;
 

-- 
2.52.0



From ajd at linux.ibm.com  Thu Dec 18 09:09:38 2025
From: ajd at linux.ibm.com (Andrew Donnellan)
Date: Fri, 19 Dec 2025 04:09:38 +1100
Subject: [PATCH v18 06/12] mm/page_table_check: Reinstate address parameter
 in [__]page_table_check_pud_clear()
In-Reply-To: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
References: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
Message-ID: <20251219-pgtable_check_v18rebase-v18-6-755bc151a50b@linux.ibm.com>

From: Rohan McLure <rmclure at linux.ibm.com>

This reverts commit 931c38e16499 ("mm/page_table_check: remove unused
parameter in [__]page_table_check_pud_clear").

Reinstate previously unused parameters for the purpose of supporting
powerpc platforms, as many do not encode user/kernel ownership of the
page in the pte, but instead in the address of the access.

[ajd at linux.ibm.com: rebase on arm64 changes]
Signed-off-by: Rohan McLure <rmclure at linux.ibm.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin at soleen.com>
Acked-by: Ingo Molnar <mingo at kernel.org>  # x86
Signed-off-by: Andrew Donnellan <ajd at linux.ibm.com>
---
v15: rebase
v17: rebase, fix conflict with riscv patch
---
 arch/arm64/include/asm/pgtable.h |  2 +-
 arch/riscv/include/asm/pgtable.h |  2 +-
 arch/x86/include/asm/pgtable.h   |  2 +-
 include/linux/page_table_check.h | 11 +++++++----
 include/linux/pgtable.h          |  2 +-
 mm/page_table_check.c            |  5 +++--
 6 files changed, 14 insertions(+), 10 deletions(-)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index d1dd0266bb0c946442df88594cc39e958185af0a..595405e6bfc736f2824a9c2e8784351f15ad0571 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -1349,7 +1349,7 @@ static inline pte_t __ptep_get_and_clear_anysz(struct mm_struct *mm,
 		break;
 #ifndef __PAGETABLE_PMD_FOLDED
 	case PUD_SIZE:
-		page_table_check_pud_clear(mm, pte_pud(pte));
+		page_table_check_pud_clear(mm, address, pte_pud(pte));
 		break;
 #endif
 	default:
diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
index 89abba40e3e426c00e6964bdf135042777319588..841494ef46ee6ae1410f420dc7d0a99c4e1958cf 100644
--- a/arch/riscv/include/asm/pgtable.h
+++ b/arch/riscv/include/asm/pgtable.h
@@ -1093,7 +1093,7 @@ static inline pud_t pudp_huge_get_and_clear(struct mm_struct *mm,
 	pud_clear(pudp);
 #endif
 
-	page_table_check_pud_clear(mm, pud);
+	page_table_check_pud_clear(mm, address, pud);
 
 	return pud;
 }
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index 7fd876f8d828ea70def7adc51cc17e70d3046e35..3eb36a36058face6aba92efe3eed7214752e751f 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -1330,7 +1330,7 @@ static inline pud_t pudp_huge_get_and_clear(struct mm_struct *mm,
 {
 	pud_t pud = native_pudp_get_and_clear(pudp);
 
-	page_table_check_pud_clear(mm, pud);
+	page_table_check_pud_clear(mm, addr, pud);
 
 	return pud;
 }
diff --git a/include/linux/page_table_check.h b/include/linux/page_table_check.h
index 66e10923841691a59620da8d17f7bb7b09e6a6d3..808cc3a48c28fcf988ba2c50031fa4f317496582 100644
--- a/include/linux/page_table_check.h
+++ b/include/linux/page_table_check.h
@@ -16,7 +16,8 @@ extern struct page_ext_operations page_table_check_ops;
 void __page_table_check_zero(struct page *page, unsigned int order);
 void __page_table_check_pte_clear(struct mm_struct *mm, pte_t pte);
 void __page_table_check_pmd_clear(struct mm_struct *mm, pmd_t pmd);
-void __page_table_check_pud_clear(struct mm_struct *mm, pud_t pud);
+void __page_table_check_pud_clear(struct mm_struct *mm, unsigned long addr,
+				  pud_t pud);
 void __page_table_check_ptes_set(struct mm_struct *mm, unsigned long addr,
 		pte_t *ptep, pte_t pte, unsigned int nr);
 void __page_table_check_pmds_set(struct mm_struct *mm, unsigned long addr,
@@ -59,12 +60,13 @@ static inline void page_table_check_pmd_clear(struct mm_struct *mm, pmd_t pmd)
 	__page_table_check_pmd_clear(mm, pmd);
 }
 
-static inline void page_table_check_pud_clear(struct mm_struct *mm, pud_t pud)
+static inline void page_table_check_pud_clear(struct mm_struct *mm,
+					      unsigned long addr, pud_t pud)
 {
 	if (static_branch_likely(&page_table_check_disabled))
 		return;
 
-	__page_table_check_pud_clear(mm, pud);
+	__page_table_check_pud_clear(mm, addr, pud);
 }
 
 static inline void page_table_check_ptes_set(struct mm_struct *mm,
@@ -123,7 +125,8 @@ static inline void page_table_check_pmd_clear(struct mm_struct *mm, pmd_t pmd)
 {
 }
 
-static inline void page_table_check_pud_clear(struct mm_struct *mm, pud_t pud)
+static inline void page_table_check_pud_clear(struct mm_struct *mm,
+					      unsigned long addr, pud_t pud)
 {
 }
 
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index 496873f44f67b73fc32940c956fd5265b748faad..ed3c28ebeb35b766418abdefa5cc6604c0533479 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -801,7 +801,7 @@ static inline pud_t pudp_huge_get_and_clear(struct mm_struct *mm,
 	pud_t pud = *pudp;
 
 	pud_clear(pudp);
-	page_table_check_pud_clear(mm, pud);
+	page_table_check_pud_clear(mm, address, pud);
 
 	return pud;
 }
diff --git a/mm/page_table_check.c b/mm/page_table_check.c
index 2871d9c453682ba922b2fcf532cb6a7d867ad952..2295bc9368ab9cc827ee671ff9abf18a6b738172 100644
--- a/mm/page_table_check.c
+++ b/mm/page_table_check.c
@@ -167,7 +167,8 @@ void __page_table_check_pmd_clear(struct mm_struct *mm, pmd_t pmd)
 }
 EXPORT_SYMBOL(__page_table_check_pmd_clear);
 
-void __page_table_check_pud_clear(struct mm_struct *mm, pud_t pud)
+void __page_table_check_pud_clear(struct mm_struct *mm, unsigned long addr,
+				  pud_t pud)
 {
 	if (&init_mm == mm)
 		return;
@@ -253,7 +254,7 @@ void __page_table_check_puds_set(struct mm_struct *mm, unsigned long addr,
 		return;
 
 	for (i = 0; i < nr; i++)
-		__page_table_check_pud_clear(mm, *(pudp + i));
+		__page_table_check_pud_clear(mm, addr + PUD_SIZE * i, *(pudp + i));
 	if (pud_user_accessible_page(pud))
 		page_table_check_set(pud_pfn(pud), stride * nr, pud_write(pud));
 }

-- 
2.52.0



From ajd at linux.ibm.com  Thu Dec 18 09:09:39 2025
From: ajd at linux.ibm.com (Andrew Donnellan)
Date: Fri, 19 Dec 2025 04:09:39 +1100
Subject: [PATCH v18 07/12] mm/page_table_check: Reinstate address parameter
 in [__]page_table_check_pmd_clear()
In-Reply-To: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
References: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
Message-ID: <20251219-pgtable_check_v18rebase-v18-7-755bc151a50b@linux.ibm.com>

From: Rohan McLure <rmclure at linux.ibm.com>

This reverts commit 1831414cd729 ("mm/page_table_check: remove unused
parameter in [__]page_table_check_pmd_clear").

Reinstate previously unused parameters for the purpose of supporting
powerpc platforms, as many do not encode user/kernel ownership of the
page in the pte, but instead in the address of the access.

[ajd at linux.ibm.com: rebase on arm64 changes]
Signed-off-by: Rohan McLure <rmclure at linux.ibm.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin at soleen.com>
Acked-by: Ingo Molnar <mingo at kernel.org>  # x86
Acked-by: Alexandre Ghiti <alexghiti at rivosinc.com> # riscv
Signed-off-by: Andrew Donnellan <ajd at linux.ibm.com>
---
v15: rebase
---
 arch/arm64/include/asm/pgtable.h |  2 +-
 arch/riscv/include/asm/pgtable.h |  2 +-
 arch/x86/include/asm/pgtable.h   |  2 +-
 include/linux/page_table_check.h | 11 +++++++----
 include/linux/pgtable.h          |  2 +-
 mm/page_table_check.c            |  5 +++--
 6 files changed, 14 insertions(+), 10 deletions(-)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 595405e6bfc736f2824a9c2e8784351f15ad0571..5abad90913eb8b0a3aa867cd5a66107bbf96e177 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -1345,7 +1345,7 @@ static inline pte_t __ptep_get_and_clear_anysz(struct mm_struct *mm,
 		page_table_check_pte_clear(mm, pte);
 		break;
 	case PMD_SIZE:
-		page_table_check_pmd_clear(mm, pte_pmd(pte));
+		page_table_check_pmd_clear(mm, address, pte_pmd(pte));
 		break;
 #ifndef __PAGETABLE_PMD_FOLDED
 	case PUD_SIZE:
diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
index 841494ef46ee6ae1410f420dc7d0a99c4e1958cf..f179970fe47d333565a9199e0991e806aed44346 100644
--- a/arch/riscv/include/asm/pgtable.h
+++ b/arch/riscv/include/asm/pgtable.h
@@ -999,7 +999,7 @@ static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
 {
 	pmd_t pmd = __pmd(atomic_long_xchg((atomic_long_t *)pmdp, 0));
 
-	page_table_check_pmd_clear(mm, pmd);
+	page_table_check_pmd_clear(mm, address, pmd);
 
 	return pmd;
 }
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index 3eb36a36058face6aba92efe3eed7214752e751f..5a2b2d3a80d83d8eff2c1a6f69df3e80590c684a 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -1319,7 +1319,7 @@ static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm, unsigned long
 {
 	pmd_t pmd = native_pmdp_get_and_clear(pmdp);
 
-	page_table_check_pmd_clear(mm, pmd);
+	page_table_check_pmd_clear(mm, addr, pmd);
 
 	return pmd;
 }
diff --git a/include/linux/page_table_check.h b/include/linux/page_table_check.h
index 808cc3a48c28fcf988ba2c50031fa4f317496582..3973b69ae294e501a9c6c3140bc462d6d9b7d203 100644
--- a/include/linux/page_table_check.h
+++ b/include/linux/page_table_check.h
@@ -15,7 +15,8 @@ extern struct page_ext_operations page_table_check_ops;
 
 void __page_table_check_zero(struct page *page, unsigned int order);
 void __page_table_check_pte_clear(struct mm_struct *mm, pte_t pte);
-void __page_table_check_pmd_clear(struct mm_struct *mm, pmd_t pmd);
+void __page_table_check_pmd_clear(struct mm_struct *mm, unsigned long addr,
+				  pmd_t pmd);
 void __page_table_check_pud_clear(struct mm_struct *mm, unsigned long addr,
 				  pud_t pud);
 void __page_table_check_ptes_set(struct mm_struct *mm, unsigned long addr,
@@ -52,12 +53,13 @@ static inline void page_table_check_pte_clear(struct mm_struct *mm, pte_t pte)
 	__page_table_check_pte_clear(mm, pte);
 }
 
-static inline void page_table_check_pmd_clear(struct mm_struct *mm, pmd_t pmd)
+static inline void page_table_check_pmd_clear(struct mm_struct *mm,
+					      unsigned long addr, pmd_t pmd)
 {
 	if (static_branch_likely(&page_table_check_disabled))
 		return;
 
-	__page_table_check_pmd_clear(mm, pmd);
+	__page_table_check_pmd_clear(mm, addr, pmd);
 }
 
 static inline void page_table_check_pud_clear(struct mm_struct *mm,
@@ -121,7 +123,8 @@ static inline void page_table_check_pte_clear(struct mm_struct *mm, pte_t pte)
 {
 }
 
-static inline void page_table_check_pmd_clear(struct mm_struct *mm, pmd_t pmd)
+static inline void page_table_check_pmd_clear(struct mm_struct *mm,
+					      unsigned long addr, pmd_t pmd)
 {
 }
 
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index ed3c28ebeb35b766418abdefa5cc6604c0533479..2d1f7369624c504b531beb8965e7352770a5f4bc 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -788,7 +788,7 @@ static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
 	pmd_t pmd = *pmdp;
 
 	pmd_clear(pmdp);
-	page_table_check_pmd_clear(mm, pmd);
+	page_table_check_pmd_clear(mm, address, pmd);
 
 	return pmd;
 }
diff --git a/mm/page_table_check.c b/mm/page_table_check.c
index 2295bc9368ab9cc827ee671ff9abf18a6b738172..e8280b0b6dda97ee68bb52593df454665bac9acf 100644
--- a/mm/page_table_check.c
+++ b/mm/page_table_check.c
@@ -156,7 +156,8 @@ void __page_table_check_pte_clear(struct mm_struct *mm, pte_t pte)
 }
 EXPORT_SYMBOL(__page_table_check_pte_clear);
 
-void __page_table_check_pmd_clear(struct mm_struct *mm, pmd_t pmd)
+void __page_table_check_pmd_clear(struct mm_struct *mm, unsigned long addr,
+				  pmd_t pmd)
 {
 	if (&init_mm == mm)
 		return;
@@ -238,7 +239,7 @@ void __page_table_check_pmds_set(struct mm_struct *mm, unsigned long addr,
 	page_table_check_pmd_flags(pmd);
 
 	for (i = 0; i < nr; i++)
-		__page_table_check_pmd_clear(mm, *(pmdp + i));
+		__page_table_check_pmd_clear(mm, addr + PMD_SIZE * i, *(pmdp + i));
 	if (pmd_user_accessible_page(pmd))
 		page_table_check_set(pmd_pfn(pmd), stride * nr, pmd_write(pmd));
 }

-- 
2.52.0



From ajd at linux.ibm.com  Thu Dec 18 09:09:40 2025
From: ajd at linux.ibm.com (Andrew Donnellan)
Date: Fri, 19 Dec 2025 04:09:40 +1100
Subject: [PATCH v18 08/12] mm/page_table_check: Reinstate address parameter
 in [__]page_table_check_pte_clear()
In-Reply-To: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
References: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
Message-ID: <20251219-pgtable_check_v18rebase-v18-8-755bc151a50b@linux.ibm.com>

From: Rohan McLure <rmclure at linux.ibm.com>

This reverts commit aa232204c468 ("mm/page_table_check: remove unused
parameter in [__]page_table_check_pte_clear").

Reinstate previously unused parameters for the purpose of supporting
powerpc platforms, as many do not encode user/kernel ownership of the
page in the pte, but instead in the address of the access.

[ajd at linux.ibm.com: rebase, fix additional occurrence and loop handling]
Signed-off-by: Rohan McLure <rmclure at linux.ibm.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin at soleen.com>
Acked-by: Ingo Molnar <mingo at kernel.org>  # x86
Acked-by: Alexandre Ghiti <alexghiti at rivosinc.com> # riscv
Signed-off-by: Andrew Donnellan <ajd at linux.ibm.com>
---
v13: fix an additional occurrence
v15: rebase, fix loop handling
---
 arch/arm64/include/asm/pgtable.h |  2 +-
 arch/riscv/include/asm/pgtable.h |  2 +-
 arch/x86/include/asm/pgtable.h   |  4 ++--
 include/linux/page_table_check.h | 11 +++++++----
 include/linux/pgtable.h          |  4 ++--
 mm/page_table_check.c            |  7 ++++---
 6 files changed, 17 insertions(+), 13 deletions(-)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 5abad90913eb8b0a3aa867cd5a66107bbf96e177..ce64c560e284e1c2ff9d698cf868070ed58ba045 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -1342,7 +1342,7 @@ static inline pte_t __ptep_get_and_clear_anysz(struct mm_struct *mm,
 
 	switch (pgsize) {
 	case PAGE_SIZE:
-		page_table_check_pte_clear(mm, pte);
+		page_table_check_pte_clear(mm, address, pte);
 		break;
 	case PMD_SIZE:
 		page_table_check_pmd_clear(mm, address, pte_pmd(pte));
diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
index f179970fe47d333565a9199e0991e806aed44346..9af5bfc780800fe2f974daa5329277c46877f848 100644
--- a/arch/riscv/include/asm/pgtable.h
+++ b/arch/riscv/include/asm/pgtable.h
@@ -662,7 +662,7 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
 {
 	pte_t pte = __pte(atomic_long_xchg((atomic_long_t *)ptep, 0));
 
-	page_table_check_pte_clear(mm, pte);
+	page_table_check_pte_clear(mm, address, pte);
 
 	return pte;
 }
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index 5a2b2d3a80d83d8eff2c1a6f69df3e80590c684a..6ec6cf7ad2d4d92da7d3396bc96a5b5902e81576 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -1252,7 +1252,7 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
 				       pte_t *ptep)
 {
 	pte_t pte = native_ptep_get_and_clear(ptep);
-	page_table_check_pte_clear(mm, pte);
+	page_table_check_pte_clear(mm, addr, pte);
 	return pte;
 }
 
@@ -1268,7 +1268,7 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm,
 		 * care about updates and native needs no locking
 		 */
 		pte = native_local_ptep_get_and_clear(ptep);
-		page_table_check_pte_clear(mm, pte);
+		page_table_check_pte_clear(mm, addr, pte);
 	} else {
 		pte = ptep_get_and_clear(mm, addr, ptep);
 	}
diff --git a/include/linux/page_table_check.h b/include/linux/page_table_check.h
index 3973b69ae294e501a9c6c3140bc462d6d9b7d203..12268a32e8be151f66f2787ce87096f10d4fa744 100644
--- a/include/linux/page_table_check.h
+++ b/include/linux/page_table_check.h
@@ -14,7 +14,8 @@ extern struct static_key_true page_table_check_disabled;
 extern struct page_ext_operations page_table_check_ops;
 
 void __page_table_check_zero(struct page *page, unsigned int order);
-void __page_table_check_pte_clear(struct mm_struct *mm, pte_t pte);
+void __page_table_check_pte_clear(struct mm_struct *mm, unsigned long addr,
+				  pte_t pte);
 void __page_table_check_pmd_clear(struct mm_struct *mm, unsigned long addr,
 				  pmd_t pmd);
 void __page_table_check_pud_clear(struct mm_struct *mm, unsigned long addr,
@@ -45,12 +46,13 @@ static inline void page_table_check_free(struct page *page, unsigned int order)
 	__page_table_check_zero(page, order);
 }
 
-static inline void page_table_check_pte_clear(struct mm_struct *mm, pte_t pte)
+static inline void page_table_check_pte_clear(struct mm_struct *mm,
+					      unsigned long addr, pte_t pte)
 {
 	if (static_branch_likely(&page_table_check_disabled))
 		return;
 
-	__page_table_check_pte_clear(mm, pte);
+	__page_table_check_pte_clear(mm, addr, pte);
 }
 
 static inline void page_table_check_pmd_clear(struct mm_struct *mm,
@@ -119,7 +121,8 @@ static inline void page_table_check_free(struct page *page, unsigned int order)
 {
 }
 
-static inline void page_table_check_pte_clear(struct mm_struct *mm, pte_t pte)
+static inline void page_table_check_pte_clear(struct mm_struct *mm,
+					      unsigned long addr, pte_t pte)
 {
 }
 
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index 2d1f7369624c504b531beb8965e7352770a5f4bc..827dca25c0bc77025653f31075ed6913355bda08 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -634,7 +634,7 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
 {
 	pte_t pte = ptep_get(ptep);
 	pte_clear(mm, address, ptep);
-	page_table_check_pte_clear(mm, pte);
+	page_table_check_pte_clear(mm, address, pte);
 	return pte;
 }
 #endif
@@ -693,7 +693,7 @@ static inline void ptep_clear(struct mm_struct *mm, unsigned long addr,
 	 * No need for ptep_get_and_clear(): page table check doesn't care about
 	 * any bits that could have been set by HW concurrently.
 	 */
-	page_table_check_pte_clear(mm, pte);
+	page_table_check_pte_clear(mm, addr, pte);
 }
 
 #ifdef CONFIG_GUP_GET_PXX_LOW_HIGH
diff --git a/mm/page_table_check.c b/mm/page_table_check.c
index e8280b0b6dda97ee68bb52593df454665bac9acf..de9e54bd27e6f2bce68304a0b3e99b139f33c313 100644
--- a/mm/page_table_check.c
+++ b/mm/page_table_check.c
@@ -145,7 +145,8 @@ void __page_table_check_zero(struct page *page, unsigned int order)
 	rcu_read_unlock();
 }
 
-void __page_table_check_pte_clear(struct mm_struct *mm, pte_t pte)
+void __page_table_check_pte_clear(struct mm_struct *mm, unsigned long addr,
+				  pte_t pte)
 {
 	if (&init_mm == mm)
 		return;
@@ -209,7 +210,7 @@ void __page_table_check_ptes_set(struct mm_struct *mm, unsigned long addr,
 	page_table_check_pte_flags(pte);
 
 	for (i = 0; i < nr; i++)
-		__page_table_check_pte_clear(mm, ptep_get(ptep + i));
+		__page_table_check_pte_clear(mm, addr + PAGE_SIZE * i, ptep_get(ptep + i));
 	if (pte_user_accessible_page(pte))
 		page_table_check_set(pte_pfn(pte), nr, pte_write(pte));
 }
@@ -275,7 +276,7 @@ void __page_table_check_pte_clear_range(struct mm_struct *mm,
 		if (WARN_ON(!ptep))
 			return;
 		for (i = 0; i < PTRS_PER_PTE; i++) {
-			__page_table_check_pte_clear(mm, ptep_get(ptep));
+			__page_table_check_pte_clear(mm, addr, ptep_get(ptep));
 			addr += PAGE_SIZE;
 			ptep++;
 		}

-- 
2.52.0



From ajd at linux.ibm.com  Thu Dec 18 09:09:41 2025
From: ajd at linux.ibm.com (Andrew Donnellan)
Date: Fri, 19 Dec 2025 04:09:41 +1100
Subject: [PATCH v18 09/12] mm: Provide address parameter to
 p{te,md,ud}_user_accessible_page()
In-Reply-To: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
References: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
Message-ID: <20251219-pgtable_check_v18rebase-v18-9-755bc151a50b@linux.ibm.com>

From: Rohan McLure <rmclure at linux.ibm.com>

On several powerpc platforms, a page table entry may not imply whether
the relevant mapping is for userspace or kernelspace. Instead, such
platforms infer this by the address which is being accessed.

Add an additional address argument to each of these routines in order to
provide support for page table check on powerpc.

[ajd at linux.ibm.com: rebase on arm64 changes]
Signed-off-by: Rohan McLure <rmclure at linux.ibm.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin at soleen.com>
Acked-by: Ingo Molnar <mingo at kernel.org>  # x86
Acked-by: Alexandre Ghiti <alexghiti at rivosinc.com> # riscv
Signed-off-by: Andrew Donnellan <ajd at linux.ibm.com>
---
v15: rebase
---
 arch/arm64/include/asm/pgtable.h |  6 +++---
 arch/riscv/include/asm/pgtable.h |  6 +++---
 arch/x86/include/asm/pgtable.h   |  6 +++---
 mm/page_table_check.c            | 12 ++++++------
 4 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index ce64c560e284e1c2ff9d698cf868070ed58ba045..d94445b4f3dfafcda88c7953a84228d39f788f3a 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -1265,17 +1265,17 @@ static inline int pmdp_set_access_flags(struct vm_area_struct *vma,
 #endif
 
 #ifdef CONFIG_PAGE_TABLE_CHECK
-static inline bool pte_user_accessible_page(pte_t pte)
+static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
 {
 	return pte_valid(pte) && (pte_user(pte) || pte_user_exec(pte));
 }
 
-static inline bool pmd_user_accessible_page(pmd_t pmd)
+static inline bool pmd_user_accessible_page(pmd_t pmd, unsigned long addr)
 {
 	return pmd_valid(pmd) && !pmd_table(pmd) && (pmd_user(pmd) || pmd_user_exec(pmd));
 }
 
-static inline bool pud_user_accessible_page(pud_t pud)
+static inline bool pud_user_accessible_page(pud_t pud, unsigned long addr)
 {
 	return pud_valid(pud) && !pud_table(pud) && (pud_user(pud) || pud_user_exec(pud));
 }
diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
index 9af5bfc780800fe2f974daa5329277c46877f848..e38da3f9908fbd32ccb27a4f95c049dc2ae705dc 100644
--- a/arch/riscv/include/asm/pgtable.h
+++ b/arch/riscv/include/asm/pgtable.h
@@ -956,17 +956,17 @@ static inline void set_pud_at(struct mm_struct *mm, unsigned long addr,
 }
 
 #ifdef CONFIG_PAGE_TABLE_CHECK
-static inline bool pte_user_accessible_page(pte_t pte)
+static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
 {
 	return pte_present(pte) && pte_user(pte);
 }
 
-static inline bool pmd_user_accessible_page(pmd_t pmd)
+static inline bool pmd_user_accessible_page(pmd_t pmd, unsigned long addr)
 {
 	return pmd_leaf(pmd) && pmd_user(pmd);
 }
 
-static inline bool pud_user_accessible_page(pud_t pud)
+static inline bool pud_user_accessible_page(pud_t pud, unsigned long addr)
 {
 	return pud_leaf(pud) && pud_user(pud);
 }
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index 6ec6cf7ad2d4d92da7d3396bc96a5b5902e81576..1662c5a8f445f58c62e7364040d13b5958347818 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -1680,17 +1680,17 @@ static inline bool arch_has_hw_nonleaf_pmd_young(void)
 #endif
 
 #ifdef CONFIG_PAGE_TABLE_CHECK
-static inline bool pte_user_accessible_page(pte_t pte)
+static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
 {
 	return (pte_val(pte) & _PAGE_PRESENT) && (pte_val(pte) & _PAGE_USER);
 }
 
-static inline bool pmd_user_accessible_page(pmd_t pmd)
+static inline bool pmd_user_accessible_page(pmd_t pmd, unsigned long addr)
 {
 	return pmd_leaf(pmd) && (pmd_val(pmd) & _PAGE_PRESENT) && (pmd_val(pmd) & _PAGE_USER);
 }
 
-static inline bool pud_user_accessible_page(pud_t pud)
+static inline bool pud_user_accessible_page(pud_t pud, unsigned long addr)
 {
 	return pud_leaf(pud) && (pud_val(pud) & _PAGE_PRESENT) && (pud_val(pud) & _PAGE_USER);
 }
diff --git a/mm/page_table_check.c b/mm/page_table_check.c
index de9e54bd27e6f2bce68304a0b3e99b139f33c313..2708c2b3ac1fbd19a0a4528f5a2b27ddbef03adf 100644
--- a/mm/page_table_check.c
+++ b/mm/page_table_check.c
@@ -151,7 +151,7 @@ void __page_table_check_pte_clear(struct mm_struct *mm, unsigned long addr,
 	if (&init_mm == mm)
 		return;
 
-	if (pte_user_accessible_page(pte)) {
+	if (pte_user_accessible_page(pte, addr)) {
 		page_table_check_clear(pte_pfn(pte), PAGE_SIZE >> PAGE_SHIFT);
 	}
 }
@@ -163,7 +163,7 @@ void __page_table_check_pmd_clear(struct mm_struct *mm, unsigned long addr,
 	if (&init_mm == mm)
 		return;
 
-	if (pmd_user_accessible_page(pmd)) {
+	if (pmd_user_accessible_page(pmd, addr)) {
 		page_table_check_clear(pmd_pfn(pmd), PMD_SIZE >> PAGE_SHIFT);
 	}
 }
@@ -175,7 +175,7 @@ void __page_table_check_pud_clear(struct mm_struct *mm, unsigned long addr,
 	if (&init_mm == mm)
 		return;
 
-	if (pud_user_accessible_page(pud)) {
+	if (pud_user_accessible_page(pud, addr)) {
 		page_table_check_clear(pud_pfn(pud), PUD_SIZE >> PAGE_SHIFT);
 	}
 }
@@ -211,7 +211,7 @@ void __page_table_check_ptes_set(struct mm_struct *mm, unsigned long addr,
 
 	for (i = 0; i < nr; i++)
 		__page_table_check_pte_clear(mm, addr + PAGE_SIZE * i, ptep_get(ptep + i));
-	if (pte_user_accessible_page(pte))
+	if (pte_user_accessible_page(pte, addr))
 		page_table_check_set(pte_pfn(pte), nr, pte_write(pte));
 }
 EXPORT_SYMBOL(__page_table_check_ptes_set);
@@ -241,7 +241,7 @@ void __page_table_check_pmds_set(struct mm_struct *mm, unsigned long addr,
 
 	for (i = 0; i < nr; i++)
 		__page_table_check_pmd_clear(mm, addr + PMD_SIZE * i, *(pmdp + i));
-	if (pmd_user_accessible_page(pmd))
+	if (pmd_user_accessible_page(pmd, addr))
 		page_table_check_set(pmd_pfn(pmd), stride * nr, pmd_write(pmd));
 }
 EXPORT_SYMBOL(__page_table_check_pmds_set);
@@ -257,7 +257,7 @@ void __page_table_check_puds_set(struct mm_struct *mm, unsigned long addr,
 
 	for (i = 0; i < nr; i++)
 		__page_table_check_pud_clear(mm, addr + PUD_SIZE * i, *(pudp + i));
-	if (pud_user_accessible_page(pud))
+	if (pud_user_accessible_page(pud, addr))
 		page_table_check_set(pud_pfn(pud), stride * nr, pud_write(pud));
 }
 EXPORT_SYMBOL(__page_table_check_puds_set);

-- 
2.52.0



From ajd at linux.ibm.com  Thu Dec 18 09:09:42 2025
From: ajd at linux.ibm.com (Andrew Donnellan)
Date: Fri, 19 Dec 2025 04:09:42 +1100
Subject: [PATCH v18 10/12] powerpc/mm: Implement *_user_accessible_page()
 for ptes
In-Reply-To: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
References: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
Message-ID: <20251219-pgtable_check_v18rebase-v18-10-755bc151a50b@linux.ibm.com>

From: Rohan McLure <rmclure at linux.ibm.com>

Page table checking depends on architectures providing an
implementation of p{te,md,ud}_user_accessible_page. With
refactorisations made on powerpc/mm, the pte_access_permitted() and
similar methods verify whether a userland page is accessible with the
required permissions.

Since page table checking is the only user of
p{te,md,ud}_user_accessible_page(), implement these for all platforms,
using some of the same preliminary checks taken by pte_access_permitted()
on that platform.

Since commit 8e9bd41e4ce1 ("powerpc/nohash: Replace pte_user() by pte_read()")
pte_user() is no longer required to be present on all platforms as it
may be equivalent to or implied by pte_read(). Hence implementations of
pte_user_accessible_page() are specialised.

[ajd at linux.ibm.com: rebase and clean up]
Signed-off-by: Rohan McLure <rmclure at linux.ibm.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin at soleen.com>
Signed-off-by: Andrew Donnellan <ajd at linux.ibm.com>
Acked-by: Madhavan Srinivasan <maddy at linux.ibm.com>
---
v18: move the definitions of p{m,u}d_user_accessible_page() to be next to
     p{m,u}d_access_permitted()
---
 arch/powerpc/include/asm/book3s/32/pgtable.h |  5 +++++
 arch/powerpc/include/asm/book3s/64/pgtable.h | 17 +++++++++++++++++
 arch/powerpc/include/asm/nohash/pgtable.h    |  5 +++++
 arch/powerpc/include/asm/pgtable.h           |  8 ++++++++
 4 files changed, 35 insertions(+)

diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h
index 87dcca962be7864be3da1e7aad0992d2bc4581cf..2edca1068b6f31e64ddc4f39f594bb3ac27a8435 100644
--- a/arch/powerpc/include/asm/book3s/32/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/32/pgtable.h
@@ -437,6 +437,11 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
 	return true;
 }
 
+static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
+{
+	return pte_present(pte) && !is_kernel_addr(addr);
+}
+
 /* Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
  *
diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
index aac8ce30cd3b39ae184a69879a57ce8d6698fff5..2d69a827594f3c8593283fa11acd4750577e71a7 100644
--- a/arch/powerpc/include/asm/book3s/64/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
@@ -539,6 +539,11 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
 	return arch_pte_access_permitted(pte_val(pte), write, 0);
 }
 
+static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
+{
+	return pte_present(pte) && pte_user(pte);
+}
+
 /*
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
@@ -909,6 +914,12 @@ static inline bool pud_access_permitted(pud_t pud, bool write)
 	return pte_access_permitted(pud_pte(pud), write);
 }
 
+#define pud_user_accessible_page pud_user_accessible_page
+static inline bool pud_user_accessible_page(pud_t pud, unsigned long addr)
+{
+	return pud_leaf(pud) && pte_user_accessible_page(pud_pte(pud), addr);
+}
+
 #define __p4d_raw(x)	((p4d_t) { __pgd_raw(x) })
 static inline __be64 p4d_raw(p4d_t x)
 {
@@ -1074,6 +1085,12 @@ static inline bool pmd_access_permitted(pmd_t pmd, bool write)
 	return pte_access_permitted(pmd_pte(pmd), write);
 }
 
+#define pmd_user_accessible_page pmd_user_accessible_page
+static inline bool pmd_user_accessible_page(pmd_t pmd, unsigned long addr)
+{
+	return pmd_leaf(pmd) && pte_user_accessible_page(pmd_pte(pmd), addr);
+}
+
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 extern pmd_t pfn_pmd(unsigned long pfn, pgprot_t pgprot);
 extern pud_t pfn_pud(unsigned long pfn, pgprot_t pgprot);
diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
index 5af168b7f292415c5896a5c63bd78641d9a2c2a6..9bf3e40f27b645da660cbeeb561f08eeef180b1b 100644
--- a/arch/powerpc/include/asm/nohash/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/pgtable.h
@@ -243,6 +243,11 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
 	return true;
 }
 
+static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
+{
+	return pte_present(pte) && !is_kernel_addr(addr);
+}
+
 /* Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
  *
diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h
index 17fd7ff6e535b6d2b320fc8c292b7eb964fa0ef2..859cdbaa54a7fa159d5bbd4653f7871381f4910f 100644
--- a/arch/powerpc/include/asm/pgtable.h
+++ b/arch/powerpc/include/asm/pgtable.h
@@ -202,6 +202,14 @@ static inline bool arch_supports_memmap_on_memory(unsigned long vmemmap_size)
 
 #endif /* CONFIG_PPC64 */
 
+#ifndef pmd_user_accessible_page
+#define pmd_user_accessible_page(pmd, addr)	false
+#endif
+
+#ifndef pud_user_accessible_page
+#define pud_user_accessible_page(pud, addr)	false
+#endif
+
 #endif /* __ASSEMBLER__ */
 
 #endif /* _ASM_POWERPC_PGTABLE_H */

-- 
2.52.0



From ajd at linux.ibm.com  Thu Dec 18 09:09:43 2025
From: ajd at linux.ibm.com (Andrew Donnellan)
Date: Fri, 19 Dec 2025 04:09:43 +1100
Subject: [PATCH v18 11/12] powerpc/mm: Use set_pte_at_unchecked() for
 internal usages
In-Reply-To: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
References: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
Message-ID: <20251219-pgtable_check_v18rebase-v18-11-755bc151a50b@linux.ibm.com>

From: Rohan McLure <rmclure at linux.ibm.com>

In the new set_ptes() API, set_pte_at() (a special case of set_ptes())
is intended to be instrumented by the page table check facility. There
are however several other routines that constitute the API for setting
page table entries, including set_pmd_at() among others. Such routines
are themselves implemented in terms of set_ptes_at().

A future patch providing support for page table checking on powerpc
must take care to avoid duplicate calls to
page_table_check_p{te,md,ud}_set(). Allow for assignment of pte entries
without instrumentation through the set_pte_at_unchecked() routine
introduced in this patch.

Cause API-facing routines that call set_pte_at() to instead call
set_pte_at_unchecked(), which will remain uninstrumented by page
table check. set_ptes() is itself implemented by calls to
__set_pte_at(), so this eliminates redundant code.

[ajd at linux.ibm.com: don't change to unchecked for early boot/kernel mappings]
Signed-off-by: Rohan McLure <rmclure at linux.ibm.com>
Signed-off-by: Andrew Donnellan <ajd at linux.ibm.com>
Acked-by: Madhavan Srinivasan <maddy at linux.ibm.com>
---
v13: don't use the unchecked version for early-boot kernel mappings (Pasha)
---
 arch/powerpc/include/asm/pgtable.h       | 2 ++
 arch/powerpc/mm/book3s64/pgtable.c       | 6 +++---
 arch/powerpc/mm/book3s64/radix_pgtable.c | 6 +++---
 arch/powerpc/mm/pgtable.c                | 8 ++++++++
 4 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h
index 859cdbaa54a7fa159d5bbd4653f7871381f4910f..dcd3a88caaf634fef26fa57f5b8852274e0d4cb5 100644
--- a/arch/powerpc/include/asm/pgtable.h
+++ b/arch/powerpc/include/asm/pgtable.h
@@ -34,6 +34,8 @@ struct mm_struct;
 void set_ptes(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
 		pte_t pte, unsigned int nr);
 #define set_ptes set_ptes
+void set_pte_at_unchecked(struct mm_struct *mm, unsigned long addr,
+			  pte_t *ptep, pte_t pte);
 #define update_mmu_cache(vma, addr, ptep) \
 	update_mmu_cache_range(NULL, vma, addr, ptep, 1)
 
diff --git a/arch/powerpc/mm/book3s64/pgtable.c b/arch/powerpc/mm/book3s64/pgtable.c
index e3485db7de027cc6a20ffb5a80dbdc53261ebb3e..97db2f42ea3d3bd476d0ef03da47ff325eb73db9 100644
--- a/arch/powerpc/mm/book3s64/pgtable.c
+++ b/arch/powerpc/mm/book3s64/pgtable.c
@@ -127,7 +127,7 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr,
 	WARN_ON(!(pmd_leaf(pmd)));
 #endif
 	trace_hugepage_set_pmd(addr, pmd_val(pmd));
-	return set_pte_at(mm, addr, pmdp_ptep(pmdp), pmd_pte(pmd));
+	return set_pte_at_unchecked(mm, addr, pmdp_ptep(pmdp), pmd_pte(pmd));
 }
 
 void set_pud_at(struct mm_struct *mm, unsigned long addr,
@@ -144,7 +144,7 @@ void set_pud_at(struct mm_struct *mm, unsigned long addr,
 	WARN_ON(!(pud_leaf(pud)));
 #endif
 	trace_hugepage_set_pud(addr, pud_val(pud));
-	return set_pte_at(mm, addr, pudp_ptep(pudp), pud_pte(pud));
+	return set_pte_at_unchecked(mm, addr, pudp_ptep(pudp), pud_pte(pud));
 }
 
 static void do_serialize(void *arg)
@@ -550,7 +550,7 @@ void ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr,
 	if (radix_enabled())
 		return radix__ptep_modify_prot_commit(vma, addr,
 						      ptep, old_pte, pte);
-	set_pte_at(vma->vm_mm, addr, ptep, pte);
+	set_pte_at_unchecked(vma->vm_mm, addr, ptep, pte);
 }
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
diff --git a/arch/powerpc/mm/book3s64/radix_pgtable.c b/arch/powerpc/mm/book3s64/radix_pgtable.c
index 73977dbabcf2615252f82a09b97f719b7fe68164..b2541bf33d01cbb59562866d844354b39b14a86c 100644
--- a/arch/powerpc/mm/book3s64/radix_pgtable.c
+++ b/arch/powerpc/mm/book3s64/radix_pgtable.c
@@ -1606,7 +1606,7 @@ void radix__ptep_modify_prot_commit(struct vm_area_struct *vma,
 	    (atomic_read(&mm->context.copros) > 0))
 		radix__flush_tlb_page(vma, addr);
 
-	set_pte_at(mm, addr, ptep, pte);
+	set_pte_at_unchecked(mm, addr, ptep, pte);
 }
 
 int pud_set_huge(pud_t *pud, phys_addr_t addr, pgprot_t prot)
@@ -1617,7 +1617,7 @@ int pud_set_huge(pud_t *pud, phys_addr_t addr, pgprot_t prot)
 	if (!radix_enabled())
 		return 0;
 
-	set_pte_at(&init_mm, 0 /* radix unused */, ptep, new_pud);
+	set_pte_at_unchecked(&init_mm, 0 /* radix unused */, ptep, new_pud);
 
 	return 1;
 }
@@ -1664,7 +1664,7 @@ int pmd_set_huge(pmd_t *pmd, phys_addr_t addr, pgprot_t prot)
 	if (!radix_enabled())
 		return 0;
 
-	set_pte_at(&init_mm, 0 /* radix unused */, ptep, new_pmd);
+	set_pte_at_unchecked(&init_mm, 0 /* radix unused */, ptep, new_pmd);
 
 	return 1;
 }
diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c
index 56d7e8960e77d877390d6bcbf0d8a305cc222101..7b69cd16e011c31fffac2439a76ba20e00fc9a78 100644
--- a/arch/powerpc/mm/pgtable.c
+++ b/arch/powerpc/mm/pgtable.c
@@ -224,6 +224,14 @@ void set_ptes(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
 	}
 }
 
+void set_pte_at_unchecked(struct mm_struct *mm, unsigned long addr,
+			  pte_t *ptep, pte_t pte)
+{
+	VM_WARN_ON(pte_hw_valid(*ptep) && !pte_protnone(*ptep));
+	pte = set_pte_filter(pte, addr);
+	__set_pte_at(mm, addr, ptep, pte, 0);
+}
+
 void unmap_kernel_page(unsigned long va)
 {
 	pmd_t *pmdp = pmd_off_k(va);

-- 
2.52.0



From ajd at linux.ibm.com  Thu Dec 18 09:09:44 2025
From: ajd at linux.ibm.com (Andrew Donnellan)
Date: Fri, 19 Dec 2025 04:09:44 +1100
Subject: [PATCH v18 12/12] powerpc/mm: Support page table check
In-Reply-To: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
References: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
Message-ID: <20251219-pgtable_check_v18rebase-v18-12-755bc151a50b@linux.ibm.com>

From: Rohan McLure <rmclure at linux.ibm.com>

On creation and clearing of a page table mapping, instrument such calls
by invoking page_table_check_pte_set and page_table_check_pte_clear
respectively. These calls serve as a sanity check against illegal
mappings.

Enable ARCH_SUPPORTS_PAGE_TABLE_CHECK on powerpc, except when HUGETLB_PAGE
is enabled (powerpc has some weirdness in how it implements
set_huge_pte_at(), which may require some further work).

See also:

riscv support in commit 3fee229a8eb9 ("riscv/mm: enable
ARCH_SUPPORTS_PAGE_TABLE_CHECK")
arm64 in commit 42b2547137f5 ("arm64/mm: enable
ARCH_SUPPORTS_PAGE_TABLE_CHECK")
x86_64 in commit d283d422c6c4 ("x86: mm: add x86_64 support for page table
check")

[ajd at linux.ibm.com: rebase, add additional instrumentation, misc fixes]
Reviewed-by: Christophe Leroy <christophe.leroy at csgroup.eu>
Signed-off-by: Rohan McLure <rmclure at linux.ibm.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin at soleen.com>
Signed-off-by: Andrew Donnellan <ajd at linux.ibm.com>
Acked-by: Madhavan Srinivasan <maddy at linux.ibm.com>
---
v18:
- instrument the new pudp_invalidate()
- don't allow with HUGETLB_PAGE, for now
---
 arch/powerpc/Kconfig                         |  1 +
 arch/powerpc/include/asm/book3s/32/pgtable.h |  7 ++++-
 arch/powerpc/include/asm/book3s/64/pgtable.h | 45 +++++++++++++++++++++-------
 arch/powerpc/include/asm/nohash/pgtable.h    |  8 ++++-
 arch/powerpc/mm/book3s64/hash_pgtable.c      |  4 +++
 arch/powerpc/mm/book3s64/pgtable.c           | 19 ++++++++----
 arch/powerpc/mm/book3s64/radix_pgtable.c     |  3 ++
 arch/powerpc/mm/pgtable.c                    |  4 +++
 8 files changed, 73 insertions(+), 18 deletions(-)

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 9537a61ebae02dbfe44918232eb6114c2b763387..271690445a454b642041e47b0d73cc3fe7d38ae5 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -172,6 +172,7 @@ config PPC
 	select ARCH_STACKWALK
 	select ARCH_SUPPORTS_ATOMIC_RMW
 	select ARCH_SUPPORTS_DEBUG_PAGEALLOC	if PPC_BOOK3S || PPC_8xx
+	select ARCH_SUPPORTS_PAGE_TABLE_CHECK	if !HUGETLB_PAGE
 	select ARCH_SUPPORTS_SCHED_MC		if SMP
 	select ARCH_SUPPORTS_SCHED_SMT		if PPC64 && SMP
 	select SCHED_MC				if ARCH_SUPPORTS_SCHED_MC
diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h
index 2edca1068b6f31e64ddc4f39f594bb3ac27a8435..dcbae85218304f9062e4414db17f589246733819 100644
--- a/arch/powerpc/include/asm/book3s/32/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/32/pgtable.h
@@ -202,6 +202,7 @@ void unmap_kernel_page(unsigned long va);
 #ifndef __ASSEMBLER__
 #include <linux/sched.h>
 #include <linux/threads.h>
+#include <linux/page_table_check.h>
 
 /* Bits to mask out from a PGD to get to the PUD page */
 #define PGD_MASKED_BITS		0
@@ -315,7 +316,11 @@ static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
 static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
 				       pte_t *ptep)
 {
-	return __pte(pte_update(mm, addr, ptep, ~_PAGE_HASHPTE, 0, 0));
+	pte_t old_pte = __pte(pte_update(mm, addr, ptep, ~_PAGE_HASHPTE, 0, 0));
+
+	page_table_check_pte_clear(mm, addr, old_pte);
+
+	return old_pte;
 }
 
 #define __HAVE_ARCH_PTEP_SET_WRPROTECT
diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
index 2d69a827594f3c8593283fa11acd4750577e71a7..1a91762b455d9380481eef01f7f86ba5f856e375 100644
--- a/arch/powerpc/include/asm/book3s/64/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
@@ -144,6 +144,8 @@
 #define PAGE_KERNEL_ROX	__pgprot(_PAGE_BASE | _PAGE_KERNEL_ROX)
 
 #ifndef __ASSEMBLER__
+#include <linux/page_table_check.h>
+
 /*
  * page table defines
  */
@@ -416,8 +418,11 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
 static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
 				       unsigned long addr, pte_t *ptep)
 {
-	unsigned long old = pte_update(mm, addr, ptep, ~0UL, 0, 0);
-	return __pte(old);
+	pte_t old_pte = __pte(pte_update(mm, addr, ptep, ~0UL, 0, 0));
+
+	page_table_check_pte_clear(mm, addr, old_pte);
+
+	return old_pte;
 }
 
 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL
@@ -426,11 +431,16 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm,
 					    pte_t *ptep, int full)
 {
 	if (full && radix_enabled()) {
+		pte_t old_pte;
+
 		/*
 		 * We know that this is a full mm pte clear and
 		 * hence can be sure there is no parallel set_pte.
 		 */
-		return radix__ptep_get_and_clear_full(mm, addr, ptep, full);
+		old_pte = radix__ptep_get_and_clear_full(mm, addr, ptep, full);
+		page_table_check_pte_clear(mm, addr, old_pte);
+
+		return old_pte;
 	}
 	return ptep_get_and_clear(mm, addr, ptep);
 }
@@ -1301,19 +1311,34 @@ extern int pudp_test_and_clear_young(struct vm_area_struct *vma,
 static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
 					    unsigned long addr, pmd_t *pmdp)
 {
-	if (radix_enabled())
-		return radix__pmdp_huge_get_and_clear(mm, addr, pmdp);
-	return hash__pmdp_huge_get_and_clear(mm, addr, pmdp);
+	pmd_t old_pmd;
+
+	if (radix_enabled()) {
+		old_pmd = radix__pmdp_huge_get_and_clear(mm, addr, pmdp);
+	} else {
+		old_pmd = hash__pmdp_huge_get_and_clear(mm, addr, pmdp);
+	}
+
+	page_table_check_pmd_clear(mm, addr, old_pmd);
+
+	return old_pmd;
 }
 
 #define __HAVE_ARCH_PUDP_HUGE_GET_AND_CLEAR
 static inline pud_t pudp_huge_get_and_clear(struct mm_struct *mm,
 					    unsigned long addr, pud_t *pudp)
 {
-	if (radix_enabled())
-		return radix__pudp_huge_get_and_clear(mm, addr, pudp);
-	BUG();
-	return *pudp;
+	pud_t old_pud;
+
+	if (radix_enabled()) {
+		old_pud = radix__pudp_huge_get_and_clear(mm, addr, pudp);
+	} else {
+		BUG();
+	}
+
+	page_table_check_pud_clear(mm, addr, old_pud);
+
+	return old_pud;
 }
 
 static inline pmd_t pmdp_collapse_flush(struct vm_area_struct *vma,
diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
index 9bf3e40f27b645da660cbeeb561f08eeef180b1b..e6da5eaccff632a353139f27bf54472e716ac246 100644
--- a/arch/powerpc/include/asm/nohash/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/pgtable.h
@@ -29,6 +29,8 @@ static inline pte_basic_t pte_update(struct mm_struct *mm, unsigned long addr, p
 
 #ifndef __ASSEMBLER__
 
+#include <linux/page_table_check.h>
+
 extern int icache_44x_need_flush;
 
 #ifndef pte_huge_size
@@ -122,7 +124,11 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
 static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
 				       pte_t *ptep)
 {
-	return __pte(pte_update(mm, addr, ptep, ~0UL, 0, 0));
+	pte_t old_pte = __pte(pte_update(mm, addr, ptep, ~0UL, 0, 0));
+
+	page_table_check_pte_clear(mm, addr, old_pte);
+
+	return old_pte;
 }
 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
 
diff --git a/arch/powerpc/mm/book3s64/hash_pgtable.c b/arch/powerpc/mm/book3s64/hash_pgtable.c
index 82d31177630b810a70c9e7797f1f163fa97ccfaf..ac2a24d15d2e3733bd013eb168b2656ad61e7af7 100644
--- a/arch/powerpc/mm/book3s64/hash_pgtable.c
+++ b/arch/powerpc/mm/book3s64/hash_pgtable.c
@@ -8,6 +8,7 @@
 #include <linux/sched.h>
 #include <linux/mm_types.h>
 #include <linux/mm.h>
+#include <linux/page_table_check.h>
 #include <linux/stop_machine.h>
 
 #include <asm/sections.h>
@@ -230,6 +231,9 @@ pmd_t hash__pmdp_collapse_flush(struct vm_area_struct *vma, unsigned long addres
 
 	pmd = *pmdp;
 	pmd_clear(pmdp);
+
+	page_table_check_pmd_clear(vma->vm_mm, address, pmd);
+
 	/*
 	 * Wait for all pending hash_page to finish. This is needed
 	 * in case of subpage collapse. When we collapse normal pages
diff --git a/arch/powerpc/mm/book3s64/pgtable.c b/arch/powerpc/mm/book3s64/pgtable.c
index 97db2f42ea3d3bd476d0ef03da47ff325eb73db9..4b09c04654a8f26e84f811df61461d83ae71f299 100644
--- a/arch/powerpc/mm/book3s64/pgtable.c
+++ b/arch/powerpc/mm/book3s64/pgtable.c
@@ -10,6 +10,7 @@
 #include <linux/pkeys.h>
 #include <linux/debugfs.h>
 #include <linux/proc_fs.h>
+#include <linux/page_table_check.h>
 
 #include <asm/pgalloc.h>
 #include <asm/tlb.h>
@@ -127,6 +128,7 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr,
 	WARN_ON(!(pmd_leaf(pmd)));
 #endif
 	trace_hugepage_set_pmd(addr, pmd_val(pmd));
+	page_table_check_pmd_set(mm, addr, pmdp, pmd);
 	return set_pte_at_unchecked(mm, addr, pmdp_ptep(pmdp), pmd_pte(pmd));
 }
 
@@ -144,6 +146,7 @@ void set_pud_at(struct mm_struct *mm, unsigned long addr,
 	WARN_ON(!(pud_leaf(pud)));
 #endif
 	trace_hugepage_set_pud(addr, pud_val(pud));
+	page_table_check_pud_set(mm, addr, pudp, pud);
 	return set_pte_at_unchecked(mm, addr, pudp_ptep(pudp), pud_pte(pud));
 }
 
@@ -179,23 +182,27 @@ void serialize_against_pte_lookup(struct mm_struct *mm)
 pmd_t pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
 		     pmd_t *pmdp)
 {
-	unsigned long old_pmd;
+	pmd_t old_pmd;
 
 	VM_WARN_ON_ONCE(!pmd_present(*pmdp));
-	old_pmd = pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_PRESENT, _PAGE_INVALID);
+	old_pmd = __pmd(pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_PRESENT, _PAGE_INVALID));
 	flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
-	return __pmd(old_pmd);
+	page_table_check_pmd_clear(vma->vm_mm, address, old_pmd);
+
+	return old_pmd;
 }
 
 pud_t pudp_invalidate(struct vm_area_struct *vma, unsigned long address,
 		      pud_t *pudp)
 {
-	unsigned long old_pud;
+	pud_t old_pud;
 
 	VM_WARN_ON_ONCE(!pud_present(*pudp));
-	old_pud = pud_hugepage_update(vma->vm_mm, address, pudp, _PAGE_PRESENT, _PAGE_INVALID);
+	old_pud = __pud(pud_hugepage_update(vma->vm_mm, address, pudp, _PAGE_PRESENT, _PAGE_INVALID));
 	flush_pud_tlb_range(vma, address, address + HPAGE_PUD_SIZE);
-	return __pud(old_pud);
+	page_table_check_pud_clear(vma->vm_mm, address, old_pud);
+
+	return old_pud;
 }
 
 pmd_t pmdp_huge_get_and_clear_full(struct vm_area_struct *vma,
diff --git a/arch/powerpc/mm/book3s64/radix_pgtable.c b/arch/powerpc/mm/book3s64/radix_pgtable.c
index b2541bf33d01cbb59562866d844354b39b14a86c..10aced261cff4d39e64407e31ac05e9eb340007b 100644
--- a/arch/powerpc/mm/book3s64/radix_pgtable.c
+++ b/arch/powerpc/mm/book3s64/radix_pgtable.c
@@ -14,6 +14,7 @@
 #include <linux/of.h>
 #include <linux/of_fdt.h>
 #include <linux/mm.h>
+#include <linux/page_table_check.h>
 #include <linux/hugetlb.h>
 #include <linux/string_helpers.h>
 #include <linux/memory.h>
@@ -1474,6 +1475,8 @@ pmd_t radix__pmdp_collapse_flush(struct vm_area_struct *vma, unsigned long addre
 	pmd = *pmdp;
 	pmd_clear(pmdp);
 
+	page_table_check_pmd_clear(vma->vm_mm, address, pmd);
+
 	radix__flush_tlb_collapsed_pmd(vma->vm_mm, address);
 
 	return pmd;
diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c
index 7b69cd16e011c31fffac2439a76ba20e00fc9a78..a9be337be3e461fdffa7181a87376cd8329aa9e0 100644
--- a/arch/powerpc/mm/pgtable.c
+++ b/arch/powerpc/mm/pgtable.c
@@ -22,6 +22,7 @@
 #include <linux/mm.h>
 #include <linux/percpu.h>
 #include <linux/hardirq.h>
+#include <linux/page_table_check.h>
 #include <linux/hugetlb.h>
 #include <asm/tlbflush.h>
 #include <asm/tlb.h>
@@ -206,6 +207,9 @@ void set_ptes(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
 	 * and not hw_valid ptes. Hence there is no translation cache flush
 	 * involved that need to be batched.
 	 */
+
+	page_table_check_ptes_set(mm, addr, ptep, pte, nr);
+
 	for (;;) {
 
 		/*

-- 
2.52.0



From nicolinc at nvidia.com  Thu Dec 18 09:32:43 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Thu, 18 Dec 2025 09:32:43 -0800
Subject: [PATCH rc v4 3/4] iommu/arm-smmu-v3: Mark STE EATS safe when
 computing the update sequence
In-Reply-To: <aUQvAKjVUT1L3N7j@google.com>
References: <cover.1765945258.git.nicolinc@nvidia.com>
 <adf08c3b9f289188aca4fe80e506dca7aa48aa19.1765945258.git.nicolinc@nvidia.com>
 <aUQvAKjVUT1L3N7j@google.com>
Message-ID: <aUQ6u+s8YbPiLC8Z@Asurada-Nvidia>

On Thu, Dec 18, 2025 at 04:42:40PM +0000, Mostafa Saleh wrote:
> On Tue, Dec 16, 2025 at 08:26:01PM -0800, Nicolin Chen wrote:
> > From: Jason Gunthorpe <jgg at nvidia.com>
> > 
> > If a VM wants to toggle EATS off at the same time as changing the CFG, the
> > hypervisor will see EATS change to 0 and insert a V=0 breaking update into
> > the STE even though the VM did not ask for that.
> > 
> > In bare metal, EATS is ignored by CFG=ABORT/BYPASS, which is why this does
> > not cause a problem until we have nested where CFG is always a variation of
> > S2 trans that does use EATS.
> > 
> > Relax the rules for EATS sequencing, we don't need it to be exact because
> > the enclosing code will always disable ATS at the PCI device if we are
> > changing EATS. This ensures there are no ATS transactions that can race
> > with an EATS change so we don't need to carefully sequence these bits.
> > 
> > Fixes: 1e8be08d1c91 ("iommu/arm-smmu-v3: Support IOMMU_DOMAIN_NESTED")
> > Cc: stable at vger.kernel.org
> > Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
> > Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
> > Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
> > ---
> >  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 9 +++++++++
> >  1 file changed, 9 insertions(+)
> > 
> > diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> > index 12a9669bcc83..a3b29ad20a82 100644
> > --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> > +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> > @@ -1095,6 +1095,15 @@ void arm_smmu_get_ste_update_safe(__le64 *safe_bits)
> >  	 *  fault records even when MEV == 0.
> >  	 */
> >  	safe_bits[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
> > +
> > +	/*
> > +	 * EATS is used to reject and control the ATS behavior of the device. If
> > +	 * we are changing it away from 0 then we already trust the device to
> > +	 * use ATS properly and we have sequenced the device's ATS enable in PCI
> > +	 * config space to prevent it from issuing ATS while we are changing
> > +	 * EATS.
> > +	 */
> 
> I am not sure about this one, Is it only about trusting the device?
>
> I?d be worried about cases where we switch domains, that means that
> briefly the HW observers EATS=1 while it was not intended, especially
> that EATS is in a different DWORD from S2TTB and CDptr. With all the
> IOMMUFD/VFIO stuff it makes it harder to reason about. But I can?t
> come up with an example to break this.

Hmm..

I think the last line that driver controls pci_enable/disable_ats()
should justify the whole thing? Are you worried about device still
doing ATS after pci_disable_ats()?

Thanks
Nicolin


From nicolinc at nvidia.com  Thu Dec 18 09:35:08 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Thu, 18 Dec 2025 09:35:08 -0800
Subject: [PATCH rc v4 4/4] iommu/arm-smmu-v3-test: Add nested
 s1bypass/s1dssbypass coverage
In-Reply-To: <aUQwKot1Ao0lE-C1@google.com>
References: <cover.1765945258.git.nicolinc@nvidia.com>
 <6fcdd663d62dcab4005401bac2d23d18dd28e0c4.1765945258.git.nicolinc@nvidia.com>
 <aUQwKot1Ao0lE-C1@google.com>
Message-ID: <aUQ7TAHn5/2DNyhw@Asurada-Nvidia>

On Thu, Dec 18, 2025 at 04:47:38PM +0000, Mostafa Saleh wrote:
> On Tue, Dec 16, 2025 at 08:26:02PM -0800, Nicolin Chen wrote:
> > STE in a nested case requires both S1 and S2 fields. And this makes the use
> > case different from the existing one.
> > 
> > Add coverage for previously failed cases shifting between S2-only and S1+S2
> > STEs.
> > 
> > Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
> > Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
> > ---
> >  .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  | 46 +++++++++++++++++++
> >  1 file changed, 46 insertions(+)
> > 
> > diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> > index 5db14718fdd6..8255a02f4efa 100644
> > --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> > +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
> > @@ -33,8 +33,12 @@ static struct mm_struct sva_mm = {
> >  enum arm_smmu_test_master_feat {
> >  	ARM_SMMU_MASTER_TEST_ATS = BIT(0),
> >  	ARM_SMMU_MASTER_TEST_STALL = BIT(1),
> > +	ARM_SMMU_MASTER_TEST_NESTED = BIT(2),
> >  };
> >  
> > +static void arm_smmu_test_make_s2_ste(struct arm_smmu_ste *ste,
> > +				      enum arm_smmu_test_master_feat feat);
> > +
> >  static bool arm_smmu_entry_differs_in_used_bits(const __le64 *entry,
> >  						const __le64 *used_bits,
> >  						const __le64 *target,
> > @@ -197,6 +201,17 @@ static void arm_smmu_test_make_cdtable_ste(struct arm_smmu_ste *ste,
> >  	};
> >  
> >  	arm_smmu_make_cdtable_ste(ste, &master, ats_enabled, s1dss);
> > +	if (feat & ARM_SMMU_MASTER_TEST_NESTED) {
> > +		struct arm_smmu_ste s2ste;
> > +		int i;
> > +
> > +		arm_smmu_test_make_s2_ste(&s2ste, ARM_SMMU_MASTER_TEST_ATS);
> 
> Shouldn't that be conditional on "ats_enabled", I see the callers of the
> new tests already set ARM_SMMU_MASTER_TEST_ATS.

I will fix that.

Thanks
Nicolin


From yonghong.song at linux.dev  Thu Dec 18 09:44:04 2025
From: yonghong.song at linux.dev (Yonghong Song)
Date: Thu, 18 Dec 2025 09:44:04 -0800
Subject: [PATCH bpf-next v2 1/2] bpf: move recursion detection logic to
 helpers
In-Reply-To: <20251217233608.2374187-2-puranjay@kernel.org>
References: <20251217233608.2374187-1-puranjay@kernel.org>
 <20251217233608.2374187-2-puranjay@kernel.org>
Message-ID: <5c57bea2-a9ff-438d-a256-954e291670af@linux.dev>



On 12/17/25 3:35 PM, Puranjay Mohan wrote:
> BPF programs detect recursion by doing atomic inc/dec on a per-cpu
> active counter from the trampoline. Create two helpers for operations on
> this active counter, this makes it easy to changes the recursion
> detection logic in future.
>
> This change makes no functional changes.
>
> Signed-off-by: Puranjay Mohan <puranjay at kernel.org>

Acked-by: Yonghong Song <yonghong.song at linux.dev>



From pasha.tatashin at soleen.com  Thu Dec 18 09:49:03 2025
From: pasha.tatashin at soleen.com (Pasha Tatashin)
Date: Thu, 18 Dec 2025 12:49:03 -0500
Subject: [PATCH v18 01/12] arm64/mm: Add addr parameter to __set_ptes_anysz()
In-Reply-To: <20251219-pgtable_check_v18rebase-v18-1-755bc151a50b@linux.ibm.com>
References: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
 <20251219-pgtable_check_v18rebase-v18-1-755bc151a50b@linux.ibm.com>
Message-ID: <CA+CK2bA-3p1iy9ryaQSthV0MhpxzuMVK91F1YF45qw90PUtG3g@mail.gmail.com>

On Thu, Dec 18, 2025 at 12:10?PM Andrew Donnellan <ajd at linux.ibm.com> wrote:
>
> To provide support for page table check on powerpc, we need to reinstate the
> address parameter in several functions, including
> page_table_check_{ptes,pmds,puds}_set().
>
> In preparation for this, add the addr parameter to arm64's __set_ptes_anysz()
> and change its callsites accordingly.
>
> Signed-off-by: Andrew Donnellan <ajd at linux.ibm.com>

Reviewed-by: Pasha Tatashin <pasha.tatashin at soleen.com>

> ---
> v15: new patch
> v16: rebase
> ---
>  arch/arm64/include/asm/pgtable.h | 19 ++++++++-----------
>  arch/arm64/mm/hugetlbpage.c      | 10 +++++-----
>  2 files changed, 13 insertions(+), 16 deletions(-)
>
> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
> index 445e18e92221c98eef717888aeac71d1d6b1da06..52f3ea07427cef399e68bea0dbab39d03ea83060 100644
> --- a/arch/arm64/include/asm/pgtable.h
> +++ b/arch/arm64/include/asm/pgtable.h
> @@ -673,8 +673,8 @@ static inline pgprot_t pud_pgprot(pud_t pud)
>         return __pgprot(pud_val(pfn_pud(pfn, __pgprot(0))) ^ pud_val(pud));
>  }
>
> -static inline void __set_ptes_anysz(struct mm_struct *mm, pte_t *ptep,
> -                                   pte_t pte, unsigned int nr,
> +static inline void __set_ptes_anysz(struct mm_struct *mm, unsigned long addr,
> +                                   pte_t *ptep, pte_t pte, unsigned int nr,
>                                     unsigned long pgsize)
>  {
>         unsigned long stride = pgsize >> PAGE_SHIFT;
> @@ -709,26 +709,23 @@ static inline void __set_ptes_anysz(struct mm_struct *mm, pte_t *ptep,
>         __set_pte_complete(pte);
>  }
>
> -static inline void __set_ptes(struct mm_struct *mm,
> -                             unsigned long __always_unused addr,
> +static inline void __set_ptes(struct mm_struct *mm, unsigned long addr,
>                               pte_t *ptep, pte_t pte, unsigned int nr)
>  {
> -       __set_ptes_anysz(mm, ptep, pte, nr, PAGE_SIZE);
> +       __set_ptes_anysz(mm, addr, ptep, pte, nr, PAGE_SIZE);
>  }
>
> -static inline void __set_pmds(struct mm_struct *mm,
> -                             unsigned long __always_unused addr,
> +static inline void __set_pmds(struct mm_struct *mm, unsigned long addr,
>                               pmd_t *pmdp, pmd_t pmd, unsigned int nr)
>  {
> -       __set_ptes_anysz(mm, (pte_t *)pmdp, pmd_pte(pmd), nr, PMD_SIZE);
> +       __set_ptes_anysz(mm, addr, (pte_t *)pmdp, pmd_pte(pmd), nr, PMD_SIZE);
>  }
>  #define set_pmd_at(mm, addr, pmdp, pmd) __set_pmds(mm, addr, pmdp, pmd, 1)
>
> -static inline void __set_puds(struct mm_struct *mm,
> -                             unsigned long __always_unused addr,
> +static inline void __set_puds(struct mm_struct *mm, unsigned long addr,
>                               pud_t *pudp, pud_t pud, unsigned int nr)
>  {
> -       __set_ptes_anysz(mm, (pte_t *)pudp, pud_pte(pud), nr, PUD_SIZE);
> +       __set_ptes_anysz(mm, addr, (pte_t *)pudp, pud_pte(pud), nr, PUD_SIZE);
>  }
>  #define set_pud_at(mm, addr, pudp, pud) __set_puds(mm, addr, pudp, pud, 1)
>
> diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c
> index 1d90a7e753336d86314fee0f753e8779d6a6bc12..1003b502075208d4252c27ffdacb1aaf4928639b 100644
> --- a/arch/arm64/mm/hugetlbpage.c
> +++ b/arch/arm64/mm/hugetlbpage.c
> @@ -225,8 +225,8 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
>         ncontig = num_contig_ptes(sz, &pgsize);
>
>         if (!pte_present(pte)) {
> -               for (i = 0; i < ncontig; i++, ptep++)
> -                       __set_ptes_anysz(mm, ptep, pte, 1, pgsize);
> +               for (i = 0; i < ncontig; i++, ptep++, addr += pgsize)
> +                       __set_ptes_anysz(mm, addr, ptep, pte, 1, pgsize);
>                 return;
>         }
>
> @@ -234,7 +234,7 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
>         if (pte_cont(pte) && pte_valid(__ptep_get(ptep)))
>                 clear_flush(mm, addr, ptep, pgsize, ncontig);
>
> -       __set_ptes_anysz(mm, ptep, pte, ncontig, pgsize);
> +       __set_ptes_anysz(mm, addr, ptep, pte, ncontig, pgsize);
>  }
>
>  pte_t *huge_pte_alloc(struct mm_struct *mm, struct vm_area_struct *vma,
> @@ -449,7 +449,7 @@ int huge_ptep_set_access_flags(struct vm_area_struct *vma,
>         if (pte_young(orig_pte))
>                 pte = pte_mkyoung(pte);
>
> -       __set_ptes_anysz(mm, ptep, pte, ncontig, pgsize);
> +       __set_ptes_anysz(mm, addr, ptep, pte, ncontig, pgsize);
>         return 1;
>  }
>
> @@ -473,7 +473,7 @@ void huge_ptep_set_wrprotect(struct mm_struct *mm,
>         pte = get_clear_contig_flush(mm, addr, ptep, pgsize, ncontig);
>         pte = pte_wrprotect(pte);
>
> -       __set_ptes_anysz(mm, ptep, pte, ncontig, pgsize);
> +       __set_ptes_anysz(mm, addr, ptep, pte, ncontig, pgsize);
>  }
>
>  pte_t huge_ptep_clear_flush(struct vm_area_struct *vma,
>
> --
> 2.52.0
>
>


From pasha.tatashin at soleen.com  Thu Dec 18 09:49:45 2025
From: pasha.tatashin at soleen.com (Pasha Tatashin)
Date: Thu, 18 Dec 2025 12:49:45 -0500
Subject: [PATCH v18 02/12] arm64/mm: Add addr parameter to __ptep_get_and_clear_anysz()
In-Reply-To: <20251219-pgtable_check_v18rebase-v18-2-755bc151a50b@linux.ibm.com>
References: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
 <20251219-pgtable_check_v18rebase-v18-2-755bc151a50b@linux.ibm.com>
Message-ID: <CA+CK2bD2FdFdM+=tcvf6L2x-j=b4HnixUwf4irWp-eNwQUeFrg@mail.gmail.com>

On Thu, Dec 18, 2025 at 12:10?PM Andrew Donnellan <ajd at linux.ibm.com> wrote:
>
> To provide support for page table check on powerpc, we need to reinstate the
> address parameter in several functions, including
> page_table_check_{pte,pmd,pud}_clear().
>
> In preparation for this, add the addr parameter to arm64's
> __ptep_get_and_clear_anysz() and change its callsites accordingly.
>
> Signed-off-by: Andrew Donnellan <ajd at linux.ibm.com>

Reviewed-by: Pasha Tatashin <pasha.tatashin at soleen.com>


From suzuki.poulose at arm.com  Thu Dec 18 09:50:38 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Thu, 18 Dec 2025 17:50:38 +0000
Subject: [PATCH v8 2/8] coresight: core: add a new API to retrieve the
 helper device
In-Reply-To: <20251211-enable-byte-cntr-for-ctcu-v8-2-3e12ff313191@oss.qualcomm.com>
References: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
 <20251211-enable-byte-cntr-for-ctcu-v8-2-3e12ff313191@oss.qualcomm.com>
Message-ID: <dd043b78-d60c-4a79-85a8-9f352a4d89e1@arm.com>

On 11/12/2025 06:10, Jie Gan wrote:
> Retrieving the helper device of the specific coresight device based on
> its helper_subtype because a single coresight device may has multiple types
> of the helper devices.
> 
> Reviewed-by: Mike Leach <mike.leach at linaro.org>
> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
> ---
>   drivers/hwtracing/coresight/coresight-core.c | 35 ++++++++++++++++++++++++++++
>   drivers/hwtracing/coresight/coresight-priv.h |  2 ++
>   2 files changed, 37 insertions(+)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
> index 0e8448784c62..667883ccb4b7 100644
> --- a/drivers/hwtracing/coresight/coresight-core.c
> +++ b/drivers/hwtracing/coresight/coresight-core.c
> @@ -585,6 +585,41 @@ struct coresight_device *coresight_get_sink(struct coresight_path *path)
>   }
>   EXPORT_SYMBOL_GPL(coresight_get_sink);
>   
> +/**
> + * coresight_get_helper: find the helper device of the assigned csdev.
> + *
> + * @csdev: The csdev the helper device is conntected to.
> + * @type:  helper_subtype of the expected helper device.
> + *
> + * Retrieve the helper device for the specific csdev based on its
> + * helper_subtype.
> + *
> + * Return: the helper's csdev upon success or NULL for fail.
> + */
> +struct coresight_device *coresight_get_helper(struct coresight_device *csdev,
> +					      enum coresight_dev_subtype_helper subtype)

We have almost a similar function in coresight-core.c :

coresight_find_output_type(pdata, type, subtype).

Please could we reuse that, instead of adding similar funcitons ?

Please be careful about the mutex.

Suzuki

> +{
> +	int i;
> +	struct coresight_device *helper;
> +
> +	/* protect the connections */
> +	mutex_lock(&coresight_mutex);
> +	for (i = 0; i < csdev->pdata->nr_outconns; ++i) {
> +		helper = csdev->pdata->out_conns[i]->dest_dev;
> +		if (!helper || !coresight_is_helper(helper))
> +			continue;
> +
> +		if (helper->subtype.helper_subtype == subtype) {
> +			mutex_unlock(&coresight_mutex);
> +			return helper;
> +		}
> +	}
> +	mutex_unlock(&coresight_mutex);
> +
> +	return NULL;
> +}
> +EXPORT_SYMBOL_GPL(coresight_get_helper);
> +
>   /**
>    * coresight_get_in_port: Find the input port number at @csdev where a @remote
>    * device is connected to.
> diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
> index cbf80b83e5ce..8e39a4dc7256 100644
> --- a/drivers/hwtracing/coresight/coresight-priv.h
> +++ b/drivers/hwtracing/coresight/coresight-priv.h
> @@ -157,6 +157,8 @@ void coresight_path_assign_trace_id(struct coresight_path *path,
>   				   enum cs_mode mode);
>   int coresight_get_in_port(struct coresight_device *csdev,
>   			  struct coresight_device *remote);
> +struct coresight_device *coresight_get_helper(struct coresight_device *csdev,
> +					      enum coresight_dev_subtype_helper subtype);
>   
>   #if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM3X)
>   int etm_readl_cp14(u32 off, unsigned int *val);
> 



From yonghong.song at linux.dev  Thu Dec 18 09:55:52 2025
From: yonghong.song at linux.dev (Yonghong Song)
Date: Thu, 18 Dec 2025 09:55:52 -0800
Subject: [PATCH bpf-next v2 2/2] bpf: arm64: Optimize recursion detection
 by not using atomics
In-Reply-To: <20251217233608.2374187-3-puranjay@kernel.org>
References: <20251217233608.2374187-1-puranjay@kernel.org>
 <20251217233608.2374187-3-puranjay@kernel.org>
Message-ID: <1728d4e1-ce5c-476e-b057-b8a9a7621e1b@linux.dev>



On 12/17/25 3:35 PM, Puranjay Mohan wrote:
> BPF programs detect recursion using a per-CPU 'active' flag in struct
> bpf_prog. The trampoline currently sets/clears this flag with atomic
> operations.
>
> On some arm64 platforms (e.g., Neoverse V2 with LSE), per-CPU atomic
> operations are relatively slow. Unlike x86_64 - where per-CPU updates
> can avoid cross-core atomicity, arm64 LSE atomics are always atomic
> across all cores, which is unnecessary overhead for strictly per-CPU
> state.
>
> This patch removes atomics from the recursion detection path on arm64 by
> changing 'active' to a per-CPU array of four u8 counters, one per
> context: {NMI, hard-irq, soft-irq, normal}. The running context uses a
> non-atomic increment/decrement on its element.  After increment,
> recursion is detected by reading the array as a u32 and verifying that
> only the expected element changed; any change in another element
> indicates inter-context recursion, and a value > 1 in the same element
> indicates same-context recursion.
>
> For example, starting from {0,0,0,0}, a normal-context trigger changes
> the array to {0,0,0,1}.  If an NMI arrives on the same CPU and triggers
> the program, the array becomes {1,0,0,1}. When the NMI context checks
> the u32 against the expected mask for normal (0x00000001), it observes
> 0x01000001 and correctly reports recursion. Same-context recursion is
> detected analogously.
>
> Signed-off-by: Puranjay Mohan <puranjay at kernel.org>

LGTM with a few nits below.

Acked-by: Yonghong Song <yonghong.song at linux.dev>

> ---
>   include/linux/bpf.h | 33 ++++++++++++++++++++++++++++++---
>   kernel/bpf/core.c   |  3 ++-
>   2 files changed, 32 insertions(+), 4 deletions(-)
>
> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index 2da986136d26..5ca2a761d9a1 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h
> @@ -31,6 +31,7 @@
>   #include <linux/static_call.h>
>   #include <linux/memcontrol.h>
>   #include <linux/cfi.h>
> +#include <linux/unaligned.h>
>   #include <asm/rqspinlock.h>
>   
>   struct bpf_verifier_env;
> @@ -1746,6 +1747,8 @@ struct bpf_prog_aux {
>   	struct bpf_map __rcu *st_ops_assoc;
>   };
>   
> +#define BPF_NR_CONTEXTS        4       /* normal, softirq, hardirq, NMI */
> +
>   struct bpf_prog {
>   	u16			pages;		/* Number of allocated pages */
>   	u16			jited:1,	/* Is our filter JIT'ed? */
> @@ -1772,7 +1775,7 @@ struct bpf_prog {
>   		u8 tag[BPF_TAG_SIZE];
>   	};
>   	struct bpf_prog_stats __percpu *stats;
> -	int __percpu		*active;
> +	u8 __percpu		*active;	/* u8[BPF_NR_CONTEXTS] for rerecursion protection */
>   	unsigned int		(*bpf_func)(const void *ctx,
>   					    const struct bpf_insn *insn);
>   	struct bpf_prog_aux	*aux;		/* Auxiliary fields */
> @@ -2006,12 +2009,36 @@ struct bpf_struct_ops_common_value {
>   
>   static inline bool bpf_prog_get_recursion_context(struct bpf_prog *prog)
>   {
> -	return this_cpu_inc_return(*(prog->active)) == 1;
> +#ifdef CONFIG_ARM64
> +	u8 rctx = interrupt_context_level();
> +	u8 *active = this_cpu_ptr(prog->active);
> +	u32 val;
> +
> +	preempt_disable();
> +	active[rctx]++;
> +	val = get_unaligned_le32(active);

The?'active' already aligned with 8 (or 4 with my below suggestion).
The get_unaligned_le32() works, but maybe we could use le32_to_cpu()
instead. Maybe there is no performance difference between
get_unaligned_le32() and le32_to_cpu() so you pick get_unaligned_le32()?
It would be good to clarify in commit message if get_unaligned_le32()
is used.

> +	preempt_enable();
> +	if (val != BIT(rctx * 8))
> +		return false;
> +
> +	return true;
> +#else
> +	return this_cpu_inc_return(*(int __percpu *)(prog->active)) == 1;
> +#endif
>   }
>   
>   static inline void bpf_prog_put_recursion_context(struct bpf_prog *prog)
>   {
> -	this_cpu_dec(*(prog->active));
> +#ifdef CONFIG_ARM64
> +	u8 rctx = interrupt_context_level();
> +	u8 *active = this_cpu_ptr(prog->active);
> +
> +	preempt_disable();
> +	active[rctx]--;
> +	preempt_enable();
> +#else
> +	this_cpu_dec(*(int __percpu *)(prog->active));
> +#endif
>   }
>   
>   #if defined(CONFIG_BPF_JIT) && defined(CONFIG_BPF_SYSCALL)
> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> index c66316e32563..b5063acfcf92 100644
> --- a/kernel/bpf/core.c
> +++ b/kernel/bpf/core.c
> @@ -112,7 +112,8 @@ struct bpf_prog *bpf_prog_alloc_no_stats(unsigned int size, gfp_t gfp_extra_flag
>   		vfree(fp);
>   		return NULL;
>   	}
> -	fp->active = alloc_percpu_gfp(int, bpf_memcg_flags(GFP_KERNEL | gfp_extra_flags));
> +	fp->active = __alloc_percpu_gfp(sizeof(u8[BPF_NR_CONTEXTS]), 8,
> +					bpf_memcg_flags(GFP_KERNEL | gfp_extra_flags));

Here, the alignment is 8. Can it be 4 since the above reads a 32bit value?

>   	if (!fp->active) {
>   		vfree(fp);
>   		kfree(aux);



From pasha.tatashin at soleen.com  Thu Dec 18 09:55:45 2025
From: pasha.tatashin at soleen.com (Pasha Tatashin)
Date: Thu, 18 Dec 2025 12:55:45 -0500
Subject: [PATCH v18 00/12] Support page table check on PowerPC
In-Reply-To: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
References: <20251219-pgtable_check_v18rebase-v18-0-755bc151a50b@linux.ibm.com>
Message-ID: <CA+CK2bBjoQmheEstv1MacGev_srdx=m5v=hwxdyfAKogbpG3FA@mail.gmail.com>

On Thu, Dec 18, 2025 at 12:10?PM Andrew Donnellan <ajd at linux.ibm.com> wrote:
>
> [I will be leaving IBM in about a month from now, and will also be on leave
> for most of that time starting tomorrow. I've cc'd my personal email, which
> I am going to use for any kernel development I do after I leave, and also
> Srish Srinivasan, who will be taking over some of my work.]
>
> Support page table check on PowerPC. Page table check tracks the usage of
> of page table entries at each level to ensure that anonymous mappings have
> at most one writable consumer, and likewise that file-backed mappings are
> not simultaneously also anonymous mappings.
>
> In order to support this infrastructure, a number of helpers or stubs must be
> defined or updated for all powerpc platforms. Additionally, we separate
> set_pte_at() and set_pte_at_unchecked(), to allow for internal, uninstrumented
> mappings.
>
> On some PowerPC platforms, implementing {pte,pmd,pud}_user_accessible_page()
> requires the address. We revert previous changes that removed the address
> parameter from various interfaces, and add it to some other interfaces,
> in order to allow this.
>
> For now, we don't allow page table check alongside HUGETLB_PAGE, due to the
> arch-specific complexity of set_huge_page_at(). (I'm sure I could figure
> this out, but I have to get this version on this list before I leave my job.)
>
> This series was initially written by Rohan McLure, who has left IBM and
> is no longer working on powerpc.
>
> v18:
>  * Rebase on mm-new
>  * Add instrumentation for pudp_invalidate()
>  * Add cleanup patch to use pte_advance_pfn()
>  * Move p{m,u}d_user_accessible_page() to a more sensible place in the code
>  * Disable when HUGETLB_PAGE is enabled

Thank you. This series looks good to me.

Pasha


From jgg at nvidia.com  Thu Dec 18 10:01:29 2025
From: jgg at nvidia.com (Jason Gunthorpe)
Date: Thu, 18 Dec 2025 14:01:29 -0400
Subject: [PATCH rc v4 3/4] iommu/arm-smmu-v3: Mark STE EATS safe when
 computing the update sequence
In-Reply-To: <aUQ6u+s8YbPiLC8Z@Asurada-Nvidia>
References: <cover.1765945258.git.nicolinc@nvidia.com>
 <adf08c3b9f289188aca4fe80e506dca7aa48aa19.1765945258.git.nicolinc@nvidia.com>
 <aUQvAKjVUT1L3N7j@google.com>
 <aUQ6u+s8YbPiLC8Z@Asurada-Nvidia>
Message-ID: <20251218180129.GA254720@nvidia.com>

On Thu, Dec 18, 2025 at 09:32:43AM -0800, Nicolin Chen wrote:
> > > diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> > > index 12a9669bcc83..a3b29ad20a82 100644
> > > --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> > > +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> > > @@ -1095,6 +1095,15 @@ void arm_smmu_get_ste_update_safe(__le64 *safe_bits)
> > >  	 *  fault records even when MEV == 0.
> > >  	 */
> > >  	safe_bits[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
> > > +
> > > +	/*
> > > +	 * EATS is used to reject and control the ATS behavior of the device. If
> > > +	 * we are changing it away from 0 then we already trust the device to
> > > +	 * use ATS properly and we have sequenced the device's ATS enable in PCI
> > > +	 * config space to prevent it from issuing ATS while we are changing
> > > +	 * EATS.
> > > +	 */
> > 
> > I am not sure about this one, Is it only about trusting the device?

Yes. The purpose of EATS=0 is to prevent the device from using ATS at
all - critically including using translated TLPs eg because it is an
untrusted device and the OS wants to prevent it from attacking the
system with direct access to physical memory.

If the device is trusted then once we disable ATS it must stop issuing
ATS, so the EATS=0 should never trigger a fault.

> > I?d be worried about cases where we switch domains, that means that
> > briefly the HW observers EATS=1 while it was not intended, especially
> > that EATS is in a different DWORD from S2TTB and CDptr. 

Well, no, it means EATS is enabled a little bit earlier or disabled a
little bit later, it doesn't mean it was not intended.

The point is our rules for ATS say that the ATC is empty at this
moment and the device is not permitted to do any ATS fetches because
we won't issue any flushes.

Thus there can be no concurrent ATS traffic and we don't need to
exactly sequence EATS with the translation.

With virtualization the hypervisor is still the exclusive owner of ATS
and guarentees that EATS enable/disable is sequences correctly with
ATC invalidation.

> I think the last line that driver controls pci_enable/disable_ats()
> should justify the whole thing? Are you worried about device still
> doing ATS after pci_disable_ats()?

Exactly right, and we can't worry about that because it says the whole
ATC coherency system is broken.

Jason


From rebecca at bsdio.com  Thu Dec 18 10:34:03 2025
From: rebecca at bsdio.com (Rebecca Cran)
Date: Thu, 18 Dec 2025 11:34:03 -0700
Subject: [PATCH v6 1/2] dt-bindings: arm: aspeed: add ASRock Rack ALTRAD8
 board
In-Reply-To: <5aa36c56-798a-40cc-b0b8-be3f7c92136f@kernel.org>
References: <20251218161816.38155-1-rebecca@bsdio.com>
 <20251218161816.38155-2-rebecca@bsdio.com>
 <5aa36c56-798a-40cc-b0b8-be3f7c92136f@kernel.org>
Message-ID: <4eff8506-8049-46e9-997e-a41edff32bbc@bsdio.com>

On 12/18/25 09:21, Krzysztof Kozlowski wrote:
> On 18/12/2025 17:18, Rebecca Cran wrote:
>> Document ASRock Rack ALTRAD8 (ALTRAD8UD-1L2T and ALTRAD8UD2-1L2Q)
>> compatibles.
>>
>> Signed-off-by: Rebecca Cran <rebecca at bsdio.com>
>> Acked-by: Conor Dooley <conor.dooley at microchip.com>
>> Tested-by: Tan Siewert <tan.siewert at hetzner.com>
> How was the binding tested?

I ran "make ARCH=arm CHECK_DTBS=y aspeed/aspeed-bmc-asrock-altrad8.dtb"
to check for errors

and have used the dts file in an ASRock Rack ALTRAD8UD-1L2T system with
Linux 6.12.61 running OpenBMC.


--?
Rebecca Cran





From alain.volmat at foss.st.com  Thu Dec 18 10:44:42 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Thu, 18 Dec 2025 19:44:42 +0100
Subject: [PATCH 02/12] media: stm32: dcmi: perform dmaengine_slave_config
 at probe
In-Reply-To: <20251218-stm32-dcmi-dma-chaining-v1-0-39948ca6cbf6@foss.st.com>
References: <20251218-stm32-dcmi-dma-chaining-v1-0-39948ca6cbf6@foss.st.com>
Message-ID: <20251218-stm32-dcmi-dma-chaining-v1-2-39948ca6cbf6@foss.st.com>

Perform the dma channel configuration at probe time right after
the channel allocation since this is fixed for the whole lifetime
of the driver.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 drivers/media/platform/st/stm32/stm32-dcmi.c | 32 +++++++++++++---------------
 1 file changed, 15 insertions(+), 17 deletions(-)

diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c
index 07b67eb5b9dd..27b283474096 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmi.c
@@ -301,23 +301,6 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi,
 			  struct dcmi_buf *buf)
 {
 	struct dma_async_tx_descriptor *desc = NULL;
-	struct dma_slave_config config;
-	int ret;
-
-	memset(&config, 0, sizeof(config));
-
-	config.src_addr = (dma_addr_t)dcmi->res->start + DCMI_DR;
-	config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-	config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-	config.dst_maxburst = 4;
-
-	/* Configure DMA channel */
-	ret = dmaengine_slave_config(dcmi->dma_chan, &config);
-	if (ret < 0) {
-		dev_err(dcmi->dev, "%s: DMA channel config failed (%d)\n",
-			__func__, ret);
-		return ret;
-	}
 
 	/*
 	 * Avoid call of dmaengine_terminate_sync() between
@@ -1888,6 +1871,7 @@ static int dcmi_probe(struct platform_device *pdev)
 	struct vb2_queue *q;
 	struct dma_chan *chan;
 	struct dma_slave_caps caps;
+	struct dma_slave_config dma_config;
 	struct clk *mclk;
 	int ret = 0;
 
@@ -1954,6 +1938,19 @@ static int dcmi_probe(struct platform_device *pdev)
 	if (!ret && caps.max_sg_burst)
 		dcmi->dma_max_burst = caps.max_sg_burst	* DMA_SLAVE_BUSWIDTH_4_BYTES;
 
+	memset(&dma_config, 0, sizeof(dma_config));
+
+	dma_config.src_addr = (dma_addr_t)dcmi->res->start + DCMI_DR;
+	dma_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+
+	/* Configure DMA channel */
+	ret = dmaengine_slave_config(chan, &dma_config);
+	if (ret < 0) {
+		dev_err(dcmi->dev, "%s: DMA channel config failed (%d)\n",
+			__func__, ret);
+		goto err_dma_slave_config;
+	}
+
 	spin_lock_init(&dcmi->irqlock);
 	mutex_init(&dcmi->lock);
 	mutex_init(&dcmi->dma_lock);
@@ -2072,6 +2069,7 @@ static int dcmi_probe(struct platform_device *pdev)
 	v4l2_device_unregister(&dcmi->v4l2_dev);
 err_media_device_cleanup:
 	media_device_cleanup(&dcmi->mdev);
+err_dma_slave_config:
 	dma_release_channel(dcmi->dma_chan);
 
 	return ret;

-- 
2.34.1



From alain.volmat at foss.st.com  Thu Dec 18 10:44:40 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Thu, 18 Dec 2025 19:44:40 +0100
Subject: [PATCH 00/12] media: stm32: dcmi: stability & performance
 enhancements
Message-ID: <20251218-stm32-dcmi-dma-chaining-v1-0-39948ca6cbf6@foss.st.com>

This series improve stability of the capture by fixing the
handling of the overrun which was leading to captured
frame corruption.
Locking within the driver is also simplified and the way
DMA is handled is reworked allowing to avoid having a
specific handling for the JPEG data.

Performances of capture can now be increased via the usage
of a DMA->MDMA chaining which allows for capture of higher
resolution / framerate.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
Alain Volmat (12):
      media: stm32: dcmi: Switch from __maybe_unused to pm_sleep_ptr()
      media: stm32: dcmi: perform dmaengine_slave_config at probe
      media: stm32: dcmi: only create dma descriptor once at buf_prepare
      media: stm32: dcmi: stop the dma transfer on overrun
      media: stm32: dcmi: rework spin_lock calls
      media: stm32: dcmi: perform all dma handling within irq_thread
      media: stm32: dcmi: use dmaengine_terminate_async in irq context
      media: stm32: dcmi: continuous mode capture in JPEG
      dt-bindings: media: st: dcmi: add DMA-MDMA chaining properties
      media: stm32: dcmi: addition of DMA-MDMA chaining support
      ARM: dts: stm32: add sram node within stm32mp151.dtsi
      ARM: dts: stm32: enable DCMI DMA-MDMA chaining on stm32mp157c-ev1.dts

 .../devicetree/bindings/media/st,stm32-dcmi.yaml   |  13 +-
 arch/arm/boot/dts/st/stm32mp151.dtsi               |   8 +
 arch/arm/boot/dts/st/stm32mp157c-ev1.dts           |  15 +
 drivers/media/platform/st/stm32/stm32-dcmi.c       | 470 ++++++++++++++-------
 4 files changed, 341 insertions(+), 165 deletions(-)
---
base-commit: f7231cff1f3ff8259bef02dc4999bc132abf29cf
change-id: 20251213-stm32-dcmi-dma-chaining-9ea1da83007d

Best regards,
-- 
Alain Volmat <alain.volmat at foss.st.com>



From alain.volmat at foss.st.com  Thu Dec 18 10:44:41 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Thu, 18 Dec 2025 19:44:41 +0100
Subject: [PATCH 01/12] media: stm32: dcmi: Switch from __maybe_unused to
 pm_sleep_ptr()
In-Reply-To: <20251218-stm32-dcmi-dma-chaining-v1-0-39948ca6cbf6@foss.st.com>
References: <20251218-stm32-dcmi-dma-chaining-v1-0-39948ca6cbf6@foss.st.com>
Message-ID: <20251218-stm32-dcmi-dma-chaining-v1-1-39948ca6cbf6@foss.st.com>

Letting the compiler remove these functions when the kernel is built
without CONFIG_PM_SLEEP support is simpler and less heavier for builds
than the use of __maybe_unused attributes.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 drivers/media/platform/st/stm32/stm32-dcmi.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c
index 13762861b769..07b67eb5b9dd 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmi.c
@@ -2092,7 +2092,7 @@ static void dcmi_remove(struct platform_device *pdev)
 	dma_release_channel(dcmi->dma_chan);
 }
 
-static __maybe_unused int dcmi_runtime_suspend(struct device *dev)
+static int dcmi_runtime_suspend(struct device *dev)
 {
 	struct stm32_dcmi *dcmi = dev_get_drvdata(dev);
 
@@ -2101,7 +2101,7 @@ static __maybe_unused int dcmi_runtime_suspend(struct device *dev)
 	return 0;
 }
 
-static __maybe_unused int dcmi_runtime_resume(struct device *dev)
+static int dcmi_runtime_resume(struct device *dev)
 {
 	struct stm32_dcmi *dcmi = dev_get_drvdata(dev);
 	int ret;
@@ -2113,7 +2113,7 @@ static __maybe_unused int dcmi_runtime_resume(struct device *dev)
 	return ret;
 }
 
-static __maybe_unused int dcmi_suspend(struct device *dev)
+static int dcmi_suspend(struct device *dev)
 {
 	/* disable clock */
 	pm_runtime_force_suspend(dev);
@@ -2124,7 +2124,7 @@ static __maybe_unused int dcmi_suspend(struct device *dev)
 	return 0;
 }
 
-static __maybe_unused int dcmi_resume(struct device *dev)
+static int dcmi_resume(struct device *dev)
 {
 	/* restore pinctl default state */
 	pinctrl_pm_select_default_state(dev);
@@ -2147,7 +2147,7 @@ static struct platform_driver stm32_dcmi_driver = {
 	.driver		= {
 		.name = DRV_NAME,
 		.of_match_table = of_match_ptr(stm32_dcmi_of_match),
-		.pm = &dcmi_pm_ops,
+		.pm = pm_sleep_ptr(&dcmi_pm_ops),
 	},
 };
 

-- 
2.34.1



From alain.volmat at foss.st.com  Thu Dec 18 10:44:43 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Thu, 18 Dec 2025 19:44:43 +0100
Subject: [PATCH 03/12] media: stm32: dcmi: only create dma descriptor once
 at buf_prepare
In-Reply-To: <20251218-stm32-dcmi-dma-chaining-v1-0-39948ca6cbf6@foss.st.com>
References: <20251218-stm32-dcmi-dma-chaining-v1-0-39948ca6cbf6@foss.st.com>
Message-ID: <20251218-stm32-dcmi-dma-chaining-v1-3-39948ca6cbf6@foss.st.com>

Perform the dmaengine prep_slave_sg call within buf_prepare and
mark the descriptor as reusable in order to avoid having to redo
this at every start of the dma.
This also allow to remove the mutex used by the driver to protect
dma descriptors related piece of codes.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 drivers/media/platform/st/stm32/stm32-dcmi.c | 78 ++++++++++++++++------------
 1 file changed, 45 insertions(+), 33 deletions(-)

diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c
index 27b283474096..d8ef06bd7506 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmi.c
@@ -113,6 +113,7 @@ struct dcmi_buf {
 	struct vb2_v4l2_buffer	vb;
 	bool			prepared;
 	struct sg_table		sgt;
+	struct dma_async_tx_descriptor *dma_desc;
 	size_t			size;
 	struct list_head	list;
 };
@@ -163,9 +164,6 @@ struct stm32_dcmi {
 	int				overrun_count;
 	int				buffers_count;
 
-	/* Ensure DMA operations atomicity */
-	struct mutex			dma_lock;
-
 	struct media_device		mdev;
 	struct media_pad		vid_cap_pad;
 	struct media_pipeline		pipeline;
@@ -300,39 +298,13 @@ static void dcmi_dma_callback(void *param)
 static int dcmi_start_dma(struct stm32_dcmi *dcmi,
 			  struct dcmi_buf *buf)
 {
-	struct dma_async_tx_descriptor *desc = NULL;
-
-	/*
-	 * Avoid call of dmaengine_terminate_sync() between
-	 * dmaengine_prep_slave_single() and dmaengine_submit()
-	 * by locking the whole DMA submission sequence
-	 */
-	mutex_lock(&dcmi->dma_lock);
-
-	/* Prepare a DMA transaction */
-	desc = dmaengine_prep_slave_sg(dcmi->dma_chan, buf->sgt.sgl, buf->sgt.nents,
-				       DMA_DEV_TO_MEM,
-				       DMA_PREP_INTERRUPT);
-	if (!desc) {
-		dev_err(dcmi->dev, "%s: DMA dmaengine_prep_slave_sg failed\n", __func__);
-		mutex_unlock(&dcmi->dma_lock);
-		return -EINVAL;
-	}
-
-	/* Set completion callback routine for notification */
-	desc->callback = dcmi_dma_callback;
-	desc->callback_param = dcmi;
-
 	/* Push current DMA transaction in the pending queue */
-	dcmi->dma_cookie = dmaengine_submit(desc);
+	dcmi->dma_cookie = dmaengine_submit(buf->dma_desc);
 	if (dma_submit_error(dcmi->dma_cookie)) {
 		dev_err(dcmi->dev, "%s: DMA submission failed\n", __func__);
-		mutex_unlock(&dcmi->dma_lock);
 		return -ENXIO;
 	}
 
-	mutex_unlock(&dcmi->dma_lock);
-
 	dma_async_issue_pending(dcmi->dma_chan);
 
 	return 0;
@@ -547,6 +519,31 @@ static int dcmi_buf_prepare(struct vb2_buffer *vb)
 			size -= bytes;
 		}
 
+		/* Prepare a DMA transaction */
+		buf->dma_desc = dmaengine_prep_slave_sg(dcmi->dma_chan,
+							buf->sgt.sgl,
+							buf->sgt.nents,
+							DMA_DEV_TO_MEM,
+							DMA_PREP_INTERRUPT);
+		if (!buf->dma_desc) {
+			dev_err(dcmi->dev, "%s: DMA dmaengine_prep_slave_sg failed\n", __func__);
+			sg_free_table(&buf->sgt);
+			return -EIO;
+		}
+
+		/* Set completion callback routine for notification */
+		buf->dma_desc->callback = dcmi_dma_callback;
+		buf->dma_desc->callback_param = dcmi;
+
+		/* Mark the descriptor as reusable to avoid having to prepare it */
+		ret = dmaengine_desc_set_reuse(buf->dma_desc);
+		if (ret) {
+			dev_err(dcmi->dev, "%s: DMA dmaengine_desc_set_reuse failed\n", __func__);
+			dmaengine_desc_free(buf->dma_desc);
+			sg_free_table(&buf->sgt);
+			return -EIO;
+		}
+
 		buf->prepared = true;
 
 		vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->size);
@@ -555,6 +552,23 @@ static int dcmi_buf_prepare(struct vb2_buffer *vb)
 	return 0;
 }
 
+static void dcmi_buf_cleanup(struct vb2_buffer *vb)
+{
+	struct stm32_dcmi *dcmi =  vb2_get_drv_priv(vb->vb2_queue);
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+	struct dcmi_buf *buf = container_of(vbuf, struct dcmi_buf, vb);
+	int ret;
+
+	if (!buf->prepared)
+		return;
+
+	ret = dmaengine_desc_free(buf->dma_desc);
+	if (ret)
+		dev_err(dcmi->dev, "%s: Failed to free the mdma descriptor (0x%x)\n",
+			__func__, ret);
+	sg_free_table(&buf->sgt);
+}
+
 static void dcmi_buf_queue(struct vb2_buffer *vb)
 {
 	struct stm32_dcmi *dcmi =  vb2_get_drv_priv(vb->vb2_queue);
@@ -859,9 +873,7 @@ static void dcmi_stop_streaming(struct vb2_queue *vq)
 	spin_unlock_irq(&dcmi->irqlock);
 
 	/* Stop all pending DMA operations */
-	mutex_lock(&dcmi->dma_lock);
 	dmaengine_terminate_sync(dcmi->dma_chan);
-	mutex_unlock(&dcmi->dma_lock);
 
 	pm_runtime_put(dcmi->dev);
 
@@ -878,6 +890,7 @@ static const struct vb2_ops dcmi_video_qops = {
 	.queue_setup		= dcmi_queue_setup,
 	.buf_init		= dcmi_buf_init,
 	.buf_prepare		= dcmi_buf_prepare,
+	.buf_cleanup		= dcmi_buf_cleanup,
 	.buf_queue		= dcmi_buf_queue,
 	.start_streaming	= dcmi_start_streaming,
 	.stop_streaming		= dcmi_stop_streaming,
@@ -1953,7 +1966,6 @@ static int dcmi_probe(struct platform_device *pdev)
 
 	spin_lock_init(&dcmi->irqlock);
 	mutex_init(&dcmi->lock);
-	mutex_init(&dcmi->dma_lock);
 	init_completion(&dcmi->complete);
 	INIT_LIST_HEAD(&dcmi->buffers);
 

-- 
2.34.1



From alain.volmat at foss.st.com  Thu Dec 18 10:44:44 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Thu, 18 Dec 2025 19:44:44 +0100
Subject: [PATCH 04/12] media: stm32: dcmi: stop the dma transfer on overrun
In-Reply-To: <20251218-stm32-dcmi-dma-chaining-v1-0-39948ca6cbf6@foss.st.com>
References: <20251218-stm32-dcmi-dma-chaining-v1-0-39948ca6cbf6@foss.st.com>
Message-ID: <20251218-stm32-dcmi-dma-chaining-v1-4-39948ca6cbf6@foss.st.com>

Ensure to stop the dma transfer whenever receiving a overrun
to avoid having a buffer partially filled with a frame and
partially with the next frame.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 drivers/media/platform/st/stm32/stm32-dcmi.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c
index d8ef06bd7506..fa33acc34eab 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmi.c
@@ -402,9 +402,21 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg)
 	spin_lock_irq(&dcmi->irqlock);
 
 	if (dcmi->misr & IT_OVR) {
+		/* Disable capture */
+		reg_clear(dcmi->regs, DCMI_CR, CR_CAPTURE);
+
 		dcmi->overrun_count++;
+
 		if (dcmi->overrun_count > OVERRUN_ERROR_THRESHOLD)
 			dcmi->errors_count++;
+
+		spin_unlock_irq(&dcmi->irqlock);
+		dmaengine_terminate_sync(dcmi->dma_chan);
+
+		if (dcmi_restart_capture(dcmi))
+			dev_err(dcmi->dev, "%s: Cannot restart capture\n", __func__);
+
+		return IRQ_HANDLED;
 	}
 	if (dcmi->misr & IT_ERR)
 		dcmi->errors_count++;

-- 
2.34.1



From alain.volmat at foss.st.com  Thu Dec 18 10:44:51 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Thu, 18 Dec 2025 19:44:51 +0100
Subject: [PATCH 11/12] ARM: dts: stm32: add sram node within
 stm32mp151.dtsi
In-Reply-To: <20251218-stm32-dcmi-dma-chaining-v1-0-39948ca6cbf6@foss.st.com>
References: <20251218-stm32-dcmi-dma-chaining-v1-0-39948ca6cbf6@foss.st.com>
Message-ID: <20251218-stm32-dcmi-dma-chaining-v1-11-39948ca6cbf6@foss.st.com>

Introduce the sram node in order to be used by drivers
requiring SRAM memory space.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 arch/arm/boot/dts/st/stm32mp151.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm/boot/dts/st/stm32mp151.dtsi b/arch/arm/boot/dts/st/stm32mp151.dtsi
index b1b568dfd126..85cb0f16ca73 100644
--- a/arch/arm/boot/dts/st/stm32mp151.dtsi
+++ b/arch/arm/boot/dts/st/stm32mp151.dtsi
@@ -123,6 +123,14 @@ soc {
 		interrupt-parent = <&intc>;
 		ranges;
 
+		sram4: sram at 10050000 {
+			compatible = "mmio-sram";
+			reg = <0x10050000 0x10000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 0x10050000 0x10000>;
+		};
+
 		ipcc: mailbox at 4c001000 {
 			compatible = "st,stm32mp1-ipcc";
 			#mbox-cells = <1>;

-- 
2.34.1



From alain.volmat at foss.st.com  Thu Dec 18 10:44:46 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Thu, 18 Dec 2025 19:44:46 +0100
Subject: [PATCH 06/12] media: stm32: dcmi: perform all dma handling within
 irq_thread
In-Reply-To: <20251218-stm32-dcmi-dma-chaining-v1-0-39948ca6cbf6@foss.st.com>
References: <20251218-stm32-dcmi-dma-chaining-v1-0-39948ca6cbf6@foss.st.com>
Message-ID: <20251218-stm32-dcmi-dma-chaining-v1-6-39948ca6cbf6@foss.st.com>

Move all the type of frame handling within the dcmi_irq_thread
handler and do not rely on dma_callback as previously.

This simplifies the code by having only a single path for both
compressed and uncompressed data while also making the system
more reactive since irq_handler have more chances to be called
faster than the dma completion callback.  Indeed, in case of the
dma completion callback, this run as a tasklet created by the
dma framework upon getting an interrupt from the dma and run
at a lower priority level than other irq handlers.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 drivers/media/platform/st/stm32/stm32-dcmi.c | 97 ++++++----------------------
 1 file changed, 18 insertions(+), 79 deletions(-)

diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c
index 1015f2d88f54..06b66095844b 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmi.c
@@ -227,8 +227,9 @@ static int dcmi_restart_capture(struct stm32_dcmi *dcmi)
 {
 	struct dcmi_buf *buf;
 
+	/* Nothing to do if we are not running */
 	if (dcmi->state != RUNNING)
-		return -EINVAL;
+		return 0;
 
 	/* Restart a new DMA transfer with next buffer */
 	if (list_empty(&dcmi->buffers)) {
@@ -242,52 +243,6 @@ static int dcmi_restart_capture(struct stm32_dcmi *dcmi)
 	return dcmi_start_capture(dcmi, buf);
 }
 
-static void dcmi_dma_callback(void *param)
-{
-	struct stm32_dcmi *dcmi = (struct stm32_dcmi *)param;
-	struct dma_tx_state state;
-	enum dma_status status;
-	struct dcmi_buf *buf = dcmi->active;
-
-	spin_lock_irq(&dcmi->irqlock);
-
-	/* Check DMA status */
-	status = dmaengine_tx_status(dcmi->dma_chan, dcmi->dma_cookie, &state);
-
-	switch (status) {
-	case DMA_IN_PROGRESS:
-		dev_dbg(dcmi->dev, "%s: Received DMA_IN_PROGRESS\n", __func__);
-		break;
-	case DMA_PAUSED:
-		dev_err(dcmi->dev, "%s: Received DMA_PAUSED\n", __func__);
-		break;
-	case DMA_ERROR:
-		dev_err(dcmi->dev, "%s: Received DMA_ERROR\n", __func__);
-
-		/* Return buffer to V4L2 in error state */
-		dcmi_buffer_done(dcmi, buf, 0, -EIO);
-		break;
-	case DMA_COMPLETE:
-		dev_dbg(dcmi->dev, "%s: Received DMA_COMPLETE\n", __func__);
-
-		/* Return buffer to V4L2 */
-		dcmi_buffer_done(dcmi, buf, buf->size, 0);
-
-		spin_unlock_irq(&dcmi->irqlock);
-
-		/* Restart capture */
-		if (dcmi_restart_capture(dcmi))
-			dev_err(dcmi->dev, "%s: Cannot restart capture on DMA complete\n",
-				__func__);
-		return;
-	default:
-		dev_err(dcmi->dev, "%s: Received unknown status\n", __func__);
-		break;
-	}
-
-	spin_unlock_irq(&dcmi->irqlock);
-}
-
 static int dcmi_start_dma(struct stm32_dcmi *dcmi,
 			  struct dcmi_buf *buf)
 {
@@ -344,7 +299,7 @@ static void dcmi_set_crop(struct stm32_dcmi *dcmi)
 	reg_set(dcmi->regs, DCMI_CR, CR_CROP);
 }
 
-static void dcmi_process_jpeg(struct stm32_dcmi *dcmi)
+static void dcmi_process_frame(struct stm32_dcmi *dcmi)
 {
 	struct dma_tx_state state;
 	enum dma_status status;
@@ -354,13 +309,11 @@ static void dcmi_process_jpeg(struct stm32_dcmi *dcmi)
 		return;
 
 	/*
-	 * Because of variable JPEG buffer size sent by sensor,
-	 * DMA transfer never completes due to transfer size never reached.
-	 * In order to ensure that all the JPEG data are transferred
-	 * in active buffer memory, DMA is drained.
-	 * Then DMA tx status gives the amount of data transferred
-	 * to memory, which is then returned to V4L2 through the active
-	 * buffer payload.
+	 * At the time FRAME interrupt is received, all dma req have been sent to the DMA,
+	 * however DMA might still be transferring data hence first synchronize prior to
+	 * getting the status of the DMA transfer.
+	 * Then DMA tx status gives the amount of data transferred to memory, which is then
+	 * returned to V4L2 through the active buffer payload.
 	 */
 
 	spin_unlock_irq(&dcmi->irqlock);
@@ -368,16 +321,16 @@ static void dcmi_process_jpeg(struct stm32_dcmi *dcmi)
 	dmaengine_synchronize(dcmi->dma_chan);
 	spin_lock_irq(&dcmi->irqlock);
 
-	/* Get DMA residue to get JPEG size */
+	/* Get DMA status and residue size */
 	status = dmaengine_tx_status(dcmi->dma_chan, dcmi->dma_cookie, &state);
 	if (status != DMA_ERROR && state.residue < buf->size) {
-		/* Return JPEG buffer to V4L2 with received JPEG buffer size */
+		/* Return buffer to V4L2 with received data size */
 		dcmi_buffer_done(dcmi, buf, buf->size - state.residue, 0);
 	} else {
 		dcmi->errors_count++;
-		dev_err(dcmi->dev, "%s: Cannot get JPEG size from DMA\n",
-			__func__);
-		/* Return JPEG buffer to V4L2 in ERROR state */
+		dev_err(dcmi->dev, "%s: DMA error. status: 0x%x, residue: %d\n",
+			__func__, status, state.residue);
+		/* Return buffer to V4L2 in ERROR state */
 		dcmi_buffer_done(dcmi, buf, 0, -EIO);
 	}
 
@@ -385,11 +338,6 @@ static void dcmi_process_jpeg(struct stm32_dcmi *dcmi)
 	/* Abort DMA operation */
 	dmaengine_terminate_sync(dcmi->dma_chan);
 	spin_lock_irq(&dcmi->irqlock);
-
-	/* Restart capture */
-	if (dcmi_restart_capture(dcmi))
-		dev_err(dcmi->dev, "%s: Cannot restart capture on JPEG received\n",
-			__func__);
 }
 
 static irqreturn_t dcmi_irq_thread(int irq, void *arg)
@@ -420,12 +368,10 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg)
 	if (dcmi->misr & IT_ERR)
 		dcmi->errors_count++;
 
-	if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG &&
-	    dcmi->misr & IT_FRAME) {
-		/* JPEG received */
-		dcmi_process_jpeg(dcmi);
-		spin_unlock_irq(&dcmi->irqlock);
-		return IRQ_HANDLED;
+	if (dcmi->misr & IT_FRAME) {
+		dcmi_process_frame(dcmi);
+		if (dcmi_restart_capture(dcmi))
+			dev_err(dcmi->dev, "%s: Cannot restart capture\n", __func__);
 	}
 
 	spin_unlock_irq(&dcmi->irqlock);
@@ -542,10 +488,6 @@ static int dcmi_buf_prepare(struct vb2_buffer *vb)
 			return -EIO;
 		}
 
-		/* Set completion callback routine for notification */
-		buf->dma_desc->callback = dcmi_dma_callback;
-		buf->dma_desc->callback_param = dcmi;
-
 		/* Mark the descriptor as reusable to avoid having to prepare it */
 		ret = dmaengine_desc_set_reuse(buf->dma_desc);
 		if (ret) {
@@ -818,10 +760,7 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
 	}
 
 	/* Enable interruptions */
-	if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG)
-		reg_set(dcmi->regs, DCMI_IER, IT_FRAME | IT_OVR | IT_ERR);
-	else
-		reg_set(dcmi->regs, DCMI_IER, IT_OVR | IT_ERR);
+	reg_set(dcmi->regs, DCMI_IER, IT_FRAME | IT_OVR | IT_ERR);
 
 	spin_unlock_irq(&dcmi->irqlock);
 

-- 
2.34.1



From alain.volmat at foss.st.com  Thu Dec 18 10:44:45 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Thu, 18 Dec 2025 19:44:45 +0100
Subject: [PATCH 05/12] media: stm32: dcmi: rework spin_lock calls
In-Reply-To: <20251218-stm32-dcmi-dma-chaining-v1-0-39948ca6cbf6@foss.st.com>
References: <20251218-stm32-dcmi-dma-chaining-v1-0-39948ca6cbf6@foss.st.com>
Message-ID: <20251218-stm32-dcmi-dma-chaining-v1-5-39948ca6cbf6@foss.st.com>

Rework of the spin_lock calls in preparation of the rework
of the data handling of the driver. Keep it straight forward
with basically spin_lock protection around everything except
dmaengine calls that might sleep (ex: synchronize / terminate)

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 drivers/media/platform/st/stm32/stm32-dcmi.c | 23 +++++++++++------------
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c
index fa33acc34eab..1015f2d88f54 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmi.c
@@ -227,25 +227,18 @@ static int dcmi_restart_capture(struct stm32_dcmi *dcmi)
 {
 	struct dcmi_buf *buf;
 
-	spin_lock_irq(&dcmi->irqlock);
-
-	if (dcmi->state != RUNNING) {
-		spin_unlock_irq(&dcmi->irqlock);
+	if (dcmi->state != RUNNING)
 		return -EINVAL;
-	}
 
 	/* Restart a new DMA transfer with next buffer */
 	if (list_empty(&dcmi->buffers)) {
 		dev_dbg(dcmi->dev, "Capture restart is deferred to next buffer queueing\n");
 		dcmi->state = WAIT_FOR_BUFFER;
-		spin_unlock_irq(&dcmi->irqlock);
 		return 0;
 	}
 	buf = list_entry(dcmi->buffers.next, struct dcmi_buf, list);
 	dcmi->active = buf;
 
-	spin_unlock_irq(&dcmi->irqlock);
-
 	return dcmi_start_capture(dcmi, buf);
 }
 
@@ -370,8 +363,10 @@ static void dcmi_process_jpeg(struct stm32_dcmi *dcmi)
 	 * buffer payload.
 	 */
 
+	spin_unlock_irq(&dcmi->irqlock);
 	/* Drain DMA */
 	dmaengine_synchronize(dcmi->dma_chan);
+	spin_lock_irq(&dcmi->irqlock);
 
 	/* Get DMA residue to get JPEG size */
 	status = dmaengine_tx_status(dcmi->dma_chan, dcmi->dma_cookie, &state);
@@ -386,8 +381,10 @@ static void dcmi_process_jpeg(struct stm32_dcmi *dcmi)
 		dcmi_buffer_done(dcmi, buf, 0, -EIO);
 	}
 
+	spin_unlock_irq(&dcmi->irqlock);
 	/* Abort DMA operation */
 	dmaengine_terminate_sync(dcmi->dma_chan);
+	spin_lock_irq(&dcmi->irqlock);
 
 	/* Restart capture */
 	if (dcmi_restart_capture(dcmi))
@@ -413,8 +410,10 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg)
 		spin_unlock_irq(&dcmi->irqlock);
 		dmaengine_terminate_sync(dcmi->dma_chan);
 
+		spin_lock_irq(&dcmi->irqlock);
 		if (dcmi_restart_capture(dcmi))
 			dev_err(dcmi->dev, "%s: Cannot restart capture\n", __func__);
+		spin_unlock_irq(&dcmi->irqlock);
 
 		return IRQ_HANDLED;
 	}
@@ -424,8 +423,8 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg)
 	if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG &&
 	    dcmi->misr & IT_FRAME) {
 		/* JPEG received */
-		spin_unlock_irq(&dcmi->irqlock);
 		dcmi_process_jpeg(dcmi);
+		spin_unlock_irq(&dcmi->irqlock);
 		return IRQ_HANDLED;
 	}
 
@@ -599,11 +598,9 @@ static void dcmi_buf_queue(struct vb2_buffer *vb)
 		dev_dbg(dcmi->dev, "Starting capture on buffer[%d] queued\n",
 			buf->vb.vb2_buf.index);
 
-		spin_unlock_irq(&dcmi->irqlock);
 		if (dcmi_start_capture(dcmi, buf))
 			dev_err(dcmi->dev, "%s: Cannot restart capture on overflow or error\n",
 				__func__);
-		return;
 	}
 
 	spin_unlock_irq(&dcmi->irqlock);
@@ -812,11 +809,11 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
 
 	dev_dbg(dcmi->dev, "Start streaming, starting capture\n");
 
-	spin_unlock_irq(&dcmi->irqlock);
 	ret = dcmi_start_capture(dcmi, buf);
 	if (ret) {
 		dev_err(dcmi->dev, "%s: Start streaming failed, cannot start capture\n",
 			__func__);
+		spin_unlock_irq(&dcmi->irqlock);
 		goto err_pipeline_stop;
 	}
 
@@ -826,6 +823,8 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
 	else
 		reg_set(dcmi->regs, DCMI_IER, IT_OVR | IT_ERR);
 
+	spin_unlock_irq(&dcmi->irqlock);
+
 	return 0;
 
 err_pipeline_stop:

-- 
2.34.1



From alain.volmat at foss.st.com  Thu Dec 18 10:44:49 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Thu, 18 Dec 2025 19:44:49 +0100
Subject: [PATCH 09/12] dt-bindings: media: st: dcmi: add DMA-MDMA chaining
 properties
In-Reply-To: <20251218-stm32-dcmi-dma-chaining-v1-0-39948ca6cbf6@foss.st.com>
References: <20251218-stm32-dcmi-dma-chaining-v1-0-39948ca6cbf6@foss.st.com>
Message-ID: <20251218-stm32-dcmi-dma-chaining-v1-9-39948ca6cbf6@foss.st.com>

Add properties update and new sram property necessary in order
to enable the DMA-MDMA chaining.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml b/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml
index 34147127192f..ccaa2d0a2669 100644
--- a/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml
+++ b/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml
@@ -27,11 +27,14 @@ properties:
       - const: mclk
 
   dmas:
-    maxItems: 1
+    minItems: 1
+    maxItems: 2
 
   dma-names:
     items:
       - const: tx
+      - const: mdma_tx
+    minItems: 1
 
   resets:
     maxItems: 1
@@ -40,6 +43,14 @@ properties:
     minItems: 1
     maxItems: 2
 
+  sram:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      phandles to a reserved SRAM region which is used as temporary
+      storage memory between DMA and MDMA engines.
+      The region should be defined as child nodes of the AHB SRAM node
+      as per the generic bindings in Documentation/devicetree/bindings/sram/sram.yaml
+
   port:
     $ref: /schemas/graph.yaml#/$defs/port-base
     unevaluatedProperties: false

-- 
2.34.1



From alain.volmat at foss.st.com  Thu Dec 18 10:44:47 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Thu, 18 Dec 2025 19:44:47 +0100
Subject: [PATCH 07/12] media: stm32: dcmi: use dmaengine_terminate_async in
 irq context
In-Reply-To: <20251218-stm32-dcmi-dma-chaining-v1-0-39948ca6cbf6@foss.st.com>
References: <20251218-stm32-dcmi-dma-chaining-v1-0-39948ca6cbf6@foss.st.com>
Message-ID: <20251218-stm32-dcmi-dma-chaining-v1-7-39948ca6cbf6@foss.st.com>

Whenever receiving an OVERRUN event or an end of frame, the driver stops
currently ongoing DMA transfer since the DCMI stops sending data to dma.
Not doing this would lead to having DMA & DCMI no more synchronized in term
of expected data to be copied.
Since this is done in irq handler context, it is not possible to make any
call that would lead to scheduling hence dmaengine_terminate_sync are not
possible.
Since the dcmi driver is NOT using dma callbacks, it is possible thus to
call instead dmaengine_terminate_async (aka without synchronize) and call
again right after a new dmaengine_submit to setup again a new transfer.
And since this is now a dmaengine_submit_async, there is no need to release
the spinlock around calls to the dmaengine_submit_async.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 drivers/media/platform/st/stm32/stm32-dcmi.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c
index 06b66095844b..25e95ba2ca84 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmi.c
@@ -334,10 +334,8 @@ static void dcmi_process_frame(struct stm32_dcmi *dcmi)
 		dcmi_buffer_done(dcmi, buf, 0, -EIO);
 	}
 
-	spin_unlock_irq(&dcmi->irqlock);
 	/* Abort DMA operation */
-	dmaengine_terminate_sync(dcmi->dma_chan);
-	spin_lock_irq(&dcmi->irqlock);
+	dmaengine_terminate_async(dcmi->dma_chan);
 }
 
 static irqreturn_t dcmi_irq_thread(int irq, void *arg)
@@ -355,10 +353,8 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg)
 		if (dcmi->overrun_count > OVERRUN_ERROR_THRESHOLD)
 			dcmi->errors_count++;
 
-		spin_unlock_irq(&dcmi->irqlock);
-		dmaengine_terminate_sync(dcmi->dma_chan);
+		dmaengine_terminate_async(dcmi->dma_chan);
 
-		spin_lock_irq(&dcmi->irqlock);
 		if (dcmi_restart_capture(dcmi))
 			dev_err(dcmi->dev, "%s: Cannot restart capture\n", __func__);
 		spin_unlock_irq(&dcmi->irqlock);

-- 
2.34.1



From alain.volmat at foss.st.com  Thu Dec 18 10:44:50 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Thu, 18 Dec 2025 19:44:50 +0100
Subject: [PATCH 10/12] media: stm32: dcmi: addition of DMA-MDMA chaining
 support
In-Reply-To: <20251218-stm32-dcmi-dma-chaining-v1-0-39948ca6cbf6@foss.st.com>
References: <20251218-stm32-dcmi-dma-chaining-v1-0-39948ca6cbf6@foss.st.com>
Message-ID: <20251218-stm32-dcmi-dma-chaining-v1-10-39948ca6cbf6@foss.st.com>

Add possibility to rely on an additional MDMA channel and chain
the DMA and MDMA channels allowing to achieve faster capture.
Indeed, on the MP15 platform, the MDMA engine has an higher
bandwidth to the DDR than the DMA engine.  Relying on that
it is possible to capture frames from the DCMI IP into the DDR
by using two channels as follow:

  DCMI -> (DMA) -> SRAM -> (MDMA) -> DDR

The DMA is able by himself to trigger a MDMA request hence, once
properly configured, the DCMI IP can simply trigger the DMA in order
to have the data pushed up to the DDR (via the SRAM and a MDMA
channel).

This behavior is detailed in the document
Documentation/arch/arm/stm32/stm32-dma-mdma-chaining.rst

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 drivers/media/platform/st/stm32/stm32-dcmi.c | 250 +++++++++++++++++++++++----
 1 file changed, 220 insertions(+), 30 deletions(-)

diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c
index 4c0f8ed0f87e..e4a9f96a989b 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmi.c
@@ -15,6 +15,7 @@
 #include <linux/completion.h>
 #include <linux/delay.h>
 #include <linux/dmaengine.h>
+#include <linux/genalloc.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
@@ -113,7 +114,9 @@ struct dcmi_buf {
 	struct vb2_v4l2_buffer	vb;
 	bool			prepared;
 	struct sg_table		sgt;
+	struct sg_table		sgt_mdma;
 	struct dma_async_tx_descriptor *dma_desc;
+	struct dma_async_tx_descriptor *mdma_desc;
 	size_t			size;
 	struct list_head	list;
 };
@@ -159,6 +162,15 @@ struct stm32_dcmi {
 	struct dma_chan			*dma_chan;
 	dma_cookie_t			dma_cookie;
 	u32				dma_max_burst;
+
+	/* Elements for the MDMA - DMA chaining */
+	struct gen_pool			*sram_pool;
+	struct dma_chan			*mdma_chan;
+	void				*sram_buf;
+	u32				sram_buf_size;
+	dma_addr_t			sram_dma_buf;
+	dma_cookie_t			mdma_cookie;
+
 	u32				misr;
 	int				errors_count;
 	int				overrun_count;
@@ -247,12 +259,22 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi,
 			  struct dcmi_buf *buf)
 {
 	/* Push current DMA transaction in the pending queue */
+	if (dcmi->mdma_chan) {
+		dcmi->mdma_cookie = dmaengine_submit(buf->mdma_desc);
+		if (dma_submit_error(dcmi->mdma_cookie)) {
+			dev_err(dcmi->dev, "%s: MDMA submission failed\n", __func__);
+			return -ENXIO;
+		}
+	}
+
 	dcmi->dma_cookie = dmaengine_submit(buf->dma_desc);
 	if (dma_submit_error(dcmi->dma_cookie)) {
 		dev_err(dcmi->dev, "%s: DMA submission failed\n", __func__);
 		return -ENXIO;
 	}
 
+	if (dcmi->mdma_chan)
+		dma_async_issue_pending(dcmi->mdma_chan);
 	dma_async_issue_pending(dcmi->dma_chan);
 
 	return 0;
@@ -301,7 +323,9 @@ static void dcmi_set_crop(struct stm32_dcmi *dcmi)
 
 static void dcmi_process_frame(struct stm32_dcmi *dcmi)
 {
-	struct dma_tx_state state;
+	struct dma_tx_state state, state_dma;
+	size_t bytes_used;
+
 	enum dma_status status;
 	struct dcmi_buf *buf = dcmi->active;
 
@@ -309,23 +333,36 @@ static void dcmi_process_frame(struct stm32_dcmi *dcmi)
 		return;
 
 	/*
-	 * At the time FRAME interrupt is received, all dma req have been sent to the DMA,
-	 * however DMA might still be transferring data hence first synchronize prior to
-	 * getting the status of the DMA transfer.
-	 * Then DMA tx status gives the amount of data transferred to memory, which is then
-	 * returned to V4L2 through the active buffer payload.
+	 * Pause the DMA transfer, leading to trigger of the MDMA channel read while
+	 * keeping a valid residue value on the dma channel
 	 */
+	if (dcmi->mdma_chan) {
+		spin_unlock_irq(&dcmi->irqlock);
+		dmaengine_pause(dcmi->dma_chan);
+		spin_lock_irq(&dcmi->irqlock);
+
+		do {
+			status = dmaengine_tx_status(dcmi->mdma_chan, dcmi->mdma_cookie, &state);
+			cpu_relax();
+		} while (status != DMA_ERROR && status != DMA_COMPLETE &&
+			 state.residue && state.in_flight_bytes);
+	} else {
+		status = dmaengine_tx_status(dcmi->dma_chan, dcmi->dma_cookie, &state);
+	}
 
-	spin_unlock_irq(&dcmi->irqlock);
-	/* Drain DMA */
-	dmaengine_synchronize(dcmi->dma_chan);
-	spin_lock_irq(&dcmi->irqlock);
-
-	/* Get DMA status and residue size */
-	status = dmaengine_tx_status(dcmi->dma_chan, dcmi->dma_cookie, &state);
 	if (status != DMA_ERROR && state.residue < buf->size) {
+		bytes_used = buf->size - state.residue;
+
+		if (state.residue && dcmi->mdma_chan) {
+			dmaengine_tx_status(dcmi->dma_chan, dcmi->dma_cookie, &state_dma);
+			/* Getting full size residue equal to no residue */
+			if (state_dma.residue == dcmi->sram_buf_size)
+				state_dma.residue = 0;
+			bytes_used -= state_dma.residue;
+		}
+
 		/* Return buffer to V4L2 with received data size */
-		dcmi_buffer_done(dcmi, buf, buf->size - state.residue, 0);
+		dcmi_buffer_done(dcmi, buf, bytes_used, 0);
 	} else {
 		dcmi->errors_count++;
 		dev_err(dcmi->dev, "%s: DMA error. status: 0x%x, residue: %d\n",
@@ -336,6 +373,8 @@ static void dcmi_process_frame(struct stm32_dcmi *dcmi)
 
 	/* Abort DMA operation */
 	dmaengine_terminate_async(dcmi->dma_chan);
+	if (dcmi->mdma_chan)
+		dmaengine_terminate_async(dcmi->mdma_chan);
 }
 
 static irqreturn_t dcmi_irq_thread(int irq, void *arg)
@@ -354,13 +393,15 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg)
 			dcmi->errors_count++;
 
 		dmaengine_terminate_async(dcmi->dma_chan);
+		if (dcmi->mdma_chan)
+			dmaengine_terminate_async(dcmi->mdma_chan);
 
 		if (dcmi_restart_capture(dcmi))
 			dev_err(dcmi->dev, "%s: Cannot restart capture\n", __func__);
 		spin_unlock_irq(&dcmi->irqlock);
-
 		return IRQ_HANDLED;
 	}
+
 	if (dcmi->misr & IT_ERR)
 		dcmi->errors_count++;
 
@@ -447,28 +488,70 @@ static int dcmi_buf_prepare(struct vb2_buffer *vb)
 	vb2_set_plane_payload(vb, 0, size);
 
 	if (!buf->prepared) {
+		u32 max_size = dcmi->dma_max_burst;
+		unsigned int dma_nents;
+
 		/* Get memory addresses */
 		buf->size = vb2_plane_size(&buf->vb.vb2_buf, 0);
-		if (buf->size > dcmi->dma_max_burst)
-			num_sgs = DIV_ROUND_UP(buf->size, dcmi->dma_max_burst);
+		if (dcmi->mdma_chan)
+			max_size = dcmi->sram_buf_size / 2;
 
-		ret = sg_alloc_table(&buf->sgt, num_sgs, GFP_ATOMIC);
+		if (buf->size > max_size)
+			num_sgs = DIV_ROUND_UP(buf->size, max_size);
+
+		/*
+		 * If we use MDMA chaining, DMA is used in cyclic mode and the scatterlist
+		 * maximum size is thus 2
+		 */
+		dma_nents = num_sgs;
+		if (dcmi->mdma_chan)
+			dma_nents = min_t(unsigned int, num_sgs, 2);
+
+		ret = sg_alloc_table(&buf->sgt, dma_nents, GFP_ATOMIC);
 		if (ret) {
-			dev_err(dcmi->dev, "sg table alloc failed\n");
+			dev_err(dcmi->dev, "sg table alloc failed for DMA\n");
 			return ret;
 		}
 
+		if (dcmi->mdma_chan) {
+			ret = sg_alloc_table(&buf->sgt_mdma, num_sgs, GFP_ATOMIC);
+			if (ret) {
+				dev_err(dcmi->dev, "sg table alloc failed for MDMA\n");
+				return ret;
+			}
+		}
+
 		dma_buf = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
 
 		dev_dbg(dcmi->dev, "buffer[%d] phy=%pad size=%zu\n",
 			vb->index, &dma_buf, buf->size);
 
-		for_each_sg(buf->sgt.sgl, sg, num_sgs, i) {
-			size_t bytes = min_t(size_t, size, dcmi->dma_max_burst);
+		for_each_sg(buf->sgt.sgl, sg, dma_nents, i) {
+			size_t bytes = min_t(size_t, size, max_size);
+
+			if (!dcmi->mdma_chan) {
+				sg_dma_address(sg) = dma_buf;
+				dma_buf += bytes;
+			} else {
+				/* Targets the beginning = first half of the sram_buf */
+				sg_dma_address(sg) = dcmi->sram_dma_buf;
+				/*
+				 * Targets the second half of the sram_bubf
+				 * for odd indexes of the item of the sg_list
+				 */
+				if (i & 1)
+					sg->dma_address += (dcmi->sram_buf_size / 2);
+			}
+			/*
+			 * In case of DMA-MDMA chaining, since the DMA is working in cyclic mode,
+			 * we need to provide two linked-list node of same size in order to have
+			 * a correct residue value computed.
+			 */
+			if (!dcmi->mdma_chan)
+				sg_dma_len(sg) = bytes;
+			else
+				sg_dma_len(sg) = dcmi->sram_buf_size / 2;
 
-			sg_dma_address(sg) = dma_buf;
-			sg_dma_len(sg) = bytes;
-			dma_buf += bytes;
 			size -= bytes;
 		}
 
@@ -480,6 +563,8 @@ static int dcmi_buf_prepare(struct vb2_buffer *vb)
 							DMA_PREP_INTERRUPT);
 		if (!buf->dma_desc) {
 			dev_err(dcmi->dev, "%s: DMA dmaengine_prep_slave_sg failed\n", __func__);
+			if (dcmi->mdma_chan)
+				sg_free_table(&buf->sgt_mdma);
 			sg_free_table(&buf->sgt);
 			return -EIO;
 		}
@@ -489,10 +574,48 @@ static int dcmi_buf_prepare(struct vb2_buffer *vb)
 		if (ret) {
 			dev_err(dcmi->dev, "%s: DMA dmaengine_desc_set_reuse failed\n", __func__);
 			dmaengine_desc_free(buf->dma_desc);
+			if (dcmi->mdma_chan)
+				sg_free_table(&buf->sgt_mdma);
 			sg_free_table(&buf->sgt);
 			return -EIO;
 		}
 
+		if (dcmi->mdma_chan) {
+			size = dcmi->fmt.fmt.pix.sizeimage;
+			for_each_sg(buf->sgt_mdma.sgl, sg, num_sgs, i) {
+				size_t bytes = min_t(size_t, size, max_size);
+
+				sg_dma_address(sg) = dma_buf;
+				sg_dma_len(sg) = bytes;
+				dma_buf += bytes;
+				size -= bytes;
+			}
+
+			buf->mdma_desc = dmaengine_prep_slave_sg(dcmi->mdma_chan, buf->sgt_mdma.sgl,
+								 buf->sgt_mdma.nents,
+								 DMA_DEV_TO_MEM,
+								 DMA_PREP_INTERRUPT);
+			if (!buf->mdma_desc) {
+				dev_err(dcmi->dev, "%s: failed dmaengine_prep_slave_sg for MDMA\n",
+					__func__);
+				dmaengine_desc_free(buf->dma_desc);
+				sg_free_table(&buf->sgt_mdma);
+				sg_free_table(&buf->sgt);
+				return -EIO;
+			}
+
+			ret = dmaengine_desc_set_reuse(buf->mdma_desc);
+			if (ret) {
+				dev_err(dcmi->dev, "%s: failed to set reuse for mdma desc\n",
+					__func__);
+				dmaengine_desc_free(buf->mdma_desc);
+				dmaengine_desc_free(buf->dma_desc);
+				sg_free_table(&buf->sgt_mdma);
+				sg_free_table(&buf->sgt);
+				return -EIO;
+			}
+		}
+
 		buf->prepared = true;
 
 		vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->size);
@@ -511,6 +634,14 @@ static void dcmi_buf_cleanup(struct vb2_buffer *vb)
 	if (!buf->prepared)
 		return;
 
+	if (dcmi->mdma_chan) {
+		ret = dmaengine_desc_free(buf->mdma_desc);
+		if (ret)
+			dev_err(dcmi->dev, "%s: Failed to free the mdma descriptor (0x%x)\n",
+				__func__, ret);
+		sg_free_table(&buf->sgt_mdma);
+	}
+
 	ret = dmaengine_desc_free(buf->dma_desc);
 	if (ret)
 		dev_err(dcmi->dev, "%s: Failed to free the mdma descriptor (0x%x)\n",
@@ -816,6 +947,8 @@ static void dcmi_stop_streaming(struct vb2_queue *vq)
 
 	/* Stop all pending DMA operations */
 	dmaengine_terminate_sync(dcmi->dma_chan);
+	if (dcmi->mdma_chan)
+		dmaengine_terminate_sync(dcmi->mdma_chan);
 
 	pm_runtime_put(dcmi->dev);
 
@@ -1824,9 +1957,9 @@ static int dcmi_probe(struct platform_device *pdev)
 	struct v4l2_fwnode_endpoint ep = { .bus_type = 0 };
 	struct stm32_dcmi *dcmi;
 	struct vb2_queue *q;
-	struct dma_chan *chan;
+	struct dma_chan *chan, *mdma_chan;
 	struct dma_slave_caps caps;
-	struct dma_slave_config dma_config;
+	struct dma_slave_config dma_config, mdma_config;
 	struct clk *mclk;
 	int ret = 0;
 
@@ -1888,15 +2021,21 @@ static int dcmi_probe(struct platform_device *pdev)
 		return dev_err_probe(&pdev->dev, PTR_ERR(chan),
 				     "Failed to request DMA channel\n");
 
-	dcmi->dma_max_burst = UINT_MAX;
-	ret = dma_get_slave_caps(chan, &caps);
-	if (!ret && caps.max_sg_burst)
-		dcmi->dma_max_burst = caps.max_sg_burst	* DMA_SLAVE_BUSWIDTH_4_BYTES;
+	mdma_chan = dma_request_chan(&pdev->dev, "mdma_tx");
+	if (IS_ERR(mdma_chan)) {
+		ret = PTR_ERR(mdma_chan);
+		if (ret != -ENODEV)
+			return dev_err_probe(&pdev->dev, ret, "Failed to request MDMA channel\n");
+		mdma_chan = NULL;
+	}
 
+	/* Configure the DMA channel */
 	memset(&dma_config, 0, sizeof(dma_config));
 
 	dma_config.src_addr = (dma_addr_t)dcmi->res->start + DCMI_DR;
 	dma_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	if (mdma_chan)
+		dma_config.peripheral_size = 1; /* Indicates chaining */
 
 	/* Configure DMA channel */
 	ret = dmaengine_slave_config(chan, &dma_config);
@@ -1906,6 +2045,47 @@ static int dcmi_probe(struct platform_device *pdev)
 		goto err_dma_slave_config;
 	}
 
+	/* If we want MDMA, we also need a sram pool */
+	if (mdma_chan) {
+		dcmi->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0);
+		if (!dcmi->sram_pool) {
+			dev_info(&pdev->dev, "No SRAM pool, can't use MDMA chaining\n");
+			goto err_dma_slave_config;
+		}
+
+		dev_info(&pdev->dev, "SRAM pool: %zu KiB for DMA/MDMA chaining\n",
+			 gen_pool_size(dcmi->sram_pool) / 1024);
+
+		dcmi->sram_buf_size = gen_pool_size(dcmi->sram_pool);
+		dcmi->sram_buf = gen_pool_dma_zalloc(dcmi->sram_pool, dcmi->sram_buf_size,
+						     &dcmi->sram_dma_buf);
+		if (!dcmi->sram_buf) {
+			dev_err(dcmi->dev, "Failed to allocate from SRAM\n");
+			goto err_dma_slave_config;
+		}
+
+		/* Configure the MDMA Channel */
+		memset(&mdma_config, 0, sizeof(mdma_config));
+		mdma_config.direction = DMA_DEV_TO_MEM;
+		mdma_config.src_addr = dcmi->sram_dma_buf;
+		mdma_config.peripheral_size = dma_config.peripheral_size;
+		mdma_config.peripheral_config = dma_config.peripheral_config;
+		ret = dmaengine_slave_config(mdma_chan, &mdma_config);
+		if (ret < 0) {
+			dev_err(dcmi->dev, "%s: MDMA channel config failed (%d)\n",
+				__func__, ret);
+			goto err_mdma_slave_config;
+		}
+	}
+
+	dcmi->dma_max_burst = UINT_MAX;
+	/* In case of using DMA-MDMA chaining we consider the maximum infini */
+	if (!mdma_chan) {
+		ret = dma_get_slave_caps(chan, &caps);
+		if (!ret && caps.max_sg_burst)
+			dcmi->dma_max_burst = caps.max_sg_burst * DMA_SLAVE_BUSWIDTH_4_BYTES;
+	}
+
 	spin_lock_init(&dcmi->irqlock);
 	mutex_init(&dcmi->lock);
 	init_completion(&dcmi->complete);
@@ -1915,6 +2095,7 @@ static int dcmi_probe(struct platform_device *pdev)
 	dcmi->mclk = mclk;
 	dcmi->state = STOPPED;
 	dcmi->dma_chan = chan;
+	dcmi->mdma_chan = mdma_chan;
 
 	q = &dcmi->queue;
 
@@ -2023,8 +2204,13 @@ static int dcmi_probe(struct platform_device *pdev)
 	v4l2_device_unregister(&dcmi->v4l2_dev);
 err_media_device_cleanup:
 	media_device_cleanup(&dcmi->mdev);
+err_mdma_slave_config:
+	if (dcmi->mdma_chan)
+		gen_pool_free(dcmi->sram_pool, (unsigned long)dcmi->sram_buf, dcmi->sram_buf_size);
 err_dma_slave_config:
 	dma_release_channel(dcmi->dma_chan);
+	if (dcmi->mdma_chan)
+		dma_release_channel(mdma_chan);
 
 	return ret;
 }
@@ -2042,6 +2228,10 @@ static void dcmi_remove(struct platform_device *pdev)
 	media_device_cleanup(&dcmi->mdev);
 
 	dma_release_channel(dcmi->dma_chan);
+	if (dcmi->mdma_chan) {
+		gen_pool_free(dcmi->sram_pool, (unsigned long)dcmi->sram_buf, dcmi->sram_buf_size);
+		dma_release_channel(dcmi->mdma_chan);
+	}
 }
 
 static int dcmi_runtime_suspend(struct device *dev)

-- 
2.34.1



From alain.volmat at foss.st.com  Thu Dec 18 10:44:52 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Thu, 18 Dec 2025 19:44:52 +0100
Subject: [PATCH 12/12] ARM: dts: stm32: enable DCMI DMA-MDMA chaining on
 stm32mp157c-ev1.dts
In-Reply-To: <20251218-stm32-dcmi-dma-chaining-v1-0-39948ca6cbf6@foss.st.com>
References: <20251218-stm32-dcmi-dma-chaining-v1-0-39948ca6cbf6@foss.st.com>
Message-ID: <20251218-stm32-dcmi-dma-chaining-v1-12-39948ca6cbf6@foss.st.com>

Enable the DMA-MDMA chaining for the dcmi (camera capture)
in order to be able to achieve higher resolution.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 arch/arm/boot/dts/st/stm32mp157c-ev1.dts | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/arch/arm/boot/dts/st/stm32mp157c-ev1.dts b/arch/arm/boot/dts/st/stm32mp157c-ev1.dts
index 8f99c30f1af1..68b536b0c6ee 100644
--- a/arch/arm/boot/dts/st/stm32mp157c-ev1.dts
+++ b/arch/arm/boot/dts/st/stm32mp157c-ev1.dts
@@ -86,6 +86,14 @@ &dcmi {
 	pinctrl-names = "default", "sleep";
 	pinctrl-0 = <&dcmi_pins_a>;
 	pinctrl-1 = <&dcmi_sleep_pins_a>;
+	/*
+	 * Enable DMA-MDMA chaining by adding a SRAM pool and
+	 * a MDMA channel
+	 */
+	sram = <&dcmi_pool>;
+
+	dmas = <&dmamux1 75 0x400 0x01>, <&mdma1 0 0x3 0x1200000a 0 0>;
+	dma-names = "tx", "mdma_tx";
 
 	port {
 		dcmi_0: endpoint {
@@ -301,6 +309,13 @@ &spi1 {
 	status = "disabled";
 };
 
+&sram4 {
+	dcmi_pool: dcmi-sram at 0 {
+		reg = <0x0 0x8000>;
+		pool;
+	};
+};
+
 &timers2 {
 	/* spare dmas for other usage (un-delete to enable pwm capture) */
 	/delete-property/dmas;

-- 
2.34.1



From alain.volmat at foss.st.com  Thu Dec 18 10:44:48 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Thu, 18 Dec 2025 19:44:48 +0100
Subject: [PATCH 08/12] media: stm32: dcmi: continuous mode capture in JPEG
In-Reply-To: <20251218-stm32-dcmi-dma-chaining-v1-0-39948ca6cbf6@foss.st.com>
References: <20251218-stm32-dcmi-dma-chaining-v1-0-39948ca6cbf6@foss.st.com>
Message-ID: <20251218-stm32-dcmi-dma-chaining-v1-8-39948ca6cbf6@foss.st.com>

Overall cleanup done allows to now have the JPEG handling
done in the same way as other formats in continuous mode,
allowing to achieve a faster framerate in all resolutions.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 drivers/media/platform/st/stm32/stm32-dcmi.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c
index 25e95ba2ca84..4c0f8ed0f87e 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmi.c
@@ -717,10 +717,6 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
 	if (dcmi->do_crop)
 		dcmi_set_crop(dcmi);
 
-	/* Enable jpeg capture */
-	if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG)
-		reg_set(dcmi->regs, DCMI_CR, CR_CM);/* Snapshot mode */
-
 	/* Enable dcmi */
 	reg_set(dcmi->regs, DCMI_CR, CR_ENABLE);
 

-- 
2.34.1



From molberding at nvidia.com  Thu Dec 18 10:48:10 2025
From: molberding at nvidia.com (Marc Olberding)
Date: Thu, 18 Dec 2025 10:48:10 -0800
Subject: [PATCH v2 0/2] arm: dts: aspeed: Add an alt 128M flash layout.
Message-ID: <20251218-alt-128-v2-0-10499a0b7eb9@nvidia.com>

Add a layout for an alternate 128M flash layout. This is useful for the
aspeed ast2500[2] and ast2600[1] SoCs, where it has the ability to boot
from one of two spi chips, nominally the primary and backup SPIs. Adding
a layout allows userspace to flash the alternate spi by partition and
switch over to it, allowing lower downtime for firmware flash, or for
updating the primary flash from the golden backup flash. This is already
an established scheme for the 32M and 64M layouts, where the layout is
the same but each partition has `alt` prepended to its name. This allows
userspace to just prepend alt to the images in the update process to
specify which flash chip to update. This series also adds support for
the msx4 to use this layout.

References:

[1] https://www.aspeedtech.com/server_ast2600/
[2] https://www.aspeedtech.com/server_ast2500/

Signed-off-by: Marc Olberding <molberding at nvidia.com>
---
Marc Olberding (2):
      arm: dts: aspeed: add an alt 128M flash layout
      arm: dts: aspeed: Add alt partition support to msx4

 .../boot/dts/aspeed/aspeed-bmc-nvidia-msx4-bmc.dts |  1 +
 .../dts/aspeed/openbmc-flash-layout-128-alt.dtsi   | 32 ++++++++++++++++++++++
 2 files changed, 33 insertions(+)
---
base-commit: 459a5aa171c0f13fcd78faa9594dc4aa5a95770b
change-id: 20251218-alt-128-19270d894872

Best regards,
-- 
Marc Olberding <molberding at nvidia.com>



From molberding at nvidia.com  Thu Dec 18 10:48:12 2025
From: molberding at nvidia.com (Marc Olberding)
Date: Thu, 18 Dec 2025 10:48:12 -0800
Subject: [PATCH v2 2/2] arm: dts: aspeed: Add alt partition support to msx4
In-Reply-To: <20251218-alt-128-v2-0-10499a0b7eb9@nvidia.com>
References: <20251218-alt-128-v2-0-10499a0b7eb9@nvidia.com>
Message-ID: <20251218-alt-128-v2-2-10499a0b7eb9@nvidia.com>

Add support for the alt 128M partition table to the msx4. This allows it
program the flash it didn't boot from by partition.

Signed-off-by: Marc Olberding <molberding at nvidia.com>
---
 arch/arm/boot/dts/aspeed/aspeed-bmc-nvidia-msx4-bmc.dts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-nvidia-msx4-bmc.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-nvidia-msx4-bmc.dts
index 44f95a3986cb9e2c6902ba9b3c1ed56e782438b3..a12d4164de4ac82160696b67b69c0e94696c23fd 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-bmc-nvidia-msx4-bmc.dts
+++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-nvidia-msx4-bmc.dts
@@ -67,6 +67,7 @@ flash at 1 {
 		spi-tx-bus-width = <1>;
 		spi-rx-bus-width = <1>;
 		status = "okay";
+		#include "openbmc-flash-layout-128-alt.dtsi"
 	};
 };
 

-- 
2.34.1



From molberding at nvidia.com  Thu Dec 18 10:48:11 2025
From: molberding at nvidia.com (Marc Olberding)
Date: Thu, 18 Dec 2025 10:48:11 -0800
Subject: [PATCH v2 1/2] arm: dts: aspeed: add an alt 128M flash layout
In-Reply-To: <20251218-alt-128-v2-0-10499a0b7eb9@nvidia.com>
References: <20251218-alt-128-v2-0-10499a0b7eb9@nvidia.com>
Message-ID: <20251218-alt-128-v2-1-10499a0b7eb9@nvidia.com>

Add a 128M layout for the BMC flash chip we didn't boot from. Including
this allows the user to write to each partition on the alternate spi
chip. This dtsi follows the existing standard of using the same layout
as non alt version and prepending `alt` to each partition's name.

Testing: Include this in msx4 and cat size, offsets and name
```
for devdir in /sys/class/mtd/mtd*; do
>     [[ -d $devdir && -r $devdir/name ]] || continue
>     name=$(<"$devdir/name")
>     [[ $name == alt* ]] || continue
>
>     size=$(<"$devdir/size")
>     offset=0
>     [[ -r $devdir/offset ]] && offset=$(<"$devdir/offset")
>
>     dev=$(basename "$devdir")
>     printf "%s name=%s offset=0x%X size=0x%X\n" "$dev" "$name" \
>        "$offset" "$size"
> done
mtd10 name=alt-rofs offset=0xA00000 size=0x5600000
mtd11 name=alt-rwfs offset=0x6000000 size=0x2000000
mtd7 name=alt-u-boot offset=0x0 size=0xE0000
mtd8 name=alt-u-boot-env offset=0xE0000 size=0x20000
mtd9 name=alt-kernel offset=0x100000 size=0x900000
```

Signed-off-by: Marc Olberding <molberding at nvidia.com>
---
 .../dts/aspeed/openbmc-flash-layout-128-alt.dtsi   | 32 ++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/arch/arm/boot/dts/aspeed/openbmc-flash-layout-128-alt.dtsi b/arch/arm/boot/dts/aspeed/openbmc-flash-layout-128-alt.dtsi
new file mode 100644
index 0000000000000000000000000000000000000000..08ce2eab472c3da4aa3d841adb0eb1c971e6a25a
--- /dev/null
+++ b/arch/arm/boot/dts/aspeed/openbmc-flash-layout-128-alt.dtsi
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+partitions {
+	compatible = "fixed-partitions";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	u-boot at 0 {
+		reg = <0x0 0xe0000>; // 896KB
+		label = "alt-u-boot";
+	};
+
+	u-boot-env at e0000 {
+		reg = <0xe0000 0x20000>; // 128KB
+		label = "alt-u-boot-env";
+	};
+
+	kernel at 100000 {
+		reg = <0x100000 0x900000>; // 9MB
+		label = "alt-kernel";
+	};
+
+	rofs at a00000 {
+		reg = <0xa00000 0x5600000>; // 86MB
+		label = "alt-rofs";
+	};
+
+	rwfs at 6000000 {
+		reg = <0x6000000 0x2000000>; // 32MB
+		label = "alt-rwfs";
+	};
+};

-- 
2.34.1



From nicolinc at nvidia.com  Thu Dec 18 10:57:23 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Thu, 18 Dec 2025 10:57:23 -0800
Subject: [PATCH V7 2/4] iommu/arm-smmu-v3: Add device-tree support for
 CMDQV driver
In-Reply-To: <e7d3e95f-a885-4b13-ab4d-bc82793c5396@nvidia.com>
References: <20251215064819.3345361-1-amhetre@nvidia.com>
 <20251215064819.3345361-3-amhetre@nvidia.com>
 <23df682e-6d08-4827-994e-1bbd89e5c903@nvidia.com>
 <5e9a0ce1-a0ba-4a31-be95-99f349ec6028@nvidia.com>
 <e7d3e95f-a885-4b13-ab4d-bc82793c5396@nvidia.com>
Message-ID: <aUROk0jRQoLmBRo3@Asurada-Nvidia>

On Thu, Dec 18, 2025 at 08:48:32AM +0000, Jon Hunter wrote:
> On 18/12/2025 06:32, Ashish Mhetre wrote:
> > On 12/18/2025 2:13 AM, Jon Hunter wrote:
> > > > +??? smmu->impl_dev = &pdev->dev;
> > > > +??? smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
> > > > +??? dev_info(smmu->dev, "found companion CMDQV device: %s\n",
> > > > +???????? dev_name(smmu->impl_dev));
> > > 
> > > This seems a bit noisy. dev_dbg?
> > > 
> > 
> > This info print is similar to what is there in ACPI path as well.
> > It's only a single print per SMMU at boot time. Should I still change
> > it to dev_dbg?
> 
> Yes, I would.

It's really not that bad IMHO, I am not against that though..

If we have to change that, we'd need another patch changing the
one in the ACPI path as well to keep things aligned.

Nicolin


From royluo at google.com  Thu Dec 18 11:02:28 2025
From: royluo at google.com (Roy Luo)
Date: Thu, 18 Dec 2025 11:02:28 -0800
Subject: [PATCH v9 2/2] usb: dwc3: Add Google Tensor SoC DWC3 glue driver
In-Reply-To: <067e0b1f-ffb6-4f38-b4ac-8abdf46518ea@kernel.org>
References: <20251205-controller-v9-0-9f158b18f979@google.com>
 <20251205-controller-v9-2-9f158b18f979@google.com> <2025120553-suffrage-divisive-5890@gregkh>
 <CA+zupgzL7v5MZDpxKDQQCqAZaqTdHbiG9-xTr+8RnigMFZJ_7Q@mail.gmail.com>
 <2025121728-reliably-crabgrass-2601@gregkh> <CA+zupgxZCyNonfNPbGnFymGGOQuaWR1TsL+hujTbH4DEcfEt9Q@mail.gmail.com>
 <CAD=FV=U63F-wxwKDo9be6_X2P2zp6aTBjNghZRbXX1rn4jFNyg@mail.gmail.com>
 <CA+zupgyG4Nov0=jihSApp_3_0hy6YNZMkfOp6Q4-zmERFm10Ag@mail.gmail.com> <067e0b1f-ffb6-4f38-b4ac-8abdf46518ea@kernel.org>
Message-ID: <CA+zupgwgfKwPYqj8G2tNf4pEXNEWA+vL2WYJPhJ16xExgko7Dw@mail.gmail.com>

On Wed, Dec 17, 2025 at 11:06?PM Krzysztof Kozlowski <krzk at kernel.org> wrote:
>
> On 18/12/2025 02:34, Roy Luo wrote:
> > On Wed, Dec 17, 2025 at 12:14?PM Doug Anderson <dianders at google.com> wrote:
> >>
> >> Hi,
> >>
> >> On Wed, Dec 17, 2025 at 11:18?AM Roy Luo <royluo at google.com> wrote:
> >>>
> >>> On Wed, Dec 17, 2025 at 5:24?AM Greg Kroah-Hartman
> >>> <gregkh at linuxfoundation.org> wrote:
> >>>>
> >>>> On Thu, Dec 04, 2025 at 11:14:39PM -0800, Roy Luo wrote:
> >>>>> On Thu, Dec 4, 2025 at 10:05?PM Greg Kroah-Hartman
> >>>>> <gregkh at linuxfoundation.org> wrote:
> >>>>>>
> >>>>>> On Fri, Dec 05, 2025 at 02:26:38AM +0000, Roy Luo wrote:
> >>>>>>> +config USB_DWC3_GOOGLE
> >>>>>>> +     tristate "Google Platform"
> >>>>>>> +     depends on ARCH_GOOGLE || COMPILE_TEST
> >>>>>>
> >>>>>> There is no ARCH_GOOGLE in the tree now, so how is this supposed to
> >>>>>> work?  Shouldn't tools that check for "invalid config options" trigger
> >>>>>> on this?
> >>>>>>
> >>>>>> thanks,
> >>>>>>
> >>>>>> greg k-h
> >>>>>
> >>>>> Hi Greg,
> >>>>>
> >>>>> The menuconfig looks like the following and it doesn't complain:
> >>>>> | Symbol: ARCH_GOOGLE [=ARCH_GOOGLE]
> >>>>> | Type  : unknown
> >>>>> |
> >>>>> | Symbol: PHY_GOOGLE_USB [=y]
> >>>>> | Type  : tristate
> >>>>> | Defined at drivers/phy/Kconfig:104
> >>>>> |     Prompt: Google Tensor SoC USB PHY driver
> >>>>> |     Depends on: ARCH_GOOGLE || COMPILE_TEST [=y]
> >>>>>
> >>>>> According to Kconfig documentation [1], the unknown symbol
> >>>>> would simply be evaluated as an "n", which is what we want.
> >>>>> "Convert the symbol into an expression. Boolean and tristate
> >>>>> symbols are simply converted into the respective expression
> >>>>> values. All other symbol types result in ?n?."
> >>>>>
> >>>>> In a different Kconfig documentation, an environment variable
> >>>>> "KCONFIG_WARN_UNKNOWN_SYMBOLS" is there to detect
> >>>>> undefined symbols in the "config input", but I can't find one that
> >>>>> catches undefined symbols in the Kconfig tree itself.
> >>>>>
> >>>>> That is, the tool seems to allow this.
> >>>>> However, if this turns out to be a major problem. I think we
> >>>>> can either:
> >>>>> - Remove ARCH_GOOGLE and leave COMPILE_TEST as
> >>>>>   the only dependency. Then add ARCH_GOOGLE back
> >>>>>   later once it's in the tree.
> >>>>
> >>>> Please do this.  I do not want to take patches that purposfully add
> >>>> dependencies on config options that might, or might not, appear in the
> >>>> future.  Please just remove all of the dependancies for now, as they are
> >>>> not needed, right?
> >>>>
> >>>> thanks,
> >>>>
> >>>> greg k-h
> >>>
> >>> Greg,
> >>>
> >>> Yes, we can remove ARCH_GOOGLE for now.
> >>> To clarify, we're not removing all of the dependencies, we still want
> >>> to keep COMPILE_TEST for build tests, right?
> >>> Please let me know if you think otherwise.
> >>
> >> I think you'd just remove all of them. Normally COMPILE_TEST just
> >> allows folks to compile stuff even when they don't want the ARCH. We
> >> can can add ARCH_GOOGLE back in later once the config exists.
> >>
> >> -Doug
> >
> > Doug,
> >
> > Thanks for chiming in. I'm hesitant to remove COMPILE_TEST
> > because Greg specifically requested its inclusion in v7 [1].
>
>
> What? No, that's not what Greg requested. Your COMPILE_TEST in current
> form helps nothing in build testing. It makes absolutely no sense at all.
>
> > Also it seems beneficial to get some build coverage before
> > ARCH_GOOGLE is officially added to the tree.
>
> And COMPILE_TEST like you wrote it does not give you that. Please first
> read how this function works.
>
> > Greg, could you clarify?
>
> Can you first look at Linux kernel sources to see how this is properly
> written?
>
> >
> > [1] https://lore.kernel.org/linux-usb/2025112144-claw-recolor-49c3 at gregkh/
> >
> > Thanks,
> > Roy
>
>
> Best regards,
> Krzysztof

Greg and Krzysztof,

Thanks for the clarification.

Regards,
Roy


From nm at ti.com  Thu Dec 18 11:04:49 2025
From: nm at ti.com (Nishanth Menon)
Date: Thu, 18 Dec 2025 13:04:49 -0600
Subject: [PATCH v5] dt-bindings: arm: keystone: add boot_* mboxes to
 ti,sci
In-Reply-To: <20251217125747.GA689283-robh@kernel.org>
References: <20251215-k3_syscon_add_boot_mailboxes-v5-1-5a8fe567fd31@ti.com>
 <20251215135708.ij5e7jr3binzmlbf@panda>
 <20251217125747.GA689283-robh@kernel.org>
Message-ID: <20251218190449.cnp46cf6hikt6cqa@freebie>

On 06:57-20251217, Rob Herring wrote:
> > >    - |
> > >      dmsc: system-controller at 44083000 {
> > > -      compatible = "ti,k2g-sci";
> > > +      compatible = "ti,am654-sci";
> > >        ti,host-id = <12>;
> > > -      mbox-names = "rx", "tx";
> > > -      mboxes = <&secure_proxy_main 11>,
> > > -               <&secure_proxy_main 13>;
> > > +      mbox-names = "rx", "tx", "notify", "boot_rx", "boot_tx";
> > > +      mboxes= <&secure_proxy_mcu 6>, <&secure_proxy_mcu 8>,
> > > +        <&secure_proxy_mcu 5>, <&secure_proxy_mcu 5>, <&secure_proxy_mcu 4>;
> > >        reg-names = "debug_messages";
> > >        reg = <0x44083000 0x1000>;
> > 
> > Please add a different example for am654, i want to make sure k2g still
> > continues to be checked.
> > 
> > That said, AM62 series of devices do not use notification pipe for
> > standard communication. So, the schema will break for those.
> > 
> > in summary:
> > k2g: rx, tx
> > am654, j721e, j721s2, j7200, j784s4, .. : rx, tx, notify, boot_rx,
> > boot_tx, boot_notify
> > am625, am62p ..: rx, tx, boot_rx, boot_tx, boot_notify
> > 
> > we will need three examples, and will need to add am62x series as one
> > additional compatible.
> 
> Do we really? We have a whole tree of examples in .dts files.

We do not. But, I would rather leave existing valid example as is rather
than modifying it for a new compatible that was just added.

-- 
Regards,
Nishanth Menon
Key (0xDDB5849D1736249D) / Fingerprint: F8A2 8693 54EB 8232 17A3  1A34 DDB5 849D 1736 249D
https://ti.com/opensource


From ebiggers at kernel.org  Thu Dec 18 11:06:06 2025
From: ebiggers at kernel.org (Eric Biggers)
Date: Thu, 18 Dec 2025 11:06:06 -0800
Subject: [GIT PULL] Crypto library fixes for v6.19-rc2
Message-ID: <20251218190606.GB21380@sol>

The following changes since commit 8f0b4cce4481fb22653697cced8d0d04027cb1e8:

  Linux 6.19-rc1 (2025-12-14 16:05:07 +1200)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git tags/libcrypto-fixes-for-linus

for you to fetch changes up to 5a0b1882506858b12cc77f0e2439a5f3c5052761:

  lib/crypto: riscv: Add poly1305-core.S to .gitignore (2025-12-14 10:18:22 -0800)

----------------------------------------------------------------

 - Fix a performance issue with the scoped_ksimd() macro (new in 6.19)
   where it unnecessarily initialized the entire fpsimd state.

 - Add a missing gitignore entry for a generated file added in 6.18.

----------------------------------------------------------------
Ard Biesheuvel (1):
      arm64/simd: Avoid pointless clearing of FP/SIMD buffer

Charles Mirabile (1):
      lib/crypto: riscv: Add poly1305-core.S to .gitignore

 arch/arm64/include/asm/simd.h | 9 ++++++++-
 lib/crypto/riscv/.gitignore   | 2 ++
 2 files changed, 10 insertions(+), 1 deletion(-)
 create mode 100644 lib/crypto/riscv/.gitignore


From andrea.porta at suse.com  Thu Dec 18 11:09:05 2025
From: andrea.porta at suse.com (Andrea della Porta)
Date: Thu, 18 Dec 2025 20:09:05 +0100
Subject: [PATCH 0/4] Fix RP1 DeviceTree hierarchy and drop overlay support
Message-ID: <cover.1766077285.git.andrea.porta@suse.com>

The current RP1 implementation is plagued by several issues, as follows:

- the node name for RP1 is too specific and should be generic instead
  (see [1]).

- the fully defined DTS has its PCI hierarchy wrongly described. There
  should be a PCI root port between the root complex and the endpoint
  (see [1]).

- since CONFIG_PCI_DYNAMIC_OF_NODES can be dropped in the future
  becoming an automatically enabled feature, it would be wise to not
  depend on it (see [2]).

- overlay support has led to a lot of confusion. It's not really usable 
  right now and users are not even used to it (see [3]).

This patch aims at solving the aforementioned problems by amending the
PCI topology as follows:

  ...
  pcie at 1000120000 {
    ...

    pci at 0,0 {
      device_type = "pci";
      reg = <0x00 0x00 0x00 0x00 0x00>;
      ...

      dev at 0,0 {
        compatible = "pci1de4,1";
        reg = <0x10000 0x00 0x00 0x00 0x00>;
        ...

        pci-ep-bus at 1 {
          compatible = "simple-bus";
          ...

          /* peripherals child nodes */
        }; 
      }; 
    }; 
  }; 

The reg property is important since it permits the binding the OF
device_node structure to the pci_dev, encoding the BDF in the upper
portion of the address.

This patch also drops the overlay support in favor of the fully
described DT while streamlining it as a result.

Links:
[1] - https://lore.kernel.org/all/aTvz_OeVnciiqATz at apocalypse/
[2] - https://lore.kernel.org/all/CAL_JsqJUzB71QdMcxJtNZ7raoPcK+SfTh7EVzGmk=syo8xLKQw at mail.gmail.com/
[3] - https://lore.kernel.org/all/CAL_JsqJUzB71QdMcxJtNZ7raoPcK+SfTh7EVzGmk=syo8xLKQw at mail.gmail.com/

Andrea della Porta (4):
  dt-bindings: misc: pci1de4,1: add required reg property for endpoint
  misc: rp1: drop overlay support
  arm64: dts: broadcom: bcm2712: fix RP1 endpoint PCI topology
  arm64: dts: broadcom: rp1: drop RP1 overlay

 .../devicetree/bindings/misc/pci1de4,1.yaml   |  8 +++-
 arch/arm64/boot/dts/broadcom/Makefile         |  4 +-
 ...-ovl-rp1.dts => bcm2712-rpi-5-b-base.dtsi} |  0
 .../boot/dts/broadcom/bcm2712-rpi-5-b.dts     | 39 ++++++++++++-------
 arch/arm64/boot/dts/broadcom/rp1-nexus.dtsi   | 14 -------
 arch/arm64/boot/dts/broadcom/rp1.dtso         | 11 ------
 drivers/misc/rp1/Kconfig                      |  6 +--
 drivers/misc/rp1/Makefile                     |  3 +-
 drivers/misc/rp1/rp1-pci.dtso                 | 25 ------------
 drivers/misc/rp1/rp1_pci.c                    | 37 ++----------------
 drivers/pci/quirks.c                          |  1 -
 11 files changed, 40 insertions(+), 108 deletions(-)
 rename arch/arm64/boot/dts/broadcom/{bcm2712-rpi-5-b-ovl-rp1.dts => bcm2712-rpi-5-b-base.dtsi} (100%)
 delete mode 100644 arch/arm64/boot/dts/broadcom/rp1-nexus.dtsi
 delete mode 100644 arch/arm64/boot/dts/broadcom/rp1.dtso
 delete mode 100644 drivers/misc/rp1/rp1-pci.dtso

-- 
2.35.3



From andrea.porta at suse.com  Thu Dec 18 11:09:06 2025
From: andrea.porta at suse.com (Andrea della Porta)
Date: Thu, 18 Dec 2025 20:09:06 +0100
Subject: [PATCH 1/4] dt-bindings: misc: pci1de4,1: add required reg property for endpoint
In-Reply-To: <cover.1766077285.git.andrea.porta@suse.com>
References: <cover.1766077285.git.andrea.porta@suse.com>
Message-ID: <b58bfcd957b2270fcf932d463f2db534b2ae1a6d.1766077285.git.andrea.porta@suse.com>

The PCI subsystem links an endpoint Device Tree node to its corresponding
pci_dev structure only if the Bus/Device/Function (BDF) encoded in the
'reg' property matches the actual hardware topology.

Add the 'reg' property and mark it as required to ensure proper binding
between the device_node and the pci_dev.

Update the example to reflect this requirement.

Signed-off-by: Andrea della Porta <andrea.porta at suse.com>
---
 Documentation/devicetree/bindings/misc/pci1de4,1.yaml | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/misc/pci1de4,1.yaml b/Documentation/devicetree/bindings/misc/pci1de4,1.yaml
index 2f9a7a554ed8a..17a8c19af8cc2 100644
--- a/Documentation/devicetree/bindings/misc/pci1de4,1.yaml
+++ b/Documentation/devicetree/bindings/misc/pci1de4,1.yaml
@@ -25,6 +25,10 @@ properties:
     items:
       - const: pci1de4,1
 
+  reg:
+    maxItems: 1
+    description: The PCI Bus-Device-Function address.
+
   '#interrupt-cells':
     const: 2
     description: |
@@ -101,6 +105,7 @@ unevaluatedProperties: false
 
 required:
   - compatible
+  - reg
   - '#interrupt-cells'
   - interrupt-controller
   - pci-ep-bus at 1
@@ -111,8 +116,9 @@ examples:
         #address-cells = <3>;
         #size-cells = <2>;
 
-        rp1 at 0,0 {
+        dev at 0,0 {
             compatible = "pci1de4,1";
+            reg = <0x10000 0x0 0x0 0x0 0x0>;
             ranges = <0x01 0x00 0x00000000  0x82010000 0x00 0x00  0x00 0x400000>;
             #address-cells = <3>;
             #size-cells = <2>;
-- 
2.35.3



From nm at ti.com  Thu Dec 18 11:06:27 2025
From: nm at ti.com (Nishanth Menon)
Date: Thu, 18 Dec 2025 13:06:27 -0600
Subject: [PATCH v4 2/2] arm64: dts: ti: Add TQ-Systems TQMa62xx SoM and
 MBa62xx carrier board Device Trees
In-Reply-To: <637f14d1c77c2a1d19f7ea221addbbea51392bd9.camel@ew.tq-group.com>
References: <cover.1762775119.git.matthias.schiffer@ew.tq-group.com>
 <0079cc291c78b94068f3d8c59df103e951247acc.1762775119.git.matthias.schiffer@ew.tq-group.com>
 <d13a95659bdd1c840dfaa46afd6d8583f1b7c88f.camel@ew.tq-group.com>
 <671625aa-f5da-4e34-9c8c-7a1da282aa5e@ti.com>
 <637f14d1c77c2a1d19f7ea221addbbea51392bd9.camel@ew.tq-group.com>
Message-ID: <20251218190627.4nun3fduu6z6yyl3@tingly>

On 10:10-20251217, Matthias Schiffer wrote:
> On Wed, 2025-11-26 at 10:47 +0530, Vignesh Raghavendra wrote:
> > Hi Matthias,
> > 
> > On 25/11/25 15:32, Matthias Schiffer wrote:
> > > On Mon, 2025-11-10 at 12:49 +0100, Matthias Schiffer wrote:
> > > > The TQMa62xx is a SoM family with a pluggable board connector based on the
> > > > TI AM62x SoCs. Add DTS(I) for the AM625 (2x Cortex-A53) variant and its
> > > > combination with our MBa62xx carrier board.
> > > 
> > > Hi Vignesh,
> > > 
> > > do you have any further comments? Can we get this in for 6.19?
> > > 
> > 
> > Oops, this somehow fell through the crack, my apologies!
> > 
> > I have already sent out the PRs for v6.19. Sorry, this would need to
> > wait for v6.20 cycle.
> > 
> > [...]
> > 
> > 
> 
> Hi Vignesh,
> 
> will these patches by applied for v6.20 (if there aren't any more review
> comments)? Should I resend them?

Yes please, Please resend after rebasing to latest next. Vignesh and I
switch picking patches, so the v6.20 window, i am picking them up, will
be good  to repost them so they appear in my private patchworks for me
to track.

Please note that there are additional checks in place so, will be good
to rerun dtbs_check prior to posting.

-- 
Regards,
Nishanth Menon
Key (0xDDB5849D1736249D) / Fingerprint: F8A2 8693 54EB 8232 17A3  1A34 DDB5 849D 1736 249D
https://ti.com/opensource


From andrea.porta at suse.com  Thu Dec 18 11:09:07 2025
From: andrea.porta at suse.com (Andrea della Porta)
Date: Thu, 18 Dec 2025 20:09:07 +0100
Subject: [PATCH 2/4] misc: rp1: drop overlay support
In-Reply-To: <cover.1766077285.git.andrea.porta@suse.com>
References: <cover.1766077285.git.andrea.porta@suse.com>
Message-ID: <4b0aa7160877cf128b9bc713776bcac73c46eb24.1766077285.git.andrea.porta@suse.com>

The RP1 driver can load an overlay at runtime to describe the inner
peripherals. This has led to a lot of confusion regarding the naming
of nodes, their topology and the reclaiming of related node resources.

Since the overlay is currently not fully functional, drop its support
in the driver in favor of the fully described static DT.

This also means that this driver does not depend on CONFIG_PCI_DYNAMIC_OF_NODES
and no longer requires PCI quirks to dynamically create the intermediate
PCI nodes.

Signed-off-by: Andrea della Porta <andrea.porta at suse.com>
---
 drivers/misc/rp1/Kconfig      |  6 +-----
 drivers/misc/rp1/Makefile     |  3 +--
 drivers/misc/rp1/rp1-pci.dtso | 25 -----------------------
 drivers/misc/rp1/rp1_pci.c    | 37 ++++-------------------------------
 drivers/pci/quirks.c          |  1 -
 5 files changed, 6 insertions(+), 66 deletions(-)
 delete mode 100644 drivers/misc/rp1/rp1-pci.dtso

diff --git a/drivers/misc/rp1/Kconfig b/drivers/misc/rp1/Kconfig
index 5232e70d3079b..2c13b3968b011 100644
--- a/drivers/misc/rp1/Kconfig
+++ b/drivers/misc/rp1/Kconfig
@@ -5,8 +5,7 @@
 
 config MISC_RP1
 	tristate "RaspberryPi RP1 misc device"
-	depends on OF_IRQ && OF_OVERLAY && PCI_MSI && PCI_QUIRKS
-	select PCI_DYNAMIC_OF_NODES
+	depends on OF_IRQ && PCI_MSI
 	help
 	  Support the RP1 peripheral chip found on Raspberry Pi 5 board.
 
@@ -15,6 +14,3 @@ config MISC_RP1
 
 	  The driver is responsible for enabling the DT node once the PCIe
 	  endpoint has been configured, and handling interrupts.
-
-	  This driver uses an overlay to load other drivers to support for
-	  RP1 internal sub-devices.
diff --git a/drivers/misc/rp1/Makefile b/drivers/misc/rp1/Makefile
index 508b4cb056277..ab32b433d7ede 100644
--- a/drivers/misc/rp1/Makefile
+++ b/drivers/misc/rp1/Makefile
@@ -1,3 +1,2 @@
 # SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_MISC_RP1)		+= rp1-pci.o
-rp1-pci-objs			:= rp1_pci.o rp1-pci.dtbo.o
+obj-$(CONFIG_MISC_RP1)		+= rp1_pci.o
diff --git a/drivers/misc/rp1/rp1-pci.dtso b/drivers/misc/rp1/rp1-pci.dtso
deleted file mode 100644
index eea826b36e029..0000000000000
--- a/drivers/misc/rp1/rp1-pci.dtso
+++ /dev/null
@@ -1,25 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
-
-/*
- * The dts overlay is included from the dts directory so
- * it can be possible to check it with CHECK_DTBS while
- * also compile it from the driver source directory.
- */
-
-/dts-v1/;
-/plugin/;
-
-/ {
-	fragment at 0 {
-		target-path="";
-		__overlay__ {
-			compatible = "pci1de4,1";
-			#address-cells = <3>;
-			#size-cells = <2>;
-			interrupt-controller;
-			#interrupt-cells = <2>;
-
-			#include "arm64/broadcom/rp1-common.dtsi"
-		};
-	};
-};
diff --git a/drivers/misc/rp1/rp1_pci.c b/drivers/misc/rp1/rp1_pci.c
index a342bcc6164bb..d210da84c30a2 100644
--- a/drivers/misc/rp1/rp1_pci.c
+++ b/drivers/misc/rp1/rp1_pci.c
@@ -34,16 +34,11 @@
 /* Interrupts */
 #define RP1_INT_END		61
 
-/* Embedded dtbo symbols created by cmd_wrap_S_dtb in scripts/Makefile.lib */
-extern char __dtbo_rp1_pci_begin[];
-extern char __dtbo_rp1_pci_end[];
-
 struct rp1_dev {
 	struct pci_dev *pdev;
 	struct irq_domain *domain;
 	struct irq_data *pcie_irqds[64];
 	void __iomem *bar1;
-	int ovcs_id;	/* overlay changeset id */
 	bool level_triggered_irq[RP1_INT_END];
 };
 
@@ -184,24 +179,13 @@ static void rp1_unregister_interrupts(struct pci_dev *pdev)
 
 static int rp1_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
-	u32 dtbo_size = __dtbo_rp1_pci_end - __dtbo_rp1_pci_begin;
-	void *dtbo_start = __dtbo_rp1_pci_begin;
 	struct device *dev = &pdev->dev;
 	struct device_node *rp1_node;
-	bool skip_ovl = true;
 	struct rp1_dev *rp1;
 	int err = 0;
 	int i;
 
-	/*
-	 * Either use rp1_nexus node if already present in DT, or
-	 * set a flag to load it from overlay at runtime
-	 */
-	rp1_node = of_find_node_by_name(NULL, "rp1_nexus");
-	if (!rp1_node) {
-		rp1_node = dev_of_node(dev);
-		skip_ovl = false;
-	}
+	rp1_node = dev_of_node(dev);
 
 	if (!rp1_node) {
 		dev_err(dev, "Missing of_node for device\n");
@@ -276,42 +260,29 @@ static int rp1_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 						 rp1_chained_handle_irq, rp1);
 	}
 
-	if (!skip_ovl) {
-		err = of_overlay_fdt_apply(dtbo_start, dtbo_size, &rp1->ovcs_id,
-					   rp1_node);
-		if (err)
-			goto err_unregister_interrupts;
-	}
-
 	err = of_platform_default_populate(rp1_node, NULL, dev);
 	if (err) {
 		dev_err_probe(&pdev->dev, err, "Error populating devicetree\n");
-		goto err_unload_overlay;
+		goto err_unregister_interrupts;
 	}
 
-	if (skip_ovl)
-		of_node_put(rp1_node);
+	of_node_put(rp1_node);
 
 	return 0;
 
-err_unload_overlay:
-	of_overlay_remove(&rp1->ovcs_id);
 err_unregister_interrupts:
 	rp1_unregister_interrupts(pdev);
 err_put_node:
-	if (skip_ovl)
-		of_node_put(rp1_node);
+	of_node_put(rp1_node);
 
 	return err;
 }
 
 static void rp1_remove(struct pci_dev *pdev)
 {
-	struct rp1_dev *rp1 = pci_get_drvdata(pdev);
 	struct device *dev = &pdev->dev;
 
 	of_platform_depopulate(dev);
-	of_overlay_remove(&rp1->ovcs_id);
 	rp1_unregister_interrupts(pdev);
 }
 
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index b9c252aa6fe08..280cd50d693bd 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -6308,7 +6308,6 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_XILINX, 0x5020, of_pci_make_dev_node);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_XILINX, 0x5021, of_pci_make_dev_node);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_REDHAT, 0x0005, of_pci_make_dev_node);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_EFAR, 0x9660, of_pci_make_dev_node);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_RPI, PCI_DEVICE_ID_RPI_RP1_C0, of_pci_make_dev_node);
 
 /*
  * Devices known to require a longer delay before first config space access
-- 
2.35.3



From andrea.porta at suse.com  Thu Dec 18 11:09:08 2025
From: andrea.porta at suse.com (Andrea della Porta)
Date: Thu, 18 Dec 2025 20:09:08 +0100
Subject: [PATCH 3/4] arm64: dts: broadcom: bcm2712: fix RP1 endpoint PCI topology
In-Reply-To: <cover.1766077285.git.andrea.porta@suse.com>
References: <cover.1766077285.git.andrea.porta@suse.com>
Message-ID: <827b12ba48bb47bc77a0f5e5617aea961c8bc6b5.1766077285.git.andrea.porta@suse.com>

The node describing the RP1 endpoint currently uses a specific name
('rp1_nexus') that does not correctly reflect the PCI topology.

Update the DT with the correct topology and use generic node names.

Additionally, since the driver dropped overlay support in favor of a
fully described DT, rename '...-ovl-rp1.dts' to '...-base.dtsi' for
inclusion in the board DTB, as it is no longer compiled as a
standalone DTB.

Signed-off-by: Andrea della Porta <andrea.porta at suse.com>
---
The DTC compiler produces the following warning:

WARNING: DT compatible string vendor "pci1de4" appears un-documented -- check ./Documentation/devicetree/bindings/vendor-prefixes.yaml
#91: FILE: arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts:31:
                        compatible = "pci1de4,1";

I'm not sure wheter I should add that compatible to vendor-prefixes.yaml
or change the compatible to something already recognized as a vendor,
such as 'raspberrypi,pci1de4,1'.
I'd prefer the former to be consistent to what would be filled by enabling
CONFIG_PCI_DYNAMIC_OF_NODES. Any hint will be really appreciated.
---
 arch/arm64/boot/dts/broadcom/Makefile         |  1 -
 ...-ovl-rp1.dts => bcm2712-rpi-5-b-base.dtsi} |  0
 .../boot/dts/broadcom/bcm2712-rpi-5-b.dts     | 39 ++++++++++++-------
 3 files changed, 26 insertions(+), 14 deletions(-)
 rename arch/arm64/boot/dts/broadcom/{bcm2712-rpi-5-b-ovl-rp1.dts => bcm2712-rpi-5-b-base.dtsi} (100%)

diff --git a/arch/arm64/boot/dts/broadcom/Makefile b/arch/arm64/boot/dts/broadcom/Makefile
index 83d45afc6588e..d43901404c955 100644
--- a/arch/arm64/boot/dts/broadcom/Makefile
+++ b/arch/arm64/boot/dts/broadcom/Makefile
@@ -7,7 +7,6 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-400.dtb \
 			      bcm2711-rpi-4-b.dtb \
 			      bcm2711-rpi-cm4-io.dtb \
 			      bcm2712-rpi-5-b.dtb \
-			      bcm2712-rpi-5-b-ovl-rp1.dtb \
 			      bcm2712-d-rpi-5-b.dtb \
 			      bcm2837-rpi-2-b.dtb \
 			      bcm2837-rpi-3-a-plus.dtb \
diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b-ovl-rp1.dts b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b-base.dtsi
similarity index 100%
rename from arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b-ovl-rp1.dts
rename to arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b-base.dtsi
diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
index 3e0319fdb93f7..2856082814462 100644
--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
+++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
@@ -1,22 +1,16 @@
 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
 /*
- * bcm2712-rpi-5-b-ovl-rp1.dts is the overlay-ready DT which will make
- * the RP1 driver to load the RP1 dtb overlay at runtime, while
- * bcm2712-rpi-5-b.dts (this file) is the fully defined one (i.e. it
- * already contains RP1 node, so no overlay is loaded nor needed).
- * This file is intended to host the override nodes for the RP1 peripherals,
- * e.g. to declare the phy of the ethernet interface or the custom pin setup
- * for several RP1 peripherals.
- * This in turn is due to the fact that there's no current generic
- * infrastructure to reference nodes (i.e. the nodes in rp1-common.dtsi) that
- * are not yet defined in the DT since they are loaded at runtime via overlay.
+ * As a loose attempt to separate RP1 customizations from SoC peripherals
+ * definitioni, this file is intended to host the override nodes for the RP1
+ * peripherals, e.g. to declare the phy of the ethernet interface or custom
+ * pin setup.
  * All other nodes that do not have anything to do with RP1 should be added
- * to the included bcm2712-rpi-5-b-ovl-rp1.dts instead.
+ * to the included bcm2712-rpi-5-b-base.dtsi instead.
  */
 
 /dts-v1/;
 
-#include "bcm2712-rpi-5-b-ovl-rp1.dts"
+#include "bcm2712-rpi-5-b-base.dtsi"
 
 / {
 	aliases {
@@ -25,7 +19,26 @@ aliases {
 };
 
 &pcie2 {
-	#include "rp1-nexus.dtsi"
+	pci at 0,0 {
+		reg = <0x0 0x0 0x0 0x0 0x0>;
+		ranges;
+		bus-range = <0 1>;
+		device_type = "pci";
+		#address-cells = <3>;
+		#size-cells = <2>;
+
+		dev at 0,0 {
+			compatible = "pci1de4,1";
+			reg = <0x10000 0x0 0x0 0x0 0x0>;
+			ranges = <0x1 0x0 0x0 0x82010000 0x0 0x0 0x0 0x400000>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
+			#address-cells = <3>;
+			#size-cells = <2>;
+
+			#include "rp1-common.dtsi"
+		};
+	};
 };
 
 &rp1_eth {
-- 
2.35.3



From andrea.porta at suse.com  Thu Dec 18 11:09:09 2025
From: andrea.porta at suse.com (Andrea della Porta)
Date: Thu, 18 Dec 2025 20:09:09 +0100
Subject: [PATCH 4/4] arm64: dts: broadcom: rp1: drop RP1 overlay
In-Reply-To: <cover.1766077285.git.andrea.porta@suse.com>
References: <cover.1766077285.git.andrea.porta@suse.com>
Message-ID: <85167b815d41ed9ed690ad239a19de5cd2e8be1c.1766077285.git.andrea.porta@suse.com>

RP1 support loaded from overlay has been dropped from the driver and
the DTB intended to be loaded with the overlay no longer exists.

Drop unused include file and overlay.

Signed-off-by: Andrea della Porta <andrea.porta at suse.com>
---
Just a heads up: This patch removes rp1.dtbo from the Makefile, just like
this [1] proposed patch also does, but the merge is trivial.

[1] - https://lore.kernel.org/all/20251211193854.1778221-1-robh at kernel.org/
---
 arch/arm64/boot/dts/broadcom/Makefile       |  3 +--
 arch/arm64/boot/dts/broadcom/rp1-nexus.dtsi | 14 --------------
 arch/arm64/boot/dts/broadcom/rp1.dtso       | 11 -----------
 3 files changed, 1 insertion(+), 27 deletions(-)
 delete mode 100644 arch/arm64/boot/dts/broadcom/rp1-nexus.dtsi
 delete mode 100644 arch/arm64/boot/dts/broadcom/rp1.dtso

diff --git a/arch/arm64/boot/dts/broadcom/Makefile b/arch/arm64/boot/dts/broadcom/Makefile
index d43901404c955..01ecfa3041845 100644
--- a/arch/arm64/boot/dts/broadcom/Makefile
+++ b/arch/arm64/boot/dts/broadcom/Makefile
@@ -13,8 +13,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-400.dtb \
 			      bcm2837-rpi-3-b.dtb \
 			      bcm2837-rpi-3-b-plus.dtb \
 			      bcm2837-rpi-cm3-io3.dtb \
-			      bcm2837-rpi-zero-2-w.dtb \
-			      rp1.dtbo
+			      bcm2837-rpi-zero-2-w.dtb
 
 subdir-y	+= bcmbca
 subdir-y	+= northstar2
diff --git a/arch/arm64/boot/dts/broadcom/rp1-nexus.dtsi b/arch/arm64/boot/dts/broadcom/rp1-nexus.dtsi
deleted file mode 100644
index 0ef30d7f1c352..0000000000000
--- a/arch/arm64/boot/dts/broadcom/rp1-nexus.dtsi
+++ /dev/null
@@ -1,14 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
-
-rp1_nexus {
-	compatible = "pci1de4,1";
-	#address-cells = <3>;
-	#size-cells = <2>;
-	ranges = <0x01 0x00 0x00000000
-		  0x02000000 0x00 0x00000000
-		  0x0 0x400000>;
-	interrupt-controller;
-	#interrupt-cells = <2>;
-
-	#include "rp1-common.dtsi"
-};
diff --git a/arch/arm64/boot/dts/broadcom/rp1.dtso b/arch/arm64/boot/dts/broadcom/rp1.dtso
deleted file mode 100644
index ab4f146d22c06..0000000000000
--- a/arch/arm64/boot/dts/broadcom/rp1.dtso
+++ /dev/null
@@ -1,11 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
-
-/dts-v1/;
-/plugin/;
-
-&pcie2 {
-	#address-cells = <3>;
-	#size-cells = <2>;
-
-	#include "rp1-nexus.dtsi"
-};
-- 
2.35.3



From Suraj.Gupta2 at amd.com  Thu Dec 18 11:06:44 2025
From: Suraj.Gupta2 at amd.com (Gupta, Suraj)
Date: Thu, 18 Dec 2025 19:06:44 +0000
Subject: [PATCH] dmaengine: xilinx_dma: Add support for residue on direct
 AXIDMA S2MM
In-Reply-To: <20251218-xilinx-dma-residue-fix-v1-1-7cd221d69d6b@ideasonboard.com>
References: <20251218-xilinx-dma-residue-fix-v1-1-7cd221d69d6b@ideasonboard.com>
Message-ID: <SA1PR12MB67987D5966B2D69688015A88C9A8A@SA1PR12MB6798.namprd12.prod.outlook.com>

[AMD Official Use Only - AMD Internal Distribution Only]

> -----Original Message-----
> From: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
> Sent: Thursday, December 18, 2025 2:10 PM
> To: Vinod Koul <vkoul at kernel.org>; Simek, Michal <michal.simek at amd.com>;
> Sagar, Vishal <vishal.sagar at amd.com>
> Cc: dmaengine at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux-
> kernel at vger.kernel.org; Laurent Pinchart
> <laurent.pinchart at ideasonboard.com>; Tomi Valkeinen
> <tomi.valkeinen at ideasonboard.com>
> Subject: [PATCH] dmaengine: xilinx_dma: Add support for residue on direct
> AXIDMA S2MM
>
> Caution: This message originated from an External Source. Use proper caution
> when opening attachments, clicking links, or responding.
>
>
> AXIDMA IP supports reporting the amount of bytes transferred on the S2MM
> channel in direct mode (i.e. non-SG), but the driver does not. Thus the
> driver always reports that all of the buffer was filled.
>
> Add xilinx_dma_get_residue_axidma_direct_s2mm() which gets the residue
> amount for direct AXIDMA for S2MM direction.
>
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>


Looks fine to me.
Reviewed-by: Suraj Gupta <suraj.gupta2 at amd.com>

> ---
>  drivers/dma/xilinx/xilinx_dma.c | 21 +++++++++++++++++++++
>  1 file changed, 21 insertions(+)
>
> diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
> index fabff602065f..64b3fba4e44f 100644
> --- a/drivers/dma/xilinx/xilinx_dma.c
> +++ b/drivers/dma/xilinx/xilinx_dma.c
> @@ -1021,6 +1021,24 @@ static u32 xilinx_dma_get_residue(struct
> xilinx_dma_chan *chan,
>         return residue;
>  }
>
> +static u32
> +xilinx_dma_get_residue_axidma_direct_s2mm(struct xilinx_dma_chan *chan,
> +                                         struct xilinx_dma_tx_descriptor *desc)
> +{
> +       struct xilinx_axidma_tx_segment *seg;
> +       struct xilinx_axidma_desc_hw *hw;
> +       u32 finished_len;
> +
> +       finished_len = dma_ctrl_read(chan, XILINX_DMA_REG_BTT);
> +
> +       seg = list_first_entry(&desc->segments, struct xilinx_axidma_tx_segment,
> +                              node);
> +
> +       hw = &seg->hw;
> +
> +       return hw->control - finished_len;
> +}
> +
>  /**
>   * xilinx_dma_chan_handle_cyclic - Cyclic dma callback
>   * @chan: Driver specific dma channel
> @@ -1732,6 +1750,9 @@ static void xilinx_dma_complete_descriptor(struct
> xilinx_dma_chan *chan)
>                 if (chan->has_sg && chan->xdev->dma_config->dmatype !=
>                     XDMA_TYPE_VDMA)
>                         desc->residue = xilinx_dma_get_residue(chan, desc);
> +               else if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA
> &&
> +                        chan->direction == DMA_DEV_TO_MEM && !chan->has_sg)
> +                       desc->residue =
> xilinx_dma_get_residue_axidma_direct_s2mm(chan, desc);
>                 else
>                         desc->residue = 0;
>                 desc->err = chan->err;
>
> ---
> base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
> change-id: 20251218-xilinx-dma-residue-fix-f6e4f97ffe61
>
> Best regards,
> --
> Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
>


From nm at ti.com  Thu Dec 18 11:08:25 2025
From: nm at ti.com (Nishanth Menon)
Date: Thu, 18 Dec 2025 13:08:25 -0600
Subject: [BUG][RT][ti-j72xx] spi: cadence-quadspi: boot failed with
 rtmutex deadlock detected
In-Reply-To: <CO6PR11MB558695EFB87C578370014430CDABA@CO6PR11MB5586.namprd11.prod.outlook.com>
References: <CO6PR11MB558695EFB87C578370014430CDABA@CO6PR11MB5586.namprd11.prod.outlook.com>
Message-ID: <20251218190825.oeucrspxenta2oix@steadfast>

On 08:21-20251217, He, Guocai (CN) wrote:
> Hi all,
> 
> I am seeing an reproducible issue in
> drivers/spi/spi-cadence-quadspi.c on TI J72xx platform.
> 
> Kernel:
>   v6.1/standard/preempt-rt/ti-sdk-6.1/ti-j7xxx
>   (based on Linux v6.1.159 PREEMPT_RT)

^^ sounds like TI vendor kernel?

> 
> Platform:
>   TI J72xx
>   QSPI controller: Cadence QuadSPI
> 

Will be good to discuss vendor kernel issues in e2e.ti.com please.
unless you can reproduce this issue on upstream stable or mainline, this
might be the wrong forum for discussion.

-- 
Regards,
Nishanth Menon
Key (0xDDB5849D1736249D) / Fingerprint: F8A2 8693 54EB 8232 17A3  1A34 DDB5 849D 1736 249D
https://ti.com/opensource


From m.felsch at pengutronix.de  Thu Dec 18 11:08:41 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Thu, 18 Dec 2025 20:08:41 +0100
Subject: [PATCH v7 1/3] dt-bindings: soc: imx93-media-blk-ctrl: Add PDFC
 subnode to schema and example
In-Reply-To: <3210190.mvXUDI8C0e@steina-w>
References: <20251202-v6-18-topic-imx93-parallel-display-v7-0-2cce31d64608@pengutronix.de>
 <705773fc-5aba-4bff-b05e-272e1cd0262c@nxp.com>
 <20251215175436.wwlgzxionq55zu27@pengutronix.de>
 <3210190.mvXUDI8C0e@steina-w>
Message-ID: <20251218190841.pmn3kwghq6lxsfl4@pengutronix.de>

Hi Alexander,

On 25-12-16, Alexander Stein wrote:
> Hi,
> 
> Am Montag, 15. Dezember 2025, 18:54:36 CET schrieb Marco Felsch:
> > Hi Liu,
> > 
> > sorry I didn't fully answer you please see below.
> > 
> > On 25-12-08, Liu Ying wrote:
> > > Hi Marco,
> > > 
> > > On 12/02/2025, Marco Felsch wrote:
> > > > From: Liu Ying <victor.liu at nxp.com>
> > > > 
> > > > i.MX93 SoC mediamix blk-ctrl contains one DISPLAY_MUX register which
> > > > configures parallel display format by using the "PARALLEL_DISP_FORMAT"
> > > > field. Document the Parallel Display Format Configuration(PDFC) subnode
> > > > and add the subnode to example.
> > > > 
> > > > Signed-off-by: Liu Ying <victor.liu at nxp.com>
> > > > [m.felsch at pengutronix.de: port to v6.18-rc1]
> > > > [m.felsch at pengutronix.de: add bus-width]
> > > > Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
> > > > ---
> > > >  .../bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml | 92 ++++++++++++++++++++++
> > > >  1 file changed, 92 insertions(+)
> > > > 
> > > > diff --git a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> > > > index 34aea58094e55365a2f9c86092f637e533f954ff..6e2d86d9341c75108b492bcbabc8a560d8e707cd 100644
> > > > --- a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> > > > +++ b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> > > > @@ -26,6 +26,12 @@ properties:
> > > >    reg:
> > > >      maxItems: 1
> > 
> > ...
> > 
> > > > +            properties:
> > > > +              endpoint:
> > > > +                $ref: /schemas/graph.yaml#/$defs/endpoint-base
> > > > +                unevaluatedProperties: false
> > > > +
> > > > +                properties:
> > > > +                  bus-width:
> > > 
> > > In v1-v5, I thought the output bus format can be determined by the sink
> > > device(a panel or a bridge) hence properties like bus-width were not needed.
> > > But, if this property is really needed, then reference video-interfaces.yaml
> > > since bus-width is documented there.  Should we reference bus-type defined
> > > in video-interfaces.yaml too?
> > 
> > You're right, the bus-width should be determined by the connected panel.
> > But there are cases where a 24-bit panel is connected but only the lower
> > 18-bits are muxed. I added the bus-width property to handle this case.
> > In the end most users don't have to specify this since the correct
> > bus-width is coming from the panel bus-fmt.
> > 
> > > > +                    enum: [ 16, 18, 24 ]
> > > 
> > > The PARALLEL_DISP_FORMAT field of DISPLAY_MUX register says this IP supports
> > > below formats.  It seems that the enum here may tell RGB888, RGB666 and RGB565.
> > > How can we tell RGB555, YCbCr 24 bits and YUV444 then?
> > > 
> > > 000b RGB888 -> RGB888
> > > 001b RGB888 -> RGB666
> > > 010b RGB565 -> RGB565
> > > 011b RGB555 -> RGB555
> > > 100b YUV -> YCbCr 24 bits
> > > 101b YUV -> YUV444
> > 
> > This enum is about the physical bus width. RGB565 == 16-bit, YUV ==
> > 24-bit.
> > 
> > That said, I don't think that you need to specify the bus-fmt since this
> > is coming from the panel. As said above, my itension with the bus-width
> > property is to provide integrators (dts-writers) a possibility to limit
> > the physical available bus width.
> 
> Mh, isn't [1] exactly about this? Not sure about the outcome at that time.

Thanks for the pointer, I wasn't aware of this discussion. I skimmed
through the dt-bindings thread and I agree with Rob and Maxime.

We do have the bus-width endpoint property already. This property is
alredy used by media and drm bridge drivers. Why not making use of for
this simple bridge driver too?

Furthermore I doubt, that a simple drm-bridge MEDIA_BUS_FMT_* convert
driver solves all the problem in a generic way for all platforms, all
connectors, all routing options.

If the i.MX93 NXP-EVKs in [1] would have connected the upper LCD_DAT*
pads instead of the lower ones, there would be no conversion needed by
the PDFC bridge driver, albeit the physical bus is cut to 18-bit width
due to the RPi ext. header limit, which is expanded to 24-bit again later on
via the Adafruit board panel FPC connector.

In such scenario the output width of the PDFC has to be 24-bit else
you would lose not only the two LSBs but also the two MSBs for each
channel. I tried to visualize what I meant for the blue channel:

                 24-bit PDFC bridge
		 ------------------
        +----+----+----+----+----+----+----+----+
 LCDIF  | B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 |
        +----+----+----+----+----+----+----+----+
          |    |    |    |    |    |    |    |
        +----+----+----+----+----+----+----+----+
 PDFC   | B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 |
        +----+----+----+----+----+----+----+----+
                    |    |    |    |    |    |
        +----+----+----+----+----+----+----+----+
SOC_PAD | xx | xx | D2 | D3 | D4 | D5 | D6 | D7 |
        +----+----+----+----+----+----+----+----+
                    |    |    |    |    |    |
        +----+----+----+----+----+----+----+----+
 ext.   | xx | xx | B2 | B3 | B4 | B5 | B6 | B7 |
 HDR    +----+----+----+----+----+----+----+----+
                    |    |    |    |    |    |
                    |    |    |    |    |    |
                    |    |    |    |    |    |
          +-----------------------------+    |
          |    +-----------------------------+
          |    |    |    |    |    |    |    |
        +----+----+----+----+----+----+----+----+
 Ada.   | B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 |
 FPC    +----+----+----+----+----+----+----+----+

                 18-bit PDFC bridge
		 ------------------
        +----+----+----+----+----+----+----+----+
 LCDIF  | B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 |
        +----+----+----+----+----+----+----+----+
          |    |    |    |    |    |    |    |
        +----+----+----+----+----+----+----+----+
 PDFC   | B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 |
        +----+----+----+----+----+----+----+----+
                    |    |    |    |    |    |
          +---------+    |    |    |    |    |
          |    +---------+    |    |    |    |
          |    |    +---------+    |    |    |
          |    |    |    +---------+    |    |
          |    |    |    |    +---------+    |
          |    |    |    |    |    +---------+
          |    |    |    |    |    |
        +----+----+----+----+----+----+----+----+
SOC_PAD | xx | xx | D2 | D3 | D4 | D5 | D6 | D7 |
        +----+----+----+----+----+----+----+----+
                    |    |    |    |    |    |
        +----+----+----+----+----+----+----+----+
 ext.   | xx | xx | B2 | B3 | B4 | B5 | B6 | B7 |
 HDR    +----+----+----+----+----+----+----+----+
                    |    |    |    |    |    |
                    |    |    |    |    |    |
                    |    |    |    |    |    |
          +-----------------------------+    |
          |    +-----------------------------+
          |    |    |    |    |    |    |    |
        +----+----+----+----+----+----+----+----+
 Ada.   | B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 |
 FPC    +----+----+----+----+----+----+----+----+


The mapping can get quite difficult for a single SoC already, just by
using a slighlty different HW routing (the upper D[ata] pads).

Therefore I would keep it simple and device/ip specific (in this case
PDFC specific) by making use of the bus-width. Specifying the bus-width
property could be also wrong albeit it's the case physically, as you can
see in my above example.

Therefore the bus-width property must have a good description.

Regards,
  Marco

> Best regards,
> Alexander
> 
> [1] https://lore.kernel.org/all/20250304101530.969920-1-victor.liu at nxp.com/
> 
> > [snip]
> -- 
> TQ-Systems GmbH | M?hlstra?e 2, Gut Delling | 82229 Seefeld, Germany
> Amtsgericht M?nchen, HRB 105018
> Gesch?ftsf?hrer: Detlef Schneider, R?diger Stahl, Stefan Schneider
> http://www.tq-group.com/



-- 
#gernperDu 
#CallMeByMyFirstName

Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | https://www.pengutronix.de/ |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-9    |


From florian.fainelli at broadcom.com  Thu Dec 18 11:11:00 2025
From: florian.fainelli at broadcom.com (Florian Fainelli)
Date: Thu, 18 Dec 2025 11:11:00 -0800
Subject: [PATCH 0/4] Fix RP1 DeviceTree hierarchy and drop overlay support
In-Reply-To: <cover.1766077285.git.andrea.porta@suse.com>
References: <cover.1766077285.git.andrea.porta@suse.com>
Message-ID: <8cbf63d2-1510-4d58-b2ca-0fd23a476539@broadcom.com>

On 12/18/25 11:09, Andrea della Porta wrote:
> The current RP1 implementation is plagued by several issues, as follows:
> 
> - the node name for RP1 is too specific and should be generic instead
>    (see [1]).
> 
> - the fully defined DTS has its PCI hierarchy wrongly described. There
>    should be a PCI root port between the root complex and the endpoint
>    (see [1]).
> 
> - since CONFIG_PCI_DYNAMIC_OF_NODES can be dropped in the future
>    becoming an automatically enabled feature, it would be wise to not
>    depend on it (see [2]).
> 
> - overlay support has led to a lot of confusion. It's not really usable
>    right now and users are not even used to it (see [3]).
> 
> This patch aims at solving the aforementioned problems by amending the
> PCI topology as follows:
> 
>    ...
>    pcie at 1000120000 {
>      ...
> 
>      pci at 0,0 {
>        device_type = "pci";
>        reg = <0x00 0x00 0x00 0x00 0x00>;
>        ...
> 
>        dev at 0,0 {
>          compatible = "pci1de4,1";
>          reg = <0x10000 0x00 0x00 0x00 0x00>;
>          ...
> 
>          pci-ep-bus at 1 {
>            compatible = "simple-bus";
>            ...
> 
>            /* peripherals child nodes */
>          };
>        };
>      };
>    };
> 
> The reg property is important since it permits the binding the OF
> device_node structure to the pci_dev, encoding the BDF in the upper
> portion of the address.
> 
> This patch also drops the overlay support in favor of the fully
> described DT while streamlining it as a result.

Timing could not have been better as I was just going to apply Rob's patch:

https://lore.kernel.org/all/20251211193854.1778221-1-robh at kernel.org

Yours is definitively more complete. Rob, Krzysztof, can you review this 
series and I will fast track it today.

Thanks!
-- 
Florian


From henrik at grimler.se  Thu Dec 18 11:19:44 2025
From: henrik at grimler.se (Henrik Grimler)
Date: Thu, 18 Dec 2025 20:19:44 +0100
Subject: [PATCH v3 3/3] ARM: samsung: exynos5250: Allow CPU1 to boot
In-Reply-To: <20251215-lat3st-staging-v3-3-2e4914b64dd8@timmermann.space>
References: <20251215-lat3st-staging-v3-0-2e4914b64dd8@timmermann.space>
 <20251215-lat3st-staging-v3-3-2e4914b64dd8@timmermann.space>
Message-ID: <20251218191944.GA63330@l14.localdomain>

Hi Lukas,

On Mon, Dec 15, 2025 at 04:05:24PM +0100, Lukas Timmermann wrote:
> From: Alexandre Marquet <tb at a-marquet.fr>
> 
> The firmware trustzone needs a special call to bring up the secondary
> cpu core on the Manta board. This seems to be not needed on other
> exynos5 boards and comes down to the available firmware on
> a particular board.
> 
> Signed-off-by: Alexandre Marquet <tb at a-marquet.fr>
> Signed-off-by: Lukas Timmermann <linux at timmermann.space>

Reviewed-by: Henrik Grimler <henrik at grimler.se>

I had a look at the manta bootloader, but have not been able to
pinpoint where the smc calls are handled. Nevertheless, Seems like
manta might be the only Exynos 5 android device that needs CPU1BOOT. I
tried to track down exynos5250-arndale's tzsw to compare with, but
seems like it is no longer available anywhere unfortunately.

Here's a summary of my findings from looking at sboot/the tzsw from
various devices, where `CPU1BOOT SMC is handled == yes` means that the
device needs the SMC call.

.----------------------.--------------.--------------.--------------.
| Device (exynos-)     | Similar tzsw | CPU1BOOT SMC | sboot/tzsw   |
|                      | to odroidxu? | is handled?  |   source     |
.----------------------.--------------.--------------.--------------.
  4212-tab3            | yes          | yes          | T310XXSBQB2
  4412-i9300           | yes          | yes          | I9300XXUGPE1
  4412-i9305           | yes          | yes          | I9305XXUFPB1
  4412-odroid{x,x2,u3} | yes          | yes          | wiki.odroid.com/_media/en/boot.tar.gz
  4412-origen          | no           | don't know   | Linaro's origen hwpack 20130130
  5260-hllte (SM-N7505)| no           | don't know   | N7505XXSDRI2
  5410-odroidxu        | yes          | no           | github.com/hsnaves/exynos5410-firmware
  5410-ja3g            | no           | don't know   | I9500XXUHPK1
  5420-chagall-wifi    | no           | no           | T800XXU1CRJ1
  5420-arndale-octa    | yes          | no           | Linaro's arndale-octa hwpack 20140323
  5422-odroid-xu{3,4}  | yes          | no           | Hardkernel's u-boot 2020.01 branch
  5422-samsung-k3g     | no           | don't know   | G900HXXU1CVG7

As can be seen none of the Exynos 5 devices in the list have been
confirmed to need/handle CPU1BOOT.

Best regards,
Henrik Grimler


> ---
>  arch/arm/mach-exynos/firmware.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c
> index a5e22678e27b..e9b0ed07bb90 100644
> --- a/arch/arm/mach-exynos/firmware.c
> +++ b/arch/arm/mach-exynos/firmware.c
> @@ -61,10 +61,10 @@ static int exynos_cpu_boot(int cpu)
>  	 * Exynos3250 doesn't need to send smc command for secondary CPU boot
>  	 * because Exynos3250 removes WFE in secure mode.
>  	 *
> -	 * On Exynos5 devices the call is ignored by trustzone firmware.
> +	 * On most Exynos5 devices the call is ignored by trustzone firmware.
>  	 */
>  	if (!soc_is_exynos4210() && !soc_is_exynos4212() &&
> -	    !soc_is_exynos4412())
> +	    !soc_is_exynos4412() && !of_machine_is_compatible("google,manta"))
>  		return 0;
>  
>  	/*
> 
> -- 
> 2.52.0
> 
> 


From royluo at google.com  Thu Dec 18 11:23:09 2025
From: royluo at google.com (Roy Luo)
Date: Thu, 18 Dec 2025 19:23:09 +0000
Subject: [PATCH v10 0/2] Add Google Tensor SoC USB controller support
Message-ID: <20251218-controller-v10-0-4047c9077274@google.com>

This series introduces USB controller support for the Google Tensor G5
SoC (codename: Laguna), a new generation of Google silicon first
launched with Pixel 10 devices.

The Tensor G5 represents a significant architectural overhaul compared
to previous Tensor generations (e.g., gs101), which were based on Samsung
Exynos IP. Although the G5 still utilizes Synopsys IP for the USB
components, the custom top-level integration introduces a completely new
design for clock, reset scheme, register interfaces and programming
sequence, necessitating new drivers and device tree bindings.

The USB subsystem on Tensor G5 integrates a Synopsys DWC3 USB 3.1
DRD-Single Port controller with hibernation support, and a custom PHY
block comprising Synopsys eUSB2 and USB 3.2/DP combo PHYs. The PHY
support is sent as a separate patch series.

Co-developed-by: Joy Chakraborty <joychakr at google.com>
Signed-off-by: Joy Chakraborty <joychakr at google.com>
Co-developed-by: Naveen Kumar <mnkumar at google.com>
Signed-off-by: Naveen Kumar <mnkumar at google.com>
Signed-off-by: Roy Luo <royluo at google.com>
---
Changes in v10:
- Per Greg's feedback, remove Kconfig dependency on ARCH_GOOGLE || COMPILE_TEST. 
  Remove ARCH_GOOGLE as it's not yet in the kernel, and COMPILE_TEST is no longer needed without it.
Link to v9: https://lore.kernel.org/r/20251205-controller-v9-0-9f158b18f979 at google.com

Changes in v9:
- Update the Kconfig dependency to depends on ARCH_GOOGLE || COMPILE_TEST
  Note that ARCH_GOOGLE does not exist yet but will eventually
  be there when the following patch lands
  https://lore.kernel.org/r/20251111112158.3.I35b9e835ac49ab408e5ca3e0983930a1f1395814 at changeid/
- Mention SoC codename Laguna in Kconfig description.
- Sort the header alphabetically.
- Add driver and binding files to the Tensor SoC MAINTAINER entry.
Link to v8: https://lore.kernel.org/r/20251122-controller-v8-0-e7562e0df658 at google.com

Changes in v8:
- Add COMPILE_TEST to dependencies for build coverage.
- Drop redundant default n in Kconfig.
- Update Kconfig help text to explicitly state the module name.
- Use container_of_const() in the to_dwc3_google() macro for type safety.
Link to v7: https://lore.kernel.org/linux-usb/20251119093749.292926-1-royluo at google.com

Changes in v7:
- Follow driver naming convention and rename the driver as "dwc3-google".
Link to v6: https://lore.kernel.org/linux-usb/20251112123257.3755489-1-royluo at google.com

Changes in v6:
- Use "lga" as SoC name instead of "gs5" to align with Tensor G5 device
  tree https://lore.kernel.org/lkml/20251111192422.4180216-1-dianders at chromium.org
Link to v5: https://lore.kernel.org/linux-usb/20251111130624.3069704-1-royluo at google.com

Changes in v5:
- Use syscon to access host_cfg and usbint_cfg MMIO space per
  discussion in https://lore.kernel.org/linux-phy/89733ddf-8af3-42d0-b6e5-20b7a4ef588c at kernel.org
- Make warn logs in dwc3_google_resume_irq() dev_dbg.
Link to v4: https://lore.kernel.org/linux-usb/20251017233459.2409975-1-royluo at google.com

Changes in v4:
- Separate controller and phy changes into two distinct patch series.
- Rename dwc3 core interrupt as "core".
- Remove u2phy_apb clk/reset (moved to PHY)
- Configure usb2only mode when usb3 phy is not present.
- Adopt pm_ptr PM macros to fix build warnings.
Link to v3: https://lore.kernel.org/linux-usb/20251010201607.1190967-1-royluo at google.com

Changes in v3:
- Align binding file name with the compatible string
- Simplify the compatible property in binding to a single const value.
- Add descriptive comments and use item list in binding.
- Rename binding entries for clarity and brevity.
Link to v2: https://lore.kernel.org/linux-usb/20251008060000.3136021-1-royluo at google.com

Changes in v2:
- Reorder patches to present bindings first.
- Update dt binding compatible strings to be SoC-specific (google,gs5-*).
- Better describe the hardware in dt binding commit messages and
  descriptions.
- Adjust PHY driver commit subjects to use correct prefixes ("phy:").
- Move PHY driver from a subdirectory to drivers/phy/.
Link to v1: https://lore.kernel.org/linux-usb/20251006232125.1833979-1-royluo at google.com/

---
Roy Luo (2):
      dt-bindings: usb: dwc3: Add Google Tensor G5 DWC3
      usb: dwc3: Add Google Tensor SoC DWC3 glue driver

 .../devicetree/bindings/usb/google,lga-dwc3.yaml   | 140 +++++
 MAINTAINERS                                        |   2 +
 drivers/usb/dwc3/Kconfig                           |  11 +
 drivers/usb/dwc3/Makefile                          |   1 +
 drivers/usb/dwc3/dwc3-google.c                     | 628 +++++++++++++++++++++
 5 files changed, 782 insertions(+)
---
base-commit: ea1013c1539270e372fc99854bc6e4d94eaeff66
change-id: 20251122-controller-129b0dd57a74

Best regards,
-- 
Roy Luo <royluo at google.com>



From royluo at google.com  Thu Dec 18 11:23:10 2025
From: royluo at google.com (Roy Luo)
Date: Thu, 18 Dec 2025 19:23:10 +0000
Subject: [PATCH v10 1/2] dt-bindings: usb: dwc3: Add Google Tensor G5 DWC3
In-Reply-To: <20251218-controller-v10-0-4047c9077274@google.com>
References: <20251218-controller-v10-0-4047c9077274@google.com>
Message-ID: <20251218-controller-v10-1-4047c9077274@google.com>

Document the device tree bindings for the DWC3 USB controller found in
Google Tensor SoCs, starting with the G5 generation (codename: laguna).

The Tensor G5 silicon represents a complete architectural departure from
previous generations (like gs101), including entirely new clock/reset
schemes, top-level wrapper and register interface. Consequently,
existing Samsung/Exynos DWC3 USB bindings are incompatible, necessitating
this new device tree binding.

The USB controller on Tensor G5 is based on Synopsys DWC3 IP and features
Dual-Role Device single port with hibernation support.

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
Signed-off-by: Roy Luo <royluo at google.com>
---
 .../devicetree/bindings/usb/google,lga-dwc3.yaml   | 140 +++++++++++++++++++++
 MAINTAINERS                                        |   1 +
 2 files changed, 141 insertions(+)

diff --git a/Documentation/devicetree/bindings/usb/google,lga-dwc3.yaml b/Documentation/devicetree/bindings/usb/google,lga-dwc3.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..95be84c843f5da0e80ef5ef1ac9193019b5eb2a0
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/google,lga-dwc3.yaml
@@ -0,0 +1,140 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright (c) 2025, Google LLC
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/google,lga-dwc3.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Google Tensor Series G5 (Laguna) DWC3 USB SoC Controller
+
+maintainers:
+  - Roy Luo <royluo at google.com>
+
+description:
+  Describes the DWC3 USB controller block implemented on Google Tensor SoCs,
+  starting with the G5 generation (laguna). Based on Synopsys DWC3 IP, the
+  controller features Dual-Role Device single port with hibernation add-on.
+
+properties:
+  compatible:
+    const: google,lga-dwc3
+
+  reg:
+    items:
+      - description: Core DWC3 IP registers.
+
+  interrupts:
+    items:
+      - description: Core DWC3 interrupt.
+      - description: High speed power management event for remote wakeup.
+      - description: Super speed power management event for remote wakeup.
+
+  interrupt-names:
+    items:
+      - const: core
+      - const: hs_pme
+      - const: ss_pme
+
+  clocks:
+    items:
+      - description: Non-sticky module clock.
+      - description: Sticky module clock.
+
+  clock-names:
+    items:
+      - const: non_sticky
+      - const: sticky
+
+  resets:
+    items:
+      - description: Non-sticky module reset.
+      - description: Sticky module reset.
+      - description: DRD bus reset.
+      - description: Top-level reset.
+
+  reset-names:
+    items:
+      - const: non_sticky
+      - const: sticky
+      - const: drd_bus
+      - const: top
+
+  power-domains:
+    items:
+      - description: Power switchable domain, the child of top domain.
+          Turning it on puts the controller into full power state,
+          turning it off puts the controller into power gated state.
+      - description: Top domain, the parent of power switchable domain.
+          Turning it on puts the controller into power gated state,
+          turning it off completely shuts off the controller.
+
+  power-domain-names:
+    items:
+      - const: psw
+      - const: top
+
+  iommus:
+    maxItems: 1
+
+  google,usb-cfg-csr:
+    description:
+      A phandle to a syscon node used to access the USB configuration
+      registers. These registers are the top-level wrapper of the USB
+      subsystem and provide control and status for the integrated USB
+      controller and USB PHY.
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    items:
+      - items:
+          - description: phandle to the syscon node.
+          - description: USB host controller configuration register offset.
+          - description: USB custom interrrupts control register offset.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-names
+  - clocks
+  - clock-names
+  - resets
+  - reset-names
+  - power-domains
+  - power-domain-names
+  - google,usb-cfg-csr
+
+allOf:
+  - $ref: snps,dwc3-common.yaml#
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        usb at c400000 {
+            compatible = "google,lga-dwc3";
+            reg = <0 0x0c400000  0 0xd060>;
+            interrupts = <GIC_SPI 580 IRQ_TYPE_LEVEL_HIGH 0>,
+                         <GIC_SPI 597 IRQ_TYPE_LEVEL_HIGH 0>,
+                         <GIC_SPI 598 IRQ_TYPE_LEVEL_HIGH 0>;
+            interrupt-names = "core", "hs_pme", "ss_pme";
+            clocks = <&hsion_usbc_non_sticky_clk>,  <&hsion_usbc_sticky_clk>;
+            clock-names = "non_sticky", "sticky";
+            resets = <&hsion_resets_usbc_non_sticky>, <&hsion_resets_usbc_sticky>,
+                     <&hsion_resets_usb_drd_bus>, <&hsion_resets_usb_top>;
+            reset-names = "non_sticky", "sticky", "drd_bus", "top";
+            power-domains = <&hsio_n_usb_psw>, <&hsio_n_usb>;
+            power-domain-names = "psw", "top";
+            phys = <&usb_phy 0>;
+            phy-names = "usb2-phy";
+            snps,quirk-frame-length-adjustment = <0x20>;
+            snps,gfladj-refclk-lpm-sel-quirk;
+            snps,incr-burst-type-adjustment = <4>;
+            google,usb-cfg-csr = <&usb_cfg_csr 0x0 0x20>;
+        };
+    };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 5b11839cba9de1e9e43f63787578edd8c429ca39..5c8fbbb63c610d4d01ed4d78b1632774603eeaa4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10722,6 +10722,7 @@ P:	Documentation/process/maintainer-soc-clean-dts.rst
 C:	irc://irc.oftc.net/pixel6-kernel-dev
 F:	Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
 F:	Documentation/devicetree/bindings/soc/google/google,gs101-pmu-intr-gen.yaml
+F:	Documentation/devicetree/bindings/usb/google,lga-dwc3.yaml
 F:	arch/arm64/boot/dts/exynos/google/
 F:	drivers/clk/samsung/clk-gs101.c
 F:	drivers/soc/samsung/gs101-pmu.c

-- 
2.52.0.322.g1dd061c0dc-goog



From royluo at google.com  Thu Dec 18 11:23:11 2025
From: royluo at google.com (Roy Luo)
Date: Thu, 18 Dec 2025 19:23:11 +0000
Subject: [PATCH v10 2/2] usb: dwc3: Add Google Tensor SoC DWC3 glue driver
In-Reply-To: <20251218-controller-v10-0-4047c9077274@google.com>
References: <20251218-controller-v10-0-4047c9077274@google.com>
Message-ID: <20251218-controller-v10-2-4047c9077274@google.com>

Add support for the DWC3 USB controller found on Google Tensor G5
(codename: laguna). The controller features dual-role functionality
and hibernation.

The primary focus is implementing hibernation support in host mode,
enabling the controller to enter a low-power state (D3). This is
particularly relevant during system power state transition and
runtime power management for power efficiency.
Highlights:
- Align suspend callback with dwc3_suspend_common() for deciding
  between a full teardown and hibernation in host mode.
- Integration with `psw` (power switchable) and `top` power domains,
  managing their states and device links to support hibernation.
- A notifier callback dwc3_google_usb_psw_pd_notifier() for
  `psw` power domain events to manage controller state
  transitions to/from D3.
- Coordination of the `non_sticky` reset during power state
  transitions, asserting it on D3 entry and deasserting on D0 entry
  in hibernation scenario.
- Handling of high-speed and super-speed PME interrupts
  that are generated by remote wakeup during hibernation.

Co-developed-by: Joy Chakraborty <joychakr at google.com>
Signed-off-by: Joy Chakraborty <joychakr at google.com>
Co-developed-by: Naveen Kumar <mnkumar at google.com>
Signed-off-by: Naveen Kumar <mnkumar at google.com>
Reviewed-by: Peter Griffin <peter.griffin at linaro.org>
Signed-off-by: Roy Luo <royluo at google.com>
---
 MAINTAINERS                    |   1 +
 drivers/usb/dwc3/Kconfig       |  11 +
 drivers/usb/dwc3/Makefile      |   1 +
 drivers/usb/dwc3/dwc3-google.c | 628 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 641 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 5c8fbbb63c610d4d01ed4d78b1632774603eeaa4..96041a00e71d1b58a0c62161c268507f63d140a5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10727,6 +10727,7 @@ F:	arch/arm64/boot/dts/exynos/google/
 F:	drivers/clk/samsung/clk-gs101.c
 F:	drivers/soc/samsung/gs101-pmu.c
 F:	drivers/phy/samsung/phy-gs101-ufs.c
+F:	drivers/usb/dwc3/dwc3-google.c
 F:	include/dt-bindings/clock/google,gs101*
 K:	[gG]oogle.?[tT]ensor
 
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index bf3e04635131005096c6bc1802b251490ad2f483..240b15bc52cbd5d5c9d08d9fddd8c63202de1a3c 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -211,4 +211,15 @@ config USB_DWC3_APPLE
 	  mode on these machines.
 	  Say 'Y' or 'M' if you have such device.
 
+config USB_DWC3_GOOGLE
+	tristate "Google Platform"
+	help
+	  Support the DesignWare Core USB3 IP found on Google Tensor SoCs,
+	  starting with the G5 generation (Laguna). This driver includes
+	  support for hibernation in host mode.
+	  Say 'Y' or 'M' if you have one such device.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called dwc3-google.ko.
+
 endif
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index 89d46ab5006856c51b5007ecdd8fbdf431ecba40..073bef5309b5b5d381c8c4690221091b4df7904a 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -59,3 +59,4 @@ obj-$(CONFIG_USB_DWC3_XILINX)		+= dwc3-xilinx.o
 obj-$(CONFIG_USB_DWC3_OCTEON)		+= dwc3-octeon.o
 obj-$(CONFIG_USB_DWC3_RTK)		+= dwc3-rtk.o
 obj-$(CONFIG_USB_DWC3_GENERIC_PLAT)	+= dwc3-generic-plat.o
+obj-$(CONFIG_USB_DWC3_GOOGLE)		+= dwc3-google.o
diff --git a/drivers/usb/dwc3/dwc3-google.c b/drivers/usb/dwc3/dwc3-google.c
new file mode 100644
index 0000000000000000000000000000000000000000..a19857bd6b131d841d165717b70f2959b4bac806
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3-google.c
@@ -0,0 +1,628 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * dwc3-google.c - Google DWC3 Specific Glue Layer
+ *
+ * Copyright (c) 2025, Google LLC
+ * Author: Roy Luo <royluo at google.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include "core.h"
+#include "glue.h"
+
+/* HOST CFG registers */
+#define HC_STATUS_OFFSET 0x0
+#define HC_STATUS_CURRENT_POWER_STATE_U2PMU GENMASK(1, 0)
+#define HC_STATUS_CURRENT_POWER_STATE_U3PMU GENMASK(4, 3)
+
+#define HOST_CFG1_OFFSET 0x4
+#define HOST_CFG1_PME_EN BIT(3)
+#define HOST_CFG1_PM_POWER_STATE_REQUEST GENMASK(5, 4)
+#define HOST_CFG1_PM_POWER_STATE_D0 0x0
+#define HOST_CFG1_PM_POWER_STATE_D3 0x3
+
+/* USBINT registers */
+#define USBINT_CFG1_OFFSET 0x0
+#define USBINT_CFG1_USBDRD_PME_GEN_U2P_INTR_MSK BIT(2)
+#define USBINT_CFG1_USBDRD_PME_GEN_U3P_INTR_MSK BIT(3)
+#define USBINT_CFG1_USBDRD_PME_GEN_U2P_INTR_INT_EN BIT(8)
+#define USBINT_CFG1_USBDRD_PME_GEN_U3P_INTR_INT_EN BIT(9)
+#define USBINT_CFG1_USBDRD_PME_GEN_U2_INTR_CLR BIT(14)
+#define USBINT_CFG1_USBDRD_PME_GEN_U3_INTR_CLR BIT(15)
+
+#define USBINT_STATUS_OFFSET 0x4
+#define USBINT_STATUS_USBDRD_PME_GEN_U2P_INTR_STS_RAW BIT(2)
+#define USBINT_STATUS_USBDRD_PME_GEN_U3P_INTR_STS_RAW BIT(3)
+
+#define USBCS_TOP_CTRL_CFG1_OFFSET 0xc
+#define USBCS_TOP_CTRL_CFG1_USB2ONLY_MODE BIT(5)
+
+#define DWC3_GOOGLE_MAX_RESETS	4
+
+struct dwc3_google {
+	struct device		*dev;
+	struct dwc3		dwc;
+	struct clk_bulk_data	*clks;
+	int			num_clks;
+	struct reset_control_bulk_data rsts[DWC3_GOOGLE_MAX_RESETS];
+	int			num_rsts;
+	struct reset_control	*non_sticky_rst;
+	struct device		*usb_psw_pd;
+	struct device_link	*usb_psw_pd_dl;
+	struct notifier_block	usb_psw_pd_nb;
+	struct device		*usb_top_pd;
+	struct device_link	*usb_top_pd_dl;
+	struct regmap		*usb_cfg_regmap;
+	unsigned int		host_cfg_offset;
+	unsigned int		usbint_cfg_offset;
+	int			hs_pme_irq;
+	int			ss_pme_irq;
+	bool			is_usb2only;
+	bool			is_hibernation;
+};
+
+#define to_dwc3_google(d) container_of_const((d), struct dwc3_google, dwc)
+
+static int dwc3_google_rst_init(struct dwc3_google *google)
+{
+	int ret;
+
+	google->num_rsts = 4;
+	google->rsts[0].id = "non_sticky";
+	google->rsts[1].id = "sticky";
+	google->rsts[2].id = "drd_bus";
+	google->rsts[3].id = "top";
+
+	ret = devm_reset_control_bulk_get_exclusive(google->dev,
+						    google->num_rsts,
+						    google->rsts);
+
+	if (ret < 0)
+		return ret;
+
+	google->non_sticky_rst = google->rsts[0].rstc;
+
+	return 0;
+}
+
+static int dwc3_google_set_pmu_state(struct dwc3_google *google, int state)
+{
+	u32 reg;
+	int ret;
+
+	regmap_read(google->usb_cfg_regmap,
+		    google->host_cfg_offset + HOST_CFG1_OFFSET, &reg);
+
+	reg &= ~HOST_CFG1_PM_POWER_STATE_REQUEST;
+	reg |= (FIELD_PREP(HOST_CFG1_PM_POWER_STATE_REQUEST, state) |
+		HOST_CFG1_PME_EN);
+	regmap_write(google->usb_cfg_regmap,
+		     google->host_cfg_offset + HOST_CFG1_OFFSET, reg);
+
+	ret = regmap_read_poll_timeout(google->usb_cfg_regmap,
+				       google->host_cfg_offset + HC_STATUS_OFFSET, reg,
+				       (FIELD_GET(HC_STATUS_CURRENT_POWER_STATE_U2PMU,
+						  reg) == state &&
+					FIELD_GET(HC_STATUS_CURRENT_POWER_STATE_U3PMU,
+						  reg) == state),
+				       10, 10000);
+
+	if (ret)
+		dev_err(google->dev, "failed to set PMU state %d\n", state);
+
+	return ret;
+}
+
+/*
+ * Clear pme interrupts and report their status.
+ * The hardware requires write-1 then write-0 sequence to clear the interrupt bits.
+ */
+static u32 dwc3_google_clear_pme_irqs(struct dwc3_google *google)
+{
+	u32 irq_status, reg_set, reg_clear;
+
+	regmap_read(google->usb_cfg_regmap,
+		    google->usbint_cfg_offset + USBINT_STATUS_OFFSET, &irq_status);
+
+	irq_status &= (USBINT_STATUS_USBDRD_PME_GEN_U2P_INTR_STS_RAW |
+		       USBINT_STATUS_USBDRD_PME_GEN_U3P_INTR_STS_RAW);
+	if (!irq_status)
+		return irq_status;
+
+	regmap_read(google->usb_cfg_regmap,
+		    google->usbint_cfg_offset + USBINT_CFG1_OFFSET, &reg_set);
+
+	reg_clear = reg_set;
+	if (irq_status & USBINT_STATUS_USBDRD_PME_GEN_U2P_INTR_STS_RAW) {
+		reg_set |= USBINT_CFG1_USBDRD_PME_GEN_U2_INTR_CLR;
+		reg_clear &= ~USBINT_CFG1_USBDRD_PME_GEN_U2_INTR_CLR;
+	}
+	if (irq_status & USBINT_STATUS_USBDRD_PME_GEN_U3P_INTR_STS_RAW) {
+		reg_set |= USBINT_CFG1_USBDRD_PME_GEN_U3_INTR_CLR;
+		reg_clear &= ~USBINT_CFG1_USBDRD_PME_GEN_U3_INTR_CLR;
+	}
+
+	regmap_write(google->usb_cfg_regmap,
+		     google->usbint_cfg_offset + USBINT_CFG1_OFFSET, reg_set);
+	regmap_write(google->usb_cfg_regmap,
+		     google->usbint_cfg_offset + USBINT_CFG1_OFFSET, reg_clear);
+
+	return irq_status;
+}
+
+static void dwc3_google_enable_pme_irq(struct dwc3_google *google)
+{
+	u32 reg;
+
+	regmap_read(google->usb_cfg_regmap,
+		    google->usbint_cfg_offset + USBINT_CFG1_OFFSET, &reg);
+	reg &= ~(USBINT_CFG1_USBDRD_PME_GEN_U2P_INTR_MSK |
+		 USBINT_CFG1_USBDRD_PME_GEN_U3P_INTR_MSK);
+	reg |= (USBINT_CFG1_USBDRD_PME_GEN_U2P_INTR_INT_EN |
+		USBINT_CFG1_USBDRD_PME_GEN_U3P_INTR_INT_EN);
+	regmap_write(google->usb_cfg_regmap,
+		     google->usbint_cfg_offset + USBINT_CFG1_OFFSET, reg);
+
+	enable_irq(google->hs_pme_irq);
+	enable_irq(google->ss_pme_irq);
+	enable_irq_wake(google->hs_pme_irq);
+	enable_irq_wake(google->ss_pme_irq);
+}
+
+static void dwc3_google_disable_pme_irq(struct dwc3_google *google)
+{
+	u32 reg;
+
+	regmap_read(google->usb_cfg_regmap,
+		    google->usbint_cfg_offset + USBINT_CFG1_OFFSET, &reg);
+	reg &= ~(USBINT_CFG1_USBDRD_PME_GEN_U2P_INTR_INT_EN |
+		 USBINT_CFG1_USBDRD_PME_GEN_U3P_INTR_INT_EN);
+	reg |= (USBINT_CFG1_USBDRD_PME_GEN_U2P_INTR_MSK |
+		USBINT_CFG1_USBDRD_PME_GEN_U3P_INTR_MSK);
+	regmap_write(google->usb_cfg_regmap,
+		     google->usbint_cfg_offset + USBINT_CFG1_OFFSET, reg);
+
+	disable_irq_wake(google->hs_pme_irq);
+	disable_irq_wake(google->ss_pme_irq);
+	disable_irq_nosync(google->hs_pme_irq);
+	disable_irq_nosync(google->ss_pme_irq);
+}
+
+static irqreturn_t dwc3_google_resume_irq(int irq, void *data)
+{
+	struct dwc3_google      *google = data;
+	struct dwc3             *dwc = &google->dwc;
+	u32 irq_status, dr_role;
+
+	irq_status = dwc3_google_clear_pme_irqs(google);
+	dr_role = dwc->current_dr_role;
+
+	if (!irq_status || !google->is_hibernation ||
+	    dr_role != DWC3_GCTL_PRTCAP_HOST) {
+		dev_dbg(google->dev, "spurious pme irq %d, hibernation %d, dr_role %u\n",
+			irq, google->is_hibernation, dr_role);
+		return IRQ_HANDLED;
+	}
+
+	if (dwc->xhci)
+		pm_runtime_resume(&dwc->xhci->dev);
+
+	return IRQ_HANDLED;
+}
+
+static int dwc3_google_request_irq(struct dwc3_google *google, struct platform_device *pdev,
+				   const char *irq_name, const char *req_name)
+{
+	int ret;
+	int irq;
+
+	irq = platform_get_irq_byname(pdev, irq_name);
+	if (irq < 0) {
+		dev_err(google->dev, "invalid irq name %s\n", irq_name);
+		return irq;
+	}
+
+	irq_set_status_flags(irq, IRQ_NOAUTOEN);
+	ret = devm_request_threaded_irq(google->dev, irq, NULL,
+					dwc3_google_resume_irq,
+					IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+					req_name, google);
+	if (ret < 0) {
+		dev_err(google->dev, "failed to request irq %s\n", req_name);
+		return ret;
+	}
+
+	return irq;
+}
+
+static int dwc3_google_usb_psw_pd_notifier(struct notifier_block *nb, unsigned long action, void *d)
+{
+	struct dwc3_google *google = container_of(nb, struct dwc3_google, usb_psw_pd_nb);
+	int ret;
+
+	if (!google->is_hibernation)
+		return NOTIFY_OK;
+
+	if (action == GENPD_NOTIFY_OFF) {
+		dev_dbg(google->dev, "enter D3 power state\n");
+		dwc3_google_set_pmu_state(google, HOST_CFG1_PM_POWER_STATE_D3);
+		ret = reset_control_assert(google->non_sticky_rst);
+		if (ret)
+			dev_err(google->dev, "non sticky reset assert failed: %d\n", ret);
+	} else if (action == GENPD_NOTIFY_ON) {
+		dev_dbg(google->dev, "enter D0 power state\n");
+		dwc3_google_clear_pme_irqs(google);
+		ret = reset_control_deassert(google->non_sticky_rst);
+		if (ret)
+			dev_err(google->dev, "non sticky reset deassert failed: %d\n", ret);
+		dwc3_google_set_pmu_state(google, HOST_CFG1_PM_POWER_STATE_D0);
+	}
+
+	return NOTIFY_OK;
+}
+
+static void dwc3_google_pm_domain_deinit(struct dwc3_google *google)
+{
+	if (google->usb_top_pd_dl)
+		device_link_del(google->usb_top_pd_dl);
+
+	if (!IS_ERR_OR_NULL(google->usb_top_pd)) {
+		device_set_wakeup_capable(google->usb_top_pd, false);
+		dev_pm_domain_detach(google->usb_top_pd, true);
+	}
+
+	if (google->usb_psw_pd_dl)
+		device_link_del(google->usb_psw_pd_dl);
+
+	if (!IS_ERR_OR_NULL(google->usb_psw_pd)) {
+		dev_pm_genpd_remove_notifier(google->usb_psw_pd);
+		dev_pm_domain_detach(google->usb_psw_pd, true);
+	}
+}
+
+static int dwc3_google_pm_domain_init(struct dwc3_google *google)
+{
+	int ret;
+
+	/*
+	 * Establish PM RUNTIME link between dwc dev and its power domain usb_psw_pd,
+	 * register notifier block to handle hibernation.
+	 */
+	google->usb_psw_pd = dev_pm_domain_attach_by_name(google->dev, "psw");
+	if (IS_ERR_OR_NULL(google->usb_psw_pd)) {
+		dev_err(google->dev, "failed to get psw pd");
+		ret = google->usb_psw_pd ? PTR_ERR(google->usb_psw_pd) : -ENODATA;
+		return ret;
+	}
+
+	google->usb_psw_pd_nb.notifier_call = dwc3_google_usb_psw_pd_notifier;
+	ret = dev_pm_genpd_add_notifier(google->usb_psw_pd, &google->usb_psw_pd_nb);
+	if (ret) {
+		dev_err(google->dev, "failed to add psw pd notifier");
+		goto err;
+	}
+
+	google->usb_psw_pd_dl = device_link_add(google->dev, google->usb_psw_pd,
+						DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME |
+						DL_FLAG_RPM_ACTIVE);
+	if (!google->usb_psw_pd_dl) {
+		dev_err(google->usb_psw_pd, "failed to add device link");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	/*
+	 * usb_top_pd is the parent power domain of usb_psw_pd. Keeping usb_top_pd on
+	 * while usb_psw_pd is off places the controller in a power-gated state,
+	 * essential for hibernation. Acquire a handle to usb_top_pd and sets it as
+	 * wakeup-capable to allow the domain to be left on during system suspend.
+	 */
+	google->usb_top_pd = dev_pm_domain_attach_by_name(google->dev, "top");
+	if (IS_ERR_OR_NULL(google->usb_top_pd)) {
+		dev_err(google->dev, "failed to get top pd");
+		ret = google->usb_top_pd ? PTR_ERR(google->usb_top_pd) : -ENODATA;
+		goto err;
+	}
+	device_set_wakeup_capable(google->usb_top_pd, true);
+
+	google->usb_top_pd_dl = device_link_add(google->dev, google->usb_top_pd,
+						DL_FLAG_STATELESS);
+	if (!google->usb_top_pd_dl) {
+		dev_err(google->usb_top_pd, "failed to add device link");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	return 0;
+
+err:
+	dwc3_google_pm_domain_deinit(google);
+
+	return ret;
+}
+
+static void dwc3_google_program_usb2only(struct dwc3_google *google)
+{
+	u32 reg;
+
+	regmap_read(google->usb_cfg_regmap,
+		    google->usbint_cfg_offset + USBCS_TOP_CTRL_CFG1_OFFSET, &reg);
+	reg |= USBCS_TOP_CTRL_CFG1_USB2ONLY_MODE;
+	regmap_write(google->usb_cfg_regmap,
+		     google->usbint_cfg_offset + USBCS_TOP_CTRL_CFG1_OFFSET, reg);
+}
+
+static int dwc3_google_probe(struct platform_device *pdev)
+{
+	struct dwc3_probe_data	probe_data = {};
+	struct device		*dev = &pdev->dev;
+	struct dwc3_google	*google;
+	struct resource		*res;
+	int			ret;
+	u32			args[2];
+
+	google = devm_kzalloc(&pdev->dev, sizeof(*google), GFP_KERNEL);
+	if (!google)
+		return -ENOMEM;
+
+	google->dev = &pdev->dev;
+
+	ret = dwc3_google_pm_domain_init(google);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "failed to init pdom\n");
+
+	google->usb_cfg_regmap =
+		syscon_regmap_lookup_by_phandle_args(dev->of_node,
+						     "google,usb-cfg-csr",
+						     ARRAY_SIZE(args), args);
+	if (IS_ERR(google->usb_cfg_regmap)) {
+		return dev_err_probe(dev, PTR_ERR(google->usb_cfg_regmap),
+				     "invalid usb cfg csr\n");
+	}
+
+	google->host_cfg_offset = args[0];
+	google->usbint_cfg_offset = args[1];
+
+	if (device_property_match_string(dev, "phy-names", "usb3-phy") < 0) {
+		google->is_usb2only = true;
+		dwc3_google_program_usb2only(google);
+	}
+
+	ret = devm_clk_bulk_get_all_enabled(dev, &google->clks);
+	if (ret < 0) {
+		ret = dev_err_probe(dev, ret, "failed to get and enable clks\n");
+		goto err_deinit_pdom;
+	}
+	google->num_clks = ret;
+
+	ret = dwc3_google_rst_init(google);
+	if (ret) {
+		ret = dev_err_probe(dev, ret, "failed to get resets\n");
+		goto err_deinit_pdom;
+	}
+
+	ret = reset_control_bulk_deassert(google->num_rsts, google->rsts);
+	if (ret) {
+		ret = dev_err_probe(dev, ret, "failed to deassert rsts\n");
+		goto err_deinit_pdom;
+	}
+
+	ret = dwc3_google_request_irq(google, pdev, "hs_pme", "USB HS wakeup");
+	if (ret < 0) {
+		ret = dev_err_probe(dev, ret, "failed to request hs pme irq");
+		goto err_reset_assert;
+	}
+	google->hs_pme_irq = ret;
+
+	ret = dwc3_google_request_irq(google, pdev, "ss_pme", "USB SS wakeup");
+	if (ret < 0) {
+		ret = dev_err_probe(dev, ret, "failed to request ss pme irq");
+		goto err_reset_assert;
+	}
+	google->ss_pme_irq = ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = dev_err_probe(dev, -ENODEV, "invalid memory\n");
+		goto err_reset_assert;
+	}
+
+	device_init_wakeup(dev, true);
+
+	google->dwc.dev = dev;
+	probe_data.dwc = &google->dwc;
+	probe_data.res = res;
+	probe_data.ignore_clocks_and_resets = true;
+	ret = dwc3_core_probe(&probe_data);
+	if (ret)  {
+		ret = dev_err_probe(dev, ret, "failed to register DWC3 Core\n");
+		goto err_reset_assert;
+	}
+
+	return 0;
+
+err_reset_assert:
+	reset_control_bulk_assert(google->num_rsts, google->rsts);
+
+err_deinit_pdom:
+	dwc3_google_pm_domain_deinit(google);
+
+	return ret;
+}
+
+static void dwc3_google_remove(struct platform_device *pdev)
+{
+	struct dwc3 *dwc = platform_get_drvdata(pdev);
+	struct dwc3_google *google = to_dwc3_google(dwc);
+
+	dwc3_core_remove(&google->dwc);
+
+	reset_control_bulk_assert(google->num_rsts, google->rsts);
+
+	dwc3_google_pm_domain_deinit(google);
+}
+
+static int dwc3_google_suspend(struct dwc3_google *google, pm_message_t msg)
+{
+	if (pm_runtime_suspended(google->dev))
+		return 0;
+
+	if (google->dwc.current_dr_role == DWC3_GCTL_PRTCAP_HOST) {
+		/*
+		 * Follow dwc3_suspend_common() guidelines for deciding between
+		 * a full teardown and hibernation.
+		 */
+		if (PMSG_IS_AUTO(msg) || device_may_wakeup(google->dev)) {
+			dev_dbg(google->dev, "enter hibernation");
+			pm_runtime_get_sync(google->usb_top_pd);
+			device_wakeup_enable(google->usb_top_pd);
+			dwc3_google_enable_pme_irq(google);
+			google->is_hibernation = true;
+			return 0;
+		}
+	}
+
+	reset_control_bulk_assert(google->num_rsts, google->rsts);
+	clk_bulk_disable_unprepare(google->num_clks, google->clks);
+
+	return 0;
+}
+
+static int dwc3_google_resume(struct dwc3_google *google, pm_message_t msg)
+{
+	int ret;
+
+	if (google->is_hibernation) {
+		dev_dbg(google->dev, "exit hibernation");
+		dwc3_google_disable_pme_irq(google);
+		device_wakeup_disable(google->usb_top_pd);
+		pm_runtime_put_sync(google->usb_top_pd);
+		google->is_hibernation = false;
+		return 0;
+	}
+
+	if (google->is_usb2only)
+		dwc3_google_program_usb2only(google);
+
+	ret = clk_bulk_prepare_enable(google->num_clks, google->clks);
+	if (ret)
+		return ret;
+
+	ret = reset_control_bulk_deassert(google->num_rsts, google->rsts);
+	if (ret) {
+		clk_bulk_disable_unprepare(google->num_clks, google->clks);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int dwc3_google_pm_suspend(struct device *dev)
+{
+	struct dwc3 *dwc = dev_get_drvdata(dev);
+	struct dwc3_google *google = to_dwc3_google(dwc);
+	int ret;
+
+	ret = dwc3_pm_suspend(&google->dwc);
+	if (ret)
+		return ret;
+
+	return dwc3_google_suspend(google, PMSG_SUSPEND);
+}
+
+static int dwc3_google_pm_resume(struct device *dev)
+{
+	struct dwc3 *dwc = dev_get_drvdata(dev);
+	struct dwc3_google *google = to_dwc3_google(dwc);
+	int ret;
+
+	ret = dwc3_google_resume(google, PMSG_RESUME);
+	if (ret)
+		return ret;
+
+	return dwc3_pm_resume(&google->dwc);
+}
+
+static void dwc3_google_complete(struct device *dev)
+{
+	struct dwc3 *dwc = dev_get_drvdata(dev);
+
+	dwc3_pm_complete(dwc);
+}
+
+static int dwc3_google_prepare(struct device *dev)
+{
+	struct dwc3 *dwc = dev_get_drvdata(dev);
+
+	return dwc3_pm_prepare(dwc);
+}
+
+static int dwc3_google_runtime_suspend(struct device *dev)
+{
+	struct dwc3 *dwc = dev_get_drvdata(dev);
+	struct dwc3_google *google = to_dwc3_google(dwc);
+	int ret;
+
+	ret = dwc3_runtime_suspend(&google->dwc);
+	if (ret)
+		return ret;
+
+	return dwc3_google_suspend(google, PMSG_AUTO_SUSPEND);
+}
+
+static int dwc3_google_runtime_resume(struct device *dev)
+{
+	struct dwc3 *dwc = dev_get_drvdata(dev);
+	struct dwc3_google *google = to_dwc3_google(dwc);
+	int ret;
+
+	ret = dwc3_google_resume(google, PMSG_AUTO_RESUME);
+	if (ret)
+		return ret;
+
+	return dwc3_runtime_resume(&google->dwc);
+}
+
+static int dwc3_google_runtime_idle(struct device *dev)
+{
+	return dwc3_runtime_idle(dev_get_drvdata(dev));
+}
+
+static const struct dev_pm_ops dwc3_google_dev_pm_ops = {
+	SYSTEM_SLEEP_PM_OPS(dwc3_google_pm_suspend, dwc3_google_pm_resume)
+	RUNTIME_PM_OPS(dwc3_google_runtime_suspend, dwc3_google_runtime_resume,
+		       dwc3_google_runtime_idle)
+	.complete = pm_sleep_ptr(dwc3_google_complete),
+	.prepare = pm_sleep_ptr(dwc3_google_prepare),
+};
+
+static const struct of_device_id dwc3_google_of_match[] = {
+	{ .compatible = "google,lga-dwc3" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, dwc3_google_of_match);
+
+static struct platform_driver dwc3_google_driver = {
+	.probe		= dwc3_google_probe,
+	.remove		= dwc3_google_remove,
+	.driver		= {
+		.name	= "dwc3-google",
+		.pm	= pm_ptr(&dwc3_google_dev_pm_ops),
+		.of_match_table	= dwc3_google_of_match,
+	},
+};
+
+module_platform_driver(dwc3_google_driver);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DesignWare DWC3 Google Glue Driver");

-- 
2.52.0.322.g1dd061c0dc-goog



From ebiggers at kernel.org  Thu Dec 18 11:25:34 2025
From: ebiggers at kernel.org (Eric Biggers)
Date: Thu, 18 Dec 2025 11:25:34 -0800
Subject: [PATCH 00/12] NH library and Adiantum cleanup
In-Reply-To: <20251211011846.8179-1-ebiggers@kernel.org>
References: <20251211011846.8179-1-ebiggers@kernel.org>
Message-ID: <20251218192534.GD21380@sol>

On Wed, Dec 10, 2025 at 05:18:32PM -0800, Eric Biggers wrote:
> This series can also be retrieved from:
> 
>     git fetch https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git nh-lib-v1
> 
> This series removes the nhpoly1305 crypto_shash algorithm, which existed
> only to fit Adiantum hashing into the traditional Linux crypto API
> paradigm.  It replaces it with an nh() library function, combined with
> code in the "adiantum" template that handles the Poly1305 step.
> 
> The result is simpler code.  As usual, I've also fixed the issue where
> the architecture-optimized code was disabled by default.
> 
> I've also included some additional cleanups for the Adiantum code.
> 
> I'm planning to take this via libcrypto-next.
> 
> Eric Biggers (12):
>   lib/crypto: nh: Add NH library
>   lib/crypto: tests: Add KUnit tests for NH
>   lib/crypto: arm/nh: Migrate optimized code into library
>   lib/crypto: arm64/nh: Migrate optimized code into library
>   lib/crypto: x86/nh: Migrate optimized code into library
>   crypto: adiantum - Convert to use NH library
>   crypto: adiantum - Use scatter_walk API instead of sg_miter
>   crypto: adiantum - Use memcpy_{to,from}_sglist()
>   crypto: adiantum - Drop support for asynchronous xchacha ciphers
>   crypto: nhpoly1305 - Remove crypto_shash support
>   crypto: testmgr - Remove nhpoly1305 tests
>   fscrypt: Drop obsolete recommendation to enable optimized NHPoly1305

Applied to https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git/log/?h=libcrypto-next

More reviews and acks would be appreciated!

- Eric


From conor at kernel.org  Thu Dec 18 11:25:52 2025
From: conor at kernel.org (Conor Dooley)
Date: Thu, 18 Dec 2025 19:25:52 +0000
Subject: [PATCH v4 01/25] dt-bindings: phy: Add mediatek,mt8196-ufsphy
 variant
In-Reply-To: <20251218-mt8196-ufs-v4-1-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
 <20251218-mt8196-ufs-v4-1-ddec7a369dd2@collabora.com>
Message-ID: <20251218-spur-uncover-04320ae6df16@spud>

Acked-by: Conor Dooley <conor.dooley at microchip.com>
pw-bot: not-applicable
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251218/080d3e69/attachment.sig>

From conor at kernel.org  Thu Dec 18 11:26:26 2025
From: conor at kernel.org (Conor Dooley)
Date: Thu, 18 Dec 2025 19:26:26 +0000
Subject: [PATCH v4 03/25] dt-bindings: ufs: mediatek,ufs: Add mt8196
 variant
In-Reply-To: <20251218-mt8196-ufs-v4-3-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
 <20251218-mt8196-ufs-v4-3-ddec7a369dd2@collabora.com>
Message-ID: <20251218-crib-mutilated-0fad21809466@spud>

On Thu, Dec 18, 2025 at 01:54:53PM +0100, Nicolas Frattaroli wrote:
> The MediaTek MT8196 SoC's UFS controller uses three additional clocks
> compared to the MT8195, and a different set of supplies. It is therefore
> not compatible with the MT8195.
> 
> While it does have a AVDD09_UFS_1 pin in addition to the AVDD09_UFS pin,
> it appears that these two pins are commoned together, as the board
> schematic I have access to uses the same supply for both, and the
> downstream driver does not distinguish between the two supplies either.
> 
> Add a compatible for it, and modify the binding correspondingly.
> 
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>

Acked-by: Conor Dooley <conor.dooley at microchip.com>
pw-bot: not-applicable
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251218/7c7196d6/attachment.sig>

From krzk at kernel.org  Thu Dec 18 11:26:35 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 18 Dec 2025 20:26:35 +0100
Subject: [PATCH v7 1/3] dt-bindings: soc: imx93-media-blk-ctrl: Add PDFC
 subnode to schema and example
In-Reply-To: <20251215161706.2ea3wtu3xlwcxxar@pengutronix.de>
References: <20251202-v6-18-topic-imx93-parallel-display-v7-0-2cce31d64608@pengutronix.de>
 <20251202-v6-18-topic-imx93-parallel-display-v7-1-2cce31d64608@pengutronix.de>
 <705773fc-5aba-4bff-b05e-272e1cd0262c@nxp.com>
 <20251215161706.2ea3wtu3xlwcxxar@pengutronix.de>
Message-ID: <7127040f-55ab-4bfa-8795-1df76085470c@kernel.org>

On 15/12/2025 17:17, Marco Felsch wrote:
> Hi Liu,
> 
> On 25-12-08, Liu Ying wrote:
>> Hi Marco,
>>
>> On 12/02/2025, Marco Felsch wrote:
>>> From: Liu Ying <victor.liu at nxp.com>
>>>
>>> i.MX93 SoC mediamix blk-ctrl contains one DISPLAY_MUX register which
>>> configures parallel display format by using the "PARALLEL_DISP_FORMAT"
>>> field. Document the Parallel Display Format Configuration(PDFC) subnode
>>> and add the subnode to example.
>>>
>>> Signed-off-by: Liu Ying <victor.liu at nxp.com>
>>> [m.felsch at pengutronix.de: port to v6.18-rc1]
>>> [m.felsch at pengutronix.de: add bus-width]
>>> Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
>>> ---
>>>  .../bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml | 92 ++++++++++++++++++++++
>>>  1 file changed, 92 insertions(+)
>>>
>>> diff --git a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
>>> index 34aea58094e55365a2f9c86092f637e533f954ff..6e2d86d9341c75108b492bcbabc8a560d8e707cd 100644
>>> --- a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
>>> +++ b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
>>> @@ -26,6 +26,12 @@ properties:
>>>    reg:
>>>      maxItems: 1
>>>  
>>> +  '#address-cells':
>>> +    const: 1
>>> +
>>> +  '#size-cells':
>>> +    const: 1
>>> +
>>>    '#power-domain-cells':
>>>      const: 1
>>>  
>>> @@ -40,6 +46,60 @@ properties:
>>>      minItems: 8
>>>      maxItems: 10
>>>  
>>> +  bridge at 60:
>>
>> The dependency patch series mentioned in cover letter has two links in it's
>> cover letter.  Reading the patch sets pointed by the two links, we may find
>> Krzysztof's comments - the child nodes of the blk-ctrl should be completely
>> documented.
> 
> Thanks for pointing this out.
> 
> @Krzysztof
> Requesting to add everything seems not feasible if everything added
> should be tested too.
> I don't see why everything should be added in one step, since the base
> .dtsi isn't added in one step too.

Because otherwise we do not see entire picture and people post incorrect
bindings, claiming they are complete picture, like messing nodes with
addressing and nodes without. So sure, if you do not want to post
complete picture, we cannot review that complete picture, therefore YOU
MUST POST CORRECT CODE.

I will not be taking excuses later "we did not know that such code is
not allowed". You must know all rules.


Best regards,
Krzysztof


From krzk at kernel.org  Thu Dec 18 11:31:31 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 18 Dec 2025 20:31:31 +0100
Subject: [PATCH v6 1/2] dt-bindings: arm: aspeed: add ASRock Rack ALTRAD8
 board
In-Reply-To: <4eff8506-8049-46e9-997e-a41edff32bbc@bsdio.com>
References: <20251218161816.38155-1-rebecca@bsdio.com>
 <20251218161816.38155-2-rebecca@bsdio.com>
 <5aa36c56-798a-40cc-b0b8-be3f7c92136f@kernel.org>
 <4eff8506-8049-46e9-997e-a41edff32bbc@bsdio.com>
Message-ID: <d215c5dd-b402-4cd2-b4c6-48358b5b2491@kernel.org>

On 18/12/2025 19:34, Rebecca Cran wrote:
> On 12/18/25 09:21, Krzysztof Kozlowski wrote:
>> On 18/12/2025 17:18, Rebecca Cran wrote:
>>> Document ASRock Rack ALTRAD8 (ALTRAD8UD-1L2T and ALTRAD8UD2-1L2Q)
>>> compatibles.
>>>
>>> Signed-off-by: Rebecca Cran <rebecca at bsdio.com>
>>> Acked-by: Conor Dooley <conor.dooley at microchip.com>
>>> Tested-by: Tan Siewert <tan.siewert at hetzner.com>
>> How was the binding tested?
> 
> I ran "make ARCH=arm CHECK_DTBS=y aspeed/aspeed-bmc-asrock-altrad8.dtb"
> to check for errors

That's a build check for DTS, not binding. I compiled this code - so it
is also Tested-by?

> 
> and have used the dts file in an ASRock Rack ALTRAD8UD-1L2T system with
> Linux 6.12.61 running OpenBMC.

This does not test anything from the binding.

Please don't add fake tests... Building instructions are not testing.

Best regards,
Krzysztof


From krzk at kernel.org  Thu Dec 18 11:32:37 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 18 Dec 2025 20:32:37 +0100
Subject: [PATCH v6 1/2] dt-bindings: arm: aspeed: add ASRock Rack ALTRAD8
 board
In-Reply-To: <b10a233e-02c3-4b02-8f11-098f6fb8197c@hetzner.com>
References: <20251218161816.38155-1-rebecca@bsdio.com>
 <20251218161816.38155-2-rebecca@bsdio.com>
 <5aa36c56-798a-40cc-b0b8-be3f7c92136f@kernel.org>
 <b10a233e-02c3-4b02-8f11-098f6fb8197c@hetzner.com>
Message-ID: <4ca60f87-39dd-44d1-bce5-c6071f226210@kernel.org>

On 18/12/2025 17:44, Tan Siewert wrote:
> On 18.12.25 17:21, Krzysztof Kozlowski wrote:
>> On 18/12/2025 17:18, Rebecca Cran wrote:
>>> Document ASRock Rack ALTRAD8 (ALTRAD8UD-1L2T and ALTRAD8UD2-1L2Q)
>>> compatibles.
>>>
>>> Signed-off-by: Rebecca Cran <rebecca at bsdio.com>
>>> Acked-by: Conor Dooley <conor.dooley at microchip.com>
>>> Tested-by: Tan Siewert <tan.siewert at hetzner.com>
>>
>> How was the binding tested?
> 
> My bad for sending the wrong trailing header in v4. Tested-by should've 
> been only on the dts instead of the dt-bindings+dts. Either way, `make 
> dt_binding_check` was what I did to check if there are any errors 
> produced for `asrock,altrad8-bmc`.

Yeah, that's not testing. It's a build command and running build process
is not a test. Otherwise why there is no Tested-by for Rob...

Best regards,
Krzysztof


From conor at kernel.org  Thu Dec 18 11:38:31 2025
From: conor at kernel.org (Conor Dooley)
Date: Thu, 18 Dec 2025 19:38:31 +0000
Subject: [PATCH v4 02/25] dt-bindings: ufs: mediatek,ufs: Complete the
 binding
In-Reply-To: <20251218-mt8196-ufs-v4-2-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
 <20251218-mt8196-ufs-v4-2-ddec7a369dd2@collabora.com>
Message-ID: <20251218-vineyard-exalted-08fe7d9bcb55@spud>

On Thu, Dec 18, 2025 at 01:54:52PM +0100, Nicolas Frattaroli wrote:
> As it stands, the mediatek,ufs.yaml binding is startlingly incomplete.
> Its one example, which is the only real "user" of this binding in
> mainline, uses the deprecated freq-table-hz property.
> 
> The resets, of which there are three optional ones, are completely
> absent.
> 
> The clock description for MT8195 is incomplete, as is the one for
> MT8192. It's not known if the one clock binding for MT8183 is even
> correct, but I do not have access to the necessary code and
> documentation to find this out myself.
> 
> The power supply situation is not much better; the binding describes one
> required power supply, but it's the UFS card supply, not any of the
> supplies feeding the controller silicon.
> 
> No second example is present in the binding, making verification
> difficult.
> 
> Disallow freq-table-hz and move to operating-points-v2. It's fine to
> break compatibility here, as the binding is currently unused and would
> be impossible to correctly use in its current state.
> 
> Add the three resets and the corresponding reset-names property. These
> resets appear to be optional, i.e. not required for the functioning of
> the device.
> 
> Move the list of clock names out of the if condition, and expand it for
> the confirmed clocks I could find by cross-referencing several clock
> drivers. For MT8195, increase the minimum number of clocks to include
> the crypt and rx_symbol ones, as they're internal to the SoC and should
> always be present, and should therefore not be omitted.
> 
> MT8192 gets to have at least 3 clocks, as these were the ones I could
> quickly confirm from a glance at various trees. I can't say this was an
> exhaustive search though, but it's better than the current situation.
> 
> Properly document all supplies, with which pin name on the SoCs they
> supply. Complete the example with them.
> 
> Also add a MT8195 example to the binding, using supply labels that I am
> pretty sure would be the right ones for e.g. the Radxa NIO 12L.
> 
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>

Reviewed-by: Conor Dooley <conor.dooley at microchip.com>
pw-bot: not-applicable
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251218/4b8901d9/attachment.sig>

From yeoreum.yun at arm.com  Thu Dec 18 11:47:49 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Thu, 18 Dec 2025 19:47:49 +0000
Subject: [PATCH v3 1/2] arm64: mmu: avoid allocating pages while splitting the linear mapping
In-Reply-To: <20251218194750.395301-1-yeoreum.yun@arm.com>
References: <20251218194750.395301-1-yeoreum.yun@arm.com>
Message-ID: <20251218194750.395301-2-yeoreum.yun@arm.com>

linear_map_split_to_ptes() currently allocates page tables while
splitting the linear mapping into PTEs under stop_machine() using GFP_ATOMIC.

This is fine for non-PREEMPT_RT configurations.
However, it becomes problematic on PREEMPT_RT, because
generic memory allocation/free APIs (e.g. pgtable_alloc(), __get_free_pages(), etc.)
cannot be called from a non-preemptible context, except for the _nolock() variants.
This is because generic memory allocation/free paths are sleepable,
as they rely on spin_lock(), which becomes sleepable on PREEMPT_RT.

In other words, even calling pgtable_alloc() with GFP_ATOMIC is not permitted
in __linear_map_split_to_pte() when it is executed by the stopper thread,
 where preemption is disabled on PREEMPT_RT.

To address this, the required number of page tables is first collected
and preallocated, and the preallocated page tables are then used
when splitting the linear mapping in __linear_map_split_to_pte().

Fixes: 3df6979d222b ("arm64: mm: split linear mapping if BBML2 unsupported on secondary CPUs")
Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
---
 arch/arm64/mm/mmu.c | 232 +++++++++++++++++++++++++++++++++++---------
 1 file changed, 184 insertions(+), 48 deletions(-)

diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 9ae7ce00a7ef..96a9fa505e71 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -527,18 +527,15 @@ static void early_create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys,
 		panic("Failed to create page tables\n");
 }
 
-static phys_addr_t __pgd_pgtable_alloc(struct mm_struct *mm, gfp_t gfp,
-				       enum pgtable_type pgtable_type)
-{
-	/* Page is zeroed by init_clear_pgtable() so don't duplicate effort. */
-	struct ptdesc *ptdesc = pagetable_alloc(gfp & ~__GFP_ZERO, 0);
-	phys_addr_t pa;
-
-	if (!ptdesc)
-		return INVALID_PHYS_ADDR;
-
-	pa = page_to_phys(ptdesc_page(ptdesc));
+static struct ptdesc **split_pgtables;
+static int split_pgtables_order;
+static unsigned long split_pgtables_count;
+static unsigned long split_pgtables_idx;
 
+static __always_inline void __pgd_pgtable_init(struct mm_struct *mm,
+					       struct ptdesc *ptdesc,
+					       enum pgtable_type pgtable_type)
+{
 	switch (pgtable_type) {
 	case TABLE_PTE:
 		BUG_ON(!pagetable_pte_ctor(mm, ptdesc));
@@ -554,19 +551,28 @@ static phys_addr_t __pgd_pgtable_alloc(struct mm_struct *mm, gfp_t gfp,
 		break;
 	}
 
-	return pa;
 }
 
-static phys_addr_t
-pgd_pgtable_alloc_init_mm_gfp(enum pgtable_type pgtable_type, gfp_t gfp)
+static phys_addr_t __pgd_pgtable_alloc(struct mm_struct *mm, gfp_t gfp,
+				       enum pgtable_type pgtable_type)
 {
-	return __pgd_pgtable_alloc(&init_mm, gfp, pgtable_type);
+	/* Page is zeroed by init_clear_pgtable() so don't duplicate effort. */
+	struct ptdesc *ptdesc = pagetable_alloc(gfp & ~__GFP_ZERO, 0);
+
+	if (!ptdesc)
+		return INVALID_PHYS_ADDR;
+
+	__pgd_pgtable_init(mm, ptdesc, pgtable_type);
+
+	return page_to_phys(ptdesc_page(ptdesc));
 }
 
+typedef phys_addr_t (split_pgtable_alloc_fn)(enum pgtable_type);
+
 static phys_addr_t __maybe_unused
 pgd_pgtable_alloc_init_mm(enum pgtable_type pgtable_type)
 {
-	return pgd_pgtable_alloc_init_mm_gfp(pgtable_type, GFP_PGTABLE_KERNEL);
+	return __pgd_pgtable_alloc(&init_mm, GFP_PGTABLE_KERNEL, pgtable_type);
 }
 
 static phys_addr_t
@@ -575,6 +581,23 @@ pgd_pgtable_alloc_special_mm(enum pgtable_type pgtable_type)
 	return  __pgd_pgtable_alloc(NULL, GFP_PGTABLE_KERNEL, pgtable_type);
 }
 
+static phys_addr_t
+pgd_pgtable_get_preallocated(enum pgtable_type pgtable_type)
+{
+	struct ptdesc *ptdesc;
+
+	if (WARN_ON(split_pgtables_idx >= split_pgtables_count))
+		return INVALID_PHYS_ADDR;
+
+	ptdesc = split_pgtables[split_pgtables_idx++];
+	if (!ptdesc)
+		return INVALID_PHYS_ADDR;
+
+	__pgd_pgtable_init(&init_mm, ptdesc, pgtable_type);
+
+	return page_to_phys(ptdesc_page(ptdesc));
+}
+
 static void split_contpte(pte_t *ptep)
 {
 	int i;
@@ -584,7 +607,9 @@ static void split_contpte(pte_t *ptep)
 		__set_pte(ptep, pte_mknoncont(__ptep_get(ptep)));
 }
 
-static int split_pmd(pmd_t *pmdp, pmd_t pmd, gfp_t gfp, bool to_cont)
+static int split_pmd(pmd_t *pmdp, pmd_t pmd,
+		     split_pgtable_alloc_fn *pgtable_alloc_fn,
+		     bool to_cont)
 {
 	pmdval_t tableprot = PMD_TYPE_TABLE | PMD_TABLE_UXN | PMD_TABLE_AF;
 	unsigned long pfn = pmd_pfn(pmd);
@@ -593,7 +618,7 @@ static int split_pmd(pmd_t *pmdp, pmd_t pmd, gfp_t gfp, bool to_cont)
 	pte_t *ptep;
 	int i;
 
-	pte_phys = pgd_pgtable_alloc_init_mm_gfp(TABLE_PTE, gfp);
+	pte_phys = pgtable_alloc_fn(TABLE_PTE);
 	if (pte_phys == INVALID_PHYS_ADDR)
 		return -ENOMEM;
 	ptep = (pte_t *)phys_to_virt(pte_phys);
@@ -628,7 +653,9 @@ static void split_contpmd(pmd_t *pmdp)
 		set_pmd(pmdp, pmd_mknoncont(pmdp_get(pmdp)));
 }
 
-static int split_pud(pud_t *pudp, pud_t pud, gfp_t gfp, bool to_cont)
+static int split_pud(pud_t *pudp, pud_t pud,
+		     split_pgtable_alloc_fn *pgtable_alloc_fn,
+		     bool to_cont)
 {
 	pudval_t tableprot = PUD_TYPE_TABLE | PUD_TABLE_UXN | PUD_TABLE_AF;
 	unsigned int step = PMD_SIZE >> PAGE_SHIFT;
@@ -638,7 +665,7 @@ static int split_pud(pud_t *pudp, pud_t pud, gfp_t gfp, bool to_cont)
 	pmd_t *pmdp;
 	int i;
 
-	pmd_phys = pgd_pgtable_alloc_init_mm_gfp(TABLE_PMD, gfp);
+	pmd_phys = pgtable_alloc_fn(TABLE_PMD);
 	if (pmd_phys == INVALID_PHYS_ADDR)
 		return -ENOMEM;
 	pmdp = (pmd_t *)phys_to_virt(pmd_phys);
@@ -707,7 +734,7 @@ static int split_kernel_leaf_mapping_locked(unsigned long addr)
 	if (!pud_present(pud))
 		goto out;
 	if (pud_leaf(pud)) {
-		ret = split_pud(pudp, pud, GFP_PGTABLE_KERNEL, true);
+		ret = split_pud(pudp, pud, pgd_pgtable_alloc_init_mm, true);
 		if (ret)
 			goto out;
 	}
@@ -732,7 +759,7 @@ static int split_kernel_leaf_mapping_locked(unsigned long addr)
 		 */
 		if (ALIGN_DOWN(addr, PMD_SIZE) == addr)
 			goto out;
-		ret = split_pmd(pmdp, pmd, GFP_PGTABLE_KERNEL, true);
+		ret = split_pmd(pmdp, pmd, pgd_pgtable_alloc_init_mm, true);
 		if (ret)
 			goto out;
 	}
@@ -831,34 +858,35 @@ int split_kernel_leaf_mapping(unsigned long start, unsigned long end)
 static int split_to_ptes_pud_entry(pud_t *pudp, unsigned long addr,
 				   unsigned long next, struct mm_walk *walk)
 {
-	gfp_t gfp = *(gfp_t *)walk->private;
+	split_pgtable_alloc_fn *pgtable_alloc_fn = walk->private;
 	pud_t pud = pudp_get(pudp);
-	int ret = 0;
 
-	if (pud_leaf(pud))
-		ret = split_pud(pudp, pud, gfp, false);
+	if (!pud_leaf(pud))
+		return 0;
 
-	return ret;
+	return split_pud(pudp, pud, pgtable_alloc_fn, false);
 }
 
 static int split_to_ptes_pmd_entry(pmd_t *pmdp, unsigned long addr,
 				   unsigned long next, struct mm_walk *walk)
 {
-	gfp_t gfp = *(gfp_t *)walk->private;
+	split_pgtable_alloc_fn *pgtable_alloc_fn = walk->private;
 	pmd_t pmd = pmdp_get(pmdp);
-	int ret = 0;
+	int ret;
 
-	if (pmd_leaf(pmd)) {
-		if (pmd_cont(pmd))
-			split_contpmd(pmdp);
-		ret = split_pmd(pmdp, pmd, gfp, false);
+	if (!pmd_leaf(pmd))
+		return 0;
 
-		/*
-		 * We have split the pmd directly to ptes so there is no need to
-		 * visit each pte to check if they are contpte.
-		 */
-		walk->action = ACTION_CONTINUE;
-	}
+	if (pmd_cont(pmd))
+		split_contpmd(pmdp);
+
+	ret = split_pmd(pmdp, pmd, pgtable_alloc_fn, false);
+
+	/*
+	 * We have split the pmd directly to ptes so there is no need to
+	 * visit each pte to check if they are contpte.
+	 */
+	walk->action = ACTION_CONTINUE;
 
 	return ret;
 }
@@ -880,13 +908,15 @@ static const struct mm_walk_ops split_to_ptes_ops = {
 	.pte_entry	= split_to_ptes_pte_entry,
 };
 
-static int range_split_to_ptes(unsigned long start, unsigned long end, gfp_t gfp)
+static int range_split_to_ptes(unsigned long start, unsigned long end,
+			       split_pgtable_alloc_fn *pgtable_alloc_fn)
 {
 	int ret;
 
 	arch_enter_lazy_mmu_mode();
 	ret = walk_kernel_page_table_range_lockless(start, end,
-					&split_to_ptes_ops, NULL, &gfp);
+						    &split_to_ptes_ops, NULL,
+						    pgtable_alloc_fn);
 	arch_leave_lazy_mmu_mode();
 
 	return ret;
@@ -903,6 +933,105 @@ static void __init init_idmap_kpti_bbml2_flag(void)
 	smp_mb();
 }
 
+static int __init
+collect_to_split_pud_entry(pud_t *pudp, unsigned long addr,
+			   unsigned long next, struct mm_walk *walk)
+{
+	pud_t pud = pudp_get(pudp);
+
+	if (pud_leaf(pud))
+		split_pgtables_count += 1 + PTRS_PER_PMD;
+
+	return 0;
+}
+
+static int __init
+collect_to_split_pmd_entry(pmd_t *pmdp, unsigned long addr,
+			   unsigned long next, struct mm_walk *walk)
+{
+	pmd_t pmd = pmdp_get(pmdp);
+
+	if (pmd_leaf(pmd))
+		split_pgtables_count++;
+
+	walk->action = ACTION_CONTINUE;
+
+	return 0;
+}
+
+static void __init linear_map_free_split_pgtables(void)
+{
+	int i;
+
+	if (!split_pgtables_count || !split_pgtables)
+		goto skip_free;
+
+	for (i = split_pgtables_idx; i < split_pgtables_count; i++) {
+		if (split_pgtables[i])
+			pagetable_free(split_pgtables[i]);
+	}
+
+	free_pages((unsigned long)split_pgtables, split_pgtables_order);
+
+skip_free:
+	split_pgtables = NULL;
+	split_pgtables_count = 0;
+	split_pgtables_idx = 0;
+	split_pgtables_order = 0;
+}
+
+static int __init linear_map_prealloc_split_pgtables(void)
+{
+	int ret, i;
+	unsigned long lstart = _PAGE_OFFSET(vabits_actual);
+	unsigned long lend = PAGE_END;
+	unsigned long kstart = (unsigned long)lm_alias(_stext);
+	unsigned long kend = (unsigned long)lm_alias(__init_begin);
+
+	const struct mm_walk_ops collect_to_split_ops = {
+		.pud_entry	= collect_to_split_pud_entry,
+		.pmd_entry	= collect_to_split_pmd_entry
+	};
+
+	split_pgtables_idx = 0;
+	split_pgtables_count = 0;
+
+	ret = walk_kernel_page_table_range_lockless(lstart, kstart,
+						    &collect_to_split_ops,
+						    NULL, NULL);
+	if (!ret)
+		ret = walk_kernel_page_table_range_lockless(kend, lend,
+							    &collect_to_split_ops,
+							    NULL, NULL);
+	if (ret || !split_pgtables_count)
+		goto error;
+
+	ret = -ENOMEM;
+
+	split_pgtables_order =
+		order_base_2(PAGE_ALIGN(split_pgtables_count *
+					sizeof(struct ptdesc *)) >> PAGE_SHIFT);
+
+	split_pgtables = (struct ptdesc **) __get_free_pages(GFP_KERNEL | __GFP_ZERO,
+							     split_pgtables_order);
+	if (!split_pgtables)
+		goto error;
+
+	for (i = 0; i < split_pgtables_count; i++) {
+		split_pgtables[i] = pagetable_alloc(GFP_KERNEL, 0);
+		if (!split_pgtables[i])
+			goto error;
+	}
+
+	ret = 0;
+
+error:
+	if (ret)
+		linear_map_free_split_pgtables();
+
+	return ret;
+}
+
 static int __init linear_map_split_to_ptes(void *__unused)
 {
 	/*
@@ -928,9 +1057,9 @@ static int __init linear_map_split_to_ptes(void *__unused)
 		 * PTE. The kernel alias remains static throughout runtime so
 		 * can continue to be safely mapped with large mappings.
 		 */
-		ret = range_split_to_ptes(lstart, kstart, GFP_ATOMIC);
+		ret = range_split_to_ptes(lstart, kstart, pgd_pgtable_get_preallocated);
 		if (!ret)
-			ret = range_split_to_ptes(kend, lend, GFP_ATOMIC);
+			ret = range_split_to_ptes(kend, lend, pgd_pgtable_get_preallocated);
 		if (ret)
 			panic("Failed to split linear map\n");
 		flush_tlb_kernel_range(lstart, lend);
@@ -963,10 +1092,16 @@ static int __init linear_map_split_to_ptes(void *__unused)
 
 void __init linear_map_maybe_split_to_ptes(void)
 {
-	if (linear_map_requires_bbml2 && !system_supports_bbml2_noabort()) {
-		init_idmap_kpti_bbml2_flag();
-		stop_machine(linear_map_split_to_ptes, NULL, cpu_online_mask);
-	}
+	if (!linear_map_requires_bbml2 || system_supports_bbml2_noabort())
+		return;
+
+	if (linear_map_prealloc_split_pgtables())
+		panic("Failed to split linear map\n");
+
+	init_idmap_kpti_bbml2_flag();
+	stop_machine(linear_map_split_to_ptes, NULL, cpu_online_mask);
+
+	linear_map_free_split_pgtables();
 }
 
 /*
@@ -1088,6 +1223,7 @@ bool arch_kfence_init_pool(void)
 	unsigned long end = start + KFENCE_POOL_SIZE;
 	int ret;
 
+
 	/* Exit early if we know the linear map is already pte-mapped. */
 	if (!split_leaf_mapping_possible())
 		return true;
@@ -1097,7 +1233,7 @@ bool arch_kfence_init_pool(void)
 		return true;
 
 	mutex_lock(&pgtable_split_lock);
-	ret = range_split_to_ptes(start, end, GFP_PGTABLE_KERNEL);
+	ret = range_split_to_ptes(start, end, pgd_pgtable_alloc_init_mm);
 	mutex_unlock(&pgtable_split_lock);
 
 	/*
-- 
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



From yeoreum.yun at arm.com  Thu Dec 18 11:47:48 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Thu, 18 Dec 2025 19:47:48 +0000
Subject: [PATCH v3 0/2]  fix wrong usage of memory allocation APIs under PREEMPT_RT in arm64
Message-ID: <20251218194750.395301-1-yeoreum.yun@arm.com>

Under PREEMPT_RT, calling generic memory allocation/free APIs
(e.x) __get_free_pages(), pgtable_alloc(), free_pages() and etc
with preemption disabled is not allowed, but allow only nolock() APIs series
because it may acquire a spin lock that becomes sleepable on RT,
potentially causing a sleep during page allocation
(See Documentation/core-api/real-time/differences.rst, Memory allocation section).

However, In arm64, __linear_map_split_to_ptes() and
__kpti_install_ng_mappings() called by stopper thread via stop_machine()
use generic memory allocation/free APIs.

This patchset fixes this problem and based on v6.19-rc1

Patch History
==============
from v2 to v3:
  - remove split-mode and split_args.
    pass proper function pointer while spliting.
  - rename function name.
  - https://lore.kernel.org/all/20251217182007.2345700-1-yeoreum.yun at arm.com/

from v1 to v2:
  - drop pagetable_alloc_nolock()
  - following @Ryan Roberts suggestion.
  - https://lore.kernel.org/all/20251212161832.2067134-1-yeoreum.yun at arm.com/


*** BLURB HERE ***

Yeoreum Yun (2):
  arm64: mmu: avoid allocating pages while splitting the linear mapping
  arm64: mmu: avoid allocating pages while installing ng-mapping for
    KPTI

 arch/arm64/mm/mmu.c | 254 ++++++++++++++++++++++++++++++++++----------
 1 file changed, 197 insertions(+), 57 deletions(-)

--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



From yeoreum.yun at arm.com  Thu Dec 18 11:47:50 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Thu, 18 Dec 2025 19:47:50 +0000
Subject: [PATCH v3 2/2] arm64: mmu: avoid allocating pages while installing ng-mapping for KPTI
In-Reply-To: <20251218194750.395301-1-yeoreum.yun@arm.com>
References: <20251218194750.395301-1-yeoreum.yun@arm.com>
Message-ID: <20251218194750.395301-3-yeoreum.yun@arm.com>

The current __kpti_install_ng_mappings() allocates a temporary PGD
while installing the NG mapping for KPTI under stop_machine(),
using GFP_ATOMIC.

This is fine in the non-PREEMPT_RT case. However, it becomes a problem
under PREEMPT_RT because generic memory allocation/free APIs
(e.g., pgtable_alloc(), __get_free_pages(), etc.) cannot be invoked
in a non-preemptible context, except for the *_nolock() variants.
These generic allocators may sleep due to their use of spin_lock().

In other words, calling __get_free_pages(), even with GFP_ATOMIC,
is not allowed in __kpti_install_ng_mappings(), which is executed by
the stopper thread where preemption is disabled under PREEMPT_RT.

To address this, preallocate the page needed for the temporary PGD
before invoking __kpti_install_ng_mappings() via stop_machine().

Fixes: 47546a1912fc ("arm64: mm: install KPTI nG mappings with MMU enabled")
Signed-off-by: Yeoreum Yun <yeoreum.yun at arm.com>
Reviewed-by: Ryan Roberts <ryan.roberts at arm.com>
---
 arch/arm64/mm/mmu.c | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 96a9fa505e71..9ad9612728e6 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -1369,7 +1369,7 @@ static phys_addr_t __init kpti_ng_pgd_alloc(enum pgtable_type type)
 	return kpti_ng_temp_alloc;
 }
 
-static int __init __kpti_install_ng_mappings(void *__unused)
+static int __init __kpti_install_ng_mappings(void *data)
 {
 	typedef void (kpti_remap_fn)(int, int, phys_addr_t, unsigned long);
 	extern kpti_remap_fn idmap_kpti_install_ng_mappings;
@@ -1377,10 +1377,9 @@ static int __init __kpti_install_ng_mappings(void *__unused)
 
 	int cpu = smp_processor_id();
 	int levels = CONFIG_PGTABLE_LEVELS;
-	int order = order_base_2(levels);
 	u64 kpti_ng_temp_pgd_pa = 0;
 	pgd_t *kpti_ng_temp_pgd;
-	u64 alloc = 0;
+	u64 alloc = *(u64 *)data;
 
 	if (levels == 5 && !pgtable_l5_enabled())
 		levels = 4;
@@ -1391,8 +1390,6 @@ static int __init __kpti_install_ng_mappings(void *__unused)
 
 	if (!cpu) {
 		int ret;
-
-		alloc = __get_free_pages(GFP_ATOMIC | __GFP_ZERO, order);
 		kpti_ng_temp_pgd = (pgd_t *)(alloc + (levels - 1) * PAGE_SIZE);
 		kpti_ng_temp_alloc = kpti_ng_temp_pgd_pa = __pa(kpti_ng_temp_pgd);
 
@@ -1423,16 +1420,17 @@ static int __init __kpti_install_ng_mappings(void *__unused)
 	remap_fn(cpu, num_online_cpus(), kpti_ng_temp_pgd_pa, KPTI_NG_TEMP_VA);
 	cpu_uninstall_idmap();
 
-	if (!cpu) {
-		free_pages(alloc, order);
+	if (!cpu)
 		arm64_use_ng_mappings = true;
-	}
 
 	return 0;
 }
 
 void __init kpti_install_ng_mappings(void)
 {
+	int order = order_base_2(CONFIG_PGTABLE_LEVELS);
+	u64 alloc;
+
 	/* Check whether KPTI is going to be used */
 	if (!arm64_kernel_unmapped_at_el0())
 		return;
@@ -1445,8 +1443,14 @@ void __init kpti_install_ng_mappings(void)
 	if (arm64_use_ng_mappings)
 		return;
 
+	alloc = __get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
+	if (!alloc)
+		panic("Failed to alloc page tables\n");
+
 	init_idmap_kpti_bbml2_flag();
-	stop_machine(__kpti_install_ng_mappings, NULL, cpu_online_mask);
+	stop_machine(__kpti_install_ng_mappings, &alloc, cpu_online_mask);
+
+	free_pages(alloc, order);
 }
 
 static pgprot_t __init kernel_exec_prot(void)
-- 
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



From nicolinc at nvidia.com  Thu Dec 18 12:26:46 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Thu, 18 Dec 2025 12:26:46 -0800
Subject: [PATCH v1 0/9] iommu/arm-smmu-v3: Share domain across SMMU/vSMMU instances
Message-ID: <cover.1766088962.git.nicolinc@nvidia.com>

In a system with multiple physical SMMU instances, multiple devices can be
passed through to a VM. Currently, a VM would allocate one domain per SMMU
instance that might be shared across devices that sit behind the same SMMU
instance. However, the gPA->PA mappings (either an S1 unmanaged domain or
an S2 nesting parent domain) can be shared across all the devices that sit
behind different SMMU instances as well, provided that the shared I/O page
table is compatible with all the SMMU instances.

The major difficulty in sharing the domain has been invalidation, since a
change to the shared I/O page table results in an invalidation on all SMMU
instances. A traditional approach involves building a linked list of SMMUs
within the domain, which is very inefficient for the invalidation path as
the linked list has to be locked.

To address this, the SMMUv3 driver now uses an RCU-protected invalidation
array. Any new device (and its SMMU) is preloaded into the array during a
device attachment. This array maintains all necessary information, such as
ASID/VMID and which SMMU instance (CMDQ) to issue the command to.

The second issue concerns the lifecycle of the iotlb tag. Currently, ASID
or VMID is allocated per domain and kept in the domain structure (cd->asid
or s2_cfg->vmid). This does not work ideally when the domain (e.g. S2) is
shared, as the VMID will have to be global across all SMMU instances, even
if a VM is not using all of them. This results in wasted VMID resources in
the bitmaps of unused SMMU instances.

Instead, an iotlb tag should be allocated per SMMU instance. Consequently,
these tags must be allocated and maintained separately. Since ASID or VMID
is only used when a CD or STE is installed to the HW (which happens during
device attachment), and the invalidation array is built right before that,
arm_smmu_invs_merge() is the ideal place to allocate a new iotlb tag:
 - when a device attaches, the driver first searches for an existing iotlb
   tag for the SMMU the device sits behind
 - If a match is found, the "users" counter is incremented
 - otherwise, a new tag is allocated.

As ASID/VMID are programmed to CD/STE that belong to a device, it's natural
to store the ASID/VMID in the master structure.

Given the above, this series reworks the driver further:
 - Add ASID/VMID allocation/free ops to the arm_smmu_invs data structure
 - Store the allocated ASID/VMID in the arm_smmu_master structure
 - Replace cd->asid and s2_cfg->vmid with the tags stored in the master
   structure, when installing them to the CD and STE
 - Deprecate cd->asid and s2_cfg->vmid.

Finally, allow sharing a domain across the SMMU instances, so long as they
passes a compatibility test.

This is on Github:
https://github.com/nicolinc/iommufd/commits/smmuv3_share_domain-v1

This is based on the series "Introduce an RCU-protected invalidation array"
https://lore.kernel.org/all/cover.1766013662.git.nicolinc at nvidia.com/
So the whole implementation follows the path Jason envisioned initially.

A earlier effort to share S2 domain can be found:
https://lore.kernel.org/all/cover.1744692494.git.nicolinc at nvidia.com/

Thanks
Nicolin

Nicolin Chen (9):
  iommu/arm-smmu-v3: Pass in ssid to arm_smmu_make_s1_cd()
  iommu/arm-smmu-v3: Add alloc_id/free_id functions to arm_smmu_invs
  iommu/arm-smmu-v3: Store ASIDs and VMID in arm_smmu_master
  iommu/arm-smmu-v3: Use alloc_id/free_id ops in
    arm_smmu_invs_merge/unref
  iommu/arm-smmu-v3: Install to CD/STE the ASID/VMID stored in the
    master
  iommu/arm-smmu-v3: Use dummy ASID/VMID in arm_smmu_master_build_invs()
  iommu/arm-smmu-v3: Remove free_fn argument from arm_smmu_invs_unref()
  iommu/arm-smmu-v3: Remove ASID/VMID from arm_smmu_domain
  iommu/arm-smmu-v3: Allow sharing domain across SMMUs

 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  47 ++-
 .../arm/arm-smmu-v3/arm-smmu-v3-iommufd.c     |  17 +-
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c   |  27 +-
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  |  24 +-
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 307 +++++++++++-------
 5 files changed, 265 insertions(+), 157 deletions(-)

-- 
2.43.0



From nicolinc at nvidia.com  Thu Dec 18 12:26:49 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Thu, 18 Dec 2025 12:26:49 -0800
Subject: [PATCH v1 3/9] iommu/arm-smmu-v3: Store ASIDs and VMID in arm_smmu_master
In-Reply-To: <cover.1766088962.git.nicolinc@nvidia.com>
References: <cover.1766088962.git.nicolinc@nvidia.com>
Message-ID: <f7fa8725aab1fbd2c2a1d564e7493b16a586e88c.1766088962.git.nicolinc@nvidia.com>

Currently, ASID is allocated per smmu_domain, stored in the domain, and
freed with the domain.

Practically, ASID is only used in a CD as an iotlb tag. Therefore, ASID
doesn't really follow the life cycle of a domain but domain attachment.

On the other hand, the CD carrying ASID is installed to a device's STE.

This applies to the VMID as well, which is installed in an STE directly.

Since a device can only have one ASID per SSID and one VMID per SID, add
an ASID array and VMID in the arm_smmu_master structure, to decouple the
ASID/VMID from the domain structure.

Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  4 +++
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  | 13 ++++++---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 28 +++++++++++++++++++
 3 files changed, 41 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index b275673c03ce..e21e95936b05 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -953,6 +953,8 @@ struct arm_smmu_master {
 	bool				stall_enabled;
 	unsigned int			ssid_bits;
 	unsigned int			iopf_refcount;
+	/* Store allocated ASID[1 << ssid_bits] and VMID */
+	u16				*asid, vmid;
 };
 
 /* SMMU private data for an IOMMU domain */
@@ -1117,11 +1119,13 @@ static inline bool arm_smmu_master_canwbs(struct arm_smmu_master *master)
  * @new_invs: for new domain, this is the new invs array to update domain->invs;
  *            for old domain, this is the master->build_invs to pass in as the
  *            to_unref argument to an arm_smmu_invs_unref() call
+ * @iotlb_tag: copy of the first entry in the build_invs for the domain
  */
 struct arm_smmu_inv_state {
 	struct arm_smmu_invs __rcu **invs_ptr;
 	struct arm_smmu_invs *old_invs;
 	struct arm_smmu_invs *new_invs;
+	struct arm_smmu_inv iotlb_tag;
 };
 
 struct arm_smmu_attach_state {
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
index e4bdb4cfdacd..ead0d84cc9a0 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
@@ -449,7 +449,8 @@ static void arm_smmu_v3_test_cd_expect_hitless_transition(
 					      num_syncs_expected, true);
 }
 
-static void arm_smmu_test_make_s1_cd(struct arm_smmu_cd *cd, unsigned int asid)
+static void arm_smmu_test_make_s1_cd(struct kunit *test, struct arm_smmu_cd *cd,
+				     unsigned int asid)
 {
 	struct arm_smmu_master master = {
 		.smmu = &smmu,
@@ -471,6 +472,10 @@ static void arm_smmu_test_make_s1_cd(struct arm_smmu_cd *cd, unsigned int asid)
 	io_pgtable.cfg.arm_lpae_s1_cfg.tcr.tsz = 4;
 	io_pgtable.cfg.arm_lpae_s1_cfg.mair = 0xabcdef012345678ULL;
 
+	master.asid = kunit_kzalloc(test, sizeof(*master.asid), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, master.asid);
+
+	master.asid[IOMMU_NO_PASID] = asid;
 	arm_smmu_make_s1_cd(cd, &master, &smmu_domain, IOMMU_NO_PASID);
 }
 
@@ -479,7 +484,7 @@ static void arm_smmu_v3_write_cd_test_s1_clear(struct kunit *test)
 	struct arm_smmu_cd cd = {};
 	struct arm_smmu_cd cd_2;
 
-	arm_smmu_test_make_s1_cd(&cd_2, 1997);
+	arm_smmu_test_make_s1_cd(test, &cd_2, 1997);
 	arm_smmu_v3_test_cd_expect_non_hitless_transition(
 		test, &cd, &cd_2, NUM_EXPECTED_SYNCS(2));
 	arm_smmu_v3_test_cd_expect_non_hitless_transition(
@@ -491,8 +496,8 @@ static void arm_smmu_v3_write_cd_test_s1_change_asid(struct kunit *test)
 	struct arm_smmu_cd cd = {};
 	struct arm_smmu_cd cd_2;
 
-	arm_smmu_test_make_s1_cd(&cd, 778);
-	arm_smmu_test_make_s1_cd(&cd_2, 1997);
+	arm_smmu_test_make_s1_cd(test, &cd, 778);
+	arm_smmu_test_make_s1_cd(test, &cd_2, 1997);
 	arm_smmu_v3_test_cd_expect_hitless_transition(test, &cd, &cd_2,
 						      NUM_EXPECTED_SYNCS(1));
 	arm_smmu_v3_test_cd_expect_hitless_transition(test, &cd_2, &cd,
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 8a2b7064d29b..1bf7b7233109 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -3391,6 +3391,7 @@ static int arm_smmu_attach_prepare_invs(struct arm_smmu_attach_state *state,
 			arm_smmu_invs_merge(invst->old_invs, build_invs);
 		if (IS_ERR(invst->new_invs))
 			return PTR_ERR(invst->new_invs);
+		invst->iotlb_tag = build_invs->inv[0];
 	}
 
 	if (old_smmu_domain) {
@@ -3440,6 +3441,11 @@ arm_smmu_install_new_domain_invs(struct arm_smmu_attach_state *state)
 	 */
 	smp_mb();
 	kfree_rcu(invst->old_invs, rcu);
+
+	if (invst->iotlb_tag.type == INV_TYPE_S1_ASID)
+		state->master->asid[state->ssid] = invst->iotlb_tag.id;
+	else
+		state->master->vmid = invst->iotlb_tag.id;
 }
 
 /*
@@ -3471,8 +3477,11 @@ static void arm_smmu_inv_flush_iotlb_tag(struct arm_smmu_inv *inv)
 static void
 arm_smmu_install_old_domain_invs(struct arm_smmu_attach_state *state)
 {
+	struct arm_smmu_inv *new_iotlb_tag = &state->new_domain_invst.iotlb_tag;
+	struct arm_smmu_inv *old_iotlb_tag = &state->old_domain_invst.iotlb_tag;
 	struct arm_smmu_inv_state *invst = &state->old_domain_invst;
 	struct arm_smmu_invs *old_invs = invst->old_invs;
+	struct arm_smmu_master *master = state->master;
 	struct arm_smmu_invs *new_invs;
 
 	lockdep_assert_held(&arm_smmu_asid_lock);
@@ -3482,6 +3491,7 @@ arm_smmu_install_old_domain_invs(struct arm_smmu_attach_state *state)
 
 	arm_smmu_invs_unref(old_invs, invst->new_invs,
 			    arm_smmu_inv_flush_iotlb_tag);
+	*old_iotlb_tag = invst->new_invs->inv[0];
 
 	new_invs = arm_smmu_invs_purge(old_invs);
 	if (!new_invs)
@@ -3506,6 +3516,14 @@ arm_smmu_install_old_domain_invs(struct arm_smmu_attach_state *state)
 	 */
 	smp_mb();
 	kfree_rcu(old_invs, rcu);
+
+	/* Make sure we don't clear the stored new iotlb tag */
+	if (!new_iotlb_tag->id) {
+		if (old_iotlb_tag->type == INV_TYPE_S1_ASID)
+			cmpxchg(&master->asid[state->ssid], old_iotlb_tag->id, 0);
+		else
+			cmpxchg(&master->vmid, old_iotlb_tag->id, 0);
+	}
 }
 
 /*
@@ -4286,6 +4304,13 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev)
 		master->ssid_bits = min_t(u8, master->ssid_bits,
 					  CTXDESC_LINEAR_CDMAX);
 
+	master->asid = kcalloc(1 << master->ssid_bits, sizeof(*master->asid),
+			       GFP_KERNEL);
+	if (!master->asid) {
+		ret = -ENOMEM;
+		goto err_disable_pasid;
+	}
+
 	if ((smmu->features & ARM_SMMU_FEAT_STALLS &&
 	     device_property_read_bool(dev, "dma-can-stall")) ||
 	    smmu->features & ARM_SMMU_FEAT_STALL_FORCE)
@@ -4299,6 +4324,9 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev)
 
 	return &smmu->iommu;
 
+err_disable_pasid:
+	arm_smmu_disable_pasid(master);
+	arm_smmu_remove_master(master);
 err_free_master:
 	kfree(master);
 	return ERR_PTR(ret);
-- 
2.43.0



From nicolinc at nvidia.com  Thu Dec 18 12:26:47 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Thu, 18 Dec 2025 12:26:47 -0800
Subject: [PATCH v1 1/9] iommu/arm-smmu-v3: Pass in ssid to arm_smmu_make_s1_cd()
In-Reply-To: <cover.1766088962.git.nicolinc@nvidia.com>
References: <cover.1766088962.git.nicolinc@nvidia.com>
Message-ID: <afa354cf674fea1a140af48cbd90096fe16cc671.1766088962.git.nicolinc@nvidia.com>

An S1 domain that holds the mappings of guest VM's RAM space can be shared
across the passthrough devices, as long as the S1 page table is compatible
with all the SMMU instances that the devices physically sit behind.

On the other hand, ASID is per CD, which is further per STE (i.e. device).
Thus, it should be decoupled from a domain structure and ideally stored in
the master structure instead.

There will be an ASID array stored in the arm_smmu_master structure, so it
needs an SSID/PASID to index a specific ASID to program the CD. To prepare
for that, pass in an SSID/PASID to arm_smmu_make_s1_cd() from its callers.

Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h      | 2 +-
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c  | 3 ++-
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c | 2 +-
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c      | 7 ++++---
 4 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index 4f104c1baa67..0a5aead300b6 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -1070,7 +1070,7 @@ struct arm_smmu_cd *arm_smmu_get_cd_ptr(struct arm_smmu_master *master,
 					u32 ssid);
 void arm_smmu_make_s1_cd(struct arm_smmu_cd *target,
 			 struct arm_smmu_master *master,
-			 struct arm_smmu_domain *smmu_domain);
+			 struct arm_smmu_domain *smmu_domain, ioasid_t ssid);
 void arm_smmu_write_cd_entry(struct arm_smmu_master *master, int ssid,
 			     struct arm_smmu_cd *cdptr,
 			     const struct arm_smmu_cd *target);
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index f1f8e01a7e91..adf802f165d1 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -29,7 +29,8 @@ arm_smmu_update_s1_domain_cd_entry(struct arm_smmu_domain *smmu_domain)
 		if (WARN_ON(!cdptr))
 			continue;
 
-		arm_smmu_make_s1_cd(&target_cd, master, smmu_domain);
+		arm_smmu_make_s1_cd(&target_cd, master, smmu_domain,
+				    master_domain->ssid);
 		arm_smmu_write_cd_entry(master, master_domain->ssid, cdptr,
 					&target_cd);
 	}
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
index 238bfd328b5b..e4bdb4cfdacd 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
@@ -471,7 +471,7 @@ static void arm_smmu_test_make_s1_cd(struct arm_smmu_cd *cd, unsigned int asid)
 	io_pgtable.cfg.arm_lpae_s1_cfg.tcr.tsz = 4;
 	io_pgtable.cfg.arm_lpae_s1_cfg.mair = 0xabcdef012345678ULL;
 
-	arm_smmu_make_s1_cd(cd, &master, &smmu_domain);
+	arm_smmu_make_s1_cd(cd, &master, &smmu_domain, IOMMU_NO_PASID);
 }
 
 static void arm_smmu_v3_write_cd_test_s1_clear(struct kunit *test)
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index d7c492ee0936..bf0df16cec45 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1613,7 +1613,7 @@ void arm_smmu_write_cd_entry(struct arm_smmu_master *master, int ssid,
 
 void arm_smmu_make_s1_cd(struct arm_smmu_cd *target,
 			 struct arm_smmu_master *master,
-			 struct arm_smmu_domain *smmu_domain)
+			 struct arm_smmu_domain *smmu_domain, ioasid_t ssid)
 {
 	struct arm_smmu_ctx_desc *cd = &smmu_domain->cd;
 	const struct io_pgtable_cfg *pgtbl_cfg =
@@ -3636,7 +3636,8 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev,
 	case ARM_SMMU_DOMAIN_S1: {
 		struct arm_smmu_cd target_cd;
 
-		arm_smmu_make_s1_cd(&target_cd, master, smmu_domain);
+		arm_smmu_make_s1_cd(&target_cd, master, smmu_domain,
+				    IOMMU_NO_PASID);
 		arm_smmu_write_cd_entry(master, IOMMU_NO_PASID, cdptr,
 					&target_cd);
 		arm_smmu_make_cdtable_ste(&target, master, state.ats_enabled,
@@ -3679,7 +3680,7 @@ static int arm_smmu_s1_set_dev_pasid(struct iommu_domain *domain,
 	 * We can read cd.asid outside the lock because arm_smmu_set_pasid()
 	 * will fix it
 	 */
-	arm_smmu_make_s1_cd(&target_cd, master, smmu_domain);
+	arm_smmu_make_s1_cd(&target_cd, master, smmu_domain, id);
 	return arm_smmu_set_pasid(master, to_smmu_domain(domain), id,
 				  &target_cd, old);
 }
-- 
2.43.0



From nicolinc at nvidia.com  Thu Dec 18 12:26:54 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Thu, 18 Dec 2025 12:26:54 -0800
Subject: [PATCH v1 8/9] iommu/arm-smmu-v3: Remove ASID/VMID from arm_smmu_domain
In-Reply-To: <cover.1766088962.git.nicolinc@nvidia.com>
References: <cover.1766088962.git.nicolinc@nvidia.com>
Message-ID: <cfc55bbfdf1dfbc23740f9cad1f4a324c40ce463.1766088963.git.nicolinc@nvidia.com>

Now ASID/VMID are stored in the arm_smmu_master. These are dead code now.

Remove all.

Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  8 ---
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c   | 20 +------
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  |  3 -
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 58 -------------------
 4 files changed, 1 insertion(+), 88 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index e38d2394e3be..4d7b7eb52dfd 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -792,10 +792,6 @@ static inline bool arm_smmu_ssids_in_use(struct arm_smmu_ctx_desc_cfg *cd_table)
 	return cd_table->used_ssids;
 }
 
-struct arm_smmu_s2_cfg {
-	u16				vmid;
-};
-
 struct arm_smmu_strtab_cfg {
 	union {
 		struct {
@@ -974,10 +970,6 @@ struct arm_smmu_domain {
 	atomic_t			nr_ats_masters;
 
 	enum arm_smmu_domain_stage	stage;
-	union {
-		struct arm_smmu_ctx_desc	cd;
-		struct arm_smmu_s2_cfg		s2_cfg;
-	};
 
 	struct iommu_domain		domain;
 
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index 0e534f2b72e0..ea5ce3e6514e 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -282,14 +282,6 @@ static void arm_smmu_sva_domain_free(struct iommu_domain *domain)
 	 */
 	arm_smmu_domain_inv(smmu_domain);
 
-	/*
-	 * Notice that the arm_smmu_mm_arch_invalidate_secondary_tlbs op can
-	 * still be called/running at this point. We allow the ASID to be
-	 * reused, and if there is a race then it just suffers harmless
-	 * unnecessary invalidation.
-	 */
-	xa_erase(&arm_smmu_asid_xa, smmu_domain->cd.asid);
-
 	/*
 	 * Actual free is defered to the SRCU callback
 	 * arm_smmu_mmu_notifier_free()
@@ -308,7 +300,6 @@ struct iommu_domain *arm_smmu_sva_domain_alloc(struct device *dev,
 	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
 	struct arm_smmu_device *smmu = master->smmu;
 	struct arm_smmu_domain *smmu_domain;
-	u32 asid;
 	int ret;
 
 	if (!(master->smmu->features & ARM_SMMU_FEAT_SVA))
@@ -327,22 +318,13 @@ struct iommu_domain *arm_smmu_sva_domain_alloc(struct device *dev,
 	smmu_domain->domain.pgsize_bitmap = PAGE_SIZE;
 	smmu_domain->stage = ARM_SMMU_DOMAIN_SVA;
 	smmu_domain->smmu = smmu;
-
-	ret = xa_alloc(&arm_smmu_asid_xa, &asid, smmu_domain,
-		       XA_LIMIT(1, (1 << smmu->asid_bits) - 1), GFP_KERNEL);
-	if (ret)
-		goto err_free;
-
-	smmu_domain->cd.asid = asid;
 	smmu_domain->mmu_notifier.ops = &arm_smmu_mmu_notifier_ops;
 	ret = mmu_notifier_register(&smmu_domain->mmu_notifier, mm);
 	if (ret)
-		goto err_asid;
+		goto err_free;
 
 	return &smmu_domain->domain;
 
-err_asid:
-	xa_erase(&arm_smmu_asid_xa, smmu_domain->cd.asid);
 err_free:
 	arm_smmu_domain_free(smmu_domain);
 	return ERR_PTR(ret);
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
index 5c8cb43f849c..b174ac2dfb4b 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
@@ -458,9 +458,6 @@ static void arm_smmu_test_make_s1_cd(struct kunit *test, struct arm_smmu_cd *cd,
 	struct io_pgtable io_pgtable = {};
 	struct arm_smmu_domain smmu_domain = {
 		.pgtbl_ops = &io_pgtable.ops,
-		.cd = {
-			.asid = asid,
-		},
 	};
 
 	io_pgtable.cfg.arm_lpae_s1_cfg.ttbr = 0xdaedbeefdeadbeefULL;
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 5052988b0e4e..04e21af9c578 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2812,66 +2812,17 @@ struct arm_smmu_domain *arm_smmu_domain_alloc(void)
 static void arm_smmu_domain_free_paging(struct iommu_domain *domain)
 {
 	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
-	struct arm_smmu_device *smmu = smmu_domain->smmu;
 
 	free_io_pgtable_ops(smmu_domain->pgtbl_ops);
-
-	/* Free the ASID or VMID */
-	if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
-		/* Prevent SVA from touching the CD while we're freeing it */
-		mutex_lock(&arm_smmu_asid_lock);
-		xa_erase(&arm_smmu_asid_xa, smmu_domain->cd.asid);
-		mutex_unlock(&arm_smmu_asid_lock);
-	} else {
-		struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg;
-		if (cfg->vmid)
-			ida_free(&smmu->vmid_map, cfg->vmid);
-	}
-
 	arm_smmu_domain_free(smmu_domain);
 }
 
-static int arm_smmu_domain_finalise_s1(struct arm_smmu_device *smmu,
-				       struct arm_smmu_domain *smmu_domain)
-{
-	int ret;
-	u32 asid = 0;
-	struct arm_smmu_ctx_desc *cd = &smmu_domain->cd;
-
-	/* Prevent SVA from modifying the ASID until it is written to the CD */
-	mutex_lock(&arm_smmu_asid_lock);
-	ret = xa_alloc(&arm_smmu_asid_xa, &asid, smmu_domain,
-		       XA_LIMIT(1, (1 << smmu->asid_bits) - 1), GFP_KERNEL);
-	cd->asid	= (u16)asid;
-	mutex_unlock(&arm_smmu_asid_lock);
-	return ret;
-}
-
-static int arm_smmu_domain_finalise_s2(struct arm_smmu_device *smmu,
-				       struct arm_smmu_domain *smmu_domain)
-{
-	int vmid;
-	struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg;
-
-	/* Reserve VMID 0 for stage-2 bypass STEs */
-	vmid = ida_alloc_range(&smmu->vmid_map, 1, (1 << smmu->vmid_bits) - 1,
-			       GFP_KERNEL);
-	if (vmid < 0)
-		return vmid;
-
-	cfg->vmid	= (u16)vmid;
-	return 0;
-}
-
 static int arm_smmu_domain_finalise(struct arm_smmu_domain *smmu_domain,
 				    struct arm_smmu_device *smmu, u32 flags)
 {
-	int ret;
 	enum io_pgtable_fmt fmt;
 	struct io_pgtable_cfg pgtbl_cfg;
 	struct io_pgtable_ops *pgtbl_ops;
-	int (*finalise_stage_fn)(struct arm_smmu_device *smmu,
-				 struct arm_smmu_domain *smmu_domain);
 	bool enable_dirty = flags & IOMMU_HWPT_ALLOC_DIRTY_TRACKING;
 
 	pgtbl_cfg = (struct io_pgtable_cfg) {
@@ -2891,7 +2842,6 @@ static int arm_smmu_domain_finalise(struct arm_smmu_domain *smmu_domain,
 		if (enable_dirty)
 			pgtbl_cfg.quirks |= IO_PGTABLE_QUIRK_ARM_HD;
 		fmt = ARM_64_LPAE_S1;
-		finalise_stage_fn = arm_smmu_domain_finalise_s1;
 		break;
 	}
 	case ARM_SMMU_DOMAIN_S2:
@@ -2900,7 +2850,6 @@ static int arm_smmu_domain_finalise(struct arm_smmu_domain *smmu_domain,
 		pgtbl_cfg.ias = smmu->ias;
 		pgtbl_cfg.oas = smmu->oas;
 		fmt = ARM_64_LPAE_S2;
-		finalise_stage_fn = arm_smmu_domain_finalise_s2;
 		if ((smmu->features & ARM_SMMU_FEAT_S2FWB) &&
 		    (flags & IOMMU_HWPT_ALLOC_NEST_PARENT))
 			pgtbl_cfg.quirks |= IO_PGTABLE_QUIRK_ARM_S2FWB;
@@ -2918,13 +2867,6 @@ static int arm_smmu_domain_finalise(struct arm_smmu_domain *smmu_domain,
 	smmu_domain->domain.geometry.force_aperture = true;
 	if (enable_dirty && smmu_domain->stage == ARM_SMMU_DOMAIN_S1)
 		smmu_domain->domain.dirty_ops = &arm_smmu_dirty_ops;
-
-	ret = finalise_stage_fn(smmu, smmu_domain);
-	if (ret < 0) {
-		free_io_pgtable_ops(pgtbl_ops);
-		return ret;
-	}
-
 	smmu_domain->pgtbl_ops = pgtbl_ops;
 	smmu_domain->smmu = smmu;
 	return 0;
-- 
2.43.0



From nicolinc at nvidia.com  Thu Dec 18 12:26:48 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Thu, 18 Dec 2025 12:26:48 -0800
Subject: [PATCH v1 2/9] iommu/arm-smmu-v3: Add alloc_id/free_id functions to arm_smmu_invs
In-Reply-To: <cover.1766088962.git.nicolinc@nvidia.com>
References: <cover.1766088962.git.nicolinc@nvidia.com>
Message-ID: <1541ea4a9e9c935c2f907c0c5f13a4af2bdc2114.1766088962.git.nicolinc@nvidia.com>

An iotlb tag (ASID/VMID) will not be used:
1) Before being installed to CD/STE during a device attachment
2) After being removed from CD/STE during a device detachment

Both (1) and (2) exactly align with the lifecyle of the domain->invs. So,
it becomes very nature to use domain->invs to allocate/free an ASID/VMID.

Add a pair of function ops in struct arm_smmu_invs, to manage iotlb tag.

Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h |  6 ++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 93 +++++++++++++++++++++
 2 files changed, 99 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index 0a5aead300b6..b275673c03ce 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -691,6 +691,9 @@ static inline bool arm_smmu_inv_is_ats(const struct arm_smmu_inv *inv)
  * @rwlock: optional rwlock to fench ATS operations
  * @has_ats: flag if the array contains an INV_TYPE_ATS or INV_TYPE_ATS_FULL
  * @rcu: rcu head for kfree_rcu()
+ * @smmu_domain: owner domain of the array
+ * @alloc_id: a callback to allocate a new iotlb tag
+ * @free_id: a callback to free an iotlb tag when its user counter reaches 0
  * @inv: flexible invalidation array
  *
  * The arm_smmu_invs is an RCU data structure. During a ->attach_dev callback,
@@ -720,6 +723,9 @@ struct arm_smmu_invs {
 	rwlock_t rwlock;
 	bool has_ats;
 	struct rcu_head rcu;
+	struct arm_smmu_domain *smmu_domain;
+	int (*alloc_id)(struct arm_smmu_inv *inv, void *data);
+	void (*free_id)(struct arm_smmu_inv *inv, bool flush);
 	struct arm_smmu_inv inv[] __counted_by(max_invs);
 };
 
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index bf0df16cec45..8a2b7064d29b 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -3117,6 +3117,94 @@ static void arm_smmu_disable_iopf(struct arm_smmu_master *master,
 		iopf_queue_remove_device(master->smmu->evtq.iopf, master->dev);
 }
 
+/*
+ * When an array entry's users count reaches zero, it means the ASID/VMID is no
+ * longer being invalidated by map/unmap and must be cleaned. The rule is that
+ * all ASIDs/VMIDs not in an invalidation array are left cleared in the IOTLB.
+ */
+static void arm_smmu_inv_free_asid(struct arm_smmu_inv *inv, bool flush)
+{
+	lockdep_assert_held(&arm_smmu_asid_lock);
+
+	if (inv->type != INV_TYPE_S1_ASID)
+		return;
+	if (refcount_read(&inv->users))
+		return;
+
+	if (flush) {
+		struct arm_smmu_cmdq_ent cmd = {
+			.opcode = inv->nsize_opcode,
+			.tlbi.asid = inv->id,
+		};
+
+		arm_smmu_cmdq_issue_cmd_with_sync(inv->smmu, &cmd);
+	}
+
+	/* Lastly, free the ASID as the last user detached */
+	xa_erase(&arm_smmu_asid_xa, inv->id);
+}
+
+static void arm_smmu_inv_free_vmid(struct arm_smmu_inv *inv, bool flush)
+{
+	lockdep_assert_held(&arm_smmu_asid_lock);
+
+	/* Note S2_VMID using nsize_opcode covers S2_VMID_S1_CLEAR already */
+	if (inv->type != INV_TYPE_S2_VMID)
+		return;
+	if (refcount_read(&inv->users))
+		return;
+
+	if (flush) {
+		struct arm_smmu_cmdq_ent cmd = {
+			.opcode = inv->nsize_opcode,
+			.tlbi.vmid = inv->id,
+		};
+
+		arm_smmu_cmdq_issue_cmd_with_sync(inv->smmu, &cmd);
+	}
+
+	/* Lastly, free the VMID as the last user detached */
+	ida_free(&inv->smmu->vmid_map, inv->id);
+}
+
+static int arm_smmu_inv_alloc_asid(struct arm_smmu_inv *inv, void *data)
+{
+	struct arm_smmu_domain *smmu_domain = data;
+	struct arm_smmu_device *smmu = inv->smmu;
+	u32 asid;
+	int ret;
+
+	lockdep_assert_held(&arm_smmu_asid_lock);
+
+	/* Allocate a new iotlb_tag.id */
+	WARN_ON(inv->type != INV_TYPE_S1_ASID);
+
+	ret = xa_alloc(&arm_smmu_asid_xa, &asid, smmu_domain,
+		       XA_LIMIT(1, (1 << smmu->asid_bits) - 1), GFP_KERNEL);
+	if (ret)
+		return ret;
+	inv->id = asid;
+	return 0;
+}
+
+static int arm_smmu_inv_alloc_vmid(struct arm_smmu_inv *inv, void *data)
+{
+	struct arm_smmu_device *smmu = inv->smmu;
+	int vmid;
+
+	lockdep_assert_held(&arm_smmu_asid_lock);
+
+	WARN_ON(inv->type != INV_TYPE_S2_VMID);
+
+	/* Reserve VMID 0 for stage-2 bypass STEs */
+	vmid = ida_alloc_range(&smmu->vmid_map, 1, (1 << smmu->vmid_bits) - 1,
+			       GFP_KERNEL);
+	if (vmid < 0)
+		return vmid;
+	inv->id = vmid;
+	return 0;
+}
+
 static struct arm_smmu_inv *
 arm_smmu_master_build_inv(struct arm_smmu_master *master,
 			  enum arm_smmu_inv_type type, u32 id, ioasid_t ssid,
@@ -3191,12 +3279,17 @@ arm_smmu_master_build_invs(struct arm_smmu_master *master, bool ats_enabled,
 					       smmu_domain->cd.asid,
 					       IOMMU_NO_PASID, pgsize))
 			return NULL;
+		master->build_invs->alloc_id = arm_smmu_inv_alloc_asid;
+		master->build_invs->free_id = arm_smmu_inv_free_asid;
+		master->build_invs->smmu_domain = smmu_domain;
 		break;
 	case ARM_SMMU_DOMAIN_S2:
 		if (!arm_smmu_master_build_inv(master, INV_TYPE_S2_VMID,
 					       smmu_domain->s2_cfg.vmid,
 					       IOMMU_NO_PASID, pgsize))
 			return NULL;
+		master->build_invs->alloc_id = arm_smmu_inv_alloc_vmid;
+		master->build_invs->free_id = arm_smmu_inv_free_vmid;
 		break;
 	default:
 		WARN_ON(true);
-- 
2.43.0



From nicolinc at nvidia.com  Thu Dec 18 12:26:50 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Thu, 18 Dec 2025 12:26:50 -0800
Subject: [PATCH v1 4/9] iommu/arm-smmu-v3: Use alloc_id/free_id ops in arm_smmu_invs_merge/unref
In-Reply-To: <cover.1766088962.git.nicolinc@nvidia.com>
References: <cover.1766088962.git.nicolinc@nvidia.com>
Message-ID: <54c98cd7092a406d84df0abc9a6cb013aadb619a.1766088962.git.nicolinc@nvidia.com>

If a domain->invs has an iotlb tag (ASID/VMID) for an SMMU, all the devices
behind the SMMU can reuse the same iotlb tag. This exactly matches with the
existing case where attaching multiple devices to the same SMMU domain has
a shared iotlb tag stored in the domain (cd->asid or s2_cfg->vmid).

If a domain->invs doesn't have an iotlb tag for another SMMU, there can be
two cases:
1) This is a new domain so not yet attached to any devices
2) This is a shareable domain that is attached to a device behind one SMMU
   but not yet to the other SMMU.

In either case, a new iotlb tag is required. Call the ->alloc_id op in the
arm_smmu_invs_merge(). The domain->invs arrary will keep it. The allocated
new iotlb tag will be returned to the caller via to_merge arrary.

Relax the arm_smmu_inv_cmp(), to allow sharing an iotlb tag across devices
behind the same SMMU instance.

Similarly, call the ->free_id op in the arm_smmu_invs_unref() when there's
no device using it any more.

Lastly, add a free helper for the revert path of arm_smmu_attach_prepare()
to use.

Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h |  3 +
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 70 +++++++++++++++++++--
 2 files changed, 69 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index e21e95936b05..230ab902a9b6 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -680,6 +680,9 @@ static inline bool arm_smmu_inv_is_ats(const struct arm_smmu_inv *inv)
 	return inv->type == INV_TYPE_ATS || inv->type == INV_TYPE_ATS_FULL;
 }
 
+/* S1_ASID/S2_VMID(S1_CLEAR) types */
+#define arm_smmu_inv_is_iotlb_tag(inv) !arm_smmu_inv_is_ats(inv)
+
 /**
  * struct arm_smmu_invs - Per-domain invalidation array
  * @max_invs: maximum capacity of the flexible array
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 1bf7b7233109..ec370e54b1bc 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1051,6 +1051,9 @@ static int arm_smmu_inv_cmp(const struct arm_smmu_inv *inv_l,
 		return cmp_int((uintptr_t)inv_l->smmu, (uintptr_t)inv_r->smmu);
 	if (inv_l->type != inv_r->type)
 		return cmp_int(inv_l->type, inv_r->type);
+	/* Each SMMU shares a single iotlb tag on a domain, so it is a match */
+	if (arm_smmu_inv_is_iotlb_tag(inv_l))
+		return 0;
 	return cmp_int(inv_l->id, inv_r->id);
 }
 
@@ -1127,9 +1130,52 @@ struct arm_smmu_invs *arm_smmu_invs_merge(struct arm_smmu_invs *invs,
 	size_t i, j;
 	int cmp;
 
-	arm_smmu_invs_for_each_cmp(invs, i, to_merge, j, cmp)
+	arm_smmu_invs_for_each_cmp(invs, i, to_merge, j, cmp) {
+		struct arm_smmu_inv *cur = &to_merge->inv[j];
+
 		num_invs++;
 
+		if (!arm_smmu_inv_is_iotlb_tag(cur))
+			continue;
+
+		/* A matching iotlb tag owned by the same SMMU can be shared */
+		if (cmp == 0) {
+			*cur = invs->inv[i];
+			continue;
+		}
+
+		/* Iterate the base invs array to find if next is a match */
+		if (cmp < 0 && i < invs->num_invs)
+			continue;
+
+		/*
+		 * Currently the @to_merge array always carries an id (> 0) that
+		 * is also installed in the CD/STE. So, we cannot allocate a new
+		 * ID at this moment, because that would misalign with what's in
+		 * the CD/STE. To not break the existing flow, bypass the new ID
+		 * allocating code. We will lift this bypass line once rework is
+		 * done.
+		 */
+		if (cur->id)
+			continue;
+
+		/* No found. Allocate a new one */
+		if (j == 0) {
+			/* KUNIT test doesn't pass in an alloc_id function */
+			if (to_merge->alloc_id) {
+				int ret;
+
+				ret = to_merge->alloc_id(cur,
+							 invs->smmu_domain);
+				if (ret)
+					return ERR_PTR(ret);
+			}
+		} else {
+			/* Copy the allocated iotlb tag from the previous inv */
+			cur->id = cur[-1].id;
+		}
+	}
+
 	new_invs = arm_smmu_invs_alloc(num_invs);
 	if (!new_invs)
 		return ERR_PTR(-ENOMEM);
@@ -1207,9 +1253,9 @@ void arm_smmu_invs_unref(struct arm_smmu_invs *invs,
 				continue;
 			}
 
-			/* KUNIT test doesn't pass in a free_fn */
-			if (free_fn)
-				free_fn(&invs->inv[i]);
+			/* KUNIT test doesn't pass in a free_id function */
+			if (to_unref->free_id)
+				to_unref->free_id(&invs->inv[i], true);
 			invs->num_trashes++;
 		} else {
 			/* item in to_unref is not in invs or already a trash */
@@ -3167,6 +3213,21 @@ static void arm_smmu_inv_free_vmid(struct arm_smmu_inv *inv, bool flush)
 	ida_free(&inv->smmu->vmid_map, inv->id);
 }
 
+static void arm_smmu_inv_free_iotlb_tag(struct arm_smmu_inv *inv)
+{
+	switch (inv->type) {
+	case INV_TYPE_S1_ASID:
+		arm_smmu_inv_free_asid(inv, false);
+		return;
+	case INV_TYPE_S2_VMID:
+		arm_smmu_inv_free_vmid(inv, false);
+		return;
+	default:
+		WARN_ON(true);
+		return;
+	}
+}
+
 static int arm_smmu_inv_alloc_asid(struct arm_smmu_inv *inv, void *data)
 {
 	struct arm_smmu_domain *smmu_domain = data;
@@ -3662,6 +3723,7 @@ int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state,
 err_free_vmaster:
 	kfree(state->vmaster);
 err_unprepare_invs:
+	arm_smmu_inv_free_iotlb_tag(&state->new_domain_invst.iotlb_tag);
 	kfree(state->new_domain_invst.new_invs);
 	return ret;
 }
-- 
2.43.0



From nicolinc at nvidia.com  Thu Dec 18 12:26:52 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Thu, 18 Dec 2025 12:26:52 -0800
Subject: [PATCH v1 6/9] iommu/arm-smmu-v3: Use dummy ASID/VMID in arm_smmu_master_build_invs()
In-Reply-To: <cover.1766088962.git.nicolinc@nvidia.com>
References: <cover.1766088962.git.nicolinc@nvidia.com>
Message-ID: <2cfda3d1f80ca3548a77d5da9261112e3f00a404.1766088962.git.nicolinc@nvidia.com>

The arm_smmu_inv_cmp() function no longer enforces ASID/VMID values on an
iotlb tag entry, to allow sharing an existing tag in the domain->invs. If
no tag is found on the same SMMU, a new tag will be allocated.

Therefore, there is no point in passing in any id to the iotlb entries in
the master->build_invs array. Use a dummy ID=0 that is out of range of an
ID allocation, so as to set free cd->asid and s2_cfg->vmid. An ATS entry
must still have a specific ID.

Since CD/STE has the ASID/VMID coming from the master structure, lift the
cur->id check in arm_smmu_invs_merge(), to use the new ID allocation path.

Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 29 ++++++++-------------
 1 file changed, 11 insertions(+), 18 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index d6ae630d0de3..d51bad1002ff 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1148,17 +1148,6 @@ struct arm_smmu_invs *arm_smmu_invs_merge(struct arm_smmu_invs *invs,
 		if (cmp < 0 && i < invs->num_invs)
 			continue;
 
-		/*
-		 * Currently the @to_merge array always carries an id (> 0) that
-		 * is also installed in the CD/STE. So, we cannot allocate a new
-		 * ID at this moment, because that would misalign with what's in
-		 * the CD/STE. To not break the existing flow, bypass the new ID
-		 * allocating code. We will lift this bypass line once rework is
-		 * done.
-		 */
-		if (cur->id)
-			continue;
-
 		/* No found. Allocate a new one */
 		if (j == 0) {
 			/* KUNIT test doesn't pass in an alloc_id function */
@@ -3331,11 +3320,16 @@ arm_smmu_master_build_invs(struct arm_smmu_master *master, bool ats_enabled,
 	if (master->smmu->features & ARM_SMMU_FEAT_RANGE_INV)
 		pgsize = __ffs(smmu_domain->domain.pgsize_bitmap);
 
+	/*
+	 * Each SMMU has only one iotlb tag in the array, so leave the iotlb tag
+	 * ID to be 0. The merge() and unref() will find the existing one in the
+	 * array to refcount_inc/dec. In case of missing a match, merge() should
+	 * allocate a new ID while unref() should WARN_ON.
+	 */
 	switch (smmu_domain->stage) {
 	case ARM_SMMU_DOMAIN_SVA:
 	case ARM_SMMU_DOMAIN_S1:
-		if (!arm_smmu_master_build_inv(master, INV_TYPE_S1_ASID,
-					       smmu_domain->cd.asid,
+		if (!arm_smmu_master_build_inv(master, INV_TYPE_S1_ASID, 0,
 					       IOMMU_NO_PASID, pgsize))
 			return NULL;
 		master->build_invs->alloc_id = arm_smmu_inv_alloc_asid;
@@ -3343,8 +3337,7 @@ arm_smmu_master_build_invs(struct arm_smmu_master *master, bool ats_enabled,
 		master->build_invs->smmu_domain = smmu_domain;
 		break;
 	case ARM_SMMU_DOMAIN_S2:
-		if (!arm_smmu_master_build_inv(master, INV_TYPE_S2_VMID,
-					       smmu_domain->s2_cfg.vmid,
+		if (!arm_smmu_master_build_inv(master, INV_TYPE_S2_VMID, 0,
 					       IOMMU_NO_PASID, pgsize))
 			return NULL;
 		master->build_invs->alloc_id = arm_smmu_inv_alloc_vmid;
@@ -3357,9 +3350,9 @@ arm_smmu_master_build_invs(struct arm_smmu_master *master, bool ats_enabled,
 
 	/* All the nested S1 ASIDs have to be flushed when S2 parent changes */
 	if (nesting) {
-		if (!arm_smmu_master_build_inv(
-			    master, INV_TYPE_S2_VMID_S1_CLEAR,
-			    smmu_domain->s2_cfg.vmid, IOMMU_NO_PASID, 0))
+		if (!arm_smmu_master_build_inv(master,
+					       INV_TYPE_S2_VMID_S1_CLEAR, 0,
+					       IOMMU_NO_PASID, 0))
 			return NULL;
 	}
 
-- 
2.43.0



From nicolinc at nvidia.com  Thu Dec 18 12:26:51 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Thu, 18 Dec 2025 12:26:51 -0800
Subject: [PATCH v1 5/9] iommu/arm-smmu-v3: Install to CD/STE the ASID/VMID stored in the master
In-Reply-To: <cover.1766088962.git.nicolinc@nvidia.com>
References: <cover.1766088962.git.nicolinc@nvidia.com>
Message-ID: <1fe65cf21f9eb6c82fde80a6591c644d7224146b.1766088962.git.nicolinc@nvidia.com>

Now the iotlb tag (ASID/VMID) allocated in arm_smmu_invs_merge() is stored
in the master, with a proper release and revert pathways. Replace the old
smmu_domain->cd.asid and smmu_domain->s2_cfg.vmid with the master ones.

The old asid/vmid will be depracated.

Note that the nested pathway needs vsmmu->vmid to be updated to align with
the VMID programmed in the STE as its invalidation code will overwrite the
VMID field using vsmmu->vmid.

Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h       |  1 +
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c   | 15 +++++++++++++--
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c   |  4 ++--
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c       | 10 ++++------
 4 files changed, 20 insertions(+), 10 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index 230ab902a9b6..dac412ff0d71 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -1186,6 +1186,7 @@ struct arm_vsmmu {
 	struct iommufd_viommu core;
 	struct arm_smmu_device *smmu;
 	struct arm_smmu_domain *s2_parent;
+	int nr_vmasters;
 	u16 vmid;
 };
 
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c
index 93fdadd07431..1c877d30f86e 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c
@@ -136,6 +136,19 @@ void arm_smmu_attach_commit_vmaster(struct arm_smmu_attach_state *state)
 	struct arm_smmu_master *master = state->master;
 
 	mutex_lock(&master->smmu->streams_mutex);
+
+	/* Clear the old vsmmu's VMID and set the new vsmmu's VMID */
+	if (master->vmaster && master->vmaster->vsmmu) {
+		if (--master->vmaster->vsmmu->nr_vmasters == 0)
+			master->vmaster->vsmmu->vmid = 0;
+		WARN_ON(master->vmaster->vsmmu->nr_vmasters < 0);
+	}
+	if (state->vmaster && state->vmaster->vsmmu) {
+		cmpxchg(&state->vmaster->vsmmu->vmid, 0, master->vmid);
+		WARN_ON(state->vmaster->vsmmu->vmid != master->vmid);
+		state->vmaster->vsmmu->nr_vmasters++;
+	}
+
 	kfree(master->vmaster);
 	master->vmaster = state->vmaster;
 	mutex_unlock(&master->smmu->streams_mutex);
@@ -454,8 +467,6 @@ int arm_vsmmu_init(struct iommufd_viommu *viommu,
 
 	vsmmu->smmu = smmu;
 	vsmmu->s2_parent = s2_parent;
-	/* FIXME Move VMID allocation from the S2 domain allocation to here */
-	vsmmu->vmid = s2_parent->s2_cfg.vmid;
 
 	if (viommu->type == IOMMU_VIOMMU_TYPE_ARM_SMMUV3) {
 		viommu->ops = &arm_vsmmu_ops;
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index adf802f165d1..0e534f2b72e0 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -164,7 +164,7 @@ static void arm_smmu_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
 		if (WARN_ON(!cdptr))
 			continue;
 		arm_smmu_make_sva_cd(&target, master, NULL,
-				     smmu_domain->cd.asid);
+				     master->asid[master_domain->ssid]);
 		arm_smmu_write_cd_entry(master, master_domain->ssid, cdptr,
 					&target);
 	}
@@ -266,7 +266,7 @@ static int arm_smmu_sva_set_dev_pasid(struct iommu_domain *domain,
 	 * This does not need the arm_smmu_asid_lock because SVA domains never
 	 * get reassigned
 	 */
-	arm_smmu_make_sva_cd(&target, master, domain->mm, smmu_domain->cd.asid);
+	arm_smmu_make_sva_cd(&target, master, domain->mm, master->asid[id]);
 	ret = arm_smmu_set_pasid(master, smmu_domain, id, &target, old);
 
 	mmput(domain->mm);
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index ec370e54b1bc..d6ae630d0de3 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1661,7 +1661,6 @@ void arm_smmu_make_s1_cd(struct arm_smmu_cd *target,
 			 struct arm_smmu_master *master,
 			 struct arm_smmu_domain *smmu_domain, ioasid_t ssid)
 {
-	struct arm_smmu_ctx_desc *cd = &smmu_domain->cd;
 	const struct io_pgtable_cfg *pgtbl_cfg =
 		&io_pgtable_ops_to_pgtable(smmu_domain->pgtbl_ops)->cfg;
 	typeof(&pgtbl_cfg->arm_lpae_s1_cfg.tcr) tcr =
@@ -1686,7 +1685,7 @@ void arm_smmu_make_s1_cd(struct arm_smmu_cd *target,
 		CTXDESC_CD_0_R |
 		CTXDESC_CD_0_A |
 		CTXDESC_CD_0_ASET |
-		FIELD_PREP(CTXDESC_CD_0_ASID, cd->asid)
+		FIELD_PREP(CTXDESC_CD_0_ASID, master->asid[ssid])
 		);
 
 	/* To enable dirty flag update, set both Access flag and dirty state update */
@@ -1945,7 +1944,6 @@ void arm_smmu_make_s2_domain_ste(struct arm_smmu_ste *target,
 				 struct arm_smmu_domain *smmu_domain,
 				 bool ats_enabled)
 {
-	struct arm_smmu_s2_cfg *s2_cfg = &smmu_domain->s2_cfg;
 	const struct io_pgtable_cfg *pgtbl_cfg =
 		&io_pgtable_ops_to_pgtable(smmu_domain->pgtbl_ops)->cfg;
 	typeof(&pgtbl_cfg->arm_lpae_s2_cfg.vtcr) vtcr =
@@ -1976,7 +1974,7 @@ void arm_smmu_make_s2_domain_ste(struct arm_smmu_ste *target,
 		   FIELD_PREP(STRTAB_STE_2_VTCR_S2TG, vtcr->tg) |
 		   FIELD_PREP(STRTAB_STE_2_VTCR_S2PS, vtcr->ps);
 	target->data[2] = cpu_to_le64(
-		FIELD_PREP(STRTAB_STE_2_S2VMID, s2_cfg->vmid) |
+		FIELD_PREP(STRTAB_STE_2_S2VMID, master->vmid) |
 		FIELD_PREP(STRTAB_STE_2_VTCR, vtcr_val) |
 		STRTAB_STE_2_S2AA64 |
 #ifdef __BIG_ENDIAN
@@ -3850,7 +3848,7 @@ static int arm_smmu_s1_set_dev_pasid(struct iommu_domain *domain,
 		return -EINVAL;
 
 	/*
-	 * We can read cd.asid outside the lock because arm_smmu_set_pasid()
+	 * We can read master.asid outside the lock because arm_smmu_set_pasid()
 	 * will fix it
 	 */
 	arm_smmu_make_s1_cd(&target_cd, master, smmu_domain, id);
@@ -3921,7 +3919,7 @@ int arm_smmu_set_pasid(struct arm_smmu_master *master,
 	 */
 	cd->data[0] &= ~cpu_to_le64(CTXDESC_CD_0_ASID);
 	cd->data[0] |= cpu_to_le64(
-		FIELD_PREP(CTXDESC_CD_0_ASID, smmu_domain->cd.asid));
+		FIELD_PREP(CTXDESC_CD_0_ASID, master->asid[pasid]));
 
 	arm_smmu_write_cd_entry(master, pasid, cdptr, cd);
 	arm_smmu_update_ste(master, sid_domain, state.ats_enabled);
-- 
2.43.0



From nicolinc at nvidia.com  Thu Dec 18 12:26:55 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Thu, 18 Dec 2025 12:26:55 -0800
Subject: [PATCH v1 9/9] iommu/arm-smmu-v3: Allow sharing domain across SMMUs
In-Reply-To: <cover.1766088962.git.nicolinc@nvidia.com>
References: <cover.1766088962.git.nicolinc@nvidia.com>
Message-ID: <1274d3dbf29ecb23dbcc8efcd56ea63f94662737.1766088963.git.nicolinc@nvidia.com>

VMM needs a domain holding the mappings between gPA to hPA. It can be an S1
domain or an S2 nesting parent domain, depending on whether the VM is built
with a vSMMU or not.

Given that the IOAS for this gPA mapping is the same across SMMU instances,
this domain can be shared across devices even if they sit behind different
SMMUs, so long as the underlying page table is compatible between the SMMU
instances.

There is no direct information about the page table from the master device,
but a comparison can be done between the physical SMMU that the domain was
allocated for and the physical SMMU that the device is behind.

Replace the smmu test in arm_smmu_attach_dev() and arm_vsmmu_init() with a
compatibility test for the S1 and S2 cases respectively. The compatibility
test goes through the physical SMMU parameters that were used to decide the
page table formats.

Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   | 20 +++++++++++++++++++
 .../arm/arm-smmu-v3/arm-smmu-v3-iommufd.c     |  2 +-
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   |  2 +-
 3 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index 4d7b7eb52dfd..d64e4e7c162d 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -992,6 +992,26 @@ struct arm_smmu_nested_domain {
 	__le64 ste[2];
 };
 
+static inline bool
+arm_smmu_domain_can_share(struct arm_smmu_domain *smmu_domain,
+			  struct arm_smmu_device *new_smmu)
+{
+	struct arm_smmu_device *base_smmu = smmu_domain->smmu;
+
+	if (base_smmu == new_smmu)
+		return true;
+	/* Only support identical SMMUs for now */
+	if (base_smmu->features != new_smmu->features)
+		return false;
+	if (base_smmu->iommu.ops != new_smmu->iommu.ops)
+		return false;
+	if (base_smmu->pgsize_bitmap != new_smmu->pgsize_bitmap)
+		return false;
+	if (base_smmu->ias > new_smmu->ias || base_smmu->oas > new_smmu->oas)
+		return false;
+	return true;
+}
+
 /* The following are exposed for testing purposes. */
 struct arm_smmu_entry_writer_ops;
 struct arm_smmu_entry_writer {
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c
index 1c877d30f86e..f2318e31d875 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c
@@ -462,7 +462,7 @@ int arm_vsmmu_init(struct iommufd_viommu *viommu,
 		container_of(viommu->iommu_dev, struct arm_smmu_device, iommu);
 	struct arm_smmu_domain *s2_parent = to_smmu_domain(parent_domain);
 
-	if (s2_parent->smmu != smmu)
+	if (!arm_smmu_domain_can_share(s2_parent, smmu))
 		return -EINVAL;
 
 	vsmmu->smmu = smmu;
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 04e21af9c578..ab329614da1f 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -3684,7 +3684,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev,
 	state.master = master = dev_iommu_priv_get(dev);
 	smmu = master->smmu;
 
-	if (smmu_domain->smmu != smmu)
+	if (!arm_smmu_domain_can_share(smmu_domain, smmu))
 		return -EINVAL;
 
 	if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
-- 
2.43.0



From nicolinc at nvidia.com  Thu Dec 18 12:26:53 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Thu, 18 Dec 2025 12:26:53 -0800
Subject: [PATCH v1 7/9] iommu/arm-smmu-v3: Remove free_fn argument from arm_smmu_invs_unref()
In-Reply-To: <cover.1766088962.git.nicolinc@nvidia.com>
References: <cover.1766088962.git.nicolinc@nvidia.com>
Message-ID: <0520abb3e9f64cc4f5ee6d64b0c72ff2f2718aba.1766088963.git.nicolinc@nvidia.com>

This is dead code now. Remove it.

Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  3 +-
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  |  6 ++--
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 34 ++-----------------
 3 files changed, 6 insertions(+), 37 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index dac412ff0d71..e38d2394e3be 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -1035,8 +1035,7 @@ void arm_smmu_make_sva_cd(struct arm_smmu_cd *target,
 struct arm_smmu_invs *arm_smmu_invs_merge(struct arm_smmu_invs *invs,
 					  struct arm_smmu_invs *to_merge);
 void arm_smmu_invs_unref(struct arm_smmu_invs *invs,
-			 struct arm_smmu_invs *to_unref,
-			 void (*free_fn)(struct arm_smmu_inv *inv));
+			 struct arm_smmu_invs *to_unref);
 struct arm_smmu_invs *arm_smmu_invs_purge(struct arm_smmu_invs *invs);
 #endif
 
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
index ead0d84cc9a0..5c8cb43f849c 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
@@ -632,7 +632,7 @@ static void arm_smmu_v3_invs_test(struct kunit *test)
 				     results2[0], results2[1]);
 
 	/* Test3: unref invs2 (same array) */
-	arm_smmu_invs_unref(test_a, &invs2, NULL);
+	arm_smmu_invs_unref(test_a, &invs2);
 	arm_smmu_v3_invs_test_verify(test, test_a, ARRAY_SIZE(results3[0]),
 				     results3[0], results3[1]);
 	KUNIT_EXPECT_EQ(test, test_a->num_trashes, 0);
@@ -644,7 +644,7 @@ static void arm_smmu_v3_invs_test(struct kunit *test)
 				     results4[0], results4[1]);
 
 	/* Test5: unref invs1 (same array) */
-	arm_smmu_invs_unref(test_b, &invs1, NULL);
+	arm_smmu_invs_unref(test_b, &invs1);
 	arm_smmu_v3_invs_test_verify(test, test_b, ARRAY_SIZE(results5[0]),
 				     results5[0], results5[1]);
 	KUNIT_EXPECT_EQ(test, test_b->num_trashes, 2);
@@ -656,7 +656,7 @@ static void arm_smmu_v3_invs_test(struct kunit *test)
 				     results6[0], results6[1]);
 
 	/* Test7: unref invs3 (same array) */
-	arm_smmu_invs_unref(test_a, &invs3, NULL);
+	arm_smmu_invs_unref(test_a, &invs3);
 	KUNIT_EXPECT_EQ(test, test_a->num_invs, 0);
 	KUNIT_EXPECT_EQ(test, test_a->num_trashes, 0);
 
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index d51bad1002ff..5052988b0e4e 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1203,9 +1203,6 @@ EXPORT_SYMBOL_IF_KUNIT(arm_smmu_invs_merge);
  *                         the user counts without deletions
  * @invs: the base invalidation array
  * @to_unref: an array of invlidations to decrease their user counts
- * @free_fn: A callback function to invoke, when an entry's user count reduces
- *           to 0
- *
  * Return: the number of trash entries in the array, for arm_smmu_invs_purge()
  *
  * This function will not fail. Any entry with users=0 will be marked as trash.
@@ -1223,8 +1220,7 @@ EXPORT_SYMBOL_IF_KUNIT(arm_smmu_invs_merge);
  */
 VISIBLE_IF_KUNIT
 void arm_smmu_invs_unref(struct arm_smmu_invs *invs,
-			 struct arm_smmu_invs *to_unref,
-			 void (*free_fn)(struct arm_smmu_inv *inv))
+			 struct arm_smmu_invs *to_unref)
 {
 	unsigned long flags;
 	size_t num_invs = 0;
@@ -3500,31 +3496,6 @@ arm_smmu_install_new_domain_invs(struct arm_smmu_attach_state *state)
 		state->master->vmid = invst->iotlb_tag.id;
 }
 
-/*
- * When an array entry's users count reaches zero, it means the ASID/VMID is no
- * longer being invalidated by map/unmap and must be cleaned. The rule is that
- * all ASIDs/VMIDs not in an invalidation array are left cleared in the IOTLB.
- */
-static void arm_smmu_inv_flush_iotlb_tag(struct arm_smmu_inv *inv)
-{
-	struct arm_smmu_cmdq_ent cmd = {};
-
-	switch (inv->type) {
-	case INV_TYPE_S1_ASID:
-		cmd.tlbi.asid = inv->id;
-		break;
-	case INV_TYPE_S2_VMID:
-		/* S2_VMID using nsize_opcode covers S2_VMID_S1_CLEAR */
-		cmd.tlbi.vmid = inv->id;
-		break;
-	default:
-		return;
-	}
-
-	cmd.opcode = inv->nsize_opcode;
-	arm_smmu_cmdq_issue_cmd_with_sync(inv->smmu, &cmd);
-}
-
 /* Should be installed after arm_smmu_install_ste_for_dev() */
 static void
 arm_smmu_install_old_domain_invs(struct arm_smmu_attach_state *state)
@@ -3541,8 +3512,7 @@ arm_smmu_install_old_domain_invs(struct arm_smmu_attach_state *state)
 	if (!invst->invs_ptr)
 		return;
 
-	arm_smmu_invs_unref(old_invs, invst->new_invs,
-			    arm_smmu_inv_flush_iotlb_tag);
+	arm_smmu_invs_unref(old_invs, invst->new_invs);
 	*old_iotlb_tag = invst->new_invs->inv[0];
 
 	new_invs = arm_smmu_invs_purge(old_invs);
-- 
2.43.0



From pr-tracker-bot at kernel.org  Thu Dec 18 12:40:09 2025
From: pr-tracker-bot at kernel.org (pr-tracker-bot at kernel.org)
Date: Thu, 18 Dec 2025 20:40:09 +0000
Subject: [GIT PULL] Crypto library fixes for v6.19-rc2
In-Reply-To: <20251218190606.GB21380@sol>
References: <20251218190606.GB21380@sol>
Message-ID: <176609040923.3123986.7208501276249795784.pr-tracker-bot@kernel.org>

The pull request you sent on Thu, 18 Dec 2025 11:06:06 -0800:

> https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git tags/libcrypto-fixes-for-linus

has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/516471569089749163be24b973ea928b56ac20d9

Thank you!

-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html


From francesco at valla.it  Thu Dec 18 13:29:38 2025
From: francesco at valla.it (Francesco Valla)
Date: Thu, 18 Dec 2025 22:29:38 +0100
Subject: [PATCH v4 2/2] arm64: dts: freescale: add support for NXP i.MX93
 FRDM
In-Reply-To: <20251218-fpg-nxp-imx93-frdm-v4-2-cd3a9f6ac89a@pengutronix.de>
References: <20251218-fpg-nxp-imx93-frdm-v4-0-cd3a9f6ac89a@pengutronix.de>
 <20251218-fpg-nxp-imx93-frdm-v4-2-cd3a9f6ac89a@pengutronix.de>
Message-ID: <aURyQsjf7AY09n41@bywater>

On Thu, Dec 18, 2025 at 12:39:22PM +0100, Fabian Pflug wrote:
> The FRDM i.MX 93 development board is a low-cost and compact development
> board featuring the i.MX93 applications processor.
> 
> It features:
> - Dual Cortex-A55
> - 2 GB LPDDR4X / LPDDR4
> - 32 GB eMMC5.1
> - MicroSD slot
> - GbE RJ45 x 2
> - USB2.0 1x Type C, 1x Type A
> 
> This file is based upon the one provided by nxp in their own kernel and
> yocto meta layer for the device, but adapted for mainline.
> 
> Signed-off-by: Haidong Zheng <haidong.zheng at nxp.com>
> Signed-off-by: Danwei Luo <danwei.luo at nxp.com>
> Signed-off-by: Lei Xu <lei.xu at nxp.com>
> Signed-off-by: Fabian Pflug <f.pflug at pengutronix.de>
> ---
>  arch/arm64/boot/dts/freescale/Makefile             |   1 +
>  arch/arm64/boot/dts/freescale/imx93-11x11-frdm.dts | 620 +++++++++++++++++++++
>  2 files changed, 621 insertions(+)
>

Reviewed-by: Francesco Valla <francesco at valla.it>
Tested-by: Francesco Valla <francesco at valla.it>


Thank you!

Regards,
Francesco



From vvidwans at nvidia.com  Thu Dec 18 13:40:50 2025
From: vvidwans at nvidia.com (Vedashree Vidwans)
Date: Thu, 18 Dec 2025 13:40:50 -0800
Subject: [RFC PATCH 5/5] firmware: smccc: lfa: refresh fw details
In-Reply-To: <44635975-326C-4DD2-BCEC-EB04188E954A@nvidia.com>
References: <20251208221319.1524888-1-vvidwans@nvidia.com>
 <20251208221319.1524888-6-vvidwans@nvidia.com>
 <44635975-326C-4DD2-BCEC-EB04188E954A@nvidia.com>
Message-ID: <850dc718-0268-43e5-81cd-2d9d2ec77327@nvidia.com>



On 12/12/25 07:37, Matt Ochs wrote:
>> On Dec 8, 2025, at 16:13, Vedashree Vidwans <vvidwans at nvidia.com> wrote:
>>
>> diff --git a/drivers/firmware/smccc/lfa_fw.c b/drivers/firmware/smccc/lfa_fw.c
>> index 24916fc53420..334090708405 100644
>> --- a/drivers/firmware/smccc/lfa_fw.c
>> +++ b/drivers/firmware/smccc/lfa_fw.c
> ...
>> + /*
>> + * Pass 2:
>> + *    If current FW components number is more than previous list, add new component nodes.
>> + */
>> + for (node_idx; node_idx < num_of_components; node_idx++) {
> 
> drivers/firmware/smccc/lfa_fw.c: In function ?update_fw_images_tree?:
> drivers/firmware/smccc/lfa_fw.c:554:9: warning: statement with no effect [-Wunused-value]
>    554 |         for (node_idx; node_idx < num_of_components; node_idx++) {
>        |         ^~~
> 
> Please drop ?node_idx? from the initializer statement.
> 
Thank you, I will include this change in next update.

Veda


From vvidwans at nvidia.com  Thu Dec 18 13:41:16 2025
From: vvidwans at nvidia.com (Vedashree Vidwans)
Date: Thu, 18 Dec 2025 13:41:16 -0800
Subject: [RFC PATCH 4/5] firmware: smccc: register as platform driver
In-Reply-To: <7E7A2433-67DC-4AED-94E0-E096DA9CF3EB@nvidia.com>
References: <20251208221319.1524888-1-vvidwans@nvidia.com>
 <20251208221319.1524888-5-vvidwans@nvidia.com>
 <7E7A2433-67DC-4AED-94E0-E096DA9CF3EB@nvidia.com>
Message-ID: <3fc13634-43d1-4447-be38-73e68fe7f36c@nvidia.com>



On 12/12/25 07:31, Matt Ochs wrote:
>> On Dec 8, 2025, at 16:13, Vedashree Vidwans <vvidwans at nvidia.com> wrote:
>>
>> diff --git a/drivers/firmware/smccc/lfa_fw.c b/drivers/firmware/smccc/lfa_fw.c
>> index 0e420cefa260..24916fc53420 100644
>> --- a/drivers/firmware/smccc/lfa_fw.c
>> +++ b/drivers/firmware/smccc/lfa_fw.c
> ...
>> +
>> +static int __init lfa_probe(struct platform_device *pdev)
>> +{
> 
> WARNING: modpost: vmlinux: section mismatch in reference: lfa_driver+0x0 (section: .data) -> lfa_probe (section: .init.text)
> 
> __init is not needed here, please remove.

Thank you, I will include this change in next update.

Veda


From m.felsch at pengutronix.de  Thu Dec 18 13:41:02 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Thu, 18 Dec 2025 22:41:02 +0100
Subject: [PATCH v7 1/3] dt-bindings: soc: imx93-media-blk-ctrl: Add PDFC
 subnode to schema and example
In-Reply-To: <7127040f-55ab-4bfa-8795-1df76085470c@kernel.org>
References: <20251202-v6-18-topic-imx93-parallel-display-v7-0-2cce31d64608@pengutronix.de>
 <20251202-v6-18-topic-imx93-parallel-display-v7-1-2cce31d64608@pengutronix.de>
 <705773fc-5aba-4bff-b05e-272e1cd0262c@nxp.com>
 <20251215161706.2ea3wtu3xlwcxxar@pengutronix.de>
 <7127040f-55ab-4bfa-8795-1df76085470c@kernel.org>
Message-ID: <20251218214102.zfv35d2fryz333gl@pengutronix.de>

On 25-12-18, Krzysztof Kozlowski wrote:
> On 15/12/2025 17:17, Marco Felsch wrote:
> > Hi Liu,
> > 
> > On 25-12-08, Liu Ying wrote:
> >> Hi Marco,
> >>
> >> On 12/02/2025, Marco Felsch wrote:
> >>> From: Liu Ying <victor.liu at nxp.com>
> >>>
> >>> i.MX93 SoC mediamix blk-ctrl contains one DISPLAY_MUX register which
> >>> configures parallel display format by using the "PARALLEL_DISP_FORMAT"
> >>> field. Document the Parallel Display Format Configuration(PDFC) subnode
> >>> and add the subnode to example.
> >>>
> >>> Signed-off-by: Liu Ying <victor.liu at nxp.com>
> >>> [m.felsch at pengutronix.de: port to v6.18-rc1]
> >>> [m.felsch at pengutronix.de: add bus-width]
> >>> Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
> >>> ---
> >>>  .../bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml | 92 ++++++++++++++++++++++
> >>>  1 file changed, 92 insertions(+)
> >>>
> >>> diff --git a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> >>> index 34aea58094e55365a2f9c86092f637e533f954ff..6e2d86d9341c75108b492bcbabc8a560d8e707cd 100644
> >>> --- a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> >>> +++ b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> >>> @@ -26,6 +26,12 @@ properties:
> >>>    reg:
> >>>      maxItems: 1
> >>>  
> >>> +  '#address-cells':
> >>> +    const: 1
> >>> +
> >>> +  '#size-cells':
> >>> +    const: 1
> >>> +
> >>>    '#power-domain-cells':
> >>>      const: 1
> >>>  
> >>> @@ -40,6 +46,60 @@ properties:
> >>>      minItems: 8
> >>>      maxItems: 10
> >>>  
> >>> +  bridge at 60:
> >>
> >> The dependency patch series mentioned in cover letter has two links in it's
> >> cover letter.  Reading the patch sets pointed by the two links, we may find
> >> Krzysztof's comments - the child nodes of the blk-ctrl should be completely
> >> documented.
> > 
> > Thanks for pointing this out.
> > 
> > @Krzysztof
> > Requesting to add everything seems not feasible if everything added
> > should be tested too.
> > I don't see why everything should be added in one step, since the base
> > .dtsi isn't added in one step too.
> 
> Because otherwise we do not see entire picture and people post incorrect
> bindings, claiming they are complete picture, like messing nodes with
> addressing and nodes without. So sure, if you do not want to post
> complete picture, we cannot review that complete picture, therefore YOU
> MUST POST CORRECT CODE.

It's not that we don't want to post the complete code, it's rather that
we don't have the projects to cover the complete MEDIA_MIX blk-ctrl.
Albeit it's a very simple IP with just a few (25) registers, all of them
do have a complete different purpose:

- control the AXI QoS and IP Cache
- control the bus NIC settings
- control the camera parallel-input setup
- control the LVDS bridge (LDB) setup
- control the parallel-output (DPI) setup + the MIPI DSI input setup
- control the MIPI DSI PLL Setup

> I will not be taking excuses later "we did not know that such code is
> not allowed". You must know all rules.

I get your point and there are only two options IMHO:
 1st) Step-by-step
 2nd) Big-Bang

Step-by-step:
------------
+ Mainline support as fast as possible for each component
+/- Contributors must be trusted that everything is communicated openly
- Unforeseen issues which may require DT adaptions

Big-Bang
--------
+ Everything bindings + code can be checked by the maintainers
+/- Less trust required, since everything is added but still min. trust
    required
- Unforeseen issues which may require DT adaptions
- No mainline support at all or very late

I can only speak for myself, I don't want to hide anything from you or
other maintainers. But I can't guarantee that everything is 100% correct
and bug-free. I'm quite sure that no one can make such promises.
E.g. I didn't test the simultaneous DPI + DSI + LVDS output. It would be
part of this patchset, if I would have tested this.

Regards,
  Marco

> Best regards,
> Krzysztof
> 

-- 
#gernperDu 
#CallMeByMyFirstName

Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | https://www.pengutronix.de/ |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-9    |


From nicolinc at nvidia.com  Thu Dec 18 13:41:58 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Thu, 18 Dec 2025 13:41:58 -0800
Subject: [PATCH rc v5 3/4] iommu/arm-smmu-v3: Mark STE EATS safe when computing the update sequence
In-Reply-To: <cover.1766093909.git.nicolinc@nvidia.com>
References: <cover.1766093909.git.nicolinc@nvidia.com>
Message-ID: <adf08c3b9f289188aca4fe80e506dca7aa48aa19.1766093909.git.nicolinc@nvidia.com>

From: Jason Gunthorpe <jgg at nvidia.com>

If a VM wants to toggle EATS off at the same time as changing the CFG, the
hypervisor will see EATS change to 0 and insert a V=0 breaking update into
the STE even though the VM did not ask for that.

In bare metal, EATS is ignored by CFG=ABORT/BYPASS, which is why this does
not cause a problem until we have nested where CFG is always a variation of
S2 trans that does use EATS.

Relax the rules for EATS sequencing, we don't need it to be exact because
the enclosing code will always disable ATS at the PCI device if we are
changing EATS. This ensures there are no ATS transactions that can race
with an EATS change so we don't need to carefully sequence these bits.

Fixes: 1e8be08d1c91 ("iommu/arm-smmu-v3: Support IOMMU_DOMAIN_NESTED")
Cc: stable at vger.kernel.org
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 12a9669bcc83..a3b29ad20a82 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1095,6 +1095,15 @@ void arm_smmu_get_ste_update_safe(__le64 *safe_bits)
 	 *  fault records even when MEV == 0.
 	 */
 	safe_bits[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
+
+	/*
+	 * EATS is used to reject and control the ATS behavior of the device. If
+	 * we are changing it away from 0 then we already trust the device to
+	 * use ATS properly and we have sequenced the device's ATS enable in PCI
+	 * config space to prevent it from issuing ATS while we are changing
+	 * EATS.
+	 */
+	safe_bits[1] |= cpu_to_le64(STRTAB_STE_1_EATS);
 }
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_update_safe);
 
-- 
2.43.0



From nicolinc at nvidia.com  Thu Dec 18 13:41:55 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Thu, 18 Dec 2025 13:41:55 -0800
Subject: [PATCH rc v5 0/4] iommu/arm-smmu-v3: Fix hitless STE update in nesting cases
Message-ID: <cover.1766093909.git.nicolinc@nvidia.com>

Occasional C_BAD_STE errors were observed in nesting setups where a device
attached to a nested bypass/identity domain enables PASID.

This occurred when the physical STE was updated from S2-only mode to S1+S2
nesting mode, but the update failed to use the hitless routine that it was
supposed to use. Instead, it cleared STE.V bit to load the CD table, while
the default substream was still actively performing DMA.

It was later found that the diff algorithm in arm_smmu_entry_qword_diff()
enforced an additional critical word due to misaligned MEV and EATS fields
between S2-only and S1+S2 modes.

Both fields are either well-managed or non-critical, so move them to the
"ignored" list to relax the qword diff algorithm.

Additionally, add KUnit test coverage for these nesting STE cases.

This is on Github:
https://github.com/nicolinc/iommufd/commits/smmuv3_ste_fixes/

A host kernel must apply this to fix the bug.

Changelog
v5:
 * Pass in feat to arm_smmu_test_make_s2_ste()
v4:
 https://lore.kernel.org/all/cover.1765945258.git.nicolinc at nvidia.com/
 * s/ignored/update_safe
 * Change entry_set to void
v3:
 https://lore.kernel.org/all/cover.1765334526.git.nicolinc at nvidia.com/
 * Add Reviewed-by from Shuai
 * Add an inline comments in nested test cases
 * Reuse arm_smmu_test_make_cdtable_ste() for nested test cases
v2:
 https://lore.kernel.org/all/cover.1765140287.git.nicolinc at nvidia.com/
 * Fix kunit tests
 * Update commit message and inline comments
 * Keep MEV/EATS in used list by masking them away using ignored_bits
v1:
 https://lore.kernel.org/all/cover.1764982046.git.nicolinc at nvidia.com/

Jason Gunthorpe (3):
  iommu/arm-smmu-v3: Add update_safe bits to fix STE update sequence
  iommu/arm-smmu-v3: Mark STE MEV safe when computing the update
    sequence
  iommu/arm-smmu-v3: Mark STE EATS safe when computing the update
    sequence

Nicolin Chen (1):
  iommu/arm-smmu-v3-test: Add nested s1bypass/s1dssbypass coverage

 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  2 +
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  | 65 ++++++++++++++++++-
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 46 +++++++++++--
 3 files changed, 103 insertions(+), 10 deletions(-)

-- 
2.43.0



From nicolinc at nvidia.com  Thu Dec 18 13:41:56 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Thu, 18 Dec 2025 13:41:56 -0800
Subject: [PATCH rc v5 1/4] iommu/arm-smmu-v3: Add update_safe bits to fix STE update sequence
In-Reply-To: <cover.1766093909.git.nicolinc@nvidia.com>
References: <cover.1766093909.git.nicolinc@nvidia.com>
Message-ID: <58f5af553fa7c3b5fd16f1eb13a81ae428f85678.1766093909.git.nicolinc@nvidia.com>

From: Jason Gunthorpe <jgg at nvidia.com>

C_BAD_STE was observed when updating nested STE from an S1-bypass mode to
an S1DSS-bypass mode. As both modes enabled S2, the used bit is slightly
different than the normal S1-bypass and S1DSS-bypass modes. As a result,
fields like MEV and EATS in S2's used list marked the word1 as a critical
word that requested a STE.V=0. This breaks a hitless update.

However, both MEV and EATS aren't critical in terms of STE update. One
controls the merge of the events and the other controls the ATS that is
managed by the driver at the same time via pci_enable_ats().

Add an arm_smmu_get_ste_update_safe() to allow STE update algorithm to
relax those fields, avoiding the STE update breakages.

After this change, entry_set has no caller checking its return value, so
change it to void.

Note that this change is required by both MEV and EATS fields, which were
introduced in different kernel versions. So add get_update_safe() first.
MEV and EATS will be added to arm_smmu_get_ste_update_safe() separately.

Fixes: 1e8be08d1c91 ("iommu/arm-smmu-v3: Support IOMMU_DOMAIN_NESTED")
Cc: stable at vger.kernel.org
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  2 ++
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  | 18 ++++++++++---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 27 ++++++++++++++-----
 3 files changed, 37 insertions(+), 10 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index ae23aacc3840..a6c976fa9df2 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -900,6 +900,7 @@ struct arm_smmu_entry_writer {
 
 struct arm_smmu_entry_writer_ops {
 	void (*get_used)(const __le64 *entry, __le64 *used);
+	void (*get_update_safe)(__le64 *safe_bits);
 	void (*sync)(struct arm_smmu_entry_writer *writer);
 };
 
@@ -911,6 +912,7 @@ void arm_smmu_make_s2_domain_ste(struct arm_smmu_ste *target,
 
 #if IS_ENABLED(CONFIG_KUNIT)
 void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits);
+void arm_smmu_get_ste_update_safe(__le64 *safe_bits);
 void arm_smmu_write_entry(struct arm_smmu_entry_writer *writer, __le64 *cur,
 			  const __le64 *target);
 void arm_smmu_get_cd_used(const __le64 *ent, __le64 *used_bits);
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
index d2671bfd3798..5db14718fdd6 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
@@ -38,13 +38,16 @@ enum arm_smmu_test_master_feat {
 static bool arm_smmu_entry_differs_in_used_bits(const __le64 *entry,
 						const __le64 *used_bits,
 						const __le64 *target,
+						const __le64 *safe,
 						unsigned int length)
 {
 	bool differs = false;
 	unsigned int i;
 
 	for (i = 0; i < length; i++) {
-		if ((entry[i] & used_bits[i]) != target[i])
+		__le64 used = used_bits[i] & ~safe[i];
+
+		if ((entry[i] & used) != (target[i] & used))
 			differs = true;
 	}
 	return differs;
@@ -56,12 +59,17 @@ arm_smmu_test_writer_record_syncs(struct arm_smmu_entry_writer *writer)
 	struct arm_smmu_test_writer *test_writer =
 		container_of(writer, struct arm_smmu_test_writer, writer);
 	__le64 *entry_used_bits;
+	__le64 *safe;
 
 	entry_used_bits = kunit_kzalloc(
 		test_writer->test, sizeof(*entry_used_bits) * NUM_ENTRY_QWORDS,
 		GFP_KERNEL);
 	KUNIT_ASSERT_NOT_NULL(test_writer->test, entry_used_bits);
 
+	safe = kunit_kzalloc(test_writer->test,
+			     sizeof(*safe) * NUM_ENTRY_QWORDS, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test_writer->test, safe);
+
 	pr_debug("STE value is now set to: ");
 	print_hex_dump_debug("    ", DUMP_PREFIX_NONE, 16, 8,
 			     test_writer->entry,
@@ -79,14 +87,17 @@ arm_smmu_test_writer_record_syncs(struct arm_smmu_entry_writer *writer)
 		 * configuration.
 		 */
 		writer->ops->get_used(test_writer->entry, entry_used_bits);
+		if (writer->ops->get_update_safe)
+			writer->ops->get_update_safe(safe);
 		KUNIT_EXPECT_FALSE(
 			test_writer->test,
 			arm_smmu_entry_differs_in_used_bits(
 				test_writer->entry, entry_used_bits,
-				test_writer->init_entry, NUM_ENTRY_QWORDS) &&
+				test_writer->init_entry, safe,
+				NUM_ENTRY_QWORDS) &&
 				arm_smmu_entry_differs_in_used_bits(
 					test_writer->entry, entry_used_bits,
-					test_writer->target_entry,
+					test_writer->target_entry, safe,
 					NUM_ENTRY_QWORDS));
 	}
 }
@@ -106,6 +117,7 @@ arm_smmu_v3_test_debug_print_used_bits(struct arm_smmu_entry_writer *writer,
 static const struct arm_smmu_entry_writer_ops test_ste_ops = {
 	.sync = arm_smmu_test_writer_record_syncs,
 	.get_used = arm_smmu_get_ste_used,
+	.get_update_safe = arm_smmu_get_ste_update_safe,
 };
 
 static const struct arm_smmu_entry_writer_ops test_cd_ops = {
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index d16d35c78c06..8dbf4ad5b51e 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1082,6 +1082,12 @@ void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits)
 }
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_used);
 
+VISIBLE_IF_KUNIT
+void arm_smmu_get_ste_update_safe(__le64 *safe_bits)
+{
+}
+EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_update_safe);
+
 /*
  * Figure out if we can do a hitless update of entry to become target. Returns a
  * bit mask where 1 indicates that qword needs to be set disruptively.
@@ -1094,13 +1100,22 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
 {
 	__le64 target_used[NUM_ENTRY_QWORDS] = {};
 	__le64 cur_used[NUM_ENTRY_QWORDS] = {};
+	__le64 safe[NUM_ENTRY_QWORDS] = {};
 	u8 used_qword_diff = 0;
 	unsigned int i;
 
 	writer->ops->get_used(entry, cur_used);
 	writer->ops->get_used(target, target_used);
+	if (writer->ops->get_update_safe)
+		writer->ops->get_update_safe(safe);
 
 	for (i = 0; i != NUM_ENTRY_QWORDS; i++) {
+		/*
+		 * Safe is only used for bits that are used by both entries,
+		 * otherwise it is sequenced according to the unused entry.
+		 */
+		safe[i] &= target_used[i] & cur_used[i];
+
 		/*
 		 * Check that masks are up to date, the make functions are not
 		 * allowed to set a bit to 1 if the used function doesn't say it
@@ -1109,6 +1124,7 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
 		WARN_ON_ONCE(target[i] & ~target_used[i]);
 
 		/* Bits can change because they are not currently being used */
+		cur_used[i] &= ~safe[i];
 		unused_update[i] = (entry[i] & cur_used[i]) |
 				   (target[i] & ~cur_used[i]);
 		/*
@@ -1121,7 +1137,7 @@ static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
 	return used_qword_diff;
 }
 
-static bool entry_set(struct arm_smmu_entry_writer *writer, __le64 *entry,
+static void entry_set(struct arm_smmu_entry_writer *writer, __le64 *entry,
 		      const __le64 *target, unsigned int start,
 		      unsigned int len)
 {
@@ -1137,7 +1153,6 @@ static bool entry_set(struct arm_smmu_entry_writer *writer, __le64 *entry,
 
 	if (changed)
 		writer->ops->sync(writer);
-	return changed;
 }
 
 /*
@@ -1207,12 +1222,9 @@ void arm_smmu_write_entry(struct arm_smmu_entry_writer *writer, __le64 *entry,
 		entry_set(writer, entry, target, 0, 1);
 	} else {
 		/*
-		 * No inuse bit changed. Sanity check that all unused bits are 0
-		 * in the entry. The target was already sanity checked by
-		 * compute_qword_diff().
+		 * No inuse bit changed, though safe bits may have changed.
 		 */
-		WARN_ON_ONCE(
-			entry_set(writer, entry, target, 0, NUM_ENTRY_QWORDS));
+		entry_set(writer, entry, target, 0, NUM_ENTRY_QWORDS);
 	}
 }
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_write_entry);
@@ -1543,6 +1555,7 @@ static void arm_smmu_ste_writer_sync_entry(struct arm_smmu_entry_writer *writer)
 static const struct arm_smmu_entry_writer_ops arm_smmu_ste_writer_ops = {
 	.sync = arm_smmu_ste_writer_sync_entry,
 	.get_used = arm_smmu_get_ste_used,
+	.get_update_safe = arm_smmu_get_ste_update_safe,
 };
 
 static void arm_smmu_write_ste(struct arm_smmu_master *master, u32 sid,
-- 
2.43.0



From nicolinc at nvidia.com  Thu Dec 18 13:41:57 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Thu, 18 Dec 2025 13:41:57 -0800
Subject: [PATCH rc v5 2/4] iommu/arm-smmu-v3: Mark STE MEV safe when computing the update sequence
In-Reply-To: <cover.1766093909.git.nicolinc@nvidia.com>
References: <cover.1766093909.git.nicolinc@nvidia.com>
Message-ID: <83f991cbbb1331213aabe7c1fc5f725e79f60ecd.1766093909.git.nicolinc@nvidia.com>

From: Jason Gunthorpe <jgg at nvidia.com>

Nested CD tables set the MEV bit to try to reduce multi-fault spamming on
the hypervisor. Since MEV is in STE word 1 this causes a breaking update
sequence that is not required and impacts real workloads.

For the purposes of STE updates the value of MEV doesn't matter, if it is
set/cleared early or late it just results in a change to the fault reports
that must be supported by the kernel anyhow. The spec says:

 Note: Software must expect, and be able to deal with, coalesced fault
 records even when MEV == 0.

So mark STE MEV safe when computing the update sequence, to avoid creating
a breaking update.

Fixes: da0c56520e88 ("iommu/arm-smmu-v3: Set MEV bit in nested STE for DoS mitigations")
Cc: stable at vger.kernel.org
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 8dbf4ad5b51e..12a9669bcc83 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1085,6 +1085,16 @@ EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_used);
 VISIBLE_IF_KUNIT
 void arm_smmu_get_ste_update_safe(__le64 *safe_bits)
 {
+	/*
+	 * MEV does not meaningfully impact the operation of the HW, it only
+	 * changes how many fault events are generated, thus we can relax it
+	 * when computing the ordering. The spec notes the device can act like
+	 * MEV=1 anyhow:
+	 *
+	 *  Note: Software must expect, and be able to deal with, coalesced
+	 *  fault records even when MEV == 0.
+	 */
+	safe_bits[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
 }
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_update_safe);
 
-- 
2.43.0



From nicolinc at nvidia.com  Thu Dec 18 13:41:59 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Thu, 18 Dec 2025 13:41:59 -0800
Subject: [PATCH rc v5 4/4] iommu/arm-smmu-v3-test: Add nested s1bypass/s1dssbypass coverage
In-Reply-To: <cover.1766093909.git.nicolinc@nvidia.com>
References: <cover.1766093909.git.nicolinc@nvidia.com>
Message-ID: <68d48a88a64223a1d9b76b59c05f4743f1953c9c.1766093909.git.nicolinc@nvidia.com>

STE in a nested case requires both S1 and S2 fields. And this makes the use
case different from the existing one.

Add coverage for previously failed cases shifting between S2-only and S1+S2
STEs.

Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  | 47 +++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
index 5db14718fdd6..4a072c2c367c 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
@@ -33,8 +33,12 @@ static struct mm_struct sva_mm = {
 enum arm_smmu_test_master_feat {
 	ARM_SMMU_MASTER_TEST_ATS = BIT(0),
 	ARM_SMMU_MASTER_TEST_STALL = BIT(1),
+	ARM_SMMU_MASTER_TEST_NESTED = BIT(2),
 };
 
+static void arm_smmu_test_make_s2_ste(struct arm_smmu_ste *ste,
+				      enum arm_smmu_test_master_feat feat);
+
 static bool arm_smmu_entry_differs_in_used_bits(const __le64 *entry,
 						const __le64 *used_bits,
 						const __le64 *target,
@@ -197,6 +201,18 @@ static void arm_smmu_test_make_cdtable_ste(struct arm_smmu_ste *ste,
 	};
 
 	arm_smmu_make_cdtable_ste(ste, &master, ats_enabled, s1dss);
+	if (feat & ARM_SMMU_MASTER_TEST_NESTED) {
+		struct arm_smmu_ste s2ste;
+		int i;
+
+		arm_smmu_test_make_s2_ste(&s2ste,
+					  feat & ~ARM_SMMU_MASTER_TEST_NESTED);
+		ste->data[0] |= cpu_to_le64(
+			FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_NESTED));
+		ste->data[1] |= cpu_to_le64(STRTAB_STE_1_MEV);
+		for (i = 2; i < NUM_ENTRY_QWORDS; i++)
+			ste->data[i] = s2ste.data[i];
+	}
 }
 
 static void arm_smmu_v3_write_ste_test_bypass_to_abort(struct kunit *test)
@@ -554,6 +570,35 @@ static void arm_smmu_v3_write_ste_test_s2_to_s1_stall(struct kunit *test)
 						       NUM_EXPECTED_SYNCS(3));
 }
 
+static void
+arm_smmu_v3_write_ste_test_nested_s1dssbypass_to_s1bypass(struct kunit *test)
+{
+	struct arm_smmu_ste s1_ste;
+	struct arm_smmu_ste s2_ste;
+
+	arm_smmu_test_make_cdtable_ste(
+		&s1_ste, STRTAB_STE_1_S1DSS_BYPASS, fake_cdtab_dma_addr,
+		ARM_SMMU_MASTER_TEST_ATS | ARM_SMMU_MASTER_TEST_NESTED);
+	arm_smmu_test_make_s2_ste(&s2_ste, 0);
+	/* Expect an additional sync to unset ignored bits: EATS and MEV */
+	arm_smmu_v3_test_ste_expect_hitless_transition(test, &s1_ste, &s2_ste,
+						       NUM_EXPECTED_SYNCS(3));
+}
+
+static void
+arm_smmu_v3_write_ste_test_nested_s1bypass_to_s1dssbypass(struct kunit *test)
+{
+	struct arm_smmu_ste s1_ste;
+	struct arm_smmu_ste s2_ste;
+
+	arm_smmu_test_make_cdtable_ste(
+		&s1_ste, STRTAB_STE_1_S1DSS_BYPASS, fake_cdtab_dma_addr,
+		ARM_SMMU_MASTER_TEST_ATS | ARM_SMMU_MASTER_TEST_NESTED);
+	arm_smmu_test_make_s2_ste(&s2_ste, 0);
+	arm_smmu_v3_test_ste_expect_hitless_transition(test, &s2_ste, &s1_ste,
+						       NUM_EXPECTED_SYNCS(2));
+}
+
 static void arm_smmu_v3_write_cd_test_sva_clear(struct kunit *test)
 {
 	struct arm_smmu_cd cd = {};
@@ -600,6 +645,8 @@ static struct kunit_case arm_smmu_v3_test_cases[] = {
 	KUNIT_CASE(arm_smmu_v3_write_cd_test_s1_change_asid),
 	KUNIT_CASE(arm_smmu_v3_write_ste_test_s1_to_s2_stall),
 	KUNIT_CASE(arm_smmu_v3_write_ste_test_s2_to_s1_stall),
+	KUNIT_CASE(arm_smmu_v3_write_ste_test_nested_s1dssbypass_to_s1bypass),
+	KUNIT_CASE(arm_smmu_v3_write_ste_test_nested_s1bypass_to_s1dssbypass),
 	KUNIT_CASE(arm_smmu_v3_write_cd_test_sva_clear),
 	KUNIT_CASE(arm_smmu_v3_write_cd_test_sva_release),
 	{},
-- 
2.43.0



From dmitry.torokhov at gmail.com  Thu Dec 18 14:19:55 2025
From: dmitry.torokhov at gmail.com (Dmitry Torokhov)
Date: Thu, 18 Dec 2025 14:19:55 -0800
Subject: [PATCH] Input: apple_z2: Fix reading incorrect reports after
 exiting sleep
In-Reply-To: <20251218-z2-init-fix-v1-1-48e3aa239caf@gmail.com>
References: <20251218-z2-init-fix-v1-1-48e3aa239caf@gmail.com>
Message-ID: <snwkpf4esyxxhyo2yzq5xepgoh6nkvvqldbiqpj6zm3bbc43zn@gdsxdsza564a>

On Thu, Dec 18, 2025 at 09:11:26AM +0100, Sasha Finkelstein via B4 Relay wrote:
> From: Sasha Finkelstein <fnkl.kernel at gmail.com>
> 
> Under certain conditions (more prevalent after a suspend/resume cycle),
> the touchscreen controller can send the "boot complete" interrupt before
> it actually finished booting. In those cases, attempting to read touch
> data resuls in a stream of "not ready" messages being read and
> interpreted as a touch report. Check that the response is in fact a
> touch report and discard it otherwise.
> 
> Reported-by: pitust <piotr at stelmaszek.com>
> Closes: https://oftc.catirclogs.org/asahi/2025-12-17#34878715;
> Fixes: 471a92f8a21a ("Input: apple_z2 - add a driver for Apple Z2 touchscreens")
> Signed-off-by: Sasha Finkelstein <fnkl.kernel at gmail.com>

Applied, thank you.

-- 
Dmitry


From rebecca at bsdio.com  Thu Dec 18 14:26:14 2025
From: rebecca at bsdio.com (Rebecca Cran)
Date: Thu, 18 Dec 2025 15:26:14 -0700
Subject: [PATCH v6 1/2] dt-bindings: arm: aspeed: add ASRock Rack ALTRAD8
 board
In-Reply-To: <d215c5dd-b402-4cd2-b4c6-48358b5b2491@kernel.org>
References: <20251218161816.38155-1-rebecca@bsdio.com>
 <20251218161816.38155-2-rebecca@bsdio.com>
 <5aa36c56-798a-40cc-b0b8-be3f7c92136f@kernel.org>
 <4eff8506-8049-46e9-997e-a41edff32bbc@bsdio.com>
 <d215c5dd-b402-4cd2-b4c6-48358b5b2491@kernel.org>
Message-ID: <b28d5c56-59ee-4723-b953-cca6629ef63f@bsdio.com>

On 12/18/25 12:31, Krzysztof Kozlowski wrote:
> This does not test anything from the binding.
>
> Please don't add fake tests... Building instructions are not testing.

Sorry. In that case I don't know how to test the bindings.


--?
Rebecca Cran




From devnull+amitsd.google.com at kernel.org  Thu Dec 18 14:49:05 2025
From: devnull+amitsd.google.com at kernel.org (Amit Sunil Dhamne via B4 Relay)
Date: Thu, 18 Dec 2025 22:49:05 +0000
Subject: [PATCH v2 0/5] Introduce MAX77759 charger driver
Message-ID: <20251218-max77759-charger-v2-0-2b259980a686@google.com>

MAX77759 PMIC is used in Pixel 6 and 6 Pro (Oriole/Raven) boards.
One of the functions of the MAX77759 PMIC is a battery charger. This
patchset introduces a driver for this function. One of the unique
features of this charger driver is that it works with a USB input where
the Type-C controller is TCPCI based.

Changes to the board files will follow soon once this patchset is reviewed.

For reference to the MAX77759 MFD based patchset (present in upstream):
https://lore.kernel.org/all/20250509-max77759-mfd-v10-0-962ac15ee3ef at linaro.org/

Signed-off-by: Amit Sunil Dhamne <amitsd at google.com>
---
Changes in v2:
- Fold charger binding in maxim,max77759-charger.yaml to its parent
  node. (Krzysztof Kozlowski)
- Renamed regulator supplier & consumer. (Krzysztof Kozlowski & Heikki
  Krogerus)
- Removed explicit setting of irq trigger types in max77759 driver.
  (Andr? Draszik & Krzysztof Kozlowski)
- Complete bit definitions for IRQ registers. (Andr? Draszik)
- Consolidate all bit definitions for charger IP in mfd/max77759.h.
  (Andr? Draszik)
- Modify the handling of charger IRQs such that regmap IRQ chip handles
  masking, de-mux and acking of interrupts. (Andr? Draszik)
- Remove unused macro definitions relating to Charger modes in tcpci
  maxim driver (Andr? Draszik)
- Add dependency on Regulator class in Kconfig definition for max77759
  chg. (Kernel Test Robot)
- Link to v1: https://lore.kernel.org/r/20251123-max77759-charger-v1-0-6b2e4b8f7f54 at google.com

---
Amit Sunil Dhamne (5):
      dt-bindings: mfd: maxim,max77759: add charger child node
      dt-bindings: usb: maxim,max33359: Add supply property for vbus
      mfd: max77759: add register bitmasks and modify irq configs for charger
      power: supply: max77759: add charger driver
      usb: typec: tcpm/tcpci_maxim: deprecate WAR for setting charger mode

 .../devicetree/bindings/mfd/maxim,max77759.yaml    |  33 +
 .../devicetree/bindings/usb/maxim,max33359.yaml    |   4 +
 MAINTAINERS                                        |   7 +
 drivers/mfd/max77759.c                             |  94 ++-
 drivers/power/supply/Kconfig                       |  11 +
 drivers/power/supply/Makefile                      |   1 +
 drivers/power/supply/max77759_charger.c            | 754 +++++++++++++++++++++
 drivers/usb/typec/tcpm/tcpci_maxim.h               |   1 +
 drivers/usb/typec/tcpm/tcpci_maxim_core.c          |  54 +-
 include/linux/mfd/max77759.h                       | 202 +++++-
 10 files changed, 1102 insertions(+), 59 deletions(-)
---
base-commit: 39f90c1967215375f7d87b81d14b0f3ed6b40c29
change-id: 20251105-max77759-charger-852b626d661a

Best regards,
-- 
Amit Sunil Dhamne <amitsd at google.com>




From devnull+amitsd.google.com at kernel.org  Thu Dec 18 14:49:07 2025
From: devnull+amitsd.google.com at kernel.org (Amit Sunil Dhamne via B4 Relay)
Date: Thu, 18 Dec 2025 22:49:07 +0000
Subject: [PATCH v2 2/5] dt-bindings: usb: maxim,max33359: Add supply
 property for vbus
In-Reply-To: <20251218-max77759-charger-v2-0-2b259980a686@google.com>
References: <20251218-max77759-charger-v2-0-2b259980a686@google.com>
Message-ID: <20251218-max77759-charger-v2-2-2b259980a686@google.com>

From: Amit Sunil Dhamne <amitsd at google.com>

Add a regulator supply property for vbus. This notifies the regulator
provider to source vbus when Type-C operates in Source power mode,
while turn off sourcing vbus when operating in Sink mode or
disconnected.

Signed-off-by: Amit Sunil Dhamne <amitsd at google.com>
---
 Documentation/devicetree/bindings/usb/maxim,max33359.yaml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/usb/maxim,max33359.yaml b/Documentation/devicetree/bindings/usb/maxim,max33359.yaml
index 3de4dc40b791..e652a24902ea 100644
--- a/Documentation/devicetree/bindings/usb/maxim,max33359.yaml
+++ b/Documentation/devicetree/bindings/usb/maxim,max33359.yaml
@@ -32,6 +32,9 @@ properties:
     description:
       Properties for usb c connector.
 
+  vbus-supply:
+    description: Regulator to control sourcing Vbus.
+
 required:
   - compatible
   - reg
@@ -53,6 +56,7 @@ examples:
             reg = <0x25>;
             interrupt-parent = <&gpa8>;
             interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+            vbus-supply = <&chgin_otg_reg>;
 
             connector {
                 compatible = "usb-c-connector";

-- 
2.52.0.322.g1dd061c0dc-goog




From devnull+amitsd.google.com at kernel.org  Thu Dec 18 14:49:06 2025
From: devnull+amitsd.google.com at kernel.org (Amit Sunil Dhamne via B4 Relay)
Date: Thu, 18 Dec 2025 22:49:06 +0000
Subject: [PATCH v2 1/5] dt-bindings: mfd: maxim,max77759: add charger child
 node
In-Reply-To: <20251218-max77759-charger-v2-0-2b259980a686@google.com>
References: <20251218-max77759-charger-v2-0-2b259980a686@google.com>
Message-ID: <20251218-max77759-charger-v2-1-2b259980a686@google.com>

From: Amit Sunil Dhamne <amitsd at google.com>

The Maxim MAX77759 MFD includes a charger function. Extend the max77759
binding to include the charger. Also, update the example to include
charger.

Signed-off-by: Amit Sunil Dhamne <amitsd at google.com>
---
 .../devicetree/bindings/mfd/maxim,max77759.yaml    | 33 ++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml b/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml
index 525de9ab3c2b..1cffdf2e5776 100644
--- a/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml
+++ b/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml
@@ -37,6 +37,30 @@ properties:
   nvmem-0:
     $ref: /schemas/nvmem/maxim,max77759-nvmem.yaml
 
+  charger:
+    type: object
+    description: This is a dual input switch mode battery charger for portable
+      applications. It supports wired and wireless charging and can operate in
+      buck and boost mode.
+
+    allOf:
+      - $ref: /schemas/power/supply/power-supply.yaml#
+
+    properties:
+      compatible:
+        const: maxim,max77759-charger
+
+      chgin-otg-regulator:
+        type: object
+        description: Provides Boost for sourcing VBUS.
+        $ref: /schemas/regulator/regulator.yaml#
+        unevaluatedProperties: false
+
+    required:
+      - compatible
+
+    unevaluatedProperties: false
+
 required:
   - compatible
   - interrupts
@@ -95,5 +119,14 @@ examples:
                     };
                 };
             };
+
+            charger {
+                compatible = "maxim,max77759-charger";
+                power-supplies = <&maxtcpci>;
+
+                chgin-otg-regulator {
+                    regulator-name = "chgin-otg";
+                };
+            };
         };
     };

-- 
2.52.0.322.g1dd061c0dc-goog




From devnull+amitsd.google.com at kernel.org  Thu Dec 18 14:49:09 2025
From: devnull+amitsd.google.com at kernel.org (Amit Sunil Dhamne via B4 Relay)
Date: Thu, 18 Dec 2025 22:49:09 +0000
Subject: [PATCH v2 4/5] power: supply: max77759: add charger driver
In-Reply-To: <20251218-max77759-charger-v2-0-2b259980a686@google.com>
References: <20251218-max77759-charger-v2-0-2b259980a686@google.com>
Message-ID: <20251218-max77759-charger-v2-4-2b259980a686@google.com>

From: Amit Sunil Dhamne <amitsd at google.com>

Add support for MAX77759 battery charger driver. This is a 4A 1-Cell
Li+/LiPoly dual input switch mode charger. While the device can support
USB & wireless charger inputs, this implementation only supports USB
input. This implementation supports both buck and boost modes.

Signed-off-by: Amit Sunil Dhamne <amitsd at google.com>
---
 MAINTAINERS                             |   7 +
 drivers/mfd/max77759.c                  |   3 +-
 drivers/power/supply/Kconfig            |  11 +
 drivers/power/supply/Makefile           |   1 +
 drivers/power/supply/max77759_charger.c | 754 ++++++++++++++++++++++++++++++++
 5 files changed, 775 insertions(+), 1 deletion(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index fed6cd812d79..f1b1015c08b5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15053,6 +15053,13 @@ F:	drivers/mfd/max77759.c
 F:	drivers/nvmem/max77759-nvmem.c
 F:	include/linux/mfd/max77759.h
 
+MAXIM MAX77759 BATTERY CHARGER DRIVER
+M:	Amit Sunil Dhamne <amitsd at google.com>
+L:	linux-kernel at vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/power/supply/maxim,max77759-charger.yaml
+F:	drivers/power/supply/max77759_charger.c
+
 MAXIM MAX77802 PMIC REGULATOR DEVICE DRIVER
 M:	Javier Martinez Canillas <javier at dowhile0.org>
 L:	linux-kernel at vger.kernel.org
diff --git a/drivers/mfd/max77759.c b/drivers/mfd/max77759.c
index a5f7da003edd..368266e2c7f3 100644
--- a/drivers/mfd/max77759.c
+++ b/drivers/mfd/max77759.c
@@ -415,7 +415,8 @@ static const struct mfd_cell max77759_maxq_cells[] = {
 };
 
 static const struct mfd_cell max77759_charger_cells[] = {
-	MFD_CELL_RES("max77759-charger", max77759_charger_resources),
+	MFD_CELL_OF("max77759-charger", max77759_charger_resources, NULL, 0, 0,
+		    "maxim,max77759-charger"),
 };
 
 int max77759_maxq_command(struct max77759 *max77759,
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 79ddb006e2da..4d8685fa3adb 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -1074,4 +1074,15 @@ config FUEL_GAUGE_MM8013
 	  the state of charge, temperature, cycle count, actual and design
 	  capacity, etc.
 
+config CHARGER_MAX77759
+	tristate "MAX77759 Charger Driver"
+	depends on MFD_MAX77759 && REGULATOR
+	default MFD_MAX77759
+	help
+	  Say M or Y here to enable the MAX77759 Charger Driver. MAX77759
+	  charger is a function of the MAX77759 PMIC. This is a dual input
+	  switch-mode charger. This driver supports buck and OTG boost modes.
+
+	  If built as a module, it will be called max77759_charger.
+
 endif # POWER_SUPPLY
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index f943c9150b32..12669734cfe3 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -122,3 +122,4 @@ obj-$(CONFIG_CHARGER_SURFACE)	+= surface_charger.o
 obj-$(CONFIG_BATTERY_UG3105)	+= ug3105_battery.o
 obj-$(CONFIG_CHARGER_QCOM_SMB2)	+= qcom_smbx.o
 obj-$(CONFIG_FUEL_GAUGE_MM8013)	+= mm8013.o
+obj-$(CONFIG_CHARGER_MAX77759)	+= max77759_charger.o
diff --git a/drivers/power/supply/max77759_charger.c b/drivers/power/supply/max77759_charger.c
new file mode 100644
index 000000000000..d1b82578aeb9
--- /dev/null
+++ b/drivers/power/supply/max77759_charger.c
@@ -0,0 +1,754 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * max77759_charger.c - Battery charger driver for MAX77759 charger device.
+ *
+ * Copyright 2025 Google LLC.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/devm-helpers.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/math64.h>
+#include <linux/mfd/max77759.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/string_choices.h>
+
+/* Default values for Fast Charge Current & Float Voltage */
+#define CHG_CC_DEFAULT_UA			2266770
+#define CHG_FV_DEFAULT_MV			4300
+
+#define FOREACH_IRQ(S)			\
+	S(AICL),			\
+	S(CHGIN),			\
+	S(CHG),				\
+	S(INLIM),			\
+	S(BAT_OILO),			\
+	S(CHG_STA_CC),			\
+	S(CHG_STA_CV),			\
+	S(CHG_STA_TO),			\
+	S(CHG_STA_DONE)
+
+#define GENERATE_ENUM(e)		e
+#define GENERATE_STRING(s)		#s
+
+enum {
+	FOREACH_IRQ(GENERATE_ENUM)
+};
+
+static const char *const chgr_irqs_str[] = {
+	FOREACH_IRQ(GENERATE_STRING)
+};
+
+static int irqs[ARRAY_SIZE(chgr_irqs_str)];
+
+struct max77759_charger {
+	struct device *dev;
+	struct regmap *regmap;
+	struct power_supply *psy;
+	struct regulator_dev *chgin_otg_rdev;
+	struct notifier_block nb;
+	struct power_supply *tcpm_psy;
+	struct work_struct psy_work;
+	struct mutex lock; /* protects the state below */
+	enum max77759_chgr_mode mode;
+};
+
+static inline int regval_to_val(int reg, int reg_offset, int step, int minval)
+{
+	return ((reg - reg_offset) * step) + minval;
+}
+
+static inline int val_to_regval(int val, int minval, int step, int reg_offset)
+{
+	s64 dividend;
+
+	if (unlikely(step == 0))
+		return reg_offset;
+
+	dividend = (s64)val - minval;
+	return DIV_S64_ROUND_CLOSEST(dividend, step) + reg_offset;
+}
+
+static inline int unlock_prot_regs(struct max77759_charger *chg, bool unlock)
+{
+	return regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_06,
+				  MAX77759_CHGR_REG_CHG_CNFG_06_CHGPROT, unlock
+				  ? MAX77759_CHGR_REG_CHG_CNFG_06_CHGPROT : 0);
+}
+
+static int charger_input_valid(struct max77759_charger *chg)
+{
+	u32 val;
+	int ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_INT_OK, &val);
+	if (ret)
+		return ret;
+
+	return (val & MAX77759_CHGR_REG_CHG_INT_CHG) &&
+		(val & MAX77759_CHGR_REG_CHG_INT_CHGIN);
+}
+
+static int get_online(struct max77759_charger *chg)
+{
+	u32 val;
+	int ret;
+
+	ret = charger_input_valid(chg);
+	if (ret <= 0)
+		return ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_DETAILS_02, &val);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&chg->lock);
+	return (val & MAX77759_CHGR_REG_CHG_DETAILS_02_CHGIN_STS) &&
+		(chg->mode == MAX77759_CHGR_MODE_CHG_BUCK_ON);
+}
+
+static int get_status(struct max77759_charger *chg)
+{
+	u32 val;
+	int ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_DETAILS_01, &val);
+	if (ret)
+		return ret;
+
+	switch (FIELD_GET(MAX77759_CHGR_REG_CHG_DETAILS_01_CHG_DTLS, val)) {
+	case MAX77759_CHGR_CHG_DTLS_PREQUAL:
+	case MAX77759_CHGR_CHG_DTLS_CC:
+	case MAX77759_CHGR_CHG_DTLS_CV:
+	case MAX77759_CHGR_CHG_DTLS_TO:
+		return POWER_SUPPLY_STATUS_CHARGING;
+	case MAX77759_CHGR_CHG_DTLS_DONE:
+		return POWER_SUPPLY_STATUS_FULL;
+	case MAX77759_CHGR_CHG_DTLS_TIMER_FAULT:
+	case MAX77759_CHGR_CHG_DTLS_SUSP_BATT_THM:
+	case MAX77759_CHGR_CHG_DTLS_OFF_WDOG_TIMER:
+	case MAX77759_CHGR_CHG_DTLS_SUSP_JEITA:
+		return POWER_SUPPLY_STATUS_NOT_CHARGING;
+	case MAX77759_CHGR_CHG_DTLS_OFF:
+		return POWER_SUPPLY_STATUS_DISCHARGING;
+	default:
+		break;
+	}
+
+	return POWER_SUPPLY_STATUS_UNKNOWN;
+}
+
+static int get_charge_type(struct max77759_charger *chg)
+{
+	u32 val;
+	int ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_DETAILS_01, &val);
+	if (ret)
+		return ret;
+
+	switch (FIELD_GET(MAX77759_CHGR_REG_CHG_DETAILS_01_CHG_DTLS, val)) {
+	case MAX77759_CHGR_CHG_DTLS_PREQUAL:
+		return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+	case MAX77759_CHGR_CHG_DTLS_CC:
+		return POWER_SUPPLY_CHARGE_TYPE_FAST;
+	case MAX77759_CHGR_CHG_DTLS_CV:
+	case MAX77759_CHGR_CHG_DTLS_TO:
+		return POWER_SUPPLY_CHARGE_TYPE_STANDARD;
+	case MAX77759_CHGR_CHG_DTLS_DONE:
+	case MAX77759_CHGR_CHG_DTLS_TIMER_FAULT:
+	case MAX77759_CHGR_CHG_DTLS_SUSP_BATT_THM:
+	case MAX77759_CHGR_CHG_DTLS_OFF_WDOG_TIMER:
+	case MAX77759_CHGR_CHG_DTLS_SUSP_JEITA:
+	case MAX77759_CHGR_CHG_DTLS_OFF:
+		return POWER_SUPPLY_CHARGE_TYPE_NONE;
+	default:
+		break;
+	}
+
+	return POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+}
+
+static int get_chg_health(struct max77759_charger *chg)
+{
+	u32 val;
+	int ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_DETAILS_00, &val);
+	if (ret)
+		return ret;
+
+	switch (FIELD_GET(MAX77759_CHGR_REG_CHG_DETAILS_OO_CHGIN_DTLS, val)) {
+	case MAX77759_CHGR_CHGIN_DTLS_VBUS_UNDERVOLTAGE:
+	case MAX77759_CHGR_CHGIN_DTLS_VBUS_MARGINAL_VOLTAGE:
+		return POWER_SUPPLY_HEALTH_UNDERVOLTAGE;
+	case MAX77759_CHGR_CHGIN_DTLS_VBUS_OVERVOLTAGE:
+		return POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+	case MAX77759_CHGR_CHGIN_DTLS_VBUS_VALID:
+		return POWER_SUPPLY_HEALTH_GOOD;
+	default:
+		break;
+	}
+
+	return POWER_SUPPLY_HEALTH_UNKNOWN;
+}
+
+static int get_batt_health(struct max77759_charger *chg)
+{
+	u32 val;
+	int ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_DETAILS_01, &val);
+	if (ret)
+		return ret;
+
+	switch (FIELD_GET(MAX77759_CHGR_REG_CHG_DETAILS_01_BAT_DTLS, val)) {
+	case MAX77759_CHGR_BAT_DTLS_NO_BATT_CHG_SUSP:
+		return POWER_SUPPLY_HEALTH_NO_BATTERY;
+	case MAX77759_CHGR_BAT_DTLS_DEAD_BATTERY:
+		return POWER_SUPPLY_HEALTH_DEAD;
+	case MAX77759_CHGR_BAT_DTLS_BAT_CHG_TIMER_FAULT:
+		return POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
+	case MAX77759_CHGR_BAT_DTLS_BAT_OKAY:
+	case MAX77759_CHGR_BAT_DTLS_BAT_ONLY_MODE:
+		return POWER_SUPPLY_HEALTH_GOOD;
+	case MAX77759_CHGR_BAT_DTLS_BAT_UNDERVOLTAGE:
+		return POWER_SUPPLY_HEALTH_UNDERVOLTAGE;
+	case MAX77759_CHGR_BAT_DTLS_BAT_OVERVOLTAGE:
+		return POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+	case MAX77759_CHGR_BAT_DTLS_BAT_OVERCURRENT:
+		return POWER_SUPPLY_HEALTH_OVERCURRENT;
+	default:
+		break;
+	}
+
+	return POWER_SUPPLY_HEALTH_UNKNOWN;
+}
+
+static int get_health(struct max77759_charger *chg)
+{
+	int ret;
+
+	ret = get_online(chg);
+	if (ret < 0)
+		return ret;
+
+	if (ret) {
+		ret = get_chg_health(chg);
+		if (ret < 0 || ret != POWER_SUPPLY_HEALTH_GOOD)
+			return ret;
+	}
+
+	return get_batt_health(chg);
+}
+
+static int get_fast_charge_current(struct max77759_charger *chg)
+{
+	u32 regval;
+	int ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_02, &regval);
+	if (ret)
+		return ret;
+
+	ret = FIELD_GET(MAX77759_CHGR_REG_CHG_CNFG_02_CHGCC, regval);
+	if (ret <= MAX77759_CHGR_CHGCC_REG_OFFSET)
+		return MAX77759_CHGR_CHGCC_MIN_UA;
+
+	return regval_to_val(ret, MAX77759_CHGR_CHGCC_REG_OFFSET,
+			     MAX77759_CHGR_CHGCC_STEP_UA,
+			     MAX77759_CHGR_CHGCC_MIN_UA);
+}
+
+static int set_fast_charge_current_limit(struct max77759_charger *chg,
+					 u32 cc_max_ua)
+{
+	u32 val;
+
+	if (cc_max_ua < MAX77759_CHGR_CHGCC_MIN_UA ||
+	    cc_max_ua > MAX77759_CHGR_CHGCC_MAX_UA)
+		return -EINVAL;
+
+	val = val_to_regval(cc_max_ua, MAX77759_CHGR_CHGCC_MIN_UA,
+			    MAX77759_CHGR_CHGCC_STEP_UA,
+			    MAX77759_CHGR_CHGCC_REG_OFFSET);
+	return regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_02,
+				  MAX77759_CHGR_REG_CHG_CNFG_02_CHGCC, val);
+}
+
+static int get_float_voltage(struct max77759_charger *chg)
+{
+	u32 regval;
+	int ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_04, &regval);
+	if (ret)
+		return ret;
+
+	ret = FIELD_GET(MAX77759_CHGR_REG_CHG_CNFG_04_CHG_CV_PRM, regval);
+	switch (ret) {
+	case MAX77759_CHGR_CHG_CV_PRM_HI_MIN_REG ... MAX77759_CHGR_CHG_CV_PRM_HI_MAX_REG:
+		return regval_to_val(ret, MAX77759_CHGR_CHG_CV_PRM_HI_MIN_REG,
+				     MAX77759_CHGR_CHG_CV_PRM_HI_STEP_MV,
+				     MAX77759_CHGR_CHG_CV_PRM_HI_MIN_MV);
+	case MAX77759_CHGR_CHG_CV_PRM_LO_MIN_REG ... MAX77759_CHGR_CHG_CV_PRM_LO_MAX_REG:
+		return regval_to_val(ret, MAX77759_CHGR_CHG_CV_PRM_LO_MIN_REG,
+				     MAX77759_CHGR_CHG_CV_PRM_LO_STEP_MV,
+				     MAX77759_CHGR_CHG_CV_PRM_LO_MIN_MV);
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int set_float_voltage_limit(struct max77759_charger *chg, u32 fv_mv)
+{
+	u32 regval;
+
+	if (fv_mv >= MAX77759_CHGR_CHG_CV_PRM_LO_MIN_MV &&
+	    fv_mv <= MAX77759_CHGR_CHG_CV_PRM_LO_MAX_MV) {
+		regval = val_to_regval(fv_mv,
+				       MAX77759_CHGR_CHG_CV_PRM_LO_MIN_MV,
+				       MAX77759_CHGR_CHG_CV_PRM_LO_STEP_MV,
+				       MAX77759_CHGR_CHG_CV_PRM_LO_MIN_REG);
+	} else if (fv_mv >= MAX77759_CHGR_CHG_CV_PRM_HI_MIN_MV &&
+		   fv_mv <= MAX77759_CHGR_CHG_CV_PRM_HI_MAX_MV) {
+		regval = val_to_regval(fv_mv,
+				       MAX77759_CHGR_CHG_CV_PRM_HI_MIN_MV,
+				       MAX77759_CHGR_CHG_CV_PRM_HI_STEP_MV,
+				       MAX77759_CHGR_CHG_CV_PRM_HI_MIN_REG);
+	} else {
+		return -EINVAL;
+	}
+
+	return regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_04,
+				  MAX77759_CHGR_REG_CHG_CNFG_04_CHG_CV_PRM,
+				  regval);
+}
+
+static int get_input_current_limit(struct max77759_charger *chg)
+{
+	u32 regval;
+	int ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_09, &regval);
+	if (ret)
+		return ret;
+
+	ret = FIELD_GET(MAX77759_CHGR_REG_CHG_CNFG_09_CHGIN_ILIM, regval);
+	if (ret <= MAX77759_CHGR_CHGIN_ILIM_REG_OFFSET)
+		return MAX77759_CHGR_CHGIN_ILIM_MIN_UA;
+
+	return regval_to_val(ret, MAX77759_CHGR_CHGIN_ILIM_REG_OFFSET,
+			     MAX77759_CHGR_CHGIN_ILIM_STEP_UA,
+			     MAX77759_CHGR_CHGIN_ILIM_MIN_UA);
+}
+
+static int set_input_current_limit(struct max77759_charger *chg, int ilim_ua)
+{
+	u32 regval;
+
+	if (ilim_ua < 0)
+		return -EINVAL;
+
+	if (ilim_ua == 0)
+		ilim_ua = MAX77759_CHGR_CHGIN_ILIM_MIN_UA;
+	else if (ilim_ua > MAX77759_CHGR_CHGIN_ILIM_MAX_UA)
+		ilim_ua = MAX77759_CHGR_CHGIN_ILIM_MAX_UA;
+
+	regval = val_to_regval(ilim_ua, MAX77759_CHGR_CHGIN_ILIM_MIN_UA,
+			       MAX77759_CHGR_CHGIN_ILIM_STEP_UA,
+			       MAX77759_CHGR_CHGIN_ILIM_REG_OFFSET);
+	return regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_09,
+				  MAX77759_CHGR_REG_CHG_CNFG_09_CHGIN_ILIM,
+				  regval);
+}
+
+static const enum power_supply_property max77759_charger_props[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_CHARGE_TYPE,
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
+	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
+};
+
+static int max77759_charger_get_property(struct power_supply *psy,
+					 enum power_supply_property psp,
+					 union power_supply_propval *pval)
+{
+	struct max77759_charger *chg = power_supply_get_drvdata(psy);
+	int ret;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		ret = get_online(chg);
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		ret = charger_input_valid(chg);
+		break;
+	case POWER_SUPPLY_PROP_STATUS:
+		ret = get_status(chg);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		ret = get_charge_type(chg);
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		ret = get_health(chg);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+		ret = get_fast_charge_current(chg);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
+		ret = get_float_voltage(chg);
+		break;
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+		ret = get_input_current_limit(chg);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	pval->intval = ret;
+	return ret < 0 ? ret : 0;
+}
+
+static const struct power_supply_desc max77759_charger_desc = {
+	.name = "max77759-charger",
+	.type = POWER_SUPPLY_TYPE_USB,
+	.properties = max77759_charger_props,
+	.num_properties = ARRAY_SIZE(max77759_charger_props),
+	.get_property = max77759_charger_get_property,
+};
+
+static int charger_set_mode(struct max77759_charger *chg,
+			    enum max77759_chgr_mode mode)
+{
+	int ret;
+
+	guard(mutex)(&chg->lock);
+
+	if (chg->mode == mode)
+		return 0;
+
+	if ((mode == MAX77759_CHGR_MODE_CHG_BUCK_ON ||
+	     mode == MAX77759_CHGR_MODE_OTG_BOOST_ON) &&
+	    chg->mode != MAX77759_CHGR_MODE_OFF) {
+		dev_err(chg->dev, "Invalid mode transition from %d to %d",
+			chg->mode, mode);
+		return -EINVAL;
+	}
+
+	ret = regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_00,
+				 MAX77759_CHGR_REG_CHG_CNFG_00_MODE, mode);
+	if (ret)
+		return ret;
+
+	chg->mode = mode;
+	return 0;
+}
+
+static int enable_chgin_otg(struct regulator_dev *rdev)
+{
+	struct max77759_charger *chg = rdev_get_drvdata(rdev);
+
+	return charger_set_mode(chg, MAX77759_CHGR_MODE_OTG_BOOST_ON);
+}
+
+static int disable_chgin_otg(struct regulator_dev *rdev)
+{
+	struct max77759_charger *chg = rdev_get_drvdata(rdev);
+
+	return charger_set_mode(chg, MAX77759_CHGR_MODE_OFF);
+}
+
+static int chgin_otg_status(struct regulator_dev *rdev)
+{
+	struct max77759_charger *chg = rdev_get_drvdata(rdev);
+
+	guard(mutex)(&chg->lock);
+	return chg->mode == MAX77759_CHGR_MODE_OTG_BOOST_ON;
+}
+
+static const struct regulator_ops chgin_otg_reg_ops = {
+	.enable = enable_chgin_otg,
+	.disable = disable_chgin_otg,
+	.is_enabled = chgin_otg_status,
+};
+
+static const struct regulator_desc chgin_otg_reg_desc = {
+	.name = "chgin-otg",
+	.of_match = of_match_ptr("chgin-otg-regulator"),
+	.owner = THIS_MODULE,
+	.ops = &chgin_otg_reg_ops,
+	.fixed_uV = 5000000,
+	.n_voltages = 1,
+};
+
+static irqreturn_t irq_handler(int irq, void *data)
+{
+	struct max77759_charger *chg = data;
+	struct device *dev = chg->dev;
+	u32 chgint_ok;
+	int i;
+
+	regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_INT_OK, &chgint_ok);
+
+	for (i = 0; i < ARRAY_SIZE(irqs); i++) {
+		if (irqs[i] == irq)
+			break;
+	}
+
+	switch (i) {
+	case AICL:
+		dev_dbg(dev, "AICL mode: %s",
+			str_no_yes(chgint_ok & MAX77759_CHGR_REG_CHG_INT_AICL));
+		break;
+	case CHGIN:
+		dev_dbg(dev, "CHGIN input valid: %s",
+			str_yes_no(chgint_ok & MAX77759_CHGR_REG_CHG_INT_CHGIN));
+		break;
+	case CHG:
+		dev_dbg(dev, "CHG status okay/off: %s",
+			str_yes_no(chgint_ok & MAX77759_CHGR_REG_CHG_INT_CHG));
+		break;
+	case INLIM:
+		dev_dbg(dev, "Current Limit reached: %s",
+			str_no_yes(chgint_ok & MAX77759_CHGR_REG_CHG_INT_INLIM));
+		break;
+	case BAT_OILO:
+		dev_dbg(dev, "Battery over-current threshold crossed");
+		break;
+	case CHG_STA_CC:
+		dev_dbg(dev, "Charger reached CC stage");
+		break;
+	case CHG_STA_CV:
+		dev_dbg(dev, "Charger reached CV stage");
+		break;
+	case CHG_STA_TO:
+		dev_dbg(dev, "Charger reached TO stage");
+		break;
+	case CHG_STA_DONE:
+		dev_dbg(dev, "Charger reached TO stage");
+		break;
+	default:
+		dev_err(dev, "Unrecognized irq: %d", i);
+		return IRQ_HANDLED;
+	}
+
+	power_supply_changed(chg->psy);
+	return IRQ_HANDLED;
+}
+
+static int max77759_init_irqhandler(struct max77759_charger *chg)
+{
+	struct device *dev = chg->dev;
+	struct irq_data *irqd;
+	unsigned long irq_flags;
+	int i, ret;
+
+	for (i = 0; i < ARRAY_SIZE(chgr_irqs_str); i++) {
+		ret = platform_get_irq_byname(to_platform_device(dev),
+					      chgr_irqs_str[i]);
+		if (ret < 0) {
+			dev_err(dev,
+				"Failed to get irq resource for %s, ret=%d",
+				chgr_irqs_str[i], ret);
+			return ret;
+		}
+
+		irqs[i] = ret;
+		irq_flags = IRQF_ONESHOT;
+		irqd = irq_get_irq_data(irqs[i]);
+		if (irqd)
+			irq_flags |= irqd_get_trigger_type(irqd);
+
+		ret = devm_request_threaded_irq(dev, irqs[i], NULL, irq_handler,
+						irq_flags, dev_name(dev), chg);
+		if (ret) {
+			dev_err(dev,
+				"Unable to register irq handler for %s, ret=%d",
+				chgr_irqs_str[i], ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int max77759_charger_init(struct max77759_charger *chg)
+{
+	int ret;
+	u32 regval;
+
+	regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_00, &regval);
+	chg->mode = FIELD_GET(MAX77759_CHGR_REG_CHG_CNFG_00_MODE, regval);
+	ret = charger_set_mode(chg, MAX77759_CHGR_MODE_OFF);
+	if (ret)
+		return ret;
+
+	ret = set_fast_charge_current_limit(chg, CHG_CC_DEFAULT_UA);
+	if (ret)
+		return ret;
+
+	ret = set_float_voltage_limit(chg, CHG_FV_DEFAULT_MV);
+	if (ret)
+		return ret;
+
+	ret = unlock_prot_regs(chg, true);
+	if (ret)
+		return ret;
+
+	/* Disable wireless charging input */
+	regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_12,
+			   MAX77759_CHGR_REG_CHG_CNFG_12_WCINSEL, 0);
+
+	regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_18,
+			   MAX77759_CHGR_REG_CHG_CNFG_18_WDTEN, 0);
+
+	return unlock_prot_regs(chg, false);
+}
+
+static void psy_work_item(struct work_struct *work)
+{
+	struct max77759_charger *chg =
+		container_of(work, struct max77759_charger, psy_work);
+	union power_supply_propval current_limit = { 0 }, online = { 0 };
+	int ret;
+
+	power_supply_get_property(chg->tcpm_psy, POWER_SUPPLY_PROP_CURRENT_MAX,
+				  &current_limit);
+	power_supply_get_property(chg->tcpm_psy, POWER_SUPPLY_PROP_ONLINE,
+				  &online);
+
+	if (online.intval && current_limit.intval) {
+		ret = set_input_current_limit(chg, current_limit.intval);
+		if (ret)
+			dev_err(chg->dev,
+				"Unable to set current limit, ret=%d", ret);
+
+		charger_set_mode(chg, MAX77759_CHGR_MODE_CHG_BUCK_ON);
+	} else {
+		charger_set_mode(chg, MAX77759_CHGR_MODE_OFF);
+	}
+}
+
+static int psy_changed(struct notifier_block *nb, unsigned long evt, void *data)
+{
+	struct max77759_charger *chg = container_of(nb, struct max77759_charger,
+						    nb);
+	const char *psy_name = "tcpm-source";
+	struct power_supply *psy = data;
+
+	if (!strnstr(psy->desc->name, psy_name, strlen(psy_name)) ||
+	    evt != PSY_EVENT_PROP_CHANGED)
+		return NOTIFY_OK;
+
+	chg->tcpm_psy = psy;
+	schedule_work(&chg->psy_work);
+	return NOTIFY_OK;
+}
+
+static void max_tcpci_unregister_psy_notifier(void *nb)
+{
+	power_supply_unreg_notifier(nb);
+}
+
+static int max77759_charger_probe(struct platform_device *pdev)
+{
+	struct regulator_config chgin_otg_reg_cfg;
+	struct power_supply_config psy_cfg;
+	struct device *dev = &pdev->dev;
+	struct max77759_charger *chg;
+	int ret;
+
+	chg = devm_kzalloc(dev, sizeof(*chg), GFP_KERNEL);
+	if (!chg)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, chg);
+	chg->dev = dev;
+	chg->regmap = dev_get_regmap(dev->parent, "charger");
+	if (!chg->regmap)
+		return dev_err_probe(dev, -ENODEV, "Missing regmap");
+
+	ret = devm_mutex_init(dev, &chg->lock);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to initialize lock");
+
+	ret = max77759_charger_init(chg);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed to initialize max77759 charger");
+
+	chgin_otg_reg_cfg.dev = dev;
+	chgin_otg_reg_cfg.driver_data = chg;
+	chgin_otg_reg_cfg.of_node = dev_of_node(dev);
+	chg->chgin_otg_rdev = devm_regulator_register(dev, &chgin_otg_reg_desc,
+						      &chgin_otg_reg_cfg);
+	if (IS_ERR(chg->chgin_otg_rdev))
+		return dev_err_probe(dev, PTR_ERR(chg->chgin_otg_rdev),
+				     "Failed to register chgin otg regulator");
+
+	psy_cfg.fwnode = dev_fwnode(dev);
+	psy_cfg.drv_data = chg;
+	chg->psy = devm_power_supply_register(dev, &max77759_charger_desc,
+					      &psy_cfg);
+	if (IS_ERR(chg->psy))
+		return dev_err_probe(dev, -EPROBE_DEFER,
+				     "Failed to register psy, ret=%ld",
+				     PTR_ERR(chg->psy));
+
+	ret = devm_work_autocancel(dev, &chg->psy_work, psy_work_item);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to initialize psy work");
+
+	chg->nb.notifier_call = psy_changed;
+	ret = power_supply_reg_notifier(&chg->nb);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Unable to register psy notifier");
+
+	ret = devm_add_action_or_reset(dev, max_tcpci_unregister_psy_notifier,
+				       &chg->nb);
+	if (ret)
+		return ret;
+
+	ret = max77759_init_irqhandler(chg);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Unable to initialize irq handler");
+	return 0;
+}
+
+static const struct of_device_id max77759_charger_ids[] = {
+	{ .compatible = "maxim,max77759-charger", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, max77759_charger_ids);
+
+static struct platform_driver max77759_charger_driver = {
+	.driver = {
+		.name = "max77759-charger",
+		.of_match_table = max77759_charger_ids,
+	},
+	.probe = max77759_charger_probe,
+};
+module_platform_driver(max77759_charger_driver);
+
+MODULE_AUTHOR("Amit Sunil Dhamne <amitsd at google.com>");
+MODULE_DESCRIPTION("Maxim MAX77759 charger driver");
+MODULE_LICENSE("GPL");

-- 
2.52.0.322.g1dd061c0dc-goog




From devnull+amitsd.google.com at kernel.org  Thu Dec 18 14:49:08 2025
From: devnull+amitsd.google.com at kernel.org (Amit Sunil Dhamne via B4 Relay)
Date: Thu, 18 Dec 2025 22:49:08 +0000
Subject: [PATCH v2 3/5] mfd: max77759: add register bitmasks and modify irq
 configs for charger
In-Reply-To: <20251218-max77759-charger-v2-0-2b259980a686@google.com>
References: <20251218-max77759-charger-v2-0-2b259980a686@google.com>
Message-ID: <20251218-max77759-charger-v2-3-2b259980a686@google.com>

From: Amit Sunil Dhamne <amitsd at google.com>

Add register bitmasks for charger function.
In addition split the charger IRQs further such that each bit represents
an IRQ downstream of charger regmap irq chip. In addition populate the
ack_base to offload irq ack to the regmap irq chip framework.

Signed-off-by: Amit Sunil Dhamne <amitsd at google.com>
---
 drivers/mfd/max77759.c       |  91 +++++++++++++++++--
 include/linux/mfd/max77759.h | 202 ++++++++++++++++++++++++++++++++++++-------
 2 files changed, 256 insertions(+), 37 deletions(-)

diff --git a/drivers/mfd/max77759.c b/drivers/mfd/max77759.c
index 6cf6306c4a3b..a5f7da003edd 100644
--- a/drivers/mfd/max77759.c
+++ b/drivers/mfd/max77759.c
@@ -201,8 +201,24 @@ static const struct regmap_config max77759_regmap_config_charger = {
  *         - SYSUVLO_INT
  *         - FSHIP_NOT_RD
  *     - CHGR_INT: charger
- *       - CHG_INT
- *       - CHG_INT2
+ *       - INT1
+ *         - AICL
+ *         - CHGIN
+ *         - WCIN
+ *         - CHG
+ *         - BAT
+ *         - INLIM
+ *         - THM2
+ *         - BYP
+ *       - INT2
+ *         - INSEL
+ *         - SYS_UVLO1
+ *         - SYS_UVLO2
+ *         - BAT_OILO
+ *         - CHG_STA_CC
+ *         - CHG_STA_CV
+ *         - CHG_STA_TO
+ *         - CHG_STA_DONE
  */
 enum {
 	MAX77759_INT_MAXQ,
@@ -228,8 +244,22 @@ enum {
 };
 
 enum {
-	MAX77759_CHARGER_INT_1,
-	MAX77759_CHARGER_INT_2,
+	MAX77759_CHGR_INT1_AICL,
+	MAX77759_CHGR_INT1_CHGIN,
+	MAX77759_CHGR_INT1_WCIN,
+	MAX77759_CHGR_INT1_CHG,
+	MAX77759_CHGR_INT1_BAT,
+	MAX77759_CHGR_INT1_INLIM,
+	MAX77759_CHGR_INT1_THM2,
+	MAX77759_CHGR_INT1_BYP,
+	MAX77759_CHGR_INT2_INSEL,
+	MAX77759_CHGR_INT2_SYS_UVLO1,
+	MAX77759_CHGR_INT2_SYS_UVLO2,
+	MAX77759_CHGR_INT2_BAT_OILO,
+	MAX77759_CHGR_INT2_CHG_STA_CC,
+	MAX77759_CHGR_INT2_CHG_STA_CV,
+	MAX77759_CHGR_INT2_CHG_STA_TO,
+	MAX77759_CHGR_INT2_CHG_STA_DONE,
 };
 
 static const struct regmap_irq max77759_pmic_irqs[] = {
@@ -256,8 +286,38 @@ static const struct regmap_irq max77759_topsys_irqs[] = {
 };
 
 static const struct regmap_irq max77759_chgr_irqs[] = {
-	REGMAP_IRQ_REG(MAX77759_CHARGER_INT_1, 0, GENMASK(7, 0)),
-	REGMAP_IRQ_REG(MAX77759_CHARGER_INT_2, 1, GENMASK(7, 0)),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT1_AICL, 0,
+		       MAX77759_CHGR_REG_CHG_INT_AICL),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT1_CHGIN, 0,
+		       MAX77759_CHGR_REG_CHG_INT_CHGIN),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT1_WCIN, 0,
+		       MAX77759_CHGR_REG_CHG_INT_WCIN),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT1_CHG, 0,
+		       MAX77759_CHGR_REG_CHG_INT_CHG),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT1_BAT, 0,
+		       MAX77759_CHGR_REG_CHG_INT_BAT),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT1_INLIM, 0,
+		       MAX77759_CHGR_REG_CHG_INT_INLIM),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT1_THM2, 0,
+		       MAX77759_CHGR_REG_CHG_INT_THM2),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT1_BYP, 0,
+		       MAX77759_CHGR_REG_CHG_INT_BYP),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT2_INSEL, 1,
+		       MAX77759_CHGR_REG_CHG_INT2_INSEL),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT2_SYS_UVLO1, 1,
+		       MAX77759_CHGR_REG_CHG_INT2_SYS_UVLO1),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT2_SYS_UVLO2, 1,
+		       MAX77759_CHGR_REG_CHG_INT2_SYS_UVLO2),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT2_BAT_OILO, 1,
+		       MAX77759_CHGR_REG_CHG_INT2_BAT_OILO),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT2_CHG_STA_CC, 1,
+		       MAX77759_CHGR_REG_CHG_INT2_CHG_STA_CC),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT2_CHG_STA_CV, 1,
+		       MAX77759_CHGR_REG_CHG_INT2_CHG_STA_CV),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT2_CHG_STA_TO, 1,
+		       MAX77759_CHGR_REG_CHG_INT2_CHG_STA_TO),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT2_CHG_STA_DONE, 1,
+		       MAX77759_CHGR_REG_CHG_INT2_CHG_STA_DONE),
 };
 
 static const struct regmap_irq_chip max77759_pmic_irq_chip = {
@@ -302,6 +362,7 @@ static const struct regmap_irq_chip max77759_chrg_irq_chip = {
 	.domain_suffix = "CHGR",
 	.status_base = MAX77759_CHGR_REG_CHG_INT,
 	.mask_base = MAX77759_CHGR_REG_CHG_INT_MASK,
+	.ack_base = MAX77759_CHGR_REG_CHG_INT,
 	.num_regs = 2,
 	.irqs = max77759_chgr_irqs,
 	.num_irqs = ARRAY_SIZE(max77759_chgr_irqs),
@@ -325,8 +386,22 @@ static const struct resource max77759_gpio_resources[] = {
 };
 
 static const struct resource max77759_charger_resources[] = {
-	DEFINE_RES_IRQ_NAMED(MAX77759_CHARGER_INT_1, "INT1"),
-	DEFINE_RES_IRQ_NAMED(MAX77759_CHARGER_INT_2, "INT2"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_AICL,         "AICL"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_CHGIN,        "CHGIN"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_WCIN,         "WCIN"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_CHG,          "CHG"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_BAT,          "BAT"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_INLIM,        "INLIM"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_THM2,         "THM2"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_BYP,          "BYP"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_INSEL,        "INSEL"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_SYS_UVLO1,    "SYS_UVLO1"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_SYS_UVLO2,    "SYS_UVLO2"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_BAT_OILO,     "BAT_OILO"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_CHG_STA_CC,   "CHG_STA_CC"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_CHG_STA_CV,   "CHG_STA_CV"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_CHG_STA_TO,   "CHG_STA_TO"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_CHG_STA_DONE, "CHG_STA_DONE"),
 };
 
 static const struct mfd_cell max77759_cells[] = {
diff --git a/include/linux/mfd/max77759.h b/include/linux/mfd/max77759.h
index c6face34e385..e674a519e782 100644
--- a/include/linux/mfd/max77759.h
+++ b/include/linux/mfd/max77759.h
@@ -59,35 +59,65 @@
 #define MAX77759_MAXQ_REG_AP_DATAIN0            0xb1
 #define MAX77759_MAXQ_REG_UIC_SWRST             0xe0
 
-#define MAX77759_CHGR_REG_CHG_INT               0xb0
-#define MAX77759_CHGR_REG_CHG_INT2              0xb1
-#define MAX77759_CHGR_REG_CHG_INT_MASK          0xb2
-#define MAX77759_CHGR_REG_CHG_INT2_MASK         0xb3
-#define MAX77759_CHGR_REG_CHG_INT_OK            0xb4
-#define MAX77759_CHGR_REG_CHG_DETAILS_00        0xb5
-#define MAX77759_CHGR_REG_CHG_DETAILS_01        0xb6
-#define MAX77759_CHGR_REG_CHG_DETAILS_02        0xb7
-#define MAX77759_CHGR_REG_CHG_DETAILS_03        0xb8
-#define MAX77759_CHGR_REG_CHG_CNFG_00           0xb9
-#define MAX77759_CHGR_REG_CHG_CNFG_01           0xba
-#define MAX77759_CHGR_REG_CHG_CNFG_02           0xbb
-#define MAX77759_CHGR_REG_CHG_CNFG_03           0xbc
-#define MAX77759_CHGR_REG_CHG_CNFG_04           0xbd
-#define MAX77759_CHGR_REG_CHG_CNFG_05           0xbe
-#define MAX77759_CHGR_REG_CHG_CNFG_06           0xbf
-#define MAX77759_CHGR_REG_CHG_CNFG_07           0xc0
-#define MAX77759_CHGR_REG_CHG_CNFG_08           0xc1
-#define MAX77759_CHGR_REG_CHG_CNFG_09           0xc2
-#define MAX77759_CHGR_REG_CHG_CNFG_10           0xc3
-#define MAX77759_CHGR_REG_CHG_CNFG_11           0xc4
-#define MAX77759_CHGR_REG_CHG_CNFG_12           0xc5
-#define MAX77759_CHGR_REG_CHG_CNFG_13           0xc6
-#define MAX77759_CHGR_REG_CHG_CNFG_14           0xc7
-#define MAX77759_CHGR_REG_CHG_CNFG_15           0xc8
-#define MAX77759_CHGR_REG_CHG_CNFG_16           0xc9
-#define MAX77759_CHGR_REG_CHG_CNFG_17           0xca
-#define MAX77759_CHGR_REG_CHG_CNFG_18           0xcb
-#define MAX77759_CHGR_REG_CHG_CNFG_19           0xcc
+#define MAX77759_CHGR_REG_CHG_INT                      0xb0
+#define   MAX77759_CHGR_REG_CHG_INT_AICL               BIT(7)
+#define   MAX77759_CHGR_REG_CHG_INT_CHGIN              BIT(6)
+#define   MAX77759_CHGR_REG_CHG_INT_WCIN               BIT(5)
+#define   MAX77759_CHGR_REG_CHG_INT_CHG                BIT(4)
+#define   MAX77759_CHGR_REG_CHG_INT_BAT                BIT(3)
+#define   MAX77759_CHGR_REG_CHG_INT_INLIM              BIT(2)
+#define   MAX77759_CHGR_REG_CHG_INT_THM2               BIT(1)
+#define   MAX77759_CHGR_REG_CHG_INT_BYP                BIT(0)
+#define MAX77759_CHGR_REG_CHG_INT2                     0xb1
+#define   MAX77759_CHGR_REG_CHG_INT2_INSEL             BIT(7)
+#define   MAX77759_CHGR_REG_CHG_INT2_SYS_UVLO1         BIT(6)
+#define   MAX77759_CHGR_REG_CHG_INT2_SYS_UVLO2         BIT(5)
+#define   MAX77759_CHGR_REG_CHG_INT2_BAT_OILO          BIT(4)
+#define   MAX77759_CHGR_REG_CHG_INT2_CHG_STA_CC        BIT(3)
+#define   MAX77759_CHGR_REG_CHG_INT2_CHG_STA_CV        BIT(2)
+#define   MAX77759_CHGR_REG_CHG_INT2_CHG_STA_TO        BIT(1)
+#define   MAX77759_CHGR_REG_CHG_INT2_CHG_STA_DONE      BIT(0)
+#define MAX77759_CHGR_REG_CHG_INT_MASK                 0xb2
+#define MAX77759_CHGR_REG_CHG_INT2_MASK                0xb3
+#define MAX77759_CHGR_REG_CHG_INT_OK                   0xb4
+#define MAX77759_CHGR_REG_CHG_DETAILS_00               0xb5
+#define   MAX77759_CHGR_REG_CHG_DETAILS_OO_CHGIN_DTLS  GENMASK(6, 5)
+#define MAX77759_CHGR_REG_CHG_DETAILS_01               0xb6
+#define   MAX77759_CHGR_REG_CHG_DETAILS_01_BAT_DTLS    GENMASK(6, 4)
+#define   MAX77759_CHGR_REG_CHG_DETAILS_01_CHG_DTLS    GENMASK(3, 0)
+#define MAX77759_CHGR_REG_CHG_DETAILS_02               0xb7
+#define   MAX77759_CHGR_REG_CHG_DETAILS_02_CHGIN_STS   BIT(5)
+#define MAX77759_CHGR_REG_CHG_DETAILS_03               0xb8
+#define MAX77759_CHGR_REG_CHG_CNFG_00                  0xb9
+#define   MAX77759_CHGR_REG_CHG_CNFG_00_MODE           GENMASK(3, 0)
+#define MAX77759_CHGR_REG_CHG_CNFG_01                  0xba
+#define MAX77759_CHGR_REG_CHG_CNFG_02                  0xbb
+#define   MAX77759_CHGR_REG_CHG_CNFG_02_CHGCC	       GENMASK(5, 0)
+#define MAX77759_CHGR_REG_CHG_CNFG_03                  0xbc
+#define MAX77759_CHGR_REG_CHG_CNFG_04                  0xbd
+#define   MAX77759_CHGR_REG_CHG_CNFG_04_CHG_CV_PRM     GENMASK(5, 0)
+#define MAX77759_CHGR_REG_CHG_CNFG_05                  0xbe
+#define MAX77759_CHGR_REG_CHG_CNFG_06                  0xbf
+#define   MAX77759_CHGR_REG_CHG_CNFG_06_CHGPROT        GENMASK(3, 2)
+#define MAX77759_CHGR_REG_CHG_CNFG_07                  0xc0
+#define MAX77759_CHGR_REG_CHG_CNFG_08                  0xc1
+#define MAX77759_CHGR_REG_CHG_CNFG_09                  0xc2
+#define   MAX77759_CHGR_REG_CHG_CNFG_09_CHGIN_ILIM     GENMASK(6, 0)
+#define MAX77759_CHGR_REG_CHG_CNFG_10                  0xc3
+#define MAX77759_CHGR_REG_CHG_CNFG_11                  0xc4
+#define MAX77759_CHGR_REG_CHG_CNFG_12                  0xc5
+/* Wireless Charging input channel select */
+#define   MAX77759_CHGR_REG_CHG_CNFG_12_WCINSEL        BIT(6)
+/* CHGIN/USB input channel select */
+#define   MAX77759_CHGR_REG_CHG_CNFG_12_CHGINSEL       BIT(5)
+#define MAX77759_CHGR_REG_CHG_CNFG_13                  0xc6
+#define MAX77759_CHGR_REG_CHG_CNFG_14                  0xc7
+#define MAX77759_CHGR_REG_CHG_CNFG_15                  0xc8
+#define MAX77759_CHGR_REG_CHG_CNFG_16                  0xc9
+#define MAX77759_CHGR_REG_CHG_CNFG_17                  0xca
+#define MAX77759_CHGR_REG_CHG_CNFG_18                  0xcb
+#define   MAX77759_CHGR_REG_CHG_CNFG_18_WDTEN          BIT(0)
+#define MAX77759_CHGR_REG_CHG_CNFG_19                  0xcc
 
 /* MaxQ opcodes for max77759_maxq_command() */
 #define MAX77759_MAXQ_OPCODE_MAXLENGTH (MAX77759_MAXQ_REG_AP_DATAOUT32 - \
@@ -101,6 +131,120 @@
 #define MAX77759_MAXQ_OPCODE_USER_SPACE_READ     0x81
 #define MAX77759_MAXQ_OPCODE_USER_SPACE_WRITE    0x82
 
+/*
+ * Charger Input Status
+ * @MAX77759_CHGR_CHGIN_DTLS_VBUS_UNDERVOLTAGE:
+ *     Charger input voltage (Vchgin) < Under Voltage Threshold (Vuvlo)
+ * @MAX77759_CHGR_CHGIN_DTLS_VBUS_MARGINAL_VOLTAGE: Vchgin > Vuvlo and
+ *     Vchgin < (Battery Voltage (Vbatt) + system voltage (Vsys))
+ * @MAX77759_CHGR_CHGIN_DTLS_VBUS_OVERVOLTAGE:
+ *     Vchgin > Over Voltage threshold (Vovlo)
+ * @MAX77759_CHGR_CHGIN_DTLS_VBUS_VALID:
+ *     Vchgin > Vuvlo, Vchgin < Vovlo and Vchgin > (Vsys + Vbatt)
+ */
+enum max77759_chgr_chgin_dtls_status {
+	MAX77759_CHGR_CHGIN_DTLS_VBUS_UNDERVOLTAGE,
+	MAX77759_CHGR_CHGIN_DTLS_VBUS_MARGINAL_VOLTAGE,
+	MAX77759_CHGR_CHGIN_DTLS_VBUS_OVERVOLTAGE,
+	MAX77759_CHGR_CHGIN_DTLS_VBUS_VALID,
+};
+
+/*
+ * Battery Details
+ * @MAX77759_CHGR_BAT_DTLS_NO_BATT_CHG_SUSP:
+ *     No battery and the charger suspended
+ * @MAX77759_CHGR_BAT_DTLS_DEAD_BATTERY: Vbatt < Vtrickle
+ * @MAX77759_CHGR_BAT_DTLS_BAT_CHG_TIMER_FAULT:
+ *     Charging suspended due to timer fault
+ * @MAX77759_CHGR_BAT_DTLS_BAT_OKAY:
+ *     Battery okay and Vbatt > Min Sys Voltage (Vsysmin)
+ * @MAX77759_CHGR_BAT_DTLS_BAT_UNDERVOLTAGE:
+ *     Battery is okay. Vtrickle < Vbatt < Vsysmin
+ * @MAX77759_CHGR_BAT_DTLS_BAT_OVERVOLTAGE:
+ *     Battery voltage > Overvoltage threshold
+ * @MAX77759_CHGR_BAT_DTLS_BAT_OVERCURRENT:
+ *     Battery current exceeds overcurrent threshold
+ * @MAX77759_CHGR_BAT_DTLS_BAT_ONLY_MODE:
+ *     Battery only mode and battery level not available
+ */
+enum max77759_chgr_bat_dtls_states {
+	MAX77759_CHGR_BAT_DTLS_NO_BATT_CHG_SUSP,
+	MAX77759_CHGR_BAT_DTLS_DEAD_BATTERY,
+	MAX77759_CHGR_BAT_DTLS_BAT_CHG_TIMER_FAULT,
+	MAX77759_CHGR_BAT_DTLS_BAT_OKAY,
+	MAX77759_CHGR_BAT_DTLS_BAT_UNDERVOLTAGE,
+	MAX77759_CHGR_BAT_DTLS_BAT_OVERVOLTAGE,
+	MAX77759_CHGR_BAT_DTLS_BAT_OVERCURRENT,
+	MAX77759_CHGR_BAT_DTLS_BAT_ONLY_MODE,
+};
+
+/*
+ * Charger Details
+ * @MAX77759_CHGR_CHG_DTLS_PREQUAL: Charger in prequalification mode
+ * @MAX77759_CHGR_CHG_DTLS_CC:      Charger in fast charge const curr mode
+ * @MAX77759_CHGR_CHG_DTLS_CV:      Charger in fast charge const voltage mode
+ * @MAX77759_CHGR_CHG_DTLS_TO:      Charger is in top off mode
+ * @MAX77759_CHGR_CHG_DTLS_DONE:    Charger is done
+ * @MAX77759_CHGR_CHG_DTLS_RSVD_1:  Reserved
+ * @MAX77759_CHGR_CHG_DTLS_TIMER_FAULT:   Charger is in timer fault mode
+ * @MAX77759_CHGR_CHG_DTLS_SUSP_BATT_THM:
+ *     Charger is suspended as bettery removal detected
+ * @MAX77759_CHGR_CHG_DTLS_OFF:
+ *     Charger is off. Input invalid or charger disabled
+ * @MAX77759_CHGR_CHG_DTLS_RSVD_2:  Reserved
+ * @MAX77759_CHGR_CHG_DTLS_RSVD_3:  Reserved
+ * @MAX77759_CHGR_CHG_DTLS_OFF_WDOG_TIMER:
+ *     Charger is off as watchdog timer expired
+ * @MAX77759_CHGR_CHG_DTLS_SUSP_JEITA:    Charger is in JEITA control mode
+ */
+enum max77759_chgr_chg_dtls_states {
+	MAX77759_CHGR_CHG_DTLS_PREQUAL,
+	MAX77759_CHGR_CHG_DTLS_CC,
+	MAX77759_CHGR_CHG_DTLS_CV,
+	MAX77759_CHGR_CHG_DTLS_TO,
+	MAX77759_CHGR_CHG_DTLS_DONE,
+	MAX77759_CHGR_CHG_DTLS_RSVD_1,
+	MAX77759_CHGR_CHG_DTLS_TIMER_FAULT,
+	MAX77759_CHGR_CHG_DTLS_SUSP_BATT_THM,
+	MAX77759_CHGR_CHG_DTLS_OFF,
+	MAX77759_CHGR_CHG_DTLS_RSVD_2,
+	MAX77759_CHGR_CHG_DTLS_RSVD_3,
+	MAX77759_CHGR_CHG_DTLS_OFF_WDOG_TIMER,
+	MAX77759_CHGR_CHG_DTLS_SUSP_JEITA,
+};
+
+enum max77759_chgr_mode {
+	MAX77759_CHGR_MODE_OFF,
+	MAX77759_CHGR_MODE_CHG_BUCK_ON = 0x5,
+	MAX77759_CHGR_MODE_OTG_BOOST_ON = 0xA,
+};
+
+/* Fast charge current limits */
+#define MAX77759_CHGR_CHGCC_MIN_UA                     133330
+#define MAX77759_CHGR_CHGCC_MAX_UA                     4000000
+#define MAX77759_CHGR_CHGCC_STEP_UA                    66670
+#define MAX77759_CHGR_CHGCC_REG_OFFSET                 0x2
+
+/* Charge Termination Voltage Limits (in 2 ranges) */
+/* [3.8, 3.9] V range */
+#define MAX77759_CHGR_CHG_CV_PRM_LO_MIN_MV             3800
+#define MAX77759_CHGR_CHG_CV_PRM_LO_MAX_MV             3900
+#define MAX77759_CHGR_CHG_CV_PRM_LO_STEP_MV            100
+#define MAX77759_CHGR_CHG_CV_PRM_LO_MIN_REG            0x38
+#define MAX77759_CHGR_CHG_CV_PRM_LO_MAX_REG            0x39
+/* [4, 4.5] V range */
+#define MAX77759_CHGR_CHG_CV_PRM_HI_MIN_MV             4000
+#define MAX77759_CHGR_CHG_CV_PRM_HI_MAX_MV             4500
+#define MAX77759_CHGR_CHG_CV_PRM_HI_STEP_MV            10
+#define MAX77759_CHGR_CHG_CV_PRM_HI_MIN_REG            0x0
+#define MAX77759_CHGR_CHG_CV_PRM_HI_MAX_REG            0x32
+
+/* USB input current limits */
+#define MAX77759_CHGR_CHGIN_ILIM_MIN_UA                100000
+#define MAX77759_CHGR_CHGIN_ILIM_MAX_UA                3200000
+#define MAX77759_CHGR_CHGIN_ILIM_STEP_UA               25000
+#define MAX77759_CHGR_CHGIN_ILIM_REG_OFFSET            0x3
+
 /**
  * struct max77759 - core max77759 internal data structure
  *

-- 
2.52.0.322.g1dd061c0dc-goog




From devnull+amitsd.google.com at kernel.org  Thu Dec 18 14:49:10 2025
From: devnull+amitsd.google.com at kernel.org (Amit Sunil Dhamne via B4 Relay)
Date: Thu, 18 Dec 2025 22:49:10 +0000
Subject: [PATCH v2 5/5] usb: typec: tcpm/tcpci_maxim: deprecate WAR for
 setting charger mode
In-Reply-To: <20251218-max77759-charger-v2-0-2b259980a686@google.com>
References: <20251218-max77759-charger-v2-0-2b259980a686@google.com>
Message-ID: <20251218-max77759-charger-v2-5-2b259980a686@google.com>

From: Amit Sunil Dhamne <amitsd at google.com>

TCPCI maxim driver directly writes to the charger's register space to
set charger mode depending on the power role. As MAX77759 chg driver
exists, this WAR is not required.

Instead, use a regulator interface to source vbus when typec is in
source power mode. In other power modes, this regulator will be turned
off if active.

Signed-off-by: Amit Sunil Dhamne <amitsd at google.com>
---
 drivers/usb/typec/tcpm/tcpci_maxim.h      |  1 +
 drivers/usb/typec/tcpm/tcpci_maxim_core.c | 54 +++++++++++++++++++------------
 2 files changed, 34 insertions(+), 21 deletions(-)

diff --git a/drivers/usb/typec/tcpm/tcpci_maxim.h b/drivers/usb/typec/tcpm/tcpci_maxim.h
index b33540a42a95..b314606eb0f6 100644
--- a/drivers/usb/typec/tcpm/tcpci_maxim.h
+++ b/drivers/usb/typec/tcpm/tcpci_maxim.h
@@ -60,6 +60,7 @@ struct max_tcpci_chip {
 	struct tcpm_port *port;
 	enum contamiant_state contaminant_state;
 	bool veto_vconn_swap;
+	struct regulator *vbus_reg;
 };
 
 static inline int max_tcpci_read16(struct max_tcpci_chip *chip, unsigned int reg, u16 *val)
diff --git a/drivers/usb/typec/tcpm/tcpci_maxim_core.c b/drivers/usb/typec/tcpm/tcpci_maxim_core.c
index 19f638650796..e9e2405c5ca0 100644
--- a/drivers/usb/typec/tcpm/tcpci_maxim_core.c
+++ b/drivers/usb/typec/tcpm/tcpci_maxim_core.c
@@ -10,6 +10,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
 #include <linux/usb/pd.h>
 #include <linux/usb/tcpci.h>
 #include <linux/usb/tcpm.h>
@@ -35,12 +36,6 @@
  */
 #define TCPC_RECEIVE_BUFFER_LEN				32
 
-#define MAX_BUCK_BOOST_SID				0x69
-#define MAX_BUCK_BOOST_OP				0xb9
-#define MAX_BUCK_BOOST_OFF				0
-#define MAX_BUCK_BOOST_SOURCE				0xa
-#define MAX_BUCK_BOOST_SINK				0x5
-
 static const struct regmap_range max_tcpci_tcpci_range[] = {
 	regmap_reg_range(0x00, 0x95)
 };
@@ -202,32 +197,49 @@ static void process_rx(struct max_tcpci_chip *chip, u16 status)
 	tcpm_pd_receive(chip->port, &msg, rx_type);
 }
 
+static int get_vbus_regulator_handle(struct max_tcpci_chip *chip)
+{
+	if (IS_ERR_OR_NULL(chip->vbus_reg)) {
+		chip->vbus_reg = devm_regulator_get_exclusive(chip->dev,
+							      "vbus");
+		if (IS_ERR_OR_NULL(chip->vbus_reg)) {
+			dev_err(chip->dev,
+				"Failed to get vbus regulator handle");
+			return -ENODEV;
+		}
+	}
+
+	return 0;
+}
+
 static int max_tcpci_set_vbus(struct tcpci *tcpci, struct tcpci_data *tdata, bool source, bool sink)
 {
 	struct max_tcpci_chip *chip = tdata_to_max_tcpci(tdata);
-	u8 buffer_source[2] = {MAX_BUCK_BOOST_OP, MAX_BUCK_BOOST_SOURCE};
-	u8 buffer_sink[2] = {MAX_BUCK_BOOST_OP, MAX_BUCK_BOOST_SINK};
-	u8 buffer_none[2] = {MAX_BUCK_BOOST_OP, MAX_BUCK_BOOST_OFF};
-	struct i2c_client *i2c = chip->client;
 	int ret;
 
-	struct i2c_msg msgs[] = {
-		{
-			.addr = MAX_BUCK_BOOST_SID,
-			.flags = i2c->flags & I2C_M_TEN,
-			.len = 2,
-			.buf = source ? buffer_source : sink ? buffer_sink : buffer_none,
-		},
-	};
-
 	if (source && sink) {
 		dev_err(chip->dev, "Both source and sink set\n");
 		return -EINVAL;
 	}
 
-	ret = i2c_transfer(i2c->adapter, msgs, 1);
+	ret = get_vbus_regulator_handle(chip);
+	if (ret) {
+		/*
+		 * Regulator is not necessary for sink only applications. Return
+		 * success in cases where sink mode is being modified.
+		 */
+		return source ? ret : 1;
+	}
+
+	if (source) {
+		if (!regulator_is_enabled(chip->vbus_reg))
+			ret = regulator_enable(chip->vbus_reg);
+	} else {
+		if (regulator_is_enabled(chip->vbus_reg))
+			ret = regulator_disable(chip->vbus_reg);
+	}
 
-	return  ret < 0 ? ret : 1;
+	return ret < 0 ? ret : 1;
 }
 
 static void process_power_status(struct max_tcpci_chip *chip)

-- 
2.52.0.322.g1dd061c0dc-goog




From dianders at google.com  Thu Dec 18 14:56:03 2025
From: dianders at google.com (Doug Anderson)
Date: Thu, 18 Dec 2025 14:56:03 -0800
Subject: Proposal: document where SoC info belongs
Message-ID: <CAD=FV=W+jE_L_LLgAhD8K_4+CtivSD9-9t7Xe63XuKrKjfyfeQ@mail.gmail.com>

Hi,

To try to move things along, I'm picking a small piece out of my
previous discussion [1] to see if we can make some progress.

Right now, the top-level "compatible" string in a dts file usually
contains one or more strings to represent the SoC. Examples chosen
semi-randomly:

exynos5250-snow.dts:
- compatible: "google,snow-rev4", "google,snow", "samsung,exynos5250",
"samsung,exynos5"
- SoC: "samsung,exynos5250", "samsung,exynos5"

sun20i-d1-clockworkpi-v3.14.dts:
- compatible: "clockwork,r-01-clockworkpi-v3.14", "allwinner,sun20i-d1"
- SoC: "allwinner,sun20i-d1"

sdm845-db845c.dts:
- compatible: "thundercomm,db845c", "qcom,sdm845"
- SoC: "qcom,sdm845"

I propose that we DEPRECATE including SoC information in the top-level
compatible string and move it elsewhere. I propose these top-level
properties that should be used instead:

soc-family-compatible = "vendor,family";
soc-product-id = <0x1234>;
soc-product-variant = <0x1234>;
soc-product-description = "Something";
soc-major-rev = <0x1234>;
soc-minor-rev = <0x1234>;
soc-sub-rev = <0x1234>;

The family-compatible would be VERY high-level and is not intended to
be a marketing name. It would be something like "samsung,exynos",
"nvidia,tegra" or "google,google-silicon". The ONLY goal for this
string is that within a family, the other properties uniquely identify
a given SoC. This is a SINGLE string, NOT a list of strings. There is
no concept of being part of multiple families.

All the other numbers are hopefully self-explanatory. These values
could be absent (assumed 0) if they don't make sense for a given SoC.

The soc-product-description is designed to be some nice name that
represents the family, product-id, and product-variant but _not_ the
rev (since that's easy for anyone who cares to represent it as "rev
X.Y.Z")


The goals here are:
* Stop trying to jam so much into the top-level "compatible".
* Make it one step easier for bootloaders (or code packaging device
trees for bootloaders) to differentiate device trees / overlays. This
isn't _enough_ since this proposal doesn't include board info, but
it's a place to start.
* Make it easier to deal with "socketed" boards where the SoC can be replaced.

NOTE: if a set of devicetrees is provided to a bootloader, it could
not just look at these properties to help it pick a devicetree but it
could also change the properties to be more detailed (it could fill in
some of the minor/sub-revs, for instance).


I think this is a positive change for everyone and a cleaner way to
represent things even if you aren't dealing with the above problems.

What I'm looking for from people is some responses. Folks could choose:

A) Yes, this is great. We already have something like this and we'd
switch to your properties if it became a standard.

B) I like the idea, but I need an extra property to represent my SoC
and then I'd use it.

C) I like the idea and I'd use it, but with some changes.

D) We don't have anything like this today, but it sounds useful.

E) Why are you wasting my time? This isn't a useful problem. The SoC
belongs in the top-level compatible string, period.

F) Other (please specify)


FWIW, from chatting with Rob Herring offline, my understanding is:
* He doesn't think that using the "soc at 0" is the right place for these
properties.
* He didn't seem enthusiastic about adding a new node and was more
amenable to adding properties, which is why I added a pile of
top-level properties.


[1] https://lore.kernel.org/r/CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA at mail.gmail.com


From suzuki.poulose at arm.com  Thu Dec 18 15:19:45 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Thu, 18 Dec 2025 23:19:45 +0000
Subject: [PATCH v8 5/8] dt-bindings: arm: add an interrupt property for
 Coresight CTCU
In-Reply-To: <a9537dc9-c767-4909-8b1c-6e939ce4f3fc@kernel.org>
References: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
 <20251211-enable-byte-cntr-for-ctcu-v8-5-3e12ff313191@oss.qualcomm.com>
 <20251211133723.GA859302-robh@kernel.org>
 <dfa43a63-ca14-4dd7-a7ab-acd95748a8b9@oss.qualcomm.com>
 <a9537dc9-c767-4909-8b1c-6e939ce4f3fc@kernel.org>
Message-ID: <2db74a3e-4aeb-4e87-9fe8-5c9693bfb67c@arm.com>

On 18/12/2025 10:17, Krzysztof Kozlowski wrote:
> On 12/12/2025 02:12, Jie Gan wrote:
>>
>>
>> On 12/11/2025 9:37 PM, Rob Herring wrote:
>>> On Thu, Dec 11, 2025 at 02:10:44PM +0800, Jie Gan wrote:
>>>> Add an interrupt property to CTCU device. The interrupt will be triggered
>>>> when the data size in the ETR buffer exceeds the threshold of the
>>>> BYTECNTRVAL register. Programming a threshold in the BYTECNTRVAL register
>>>> of CTCU device will enable the interrupt.
>>>>
>>>> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
>>>> Reviewed-by: Mike Leach <mike.leach at linaro.org>
>>>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>>>> ---
>>>>    .../devicetree/bindings/arm/qcom,coresight-ctcu.yaml    | 17 +++++++++++++++++
>>>>    1 file changed, 17 insertions(+)
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
>>>> index c969c16c21ef..90f88cc6cd3e 100644
>>>> --- a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
>>>> +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
>>>> @@ -39,6 +39,16 @@ properties:
>>>>        items:
>>>>          - const: apb
>>>>    
>>>> +  interrupts:
>>>> +    items:
>>>> +      - description: Byte cntr interrupt for the first etr device
>>>> +      - description: Byte cntr interrupt for the second etr device

This is really vague. How do you define first vs second ? Probe order ?
No way. This must be the "port" number to which the ETR is connected
to the CTCU. IIUC, there is a config area for each ETR (e.g., trace id
filter) connected to the CTCU. I was under the assumption that they
are identified as "ports" (input ports). I don't really understand how
this interrupt mapping works now. Please explain it clearly.

>>>> +
>>>> +  interrupt-names:
>>>> +    items:
>>>> +      - const: etrirq0
>>>> +      - const: etrirq1
>>>
>>> Names are kind of pointless when it is just foo<index>.
>>
>> Hi Rob,
>>
>> I was naming them as etr0/etr1. Are these names acceptable?
> 
> Obviously irq is redundant, but how does etr0 solves the problem of
> calling it foo0?
> 
> I don't think you really read Rob's comment.
> 
>> The interrupts are assigned exclusively to a specific ETR device.
>>
>> But Suzuki is concerned that this might cause confusion because the ETR
>> device is named randomly in the driver. Suzuki suggested using ?port-0?
>> and ?port-1? and would also like to hear your feedback on these names.
> 
> There is no confusion here. Writing bindings luckily clarifies this what
> the indices in the array mean.

The point is there are "n" interrupts. Question is, could there be more
devices(ETRs) connected to the CTCU than "n".

e.g., Lets CTCU can control upto 4 ETRs and on a particular system, the

TMC-ETR0 -> CTCU-Port0

TMC-ETR1 -> CTCU-Port2
TMC-ETR2 -> CTCU-Port3

Now, how many interrupts are described in the DT ? How do we map which
interrupts correspond to the CTCU-Portn. (Finding the TMC-ETRx back
from the port is possible, with the topology).

This is what I raised in the previous version. Again, happy to hear
if there is a standard way to describe the interrupts.

Suzuki


> 
>>
>> Usually, the probe sequence follows the order of the addresses. In our
>> specification, ?ETR0? is always probed before ?ETR1? because its address
>> is lower.
> 
> How is this even relevant? You are answering to something completely
> different, so I don't think you really tried to understand review.
> 
> 
> 
> Best regards,
> Krzysztof



From detlev.casanova at collabora.com  Thu Dec 18 15:28:10 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Thu, 18 Dec 2025 18:28:10 -0500
Subject: [PATCH v7 00/17] media: rkvdec: Add support for VDPU381 and VDPU383
Message-ID: <20251218232829.337811-1-detlev.casanova@collabora.com>

These variants are found respectively in the RK3588 and RK3576 SoCs.
This patch only adds support for H264 and H265 in both variants.

As there is a considerable part of the code that can be shared with the
already supported rkvdec decoder driver, the support for these variants
is added here rather than writing a new driver.

This patch set uses the newly introduced hevc_ext_sps_[ls]t_rps v4l2
controls for HEVC.
Therefore, a patched version of userpace tools is needed for HEVC
support (added for GStreamer[1] and in an early stage for FFmpeg[2]).

The DTS changes can be found in another patch set: [3]

[1]: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/9355
[2]: https://gitlab.collabora.com/detlev/ffmpeg
[3]: https://lore.kernel.org/all/20251020212009.8852-1-detlev.casanova at collabora.com/

Changes since v6:
 - Remove coded_fmts capabilities
 - Remove inexistant V4L2_HEVC kconfig dependency
 - Add missing rkvdec registers
 - Fix memcpy sizes
 - Remove non-necessary name and style changes
 - Use common get_image_fmt
 - Do not validate sps in start()
 - Remove unused variable
 - Change named_regs to has_single_reg_region
 - Compared to v6, I didn't use a union for the ref addr and flags
   registers, as I find the flat struct more readable.

Changes since v5:
- Extract multicore management in separate commit
- Move variant specific functions to an ops struct
- Fix a typo and "h264" -> "hevc" copy/paste mistakes
- Move RKVDEC_*_PIXELS to rkvdec.h
- Drop VDPU383_*_PIXELS, use the the RKVDEC ones instead
- Change RKVDEC_1080P_PIXELS value to 1920 * 1088
- Long and short term ref sets extend controls:
  - Add them in visl traces
  - Reword documentation to specify SPS extension and use
  - Mention Vulkan Video API similarity
  - Specify behavior for empty array values
  - Reorder struct fields to ensure fixed compiled size
  - Remove the mention of V4L2_CTRL_FLAG_DYNAMIC_ARRAY flag

Changes since v4:
 - Add basic ext_sps_[ls]t_rps validation (flags only)
 - Add missing copyright in new common files
 - Rename num_coded_fmts, rcb_num, clk_count
 - Avoid allocating RCB config when not needed
 - Merge rkvdec_config into rkvdec_variant
 - Keep rkvdec_hevc_get_image_fmt per variant

Changes since v3:
 - Rebased on latest next (ea299a216426) + HEVC support for rk3399

Changes since v2:
 - Rebased on Kwiboo's HEVC support for rk3399
 - Include hevc_ext_sps_[ls]t_rps v4l2 controls commits
 - Remove empty lines at end of files
 - Rename RKVDEC2_ALLOC_* to RKVDEC_ALLOC_*
 - Set min_with and min_height to 64
 - Remove vdpu38x_fill_pixfmt_mp() function
 - Handle userspace not supporting hevc_ext_sps_[ls]t_rps
 - Make all config structs static const

Changes since v1:
 - Add parsing of the short and long term ref frame sets from the new v4l2
   controls
 - Add RPS cache to avoid parsing the same data again
 - Fix HEVC pixel formats selection
 - Fix multiple indentation errors

Detlev Casanova (17):
  media: uapi: HEVC: Add v4l2_ctrl_hevc_ext_sps_[ls]t_rps controls
  media: v4l2-ctrls: Add hevc_ext_sps_[ls]t_rps controls
  media: visl: Add HEVC short and long term RPS sets
  media: rkvdec: Switch to using structs instead of writel
  media: rkvdec: Move cabac tables to their own source file
  media: rkvdec: Use structs to represent the HW RPS
  media: rkvdec: Move h264 functions to common file
  media: rkvdec: Move hevc functions to common file
  media: rkvdec: Add variant specific coded formats list
  media: rkvdec: Add RCB and SRAM support
  media: rkvdec: Support per-variant interrupt handler
  media: rkvdec: Enable all clocks without naming them
  media: rkvdec: Disable multicore support
  media: rkvdec: Add H264 support for the VDPU381 variant
  media: rkvdec: Add H264 support for the VDPU383 variant
  media: rkvdec: Add HEVC support for the VDPU381 variant
  media: rkvdec: Add HEVC support for the VDPU383 variant

 .../media/v4l/ext-ctrls-codec-stateless.rst   | 120 +++
 .../media/v4l/videodev2.h.rst.exceptions      |   2 +
 .../media/v4l/vidioc-queryctrl.rst            |  12 +
 .../media/platform/rockchip/rkvdec/Makefile   |  14 +-
 .../{rkvdec-hevc-data.c => rkvdec-cabac.c}    | 506 +++++++++-
 .../rockchip/rkvdec/rkvdec-h264-common.c      | 258 +++++
 .../rockchip/rkvdec/rkvdec-h264-common.h      |  89 ++
 .../platform/rockchip/rkvdec/rkvdec-h264.c    | 892 ++----------------
 .../rockchip/rkvdec/rkvdec-hevc-common.c      | 512 ++++++++++
 .../rockchip/rkvdec/rkvdec-hevc-common.h      | 109 +++
 .../platform/rockchip/rkvdec/rkvdec-hevc.c    | 281 +-----
 .../platform/rockchip/rkvdec/rkvdec-rcb.c     | 179 ++++
 .../platform/rockchip/rkvdec/rkvdec-rcb.h     |  29 +
 .../platform/rockchip/rkvdec/rkvdec-regs.h    | 586 ++++++++----
 .../rockchip/rkvdec/rkvdec-vdpu381-h264.c     | 465 +++++++++
 .../rockchip/rkvdec/rkvdec-vdpu381-hevc.c     | 621 ++++++++++++
 .../rockchip/rkvdec/rkvdec-vdpu381-regs.h     | 424 +++++++++
 .../rockchip/rkvdec/rkvdec-vdpu383-h264.c     | 578 ++++++++++++
 .../rockchip/rkvdec/rkvdec-vdpu383-hevc.c     | 720 ++++++++++++++
 .../rockchip/rkvdec/rkvdec-vdpu383-regs.h     | 281 ++++++
 .../platform/rockchip/rkvdec/rkvdec-vp9.c     | 232 ++---
 .../media/platform/rockchip/rkvdec/rkvdec.c   | 572 +++++++++--
 .../media/platform/rockchip/rkvdec/rkvdec.h   |  49 +-
 drivers/media/test-drivers/visl/visl-dec.c    |   7 +
 drivers/media/test-drivers/visl/visl-dec.h    |   3 +
 .../media/test-drivers/visl/visl-trace-hevc.h |  59 ++
 drivers/media/v4l2-core/v4l2-ctrls-core.c     |  28 +
 drivers/media/v4l2-core/v4l2-ctrls-defs.c     |  10 +
 include/uapi/linux/v4l2-controls.h            |  61 ++
 include/uapi/linux/videodev2.h                |   2 +
 30 files changed, 6238 insertions(+), 1463 deletions(-)
 rename drivers/media/platform/rockchip/rkvdec/{rkvdec-hevc-data.c => rkvdec-cabac.c} (86%)
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.c
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-regs.h

-- 
2.52.0



From detlev.casanova at collabora.com  Thu Dec 18 15:28:11 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Thu, 18 Dec 2025 18:28:11 -0500
Subject: [PATCH v7 01/17] media: uapi: HEVC: Add v4l2_ctrl_hevc_ext_sps_[ls]t_rps controls
In-Reply-To: <20251218232829.337811-1-detlev.casanova@collabora.com>
References: <20251218232829.337811-1-detlev.casanova@collabora.com>
Message-ID: <20251218232829.337811-2-detlev.casanova@collabora.com>

Some hardware (e.g.: Rockchip's rk3588 hevc decoder) need to fully parse
the slice header, which cannot be passed with the current controls.
There is also no skip method similar as to what can be found in
verisilicon HW.

The SPS is therefore extended through these 2 new controls, providing the
long and short term reference information from the slice header for HEVC
decoding.

These now controls are similar as what is passed in the Vulkan Video API
with the StdVideoH265ShortTermRefPicSet and StdVideoH265LongTermRefPicsSps
structures embedded in the SPS struct.

Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../media/v4l/ext-ctrls-codec-stateless.rst   | 120 ++++++++++++++++++
 .../media/v4l/videodev2.h.rst.exceptions      |   2 +
 .../media/v4l/vidioc-queryctrl.rst            |  12 ++
 3 files changed, 134 insertions(+)

diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst
index 497ae74379f6c..3b1e05c6eb139 100644
--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst
+++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst
@@ -2959,6 +2959,126 @@ This structure contains all loop filter related parameters. See sections
       - 0x00000004
       -
 
+``V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS (struct)``
+    Subset of the :c:type:`v4l2_ctrl_hevc_sps` control.
+    It extends it with the list of Long-term reference sets parameters.
+    These parameters are defined according to :ref:`hevc`.
+    They are described in section 7.4.3.2.1 "General sequence parameter set
+    RBSP semantics" of the specification.
+    This control is a dynamically sized 1-dimensional array.
+    The values in the array should be ignored when either
+    num_long_term_ref_pics_sps is 0 or the
+    V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT flag is not set in
+    :c:type:`v4l2_ctrl_hevc_sps`.
+
+.. c:type:: v4l2_ctrl_hevc_ext_sps_lt_rps
+
+.. cssclass:: longtable
+
+.. flat-table:: struct v4l2_ctrl_hevc_ext_sps_lt_rps
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - __u16
+      - ``lt_ref_pic_poc_lsb_sps``
+      - Long term reference picture order count as described in section 7.4.3.2.1
+        "General sequence parameter set RBSP semantics" of the specification.
+    * - __u16
+      - ``flags``
+      - See :ref:`Extended Long-Term RPS Flags <hevc_ext_sps_lt_rps_flags>`
+
+.. _hevc_ext_sps_lt_rps_flags:
+
+``Extended SPS Long-Term RPS Flags``
+
+.. cssclass:: longtable
+
+.. flat-table::
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - ``V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_USED_LT``
+      - 0x00000001
+      - Specifies if the long-term reference picture is used 7.4.3.2.1 "General sequence parameter
+        set RBSP semantics" of the specification.
+
+``V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS (struct)``
+    Subset of the :c:type:`v4l2_ctrl_hevc_sps` control.
+    It extends it with the list of Short-term reference sets parameters.
+    These parameters are defined according to :ref:`hevc`.
+    They are described in section 7.4.8 "Short-term reference picture set
+    semantics" of the specification.
+    This control is a dynamically sized 1-dimensional array.
+    The values in the array should be ignored when
+    num_short_term_ref_pic_sets is 0.
+
+.. c:type:: v4l2_ctrl_hevc_ext_sps_st_rps
+
+.. cssclass:: longtable
+
+.. flat-table:: struct v4l2_ctrl_hevc_ext_sps_st_rps
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - __u8
+      - ``delta_idx_minus1``
+      - Specifies the delta compare to the index. See details in section 7.4.8 "Short-term
+        reference picture set semantics" of the specification.
+    * - __u8
+      - ``delta_rps_sign``
+      - Sign of the delta as specified in section 7.4.8 "Short-term reference picture set
+        semantics" of the specification.
+    * - __u8
+      - ``num_negative_pics``
+      - Number of short-term RPS entries that have picture order count values less than the
+        picture order count value of the current picture.
+    * - __u8
+      - ``num_positive_pics``
+      - Number of short-term RPS entries that have picture order count values greater than the
+        picture order count value of the current picture.
+    * - __u32
+      - ``used_by_curr_pic``
+      - Bit i specifies if short-term RPS i is used by the current picture.
+    * - __u32
+      - ``use_delta_flag``
+      - Bit i specifies if short-term RPS i is included in the short-term RPS entries.
+    * - __u16
+      - ``abs_delta_rps_minus1``
+      - Absolute delta RPS as specified in section 7.4.8 "Short-term reference picture set
+        semantics" of the specification.
+    * - __u16
+      - ``delta_poc_s0_minus1[16]``
+      - Specifies the negative picture order count delta for the i-th entry in the short-term RPS.
+        See details in section 7.4.8 "Short-term reference picture set semantics" of the
+        specification.
+    * - __u16
+      - ``delta_poc_s1_minus1[16]``
+      - Specifies the positive picture order count delta for the i-th entry in the short-term RPS.
+        See details in section 7.4.8 "Short-term reference picture set semantics" of the
+        specification.
+    * - __u16
+      - ``flags``
+      - See :ref:`Extended Short-Term RPS Flags <hevc_ext_sps_st_rps_flags>`
+
+.. _hevc_ext_sps_st_rps_flags:
+
+``Extended SPS Short-Term RPS Flags``
+
+.. cssclass:: longtable
+
+.. flat-table::
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - ``V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED``
+      - 0x00000001
+      - Specifies if the short-term RPS is predicted from another short term RPS. See details in
+        section 7.4.8 "Short-term reference picture set semantics" of the specification.
+
 .. _v4l2-codec-stateless-av1:
 
 ``V4L2_CID_STATELESS_AV1_SEQUENCE (struct)``
diff --git a/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions b/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions
index c41693115db64..6182b4e2d2ee0 100644
--- a/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions
+++ b/Documentation/userspace-api/media/v4l/videodev2.h.rst.exceptions
@@ -150,6 +150,8 @@ replace symbol V4L2_CTRL_TYPE_H264_SCALING_MATRIX :c:type:`V4L.v4l2_ctrl_type`
 replace symbol V4L2_CTRL_TYPE_H264_PRED_WEIGHTS :c:type:`V4L.v4l2_ctrl_type`
 replace symbol V4L2_CTRL_TYPE_H264_SLICE_PARAMS :c:type:`V4L.v4l2_ctrl_type`
 replace symbol V4L2_CTRL_TYPE_H264_DECODE_PARAMS :c:type:`V4L.v4l2_ctrl_type`
+replace symbol V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS :c:type:`V4L.v4l2_ctrl_type`
+replace symbol V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS :c:type:`V4L.v4l2_ctrl_type`
 replace symbol V4L2_CTRL_TYPE_HEVC_SPS :c:type:`V4L.v4l2_ctrl_type`
 replace symbol V4L2_CTRL_TYPE_HEVC_PPS :c:type:`V4L.v4l2_ctrl_type`
 replace symbol V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS :c:type:`V4L.v4l2_ctrl_type`
diff --git a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
index c8baa9430c14d..82c8b52e771ce 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
@@ -531,6 +531,18 @@ See also the examples in :ref:`control`.
       - n/a
       - A struct :c:type:`v4l2_ctrl_hevc_decode_params`, containing HEVC
 	decoding parameters for stateless video decoders.
+    * - ``V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS``
+      - n/a
+      - n/a
+      - n/a
+      - A struct :c:type:`v4l2_ctrl_hevc_ext_sps_lt_rps`, containing HEVC
+	extended Long-Term RPS for stateless video decoders.
+    * - ``V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS``
+      - n/a
+      - n/a
+      - n/a
+      - A struct :c:type:`v4l2_ctrl_hevc_ext_sps_st_rps`, containing HEVC
+	extended Short-Term RPS for stateless video decoders.
     * - ``V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR``
       - n/a
       - n/a
-- 
2.52.0



From detlev.casanova at collabora.com  Thu Dec 18 15:28:12 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Thu, 18 Dec 2025 18:28:12 -0500
Subject: [PATCH v7 02/17] media: v4l2-ctrls: Add hevc_ext_sps_[ls]t_rps controls
In-Reply-To: <20251218232829.337811-1-detlev.casanova@collabora.com>
References: <20251218232829.337811-1-detlev.casanova@collabora.com>
Message-ID: <20251218232829.337811-3-detlev.casanova@collabora.com>

The vdpu381 decoder found on newer Rockchip SoC need the information
from the long term and short term ref pic sets from the SPS.

So far, it wasn't included in the v4l2 API, so add it with new dynamic
sized controls.

Each element of the hevc_ext_sps_lt_rps array contains the long term ref
pic set at that index.
Each element of the hevc_ext_sps_st_rps contains the short term ref pic
set at that index, as the raw data.
It is the role of the drivers to calculate the reference sets values.

Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 drivers/media/v4l2-core/v4l2-ctrls-core.c | 28 +++++++++++
 drivers/media/v4l2-core/v4l2-ctrls-defs.c | 10 ++++
 include/uapi/linux/v4l2-controls.h        | 61 +++++++++++++++++++++++
 include/uapi/linux/videodev2.h            |  2 +
 4 files changed, 101 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c
index 209bc05883bb1..f11255255c74f 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-core.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c
@@ -424,6 +424,12 @@ void v4l2_ctrl_type_op_log(const struct v4l2_ctrl *ctrl)
 	case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
 		pr_cont("HEVC_SLICE_PARAMS");
 		break;
+	case V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS:
+		pr_cont("HEVC_EXT_SPS_ST_RPS");
+		break;
+	case V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS:
+		pr_cont("HEVC_EXT_SPS_LT_RPS");
+		break;
 	case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX:
 		pr_cont("HEVC_SCALING_MATRIX");
 		break;
@@ -961,6 +967,8 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
 	struct v4l2_ctrl_h264_pred_weights *p_h264_pred_weights;
 	struct v4l2_ctrl_h264_slice_params *p_h264_slice_params;
 	struct v4l2_ctrl_h264_decode_params *p_h264_dec_params;
+	struct v4l2_ctrl_hevc_ext_sps_lt_rps *p_hevc_lt_rps;
+	struct v4l2_ctrl_hevc_ext_sps_st_rps *p_hevc_st_rps;
 	struct v4l2_ctrl_hevc_sps *p_hevc_sps;
 	struct v4l2_ctrl_hevc_pps *p_hevc_pps;
 	struct v4l2_ctrl_hdr10_mastering_display *p_hdr10_mastering;
@@ -1254,6 +1262,20 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
 	case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
 		break;
 
+	case V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS:
+		p_hevc_st_rps = p;
+
+		if (p_hevc_st_rps->flags & ~V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED)
+			return -EINVAL;
+		break;
+
+	case V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS:
+		p_hevc_lt_rps = p;
+
+		if (p_hevc_lt_rps->flags & ~V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_USED_LT)
+			return -EINVAL;
+		break;
+
 	case V4L2_CTRL_TYPE_HDR10_CLL_INFO:
 		break;
 
@@ -2006,6 +2028,12 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 	case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
 		elem_size = sizeof(struct v4l2_ctrl_hevc_slice_params);
 		break;
+	case V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS:
+		elem_size = sizeof(struct v4l2_ctrl_hevc_ext_sps_st_rps);
+		break;
+	case V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS:
+		elem_size = sizeof(struct v4l2_ctrl_hevc_ext_sps_lt_rps);
+		break;
 	case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX:
 		elem_size = sizeof(struct v4l2_ctrl_hevc_scaling_matrix);
 		break;
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
index ad41f65374e23..167286c9e4243 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
@@ -1233,6 +1233,8 @@ const char *v4l2_ctrl_get_name(u32 id)
 	case V4L2_CID_STATELESS_HEVC_DECODE_MODE:		return "HEVC Decode Mode";
 	case V4L2_CID_STATELESS_HEVC_START_CODE:		return "HEVC Start Code";
 	case V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS:	return "HEVC Entry Point Offsets";
+	case V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS:		return "HEVC Short Term Ref Sets";
+	case V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS:		return "HEVC Long Term Ref Sets";
 	case V4L2_CID_STATELESS_AV1_SEQUENCE:			return "AV1 Sequence Parameters";
 	case V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY:		return "AV1 Tile Group Entry";
 	case V4L2_CID_STATELESS_AV1_FRAME:			return "AV1 Frame Parameters";
@@ -1578,6 +1580,14 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
 		*type = V4L2_CTRL_TYPE_U32;
 		*flags |= V4L2_CTRL_FLAG_DYNAMIC_ARRAY;
 		break;
+	case V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS:
+		*type = V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS;
+		*flags |= V4L2_CTRL_FLAG_DYNAMIC_ARRAY;
+		break;
+	case V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS:
+		*type = V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS;
+		*flags |= V4L2_CTRL_FLAG_DYNAMIC_ARRAY;
+		break;
 	case V4L2_CID_STATELESS_VP9_COMPRESSED_HDR:
 		*type = V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR;
 		break;
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index f84ed133a6c9b..e9f1fcc4f8409 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -2099,6 +2099,8 @@ struct v4l2_ctrl_mpeg2_quantisation {
 #define V4L2_CID_STATELESS_HEVC_DECODE_MODE	(V4L2_CID_CODEC_STATELESS_BASE + 405)
 #define V4L2_CID_STATELESS_HEVC_START_CODE	(V4L2_CID_CODEC_STATELESS_BASE + 406)
 #define V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS (V4L2_CID_CODEC_STATELESS_BASE + 407)
+#define V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS  (V4L2_CID_CODEC_STATELESS_BASE + 408)
+#define V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS  (V4L2_CID_CODEC_STATELESS_BASE + 409)
 
 enum v4l2_stateless_hevc_decode_mode {
 	V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED,
@@ -2554,6 +2556,65 @@ struct v4l2_ctrl_hevc_scaling_matrix {
 	__u8	scaling_list_dc_coef_32x32[2];
 };
 
+#define V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED	0x1
+
+/*
+ * struct v4l2_ctrl_hevc_ext_sps_st_rps - HEVC short term RPS parameters
+ *
+ * Dynamic size 1-dimension array for short term RPS. The number of elements
+ * is v4l2_ctrl_hevc_sps::num_short_term_ref_pic_sets. It can contain up to 65 elements.
+ *
+ * @delta_idx_minus1: Specifies the delta compare to the index. See details in section 7.4.8
+ *                    "Short-term reference picture set semantics" of the specification.
+ * @delta_rps_sign: Sign of the delta as specified in section 7.4.8 "Short-term reference picture
+ *                  set semantics" of the specification.
+ * @abs_delta_rps_minus1: Absolute delta RPS as specified in section 7.4.8 "Short-term reference
+ *                        picture set semantics" of the specification.
+ * @num_negative_pics: Number of short-term RPS entries that have picture order count values less
+ *                     than the picture order count value of the current picture.
+ * @num_positive_pics: Number of short-term RPS entries that have picture order count values
+ *                     greater than the picture order count value of the current picture.
+ * @used_by_curr_pic: Bit j specifies if short-term RPS j is used by the current picture.
+ * @use_delta_flag: Bit j equals to 1 specifies that the j-th entry in the source candidate
+ *                  short-term RPS is included in this candidate short-term RPS.
+ * @delta_poc_s0_minus1: Specifies the negative picture order count delta for the i-th entry in
+ *                       the short-term RPS. See details in section 7.4.8 "Short-term reference
+ *                       picture set semantics" of the specification.
+ * @delta_poc_s1_minus1: Specifies the positive picture order count delta for the i-th entry in
+ *                       the short-term RPS. See details in section 7.4.8 "Short-term reference
+ *                       picture set semantics" of the specification.
+ * @flags: See V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_{}
+ */
+struct v4l2_ctrl_hevc_ext_sps_st_rps {
+	__u8	delta_idx_minus1;
+	__u8	delta_rps_sign;
+	__u8	num_negative_pics;
+	__u8	num_positive_pics;
+	__u32	used_by_curr_pic;
+	__u32	use_delta_flag;
+	__u16	abs_delta_rps_minus1;
+	__u16	delta_poc_s0_minus1[16];
+	__u16	delta_poc_s1_minus1[16];
+	__u16	flags;
+};
+
+#define V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_USED_LT		0x1
+
+/*
+ * struct v4l2_ctrl_hevc_ext_sps_lt_rps - HEVC long term RPS parameters
+ *
+ * Dynamic size 1-dimension array for long term RPS. The number of elements
+ * is v4l2_ctrl_hevc_sps::num_long_term_ref_pics_sps. It can contain up to 65 elements.
+ *
+ * @lt_ref_pic_poc_lsb_sps: picture order count modulo MaxPicOrderCntLsb of the i-th candidate
+ *                          long-term reference picture.
+ * @flags: See V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_{}
+ */
+struct v4l2_ctrl_hevc_ext_sps_lt_rps {
+	__u16	lt_ref_pic_poc_lsb_sps;
+	__u16	flags;
+};
+
 /* Stateless VP9 controls */
 
 #define V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED	0x1
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index add08188f0689..5efaeb74ef92d 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -1985,6 +1985,8 @@ enum v4l2_ctrl_type {
 	V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS	= 0x0272,
 	V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX	= 0x0273,
 	V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS	= 0x0274,
+	V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS	= 0x0275,
+	V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS	= 0x0276,
 
 	V4L2_CTRL_TYPE_AV1_SEQUENCE	    = 0x280,
 	V4L2_CTRL_TYPE_AV1_TILE_GROUP_ENTRY = 0x281,
-- 
2.52.0



From detlev.casanova at collabora.com  Thu Dec 18 15:28:13 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Thu, 18 Dec 2025 18:28:13 -0500
Subject: [PATCH v7 03/17] media: visl: Add HEVC short and long term RPS sets
In-Reply-To: <20251218232829.337811-1-detlev.casanova@collabora.com>
References: <20251218232829.337811-1-detlev.casanova@collabora.com>
Message-ID: <20251218232829.337811-4-detlev.casanova@collabora.com>

Log the recently added v4l2 controls to set HEVC short and long term RPS
sets with 2 new ftrace entries.

Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 drivers/media/test-drivers/visl/visl-dec.c    |  7 +++
 drivers/media/test-drivers/visl/visl-dec.h    |  3 +
 .../media/test-drivers/visl/visl-trace-hevc.h | 59 +++++++++++++++++++
 3 files changed, 69 insertions(+)

diff --git a/drivers/media/test-drivers/visl/visl-dec.c b/drivers/media/test-drivers/visl/visl-dec.c
index d90b79de8384a..6bbf937570478 100644
--- a/drivers/media/test-drivers/visl/visl-dec.c
+++ b/drivers/media/test-drivers/visl/visl-dec.c
@@ -547,6 +547,9 @@ static void visl_trace_ctrls(struct visl_ctx *ctx, struct visl_run *run)
 			trace_v4l2_hevc_dpb_entry(&run->hevc.dpram->dpb[i]);
 
 		trace_v4l2_hevc_pred_weight_table(&run->hevc.spram->pred_weight_table);
+		trace_v4l2_ctrl_hevc_ext_sps_lt_rps(run->hevc.rps_lt);
+		trace_v4l2_ctrl_hevc_ext_sps_st_rps(run->hevc.rps_st);
+
 		break;
 	case VISL_CODEC_AV1:
 		trace_v4l2_ctrl_av1_sequence(run->av1.seq);
@@ -611,6 +614,10 @@ void visl_device_run(void *priv)
 		run.hevc.spram = visl_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_SLICE_PARAMS);
 		run.hevc.sm = visl_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_SCALING_MATRIX);
 		run.hevc.dpram = visl_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_DECODE_PARAMS);
+		run.hevc.rps_lt = visl_find_control_data(ctx,
+							 V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS);
+		run.hevc.rps_st = visl_find_control_data(ctx,
+							 V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS);
 		break;
 	case VISL_CODEC_AV1:
 		run.av1.seq = visl_find_control_data(ctx, V4L2_CID_STATELESS_AV1_SEQUENCE);
diff --git a/drivers/media/test-drivers/visl/visl-dec.h b/drivers/media/test-drivers/visl/visl-dec.h
index c2c2ef3a8798c..6e7562e555bb9 100644
--- a/drivers/media/test-drivers/visl/visl-dec.h
+++ b/drivers/media/test-drivers/visl/visl-dec.h
@@ -7,6 +7,7 @@
 #ifndef _VISL_DEC_H_
 #define _VISL_DEC_H_
 
+#include "linux/v4l2-controls.h"
 #include "visl.h"
 
 struct visl_fwht_run {
@@ -43,6 +44,8 @@ struct visl_hevc_run {
 	const struct v4l2_ctrl_hevc_slice_params *spram;
 	const struct v4l2_ctrl_hevc_scaling_matrix *sm;
 	const struct v4l2_ctrl_hevc_decode_params *dpram;
+	const struct v4l2_ctrl_hevc_ext_sps_lt_rps *rps_lt;
+	const struct v4l2_ctrl_hevc_ext_sps_st_rps *rps_st;
 };
 
 struct visl_av1_run {
diff --git a/drivers/media/test-drivers/visl/visl-trace-hevc.h b/drivers/media/test-drivers/visl/visl-trace-hevc.h
index 837b8ec12e975..963914c463dbc 100644
--- a/drivers/media/test-drivers/visl/visl-trace-hevc.h
+++ b/drivers/media/test-drivers/visl/visl-trace-hevc.h
@@ -1,4 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0+ */
+#include "linux/v4l2-controls.h"
 #if !defined(_VISL_TRACE_HEVC_H_) || defined(TRACE_HEADER_MULTI_READ)
 #define _VISL_TRACE_HEVC_H_
 
@@ -343,6 +344,54 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_decode_params_tmpl,
 	))
 );
 
+DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_ext_sps_lt_rps_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_hevc_ext_sps_lt_rps *lt),
+	TP_ARGS(lt),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_hevc_ext_sps_lt_rps, lt)),
+	TP_fast_assign(__entry->lt = *lt),
+	TP_printk("\nflags %s\n"
+		  "lt_ref_pic_poc_lsb_sps %x\n",
+		  __print_flags(__entry->lt.flags, "|",
+		  {V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_USED_LT, "USED_LT"}
+		  ),
+		  __entry->lt.lt_ref_pic_poc_lsb_sps
+	)
+)
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_ext_sps_st_rps_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_hevc_ext_sps_st_rps *st),
+	TP_ARGS(st),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_hevc_ext_sps_st_rps, st)),
+	TP_fast_assign(__entry->st = *st),
+	TP_printk("\nflags %s\n"
+		  "delta_idx_minus1: %u\n"
+		  "delta_rps_sign: %u\n"
+		  "abs_delta_rps_minus1: %u\n"
+		  "num_negative_pics: %u\n"
+		  "num_positive_pics: %u\n"
+		  "used_by_curr_pic: %08x\n"
+		  "use_delta_flag: %08x\n"
+		  "delta_poc_s0_minus1: %s\n"
+		  "delta_poc_s1_minus1: %s\n",
+		  __print_flags(__entry->st.flags, "|",
+		  {V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED, "INTER_REF_PIC_SET_PRED"}
+		  ),
+		  __entry->st.delta_idx_minus1,
+		  __entry->st.delta_rps_sign,
+		  __entry->st.abs_delta_rps_minus1,
+		  __entry->st.num_negative_pics,
+		  __entry->st.num_positive_pics,
+		  __entry->st.used_by_curr_pic,
+		  __entry->st.use_delta_flag,
+		  __print_array(__entry->st.delta_poc_s0_minus1,
+				ARRAY_SIZE(__entry->st.delta_poc_s0_minus1),
+				sizeof(__entry->st.delta_poc_s0_minus1[0])),
+		  __print_array(__entry->st.delta_poc_s1_minus1,
+				ARRAY_SIZE(__entry->st.delta_poc_s1_minus1),
+				sizeof(__entry->st.delta_poc_s1_minus1[0]))
+	)
+)
+
 
 DECLARE_EVENT_CLASS(v4l2_hevc_dpb_entry_tmpl,
 	TP_PROTO(const struct v4l2_hevc_dpb_entry *e),
@@ -391,6 +440,16 @@ DEFINE_EVENT(v4l2_ctrl_hevc_decode_params_tmpl, v4l2_ctrl_hevc_decode_params,
 	TP_ARGS(d)
 );
 
+DEFINE_EVENT(v4l2_ctrl_hevc_ext_sps_lt_rps_tmpl, v4l2_ctrl_hevc_ext_sps_lt_rps,
+	TP_PROTO(const struct v4l2_ctrl_hevc_ext_sps_lt_rps *lt),
+	TP_ARGS(lt)
+);
+
+DEFINE_EVENT(v4l2_ctrl_hevc_ext_sps_st_rps_tmpl, v4l2_ctrl_hevc_ext_sps_st_rps,
+	TP_PROTO(const struct v4l2_ctrl_hevc_ext_sps_st_rps *st),
+	TP_ARGS(st)
+);
+
 DEFINE_EVENT(v4l2_hevc_dpb_entry_tmpl, v4l2_hevc_dpb_entry,
 	TP_PROTO(const struct v4l2_hevc_dpb_entry *e),
 	TP_ARGS(e)
-- 
2.52.0



From detlev.casanova at collabora.com  Thu Dec 18 15:28:14 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Thu, 18 Dec 2025 18:28:14 -0500
Subject: [PATCH v7 04/17] media: rkvdec: Switch to using structs instead of writel
In-Reply-To: <20251218232829.337811-1-detlev.casanova@collabora.com>
References: <20251218232829.337811-1-detlev.casanova@collabora.com>
Message-ID: <20251218232829.337811-5-detlev.casanova@collabora.com>

In an effort to merge the rkvdec2 driver [1] with this one, switch from
writel() calls to using structs to represent the register mappings.

This is done in order to have all supported decoders use the same format
in the future and ease reading of the code.

Using structs also improves stability as the hardware is tested and
validated downstream using a similar method.
It was noticed, on decoders, that:
 - Some registers require to be writen in increasing order [2]
 - Some registers, even if unrelated, need to be written to their reset
   values (it was the case here for axi_ddr_[rw]data).

Using structs can also help improving performance later when, e.g.
multicore support is added on RK3588.

Performance seems to be slightly improved, but at least, not made worse.
Running fluster's JVT-AVC_V1 test suite with GStreamer on the Radxa ROCK
PI 4 SE gives the following times:

Before this patch:

- --jobs 1: Ran 129/135 tests successfully               in 77.167 secs
- --jobs 6: Ran 129/135 tests successfully               in 23.046 secs

With this patch:
- --jobs 1: Ran 129/135 tests successfully               in 70.698 secs
- --jobs 6: Ran 129/135 tests successfully               in 22.917 secs

This also shows that the fluster score hasn't changed.

[1]: https://lore.kernel.org/all/20250325213303.826925-1-detlev.casanova at collabora.com/
[2]: https://lore.kernel.org/all/20200127143009.15677-5-andrzej.p at collabora.com/

Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../platform/rockchip/rkvdec/rkvdec-h264.c    | 166 +++--
 .../platform/rockchip/rkvdec/rkvdec-hevc.c    |  64 +-
 .../platform/rockchip/rkvdec/rkvdec-regs.h    | 586 ++++++++++++------
 .../platform/rockchip/rkvdec/rkvdec-vp9.c     | 232 +++----
 .../media/platform/rockchip/rkvdec/rkvdec.c   |  10 +-
 .../media/platform/rockchip/rkvdec/rkvdec.h   |   1 +
 6 files changed, 604 insertions(+), 455 deletions(-)

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
index d14b4d173448d..68e20cb81a885 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
@@ -115,6 +115,7 @@ struct rkvdec_h264_run {
 struct rkvdec_h264_ctx {
 	struct rkvdec_aux_buf priv_tbl;
 	struct rkvdec_h264_reflists reflists;
+	struct rkvdec_regs regs;
 };
 
 #define CABAC_ENTRY(ctxidx, idc0_m, idc0_n, idc1_m, idc1_n,		\
@@ -841,45 +842,41 @@ static void assemble_hw_scaling_list(struct rkvdec_ctx *ctx,
 }
 
 /*
- * dpb poc related registers table
+ * Set the ref POC in the correct register.
+ *
+ * The 32 registers are spread across 3 regions, each alternating top and bottom ref POCs:
+ *  - 1: ref 0 to 14 contain top 0 to 7 and bottoms 0 to 6
+ *  - 2: ref 15 to 29 contain top 8 to 14 and bottoms 7 to 14
+ *  - 3: ref 30 and 31 which correspond to top 15 and bottom 15 respectively.
  */
-static const u32 poc_reg_tbl_top_field[16] = {
-	RKVDEC_REG_H264_POC_REFER0(0),
-	RKVDEC_REG_H264_POC_REFER0(2),
-	RKVDEC_REG_H264_POC_REFER0(4),
-	RKVDEC_REG_H264_POC_REFER0(6),
-	RKVDEC_REG_H264_POC_REFER0(8),
-	RKVDEC_REG_H264_POC_REFER0(10),
-	RKVDEC_REG_H264_POC_REFER0(12),
-	RKVDEC_REG_H264_POC_REFER0(14),
-	RKVDEC_REG_H264_POC_REFER1(1),
-	RKVDEC_REG_H264_POC_REFER1(3),
-	RKVDEC_REG_H264_POC_REFER1(5),
-	RKVDEC_REG_H264_POC_REFER1(7),
-	RKVDEC_REG_H264_POC_REFER1(9),
-	RKVDEC_REG_H264_POC_REFER1(11),
-	RKVDEC_REG_H264_POC_REFER1(13),
-	RKVDEC_REG_H264_POC_REFER2(0)
-};
-
-static const u32 poc_reg_tbl_bottom_field[16] = {
-	RKVDEC_REG_H264_POC_REFER0(1),
-	RKVDEC_REG_H264_POC_REFER0(3),
-	RKVDEC_REG_H264_POC_REFER0(5),
-	RKVDEC_REG_H264_POC_REFER0(7),
-	RKVDEC_REG_H264_POC_REFER0(9),
-	RKVDEC_REG_H264_POC_REFER0(11),
-	RKVDEC_REG_H264_POC_REFER0(13),
-	RKVDEC_REG_H264_POC_REFER1(0),
-	RKVDEC_REG_H264_POC_REFER1(2),
-	RKVDEC_REG_H264_POC_REFER1(4),
-	RKVDEC_REG_H264_POC_REFER1(6),
-	RKVDEC_REG_H264_POC_REFER1(8),
-	RKVDEC_REG_H264_POC_REFER1(10),
-	RKVDEC_REG_H264_POC_REFER1(12),
-	RKVDEC_REG_H264_POC_REFER1(14),
-	RKVDEC_REG_H264_POC_REFER2(1)
-};
+static void set_poc_reg(struct rkvdec_regs *regs, uint32_t poc, int id, bool bottom)
+{
+	if (!bottom) {
+		switch (id) {
+		case 0 ... 7:
+			regs->h26x.ref0_14_poc[id * 2] = poc;
+			break;
+		case 8 ... 14:
+			regs->h26x.ref15_29_poc[(id - 8) * 2 + 1] = poc;
+			break;
+		case 15:
+			regs->h26x.ref30_poc = poc;
+			break;
+		}
+	} else {
+		switch (id) {
+		case 0 ... 6:
+			regs->h26x.ref0_14_poc[id * 2 + 1] = poc;
+			break;
+		case 7 ... 14:
+			regs->h26x.ref15_29_poc[(id - 7) * 2] = poc;
+			break;
+		case 15:
+			regs->h26x.ref31_poc = poc;
+			break;
+		}
+	}
+}
 
 static void config_registers(struct rkvdec_ctx *ctx,
 			     struct rkvdec_h264_run *run)
@@ -894,6 +891,7 @@ static void config_registers(struct rkvdec_ctx *ctx,
 	struct vb2_v4l2_buffer *src_buf = run->base.bufs.src;
 	struct vb2_v4l2_buffer *dst_buf = run->base.bufs.dst;
 	const struct v4l2_format *f;
+	struct rkvdec_regs *regs = &h264_ctx->regs;
 	dma_addr_t rlc_addr;
 	dma_addr_t refer_addr;
 	u32 rlc_len;
@@ -903,10 +901,11 @@ static void config_registers(struct rkvdec_ctx *ctx,
 	u32 yuv_virstride = 0;
 	u32 offset;
 	dma_addr_t dst_addr;
-	u32 reg, i;
+	u32 i;
 
-	reg = RKVDEC_MODE(RKVDEC_MODE_H264);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_SYSCTRL);
+	memset(regs, 0, sizeof(*regs));
+
+	regs->common.reg02.dec_mode = RKVDEC_MODE_H264;
 
 	f = &ctx->decoded_fmt;
 	dst_fmt = &f->fmt.pix_mp;
@@ -921,39 +920,35 @@ static void config_registers(struct rkvdec_ctx *ctx,
 	else if (sps->chroma_format_idc == 2)
 		yuv_virstride = 2 * y_virstride;
 
-	reg = RKVDEC_Y_HOR_VIRSTRIDE(hor_virstride / 16) |
-	      RKVDEC_UV_HOR_VIRSTRIDE(hor_virstride / 16) |
-	      RKVDEC_SLICE_NUM_HIGHBIT |
-	      RKVDEC_SLICE_NUM_LOWBITS(0x7ff);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_PICPAR);
+	regs->common.reg03.uv_hor_virstride = hor_virstride / 16;
+	regs->common.reg03.y_hor_virstride = hor_virstride / 16;
+	regs->common.reg03.slice_num_highbit = 1;
+	regs->common.reg03.slice_num_lowbits = 0x7ff;
 
 	/* config rlc base address */
 	rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
-	writel_relaxed(rlc_addr, rkvdec->regs + RKVDEC_REG_STRM_RLC_BASE);
-	writel_relaxed(rlc_addr, rkvdec->regs + RKVDEC_REG_RLCWRITE_BASE);
+	regs->common.strm_rlc_base = rlc_addr;
+	regs->h26x.rlcwrite_base = rlc_addr;
 
 	rlc_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
-	reg = RKVDEC_STRM_LEN(rlc_len);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_STRM_LEN);
+	regs->common.stream_len = rlc_len;
 
 	/* config cabac table */
 	offset = offsetof(struct rkvdec_h264_priv_tbl, cabac_table);
-	writel_relaxed(priv_start_addr + offset,
-		       rkvdec->regs + RKVDEC_REG_CABACTBL_PROB_BASE);
+	regs->common.cabactbl_base = priv_start_addr + offset;
 
 	/* config output base address */
 	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
-	writel_relaxed(dst_addr, rkvdec->regs + RKVDEC_REG_DECOUT_BASE);
+	regs->common.decout_base = dst_addr;
 
-	reg = RKVDEC_Y_VIRSTRIDE(y_virstride / 16);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_Y_VIRSTRIDE);
+	regs->common.reg08.y_virstride = y_virstride / 16;
 
-	reg = RKVDEC_YUV_VIRSTRIDE(yuv_virstride / 16);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_YUV_VIRSTRIDE);
+	regs->common.reg09.yuv_virstride = yuv_virstride / 16;
 
 	/* config ref pic address & poc */
 	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
 		struct vb2_buffer *vb_buf = run->ref_buf[i];
+		struct ref_base *base;
 
 		/*
 		 * If a DPB entry is unused or invalid, address of current destination
@@ -963,54 +958,37 @@ static void config_registers(struct rkvdec_ctx *ctx,
 			vb_buf = &dst_buf->vb2_buf;
 		refer_addr = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
 
-		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)
-			refer_addr |= RKVDEC_COLMV_USED_FLAG_REF;
-		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD)
-			refer_addr |= RKVDEC_FIELD_REF;
-
-		if (dpb[i].fields & V4L2_H264_TOP_FIELD_REF)
-			refer_addr |= RKVDEC_TOPFIELD_USED_REF;
-		if (dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF)
-			refer_addr |= RKVDEC_BOTFIELD_USED_REF;
-
-		writel_relaxed(dpb[i].top_field_order_cnt,
-			       rkvdec->regs +  poc_reg_tbl_top_field[i]);
-		writel_relaxed(dpb[i].bottom_field_order_cnt,
-			       rkvdec->regs + poc_reg_tbl_bottom_field[i]);
-
 		if (i < V4L2_H264_NUM_DPB_ENTRIES - 1)
-			writel_relaxed(refer_addr,
-				       rkvdec->regs + RKVDEC_REG_H264_BASE_REFER(i));
+			base = &regs->h26x.ref0_14_base[i];
 		else
-			writel_relaxed(refer_addr,
-				       rkvdec->regs + RKVDEC_REG_H264_BASE_REFER15);
-	}
+			base = &regs->h26x.ref15_base;
 
-	reg = RKVDEC_CUR_POC(dec_params->top_field_order_cnt);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC0);
+		base->base_addr = refer_addr >> 4;
+		base->field_ref = !!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD);
+		base->colmv_use_flag_ref = !!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE);
+		base->topfield_used_ref = !!(dpb[i].fields & V4L2_H264_TOP_FIELD_REF);
+		base->botfield_used_ref = !!(dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF);
 
-	reg = RKVDEC_CUR_POC(dec_params->bottom_field_order_cnt);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC1);
+		set_poc_reg(regs, dpb[i].top_field_order_cnt, i, false);
+		set_poc_reg(regs, dpb[i].bottom_field_order_cnt, i, true);
+	}
+
+	regs->h26x.cur_poc = dec_params->top_field_order_cnt;
+	regs->h26x.cur_poc1 = dec_params->bottom_field_order_cnt;
 
 	/* config hw pps address */
 	offset = offsetof(struct rkvdec_h264_priv_tbl, param_set);
-	writel_relaxed(priv_start_addr + offset,
-		       rkvdec->regs + RKVDEC_REG_PPS_BASE);
+	regs->h26x.pps_base = priv_start_addr + offset;
 
 	/* config hw rps address */
 	offset = offsetof(struct rkvdec_h264_priv_tbl, rps);
-	writel_relaxed(priv_start_addr + offset,
-		       rkvdec->regs + RKVDEC_REG_RPS_BASE);
-
-	reg = RKVDEC_AXI_DDR_RDATA(0);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_RDATA);
-
-	reg = RKVDEC_AXI_DDR_WDATA(0);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_WDATA);
+	regs->h26x.rps_base = priv_start_addr + offset;
 
 	offset = offsetof(struct rkvdec_h264_priv_tbl, err_info);
-	writel_relaxed(priv_start_addr + offset,
-		       rkvdec->regs + RKVDEC_REG_H264_ERRINFO_BASE);
+	regs->h26x.errorinfo_base = priv_start_addr + offset;
+
+	rkvdec_memcpy_toio(rkvdec->regs, regs,
+			   MIN(sizeof(*regs), sizeof(u32) * rkvdec->variant->num_regs));
 }
 
 #define RKVDEC_H264_MAX_DEPTH_IN_BYTES		2
@@ -1181,8 +1159,6 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
 
 	schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000));
 
-	writel(0, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN);
-	writel(0, rkvdec->regs + RKVDEC_REG_H264_ERR_E);
 	writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND);
 	writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);
 
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
index fc7e6a260b0a7..2d9e0e947a6dc 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
@@ -129,6 +129,7 @@ struct rkvdec_hevc_run {
 struct rkvdec_hevc_ctx {
 	struct rkvdec_aux_buf priv_tbl;
 	struct v4l2_ctrl_hevc_scaling_matrix scaling_matrix_cache;
+	struct rkvdec_regs regs;
 };
 
 struct scaling_factor {
@@ -548,6 +549,7 @@ static void config_registers(struct rkvdec_ctx *ctx,
 	const struct v4l2_ctrl_hevc_slice_params *sl_params = &run->slices_params[0];
 	const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb;
 	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
+	struct rkvdec_regs *regs = &hevc_ctx->regs;
 	dma_addr_t priv_start_addr = hevc_ctx->priv_tbl.dma;
 	const struct v4l2_pix_format_mplane *dst_fmt;
 	struct vb2_v4l2_buffer *src_buf = run->base.bufs.src;
@@ -564,8 +566,9 @@ static void config_registers(struct rkvdec_ctx *ctx,
 	dma_addr_t dst_addr;
 	u32 reg, i;
 
-	reg = RKVDEC_MODE(RKVDEC_MODE_HEVC);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_SYSCTRL);
+	memset(regs, 0, sizeof(*regs));
+
+	regs->common.reg02.dec_mode = RKVDEC_MODE_HEVC;
 
 	f = &ctx->decoded_fmt;
 	dst_fmt = &f->fmt.pix_mp;
@@ -580,33 +583,27 @@ static void config_registers(struct rkvdec_ctx *ctx,
 	else if (sps->chroma_format_idc == 2)
 		yuv_virstride = 2 * y_virstride;
 
-	reg = RKVDEC_Y_HOR_VIRSTRIDE(hor_virstride / 16) |
-	      RKVDEC_UV_HOR_VIRSTRIDE(hor_virstride / 16) |
-	      RKVDEC_SLICE_NUM_LOWBITS(run->num_slices);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_PICPAR);
+	regs->common.reg03.slice_num_lowbits = run->num_slices;
+	regs->common.reg03.uv_hor_virstride = hor_virstride / 16;
+	regs->common.reg03.y_hor_virstride = hor_virstride / 16;
 
 	/* config rlc base address */
 	rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
-	writel_relaxed(rlc_addr, rkvdec->regs + RKVDEC_REG_STRM_RLC_BASE);
+	regs->common.strm_rlc_base = rlc_addr;
 
 	rlc_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
-	reg = RKVDEC_STRM_LEN(round_up(rlc_len, 16) + 64);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_STRM_LEN);
+	regs->common.stream_len = round_up(rlc_len, 16) + 64;
 
 	/* config cabac table */
 	offset = offsetof(struct rkvdec_hevc_priv_tbl, cabac_table);
-	writel_relaxed(priv_start_addr + offset,
-		       rkvdec->regs + RKVDEC_REG_CABACTBL_PROB_BASE);
+	regs->common.cabactbl_base = priv_start_addr + offset;
 
 	/* config output base address */
 	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
-	writel_relaxed(dst_addr, rkvdec->regs + RKVDEC_REG_DECOUT_BASE);
-
-	reg = RKVDEC_Y_VIRSTRIDE(y_virstride / 16);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_Y_VIRSTRIDE);
+	regs->common.decout_base = dst_addr;
 
-	reg = RKVDEC_YUV_VIRSTRIDE(yuv_virstride / 16);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_YUV_VIRSTRIDE);
+	regs->common.reg08.y_virstride = y_virstride / 16;
+	regs->common.reg09.yuv_virstride = yuv_virstride / 16;
 
 	/* config ref pic address */
 	for (i = 0; i < 15; i++) {
@@ -620,33 +617,30 @@ static void config_registers(struct rkvdec_ctx *ctx,
 		}
 
 		refer_addr = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
-		writel_relaxed(refer_addr | reg,
-			       rkvdec->regs + RKVDEC_REG_H264_BASE_REFER(i));
 
-		reg = RKVDEC_POC_REFER(i < decode_params->num_active_dpb_entries ?
-			dpb[i].pic_order_cnt_val : 0);
-		writel_relaxed(reg,
-			       rkvdec->regs + RKVDEC_REG_H264_POC_REFER0(i));
+		regs->h26x.ref0_14_base[i].base_addr = refer_addr >> 4;
+		regs->h26x.ref0_14_base[i].field_ref = !!(reg & 1);
+		regs->h26x.ref0_14_base[i].topfield_used_ref = !!(reg & 2);
+		regs->h26x.ref0_14_base[i].botfield_used_ref = !!(reg & 4);
+		regs->h26x.ref0_14_base[i].colmv_use_flag_ref = !!(reg & 8);
+
+		regs->h26x.ref0_14_poc[i] = i < decode_params->num_active_dpb_entries
+					    ? dpb[i].pic_order_cnt_val
+					    : 0;
 	}
 
-	reg = RKVDEC_CUR_POC(sl_params->slice_pic_order_cnt);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC0);
+	regs->h26x.cur_poc = sl_params->slice_pic_order_cnt;
 
 	/* config hw pps address */
 	offset = offsetof(struct rkvdec_hevc_priv_tbl, param_set);
-	writel_relaxed(priv_start_addr + offset,
-		       rkvdec->regs + RKVDEC_REG_PPS_BASE);
+	regs->h26x.pps_base = priv_start_addr + offset;
 
 	/* config hw rps address */
 	offset = offsetof(struct rkvdec_hevc_priv_tbl, rps);
-	writel_relaxed(priv_start_addr + offset,
-		       rkvdec->regs + RKVDEC_REG_RPS_BASE);
-
-	reg = RKVDEC_AXI_DDR_RDATA(0);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_RDATA);
+	regs->h26x.rps_base = priv_start_addr + offset;
 
-	reg = RKVDEC_AXI_DDR_WDATA(0);
-	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_WDATA);
+	rkvdec_memcpy_toio(rkvdec->regs, regs,
+			   MIN(sizeof(*regs), sizeof(u32) * rkvdec->variant->num_regs));
 }
 
 #define RKVDEC_HEVC_MAX_DEPTH_IN_BYTES		2
@@ -784,8 +778,6 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
 
 	schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000));
 
-	writel(0, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN);
-	writel(0, rkvdec->regs + RKVDEC_REG_H264_ERR_E);
 	writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND);
 	writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);
 
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h
index c627b6b6f53a1..1af66c5f1c9b6 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h
@@ -3,7 +3,12 @@
 #ifndef RKVDEC_REGS_H_
 #define RKVDEC_REGS_H_
 
-/* rkvcodec registers */
+#include <linux/types.h>
+
+/*
+ * REG_INTERRUPT is accessed via writel to enable the decoder after
+ * configuring it and clear interrupt strmd_error_status
+ */
 #define RKVDEC_REG_INTERRUPT				0x004
 #define RKVDEC_INTERRUPT_DEC_E				BIT(0)
 #define RKVDEC_CONFIG_DEC_CLK_GATE_E			BIT(1)
@@ -30,198 +35,399 @@
 #define RKVDEC_SOFTRESET_RDY				BIT(22)
 #define RKVDEC_WR_DDR_ALIGN_EN				BIT(23)
 
-#define RKVDEC_REG_SYSCTRL				0x008
-#define RKVDEC_IN_ENDIAN				BIT(0)
-#define RKVDEC_IN_SWAP32_E				BIT(1)
-#define RKVDEC_IN_SWAP64_E				BIT(2)
-#define RKVDEC_STR_ENDIAN				BIT(3)
-#define RKVDEC_STR_SWAP32_E				BIT(4)
-#define RKVDEC_STR_SWAP64_E				BIT(5)
-#define RKVDEC_OUT_ENDIAN				BIT(6)
-#define RKVDEC_OUT_SWAP32_E				BIT(7)
-#define RKVDEC_OUT_CBCR_SWAP				BIT(8)
-#define RKVDEC_RLC_MODE_DIRECT_WRITE			BIT(10)
-#define RKVDEC_RLC_MODE					BIT(11)
-#define RKVDEC_STRM_START_BIT(x)			(((x) & 0x7f) << 12)
-#define RKVDEC_MODE(x)					(((x) & 0x03) << 20)
-#define RKVDEC_MODE_HEVC				0
-#define RKVDEC_MODE_H264				1
-#define RKVDEC_MODE_VP9					2
-#define RKVDEC_RPS_MODE					BIT(24)
-#define RKVDEC_STRM_MODE				BIT(25)
-#define RKVDEC_H264_STRM_LASTPKT			BIT(26)
-#define RKVDEC_H264_FIRSTSLICE_FLAG			BIT(27)
-#define RKVDEC_H264_FRAME_ORSLICE			BIT(28)
-#define RKVDEC_BUSPR_SLOT_DIS				BIT(29)
-
-#define RKVDEC_REG_PICPAR				0x00C
-#define RKVDEC_Y_HOR_VIRSTRIDE(x)			((x) & 0x1ff)
-#define RKVDEC_SLICE_NUM_HIGHBIT			BIT(11)
-#define RKVDEC_UV_HOR_VIRSTRIDE(x)			(((x) & 0x1ff) << 12)
-#define RKVDEC_SLICE_NUM_LOWBITS(x)			(((x) & 0x7ff) << 21)
-
-#define RKVDEC_REG_STRM_RLC_BASE			0x010
-
-#define RKVDEC_REG_STRM_LEN				0x014
-#define RKVDEC_STRM_LEN(x)				((x) & 0x7ffffff)
-
-#define RKVDEC_REG_CABACTBL_PROB_BASE			0x018
-#define RKVDEC_REG_DECOUT_BASE				0x01C
-
-#define RKVDEC_REG_Y_VIRSTRIDE				0x020
-#define RKVDEC_Y_VIRSTRIDE(x)				((x) & 0xfffff)
-
-#define RKVDEC_REG_YUV_VIRSTRIDE			0x024
-#define RKVDEC_YUV_VIRSTRIDE(x)				((x) & 0x1fffff)
-#define RKVDEC_REG_H264_BASE_REFER(i)			(((i) * 0x04) + 0x028)
-
-#define RKVDEC_REG_H264_BASE_REFER15			0x0C0
-#define RKVDEC_FIELD_REF				BIT(0)
-#define RKVDEC_TOPFIELD_USED_REF			BIT(1)
-#define RKVDEC_BOTFIELD_USED_REF			BIT(2)
-#define RKVDEC_COLMV_USED_FLAG_REF			BIT(3)
-
-#define RKVDEC_REG_VP9_LAST_FRAME_BASE			0x02c
-#define RKVDEC_REG_VP9_GOLDEN_FRAME_BASE		0x030
-#define RKVDEC_REG_VP9_ALTREF_FRAME_BASE		0x034
-
-#define RKVDEC_REG_VP9_CPRHEADER_OFFSET			0x028
-#define RKVDEC_VP9_CPRHEADER_OFFSET(x)			((x) & 0xffff)
-
-#define RKVDEC_REG_VP9_REFERLAST_BASE			0x02C
-#define RKVDEC_REG_VP9_REFERGOLDEN_BASE			0x030
-#define RKVDEC_REG_VP9_REFERALFTER_BASE			0x034
-
-#define RKVDEC_REG_VP9COUNT_BASE			0x038
-#define RKVDEC_VP9COUNT_UPDATE_EN			BIT(0)
-
-#define RKVDEC_REG_VP9_SEGIDLAST_BASE			0x03C
-#define RKVDEC_REG_VP9_SEGIDCUR_BASE			0x040
-#define RKVDEC_REG_VP9_FRAME_SIZE(i)			((i) * 0x04 + 0x044)
-#define RKVDEC_VP9_FRAMEWIDTH(x)			(((x) & 0xffff) << 0)
-#define RKVDEC_VP9_FRAMEHEIGHT(x)			(((x) & 0xffff) << 16)
-
-#define RKVDEC_VP9_SEGID_GRP(i)				((i) * 0x04 + 0x050)
-#define RKVDEC_SEGID_ABS_DELTA(x)			((x) & 0x1)
-#define RKVDEC_SEGID_FRAME_QP_DELTA_EN(x)		(((x) & 0x1) << 1)
-#define RKVDEC_SEGID_FRAME_QP_DELTA(x)			(((x) & 0x1ff) << 2)
-#define RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE_EN(x)	(((x) & 0x1) << 11)
-#define RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE(x)		(((x) & 0x7f) << 12)
-#define RKVDEC_SEGID_REFERINFO_EN(x)			(((x) & 0x1) << 19)
-#define RKVDEC_SEGID_REFERINFO(x)			(((x) & 0x03) << 20)
-#define RKVDEC_SEGID_FRAME_SKIP_EN(x)			(((x) & 0x1) << 22)
-
-#define RKVDEC_VP9_CPRHEADER_CONFIG			0x070
-#define RKVDEC_VP9_TX_MODE(x)				((x) & 0x07)
-#define RKVDEC_VP9_FRAME_REF_MODE(x)			(((x) & 0x03) << 3)
-
-#define RKVDEC_VP9_REF_SCALE(i)				((i) * 0x04 + 0x074)
-#define RKVDEC_VP9_REF_HOR_SCALE(x)			((x) & 0xffff)
-#define RKVDEC_VP9_REF_VER_SCALE(x)			(((x) & 0xffff) << 16)
-
-#define RKVDEC_VP9_REF_DELTAS_LASTFRAME			0x080
-#define RKVDEC_REF_DELTAS_LASTFRAME(pos, val)		(((val) & 0x7f) << ((pos) * 7))
-
-#define RKVDEC_VP9_INFO_LASTFRAME			0x084
-#define RKVDEC_MODE_DELTAS_LASTFRAME(pos, val)		(((val) & 0x7f) << ((pos) * 7))
-#define RKVDEC_SEG_EN_LASTFRAME				BIT(16)
-#define RKVDEC_LAST_SHOW_FRAME				BIT(17)
-#define RKVDEC_LAST_INTRA_ONLY				BIT(18)
-#define RKVDEC_LAST_WIDHHEIGHT_EQCUR			BIT(19)
-#define RKVDEC_COLOR_SPACE_LASTKEYFRAME(x)		(((x) & 0x07) << 20)
-
-#define RKVDEC_VP9_INTERCMD_BASE			0x088
-
-#define RKVDEC_VP9_INTERCMD_NUM				0x08C
-#define RKVDEC_INTERCMD_NUM(x)				((x) & 0xffffff)
-
-#define RKVDEC_VP9_LASTTILE_SIZE			0x090
-#define RKVDEC_LASTTILE_SIZE(x)				((x) & 0xffffff)
-
-#define RKVDEC_VP9_HOR_VIRSTRIDE(i)			((i) * 0x04 + 0x094)
-#define RKVDEC_HOR_Y_VIRSTRIDE(x)			((x) & 0x1ff)
-#define RKVDEC_HOR_UV_VIRSTRIDE(x)			(((x) & 0x1ff) << 16)
-
-#define RKVDEC_REG_H264_POC_REFER0(i)			(((i) * 0x04) + 0x064)
-#define RKVDEC_REG_H264_POC_REFER1(i)			(((i) * 0x04) + 0x0C4)
-#define RKVDEC_REG_H264_POC_REFER2(i)			(((i) * 0x04) + 0x120)
-#define RKVDEC_POC_REFER(x)				((x) & 0xffffffff)
-
-#define RKVDEC_REG_CUR_POC0				0x0A0
-#define RKVDEC_REG_CUR_POC1				0x128
-#define RKVDEC_CUR_POC(x)				((x) & 0xffffffff)
-
-#define RKVDEC_REG_RLCWRITE_BASE			0x0A4
-#define RKVDEC_REG_PPS_BASE				0x0A8
-#define RKVDEC_REG_RPS_BASE				0x0AC
-
-#define RKVDEC_REG_STRMD_ERR_EN				0x0B0
-#define RKVDEC_STRMD_ERR_EN(x)				((x) & 0xffffffff)
-
-#define RKVDEC_REG_STRMD_ERR_STA			0x0B4
-#define RKVDEC_STRMD_ERR_STA(x)				((x) & 0xfffffff)
-#define RKVDEC_COLMV_ERR_REF_PICIDX(x)			(((x) & 0x0f) << 28)
-
-#define RKVDEC_REG_STRMD_ERR_CTU			0x0B8
-#define RKVDEC_STRMD_ERR_CTU(x)				((x) & 0xff)
-#define RKVDEC_STRMD_ERR_CTU_YOFFSET(x)			(((x) & 0xff) << 8)
-#define RKVDEC_STRMFIFO_SPACE2FULL(x)			(((x) & 0x7f) << 16)
-#define RKVDEC_VP9_ERR_EN_CTU0				BIT(24)
-
-#define RKVDEC_REG_SAO_CTU_POS				0x0BC
-#define RKVDEC_SAOWR_XOFFSET(x)				((x) & 0x1ff)
-#define RKVDEC_SAOWR_YOFFSET(x)				(((x) & 0x3ff) << 16)
-
-#define RKVDEC_VP9_LAST_FRAME_YSTRIDE			0x0C0
-#define RKVDEC_VP9_GOLDEN_FRAME_YSTRIDE			0x0C4
-#define RKVDEC_VP9_ALTREF_FRAME_YSTRIDE			0x0C8
-#define RKVDEC_VP9_REF_YSTRIDE(x)			(((x) & 0xfffff) << 0)
-
-#define RKVDEC_VP9_LAST_FRAME_YUVSTRIDE			0x0CC
-#define RKVDEC_VP9_REF_YUVSTRIDE(x)			(((x) & 0x1fffff) << 0)
-
-#define RKVDEC_VP9_REF_COLMV_BASE			0x0D0
-
-#define RKVDEC_REG_PERFORMANCE_CYCLE			0x100
-#define RKVDEC_PERFORMANCE_CYCLE(x)			((x) & 0xffffffff)
-
-#define RKVDEC_REG_AXI_DDR_RDATA			0x104
-#define RKVDEC_AXI_DDR_RDATA(x)				((x) & 0xffffffff)
-
-#define RKVDEC_REG_AXI_DDR_WDATA			0x108
-#define RKVDEC_AXI_DDR_WDATA(x)				((x) & 0xffffffff)
-
-#define RKVDEC_REG_FPGADEBUG_RESET			0x10C
-#define RKVDEC_BUSIFD_RESETN				BIT(0)
-#define RKVDEC_CABAC_RESETN				BIT(1)
-#define RKVDEC_DEC_CTRL_RESETN				BIT(2)
-#define RKVDEC_TRANSD_RESETN				BIT(3)
-#define RKVDEC_INTRA_RESETN				BIT(4)
-#define RKVDEC_INTER_RESETN				BIT(5)
-#define RKVDEC_RECON_RESETN				BIT(6)
-#define RKVDEC_FILER_RESETN				BIT(7)
-
-#define RKVDEC_REG_PERFORMANCE_SEL			0x110
-#define RKVDEC_PERF_SEL_CNT0(x)				((x) & 0x3f)
-#define RKVDEC_PERF_SEL_CNT1(x)				(((x) & 0x3f) << 8)
-#define RKVDEC_PERF_SEL_CNT2(x)				(((x) & 0x3f) << 16)
-
-#define RKVDEC_REG_PERFORMANCE_CNT(i)			((i) * 0x04 + 0x114)
-#define RKVDEC_PERF_CNT(x)				((x) & 0xffffffff)
-
-#define RKVDEC_REG_H264_ERRINFO_BASE			0x12C
-
-#define RKVDEC_REG_H264_ERRINFO_NUM			0x130
-#define RKVDEC_SLICEDEC_NUM(x)				((x) & 0x3fff)
-#define RKVDEC_STRMD_DECT_ERR_FLAG			BIT(15)
-#define RKVDEC_ERR_PKT_NUM(x)				(((x) & 0x3fff) << 16)
-
-#define RKVDEC_REG_H264_ERR_E				0x134
-#define RKVDEC_H264_ERR_EN_HIGHBITS(x)			((x) & 0x3fffffff)
-
 #define RKVDEC_REG_QOS_CTRL				0x18C
 
+/*
+ * Cache configuration is not covered in the range of the register struct
+ */
 #define RKVDEC_REG_PREF_LUMA_CACHE_COMMAND		0x410
 #define RKVDEC_REG_PREF_CHR_CACHE_COMMAND		0x450
 
+/*
+ * Define the mode values
+ */
+#define RKVDEC_MODE_HEVC				0
+#define RKVDEC_MODE_H264				1
+#define RKVDEC_MODE_VP9					2
+
+/* rkvcodec registers */
+struct rkvdec_common_regs {
+	struct rkvdec_id {
+		u32 minor_ver	: 8;
+		u32 level	: 1;
+		u32 dec_support	: 3;
+		u32 profile	: 1;
+		u32 reserved0	: 1;
+		u32 codec_flag	: 1;
+		u32 reserved1	: 1;
+		u32 prod_num	: 16;
+	} reg00;
+
+	struct rkvdec_int {
+		u32 dec_e			: 1;
+		u32 dec_clkgate_e		: 1;
+		u32 dec_e_strmd_clkgate_dis	: 1;
+		u32 timeout_mode		: 1;
+		u32 dec_irq_dis			: 1;
+		u32 dec_timeout_e		: 1;
+		u32 buf_empty_en		: 1;
+		u32 stmerror_waitdecfifo_empty	: 1;
+		u32 dec_irq			: 1;
+		u32 dec_irq_raw			: 1;
+		u32 reserved2			: 2;
+		u32 dec_rdy_sta			: 1;
+		u32 dec_bus_sta			: 1;
+		u32 dec_error_sta		: 1;
+		u32 dec_timeout_sta		: 1;
+		u32 dec_empty_sta		: 1;
+		u32 colmv_ref_error_sta		: 1;
+		u32 cabu_end_sta		: 1;
+		u32 h264orvp9_error_mode	: 1;
+		u32 softrst_en_p		: 1;
+		u32 force_softreset_valid	: 1;
+		u32 softreset_rdy		: 1;
+		u32 wr_ddr_align_en		: 1;
+		u32 scl_down_en			: 1;
+		u32 allow_not_wr_unref_bframe	: 1;
+		u32 reserved1			: 6;
+	} reg01;
+
+	struct rkvdec_sysctrl {
+		u32 in_endian			: 1;
+		u32 in_swap32_e			: 1;
+		u32 in_swap64_e			: 1;
+		u32 str_endian			: 1;
+		u32 str_swap32_e		: 1;
+		u32 str_swap64_e		: 1;
+		u32 out_endian			: 1;
+		u32 out_swap32_e		: 1;
+		u32 out_cbcr_swap		: 1;
+		u32 reserved0			: 1;
+		u32 rlc_mode_direct_write	: 1;
+		u32 rlc_mode			: 1;
+		u32 strm_start_bit		: 7;
+		u32 reserved1			: 1;
+		u32 dec_mode			: 2;
+		u32 reserved2			: 2;
+		u32 rps_mode			: 1;
+		u32 stream_mode			: 1;
+		u32 stream_lastpacket		: 1;
+		u32 firstslice_flag		: 1;
+		u32 frame_orslice		: 1;
+		u32 buspr_slot_disable		: 1;
+		u32 colmv_mode			: 1;
+		u32 ycacherd_prior		: 1;
+	} reg02;
+
+	struct rkvdec_picpar {
+		u32 y_hor_virstride	: 9;
+		u32 reserved		: 2;
+		u32 slice_num_highbit	: 1;
+		u32 uv_hor_virstride	: 9;
+		u32 slice_num_lowbits	: 11;
+	} reg03;
+
+	u32 strm_rlc_base;
+	u32 stream_len;
+	u32 cabactbl_base;
+	u32 decout_base;
+
+	struct rkvdec_y_virstride {
+		u32 y_virstride	: 20;
+		u32 reserved0	: 12;
+	} reg08;
+
+	struct rkvdec_yuv_virstride {
+		u32 yuv_virstride	: 21;
+		u32 reserved0		: 11;
+	} reg09;
+} __packed;
+
+struct ref_base {
+	u32 field_ref		: 1;
+	u32 topfield_used_ref	: 1;
+	u32 botfield_used_ref	: 1;
+	u32 colmv_use_flag_ref	: 1;
+	u32 base_addr		: 28;
+};
+
+struct rkvdec_h26x_regs {
+	struct ref_base ref0_14_base[15];
+	u32 ref0_14_poc[15];
+
+	u32 cur_poc;
+	u32 rlcwrite_base;
+	u32 pps_base;
+	u32 rps_base;
+
+	u32 strmd_error_e;
+
+	struct {
+		u32 strmd_error_status		: 28;
+		u32 colmv_error_ref_picidx	: 4;
+	} reg45;
+
+	struct {
+		u32 strmd_error_ctu_xoffset	: 8;
+		u32 strmd_error_ctu_yoffset	: 8;
+		u32 streamfifo_space2full	: 7;
+		u32 reserved0			: 1;
+		u32 vp9_error_ctu0_en		: 1;
+		u32 reserved1			: 7;
+	} reg46;
+
+	struct {
+		u32 saowr_xoffet	: 9;
+		u32 reserved0		: 7;
+		u32 saowr_yoffset	: 10;
+		u32 reserved1		: 6;
+	} reg47;
+
+	struct ref_base ref15_base;
+
+	u32 ref15_29_poc[15];
+
+	u32 performance_cycle;
+	u32 axi_ddr_rdata;
+	u32 axi_ddr_wdata;
+
+	struct {
+		u32 busifd_resetn	: 1;
+		u32 cabac_resetn	: 1;
+		u32 dec_ctrl_resetn	: 1;
+		u32 transd_resetn	: 1;
+		u32 intra_resetn	: 1;
+		u32 inter_resetn	: 1;
+		u32 recon_resetn	: 1;
+		u32 filer_resetn	: 1;
+		u32 reserved0		: 24;
+	} reg67;
+
+	struct {
+		u32 perf_cnt0_sel	: 6;
+		u32 reserved0		: 2;
+		u32 perf_cnt1_sel	: 6;
+		u32 reserved1		: 2;
+		u32 perf_cnt2_sel	: 6;
+		u32 reserved2		: 10;
+	} reg68;
+
+	u32 perf_cnt0;
+	u32 perf_cnt1;
+	u32 perf_cnt2;
+	u32 ref30_poc;
+	u32 ref31_poc;
+	u32 cur_poc1;
+	u32 errorinfo_base;
+
+	struct {
+		u32 slicedec_num		: 14;
+		u32 reserved0			: 1;
+		u32 strmd_detect_error_flag	: 1;
+		u32 error_packet_num		: 14;
+		u32 reserved1			: 2;
+	} reg76;
+
+	struct {
+		u32 error_en_highbits		: 30;
+		u32 strmd_error_slice_en	: 1;
+		u32 strmd_error_frame_en	: 1;
+	} reg77;
+
+	u32 colmv_cur_base;
+	u32 colmv_ref_base[16];
+	u32 scanlist_addr;
+	u32 reg96_sd_decout_base;
+	u32 sd_y_virstride;
+	u32 sd_hor_stride;
+	u32 qos_ctrl;
+	u32 perf[8];
+	u32 qos1;
+} __packed;
+
+struct rkvdec_vp9_regs {
+	struct cprheader_offset {
+		u32 cprheader_offset	: 16;
+		u32 reserved		: 16;
+	} reg10;
+
+	u32 refer_bases[3];
+	u32 count_base;
+	u32 segidlast_base;
+	u32 segidcur_base;
+
+	struct frame_sizes {
+		u32 framewidth		: 16;
+		u32 frameheight		: 16;
+	} reg17_19[3];
+
+	struct segid_grp {
+		u32 segid_abs_delta			: 1;
+		u32 segid_frame_qp_delta_en		: 1;
+		u32 segid_frame_qp_delta		: 9;
+		u32 segid_frame_loopfilter_value_en	: 1;
+		u32 segid_frame_loopfilter_value	: 7;
+		u32 segid_referinfo_en			: 1;
+		u32 segid_referinfo			: 2;
+		u32 segid_frame_skip_en			: 1;
+		u32 reserved				: 9;
+	} reg20_27[8];
+
+	struct cprheader_config {
+		u32 tx_mode			: 3;
+		u32 frame_reference_mode	: 2;
+		u32 reserved			: 27;
+	} reg28;
+
+	struct ref_scale {
+		u32 ref_hor_scale		: 16;
+		u32 ref_ver_scale		: 16;
+	} reg29_31[3];
+
+	struct ref_deltas_lastframe {
+		u32 ref_deltas_lastframe0	: 7;
+		u32 ref_deltas_lastframe1	: 7;
+		u32 ref_deltas_lastframe2	: 7;
+		u32 ref_deltas_lastframe3	: 7;
+		u32 reserved			: 4;
+	} reg32;
+
+	struct info_lastframe {
+		u32 mode_deltas_lastframe0		: 7;
+		u32 mode_deltas_lastframe1		: 7;
+		u32 reserved0				: 2;
+		u32 segmentation_enable_lstframe	: 1;
+		u32 last_show_frame			: 1;
+		u32 last_intra_only			: 1;
+		u32 last_widthheight_eqcur		: 1;
+		u32 color_space_lastkeyframe		: 3;
+		u32 reserved1				: 9;
+	} reg33;
+
+	u32 intercmd_base;
+
+	struct intercmd_num {
+		u32 intercmd_num	: 24;
+		u32 reserved		: 8;
+	} reg35;
+
+	struct lasttile_size {
+		u32 lasttile_size	: 24;
+		u32 reserved		: 8;
+	} reg36;
+
+	struct hor_virstride {
+		u32 y_hor_virstride	: 9;
+		u32 reserved0		: 7;
+		u32 uv_hor_virstride	: 9;
+		u32 reserved1		: 7;
+	} reg37_39[3];
+
+	u32 cur_poc;
+
+	struct rlcwrite_base {
+		u32 reserved		: 3;
+		u32 rlcwrite_base	: 29;
+	} reg41;
+
+	struct pps_base {
+		u32 reserved	: 4;
+		u32 pps_base	: 28;
+	} reg42;
+
+	struct rps_base {
+		u32 reserved	: 4;
+		u32 rps_base	: 28;
+	} reg43;
+
+	struct strmd_error_en {
+		u32 strmd_error_e	: 28;
+		u32 reserved		: 4;
+	} reg44;
+
+	u32 vp9_error_info0;
+
+	struct strmd_error_ctu {
+		u32 strmd_error_ctu_xoffset	: 8;
+		u32 strmd_error_ctu_yoffset	: 8;
+		u32 streamfifo_space2full	: 7;
+		u32 reserved0			: 1;
+		u32 error_ctu0_en		: 1;
+		u32 reserved1			: 7;
+	} reg46;
+
+	struct sao_ctu_position {
+		u32 saowr_xoffet	: 9;
+		u32 reserved0		: 7;
+		u32 saowr_yoffset	: 10;
+		u32 reserved1		: 6;
+	} reg47;
+
+	struct ystride {
+		u32 virstride	: 20;
+		u32 reserved	: 12;
+	} reg48_50[3];
+
+	struct lastref_yuvstride {
+		u32 lastref_yuv_virstride	: 21;
+		u32 reserved			: 11;
+	} reg51;
+
+	u32 refcolmv_base;
+
+	u32 reserved0[11];
+
+	u32 performance_cycle;
+	u32 axi_ddr_rdata;
+	u32 axi_ddr_wdata;
+
+	struct fpgadebug_reset {
+		u32 busifd_resetn	: 1;
+		u32 cabac_resetn	: 1;
+		u32 dec_ctrl_resetn	: 1;
+		u32 transd_resetn	: 1;
+		u32 intra_resetn	: 1;
+		u32 inter_resetn	: 1;
+		u32 recon_resetn	: 1;
+		u32 filer_resetn	: 1;
+		u32 reserved		: 24;
+	} reg67;
+
+	struct performance_sel {
+		u32 perf_cnt0_sel	: 6;
+		u32 reserved0		: 2;
+		u32 perf_cnt1_sel	: 6;
+		u32 reserved1		: 2;
+		u32 perf_cnt2_sel	: 6;
+		u32 reserved		: 10;
+	} reg68;
+
+	u32 perf_cnt0;
+	u32 perf_cnt1;
+	u32 perf_cnt2;
+
+	u32 reserved1[3];
+
+	u32 vp9_error_info1;
+
+	struct error_ctu1 {
+		u32 vp9_error_ctu1_x	: 6;
+		u32 reserved0		: 2;
+		u32 vp9_error_ctu1_y	: 6;
+		u32 reserved1		: 1;
+		u32 vp9_error_ctu1_en	: 1;
+		u32 reserved2		: 16;
+	} reg76;
+
+	u32 reserved2;
+} __packed;
+
+struct rkvdec_regs {
+	struct rkvdec_common_regs common;
+	union {
+		struct rkvdec_h26x_regs h26x;
+		struct rkvdec_vp9_regs  vp9;
+	};
+} __packed;
+
 #endif /* RKVDEC_REGS_H_ */
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
index b4bf01e839eff..ba51a7c2fe555 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
@@ -163,6 +163,7 @@ struct rkvdec_vp9_ctx {
 	struct v4l2_vp9_frame_context frame_context[4];
 	struct rkvdec_vp9_frame_info cur;
 	struct rkvdec_vp9_frame_info last;
+	struct rkvdec_regs regs;
 };
 
 static void write_coeff_plane(const u8 coef[6][6][3], u8 *coeff_plane)
@@ -347,38 +348,6 @@ static void init_probs(struct rkvdec_ctx *ctx,
 		init_inter_probs(ctx, run);
 }
 
-struct rkvdec_vp9_ref_reg {
-	u32 reg_frm_size;
-	u32 reg_hor_stride;
-	u32 reg_y_stride;
-	u32 reg_yuv_stride;
-	u32 reg_ref_base;
-};
-
-static struct rkvdec_vp9_ref_reg ref_regs[] = {
-	{
-		.reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(0),
-		.reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(0),
-		.reg_y_stride = RKVDEC_VP9_LAST_FRAME_YSTRIDE,
-		.reg_yuv_stride = RKVDEC_VP9_LAST_FRAME_YUVSTRIDE,
-		.reg_ref_base = RKVDEC_REG_VP9_LAST_FRAME_BASE,
-	},
-	{
-		.reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(1),
-		.reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(1),
-		.reg_y_stride = RKVDEC_VP9_GOLDEN_FRAME_YSTRIDE,
-		.reg_yuv_stride = 0,
-		.reg_ref_base = RKVDEC_REG_VP9_GOLDEN_FRAME_BASE,
-	},
-	{
-		.reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(2),
-		.reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(2),
-		.reg_y_stride = RKVDEC_VP9_ALTREF_FRAME_YSTRIDE,
-		.reg_yuv_stride = 0,
-		.reg_ref_base = RKVDEC_REG_VP9_ALTREF_FRAME_BASE,
-	}
-};
-
 static struct rkvdec_decoded_buffer *
 get_ref_buf(struct rkvdec_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp)
 {
@@ -412,18 +381,17 @@ static dma_addr_t get_mv_base_addr(struct rkvdec_decoded_buffer *buf)
 static void config_ref_registers(struct rkvdec_ctx *ctx,
 				 const struct rkvdec_vp9_run *run,
 				 struct rkvdec_decoded_buffer *ref_buf,
-				 struct rkvdec_vp9_ref_reg *ref_reg)
+				 int i)
 {
 	unsigned int aligned_pitch, aligned_height, y_len, yuv_len;
-	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
+	struct rkvdec_regs *regs = &vp9_ctx->regs;
 
 	aligned_height = round_up(ref_buf->vp9.height, 64);
-	writel_relaxed(RKVDEC_VP9_FRAMEWIDTH(ref_buf->vp9.width) |
-		       RKVDEC_VP9_FRAMEHEIGHT(ref_buf->vp9.height),
-		       rkvdec->regs + ref_reg->reg_frm_size);
+	regs->vp9.reg17_19[i].frameheight = ref_buf->vp9.height;
+	regs->vp9.reg17_19[i].framewidth = ref_buf->vp9.width;
 
-	writel_relaxed(vb2_dma_contig_plane_dma_addr(&ref_buf->base.vb.vb2_buf, 0),
-		       rkvdec->regs + ref_reg->reg_ref_base);
+	regs->vp9.refer_bases[i] = vb2_dma_contig_plane_dma_addr(&ref_buf->base.vb.vb2_buf, 0);
 
 	if (&ref_buf->base.vb == run->base.bufs.dst)
 		return;
@@ -432,59 +400,50 @@ static void config_ref_registers(struct rkvdec_ctx *ctx,
 	y_len = aligned_height * aligned_pitch;
 	yuv_len = (y_len * 3) / 2;
 
-	writel_relaxed(RKVDEC_HOR_Y_VIRSTRIDE(aligned_pitch / 16) |
-		       RKVDEC_HOR_UV_VIRSTRIDE(aligned_pitch / 16),
-		       rkvdec->regs + ref_reg->reg_hor_stride);
-	writel_relaxed(RKVDEC_VP9_REF_YSTRIDE(y_len / 16),
-		       rkvdec->regs + ref_reg->reg_y_stride);
-
-	if (!ref_reg->reg_yuv_stride)
-		return;
+	regs->vp9.reg37_39[i].y_hor_virstride = aligned_pitch / 16;
+	regs->vp9.reg37_39[i].uv_hor_virstride = aligned_pitch / 16;
+	regs->vp9.reg48_50[i].virstride = y_len / 16;
 
-	writel_relaxed(RKVDEC_VP9_REF_YUVSTRIDE(yuv_len / 16),
-		       rkvdec->regs + ref_reg->reg_yuv_stride);
+	if (!i)
+		regs->vp9.reg51.lastref_yuv_virstride = yuv_len / 16;
 }
 
 static void config_seg_registers(struct rkvdec_ctx *ctx, unsigned int segid)
 {
 	struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
+	struct rkvdec_regs *regs = &vp9_ctx->regs;
 	const struct v4l2_vp9_segmentation *seg;
-	struct rkvdec_dev *rkvdec = ctx->dev;
 	s16 feature_val;
 	int feature_id;
-	u32 val = 0;
 
 	seg = vp9_ctx->last.valid ? &vp9_ctx->last.seg : &vp9_ctx->cur.seg;
 	feature_id = V4L2_VP9_SEG_LVL_ALT_Q;
 	if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid)) {
 		feature_val = seg->feature_data[segid][feature_id];
-		val |= RKVDEC_SEGID_FRAME_QP_DELTA_EN(1) |
-		       RKVDEC_SEGID_FRAME_QP_DELTA(feature_val);
+		regs->vp9.reg20_27[segid].segid_frame_qp_delta_en = 1;
+		regs->vp9.reg20_27[segid].segid_frame_qp_delta = feature_val;
 	}
 
 	feature_id = V4L2_VP9_SEG_LVL_ALT_L;
 	if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid)) {
 		feature_val = seg->feature_data[segid][feature_id];
-		val |= RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE_EN(1) |
-		       RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE(feature_val);
+		regs->vp9.reg20_27[segid].segid_frame_loopfilter_value_en = 1;
+		regs->vp9.reg20_27[segid].segid_frame_loopfilter_value = feature_val;
 	}
 
 	feature_id = V4L2_VP9_SEG_LVL_REF_FRAME;
 	if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid)) {
 		feature_val = seg->feature_data[segid][feature_id];
-		val |= RKVDEC_SEGID_REFERINFO_EN(1) |
-		       RKVDEC_SEGID_REFERINFO(feature_val);
+		regs->vp9.reg20_27[segid].segid_referinfo_en = 1;
+		regs->vp9.reg20_27[segid].segid_referinfo = feature_val;
 	}
 
 	feature_id = V4L2_VP9_SEG_LVL_SKIP;
-	if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid))
-		val |= RKVDEC_SEGID_FRAME_SKIP_EN(1);
-
-	if (!segid &&
-	    (seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE))
-		val |= RKVDEC_SEGID_ABS_DELTA(1);
+	regs->vp9.reg20_27[segid].segid_frame_skip_en =
+		v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid);
 
-	writel_relaxed(val, rkvdec->regs + RKVDEC_VP9_SEGID_GRP(segid));
+	regs->vp9.reg20_27[segid].segid_abs_delta = !segid &&
+		(seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE);
 }
 
 static void update_dec_buf_info(struct rkvdec_decoded_buffer *buf,
@@ -521,7 +480,7 @@ static void config_registers(struct rkvdec_ctx *ctx,
 	struct rkvdec_decoded_buffer *ref_bufs[3];
 	struct rkvdec_decoded_buffer *dst, *last, *mv_ref;
 	struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
-	u32 val, last_frame_info = 0;
+	struct rkvdec_regs *regs = &vp9_ctx->regs;
 	const struct v4l2_vp9_segmentation *seg;
 	struct rkvdec_dev *rkvdec = ctx->dev;
 	dma_addr_t addr;
@@ -547,8 +506,7 @@ static void config_registers(struct rkvdec_ctx *ctx,
 			(V4L2_VP9_FRAME_FLAG_KEY_FRAME |
 			 V4L2_VP9_FRAME_FLAG_INTRA_ONLY));
 
-	writel_relaxed(RKVDEC_MODE(RKVDEC_MODE_VP9),
-		       rkvdec->regs + RKVDEC_REG_SYSCTRL);
+	regs->common.reg02.dec_mode = RKVDEC_MODE_VP9;
 
 	bit_depth = dec_params->bit_depth;
 	aligned_height = round_up(ctx->decoded_fmt.fmt.pix_mp.height, 64);
@@ -560,17 +518,14 @@ static void config_registers(struct rkvdec_ctx *ctx,
 	uv_len = y_len / 2;
 	yuv_len = y_len + uv_len;
 
-	writel_relaxed(RKVDEC_Y_HOR_VIRSTRIDE(aligned_pitch / 16) |
-		       RKVDEC_UV_HOR_VIRSTRIDE(aligned_pitch / 16),
-		       rkvdec->regs + RKVDEC_REG_PICPAR);
-	writel_relaxed(RKVDEC_Y_VIRSTRIDE(y_len / 16),
-		       rkvdec->regs + RKVDEC_REG_Y_VIRSTRIDE);
-	writel_relaxed(RKVDEC_YUV_VIRSTRIDE(yuv_len / 16),
-		       rkvdec->regs + RKVDEC_REG_YUV_VIRSTRIDE);
+	regs->common.reg03.y_hor_virstride = aligned_pitch / 16;
+	regs->common.reg03.uv_hor_virstride = aligned_pitch / 16;
+	regs->common.reg08.y_virstride = y_len / 16;
+	regs->common.reg09.yuv_virstride = yuv_len / 16;
 
 	stream_len = vb2_get_plane_payload(&run->base.bufs.src->vb2_buf, 0);
-	writel_relaxed(RKVDEC_STRM_LEN(stream_len),
-		       rkvdec->regs + RKVDEC_REG_STRM_LEN);
+
+	regs->common.stream_len = stream_len;
 
 	/*
 	 * Reset count buffer, because decoder only output intra related syntax
@@ -588,14 +543,13 @@ static void config_registers(struct rkvdec_ctx *ctx,
 		vp9_ctx->cur.segmapid++;
 
 	for (i = 0; i < ARRAY_SIZE(ref_bufs); i++)
-		config_ref_registers(ctx, run, ref_bufs[i], &ref_regs[i]);
+		config_ref_registers(ctx, run, ref_bufs[i], i);
 
 	for (i = 0; i < 8; i++)
 		config_seg_registers(ctx, i);
 
-	writel_relaxed(RKVDEC_VP9_TX_MODE(vp9_ctx->cur.tx_mode) |
-		       RKVDEC_VP9_FRAME_REF_MODE(dec_params->reference_mode),
-		       rkvdec->regs + RKVDEC_VP9_CPRHEADER_CONFIG);
+	regs->vp9.reg28.tx_mode = vp9_ctx->cur.tx_mode;
+	regs->vp9.reg28.frame_reference_mode = dec_params->reference_mode;
 
 	if (!intra_only) {
 		const struct v4l2_vp9_loop_filter *lf;
@@ -606,46 +560,58 @@ static void config_registers(struct rkvdec_ctx *ctx,
 		else
 			lf = &vp9_ctx->cur.lf;
 
-		val = 0;
 		for (i = 0; i < ARRAY_SIZE(lf->ref_deltas); i++) {
 			delta = lf->ref_deltas[i];
-			val |= RKVDEC_REF_DELTAS_LASTFRAME(i, delta);
+			switch (i) {
+			case 0:
+				regs->vp9.reg32.ref_deltas_lastframe0 = delta;
+				break;
+			case 1:
+				regs->vp9.reg32.ref_deltas_lastframe1 = delta;
+				break;
+			case 2:
+				regs->vp9.reg32.ref_deltas_lastframe2 = delta;
+				break;
+			case 3:
+				regs->vp9.reg32.ref_deltas_lastframe3 = delta;
+				break;
+			}
 		}
 
-		writel_relaxed(val,
-			       rkvdec->regs + RKVDEC_VP9_REF_DELTAS_LASTFRAME);
-
 		for (i = 0; i < ARRAY_SIZE(lf->mode_deltas); i++) {
 			delta = lf->mode_deltas[i];
-			last_frame_info |= RKVDEC_MODE_DELTAS_LASTFRAME(i,
-									delta);
+			switch (i) {
+			case 0:
+				regs->vp9.reg33.mode_deltas_lastframe0 = delta;
+				break;
+			case 1:
+				regs->vp9.reg33.mode_deltas_lastframe1 = delta;
+				break;
+			}
 		}
 	}
 
-	if (vp9_ctx->last.valid && !intra_only &&
-	    vp9_ctx->last.seg.flags & V4L2_VP9_SEGMENTATION_FLAG_ENABLED)
-		last_frame_info |= RKVDEC_SEG_EN_LASTFRAME;
+	regs->vp9.reg33.segmentation_enable_lstframe =
+		vp9_ctx->last.valid && !intra_only &&
+		vp9_ctx->last.seg.flags & V4L2_VP9_SEGMENTATION_FLAG_ENABLED;
 
-	if (vp9_ctx->last.valid &&
-	    vp9_ctx->last.flags & V4L2_VP9_FRAME_FLAG_SHOW_FRAME)
-		last_frame_info |= RKVDEC_LAST_SHOW_FRAME;
+	regs->vp9.reg33.last_show_frame =
+		vp9_ctx->last.valid &&
+		vp9_ctx->last.flags & V4L2_VP9_FRAME_FLAG_SHOW_FRAME;
 
-	if (vp9_ctx->last.valid &&
-	    vp9_ctx->last.flags &
-	    (V4L2_VP9_FRAME_FLAG_KEY_FRAME | V4L2_VP9_FRAME_FLAG_INTRA_ONLY))
-		last_frame_info |= RKVDEC_LAST_INTRA_ONLY;
+	regs->vp9.reg33.last_intra_only =
+		vp9_ctx->last.valid &&
+		vp9_ctx->last.flags &
+		(V4L2_VP9_FRAME_FLAG_KEY_FRAME | V4L2_VP9_FRAME_FLAG_INTRA_ONLY);
 
-	if (vp9_ctx->last.valid &&
-	    last->vp9.width == dst->vp9.width &&
-	    last->vp9.height == dst->vp9.height)
-		last_frame_info |= RKVDEC_LAST_WIDHHEIGHT_EQCUR;
+	regs->vp9.reg33.last_widthheight_eqcur =
+		vp9_ctx->last.valid &&
+		last->vp9.width == dst->vp9.width &&
+		last->vp9.height == dst->vp9.height;
 
-	writel_relaxed(last_frame_info,
-		       rkvdec->regs + RKVDEC_VP9_INFO_LASTFRAME);
-
-	writel_relaxed(stream_len - dec_params->compressed_header_size -
-		       dec_params->uncompressed_header_size,
-		       rkvdec->regs + RKVDEC_VP9_LASTTILE_SIZE);
+	regs->vp9.reg36.lasttile_size =
+		stream_len - dec_params->compressed_header_size -
+		dec_params->uncompressed_header_size;
 
 	for (i = 0; !intra_only && i < ARRAY_SIZE(ref_bufs); i++) {
 		unsigned int refw = ref_bufs[i]->vp9.width;
@@ -654,29 +620,28 @@ static void config_registers(struct rkvdec_ctx *ctx,
 
 		hscale = (refw << 14) /	dst->vp9.width;
 		vscale = (refh << 14) / dst->vp9.height;
-		writel_relaxed(RKVDEC_VP9_REF_HOR_SCALE(hscale) |
-			       RKVDEC_VP9_REF_VER_SCALE(vscale),
-			       rkvdec->regs + RKVDEC_VP9_REF_SCALE(i));
+
+		regs->vp9.reg29_31[i].ref_hor_scale = hscale;
+		regs->vp9.reg29_31[i].ref_ver_scale = vscale;
 	}
 
 	addr = vb2_dma_contig_plane_dma_addr(&dst->base.vb.vb2_buf, 0);
-	writel_relaxed(addr, rkvdec->regs + RKVDEC_REG_DECOUT_BASE);
+	regs->common.decout_base = addr;
 	addr = vb2_dma_contig_plane_dma_addr(&run->base.bufs.src->vb2_buf, 0);
-	writel_relaxed(addr, rkvdec->regs + RKVDEC_REG_STRM_RLC_BASE);
-	writel_relaxed(vp9_ctx->priv_tbl.dma +
-		       offsetof(struct rkvdec_vp9_priv_tbl, probs),
-		       rkvdec->regs + RKVDEC_REG_CABACTBL_PROB_BASE);
-	writel_relaxed(vp9_ctx->count_tbl.dma,
-		       rkvdec->regs + RKVDEC_REG_VP9COUNT_BASE);
-
-	writel_relaxed(vp9_ctx->priv_tbl.dma +
-		       offsetof(struct rkvdec_vp9_priv_tbl, segmap) +
-		       (RKVDEC_VP9_MAX_SEGMAP_SIZE * vp9_ctx->cur.segmapid),
-		       rkvdec->regs + RKVDEC_REG_VP9_SEGIDCUR_BASE);
-	writel_relaxed(vp9_ctx->priv_tbl.dma +
-		       offsetof(struct rkvdec_vp9_priv_tbl, segmap) +
-		       (RKVDEC_VP9_MAX_SEGMAP_SIZE * (!vp9_ctx->cur.segmapid)),
-		       rkvdec->regs + RKVDEC_REG_VP9_SEGIDLAST_BASE);
+	regs->common.strm_rlc_base = addr;
+
+	regs->common.cabactbl_base = vp9_ctx->priv_tbl.dma +
+		offsetof(struct rkvdec_vp9_priv_tbl, probs);
+
+	regs->vp9.count_base = vp9_ctx->count_tbl.dma;
+
+	regs->vp9.segidlast_base = vp9_ctx->priv_tbl.dma +
+		offsetof(struct rkvdec_vp9_priv_tbl, segmap) +
+		(RKVDEC_VP9_MAX_SEGMAP_SIZE * (!vp9_ctx->cur.segmapid));
+
+	regs->vp9.segidcur_base = vp9_ctx->priv_tbl.dma +
+		offsetof(struct rkvdec_vp9_priv_tbl, segmap) +
+		(RKVDEC_VP9_MAX_SEGMAP_SIZE * vp9_ctx->cur.segmapid);
 
 	if (!intra_only &&
 	    !(dec_params->flags & V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT) &&
@@ -685,12 +650,15 @@ static void config_registers(struct rkvdec_ctx *ctx,
 	else
 		mv_ref = dst;
 
-	writel_relaxed(get_mv_base_addr(mv_ref),
-		       rkvdec->regs + RKVDEC_VP9_REF_COLMV_BASE);
+	regs->vp9.refcolmv_base = get_mv_base_addr(mv_ref);
 
-	writel_relaxed(ctx->decoded_fmt.fmt.pix_mp.width |
-		       (ctx->decoded_fmt.fmt.pix_mp.height << 16),
-		       rkvdec->regs + RKVDEC_REG_PERFORMANCE_CYCLE);
+	regs->vp9.performance_cycle = ctx->decoded_fmt.fmt.pix_mp.width |
+		       (ctx->decoded_fmt.fmt.pix_mp.height << 16);
+
+	regs->vp9.reg44.strmd_error_e = 0xe;
+
+	rkvdec_memcpy_toio(rkvdec->regs, regs,
+			   MIN(sizeof(*regs), sizeof(u32) * rkvdec->variant->num_regs));
 }
 
 static int validate_dec_params(struct rkvdec_ctx *ctx,
@@ -823,8 +791,6 @@ static int rkvdec_vp9_run(struct rkvdec_ctx *ctx)
 	writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND);
 	writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);
 
-	writel(0xe, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN);
-
 	if (rkvdec->variant->quirks & RKVDEC_QUIRK_DISABLE_QOS)
 		rkvdec_quirks_disable_qos(ctx);
 
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index 5af9aa5ab353b..776149f871b09 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -914,6 +914,15 @@ void rkvdec_quirks_disable_qos(struct rkvdec_ctx *ctx)
 	writel(reg, rkvdec->regs + RKVDEC_REG_QOS_CTRL);
 }
 
+void rkvdec_memcpy_toio(void __iomem *dst, void *src, size_t len)
+{
+#ifdef CONFIG_ARM64
+	__iowrite32_copy(dst, src, len / 4);
+#else
+	memcpy_toio(dst, src, len);
+#endif
+}
+
 static void rkvdec_device_run(void *priv)
 {
 	struct rkvdec_ctx *ctx = priv;
@@ -1227,7 +1236,6 @@ static void rkvdec_watchdog_func(struct work_struct *work)
 	if (ctx) {
 		dev_err(rkvdec->dev, "Frame processing timed out!\n");
 		writel(RKVDEC_IRQ_DIS, rkvdec->regs + RKVDEC_REG_INTERRUPT);
-		writel(0, rkvdec->regs + RKVDEC_REG_SYSCTRL);
 		rkvdec_job_finish(ctx, VB2_BUF_STATE_ERROR);
 	}
 }
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
index 566e06fa2b1ed..f35f6e80ea2e3 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
@@ -151,6 +151,7 @@ struct rkvdec_aux_buf {
 
 void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run);
 void rkvdec_run_postamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run);
+void rkvdec_memcpy_toio(void __iomem *dst, void *src, size_t len);
 
 void rkvdec_quirks_disable_qos(struct rkvdec_ctx *ctx);
 
-- 
2.52.0



From detlev.casanova at collabora.com  Thu Dec 18 15:28:15 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Thu, 18 Dec 2025 18:28:15 -0500
Subject: [PATCH v7 05/17] media: rkvdec: Move cabac tables to their own source file
In-Reply-To: <20251218232829.337811-1-detlev.casanova@collabora.com>
References: <20251218232829.337811-1-detlev.casanova@collabora.com>
Message-ID: <20251218232829.337811-6-detlev.casanova@collabora.com>

This is in preparation to add support for new variants that will use the
same tables.

Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../media/platform/rockchip/rkvdec/Makefile   |   7 +-
 .../{rkvdec-hevc-data.c => rkvdec-cabac.c}    | 506 +++++++++++++++++-
 .../platform/rockchip/rkvdec/rkvdec-h264.c    | 501 +----------------
 .../platform/rockchip/rkvdec/rkvdec-hevc.c    |   6 +-
 4 files changed, 514 insertions(+), 506 deletions(-)
 rename drivers/media/platform/rockchip/rkvdec/{rkvdec-hevc-data.c => rkvdec-cabac.c} (86%)

diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
index a77122641d141..a8ff5e3d7bec3 100644
--- a/drivers/media/platform/rockchip/rkvdec/Makefile
+++ b/drivers/media/platform/rockchip/rkvdec/Makefile
@@ -1,3 +1,8 @@
 obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC) += rockchip-vdec.o
 
-rockchip-vdec-y += rkvdec.o rkvdec-h264.o rkvdec-hevc.o rkvdec-vp9.o
+rockchip-vdec-y += \
+		   rkvdec.o \
+		   rkvdec-cabac.o \
+		   rkvdec-h264.o \
+		   rkvdec-hevc.o \
+		   rkvdec-vp9.o
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-data.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-cabac.c
similarity index 86%
rename from drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-data.c
rename to drivers/media/platform/rockchip/rkvdec/rkvdec-cabac.c
index eac4ea604949f..bc87f59636ea1 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-data.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-cabac.c
@@ -1,19 +1,517 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Rockchip Video Decoder driver
+ * Rockchip Video Decoder CABAC tables
  *
  * Copyright (C) 2023 Collabora, Ltd.
  *	Sebastian Fricke <sebastian.fricke at collabora.com>
+ * Copyright (C) 2019 Collabora, Ltd.
+ *	Boris Brezillon <boris.brezillon at collabora.com>
  */
 
 #include <linux/types.h>
 
-#define RKV_CABAC_TABLE_SIZE		27456
+#define CABAC_ENTRY(ctxidx, idc0_m, idc0_n, idc1_m, idc1_n,		\
+	    idc2_m, idc2_n, intra_m, intra_n)			\
+	[0][(ctxidx)] = {idc0_m, idc0_n},			\
+	[1][(ctxidx)] = {idc1_m, idc1_n},			\
+	[2][(ctxidx)] = {idc2_m, idc2_n},			\
+	[3][(ctxidx)] = {intra_m, intra_n}
 
 /*
- * This file is #include from rkvdec-hevc.c and not compiled.
+ * Constant CABAC table.
+ * Built from the tables described in section '9.3.1.1 Initialisation process
+ * for context variables' of the H264 spec.
  */
-static const u8 rkvdec_hevc_cabac_table[RKV_CABAC_TABLE_SIZE] = {
+const s8 rkvdec_h264_cabac_table[4][464][2] = {
+	/* Table 9-12 ? Values of variables m and n for ctxIdx from 0 to 10 */
+	CABAC_ENTRY(0, 20, -15, 20, -15, 20, -15, 20, -15),
+	CABAC_ENTRY(1, 2, 54, 2, 54, 2, 54, 2, 54),
+	CABAC_ENTRY(2, 3, 74, 3, 74, 3, 74, 3, 74),
+	CABAC_ENTRY(3, 20, -15, 20, -15, 20, -15, 20, -15),
+	CABAC_ENTRY(4, 2, 54, 2, 54, 2, 54, 2, 54),
+	CABAC_ENTRY(5, 3, 74, 3, 74, 3, 74, 3, 74),
+	CABAC_ENTRY(6, -28, 127, -28, 127, -28, 127, -28, 127),
+	CABAC_ENTRY(7, -23, 104, -23, 104, -23, 104, -23, 104),
+	CABAC_ENTRY(8, -6, 53, -6, 53, -6, 53, -6, 53),
+	CABAC_ENTRY(9, -1, 54, -1, 54, -1, 54, -1, 54),
+	CABAC_ENTRY(10, 7, 51, 7, 51, 7, 51, 7, 51),
+
+	/* Table 9-13 ? Values of variables m and n for ctxIdx from 11 to 23 */
+	CABAC_ENTRY(11, 23, 33, 22, 25, 29, 16, 0, 0),
+	CABAC_ENTRY(12, 23, 2, 34, 0, 25, 0, 0, 0),
+	CABAC_ENTRY(13, 21, 0, 16, 0, 14, 0, 0, 0),
+	CABAC_ENTRY(14, 1, 9, -2, 9, -10, 51, 0, 0),
+	CABAC_ENTRY(15, 0, 49, 4, 41, -3, 62, 0, 0),
+	CABAC_ENTRY(16, -37, 118, -29, 118, -27, 99, 0, 0),
+	CABAC_ENTRY(17, 5, 57, 2, 65, 26, 16, 0, 0),
+	CABAC_ENTRY(18, -13, 78, -6, 71, -4, 85, 0, 0),
+	CABAC_ENTRY(19, -11, 65, -13, 79, -24, 102, 0, 0),
+	CABAC_ENTRY(20, 1, 62, 5, 52, 5, 57, 0, 0),
+	CABAC_ENTRY(21, 12, 49, 9, 50, 6, 57, 0, 0),
+	CABAC_ENTRY(22, -4, 73, -3, 70, -17, 73, 0, 0),
+	CABAC_ENTRY(23, 17, 50, 10, 54, 14, 57, 0, 0),
+
+	/* Table 9-14 ? Values of variables m and n for ctxIdx from 24 to 39 */
+	CABAC_ENTRY(24, 18, 64, 26, 34, 20, 40, 0, 0),
+	CABAC_ENTRY(25, 9, 43, 19, 22, 20, 10, 0, 0),
+	CABAC_ENTRY(26, 29, 0, 40, 0, 29, 0, 0, 0),
+	CABAC_ENTRY(27, 26, 67, 57, 2, 54, 0, 0, 0),
+	CABAC_ENTRY(28, 16, 90, 41, 36, 37, 42, 0, 0),
+	CABAC_ENTRY(29, 9, 104, 26, 69, 12, 97, 0, 0),
+	CABAC_ENTRY(30, -46, 127, -45, 127, -32, 127, 0, 0),
+	CABAC_ENTRY(31, -20, 104, -15, 101, -22, 117, 0, 0),
+	CABAC_ENTRY(32, 1, 67, -4, 76, -2, 74, 0, 0),
+	CABAC_ENTRY(33, -13, 78, -6, 71, -4, 85, 0, 0),
+	CABAC_ENTRY(34, -11, 65, -13, 79, -24, 102, 0, 0),
+	CABAC_ENTRY(35, 1, 62, 5, 52, 5, 57, 0, 0),
+	CABAC_ENTRY(36, -6, 86, 6, 69, -6, 93, 0, 0),
+	CABAC_ENTRY(37, -17, 95, -13, 90, -14, 88, 0, 0),
+	CABAC_ENTRY(38, -6, 61, 0, 52, -6, 44, 0, 0),
+	CABAC_ENTRY(39, 9, 45, 8, 43, 4, 55, 0, 0),
+
+	/* Table 9-15 ? Values of variables m and n for ctxIdx from 40 to 53 */
+	CABAC_ENTRY(40, -3, 69, -2, 69, -11, 89, 0, 0),
+	CABAC_ENTRY(41, -6, 81, -5, 82, -15, 103, 0, 0),
+	CABAC_ENTRY(42, -11, 96, -10, 96, -21, 116, 0, 0),
+	CABAC_ENTRY(43, 6, 55, 2, 59, 19, 57, 0, 0),
+	CABAC_ENTRY(44, 7, 67, 2, 75, 20, 58, 0, 0),
+	CABAC_ENTRY(45, -5, 86, -3, 87, 4, 84, 0, 0),
+	CABAC_ENTRY(46, 2, 88, -3, 100, 6, 96, 0, 0),
+	CABAC_ENTRY(47, 0, 58, 1, 56, 1, 63, 0, 0),
+	CABAC_ENTRY(48, -3, 76, -3, 74, -5, 85, 0, 0),
+	CABAC_ENTRY(49, -10, 94, -6, 85, -13, 106, 0, 0),
+	CABAC_ENTRY(50, 5, 54, 0, 59, 5, 63, 0, 0),
+	CABAC_ENTRY(51, 4, 69, -3, 81, 6, 75, 0, 0),
+	CABAC_ENTRY(52, -3, 81, -7, 86, -3, 90, 0, 0),
+	CABAC_ENTRY(53, 0, 88, -5, 95, -1, 101, 0, 0),
+
+	/* Table 9-16 ? Values of variables m and n for ctxIdx from 54 to 59 */
+	CABAC_ENTRY(54, -7, 67, -1, 66, 3, 55, 0, 0),
+	CABAC_ENTRY(55, -5, 74, -1, 77, -4, 79, 0, 0),
+	CABAC_ENTRY(56, -4, 74, 1, 70, -2, 75, 0, 0),
+	CABAC_ENTRY(57, -5, 80, -2, 86, -12, 97, 0, 0),
+	CABAC_ENTRY(58, -7, 72, -5, 72, -7, 50, 0, 0),
+	CABAC_ENTRY(59, 1, 58, 0, 61, 1, 60, 0, 0),
+
+	/* Table 9-17 ? Values of variables m and n for ctxIdx from 60 to 69 */
+	CABAC_ENTRY(60, 0, 41, 0, 41, 0, 41, 0, 41),
+	CABAC_ENTRY(61, 0, 63, 0, 63, 0, 63, 0, 63),
+	CABAC_ENTRY(62, 0, 63, 0, 63, 0, 63, 0, 63),
+	CABAC_ENTRY(63, 0, 63, 0, 63, 0, 63, 0, 63),
+	CABAC_ENTRY(64, -9, 83, -9, 83, -9, 83, -9, 83),
+	CABAC_ENTRY(65, 4, 86, 4, 86, 4, 86, 4, 86),
+	CABAC_ENTRY(66, 0, 97, 0, 97, 0, 97, 0, 97),
+	CABAC_ENTRY(67, -7, 72, -7, 72, -7, 72, -7, 72),
+	CABAC_ENTRY(68, 13, 41, 13, 41, 13, 41, 13, 41),
+	CABAC_ENTRY(69, 3, 62, 3, 62, 3, 62, 3, 62),
+
+	/* Table 9-18 ? Values of variables m and n for ctxIdx from 70 to 104 */
+	CABAC_ENTRY(70, 0, 45, 13, 15, 7, 34, 0, 11),
+	CABAC_ENTRY(71, -4, 78, 7, 51, -9, 88, 1, 55),
+	CABAC_ENTRY(72, -3, 96, 2, 80, -20, 127, 0, 69),
+	CABAC_ENTRY(73, -27, 126, -39, 127, -36, 127, -17, 127),
+	CABAC_ENTRY(74, -28, 98, -18, 91, -17, 91, -13, 102),
+	CABAC_ENTRY(75, -25, 101, -17, 96, -14, 95, 0, 82),
+	CABAC_ENTRY(76, -23, 67, -26, 81, -25, 84, -7, 74),
+	CABAC_ENTRY(77, -28, 82, -35, 98, -25, 86, -21, 107),
+	CABAC_ENTRY(78, -20, 94, -24, 102, -12, 89, -27, 127),
+	CABAC_ENTRY(79, -16, 83, -23, 97, -17, 91, -31, 127),
+	CABAC_ENTRY(80, -22, 110, -27, 119, -31, 127, -24, 127),
+	CABAC_ENTRY(81, -21, 91, -24, 99, -14, 76, -18, 95),
+	CABAC_ENTRY(82, -18, 102, -21, 110, -18, 103, -27, 127),
+	CABAC_ENTRY(83, -13, 93, -18, 102, -13, 90, -21, 114),
+	CABAC_ENTRY(84, -29, 127, -36, 127, -37, 127, -30, 127),
+	CABAC_ENTRY(85, -7, 92, 0, 80, 11, 80, -17, 123),
+	CABAC_ENTRY(86, -5, 89, -5, 89, 5, 76, -12, 115),
+	CABAC_ENTRY(87, -7, 96, -7, 94, 2, 84, -16, 122),
+	CABAC_ENTRY(88, -13, 108, -4, 92, 5, 78, -11, 115),
+	CABAC_ENTRY(89, -3, 46, 0, 39, -6, 55, -12, 63),
+	CABAC_ENTRY(90, -1, 65, 0, 65, 4, 61, -2, 68),
+	CABAC_ENTRY(91, -1, 57, -15, 84, -14, 83, -15, 84),
+	CABAC_ENTRY(92, -9, 93, -35, 127, -37, 127, -13, 104),
+	CABAC_ENTRY(93, -3, 74, -2, 73, -5, 79, -3, 70),
+	CABAC_ENTRY(94, -9, 92, -12, 104, -11, 104, -8, 93),
+	CABAC_ENTRY(95, -8, 87, -9, 91, -11, 91, -10, 90),
+	CABAC_ENTRY(96, -23, 126, -31, 127, -30, 127, -30, 127),
+	CABAC_ENTRY(97, 5, 54, 3, 55, 0, 65, -1, 74),
+	CABAC_ENTRY(98, 6, 60, 7, 56, -2, 79, -6, 97),
+	CABAC_ENTRY(99, 6, 59, 7, 55, 0, 72, -7, 91),
+	CABAC_ENTRY(100, 6, 69, 8, 61, -4, 92, -20, 127),
+	CABAC_ENTRY(101, -1, 48, -3, 53, -6, 56, -4, 56),
+	CABAC_ENTRY(102, 0, 68, 0, 68, 3, 68, -5, 82),
+	CABAC_ENTRY(103, -4, 69, -7, 74, -8, 71, -7, 76),
+	CABAC_ENTRY(104, -8, 88, -9, 88, -13, 98, -22, 125),
+
+	/* Table 9-19 ? Values of variables m and n for ctxIdx from 105 to 165 */
+	CABAC_ENTRY(105, -2, 85, -13, 103, -4, 86, -7, 93),
+	CABAC_ENTRY(106, -6, 78, -13, 91, -12, 88, -11, 87),
+	CABAC_ENTRY(107, -1, 75, -9, 89, -5, 82, -3, 77),
+	CABAC_ENTRY(108, -7, 77, -14, 92, -3, 72, -5, 71),
+	CABAC_ENTRY(109, 2, 54, -8, 76, -4, 67, -4, 63),
+	CABAC_ENTRY(110, 5, 50, -12, 87, -8, 72, -4, 68),
+	CABAC_ENTRY(111, -3, 68, -23, 110, -16, 89, -12, 84),
+	CABAC_ENTRY(112, 1, 50, -24, 105, -9, 69, -7, 62),
+	CABAC_ENTRY(113, 6, 42, -10, 78, -1, 59, -7, 65),
+	CABAC_ENTRY(114, -4, 81, -20, 112, 5, 66, 8, 61),
+	CABAC_ENTRY(115, 1, 63, -17, 99, 4, 57, 5, 56),
+	CABAC_ENTRY(116, -4, 70, -78, 127, -4, 71, -2, 66),
+	CABAC_ENTRY(117, 0, 67, -70, 127, -2, 71, 1, 64),
+	CABAC_ENTRY(118, 2, 57, -50, 127, 2, 58, 0, 61),
+	CABAC_ENTRY(119, -2, 76, -46, 127, -1, 74, -2, 78),
+	CABAC_ENTRY(120, 11, 35, -4, 66, -4, 44, 1, 50),
+	CABAC_ENTRY(121, 4, 64, -5, 78, -1, 69, 7, 52),
+	CABAC_ENTRY(122, 1, 61, -4, 71, 0, 62, 10, 35),
+	CABAC_ENTRY(123, 11, 35, -8, 72, -7, 51, 0, 44),
+	CABAC_ENTRY(124, 18, 25, 2, 59, -4, 47, 11, 38),
+	CABAC_ENTRY(125, 12, 24, -1, 55, -6, 42, 1, 45),
+	CABAC_ENTRY(126, 13, 29, -7, 70, -3, 41, 0, 46),
+	CABAC_ENTRY(127, 13, 36, -6, 75, -6, 53, 5, 44),
+	CABAC_ENTRY(128, -10, 93, -8, 89, 8, 76, 31, 17),
+	CABAC_ENTRY(129, -7, 73, -34, 119, -9, 78, 1, 51),
+	CABAC_ENTRY(130, -2, 73, -3, 75, -11, 83, 7, 50),
+	CABAC_ENTRY(131, 13, 46, 32, 20, 9, 52, 28, 19),
+	CABAC_ENTRY(132, 9, 49, 30, 22, 0, 67, 16, 33),
+	CABAC_ENTRY(133, -7, 100, -44, 127, -5, 90, 14, 62),
+	CABAC_ENTRY(134, 9, 53, 0, 54, 1, 67, -13, 108),
+	CABAC_ENTRY(135, 2, 53, -5, 61, -15, 72, -15, 100),
+	CABAC_ENTRY(136, 5, 53, 0, 58, -5, 75, -13, 101),
+	CABAC_ENTRY(137, -2, 61, -1, 60, -8, 80, -13, 91),
+	CABAC_ENTRY(138, 0, 56, -3, 61, -21, 83, -12, 94),
+	CABAC_ENTRY(139, 0, 56, -8, 67, -21, 64, -10, 88),
+	CABAC_ENTRY(140, -13, 63, -25, 84, -13, 31, -16, 84),
+	CABAC_ENTRY(141, -5, 60, -14, 74, -25, 64, -10, 86),
+	CABAC_ENTRY(142, -1, 62, -5, 65, -29, 94, -7, 83),
+	CABAC_ENTRY(143, 4, 57, 5, 52, 9, 75, -13, 87),
+	CABAC_ENTRY(144, -6, 69, 2, 57, 17, 63, -19, 94),
+	CABAC_ENTRY(145, 4, 57, 0, 61, -8, 74, 1, 70),
+	CABAC_ENTRY(146, 14, 39, -9, 69, -5, 35, 0, 72),
+	CABAC_ENTRY(147, 4, 51, -11, 70, -2, 27, -5, 74),
+	CABAC_ENTRY(148, 13, 68, 18, 55, 13, 91, 18, 59),
+	CABAC_ENTRY(149, 3, 64, -4, 71, 3, 65, -8, 102),
+	CABAC_ENTRY(150, 1, 61, 0, 58, -7, 69, -15, 100),
+	CABAC_ENTRY(151, 9, 63, 7, 61, 8, 77, 0, 95),
+	CABAC_ENTRY(152, 7, 50, 9, 41, -10, 66, -4, 75),
+	CABAC_ENTRY(153, 16, 39, 18, 25, 3, 62, 2, 72),
+	CABAC_ENTRY(154, 5, 44, 9, 32, -3, 68, -11, 75),
+	CABAC_ENTRY(155, 4, 52, 5, 43, -20, 81, -3, 71),
+	CABAC_ENTRY(156, 11, 48, 9, 47, 0, 30, 15, 46),
+	CABAC_ENTRY(157, -5, 60, 0, 44, 1, 7, -13, 69),
+	CABAC_ENTRY(158, -1, 59, 0, 51, -3, 23, 0, 62),
+	CABAC_ENTRY(159, 0, 59, 2, 46, -21, 74, 0, 65),
+	CABAC_ENTRY(160, 22, 33, 19, 38, 16, 66, 21, 37),
+	CABAC_ENTRY(161, 5, 44, -4, 66, -23, 124, -15, 72),
+	CABAC_ENTRY(162, 14, 43, 15, 38, 17, 37, 9, 57),
+	CABAC_ENTRY(163, -1, 78, 12, 42, 44, -18, 16, 54),
+	CABAC_ENTRY(164, 0, 60, 9, 34, 50, -34, 0, 62),
+	CABAC_ENTRY(165, 9, 69, 0, 89, -22, 127, 12, 72),
+
+	/* Table 9-20 ? Values of variables m and n for ctxIdx from 166 to 226 */
+	CABAC_ENTRY(166, 11, 28, 4, 45, 4, 39, 24, 0),
+	CABAC_ENTRY(167, 2, 40, 10, 28, 0, 42, 15, 9),
+	CABAC_ENTRY(168, 3, 44, 10, 31, 7, 34, 8, 25),
+	CABAC_ENTRY(169, 0, 49, 33, -11, 11, 29, 13, 18),
+	CABAC_ENTRY(170, 0, 46, 52, -43, 8, 31, 15, 9),
+	CABAC_ENTRY(171, 2, 44, 18, 15, 6, 37, 13, 19),
+	CABAC_ENTRY(172, 2, 51, 28, 0, 7, 42, 10, 37),
+	CABAC_ENTRY(173, 0, 47, 35, -22, 3, 40, 12, 18),
+	CABAC_ENTRY(174, 4, 39, 38, -25, 8, 33, 6, 29),
+	CABAC_ENTRY(175, 2, 62, 34, 0, 13, 43, 20, 33),
+	CABAC_ENTRY(176, 6, 46, 39, -18, 13, 36, 15, 30),
+	CABAC_ENTRY(177, 0, 54, 32, -12, 4, 47, 4, 45),
+	CABAC_ENTRY(178, 3, 54, 102, -94, 3, 55, 1, 58),
+	CABAC_ENTRY(179, 2, 58, 0, 0, 2, 58, 0, 62),
+	CABAC_ENTRY(180, 4, 63, 56, -15, 6, 60, 7, 61),
+	CABAC_ENTRY(181, 6, 51, 33, -4, 8, 44, 12, 38),
+	CABAC_ENTRY(182, 6, 57, 29, 10, 11, 44, 11, 45),
+	CABAC_ENTRY(183, 7, 53, 37, -5, 14, 42, 15, 39),
+	CABAC_ENTRY(184, 6, 52, 51, -29, 7, 48, 11, 42),
+	CABAC_ENTRY(185, 6, 55, 39, -9, 4, 56, 13, 44),
+	CABAC_ENTRY(186, 11, 45, 52, -34, 4, 52, 16, 45),
+	CABAC_ENTRY(187, 14, 36, 69, -58, 13, 37, 12, 41),
+	CABAC_ENTRY(188, 8, 53, 67, -63, 9, 49, 10, 49),
+	CABAC_ENTRY(189, -1, 82, 44, -5, 19, 58, 30, 34),
+	CABAC_ENTRY(190, 7, 55, 32, 7, 10, 48, 18, 42),
+	CABAC_ENTRY(191, -3, 78, 55, -29, 12, 45, 10, 55),
+	CABAC_ENTRY(192, 15, 46, 32, 1, 0, 69, 17, 51),
+	CABAC_ENTRY(193, 22, 31, 0, 0, 20, 33, 17, 46),
+	CABAC_ENTRY(194, -1, 84, 27, 36, 8, 63, 0, 89),
+	CABAC_ENTRY(195, 25, 7, 33, -25, 35, -18, 26, -19),
+	CABAC_ENTRY(196, 30, -7, 34, -30, 33, -25, 22, -17),
+	CABAC_ENTRY(197, 28, 3, 36, -28, 28, -3, 26, -17),
+	CABAC_ENTRY(198, 28, 4, 38, -28, 24, 10, 30, -25),
+	CABAC_ENTRY(199, 32, 0, 38, -27, 27, 0, 28, -20),
+	CABAC_ENTRY(200, 34, -1, 34, -18, 34, -14, 33, -23),
+	CABAC_ENTRY(201, 30, 6, 35, -16, 52, -44, 37, -27),
+	CABAC_ENTRY(202, 30, 6, 34, -14, 39, -24, 33, -23),
+	CABAC_ENTRY(203, 32, 9, 32, -8, 19, 17, 40, -28),
+	CABAC_ENTRY(204, 31, 19, 37, -6, 31, 25, 38, -17),
+	CABAC_ENTRY(205, 26, 27, 35, 0, 36, 29, 33, -11),
+	CABAC_ENTRY(206, 26, 30, 30, 10, 24, 33, 40, -15),
+	CABAC_ENTRY(207, 37, 20, 28, 18, 34, 15, 41, -6),
+	CABAC_ENTRY(208, 28, 34, 26, 25, 30, 20, 38, 1),
+	CABAC_ENTRY(209, 17, 70, 29, 41, 22, 73, 41, 17),
+	CABAC_ENTRY(210, 1, 67, 0, 75, 20, 34, 30, -6),
+	CABAC_ENTRY(211, 5, 59, 2, 72, 19, 31, 27, 3),
+	CABAC_ENTRY(212, 9, 67, 8, 77, 27, 44, 26, 22),
+	CABAC_ENTRY(213, 16, 30, 14, 35, 19, 16, 37, -16),
+	CABAC_ENTRY(214, 18, 32, 18, 31, 15, 36, 35, -4),
+	CABAC_ENTRY(215, 18, 35, 17, 35, 15, 36, 38, -8),
+	CABAC_ENTRY(216, 22, 29, 21, 30, 21, 28, 38, -3),
+	CABAC_ENTRY(217, 24, 31, 17, 45, 25, 21, 37, 3),
+	CABAC_ENTRY(218, 23, 38, 20, 42, 30, 20, 38, 5),
+	CABAC_ENTRY(219, 18, 43, 18, 45, 31, 12, 42, 0),
+	CABAC_ENTRY(220, 20, 41, 27, 26, 27, 16, 35, 16),
+	CABAC_ENTRY(221, 11, 63, 16, 54, 24, 42, 39, 22),
+	CABAC_ENTRY(222, 9, 59, 7, 66, 0, 93, 14, 48),
+	CABAC_ENTRY(223, 9, 64, 16, 56, 14, 56, 27, 37),
+	CABAC_ENTRY(224, -1, 94, 11, 73, 15, 57, 21, 60),
+	CABAC_ENTRY(225, -2, 89, 10, 67, 26, 38, 12, 68),
+	CABAC_ENTRY(226, -9, 108, -10, 116, -24, 127, 2, 97),
+
+	/* Table 9-21 ? Values of variables m and n for ctxIdx from 227 to 275 */
+	CABAC_ENTRY(227, -6, 76, -23, 112, -24, 115, -3, 71),
+	CABAC_ENTRY(228, -2, 44, -15, 71, -22, 82, -6, 42),
+	CABAC_ENTRY(229, 0, 45, -7, 61, -9, 62, -5, 50),
+	CABAC_ENTRY(230, 0, 52, 0, 53, 0, 53, -3, 54),
+	CABAC_ENTRY(231, -3, 64, -5, 66, 0, 59, -2, 62),
+	CABAC_ENTRY(232, -2, 59, -11, 77, -14, 85, 0, 58),
+	CABAC_ENTRY(233, -4, 70, -9, 80, -13, 89, 1, 63),
+	CABAC_ENTRY(234, -4, 75, -9, 84, -13, 94, -2, 72),
+	CABAC_ENTRY(235, -8, 82, -10, 87, -11, 92, -1, 74),
+	CABAC_ENTRY(236, -17, 102, -34, 127, -29, 127, -9, 91),
+	CABAC_ENTRY(237, -9, 77, -21, 101, -21, 100, -5, 67),
+	CABAC_ENTRY(238, 3, 24, -3, 39, -14, 57, -5, 27),
+	CABAC_ENTRY(239, 0, 42, -5, 53, -12, 67, -3, 39),
+	CABAC_ENTRY(240, 0, 48, -7, 61, -11, 71, -2, 44),
+	CABAC_ENTRY(241, 0, 55, -11, 75, -10, 77, 0, 46),
+	CABAC_ENTRY(242, -6, 59, -15, 77, -21, 85, -16, 64),
+	CABAC_ENTRY(243, -7, 71, -17, 91, -16, 88, -8, 68),
+	CABAC_ENTRY(244, -12, 83, -25, 107, -23, 104, -10, 78),
+	CABAC_ENTRY(245, -11, 87, -25, 111, -15, 98, -6, 77),
+	CABAC_ENTRY(246, -30, 119, -28, 122, -37, 127, -10, 86),
+	CABAC_ENTRY(247, 1, 58, -11, 76, -10, 82, -12, 92),
+	CABAC_ENTRY(248, -3, 29, -10, 44, -8, 48, -15, 55),
+	CABAC_ENTRY(249, -1, 36, -10, 52, -8, 61, -10, 60),
+	CABAC_ENTRY(250, 1, 38, -10, 57, -8, 66, -6, 62),
+	CABAC_ENTRY(251, 2, 43, -9, 58, -7, 70, -4, 65),
+	CABAC_ENTRY(252, -6, 55, -16, 72, -14, 75, -12, 73),
+	CABAC_ENTRY(253, 0, 58, -7, 69, -10, 79, -8, 76),
+	CABAC_ENTRY(254, 0, 64, -4, 69, -9, 83, -7, 80),
+	CABAC_ENTRY(255, -3, 74, -5, 74, -12, 92, -9, 88),
+	CABAC_ENTRY(256, -10, 90, -9, 86, -18, 108, -17, 110),
+	CABAC_ENTRY(257, 0, 70, 2, 66, -4, 79, -11, 97),
+	CABAC_ENTRY(258, -4, 29, -9, 34, -22, 69, -20, 84),
+	CABAC_ENTRY(259, 5, 31, 1, 32, -16, 75, -11, 79),
+	CABAC_ENTRY(260, 7, 42, 11, 31, -2, 58, -6, 73),
+	CABAC_ENTRY(261, 1, 59, 5, 52, 1, 58, -4, 74),
+	CABAC_ENTRY(262, -2, 58, -2, 55, -13, 78, -13, 86),
+	CABAC_ENTRY(263, -3, 72, -2, 67, -9, 83, -13, 96),
+	CABAC_ENTRY(264, -3, 81, 0, 73, -4, 81, -11, 97),
+	CABAC_ENTRY(265, -11, 97, -8, 89, -13, 99, -19, 117),
+	CABAC_ENTRY(266, 0, 58, 3, 52, -13, 81, -8, 78),
+	CABAC_ENTRY(267, 8, 5, 7, 4, -6, 38, -5, 33),
+	CABAC_ENTRY(268, 10, 14, 10, 8, -13, 62, -4, 48),
+	CABAC_ENTRY(269, 14, 18, 17, 8, -6, 58, -2, 53),
+	CABAC_ENTRY(270, 13, 27, 16, 19, -2, 59, -3, 62),
+	CABAC_ENTRY(271, 2, 40, 3, 37, -16, 73, -13, 71),
+	CABAC_ENTRY(272, 0, 58, -1, 61, -10, 76, -10, 79),
+	CABAC_ENTRY(273, -3, 70, -5, 73, -13, 86, -12, 86),
+	CABAC_ENTRY(274, -6, 79, -1, 70, -9, 83, -13, 90),
+	CABAC_ENTRY(275, -8, 85, -4, 78, -10, 87, -14, 97),
+
+	/* Table 9-22 ? Values of variables m and n for ctxIdx from 277 to 337 */
+	CABAC_ENTRY(277, -13, 106, -21, 126, -22, 127, -6, 93),
+	CABAC_ENTRY(278, -16, 106, -23, 124, -25, 127, -6, 84),
+	CABAC_ENTRY(279, -10, 87, -20, 110, -25, 120, -8, 79),
+	CABAC_ENTRY(280, -21, 114, -26, 126, -27, 127, 0, 66),
+	CABAC_ENTRY(281, -18, 110, -25, 124, -19, 114, -1, 71),
+	CABAC_ENTRY(282, -14, 98, -17, 105, -23, 117, 0, 62),
+	CABAC_ENTRY(283, -22, 110, -27, 121, -25, 118, -2, 60),
+	CABAC_ENTRY(284, -21, 106, -27, 117, -26, 117, -2, 59),
+	CABAC_ENTRY(285, -18, 103, -17, 102, -24, 113, -5, 75),
+	CABAC_ENTRY(286, -21, 107, -26, 117, -28, 118, -3, 62),
+	CABAC_ENTRY(287, -23, 108, -27, 116, -31, 120, -4, 58),
+	CABAC_ENTRY(288, -26, 112, -33, 122, -37, 124, -9, 66),
+	CABAC_ENTRY(289, -10, 96, -10, 95, -10, 94, -1, 79),
+	CABAC_ENTRY(290, -12, 95, -14, 100, -15, 102, 0, 71),
+	CABAC_ENTRY(291, -5, 91, -8, 95, -10, 99, 3, 68),
+	CABAC_ENTRY(292, -9, 93, -17, 111, -13, 106, 10, 44),
+	CABAC_ENTRY(293, -22, 94, -28, 114, -50, 127, -7, 62),
+	CABAC_ENTRY(294, -5, 86, -6, 89, -5, 92, 15, 36),
+	CABAC_ENTRY(295, 9, 67, -2, 80, 17, 57, 14, 40),
+	CABAC_ENTRY(296, -4, 80, -4, 82, -5, 86, 16, 27),
+	CABAC_ENTRY(297, -10, 85, -9, 85, -13, 94, 12, 29),
+	CABAC_ENTRY(298, -1, 70, -8, 81, -12, 91, 1, 44),
+	CABAC_ENTRY(299, 7, 60, -1, 72, -2, 77, 20, 36),
+	CABAC_ENTRY(300, 9, 58, 5, 64, 0, 71, 18, 32),
+	CABAC_ENTRY(301, 5, 61, 1, 67, -1, 73, 5, 42),
+	CABAC_ENTRY(302, 12, 50, 9, 56, 4, 64, 1, 48),
+	CABAC_ENTRY(303, 15, 50, 0, 69, -7, 81, 10, 62),
+	CABAC_ENTRY(304, 18, 49, 1, 69, 5, 64, 17, 46),
+	CABAC_ENTRY(305, 17, 54, 7, 69, 15, 57, 9, 64),
+	CABAC_ENTRY(306, 10, 41, -7, 69, 1, 67, -12, 104),
+	CABAC_ENTRY(307, 7, 46, -6, 67, 0, 68, -11, 97),
+	CABAC_ENTRY(308, -1, 51, -16, 77, -10, 67, -16, 96),
+	CABAC_ENTRY(309, 7, 49, -2, 64, 1, 68, -7, 88),
+	CABAC_ENTRY(310, 8, 52, 2, 61, 0, 77, -8, 85),
+	CABAC_ENTRY(311, 9, 41, -6, 67, 2, 64, -7, 85),
+	CABAC_ENTRY(312, 6, 47, -3, 64, 0, 68, -9, 85),
+	CABAC_ENTRY(313, 2, 55, 2, 57, -5, 78, -13, 88),
+	CABAC_ENTRY(314, 13, 41, -3, 65, 7, 55, 4, 66),
+	CABAC_ENTRY(315, 10, 44, -3, 66, 5, 59, -3, 77),
+	CABAC_ENTRY(316, 6, 50, 0, 62, 2, 65, -3, 76),
+	CABAC_ENTRY(317, 5, 53, 9, 51, 14, 54, -6, 76),
+	CABAC_ENTRY(318, 13, 49, -1, 66, 15, 44, 10, 58),
+	CABAC_ENTRY(319, 4, 63, -2, 71, 5, 60, -1, 76),
+	CABAC_ENTRY(320, 6, 64, -2, 75, 2, 70, -1, 83),
+	CABAC_ENTRY(321, -2, 69, -1, 70, -2, 76, -7, 99),
+	CABAC_ENTRY(322, -2, 59, -9, 72, -18, 86, -14, 95),
+	CABAC_ENTRY(323, 6, 70, 14, 60, 12, 70, 2, 95),
+	CABAC_ENTRY(324, 10, 44, 16, 37, 5, 64, 0, 76),
+	CABAC_ENTRY(325, 9, 31, 0, 47, -12, 70, -5, 74),
+	CABAC_ENTRY(326, 12, 43, 18, 35, 11, 55, 0, 70),
+	CABAC_ENTRY(327, 3, 53, 11, 37, 5, 56, -11, 75),
+	CABAC_ENTRY(328, 14, 34, 12, 41, 0, 69, 1, 68),
+	CABAC_ENTRY(329, 10, 38, 10, 41, 2, 65, 0, 65),
+	CABAC_ENTRY(330, -3, 52, 2, 48, -6, 74, -14, 73),
+	CABAC_ENTRY(331, 13, 40, 12, 41, 5, 54, 3, 62),
+	CABAC_ENTRY(332, 17, 32, 13, 41, 7, 54, 4, 62),
+	CABAC_ENTRY(333, 7, 44, 0, 59, -6, 76, -1, 68),
+	CABAC_ENTRY(334, 7, 38, 3, 50, -11, 82, -13, 75),
+	CABAC_ENTRY(335, 13, 50, 19, 40, -2, 77, 11, 55),
+	CABAC_ENTRY(336, 10, 57, 3, 66, -2, 77, 5, 64),
+	CABAC_ENTRY(337, 26, 43, 18, 50, 25, 42, 12, 70),
+
+	/* Table 9-23 ? Values of variables m and n for ctxIdx from 338 to 398 */
+	CABAC_ENTRY(338, 14, 11, 19, -6, 17, -13, 15, 6),
+	CABAC_ENTRY(339, 11, 14, 18, -6, 16, -9, 6, 19),
+	CABAC_ENTRY(340, 9, 11, 14, 0, 17, -12, 7, 16),
+	CABAC_ENTRY(341, 18, 11, 26, -12, 27, -21, 12, 14),
+	CABAC_ENTRY(342, 21, 9, 31, -16, 37, -30, 18, 13),
+	CABAC_ENTRY(343, 23, -2, 33, -25, 41, -40, 13, 11),
+	CABAC_ENTRY(344, 32, -15, 33, -22, 42, -41, 13, 15),
+	CABAC_ENTRY(345, 32, -15, 37, -28, 48, -47, 15, 16),
+	CABAC_ENTRY(346, 34, -21, 39, -30, 39, -32, 12, 23),
+	CABAC_ENTRY(347, 39, -23, 42, -30, 46, -40, 13, 23),
+	CABAC_ENTRY(348, 42, -33, 47, -42, 52, -51, 15, 20),
+	CABAC_ENTRY(349, 41, -31, 45, -36, 46, -41, 14, 26),
+	CABAC_ENTRY(350, 46, -28, 49, -34, 52, -39, 14, 44),
+	CABAC_ENTRY(351, 38, -12, 41, -17, 43, -19, 17, 40),
+	CABAC_ENTRY(352, 21, 29, 32, 9, 32, 11, 17, 47),
+	CABAC_ENTRY(353, 45, -24, 69, -71, 61, -55, 24, 17),
+	CABAC_ENTRY(354, 53, -45, 63, -63, 56, -46, 21, 21),
+	CABAC_ENTRY(355, 48, -26, 66, -64, 62, -50, 25, 22),
+	CABAC_ENTRY(356, 65, -43, 77, -74, 81, -67, 31, 27),
+	CABAC_ENTRY(357, 43, -19, 54, -39, 45, -20, 22, 29),
+	CABAC_ENTRY(358, 39, -10, 52, -35, 35, -2, 19, 35),
+	CABAC_ENTRY(359, 30, 9, 41, -10, 28, 15, 14, 50),
+	CABAC_ENTRY(360, 18, 26, 36, 0, 34, 1, 10, 57),
+	CABAC_ENTRY(361, 20, 27, 40, -1, 39, 1, 7, 63),
+	CABAC_ENTRY(362, 0, 57, 30, 14, 30, 17, -2, 77),
+	CABAC_ENTRY(363, -14, 82, 28, 26, 20, 38, -4, 82),
+	CABAC_ENTRY(364, -5, 75, 23, 37, 18, 45, -3, 94),
+	CABAC_ENTRY(365, -19, 97, 12, 55, 15, 54, 9, 69),
+	CABAC_ENTRY(366, -35, 125, 11, 65, 0, 79, -12, 109),
+	CABAC_ENTRY(367, 27, 0, 37, -33, 36, -16, 36, -35),
+	CABAC_ENTRY(368, 28, 0, 39, -36, 37, -14, 36, -34),
+	CABAC_ENTRY(369, 31, -4, 40, -37, 37, -17, 32, -26),
+	CABAC_ENTRY(370, 27, 6, 38, -30, 32, 1, 37, -30),
+	CABAC_ENTRY(371, 34, 8, 46, -33, 34, 15, 44, -32),
+	CABAC_ENTRY(372, 30, 10, 42, -30, 29, 15, 34, -18),
+	CABAC_ENTRY(373, 24, 22, 40, -24, 24, 25, 34, -15),
+	CABAC_ENTRY(374, 33, 19, 49, -29, 34, 22, 40, -15),
+	CABAC_ENTRY(375, 22, 32, 38, -12, 31, 16, 33, -7),
+	CABAC_ENTRY(376, 26, 31, 40, -10, 35, 18, 35, -5),
+	CABAC_ENTRY(377, 21, 41, 38, -3, 31, 28, 33, 0),
+	CABAC_ENTRY(378, 26, 44, 46, -5, 33, 41, 38, 2),
+	CABAC_ENTRY(379, 23, 47, 31, 20, 36, 28, 33, 13),
+	CABAC_ENTRY(380, 16, 65, 29, 30, 27, 47, 23, 35),
+	CABAC_ENTRY(381, 14, 71, 25, 44, 21, 62, 13, 58),
+	CABAC_ENTRY(382, 8, 60, 12, 48, 18, 31, 29, -3),
+	CABAC_ENTRY(383, 6, 63, 11, 49, 19, 26, 26, 0),
+	CABAC_ENTRY(384, 17, 65, 26, 45, 36, 24, 22, 30),
+	CABAC_ENTRY(385, 21, 24, 22, 22, 24, 23, 31, -7),
+	CABAC_ENTRY(386, 23, 20, 23, 22, 27, 16, 35, -15),
+	CABAC_ENTRY(387, 26, 23, 27, 21, 24, 30, 34, -3),
+	CABAC_ENTRY(388, 27, 32, 33, 20, 31, 29, 34, 3),
+	CABAC_ENTRY(389, 28, 23, 26, 28, 22, 41, 36, -1),
+	CABAC_ENTRY(390, 28, 24, 30, 24, 22, 42, 34, 5),
+	CABAC_ENTRY(391, 23, 40, 27, 34, 16, 60, 32, 11),
+	CABAC_ENTRY(392, 24, 32, 18, 42, 15, 52, 35, 5),
+	CABAC_ENTRY(393, 28, 29, 25, 39, 14, 60, 34, 12),
+	CABAC_ENTRY(394, 23, 42, 18, 50, 3, 78, 39, 11),
+	CABAC_ENTRY(395, 19, 57, 12, 70, -16, 123, 30, 29),
+	CABAC_ENTRY(396, 22, 53, 21, 54, 21, 53, 34, 26),
+	CABAC_ENTRY(397, 22, 61, 14, 71, 22, 56, 29, 39),
+	CABAC_ENTRY(398, 11, 86, 11, 83, 25, 61, 19, 66),
+
+	/* Values of variables m and n for ctxIdx from 399 to 463 (not documented) */
+	CABAC_ENTRY(399, 12, 40, 25, 32, 21, 33, 31, 21),
+	CABAC_ENTRY(400, 11, 51, 21, 49, 19, 50, 31, 31),
+	CABAC_ENTRY(401, 14, 59, 21, 54, 17, 61, 25, 50),
+	CABAC_ENTRY(402, -4, 79, -5, 85, -3, 78, -17, 120),
+	CABAC_ENTRY(403, -7, 71, -6, 81, -8, 74, -20, 112),
+	CABAC_ENTRY(404, -5, 69, -10, 77, -9, 72, -18, 114),
+	CABAC_ENTRY(405, -9, 70, -7, 81, -10, 72, -11, 85),
+	CABAC_ENTRY(406, -8, 66, -17, 80, -18, 75, -15, 92),
+	CABAC_ENTRY(407, -10, 68, -18, 73, -12, 71, -14, 89),
+	CABAC_ENTRY(408, -19, 73, -4, 74, -11, 63, -26, 71),
+	CABAC_ENTRY(409, -12, 69, -10, 83, -5, 70, -15, 81),
+	CABAC_ENTRY(410, -16, 70, -9, 71, -17, 75, -14, 80),
+	CABAC_ENTRY(411, -15, 67, -9, 67, -14, 72, 0, 68),
+	CABAC_ENTRY(412, -20, 62, -1, 61, -16, 67, -14, 70),
+	CABAC_ENTRY(413, -19, 70, -8, 66, -8, 53, -24, 56),
+	CABAC_ENTRY(414, -16, 66, -14, 66, -14, 59, -23, 68),
+	CABAC_ENTRY(415, -22, 65, 0, 59, -9, 52, -24, 50),
+	CABAC_ENTRY(416, -20, 63, 2, 59, -11, 68, -11, 74),
+	CABAC_ENTRY(417, 9, -2, 17, -10, 9, -2, 23, -13),
+	CABAC_ENTRY(418, 26, -9, 32, -13, 30, -10, 26, -13),
+	CABAC_ENTRY(419, 33, -9, 42, -9, 31, -4, 40, -15),
+	CABAC_ENTRY(420, 39, -7, 49, -5, 33, -1, 49, -14),
+	CABAC_ENTRY(421, 41, -2, 53, 0, 33, 7, 44, 3),
+	CABAC_ENTRY(422, 45, 3, 64, 3, 31, 12, 45, 6),
+	CABAC_ENTRY(423, 49, 9, 68, 10, 37, 23, 44, 34),
+	CABAC_ENTRY(424, 45, 27, 66, 27, 31, 38, 33, 54),
+	CABAC_ENTRY(425, 36, 59, 47, 57, 20, 64, 19, 82),
+	CABAC_ENTRY(426, -6, 66, -5, 71, -9, 71, -3, 75),
+	CABAC_ENTRY(427, -7, 35, 0, 24, -7, 37, -1, 23),
+	CABAC_ENTRY(428, -7, 42, -1, 36, -8, 44, 1, 34),
+	CABAC_ENTRY(429, -8, 45, -2, 42, -11, 49, 1, 43),
+	CABAC_ENTRY(430, -5, 48, -2, 52, -10, 56, 0, 54),
+	CABAC_ENTRY(431, -12, 56, -9, 57, -12, 59, -2, 55),
+	CABAC_ENTRY(432, -6, 60, -6, 63, -8, 63, 0, 61),
+	CABAC_ENTRY(433, -5, 62, -4, 65, -9, 67, 1, 64),
+	CABAC_ENTRY(434, -8, 66, -4, 67, -6, 68, 0, 68),
+	CABAC_ENTRY(435, -8, 76, -7, 82, -10, 79, -9, 92),
+	CABAC_ENTRY(436, -5, 85, -3, 81, -3, 78, -14, 106),
+	CABAC_ENTRY(437, -6, 81, -3, 76, -8, 74, -13, 97),
+	CABAC_ENTRY(438, -10, 77, -7, 72, -9, 72, -15, 90),
+	CABAC_ENTRY(439, -7, 81, -6, 78, -10, 72, -12, 90),
+	CABAC_ENTRY(440, -17, 80, -12, 72, -18, 75, -18, 88),
+	CABAC_ENTRY(441, -18, 73, -14, 68, -12, 71, -10, 73),
+	CABAC_ENTRY(442, -4, 74, -3, 70, -11, 63, -9, 79),
+	CABAC_ENTRY(443, -10, 83, -6, 76, -5, 70, -14, 86),
+	CABAC_ENTRY(444, -9, 71, -5, 66, -17, 75, -10, 73),
+	CABAC_ENTRY(445, -9, 67, -5, 62, -14, 72, -10, 70),
+	CABAC_ENTRY(446, -1, 61, 0, 57, -16, 67, -10, 69),
+	CABAC_ENTRY(447, -8, 66, -4, 61, -8, 53, -5, 66),
+	CABAC_ENTRY(448, -14, 66, -9, 60, -14, 59, -9, 64),
+	CABAC_ENTRY(449, 0, 59, 1, 54, -9, 52, -5, 58),
+	CABAC_ENTRY(450, 2, 59, 2, 58, -11, 68, 2, 59),
+	CABAC_ENTRY(451, 21, -13, 17, -10, 9, -2, 21, -10),
+	CABAC_ENTRY(452, 33, -14, 32, -13, 30, -10, 24, -11),
+	CABAC_ENTRY(453, 39, -7, 42, -9, 31, -4, 28, -8),
+	CABAC_ENTRY(454, 46, -2, 49, -5, 33, -1, 28, -1),
+	CABAC_ENTRY(455, 51, 2, 53, 0, 33, 7, 29, 3),
+	CABAC_ENTRY(456, 60, 6, 64, 3, 31, 12, 29, 9),
+	CABAC_ENTRY(457, 61, 17, 68, 10, 37, 23, 35, 20),
+	CABAC_ENTRY(458, 55, 34, 66, 27, 31, 38, 29, 36),
+	CABAC_ENTRY(459, 42, 62, 47, 57, 20, 64, 14, 67),
+};
+
+#define RKV_HEVC_CABAC_TABLE_SIZE		27456
+
+const u8 rkvdec_hevc_cabac_table[RKV_HEVC_CABAC_TABLE_SIZE] = {
 	0x07, 0x0f, 0x48, 0x58, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0f, 0x40, 0x40, 0x40, 0x0f,
 	0x68, 0x48, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x40,
 	0x40, 0x68, 0x58, 0x60, 0x40, 0x1f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x48, 0x48, 0x60,
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
index 68e20cb81a885..088840248a76b 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
@@ -15,6 +15,8 @@
 #include "rkvdec.h"
 #include "rkvdec-regs.h"
 
+extern const s8 rkvdec_h264_cabac_table[4][464][2];
+
 /* Size with u32 units. */
 #define RKV_CABAC_INIT_BUFFER_SIZE	(3680 + 128)
 #define RKV_RPS_SIZE			((128 + 128) / 4)
@@ -118,505 +120,6 @@ struct rkvdec_h264_ctx {
 	struct rkvdec_regs regs;
 };
 
-#define CABAC_ENTRY(ctxidx, idc0_m, idc0_n, idc1_m, idc1_n,		\
-	    idc2_m, idc2_n, intra_m, intra_n)			\
-	[0][(ctxidx)] = {idc0_m, idc0_n},			\
-	[1][(ctxidx)] = {idc1_m, idc1_n},			\
-	[2][(ctxidx)] = {idc2_m, idc2_n},			\
-	[3][(ctxidx)] = {intra_m, intra_n}
-
-/*
- * Constant CABAC table.
- * Built from the tables described in section '9.3.1.1 Initialisation process
- * for context variables' of the H264 spec.
- */
-static const s8 rkvdec_h264_cabac_table[4][464][2] = {
-	/* Table 9-12 ? Values of variables m and n for ctxIdx from 0 to 10 */
-	CABAC_ENTRY(0, 20, -15, 20, -15, 20, -15, 20, -15),
-	CABAC_ENTRY(1, 2, 54, 2, 54, 2, 54, 2, 54),
-	CABAC_ENTRY(2, 3, 74, 3, 74, 3, 74, 3, 74),
-	CABAC_ENTRY(3, 20, -15, 20, -15, 20, -15, 20, -15),
-	CABAC_ENTRY(4, 2, 54, 2, 54, 2, 54, 2, 54),
-	CABAC_ENTRY(5, 3, 74, 3, 74, 3, 74, 3, 74),
-	CABAC_ENTRY(6, -28, 127, -28, 127, -28, 127, -28, 127),
-	CABAC_ENTRY(7, -23, 104, -23, 104, -23, 104, -23, 104),
-	CABAC_ENTRY(8, -6, 53, -6, 53, -6, 53, -6, 53),
-	CABAC_ENTRY(9, -1, 54, -1, 54, -1, 54, -1, 54),
-	CABAC_ENTRY(10, 7, 51, 7, 51, 7, 51, 7, 51),
-
-	/* Table 9-13 ? Values of variables m and n for ctxIdx from 11 to 23 */
-	CABAC_ENTRY(11, 23, 33, 22, 25, 29, 16, 0, 0),
-	CABAC_ENTRY(12, 23, 2, 34, 0, 25, 0, 0, 0),
-	CABAC_ENTRY(13, 21, 0, 16, 0, 14, 0, 0, 0),
-	CABAC_ENTRY(14, 1, 9, -2, 9, -10, 51, 0, 0),
-	CABAC_ENTRY(15, 0, 49, 4, 41, -3, 62, 0, 0),
-	CABAC_ENTRY(16, -37, 118, -29, 118, -27, 99, 0, 0),
-	CABAC_ENTRY(17, 5, 57, 2, 65, 26, 16, 0, 0),
-	CABAC_ENTRY(18, -13, 78, -6, 71, -4, 85, 0, 0),
-	CABAC_ENTRY(19, -11, 65, -13, 79, -24, 102, 0, 0),
-	CABAC_ENTRY(20, 1, 62, 5, 52, 5, 57, 0, 0),
-	CABAC_ENTRY(21, 12, 49, 9, 50, 6, 57, 0, 0),
-	CABAC_ENTRY(22, -4, 73, -3, 70, -17, 73, 0, 0),
-	CABAC_ENTRY(23, 17, 50, 10, 54, 14, 57, 0, 0),
-
-	/* Table 9-14 ? Values of variables m and n for ctxIdx from 24 to 39 */
-	CABAC_ENTRY(24, 18, 64, 26, 34, 20, 40, 0, 0),
-	CABAC_ENTRY(25, 9, 43, 19, 22, 20, 10, 0, 0),
-	CABAC_ENTRY(26, 29, 0, 40, 0, 29, 0, 0, 0),
-	CABAC_ENTRY(27, 26, 67, 57, 2, 54, 0, 0, 0),
-	CABAC_ENTRY(28, 16, 90, 41, 36, 37, 42, 0, 0),
-	CABAC_ENTRY(29, 9, 104, 26, 69, 12, 97, 0, 0),
-	CABAC_ENTRY(30, -46, 127, -45, 127, -32, 127, 0, 0),
-	CABAC_ENTRY(31, -20, 104, -15, 101, -22, 117, 0, 0),
-	CABAC_ENTRY(32, 1, 67, -4, 76, -2, 74, 0, 0),
-	CABAC_ENTRY(33, -13, 78, -6, 71, -4, 85, 0, 0),
-	CABAC_ENTRY(34, -11, 65, -13, 79, -24, 102, 0, 0),
-	CABAC_ENTRY(35, 1, 62, 5, 52, 5, 57, 0, 0),
-	CABAC_ENTRY(36, -6, 86, 6, 69, -6, 93, 0, 0),
-	CABAC_ENTRY(37, -17, 95, -13, 90, -14, 88, 0, 0),
-	CABAC_ENTRY(38, -6, 61, 0, 52, -6, 44, 0, 0),
-	CABAC_ENTRY(39, 9, 45, 8, 43, 4, 55, 0, 0),
-
-	/* Table 9-15 ? Values of variables m and n for ctxIdx from 40 to 53 */
-	CABAC_ENTRY(40, -3, 69, -2, 69, -11, 89, 0, 0),
-	CABAC_ENTRY(41, -6, 81, -5, 82, -15, 103, 0, 0),
-	CABAC_ENTRY(42, -11, 96, -10, 96, -21, 116, 0, 0),
-	CABAC_ENTRY(43, 6, 55, 2, 59, 19, 57, 0, 0),
-	CABAC_ENTRY(44, 7, 67, 2, 75, 20, 58, 0, 0),
-	CABAC_ENTRY(45, -5, 86, -3, 87, 4, 84, 0, 0),
-	CABAC_ENTRY(46, 2, 88, -3, 100, 6, 96, 0, 0),
-	CABAC_ENTRY(47, 0, 58, 1, 56, 1, 63, 0, 0),
-	CABAC_ENTRY(48, -3, 76, -3, 74, -5, 85, 0, 0),
-	CABAC_ENTRY(49, -10, 94, -6, 85, -13, 106, 0, 0),
-	CABAC_ENTRY(50, 5, 54, 0, 59, 5, 63, 0, 0),
-	CABAC_ENTRY(51, 4, 69, -3, 81, 6, 75, 0, 0),
-	CABAC_ENTRY(52, -3, 81, -7, 86, -3, 90, 0, 0),
-	CABAC_ENTRY(53, 0, 88, -5, 95, -1, 101, 0, 0),
-
-	/* Table 9-16 ? Values of variables m and n for ctxIdx from 54 to 59 */
-	CABAC_ENTRY(54, -7, 67, -1, 66, 3, 55, 0, 0),
-	CABAC_ENTRY(55, -5, 74, -1, 77, -4, 79, 0, 0),
-	CABAC_ENTRY(56, -4, 74, 1, 70, -2, 75, 0, 0),
-	CABAC_ENTRY(57, -5, 80, -2, 86, -12, 97, 0, 0),
-	CABAC_ENTRY(58, -7, 72, -5, 72, -7, 50, 0, 0),
-	CABAC_ENTRY(59, 1, 58, 0, 61, 1, 60, 0, 0),
-
-	/* Table 9-17 ? Values of variables m and n for ctxIdx from 60 to 69 */
-	CABAC_ENTRY(60, 0, 41, 0, 41, 0, 41, 0, 41),
-	CABAC_ENTRY(61, 0, 63, 0, 63, 0, 63, 0, 63),
-	CABAC_ENTRY(62, 0, 63, 0, 63, 0, 63, 0, 63),
-	CABAC_ENTRY(63, 0, 63, 0, 63, 0, 63, 0, 63),
-	CABAC_ENTRY(64, -9, 83, -9, 83, -9, 83, -9, 83),
-	CABAC_ENTRY(65, 4, 86, 4, 86, 4, 86, 4, 86),
-	CABAC_ENTRY(66, 0, 97, 0, 97, 0, 97, 0, 97),
-	CABAC_ENTRY(67, -7, 72, -7, 72, -7, 72, -7, 72),
-	CABAC_ENTRY(68, 13, 41, 13, 41, 13, 41, 13, 41),
-	CABAC_ENTRY(69, 3, 62, 3, 62, 3, 62, 3, 62),
-
-	/* Table 9-18 ? Values of variables m and n for ctxIdx from 70 to 104 */
-	CABAC_ENTRY(70, 0, 45, 13, 15, 7, 34, 0, 11),
-	CABAC_ENTRY(71, -4, 78, 7, 51, -9, 88, 1, 55),
-	CABAC_ENTRY(72, -3, 96, 2, 80, -20, 127, 0, 69),
-	CABAC_ENTRY(73, -27, 126, -39, 127, -36, 127, -17, 127),
-	CABAC_ENTRY(74, -28, 98, -18, 91, -17, 91, -13, 102),
-	CABAC_ENTRY(75, -25, 101, -17, 96, -14, 95, 0, 82),
-	CABAC_ENTRY(76, -23, 67, -26, 81, -25, 84, -7, 74),
-	CABAC_ENTRY(77, -28, 82, -35, 98, -25, 86, -21, 107),
-	CABAC_ENTRY(78, -20, 94, -24, 102, -12, 89, -27, 127),
-	CABAC_ENTRY(79, -16, 83, -23, 97, -17, 91, -31, 127),
-	CABAC_ENTRY(80, -22, 110, -27, 119, -31, 127, -24, 127),
-	CABAC_ENTRY(81, -21, 91, -24, 99, -14, 76, -18, 95),
-	CABAC_ENTRY(82, -18, 102, -21, 110, -18, 103, -27, 127),
-	CABAC_ENTRY(83, -13, 93, -18, 102, -13, 90, -21, 114),
-	CABAC_ENTRY(84, -29, 127, -36, 127, -37, 127, -30, 127),
-	CABAC_ENTRY(85, -7, 92, 0, 80, 11, 80, -17, 123),
-	CABAC_ENTRY(86, -5, 89, -5, 89, 5, 76, -12, 115),
-	CABAC_ENTRY(87, -7, 96, -7, 94, 2, 84, -16, 122),
-	CABAC_ENTRY(88, -13, 108, -4, 92, 5, 78, -11, 115),
-	CABAC_ENTRY(89, -3, 46, 0, 39, -6, 55, -12, 63),
-	CABAC_ENTRY(90, -1, 65, 0, 65, 4, 61, -2, 68),
-	CABAC_ENTRY(91, -1, 57, -15, 84, -14, 83, -15, 84),
-	CABAC_ENTRY(92, -9, 93, -35, 127, -37, 127, -13, 104),
-	CABAC_ENTRY(93, -3, 74, -2, 73, -5, 79, -3, 70),
-	CABAC_ENTRY(94, -9, 92, -12, 104, -11, 104, -8, 93),
-	CABAC_ENTRY(95, -8, 87, -9, 91, -11, 91, -10, 90),
-	CABAC_ENTRY(96, -23, 126, -31, 127, -30, 127, -30, 127),
-	CABAC_ENTRY(97, 5, 54, 3, 55, 0, 65, -1, 74),
-	CABAC_ENTRY(98, 6, 60, 7, 56, -2, 79, -6, 97),
-	CABAC_ENTRY(99, 6, 59, 7, 55, 0, 72, -7, 91),
-	CABAC_ENTRY(100, 6, 69, 8, 61, -4, 92, -20, 127),
-	CABAC_ENTRY(101, -1, 48, -3, 53, -6, 56, -4, 56),
-	CABAC_ENTRY(102, 0, 68, 0, 68, 3, 68, -5, 82),
-	CABAC_ENTRY(103, -4, 69, -7, 74, -8, 71, -7, 76),
-	CABAC_ENTRY(104, -8, 88, -9, 88, -13, 98, -22, 125),
-
-	/* Table 9-19 ? Values of variables m and n for ctxIdx from 105 to 165 */
-	CABAC_ENTRY(105, -2, 85, -13, 103, -4, 86, -7, 93),
-	CABAC_ENTRY(106, -6, 78, -13, 91, -12, 88, -11, 87),
-	CABAC_ENTRY(107, -1, 75, -9, 89, -5, 82, -3, 77),
-	CABAC_ENTRY(108, -7, 77, -14, 92, -3, 72, -5, 71),
-	CABAC_ENTRY(109, 2, 54, -8, 76, -4, 67, -4, 63),
-	CABAC_ENTRY(110, 5, 50, -12, 87, -8, 72, -4, 68),
-	CABAC_ENTRY(111, -3, 68, -23, 110, -16, 89, -12, 84),
-	CABAC_ENTRY(112, 1, 50, -24, 105, -9, 69, -7, 62),
-	CABAC_ENTRY(113, 6, 42, -10, 78, -1, 59, -7, 65),
-	CABAC_ENTRY(114, -4, 81, -20, 112, 5, 66, 8, 61),
-	CABAC_ENTRY(115, 1, 63, -17, 99, 4, 57, 5, 56),
-	CABAC_ENTRY(116, -4, 70, -78, 127, -4, 71, -2, 66),
-	CABAC_ENTRY(117, 0, 67, -70, 127, -2, 71, 1, 64),
-	CABAC_ENTRY(118, 2, 57, -50, 127, 2, 58, 0, 61),
-	CABAC_ENTRY(119, -2, 76, -46, 127, -1, 74, -2, 78),
-	CABAC_ENTRY(120, 11, 35, -4, 66, -4, 44, 1, 50),
-	CABAC_ENTRY(121, 4, 64, -5, 78, -1, 69, 7, 52),
-	CABAC_ENTRY(122, 1, 61, -4, 71, 0, 62, 10, 35),
-	CABAC_ENTRY(123, 11, 35, -8, 72, -7, 51, 0, 44),
-	CABAC_ENTRY(124, 18, 25, 2, 59, -4, 47, 11, 38),
-	CABAC_ENTRY(125, 12, 24, -1, 55, -6, 42, 1, 45),
-	CABAC_ENTRY(126, 13, 29, -7, 70, -3, 41, 0, 46),
-	CABAC_ENTRY(127, 13, 36, -6, 75, -6, 53, 5, 44),
-	CABAC_ENTRY(128, -10, 93, -8, 89, 8, 76, 31, 17),
-	CABAC_ENTRY(129, -7, 73, -34, 119, -9, 78, 1, 51),
-	CABAC_ENTRY(130, -2, 73, -3, 75, -11, 83, 7, 50),
-	CABAC_ENTRY(131, 13, 46, 32, 20, 9, 52, 28, 19),
-	CABAC_ENTRY(132, 9, 49, 30, 22, 0, 67, 16, 33),
-	CABAC_ENTRY(133, -7, 100, -44, 127, -5, 90, 14, 62),
-	CABAC_ENTRY(134, 9, 53, 0, 54, 1, 67, -13, 108),
-	CABAC_ENTRY(135, 2, 53, -5, 61, -15, 72, -15, 100),
-	CABAC_ENTRY(136, 5, 53, 0, 58, -5, 75, -13, 101),
-	CABAC_ENTRY(137, -2, 61, -1, 60, -8, 80, -13, 91),
-	CABAC_ENTRY(138, 0, 56, -3, 61, -21, 83, -12, 94),
-	CABAC_ENTRY(139, 0, 56, -8, 67, -21, 64, -10, 88),
-	CABAC_ENTRY(140, -13, 63, -25, 84, -13, 31, -16, 84),
-	CABAC_ENTRY(141, -5, 60, -14, 74, -25, 64, -10, 86),
-	CABAC_ENTRY(142, -1, 62, -5, 65, -29, 94, -7, 83),
-	CABAC_ENTRY(143, 4, 57, 5, 52, 9, 75, -13, 87),
-	CABAC_ENTRY(144, -6, 69, 2, 57, 17, 63, -19, 94),
-	CABAC_ENTRY(145, 4, 57, 0, 61, -8, 74, 1, 70),
-	CABAC_ENTRY(146, 14, 39, -9, 69, -5, 35, 0, 72),
-	CABAC_ENTRY(147, 4, 51, -11, 70, -2, 27, -5, 74),
-	CABAC_ENTRY(148, 13, 68, 18, 55, 13, 91, 18, 59),
-	CABAC_ENTRY(149, 3, 64, -4, 71, 3, 65, -8, 102),
-	CABAC_ENTRY(150, 1, 61, 0, 58, -7, 69, -15, 100),
-	CABAC_ENTRY(151, 9, 63, 7, 61, 8, 77, 0, 95),
-	CABAC_ENTRY(152, 7, 50, 9, 41, -10, 66, -4, 75),
-	CABAC_ENTRY(153, 16, 39, 18, 25, 3, 62, 2, 72),
-	CABAC_ENTRY(154, 5, 44, 9, 32, -3, 68, -11, 75),
-	CABAC_ENTRY(155, 4, 52, 5, 43, -20, 81, -3, 71),
-	CABAC_ENTRY(156, 11, 48, 9, 47, 0, 30, 15, 46),
-	CABAC_ENTRY(157, -5, 60, 0, 44, 1, 7, -13, 69),
-	CABAC_ENTRY(158, -1, 59, 0, 51, -3, 23, 0, 62),
-	CABAC_ENTRY(159, 0, 59, 2, 46, -21, 74, 0, 65),
-	CABAC_ENTRY(160, 22, 33, 19, 38, 16, 66, 21, 37),
-	CABAC_ENTRY(161, 5, 44, -4, 66, -23, 124, -15, 72),
-	CABAC_ENTRY(162, 14, 43, 15, 38, 17, 37, 9, 57),
-	CABAC_ENTRY(163, -1, 78, 12, 42, 44, -18, 16, 54),
-	CABAC_ENTRY(164, 0, 60, 9, 34, 50, -34, 0, 62),
-	CABAC_ENTRY(165, 9, 69, 0, 89, -22, 127, 12, 72),
-
-	/* Table 9-20 ? Values of variables m and n for ctxIdx from 166 to 226 */
-	CABAC_ENTRY(166, 11, 28, 4, 45, 4, 39, 24, 0),
-	CABAC_ENTRY(167, 2, 40, 10, 28, 0, 42, 15, 9),
-	CABAC_ENTRY(168, 3, 44, 10, 31, 7, 34, 8, 25),
-	CABAC_ENTRY(169, 0, 49, 33, -11, 11, 29, 13, 18),
-	CABAC_ENTRY(170, 0, 46, 52, -43, 8, 31, 15, 9),
-	CABAC_ENTRY(171, 2, 44, 18, 15, 6, 37, 13, 19),
-	CABAC_ENTRY(172, 2, 51, 28, 0, 7, 42, 10, 37),
-	CABAC_ENTRY(173, 0, 47, 35, -22, 3, 40, 12, 18),
-	CABAC_ENTRY(174, 4, 39, 38, -25, 8, 33, 6, 29),
-	CABAC_ENTRY(175, 2, 62, 34, 0, 13, 43, 20, 33),
-	CABAC_ENTRY(176, 6, 46, 39, -18, 13, 36, 15, 30),
-	CABAC_ENTRY(177, 0, 54, 32, -12, 4, 47, 4, 45),
-	CABAC_ENTRY(178, 3, 54, 102, -94, 3, 55, 1, 58),
-	CABAC_ENTRY(179, 2, 58, 0, 0, 2, 58, 0, 62),
-	CABAC_ENTRY(180, 4, 63, 56, -15, 6, 60, 7, 61),
-	CABAC_ENTRY(181, 6, 51, 33, -4, 8, 44, 12, 38),
-	CABAC_ENTRY(182, 6, 57, 29, 10, 11, 44, 11, 45),
-	CABAC_ENTRY(183, 7, 53, 37, -5, 14, 42, 15, 39),
-	CABAC_ENTRY(184, 6, 52, 51, -29, 7, 48, 11, 42),
-	CABAC_ENTRY(185, 6, 55, 39, -9, 4, 56, 13, 44),
-	CABAC_ENTRY(186, 11, 45, 52, -34, 4, 52, 16, 45),
-	CABAC_ENTRY(187, 14, 36, 69, -58, 13, 37, 12, 41),
-	CABAC_ENTRY(188, 8, 53, 67, -63, 9, 49, 10, 49),
-	CABAC_ENTRY(189, -1, 82, 44, -5, 19, 58, 30, 34),
-	CABAC_ENTRY(190, 7, 55, 32, 7, 10, 48, 18, 42),
-	CABAC_ENTRY(191, -3, 78, 55, -29, 12, 45, 10, 55),
-	CABAC_ENTRY(192, 15, 46, 32, 1, 0, 69, 17, 51),
-	CABAC_ENTRY(193, 22, 31, 0, 0, 20, 33, 17, 46),
-	CABAC_ENTRY(194, -1, 84, 27, 36, 8, 63, 0, 89),
-	CABAC_ENTRY(195, 25, 7, 33, -25, 35, -18, 26, -19),
-	CABAC_ENTRY(196, 30, -7, 34, -30, 33, -25, 22, -17),
-	CABAC_ENTRY(197, 28, 3, 36, -28, 28, -3, 26, -17),
-	CABAC_ENTRY(198, 28, 4, 38, -28, 24, 10, 30, -25),
-	CABAC_ENTRY(199, 32, 0, 38, -27, 27, 0, 28, -20),
-	CABAC_ENTRY(200, 34, -1, 34, -18, 34, -14, 33, -23),
-	CABAC_ENTRY(201, 30, 6, 35, -16, 52, -44, 37, -27),
-	CABAC_ENTRY(202, 30, 6, 34, -14, 39, -24, 33, -23),
-	CABAC_ENTRY(203, 32, 9, 32, -8, 19, 17, 40, -28),
-	CABAC_ENTRY(204, 31, 19, 37, -6, 31, 25, 38, -17),
-	CABAC_ENTRY(205, 26, 27, 35, 0, 36, 29, 33, -11),
-	CABAC_ENTRY(206, 26, 30, 30, 10, 24, 33, 40, -15),
-	CABAC_ENTRY(207, 37, 20, 28, 18, 34, 15, 41, -6),
-	CABAC_ENTRY(208, 28, 34, 26, 25, 30, 20, 38, 1),
-	CABAC_ENTRY(209, 17, 70, 29, 41, 22, 73, 41, 17),
-	CABAC_ENTRY(210, 1, 67, 0, 75, 20, 34, 30, -6),
-	CABAC_ENTRY(211, 5, 59, 2, 72, 19, 31, 27, 3),
-	CABAC_ENTRY(212, 9, 67, 8, 77, 27, 44, 26, 22),
-	CABAC_ENTRY(213, 16, 30, 14, 35, 19, 16, 37, -16),
-	CABAC_ENTRY(214, 18, 32, 18, 31, 15, 36, 35, -4),
-	CABAC_ENTRY(215, 18, 35, 17, 35, 15, 36, 38, -8),
-	CABAC_ENTRY(216, 22, 29, 21, 30, 21, 28, 38, -3),
-	CABAC_ENTRY(217, 24, 31, 17, 45, 25, 21, 37, 3),
-	CABAC_ENTRY(218, 23, 38, 20, 42, 30, 20, 38, 5),
-	CABAC_ENTRY(219, 18, 43, 18, 45, 31, 12, 42, 0),
-	CABAC_ENTRY(220, 20, 41, 27, 26, 27, 16, 35, 16),
-	CABAC_ENTRY(221, 11, 63, 16, 54, 24, 42, 39, 22),
-	CABAC_ENTRY(222, 9, 59, 7, 66, 0, 93, 14, 48),
-	CABAC_ENTRY(223, 9, 64, 16, 56, 14, 56, 27, 37),
-	CABAC_ENTRY(224, -1, 94, 11, 73, 15, 57, 21, 60),
-	CABAC_ENTRY(225, -2, 89, 10, 67, 26, 38, 12, 68),
-	CABAC_ENTRY(226, -9, 108, -10, 116, -24, 127, 2, 97),
-
-	/* Table 9-21 ? Values of variables m and n for ctxIdx from 227 to 275 */
-	CABAC_ENTRY(227, -6, 76, -23, 112, -24, 115, -3, 71),
-	CABAC_ENTRY(228, -2, 44, -15, 71, -22, 82, -6, 42),
-	CABAC_ENTRY(229, 0, 45, -7, 61, -9, 62, -5, 50),
-	CABAC_ENTRY(230, 0, 52, 0, 53, 0, 53, -3, 54),
-	CABAC_ENTRY(231, -3, 64, -5, 66, 0, 59, -2, 62),
-	CABAC_ENTRY(232, -2, 59, -11, 77, -14, 85, 0, 58),
-	CABAC_ENTRY(233, -4, 70, -9, 80, -13, 89, 1, 63),
-	CABAC_ENTRY(234, -4, 75, -9, 84, -13, 94, -2, 72),
-	CABAC_ENTRY(235, -8, 82, -10, 87, -11, 92, -1, 74),
-	CABAC_ENTRY(236, -17, 102, -34, 127, -29, 127, -9, 91),
-	CABAC_ENTRY(237, -9, 77, -21, 101, -21, 100, -5, 67),
-	CABAC_ENTRY(238, 3, 24, -3, 39, -14, 57, -5, 27),
-	CABAC_ENTRY(239, 0, 42, -5, 53, -12, 67, -3, 39),
-	CABAC_ENTRY(240, 0, 48, -7, 61, -11, 71, -2, 44),
-	CABAC_ENTRY(241, 0, 55, -11, 75, -10, 77, 0, 46),
-	CABAC_ENTRY(242, -6, 59, -15, 77, -21, 85, -16, 64),
-	CABAC_ENTRY(243, -7, 71, -17, 91, -16, 88, -8, 68),
-	CABAC_ENTRY(244, -12, 83, -25, 107, -23, 104, -10, 78),
-	CABAC_ENTRY(245, -11, 87, -25, 111, -15, 98, -6, 77),
-	CABAC_ENTRY(246, -30, 119, -28, 122, -37, 127, -10, 86),
-	CABAC_ENTRY(247, 1, 58, -11, 76, -10, 82, -12, 92),
-	CABAC_ENTRY(248, -3, 29, -10, 44, -8, 48, -15, 55),
-	CABAC_ENTRY(249, -1, 36, -10, 52, -8, 61, -10, 60),
-	CABAC_ENTRY(250, 1, 38, -10, 57, -8, 66, -6, 62),
-	CABAC_ENTRY(251, 2, 43, -9, 58, -7, 70, -4, 65),
-	CABAC_ENTRY(252, -6, 55, -16, 72, -14, 75, -12, 73),
-	CABAC_ENTRY(253, 0, 58, -7, 69, -10, 79, -8, 76),
-	CABAC_ENTRY(254, 0, 64, -4, 69, -9, 83, -7, 80),
-	CABAC_ENTRY(255, -3, 74, -5, 74, -12, 92, -9, 88),
-	CABAC_ENTRY(256, -10, 90, -9, 86, -18, 108, -17, 110),
-	CABAC_ENTRY(257, 0, 70, 2, 66, -4, 79, -11, 97),
-	CABAC_ENTRY(258, -4, 29, -9, 34, -22, 69, -20, 84),
-	CABAC_ENTRY(259, 5, 31, 1, 32, -16, 75, -11, 79),
-	CABAC_ENTRY(260, 7, 42, 11, 31, -2, 58, -6, 73),
-	CABAC_ENTRY(261, 1, 59, 5, 52, 1, 58, -4, 74),
-	CABAC_ENTRY(262, -2, 58, -2, 55, -13, 78, -13, 86),
-	CABAC_ENTRY(263, -3, 72, -2, 67, -9, 83, -13, 96),
-	CABAC_ENTRY(264, -3, 81, 0, 73, -4, 81, -11, 97),
-	CABAC_ENTRY(265, -11, 97, -8, 89, -13, 99, -19, 117),
-	CABAC_ENTRY(266, 0, 58, 3, 52, -13, 81, -8, 78),
-	CABAC_ENTRY(267, 8, 5, 7, 4, -6, 38, -5, 33),
-	CABAC_ENTRY(268, 10, 14, 10, 8, -13, 62, -4, 48),
-	CABAC_ENTRY(269, 14, 18, 17, 8, -6, 58, -2, 53),
-	CABAC_ENTRY(270, 13, 27, 16, 19, -2, 59, -3, 62),
-	CABAC_ENTRY(271, 2, 40, 3, 37, -16, 73, -13, 71),
-	CABAC_ENTRY(272, 0, 58, -1, 61, -10, 76, -10, 79),
-	CABAC_ENTRY(273, -3, 70, -5, 73, -13, 86, -12, 86),
-	CABAC_ENTRY(274, -6, 79, -1, 70, -9, 83, -13, 90),
-	CABAC_ENTRY(275, -8, 85, -4, 78, -10, 87, -14, 97),
-
-	/* Table 9-22 ? Values of variables m and n for ctxIdx from 277 to 337 */
-	CABAC_ENTRY(277, -13, 106, -21, 126, -22, 127, -6, 93),
-	CABAC_ENTRY(278, -16, 106, -23, 124, -25, 127, -6, 84),
-	CABAC_ENTRY(279, -10, 87, -20, 110, -25, 120, -8, 79),
-	CABAC_ENTRY(280, -21, 114, -26, 126, -27, 127, 0, 66),
-	CABAC_ENTRY(281, -18, 110, -25, 124, -19, 114, -1, 71),
-	CABAC_ENTRY(282, -14, 98, -17, 105, -23, 117, 0, 62),
-	CABAC_ENTRY(283, -22, 110, -27, 121, -25, 118, -2, 60),
-	CABAC_ENTRY(284, -21, 106, -27, 117, -26, 117, -2, 59),
-	CABAC_ENTRY(285, -18, 103, -17, 102, -24, 113, -5, 75),
-	CABAC_ENTRY(286, -21, 107, -26, 117, -28, 118, -3, 62),
-	CABAC_ENTRY(287, -23, 108, -27, 116, -31, 120, -4, 58),
-	CABAC_ENTRY(288, -26, 112, -33, 122, -37, 124, -9, 66),
-	CABAC_ENTRY(289, -10, 96, -10, 95, -10, 94, -1, 79),
-	CABAC_ENTRY(290, -12, 95, -14, 100, -15, 102, 0, 71),
-	CABAC_ENTRY(291, -5, 91, -8, 95, -10, 99, 3, 68),
-	CABAC_ENTRY(292, -9, 93, -17, 111, -13, 106, 10, 44),
-	CABAC_ENTRY(293, -22, 94, -28, 114, -50, 127, -7, 62),
-	CABAC_ENTRY(294, -5, 86, -6, 89, -5, 92, 15, 36),
-	CABAC_ENTRY(295, 9, 67, -2, 80, 17, 57, 14, 40),
-	CABAC_ENTRY(296, -4, 80, -4, 82, -5, 86, 16, 27),
-	CABAC_ENTRY(297, -10, 85, -9, 85, -13, 94, 12, 29),
-	CABAC_ENTRY(298, -1, 70, -8, 81, -12, 91, 1, 44),
-	CABAC_ENTRY(299, 7, 60, -1, 72, -2, 77, 20, 36),
-	CABAC_ENTRY(300, 9, 58, 5, 64, 0, 71, 18, 32),
-	CABAC_ENTRY(301, 5, 61, 1, 67, -1, 73, 5, 42),
-	CABAC_ENTRY(302, 12, 50, 9, 56, 4, 64, 1, 48),
-	CABAC_ENTRY(303, 15, 50, 0, 69, -7, 81, 10, 62),
-	CABAC_ENTRY(304, 18, 49, 1, 69, 5, 64, 17, 46),
-	CABAC_ENTRY(305, 17, 54, 7, 69, 15, 57, 9, 64),
-	CABAC_ENTRY(306, 10, 41, -7, 69, 1, 67, -12, 104),
-	CABAC_ENTRY(307, 7, 46, -6, 67, 0, 68, -11, 97),
-	CABAC_ENTRY(308, -1, 51, -16, 77, -10, 67, -16, 96),
-	CABAC_ENTRY(309, 7, 49, -2, 64, 1, 68, -7, 88),
-	CABAC_ENTRY(310, 8, 52, 2, 61, 0, 77, -8, 85),
-	CABAC_ENTRY(311, 9, 41, -6, 67, 2, 64, -7, 85),
-	CABAC_ENTRY(312, 6, 47, -3, 64, 0, 68, -9, 85),
-	CABAC_ENTRY(313, 2, 55, 2, 57, -5, 78, -13, 88),
-	CABAC_ENTRY(314, 13, 41, -3, 65, 7, 55, 4, 66),
-	CABAC_ENTRY(315, 10, 44, -3, 66, 5, 59, -3, 77),
-	CABAC_ENTRY(316, 6, 50, 0, 62, 2, 65, -3, 76),
-	CABAC_ENTRY(317, 5, 53, 9, 51, 14, 54, -6, 76),
-	CABAC_ENTRY(318, 13, 49, -1, 66, 15, 44, 10, 58),
-	CABAC_ENTRY(319, 4, 63, -2, 71, 5, 60, -1, 76),
-	CABAC_ENTRY(320, 6, 64, -2, 75, 2, 70, -1, 83),
-	CABAC_ENTRY(321, -2, 69, -1, 70, -2, 76, -7, 99),
-	CABAC_ENTRY(322, -2, 59, -9, 72, -18, 86, -14, 95),
-	CABAC_ENTRY(323, 6, 70, 14, 60, 12, 70, 2, 95),
-	CABAC_ENTRY(324, 10, 44, 16, 37, 5, 64, 0, 76),
-	CABAC_ENTRY(325, 9, 31, 0, 47, -12, 70, -5, 74),
-	CABAC_ENTRY(326, 12, 43, 18, 35, 11, 55, 0, 70),
-	CABAC_ENTRY(327, 3, 53, 11, 37, 5, 56, -11, 75),
-	CABAC_ENTRY(328, 14, 34, 12, 41, 0, 69, 1, 68),
-	CABAC_ENTRY(329, 10, 38, 10, 41, 2, 65, 0, 65),
-	CABAC_ENTRY(330, -3, 52, 2, 48, -6, 74, -14, 73),
-	CABAC_ENTRY(331, 13, 40, 12, 41, 5, 54, 3, 62),
-	CABAC_ENTRY(332, 17, 32, 13, 41, 7, 54, 4, 62),
-	CABAC_ENTRY(333, 7, 44, 0, 59, -6, 76, -1, 68),
-	CABAC_ENTRY(334, 7, 38, 3, 50, -11, 82, -13, 75),
-	CABAC_ENTRY(335, 13, 50, 19, 40, -2, 77, 11, 55),
-	CABAC_ENTRY(336, 10, 57, 3, 66, -2, 77, 5, 64),
-	CABAC_ENTRY(337, 26, 43, 18, 50, 25, 42, 12, 70),
-
-	/* Table 9-23 ? Values of variables m and n for ctxIdx from 338 to 398 */
-	CABAC_ENTRY(338, 14, 11, 19, -6, 17, -13, 15, 6),
-	CABAC_ENTRY(339, 11, 14, 18, -6, 16, -9, 6, 19),
-	CABAC_ENTRY(340, 9, 11, 14, 0, 17, -12, 7, 16),
-	CABAC_ENTRY(341, 18, 11, 26, -12, 27, -21, 12, 14),
-	CABAC_ENTRY(342, 21, 9, 31, -16, 37, -30, 18, 13),
-	CABAC_ENTRY(343, 23, -2, 33, -25, 41, -40, 13, 11),
-	CABAC_ENTRY(344, 32, -15, 33, -22, 42, -41, 13, 15),
-	CABAC_ENTRY(345, 32, -15, 37, -28, 48, -47, 15, 16),
-	CABAC_ENTRY(346, 34, -21, 39, -30, 39, -32, 12, 23),
-	CABAC_ENTRY(347, 39, -23, 42, -30, 46, -40, 13, 23),
-	CABAC_ENTRY(348, 42, -33, 47, -42, 52, -51, 15, 20),
-	CABAC_ENTRY(349, 41, -31, 45, -36, 46, -41, 14, 26),
-	CABAC_ENTRY(350, 46, -28, 49, -34, 52, -39, 14, 44),
-	CABAC_ENTRY(351, 38, -12, 41, -17, 43, -19, 17, 40),
-	CABAC_ENTRY(352, 21, 29, 32, 9, 32, 11, 17, 47),
-	CABAC_ENTRY(353, 45, -24, 69, -71, 61, -55, 24, 17),
-	CABAC_ENTRY(354, 53, -45, 63, -63, 56, -46, 21, 21),
-	CABAC_ENTRY(355, 48, -26, 66, -64, 62, -50, 25, 22),
-	CABAC_ENTRY(356, 65, -43, 77, -74, 81, -67, 31, 27),
-	CABAC_ENTRY(357, 43, -19, 54, -39, 45, -20, 22, 29),
-	CABAC_ENTRY(358, 39, -10, 52, -35, 35, -2, 19, 35),
-	CABAC_ENTRY(359, 30, 9, 41, -10, 28, 15, 14, 50),
-	CABAC_ENTRY(360, 18, 26, 36, 0, 34, 1, 10, 57),
-	CABAC_ENTRY(361, 20, 27, 40, -1, 39, 1, 7, 63),
-	CABAC_ENTRY(362, 0, 57, 30, 14, 30, 17, -2, 77),
-	CABAC_ENTRY(363, -14, 82, 28, 26, 20, 38, -4, 82),
-	CABAC_ENTRY(364, -5, 75, 23, 37, 18, 45, -3, 94),
-	CABAC_ENTRY(365, -19, 97, 12, 55, 15, 54, 9, 69),
-	CABAC_ENTRY(366, -35, 125, 11, 65, 0, 79, -12, 109),
-	CABAC_ENTRY(367, 27, 0, 37, -33, 36, -16, 36, -35),
-	CABAC_ENTRY(368, 28, 0, 39, -36, 37, -14, 36, -34),
-	CABAC_ENTRY(369, 31, -4, 40, -37, 37, -17, 32, -26),
-	CABAC_ENTRY(370, 27, 6, 38, -30, 32, 1, 37, -30),
-	CABAC_ENTRY(371, 34, 8, 46, -33, 34, 15, 44, -32),
-	CABAC_ENTRY(372, 30, 10, 42, -30, 29, 15, 34, -18),
-	CABAC_ENTRY(373, 24, 22, 40, -24, 24, 25, 34, -15),
-	CABAC_ENTRY(374, 33, 19, 49, -29, 34, 22, 40, -15),
-	CABAC_ENTRY(375, 22, 32, 38, -12, 31, 16, 33, -7),
-	CABAC_ENTRY(376, 26, 31, 40, -10, 35, 18, 35, -5),
-	CABAC_ENTRY(377, 21, 41, 38, -3, 31, 28, 33, 0),
-	CABAC_ENTRY(378, 26, 44, 46, -5, 33, 41, 38, 2),
-	CABAC_ENTRY(379, 23, 47, 31, 20, 36, 28, 33, 13),
-	CABAC_ENTRY(380, 16, 65, 29, 30, 27, 47, 23, 35),
-	CABAC_ENTRY(381, 14, 71, 25, 44, 21, 62, 13, 58),
-	CABAC_ENTRY(382, 8, 60, 12, 48, 18, 31, 29, -3),
-	CABAC_ENTRY(383, 6, 63, 11, 49, 19, 26, 26, 0),
-	CABAC_ENTRY(384, 17, 65, 26, 45, 36, 24, 22, 30),
-	CABAC_ENTRY(385, 21, 24, 22, 22, 24, 23, 31, -7),
-	CABAC_ENTRY(386, 23, 20, 23, 22, 27, 16, 35, -15),
-	CABAC_ENTRY(387, 26, 23, 27, 21, 24, 30, 34, -3),
-	CABAC_ENTRY(388, 27, 32, 33, 20, 31, 29, 34, 3),
-	CABAC_ENTRY(389, 28, 23, 26, 28, 22, 41, 36, -1),
-	CABAC_ENTRY(390, 28, 24, 30, 24, 22, 42, 34, 5),
-	CABAC_ENTRY(391, 23, 40, 27, 34, 16, 60, 32, 11),
-	CABAC_ENTRY(392, 24, 32, 18, 42, 15, 52, 35, 5),
-	CABAC_ENTRY(393, 28, 29, 25, 39, 14, 60, 34, 12),
-	CABAC_ENTRY(394, 23, 42, 18, 50, 3, 78, 39, 11),
-	CABAC_ENTRY(395, 19, 57, 12, 70, -16, 123, 30, 29),
-	CABAC_ENTRY(396, 22, 53, 21, 54, 21, 53, 34, 26),
-	CABAC_ENTRY(397, 22, 61, 14, 71, 22, 56, 29, 39),
-	CABAC_ENTRY(398, 11, 86, 11, 83, 25, 61, 19, 66),
-
-	/* Values of variables m and n for ctxIdx from 399 to 463 (not documented) */
-	CABAC_ENTRY(399, 12, 40, 25, 32, 21, 33, 31, 21),
-	CABAC_ENTRY(400, 11, 51, 21, 49, 19, 50, 31, 31),
-	CABAC_ENTRY(401, 14, 59, 21, 54, 17, 61, 25, 50),
-	CABAC_ENTRY(402, -4, 79, -5, 85, -3, 78, -17, 120),
-	CABAC_ENTRY(403, -7, 71, -6, 81, -8, 74, -20, 112),
-	CABAC_ENTRY(404, -5, 69, -10, 77, -9, 72, -18, 114),
-	CABAC_ENTRY(405, -9, 70, -7, 81, -10, 72, -11, 85),
-	CABAC_ENTRY(406, -8, 66, -17, 80, -18, 75, -15, 92),
-	CABAC_ENTRY(407, -10, 68, -18, 73, -12, 71, -14, 89),
-	CABAC_ENTRY(408, -19, 73, -4, 74, -11, 63, -26, 71),
-	CABAC_ENTRY(409, -12, 69, -10, 83, -5, 70, -15, 81),
-	CABAC_ENTRY(410, -16, 70, -9, 71, -17, 75, -14, 80),
-	CABAC_ENTRY(411, -15, 67, -9, 67, -14, 72, 0, 68),
-	CABAC_ENTRY(412, -20, 62, -1, 61, -16, 67, -14, 70),
-	CABAC_ENTRY(413, -19, 70, -8, 66, -8, 53, -24, 56),
-	CABAC_ENTRY(414, -16, 66, -14, 66, -14, 59, -23, 68),
-	CABAC_ENTRY(415, -22, 65, 0, 59, -9, 52, -24, 50),
-	CABAC_ENTRY(416, -20, 63, 2, 59, -11, 68, -11, 74),
-	CABAC_ENTRY(417, 9, -2, 17, -10, 9, -2, 23, -13),
-	CABAC_ENTRY(418, 26, -9, 32, -13, 30, -10, 26, -13),
-	CABAC_ENTRY(419, 33, -9, 42, -9, 31, -4, 40, -15),
-	CABAC_ENTRY(420, 39, -7, 49, -5, 33, -1, 49, -14),
-	CABAC_ENTRY(421, 41, -2, 53, 0, 33, 7, 44, 3),
-	CABAC_ENTRY(422, 45, 3, 64, 3, 31, 12, 45, 6),
-	CABAC_ENTRY(423, 49, 9, 68, 10, 37, 23, 44, 34),
-	CABAC_ENTRY(424, 45, 27, 66, 27, 31, 38, 33, 54),
-	CABAC_ENTRY(425, 36, 59, 47, 57, 20, 64, 19, 82),
-	CABAC_ENTRY(426, -6, 66, -5, 71, -9, 71, -3, 75),
-	CABAC_ENTRY(427, -7, 35, 0, 24, -7, 37, -1, 23),
-	CABAC_ENTRY(428, -7, 42, -1, 36, -8, 44, 1, 34),
-	CABAC_ENTRY(429, -8, 45, -2, 42, -11, 49, 1, 43),
-	CABAC_ENTRY(430, -5, 48, -2, 52, -10, 56, 0, 54),
-	CABAC_ENTRY(431, -12, 56, -9, 57, -12, 59, -2, 55),
-	CABAC_ENTRY(432, -6, 60, -6, 63, -8, 63, 0, 61),
-	CABAC_ENTRY(433, -5, 62, -4, 65, -9, 67, 1, 64),
-	CABAC_ENTRY(434, -8, 66, -4, 67, -6, 68, 0, 68),
-	CABAC_ENTRY(435, -8, 76, -7, 82, -10, 79, -9, 92),
-	CABAC_ENTRY(436, -5, 85, -3, 81, -3, 78, -14, 106),
-	CABAC_ENTRY(437, -6, 81, -3, 76, -8, 74, -13, 97),
-	CABAC_ENTRY(438, -10, 77, -7, 72, -9, 72, -15, 90),
-	CABAC_ENTRY(439, -7, 81, -6, 78, -10, 72, -12, 90),
-	CABAC_ENTRY(440, -17, 80, -12, 72, -18, 75, -18, 88),
-	CABAC_ENTRY(441, -18, 73, -14, 68, -12, 71, -10, 73),
-	CABAC_ENTRY(442, -4, 74, -3, 70, -11, 63, -9, 79),
-	CABAC_ENTRY(443, -10, 83, -6, 76, -5, 70, -14, 86),
-	CABAC_ENTRY(444, -9, 71, -5, 66, -17, 75, -10, 73),
-	CABAC_ENTRY(445, -9, 67, -5, 62, -14, 72, -10, 70),
-	CABAC_ENTRY(446, -1, 61, 0, 57, -16, 67, -10, 69),
-	CABAC_ENTRY(447, -8, 66, -4, 61, -8, 53, -5, 66),
-	CABAC_ENTRY(448, -14, 66, -9, 60, -14, 59, -9, 64),
-	CABAC_ENTRY(449, 0, 59, 1, 54, -9, 52, -5, 58),
-	CABAC_ENTRY(450, 2, 59, 2, 58, -11, 68, 2, 59),
-	CABAC_ENTRY(451, 21, -13, 17, -10, 9, -2, 21, -10),
-	CABAC_ENTRY(452, 33, -14, 32, -13, 30, -10, 24, -11),
-	CABAC_ENTRY(453, 39, -7, 42, -9, 31, -4, 28, -8),
-	CABAC_ENTRY(454, 46, -2, 49, -5, 33, -1, 28, -1),
-	CABAC_ENTRY(455, 51, 2, 53, 0, 33, 7, 29, 3),
-	CABAC_ENTRY(456, 60, 6, 64, 3, 31, 12, 29, 9),
-	CABAC_ENTRY(457, 61, 17, 68, 10, 37, 23, 35, 20),
-	CABAC_ENTRY(458, 55, 34, 66, 27, 31, 38, 29, 36),
-	CABAC_ENTRY(459, 42, 62, 47, 57, 20, 64, 14, 67),
-};
-
 static void set_ps_field(u32 *buf, struct rkvdec_ps_field field, u32 value)
 {
 	u8 bit = field.offset % 32, word = field.offset / 32;
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
index 2d9e0e947a6dc..dfadb9a13c9a8 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
@@ -16,7 +16,6 @@
 
 #include "rkvdec.h"
 #include "rkvdec-regs.h"
-#include "rkvdec-hevc-data.c"
 
 /* Size in u8/u32 units. */
 #define RKV_SCALING_LIST_SIZE		1360
@@ -25,6 +24,9 @@
 #define RKV_RPS_SIZE			(32 / 4)
 #define RKV_RPS_LEN			600
 
+#define RKV_HEVC_CABAC_TABLE_SIZE		27456
+extern const u8 rkvdec_hevc_cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
+
 struct rkvdec_sps_pps_packet {
 	u32 info[RKV_PPS_SIZE];
 };
@@ -110,7 +112,7 @@ struct rkvdec_ps_field {
 
 /* Data structure describing auxiliary buffer format. */
 struct rkvdec_hevc_priv_tbl {
-	u8 cabac_table[RKV_CABAC_TABLE_SIZE];
+	u8 cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
 	u8 scaling_list[RKV_SCALING_LIST_SIZE];
 	struct rkvdec_sps_pps_packet param_set[RKV_PPS_LEN];
 	struct rkvdec_rps_packet rps[RKV_RPS_LEN];
-- 
2.52.0



From detlev.casanova at collabora.com  Thu Dec 18 15:28:17 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Thu, 18 Dec 2025 18:28:17 -0500
Subject: [PATCH v7 07/17] media: rkvdec: Move h264 functions to common file
In-Reply-To: <20251218232829.337811-1-detlev.casanova@collabora.com>
References: <20251218232829.337811-1-detlev.casanova@collabora.com>
Message-ID: <20251218232829.337811-8-detlev.casanova@collabora.com>

This is a preparation commit to add support for new variants of the
decoder.

The functions will later be shared with vdpu381 (rk3588) and vdpu383
(rk3576).

Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../media/platform/rockchip/rkvdec/Makefile   |   1 +
 .../rockchip/rkvdec/rkvdec-h264-common.c      | 258 +++++++++++++++
 .../rockchip/rkvdec/rkvdec-h264-common.h      |  87 +++++
 .../platform/rockchip/rkvdec/rkvdec-h264.c    | 310 +-----------------
 4 files changed, 350 insertions(+), 306 deletions(-)
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.c
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h

diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
index a8ff5e3d7bec3..d2ba7a7c15e59 100644
--- a/drivers/media/platform/rockchip/rkvdec/Makefile
+++ b/drivers/media/platform/rockchip/rkvdec/Makefile
@@ -4,5 +4,6 @@ rockchip-vdec-y += \
 		   rkvdec.o \
 		   rkvdec-cabac.o \
 		   rkvdec-h264.o \
+		   rkvdec-h264-common.o \
 		   rkvdec-hevc.o \
 		   rkvdec-vp9.o
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.c
new file mode 100644
index 0000000000000..e28f063944705
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.c
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip video decoder h264 common functions
+ *
+ * Copyright (C) 2025 Collabora, Ltd.
+ *	Detlev Casanova <detlev.casanova at collabora.com>
+ *
+ * Copyright (C) 2019 Collabora, Ltd.
+ *	Boris Brezillon <boris.brezillon at collabora.com>
+ *
+ * Copyright (C) 2016 Rockchip Electronics Co., Ltd.
+ *	Jeffy Chen <jeffy.chen at rock-chips.com>
+ */
+
+#include <linux/v4l2-common.h>
+#include <media/v4l2-h264.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "rkvdec.h"
+#include "rkvdec-h264-common.h"
+
+#define RKVDEC_NUM_REFLIST		3
+
+static void set_dpb_info(struct rkvdec_rps_entry *entries,
+			 u8 reflist,
+			 u8 refnum,
+			 u8 info,
+			 bool bottom)
+{
+	struct rkvdec_rps_entry *entry = &entries[(reflist * 4) + refnum / 8];
+	u8 idx = refnum % 8;
+
+	switch (idx) {
+	case 0:
+		entry->dpb_info0 = info;
+		entry->bottom_flag0 = bottom;
+		break;
+	case 1:
+		entry->dpb_info1 = info;
+		entry->bottom_flag1 = bottom;
+		break;
+	case 2:
+		entry->dpb_info2 = info;
+		entry->bottom_flag2 = bottom;
+		break;
+	case 3:
+		entry->dpb_info3 = info;
+		entry->bottom_flag3 = bottom;
+		break;
+	case 4:
+		entry->dpb_info4 = info;
+		entry->bottom_flag4 = bottom;
+		break;
+	case 5:
+		entry->dpb_info5 = info;
+		entry->bottom_flag5 = bottom;
+		break;
+	case 6:
+		entry->dpb_info6 = info;
+		entry->bottom_flag6 = bottom;
+		break;
+	case 7:
+		entry->dpb_info7 = info;
+		entry->bottom_flag7 = bottom;
+		break;
+	}
+}
+
+void lookup_ref_buf_idx(struct rkvdec_ctx *ctx,
+			struct rkvdec_h264_run *run)
+{
+	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
+	u32 i;
+
+	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
+		struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
+		const struct v4l2_h264_dpb_entry *dpb = run->decode_params->dpb;
+		struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q;
+		struct vb2_buffer *buf = NULL;
+
+		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) {
+			buf = vb2_find_buffer(cap_q, dpb[i].reference_ts);
+			if (!buf)
+				pr_debug("No buffer for reference_ts %llu",
+					 dpb[i].reference_ts);
+		}
+
+		run->ref_buf[i] = buf;
+	}
+}
+
+void assemble_hw_rps(struct v4l2_h264_reflist_builder *builder,
+		     struct rkvdec_h264_run *run,
+		     struct rkvdec_h264_reflists *reflists,
+		     struct rkvdec_rps *hw_rps)
+{
+	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
+	const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb;
+
+	u32 i, j;
+
+	memset(hw_rps, 0, sizeof(*hw_rps));
+
+	/*
+	 * Assign an invalid pic_num if DPB entry at that position is inactive.
+	 * If we assign 0 in that position hardware will treat that as a real
+	 * reference picture with pic_num 0, triggering output picture
+	 * corruption.
+	 */
+	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
+		if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
+			continue;
+
+		hw_rps->frame_num[i] = builder->refs[i].frame_num;
+	}
+
+	for (j = 0; j < RKVDEC_NUM_REFLIST; j++) {
+		for (i = 0; i < builder->num_valid; i++) {
+			struct v4l2_h264_reference *ref;
+			bool dpb_valid;
+			bool bottom;
+
+			switch (j) {
+			case 0:
+				ref = &reflists->p[i];
+				break;
+			case 1:
+				ref = &reflists->b0[i];
+				break;
+			case 2:
+				ref = &reflists->b1[i];
+				break;
+			}
+
+			if (WARN_ON(ref->index >= ARRAY_SIZE(dec_params->dpb)))
+				continue;
+
+			dpb_valid = !!(run->ref_buf[ref->index]);
+			bottom = ref->fields == V4L2_H264_BOTTOM_FIELD_REF;
+
+			set_dpb_info(hw_rps->entries, j, i, ref->index | (dpb_valid << 4), bottom);
+		}
+	}
+}
+
+void assemble_hw_scaling_list(struct rkvdec_h264_run *run,
+			      struct rkvdec_h264_scaling_list *scaling_list)
+{
+	const struct v4l2_ctrl_h264_scaling_matrix *scaling = run->scaling_matrix;
+	const struct v4l2_ctrl_h264_pps *pps = run->pps;
+
+	if (!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT))
+		return;
+
+	BUILD_BUG_ON(sizeof(scaling_list->scaling_list_4x4) !=
+		     sizeof(scaling->scaling_list_4x4));
+	BUILD_BUG_ON(sizeof(scaling_list->scaling_list_8x8) !=
+		     sizeof(scaling->scaling_list_8x8));
+
+	memcpy(scaling_list->scaling_list_4x4,
+	       scaling->scaling_list_4x4,
+	       sizeof(scaling->scaling_list_4x4));
+
+	memcpy(scaling_list->scaling_list_8x8,
+	       scaling->scaling_list_8x8,
+	       sizeof(scaling->scaling_list_8x8));
+}
+
+#define RKVDEC_H264_MAX_DEPTH_IN_BYTES		2
+
+int rkvdec_h264_adjust_fmt(struct rkvdec_ctx *ctx,
+			   struct v4l2_format *f)
+{
+	struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp;
+
+	fmt->num_planes = 1;
+	if (!fmt->plane_fmt[0].sizeimage)
+		fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height *
+					      RKVDEC_H264_MAX_DEPTH_IN_BYTES;
+	return 0;
+}
+
+enum rkvdec_image_fmt rkvdec_h264_get_image_fmt(struct rkvdec_ctx *ctx,
+						struct v4l2_ctrl *ctrl)
+{
+	const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps;
+
+	if (ctrl->id != V4L2_CID_STATELESS_H264_SPS)
+		return RKVDEC_IMG_FMT_ANY;
+
+	if (sps->bit_depth_luma_minus8 == 0) {
+		if (sps->chroma_format_idc == 2)
+			return RKVDEC_IMG_FMT_422_8BIT;
+		else
+			return RKVDEC_IMG_FMT_420_8BIT;
+	} else if (sps->bit_depth_luma_minus8 == 2) {
+		if (sps->chroma_format_idc == 2)
+			return RKVDEC_IMG_FMT_422_10BIT;
+		else
+			return RKVDEC_IMG_FMT_420_10BIT;
+	}
+
+	return RKVDEC_IMG_FMT_ANY;
+}
+
+int rkvdec_h264_validate_sps(struct rkvdec_ctx *ctx,
+			     const struct v4l2_ctrl_h264_sps *sps)
+{
+	unsigned int width, height;
+
+	if (sps->chroma_format_idc > 2)
+		/* Only 4:0:0, 4:2:0 and 4:2:2 are supported */
+		return -EINVAL;
+	if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
+		/* Luma and chroma bit depth mismatch */
+		return -EINVAL;
+	if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2)
+		/* Only 8-bit and 10-bit is supported */
+		return -EINVAL;
+
+	width = (sps->pic_width_in_mbs_minus1 + 1) * 16;
+	height = (sps->pic_height_in_map_units_minus1 + 1) * 16;
+
+	/*
+	 * When frame_mbs_only_flag is not set, this is field height,
+	 * which is half the final height (see (7-18) in the
+	 * specification)
+	 */
+	if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY))
+		height *= 2;
+
+	if (width > ctx->coded_fmt.fmt.pix_mp.width ||
+	    height > ctx->coded_fmt.fmt.pix_mp.height)
+		return -EINVAL;
+
+	return 0;
+}
+
+void rkvdec_h264_run_preamble(struct rkvdec_ctx *ctx,
+			      struct rkvdec_h264_run *run)
+{
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_H264_DECODE_PARAMS);
+	run->decode_params = ctrl ? ctrl->p_cur.p : NULL;
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_H264_SPS);
+	run->sps = ctrl ? ctrl->p_cur.p : NULL;
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_H264_PPS);
+	run->pps = ctrl ? ctrl->p_cur.p : NULL;
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_H264_SCALING_MATRIX);
+	run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL;
+
+	rkvdec_run_preamble(ctx, &run->base);
+}
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h
new file mode 100644
index 0000000000000..bd0c0081365b1
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Rockchip video decoder h264 common functions
+ *
+ * Copyright (C) 2025 Collabora, Ltd.
+ *	Detlev Casanova <detlev.casanova at collabora.com>
+ *
+ * Copyright (C) 2019 Collabora, Ltd.
+ *	Boris Brezillon <boris.brezillon at collabora.com>
+ *
+ * Copyright (C) 2016 Rockchip Electronics Co., Ltd.
+ *	Jeffy Chen <jeffy.chen at rock-chips.com>
+ */
+
+#include <media/v4l2-h264.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "rkvdec.h"
+
+extern const s8 rkvdec_h264_cabac_table[4][464][2];
+
+struct rkvdec_h264_scaling_list {
+	u8 scaling_list_4x4[6][16];
+	u8 scaling_list_8x8[6][64];
+	u8 padding[128];
+};
+
+struct rkvdec_h264_reflists {
+	struct v4l2_h264_reference p[V4L2_H264_REF_LIST_LEN];
+	struct v4l2_h264_reference b0[V4L2_H264_REF_LIST_LEN];
+	struct v4l2_h264_reference b1[V4L2_H264_REF_LIST_LEN];
+};
+
+struct rkvdec_h264_run {
+	struct rkvdec_run base;
+	const struct v4l2_ctrl_h264_decode_params *decode_params;
+	const struct v4l2_ctrl_h264_sps *sps;
+	const struct v4l2_ctrl_h264_pps *pps;
+	const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix;
+	struct vb2_buffer *ref_buf[V4L2_H264_NUM_DPB_ENTRIES];
+};
+
+struct rkvdec_rps_entry {
+	u32 dpb_info0:          5;
+	u32 bottom_flag0:       1;
+	u32 view_index_off0:    1;
+	u32 dpb_info1:          5;
+	u32 bottom_flag1:       1;
+	u32 view_index_off1:    1;
+	u32 dpb_info2:          5;
+	u32 bottom_flag2:       1;
+	u32 view_index_off2:    1;
+	u32 dpb_info3:          5;
+	u32 bottom_flag3:       1;
+	u32 view_index_off3:    1;
+	u32 dpb_info4:          5;
+	u32 bottom_flag4:       1;
+	u32 view_index_off4:    1;
+	u32 dpb_info5:          5;
+	u32 bottom_flag5:       1;
+	u32 view_index_off5:    1;
+	u32 dpb_info6:          5;
+	u32 bottom_flag6:       1;
+	u32 view_index_off6:    1;
+	u32 dpb_info7:          5;
+	u32 bottom_flag7:       1;
+	u32 view_index_off7:    1;
+} __packed;
+
+struct rkvdec_rps {
+	u16 frame_num[16];
+	u32 reserved0;
+	struct rkvdec_rps_entry entries[12];
+	u32 reserved1[66];
+} __packed;
+
+void lookup_ref_buf_idx(struct rkvdec_ctx *ctx, struct rkvdec_h264_run *run);
+void assemble_hw_rps(struct v4l2_h264_reflist_builder *builder,
+		     struct rkvdec_h264_run *run,
+		     struct rkvdec_h264_reflists *reflists,
+		     struct rkvdec_rps *hw_rps);
+void assemble_hw_scaling_list(struct rkvdec_h264_run *run,
+			      struct rkvdec_h264_scaling_list *scaling_list);
+int rkvdec_h264_adjust_fmt(struct rkvdec_ctx *ctx, struct v4l2_format *f);
+enum rkvdec_image_fmt rkvdec_h264_get_image_fmt(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl);
+int rkvdec_h264_validate_sps(struct rkvdec_ctx *ctx, const struct v4l2_ctrl_h264_sps *sps);
+void rkvdec_h264_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_h264_run *run);
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
index fd941e9262796..d93c7953692d6 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
@@ -14,59 +14,16 @@
 
 #include "rkvdec.h"
 #include "rkvdec-regs.h"
-
-extern const s8 rkvdec_h264_cabac_table[4][464][2];
+#include "rkvdec-h264-common.h"
 
 /* Size with u32 units. */
 #define RKV_CABAC_INIT_BUFFER_SIZE	(3680 + 128)
 #define RKV_ERROR_INFO_SIZE		(256 * 144 * 4)
 
-#define RKVDEC_NUM_REFLIST		3
-
-struct rkvdec_h264_scaling_list {
-	u8 scaling_list_4x4[6][16];
-	u8 scaling_list_8x8[6][64];
-	u8 padding[128];
-};
-
 struct rkvdec_sps_pps_packet {
 	u32 info[8];
 };
 
-struct rkvdec_rps_entry {
-	u32 dpb_info0:          5;
-	u32 bottom_flag0:       1;
-	u32 view_index_off0:    1;
-	u32 dpb_info1:          5;
-	u32 bottom_flag1:       1;
-	u32 view_index_off1:    1;
-	u32 dpb_info2:          5;
-	u32 bottom_flag2:       1;
-	u32 view_index_off2:    1;
-	u32 dpb_info3:          5;
-	u32 bottom_flag3:       1;
-	u32 view_index_off3:    1;
-	u32 dpb_info4:          5;
-	u32 bottom_flag4:       1;
-	u32 view_index_off4:    1;
-	u32 dpb_info5:          5;
-	u32 bottom_flag5:       1;
-	u32 view_index_off5:    1;
-	u32 dpb_info6:          5;
-	u32 bottom_flag6:       1;
-	u32 view_index_off6:    1;
-	u32 dpb_info7:          5;
-	u32 bottom_flag7:       1;
-	u32 view_index_off7:    1;
-} __packed;
-
-struct rkvdec_rps {
-	u16 frame_num[16];
-	u32 reserved0;
-	struct rkvdec_rps_entry entries[12];
-	u32 reserved1[66];
-} __packed;
-
 struct rkvdec_ps_field {
 	u16 offset;
 	u8 len;
@@ -118,11 +75,6 @@ struct rkvdec_ps_field {
 #define SCALING_LIST_ADDRESS				PS_FIELD(184, 32)
 #define IS_LONG_TERM(i)				PS_FIELD(216 + (i), 1)
 
-#define DPB_OFFS(i, j)					(288 + ((j) * 32 * 7) + ((i) * 7))
-#define DPB_INFO(i, j)					PS_FIELD(DPB_OFFS(i, j), 5)
-#define BOTTOM_FLAG(i, j)				PS_FIELD(DPB_OFFS(i, j) + 5, 1)
-#define VIEW_INDEX_OFF(i, j)				PS_FIELD(DPB_OFFS(i, j) + 6, 1)
-
 /* Data structure describing auxiliary buffer format. */
 struct rkvdec_h264_priv_tbl {
 	s8 cabac_table[4][464][2];
@@ -132,21 +84,6 @@ struct rkvdec_h264_priv_tbl {
 	u8 err_info[RKV_ERROR_INFO_SIZE];
 };
 
-struct rkvdec_h264_reflists {
-	struct v4l2_h264_reference p[V4L2_H264_REF_LIST_LEN];
-	struct v4l2_h264_reference b0[V4L2_H264_REF_LIST_LEN];
-	struct v4l2_h264_reference b1[V4L2_H264_REF_LIST_LEN];
-};
-
-struct rkvdec_h264_run {
-	struct rkvdec_run base;
-	const struct v4l2_ctrl_h264_decode_params *decode_params;
-	const struct v4l2_ctrl_h264_sps *sps;
-	const struct v4l2_ctrl_h264_pps *pps;
-	const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix;
-	struct vb2_buffer *ref_buf[V4L2_H264_NUM_DPB_ENTRIES];
-};
-
 struct rkvdec_h264_ctx {
 	struct rkvdec_aux_buf priv_tbl;
 	struct rkvdec_h264_reflists reflists;
@@ -270,155 +207,6 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
 	}
 }
 
-static void lookup_ref_buf_idx(struct rkvdec_ctx *ctx,
-			       struct rkvdec_h264_run *run)
-{
-	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
-	u32 i;
-
-	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
-		struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
-		const struct v4l2_h264_dpb_entry *dpb = run->decode_params->dpb;
-		struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q;
-		struct vb2_buffer *buf = NULL;
-
-		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) {
-			buf = vb2_find_buffer(cap_q, dpb[i].reference_ts);
-			if (!buf)
-				pr_debug("No buffer for reference_ts %llu",
-					 dpb[i].reference_ts);
-		}
-
-		run->ref_buf[i] = buf;
-	}
-}
-
-static void set_dpb_info(struct rkvdec_rps_entry *entries,
-			 u8 reflist,
-			 u8 refnum,
-			 u8 info,
-			 bool bottom)
-{
-	struct rkvdec_rps_entry *entry = &entries[(reflist * 4) + refnum / 8];
-	u8 idx = refnum % 8;
-
-	switch (idx) {
-	case 0:
-		entry->dpb_info0 = info;
-		entry->bottom_flag0 = bottom;
-		break;
-	case 1:
-		entry->dpb_info1 = info;
-		entry->bottom_flag1 = bottom;
-		break;
-	case 2:
-		entry->dpb_info2 = info;
-		entry->bottom_flag2 = bottom;
-		break;
-	case 3:
-		entry->dpb_info3 = info;
-		entry->bottom_flag3 = bottom;
-		break;
-	case 4:
-		entry->dpb_info4 = info;
-		entry->bottom_flag4 = bottom;
-		break;
-	case 5:
-		entry->dpb_info5 = info;
-		entry->bottom_flag5 = bottom;
-		break;
-	case 6:
-		entry->dpb_info6 = info;
-		entry->bottom_flag6 = bottom;
-		break;
-	case 7:
-		entry->dpb_info7 = info;
-		entry->bottom_flag7 = bottom;
-		break;
-	}
-}
-
-static void assemble_hw_rps(struct rkvdec_ctx *ctx,
-			    struct v4l2_h264_reflist_builder *builder,
-			    struct rkvdec_h264_run *run)
-{
-	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
-	const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb;
-	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
-	struct rkvdec_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu;
-
-	struct rkvdec_rps *hw_rps = &priv_tbl->rps;
-	u32 i, j;
-
-	memset(hw_rps, 0, sizeof(*hw_rps));
-
-	/*
-	 * Assign an invalid pic_num if DPB entry at that position is inactive.
-	 * If we assign 0 in that position hardware will treat that as a real
-	 * reference picture with pic_num 0, triggering output picture
-	 * corruption.
-	 */
-	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
-		if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
-			continue;
-
-		hw_rps->frame_num[i] = builder->refs[i].frame_num;
-	}
-
-	for (j = 0; j < RKVDEC_NUM_REFLIST; j++) {
-		for (i = 0; i < builder->num_valid; i++) {
-			struct v4l2_h264_reference *ref;
-			bool dpb_valid;
-			bool bottom;
-
-			switch (j) {
-			case 0:
-				ref = &h264_ctx->reflists.p[i];
-				break;
-			case 1:
-				ref = &h264_ctx->reflists.b0[i];
-				break;
-			case 2:
-				ref = &h264_ctx->reflists.b1[i];
-				break;
-			}
-
-			if (WARN_ON(ref->index >= ARRAY_SIZE(dec_params->dpb)))
-				continue;
-
-			dpb_valid = run->ref_buf[ref->index] != NULL;
-			bottom = ref->fields == V4L2_H264_BOTTOM_FIELD_REF;
-
-			set_dpb_info(hw_rps->entries, j, i, ref->index | (dpb_valid << 4), bottom);
-		}
-	}
-}
-
-static void assemble_hw_scaling_list(struct rkvdec_ctx *ctx,
-				     struct rkvdec_h264_run *run)
-{
-	const struct v4l2_ctrl_h264_scaling_matrix *scaling = run->scaling_matrix;
-	const struct v4l2_ctrl_h264_pps *pps = run->pps;
-	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
-	struct rkvdec_h264_priv_tbl *tbl = h264_ctx->priv_tbl.cpu;
-
-	if (!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT))
-		return;
-
-	BUILD_BUG_ON(sizeof(tbl->scaling_list.scaling_list_4x4) !=
-		     sizeof(scaling->scaling_list_4x4));
-	BUILD_BUG_ON(sizeof(tbl->scaling_list.scaling_list_8x8) !=
-		     sizeof(scaling->scaling_list_8x8));
-
-	memcpy(tbl->scaling_list.scaling_list_4x4,
-	       scaling->scaling_list_4x4,
-	       sizeof(scaling->scaling_list_4x4));
-
-	memcpy(tbl->scaling_list.scaling_list_8x8,
-	       scaling->scaling_list_8x8,
-	       sizeof(scaling->scaling_list_8x8));
-}
-
 /*
  * Set the ref POC in the correct register.
  *
@@ -569,76 +357,6 @@ static void config_registers(struct rkvdec_ctx *ctx,
 			   MIN(sizeof(*regs), sizeof(u32) * rkvdec->variant->num_regs));
 }
 
-#define RKVDEC_H264_MAX_DEPTH_IN_BYTES		2
-
-static int rkvdec_h264_adjust_fmt(struct rkvdec_ctx *ctx,
-				  struct v4l2_format *f)
-{
-	struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp;
-
-	fmt->num_planes = 1;
-	if (!fmt->plane_fmt[0].sizeimage)
-		fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height *
-					      RKVDEC_H264_MAX_DEPTH_IN_BYTES;
-	return 0;
-}
-
-static enum rkvdec_image_fmt rkvdec_h264_get_image_fmt(struct rkvdec_ctx *ctx,
-						       struct v4l2_ctrl *ctrl)
-{
-	const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps;
-
-	if (ctrl->id != V4L2_CID_STATELESS_H264_SPS)
-		return RKVDEC_IMG_FMT_ANY;
-
-	if (sps->bit_depth_luma_minus8 == 0) {
-		if (sps->chroma_format_idc == 2)
-			return RKVDEC_IMG_FMT_422_8BIT;
-		else
-			return RKVDEC_IMG_FMT_420_8BIT;
-	} else if (sps->bit_depth_luma_minus8 == 2) {
-		if (sps->chroma_format_idc == 2)
-			return RKVDEC_IMG_FMT_422_10BIT;
-		else
-			return RKVDEC_IMG_FMT_420_10BIT;
-	}
-
-	return RKVDEC_IMG_FMT_ANY;
-}
-
-static int rkvdec_h264_validate_sps(struct rkvdec_ctx *ctx,
-				    const struct v4l2_ctrl_h264_sps *sps)
-{
-	unsigned int width, height;
-
-	if (sps->chroma_format_idc > 2)
-		/* Only 4:0:0, 4:2:0 and 4:2:2 are supported */
-		return -EINVAL;
-	if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
-		/* Luma and chroma bit depth mismatch */
-		return -EINVAL;
-	if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2)
-		/* Only 8-bit and 10-bit is supported */
-		return -EINVAL;
-
-	width = (sps->pic_width_in_mbs_minus1 + 1) * 16;
-	height = (sps->pic_height_in_map_units_minus1 + 1) * 16;
-
-	/*
-	 * When frame_mbs_only_flag is not set, this is field height,
-	 * which is half the final height (see (7-18) in the
-	 * specification)
-	 */
-	if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY))
-		height *= 2;
-
-	if (width > ctx->coded_fmt.fmt.pix_mp.width ||
-	    height > ctx->coded_fmt.fmt.pix_mp.height)
-		return -EINVAL;
-
-	return 0;
-}
-
 static int rkvdec_h264_start(struct rkvdec_ctx *ctx)
 {
 	struct rkvdec_dev *rkvdec = ctx->dev;
@@ -690,33 +408,13 @@ static void rkvdec_h264_stop(struct rkvdec_ctx *ctx)
 	kfree(h264_ctx);
 }
 
-static void rkvdec_h264_run_preamble(struct rkvdec_ctx *ctx,
-				     struct rkvdec_h264_run *run)
-{
-	struct v4l2_ctrl *ctrl;
-
-	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
-			      V4L2_CID_STATELESS_H264_DECODE_PARAMS);
-	run->decode_params = ctrl ? ctrl->p_cur.p : NULL;
-	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
-			      V4L2_CID_STATELESS_H264_SPS);
-	run->sps = ctrl ? ctrl->p_cur.p : NULL;
-	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
-			      V4L2_CID_STATELESS_H264_PPS);
-	run->pps = ctrl ? ctrl->p_cur.p : NULL;
-	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
-			      V4L2_CID_STATELESS_H264_SCALING_MATRIX);
-	run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL;
-
-	rkvdec_run_preamble(ctx, &run->base);
-}
-
 static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
 {
 	struct v4l2_h264_reflist_builder reflist_builder;
 	struct rkvdec_dev *rkvdec = ctx->dev;
 	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
 	struct rkvdec_h264_run run;
+	struct rkvdec_h264_priv_tbl *tbl = h264_ctx->priv_tbl.cpu;
 
 	rkvdec_h264_run_preamble(ctx, &run);
 
@@ -727,10 +425,10 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
 	v4l2_h264_build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0,
 				    h264_ctx->reflists.b1);
 
-	assemble_hw_scaling_list(ctx, &run);
+	assemble_hw_scaling_list(&run, &tbl->scaling_list);
 	assemble_hw_pps(ctx, &run);
 	lookup_ref_buf_idx(ctx, &run);
-	assemble_hw_rps(ctx, &reflist_builder, &run);
+	assemble_hw_rps(&reflist_builder, &run, &h264_ctx->reflists, &tbl->rps);
 	config_registers(ctx, &run);
 
 	rkvdec_run_postamble(ctx, &run.base);
-- 
2.52.0



From detlev.casanova at collabora.com  Thu Dec 18 15:28:18 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Thu, 18 Dec 2025 18:28:18 -0500
Subject: [PATCH v7 08/17] media: rkvdec: Move hevc functions to common file
In-Reply-To: <20251218232829.337811-1-detlev.casanova@collabora.com>
References: <20251218232829.337811-1-detlev.casanova@collabora.com>
Message-ID: <20251218232829.337811-9-detlev.casanova@collabora.com>

This is a preparation commit to add support for new variants of the
decoder.

The functions will later be shared with vdpu381 (rk3588) and vdpu383
(rk3576).

Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../media/platform/rockchip/rkvdec/Makefile   |   1 +
 .../rockchip/rkvdec/rkvdec-hevc-common.c      | 206 +++++++++++++++++
 .../rockchip/rkvdec/rkvdec-hevc-common.h      |  49 ++++
 .../platform/rockchip/rkvdec/rkvdec-hevc.c    | 217 +-----------------
 4 files changed, 263 insertions(+), 210 deletions(-)
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h

diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
index d2ba7a7c15e59..1b4bc44be23ee 100644
--- a/drivers/media/platform/rockchip/rkvdec/Makefile
+++ b/drivers/media/platform/rockchip/rkvdec/Makefile
@@ -6,4 +6,5 @@ rockchip-vdec-y += \
 		   rkvdec-h264.o \
 		   rkvdec-h264-common.o \
 		   rkvdec-hevc.o \
+		   rkvdec-hevc-common.o \
 		   rkvdec-vp9.o
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
new file mode 100644
index 0000000000000..cb56a9a243927
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip video decoder hevc common functions
+ *
+ * Copyright (C) 2025 Collabora, Ltd.
+ *      Detlev Casanova <detlev.casanova at collabora.com>
+ *
+ * Copyright (C) 2023 Collabora, Ltd.
+ *      Sebastian Fricke <sebastian.fricke at collabora.com>
+ *
+ * Copyright (C) 2019 Collabora, Ltd.
+ *	Boris Brezillon <boris.brezillon at collabora.com>
+ *
+ * Copyright (C) 2016 Rockchip Electronics Co., Ltd.
+ *	Jeffy Chen <jeffy.chen at rock-chips.com>
+ */
+
+#include <linux/v4l2-common.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "rkvdec.h"
+#include "rkvdec-hevc-common.h"
+
+/*
+ * Flip one or more matrices along their main diagonal and flatten them
+ * before writing it to the memory.
+ * Convert:
+ * ABCD         AEIM
+ * EFGH     =>  BFJN     =>     AEIMBFJNCGKODHLP
+ * IJKL         CGKO
+ * MNOP         DHLP
+ */
+static void transpose_and_flatten_matrices(u8 *output, const u8 *input,
+					   int matrices, int row_length)
+{
+	int i, j, row, x_offset, matrix_offset, rot_index, y_offset, matrix_size, new_value;
+
+	matrix_size = row_length * row_length;
+	for (i = 0; i < matrices; i++) {
+		row = 0;
+		x_offset = 0;
+		matrix_offset = i * matrix_size;
+		for (j = 0; j < matrix_size; j++) {
+			y_offset = j - (row * row_length);
+			rot_index = y_offset * row_length + x_offset;
+			new_value = *(input + i * matrix_size + j);
+			output[matrix_offset + rot_index] = new_value;
+			if ((j + 1) % row_length == 0) {
+				row += 1;
+				x_offset += 1;
+			}
+		}
+	}
+}
+
+static void assemble_scalingfactor0(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input)
+{
+	int offset = 0;
+
+	transpose_and_flatten_matrices(output, (const u8 *)input->scaling_list_4x4, 6, 4);
+	offset = 6 * 16 * sizeof(u8);
+	transpose_and_flatten_matrices(output + offset, (const u8 *)input->scaling_list_8x8, 6, 8);
+	offset += 6 * 64 * sizeof(u8);
+	transpose_and_flatten_matrices(output + offset,
+				       (const u8 *)input->scaling_list_16x16, 6, 8);
+	offset += 6 * 64 * sizeof(u8);
+	/* Add a 128 byte padding with 0s between the two 32x32 matrices */
+	transpose_and_flatten_matrices(output + offset,
+				       (const u8 *)input->scaling_list_32x32, 1, 8);
+	offset += 64 * sizeof(u8);
+	memset(output + offset, 0, 128);
+	offset += 128 * sizeof(u8);
+	transpose_and_flatten_matrices(output + offset,
+				       (const u8 *)input->scaling_list_32x32 + (64 * sizeof(u8)),
+				       1, 8);
+	offset += 64 * sizeof(u8);
+	memset(output + offset, 0, 128);
+}
+
+/*
+ * Required layout:
+ * A = scaling_list_dc_coef_16x16
+ * B = scaling_list_dc_coef_32x32
+ * 0 = Padding
+ *
+ * A, A, A, A, A, A, B, 0, 0, B, 0, 0
+ */
+static void assemble_scalingdc(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input)
+{
+	u8 list_32x32[6] = {0};
+
+	memcpy(output, input->scaling_list_dc_coef_16x16, 6 * sizeof(u8));
+	list_32x32[0] = input->scaling_list_dc_coef_32x32[0];
+	list_32x32[3] = input->scaling_list_dc_coef_32x32[1];
+	memcpy(output + 6 * sizeof(u8), list_32x32, 6 * sizeof(u8));
+}
+
+static void translate_scaling_list(struct scaling_factor *output,
+				   const struct v4l2_ctrl_hevc_scaling_matrix *input)
+{
+	assemble_scalingfactor0(output->scalingfactor0, input);
+	memcpy(output->scalingfactor1, (const u8 *)input->scaling_list_4x4, 96);
+	assemble_scalingdc(output->scalingdc, input);
+	memset(output->reserved, 0, 4 * sizeof(u8));
+}
+
+void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
+					  struct scaling_factor *scaling_factor,
+					  struct v4l2_ctrl_hevc_scaling_matrix *cache)
+{
+	const struct v4l2_ctrl_hevc_scaling_matrix *scaling = run->scaling_matrix;
+
+	if (!memcmp(cache, scaling,
+		    sizeof(struct v4l2_ctrl_hevc_scaling_matrix)))
+		return;
+
+	translate_scaling_list(scaling_factor, scaling);
+
+	memcpy(cache, scaling,
+	       sizeof(struct v4l2_ctrl_hevc_scaling_matrix));
+}
+
+struct vb2_buffer *
+get_ref_buf(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run,
+	    unsigned int dpb_idx)
+{
+	struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
+	const struct v4l2_ctrl_hevc_decode_params *decode_params = run->decode_params;
+	const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb;
+	struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q;
+	struct vb2_buffer *buf = NULL;
+
+	if (dpb_idx < decode_params->num_active_dpb_entries)
+		buf = vb2_find_buffer(cap_q, dpb[dpb_idx].timestamp);
+
+	/*
+	 * If a DPB entry is unused or invalid, the address of current destination
+	 * buffer is returned.
+	 */
+	if (!buf)
+		return &run->base.bufs.dst->vb2_buf;
+
+	return buf;
+}
+
+#define RKVDEC_HEVC_MAX_DEPTH_IN_BYTES		2
+
+int rkvdec_hevc_adjust_fmt(struct rkvdec_ctx *ctx, struct v4l2_format *f)
+{
+	struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp;
+
+	fmt->num_planes = 1;
+	if (!fmt->plane_fmt[0].sizeimage)
+		fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height *
+					      RKVDEC_HEVC_MAX_DEPTH_IN_BYTES;
+	return 0;
+}
+
+enum rkvdec_image_fmt rkvdec_hevc_get_image_fmt(struct rkvdec_ctx *ctx,
+						struct v4l2_ctrl *ctrl)
+{
+	const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps;
+
+	if (ctrl->id != V4L2_CID_STATELESS_HEVC_SPS)
+		return RKVDEC_IMG_FMT_ANY;
+
+	if (sps->bit_depth_luma_minus8 == 0) {
+		if (sps->chroma_format_idc == 2)
+			return RKVDEC_IMG_FMT_422_8BIT;
+		else
+			return RKVDEC_IMG_FMT_420_8BIT;
+	} else if (sps->bit_depth_luma_minus8 == 2) {
+		if (sps->chroma_format_idc == 2)
+			return RKVDEC_IMG_FMT_422_10BIT;
+		else
+			return RKVDEC_IMG_FMT_420_10BIT;
+	}
+
+	return RKVDEC_IMG_FMT_ANY;
+}
+
+
+void rkvdec_hevc_run_preamble(struct rkvdec_ctx *ctx,
+			      struct rkvdec_hevc_run *run)
+{
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_HEVC_DECODE_PARAMS);
+	run->decode_params = ctrl ? ctrl->p_cur.p : NULL;
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_HEVC_SLICE_PARAMS);
+	run->slices_params = ctrl ? ctrl->p_cur.p : NULL;
+	run->num_slices = ctrl ? ctrl->new_elems : 0;
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_HEVC_SPS);
+	run->sps = ctrl ? ctrl->p_cur.p : NULL;
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_HEVC_PPS);
+	run->pps = ctrl ? ctrl->p_cur.p : NULL;
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_HEVC_SCALING_MATRIX);
+	run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL;
+
+	rkvdec_run_preamble(ctx, &run->base);
+}
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
new file mode 100644
index 0000000000000..e3099fdd784b1
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Rockchip video decoder hevc common functions
+ *
+ * Copyright (C) 2025 Collabora, Ltd.
+ *      Detlev Casanova <detlev.casanova at collabora.com>
+ *
+ * Copyright (C) 2023 Collabora, Ltd.
+ *      Sebastian Fricke <sebastian.fricke at collabora.com>
+ *
+ * Copyright (C) 2019 Collabora, Ltd.
+ *	Boris Brezillon <boris.brezillon at collabora.com>
+ *
+ * Copyright (C) 2016 Rockchip Electronics Co., Ltd.
+ *	Jeffy Chen <jeffy.chen at rock-chips.com>
+ */
+
+#include <media/v4l2-mem2mem.h>
+#include "rkvdec.h"
+
+#define RKV_HEVC_CABAC_TABLE_SIZE		27456
+extern const u8 rkvdec_hevc_cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
+
+struct rkvdec_hevc_run {
+	struct rkvdec_run base;
+	const struct v4l2_ctrl_hevc_slice_params *slices_params;
+	const struct v4l2_ctrl_hevc_decode_params *decode_params;
+	const struct v4l2_ctrl_hevc_sps *sps;
+	const struct v4l2_ctrl_hevc_pps *pps;
+	const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix;
+	int num_slices;
+};
+
+struct scaling_factor {
+	u8 scalingfactor0[1248];
+	u8 scalingfactor1[96];	/*4X4 TU Rotate, total 16X4*/
+	u8 scalingdc[12];	/*N1005 Vienna Meeting*/
+	u8 reserved[4];		/*16Bytes align*/
+};
+
+void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
+					  struct scaling_factor *scaling_factor,
+					  struct v4l2_ctrl_hevc_scaling_matrix *cache);
+struct vb2_buffer *get_ref_buf(struct rkvdec_ctx *ctx,
+			       struct rkvdec_hevc_run *run,
+			       unsigned int dpb_idx);
+int rkvdec_hevc_adjust_fmt(struct rkvdec_ctx *ctx, struct v4l2_format *f);
+enum rkvdec_image_fmt rkvdec_hevc_get_image_fmt(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl);
+void rkvdec_hevc_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run);
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
index dfadb9a13c9a8..156ce381f0680 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
@@ -16,6 +16,7 @@
 
 #include "rkvdec.h"
 #include "rkvdec-regs.h"
+#include "rkvdec-hevc-common.h"
 
 /* Size in u8/u32 units. */
 #define RKV_SCALING_LIST_SIZE		1360
@@ -24,9 +25,6 @@
 #define RKV_RPS_SIZE			(32 / 4)
 #define RKV_RPS_LEN			600
 
-#define RKV_HEVC_CABAC_TABLE_SIZE		27456
-extern const u8 rkvdec_hevc_cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
-
 struct rkvdec_sps_pps_packet {
 	u32 info[RKV_PPS_SIZE];
 };
@@ -113,34 +111,17 @@ struct rkvdec_ps_field {
 /* Data structure describing auxiliary buffer format. */
 struct rkvdec_hevc_priv_tbl {
 	u8 cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
-	u8 scaling_list[RKV_SCALING_LIST_SIZE];
+	struct scaling_factor scaling_list;
 	struct rkvdec_sps_pps_packet param_set[RKV_PPS_LEN];
 	struct rkvdec_rps_packet rps[RKV_RPS_LEN];
 };
 
-struct rkvdec_hevc_run {
-	struct rkvdec_run base;
-	const struct v4l2_ctrl_hevc_slice_params *slices_params;
-	const struct v4l2_ctrl_hevc_decode_params *decode_params;
-	const struct v4l2_ctrl_hevc_sps *sps;
-	const struct v4l2_ctrl_hevc_pps *pps;
-	const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix;
-	int num_slices;
-};
-
 struct rkvdec_hevc_ctx {
 	struct rkvdec_aux_buf priv_tbl;
 	struct v4l2_ctrl_hevc_scaling_matrix scaling_matrix_cache;
 	struct rkvdec_regs regs;
 };
 
-struct scaling_factor {
-	u8 scalingfactor0[1248];
-	u8 scalingfactor1[96];		/*4X4 TU Rotate, total 16X4*/
-	u8 scalingdc[12];		/*N1005 Vienna Meeting*/
-	u8 reserved[4];		/*16Bytes align*/
-};
-
 static void set_ps_field(u32 *buf, struct rkvdec_ps_field field, u32 value)
 {
 	u8 bit = field.offset % 32, word = field.offset / 32;
@@ -417,131 +398,6 @@ static void assemble_sw_rps(struct rkvdec_ctx *ctx,
 	}
 }
 
-/*
- * Flip one or more matrices along their main diagonal and flatten them
- * before writing it to the memory.
- * Convert:
- * ABCD         AEIM
- * EFGH     =>  BFJN     =>     AEIMBFJNCGKODHLP
- * IJKL         CGKO
- * MNOP         DHLP
- */
-static void transpose_and_flatten_matrices(u8 *output, const u8 *input,
-					   int matrices, int row_length)
-{
-	int i, j, row, x_offset, matrix_offset, rot_index, y_offset, matrix_size, new_value;
-
-	matrix_size = row_length * row_length;
-	for (i = 0; i < matrices; i++) {
-		row = 0;
-		x_offset = 0;
-		matrix_offset = i * matrix_size;
-		for (j = 0; j < matrix_size; j++) {
-			y_offset = j - (row * row_length);
-			rot_index = y_offset * row_length + x_offset;
-			new_value = *(input + i * matrix_size + j);
-			output[matrix_offset + rot_index] = new_value;
-			if ((j + 1) % row_length == 0) {
-				row += 1;
-				x_offset += 1;
-			}
-		}
-	}
-}
-
-static void assemble_scalingfactor0(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input)
-{
-	int offset = 0;
-
-	transpose_and_flatten_matrices(output, (const u8 *)input->scaling_list_4x4, 6, 4);
-	offset = 6 * 16 * sizeof(u8);
-	transpose_and_flatten_matrices(output + offset, (const u8 *)input->scaling_list_8x8, 6, 8);
-	offset += 6 * 64 * sizeof(u8);
-	transpose_and_flatten_matrices(output + offset,
-				       (const u8 *)input->scaling_list_16x16, 6, 8);
-	offset += 6 * 64 * sizeof(u8);
-	/* Add a 128 byte padding with 0s between the two 32x32 matrices */
-	transpose_and_flatten_matrices(output + offset,
-				       (const u8 *)input->scaling_list_32x32, 1, 8);
-	offset += 64 * sizeof(u8);
-	memset(output + offset, 0, 128);
-	offset += 128 * sizeof(u8);
-	transpose_and_flatten_matrices(output + offset,
-				       (const u8 *)input->scaling_list_32x32 + (64 * sizeof(u8)),
-				       1, 8);
-	offset += 64 * sizeof(u8);
-	memset(output + offset, 0, 128);
-}
-
-/*
- * Required layout:
- * A = scaling_list_dc_coef_16x16
- * B = scaling_list_dc_coef_32x32
- * 0 = Padding
- *
- * A, A, A, A, A, A, B, 0, 0, B, 0, 0
- */
-static void assemble_scalingdc(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input)
-{
-	u8 list_32x32[6] = {0};
-
-	memcpy(output, input->scaling_list_dc_coef_16x16, 6 * sizeof(u8));
-	list_32x32[0] = input->scaling_list_dc_coef_32x32[0];
-	list_32x32[3] = input->scaling_list_dc_coef_32x32[1];
-	memcpy(output + 6 * sizeof(u8), list_32x32, 6 * sizeof(u8));
-}
-
-static void translate_scaling_list(struct scaling_factor *output,
-				   const struct v4l2_ctrl_hevc_scaling_matrix *input)
-{
-	assemble_scalingfactor0(output->scalingfactor0, input);
-	memcpy(output->scalingfactor1, (const u8 *)input->scaling_list_4x4, 96);
-	assemble_scalingdc(output->scalingdc, input);
-	memset(output->reserved, 0, 4 * sizeof(u8));
-}
-
-static void assemble_hw_scaling_list(struct rkvdec_ctx *ctx,
-				     struct rkvdec_hevc_run *run)
-{
-	const struct v4l2_ctrl_hevc_scaling_matrix *scaling = run->scaling_matrix;
-	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
-	struct rkvdec_hevc_priv_tbl *tbl = hevc_ctx->priv_tbl.cpu;
-	u8 *dst;
-
-	if (!memcmp((void *)&hevc_ctx->scaling_matrix_cache, scaling,
-		    sizeof(struct v4l2_ctrl_hevc_scaling_matrix)))
-		return;
-
-	dst = tbl->scaling_list;
-	translate_scaling_list((struct scaling_factor *)dst, scaling);
-
-	memcpy((void *)&hevc_ctx->scaling_matrix_cache, scaling,
-	       sizeof(struct v4l2_ctrl_hevc_scaling_matrix));
-}
-
-static struct vb2_buffer *
-get_ref_buf(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run,
-	    unsigned int dpb_idx)
-{
-	struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
-	const struct v4l2_ctrl_hevc_decode_params *decode_params = run->decode_params;
-	const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb;
-	struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q;
-	struct vb2_buffer *buf = NULL;
-
-	if (dpb_idx < decode_params->num_active_dpb_entries)
-		buf = vb2_find_buffer(cap_q, dpb[dpb_idx].timestamp);
-
-	/*
-	 * If a DPB entry is unused or invalid, the address of current destination
-	 * buffer is returned.
-	 */
-	if (!buf)
-		return &run->base.bufs.dst->vb2_buf;
-
-	return buf;
-}
-
 static void config_registers(struct rkvdec_ctx *ctx,
 			     struct rkvdec_hevc_run *run)
 {
@@ -645,43 +501,6 @@ static void config_registers(struct rkvdec_ctx *ctx,
 			   MIN(sizeof(*regs), sizeof(u32) * rkvdec->variant->num_regs));
 }
 
-#define RKVDEC_HEVC_MAX_DEPTH_IN_BYTES		2
-
-static int rkvdec_hevc_adjust_fmt(struct rkvdec_ctx *ctx,
-				  struct v4l2_format *f)
-{
-	struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp;
-
-	fmt->num_planes = 1;
-	if (!fmt->plane_fmt[0].sizeimage)
-		fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height *
-					      RKVDEC_HEVC_MAX_DEPTH_IN_BYTES;
-	return 0;
-}
-
-static enum rkvdec_image_fmt rkvdec_hevc_get_image_fmt(struct rkvdec_ctx *ctx,
-						       struct v4l2_ctrl *ctrl)
-{
-	const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps;
-
-	if (ctrl->id != V4L2_CID_STATELESS_HEVC_SPS)
-		return RKVDEC_IMG_FMT_ANY;
-
-	if (sps->bit_depth_luma_minus8 == 0) {
-		if (sps->chroma_format_idc == 2)
-			return RKVDEC_IMG_FMT_422_8BIT;
-		else
-			return RKVDEC_IMG_FMT_420_8BIT;
-	} else if (sps->bit_depth_luma_minus8 == 2) {
-		if (sps->chroma_format_idc == 2)
-			return RKVDEC_IMG_FMT_422_10BIT;
-		else
-			return RKVDEC_IMG_FMT_420_10BIT;
-	}
-
-	return RKVDEC_IMG_FMT_ANY;
-}
-
 static int rkvdec_hevc_validate_sps(struct rkvdec_ctx *ctx,
 				    const struct v4l2_ctrl_hevc_sps *sps)
 {
@@ -692,7 +511,7 @@ static int rkvdec_hevc_validate_sps(struct rkvdec_ctx *ctx,
 		/* Luma and chroma bit depth mismatch */
 		return -EINVAL;
 	if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2)
-		/* Only 8-bit and 10-bit is supported */
+		/* Only 8-bit and 10-bit are supported */
 		return -EINVAL;
 
 	if (sps->pic_width_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.width ||
@@ -738,40 +557,18 @@ static void rkvdec_hevc_stop(struct rkvdec_ctx *ctx)
 	kfree(hevc_ctx);
 }
 
-static void rkvdec_hevc_run_preamble(struct rkvdec_ctx *ctx,
-				     struct rkvdec_hevc_run *run)
-{
-	struct v4l2_ctrl *ctrl;
-
-	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
-			      V4L2_CID_STATELESS_HEVC_DECODE_PARAMS);
-	run->decode_params = ctrl ? ctrl->p_cur.p : NULL;
-	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
-			      V4L2_CID_STATELESS_HEVC_SLICE_PARAMS);
-	run->slices_params = ctrl ? ctrl->p_cur.p : NULL;
-	run->num_slices = ctrl ? ctrl->new_elems : 0;
-	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
-			      V4L2_CID_STATELESS_HEVC_SPS);
-	run->sps = ctrl ? ctrl->p_cur.p : NULL;
-	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
-			      V4L2_CID_STATELESS_HEVC_PPS);
-	run->pps = ctrl ? ctrl->p_cur.p : NULL;
-	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
-			      V4L2_CID_STATELESS_HEVC_SCALING_MATRIX);
-	run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL;
-
-	rkvdec_run_preamble(ctx, &run->base);
-}
-
 static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
 {
 	struct rkvdec_dev *rkvdec = ctx->dev;
 	struct rkvdec_hevc_run run;
+	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
+	struct rkvdec_hevc_priv_tbl *tbl = hevc_ctx->priv_tbl.cpu;
 	u32 reg;
 
 	rkvdec_hevc_run_preamble(ctx, &run);
 
-	assemble_hw_scaling_list(ctx, &run);
+	rkvdec_hevc_assemble_hw_scaling_list(&run, &tbl->scaling_list,
+					     &hevc_ctx->scaling_matrix_cache);
 	assemble_hw_pps(ctx, &run);
 	assemble_sw_rps(ctx, &run);
 	config_registers(ctx, &run);
-- 
2.52.0



From detlev.casanova at collabora.com  Thu Dec 18 15:28:19 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Thu, 18 Dec 2025 18:28:19 -0500
Subject: [PATCH v7 09/17] media: rkvdec: Add variant specific coded formats list
In-Reply-To: <20251218232829.337811-1-detlev.casanova@collabora.com>
References: <20251218232829.337811-1-detlev.casanova@collabora.com>
Message-ID: <20251218232829.337811-10-detlev.casanova@collabora.com>

Prepare for adding new variants of the decoder and support specific
formats and format ops per variant.

This removes the need of capability flags for variants, so remove them.

Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../media/platform/rockchip/rkvdec/rkvdec.c   | 68 ++++++++++---------
 .../media/platform/rockchip/rkvdec/rkvdec.h   |  8 +--
 2 files changed, 39 insertions(+), 37 deletions(-)

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index 776149f871b09..92b1c7b62bd20 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -328,7 +328,6 @@ static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = {
 		.ops = &rkvdec_hevc_fmt_ops,
 		.num_decoded_fmts = ARRAY_SIZE(rkvdec_hevc_decoded_fmts),
 		.decoded_fmts = rkvdec_hevc_decoded_fmts,
-		.capability = RKVDEC_CAPABILITY_HEVC,
 	},
 	{
 		.fourcc = V4L2_PIX_FMT_H264_SLICE,
@@ -345,7 +344,6 @@ static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = {
 		.num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts),
 		.decoded_fmts = rkvdec_h264_decoded_fmts,
 		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
-		.capability = RKVDEC_CAPABILITY_H264,
 	},
 	{
 		.fourcc = V4L2_PIX_FMT_VP9_FRAME,
@@ -361,27 +359,38 @@ static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = {
 		.ops = &rkvdec_vp9_fmt_ops,
 		.num_decoded_fmts = ARRAY_SIZE(rkvdec_vp9_decoded_fmts),
 		.decoded_fmts = rkvdec_vp9_decoded_fmts,
-		.capability = RKVDEC_CAPABILITY_VP9,
 	}
 };
 
-static bool rkvdec_is_capable(struct rkvdec_ctx *ctx, unsigned int capability)
-{
-	return (ctx->dev->variant->capabilities & capability) == capability;
-}
+static const struct rkvdec_coded_fmt_desc rk3288_coded_fmts[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_HEVC_SLICE,
+		.frmsize = {
+			.min_width = 64,
+			.max_width = 4096,
+			.step_width = 64,
+			.min_height = 64,
+			.max_height = 2304,
+			.step_height = 16,
+		},
+		.ctrls = &rkvdec_hevc_ctrls,
+		.ops = &rkvdec_hevc_fmt_ops,
+		.num_decoded_fmts = ARRAY_SIZE(rkvdec_hevc_decoded_fmts),
+		.decoded_fmts = rkvdec_hevc_decoded_fmts,
+	}
+};
 
 static const struct rkvdec_coded_fmt_desc *
 rkvdec_enum_coded_fmt_desc(struct rkvdec_ctx *ctx, int index)
 {
+	const struct rkvdec_variant *variant = ctx->dev->variant;
 	int fmt_idx = -1;
 	unsigned int i;
 
-	for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++) {
-		if (!rkvdec_is_capable(ctx, rkvdec_coded_fmts[i].capability))
-			continue;
+	for (i = 0; i < variant->num_coded_fmts; i++) {
 		fmt_idx++;
 		if (index == fmt_idx)
-			return &rkvdec_coded_fmts[i];
+			return &variant->coded_fmts[i];
 	}
 
 	return NULL;
@@ -390,12 +399,12 @@ rkvdec_enum_coded_fmt_desc(struct rkvdec_ctx *ctx, int index)
 static const struct rkvdec_coded_fmt_desc *
 rkvdec_find_coded_fmt_desc(struct rkvdec_ctx *ctx, u32 fourcc)
 {
+	const struct rkvdec_variant *variant = ctx->dev->variant;
 	unsigned int i;
 
-	for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++) {
-		if (rkvdec_is_capable(ctx, rkvdec_coded_fmts[i].capability) &&
-		    rkvdec_coded_fmts[i].fourcc == fourcc)
-			return &rkvdec_coded_fmts[i];
+	for (i = 0; i < variant->num_coded_fmts; i++) {
+		if (variant->coded_fmts[i].fourcc == fourcc)
+			return &variant->coded_fmts[i];
 	}
 
 	return NULL;
@@ -1014,21 +1023,19 @@ static int rkvdec_add_ctrls(struct rkvdec_ctx *ctx,
 
 static int rkvdec_init_ctrls(struct rkvdec_ctx *ctx)
 {
+	const struct rkvdec_variant *variant = ctx->dev->variant;
 	unsigned int i, nctrls = 0;
 	int ret;
 
-	for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++)
-		if (rkvdec_is_capable(ctx, rkvdec_coded_fmts[i].capability))
-			nctrls += rkvdec_coded_fmts[i].ctrls->num_ctrls;
+	for (i = 0; i < variant->num_coded_fmts; i++)
+		nctrls += variant->coded_fmts[i].ctrls->num_ctrls;
 
 	v4l2_ctrl_handler_init(&ctx->ctrl_hdl, nctrls);
 
-	for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++) {
-		if (rkvdec_is_capable(ctx, rkvdec_coded_fmts[i].capability)) {
-			ret = rkvdec_add_ctrls(ctx, rkvdec_coded_fmts[i].ctrls);
-			if (ret)
-				goto err_free_handler;
-		}
+	for (i = 0; i < variant->num_coded_fmts; i++) {
+		ret = rkvdec_add_ctrls(ctx, variant->coded_fmts[i].ctrls);
+		if (ret)
+			goto err_free_handler;
 	}
 
 	ret = v4l2_ctrl_handler_setup(&ctx->ctrl_hdl);
@@ -1242,22 +1249,21 @@ static void rkvdec_watchdog_func(struct work_struct *work)
 
 static const struct rkvdec_variant rk3288_rkvdec_variant = {
 	.num_regs = 68,
-	.capabilities = RKVDEC_CAPABILITY_HEVC,
+	.coded_fmts = rk3288_coded_fmts,
+	.num_coded_fmts = ARRAY_SIZE(rk3288_coded_fmts),
 };
 
 static const struct rkvdec_variant rk3328_rkvdec_variant = {
 	.num_regs = 109,
-	.capabilities = RKVDEC_CAPABILITY_HEVC |
-			RKVDEC_CAPABILITY_H264 |
-			RKVDEC_CAPABILITY_VP9,
+	.coded_fmts = rkvdec_coded_fmts,
+	.num_coded_fmts = ARRAY_SIZE(rkvdec_coded_fmts),
 	.quirks = RKVDEC_QUIRK_DISABLE_QOS,
 };
 
 static const struct rkvdec_variant rk3399_rkvdec_variant = {
 	.num_regs = 78,
-	.capabilities = RKVDEC_CAPABILITY_HEVC |
-			RKVDEC_CAPABILITY_H264 |
-			RKVDEC_CAPABILITY_VP9,
+	.coded_fmts = rkvdec_coded_fmts,
+	.num_coded_fmts = ARRAY_SIZE(rkvdec_coded_fmts),
 };
 
 static const struct of_device_id of_rkvdec_match[] = {
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
index f35f6e80ea2e3..8c4f96ba5cdea 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
@@ -22,10 +22,6 @@
 #include <media/videobuf2-core.h>
 #include <media/videobuf2-dma-contig.h>
 
-#define RKVDEC_CAPABILITY_HEVC		BIT(0)
-#define RKVDEC_CAPABILITY_H264		BIT(1)
-#define RKVDEC_CAPABILITY_VP9		BIT(2)
-
 #define RKVDEC_QUIRK_DISABLE_QOS	BIT(0)
 
 struct rkvdec_ctx;
@@ -71,7 +67,8 @@ vb2_to_rkvdec_decoded_buf(struct vb2_buffer *buf)
 
 struct rkvdec_variant {
 	unsigned int num_regs;
-	unsigned int capabilities;
+	const struct rkvdec_coded_fmt_desc *coded_fmts;
+	size_t num_coded_fmts;
 	unsigned int quirks;
 };
 
@@ -110,7 +107,6 @@ struct rkvdec_coded_fmt_desc {
 	unsigned int num_decoded_fmts;
 	const struct rkvdec_decoded_fmt_desc *decoded_fmts;
 	u32 subsystem_flags;
-	unsigned int capability;
 };
 
 struct rkvdec_dev {
-- 
2.52.0



From detlev.casanova at collabora.com  Thu Dec 18 15:28:22 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Thu, 18 Dec 2025 18:28:22 -0500
Subject: [PATCH v7 12/17] media: rkvdec: Enable all clocks without naming them
In-Reply-To: <20251218232829.337811-1-detlev.casanova@collabora.com>
References: <20251218232829.337811-1-detlev.casanova@collabora.com>
Message-ID: <20251218232829.337811-13-detlev.casanova@collabora.com>

For other variants, the clock names and number will differ.

There is no need to keep track of the clock names in the driver so drop
them to avoid having a list for each variant.

Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../media/platform/rockchip/rkvdec/rkvdec.c   | 26 +++++--------------
 .../media/platform/rockchip/rkvdec/rkvdec.h   |  1 +
 2 files changed, 7 insertions(+), 20 deletions(-)

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index 174536ebdcc7c..ce96a0470d4d9 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -1312,15 +1312,10 @@ static const struct of_device_id of_rkvdec_match[] = {
 };
 MODULE_DEVICE_TABLE(of, of_rkvdec_match);
 
-static const char * const rkvdec_clk_names[] = {
-	"axi", "ahb", "cabac", "core"
-};
-
 static int rkvdec_probe(struct platform_device *pdev)
 {
 	const struct rkvdec_variant *variant;
 	struct rkvdec_dev *rkvdec;
-	unsigned int i;
 	int ret, irq;
 
 	variant = of_device_get_match_data(&pdev->dev);
@@ -1337,19 +1332,12 @@ static int rkvdec_probe(struct platform_device *pdev)
 	mutex_init(&rkvdec->vdev_lock);
 	INIT_DELAYED_WORK(&rkvdec->watchdog_work, rkvdec_watchdog_func);
 
-	rkvdec->clocks = devm_kcalloc(&pdev->dev, ARRAY_SIZE(rkvdec_clk_names),
-				      sizeof(*rkvdec->clocks), GFP_KERNEL);
-	if (!rkvdec->clocks)
-		return -ENOMEM;
-
-	for (i = 0; i < ARRAY_SIZE(rkvdec_clk_names); i++)
-		rkvdec->clocks[i].id = rkvdec_clk_names[i];
-
-	ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(rkvdec_clk_names),
-				rkvdec->clocks);
-	if (ret)
+	ret = devm_clk_bulk_get_all_enabled(&pdev->dev, &rkvdec->clocks);
+	if (ret < 0)
 		return ret;
 
+	rkvdec->num_clocks = ret;
+
 	rkvdec->regs = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(rkvdec->regs))
 		return PTR_ERR(rkvdec->regs);
@@ -1427,16 +1415,14 @@ static int rkvdec_runtime_resume(struct device *dev)
 {
 	struct rkvdec_dev *rkvdec = dev_get_drvdata(dev);
 
-	return clk_bulk_prepare_enable(ARRAY_SIZE(rkvdec_clk_names),
-				       rkvdec->clocks);
+	return clk_bulk_prepare_enable(rkvdec->num_clocks, rkvdec->clocks);
 }
 
 static int rkvdec_runtime_suspend(struct device *dev)
 {
 	struct rkvdec_dev *rkvdec = dev_get_drvdata(dev);
 
-	clk_bulk_disable_unprepare(ARRAY_SIZE(rkvdec_clk_names),
-				   rkvdec->clocks);
+	clk_bulk_disable_unprepare(rkvdec->num_clocks, rkvdec->clocks);
 	return 0;
 }
 #endif
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
index faabedd2b9d88..7766a79caf68b 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
@@ -125,6 +125,7 @@ struct rkvdec_dev {
 	struct v4l2_m2m_dev *m2m_dev;
 	struct device *dev;
 	struct clk_bulk_data *clocks;
+	unsigned int num_clocks;
 	void __iomem *regs;
 	struct mutex vdev_lock; /* serializes ioctls */
 	struct delayed_work watchdog_work;
-- 
2.52.0



From detlev.casanova at collabora.com  Thu Dec 18 15:28:23 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Thu, 18 Dec 2025 18:28:23 -0500
Subject: [PATCH v7 13/17] media: rkvdec: Disable multicore support
In-Reply-To: <20251218232829.337811-1-detlev.casanova@collabora.com>
References: <20251218232829.337811-1-detlev.casanova@collabora.com>
Message-ID: <20251218232829.337811-14-detlev.casanova@collabora.com>

Similarly to what is done in Hantro, avoid exposing equal video codecs to
userspace. Equal video codecs allow scheduling work between the cores.
For that kernel support is required, which does not yet exist.
Until that is implemented, avoid exposing each core separately to
userspace so that multicore can be added in the future without breaking
userspace ABI.

This currently applies only to RK3588 which has 2 equal VDPU381 decoders,
but will be applied for all SoC supported by rkvdec that has multiple DTS
nodes with the same compatible.

Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../media/platform/rockchip/rkvdec/rkvdec.c   | 47 +++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index ce96a0470d4d9..af2eced900269 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -1269,6 +1269,49 @@ static void rkvdec_watchdog_func(struct work_struct *work)
 	}
 }
 
+/*
+ * Some SoCs, like RK3588 have multiple identical VDPU cores, but the
+ * kernel is currently missing support for multi-core handling. Exposing
+ * separate devices for each core to userspace is bad, since that does
+ * not allow scheduling tasks properly (and creates ABI). With this workaround
+ * the driver will only probe for the first core and early exit for the other
+ * cores. Once the driver gains multi-core support, the same technique
+ * for detecting the first core can be used to cluster all cores together.
+ */
+static int rkvdec_disable_multicore(struct rkvdec_dev *rkvdec)
+{
+	struct device_node *node = NULL;
+	const char *compatible;
+	bool is_first_core;
+	int ret;
+
+	/* Intentionally ignores the fallback strings */
+	ret = of_property_read_string(rkvdec->dev->of_node, "compatible", &compatible);
+	if (ret)
+		return ret;
+
+	/* The first compatible and available node found is considered the main core */
+	do {
+		node = of_find_compatible_node(node, NULL, compatible);
+		if (of_device_is_available(node))
+			break;
+	} while (node);
+
+	if (!node)
+		return -EINVAL;
+
+	is_first_core = (rkvdec->dev->of_node == node);
+
+	of_node_put(node);
+
+	if (!is_first_core) {
+		dev_info(rkvdec->dev, "missing multi-core support, ignoring this instance\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
 static const struct rkvdec_variant_ops rk3399_variant_ops = {
 	.irq_handler = rk3399_irq_handler,
 };
@@ -1332,6 +1375,10 @@ static int rkvdec_probe(struct platform_device *pdev)
 	mutex_init(&rkvdec->vdev_lock);
 	INIT_DELAYED_WORK(&rkvdec->watchdog_work, rkvdec_watchdog_func);
 
+	ret = rkvdec_disable_multicore(rkvdec);
+	if (ret)
+		return ret;
+
 	ret = devm_clk_bulk_get_all_enabled(&pdev->dev, &rkvdec->clocks);
 	if (ret < 0)
 		return ret;
-- 
2.52.0



From detlev.casanova at collabora.com  Thu Dec 18 15:28:24 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Thu, 18 Dec 2025 18:28:24 -0500
Subject: [PATCH v7 14/17] media: rkvdec: Add H264 support for the VDPU381 variant
In-Reply-To: <20251218232829.337811-1-detlev.casanova@collabora.com>
References: <20251218232829.337811-1-detlev.casanova@collabora.com>
Message-ID: <20251218232829.337811-15-detlev.casanova@collabora.com>

This decoder variant is found in Rockchip RK3588 SoC family.

Like for rkvdec on rk3399, it supports the NV12, NV15, NV16 and NV20
output formats and level up to 5.1.

The maximum width and height have been significantly increased
supporting up to 65520 pixels for both.

Support for named register sections is added for this variant and future
ones.

Fluster score for JVT-AVC_V1 is 129/135.

Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../media/platform/rockchip/rkvdec/Makefile   |   1 +
 .../rockchip/rkvdec/rkvdec-h264-common.h      |   2 +
 .../rockchip/rkvdec/rkvdec-vdpu381-h264.c     | 465 ++++++++++++++++++
 .../rockchip/rkvdec/rkvdec-vdpu381-regs.h     | 424 ++++++++++++++++
 .../media/platform/rockchip/rkvdec/rkvdec.c   |  97 +++-
 .../media/platform/rockchip/rkvdec/rkvdec.h   |  11 +
 6 files changed, 997 insertions(+), 3 deletions(-)
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h

diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
index 3d75103e536d2..7bfd95151e404 100644
--- a/drivers/media/platform/rockchip/rkvdec/Makefile
+++ b/drivers/media/platform/rockchip/rkvdec/Makefile
@@ -8,4 +8,5 @@ rockchip-vdec-y += \
 		   rkvdec-hevc.o \
 		   rkvdec-hevc-common.o \
 		   rkvdec-rcb.o \
+		   rkvdec-vdpu381-h264.o \
 		   rkvdec-vp9.o
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h
index bd0c0081365b1..3be6cea3a7585 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h
@@ -74,6 +74,8 @@ struct rkvdec_rps {
 	u32 reserved1[66];
 } __packed;
 
+extern const s8 rkvdec_h264_cabac_table[4][464][2];
+
 void lookup_ref_buf_idx(struct rkvdec_ctx *ctx, struct rkvdec_h264_run *run);
 void assemble_hw_rps(struct v4l2_h264_reflist_builder *builder,
 		     struct rkvdec_h264_run *run,
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c
new file mode 100644
index 0000000000000..eaa0f7aac08e3
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c
@@ -0,0 +1,465 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip VDPU381 Video Decoder H264 backend
+ *
+ * Copyright (C) 2024 Collabora, Ltd.
+ *  Detlev Casanova <detlev.casanova at collabora.com>
+ */
+
+#include <media/v4l2-h264.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "rkvdec.h"
+#include "rkvdec-rcb.h"
+#include "rkvdec-h264-common.h"
+#include "rkvdec-vdpu381-regs.h"
+
+struct rkvdec_sps {
+	u16 seq_parameter_set_id:			4;
+	u16 profile_idc:				8;
+	u16 constraint_set3_flag:			1;
+	u16 chroma_format_idc:				2;
+	u16 bit_depth_luma:				3;
+	u16 bit_depth_chroma:				3;
+	u16 qpprime_y_zero_transform_bypass_flag:	1;
+	u16 log2_max_frame_num_minus4:			4;
+	u16 max_num_ref_frames:				5;
+	u16 pic_order_cnt_type:				2;
+	u16 log2_max_pic_order_cnt_lsb_minus4:		4;
+	u16 delta_pic_order_always_zero_flag:		1;
+	u16 pic_width_in_mbs:				12;
+	u16 pic_height_in_mbs:				12;
+	u16 frame_mbs_only_flag:			1;
+	u16 mb_adaptive_frame_field_flag:		1;
+	u16 direct_8x8_inference_flag:			1;
+	u16 mvc_extension_enable:			1;
+	u16 num_views:					2;
+
+	u16 reserved_bits:				12;
+	u16 reserved[11];
+} __packed;
+
+struct rkvdec_pps {
+	u16 pic_parameter_set_id:				8;
+	u16 pps_seq_parameter_set_id:				5;
+	u16 entropy_coding_mode_flag:				1;
+	u16 bottom_field_pic_order_in_frame_present_flag:	1;
+	u16 num_ref_idx_l0_default_active_minus1:		5;
+	u16 num_ref_idx_l1_default_active_minus1:		5;
+	u16 weighted_pred_flag:					1;
+	u16 weighted_bipred_idc:				2;
+	u16 pic_init_qp_minus26:				7;
+	u16 pic_init_qs_minus26:				6;
+	u16 chroma_qp_index_offset:				5;
+	u16 deblocking_filter_control_present_flag:		1;
+	u16 constrained_intra_pred_flag:			1;
+	u16 redundant_pic_cnt_present:				1;
+	u16 transform_8x8_mode_flag:				1;
+	u16 second_chroma_qp_index_offset:			5;
+	u16 scaling_list_enable_flag:				1;
+	u32 scaling_list_address;
+	u16 is_longterm;
+
+	u8 reserved[3];
+} __packed;
+
+struct rkvdec_sps_pps {
+	struct rkvdec_sps sps;
+	struct rkvdec_pps pps;
+} __packed;
+
+/* Data structure describing auxiliary buffer format. */
+struct rkvdec_h264_priv_tbl {
+	s8 cabac_table[4][464][2];
+	struct rkvdec_h264_scaling_list scaling_list;
+	struct rkvdec_sps_pps param_set[256];
+	struct rkvdec_rps rps;
+};
+
+struct rkvdec_h264_ctx {
+	struct rkvdec_aux_buf priv_tbl;
+	struct rkvdec_h264_reflists reflists;
+	struct rkvdec_vdpu381_regs_h264 regs;
+};
+
+static void assemble_hw_pps(struct rkvdec_ctx *ctx,
+			    struct rkvdec_h264_run *run)
+{
+	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
+	const struct v4l2_ctrl_h264_sps *sps = run->sps;
+	const struct v4l2_ctrl_h264_pps *pps = run->pps;
+	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
+	const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb;
+	struct rkvdec_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu;
+	struct rkvdec_sps_pps *hw_ps;
+	dma_addr_t scaling_list_address;
+	u32 scaling_distance;
+	u32 i;
+
+	/*
+	 * HW read the SPS/PPS information from PPS packet index by PPS id.
+	 * offset from the base can be calculated by PPS_id * 32 (size per PPS
+	 * packet unit). so the driver copy SPS/PPS information to the exact PPS
+	 * packet unit for HW accessing.
+	 */
+	hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id];
+	memset(hw_ps, 0, sizeof(*hw_ps));
+
+	/* write sps */
+	hw_ps->sps.seq_parameter_set_id = sps->seq_parameter_set_id;
+	hw_ps->sps.profile_idc = sps->profile_idc;
+	hw_ps->sps.constraint_set3_flag = !!(sps->constraint_set_flags & (1 << 3));
+	hw_ps->sps.chroma_format_idc = sps->chroma_format_idc;
+	hw_ps->sps.bit_depth_luma = sps->bit_depth_luma_minus8;
+	hw_ps->sps.bit_depth_chroma = sps->bit_depth_chroma_minus8;
+	hw_ps->sps.qpprime_y_zero_transform_bypass_flag =
+		!!(sps->flags & V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS);
+	hw_ps->sps.log2_max_frame_num_minus4 = sps->log2_max_frame_num_minus4;
+	hw_ps->sps.max_num_ref_frames = sps->max_num_ref_frames;
+	hw_ps->sps.pic_order_cnt_type = sps->pic_order_cnt_type;
+	hw_ps->sps.log2_max_pic_order_cnt_lsb_minus4 =
+		sps->log2_max_pic_order_cnt_lsb_minus4;
+	hw_ps->sps.delta_pic_order_always_zero_flag =
+		!!(sps->flags & V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO);
+	hw_ps->sps.mvc_extension_enable = 1;
+	hw_ps->sps.num_views = 1;
+
+	/*
+	 * Use the SPS values since they are already in macroblocks
+	 * dimensions, height can be field height (halved) if
+	 * V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY is not set and also it allows
+	 * decoding smaller images into larger allocation which can be used
+	 * to implementing SVC spatial layer support.
+	 */
+	hw_ps->sps.pic_width_in_mbs = sps->pic_width_in_mbs_minus1 + 1;
+	hw_ps->sps.pic_height_in_mbs = sps->pic_height_in_map_units_minus1 + 1;
+	hw_ps->sps.frame_mbs_only_flag =
+		!!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY);
+	hw_ps->sps.mb_adaptive_frame_field_flag =
+		!!(sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD);
+	hw_ps->sps.direct_8x8_inference_flag =
+		!!(sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE);
+
+	/* write pps */
+	hw_ps->pps.pic_parameter_set_id = pps->pic_parameter_set_id;
+	hw_ps->pps.pps_seq_parameter_set_id = pps->seq_parameter_set_id;
+	hw_ps->pps.entropy_coding_mode_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE);
+	hw_ps->pps.bottom_field_pic_order_in_frame_present_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT);
+	hw_ps->pps.num_ref_idx_l0_default_active_minus1 =
+		pps->num_ref_idx_l0_default_active_minus1;
+	hw_ps->pps.num_ref_idx_l1_default_active_minus1 =
+		pps->num_ref_idx_l1_default_active_minus1;
+	hw_ps->pps.weighted_pred_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED);
+	hw_ps->pps.weighted_bipred_idc = pps->weighted_bipred_idc;
+	hw_ps->pps.pic_init_qp_minus26 = pps->pic_init_qp_minus26;
+	hw_ps->pps.pic_init_qs_minus26 = pps->pic_init_qs_minus26;
+	hw_ps->pps.chroma_qp_index_offset = pps->chroma_qp_index_offset;
+	hw_ps->pps.deblocking_filter_control_present_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT);
+	hw_ps->pps.constrained_intra_pred_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED);
+	hw_ps->pps.redundant_pic_cnt_present =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT);
+	hw_ps->pps.transform_8x8_mode_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE);
+	hw_ps->pps.second_chroma_qp_index_offset = pps->second_chroma_qp_index_offset;
+	hw_ps->pps.scaling_list_enable_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT);
+
+	/*
+	 * To be on the safe side, program the scaling matrix address
+	 */
+	scaling_distance = offsetof(struct rkvdec_h264_priv_tbl, scaling_list);
+	scaling_list_address = h264_ctx->priv_tbl.dma + scaling_distance;
+	hw_ps->pps.scaling_list_address = scaling_list_address;
+
+	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
+		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
+			hw_ps->pps.is_longterm |= (1 << i);
+	}
+}
+
+static void rkvdec_write_regs(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
+
+	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_REGS,
+			   &h264_ctx->regs.common,
+			   sizeof(h264_ctx->regs.common));
+	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_PARAMS_REGS,
+			   &h264_ctx->regs.h264_param,
+			   sizeof(h264_ctx->regs.h264_param));
+	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_ADDR_REGS,
+			   &h264_ctx->regs.common_addr,
+			   sizeof(h264_ctx->regs.common_addr));
+	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_ADDR_REGS,
+			   &h264_ctx->regs.h264_addr,
+			   sizeof(h264_ctx->regs.h264_addr));
+	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_POC_HIGHBIT_REGS,
+			   &h264_ctx->regs.h264_highpoc,
+			   sizeof(h264_ctx->regs.h264_highpoc));
+}
+
+static void config_registers(struct rkvdec_ctx *ctx,
+			     struct rkvdec_h264_run *run)
+{
+	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
+	const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb;
+	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
+	dma_addr_t priv_start_addr = h264_ctx->priv_tbl.dma;
+	const struct v4l2_pix_format_mplane *dst_fmt;
+	struct vb2_v4l2_buffer *src_buf = run->base.bufs.src;
+	struct vb2_v4l2_buffer *dst_buf = run->base.bufs.dst;
+	struct rkvdec_vdpu381_regs_h264 *regs = &h264_ctx->regs;
+	const struct v4l2_format *f;
+	dma_addr_t rlc_addr;
+	dma_addr_t dst_addr;
+	u32 hor_virstride;
+	u32 ver_virstride;
+	u32 y_virstride;
+	u32 offset;
+	u32 pixels;
+	u32 i;
+
+	memset(regs, 0, sizeof(*regs));
+
+	/* Set H264 mode */
+	regs->common.reg009.dec_mode = VDPU381_MODE_H264;
+
+	/* Set config */
+	regs->common.reg011.buf_empty_en = 1;
+	regs->common.reg011.dec_clkgate_e = 1;
+	regs->common.reg011.dec_timeout_e = 1;
+	regs->common.reg011.pix_range_detection_e = 1;
+
+	/*
+	 * Even though the scan list address can be set in RPS,
+	 * with some frames, it will try to use the address set in the register.
+	 */
+	regs->common.reg012.scanlist_addr_valid_en = 1;
+
+	/* Set IDR flag */
+	regs->common.reg013.cur_pic_is_idr =
+		!!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC);
+
+	/* Set input stream length */
+	regs->common.stream_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
+
+	/* Set max slice number */
+	regs->common.reg017.slice_num = MAX_SLICE_NUMBER;
+
+	/* Set strides */
+	f = &ctx->decoded_fmt;
+	dst_fmt = &f->fmt.pix_mp;
+	hor_virstride = dst_fmt->plane_fmt[0].bytesperline;
+	ver_virstride = dst_fmt->height;
+	y_virstride = hor_virstride * ver_virstride;
+
+	pixels = dst_fmt->height * dst_fmt->width;
+
+	regs->common.reg018.y_hor_virstride = hor_virstride / 16;
+	regs->common.reg019.uv_hor_virstride = hor_virstride / 16;
+	regs->common.reg020.y_virstride = y_virstride / 16;
+
+	/* Activate block gating */
+	regs->common.reg026.swreg_block_gating_e = 0xfffef;
+	regs->common.reg026.reg_cfg_gating_en = 1;
+
+	/* Set timeout threshold */
+	if (pixels < RKVDEC_1080P_PIXELS)
+		regs->common.timeout_threshold = RKVDEC_TIMEOUT_1080p;
+	else if (pixels < RKVDEC_4K_PIXELS)
+		regs->common.timeout_threshold = RKVDEC_TIMEOUT_4K;
+	else if (pixels < RKVDEC_8K_PIXELS)
+		regs->common.timeout_threshold = RKVDEC_TIMEOUT_8K;
+	else
+		regs->common.timeout_threshold = RKVDEC_TIMEOUT_MAX;
+
+	/* Set TOP and BOTTOM POCs */
+	regs->h264_param.cur_top_poc = dec_params->top_field_order_cnt;
+	regs->h264_param.cur_bot_poc = dec_params->bottom_field_order_cnt;
+
+	/* Set ref pic address & poc */
+	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
+		struct vb2_buffer *vb_buf = run->ref_buf[i];
+		dma_addr_t buf_dma;
+
+		/*
+		 * If a DPB entry is unused or invalid, address of current destination
+		 * buffer is returned.
+		 */
+		if (!vb_buf)
+			vb_buf = &dst_buf->vb2_buf;
+
+		buf_dma = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
+
+		/* Set reference addresses */
+		regs->h264_addr.ref_base[i] = buf_dma;
+
+		/* Set COLMV addresses */
+		regs->h264_addr.colmv_base[i] = buf_dma + ctx->colmv_offset;
+
+		struct rkvdec_vdpu381_h264_ref_info *ref_info =
+			&regs->h264_param.ref_info_regs[i / 4].ref_info[i % 4];
+
+		ref_info->ref_field =
+			!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD);
+		ref_info->ref_colmv_use_flag =
+			!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE);
+		ref_info->ref_topfield_used =
+			!!(dpb[i].fields & V4L2_H264_TOP_FIELD_REF);
+		ref_info->ref_botfield_used =
+			!!(dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF);
+
+		regs->h264_param.ref_pocs[i * 2] =
+			dpb[i].top_field_order_cnt;
+		regs->h264_param.ref_pocs[i * 2 + 1] =
+			dpb[i].bottom_field_order_cnt;
+	}
+
+	/* Set rlc base address (input stream) */
+	rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+	regs->common_addr.rlc_base = rlc_addr;
+	regs->common_addr.rlcwrite_base = rlc_addr;
+
+	/* Set output base address */
+	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
+	regs->common_addr.decout_base = dst_addr;
+	regs->common_addr.error_ref_base = dst_addr;
+
+	/* Set colmv address */
+	regs->common_addr.colmv_cur_base = dst_addr + ctx->colmv_offset;
+
+	/* Set RCB addresses */
+	for (i = 0; i < rkvdec_rcb_buf_count(ctx); i++)
+		regs->common_addr.rcb_base[i] = rkvdec_rcb_buf_dma_addr(ctx, i);
+
+	/* Set hw pps address */
+	offset = offsetof(struct rkvdec_h264_priv_tbl, param_set);
+	regs->h264_addr.pps_base = priv_start_addr + offset;
+
+	/* Set hw rps address */
+	offset = offsetof(struct rkvdec_h264_priv_tbl, rps);
+	regs->h264_addr.rps_base = priv_start_addr + offset;
+
+	/* Set cabac table */
+	offset = offsetof(struct rkvdec_h264_priv_tbl, cabac_table);
+	regs->h264_addr.cabactbl_base = priv_start_addr + offset;
+
+	offset = offsetof(struct rkvdec_h264_priv_tbl, scaling_list);
+	regs->h264_addr.scanlist_addr = priv_start_addr + offset;
+
+	rkvdec_write_regs(ctx);
+}
+
+static int rkvdec_h264_start(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_h264_priv_tbl *priv_tbl;
+	struct rkvdec_h264_ctx *h264_ctx;
+	struct v4l2_ctrl *ctrl;
+	int ret;
+
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_H264_SPS);
+	if (!ctrl)
+		return -EINVAL;
+
+	h264_ctx = kzalloc(sizeof(*h264_ctx), GFP_KERNEL);
+	if (!h264_ctx)
+		return -ENOMEM;
+
+	priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl),
+				      &h264_ctx->priv_tbl.dma, GFP_KERNEL);
+	if (!priv_tbl) {
+		ret = -ENOMEM;
+		goto err_free_ctx;
+	}
+
+	h264_ctx->priv_tbl.size = sizeof(*priv_tbl);
+	h264_ctx->priv_tbl.cpu = priv_tbl;
+	memcpy(priv_tbl->cabac_table, rkvdec_h264_cabac_table,
+	       sizeof(rkvdec_h264_cabac_table));
+
+	ctx->priv = h264_ctx;
+	return 0;
+
+err_free_ctx:
+	kfree(h264_ctx);
+	return ret;
+}
+
+static void rkvdec_h264_stop(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
+	struct rkvdec_dev *rkvdec = ctx->dev;
+
+	dma_free_coherent(rkvdec->dev, h264_ctx->priv_tbl.size,
+			  h264_ctx->priv_tbl.cpu, h264_ctx->priv_tbl.dma);
+	kfree(h264_ctx);
+}
+
+static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
+{
+	struct v4l2_h264_reflist_builder reflist_builder;
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
+	struct rkvdec_h264_priv_tbl *tbl = h264_ctx->priv_tbl.cpu;
+	struct rkvdec_h264_run run;
+	u32 watchdog_time;
+
+	rkvdec_h264_run_preamble(ctx, &run);
+
+	/* Build the P/B{0,1} ref lists. */
+	v4l2_h264_init_reflist_builder(&reflist_builder, run.decode_params,
+				       run.sps, run.decode_params->dpb);
+	v4l2_h264_build_p_ref_list(&reflist_builder, h264_ctx->reflists.p);
+	v4l2_h264_build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0,
+				    h264_ctx->reflists.b1);
+
+	assemble_hw_scaling_list(&run, &tbl->scaling_list);
+	assemble_hw_pps(ctx, &run);
+	lookup_ref_buf_idx(ctx, &run);
+	assemble_hw_rps(&reflist_builder, &run, &h264_ctx->reflists, &tbl->rps);
+
+	config_registers(ctx, &run);
+
+	rkvdec_run_postamble(ctx, &run.base);
+
+	/* Set watchdog at 2 times the hardware timeout threshold */
+	u64 timeout_threshold = h264_ctx->regs.common.timeout_threshold;
+	unsigned long axi_rate = clk_get_rate(rkvdec->axi_clk);
+
+	if (axi_rate)
+		watchdog_time = 2 * (1000 * timeout_threshold) / axi_rate;
+	else
+		watchdog_time = 2000;
+	schedule_delayed_work(&rkvdec->watchdog_work,
+			      msecs_to_jiffies(watchdog_time));
+
+	/* Start decoding! */
+	writel(VDPU381_DEC_E_BIT, rkvdec->regs + VDPU381_REG_DEC_E);
+
+	return 0;
+}
+
+static int rkvdec_h264_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
+{
+	if (ctrl->id == V4L2_CID_STATELESS_H264_SPS)
+		return rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps);
+
+	return 0;
+}
+
+const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_h264_fmt_ops = {
+	.adjust_fmt = rkvdec_h264_adjust_fmt,
+	.get_image_fmt = rkvdec_h264_get_image_fmt,
+	.start = rkvdec_h264_start,
+	.stop = rkvdec_h264_stop,
+	.run = rkvdec_h264_run,
+	.try_ctrl = rkvdec_h264_try_ctrl,
+};
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h
new file mode 100644
index 0000000000000..a9a2daa24048b
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h
@@ -0,0 +1,424 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Rockchip VDPU381 Video Decoder driver registers description
+ *
+ * Copyright (C) 2024 Collabora, Ltd.
+ *  Detlev Casanova <detlev.casanova at collabora.com>
+ */
+
+#include <linux/types.h>
+
+#ifndef _RKVDEC_REGS_H_
+#define _RKVDEC_REGS_H_
+
+#define OFFSET_COMMON_REGS		(8 * sizeof(u32))
+#define OFFSET_CODEC_PARAMS_REGS	(64 * sizeof(u32))
+#define OFFSET_COMMON_ADDR_REGS		(128 * sizeof(u32))
+#define OFFSET_CODEC_ADDR_REGS		(160 * sizeof(u32))
+#define OFFSET_POC_HIGHBIT_REGS		(200 * sizeof(u32))
+
+#define VDPU381_MODE_HEVC	0
+#define VDPU381_MODE_H264	1
+#define VDPU381_MODE_VP9	2
+#define VDPU381_MODE_AVS2	3
+
+#define MAX_SLICE_NUMBER	0x3fff
+
+#define RKVDEC_TIMEOUT_1080p		(0xefffff)
+#define RKVDEC_TIMEOUT_4K		(0x2cfffff)
+#define RKVDEC_TIMEOUT_8K		(0x4ffffff)
+#define RKVDEC_TIMEOUT_MAX		(0xffffffff)
+
+#define VDPU381_REG_DEC_E		0x028
+#define VDPU381_DEC_E_BIT		1
+
+#define VDPU381_REG_IMPORTANT_EN	0x02c
+#define VDPU381_DEC_IRQ_DISABLE	BIT(4)
+
+#define VDPU381_REG_STA_INT		0x380
+#define VDPU381_STA_INT_DEC_RDY_STA	BIT(2)
+#define VDPU381_STA_INT_ERROR		BIT(4)
+#define VDPU381_STA_INT_TIMEOUT		BIT(5)
+#define VDPU381_STA_INT_SOFTRESET_RDY	BIT(9)
+
+/* base: OFFSET_COMMON_REGS */
+struct rkvdec_vdpu381_regs_common {
+	struct rkvdec_vdpu381_in_out {
+		u32 in_endian		: 1;
+		u32 in_swap32_e		: 1;
+		u32 in_swap64_e		: 1;
+		u32 str_endian		: 1;
+		u32 str_swap32_e	: 1;
+		u32 str_swap64_e	: 1;
+		u32 out_endian		: 1;
+		u32 out_swap32_e	: 1;
+		u32 out_cbcr_swap	: 1;
+		u32 out_swap64_e	: 1;
+		u32 reserved		: 22;
+	} reg008;
+
+	struct rkvdec_vdpu381_dec_mode {
+		u32 dec_mode	: 10;
+		u32 reserved	: 22;
+	} reg009;
+
+	struct rkvdec_vdpu381_dec_e {
+		u32 dec_e	: 1;
+		u32 reserved	: 31;
+	} reg010;
+
+	struct rkvdec_vdpu381_important_en {
+		u32 reserved			: 1;
+		u32 dec_clkgate_e		: 1;
+		u32 dec_e_strmd_clkgate_dis	: 1;
+		u32 reserved0			: 1;
+
+		u32 dec_irq_dis			: 1;
+		u32 dec_timeout_e		: 1;
+		u32 buf_empty_en		: 1;
+		u32 reserved1			: 3;
+
+		u32 dec_e_rewrite_valid		: 1;
+		u32 reserved2			: 9;
+		u32 softrst_en_p		: 1;
+		u32 force_softreset_valid	: 1;
+		u32 reserved3			: 2;
+		u32 pix_range_detection_e	: 1;
+		u32 reserved4			: 7;
+	} reg011;
+
+	struct rkvdec_vdpu381_secondary_en {
+		u32 wr_ddr_align_en		: 1;
+		u32 colmv_compress_en		: 1;
+		u32 fbc_e			: 1;
+		u32 reserved0			: 1;
+
+		u32 buspr_slot_disable		: 1;
+		u32 error_info_en		: 1;
+		u32 info_collect_en		: 1;
+		u32 wait_reset_en		: 1;
+
+		u32 scanlist_addr_valid_en	: 1;
+		u32 scale_down_en		: 1;
+		u32 error_cfg_wr_disable	: 1;
+		u32 reserved1			: 21;
+	} reg012;
+
+	struct rkvdec_vdpu381_en_mode_set {
+		u32 timeout_mode		: 1;
+		u32 req_timeout_rst_sel		: 1;
+		u32 reserved0			: 1;
+		u32 dec_commonirq_mode		: 1;
+		u32 reserved1			: 2;
+		u32 stmerror_waitdecfifo_empty	: 1;
+		u32 reserved2			: 2;
+		u32 h26x_streamd_error_mode	: 1;
+		u32 reserved3			: 2;
+		u32 allow_not_wr_unref_bframe	: 1;
+		u32 fbc_output_wr_disable	: 1;
+		u32 reserved4			: 1;
+		u32 colmv_error_mode		: 1;
+
+		u32 reserved5			: 2;
+		u32 h26x_error_mode		: 1;
+		u32 reserved6			: 2;
+		u32 ycacherd_prior		: 1;
+		u32 reserved7			: 2;
+		u32 cur_pic_is_idr		: 1;
+		u32 reserved8			: 1;
+		u32 right_auto_rst_disable	: 1;
+		u32 frame_end_err_rst_flag	: 1;
+		u32 rd_prior_mode		: 1;
+		u32 rd_ctrl_prior_mode		: 1;
+		u32 reserved9			: 1;
+		u32 filter_outbuf_mode		: 1;
+	} reg013;
+
+	struct rkvdec_vdpu381_fbc_param_set {
+		u32 fbc_force_uncompress	: 1;
+
+		u32 reserved0			: 2;
+		u32 allow_16x8_cp_flag		: 1;
+		u32 reserved1			: 2;
+
+		u32 fbc_h264_exten_4or8_flag	: 1;
+		u32 reserved2			: 25;
+	} reg014;
+
+	struct rkvdec_vdpu381_stream_param_set {
+		u32 rlc_mode_direct_write	: 1;
+		u32 rlc_mode			: 1;
+		u32 reserved0			: 3;
+
+		u32 strm_start_bit		: 7;
+		u32 reserved1			: 20;
+	} reg015;
+
+	u32 stream_len;
+
+	struct rkvdec_vdpu381_slice_number {
+		u32 slice_num	: 25;
+		u32 reserved	: 7;
+	} reg017;
+
+	struct rkvdec_vdpu381_y_hor_stride {
+		u32 y_hor_virstride	: 16;
+		u32 reserved		: 16;
+	} reg018;
+
+	struct rkvdec_vdpu381_uv_hor_stride {
+		u32 uv_hor_virstride	: 16;
+		u32 reserved		: 16;
+	} reg019;
+
+	struct rkvdec_vdpu381_y_stride {
+		u32 y_virstride		: 28;
+		u32 reserved		: 4;
+	} reg020;
+
+	struct rkvdec_vdpu381_error_ctrl_set {
+		u32 inter_error_prc_mode		: 1;
+		u32 error_intra_mode			: 1;
+		u32 error_deb_en			: 1;
+		u32 picidx_replace			: 5;
+		u32 error_spread_e			: 1;
+		u32 reserved0				: 3;
+		u32 error_inter_pred_cross_slice	: 1;
+		u32 reserved1				: 11;
+		u32 roi_error_ctu_cal_en		: 1;
+		u32 reserved2				: 7;
+	} reg021;
+
+	struct rkvdec_vdpu381_err_roi_ctu_offset_start {
+		u32 roi_x_ctu_offset_st	: 12;
+		u32 reserved0		: 4;
+		u32 roi_y_ctu_offset_st	: 12;
+		u32 reserved1		: 4;
+	} reg022;
+
+	struct rkvdec_vdpu381_err_roi_ctu_offset_end {
+		u32 roi_x_ctu_offset_end	: 12;
+		u32 reserved0			: 4;
+		u32 roi_y_ctu_offset_end	: 12;
+		u32 reserved1			: 4;
+	} reg023;
+
+	struct rkvdec_vdpu381_cabac_error_en_lowbits {
+		u32 cabac_err_en_lowbits	: 32;
+	} reg024;
+
+	struct rkvdec_vdpu381_cabac_error_en_highbits {
+		u32 cabac_err_en_highbits	: 30;
+		u32 reserved			: 2;
+	} reg025;
+
+	struct rkvdec_vdpu381_block_gating_en {
+		u32 swreg_block_gating_e	: 20;
+		u32 reserved			: 11;
+		u32 reg_cfg_gating_en		: 1;
+	} reg026;
+
+	struct SW027_CORE_SAFE_PIXELS {
+		u32 core_safe_x_pixels	: 16;
+		u32 core_safe_y_pixels	: 16;
+	} reg027;
+
+	struct rkvdec_vdpu381_multiply_core_ctrl {
+		u32 swreg_vp9_wr_prob_idx	: 3;
+		u32 reserved0			: 1;
+		u32 swreg_vp9_rd_prob_idx	: 3;
+		u32 reserved1			: 1;
+
+		u32 swreg_ref_req_advance_flag	: 1;
+		u32 sw_colmv_req_advance_flag	: 1;
+		u32 sw_poc_only_highbit_flag	: 1;
+		u32 sw_poc_arb_flag		: 1;
+
+		u32 reserved2			: 4;
+		u32 sw_film_idx			: 10;
+		u32 reserved3			: 2;
+		u32 sw_pu_req_mismatch_dis	: 1;
+		u32 sw_colmv_req_mismatch_dis	: 1;
+		u32 reserved4			: 2;
+	} reg028;
+
+	struct SW029_SCALE_DOWN_CTRL {
+		u32 scale_down_hor_ratio	: 2;
+		u32 reserved0			: 6;
+		u32 scale_down_vrz_ratio	: 2;
+		u32 reserved1			: 22;
+	} reg029;
+
+	struct SW032_Y_SCALE_DOWN_TILE8x8_HOR_STRIDE {
+		u32 y_scale_down_hor_stride	: 20;
+		u32 reserved0			: 12;
+	} reg030;
+
+	struct SW031_UV_SCALE_DOWN_TILE8x8_HOR_STRIDE {
+		u32 uv_scale_down_hor_stride	: 20;
+		u32 reserved0			: 12;
+	} reg031;
+
+	u32 timeout_threshold;
+} __packed;
+
+/* base: OFFSET_COMMON_ADDR_REGS */
+struct rkvdec_vdpu381_regs_common_addr {
+	u32 rlc_base;
+	u32 rlcwrite_base;
+	u32 decout_base;
+	u32 colmv_cur_base;
+	u32 error_ref_base;
+	u32 rcb_base[10];
+} __packed;
+
+struct rkvdec_vdpu381_h26x_set {
+	u32 h26x_frame_orslice		: 1;
+	u32 h26x_rps_mode		: 1;
+	u32 h26x_stream_mode		: 1;
+	u32 h26x_stream_lastpacket	: 1;
+	u32 h264_firstslice_flag	: 1;
+	u32 reserved			: 27;
+} __packed;
+
+/* base: OFFSET_CODEC_PARAMS_REGS */
+struct rkvdec_vdpu381_regs_h264_params {
+	struct rkvdec_vdpu381_h26x_set reg064;
+
+	u32 cur_top_poc;
+	u32 cur_bot_poc;
+	u32 ref_pocs[32];
+
+	struct rkvdec_vdpu381_h264_info {
+		struct rkvdec_vdpu381_h264_ref_info {
+			u32 ref_field		: 1;
+			u32 ref_topfield_used	: 1;
+			u32 ref_botfield_used	: 1;
+			u32 ref_colmv_use_flag	: 1;
+			u32 ref_reserved	: 4;
+		} __packed ref_info[4];
+	} __packed ref_info_regs[4];
+
+	u32 reserved_103_111[9];
+
+	struct rkvdec_vdpu381_error_ref_info {
+		u32 avs2_ref_error_field	: 1;
+		u32 avs2_ref_error_topfield	: 1;
+		u32 ref_error_topfield_used	: 1;
+		u32 ref_error_botfield_used	: 1;
+		u32 reserved			: 28;
+	} reg112;
+} __packed;
+
+struct rkvdec_vdpu381_regs_hevc_params {
+	struct rkvdec_vdpu381_h26x_set reg064;
+
+	u32 cur_top_poc;
+	u32 cur_bot_poc;
+
+	u32 reg067_082_ref_poc[16];
+
+	u32 reserved_083_098[16];
+
+	struct rkvdec_vdpu381_hevc_ref_valid {
+		u32 hevc_ref_valid_0    : 1;
+		u32 hevc_ref_valid_1    : 1;
+		u32 hevc_ref_valid_2    : 1;
+		u32 hevc_ref_valid_3    : 1;
+		u32 reserve0            : 4;
+		u32 hevc_ref_valid_4    : 1;
+		u32 hevc_ref_valid_5    : 1;
+		u32 hevc_ref_valid_6    : 1;
+		u32 hevc_ref_valid_7    : 1;
+		u32 reserve1            : 4;
+		u32 hevc_ref_valid_8    : 1;
+		u32 hevc_ref_valid_9    : 1;
+		u32 hevc_ref_valid_10   : 1;
+		u32 hevc_ref_valid_11   : 1;
+		u32 reserve2            : 4;
+		u32 hevc_ref_valid_12   : 1;
+		u32 hevc_ref_valid_13   : 1;
+		u32 hevc_ref_valid_14   : 1;
+		u32 reserve3            : 5;
+	} reg099;
+
+	u32 reserved_100_102[3];
+
+	struct rkvdec_vdpu381_hevc_mvc0 {
+		u32 ref_pic_layer_same_with_cur : 16;
+		u32 reserve                     : 16;
+	} reg103;
+
+	struct rkvdec_vdpu381_hevc_mvc1 {
+		u32 poc_lsb_not_present_flag        : 1;
+		u32 num_direct_ref_layers           : 6;
+		u32 reserve0                        : 1;
+
+		u32 num_reflayer_pics               : 6;
+		u32 default_ref_layers_active_flag  : 1;
+		u32 max_one_active_ref_layer_flag   : 1;
+
+		u32 poc_reset_info_present_flag     : 1;
+		u32 vps_poc_lsb_aligned_flag        : 1;
+		u32 mvc_poc15_valid_flag            : 1;
+		u32 reserve1                        : 13;
+	} reg104;
+
+	u32 reserved_105_111[7];
+
+	struct rkvdec_vdpu381_hevc_ref_info {
+		u32 avs2_ref_error_field        : 1;
+		u32 avs2_ref_error_topfield     : 1;
+		u32 ref_error_topfield_used     : 1;
+		u32 ref_error_botfield_used     : 1;
+		u32 reserve                     : 28;
+	} reg112;
+
+} __packed;
+
+/* base: OFFSET_CODEC_ADDR_REGS */
+struct rkvdec_vdpu381_regs_h26x_addr {
+	u32 reserved_160;
+	u32 pps_base;
+	u32 reserved_162;
+	u32 rps_base;
+	u32 ref_base[16];
+	u32 scanlist_addr;
+	u32 colmv_base[16];
+	u32 cabactbl_base;
+} __packed;
+
+struct rkvdec_vdpu381_regs_h26x_highpoc {
+	struct rkvdec_vdpu381_ref_poc_highbit {
+		u32 ref0_poc_highbit	: 4;
+		u32 ref1_poc_highbit	: 4;
+		u32 ref2_poc_highbit	: 4;
+		u32 ref3_poc_highbit	: 4;
+		u32 ref4_poc_highbit	: 4;
+		u32 ref5_poc_highbit	: 4;
+		u32 ref6_poc_highbit	: 4;
+		u32 ref7_poc_highbit	: 4;
+	} reg200[4];
+	struct rkvdec_vdpu381_cur_poc_highbit {
+		u32 cur_poc_highbit	: 4;
+		u32 reserved		: 28;
+	} reg204;
+} __packed;
+
+struct rkvdec_vdpu381_regs_h264 {
+	struct rkvdec_vdpu381_regs_common		common;
+	struct rkvdec_vdpu381_regs_h264_params		h264_param;
+	struct rkvdec_vdpu381_regs_common_addr		common_addr;
+	struct rkvdec_vdpu381_regs_h26x_addr		h264_addr;
+	struct rkvdec_vdpu381_regs_h26x_highpoc		h264_highpoc;
+} __packed;
+
+struct rkvdec_vdpu381_regs_hevc {
+	struct rkvdec_vdpu381_regs_common		common;
+	struct rkvdec_vdpu381_regs_hevc_params		hevc_param;
+	struct rkvdec_vdpu381_regs_common_addr		common_addr;
+	struct rkvdec_vdpu381_regs_h26x_addr		hevc_addr;
+	struct rkvdec_vdpu381_regs_h26x_highpoc		hevc_highpoc;
+} __packed;
+
+#endif /* __RKVDEC_REGS_H__ */
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index af2eced900269..3d243b6e11445 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -29,6 +29,7 @@
 
 #include "rkvdec.h"
 #include "rkvdec-regs.h"
+#include "rkvdec-vdpu381-regs.h"
 #include "rkvdec-rcb.h"
 
 static bool rkvdec_image_fmt_match(enum rkvdec_image_fmt fmt1,
@@ -90,6 +91,9 @@ static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx,
 {
 	v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat,
 			    pix_mp->width, pix_mp->height);
+
+	ctx->colmv_offset = pix_mp->plane_fmt[0].sizeimage;
+
 	pix_mp->plane_fmt[0].sizeimage += 128 *
 		DIV_ROUND_UP(pix_mp->width, 16) *
 		DIV_ROUND_UP(pix_mp->height, 16);
@@ -382,6 +386,25 @@ static const struct rkvdec_coded_fmt_desc rk3288_coded_fmts[] = {
 	}
 };
 
+static const struct rkvdec_coded_fmt_desc vdpu381_coded_fmts[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_H264_SLICE,
+		.frmsize = {
+			.min_width = 64,
+			.max_width =  65520,
+			.step_width = 64,
+			.min_height = 64,
+			.max_height =  65520,
+			.step_height = 16,
+		},
+		.ctrls = &rkvdec_h264_ctrls,
+		.ops = &rkvdec_vdpu381_h264_fmt_ops,
+		.num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts),
+		.decoded_fmts = rkvdec_h264_decoded_fmts,
+		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
+	},
+};
+
 static const struct rkvdec_coded_fmt_desc *
 rkvdec_enum_coded_fmt_desc(struct rkvdec_ctx *ctx, int index)
 {
@@ -1245,6 +1268,35 @@ static irqreturn_t rk3399_irq_handler(struct rkvdec_ctx *ctx)
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t vdpu381_irq_handler(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	enum vb2_buffer_state state;
+	bool need_reset = 0;
+	u32 status;
+
+	status = readl(rkvdec->regs + VDPU381_REG_STA_INT);
+	writel(0, rkvdec->regs + VDPU381_REG_STA_INT);
+
+	if (status & VDPU381_STA_INT_DEC_RDY_STA) {
+		state = VB2_BUF_STATE_DONE;
+	} else {
+		state = VB2_BUF_STATE_ERROR;
+		if (status & (VDPU381_STA_INT_SOFTRESET_RDY |
+			      VDPU381_STA_INT_TIMEOUT |
+			      VDPU381_STA_INT_ERROR))
+			rkvdec_iommu_restore(rkvdec);
+	}
+
+	if (need_reset)
+		rkvdec_iommu_restore(rkvdec);
+
+	if (cancel_delayed_work(&rkvdec->watchdog_work))
+		rkvdec_job_finish(ctx, state);
+
+	return IRQ_HANDLED;
+}
+
 static irqreturn_t rkvdec_irq_handler(int irq, void *priv)
 {
 	struct rkvdec_dev *rkvdec = priv;
@@ -1321,6 +1373,7 @@ static const struct rkvdec_variant rk3288_rkvdec_variant = {
 	.coded_fmts = rk3288_coded_fmts,
 	.num_coded_fmts = ARRAY_SIZE(rk3288_coded_fmts),
 	.ops = &rk3399_variant_ops,
+	.has_single_reg_region = true,
 };
 
 static const struct rkvdec_variant rk3328_rkvdec_variant = {
@@ -1328,6 +1381,7 @@ static const struct rkvdec_variant rk3328_rkvdec_variant = {
 	.coded_fmts = rkvdec_coded_fmts,
 	.num_coded_fmts = ARRAY_SIZE(rkvdec_coded_fmts),
 	.ops = &rk3399_variant_ops,
+	.has_single_reg_region = true,
 	.quirks = RKVDEC_QUIRK_DISABLE_QOS,
 };
 
@@ -1336,6 +1390,32 @@ static const struct rkvdec_variant rk3399_rkvdec_variant = {
 	.coded_fmts = rkvdec_coded_fmts,
 	.num_coded_fmts = ARRAY_SIZE(rkvdec_coded_fmts),
 	.ops = &rk3399_variant_ops,
+	.has_single_reg_region = true,
+};
+
+static const struct rcb_size_info vdpu381_rcb_sizes[] = {
+	{6,	PIC_WIDTH},	// intrar
+	{1,	PIC_WIDTH},	// transdr (Is actually 0.4*pic_width)
+	{1,	PIC_HEIGHT},	// transdc (Is actually 0.1*pic_height)
+	{3,	PIC_WIDTH},	// streamdr
+	{6,	PIC_WIDTH},	// interr
+	{3,	PIC_HEIGHT},	// interc
+	{22,	PIC_WIDTH},	// dblkr
+	{6,	PIC_WIDTH},	// saor
+	{11,	PIC_WIDTH},	// fbcr
+	{67,	PIC_HEIGHT},	// filtc col
+};
+
+static const struct rkvdec_variant_ops vdpu381_variant_ops = {
+	.irq_handler = vdpu381_irq_handler,
+};
+
+static const struct rkvdec_variant vdpu381_variant = {
+	.coded_fmts = vdpu381_coded_fmts,
+	.num_coded_fmts = ARRAY_SIZE(vdpu381_coded_fmts),
+	.rcb_sizes = vdpu381_rcb_sizes,
+	.num_rcb_sizes = ARRAY_SIZE(vdpu381_rcb_sizes),
+	.ops = &vdpu381_variant_ops,
 };
 
 static const struct of_device_id of_rkvdec_match[] = {
@@ -1351,6 +1431,10 @@ static const struct of_device_id of_rkvdec_match[] = {
 		.compatible = "rockchip,rk3399-vdec",
 		.data = &rk3399_rkvdec_variant,
 	},
+	{
+		.compatible = "rockchip,rk3588-vdec",
+		.data = &vdpu381_variant,
+	},
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, of_rkvdec_match);
@@ -1384,10 +1468,17 @@ static int rkvdec_probe(struct platform_device *pdev)
 		return ret;
 
 	rkvdec->num_clocks = ret;
+	rkvdec->axi_clk = devm_clk_get(&pdev->dev, "axi");
 
-	rkvdec->regs = devm_platform_ioremap_resource(pdev, 0);
-	if (IS_ERR(rkvdec->regs))
-		return PTR_ERR(rkvdec->regs);
+	if (rkvdec->variant->has_single_reg_region) {
+		rkvdec->regs = devm_platform_ioremap_resource(pdev, 0);
+		if (IS_ERR(rkvdec->regs))
+			return PTR_ERR(rkvdec->regs);
+	} else {
+		rkvdec->regs = devm_platform_ioremap_resource_byname(pdev, "function");
+		if (IS_ERR(rkvdec->regs))
+			return PTR_ERR(rkvdec->regs);
+	}
 
 	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
 	if (ret) {
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
index 7766a79caf68b..401221061e081 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
@@ -25,6 +25,10 @@
 
 #define RKVDEC_QUIRK_DISABLE_QOS	BIT(0)
 
+#define RKVDEC_1080P_PIXELS		(1920 * 1088)
+#define RKVDEC_4K_PIXELS		(4096 * 2304)
+#define RKVDEC_8K_PIXELS		(7680 * 4320)
+
 struct rkvdec_ctx;
 struct rkvdec_rcb_config;
 
@@ -78,6 +82,7 @@ struct rkvdec_variant {
 	const struct rcb_size_info *rcb_sizes;
 	size_t num_rcb_sizes;
 	const struct rkvdec_variant_ops *ops;
+	bool has_single_reg_region;
 	unsigned int quirks;
 };
 
@@ -126,6 +131,7 @@ struct rkvdec_dev {
 	struct device *dev;
 	struct clk_bulk_data *clocks;
 	unsigned int num_clocks;
+	struct clk *axi_clk;
 	void __iomem *regs;
 	struct mutex vdev_lock; /* serializes ioctls */
 	struct delayed_work watchdog_work;
@@ -144,6 +150,7 @@ struct rkvdec_ctx {
 	struct rkvdec_dev *dev;
 	enum rkvdec_image_fmt image_fmt;
 	struct rkvdec_rcb_config *rcb_config;
+	u32 colmv_offset;
 	void *priv;
 };
 
@@ -170,8 +177,12 @@ void rkvdec_memcpy_toio(void __iomem *dst, void *src, size_t len);
 
 void rkvdec_quirks_disable_qos(struct rkvdec_ctx *ctx);
 
+/* RKVDEC ops */
 extern const struct rkvdec_coded_fmt_ops rkvdec_h264_fmt_ops;
 extern const struct rkvdec_coded_fmt_ops rkvdec_hevc_fmt_ops;
 extern const struct rkvdec_coded_fmt_ops rkvdec_vp9_fmt_ops;
 
+/* VDPU381 ops */
+extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_h264_fmt_ops;
+
 #endif /* RKVDEC_H_ */
-- 
2.52.0



From detlev.casanova at collabora.com  Thu Dec 18 15:28:21 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Thu, 18 Dec 2025 18:28:21 -0500
Subject: [PATCH v7 11/17] media: rkvdec: Support per-variant interrupt handler
In-Reply-To: <20251218232829.337811-1-detlev.casanova@collabora.com>
References: <20251218232829.337811-1-detlev.casanova@collabora.com>
Message-ID: <20251218232829.337811-12-detlev.casanova@collabora.com>

Prepare for supporting different variants with different interrupt
managers.

To support other variants specific function type later, introduce the
rkvdec_variant_ops struct.

Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../media/platform/rockchip/rkvdec/rkvdec.c   | 21 ++++++++++++++++---
 .../media/platform/rockchip/rkvdec/rkvdec.h   |  5 +++++
 2 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index ff6a09e45462e..174536ebdcc7c 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -1222,10 +1222,9 @@ static void rkvdec_iommu_restore(struct rkvdec_dev *rkvdec)
 	}
 }
 
-static irqreturn_t rkvdec_irq_handler(int irq, void *priv)
+static irqreturn_t rk3399_irq_handler(struct rkvdec_ctx *ctx)
 {
-	struct rkvdec_dev *rkvdec = priv;
-	struct rkvdec_ctx *ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev);
+	struct rkvdec_dev *rkvdec = ctx->dev;
 	enum vb2_buffer_state state;
 	u32 status;
 
@@ -1246,6 +1245,15 @@ static irqreturn_t rkvdec_irq_handler(int irq, void *priv)
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t rkvdec_irq_handler(int irq, void *priv)
+{
+	struct rkvdec_dev *rkvdec = priv;
+	struct rkvdec_ctx *ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev);
+	const struct rkvdec_variant *variant = rkvdec->variant;
+
+	return variant->ops->irq_handler(ctx);
+}
+
 static void rkvdec_watchdog_func(struct work_struct *work)
 {
 	struct rkvdec_dev *rkvdec;
@@ -1261,16 +1269,22 @@ static void rkvdec_watchdog_func(struct work_struct *work)
 	}
 }
 
+static const struct rkvdec_variant_ops rk3399_variant_ops = {
+	.irq_handler = rk3399_irq_handler,
+};
+
 static const struct rkvdec_variant rk3288_rkvdec_variant = {
 	.num_regs = 68,
 	.coded_fmts = rk3288_coded_fmts,
 	.num_coded_fmts = ARRAY_SIZE(rk3288_coded_fmts),
+	.ops = &rk3399_variant_ops,
 };
 
 static const struct rkvdec_variant rk3328_rkvdec_variant = {
 	.num_regs = 109,
 	.coded_fmts = rkvdec_coded_fmts,
 	.num_coded_fmts = ARRAY_SIZE(rkvdec_coded_fmts),
+	.ops = &rk3399_variant_ops,
 	.quirks = RKVDEC_QUIRK_DISABLE_QOS,
 };
 
@@ -1278,6 +1292,7 @@ static const struct rkvdec_variant rk3399_rkvdec_variant = {
 	.num_regs = 78,
 	.coded_fmts = rkvdec_coded_fmts,
 	.num_coded_fmts = ARRAY_SIZE(rkvdec_coded_fmts),
+	.ops = &rk3399_variant_ops,
 };
 
 static const struct of_device_id of_rkvdec_match[] = {
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
index 751f39afe7e2d..faabedd2b9d88 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
@@ -67,12 +67,17 @@ vb2_to_rkvdec_decoded_buf(struct vb2_buffer *buf)
 			    base.vb.vb2_buf);
 }
 
+struct rkvdec_variant_ops {
+	irqreturn_t (*irq_handler)(struct rkvdec_ctx *ctx);
+};
+
 struct rkvdec_variant {
 	unsigned int num_regs;
 	const struct rkvdec_coded_fmt_desc *coded_fmts;
 	size_t num_coded_fmts;
 	const struct rcb_size_info *rcb_sizes;
 	size_t num_rcb_sizes;
+	const struct rkvdec_variant_ops *ops;
 	unsigned int quirks;
 };
 
-- 
2.52.0



From detlev.casanova at collabora.com  Thu Dec 18 15:28:20 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Thu, 18 Dec 2025 18:28:20 -0500
Subject: [PATCH v7 10/17] media: rkvdec: Add RCB and SRAM support
In-Reply-To: <20251218232829.337811-1-detlev.casanova@collabora.com>
References: <20251218232829.337811-1-detlev.casanova@collabora.com>
Message-ID: <20251218232829.337811-11-detlev.casanova@collabora.com>

The RCB (Rows and Cols Buffers) are a set of buffers used by other
variations of the decoder to store temporary data.

Those variation come with a dedicated SRAM area used to store those
buffers for better performances.

The buffer sizes are either the width or height of the frame being
decoded multiplied by a documented factor and can be stored either
in SRAM or RAM.
A fallback to RAM is provided if the SRAM is full (e.g.: multiple
streams are being decoded at the same time).

To manage the different kind of allocation, an enum is added to the
rkvdec_aux_buf struct to specify how the buffer was allocated, and
so, how to free it.

This commit is in preparation of other variants support.

Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../media/platform/rockchip/rkvdec/Makefile   |   1 +
 .../platform/rockchip/rkvdec/rkvdec-rcb.c     | 179 ++++++++++++++++++
 .../platform/rockchip/rkvdec/rkvdec-rcb.h     |  29 +++
 .../media/platform/rockchip/rkvdec/rkvdec.c   |  27 ++-
 .../media/platform/rockchip/rkvdec/rkvdec.h   |  13 ++
 5 files changed, 247 insertions(+), 2 deletions(-)
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h

diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
index 1b4bc44be23ee..3d75103e536d2 100644
--- a/drivers/media/platform/rockchip/rkvdec/Makefile
+++ b/drivers/media/platform/rockchip/rkvdec/Makefile
@@ -7,4 +7,5 @@ rockchip-vdec-y += \
 		   rkvdec-h264-common.o \
 		   rkvdec-hevc.o \
 		   rkvdec-hevc-common.o \
+		   rkvdec-rcb.o \
 		   rkvdec-vp9.o
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c
new file mode 100644
index 0000000000000..fdcf1f1773797
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip video decoder Rows and Cols Buffers manager
+ *
+ * Copyright (C) 2025 Collabora, Ltd.
+ *  Detlev Casanova <detlev.casanova at collabora.com>
+ */
+
+#include "rkvdec.h"
+#include "rkvdec-rcb.h"
+
+#include <linux/iommu.h>
+#include <linux/genalloc.h>
+#include <linux/sizes.h>
+#include <linux/types.h>
+
+struct rkvdec_rcb_config {
+	struct rkvdec_aux_buf *rcb_bufs;
+	size_t rcb_count;
+};
+
+static size_t rkvdec_rcb_size(const struct rcb_size_info *size_info,
+			      unsigned int width, unsigned int height)
+{
+	return size_info->multiplier * (size_info->axis == PIC_HEIGHT ? height : width);
+}
+
+dma_addr_t rkvdec_rcb_buf_dma_addr(struct rkvdec_ctx *ctx, int id)
+{
+	return ctx->rcb_config->rcb_bufs[id].dma;
+}
+
+size_t rkvdec_rcb_buf_size(struct rkvdec_ctx *ctx, int id)
+{
+	return ctx->rcb_config->rcb_bufs[id].size;
+}
+
+int rkvdec_rcb_buf_count(struct rkvdec_ctx *ctx)
+{
+	return ctx->rcb_config->rcb_count;
+}
+
+void rkvdec_free_rcb(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_dev *dev = ctx->dev;
+	struct rkvdec_rcb_config *cfg = ctx->rcb_config;
+	unsigned long virt_addr;
+	int i;
+
+	if (!cfg)
+		return;
+
+	for (i = 0; i < cfg->rcb_count; i++) {
+		size_t rcb_size = cfg->rcb_bufs[i].size;
+
+		if (!cfg->rcb_bufs[i].cpu)
+			continue;
+
+		switch (cfg->rcb_bufs[i].type) {
+		case RKVDEC_ALLOC_SRAM:
+			virt_addr = (unsigned long)cfg->rcb_bufs[i].cpu;
+
+			if (dev->iommu_domain)
+				iommu_unmap(dev->iommu_domain, virt_addr, rcb_size);
+			gen_pool_free(dev->sram_pool, virt_addr, rcb_size);
+			break;
+		case RKVDEC_ALLOC_DMA:
+			dma_free_coherent(dev->dev,
+					  rcb_size,
+					  cfg->rcb_bufs[i].cpu,
+					  cfg->rcb_bufs[i].dma);
+			break;
+		}
+	}
+
+	if (cfg->rcb_bufs)
+		devm_kfree(dev->dev, cfg->rcb_bufs);
+
+	devm_kfree(dev->dev, cfg);
+}
+
+int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx,
+			const struct rcb_size_info *size_info,
+			size_t rcb_count)
+{
+	int ret, i;
+	u32 width, height;
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_rcb_config *cfg;
+
+	if (!size_info || !rcb_count) {
+		ctx->rcb_config = NULL;
+		return 0;
+	}
+
+	ctx->rcb_config = devm_kzalloc(rkvdec->dev, sizeof(*ctx->rcb_config), GFP_KERNEL);
+	if (!ctx->rcb_config)
+		return -ENOMEM;
+
+	cfg = ctx->rcb_config;
+
+	cfg->rcb_bufs = devm_kzalloc(rkvdec->dev, sizeof(*cfg->rcb_bufs) * rcb_count, GFP_KERNEL);
+	if (!cfg->rcb_bufs) {
+		ret = -ENOMEM;
+		goto err_alloc;
+	}
+
+	width = ctx->decoded_fmt.fmt.pix_mp.width;
+	height = ctx->decoded_fmt.fmt.pix_mp.height;
+
+	for (i = 0; i < rcb_count; i++) {
+		void *cpu = NULL;
+		dma_addr_t dma;
+		size_t rcb_size = rkvdec_rcb_size(&size_info[i], width, height);
+		enum rkvdec_alloc_type alloc_type = RKVDEC_ALLOC_SRAM;
+
+		/* Try allocating an SRAM buffer */
+		if (ctx->dev->sram_pool) {
+			if (rkvdec->iommu_domain)
+				rcb_size = ALIGN(rcb_size, SZ_4K);
+
+			cpu = gen_pool_dma_zalloc_align(ctx->dev->sram_pool,
+							rcb_size,
+							&dma,
+							SZ_4K);
+		}
+
+		/* If an IOMMU is used, map the SRAM address through it */
+		if (cpu && rkvdec->iommu_domain) {
+			unsigned long virt_addr = (unsigned long)cpu;
+			phys_addr_t phys_addr = dma;
+
+			ret = iommu_map(rkvdec->iommu_domain, virt_addr, phys_addr,
+					rcb_size, IOMMU_READ | IOMMU_WRITE, 0);
+			if (ret) {
+				gen_pool_free(ctx->dev->sram_pool,
+					      (unsigned long)cpu,
+					      rcb_size);
+				cpu = NULL;
+				goto ram_fallback;
+			}
+
+			/*
+			 * The registers will be configured with the virtual
+			 * address so that it goes through the IOMMU
+			 */
+			dma = virt_addr;
+		}
+
+ram_fallback:
+		/* Fallback to RAM */
+		if (!cpu) {
+			cpu = dma_alloc_coherent(ctx->dev->dev,
+						 rcb_size,
+						 &dma,
+						 GFP_KERNEL);
+			alloc_type = RKVDEC_ALLOC_DMA;
+		}
+
+		if (!cpu) {
+			ret = -ENOMEM;
+			goto err_alloc;
+		}
+
+		cfg->rcb_bufs[i].cpu = cpu;
+		cfg->rcb_bufs[i].dma = dma;
+		cfg->rcb_bufs[i].size = rcb_size;
+		cfg->rcb_bufs[i].type = alloc_type;
+
+		cfg->rcb_count += 1;
+	}
+
+	return 0;
+
+err_alloc:
+	rkvdec_free_rcb(ctx);
+
+	return ret;
+}
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h
new file mode 100644
index 0000000000000..30e8002555c8a
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Rockchip video decoder Rows and Cols Buffers manager
+ *
+ * Copyright (C) 2025 Collabora, Ltd.
+ *  Detlev Casanova <detlev.casanova at collabora.com>
+ */
+
+#include <linux/types.h>
+
+struct rkvdec_ctx;
+
+enum rcb_axis {
+	PIC_WIDTH = 0,
+	PIC_HEIGHT = 1
+};
+
+struct rcb_size_info {
+	u8 multiplier;
+	enum rcb_axis axis;
+};
+
+int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx,
+			const struct rcb_size_info *size_info,
+			size_t rcb_count);
+dma_addr_t rkvdec_rcb_buf_dma_addr(struct rkvdec_ctx *ctx, int id);
+size_t rkvdec_rcb_buf_size(struct rkvdec_ctx *ctx, int id);
+int rkvdec_rcb_buf_count(struct rkvdec_ctx *ctx);
+void rkvdec_free_rcb(struct rkvdec_ctx *ctx);
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index 92b1c7b62bd20..ff6a09e45462e 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -10,6 +10,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/genalloc.h>
 #include <linux/interrupt.h>
 #include <linux/iommu.h>
 #include <linux/module.h>
@@ -28,6 +29,7 @@
 
 #include "rkvdec.h"
 #include "rkvdec-regs.h"
+#include "rkvdec-rcb.h"
 
 static bool rkvdec_image_fmt_match(enum rkvdec_image_fmt fmt1,
 				   enum rkvdec_image_fmt fmt2)
@@ -778,6 +780,7 @@ static int rkvdec_start_streaming(struct vb2_queue *q, unsigned int count)
 {
 	struct rkvdec_ctx *ctx = vb2_get_drv_priv(q);
 	const struct rkvdec_coded_fmt_desc *desc;
+	const struct rkvdec_variant *variant = ctx->dev->variant;
 	int ret;
 
 	if (V4L2_TYPE_IS_CAPTURE(q->type))
@@ -787,13 +790,22 @@ static int rkvdec_start_streaming(struct vb2_queue *q, unsigned int count)
 	if (WARN_ON(!desc))
 		return -EINVAL;
 
+	ret = rkvdec_allocate_rcb(ctx, variant->rcb_sizes, variant->num_rcb_sizes);
+	if (ret)
+		return ret;
+
 	if (desc->ops->start) {
 		ret = desc->ops->start(ctx);
 		if (ret)
-			return ret;
+			goto err_ops_start;
 	}
 
 	return 0;
+
+err_ops_start:
+	rkvdec_free_rcb(ctx);
+
+	return ret;
 }
 
 static void rkvdec_queue_cleanup(struct vb2_queue *vq, u32 state)
@@ -829,6 +841,8 @@ static void rkvdec_stop_streaming(struct vb2_queue *q)
 
 		if (desc->ops->stop)
 			desc->ops->stop(ctx);
+
+		rkvdec_free_rcb(ctx);
 	}
 
 	rkvdec_queue_cleanup(q, VB2_BUF_STATE_ERROR);
@@ -1345,6 +1359,10 @@ static int rkvdec_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	rkvdec->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0);
+	if (!rkvdec->sram_pool && rkvdec->variant->num_rcb_sizes > 0)
+		dev_info(&pdev->dev, "No sram node, RCB will be stored in RAM\n");
+
 	pm_runtime_set_autosuspend_delay(&pdev->dev, 100);
 	pm_runtime_use_autosuspend(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
@@ -1353,7 +1371,8 @@ static int rkvdec_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_disable_runtime_pm;
 
-	if (iommu_get_domain_for_dev(&pdev->dev)) {
+	rkvdec->iommu_domain = iommu_get_domain_for_dev(&pdev->dev);
+	if (rkvdec->iommu_domain) {
 		rkvdec->empty_domain = iommu_paging_domain_alloc(rkvdec->dev);
 
 		if (IS_ERR(rkvdec->empty_domain)) {
@@ -1367,6 +1386,10 @@ static int rkvdec_probe(struct platform_device *pdev)
 err_disable_runtime_pm:
 	pm_runtime_dont_use_autosuspend(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
+
+	if (rkvdec->sram_pool)
+		gen_pool_destroy(rkvdec->sram_pool);
+
 	return ret;
 }
 
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
index 8c4f96ba5cdea..751f39afe7e2d 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
@@ -19,12 +19,14 @@
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
 #include <media/videobuf2-core.h>
 #include <media/videobuf2-dma-contig.h>
 
 #define RKVDEC_QUIRK_DISABLE_QOS	BIT(0)
 
 struct rkvdec_ctx;
+struct rkvdec_rcb_config;
 
 struct rkvdec_ctrl_desc {
 	struct v4l2_ctrl_config cfg;
@@ -69,6 +71,8 @@ struct rkvdec_variant {
 	unsigned int num_regs;
 	const struct rkvdec_coded_fmt_desc *coded_fmts;
 	size_t num_coded_fmts;
+	const struct rcb_size_info *rcb_sizes;
+	size_t num_rcb_sizes;
 	unsigned int quirks;
 };
 
@@ -119,6 +123,8 @@ struct rkvdec_dev {
 	void __iomem *regs;
 	struct mutex vdev_lock; /* serializes ioctls */
 	struct delayed_work watchdog_work;
+	struct gen_pool *sram_pool;
+	struct iommu_domain *iommu_domain;
 	struct iommu_domain *empty_domain;
 	const struct rkvdec_variant *variant;
 };
@@ -131,6 +137,7 @@ struct rkvdec_ctx {
 	struct v4l2_ctrl_handler ctrl_hdl;
 	struct rkvdec_dev *dev;
 	enum rkvdec_image_fmt image_fmt;
+	struct rkvdec_rcb_config *rcb_config;
 	void *priv;
 };
 
@@ -139,10 +146,16 @@ static inline struct rkvdec_ctx *file_to_rkvdec_ctx(struct file *filp)
 	return container_of(file_to_v4l2_fh(filp), struct rkvdec_ctx, fh);
 }
 
+enum rkvdec_alloc_type {
+	RKVDEC_ALLOC_DMA  = 0,
+	RKVDEC_ALLOC_SRAM = 1,
+};
+
 struct rkvdec_aux_buf {
 	void *cpu;
 	dma_addr_t dma;
 	size_t size;
+	enum rkvdec_alloc_type type;
 };
 
 void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run);
-- 
2.52.0



From detlev.casanova at collabora.com  Thu Dec 18 15:28:25 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Thu, 18 Dec 2025 18:28:25 -0500
Subject: [PATCH v7 15/17] media: rkvdec: Add H264 support for the VDPU383 variant
In-Reply-To: <20251218232829.337811-1-detlev.casanova@collabora.com>
References: <20251218232829.337811-1-detlev.casanova@collabora.com>
Message-ID: <20251218232829.337811-16-detlev.casanova@collabora.com>

This variant is used on the RK3576 SoC.

The moving vectors size requirements are slightly different so support
for a colmv_size function per variant is added.

Also, the link registers are used to start the decoder and read IRQ status.

The fluster score is 128/135 for JVT-AVC_V1, with MPS_MW_A failing in
addition to the usual ones.
The other test suites are not supported yet.

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../media/platform/rockchip/rkvdec/Makefile   |   1 +
 .../rockchip/rkvdec/rkvdec-vdpu383-h264.c     | 578 ++++++++++++++++++
 .../rockchip/rkvdec/rkvdec-vdpu383-regs.h     | 281 +++++++++
 .../media/platform/rockchip/rkvdec/rkvdec.c   | 105 +++-
 .../media/platform/rockchip/rkvdec/rkvdec.h   |   5 +
 5 files changed, 965 insertions(+), 5 deletions(-)
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-regs.h

diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
index 7bfd95151e404..a58d4aede2fea 100644
--- a/drivers/media/platform/rockchip/rkvdec/Makefile
+++ b/drivers/media/platform/rockchip/rkvdec/Makefile
@@ -9,4 +9,5 @@ rockchip-vdec-y += \
 		   rkvdec-hevc-common.o \
 		   rkvdec-rcb.o \
 		   rkvdec-vdpu381-h264.o \
+		   rkvdec-vdpu383-h264.o \
 		   rkvdec-vp9.o
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c
new file mode 100644
index 0000000000000..cc5a41bba81cc
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c
@@ -0,0 +1,578 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip Video Decoder VDPU383 H264 backend
+ *
+ * Copyright (C) 2024 Collabora, Ltd.
+ *  Detlev Casanova <detlev.casanova at collabora.com>
+ */
+
+#include <media/v4l2-h264.h>
+#include <media/v4l2-mem2mem.h>
+
+#include <linux/iopoll.h>
+
+#include "rkvdec-rcb.h"
+#include "rkvdec-vdpu383-regs.h"
+#include "rkvdec-h264-common.h"
+
+struct rkvdec_sps {
+	u16 seq_parameter_set_id:			4;
+	u16 profile_idc:				8;
+	u16 constraint_set3_flag:			1;
+	u16 chroma_format_idc:				2;
+	u16 bit_depth_luma:				3;
+	u16 bit_depth_chroma:				3;
+	u16 qpprime_y_zero_transform_bypass_flag:	1;
+	u16 log2_max_frame_num_minus4:			4;
+	u16 max_num_ref_frames:				5;
+	u16 pic_order_cnt_type:				2;
+	u16 log2_max_pic_order_cnt_lsb_minus4:		4;
+	u16 delta_pic_order_always_zero_flag:		1;
+
+	u16 pic_width_in_mbs:				16;
+	u16 pic_height_in_mbs:				16;
+
+	u16 frame_mbs_only_flag:			1;
+	u16 mb_adaptive_frame_field_flag:		1;
+	u16 direct_8x8_inference_flag:			1;
+	u16 mvc_extension_enable:			1;
+	u16 num_views:					2;
+	u16 view_id0:                                   10;
+	u16 view_id1:                                   10;
+} __packed;
+
+struct rkvdec_pps {
+	u32 pic_parameter_set_id:				8;
+	u32 pps_seq_parameter_set_id:				5;
+	u32 entropy_coding_mode_flag:				1;
+	u32 bottom_field_pic_order_in_frame_present_flag:	1;
+	u32 num_ref_idx_l0_default_active_minus1:		5;
+	u32 num_ref_idx_l1_default_active_minus1:		5;
+	u32 weighted_pred_flag:					1;
+	u32 weighted_bipred_idc:				2;
+	u32 pic_init_qp_minus26:				7;
+	u32 pic_init_qs_minus26:				6;
+	u32 chroma_qp_index_offset:				5;
+	u32 deblocking_filter_control_present_flag:		1;
+	u32 constrained_intra_pred_flag:			1;
+	u32 redundant_pic_cnt_present:				1;
+	u32 transform_8x8_mode_flag:				1;
+	u32 second_chroma_qp_index_offset:			5;
+	u32 scaling_list_enable_flag:				1;
+	u32 is_longterm:					16;
+	u32 voidx:						16;
+
+	// dpb
+	u32 pic_field_flag:                                     1;
+	u32 pic_associated_flag:                                1;
+	u32 cur_top_field:					32;
+	u32 cur_bot_field:					32;
+
+	u32 top_field_order_cnt0:				32;
+	u32 bot_field_order_cnt0:				32;
+	u32 top_field_order_cnt1:				32;
+	u32 bot_field_order_cnt1:				32;
+	u32 top_field_order_cnt2:				32;
+	u32 bot_field_order_cnt2:				32;
+	u32 top_field_order_cnt3:				32;
+	u32 bot_field_order_cnt3:				32;
+	u32 top_field_order_cnt4:				32;
+	u32 bot_field_order_cnt4:				32;
+	u32 top_field_order_cnt5:				32;
+	u32 bot_field_order_cnt5:				32;
+	u32 top_field_order_cnt6:				32;
+	u32 bot_field_order_cnt6:				32;
+	u32 top_field_order_cnt7:				32;
+	u32 bot_field_order_cnt7:				32;
+	u32 top_field_order_cnt8:				32;
+	u32 bot_field_order_cnt8:				32;
+	u32 top_field_order_cnt9:				32;
+	u32 bot_field_order_cnt9:				32;
+	u32 top_field_order_cnt10:				32;
+	u32 bot_field_order_cnt10:				32;
+	u32 top_field_order_cnt11:				32;
+	u32 bot_field_order_cnt11:				32;
+	u32 top_field_order_cnt12:				32;
+	u32 bot_field_order_cnt12:				32;
+	u32 top_field_order_cnt13:				32;
+	u32 bot_field_order_cnt13:				32;
+	u32 top_field_order_cnt14:				32;
+	u32 bot_field_order_cnt14:				32;
+	u32 top_field_order_cnt15:				32;
+	u32 bot_field_order_cnt15:				32;
+
+	u32 ref_field_flags:					16;
+	u32 ref_topfield_used:					16;
+	u32 ref_botfield_used:					16;
+	u32 ref_colmv_use_flag:					16;
+
+	u32 reserved0:						30;
+	u32 reserved[3];
+} __packed;
+
+struct rkvdec_sps_pps {
+	struct rkvdec_sps sps;
+	struct rkvdec_pps pps;
+} __packed;
+
+/* Data structure describing auxiliary buffer format. */
+struct rkvdec_h264_priv_tbl {
+	s8 cabac_table[4][464][2];
+	struct rkvdec_h264_scaling_list scaling_list;
+	struct rkvdec_sps_pps param_set[256];
+	struct rkvdec_rps rps;
+} __packed;
+
+struct rkvdec_h264_ctx {
+	struct rkvdec_aux_buf priv_tbl;
+	struct rkvdec_h264_reflists reflists;
+	struct vdpu383_regs_h26x regs;
+};
+
+static void set_field_order_cnt(struct rkvdec_sps_pps *hw_ps, int id, u32 top, u32 bottom)
+{
+	switch (id) {
+	case 0:
+		hw_ps->pps.top_field_order_cnt0 = top;
+		hw_ps->pps.bot_field_order_cnt0 = bottom;
+		break;
+	case 1:
+		hw_ps->pps.top_field_order_cnt1 = top;
+		hw_ps->pps.bot_field_order_cnt1 = bottom;
+		break;
+	case 2:
+		hw_ps->pps.top_field_order_cnt2 = top;
+		hw_ps->pps.bot_field_order_cnt2 = bottom;
+		break;
+	case 3:
+		hw_ps->pps.top_field_order_cnt3 = top;
+		hw_ps->pps.bot_field_order_cnt3 = bottom;
+		break;
+	case 4:
+		hw_ps->pps.top_field_order_cnt4 = top;
+		hw_ps->pps.bot_field_order_cnt4 = bottom;
+		break;
+	case 5:
+		hw_ps->pps.top_field_order_cnt5 = top;
+		hw_ps->pps.bot_field_order_cnt5 = bottom;
+		break;
+	case 6:
+		hw_ps->pps.top_field_order_cnt6 = top;
+		hw_ps->pps.bot_field_order_cnt6 = bottom;
+		break;
+	case 7:
+		hw_ps->pps.top_field_order_cnt7 = top;
+		hw_ps->pps.bot_field_order_cnt7 = bottom;
+		break;
+	case 8:
+		hw_ps->pps.top_field_order_cnt8 = top;
+		hw_ps->pps.bot_field_order_cnt8 = bottom;
+		break;
+	case 9:
+		hw_ps->pps.top_field_order_cnt9 = top;
+		hw_ps->pps.bot_field_order_cnt9 = bottom;
+		break;
+	case 10:
+		hw_ps->pps.top_field_order_cnt10 = top;
+		hw_ps->pps.bot_field_order_cnt10 = bottom;
+		break;
+	case 11:
+		hw_ps->pps.top_field_order_cnt11 = top;
+		hw_ps->pps.bot_field_order_cnt11 = bottom;
+		break;
+	case 12:
+		hw_ps->pps.top_field_order_cnt12 = top;
+		hw_ps->pps.bot_field_order_cnt12 = bottom;
+		break;
+	case 13:
+		hw_ps->pps.top_field_order_cnt13 = top;
+		hw_ps->pps.bot_field_order_cnt13 = bottom;
+		break;
+	case 14:
+		hw_ps->pps.top_field_order_cnt14 = top;
+		hw_ps->pps.bot_field_order_cnt14 = bottom;
+		break;
+	case 15:
+		hw_ps->pps.top_field_order_cnt15 = top;
+		hw_ps->pps.bot_field_order_cnt15 = bottom;
+		break;
+	}
+}
+
+static void assemble_hw_pps(struct rkvdec_ctx *ctx,
+			    struct rkvdec_h264_run *run)
+{
+	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
+	const struct v4l2_ctrl_h264_sps *sps = run->sps;
+	const struct v4l2_ctrl_h264_pps *pps = run->pps;
+	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
+	const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb;
+	struct rkvdec_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu;
+	struct rkvdec_sps_pps *hw_ps;
+	u32 pic_width, pic_height;
+	u32 i;
+
+	/*
+	 * HW read the SPS/PPS information from PPS packet index by PPS id.
+	 * offset from the base can be calculated by PPS_id * 32 (size per PPS
+	 * packet unit). so the driver copy SPS/PPS information to the exact PPS
+	 * packet unit for HW accessing.
+	 */
+	hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id];
+	memset(hw_ps, 0, sizeof(*hw_ps));
+
+	/* write sps */
+	hw_ps->sps.seq_parameter_set_id = sps->seq_parameter_set_id;
+	hw_ps->sps.profile_idc = sps->profile_idc;
+	hw_ps->sps.constraint_set3_flag = !!(sps->constraint_set_flags & (1 << 3));
+	hw_ps->sps.chroma_format_idc = sps->chroma_format_idc;
+	hw_ps->sps.bit_depth_luma = sps->bit_depth_luma_minus8;
+	hw_ps->sps.bit_depth_chroma = sps->bit_depth_chroma_minus8;
+	hw_ps->sps.qpprime_y_zero_transform_bypass_flag =
+		!!(sps->flags & V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS);
+	hw_ps->sps.log2_max_frame_num_minus4 = sps->log2_max_frame_num_minus4;
+	hw_ps->sps.max_num_ref_frames = sps->max_num_ref_frames;
+	hw_ps->sps.pic_order_cnt_type = sps->pic_order_cnt_type;
+	hw_ps->sps.log2_max_pic_order_cnt_lsb_minus4 =
+		sps->log2_max_pic_order_cnt_lsb_minus4;
+	hw_ps->sps.delta_pic_order_always_zero_flag =
+		!!(sps->flags & V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO);
+	hw_ps->sps.mvc_extension_enable = 0;
+	hw_ps->sps.num_views = 0;
+
+	/*
+	 * Use the SPS values since they are already in macroblocks
+	 * dimensions, height can be field height (halved) if
+	 * V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY is not set and also it allows
+	 * decoding smaller images into larger allocation which can be used
+	 * to implementing SVC spatial layer support.
+	 */
+	pic_width = 16 * (sps->pic_width_in_mbs_minus1 + 1);
+	pic_height = 16 * (sps->pic_height_in_map_units_minus1 + 1);
+	if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY))
+		pic_height *= 2;
+	if (!!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC))
+		pic_height /= 2;
+
+	hw_ps->sps.pic_width_in_mbs = pic_width;
+	hw_ps->sps.pic_height_in_mbs = pic_height;
+
+	hw_ps->sps.frame_mbs_only_flag =
+		!!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY);
+	hw_ps->sps.mb_adaptive_frame_field_flag =
+		!!(sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD);
+	hw_ps->sps.direct_8x8_inference_flag =
+		!!(sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE);
+
+	/* write pps */
+	hw_ps->pps.pic_parameter_set_id = pps->pic_parameter_set_id;
+	hw_ps->pps.pps_seq_parameter_set_id = pps->seq_parameter_set_id;
+	hw_ps->pps.entropy_coding_mode_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE);
+	hw_ps->pps.bottom_field_pic_order_in_frame_present_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT);
+	hw_ps->pps.num_ref_idx_l0_default_active_minus1 =
+		pps->num_ref_idx_l0_default_active_minus1;
+	hw_ps->pps.num_ref_idx_l1_default_active_minus1 =
+		pps->num_ref_idx_l1_default_active_minus1;
+	hw_ps->pps.weighted_pred_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED);
+	hw_ps->pps.weighted_bipred_idc = pps->weighted_bipred_idc;
+	hw_ps->pps.pic_init_qp_minus26 = pps->pic_init_qp_minus26;
+	hw_ps->pps.pic_init_qs_minus26 = pps->pic_init_qs_minus26;
+	hw_ps->pps.chroma_qp_index_offset = pps->chroma_qp_index_offset;
+	hw_ps->pps.deblocking_filter_control_present_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT);
+	hw_ps->pps.constrained_intra_pred_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED);
+	hw_ps->pps.redundant_pic_cnt_present =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT);
+	hw_ps->pps.transform_8x8_mode_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE);
+	hw_ps->pps.second_chroma_qp_index_offset = pps->second_chroma_qp_index_offset;
+	hw_ps->pps.scaling_list_enable_flag =
+		!!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT);
+
+	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
+		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
+			hw_ps->pps.is_longterm |= (1 << i);
+
+		set_field_order_cnt(hw_ps, i, dpb[i].top_field_order_cnt,
+				    dpb[i].bottom_field_order_cnt);
+
+		hw_ps->pps.ref_field_flags |=
+			(!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD)) << i;
+		hw_ps->pps.ref_colmv_use_flag |=
+			(!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) << i;
+		hw_ps->pps.ref_topfield_used |=
+			(!!(dpb[i].fields & V4L2_H264_TOP_FIELD_REF)) << i;
+		hw_ps->pps.ref_botfield_used |=
+			(!!(dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF)) << i;
+	}
+
+	hw_ps->pps.pic_field_flag =
+		!!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC);
+	hw_ps->pps.pic_associated_flag =
+		!!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD);
+
+	hw_ps->pps.cur_top_field = dec_params->top_field_order_cnt;
+	hw_ps->pps.cur_bot_field = dec_params->bottom_field_order_cnt;
+}
+
+static void rkvdec_write_regs(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
+
+	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_COMMON_REGS,
+			   &h264_ctx->regs.common,
+			   sizeof(h264_ctx->regs.common));
+	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_COMMON_ADDR_REGS,
+			   &h264_ctx->regs.common_addr,
+			   sizeof(h264_ctx->regs.common_addr));
+	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_CODEC_PARAMS_REGS,
+			   &h264_ctx->regs.h26x_params,
+			   sizeof(h264_ctx->regs.h26x_params));
+	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_CODEC_ADDR_REGS,
+			   &h264_ctx->regs.h26x_addr,
+			   sizeof(h264_ctx->regs.h26x_addr));
+}
+
+static void config_registers(struct rkvdec_ctx *ctx,
+			     struct rkvdec_h264_run *run)
+{
+	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
+	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
+	dma_addr_t priv_start_addr = h264_ctx->priv_tbl.dma;
+	const struct v4l2_pix_format_mplane *dst_fmt;
+	struct vb2_v4l2_buffer *src_buf = run->base.bufs.src;
+	struct vb2_v4l2_buffer *dst_buf = run->base.bufs.dst;
+	struct vdpu383_regs_h26x *regs = &h264_ctx->regs;
+	const struct v4l2_format *f;
+	dma_addr_t rlc_addr;
+	dma_addr_t dst_addr;
+	u32 hor_virstride;
+	u32 ver_virstride;
+	u32 y_virstride;
+	u32 offset;
+	u32 pixels;
+	u32 i;
+
+	memset(regs, 0, sizeof(*regs));
+
+	/* Set H264 mode */
+	regs->common.reg008_dec_mode = VDPU383_MODE_H264;
+
+	/* Set input stream length */
+	regs->h26x_params.reg066_stream_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
+
+	/* Set strides */
+	f = &ctx->decoded_fmt;
+	dst_fmt = &f->fmt.pix_mp;
+	hor_virstride = dst_fmt->plane_fmt[0].bytesperline;
+	ver_virstride = dst_fmt->height;
+	y_virstride = hor_virstride * ver_virstride;
+
+	pixels = dst_fmt->height * dst_fmt->width;
+
+	regs->h26x_params.reg068_hor_virstride = hor_virstride / 16;
+	regs->h26x_params.reg069_raster_uv_hor_virstride = hor_virstride / 16;
+	regs->h26x_params.reg070_y_virstride = y_virstride / 16;
+
+	/* Activate block gating */
+	regs->common.reg010.strmd_auto_gating_e      = 1;
+	regs->common.reg010.inter_auto_gating_e      = 1;
+	regs->common.reg010.intra_auto_gating_e      = 1;
+	regs->common.reg010.transd_auto_gating_e     = 1;
+	regs->common.reg010.recon_auto_gating_e      = 1;
+	regs->common.reg010.filterd_auto_gating_e    = 1;
+	regs->common.reg010.bus_auto_gating_e        = 1;
+	regs->common.reg010.ctrl_auto_gating_e       = 1;
+	regs->common.reg010.rcb_auto_gating_e        = 1;
+	regs->common.reg010.err_prc_auto_gating_e    = 1;
+
+	/* Set timeout threshold */
+	if (pixels < RKVDEC_1080P_PIXELS)
+		regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_1080p;
+	else if (pixels < RKVDEC_4K_PIXELS)
+		regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_4K;
+	else if (pixels < RKVDEC_8K_PIXELS)
+		regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_8K;
+	else
+		regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_MAX;
+
+	regs->common.reg016.error_proc_disable = 1;
+
+	/* Set ref pic address & poc */
+	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
+		struct vb2_buffer *vb_buf = run->ref_buf[i];
+		dma_addr_t buf_dma;
+
+		/*
+		 * If a DPB entry is unused or invalid, address of current destination
+		 * buffer is returned.
+		 */
+		if (!vb_buf)
+			vb_buf = &dst_buf->vb2_buf;
+
+		buf_dma = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
+
+		/* Set reference addresses */
+		regs->h26x_addr.reg170_185_ref_base[i] = buf_dma;
+		regs->h26x_addr.reg195_210_payload_st_ref_base[i] = buf_dma;
+
+		/* Set COLMV addresses */
+		regs->h26x_addr.reg217_232_colmv_ref_base[i] = buf_dma + ctx->colmv_offset;
+	}
+
+	/* Set rlc base address (input stream) */
+	rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+	regs->common_addr.reg128_strm_base = rlc_addr;
+
+	/* Set output base address */
+	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
+	regs->h26x_addr.reg168_decout_base = dst_addr;
+	regs->h26x_addr.reg169_error_ref_base = dst_addr;
+	regs->h26x_addr.reg192_payload_st_cur_base = dst_addr;
+
+	/* Set colmv address */
+	regs->h26x_addr.reg216_colmv_cur_base = dst_addr + ctx->colmv_offset;
+
+	/* Set RCB addresses */
+	for (i = 0; i < rkvdec_rcb_buf_count(ctx); i++) {
+		regs->common_addr.reg140_162_rcb_info[i].offset = rkvdec_rcb_buf_dma_addr(ctx, i);
+		regs->common_addr.reg140_162_rcb_info[i].size = rkvdec_rcb_buf_size(ctx, i);
+	}
+
+	/* Set hw pps address */
+	offset = offsetof(struct rkvdec_h264_priv_tbl, param_set);
+	regs->common_addr.reg131_gbl_base = priv_start_addr + offset;
+	regs->h26x_params.reg067_global_len = sizeof(struct rkvdec_sps_pps) / 16;
+
+	/* Set hw rps address */
+	offset = offsetof(struct rkvdec_h264_priv_tbl, rps);
+	regs->common_addr.reg129_rps_base = priv_start_addr + offset;
+
+	/* Set cabac table */
+	offset = offsetof(struct rkvdec_h264_priv_tbl, cabac_table);
+	regs->common_addr.reg130_cabactbl_base = priv_start_addr + offset;
+
+	/* Set scaling list address */
+	offset = offsetof(struct rkvdec_h264_priv_tbl, scaling_list);
+	regs->common_addr.reg132_scanlist_addr = priv_start_addr + offset;
+
+	rkvdec_write_regs(ctx);
+}
+
+static int rkvdec_h264_start(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_h264_priv_tbl *priv_tbl;
+	struct rkvdec_h264_ctx *h264_ctx;
+	struct v4l2_ctrl *ctrl;
+	int ret;
+
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_H264_SPS);
+	if (!ctrl)
+		return -EINVAL;
+
+	h264_ctx = kzalloc(sizeof(*h264_ctx), GFP_KERNEL);
+	if (!h264_ctx)
+		return -ENOMEM;
+
+	priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl),
+				      &h264_ctx->priv_tbl.dma, GFP_KERNEL);
+	if (!priv_tbl) {
+		ret = -ENOMEM;
+		goto err_free_ctx;
+	}
+
+	h264_ctx->priv_tbl.size = sizeof(*priv_tbl);
+	h264_ctx->priv_tbl.cpu = priv_tbl;
+	memcpy(priv_tbl->cabac_table, rkvdec_h264_cabac_table,
+	       sizeof(rkvdec_h264_cabac_table));
+
+	ctx->priv = h264_ctx;
+
+	return 0;
+
+err_free_ctx:
+	kfree(h264_ctx);
+	return ret;
+}
+
+static void rkvdec_h264_stop(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
+	struct rkvdec_dev *rkvdec = ctx->dev;
+
+	dma_free_coherent(rkvdec->dev, h264_ctx->priv_tbl.size,
+			  h264_ctx->priv_tbl.cpu, h264_ctx->priv_tbl.dma);
+	kfree(h264_ctx);
+}
+
+static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
+{
+	struct v4l2_h264_reflist_builder reflist_builder;
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
+	struct rkvdec_h264_run run;
+	struct rkvdec_h264_priv_tbl *tbl = h264_ctx->priv_tbl.cpu;
+	u32 watchdog_time;
+	u64 timeout_threshold;
+	unsigned long axi_rate;
+
+	rkvdec_h264_run_preamble(ctx, &run);
+
+	/* Build the P/B{0,1} ref lists. */
+	v4l2_h264_init_reflist_builder(&reflist_builder, run.decode_params,
+				       run.sps, run.decode_params->dpb);
+	v4l2_h264_build_p_ref_list(&reflist_builder, h264_ctx->reflists.p);
+	v4l2_h264_build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0,
+				    h264_ctx->reflists.b1);
+
+	assemble_hw_scaling_list(&run, &tbl->scaling_list);
+	assemble_hw_pps(ctx, &run);
+	lookup_ref_buf_idx(ctx, &run);
+	assemble_hw_rps(&reflist_builder, &run, &h264_ctx->reflists, &tbl->rps);
+
+	config_registers(ctx, &run);
+
+	rkvdec_run_postamble(ctx, &run.base);
+
+	/* Set watchdog at 2 times the hardware timeout threshold */
+	timeout_threshold = h264_ctx->regs.common.reg013_core_timeout_threshold;
+	axi_rate = clk_get_rate(rkvdec->axi_clk);
+
+	if (axi_rate)
+		watchdog_time = 2 * (1000 * timeout_threshold) / axi_rate;
+	else
+		watchdog_time = 2000;
+	schedule_delayed_work(&rkvdec->watchdog_work,
+			      msecs_to_jiffies(watchdog_time));
+
+	/* Start decoding! */
+	writel(timeout_threshold, rkvdec->link + VDPU383_LINK_TIMEOUT_THRESHOLD);
+	writel(0, rkvdec->link + VDPU383_LINK_IP_ENABLE);
+	writel(VDPU383_DEC_E_BIT, rkvdec->link + VDPU383_LINK_DEC_ENABLE);
+
+	return 0;
+}
+
+static int rkvdec_h264_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
+{
+	if (ctrl->id == V4L2_CID_STATELESS_H264_SPS)
+		return rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps);
+
+	return 0;
+}
+
+const struct rkvdec_coded_fmt_ops rkvdec_vdpu383_h264_fmt_ops = {
+	.adjust_fmt = rkvdec_h264_adjust_fmt,
+	.get_image_fmt = rkvdec_h264_get_image_fmt,
+	.start = rkvdec_h264_start,
+	.stop = rkvdec_h264_stop,
+	.run = rkvdec_h264_run,
+	.try_ctrl = rkvdec_h264_try_ctrl,
+};
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-regs.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-regs.h
new file mode 100644
index 0000000000000..bc1c2b4272b0c
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-regs.h
@@ -0,0 +1,281 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Rockchip Video Decoder VDPU383 driver registers description
+ *
+ * Copyright (C) 2025 Collabora, Ltd.
+ *  Detlev Casanova <detlev.casanova at collabora.com>
+ */
+
+#ifndef _RKVDEC_VDPU838_REGS_H_
+#define _RKVDEC_VDPU838_REGS_H_
+
+#include <linux/types.h>
+
+#define VDPU383_OFFSET_COMMON_REGS		(8 * sizeof(u32))
+#define VDPU383_OFFSET_CODEC_PARAMS_REGS	(64 * sizeof(u32))
+#define VDPU383_OFFSET_COMMON_ADDR_REGS		(128 * sizeof(u32))
+#define VDPU383_OFFSET_CODEC_ADDR_REGS		(168 * sizeof(u32))
+#define VDPU383_OFFSET_POC_HIGHBIT_REGS		(200 * sizeof(u32))
+
+#define VDPU383_MODE_HEVC	0
+#define VDPU383_MODE_H264	1
+
+#define VDPU383_TIMEOUT_1080p		(0xffffff)
+#define VDPU383_TIMEOUT_4K		(0x2cfffff)
+#define VDPU383_TIMEOUT_8K		(0x4ffffff)
+#define VDPU383_TIMEOUT_MAX		(0xffffffff)
+
+#define VDPU383_LINK_TIMEOUT_THRESHOLD	0x54
+
+#define VDPU383_LINK_IP_ENABLE		0x58
+#define VDPU383_IP_CRU_MODE		BIT(24)
+
+#define VDPU383_LINK_DEC_ENABLE		0x40
+#define VDPU383_DEC_E_BIT		BIT(0)
+
+#define VDPU383_LINK_INT_EN		0x048
+#define VDPU383_INT_EN_IRQ		BIT(0)
+#define VDPU383_INT_EN_LINE_IRQ		BIT(1)
+
+#define VDPU383_LINK_STA_INT		0x04c
+#define VDPU383_STA_INT_DEC_RDY_STA	BIT(0)
+#define VDPU383_STA_INT_SOFTRESET_RDY	(BIT(10) | BIT(11))
+#define VDPU383_STA_INT_ALL		0x3ff
+
+struct vdpu383_regs_common {
+	u32 reg008_dec_mode;
+
+	struct swreg9_important_en {
+		u32 fbc_e			: 1;
+		u32 tile_e			: 1;
+		u32 reserve0			: 2;
+		u32 buf_empty_en		: 1;
+		u32 scale_down_en		: 1;
+		u32 reserve1			: 1;
+		u32 pix_range_det_e		: 1;
+		u32 av1_fgs_en			: 1;
+		u32 reserve2			: 7;
+		u32 line_irq_en			: 1;
+		u32 out_cbcr_swap		: 1;
+		u32 fbc_force_uncompress	: 1;
+		u32 fbc_sparse_mode		: 1;
+		u32 reserve3			: 12;
+	} reg009;
+
+	struct swreg010_block_gating_en {
+		u32 strmd_auto_gating_e		: 1;
+		u32 inter_auto_gating_e		: 1;
+		u32 intra_auto_gating_e		: 1;
+		u32 transd_auto_gating_e	: 1;
+		u32 recon_auto_gating_e		: 1;
+		u32 filterd_auto_gating_e	: 1;
+		u32 bus_auto_gating_e		: 1;
+		u32 ctrl_auto_gating_e		: 1;
+		u32 rcb_auto_gating_e		: 1;
+		u32 err_prc_auto_gating_e	: 1;
+		u32 reserve0			: 22;
+	} reg010;
+
+	struct swreg011_cfg_para {
+		u32 reserve0			: 9;
+		u32 dec_timeout_dis		: 1;
+		u32 reserve1			: 22;
+	} reg011;
+
+	struct swreg012_cache_hash_mask {
+		u32 reserve0			: 7;
+		u32 cache_hash_mask		: 25;
+	} reg012;
+
+	u32 reg013_core_timeout_threshold;
+
+	struct swreg014_line_irq_ctrl {
+		u32 dec_line_irq_step		: 16;
+		u32 dec_line_offset_y_st	: 16;
+	} reg014;
+
+	struct swreg015_irq_sta {
+		u32 rkvdec_frame_rdy_sta	: 1;
+		u32 rkvdec_strm_error_sta	: 1;
+		u32 rkvdec_core_timeout_sta	: 1;
+		u32 rkvdec_ip_timeout_sta	: 1;
+		u32 rkvdec_bus_error_sta	: 1;
+		u32 rkvdec_buffer_empty_sta	: 1;
+		u32 rkvdec_colmv_ref_error_sta	: 1;
+		u32 rkvdec_error_spread_sta	: 1;
+		u32 create_core_timeout_sta	: 1;
+		u32 wlast_miss_match_sta	: 1;
+		u32 rkvdec_core_rst_rdy_sta	: 1;
+		u32 rkvdec_ip_rst_rdy_sta	: 1;
+		u32 force_busidle_rdy_sta	: 1;
+		u32 ltb_pause_rdy_sta		: 1;
+		u32 ltb_end_flag		: 1;
+		u32 unsupport_decmode_error_sta	: 1;
+		u32 wmask_bits			: 15;
+		u32 reserve0			: 1;
+	} reg015;
+
+	struct swreg016_error_ctrl_set {
+		u32 error_proc_disable		: 1;
+		u32 reserve0			: 7;
+		u32 error_spread_disable	: 1;
+		u32 reserve1			: 15;
+		u32 roi_error_ctu_cal_en	: 1;
+		u32 reserve2			: 7;
+	} reg016;
+
+	struct swreg017_err_roi_ctu_offset_start {
+		u32 roi_x_ctu_offset_st		: 12;
+		u32 reserve0			: 4;
+		u32 roi_y_ctu_offset_st		: 12;
+		u32 reserve1			: 4;
+	} reg017;
+
+	struct swreg018_err_roi_ctu_offset_end {
+		u32 roi_x_ctu_offset_end	: 12;
+		u32 reserve0			: 4;
+		u32 roi_y_ctu_offset_end	: 12;
+		u32 reserve1			: 4;
+	} reg018;
+
+	struct swreg019_error_ref_info {
+		u32 avs2_ref_error_field	: 1;
+		u32 avs2_ref_error_topfield	: 1;
+		u32 ref_error_topfield_used	: 1;
+		u32 ref_error_botfield_used	: 1;
+		u32 reserve0			: 28;
+	} reg019;
+
+	u32 reg020_cabac_error_en_lowbits;
+	u32 reg021_cabac_error_en_highbits;
+
+	u32 reg022_reserved;
+
+	struct swreg023_invalid_pixel_fill {
+		u32 fill_y			: 10;
+		u32 fill_u			: 10;
+		u32 fill_v			: 10;
+		u32 reserve0			: 2;
+	} reg023;
+
+	u32 reg024_026_reserved[3];
+
+	struct swreg027_align_en {
+		u32 reserve0			: 4;
+		u32 ctu_align_wr_en		: 1;
+		u32 reserve1			: 27;
+	} reg027;
+
+	struct swreg028_debug_perf_latency_ctrl0 {
+		u32 axi_perf_work_e		: 1;
+		u32 reserve0			: 2;
+		u32 axi_cnt_type		: 1;
+		u32 rd_latency_id		: 8;
+		u32 reserve1			: 4;
+		u32 rd_latency_thr		: 12;
+		u32 reserve2			: 4;
+	} reg028;
+
+	struct swreg029_debug_perf_latency_ctrl1 {
+		u32 addr_align_type		: 2;
+		u32 ar_cnt_id_type		: 1;
+		u32 aw_cnt_id_type		: 1;
+		u32 ar_count_id			: 8;
+		u32 reserve0			: 4;
+		u32 aw_count_id			: 8;
+		u32 rd_band_width_mode		: 1;
+		u32 reserve1			: 7;
+	} reg029;
+
+	struct swreg030_qos_ctrl {
+		u32 axi_wr_qos_level		: 4;
+		u32 reserve0			: 4;
+		u32 axi_wr_qos			: 4;
+		u32 reserve1			: 4;
+		u32 axi_rd_qos_level		: 4;
+		u32 reserve2			: 4;
+		u32 axi_rd_qos			: 4;
+		u32 reserve3			: 4;
+	} reg030;
+};
+
+struct vdpu383_regs_common_addr {
+	u32 reg128_strm_base;
+	u32 reg129_rps_base;
+	u32 reg130_cabactbl_base;
+	u32 reg131_gbl_base;
+	u32 reg132_scanlist_addr;
+	u32 reg133_scale_down_base;
+	u32 reg134_fgs_base;
+	u32 reg135_139_reserved[5];
+
+	struct rcb_info {
+	u32 offset;
+	u32 size;
+	} reg140_162_rcb_info[11];
+};
+
+struct vdpu383_regs_h26x_addr {
+	u32 reg168_decout_base;
+	u32 reg169_error_ref_base;
+	u32 reg170_185_ref_base[16];
+	u32 reg186_191_reserved[6];
+	u32 reg192_payload_st_cur_base;
+	u32 reg193_fbc_payload_offset;
+	u32 reg194_payload_st_error_ref_base;
+	u32 reg195_210_payload_st_ref_base[16];
+	u32 reg211_215_reserved[5];
+	u32 reg216_colmv_cur_base;
+	u32 reg217_232_colmv_ref_base[16];
+};
+
+struct vdpu383_regs_h26x_params {
+	u32 reg064_start_decoder;
+	u32 reg065_strm_start_bit;
+	u32 reg066_stream_len;
+	u32 reg067_global_len;
+	u32 reg068_hor_virstride;
+	u32 reg069_raster_uv_hor_virstride;
+	u32 reg070_y_virstride;
+	u32 reg071_scl_ref_hor_virstride;
+	u32 reg072_scl_ref_raster_uv_hor_virstride;
+	u32 reg073_scl_ref_virstride;
+	u32 reg074_fgs_ref_hor_virstride;
+	u32 reg075_079_reserved[5];
+	u32 reg080_error_ref_hor_virstride;
+	u32 reg081_error_ref_raster_uv_hor_virstride;
+	u32 reg082_error_ref_virstride;
+	u32 reg083_ref0_hor_virstride;
+	u32 reg084_ref0_raster_uv_hor_virstride;
+	u32 reg085_ref0_virstride;
+	u32 reg086_ref1_hor_virstride;
+	u32 reg087_ref1_raster_uv_hor_virstride;
+	u32 reg088_ref1_virstride;
+	u32 reg089_ref2_hor_virstride;
+	u32 reg090_ref2_raster_uv_hor_virstride;
+	u32 reg091_ref2_virstride;
+	u32 reg092_ref3_hor_virstride;
+	u32 reg093_ref3_raster_uv_hor_virstride;
+	u32 reg094_ref3_virstride;
+	u32 reg095_ref4_hor_virstride;
+	u32 reg096_ref4_raster_uv_hor_virstride;
+	u32 reg097_ref4_virstride;
+	u32 reg098_ref5_hor_virstride;
+	u32 reg099_ref5_raster_uv_hor_virstride;
+	u32 reg100_ref5_virstride;
+	u32 reg101_ref6_hor_virstride;
+	u32 reg102_ref6_raster_uv_hor_virstride;
+	u32 reg103_ref6_virstride;
+	u32 reg104_ref7_hor_virstride;
+	u32 reg105_ref7_raster_uv_hor_virstride;
+	u32 reg106_ref7_virstride;
+};
+
+struct vdpu383_regs_h26x {
+	struct vdpu383_regs_common		common;		/* 8-30 */
+	struct vdpu383_regs_h26x_params		h26x_params;	/* 64-74, 80-106 */
+	struct vdpu383_regs_common_addr		common_addr;	/* 128-134, 140-161 */
+	struct vdpu383_regs_h26x_addr		h26x_addr;	/* 168-185, 192-210, 216-232 */
+} __packed;
+
+#endif /* __RKVDEC_VDPU838_REGS_H__ */
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index 3d243b6e11445..fe33e69710bfa 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -9,6 +9,7 @@
  * Copyright (C) 2011 Samsung Electronics Co., Ltd.
  */
 
+#include <linux/hw_bitfield.h>
 #include <linux/clk.h>
 #include <linux/genalloc.h>
 #include <linux/interrupt.h>
@@ -30,6 +31,7 @@
 #include "rkvdec.h"
 #include "rkvdec-regs.h"
 #include "rkvdec-vdpu381-regs.h"
+#include "rkvdec-vdpu383-regs.h"
 #include "rkvdec-rcb.h"
 
 static bool rkvdec_image_fmt_match(enum rkvdec_image_fmt fmt1,
@@ -86,17 +88,26 @@ static bool rkvdec_is_valid_fmt(struct rkvdec_ctx *ctx, u32 fourcc,
 	return false;
 }
 
+static u32 rkvdec_colmv_size(u16 width, u16 height)
+{
+	return 128 * DIV_ROUND_UP(width, 16) * DIV_ROUND_UP(height, 16);
+}
+
+static u32 vdpu383_colmv_size(u16 width, u16 height)
+{
+	return ALIGN(width, 64) * ALIGN(height, 16);
+}
+
 static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx,
 				       struct v4l2_pix_format_mplane *pix_mp)
 {
-	v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat,
-			    pix_mp->width, pix_mp->height);
+	const struct rkvdec_variant *variant = ctx->dev->variant;
+
+	v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat, pix_mp->width, pix_mp->height);
 
 	ctx->colmv_offset = pix_mp->plane_fmt[0].sizeimage;
 
-	pix_mp->plane_fmt[0].sizeimage += 128 *
-		DIV_ROUND_UP(pix_mp->width, 16) *
-		DIV_ROUND_UP(pix_mp->height, 16);
+	pix_mp->plane_fmt[0].sizeimage += variant->ops->colmv_size(pix_mp->width, pix_mp->height);
 }
 
 static void rkvdec_reset_fmt(struct rkvdec_ctx *ctx, struct v4l2_format *f,
@@ -405,6 +416,25 @@ static const struct rkvdec_coded_fmt_desc vdpu381_coded_fmts[] = {
 	},
 };
 
+static const struct rkvdec_coded_fmt_desc vdpu383_coded_fmts[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_H264_SLICE,
+		.frmsize = {
+			.min_width = 64,
+			.max_width =  65520,
+			.step_width = 64,
+			.min_height = 64,
+			.max_height =  65520,
+			.step_height = 16,
+		},
+		.ctrls = &rkvdec_h264_ctrls,
+		.ops = &rkvdec_vdpu383_h264_fmt_ops,
+		.num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts),
+		.decoded_fmts = rkvdec_h264_decoded_fmts,
+		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
+	},
+};
+
 static const struct rkvdec_coded_fmt_desc *
 rkvdec_enum_coded_fmt_desc(struct rkvdec_ctx *ctx, int index)
 {
@@ -1297,6 +1327,35 @@ static irqreturn_t vdpu381_irq_handler(struct rkvdec_ctx *ctx)
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t vdpu383_irq_handler(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	enum vb2_buffer_state state;
+	bool need_reset = 0;
+	u32 status;
+
+	status = readl(rkvdec->link + VDPU383_LINK_STA_INT);
+	writel(FIELD_PREP_WM16(VDPU383_STA_INT_ALL, 0), rkvdec->link + VDPU383_LINK_STA_INT);
+	/* On vdpu383, the interrupts must be disabled */
+	writel(FIELD_PREP_WM16(VDPU383_INT_EN_IRQ | VDPU383_INT_EN_LINE_IRQ, 0),
+	       rkvdec->link + VDPU383_LINK_INT_EN);
+
+	if (status & VDPU383_STA_INT_DEC_RDY_STA) {
+		state = VB2_BUF_STATE_DONE;
+	} else {
+		state = VB2_BUF_STATE_ERROR;
+		rkvdec_iommu_restore(rkvdec);
+	}
+
+	if (need_reset)
+		rkvdec_iommu_restore(rkvdec);
+
+	if (cancel_delayed_work(&rkvdec->watchdog_work))
+		rkvdec_job_finish(ctx, state);
+
+	return IRQ_HANDLED;
+}
+
 static irqreturn_t rkvdec_irq_handler(int irq, void *priv)
 {
 	struct rkvdec_dev *rkvdec = priv;
@@ -1366,6 +1425,7 @@ static int rkvdec_disable_multicore(struct rkvdec_dev *rkvdec)
 
 static const struct rkvdec_variant_ops rk3399_variant_ops = {
 	.irq_handler = rk3399_irq_handler,
+	.colmv_size = rkvdec_colmv_size,
 };
 
 static const struct rkvdec_variant rk3288_rkvdec_variant = {
@@ -1408,6 +1468,7 @@ static const struct rcb_size_info vdpu381_rcb_sizes[] = {
 
 static const struct rkvdec_variant_ops vdpu381_variant_ops = {
 	.irq_handler = vdpu381_irq_handler,
+	.colmv_size = rkvdec_colmv_size,
 };
 
 static const struct rkvdec_variant vdpu381_variant = {
@@ -1418,6 +1479,32 @@ static const struct rkvdec_variant vdpu381_variant = {
 	.ops = &vdpu381_variant_ops,
 };
 
+static const struct rcb_size_info vdpu383_rcb_sizes[] = {
+	{6,	PIC_WIDTH},	// streamd
+	{6,	PIC_WIDTH},	// streamd_tile
+	{12,	PIC_WIDTH},	// inter
+	{12,	PIC_WIDTH},	// inter_tile
+	{16,	PIC_WIDTH},	// intra
+	{10,	PIC_WIDTH},	// intra_tile
+	{120,	PIC_WIDTH},	// filterd
+	{120,	PIC_WIDTH},	// filterd_protect
+	{120,	PIC_WIDTH},	// filterd_tile_row
+	{180,	PIC_HEIGHT},	// filterd_tile_col
+};
+
+static const struct rkvdec_variant_ops vdpu383_variant_ops = {
+	.irq_handler = vdpu383_irq_handler,
+	.colmv_size = vdpu383_colmv_size,
+};
+
+static const struct rkvdec_variant vdpu383_variant = {
+	.coded_fmts = vdpu383_coded_fmts,
+	.num_coded_fmts = ARRAY_SIZE(vdpu383_coded_fmts),
+	.rcb_sizes = vdpu383_rcb_sizes,
+	.num_rcb_sizes = ARRAY_SIZE(vdpu383_rcb_sizes),
+	.ops = &vdpu383_variant_ops,
+};
+
 static const struct of_device_id of_rkvdec_match[] = {
 	{
 		.compatible = "rockchip,rk3288-vdec",
@@ -1435,6 +1522,10 @@ static const struct of_device_id of_rkvdec_match[] = {
 		.compatible = "rockchip,rk3588-vdec",
 		.data = &vdpu381_variant,
 	},
+	{
+		.compatible = "rockchip,rk3576-vdec",
+		.data = &vdpu383_variant,
+	},
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, of_rkvdec_match);
@@ -1478,6 +1569,10 @@ static int rkvdec_probe(struct platform_device *pdev)
 		rkvdec->regs = devm_platform_ioremap_resource_byname(pdev, "function");
 		if (IS_ERR(rkvdec->regs))
 			return PTR_ERR(rkvdec->regs);
+
+		rkvdec->link = devm_platform_ioremap_resource_byname(pdev, "link");
+		if (IS_ERR(rkvdec->link))
+			return PTR_ERR(rkvdec->link);
 	}
 
 	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
index 401221061e081..a76bc270d0062 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
@@ -73,6 +73,7 @@ vb2_to_rkvdec_decoded_buf(struct vb2_buffer *buf)
 
 struct rkvdec_variant_ops {
 	irqreturn_t (*irq_handler)(struct rkvdec_ctx *ctx);
+	u32 (*colmv_size)(u16 width, u16 height);
 };
 
 struct rkvdec_variant {
@@ -133,6 +134,7 @@ struct rkvdec_dev {
 	unsigned int num_clocks;
 	struct clk *axi_clk;
 	void __iomem *regs;
+	void __iomem *link;
 	struct mutex vdev_lock; /* serializes ioctls */
 	struct delayed_work watchdog_work;
 	struct gen_pool *sram_pool;
@@ -185,4 +187,7 @@ extern const struct rkvdec_coded_fmt_ops rkvdec_vp9_fmt_ops;
 /* VDPU381 ops */
 extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_h264_fmt_ops;
 
+/* VDPU383 ops */
+extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu383_h264_fmt_ops;
+
 #endif /* RKVDEC_H_ */
-- 
2.52.0



From detlev.casanova at collabora.com  Thu Dec 18 15:28:26 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Thu, 18 Dec 2025 18:28:26 -0500
Subject: [PATCH v7 16/17] media: rkvdec: Add HEVC support for the VDPU381 variant
In-Reply-To: <20251218232829.337811-1-detlev.casanova@collabora.com>
References: <20251218232829.337811-1-detlev.casanova@collabora.com>
Message-ID: <20251218232829.337811-17-detlev.casanova@collabora.com>

The VDPU381 supports HEVC decoding up to 7680x4320 at 30fps.
It could double that when using both decoder cores.

It support YUV420 (8 and 10 bits) as well as AFBC (not implemented
here)

The fluster score is 146/147 for JCT-VC-HEVC_V1, tested on ROCK 5B.
None of the other test suites works.

Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../media/platform/rockchip/rkvdec/Makefile   |   1 +
 .../rockchip/rkvdec/rkvdec-hevc-common.c      | 335 ++++++++++
 .../rockchip/rkvdec/rkvdec-hevc-common.h      |  59 ++
 .../rockchip/rkvdec/rkvdec-vdpu381-hevc.c     | 622 ++++++++++++++++++
 .../media/platform/rockchip/rkvdec/rkvdec.c   |  82 +++
 .../media/platform/rockchip/rkvdec/rkvdec.h   |   3 +
 6 files changed, 1102 insertions(+)
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c

diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
index a58d4aede2fea..e30fdd7d51c3c 100644
--- a/drivers/media/platform/rockchip/rkvdec/Makefile
+++ b/drivers/media/platform/rockchip/rkvdec/Makefile
@@ -9,5 +9,6 @@ rockchip-vdec-y += \
 		   rkvdec-hevc-common.o \
 		   rkvdec-rcb.o \
 		   rkvdec-vdpu381-h264.o \
+		   rkvdec-vdpu381-hevc.o \
 		   rkvdec-vdpu383-h264.o \
 		   rkvdec-vp9.o
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
index cb56a9a243927..52926c67d0189 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
@@ -21,6 +21,125 @@
 #include "rkvdec.h"
 #include "rkvdec-hevc-common.h"
 
+/* Store the Short term ref pic set calculated values */
+struct calculated_rps_st_set {
+	u8 num_delta_pocs;
+	u8 num_negative_pics;
+	u8 num_positive_pics;
+	u8 used_by_curr_pic_s0[16];
+	u8 used_by_curr_pic_s1[16];
+	s32 delta_poc_s0[16];
+	s32 delta_poc_s1[16];
+};
+
+void compute_tiles_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size,
+			   u16 width, u16 height, s32 pic_in_cts_width,
+			   s32 pic_in_cts_height, u16 *column_width, u16 *row_height)
+{
+	const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+	int i;
+
+	for (i = 0; i < pps->num_tile_columns_minus1 + 1; i++)
+		column_width[i] = ((i + 1) * pic_in_cts_width) /
+				  (pps->num_tile_columns_minus1 + 1) -
+				  (i * pic_in_cts_width) /
+				  (pps->num_tile_columns_minus1 + 1);
+
+	for (i = 0; i < pps->num_tile_rows_minus1 + 1; i++)
+		row_height[i] = ((i + 1) * pic_in_cts_height) /
+				(pps->num_tile_rows_minus1 + 1) -
+				(i * pic_in_cts_height) /
+				(pps->num_tile_rows_minus1 + 1);
+}
+
+void compute_tiles_non_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size,
+			       u16 width, u16 height, s32 pic_in_cts_width,
+			       s32 pic_in_cts_height, u16 *column_width, u16 *row_height)
+{
+	const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+	s32 sum = 0;
+	int i;
+
+	for (i = 0; i < pps->num_tile_columns_minus1; i++) {
+		column_width[i] = pps->column_width_minus1[i] + 1;
+		sum += column_width[i];
+	}
+	column_width[i] = pic_in_cts_width - sum;
+
+	sum = 0;
+	for (i = 0; i < pps->num_tile_rows_minus1; i++) {
+		row_height[i] = pps->row_height_minus1[i] + 1;
+		sum += row_height[i];
+	}
+	row_height[i] = pic_in_cts_height - sum;
+}
+
+static void set_ref_poc(struct rkvdec_rps_short_term_ref_set *set, int poc, int value, int flag)
+{
+	switch (poc) {
+	case 0:
+		set->delta_poc0 = value;
+		set->used_flag0 = flag;
+		break;
+	case 1:
+		set->delta_poc1 = value;
+		set->used_flag1 = flag;
+		break;
+	case 2:
+		set->delta_poc2 = value;
+		set->used_flag2 = flag;
+		break;
+	case 3:
+		set->delta_poc3 = value;
+		set->used_flag3 = flag;
+		break;
+	case 4:
+		set->delta_poc4 = value;
+		set->used_flag4 = flag;
+		break;
+	case 5:
+		set->delta_poc5 = value;
+		set->used_flag5 = flag;
+		break;
+	case 6:
+		set->delta_poc6 = value;
+		set->used_flag6 = flag;
+		break;
+	case 7:
+		set->delta_poc7 = value;
+		set->used_flag7 = flag;
+		break;
+	case 8:
+		set->delta_poc8 = value;
+		set->used_flag8 = flag;
+		break;
+	case 9:
+		set->delta_poc9 = value;
+		set->used_flag9 = flag;
+		break;
+	case 10:
+		set->delta_poc10 = value;
+		set->used_flag10 = flag;
+		break;
+	case 11:
+		set->delta_poc11 = value;
+		set->used_flag11 = flag;
+		break;
+	case 12:
+		set->delta_poc12 = value;
+		set->used_flag12 = flag;
+		break;
+	case 13:
+		set->delta_poc13 = value;
+		set->used_flag13 = flag;
+		break;
+	case 14:
+		set->delta_poc14 = value;
+		set->used_flag14 = flag;
+		break;
+	}
+}
+
 /*
  * Flip one or more matrices along their main diagonal and flatten them
  * before writing it to the memory.
@@ -120,6 +239,211 @@ void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
 	       sizeof(struct v4l2_ctrl_hevc_scaling_matrix));
 }
 
+static void rkvdec_hevc_assemble_hw_lt_rps(struct rkvdec_hevc_run *run, struct rkvdec_rps *rps)
+{
+	const struct v4l2_ctrl_hevc_sps *sps = run->sps;
+
+	if (!run->ext_sps_lt_rps)
+		return;
+
+	for (int i = 0; i < sps->num_long_term_ref_pics_sps; i++) {
+		rps->refs[i].lt_ref_pic_poc_lsb =
+			run->ext_sps_lt_rps[i].lt_ref_pic_poc_lsb_sps;
+		rps->refs[i].used_by_curr_pic_lt_flag =
+			!!(run->ext_sps_lt_rps[i].flags & V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_USED_LT);
+	}
+}
+
+static void rkvdec_hevc_assemble_hw_st_rps(struct rkvdec_hevc_run *run, struct rkvdec_rps *rps,
+					   struct calculated_rps_st_set *calculated_rps_st_sets)
+{
+	const struct v4l2_ctrl_hevc_sps *sps = run->sps;
+
+	for (int i = 0; i < sps->num_short_term_ref_pic_sets; i++) {
+		int poc = 0;
+		int j = 0;
+		const struct calculated_rps_st_set *set = &calculated_rps_st_sets[i];
+
+		rps->short_term_ref_sets[i].num_negative = set->num_negative_pics;
+		rps->short_term_ref_sets[i].num_positive = set->num_positive_pics;
+
+		for (; j < set->num_negative_pics; j++) {
+			set_ref_poc(&rps->short_term_ref_sets[i], j,
+				    set->delta_poc_s0[j], set->used_by_curr_pic_s0[j]);
+		}
+		poc = j;
+
+		for (j = 0; j < set->num_positive_pics; j++) {
+			set_ref_poc(&rps->short_term_ref_sets[i], poc + j,
+				    set->delta_poc_s1[j], set->used_by_curr_pic_s1[j]);
+		}
+	}
+}
+
+/*
+ * Compute the short term ref pic set parameters based on its reference short term ref pic
+ */
+static void st_ref_pic_set_prediction(struct rkvdec_hevc_run *run, int idx,
+				      struct calculated_rps_st_set *calculated_rps_st_sets)
+{
+	const struct v4l2_ctrl_hevc_ext_sps_st_rps *rps_data = &run->ext_sps_st_rps[idx];
+	struct calculated_rps_st_set *st_rps = &calculated_rps_st_sets[idx];
+	struct calculated_rps_st_set *ref_rps;
+	u8 st_rps_idx = idx;
+	u8 ref_rps_idx = 0;
+	s16 delta_rps = 0;
+	u8 use_delta_flag[16] = { 0 };
+	u8 used_by_curr_pic_flag[16] = { 0 };
+	int i, j;
+	int dPoc;
+
+	ref_rps_idx = st_rps_idx - (rps_data->delta_idx_minus1 + 1); /* 7-59 */
+	delta_rps = (1 - 2 * rps_data->delta_rps_sign) *
+		   (rps_data->abs_delta_rps_minus1 + 1); /* 7-60 */
+
+	ref_rps = &calculated_rps_st_sets[ref_rps_idx];
+
+	for (j = 0; j <= ref_rps->num_delta_pocs; j++) {
+		used_by_curr_pic_flag[j] = !!(rps_data->used_by_curr_pic & (1 << j));
+		use_delta_flag[j] = !!(rps_data->use_delta_flag & (1 << j));
+	}
+
+	/* 7-61: calculate num_negative_pics, delta_poc_s0 and used_by_curr_pic_s0 */
+	i = 0;
+	for (j = (ref_rps->num_positive_pics - 1); j >= 0; j--) {
+		dPoc = ref_rps->delta_poc_s1[j] + delta_rps;
+		if (dPoc < 0 && use_delta_flag[ref_rps->num_negative_pics + j]) {
+			st_rps->delta_poc_s0[i] = dPoc;
+			st_rps->used_by_curr_pic_s0[i++] =
+				used_by_curr_pic_flag[ref_rps->num_negative_pics + j];
+		}
+	}
+	if (delta_rps < 0 && use_delta_flag[ref_rps->num_delta_pocs]) {
+		st_rps->delta_poc_s0[i] = delta_rps;
+		st_rps->used_by_curr_pic_s0[i++] = used_by_curr_pic_flag[ref_rps->num_delta_pocs];
+	}
+	for (j = 0; j < ref_rps->num_negative_pics; j++) {
+		dPoc = ref_rps->delta_poc_s0[j] + delta_rps;
+		if (dPoc < 0 && use_delta_flag[j]) {
+			st_rps->delta_poc_s0[i] = dPoc;
+			st_rps->used_by_curr_pic_s0[i++] = used_by_curr_pic_flag[j];
+		}
+	}
+	st_rps->num_negative_pics = i;
+
+	/* 7-62: calculate num_positive_pics, delta_poc_s1 and used_by_curr_pic_s1 */
+	i = 0;
+	for (j = (ref_rps->num_negative_pics - 1); j >= 0; j--) {
+		dPoc = ref_rps->delta_poc_s0[j] + delta_rps;
+		if (dPoc > 0 && use_delta_flag[j]) {
+			st_rps->delta_poc_s1[i] = dPoc;
+			st_rps->used_by_curr_pic_s1[i++] = used_by_curr_pic_flag[j];
+		}
+	}
+	if (delta_rps > 0 && use_delta_flag[ref_rps->num_delta_pocs]) {
+		st_rps->delta_poc_s1[i] = delta_rps;
+		st_rps->used_by_curr_pic_s1[i++] = used_by_curr_pic_flag[ref_rps->num_delta_pocs];
+	}
+	for (j = 0; j < ref_rps->num_positive_pics; j++) {
+		dPoc = ref_rps->delta_poc_s1[j] + delta_rps;
+		if (dPoc > 0 && use_delta_flag[ref_rps->num_negative_pics + j]) {
+			st_rps->delta_poc_s1[i] = dPoc;
+			st_rps->used_by_curr_pic_s1[i++] =
+				used_by_curr_pic_flag[ref_rps->num_negative_pics + j];
+		}
+	}
+	st_rps->num_positive_pics = i;
+
+	st_rps->num_delta_pocs = st_rps->num_positive_pics + st_rps->num_negative_pics;
+}
+
+/*
+ * Compute the short term ref pic set parameters based on the control's data.
+ */
+static void st_ref_pic_set_calculate(struct rkvdec_hevc_run *run, int idx,
+				     struct calculated_rps_st_set *calculated_rps_st_sets)
+{
+	const struct v4l2_ctrl_hevc_ext_sps_st_rps *rps_data = &run->ext_sps_st_rps[idx];
+	struct calculated_rps_st_set *st_rps = &calculated_rps_st_sets[idx];
+	int j, i = 0;
+
+	/* 7-63 */
+	st_rps->num_negative_pics = rps_data->num_negative_pics;
+	/* 7-64 */
+	st_rps->num_positive_pics = rps_data->num_positive_pics;
+
+	for (i = 0; i < st_rps->num_negative_pics; i++) {
+		/* 7-65 */
+		st_rps->used_by_curr_pic_s0[i] = !!(rps_data->used_by_curr_pic & (1 << i));
+
+		if (i == 0) {
+			/* 7-67 */
+			st_rps->delta_poc_s0[i] = -(rps_data->delta_poc_s0_minus1[i] + 1);
+		} else {
+			/* 7-69 */
+			st_rps->delta_poc_s0[i] =
+				st_rps->delta_poc_s0[i - 1] -
+				(rps_data->delta_poc_s0_minus1[i] + 1);
+		}
+	}
+
+	for (j = 0; j < st_rps->num_positive_pics; j++) {
+		/* 7-66 */
+		st_rps->used_by_curr_pic_s1[j] = !!(rps_data->used_by_curr_pic & (1 << (i + j)));
+
+		if (j == 0) {
+			/* 7-68 */
+			st_rps->delta_poc_s1[j] = rps_data->delta_poc_s1_minus1[j] + 1;
+		} else {
+			/* 7-70 */
+			st_rps->delta_poc_s1[j] =
+				st_rps->delta_poc_s1[j - 1] +
+				(rps_data->delta_poc_s1_minus1[j] + 1);
+		}
+	}
+
+	/* 7-71 */
+	st_rps->num_delta_pocs = st_rps->num_positive_pics + st_rps->num_negative_pics;
+}
+
+static void rkvdec_hevc_prepare_hw_st_rps(struct rkvdec_hevc_run *run, struct rkvdec_rps *rps,
+					  struct v4l2_ctrl_hevc_ext_sps_st_rps *cache)
+{
+	int idx;
+
+	if (!run->ext_sps_st_rps)
+		return;
+
+	if (!memcmp(cache, run->ext_sps_st_rps, sizeof(struct v4l2_ctrl_hevc_ext_sps_st_rps)))
+		return;
+
+	struct calculated_rps_st_set *calculated_rps_st_sets =
+		kzalloc(sizeof(struct calculated_rps_st_set) *
+			run->sps->num_short_term_ref_pic_sets, GFP_KERNEL);
+
+	for (idx = 0; idx < run->sps->num_short_term_ref_pic_sets; idx++) {
+		const struct v4l2_ctrl_hevc_ext_sps_st_rps *rps_data = &run->ext_sps_st_rps[idx];
+
+		if (rps_data->flags & V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED)
+			st_ref_pic_set_prediction(run, idx, calculated_rps_st_sets);
+		else
+			st_ref_pic_set_calculate(run, idx, calculated_rps_st_sets);
+	}
+
+	rkvdec_hevc_assemble_hw_st_rps(run, rps, calculated_rps_st_sets);
+
+	kfree(calculated_rps_st_sets);
+
+	memcpy(cache, run->ext_sps_st_rps, sizeof(struct v4l2_ctrl_hevc_ext_sps_st_rps));
+}
+
+void rkvdec_hevc_assemble_hw_rps(struct rkvdec_hevc_run *run, struct rkvdec_rps *rps,
+				 struct v4l2_ctrl_hevc_ext_sps_st_rps *st_cache)
+{
+	rkvdec_hevc_prepare_hw_st_rps(run, rps, st_cache);
+	rkvdec_hevc_assemble_hw_lt_rps(run, rps);
+}
+
 struct vb2_buffer *
 get_ref_buf(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run,
 	    unsigned int dpb_idx)
@@ -202,5 +526,16 @@ void rkvdec_hevc_run_preamble(struct rkvdec_ctx *ctx,
 			      V4L2_CID_STATELESS_HEVC_SCALING_MATRIX);
 	run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL;
 
+	if (ctx->has_sps_st_rps) {
+		ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+				      V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS);
+		run->ext_sps_st_rps = ctrl ? ctrl->p_cur.p : NULL;
+	}
+	if (ctx->has_sps_lt_rps) {
+		ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+				      V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS);
+		run->ext_sps_lt_rps = ctrl ? ctrl->p_cur.p : NULL;
+	}
+
 	rkvdec_run_preamble(ctx, &run->base);
 }
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
index e3099fdd784b1..0d7498e6a112a 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
@@ -16,11 +16,60 @@
  */
 
 #include <media/v4l2-mem2mem.h>
+#include <linux/types.h>
 #include "rkvdec.h"
 
 #define RKV_HEVC_CABAC_TABLE_SIZE		27456
 extern const u8 rkvdec_hevc_cabac_table[RKV_HEVC_CABAC_TABLE_SIZE];
 
+struct rkvdec_rps_refs {
+	u16 lt_ref_pic_poc_lsb;
+	u16 used_by_curr_pic_lt_flag	: 1;
+	u16 reserved			: 15;
+} __packed;
+
+struct rkvdec_rps_short_term_ref_set {
+	u32 num_negative	: 4;
+	u32 num_positive	: 4;
+	u32 delta_poc0		: 16;
+	u32 used_flag0		: 1;
+	u32 delta_poc1		: 16;
+	u32 used_flag1		: 1;
+	u32 delta_poc2		: 16;
+	u32 used_flag2		: 1;
+	u32 delta_poc3		: 16;
+	u32 used_flag3		: 1;
+	u32 delta_poc4		: 16;
+	u32 used_flag4		: 1;
+	u32 delta_poc5		: 16;
+	u32 used_flag5		: 1;
+	u32 delta_poc6		: 16;
+	u32 used_flag6		: 1;
+	u32 delta_poc7		: 16;
+	u32 used_flag7		: 1;
+	u32 delta_poc8		: 16;
+	u32 used_flag8		: 1;
+	u32 delta_poc9		: 16;
+	u32 used_flag9		: 1;
+	u32 delta_poc10		: 16;
+	u32 used_flag10		: 1;
+	u32 delta_poc11		: 16;
+	u32 used_flag11		: 1;
+	u32 delta_poc12		: 16;
+	u32 used_flag12		: 1;
+	u32 delta_poc13		: 16;
+	u32 used_flag13		: 1;
+	u32 delta_poc14		: 16;
+	u32 used_flag14		: 1;
+	u32 reserved_bits	: 25;
+	u32 reserved[3];
+} __packed;
+
+struct rkvdec_rps {
+	struct rkvdec_rps_refs refs[32];
+	struct rkvdec_rps_short_term_ref_set short_term_ref_sets[64];
+} __packed;
+
 struct rkvdec_hevc_run {
 	struct rkvdec_run base;
 	const struct v4l2_ctrl_hevc_slice_params *slices_params;
@@ -28,6 +77,8 @@ struct rkvdec_hevc_run {
 	const struct v4l2_ctrl_hevc_sps *sps;
 	const struct v4l2_ctrl_hevc_pps *pps;
 	const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix;
+	const struct v4l2_ctrl_hevc_ext_sps_st_rps *ext_sps_st_rps;
+	const struct v4l2_ctrl_hevc_ext_sps_lt_rps *ext_sps_lt_rps;
 	int num_slices;
 };
 
@@ -38,6 +89,14 @@ struct scaling_factor {
 	u8 reserved[4];		/*16Bytes align*/
 };
 
+void compute_tiles_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size,
+			   u16 width, u16 height, s32 pic_in_cts_width,
+			   s32 pic_in_cts_height, u16 *column_width, u16 *row_height);
+void compute_tiles_non_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size,
+			       u16 width, u16 height, s32 pic_in_cts_width,
+			       s32 pic_in_cts_height, u16 *column_width, u16 *row_height);
+void rkvdec_hevc_assemble_hw_rps(struct rkvdec_hevc_run *run, struct rkvdec_rps *rps,
+				 struct v4l2_ctrl_hevc_ext_sps_st_rps *st_cache);
 void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
 					  struct scaling_factor *scaling_factor,
 					  struct v4l2_ctrl_hevc_scaling_matrix *cache);
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
new file mode 100644
index 0000000000000..6a73f587bdd1d
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
@@ -0,0 +1,622 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip VDPU381 HEVC backend
+ *
+ * Copyright (C) 2025 Collabora, Ltd.
+ *  Detlev Casanova <detlev.casanova at collabora.com>
+ */
+
+#include <media/v4l2-mem2mem.h>
+
+#include "rkvdec.h"
+#include "rkvdec-rcb.h"
+#include "rkvdec-hevc-common.h"
+#include "rkvdec-vdpu381-regs.h"
+
+// SPS
+struct rkvdec_hevc_sps {
+	u16 video_parameters_set_id			: 4;
+	u16 seq_parameters_set_id_sps			: 4;
+	u16 chroma_format_idc				: 2;
+	u16 width					: 16;
+	u16 height					: 16;
+	u16 bit_depth_luma				: 4;
+	u16 bit_depth_chroma				: 4;
+	u16 max_pic_order_count_lsb			: 5;
+	u16 diff_max_min_luma_coding_block_size		: 2;
+	u16 min_luma_coding_block_size			: 3;
+	u16 min_transform_block_size			: 3;
+	u16 diff_max_min_transform_block_size		: 2;
+	u16 max_transform_hierarchy_depth_inter		: 3;
+	u16 max_transform_hierarchy_depth_intra		: 3;
+	u16 scaling_list_enabled_flag			: 1;
+	u16 amp_enabled_flag				: 1;
+	u16 sample_adaptive_offset_enabled_flag		: 1;
+	u16 pcm_enabled_flag				: 1;
+	u16 pcm_sample_bit_depth_luma			: 4;
+	u16 pcm_sample_bit_depth_chroma			: 4;
+	u16 pcm_loop_filter_disabled_flag		: 1;
+	u16 diff_max_min_pcm_luma_coding_block_size	: 3;
+	u16 min_pcm_luma_coding_block_size		: 3;
+	u16 num_short_term_ref_pic_sets			: 7;
+	u16 long_term_ref_pics_present_flag		: 1;
+	u16 num_long_term_ref_pics_sps			: 6;
+	u16 sps_temporal_mvp_enabled_flag		: 1;
+	u16 strong_intra_smoothing_enabled_flag		: 1;
+	u16 reserved_0					: 7;
+	u16 sps_max_dec_pic_buffering_minus1		: 4;
+	u16 reserved_0_2				: 3;
+	u16 reserved_f					: 8;
+} __packed;
+
+//PPS
+struct rkvdec_hevc_pps {
+	u16 picture_parameters_set_id			: 6;
+	u16 seq_parameters_set_id_pps			: 4;
+	u16 dependent_slice_segments_enabled_flag	: 1;
+	u16 output_flag_present_flag			: 1;
+	u16 num_extra_slice_header_bits			: 13;
+	u16 sign_data_hiding_enabled_flag		: 1;
+	u16 cabac_init_present_flag			: 1;
+	u16 num_ref_idx_l0_default_active		: 4;
+	u16 num_ref_idx_l1_default_active		: 4;
+	u16 init_qp_minus26				: 7;
+	u16 constrained_intra_pred_flag			: 1;
+	u16 transform_skip_enabled_flag			: 1;
+	u16 cu_qp_delta_enabled_flag			: 1;
+	u16 log2_min_cb_size				: 3;
+	u16 pps_cb_qp_offset				: 5;
+	u16 pps_cr_qp_offset				: 5;
+	u16 pps_slice_chroma_qp_offsets_present_flag	: 1;
+	u16 weighted_pred_flag				: 1;
+	u16 weighted_bipred_flag			: 1;
+	u16 transquant_bypass_enabled_flag		: 1;
+	u16 tiles_enabled_flag				: 1;
+	u16 entropy_coding_sync_enabled_flag		: 1;
+	u16 pps_loop_filter_across_slices_enabled_flag	: 1;
+	u16 loop_filter_across_tiles_enabled_flag	: 1;
+	u16 deblocking_filter_override_enabled_flag	: 1;
+	u16 pps_deblocking_filter_disabled_flag		: 1;
+	u16 pps_beta_offset_div2			: 4;
+	u16 pps_tc_offset_div2				: 4;
+	u16 lists_modification_present_flag		: 1;
+	u16 log2_parallel_merge_level			: 3;
+	u16 slice_segment_header_extension_present_flag	: 1;
+	u16 zeroes					: 3;
+	u16 num_tile_columns				: 5;
+	u16 num_tile_rows				: 5;
+	u16 sps_pps_mode				: 4;
+	u16 reserved_bits				: 14;
+	u16 reserved;
+} __packed;
+
+struct rkvdec_hevc_tile {
+	u16 value0	: 12;
+	u16 value1	: 12;
+} __packed;
+
+struct rkvdec_sps_pps_packet {
+	struct rkvdec_hevc_sps sps;
+	struct rkvdec_hevc_pps pps;
+	struct rkvdec_hevc_tile column_width[10];
+	struct rkvdec_hevc_tile row_height[11];
+	u32 zeroes[3];
+	u32 zeroes_bits		: 6;
+	u32 padding_bits	: 2;
+	u32 padding;
+} __packed;
+
+struct rkvdec_hevc_priv_tbl {
+	struct rkvdec_sps_pps_packet param_set[64];
+	struct rkvdec_rps rps;
+	struct scaling_factor scaling_list;
+	u8 cabac_table[27456];
+};
+
+struct rkvdec_hevc_ctx {
+	struct rkvdec_aux_buf			priv_tbl;
+	struct v4l2_ctrl_hevc_scaling_matrix	scaling_matrix_cache;
+	struct v4l2_ctrl_hevc_ext_sps_st_rps	st_cache;
+	struct rkvdec_vdpu381_regs_hevc		regs;
+};
+
+static void assemble_hw_pps(struct rkvdec_ctx *ctx,
+			    struct rkvdec_hevc_run *run)
+{
+	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
+	const struct v4l2_ctrl_hevc_sps *sps = run->sps;
+	const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+	struct rkvdec_hevc_priv_tbl *priv_tbl = hevc_ctx->priv_tbl.cpu;
+	struct rkvdec_sps_pps_packet *hw_ps;
+	bool tiles_enabled;
+	s32 max_cu_width;
+	s32 pic_in_cts_width;
+	s32 pic_in_cts_height;
+	u16 log2_min_cb_size, width, height;
+	u16 column_width[20];
+	u16 row_height[22];
+	u8 pcm_enabled;
+	u32 i;
+
+	/*
+	 * HW read the SPS/PPS information from PPS packet index by PPS id.
+	 * offset from the base can be calculated by PPS_id * 32 (size per PPS
+	 * packet unit). so the driver copy SPS/PPS information to the exact PPS
+	 * packet unit for HW accessing.
+	 */
+	hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id];
+	memset(hw_ps, 0, sizeof(*hw_ps));
+
+	/* write sps */
+	hw_ps->sps.video_parameters_set_id = sps->video_parameter_set_id;
+	hw_ps->sps.seq_parameters_set_id_sps = sps->seq_parameter_set_id;
+	hw_ps->sps.chroma_format_idc = sps->chroma_format_idc;
+
+	log2_min_cb_size = sps->log2_min_luma_coding_block_size_minus3 + 3;
+	width = sps->pic_width_in_luma_samples;
+	height = sps->pic_height_in_luma_samples;
+	hw_ps->sps.width = width;
+	hw_ps->sps.height = height;
+	hw_ps->sps.bit_depth_luma = sps->bit_depth_luma_minus8 + 8;
+	hw_ps->sps.bit_depth_chroma = sps->bit_depth_chroma_minus8 + 8;
+	hw_ps->sps.max_pic_order_count_lsb = sps->log2_max_pic_order_cnt_lsb_minus4 + 4;
+	hw_ps->sps.diff_max_min_luma_coding_block_size =
+		sps->log2_diff_max_min_luma_coding_block_size;
+	hw_ps->sps.min_luma_coding_block_size = sps->log2_min_luma_coding_block_size_minus3 + 3;
+	hw_ps->sps.min_transform_block_size = sps->log2_min_luma_transform_block_size_minus2 + 2;
+	hw_ps->sps.diff_max_min_transform_block_size =
+		sps->log2_diff_max_min_luma_transform_block_size;
+	hw_ps->sps.max_transform_hierarchy_depth_inter = sps->max_transform_hierarchy_depth_inter;
+	hw_ps->sps.max_transform_hierarchy_depth_intra = sps->max_transform_hierarchy_depth_intra;
+	hw_ps->sps.scaling_list_enabled_flag =
+		!!(sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED);
+	hw_ps->sps.amp_enabled_flag = !!(sps->flags & V4L2_HEVC_SPS_FLAG_AMP_ENABLED);
+	hw_ps->sps.sample_adaptive_offset_enabled_flag =
+		!!(sps->flags & V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET);
+
+	pcm_enabled = !!(sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED);
+	hw_ps->sps.pcm_enabled_flag = pcm_enabled;
+	hw_ps->sps.pcm_sample_bit_depth_luma =
+		pcm_enabled ? sps->pcm_sample_bit_depth_luma_minus1 + 1 : 0;
+	hw_ps->sps.pcm_sample_bit_depth_chroma =
+		pcm_enabled ? sps->pcm_sample_bit_depth_chroma_minus1 + 1 : 0;
+	hw_ps->sps.pcm_loop_filter_disabled_flag =
+		!!(sps->flags & V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED);
+	hw_ps->sps.diff_max_min_pcm_luma_coding_block_size =
+		sps->log2_diff_max_min_pcm_luma_coding_block_size;
+	hw_ps->sps.min_pcm_luma_coding_block_size =
+		pcm_enabled ? sps->log2_min_pcm_luma_coding_block_size_minus3 + 3 : 0;
+	hw_ps->sps.num_short_term_ref_pic_sets = sps->num_short_term_ref_pic_sets;
+	hw_ps->sps.long_term_ref_pics_present_flag =
+		!!(sps->flags & V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT);
+	hw_ps->sps.num_long_term_ref_pics_sps = sps->num_long_term_ref_pics_sps;
+	hw_ps->sps.sps_temporal_mvp_enabled_flag =
+		!!(sps->flags & V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED);
+	hw_ps->sps.strong_intra_smoothing_enabled_flag =
+		!!(sps->flags & V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED);
+	hw_ps->sps.sps_max_dec_pic_buffering_minus1 = sps->sps_max_dec_pic_buffering_minus1;
+	hw_ps->sps.reserved_f = 0xff;
+
+	/* write pps */
+	hw_ps->pps.picture_parameters_set_id = pps->pic_parameter_set_id;
+	hw_ps->pps.seq_parameters_set_id_pps = sps->seq_parameter_set_id;
+	hw_ps->pps.dependent_slice_segments_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED);
+	hw_ps->pps.output_flag_present_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT);
+	hw_ps->pps.num_extra_slice_header_bits = pps->num_extra_slice_header_bits;
+	hw_ps->pps.sign_data_hiding_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED);
+	hw_ps->pps.cabac_init_present_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT);
+	hw_ps->pps.num_ref_idx_l0_default_active = pps->num_ref_idx_l0_default_active_minus1 + 1;
+	hw_ps->pps.num_ref_idx_l1_default_active = pps->num_ref_idx_l1_default_active_minus1 + 1;
+	hw_ps->pps.init_qp_minus26 = pps->init_qp_minus26;
+	hw_ps->pps.constrained_intra_pred_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED);
+	hw_ps->pps.transform_skip_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED);
+	hw_ps->pps.cu_qp_delta_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED);
+	hw_ps->pps.log2_min_cb_size = log2_min_cb_size +
+				      sps->log2_diff_max_min_luma_coding_block_size -
+				      pps->diff_cu_qp_delta_depth;
+	hw_ps->pps.pps_cb_qp_offset = pps->pps_cb_qp_offset;
+	hw_ps->pps.pps_cr_qp_offset = pps->pps_cr_qp_offset;
+	hw_ps->pps.pps_slice_chroma_qp_offsets_present_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT);
+	hw_ps->pps.weighted_pred_flag = !!(pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED);
+	hw_ps->pps.weighted_bipred_flag = !!(pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED);
+	hw_ps->pps.transquant_bypass_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED);
+
+	tiles_enabled = !!(pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED);
+	hw_ps->pps.tiles_enabled_flag = tiles_enabled;
+	hw_ps->pps.entropy_coding_sync_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED);
+	hw_ps->pps.pps_loop_filter_across_slices_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED);
+	hw_ps->pps.loop_filter_across_tiles_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED);
+	hw_ps->pps.deblocking_filter_override_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED);
+	hw_ps->pps.pps_deblocking_filter_disabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER);
+	hw_ps->pps.pps_beta_offset_div2 = pps->pps_beta_offset_div2;
+	hw_ps->pps.pps_tc_offset_div2 = pps->pps_tc_offset_div2;
+	hw_ps->pps.lists_modification_present_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT);
+	hw_ps->pps.log2_parallel_merge_level = pps->log2_parallel_merge_level_minus2 + 2;
+	hw_ps->pps.slice_segment_header_extension_present_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT);
+	hw_ps->pps.num_tile_columns = tiles_enabled ? pps->num_tile_columns_minus1 + 1 : 0;
+	hw_ps->pps.num_tile_rows = tiles_enabled ? pps->num_tile_rows_minus1 + 1 : 0;
+	hw_ps->pps.sps_pps_mode = 0;
+	hw_ps->pps.reserved_bits = 0x3fff;
+	hw_ps->pps.reserved = 0xffff;
+
+	// Setup tiles information
+	memset(column_width, 0, sizeof(column_width));
+	memset(row_height, 0, sizeof(row_height));
+
+	max_cu_width = 1 << (sps->log2_diff_max_min_luma_coding_block_size + log2_min_cb_size);
+	pic_in_cts_width = (width + max_cu_width - 1) / max_cu_width;
+	pic_in_cts_height = (height + max_cu_width - 1) / max_cu_width;
+
+	if (pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED) {
+		if (pps->flags & V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING) {
+			compute_tiles_uniform(run, log2_min_cb_size, width, height,
+					      pic_in_cts_width, pic_in_cts_height,
+					      column_width, row_height);
+		} else {
+			compute_tiles_non_uniform(run, log2_min_cb_size, width, height,
+						  pic_in_cts_width, pic_in_cts_height,
+						  column_width, row_height);
+		}
+	} else {
+		column_width[0] = (width + max_cu_width - 1) / max_cu_width;
+		row_height[0] = (height + max_cu_width - 1) / max_cu_width;
+	}
+
+	for (i = 0; i < 20; i++) {
+		if (column_width[i] > 0)
+			column_width[i]--;
+
+		if (i & 1)
+			hw_ps->column_width[i / 2].value1 = column_width[i];
+		else
+			hw_ps->column_width[i / 2].value0 = column_width[i];
+	}
+
+	for (i = 0; i < 22; i++) {
+		if (row_height[i] > 0)
+			row_height[i]--;
+
+		if (i & 1)
+			hw_ps->row_height[i / 2].value1 = row_height[i];
+		else
+			hw_ps->row_height[i / 2].value0 = row_height[i];
+	}
+
+	hw_ps->padding = 0xffffffff;
+	hw_ps->padding_bits = 0x3;
+}
+
+static void set_ref_valid(struct rkvdec_vdpu381_regs_hevc *regs, int id, u32 valid)
+{
+	switch (id) {
+	case 0:
+		regs->hevc_param.reg099.hevc_ref_valid_0 = valid;
+		break;
+	case 1:
+		regs->hevc_param.reg099.hevc_ref_valid_1 = valid;
+		break;
+	case 2:
+		regs->hevc_param.reg099.hevc_ref_valid_2 = valid;
+		break;
+	case 3:
+		regs->hevc_param.reg099.hevc_ref_valid_3 = valid;
+		break;
+	case 4:
+		regs->hevc_param.reg099.hevc_ref_valid_4 = valid;
+		break;
+	case 5:
+		regs->hevc_param.reg099.hevc_ref_valid_5 = valid;
+		break;
+	case 6:
+		regs->hevc_param.reg099.hevc_ref_valid_6 = valid;
+		break;
+	case 7:
+		regs->hevc_param.reg099.hevc_ref_valid_7 = valid;
+		break;
+	case 8:
+		regs->hevc_param.reg099.hevc_ref_valid_8 = valid;
+		break;
+	case 9:
+		regs->hevc_param.reg099.hevc_ref_valid_9 = valid;
+		break;
+	case 10:
+		regs->hevc_param.reg099.hevc_ref_valid_10 = valid;
+		break;
+	case 11:
+		regs->hevc_param.reg099.hevc_ref_valid_11 = valid;
+		break;
+	case 12:
+		regs->hevc_param.reg099.hevc_ref_valid_12 = valid;
+		break;
+	case 13:
+		regs->hevc_param.reg099.hevc_ref_valid_13 = valid;
+		break;
+	case 14:
+		regs->hevc_param.reg099.hevc_ref_valid_14 = valid;
+		break;
+	}
+}
+
+static void rkvdec_write_regs(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
+
+	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_REGS,
+			   &hevc_ctx->regs.common,
+			   sizeof(hevc_ctx->regs.common));
+	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_PARAMS_REGS,
+			   &hevc_ctx->regs.hevc_param,
+			   sizeof(hevc_ctx->regs.hevc_param));
+	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_ADDR_REGS,
+			   &hevc_ctx->regs.common_addr,
+			   sizeof(hevc_ctx->regs.common_addr));
+	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_ADDR_REGS,
+			   &hevc_ctx->regs.hevc_addr,
+			   sizeof(hevc_ctx->regs.hevc_addr));
+	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_POC_HIGHBIT_REGS,
+			   &hevc_ctx->regs.hevc_highpoc,
+			   sizeof(hevc_ctx->regs.hevc_highpoc));
+}
+
+static void config_registers(struct rkvdec_ctx *ctx,
+			     struct rkvdec_hevc_run *run)
+{
+	const struct v4l2_ctrl_hevc_decode_params *dec_params = run->decode_params;
+	const struct v4l2_hevc_dpb_entry *dpb = dec_params->dpb;
+	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
+	struct rkvdec_vdpu381_regs_hevc *regs = &hevc_ctx->regs;
+	dma_addr_t priv_start_addr = hevc_ctx->priv_tbl.dma;
+	const struct v4l2_pix_format_mplane *dst_fmt;
+	struct vb2_v4l2_buffer *src_buf = run->base.bufs.src;
+	struct vb2_v4l2_buffer *dst_buf = run->base.bufs.dst;
+	const struct v4l2_format *f;
+	dma_addr_t rlc_addr;
+	u32 hor_virstride = 0;
+	u32 ver_virstride = 0;
+	u32 y_virstride = 0;
+	u32 offset;
+	u32 pixels;
+	dma_addr_t dst_addr;
+	u32 i;
+
+	memset(regs, 0, sizeof(*regs));
+
+	/* Set HEVC mode */
+	regs->common.reg009.dec_mode = VDPU381_MODE_HEVC;
+
+	/* Set config */
+	regs->common.reg011.buf_empty_en = 1;
+	regs->common.reg011.dec_clkgate_e = 1;
+	regs->common.reg011.dec_timeout_e = 1;
+	regs->common.reg011.pix_range_detection_e = 1;
+
+	/* Set IDR flag */
+	regs->common.reg013.cur_pic_is_idr =
+		!!(dec_params->flags & V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC);
+
+	/* Set input stream length */
+	regs->common.stream_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
+
+	/* Set max slice number */
+	regs->common.reg017.slice_num = 1;
+
+	/* Set strides */
+	f = &ctx->decoded_fmt;
+	dst_fmt = &f->fmt.pix_mp;
+	hor_virstride = dst_fmt->plane_fmt[0].bytesperline;
+	ver_virstride = dst_fmt->height;
+	y_virstride = hor_virstride * ver_virstride;
+	pixels = dst_fmt->height * dst_fmt->width;
+
+	regs->common.reg018.y_hor_virstride = hor_virstride / 16;
+	regs->common.reg019.uv_hor_virstride = hor_virstride / 16;
+	regs->common.reg020.y_virstride = y_virstride / 16;
+
+	/* Activate block gating */
+	regs->common.reg026.swreg_block_gating_e = 0xfffef;
+	regs->common.reg026.reg_cfg_gating_en = 1;
+
+	/* Set timeout threshold */
+	if (pixels < RKVDEC_1080P_PIXELS)
+		regs->common.timeout_threshold = RKVDEC_TIMEOUT_1080p;
+	else if (pixels < RKVDEC_4K_PIXELS)
+		regs->common.timeout_threshold = RKVDEC_TIMEOUT_4K;
+	else if (pixels < RKVDEC_8K_PIXELS)
+		regs->common.timeout_threshold = RKVDEC_TIMEOUT_8K;
+
+	/* Set POC val */
+	regs->hevc_param.cur_top_poc = dec_params->pic_order_cnt_val;
+
+	/* Set ref pic address & poc */
+	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
+		struct vb2_buffer *vb_buf = get_ref_buf(ctx, run, i);
+		dma_addr_t buf_dma = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
+		u32 valid = !!(dec_params->num_active_dpb_entries > i);
+
+		/* Set reference addresses */
+		regs->hevc_addr.ref_base[i] = buf_dma;
+
+		/* Set COLMV addresses */
+		regs->hevc_addr.colmv_base[i] = buf_dma + ctx->colmv_offset;
+
+		regs->hevc_param.reg067_082_ref_poc[i] =
+			dpb[i].pic_order_cnt_val;
+
+		set_ref_valid(regs, i, valid);
+		regs->hevc_param.reg103.ref_pic_layer_same_with_cur |= 1 << i;
+	}
+
+	/* Set rlc base address (input stream) */
+	rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+	regs->common_addr.rlc_base = rlc_addr;
+	regs->common_addr.rlcwrite_base = rlc_addr;
+
+	/* Set output base address */
+	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
+	regs->common_addr.decout_base = dst_addr;
+	regs->common_addr.error_ref_base = dst_addr;
+
+	/* Set colmv address */
+	regs->common_addr.colmv_cur_base = dst_addr + ctx->colmv_offset;
+
+	/* Set RCB addresses */
+	for (i = 0; i < rkvdec_rcb_buf_count(ctx); i++)
+		regs->common_addr.rcb_base[i] = rkvdec_rcb_buf_dma_addr(ctx, i);
+
+	/* Set hw pps address */
+	offset = offsetof(struct rkvdec_hevc_priv_tbl, param_set);
+	regs->hevc_addr.pps_base = priv_start_addr + offset;
+
+	/* Set hw rps address */
+	offset = offsetof(struct rkvdec_hevc_priv_tbl, rps);
+	regs->hevc_addr.rps_base = priv_start_addr + offset;
+
+	/* Set cabac table */
+	offset = offsetof(struct rkvdec_hevc_priv_tbl, cabac_table);
+	regs->hevc_addr.cabactbl_base = priv_start_addr + offset;
+
+	/* Set scaling matrix */
+	offset = offsetof(struct rkvdec_hevc_priv_tbl, scaling_list);
+	regs->hevc_addr.scanlist_addr = priv_start_addr + offset;
+
+	rkvdec_write_regs(ctx);
+}
+
+static int rkvdec_hevc_validate_sps(struct rkvdec_ctx *ctx,
+				    const struct v4l2_ctrl_hevc_sps *sps)
+{
+	if (sps->chroma_format_idc != 1)
+		/* Only 4:2:0 is supported */
+		return -EINVAL;
+
+	if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
+		/* Luma and chroma bit depth mismatch */
+		return -EINVAL;
+
+	if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2)
+		/* Only 8-bit and 10-bit are supported */
+		return -EINVAL;
+
+	if (sps->pic_width_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.width ||
+	    sps->pic_height_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.height)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int rkvdec_hevc_start(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_hevc_priv_tbl *priv_tbl;
+	struct rkvdec_hevc_ctx *hevc_ctx;
+	struct v4l2_ctrl *ctrl;
+	int ret;
+
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_HEVC_SPS);
+	if (!ctrl)
+		return -EINVAL;
+
+	hevc_ctx = kzalloc(sizeof(*hevc_ctx), GFP_KERNEL);
+	if (!hevc_ctx)
+		return -ENOMEM;
+
+	priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl),
+				      &hevc_ctx->priv_tbl.dma, GFP_KERNEL);
+	if (!priv_tbl) {
+		ret = -ENOMEM;
+		goto err_free_ctx;
+	}
+
+	hevc_ctx->priv_tbl.size = sizeof(*priv_tbl);
+	hevc_ctx->priv_tbl.cpu = priv_tbl;
+	memcpy(priv_tbl->cabac_table, rkvdec_hevc_cabac_table,
+	       sizeof(rkvdec_hevc_cabac_table));
+
+	ctx->priv = hevc_ctx;
+	return 0;
+
+err_free_ctx:
+	kfree(hevc_ctx);
+	return ret;
+}
+
+static void rkvdec_hevc_stop(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
+	struct rkvdec_dev *rkvdec = ctx->dev;
+
+	dma_free_coherent(rkvdec->dev, hevc_ctx->priv_tbl.size,
+			  hevc_ctx->priv_tbl.cpu, hevc_ctx->priv_tbl.dma);
+	kfree(hevc_ctx);
+}
+
+static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_hevc_run run;
+	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
+	struct rkvdec_hevc_priv_tbl *tbl = hevc_ctx->priv_tbl.cpu;
+
+	rkvdec_hevc_run_preamble(ctx, &run);
+
+	/*
+	 * On vdpu381, not setting the long and short term ref sets will just output wrong frames.
+	 * Let's just warn about it and let the decoder run anyway.
+	 */
+	if ((!ctx->has_sps_lt_rps && run.sps->num_long_term_ref_pics_sps) ||
+		(!ctx->has_sps_st_rps && run.sps->num_short_term_ref_pic_sets)) {
+		dev_warn_ratelimited(rkvdec->dev, "Long and short term RPS not set\n");
+	}
+
+	rkvdec_hevc_assemble_hw_scaling_list(&run,
+					     &tbl->scaling_list,
+					     &hevc_ctx->scaling_matrix_cache);
+	assemble_hw_pps(ctx, &run);
+	rkvdec_hevc_assemble_hw_rps(&run, &tbl->rps, &hevc_ctx->st_cache);
+
+	config_registers(ctx, &run);
+
+	rkvdec_run_postamble(ctx, &run.base);
+
+	schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000));
+
+	/* Start decoding! */
+	writel(VDPU381_DEC_E_BIT, rkvdec->regs + VDPU381_REG_DEC_E);
+
+	return 0;
+}
+
+static int rkvdec_hevc_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
+{
+	if (ctrl->id == V4L2_CID_STATELESS_HEVC_SPS)
+		return rkvdec_hevc_validate_sps(ctx, ctrl->p_new.p_hevc_sps);
+
+	return 0;
+}
+
+const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_hevc_fmt_ops = {
+	.adjust_fmt = rkvdec_hevc_adjust_fmt,
+	.start = rkvdec_hevc_start,
+	.stop = rkvdec_hevc_stop,
+	.run = rkvdec_hevc_run,
+	.try_ctrl = rkvdec_hevc_try_ctrl,
+	.get_image_fmt = rkvdec_hevc_get_image_fmt,
+};
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index fe33e69710bfa..8405ddb5962b8 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -153,6 +153,16 @@ static int rkvdec_s_ctrl(struct v4l2_ctrl *ctrl)
 	enum rkvdec_image_fmt image_fmt;
 	struct vb2_queue *vq;
 
+	if (ctrl->id == V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS) {
+		ctx->has_sps_st_rps |= !!(ctrl->has_changed);
+		return 0;
+	}
+
+	if (ctrl->id == V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS) {
+		ctx->has_sps_lt_rps |= !!(ctrl->has_changed);
+		return 0;
+	}
+
 	/* Check if this change requires a capture format reset */
 	if (!desc->ops->get_image_fmt)
 		return 0;
@@ -226,6 +236,62 @@ static const struct rkvdec_ctrls rkvdec_hevc_ctrls = {
 	.num_ctrls = ARRAY_SIZE(rkvdec_hevc_ctrl_descs),
 };
 
+static const struct rkvdec_ctrl_desc vdpu38x_hevc_ctrl_descs[] = {
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_SPS,
+		.cfg.ops = &rkvdec_ctrl_ops,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_PPS,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_MODE,
+		.cfg.min = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
+		.cfg.max = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
+		.cfg.def = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_START_CODE,
+		.cfg.min = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
+		.cfg.def = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
+		.cfg.max = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
+	},
+	{
+		.cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
+		.cfg.min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
+		.cfg.max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
+		.cfg.menu_skip_mask =
+			BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE),
+		.cfg.def = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
+	},
+	{
+		.cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
+		.cfg.min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
+		.cfg.max = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS,
+		.cfg.ops = &rkvdec_ctrl_ops,
+		.cfg.dims = { 65 },
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS,
+		.cfg.ops = &rkvdec_ctrl_ops,
+		.cfg.dims = { 65 },
+	},
+};
+
+static const struct rkvdec_ctrls vdpu38x_hevc_ctrls = {
+	.ctrls = vdpu38x_hevc_ctrl_descs,
+	.num_ctrls = ARRAY_SIZE(vdpu38x_hevc_ctrl_descs),
+};
+
 static const struct rkvdec_decoded_fmt_desc rkvdec_hevc_decoded_fmts[] = {
 	{
 		.fourcc = V4L2_PIX_FMT_NV12,
@@ -398,6 +464,22 @@ static const struct rkvdec_coded_fmt_desc rk3288_coded_fmts[] = {
 };
 
 static const struct rkvdec_coded_fmt_desc vdpu381_coded_fmts[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_HEVC_SLICE,
+		.frmsize = {
+			.min_width = 64,
+			.max_width = 65472,
+			.step_width = 64,
+			.min_height = 64,
+			.max_height = 65472,
+			.step_height = 16,
+		},
+		.ctrls = &vdpu38x_hevc_ctrls,
+		.ops = &rkvdec_vdpu381_hevc_fmt_ops,
+		.num_decoded_fmts = ARRAY_SIZE(rkvdec_hevc_decoded_fmts),
+		.decoded_fmts = rkvdec_hevc_decoded_fmts,
+		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
+	},
 	{
 		.fourcc = V4L2_PIX_FMT_H264_SLICE,
 		.frmsize = {
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
index a76bc270d0062..ad19f6ae562d3 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
@@ -154,6 +154,8 @@ struct rkvdec_ctx {
 	struct rkvdec_rcb_config *rcb_config;
 	u32 colmv_offset;
 	void *priv;
+	u8 has_sps_st_rps: 1;
+	u8 has_sps_lt_rps: 1;
 };
 
 static inline struct rkvdec_ctx *file_to_rkvdec_ctx(struct file *filp)
@@ -186,6 +188,7 @@ extern const struct rkvdec_coded_fmt_ops rkvdec_vp9_fmt_ops;
 
 /* VDPU381 ops */
 extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_h264_fmt_ops;
+extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_hevc_fmt_ops;
 
 /* VDPU383 ops */
 extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu383_h264_fmt_ops;
-- 
2.52.0



From detlev.casanova at collabora.com  Thu Dec 18 15:28:16 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Thu, 18 Dec 2025 18:28:16 -0500
Subject: [PATCH v7 06/17] media: rkvdec: Use structs to represent the HW RPS
In-Reply-To: <20251218232829.337811-1-detlev.casanova@collabora.com>
References: <20251218232829.337811-1-detlev.casanova@collabora.com>
Message-ID: <20251218232829.337811-7-detlev.casanova@collabora.com>

This is in preparation to add support for other variants of the decoder.

Moving to struct representation is mainly to prepare for multicore
support that is present in e.g. rk3588.

Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../platform/rockchip/rkvdec/rkvdec-h264.c    | 93 +++++++++++++++++--
 1 file changed, 84 insertions(+), 9 deletions(-)

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
index 088840248a76b..fd941e9262796 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
@@ -19,7 +19,6 @@ extern const s8 rkvdec_h264_cabac_table[4][464][2];
 
 /* Size with u32 units. */
 #define RKV_CABAC_INIT_BUFFER_SIZE	(3680 + 128)
-#define RKV_RPS_SIZE			((128 + 128) / 4)
 #define RKV_ERROR_INFO_SIZE		(256 * 144 * 4)
 
 #define RKVDEC_NUM_REFLIST		3
@@ -34,6 +33,40 @@ struct rkvdec_sps_pps_packet {
 	u32 info[8];
 };
 
+struct rkvdec_rps_entry {
+	u32 dpb_info0:          5;
+	u32 bottom_flag0:       1;
+	u32 view_index_off0:    1;
+	u32 dpb_info1:          5;
+	u32 bottom_flag1:       1;
+	u32 view_index_off1:    1;
+	u32 dpb_info2:          5;
+	u32 bottom_flag2:       1;
+	u32 view_index_off2:    1;
+	u32 dpb_info3:          5;
+	u32 bottom_flag3:       1;
+	u32 view_index_off3:    1;
+	u32 dpb_info4:          5;
+	u32 bottom_flag4:       1;
+	u32 view_index_off4:    1;
+	u32 dpb_info5:          5;
+	u32 bottom_flag5:       1;
+	u32 view_index_off5:    1;
+	u32 dpb_info6:          5;
+	u32 bottom_flag6:       1;
+	u32 view_index_off6:    1;
+	u32 dpb_info7:          5;
+	u32 bottom_flag7:       1;
+	u32 view_index_off7:    1;
+} __packed;
+
+struct rkvdec_rps {
+	u16 frame_num[16];
+	u32 reserved0;
+	struct rkvdec_rps_entry entries[12];
+	u32 reserved1[66];
+} __packed;
+
 struct rkvdec_ps_field {
 	u16 offset;
 	u8 len;
@@ -94,7 +127,7 @@ struct rkvdec_ps_field {
 struct rkvdec_h264_priv_tbl {
 	s8 cabac_table[4][464][2];
 	struct rkvdec_h264_scaling_list scaling_list;
-	u32 rps[RKV_RPS_SIZE];
+	struct rkvdec_rps rps;
 	struct rkvdec_sps_pps_packet param_set[256];
 	u8 err_info[RKV_ERROR_INFO_SIZE];
 };
@@ -260,6 +293,51 @@ static void lookup_ref_buf_idx(struct rkvdec_ctx *ctx,
 	}
 }
 
+static void set_dpb_info(struct rkvdec_rps_entry *entries,
+			 u8 reflist,
+			 u8 refnum,
+			 u8 info,
+			 bool bottom)
+{
+	struct rkvdec_rps_entry *entry = &entries[(reflist * 4) + refnum / 8];
+	u8 idx = refnum % 8;
+
+	switch (idx) {
+	case 0:
+		entry->dpb_info0 = info;
+		entry->bottom_flag0 = bottom;
+		break;
+	case 1:
+		entry->dpb_info1 = info;
+		entry->bottom_flag1 = bottom;
+		break;
+	case 2:
+		entry->dpb_info2 = info;
+		entry->bottom_flag2 = bottom;
+		break;
+	case 3:
+		entry->dpb_info3 = info;
+		entry->bottom_flag3 = bottom;
+		break;
+	case 4:
+		entry->dpb_info4 = info;
+		entry->bottom_flag4 = bottom;
+		break;
+	case 5:
+		entry->dpb_info5 = info;
+		entry->bottom_flag5 = bottom;
+		break;
+	case 6:
+		entry->dpb_info6 = info;
+		entry->bottom_flag6 = bottom;
+		break;
+	case 7:
+		entry->dpb_info7 = info;
+		entry->bottom_flag7 = bottom;
+		break;
+	}
+}
+
 static void assemble_hw_rps(struct rkvdec_ctx *ctx,
 			    struct v4l2_h264_reflist_builder *builder,
 			    struct rkvdec_h264_run *run)
@@ -269,11 +347,10 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx,
 	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
 	struct rkvdec_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu;
 
-	u32 *hw_rps = priv_tbl->rps;
+	struct rkvdec_rps *hw_rps = &priv_tbl->rps;
 	u32 i, j;
-	u16 *p = (u16 *)hw_rps;
 
-	memset(hw_rps, 0, sizeof(priv_tbl->rps));
+	memset(hw_rps, 0, sizeof(*hw_rps));
 
 	/*
 	 * Assign an invalid pic_num if DPB entry at that position is inactive.
@@ -285,7 +362,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx,
 		if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
 			continue;
 
-		p[i] = builder->refs[i].frame_num;
+		hw_rps->frame_num[i] = builder->refs[i].frame_num;
 	}
 
 	for (j = 0; j < RKVDEC_NUM_REFLIST; j++) {
@@ -312,9 +389,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx,
 			dpb_valid = run->ref_buf[ref->index] != NULL;
 			bottom = ref->fields == V4L2_H264_BOTTOM_FIELD_REF;
 
-			set_ps_field(hw_rps, DPB_INFO(i, j),
-				     ref->index | dpb_valid << 4);
-			set_ps_field(hw_rps, BOTTOM_FLAG(i, j), bottom);
+			set_dpb_info(hw_rps->entries, j, i, ref->index | (dpb_valid << 4), bottom);
 		}
 	}
 }
-- 
2.52.0



From detlev.casanova at collabora.com  Thu Dec 18 15:28:27 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Thu, 18 Dec 2025 18:28:27 -0500
Subject: [PATCH v7 17/17] media: rkvdec: Add HEVC support for the VDPU383 variant
In-Reply-To: <20251218232829.337811-1-detlev.casanova@collabora.com>
References: <20251218232829.337811-1-detlev.casanova@collabora.com>
Message-ID: <20251218232829.337811-18-detlev.casanova@collabora.com>

The VDPU383 decoder is used on the RK3576 SoC and has support for HEVC.

This patch also moves some functions to a common rkvdec-hevc-common.c
file and adds a specific scaling matrix flatten function.

The fluster score for JCT-VC-HEVC_V1 is 146/147.

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 .../media/platform/rockchip/rkvdec/Makefile   |   1 +
 .../rockchip/rkvdec/rkvdec-hevc-common.c      |  59 +-
 .../rockchip/rkvdec/rkvdec-hevc-common.h      |   3 +-
 .../platform/rockchip/rkvdec/rkvdec-hevc.c    |   2 +-
 .../rockchip/rkvdec/rkvdec-vdpu381-hevc.c     |   3 +-
 .../rockchip/rkvdec/rkvdec-vdpu383-hevc.c     | 720 ++++++++++++++++++
 .../media/platform/rockchip/rkvdec/rkvdec.c   |  91 +++
 .../media/platform/rockchip/rkvdec/rkvdec.h   |   2 +
 8 files changed, 833 insertions(+), 48 deletions(-)
 create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c

diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
index e30fdd7d51c3c..e629d571e4d89 100644
--- a/drivers/media/platform/rockchip/rkvdec/Makefile
+++ b/drivers/media/platform/rockchip/rkvdec/Makefile
@@ -11,4 +11,5 @@ rockchip-vdec-y += \
 		   rkvdec-vdpu381-h264.o \
 		   rkvdec-vdpu381-hevc.o \
 		   rkvdec-vdpu383-h264.o \
+		   rkvdec-vdpu383-hevc.o \
 		   rkvdec-vp9.o
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
index 52926c67d0189..81f41bf661d35 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
@@ -140,56 +140,26 @@ static void set_ref_poc(struct rkvdec_rps_short_term_ref_set *set, int poc, int
 	}
 }
 
-/*
- * Flip one or more matrices along their main diagonal and flatten them
- * before writing it to the memory.
- * Convert:
- * ABCD         AEIM
- * EFGH     =>  BFJN     =>     AEIMBFJNCGKODHLP
- * IJKL         CGKO
- * MNOP         DHLP
- */
-static void transpose_and_flatten_matrices(u8 *output, const u8 *input,
-					   int matrices, int row_length)
-{
-	int i, j, row, x_offset, matrix_offset, rot_index, y_offset, matrix_size, new_value;
-
-	matrix_size = row_length * row_length;
-	for (i = 0; i < matrices; i++) {
-		row = 0;
-		x_offset = 0;
-		matrix_offset = i * matrix_size;
-		for (j = 0; j < matrix_size; j++) {
-			y_offset = j - (row * row_length);
-			rot_index = y_offset * row_length + x_offset;
-			new_value = *(input + i * matrix_size + j);
-			output[matrix_offset + rot_index] = new_value;
-			if ((j + 1) % row_length == 0) {
-				row += 1;
-				x_offset += 1;
-			}
-		}
-	}
-}
-
-static void assemble_scalingfactor0(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input)
+static void assemble_scalingfactor0(struct rkvdec_ctx *ctx, u8 *output,
+				    const struct v4l2_ctrl_hevc_scaling_matrix *input)
 {
+	const struct rkvdec_variant *variant = ctx->dev->variant;
 	int offset = 0;
 
-	transpose_and_flatten_matrices(output, (const u8 *)input->scaling_list_4x4, 6, 4);
+	variant->ops->flatten_matrices(output, (const u8 *)input->scaling_list_4x4, 6, 4);
 	offset = 6 * 16 * sizeof(u8);
-	transpose_and_flatten_matrices(output + offset, (const u8 *)input->scaling_list_8x8, 6, 8);
+	variant->ops->flatten_matrices(output + offset, (const u8 *)input->scaling_list_8x8, 6, 8);
 	offset += 6 * 64 * sizeof(u8);
-	transpose_and_flatten_matrices(output + offset,
-				       (const u8 *)input->scaling_list_16x16, 6, 8);
+	variant->ops->flatten_matrices(output + offset, (const u8 *)input->scaling_list_16x16,
+				       6, 8);
 	offset += 6 * 64 * sizeof(u8);
 	/* Add a 128 byte padding with 0s between the two 32x32 matrices */
-	transpose_and_flatten_matrices(output + offset,
-				       (const u8 *)input->scaling_list_32x32, 1, 8);
+	variant->ops->flatten_matrices(output + offset, (const u8 *)input->scaling_list_32x32,
+				       1, 8);
 	offset += 64 * sizeof(u8);
 	memset(output + offset, 0, 128);
 	offset += 128 * sizeof(u8);
-	transpose_and_flatten_matrices(output + offset,
+	variant->ops->flatten_matrices(output + offset,
 				       (const u8 *)input->scaling_list_32x32 + (64 * sizeof(u8)),
 				       1, 8);
 	offset += 64 * sizeof(u8);
@@ -214,16 +184,17 @@ static void assemble_scalingdc(u8 *output, const struct v4l2_ctrl_hevc_scaling_m
 	memcpy(output + 6 * sizeof(u8), list_32x32, 6 * sizeof(u8));
 }
 
-static void translate_scaling_list(struct scaling_factor *output,
+static void translate_scaling_list(struct rkvdec_ctx *ctx, struct scaling_factor *output,
 				   const struct v4l2_ctrl_hevc_scaling_matrix *input)
 {
-	assemble_scalingfactor0(output->scalingfactor0, input);
+	assemble_scalingfactor0(ctx, output->scalingfactor0, input);
 	memcpy(output->scalingfactor1, (const u8 *)input->scaling_list_4x4, 96);
 	assemble_scalingdc(output->scalingdc, input);
 	memset(output->reserved, 0, 4 * sizeof(u8));
 }
 
-void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
+void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_ctx *ctx,
+					  struct rkvdec_hevc_run *run,
 					  struct scaling_factor *scaling_factor,
 					  struct v4l2_ctrl_hevc_scaling_matrix *cache)
 {
@@ -233,7 +204,7 @@ void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
 		    sizeof(struct v4l2_ctrl_hevc_scaling_matrix)))
 		return;
 
-	translate_scaling_list(scaling_factor, scaling);
+	translate_scaling_list(ctx, scaling_factor, scaling);
 
 	memcpy(cache, scaling,
 	       sizeof(struct v4l2_ctrl_hevc_scaling_matrix));
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
index 0d7498e6a112a..96521d7234776 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.h
@@ -97,7 +97,8 @@ void compute_tiles_non_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size
 			       s32 pic_in_cts_height, u16 *column_width, u16 *row_height);
 void rkvdec_hevc_assemble_hw_rps(struct rkvdec_hevc_run *run, struct rkvdec_rps *rps,
 				 struct v4l2_ctrl_hevc_ext_sps_st_rps *st_cache);
-void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_hevc_run *run,
+void rkvdec_hevc_assemble_hw_scaling_list(struct rkvdec_ctx *ctx,
+					  struct rkvdec_hevc_run *run,
 					  struct scaling_factor *scaling_factor,
 					  struct v4l2_ctrl_hevc_scaling_matrix *cache);
 struct vb2_buffer *get_ref_buf(struct rkvdec_ctx *ctx,
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
index 156ce381f0680..89b70ca27127f 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
@@ -567,7 +567,7 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
 
 	rkvdec_hevc_run_preamble(ctx, &run);
 
-	rkvdec_hevc_assemble_hw_scaling_list(&run, &tbl->scaling_list,
+	rkvdec_hevc_assemble_hw_scaling_list(ctx, &run, &tbl->scaling_list,
 					     &hevc_ctx->scaling_matrix_cache);
 	assemble_hw_pps(ctx, &run);
 	assemble_sw_rps(ctx, &run);
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
index 6a73f587bdd1d..c342c7838040f 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
@@ -586,8 +586,7 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
 		dev_warn_ratelimited(rkvdec->dev, "Long and short term RPS not set\n");
 	}
 
-	rkvdec_hevc_assemble_hw_scaling_list(&run,
-					     &tbl->scaling_list,
+	rkvdec_hevc_assemble_hw_scaling_list(ctx, &run, &tbl->scaling_list,
 					     &hevc_ctx->scaling_matrix_cache);
 	assemble_hw_pps(ctx, &run);
 	rkvdec_hevc_assemble_hw_rps(&run, &tbl->rps, &hevc_ctx->st_cache);
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c
new file mode 100644
index 0000000000000..26c49f79f07f5
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c
@@ -0,0 +1,720 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip VDPU383 HEVC backend
+ *
+ * Copyright (C) 2025 Collabora, Ltd.
+ *  Detlev Casanova <detlev.casanova at collabora.com>
+ */
+
+#include <media/v4l2-mem2mem.h>
+
+#include "rkvdec.h"
+#include "rkvdec-rcb.h"
+#include "rkvdec-hevc-common.h"
+#include "rkvdec-vdpu383-regs.h"
+
+struct rkvdec_hevc_sps_pps {
+	// SPS
+	u16 video_parameters_set_id			: 4;
+	u16 seq_parameters_set_id_sps			: 4;
+	u16 chroma_format_idc				: 2;
+	u16 width					: 16;
+	u16 height					: 16;
+	u16 bit_depth_luma				: 3;
+	u16 bit_depth_chroma				: 3;
+	u16 max_pic_order_count_lsb			: 5;
+	u16 diff_max_min_luma_coding_block_size		: 2;
+	u16 min_luma_coding_block_size			: 3;
+	u16 min_transform_block_size			: 3;
+	u16 diff_max_min_transform_block_size		: 2;
+	u16 max_transform_hierarchy_depth_inter		: 3;
+	u16 max_transform_hierarchy_depth_intra		: 3;
+	u16 scaling_list_enabled_flag			: 1;
+	u16 amp_enabled_flag				: 1;
+	u16 sample_adaptive_offset_enabled_flag		: 1;
+	u16 pcm_enabled_flag				: 1;
+	u16 pcm_sample_bit_depth_luma			: 4;
+	u16 pcm_sample_bit_depth_chroma			: 4;
+	u16 pcm_loop_filter_disabled_flag		: 1;
+	u16 diff_max_min_pcm_luma_coding_block_size	: 3;
+	u16 min_pcm_luma_coding_block_size		: 3;
+	u16 num_short_term_ref_pic_sets			: 7;
+	u16 long_term_ref_pics_present_flag		: 1;
+	u16 num_long_term_ref_pics_sps			: 6;
+	u16 sps_temporal_mvp_enabled_flag		: 1;
+	u16 strong_intra_smoothing_enabled_flag		: 1;
+	u16 reserved0					: 7;
+	u16 sps_max_dec_pic_buffering_minus1		: 4;
+	u16 separate_colour_plane_flag			: 1;
+	u16 high_precision_offsets_enabled_flag		: 1;
+	u16 persistent_rice_adaptation_enabled_flag	: 1;
+
+	// PPS
+	u16 picture_parameters_set_id			: 6;
+	u16 seq_parameters_set_id_pps			: 4;
+	u16 dependent_slice_segments_enabled_flag	: 1;
+	u16 output_flag_present_flag			: 1;
+	u16 num_extra_slice_header_bits			: 13;
+	u16 sign_data_hiding_enabled_flag		: 1;
+	u16 cabac_init_present_flag			: 1;
+	u16 num_ref_idx_l0_default_active		: 4;
+	u16 num_ref_idx_l1_default_active		: 4;
+	u16 init_qp_minus26				: 7;
+	u16 constrained_intra_pred_flag			: 1;
+	u16 transform_skip_enabled_flag			: 1;
+	u16 cu_qp_delta_enabled_flag			: 1;
+	u16 log2_min_cb_size				: 3;
+	u16 pps_cb_qp_offset				: 5;
+	u16 pps_cr_qp_offset				: 5;
+	u16 pps_slice_chroma_qp_offsets_present_flag	: 1;
+	u16 weighted_pred_flag				: 1;
+	u16 weighted_bipred_flag			: 1;
+	u16 transquant_bypass_enabled_flag		: 1;
+	u16 tiles_enabled_flag				: 1;
+	u16 entropy_coding_sync_enabled_flag		: 1;
+	u16 pps_loop_filter_across_slices_enabled_flag	: 1;
+	u16 loop_filter_across_tiles_enabled_flag	: 1;
+	u16 deblocking_filter_override_enabled_flag	: 1;
+	u16 pps_deblocking_filter_disabled_flag		: 1;
+	u16 pps_beta_offset_div2			: 4;
+	u16 pps_tc_offset_div2				: 4;
+	u16 lists_modification_present_flag		: 1;
+	u16 log2_parallel_merge_level			: 3;
+	u16 slice_segment_header_extension_present_flag	: 1;
+	u16 reserved1					: 3;
+
+	// pps extensions
+	u16 log2_max_transform_skip_block_size		: 2;
+	u16 cross_component_prediction_enabled_flag	: 1;
+	u16 chroma_qp_offset_list_enabled_flag		: 1;
+	u16 log2_min_cu_chroma_qp_delta_size		: 3;
+	u16 cb_qp_offset_list0				: 5;
+	u16 cb_qp_offset_list1				: 5;
+	u16 cb_qp_offset_list2				: 5;
+	u16 cb_qp_offset_list3				: 5;
+	u16 cb_qp_offset_list4				: 5;
+	u16 cb_qp_offset_list5				: 5;
+	u16 cb_cr_offset_list0				: 5;
+	u16 cb_cr_offset_list1				: 5;
+	u16 cb_cr_offset_list2				: 5;
+	u16 cb_cr_offset_list3				: 5;
+	u16 cb_cr_offset_list4				: 5;
+	u16 cb_cr_offset_list5				: 5;
+	u16 chroma_qp_offset_list_len_minus1		: 3;
+
+	/* mvc0 && mvc1 */
+	u16 mvc_ff					: 16;
+	u16 mvc_00					: 9;
+
+	/* poc info */
+	u16 reserved2					: 3;
+	u32 current_poc					: 32;
+	u32 ref_pic_poc0				: 32;
+	u32 ref_pic_poc1				: 32;
+	u32 ref_pic_poc2				: 32;
+	u32 ref_pic_poc3				: 32;
+	u32 ref_pic_poc4				: 32;
+	u32 ref_pic_poc5				: 32;
+	u32 ref_pic_poc6				: 32;
+	u32 ref_pic_poc7				: 32;
+	u32 ref_pic_poc8				: 32;
+	u32 ref_pic_poc9				: 32;
+	u32 ref_pic_poc10				: 32;
+	u32 ref_pic_poc11				: 32;
+	u32 ref_pic_poc12				: 32;
+	u32 ref_pic_poc13				: 32;
+	u32 ref_pic_poc14				: 32;
+	u32 reserved3					: 32;
+	u32 ref_is_valid				: 15;
+	u32 reserved4					: 1;
+
+	/* tile info*/
+	u16 num_tile_columns				: 5;
+	u16 num_tile_rows				: 5;
+	u32 column_width0				: 24;
+	u32 column_width1				: 24;
+	u32 column_width2				: 24;
+	u32 column_width3				: 24;
+	u32 column_width4				: 24;
+	u32 column_width5				: 24;
+	u32 column_width6				: 24;
+	u32 column_width7				: 24;
+	u32 column_width8				: 24;
+	u32 column_width9				: 24;
+	u32 row_height0					: 24;
+	u32 row_height1					: 24;
+	u32 row_height2					: 24;
+	u32 row_height3					: 24;
+	u32 row_height4					: 24;
+	u32 row_height5					: 24;
+	u32 row_height6					: 24;
+	u32 row_height7					: 24;
+	u32 row_height8					: 24;
+	u32 row_height9					: 24;
+	u32 row_height10				: 24;
+	u32 reserved5					: 2;
+	u32 padding;
+} __packed;
+
+struct rkvdec_hevc_priv_tbl {
+	struct rkvdec_hevc_sps_pps param_set;
+	struct rkvdec_rps rps;
+	struct scaling_factor scaling_list;
+	u8 cabac_table[27456];
+}  __packed;
+
+struct rkvdec_hevc_ctx {
+	struct rkvdec_aux_buf			priv_tbl;
+	struct v4l2_ctrl_hevc_scaling_matrix	scaling_matrix_cache;
+	struct v4l2_ctrl_hevc_ext_sps_st_rps	st_cache;
+	struct vdpu383_regs_h26x		regs;
+};
+
+static void set_column_row(struct rkvdec_hevc_sps_pps *hw_ps, u16 column, u16 row, int i)
+{
+	int shift = (i & 1) ? 12 : 0;
+
+	switch (i / 2) {
+	case 0:
+		hw_ps->column_width0 |= column << shift;
+		hw_ps->row_height0 |= row << shift;
+		break;
+	case 1:
+		hw_ps->column_width1 |= column << shift;
+		hw_ps->row_height1 |= row << shift;
+		break;
+	case 2:
+		hw_ps->column_width2 |= column << shift;
+		hw_ps->row_height2 |= row << shift;
+		break;
+	case 3:
+		hw_ps->column_width3 |= column << shift;
+		hw_ps->row_height3 |= row << shift;
+		break;
+	case 4:
+		hw_ps->column_width4 |= column << shift;
+		hw_ps->row_height4 |= row << shift;
+		break;
+	case 5:
+		hw_ps->column_width5 |= column << shift;
+		hw_ps->row_height5 |= row << shift;
+		break;
+	case 6:
+		hw_ps->column_width6 |= column << shift;
+		hw_ps->row_height6 |= row << shift;
+		break;
+	case 7:
+		hw_ps->column_width7 |= column << shift;
+		hw_ps->row_height7 |= row << shift;
+		break;
+	case 8:
+		hw_ps->column_width8 |= column << shift;
+		hw_ps->row_height8 |= row << shift;
+		break;
+	case 9:
+		hw_ps->column_width9 |= column << shift;
+		hw_ps->row_height9 |= row << shift;
+		break;
+	case 10:
+		hw_ps->row_height10 |= row << shift;
+		break;
+	}
+}
+
+static void set_pps_ref_pic_poc(struct rkvdec_hevc_sps_pps *hw_ps, u32 poc, int i)
+{
+	switch (i) {
+	case 0:
+		hw_ps->ref_pic_poc0 = poc;
+		break;
+	case 1:
+		hw_ps->ref_pic_poc1 = poc;
+		break;
+	case 2:
+		hw_ps->ref_pic_poc2 = poc;
+		break;
+	case 3:
+		hw_ps->ref_pic_poc3 = poc;
+		break;
+	case 4:
+		hw_ps->ref_pic_poc4 = poc;
+		break;
+	case 5:
+		hw_ps->ref_pic_poc5 = poc;
+		break;
+	case 6:
+		hw_ps->ref_pic_poc6 = poc;
+		break;
+	case 7:
+		hw_ps->ref_pic_poc7 = poc;
+		break;
+	case 8:
+		hw_ps->ref_pic_poc8 = poc;
+		break;
+	case 9:
+		hw_ps->ref_pic_poc9 = poc;
+		break;
+	case 10:
+		hw_ps->ref_pic_poc10 = poc;
+		break;
+	case 11:
+		hw_ps->ref_pic_poc11 = poc;
+		break;
+	case 12:
+		hw_ps->ref_pic_poc12 = poc;
+		break;
+	case 13:
+		hw_ps->ref_pic_poc13 = poc;
+		break;
+	case 14:
+		hw_ps->ref_pic_poc14 = poc;
+		break;
+	}
+}
+
+static void assemble_hw_pps(struct rkvdec_ctx *ctx,
+			    struct rkvdec_hevc_run *run)
+{
+	struct rkvdec_hevc_ctx *h264_ctx = ctx->priv;
+	const struct v4l2_ctrl_hevc_sps *sps = run->sps;
+	const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+	const struct v4l2_ctrl_hevc_decode_params *dec_params = run->decode_params;
+	struct rkvdec_hevc_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu;
+	struct rkvdec_hevc_sps_pps *hw_ps;
+	bool tiles_enabled;
+	s32 max_cu_width;
+	s32 pic_in_cts_width;
+	s32 pic_in_cts_height;
+	u16 log2_min_cb_size, width, height;
+	u16 column_width[22];
+	u16 row_height[22];
+	u8 pcm_enabled;
+	u32 i;
+
+	/*
+	 * HW read the SPS/PPS information from PPS packet index by PPS id.
+	 * offset from the base can be calculated by PPS_id * 32 (size per PPS
+	 * packet unit). so the driver copy SPS/PPS information to the exact PPS
+	 * packet unit for HW accessing.
+	 */
+	hw_ps = &priv_tbl->param_set;
+	memset(hw_ps, 0, sizeof(*hw_ps));
+
+	/* write sps */
+	hw_ps->video_parameters_set_id = sps->video_parameter_set_id;
+	hw_ps->seq_parameters_set_id_sps = sps->seq_parameter_set_id;
+	hw_ps->chroma_format_idc = sps->chroma_format_idc;
+
+	log2_min_cb_size = sps->log2_min_luma_coding_block_size_minus3 + 3;
+	width = sps->pic_width_in_luma_samples;
+	height = sps->pic_height_in_luma_samples;
+	hw_ps->width = width;
+	hw_ps->height = height;
+	hw_ps->bit_depth_luma = sps->bit_depth_luma_minus8 + 8;
+	hw_ps->bit_depth_chroma = sps->bit_depth_chroma_minus8 + 8;
+	hw_ps->max_pic_order_count_lsb = sps->log2_max_pic_order_cnt_lsb_minus4 + 4;
+	hw_ps->diff_max_min_luma_coding_block_size = sps->log2_diff_max_min_luma_coding_block_size;
+	hw_ps->min_luma_coding_block_size = sps->log2_min_luma_coding_block_size_minus3 + 3;
+	hw_ps->min_transform_block_size = sps->log2_min_luma_transform_block_size_minus2 + 2;
+	hw_ps->diff_max_min_transform_block_size =
+		sps->log2_diff_max_min_luma_transform_block_size;
+	hw_ps->max_transform_hierarchy_depth_inter = sps->max_transform_hierarchy_depth_inter;
+	hw_ps->max_transform_hierarchy_depth_intra = sps->max_transform_hierarchy_depth_intra;
+	hw_ps->scaling_list_enabled_flag =
+		!!(sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED);
+	hw_ps->amp_enabled_flag = !!(sps->flags & V4L2_HEVC_SPS_FLAG_AMP_ENABLED);
+	hw_ps->sample_adaptive_offset_enabled_flag =
+		!!(sps->flags & V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET);
+
+	pcm_enabled = !!(sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED);
+	hw_ps->pcm_enabled_flag = pcm_enabled;
+	hw_ps->pcm_sample_bit_depth_luma =
+		pcm_enabled ? sps->pcm_sample_bit_depth_luma_minus1 + 1 : 0;
+	hw_ps->pcm_sample_bit_depth_chroma =
+		pcm_enabled ? sps->pcm_sample_bit_depth_chroma_minus1 + 1 : 0;
+	hw_ps->pcm_loop_filter_disabled_flag =
+		!!(sps->flags & V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED);
+	hw_ps->diff_max_min_pcm_luma_coding_block_size =
+		sps->log2_diff_max_min_pcm_luma_coding_block_size;
+	hw_ps->min_pcm_luma_coding_block_size =
+		pcm_enabled ? sps->log2_min_pcm_luma_coding_block_size_minus3 + 3 : 0;
+	hw_ps->num_short_term_ref_pic_sets = sps->num_short_term_ref_pic_sets;
+	hw_ps->long_term_ref_pics_present_flag =
+		!!(sps->flags & V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT);
+	hw_ps->num_long_term_ref_pics_sps = sps->num_long_term_ref_pics_sps;
+	hw_ps->sps_temporal_mvp_enabled_flag =
+		!!(sps->flags & V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED);
+	hw_ps->strong_intra_smoothing_enabled_flag =
+		!!(sps->flags & V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED);
+	hw_ps->sps_max_dec_pic_buffering_minus1 = sps->sps_max_dec_pic_buffering_minus1;
+
+	/* write pps */
+	hw_ps->picture_parameters_set_id = pps->pic_parameter_set_id;
+	hw_ps->seq_parameters_set_id_pps = sps->seq_parameter_set_id;
+	hw_ps->dependent_slice_segments_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED);
+	hw_ps->output_flag_present_flag = !!(pps->flags & V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT);
+	hw_ps->num_extra_slice_header_bits = pps->num_extra_slice_header_bits;
+	hw_ps->sign_data_hiding_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED);
+	hw_ps->cabac_init_present_flag = !!(pps->flags & V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT);
+	hw_ps->num_ref_idx_l0_default_active = pps->num_ref_idx_l0_default_active_minus1 + 1;
+	hw_ps->num_ref_idx_l1_default_active = pps->num_ref_idx_l1_default_active_minus1 + 1;
+	hw_ps->init_qp_minus26 = pps->init_qp_minus26;
+	hw_ps->constrained_intra_pred_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED);
+	hw_ps->transform_skip_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED);
+	hw_ps->cu_qp_delta_enabled_flag = !!(pps->flags & V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED);
+	hw_ps->log2_min_cb_size = log2_min_cb_size +
+				  sps->log2_diff_max_min_luma_coding_block_size -
+				  pps->diff_cu_qp_delta_depth;
+	hw_ps->pps_cb_qp_offset = pps->pps_cb_qp_offset;
+	hw_ps->pps_cr_qp_offset = pps->pps_cr_qp_offset;
+	hw_ps->pps_slice_chroma_qp_offsets_present_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT);
+	hw_ps->weighted_pred_flag = !!(pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED);
+	hw_ps->weighted_bipred_flag = !!(pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED);
+	hw_ps->transquant_bypass_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED);
+	tiles_enabled = !!(pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED);
+	hw_ps->tiles_enabled_flag = tiles_enabled;
+	hw_ps->entropy_coding_sync_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED);
+	hw_ps->pps_loop_filter_across_slices_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED);
+	hw_ps->loop_filter_across_tiles_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED);
+	hw_ps->deblocking_filter_override_enabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED);
+	hw_ps->pps_deblocking_filter_disabled_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER);
+	hw_ps->pps_beta_offset_div2 = pps->pps_beta_offset_div2;
+	hw_ps->pps_tc_offset_div2 = pps->pps_tc_offset_div2;
+	hw_ps->lists_modification_present_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT);
+	hw_ps->log2_parallel_merge_level = pps->log2_parallel_merge_level_minus2 + 2;
+	hw_ps->slice_segment_header_extension_present_flag =
+		!!(pps->flags & V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT);
+	hw_ps->num_tile_columns = tiles_enabled ? pps->num_tile_columns_minus1 + 1 : 1;
+	hw_ps->num_tile_rows = tiles_enabled ? pps->num_tile_rows_minus1 + 1 : 1;
+	hw_ps->mvc_ff = 0xffff;
+
+	// Setup tiles information
+	memset(column_width, 0, sizeof(column_width));
+	memset(row_height, 0, sizeof(row_height));
+
+	max_cu_width = 1 << (sps->log2_diff_max_min_luma_coding_block_size + log2_min_cb_size);
+	pic_in_cts_width = (width + max_cu_width - 1) / max_cu_width;
+	pic_in_cts_height = (height + max_cu_width - 1) / max_cu_width;
+
+	if (tiles_enabled) {
+		if (pps->flags & V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING) {
+			compute_tiles_uniform(run, log2_min_cb_size, width, height,
+					      pic_in_cts_width, pic_in_cts_height,
+					      column_width, row_height);
+		} else {
+			compute_tiles_non_uniform(run, log2_min_cb_size, width, height,
+						  pic_in_cts_width, pic_in_cts_height,
+						  column_width, row_height);
+		}
+	} else {
+		column_width[0] = (width + max_cu_width - 1) / max_cu_width;
+		row_height[0] = (height + max_cu_width - 1) / max_cu_width;
+	}
+
+	for (i = 0; i < 22; i++)
+		set_column_row(hw_ps, column_width[i], row_height[i], i);
+
+	// Setup POC information
+	hw_ps->current_poc = dec_params->pic_order_cnt_val;
+
+	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
+		u32 valid = !!(dec_params->num_active_dpb_entries > i);
+
+		set_pps_ref_pic_poc(hw_ps, dec_params->dpb[i].pic_order_cnt_val, i);
+		hw_ps->ref_is_valid |= valid << i;
+	}
+}
+
+static void rkvdec_write_regs(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_hevc_ctx *h265_ctx = ctx->priv;
+
+	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_COMMON_REGS,
+			   &h265_ctx->regs.common,
+			   sizeof(h265_ctx->regs.common));
+	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_COMMON_ADDR_REGS,
+			   &h265_ctx->regs.common_addr,
+			   sizeof(h265_ctx->regs.common_addr));
+	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_CODEC_PARAMS_REGS,
+			   &h265_ctx->regs.h26x_params,
+			   sizeof(h265_ctx->regs.h26x_params));
+	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_CODEC_ADDR_REGS,
+			   &h265_ctx->regs.h26x_addr,
+			   sizeof(h265_ctx->regs.h26x_addr));
+}
+
+static void config_registers(struct rkvdec_ctx *ctx,
+			     struct rkvdec_hevc_run *run)
+{
+	const struct v4l2_ctrl_hevc_decode_params *dec_params = run->decode_params;
+	struct rkvdec_hevc_ctx *h265_ctx = ctx->priv;
+	const struct v4l2_ctrl_hevc_sps *sps = run->sps;
+	dma_addr_t priv_start_addr = h265_ctx->priv_tbl.dma;
+	const struct v4l2_pix_format_mplane *dst_fmt;
+	struct vb2_v4l2_buffer *src_buf = run->base.bufs.src;
+	struct vb2_v4l2_buffer *dst_buf = run->base.bufs.dst;
+	struct vdpu383_regs_h26x *regs = &h265_ctx->regs;
+	const struct v4l2_format *f;
+	dma_addr_t rlc_addr;
+	dma_addr_t dst_addr;
+	u32 hor_virstride;
+	u32 ver_virstride;
+	u32 y_virstride;
+	u32 offset;
+	u32 pixels;
+	u32 i;
+
+	memset(regs, 0, sizeof(*regs));
+
+	/* Set HEVC mode */
+	regs->common.reg008_dec_mode = VDPU383_MODE_HEVC;
+
+	/* Set input stream length */
+	regs->h26x_params.reg066_stream_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
+
+	/* Set strides */
+	f = &ctx->decoded_fmt;
+	dst_fmt = &f->fmt.pix_mp;
+	hor_virstride = dst_fmt->plane_fmt[0].bytesperline;
+	ver_virstride = dst_fmt->height;
+	y_virstride = hor_virstride * ver_virstride;
+
+	pixels = dst_fmt->height * dst_fmt->width;
+
+	regs->h26x_params.reg068_hor_virstride = hor_virstride / 16;
+	regs->h26x_params.reg069_raster_uv_hor_virstride = hor_virstride / 16;
+	regs->h26x_params.reg070_y_virstride = y_virstride / 16;
+
+	/* Activate block gating */
+	regs->common.reg010.strmd_auto_gating_e      = 1;
+	regs->common.reg010.inter_auto_gating_e      = 1;
+	regs->common.reg010.intra_auto_gating_e      = 1;
+	regs->common.reg010.transd_auto_gating_e     = 1;
+	regs->common.reg010.recon_auto_gating_e      = 1;
+	regs->common.reg010.filterd_auto_gating_e    = 1;
+	regs->common.reg010.bus_auto_gating_e	     = 1;
+	regs->common.reg010.ctrl_auto_gating_e       = 1;
+	regs->common.reg010.rcb_auto_gating_e	     = 1;
+	regs->common.reg010.err_prc_auto_gating_e    = 1;
+
+	/* Set timeout threshold */
+	if (pixels < RKVDEC_1080P_PIXELS)
+		regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_1080p;
+	else if (pixels < RKVDEC_4K_PIXELS)
+		regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_4K;
+	else if (pixels < RKVDEC_8K_PIXELS)
+		regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_8K;
+	else
+		regs->common.reg013_core_timeout_threshold = VDPU383_TIMEOUT_MAX;
+
+	regs->common.reg016.error_proc_disable = 1;
+
+	/* Set ref pic address & poc */
+	for (i = 0; i < ARRAY_SIZE(dec_params->dpb) - 1; i++) {
+		struct vb2_buffer *vb_buf = get_ref_buf(ctx, run, i);
+		dma_addr_t buf_dma;
+
+		buf_dma = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
+
+		/* Set reference addresses */
+		regs->h26x_addr.reg170_185_ref_base[i] = buf_dma;
+		regs->h26x_addr.reg195_210_payload_st_ref_base[i] = buf_dma;
+
+		/* Set COLMV addresses */
+		regs->h26x_addr.reg217_232_colmv_ref_base[i] = buf_dma + ctx->colmv_offset;
+	}
+
+	/* Set rlc base address (input stream) */
+	rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+	regs->common_addr.reg128_strm_base = rlc_addr;
+
+	/* Set output base address */
+	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
+	regs->h26x_addr.reg168_decout_base = dst_addr;
+	regs->h26x_addr.reg169_error_ref_base = dst_addr;
+	regs->h26x_addr.reg192_payload_st_cur_base = dst_addr;
+
+	/* Set colmv address */
+	regs->h26x_addr.reg216_colmv_cur_base = dst_addr + ctx->colmv_offset;
+
+	/* Set RCB addresses */
+	for (i = 0; i < rkvdec_rcb_buf_count(ctx); i++) {
+		regs->common_addr.reg140_162_rcb_info[i].offset = rkvdec_rcb_buf_dma_addr(ctx, i);
+		regs->common_addr.reg140_162_rcb_info[i].size = rkvdec_rcb_buf_size(ctx, i);
+	}
+
+	if (sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED) {
+		/* Set scaling matrix */
+		offset = offsetof(struct rkvdec_hevc_priv_tbl, scaling_list);
+		regs->common_addr.reg132_scanlist_addr = priv_start_addr + offset;
+	}
+
+	/* Set hw pps address */
+	offset = offsetof(struct rkvdec_hevc_priv_tbl, param_set);
+	regs->common_addr.reg131_gbl_base = priv_start_addr + offset;
+	regs->h26x_params.reg067_global_len = sizeof(struct rkvdec_hevc_sps_pps) / 16;
+
+	/* Set hw rps address */
+	offset = offsetof(struct rkvdec_hevc_priv_tbl, rps);
+	regs->common_addr.reg129_rps_base = priv_start_addr + offset;
+
+	/* Set cabac table */
+	offset = offsetof(struct rkvdec_hevc_priv_tbl, cabac_table);
+	regs->common_addr.reg130_cabactbl_base = priv_start_addr + offset;
+
+	rkvdec_write_regs(ctx);
+}
+
+static int rkvdec_hevc_validate_sps(struct rkvdec_ctx *ctx,
+				    const struct v4l2_ctrl_hevc_sps *sps)
+{
+	if (sps->chroma_format_idc != 1)
+		/* Only 4:2:0 is supported */
+		return -EINVAL;
+
+	if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
+		/* Luma and chroma bit depth mismatch */
+		return -EINVAL;
+
+	if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2)
+		/* Only 8-bit and 10-bit are supported */
+		return -EINVAL;
+
+	if (sps->pic_width_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.width ||
+	    sps->pic_height_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.height)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int rkvdec_hevc_start(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_hevc_priv_tbl *priv_tbl;
+	struct rkvdec_hevc_ctx *hevc_ctx;
+	struct v4l2_ctrl *ctrl;
+	int ret;
+
+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+			      V4L2_CID_STATELESS_HEVC_SPS);
+	if (!ctrl)
+		return -EINVAL;
+
+	ret = rkvdec_hevc_validate_sps(ctx, ctrl->p_new.p_hevc_sps);
+	if (ret)
+		return ret;
+
+	hevc_ctx = kzalloc(sizeof(*hevc_ctx), GFP_KERNEL);
+	if (!hevc_ctx)
+		return -ENOMEM;
+
+	priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl),
+				      &hevc_ctx->priv_tbl.dma, GFP_KERNEL);
+	if (!priv_tbl) {
+		ret = -ENOMEM;
+		goto err_free_ctx;
+	}
+
+	hevc_ctx->priv_tbl.size = sizeof(*priv_tbl);
+	hevc_ctx->priv_tbl.cpu = priv_tbl;
+	memcpy(priv_tbl->cabac_table, rkvdec_hevc_cabac_table,
+	       sizeof(rkvdec_hevc_cabac_table));
+
+	ctx->priv = hevc_ctx;
+	return 0;
+
+err_free_ctx:
+	kfree(hevc_ctx);
+	return ret;
+}
+
+static void rkvdec_hevc_stop(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
+	struct rkvdec_dev *rkvdec = ctx->dev;
+
+	dma_free_coherent(rkvdec->dev, hevc_ctx->priv_tbl.size,
+			  hevc_ctx->priv_tbl.cpu, hevc_ctx->priv_tbl.dma);
+	kfree(hevc_ctx);
+}
+
+static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
+{
+	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_hevc_run run;
+	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
+	struct rkvdec_hevc_priv_tbl *tbl = hevc_ctx->priv_tbl.cpu;
+	u32 watchdog_time;
+	u64 timeout_threshold;
+	unsigned long axi_rate;
+
+	rkvdec_hevc_run_preamble(ctx, &run);
+
+	/*
+	 * On vdpu383, not setting the long and short term ref sets leads to IOMMU page faults.
+	 * To be on the safe side for this new v4l2 control, write an error in the log and mark
+	 * the buffer as failed by returning an error here.
+	 */
+	if ((!ctx->has_sps_lt_rps && run.sps->num_long_term_ref_pics_sps) ||
+		(!ctx->has_sps_st_rps && run.sps->num_short_term_ref_pic_sets)) {
+		dev_err_ratelimited(rkvdec->dev, "Long and short term RPS not set\n");
+		return -EINVAL;
+	}
+
+	rkvdec_hevc_assemble_hw_scaling_list(ctx, &run, &tbl->scaling_list,
+					     &hevc_ctx->scaling_matrix_cache);
+	assemble_hw_pps(ctx, &run);
+	rkvdec_hevc_assemble_hw_rps(&run, &tbl->rps, &hevc_ctx->st_cache);
+
+	config_registers(ctx, &run);
+
+	rkvdec_run_postamble(ctx, &run.base);
+
+	/* Set watchdog at 2 times the hardware timeout threshold */
+	timeout_threshold = hevc_ctx->regs.common.reg013_core_timeout_threshold;
+	axi_rate = clk_get_rate(rkvdec->axi_clk);
+
+	if (axi_rate)
+		watchdog_time = 2 * (1000 * timeout_threshold) / axi_rate;
+	else
+		watchdog_time = 2000;
+	schedule_delayed_work(&rkvdec->watchdog_work,
+			      msecs_to_jiffies(watchdog_time));
+
+	/* Start decoding! */
+	writel(timeout_threshold, rkvdec->link + VDPU383_LINK_TIMEOUT_THRESHOLD);
+	writel(VDPU383_IP_CRU_MODE, rkvdec->link + VDPU383_LINK_IP_ENABLE);
+	writel(VDPU383_DEC_E_BIT, rkvdec->link + VDPU383_LINK_DEC_ENABLE);
+
+	return 0;
+}
+
+static int rkvdec_hevc_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
+{
+	if (ctrl->id == V4L2_CID_STATELESS_HEVC_SPS)
+		return rkvdec_hevc_validate_sps(ctx, ctrl->p_new.p_hevc_sps);
+
+	return 0;
+}
+
+const struct rkvdec_coded_fmt_ops rkvdec_vdpu383_hevc_fmt_ops = {
+	.adjust_fmt = rkvdec_hevc_adjust_fmt,
+	.start = rkvdec_hevc_start,
+	.stop = rkvdec_hevc_stop,
+	.run = rkvdec_hevc_run,
+	.try_ctrl = rkvdec_hevc_try_ctrl,
+	.get_image_fmt = rkvdec_hevc_get_image_fmt,
+};
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index 8405ddb5962b8..e547057dc75f9 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -499,6 +499,22 @@ static const struct rkvdec_coded_fmt_desc vdpu381_coded_fmts[] = {
 };
 
 static const struct rkvdec_coded_fmt_desc vdpu383_coded_fmts[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_HEVC_SLICE,
+		.frmsize = {
+			.min_width = 64,
+			.max_width = 65472,
+			.step_width = 64,
+			.min_height = 64,
+			.max_height = 65472,
+			.step_height = 16,
+		},
+		.ctrls = &vdpu38x_hevc_ctrls,
+		.ops = &rkvdec_vdpu383_hevc_fmt_ops,
+		.num_decoded_fmts = ARRAY_SIZE(rkvdec_hevc_decoded_fmts),
+		.decoded_fmts = rkvdec_hevc_decoded_fmts,
+		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
+	},
 	{
 		.fourcc = V4L2_PIX_FMT_H264_SLICE,
 		.frmsize = {
@@ -1447,6 +1463,78 @@ static irqreturn_t rkvdec_irq_handler(int irq, void *priv)
 	return variant->ops->irq_handler(ctx);
 }
 
+/*
+ * Flip one or more matrices along their main diagonal and flatten them
+ * before writing it to the memory.
+ * Convert:
+ * ABCD         AEIM
+ * EFGH     =>  BFJN     =>     AEIMBFJNCGKODHLP
+ * IJKL         CGKO
+ * MNOP         DHLP
+ */
+static void transpose_and_flatten_matrices(u8 *output, const u8 *input,
+					   int matrices, int row_length)
+{
+	int i, j, row, x_offset, matrix_offset, rot_index, y_offset, matrix_size, new_value;
+
+	matrix_size = row_length * row_length;
+	for (i = 0; i < matrices; i++) {
+		row = 0;
+		x_offset = 0;
+		matrix_offset = i * matrix_size;
+		for (j = 0; j < matrix_size; j++) {
+			y_offset = j - (row * row_length);
+			rot_index = y_offset * row_length + x_offset;
+			new_value = *(input + i * matrix_size + j);
+			output[matrix_offset + rot_index] = new_value;
+			if ((j + 1) % row_length == 0) {
+				row += 1;
+				x_offset += 1;
+			}
+		}
+	}
+}
+
+/*
+ * VDPU383 needs a specific order:
+ * The 8x8 flatten matrix is based on 4x4 blocks.
+ * Each 4x4 block is written separately in order.
+ *
+ * Base data    =>  Transposed    VDPU383 transposed
+ *
+ * ABCDEFGH         AIQYaiqy      AIQYBJRZ
+ * IJKLMNOP         BJRZbjrz      CKS0DLT1
+ * QRSTUVWX         CKS0cks6      aiqybjrz
+ * YZ012345     =>  DLT1dlt7      cks6dlt7
+ * abcdefgh         EMU2emu8      EMU2FNV3
+ * ijklmnop         FNV3fnv9      GOW4HPX5
+ * qrstuvwx         GOW4gow#      emu8fnv9
+ * yz6789#$         HPX5hpx$      gow#hpx$
+ *
+ * As the function reads block of 4x4 it can be used for both 4x4 and 8x8 matrices.
+ *
+ */
+static void vdpu383_flatten_matrices(u8 *output, const u8 *input, int matrices, int row_length)
+{
+	u8 block;
+	int i, j, matrix_offset, matrix_size, new_value, input_idx, line_offset, block_offset;
+
+	matrix_size = row_length * row_length;
+	for (i = 0; i < matrices; i++) {
+		matrix_offset = i * matrix_size;
+		for (j = 0; j < matrix_size; j++) {
+			block = j / 16;
+			line_offset = (j % 16) / 4;
+			block_offset = (block & 1) * 32 + (block & 2) * 2;
+			input_idx = ((j % 4) * row_length) + line_offset + block_offset;
+
+			new_value = *(input + i * matrix_size + input_idx);
+
+			output[matrix_offset + j] = new_value;
+		}
+	}
+}
+
 static void rkvdec_watchdog_func(struct work_struct *work)
 {
 	struct rkvdec_dev *rkvdec;
@@ -1508,6 +1596,7 @@ static int rkvdec_disable_multicore(struct rkvdec_dev *rkvdec)
 static const struct rkvdec_variant_ops rk3399_variant_ops = {
 	.irq_handler = rk3399_irq_handler,
 	.colmv_size = rkvdec_colmv_size,
+	.flatten_matrices = transpose_and_flatten_matrices,
 };
 
 static const struct rkvdec_variant rk3288_rkvdec_variant = {
@@ -1551,6 +1640,7 @@ static const struct rcb_size_info vdpu381_rcb_sizes[] = {
 static const struct rkvdec_variant_ops vdpu381_variant_ops = {
 	.irq_handler = vdpu381_irq_handler,
 	.colmv_size = rkvdec_colmv_size,
+	.flatten_matrices = transpose_and_flatten_matrices,
 };
 
 static const struct rkvdec_variant vdpu381_variant = {
@@ -1577,6 +1667,7 @@ static const struct rcb_size_info vdpu383_rcb_sizes[] = {
 static const struct rkvdec_variant_ops vdpu383_variant_ops = {
 	.irq_handler = vdpu383_irq_handler,
 	.colmv_size = vdpu383_colmv_size,
+	.flatten_matrices = vdpu383_flatten_matrices,
 };
 
 static const struct rkvdec_variant vdpu383_variant = {
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
index ad19f6ae562d3..c87d637770d36 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
@@ -74,6 +74,7 @@ vb2_to_rkvdec_decoded_buf(struct vb2_buffer *buf)
 struct rkvdec_variant_ops {
 	irqreturn_t (*irq_handler)(struct rkvdec_ctx *ctx);
 	u32 (*colmv_size)(u16 width, u16 height);
+	void (*flatten_matrices)(u8 *output, const u8 *input, int matrices, int row_length);
 };
 
 struct rkvdec_variant {
@@ -192,5 +193,6 @@ extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_hevc_fmt_ops;
 
 /* VDPU383 ops */
 extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu383_h264_fmt_ops;
+extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu383_hevc_fmt_ops;
 
 #endif /* RKVDEC_H_ */
-- 
2.52.0



From baolin.wang at linux.alibaba.com  Thu Dec 18 16:56:09 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Fri, 19 Dec 2025 08:56:09 +0800
Subject: [PATCH v2 2/3] mm: rmap: support batched checks of the references
 for large folios
In-Reply-To: <0caffb55-f242-4b01-b60a-c8749aadf661@arm.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <545dba5e899634bc6c8ca782417d16fef3bd049f.1765439381.git.baolin.wang@linux.alibaba.com>
 <cb4d7243-d8c6-4706-a254-6f5afc148910@arm.com>
 <89cdd927-fc88-42cf-b8a1-2fbd736d5f7c@linux.alibaba.com>
 <0caffb55-f242-4b01-b60a-c8749aadf661@arm.com>
Message-ID: <121c8ffb-adff-4766-aae9-8be6d37d546a@linux.alibaba.com>



On 2025/12/18 20:08, Ryan Roberts wrote:
>>>>  ? +#define clear_flush_young_ptes clear_flush_young_ptes
>>>> +static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
>>>> +??????????????????? unsigned long addr, pte_t *ptep,
>>>> +??????????????????? unsigned int nr)
>>>> +{
>>>> +??? if (likely(nr == 1))
>>>> +??????? return __ptep_clear_flush_young(vma, addr, ptep);
>>>
>>> Bug: This is broken if core-mm tries to call this for nr=1 on a pte that is part
>>> of a contpte mapping.
>>>
>>> The similar fastpaths are here to prevent regressing the common small folio case.
>>
>> Thanks for catching this. I had considered this before, but I still missed it.
>>
>>> I guess here the best approach is (note no leading underscores):
>>>
>>>  ????if (likely(nr == 1))
>>>  ??????? return ptep_clear_flush_young(vma, addr, ptep);
>>
>> However, I prefer to use pte_cont() to check it. Later, I plan to clean up the
>> ptep_clear_flush_young().
>>
>>  ????if (nr == 1 && !pte_cont(__ptep_get(ptep))
>>  ??????? return __ptep_clear_flush_young(vma, addr, ptep);
> 
> Sure. That would follow the pattern in clear_young_dirty_ptes(). Please use the
> likely() hint as is done everywhere else:
> 
> 	if (likely(nr == 1 && !pte_cont(__ptep_get(ptep))))

Sure.

> I notice that ptep_test_and_clear_young() and ptep_clear_flush_young() are both
> testing aginst pte_valid_cont(). These could probably be relaxed to pte_cont()
> since it is implicit the the pte must be valid?

Yes, I think so. I can do a cleanup later in a separate patch.


From baolin.wang at linux.alibaba.com  Thu Dec 18 17:00:34 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Fri, 19 Dec 2025 09:00:34 +0800
Subject: [PATCH v2 1/3] arm64: mm: support batch clearing of the young
 flag for large folios
In-Reply-To: <d3b40df8-e5cf-42aa-8205-de624024fad1@arm.com>
References: <cover.1765439380.git.baolin.wang@linux.alibaba.com>
 <e10f876ce130134fa089befe83f30561b48b9889.1765439380.git.baolin.wang@linux.alibaba.com>
 <1beaa7de-4b31-4f19-abee-83872f868e28@arm.com>
 <96c0adcc-abfd-4a44-be93-1c6bd7942d6d@linux.alibaba.com>
 <d3b40df8-e5cf-42aa-8205-de624024fad1@arm.com>
Message-ID: <9c6393e1-fc88-46bf-9a3e-b28b8cda1c75@linux.alibaba.com>



On 2025/12/18 20:20, Ryan Roberts wrote:
> On 18/12/2025 07:15, Baolin Wang wrote:
>>
>>
>> On 2025/12/17 23:43, Ryan Roberts wrote:
>>> Sorry I'm a bit late to the party...
>>
>> Never mind. It's not late and comments are always welcome :)
>>
>>> On 11/12/2025 08:16, Baolin Wang wrote:
>>>> Currently, contpte_ptep_test_and_clear_young() and
>>>> contpte_ptep_clear_flush_young()
>>>> only clear the young flag and flush TLBs for PTEs within the contiguous range.
>>>> To support batch PTE operations for other sized large folios in the following
>>>> patches, adding a new parameter to specify the number of PTEs.
>>>>
>>>> While we are at it, rename the functions to maintain consistency with other
>>>> contpte_*() functions.
>>>>
>>>> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
>>>> ---
>>>>  ? arch/arm64/include/asm/pgtable.h | 12 ++++-----
>>>>  ? arch/arm64/mm/contpte.c????????? | 44 ++++++++++++++++++++++----------
>>>>  ? 2 files changed, 37 insertions(+), 19 deletions(-)
>>>>
>>>> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
>>>> index 0944e296dd4a..e03034683156 100644
>>>> --- a/arch/arm64/include/asm/pgtable.h
>>>> +++ b/arch/arm64/include/asm/pgtable.h
>>>> @@ -1679,10 +1679,10 @@ extern void contpte_clear_full_ptes(struct mm_struct
>>>> *mm, unsigned long addr,
>>>>  ? extern pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
>>>>  ????????????????? unsigned long addr, pte_t *ptep,
>>>>  ????????????????? unsigned int nr, int full);
>>>> -extern int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
>>>> -??????????????? unsigned long addr, pte_t *ptep);
>>>> -extern int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
>>>> -??????????????? unsigned long addr, pte_t *ptep);
>>>> +extern int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
>>>> +??????????????? unsigned long addr, pte_t *ptep, unsigned int nr);
>>>> +extern int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
>>>> +??????????????? unsigned long addr, pte_t *ptep, unsigned int nr);
>>>
>>> The "contpte_" functions are intended to be private to the arm64 arch and should
>>> be exposed via the generic APIs. But I don't see any generic batched API for
>>> this, so you're only actually able to pass CONT_PTES as nr. Perhaps you're
>>> planning to define "test_and_clear_young_ptes()" and "clear_flush_young_ptes()"
>>> in later patches?
>>
>> Right. This is a preparation patch, and will be used in patch 2.
>>
>>>>  ? extern void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
>>>>  ????????????????? pte_t *ptep, unsigned int nr);
>>>>  ? extern int contpte_ptep_set_access_flags(struct vm_area_struct *vma,
>>>> @@ -1854,7 +1854,7 @@ static inline int ptep_test_and_clear_young(struct
>>>> vm_area_struct *vma,
>>>>  ????? if (likely(!pte_valid_cont(orig_pte)))
>>>>  ????????? return __ptep_test_and_clear_young(vma, addr, ptep);
>>>>  ? -??? return contpte_ptep_test_and_clear_young(vma, addr, ptep);
>>>> +??? return contpte_test_and_clear_young_ptes(vma, addr, ptep, CONT_PTES);
>>>>  ? }
>>>>  ? ? #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
>>>> @@ -1866,7 +1866,7 @@ static inline int ptep_clear_flush_young(struct
>>>> vm_area_struct *vma,
>>>>  ????? if (likely(!pte_valid_cont(orig_pte)))
>>>>  ????????? return __ptep_clear_flush_young(vma, addr, ptep);
>>>>  ? -??? return contpte_ptep_clear_flush_young(vma, addr, ptep);
>>>> +??? return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
>>>>  ? }
>>>>  ? ? #define wrprotect_ptes wrprotect_ptes
>>>> diff --git a/arch/arm64/mm/contpte.c b/arch/arm64/mm/contpte.c
>>>> index c0557945939c..19b122441be3 100644
>>>> --- a/arch/arm64/mm/contpte.c
>>>> +++ b/arch/arm64/mm/contpte.c
>>>> @@ -488,8 +488,9 @@ pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
>>>>  ? }
>>>>  ? EXPORT_SYMBOL_GPL(contpte_get_and_clear_full_ptes);
>>>>  ? -int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
>>>> -??????????????????? unsigned long addr, pte_t *ptep)
>>>> +int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
>>>> +??????????????????? unsigned long addr, pte_t *ptep,
>>>> +??????????????????? unsigned int nr)
>>>>  ? {
>>>>  ????? /*
>>>>  ?????? * ptep_clear_flush_young() technically requires us to clear the access
>>>> @@ -500,39 +501,56 @@ int contpte_ptep_test_and_clear_young(struct
>>>> vm_area_struct *vma,
>>>>  ?????? * having to unfold.
>>>>  ?????? */
>>>>  ? +??? unsigned long start = addr;
>>>
>>> Personally I wouldn't bother defining start - just reuse addr. You're
>>> incrementing start in the below loop, so it's more appropriate to call it addr
>>> anyway.
>>
>> OK.
>>
>>>> +??? unsigned long end = start + nr * PAGE_SIZE;
>>>>  ????? int young = 0;
>>>>  ????? int i;
>>>>  ? -??? ptep = contpte_align_down(ptep);
>>>> -??? addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
>>>> +??? if (pte_cont(__ptep_get(ptep + nr - 1)))
>>>> +??????? end = ALIGN(end, CONT_PTE_SIZE);
>>>>  ? -??? for (i = 0; i < CONT_PTES; i++, ptep++, addr += PAGE_SIZE)
>>>> -??????? young |= __ptep_test_and_clear_young(vma, addr, ptep);
>>>> +??? if (pte_cont(__ptep_get(ptep))) {
>>>> +??????? start = ALIGN_DOWN(start, CONT_PTE_SIZE);
>>>> +??????? ptep = contpte_align_down(ptep);
>>>> +??? }
>>>> +
>>>> +??? nr = (end - start) / PAGE_SIZE;
>>>> +??? for (i = 0; i < nr; i++, ptep++, start += PAGE_SIZE)
>>>
>>> Given you're now defining end, perhaps we don't need nr?
>>>
>>>  ????for (; addr != end; ptep++, addr += PAGE_SIZE)
>>>  ??????? young |= __ptep_test_and_clear_young(vma, addr, ptep);
>>
>> Yes, good point.
>>
>>>> +??????? young |= __ptep_test_and_clear_young(vma, start, ptep);
>>>>  ? ????? return young;
>>>>  ? }
>>>> -EXPORT_SYMBOL_GPL(contpte_ptep_test_and_clear_young);
>>>> +EXPORT_SYMBOL_GPL(contpte_test_and_clear_young_ptes);
>>>>  ? -int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
>>>> -??????????????????? unsigned long addr, pte_t *ptep)
>>>> +int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
>>>> +??????????????? unsigned long addr, pte_t *ptep,
>>>> +??????????????? unsigned int nr)
>>>>  ? {
>>>>  ????? int young;
>>>>  ? -??? young = contpte_ptep_test_and_clear_young(vma, addr, ptep);
>>>> +??? young = contpte_test_and_clear_young_ptes(vma, addr, ptep, nr);
>>>>  ? ????? if (young) {
>>>> +??????? unsigned long start = addr;
>>>> +??????? unsigned long end = start + nr * PAGE_SIZE;
>>>> +
>>>> +??????? if (pte_cont(__ptep_get(ptep + nr - 1)))
>>>> +??????????? end = ALIGN(end, CONT_PTE_SIZE);
>>>> +
>>>> +??????? if (pte_cont(__ptep_get(ptep)))
>>>> +??????????? start = ALIGN_DOWN(start, CONT_PTE_SIZE);
>>>> +
>>>
>>> We now have this pattern of expanding contpte blocks up and down in 3 places.
>>> Perhaps create a helper?
>>
>> Sounds reasonable. How about the following helper?
>>
>> static pte_t *contpte_align_addr_ptep(unsigned long *start, unsigned long *end,
>>  ??????????????????????????????????????? pte_t *ptep, unsigned int nr)
>> {
>>  ??????? unsigned long end_addr = *start + nr * PAGE_SIZE;
>>
>>  ??????? if (pte_cont(__ptep_get(ptep + nr - 1)))
> 
> I think this is safe but calling it out to check; you're not checking that the
> pte is valid, so theoretically you could have a swap-entry here with whatever
> overlays the contiguous bit set. So then you would incorrectly extend.
> 
> But I think it is safe because the expectation is that core-mm has already
> checked that the whole range is present?

Yes. They must be present PTEs that map consecutive pages of the same 
large folio within a single VMA and a single page table. I will add some 
comments to make this clear.

>>  ??????????????? *end = ALIGN(end_addr, CONT_PTE_SIZE);
>>
>>  ??????? if (pte_cont(__ptep_get(ptep))) {
>>  ??????????????? *start = ALIGN_DOWN(*start, CONT_PTE_SIZE);
>>  ??????????????? ptep = contpte_align_down(ptep);
>>  ??????? }
>>
>>  ??????? return ptep;
>> }
> 
> Looks good.

Thanks for reviewing.


From guoniu.zhou at oss.nxp.com  Thu Dec 18 17:50:56 2025
From: guoniu.zhou at oss.nxp.com (Guoniu Zhou)
Date: Fri, 19 Dec 2025 09:50:56 +0800
Subject: [PATCH v3 0/2] media: nxp: Add CSI Pixel Formatter support
Message-ID: <20251219-csi_formatter-v3-0-8680d6d87091@nxp.com>

CSI Pixel Formatter is a module found on i.MX95. It could unpack the
pixels received by the formatter and reformat them to meet the pixel
link format requirement.

This patch series adds a new V4L2 driver for CSI Pixel Formatter.

v4l2-compliance 1.28.1-5233, 64 bits, 64-bit time_t
v4l2-compliance SHA: fc15e229d9d3 2024-07-23 19:22:15

Compliance test for device /dev/v4l-subdev9:

Driver Info:
	Driver version   : 6.18.0
	Capabilities     : 0x00000002
		Streams Support
	Client Capabilities: 0x0000000000000003
streams interval-uses-which
Required ioctls:
	test VIDIOC_SUDBEV_QUERYCAP: OK
	test invalid ioctls: OK

Allow for multiple opens:
	test second /dev/v4l-subdev9 open: OK
	test VIDIOC_SUBDEV_QUERYCAP: OK
	test for unlimited opens: OK

Debug ioctls:
	test VIDIOC_LOG_STATUS: OK (Not Supported)

Input ioctls:
	test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
	test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
	test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
	test VIDIOC_ENUMAUDIO: OK (Not Supported)
	test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
	test VIDIOC_G/S_AUDIO: OK (Not Supported)
	Inputs: 0 Audio Inputs: 0 Tuners: 0

Output ioctls:
	test VIDIOC_G/S_MODULATOR: OK (Not Supported)
	test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
	test VIDIOC_ENUMAUDOUT: OK (Not Supported)
	test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
	test VIDIOC_G/S_AUDOUT: OK (Not Supported)
	Outputs: 0 Audio Outputs: 0 Modulators: 0

Input/Output configuration ioctls:
	test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
	test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
	test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
	test VIDIOC_G/S_EDID: OK (Not Supported)

Sub-Device routing ioctls:
	test Try VIDIOC_SUBDEV_G_ROUTING/VIDIOC_SUBDEV_S_ROUTING: OK
	test Active VIDIOC_SUBDEV_G_ROUTING/VIDIOC_SUBDEV_S_ROUTING: OK

Control ioctls:
	test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK (Not Supported)
	test VIDIOC_QUERYCTRL: OK (Not Supported)
	test VIDIOC_G/S_CTRL: OK (Not Supported)
	test VIDIOC_G/S/TRY_EXT_CTRLS: OK (Not Supported)
	test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK (Not Supported)
	test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
	Standard Controls: 0 Private Controls: 0

Format ioctls:
	test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK (Not Supported)
	test VIDIOC_G/S_PARM: OK (Not Supported)
	test VIDIOC_G_FBUF: OK (Not Supported)
	test VIDIOC_G_FMT: OK (Not Supported)
	test VIDIOC_TRY_FMT: OK (Not Supported)
	test VIDIOC_S_FMT: OK (Not Supported)
	test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
	test Cropping: OK (Not Supported)
	test Composing: OK (Not Supported)
	test Scaling: OK (Not Supported)

Codec ioctls:
	test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
	test VIDIOC_G_ENC_INDEX: OK (Not Supported)
	test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

Buffer ioctls:
	test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK (Not Supported)
	test CREATE_BUFS maximum buffers: OK
	test VIDIOC_REMOVE_BUFS: OK
	test VIDIOC_EXPBUF: OK (Not Supported)
	test Requests: OK (Not Supported)

Total for device /dev/v4l-subdev9: 47, Succeeded: 47, Failed: 0, Warnings: 0

Signed-off-by: Guoniu Zhou <guoniu.zhou at nxp.com>
---
Changes in v3:
- Rename nxp,imx9-csi-formatter.yaml to fsl,imx9-csi-formatter.yaml.
- Drop clock-names property.
- Drop macro IMX95_PD_CAMERA definition and use a constant directly.
  [PATCH 1/2] media: dt-bindings: Add CSI Pixel Formatter DT bindings
- Remove the assignment driver.owner = THIS_MODULE.
- Assign struct fwnode_handle *ep __free(fwnode_handle) when definition.
- Update yaml file name for csi formatter in MAINTAINERS.
  [PATCH 2/2] media: nxp: Add i.MX9 CSI pixel formatter v4l2 driver
- Link to v2: https://lore.kernel.org/r/20251217-csi_formatter-v2-0-62168af80210 at nxp.com

Changes in v2:
- Delete "|" for description key. 
- Add empty line between child node and property.
- Delete labels for endpoint of child nodes.
  [PATCH 1/2] media: dt-bindings: Add CSI Pixel Formatter DT bindings

- Update commit message.
- Use the value defined by bellow macros directly since they are used only once.
  #define CSI_FORMATTER_DEF_MBUS_CODE	MEDIA_BUS_FMT_UYVY8_1X16
  #define CSI_FORMATTER_DEF_PIX_WIDTH	1920U
  #define CSI_FORMATTER_DEF_PIX_HEIGHT	1080U
  #define CSI_FORMATTER_MAX_PIX_WIDTH	0xffff
  #define CSI_FORMATTER_MAX_PIX_HEIGHT	0xffff
- Use macro pm_ptr() to fix build warning when CONFIG_PM is disabled. 
- Finish route loop by break statement, instead of goto.
- Return dev_err_probe() when meet errors in probe() function instead of dev_err().
- Remove MODULE_ALIAS().
- Refine .enable(.dsable)_stream callback implementation, include bellow changes:
  Add stream checking.
  Fix potential pm runtime count unbalance issue.
  Add stop stream error handling when enabling remote subdev stream.
- Use __free(fwnode_handle) to drop reference to a device node automatically.
  [PATCH 2/2] media: nxp: Add i.MX9 CSI pixel formatter v4l2 driver

- Link to v1: https://lore.kernel.org/r/20251203-csi_formatter-v1-0-eb9e1147b49e at nxp.com

---
Guoniu Zhou (2):
      media: dt-bindings: Add CSI Pixel Formatter DT bindings
      media: nxp: Add i.MX9 CSI pixel formatter v4l2 driver

 .../bindings/media/fsl,imx9-csi-formatter.yaml     |  87 ++
 MAINTAINERS                                        |   8 +
 drivers/media/platform/nxp/Kconfig                 |  14 +
 drivers/media/platform/nxp/Makefile                |   1 +
 drivers/media/platform/nxp/imx9-csi-formatter.c    | 880 +++++++++++++++++++++
 5 files changed, 990 insertions(+)
---
base-commit: 1f2353f5a1af995efbf7bea44341aa0d03460b28
change-id: 20251125-csi_formatter-e6d29316dce6

Best regards,
-- 
Guoniu Zhou <guoniu.zhou at nxp.com>



From guoniu.zhou at oss.nxp.com  Thu Dec 18 17:50:57 2025
From: guoniu.zhou at oss.nxp.com (Guoniu Zhou)
Date: Fri, 19 Dec 2025 09:50:57 +0800
Subject: [PATCH v3 1/2] media: dt-bindings: Add CSI Pixel Formatter DT
 bindings
In-Reply-To: <20251219-csi_formatter-v3-0-8680d6d87091@nxp.com>
References: <20251219-csi_formatter-v3-0-8680d6d87091@nxp.com>
Message-ID: <20251219-csi_formatter-v3-1-8680d6d87091@nxp.com>

From: Guoniu Zhou <guoniu.zhou at nxp.com>

The i.MX9 CSI pixel formatting module uses packet info, pixel and
non-pixel data from the CSI-2 host controller and reformat them to
match Pixel Link(PL) definition.

Signed-off-by: Guoniu Zhou <guoniu.zhou at nxp.com>
---
 .../bindings/media/fsl,imx9-csi-formatter.yaml     | 87 ++++++++++++++++++++++
 1 file changed, 87 insertions(+)

diff --git a/Documentation/devicetree/bindings/media/fsl,imx9-csi-formatter.yaml b/Documentation/devicetree/bindings/media/fsl,imx9-csi-formatter.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..774d37d2b987a679f0bb6378897a6dd196ea4f13
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/fsl,imx9-csi-formatter.yaml
@@ -0,0 +1,87 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/fsl,imx9-csi-formatter.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: i.MX9 CSI Pixel Formatter
+
+maintainers:
+  - Guoniu Zhou <guoniu.zhou at nxp.com>
+
+description:
+  The CSI pixel formatting module uses packet info, pixel and non-pixel
+  data from the CSI-2 host controller and reformat them to match Pixel
+  Link(PL) definition.
+
+properties:
+  compatible:
+    const: fsl,imx9-csi-formatter
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 1
+
+  ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+
+    properties:
+      port at 0:
+        $ref: /schemas/graph.yaml#/$defs/port-base
+        unevaluatedProperties: false
+        description: MIPI CSI-2 RX IDI interface
+
+        properties:
+          endpoint:
+            $ref: video-interfaces.yaml#
+            unevaluatedProperties: false
+
+      port at 1:
+        $ref: /schemas/graph.yaml#/properties/port
+        description: Pixel Link Interface
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - power-domains
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/nxp,imx95-clock.h>
+
+    formatter at 20 {
+        compatible = "fsl,imx9-csi-formatter";
+        reg = <0x20 0x100>;
+        clocks = <&cameramix_csr IMX95_CLK_CAMBLK_CSI2_FOR0>;
+        power-domains = <&scmi_devpd 3>;
+
+        ports {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            port at 0 {
+                reg = <0>;
+
+                endpoint {
+                    remote-endpoint = <&mipi_csi_0_out>;
+                };
+            };
+
+            port at 1 {
+                reg = <1>;
+
+                endpoint {
+                    remote-endpoint = <&isi_in_2>;
+                };
+            };
+        };
+    };

-- 
2.34.1



From guoniu.zhou at oss.nxp.com  Thu Dec 18 17:50:58 2025
From: guoniu.zhou at oss.nxp.com (Guoniu Zhou)
Date: Fri, 19 Dec 2025 09:50:58 +0800
Subject: [PATCH v3 2/2] media: nxp: Add i.MX9 CSI pixel formatter v4l2
 driver
In-Reply-To: <20251219-csi_formatter-v3-0-8680d6d87091@nxp.com>
References: <20251219-csi_formatter-v3-0-8680d6d87091@nxp.com>
Message-ID: <20251219-csi_formatter-v3-2-8680d6d87091@nxp.com>

From: Guoniu Zhou <guoniu.zhou at nxp.com>

The CSI pixel formatter is a module found on i.MX95 used to reformat
packet info, pixel and non-pixel data from CSI-2 host controller to
match Pixel Link(PL) definition.

Add data formatting support.

Signed-off-by: Guoniu Zhou <guoniu.zhou at nxp.com>
---
 MAINTAINERS                                     |   8 +
 drivers/media/platform/nxp/Kconfig              |  14 +
 drivers/media/platform/nxp/Makefile             |   1 +
 drivers/media/platform/nxp/imx9-csi-formatter.c | 880 ++++++++++++++++++++++++
 4 files changed, 903 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 4205ca007e076f869613032b51e8cc5bff06b98e..3878957b81156e5cb41da2699b2f588e49521724 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18626,6 +18626,14 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/media/nxp,imx8-jpeg.yaml
 F:	drivers/media/platform/nxp/imx-jpeg
 
+NXP i.MX 9 CSI PIXEL FORMATTER V4L2 DRIVER
+M:	Guoniu Zhou <guoniu.zhou at nxp.com>
+L:	imx at lists.linux.dev
+L:	linux-media at vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/media/fsl,imx9-csi-formatter.yaml
+F:	drivers/media/platform/nxp/imx9-csi-formatter.c
+
 NXP i.MX CLOCK DRIVERS
 M:	Abel Vesa <abelvesa at kernel.org>
 R:	Peng Fan <peng.fan at nxp.com>
diff --git a/drivers/media/platform/nxp/Kconfig b/drivers/media/platform/nxp/Kconfig
index 40e3436669e213fdc5da70821dc0b420e1821f4f..a7bb62a2b0249659ffdfeac50fa488aee9590a87 100644
--- a/drivers/media/platform/nxp/Kconfig
+++ b/drivers/media/platform/nxp/Kconfig
@@ -28,6 +28,20 @@ config VIDEO_IMX8MQ_MIPI_CSI2
 	  Video4Linux2 driver for the MIPI CSI-2 receiver found on the i.MX8MQ
 	  SoC.
 
+config VIDEO_IMX9_CSI_FORMATTER
+	tristate "NXP i.MX9 CSI Pixel Formatter driver"
+	depends on ARCH_MXC || COMPILE_TEST
+	depends on VIDEO_DEV
+	select MEDIA_CONTROLLER
+	select V4L2_FWNODE
+	select VIDEO_V4L2_SUBDEV_API
+	help
+	  This driver provides support for the CSI Pixel Formatter found on
+	  i.MX9 series SoC. This module unpacks the pixels received by the
+	  formatter and reformats them to meet the pixel link format requirement.
+
+	  Say Y here to enable CSI Pixel Formater module for i.MX9 SoC.
+
 config VIDEO_IMX_MIPI_CSIS
 	tristate "NXP MIPI CSI-2 CSIS receiver found on i.MX7 and i.MX8 models"
 	depends on ARCH_MXC || COMPILE_TEST
diff --git a/drivers/media/platform/nxp/Makefile b/drivers/media/platform/nxp/Makefile
index 4d90eb71365259ebdda84ea58483e1c4131d3ac7..39ba5660ba923141e7637b01b5b34a021dad7bb3 100644
--- a/drivers/media/platform/nxp/Makefile
+++ b/drivers/media/platform/nxp/Makefile
@@ -6,6 +6,7 @@ obj-y += imx8-isi/
 
 obj-$(CONFIG_VIDEO_IMX7_CSI) += imx7-media-csi.o
 obj-$(CONFIG_VIDEO_IMX8MQ_MIPI_CSI2) += imx8mq-mipi-csi2.o
+obj-$(CONFIG_VIDEO_IMX9_CSI_FORMATTER) += imx9-csi-formatter.o
 obj-$(CONFIG_VIDEO_IMX_MIPI_CSIS) += imx-mipi-csis.o
 obj-$(CONFIG_VIDEO_IMX_PXP) += imx-pxp.o
 obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o
diff --git a/drivers/media/platform/nxp/imx9-csi-formatter.c b/drivers/media/platform/nxp/imx9-csi-formatter.c
new file mode 100644
index 0000000000000000000000000000000000000000..5786e4690e31ee471caf8201329c8e02a2cc0ee6
--- /dev/null
+++ b/drivers/media/platform/nxp/imx9-csi-formatter.c
@@ -0,0 +1,880 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2025 NXP
+ */
+
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include <media/mipi-csi2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mc.h>
+#include <media/v4l2-subdev.h>
+
+/* CSI Pixel Formatter registers map */
+
+#define CSI_VCx_INTERLACED_LINE_CNT(x)		(0x00 + (x) * 0x04)
+#define INTERLACED_ODD_LINE_CNT_SET(x)		FIELD_PREP(GENMASK(13, 0), (x))
+#define INTERLACED_EVEN_LINE_CNT_SET(x)		FIELD_PREP(GENMASK(29, 16), (x))
+
+#define CSI_VC_INTERLACED_CTRL			0x20
+
+#define CSI_VC_INTERLACED_ERR			0x24
+#define CSI_VC_ERR_MASK				GENMASK(7, 0)
+#define CSI_VC_ERR(vc)				BIT((vc))
+
+#define CSI_VC_YUV420_FIRST_LINE_EVEN		0x28
+#define YUV420_FIRST_LINE_EVEN(vc)		BIT((vc))
+
+#define CSI_RAW32_CTRL				0x30
+#define CSI_VCX_RAW32_MODE(vc)			BIT((vc))
+#define CSI_VCX_RAW32_SWAP_MODE(vc)		BIT((vc) + 8)
+
+#define STREAM_FENCING_CTRL			0x34
+#define CSI_VCx_STREAM_FENCING(vc)		BIT((vc))
+#define CSI_VCx_STREAM_FENCING_RST(vc)		BIT((vc) + 8)
+
+#define STREAM_FENCING_STS			0x38
+#define STREAM_FENCING_STS_MASK			GENMASK(7, 0)
+
+#define CSI_VCX_NON_PIXEL_DATA_TYPE(vc)		(0x40 + (vc) * 0x04)
+
+#define CSI_VCX_PIXEL_DATA_CTRL(vc)		(0x60 + (vc) * 0x04)
+#define NEW_VC(x)				FIELD_PREP(GENMASK(3, 1), x)
+#define REROUTE_VC_ENABLE			BIT(0)
+
+#define CSI_VCx_ROUTE_PIXEL_DATA_TYPE(vc)	(0x80 + (vc) * 0x04)
+
+#define CSI_VCx_NON_PIXEL_DATA_CTRL(vc)		(0xa0 + (vc) * 0x04)
+
+#define CSI_VCx_PIXEL_DATA_TYPE(vc)		(0xc0 + (vc) * 0x04)
+
+#define CSI_VCx_PIXEL_DATA_TYPE_ERR(vc)		(0xe0 + (vc) * 0x04)
+
+#define CSI_FORMATTER_PAD_SINK			0
+#define CSI_FORMATTER_PAD_SOURCE		1
+#define CSI_FORMATTER_PAD_NUM			2
+
+#define CSI_FORMATTER_DRV_NAME			"csi-pixel-formatter"
+#define CSI_FORMATTER_VC_MAX			8
+
+struct formatter_pix_format {
+	u32 code;
+	u32 data_type;
+};
+
+struct csi_formatter {
+	struct device *dev;
+	struct regmap *regs;
+	struct clk *clk;
+
+	struct v4l2_subdev sd;
+	struct v4l2_subdev *csi_sd;
+	struct v4l2_async_notifier notifier;
+	struct v4l2_mbus_framefmt format[CSI_FORMATTER_PAD_NUM];
+	struct media_pad pads[CSI_FORMATTER_PAD_NUM];
+	const struct formatter_pix_format *fmt;
+
+	u16 remote_pad;
+	u32 reg_offset;
+	u64 enabled_streams;
+};
+
+struct dt_index {
+	u8 dtype;
+	u8 index;
+};
+
+static const struct dt_index formatter_dt_to_index_map[] = {
+	{ .dtype = MIPI_CSI2_DT_YUV420_8B,        .index = 0 },
+	{ .dtype = MIPI_CSI2_DT_YUV420_8B_LEGACY, .index = 2 },
+	{ .dtype = MIPI_CSI2_DT_YUV422_8B,        .index = 6 },
+	{ .dtype = MIPI_CSI2_DT_RGB444,		  .index = 8 },
+	{ .dtype = MIPI_CSI2_DT_RGB555,           .index = 9 },
+	{ .dtype = MIPI_CSI2_DT_RGB565,           .index = 10 },
+	{ .dtype = MIPI_CSI2_DT_RGB666,           .index = 11 },
+	{ .dtype = MIPI_CSI2_DT_RGB888,           .index = 12 },
+	{ .dtype = MIPI_CSI2_DT_RAW6,             .index = 16 },
+	{ .dtype = MIPI_CSI2_DT_RAW7,             .index = 17 },
+	{ .dtype = MIPI_CSI2_DT_RAW8,             .index = 18 },
+	{ .dtype = MIPI_CSI2_DT_RAW10,            .index = 19 },
+	{ .dtype = MIPI_CSI2_DT_RAW12,            .index = 20 },
+	{ .dtype = MIPI_CSI2_DT_RAW14,            .index = 21 },
+	{ .dtype = MIPI_CSI2_DT_RAW16,            .index = 22 },
+};
+
+static const struct formatter_pix_format formats[] = {
+	/* YUV formats */
+	{
+		.code = MEDIA_BUS_FMT_UYVY8_1X16,
+		.data_type = MIPI_CSI2_DT_YUV422_8B,
+	},
+	/* RGB formats */
+	{
+		.code = MEDIA_BUS_FMT_RGB565_1X16,
+		.data_type = MIPI_CSI2_DT_RGB565,
+	}, {
+		.code = MEDIA_BUS_FMT_RGB888_1X24,
+		.data_type = MIPI_CSI2_DT_RGB888,
+	},
+	/* RAW (Bayer and greyscale) formats. */
+	{
+		.code = MEDIA_BUS_FMT_SBGGR8_1X8,
+		.data_type = MIPI_CSI2_DT_RAW8,
+	}, {
+		.code = MEDIA_BUS_FMT_SGBRG8_1X8,
+		.data_type = MIPI_CSI2_DT_RAW8,
+	}, {
+		.code = MEDIA_BUS_FMT_SGRBG8_1X8,
+		.data_type = MIPI_CSI2_DT_RAW8,
+	}, {
+		.code = MEDIA_BUS_FMT_SRGGB8_1X8,
+		.data_type = MIPI_CSI2_DT_RAW8,
+	}, {
+		.code = MEDIA_BUS_FMT_Y8_1X8,
+		.data_type = MIPI_CSI2_DT_RAW8,
+	}, {
+		.code = MEDIA_BUS_FMT_SBGGR10_1X10,
+		.data_type = MIPI_CSI2_DT_RAW10,
+	}, {
+		.code = MEDIA_BUS_FMT_SGBRG10_1X10,
+		.data_type = MIPI_CSI2_DT_RAW10,
+	}, {
+		.code = MEDIA_BUS_FMT_SGRBG10_1X10,
+		.data_type = MIPI_CSI2_DT_RAW10,
+	}, {
+		.code = MEDIA_BUS_FMT_SRGGB10_1X10,
+		.data_type = MIPI_CSI2_DT_RAW10,
+	}, {
+		.code = MEDIA_BUS_FMT_Y10_1X10,
+		.data_type = MIPI_CSI2_DT_RAW10,
+	}, {
+		.code = MEDIA_BUS_FMT_SBGGR12_1X12,
+		.data_type = MIPI_CSI2_DT_RAW12,
+	}, {
+		.code = MEDIA_BUS_FMT_SGBRG12_1X12,
+		.data_type = MIPI_CSI2_DT_RAW12,
+	}, {
+		.code = MEDIA_BUS_FMT_SGRBG12_1X12,
+		.data_type = MIPI_CSI2_DT_RAW12,
+	}, {
+		.code = MEDIA_BUS_FMT_SRGGB12_1X12,
+		.data_type = MIPI_CSI2_DT_RAW12,
+	}, {
+		.code = MEDIA_BUS_FMT_Y12_1X12,
+		.data_type = MIPI_CSI2_DT_RAW12,
+	}, {
+		.code = MEDIA_BUS_FMT_SBGGR14_1X14,
+		.data_type = MIPI_CSI2_DT_RAW14,
+	}, {
+		.code = MEDIA_BUS_FMT_SGBRG14_1X14,
+		.data_type = MIPI_CSI2_DT_RAW14,
+	}, {
+		.code = MEDIA_BUS_FMT_SGRBG14_1X14,
+		.data_type = MIPI_CSI2_DT_RAW14,
+	}, {
+		.code = MEDIA_BUS_FMT_SRGGB14_1X14,
+		.data_type = MIPI_CSI2_DT_RAW14,
+	}, {
+		.code = MEDIA_BUS_FMT_SBGGR16_1X16,
+		.data_type = MIPI_CSI2_DT_RAW16,
+	}, {
+		.code = MEDIA_BUS_FMT_SGBRG16_1X16,
+		.data_type = MIPI_CSI2_DT_RAW16,
+	}, {
+		.code = MEDIA_BUS_FMT_SGRBG16_1X16,
+		.data_type = MIPI_CSI2_DT_RAW16,
+	}, {
+		.code = MEDIA_BUS_FMT_SRGGB16_1X16,
+		.data_type = MIPI_CSI2_DT_RAW16,
+	}
+};
+
+static const struct v4l2_mbus_framefmt formatter_default_fmt = {
+	.code = MEDIA_BUS_FMT_UYVY8_1X16,
+	.width = 1920U,
+	.height = 1080U,
+	.field = V4L2_FIELD_NONE,
+	.colorspace = V4L2_COLORSPACE_SMPTE170M,
+	.xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SMPTE170M),
+	.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SMPTE170M),
+	.quantization = V4L2_QUANTIZATION_LIM_RANGE,
+};
+
+static const struct formatter_pix_format *find_csi_format(u32 code)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(formats); i++)
+		if (code == formats[i].code)
+			return &formats[i];
+
+	return &formats[0];
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+static inline struct csi_formatter *sd_to_formatter(struct v4l2_subdev *sdev)
+{
+	return container_of(sdev, struct csi_formatter, sd);
+}
+
+static int __formatter_subdev_set_routing(struct v4l2_subdev *sd,
+					  struct v4l2_subdev_state *state,
+					  struct v4l2_subdev_krouting *routing)
+{
+	int ret;
+
+	if (routing->num_routes > V4L2_FRAME_DESC_ENTRY_MAX)
+		return -EINVAL;
+
+	ret = v4l2_subdev_routing_validate(sd, routing,
+					   V4L2_SUBDEV_ROUTING_ONLY_1_TO_1);
+	if (ret)
+		return ret;
+
+	return v4l2_subdev_set_routing_with_fmt(sd, state, routing,
+						&formatter_default_fmt);
+}
+
+static int formatter_subdev_init_state(struct v4l2_subdev *sd,
+				       struct v4l2_subdev_state *sd_state)
+{
+	struct v4l2_subdev_route routes[] = {
+		{
+			.sink_pad = CSI_FORMATTER_PAD_SINK,
+			.sink_stream = 0,
+			.source_pad = CSI_FORMATTER_PAD_SOURCE,
+			.source_stream = 0,
+			.flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
+		},
+	};
+
+	struct v4l2_subdev_krouting routing = {
+		.num_routes = ARRAY_SIZE(routes),
+		.routes = routes,
+	};
+
+	return __formatter_subdev_set_routing(sd, sd_state, &routing);
+}
+
+static int formatter_subdev_enum_mbus_code(struct v4l2_subdev *sd,
+					   struct v4l2_subdev_state *sd_state,
+					   struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->pad == CSI_FORMATTER_PAD_SOURCE) {
+		struct v4l2_mbus_framefmt *fmt;
+
+		if (code->index > 0)
+			return -EINVAL;
+
+		fmt = v4l2_subdev_state_get_format(sd_state, code->pad,
+						   code->stream);
+		code->code = fmt->code;
+		return 0;
+	}
+
+	if (code->index >= ARRAY_SIZE(formats))
+		return -EINVAL;
+
+	code->code = formats[code->index].code;
+
+	return 0;
+}
+
+static int formatter_subdev_set_fmt(struct v4l2_subdev *sd,
+				    struct v4l2_subdev_state *sd_state,
+				    struct v4l2_subdev_format *sdformat)
+{
+	struct csi_formatter *formatter = sd_to_formatter(sd);
+	struct formatter_pix_format const *format;
+	struct v4l2_mbus_framefmt *fmt;
+
+	if (sdformat->pad == CSI_FORMATTER_PAD_SOURCE)
+		return v4l2_subdev_get_fmt(sd, sd_state, sdformat);
+
+	/*
+	 * Validate the media bus code and clamp and align the size.
+	 *
+	 * The total number of bits per line must be a multiple of 8. We thus
+	 * need to align the width for formats that are not multiples of 8
+	 * bits.
+	 */
+	format = find_csi_format(sdformat->format.code);
+
+	v4l_bound_align_image(&sdformat->format.width, 1, 0xffff, 2,
+			      &sdformat->format.height, 1, 0xffff, 0, 0);
+
+	fmt = v4l2_subdev_state_get_format(sd_state, sdformat->pad,
+					   sdformat->stream);
+	*fmt = sdformat->format;
+
+	/* Set default code if user set an invalid value */
+	fmt->code = format->code;
+
+	/* Propagate the format from sink stream to source stream */
+	fmt = v4l2_subdev_state_get_opposite_stream_format(sd_state, sdformat->pad,
+							   sdformat->stream);
+	if (!fmt)
+		return -EINVAL;
+
+	*fmt = sdformat->format;
+
+	/* Store the CSIS format descriptor for active formats. */
+	if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+		formatter->fmt = format;
+
+	return 0;
+}
+
+static int formatter_subdev_get_frame_desc(struct v4l2_subdev *sd,
+					   unsigned int pad,
+					   struct v4l2_mbus_frame_desc *fd)
+{
+	struct csi_formatter *formatter = sd_to_formatter(sd);
+	struct v4l2_mbus_frame_desc csi_fd;
+	struct v4l2_subdev_route *route;
+	struct v4l2_subdev_state *state;
+	int ret;
+
+	if (pad != CSI_FORMATTER_PAD_SOURCE)
+		return -EINVAL;
+
+	ret = v4l2_subdev_call(formatter->csi_sd, pad, get_frame_desc,
+			       formatter->remote_pad, &csi_fd);
+	if (ret)
+		return ret;
+
+	if (csi_fd.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) {
+		dev_err(formatter->dev,
+			"Frame descriptor does not describe CSI-2 link\n");
+		return -EINVAL;
+	}
+
+	memset(fd, 0, sizeof(*fd));
+
+	fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2;
+
+	state = v4l2_subdev_lock_and_get_active_state(sd);
+
+	for_each_active_route(&state->routing, route) {
+		struct v4l2_mbus_frame_desc_entry *entry = NULL;
+		unsigned int i;
+
+		if (route->source_pad != pad)
+			continue;
+
+		for (i = 0; i < csi_fd.num_entries; ++i) {
+			if (csi_fd.entry[i].stream == route->sink_stream) {
+				entry = &csi_fd.entry[i];
+				break;
+			}
+		}
+
+		if (!entry) {
+			dev_err(formatter->dev,
+				"Failed to find stream from source frames desc\n");
+			ret = -EPIPE;
+			break;
+		}
+
+		fd->entry[fd->num_entries].stream = route->source_stream;
+		fd->entry[fd->num_entries].flags = entry->flags;
+		fd->entry[fd->num_entries].length = entry->length;
+		fd->entry[fd->num_entries].pixelcode = entry->pixelcode;
+		fd->entry[fd->num_entries].bus.csi2.vc = entry->bus.csi2.vc;
+		fd->entry[fd->num_entries].bus.csi2.dt = entry->bus.csi2.dt;
+
+		fd->num_entries++;
+	}
+
+	v4l2_subdev_unlock_state(state);
+	return ret;
+}
+
+static int formatter_subdev_set_routing(struct v4l2_subdev *sd,
+					struct v4l2_subdev_state *state,
+					enum v4l2_subdev_format_whence which,
+					struct v4l2_subdev_krouting *routing)
+{
+	if (which == V4L2_SUBDEV_FORMAT_ACTIVE &&
+	    media_entity_is_streaming(&sd->entity))
+		return -EBUSY;
+
+	return __formatter_subdev_set_routing(sd, state, routing);
+}
+
+static inline void formatter_write(struct csi_formatter *formatter,
+				   unsigned int reg, unsigned int value)
+{
+	u32 offset = formatter->reg_offset;
+
+	regmap_write(formatter->regs, reg + offset, value);
+}
+
+static u8 get_index_by_dt(u8 data_type)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(formatter_dt_to_index_map); ++i)
+		if (data_type == formatter_dt_to_index_map[i].dtype)
+			break;
+
+	if (i == ARRAY_SIZE(formatter_dt_to_index_map))
+		return formatter_dt_to_index_map[0].index;
+
+	return formatter_dt_to_index_map[i].index;
+}
+
+static int get_vc(struct csi_formatter *formatter, unsigned int stream)
+{
+	struct v4l2_mbus_frame_desc source_fd;
+	struct v4l2_mbus_frame_desc_entry *entry = NULL;
+	unsigned int i;
+	int ret;
+
+	/*
+	 * Return virtual channel 0 as default value when remote subdev
+	 * don't implement .get_frame_desc subdev callback
+	 */
+	ret = v4l2_subdev_call(formatter->csi_sd, pad, get_frame_desc,
+			       formatter->remote_pad, &source_fd);
+	if (ret < 0)
+		return (ret == -ENOIOCTLCMD) ? 0 : ret;
+
+	for (i = 0; i < source_fd.num_entries; ++i) {
+		if (source_fd.entry[i].stream == stream) {
+			entry = &source_fd.entry[i];
+			break;
+		}
+	}
+
+	if (!entry) {
+		dev_err(formatter->dev,
+			"Can't find valid frame desc corresponding to stream %d\n", stream);
+		return -EPIPE;
+	}
+
+	return entry->bus.csi2.vc;
+}
+
+static int csi_formatter_start_stream(struct csi_formatter *formatter,
+				      u64 stream_mask)
+{
+	const struct formatter_pix_format *fmt = formatter->fmt;
+	unsigned int i;
+	u32 val;
+	int vc;
+
+	for (i = 0; i < V4L2_FRAME_DESC_ENTRY_MAX; ++i) {
+		if (stream_mask & BIT(i))
+			break;
+	}
+
+	if (i == V4L2_FRAME_DESC_ENTRY_MAX) {
+		dev_err(formatter->dev, "Stream ID out of range\n");
+		return -EINVAL;
+	}
+
+	val = BIT(get_index_by_dt(fmt->data_type));
+	vc = get_vc(formatter, i);
+
+	if (vc < 0 || vc > CSI_FORMATTER_VC_MAX) {
+		dev_err(formatter->dev, "Invalid virtual channel(%d)\n", vc);
+		return -EINVAL;
+	}
+
+	formatter_write(formatter, CSI_VCx_PIXEL_DATA_TYPE(vc), val);
+
+	return 0;
+}
+
+static int csi_formatter_stop_stream(struct csi_formatter *formatter,
+				     u64 stream_mask)
+{
+	unsigned int i;
+	int vc;
+
+	for (i = 0; i < V4L2_FRAME_DESC_ENTRY_MAX; ++i) {
+		if (stream_mask & BIT(i))
+			break;
+	}
+
+	if (i == V4L2_FRAME_DESC_ENTRY_MAX) {
+		dev_err(formatter->dev, "Stream ID out of range\n");
+		return -EINVAL;
+	}
+
+	vc = get_vc(formatter, i);
+
+	if (vc < 0 || vc > CSI_FORMATTER_VC_MAX) {
+		dev_err(formatter->dev, "Invalid virtual channel(%d)\n", vc);
+		return -EINVAL;
+	}
+
+	formatter_write(formatter, CSI_VCx_PIXEL_DATA_TYPE(vc), 0);
+
+	return 0;
+}
+
+static int formatter_subdev_enable_streams(struct v4l2_subdev *sd,
+					   struct v4l2_subdev_state *state,
+					   u32 pad, u64 streams_mask)
+{
+	struct csi_formatter *formatter = sd_to_formatter(sd);
+	struct device *dev = formatter->dev;
+	u64 sink_streams;
+	int ret;
+
+	sink_streams = v4l2_subdev_state_xlate_streams(state,
+						       CSI_FORMATTER_PAD_SOURCE,
+						       CSI_FORMATTER_PAD_SINK,
+						       &streams_mask);
+	if (!sink_streams || !streams_mask)
+		return -EINVAL;
+
+	dev_dbg(dev, "remote sd: %s pad: %u, sink_stream:0x%llx\n",
+		formatter->csi_sd->name, formatter->remote_pad, sink_streams);
+
+	if (!formatter->csi_sd) {
+		dev_err(dev, "CSI controller don't link with formatter\n");
+		return -EPIPE;
+	}
+
+	if (!formatter->enabled_streams) {
+		ret = pm_runtime_resume_and_get(formatter->dev);
+		if (ret < 0) {
+			dev_err(dev, "Formatter runtime get fail\n");
+			return ret;
+		}
+	}
+
+	ret = csi_formatter_start_stream(formatter, streams_mask);
+	if (ret)
+		goto runtime_put;
+
+	ret = v4l2_subdev_enable_streams(formatter->csi_sd,
+					 formatter->remote_pad,
+					 sink_streams);
+	if (ret)
+		goto stop_stream;
+
+	formatter->enabled_streams |= streams_mask;
+
+	return 0;
+
+stop_stream:
+	csi_formatter_stop_stream(formatter, streams_mask);
+runtime_put:
+	if (!formatter->enabled_streams)
+		pm_runtime_put(formatter->dev);
+	return ret;
+}
+
+static int formatter_subdev_disable_streams(struct v4l2_subdev *sd,
+					    struct v4l2_subdev_state *state,
+					    u32 pad, u64 streams_mask)
+{
+	struct csi_formatter *formatter = sd_to_formatter(sd);
+	u64 sink_streams;
+	int ret;
+
+	sink_streams = v4l2_subdev_state_xlate_streams(state,
+						       CSI_FORMATTER_PAD_SOURCE,
+						       CSI_FORMATTER_PAD_SINK,
+						       &streams_mask);
+	if (!sink_streams || !streams_mask)
+		return -EINVAL;
+
+	ret = v4l2_subdev_disable_streams(formatter->csi_sd, formatter->remote_pad,
+					  sink_streams);
+	if (ret)
+		return ret;
+
+	ret = csi_formatter_stop_stream(formatter, streams_mask);
+	if (ret)
+		return ret;
+
+	formatter->enabled_streams &= ~streams_mask;
+
+	if (!formatter->enabled_streams)
+		pm_runtime_put(formatter->dev);
+
+	return 0;
+}
+
+static const struct v4l2_subdev_pad_ops formatter_subdev_pad_ops = {
+	.enum_mbus_code		= formatter_subdev_enum_mbus_code,
+	.get_fmt		= v4l2_subdev_get_fmt,
+	.set_fmt		= formatter_subdev_set_fmt,
+	.get_frame_desc		= formatter_subdev_get_frame_desc,
+	.set_routing		= formatter_subdev_set_routing,
+	.enable_streams		= formatter_subdev_enable_streams,
+	.disable_streams	= formatter_subdev_disable_streams,
+};
+
+static const struct v4l2_subdev_ops formatter_subdev_ops = {
+	.pad = &formatter_subdev_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops formatter_internal_ops = {
+	.init_state = formatter_subdev_init_state,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+static const struct media_entity_operations formatter_entity_ops = {
+	.link_validate	= v4l2_subdev_link_validate,
+	.get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1,
+};
+
+static int csi_formatter_subdev_init(struct csi_formatter *formatter)
+{
+	struct v4l2_subdev *sd = &formatter->sd;
+	int ret;
+
+	v4l2_subdev_init(sd, &formatter_subdev_ops);
+
+	snprintf(sd->name, sizeof(sd->name), "%s", dev_name(formatter->dev));
+	sd->internal_ops = &formatter_internal_ops;
+
+	sd->owner = THIS_MODULE;
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+		     V4L2_SUBDEV_FL_HAS_EVENTS |
+		     V4L2_SUBDEV_FL_STREAMS;
+	sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
+	sd->entity.ops = &formatter_entity_ops;
+	sd->dev = formatter->dev;
+
+	formatter->pads[CSI_FORMATTER_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+	formatter->pads[CSI_FORMATTER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+	ret = media_entity_pads_init(&sd->entity, CSI_FORMATTER_PAD_NUM,
+				     formatter->pads);
+	if (ret) {
+		dev_err(formatter->dev, "Failed to init pads\n");
+		return ret;
+	}
+
+	ret = v4l2_subdev_init_finalize(sd);
+	if (ret)
+		media_entity_cleanup(&sd->entity);
+
+	return ret;
+}
+
+static inline struct csi_formatter *
+notifier_to_formatter(struct v4l2_async_notifier *n)
+{
+	return container_of(n, struct csi_formatter, notifier);
+}
+
+static int csi_formatter_notify_bound(struct v4l2_async_notifier *notifier,
+				      struct v4l2_subdev *sd,
+				      struct v4l2_async_connection *asc)
+{
+	const unsigned int link_flags = MEDIA_LNK_FL_IMMUTABLE
+				      | MEDIA_LNK_FL_ENABLED;
+	struct csi_formatter *formatter = notifier_to_formatter(notifier);
+	struct v4l2_subdev *sdev = &formatter->sd;
+	struct media_pad *sink = &sdev->entity.pads[CSI_FORMATTER_PAD_SINK];
+	struct media_pad *remote_pad;
+	int ret;
+
+	formatter->csi_sd = sd;
+
+	dev_dbg(formatter->dev, "Bound subdev: %s pad\n", sd->name);
+
+	ret = v4l2_create_fwnode_links_to_pad(sd, sink, link_flags);
+	if (ret < 0)
+		return ret;
+
+	remote_pad = media_pad_remote_pad_first(sink);
+	if (!remote_pad) {
+		dev_err(formatter->dev, "Pipe not setup correctly\n");
+		return -EPIPE;
+	}
+	formatter->remote_pad = remote_pad->index;
+
+	return 0;
+}
+
+static const struct v4l2_async_notifier_operations formatter_notify_ops = {
+	.bound = csi_formatter_notify_bound,
+};
+
+static int csi_formatter_async_register(struct csi_formatter *formatter)
+{
+	struct device *dev = formatter->dev;
+	struct v4l2_async_connection *asc;
+	int ret;
+
+	struct fwnode_handle *ep __free(fwnode_handle) =
+		fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0,
+						FWNODE_GRAPH_ENDPOINT_NEXT);
+	if (!ep)
+		return -ENOTCONN;
+
+	v4l2_async_subdev_nf_init(&formatter->notifier, &formatter->sd);
+
+	asc = v4l2_async_nf_add_fwnode_remote(&formatter->notifier, ep,
+					      struct v4l2_async_connection);
+	if (IS_ERR(asc))
+		return PTR_ERR(asc);
+
+	formatter->notifier.ops = &formatter_notify_ops;
+
+	ret = v4l2_async_nf_register(&formatter->notifier);
+	if (ret)
+		return ret;
+
+	return v4l2_async_register_subdev(&formatter->sd);
+}
+
+/* -----------------------------------------------------------------------------
+ * Suspend/resume
+ */
+
+static int csi_formatter_system_suspend(struct device *dev)
+{
+	return pm_runtime_force_suspend(dev);
+}
+
+static int csi_formatter_system_resume(struct device *dev)
+{
+	int ret;
+
+	ret = pm_runtime_force_resume(dev);
+	if (ret < 0) {
+		dev_err(dev, "force resume %s failed!\n", dev_name(dev));
+		return ret;
+	}
+
+	return 0;
+}
+
+static int csi_formatter_runtime_suspend(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct csi_formatter *formatter = sd_to_formatter(sd);
+
+	clk_disable_unprepare(formatter->clk);
+
+	return 0;
+}
+
+static int csi_formatter_runtime_resume(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct csi_formatter *formatter = sd_to_formatter(sd);
+
+	return clk_prepare_enable(formatter->clk);
+}
+
+static const struct dev_pm_ops csi_formatter_pm_ops = {
+	SYSTEM_SLEEP_PM_OPS(csi_formatter_system_suspend,
+			    csi_formatter_system_resume)
+	RUNTIME_PM_OPS(csi_formatter_runtime_suspend,
+		       csi_formatter_runtime_resume, NULL)
+};
+
+static int csi_formatter_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct csi_formatter *formatter;
+	u32 val;
+	int ret;
+
+	formatter = devm_kzalloc(dev, sizeof(*formatter), GFP_KERNEL);
+	if (!formatter)
+		return -ENOMEM;
+
+	formatter->dev = dev;
+
+	formatter->regs = syscon_node_to_regmap(dev->parent->of_node);
+	if (IS_ERR(formatter->regs))
+		return dev_err_probe(dev, PTR_ERR(formatter->regs),
+				     "Failed to get csi formatter regmap\n");
+
+	ret = of_property_read_u32(dev->of_node, "reg", &val);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "Failed to get csi formatter reg property\n");
+
+	formatter->reg_offset = val;
+
+	formatter->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(formatter->clk))
+		return dev_err_probe(dev, PTR_ERR(formatter->clk),
+				     "Failed to get pixel clock\n");
+
+	ret = csi_formatter_subdev_init(formatter);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "formatter subdev init fail\n");
+
+	/* Initialize formatter pixel format */
+	formatter->fmt = find_csi_format(formatter_default_fmt.code);
+
+	ret = csi_formatter_async_register(formatter);
+	if (ret < 0) {
+		v4l2_subdev_cleanup(&formatter->sd);
+		return dev_err_probe(dev, ret, "Async register failed\n");
+	}
+
+	platform_set_drvdata(pdev, &formatter->sd);
+
+	/* Enable runtime PM. */
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static void csi_formatter_remove(struct platform_device *pdev)
+{
+	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+	struct csi_formatter *formatter = sd_to_formatter(sd);
+
+	v4l2_async_nf_unregister(&formatter->notifier);
+	v4l2_async_nf_cleanup(&formatter->notifier);
+	v4l2_async_unregister_subdev(&formatter->sd);
+
+	pm_runtime_disable(&pdev->dev);
+	media_entity_cleanup(&formatter->sd.entity);
+	pm_runtime_set_suspended(&pdev->dev);
+}
+
+static const struct of_device_id csi_formatter_of_match[] = {
+	{ .compatible = "fsl,imx9-csi-formatter" },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, csi_formatter_of_match);
+
+static struct platform_driver csi_formatter_device_driver = {
+	.driver = {
+		.name           = CSI_FORMATTER_DRV_NAME,
+		.of_match_table = csi_formatter_of_match,
+		.pm             = pm_ptr(&csi_formatter_pm_ops),
+	},
+	.probe  = csi_formatter_probe,
+	.remove = csi_formatter_remove,
+};
+
+module_platform_driver(csi_formatter_device_driver);
+
+MODULE_AUTHOR("NXP Semiconductor, Inc.");
+MODULE_DESCRIPTION("NXP i.MX9 CSI Pixel Formatter driver");
+MODULE_LICENSE("GPL");

-- 
2.34.1



From yuanfang.zhang at oss.qualcomm.com  Thu Dec 18 17:50:18 2025
From: yuanfang.zhang at oss.qualcomm.com (yuanfang zhang)
Date: Fri, 19 Dec 2025 09:50:18 +0800
Subject: [PATCH v2 00/12] coresight: Add CPU cluster funnel/replicator/tmc
 support
In-Reply-To: <20251218104027.GA1790402@e132581.arm.com>
References: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
 <20251218104027.GA1790402@e132581.arm.com>
Message-ID: <927f15d5-da2a-4282-b80f-c1c7563a4367@oss.qualcomm.com>



On 12/18/2025 6:40 PM, Leo Yan wrote:
> Hi,
> 
> On Thu, Dec 18, 2025 at 12:09:40AM -0800, Coresight ML wrote:
> 
> [...]
> 
>> - Utilizing `smp_call_function_single()` to ensure register accesses
>>   (initialization, enablement, sysfs reads) are always executed on a
>>   powered CPU within the target cluster.
> 
> This is concerned as Mike suggested earlier.
> 
> Let me convert to a common question: how does the Linux kernel manage
> a power domain shared by multiple hardware modules?
> 
> A general solution is to bind a power domain (let's say PD1) to both
> module A (MOD_A) and module B (MOD_B).  Each time before accessing MOD_A
> or MOD_B, PD1 must be powered on first via the pm_runtime APIs, with
> its refcount increased accordingly.
> 
> My understanding is the problem in your case is that the driver fails to
> create a relationship between the funnel/replicator modules and the
> cluster power domain.  Instead, you are trying to use the CPUs in the
> same cluster as a delegate for power operations - when you want to
> access MOD_B, your wake up MOD_A which sharing the same power domain,
> only to turn on the PD_A in order to access MOD_B.
> 
> Have you discussed with the firmware and hardware engineers whether it
> is feasible to provide explicit power and clock control interfaces for
> the funnel and replicator modules?  I can imagine the cluster power
> domain's design might differ from other device power domains, but
> should not the hardware provide a sane design that allows software to
> control power for the access logic within it?
> 

It is due to the particular characteristics of the CPU cluster power domain.
Runtime PM for CPU devices works little different, it is mostly used to manage hierarchical
CPU topology (PSCI OSI mode) to talk with genpd framework to manage the last CPU handling in
cluster.
It doesn?t really send IPI to wakeup CPU device (It don?t have .power_on/.power_off) callback
implemented which gets invoked from .runtime_resume callback. This behavior is aligned with
the upstream Kernel.


> General speaking, using smp_call_function_single() makes sense if only
> when accessing logics within the CPU boundary.
> 
> P.s., currently you can use "taskset" as a temporary solution without
> any code change, something like:
> 
>   taskset -c 0 echo 1 > /sys/bus/coresight/devices/etm0/enable_source


This can address the runtime issue, but it does not resolve the problem during the probe phase.

thanks,
Yuanfang> 
> Thanks,
> Leo



From jie.gan at oss.qualcomm.com  Thu Dec 18 18:05:03 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Fri, 19 Dec 2025 10:05:03 +0800
Subject: [PATCH v8 5/8] dt-bindings: arm: add an interrupt property for
 Coresight CTCU
In-Reply-To: <2db74a3e-4aeb-4e87-9fe8-5c9693bfb67c@arm.com>
References: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
 <20251211-enable-byte-cntr-for-ctcu-v8-5-3e12ff313191@oss.qualcomm.com>
 <20251211133723.GA859302-robh@kernel.org>
 <dfa43a63-ca14-4dd7-a7ab-acd95748a8b9@oss.qualcomm.com>
 <a9537dc9-c767-4909-8b1c-6e939ce4f3fc@kernel.org>
 <2db74a3e-4aeb-4e87-9fe8-5c9693bfb67c@arm.com>
Message-ID: <46afd4f6-f287-4d19-bc68-f2f6eac36e6a@oss.qualcomm.com>



On 12/19/2025 7:19 AM, Suzuki K Poulose wrote:
> On 18/12/2025 10:17, Krzysztof Kozlowski wrote:
>> On 12/12/2025 02:12, Jie Gan wrote:
>>>
>>>
>>> On 12/11/2025 9:37 PM, Rob Herring wrote:
>>>> On Thu, Dec 11, 2025 at 02:10:44PM +0800, Jie Gan wrote:
>>>>> Add an interrupt property to CTCU device. The interrupt will be 
>>>>> triggered
>>>>> when the data size in the ETR buffer exceeds the threshold of the
>>>>> BYTECNTRVAL register. Programming a threshold in the BYTECNTRVAL 
>>>>> register
>>>>> of CTCU device will enable the interrupt.
>>>>>
>>>>> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
>>>>> Reviewed-by: Mike Leach <mike.leach at linaro.org>
>>>>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>>>>> ---
>>>>> ?? .../devicetree/bindings/arm/qcom,coresight-ctcu.yaml??? | 17 +++ 
>>>>> ++++++++++++++
>>>>> ?? 1 file changed, 17 insertions(+)
>>>>>
>>>>> diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight- 
>>>>> ctcu.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight- 
>>>>> ctcu.yaml
>>>>> index c969c16c21ef..90f88cc6cd3e 100644
>>>>> --- a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
>>>>> +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
>>>>> @@ -39,6 +39,16 @@ properties:
>>>>> ?????? items:
>>>>> ???????? - const: apb
>>>>> +? interrupts:
>>>>> +??? items:
>>>>> +????? - description: Byte cntr interrupt for the first etr device
>>>>> +????? - description: Byte cntr interrupt for the second etr device
> 
> This is really vague. How do you define first vs second ? Probe order ?
> No way. This must be the "port" number to which the ETR is connected
> to the CTCU. IIUC, there is a config area for each ETR (e.g., trace id
> filter) connected to the CTCU. I was under the assumption that they
> are identified as "ports" (input ports). I don't really understand how
> this interrupt mapping works now. Please explain it clearly.
> 

Sorry for the misunderstanding.

Each ETR device should have its own interrupt line and an IRQ register 
within the CTCU device, as defined by the specification. In existing 
projects, the maximum supported number of ETR devices is 2.

Each interrupt is directly mapped to a specific ETR device, for example:
tmc at 1000 ? interrupt line 0
tmc at 1001 ? interrupt line 1

The suggestion to identify devices by ?ports? is much clearer than my 
previous explanation, as it explicitly shows which device is connected 
to which port.

>>>>> +
>>>>> +? interrupt-names:
>>>>> +??? items:
>>>>> +????? - const: etrirq0
>>>>> +????? - const: etrirq1
>>>>
>>>> Names are kind of pointless when it is just foo<index>.
>>>
>>> Hi Rob,
>>>
>>> I was naming them as etr0/etr1. Are these names acceptable?
>>
>> Obviously irq is redundant, but how does etr0 solves the problem of
>> calling it foo0?
>>
>> I don't think you really read Rob's comment.
>>
>>> The interrupts are assigned exclusively to a specific ETR device.
>>>
>>> But Suzuki is concerned that this might cause confusion because the ETR
>>> device is named randomly in the driver. Suzuki suggested using ?port-0?
>>> and ?port-1? and would also like to hear your feedback on these names.
>>
>> There is no confusion here. Writing bindings luckily clarifies this what
>> the indices in the array mean.
> 
> The point is there are "n" interrupts. Question is, could there be more
> devices(ETRs) connected to the CTCU than "n".
> 
> e.g., Lets CTCU can control upto 4 ETRs and on a particular system, the
> 
> TMC-ETR0 -> CTCU-Port0
> 
> TMC-ETR1 -> CTCU-Port2
> TMC-ETR2 -> CTCU-Port3
> 
> Now, how many interrupts are described in the DT ? How do we map which
> interrupts correspond to the CTCU-Portn. (Finding the TMC-ETRx back
> from the port is possible, with the topology).
> 

Got your point and it's much clearer.

> This is what I raised in the previous version. Again, happy to hear
> if there is a standard way to describe the interrupts.
> 
> Suzuki
> 
> 
>>
>>>
>>> Usually, the probe sequence follows the order of the addresses. In our
>>> specification, ?ETR0? is always probed before ?ETR1? because its address
>>> is lower.
>>
>> How is this even relevant? You are answering to something completely
>> different, so I don't think you really tried to understand review.
>>

My previous explanation was definitely unclear. As Suzuki suggested, 
mapping the interrupt to the port number (to identify the relevant 
device based on topology) makes sense and provides a much easier way to 
understand the relationship between the interrupt and the ETR device.

So with the suggestion, here is the new description about the interrupts:

   interrupts:
     items:
       - description: Interrupt for the ETR device connected to in-port0.
       - description: Interrupt for the ETR device connected to in-port1.

  interrupt-names:
     items:
      - const: port0
      - const: port1

Thanks,
Jie

>>
>>
>> Best regards,
>> Krzysztof
> 



From yuanfang.zhang at oss.qualcomm.com  Thu Dec 18 18:13:14 2025
From: yuanfang.zhang at oss.qualcomm.com (yuanfang zhang)
Date: Fri, 19 Dec 2025 10:13:14 +0800
Subject: [PATCH v2 00/12] coresight: Add CPU cluster funnel/replicator/tmc
 support
In-Reply-To: <20251218-careful-ruby-wildebeest-a8babd@sudeepholla>
References: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
 <20251218-careful-ruby-wildebeest-a8babd@sudeepholla>
Message-ID: <d0ce8306-84e0-4940-98aa-dbc356d87593@oss.qualcomm.com>



On 12/18/2025 7:33 PM, Sudeep Holla wrote:
> On Thu, Dec 18, 2025 at 12:09:40AM -0800, Yuanfang Zhang wrote:
>> This patch series adds support for CoreSight components local to CPU clusters,
>> including funnel, replicator, and TMC, which reside within CPU cluster power
>> domains. These components require special handling due to power domain
>> constraints.
>>
> 
> Could you clarify why PSCI-based power domains associated with clusters in
> domain-idle-states cannot address these requirements, given that PSCI CPU-idle
> OSI mode was originally intended to support them? My understanding of this
> patch series is that OSI mode is unable to do so, which, if accurate, appears
> to be a flaw that should be corrected.

It is due to the particular characteristics of the CPU cluster power domain.Runtime PM for CPU devices works little different, it is mostly used to manage hierarchical
CPU topology (PSCI OSI mode) to talk with genpd framework to manage the last CPU handling in
cluster.
It doesn?t really send IPI to wakeup CPU device (It don?t have .power_on/.power_off) callback
implemented which gets invoked from .runtime_resume callback. This behavior is aligned with
the upstream Kernel.

> 
>> Unlike system-level CoreSight devices, these components share the CPU cluster's
>> power domain. When the cluster enters low-power mode (LPM), their registers
>> become inaccessible. Notably, `pm_runtime_get` alone cannot bring the cluster
>> out of LPM, making standard register access unreliable.
>>
> 
> Are these devices the only ones on the system that are uniquely bound to
> cluster-level power domains? If not, what additional devices share this
> dependency so that we can understand how they are managed in comparison?
> 

Yes, devices like ETM and TRBE also share this power domain and access constraint.
Their drivers naturally handle enablement/disablement on the specific CPU they
belong to (e.g., via hotplug callbacks or existing smp_call_function paths).
>> To address this, the series introduces:
>> - Identifying cluster-bound devices via a new `qcom,cpu-bound-components`
>>   device tree property.
> 
> Really, no please.
> 

Our objective is to determine which CoreSight components are physically locate
within the CPU cluster power domain. 
Would it be acceptable to derive this relationship from the existing power-domains binding?
For example, if a Funnel or Replicator node is linked to a power-domains entry that specifies a cpumask,
the driver could recognize this shared dependency and automatically apply the appropriate cluster-aware behavior.

thanks,
yuanfang.


From vulab at iscas.ac.cn  Thu Dec 18 18:16:15 2025
From: vulab at iscas.ac.cn (Haotian Zhang)
Date: Fri, 19 Dec 2025 10:16:15 +0800
Subject: [PATCH v3] PCI: xilinx: Fix INTx IRQ domain leak in error paths
In-Reply-To: <20251119033301.518-1-vulab@iscas.ac.cn>
References: <20251119033301.518-1-vulab@iscas.ac.cn>
Message-ID: <20251219021615.965-1-vulab@iscas.ac.cn>

In xilinx_pcie_init_irq_domain(), if xilinx_allocate_msi_domains()
fails after pcie->leg_domain has been successfully created via
irq_domain_create_linear(), the function returns directly without
cleaning up the allocated IRQ domain, resulting in a resource leak.
In xilinx_free_msi_domains(), pcie->leg_domain is also neglected.

Add irq_domain_remove() call in the error path to properly release the
IRQ domain before returning the error. Rename xilinx_free_msi_domains()
to xilinx_free_irq_domains() and add the release of pcie->leg_domain
in the function.

Fixes: 313b64c3ae52 ("PCI: xilinx: Convert to MSI domains")
Suggested-by: Manivannan Sadhasivam <mani at kernel.org>
Signed-off-by: Haotian Zhang <vulab at iscas.ac.cn>
---
Changes in v3:
  - Rename xilinx_free_msi_domains() to xilinx_free_irq_domains()
    and add the release of pcie->leg_domain in the function as
    suggested by Manivannan Sadhasivam.
---
Changes in v2:
  - Correct the Fixes tag to point to the commit that introduced the
    legacy IRQ domain leak on MSI allocation failure.
---
 drivers/pci/controller/pcie-xilinx.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/controller/pcie-xilinx.c b/drivers/pci/controller/pcie-xilinx.c
index 937ea6ae1ac4..4aa139abac16 100644
--- a/drivers/pci/controller/pcie-xilinx.c
+++ b/drivers/pci/controller/pcie-xilinx.c
@@ -302,9 +302,10 @@ static int xilinx_allocate_msi_domains(struct xilinx_pcie *pcie)
 	return 0;
 }
 
-static void xilinx_free_msi_domains(struct xilinx_pcie *pcie)
+static void xilinx_free_irq_domains(struct xilinx_pcie *pcie)
 {
 	irq_domain_remove(pcie->msi_domain);
+	irq_domain_remove(pcie->leg_domain);
 }
 
 /* INTx Functions */
@@ -480,8 +481,10 @@ static int xilinx_pcie_init_irq_domain(struct xilinx_pcie *pcie)
 		phys_addr_t pa = ALIGN_DOWN(virt_to_phys(pcie), SZ_4K);
 
 		ret = xilinx_allocate_msi_domains(pcie);
-		if (ret)
+		if (ret) {
+			irq_domain_remove(pcie->leg_domain);
 			return ret;
+		}
 
 		pcie_write(pcie, upper_32_bits(pa), XILINX_PCIE_REG_MSIBASE1);
 		pcie_write(pcie, lower_32_bits(pa), XILINX_PCIE_REG_MSIBASE2);
@@ -600,7 +603,7 @@ static int xilinx_pcie_probe(struct platform_device *pdev)
 
 	err = pci_host_probe(bridge);
 	if (err)
-		xilinx_free_msi_domains(pcie);
+		xilinx_free_irq_domains(pcie);
 
 	return err;
 }
-- 
2.50.1.windows.1



From andersson at kernel.org  Thu Dec 18 18:23:37 2025
From: andersson at kernel.org (Bjorn Andersson)
Date: Thu, 18 Dec 2025 20:23:37 -0600
Subject: [PATCH v6 2/5] remoteproc: imx_rproc: Populate devices under
 "rpmsg" subnode
In-Reply-To: <20251212194341.966387-3-shenwei.wang@nxp.com>
References: <20251212194341.966387-1-shenwei.wang@nxp.com>
 <20251212194341.966387-3-shenwei.wang@nxp.com>
Message-ID: <3bbemd2vbsfss3sqpjpokytvvzweoqrtiqygffj5vqazqk3jyq@eobv6ruriiwb>

On Fri, Dec 12, 2025 at 01:43:38PM -0600, Shenwei Wang wrote:
> Register the RPMsg channel driver and populate remote devices defined
> under the "rpmsg" subnode upon receiving their notification messages.

Please provide a proper description of what "problem" this patch solves.

> 
> The following illustrates the expected DTS layout structure:
> 
> 	cm33: remoteproc-cm33 {
> 		compatible = "fsl,imx8ulp-cm33";
> 
> 		rpmsg {
> 			rpmsg-io-channel {
> 				gpio at 0 {
> 					compatible = "fsl,imx-rpmsg-gpio";
> 					reg = <0>;

Surely there needs to be some "gpio-controller" and "#gpio-cells" here?
Would be useful if the example is somewhat complete, to give a picture
of what's actually going on.

> 				};
> 
> 				gpio at 1 {
> 					compatible = "fsl,imx-rpmsg-gpio";
> 					reg = <1>;
> 				};
> 
> 				...
> 			};
> 
> 			...
> 		};
> 	};
> 
> Signed-off-by: Shenwei Wang <shenwei.wang at nxp.com>
> ---
>  drivers/remoteproc/imx_rproc.c   | 143 +++++++++++++++++++++++++++++++
>  include/linux/rpmsg/rpdev_info.h |  33 +++++++
>  2 files changed, 176 insertions(+)
>  create mode 100644 include/linux/rpmsg/rpdev_info.h
> 
> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
> index 33f21ab24c92..65ee16fd66d1 100644
> --- a/drivers/remoteproc/imx_rproc.c
> +++ b/drivers/remoteproc/imx_rproc.c
> @@ -15,6 +15,8 @@
>  #include <linux/module.h>
>  #include <linux/of.h>
>  #include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
>  #include <linux/of_reserved_mem.h>
>  #include <linux/platform_device.h>
>  #include <linux/pm_domain.h>
> @@ -22,6 +24,8 @@
>  #include <linux/reboot.h>
>  #include <linux/regmap.h>
>  #include <linux/remoteproc.h>
> +#include <linux/rpmsg.h>
> +#include <linux/rpmsg/rpdev_info.h>
>  #include <linux/workqueue.h>
>  
>  #include "imx_rproc.h"
> @@ -1016,6 +1020,141 @@ static void imx_rproc_destroy_workqueue(void *data)
>  	destroy_workqueue(workqueue);
>  }
>  
> +struct imx_rpmsg_driver {
> +	struct rpmsg_driver rpdrv;
> +	const char *compat;
> +	void *driver_data;
> +};
> +
> +static const char *channel_device_map[][2] = {
> +	{"rpmsg-io-channel", "rpmsg-gpio"},
> +};
> +
> +static int imx_rpmsg_endpoint_cb(struct rpmsg_device *rpdev, void *data,
> +				 int len, void *priv, u32 src)
> +{
> +	struct rpdev_platform_info *drvdata;
> +
> +	drvdata = dev_get_drvdata(&rpdev->dev);
> +	if (drvdata && drvdata->rx_callback)
> +		return drvdata->rx_callback(rpdev, data, len, priv, src);
> +
> +	return 0;
> +}
> +
> +static void imx_rpmsg_endpoint_remove(struct rpmsg_device *rpdev)
> +{
> +	of_platform_depopulate(&rpdev->dev);
> +}
> +
> +static int imx_rpmsg_endpoint_probe(struct rpmsg_device *rpdev)
> +{
> +	struct rpdev_platform_info *drvdata;
> +	struct imx_rpmsg_driver *imx_rpdrv;
> +	struct device *dev = &rpdev->dev;
> +	struct of_dev_auxdata *auxdata;
> +	struct rpmsg_driver *rpdrv;
> +
> +	rpdrv = container_of(dev->driver, struct rpmsg_driver, drv);
> +	imx_rpdrv = container_of(rpdrv, struct imx_rpmsg_driver, rpdrv);
> +
> +	if (!imx_rpdrv->driver_data)
> +		return -EINVAL;
> +
> +	drvdata = devm_kmemdup(dev, imx_rpdrv->driver_data, sizeof(*drvdata), GFP_KERNEL);
> +	if (!drvdata)
> +		return -ENOMEM;
> +
> +	auxdata = devm_kzalloc(dev, sizeof(*auxdata) * 2, GFP_KERNEL);
> +	if (!auxdata)
> +		return -ENOMEM;
> +
> +	drvdata->rpdev = rpdev;
> +	auxdata[0].compatible = devm_kstrdup(dev, imx_rpdrv->compat, GFP_KERNEL);
> +	auxdata[0].platform_data = drvdata;
> +	dev_set_drvdata(dev, drvdata);
> +
> +	of_platform_populate(drvdata->channel_node, NULL, auxdata, dev);

auxiliary_bus would be a better choice, but I don't understand why you
probe a rpmsg_device for each "gpio channel" and then from that create a
platform_device.

Why don't you just make the rpmsg_device register the gpio controller
directly?

> +
> +	return 0;
> +}
> +
> +static const char *imx_of_rpmsg_is_in_map(const char *name)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(channel_device_map); i++) {
> +		if (strcmp(name, channel_device_map[i][0]) == 0)
> +			return channel_device_map[i][1];
> +	}
> +
> +	return NULL;
> +}
> +
> +static int imx_of_rpmsg_register_rpdriver(struct device_node *channel,
> +					  struct device *dev,
> +					  const char *name,
> +					  const char *compat)
> +{
> +	struct rpdev_platform_info *driver_data;
> +	struct imx_rpmsg_driver *rp_driver;
> +	struct rpmsg_device_id *rpdev_id;
> +
> +	/* rpmsg_device_id is a NULL terminated array */
> +	rpdev_id = devm_kzalloc(dev, sizeof(*rpdev_id) * 2, GFP_KERNEL);
> +	if (!rpdev_id)
> +		return -ENOMEM;
> +
> +	strscpy(rpdev_id[0].name, name, RPMSG_NAME_SIZE);
> +
> +	rp_driver = devm_kzalloc(dev, sizeof(*rp_driver), GFP_KERNEL);
> +	if (!rp_driver)
> +		return -ENOMEM;
> +
> +	driver_data = devm_kzalloc(dev, sizeof(*driver_data), GFP_KERNEL);
> +	if (!driver_data)
> +		return -ENOMEM;
> +
> +	driver_data->rproc_name = dev->of_node->name;
> +	driver_data->channel_node = channel;
> +
> +	rp_driver->rpdrv.drv.name = name;
> +	rp_driver->rpdrv.id_table = rpdev_id;
> +	rp_driver->rpdrv.probe = imx_rpmsg_endpoint_probe;
> +	rp_driver->rpdrv.remove = imx_rpmsg_endpoint_remove;
> +	rp_driver->rpdrv.callback = imx_rpmsg_endpoint_cb;
> +	rp_driver->driver_data = driver_data;
> +	rp_driver->compat = compat;
> +
> +	register_rpmsg_driver(&rp_driver->rpdrv);

This would then also imply that it's the gpio driver that registers the
rpmsg_driver.

> +
> +	return 0;
> +}
> +
> +static int rproc_of_rpmsg_node_init(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	const char *compat;
> +	int ret;
> +
> +	struct device_node *np __free(device_node) = of_get_child_by_name(dev->of_node, "rpmsg");
> +	if (!np)
> +		return 0;
> +
> +	for_each_child_of_node_scoped(np, child) {
> +		compat = imx_of_rpmsg_is_in_map(child->name);
> +		if (!compat)
> +			ret = of_platform_default_populate(child, NULL, dev);

So if you don't recognize the child device node name you just register
platform_devices for each of the children?

> +		else
> +			ret = imx_of_rpmsg_register_rpdriver(child, dev, child->name, compat);
> +
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
>  static int imx_rproc_probe(struct platform_device *pdev)
>  {
>  	struct device *dev = &pdev->dev;
> @@ -1114,6 +1253,10 @@ static int imx_rproc_probe(struct platform_device *pdev)
>  		goto err_put_pm;
>  	}
>  
> +	ret = rproc_of_rpmsg_node_init(pdev);
> +	if (ret < 0)
> +		dev_info(dev, "populating 'rpmsg' node failed\n");
> +
>  	return 0;
>  
>  err_put_pm:
> diff --git a/include/linux/rpmsg/rpdev_info.h b/include/linux/rpmsg/rpdev_info.h
> new file mode 100644
> index 000000000000..13e020cd028b
> --- /dev/null
> +++ b/include/linux/rpmsg/rpdev_info.h
> @@ -0,0 +1,33 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright 2025 NXP */
> +
> +/*
> + * @file linux/rpdev_info.h
> + *
> + * @brief Global header file for RPDEV Info
> + *
> + * @ingroup RPMSG
> + */
> +#ifndef __LINUX_RPDEV_INFO_H__
> +#define __LINUX_RPDEV_INFO_H__
> +
> +#define MAX_DEV_PER_CHANNEL    10
> +
> +/**
> + * rpdev_platform_info - store the platform information of rpdev
> + * @rproc_name: the name of the remote proc.
> + * @rpdev: rpmsg channel device
> + * @device_node: pointer to the device node of the rpdev.
> + * @rx_callback: rx callback handler of the rpdev.
> + * @channel_devices: an array of the devices related to the rpdev.
> + */
> +struct rpdev_platform_info {

I don't understand what this structure represents. Why is this glue
between the rpmsg_device and a made up platform_device needed?

> +	const char *rproc_name;

You don't need this, because you can rproc_get_by_child(&self) and then
get the remoteproc name from that.

> +	struct rpmsg_device *rpdev;
> +	struct device_node *channel_node;
> +	int (*rx_callback)(struct rpmsg_device *rpdev, void *data,
> +			   int len, void *priv, u32 src);
> +	void *channel_devices[MAX_DEV_PER_CHANNEL];

Why 10? What does it mean?

I think this becomes the list of the 10 grandchildren of the remoteproc
(per child node). So what happens if those matches against two different
drivers, what will rx_callback point to?

> +};

Regards,
Bjorn

> +
> +#endif /* __LINUX_RPDEV_INFO_H__ */
> -- 
> 2.43.0
> 


From andersson at kernel.org  Thu Dec 18 18:39:22 2025
From: andersson at kernel.org (Bjorn Andersson)
Date: Thu, 18 Dec 2025 20:39:22 -0600
Subject: Proposal: document where SoC info belongs
In-Reply-To: <CAD=FV=W+jE_L_LLgAhD8K_4+CtivSD9-9t7Xe63XuKrKjfyfeQ@mail.gmail.com>
References: <CAD=FV=W+jE_L_LLgAhD8K_4+CtivSD9-9t7Xe63XuKrKjfyfeQ@mail.gmail.com>
Message-ID: <qjpukes4etbgh4ncapec4v6okkiohlcqqdfvjfinyrj6olaryc@l3vspbwze7ri>

On Thu, Dec 18, 2025 at 02:56:03PM -0800, Doug Anderson wrote:
> Hi,
> 
> To try to move things along, I'm picking a small piece out of my
> previous discussion [1] to see if we can make some progress.
> 
> Right now, the top-level "compatible" string in a dts file usually
> contains one or more strings to represent the SoC. Examples chosen
> semi-randomly:
> 
> exynos5250-snow.dts:
> - compatible: "google,snow-rev4", "google,snow", "samsung,exynos5250",
> "samsung,exynos5"
> - SoC: "samsung,exynos5250", "samsung,exynos5"
> 
> sun20i-d1-clockworkpi-v3.14.dts:
> - compatible: "clockwork,r-01-clockworkpi-v3.14", "allwinner,sun20i-d1"
> - SoC: "allwinner,sun20i-d1"
> 
> sdm845-db845c.dts:
> - compatible: "thundercomm,db845c", "qcom,sdm845"
> - SoC: "qcom,sdm845"
> 
> I propose that we DEPRECATE including SoC information in the top-level
> compatible string and move it elsewhere. I propose these top-level
> properties that should be used instead:
> 
> soc-family-compatible = "vendor,family";
> soc-product-id = <0x1234>;
> soc-product-variant = <0x1234>;
> soc-product-description = "Something";
> soc-major-rev = <0x1234>;
> soc-minor-rev = <0x1234>;
> soc-sub-rev = <0x1234>;

So these 6 properties defines the soc itself? And the rules for how a
bootloader matches against these 6 properties is defined elsewhere?

What about "PCB" name and version?

How about the case where my product has 5 different components that
might come from a second source?

Are you proposing that we allow adding arbitrary properties matching
some pattern in the top-level node to facilitate matching? Presumably
defined in some combination of vendor bindings?

> 
> The family-compatible would be VERY high-level and is not intended to
> be a marketing name. It would be something like "samsung,exynos",
> "nvidia,tegra" or "google,google-silicon". The ONLY goal for this
> string is that within a family, the other properties uniquely identify
> a given SoC. This is a SINGLE string, NOT a list of strings. There is
> no concept of being part of multiple families.
> 
> All the other numbers are hopefully self-explanatory. These values
> could be absent (assumed 0) if they don't make sense for a given SoC.
> 
> The soc-product-description is designed to be some nice name that
> represents the family, product-id, and product-variant but _not_ the
> rev (since that's easy for anyone who cares to represent it as "rev
> X.Y.Z")
> 
> 
> The goals here are:
> * Stop trying to jam so much into the top-level "compatible".
> * Make it one step easier for bootloaders (or code packaging device
> trees for bootloaders) to differentiate device trees / overlays. This
> isn't _enough_ since this proposal doesn't include board info, but
> it's a place to start.
> * Make it easier to deal with "socketed" boards where the SoC can be replaced.
> 
> NOTE: if a set of devicetrees is provided to a bootloader, it could
> not just look at these properties to help it pick a devicetree but it
> could also change the properties to be more detailed (it could fill in
> some of the minor/sub-revs, for instance).
> 
> 
> I think this is a positive change for everyone and a cleaner way to
> represent things even if you aren't dealing with the above problems.
> 
> What I'm looking for from people is some responses. Folks could choose:
> 
> A) Yes, this is great. We already have something like this and we'd
> switch to your properties if it became a standard.
> 

We have qcom,msm-id; qcom,board-id; qcom,pmic-id; these have met the
needs of some, but generally it lacks multiple axis.

> B) I like the idea, but I need an extra property to represent my SoC
> and then I'd use it.
> 

s/an/several/

> C) I like the idea and I'd use it, but with some changes.
> 
> D) We don't have anything like this today, but it sounds useful.
> 
> E) Why are you wasting my time? This isn't a useful problem. The SoC
> belongs in the top-level compatible string, period.
> 

We do have functionality that relates to the generic soc name,
(qcom,sdm845 in your example above). Extracting it into something else
would imply that we need to check against soc-family-compatible?

But when it comes to bootloaders picking the appropriate compatible,
I've seen plenty of cases where basing it on compatible would be nasty.

E.g. how do you write your string matching routine such that it allows
all the different axis, where some are optional, some allows fallback to
previous minor revisions of the chip etc.

Regards,
Bjorn

> F) Other (please specify)
> 
> 
> FWIW, from chatting with Rob Herring offline, my understanding is:
> * He doesn't think that using the "soc at 0" is the right place for these
> properties.
> * He didn't seem enthusiastic about adding a new node and was more
> amenable to adding properties, which is why I added a pile of
> top-level properties.
> 
> 
> [1] https://lore.kernel.org/r/CAD=FV=Ux7nGFnYEyX0cUL-9__BKnTYc+kAJjkF458ZnFS7zoJA at mail.gmail.com


From make24 at iscas.ac.cn  Thu Dec 18 18:39:49 2025
From: make24 at iscas.ac.cn (Ma Ke)
Date: Fri, 19 Dec 2025 10:39:49 +0800
Subject: [PATCH v2 RESEND] coresight: etm-perf: Fix reference count leak in etm_setup_aux
In-Reply-To: <f85c7d37-4980-46f0-9136-353a35a8f0ed@oss.qualcomm.com>
References: <f85c7d37-4980-46f0-9136-353a35a8f0ed@oss.qualcomm.com>
Message-ID: <20251219023949.12699-1-make24@iscas.ac.cn>

On 12/15/2025 10:09 AM, Jie Gan wrote:
> On 12/15/2025 5:51 PM, Leo Yan wrote:
>> On Mon, Dec 15, 2025 at 11:02:08AM +0200, James Clark wrote:
>>>
>>>
>>> On 15/12/2025 04:27, Ma Ke wrote:
>>>> In etm_setup_aux(), when a user sink is obtained via
>>>> coresight_get_sink_by_id(), it increments the reference count of the
>>>> sink device. However, if the sink is used in path building, the path
>>>> holds a reference, but the initial reference from
>>>> coresight_get_sink_by_id() is not released, causing a reference count
>>>> leak. We should release the initial reference after the path is built.
>>>>
>>>> Found by code review.
>>>>
>>>> Cc: stable at vger.kernel.org
>>>> Fixes: 0e6c20517596 ("coresight: etm-perf: Allow an event to use different sinks")
>>>> Signed-off-by: Ma Ke <make24 at iscas.ac.cn>
>>>> ---
>>>> Changes in v2:
>>>> - modified the patch as suggestions.
>>>
>>> I think Leo's comment on the previous v2 is still unaddressed. But releasing
>>> it in coresight_get_sink_by_id() would make it consistent with
>>> coresight_find_csdev_by_fwnode() and prevent further mistakes.
>> 
>> The point is the coresight core layer uses coresight_grab_device() to
>> increase the device's refcnt.  This is why we don't need to grab a
>> device when setup AUX.
>
> That make sense. We dont need to hold the refcnt for a while and it 
> should be released immediately after locating the required device.
>
> Thanks,
> Jie

>> 
>>> It also leads me to see that users of coresight_find_device_by_fwnode()
>>> should also release it, but only one out of two appears to.
>> 
>> Good finding!
>> 
>> Thanks,
>> Leo
>> 
Hi all,

Thank you for the insightful discussion. I've carefully read the 
feedback from Leo, James, and Jie, and now have a clear understanding 
of the reference count management.

The core issue: coresight_get_sink_by_id() internally calls 
bus_find_device(), which increases reference count via get_device().

>From the discussion, I note two possible fix directions:

1. Release the initial reference in etm_setup_aux() (current v2 patch)
2. Modify the behavior of coresight_get_sink_by_id() itself so it 
doesn't increase the reference count. 

Leo mentioned referencing how acpi_dev_present() does it, and James 
also pointed out that APIs should be consistent. I think it makes 
sense that following the principle like "lookup doesn't hold a 
reference" could prevent similar leaks in the future.

To ensure the correctness of the v3 patch, I'd like to confirm which 
patch is preferred. If option 2 is the consensus, I'm happy to modify 
the implementation of coresight_get_sink_by_id() as suggested.

Looking forward to your further guidance.

Thanks!



From xianwei.zhao at amlogic.com  Thu Dec 18 18:46:16 2025
From: xianwei.zhao at amlogic.com (Xianwei Zhao)
Date: Fri, 19 Dec 2025 10:46:16 +0800
Subject: [PATCH 2/4] arm64: dts: amlogic: Add S6 Reset Controller
In-Reply-To: <CAFBinCA19ws1OmfZLh+OSmiEuvY4owOKyzFpaz5KO6E8HaKmmg@mail.gmail.com>
References: <20251127-reset-s6-s7-s7d-v1-0-879099ad90d3@amlogic.com>
 <20251127-reset-s6-s7-s7d-v1-2-879099ad90d3@amlogic.com>
 <CAFBinCA19ws1OmfZLh+OSmiEuvY4owOKyzFpaz5KO6E8HaKmmg@mail.gmail.com>
Message-ID: <7d6084d2-3c56-43b8-8337-0b696614e4fb@amlogic.com>

Hi Martin,
    Thanks for your reply.

On 2025/12/17 23:51, Martin Blumenstingl wrote:
> [ EXTERNAL EMAIL ]
> 
> On Thu, Nov 27, 2025 at 8:30?AM Xianwei Zhao via B4 Relay
> <devnull+xianwei.zhao.amlogic.com at kernel.org> wrote:
> [...]
>> +#define RESET_BRG_MAIL_DMC_PIPEL       167
> On the S7 SoC this reset line is called RESET_BRG_MALI_PIPL0:
> - is MAIL <> MALI a typo (seems like it should be MALI)?
Yes. I will fix it.
> - and is PIPEL <> PIPL also a typo (I don't know which one is "correct")?
PIPEL is PIPE , I will fix it.




From jie.gan at oss.qualcomm.com  Thu Dec 18 19:31:49 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Fri, 19 Dec 2025 11:31:49 +0800
Subject: [PATCH v4 1/3] coresight: tpda: add sysfs nodes for tpda
 cross-trigger configuration
In-Reply-To: <a785ced7-95ae-444b-b8ca-b40aecb35230@arm.com>
References: <20251028-configure_tpda_reg-v4-0-23000805d21d@oss.qualcomm.com>
 <20251028-configure_tpda_reg-v4-1-23000805d21d@oss.qualcomm.com>
 <a785ced7-95ae-444b-b8ca-b40aecb35230@arm.com>
Message-ID: <f049f546-5df0-4d17-a025-e1a46eb035fc@oss.qualcomm.com>



On 12/18/2025 7:10 PM, Suzuki K Poulose wrote:
> On 28/10/2025 02:02, Jie Gan wrote:
>> From: Tao Zhang <tao.zhang at oss.qualcomm.com>
>>
>> Introduce sysfs nodes to configure cross-trigger parameters for TPDA.
>> These registers define the characteristics of cross-trigger packets,
>> including generation frequency and flag values.
>>
>> Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
>> Reviewed-by: James Clark <james.clark at linaro.org>
>> Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> ---
>> ? .../ABI/testing/sysfs-bus-coresight-devices-tpda?? |? 43 ++++
>> ? drivers/hwtracing/coresight/coresight-tpda.c?????? | 230 +++++++++++ 
>> ++++++++++
>> ? drivers/hwtracing/coresight/coresight-tpda.h?????? |? 27 ++-
>> ? 3 files changed, 299 insertions(+), 1 deletion(-)
>>
>> diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices- 
>> tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
>> new file mode 100644
>> index 000000000000..80e4b05a1ab4
>> --- /dev/null
>> +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
>> @@ -0,0 +1,43 @@
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/trig_async_enable
>> +Date:??????? October 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Enable/disable cross trigger synchronization sequence 
>> interface.
>> +
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/trig_flag_ts_enable
>> +Date:??????? October 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Enable/disable cross trigger FLAG packet request interface.
>> +
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/trig_freq_enable
>> +Date:??????? October 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Enable/disable cross trigger FREQ packet request interface.
>> +
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/freq_ts_enable
>> +Date:??????? October 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Enable/disable the timestamp for all FREQ packets.
>> +
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/global_flush_req
>> +Date:??????? October 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Set global (all ports) flush request bit. The bit 
>> remains set until a
>> +??????? global flush request sequence completes.
>> +
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/cmbchan_mode
>> +Date:??????? October 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Configure the CMB/MCMB channel mode for all enabled ports.
>> +??????? Value 0 means raw channel mapping mode. Value 1 means channel 
>> pair marking mode.
>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/ 
>> hwtracing/coresight/coresight-tpda.c
>> index 333b3cb23685..a9a27bcc65a1 100644
>> --- a/drivers/hwtracing/coresight/coresight-tpda.c
>> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
>> @@ -147,9 +147,37 @@ static void tpda_enable_pre_port(struct 
>> tpda_drvdata *drvdata)
>> ????? u32 val;
>> ????? val = readl_relaxed(drvdata->base + TPDA_CR);
>> +??? val &= ~TPDA_CR_MID;
>> ????? val &= ~TPDA_CR_ATID;
> 
> See, below.
> 
>> ????? val |= FIELD_PREP(TPDA_CR_ATID, drvdata->atid);
>> +??? if (drvdata->trig_async)
>> +??????? val |= TPDA_CR_SRIE;
>> +??? else
>> +??????? val &= ~TPDA_CR_SRIE;
>> +??? if (drvdata->trig_flag_ts)
>> +??????? val |= TPDA_CR_FLRIE;
>> +??? else
>> +??????? val &= ~TPDA_CR_FLRIE;
>> +??? if (drvdata->trig_freq)
>> +??????? val |= TPDA_CR_FRIE;
>> +??? else
>> +??????? val &= ~TPDA_CR_FRIE;
>> +??? if (drvdata->freq_ts)
>> +??????? val |= TPDA_CR_FREQTS;
>> +??? else
>> +??????? val &= ~TPDA_CR_FREQTS;
>> +??? if (drvdata->cmbchan_mode)
>> +??????? val |= TPDA_CR_CMBCHANMODE;
>> +??? else
>> +??????? val &= ~TPDA_CR_CMBCHANMODE;
> 
> Could we clear all of the bits that are configurable in one go in the
> beginning and set the appropriate ones based on the setting ? i.e.:
> 
> Do we really need to retain any values ? And if not, why not start
> with a fresh set of values and avoid the read ?

Got it. We can start with a clean value and set the required bits, 
without needing to read the register once.

> 
>> ????? writel_relaxed(val, drvdata->base + TPDA_CR);
>> +
>> +??? /*
>> +???? * If FLRIE bit is set, set the master and channel
>> +???? * id as zero
>> +???? */
>> +??? if (drvdata->trig_flag_ts)
>> +??????? writel_relaxed(0x0, drvdata->base + TPDA_FPID_CR);
>> ? }
>> ? static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
>> @@ -265,6 +293,206 @@ static const struct coresight_ops tpda_cs_ops = {
>> ????? .link_ops??? = &tpda_link_ops,
>> ? };
>> +static ssize_t trig_async_enable_show(struct device *dev,
>> +????????????????????? struct device_attribute *attr,
>> +????????????????????? char *buf)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +
>> +??? return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_async);
>> +}
>> +
>> +static ssize_t trig_async_enable_store(struct device *dev,
>> +?????????????????????? struct device_attribute *attr,
>> +?????????????????????? const char *buf,
>> +?????????????????????? size_t size)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +??? unsigned long val;
>> +
>> +??? if (kstrtoul(buf, 0, &val))
>> +??????? return -EINVAL;
>> +
>> +??? guard(spinlock)(&drvdata->spinlock);
>> +??? drvdata->trig_async = !!val;
>> +
> 
> 
> 
>> +??? return size;
>> +}
>> +static DEVICE_ATTR_RW(trig_async_enable);
> 
> ...
> 
>> +static DEVICE_ATTR_RW(trig_flag_ts_enable);
> 
> ...
> 
>> +static DEVICE_ATTR_RW(trig_freq_enable);
> 
> ...
>> +static DEVICE_ATTR_RW(freq_ts_enable);
> 
> These attribute are boolean and looks like we could save some space on
> code by using dev_ext_attribute.
> see tpdm_simple_dataset_rw()/tpdm_simple_dataset_ro() . You could
> 
> #define TPDA_TRIG_ASYNC??????? 0
> #define TPDA_TRIG_FLAG_TS???? 1
> #define TPDA_TRIG_FREQ??????? 2
> 
> 
> tpda_trig_sysfs_show/store()
> 
>  ?bool *ptr;
>  ?switch (eattr->var) {
>  ?case TPDA_TRIG_ASYNC:
>  ????ptr = &drvdata->trig_async;
>  ????break;
>  ?case TPDA_TRIG_FLAG_TS:
>  ????ptr = &drvdata->trig_flag_ts;
>  ????break;
> ...
> 
>  ?}
> 

Will wrap in tpda_trig_sysfs_show/store().

> 
> 
>> +
>> +static ssize_t global_flush_req_show(struct device *dev,
>> +???????????????????? struct device_attribute *attr,
>> +???????????????????? char *buf)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +??? unsigned long val;
>> +
>> +??? if (!drvdata->csdev->refcnt)
>> +??????? return -EINVAL;
>> +
>> +??? guard(spinlock)(&drvdata->spinlock);
>> +??? CS_UNLOCK(drvdata->base);
>> +??? val = readl_relaxed(drvdata->base + TPDA_CR);
>> +??? CS_LOCK(drvdata->base);
>> +??? /* Only read value for bit 0 */
>> +??? val &= BIT(0);
>> +
>> +??? return sysfs_emit(buf, "%lu\n", val);
>> +}
>> +
>> +static ssize_t global_flush_req_store(struct device *dev,
>> +????????????????????? struct device_attribute *attr,
>> +????????????????????? const char *buf,
>> +????????????????????? size_t size)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +??? unsigned long val;
>> +
>> +??? if (kstrtoul(buf, 0, &val))
>> +??????? return -EINVAL;
>> +
>> +??? if (!drvdata->csdev->refcnt || !val)
>> +??????? return -EINVAL;
>> +
>> +??? guard(spinlock)(&drvdata->spinlock);
>> +??? CS_UNLOCK(drvdata->base);
>> +??? val = readl_relaxed(drvdata->base + TPDA_CR);
>> +??? /* Only set bit 0 */
>> +??? val |= BIT(0);
> 
> What is BIT 0 ? Please document it

will document it.

Bit0 is Global (all ports) flush request bit.
Set 1 means a flush request is made for all ports.

> 
>> +??? writel_relaxed(val, drvdata->base + TPDA_CR);
>> +??? CS_LOCK(drvdata->base);
>> +
>> +??? return size;
>> +}
>> +static DEVICE_ATTR_RW(global_flush_req);
> 
> 
> 
>> +
>> +static ssize_t cmbchan_mode_show(struct device *dev,
>> +???????????????? struct device_attribute *attr,
>> +???????????????? char *buf)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +
>> +??? return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->cmbchan_mode);
>> +}
>> +
>> +static ssize_t cmbchan_mode_store(struct device *dev,
>> +????????????????? struct device_attribute *attr,
>> +????????????????? const char *buf,
>> +????????????????? size_t size)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +??? unsigned long val;
>> +
>> +??? if (kstrtoul(buf, 0, &val))
>> +??????? return -EINVAL;
>> +
>> +??? guard(spinlock)(&drvdata->spinlock);
>> +??? drvdata->cmbchan_mode = !!val;
>> +
>> +??? return size;
>> +}
>> +static DEVICE_ATTR_RW(cmbchan_mode);
> 
> Even this could go to the dev_ext_attribute magic and reuse a single 
> show/store.

Got it.

> 
>> +
>> +static struct attribute *tpda_attrs[] = {
>> +??? &dev_attr_trig_async_enable.attr,
>> +??? &dev_attr_trig_flag_ts_enable.attr,
>> +??? &dev_attr_trig_freq_enable.attr,
>> +??? &dev_attr_freq_ts_enable.attr,
>> +??? &dev_attr_global_flush_req.attr,
>> +??? &dev_attr_cmbchan_mode.attr,
>> +??? NULL,
>> +};
> 
>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/ 
>> hwtracing/coresight/coresight-tpda.h
>> index c6af3d2da3ef..0be625fb52fd 100644
>> --- a/drivers/hwtracing/coresight/coresight-tpda.h
>> +++ b/drivers/hwtracing/coresight/coresight-tpda.h
>> @@ -1,6 +1,6 @@
>> ? /* SPDX-License-Identifier: GPL-2.0 */
>> ? /*
>> - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights 
>> reserved.
>> + * Copyright (c) 2023,2025 Qualcomm Innovation Center, Inc. All 
>> rights reserved.
>> ?? */
>> ? #ifndef _CORESIGHT_CORESIGHT_TPDA_H
>> @@ -8,6 +8,19 @@
>> ? #define TPDA_CR??????????? (0x000)
>> ? #define TPDA_Pn_CR(n)??????? (0x004 + (n * 4))
>> +#define TPDA_FPID_CR??????? (0x084)
>> +
>> +/* Cross trigger FREQ packets timestamp bit */
>> +#define TPDA_CR_FREQTS??????? BIT(2)
>> +/* Cross trigger FREQ packet request bit */
>> +#define TPDA_CR_FRIE??????? BIT(3)
>> +/* Cross trigger FLAG packet request interface bit */
>> +#define TPDA_CR_FLRIE??????? BIT(4)
>> +/* Cross trigger synchronization bit */
>> +#define TPDA_CR_SRIE??????? BIT(5)
>> +/* Packetize CMB/MCMB traffic bit */
>> +#define TPDA_CR_CMBCHANMODE??? BIT(20)
>> +
> 
> Why are these not clubbed with the other TPDA_CR_ defintions ?

I should put this bit after:

    /* Bits 6 ~ 12 is for atid value */
    #define TPDA_CR_ATID        GENMASK(12, 6)
  +/* Bits 13 ~ 19 is for mid value */
  +#define TPDA_CR_MID        GENMASK(19, 13)

MID here is the master ID which is used to identify the TPDA device 
itself in received packets when multiple tpda devices are enabled.

Thanks,
Jie

> 
>> ? /* Aggregator port enable bit */
>> ? #define TPDA_Pn_CR_ENA??????? BIT(0)
>> ? /* Aggregator port CMB data set element size bit */
>> @@ -19,6 +32,8 @@
>> ? /* Bits 6 ~ 12 is for atid value */
>> ? #define TPDA_CR_ATID??????? GENMASK(12, 6)
>> +/* Bits 13 ~ 19 is for mid value */
>> +#define TPDA_CR_MID??????? GENMASK(19, 13)
>> ? /**
>> ?? * struct tpda_drvdata - specifics associated to an TPDA component
>> @@ -29,6 +44,11 @@
>> ?? * @enable:???? enable status of the component.
>> ?? * @dsb_esize?? Record the DSB element size.
>> ?? * @cmb_esize?? Record the CMB element size.
>> + * @trig_async:??? Enable/disable cross trigger synchronization 
>> sequence interface.
>> + * @trig_flag_ts: Enable/disable cross trigger FLAG packet request 
>> interface.
>> + * @trig_freq:??? Enable/disable cross trigger FREQ packet request 
>> interface.
>> + * @freq_ts:??? Enable/disable the timestamp for all FREQ packets.
>> + * @cmbchan_mode: Configure the CMB/MCMB channel mode.
>> ?? */
>> ? struct tpda_drvdata {
>> ????? void __iomem??????? *base;
>> @@ -38,6 +58,11 @@ struct tpda_drvdata {
>> ????? u8??????????? atid;
>> ????? u32??????????? dsb_esize;
>> ????? u32??????????? cmb_esize;
>> +??? bool??????????? trig_async;
>> +??? bool??????????? trig_flag_ts;
>> +??? bool??????????? trig_freq;
>> +??? bool??????????? freq_ts;
>> +??? bool??????????? cmbchan_mode;
>> ? };
>> ? #endif? /* _CORESIGHT_CORESIGHT_TPDA_H */
> 
> Suzuki
> 



From herbert at gondor.apana.org.au  Thu Dec 18 19:35:14 2025
From: herbert at gondor.apana.org.au (Herbert Xu)
Date: Fri, 19 Dec 2025 11:35:14 +0800
Subject: [PATCH v4 1/2] hwrng: imx-rngc: Use optional clock
In-Reply-To: <20251126-b4-m5441x-add-rng-support-v4-1-5309548c9555@yoseli.org>
References: <20251126-b4-m5441x-add-rng-support-v4-0-5309548c9555@yoseli.org>
 <20251126-b4-m5441x-add-rng-support-v4-1-5309548c9555@yoseli.org>
Message-ID: <aUTH8q5nejrngXck@gondor.apana.org.au>

On Wed, Nov 26, 2025 at 08:08:09AM +0100, Jean-Michel Hautbois via B4 Relay wrote:
> From: Jean-Michel Hautbois <jeanmichel.hautbois at yoseli.org>
> 
> Change devm_clk_get() to devm_clk_get_optional() to support platforms
> where the RNG clock is always enabled and not exposed via the clock
> framework (such as ColdFire MCF54418).
> 
> Reviewed-by: Frank Li <Frank.Li at nxp.com>
> Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois at yoseli.org>
> ---
>  drivers/char/hw_random/imx-rngc.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)

Acked-by: Herbert Xu <herbert at gondor.apana.org.au>
-- 
Email: Herbert Xu <herbert at gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt


From herbert at gondor.apana.org.au  Thu Dec 18 19:35:30 2025
From: herbert at gondor.apana.org.au (Herbert Xu)
Date: Fri, 19 Dec 2025 11:35:30 +0800
Subject: [PATCH v4 2/2] m68k: coldfire: Add RNG support for MCF54418
In-Reply-To: <20251126-b4-m5441x-add-rng-support-v4-2-5309548c9555@yoseli.org>
References: <20251126-b4-m5441x-add-rng-support-v4-0-5309548c9555@yoseli.org>
 <20251126-b4-m5441x-add-rng-support-v4-2-5309548c9555@yoseli.org>
Message-ID: <aUTIAicJiTxKHJb7@gondor.apana.org.au>

On Wed, Nov 26, 2025 at 08:08:10AM +0100, Jean-Michel Hautbois via B4 Relay wrote:
> From: Jean-Michel Hautbois <jeanmichel.hautbois at yoseli.org>
> 
> Add support for the hardware Random Number Generator (RNGB) found on
> MCF54418 ColdFire processors with clock enabled at platform
> initialization.
> 
> The RNGB block is compatible with the imx-rngc driver.
> 
> Reviewed-by: Frank Li <Frank.Li at nxp.com>
> Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois at yoseli.org>
> ---
>  arch/m68k/coldfire/device.c       | 28 ++++++++++++++++++++++++++++
>  arch/m68k/coldfire/m5441x.c       |  2 +-
>  arch/m68k/include/asm/m5441xsim.h |  9 +++++++++
>  drivers/char/hw_random/Kconfig    |  3 ++-
>  drivers/char/hw_random/imx-rngc.c |  7 +++++++
>  5 files changed, 47 insertions(+), 2 deletions(-)

Acked-by: Herbert Xu <herbert at gondor.apana.org.au>
-- 
Email: Herbert Xu <herbert at gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt


From dianders at google.com  Thu Dec 18 19:53:21 2025
From: dianders at google.com (Doug Anderson)
Date: Thu, 18 Dec 2025 19:53:21 -0800
Subject: Proposal: document where SoC info belongs
In-Reply-To: <qjpukes4etbgh4ncapec4v6okkiohlcqqdfvjfinyrj6olaryc@l3vspbwze7ri>
References: <CAD=FV=W+jE_L_LLgAhD8K_4+CtivSD9-9t7Xe63XuKrKjfyfeQ@mail.gmail.com>
 <qjpukes4etbgh4ncapec4v6okkiohlcqqdfvjfinyrj6olaryc@l3vspbwze7ri>
Message-ID: <CAD=FV=VmzcsauPM3WuJhc9=_+qa+Tvmtqdhz0eDXz5TF-fHaKA@mail.gmail.com>

Hi,

On Thu, Dec 18, 2025 at 6:39?PM Bjorn Andersson <andersson at kernel.org> wrote:
>
> On Thu, Dec 18, 2025 at 02:56:03PM -0800, Doug Anderson wrote:
> > Hi,
> >
> > To try to move things along, I'm picking a small piece out of my
> > previous discussion [1] to see if we can make some progress.
> >
> > Right now, the top-level "compatible" string in a dts file usually
> > contains one or more strings to represent the SoC. Examples chosen
> > semi-randomly:
> >
> > exynos5250-snow.dts:
> > - compatible: "google,snow-rev4", "google,snow", "samsung,exynos5250",
> > "samsung,exynos5"
> > - SoC: "samsung,exynos5250", "samsung,exynos5"
> >
> > sun20i-d1-clockworkpi-v3.14.dts:
> > - compatible: "clockwork,r-01-clockworkpi-v3.14", "allwinner,sun20i-d1"
> > - SoC: "allwinner,sun20i-d1"
> >
> > sdm845-db845c.dts:
> > - compatible: "thundercomm,db845c", "qcom,sdm845"
> > - SoC: "qcom,sdm845"
> >
> > I propose that we DEPRECATE including SoC information in the top-level
> > compatible string and move it elsewhere. I propose these top-level
> > properties that should be used instead:
> >
> > soc-family-compatible = "vendor,family";
> > soc-product-id = <0x1234>;
> > soc-product-variant = <0x1234>;
> > soc-product-description = "Something";
> > soc-major-rev = <0x1234>;
> > soc-minor-rev = <0x1234>;
> > soc-sub-rev = <0x1234>;
>
> So these 6 properties defines the soc itself? And the rules for how a
> bootloader matches against these 6 properties is defined elsewhere?

Right. See below, but I think a bootloader would need to know how
important a mismatched minor-rev or sub-rev is. I guess we could come
up with a rule and hope it works for everyone, though...


> What about "PCB" name and version?
>
> How about the case where my product has 5 different components that
> might come from a second source?

This _only_ covers SoC with the goal of getting the SoC out of the
top-level compatible string. The SoC tends to be a lot easier to deal
with. It doesn't try to solve the board problem. I was hoping to bite
off something small that we could agree upon and I'm worried that if
we try to tackle the board problem at the same time we'll just get
deadlocked.

IMO different families of boards will have different ways of
identifying different SKUs or boards with different 2nd source
components. Thus, IMO, for describing that type of thing we need to
allow different "loaders" to specify different types of properties.
...but I guess this is controversial and folks would like to identify
some sort of "universal" system that everyone can agree upon. While
that seems like it could be doable for SoC, I don't see it working for
boards. Maybe I'm just wrongheaded.


> Are you proposing that we allow adding arbitrary properties matching
> some pattern in the top-level node to facilitate matching? Presumably
> defined in some combination of vendor bindings?
>
> >
> > The family-compatible would be VERY high-level and is not intended to
> > be a marketing name. It would be something like "samsung,exynos",
> > "nvidia,tegra" or "google,google-silicon". The ONLY goal for this
> > string is that within a family, the other properties uniquely identify
> > a given SoC. This is a SINGLE string, NOT a list of strings. There is
> > no concept of being part of multiple families.
> >
> > All the other numbers are hopefully self-explanatory. These values
> > could be absent (assumed 0) if they don't make sense for a given SoC.
> >
> > The soc-product-description is designed to be some nice name that
> > represents the family, product-id, and product-variant but _not_ the
> > rev (since that's easy for anyone who cares to represent it as "rev
> > X.Y.Z")
> >
> >
> > The goals here are:
> > * Stop trying to jam so much into the top-level "compatible".
> > * Make it one step easier for bootloaders (or code packaging device
> > trees for bootloaders) to differentiate device trees / overlays. This
> > isn't _enough_ since this proposal doesn't include board info, but
> > it's a place to start.
> > * Make it easier to deal with "socketed" boards where the SoC can be replaced.
> >
> > NOTE: if a set of devicetrees is provided to a bootloader, it could
> > not just look at these properties to help it pick a devicetree but it
> > could also change the properties to be more detailed (it could fill in
> > some of the minor/sub-revs, for instance).
> >
> >
> > I think this is a positive change for everyone and a cleaner way to
> > represent things even if you aren't dealing with the above problems.
> >
> > What I'm looking for from people is some responses. Folks could choose:
> >
> > A) Yes, this is great. We already have something like this and we'd
> > switch to your properties if it became a standard.
> >
>
> We have qcom,msm-id; qcom,board-id; qcom,pmic-id; these have met the
> needs of some, but generally it lacks multiple axis.
>
> > B) I like the idea, but I need an extra property to represent my SoC
> > and then I'd use it.
> >
>
> s/an/several/

Aside from helping to deal with boards / second sources, what is missing?


> > C) I like the idea and I'd use it, but with some changes.
> >
> > D) We don't have anything like this today, but it sounds useful.
> >
> > E) Why are you wasting my time? This isn't a useful problem. The SoC
> > belongs in the top-level compatible string, period.
> >
>
> We do have functionality that relates to the generic soc name,
> (qcom,sdm845 in your example above). Extracting it into something else
> would imply that we need to check against soc-family-compatible?
>
> But when it comes to bootloaders picking the appropriate compatible,
> I've seen plenty of cases where basing it on compatible would be nasty.
>
> E.g. how do you write your string matching routine such that it allows
> all the different axis, where some are optional, some allows fallback to
> previous minor revisions of the chip etc.

If we're _just_ worrying about the SoC, I think we don't need to do
any string parsing. In the case of Qualcomm, I'd imagine that you'd
have _just one_ "soc-family-compatible" for all Qualcomm SoCs. Perhaps
"qcom,msm". This is because I believe all Qualcomm chips have a global
"product ID". So for "sdm845", you'd have:

soc-family-compatible = "qcom,msm";
soc-product-id = <0xSDM845_PRODUCT_ID>;
soc-product-variant = <0xIF_THERE_ARE_SKUS_OF_SDM845_PUT_HERE>;
soc-product-description = "Qualcomm SDM845";
soc-major-rev = <...>;
soc-minor-rev = <...>;
soc-sub-rev = <...>;

So no string matching. The bootloader would have to have knowledge of
whether it would pick a device tree where a sub-rev, minor-rev,
major-rev, or variant doesn't quite match.

With that explanation, does it sound better? ...or maybe it's just not
useful to you because moving the SoC out of the compatible isn't
useful to you without also handling the different SKUs and second
source components?

-Doug


From lkp at intel.com  Thu Dec 18 20:52:55 2025
From: lkp at intel.com (kernel test robot)
Date: Fri, 19 Dec 2025 12:52:55 +0800
Subject: [PATCH v8 03/12] arm64/delay: move some constants out to a
 separate header
In-Reply-To: <20251215044919.460086-4-ankur.a.arora@oracle.com>
References: <20251215044919.460086-4-ankur.a.arora@oracle.com>
Message-ID: <202512191227.TXFkHrQf-lkp@intel.com>

Hi Ankur,

kernel test robot noticed the following build errors:

[auto build test ERROR on bpf-next/master]
[also build test ERROR on bpf/master linus/master arnd-asm-generic/master v6.19-rc1 next-20251218]
[cannot apply to arm64/for-next/core bpf-next/net]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Ankur-Arora/asm-generic-barrier-Add-smp_cond_load_relaxed_timeout/20251215-130116
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master
patch link:    https://lore.kernel.org/r/20251215044919.460086-4-ankur.a.arora%40oracle.com
patch subject: [PATCH v8 03/12] arm64/delay: move some constants out to a separate header
config: x86_64-buildonly-randconfig-004-20251215 (https://download.01.org/0day-ci/archive/20251219/202512191227.TXFkHrQf-lkp at intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251219/202512191227.TXFkHrQf-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512191227.TXFkHrQf-lkp at intel.com/

All errors (new ones prefixed by >>):

>> drivers/soc/qcom/rpmh-rsc.c:29:10: fatal error: 'asm/delay-const.h' file not found
      29 | #include <asm/delay-const.h>
         |          ^~~~~~~~~~~~~~~~~~~
   1 error generated.


vim +29 drivers/soc/qcom/rpmh-rsc.c

     8	
     9	#include <linux/atomic.h>
    10	#include <linux/cpu_pm.h>
    11	#include <linux/delay.h>
    12	#include <linux/interrupt.h>
    13	#include <linux/io.h>
    14	#include <linux/iopoll.h>
    15	#include <linux/kernel.h>
    16	#include <linux/ktime.h>
    17	#include <linux/list.h>
    18	#include <linux/module.h>
    19	#include <linux/notifier.h>
    20	#include <linux/of.h>
    21	#include <linux/of_irq.h>
    22	#include <linux/of_platform.h>
    23	#include <linux/platform_device.h>
    24	#include <linux/pm_domain.h>
    25	#include <linux/pm_runtime.h>
    26	#include <linux/slab.h>
    27	#include <linux/spinlock.h>
    28	#include <linux/wait.h>
  > 29	#include <asm/delay-const.h>
    30	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From jie.gan at oss.qualcomm.com  Thu Dec 18 20:53:59 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Fri, 19 Dec 2025 12:53:59 +0800
Subject: [PATCH v4 1/3] coresight: tpda: add sysfs nodes for tpda
 cross-trigger configuration
In-Reply-To: <a95dc8ee-0b65-4ab6-966f-b15c31f6c6dc@arm.com>
References: <20251028-configure_tpda_reg-v4-0-23000805d21d@oss.qualcomm.com>
 <20251028-configure_tpda_reg-v4-1-23000805d21d@oss.qualcomm.com>
 <a785ced7-95ae-444b-b8ca-b40aecb35230@arm.com>
 <a95dc8ee-0b65-4ab6-966f-b15c31f6c6dc@arm.com>
Message-ID: <83130e02-4510-41d8-be5c-bbe9ad49dba1@oss.qualcomm.com>



On 12/18/2025 7:20 PM, Suzuki K Poulose wrote:
> On 18/12/2025 11:10, Suzuki K Poulose wrote:
>> On 28/10/2025 02:02, Jie Gan wrote:
>>> From: Tao Zhang <tao.zhang at oss.qualcomm.com>
>>>
>>> Introduce sysfs nodes to configure cross-trigger parameters for TPDA.
>>> These registers define the characteristics of cross-trigger packets,
>>> including generation frequency and flag values.
>>>
>>> Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
>>> Reviewed-by: James Clark <james.clark at linaro.org>
>>> Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
>>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>>> ---
>>> ? .../ABI/testing/sysfs-bus-coresight-devices-tpda?? |? 43 ++++
>>> ? drivers/hwtracing/coresight/coresight-tpda.c?????? | 230 ++++++++++ 
>>> + ++++++++++
>>> ? drivers/hwtracing/coresight/coresight-tpda.h?????? |? 27 ++-
>>> ? 3 files changed, 299 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices- 
>>> tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
>>> new file mode 100644
>>> index 000000000000..80e4b05a1ab4
>>> --- /dev/null
>>> +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
>>> @@ -0,0 +1,43 @@
>>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/trig_async_enable
>>> +Date:??????? October 2025
>>> +KernelVersion:??? 6.19
>>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>>> +Description:
>>> +??????? (RW) Enable/disable cross trigger synchronization sequence 
>>> interface.
>>> +
>>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/trig_flag_ts_enable
>>> +Date:??????? October 2025
>>> +KernelVersion:??? 6.19
>>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>>> +Description:
>>> +??????? (RW) Enable/disable cross trigger FLAG packet request 
>>> interface.
>>> +
>>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/trig_freq_enable
>>> +Date:??????? October 2025
>>> +KernelVersion:??? 6.19
>>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>>> +Description:
>>> +??????? (RW) Enable/disable cross trigger FREQ packet request 
>>> interface.
>>> +
>>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/freq_ts_enable
>>> +Date:??????? October 2025
>>> +KernelVersion:??? 6.19
>>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>>> +Description:
>>> +??????? (RW) Enable/disable the timestamp for all FREQ packets.
>>> +
>>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/global_flush_req
>>> +Date:??????? October 2025
>>> +KernelVersion:??? 6.19
>>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>>> +Description:
>>> +??????? (RW) Set global (all ports) flush request bit. The bit 
>>> remains set until a
>>> +??????? global flush request sequence completes.
>>> +
>>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/cmbchan_mode
>>> +Date:??????? October 2025
>>> +KernelVersion:??? 6.19
>>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>>> +Description:
>>> +??????? (RW) Configure the CMB/MCMB channel mode for all enabled ports.
>>> +??????? Value 0 means raw channel mapping mode. Value 1 means 
>>> channel pair marking mode.
>>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/ 
>>> hwtracing/coresight/coresight-tpda.c
>>> index 333b3cb23685..a9a27bcc65a1 100644
>>> --- a/drivers/hwtracing/coresight/coresight-tpda.c
>>> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
>>> @@ -147,9 +147,37 @@ static void tpda_enable_pre_port(struct 
>>> tpda_drvdata *drvdata)
>>> ????? u32 val;
>>> ????? val = readl_relaxed(drvdata->base + TPDA_CR);
>>> +??? val &= ~TPDA_CR_MID;
>>> ????? val &= ~TPDA_CR_ATID;
>>
>> See, below.
>>
>>> ????? val |= FIELD_PREP(TPDA_CR_ATID, drvdata->atid);
>>> +??? if (drvdata->trig_async)
>>> +??????? val |= TPDA_CR_SRIE;
>>> +??? else
>>> +??????? val &= ~TPDA_CR_SRIE;
>>> +??? if (drvdata->trig_flag_ts)
>>> +??????? val |= TPDA_CR_FLRIE;
>>> +??? else
>>> +??????? val &= ~TPDA_CR_FLRIE;
>>> +??? if (drvdata->trig_freq)
>>> +??????? val |= TPDA_CR_FRIE;
>>> +??? else
>>> +??????? val &= ~TPDA_CR_FRIE;
>>> +??? if (drvdata->freq_ts)
>>> +??????? val |= TPDA_CR_FREQTS;
>>> +??? else
>>> +??????? val &= ~TPDA_CR_FREQTS;
>>> +??? if (drvdata->cmbchan_mode)
>>> +??????? val |= TPDA_CR_CMBCHANMODE;
>>> +??? else
>>> +??????? val &= ~TPDA_CR_CMBCHANMODE;
>>
>> Could we clear all of the bits that are configurable in one go in the
>> beginning and set the appropriate ones based on the setting ? i.e.:
>>
>> Do we really need to retain any values ? And if not, why not start
>> with a fresh set of values and avoid the read ?
>>
>>> ????? writel_relaxed(val, drvdata->base + TPDA_CR);
>>> +
>>> +??? /*
>>> +???? * If FLRIE bit is set, set the master and channel
>>> +???? * id as zero
>>> +???? */
>>> +??? if (drvdata->trig_flag_ts)
>>> +??????? writel_relaxed(0x0, drvdata->base + TPDA_FPID_CR);
>>> ? }
>>> ? static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
>>> @@ -265,6 +293,206 @@ static const struct coresight_ops tpda_cs_ops = {
>>> ????? .link_ops??? = &tpda_link_ops,
>>> ? };
>>> +static ssize_t trig_async_enable_show(struct device *dev,
>>> +????????????????????? struct device_attribute *attr,
>>> +????????????????????? char *buf)
>>> +{
>>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>>> +
>>> +??? return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_async);
>>> +}
>>> +
>>> +static ssize_t trig_async_enable_store(struct device *dev,
>>> +?????????????????????? struct device_attribute *attr,
>>> +?????????????????????? const char *buf,
>>> +?????????????????????? size_t size)
>>> +{
>>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>>> +??? unsigned long val;
>>> +
>>> +??? if (kstrtoul(buf, 0, &val))
>>> +??????? return -EINVAL;
>>> +
>>> +??? guard(spinlock)(&drvdata->spinlock);
>>> +??? drvdata->trig_async = !!val;
>>> +
>>
>>
>>
>>> +??? return size;
>>> +}
>>> +static DEVICE_ATTR_RW(trig_async_enable);
>>
>> ...
>>
>>> +static DEVICE_ATTR_RW(trig_flag_ts_enable);
>>
>> ...
>>
>>> +static DEVICE_ATTR_RW(trig_freq_enable);
>>
>> ...
>>> +static DEVICE_ATTR_RW(freq_ts_enable);
>>
>> These attribute are boolean and looks like we could save some space on
>> code by using dev_ext_attribute.
>> see tpdm_simple_dataset_rw()/tpdm_simple_dataset_ro() . You could
>>
>> #define TPDA_TRIG_ASYNC??????? 0
>> #define TPDA_TRIG_FLAG_TS???? 1
>> #define TPDA_TRIG_FREQ??????? 2
>>
>>
>> tpda_trig_sysfs_show/store()
>>
>> ??bool *ptr;
>> ??switch (eattr->var) {
>> ??case TPDA_TRIG_ASYNC:
>> ?????ptr = &drvdata->trig_async;
>> ?????break;
>> ??case TPDA_TRIG_FLAG_TS:
>> ?????ptr = &drvdata->trig_flag_ts;
>> ?????break;
>> ...
>>
>> ??}
>>
>>
>>
> 
> -->8--
> 
> Cut here
> 
>>> +
>>> +static ssize_t global_flush_req_show(struct device *dev,
>>> +???????????????????? struct device_attribute *attr,
>>> +???????????????????? char *buf)
>>> +{
>>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>>> +??? unsigned long val;
>>> +
>>> +??? if (!drvdata->csdev->refcnt)
>>> +??????? return -EINVAL;
>>> +
>>> +??? guard(spinlock)(&drvdata->spinlock);
>>> +??? CS_UNLOCK(drvdata->base);
>>> +??? val = readl_relaxed(drvdata->base + TPDA_CR);
>>> +??? CS_LOCK(drvdata->base);
>>> +??? /* Only read value for bit 0 */
>>> +??? val &= BIT(0);
>>> +
>>> +??? return sysfs_emit(buf, "%lu\n", val);
>>> +}
>>> +
>>> +static ssize_t global_flush_req_store(struct device *dev,
>>> +????????????????????? struct device_attribute *attr,
>>> +????????????????????? const char *buf,
>>> +????????????????????? size_t size)
>>> +{
>>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>>> +??? unsigned long val;
>>> +
>>> +??? if (kstrtoul(buf, 0, &val))
>>> +??????? return -EINVAL;
>>> +
>>> +??? if (!drvdata->csdev->refcnt || !val)
>>> +??????? return -EINVAL;
>>> +
>>> +??? guard(spinlock)(&drvdata->spinlock);
>>> +??? CS_UNLOCK(drvdata->base);
>>> +??? val = readl_relaxed(drvdata->base + TPDA_CR);
>>> +??? /* Only set bit 0 */
>>> +??? val |= BIT(0);
>>
>> What is BIT 0 ? Please document it
>>
>>> +??? writel_relaxed(val, drvdata->base + TPDA_CR);
>>> +??? CS_LOCK(drvdata->base);
>>> +
>>> +??? return size;
>>> +}
> 
> Also this, global_flush_req seems to be a separate change from the rest 
> of the additions in the patch. Why not split it into a separate patch
> with appropriate description of what this is for ?

Hi Suzuki,

global_flush_req is part of the TPDA_CR register, it's the bit0 of the 
register.

I should document it in header file:
/* Cross trigger Global (all ports) flush request bit */
#define TPDA_CR_FLREQ     BIT(0)

We also have below bit that is not in use:
#define TPDA_CR_FREQREQ   BIT(1)

It's frequency request bit, that determines the frequency for generating 
frequency packets.

Thanks,
Jie

> 
> Suzuki



From pankaj.gupta at nxp.com  Thu Dec 18 21:20:38 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Fri, 19 Dec 2025 10:50:38 +0530
Subject: [PATCH v23 0/7] firmware: imx: driver for NXP secure-enclave
Message-ID: <20251219-imx-se-if-v23-0-5c6773d00318@nxp.com>

The NXP's i.MX EdgeLock Enclave, a HW IP creating an embedded secure
enclave within the SoC boundary to enable features like
- HSM
- SHE
- V2X

Communicates via message unit with linux kernel. This driver is
enables communication ensuring well defined message sequence protocol
between Application Core and enclave's firmware.

Driver configures multiple misc-device on the MU, for multiple
user-space applications can communicate on single MU.

It exists on some i.MX processors. e.g. i.MX8ULP, i.MX93 etc.

-------
Changes in v23:
5/7
- removed un-neccessary 'kfree' from the func se_ioctl_cmd_snd_rcv_rsp_handler().

1/2, 2/7, 3/7, 4/7, 6/7 & 7/7
- No changes

Reference:
- Link to v22: https://lore.kernel.org/r/20251218-imx-se-if-v22-0-07418c872509 at nxp.com

Changes in v22:
3/7 & 5/7
- reverted to previous change of using "__free(kfree)", by declare-and-initialize __free() vars next to their allocations.

1/7
- rename the se_fw.c to se_ctrl.c

2/7, 4/7, 5/7 & 7/7
- No changes.

Reference:
- Link to v21: https://lore.kernel.org/r/20251212-imx-se-if-v21-0-ee7d6052d848 at nxp.com

Changes in v21:
3/7
- smatch warning fixes.
- Added "COMPILE_TEST" into "depends on IMX_MBOX && ARCH_MXC && ARM64"
- removed "__free(kfree)" & added kfree();

5/7
- removed "__free(kfree)" & added kfree();

1/2, 2/7, 4/7, & 7/7
- No changes

Reference:
- Link to v20: https://lore.kernel.org/r/20251203-imx-se-if-v20-0-a04a25c4255f at nxp.com

Changes in v20:
5/7:
- adds a func "se_chk_tx_msg_hdr", to check the validity of the in-coming message from usersapce.

1/2, 2/7, 3/7, 4/7, 6/7 & 7/7
- No changes

Reference:
- Link to v19: https://lore.kernel.org/r/20250927-imx-se-if-v19-0-d1e7e960c118 at nxp.com

Changes in v19:

1/7
- Added 9 lines to the Introduction from line 73-82.

3/7
-  Update the commit message for " For i.MX9x SoC(s) there is at least one
dedicated ELE MU(s) for each world - Linux(one or more) and OP-TEE OS (one or
more), that needs to be shared between them.."

Reference:
- Link to v18: https://lore.kernel.org/r/20250619-imx-se-if-v18-0-c98391ba446d at nxp.com

Changes in v18:

1/7
- Wrap both diagrams above in literal code block by using double-colon

3/7 & 5/7
- Collected Frank's R-b tag.

2/7, 4/7, 6/7 & 7/7
- No changes

Reference:
- Link to v17: https://lore.kernel.org/r/20250426-imx-se-if-v17-0-0c85155a50d1 at nxp.com

Changes in v17:
- Changes to 3/7 & 5/7: to wrap code text at 80 character whereever possible.

Reference:
- Link to v16: https://lore.kernel.org/r/20250409-imx-se-if-v16-0-5394e5f3417e at nxp.com

Changes in v16:
- commit 3/7 and 4/7 are moved to end commits making them as 6/7 and 7/7 respectively.
- No change in 1/7 & 2/7.

7/7
- Collected Frank's R-b tag.

6/7
- commit message is updated to wrap at 75 characters.

5/7
- func add_b_desc_to_pending_list, removed the initialization of b_desc to
  NULL.
- variable timeout in func ele_msg_rcv(), is renamed to timeout_ms.
- struct se_if_priv, member variable se_rcv_msg_timeout, is renamed to
  se_rcv_msg_timeout_ms.
- in func load_firmware, move the label exit after dma_free_coherent.

4/7
- commit message is updated to wrap at 75 characters.

3/7
- ele_debug_dump, updated the assignment of keep_logging.
- ele_fw_authenticate function definition is updated to take two address
  as arguments.

Reference:
- Link to v15: https://lore.kernel.org/r/20250407-imx-se-if-v15-0-e3382cecda01 at nxp.com

Changes in v15:
- Patch 3/6 is split into two:
  - 3/7: arm64: dts: imx8ulp-evk: add reserved memory property
  - 4/7: arm64: dts: imx8ulp: add nxp secure enclave firmware
- No change in 1/7 & 2/7.

7/7
- removed the se_intance_id structure member variable.
- replace variable name from wait to timeout.
- used 'goto' to follow the common exit path calling "release_firmware(fw);" in case of error path.
- removed TBD string.
- Used ARRAY_SIZE(pending_lists).
- moved init_device_context after init_misc_device_context.
- defined err as long to avoid force convert in func
- added se_rcv_msg_timeout to priv, to control probe/suspend/resume per interface.

6/7
- removed the se_intance_id structure member variable.
- Added dev_ctx to the structure se_clbk_handle, too.
- Collected Frank's R-b tag.

5/7
- removed the se_intance_id structure member variable.
- since added se_if_probe_cleanup to devm, se_if_remove() is redundant. hence removed it.
- rename se_add_msg_chksum to se_get_msg_chksum
- added check if msg-size is 4 byte aligned.
- Fixed multiline comments.
- ele_debug_dump api is updated as part of comment disposition like single setting of flag "keep_logging" & adding if (ret).
- moved dev_err to dev_dbg, for imem save/restore functions.
- moved func get_se_if_name, from 7/7 to here.

3/7
- Updated the commit message.
- split the current patch into two:
  -- 3/7 for board dts, and
  -- 4/7 for chip dts

Reference:
- Link to v14: https://lore.kernel.org/r/20250327-imx-se-if-v14-0-2219448932e4 at nxp.com

Changes in v14:

- Patch 5/5 is split into two:
  - firmware: drivers: imx: adds miscdev
  - Introduce dev-ctx dedicated to private.
    -- Base patch before enabling misc-device context, to have the send-receive path, based on device context.
- No change in 1/6 & 2/6.
- Copied change logs from individual commits.

6/6
- moved definition of func se_load_firmware, from 4/6 patch to this patch.
- split init_device_context to init_misc_device_context.
- Different value of se_rcv_msg_timeout is required to be set. Receiving the response of 4K RSA operation can to take upto 3 minutes.
  This long value cannot be set during Linux: boot-up and suspend-resume.
  Hence, it will be set to default small-value during Linux: boot-up and suspend-resume.
- func se_dev_ctx_cpy_out_data(), in either case: do_cpy true or false, the clean-up needs to be done and it is implemented like wise.
  Once do_cpy is false, no need to continue copy to user buffer. But continue to do clean-up. hence cannot return.
  And every dev-ctx operation is done after taking the lock. Hence, two operations with same dev-ctx is not possible in parallel.
- func "init_device_context", for 0th misc dev_ctx, which is created at the time of probe, the device memory management is required. hence there is a difference.
- func "init_device_context", dev_er is replaced with return dev_err_probe.
- func "init_device_context", devm_add_action is replaced by devm_add_action_reset.
- removed type-cast from func se_ioctl_get_se_soc_info_handler().
- used scoped_cond_guard(mutex, _intr, return -EBUSY, &<mutex_lock>)
- combined dev_err & dev_dbg to one dev_err in se_if_fops_read().
- removed the structure member "se_shared_mem_mgmt->secure_mem".

4/6
- trimmed the ele_fetch_soc_info.
- removed the function ptr "se_info->se_fetch_soc_info" and replaced with ele_fetch_soc_info.
- moved definition of func se_load_firmware, to 6/6 patch.
- Different SoC, different ways to fetch soc_info. Generic function declaration for ele_fetch_soc_info() is needed. Hence wrapping ele_get_info() in it.
- Updated Kconfig help text for assertive tone.
- func ele_debug_dump is updated, to remove constructing the format string.
- removed the macro usage for SOC_ID_MASK.
- used low case hex number.
- Condition will never occur, where msg_len satisfy the following condition "msg_len % 4 != 0". Err msg is added if it occurs.
- Function description is added to se_add_msg_crc.
- timeout is added to function ele_msg_rcv, in 5/5 patch.
- local variable "header" is initialized with "tx_msg" and replaced "return err" with "return tx_msg_sz" in func ele_msg_send().
- replace function name from "exception_for_size" to "check_hdr_exception_for_sz"
- replaced "return ret > 0 ? 0 : -1;" with "return ret > 0 ? 0 : ret;" in func "se_save_imem_state".
- func "se_restore_imem_state", to return if the condition is false to proceed.
- removed casting by (void *).
- removed devm_kasprintf and done direct allocatiion for attr->soc_id = "i.MX8ULP" & attr->soc_id = "i.MX8ULP", & attr->family.
- Followed Reverse christmas tree order, whereever missing.
- There is no return if ele_fw_authenticate fails. Execution flow continue forward and execute the fucn dma_free_coherent().
- The loop is not for retry. The loop is needed to load secondary fw followed by loading primary fw, first. This is the case when ELE also got reset.
- dev_err_probe is corrected in func "se_if_request_channel".

3/6
-

Reference:
- Link to v13: https://lore.kernel.org/r/20250311-imx-se-if-v13-0-9cc6d8fd6d1c at nxp.com

Changes in v13:

5/5
- Updated the commit message for imperative mood.
- Remove the usage of macros- NODE_NAME, GET_ASCII_TO_U8, GET_IDX_FROM_DEV_NODE_NAME.
- Clean-up the return path by replacing "ret = -<err>; return ret;" with "return -<err>;"
- Clean-up the return path by replacing "ret = -<err>; goto exit;" with "return -<err>;"
- Removed goto statements from the entire driver, where there is no common code at function's exit.
- Fixes the check-patch erros reported with flag "--strict"
- Replaced devm_add_action, with devm_add_action_or_reset
- Removed the un-necesary and obvious code comments.
- Removed dev_probe_err at the exit of function se_if_probe().

4/5
- Clean-up the return path by replacing "ret = -<err>; return ret;" with "return -<err>;"
- Clean-up the return path by replacing "ret = -<err>; goto exit;" with "return -<err>;"
- Removed goto statements from the entire driver, where there is no common code at function's exit.
- fixes the check-patch erros reported with flag "--strict"
- removed the un-necesary and obvious code comments.
- variable received msg timeout to be different at boot-up & suspend/resume and send/recv ioctlis.

3/5
- compatible string is modified from "fsl,imx8ulp-se" to "fsl,imx8ulp-se-ele-hsm".
- updated the alias name.

2/5
- compatible string is modified from "fsl,imx8ulp-se" to "fsl,imx8ulp-se-ele-hsm".
- compatible string is modified from "fsl,imx93-se" to "fsl,imx93-se-ele-hsm".
- compatible string is modified from "fsl,imx95-se" to "fsl,imx95-se-ele-hsm".
- Mis-understood the +1 from Conor. Hence dropped the Reviewed-by tag.
- Collected Rob's R-b tag on v7 (https://lore.kernel.org/all/172589152997.4184616.5889493628960272898.robh at kernel.org/)

1/5
- No change

Reference:
- Link to v12: https://lore.kernel.org/r/20250120-imx-se-if-v12-0-c5ec9754570c at nxp.com

Changes in v12:

5/5
- increased the wait-timeout.

4/5
- rename flag "handle_susp_resm" to "imem_mgmt"
- moved the buffer allocation ot load_fw->imem.buf, to se_probe_if.
- setting imem state at initialization.

3/5
- No change

2/5
- No change

1/5
- No change

Reference:
- Link to v11: https://lore.kernel.org/r/20241220-imx-se-if-v11-0-0c7e65d7ae7b at nxp.com

Changes in v11:

5/5
- devname is constructed by concatinating get_se_if_name(se_if_id) & se_if_instance_id.
- ele_rcv_msg(), is updated to add the wait_interruptible_timeout for the non-NVM-Daemon message exchanges, such that in case of no response from FW,
  Linux donot hangs.
- added a new helper function get_se_if_name(), to return the secure-enclave interface owner's name string.
- added a new helper function get_se_soc_id(), to return the secure-enclave's SoC id.

4/5
- moved the se_if_node_info member "soc_register", to the struct "se_if_node_info_list"; as soc registration done once, not per interface.
- moved the se_if_node_info member "se_fetch_soc_info", to the struct "se_if_node_info_list"; as soc info fetching is done once, not per interface.
- Added two member variable se_if_id and se_if_instance_id to struct se_if_defines.
- removed the member "se_name" from struct "se_if_node_info". Rather, it will constructed by concatinating get_se_if_name(se_if_id) & se_if_instance_id.
- moved the static global variable "se_version", to the newly created structure "struct se_var_info".
- moved the member "struct se_fw_load_info load_fw" of "se_if_node_info_list", to the newly created structure "struct se_var_info".
- Replaced RUNTIME_PM_OPS with SET_SYSTEM_SLEEP_PM_OPS, in power-managment ops.

3/5
- No change

2/5
- No change

1/5
- No change

Reference:
- Link to v10: https://lore.kernel.org/r/20241104-imx-se-if-v10-0-bf06083cc97f at nxp.com

v10: firmware: imx: driver for NXP secure-enclave

Changes in v10:
5/5
- replaced the u8, u16, u32, u64, with __u8, __u16, __u32, __u64 in
  'include/uapi/linux/se_ioctl.h'.

4/5
- No change

3/5
- No change

2/5
- No change

1/5
- No change

Reference:
- Link to v9: https://lore.kernel.org/r/20241016-imx-se-if-v9-0-fd8fa0c04eab at nxp.com

Changes in v9:

4/5
- change se_if_remove function signature, required after rebase to v6.12-rc1.
- move the info->macros to a structure "struct se_if_defines if_defs".
- Removed "info" from "struct se_if_defines if_defs".
- Moved "mem_pool" from "struct se_if_defines if_defs" to "priv".
- Fetching "info" using container-of.

5/5
- Fetching "info" using container-of.
- Fixed issue reported by sparse.

Reference:
- Link to v8: https://lore.kernel.org/r/20241015-imx-se-if-v8-0-915438e267d3 at nxp.com

Changes in v8:

5/5
- Remove the check for SE_IF_CTX_OPENED.
- replaced dev_ctx->priv-dev, priv->dev, whereever possible.
- func "if_misc_deregister" moved before func "init_device_context".
- func "init_device_context" before func "se_ioctl_cmd_snd_rcv_rsp_handler".
- func "se_if_fops_write" and "se_if_fops_read", are moved after func "se_ioctl_get_mu_info".
- non static functions "se_dev_ctx_cpy_out_data, se_dev_ctx_shared_mem_cleanup & init_device_context" are moved static and local scope.
- Removed back & forth between the two structs "struct se_if_device_ctx *dev_ctx" and "struct se_shared_mem_mgmt_info *se_shared_mem_mgmt"
- removed the NULL check for bdesc.
- fops_open, is corrected for acquiring the fops_lock.
- Fops_close, mutex unlock is removed. Infact check for waiting_rsp_clbk_hdl.dev_ctx, is removed.
- sema_init(&dev_ctx->fops_lock, 1);, replaced with Mutex.
- structure member se_notify, is removed.

4/5
- removed initializing err to zero in func ele_fetch_soc_info(),
- replaced 'return 0', with 'goto exit', if the condition (!priv->mem_pool) is true.
- replaced "struct *dev" with "struct se_if_priv *priv", in base_message API(s) and others.
- Created a separate structure "struct se_if_defines" to maintain interface's fixed values like cmd_tag, rsp_tag, success_tag etc.
- removed the macros "WORD_SZ", "SOC_VER_MASK", "DEFAULT_IMX_SOC_VER", "RESERVED_DMA_POOL".
- Added handling for "ctrl+c", by postponing the interrupt, till the response to the "command in flight" is received.
- Removed the mutext lock "se_if_lock".
- furnction prototype for "se_save_imem_state" and "se_restore_imem_state", is changed to pass "imem" by reference.
- Added a new structure "struct se_fw_load_info", dedicated to contain FW loading relevant info. It is a member of struct info_list.
- split "imem_mgmt_file_in_rfs" into two "prim_fw_nm_in_rfs" and "seco_fw_nm_in_rfs", to be part of "struct se_fw_load_info".
- moved the function "se_load_firmware" prior to func "if_mbox_free_channel".
- function "se_load_firmware" is updated to use "request_firmware", instead of "request_firmware_no_wait".
- function "se_load_firmware" is updated to load "primary" fw image, if the imem_state is not BAD. Then load the "secondary FW" image.
- Added a new mutex_lock in the function "se_load_firmware", for ensuring FW loading done once, when there are multiple application are in play.
- instead of "wait_queue_head_t wq", used "sruct completion".
- add devm_add_action with action as se_if_probe_cleanup.

Reference:
- Link to v7: https://lore.kernel.org/r/20240904-imx-se-if-v7-0-5afd2ab74264 at nxp.com

Changes in v7:

5/5
- struct se_clbk_handle, is added with a member struct se_if_device_ctx *dev_ctx.
- func call to ele_miscdev_msg_rcv() & ele_miscdev_msg_send(), are removed.
- func se_ioctl_cmd_snd_rcv_rsp_handler(), is modified to remove the func call to ele_miscdev_msg_rcv() & ele_miscdev_msg_send()
- func se_ioctl_cmd_snd_rcv_rsp_handler is callig func ele_msg_send_rcv(), instead.
- Mutext "se_cmd_if_lock", handling is removed from this patch.
- func ele_miscdev_msg_send() is replaced with func ele_msg_send(), in fops_write.
- func ele_miscdev_msg_rcv() is replaced with func ele_msg_rcv(), in fops_read.
- fops_open is modified to create the new dev_ctx instance (using func init_device_context()), which is not registered as miscdev.
- Only one dev_ctx is registered as miscdev and its reference is stored in the struct se_if_priv, as priv_dev_ctx.
- Separate func cleanup_se_shared_mem() & func init_se_shared_mem(), for shared memory handling part of struct dev_ctx.
- Input param for func(s) ele_msg_rcv(), ele_msg_send() & ele_msg_send_rcv(), is replaced from struct se_if_priv to struct se_if_device_ctx.

4/5
- A new structure is defined name struct "se_clbk_handle", to contain members processed in mailbox call-back function.
- "struct se_if_priv" is modified to contain the two structures of "se_clbk_handle" - waiting_rsp_clbk_hdl & cmd_receiver_clbk_hdl.
- func ele_msg_rcv() is modified to take a new additional input reference param "struct se_clbk_handle *se_clbk_hdl".
- func ele_msg_send() is modified to take a new additional input tx_msg_sz.
- func ele_msg_send_rcv(), is modified to take 2 more inputs - tx_msg_sz & exp_rx_msg_sz.
- func se_val_rsp_hdr_n_status(), is modified to take input of rx_msg buffer, instead of header value, as input param.
- each caller of the func ele_msg_send_rcv(), is sending these two additional input params.
- func se_if_callback(), is modified to work on two structures of "se_clbk_handle" - waiting_rsp_clbk_hdl & cmd_receiver_clbk_hdl.
- Variable "max_dev_ctx", is removed from info & priv struture, as well its usage.
- New member variable "se_img_file_to_load", is added to structure "priv".
- Other member variables - rx_msg(ptr), rx_msg_sz, completion done & list of dev_ctxs, is removed from priv struture, along with their usage.
- func se_resume(), updated to wakeup the two "wq", part of "struct se_clbk_handle": priv->waiting_rsp_clbk_hdl & priv->cmd_receiver_clbk_hdl.

3/5
- Node name is changed from senclave-firmware at 0 to "secure-enclave"

2/5
- Node name is changed to "secure-enclave".

Reference:
- Link to v6: https://lore.kernel.org/r/20240722-imx-se-if-v6-0-ee26a87b824a at nxp.com

Changes in v6:

5/5
- replaced scope_gaurd with gaurd.

4/5
- replaced scope_gaurd with gaurd.
- remove reading the regs property from dtb.
- Added NULL check for priv data fetched from device, as a sanity check, for ele_base_msg apis)

3/5
- replace firmware with senclave-firmware.

2/5
- replace firmware with senclave-firmware.
- drop description for mbox
- Replaced "items:" with maxItems:1 for "memory-region"
- Replaced "items:" with maxItems:1 for "sram"
- remove regs property.
- remove "$nodename"

Reference:
- Link to v5: https://lore.kernel.org/r/20240712-imx-se-if-v5-0-66a79903a872 at nxp.com

Changes in v5:

2/5
- updated the description of mboxes
- updated the description & items for mbox-names.
- updated the description of memory-region
- move "additional properties: false" after allOf block.
- removed other example except one.

4/5
- Corrected the indentation in Kconfig.
- info members:mbox_tx_name & mbox_rx_name, are replaced with macros.

5/5
- Replaced "for  secure enclaves", with "for secure enclaves"
- Replaced "user space" with "userspace".
- End the line "[include]<linux/firmware/imx/ele_mu_ioctl.h>" with a period.

Reference:
- Link to v4: https://lore.kernel.org/r/20240705-imx-se-if-v4-0-52d000e18a1d at nxp.com

Changes in v4:

1/5
a. Removed - from EdgeLock Enclave.

b. Removed , after "Each of the above feature,"

c. replace "can exists" with "can exist".

d.
-messaging units(MU) per SE. Each co-existing 'se' can have one or multiple exclusive
-MU(s), dedicated to itself. None of the MU is shared between two SEs.
+messaging units(MU) per SE. Each co-existing SE can have one or multiple exclusive
+MUs, dedicated to itself. None of the MU is shared between two SEs.
 Communication of the MU is realized using the Linux mailbox driver.

e.
-All those SE interfaces 'se-if' that is/are dedicated to a particular SE, will be
-enumerated and provisioned under the very single 'SE' node.
+Although MU(s) is/are not shared between SE(s). But for SoC like i.MX95 which has
+multiple SE(s) like HSM, V2X-HSM, V2X-SHE; all the SE(s) and their interfaces 'se-if'
+that is/are dedicated to a particular SE will be enumerated and provisioned using the
+single compatible node("fsl,imx95-se").

f. Removed ",". Replaced for "Each 'se-if'," with "Each se-if'.

g. removed ","
-  This layer is responsible for ensuring the communication protocol, that is defined
+  This layer is responsible for ensuring the communication protocol that is defined

h. removed "-"
-  - FW can handle one command-message at a time.
+  - FW can handle one command message at a time.

i.
-  Using these multiple device contexts, that are getting multiplexed over a single MU,
-  user-space application(s) can call fops like write/read to send the command-message,
-  and read back the command-response-message to/from Firmware.
-  fops like read & write uses the above defined service layer API(s) to communicate with
+  Using these multiple device contexts that are getting multiplexed over a single MU,
+  userspace application(s) can call fops like write/read to send the command message,
+  and read back the command response message to/from Firmware.
+  fops like read & write use the above defined service layer API(s) to communicate with
   Firmware.

j. Uppercase for word "Linux".

2/5
a. Rephrased the description to remove list of phandles.

b. Moved required before allOf:
+required:
+  - compatible
+  - reg
+  - mboxes
+  - mbox-names
+
+additionalProperties: false
+
 allOf:

c. replaced not: required: with properties: <property-name>: false.
   # memory-region
-      not:
-        required:
-          - memory-region
+      properties:
+        memory-region: false

   # sram
-    else:
-      not:
-        required:
-          - sram

d. Reduced examples. keeping example of i.MX95.
e. node-name is changed to "firmware@<hex>"

3/5
- node name changed to "firmware@<hex>".

4/5
- used sizeof(*s_info)
- return early, rather than doing goto exit, in ele_get_info().
- Use upper_32_bits() and lower_32_bits()
- use rx_msg here instead of priv->rx_msg
- Moved the status check to validate_rsp_hdr. Rename the function to "se_val_rsp_hdr_n_status"
- typecasting removed header = (struct se_msg_hdr *) msg;
- Converted the API name with prefix imx_ele_* or imx_se_*, to ele_* and se_*, respectively.
- Removed the functions definition & declaration for: free_phybuf_mem_pool() & get_phybuf_mem_pool()
- removed the mbox_free_channel() calls from clean-up.
- Flag "priv->flags" is removed.
- Converted the int se_if_probe_cleanup() to void se_if_probe_cleanup().
- Replaced NULL initialization of structure members: priv->cmd_receiver_dev & priv->waiting_rsp_dev , with comments.
- Removed the function's declaration get_phy_buf_mem_pool1

5/5
Changes to Documentation/ABI/testing/se-cdev.
a. Removed "-" from "secure-enclave" and "file-descriptor".

b. Removed "-" from "shared-library"

c. Replaced "get" with "getting".

d. Added description for the new IOCTL "send command and receive command response"

e. Replaced "wakeup_intruptible" with "wait_event_interruptible"

f. Removed ";"

g. Removd "," from "mailbox_lock,"

h. Replaced "free" with "frees"

i. In mailbox callback function, checking the buffer size before
copying.

Reference:
- Link to v3: https://lore.kernel.org/r/20240617-imx-se-if-v3-0-a7d28dea5c4a at nxp.com

Changes in v3:
5/5:
- Initialize tx_msg with NULL.
- memdup_user() returns an error pointer, not NULL. correct it by adding check for err_ptr.
- new IOCTL is added to send & recieve the message.
- replaced the while loop till list is empty, with list_for_each_entry.
- replaced __list_del_entry, with list_del.
- Removed the dev_err message from copy to user.
- Removed the casting of void *.
- corrected the typcasting in copy to user.
- removed un-necessary goto statement.
- Removed dead code for clean-up of memory.
- Removed un-mapping of secured memory
- Passing se_if_priv structure to init_device_context.
- Updated the below check to replace io.length with round_up(io.length).
	if (shared_mem->size < shared_mem->pos|| io.length >= shared_mem->size - shared_mem->pos)
- Created a function to cleanup the list of shared memory buffers.
- Used list_for_each_entry_safe(). created a separate functions: se_dev_ctx_cpy_out_data() & se_dev_ctx_shared_mem_cleanup()

4/5
- Changed the compatible string to replace "-ele", to "-se".
- Declaration of imx_se_node_info, is done as const in the whole file
- Remove the unused macros from ele_base_msg.h
- Remove the function declaration get_phy_buf_mem_pool1, from the header file.
- Replace the use of dmam_alloc_coherent to dma_alloc_coherent
- Check for function pointer, before calling the fucntion pointer in imx_fetch_se_soc_info
- Removed the unused flag for SE_MU_IO_FLAGS_USE_SEC_MEM.
-  Removed the unused macros WORD_SZ
- instead of struct device *dev, struct se_if_priv *priv, is used as argument to the funtions:se_save_imem_state, se_restore_imem_state, imx_fetch_se_soc_info
- Removed ret from validate_rsp_hdr.
- changed the prefix of the funtion: plat_add_msg_crc and plat_fill_cmd_msg_hdr.
- indentation correction for info structures.
- remove the check for priv not null from se_if_probe_cleanup
- Removed the casting of void *.
- se_load_firmware function is corrected for not freeing the buffer when allocation fails.
- Checking if get_imx_se_node_info() can return NULL, in se_if_probe()
- imem.size has type u32. return value from se_save_imem_state() will be assigned to imem.size in case of success only.
- removed the flag un-setting in case of failure. priv->flags &= (~RESERVED_DMA_POOL);
- removed the function call for devm_of_platform_populate(dev);
- Checking for not-NULL,  before calling the funtion pointer se_fetch_soc_info.
- Removed the checking for reserved memory flag, before freeing up the reserved memory, in se_probe_if_cleanup.

3/5
- Changed the compatible string to replace "-ele", to "-se".

2/5
- to fix the warning error, replaced the "-ele" & "-v2x" in compatible string, to "-se".
- Added an example for ele at 0 for compatible string "fsl,imx95-se"

Reference
- Link to v2: https://lore.kernel.org/r/20240523-imx-se-if-v2-0-5a6fd189a539 at nxp.com

Changes in v2:

4/4
- Split this patch into two: 1. base driver & 2. Miscdev
- Initialize the return variable "err" as 0, before calling 'return err', in the file ele_common.c
- Fix the usage of un-iniitialized pointer variable, by initializing them with NULL, in ele_base_msg.c.
- Fix initializing the ret variable, to return the correct error code in case of issue.
- replaced dmam_alloc_coherent with dma_alloc_coherent.
- Replace the use of ELE_GET_INFO_READ_SZ, with sizeof(soc_info).
- Replaced -1 with -EPERM
- Removed the safety check on func-input param, in ele_get_info().
- fix the assigning data[1] with lower 32 address, rather than zero, for ele_fw_authenticate API.
- Correctly initializing the function's return error code, for file  ele_base_msg.c.
- replaced 'return' with 'goto'.
- Use length in bytes.
- Corrected the structure se_msg_hdr.
- Moved setting of rx_msg  to priv, into the function imx_ele_msg_send_rcv
- Will add lockdep_assert_held, to receive path, in v2.
- corrected the spacing at "ret  = validate_rsp_hdr"
- FIELD_GET() used for RES_STATUS
- Re-write the structure soc_info, matching the information provided in response to this api.
- The "|" goes to the end of the previous line.
- Moved the locking and unlocking of the command lock to the caller of the function.
- removed the safety check for device private data.
- Structure memory reference, used to read message header.
- In the interrupt call back function, remove assigning waiting_rsp_dev to NULL, in case of response message rcv from FW.
- do while removed.
- replaced BIT(1) for RESERVED_DMA_POOL, to BIT(0)
- The backslash is removed while assigning the file name with absolute path to structure variable.fw_name_in_rfs =.
- Update the 'if' condition by removing "idx < 0".
- mbox_request_channel_byname() uses a "char" for the name not a u8. Corrected.
- devm managed resources, are not cleaned now, in function se_probe_if_cleanup
- Used dev_err_probe().
- Used %pe to print error string.
- remove "__maybe_unused" for "struct platform_device *enum_plat_dev __maybe_unused;"
- used FIELD_GET(), for  RES_STATUS. Removed the use of MSG_TAG, MSG_COMMAND, MSG_SIZE, MSG_VER.
- Depricated the used of member of struct se_if_priv, bool no_dev_ctx_used;
- Moved the text explaing the synchronization logic via mutexes, from patch 1/4 to se_ctrl.h.
- removed the type casting of info_list = (struct imx_se_node_info_list *) device_get_match_data(dev->parent);
- Used static variable priv->soc_rev in the se_ctrl.c, replaced the following condition: if (info_list->soc_rev) to if (priv->soc_rev) for checking if this flow is already executed or not.
- imx_fetch_soc_info will return failure if the get_info function fails.
- Removed devm_free from imx_fetch_soc_info too.

3/3
- Made changes to move all the properties to parent node, without any child node.

2/4
- Use Hex pattern string.
- Move the properties to parent node, with no child node.
- Add i.MX95-ele to compatible nodes to fix the warning "/example-2/v2x: failed to match any schema with compatible: ['fsl,imx95-v2x']"

1/1
- Corrected the spelling from creats to creates.
- drop the braces around the plural 's' for interfaces
- written se in upper case SE.
- Replace "multiple message(s)" with messages.
- Removed too much details about locks.

Testing
- make CHECK_DTBS=y freescale/imx8ulp-evk.dtb;
- make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j8  dt_binding_check DT_SCHEMA_FILES=fsl,imx-se.yaml
- make C=1 CHECK=scripts/coccicheck drivers/firmware/imx/*.* W=1 > r.txt
- ./scripts/checkpatch.pl --git <>..HEAD
- Tested the Image and .dtb, on the i.MX8ULP.

Reference
- Link to v1: https://lore.kernel.org/r/20240510-imx-se-if-v1-0-27c5a674916d at nxp.com

---
Pankaj Gupta (7):
      Documentation/firmware: add imx/se to other_interfaces
      dt-bindings: arm: fsl: add imx-se-fw binding doc
      firmware: imx: add driver for NXP EdgeLock Enclave
      firmware: imx: device context dedicated to priv
      firmware: drivers: imx: adds miscdev
      arm64: dts: imx8ulp: add secure enclave node
      arm64: dts: imx8ulp-evk: add reserved memory property

 Documentation/ABI/testing/se-cdev                  |   43 +
 .../devicetree/bindings/firmware/fsl,imx-se.yaml   |   91 ++
 .../driver-api/firmware/other_interfaces.rst       |  131 +++
 arch/arm64/boot/dts/freescale/imx8ulp-evk.dts      |   12 +-
 arch/arm64/boot/dts/freescale/imx8ulp.dtsi         |   11 +-
 drivers/firmware/imx/Kconfig                       |   13 +
 drivers/firmware/imx/Makefile                      |    2 +
 drivers/firmware/imx/ele_base_msg.c                |  298 +++++
 drivers/firmware/imx/ele_base_msg.h                |  115 ++
 drivers/firmware/imx/ele_common.c                  |  373 +++++++
 drivers/firmware/imx/ele_common.h                  |   51 +
 drivers/firmware/imx/se_ctrl.c                     | 1160 ++++++++++++++++++++
 drivers/firmware/imx/se_ctrl.h                     |  128 +++
 include/linux/firmware/imx/se_api.h                |   14 +
 include/uapi/linux/se_ioctl.h                      |   97 ++
 15 files changed, 2536 insertions(+), 3 deletions(-)
---
base-commit: 4a26e7032d7d57c998598c08a034872d6f0d3945
change-id: 20240507-imx-se-if-a40055093dc6

Best regards,
-- 
Pankaj Gupta <pankaj.gupta at nxp.com>



From pankaj.gupta at nxp.com  Thu Dec 18 21:20:39 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Fri, 19 Dec 2025 10:50:39 +0530
Subject: [PATCH v23 1/7] Documentation/firmware: add imx/se to
 other_interfaces
In-Reply-To: <20251219-imx-se-if-v23-0-5c6773d00318@nxp.com>
References: <20251219-imx-se-if-v23-0-5c6773d00318@nxp.com>
Message-ID: <20251219-imx-se-if-v23-1-5c6773d00318@nxp.com>

Documents i.MX SoC's Service layer and C_DEV driver for selected SoC(s)
that contains the NXP hardware IP(s) for Secure Enclaves(se) like:
- NXP EdgeLock Enclave on i.MX93 & i.MX8ULP

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
---
Changes from v21 to v22
- rename the se_fw.c to se_ctrl.c
---
 .../driver-api/firmware/other_interfaces.rst       | 131 +++++++++++++++++++++
 1 file changed, 131 insertions(+)

diff --git a/Documentation/driver-api/firmware/other_interfaces.rst b/Documentation/driver-api/firmware/other_interfaces.rst
index 06ac89adaafb..cbd425c5a11d 100644
--- a/Documentation/driver-api/firmware/other_interfaces.rst
+++ b/Documentation/driver-api/firmware/other_interfaces.rst
@@ -49,3 +49,134 @@ of the requests on to a secure monitor (EL3).
 
 .. kernel-doc:: drivers/firmware/stratix10-svc.c
    :export:
+
+NXP Secure Enclave Firmware Interface
+=====================================
+
+Introduction
+------------
+The NXP's i.MX HW IP like EdgeLock Enclave, V2X etc., creates an embedded secure
+enclave within the SoC boundary to enable features like
+ - Hardware Security Module (HSM)
+ - Security Hardware Extension (SHE)
+ - Vehicular to Anything (V2X)
+
+Each of the above feature is enabled through dedicated NXP H/W IP on the SoC.
+On a single SoC, multiple hardware IP (or can say more than one secure enclave)
+can exist.
+
+NXP SoCs enabled with the such secure enclaves(SEs) IPs are:
+i.MX93, i.MX8ULP
+
+To communicate with one or more co-existing SE(s) on SoC, there is/are dedicated
+messaging units(MU) per SE. Each co-existing SE can have one or multiple exclusive
+MUs, dedicated to itself. None of the MU is shared between two SEs. Communication
+of the MU is realized using the mailbox driver. Each secure enclave can cater to
+multiple clients by virtue of these exclusive MUs. Also, they can distinguish
+transactions originating from these clients based on the MU used and core security
+state. The communication between the clients and secure enclaves is in form of
+command/response mechanism. Each client could expose specific set of secure enclave
+features to the higher layers, based on the commands supported by that client. For
+example, the secure enclave could simultaneously support an OPTEE TA and Linux
+middleware as clients. Each of these clients can expose specific set of secure
+enclave features based on the command set supported by them.
+
+NXP Secure Enclave(SE) Interface
+--------------------------------
+Although MU(s) is/are not shared between SE(s). But for SoC like i.MX95 which has
+multiple SE(s) like HSM, V2X-HSM, V2X-SHE; all the SE(s) and their interfaces 'se-if'
+that is/are dedicated to a particular SE will be enumerated and provisioned using the
+single compatible node("fsl,imx95-se").
+
+Each 'se-if' comprise of twp layers:
+- (C_DEV Layer) User-Space software-access interface.
+- (Service Layer) OS-level software-access interface.
+
+::
+   +--------------------------------------------+
+   |            Character Device(C_DEV)         |
+   |                                            |
+   |   +---------+ +---------+     +---------+  |
+   |   | misc #1 | | misc #2 | ... | misc #n |  |
+   |   |  dev    | |  dev    |     | dev     |  |
+   |   +---------+ +---------+     +---------+  |
+   |        +-------------------------+         |
+   |        | Misc. Dev Synchr. Logic |         |
+   |        +-------------------------+         |
+   |                                            |
+   +--------------------------------------------+
+
+   +--------------------------------------------+
+   |               Service Layer                |
+   |                                            |
+   |      +-----------------------------+       |
+   |      | Message Serialization Logic |       |
+   |      +-----------------------------+       |
+   |          +---------------+                 |
+   |          |  imx-mailbox  |                 |
+   |          |   mailbox.c   |                 |
+   |          +---------------+                 |
+   |                                            |
+   +--------------------------------------------+
+
+- service layer:
+  This layer is responsible for ensuring the communication protocol that is defined
+  for communication with firmware.
+
+  FW Communication protocol ensures two things:
+  - Serializing the messages to be sent over an MU.
+
+  - FW can handle one command message at a time.
+
+- c_dev:
+  This layer offers character device contexts, created as '/dev/<se>_mux_chx'.
+  Using these multiple device contexts that are getting multiplexed over a single MU,
+  userspace application(s) can call fops like write/read to send the command message,
+  and read back the command response message to/from Firmware.
+  fops like read & write use the above defined service layer API(s) to communicate with
+  Firmware.
+
+  Misc-device(/dev/<se>_mux_chn) synchronization protocol:
+::
+
+                                Non-Secure               +   Secure
+                                                         |
+                                                         |
+                +-----------+      +-------------+       |
+                | se_ctrl.c +<---->+imx-mailbox.c|       |
+                |           |      |  mailbox.c  +<-->+------+    +------+
+                +-----+-----+      +-------------+    | MU X +<-->+ ELE |
+                      |                               +------+    +------+
+                      +----------------+                 |
+                      |                |                 |
+                      v                v                 |
+                  logical           logical              |
+                  receiver          waiter               |
+                     +                 +                 |
+                     |                 |                 |
+                     |                 |                 |
+                     |            +----+------+          |
+                     |            |           |          |
+                     |            |           |          |
+              device_ctx     device_ctx     device_ctx   |
+                                                         |
+                User 0        User 1       User Y        |
+                +------+      +------+     +------+      |
+                |misc.c|      |misc.c|     |misc.c|      |
+ kernel space   +------+      +------+     +------+      |
+                                                         |
+ +------------------------------------------------------ |
+                    |             |           |          |
+ userspace     /dev/ele_muXch0    |           |          |
+                          /dev/ele_muXch1     |          |
+                                        /dev/ele_muXchY  |
+                                                         |
+
+When a user sends a command to the firmware, it registers its device_ctx
+as waiter of a response from firmware.
+
+Enclave's Firmware owns the storage management, over Linux filesystem.
+For this c_dev provisions a dedicated slave device called "receiver".
+
+.. kernel-doc:: drivers/firmware/imx/se_ctrl.c
+   :export:

-- 
2.43.0



From pankaj.gupta at nxp.com  Thu Dec 18 21:20:40 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Fri, 19 Dec 2025 10:50:40 +0530
Subject: [PATCH v23 2/7] dt-bindings: arm: fsl: add imx-se-fw binding doc
In-Reply-To: <20251219-imx-se-if-v23-0-5c6773d00318@nxp.com>
References: <20251219-imx-se-if-v23-0-5c6773d00318@nxp.com>
Message-ID: <20251219-imx-se-if-v23-2-5c6773d00318@nxp.com>

The NXP security hardware IP(s) like: i.MX EdgeLock Enclave, V2X etc.,
creates an embedded secure enclave within the SoC boundary to enable
features like:
- HSM
- SHE
- V2X

Secure-Enclave(s) communication interface are typically via message
unit, i.e., based on mailbox linux kernel driver. This driver enables
communication ensuring well defined message sequence protocol between
Application Core and enclave's firmware.

Driver configures multiple misc-device on the MU, for multiple
user-space applications, to be able to communicate over single MU.

It exists on some i.MX processors. e.g. i.MX8ULP, i.MX93 etc.

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
---
 .../devicetree/bindings/firmware/fsl,imx-se.yaml   | 91 ++++++++++++++++++++++
 1 file changed, 91 insertions(+)

diff --git a/Documentation/devicetree/bindings/firmware/fsl,imx-se.yaml b/Documentation/devicetree/bindings/firmware/fsl,imx-se.yaml
new file mode 100644
index 000000000000..fa81adbf9b80
--- /dev/null
+++ b/Documentation/devicetree/bindings/firmware/fsl,imx-se.yaml
@@ -0,0 +1,91 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/firmware/fsl,imx-se.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP i.MX HW Secure Enclave(s) EdgeLock Enclave
+
+maintainers:
+  - Pankaj Gupta <pankaj.gupta at nxp.com>
+
+description: |
+  NXP's SoC may contain one or multiple embedded secure-enclave HW
+  IP(s) like i.MX EdgeLock Enclave, V2X etc. These NXP's HW IP(s)
+  enables features like
+    - Hardware Security Module (HSM),
+    - Security Hardware Extension (SHE), and
+    - Vehicular to Anything (V2X)
+
+  Communication interface to the secure-enclaves(se) is based on the
+  messaging unit(s).
+
+properties:
+  compatible:
+    enum:
+      - fsl,imx8ulp-se-ele-hsm
+      - fsl,imx93-se-ele-hsm
+      - fsl,imx95-se-ele-hsm
+
+  mboxes:
+    items:
+      - description: mailbox phandle to send message to se firmware
+      - description: mailbox phandle to receive message from se firmware
+
+  mbox-names:
+    items:
+      - const: tx
+      - const: rx
+
+  memory-region:
+    maxItems: 1
+
+  sram:
+    maxItems: 1
+
+required:
+  - compatible
+  - mboxes
+  - mbox-names
+
+allOf:
+  # memory-region
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - fsl,imx8ulp-se-ele-hsm
+              - fsl,imx93-se-ele-hsm
+    then:
+      required:
+        - memory-region
+    else:
+      properties:
+        memory-region: false
+
+  # sram
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - fsl,imx8ulp-se-ele-hsm
+    then:
+      required:
+        - sram
+
+    else:
+      properties:
+        sram: false
+
+additionalProperties: false
+
+examples:
+  - |
+    secure-enclave {
+      compatible = "fsl,imx95-se-ele-hsm";
+      mboxes = <&ele_mu0 0 0>, <&ele_mu0 1 0>;
+      mbox-names = "tx", "rx";
+    };
+...

-- 
2.43.0



From pankaj.gupta at nxp.com  Thu Dec 18 21:20:41 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Fri, 19 Dec 2025 10:50:41 +0530
Subject: [PATCH v23 3/7] firmware: imx: add driver for NXP EdgeLock Enclave
In-Reply-To: <20251219-imx-se-if-v23-0-5c6773d00318@nxp.com>
References: <20251219-imx-se-if-v23-0-5c6773d00318@nxp.com>
Message-ID: <20251219-imx-se-if-v23-3-5c6773d00318@nxp.com>

Add driver for enabling MU based communication interface to secure-enclave.

NXP hardware IP(s) for secure-enclaves like Edgelock Enclave(ELE), are
embedded in the SoC to support the features like HSM, SHE & V2X, using
message based communication interface.

The secure enclave FW communicates with Linux over single or multiple
dedicated messaging unit(MU) based interface(s).
Exists on i.MX SoC(s) like i.MX8ULP, i.MX93, i.MX95 etc.

For i.MX9x SoC(s) there is at least one dedicated ELE MU(s) for each
world - Linux(one or more) and OPTEE-OS (one or more).

Other dependent kernel drivers will be:
- NVMEM: that supports non-volatile devices like EFUSES,
         managed by NXP's secure-enclave.

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
Changes from v21 to v22:
- reverted to previous change of using "__free(kfree)", by
  declare-and-initialize __free() vars next to their allocations.
---
 drivers/firmware/imx/Kconfig        |  13 ++
 drivers/firmware/imx/Makefile       |   2 +
 drivers/firmware/imx/ele_base_msg.c | 270 ++++++++++++++++++++++++
 drivers/firmware/imx/ele_base_msg.h |  95 +++++++++
 drivers/firmware/imx/ele_common.c   | 335 +++++++++++++++++++++++++++++
 drivers/firmware/imx/ele_common.h   |  45 ++++
 drivers/firmware/imx/se_ctrl.c      | 408 ++++++++++++++++++++++++++++++++++++
 drivers/firmware/imx/se_ctrl.h      |  86 ++++++++
 include/linux/firmware/imx/se_api.h |  14 ++
 9 files changed, 1268 insertions(+)

diff --git a/drivers/firmware/imx/Kconfig b/drivers/firmware/imx/Kconfig
index 127ad752acf8..1f89dd140113 100644
--- a/drivers/firmware/imx/Kconfig
+++ b/drivers/firmware/imx/Kconfig
@@ -55,3 +55,16 @@ config IMX_SCMI_MISC_DRV
 	  core that could provide misc functions such as board control.
 
 	  This driver can also be built as a module.
+
+config IMX_SEC_ENCLAVE
+	tristate "i.MX Embedded Secure Enclave - EdgeLock Enclave Firmware driver."
+	depends on (IMX_MBOX && ARCH_MXC && ARM64) || COMPILE_TEST
+	select FW_LOADER
+	default m if ARCH_MXC
+
+	help
+	  Exposes APIs supported by the iMX Secure Enclave HW IP called:
+	  - EdgeLock Enclave Firmware (for i.MX8ULP, i.MX93),
+	    like base, HSM, V2X & SHE using the SAB protocol via the shared Messaging
+	    Unit. This driver exposes these interfaces via a set of file descriptors
+	    allowing to configure shared memory, send and receive messages.
diff --git a/drivers/firmware/imx/Makefile b/drivers/firmware/imx/Makefile
index 3bbaffa6e347..4412b15846b1 100644
--- a/drivers/firmware/imx/Makefile
+++ b/drivers/firmware/imx/Makefile
@@ -4,3 +4,5 @@ obj-$(CONFIG_IMX_SCU)		+= imx-scu.o misc.o imx-scu-irq.o rm.o imx-scu-soc.o
 obj-${CONFIG_IMX_SCMI_CPU_DRV}	+= sm-cpu.o
 obj-${CONFIG_IMX_SCMI_MISC_DRV}	+= sm-misc.o
 obj-${CONFIG_IMX_SCMI_LMM_DRV}	+= sm-lmm.o
+sec_enclave-objs		= se_ctrl.o ele_common.o ele_base_msg.o
+obj-${CONFIG_IMX_SEC_ENCLAVE}	+= sec_enclave.o
diff --git a/drivers/firmware/imx/ele_base_msg.c b/drivers/firmware/imx/ele_base_msg.c
new file mode 100644
index 000000000000..da50686786f2
--- /dev/null
+++ b/drivers/firmware/imx/ele_base_msg.c
@@ -0,0 +1,270 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 NXP
+ */
+
+#include <linux/types.h>
+
+#include <linux/cleanup.h>
+#include <linux/completion.h>
+#include <linux/dma-mapping.h>
+#include <linux/genalloc.h>
+
+#include "ele_base_msg.h"
+#include "ele_common.h"
+
+#define FW_DBG_DUMP_FIXED_STR		"ELE"
+
+int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info)
+{
+	dma_addr_t get_info_addr = 0;
+	u32 *get_info_data = NULL;
+	int ret = 0;
+
+	if (!priv)
+		return -EINVAL;
+
+	memset(s_info, 0x0, sizeof(*s_info));
+
+	struct se_api_msg *tx_msg __free(kfree) =
+		kzalloc(ELE_GET_INFO_REQ_MSG_SZ, GFP_KERNEL);
+	if (!tx_msg)
+		return -ENOMEM;
+
+	struct se_api_msg *rx_msg __free(kfree) =
+		kzalloc(ELE_GET_INFO_RSP_MSG_SZ, GFP_KERNEL);
+	if (!rx_msg)
+		return -ENOMEM;
+
+	if (priv->mem_pool)
+		get_info_data = gen_pool_dma_alloc(priv->mem_pool,
+						   ELE_GET_INFO_BUFF_SZ,
+						   &get_info_addr);
+	else
+		get_info_data = dma_alloc_coherent(priv->dev,
+						   ELE_GET_INFO_BUFF_SZ,
+						   &get_info_addr,
+						   GFP_KERNEL);
+	if (!get_info_data) {
+		dev_dbg(priv->dev,
+			"%s: Failed to allocate get_info_addr.", __func__);
+		return -ENOMEM;
+	}
+
+	ret = se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
+				  ELE_GET_INFO_REQ, ELE_GET_INFO_REQ_MSG_SZ,
+				  true);
+	if (ret)
+		goto exit;
+
+	tx_msg->data[0] = upper_32_bits(get_info_addr);
+	tx_msg->data[1] = lower_32_bits(get_info_addr);
+	tx_msg->data[2] = sizeof(*s_info);
+	ret = ele_msg_send_rcv(priv, tx_msg, ELE_GET_INFO_REQ_MSG_SZ, rx_msg,
+			       ELE_GET_INFO_RSP_MSG_SZ);
+	if (ret < 0)
+		goto exit;
+
+	ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_GET_INFO_REQ,
+				      ELE_GET_INFO_RSP_MSG_SZ, true);
+
+	memcpy(s_info, get_info_data, sizeof(*s_info));
+exit:
+	if (priv->mem_pool)
+		gen_pool_free(priv->mem_pool, (unsigned long)get_info_data,
+			      ELE_GET_INFO_BUFF_SZ);
+	else
+		dma_free_coherent(priv->dev, ELE_GET_INFO_BUFF_SZ,
+				  get_info_data, get_info_addr);
+
+	return ret;
+}
+
+int ele_fetch_soc_info(struct se_if_priv *priv, void *data)
+{
+	return ele_get_info(priv, data);
+}
+
+int ele_ping(struct se_if_priv *priv)
+{
+	int ret = 0;
+
+	if (!priv)
+		return -EINVAL;
+
+	struct se_api_msg *tx_msg __free(kfree) = kzalloc(ELE_PING_REQ_SZ,
+							  GFP_KERNEL);
+	if (!tx_msg)
+		return -ENOMEM;
+
+	struct se_api_msg *rx_msg __free(kfree) = kzalloc(ELE_PING_RSP_SZ,
+							  GFP_KERNEL);
+	if (!rx_msg)
+		return -ENOMEM;
+
+	ret = se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
+				  ELE_PING_REQ, ELE_PING_REQ_SZ, true);
+	if (ret) {
+		dev_err(priv->dev, "Error: se_fill_cmd_msg_hdr failed.");
+		return ret;
+	}
+
+	ret = ele_msg_send_rcv(priv, tx_msg, ELE_PING_REQ_SZ, rx_msg,
+			       ELE_PING_RSP_SZ);
+	if (ret < 0)
+		return ret;
+
+	ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_PING_REQ,
+				      ELE_PING_RSP_SZ, true);
+
+	return ret;
+}
+
+int ele_service_swap(struct se_if_priv *priv,
+		     phys_addr_t addr,
+		     u32 addr_size, u16 flag)
+{
+	int ret = 0;
+
+	if (!priv)
+		return -EINVAL;
+
+	struct se_api_msg *tx_msg __free(kfree)	=
+		kzalloc(ELE_SERVICE_SWAP_REQ_MSG_SZ, GFP_KERNEL);
+	if (!tx_msg)
+		return -ENOMEM;
+
+	struct se_api_msg *rx_msg __free(kfree) =
+		kzalloc(ELE_SERVICE_SWAP_RSP_MSG_SZ, GFP_KERNEL);
+	if (!rx_msg)
+		return -ENOMEM;
+
+	ret = se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
+				  ELE_SERVICE_SWAP_REQ,
+				  ELE_SERVICE_SWAP_REQ_MSG_SZ, true);
+	if (ret)
+		return ret;
+
+	tx_msg->data[0] = flag;
+	tx_msg->data[1] = addr_size;
+	tx_msg->data[2] = ELE_NONE_VAL;
+	tx_msg->data[3] = lower_32_bits(addr);
+	tx_msg->data[4] = se_get_msg_chksum((u32 *)&tx_msg[0],
+					    ELE_SERVICE_SWAP_REQ_MSG_SZ);
+	if (!tx_msg->data[4])
+		return -EINVAL;
+
+	ret = ele_msg_send_rcv(priv, tx_msg, ELE_SERVICE_SWAP_REQ_MSG_SZ,
+			       rx_msg, ELE_SERVICE_SWAP_RSP_MSG_SZ);
+	if (ret < 0)
+		return ret;
+
+	ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_SERVICE_SWAP_REQ,
+				      ELE_SERVICE_SWAP_RSP_MSG_SZ, true);
+	if (ret)
+		return ret;
+
+	if (flag == ELE_IMEM_EXPORT)
+		ret = rx_msg->data[1];
+	else
+		ret = 0;
+
+	return ret;
+}
+
+int ele_fw_authenticate(struct se_if_priv *priv, phys_addr_t contnr_addr,
+			phys_addr_t img_addr)
+{
+	int ret = 0;
+
+	if (!priv)
+		return -EINVAL;
+
+	struct se_api_msg *tx_msg __free(kfree)	=
+		kzalloc(ELE_FW_AUTH_REQ_SZ, GFP_KERNEL);
+	if (!tx_msg)
+		return -ENOMEM;
+
+	struct se_api_msg *rx_msg __free(kfree) =
+		kzalloc(ELE_FW_AUTH_RSP_MSG_SZ, GFP_KERNEL);
+	if (!rx_msg)
+		return -ENOMEM;
+
+	ret = se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
+				  ELE_FW_AUTH_REQ, ELE_FW_AUTH_REQ_SZ, true);
+	if (ret)
+		return ret;
+
+	tx_msg->data[0] = lower_32_bits(contnr_addr);
+	tx_msg->data[1] = upper_32_bits(contnr_addr);
+	tx_msg->data[2] = img_addr;
+
+	ret = ele_msg_send_rcv(priv, tx_msg, ELE_FW_AUTH_REQ_SZ, rx_msg,
+			       ELE_FW_AUTH_RSP_MSG_SZ);
+	if (ret < 0)
+		return ret;
+
+	ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_FW_AUTH_REQ,
+				      ELE_FW_AUTH_RSP_MSG_SZ, true);
+
+	return ret;
+}
+
+int ele_debug_dump(struct se_if_priv *priv)
+{
+	bool keep_logging;
+	int msg_ex_cnt;
+	int ret = 0;
+	int i;
+
+	if (!priv)
+		return -EINVAL;
+
+	struct se_api_msg *tx_msg __free(kfree) = kzalloc(ELE_DEBUG_DUMP_REQ_SZ,
+							  GFP_KERNEL);
+	if (!tx_msg)
+		return -ENOMEM;
+
+	struct se_api_msg *rx_msg __free(kfree)	= kzalloc(ELE_DEBUG_DUMP_RSP_SZ,
+							  GFP_KERNEL);
+	if (!rx_msg)
+		return -ENOMEM;
+
+	ret = se_fill_cmd_msg_hdr(priv, &tx_msg->header, ELE_DEBUG_DUMP_REQ,
+				  ELE_DEBUG_DUMP_REQ_SZ, true);
+	if (ret)
+		return ret;
+
+	msg_ex_cnt = 0;
+	do {
+		memset(rx_msg, 0x0, ELE_DEBUG_DUMP_RSP_SZ);
+
+		ret = ele_msg_send_rcv(priv, tx_msg, ELE_DEBUG_DUMP_REQ_SZ,
+				       rx_msg, ELE_DEBUG_DUMP_RSP_SZ);
+		if (ret < 0)
+			return ret;
+
+		ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_DEBUG_DUMP_REQ,
+					      ELE_DEBUG_DUMP_RSP_SZ, true);
+		if (ret) {
+			dev_err(priv->dev, "Dump_Debug_Buffer Error: %x.", ret);
+			break;
+		}
+		keep_logging = (rx_msg->header.size >= (ELE_DEBUG_DUMP_RSP_SZ >> 2) &&
+				msg_ex_cnt < ELE_MAX_DBG_DMP_PKT);
+
+		rx_msg->header.size -= 2;
+
+		if (rx_msg->header.size > 4)
+			rx_msg->header.size--;
+
+		for (i = 0; i < rx_msg->header.size; i += 2)
+			dev_info(priv->dev, "%s%02x_%02x: 0x%08x 0x%08x",
+				 FW_DBG_DUMP_FIXED_STR,	msg_ex_cnt, i,
+				 rx_msg->data[i + 1], rx_msg->data[i + 2]);
+
+		msg_ex_cnt++;
+	} while (keep_logging);
+
+	return ret;
+}
diff --git a/drivers/firmware/imx/ele_base_msg.h b/drivers/firmware/imx/ele_base_msg.h
new file mode 100644
index 000000000000..8e5b015e99a2
--- /dev/null
+++ b/drivers/firmware/imx/ele_base_msg.h
@@ -0,0 +1,95 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2025 NXP
+ *
+ * Header file for the EdgeLock Enclave Base API(s).
+ */
+
+#ifndef ELE_BASE_MSG_H
+#define ELE_BASE_MSG_H
+
+#include <linux/device.h>
+#include <linux/types.h>
+
+#include "se_ctrl.h"
+
+#define ELE_NONE_VAL			0x0
+
+#define ELE_GET_INFO_REQ		0xda
+#define ELE_GET_INFO_REQ_MSG_SZ		0x10
+#define ELE_GET_INFO_RSP_MSG_SZ		0x08
+
+#define MAX_UID_SIZE                     (16)
+#define DEV_GETINFO_ROM_PATCH_SHA_SZ     (32)
+#define DEV_GETINFO_FW_SHA_SZ            (32)
+#define DEV_GETINFO_OEM_SRKH_SZ          (64)
+#define DEV_GETINFO_MIN_VER_MASK	0xff
+#define DEV_GETINFO_MAJ_VER_MASK	0xff00
+#define ELE_DEV_INFO_EXTRA_SZ		0x60
+
+struct dev_info {
+	u8  cmd;
+	u8  ver;
+	u16 length;
+	u16 soc_id;
+	u16 soc_rev;
+	u16 lmda_val;
+	u8  ssm_state;
+	u8  dev_atts_api_ver;
+	u8  uid[MAX_UID_SIZE];
+	u8  sha_rom_patch[DEV_GETINFO_ROM_PATCH_SHA_SZ];
+	u8  sha_fw[DEV_GETINFO_FW_SHA_SZ];
+};
+
+struct dev_addn_info {
+	u8  oem_srkh[DEV_GETINFO_OEM_SRKH_SZ];
+	u8  trng_state;
+	u8  csal_state;
+	u8  imem_state;
+	u8  reserved2;
+};
+
+struct ele_dev_info {
+	struct dev_info d_info;
+	struct dev_addn_info d_addn_info;
+};
+
+#define ELE_GET_INFO_BUFF_SZ		(sizeof(struct ele_dev_info) \
+						+ ELE_DEV_INFO_EXTRA_SZ)
+
+#define GET_SERIAL_NUM_FROM_UID(x, uid_word_sz) \
+	(((u64)(((u32 *)(x))[(uid_word_sz) - 1]) << 32) | ((u32 *)(x))[0])
+
+#define ELE_MAX_DBG_DMP_PKT		50
+#define ELE_DEBUG_DUMP_REQ		0x21
+#define ELE_DEBUG_DUMP_REQ_SZ		0x4
+#define ELE_DEBUG_DUMP_RSP_SZ		0x5c
+
+#define ELE_PING_REQ			0x01
+#define ELE_PING_REQ_SZ			0x04
+#define ELE_PING_RSP_SZ			0x08
+
+#define ELE_SERVICE_SWAP_REQ		0xdf
+#define ELE_SERVICE_SWAP_REQ_MSG_SZ	0x18
+#define ELE_SERVICE_SWAP_RSP_MSG_SZ	0x0c
+#define ELE_IMEM_SIZE			0x10000
+#define ELE_IMEM_STATE_OK		0xca
+#define ELE_IMEM_STATE_BAD		0xfe
+#define ELE_IMEM_STATE_WORD		0x27
+#define ELE_IMEM_STATE_MASK		0x00ff0000
+#define ELE_IMEM_EXPORT			0x1
+#define ELE_IMEM_IMPORT			0x2
+
+#define ELE_FW_AUTH_REQ			0x02
+#define ELE_FW_AUTH_REQ_SZ		0x10
+#define ELE_FW_AUTH_RSP_MSG_SZ		0x08
+
+int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info);
+int ele_fetch_soc_info(struct se_if_priv *priv, void *data);
+int ele_ping(struct se_if_priv *priv);
+int ele_service_swap(struct se_if_priv *priv, phys_addr_t addr,
+		     u32 addr_size, u16 flag);
+int ele_fw_authenticate(struct se_if_priv *priv, phys_addr_t contnr_addr,
+			phys_addr_t img_addr);
+int ele_debug_dump(struct se_if_priv *priv);
+#endif
diff --git a/drivers/firmware/imx/ele_common.c b/drivers/firmware/imx/ele_common.c
new file mode 100644
index 000000000000..a7150ff8e3b9
--- /dev/null
+++ b/drivers/firmware/imx/ele_common.c
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 NXP
+ */
+
+#include "ele_base_msg.h"
+#include "ele_common.h"
+
+/*
+ * se_get_msg_chksum() - to calculate checksum word by word.
+ *
+ * @msg : reference to the input msg-data.
+ * @msg_len : reference to the input msg-data length in bytes.
+ *            Includes extra 4 bytes (or 1 words) chksum.
+ *
+ * This function returns the checksum calculated by ORing word by word.
+ *
+ * Return:
+ *  0: if the input length is not 4 byte aligned, or num of words < 5.
+ *  chksum: calculated word by word.
+ */
+u32 se_get_msg_chksum(u32 *msg, u32 msg_len)
+{
+	u32 nb_words = msg_len / (u32)sizeof(u32);
+	u32 chksum = 0;
+	u32 i;
+
+	if (nb_words < 5)
+		return chksum;
+
+	if (msg_len % SE_MSG_WORD_SZ) {
+		pr_err("Msg-len is not 4-byte aligned.");
+		return chksum;
+	}
+
+	/* nb_words include one checksum word, so skip it. */
+	nb_words--;
+
+	for (i = 0; i < nb_words; i++)
+		chksum ^= *(msg + i);
+
+	return chksum;
+}
+
+int ele_msg_rcv(struct se_if_priv *priv, struct se_clbk_handle *se_clbk_hdl)
+{
+	unsigned long timeout;
+	int ret;
+
+	do {
+		timeout = MAX_SCHEDULE_TIMEOUT;
+
+		ret = wait_for_completion_interruptible_timeout(&se_clbk_hdl->done, timeout);
+		if (ret == -ERESTARTSYS) {
+			if (priv->waiting_rsp_clbk_hdl.rx_msg) {
+				priv->waiting_rsp_clbk_hdl.signal_rcvd = true;
+				continue;
+			}
+			ret = -EINTR;
+			break;
+		}
+		ret = se_clbk_hdl->rx_msg_sz;
+		break;
+	} while (ret < 0);
+
+	return ret;
+}
+
+int ele_msg_send(struct se_if_priv *priv,
+		 void *tx_msg,
+		 int tx_msg_sz)
+{
+	struct se_msg_hdr *header = tx_msg;
+	int err;
+
+	/*
+	 * Check that the size passed as argument matches the size
+	 * carried in the message.
+	 */
+	if (header->size << 2 != tx_msg_sz) {
+		dev_err(priv->dev,
+			"User buf hdr: 0x%x, sz mismatced with input-sz (%d != %d).",
+			*(u32 *)header, header->size << 2, tx_msg_sz);
+		return -EINVAL;
+	}
+
+	err = mbox_send_message(priv->tx_chan, tx_msg);
+	if (err < 0) {
+		dev_err(priv->dev, "Error: mbox_send_message failure.\n");
+		return err;
+	}
+
+	return tx_msg_sz;
+}
+
+/* API used for send/receive blocking call. */
+int ele_msg_send_rcv(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz,
+		     void *rx_msg, int exp_rx_msg_sz)
+{
+	int err;
+
+	guard(mutex)(&priv->se_if_cmd_lock);
+
+	priv->waiting_rsp_clbk_hdl.rx_msg_sz = exp_rx_msg_sz;
+	priv->waiting_rsp_clbk_hdl.rx_msg = rx_msg;
+
+	err = ele_msg_send(priv, tx_msg, tx_msg_sz);
+	if (err < 0)
+		return err;
+
+	err = ele_msg_rcv(priv, &priv->waiting_rsp_clbk_hdl);
+
+	if (priv->waiting_rsp_clbk_hdl.signal_rcvd) {
+		err = -EINTR;
+		priv->waiting_rsp_clbk_hdl.signal_rcvd = false;
+		dev_err(priv->dev, "Err[0x%x]:Interrupted by signal.\n", err);
+	}
+
+	return err;
+}
+
+static bool check_hdr_exception_for_sz(struct se_if_priv *priv,
+				       struct se_msg_hdr *header)
+{
+	/*
+	 * List of API(s) header that can be accepte variable length
+	 * response buffer.
+	 */
+	if (header->command == ELE_DEBUG_DUMP_REQ &&
+	    header->ver == priv->if_defs->base_api_ver &&
+	    header->size >= 0 && header->size <= ELE_DEBUG_DUMP_RSP_SZ)
+		return true;
+
+	return false;
+}
+
+/*
+ * Callback called by mailbox FW, when data is received.
+ */
+void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg)
+{
+	struct se_clbk_handle *se_clbk_hdl;
+	struct device *dev = mbox_cl->dev;
+	struct se_msg_hdr *header;
+	struct se_if_priv *priv;
+	u32 rx_msg_sz;
+
+	priv = dev_get_drvdata(dev);
+
+	/* The function can be called with NULL msg */
+	if (!msg) {
+		dev_err(dev, "Message is invalid\n");
+		return;
+	}
+
+	header = msg;
+	rx_msg_sz = header->size << 2;
+
+	/* Incoming command: wake up the receiver if any. */
+	if (header->tag == priv->if_defs->cmd_tag) {
+		se_clbk_hdl = &priv->cmd_receiver_clbk_hdl;
+		dev_dbg(dev, "Selecting cmd receiver for mesg header:0x%x.",
+			*(u32 *)header);
+
+		/*
+		 * Pre-allocated buffer of MAX_NVM_MSG_LEN
+		 * as the NVM command are initiated by FW.
+		 * Size is revealed as part of this call function.
+		 */
+		if (rx_msg_sz > MAX_NVM_MSG_LEN) {
+			dev_err(dev,
+				"CMD-RCVER NVM: hdr(0x%x) with different sz(%d != %d).\n",
+				*(u32 *)header, rx_msg_sz, se_clbk_hdl->rx_msg_sz);
+
+			se_clbk_hdl->rx_msg_sz = MAX_NVM_MSG_LEN;
+		}
+		se_clbk_hdl->rx_msg_sz = rx_msg_sz;
+
+	} else if (header->tag == priv->if_defs->rsp_tag) {
+		se_clbk_hdl = &priv->waiting_rsp_clbk_hdl;
+		dev_dbg(dev, "Selecting resp waiter for mesg header:0x%x.",
+			*(u32 *)header);
+
+		if (rx_msg_sz != se_clbk_hdl->rx_msg_sz &&
+		    check_hdr_exception_for_sz(priv, header)) {
+			dev_err(dev,
+				"Rsp to CMD: hdr(0x%x) with different sz(%d != %d).\n",
+				*(u32 *)header, rx_msg_sz, se_clbk_hdl->rx_msg_sz);
+
+			se_clbk_hdl->rx_msg_sz = min(rx_msg_sz, se_clbk_hdl->rx_msg_sz);
+		}
+	} else {
+		dev_err(dev, "Failed to select a device for message: %.8x\n",
+			*((u32 *)header));
+		return;
+	}
+
+	memcpy(se_clbk_hdl->rx_msg, msg, se_clbk_hdl->rx_msg_sz);
+
+	/* Allow user to read */
+	complete(&se_clbk_hdl->done);
+}
+
+int se_val_rsp_hdr_n_status(struct se_if_priv *priv, struct se_api_msg *msg,
+			    u8 msg_id, u8 sz, bool is_base_api)
+{
+	struct se_msg_hdr *header = &msg->header;
+	u32 status;
+
+	if (header->tag != priv->if_defs->rsp_tag) {
+		dev_err(priv->dev, "MSG[0x%x] Hdr: Resp tag mismatch. (0x%x != 0x%x)",
+			msg_id, header->tag, priv->if_defs->rsp_tag);
+		return -EINVAL;
+	}
+
+	if (header->command != msg_id) {
+		dev_err(priv->dev, "MSG Header: Cmd id mismatch. (0x%x != 0x%x)",
+			header->command, msg_id);
+		return -EINVAL;
+	}
+
+	if ((sz % 4) || (header->size != (sz >> 2) &&
+			 !check_hdr_exception_for_sz(priv, header))) {
+		dev_err(priv->dev, "MSG[0x%x] Hdr: Cmd size mismatch. (0x%x != 0x%x)",
+			msg_id, header->size, (sz >> 2));
+		return -EINVAL;
+	}
+
+	if (is_base_api && header->ver != priv->if_defs->base_api_ver) {
+		dev_err(priv->dev,
+			"MSG[0x%x] Hdr: Base API Vers mismatch. (0x%x != 0x%x)",
+			msg_id, header->ver, priv->if_defs->base_api_ver);
+		return -EINVAL;
+	} else if (!is_base_api && header->ver != priv->if_defs->fw_api_ver) {
+		dev_err(priv->dev,
+			"MSG[0x%x] Hdr: FW API Vers mismatch. (0x%x != 0x%x)",
+			msg_id, header->ver, priv->if_defs->fw_api_ver);
+		return -EINVAL;
+	}
+
+	status = RES_STATUS(msg->data[0]);
+	if (status != priv->if_defs->success_tag) {
+		dev_err(priv->dev, "Command Id[%x], Response Failure = 0x%x",
+			header->command, status);
+		return -EPERM;
+	}
+
+	return 0;
+}
+
+int se_save_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem)
+{
+	struct ele_dev_info s_info = {0};
+	int ret;
+
+	ret = ele_get_info(priv, &s_info);
+	if (ret) {
+		dev_err(priv->dev, "Failed to get info from ELE.\n");
+		return ret;
+	}
+
+	/* Check for the imem-state before continue to save imem state. */
+	if (s_info.d_addn_info.imem_state == ELE_IMEM_STATE_BAD)
+		return -EIO;
+
+	/*
+	 * EXPORT command will save encrypted IMEM to given address,
+	 * so later in resume, IMEM can be restored from the given
+	 * address.
+	 *
+	 * Size must be at least 64 kB.
+	 */
+	ret = ele_service_swap(priv, imem->phyaddr, ELE_IMEM_SIZE, ELE_IMEM_EXPORT);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to export IMEM.");
+		imem->size = 0;
+	} else {
+		dev_dbg(priv->dev,
+			"Exported %d bytes of encrypted IMEM.",
+			ret);
+		imem->size = ret;
+	}
+
+	return ret > 0 ? 0 : ret;
+}
+
+int se_restore_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem)
+{
+	struct ele_dev_info s_info;
+	int ret;
+
+	/* get info from ELE */
+	ret = ele_get_info(priv, &s_info);
+	if (ret) {
+		dev_err(priv->dev, "Failed to get info from ELE.");
+		return ret;
+	}
+	imem->state = s_info.d_addn_info.imem_state;
+
+	/* Check for the imem-state and imem-size before continue to
+	 * restore imem state.
+	 */
+	if (s_info.d_addn_info.imem_state != ELE_IMEM_STATE_BAD || !imem->size)
+		return -EIO;
+
+	/*
+	 * IMPORT command will restore IMEM from the given
+	 * address, here size is the actual size returned by ELE
+	 * during the export operation
+	 */
+	ret = ele_service_swap(priv, imem->phyaddr, imem->size, ELE_IMEM_IMPORT);
+	if (ret) {
+		dev_err(priv->dev, "Failed to import IMEM");
+		return ret;
+	}
+
+	/*
+	 * After importing IMEM, check if IMEM state is equal to 0xCA
+	 * to ensure IMEM is fully loaded and
+	 * ELE functionality can be used.
+	 */
+	ret = ele_get_info(priv, &s_info);
+	if (ret) {
+		dev_err(priv->dev, "Failed to get info from ELE.");
+		return ret;
+	}
+	imem->state = s_info.d_addn_info.imem_state;
+
+	if (s_info.d_addn_info.imem_state == ELE_IMEM_STATE_OK)
+		dev_dbg(priv->dev, "Successfully restored IMEM.");
+	else
+		dev_err(priv->dev, "Failed to restore IMEM.");
+
+	return ret;
+}
diff --git a/drivers/firmware/imx/ele_common.h b/drivers/firmware/imx/ele_common.h
new file mode 100644
index 000000000000..96e987ef6f88
--- /dev/null
+++ b/drivers/firmware/imx/ele_common.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2025 NXP
+ */
+
+#ifndef __ELE_COMMON_H__
+#define __ELE_COMMON_H__
+
+#include "se_ctrl.h"
+
+#define ELE_SUCCESS_IND			0xD6
+
+#define IMX_ELE_FW_DIR                 "imx/ele/"
+
+u32 se_get_msg_chksum(u32 *msg, u32 msg_len);
+
+int ele_msg_rcv(struct se_if_priv *priv, struct se_clbk_handle *se_clbk_hdl);
+
+int ele_msg_send(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz);
+
+int ele_msg_send_rcv(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz,
+		     void *rx_msg, int exp_rx_msg_sz);
+
+void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg);
+
+int se_val_rsp_hdr_n_status(struct se_if_priv *priv, struct se_api_msg *msg,
+			    u8 msg_id, u8 sz, bool is_base_api);
+
+/* Fill a command message header with a given command ID and length in bytes. */
+static inline int se_fill_cmd_msg_hdr(struct se_if_priv *priv, struct se_msg_hdr *hdr,
+				      u8 cmd, u32 len, bool is_base_api)
+{
+	hdr->tag = priv->if_defs->cmd_tag;
+	hdr->ver = (is_base_api) ? priv->if_defs->base_api_ver : priv->if_defs->fw_api_ver;
+	hdr->command = cmd;
+	hdr->size = len >> 2;
+
+	return 0;
+}
+
+int se_save_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem);
+
+int se_restore_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem);
+
+#endif /*__ELE_COMMON_H__ */
diff --git a/drivers/firmware/imx/se_ctrl.c b/drivers/firmware/imx/se_ctrl.c
new file mode 100644
index 000000000000..1c91b4698465
--- /dev/null
+++ b/drivers/firmware/imx/se_ctrl.c
@@ -0,0 +1,408 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 NXP
+ */
+
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/firmware.h>
+#include <linux/firmware/imx/se_api.h>
+#include <linux/genalloc.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/miscdevice.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/sys_soc.h>
+
+#include "ele_base_msg.h"
+#include "ele_common.h"
+#include "se_ctrl.h"
+
+#define MAX_SOC_INFO_DATA_SZ		256
+#define MBOX_TX_NAME			"tx"
+#define MBOX_RX_NAME			"rx"
+
+#define SE_TYPE_STR_DBG			"dbg"
+#define SE_TYPE_STR_HSM			"hsm"
+
+#define SE_TYPE_ID_DBG			0x1
+#define SE_TYPE_ID_HSM			0x2
+
+struct se_fw_img_name {
+	const u8 *prim_fw_nm_in_rfs;
+	const u8 *seco_fw_nm_in_rfs;
+};
+
+struct se_fw_load_info {
+	const struct se_fw_img_name *se_fw_img_nm;
+	bool is_fw_tobe_loaded;
+	bool imem_mgmt;
+	struct se_imem_buf imem;
+};
+
+struct se_var_info {
+	u16 soc_rev;
+	struct se_fw_load_info load_fw;
+};
+
+/* contains fixed information */
+struct se_soc_info {
+	const u16 soc_id;
+	const bool soc_register;
+	const struct se_fw_img_name se_fw_img_nm;
+};
+
+struct se_if_node {
+	struct se_soc_info *se_info;
+	u8 *pool_name;
+	bool reserved_dma_ranges;
+	struct se_if_defines if_defs;
+};
+
+/* common for all the SoC. */
+static struct se_var_info var_se_info;
+
+static struct se_soc_info se_imx8ulp_info = {
+	.soc_id = SOC_ID_OF_IMX8ULP,
+	.soc_register = true,
+	.se_fw_img_nm = {
+		.prim_fw_nm_in_rfs = IMX_ELE_FW_DIR
+			"mx8ulpa2-ahab-container.img",
+		.seco_fw_nm_in_rfs = IMX_ELE_FW_DIR
+			"mx8ulpa2ext-ahab-container.img",
+	},
+};
+
+static struct se_if_node imx8ulp_se_ele_hsm = {
+	.se_info = &se_imx8ulp_info,
+	.pool_name = "sram",
+	.reserved_dma_ranges = true,
+	.if_defs = {
+		.se_if_type = SE_TYPE_ID_HSM,
+		.cmd_tag = 0x17,
+		.rsp_tag = 0xe1,
+		.success_tag = ELE_SUCCESS_IND,
+		.base_api_ver = MESSAGING_VERSION_6,
+		.fw_api_ver = MESSAGING_VERSION_7,
+	},
+};
+
+static struct se_soc_info se_imx93_info = {
+	.soc_id = SOC_ID_OF_IMX93,
+};
+
+static struct se_if_node imx93_se_ele_hsm = {
+	.se_info = &se_imx93_info,
+	.reserved_dma_ranges = true,
+	.if_defs = {
+		.se_if_type = SE_TYPE_ID_HSM,
+		.cmd_tag = 0x17,
+		.rsp_tag = 0xe1,
+		.success_tag = ELE_SUCCESS_IND,
+		.base_api_ver = MESSAGING_VERSION_6,
+		.fw_api_ver = MESSAGING_VERSION_7,
+	},
+};
+
+static const struct of_device_id se_match[] = {
+	{ .compatible = "fsl,imx8ulp-se-ele-hsm", .data = &imx8ulp_se_ele_hsm},
+	{ .compatible = "fsl,imx93-se-ele-hsm", .data = &imx93_se_ele_hsm},
+	{},
+};
+
+char *get_se_if_name(u8 se_if_id)
+{
+	switch (se_if_id) {
+	case SE_TYPE_ID_DBG: return SE_TYPE_STR_DBG;
+	case SE_TYPE_ID_HSM: return SE_TYPE_STR_HSM;
+	}
+
+	return NULL;
+}
+
+static struct se_fw_load_info *get_load_fw_instance(struct se_if_priv *priv)
+{
+	return &var_se_info.load_fw;
+}
+
+static int get_se_soc_info(struct se_if_priv *priv, const struct se_soc_info *se_info)
+{
+	struct se_fw_load_info *load_fw = get_load_fw_instance(priv);
+	struct soc_device_attribute *attr;
+	u8 data[MAX_SOC_INFO_DATA_SZ];
+	struct ele_dev_info *s_info;
+	struct soc_device *sdev;
+	int err = 0;
+
+	/*
+	 * This function should be called once.
+	 * Check if the se_soc_rev is zero to continue.
+	 */
+	if (var_se_info.soc_rev)
+		return err;
+
+	err = ele_fetch_soc_info(priv, &data);
+	if (err < 0)
+		return dev_err_probe(priv->dev, err, "Failed to fetch SoC Info.");
+	s_info = (void *)data;
+	var_se_info.soc_rev = s_info->d_info.soc_rev;
+	load_fw->imem.state = s_info->d_addn_info.imem_state;
+
+	if (!se_info->soc_register)
+		return 0;
+
+	attr = devm_kzalloc(priv->dev, sizeof(*attr), GFP_KERNEL);
+	if (!attr)
+		return -ENOMEM;
+
+	if (FIELD_GET(DEV_GETINFO_MIN_VER_MASK, var_se_info.soc_rev))
+		attr->revision = devm_kasprintf(priv->dev, GFP_KERNEL, "%x.%x",
+						FIELD_GET(DEV_GETINFO_MIN_VER_MASK,
+							  var_se_info.soc_rev),
+						FIELD_GET(DEV_GETINFO_MAJ_VER_MASK,
+							  var_se_info.soc_rev));
+	else
+		attr->revision = devm_kasprintf(priv->dev, GFP_KERNEL, "%x",
+						FIELD_GET(DEV_GETINFO_MAJ_VER_MASK,
+							  var_se_info.soc_rev));
+
+	switch (se_info->soc_id) {
+	case SOC_ID_OF_IMX8ULP:
+		attr->soc_id = "i.MX8ULP";
+		break;
+	case SOC_ID_OF_IMX93:
+		attr->soc_id = "i.MX93";
+		break;
+	}
+
+	err = of_property_read_string(of_root, "model", &attr->machine);
+	if (err)
+		return -EINVAL;
+
+	attr->family = "Freescale i.MX";
+
+	attr->serial_number = devm_kasprintf(priv->dev,
+					     GFP_KERNEL, "%016llX",
+					     GET_SERIAL_NUM_FROM_UID(s_info->d_info.uid,
+								     MAX_UID_SIZE >> 2));
+
+	sdev = soc_device_register(attr);
+	if (IS_ERR(sdev))
+		return PTR_ERR(sdev);
+
+	return 0;
+}
+
+/* interface for managed res to free a mailbox channel */
+static void if_mbox_free_channel(void *mbox_chan)
+{
+	mbox_free_channel(mbox_chan);
+}
+
+static int se_if_request_channel(struct device *dev, struct mbox_chan **chan,
+				 struct mbox_client *cl, const char *name)
+{
+	struct mbox_chan *t_chan;
+	int ret = 0;
+
+	t_chan = mbox_request_channel_byname(cl, name);
+	if (IS_ERR(t_chan))
+		return dev_err_probe(dev, PTR_ERR(t_chan),
+				     "Failed to request %s channel.", name);
+
+	ret = devm_add_action_or_reset(dev, if_mbox_free_channel, t_chan);
+	if (ret)
+		return dev_err_probe(dev, -EPERM,
+				     "Failed to add-action for removal of mbox: %s\n",
+				     name);
+	*chan = t_chan;
+
+	return ret;
+}
+
+static void se_if_probe_cleanup(void *plat_dev)
+{
+	struct platform_device *pdev = plat_dev;
+	struct se_fw_load_info *load_fw;
+	struct device *dev = &pdev->dev;
+	struct se_if_priv *priv;
+
+	priv = dev_get_drvdata(dev);
+	load_fw = get_load_fw_instance(priv);
+
+	/*
+	 * In se_if_request_channel(), passed the clean-up functional
+	 * pointer reference as action to devm_add_action_or_reset().
+	 * No need to free the mbox channels here.
+	 */
+
+	/*
+	 * free the buffer in se remove, previously allocated
+	 * in se probe to store encrypted IMEM
+	 */
+	if (load_fw && load_fw->imem.buf) {
+		dmam_free_coherent(dev, ELE_IMEM_SIZE, load_fw->imem.buf,
+				   load_fw->imem.phyaddr);
+		load_fw->imem.buf = NULL;
+	}
+
+	/*
+	 * No need to check, if reserved memory is allocated
+	 * before calling for its release. Or clearing the
+	 * un-set bit.
+	 */
+	of_reserved_mem_device_release(dev);
+}
+
+static int se_if_probe(struct platform_device *pdev)
+{
+	const struct se_soc_info *se_info;
+	const struct se_if_node *if_node;
+	struct se_fw_load_info *load_fw;
+	struct device *dev = &pdev->dev;
+	struct se_if_priv *priv;
+	int ret;
+
+	if_node = device_get_match_data(dev);
+	if (!if_node)
+		return -EINVAL;
+
+	se_info = if_node->se_info;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = dev;
+	priv->if_defs = &if_node->if_defs;
+	dev_set_drvdata(dev, priv);
+
+	ret = devm_add_action_or_reset(dev, se_if_probe_cleanup, pdev);
+	if (ret)
+		return ret;
+
+	/* Mailbox client configuration */
+	priv->se_mb_cl.dev		= dev;
+	priv->se_mb_cl.tx_block		= false;
+	priv->se_mb_cl.knows_txdone	= true;
+	priv->se_mb_cl.rx_callback	= se_if_rx_callback;
+
+	ret = se_if_request_channel(dev, &priv->tx_chan, &priv->se_mb_cl, MBOX_TX_NAME);
+	if (ret)
+		return ret;
+
+	ret = se_if_request_channel(dev, &priv->rx_chan, &priv->se_mb_cl, MBOX_RX_NAME);
+	if (ret)
+		return ret;
+
+	mutex_init(&priv->se_if_cmd_lock);
+
+	init_completion(&priv->waiting_rsp_clbk_hdl.done);
+	init_completion(&priv->cmd_receiver_clbk_hdl.done);
+
+	if (if_node->pool_name) {
+		priv->mem_pool = of_gen_pool_get(dev->of_node, if_node->pool_name, 0);
+		if (!priv->mem_pool)
+			return dev_err_probe(dev, -ENOMEM,
+					     "Unable to get sram pool = %s.",
+					     if_node->pool_name);
+	}
+
+	if (if_node->reserved_dma_ranges) {
+		ret = of_reserved_mem_device_init(dev);
+		if (ret)
+			return dev_err_probe(dev, ret,
+					    "Failed to init reserved memory region.");
+	}
+
+	if (if_node->if_defs.se_if_type == SE_TYPE_ID_HSM) {
+		ret = get_se_soc_info(priv, se_info);
+		if (ret)
+			return dev_err_probe(dev, ret, "Failed to fetch SoC Info.");
+	}
+
+	/* By default, there is no pending FW to be loaded.*/
+	if (se_info->se_fw_img_nm.seco_fw_nm_in_rfs) {
+		load_fw = get_load_fw_instance(priv);
+		load_fw->se_fw_img_nm = &se_info->se_fw_img_nm;
+		load_fw->is_fw_tobe_loaded = true;
+
+		if (load_fw->se_fw_img_nm->prim_fw_nm_in_rfs) {
+			/* allocate buffer where SE store encrypted IMEM */
+			load_fw->imem.buf = dmam_alloc_coherent(priv->dev, ELE_IMEM_SIZE,
+								&load_fw->imem.phyaddr,
+								GFP_KERNEL);
+			if (!load_fw->imem.buf)
+				return dev_err_probe(dev, -ENOMEM,
+						     "dmam-alloc-failed: To store encr-IMEM.");
+			load_fw->imem_mgmt = true;
+		}
+	}
+	dev_info(dev, "i.MX secure-enclave: %s0 interface to firmware, configured.",
+		 get_se_if_name(priv->if_defs->se_if_type));
+
+	return ret;
+}
+
+static int se_suspend(struct device *dev)
+{
+	struct se_if_priv *priv = dev_get_drvdata(dev);
+	struct se_fw_load_info *load_fw;
+	int ret = 0;
+
+	load_fw = get_load_fw_instance(priv);
+
+	if (load_fw->imem_mgmt) {
+		ret = se_save_imem_state(priv, &load_fw->imem);
+		if (ret)
+			dev_err(dev, "Failure saving IMEM state[0x%x]", ret);
+	}
+
+	return 0;
+}
+
+static int se_resume(struct device *dev)
+{
+	struct se_if_priv *priv = dev_get_drvdata(dev);
+	struct se_fw_load_info *load_fw;
+	int ret = 0;
+
+	load_fw = get_load_fw_instance(priv);
+
+	if (load_fw->imem_mgmt) {
+		se_restore_imem_state(priv, &load_fw->imem);
+		if (ret)
+			dev_err(dev, "Failure restoring IMEM state[0x%x]", ret);
+	}
+
+	return 0;
+}
+
+static const struct dev_pm_ops se_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(se_suspend, se_resume)
+};
+
+static struct platform_driver se_driver = {
+	.driver = {
+		.name = "fsl-se",
+		.of_match_table = se_match,
+		.pm = &se_pm,
+	},
+	.probe = se_if_probe,
+};
+MODULE_DEVICE_TABLE(of, se_match);
+
+module_platform_driver(se_driver);
+MODULE_AUTHOR("Pankaj Gupta <pankaj.gupta at nxp.com>");
+MODULE_DESCRIPTION("iMX Secure Enclave Driver.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/imx/se_ctrl.h b/drivers/firmware/imx/se_ctrl.h
new file mode 100644
index 000000000000..b15c4022a46c
--- /dev/null
+++ b/drivers/firmware/imx/se_ctrl.h
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2025 NXP
+ */
+
+#ifndef SE_MU_H
+#define SE_MU_H
+
+#include <linux/miscdevice.h>
+#include <linux/semaphore.h>
+#include <linux/mailbox_client.h>
+
+#define MAX_FW_LOAD_RETRIES		50
+#define SE_MSG_WORD_SZ			0x4
+
+#define RES_STATUS(x)			FIELD_GET(0x000000ff, x)
+#define MAX_NVM_MSG_LEN			(256)
+#define MESSAGING_VERSION_6		0x6
+#define MESSAGING_VERSION_7		0x7
+
+struct se_clbk_handle {
+	struct completion done;
+	bool signal_rcvd;
+	u32 rx_msg_sz;
+	/*
+	 * Assignment of the rx_msg buffer to held till the
+	 * received content as part callback function, is copied.
+	 */
+	struct se_api_msg *rx_msg;
+};
+
+struct se_imem_buf {
+	u8 *buf;
+	phys_addr_t phyaddr;
+	u32 size;
+	u32 state;
+};
+
+/* Header of the messages exchange with the EdgeLock Enclave */
+struct se_msg_hdr {
+	u8 ver;
+	u8 size;
+	u8 command;
+	u8 tag;
+}  __packed;
+
+#define SE_MU_HDR_SZ	4
+
+struct se_api_msg {
+	struct se_msg_hdr header;
+	u32 data[];
+};
+
+struct se_if_defines {
+	const u8 se_if_type;
+	u8 cmd_tag;
+	u8 rsp_tag;
+	u8 success_tag;
+	u8 base_api_ver;
+	u8 fw_api_ver;
+};
+
+struct se_if_priv {
+	struct device *dev;
+
+	struct se_clbk_handle cmd_receiver_clbk_hdl;
+	/*
+	 * Update to the waiting_rsp_dev, to be protected
+	 * under se_if_cmd_lock.
+	 */
+	struct se_clbk_handle waiting_rsp_clbk_hdl;
+	/*
+	 * prevent new command to be sent on the se interface while previous
+	 * command is still processing. (response is awaited)
+	 */
+	struct mutex se_if_cmd_lock;
+
+	struct mbox_client se_mb_cl;
+	struct mbox_chan *tx_chan, *rx_chan;
+
+	struct gen_pool *mem_pool;
+	const struct se_if_defines *if_defs;
+};
+
+char *get_se_if_name(u8 se_if_id);
+#endif
diff --git a/include/linux/firmware/imx/se_api.h b/include/linux/firmware/imx/se_api.h
new file mode 100644
index 000000000000..b1c4c9115d7b
--- /dev/null
+++ b/include/linux/firmware/imx/se_api.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2025 NXP
+ */
+
+#ifndef __SE_API_H__
+#define __SE_API_H__
+
+#include <linux/types.h>
+
+#define SOC_ID_OF_IMX8ULP		0x084d
+#define SOC_ID_OF_IMX93			0x9300
+
+#endif /* __SE_API_H__ */

-- 
2.43.0



From pankaj.gupta at nxp.com  Thu Dec 18 21:20:42 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Fri, 19 Dec 2025 10:50:42 +0530
Subject: [PATCH v23 4/7] firmware: imx: device context dedicated to priv
In-Reply-To: <20251219-imx-se-if-v23-0-5c6773d00318@nxp.com>
References: <20251219-imx-se-if-v23-0-5c6773d00318@nxp.com>
Message-ID: <20251219-imx-se-if-v23-4-5c6773d00318@nxp.com>

Add priv_dev_ctx to prepare enabling misc-device context based send-receive
path, to communicate with FW.

No functionality change.

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
 drivers/firmware/imx/ele_base_msg.c | 14 +++++-----
 drivers/firmware/imx/ele_common.c   | 51 +++++++++++++++++++++----------------
 drivers/firmware/imx/ele_common.h   |  8 +++---
 drivers/firmware/imx/se_ctrl.c      | 29 +++++++++++++++++++++
 drivers/firmware/imx/se_ctrl.h      |  9 +++++++
 5 files changed, 78 insertions(+), 33 deletions(-)

diff --git a/drivers/firmware/imx/ele_base_msg.c b/drivers/firmware/imx/ele_base_msg.c
index da50686786f2..475ba98be199 100644
--- a/drivers/firmware/imx/ele_base_msg.c
+++ b/drivers/firmware/imx/ele_base_msg.c
@@ -60,8 +60,8 @@ int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info)
 	tx_msg->data[0] = upper_32_bits(get_info_addr);
 	tx_msg->data[1] = lower_32_bits(get_info_addr);
 	tx_msg->data[2] = sizeof(*s_info);
-	ret = ele_msg_send_rcv(priv, tx_msg, ELE_GET_INFO_REQ_MSG_SZ, rx_msg,
-			       ELE_GET_INFO_RSP_MSG_SZ);
+	ret = ele_msg_send_rcv(priv->priv_dev_ctx, tx_msg, ELE_GET_INFO_REQ_MSG_SZ,
+			       rx_msg, ELE_GET_INFO_RSP_MSG_SZ);
 	if (ret < 0)
 		goto exit;
 
@@ -109,8 +109,8 @@ int ele_ping(struct se_if_priv *priv)
 		return ret;
 	}
 
-	ret = ele_msg_send_rcv(priv, tx_msg, ELE_PING_REQ_SZ, rx_msg,
-			       ELE_PING_RSP_SZ);
+	ret = ele_msg_send_rcv(priv->priv_dev_ctx, tx_msg, ELE_PING_REQ_SZ,
+			       rx_msg, ELE_PING_RSP_SZ);
 	if (ret < 0)
 		return ret;
 
@@ -154,7 +154,7 @@ int ele_service_swap(struct se_if_priv *priv,
 	if (!tx_msg->data[4])
 		return -EINVAL;
 
-	ret = ele_msg_send_rcv(priv, tx_msg, ELE_SERVICE_SWAP_REQ_MSG_SZ,
+	ret = ele_msg_send_rcv(priv->priv_dev_ctx, tx_msg, ELE_SERVICE_SWAP_REQ_MSG_SZ,
 			       rx_msg, ELE_SERVICE_SWAP_RSP_MSG_SZ);
 	if (ret < 0)
 		return ret;
@@ -199,7 +199,7 @@ int ele_fw_authenticate(struct se_if_priv *priv, phys_addr_t contnr_addr,
 	tx_msg->data[1] = upper_32_bits(contnr_addr);
 	tx_msg->data[2] = img_addr;
 
-	ret = ele_msg_send_rcv(priv, tx_msg, ELE_FW_AUTH_REQ_SZ, rx_msg,
+	ret = ele_msg_send_rcv(priv->priv_dev_ctx, tx_msg, ELE_FW_AUTH_REQ_SZ, rx_msg,
 			       ELE_FW_AUTH_RSP_MSG_SZ);
 	if (ret < 0)
 		return ret;
@@ -239,7 +239,7 @@ int ele_debug_dump(struct se_if_priv *priv)
 	do {
 		memset(rx_msg, 0x0, ELE_DEBUG_DUMP_RSP_SZ);
 
-		ret = ele_msg_send_rcv(priv, tx_msg, ELE_DEBUG_DUMP_REQ_SZ,
+		ret = ele_msg_send_rcv(priv->priv_dev_ctx, tx_msg, ELE_DEBUG_DUMP_REQ_SZ,
 				       rx_msg, ELE_DEBUG_DUMP_RSP_SZ);
 		if (ret < 0)
 			return ret;
diff --git a/drivers/firmware/imx/ele_common.c b/drivers/firmware/imx/ele_common.c
index a7150ff8e3b9..fcd0f561d72d 100644
--- a/drivers/firmware/imx/ele_common.c
+++ b/drivers/firmware/imx/ele_common.c
@@ -42,7 +42,7 @@ u32 se_get_msg_chksum(u32 *msg, u32 msg_len)
 	return chksum;
 }
 
-int ele_msg_rcv(struct se_if_priv *priv, struct se_clbk_handle *se_clbk_hdl)
+int ele_msg_rcv(struct se_if_device_ctx *dev_ctx, struct se_clbk_handle *se_clbk_hdl)
 {
 	unsigned long timeout;
 	int ret;
@@ -52,8 +52,8 @@ int ele_msg_rcv(struct se_if_priv *priv, struct se_clbk_handle *se_clbk_hdl)
 
 		ret = wait_for_completion_interruptible_timeout(&se_clbk_hdl->done, timeout);
 		if (ret == -ERESTARTSYS) {
-			if (priv->waiting_rsp_clbk_hdl.rx_msg) {
-				priv->waiting_rsp_clbk_hdl.signal_rcvd = true;
+			if (dev_ctx->priv->waiting_rsp_clbk_hdl.dev_ctx) {
+				dev_ctx->priv->waiting_rsp_clbk_hdl.signal_rcvd = true;
 				continue;
 			}
 			ret = -EINTR;
@@ -66,7 +66,7 @@ int ele_msg_rcv(struct se_if_priv *priv, struct se_clbk_handle *se_clbk_hdl)
 	return ret;
 }
 
-int ele_msg_send(struct se_if_priv *priv,
+int ele_msg_send(struct se_if_device_ctx *dev_ctx,
 		 void *tx_msg,
 		 int tx_msg_sz)
 {
@@ -78,15 +78,16 @@ int ele_msg_send(struct se_if_priv *priv,
 	 * carried in the message.
 	 */
 	if (header->size << 2 != tx_msg_sz) {
-		dev_err(priv->dev,
-			"User buf hdr: 0x%x, sz mismatced with input-sz (%d != %d).",
-			*(u32 *)header, header->size << 2, tx_msg_sz);
+		dev_err(dev_ctx->priv->dev,
+			"%s: User buf hdr: 0x%x, sz mismatced with input-sz (%d != %d).",
+			dev_ctx->devname, *(u32 *)header, header->size << 2, tx_msg_sz);
 		return -EINVAL;
 	}
 
-	err = mbox_send_message(priv->tx_chan, tx_msg);
+	err = mbox_send_message(dev_ctx->priv->tx_chan, tx_msg);
 	if (err < 0) {
-		dev_err(priv->dev, "Error: mbox_send_message failure.\n");
+		dev_err(dev_ctx->priv->dev,
+			"%s: Error: mbox_send_message failure.", dev_ctx->devname);
 		return err;
 	}
 
@@ -94,27 +95,31 @@ int ele_msg_send(struct se_if_priv *priv,
 }
 
 /* API used for send/receive blocking call. */
-int ele_msg_send_rcv(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz,
-		     void *rx_msg, int exp_rx_msg_sz)
+int ele_msg_send_rcv(struct se_if_device_ctx *dev_ctx, void *tx_msg,
+		     int tx_msg_sz, void *rx_msg, int exp_rx_msg_sz)
 {
+	struct se_if_priv *priv = dev_ctx->priv;
 	int err;
 
 	guard(mutex)(&priv->se_if_cmd_lock);
 
+	priv->waiting_rsp_clbk_hdl.dev_ctx = dev_ctx;
 	priv->waiting_rsp_clbk_hdl.rx_msg_sz = exp_rx_msg_sz;
 	priv->waiting_rsp_clbk_hdl.rx_msg = rx_msg;
 
-	err = ele_msg_send(priv, tx_msg, tx_msg_sz);
+	err = ele_msg_send(dev_ctx, tx_msg, tx_msg_sz);
 	if (err < 0)
 		return err;
 
-	err = ele_msg_rcv(priv, &priv->waiting_rsp_clbk_hdl);
+	err = ele_msg_rcv(dev_ctx, &priv->waiting_rsp_clbk_hdl);
 
 	if (priv->waiting_rsp_clbk_hdl.signal_rcvd) {
 		err = -EINTR;
 		priv->waiting_rsp_clbk_hdl.signal_rcvd = false;
-		dev_err(priv->dev, "Err[0x%x]:Interrupted by signal.\n", err);
+		dev_err(priv->dev, "%s: Err[0x%x]:Interrupted by signal.",
+			dev_ctx->devname, err);
 	}
+	priv->waiting_rsp_clbk_hdl.dev_ctx = NULL;
 
 	return err;
 }
@@ -159,8 +164,8 @@ void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg)
 	/* Incoming command: wake up the receiver if any. */
 	if (header->tag == priv->if_defs->cmd_tag) {
 		se_clbk_hdl = &priv->cmd_receiver_clbk_hdl;
-		dev_dbg(dev, "Selecting cmd receiver for mesg header:0x%x.",
-			*(u32 *)header);
+		dev_dbg(dev, "Selecting cmd receiver:%s for mesg header:0x%x.",
+			se_clbk_hdl->dev_ctx->devname,  *(u32 *)header);
 
 		/*
 		 * Pre-allocated buffer of MAX_NVM_MSG_LEN
@@ -169,8 +174,9 @@ void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg)
 		 */
 		if (rx_msg_sz > MAX_NVM_MSG_LEN) {
 			dev_err(dev,
-				"CMD-RCVER NVM: hdr(0x%x) with different sz(%d != %d).\n",
-				*(u32 *)header, rx_msg_sz, se_clbk_hdl->rx_msg_sz);
+				"%s: CMD-RCVER NVM: hdr(0x%x) with different sz(%d != %d).\n",
+				se_clbk_hdl->dev_ctx->devname, *(u32 *)header,
+				rx_msg_sz, se_clbk_hdl->rx_msg_sz);
 
 			se_clbk_hdl->rx_msg_sz = MAX_NVM_MSG_LEN;
 		}
@@ -178,14 +184,15 @@ void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg)
 
 	} else if (header->tag == priv->if_defs->rsp_tag) {
 		se_clbk_hdl = &priv->waiting_rsp_clbk_hdl;
-		dev_dbg(dev, "Selecting resp waiter for mesg header:0x%x.",
-			*(u32 *)header);
+		dev_dbg(dev, "Selecting resp waiter:%s for mesg header:0x%x.",
+			se_clbk_hdl->dev_ctx->devname, *(u32 *)header);
 
 		if (rx_msg_sz != se_clbk_hdl->rx_msg_sz &&
 		    check_hdr_exception_for_sz(priv, header)) {
 			dev_err(dev,
-				"Rsp to CMD: hdr(0x%x) with different sz(%d != %d).\n",
-				*(u32 *)header, rx_msg_sz, se_clbk_hdl->rx_msg_sz);
+				"%s: Rsp to CMD: hdr(0x%x) with different sz(%d != %d).\n",
+				se_clbk_hdl->dev_ctx->devname, *(u32 *)header,
+				rx_msg_sz, se_clbk_hdl->rx_msg_sz);
 
 			se_clbk_hdl->rx_msg_sz = min(rx_msg_sz, se_clbk_hdl->rx_msg_sz);
 		}
diff --git a/drivers/firmware/imx/ele_common.h b/drivers/firmware/imx/ele_common.h
index 96e987ef6f88..5bac14439d7d 100644
--- a/drivers/firmware/imx/ele_common.h
+++ b/drivers/firmware/imx/ele_common.h
@@ -14,12 +14,12 @@
 
 u32 se_get_msg_chksum(u32 *msg, u32 msg_len);
 
-int ele_msg_rcv(struct se_if_priv *priv, struct se_clbk_handle *se_clbk_hdl);
+int ele_msg_rcv(struct se_if_device_ctx *dev_ctx, struct se_clbk_handle *se_clbk_hdl);
 
-int ele_msg_send(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz);
+int ele_msg_send(struct se_if_device_ctx *dev_ctx, void *tx_msg, int tx_msg_sz);
 
-int ele_msg_send_rcv(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz,
-		     void *rx_msg, int exp_rx_msg_sz);
+int ele_msg_send_rcv(struct se_if_device_ctx *dev_ctx, void *tx_msg,
+		     int tx_msg_sz, void *rx_msg, int exp_rx_msg_sz);
 
 void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg);
 
diff --git a/drivers/firmware/imx/se_ctrl.c b/drivers/firmware/imx/se_ctrl.c
index 1c91b4698465..63562a4d9a3e 100644
--- a/drivers/firmware/imx/se_ctrl.c
+++ b/drivers/firmware/imx/se_ctrl.c
@@ -203,6 +203,29 @@ static int get_se_soc_info(struct se_if_priv *priv, const struct se_soc_info *se
 	return 0;
 }
 
+static int init_misc_device_context(struct se_if_priv *priv, int ch_id,
+				    struct se_if_device_ctx **new_dev_ctx)
+{
+	struct se_if_device_ctx *dev_ctx;
+	int ret = 0;
+
+	dev_ctx = devm_kzalloc(priv->dev, sizeof(*dev_ctx), GFP_KERNEL);
+
+	if (!dev_ctx)
+		return -ENOMEM;
+
+	dev_ctx->devname = devm_kasprintf(priv->dev, GFP_KERNEL, "%s0_ch%d",
+					  get_se_if_name(priv->if_defs->se_if_type),
+					  ch_id);
+	if (!dev_ctx->devname)
+		return -ENOMEM;
+
+	dev_ctx->priv = priv;
+	*new_dev_ctx = dev_ctx;
+
+	return ret;
+}
+
 /* interface for managed res to free a mailbox channel */
 static void if_mbox_free_channel(void *mbox_chan)
 {
@@ -325,6 +348,12 @@ static int se_if_probe(struct platform_device *pdev)
 					    "Failed to init reserved memory region.");
 	}
 
+	ret = init_misc_device_context(priv, 0, &priv->priv_dev_ctx);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed[0x%x] to create device contexts.",
+				     ret);
+
 	if (if_node->if_defs.se_if_type == SE_TYPE_ID_HSM) {
 		ret = get_se_soc_info(priv, se_info);
 		if (ret)
diff --git a/drivers/firmware/imx/se_ctrl.h b/drivers/firmware/imx/se_ctrl.h
index b15c4022a46c..b5e7705e2f26 100644
--- a/drivers/firmware/imx/se_ctrl.h
+++ b/drivers/firmware/imx/se_ctrl.h
@@ -19,6 +19,7 @@
 #define MESSAGING_VERSION_7		0x7
 
 struct se_clbk_handle {
+	struct se_if_device_ctx *dev_ctx;
 	struct completion done;
 	bool signal_rcvd;
 	u32 rx_msg_sz;
@@ -36,6 +37,12 @@ struct se_imem_buf {
 	u32 state;
 };
 
+/* Private struct for each char device instance. */
+struct se_if_device_ctx {
+	struct se_if_priv *priv;
+	const char *devname;
+};
+
 /* Header of the messages exchange with the EdgeLock Enclave */
 struct se_msg_hdr {
 	u8 ver;
@@ -80,6 +87,8 @@ struct se_if_priv {
 
 	struct gen_pool *mem_pool;
 	const struct se_if_defines *if_defs;
+
+	struct se_if_device_ctx *priv_dev_ctx;
 };
 
 char *get_se_if_name(u8 se_if_id);

-- 
2.43.0



From pankaj.gupta at nxp.com  Thu Dec 18 21:20:43 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Fri, 19 Dec 2025 10:50:43 +0530
Subject: [PATCH v23 5/7] firmware: drivers: imx: adds miscdev
In-Reply-To: <20251219-imx-se-if-v23-0-5c6773d00318@nxp.com>
References: <20251219-imx-se-if-v23-0-5c6773d00318@nxp.com>
Message-ID: <20251219-imx-se-if-v23-5-5c6773d00318@nxp.com>

Adds the driver for communication interface to secure-enclave, that
enables exchanging messages with NXP secure enclave HW IP(s)
like EdgeLock Enclave, from:
- User-Space Applications via character driver.

ABI documentation for the NXP secure-enclave driver.

User-space library using this driver:
- i.MX Secure Enclave library:
  -- URL: https://github.com/nxp-imx/imx-secure-enclave.git,
- i.MX Secure Middle-Ware:
  -- URL: https://github.com/nxp-imx/imx-smw.git

Following checks are performed on the incoming msg-header,
to block exchanging invalid arbitrary commands:
- maximum allowed words,
- check if command-tag & response-tag are valid
- version,
- command id validation check, to allow limited base-line API(s)
  and restrict following:
  - exchanging power management commands.
  - reset requests.
  - BBSM configuration requests.
  - re-initializing the FW.
  - RNG init
  - CAAM resource release management
  - SE's internal memory management.
from user-space.

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
Changes from v22 to v23
- removed un-neccessary 'kfree' from the func se_ioctl_cmd_snd_rcv_rsp_handler().
---
 Documentation/ABI/testing/se-cdev   |  43 +++
 drivers/firmware/imx/ele_base_msg.c |  28 ++
 drivers/firmware/imx/ele_base_msg.h |  20 +
 drivers/firmware/imx/ele_common.c   |  37 +-
 drivers/firmware/imx/ele_common.h   |   6 +
 drivers/firmware/imx/se_ctrl.c      | 741 +++++++++++++++++++++++++++++++++++-
 drivers/firmware/imx/se_ctrl.h      |  33 ++
 include/uapi/linux/se_ioctl.h       |  97 +++++
 8 files changed, 993 insertions(+), 12 deletions(-)

diff --git a/Documentation/ABI/testing/se-cdev b/Documentation/ABI/testing/se-cdev
new file mode 100644
index 000000000000..dad39ffd245a
--- /dev/null
+++ b/Documentation/ABI/testing/se-cdev
@@ -0,0 +1,43 @@
+What:		/dev/<se>_mu[0-9]+_ch[0-9]+
+Date:		Mar 2025
+KernelVersion:	6.8
+Contact:	linux-imx at nxp.com, pankaj.gupta at nxp.com
+Description:
+		NXP offers multiple hardware IP(s) for secure enclaves like EdgeLock-
+		Enclave(ELE), SECO. The character device file descriptors
+		/dev/<se>_mu*_ch* are the interface between userspace NXP's secure-
+		enclave shared library and the kernel driver.
+
+		The ioctl(2)-based ABI is defined and documented in
+		[include]<linux/firmware/imx/ele_mu_ioctl.h>.
+		ioctl(s) are used primarily for:
+			- shared memory management
+			- allocation of I/O buffers
+			- getting mu info
+			- setting a dev-ctx as receiver to receive all the commands from FW
+			- getting SoC info
+			- send command and receive command response
+
+		The following file operations are supported:
+
+		open(2)
+		  Currently the only useful flags are O_RDWR.
+
+		read(2)
+		  Every read() from the opened character device context is waiting on
+		  wait_event_interruptible, that gets set by the registered mailbox callback
+		  function, indicating a message received from the firmware on message-
+		  unit.
+
+		write(2)
+		  Every write() to the opened character device context needs to acquire
+		  mailbox_lock before sending message on to the message unit.
+
+		close(2)
+		  Stops and frees up the I/O contexts that were associated
+		  with the file descriptor.
+
+Users:		https://github.com/nxp-imx/imx-secure-enclave.git,
+		https://github.com/nxp-imx/imx-smw.git
+		crypto/skcipher,
+		drivers/nvmem/imx-ocotp-ele.c
diff --git a/drivers/firmware/imx/ele_base_msg.c b/drivers/firmware/imx/ele_base_msg.c
index 475ba98be199..23f68076b85c 100644
--- a/drivers/firmware/imx/ele_base_msg.c
+++ b/drivers/firmware/imx/ele_base_msg.c
@@ -15,6 +15,34 @@
 
 #define FW_DBG_DUMP_FIXED_STR		"ELE"
 
+int ele_uapi_allowed_base_cmd(struct se_if_priv *priv,
+			      struct se_msg_hdr *header)
+{
+	switch (header->command) {
+	case ELE_PING_REQ: return 0;
+	case ELE_DEBUG_DUMP_REQ: return 0;
+	case ELE_OEM_AUTH_CONTAINER_REQ: return 0;
+	case ELE_OEM_VERIFY_IMAGE_REQ: return 0;
+	case ELE_OEM_REL_CONTAINER_REQ: return 0;
+	case ELE_FW_LIFE_CYCLE_REQ: return 0;
+	case ELE_READ_FUSE_REQ: return 0;
+	case ELE_GET_FW_VERS_REQ: return 0;
+	case ELE_RETURN_LIFE_CYCLE_REQ: return 0;
+	case ELE_GET_EVENT_REQ: return 0;
+	case ELE_COMMIT_REQ: return 0;
+	case ELE_GEN_KEY_BLOB_REQ: return 0;
+	case ELE_GET_FW_STATUS_REQ: return 0;
+	case ELE_XIP_DECRYPT_REQ: return 0;
+	case ELE_WRITE_FUSE: return 0;
+	case ELE_GET_INFO_REQ: return 0;
+	case ELE_DEV_ATTEST_REQ: return 0;
+	case ELE_WRITE_SHADOW_FUSE_REQ: return 0;
+	case ELE_READ_SHADOW_FUSE_REQ: return 0;
+	default:
+		return -EACCES;
+	}
+}
+
 int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info)
 {
 	dma_addr_t get_info_addr = 0;
diff --git a/drivers/firmware/imx/ele_base_msg.h b/drivers/firmware/imx/ele_base_msg.h
index 8e5b015e99a2..f8fabac331fd 100644
--- a/drivers/firmware/imx/ele_base_msg.h
+++ b/drivers/firmware/imx/ele_base_msg.h
@@ -15,6 +15,24 @@
 
 #define ELE_NONE_VAL			0x0
 
+
+#define ELE_OEM_AUTH_CONTAINER_REQ	0x87
+#define ELE_OEM_VERIFY_IMAGE_REQ	0x88
+#define ELE_OEM_REL_CONTAINER_REQ	0x89
+#define ELE_FW_LIFE_CYCLE_REQ		0x95
+#define ELE_READ_FUSE_REQ		0x97
+#define ELE_GET_FW_VERS_REQ		0x9d
+#define ELE_RETURN_LIFE_CYCLE_REQ	0xa0
+#define ELE_GET_EVENT_REQ		0xa2
+#define ELE_COMMIT_REQ			0xa8
+#define ELE_GEN_KEY_BLOB_REQ		0xaf
+#define ELE_GET_FW_STATUS_REQ		0xc5
+#define ELE_XIP_DECRYPT_REQ		0xc6
+#define ELE_WRITE_FUSE                  0xd6
+#define ELE_DEV_ATTEST_REQ              0xdb
+#define ELE_WRITE_SHADOW_FUSE_REQ       0xf2
+#define ELE_READ_SHADOW_FUSE_REQ        0xf3
+
 #define ELE_GET_INFO_REQ		0xda
 #define ELE_GET_INFO_REQ_MSG_SZ		0x10
 #define ELE_GET_INFO_RSP_MSG_SZ		0x08
@@ -92,4 +110,6 @@ int ele_service_swap(struct se_if_priv *priv, phys_addr_t addr,
 int ele_fw_authenticate(struct se_if_priv *priv, phys_addr_t contnr_addr,
 			phys_addr_t img_addr);
 int ele_debug_dump(struct se_if_priv *priv);
+int ele_uapi_allowed_base_cmd(struct se_if_priv *priv,
+			      struct se_msg_hdr *header);
 #endif
diff --git a/drivers/firmware/imx/ele_common.c b/drivers/firmware/imx/ele_common.c
index fcd0f561d72d..78440f62bf92 100644
--- a/drivers/firmware/imx/ele_common.c
+++ b/drivers/firmware/imx/ele_common.c
@@ -6,6 +6,23 @@
 #include "ele_base_msg.h"
 #include "ele_common.h"
 
+int se_chk_tx_msg_hdr(struct se_if_priv *priv, struct se_msg_hdr *header)
+{
+	if (!header->size || header->size > MAX_WORD_SIZE)
+		return -EINVAL;
+
+	if (header->tag != priv->if_defs->cmd_tag &&
+	    header->tag != priv->if_defs->rsp_tag)
+		return -EINVAL;
+
+	if (header->ver == priv->if_defs->base_api_ver)
+		return ele_uapi_allowed_base_cmd(priv, header);
+	else if (header->ver == priv->if_defs->fw_api_ver)
+		return 0;
+
+	return -EINVAL;
+}
+
 /*
  * se_get_msg_chksum() - to calculate checksum word by word.
  *
@@ -42,15 +59,22 @@ u32 se_get_msg_chksum(u32 *msg, u32 msg_len)
 	return chksum;
 }
 
+void set_se_rcv_msg_timeout(struct se_if_priv *priv, u32 timeout_ms)
+{
+	priv->se_rcv_msg_timeout_ms = timeout_ms;
+}
+
 int ele_msg_rcv(struct se_if_device_ctx *dev_ctx, struct se_clbk_handle *se_clbk_hdl)
 {
-	unsigned long timeout;
+	unsigned long timeout_ms;
 	int ret;
 
 	do {
-		timeout = MAX_SCHEDULE_TIMEOUT;
+		timeout_ms = MAX_SCHEDULE_TIMEOUT;
+		if (dev_ctx->priv->cmd_receiver_clbk_hdl.dev_ctx != dev_ctx)
+			timeout_ms = msecs_to_jiffies(dev_ctx->priv->se_rcv_msg_timeout_ms);
 
-		ret = wait_for_completion_interruptible_timeout(&se_clbk_hdl->done, timeout);
+		ret = wait_for_completion_interruptible_timeout(&se_clbk_hdl->done, timeout_ms);
 		if (ret == -ERESTARTSYS) {
 			if (dev_ctx->priv->waiting_rsp_clbk_hdl.dev_ctx) {
 				dev_ctx->priv->waiting_rsp_clbk_hdl.signal_rcvd = true;
@@ -59,6 +83,13 @@ int ele_msg_rcv(struct se_if_device_ctx *dev_ctx, struct se_clbk_handle *se_clbk
 			ret = -EINTR;
 			break;
 		}
+		if (ret == 0) {
+			ret = -ETIMEDOUT;
+			dev_err(dev_ctx->priv->dev,
+				"Fatal Error: SE interface: %s0, hangs indefinitely.\n",
+				get_se_if_name(dev_ctx->priv->if_defs->se_if_type));
+			break;
+		}
 		ret = se_clbk_hdl->rx_msg_sz;
 		break;
 	} while (ret < 0);
diff --git a/drivers/firmware/imx/ele_common.h b/drivers/firmware/imx/ele_common.h
index 5bac14439d7d..bdc13d1b715d 100644
--- a/drivers/firmware/imx/ele_common.h
+++ b/drivers/firmware/imx/ele_common.h
@@ -12,6 +12,11 @@
 
 #define IMX_ELE_FW_DIR                 "imx/ele/"
 
+#define MAX_WORD_SIZE			0x20
+#define SE_RCV_MSG_DEFAULT_TIMEOUT	5000
+#define SE_RCV_MSG_LONG_TIMEOUT		5000000
+
+void set_se_rcv_msg_timeout(struct se_if_priv *priv, u32 val);
 u32 se_get_msg_chksum(u32 *msg, u32 msg_len);
 
 int ele_msg_rcv(struct se_if_device_ctx *dev_ctx, struct se_clbk_handle *se_clbk_hdl);
@@ -42,4 +47,5 @@ int se_save_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem);
 
 int se_restore_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem);
 
+int se_chk_tx_msg_hdr(struct se_if_priv *priv, struct se_msg_hdr *header);
 #endif /*__ELE_COMMON_H__ */
diff --git a/drivers/firmware/imx/se_ctrl.c b/drivers/firmware/imx/se_ctrl.c
index 63562a4d9a3e..b00abd0ce966 100644
--- a/drivers/firmware/imx/se_ctrl.c
+++ b/drivers/firmware/imx/se_ctrl.c
@@ -3,6 +3,7 @@
  * Copyright 2025 NXP
  */
 
+#include <linux/cleanup.h>
 #include <linux/completion.h>
 #include <linux/delay.h>
 #include <linux/dev_printk.h>
@@ -23,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/sys_soc.h>
+#include <uapi/linux/se_ioctl.h>
 
 #include "ele_base_msg.h"
 #include "ele_common.h"
@@ -32,12 +34,6 @@
 #define MBOX_TX_NAME			"tx"
 #define MBOX_RX_NAME			"rx"
 
-#define SE_TYPE_STR_DBG			"dbg"
-#define SE_TYPE_STR_HSM			"hsm"
-
-#define SE_TYPE_ID_DBG			0x1
-#define SE_TYPE_ID_HSM			0x2
-
 struct se_fw_img_name {
 	const u8 *prim_fw_nm_in_rfs;
 	const u8 *seco_fw_nm_in_rfs;
@@ -130,6 +126,13 @@ char *get_se_if_name(u8 se_if_id)
 	return NULL;
 }
 
+static u32 get_se_soc_id(struct se_if_priv *priv)
+{
+	const struct se_soc_info *se_info = device_get_match_data(priv->dev);
+
+	return se_info->soc_id;
+}
+
 static struct se_fw_load_info *get_load_fw_instance(struct se_if_priv *priv)
 {
 	return &var_se_info.load_fw;
@@ -203,8 +206,213 @@ static int get_se_soc_info(struct se_if_priv *priv, const struct se_soc_info *se
 	return 0;
 }
 
+static int load_firmware(struct se_if_priv *priv, const u8 *se_img_file_to_load)
+{
+	const struct firmware *fw = NULL;
+	phys_addr_t se_fw_phyaddr;
+	u8 *se_fw_buf;
+	int ret;
+
+	if (!se_img_file_to_load) {
+		dev_err(priv->dev, "FW image is not provided.");
+		return -EINVAL;
+	}
+	ret = request_firmware(&fw, se_img_file_to_load, priv->dev);
+	if (ret)
+		return ret;
+
+	dev_info(priv->dev, "loading firmware %s.", se_img_file_to_load);
+
+	/* allocate buffer to store the SE FW */
+	se_fw_buf = dma_alloc_coherent(priv->dev, fw->size, &se_fw_phyaddr, GFP_KERNEL);
+	if (!se_fw_buf) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	memcpy(se_fw_buf, fw->data, fw->size);
+	ret = ele_fw_authenticate(priv, se_fw_phyaddr, se_fw_phyaddr);
+	if (ret < 0) {
+		dev_err(priv->dev,
+			"Error %pe: Authenticate & load SE firmware %s.",
+			ERR_PTR(ret), se_img_file_to_load);
+		ret = -EPERM;
+	}
+	dma_free_coherent(priv->dev, fw->size, se_fw_buf, se_fw_phyaddr);
+exit:
+	release_firmware(fw);
+
+	return ret;
+}
+
+static int se_load_firmware(struct se_if_priv *priv)
+{
+	struct se_fw_load_info *load_fw = get_load_fw_instance(priv);
+	int ret = 0;
+
+	if (!load_fw->is_fw_tobe_loaded)
+		return 0;
+
+	if (load_fw->imem.state == ELE_IMEM_STATE_BAD) {
+		ret = load_firmware(priv, load_fw->se_fw_img_nm->prim_fw_nm_in_rfs);
+		if (ret) {
+			dev_err(priv->dev, "Failed to load boot firmware.");
+			return -EPERM;
+		}
+	}
+
+	ret = load_firmware(priv, load_fw->se_fw_img_nm->seco_fw_nm_in_rfs);
+	if (ret) {
+		dev_err(priv->dev, "Failed to load runtime firmware.");
+		return -EPERM;
+	}
+
+	load_fw->is_fw_tobe_loaded = false;
+
+	return ret;
+}
+
+static int init_se_shared_mem(struct se_if_device_ctx *dev_ctx)
+{
+	struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
+	struct se_if_priv *priv = dev_ctx->priv;
+
+	INIT_LIST_HEAD(&se_shared_mem_mgmt->pending_out);
+	INIT_LIST_HEAD(&se_shared_mem_mgmt->pending_in);
+
+	/*
+	 * Allocate some memory for data exchanges with S40x.
+	 * This will be used for data not requiring secure memory.
+	 */
+	se_shared_mem_mgmt->non_secure_mem.ptr =
+			dma_alloc_coherent(priv->dev, MAX_DATA_SIZE_PER_USER,
+					   &se_shared_mem_mgmt->non_secure_mem.dma_addr,
+					   GFP_KERNEL);
+	if (!se_shared_mem_mgmt->non_secure_mem.ptr)
+		return -ENOMEM;
+
+	se_shared_mem_mgmt->non_secure_mem.size = MAX_DATA_SIZE_PER_USER;
+	se_shared_mem_mgmt->non_secure_mem.pos = 0;
+
+	return 0;
+}
+
+static void cleanup_se_shared_mem(struct se_if_device_ctx *dev_ctx)
+{
+	struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
+	struct se_if_priv *priv = dev_ctx->priv;
+
+	/* Free non-secure shared buffer. */
+	dma_free_coherent(priv->dev, MAX_DATA_SIZE_PER_USER,
+			  se_shared_mem_mgmt->non_secure_mem.ptr,
+			  se_shared_mem_mgmt->non_secure_mem.dma_addr);
+
+	se_shared_mem_mgmt->non_secure_mem.ptr = NULL;
+	se_shared_mem_mgmt->non_secure_mem.dma_addr = 0;
+	se_shared_mem_mgmt->non_secure_mem.size = 0;
+	se_shared_mem_mgmt->non_secure_mem.pos = 0;
+}
+
+/* Need to copy the output data to user-device context.
+ */
+static int se_dev_ctx_cpy_out_data(struct se_if_device_ctx *dev_ctx)
+{
+	struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
+	struct se_if_priv *priv = dev_ctx->priv;
+	struct se_buf_desc *b_desc, *temp;
+	bool do_cpy = true;
+
+	list_for_each_entry_safe(b_desc, temp, &se_shared_mem_mgmt->pending_out, link) {
+		if (b_desc->usr_buf_ptr && b_desc->shared_buf_ptr && do_cpy) {
+			dev_dbg(priv->dev, "Copying output data to user.");
+			if (do_cpy && copy_to_user(b_desc->usr_buf_ptr,
+						   b_desc->shared_buf_ptr,
+						   b_desc->size)) {
+				dev_err(priv->dev, "Failure copying output data to user.");
+				do_cpy = false;
+			}
+		}
+
+		if (b_desc->shared_buf_ptr)
+			memset(b_desc->shared_buf_ptr, 0, b_desc->size);
+
+		list_del(&b_desc->link);
+		kfree(b_desc);
+	}
+
+	return do_cpy ? 0 : -EFAULT;
+}
+
+/*
+ * Clean the used Shared Memory space,
+ * whether its Input Data copied from user buffers, or
+ * Data received from FW.
+ */
+static void se_dev_ctx_shared_mem_cleanup(struct se_if_device_ctx *dev_ctx)
+{
+	struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
+	struct list_head *pending_lists[] = {&se_shared_mem_mgmt->pending_in,
+						&se_shared_mem_mgmt->pending_out};
+	struct se_buf_desc *b_desc, *temp;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pending_lists); i++) {
+		list_for_each_entry_safe(b_desc, temp, pending_lists[i], link) {
+			if (b_desc->shared_buf_ptr)
+				memset(b_desc->shared_buf_ptr, 0, b_desc->size);
+
+			list_del(&b_desc->link);
+			kfree(b_desc);
+		}
+	}
+	se_shared_mem_mgmt->non_secure_mem.pos = 0;
+}
+
+static int add_b_desc_to_pending_list(void *shared_ptr_with_pos,
+				      struct se_ioctl_setup_iobuf *io,
+				      struct se_if_device_ctx *dev_ctx)
+{
+	struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
+	struct se_buf_desc *b_desc;
+
+	b_desc = kzalloc(sizeof(*b_desc), GFP_KERNEL);
+	if (!b_desc)
+		return -ENOMEM;
+
+	b_desc->shared_buf_ptr = shared_ptr_with_pos;
+	b_desc->usr_buf_ptr = io->user_buf;
+	b_desc->size = io->length;
+
+	if (io->flags & SE_IO_BUF_FLAGS_IS_INPUT) {
+		/*
+		 * buffer is input:
+		 * add an entry in the "pending input buffers" list so
+		 * that copied data can be cleaned from shared memory
+		 * later.
+		 */
+		list_add_tail(&b_desc->link, &se_shared_mem_mgmt->pending_in);
+	} else {
+		/*
+		 * buffer is output:
+		 * add an entry in the "pending out buffers" list so data
+		 * can be copied to user space when receiving Secure-Enclave
+		 * response.
+		 */
+		list_add_tail(&b_desc->link, &se_shared_mem_mgmt->pending_out);
+	}
+
+	return 0;
+}
+
+/* interface for managed res to unregister a character device */
+static void if_misc_deregister(void *miscdevice)
+{
+	misc_deregister(miscdevice);
+}
+
 static int init_misc_device_context(struct se_if_priv *priv, int ch_id,
-				    struct se_if_device_ctx **new_dev_ctx)
+				    struct se_if_device_ctx **new_dev_ctx,
+				    const struct file_operations *se_if_fops)
 {
 	struct se_if_device_ctx *dev_ctx;
 	int ret = 0;
@@ -220,12 +428,516 @@ static int init_misc_device_context(struct se_if_priv *priv, int ch_id,
 	if (!dev_ctx->devname)
 		return -ENOMEM;
 
+	mutex_init(&dev_ctx->fops_lock);
+
+	dev_ctx->priv = priv;
+	*new_dev_ctx = dev_ctx;
+
+	dev_ctx->miscdev = devm_kzalloc(priv->dev, sizeof(*dev_ctx->miscdev), GFP_KERNEL);
+	if (!dev_ctx->miscdev) {
+		*new_dev_ctx = NULL;
+		return -ENOMEM;
+	}
+
+	dev_ctx->miscdev->name = dev_ctx->devname;
+	dev_ctx->miscdev->minor = MISC_DYNAMIC_MINOR;
+	dev_ctx->miscdev->fops = se_if_fops;
+	dev_ctx->miscdev->parent = priv->dev;
+	ret = misc_register(dev_ctx->miscdev);
+	if (ret)
+		return dev_err_probe(priv->dev, ret, "Failed to register misc device.");
+
+	ret = devm_add_action_or_reset(priv->dev, if_misc_deregister, dev_ctx->miscdev);
+	if (ret)
+		return dev_err_probe(priv->dev, ret,
+				     "Failed to add action to the misc-dev.");
+	return ret;
+}
+
+static int init_device_context(struct se_if_priv *priv, int ch_id,
+			       struct se_if_device_ctx **new_dev_ctx)
+{
+	struct se_if_device_ctx *dev_ctx;
+	int ret = 0;
+
+	dev_ctx = kzalloc(sizeof(*dev_ctx), GFP_KERNEL);
+
+	if (!dev_ctx)
+		return -ENOMEM;
+
+	dev_ctx->devname = kasprintf(GFP_KERNEL, "%s0_ch%d",
+				     get_se_if_name(priv->if_defs->se_if_type),
+				     ch_id);
+	if (!dev_ctx->devname) {
+		kfree(dev_ctx);
+		return -ENOMEM;
+	}
+
+	mutex_init(&dev_ctx->fops_lock);
 	dev_ctx->priv = priv;
 	*new_dev_ctx = dev_ctx;
 
+	list_add_tail(&dev_ctx->link, &priv->dev_ctx_list);
+	priv->active_devctx_count++;
+
+	ret = init_se_shared_mem(dev_ctx);
+	if (ret < 0) {
+		kfree(dev_ctx->devname);
+		kfree(dev_ctx);
+		*new_dev_ctx = NULL;
+	}
+
 	return ret;
 }
 
+static int se_ioctl_cmd_snd_rcv_rsp_handler(struct se_if_device_ctx *dev_ctx,
+					    u64 arg)
+{
+	struct se_ioctl_cmd_snd_rcv_rsp_info cmd_snd_rcv_rsp_info = {0};
+	struct se_if_priv *priv = dev_ctx->priv;
+	int err = 0;
+
+	if (copy_from_user(&cmd_snd_rcv_rsp_info, (u8 __user *)arg,
+			   sizeof(cmd_snd_rcv_rsp_info))) {
+		dev_err(priv->dev,
+			"%s: Failed to copy cmd_snd_rcv_rsp_info from user.",
+			dev_ctx->devname);
+		err = -EFAULT;
+		goto exit;
+	}
+
+	if (cmd_snd_rcv_rsp_info.tx_buf_sz < SE_MU_HDR_SZ) {
+		dev_err(priv->dev, "%s: User buffer too small(%d < %d)",
+			dev_ctx->devname, cmd_snd_rcv_rsp_info.tx_buf_sz, SE_MU_HDR_SZ);
+		err = -ENOSPC;
+		goto exit;
+	}
+
+	err = se_chk_tx_msg_hdr(priv, (struct se_msg_hdr *)cmd_snd_rcv_rsp_info.tx_buf);
+	if (err)
+		goto exit;
+
+	struct se_api_msg *rx_msg __free(kfree) =
+		kzalloc(cmd_snd_rcv_rsp_info.rx_buf_sz, GFP_KERNEL);
+	if (!rx_msg) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	struct se_api_msg *tx_msg __free(kfree) =
+		memdup_user(cmd_snd_rcv_rsp_info.tx_buf,
+			    cmd_snd_rcv_rsp_info.tx_buf_sz);
+	if (IS_ERR(tx_msg)) {
+		err = PTR_ERR(tx_msg);
+		goto exit;
+	}
+
+	if (tx_msg->header.tag != priv->if_defs->cmd_tag) {
+		err = -EINVAL;
+		goto exit;
+	}
+
+	if (tx_msg->header.ver == priv->if_defs->fw_api_ver &&
+	    get_load_fw_instance(priv)->is_fw_tobe_loaded) {
+		err = se_load_firmware(priv);
+		if (err) {
+			dev_err(priv->dev, "Could not send msg as FW is not loaded.");
+			err = -EPERM;
+			goto exit;
+		}
+	}
+	set_se_rcv_msg_timeout(priv, SE_RCV_MSG_LONG_TIMEOUT);
+
+	err = ele_msg_send_rcv(dev_ctx, tx_msg, cmd_snd_rcv_rsp_info.tx_buf_sz,
+			       rx_msg, cmd_snd_rcv_rsp_info.rx_buf_sz);
+	if (err < 0)
+		goto exit;
+
+	dev_dbg(priv->dev, "%s: %s %s.", dev_ctx->devname, __func__,
+		"message received, start transmit to user");
+
+	/* We may need to copy the output data to user before
+	 * delivering the completion message.
+	 */
+	err = se_dev_ctx_cpy_out_data(dev_ctx);
+	if (err < 0)
+		goto exit;
+
+	/* Copy data from the buffer */
+	print_hex_dump_debug("to user ", DUMP_PREFIX_OFFSET, 4, 4, rx_msg,
+			     cmd_snd_rcv_rsp_info.rx_buf_sz, false);
+
+	if (copy_to_user(cmd_snd_rcv_rsp_info.rx_buf, rx_msg,
+			 cmd_snd_rcv_rsp_info.rx_buf_sz)) {
+		dev_err(priv->dev, "%s: Failed to copy to user.", dev_ctx->devname);
+		err = -EFAULT;
+	}
+
+exit:
+
+	/* shared memory is allocated before this IOCTL */
+	se_dev_ctx_shared_mem_cleanup(dev_ctx);
+
+	if (copy_to_user((void __user *)arg, &cmd_snd_rcv_rsp_info,
+			 sizeof(cmd_snd_rcv_rsp_info))) {
+		dev_err(priv->dev, "%s: Failed to copy cmd_snd_rcv_rsp_info from user.",
+			dev_ctx->devname);
+		err = -EFAULT;
+	}
+
+	return err;
+}
+
+static int se_ioctl_get_mu_info(struct se_if_device_ctx *dev_ctx,
+				u64 arg)
+{
+	struct se_if_priv *priv = dev_ctx->priv;
+	struct se_ioctl_get_if_info if_info;
+	struct se_if_node *if_node;
+	int err = 0;
+
+	if_node = container_of(priv->if_defs, typeof(*if_node), if_defs);
+
+	if_info.se_if_id = 0;
+	if_info.interrupt_idx = 0;
+	if_info.tz = 0;
+	if_info.did = 0;
+	if_info.cmd_tag = priv->if_defs->cmd_tag;
+	if_info.rsp_tag = priv->if_defs->rsp_tag;
+	if_info.success_tag = priv->if_defs->success_tag;
+	if_info.base_api_ver = priv->if_defs->base_api_ver;
+	if_info.fw_api_ver = priv->if_defs->fw_api_ver;
+
+	dev_dbg(priv->dev, "%s: info [se_if_id: %d, irq_idx: %d, tz: 0x%x, did: 0x%x].",
+		dev_ctx->devname, if_info.se_if_id, if_info.interrupt_idx, if_info.tz,
+		if_info.did);
+
+	if (copy_to_user((u8 __user *)arg, &if_info, sizeof(if_info))) {
+		dev_err(priv->dev, "%s: Failed to copy mu info to user.",
+			dev_ctx->devname);
+		err = -EFAULT;
+	}
+
+	return err;
+}
+
+/*
+ * Copy a buffer of data to/from the user and return the address to use in
+ * messages
+ */
+static int se_ioctl_setup_iobuf_handler(struct se_if_device_ctx *dev_ctx,
+					u64 arg)
+{
+	struct se_shared_mem *shared_mem = NULL;
+	struct se_ioctl_setup_iobuf io = {0};
+	int err = 0;
+	u32 pos;
+
+	if (copy_from_user(&io, (u8 __user *)arg, sizeof(io))) {
+		dev_err(dev_ctx->priv->dev, "%s: Failed copy iobuf config from user.",
+			dev_ctx->devname);
+		return -EFAULT;
+	}
+
+	dev_dbg(dev_ctx->priv->dev, "%s: io [buf: %p(%d) flag: %x].", dev_ctx->devname,
+		io.user_buf, io.length, io.flags);
+
+	if (io.length == 0 || !io.user_buf) {
+		/*
+		 * Accept NULL pointers since some buffers are optional
+		 * in FW commands. In this case we should return 0 as
+		 * pointer to be embedded into the message.
+		 * Skip all data copy part of code below.
+		 */
+		io.ele_addr = 0;
+		goto copy;
+	}
+
+	/* No specific requirement for this buffer. */
+	shared_mem = &dev_ctx->se_shared_mem_mgmt.non_secure_mem;
+
+	/* Check there is enough space in the shared memory. */
+	dev_dbg(dev_ctx->priv->dev, "%s: req_size = %d, max_size= %d, curr_pos = %d",
+		dev_ctx->devname, round_up(io.length, 8u), shared_mem->size,
+		shared_mem->pos);
+
+	if (shared_mem->size < shared_mem->pos ||
+	    round_up(io.length, 8u) > (shared_mem->size - shared_mem->pos)) {
+		dev_err(dev_ctx->priv->dev, "%s: Not enough space in shared memory.",
+			dev_ctx->devname);
+		return -ENOMEM;
+	}
+
+	/* Allocate space in shared memory. 8 bytes aligned. */
+	pos = shared_mem->pos;
+	shared_mem->pos += round_up(io.length, 8u);
+	io.ele_addr = (u64)shared_mem->dma_addr + pos;
+
+	memset(shared_mem->ptr + pos, 0, io.length);
+	if ((io.flags & SE_IO_BUF_FLAGS_IS_INPUT) ||
+	    (io.flags & SE_IO_BUF_FLAGS_IS_IN_OUT)) {
+		/*
+		 * buffer is input:
+		 * copy data from user space to this allocated buffer.
+		 */
+		if (copy_from_user(shared_mem->ptr + pos, io.user_buf, io.length)) {
+			dev_err(dev_ctx->priv->dev,
+				"%s: Failed copy data to shared memory.",
+				dev_ctx->devname);
+			return -EFAULT;
+		}
+	}
+
+	err = add_b_desc_to_pending_list(shared_mem->ptr + pos, &io, dev_ctx);
+	if (err < 0)
+		dev_err(dev_ctx->priv->dev, "%s: Failed to allocate/link b_desc.",
+			dev_ctx->devname);
+
+copy:
+	/* Provide the EdgeLock Enclave address to user space only if success.*/
+	if (copy_to_user((u8 __user *)arg, &io, sizeof(io))) {
+		dev_err(dev_ctx->priv->dev, "%s: Failed to copy iobuff setup to user.",
+			dev_ctx->devname);
+		err = -EFAULT;
+	}
+
+	return err;
+}
+
+/* IOCTL to provide SoC information */
+static int se_ioctl_get_se_soc_info_handler(struct se_if_device_ctx *dev_ctx, u64 arg)
+{
+	struct se_ioctl_get_soc_info soc_info;
+	int err = -EINVAL;
+
+	soc_info.soc_id = get_se_soc_id(dev_ctx->priv);
+	soc_info.soc_rev = var_se_info.soc_rev;
+
+	err = copy_to_user((u8 __user *)arg, (u8 *)(&soc_info), sizeof(soc_info));
+	if (err) {
+		dev_err(dev_ctx->priv->dev, "%s: Failed to copy soc info to user.",
+			dev_ctx->devname);
+		err = -EFAULT;
+	}
+
+	return err;
+}
+
+/*
+ * File operations for user-space
+ */
+
+/* Write a message to the MU. */
+static ssize_t se_if_fops_write(struct file *fp, const char __user *buf,
+				size_t size, loff_t *ppos)
+{
+	struct se_if_device_ctx *dev_ctx = fp->private_data;
+	struct se_if_priv *priv = dev_ctx->priv;
+	int err;
+
+	dev_dbg(priv->dev, "%s: write from buf (%p)%zu, ppos=%lld.", dev_ctx->devname,
+		buf, size, ((ppos) ? *ppos : 0));
+
+	scoped_cond_guard(mutex_intr, return -EBUSY, &dev_ctx->fops_lock) {
+		if (dev_ctx != priv->cmd_receiver_clbk_hdl.dev_ctx)
+			return -EINVAL;
+
+		err = se_chk_tx_msg_hdr(priv, (struct se_msg_hdr *)buf);
+		if (err)
+			return err;
+
+		if (size < SE_MU_HDR_SZ) {
+			dev_err(priv->dev, "%s: User buffer too small(%zu < %d).",
+				dev_ctx->devname, size, SE_MU_HDR_SZ);
+			return -ENOSPC;
+		}
+
+		struct se_api_msg *tx_msg __free(kfree) = memdup_user(buf, size);
+		if (IS_ERR(tx_msg))
+			return PTR_ERR(tx_msg);
+
+		print_hex_dump_debug("from user ", DUMP_PREFIX_OFFSET, 4, 4,
+				     tx_msg, size, false);
+
+		err = ele_msg_send(dev_ctx, tx_msg, size);
+
+		return err;
+	}
+}
+
+/*
+ * Read a message from the MU.
+ * Blocking until a message is available.
+ */
+static ssize_t se_if_fops_read(struct file *fp, char __user *buf, size_t size,
+			       loff_t *ppos)
+{
+	struct se_if_device_ctx *dev_ctx = fp->private_data;
+	struct se_if_priv *priv = dev_ctx->priv;
+	int err;
+
+	dev_dbg(priv->dev, "%s: read to buf %p(%zu), ppos=%lld.", dev_ctx->devname,
+		buf, size, ((ppos) ? *ppos : 0));
+
+	scoped_cond_guard(mutex_intr, return -EBUSY, &dev_ctx->fops_lock) {
+		if (dev_ctx != priv->cmd_receiver_clbk_hdl.dev_ctx) {
+			err = -EINVAL;
+			goto exit;
+		}
+
+		err = ele_msg_rcv(dev_ctx, &priv->cmd_receiver_clbk_hdl);
+		if (err < 0) {
+			dev_err(priv->dev, "%s: Err[0x%x]:Interrupted by signal."
+				"Current active dev-ctx count = %d.",
+				dev_ctx->devname, err, dev_ctx->priv->active_devctx_count);
+			goto exit;
+		}
+
+		/* We may need to copy the output data to user before
+		 * delivering the completion message.
+		 */
+		err = se_dev_ctx_cpy_out_data(dev_ctx);
+		if (err < 0)
+			goto exit;
+
+		/* Copy data from the buffer */
+		print_hex_dump_debug("to user ", DUMP_PREFIX_OFFSET, 4, 4,
+				     priv->cmd_receiver_clbk_hdl.rx_msg,
+				     priv->cmd_receiver_clbk_hdl.rx_msg_sz,
+				     false);
+
+		if (copy_to_user(buf, priv->cmd_receiver_clbk_hdl.rx_msg,
+				 priv->cmd_receiver_clbk_hdl.rx_msg_sz)) {
+			dev_err(priv->dev, "%s: Failed to copy to user.",
+				dev_ctx->devname);
+			err = -EFAULT;
+		} else {
+			err = priv->cmd_receiver_clbk_hdl.rx_msg_sz;
+		}
+exit:
+		priv->cmd_receiver_clbk_hdl.rx_msg_sz = 0;
+
+		se_dev_ctx_shared_mem_cleanup(dev_ctx);
+
+		return err;
+	}
+}
+
+/* Open a character device. */
+static int se_if_fops_open(struct inode *nd, struct file *fp)
+{
+	struct miscdevice *miscdev = fp->private_data;
+	struct se_if_device_ctx *misc_dev_ctx;
+	struct se_if_device_ctx *dev_ctx;
+	struct se_if_priv *priv;
+	int err = 0;
+
+	priv = dev_get_drvdata(miscdev->parent);
+	misc_dev_ctx = priv->priv_dev_ctx;
+
+	scoped_cond_guard(mutex_intr, return -EBUSY, &misc_dev_ctx->fops_lock) {
+		priv->dev_ctx_mono_count++;
+		err = init_device_context(priv,
+					  priv->dev_ctx_mono_count ?
+					  priv->dev_ctx_mono_count
+					  : priv->dev_ctx_mono_count++,
+					  &dev_ctx);
+		if (err)
+			dev_err(priv->dev, "Failed[0x%x] to create dev-ctx.", err);
+		else
+			fp->private_data = dev_ctx;
+
+		return err;
+	}
+}
+
+/* Close a character device. */
+static int se_if_fops_close(struct inode *nd, struct file *fp)
+{
+	struct se_if_device_ctx *dev_ctx = fp->private_data;
+	struct se_if_priv *priv = dev_ctx->priv;
+
+	scoped_cond_guard(mutex_intr, return -EBUSY, &dev_ctx->fops_lock) {
+		/* check if this device was registered as command receiver. */
+		if (priv->cmd_receiver_clbk_hdl.dev_ctx == dev_ctx) {
+			priv->cmd_receiver_clbk_hdl.dev_ctx = NULL;
+			kfree(priv->cmd_receiver_clbk_hdl.rx_msg);
+			priv->cmd_receiver_clbk_hdl.rx_msg = NULL;
+		}
+
+		se_dev_ctx_shared_mem_cleanup(dev_ctx);
+		cleanup_se_shared_mem(dev_ctx);
+
+		priv->active_devctx_count--;
+		list_del(&dev_ctx->link);
+
+		kfree(dev_ctx->devname);
+		kfree(dev_ctx);
+	}
+
+	return 0;
+}
+
+/* IOCTL entry point of a character device */
+static long se_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
+{
+	struct se_if_device_ctx *dev_ctx = fp->private_data;
+	struct se_if_priv *priv = dev_ctx->priv;
+	long err;
+
+	/* Prevent race during change of device context */
+	scoped_cond_guard(mutex_intr, return -EBUSY, &dev_ctx->fops_lock) {
+		switch (cmd) {
+		case SE_IOCTL_ENABLE_CMD_RCV:
+			if (!priv->cmd_receiver_clbk_hdl.dev_ctx) {
+				if (!priv->cmd_receiver_clbk_hdl.rx_msg) {
+					priv->cmd_receiver_clbk_hdl.rx_msg =
+						kzalloc(MAX_NVM_MSG_LEN,
+							GFP_KERNEL);
+					if (!priv->cmd_receiver_clbk_hdl.rx_msg) {
+						err = -ENOMEM;
+						break;
+					}
+				}
+				priv->cmd_receiver_clbk_hdl.rx_msg_sz = MAX_NVM_MSG_LEN;
+				priv->cmd_receiver_clbk_hdl.dev_ctx = dev_ctx;
+				err = 0;
+			} else {
+				err = -EBUSY;
+			}
+			break;
+		case SE_IOCTL_GET_MU_INFO:
+			err = se_ioctl_get_mu_info(dev_ctx, arg);
+			break;
+		case SE_IOCTL_SETUP_IOBUF:
+			err = se_ioctl_setup_iobuf_handler(dev_ctx, arg);
+			break;
+		case SE_IOCTL_GET_SOC_INFO:
+			err = se_ioctl_get_se_soc_info_handler(dev_ctx, arg);
+			break;
+		case SE_IOCTL_CMD_SEND_RCV_RSP:
+			err = se_ioctl_cmd_snd_rcv_rsp_handler(dev_ctx, arg);
+			break;
+		default:
+			err = -EINVAL;
+			dev_dbg(priv->dev, "%s: IOCTL %.8x not supported.",
+				dev_ctx->devname, cmd);
+		}
+	}
+
+	return err;
+}
+
+/* Char driver setup */
+static const struct file_operations se_if_fops = {
+	.open		= se_if_fops_open,
+	.owner		= THIS_MODULE,
+	.release	= se_if_fops_close,
+	.unlocked_ioctl = se_ioctl,
+	.read		= se_if_fops_read,
+	.write		= se_if_fops_write,
+};
+
 /* interface for managed res to free a mailbox channel */
 static void if_mbox_free_channel(void *mbox_chan)
 {
@@ -246,7 +958,7 @@ static int se_if_request_channel(struct device *dev, struct mbox_chan **chan,
 	ret = devm_add_action_or_reset(dev, if_mbox_free_channel, t_chan);
 	if (ret)
 		return dev_err_probe(dev, -EPERM,
-				     "Failed to add-action for removal of mbox: %s\n",
+				     "Failed to add-action for removal of mbox: %s.",
 				     name);
 	*chan = t_chan;
 
@@ -255,6 +967,7 @@ static int se_if_request_channel(struct device *dev, struct mbox_chan **chan,
 
 static void se_if_probe_cleanup(void *plat_dev)
 {
+	struct se_if_device_ctx *dev_ctx, *t_dev_ctx;
 	struct platform_device *pdev = plat_dev;
 	struct se_fw_load_info *load_fw;
 	struct device *dev = &pdev->dev;
@@ -279,6 +992,13 @@ static void se_if_probe_cleanup(void *plat_dev)
 		load_fw->imem.buf = NULL;
 	}
 
+	if (priv->dev_ctx_mono_count) {
+		list_for_each_entry_safe(dev_ctx, t_dev_ctx, &priv->dev_ctx_list, link) {
+			list_del(&dev_ctx->link);
+			priv->active_devctx_count--;
+		}
+	}
+
 	/*
 	 * No need to check, if reserved memory is allocated
 	 * before calling for its release. Or clearing the
@@ -319,6 +1039,7 @@ static int se_if_probe(struct platform_device *pdev)
 	priv->se_mb_cl.tx_block		= false;
 	priv->se_mb_cl.knows_txdone	= true;
 	priv->se_mb_cl.rx_callback	= se_if_rx_callback;
+	set_se_rcv_msg_timeout(priv, SE_RCV_MSG_DEFAULT_TIMEOUT);
 
 	ret = se_if_request_channel(dev, &priv->tx_chan, &priv->se_mb_cl, MBOX_TX_NAME);
 	if (ret)
@@ -340,6 +1061,7 @@ static int se_if_probe(struct platform_device *pdev)
 					     "Unable to get sram pool = %s.",
 					     if_node->pool_name);
 	}
+	INIT_LIST_HEAD(&priv->dev_ctx_list);
 
 	if (if_node->reserved_dma_ranges) {
 		ret = of_reserved_mem_device_init(dev);
@@ -348,7 +1070,7 @@ static int se_if_probe(struct platform_device *pdev)
 					    "Failed to init reserved memory region.");
 	}
 
-	ret = init_misc_device_context(priv, 0, &priv->priv_dev_ctx);
+	ret = init_misc_device_context(priv, 0, &priv->priv_dev_ctx, &se_if_fops);
 	if (ret)
 		return dev_err_probe(dev, ret,
 				     "Failed[0x%x] to create device contexts.",
@@ -389,6 +1111,7 @@ static int se_suspend(struct device *dev)
 	struct se_fw_load_info *load_fw;
 	int ret = 0;
 
+	set_se_rcv_msg_timeout(priv, SE_RCV_MSG_DEFAULT_TIMEOUT);
 	load_fw = get_load_fw_instance(priv);
 
 	if (load_fw->imem_mgmt) {
diff --git a/drivers/firmware/imx/se_ctrl.h b/drivers/firmware/imx/se_ctrl.h
index b5e7705e2f26..5fcdcfe3e8e5 100644
--- a/drivers/firmware/imx/se_ctrl.h
+++ b/drivers/firmware/imx/se_ctrl.h
@@ -14,6 +14,7 @@
 #define SE_MSG_WORD_SZ			0x4
 
 #define RES_STATUS(x)			FIELD_GET(0x000000ff, x)
+#define MAX_DATA_SIZE_PER_USER		(65 * 1024)
 #define MAX_NVM_MSG_LEN			(256)
 #define MESSAGING_VERSION_6		0x6
 #define MESSAGING_VERSION_7		0x7
@@ -37,10 +38,38 @@ struct se_imem_buf {
 	u32 state;
 };
 
+struct se_buf_desc {
+	u8 *shared_buf_ptr;
+	void __user *usr_buf_ptr;
+	u32 size;
+	struct list_head link;
+};
+
+struct se_shared_mem {
+	dma_addr_t dma_addr;
+	u32 size;
+	u32 pos;
+	u8 *ptr;
+};
+
+struct se_shared_mem_mgmt_info {
+	struct list_head pending_in;
+	struct list_head pending_out;
+
+	struct se_shared_mem non_secure_mem;
+};
+
 /* Private struct for each char device instance. */
 struct se_if_device_ctx {
 	struct se_if_priv *priv;
+	struct miscdevice *miscdev;
 	const char *devname;
+
+	/* process one file operation at a time. */
+	struct mutex fops_lock;
+
+	struct se_shared_mem_mgmt_info se_shared_mem_mgmt;
+	struct list_head link;
 };
 
 /* Header of the messages exchange with the EdgeLock Enclave */
@@ -89,6 +118,10 @@ struct se_if_priv {
 	const struct se_if_defines *if_defs;
 
 	struct se_if_device_ctx *priv_dev_ctx;
+	struct list_head dev_ctx_list;
+	u32 active_devctx_count;
+	u32 dev_ctx_mono_count;
+	u32 se_rcv_msg_timeout_ms;
 };
 
 char *get_se_if_name(u8 se_if_id);
diff --git a/include/uapi/linux/se_ioctl.h b/include/uapi/linux/se_ioctl.h
new file mode 100644
index 000000000000..0c948bdc8c26
--- /dev/null
+++ b/include/uapi/linux/se_ioctl.h
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause*/
+/*
+ * Copyright 2025 NXP
+ */
+
+#ifndef SE_IOCTL_H
+#define SE_IOCTL_H
+
+#include <linux/types.h>
+
+#define SE_TYPE_STR_DBG			"dbg"
+#define SE_TYPE_STR_HSM			"hsm"
+#define SE_TYPE_ID_UNKWN		0x0
+#define SE_TYPE_ID_DBG			0x1
+#define SE_TYPE_ID_HSM			0x2
+/* IOCTL definitions. */
+
+struct se_ioctl_setup_iobuf {
+	void __user *user_buf;
+	__u32 length;
+	__u32 flags;
+	__u64 ele_addr;
+};
+
+struct se_ioctl_shared_mem_cfg {
+	__u32 base_offset;
+	__u32 size;
+};
+
+struct se_ioctl_get_if_info {
+	__u8 se_if_id;
+	__u8 interrupt_idx;
+	__u8 tz;
+	__u8 did;
+	__u8 cmd_tag;
+	__u8 rsp_tag;
+	__u8 success_tag;
+	__u8 base_api_ver;
+	__u8 fw_api_ver;
+};
+
+struct se_ioctl_cmd_snd_rcv_rsp_info {
+	__u32 __user *tx_buf;
+	int tx_buf_sz;
+	__u32 __user *rx_buf;
+	int rx_buf_sz;
+};
+
+struct se_ioctl_get_soc_info {
+	__u16 soc_id;
+	__u16 soc_rev;
+};
+
+/* IO Buffer Flags */
+#define SE_IO_BUF_FLAGS_IS_OUTPUT	(0x00u)
+#define SE_IO_BUF_FLAGS_IS_INPUT	(0x01u)
+#define SE_IO_BUF_FLAGS_USE_SEC_MEM	(0x02u)
+#define SE_IO_BUF_FLAGS_USE_SHORT_ADDR	(0x04u)
+#define SE_IO_BUF_FLAGS_IS_IN_OUT	(0x10u)
+
+/* IOCTLS */
+#define SE_IOCTL			0x0A /* like MISC_MAJOR. */
+
+/*
+ * ioctl to designated the current fd as logical-reciever.
+ * This is ioctl is send when the nvm-daemon, a slave to the
+ * firmware is started by the user.
+ */
+#define SE_IOCTL_ENABLE_CMD_RCV	_IO(SE_IOCTL, 0x01)
+
+/*
+ * ioctl to get the buffer allocated from the memory, which is shared
+ * between kernel and FW.
+ * Post allocation, the kernel tagged the allocated memory with:
+ *  Output
+ *  Input
+ *  Input-Output
+ *  Short address
+ *  Secure-memory
+ */
+#define SE_IOCTL_SETUP_IOBUF	_IOWR(SE_IOCTL, 0x03, struct se_ioctl_setup_iobuf)
+
+/*
+ * ioctl to get the mu information, that is used to exchange message
+ * with FW, from user-spaced.
+ */
+#define SE_IOCTL_GET_MU_INFO	_IOR(SE_IOCTL, 0x04, struct se_ioctl_get_if_info)
+/*
+ * ioctl to get SoC Info from user-space.
+ */
+#define SE_IOCTL_GET_SOC_INFO      _IOR(SE_IOCTL, 0x06, struct se_ioctl_get_soc_info)
+
+/*
+ * ioctl to send command and receive response from user-space.
+ */
+#define SE_IOCTL_CMD_SEND_RCV_RSP _IOWR(SE_IOCTL, 0x07, struct se_ioctl_cmd_snd_rcv_rsp_info)
+#endif

-- 
2.43.0



From pankaj.gupta at nxp.com  Thu Dec 18 21:20:44 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Fri, 19 Dec 2025 10:50:44 +0530
Subject: [PATCH v23 6/7] arm64: dts: imx8ulp: add secure enclave node
In-Reply-To: <20251219-imx-se-if-v23-0-5c6773d00318@nxp.com>
References: <20251219-imx-se-if-v23-0-5c6773d00318@nxp.com>
Message-ID: <20251219-imx-se-if-v23-6-5c6773d00318@nxp.com>

Add support for NXP secure enclave called EdgeLock Enclave firmware (se-fw)
for imx8ulp-evk.

Add label sram0 for sram at 2201f000 and add secure-enclave node

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
 arch/arm64/boot/dts/freescale/imx8ulp.dtsi | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8ulp.dtsi b/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
index 13b01f3aa2a4..10a4779dd24c 100644
--- a/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
- * Copyright 2021 NXP
+ * Copyright 2021, 2025 NXP
  */
 
 #include <dt-bindings/clock/imx8ulp-clock.h>
@@ -154,7 +154,7 @@ sosc: clock-sosc {
 		#clock-cells = <0>;
 	};
 
-	sram at 2201f000 {
+	sram0: sram at 2201f000 {
 		compatible = "mmio-sram";
 		reg = <0x0 0x2201f000 0x0 0x1000>;
 
@@ -186,6 +186,13 @@ scmi_sensor: protocol at 15 {
 				#thermal-sensor-cells = <1>;
 			};
 		};
+
+		hsm0: secure-enclave {
+			 compatible = "fsl,imx8ulp-se-ele-hsm";
+			 mbox-names = "tx", "rx";
+			 mboxes = <&s4muap 0 0>, <&s4muap 1 0>;
+			 sram = <&sram0>;
+		 };
 	};
 
 	cm33: remoteproc-cm33 {

-- 
2.43.0



From pankaj.gupta at nxp.com  Thu Dec 18 21:20:45 2025
From: pankaj.gupta at nxp.com (Pankaj Gupta)
Date: Fri, 19 Dec 2025 10:50:45 +0530
Subject: [PATCH v23 7/7] arm64: dts: imx8ulp-evk: add reserved memory
 property
In-Reply-To: <20251219-imx-se-if-v23-0-5c6773d00318@nxp.com>
References: <20251219-imx-se-if-v23-0-5c6773d00318@nxp.com>
Message-ID: <20251219-imx-se-if-v23-7-5c6773d00318@nxp.com>

Reserve 1MB of DDR memory region due to EdgeLock Enclave's hardware
limitation restricting access to DDR addresses from 0x80000000
to 0xafffffff.

Signed-off-by: Pankaj Gupta <pankaj.gupta at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
---
 arch/arm64/boot/dts/freescale/imx8ulp-evk.dts | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8ulp-evk.dts b/arch/arm64/boot/dts/freescale/imx8ulp-evk.dts
index 290a49bea2f7..10aaf02f8ea7 100644
--- a/arch/arm64/boot/dts/freescale/imx8ulp-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8ulp-evk.dts
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
- * Copyright 2021 NXP
+ * Copyright 2021, 2025 NXP
  */
 
 /dts-v1/;
@@ -37,6 +37,12 @@ linux,cma {
 			linux,cma-default;
 		};
 
+		ele_reserved: memory at 90000000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x90000000 0 0x100000>;
+			no-map;
+		};
+
 		m33_reserved: noncacheable-section at a8600000 {
 			reg = <0 0xa8600000 0 0x1000000>;
 			no-map;
@@ -259,6 +265,10 @@ &usdhc0 {
 	status = "okay";
 };
 
+&hsm0 {
+	memory-region = <&ele_reserved>;
+};
+
 &fec {
 	pinctrl-names = "default", "sleep";
 	pinctrl-0 = <&pinctrl_enet>;

-- 
2.43.0



From 21cnbao at gmail.com  Thu Dec 18 21:36:53 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Fri, 19 Dec 2025 13:36:53 +0800
Subject: [PATCH 1/6] arm64: Provide dcache_by_myline_op_nosync helper
In-Reply-To: <20251219053658.84978-1-21cnbao@gmail.com>
References: <20251219053658.84978-1-21cnbao@gmail.com>
Message-ID: <20251219053658.84978-2-21cnbao@gmail.com>

From: Barry Song <v-songbaohua at oppo.com>

dcache_by_myline_op ensures completion of the data cache operations for a
region, while dcache_by_myline_op_nosync only issues them without waiting.
This enables deferred synchronization so completion for multiple regions
can be handled together later.

Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Will Deacon <will at kernel.org>
Cc: Marek Szyprowski <m.szyprowski at samsung.com>
Cc: Robin Murphy <robin.murphy at arm.com>
Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
Cc: Ard Biesheuvel <ardb at kernel.org>
Cc: Marc Zyngier <maz at kernel.org>
Cc: Anshuman Khandual <anshuman.khandual at arm.com>
Cc: Ryan Roberts <ryan.roberts at arm.com>
Cc: Suren Baghdasaryan <surenb at google.com>
Cc: Tangquan Zheng <zhengtangquan at oppo.com>
Signed-off-by: Barry Song <v-songbaohua at oppo.com>
---
 arch/arm64/include/asm/assembler.h | 79 ++++++++++++++++++++++--------
 1 file changed, 59 insertions(+), 20 deletions(-)

diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index f0ca7196f6fa..7d84a9ca7880 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -366,22 +366,7 @@ alternative_else
 alternative_endif
 	.endm
 
-/*
- * Macro to perform a data cache maintenance for the interval
- * [start, end) with dcache line size explicitly provided.
- *
- * 	op:		operation passed to dc instruction
- * 	domain:		domain used in dsb instruction
- * 	start:          starting virtual address of the region
- * 	end:            end virtual address of the region
- *	linesz:		dcache line size
- * 	fixup:		optional label to branch to on user fault
- * 	Corrupts:       start, end, tmp
- */
-	.macro dcache_by_myline_op op, domain, start, end, linesz, tmp, fixup
-	sub	\tmp, \linesz, #1
-	bic	\start, \start, \tmp
-.Ldcache_op\@:
+	.macro __dcache_op_line op, start
 	.ifc	\op, cvau
 	__dcache_op_workaround_clean_cache \op, \start
 	.else
@@ -399,14 +384,54 @@ alternative_endif
 	.endif
 	.endif
 	.endif
-	add	\start, \start, \linesz
-	cmp	\start, \end
-	b.lo	.Ldcache_op\@
-	dsb	\domain
+	.endm
+
+/*
+ * Macro to perform a data cache maintenance for the interval
+ * [start, end) with dcache line size explicitly provided.
+ *
+ * 	op:		operation passed to dc instruction
+ * 	domain:		domain used in dsb instruction
+ * 	start:          starting virtual address of the region
+ * 	end:            end virtual address of the region
+ *	linesz:		dcache line size
+ * 	fixup:		optional label to branch to on user fault
+ * 	Corrupts:       start, end, tmp
+ */
+	.macro dcache_by_myline_op op, domain, start, end, linesz, tmp, fixup
+	sub	\tmp, \linesz, #1
+	bic	\start, \start, \tmp
+.Ldcache_op\@:
+	__dcache_op_line \op, \start
+	add     \start, \start, \linesz
+	cmp     \start, \end
+	b.lo    .Ldcache_op\@
 
+	dsb	\domain
 	_cond_uaccess_extable .Ldcache_op\@, \fixup
 	.endm
 
+/*
+ * Macro to perform a data cache maintenance for the interval
+ * [start, end) with dcache line size explicitly provided.
+ * It won't wait for the completion of the dc operation.
+ *
+ * 	op:		operation passed to dc instruction
+ * 	start:          starting virtual address of the region
+ * 	end:            end virtual address of the region
+ *	linesz:		dcache line size
+ * 	Corrupts:       start, end, tmp
+ */
+	.macro dcache_by_myline_op_nosync op, start, end, linesz, tmp
+	sub	\tmp, \linesz, #1
+	bic	\start, \start, \tmp
+.Ldcache_op\@:
+	__dcache_op_line \op, \start
+	add     \start, \start, \linesz
+	cmp     \start, \end
+	b.lo    .Ldcache_op\@
+	.endm
+
 /*
  * Macro to perform a data cache maintenance for the interval
  * [start, end)
@@ -423,6 +448,20 @@ alternative_endif
 	dcache_by_myline_op \op, \domain, \start, \end, \tmp1, \tmp2, \fixup
 	.endm
 
+/*
+ * Macro to perform a data cache maintenance for the interval
+ * [start, end). It won?t wait for the dc operation to complete.
+ *
+ * 	op:		operation passed to dc instruction
+ * 	start:          starting virtual address of the region
+ * 	end:            end virtual address of the region
+ * 	Corrupts:       start, end, tmp1, tmp2
+ */
+	.macro dcache_by_line_op_nosync op, start, end, tmp1, tmp2
+	dcache_line_size \tmp1, \tmp2
+	dcache_by_myline_op_nosync \op, \start, \end, \tmp1, \tmp2
+	.endm
+
 /*
  * Macro to perform an instruction cache maintenance for the interval
  * [start, end)
-- 
2.39.3 (Apple Git-146)



From 21cnbao at gmail.com  Thu Dec 18 21:36:54 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Fri, 19 Dec 2025 13:36:54 +0800
Subject: [PATCH 2/6] arm64: Provide dcache_clean_poc_nosync helper
In-Reply-To: <20251219053658.84978-1-21cnbao@gmail.com>
References: <20251219053658.84978-1-21cnbao@gmail.com>
Message-ID: <20251219053658.84978-3-21cnbao@gmail.com>

From: Barry Song <v-songbaohua at oppo.com>

dcache_clean_poc_nosync does not wait for the data cache clean to
complete. Later, we wait for completion of all scatter-gather entries
together.

Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Will Deacon <will at kernel.org>
Cc: Marek Szyprowski <m.szyprowski at samsung.com>
Cc: Robin Murphy <robin.murphy at arm.com>
Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
Cc: Ard Biesheuvel <ardb at kernel.org>
Cc: Marc Zyngier <maz at kernel.org>
Cc: Anshuman Khandual <anshuman.khandual at arm.com>
Cc: Ryan Roberts <ryan.roberts at arm.com>
Cc: Suren Baghdasaryan <surenb at google.com>
Cc: Tangquan Zheng <zhengtangquan at oppo.com>
Signed-off-by: Barry Song <v-songbaohua at oppo.com>
---
 arch/arm64/include/asm/cacheflush.h |  1 +
 arch/arm64/mm/cache.S               | 15 +++++++++++++++
 2 files changed, 16 insertions(+)

diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h
index 28ab96e808ef..9b6d0a62cf3d 100644
--- a/arch/arm64/include/asm/cacheflush.h
+++ b/arch/arm64/include/asm/cacheflush.h
@@ -74,6 +74,7 @@ extern void icache_inval_pou(unsigned long start, unsigned long end);
 extern void dcache_clean_inval_poc(unsigned long start, unsigned long end);
 extern void dcache_inval_poc(unsigned long start, unsigned long end);
 extern void dcache_clean_poc(unsigned long start, unsigned long end);
+extern void dcache_clean_poc_nosync(unsigned long start, unsigned long end);
 extern void dcache_clean_pop(unsigned long start, unsigned long end);
 extern void dcache_clean_pou(unsigned long start, unsigned long end);
 extern long caches_clean_inval_user_pou(unsigned long start, unsigned long end);
diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S
index 503567c864fd..4a7c7e03785d 100644
--- a/arch/arm64/mm/cache.S
+++ b/arch/arm64/mm/cache.S
@@ -178,6 +178,21 @@ SYM_FUNC_START(__pi_dcache_clean_poc)
 SYM_FUNC_END(__pi_dcache_clean_poc)
 SYM_FUNC_ALIAS(dcache_clean_poc, __pi_dcache_clean_poc)
 
+/*
+ *	dcache_clean_poc_nosync(start, end)
+ *
+ * 	Issue the instructions of D-cache lines for the interval [start, end).
+ * 	not necessarily cleaned to the PoC till an explicit dsb sy afterward.
+ *
+ *	- start   - virtual start address of region
+ *	- end     - virtual end address of region
+ */
+SYM_FUNC_START(__pi_dcache_clean_poc_nosync)
+	dcache_by_line_op_nosync cvac, x0, x1, x2, x3
+	ret
+SYM_FUNC_END(__pi_dcache_clean_poc_nosync)
+SYM_FUNC_ALIAS(dcache_clean_poc_nosync, __pi_dcache_clean_poc_nosync)
+
 /*
  *	dcache_clean_pop(start, end)
  *
-- 
2.39.3 (Apple Git-146)



From 21cnbao at gmail.com  Thu Dec 18 21:36:55 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Fri, 19 Dec 2025 13:36:55 +0800
Subject: [PATCH 3/6] arm64: Provide dcache_inval_poc_nosync helper
In-Reply-To: <20251219053658.84978-1-21cnbao@gmail.com>
References: <20251219053658.84978-1-21cnbao@gmail.com>
Message-ID: <20251219053658.84978-4-21cnbao@gmail.com>

From: Barry Song <v-songbaohua at oppo.com>

dcache_inval_poc_nosync does not wait for the data cache invalidation to
complete. Later, we defer the synchronization so we can wait for all SG
entries together.

Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Will Deacon <will at kernel.org>
Cc: Marek Szyprowski <m.szyprowski at samsung.com>
Cc: Robin Murphy <robin.murphy at arm.com>
Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
Cc: Ard Biesheuvel <ardb at kernel.org>
Cc: Marc Zyngier <maz at kernel.org>
Cc: Anshuman Khandual <anshuman.khandual at arm.com>
Cc: Ryan Roberts <ryan.roberts at arm.com>
Cc: Suren Baghdasaryan <surenb at google.com>
Cc: Tangquan Zheng <zhengtangquan at oppo.com>
Signed-off-by: Barry Song <v-songbaohua at oppo.com>
---
 arch/arm64/include/asm/cacheflush.h |  1 +
 arch/arm64/mm/cache.S               | 43 +++++++++++++++++++++--------
 2 files changed, 33 insertions(+), 11 deletions(-)

diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h
index 9b6d0a62cf3d..382b4ac3734d 100644
--- a/arch/arm64/include/asm/cacheflush.h
+++ b/arch/arm64/include/asm/cacheflush.h
@@ -74,6 +74,7 @@ extern void icache_inval_pou(unsigned long start, unsigned long end);
 extern void dcache_clean_inval_poc(unsigned long start, unsigned long end);
 extern void dcache_inval_poc(unsigned long start, unsigned long end);
 extern void dcache_clean_poc(unsigned long start, unsigned long end);
+extern void dcache_inval_poc_nosync(unsigned long start, unsigned long end);
 extern void dcache_clean_poc_nosync(unsigned long start, unsigned long end);
 extern void dcache_clean_pop(unsigned long start, unsigned long end);
 extern void dcache_clean_pou(unsigned long start, unsigned long end);
diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S
index 4a7c7e03785d..8c1043c9b9e5 100644
--- a/arch/arm64/mm/cache.S
+++ b/arch/arm64/mm/cache.S
@@ -132,17 +132,7 @@ alternative_else_nop_endif
 	ret
 SYM_FUNC_END(dcache_clean_pou)
 
-/*
- *	dcache_inval_poc(start, end)
- *
- * 	Ensure that any D-cache lines for the interval [start, end)
- * 	are invalidated. Any partial lines at the ends of the interval are
- *	also cleaned to PoC to prevent data loss.
- *
- *	- start   - kernel start address of region
- *	- end     - kernel end address of region
- */
-SYM_FUNC_START(__pi_dcache_inval_poc)
+.macro _dcache_inval_poc_impl, do_sync
 	dcache_line_size x2, x3
 	sub	x3, x2, #1
 	tst	x1, x3				// end cache line aligned?
@@ -158,11 +148,42 @@ SYM_FUNC_START(__pi_dcache_inval_poc)
 3:	add	x0, x0, x2
 	cmp	x0, x1
 	b.lo	2b
+.if \do_sync
 	dsb	sy
+.endif
 	ret
+.endm
+
+/*
+ *	dcache_inval_poc(start, end)
+ *
+ * 	Ensure that any D-cache lines for the interval [start, end)
+ * 	are invalidated. Any partial lines at the ends of the interval are
+ *	also cleaned to PoC to prevent data loss.
+ *
+ *	- start   - kernel start address of region
+ *	- end     - kernel end address of region
+ */
+SYM_FUNC_START(__pi_dcache_inval_poc)
+	_dcache_inval_poc_impl 1
 SYM_FUNC_END(__pi_dcache_inval_poc)
 SYM_FUNC_ALIAS(dcache_inval_poc, __pi_dcache_inval_poc)
 
+/*
+ *	dcache_inval_poc_nosync(start, end)
+ *
+ * 	Issue the instructions of D-cache lines for the interval [start, end)
+ * 	for invalidation. Not necessarily cleaned to PoC till an explicit dsb
+ *	sy later
+ *
+ *	- start   - kernel start address of region
+ *	- end     - kernel end address of region
+ */
+SYM_FUNC_START(__pi_dcache_inval_poc_nosync)
+	_dcache_inval_poc_impl 0
+SYM_FUNC_END(__pi_dcache_inval_poc_nosync)
+SYM_FUNC_ALIAS(dcache_inval_poc_nosync, __pi_dcache_inval_poc_nosync)
+
 /*
  *	dcache_clean_poc(start, end)
  *
-- 
2.39.3 (Apple Git-146)



From 21cnbao at gmail.com  Thu Dec 18 21:36:56 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Fri, 19 Dec 2025 13:36:56 +0800
Subject: [PATCH 4/6] arm64: Provide arch_sync_dma_ batched helpers
In-Reply-To: <20251219053658.84978-1-21cnbao@gmail.com>
References: <20251219053658.84978-1-21cnbao@gmail.com>
Message-ID: <20251219053658.84978-5-21cnbao@gmail.com>

From: Barry Song <v-songbaohua at oppo.com>

arch_sync_dma_for_device_batch_add() and
arch_sync_dma_for_cpu_batch_add() batch DMA sync operations,
while arch_sync_dma_batch_flush() waits for their completion
as a group.

On architectures that do not support batching,
arch_sync_dma_for_device_batch_add() and
arch_sync_dma_for_cpu_batch_add() fall back to the non-batched
implementations, and arch_sync_dma_batch_flush() is a no-op.

Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Will Deacon <will at kernel.org>
Cc: Marek Szyprowski <m.szyprowski at samsung.com>
Cc: Robin Murphy <robin.murphy at arm.com>
Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
Cc: Ard Biesheuvel <ardb at kernel.org>
Cc: Marc Zyngier <maz at kernel.org>
Cc: Anshuman Khandual <anshuman.khandual at arm.com>
Cc: Ryan Roberts <ryan.roberts at arm.com>
Cc: Suren Baghdasaryan <surenb at google.com>
Cc: Tangquan Zheng <zhengtangquan at oppo.com>
Signed-off-by: Barry Song <v-songbaohua at oppo.com>
---
 arch/arm64/Kconfig          |  1 +
 arch/arm64/mm/dma-mapping.c | 24 ++++++++++++++++++++++++
 include/linux/dma-map-ops.h | 22 ++++++++++++++++++++++
 kernel/dma/Kconfig          |  3 +++
 4 files changed, 50 insertions(+)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 93173f0a09c7..c8adbf21b7bf 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -112,6 +112,7 @@ config ARM64
 	select ARCH_SUPPORTS_SCHED_CLUSTER
 	select ARCH_SUPPORTS_SCHED_MC
 	select ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
+	select ARCH_WANT_BATCHED_DMA_SYNC
 	select ARCH_WANT_COMPAT_IPC_PARSE_VERSION if COMPAT
 	select ARCH_WANT_DEFAULT_BPF_JIT
 	select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index b2b5792b2caa..9ac1ddd1bb9c 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -31,6 +31,30 @@ void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
 	dcache_inval_poc(start, start + size);
 }
 
+void arch_sync_dma_for_device_batch_add(phys_addr_t paddr, size_t size,
+			      enum dma_data_direction dir)
+{
+	unsigned long start = (unsigned long)phys_to_virt(paddr);
+
+	dcache_clean_poc_nosync(start, start + size);
+}
+
+void arch_sync_dma_for_cpu_batch_add(phys_addr_t paddr, size_t size,
+			   enum dma_data_direction dir)
+{
+	unsigned long start = (unsigned long)phys_to_virt(paddr);
+
+	if (dir == DMA_TO_DEVICE)
+		return;
+
+	dcache_inval_poc_nosync(start, start + size);
+}
+
+void arch_sync_dma_batch_flush(void)
+{
+	dsb(sy);
+}
+
 void arch_dma_prep_coherent(struct page *page, size_t size)
 {
 	unsigned long start = (unsigned long)page_address(page);
diff --git a/include/linux/dma-map-ops.h b/include/linux/dma-map-ops.h
index 4809204c674c..5ee92c410e3c 100644
--- a/include/linux/dma-map-ops.h
+++ b/include/linux/dma-map-ops.h
@@ -361,6 +361,28 @@ static inline void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
 }
 #endif /* ARCH_HAS_SYNC_DMA_FOR_CPU */
 
+#ifdef CONFIG_ARCH_WANT_BATCHED_DMA_SYNC
+void arch_sync_dma_for_device_batch_add(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir);
+void arch_sync_dma_for_cpu_batch_add(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir);
+void arch_sync_dma_batch_flush(void);
+#else
+static inline void arch_sync_dma_for_device_batch_add(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
+{
+	arch_sync_dma_for_device(paddr, size, dir);
+}
+static inline void arch_sync_dma_for_cpu_batch_add(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
+{
+	arch_sync_dma_for_cpu(paddr, size, dir);
+}
+static inline void arch_sync_dma_batch_flush(void)
+{
+}
+#endif
+
 #ifdef CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU_ALL
 void arch_sync_dma_for_cpu_all(void);
 #else
diff --git a/kernel/dma/Kconfig b/kernel/dma/Kconfig
index 31cfdb6b4bc3..2785099b2fa0 100644
--- a/kernel/dma/Kconfig
+++ b/kernel/dma/Kconfig
@@ -78,6 +78,9 @@ config ARCH_HAS_DMA_PREP_COHERENT
 config ARCH_HAS_FORCE_DMA_UNENCRYPTED
 	bool
 
+config ARCH_WANT_BATCHED_DMA_SYNC
+	bool
+
 #
 # Select this option if the architecture assumes DMA devices are coherent
 # by default.
-- 
2.39.3 (Apple Git-146)



From 21cnbao at gmail.com  Thu Dec 18 21:36:57 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Fri, 19 Dec 2025 13:36:57 +0800
Subject: [PATCH 5/6] dma-mapping: Allow batched DMA sync operations if supported by the arch
In-Reply-To: <20251219053658.84978-1-21cnbao@gmail.com>
References: <20251219053658.84978-1-21cnbao@gmail.com>
Message-ID: <20251219053658.84978-6-21cnbao@gmail.com>

From: Barry Song <v-songbaohua at oppo.com>

This enables dma_direct_sync_sg_for_device, dma_direct_sync_sg_for_cpu,
dma_direct_map_sg, and dma_direct_unmap_sg to use batched DMA sync
operations when possible. This significantly improves performance on
devices without hardware cache coherence.

Tangquan's initial results show that batched synchronization can reduce
dma_map_sg() time by 64.61% and dma_unmap_sg() time by 66.60% on an MTK
phone platform (MediaTek Dimensity 9500). The tests were performed by
pinning the task to CPU7 and fixing the CPU frequency at 2.6 GHz,
running dma_map_sg() and dma_unmap_sg() on 10 MB buffers (10 MB / 4 KB
sg entries per buffer) for 200 iterations and then averaging the
results.

Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Will Deacon <will at kernel.org>
Cc: Marek Szyprowski <m.szyprowski at samsung.com>
Cc: Robin Murphy <robin.murphy at arm.com>
Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
Cc: Ard Biesheuvel <ardb at kernel.org>
Cc: Marc Zyngier <maz at kernel.org>
Cc: Anshuman Khandual <anshuman.khandual at arm.com>
Cc: Ryan Roberts <ryan.roberts at arm.com>
Cc: Suren Baghdasaryan <surenb at google.com>
Cc: Tangquan Zheng <zhengtangquan at oppo.com>
Signed-off-by: Barry Song <v-songbaohua at oppo.com>
---
 kernel/dma/direct.c | 28 ++++++++++-----
 kernel/dma/direct.h | 86 +++++++++++++++++++++++++++++++++++++++------
 2 files changed, 95 insertions(+), 19 deletions(-)

diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index 50c3fe2a1d55..ed2339b0c5e7 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -403,9 +403,10 @@ void dma_direct_sync_sg_for_device(struct device *dev,
 		swiotlb_sync_single_for_device(dev, paddr, sg->length, dir);
 
 		if (!dev_is_dma_coherent(dev))
-			arch_sync_dma_for_device(paddr, sg->length,
-					dir);
+			arch_sync_dma_for_device_batch_add(paddr, sg->length, dir);
 	}
+	if (!dev_is_dma_coherent(dev))
+		arch_sync_dma_batch_flush();
 }
 #endif
 
@@ -422,7 +423,7 @@ void dma_direct_sync_sg_for_cpu(struct device *dev,
 		phys_addr_t paddr = dma_to_phys(dev, sg_dma_address(sg));
 
 		if (!dev_is_dma_coherent(dev))
-			arch_sync_dma_for_cpu(paddr, sg->length, dir);
+			arch_sync_dma_for_cpu_batch_add(paddr, sg->length, dir);
 
 		swiotlb_sync_single_for_cpu(dev, paddr, sg->length, dir);
 
@@ -430,8 +431,10 @@ void dma_direct_sync_sg_for_cpu(struct device *dev,
 			arch_dma_mark_clean(paddr, sg->length);
 	}
 
-	if (!dev_is_dma_coherent(dev))
+	if (!dev_is_dma_coherent(dev)) {
 		arch_sync_dma_for_cpu_all();
+		arch_sync_dma_batch_flush();
+	}
 }
 
 /*
@@ -443,14 +446,19 @@ void dma_direct_unmap_sg(struct device *dev, struct scatterlist *sgl,
 {
 	struct scatterlist *sg;
 	int i;
+	bool need_sync = false;
 
 	for_each_sg(sgl,  sg, nents, i) {
-		if (sg_dma_is_bus_address(sg))
+		if (sg_dma_is_bus_address(sg)) {
 			sg_dma_unmark_bus_address(sg);
-		else
-			dma_direct_unmap_phys(dev, sg->dma_address,
+		} else {
+			need_sync = true;
+			dma_direct_unmap_phys_batch_add(dev, sg->dma_address,
 					      sg_dma_len(sg), dir, attrs);
+		}
 	}
+	if (need_sync && !dev_is_dma_coherent(dev))
+		arch_sync_dma_batch_flush();
 }
 #endif
 
@@ -460,6 +468,7 @@ int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
 	struct pci_p2pdma_map_state p2pdma_state = {};
 	struct scatterlist *sg;
 	int i, ret;
+	bool need_sync = false;
 
 	for_each_sg(sgl, sg, nents, i) {
 		switch (pci_p2pdma_state(&p2pdma_state, dev, sg_page(sg))) {
@@ -471,7 +480,8 @@ int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
 			 */
 			break;
 		case PCI_P2PDMA_MAP_NONE:
-			sg->dma_address = dma_direct_map_phys(dev, sg_phys(sg),
+			need_sync = true;
+			sg->dma_address = dma_direct_map_phys_batch_add(dev, sg_phys(sg),
 					sg->length, dir, attrs);
 			if (sg->dma_address == DMA_MAPPING_ERROR) {
 				ret = -EIO;
@@ -491,6 +501,8 @@ int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
 		sg_dma_len(sg) = sg->length;
 	}
 
+	if (need_sync && !dev_is_dma_coherent(dev))
+		arch_sync_dma_batch_flush();
 	return nents;
 
 out_unmap:
diff --git a/kernel/dma/direct.h b/kernel/dma/direct.h
index da2fadf45bcd..a211bab26478 100644
--- a/kernel/dma/direct.h
+++ b/kernel/dma/direct.h
@@ -64,15 +64,11 @@ static inline void dma_direct_sync_single_for_device(struct device *dev,
 		arch_sync_dma_for_device(paddr, size, dir);
 }
 
-static inline void dma_direct_sync_single_for_cpu(struct device *dev,
-		dma_addr_t addr, size_t size, enum dma_data_direction dir)
+static inline void __dma_direct_sync_single_for_cpu(struct device *dev,
+		phys_addr_t paddr, size_t size, enum dma_data_direction dir)
 {
-	phys_addr_t paddr = dma_to_phys(dev, addr);
-
-	if (!dev_is_dma_coherent(dev)) {
-		arch_sync_dma_for_cpu(paddr, size, dir);
+	if (!dev_is_dma_coherent(dev))
 		arch_sync_dma_for_cpu_all();
-	}
 
 	swiotlb_sync_single_for_cpu(dev, paddr, size, dir);
 
@@ -80,7 +76,31 @@ static inline void dma_direct_sync_single_for_cpu(struct device *dev,
 		arch_dma_mark_clean(paddr, size);
 }
 
-static inline dma_addr_t dma_direct_map_phys(struct device *dev,
+#ifdef CONFIG_ARCH_WANT_BATCHED_DMA_SYNC
+static inline void dma_direct_sync_single_for_cpu_batch_add(struct device *dev,
+		dma_addr_t addr, size_t size, enum dma_data_direction dir)
+{
+	phys_addr_t paddr = dma_to_phys(dev, addr);
+
+	if (!dev_is_dma_coherent(dev))
+		arch_sync_dma_for_cpu_batch_add(paddr, size, dir);
+
+	__dma_direct_sync_single_for_cpu(dev, paddr, size, dir);
+}
+#endif
+
+static inline void dma_direct_sync_single_for_cpu(struct device *dev,
+		dma_addr_t addr, size_t size, enum dma_data_direction dir)
+{
+	phys_addr_t paddr = dma_to_phys(dev, addr);
+
+	if (!dev_is_dma_coherent(dev))
+		arch_sync_dma_for_cpu(paddr, size, dir);
+
+	__dma_direct_sync_single_for_cpu(dev, paddr, size, dir);
+}
+
+static inline dma_addr_t __dma_direct_map_phys(struct device *dev,
 		phys_addr_t phys, size_t size, enum dma_data_direction dir,
 		unsigned long attrs)
 {
@@ -108,9 +128,6 @@ static inline dma_addr_t dma_direct_map_phys(struct device *dev,
 		}
 	}
 
-	if (!dev_is_dma_coherent(dev) &&
-	    !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO)))
-		arch_sync_dma_for_device(phys, size, dir);
 	return dma_addr;
 
 err_overflow:
@@ -121,6 +138,53 @@ static inline dma_addr_t dma_direct_map_phys(struct device *dev,
 	return DMA_MAPPING_ERROR;
 }
 
+#ifdef CONFIG_ARCH_WANT_BATCHED_DMA_SYNC
+static inline dma_addr_t dma_direct_map_phys_batch_add(struct device *dev,
+		phys_addr_t phys, size_t size, enum dma_data_direction dir,
+		unsigned long attrs)
+{
+	dma_addr_t dma_addr = __dma_direct_map_phys(dev, phys, size, dir, attrs);
+
+	if (dma_addr != DMA_MAPPING_ERROR && !dev_is_dma_coherent(dev) &&
+	    !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO)))
+		arch_sync_dma_for_device_batch_add(phys, size, dir);
+
+	return dma_addr;
+}
+#endif
+
+static inline dma_addr_t dma_direct_map_phys(struct device *dev,
+		phys_addr_t phys, size_t size, enum dma_data_direction dir,
+		unsigned long attrs)
+{
+	dma_addr_t dma_addr = __dma_direct_map_phys(dev, phys, size, dir, attrs);
+
+	if (dma_addr != DMA_MAPPING_ERROR && !dev_is_dma_coherent(dev) &&
+	    !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO)))
+		arch_sync_dma_for_device(phys, size, dir);
+
+	return dma_addr;
+}
+
+#ifdef CONFIG_ARCH_WANT_BATCHED_DMA_SYNC
+static inline void dma_direct_unmap_phys_batch_add(struct device *dev, dma_addr_t addr,
+		size_t size, enum dma_data_direction dir, unsigned long attrs)
+{
+	phys_addr_t phys;
+
+	if (attrs & DMA_ATTR_MMIO)
+		/* nothing to do: uncached and no swiotlb */
+		return;
+
+	phys = dma_to_phys(dev, addr);
+	if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
+		dma_direct_sync_single_for_cpu_batch_add(dev, addr, size, dir);
+
+	swiotlb_tbl_unmap_single(dev, phys, size, dir,
+					 attrs | DMA_ATTR_SKIP_CPU_SYNC);
+}
+#endif
+
 static inline void dma_direct_unmap_phys(struct device *dev, dma_addr_t addr,
 		size_t size, enum dma_data_direction dir, unsigned long attrs)
 {
-- 
2.39.3 (Apple Git-146)



From 21cnbao at gmail.com  Thu Dec 18 21:36:58 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Fri, 19 Dec 2025 13:36:58 +0800
Subject: [PATCH RFC 6/6] dma-iommu: Allow DMA sync batching for IOVA link/unlink
In-Reply-To: <20251219053658.84978-1-21cnbao@gmail.com>
References: <20251219053658.84978-1-21cnbao@gmail.com>
Message-ID: <20251219053658.84978-7-21cnbao@gmail.com>

From: Barry Song <v-songbaohua at oppo.com>

Apply batched DMA synchronization to __dma_iova_link() and
iommu_dma_iova_unlink_range_slow(). For multiple
sync_dma_for_device() and sync_dma_for_cpu() calls, we only
need to wait once for the completion of all sync operations,
rather than waiting for each one individually.

I do not have the hardware to test this, so it is marked as
RFC. I would greatly appreciate it if someone could test it.

Suggested-by: Marek Szyprowski <m.szyprowski at samsung.com>
Cc: Robin Murphy <robin.murphy at arm.com>
Cc: Joerg Roedel <joro at 8bytes.org>
Cc: Will Deacon <will at kernel.org>
Signed-off-by: Barry Song <v-songbaohua at oppo.com>
---
 drivers/iommu/dma-iommu.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index c92088855450..95432bdc364f 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -1837,7 +1837,7 @@ static int __dma_iova_link(struct device *dev, dma_addr_t addr,
 	int prot = dma_info_to_prot(dir, coherent, attrs);
 
 	if (!coherent && !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO)))
-		arch_sync_dma_for_device(phys, size, dir);
+		arch_sync_dma_for_device_batch_add(phys, size, dir);
 
 	return iommu_map_nosync(iommu_get_dma_domain(dev), addr, phys, size,
 			prot, GFP_ATOMIC);
@@ -1980,6 +1980,8 @@ int dma_iova_sync(struct device *dev, struct dma_iova_state *state,
 	dma_addr_t addr = state->addr + offset;
 	size_t iova_start_pad = iova_offset(iovad, addr);
 
+	if (!dev_is_dma_coherent(dev))
+		arch_sync_dma_batch_flush();
 	return iommu_sync_map(domain, addr - iova_start_pad,
 		      iova_align(iovad, size + iova_start_pad));
 }
@@ -1993,6 +1995,8 @@ static void iommu_dma_iova_unlink_range_slow(struct device *dev,
 	struct iommu_dma_cookie *cookie = domain->iova_cookie;
 	struct iova_domain *iovad = &cookie->iovad;
 	size_t iova_start_pad = iova_offset(iovad, addr);
+	bool need_sync_dma = !dev_is_dma_coherent(dev) &&
+			!(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO));
 	dma_addr_t end = addr + size;
 
 	do {
@@ -2007,8 +2011,7 @@ static void iommu_dma_iova_unlink_range_slow(struct device *dev,
 		len = min_t(size_t,
 			end - addr, iovad->granule - iova_start_pad);
 
-		if (!dev_is_dma_coherent(dev) &&
-		    !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO)))
+		if (need_sync_dma)
 			arch_sync_dma_for_cpu(phys, len, dir);
 
 		swiotlb_tbl_unmap_single(dev, phys, len, dir, attrs);
@@ -2016,6 +2019,9 @@ static void iommu_dma_iova_unlink_range_slow(struct device *dev,
 		addr += len;
 		iova_start_pad = 0;
 	} while (addr < end);
+
+	if (need_sync_dma)
+		arch_sync_dma_batch_flush();
 }
 
 static void __iommu_dma_iova_unlink(struct device *dev,
-- 
2.39.3 (Apple Git-146)



From dmitry.torokhov at gmail.com  Thu Dec 18 21:47:41 2025
From: dmitry.torokhov at gmail.com (Dmitry Torokhov)
Date: Thu, 18 Dec 2025 21:47:41 -0800
Subject: [PATCH v4 2/8] Input: ilitek_ts_i2c: fix warning with gpio
 controllers that sleep
In-Reply-To: <20251201-imx8mp-hb-iiot-v4-2-53a4cd6c21bf@solid-run.com>
References: <20251201-imx8mp-hb-iiot-v4-0-53a4cd6c21bf@solid-run.com>
 <20251201-imx8mp-hb-iiot-v4-2-53a4cd6c21bf@solid-run.com>
Message-ID: <6bbjei3z3arl2t2alkyl6gzok3yanzbni63q5z53mbcabb3za5@2ot3tcfkld6g>

On Mon, Dec 01, 2025 at 02:07:21PM +0100, Josua Mayer wrote:
> The ilitek touchscreen driver uses the non-sleeping gpiod_set_value
> function for reset.
> 
> Switch to using gpiod_set_value_cansleep() when controlling reset_gpio to
> support GPIO providers that may sleep, such as I2C GPIO expanders.
> 
> Further switch the mdelay calls on the reset path to fsleep (preferred
> in non-atomic contexts).
> 
> This fixes noisy complaints in kernel log for gpio providers that do
> sleep.
> 
> Signed-off-by: Josua Mayer <josua at solid-run.com>

Applied, thank you.

-- 
Dmitry


From baolin.wang at linux.alibaba.com  Thu Dec 18 22:02:50 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Fri, 19 Dec 2025 14:02:50 +0800
Subject: [PATCH v3 0/5] support batch checking of references and unmapping for large folios
Message-ID: <cover.1766121341.git.baolin.wang@linux.alibaba.com>

Currently, folio_referenced_one() always checks the young flag for each PTE
sequentially, which is inefficient for large folios. This inefficiency is
especially noticeable when reclaiming clean file-backed large folios, where
folio_referenced() is observed as a significant performance hotspot.

Moreover, on Arm architecture, which supports contiguous PTEs, there is already
an optimization to clear the young flags for PTEs within a contiguous range.
However, this is not sufficient. We can extend this to perform batched operations
for the entire large folio (which might exceed the contiguous range: CONT_PTE_SIZE).

Similar to folio_referenced_one(), we can also apply batched unmapping for large
file folios to optimize the performance of file folio reclamation. By supporting
batched checking of the young flags, flushing TLB entries, and unmapping, I can
observed a significant performance improvements in my performance tests for file
folios reclamation. Please check the performance data in the commit message of
each patch.

Run stress-ng and mm selftests, no issues were found.

Patch 1: Add a new generic batched PTE helper that supports batched checks of
the references for large folios.
Patch 2 - 3: Preparation patches.
patch 4: Implement the Arm64 arch-specific clear_flush_young_ptes().
Patch 5: Support batched unmapping for file large folios.

Changes from v2:
 - Rearrange the patch set (per Ryan).
 - Add pte_cont() check in clear_flush_young_ptes() (per Ryan).
 - Add a helper to do contpte block alignment (per Ryan).
 - Fix some coding style issues (per Lorenzo and Ryan).
 - Add more comments and update the commit message (per Lorenzo and Ryan).
 - Add acked tag from Barry. Thanks. 

Changes from v1:
 - Add a new patch to support batched unmapping for file large folios.
 - Update the cover letter

Baolin Wang (5):
  mm: rmap: support batched checks of the references for large folios
  arm64: mm: factor out the address and ptep alignment into a new helper
  arm64: mm: support batch clearing of the young flag for large folios
  arm64: mm: implement the architecture-specific
    clear_flush_young_ptes()
  mm: rmap: support batched unmapping for file large folios

 arch/arm64/include/asm/pgtable.h | 23 ++++++++----
 arch/arm64/mm/contpte.c          | 62 ++++++++++++++++++++------------
 include/linux/mmu_notifier.h     |  9 ++---
 include/linux/pgtable.h          | 35 ++++++++++++++++++
 mm/rmap.c                        | 36 ++++++++++++++++---
 5 files changed, 128 insertions(+), 37 deletions(-)

-- 
2.47.3



From baolin.wang at linux.alibaba.com  Thu Dec 18 22:02:51 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Fri, 19 Dec 2025 14:02:51 +0800
Subject: [PATCH v3 1/5] mm: rmap: support batched checks of the references for large folios
In-Reply-To: <cover.1766121341.git.baolin.wang@linux.alibaba.com>
References: <cover.1766121341.git.baolin.wang@linux.alibaba.com>
Message-ID: <24b9d33acad627997febe9b61d398fc53739a333.1766121341.git.baolin.wang@linux.alibaba.com>

Currently, folio_referenced_one() always checks the young flag for each PTE
sequentially, which is inefficient for large folios. This inefficiency is
especially noticeable when reclaiming clean file-backed large folios, where
folio_referenced() is observed as a significant performance hotspot.

Moreover, on Arm64 architecture, which supports contiguous PTEs, there is already
an optimization to clear the young flags for PTEs within a contiguous range.
However, this is not sufficient. We can extend this to perform batched operations
for the entire large folio (which might exceed the contiguous range: CONT_PTE_SIZE).

Introduce a new API: clear_flush_young_ptes() to facilitate batched checking
of the young flags and flushing TLB entries, thereby improving performance
during large folio reclamation. And it will be overridden by the architecture
that implements a more efficient batch operation in the following patches.

Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
---
 include/linux/mmu_notifier.h |  9 +++++----
 include/linux/pgtable.h      | 35 +++++++++++++++++++++++++++++++++++
 mm/rmap.c                    | 29 +++++++++++++++++++++++++++--
 3 files changed, 67 insertions(+), 6 deletions(-)

diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h
index d1094c2d5fb6..be594b274729 100644
--- a/include/linux/mmu_notifier.h
+++ b/include/linux/mmu_notifier.h
@@ -515,16 +515,17 @@ static inline void mmu_notifier_range_init_owner(
 	range->owner = owner;
 }
 
-#define ptep_clear_flush_young_notify(__vma, __address, __ptep)		\
+#define ptep_clear_flush_young_notify(__vma, __address, __ptep, __nr)	\
 ({									\
 	int __young;							\
 	struct vm_area_struct *___vma = __vma;				\
 	unsigned long ___address = __address;				\
-	__young = ptep_clear_flush_young(___vma, ___address, __ptep);	\
+	unsigned int ___nr = __nr;					\
+	__young = clear_flush_young_ptes(___vma, ___address, __ptep, ___nr);	\
 	__young |= mmu_notifier_clear_flush_young(___vma->vm_mm,	\
 						  ___address,		\
 						  ___address +		\
-							PAGE_SIZE);	\
+						nr * PAGE_SIZE);	\
 	__young;							\
 })
 
@@ -650,7 +651,7 @@ static inline void mmu_notifier_subscriptions_destroy(struct mm_struct *mm)
 
 #define mmu_notifier_range_update_to_read_only(r) false
 
-#define ptep_clear_flush_young_notify ptep_clear_flush_young
+#define ptep_clear_flush_young_notify clear_flush_young_ptes
 #define pmdp_clear_flush_young_notify pmdp_clear_flush_young
 #define ptep_clear_young_notify ptep_test_and_clear_young
 #define pmdp_clear_young_notify pmdp_test_and_clear_young
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index b13b6f42be3c..7e659f4171e2 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -947,6 +947,41 @@ static inline void wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
 }
 #endif
 
+#ifndef clear_flush_young_ptes
+/**
+ * clear_flush_young_ptes - Clear the access bit and perform a TLB flush for PTEs
+ *			    that map consecutive pages of the same folio.
+ * @vma: The virtual memory area the pages are mapped into.
+ * @addr: Address the first page is mapped at.
+ * @ptep: Page table pointer for the first entry.
+ * @nr: Number of entries to clear access bit.
+ *
+ * May be overridden by the architecture; otherwise, implemented as a simple
+ * loop over ptep_clear_flush_young().
+ *
+ * Note that PTE bits in the PTE range besides the PFN can differ. For example,
+ * some PTEs might be write-protected.
+ *
+ * Context: The caller holds the page table lock.  The PTEs map consecutive
+ * pages that belong to the same folio.  The PTEs are all in the same PMD.
+ */
+static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
+					 unsigned long addr, pte_t *ptep,
+					 unsigned int nr)
+{
+	int young;
+
+	young = ptep_clear_flush_young(vma, addr, ptep);
+	while (--nr) {
+		ptep++;
+		addr += PAGE_SIZE;
+		young |= ptep_clear_flush_young(vma, addr, ptep);
+	}
+
+	return young;
+}
+#endif
+
 /*
  * On some architectures hardware does not set page access bit when accessing
  * memory page, it is responsibility of software setting this bit. It brings
diff --git a/mm/rmap.c b/mm/rmap.c
index d6799afe1114..a0fc05f5966f 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -827,9 +827,11 @@ static bool folio_referenced_one(struct folio *folio,
 	struct folio_referenced_arg *pra = arg;
 	DEFINE_FOLIO_VMA_WALK(pvmw, folio, vma, address, 0);
 	int ptes = 0, referenced = 0;
+	unsigned int nr;
 
 	while (page_vma_mapped_walk(&pvmw)) {
 		address = pvmw.address;
+		nr = 1;
 
 		if (vma->vm_flags & VM_LOCKED) {
 			ptes++;
@@ -874,9 +876,24 @@ static bool folio_referenced_one(struct folio *folio,
 			if (lru_gen_look_around(&pvmw))
 				referenced++;
 		} else if (pvmw.pte) {
+			if (folio_test_large(folio)) {
+				unsigned long end_addr =
+					pmd_addr_end(address, vma->vm_end);
+				unsigned int max_nr =
+					(end_addr - address) >> PAGE_SHIFT;
+				pte_t pteval = ptep_get(pvmw.pte);
+
+				nr = folio_pte_batch(folio, pvmw.pte,
+						     pteval, max_nr);
+			}
+
+			ptes += nr;
 			if (ptep_clear_flush_young_notify(vma, address,
-						pvmw.pte))
+						pvmw.pte, nr))
 				referenced++;
+			/* Skip the batched PTEs */
+			pvmw.pte += nr - 1;
+			pvmw.address += (nr - 1) * PAGE_SIZE;
 		} else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) {
 			if (pmdp_clear_flush_young_notify(vma, address,
 						pvmw.pmd))
@@ -886,7 +903,15 @@ static bool folio_referenced_one(struct folio *folio,
 			WARN_ON_ONCE(1);
 		}
 
-		pra->mapcount--;
+		pra->mapcount -= nr;
+		/*
+		 * If we are sure that we batched the entire folio,
+		 * we can just optimize and stop right here.
+		 */
+		if (ptes == pvmw.nr_pages) {
+			page_vma_mapped_walk_done(&pvmw);
+			break;
+		}
 	}
 
 	if (referenced)
-- 
2.47.3



From baolin.wang at linux.alibaba.com  Thu Dec 18 22:02:52 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Fri, 19 Dec 2025 14:02:52 +0800
Subject: [PATCH v3 2/5] arm64: mm: factor out the address and ptep alignment into a new helper
In-Reply-To: <cover.1766121341.git.baolin.wang@linux.alibaba.com>
References: <cover.1766121341.git.baolin.wang@linux.alibaba.com>
Message-ID: <8606e13617bb8ec302806a6ebdbe5f680e4466a4.1766121341.git.baolin.wang@linux.alibaba.com>

Factor out the contpte block's address and ptep alignment into a new helper,
and will be reused in the following patch.

No functional changes.

Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
---
 arch/arm64/mm/contpte.c | 29 +++++++++++++++++++++--------
 1 file changed, 21 insertions(+), 8 deletions(-)

diff --git a/arch/arm64/mm/contpte.c b/arch/arm64/mm/contpte.c
index c0557945939c..c73e77207584 100644
--- a/arch/arm64/mm/contpte.c
+++ b/arch/arm64/mm/contpte.c
@@ -26,6 +26,26 @@ static inline pte_t *contpte_align_down(pte_t *ptep)
 	return PTR_ALIGN_DOWN(ptep, sizeof(*ptep) * CONT_PTES);
 }
 
+static inline pte_t *contpte_align_addr_ptep(unsigned long *start,
+					     unsigned long *end, pte_t *ptep,
+					     unsigned int nr)
+{
+	/*
+	 * Note: caller must ensure these nr PTEs are consecutive (present)
+	 * PTEs that map consecutive pages of the same large folio within a
+	 * single VMA and a single page table.
+	 */
+	if (pte_cont(__ptep_get(ptep + nr - 1)))
+		*end = ALIGN(*end, CONT_PTE_SIZE);
+
+	if (pte_cont(__ptep_get(ptep))) {
+		*start = ALIGN_DOWN(*start, CONT_PTE_SIZE);
+		ptep = contpte_align_down(ptep);
+	}
+
+	return ptep;
+}
+
 static void contpte_try_unfold_partial(struct mm_struct *mm, unsigned long addr,
 					pte_t *ptep, unsigned int nr)
 {
@@ -569,14 +589,7 @@ void contpte_clear_young_dirty_ptes(struct vm_area_struct *vma,
 	unsigned long start = addr;
 	unsigned long end = start + nr * PAGE_SIZE;
 
-	if (pte_cont(__ptep_get(ptep + nr - 1)))
-		end = ALIGN(end, CONT_PTE_SIZE);
-
-	if (pte_cont(__ptep_get(ptep))) {
-		start = ALIGN_DOWN(start, CONT_PTE_SIZE);
-		ptep = contpte_align_down(ptep);
-	}
-
+	ptep = contpte_align_addr_ptep(&start, &end, ptep, nr);
 	__clear_young_dirty_ptes(vma, start, ptep, (end - start) / PAGE_SIZE, flags);
 }
 EXPORT_SYMBOL_GPL(contpte_clear_young_dirty_ptes);
-- 
2.47.3



From baolin.wang at linux.alibaba.com  Thu Dec 18 22:02:53 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Fri, 19 Dec 2025 14:02:53 +0800
Subject: [PATCH v3 3/5] arm64: mm: support batch clearing of the young flag for large folios
In-Reply-To: <cover.1766121341.git.baolin.wang@linux.alibaba.com>
References: <cover.1766121341.git.baolin.wang@linux.alibaba.com>
Message-ID: <0fc85ceb11b26e2fd0bc164df0391c7117881c61.1766121341.git.baolin.wang@linux.alibaba.com>

Currently, contpte_ptep_test_and_clear_young() and contpte_ptep_clear_flush_young()
only clear the young flag and flush TLBs for PTEs within the contiguous range.
To support batch PTE operations for other sized large folios in the following
patches, adding a new parameter to specify the number of PTEs that map consecutive
pages of the same large folio in a single VMA and a single page table.

While we are at it, rename the functions to maintain consistency with other
contpte_*() functions.

Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
---
 arch/arm64/include/asm/pgtable.h | 12 ++++++------
 arch/arm64/mm/contpte.c          | 33 ++++++++++++++++++--------------
 2 files changed, 25 insertions(+), 20 deletions(-)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 0944e296dd4a..9086753f68b4 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -1679,10 +1679,10 @@ extern void contpte_clear_full_ptes(struct mm_struct *mm, unsigned long addr,
 extern pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
 				unsigned long addr, pte_t *ptep,
 				unsigned int nr, int full);
-extern int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
-				unsigned long addr, pte_t *ptep);
-extern int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
-				unsigned long addr, pte_t *ptep);
+int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
+				unsigned long addr, pte_t *ptep, unsigned int nr);
+int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
+				unsigned long addr, pte_t *ptep, unsigned int nr);
 extern void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
 				pte_t *ptep, unsigned int nr);
 extern int contpte_ptep_set_access_flags(struct vm_area_struct *vma,
@@ -1854,7 +1854,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
 	if (likely(!pte_valid_cont(orig_pte)))
 		return __ptep_test_and_clear_young(vma, addr, ptep);
 
-	return contpte_ptep_test_and_clear_young(vma, addr, ptep);
+	return contpte_test_and_clear_young_ptes(vma, addr, ptep, CONT_PTES);
 }
 
 #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
@@ -1866,7 +1866,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
 	if (likely(!pte_valid_cont(orig_pte)))
 		return __ptep_clear_flush_young(vma, addr, ptep);
 
-	return contpte_ptep_clear_flush_young(vma, addr, ptep);
+	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
 }
 
 #define wrprotect_ptes wrprotect_ptes
diff --git a/arch/arm64/mm/contpte.c b/arch/arm64/mm/contpte.c
index c73e77207584..c0f89af605e0 100644
--- a/arch/arm64/mm/contpte.c
+++ b/arch/arm64/mm/contpte.c
@@ -508,8 +508,9 @@ pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
 }
 EXPORT_SYMBOL_GPL(contpte_get_and_clear_full_ptes);
 
-int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
-					unsigned long addr, pte_t *ptep)
+int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
+					unsigned long addr, pte_t *ptep,
+					unsigned int nr)
 {
 	/*
 	 * ptep_clear_flush_young() technically requires us to clear the access
@@ -518,41 +519,45 @@ int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
 	 * contig range when the range is covered by a single folio, we can get
 	 * away with clearing young for the whole contig range here, so we avoid
 	 * having to unfold.
+	 *
+	 * The 'nr' means consecutive (present) PTEs that map consecutive pages
+	 * of the same large folio in a single VMA and a single page table.
 	 */
 
+	unsigned long end = addr + nr * PAGE_SIZE;
 	int young = 0;
-	int i;
 
-	ptep = contpte_align_down(ptep);
-	addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
-
-	for (i = 0; i < CONT_PTES; i++, ptep++, addr += PAGE_SIZE)
+	ptep = contpte_align_addr_ptep(&addr, &end, ptep, nr);
+	for (; addr != end; ptep++, addr += PAGE_SIZE)
 		young |= __ptep_test_and_clear_young(vma, addr, ptep);
 
 	return young;
 }
-EXPORT_SYMBOL_GPL(contpte_ptep_test_and_clear_young);
+EXPORT_SYMBOL_GPL(contpte_test_and_clear_young_ptes);
 
-int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
-					unsigned long addr, pte_t *ptep)
+int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
+				unsigned long addr, pte_t *ptep,
+				unsigned int nr)
 {
 	int young;
 
-	young = contpte_ptep_test_and_clear_young(vma, addr, ptep);
+	young = contpte_test_and_clear_young_ptes(vma, addr, ptep, nr);
 
 	if (young) {
+		unsigned long end = addr + nr * PAGE_SIZE;
+
+		contpte_align_addr_ptep(&addr, &end, ptep, nr);
 		/*
 		 * See comment in __ptep_clear_flush_young(); same rationale for
 		 * eliding the trailing DSB applies here.
 		 */
-		addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
-		__flush_tlb_range_nosync(vma->vm_mm, addr, addr + CONT_PTE_SIZE,
+		__flush_tlb_range_nosync(vma->vm_mm, addr, end,
 					 PAGE_SIZE, true, 3);
 	}
 
 	return young;
 }
-EXPORT_SYMBOL_GPL(contpte_ptep_clear_flush_young);
+EXPORT_SYMBOL_GPL(contpte_clear_flush_young_ptes);
 
 void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
 					pte_t *ptep, unsigned int nr)
-- 
2.47.3



From baolin.wang at linux.alibaba.com  Thu Dec 18 22:02:54 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Fri, 19 Dec 2025 14:02:54 +0800
Subject: [PATCH v3 4/5] arm64: mm: implement the architecture-specific clear_flush_young_ptes()
In-Reply-To: <cover.1766121341.git.baolin.wang@linux.alibaba.com>
References: <cover.1766121341.git.baolin.wang@linux.alibaba.com>
Message-ID: <511d0f46d5f02f5e1ecc67318bc2ce8997208c85.1766121341.git.baolin.wang@linux.alibaba.com>

Implement the Arm64 architecture-specific clear_flush_young_ptes() to enable
batched checking of young flags and TLB flushing, improving performance during
large folio reclamation.

Performance testing:
Allocate 10G clean file-backed folios by mmap() in a memory cgroup, and try to
reclaim 8G file-backed folios via the memory.reclaim interface. I can observe
33% performance improvement on my Arm64 32-core server (and 10%+ improvement
on my X86 machine). Meanwhile, the hotspot folio_check_references() dropped
from approximately 35% to around 5%.

W/o patchset:
real	0m1.518s
user	0m0.000s
sys	0m1.518s

W/ patchset:
real	0m1.018s
user	0m0.000s
sys	0m1.018s

Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
---
 arch/arm64/include/asm/pgtable.h | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 9086753f68b4..c57eda654d9b 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -1869,6 +1869,17 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
 	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
 }
 
+#define clear_flush_young_ptes clear_flush_young_ptes
+static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
+					unsigned long addr, pte_t *ptep,
+					unsigned int nr)
+{
+	if (likely(nr == 1 && !pte_cont(__ptep_get(ptep))))
+		return __ptep_clear_flush_young(vma, addr, ptep);
+
+	return contpte_clear_flush_young_ptes(vma, addr, ptep, nr);
+}
+
 #define wrprotect_ptes wrprotect_ptes
 static __always_inline void wrprotect_ptes(struct mm_struct *mm,
 				unsigned long addr, pte_t *ptep, unsigned int nr)
-- 
2.47.3



From baolin.wang at linux.alibaba.com  Thu Dec 18 22:02:55 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Fri, 19 Dec 2025 14:02:55 +0800
Subject: [PATCH v3 5/5] mm: rmap: support batched unmapping for file large folios
In-Reply-To: <cover.1766121341.git.baolin.wang@linux.alibaba.com>
References: <cover.1766121341.git.baolin.wang@linux.alibaba.com>
Message-ID: <cb6ca508c6800a1feef5ce31f96aa1e55ddd6c97.1766121341.git.baolin.wang@linux.alibaba.com>

Similar to folio_referenced_one(), we can apply batched unmapping for file
large folios to optimize the performance of file folios reclamation.

Barry previously implemented batched unmapping for lazyfree anonymous large
folios[1] and did not further optimize anonymous large folios or file-backed
large folios at that stage. As for file-backed large folios, the batched
unmapping support is relatively straightforward, as we only need to clear
the consecutive (present) PTE entries for file-backed large folios.

Performance testing:
Allocate 10G clean file-backed folios by mmap() in a memory cgroup, and try to
reclaim 8G file-backed folios via the memory.reclaim interface. I can observe
75% performance improvement on my Arm64 32-core server (and 50%+ improvement
on my X86 machine) with this patch.

W/o patch:
real    0m1.018s
user    0m0.000s
sys     0m1.018s

W/ patch:
real	0m0.249s
user	0m0.000s
sys	0m0.249s

[1] https://lore.kernel.org/all/20250214093015.51024-4-21cnbao at gmail.com/T/#u
Acked-by: Barry Song <baohua at kernel.org>
Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
---
 mm/rmap.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/mm/rmap.c b/mm/rmap.c
index a0fc05f5966f..7482121d4e92 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1862,9 +1862,10 @@ static inline unsigned int folio_unmap_pte_batch(struct folio *folio,
 	end_addr = pmd_addr_end(addr, vma->vm_end);
 	max_nr = (end_addr - addr) >> PAGE_SHIFT;
 
-	/* We only support lazyfree batching for now ... */
-	if (!folio_test_anon(folio) || folio_test_swapbacked(folio))
+	/* We only support lazyfree or file folios batching for now ... */
+	if (folio_test_anon(folio) && folio_test_swapbacked(folio))
 		return 1;
+
 	if (pte_unused(pte))
 		return 1;
 
@@ -2230,7 +2231,7 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
 			 *
 			 * See Documentation/mm/mmu_notifier.rst
 			 */
-			dec_mm_counter(mm, mm_counter_file(folio));
+			add_mm_counter(mm, mm_counter_file(folio), -nr_pages);
 		}
 discard:
 		if (unlikely(folio_test_hugetlb(folio))) {
-- 
2.47.3



From nicolinc at nvidia.com  Thu Dec 18 22:05:19 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Thu, 18 Dec 2025 22:05:19 -0800
Subject: [PATCH rc v4 1/4] iommu/arm-smmu-v3: Add update_safe bits to fix
 STE update sequence
In-Reply-To: <aUQuYdFKYlFeQGCg@google.com>
References: <cover.1765945258.git.nicolinc@nvidia.com>
 <58f5af553fa7c3b5fd16f1eb13a81ae428f85678.1765945258.git.nicolinc@nvidia.com>
 <aUQuYdFKYlFeQGCg@google.com>
Message-ID: <aUTrHxXHfx0bMqZ5@Asurada-Nvidia>

Hi Mostafa,

On Thu, Dec 18, 2025 at 04:40:01PM +0000, Mostafa Saleh wrote:
> On Tue, Dec 16, 2025 at 08:25:59PM -0800, Nicolin Chen wrote:
> > From: Jason Gunthorpe <jgg at nvidia.com>
> > 
> > C_BAD_STE was observed when updating nested STE from an S1-bypass mode to
> > an S1DSS-bypass mode. As both modes enabled S2, the used bit is slightly
> > different than the normal S1-bypass and S1DSS-bypass modes. As a result,
> > fields like MEV and EATS in S2's used list marked the word1 as a critical
> > word that requested a STE.V=0. This breaks a hitless update.
> > 
> > However, both MEV and EATS aren't critical in terms of STE update. One
> > controls the merge of the events and the other controls the ATS that is
> > managed by the driver at the same time via pci_enable_ats().
> > 
> > Add an arm_smmu_get_ste_update_safe() to allow STE update algorithm to
> > relax those fields, avoiding the STE update breakages.
> > 
> > After this change, entry_set has no caller checking its return value, so
> > change it to void.
> > 
> > Note that this change is required by both MEV and EATS fields, which were
> > introduced in different kernel versions. So add get_update_safe() first.
> > MEV and EATS will be added to arm_smmu_get_ste_update_safe() separately.
> > 
> > Fixes: 1e8be08d1c91 ("iommu/arm-smmu-v3: Support IOMMU_DOMAIN_NESTED")
> > Cc: stable at vger.kernel.org
> > Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
> > Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
> > Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
 
> Reviewed-by: Mostafa Saleh <smostafa at google.com>

I failed to add the two review tags of yours into the v5..

Would you mind replying with your tags once again to v5?

Sorry for the inconvenience!

Nicolin


From 21cnbao at gmail.com  Thu Dec 18 22:12:28 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Fri, 19 Dec 2025 14:12:28 +0800
Subject: [PATCH 0/6] dma-mapping: arm64: support batched cache sync
In-Reply-To: <20251219053658.84978-1-21cnbao@gmail.com>
References: <20251219053658.84978-1-21cnbao@gmail.com>
Message-ID: <CAGsJ_4yKeUHgxRJJHiOcdaVcV1pjeHRjbybvEs5YLm=AJoe-Dw@mail.gmail.com>

It is unclear why, but the cover letter was missed in the
initial posting, even though Gmail shows it as sent. I am
resending it here as a reply to check whether it appears on
the mailing list. Apologies for the inconvenience.

On Fri, Dec 19, 2025 at 1:37?PM Barry Song <21cnbao at gmail.com> wrote:
>
> From: Barry Song <v-songbaohua at oppo.com>
>
> Many embedded ARM64 SoCs still lack hardware cache coherency support, which
> causes DMA mapping operations to appear as hotspots in on-CPU flame graphs.
>
> For an SG list with *nents* entries, the current dma_map/unmap_sg() and DMA
> sync APIs perform cache maintenance one entry at a time. After each entry,
> the implementation synchronously waits for the corresponding region?s
> D-cache operations to complete. On architectures like arm64, efficiency can
> be improved by issuing all entries? operations first and then performing a
> single batched wait for completion.
>
> Tangquan's results show that batched synchronization can reduce
> dma_map_sg() time by 64.61% and dma_unmap_sg() time by 66.60% on an MTK
> phone platform (MediaTek Dimensity 9500). The tests were performed by
> pinning the task to CPU7 and fixing the CPU frequency at 2.6 GHz,
> running dma_map_sg() and dma_unmap_sg() on 10 MB buffers (10 MB / 4 KB
> sg entries per buffer) for 200 iterations and then averaging the
> results.
>
> I also ran this patch set on an RK3588 Rock5B+ board and
> observed that millions of DMA sync operations were batched.
>
> diff with RFC:
>  * Dropped lots of #ifdef/#else/#endif according to Catalin and Marek,
>   thanks!
>  * Also add iova link/unlink batches, which is marked as RFC as i lack
>    hardware. This is suggested by Marek, thanks!
>
> RFC link:
>  https://lore.kernel.org/lkml/20251029023115.22809-1-21cnbao at gmail.com/
>
> Barry Song (6):
>   arm64: Provide dcache_by_myline_op_nosync helper
>   arm64: Provide dcache_clean_poc_nosync helper
>   arm64: Provide dcache_inval_poc_nosync helper
>   arm64: Provide arch_sync_dma_ batched helpers
>   dma-mapping: Allow batched DMA sync operations if supported by the
>     arch
>   dma-iommu: Allow DMA sync batching for IOVA link/unlink
>
>  arch/arm64/Kconfig                  |  1 +
>  arch/arm64/include/asm/assembler.h  | 79 +++++++++++++++++++-------
>  arch/arm64/include/asm/cacheflush.h |  2 +
>  arch/arm64/mm/cache.S               | 58 +++++++++++++++----
>  arch/arm64/mm/dma-mapping.c         | 24 ++++++++
>  drivers/iommu/dma-iommu.c           | 12 +++-
>  include/linux/dma-map-ops.h         | 22 ++++++++
>  kernel/dma/Kconfig                  |  3 +
>  kernel/dma/direct.c                 | 28 +++++++---
>  kernel/dma/direct.h                 | 86 +++++++++++++++++++++++++----
>  10 files changed, 262 insertions(+), 53 deletions(-)
>
> --
> 2.39.3 (Apple Git-146)
>


From chou.cosmo at gmail.com  Thu Dec 18 22:29:48 2025
From: chou.cosmo at gmail.com (Cosmo Chou)
Date: Fri, 19 Dec 2025 14:29:48 +0800
Subject: [PATCH] ARM: dts: aspeed: bletchley: Remove try-power-role from connectors
Message-ID: <20251219062948.528824-1-chou.cosmo@gmail.com>

Remove the "try-power-role = sink" property from all USB-C connectors.
The try mechanism is unnecessary and wastes time during connection.
Since power-role = "dual" is already configured, standard USB PD
negotiation is sufficient and more efficient.

Signed-off-by: Cosmo Chou <chou.cosmo at gmail.com>
---
 arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts
index 7c27bf6bb51d..d1a04b63df9e 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts
+++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts
@@ -414,7 +414,6 @@ connector {
 			label = "USB-C";
 			pd-revision = /bits/ 8 <0x2 0x0 0x1 0x20>;
 			power-role = "dual";
-			try-power-role = "sink";
 			data-role = "dual";
 			source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
 			sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
@@ -501,7 +500,6 @@ connector {
 			label = "USB-C";
 			pd-revision = /bits/ 8 <0x2 0x0 0x1 0x20>;
 			power-role = "dual";
-			try-power-role = "sink";
 			data-role = "dual";
 			source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
 			sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
@@ -588,7 +586,6 @@ connector {
 			label = "USB-C";
 			pd-revision = /bits/ 8 <0x2 0x0 0x1 0x20>;
 			power-role = "dual";
-			try-power-role = "sink";
 			data-role = "dual";
 			source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
 			sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
@@ -675,7 +672,6 @@ connector {
 			label = "USB-C";
 			pd-revision = /bits/ 8 <0x2 0x0 0x1 0x20>;
 			power-role = "dual";
-			try-power-role = "sink";
 			data-role = "dual";
 			source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
 			sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
@@ -762,7 +758,6 @@ connector {
 			label = "USB-C";
 			pd-revision = /bits/ 8 <0x2 0x0 0x1 0x20>;
 			power-role = "dual";
-			try-power-role = "sink";
 			data-role = "dual";
 			source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
 			sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
@@ -849,7 +844,6 @@ connector {
 			label = "USB-C";
 			pd-revision = /bits/ 8 <0x2 0x0 0x1 0x20>;
 			power-role = "dual";
-			try-power-role = "sink";
 			data-role = "dual";
 			source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
 			sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
-- 
2.43.0



From peng.fan at oss.nxp.com  Thu Dec 18 22:36:48 2025
From: peng.fan at oss.nxp.com (Peng Fan)
Date: Fri, 19 Dec 2025 14:36:48 +0800
Subject: [PATCH v23 0/7] firmware: imx: driver for NXP secure-enclave
In-Reply-To: <20251219-imx-se-if-v23-0-5c6773d00318@nxp.com>
References: <20251219-imx-se-if-v23-0-5c6773d00318@nxp.com>
Message-ID: <aUTybpjIEoFFOC3o@shlinux89>

>Pankaj Gupta (7):
>      Documentation/firmware: add imx/se to other_interfaces
>      dt-bindings: arm: fsl: add imx-se-fw binding doc
>      firmware: imx: add driver for NXP EdgeLock Enclave
>      firmware: imx: device context dedicated to priv
>      firmware: drivers: imx: adds miscdev
>      arm64: dts: imx8ulp: add secure enclave node
>      arm64: dts: imx8ulp-evk: add reserved memory property
>

Tested-by: Peng Fan <peng.fan at nxp.com> #i.MX8ULP-EVK

Regards
Peng.


From herbert at gondor.apana.org.au  Thu Dec 18 22:58:25 2025
From: herbert at gondor.apana.org.au (Herbert Xu)
Date: Fri, 19 Dec 2025 14:58:25 +0800
Subject: [PATCH][next] crypto: sun8i-ss - Avoid
 -Wflex-array-member-not-at-end warning
In-Reply-To: <aSQhQh1xyp-zauPM@kspp>
References: <aSQhQh1xyp-zauPM@kspp>
Message-ID: <aUT3keNXVOUw2lOg@gondor.apana.org.au>

On Mon, Nov 24, 2025 at 06:11:30PM +0900, Gustavo A. R. Silva wrote:
> -Wflex-array-member-not-at-end was introduced in GCC-14, and we are
> getting ready to enable it, globally.
> 
> Move the conflicting declaration to the end of the corresponding
> structure. Notice that `struct ahash_request` is a flexible structure,
> this is a structure that contains a flexible-array member.
> 
> With these changes fix the following warning:
> 
> drivers/crypto/allwinner/sun8i-ss/sun8i-ss.h:251:30: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]
> 
> Signed-off-by: Gustavo A. R. Silva <gustavoars at kernel.org>
> ---
>  drivers/crypto/allwinner/sun8i-ss/sun8i-ss.h | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)

Patch applied.  Thanks.
-- 
Email: Herbert Xu <herbert at gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt


From songwei.chai at oss.qualcomm.com  Thu Dec 18 22:58:55 2025
From: songwei.chai at oss.qualcomm.com (Songwei Chai)
Date: Thu, 18 Dec 2025 22:58:55 -0800
Subject: [PATCH v9 0/7] Provide support for Trigger Generation Unit
Message-ID: <20251219065902.2296896-1-songwei.chai@oss.qualcomm.com>

We propose creating a new qcom directory under drivers/hwtracing
to host this TGU driver, as well as additional Qualcomm-specific
hwtracing drivers that we plan to submit in the coming months.
This structure will help organize vendor-specific implementations
and facilitate future development and maintenance.

Feedback from the community on this proposal is highly appreciated.

- Why we are proposing this:

TGU has the ability to monitor signal conditions and trigger debug-related
actions, serving as a programmable hardware component that enhances system
trace and debug capabilities. Placing it under drivers/hwtracing aligns with
its function as a trace generation utility.

We previously attempted to push this driver to drivers/hwtracing/coresight,
but did not receive support from the maintainers of the CoreSight subsystem.
The reason provided was: ?This component is primarily a part of the
Qualcomm proprietary QPMDA subsystem, and is capable of operating
independently from the CoreSight hardware trace generation system.?

Chat history : https://lore.kernel.org/all/CAJ9a7ViKxHThyZfFFDV_FkNRimk4uo1NrMtQ-kcaj1qO4ZcGnA at mail.gmail.com/

Given this, we have been considering whether it would be appropriate
to create a dedicated drivers/hwtracing/qcom directory for
Qualcomm-related hwtracing drivers. This would follow the precedent set
by Intel, which maintains its own directory at drivers/hwtracing/intel_th.
We believe this structure would significantly facilitate
future submissions of related Qualcomm drivers.

- Maintenance of drivers/hwtracing/qcom:

Bjorn, who maintains linux-arm-msm, will be the maintainer of this
directory ? we?ve discussed this with him and he?s aware that his task
list may grow accordingly. Additionally, Qualcomm engineers familiar with
the debug hardware ? such as [Tingwei Zhang, Jinlong Mao, Songwei Chai],
will be available to review incoming patches and support ongoing
development.

- Detail for TGU:

This component can be utilized to sense a plurality of signals and
create a trigger into the CTI or generate interrupts to processors
once the input signal meets the conditions. We can treat the TGU?s
workflow as a flowsheet, it has some ?steps? regions for customization.
In each step region, we can set the signals that we want with priority
in priority_group, set the conditions in each step via condition_decode,
and set the resultant action by condition_select. Meanwhile,
some TGUs (not all) also provide timer/counter functionality.
Based on the characteristics described above, we consider the TGU as a
helper in the CoreSight subsystem. Its master device is the TPDM, which
can transmit signals from other subsystems, and we reuse the existing
ports mechanism to link the TPDM to the connected TGU.

Here is a detailed example to explain how to use the TGU:

In this example, the TGU is configured to use 2 conditions, 2 steps, and
the timer. The goal is to look for one of two patterns which are generated
from TPDM, giving priority to one, and then generate a trigger once the
timer reaches a certain value. In other words, two conditions are used
for the first step to look for the two patterns, where the one with the
highest priority is used in the first condition. Then, in the second step,
the timer is enabled and set to be compared to the given value at each
clock cycle. These steps are better shown below.
    
              |-----------------|
              |                 |
              |       TPDM      |
              |                 |
              |-----------------|
                       |
                       |
    --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ------
    |                  |                                                 |
    |                  |                          |--------------------| |
    |    |---- --->    |                          |  Go to next steps  | |
    |    |             |                |--- ---> |  Enable timer      | |
    |    |             v                |         |                    | |
    |    |    |-----------------|       |         |--------------------| |
    |    |    |                 |  Yes  |                    |           |
    |    |    |   inputs==0xB   | ----->|                    | <-------- |
    |    |    |                 |       |                    |      No | |
    | No |    |-----------------|       |                    v         | |
    |    |             |                |          |-----------------| | |
    |    |             |                |          |                 | | |
    |    |             |                |          |      timer>=3   |-- |
    |    |             v                |          |                 |   |
    |    |    |-----------------|       |          |-----------------|   |
    |    |    |                 |  Yes  |                    |           |
    |    |--- |   inputs==0xA   | ----->|                    | Yes       |
    |         |                 |                            |           |
    |         |-----------------|                            v           |
    |                                              |-----------------|   |
    |                                              |                 |   |
    |                                              |      Trigger    |   |
    |                                              |                 |   |
    |                                              |-----------------|   |
    |  TGU                                                   |           |
    |--- --- --- --- --- --- --- --- --- --- --- --- --- --- |--- --- -- |
                                                             |
                                                             v
                                                    |-----------------|
                                                    |The controllers  |
                                                    |which will use   |
                                                    |triggers further |
                                                    |-----------------|

steps:
    1. Reset TGU /*it will disable tgu and reset dataset*/
    - echo 1 > /sys/bus/amba/devices/<tgu-name>/reset_tgu

    2. Set the pattern match for priority0 to 0xA = 0b1010 and for
       priority 1 to 0xB = 0b1011.
    - echo 0x11113232 > /sys/bus/amba/devices/<tgu-name>/step0_priority0/reg0
    - echo 0x11113233 > /sys/bus/amba/devices/<tgu-name>/step0_priority1/reg0

    Note:
        Bit distribution diagram for each priority register
    |-------------------------------------------------------------------|
    |   Bits          |       Field Nam   |    Description              |
    |-------------------------------------------------------------------|
    |                 |                   | 00 = bypass for OR output   |
    |     29:28       |   SEL_BIT7_TYPE2  | 01 = bypass for AND output  |
    |                 |                   | 10 = sense input '0' is true|
    |                 |                   | 11 = sense input '1' is true|
    |-------------------------------------------------------------------|
    |                 |                   | 00 = bypass for OR output   |
    |     25:24       |   SEL_BIT6_TYPE2  | 01 = bypass for AND output  |
    |                 |                   | 10 = sense input '0' is true|
    |                 |                   | 11 = sense input '1' is true|
    |-------------------------------------------------------------------|
    |                 |                   | 00 = bypass for OR output   |
    |     21:20       |   SEL_BIT5_TYPE2  | 01 = bypass for AND output  |
    |                 |                   | 10 = sense input '0' is true|
    |                 |                   | 11 = sense input '1' is true|
    |-------------------------------------------------------------------|
    |                 |                   | 00 = bypass for OR output   |
    |     17:16       |   SEL_BIT4_TYPE2  | 01 = bypass for AND output  |
    |                 |                   | 10 = sense input '0' is true|
    |                 |                   | 11 = sense input '1' is true|
    |-------------------------------------------------------------------|
    |                 |                   | 00 = bypass for OR output   |
    |     13:12       |   SEL_BIT3_TYPE2  | 01 = bypass for AND output  |
    |                 |                   | 10 = sense input '0' is true|
    |                 |                   | 11 = sense input '1' is true|
    |-------------------------------------------------------------------|
    |                 |                   | 00 = bypass for OR output   |
    |      9:8        |   SEL_BIT2_TYPE2  | 01 = bypass for AND output  |
    |                 |                   | 10 = sense input '0' is true|
    |                 |                   | 11 = sense input '1' is true|
    |-------------------------------------------------------------------|
    |                 |                   | 00 = bypass for OR output   |
    |      5:4        |  SEL_BIT1_TYPE2   | 01 = bypass for AND output  |
    |                 |                   | 10 = sense input '0' is true|
    |                 |                   | 11 = sense input '1' is true|
    |-------------------------------------------------------------------|
    |                 |                   | 00 = bypass for OR output   |
    |      1:0        |  SEL_BIT0_TYPE2   | 01 = bypass for AND output  |
    |                 |                   | 10 = sense input '0' is true|
    |                 |                   | 11 = sense input '1' is true|
    |-------------------------------------------------------------------|
    These bits are used to identify the signals we want to sense, with
    a maximum signal number of 140. For example, to sense the signal
    0xA (binary 1010), we set the value of bits 0 to 13 to 3232, which
    represents 1010. The remaining bits are set to 1, as we want to use
    AND gate to summarize all the signals we want to sense here. For
    rising or falling edge detection of any input to the priority, set
    the remaining bits to 0 to use an OR gate.

    3. look for the pattern for priority_i i=0,1.
    - echo 0x3 > /sys/bus/amba/devices/<tgu-name>/step0_condition_decode/reg0
    - echo 0x30 > /sys/bus/amba/devices/<tgu-name>/step0_condition_decode/reg1

    |-------------------------------------------------------------------------------|
    |   Bits          |    Field Nam        |            Description                |
    |-------------------------------------------------------------------------------|
    |                 |                     |For each decoded condition, this       |
    |      24         |       NOT           |inverts the output. If the condition   |
    |                 |                     |decodes to true, and the NOT field     |
    |                 |                     |is '1', then the output is NOT true.   |
    |-------------------------------------------------------------------------------|
    |                 |                     |When '1' the output from the associated|
    |      21         |  BC0_COMP_ACTIVE    |comparator will be actively included in|
    |                 |                     |the decoding of this particular        |
    |                 |                     |condition.                             |
    |-------------------------------------------------------------------------------|
    |                 |                     |When '1' the output from the associated|
    |                 |                     |comparator will need to be 1 to affect |
    |      20         |   BC0_COMP_HIGH     |the decoding of this condition.        |
    |                 |                     |Conversely, a '0' here requires a '0'  |
    |                 |                     |from the comparator                    |
    |-------------------------------------------------------------------------------|
    |                 |                     |When '1' the output from the associated|
    |      17         |                     |comparator will be actively included in|
    |                 |  TC0_COMP_ACTIVE    |the decoding of this particular        |
    |                 |                     |condition.                             |
    |-------------------------------------------------------------------------------|
    |                 |                     |When '1' the output from the associated|
    |                 |                     |comparator will need to be 1 to affect |
    |      16         |  TC0_COMP_HIGH      |the decoding of this particular        |
    |                 |                     |condition.Conversely, a 0 here         |
    |                 |                     |requires a '0' from the comparator     |
    |-------------------------------------------------------------------------------|
    |                 |                     |When '1' the output from Priority_n    |
    |                 |                     |OR logic will be actively              |
    |     4n+3        | Priority_n_OR_ACTIVE|included in the decoding of            |
    |                 |    (n=0,1,2,3)      |this particular condition.             |
    |                 |                     |                                       |
    |-------------------------------------------------------------------------------|
    |                 |                     |When '1' the output from Priority_n    |
    |                 |                     |will need to be '1' to affect the      |
    |     4n+2        |  Priority_n_OR_HIGH |decoding of this particular            |
    |                 |    (n=0,1,2,3)      |condition. Conversely, a '0' here      |
    |                 |                     |requires a '0' from Priority_n OR logic|
    |-------------------------------------------------------------------------------|
    |                 |                     |When '1' the output from Priority_n    |
    |                 |                     |AND logic will be actively             |
    |     4n+1        |Priority_n_AND_ACTIVE|included in the decoding of this       |
    |                 |  (n=0,1,2,3)        |particular condition.                  |
    |                 |                     |                                       |
    |-------------------------------------------------------------------------------|
    |                 |                     |When '1' the output from Priority_n    |
    |                 |                     |AND logic will need to be '1' to       |
    |      4n         | Priority_n_AND_HIGH |affect the decoding of this            |
    |                 |   (n=0,1,2,3)       |particular condition. Conversely,      |
    |                 |                     |a '0' here requires a '0' from         |
    |                 |                     |Priority_n AND logic.                  |
    |-------------------------------------------------------------------------------|
    Since we use `priority_0` and `priority_1` with an AND output in step 2, we set `0x3`
    and `0x30` here to activate them.

    4. Set NEXT_STEP = 1 and TC0_ENABLE = 1 so that when the conditions
       are met then the next step will be step 1 and the timer will be enabled.
    - echo 0x20008 > /sys/bus/amba/devices/<tgu-name>/step0_condition_select/reg0
    - echo 0x20008 > /sys/bus/amba/devices/<tgu-name>/step0_condition_select/reg1

    |-----------------------------------------------------------------------------|
    |   Bits          |       Field Nam   |            Description                |
    |-----------------------------------------------------------------------------|
    |                 |                   |This field defines the next step the   |
    |    18:17        |     NEXT_STEP     |TGU will 'goto' for the associated     |
    |                 |                   |Condition and Step.                    |
    |-----------------------------------------------------------------------------|
    |                 |                   |For each possible output trigger       |
    |    13           |     TRIGGER       |available, set a '1' if you want       |
    |                 |                   |the trigger to go active for the       |
    |                 |                   |associated condition and Step.         |
    |-----------------------------------------------------------------------------|
    |                 |                   |This will cause BC0 to increment if the|
    |    9            |     BC0_INC       |associated Condition is decoded for    |
    |                 |                   |this step.                             |
    |-----------------------------------------------------------------------------|
    |                 |                   |This will cause BC0 to decrement if the|
    |    8            |     BC0_DEC       |associated Condition is decoded for    |
    |                 |                   |this step.                             |
    |-----------------------------------------------------------------------------|
    |                 |                   |This will clear BC0 count value to 0 if|
    |    7            |     BC0_CLEAR     |the associated Condition is decoded    |
    |                 |                   |for this step.                         |
    |-----------------------------------------------------------------------------|
    |                 |                   |This will cause TC0 to increment until |
    |    3            |     TC0_ENABLE    |paused or cleared if the associated    |
    |                 |                   |Condition is decoded for this step.    |
    |-----------------------------------------------------------------------------|
    |                 |                   |This will cause TC0 to pause until     |
    |    2            |     TC0_PAUSE     |enabled if the associated Condition    |
    |                 |                   |is decoded for this step.              |
    |-----------------------------------------------------------------------------|
    |                 |                   |This will clear TC0 count value to 0   |
    |    1            |     TC0_CLEAR     |if the associated Condition is         |
    |                 |                   |decoded for this step.                 |
    |-----------------------------------------------------------------------------|
    |                 |                   |This will set the done signal to the   |
    |    0            |     DONE          |TGU FSM if the associated Condition    |
    |                 |                   |is decoded for this step.              |
    |-----------------------------------------------------------------------------|
    Based on the distribution diagram, we set `0x20008` for `priority0` and `priority1` to
    achieve "jump to step 1 and enable TC0" once the signal is sensed.

    5. activate the timer comparison for this step.
    -  echo 0x30000  > /sys/bus/amba/devices/<tgu-name>/step1_condition_decode/reg0

    |-------------------------------------------------------------------------------|
    |                 |                     |When '1' the output from the associated|
    |      17         |                     |comparator will be actively included in|
    |                 |  TC0_COMP_ACTIVE    |the decoding of this particular        |
    |                 |                     |condition.                             |
    |-------------------------------------------------------------------------------|
    |                 |                     |When '1' the output from the associated|
    |                 |                     |comparator will need to be 1 to affect |
    |      16         |  TC0_COMP_HIGH      |the decoding of this particular        |
    |                 |                     |condition.Conversely, a 0 here         |
    |                 |                     |requires a '0' from the comparator     |
    |-------------------------------------------------------------------------------|
    Accroding to the decode distribution diagram , we give 0x30000 here to set 16th&17th bit
    to enable timer comparison.

    6. Set the NEXT_STEP = 0 and TC0_PAUSE = 1 and TC0_CLEAR = 1 once the timer
       has reached the given value.
    - echo 0x6 > /sys/bus/amba/devices/<tgu-name>/step1_condition_select/reg0

    7. Enable Trigger 0 for TGU when the condition 0 is met in step1,
       i.e. when the timer reaches 3.
    - echo 0x2000 > /sys/bus/amba/devices/<tgu-name>/step1_condition_select/default

    Note:
        1. 'default' register allows for establishing the resultant action for
        the default condition

        2. Trigger:For each possible output trigger available from
        the Design document, there are three triggers: interrupts, CTI,
        and Cross-TGU mapping.All three triggers can occur, but
        the choice of which trigger to use depends on the user's
        needs.

    8. Compare the timer to 3 in step 1.
    - echo 0x3 > /sys/bus/amba/devices/<tgu-name>/step1_timer/reg0

    9. enale tgu
    - echo 1 > /sys/bus/amba/devices/<tgu-name>/enable_tgu
---
Link to V8: https://lore.kernel.org/all/20251203090055.2432719-1-songwei.chai at oss.qualcomm.com/

Changes in V9:
- Decoupled the tgu driver from coresight header file and registered it as an amba device.
- Retained Rob's reviewed-by tag on patch1/7 since the file remains unchanged.
- Updated the sysfs node path in the Documentation directory.
---
Link to V7: https://lore.kernel.org/all/20251104064043.88972-1-songwei.chai at oss.qualcomm.com/

Changes in V8:
- Add "select" section in bindings.
- Update publish date in "sysfs-bus-coresight-devices-tgu".
---
Link to V6: https://lore.kernel.org/all/20250709104114.22240-1-songchai at qti.qualcomm.com/

Changes in V7:
- Move the TGU code location from 'drivers/hwtracing/coresight/' to 'drivers/hwtracing/qcom/'.
- Rename the spinlock used in the code from 'spinlock' to 'lock'.
- Perform the 'calculate_array_location' separately, instead of doing it within the function.
- Update the sender email address.
---
Link to V5: https://lore.kernel.org/all/20250529081949.26493-1-quic_songchai at quicinc.com/

Changes in V6:
- Replace spinlock with guard(spinlock) in tgu_enable.
- Remove redundant blank line.
- Update publish date and contact member's name in "sysfs-bus-coresight-devices-tgu".
---
Link to V4: https://patchwork.kernel.org/project/linux-arm-msm/cover/20250423101054.954066-1-quic_songchai at quicinc.com/

Changes in V5:
- Update publish date and kernel_version in "sysfs-bus-coresight-devices-tgu"
---
Link to V3: https://lore.kernel.org/all/20250227092640.2666894-1-quic_songchai at quicinc.com/

Changes in V4:
- Add changlog in coverletter.
- Correct 'year' in Copyright in patch1.
- Correct port mechansim description in patch1.
- Remove 'tgu-steps','tgu-regs','tgu-conditions','tgu-timer-counters' from dt-binding
and set them through reading DEVID register as per Mike's suggestion.
- Modify tgu_disable func to make it have single return point in patch2 as per
Mike's suggestion.
- Use sysfs_emit in enable_tgu_show func in ptach2.
- Remove redundant judgement in enable_tgu_store in patch2.
- Correct typo in description in patch3.
- Set default ret as SYSFS_GROUP_INVISIBLE, and returnret at end in pacth3 as
per Mike's suggestion.
- Remove tgu_dataset_ro definition in patch3
- Use #define constants with explanations of what they are rather than
arbitrary magic numbers in patch3 and patch4.
- Check -EINVAL before using 'calculate_array_location()' in array in patch4.
- Add 'default' in 'tgu_dataset_show''s switch part in patch4.
- Document the value needed to initiate the reset in pacth7.
- Check "value" in 'reset_tgu_store' and bail out with an error code if 0 in patch7.
- Remove dev_dbg in 'reset_tgu_store' in patch7.
---
Link to V2: https://lore.kernel.org/all/20241010073917.16023-1-quic_songchai at quicinc.com/

Changes in V3:
- Correct typo and format in dt-binding in patch1
- Rebase to the latest kernel version
---
Link to V1: https://lore.kernel.org/all/20240830092311.14400-1-quic_songchai at quicinc.com/

Changes in V2:
 - Use real name instead of login name,
 - Correct typo and format in dt-binding and code.
 - Bring order in tgu_prob(declarations with and without assignments) as per
Krzysztof's suggestion.
 - Add module device table in patch2.
 - Set const for tgu_common_grp and tgu_ids in patch2.
 - Initialize 'data' in tgu_ids to fix the warning in pacth2.
---

Songwei Chai (7):
  dt-bindings: arm: Add support for Qualcomm TGU trace
  qcom-tgu: Add TGU driver
  qcom-tgu: Add signal priority support
  qcom-tgu: Add TGU decode support
  qcom-tgu: Add support to configure next action
  qcom-tgu: Add timer/counter functionality for TGU
  qcom-tgu: Add reset node to initialize

 .../ABI/testing/sysfs-bus-amba-devices-tgu    |  51 ++
 .../devicetree/bindings/arm/qcom,tgu.yaml     |  92 +++
 drivers/Makefile                              |   1 +
 drivers/hwtracing/Kconfig                     |   2 +
 drivers/hwtracing/qcom/Kconfig                |  18 +
 drivers/hwtracing/qcom/Makefile               |   3 +
 drivers/hwtracing/qcom/tgu.c                  | 702 ++++++++++++++++++
 drivers/hwtracing/qcom/tgu.h                  | 272 +++++++
 8 files changed, 1141 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
 create mode 100644 Documentation/devicetree/bindings/arm/qcom,tgu.yaml
 create mode 100644 drivers/hwtracing/qcom/Kconfig
 create mode 100644 drivers/hwtracing/qcom/Makefile
 create mode 100644 drivers/hwtracing/qcom/tgu.c
 create mode 100644 drivers/hwtracing/qcom/tgu.h

-- 
2.34.1



From songwei.chai at oss.qualcomm.com  Thu Dec 18 22:58:56 2025
From: songwei.chai at oss.qualcomm.com (Songwei Chai)
Date: Thu, 18 Dec 2025 22:58:56 -0800
Subject: [PATCH v9 1/7] dt-bindings: arm: Add support for Qualcomm TGU trace
In-Reply-To: <20251219065902.2296896-1-songwei.chai@oss.qualcomm.com>
References: <20251219065902.2296896-1-songwei.chai@oss.qualcomm.com>
Message-ID: <20251219065902.2296896-2-songwei.chai@oss.qualcomm.com>

The Trigger Generation Unit (TGU) is designed to detect patterns or
sequences within a specific region of the System on Chip (SoC). Once
configured and activated, it monitors sense inputs and can detect a
pre-programmed state or sequence across clock cycles, subsequently
producing a trigger.

   TGU configuration space
        offset table
 x-------------------------x
 |                         |
 |                         |
 |                         |                           Step configuration
 |                         |                             space layout
 |   coresight management  |                           x-------------x
 |        registers        |                     |---> |             |
 |                         |                     |     |  reserve    |
 |                         |                     |     |             |
 |-------------------------|                     |     |-------------|
 |                         |                     |     | priority[3] |
 |         step[7]         |<--                  |     |-------------|
 |-------------------------|   |                 |     | priority[2] |
 |                         |   |                 |     |-------------|
 |           ...           |   |Steps region     |     | priority[1] |
 |                         |   |                 |     |-------------|
 |-------------------------|   |                 |     | priority[0] |
 |                         |<--                  |     |-------------|
 |         step[0]         |-------------------->      |             |
 |-------------------------|                           |  condition  |
 |                         |                           |             |
 |     control and status  |                           x-------------x
 |           space         |                           |             |
 x-------------------------x                           |Timer/Counter|
                                                       |             |
						       x-------------x
TGU Configuration in Hardware

The TGU provides a step region for user configuration, similar
to a flow chart. Each step region consists of three register clusters:

1.Priority Region: Sets the required signals with priority.
2.Condition Region: Defines specific requirements (e.g., signal A
reaches three times) and the subsequent action once the requirement is
met.
3.Timer/Counter (Optional): Provides timing or counting functionality.

Add a new tgu.yaml file to describe the bindings required to
define the TGU in the device trees.

Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Songwei Chai <songwei.chai at oss.qualcomm.com>
---
 .../devicetree/bindings/arm/qcom,tgu.yaml     | 92 +++++++++++++++++++
 1 file changed, 92 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/qcom,tgu.yaml

diff --git a/Documentation/devicetree/bindings/arm/qcom,tgu.yaml b/Documentation/devicetree/bindings/arm/qcom,tgu.yaml
new file mode 100644
index 000000000000..5b6a58ebe691
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/qcom,tgu.yaml
@@ -0,0 +1,92 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+# Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/qcom,tgu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Trigger Generation Unit - TGU
+
+description: |
+  The Trigger Generation Unit (TGU) is a Data Engine which can be utilized
+  to sense a plurality of signals and create a trigger into the CTI or
+  generate interrupts to processors. The TGU is like the trigger circuit
+  of a Logic Analyzer. The corresponding trigger logic can be realized by
+  configuring the conditions for each step after sensing the signal.
+  Once setup and enabled, it will observe sense inputs and based upon
+  the activity of those inputs, even over clock cycles, may detect a
+  preprogrammed state/sequence and then produce a trigger or interrupt.
+
+  The primary use case of the TGU is to detect patterns or sequences on a
+  given set of signals within some region to identify the issue in time
+  once there is abnormal behavior in the subsystem.
+
+maintainers:
+  - Mao Jinlong <jinlong.mao at oss.qualcomm.com>
+  - Songwei Chai <songwei.chai at oss.qualcomm.com>
+
+# Need a custom select here or 'arm,primecell' will match on lots of nodes
+select:
+  properties:
+    compatible:
+      contains:
+        enum:
+          - qcom,tgu
+  required:
+    - compatible
+
+properties:
+  compatible:
+    items:
+      - const: qcom,tgu
+      - const: arm,primecell
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: apb_pclk
+
+  in-ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+    additionalProperties: false
+
+    properties:
+      port:
+        description:
+          The port mechanism here ensures the relationship between TGU and
+          TPDM, as TPDM is one of the inputs for TGU. It will allow TGU to
+          function as TPDM's helper and enable TGU when the connected
+          TPDM is enabled.
+        $ref: /schemas/graph.yaml#/properties/port
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    tgu at 10b0e000 {
+        compatible = "qcom,tgu", "arm,primecell";
+        reg = <0x10b0e000 0x1000>;
+
+        clocks = <&aoss_qmp>;
+        clock-names = "apb_pclk";
+
+        in-ports {
+            port {
+                tgu_in_tpdm_swao: endpoint{
+                    remote-endpoint = <&tpdm_swao_out_tgu>;
+                };
+            };
+        };
+    };
+...
-- 
2.34.1



From songwei.chai at oss.qualcomm.com  Thu Dec 18 22:58:57 2025
From: songwei.chai at oss.qualcomm.com (Songwei Chai)
Date: Thu, 18 Dec 2025 22:58:57 -0800
Subject: [PATCH v9 2/7] qcom-tgu: Add TGU driver
In-Reply-To: <20251219065902.2296896-1-songwei.chai@oss.qualcomm.com>
References: <20251219065902.2296896-1-songwei.chai@oss.qualcomm.com>
Message-ID: <20251219065902.2296896-3-songwei.chai@oss.qualcomm.com>

Add driver to support device TGU (Trigger Generation Unit).
TGU is a Data Engine which can be utilized to sense a plurality of
signals and create a trigger into the CTI or generate interrupts to
processors. Add probe/enable/disable functions for tgu.

Signed-off-by: Songwei Chai <songwei.chai at oss.qualcomm.com>
---
 .../ABI/testing/sysfs-bus-amba-devices-tgu    |   9 +
 drivers/Makefile                              |   1 +
 drivers/hwtracing/Kconfig                     |   2 +
 drivers/hwtracing/qcom/Kconfig                |  18 ++
 drivers/hwtracing/qcom/Makefile               |   3 +
 drivers/hwtracing/qcom/tgu.c                  | 178 ++++++++++++++++++
 drivers/hwtracing/qcom/tgu.h                  |  51 +++++
 7 files changed, 262 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
 create mode 100644 drivers/hwtracing/qcom/Kconfig
 create mode 100644 drivers/hwtracing/qcom/Makefile
 create mode 100644 drivers/hwtracing/qcom/tgu.c
 create mode 100644 drivers/hwtracing/qcom/tgu.h

diff --git a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
new file mode 100644
index 000000000000..24dcdf1d70cc
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
@@ -0,0 +1,9 @@
+What:		/sys/bus/amba/devices/<tgu-name>/enable_tgu
+Date:		December 2025
+KernelVersion	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Songwei Chai <songwei.chai at oss.qualcomm.com>
+Description:
+		(RW) Set/Get the enable/disable status of TGU
+		Accepts only one of the 2 values -  0 or 1.
+		0 : disable TGU.
+		1 : enable TGU.
diff --git a/drivers/Makefile b/drivers/Makefile
index ccc05f1eae3e..9608a3debb1f 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -177,6 +177,7 @@ obj-$(CONFIG_RAS)		+= ras/
 obj-$(CONFIG_USB4)		+= thunderbolt/
 obj-$(CONFIG_CORESIGHT)		+= hwtracing/coresight/
 obj-y				+= hwtracing/intel_th/
+obj-y				+= hwtracing/qcom/
 obj-$(CONFIG_STM)		+= hwtracing/stm/
 obj-$(CONFIG_HISI_PTT)		+= hwtracing/ptt/
 obj-y				+= android/
diff --git a/drivers/hwtracing/Kconfig b/drivers/hwtracing/Kconfig
index 911ee977103c..8a640218eed8 100644
--- a/drivers/hwtracing/Kconfig
+++ b/drivers/hwtracing/Kconfig
@@ -7,4 +7,6 @@ source "drivers/hwtracing/intel_th/Kconfig"
 
 source "drivers/hwtracing/ptt/Kconfig"
 
+source "drivers/hwtracing/qcom/Kconfig"
+
 endmenu
diff --git a/drivers/hwtracing/qcom/Kconfig b/drivers/hwtracing/qcom/Kconfig
new file mode 100644
index 000000000000..d6f6d4b0f28e
--- /dev/null
+++ b/drivers/hwtracing/qcom/Kconfig
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# QCOM specific hwtracing drivers
+#
+menu "Qualcomm specific hwtracing drivers"
+
+config QCOM_TGU
+	tristate "QCOM Trigger Generation Unit driver"
+	help
+	  This driver provides support for Trigger Generation Unit that is
+	  used to detect patterns or sequences on a given set of signals.
+	  TGU is used to monitor a particular bus within a given region to
+	  detect illegal transaction sequences or slave responses. It is also
+	  used to monitor a data stream to detect protocol violations and to
+	  provide a trigger point for centering data around a specific event
+	  within the trace data buffer.
+
+endmenu
diff --git a/drivers/hwtracing/qcom/Makefile b/drivers/hwtracing/qcom/Makefile
new file mode 100644
index 000000000000..5a0a868c1ea0
--- /dev/null
+++ b/drivers/hwtracing/qcom/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_QCOM_TGU) += tgu.o
diff --git a/drivers/hwtracing/qcom/tgu.c b/drivers/hwtracing/qcom/tgu.c
new file mode 100644
index 000000000000..dbd1acbd2fa5
--- /dev/null
+++ b/drivers/hwtracing/qcom/tgu.c
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/amba/bus.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+
+#include "tgu.h"
+
+static void tgu_write_all_hw_regs(struct tgu_drvdata *drvdata)
+{
+	TGU_UNLOCK(drvdata->base);
+	/* Enable TGU to program the triggers */
+	writel(1, drvdata->base + TGU_CONTROL);
+	TGU_LOCK(drvdata->base);
+}
+
+static int tgu_enable(struct device *dev)
+{
+	struct tgu_drvdata *drvdata = dev_get_drvdata(dev);
+
+	guard(spinlock)(&drvdata->lock);
+	if (drvdata->enable)
+		return -EBUSY;
+
+	tgu_write_all_hw_regs(drvdata);
+	drvdata->enable = true;
+
+	return 0;
+}
+
+static int tgu_disable(struct device *dev)
+{
+	struct tgu_drvdata *drvdata = dev_get_drvdata(dev);
+
+	guard(spinlock)(&drvdata->lock);
+	if (drvdata->enable) {
+		TGU_UNLOCK(drvdata->base);
+		writel(0, drvdata->base + TGU_CONTROL);
+		TGU_LOCK(drvdata->base);
+
+		drvdata->enable = false;
+	}
+	return 0;
+}
+
+static ssize_t enable_tgu_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	bool enabled;
+	struct tgu_drvdata *drvdata = dev_get_drvdata(dev);
+
+	guard(spinlock)(&drvdata->lock);
+	enabled = drvdata->enable;
+
+	return sysfs_emit(buf, "%d\n", enabled);
+}
+
+/* enable_tgu_store - Configure Trace and Gating Unit (TGU) triggers. */
+static ssize_t enable_tgu_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf,
+				size_t size)
+{
+	int ret = 0;
+	unsigned long val;
+
+	ret = kstrtoul(buf, 0, &val);
+	if (ret)
+		return ret;
+
+	if (val) {
+		ret = pm_runtime_resume_and_get(dev);
+		if (ret)
+			return ret;
+		ret = tgu_enable(dev);
+		if (ret)
+			pm_runtime_put(dev);
+	} else {
+		ret = tgu_disable(dev);
+		pm_runtime_put(dev);
+	}
+
+	if (ret)
+		return ret;
+	return size;
+}
+static DEVICE_ATTR_RW(enable_tgu);
+
+static struct attribute *tgu_common_attrs[] = {
+	&dev_attr_enable_tgu.attr,
+	NULL,
+};
+
+static const struct attribute_group tgu_common_grp = {
+	.attrs = tgu_common_attrs,
+	NULL,
+};
+
+static const struct attribute_group *tgu_attr_groups[] = {
+	&tgu_common_grp,
+	NULL,
+};
+
+static int tgu_probe(struct amba_device *adev, const struct amba_id *id)
+{
+	struct device *dev = &adev->dev;
+	struct tgu_drvdata *drvdata;
+	int ret;
+
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+
+	drvdata->dev = &adev->dev;
+	dev_set_drvdata(dev, drvdata);
+
+	drvdata->base = devm_ioremap_resource(dev, &adev->res);
+	if (IS_ERR(drvdata->base))
+		return PTR_ERR(drvdata->base);
+
+	spin_lock_init(&drvdata->lock);
+
+	ret = sysfs_create_groups(&dev->kobj, tgu_attr_groups);
+	if (ret) {
+		dev_err(dev, "failed to create sysfs groups: %d\n", ret);
+		return ret;
+	}
+
+	drvdata->enable = false;
+
+	pm_runtime_put(&adev->dev);
+	return 0;
+}
+
+static void tgu_remove(struct amba_device *adev)
+{
+	struct device *dev = &adev->dev;
+
+	sysfs_remove_groups(&dev->kobj, tgu_attr_groups);
+
+	tgu_disable(dev);
+	dev_set_drvdata(dev, NULL);
+}
+
+static const struct amba_id tgu_ids[] = {
+	{
+		.id = 0x000f0e00,
+		.mask = 0x000fffff,
+	},
+	{ 0, 0, NULL },
+};
+
+MODULE_DEVICE_TABLE(amba, tgu_ids);
+
+static struct amba_driver tgu_driver = {
+	.drv = {
+		.name = "qcom-tgu",
+		.suppress_bind_attrs = true,
+	},
+	.probe = tgu_probe,
+	.remove = tgu_remove,
+	.id_table = tgu_ids,
+};
+
+module_amba_driver(tgu_driver);
+
+MODULE_AUTHOR("Songwei Chai <songwei.chai at oss.qualcomm.com>");
+MODULE_AUTHOR("Jinlong Mao <jinlong.mao at oss.qualcomm.com>");
+MODULE_DESCRIPTION("Qualcomm Trigger Generation Unit driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwtracing/qcom/tgu.h b/drivers/hwtracing/qcom/tgu.h
new file mode 100644
index 000000000000..abc732f91dfc
--- /dev/null
+++ b/drivers/hwtracing/qcom/tgu.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _QCOM_TGU_H
+#define _QCOM_TGU_H
+
+/* Register addresses */
+#define TGU_CONTROL 0x0000
+#define TGU_LAR		0xfb0
+#define TGU_UNLOCK_OFFSET	0xc5acce55
+
+static inline void TGU_LOCK(void __iomem *addr)
+{
+	do {
+		/* Wait for things to settle */
+		mb();
+		writel_relaxed(0x0, addr + TGU_LAR);
+	} while (0);
+}
+
+static inline void TGU_UNLOCK(void __iomem *addr)
+{
+	do {
+		writel_relaxed(TGU_UNLOCK_OFFSET, addr + TGU_LAR);
+		/* Make sure everyone has seen this */
+		mb();
+	} while (0);
+}
+
+/**
+ * struct tgu_drvdata - Data structure for a TGU (Trigger Generator Unit)
+ * @base: Memory-mapped base address of the TGU device
+ * @dev: Pointer to the associated device structure
+ * @lock: Spinlock for handling concurrent access
+ * @enable: Flag indicating whether the TGU device is enabled
+ *
+ * This structure defines the data associated with a TGU device,
+ * including its base address, device pointers, clock, spinlock for
+ * synchronization, trigger data pointers, maximum limits for various
+ * trigger-related parameters, and enable status.
+ */
+struct tgu_drvdata {
+	void __iomem *base;
+	struct device *dev;
+	spinlock_t lock;
+	bool enable;
+};
+
+#endif
-- 
2.34.1



From songwei.chai at oss.qualcomm.com  Thu Dec 18 22:58:58 2025
From: songwei.chai at oss.qualcomm.com (Songwei Chai)
Date: Thu, 18 Dec 2025 22:58:58 -0800
Subject: [PATCH v9 3/7] qcom-tgu: Add signal priority support
In-Reply-To: <20251219065902.2296896-1-songwei.chai@oss.qualcomm.com>
References: <20251219065902.2296896-1-songwei.chai@oss.qualcomm.com>
Message-ID: <20251219065902.2296896-4-songwei.chai@oss.qualcomm.com>

Like circuit of a Logic analyzer, in TGU, the requirement could be
configured in each step and the trigger will be created once the
requirements are met. Add priority functionality here to sort the
signals into different priorities. The signal which is wanted could
be configured in each step's priority node, the larger number means
the higher priority and the signal with higher priority will be sensed
more preferentially.

Signed-off-by: Songwei Chai <songwei.chai at oss.qualcomm.com>
---
 .../ABI/testing/sysfs-bus-amba-devices-tgu    |   7 +
 drivers/hwtracing/qcom/tgu.c                  | 156 ++++++++++++++++++
 drivers/hwtracing/qcom/tgu.h                  | 113 +++++++++++++
 3 files changed, 276 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
index 24dcdf1d70cc..d04a01368089 100644
--- a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
+++ b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
@@ -7,3 +7,10 @@ Description:
 		Accepts only one of the 2 values -  0 or 1.
 		0 : disable TGU.
 		1 : enable TGU.
+
+What:		/sys/bus/amba/devices/<tgu-name>/step[0:7]_priority[0:3]/reg[0:17]
+Date:		December 2025
+KernelVersion	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Songwei Chai <songwei.chai at oss.qualcomm.com>
+Description:
+		(RW) Set/Get the sensed signal with specific step and priority for TGU.
diff --git a/drivers/hwtracing/qcom/tgu.c b/drivers/hwtracing/qcom/tgu.c
index dbd1acbd2fa5..447d7e68d132 100644
--- a/drivers/hwtracing/qcom/tgu.c
+++ b/drivers/hwtracing/qcom/tgu.c
@@ -14,14 +14,121 @@
 
 #include "tgu.h"
 
+static int calculate_array_location(struct tgu_drvdata *drvdata,
+				   int step_index, int operation_index,
+				   int reg_index)
+{
+	return operation_index * (drvdata->max_step) * (drvdata->max_reg) +
+		step_index * (drvdata->max_reg) + reg_index;
+}
+
+static ssize_t tgu_dataset_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int index;
+	struct tgu_drvdata *drvdata = dev_get_drvdata(dev);
+	struct tgu_attribute *tgu_attr =
+			container_of(attr, struct tgu_attribute, attr);
+
+	index = calculate_array_location(drvdata, tgu_attr->step_index,
+					 tgu_attr->operation_index,
+					 tgu_attr->reg_num);
+
+	return sysfs_emit(buf, "0x%x\n",
+			  drvdata->value_table->priority[index]);
+}
+
+static ssize_t tgu_dataset_store(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf, size_t size)
+{
+	int index;
+	unsigned long val;
+
+	struct tgu_drvdata *tgu_drvdata = dev_get_drvdata(dev);
+	struct tgu_attribute *tgu_attr =
+		container_of(attr, struct tgu_attribute, attr);
+
+	if (kstrtoul(buf, 0, &val))
+		return -EINVAL;
+
+	guard(spinlock)(&tgu_drvdata->lock);
+	index = calculate_array_location(tgu_drvdata, tgu_attr->step_index,
+					 tgu_attr->operation_index,
+					 tgu_attr->reg_num);
+
+	tgu_drvdata->value_table->priority[index] = val;
+	return size;
+}
+
+static umode_t tgu_node_visible(struct kobject *kobject,
+				struct attribute *attr,
+				int n)
+{
+	struct device *dev = kobj_to_dev(kobject);
+	struct tgu_drvdata *drvdata = dev_get_drvdata(dev);
+	int ret = SYSFS_GROUP_INVISIBLE;
+
+	struct device_attribute *dev_attr =
+		container_of(attr, struct device_attribute, attr);
+	struct tgu_attribute *tgu_attr =
+		container_of(dev_attr, struct tgu_attribute, attr);
+
+	if (tgu_attr->step_index < drvdata->max_step) {
+		ret = (tgu_attr->reg_num < drvdata->max_reg) ?
+			attr->mode : 0;
+	}
+	return ret;
+}
+
 static void tgu_write_all_hw_regs(struct tgu_drvdata *drvdata)
 {
+	int i, j, k, index;
+
 	TGU_UNLOCK(drvdata->base);
+	for (i = 0; i < drvdata->max_step; i++) {
+		for (j = 0; j < MAX_PRIORITY; j++) {
+			for (k = 0; k < drvdata->max_reg; k++) {
+				index = calculate_array_location(
+							drvdata, i, j, k);
+
+				writel(drvdata->value_table->priority[index],
+					drvdata->base +
+					PRIORITY_REG_STEP(i, j, k));
+			}
+		}
+	}
 	/* Enable TGU to program the triggers */
 	writel(1, drvdata->base + TGU_CONTROL);
 	TGU_LOCK(drvdata->base);
 }
 
+static void tgu_set_reg_number(struct tgu_drvdata *drvdata)
+{
+	int num_sense_input;
+	int num_reg;
+	u32 devid;
+
+	devid = readl(drvdata->base + TGU_DEVID);
+
+	num_sense_input = TGU_DEVID_SENSE_INPUT(devid);
+	if (((num_sense_input * NUMBER_BITS_EACH_SIGNAL) % LENGTH_REGISTER) == 0)
+		num_reg = (num_sense_input * NUMBER_BITS_EACH_SIGNAL) / LENGTH_REGISTER;
+	else
+		num_reg = ((num_sense_input * NUMBER_BITS_EACH_SIGNAL) / LENGTH_REGISTER) + 1;
+	drvdata->max_reg = num_reg;
+
+}
+
+static void tgu_set_steps(struct tgu_drvdata *drvdata)
+{
+	u32 devid;
+
+	devid = readl(drvdata->base + TGU_DEVID);
+
+	drvdata->max_step = TGU_DEVID_STEPS(devid);
+}
+
 static int tgu_enable(struct device *dev)
 {
 	struct tgu_drvdata *drvdata = dev_get_drvdata(dev);
@@ -106,6 +213,38 @@ static const struct attribute_group tgu_common_grp = {
 
 static const struct attribute_group *tgu_attr_groups[] = {
 	&tgu_common_grp,
+	PRIORITY_ATTRIBUTE_GROUP_INIT(0, 0),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(0, 1),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(0, 2),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(0, 3),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(1, 0),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(1, 1),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(1, 2),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(1, 3),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(2, 0),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(2, 1),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(2, 2),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(2, 3),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(3, 0),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(3, 1),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(3, 2),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(3, 3),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(4, 0),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(4, 1),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(4, 2),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(4, 3),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(5, 0),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(5, 1),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(5, 2),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(5, 3),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(6, 0),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(6, 1),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(6, 2),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(6, 3),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(7, 0),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(7, 1),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(7, 2),
+	PRIORITY_ATTRIBUTE_GROUP_INIT(7, 3),
 	NULL,
 };
 
@@ -128,12 +267,29 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id)
 
 	spin_lock_init(&drvdata->lock);
 
+	tgu_set_reg_number(drvdata);
+	tgu_set_steps(drvdata);
+
 	ret = sysfs_create_groups(&dev->kobj, tgu_attr_groups);
 	if (ret) {
 		dev_err(dev, "failed to create sysfs groups: %d\n", ret);
 		return ret;
 	}
 
+	drvdata->value_table =
+		devm_kzalloc(dev, sizeof(*drvdata->value_table), GFP_KERNEL);
+	if (!drvdata->value_table)
+		return -ENOMEM;
+
+	drvdata->value_table->priority = devm_kzalloc(
+		dev,
+		MAX_PRIORITY * drvdata->max_reg * drvdata->max_step *
+			sizeof(*(drvdata->value_table->priority)),
+		GFP_KERNEL);
+
+	if (!drvdata->value_table->priority)
+		return -ENOMEM;
+
 	drvdata->enable = false;
 
 	pm_runtime_put(&adev->dev);
diff --git a/drivers/hwtracing/qcom/tgu.h b/drivers/hwtracing/qcom/tgu.h
index abc732f91dfc..2cf95c239ee7 100644
--- a/drivers/hwtracing/qcom/tgu.h
+++ b/drivers/hwtracing/qcom/tgu.h
@@ -10,6 +10,113 @@
 #define TGU_CONTROL 0x0000
 #define TGU_LAR		0xfb0
 #define TGU_UNLOCK_OFFSET	0xc5acce55
+#define TGU_DEVID	0xfc8
+
+#define BMVAL(val, lsb, msb)	((val & GENMASK(msb, lsb)) >> lsb)
+#define TGU_DEVID_SENSE_INPUT(devid_val) ((int) BMVAL(devid_val, 10, 17))
+#define TGU_DEVID_STEPS(devid_val) ((int)BMVAL(devid_val, 3, 6))
+#define NUMBER_BITS_EACH_SIGNAL 4
+#define LENGTH_REGISTER 32
+
+/*
+ *  TGU configuration space                              Step configuration
+ *  offset table                                         space layout
+ * x-------------------------x$                          x-------------x$
+ * |                         |$                          |             |$
+ * |                         |                           |   reserve   |$
+ * |                         |                           |             |$
+ * |coresight management     |                           |-------------|base+n*0x1D8+0x1F4$
+ * |     registe             |                     |---> |prioroty[3]  |$
+ * |                         |                     |     |-------------|base+n*0x1D8+0x194$
+ * |                         |                     |     |prioroty[2]  |$
+ * |-------------------------|                     |     |-------------|base+n*0x1D8+0x134$
+ * |                         |                     |     |prioroty[1]  |$
+ * |         step[7]         |                     |     |-------------|base+n*0x1D8+0xD4$
+ * |-------------------------|->base+0x40+7*0x1D8  |     |prioroty[0]  |$
+ * |                         |                     |     |-------------|base+n*0x1D8+0x74$
+ * |         ...             |                     |     |  condition  |$
+ * |                         |                     |     |   select    |$
+ * |-------------------------|->base+0x40+1*0x1D8  |     |-------------|base+n*0x1D8+0x60$
+ * |                         |                     |     |  condition  |$
+ * |         step[0]         |-------------------->      |   decode    |$
+ * |-------------------------|-> base+0x40               |-------------|base+n*0x1D8+0x50$
+ * |                         |                           |             |$
+ * | Control and status space|                           |Timer/Counter|$
+ * |        space            |                           |             |$
+ * x-------------------------x->base                     x-------------x base+n*0x1D8+0x40$
+ *
+ */
+#define STEP_OFFSET 0x1D8
+#define PRIORITY_START_OFFSET 0x0074
+#define PRIORITY_OFFSET 0x60
+#define REG_OFFSET 0x4
+
+/* Calculate compare step addresses */
+#define PRIORITY_REG_STEP(step, priority, reg)\
+	(PRIORITY_START_OFFSET + PRIORITY_OFFSET * priority +\
+	 REG_OFFSET * reg + STEP_OFFSET * step)
+
+#define tgu_dataset_rw(name, step_index, type, reg_num)                  \
+	(&((struct tgu_attribute[]){ {                                   \
+		__ATTR(name, 0644, tgu_dataset_show, tgu_dataset_store), \
+		step_index,                                              \
+		type,                                                    \
+		reg_num,                                                 \
+	} })[0].attr.attr)
+
+#define STEP_PRIORITY(step_index, reg_num, priority)                     \
+	tgu_dataset_rw(reg##reg_num, step_index, TGU_PRIORITY##priority, \
+			reg_num)
+
+#define STEP_PRIORITY_LIST(step_index, priority)  \
+	{STEP_PRIORITY(step_index, 0, priority),  \
+	 STEP_PRIORITY(step_index, 1, priority),  \
+	 STEP_PRIORITY(step_index, 2, priority),  \
+	 STEP_PRIORITY(step_index, 3, priority),  \
+	 STEP_PRIORITY(step_index, 4, priority),  \
+	 STEP_PRIORITY(step_index, 5, priority),  \
+	 STEP_PRIORITY(step_index, 6, priority),  \
+	 STEP_PRIORITY(step_index, 7, priority),  \
+	 STEP_PRIORITY(step_index, 8, priority),  \
+	 STEP_PRIORITY(step_index, 9, priority),  \
+	 STEP_PRIORITY(step_index, 10, priority), \
+	 STEP_PRIORITY(step_index, 11, priority), \
+	 STEP_PRIORITY(step_index, 12, priority), \
+	 STEP_PRIORITY(step_index, 13, priority), \
+	 STEP_PRIORITY(step_index, 14, priority), \
+	 STEP_PRIORITY(step_index, 15, priority), \
+	 STEP_PRIORITY(step_index, 16, priority), \
+	 STEP_PRIORITY(step_index, 17, priority), \
+	 NULL                   \
+	}
+
+#define PRIORITY_ATTRIBUTE_GROUP_INIT(step, priority)\
+	(&(const struct attribute_group){\
+		.attrs = (struct attribute*[])STEP_PRIORITY_LIST(step, priority),\
+		.is_visible = tgu_node_visible,\
+		.name = "step" #step "_priority" #priority \
+	})
+
+enum operation_index {
+	TGU_PRIORITY0,
+	TGU_PRIORITY1,
+	TGU_PRIORITY2,
+	TGU_PRIORITY3,
+};
+
+/* Maximum priority that TGU supports */
+#define MAX_PRIORITY 4
+
+struct tgu_attribute {
+	struct device_attribute attr;
+	u32 step_index;
+	enum operation_index operation_index;
+	u32 reg_num;
+};
+
+struct value_table {
+	unsigned int *priority;
+};
 
 static inline void TGU_LOCK(void __iomem *addr)
 {
@@ -35,6 +142,9 @@ static inline void TGU_UNLOCK(void __iomem *addr)
  * @dev: Pointer to the associated device structure
  * @lock: Spinlock for handling concurrent access
  * @enable: Flag indicating whether the TGU device is enabled
+ * @value_table: Store given value based on relevant parameters.
+ * @max_reg: Maximum number of registers
+ * @max_step: Maximum step size
  *
  * This structure defines the data associated with a TGU device,
  * including its base address, device pointers, clock, spinlock for
@@ -46,6 +156,9 @@ struct tgu_drvdata {
 	struct device *dev;
 	spinlock_t lock;
 	bool enable;
+	struct value_table *value_table;
+	int max_reg;
+	int max_step;
 };
 
 #endif
-- 
2.34.1



From songwei.chai at oss.qualcomm.com  Thu Dec 18 22:58:59 2025
From: songwei.chai at oss.qualcomm.com (Songwei Chai)
Date: Thu, 18 Dec 2025 22:58:59 -0800
Subject: [PATCH v9 4/7] qcom-tgu: Add TGU decode support
In-Reply-To: <20251219065902.2296896-1-songwei.chai@oss.qualcomm.com>
References: <20251219065902.2296896-1-songwei.chai@oss.qualcomm.com>
Message-ID: <20251219065902.2296896-5-songwei.chai@oss.qualcomm.com>

Decoding is when all the potential pieces for creating a trigger
are brought together for a given step. Example - there may be a
counter keeping track of some occurrences and a priority-group that
is being used to detect a pattern on the sense inputs. These 2
inputs to condition_decode must be programmed, for a given step,
to establish the condition for the trigger, or movement to another
steps.

Signed-off-by: Songwei Chai <songwei.chai at oss.qualcomm.com>
---
 .../ABI/testing/sysfs-bus-amba-devices-tgu    |   7 +
 drivers/hwtracing/qcom/tgu.c                  | 156 ++++++++++++++++--
 drivers/hwtracing/qcom/tgu.h                  |  27 +++
 3 files changed, 173 insertions(+), 17 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
index d04a01368089..c0e50ee95839 100644
--- a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
+++ b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
@@ -14,3 +14,10 @@ KernelVersion	6.19
 Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Songwei Chai <songwei.chai at oss.qualcomm.com>
 Description:
 		(RW) Set/Get the sensed signal with specific step and priority for TGU.
+
+What:		/sys/bus/amba/devices/<tgu-name>/step[0:7]_condition_decode/reg[0:3]
+Date:		December 2025
+KernelVersion	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Songwei Chai <songwei.chai at oss.qualcomm.com>
+Description:
+		(RW) Set/Get the decode mode with specific step for TGU.
diff --git a/drivers/hwtracing/qcom/tgu.c b/drivers/hwtracing/qcom/tgu.c
index 447d7e68d132..4140dc544e5e 100644
--- a/drivers/hwtracing/qcom/tgu.c
+++ b/drivers/hwtracing/qcom/tgu.c
@@ -18,8 +18,36 @@ static int calculate_array_location(struct tgu_drvdata *drvdata,
 				   int step_index, int operation_index,
 				   int reg_index)
 {
-	return operation_index * (drvdata->max_step) * (drvdata->max_reg) +
-		step_index * (drvdata->max_reg) + reg_index;
+	int ret = -EINVAL;
+
+	switch (operation_index) {
+	case TGU_PRIORITY0:
+	case TGU_PRIORITY1:
+	case TGU_PRIORITY2:
+	case TGU_PRIORITY3:
+		ret = operation_index * (drvdata->max_step) *
+			(drvdata->max_reg) +
+			step_index * (drvdata->max_reg) + reg_index;
+		break;
+	case TGU_CONDITION_DECODE:
+		ret = step_index * (drvdata->max_condition_decode) +
+			reg_index;
+		break;
+	default:
+		break;
+	}
+	return ret;
+}
+
+static int check_array_location(struct tgu_drvdata *drvdata, int step,
+				int ops, int reg)
+{
+	int result = calculate_array_location(drvdata, step, ops, reg);
+
+	if (result == -EINVAL)
+		dev_err(drvdata->dev, "%s - Fail\n", __func__);
+
+	return result;
 }
 
 static ssize_t tgu_dataset_show(struct device *dev,
@@ -30,12 +58,26 @@ static ssize_t tgu_dataset_show(struct device *dev,
 	struct tgu_attribute *tgu_attr =
 			container_of(attr, struct tgu_attribute, attr);
 
-	index = calculate_array_location(drvdata, tgu_attr->step_index,
-					 tgu_attr->operation_index,
-					 tgu_attr->reg_num);
+	index = check_array_location(drvdata, tgu_attr->step_index,
+			     tgu_attr->operation_index, tgu_attr->reg_num);
+
+	if (index == -EINVAL)
+		return -EINVAL;
 
-	return sysfs_emit(buf, "0x%x\n",
-			  drvdata->value_table->priority[index]);
+	switch (tgu_attr->operation_index) {
+	case TGU_PRIORITY0:
+	case TGU_PRIORITY1:
+	case TGU_PRIORITY2:
+	case TGU_PRIORITY3:
+		return sysfs_emit(buf, "0x%x\n",
+				  drvdata->value_table->priority[index]);
+	case TGU_CONDITION_DECODE:
+		return sysfs_emit(buf, "0x%x\n",
+				  drvdata->value_table->condition_decode[index]);
+	default:
+		break;
+	}
+	return -EINVAL;
 }
 
 static ssize_t tgu_dataset_store(struct device *dev,
@@ -43,6 +85,7 @@ static ssize_t tgu_dataset_store(struct device *dev,
 				 const char *buf, size_t size)
 {
 	int index;
+	int ret = -EINVAL;
 	unsigned long val;
 
 	struct tgu_drvdata *tgu_drvdata = dev_get_drvdata(dev);
@@ -50,15 +93,32 @@ static ssize_t tgu_dataset_store(struct device *dev,
 		container_of(attr, struct tgu_attribute, attr);
 
 	if (kstrtoul(buf, 0, &val))
-		return -EINVAL;
+		return ret;
 
 	guard(spinlock)(&tgu_drvdata->lock);
-	index = calculate_array_location(tgu_drvdata, tgu_attr->step_index,
+	index = check_array_location(tgu_drvdata, tgu_attr->step_index,
 					 tgu_attr->operation_index,
 					 tgu_attr->reg_num);
 
-	tgu_drvdata->value_table->priority[index] = val;
-	return size;
+	if (index == -EINVAL)
+		return ret;
+
+	switch (tgu_attr->operation_index) {
+	case TGU_PRIORITY0:
+	case TGU_PRIORITY1:
+	case TGU_PRIORITY2:
+	case TGU_PRIORITY3:
+		tgu_drvdata->value_table->priority[index] = val;
+		ret = size;
+		break;
+	case TGU_CONDITION_DECODE:
+		tgu_drvdata->value_table->condition_decode[index] = val;
+		ret = size;
+		break;
+	default:
+		break;
+	}
+	return ret;
 }
 
 static umode_t tgu_node_visible(struct kobject *kobject,
@@ -75,13 +135,27 @@ static umode_t tgu_node_visible(struct kobject *kobject,
 		container_of(dev_attr, struct tgu_attribute, attr);
 
 	if (tgu_attr->step_index < drvdata->max_step) {
-		ret = (tgu_attr->reg_num < drvdata->max_reg) ?
-			attr->mode : 0;
+		switch (tgu_attr->operation_index) {
+		case TGU_PRIORITY0:
+		case TGU_PRIORITY1:
+		case TGU_PRIORITY2:
+		case TGU_PRIORITY3:
+			ret = (tgu_attr->reg_num < drvdata->max_reg) ?
+				attr->mode : 0;
+			break;
+		case TGU_CONDITION_DECODE:
+			ret = (tgu_attr->reg_num <
+				drvdata->max_condition_decode) ?
+				attr->mode : 0;
+			break;
+		default:
+			break;
+		}
 	}
 	return ret;
 }
 
-static void tgu_write_all_hw_regs(struct tgu_drvdata *drvdata)
+static ssize_t tgu_write_all_hw_regs(struct tgu_drvdata *drvdata)
 {
 	int i, j, k, index;
 
@@ -89,8 +163,10 @@ static void tgu_write_all_hw_regs(struct tgu_drvdata *drvdata)
 	for (i = 0; i < drvdata->max_step; i++) {
 		for (j = 0; j < MAX_PRIORITY; j++) {
 			for (k = 0; k < drvdata->max_reg; k++) {
-				index = calculate_array_location(
+				index = check_array_location(
 							drvdata, i, j, k);
+				if (index == -EINVAL)
+					goto exit;
 
 				writel(drvdata->value_table->priority[index],
 					drvdata->base +
@@ -98,9 +174,23 @@ static void tgu_write_all_hw_regs(struct tgu_drvdata *drvdata)
 			}
 		}
 	}
+
+	for (i = 0; i < drvdata->max_step; i++) {
+		for (j = 0; j < drvdata->max_condition_decode; j++) {
+			index = check_array_location(drvdata, i,
+						TGU_CONDITION_DECODE, j);
+			if (index == -EINVAL)
+				goto exit;
+
+			writel(drvdata->value_table->condition_decode[index],
+				drvdata->base + CONDITION_DECODE_STEP(i, j));
+		}
+	}
 	/* Enable TGU to program the triggers */
 	writel(1, drvdata->base + TGU_CONTROL);
+exit:
 	TGU_LOCK(drvdata->base);
+	return index >= 0 ? 0 : -EINVAL;
 }
 
 static void tgu_set_reg_number(struct tgu_drvdata *drvdata)
@@ -129,18 +219,32 @@ static void tgu_set_steps(struct tgu_drvdata *drvdata)
 	drvdata->max_step = TGU_DEVID_STEPS(devid);
 }
 
+static void tgu_set_conditions(struct tgu_drvdata *drvdata)
+{
+	u32 devid;
+
+	devid = readl(drvdata->base + TGU_DEVID);
+	drvdata->max_condition_decode = TGU_DEVID_CONDITIONS(devid);
+}
+
 static int tgu_enable(struct device *dev)
 {
+	int ret = 0;
 	struct tgu_drvdata *drvdata = dev_get_drvdata(dev);
 
 	guard(spinlock)(&drvdata->lock);
 	if (drvdata->enable)
 		return -EBUSY;
 
-	tgu_write_all_hw_regs(drvdata);
+	ret = tgu_write_all_hw_regs(drvdata);
+
+	if (ret == -EINVAL)
+		goto exit;
+
 	drvdata->enable = true;
 
-	return 0;
+exit:
+	return ret;
 }
 
 static int tgu_disable(struct device *dev)
@@ -245,6 +349,14 @@ static const struct attribute_group *tgu_attr_groups[] = {
 	PRIORITY_ATTRIBUTE_GROUP_INIT(7, 1),
 	PRIORITY_ATTRIBUTE_GROUP_INIT(7, 2),
 	PRIORITY_ATTRIBUTE_GROUP_INIT(7, 3),
+	CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(0),
+	CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(1),
+	CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(2),
+	CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(3),
+	CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(4),
+	CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(5),
+	CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(6),
+	CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(7),
 	NULL,
 };
 
@@ -269,6 +381,7 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id)
 
 	tgu_set_reg_number(drvdata);
 	tgu_set_steps(drvdata);
+	tgu_set_conditions(drvdata);
 
 	ret = sysfs_create_groups(&dev->kobj, tgu_attr_groups);
 	if (ret) {
@@ -290,6 +403,15 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id)
 	if (!drvdata->value_table->priority)
 		return -ENOMEM;
 
+	drvdata->value_table->condition_decode = devm_kzalloc(
+		dev,
+		drvdata->max_condition_decode * drvdata->max_step *
+			sizeof(*(drvdata->value_table->condition_decode)),
+		GFP_KERNEL);
+
+	if (!drvdata->value_table->condition_decode)
+		return -ENOMEM;
+
 	drvdata->enable = false;
 
 	pm_runtime_put(&adev->dev);
diff --git a/drivers/hwtracing/qcom/tgu.h b/drivers/hwtracing/qcom/tgu.h
index 2cf95c239ee7..732126b896e1 100644
--- a/drivers/hwtracing/qcom/tgu.h
+++ b/drivers/hwtracing/qcom/tgu.h
@@ -15,6 +15,7 @@
 #define BMVAL(val, lsb, msb)	((val & GENMASK(msb, lsb)) >> lsb)
 #define TGU_DEVID_SENSE_INPUT(devid_val) ((int) BMVAL(devid_val, 10, 17))
 #define TGU_DEVID_STEPS(devid_val) ((int)BMVAL(devid_val, 3, 6))
+#define TGU_DEVID_CONDITIONS(devid_val) ((int)BMVAL(devid_val, 0, 2))
 #define NUMBER_BITS_EACH_SIGNAL 4
 #define LENGTH_REGISTER 32
 
@@ -48,6 +49,7 @@
  */
 #define STEP_OFFSET 0x1D8
 #define PRIORITY_START_OFFSET 0x0074
+#define CONDITION_DECODE_OFFSET 0x0050
 #define PRIORITY_OFFSET 0x60
 #define REG_OFFSET 0x4
 
@@ -56,6 +58,9 @@
 	(PRIORITY_START_OFFSET + PRIORITY_OFFSET * priority +\
 	 REG_OFFSET * reg + STEP_OFFSET * step)
 
+#define CONDITION_DECODE_STEP(step, decode) \
+	(CONDITION_DECODE_OFFSET + REG_OFFSET * decode + STEP_OFFSET * step)
+
 #define tgu_dataset_rw(name, step_index, type, reg_num)                  \
 	(&((struct tgu_attribute[]){ {                                   \
 		__ATTR(name, 0644, tgu_dataset_show, tgu_dataset_store), \
@@ -68,6 +73,9 @@
 	tgu_dataset_rw(reg##reg_num, step_index, TGU_PRIORITY##priority, \
 			reg_num)
 
+#define STEP_DECODE(step_index, reg_num) \
+	tgu_dataset_rw(reg##reg_num, step_index, TGU_CONDITION_DECODE, reg_num)
+
 #define STEP_PRIORITY_LIST(step_index, priority)  \
 	{STEP_PRIORITY(step_index, 0, priority),  \
 	 STEP_PRIORITY(step_index, 1, priority),  \
@@ -90,6 +98,14 @@
 	 NULL                   \
 	}
 
+#define STEP_DECODE_LIST(n) \
+	{STEP_DECODE(n, 0), \
+	 STEP_DECODE(n, 1), \
+	 STEP_DECODE(n, 2), \
+	 STEP_DECODE(n, 3), \
+	 NULL		    \
+	}
+
 #define PRIORITY_ATTRIBUTE_GROUP_INIT(step, priority)\
 	(&(const struct attribute_group){\
 		.attrs = (struct attribute*[])STEP_PRIORITY_LIST(step, priority),\
@@ -97,11 +113,19 @@
 		.name = "step" #step "_priority" #priority \
 	})
 
+#define CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(step)\
+	(&(const struct attribute_group){\
+		.attrs = (struct attribute*[])STEP_DECODE_LIST(step),\
+		.is_visible = tgu_node_visible,\
+		.name = "step" #step "_condition_decode" \
+	})
+
 enum operation_index {
 	TGU_PRIORITY0,
 	TGU_PRIORITY1,
 	TGU_PRIORITY2,
 	TGU_PRIORITY3,
+	TGU_CONDITION_DECODE,
 };
 
 /* Maximum priority that TGU supports */
@@ -116,6 +140,7 @@ struct tgu_attribute {
 
 struct value_table {
 	unsigned int *priority;
+	unsigned int *condition_decode;
 };
 
 static inline void TGU_LOCK(void __iomem *addr)
@@ -145,6 +170,7 @@ static inline void TGU_UNLOCK(void __iomem *addr)
  * @value_table: Store given value based on relevant parameters.
  * @max_reg: Maximum number of registers
  * @max_step: Maximum step size
+ * @max_condition_decode: Maximum number of condition_decode
  *
  * This structure defines the data associated with a TGU device,
  * including its base address, device pointers, clock, spinlock for
@@ -159,6 +185,7 @@ struct tgu_drvdata {
 	struct value_table *value_table;
 	int max_reg;
 	int max_step;
+	int max_condition_decode;
 };
 
 #endif
-- 
2.34.1



From songwei.chai at oss.qualcomm.com  Thu Dec 18 22:59:00 2025
From: songwei.chai at oss.qualcomm.com (Songwei Chai)
Date: Thu, 18 Dec 2025 22:59:00 -0800
Subject: [PATCH v9 5/7] qcom-tgu: Add support to configure next action
In-Reply-To: <20251219065902.2296896-1-songwei.chai@oss.qualcomm.com>
References: <20251219065902.2296896-1-songwei.chai@oss.qualcomm.com>
Message-ID: <20251219065902.2296896-6-songwei.chai@oss.qualcomm.com>

Add "select" node for each step to determine if another step is taken,
trigger(s) are generated, counters/timers incremented/decremented, etc.

Signed-off-by: Songwei Chai <songwei.chai at oss.qualcomm.com>
---
 .../ABI/testing/sysfs-bus-amba-devices-tgu    |  7 +++
 drivers/hwtracing/qcom/tgu.c                  | 52 +++++++++++++++++++
 drivers/hwtracing/qcom/tgu.h                  | 27 ++++++++++
 3 files changed, 86 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
index c0e50ee95839..6fbd86592681 100644
--- a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
+++ b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
@@ -21,3 +21,10 @@ KernelVersion	6.19
 Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Songwei Chai <songwei.chai at oss.qualcomm.com>
 Description:
 		(RW) Set/Get the decode mode with specific step for TGU.
+
+What:		/sys/bus/amba/devices/<tgu-name>/step[0:7]_condition_select/reg[0:3]
+Date:		December 2025
+KernelVersion	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Songwei Chai <songwei.chai at oss.qualcomm.com>
+Description:
+		(RW) Set/Get the next action with specific step for TGU.
diff --git a/drivers/hwtracing/qcom/tgu.c b/drivers/hwtracing/qcom/tgu.c
index 4140dc544e5e..98648ee61a10 100644
--- a/drivers/hwtracing/qcom/tgu.c
+++ b/drivers/hwtracing/qcom/tgu.c
@@ -33,6 +33,10 @@ static int calculate_array_location(struct tgu_drvdata *drvdata,
 		ret = step_index * (drvdata->max_condition_decode) +
 			reg_index;
 		break;
+	case TGU_CONDITION_SELECT:
+		ret = step_index * (drvdata->max_condition_select) +
+			reg_index;
+		break;
 	default:
 		break;
 	}
@@ -74,6 +78,9 @@ static ssize_t tgu_dataset_show(struct device *dev,
 	case TGU_CONDITION_DECODE:
 		return sysfs_emit(buf, "0x%x\n",
 				  drvdata->value_table->condition_decode[index]);
+	case TGU_CONDITION_SELECT:
+		return sysfs_emit(buf, "0x%x\n",
+				  drvdata->value_table->condition_select[index]);
 	default:
 		break;
 	}
@@ -115,6 +122,10 @@ static ssize_t tgu_dataset_store(struct device *dev,
 		tgu_drvdata->value_table->condition_decode[index] = val;
 		ret = size;
 		break;
+	case TGU_CONDITION_SELECT:
+		tgu_drvdata->value_table->condition_select[index] = val;
+		ret = size;
+		break;
 	default:
 		break;
 	}
@@ -148,6 +159,15 @@ static umode_t tgu_node_visible(struct kobject *kobject,
 				drvdata->max_condition_decode) ?
 				attr->mode : 0;
 			break;
+		case TGU_CONDITION_SELECT:
+		/* 'default' register is at the end of 'select' region */
+			if (tgu_attr->reg_num ==
+			    drvdata->max_condition_select - 1)
+				attr->name = "default";
+			ret = (tgu_attr->reg_num <
+				drvdata->max_condition_select) ?
+				attr->mode : 0;
+			break;
 		default:
 			break;
 		}
@@ -186,6 +206,19 @@ static ssize_t tgu_write_all_hw_regs(struct tgu_drvdata *drvdata)
 				drvdata->base + CONDITION_DECODE_STEP(i, j));
 		}
 	}
+
+	for (i = 0; i < drvdata->max_step; i++) {
+		for (j = 0; j < drvdata->max_condition_select; j++) {
+			index = check_array_location(drvdata, i,
+						TGU_CONDITION_SELECT, j);
+
+			if (index == -EINVAL)
+				goto exit;
+
+			writel(drvdata->value_table->condition_select[index],
+				drvdata->base + CONDITION_SELECT_STEP(i, j));
+		}
+	}
 	/* Enable TGU to program the triggers */
 	writel(1, drvdata->base + TGU_CONTROL);
 exit:
@@ -225,6 +258,8 @@ static void tgu_set_conditions(struct tgu_drvdata *drvdata)
 
 	devid = readl(drvdata->base + TGU_DEVID);
 	drvdata->max_condition_decode = TGU_DEVID_CONDITIONS(devid);
+	/* select region has an additional 'default' register */
+	drvdata->max_condition_select = TGU_DEVID_CONDITIONS(devid) + 1;
 }
 
 static int tgu_enable(struct device *dev)
@@ -357,6 +392,14 @@ static const struct attribute_group *tgu_attr_groups[] = {
 	CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(5),
 	CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(6),
 	CONDITION_DECODE_ATTRIBUTE_GROUP_INIT(7),
+	CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(0),
+	CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(1),
+	CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(2),
+	CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(3),
+	CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(4),
+	CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(5),
+	CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(6),
+	CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(7),
 	NULL,
 };
 
@@ -412,6 +455,15 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id)
 	if (!drvdata->value_table->condition_decode)
 		return -ENOMEM;
 
+	drvdata->value_table->condition_select = devm_kzalloc(
+		dev,
+		drvdata->max_condition_select * drvdata->max_step *
+			sizeof(*(drvdata->value_table->condition_select)),
+		GFP_KERNEL);
+
+	if (!drvdata->value_table->condition_select)
+		return -ENOMEM;
+
 	drvdata->enable = false;
 
 	pm_runtime_put(&adev->dev);
diff --git a/drivers/hwtracing/qcom/tgu.h b/drivers/hwtracing/qcom/tgu.h
index 732126b896e1..1f46da35b40a 100644
--- a/drivers/hwtracing/qcom/tgu.h
+++ b/drivers/hwtracing/qcom/tgu.h
@@ -50,6 +50,7 @@
 #define STEP_OFFSET 0x1D8
 #define PRIORITY_START_OFFSET 0x0074
 #define CONDITION_DECODE_OFFSET 0x0050
+#define CONDITION_SELECT_OFFSET 0x0060
 #define PRIORITY_OFFSET 0x60
 #define REG_OFFSET 0x4
 
@@ -61,6 +62,9 @@
 #define CONDITION_DECODE_STEP(step, decode) \
 	(CONDITION_DECODE_OFFSET + REG_OFFSET * decode + STEP_OFFSET * step)
 
+#define CONDITION_SELECT_STEP(step, select) \
+	(CONDITION_SELECT_OFFSET + REG_OFFSET * select + STEP_OFFSET * step)
+
 #define tgu_dataset_rw(name, step_index, type, reg_num)                  \
 	(&((struct tgu_attribute[]){ {                                   \
 		__ATTR(name, 0644, tgu_dataset_show, tgu_dataset_store), \
@@ -76,6 +80,9 @@
 #define STEP_DECODE(step_index, reg_num) \
 	tgu_dataset_rw(reg##reg_num, step_index, TGU_CONDITION_DECODE, reg_num)
 
+#define STEP_SELECT(step_index, reg_num) \
+	tgu_dataset_rw(reg##reg_num, step_index, TGU_CONDITION_SELECT, reg_num)
+
 #define STEP_PRIORITY_LIST(step_index, priority)  \
 	{STEP_PRIORITY(step_index, 0, priority),  \
 	 STEP_PRIORITY(step_index, 1, priority),  \
@@ -106,6 +113,15 @@
 	 NULL		    \
 	}
 
+#define STEP_SELECT_LIST(n) \
+	{STEP_SELECT(n, 0), \
+	 STEP_SELECT(n, 1), \
+	 STEP_SELECT(n, 2), \
+	 STEP_SELECT(n, 3), \
+	 STEP_SELECT(n, 4), \
+	 NULL		    \
+	}
+
 #define PRIORITY_ATTRIBUTE_GROUP_INIT(step, priority)\
 	(&(const struct attribute_group){\
 		.attrs = (struct attribute*[])STEP_PRIORITY_LIST(step, priority),\
@@ -120,12 +136,20 @@
 		.name = "step" #step "_condition_decode" \
 	})
 
+#define CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(step)\
+	(&(const struct attribute_group){\
+		.attrs = (struct attribute*[])STEP_SELECT_LIST(step),\
+		.is_visible = tgu_node_visible,\
+		.name = "step" #step "_condition_select" \
+	})
+
 enum operation_index {
 	TGU_PRIORITY0,
 	TGU_PRIORITY1,
 	TGU_PRIORITY2,
 	TGU_PRIORITY3,
 	TGU_CONDITION_DECODE,
+	TGU_CONDITION_SELECT,
 };
 
 /* Maximum priority that TGU supports */
@@ -141,6 +165,7 @@ struct tgu_attribute {
 struct value_table {
 	unsigned int *priority;
 	unsigned int *condition_decode;
+	unsigned int *condition_select;
 };
 
 static inline void TGU_LOCK(void __iomem *addr)
@@ -171,6 +196,7 @@ static inline void TGU_UNLOCK(void __iomem *addr)
  * @max_reg: Maximum number of registers
  * @max_step: Maximum step size
  * @max_condition_decode: Maximum number of condition_decode
+ * @max_condition_select: Maximum number of condition_select
  *
  * This structure defines the data associated with a TGU device,
  * including its base address, device pointers, clock, spinlock for
@@ -186,6 +212,7 @@ struct tgu_drvdata {
 	int max_reg;
 	int max_step;
 	int max_condition_decode;
+	int max_condition_select;
 };
 
 #endif
-- 
2.34.1



From songwei.chai at oss.qualcomm.com  Thu Dec 18 22:59:01 2025
From: songwei.chai at oss.qualcomm.com (Songwei Chai)
Date: Thu, 18 Dec 2025 22:59:01 -0800
Subject: [PATCH v9 6/7] qcom-tgu: Add timer/counter functionality for TGU
In-Reply-To: <20251219065902.2296896-1-songwei.chai@oss.qualcomm.com>
References: <20251219065902.2296896-1-songwei.chai@oss.qualcomm.com>
Message-ID: <20251219065902.2296896-7-songwei.chai@oss.qualcomm.com>

Add counter and timer node for each step which could be
programed if they are to be utilized in trigger event/sequence.

Signed-off-by: Songwei Chai <songwei.chai at oss.qualcomm.com>
---
 .../ABI/testing/sysfs-bus-amba-devices-tgu    |  14 ++
 drivers/hwtracing/qcom/tgu.c                  | 120 ++++++++++++++++++
 drivers/hwtracing/qcom/tgu.h                  |  54 ++++++++
 3 files changed, 188 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
index 6fbd86592681..010eade0a1c5 100644
--- a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
+++ b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
@@ -28,3 +28,17 @@ KernelVersion	6.19
 Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Songwei Chai <songwei.chai at oss.qualcomm.com>
 Description:
 		(RW) Set/Get the next action with specific step for TGU.
+
+What:		/sys/bus/amba/devices/<tgu-name>/step[0:7]_timer/reg[0:1]
+Date:		December 2025
+KernelVersion	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Songwei Chai <songwei.chai at oss.qualcomm.com>
+Description:
+		(RW) Set/Get the timer value with specific step for TGU.
+
+What:		/sys/bus/amba/devices/<tgu-name>/step[0:7]_counter/reg[0:1]
+Date:		December 2025
+KernelVersion	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Songwei Chai <songwei.chai at oss.qualcomm.com>
+Description:
+		(RW) Set/Get the counter value with specific step for TGU.
diff --git a/drivers/hwtracing/qcom/tgu.c b/drivers/hwtracing/qcom/tgu.c
index 98648ee61a10..d4210869556e 100644
--- a/drivers/hwtracing/qcom/tgu.c
+++ b/drivers/hwtracing/qcom/tgu.c
@@ -37,6 +37,12 @@ static int calculate_array_location(struct tgu_drvdata *drvdata,
 		ret = step_index * (drvdata->max_condition_select) +
 			reg_index;
 		break;
+	case TGU_COUNTER:
+		ret = step_index * (drvdata->max_counter) + reg_index;
+		break;
+	case TGU_TIMER:
+		ret = step_index * (drvdata->max_timer) + reg_index;
+		break;
 	default:
 		break;
 	}
@@ -81,6 +87,12 @@ static ssize_t tgu_dataset_show(struct device *dev,
 	case TGU_CONDITION_SELECT:
 		return sysfs_emit(buf, "0x%x\n",
 				  drvdata->value_table->condition_select[index]);
+	case TGU_TIMER:
+		return sysfs_emit(buf, "0x%x\n",
+				  drvdata->value_table->timer[index]);
+	case TGU_COUNTER:
+		return sysfs_emit(buf, "0x%x\n",
+				  drvdata->value_table->counter[index]);
 	default:
 		break;
 	}
@@ -126,6 +138,14 @@ static ssize_t tgu_dataset_store(struct device *dev,
 		tgu_drvdata->value_table->condition_select[index] = val;
 		ret = size;
 		break;
+	case TGU_TIMER:
+		tgu_drvdata->value_table->timer[index] = val;
+		ret = size;
+		break;
+	case TGU_COUNTER:
+		tgu_drvdata->value_table->counter[index] = val;
+		ret = size;
+		break;
 	default:
 		break;
 	}
@@ -168,6 +188,22 @@ static umode_t tgu_node_visible(struct kobject *kobject,
 				drvdata->max_condition_select) ?
 				attr->mode : 0;
 			break;
+		case TGU_COUNTER:
+			if (drvdata->max_counter == 0)
+				ret = SYSFS_GROUP_INVISIBLE;
+			else
+				ret = (tgu_attr->reg_num <
+					drvdata->max_counter) ?
+					attr->mode : 0;
+			break;
+		case TGU_TIMER:
+			if (drvdata->max_timer == 0)
+				ret = SYSFS_GROUP_INVISIBLE;
+			else
+				ret = (tgu_attr->reg_num <
+					drvdata->max_timer) ?
+					attr->mode : 0;
+			break;
 		default:
 			break;
 		}
@@ -219,6 +255,30 @@ static ssize_t tgu_write_all_hw_regs(struct tgu_drvdata *drvdata)
 				drvdata->base + CONDITION_SELECT_STEP(i, j));
 		}
 	}
+
+	for (i = 0; i < drvdata->max_step; i++) {
+		for (j = 0; j < drvdata->max_timer; j++) {
+			index = check_array_location(drvdata, i, TGU_TIMER, j);
+
+			if (index == -EINVAL)
+				goto exit;
+
+			writel(drvdata->value_table->timer[index],
+				drvdata->base + TIMER_COMPARE_STEP(i, j));
+		}
+	}
+
+	for (i = 0; i < drvdata->max_step; i++) {
+		for (j = 0; j < drvdata->max_counter; j++) {
+			index = check_array_location(drvdata, i, TGU_COUNTER, j);
+
+			if (index == -EINVAL)
+				goto exit;
+
+			writel(drvdata->value_table->counter[index],
+				drvdata->base + COUNTER_COMPARE_STEP(i, j));
+		}
+	}
 	/* Enable TGU to program the triggers */
 	writel(1, drvdata->base + TGU_CONTROL);
 exit:
@@ -262,6 +322,31 @@ static void tgu_set_conditions(struct tgu_drvdata *drvdata)
 	drvdata->max_condition_select = TGU_DEVID_CONDITIONS(devid) + 1;
 }
 
+static void tgu_set_timer_counter(struct tgu_drvdata *drvdata)
+{
+	int num_timers, num_counters;
+	u32 devid2;
+
+	devid2 = readl(drvdata->base + CORESIGHT_DEVID2);
+
+	if (TGU_DEVID2_TIMER0(devid2) && TGU_DEVID2_TIMER1(devid2))
+		num_timers = 2;
+	else if (TGU_DEVID2_TIMER0(devid2) || TGU_DEVID2_TIMER1(devid2))
+		num_timers = 1;
+	else
+		num_timers = 0;
+
+	if (TGU_DEVID2_COUNTER0(devid2) && TGU_DEVID2_COUNTER1(devid2))
+		num_counters = 2;
+	else if (TGU_DEVID2_COUNTER0(devid2) || TGU_DEVID2_COUNTER1(devid2))
+		num_counters = 1;
+	else
+		num_counters = 0;
+
+	drvdata->max_timer = num_timers;
+	drvdata->max_counter = num_counters;
+}
+
 static int tgu_enable(struct device *dev)
 {
 	int ret = 0;
@@ -400,6 +485,22 @@ static const struct attribute_group *tgu_attr_groups[] = {
 	CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(5),
 	CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(6),
 	CONDITION_SELECT_ATTRIBUTE_GROUP_INIT(7),
+	TIMER_ATTRIBUTE_GROUP_INIT(0),
+	TIMER_ATTRIBUTE_GROUP_INIT(1),
+	TIMER_ATTRIBUTE_GROUP_INIT(2),
+	TIMER_ATTRIBUTE_GROUP_INIT(3),
+	TIMER_ATTRIBUTE_GROUP_INIT(4),
+	TIMER_ATTRIBUTE_GROUP_INIT(5),
+	TIMER_ATTRIBUTE_GROUP_INIT(6),
+	TIMER_ATTRIBUTE_GROUP_INIT(7),
+	COUNTER_ATTRIBUTE_GROUP_INIT(0),
+	COUNTER_ATTRIBUTE_GROUP_INIT(1),
+	COUNTER_ATTRIBUTE_GROUP_INIT(2),
+	COUNTER_ATTRIBUTE_GROUP_INIT(3),
+	COUNTER_ATTRIBUTE_GROUP_INIT(4),
+	COUNTER_ATTRIBUTE_GROUP_INIT(5),
+	COUNTER_ATTRIBUTE_GROUP_INIT(6),
+	COUNTER_ATTRIBUTE_GROUP_INIT(7),
 	NULL,
 };
 
@@ -425,6 +526,7 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id)
 	tgu_set_reg_number(drvdata);
 	tgu_set_steps(drvdata);
 	tgu_set_conditions(drvdata);
+	tgu_set_timer_counter(drvdata);
 
 	ret = sysfs_create_groups(&dev->kobj, tgu_attr_groups);
 	if (ret) {
@@ -464,6 +566,24 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id)
 	if (!drvdata->value_table->condition_select)
 		return -ENOMEM;
 
+	drvdata->value_table->timer = devm_kzalloc(
+		dev,
+		drvdata->max_step * drvdata->max_timer *
+			sizeof(*(drvdata->value_table->timer)),
+		GFP_KERNEL);
+
+	if (!drvdata->value_table->timer)
+		return -ENOMEM;
+
+	drvdata->value_table->counter = devm_kzalloc(
+		dev,
+		drvdata->max_step * drvdata->max_counter *
+			sizeof(*(drvdata->value_table->counter)),
+		GFP_KERNEL);
+
+	if (!drvdata->value_table->counter)
+		return -ENOMEM;
+
 	drvdata->enable = false;
 
 	pm_runtime_put(&adev->dev);
diff --git a/drivers/hwtracing/qcom/tgu.h b/drivers/hwtracing/qcom/tgu.h
index 1f46da35b40a..46a4cffedd7b 100644
--- a/drivers/hwtracing/qcom/tgu.h
+++ b/drivers/hwtracing/qcom/tgu.h
@@ -11,11 +11,17 @@
 #define TGU_LAR		0xfb0
 #define TGU_UNLOCK_OFFSET	0xc5acce55
 #define TGU_DEVID	0xfc8
+#define CORESIGHT_DEVID2       0xfc0
 
 #define BMVAL(val, lsb, msb)	((val & GENMASK(msb, lsb)) >> lsb)
 #define TGU_DEVID_SENSE_INPUT(devid_val) ((int) BMVAL(devid_val, 10, 17))
 #define TGU_DEVID_STEPS(devid_val) ((int)BMVAL(devid_val, 3, 6))
 #define TGU_DEVID_CONDITIONS(devid_val) ((int)BMVAL(devid_val, 0, 2))
+#define TGU_DEVID2_TIMER0(devid_val) ((int)BMVAL(devid_val, 18, 23))
+#define TGU_DEVID2_TIMER1(devid_val) ((int)BMVAL(devid_val, 13, 17))
+#define TGU_DEVID2_COUNTER0(devid_val) ((int)BMVAL(devid_val, 6, 11))
+#define TGU_DEVID2_COUNTER1(devid_val) ((int)BMVAL(devid_val, 0, 5))
+
 #define NUMBER_BITS_EACH_SIGNAL 4
 #define LENGTH_REGISTER 32
 
@@ -51,6 +57,8 @@
 #define PRIORITY_START_OFFSET 0x0074
 #define CONDITION_DECODE_OFFSET 0x0050
 #define CONDITION_SELECT_OFFSET 0x0060
+#define TIMER_START_OFFSET 0x0040
+#define COUNTER_START_OFFSET 0x0048
 #define PRIORITY_OFFSET 0x60
 #define REG_OFFSET 0x4
 
@@ -62,6 +70,12 @@
 #define CONDITION_DECODE_STEP(step, decode) \
 	(CONDITION_DECODE_OFFSET + REG_OFFSET * decode + STEP_OFFSET * step)
 
+#define TIMER_COMPARE_STEP(step, timer) \
+	(TIMER_START_OFFSET + REG_OFFSET * timer + STEP_OFFSET * step)
+
+#define COUNTER_COMPARE_STEP(step, counter) \
+	(COUNTER_START_OFFSET + REG_OFFSET * counter + STEP_OFFSET * step)
+
 #define CONDITION_SELECT_STEP(step, select) \
 	(CONDITION_SELECT_OFFSET + REG_OFFSET * select + STEP_OFFSET * step)
 
@@ -83,6 +97,12 @@
 #define STEP_SELECT(step_index, reg_num) \
 	tgu_dataset_rw(reg##reg_num, step_index, TGU_CONDITION_SELECT, reg_num)
 
+#define STEP_TIMER(step_index, reg_num) \
+	tgu_dataset_rw(reg##reg_num, step_index, TGU_TIMER, reg_num)
+
+#define STEP_COUNTER(step_index, reg_num) \
+	tgu_dataset_rw(reg##reg_num, step_index, TGU_COUNTER, reg_num)
+
 #define STEP_PRIORITY_LIST(step_index, priority)  \
 	{STEP_PRIORITY(step_index, 0, priority),  \
 	 STEP_PRIORITY(step_index, 1, priority),  \
@@ -122,6 +142,18 @@
 	 NULL		    \
 	}
 
+#define STEP_TIMER_LIST(n) \
+	{STEP_TIMER(n, 0), \
+	 STEP_TIMER(n, 1), \
+	 NULL              \
+	}
+
+#define STEP_COUNTER_LIST(n) \
+	{STEP_COUNTER(n, 0), \
+	 STEP_COUNTER(n, 1), \
+	 NULL                \
+	}
+
 #define PRIORITY_ATTRIBUTE_GROUP_INIT(step, priority)\
 	(&(const struct attribute_group){\
 		.attrs = (struct attribute*[])STEP_PRIORITY_LIST(step, priority),\
@@ -143,6 +175,20 @@
 		.name = "step" #step "_condition_select" \
 	})
 
+#define TIMER_ATTRIBUTE_GROUP_INIT(step)\
+	(&(const struct attribute_group){\
+		.attrs = (struct attribute*[])STEP_TIMER_LIST(step),\
+		.is_visible = tgu_node_visible,\
+		.name = "step" #step "_timer" \
+	})
+
+#define COUNTER_ATTRIBUTE_GROUP_INIT(step)\
+	(&(const struct attribute_group){\
+		.attrs = (struct attribute*[])STEP_COUNTER_LIST(step),\
+		.is_visible = tgu_node_visible,\
+		.name = "step" #step "_counter" \
+	})
+
 enum operation_index {
 	TGU_PRIORITY0,
 	TGU_PRIORITY1,
@@ -150,6 +196,8 @@ enum operation_index {
 	TGU_PRIORITY3,
 	TGU_CONDITION_DECODE,
 	TGU_CONDITION_SELECT,
+	TGU_TIMER,
+	TGU_COUNTER
 };
 
 /* Maximum priority that TGU supports */
@@ -166,6 +214,8 @@ struct value_table {
 	unsigned int *priority;
 	unsigned int *condition_decode;
 	unsigned int *condition_select;
+	unsigned int *timer;
+	unsigned int *counter;
 };
 
 static inline void TGU_LOCK(void __iomem *addr)
@@ -197,6 +247,8 @@ static inline void TGU_UNLOCK(void __iomem *addr)
  * @max_step: Maximum step size
  * @max_condition_decode: Maximum number of condition_decode
  * @max_condition_select: Maximum number of condition_select
+ * @max_timer: Maximum number of timers
+ * @max_counter: Maximum number of counters
  *
  * This structure defines the data associated with a TGU device,
  * including its base address, device pointers, clock, spinlock for
@@ -213,6 +265,8 @@ struct tgu_drvdata {
 	int max_step;
 	int max_condition_decode;
 	int max_condition_select;
+	int max_timer;
+	int max_counter;
 };
 
 #endif
-- 
2.34.1



From songwei.chai at oss.qualcomm.com  Thu Dec 18 22:59:02 2025
From: songwei.chai at oss.qualcomm.com (Songwei Chai)
Date: Thu, 18 Dec 2025 22:59:02 -0800
Subject: [PATCH v9 7/7] qcom-tgu: Add reset node to initialize
In-Reply-To: <20251219065902.2296896-1-songwei.chai@oss.qualcomm.com>
References: <20251219065902.2296896-1-songwei.chai@oss.qualcomm.com>
Message-ID: <20251219065902.2296896-8-songwei.chai@oss.qualcomm.com>

Add reset node to initialize the value of
priority/condition_decode/condition_select/timer/counter nodes.

Signed-off-by: Songwei Chai <songwei.chai at oss.qualcomm.com>
---
 .../ABI/testing/sysfs-bus-amba-devices-tgu    |  7 ++
 drivers/hwtracing/qcom/tgu.c                  | 74 +++++++++++++++++++
 2 files changed, 81 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
index 010eade0a1c5..0733b3e07b45 100644
--- a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
+++ b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
@@ -42,3 +42,10 @@ KernelVersion	6.19
 Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Songwei Chai <songwei.chai at oss.qualcomm.com>
 Description:
 		(RW) Set/Get the counter value with specific step for TGU.
+
+What:		/sys/bus/amba/devices/<tgu-name>/reset_tgu
+Date:		December 2025
+KernelVersion	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Songwei Chai <songwei.chai at oss.qualcomm.com>
+Description:
+		(Write) Write 1 to reset the dataset for TGU.
diff --git a/drivers/hwtracing/qcom/tgu.c b/drivers/hwtracing/qcom/tgu.c
index d4210869556e..5a8c6af9b719 100644
--- a/drivers/hwtracing/qcom/tgu.c
+++ b/drivers/hwtracing/qcom/tgu.c
@@ -425,8 +425,82 @@ static ssize_t enable_tgu_store(struct device *dev,
 }
 static DEVICE_ATTR_RW(enable_tgu);
 
+/* reset_tgu_store - Reset Trace and Gating Unit (TGU) configuration. */
+static ssize_t reset_tgu_store(struct device *dev,
+			       struct device_attribute *attr, const char *buf,
+			       size_t size)
+{
+	unsigned long value;
+	struct tgu_drvdata *drvdata = dev_get_drvdata(dev);
+	int i, j, ret;
+
+	if (kstrtoul(buf, 0, &value) || value == 0)
+		return -EINVAL;
+
+	if (!drvdata->enable) {
+		ret = pm_runtime_get_sync(drvdata->dev);
+		if (ret < 0) {
+			pm_runtime_put(drvdata->dev);
+			return ret;
+		}
+	}
+
+	guard(spinlock)(&drvdata->lock);
+	TGU_UNLOCK(drvdata->base);
+
+	writel(0, drvdata->base + TGU_CONTROL);
+
+	if (drvdata->value_table->priority)
+		memset(drvdata->value_table->priority, 0,
+			    MAX_PRIORITY * drvdata->max_step *
+				drvdata->max_reg * sizeof(unsigned int));
+
+	if (drvdata->value_table->condition_decode)
+		memset(drvdata->value_table->condition_decode, 0,
+			    drvdata->max_condition_decode * drvdata->max_step *
+				sizeof(unsigned int));
+
+		/* Initialize all condition registers to NOT(value=0x1000000) */
+	for (i = 0; i < drvdata->max_step; i++) {
+		for (j = 0; j < drvdata->max_condition_decode; j++) {
+			drvdata->value_table
+			->condition_decode[calculate_array_location(
+			drvdata, i, TGU_CONDITION_DECODE, j)] =
+			0x1000000;
+		}
+	}
+
+	if (drvdata->value_table->condition_select)
+		memset(drvdata->value_table->condition_select, 0,
+				drvdata->max_condition_select * drvdata->max_step *
+				sizeof(unsigned int));
+
+	if (drvdata->value_table->timer)
+		memset(drvdata->value_table->timer, 0,
+			    (drvdata->max_step) *
+				(drvdata->max_timer) *
+				sizeof(unsigned int));
+
+	if (drvdata->value_table->counter)
+		memset(drvdata->value_table->counter, 0,
+			    (drvdata->max_step) *
+				(drvdata->max_counter) *
+				sizeof(unsigned int));
+
+	dev_dbg(dev, "Coresight-TGU reset complete\n");
+
+	TGU_LOCK(drvdata->base);
+
+	drvdata->enable = false;
+	pm_runtime_put(drvdata->dev);
+
+	return size;
+}
+static DEVICE_ATTR_WO(reset_tgu);
+
 static struct attribute *tgu_common_attrs[] = {
 	&dev_attr_enable_tgu.attr,
+	&dev_attr_reset_tgu.attr,
 	NULL,
 };
 
-- 
2.34.1



From 21cnbao at gmail.com  Thu Dec 18 21:36:52 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Fri, 19 Dec 2025 13:36:52 +0800
Subject: [PATCH 0/6] dma-mapping: arm64: support batched cache sync
Message-ID: <20251219053658.84978-1-21cnbao@gmail.com>

From: Barry Song <v-songbaohua at oppo.com>

Many embedded ARM64 SoCs still lack hardware cache coherency support, which
causes DMA mapping operations to appear as hotspots in on-CPU flame graphs.

For an SG list with *nents* entries, the current dma_map/unmap_sg() and DMA
sync APIs perform cache maintenance one entry at a time. After each entry,
the implementation synchronously waits for the corresponding region?s
D-cache operations to complete. On architectures like arm64, efficiency can
be improved by issuing all entries? operations first and then performing a
single batched wait for completion.

Tangquan's results show that batched synchronization can reduce
dma_map_sg() time by 64.61% and dma_unmap_sg() time by 66.60% on an MTK
phone platform (MediaTek Dimensity 9500). The tests were performed by
pinning the task to CPU7 and fixing the CPU frequency at 2.6 GHz,
running dma_map_sg() and dma_unmap_sg() on 10 MB buffers (10 MB / 4 KB
sg entries per buffer) for 200 iterations and then averaging the
results.

I also ran this patch set on an RK3588 Rock5B+ board and
observed that millions of DMA sync operations were batched.

diff with RFC:
 * Dropped lots of #ifdef/#else/#endif according to Catalin and Marek,
  thanks!
 * Also add iova link/unlink batches, which is marked as RFC as i lack
   hardware. This is suggested by Marek, thanks!

RFC link:
 https://lore.kernel.org/lkml/20251029023115.22809-1-21cnbao at gmail.com/

Barry Song (6):
  arm64: Provide dcache_by_myline_op_nosync helper
  arm64: Provide dcache_clean_poc_nosync helper
  arm64: Provide dcache_inval_poc_nosync helper
  arm64: Provide arch_sync_dma_ batched helpers
  dma-mapping: Allow batched DMA sync operations if supported by the
    arch
  dma-iommu: Allow DMA sync batching for IOVA link/unlink

 arch/arm64/Kconfig                  |  1 +
 arch/arm64/include/asm/assembler.h  | 79 +++++++++++++++++++-------
 arch/arm64/include/asm/cacheflush.h |  2 +
 arch/arm64/mm/cache.S               | 58 +++++++++++++++----
 arch/arm64/mm/dma-mapping.c         | 24 ++++++++
 drivers/iommu/dma-iommu.c           | 12 +++-
 include/linux/dma-map-ops.h         | 22 ++++++++
 kernel/dma/Kconfig                  |  3 +
 kernel/dma/direct.c                 | 28 +++++++---
 kernel/dma/direct.h                 | 86 +++++++++++++++++++++++++----
 10 files changed, 262 insertions(+), 53 deletions(-)

-- 
2.39.3 (Apple Git-146)



From krzk at kernel.org  Thu Dec 18 23:35:04 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 08:35:04 +0100
Subject: [PATCH v4 01/21] dt-bindings: clock: mediatek: Add MT8189 clock
 definitions
In-Reply-To: <20251215034944.2973003-2-irving-ch.lin@mediatek.com>
References: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
 <20251215034944.2973003-2-irving-ch.lin@mediatek.com>
Message-ID: <20251219-venomous-ninja-uakari-bf8d1a@quoll>

On Mon, Dec 15, 2025 at 11:49:10AM +0800, irving.ch.lin wrote:
> From: Irving-CH Lin <irving-ch.lin at mediatek.com>
> 
> Add device tree bindings for the clock of MediaTek MT8189 SoC.

You in different patchset already received that comment:

A nit, subject: drop second/last, redundant "bindings" or "definitions"
or whatever you keep adding here redundantly. The
"dt-bindings" prefix is already stating that these are bindings.
See also:
https://elixir.bootlin.com/linux/v6.17-rc3/source/Documentation/devicetree/bindings/submitting-patches.rst#L18

Can you finally read the docs?

> 
> Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
> ---
>  .../bindings/clock/mediatek,mt8189-clock.yaml |  90 +++
>  .../clock/mediatek,mt8189-sys-clock.yaml      |  58 ++
>  .../dt-bindings/clock/mediatek,mt8189-clk.h   | 580 ++++++++++++++++++
>  3 files changed, 728 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt8189-clock.yaml
>  create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt8189-sys-clock.yaml
>  create mode 100644 include/dt-bindings/clock/mediatek,mt8189-clk.h
> 
> diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8189-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8189-clock.yaml
> new file mode 100644
> index 000000000000..d21e02df36a1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/mediatek,mt8189-clock.yaml
> @@ -0,0 +1,90 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/clock/mediatek,mt8189-clock.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek Functional Clock Controller for MT8189
> +
> +maintainers:
> +  - Qiqi Wang <qiqi.wang at mediatek.com>

Why there is n ack for this? Is above person going to provide any
reviews? Why didn't this person review this binding, already at v4.

> +
> +description: |
> +  The clock architecture in MediaTek like below
> +  PLLs -->
> +          dividers -->
> +                      muxes -->
> +                               clock gate
> +
> +  The devices provide clock gate control in different IP blocks.
> +
> +properties:
> +  compatible:
> +    items:
> +      - enum:
> +          - mediatek,mt8189-camsys-main
> +          - mediatek,mt8189-camsys-rawa
> +          - mediatek,mt8189-camsys-rawb
> +          - mediatek,mt8189-dbg-ao
> +          - mediatek,mt8189-dem
> +          - mediatek,mt8189-dispsys
> +          - mediatek,mt8189-dvfsrc-top
> +          - mediatek,mt8189-gce-d
> +          - mediatek,mt8189-gce-m
> +          - mediatek,mt8189-iic-wrap-e
> +          - mediatek,mt8189-iic-wrap-en
> +          - mediatek,mt8189-iic-wrap-s
> +          - mediatek,mt8189-iic-wrap-ws
> +          - mediatek,mt8189-imgsys1
> +          - mediatek,mt8189-imgsys2
> +          - mediatek,mt8189-infra-ao
> +          - mediatek,mt8189-ipesys
> +          - mediatek,mt8189-mdpsys
> +          - mediatek,mt8189-mfgcfg
> +          - mediatek,mt8189-mm-infra
> +          - mediatek,mt8189-peri-ao
> +          - mediatek,mt8189-scp-clk
> +          - mediatek,mt8189-scp-i2c-clk
> +          - mediatek,mt8189-ufscfg-ao
> +          - mediatek,mt8189-ufscfg-pdn
> +          - mediatek,mt8189-vdec-core
> +          - mediatek,mt8189-venc
> +      - const: syscon
> +
> +  reg:
> +    maxItems: 1
> +
> +  '#clock-cells':
> +    const: 1
> +
> +  '#reset-cells':
> +    const: 1
> +
> +required:
> +  - compatible
> +  - reg
> +  - '#clock-cells'
> +
> +allOf:
> +  - if:
> +      properties:
> +        compatible:
> +          contains:
> +            enum:
> +              - mediatek,mt8189-peri-ao
> +              - mediatek,mt8189-ufscfg-ao
> +              - mediatek,mt8189-ufscfg-pdn
> +
> +    then:
> +      required:
> +        - '#reset-cells'

else:
  properties:
    reset-cells: false

> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    clock-controller at 11b21000 {
> +        compatible = "mediatek,mt8189-iic-wrap-ws", "syscon";
> +        reg = <0x11b21000 0x1000>;
> +        #clock-cells = <1>;
> +    };
> diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8189-sys-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8189-sys-clock.yaml
> new file mode 100644
> index 000000000000..c94de207e289
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/mediatek,mt8189-sys-clock.yaml
> @@ -0,0 +1,58 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/clock/mediatek,mt8189-sys-clock.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek System Clock Controller for MT8189
> +
> +maintainers:
> +  - Qiqi Wang <qiqi.wang at mediatek.com>

Same problem. We are at v4 and maintainer did not bother to review it in
public. What sort of maintenance is this?

> +
> +description: |
> +  The clock architecture in MediaTek like below
> +  PLLs -->
> +          dividers -->
> +                      muxes -->
> +                               clock gate

Pretty obvious, no? Is there a clock topology which is different?

> +
> +  The apmixedsys provides most of PLLs which generated from SoC 26m.
> +  The topckgen provides dividers and muxes which provide the clock source to other IP blocks.
> +  The infracfg_ao provides clock gate in peripheral and infrastructure IP blocks.
> +  The mcusys provides mux control to select the clock source in AP MCU.
> +  The device nodes also provide the system control capacity for configuration.
> +
> +properties:
> +  compatible:
> +    items:
> +      - enum:
> +          - mediatek,mt8189-apmixedsys
> +          - mediatek,mt8189-topckgen
> +          - mediatek,mt8189-vlpckgen
> +          - mediatek,mt8189-vlp-ao
> +          - mediatek,mt8189-vlpcfg-ao
> +      - const: syscon

I do not understand why this is separate from the previous binding. It's
exactly the same, even description is the same.

Best regards,
Krzysztof



From krzk at kernel.org  Thu Dec 18 23:36:26 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 08:36:26 +0100
Subject: [PATCH v4 02/21] dt-bindings: power: mediatek: Add MT8189 power
 domain definitions
In-Reply-To: <20251215034944.2973003-3-irving-ch.lin@mediatek.com>
References: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
 <20251215034944.2973003-3-irving-ch.lin@mediatek.com>
Message-ID: <20251219-hissing-chicken-of-poetry-5fbfd9@quoll>

On Mon, Dec 15, 2025 at 11:49:11AM +0800, irving.ch.lin wrote:
> From: Irving-CH Lin <irving-ch.lin at mediatek.com>
> 
> Add device tree bindings for the power domains of MediaTek MT8189 SoC.
> 
> Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
> ---
>  .../power/mediatek,power-controller.yaml      |  1 +
>  .../dt-bindings/power/mediatek,mt8189-power.h | 38 +++++++++++++++++++
>  2 files changed, 39 insertions(+)
>  create mode 100644 include/dt-bindings/power/mediatek,mt8189-power.h

You did not cc maintainer of the binding, so either it's fake entry or
you forgot to use tools.

Please use scripts/get_maintainers.pl to get a list of necessary people
and lists to CC (and consider --no-git-fallback argument, so you will
not CC people just because they made one commit years ago). It might
happen, that command when run on an older kernel, gives you outdated
entries. Therefore please be sure you base your patches on recent Linux
kernel.

Tools like b4 or scripts/get_maintainer.pl provide you proper list of
people, so fix your workflow. Tools might also fail if you work on some
ancient tree (don't, instead use mainline) or work on fork of kernel
(don't, instead use mainline). Just use b4 and everything should be
fine, although remember about 'b4 prep --auto-to-cc' if you added new
patches to the patchset.

Best regards,
Krzysztof



From krzysztof.kozlowski at oss.qualcomm.com  Thu Dec 18 23:40:36 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 08:40:36 +0100
Subject: [PATCH] dt-bindings: mediatek: Drop inactive MandyJH Liu
Message-ID: <20251219074035.13001-2-krzysztof.kozlowski@oss.qualcomm.com>

There are no emails from MandyJH Liu, no reviews [1] of these bindings, so
clearly no maintenance is happening here.  Switch to Mediatek SoC
maintainers.

Cc: MandyJH Liu <mandyjh.liu at mediatek.com>
Link: https://lore.kernel.org/all/?q=f%3Amandyjh.liu%40mediatek.com [1]
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 .../devicetree/bindings/mfd/mediatek,mt8195-scpsys.yaml        | 3 ++-
 .../devicetree/bindings/power/mediatek,power-controller.yaml   | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/mfd/mediatek,mt8195-scpsys.yaml b/Documentation/devicetree/bindings/mfd/mediatek,mt8195-scpsys.yaml
index 0e1d43c96fb9..1cb9d6797b92 100644
--- a/Documentation/devicetree/bindings/mfd/mediatek,mt8195-scpsys.yaml
+++ b/Documentation/devicetree/bindings/mfd/mediatek,mt8195-scpsys.yaml
@@ -7,7 +7,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: MediaTek System Control Processor System
 
 maintainers:
-  - MandyJH Liu <mandyjh.liu at mediatek.com>
+  - AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
+  - Matthias Brugger <matthias.bgg at gmail.com>
 
 description:
   MediaTek System Control Processor System (SCPSYS) has several
diff --git a/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml b/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml
index f8a13928f615..9507b342a7ee 100644
--- a/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml
+++ b/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Mediatek Power Domains Controller
 
 maintainers:
-  - MandyJH Liu <mandyjh.liu at mediatek.com>
+  - AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
   - Matthias Brugger <mbrugger at suse.com>
 
 description: |
-- 
2.51.0



From krzk at kernel.org  Thu Dec 18 23:42:36 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 08:42:36 +0100
Subject: [PATCH v4 02/21] dt-bindings: power: mediatek: Add MT8189 power
 domain definitions
In-Reply-To: <20251219-hissing-chicken-of-poetry-5fbfd9@quoll>
References: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
 <20251215034944.2973003-3-irving-ch.lin@mediatek.com>
 <20251219-hissing-chicken-of-poetry-5fbfd9@quoll>
Message-ID: <a11bd4dc-6602-4ea1-b68b-e1450ea5f30f@kernel.org>

On 19/12/2025 08:36, Krzysztof Kozlowski wrote:
> On Mon, Dec 15, 2025 at 11:49:11AM +0800, irving.ch.lin wrote:
>> From: Irving-CH Lin <irving-ch.lin at mediatek.com>
>>
>> Add device tree bindings for the power domains of MediaTek MT8189 SoC.
>>
>> Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
>> ---
>>  .../power/mediatek,power-controller.yaml      |  1 +
>>  .../dt-bindings/power/mediatek,mt8189-power.h | 38 +++++++++++++++++++
>>  2 files changed, 39 insertions(+)
>>  create mode 100644 include/dt-bindings/power/mediatek,mt8189-power.h
> 
> You did not cc maintainer of the binding, so either it's fake entry or
> you forgot to use tools.

Although maintainer's entry for MandyJH Liu seems to be just bogus - no
maintenance happening here, so I just sent patch to remove them.

I would prefer if Mediatek did care about these bindings. It's another
piece to my complain list about very poor Mediatek company upstreaming.

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof


From alexander.stein at ew.tq-group.com  Thu Dec 18 23:45:57 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Fri, 19 Dec 2025 08:45:57 +0100
Subject: [PATCH v7 1/3] dt-bindings: soc: imx93-media-blk-ctrl: Add PDFC subnode
 to schema and example
In-Reply-To: <20251218190841.pmn3kwghq6lxsfl4@pengutronix.de>
References: <20251202-v6-18-topic-imx93-parallel-display-v7-0-2cce31d64608@pengutronix.de>
 <3210190.mvXUDI8C0e@steina-w>
 <20251218190841.pmn3kwghq6lxsfl4@pengutronix.de>
Message-ID: <7637686.lOV4Wx5bFT@steina-w>

Hi Marco,

Am Donnerstag, 18. Dezember 2025, 20:08:41 CET schrieb Marco Felsch:
> Hi Alexander,
> 
> On 25-12-16, Alexander Stein wrote:
> > Hi,
> > 
> > Am Montag, 15. Dezember 2025, 18:54:36 CET schrieb Marco Felsch:
> > > Hi Liu,
> > > 
> > > sorry I didn't fully answer you please see below.
> > > 
> > > On 25-12-08, Liu Ying wrote:
> > > > Hi Marco,
> > > > 
> > > > On 12/02/2025, Marco Felsch wrote:
> > > > > From: Liu Ying <victor.liu at nxp.com>
> > > > > 
> > > > > i.MX93 SoC mediamix blk-ctrl contains one DISPLAY_MUX register which
> > > > > configures parallel display format by using the "PARALLEL_DISP_FORMAT"
> > > > > field. Document the Parallel Display Format Configuration(PDFC) subnode
> > > > > and add the subnode to example.
> > > > > 
> > > > > Signed-off-by: Liu Ying <victor.liu at nxp.com>
> > > > > [m.felsch at pengutronix.de: port to v6.18-rc1]
> > > > > [m.felsch at pengutronix.de: add bus-width]
> > > > > Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
> > > > > ---
> > > > >  .../bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml | 92 ++++++++++++++++++++++
> > > > >  1 file changed, 92 insertions(+)
> > > > > 
> > > > > diff --git a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> > > > > index 34aea58094e55365a2f9c86092f637e533f954ff..6e2d86d9341c75108b492bcbabc8a560d8e707cd 100644
> > > > > --- a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> > > > > +++ b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> > > > > @@ -26,6 +26,12 @@ properties:
> > > > >    reg:
> > > > >      maxItems: 1
> > > 
> > > ...
> > > 
> > > > > +            properties:
> > > > > +              endpoint:
> > > > > +                $ref: /schemas/graph.yaml#/$defs/endpoint-base
> > > > > +                unevaluatedProperties: false
> > > > > +
> > > > > +                properties:
> > > > > +                  bus-width:
> > > > 
> > > > In v1-v5, I thought the output bus format can be determined by the sink
> > > > device(a panel or a bridge) hence properties like bus-width were not needed.
> > > > But, if this property is really needed, then reference video-interfaces.yaml
> > > > since bus-width is documented there.  Should we reference bus-type defined
> > > > in video-interfaces.yaml too?
> > > 
> > > You're right, the bus-width should be determined by the connected panel.
> > > But there are cases where a 24-bit panel is connected but only the lower
> > > 18-bits are muxed. I added the bus-width property to handle this case.
> > > In the end most users don't have to specify this since the correct
> > > bus-width is coming from the panel bus-fmt.
> > > 
> > > > > +                    enum: [ 16, 18, 24 ]
> > > > 
> > > > The PARALLEL_DISP_FORMAT field of DISPLAY_MUX register says this IP supports
> > > > below formats.  It seems that the enum here may tell RGB888, RGB666 and RGB565.
> > > > How can we tell RGB555, YCbCr 24 bits and YUV444 then?
> > > > 
> > > > 000b RGB888 -> RGB888
> > > > 001b RGB888 -> RGB666
> > > > 010b RGB565 -> RGB565
> > > > 011b RGB555 -> RGB555
> > > > 100b YUV -> YCbCr 24 bits
> > > > 101b YUV -> YUV444
> > > 
> > > This enum is about the physical bus width. RGB565 == 16-bit, YUV ==
> > > 24-bit.
> > > 
> > > That said, I don't think that you need to specify the bus-fmt since this
> > > is coming from the panel. As said above, my itension with the bus-width
> > > property is to provide integrators (dts-writers) a possibility to limit
> > > the physical available bus width.
> > 
> > Mh, isn't [1] exactly about this? Not sure about the outcome at that time.
> 
> Thanks for the pointer, I wasn't aware of this discussion. I skimmed
> through the dt-bindings thread and I agree with Rob and Maxime.
> 
> We do have the bus-width endpoint property already. This property is
> alredy used by media and drm bridge drivers. Why not making use of for
> this simple bridge driver too?
> 
> Furthermore I doubt, that a simple drm-bridge MEDIA_BUS_FMT_* convert
> driver solves all the problem in a generic way for all platforms, all
> connectors, all routing options.

Nobody knows what new hardware comes up with ?\_ (?)_/?
Anyway we already have a similar problem on our MBa6ULx mainboard.
Current downstream workaround is to clone the display timings but
change the bus format. See [1]. Although I would like to get rid of it.
This is just the display connector on the mainboard causing the shift.

Best regards
Alexander

[1] https://github.com/tq-systems/linux-tqmaxx/commit/777c02480182d3054264aaaf80e1dbc40a02cfc1

> If the i.MX93 NXP-EVKs in [1] would have connected the upper LCD_DAT*
> pads instead of the lower ones, there would be no conversion needed by
> the PDFC bridge driver, albeit the physical bus is cut to 18-bit width
> due to the RPi ext. header limit, which is expanded to 24-bit again later on
> via the Adafruit board panel FPC connector.
> 
> In such scenario the output width of the PDFC has to be 24-bit else
> you would lose not only the two LSBs but also the two MSBs for each
> channel. I tried to visualize what I meant for the blue channel:
> 
>                  24-bit PDFC bridge
> 		 ------------------
>         +----+----+----+----+----+----+----+----+
>  LCDIF  | B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 |
>         +----+----+----+----+----+----+----+----+
>           |    |    |    |    |    |    |    |
>         +----+----+----+----+----+----+----+----+
>  PDFC   | B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 |
>         +----+----+----+----+----+----+----+----+
>                     |    |    |    |    |    |
>         +----+----+----+----+----+----+----+----+
> SOC_PAD | xx | xx | D2 | D3 | D4 | D5 | D6 | D7 |
>         +----+----+----+----+----+----+----+----+
>                     |    |    |    |    |    |
>         +----+----+----+----+----+----+----+----+
>  ext.   | xx | xx | B2 | B3 | B4 | B5 | B6 | B7 |
>  HDR    +----+----+----+----+----+----+----+----+
>                     |    |    |    |    |    |
>                     |    |    |    |    |    |
>                     |    |    |    |    |    |
>           +-----------------------------+    |
>           |    +-----------------------------+
>           |    |    |    |    |    |    |    |
>         +----+----+----+----+----+----+----+----+
>  Ada.   | B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 |
>  FPC    +----+----+----+----+----+----+----+----+
> 
>                  18-bit PDFC bridge
> 		 ------------------
>         +----+----+----+----+----+----+----+----+
>  LCDIF  | B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 |
>         +----+----+----+----+----+----+----+----+
>           |    |    |    |    |    |    |    |
>         +----+----+----+----+----+----+----+----+
>  PDFC   | B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 |
>         +----+----+----+----+----+----+----+----+
>                     |    |    |    |    |    |
>           +---------+    |    |    |    |    |
>           |    +---------+    |    |    |    |
>           |    |    +---------+    |    |    |
>           |    |    |    +---------+    |    |
>           |    |    |    |    +---------+    |
>           |    |    |    |    |    +---------+
>           |    |    |    |    |    |
>         +----+----+----+----+----+----+----+----+
> SOC_PAD | xx | xx | D2 | D3 | D4 | D5 | D6 | D7 |
>         +----+----+----+----+----+----+----+----+
>                     |    |    |    |    |    |
>         +----+----+----+----+----+----+----+----+
>  ext.   | xx | xx | B2 | B3 | B4 | B5 | B6 | B7 |
>  HDR    +----+----+----+----+----+----+----+----+
>                     |    |    |    |    |    |
>                     |    |    |    |    |    |
>                     |    |    |    |    |    |
>           +-----------------------------+    |
>           |    +-----------------------------+
>           |    |    |    |    |    |    |    |
>         +----+----+----+----+----+----+----+----+
>  Ada.   | B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 |
>  FPC    +----+----+----+----+----+----+----+----+
> 
> 
> The mapping can get quite difficult for a single SoC already, just by
> using a slighlty different HW routing (the upper D[ata] pads).
> 
> Therefore I would keep it simple and device/ip specific (in this case
> PDFC specific) by making use of the bus-width. Specifying the bus-width
> property could be also wrong albeit it's the case physically, as you can
> see in my above example.
> 
> Therefore the bus-width property must have a good description.
> 
> Regards,
>   Marco
> 
> > Best regards,
> > Alexander
> > 
> > [1] https://lore.kernel.org/all/20250304101530.969920-1-victor.liu at nxp.com/
> > 
> > > [snip]
> 
> 
> 
> 


-- 
TQ-Systems GmbH | M?hlstra?e 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht M?nchen, HRB 105018
Gesch?ftsf?hrer: Detlef Schneider, R?diger Stahl, Stefan Schneider
http://www.tq-group.com/




From 21cnbao at gmail.com  Thu Dec 18 22:04:52 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Fri, 19 Dec 2025 14:04:52 +0800
Subject: [PATCH 0/6] dma-mapping: arm64: support batched cache sync
In-Reply-To: <20251219053658.84978-1-21cnbao@gmail.com>
References: <20251219053658.84978-1-21cnbao@gmail.com>
Message-ID: <20251219060452.85288-1-21cnbao@gmail.com>

From: Barry Song <v-songbaohua at oppo.com>

For reasons unclear, the cover letter was omitted from the
initial posting, despite Gmail indicating it was sent. This
is a resend. Apologies for the noise.

Many embedded ARM64 SoCs still lack hardware cache coherency support, which
causes DMA mapping operations to appear as hotspots in on-CPU flame graphs.

For an SG list with *nents* entries, the current dma_map/unmap_sg() and DMA
sync APIs perform cache maintenance one entry at a time. After each entry,
the implementation synchronously waits for the corresponding region?s
D-cache operations to complete. On architectures like arm64, efficiency can
be improved by issuing all entries? operations first and then performing a
single batched wait for completion.

Tangquan's results show that batched synchronization can reduce
dma_map_sg() time by 64.61% and dma_unmap_sg() time by 66.60% on an MTK
phone platform (MediaTek Dimensity 9500). The tests were performed by
pinning the task to CPU7 and fixing the CPU frequency at 2.6 GHz,
running dma_map_sg() and dma_unmap_sg() on 10 MB buffers (10 MB / 4 KB
sg entries per buffer) for 200 iterations and then averaging the
results.

I also ran this patch set on an RK3588 Rock5B+ board and
observed that millions of DMA sync operations were batched.

diff with RFC:
 * Dropped lots of #ifdef/#else/#endif according to Catalin and Marek,
  thanks!
 * Also add iova link/unlink batches, which is marked as RFC as i lack
   hardware. This is suggested by Marek, thanks!

RFC link:
 https://lore.kernel.org/lkml/20251029023115.22809-1-21cnbao at gmail.com/

Barry Song (6):
  arm64: Provide dcache_by_myline_op_nosync helper
  arm64: Provide dcache_clean_poc_nosync helper
  arm64: Provide dcache_inval_poc_nosync helper
  arm64: Provide arch_sync_dma_ batched helpers
  dma-mapping: Allow batched DMA sync operations if supported by the
    arch
  dma-iommu: Allow DMA sync batching for IOVA link/unlink

 arch/arm64/Kconfig                  |  1 +
 arch/arm64/include/asm/assembler.h  | 79 +++++++++++++++++++-------
 arch/arm64/include/asm/cacheflush.h |  2 +
 arch/arm64/mm/cache.S               | 58 +++++++++++++++----
 arch/arm64/mm/dma-mapping.c         | 24 ++++++++
 drivers/iommu/dma-iommu.c           | 12 +++-
 include/linux/dma-map-ops.h         | 22 ++++++++
 kernel/dma/Kconfig                  |  3 +
 kernel/dma/direct.c                 | 28 +++++++---
 kernel/dma/direct.h                 | 86 +++++++++++++++++++++++++----
 10 files changed, 262 insertions(+), 53 deletions(-)

-- 
2.39.3 (Apple Git-146)



From xu.yang_2 at nxp.com  Thu Dec 18 23:54:47 2025
From: xu.yang_2 at nxp.com (Xu Yang)
Date: Fri, 19 Dec 2025 15:54:47 +0800
Subject: [PATCH] phy: fsl-imx8mq-usb: add debugfs to access control register
Message-ID: <20251219075447.3672833-1-xu.yang_2@nxp.com>

The CR port is a simple 16-bit data/address parallel port that is
provided for on-chip access to the control registers inside the
USB 3.0 femtoPHY. While access to these registers is not required
for normal PHY operation, this interface enables you to access
some of the PHY?s diagnostic features during normal operation or
to override some basic PHY control signals.

3 debugfs files are created to read and write control registers,
all use hexadecimal format:
ctrl_reg_base: the register offset to write, or the start offset
               to read.
ctrl_reg_count: how many continuous registers to be read.
ctrl_reg_value: read to show the continuous registers value from
                the offset in ctrl_reg_base, to ctrl_reg_base
                + ctrl_reg_count - 1, one line for one register.
                when write, override the register at ctrl_reg_base,
                one time can only change one 16bits register.

Signed-off-by: Li Jun <jun.li at nxp.com>
Signed-off-by: Xu Yang <xu.yang_2 at nxp.com>
---
 drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 221 ++++++++++++++++++++-
 1 file changed, 220 insertions(+), 1 deletion(-)

diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
index ad8a55012e42..cb2392008ad2 100644
--- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
+++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
@@ -1,8 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0+
-/* Copyright (c) 2017 NXP. */
+/* Copyright (c) 2017-2025 NXP. */
 
 #include <linux/bitfield.h>
 #include <linux/clk.h>
+#include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/module.h>
@@ -52,6 +53,21 @@
 
 #define PHY_TUNE_DEFAULT		0xffffffff
 
+/* PHY control register access */
+#define PHY_CTRL_REG_COUNT_MAX		0x42
+#define PHY_CTRL_REG_OFFSET_MAX		0x201f
+
+#define PHY_CRCTL			0x30
+#define PHY_CRCTL_DATA_IN_MASK		GENMASK(15, 0)
+#define PHY_CRCTL_CAP_ADDR		BIT(16)
+#define PHY_CRCTL_CAP_DATA		BIT(17)
+#define PHY_CRCTL_CR_WRITE		BIT(18)
+#define PHY_CRCTL_CR_READ		BIT(19)
+
+#define PHY_CRSR			0x34
+#define PHY_CRSR_DATA_OUT_MASK		GENMASK(15, 0)
+#define PHY_CRSR_CR_ACK			BIT(16)
+
 #define TCA_CLK_RST			0x00
 #define TCA_CLK_RST_SW			BIT(9)
 #define TCA_CLK_RST_REF_CLK_EN		BIT(1)
@@ -113,6 +129,9 @@ struct imx8mq_usb_phy {
 	void __iomem *base;
 	struct regulator *vbus;
 	struct tca_blk *tca;
+	struct dentry *debugfs;
+	u16 cr_access_base;
+	u16 cr_read_count;
 	u32 pcs_tx_swing_full;
 	u32 pcs_tx_deemph_3p5db;
 	u32 tx_vref_tune;
@@ -420,6 +439,204 @@ static u32 phy_pcs_tx_swing_full_from_property(u32 percent)
 	percent = min(percent, 100U);
 
 	return (percent * 127) / 100;
+};
+
+#define IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT 500000
+static int imx8mq_phy_ctrl_reg_addr(struct imx8mq_usb_phy *imx_phy, u16 offset)
+{
+	void __iomem	*cr_ctrl = imx_phy->base + PHY_CRCTL;
+	void __iomem	*cr_sr = imx_phy->base + PHY_CRSR;
+	struct device	*dev = &imx_phy->phy->dev;
+	int i;
+
+	/* Address Phrase */
+	writel(offset, cr_ctrl);
+	writel(readl(cr_ctrl) | PHY_CRCTL_CAP_ADDR, cr_ctrl);
+
+	/* Wait CRSR[16] == 1 */
+	i = IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT;
+	while (!(readl(cr_sr) & PHY_CRSR_CR_ACK) && i > 0)
+		i--;
+	if (i == 0)
+		goto cr_addr_err;
+
+	writel(readl(cr_ctrl) & (~PHY_CRCTL_CAP_ADDR), cr_ctrl);
+
+	/* Wait CRSR[16] == 0 */
+	i = IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT;
+	while ((readl(cr_sr) & PHY_CRSR_CR_ACK) && i > 0)
+		i--;
+	if (i == 0)
+		goto cr_addr_err;
+
+	return 0;
+
+cr_addr_err:
+	dev_err(dev, "Failed to address reg 0x%x.\n", offset);
+	return -EIO;
+}
+
+static int imx8mq_phy_ctrl_reg_read(struct imx8mq_usb_phy *imx_phy, u16 offset)
+{
+	void __iomem	*cr_ctrl = imx_phy->base + PHY_CRCTL;
+	void __iomem	*cr_sr = imx_phy->base + PHY_CRSR;
+	struct device	*dev = &imx_phy->phy->dev;
+	int val, i;
+
+	/* Address Phrase */
+	val = imx8mq_phy_ctrl_reg_addr(imx_phy, offset);
+	if (val)
+		return val;
+
+	/* Read Phrase */
+	writel(readl(cr_ctrl) | PHY_CRCTL_CR_READ, cr_ctrl);
+
+	/* Wait CRSR[16] == 1 */
+	i = IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT;
+	while (!(readl(cr_sr) & PHY_CRSR_CR_ACK) && i > 0)
+		i--;
+	if (i == 0)
+		goto cr_read_err;
+
+	val = readl(cr_sr);
+	writel(val & ~PHY_CRCTL_CR_READ, cr_ctrl);
+
+	/* Wait CRSR[16] == 0 */
+	i = IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT;
+	while (!(readl(cr_sr) & PHY_CRSR_CR_ACK) && i > 0)
+		i--;
+	if (i == 0)
+		goto cr_read_err;
+
+	return val;
+
+cr_read_err:
+	dev_err(dev, "Failed to read reg 0x%x.\n", offset);
+	return -EIO;
+}
+
+static int imx8mq_phy_ctrl_reg_write(struct imx8mq_usb_phy *imx_phy,
+				     u16 offset, u16 val)
+{
+	void __iomem	*cr_ctrl = imx_phy->base + PHY_CRCTL;
+	void __iomem	*cr_sr = imx_phy->base + PHY_CRSR;
+	struct device	*dev = &imx_phy->phy->dev;
+	int i, ret;
+
+	/* Address Phrase */
+	ret = imx8mq_phy_ctrl_reg_addr(imx_phy, offset);
+	if (ret)
+		return ret;
+
+	writel(val, cr_ctrl);
+
+	/* Set cr_cap_data to be 1'b1 */
+	writel(readl(cr_ctrl) | PHY_CRCTL_CAP_DATA, cr_ctrl);
+	/* Wait CRSR[16] == 1 */
+	i = IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT;
+	while (!(readl(cr_sr) & PHY_CRSR_CR_ACK) && i > 0)
+		i--;
+	if (i == 0)
+		goto cr_write_err;
+
+	/* Clear cr_cap_data to be 1'br0 */
+	writel(readl(cr_ctrl) & ~PHY_CRCTL_CAP_DATA, cr_ctrl);
+	/* Wait CRSR[16] == 0 */
+	i = IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT;
+	while ((readl(cr_sr) & PHY_CRSR_CR_ACK) && i > 0)
+		i--;
+	if (i == 0)
+		goto cr_write_err;
+
+	/* Set cr_write to be 1'b1 */
+	writel(readl(cr_ctrl) | PHY_CRCTL_CR_WRITE, cr_ctrl);
+	/* Wait CRSR[16] == 1 */
+	i = IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT;
+	while (!(readl(cr_sr) & PHY_CRSR_CR_ACK) && i > 0)
+		i--;
+	if (i == 0)
+		goto cr_write_err;
+
+	/* Clear cr_write to be 1'br0 */
+	writel(readl(cr_ctrl) & ~PHY_CRCTL_CR_WRITE, cr_ctrl);
+	/* Wait CRSR[16] == 0 */
+	i = IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT;
+	while ((readl(cr_sr) & PHY_CRSR_CR_ACK) && i > 0)
+		i--;
+	if (i == 0)
+		goto cr_write_err;
+
+	return 0;
+
+cr_write_err:
+	dev_err(dev, "Failed to write reg 0x%x.\n", offset);
+	return -EIO;
+}
+
+static int ctrl_reg_value_show(struct seq_file *s, void *unused)
+{
+	struct imx8mq_usb_phy *imx_phy = s->private;
+	u16 i, val, base = imx_phy->cr_access_base;
+
+	for (i = 0; i < imx_phy->cr_read_count; i++) {
+		val = imx8mq_phy_ctrl_reg_read(imx_phy, base + i);
+		seq_printf(s, "Control Register 0x%x value is 0x%4x\n",
+			   base + i, val);
+	}
+
+	return 0;
+}
+
+static int ctrl_reg_value_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ctrl_reg_value_show, inode->i_private);
+}
+
+static ssize_t ctrl_reg_value_write(struct file *file, const char __user *ubuf,
+				    size_t count, loff_t *ppos)
+{
+	struct seq_file		*s = file->private_data;
+	struct imx8mq_usb_phy	*imx_phy = s->private;
+	u16			cr_value;
+	int			ret;
+
+	ret = kstrtou16_from_user(ubuf, count, 16, &cr_value);
+	if (ret)
+		return ret;
+
+	imx8mq_phy_ctrl_reg_write(imx_phy, imx_phy->cr_access_base, cr_value);
+
+	return count;
+}
+
+static const struct file_operations ctrl_reg_value_fops = {
+	.open		= ctrl_reg_value_open,
+	.write		= ctrl_reg_value_write,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static void debug_create_files(struct imx8mq_usb_phy *imx_phy)
+{
+	struct device *dev = &imx_phy->phy->dev;
+
+	imx_phy->debugfs = debugfs_create_dir(dev_name(dev), imx_phy->phy->debugfs);
+
+	debugfs_create_x16("ctrl_reg_base", 0600, imx_phy->debugfs,
+			   &imx_phy->cr_access_base);
+	debugfs_create_x16("ctrl_reg_count", 0600, imx_phy->debugfs,
+			   &imx_phy->cr_read_count);
+	debugfs_create_file("ctrl_reg_value", 0600, imx_phy->debugfs,
+			    imx_phy, &ctrl_reg_value_fops);
+
+	imx_phy->cr_access_base = 0;
+	imx_phy->cr_read_count = 1;
+}
+
+static void debug_remove_files(struct imx8mq_usb_phy *imx_phy)
+{
+	debugfs_remove_recursive(imx_phy->debugfs);
 }
 
 static void imx8m_get_phy_tuning_data(struct imx8mq_usb_phy *imx_phy)
@@ -724,6 +941,7 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
 					"failed to get tca\n");
 
 	imx8m_get_phy_tuning_data(imx_phy);
+	debug_create_files(imx_phy);
 
 	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
 
@@ -734,6 +952,7 @@ static void imx8mq_usb_phy_remove(struct platform_device *pdev)
 {
 	struct imx8mq_usb_phy *imx_phy = platform_get_drvdata(pdev);
 
+	debug_remove_files(imx_phy);
 	imx95_usb_phy_put_tca(imx_phy);
 }
 
-- 
2.34.1



From krzk at kernel.org  Fri Dec 19 00:06:46 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 09:06:46 +0100
Subject: [PATCH v2 1/4] dt-bindings: soc: mediatek: devapc: Add bindings
 for MT8189
In-Reply-To: <20251217063429.1157084-2-xiaoshun.xu@mediatek.corp-partner.google.com>
References: <20251217063429.1157084-1-xiaoshun.xu@mediatek.corp-partner.google.com>
 <20251217063429.1157084-2-xiaoshun.xu@mediatek.corp-partner.google.com>
Message-ID: <20251219-eccentric-mouse-of-drizzle-0c667a@quoll>

On Wed, Dec 17, 2025 at 02:34:10PM +0800, Xiaoshun Xu wrote:
> 
> External email : Please do not click links or open attachments until you have verified the sender or the content.

This is not a proper email. You already received such comment before.
Why did you ignore it?

NAK

Best regards,
Krzysztof



From kevin.tung.openbmc at gmail.com  Fri Dec 19 00:09:53 2025
From: kevin.tung.openbmc at gmail.com (Kevin Tung)
Date: Fri, 19 Dec 2025 16:09:53 +0800
Subject: [PATCH v3 0/5] Revise Meta Yosemite5 devicetree
Message-ID: <20251219-yv5_revise_dts-v3-0-ca1d5a382013@gmail.com>

Summary:
Revise linux device tree entry related to Meta (Facebook) Yosemite5.

Changes in v3:
- Correct power monitor shunt resistor
- Revert the previous SGPIO P0_I3C_APML_ALERT_L renaming change
- Add new SGPIO line names and rename signal
- Retitle Update sensor configuration for more clarity
- Link to v2: https://lore.kernel.org/r/20251120-yv5_revise_dts-v2-0-4d7de701c5be at gmail.com

Changes in v2:
- Add ipmb node for OCP debug card
- Link to v1: https://lore.kernel.org/r/20251118-yv5_revise_dts-v1-0-fcd6b44b4497 at gmail.com

Changes in v1:
- Increase i2c4/i2c12 bus speed to 400 kHz
- Update sensor configuration
- Rename sgpio P0_I3C_APML_ALERT_L

Signed-off-by: Kevin Tung <kevin.tung.openbmc at gmail.com>
---
Kevin Tung (5):
      ARM: dts: aspeed: yosemite5: Increase i2c4/i2c12 bus speed to 400 kHz
      ARM: dts: aspeed: yosemite5: Remove ambiguous power monitor DTS nodes
      ARM: dts: aspeed: yosemite5: Add new SGPIO line names and rename signal
      ARM: dts: aspeed: yosemite5: Add ipmb node for OCP debug card
      ARM: dts: aspeed: yosemite5: Correct power monitor shunt resistor

 .../dts/aspeed/aspeed-bmc-facebook-yosemite5.dts   | 68 +++++++++++++---------
 1 file changed, 42 insertions(+), 26 deletions(-)
---
base-commit: 111e542d267576de402d0836603e1def2b60316b
change-id: 20251118-yv5_revise_dts-12e10edd95d6

Best regards,
-- 
Kevin Tung <kevin.tung.openbmc at gmail.com>



From kevin.tung.openbmc at gmail.com  Fri Dec 19 00:09:54 2025
From: kevin.tung.openbmc at gmail.com (Kevin Tung)
Date: Fri, 19 Dec 2025 16:09:54 +0800
Subject: [PATCH v3 1/5] ARM: dts: aspeed: yosemite5: Increase i2c4/i2c12
 bus speed to 400 kHz
In-Reply-To: <20251219-yv5_revise_dts-v3-0-ca1d5a382013@gmail.com>
References: <20251219-yv5_revise_dts-v3-0-ca1d5a382013@gmail.com>
Message-ID: <20251219-yv5_revise_dts-v3-1-ca1d5a382013@gmail.com>

Configure i2c4 and i2c12 to operate at 400 kHz instead of 100 kHz.
This update aligns the bus settings with the hardware capabilities
and improves MCTP communication performance.

Signed-off-by: Kevin Tung <kevin.tung.openbmc at gmail.com>
---
 arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts
index 2486981f3d6bd36f3fe780b21e834b85242f8aa9..7991e9360847532cff9aad4ad4ed57d4c30668a0 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts
+++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts
@@ -231,6 +231,7 @@ sbtsi at 4c {
 &i2c4 {
 	multi-master;
 	mctp-controller;
+	clock-frequency = <400000>;
 	status = "okay";
 
 	mctp at 10 {
@@ -782,6 +783,7 @@ adc at 4b {
 &i2c12 {
 	multi-master;
 	mctp-controller;
+	clock-frequency = <400000>;
 	status = "okay";
 
 	mctp at 10 {

-- 
2.52.0



From kevin.tung.openbmc at gmail.com  Fri Dec 19 00:09:55 2025
From: kevin.tung.openbmc at gmail.com (Kevin Tung)
Date: Fri, 19 Dec 2025 16:09:55 +0800
Subject: [PATCH v3 2/5] ARM: dts: aspeed: yosemite5: Remove ambiguous power
 monitor DTS nodes
In-Reply-To: <20251219-yv5_revise_dts-v3-0-ca1d5a382013@gmail.com>
References: <20251219-yv5_revise_dts-v3-0-ca1d5a382013@gmail.com>
Message-ID: <20251219-yv5_revise_dts-v3-2-ca1d5a382013@gmail.com>

Two different power monitor devices, using different drivers, reuse
I2C addresses 0x40 and 0x45 on bus 10 across Yosemite5 board variants.
Defining these devices statically in the DTS can lead to incorrect
driver binding on newer boards when the wrong device is instantiated.

Therefore, remove 10-0040 and 10-0045 device nodes, and let the driver
selection is instead handled in user space by the OpenBMC Entity
Manager based on the actual board configuration.

Signed-off-by: Kevin Tung <kevin.tung.openbmc at gmail.com>
---
 arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts | 14 --------------
 1 file changed, 14 deletions(-)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts
index 7991e9360847532cff9aad4ad4ed57d4c30668a0..45b8ac2e8c65a4f672e64571631b7f6944f26213 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts
+++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts
@@ -674,20 +674,6 @@ gpio-expander at 22 {
 			"PWRGD_P3V3_AUX","ALERT_TEMP";
 	};
 
-	power-sensor at 40 {
-		compatible = "ti,ina233";
-		reg = <0x40>;
-		shunt-resistor = <2000>;
-		ti,maximum-expected-current-microamp = <32768000>;
-	};
-
-	power-sensor at 45 {
-		compatible = "ti,ina233";
-		reg = <0x45>;
-		shunt-resistor = <2000>;
-		ti,maximum-expected-current-microamp = <32768000>;
-	};
-
 	adc at 48 {
 		compatible = "ti,ads7830";
 		reg = <0x48>;

-- 
2.52.0



From kevin.tung.openbmc at gmail.com  Fri Dec 19 00:09:56 2025
From: kevin.tung.openbmc at gmail.com (Kevin Tung)
Date: Fri, 19 Dec 2025 16:09:56 +0800
Subject: [PATCH v3 3/5] ARM: dts: aspeed: yosemite5: Add new SGPIO line
 names and rename signal
In-Reply-To: <20251219-yv5_revise_dts-v3-0-ca1d5a382013@gmail.com>
References: <20251219-yv5_revise_dts-v3-0-ca1d5a382013@gmail.com>
Message-ID: <20251219-yv5_revise_dts-v3-3-ca1d5a382013@gmail.com>

Add new SGPIO line names for user space monitoring and event logging.

Also rename PADDLE_BD_IOEXP_INT to ALERT_IRQ_PMBUS_PWR2_N to match
hardware naming. The original PADDLE_BD_IOEXP_INT is unused, so this
change does not affect current system functionality.

Signed-off-by: Kevin Tung <kevin.tung.openbmc at gmail.com>
---
 .../dts/aspeed/aspeed-bmc-facebook-yosemite5.dts   | 31 ++++++++++++++++++----
 1 file changed, 26 insertions(+), 5 deletions(-)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts
index 45b8ac2e8c65a4f672e64571631b7f6944f26213..983aebc394d9159c7e3db2e7c39e963f7b64c855 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts
+++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts
@@ -978,7 +978,7 @@ &sgpiom0 {
 	"E1S_0_BD_IOEXP","",
 	"E1S_1_BD_IOEXP","",
 	/*bit88-bit95*/
-	"PADDLE_BD_IOEXP_INT","",
+	"ALERT_IRQ_PMBUS_PWR2_N","",
 	"FM_BOARD_REV_ID0","",
 	"FM_BOARD_REV_ID1","",
 	"FM_BOARD_REV_ID2","",
@@ -991,16 +991,37 @@ &sgpiom0 {
 	"PRSNT_BOOT_N_FF","",
 	"PRSNT_MCIO1A_N_FF","",
 	"NIC_PRSNT_N","",
-	"","",
+	"FM_CPU_BMC_RST_N","",
 	"","",
 	"","",
 	"","",
 	/*bit104-bit111*/
-	"","","","","","","","","","","","","","","","",
+	"MASTER_PWR_EN","",
+	"MASTER_PWR2_EN","",
+	"PRSNT_MCIO0A_E1S0_N","",
+	"","",
+	"PRSNT_MCIO0A_E1S1_N","",
+	"","",
+	"","",
+	"Fault","",
 	/*bit112-bit119*/
-	"","","","","","","","","","","","","","","","",
+	"FM_CPLD_RSVD_MCIO0A_SB1","",
+	"FM_CPLD_RSVD_MCIO0A_SB2","",
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
 	/*bit120-bit127*/
-	"","","","","","","","","","","","","","","","";
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
+	"","";
 	status = "okay";
 };
 

-- 
2.52.0



From alexander.stein at ew.tq-group.com  Fri Dec 19 00:09:23 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Fri, 19 Dec 2025 09:09:23 +0100
Subject: [PATCH 1/6] dt-bindings: clk: rs9: add clock-output-names property
In-Reply-To: <CAMuHMdWEJ-eYwUTnotsTVEtKrujYVsEB4kFVjRYh3wXZvyjfGQ@mail.gmail.com>
References: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
 <20251218152058.1521806-2-alexander.stein@ew.tq-group.com>
 <CAMuHMdWEJ-eYwUTnotsTVEtKrujYVsEB4kFVjRYh3wXZvyjfGQ@mail.gmail.com>
Message-ID: <3357591.tdWV9SEqCh@steina-w>

Am Donnerstag, 18. Dezember 2025, 16:26:10 CET schrieb Geert Uytterhoeven:
> Hi Alexander,
> 
> On Thu, 18 Dec 2025 at 16:21, Alexander Stein
> <alexander.stein at ew.tq-group.com> wrote:
> > Add "clock-output-names" which is a standard property for clock
> > providers.
> 
> Why? Isn't that property sort of deprecated?

It is? Oh, I wasn't aware of that. Maybe the property should be
marked deprecated in dt schema then.

Thanks and best regards,
Alexander

> 
> Will be replying to the cover letter next...
> 
> > Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
> 
> Gr{oetje,eeting}s,
> 
>                         Geert
> 
> 


-- 
TQ-Systems GmbH | M?hlstra?e 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht M?nchen, HRB 105018
Gesch?ftsf?hrer: Detlef Schneider, R?diger Stahl, Stefan Schneider
http://www.tq-group.com/




From kevin.tung.openbmc at gmail.com  Fri Dec 19 00:09:57 2025
From: kevin.tung.openbmc at gmail.com (Kevin Tung)
Date: Fri, 19 Dec 2025 16:09:57 +0800
Subject: [PATCH v3 4/5] ARM: dts: aspeed: yosemite5: Add ipmb node for OCP
 debug card
In-Reply-To: <20251219-yv5_revise_dts-v3-0-ca1d5a382013@gmail.com>
References: <20251219-yv5_revise_dts-v3-0-ca1d5a382013@gmail.com>
Message-ID: <20251219-yv5_revise_dts-v3-4-ca1d5a382013@gmail.com>

Add the device tree node to enable the IPMB interface used by
the OCP debug card.

Signed-off-by: Kevin Tung <kevin.tung.openbmc at gmail.com>
---
 arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts
index 983aebc394d9159c7e3db2e7c39e963f7b64c855..84d3731b17f7c7c87338672bbcc859de2b89b722 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts
+++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts
@@ -365,7 +365,14 @@ i2c6mux0ch3: i2c at 3 {
 
 /* SCM CPLD I2C */
 &i2c7 {
+	multi-master;
 	status = "okay";
+
+	ipmb at 10 {
+		compatible = "ipmb-dev";
+		reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>;
+		i2c-protocol;
+	};
 };
 
 &i2c8 {

-- 
2.52.0



From kevin.tung.openbmc at gmail.com  Fri Dec 19 00:09:58 2025
From: kevin.tung.openbmc at gmail.com (Kevin Tung)
Date: Fri, 19 Dec 2025 16:09:58 +0800
Subject: [PATCH v3 5/5] ARM: dts: aspeed: yosemite5: Correct power monitor
 shunt resistor
In-Reply-To: <20251219-yv5_revise_dts-v3-0-ca1d5a382013@gmail.com>
References: <20251219-yv5_revise_dts-v3-0-ca1d5a382013@gmail.com>
Message-ID: <20251219-yv5_revise_dts-v3-5-ca1d5a382013@gmail.com>

Correct the shunt resistor value in the DTS with the hardware setting
to ensure accurate power and current measurements.

Signed-off-by: Kevin Tung <kevin.tung.openbmc at gmail.com>
---
 arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts
index 84d3731b17f7c7c87338672bbcc859de2b89b722..524597a81365ef10cd03b67d35eeb88a965cbe0a 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts
+++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts
@@ -415,7 +415,7 @@ power-sensor at 42 {
 	power-monitor at 43 {
 		compatible = "lltc,ltc4287";
 		reg = <0x43>;
-		shunt-resistor-micro-ohms = <250>;
+		shunt-resistor-micro-ohms = <100>;
 	};
 
 	power-sensor at 44 {
@@ -461,25 +461,25 @@ eeprom at 57 {
 	power-monitor at 58 {
 		compatible = "renesas,isl28022";
 		reg = <0x58>;
-		shunt-resistor-micro-ohms = <1000>;
+		shunt-resistor-micro-ohms = <10000>;
 	};
 
 	power-monitor at 59 {
 		compatible = "renesas,isl28022";
 		reg = <0x59>;
-		shunt-resistor-micro-ohms = <1000>;
+		shunt-resistor-micro-ohms = <10000>;
 	};
 
 	power-monitor at 5a {
 		compatible = "renesas,isl28022";
 		reg = <0x5a>;
-		shunt-resistor-micro-ohms = <1000>;
+		shunt-resistor-micro-ohms = <10000>;
 	};
 
 	power-monitor at 5b {
 		compatible = "renesas,isl28022";
 		reg = <0x5b>;
-		shunt-resistor-micro-ohms = <1000>;
+		shunt-resistor-micro-ohms = <10000>;
 	};
 
 	psu at 5c {
@@ -723,13 +723,13 @@ gpio-expander at 21 {
 	power-sensor at 40 {
 		compatible = "ti,ina230";
 		reg = <0x40>;
-		shunt-resistor = <2000>;
+		shunt-resistor = <1000>;
 	};
 
 	power-sensor at 41 {
 		compatible = "ti,ina230";
 		reg = <0x41>;
-		shunt-resistor = <2000>;
+		shunt-resistor = <1000>;
 	};
 
 	power-sensor at 42 {

-- 
2.52.0



From xu.yang_2 at nxp.com  Fri Dec 19 00:13:54 2025
From: xu.yang_2 at nxp.com (Xu Yang)
Date: Fri, 19 Dec 2025 16:13:54 +0800
Subject: [PATCH] phy: fsl-imx8mq-usb: change ssc_range value for i.MX8MQ
Message-ID: <20251219081354.3806806-1-xu.yang_2@nxp.com>

According to IC engineer suggestion, set ssc_range as -4003 ppm
will have more tolerance for EMI, and suitable for more boards.
Besides, it's confirmed that with this setting the TX SSC test
will pass on one customer board.

Signed-off-by: Li Jun <jun.li at nxp.com>
Signed-off-by: Xu Yang <xu.yang_2 at nxp.com>
---
 drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
index cb2392008ad2..02d9af409b08 100644
--- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
+++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
@@ -18,6 +18,10 @@
 #define PHY_CTRL0_FSEL_MASK		GENMASK(10, 5)
 #define PHY_CTRL0_FSEL_24M		0x2a
 #define PHY_CTRL0_FSEL_100M		0x27
+#define PHY_CTRL0_SSC_RANGE_MASK	GENMASK(23, 21)
+#define PHY_CTRL0_SSC_RANGE_4003PPM	0x2
+#define PHY_CTRL0_SSC_RANGE_4492PPM	0x1
+#define PHY_CTRL0_SSC_RANGE_4980PPM	0x0
 
 #define PHY_CTRL1			0x4
 #define PHY_CTRL1_RESET			BIT(0)
@@ -780,6 +784,9 @@ static int imx8mq_usb_phy_init(struct phy *phy)
 
 	value = readl(imx_phy->base + PHY_CTRL0);
 	value |= PHY_CTRL0_REF_SSP_EN;
+	value &= ~PHY_CTRL0_SSC_RANGE_MASK;
+	value |= FIELD_PREP(PHY_CTRL0_SSC_RANGE_MASK,
+			    PHY_CTRL0_SSC_RANGE_4003PPM);
 	writel(value, imx_phy->base + PHY_CTRL0);
 
 	value = readl(imx_phy->base + PHY_CTRL2);
-- 
2.34.1



From patchwork-bot+linux-riscv at kernel.org  Fri Dec 19 00:10:08 2025
From: patchwork-bot+linux-riscv at kernel.org (patchwork-bot+linux-riscv at kernel.org)
Date: Fri, 19 Dec 2025 08:10:08 +0000
Subject: [PATCH v7 00/31] context_tracking,x86: Defer some IPIs until a
 user->kernel transition
In-Reply-To: <20251114150133.1056710-1-vschneid@redhat.com>
References: <20251114150133.1056710-1-vschneid@redhat.com>
Message-ID: <176613180853.3684357.18339473690014642605.git-patchwork-notify@kernel.org>

Hello:

This series was applied to riscv/linux.git (fixes)
by Frederic Weisbecker <frederic at kernel.org>:

On Fri, 14 Nov 2025 16:01:02 +0100 you wrote:
> Context
> =======
> 
> We've observed within Red Hat that isolated, NOHZ_FULL CPUs running a
> pure-userspace application get regularly interrupted by IPIs sent from
> housekeeping CPUs. Those IPIs are caused by activity on the housekeeping CPUs
> leading to various on_each_cpu() calls, e.g.:
> 
> [...]

Here is the summary with links:
  - [v7,01/31] objtool: Make validate_call() recognize indirect calls to pv_ops[]
    (no matching commit)
  - [v7,02/31] objtool: Flesh out warning related to pv_ops[] calls
    (no matching commit)
  - [v7,03/31] rcu: Add a small-width RCU watching counter debug option
    https://git.kernel.org/riscv/c/d1e6d2773898
  - [v7,04/31] rcutorture: Make TREE04 use CONFIG_RCU_DYNTICKS_TORTURE
    https://git.kernel.org/riscv/c/82a224498005
  - [v7,05/31] jump_label: Add annotations for validating noinstr usage
    (no matching commit)
  - [v7,06/31] static_call: Add read-only-after-init static calls
    (no matching commit)
  - [v7,07/31] x86/paravirt: Mark pv_sched_clock static call as __ro_after_init
    (no matching commit)
  - [v7,08/31] x86/idle: Mark x86_idle static call as __ro_after_init
    (no matching commit)
  - [v7,09/31] x86/paravirt: Mark pv_steal_clock static call as __ro_after_init
    (no matching commit)
  - [v7,10/31] riscv/paravirt: Mark pv_steal_clock static call as __ro_after_init
    (no matching commit)
  - [v7,11/31] loongarch/paravirt: Mark pv_steal_clock static call as __ro_after_init
    (no matching commit)
  - [v7,12/31] arm64/paravirt: Mark pv_steal_clock static call as __ro_after_init
    (no matching commit)
  - [v7,13/31] arm/paravirt: Mark pv_steal_clock static call as __ro_after_init
    (no matching commit)
  - [v7,14/31] perf/x86/amd: Mark perf_lopwr_cb static call as __ro_after_init
    (no matching commit)
  - [v7,15/31] sched/clock: Mark sched_clock_running key as __ro_after_init
    (no matching commit)
  - [v7,16/31] KVM: VMX: Mark __kvm_is_using_evmcs static key as __ro_after_init
    (no matching commit)
  - [v7,17/31] x86/bugs: Mark cpu_buf_vm_clear key as allowed in .noinstr
    (no matching commit)
  - [v7,18/31] x86/speculation/mds: Mark cpu_buf_idle_clear key as allowed in .noinstr
    (no matching commit)
  - [v7,19/31] sched/clock, x86: Mark __sched_clock_stable key as allowed in .noinstr
    (no matching commit)
  - [v7,20/31] KVM: VMX: Mark vmx_l1d_should flush and vmx_l1d_flush_cond keys as allowed in .noinstr
    (no matching commit)
  - [v7,21/31] stackleack: Mark stack_erasing_bypass key as allowed in .noinstr
    (no matching commit)
  - [v7,22/31] objtool: Add noinstr validation for static branches/calls
    (no matching commit)
  - [v7,23/31] module: Add MOD_NOINSTR_TEXT mem_type
    (no matching commit)
  - [v7,24/31] context-tracking: Introduce work deferral infrastructure
    (no matching commit)
  - [v7,25/31] context_tracking,x86: Defer kernel text patching IPIs
    (no matching commit)
  - [v7,26/31] x86/jump_label: Add ASM support for static_branch_likely()
    (no matching commit)
  - [v7,27/31] x86/mm: Make INVPCID type macros available to assembly
    (no matching commit)
  - [RFC,v7,28/31] x86/mm/pti: Introduce a kernel/user CR3 software signal
    (no matching commit)
  - [RFC,v7,29/31] x86/mm/pti: Implement a TLB flush immediately after a switch to kernel CR3
    (no matching commit)
  - [RFC,v7,30/31] x86/mm, mm/vmalloc: Defer kernel TLB flush IPIs under CONFIG_COALESCE_TLBI=y
    (no matching commit)
  - [RFC,v7,31/31] x86/entry: Add an option to coalesce TLB flushes
    (no matching commit)

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html




From patchwork-bot+linux-riscv at kernel.org  Fri Dec 19 00:10:07 2025
From: patchwork-bot+linux-riscv at kernel.org (patchwork-bot+linux-riscv at kernel.org)
Date: Fri, 19 Dec 2025 08:10:07 +0000
Subject: [patch V5 00/12] uaccess: Provide and use scopes for user access
In-Reply-To: <20251027083700.573016505@linutronix.de>
References: <20251027083700.573016505@linutronix.de>
Message-ID: <176613180728.3684357.15978002339429469981.git-patchwork-notify@kernel.org>

Hello:

This series was applied to riscv/linux.git (fixes)
by Ingo Molnar <mingo at kernel.org>:

On Mon, 27 Oct 2025 09:43:40 +0100 (CET) you wrote:
> This is a follow up on the V4 feedback:
> 
>    https://lore.kernel.org/20251022102427.400699796 at linutronix.de
> 
> Changes vs. V4:
> 
>   - Rename get/put_user_masked() to get/put_user_inline()
> 
> [...]

Here is the summary with links:
  - [V5,01/12] ARM: uaccess: Implement missing __get_user_asm_dword()
    https://git.kernel.org/riscv/c/44c5b6768e3a
  - [V5,02/12] uaccess: Provide ASM GOTO safe wrappers for unsafe_*_user()
    (no matching commit)
  - [V5,03/12] x86/uaccess: Use unsafe wrappers for ASM GOTO
    https://git.kernel.org/riscv/c/14219398e3e1
  - [V5,04/12] powerpc/uaccess: Use unsafe wrappers for ASM GOTO
    https://git.kernel.org/riscv/c/5002dd53144f
  - [V5,05/12] riscv/uaccess: Use unsafe wrappers for ASM GOTO
    https://git.kernel.org/riscv/c/0988ea18c624
  - [V5,06/12] s390/uaccess: Use unsafe wrappers for ASM GOTO
    https://git.kernel.org/riscv/c/43cc54d8dbe6
  - [V5,07/12] uaccess: Provide scoped user access regions
    https://git.kernel.org/riscv/c/e497310b4ffb
  - [V5,08/12] uaccess: Provide put/get_user_inline()
    https://git.kernel.org/riscv/c/b2cfc0cd68b8
  - [V5,09/12,RFC] coccinelle: misc: Add scoped_masked_$MODE_access() checker script
    (no matching commit)
  - [V5,10/12] futex: Convert to get/put_user_inline()
    https://git.kernel.org/riscv/c/e4e28fd6986e
  - [V5,11/12] x86/futex: Convert to scoped user access
    https://git.kernel.org/riscv/c/e02718c9865c
  - [V5,12/12] select: Convert to scoped user access
    https://git.kernel.org/riscv/c/3ce17e690994

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html




From patchwork-bot+linux-riscv at kernel.org  Fri Dec 19 00:10:09 2025
From: patchwork-bot+linux-riscv at kernel.org (patchwork-bot+linux-riscv at kernel.org)
Date: Fri, 19 Dec 2025 08:10:09 +0000
Subject: [PATCH v2 0/6] iommu: Pass in old_domain pointer to attach_dev
In-Reply-To: <cover.1761017765.git.nicolinc@nvidia.com>
References: <cover.1761017765.git.nicolinc@nvidia.com>
Message-ID: <176613180983.3684357.11179224135837486617.git-patchwork-notify@kernel.org>

Hello:

This series was applied to riscv/linux.git (fixes)
by Joerg Roedel <joerg.roedel at amd.com>:

On Wed, 22 Oct 2025 19:21:03 -0700 you wrote:
> Tidy the release_device callbacks in the drivers and switch to the core
> managed release_domain.
> 
> This allows the core further to pass in the old domain pointer into the
> attach_dev callbacks to reduce the use of iommu_get_domain_for_dev().
> 
> This is a preparatory series for new iommu_dev_reset APIs:
> https://lore.kernel.org/all/cover.1756682135.git.nicolinc at nvidia.com/
> 
> [...]

Here is the summary with links:
  - [v2,1/6] iommu: Generic support for RMRs during device release
    https://git.kernel.org/riscv/c/e94160488e65
  - [v2,2/6] iommu/arm-smmu-v3: Set release_domain to arm_smmu_blocked_domain
    https://git.kernel.org/riscv/c/52f77fb176ec
  - [v2,3/6] iommu/exynos-iommu: Set release_domain to exynos_identity_domain
    https://git.kernel.org/riscv/c/680a6a60fc08
  - [v2,4/6] iommu/amd: Set release_domain to blocked_domain
    https://git.kernel.org/riscv/c/c21b34762e2f
  - [v2,5/6] iommu: Do not revert set_domain for the last gdev
    https://git.kernel.org/riscv/c/2b33598e666d
  - [v2,6/6] iommu: Pass in old domain to attach_dev callback functions
    (no matching commit)

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html




From patchwork-bot+linux-riscv at kernel.org  Fri Dec 19 00:10:12 2025
From: patchwork-bot+linux-riscv at kernel.org (patchwork-bot+linux-riscv at kernel.org)
Date: Fri, 19 Dec 2025 08:10:12 +0000
Subject: [patch V3 00/12] uaccess: Provide and use scopes for user masked
 access
In-Reply-To: <20251017085938.150569636@linutronix.de>
References: <20251017085938.150569636@linutronix.de>
Message-ID: <176613181252.3684357.901874888075051255.git-patchwork-notify@kernel.org>

Hello:

This series was applied to riscv/linux.git (fixes)
by Peter Zijlstra <peterz at infradead.org>:

On Fri, 17 Oct 2025 12:08:54 +0200 (CEST) you wrote:
> This is a follow up on the V2 feedback:
> 
>    https://lore.kernel.org/20250916163004.674341701 at linutronix.de
> 
> The main concern over the V2 implementation was the requirement to have
> the code within the macro itself.
> 
> [...]

Here is the summary with links:
  - [V3,01/12] ARM: uaccess: Implement missing __get_user_asm_dword()
    (no matching commit)
  - [V3,02/12] uaccess: Provide ASM GOTO safe wrappers for unsafe_*_user()
    (no matching commit)
  - [V3,03/12] x86/uaccess: Use unsafe wrappers for ASM GOTO
    (no matching commit)
  - [V3,04/12] powerpc/uaccess: Use unsafe wrappers for ASM GOTO
    (no matching commit)
  - [V3,05/12] riscv/uaccess: Use unsafe wrappers for ASM GOTO
    https://git.kernel.org/riscv/c/0988ea18c624
  - [V3,06/12] s390/uaccess: Use unsafe wrappers for ASM GOTO
    (no matching commit)
  - [V3,07/12] uaccess: Provide scoped masked user access regions
    (no matching commit)
  - [V3,08/12] uaccess: Provide put/get_user_masked()
    (no matching commit)
  - [V3,09/12,RFC] coccinelle: misc: Add scoped_masked_$MODE_access() checker script
    (no matching commit)
  - [V3,10/12] futex: Convert to scoped masked user access
    (no matching commit)
  - [V3,11/12] x86/futex: Convert to scoped masked user access
    (no matching commit)
  - [V3,12/12] select: Convert to scoped masked user access
    (no matching commit)

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html




From patchwork-bot+linux-riscv at kernel.org  Fri Dec 19 00:10:15 2025
From: patchwork-bot+linux-riscv at kernel.org (patchwork-bot+linux-riscv at kernel.org)
Date: Fri, 19 Dec 2025 08:10:15 +0000
Subject: [patch V6 02/12] uaccess: Provide ASM GOTO safe wrappers for
 unsafe_*_user()
In-Reply-To: <877bweujtn.ffs@tglx>
References: <877bweujtn.ffs@tglx>
Message-ID: <176613181528.3684357.16950067300895090684.git-patchwork-notify@kernel.org>

Hello:

This patch was applied to riscv/linux.git (fixes)
by Peter Zijlstra <peterz at infradead.org>:

On Wed, 29 Oct 2025 10:40:52 +0100 you wrote:
> ASM GOTO is miscompiled by GCC when it is used inside a auto cleanup scope:
> 
> bool foo(u32 __user *p, u32 val)
> {
> 	scoped_guard(pagefault)
> 		unsafe_put_user(val, p, efault);
> 	return true;
> efault:
> 	return false;
> }
> 
> [...]

Here is the summary with links:
  - [V6,02/12] uaccess: Provide ASM GOTO safe wrappers for unsafe_*_user()
    https://git.kernel.org/riscv/c/3eb6660f26d1

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html




From krzk at kernel.org  Fri Dec 19 00:13:18 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 09:13:18 +0100
Subject: [PATCH 1/3] dt-bindings: arm: fsl: add i.MX952 EVK board
In-Reply-To: <20251217-imx952-v1-v1-1-a55a7fe2df0b@nxp.com>
References: <20251217-imx952-v1-v1-0-a55a7fe2df0b@nxp.com>
 <20251217-imx952-v1-v1-1-a55a7fe2df0b@nxp.com>
Message-ID: <20251219-inescapable-powerful-bettong-3e9dbc@quoll>

On Wed, Dec 17, 2025 at 09:58:26AM +0800, Peng Fan (OSS) wrote:
> From: Peng Fan <peng.fan at nxp.com>
> 
> Add DT compatible string for NXP i.MX952 EVK board.
> 
> Signed-off-by: Peng Fan <peng.fan at nxp.com>
> ---
>  Documentation/devicetree/bindings/arm/fsl.yaml | 6 ++++++
>  1 file changed, 6 insertions(+)

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof



From krzk at kernel.org  Fri Dec 19 00:17:44 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 09:17:44 +0100
Subject: [PATCH v2 1/5] dt-bindings: mfd: maxim,max77759: add charger
 child node
In-Reply-To: <20251218-max77759-charger-v2-1-2b259980a686@google.com>
References: <20251218-max77759-charger-v2-0-2b259980a686@google.com>
 <20251218-max77759-charger-v2-1-2b259980a686@google.com>
Message-ID: <411802b6-517d-497e-bf7b-183e6e6d7a64@kernel.org>

On 18/12/2025 23:49, Amit Sunil Dhamne via B4 Relay wrote:
> From: Amit Sunil Dhamne <amitsd at google.com>
> 
> The Maxim MAX77759 MFD includes a charger function. Extend the max77759
> binding to include the charger. Also, update the example to include
> charger.
> 
> Signed-off-by: Amit Sunil Dhamne <amitsd at google.com>
> ---
>  .../devicetree/bindings/mfd/maxim,max77759.yaml    | 33 ++++++++++++++++++++++
>  1 file changed, 33 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml b/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml
> index 525de9ab3c2b..1cffdf2e5776 100644
> --- a/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml
> +++ b/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml
> @@ -37,6 +37,30 @@ properties:
>    nvmem-0:
>      $ref: /schemas/nvmem/maxim,max77759-nvmem.yaml
>  
> +  charger:
> +    type: object
> +    description: This is a dual input switch mode battery charger for portable
> +      applications. It supports wired and wireless charging and can operate in
> +      buck and boost mode.
> +


I do not see any improvements, so same comment: this should be folded
into the parent.

Please read DTS 101 slides or writing bindings or any other talks...

Best regards,
Krzysztof


From krzk at kernel.org  Fri Dec 19 00:19:06 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 09:19:06 +0100
Subject: [PATCH v2 2/5] dt-bindings: usb: maxim,max33359: Add supply
 property for vbus
In-Reply-To: <20251218-max77759-charger-v2-2-2b259980a686@google.com>
References: <20251218-max77759-charger-v2-0-2b259980a686@google.com>
 <20251218-max77759-charger-v2-2-2b259980a686@google.com>
Message-ID: <90c00d57-3737-4631-a2e9-8ff2e315db14@kernel.org>

On 18/12/2025 23:49, Amit Sunil Dhamne via B4 Relay wrote:
> From: Amit Sunil Dhamne <amitsd at google.com>
> 
> Add a regulator supply property for vbus. This notifies the regulator
> provider to source vbus when Type-C operates in Source power mode,
> while turn off sourcing vbus when operating in Sink mode or
> disconnected.
> 
> Signed-off-by: Amit Sunil Dhamne <amitsd at google.com>
> ---
>  Documentation/devicetree/bindings/usb/maxim,max33359.yaml | 4 ++++
>  1 file changed, 4 insertions(+)


Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof


From kevin.tung.openbmc at gmail.com  Fri Dec 19 00:26:02 2025
From: kevin.tung.openbmc at gmail.com (Kevin Tung)
Date: Fri, 19 Dec 2025 16:26:02 +0800
Subject: [PATCH 3/3] ARM: dts: aspeed: yosemite5: Rename sgpio P0_I3C_APML_ALERT_L
In-Reply-To: <74b9c09cebac1de0e6e2e712a1374ab5294f61d8.camel@codeconstruct.com.au>
References: <20251118-yv5_revise_dts-v1-0-fcd6b44b4497@gmail.com>
 <20251118-yv5_revise_dts-v1-3-fcd6b44b4497@gmail.com> <74b9c09cebac1de0e6e2e712a1374ab5294f61d8.camel@codeconstruct.com.au>
Message-ID: <CABh9gBd8Mvpyv5WmFMQ7T4uDirxjprKpnq90+if11UOKZ4CN_Q@mail.gmail.com>

Hi Andrew,

I?ve sent v3 of this series to address these concerns.
The signal rename has been reverted to avoid breaking any existing
user space dependencies. In addition, a new patch has been added to
introduce additional SGPIO line names and a more detailed
discussion in the commit message.

BR,
Kevin

On Mon, Nov 24, 2025 at 12:44?PM Andrew Jeffery
<andrew at codeconstruct.com.au> wrote:
>
> On Tue, 2025-11-18 at 18:53 +0800, Kevin Tung wrote:
> > Rename P0_I3C_APML_ALERT_L to FM_APML_CPU_ALERT_N for clarity.
>
> Are user space components looking for these names? Will updating the
> devicetree break older applications? I'd like to see more discussion of
> these problems in the commit message.
>
> Cheers,
>
> Andrew
>
> >
> > Signed-off-by: Kevin Tung <kevin.tung.openbmc at gmail.com>
> > ---
> >  arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts
> > index 45b8ac2e8c65a4f672e64571631b7f6944f26213..060757b7211a6da777c51d9f0c886796cf2450a4 100644
> > --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts
> > +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts
> > @@ -964,7 +964,7 @@ &sgpiom0 {
> >       "FAULT_P3V3_NIC_N","",
> >       "FAULT_P12V_NIC_N","",
> >       "FAULT_P12V_SCM_N","",
> > -     "P0_I3C_APML_ALERT_L","",
> > +     "FM_APML_CPU_ALERT_N","",
> >       "ALERT_INLET_TEMP_N","",
> >       "FM_CPU_PROCHOT_R_N","",
> >       "FM_CPU_THERMTRIP_N","",


From vvidwans at nvidia.com  Fri Dec 19 00:26:30 2025
From: vvidwans at nvidia.com (Vedashree Vidwans)
Date: Fri, 19 Dec 2025 00:26:30 -0800
Subject: [RFC PATCH 4/5] firmware: smccc: register as platform driver
In-Reply-To: <20251209-hysterical-cobalt-viper-54433c@sudeepholla>
References: <20251208221319.1524888-1-vvidwans@nvidia.com>
 <20251208221319.1524888-5-vvidwans@nvidia.com>
 <20251209-hysterical-cobalt-viper-54433c@sudeepholla>
Message-ID: <29248f8c-b57d-4818-851c-7905dc9f8317@nvidia.com>



On 12/9/25 03:47, Sudeep Holla wrote:
> On Mon, Dec 08, 2025 at 10:13:14PM +0000, Vedashree Vidwans wrote:
>> - Update driver to be in-built kernel module. This will ensure driver is
>> installed in kernel and would not require any user intervention.
>> - Register the LFA driver as a platform driver corresponding to
>> 'armhf000' device. The driver will be invoked when the device is
>> detected on a platform.
>> - Add functionality to register LFA interrupt in the driver probe().
>> This LFA IRQ number will be retrived from the LFA device node.
>> - On IRQ, driver will query FW component details and trigger activation
>> of capable and pending FW component. The driver will loop to update FW
>> component details after every successful FW component activation.
>> - Mutex synchronization is implemented to avoid concurrent LFA updates
>> through interrupt and sysfs interfaces.
>>
>> Device node snippet from LFA spec[1]:
>> fwu0 {
>>      compatible = "arm,armhf000";
>>      memory-region = <&fwu_payload>;
>>      interrupt-parent = <&ic>;
>>      interrupts = <0 100 1>; // SPI, Interrupt #100, Edge Rising
>> };
>>
> 
> This will be gone in the latest beta of LFA, so please discuss and get
> an agreement for the LFA device tree bindings.
> 
> We don't just use ACPI HID as devicetree compatibles. There are more
> aligned with ACPI CID IIUC but I don't expect you to use ACPI CID just to
> match DT compatible as ACPI HID will be defined for LFA.
> 
Thank you for your comment.
Sorry I haven't completely understood the concern here. I am using the 
ACPI HID and device node compatible string provided by the LFA spec.
Please find below ACPI and device tree node from the spec for reference.
In case the LFA spec is updated, I will revise the driver implementation.

LFA spec: https://developer.arm.com/documentation/den0147/latest/

ACPI node:
DefinitionBlock ("", "SSDT", 2, "XXXXXX", "XXXXXXXX", 1) {
     Scope (\_SB)
     {
         Device (FWU0) {
             Name (_HID, "ARMHF000") // Arm HAFW DSDT table identifier.
             Name (_CRS, ResourceTemplate () {

                 // Payload buffer description.
                 QWordMemory (,
                     ,
                     MinFixed,
                     MaxFixed,
                     NonCacheable,
                     ReadWrite,
                     0x0,
                     0x2000, // base PA of payload buffer
                     0x2FFF, // top PA of payload buffer
                     0,
                     0x1000, // payload buffer length
                     ,
                     ,
                 )

                 // Interrupt signaling the updated Live Activation Store.
                 Interrupt(,
                     Edge, // Interrupt type (or interrupt mode)
                     ActiveHigh, // Interrupt level
                     ,
                     ,
                     ,
                 ) {100} // Note that this is an example interrupt.
                     // The interrupt ID is defined per-platform.
             })

             // _DSD -- Holds map between field names and objects within 
the _CRS
             Name (_DSD, Package () {
                 ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa30") ,
                 Package() {
                     // Contains a set of packages of 2 entries each,
                     // the second entry is an index into the _CRS.
                     Package (2) {"payload-buffer", 1},
                     Package (2) {"fw-store-updated-interrupt", 2},
                 },
             })
         }
     }
}

Device Tree node:
/dts-v1/;
/ {
     #address-cells = <2>;
     #size-cells = <2>;
     ic: interrupt-controller at 2f000000 {
         compatible = "arm,gic-v3";
         #interrupt-cells = <3>;
         #address-cells = <2>;
         #size-cells = <2>;
         interrupt-controller;
         reg = <0x0 0x2f000000 0x0 0x10000>,
               <0x0 0x2f100000 0x0 0x200000>;
     };

     reserved-memory {
         #address-cells = <2>;
         #size-cells = <2>;
         ranges;
         fwu_payload: fwu_payload at 2000 {
             reg = <0x0 0x2000 0x0 0x1000>;
             no-map;
         };
     };

     soc {
         #address-cells = <2>;
         #size-cells = <2>;
         ranges;
         fwu0 {
             compatible = "arm,armhf000";
             memory-region = <&fwu_payload>;
             interrupt-parent = <&ic>;
             interrupts = <0 100 1>; // SPI, Interrupt #100, Edge Rising
         };
     };
};

>> [1] https://developer.arm.com/documentation/den0147/latest/
>>
>> Signed-off-by: Vedashree Vidwans <vvidwans at nvidia.com>
>> ---
>>   drivers/firmware/smccc/Kconfig  |   3 +-
>>   drivers/firmware/smccc/lfa_fw.c | 124 +++++++++++++++++++++++++++++++-
>>   2 files changed, 125 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/firmware/smccc/Kconfig b/drivers/firmware/smccc/Kconfig
>> index 48b98c14f770..c21be43fbfed 100644
>> --- a/drivers/firmware/smccc/Kconfig
>> +++ b/drivers/firmware/smccc/Kconfig
>> @@ -25,8 +25,9 @@ config ARM_SMCCC_SOC_ID
>>   	  platforms providing some sysfs information about the SoC variant.
>>   
>>   config ARM_LFA
>> -	tristate "Arm Live Firmware activation support"
>> +	bool "Arm Live Firmware activation support"
>>   	depends on HAVE_ARM_SMCCC_DISCOVERY
>> +	default y
>>   	help
>>   	  Include support for triggering Live Firmware Activation, which
>>   	  allows to upgrade certain firmware components without a reboot.
>> diff --git a/drivers/firmware/smccc/lfa_fw.c b/drivers/firmware/smccc/lfa_fw.c
>> index 0e420cefa260..24916fc53420 100644
>> --- a/drivers/firmware/smccc/lfa_fw.c
>> +++ b/drivers/firmware/smccc/lfa_fw.c
>> @@ -19,7 +19,12 @@
>>   #include <linux/nmi.h>
>>   #include <linux/ktime.h>
>>   #include <linux/delay.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/acpi.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/mutex.h>
>>   
>> +#define DRIVER_NAME	"ARM_LFA"
>>   #define LFA_ERROR_STRING(name) \
>>   	[name] = #name
>>   #undef pr_fmt
>> @@ -129,6 +134,7 @@ static const struct fw_image_uuid {
>>   };
>>   
>>   static struct kobject *lfa_dir;
>> +static DEFINE_MUTEX(lfa_lock);
>>   
>>   static int get_nr_lfa_components(void)
>>   {
>> @@ -374,17 +380,23 @@ static ssize_t activate_store(struct kobject *kobj, struct kobj_attribute *attr,
>>   					 image_attrs[LFA_ATTR_ACTIVATE]);
>>   	int ret;
>>   
>> +	if (!mutex_trylock(&lfa_lock)) {
>> +		pr_err("Mutex locked, try again");
>> +		return -EAGAIN;
>> +	}
>> +
>>   	ret = activate_fw_image(attrs);
>>   	if (ret) {
>>   		pr_err("Firmware activation failed: %s\n",
>>   			lfa_error_strings[-ret]);
>> -
>> +		mutex_unlock(&lfa_lock);
>>   		return -ECANCELED;
>>   	}
>>   
>>   	pr_info("Firmware activation succeeded\n");
>>   
>>   	/* TODO: refresh image flags here*/
>> +	mutex_unlock(&lfa_lock);
>>   	return count;
>>   }
>>   
>> @@ -510,6 +522,106 @@ static int create_fw_images_tree(void)
>>   	return 0;
>>   }
>>   
>> +static irqreturn_t lfa_irq_thread(int irq, void *data)
>> +{
>> +	struct image_props *attrs = NULL;
>> +	int ret;
>> +	int num_of_components, curr_component;
>> +
>> +	mutex_lock(&lfa_lock);
>> +
>> +	/*
>> +	 * As per LFA spec, after activation of a component, the caller
>> +	 * is expected to re-enumerate the component states (using
>> +	 * LFA_GET_INFO then LFA_GET_INVENTORY).
>> +	 * Hence we need an unconditional loop.
>> +	 */
>> +
>> +	do {
>> +		/* TODO: refresh image flags here */
>> +		/* If refresh fails goto exit_unlock */
>> +
>> +		/* Initialize counters to track list traversal  */
>> +		num_of_components = get_nr_lfa_components();
>> +		curr_component = 0;
>> +
>> +		/* Execute PRIME and ACTIVATE for activable FW component */
>> +		list_for_each_entry(attrs, &lfa_fw_images, image_node) {
>> +			curr_component++;
>> +			if ((!attrs->activation_capable) || (!attrs->activation_pending)) {
>> +				/* LFA not applicable for this FW component */
>> +				continue;
>> +			}
>> +
>> +			ret = activate_fw_image(attrs);
>> +			if (ret) {
>> +				pr_err("Firmware %s activation failed: %s\n",
>> +					attrs->image_name, lfa_error_strings[-ret]);
>> +				goto exit_unlock;
>> +			}
>> +
>> +			pr_info("Firmware %s activation succeeded", attrs->image_name);
>> +			/* Refresh FW component details */
>> +			break;
>> +		}
>> +	} while (curr_component < num_of_components);
>> +
>> +	/* TODO: refresh image flags here */
>> +	/* If refresh fails goto exit_unlock */
>> +
>> +exit_unlock:
>> +	mutex_unlock(&lfa_lock);
>> +	return IRQ_HANDLED;
>> +}
>> +
>> +static int __init lfa_probe(struct platform_device *pdev)
>> +{
>> +	int err;
>> +	unsigned int irq;
>> +
>> +	err = platform_get_irq_byname_optional(pdev, "fw-store-updated-interrupt");
> 
> Nice, "fw-store-updated-interrupt" is not even mentioned in the example DT
> node above, let alone proper DT bindings.
> 
Thank you for pointing this out. The DT binding would have to be updated 
to below or the driver will fall back to platform_get_irq().

fwu0 {
     compatible = "arm,armhf000";
     memory-region = <&fwu_payload>;
     interrupt-parent = <&ic>;
     interrupts = <0 100 1>; // SPI, Interrupt #100, Edge Rising
     interrupt-names = "fw-store-updated-interrupt";
};

Regards,
Veda


From xu.yang_2 at nxp.com  Fri Dec 19 00:30:04 2025
From: xu.yang_2 at nxp.com (Xu Yang)
Date: Fri, 19 Dec 2025 16:30:04 +0800
Subject: [PATCH] phy: fsl-imx8mq-usb: enable RxTermination_override_sel
Message-ID: <20251219083004.3883898-1-xu.yang_2@nxp.com>

This is to resolve the problem of wakeup system by USB3 device
insertion if HSIOMIX on, in that case, the USB3 device detects
RX term on so doesn't downgrade to USB2, so DP/DM wakeup can't
happen, with this override bit we can force the RX term off when
enters system suspend, and disable the override after system resume.

Signed-off-by: Li Jun <jun.li at nxp.com>
Signed-off-by: Xu Yang <xu.yang_2 at nxp.com>
---
 drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
index 02d9af409b08..0831ed465775 100644
--- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
+++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
@@ -52,6 +52,7 @@
 #define PHY_CTRL5_PCS_TX_SWING_FULL_MASK	GENMASK(6, 0)
 
 #define PHY_CTRL6			0x18
+#define PHY_CTRL6_RXTERM_OVERRIDE_SEL	BIT(29)
 #define PHY_CTRL6_ALT_CLK_EN		BIT(1)
 #define PHY_CTRL6_ALT_CLK_SEL		BIT(0)
 
@@ -847,6 +848,7 @@ static int imx8mp_usb_phy_init(struct phy *phy)
 static int imx8mq_phy_power_on(struct phy *phy)
 {
 	struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
+	u32 value;
 	int ret;
 
 	ret = regulator_enable(imx_phy->vbus);
@@ -863,12 +865,23 @@ static int imx8mq_phy_power_on(struct phy *phy)
 		return ret;
 	}
 
-	return ret;
+	/* Disable rx term override */
+	value = readl(imx_phy->base + PHY_CTRL6);
+	value &= ~PHY_CTRL6_RXTERM_OVERRIDE_SEL;
+	writel(value, imx_phy->base + PHY_CTRL6);
+
+	return 0;
 }
 
 static int imx8mq_phy_power_off(struct phy *phy)
 {
 	struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
+	u32 value;
+
+	/* Override rx term to be 0 */
+	value = readl(imx_phy->base + PHY_CTRL6);
+	value |= PHY_CTRL6_RXTERM_OVERRIDE_SEL;
+	writel(value, imx_phy->base + PHY_CTRL6);
 
 	clk_disable_unprepare(imx_phy->alt_clk);
 	clk_disable_unprepare(imx_phy->clk);
-- 
2.34.1



From kevin.tung.openbmc at gmail.com  Fri Dec 19 00:36:08 2025
From: kevin.tung.openbmc at gmail.com (Kevin Tung)
Date: Fri, 19 Dec 2025 16:36:08 +0800
Subject: [PATCH 2/3] ARM: dts: aspeed: yosemite5: Update sensor configuration
In-Reply-To: <ad11cd30eddc1b7c496cc92eef129eb5c0f2d604.camel@codeconstruct.com.au>
References: <20251118-yv5_revise_dts-v1-0-fcd6b44b4497@gmail.com>
 <20251118-yv5_revise_dts-v1-2-fcd6b44b4497@gmail.com> <ad11cd30eddc1b7c496cc92eef129eb5c0f2d604.camel@codeconstruct.com.au>
Message-ID: <CABh9gBeCU7Xr818AL2ud4SxFQ=D=4D9YwiDUu4HttWuOqO+7ag@mail.gmail.com>

Hi Andrew,

Sure. I?ve added more detail in the v3 patch to clarify the hardware
revisions and the rationale behind this change.

Across Yosemite5 board variants, two different power monitor devices
(using different drivers) reuse the same I2C addresses 0x40 and 0x45
on bus 10. As the hardware evolved, newer board revisions replaced the
original devices with different ones at the same addresses.

Keeping these devices statically defined in the DTS can therefore
result in incorrect driver binding when running on newer hardware.
To avoid this, the 10-0040 and 10-0045 device nodes are removed from
the DTS, and the probe of the driver is instead handled in user space by
the OpenBMC Entity Manager based on the detected board configuration.

BR,
Kevin

On Mon, Nov 24, 2025 at 12:42?PM Andrew Jeffery
<andrew at codeconstruct.com.au> wrote:
>
> On Tue, 2025-11-18 at 18:53 +0800, Kevin Tung wrote:
> > Remove sensors 10-0040 and 10-0045 to align with the latest
> > hardware design changes.
>
> Can you please elaborate on this commit message? I'd like this
> description to be much more specific about revisions of the hardware
> design, and why you expect all instances of the previous design to
> suddenly stop existing.
>
> I can't imagine this is the only hardware change that occurred. What
> other changes are lurking?
>
> Andrew
>
> >
> > Signed-off-by: Kevin Tung <kevin.tung.openbmc at gmail.com>
> > ---
> >  arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts | 14 --------------
> >  1 file changed, 14 deletions(-)
> >
> > diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts
> > index 7991e9360847532cff9aad4ad4ed57d4c30668a0..45b8ac2e8c65a4f672e64571631b7f6944f26213 100644
> > --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts
> > +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts
> > @@ -674,20 +674,6 @@ gpio-expander at 22 {
> >                       "PWRGD_P3V3_AUX","ALERT_TEMP";
> >       };
> >
> > -     power-sensor at 40 {
> > -             compatible = "ti,ina233";
> > -             reg = <0x40>;
> > -             shunt-resistor = <2000>;
> > -             ti,maximum-expected-current-microamp = <32768000>;
> > -     };
> > -
> > -     power-sensor at 45 {
> > -             compatible = "ti,ina233";
> > -             reg = <0x45>;
> > -             shunt-resistor = <2000>;
> > -             ti,maximum-expected-current-microamp = <32768000>;
> > -     };
> > -
> >       adc at 48 {
> >               compatible = "ti,ads7830";
> >               reg = <0x48>;


From kevin.tung.openbmc at gmail.com  Fri Dec 19 00:39:02 2025
From: kevin.tung.openbmc at gmail.com (Kevin Tung)
Date: Fri, 19 Dec 2025 16:39:02 +0800
Subject: [PATCH v2 0/4] Revise Meta Yosemite5 devicetree
In-Reply-To: <c56ef6e76858c7df19ec43a3a18ccf79ff3cc489.camel@codeconstruct.com.au>
References: <20251120-yv5_revise_dts-v2-0-4d7de701c5be@gmail.com> <c56ef6e76858c7df19ec43a3a18ccf79ff3cc489.camel@codeconstruct.com.au>
Message-ID: <CABh9gBcntYi6WeL6bOAAboUdic8afmn4X3-LW=zaHDditTr9OQ@mail.gmail.com>

Hi Andrew,

Sorry for the late reply. I?ve addressed the points raised in your review
and sent a follow up v3 patch series. Thanks.

BR,
Kevin

On Mon, Nov 24, 2025 at 12:53?PM Andrew Jeffery
<andrew at codeconstruct.com.au> wrote:
>
> Hi Kevin,
>
> On Thu, 2025-11-20 at 13:25 +0800, Kevin Tung wrote:
> > Summary:
> > Revise linux device tree entry related to Meta (Facebook) Yosemite5.
> >
> > Changes in v2:
> > - Add ipmb node for OCP debug card
> > - Link to v1: https://lore.kernel.org/r/20251118-yv5_revise_dts-v1-0-fcd6b44b4497 at gmail.com
> >
> > Changes in v1:
> > - Increase i2c4/i2c12 bus speed to 400 kHz
> > - Update sensor configuration
> > - Rename sgpio P0_I3C_APML_ALERT_L
>
> Sorry, I replied with comments on v1 before I saw v2.
>
> Can you please resolve the discussions on v1 and send a follow-up
> series if necessary?
>
> Andrew


From vvidwans at nvidia.com  Fri Dec 19 00:38:39 2025
From: vvidwans at nvidia.com (Vedashree Vidwans)
Date: Fri, 19 Dec 2025 00:38:39 -0800
Subject: [RFC PATCH 0/5] Arm LFA: Improvements and interrupt support
In-Reply-To: <20251209-miniature-curassow-of-energy-b6a303@sudeepholla>
References: <20251208221319.1524888-1-vvidwans@nvidia.com>
 <20251209-miniature-curassow-of-energy-b6a303@sudeepholla>
Message-ID: <8bca8c4b-52b8-4a1d-9f21-176c994a58bb@nvidia.com>



On 12/9/25 03:39, Sudeep Holla wrote:
> On Mon, Dec 08, 2025 at 10:13:10PM +0000, Vedashree Vidwans wrote:
>> Hello,
>>
>> The patches update the proposed Arm Live Firmware Activation (LFA)
>> kernel driver [1] to incorporate review feedback [2] and refine the
>> activation flow while remaining aligned with the LFA specification
>> DEN0147 [3] and the SMCCC 1.2 calling convention. The series keeps
>> the existing functionality but restructures and extends it to improve
>> robustness, reviewability, and future extensibility.?
>>
>> The SMCCC usage in the driver is updated to consistently use the
>> SMCCC 1.2 register-based calling convention, consolidating arguments
>> and results into a single struct to reduce stack usage and simplify
>> the SMC interface. The patches also split the original changes into
>> focused pieces and document the device node bindings in the commit
>> messages, making it easier to follow and validate the implementation
>> against the specification.?
>>
>> The kernel driver is registered as a platform driver in accordence to
>> the LFA device defined by the specification [3]. The driver now extends
>> interface for interrupt-based enablement of LFA. During LFA, the
>> interrupt
>> thread refreshes firmware component details after each activation step
>> and iterates over all activable components until no further activation
>> is pending, matching the spec?s allowance for component detail changes
>> after activation. This ensures that sysfs exposure of LFA components
>> remains consistent with the authoritative information provided by the
>> secure firmware.?
>>
>> The handling of CPU rendezvous is adjusted so that the kernel now
>> honors the rendezvous policy chosen by the firmware, instead of
>> unconditionally forcing a rendezvous. This reflects experience with
>> existing firmware deployments where mandatory rendezvous is not
>> required, while still allowing the firmware to request it when
>> needed.?
>>
>> Thank you,
>> Veda
>>
>> [1] https://lore.kernel.org/lkml/20250926123145.268728-1-salman.nabi at arm.com/
>> [2] https://lkml.org/lkml/2025/10/8/980
>> [3] https://developer.arm.com/documentation/den0147/latest/
>>
>> Vedashree Vidwans (5):
>>    firmware: smccc: LFA: use smcc 1.2
>>    firmware: smccc: LFA: refactor
>>    firmware: smccc: add timeout, touch wdt
>>    firmware: smccc: register as platform driver
>>    firmware: smccc: lfa: refresh fw details
>>
>>   drivers/firmware/smccc/Kconfig  |   3 +-
>>   drivers/firmware/smccc/lfa_fw.c | 478 +++++++++++++++++++++++++-------
> 
> Same comment as before[1], looks like the feedback got ignored or missed.
> 
> -- 
> Regards,
> Sudeep
> 
> [1]https://lore.kernel.org/all/20251009-calculating-glorious-oriole- 
> ceccf6 at sudeepholla

Thank you for your comment.
I did include DT binding in commit message of the patch. Please let me 
know if there's anything else I can elaborate.

Regards,
Veda


From vvidwans at nvidia.com  Fri Dec 19 00:47:52 2025
From: vvidwans at nvidia.com (Vedashree Vidwans)
Date: Fri, 19 Dec 2025 00:47:52 -0800
Subject: [RFC PATCH 1/5] firmware: smccc: LFA: use smcc 1.2
In-Reply-To: <20251209-curvy-walrus-of-wonder-dbb178@sudeepholla>
References: <20251208221319.1524888-1-vvidwans@nvidia.com>
 <20251208221319.1524888-2-vvidwans@nvidia.com>
 <20251209-curvy-walrus-of-wonder-dbb178@sudeepholla>
Message-ID: <b8fdec67-584f-492e-b2a7-8c932871f459@nvidia.com>



On 12/9/25 03:42, Sudeep Holla wrote:
> On Mon, Dec 08, 2025 at 10:13:11PM +0000, Vedashree Vidwans wrote:
>> Update driver to use SMCCC 1.2+ version as mentioned in the LFA spec.
>>
> 
> I would prefer if you work with Salman Nabi and get this incorporated
> in the original patch by providing this as a review feedback.
> 
> There is no point in having this independent of the original patch as it
> is not yet merged.
> 
> -- 
> Regards,
> Sudeep

Thank you for the suggestion.

Hi Salman,
Could we come up with a strategy to combine the LFA driver patches? I 
have been working on this recently and I would be happy to revise all 
the patches so that we are followiing the specification from the start.

Please let me know if you think of any other approach.

Regards,
Veda


From alexander.stein at ew.tq-group.com  Fri Dec 19 00:52:15 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Fri, 19 Dec 2025 09:52:15 +0100
Subject: [PATCH 0/6] Support TQMa8QM
In-Reply-To: <CAMuHMdUkghCNb96J38hbEZ8Jct6m2MPvnPumGp-y_dPfPW9eAg@mail.gmail.com>
References: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
 <CAMuHMdUkghCNb96J38hbEZ8Jct6m2MPvnPumGp-y_dPfPW9eAg@mail.gmail.com>
Message-ID: <24355727.EfDdHjke4D@steina-w>

Am Donnerstag, 18. Dezember 2025, 16:28:39 CET schrieb Geert Uytterhoeven:
> Hi Alexander,
> 
> On Thu, 18 Dec 2025 at 16:22, Alexander Stein
> <alexander.stein at ew.tq-group.com> wrote:
> > this series adds support for TQ's TQMa8QM. The first 3 patches are prepatory:
> > 1. Add support for clock-output-names for clk-renesas-pcie. This is necessary
> > as clk-imx8qxp-lpcg.c (driver for phyx1 phyx2 clock gating) reqiures that
> > property on the parent clock.
> 
> Hmm, clock consumers should have no business with the names used by
> clock providers, even less so whether those names are specified in DT
> or not.

Well drivers/clk/imx/clk-imx8qxp-lpcg.c does exactly this. AFAIK not just
the ones references in DT, but also hard codes ones.

The root cause is that clock-hsio-refa and clock-hsio-refb in
arch/arm64/boot/dts/freescale/imx8-ss-hsio.dtsi are setting platform-specific
GPIOs in SoC .dtsi...

My current idea is to use fixed-factor-clock instead:

> &hsio_refa_clk {
> 	compatible = "fixed-factor-clock";
> 	clocks = <&pcieclk 0>;
> 	clock-div = <1>;
> 	clock-mult = <1>;
> 	/delete-property/ enable-gpios;
> };
> 
> &hsio_refb_clk {
> 	compatible = "fixed-factor-clock";
> 	clocks = <&pcieclk 0>;
> 	clock-div = <1>;
> 	clock-mult = <1>;
> 	/delete-property/ enable-gpios;
> };

Best regards,
Alexander
-- 
TQ-Systems GmbH | M?hlstra?e 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht M?nchen, HRB 105018
Gesch?ftsf?hrer: Detlef Schneider, R?diger Stahl, Stefan Schneider
http://www.tq-group.com/




From alexander.stein at ew.tq-group.com  Fri Dec 19 00:52:40 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Fri, 19 Dec 2025 09:52:40 +0100
Subject: [PATCH 5/6] arm64: dts: Add TQ imx8qm based board
In-Reply-To: <CAOMZO5CmP_rdFA=PqGSmKDU+ObzifHFDjwYMD3J67bjs0h_sfw@mail.gmail.com>
References: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
 <20251218154412.1524249-1-alexander.stein@ew.tq-group.com>
 <CAOMZO5CmP_rdFA=PqGSmKDU+ObzifHFDjwYMD3J67bjs0h_sfw@mail.gmail.com>
Message-ID: <5334958.kQq0lBPeGt@steina-w>

Hi Fabio,

Am Donnerstag, 18. Dezember 2025, 16:47:33 CET schrieb Fabio Estevam:
> On Thu, Dec 18, 2025 at 12:45?PM Alexander Stein
> <alexander.stein at ew.tq-group.com> wrote:
> >
> > * TQMa8QM on MBa8x
> 
> This commit log should be improved by explaining the SoM and base
> board in more detail, providing a URL, etc.
> 

Will do, thanks.

Best regards,
Alexander
-- 
TQ-Systems GmbH | M?hlstra?e 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht M?nchen, HRB 105018
Gesch?ftsf?hrer: Detlef Schneider, R?diger Stahl, Stefan Schneider
http://www.tq-group.com/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251219/08618455/attachment-0001.sig>

From alexander.stein at ew.tq-group.com  Fri Dec 19 00:55:31 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Fri, 19 Dec 2025 09:55:31 +0100
Subject: [PATCH 2/6] dt-bindings: usb: cdns,usb3: support USB devices in DT
In-Reply-To: <20251218152058.1521806-3-alexander.stein@ew.tq-group.com>
References: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
 <20251218152058.1521806-3-alexander.stein@ew.tq-group.com>
Message-ID: <4732491.5fSG56mABF@steina-w>

Am Donnerstag, 18. Dezember 2025, 16:20:49 CET schrieb Alexander Stein:
> Reference usb-hxci.yaml in host mode in order to support on-board USB
> hubs.
> 
> Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
> ---
>  Documentation/devicetree/bindings/usb/cdns,usb3.yaml | 11 +++++++++++
>  1 file changed, 11 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/usb/cdns,usb3.yaml b/Documentation/devicetree/bindings/usb/cdns,usb3.yaml
> index f454ddd9bbaa6..1f7f0adc3b1ed 100644
> --- a/Documentation/devicetree/bindings/usb/cdns,usb3.yaml
> +++ b/Documentation/devicetree/bindings/usb/cdns,usb3.yaml
> @@ -85,6 +85,17 @@ required:
>  
>  allOf:
>    - $ref: usb-drd.yaml#
> +  - if:
> +      properties:
> +        dr_mode:
> +          const: peripheral
> +
> +      required:
> +        - dr_mode
> +    then:
> +      $ref: usb.yaml#
> +    else:
> +      $ref: usb-xhci.yaml#
>  
>  unevaluatedProperties: false
>  
> 

This one is actually independent of the rest in this series and can be
picked on it's own, especially as I won't be able to work on the board
support until February. I just wanted to give some context / usage.

Best regards,
Alexander
-- 
TQ-Systems GmbH | M?hlstra?e 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht M?nchen, HRB 105018
Gesch?ftsf?hrer: Detlef Schneider, R?diger Stahl, Stefan Schneider
http://www.tq-group.com/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251219/6651ea04/attachment.sig>

From alexander.stein at ew.tq-group.com  Fri Dec 19 00:55:38 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Fri, 19 Dec 2025 09:55:38 +0100
Subject: [PATCH 3/6] arm64: dts: imx8qm-ss-hsio: Wire up DMA IRQ for PCIe
In-Reply-To: <20251218152058.1521806-4-alexander.stein@ew.tq-group.com>
References: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
 <20251218152058.1521806-4-alexander.stein@ew.tq-group.com>
Message-ID: <10076440.NyiUUSuA9g@steina-w>

Am Donnerstag, 18. Dezember 2025, 16:20:50 CET schrieb Alexander Stein:
> IRQ mapping is already present. Add the missing DMA interrupt. This is
> similar to commit 0b4c46f9ad79c ("arm64: dts: imx8qm-ss-hsio: Wire up
> DMA IRQ for PCIe")
> 
> Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
> ---
>  arch/arm64/boot/dts/freescale/imx8qm-ss-hsio.dtsi | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/freescale/imx8qm-ss-hsio.dtsi b/arch/arm64/boot/dts/freescale/imx8qm-ss-hsio.dtsi
> index bd6e0aa27efe9..f2c94cdb682b9 100644
> --- a/arch/arm64/boot/dts/freescale/imx8qm-ss-hsio.dtsi
> +++ b/arch/arm64/boot/dts/freescale/imx8qm-ss-hsio.dtsi
> @@ -20,8 +20,9 @@ pcie0: pciea: pcie at 5f000000 {
>  		ranges = <0x81000000 0 0x00000000 0x4ff80000 0 0x00010000>,
>  			 <0x82000000 0 0x40000000 0x40000000 0 0x0ff00000>;
>  		#interrupt-cells = <1>;
> -		interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
> -		interrupt-names = "msi";
> +		interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>,
> +			     <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
> +		interrupt-names = "msi", "dma";
>  		#address-cells = <3>;
>  		#size-cells = <2>;
>  		clocks = <&pciea_lpcg IMX_LPCG_CLK_6>,
> 

This one is actually independent of the rest in this series and can be
picked on it's own, especially as I won't be able to work on the board
support until February. I just wanted to give some context / usage.

Best regards,
Alexander

-- 
TQ-Systems GmbH | M?hlstra?e 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht M?nchen, HRB 105018
Gesch?ftsf?hrer: Detlef Schneider, R?diger Stahl, Stefan Schneider
http://www.tq-group.com/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251219/ce0c5efc/attachment.sig>

From ahmed.tiba at arm.com  Fri Dec 19 01:02:35 2025
From: ahmed.tiba at arm.com (Ahmed Tiba)
Date: Fri, 19 Dec 2025 09:02:35 +0000
Subject: [PATCH 11/12] ras: add DeviceTree estatus provider driver
In-Reply-To: <aUQbdZHkzumTnwVP@willie-the-truck>
References: <aUQbdZHkzumTnwVP@willie-the-truck>
Message-ID: <20251219090239.2692458-1-ahmed.tiba@arm.com>

On Thu, 18 Dec 2025 03:19:17PM +0000, Will Deacon wrote:
> On Thu, Dec 18, 2025 at 01:42:47PM +0000, Ahmed Tiba wrote:
>> On Thu, 18 Dec 2025 12:13:25PM +0000, Will Deacon wrote:
>> >> Introduce a platform driver that maps the CPER status block described
>> >> in DeviceTree, feeds it into the estatus core and handles either IRQ- or
>> >> poll-driven notifications. Arm64 gains a FIX_ESTATUS_IRQ slot so the
>> >> driver can safely map the shared buffer while copying records.
>> >>
>> >> Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>
>> >> ---
>> >>  MAINTAINERS                     |   1 +
>> >>  arch/arm64/include/asm/fixmap.h |   5 +
>> >>  drivers/ras/Kconfig             |  14 ++
>> >>  drivers/ras/Makefile            |   1 +
>> >>  drivers/ras/estatus-dt.c        | 318 ++++++++++++++++++++++++++++++++
>> >>  include/linux/estatus.h         |   3 +-
>> >>  6 files changed, 341 insertions(+), 1 deletion(-)
>> >>  create mode 100644 drivers/ras/estatus-dt.c
>> >>
>> >> diff --git a/MAINTAINERS b/MAINTAINERS
>> >> index 6b2ef2ddc0c7..5567d5e82053 100644
>> >> --- a/MAINTAINERS
>> >> +++ b/MAINTAINERS
>> >> @@ -21761,6 +21761,7 @@ RAS ERROR STATUS
>> >>  M:   Ahmed Tiba <ahmed.tiba at arm.com>
>> >>  S:   Maintained
>> >>  F:   Documentation/devicetree/bindings/ras/arm,ras-ffh.yaml
>> >> +F:   drivers/ras/estatus-dt.c
>> >>  F:   drivers/firmware/efi/estatus.c
>> >>  F:   include/linux/estatus.h
>> >>
>> >> diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h
>> >> index 65555284446e..85ffba87bab9 100644
>> >> --- a/arch/arm64/include/asm/fixmap.h
>> >> +++ b/arch/arm64/include/asm/fixmap.h
>> >> @@ -64,6 +64,11 @@ enum fixed_addresses {
>> >>  #endif
>> >>  #endif /* CONFIG_ACPI_APEI_GHES */
>> >>
>> >> +#ifdef CONFIG_RAS_ESTATUS_DT
>> >> +     /* Used for ESTATUS mapping from assorted contexts */
>> >> +     FIX_ESTATUS_IRQ,
>> >> +#endif /* CONFIG_RAS_ESTATUS_DT */
>> >
>> > Why do we need this in addition to the four existing GHES slots? The DT
>> > code doesn't use it and I was assuming that the ACPI code would continue
>> > to use the existing irq; is that not the case?
>>
>>
>> We still need a dedicated slot when only the DT provider is built.
>> All four GHES slots are defined as part of the ACPI implementation,
>> so they are not present in a DT-only configuration.
>>
>> The estatus core always requests a fixmap index from each provider
>> before copying a CPER record. As a result, the DT driver must supply
>> its own slot to return a valid enum value to satisfy the common code.
>
> Sorry, but I still don't follow this. The DT code doesn't use the fixmap,
> does it? It looks like it maps the buffer ahead of time using
> devm_ioremap_resource() and then the accessors don't use the fixmap
> index at all, hence the horrible '(void)fixmap_idx;' cast which presumably
> stops the compiler from complaining about an unused variable.

Correct. The current DT driver keeps the CPER buffer permanently mapped with
devm_ioremap_resource() and that (void)fixmap_idx; line is just silencing
the warning. I?ll fix that by dropping the permanent mapping and copying the
status block via the fixmap entry, so the DT implementation mirrors GHES. That
gets rid of the cast and makes FIX_ESTATUS_IRQ do real work.


Thanks,
Ahmed


From jie.gan at oss.qualcomm.com  Fri Dec 19 01:08:39 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Fri, 19 Dec 2025 17:08:39 +0800
Subject: [PATCH v4 1/2] dt-bindings: arm: add CTCU device for monaco
In-Reply-To: <20251103-enable-ctcu-for-monaco-v4-1-92ff83201584@oss.qualcomm.com>
References: <20251103-enable-ctcu-for-monaco-v4-0-92ff83201584@oss.qualcomm.com>
 <20251103-enable-ctcu-for-monaco-v4-1-92ff83201584@oss.qualcomm.com>
Message-ID: <c6a75ea4-a36c-4f99-ae36-75f062937a66@oss.qualcomm.com>



On 11/3/2025 3:06 PM, Jie Gan wrote:
> The CTCU device for monaco shares the same configurations as SA8775p. Add
> a fallback to enable the CTCU for monaco to utilize the compitable of the
> SA8775p.
> 

Gentle reminder.

> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
> Acked-by: Suzuki K Poulose <suzuki.poulose at arm.com>
> Reviewed-by: Bjorn Andersson <andersson at kernel.org>
> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
> ---
>   Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml | 9 +++++++--
>   1 file changed, 7 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
> index c969c16c21ef..460f38ddbd73 100644
> --- a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
> +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
> @@ -26,8 +26,13 @@ description: |
>   
>   properties:
>     compatible:
> -    enum:
> -      - qcom,sa8775p-ctcu
> +    oneOf:
> +      - items:
> +          - enum:
> +              - qcom,qcs8300-ctcu
> +          - const: qcom,sa8775p-ctcu
> +      - enum:
> +          - qcom,sa8775p-ctcu
>   
>     reg:
>       maxItems: 1
> 



From sjg168 at gmail.com  Fri Dec 19 01:16:30 2025
From: sjg168 at gmail.com (Peter Shen)
Date: Fri, 19 Dec 2025 17:16:30 +0800
Subject: [PATCH v9 0/2] ARM: dts: aspeed: Add Facebook Anacapa platform
Message-ID: <20251219091632.1598603-1-sjg168@gmail.com>

The Meta Anacapa BMC is the DC-SCM (Data Center Secure Control
Module) controller for the Meta OCP Open Rack Wide (ORW) compute tray.
This platform is a key component of the AMD Helios AI rack reference
design system, designed for next-generation AI workloads.

The BMC utilizes the Aspeed AST2600 SoC to manage the compute tray, which
contains up to 4 AMD Instinct MI450 Series GPUs (connected via a Broadcom
OCP NIC) and host CPUs. Its primary role is to provide essential system
control, power sequencing, and telemetry reporting for the compute complex
via the OpenBMC software stack.

For more detail on the AMD Helios reference design:
https://www.amd.com/en/blogs/2025/amd-helios-ai-rack-built-on-metas-2025-ocp-design.html

Changes in v9:
  - Describe platform and hardware architecture (Andrew Jeffery).
  - Remove "Device Tree" from patch subjects (Andrew Jeffery).
  - Reconfigured aliases to be sequential (Andrew Jeffery).
  - Alphabetized all DTS label references (Andrew Jeffery).

Changes in v8:
  - Dropped unused 'pcc_memory' reserved memory (Andrew Jeffery).
  - Grouped 'spi-gpio' properties together (Andrew Jeffery).
  - Moved 'pinctrl_ncsi3_default' to aspeed-g6.dtsi (Andrew Jeffery).
  - Revised 'gpio-line-names' to match schematics (Andrew Jeffery).
  - Improved 'sgpio-line-names' formatting.
  - Removed unused 'led-2' definition.
  - Added ADC128D818 sensor support.

Peter Shen (2):
  dt-bindings: arm: aspeed: Add compatible for Facebook Anacapa BMC
  ARM: dts: aspeed: Add Facebook Anacapa platform

 .../bindings/arm/aspeed/aspeed.yaml           |    1 +
 arch/arm/boot/dts/aspeed/Makefile             |    1 +
 .../aspeed/aspeed-bmc-facebook-anacapa.dts    | 1045 +++++++++++++++++
 3 files changed, 1047 insertions(+)
 create mode 100644 arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-anacapa.dts

-- 
2.34.1


From sjg168 at gmail.com  Fri Dec 19 01:16:31 2025
From: sjg168 at gmail.com (Peter Shen)
Date: Fri, 19 Dec 2025 17:16:31 +0800
Subject: [PATCH v9 1/2] dt-bindings: arm: aspeed: Add compatible for Facebook Anacapa BMC
In-Reply-To: <20251219091632.1598603-1-sjg168@gmail.com>
References: <20251219091632.1598603-1-sjg168@gmail.com>
Message-ID: <20251219091632.1598603-2-sjg168@gmail.com>

This patch adds the compatible string for the Facebook Anacapa BMC
which uses an Aspeed AST2600 SoC. This is required before adding
the board's device tree source file.

Signed-off-by: Peter Shen <sjg168 at gmail.com>
Acked-by: KKrzysztof Kozlowski <krzk at kernel.org>
---
 Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
index 9298c1a75dd1..4cbd79363da2 100644
--- a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
+++ b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
@@ -80,6 +80,7 @@ properties:
               - aspeed,ast2600-evb
               - aspeed,ast2600-evb-a1
               - asus,x4tf-bmc
+              - facebook,anacapa-bmc
               - facebook,bletchley-bmc
               - facebook,catalina-bmc
               - facebook,clemente-bmc
-- 
2.34.1



From sjg168 at gmail.com  Fri Dec 19 01:16:32 2025
From: sjg168 at gmail.com (Peter Shen)
Date: Fri, 19 Dec 2025 17:16:32 +0800
Subject: [PATCH v9 2/2] ARM: dts: aspeed: Add Facebook Anacapa platform
In-Reply-To: <20251219091632.1598603-1-sjg168@gmail.com>
References: <20251219091632.1598603-1-sjg168@gmail.com>
Message-ID: <20251219091632.1598603-3-sjg168@gmail.com>

The Meta Anacapa BMC is the DC-SCM (Data Center Secure Control
Module) controller for the Meta OCP Open Rack Wide (ORW) compute tray.
This platform is a key component of the AMD Helios AI rack reference
design system, designed for next-generation AI workloads.

The BMC utilizes the Aspeed AST2600 SoC to manage the compute tray, which
contains up to 4 AMD Instinct MI450 Series GPUs (connected via a Broadcom
OCP NIC) and host CPUs. Its primary role is to provide essential system
control, power sequencing, and telemetry reporting for the compute complex
via the OpenBMC software stack.

For more detail on the AMD Helios reference design:

https://www.amd.com/en/blogs/2025/amd-helios-ai-rack-built-on-metas-2025-ocp-design.html

Signed-off-by: Peter Shen <sjg168 at gmail.com>
---
 arch/arm/boot/dts/aspeed/Makefile             |    1 +
 .../aspeed/aspeed-bmc-facebook-anacapa.dts    | 1045 +++++++++++++++++
 2 files changed, 1046 insertions(+)
 create mode 100644 arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-anacapa.dts

diff --git a/arch/arm/boot/dts/aspeed/Makefile b/arch/arm/boot/dts/aspeed/Makefile
index 9adf9278dc94..ad94b65703e9 100644
--- a/arch/arm/boot/dts/aspeed/Makefile
+++ b/arch/arm/boot/dts/aspeed/Makefile
@@ -17,6 +17,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \
 	aspeed-bmc-asus-x4tf.dtb \
 	aspeed-bmc-bytedance-g220a.dtb \
 	aspeed-bmc-delta-ahe50dc.dtb \
+	aspeed-bmc-facebook-anacapa.dtb \
 	aspeed-bmc-facebook-bletchley.dtb \
 	aspeed-bmc-facebook-catalina.dtb \
 	aspeed-bmc-facebook-clemente.dtb \
diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-anacapa.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-anacapa.dts
new file mode 100644
index 000000000000..221af858cb6b
--- /dev/null
+++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-anacapa.dts
@@ -0,0 +1,1045 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/dts-v1/;
+#include "aspeed-g6.dtsi"
+#include <dt-bindings/gpio/aspeed-gpio.h>
+#include <dt-bindings/i2c/i2c.h>
+
+/ {
+	model = "Facebook Anacapa BMC";
+	compatible = "facebook,anacapa-bmc", "aspeed,ast2600";
+
+	aliases {
+		serial0 = &uart1;
+		serial1 = &uart2;
+		serial2 = &uart3;
+		serial3 = &uart4;
+		serial4 = &uart5;
+		i2c16 = &i2c0mux0ch0;
+		i2c17 = &i2c0mux0ch1;
+		i2c18 = &i2c0mux0ch2;
+		i2c19 = &i2c0mux0ch3;
+		i2c20 = &i2c1mux0ch0;
+		i2c21 = &i2c1mux0ch1;
+		i2c22 = &i2c1mux0ch2;
+		i2c23 = &i2c1mux0ch3;
+		i2c24 = &i2c4mux0ch0;
+		i2c25 = &i2c4mux0ch1;
+		i2c26 = &i2c4mux0ch2;
+		i2c27 = &i2c4mux0ch3;
+		i2c28 = &i2c4mux0ch4;
+		i2c29 = &i2c4mux0ch5;
+		i2c30 = &i2c4mux0ch6;
+		i2c31 = &i2c4mux0ch7;
+		i2c32 = &i2c8mux0ch0;
+		i2c33 = &i2c8mux0ch1;
+		i2c34 = &i2c8mux0ch2;
+		i2c35 = &i2c8mux0ch3;
+		i2c36 = &i2c10mux0ch0;
+		i2c37 = &i2c10mux0ch1;
+		i2c38 = &i2c10mux0ch2;
+		i2c39 = &i2c10mux0ch3;
+		i2c40 = &i2c10mux0ch4;
+		i2c41 = &i2c10mux0ch5;
+		i2c42 = &i2c10mux0ch6;
+		i2c43 = &i2c10mux0ch7;
+		i2c44 = &i2c11mux0ch0;
+		i2c45 = &i2c11mux0ch1;
+		i2c46 = &i2c11mux0ch2;
+		i2c47 = &i2c11mux0ch3;
+		i2c48 = &i2c11mux0ch4;
+		i2c49 = &i2c11mux0ch5;
+		i2c50 = &i2c11mux0ch6;
+		i2c51 = &i2c11mux0ch7;
+		i2c52 = &i2c13mux0ch0;
+		i2c53 = &i2c13mux0ch1;
+		i2c54 = &i2c13mux0ch2;
+		i2c55 = &i2c13mux0ch3;
+		i2c56 = &i2c13mux0ch4;
+		i2c57 = &i2c13mux0ch5;
+		i2c58 = &i2c13mux0ch6;
+		i2c59 = &i2c13mux0ch7;
+	};
+
+	chosen {
+		stdout-path = "serial4:57600n8";
+	};
+
+	iio-hwmon {
+		compatible = "iio-hwmon";
+		io-channels = <&adc0 0>, <&adc0 1>, <&adc0 2>, <&adc0 3>,
+				  <&adc0 4>, <&adc0 5>, <&adc0 6>, <&adc0 7>,
+				  <&adc1 2>;
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		led-0 {
+			label = "bmc_heartbeat_amber";
+			gpios = <&gpio0 ASPEED_GPIO(P, 7) GPIO_ACTIVE_LOW>;
+			linux,default-trigger = "heartbeat";
+		};
+
+		led-1 {
+			label = "fp_id_amber";
+			default-state = "off";
+			gpios = <&gpio0 ASPEED_GPIO(B, 5) GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	memory at 80000000 {
+		device_type = "memory";
+		reg = <0x80000000 0x80000000>;
+	};
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		video_engine_memory: video {
+			size = <0x02c00000>;
+			alignment = <0x00100000>;
+			compatible = "shared-dma-pool";
+			reusable;
+		};
+
+		gfx_memory: framebuffer {
+			size = <0x01000000>;
+			alignment = <0x01000000>;
+			compatible = "shared-dma-pool";
+			reusable;
+		};
+	};
+
+	p3v3_bmc_aux: regulator-p3v3-bmc-aux {
+		compatible = "regulator-fixed";
+		regulator-name = "p3v3_bmc_aux";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	spi_gpio: spi {
+		compatible = "spi-gpio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		sck-gpios = <&gpio0 ASPEED_GPIO(Z, 3) GPIO_ACTIVE_HIGH>;
+		mosi-gpios = <&gpio0 ASPEED_GPIO(Z, 4) GPIO_ACTIVE_HIGH>;
+		miso-gpios = <&gpio0 ASPEED_GPIO(Z, 5) GPIO_ACTIVE_HIGH>;
+		cs-gpios = <&gpio0 ASPEED_GPIO(Z, 0) GPIO_ACTIVE_LOW>;
+		num-chipselects = <1>;
+		status = "okay";
+
+		tpm at 0 {
+			compatible = "infineon,slb9670", "tcg,tpm_tis-spi";
+			spi-max-frequency = <33000000>;
+			reg = <0>;
+		};
+	};
+};
+
+&adc0 {
+	aspeed,int-vref-microvolt = <2500000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_adc0_default &pinctrl_adc1_default
+		&pinctrl_adc2_default &pinctrl_adc3_default
+		&pinctrl_adc4_default &pinctrl_adc5_default
+		&pinctrl_adc6_default &pinctrl_adc7_default>;
+	status = "okay";
+};
+
+&adc1 {
+	aspeed,int-vref-microvolt = <2500000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_adc10_default>;
+	status = "okay";
+};
+
+&ehci1 {
+	status = "okay";
+};
+
+&fmc {
+	status = "okay";
+
+	flash at 0 {
+		status = "okay";
+		m25p,fast-read;
+		label = "bmc";
+		spi-max-frequency = <50000000>;
+#include "openbmc-flash-layout-128.dtsi"
+	};
+
+	flash at 1 {
+		status = "okay";
+		m25p,fast-read;
+		label = "alt-bmc";
+		spi-max-frequency = <50000000>;
+	};
+};
+
+&gfx {
+	status = "okay";
+	memory-region = <&gfx_memory>;
+};
+
+&gpio0 {
+	gpio-line-names =
+
+	/*A0-A7*/
+	"","","","","","","","",
+
+	/*B0-B7*/
+	"BATTERY_DETECT", "", "", "BMC_READY",
+	"", "FM_ID_LED", "", "",
+
+	/*C0-C7*/
+	"","","","","","","","",
+
+	/*D0-D7*/
+	"","","","","","","","",
+
+	/*E0-E7*/
+	"","","","","","","","",
+
+	/*F0-F7*/
+	"","","","","","","","",
+
+	/*G0-G7*/
+	"FM_MUX1_SEL", "", "", "",
+	"", "", "FM_DEBUG_PORT_PRSNT_N", "FM_BMC_DBP_PRESENT_N",
+
+	/*H0-H7*/
+	"","","","","","","","",
+
+	/*I0-I7*/
+	"", "", "", "",
+	"", "FLASH_WP_STATUS", "BMC_JTAG_MUX_SEL", "",
+
+	/*J0-J7*/
+	"","","","","","","","",
+
+	/*K0-K7*/
+	"","","","","","","","",
+
+	/*L0-L7*/
+	"","","","","","","","",
+
+	/*M0-M7*/
+	"", "BMC_FRU_WP", "", "",
+	"", "", "", "",
+
+	/*N0-N7*/
+	"LED_POSTCODE_0", "LED_POSTCODE_1", "LED_POSTCODE_2", "LED_POSTCODE_3",
+	"LED_POSTCODE_4", "LED_POSTCODE_5", "LED_POSTCODE_6", "LED_POSTCODE_7",
+
+	/*O0-O7*/
+	"","","","","","","","",
+
+	/*P0-P7*/
+	"PWR_BTN_BMC_BUF_N", "", "ID_RST_BTN_BMC_N", "",
+	"PWR_LED", "", "", "BMC_HEARTBEAT_N",
+
+	/*Q0-Q7*/
+	"","","","","","","","",
+
+	/*R0-R7*/
+	"","","","","","","","",
+
+	/*S0-S7*/
+	"", "", "SYS_BMC_PWRBTN_N", "",
+	"", "", "", "RUN_POWER_FAULT",
+
+	/*T0-T7*/
+	"","","","","","","","",
+
+	/*U0-U7*/
+	"","","","","","","","",
+
+	/*V0-V7*/
+	"","","","","","","","",
+
+	/*W0-W7*/
+	"","","","","","","","",
+
+	/*X0-X7*/
+	"","","","","","","","",
+
+	/*Y0-Y7*/
+	"","","","","","","","",
+
+	/*Z0-Z7*/
+	"SPI_BMC_TPM_CS2_N", "", "", "SPI_BMC_TPM_CLK",
+	"SPI_BMC_TPM_MOSI", "SPI_BMC_TPM_MISO", "", "";
+};
+
+&gpio1 {
+	gpio-line-names =
+	/*18A0-18A7*/
+	"","","","","","","","",
+
+	/*18B0-18B7*/
+	"","","","",
+	"FM_BOARD_BMC_REV_ID0", "FM_BOARD_BMC_REV_ID1",
+	"FM_BOARD_BMC_REV_ID2", "",
+
+	/*18C0-18C7*/
+	"","","","","","","","",
+
+	/*18D0-18D7*/
+	"","","","","","","","",
+
+	/*18E0-18E3*/
+	"FM_BMC_PROT_LS_EN", "AC_PWR_BMC_BTN_N", "", "";
+};
+
+// L Bridge Board
+&i2c0 {
+	status = "okay";
+
+	i2c-mux at 70 {
+		compatible = "nxp,pca9546";
+		reg = <0x70>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		i2c0mux0ch0: i2c at 0 {
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c0mux0ch1: i2c at 1 {
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c0mux0ch2: i2c at 2 {
+			reg = <2>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c0mux0ch3: i2c at 3 {
+			reg = <3>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+};
+
+// R Bridge Board
+&i2c1 {
+	status = "okay";
+
+	i2c-mux at 70 {
+		compatible = "nxp,pca9546";
+		reg = <0x70>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		i2c1mux0ch0: i2c at 0 {
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c1mux0ch1: i2c at 1 {
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c1mux0ch2: i2c at 2 {
+			reg = <2>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c1mux0ch3: i2c at 3 {
+			reg = <3>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+};
+
+// MB - E1.S
+&i2c4 {
+	status = "okay";
+
+	i2c-mux at 70 {
+		compatible = "nxp,pca9548";
+		reg = <0x70>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		i2c4mux0ch0: i2c at 0 {
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c4mux0ch1: i2c at 1 {
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c4mux0ch2: i2c at 2 {
+			reg = <2>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c4mux0ch3: i2c at 3 {
+			reg = <3>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c4mux0ch4: i2c at 4 {
+			reg = <4>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c4mux0ch5: i2c at 5 {
+			reg = <5>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c4mux0ch6: i2c at 6 {
+			reg = <6>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c4mux0ch7: i2c at 7 {
+			reg = <7>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+};
+
+// AMC
+&i2c5 {
+	status = "okay";
+};
+
+// MB
+&i2c6 {
+	status = "okay";
+
+	// HPM FRU
+	eeprom at 50 {
+		compatible = "atmel,24c256";
+		reg = <0x50>;
+	};
+};
+
+// SCM
+&i2c7 {
+	status = "okay";
+
+
+};
+
+// MB - PDB
+&i2c8 {
+	status = "okay";
+
+	i2c-mux at 72 {
+		compatible = "nxp,pca9546";
+		reg = <0x72>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		i2c8mux0ch0: i2c at 0 {
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			adc at 1f {
+				compatible = "ti,adc128d818";
+				reg = <0x1f>;
+				ti,mode = /bits/ 8 <1>;
+			};
+
+			gpio at 22 {
+				compatible = "nxp,pca9555";
+				reg = <0x22>;
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				gpio-line-names =
+					"RPDB_FAN_FULL_SPEED_R_N", "RPDB_I2C_TEMP75_U8_ALERT_R_N",
+					"RPDB_I2C_TMP432_U29_ALERT_R_N", "RPDB_GLOBAL_WP",
+					"RPDB_FAN_CT_FAN_FAIL_R_N", "",
+					"", "",
+					"RPDB_ALERT_P50V_HSC2_R_N", "RPDB_ALERT_P50V_HSC3_R_N",
+					"RPDB_ALERT_P50V_HSC4_R_N", "RPDB_ALERT_P50V_STBY_R_N",
+					"RPDB_I2C_P12V_MB_VRM_ALERT_R_N",
+					"RPDB_I2C_P12V_STBY_VRM_ALERT_R_N",
+					"RPDB_PGD_P3V3_STBY_PWRGD_R",
+					"RPDB_P12V_STBY_VRM_PWRGD_BUF_R";
+			};
+
+			gpio at 24 {
+				compatible = "nxp,pca9555";
+				reg = <0x24>;
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				gpio-line-names =
+					"RPDB_EAM2_PRSNT_MOS_N_R", "RPDB_EAM3_PRSNT_MOS_N_R",
+					"RPDB_PWRGD_P50V_HSC4_SYS_R",
+					"RPDB_PWRGD_P50V_STBY_SYS_BUF_R",
+					"RPDB_P50V_FAN1_R2_PG", "RPDB_P50V_FAN2_R2_PG",
+					"RPDB_P50V_FAN3_R2_PG", "RPDB_P50V_FAN4_R2_PG",
+					"", "RPDB_FAN1_PRSNT_N_R",
+					"", "RPDB_FAN2_PRSNT_N_R",
+					"RPDB_FAN3_PRSNT_N_R", "RPDB_FAN4_PRSNT_N_R",
+					"", "";
+			};
+
+			// R-PDB FRU
+			eeprom at 50 {
+				compatible = "atmel,24c128";
+				reg = <0x50>;
+			};
+		};
+		i2c8mux0ch1: i2c at 1 {
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			gpio at 22 {
+				compatible = "nxp,pca9555";
+				reg = <0x22>;
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				gpio-line-names =
+					"LPDB_FAN_FULL_SPEED_R_N","LPDB_I2C_TEMP75_U8_ALERT_R_N",
+					"LPDB_I2C_TMP432_U29_ALERT_R_N","LPDB_GLOBAL_WP",
+					"LPDB_FAN_CT_FAN_FAIL_R_N","",
+					"","",
+					"LPDB_ALERT_P50V_HSC0_R_N","LPDB_ALERT_P50V_HSC1_R_N",
+					"LPDB_ALERT_P50V_HSC5_R_N","LPDB_I2C_P12V_SW_VRM_ALERT_R_N",
+					"LPDB_EAM0_PRSNT_MOS_N_R","LPDB_EAM1_PRSNT_MOS_N_R",
+					"LPDB_PWRGD_P50V_HSC5_SYS_R","";
+			};
+
+			gpio at 24 {
+				compatible = "nxp,pca9555";
+				reg = <0x24>;
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				gpio-line-names =
+					"LPDB_P50V_FAN1_R2_PG","LPDB_P50V_FAN2_R2_PG",
+					"LPDB_P50V_FAN3_R2_PG","LPDB_P50V_FAN4_R2_PG",
+					"LPDB_P50V_FAN5_R2_PG","LPDB_FAN1_PRSNT_N_R",
+					"LPDB_FAN2_PRSNT_N_R","LPDB_FAN3_PRSNT_N_R",
+					"LPDB_FAN4_PRSNT_N_R","LPDB_FAN5_PRSNT_N_R",
+					"","",
+					"","",
+					"","";
+			};
+
+			// L-PDB FRU
+			eeprom at 50 {
+				compatible = "atmel,24c128";
+				reg = <0x50>;
+			};
+		};
+		i2c8mux0ch2: i2c at 2 {
+			reg = <2>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c8mux0ch3: i2c at 3 {
+			reg = <3>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+};
+
+// SCM
+&i2c9 {
+	status = "okay";
+
+	// SCM FRU
+	eeprom at 50 {
+		compatible = "atmel,24c128";
+		reg = <0x50>;
+	};
+
+	// BSM FRU
+	eeprom at 56 {
+		compatible = "atmel,24c64";
+		reg = <0x56>;
+	};
+};
+
+// R Bridge Board
+&i2c10 {
+	status = "okay";
+
+	i2c-mux at 71 {
+		compatible = "nxp,pca9548";
+		reg = <0x71>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		i2c10mux0ch0: i2c at 0 {
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c10mux0ch1: i2c at 1 {
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c10mux0ch2: i2c at 2 {
+			reg = <2>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c10mux0ch3: i2c at 3 {
+			reg = <3>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c10mux0ch4: i2c at 4 {
+			reg = <4>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c10mux0ch5: i2c at 5 {
+			reg = <5>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			gpio at 22 {
+				compatible = "nxp,pca9555";
+				reg = <0x22>;
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				gpio-line-names =
+					"","",
+					"","RBB_CPLD_REFRESH_IN_PRGRS_R_L",
+					"RBB_EAM0_NIC_CBL_PRSNT_R_L","RBB_EAM1_NIC_CBL_PRSNT_R_L",
+					"RBB_AINIC_JTAG_MUX_R2_SEL","RBB_SPI_MUX0_R2_SEL",
+					"RBB_AINIC_PRSNT_R_L","RBB_AINIC_OE_R_N",
+					"RBB_AINIC_BOARD_R2_ID","RBB_RST_USB2_HUB_R_N",
+					"RBB_RST_FT4222_R_N","RBB_RST_MCP2210_R_N",
+					"","";
+			};
+
+			// R Bridge Board FRU
+			eeprom at 52 {
+				compatible = "atmel,24c256";
+				reg = <0x52>;
+			};
+		};
+		i2c10mux0ch6: i2c at 6 {
+			reg = <6>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c10mux0ch7: i2c at 7 {
+			reg = <7>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+};
+
+// L Bridge Board
+&i2c11 {
+	status = "okay";
+
+	i2c-mux at 71 {
+		compatible = "nxp,pca9548";
+		reg = <0x71>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		i2c11mux0ch0: i2c at 0 {
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c11mux0ch1: i2c at 1 {
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c11mux0ch2: i2c at 2 {
+			reg = <2>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c11mux0ch3: i2c at 3 {
+			reg = <3>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c11mux0ch4: i2c at 4 {
+			reg = <4>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c11mux0ch5: i2c at 5 {
+			reg = <5>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			gpio at 22 {
+				compatible = "nxp,pca9555";
+				reg = <0x22>;
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				gpio-line-names =
+					"","",
+					"","LBB_CPLD_REFRESH_IN_PRGRS_R_L",
+					"LBB_EAM0_NIC_CBL_PRSNT_R_L","LBB_EAM1_NIC_CBL_PRSNT_R_L",
+					"LBB_AINIC_JTAG_MUX_R2_SEL","LBB_SPI_MUX0_R2_SEL",
+					"LBB_AINIC_PRSNT_R_L","LBB_AINIC_OE_R_N",
+					"LBB_AINIC_BOARD_R2_ID","LBB_RST_USB2_HUB_R_N",
+					"LBB_RST_FT4222_R_N","LBB_RST_MCP2210_R_N",
+					"","";
+			};
+
+			// L Bridge Board FRU
+			eeprom at 52 {
+				compatible = "atmel,24c256";
+				reg = <0x52>;
+			};
+		};
+		i2c11mux0ch6: i2c at 6 {
+			reg = <6>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c11mux0ch7: i2c at 7 {
+			reg = <7>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+};
+
+// Debug Card
+&i2c12 {
+	status = "okay";
+};
+
+// MB
+&i2c13 {
+	status = "okay";
+
+	i2c-mux at 70 {
+		compatible = "nxp,pca9548";
+		reg = <0x70>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		i2c13mux0ch0: i2c at 0 {
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c13mux0ch1: i2c at 1 {
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c13mux0ch2: i2c at 2 {
+			reg = <2>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c13mux0ch3: i2c at 3 {
+			reg = <3>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			adc at 1f {
+				compatible = "ti,adc128d818";
+				reg = <0x1f>;
+				ti,mode = /bits/ 8 <1>;
+			};
+		};
+		i2c13mux0ch4: i2c at 4 {
+			reg = <4>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			// HPM BRD ID FRU
+			eeprom at 51 {
+				compatible = "atmel,24c256";
+				reg = <0x51>;
+			};
+		};
+		i2c13mux0ch5: i2c at 5 {
+			reg = <5>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c13mux0ch6: i2c at 6 {
+			reg = <6>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		i2c13mux0ch7: i2c at 7 {
+			reg = <7>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+};
+
+// SCM
+&i2c14 {
+	status = "okay";
+};
+
+&i2c15 {
+	status = "okay";
+};
+
+&kcs2 {
+	aspeed,lpc-io-reg = <0xca8>;
+	status = "okay";
+};
+
+&kcs3 {
+	aspeed,lpc-io-reg = <0xca2>;
+	status = "okay";
+};
+
+&lpc_ctrl {
+	status = "okay";
+};
+
+&mac2 {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ncsi3_default>;
+	use-ncsi;
+};
+
+&sgpiom0 {
+	ngpios = <128>;
+	bus-frequency = <2000000>;
+	gpio-line-names =
+	/*in - out - in - out */
+	/* A0-A7 line 0-15 */
+	"", "FM_CPU0_SYS_RESET_N", "", "CPU0_KBRST_N",
+	"", "FM_CPU0_PROCHOT_trigger_N", "", "FM_CLR_CMOS_R_P0",
+	"", "Force_I3C_SEL", "", "SYSTEM_Force_Run_AC_Cycle",
+	"", "", "", "",
+
+	/* B0-B7 line 16-31 */
+	"Channel0_leakage_EAM3", "FM_CPU_FPGA_JTAG_MUX_SEL",
+	"Channel1_leakage_EAM0", "FM_SCM_JTAG_MUX_SEL",
+	"Channel2_leakage_Manifold1", "FM_BRIDGE_JTAG_MUX_SEL",
+	"Channel3_leakage", "FM_CPU0_NMI_SYNC_FLOOD_N",
+	"Channel4_leakage_Manifold2", "",
+	"Channel5_leakage_EAM1", "",
+	"Channel6_leakage_CPU_DIMM", "",
+	"Channel7_leakage_EAM2", "",
+
+	/* C0-C7 line 32-47 */
+	"RSVD_RMC_GPIO3", "", "", "",
+	"", "", "", "",
+	"LEAK_DETECT_RMC_N", "", "", "",
+	"", "", "", "",
+
+	/* D0-D7 line 48-63 */
+	"PWRGD_PDB_EAMHSC0_CPLD_PG_R", "",
+	"PWRGD_PDB_EAMHSC1_CPLD_PG_R", "",
+	"PWRGD_PDB_EAMHSC2_CPLD_PG_R", "",
+	"PWRGD_PDB_EAMHSC3_CPLD_PG_R", "",
+	"AMC_BRD_PRSNT_CPLD_L", "", "", "",
+	"", "", "", "",
+
+	/* E0-E7 line 64-79 */
+	"AMC_PDB_EAMHSC0_CPLD_EN_R", "",
+	"AMC_PDB_EAMHSC1_CPLD_EN_R", "",
+	"AMC_PDB_EAMHSC2_CPLD_EN_R", "",
+	"AMC_PDB_EAMHSC3_CPLD_EN_R", "",
+	"", "", "", "",
+	"", "", "", "",
+
+	/* F0-F7 line 80-95 */
+	"PWRGD_PVDDCR_CPU1_P0", "SGPIO_READY",
+	"PWRGD_PVDDCR_CPU0_P0", "",
+	"", "", "", "",
+	"", "", "", "",
+
+	/* G0-G7 line 96-111 */
+	"PWRGD_PVDDCR_SOC_P0", "",
+	"PWRGD_PVDDIO_P0", "",
+	"PWRGD_PVDDIO_MEM_S3_P0", "",
+	"PWRGD_CHMP_CPU0_FPGA", "",
+	"PWRGD_CHIL_CPU0_FPGA", "",
+	"PWRGD_CHEH_CPU0_FPGA", "",
+	"PWRGD_CHAD_CPU0_FPGA", "FM_BMC_READY_PLD",
+	"", "",
+
+	/* H0-H7 line 112-127 */
+	"PWRGD_P3V3", "",
+	"P12V_DDR_IP_PWRGD_R", "",
+	"P12V_DDR_AH_PWRGD_R", "",
+	"PWRGD_P12V_VRM1_CPLD_PG_R", "",
+	"PWRGD_P12V_VRM0_CPLD_PG_R", "",
+	"PWRGD_PDB_HSC4_CPLD_PG_R", "",
+	"PWRGD_PVDD18_S5_P0_PG", "",
+	"PWRGD_PVDD33_S5_P0_PG", "",
+
+	/* I0-I7 line 128-143 */
+	"EAM0_BRD_PRSNT_R_L", "",
+	"EAM1_BRD_PRSNT_R_L", "",
+	"EAM2_BRD_PRSNT_R_L", "",
+	"EAM3_BRD_PRSNT_R_L", "",
+	"EAM0_CPU_MOD_PWR_GD_R", "",
+	"EAM1_CPU_MOD_PWR_GD_R", "",
+	"EAM2_CPU_MOD_PWR_GD_R", "",
+	"EAM3_CPU_MOD_PWR_GD_R", "",
+
+	/* J0-J7 line 144-159 */
+	"PRSNT_L_BIRDGE_R", "",
+	"PRSNT_R_BIRDGE_R", "",
+	"BRIDGE_L_MAIN_PG_R", "",
+	"BRIDGE_R_MAIN_PG_R", "",
+	"BRIDGE_L_STBY_PG_R", "",
+	"BRIDGE_R_STBY_PG_R", "",
+	"", "", "", "",
+
+	/* K0-K7 line 160-175 */
+	"ADC_I2C_ALERT_N", "",
+	"TEMP_I2C_ALERT_R_L", "",
+	"CPU0_VR_SMB_ALERT_CPLD_N", "",
+	"COVER_INTRUDER_R_N", "",
+	"HANDLE_INTRUDER_CPLD_N", "",
+	"IRQ_MCIO_CPLD_WAKE_R_N", "",
+	"APML_CPU0_ALERT_R_N", "",
+	"PDB_ALERT_R_N", "",
+
+	/* L0-L7 line 176-191 */
+	"CPU0_SP7R1", "", "CPU0_SP7R2", "",
+	"CPU0_SP7R3", "", "CPU0_SP7R4", "",
+	"CPU0_CORETYPE0", "", "CPU0_CORETYPE1", "",
+	"CPU0_CORETYPE2", "", "FM_BIOS_POST_CMPLT_R_N", "",
+
+	/* M0-M7 line 192-207 */
+	"EAM0_SMERR_CPLD_R_L", "",
+	"EAM1_SMERR_CPLD_R_L", "",
+	"EAM2_SMERR_CPLD_R_L", "",
+	"EAM3_SMERR_CPLD_R_L", "",
+	"CPU0_SMERR_N_R", "",
+	"CPU0_NV_SAVE_N_R", "",
+	"PDB_PWR_LOSS_CPLD_N", "",
+	"IRQ_BMC_SMI_ACTIVE_R_N", "",
+
+	/* N0-N7 line 208-223 */
+	"AMCROT_BMC_S5_RDY_R", "",
+	"AMC_RDY_R", "",
+	"AMC_STBY_PGOOD_R", "",
+	"CPU_AMC_SLP_S5_R_L", "",
+	"AMC_CPU_EAMPG_R", "",
+	"", "", "", "",
+
+	/* O0-O7 line 224-239 */
+	"HPM_PWR_FAIL", "Port80_b0",
+	"FM_DIMM_IP_FAIL", "Port80_b1",
+	"FM_DIMM_AH_FAIL", "Port80_b2",
+	"HPM_AMC_THERMTRIP_R_L", "Port80_b3",
+	"FM_CPU0_THERMTRIP_N", "Port80_b4",
+	"PVDDCR_SOC_P0_OCP_L", "Port80_b5",
+	"CPLD_SGPIO_RDY", "Port80_b6",
+	"", "Port80_b7",
+
+	/* P0-P7 line 240-255 */
+	"CPU0_SLP_S5_N_R", "NFC_VEN",
+	"CPU0_SLP_S3_N_R", "",
+	"FM_CPU0_PWRGD", "",
+	"PWRGD_RMC", "",
+	"FM_RST_CPU0_RESET_N", "",
+	"FM_PWRGD_CPU0_PWROK", "",
+	"wS5_PWR_Ready", "",
+	"wS0_ON_N", "PWRGD_P1V0_AUX";
+	status = "okay";
+};
+
+// BIOS Flash
+&spi2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_spi2_default>;
+	status = "okay";
+	reg = <0x1e631000 0xc4>, <0x50000000 0x8000000>;
+
+	flash at 0 {
+		compatible = "jedec,spi-nor";
+		label = "pnor";
+		spi-max-frequency = <12000000>;
+		spi-tx-bus-width = <2>;
+		spi-rx-bus-width = <2>;
+		status = "okay";
+	};
+};
+
+// HOST BIOS Debug
+&uart1 {
+	status = "okay";
+};
+
+&uart3 {
+	status = "okay";
+};
+
+&uart4 {
+	status = "okay";
+};
+
+// BMC Debug Console
+&uart5 {
+	status = "okay";
+};
+
+&uart_routing {
+	status = "okay";
+};
+
+&uhci {
+	status = "okay";
+};
+
+&vhub {
+	status = "okay";
+	pinctrl-names = "default";
+};
+
+&video {
+	status = "okay";
+	memory-region = <&video_engine_memory>;
+};
+
+&wdt1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_wdtrst1_default>;
+	aspeed,reset-type = "soc";
+	aspeed,external-signal;
+	aspeed,ext-push-pull;
+	aspeed,ext-active-high;
+	aspeed,ext-pulse-duration = <256>;
+	status = "okay";
+};
-- 
2.34.1



From zaneta.kedzierska at fontri.pl  Fri Dec 19 01:15:36 2025
From: zaneta.kedzierska at fontri.pl (=?UTF-8?Q? =C5=BBaneta_K=C4=99dzierska ?=)
Date: Fri, 19 Dec 2025 09:15:36 GMT
Subject: =?UTF-8?Q?Odbi=C3=B3r_w_paczkomacie_?=
Message-ID: <20251219084500-0.1.t3.6e9qq.0.6npl71zkkd@fontri.pl>

Dzie? dobry,

jako lider w us?ugach kurierskich w Polsce przygotowali?my elastyczne rozwi?zanie dla przedsi?biorc?w.

Stworzyli?my abonament ??cz?cy dostawy do Paczkomat 24/7 oraz obs?ug? kuriersk? - jeden dostawca, jedna faktura i przewidywalne, sta?e koszty. 

Czy mog? przedstawi?, co mo?emy zaproponowa? wzgl?dem Pa?stwa potrzeb?


Pozdrawiam
?aneta K?dzierska


From pabeni at redhat.com  Fri Dec 19 01:17:52 2025
From: pabeni at redhat.com (Paolo Abeni)
Date: Fri, 19 Dec 2025 10:17:52 +0100
Subject: [PATCH net-next v2 1/2] net: stmmac: dwmac-rk: rename
 phy_power_on to avoid conflict
In-Reply-To: <20251216150611.3616-1-sensor1010@163.com>
References: <20251216150611.3616-1-sensor1010@163.com>
Message-ID: <3c72a0d9-88e2-422a-9f9b-900ca7867091@redhat.com>

On 12/16/25 4:06 PM, Lizhe wrote:
> Rename local function 'phy_power_on' to 'rk_phy_power_set' to avoid
> conflict with PHY subsystem function. Keep original error handling.
> 
> Signed-off-by: Lizhe <sensor1010 at 163.com>

## Form letter - net-next-closed

The net-next tree is closed for new drivers, features, code refactoring
and optimizations due to the merge window and the winter break. We are
currently accepting bug fixes only.

Please repost when net-next reopens after Jan 2nd.

RFC patches sent for review only are obviously welcome at any time.




From jie.gan at oss.qualcomm.com  Fri Dec 19 01:24:15 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Fri, 19 Dec 2025 17:24:15 +0800
Subject: [PATCH v8 2/8] coresight: core: add a new API to retrieve the
 helper device
In-Reply-To: <dd043b78-d60c-4a79-85a8-9f352a4d89e1@arm.com>
References: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
 <20251211-enable-byte-cntr-for-ctcu-v8-2-3e12ff313191@oss.qualcomm.com>
 <dd043b78-d60c-4a79-85a8-9f352a4d89e1@arm.com>
Message-ID: <ac1dcd53-87f9-4b6e-ac95-dfe5fc972a89@oss.qualcomm.com>



On 12/19/2025 1:50 AM, Suzuki K Poulose wrote:
> On 11/12/2025 06:10, Jie Gan wrote:
>> Retrieving the helper device of the specific coresight device based on
>> its helper_subtype because a single coresight device may has multiple 
>> types
>> of the helper devices.
>>
>> Reviewed-by: Mike Leach <mike.leach at linaro.org>
>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> ---
>> ? drivers/hwtracing/coresight/coresight-core.c | 35 ++++++++++++++++++ 
>> ++++++++++
>> ? drivers/hwtracing/coresight/coresight-priv.h |? 2 ++
>> ? 2 files changed, 37 insertions(+)
>>
>> diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/ 
>> hwtracing/coresight/coresight-core.c
>> index 0e8448784c62..667883ccb4b7 100644
>> --- a/drivers/hwtracing/coresight/coresight-core.c
>> +++ b/drivers/hwtracing/coresight/coresight-core.c
>> @@ -585,6 +585,41 @@ struct coresight_device 
>> *coresight_get_sink(struct coresight_path *path)
>> ? }
>> ? EXPORT_SYMBOL_GPL(coresight_get_sink);
>> +/**
>> + * coresight_get_helper: find the helper device of the assigned csdev.
>> + *
>> + * @csdev: The csdev the helper device is conntected to.
>> + * @type:? helper_subtype of the expected helper device.
>> + *
>> + * Retrieve the helper device for the specific csdev based on its
>> + * helper_subtype.
>> + *
>> + * Return: the helper's csdev upon success or NULL for fail.
>> + */
>> +struct coresight_device *coresight_get_helper(struct coresight_device 
>> *csdev,
>> +????????????????????????? enum coresight_dev_subtype_helper subtype)
> 
> We have almost a similar function in coresight-core.c :
> 
> coresight_find_output_type(pdata, type, subtype).
> 
> Please could we reuse that, instead of adding similar funcitons ?
> 
> Please be careful about the mutex.
> 

Thanks for the suggestion. I reviewed coresight_find_output_type, and I 
believe we can reuse it to retrieve the CTCU device.

Thanks,
Jie

> Suzuki
> 
>> +{
>> +??? int i;
>> +??? struct coresight_device *helper;
>> +
>> +??? /* protect the connections */
>> +??? mutex_lock(&coresight_mutex);
>> +??? for (i = 0; i < csdev->pdata->nr_outconns; ++i) {
>> +??????? helper = csdev->pdata->out_conns[i]->dest_dev;
>> +??????? if (!helper || !coresight_is_helper(helper))
>> +??????????? continue;
>> +
>> +??????? if (helper->subtype.helper_subtype == subtype) {
>> +??????????? mutex_unlock(&coresight_mutex);
>> +??????????? return helper;
>> +??????? }
>> +??? }
>> +??? mutex_unlock(&coresight_mutex);
>> +
>> +??? return NULL;
>> +}
>> +EXPORT_SYMBOL_GPL(coresight_get_helper);
>> +
>> ? /**
>> ?? * coresight_get_in_port: Find the input port number at @csdev where 
>> a @remote
>> ?? * device is connected to.
>> diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/ 
>> hwtracing/coresight/coresight-priv.h
>> index cbf80b83e5ce..8e39a4dc7256 100644
>> --- a/drivers/hwtracing/coresight/coresight-priv.h
>> +++ b/drivers/hwtracing/coresight/coresight-priv.h
>> @@ -157,6 +157,8 @@ void coresight_path_assign_trace_id(struct 
>> coresight_path *path,
>> ???????????????????? enum cs_mode mode);
>> ? int coresight_get_in_port(struct coresight_device *csdev,
>> ??????????????? struct coresight_device *remote);
>> +struct coresight_device *coresight_get_helper(struct coresight_device 
>> *csdev,
>> +????????????????????????? enum coresight_dev_subtype_helper subtype);
>> ? #if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM3X)
>> ? int etm_readl_cp14(u32 off, unsigned int *val);
>>
> 



From u.kleine-koenig at baylibre.com  Fri Dec 19 01:25:30 2025
From: u.kleine-koenig at baylibre.com (=?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?=)
Date: Fri, 19 Dec 2025 10:25:30 +0100
Subject: [PATCH v2 1/8] scsi: Pass a struct scsi_driver to scsi_{,un}register_driver()
In-Reply-To: <cover.1766133330.git.u.kleine-koenig@baylibre.com>
References: <cover.1766133330.git.u.kleine-koenig@baylibre.com>
Message-ID: <ac17fdea58e384cb514c639306d48ce0005820b0.1766133330.git.u.kleine-koenig@baylibre.com>

This aligns with what other subsystems do, reduces boilerplate a bit for
device drivers and is less error prone.

Reviewed-by: Peter Wang <peter.wang at mediatek.com>
Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig at baylibre.com>
---
 drivers/scsi/ch.c          | 4 ++--
 drivers/scsi/scsi_sysfs.c  | 4 +++-
 drivers/scsi/sd.c          | 4 ++--
 drivers/scsi/ses.c         | 4 ++--
 drivers/scsi/sr.c          | 4 ++--
 drivers/scsi/st.c          | 4 ++--
 drivers/ufs/core/ufshcd.c  | 4 ++--
 include/scsi/scsi_driver.h | 4 ++--
 8 files changed, 17 insertions(+), 15 deletions(-)

diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
index fa07a6f54003..f2b63e4b9b99 100644
--- a/drivers/scsi/ch.c
+++ b/drivers/scsi/ch.c
@@ -1014,7 +1014,7 @@ static int __init init_ch_module(void)
 		       SCSI_CHANGER_MAJOR);
 		goto fail1;
 	}
-	rc = scsi_register_driver(&ch_template.gendrv);
+	rc = scsi_register_driver(&ch_template);
 	if (rc < 0)
 		goto fail2;
 	return 0;
@@ -1028,7 +1028,7 @@ static int __init init_ch_module(void)
 
 static void __exit exit_ch_module(void)
 {
-	scsi_unregister_driver(&ch_template.gendrv);
+	scsi_unregister_driver(&ch_template);
 	unregister_chrdev(SCSI_CHANGER_MAJOR, "ch");
 	class_unregister(&ch_sysfs_class);
 	idr_destroy(&ch_index_idr);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 99eb0a30df61..db0ba68f2e6e 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -1554,8 +1554,10 @@ void scsi_remove_target(struct device *dev)
 }
 EXPORT_SYMBOL(scsi_remove_target);
 
-int __scsi_register_driver(struct device_driver *drv, struct module *owner)
+int __scsi_register_driver(struct scsi_driver *sdrv, struct module *owner)
 {
+	struct device_driver *drv = &sdrv->gendrv;
+
 	drv->bus = &scsi_bus_type;
 	drv->owner = owner;
 
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index f50b92e63201..6ea6ee2830a4 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -4417,7 +4417,7 @@ static int __init init_sd(void)
 		goto err_out_class;
 	}
 
-	err = scsi_register_driver(&sd_template.gendrv);
+	err = scsi_register_driver(&sd_template);
 	if (err)
 		goto err_out_driver;
 
@@ -4444,7 +4444,7 @@ static void __exit exit_sd(void)
 
 	SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n"));
 
-	scsi_unregister_driver(&sd_template.gendrv);
+	scsi_unregister_driver(&sd_template);
 	mempool_destroy(sd_page_pool);
 
 	class_unregister(&sd_disk_class);
diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c
index 2c61624cb4b0..f8f5164f3de2 100644
--- a/drivers/scsi/ses.c
+++ b/drivers/scsi/ses.c
@@ -921,7 +921,7 @@ static int __init ses_init(void)
 	if (err)
 		return err;
 
-	err = scsi_register_driver(&ses_template.gendrv);
+	err = scsi_register_driver(&ses_template);
 	if (err)
 		goto out_unreg;
 
@@ -934,7 +934,7 @@ static int __init ses_init(void)
 
 static void __exit ses_exit(void)
 {
-	scsi_unregister_driver(&ses_template.gendrv);
+	scsi_unregister_driver(&ses_template);
 	scsi_unregister_interface(&ses_interface);
 }
 
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index add13e306898..2f6bb6355186 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -1001,7 +1001,7 @@ static int __init init_sr(void)
 	rc = register_blkdev(SCSI_CDROM_MAJOR, "sr");
 	if (rc)
 		return rc;
-	rc = scsi_register_driver(&sr_template.gendrv);
+	rc = scsi_register_driver(&sr_template);
 	if (rc)
 		unregister_blkdev(SCSI_CDROM_MAJOR, "sr");
 
@@ -1010,7 +1010,7 @@ static int __init init_sr(void)
 
 static void __exit exit_sr(void)
 {
-	scsi_unregister_driver(&sr_template.gendrv);
+	scsi_unregister_driver(&sr_template);
 	unregister_blkdev(SCSI_CDROM_MAJOR, "sr");
 }
 
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 168f25e4aaa3..45622cfce926 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -4576,7 +4576,7 @@ static int __init init_st(void)
 		goto err_class;
 	}
 
-	err = scsi_register_driver(&st_template.gendrv);
+	err = scsi_register_driver(&st_template);
 	if (err)
 		goto err_chrdev;
 
@@ -4592,7 +4592,7 @@ static int __init init_st(void)
 
 static void __exit exit_st(void)
 {
-	scsi_unregister_driver(&st_template.gendrv);
+	scsi_unregister_driver(&st_template);
 	unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
 				 ST_MAX_TAPE_ENTRIES);
 	class_unregister(&st_sysfs_class);
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 80c0b49f30b0..da1e89e95d07 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -11240,7 +11240,7 @@ static int __init ufshcd_core_init(void)
 
 	ufs_debugfs_init();
 
-	ret = scsi_register_driver(&ufs_dev_wlun_template.gendrv);
+	ret = scsi_register_driver(&ufs_dev_wlun_template);
 	if (ret)
 		ufs_debugfs_exit();
 	return ret;
@@ -11249,7 +11249,7 @@ static int __init ufshcd_core_init(void)
 static void __exit ufshcd_core_exit(void)
 {
 	ufs_debugfs_exit();
-	scsi_unregister_driver(&ufs_dev_wlun_template.gendrv);
+	scsi_unregister_driver(&ufs_dev_wlun_template);
 }
 
 module_init(ufshcd_core_init);
diff --git a/include/scsi/scsi_driver.h b/include/scsi/scsi_driver.h
index c0e89996bdb3..40aba9a9349a 100644
--- a/include/scsi/scsi_driver.h
+++ b/include/scsi/scsi_driver.h
@@ -25,9 +25,9 @@ struct scsi_driver {
 
 #define scsi_register_driver(drv) \
 	__scsi_register_driver(drv, THIS_MODULE)
-int __scsi_register_driver(struct device_driver *, struct module *);
+int __scsi_register_driver(struct scsi_driver *, struct module *);
 #define scsi_unregister_driver(drv) \
-	driver_unregister(drv);
+	driver_unregister(&(drv)->gendrv);
 
 extern int scsi_register_interface(struct class_interface *);
 #define scsi_unregister_interface(intf) \
-- 
2.47.3



From u.kleine-koenig at baylibre.com  Fri Dec 19 01:25:29 2025
From: u.kleine-koenig at baylibre.com (=?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?=)
Date: Fri, 19 Dec 2025 10:25:29 +0100
Subject: [PATCH v2 0/8] scsi: Make use of bus callbacks
Message-ID: <cover.1766133330.git.u.kleine-koenig@baylibre.com>

Hello,

this is v2 of the series to make the scsi subsystem stop using the
callbacks .probe(), .remove() and .shutdown() of struct device_driver.
Instead use their designated alternatives in struct bus_type.

The eventual goal is to drop the callbacks from struct device_driver.

The 2nd patch introduces some legacy handling for drivers still using
the device_driver callbacks. This results in a runtime warning (in
driver_register()). The following patches convert all in-tree drivers
(and thus fix the warnings one after another).
Conceptually this legacy handling could be dropped at the end of the
series, but I think this is a bad idea because this silently breaks
out-of-tree drivers (which also covers drivers that are currently
prepared for mainline submission) and in-tree drivers I might have
missed (though I'm convinced I catched them all). That convinces me that
keeping the legacy handling for at least one development cycle is the
right choice. I'll care for that at the latest when I remove the
callbacks from struct device_driver.

Changes since (implicit) v1, available at
https://lore.kernel.org/linux-scsi/cover.1765312062.git.u.kleine-koenig at baylibre.com:

 - trivially rebase to v6.19-rc1
 - fix a kdoc warning uncovered by the intel kernel test robot
 - rename a few variables to align with the already existing naming in
   the individual drivers
 - slightly reword the commit logs
 - add the tags received in v1

Best regards
Uwe

Uwe Kleine-K?nig (8):
  scsi: Pass a struct scsi_driver to scsi_{,un}register_driver()
  scsi: Make use of bus callbacks
  scsi: ch: Convert to scsi bus methods
  scsi: sd: Convert to scsi bus methods
  scsi: ses: Convert to scsi bus methods
  scsi: sr: Convert to scsi bus methods
  scsi: st: Convert to scsi bus methods
  scsi: ufs: Convert to scsi bus methods

 drivers/scsi/ch.c          | 18 ++++-----
 drivers/scsi/scsi_sysfs.c  | 77 ++++++++++++++++++++++++++++++++++++--
 drivers/scsi/sd.c          | 29 +++++++-------
 drivers/scsi/ses.c         | 15 ++------
 drivers/scsi/sr.c          | 21 +++++------
 drivers/scsi/st.c          | 22 +++++------
 drivers/ufs/core/ufshcd.c  | 22 +++++------
 include/scsi/scsi_driver.h |  7 +++-
 8 files changed, 139 insertions(+), 72 deletions(-)


base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
-- 
2.47.3



From u.kleine-koenig at baylibre.com  Fri Dec 19 01:25:31 2025
From: u.kleine-koenig at baylibre.com (=?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?=)
Date: Fri, 19 Dec 2025 10:25:31 +0100
Subject: [PATCH v2 2/8] scsi: Make use of bus callbacks
In-Reply-To: <cover.1766133330.git.u.kleine-koenig@baylibre.com>
References: <cover.1766133330.git.u.kleine-koenig@baylibre.com>
Message-ID: <a54e363a3fd2054fb924afd7df44bca7f444b5f1.1766133330.git.u.kleine-koenig@baylibre.com>

Introduce a bus specific probe, remove and shutdown function. For now
this only allows to get rid of a cast of the generic device to an scsi
device in the drivers and changes the remove prototype to return
void---a non-zero return value is ignored anyhow.

The objective is to get rid of users of struct device_driver callbacks
.probe(), .remove() and .shutdown() to eventually remove these. Until
all scsi drivers are converted this results in a runtime warning about
the drivers needing an update because there is a bus probe function and
a driver probe function. The in-tree drivers are fixed by the following
commits.

Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig at baylibre.com>
---
 drivers/scsi/scsi_sysfs.c  | 73 ++++++++++++++++++++++++++++++++++++--
 include/scsi/scsi_driver.h |  3 ++
 2 files changed, 74 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index db0ba68f2e6e..6b8c5c05f294 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -554,10 +554,48 @@ static int scsi_bus_uevent(const struct device *dev, struct kobj_uevent_env *env
 	return 0;
 }
 
+static int scsi_bus_probe(struct device *dev)
+{
+	struct scsi_device *sdp = to_scsi_device(dev);
+	struct scsi_driver *drv = to_scsi_driver(dev->driver);
+
+	if (drv->probe)
+		return drv->probe(sdp);
+	else
+		return 0;
+}
+
+static void scsi_bus_remove(struct device *dev)
+{
+	struct scsi_device *sdp = to_scsi_device(dev);
+	struct scsi_driver *drv = to_scsi_driver(dev->driver);
+
+	if (drv->remove)
+		drv->remove(sdp);
+}
+
+static void scsi_bus_shutdown(struct device *dev)
+{
+	struct scsi_device *sdp = to_scsi_device(dev);
+	struct scsi_driver *drv;
+
+	if (!dev->driver)
+		return;
+
+	drv = to_scsi_driver(dev->driver);
+
+	if (drv->shutdown)
+		drv->shutdown(sdp);
+}
+
+
 const struct bus_type scsi_bus_type = {
-        .name		= "scsi",
-        .match		= scsi_bus_match,
+	.name		= "scsi",
+	.match		= scsi_bus_match,
 	.uevent		= scsi_bus_uevent,
+	.probe		= scsi_bus_probe,
+	.remove		= scsi_bus_remove,
+	.shutdown	= scsi_bus_shutdown,
 #ifdef CONFIG_PM
 	.pm		= &scsi_bus_pm_ops,
 #endif
@@ -1554,6 +1592,30 @@ void scsi_remove_target(struct device *dev)
 }
 EXPORT_SYMBOL(scsi_remove_target);
 
+static int scsi_legacy_probe(struct scsi_device *sdp)
+{
+	struct device *dev = &sdp->sdev_gendev;
+	struct device_driver *driver = dev->driver;
+
+	return driver->probe(dev);
+}
+
+static void scsi_legacy_remove(struct scsi_device *sdp)
+{
+	struct device *dev = &sdp->sdev_gendev;
+	struct device_driver *driver = dev->driver;
+
+	driver->remove(dev);
+}
+
+static void scsi_legacy_shutdown(struct scsi_device *sdp)
+{
+	struct device *dev = &sdp->sdev_gendev;
+	struct device_driver *driver = dev->driver;
+
+	driver->shutdown(dev);
+}
+
 int __scsi_register_driver(struct scsi_driver *sdrv, struct module *owner)
 {
 	struct device_driver *drv = &sdrv->gendrv;
@@ -1561,6 +1623,13 @@ int __scsi_register_driver(struct scsi_driver *sdrv, struct module *owner)
 	drv->bus = &scsi_bus_type;
 	drv->owner = owner;
 
+	if (!sdrv->probe && drv->probe)
+		sdrv->probe = scsi_legacy_probe;
+	if (!sdrv->remove && drv->remove)
+		sdrv->remove = scsi_legacy_remove;
+	if (!sdrv->shutdown && drv->shutdown)
+		sdrv->shutdown = scsi_legacy_shutdown;
+
 	return driver_register(drv);
 }
 EXPORT_SYMBOL(__scsi_register_driver);
diff --git a/include/scsi/scsi_driver.h b/include/scsi/scsi_driver.h
index 40aba9a9349a..249cea724abd 100644
--- a/include/scsi/scsi_driver.h
+++ b/include/scsi/scsi_driver.h
@@ -12,6 +12,9 @@ struct request;
 struct scsi_driver {
 	struct device_driver	gendrv;
 
+	int (*probe)(struct scsi_device *);
+	void (*remove)(struct scsi_device *);
+	void (*shutdown)(struct scsi_device *);
 	int (*resume)(struct device *);
 	void (*rescan)(struct device *);
 	blk_status_t (*init_command)(struct scsi_cmnd *);
-- 
2.47.3



From u.kleine-koenig at baylibre.com  Fri Dec 19 01:25:37 2025
From: u.kleine-koenig at baylibre.com (=?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?=)
Date: Fri, 19 Dec 2025 10:25:37 +0100
Subject: [PATCH v2 8/8] scsi: ufs: Convert to scsi bus methods
In-Reply-To: <cover.1766133330.git.u.kleine-koenig@baylibre.com>
References: <cover.1766133330.git.u.kleine-koenig@baylibre.com>
Message-ID: <69f17c7d4f8f587e2a56e3ea268d441d98a6a895.1766133330.git.u.kleine-koenig@baylibre.com>

The scsi subsystem has implemented dedicated callbacks for probe, remove
and shutdown. Make use of them. This fixes a runtime warning about the
driver needing to be converted to the bus probe method.

Reviewed-by: Peter Wang <peter.wang at mediatek.com>
Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig at baylibre.com>
---
 drivers/ufs/core/ufshcd.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index da1e89e95d07..78669c205568 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -10525,9 +10525,8 @@ int ufshcd_runtime_resume(struct device *dev)
 EXPORT_SYMBOL(ufshcd_runtime_resume);
 #endif /* CONFIG_PM */
 
-static void ufshcd_wl_shutdown(struct device *dev)
+static void ufshcd_wl_shutdown(struct scsi_device *sdev)
 {
-	struct scsi_device *sdev = to_scsi_device(dev);
 	struct ufs_hba *hba = shost_priv(sdev->host);
 
 	down(&hba->host_sem);
@@ -11133,9 +11132,9 @@ static int ufshcd_wl_poweroff(struct device *dev)
 }
 #endif
 
-static int ufshcd_wl_probe(struct device *dev)
+static int ufshcd_wl_probe(struct scsi_device *sdev)
 {
-	struct scsi_device *sdev = to_scsi_device(dev);
+	struct device *dev = &sdev->sdev_gendev;
 
 	if (!is_device_wlun(sdev))
 		return -ENODEV;
@@ -11147,10 +11146,11 @@ static int ufshcd_wl_probe(struct device *dev)
 	return  0;
 }
 
-static int ufshcd_wl_remove(struct device *dev)
+static void ufshcd_wl_remove(struct scsi_device *sdev)
 {
+	struct device *dev = &sdev->sdev_gendev;
+
 	pm_runtime_forbid(dev);
-	return 0;
 }
 
 static const struct dev_pm_ops ufshcd_wl_pm_ops = {
@@ -11223,12 +11223,12 @@ static void ufshcd_check_header_layout(void)
  * Hence register a scsi driver for ufs wluns only.
  */
 static struct scsi_driver ufs_dev_wlun_template = {
+	.probe = ufshcd_wl_probe,
+	.remove = ufshcd_wl_remove,
+	.shutdown = ufshcd_wl_shutdown,
 	.gendrv = {
 		.name = "ufs_device_wlun",
-		.probe = ufshcd_wl_probe,
-		.remove = ufshcd_wl_remove,
 		.pm = &ufshcd_wl_pm_ops,
-		.shutdown = ufshcd_wl_shutdown,
 	},
 };
 
-- 
2.47.3



From olsajiri at gmail.com  Fri Dec 19 01:27:31 2025
From: olsajiri at gmail.com (Jiri Olsa)
Date: Fri, 19 Dec 2025 10:27:31 +0100
Subject: [PATCHv5 bpf-next 3/9] ftrace: Export some of hash related
 functions
In-Reply-To: <20251217200712.606a9a7a@robin>
References: <20251215211402.353056-1-jolsa@kernel.org>
 <20251215211402.353056-4-jolsa@kernel.org>
 <20251217200712.606a9a7a@robin>
Message-ID: <aUUag8LVUy2CTNpS@krava>

On Wed, Dec 17, 2025 at 08:07:12PM -0500, Steven Rostedt wrote:
> On Mon, 15 Dec 2025 22:13:56 +0100
> Jiri Olsa <jolsa at kernel.org> wrote:
> 
> > index 505b7d3f5641..c0a72fcae1f6 100644
> > --- a/include/linux/ftrace.h
> > +++ b/include/linux/ftrace.h
> > @@ -82,6 +82,7 @@ static inline void early_trace_init(void) { }
> >  
> >  struct module;
> >  struct ftrace_hash;
> > +struct ftrace_func_entry;
> >  
> >  #if defined(CONFIG_FUNCTION_TRACER) && defined(CONFIG_MODULES) && \
> >  	defined(CONFIG_DYNAMIC_FTRACE)
> > @@ -405,6 +406,14 @@ enum ftrace_ops_cmd {
> >  typedef int (*ftrace_ops_func_t)(struct ftrace_ops *op, enum ftrace_ops_cmd cmd);
> >  
> >  #ifdef CONFIG_DYNAMIC_FTRACE
> > +
> > +#define FTRACE_HASH_DEFAULT_BITS 10
> > +
> > +struct ftrace_hash *alloc_ftrace_hash(int size_bits);
> > +void free_ftrace_hash(struct ftrace_hash *hash);
> > +struct ftrace_func_entry *add_hash_entry_direct(struct ftrace_hash *hash,
> 
> As this is no longer static and is exported to other users within the
> kernel, it should be renamed to: add_ftrace_hash_entry_direct()
> to keep the namespace unique.

ok, will change

jirka

> 
> -- Steve
> 
> > +						unsigned long ip, unsigned long direct);
> > +
> >  /* The hash used to know what functions callbacks trace */
> >  struct ftrace_ops_hash {
> >  	struct ftrace_hash __rcu	*notrace_hash;


From olsajiri at gmail.com  Fri Dec 19 01:27:38 2025
From: olsajiri at gmail.com (Jiri Olsa)
Date: Fri, 19 Dec 2025 10:27:38 +0100
Subject: [PATCHv5 bpf-next 4/9] ftrace: Add update_ftrace_direct_add
 function
In-Reply-To: <20251217203909.474ae959@robin>
References: <20251215211402.353056-1-jolsa@kernel.org>
 <20251215211402.353056-5-jolsa@kernel.org>
 <20251217203909.474ae959@robin>
Message-ID: <aUUaiqP4kjGwlUMG@krava>

On Wed, Dec 17, 2025 at 08:39:09PM -0500, Steven Rostedt wrote:
> On Mon, 15 Dec 2025 22:13:57 +0100
> Jiri Olsa <jolsa at kernel.org> wrote:
> 
> 
> > +/**
> > + * hash_add - adds two struct ftrace_hash and returns the result
> > + * @a: struct ftrace_hash object
> > + * @b: struct ftrace_hash object
> > + *
> > + * Returns struct ftrace_hash object on success, NULL on error.
> > + */
> > +static struct ftrace_hash *hash_add(struct ftrace_hash *a, struct ftrace_hash *b)
> > +{
> > +	struct ftrace_func_entry *entry;
> > +	struct ftrace_hash *add;
> > +	int size, i;
> > +
> > +	size = hash_count(a) + hash_count(b);
> > +	if (size > 32)
> > +		size = 32;
> > +
> > +	add = alloc_and_copy_ftrace_hash(fls(size), a);
> > +	if (!add)
> > +		goto error;
> 
> You can just return NULL here, as add is NULL.

ok

> 
> > +
> > +	size = 1 << b->size_bits;
> > +	for (i = 0; i < size; i++) {
> > +		hlist_for_each_entry(entry, &b->buckets[i], hlist) {
> > +			if (add_hash_entry_direct(add, entry->ip, entry->direct) == NULL)
> > +				goto error;
> 
> Could remove the error and have:
> 
> 			if (add_hash_entry_direct(add, entry->ip, entry->direct) == NULL) {
> 				free_ftrace_hash(add);
> 				return NULL;
> 			}

ok

> 
> 
> > +		}
> > +	}
> > +	return add;
> > +
> > + error:
> > +	free_ftrace_hash(add);
> > +	return NULL;
> > +}
> > +
> 
> Non static functions require a kerneldoc header.

ah right, will add

> 
> > +int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash)
> > +{
> > +	struct ftrace_hash *old_direct_functions = NULL, *new_direct_functions;
> > +	struct ftrace_hash *old_filter_hash, *new_filter_hash = NULL;
> 
> BTW, I prefer to not double up on variables. That is to have each on
> their own lines. Makes it easier to read for me.
> 
> > +	struct ftrace_func_entry *entry;
> > +	int i, size, err = -EINVAL;
> 
> Even here.

ok, will split

> 
> > +	bool reg;
> > +
> > +	if (!hash_count(hash))
> > +		return -EINVAL;
> > +
> > +	mutex_lock(&direct_mutex);
> > +
> > +	/* Make sure requested entries are not already registered. */
> > +	size = 1 << hash->size_bits;
> > +	for (i = 0; i < size; i++) {
> 
> If you want, you can remove the i declaration and use for(int i = 0; ... here.

ok

SNIP

> > +	}
> > +
> > +	if (err) {
> > +		/* reset direct_functions and free the new one */
> > +		rcu_assign_pointer(direct_functions, old_direct_functions);
> > +		old_direct_functions = new_direct_functions;
> > +	}
> > +
> > + out_unlock:
> > +	mutex_unlock(&direct_mutex);
> > +
> > +	if (old_direct_functions && old_direct_functions != EMPTY_HASH)
> > +		call_rcu_tasks(&old_direct_functions->rcu, register_ftrace_direct_cb);
> > +	if (new_filter_hash)
> 
> free_ftrace_hash() checks for NULL, so you don't need the above if statement.

ok

thanks,
jirka


From olsajiri at gmail.com  Fri Dec 19 01:27:45 2025
From: olsajiri at gmail.com (Jiri Olsa)
Date: Fri, 19 Dec 2025 10:27:45 +0100
Subject: [PATCHv5 bpf-next 5/9] ftrace: Add update_ftrace_direct_del
 function
In-Reply-To: <20251217204814.38756224@robin>
References: <20251215211402.353056-1-jolsa@kernel.org>
 <20251215211402.353056-6-jolsa@kernel.org>
 <20251217204814.38756224@robin>
Message-ID: <aUUakb_Bv1sDfJUR@krava>

On Wed, Dec 17, 2025 at 08:48:14PM -0500, Steven Rostedt wrote:
> On Mon, 15 Dec 2025 22:13:58 +0100
> Jiri Olsa <jolsa at kernel.org> wrote:
> > +/**
> > + * hash_sub - substracts @b from @a and returns the result
> > + * @a: struct ftrace_hash object
> > + * @b: struct ftrace_hash object
> > + *
> > + * Returns struct ftrace_hash object on success, NULL on error.
> > + */
> > +static struct ftrace_hash *hash_sub(struct ftrace_hash *a, struct ftrace_hash *b)
> > +{
> > +	struct ftrace_func_entry *entry, *del;
> > +	struct ftrace_hash *sub;
> > +	int size, i;
> > +
> > +	sub = alloc_and_copy_ftrace_hash(a->size_bits, a);
> > +	if (!sub)
> > +		goto error;
> 
> Again, this can be just return NULL;

ok

> 
> > +
> > +	size = 1 << b->size_bits;
> > +	for (i = 0; i < size; i++) {
> 
> You can make this for (int i = 0; ...) too.

ok

> 
> > +		hlist_for_each_entry(entry, &b->buckets[i], hlist) {
> > +			del = __ftrace_lookup_ip(sub, entry->ip);
> > +			if (WARN_ON_ONCE(!del))
> > +				goto error;
> 
> And you can remove the error label here too:

ok

> 
> 			if (WARN_ON_ONCE(!del)) {
> 				free_ftrace_hash(sub);
> 				return NULL;
> 			}
> 
> 
> > +			remove_hash_entry(sub, del);
> > +			kfree(del);
> > +		}
> > +	}
> > +	return sub;
> > +
> > + error:
> > +	free_ftrace_hash(sub);
> > +	return NULL;
> > +}
> > +
> > +int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash)
> > +{
> > +	struct ftrace_hash *old_direct_functions = NULL, *new_direct_functions;
> > +	struct ftrace_hash *old_filter_hash, *new_filter_hash = NULL;
> > +	struct ftrace_func_entry *del, *entry;
> 
> One variable per line.

ok

> 
> > +	unsigned long size, i;
> > +	int err = -EINVAL;
> > +
> > +	if (!hash_count(hash))
> > +		return -EINVAL;
> > +	if (check_direct_multi(ops))
> > +		return -EINVAL;
> > +	if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
> > +		return -EINVAL;
> > +	if (direct_functions == EMPTY_HASH)
> > +		return -EINVAL;
> > +
> > +	mutex_lock(&direct_mutex);
> > +
> > +	old_filter_hash = ops->func_hash ? ops->func_hash->filter_hash : NULL;
> > +
> > +	if (!hash_count(old_filter_hash))
> > +		goto out_unlock;
> > +
> > +	/* Make sure requested entries are already registered. */
> > +	size = 1 << hash->size_bits;
> > +	for (i = 0; i < size; i++) {
> 
> 	for (int i = 0; ...) 

ack

thanks,
jirka


From olsajiri at gmail.com  Fri Dec 19 01:27:51 2025
From: olsajiri at gmail.com (Jiri Olsa)
Date: Fri, 19 Dec 2025 10:27:51 +0100
Subject: [PATCHv5 bpf-next 6/9] ftrace: Add update_ftrace_direct_mod
 function
In-Reply-To: <20251218101942.0716efd6@gandalf.local.home>
References: <20251215211402.353056-1-jolsa@kernel.org>
 <20251215211402.353056-7-jolsa@kernel.org>
 <20251218101942.0716efd6@gandalf.local.home>
Message-ID: <aUUal38FoUFnndOI@krava>

On Thu, Dec 18, 2025 at 10:19:42AM -0500, Steven Rostedt wrote:
> On Mon, 15 Dec 2025 22:13:59 +0100
> Jiri Olsa <jolsa at kernel.org> wrote:
> 
> > diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
> > index 48dc0de5f2ce..95a38fb18ed7 100644
> > --- a/kernel/trace/ftrace.c
> > +++ b/kernel/trace/ftrace.c
> > @@ -6489,6 +6489,78 @@ int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash)
> >  	return err;
> >  }
> >  
> 
> Kerneldoc needed.

will add

> 
> > +int update_ftrace_direct_mod(struct ftrace_ops *ops, struct ftrace_hash *hash, bool do_direct_lock)
> > +{
> > +	struct ftrace_func_entry *entry, *tmp;
> > +	static struct ftrace_ops tmp_ops = {
> > +		.func		= ftrace_stub,
> > +		.flags		= FTRACE_OPS_FL_STUB,
> > +	};
> > +	struct ftrace_hash *orig_hash;
> > +	unsigned long size, i;
> > +	int err = -EINVAL;
> > +
> > +	if (!hash_count(hash))
> > +		return -EINVAL;
> > +	if (check_direct_multi(ops))
> > +		return -EINVAL;
> > +	if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
> > +		return -EINVAL;
> > +	if (direct_functions == EMPTY_HASH)
> > +		return -EINVAL;
> > +
> > +	if (do_direct_lock)
> > +		mutex_lock(&direct_mutex);
> 
> This optional taking of the direct_mutex lock needs some serious rationale
> and documentation.

it mirrors the use of modify_ftrace_direct/modify_ftrace_direct_nolock
when we do trampoline update from within ftrace_ops->ops_func callback

I'll add comments with more details

> 
> > +
> > +	orig_hash = ops->func_hash ? ops->func_hash->filter_hash : NULL;
> > +	if (!orig_hash)
> > +		goto unlock;
> > +
> > +	/* Enable the tmp_ops to have the same functions as the direct ops */
> > +	ftrace_ops_init(&tmp_ops);
> > +	tmp_ops.func_hash = ops->func_hash;
> > +
> > +	err = register_ftrace_function_nolock(&tmp_ops);
> > +	if (err)
> > +		goto unlock;
> > +
> > +	/*
> > +	 * Call __ftrace_hash_update_ipmodify() here, so that we can call
> > +	 * ops->ops_func for the ops. This is needed because the above
> > +	 * register_ftrace_function_nolock() worked on tmp_ops.
> > +	 */
> > +	err = __ftrace_hash_update_ipmodify(ops, orig_hash, orig_hash, true);
> > +	if (err)
> > +		goto out;
> > +
> > +	/*
> > +	 * Now the ftrace_ops_list_func() is called to do the direct callers.
> > +	 * We can safely change the direct functions attached to each entry.
> > +	 */
> > +	mutex_lock(&ftrace_lock);
> 
> I'm going to need some time staring at this code. It looks like it may be
> relying on some internals here.

ok, thanks

jirka


From olsajiri at gmail.com  Fri Dec 19 01:27:56 2025
From: olsajiri at gmail.com (Jiri Olsa)
Date: Fri, 19 Dec 2025 10:27:56 +0100
Subject: [PATCHv5 bpf-next 9/9] bpf,x86: Use single ftrace_ops for direct
 calls
In-Reply-To: <20251218112608.11a14a4a@gandalf.local.home>
References: <20251215211402.353056-1-jolsa@kernel.org>
 <20251215211402.353056-10-jolsa@kernel.org>
 <20251218112608.11a14a4a@gandalf.local.home>
Message-ID: <aUUanPijlWsDlS0X@krava>

On Thu, Dec 18, 2025 at 11:26:08AM -0500, Steven Rostedt wrote:
> On Mon, 15 Dec 2025 22:14:02 +0100
> Jiri Olsa <jolsa at kernel.org> wrote:
> 
> > Using single ftrace_ops for direct calls update instead of allocating
> > ftrace_ops object for each trampoline.
> > 
> > With single ftrace_ops object we can use update_ftrace_direct_* api
> > that allows multiple ip sites updates on single ftrace_ops object.
> > 
> > Adding HAVE_SINGLE_FTRACE_DIRECT_OPS config option to be enabled on
> > each arch that supports this.
> > 
> > At the moment we can enable this only on x86 arch, because arm relies
> > on ftrace_ops object representing just single trampoline image (stored
> > in ftrace_ops::direct_call). Ach that do not support this will continue
> 
> My back "Ach" and doesn't support me well. ;-)

heh, should have been 'Archs' ;-)

> 
> > to use *_ftrace_direct api.
> > 
> > Signed-off-by: Jiri Olsa <jolsa at kernel.org>
> > ---
> >  arch/x86/Kconfig        |   1 +
> >  kernel/bpf/trampoline.c | 195 ++++++++++++++++++++++++++++++++++------
> >  kernel/trace/Kconfig    |   3 +
> >  kernel/trace/ftrace.c   |   7 +-
> >  4 files changed, 177 insertions(+), 29 deletions(-)
> > 
> > diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> > index 17a107cc5244..d0c36e49e66e 100644
> > --- a/arch/x86/Kconfig
> > +++ b/arch/x86/Kconfig
> > @@ -335,6 +335,7 @@ config X86
> >  	select SCHED_SMT			if SMP
> >  	select ARCH_SUPPORTS_SCHED_CLUSTER	if SMP
> >  	select ARCH_SUPPORTS_SCHED_MC		if SMP
> > +	select HAVE_SINGLE_FTRACE_DIRECT_OPS	if X86_64 && DYNAMIC_FTRACE_WITH_DIRECT_CALLS
> 
> You can remove the "&& DYNAMIC_FTRACE_WITH_DIRECT_CALLS" part by having the
> config depend on it (see below).

...

> 
> >  
> >  config INSTRUCTION_DECODER
> >  	def_bool y
> > diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
> > index 17af2aad8382..02371db3db3e 100644
> > --- a/kernel/bpf/trampoline.c
> > +++ b/kernel/bpf/trampoline.c
> > @@ -33,12 +33,40 @@ static DEFINE_MUTEX(trampoline_mutex);
> >  #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
> >  static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mutex);
> >  
> > +#ifdef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS
> 
> Make this:
> 
>  #ifdef CONFIG_SINGLE_FTRACE_DIRECT_OPS
> 
> for the suggested modification in the Kconfig below.
> 
> > +static struct bpf_trampoline *direct_ops_ip_lookup(struct ftrace_ops *ops, unsigned long ip)
> > +{
> > +	struct hlist_head *head_ip;
> > +	struct bpf_trampoline *tr;
> > +
> > +	mutex_lock(&trampoline_mutex);
> 
> 	guard(mutex)(&trampoline_mutex);

right, will change

> 
> > +	head_ip = &trampoline_ip_table[hash_64(ip, TRAMPOLINE_HASH_BITS)];
> > +	hlist_for_each_entry(tr, head_ip, hlist_ip) {
> > +		if (tr->ip == ip)
> 
> 			return NULL;
> 
> > +			goto out;
> > +	}
> 
> 
> > +	tr = NULL;
> > +out:
> > +	mutex_unlock(&trampoline_mutex);
> 
> No need for the above

yep

> 
> > +	return tr;
> > +}
> > +#else
> > +static struct bpf_trampoline *direct_ops_ip_lookup(struct ftrace_ops *ops, unsigned long ip)
> > +{
> > +	return ops->private;
> > +}
> > +#endif /* CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS */
> > +
> >  static int bpf_tramp_ftrace_ops_func(struct ftrace_ops *ops, unsigned long ip,
> >  				     enum ftrace_ops_cmd cmd)
> >  {
> > -	struct bpf_trampoline *tr = ops->private;
> > +	struct bpf_trampoline *tr;
> >  	int ret = 0;
> >  
> > +	tr = direct_ops_ip_lookup(ops, ip);
> > +	if (!tr)
> > +		return -EINVAL;
> > +
> >  	if (cmd == FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_SELF) {
> >  		/* This is called inside register_ftrace_direct_multi(), so
> >  		 * tr->mutex is already locked.
> > @@ -137,6 +165,139 @@ void bpf_image_ksym_del(struct bpf_ksym *ksym)
> >  			   PAGE_SIZE, true, ksym->name);
> >  }
> >  
> > +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
> > +#ifdef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS
> 
> Replace the above two with:
> 
>  #ifdef CONFIG_SINGLE_FTRACE_DIRECT_OPS

...

> 
> > +/*
> > + * We have only single direct_ops which contains all the direct call
> > + * sites and is the only global ftrace_ops for all trampolines.
> > + *
> > + * We use 'update_ftrace_direct_*' api for attachment.
> > + */
> > +struct ftrace_ops direct_ops = {
> > +	.ops_func = bpf_tramp_ftrace_ops_func,
> > +};
> > +
> > +static int direct_ops_alloc(struct bpf_trampoline *tr)
> > +{
> > +	tr->fops = &direct_ops;
> > +	return 0;
> > +}
> > +
> > +static void direct_ops_free(struct bpf_trampoline *tr) { }
> > +
> > +static struct ftrace_hash *hash_from_ip(struct bpf_trampoline *tr, void *ptr)
> > +{
> > +	unsigned long ip, addr = (unsigned long) ptr;
> > +	struct ftrace_hash *hash;
> > +
> > +	ip = ftrace_location(tr->ip);
> > +	if (!ip)
> > +		return NULL;
> > +	hash = alloc_ftrace_hash(FTRACE_HASH_DEFAULT_BITS);
> > +	if (!hash)
> > +		return NULL;
> > +	if (bpf_trampoline_use_jmp(tr->flags))
> > +		addr = ftrace_jmp_set(addr);
> > +	if (!add_hash_entry_direct(hash, ip, addr)) {
> > +		free_ftrace_hash(hash);
> > +		return NULL;
> > +	}
> > +	return hash;
> > +}
> > +
> > +static int direct_ops_add(struct bpf_trampoline *tr, void *addr)
> > +{
> > +	struct ftrace_hash *hash = hash_from_ip(tr, addr);
> > +	int err = -ENOMEM;
> > +
> > +	if (hash)
> > +		err = update_ftrace_direct_add(tr->fops, hash);
> > +	free_ftrace_hash(hash);
> > +	return err;
> > +}
> 
> I think these functions would be cleaner as:
> 
> {
> 	struct ftrace_hash *hash = hash_from_ip(tr, addr);
> 	int err;
> 
> 	if (!hash)
> 		return -ENOMEM;
> 
> 	err = update_ftrace_direct_*(tr->fops, hash);
> 	free_ftrace_hash(hash);
> 	return err;
> }

np, will change

> 
> 
> > +
> > +static int direct_ops_del(struct bpf_trampoline *tr, void *addr)
> > +{
> > +	struct ftrace_hash *hash = hash_from_ip(tr, addr);
> > +	int err = -ENOMEM;
> > +
> > +	if (hash)
> > +		err = update_ftrace_direct_del(tr->fops, hash);
> > +	free_ftrace_hash(hash);
> > +	return err;
> > +}
> > +
> > +static int direct_ops_mod(struct bpf_trampoline *tr, void *addr, bool lock_direct_mutex)
> > +{
> > +	struct ftrace_hash *hash = hash_from_ip(tr, addr);
> > +	int err = -ENOMEM;
> > +
> > +	if (hash)
> > +		err = update_ftrace_direct_mod(tr->fops, hash, lock_direct_mutex);
> > +	free_ftrace_hash(hash);
> > +	return err;
> > +}
> > +#else
> > +/*
> > + * We allocate ftrace_ops object for each trampoline and it contains
> > + * call site specific for that trampoline.
> > + *
> > + * We use *_ftrace_direct api for attachment.
> > + */
> > +static int direct_ops_alloc(struct bpf_trampoline *tr)
> > +{
> > +	tr->fops = kzalloc(sizeof(struct ftrace_ops), GFP_KERNEL);
> > +	if (!tr->fops)
> > +		return -ENOMEM;
> > +	tr->fops->private = tr;
> > +	tr->fops->ops_func = bpf_tramp_ftrace_ops_func;
> > +	return 0;
> > +}
> > +
> > +static void direct_ops_free(struct bpf_trampoline *tr)
> > +{
> > +	if (tr->fops) {
> > +		ftrace_free_filter(tr->fops);
> > +		kfree(tr->fops);
> > +	}
> > +}
> 
> Why not:
> 
> static void direct_ops_free(struct bpf_trampoline *tr)
> {
> 	if (!tr->fops)
> 		return;
> 
> 	ftrace_free_filter(tr->fops);
> 	kfree(tr->fops);
> }

same pattern like above, ok

> 
>  ?
> 
> > +
> > +static int direct_ops_add(struct bpf_trampoline *tr, void *ptr)
> > +{
> > +	unsigned long addr = (unsigned long) ptr;
> > +	struct ftrace_ops *ops = tr->fops;
> > +	int ret;
> > +
> > +	if (bpf_trampoline_use_jmp(tr->flags))
> > +		addr = ftrace_jmp_set(addr);
> > +
> > +	ret = ftrace_set_filter_ip(ops, tr->ip, 0, 1);
> > +	if (ret)
> > +		return ret;
> > +	return register_ftrace_direct(ops, addr);
> > +}
> > +
> > +static int direct_ops_del(struct bpf_trampoline *tr, void *addr)
> > +{
> > +	return unregister_ftrace_direct(tr->fops, (long)addr, false);
> > +}
> > +
> > +static int direct_ops_mod(struct bpf_trampoline *tr, void *ptr, bool lock_direct_mutex)
> > +{
> > +	unsigned long addr = (unsigned long) ptr;
> > +	struct ftrace_ops *ops = tr->fops;
> > +
> > +	if (bpf_trampoline_use_jmp(tr->flags))
> > +		addr = ftrace_jmp_set(addr);
> > +	if (lock_direct_mutex)
> > +		return modify_ftrace_direct(ops, addr);
> > +	return modify_ftrace_direct_nolock(ops, addr);
> > +}
> > +#endif /* CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS */
> > +#else
> > +static void direct_ops_free(struct bpf_trampoline *tr) { }
> 
> This is somewhat inconsistent with direct_ops_alloc() that has:
> 
> #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
> 	if (direct_ops_alloc(tr)) {
> 		kfree(tr);
> 		tr = NULL;
> 		goto out;
> 	}
> #endif
> 
> Now, if you wrap the direct_ops_free() too, we can remove the
>  #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
> part with my kconfig suggestion. Otherwise keep the kconfig as is, but I
> would add a stub function for direct_ops_alloc() too.

ah right.. I think let's do the kconfig change you suggest to make
this simpler

> 
> > +#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
> > +
> >  static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
> >  {
> >  	struct bpf_trampoline *tr;
> > @@ -155,14 +316,11 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
> >  	if (!tr)
> >  		goto out;
> >  #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
> > -	tr->fops = kzalloc(sizeof(struct ftrace_ops), GFP_KERNEL);
> > -	if (!tr->fops) {
> > +	if (direct_ops_alloc(tr)) {
> >  		kfree(tr);
> >  		tr = NULL;
> >  		goto out;
> >  	}
> > -	tr->fops->private = tr;
> > -	tr->fops->ops_func = bpf_tramp_ftrace_ops_func;
> >  #endif
> >  
> >  	tr->key = key;
> > @@ -206,7 +364,7 @@ static int unregister_fentry(struct bpf_trampoline *tr, u32 orig_flags,
> >  	int ret;
> >  
> >  	if (tr->func.ftrace_managed)
> > -		ret = unregister_ftrace_direct(tr->fops, (long)old_addr, false);
> > +		ret = direct_ops_del(tr, old_addr);
> 
> Doesn't this need a wrapper too?

yep

> 
> >  	else
> >  		ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr, NULL);
> >  
> > @@ -220,15 +378,7 @@ static int modify_fentry(struct bpf_trampoline *tr, u32 orig_flags,
> >  	int ret;
> >  
> >  	if (tr->func.ftrace_managed) {
> > -		unsigned long addr = (unsigned long) new_addr;
> > -
> > -		if (bpf_trampoline_use_jmp(tr->flags))
> > -			addr = ftrace_jmp_set(addr);
> > -
> > -		if (lock_direct_mutex)
> > -			ret = modify_ftrace_direct(tr->fops, addr);
> > -		else
> > -			ret = modify_ftrace_direct_nolock(tr->fops, addr);
> > +		ret = direct_ops_mod(tr, new_addr, lock_direct_mutex);
> 
> and this.
> 
> >  	} else {
> >  		ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr,
> >  						   new_addr);
> > @@ -251,15 +401,7 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
> >  	}
> >  
> >  	if (tr->func.ftrace_managed) {
> > -		unsigned long addr = (unsigned long) new_addr;
> > -
> > -		if (bpf_trampoline_use_jmp(tr->flags))
> > -			addr = ftrace_jmp_set(addr);
> > -
> > -		ret = ftrace_set_filter_ip(tr->fops, (unsigned long)ip, 0, 1);
> > -		if (ret)
> > -			return ret;
> > -		ret = register_ftrace_direct(tr->fops, addr);
> > +		ret = direct_ops_add(tr, new_addr);
> 
> Ditto.

yes

> 
> >  	} else {
> >  		ret = bpf_trampoline_update_fentry(tr, 0, NULL, new_addr);
> >  	}
> > @@ -910,10 +1052,7 @@ void bpf_trampoline_put(struct bpf_trampoline *tr)
> >  	 */
> >  	hlist_del(&tr->hlist_key);
> >  	hlist_del(&tr->hlist_ip);
> > -	if (tr->fops) {
> > -		ftrace_free_filter(tr->fops);
> > -		kfree(tr->fops);
> > -	}
> > +	direct_ops_free(tr);
> >  	kfree(tr);
> >  out:
> >  	mutex_unlock(&trampoline_mutex);
> > diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
> > index 4661b9e606e0..1ad2e307c834 100644
> > --- a/kernel/trace/Kconfig
> > +++ b/kernel/trace/Kconfig
> > @@ -50,6 +50,9 @@ config HAVE_DYNAMIC_FTRACE_WITH_REGS
> >  config HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
> >  	bool
> >  
> > +config HAVE_SINGLE_FTRACE_DIRECT_OPS
> > +	bool
> > +
> 
> Now you could add:
> 
>   config SINGLE_FTRACE_DIRECT_OPS
> 	bool
> 	default y
> 	depends on HAVE_SINGLE_FTRACE_DIRECT_OPS && DYNAMIC_FTRACE_WITH_DIRECT_CALLS

ok, the dependency is more ovbvious, will change

thanks,
jirka


From c.parant at phytec.fr  Fri Dec 19 01:28:51 2025
From: c.parant at phytec.fr (Christophe Parant)
Date: Fri, 19 Dec 2025 09:28:51 +0000
Subject: [PATCH RESEND v2 03/11] dt-bindings: arm: stm32: Modify
 STM32MP15x Phytec board items types
In-Reply-To: <20251211160013.GA1485420-robh@kernel.org>
References: <20251210101611.27008-1-c.parant@phytec.fr>
	 <20251210101611.27008-4-c.parant@phytec.fr>
	 <20251211160013.GA1485420-robh@kernel.org>
Message-ID: <0ad7413a5252633b2a820db1cf2a10f7d658f6c6.camel@phytec.fr>

Hi Rob,

Le jeudi 11 d?cembre 2025 ? 10:00 -0600, Rob Herring a ?crit?:
> On Wed, Dec 10, 2025 at 11:16:03AM +0100, Christophe Parant wrote:
> > As Phytec manages different SoM configurations with different
> > STM32MP15
> > SoC versions, modify the phyBOARD and SoM compatible items to
> > "enum"
> > instead of "const".
> 
> Change to enum when you add a 2nd string. I don't follow why you
> would 
Ok, I thought it was possible to use enum here (kind of information
that others board versions are available but not upstream yet).
As I saw examples in the same file where enum is used with only one
string. For example: "seeed,stm32mp157c-odyssey" or "st,stm32mp235f-
dk".
But I could change to const if this is an issue, no problem.

> do that either. You have more than 1 SoM for stm32mp157?
Yes we have several versions. Here, we would also like to add our
"phycore-stm32mp1-4" which is equipped with the "F" version of
stm32mp157: "stm32mp157f" (which is
another board device tree).
But didn't want to add it now in this patch series.
We also have "phycore-stm32mp1-6" which is equipped with "stm32mp153a".
The idea was to keep this Description section for the "st,stm32mp157"
(const items) and would need another section for the "st,stm32mp13a".
> 
> > The description concerns PHYTEC SoM equipped with STM32MP157
> > ("st,stm32mp157" is "const").
> > Also add comments in front of the enum items to be able to identify
> > the
> > compatible string with the phyBOARD/phyCORE names.
> > 
> > Signed-off-by: Christophe Parant <c.parant at phytec.fr>
> > ---
> > ?Documentation/devicetree/bindings/arm/stm32/stm32.yaml | 8 +++++--
> > -
> > ?1 file changed, 5 insertions(+), 3 deletions(-)
> > 
> > diff --git a/Documentation/devicetree/bindings/arm/stm32/stm32.yaml
> > b/Documentation/devicetree/bindings/arm/stm32/stm32.yaml
> > index 408532504a24..fbd3d364c1f7 100644
> > --- a/Documentation/devicetree/bindings/arm/stm32/stm32.yaml
> > +++ b/Documentation/devicetree/bindings/arm/stm32/stm32.yaml
> > @@ -182,10 +182,12 @@ properties:
> > ?????????? - const: seeed,stm32mp157c-odyssey-som
> > ?????????? - const: st,stm32mp157
> > ?
> > -????? - description: Phytec STM32MP1 SoM based Boards
> > +????? - description: Phytec STM32MP157 SoM based Boards
> > ???????? items:
> > -????????? - const: phytec,phycore-stm32mp1-3
> > -????????? - const: phytec,phycore-stm32mp157c-som
> > +????????? - enum:
> > +????????????? - phytec,phycore-stm32mp1-3 # phyBOARD-Sargas with
> > phyCORE-STM32MP157C SoM
> > +????????? - enum:
> > +????????????? - phytec,phycore-stm32mp157c-som # phyCORE-
> > STM32MP157C SoM
> > ?????????? - const: st,stm32mp157
> > ?
> > ?????? - description: Ultratronik STM32MP1 SBC based Boards
> > -- 
> > 2.34.1
> > 

From maqianga at uniontech.com  Fri Dec 19 01:31:30 2025
From: maqianga at uniontech.com (Qiang Ma)
Date: Fri, 19 Dec 2025 17:31:30 +0800
Subject: [PATCH v2 0/4] kexec: add kexec flag to control debug printing
Message-ID: <20251219093134.2268620-1-maqianga@uniontech.com>

Overview:
=========
The commit cbc2fe9d9cb2 ("kexec_file: add kexec_file flag to control
debug printing") added the kexec_file flag to control debug printing.
However, for arm64, after commit 6f8c1da071a4 ("kexec_file, arm64: print
out debugging message if required"), when using the kexec_load interface,
the kexec_image_info function is called to print debug message, but
it uses kexec_dprintk, which is only available under kexec_file,
then when specifying 'kexec -d', kexec_load interface will print nothing.

For riscv, commit eb7622d908a09 ("kexec_file, riscv: print out debugging
message if required") remove kexec_image_info(), because the content has
been printed out in generic code in kexec_file_load, but not in kexec_load.

Therefore, in order to solve the two problems mentioned above, for this
patchset, several things need to be done:

1. Enabling kexec_dprintk is available for kexec_load.
2. Add some debugging message of the deleted kexec_image_info
   to generic code.
3. Remove duplicate debugging prints for arm64.

Since kexec_load and kexec_file_load are not triggered simultaneously,
we can unify the debug flag of kexec and kexec_file as kexec_dbg_print.

In this way, kexec_dprintk is available for kexec_load and kexec_file_load.

Then when specifying 'kexec -d', the debugging message using kexec_dprintk
in kexec_image_info can be printed normally.

The following are the key points of the specific changes:

1. rename kexec_file_dbg_print to kexec_dbg_print
2. Add KEXEC_DEBUG
3. Initialize kexec_dbg_print for kexec
4. Set the reset of kexec_dbg_print to kimage_free

Testing:
=========
I did testing on x86_64, arm64 and loongarch. On x86_64, the printed
messages look like below:

Unset CONFIG_KEXEC_FILE:
[   36.774228] kexec_file: kernel: 0000000066c386c8 kernel_size: 0xd78400
[   36.821814] kexec-bzImage64: Loaded purgatory at 0x23fffb000
[   36.821826] kexec-bzImage64: Loaded boot_param, command line and misc at 0x23fff9000 bufsz=0x12d0 memsz=0x2000
[   36.821829] kexec-bzImage64: Loaded 64bit kernel at 0x23d400000 bufsz=0xd73400 memsz=0x2ab7000
[   36.821918] kexec-bzImage64: Loaded initrd at 0x23bd0b000 bufsz=0x16f40a8 memsz=0x16f40a8
[   36.821920] kexec-bzImage64: Final command line is: root=/dev/mapper/test-root crashkernel=auto rd.lvm.lv=test/root
[   36.821925] kexec-bzImage64: E820 memmap:
[   36.821926] kexec-bzImage64: 0000000000000000-000000000009ffff (1)
[   36.821928] kexec-bzImage64: 0000000000100000-0000000000811fff (1)
[   36.821930] kexec-bzImage64: 0000000000812000-0000000000812fff (2)
[   36.821931] kexec-bzImage64: 0000000000813000-00000000bee38fff (1)
[   36.821933] kexec-bzImage64: 00000000bee39000-00000000beec2fff (2)
[   36.821934] kexec-bzImage64: 00000000beec3000-00000000bf8ecfff (1)
[   36.821935] kexec-bzImage64: 00000000bf8ed000-00000000bfb6cfff (2)
[   36.821936] kexec-bzImage64: 00000000bfb6d000-00000000bfb7efff (3)
[   36.821937] kexec-bzImage64: 00000000bfb7f000-00000000bfbfefff (4)
[   36.821938] kexec-bzImage64: 00000000bfbff000-00000000bff7bfff (1)
[   36.821939] kexec-bzImage64: 00000000bff7c000-00000000bfffffff (2)
[   36.821940] kexec-bzImage64: 00000000feffc000-00000000feffffff (2)
[   36.821941] kexec-bzImage64: 00000000ffc00000-00000000ffffffff (2)
[   36.821942] kexec-bzImage64: 0000000100000000-000000023fffffff (1)
[   36.872348] kexec_file: nr_segments = 4
[   36.872356] kexec_file: segment[0]: buf=0x000000005314ece7 bufsz=0x4000 mem=0x23fffb000 memsz=0x5000
[   36.872370] kexec_file: segment[1]: buf=0x000000006e59b143 bufsz=0x12d0 mem=0x23fff9000 memsz=0x2000
[   36.872374] kexec_file: segment[2]: buf=0x00000000eb7b1fc3 bufsz=0xd73400 mem=0x23d400000 memsz=0x2ab7000
[   36.882172] kexec_file: segment[3]: buf=0x000000006af76441 bufsz=0x16f40a8 mem=0x23bd0b000 memsz=0x16f5000
[   36.889113] kexec_file: kexec_file_load: type:0, start:0x23fffb150 head:0x101a2e002 flags:0x8

On aarch64, the printed messages look like below:

Set CONFIG_KEXEC_FILE
[   39.033203] kexec_file: kernel: 0000000073414684 kernel_size: 0x3123a00
[   39.047010] kexec_file: Loaded initrd at 0x43cf0000 bufsz=0x17e0e19 memsz=0x17e1000
[   39.047054] kexec_file: Loaded dtb at 0x23ec00000 bufsz=0x386 memsz=0x1000
[   39.047056] kexec_file(Image): Loaded kernel at 0x40000000 bufsz=0x3123a00 memsz=0x3cf0000
[   39.047063] kexec_file: nr_segments = 3
[   39.047064] kexec_file: segment[0]: buf=0x0000000073414684 bufsz=0x3123a00 mem=0x40000000 memsz=0x3cf0000
[   39.073612] kexec_file: segment[1]: buf=0x000000005cd5746b bufsz=0x17e0e19 mem=0x43cf0000 memsz=0x17e1000
[   39.085309] kexec_file: segment[2]: buf=0x0000000084c4a0f1 bufsz=0x386 mem=0x23ec00000 memsz=0x1000
[   39.085459] machine_kexec_post_load:155:
[   39.085463]   kexec kimage info:
[   39.085467]     kern_reloc: 0x00000001620e2000
[   39.085468]     el2_vectors: 0x0000000000000000
[   39.085470] kexec_file: kexec_file_load: type:0, start:0x40000000 head:0x1620e4002 flags:0x8

Unset CONFIG_KEXEC_FILE:

With this patch:
[   35.156088] machine_kexec_post_load:155:
[   35.156097]   kexec kimage info:
[   35.156101]     kern_reloc: 0x000000011c134000
[   35.156102]     el2_vectors: 0x0000000000000000
[   35.156104] kexec: kexec_load: type:0, start:0x454d26b0 head:0x105c14002 flags:0xb70010

Without this patch:
There is no kexec print in dmesg.

Previous posts:
Link: https://lore.kernel.org/all/aTdxEvqY6Bcy7Wa1 at MiWiFi-R3L-srv/

Changes in v2:
==========
- Remove the Reported-by record of patch "kexec: print out debugging
  message if required for kexec_load"
- Move patch "kexec: Replace the goto out_unlock with out" to this patchset

Qiang Ma (4):
  kexec: Replace the goto out_unlock with out
  kexec: add kexec flag to control debug printing
  kexec: print out debugging message if required for kexec_load
  arm64: kexec: Adjust the debug print of kexec_image_info

 arch/arm64/kernel/machine_kexec.c | 2 --
 include/linux/kexec.h             | 9 +++++----
 include/uapi/linux/kexec.h        | 1 +
 kernel/kexec.c                    | 8 +++++++-
 kernel/kexec_core.c               | 4 +++-
 kernel/kexec_file.c               | 4 +---
 6 files changed, 17 insertions(+), 11 deletions(-)

-- 
2.20.1



From maqianga at uniontech.com  Fri Dec 19 01:31:31 2025
From: maqianga at uniontech.com (Qiang Ma)
Date: Fri, 19 Dec 2025 17:31:31 +0800
Subject: [PATCH v2 1/4] kexec: Replace the goto out_unlock with out
In-Reply-To: <20251219093134.2268620-1-maqianga@uniontech.com>
References: <20251219093134.2268620-1-maqianga@uniontech.com>
Message-ID: <20251219093134.2268620-2-maqianga@uniontech.com>

The image is initialized to NULL. Then, after calling kimage_alloc_init,
we can directly goto 'out' because at this time, the kimage_free will
determine whether image is a NULL pointer.

This will prepare for the subsequent patch to reset the variable in
kimage_free.

Signed-off-by: Qiang Ma <maqianga at uniontech.com>
---
 kernel/kexec.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/kernel/kexec.c b/kernel/kexec.c
index 28008e3d462e..9bb1f2b6b268 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -95,6 +95,8 @@ static int do_kexec_load(unsigned long entry, unsigned long nr_segments,
 	unsigned long i;
 	int ret;
 
+	image = NULL;
+
 	/*
 	 * Because we write directly to the reserved memory region when loading
 	 * crash kernels we need a serialization here to prevent multiple crash
@@ -129,7 +131,7 @@ static int do_kexec_load(unsigned long entry, unsigned long nr_segments,
 
 	ret = kimage_alloc_init(&image, entry, nr_segments, segments, flags);
 	if (ret)
-		goto out_unlock;
+		goto out;
 
 	if (flags & KEXEC_PRESERVE_CONTEXT)
 		image->preserve_context = 1;
-- 
2.20.1



From maqianga at uniontech.com  Fri Dec 19 01:31:33 2025
From: maqianga at uniontech.com (Qiang Ma)
Date: Fri, 19 Dec 2025 17:31:33 +0800
Subject: [PATCH v2 3/4] kexec: print out debugging message if required for kexec_load
In-Reply-To: <20251219093134.2268620-1-maqianga@uniontech.com>
References: <20251219093134.2268620-1-maqianga@uniontech.com>
Message-ID: <20251219093134.2268620-4-maqianga@uniontech.com>

The commit a85ee18c7900 ("kexec_file: print out debugging message
if required") has added general code printing in kexec_file_load(),
but not in kexec_load().

As a result, when using '-d' for the kexec_load interface,
print nothing in the kernel space.

Since the segments debugging message has already been printed by the
user-space tool kexec-tools, it will not be printed here in the
kernel space.

And print out type/start/head of kimage and flags to help debug.

Signed-off-by: Qiang Ma <maqianga at uniontech.com>
---
 kernel/kexec.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/kernel/kexec.c b/kernel/kexec.c
index f6c58c767eb0..37e4ac8af9f3 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -166,6 +166,9 @@ static int do_kexec_load(unsigned long entry, unsigned long nr_segments,
 	if (ret)
 		goto out;
 
+	kexec_dprintk("kexec_load: type:%u, start:0x%lx head:0x%lx flags:0x%lx\n",
+		      image->type, image->start, image->head, flags);
+
 	/* Install the new kernel and uninstall the old */
 	image = xchg(dest_image, image);
 
-- 
2.20.1



From maqianga at uniontech.com  Fri Dec 19 01:31:32 2025
From: maqianga at uniontech.com (Qiang Ma)
Date: Fri, 19 Dec 2025 17:31:32 +0800
Subject: [PATCH v2 2/4] kexec: add kexec flag to control debug printing
In-Reply-To: <20251219093134.2268620-1-maqianga@uniontech.com>
References: <20251219093134.2268620-1-maqianga@uniontech.com>
Message-ID: <20251219093134.2268620-3-maqianga@uniontech.com>

The commit cbc2fe9d9cb2 ("kexec_file: add kexec_file flag to control
debug printing") added the kexec_file flag to control debug printing.
However, for arm64, after commit 6f8c1da071a4 ("kexec_file, arm64: print
out debugging message if required"), when using the kexec_load interface,
the kexec_image_info function is called to print debug message, but
it uses kexec_dprintk, which is only available under kexec_file,
then when specifying 'kexec -d', kexec_load interface will print nothing.

For riscv, commit eb7622d908a09 ("kexec_file, riscv: print out debugging
message if required") remove kexec_image_info(), because the content has
been printed out in generic code in kexec_file_load, but not in kexec_load.

Therefore, in order to solve the two problems mentioned above, for this
patchset, several things need to be done:

1. Enabling kexec_dprintk is available for kexec_load.
2. Add some debugging message of the deleted kexec_image_info
   to generic code.
3. Remove duplicate debugging prints for arm64

Since kexec_load and kexec_file_load are not triggered simultaneously,
we can unify the debug flag of kexec and kexec_file as kexec_dbg_print.

In this way, kexec_dprintk is available for kexec_load and kexec_file_load.

The following are the key points of the specific changes:

1. rename kexec_file_dbg_print to kexec_dbg_print
2. Add KEXEC_DEBUG
3. Initialize kexec_dbg_print for kexec
4. Set the reset of kexec_dbg_print to kimage_free

Signed-off-by: Qiang Ma <maqianga at uniontech.com>
---
 include/linux/kexec.h      | 9 +++++----
 include/uapi/linux/kexec.h | 1 +
 kernel/kexec.c             | 1 +
 kernel/kexec_core.c        | 4 +++-
 kernel/kexec_file.c        | 4 +---
 5 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index ff7e231b0485..23f10aec0b34 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -455,10 +455,11 @@ bool kexec_load_permitted(int kexec_image_type);
 
 /* List of defined/legal kexec flags */
 #ifndef CONFIG_KEXEC_JUMP
-#define KEXEC_FLAGS    (KEXEC_ON_CRASH | KEXEC_UPDATE_ELFCOREHDR | KEXEC_CRASH_HOTPLUG_SUPPORT)
+#define KEXEC_FLAGS    (KEXEC_ON_CRASH | KEXEC_UPDATE_ELFCOREHDR | KEXEC_CRASH_HOTPLUG_SUPPORT | \
+			KEXEC_DEBUG)
 #else
 #define KEXEC_FLAGS    (KEXEC_ON_CRASH | KEXEC_PRESERVE_CONTEXT | KEXEC_UPDATE_ELFCOREHDR | \
-			KEXEC_CRASH_HOTPLUG_SUPPORT)
+			KEXEC_CRASH_HOTPLUG_SUPPORT | KEXEC_DEBUG)
 #endif
 
 /* List of defined/legal kexec file flags */
@@ -525,10 +526,10 @@ static inline int arch_kexec_post_alloc_pages(void *vaddr, unsigned int pages, g
 static inline void arch_kexec_pre_free_pages(void *vaddr, unsigned int pages) { }
 #endif
 
-extern bool kexec_file_dbg_print;
+extern bool kexec_dbg_print;
 
 #define kexec_dprintk(fmt, arg...) \
-        do { if (kexec_file_dbg_print) pr_info(fmt, ##arg); } while (0)
+	do { if (kexec_dbg_print) pr_info(fmt, ##arg); } while (0)
 
 extern void *kimage_map_segment(struct kimage *image, unsigned long addr, unsigned long size);
 extern void kimage_unmap_segment(void *buffer);
diff --git a/include/uapi/linux/kexec.h b/include/uapi/linux/kexec.h
index 55749cb0b81d..819c600af125 100644
--- a/include/uapi/linux/kexec.h
+++ b/include/uapi/linux/kexec.h
@@ -14,6 +14,7 @@
 #define KEXEC_PRESERVE_CONTEXT	0x00000002
 #define KEXEC_UPDATE_ELFCOREHDR	0x00000004
 #define KEXEC_CRASH_HOTPLUG_SUPPORT 0x00000008
+#define KEXEC_DEBUG		0x00000010
 #define KEXEC_ARCH_MASK		0xffff0000
 
 /*
diff --git a/kernel/kexec.c b/kernel/kexec.c
index 9bb1f2b6b268..f6c58c767eb0 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -42,6 +42,7 @@ static int kimage_alloc_init(struct kimage **rimage, unsigned long entry,
 	if (!image)
 		return -ENOMEM;
 
+	kexec_dbg_print = !!(flags & KEXEC_DEBUG);
 	image->start = entry;
 	image->nr_segments = nr_segments;
 	memcpy(image->segment, segments, nr_segments * sizeof(*segments));
diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index 0f92acdd354d..d7c2a2b79214 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -55,7 +55,7 @@ atomic_t __kexec_lock = ATOMIC_INIT(0);
 /* Flag to indicate we are going to kexec a new kernel */
 bool kexec_in_progress = false;
 
-bool kexec_file_dbg_print;
+bool kexec_dbg_print;
 
 /*
  * When kexec transitions to the new kernel there is a one-to-one
@@ -578,6 +578,8 @@ void kimage_free(struct kimage *image)
 	kimage_entry_t *ptr, entry;
 	kimage_entry_t ind = 0;
 
+	kexec_dbg_print = false;
+
 	if (!image)
 		return;
 
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index eb62a9794242..3f1d6c4e8ff2 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -138,8 +138,6 @@ void kimage_file_post_load_cleanup(struct kimage *image)
 	 */
 	kfree(image->image_loader_data);
 	image->image_loader_data = NULL;
-
-	kexec_file_dbg_print = false;
 }
 
 #ifdef CONFIG_KEXEC_SIG
@@ -314,7 +312,7 @@ kimage_file_alloc_init(struct kimage **rimage, int kernel_fd,
 	if (!image)
 		return -ENOMEM;
 
-	kexec_file_dbg_print = !!(flags & KEXEC_FILE_DEBUG);
+	kexec_dbg_print = !!(flags & KEXEC_FILE_DEBUG);
 	image->file_mode = 1;
 
 #ifdef CONFIG_CRASH_DUMP
-- 
2.20.1



From maqianga at uniontech.com  Fri Dec 19 01:31:34 2025
From: maqianga at uniontech.com (Qiang Ma)
Date: Fri, 19 Dec 2025 17:31:34 +0800
Subject: [PATCH v2 4/4] arm64: kexec: Adjust the debug print of kexec_image_info
In-Reply-To: <20251219093134.2268620-1-maqianga@uniontech.com>
References: <20251219093134.2268620-1-maqianga@uniontech.com>
Message-ID: <20251219093134.2268620-5-maqianga@uniontech.com>

In the previous patch, we move start/head of kimage to the
generic code, so, we remove them to avoid duplicate printing.

Signed-off-by: Qiang Ma <maqianga at uniontech.com>
---
 arch/arm64/kernel/machine_kexec.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c
index 239c16e3d02f..0896e3e6a811 100644
--- a/arch/arm64/kernel/machine_kexec.c
+++ b/arch/arm64/kernel/machine_kexec.c
@@ -34,8 +34,6 @@ static void _kexec_image_info(const char *func, int line,
 {
 	kexec_dprintk("%s:%d:\n", func, line);
 	kexec_dprintk("  kexec kimage info:\n");
-	kexec_dprintk("    type:        %d\n", kimage->type);
-	kexec_dprintk("    head:        %lx\n", kimage->head);
 	kexec_dprintk("    kern_reloc: %pa\n", &kimage->arch.kern_reloc);
 	kexec_dprintk("    el2_vectors: %pa\n", &kimage->arch.el2_vectors);
 }
-- 
2.20.1



From daniel.baluta at gmail.com  Fri Dec 19 01:34:56 2025
From: daniel.baluta at gmail.com (Daniel Baluta)
Date: Fri, 19 Dec 2025 11:34:56 +0200
Subject: [PATCH] phy: fsl-imx8mq-usb: add debugfs to access control register
In-Reply-To: <20251219075447.3672833-1-xu.yang_2@nxp.com>
References: <20251219075447.3672833-1-xu.yang_2@nxp.com>
Message-ID: <CAEnQRZCZJnkXCM2ACf3dXQ-ZynRB1q2zcarWLAZO_1TsL-1GcA@mail.gmail.com>

On Fri, Dec 19, 2025 at 9:56?AM Xu Yang <xu.yang_2 at nxp.com> wrote:
>
> The CR port is a simple 16-bit data/address parallel port that is
> provided for on-chip access to the control registers inside the
> USB 3.0 femtoPHY. While access to these registers is not required
> for normal PHY operation, this interface enables you to access
> some of the PHY?s diagnostic features during normal operation or
> to override some basic PHY control signals.
>
> 3 debugfs files are created to read and write control registers,
> all use hexadecimal format:
> ctrl_reg_base: the register offset to write, or the start offset
>                to read.
> ctrl_reg_count: how many continuous registers to be read.
> ctrl_reg_value: read to show the continuous registers value from
>                 the offset in ctrl_reg_base, to ctrl_reg_base
>                 + ctrl_reg_count - 1, one line for one register.
>                 when write, override the register at ctrl_reg_base,
>                 one time can only change one 16bits register.
>
> Signed-off-by: Li Jun <jun.li at nxp.com>
> Signed-off-by: Xu Yang <xu.yang_2 at nxp.com>
> ---
>  drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 221 ++++++++++++++++++++-
>  1 file changed, 220 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> index ad8a55012e42..cb2392008ad2 100644
> --- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> +++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> @@ -1,8 +1,9 @@
>  // SPDX-License-Identifier: GPL-2.0+
> -/* Copyright (c) 2017 NXP. */
> +/* Copyright (c) 2017-2025 NXP. */

While you are at it can you remove the (c). New policy
from NXP is to use directly:

Copyright 2017-2025 NXP.

thanks,
Daniel.


From leo.yan at arm.com  Fri Dec 19 01:41:41 2025
From: leo.yan at arm.com (Leo Yan)
Date: Fri, 19 Dec 2025 09:41:41 +0000
Subject: [PATCH v2 RESEND] coresight: etm-perf: Fix reference count leak
 in etm_setup_aux
In-Reply-To: <20251219023949.12699-1-make24@iscas.ac.cn>
References: <f85c7d37-4980-46f0-9136-353a35a8f0ed@oss.qualcomm.com>
 <20251219023949.12699-1-make24@iscas.ac.cn>
Message-ID: <20251219094141.GA9788@e132581.arm.com>

Hi,

On Fri, Dec 19, 2025 at 10:39:49AM +0800, Ma Ke wrote:

[...]

> From the discussion, I note two possible fix directions:
> 
> 1. Release the initial reference in etm_setup_aux() (current v2 patch)
> 2. Modify the behavior of coresight_get_sink_by_id() itself so it 
> doesn't increase the reference count. 

The option 2 is the right way to go.

> To ensure the correctness of the v3 patch, I'd like to confirm which 
> patch is preferred. If option 2 is the consensus, I'm happy to modify 
> the implementation of coresight_get_sink_by_id() as suggested.

It is good to use a separate patch to fix
coresight_find_device_by_fwnode() mentioned by James:

diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c
index 0db64c5f4995..2b34f818ba88 100644
--- a/drivers/hwtracing/coresight/coresight-platform.c
+++ b/drivers/hwtracing/coresight/coresight-platform.c
@@ -107,14 +107,16 @@ coresight_find_device_by_fwnode(struct fwnode_handle *fwnode)
 	 * platform bus.
 	 */
 	dev = bus_find_device_by_fwnode(&platform_bus_type, fwnode);
-	if (dev)
-		return dev;
 
 	/*
 	 * We have a configurable component - circle through the AMBA bus
 	 * looking for the device that matches the endpoint node.
 	 */
-	return bus_find_device_by_fwnode(&amba_bustype, fwnode);
+	if (!dev)
+		dev = bus_find_device_by_fwnode(&amba_bustype, fwnode);
+
+	put_device(dev);
+	return dev;
 }
 
 /*
@@ -274,7 +276,6 @@ static int of_coresight_parse_endpoint(struct device *dev,
 
 	of_node_put(rparent);
 	of_node_put(rep);
-	put_device(rdev);
 
 	return ret;
 }

Thanks for working on this.


From m.felsch at pengutronix.de  Fri Dec 19 01:50:46 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Fri, 19 Dec 2025 10:50:46 +0100
Subject: [PATCH v7 1/3] dt-bindings: soc: imx93-media-blk-ctrl: Add PDFC
 subnode to schema and example
In-Reply-To: <7637686.lOV4Wx5bFT@steina-w>
References: <20251202-v6-18-topic-imx93-parallel-display-v7-0-2cce31d64608@pengutronix.de>
 <3210190.mvXUDI8C0e@steina-w>
 <20251218190841.pmn3kwghq6lxsfl4@pengutronix.de>
 <7637686.lOV4Wx5bFT@steina-w>
Message-ID: <20251219095046.dgtaknhnvzjfw6ch@pengutronix.de>

On 25-12-19, Alexander Stein wrote:
> Hi Marco,
> 
> Am Donnerstag, 18. Dezember 2025, 20:08:41 CET schrieb Marco Felsch:
> > Hi Alexander,
> > 
> > On 25-12-16, Alexander Stein wrote:
> > > Hi,
> > > 
> > > Am Montag, 15. Dezember 2025, 18:54:36 CET schrieb Marco Felsch:
> > > > Hi Liu,
> > > > 
> > > > sorry I didn't fully answer you please see below.
> > > > 
> > > > On 25-12-08, Liu Ying wrote:
> > > > > Hi Marco,
> > > > > 
> > > > > On 12/02/2025, Marco Felsch wrote:
> > > > > > From: Liu Ying <victor.liu at nxp.com>
> > > > > > 
> > > > > > i.MX93 SoC mediamix blk-ctrl contains one DISPLAY_MUX register which
> > > > > > configures parallel display format by using the "PARALLEL_DISP_FORMAT"
> > > > > > field. Document the Parallel Display Format Configuration(PDFC) subnode
> > > > > > and add the subnode to example.
> > > > > > 
> > > > > > Signed-off-by: Liu Ying <victor.liu at nxp.com>
> > > > > > [m.felsch at pengutronix.de: port to v6.18-rc1]
> > > > > > [m.felsch at pengutronix.de: add bus-width]
> > > > > > Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
> > > > > > ---
> > > > > >  .../bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml | 92 ++++++++++++++++++++++
> > > > > >  1 file changed, 92 insertions(+)
> > > > > > 
> > > > > > diff --git a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> > > > > > index 34aea58094e55365a2f9c86092f637e533f954ff..6e2d86d9341c75108b492bcbabc8a560d8e707cd 100644
> > > > > > --- a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> > > > > > +++ b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> > > > > > @@ -26,6 +26,12 @@ properties:
> > > > > >    reg:
> > > > > >      maxItems: 1
> > > > 
> > > > ...
> > > > 
> > > > > > +            properties:
> > > > > > +              endpoint:
> > > > > > +                $ref: /schemas/graph.yaml#/$defs/endpoint-base
> > > > > > +                unevaluatedProperties: false
> > > > > > +
> > > > > > +                properties:
> > > > > > +                  bus-width:
> > > > > 
> > > > > In v1-v5, I thought the output bus format can be determined by the sink
> > > > > device(a panel or a bridge) hence properties like bus-width were not needed.
> > > > > But, if this property is really needed, then reference video-interfaces.yaml
> > > > > since bus-width is documented there.  Should we reference bus-type defined
> > > > > in video-interfaces.yaml too?
> > > > 
> > > > You're right, the bus-width should be determined by the connected panel.
> > > > But there are cases where a 24-bit panel is connected but only the lower
> > > > 18-bits are muxed. I added the bus-width property to handle this case.
> > > > In the end most users don't have to specify this since the correct
> > > > bus-width is coming from the panel bus-fmt.
> > > > 
> > > > > > +                    enum: [ 16, 18, 24 ]
> > > > > 
> > > > > The PARALLEL_DISP_FORMAT field of DISPLAY_MUX register says this IP supports
> > > > > below formats.  It seems that the enum here may tell RGB888, RGB666 and RGB565.
> > > > > How can we tell RGB555, YCbCr 24 bits and YUV444 then?
> > > > > 
> > > > > 000b RGB888 -> RGB888
> > > > > 001b RGB888 -> RGB666
> > > > > 010b RGB565 -> RGB565
> > > > > 011b RGB555 -> RGB555
> > > > > 100b YUV -> YCbCr 24 bits
> > > > > 101b YUV -> YUV444
> > > > 
> > > > This enum is about the physical bus width. RGB565 == 16-bit, YUV ==
> > > > 24-bit.
> > > > 
> > > > That said, I don't think that you need to specify the bus-fmt since this
> > > > is coming from the panel. As said above, my itension with the bus-width
> > > > property is to provide integrators (dts-writers) a possibility to limit
> > > > the physical available bus width.
> > > 
> > > Mh, isn't [1] exactly about this? Not sure about the outcome at that time.
> > 
> > Thanks for the pointer, I wasn't aware of this discussion. I skimmed
> > through the dt-bindings thread and I agree with Rob and Maxime.
> > 
> > We do have the bus-width endpoint property already. This property is
> > alredy used by media and drm bridge drivers. Why not making use of for
> > this simple bridge driver too?
> > 
> > Furthermore I doubt, that a simple drm-bridge MEDIA_BUS_FMT_* convert
> > driver solves all the problem in a generic way for all platforms, all
> > connectors, all routing options.
> 
> Nobody knows what new hardware comes up with ?\_ (?)_/?
> Anyway we already have a similar problem on our MBa6ULx mainboard.
> Current downstream workaround is to clone the display timings but
> change the bus format. See [1]. Although I would like to get rid of it.
> This is just the display connector on the mainboard causing the shift.

I had something similiar in mind as a quick and dirty hack. However, I
think that the same abbroach used here for the PDFC bridge could be used
for the panel endpoint node to enforce a specific bus width. Another
solution could be to add the bus-fmt support to the panel of desciption,
so you can describe your panel within the OF.

Regards,
  Marco


> Best regards
> Alexander
> 
> [1] https://github.com/tq-systems/linux-tqmaxx/commit/777c02480182d3054264aaaf80e1dbc40a02cfc1
> 
> > If the i.MX93 NXP-EVKs in [1] would have connected the upper LCD_DAT*
> > pads instead of the lower ones, there would be no conversion needed by
> > the PDFC bridge driver, albeit the physical bus is cut to 18-bit width
> > due to the RPi ext. header limit, which is expanded to 24-bit again later on
> > via the Adafruit board panel FPC connector.
> > 
> > In such scenario the output width of the PDFC has to be 24-bit else
> > you would lose not only the two LSBs but also the two MSBs for each
> > channel. I tried to visualize what I meant for the blue channel:
> > 
> >                  24-bit PDFC bridge
> > 		 ------------------
> >         +----+----+----+----+----+----+----+----+
> >  LCDIF  | B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 |
> >         +----+----+----+----+----+----+----+----+
> >           |    |    |    |    |    |    |    |
> >         +----+----+----+----+----+----+----+----+
> >  PDFC   | B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 |
> >         +----+----+----+----+----+----+----+----+
> >                     |    |    |    |    |    |
> >         +----+----+----+----+----+----+----+----+
> > SOC_PAD | xx | xx | D2 | D3 | D4 | D5 | D6 | D7 |
> >         +----+----+----+----+----+----+----+----+
> >                     |    |    |    |    |    |
> >         +----+----+----+----+----+----+----+----+
> >  ext.   | xx | xx | B2 | B3 | B4 | B5 | B6 | B7 |
> >  HDR    +----+----+----+----+----+----+----+----+
> >                     |    |    |    |    |    |
> >                     |    |    |    |    |    |
> >                     |    |    |    |    |    |
> >           +-----------------------------+    |
> >           |    +-----------------------------+
> >           |    |    |    |    |    |    |    |
> >         +----+----+----+----+----+----+----+----+
> >  Ada.   | B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 |
> >  FPC    +----+----+----+----+----+----+----+----+
> > 
> >                  18-bit PDFC bridge
> > 		 ------------------
> >         +----+----+----+----+----+----+----+----+
> >  LCDIF  | B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 |
> >         +----+----+----+----+----+----+----+----+
> >           |    |    |    |    |    |    |    |
> >         +----+----+----+----+----+----+----+----+
> >  PDFC   | B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 |
> >         +----+----+----+----+----+----+----+----+
> >                     |    |    |    |    |    |
> >           +---------+    |    |    |    |    |
> >           |    +---------+    |    |    |    |
> >           |    |    +---------+    |    |    |
> >           |    |    |    +---------+    |    |
> >           |    |    |    |    +---------+    |
> >           |    |    |    |    |    +---------+
> >           |    |    |    |    |    |
> >         +----+----+----+----+----+----+----+----+
> > SOC_PAD | xx | xx | D2 | D3 | D4 | D5 | D6 | D7 |
> >         +----+----+----+----+----+----+----+----+
> >                     |    |    |    |    |    |
> >         +----+----+----+----+----+----+----+----+
> >  ext.   | xx | xx | B2 | B3 | B4 | B5 | B6 | B7 |
> >  HDR    +----+----+----+----+----+----+----+----+
> >                     |    |    |    |    |    |
> >                     |    |    |    |    |    |
> >                     |    |    |    |    |    |
> >           +-----------------------------+    |
> >           |    +-----------------------------+
> >           |    |    |    |    |    |    |    |
> >         +----+----+----+----+----+----+----+----+
> >  Ada.   | B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 |
> >  FPC    +----+----+----+----+----+----+----+----+
> > 
> > 
> > The mapping can get quite difficult for a single SoC already, just by
> > using a slighlty different HW routing (the upper D[ata] pads).
> > 
> > Therefore I would keep it simple and device/ip specific (in this case
> > PDFC specific) by making use of the bus-width. Specifying the bus-width
> > property could be also wrong albeit it's the case physically, as you can
> > see in my above example.
> > 
> > Therefore the bus-width property must have a good description.
> > 
> > Regards,
> >   Marco
> > 
> > > Best regards,
> > > Alexander
> > > 
> > > [1] https://lore.kernel.org/all/20250304101530.969920-1-victor.liu at nxp.com/
> > > 
> > > > [snip]
> > 
> > 
> > 
> > 
> 
> 
> -- 
> TQ-Systems GmbH | M?hlstra?e 2, Gut Delling | 82229 Seefeld, Germany
> Amtsgericht M?nchen, HRB 105018
> Gesch?ftsf?hrer: Detlef Schneider, R?diger Stahl, Stefan Schneider
> http://www.tq-group.com/
> 
> 
> 

-- 
#gernperDu 
#CallMeByMyFirstName

Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | https://www.pengutronix.de/ |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-9    |


From krzk at kernel.org  Fri Dec 19 01:53:23 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 10:53:23 +0100
Subject: [PATCH 10/12] dt-bindings: ras: document estatus provider
In-Reply-To: <20251218103139.2238844-1-ahmed.tiba@arm.com>
References: <2a2baef6-c294-4c31-bec2-10fbaa3f7941@kernel.org>
 <20251218103139.2238844-1-ahmed.tiba@arm.com>
Message-ID: <57772b40-e4d9-4152-9709-04ba897608d0@kernel.org>

On 18/12/2025 11:31, Ahmed Tiba wrote:
> On 17/12/2025 12:41, Krzysztof Kozlowski wrote:
>>> +properties:
>>> +  compatible:
>>> +    const: arm,ras-ffh
>>
>> Again ras - what's that? Your patch or binding must explain that.
> 
> That updated description will explicitly expand the Arm RAS acronym so the
> compatible string is self-explanatory.
> 
>>> +
>>> +  reg:
>>> +    minItems: 1
>>
>> Why is this flexible?
> 
> I'll keep `reg` describing the CPER status buffer, cap it at two entries, and
> document the second entry as the optional doorbell register that some firmware
> requires before reusing the buffer.

I still do not understand why this is flexible or in other words - why
second address space appears and disappears.

> 
>>> +    items:
>>> +      - description: CPER status block exposed by firmware
>>> +      - description:
>>> +          Optional 32- or 64-bit acknowledgment register. Firmware watches this
>>> +          register and expects bit 0 to be written to 1 once the OS consumes the
>>> +          status buffer so it can reuse the record.
>>> +


Best regards,
Krzysztof


From suzuki.poulose at arm.com  Fri Dec 19 01:54:14 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Fri, 19 Dec 2025 09:54:14 +0000
Subject: [PATCH v8 5/8] dt-bindings: arm: add an interrupt property for
 Coresight CTCU
In-Reply-To: <46afd4f6-f287-4d19-bc68-f2f6eac36e6a@oss.qualcomm.com>
References: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
 <20251211-enable-byte-cntr-for-ctcu-v8-5-3e12ff313191@oss.qualcomm.com>
 <20251211133723.GA859302-robh@kernel.org>
 <dfa43a63-ca14-4dd7-a7ab-acd95748a8b9@oss.qualcomm.com>
 <a9537dc9-c767-4909-8b1c-6e939ce4f3fc@kernel.org>
 <2db74a3e-4aeb-4e87-9fe8-5c9693bfb67c@arm.com>
 <46afd4f6-f287-4d19-bc68-f2f6eac36e6a@oss.qualcomm.com>
Message-ID: <95ac571a-1c8f-45d9-9874-648d4123ce18@arm.com>

On 19/12/2025 02:05, Jie Gan wrote:
> 
> 
> On 12/19/2025 7:19 AM, Suzuki K Poulose wrote:
>> On 18/12/2025 10:17, Krzysztof Kozlowski wrote:
>>> On 12/12/2025 02:12, Jie Gan wrote:
>>>>
>>>>
>>>> On 12/11/2025 9:37 PM, Rob Herring wrote:
>>>>> On Thu, Dec 11, 2025 at 02:10:44PM +0800, Jie Gan wrote:
>>>>>> Add an interrupt property to CTCU device. The interrupt will be 
>>>>>> triggered
>>>>>> when the data size in the ETR buffer exceeds the threshold of the
>>>>>> BYTECNTRVAL register. Programming a threshold in the BYTECNTRVAL 
>>>>>> register
>>>>>> of CTCU device will enable the interrupt.
>>>>>>
>>>>>> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
>>>>>> Reviewed-by: Mike Leach <mike.leach at linaro.org>
>>>>>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>>>>>> ---
>>>>>> ?? .../devicetree/bindings/arm/qcom,coresight-ctcu.yaml??? | 17 ++ 
>>>>>> + ++++++++++++++
>>>>>> ?? 1 file changed, 17 insertions(+)
>>>>>>
>>>>>> diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight- 
>>>>>> ctcu.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight- 
>>>>>> ctcu.yaml
>>>>>> index c969c16c21ef..90f88cc6cd3e 100644
>>>>>> --- a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
>>>>>> +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
>>>>>> @@ -39,6 +39,16 @@ properties:
>>>>>> ?????? items:
>>>>>> ???????? - const: apb
>>>>>> +? interrupts:
>>>>>> +??? items:
>>>>>> +????? - description: Byte cntr interrupt for the first etr device
>>>>>> +????? - description: Byte cntr interrupt for the second etr device
>>
>> This is really vague. How do you define first vs second ? Probe order ?
>> No way. This must be the "port" number to which the ETR is connected
>> to the CTCU. IIUC, there is a config area for each ETR (e.g., trace id
>> filter) connected to the CTCU. I was under the assumption that they
>> are identified as "ports" (input ports). I don't really understand how
>> this interrupt mapping works now. Please explain it clearly.
>>
> 
> Sorry for the misunderstanding.
> 
> Each ETR device should have its own interrupt line and an IRQ register 
> within the CTCU device, as defined by the specification. In existing 
> projects, the maximum supported number of ETR devices is 2.
> 
> Each interrupt is directly mapped to a specific ETR device, for example:
> tmc at 1000 ? interrupt line 0
> tmc at 1001 ? interrupt line 1
> 
> The suggestion to identify devices by ?ports? is much clearer than my 
> previous explanation, as it explicitly shows which device is connected 
> to which port.

Thanks for confirming.

> 
>>>>>> +
>>>>>> +? interrupt-names:
>>>>>> +??? items:
>>>>>> +????? - const: etrirq0
>>>>>> +????? - const: etrirq1
>>>>>
>>>>> Names are kind of pointless when it is just foo<index>.
>>>>
>>>> Hi Rob,
>>>>
>>>> I was naming them as etr0/etr1. Are these names acceptable?
>>>
>>> Obviously irq is redundant, but how does etr0 solves the problem of
>>> calling it foo0?
>>>
>>> I don't think you really read Rob's comment.
>>>
>>>> The interrupts are assigned exclusively to a specific ETR device.
>>>>
>>>> But Suzuki is concerned that this might cause confusion because the ETR
>>>> device is named randomly in the driver. Suzuki suggested using ?port-0?
>>>> and ?port-1? and would also like to hear your feedback on these names.
>>>
>>> There is no confusion here. Writing bindings luckily clarifies this what
>>> the indices in the array mean.
>>
>> The point is there are "n" interrupts. Question is, could there be more
>> devices(ETRs) connected to the CTCU than "n".
>>
>> e.g., Lets CTCU can control upto 4 ETRs and on a particular system, the
>>
>> TMC-ETR0 -> CTCU-Port0
>>
>> TMC-ETR1 -> CTCU-Port2
>> TMC-ETR2 -> CTCU-Port3
>>
>> Now, how many interrupts are described in the DT ? How do we map which
>> interrupts correspond to the CTCU-Portn. (Finding the TMC-ETRx back
>> from the port is possible, with the topology).
>>
> 
> Got your point and it's much clearer.
> 
>> This is what I raised in the previous version. Again, happy to hear
>> if there is a standard way to describe the interrupts.
>>
>> Suzuki
>>
>>
>>>
>>>>
>>>> Usually, the probe sequence follows the order of the addresses. In our
>>>> specification, ?ETR0? is always probed before ?ETR1? because its 
>>>> address
>>>> is lower.
>>>
>>> How is this even relevant? You are answering to something completely
>>> different, so I don't think you really tried to understand review.
>>>
> 
> My previous explanation was definitely unclear. As Suzuki suggested, 
> mapping the interrupt to the port number (to identify the relevant 
> device based on topology) makes sense and provides a much easier way to 
> understand the relationship between the interrupt and the ETR device.
> 
> So with the suggestion, here is the new description about the interrupts:
> 
>  ? interrupts:
>  ??? items:
>  ????? - description: Interrupt for the ETR device connected to in-port0.
>  ????? - description: Interrupt for the ETR device connected to in-port1.
> 
>  ?interrupt-names:
>  ??? items:
>  ???? - const: port0
>  ???? - const: port1

Which brings us back to the question I posted in the previous version. 
Do we really need a "name" or are there other ways to define, a sparse
list of interrupts ?

Suzuki


> 
> Thanks,
> Jie
> 
>>>
>>>
>>> Best regards,
>>> Krzysztof
>>
> 



From gary.yang at cixtech.com  Fri Dec 19 01:54:09 2025
From: gary.yang at cixtech.com (Gary Yang)
Date: Fri, 19 Dec 2025 17:54:09 +0800
Subject: [PATCH v1 2/2] arm64: dts: cix: Add OrangePi 6 Plus board support
In-Reply-To: <20251219095409.1395587-1-gary.yang@cixtech.com>
References: <20251219095409.1395587-1-gary.yang@cixtech.com>
Message-ID: <20251219095409.1395587-3-gary.yang@cixtech.com>

OrangePi 6 Plus adopts CIX CD8180/CD8160 SoC,
built-in 12-core 64-bit processor + NPU processor,
integrated graphics processor, equipped with 16GB/32GB/64GB
LPDDR5, and provides two M.2 KEY-M interfaces 2280 for NVMe SSD,
as well as SPI FLASH and TF slots to meet the needs of fast
read/write and high-capacity storage;

Signed-off-by: Gary Yang <gary.yang at cixtech.com>
---
 arch/arm64/boot/dts/cix/Makefile     |  1 +
 arch/arm64/boot/dts/cix/sky1-xcp.dts | 83 ++++++++++++++++++++++++++++
 2 files changed, 84 insertions(+)
 create mode 100644 arch/arm64/boot/dts/cix/sky1-xcp.dts

diff --git a/arch/arm64/boot/dts/cix/Makefile b/arch/arm64/boot/dts/cix/Makefile
index ed3713982012..8a6c6fdc4ec0 100644
--- a/arch/arm64/boot/dts/cix/Makefile
+++ b/arch/arm64/boot/dts/cix/Makefile
@@ -1,2 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0
 dtb-$(CONFIG_ARCH_CIX) += sky1-orion-o6.dtb
+dtb-$(CONFIG_ARCH_CIX) += sky1-xcp.dtb
diff --git a/arch/arm64/boot/dts/cix/sky1-xcp.dts b/arch/arm64/boot/dts/cix/sky1-xcp.dts
new file mode 100644
index 000000000000..4350fbd6e780
--- /dev/null
+++ b/arch/arm64/boot/dts/cix/sky1-xcp.dts
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright 2025 Cix Technology Group Co., Ltd.
+ *
+ */
+
+/dts-v1/;
+
+#include "sky1.dtsi"
+#include "sky1-pinfunc.h"
+
+/ {
+	model = "OrangePi 6 Plus";
+	compatible = "OrangePi,6p", "cix,sky1";
+
+	aliases {
+		serial2 = &uart2;
+	};
+
+	chosen {
+		stdout-path = &uart2;
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		linux,cma {
+			compatible = "shared-dma-pool";
+			reusable;
+			size = <0x0 0x28000000>;
+			linux,cma-default;
+		};
+	};
+
+};
+
+&iomuxc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_hog>;
+
+	pinctrl_hog: hog-cfg {
+		pins {
+			pinmux = <CIX_PAD_GPIO144_FUNC_GPIO144>,
+				<CIX_PAD_GPIO145_FUNC_GPIO145>,
+				<CIX_PAD_GPIO146_FUNC_GPIO146>,
+				<CIX_PAD_GPIO147_FUNC_GPIO147>;
+			bias-pull-down;
+			drive-strength = <8>;
+		};
+	};
+};
+
+&iomuxc_s5 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_hog_s5>;
+
+	pinctrl_hog_s5: hog-s5-cfg {
+		pins {
+			pinmux = <CIX_PAD_GPIO014_FUNC_GPIO014>;
+			bias-pull-up;
+			drive-strength = <8>;
+
+		};
+	};
+};
+
+&pcie_x8_rc {
+	status = "okay";
+};
+
+&pcie_x2_rc {
+	status = "okay";
+};
+
+&pcie_x1_1_rc {
+	status = "okay";
+};
+
+&uart2 {
+	status = "okay";
+};
-- 
2.49.0



From gary.yang at cixtech.com  Fri Dec 19 01:54:08 2025
From: gary.yang at cixtech.com (Gary Yang)
Date: Fri, 19 Dec 2025 17:54:08 +0800
Subject: [PATCH v1 1/2] dt-bindings: arm: cix: add OrangePi 6 Plus board
In-Reply-To: <20251219095409.1395587-1-gary.yang@cixtech.com>
References: <20251219095409.1395587-1-gary.yang@cixtech.com>
Message-ID: <20251219095409.1395587-2-gary.yang@cixtech.com>

OrangePi 6 Plus adopts CIX CD8180/CD8160 SoC,
built-in 12-core 64-bit processor + NPU processor,
integrated graphics processor, equipped with 16GB/32GB/64GB
LPDDR5, and provides two M.2 KEY-M interfaces 2280 for NVMe SSD,
as well as SPI FLASH and TF slots to meet the needs of fast
read/write and high-capacity storage;

Signed-off-by: Gary Yang <gary.yang at cixtech.com>
---
 Documentation/devicetree/bindings/arm/cix.yaml | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/cix.yaml b/Documentation/devicetree/bindings/arm/cix.yaml
index 114dab4bc4d2..92fb4ad7b5d8 100644
--- a/Documentation/devicetree/bindings/arm/cix.yaml
+++ b/Documentation/devicetree/bindings/arm/cix.yaml
@@ -21,6 +21,11 @@ properties:
           - const: radxa,orion-o6
           - const: cix,sky1
 
+      - description: OrangePi 6 Plus
+        items:
+          - const: OrangePi,6p
+          - const: cix,sky1
+
 additionalProperties: true
 
 ...
-- 
2.49.0



From gary.yang at cixtech.com  Fri Dec 19 01:54:07 2025
From: gary.yang at cixtech.com (Gary Yang)
Date: Fri, 19 Dec 2025 17:54:07 +0800
Subject: [PATCH v1 0/2] Add OrangePi 6 Plus board
Message-ID: <20251219095409.1395587-1-gary.yang@cixtech.com>

Patch 1: add compatible strings for OrangePi 6 Plus board
Patch 2: add dts file for OrangePi 6 Plus board

OrangePi 6 Plus board is powered by Cix Sky1. You could find brief
introduction for SoC and related boards at:
http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/details/Orange-Pi-6-Plus.html

Currently, to run upstream kernel at OrangePi 6 Plus board, you need to
use BIOS released by OrangePi, and add "clk_ignore_unused=1" at bootargs.
http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/service-and-support/Orange-Pi-6-Plus.html

Gary Yang (2):
  dt-bindings: arm: cix: add OrangePi 6 Plus board
  arm64: dts: cix: Add OrangePi 6 Plus board support

 .../devicetree/bindings/arm/cix.yaml          |  5 ++
 arch/arm64/boot/dts/cix/Makefile              |  1 +
 arch/arm64/boot/dts/cix/sky1-xcp.dts          | 83 +++++++++++++++++++
 3 files changed, 89 insertions(+)
 create mode 100644 arch/arm64/boot/dts/cix/sky1-xcp.dts

-- 
2.49.0



From mripard at kernel.org  Fri Dec 19 01:54:53 2025
From: mripard at kernel.org (Maxime Ripard)
Date: Fri, 19 Dec 2025 10:54:53 +0100
Subject: [PATCH v3 00/11] drm/connector: hdmi: limit infoframes per
 driver capabilities
In-Reply-To: <5dyhjur3hkhvtlwrl4h2m342byor7f3ssvkunj4cggnhbhlmnb@l2mfz7ypjj37>
References: <20250929-gregarious-worm-of-memory-c5354d@houat>
 <itgffxygopi7etkt7xhvmyuvyl5ad3k43nsxvjzw3ubtwiikn7@ocugfdaigtu7>
 <20251003-uptight-echidna-of-stamina-815305@houat>
 <zpygq4kapil3swsmhhqkdwny4ry2dznnzixsw5rkza5p2kqnvp@abvf2vxlbwif>
 <2a5fitdzr2bz235fj6rvqzxr6ckszkjbazjfszlvnizdh2cvbt@w3ypjo7vahhs>
 <pibxhl5hlcpuk3zsgyienfdlda5cwuxrnofwlw356scuzzplqy@zw3ofelgvwik>
 <bsoqyzxi45i67jpzhwr2d4illufa5ghqf25z6flbp67lsbvh22@rrlcihp2oxea>
 <cgzclxjubj5oca3rdnv44qwrkmpddxve4tlz76cc6p3b4hz3oc@3l7mt5ha7do6>
 <20251201-enlightened-zebu-from-asgard-5a20be@houat>
 <5dyhjur3hkhvtlwrl4h2m342byor7f3ssvkunj4cggnhbhlmnb@l2mfz7ypjj37>
Message-ID: <20251219-honest-slim-crab-02e932@houat>

On Sat, Dec 06, 2025 at 01:28:14PM +0200, Dmitry Baryshkov wrote:
> On Mon, Dec 01, 2025 at 06:01:56PM +0100, Maxime Ripard wrote:
> > On Fri, Nov 21, 2025 at 07:09:01PM +0200, Dmitry Baryshkov wrote:
> > > > So it's not really impossible, you just need some hardware and a day's
> > > > worth of work.
> > > > 
> > > > There's no reason these should get a pass, it's breaking the spec for no
> > > > reason.
> > > > 
> > > > > > For SPD, It's really not clear to me why atomic_check should do that in
> > > > > > the first place. Your initial concern was about exposing infoframes in
> > > > > > debugfs that wouldn't be used by the driver.
> > > > > > 
> > > > > > If the driver doesn't register a debugfs file for SPD, and ignores
> > > > > > whatever is in the atomic state, what's should we force drivers to do
> > > > > > that?
> > > > > 
> > > > > I really don't think that drivers should mess up with debugfs on their
> > > > > own. Making atomic_check() disable the unsupported InfoFrames makes the
> > > > > picture perfect: the DRM no longer tries to program them to the
> > > > > hardware, DebugFS files stay empty, so the whole state becomes
> > > > > consistent.
> > > > 
> > > > In the "bridge has no access to infoframes" case, there's really no
> > > > infoframe. An empty file is "the infoframe can be there but isn't used",
> > > > not "we don't have access to it and can't report them". Only drivers
> > > > have those infos.
> > > > 
> > > > If we do split up write_infoframe into multiple functions though, I
> > > > guess we could create the debugfs file only if the function pointer is
> > > > set, which removes drivers' involvement if you don't like that.
> > > 
> > > I'm fine with not using HDMI connector framework for lt9611uxc.
> > > Likewise, I think, it's fine to have empty files for the infoframes
> > > which are not being sent over the wire for any reason (hw not supporting
> > > it is one of the reasons).
> > 
> > I can't think of any other example in the kernel where an empty file
> > means that the driver doesn't support something.
> 
> Okay. So we need to sort out implementing the split write_infoframes in
> drm_bridge_connector. Any suggestions there? I'm asking, because I don't
> want to end up exploding it.

I guess it's only really a problem if we want to make it const, but we
don't have to? We could just as well allocate the structure directly at
probe with a drmm helper and fill it as we need to.

Maxime
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 273 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251219/a9f53cf0/attachment.sig>

From krzk at kernel.org  Fri Dec 19 01:56:17 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 10:56:17 +0100
Subject: [PATCH v1 1/2] dt-bindings: arm: cix: add OrangePi 6 Plus board
In-Reply-To: <20251219095409.1395587-2-gary.yang@cixtech.com>
References: <20251219095409.1395587-1-gary.yang@cixtech.com>
 <20251219095409.1395587-2-gary.yang@cixtech.com>
Message-ID: <b83d45c4-eeea-4c0f-9395-6d6483c278f7@kernel.org>

On 19/12/2025 10:54, Gary Yang wrote:
> OrangePi 6 Plus adopts CIX CD8180/CD8160 SoC,
> built-in 12-core 64-bit processor + NPU processor,
> integrated graphics processor, equipped with 16GB/32GB/64GB
> LPDDR5, and provides two M.2 KEY-M interfaces 2280 for NVMe SSD,
> as well as SPI FLASH and TF slots to meet the needs of fast
> read/write and high-capacity storage;
> 
> Signed-off-by: Gary Yang <gary.yang at cixtech.com>
> ---
>  Documentation/devicetree/bindings/arm/cix.yaml | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/arm/cix.yaml b/Documentation/devicetree/bindings/arm/cix.yaml
> index 114dab4bc4d2..92fb4ad7b5d8 100644
> --- a/Documentation/devicetree/bindings/arm/cix.yaml
> +++ b/Documentation/devicetree/bindings/arm/cix.yaml
> @@ -21,6 +21,11 @@ properties:
>            - const: radxa,orion-o6
>            - const: cix,sky1
>  
> +      - description: OrangePi 6 Plus
> +        items:
> +          - const: OrangePi,6p

That's not a valid prefix. Where is it documented and how it looks there?

Why this cannot be part of enum with the first device? Creating a list
per device scales poorly.

> +          - const: cix,sky1
> +
>  additionalProperties: true
>  
>  ...


Best regards,
Krzysztof


From dmitry.baryshkov at oss.qualcomm.com  Fri Dec 19 01:56:41 2025
From: dmitry.baryshkov at oss.qualcomm.com (Dmitry Baryshkov)
Date: Fri, 19 Dec 2025 11:56:41 +0200
Subject: [PATCH v3 00/11] drm/connector: hdmi: limit infoframes per driver
 capabilities
In-Reply-To: <20251219-honest-slim-crab-02e932@houat>
References: <20250929-gregarious-worm-of-memory-c5354d@houat>
 <itgffxygopi7etkt7xhvmyuvyl5ad3k43nsxvjzw3ubtwiikn7@ocugfdaigtu7>
 <20251003-uptight-echidna-of-stamina-815305@houat>
 <zpygq4kapil3swsmhhqkdwny4ry2dznnzixsw5rkza5p2kqnvp@abvf2vxlbwif>
 <2a5fitdzr2bz235fj6rvqzxr6ckszkjbazjfszlvnizdh2cvbt@w3ypjo7vahhs>
 <pibxhl5hlcpuk3zsgyienfdlda5cwuxrnofwlw356scuzzplqy@zw3ofelgvwik>
 <bsoqyzxi45i67jpzhwr2d4illufa5ghqf25z6flbp67lsbvh22@rrlcihp2oxea>
 <cgzclxjubj5oca3rdnv44qwrkmpddxve4tlz76cc6p3b4hz3oc@3l7mt5ha7do6>
 <20251201-enlightened-zebu-from-asgard-5a20be@houat>
 <5dyhjur3hkhvtlwrl4h2m342byor7f3ssvkunj4cggnhbhlmnb@l2mfz7ypjj37>
 <20251219-honest-slim-crab-02e932@houat>
Message-ID: <a0acccc3-00d9-4235-9b4a-f4498b2896ac@oss.qualcomm.com>

On 19/12/2025 11:54, Maxime Ripard wrote:
> On Sat, Dec 06, 2025 at 01:28:14PM +0200, Dmitry Baryshkov wrote:
>> On Mon, Dec 01, 2025 at 06:01:56PM +0100, Maxime Ripard wrote:
>>> On Fri, Nov 21, 2025 at 07:09:01PM +0200, Dmitry Baryshkov wrote:
>>>>> So it's not really impossible, you just need some hardware and a day's
>>>>> worth of work.
>>>>>
>>>>> There's no reason these should get a pass, it's breaking the spec for no
>>>>> reason.
>>>>>
>>>>>>> For SPD, It's really not clear to me why atomic_check should do that in
>>>>>>> the first place. Your initial concern was about exposing infoframes in
>>>>>>> debugfs that wouldn't be used by the driver.
>>>>>>>
>>>>>>> If the driver doesn't register a debugfs file for SPD, and ignores
>>>>>>> whatever is in the atomic state, what's should we force drivers to do
>>>>>>> that?
>>>>>>
>>>>>> I really don't think that drivers should mess up with debugfs on their
>>>>>> own. Making atomic_check() disable the unsupported InfoFrames makes the
>>>>>> picture perfect: the DRM no longer tries to program them to the
>>>>>> hardware, DebugFS files stay empty, so the whole state becomes
>>>>>> consistent.
>>>>>
>>>>> In the "bridge has no access to infoframes" case, there's really no
>>>>> infoframe. An empty file is "the infoframe can be there but isn't used",
>>>>> not "we don't have access to it and can't report them". Only drivers
>>>>> have those infos.
>>>>>
>>>>> If we do split up write_infoframe into multiple functions though, I
>>>>> guess we could create the debugfs file only if the function pointer is
>>>>> set, which removes drivers' involvement if you don't like that.
>>>>
>>>> I'm fine with not using HDMI connector framework for lt9611uxc.
>>>> Likewise, I think, it's fine to have empty files for the infoframes
>>>> which are not being sent over the wire for any reason (hw not supporting
>>>> it is one of the reasons).
>>>
>>> I can't think of any other example in the kernel where an empty file
>>> means that the driver doesn't support something.
>>
>> Okay. So we need to sort out implementing the split write_infoframes in
>> drm_bridge_connector. Any suggestions there? I'm asking, because I don't
>> want to end up exploding it.
> 
> I guess it's only really a problem if we want to make it const, but we
> don't have to? We could just as well allocate the structure directly at
> probe with a drmm helper and fill it as we need to.


Yes, I wanted to keep it const, as we usually do for all function 
tables. I will use drmm_alloc for it.


-- 
With best wishes
Dmitry


From suzuki.poulose at arm.com  Fri Dec 19 01:59:54 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Fri, 19 Dec 2025 09:59:54 +0000
Subject: [PATCH v2 RESEND] coresight: etm-perf: Fix reference count leak
 in etm_setup_aux
In-Reply-To: <20251219094141.GA9788@e132581.arm.com>
References: <f85c7d37-4980-46f0-9136-353a35a8f0ed@oss.qualcomm.com>
 <20251219023949.12699-1-make24@iscas.ac.cn>
 <20251219094141.GA9788@e132581.arm.com>
Message-ID: <d4946831-fc8c-4727-abec-3edd92e357d1@arm.com>

On 19/12/2025 09:41, Leo Yan wrote:
> Hi,
> 
> On Fri, Dec 19, 2025 at 10:39:49AM +0800, Ma Ke wrote:
> 
> [...]
> 
>>  From the discussion, I note two possible fix directions:
>>
>> 1. Release the initial reference in etm_setup_aux() (current v2 patch)
>> 2. Modify the behavior of coresight_get_sink_by_id() itself so it
>> doesn't increase the reference count.
> 
> The option 2 is the right way to go.
> 
>> To ensure the correctness of the v3 patch, I'd like to confirm which
>> patch is preferred. If option 2 is the consensus, I'm happy to modify
>> the implementation of coresight_get_sink_by_id() as suggested.
> 
> It is good to use a separate patch to fix
> coresight_find_device_by_fwnode() mentioned by James:
> 
> diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c
> index 0db64c5f4995..2b34f818ba88 100644
> --- a/drivers/hwtracing/coresight/coresight-platform.c
> +++ b/drivers/hwtracing/coresight/coresight-platform.c
> @@ -107,14 +107,16 @@ coresight_find_device_by_fwnode(struct fwnode_handle *fwnode)
>   	 * platform bus.
>   	 */
>   	dev = bus_find_device_by_fwnode(&platform_bus_type, fwnode);
> -	if (dev)
> -		return dev;
>   
>   	/*
>   	 * We have a configurable component - circle through the AMBA bus
>   	 * looking for the device that matches the endpoint node.
>   	 */
> -	return bus_find_device_by_fwnode(&amba_bustype, fwnode);
> +	if (!dev)
> +		dev = bus_find_device_by_fwnode(&amba_bustype, fwnode);
> +
> +	put_device(dev);

^^ NAK, see below.

> +	return dev;
>   }
>   
>   /*
> @@ -274,7 +276,6 @@ static int of_coresight_parse_endpoint(struct device *dev,
>   
>   	of_node_put(rparent);
>   	of_node_put(rep);
> -	put_device(rdev);

This doesn't look good. We can't use the "dev" reliably without the 
reference count. We are opening up use-after-free.

NAK for this.

Suzuki

>   
>   	return ret;
>   }
> 
> Thanks for working on this.



From jie.gan at oss.qualcomm.com  Fri Dec 19 02:04:18 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Fri, 19 Dec 2025 18:04:18 +0800
Subject: [PATCH v5 0/3] add sysfs nodes to configure TPDA's registers
Message-ID: <20251219-add_sysfs_nodes_to_configure_tpda-v5-0-ca93ddfe9d30@oss.qualcomm.com>

Patchset 1 introduces configuration of the global control register with
appropriate values to enable proper generation of cross-trigger packets.

Patchset 2 introduces a logic to configure the TPDA_SYNCR register,
which determines the frequency of ASYNC packet generation. These packets
assist userspace tools in accurately identifying each valid packet.

Patchset 3 introduces a sysfs node to initiate a flush request for the
specific port, forcing the data to synchronize and be transmitted to the
sink device.

Chnages in V5:
1. Optimizing the solution to creat sysfs nodes.
2. Optimizing the logic for configuring bits of the global control
   register.
Link to V4 - https://lore.kernel.org/all/20251028-configure_tpda_reg-v4-0-23000805d21d at oss.qualcomm.com/

Changes in V4:
1. Document sysfs nodes with correct kernel version and date.
Link to V3 - https://lore.kernel.org/linux-arm-kernel/20250827105545.7140-1-jie.gan at oss.qualcomm.com/

Changes in V3:
1. Optimizing codes according to James's comment.
Link to V2 - https://lore.kernel.org/all/20250827042042.6786-1-jie.gan at oss.qualcomm.com/

Changes in V2:
1. Refactoring the code based on James's comment for optimization.
Link to V1 - https://lore.kernel.org/all/20250826070150.5603-1-jie.gan at oss.qualcomm.com/

Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
Tao Zhang (3):
      coresight: tpda: add sysfs nodes for tpda cross-trigger configuration
      coresight: tpda: add logic to configure TPDA_SYNCR register
      coresight: tpda: add sysfs node to flush specific port

 .../ABI/testing/sysfs-bus-coresight-devices-tpda   |  50 ++++++
 drivers/hwtracing/coresight/coresight-tpda.c       | 194 ++++++++++++++++++++-
 drivers/hwtracing/coresight/coresight-tpda.h       |  75 +++++++-
 3 files changed, 312 insertions(+), 7 deletions(-)
---
base-commit: 12b95d29eb979e5c4f4f31bb05817bc935c52050
change-id: 20251219-add_sysfs_nodes_to_configure_tpda-f54636512817

Best regards,
-- 
Jie Gan <jie.gan at oss.qualcomm.com>



From hkelam at marvell.com  Fri Dec 19 02:04:20 2025
From: hkelam at marvell.com (Hariprasad Kelam)
Date: Fri, 19 Dec 2025 15:34:20 +0530
Subject: [PATCH net] net: stmmac: fix the crash issue for zero copy
 XDP_TX action
In-Reply-To: <PAXPR04MB8510499B65301187736D511088A8A@PAXPR04MB8510.eurprd04.prod.outlook.com>
References: <20251204071332.1907111-1-wei.fang@nxp.com>
 <aUKPHdtAPDnMqB7X@test-OptiPlex-Tower-Plus-7010>
 <AS8PR04MB849779A6392D543049A3F5BE88ABA@AS8PR04MB8497.eurprd04.prod.outlook.com>
 <aUOddielBMkrmwhd@test-OptiPlex-Tower-Plus-7010>
 <PAXPR04MB8510499B65301187736D511088A8A@PAXPR04MB8510.eurprd04.prod.outlook.com>
Message-ID: <aUUjJH1tQkN1UcYL@test-OptiPlex-Tower-Plus-7010>

On 2025-12-18 at 12:06:47, Wei Fang (wei.fang at nxp.com) wrote:
> > On 2025-12-17 at 18:19:19, Wei Fang (wei.fang at nxp.com) wrote:
> > > > > -	res = stmmac_xdp_xmit_xdpf(priv, queue, xdpf, false);
> > > > > -	if (res == STMMAC_XDP_TX)
> > > > > +	/* For zero copy XDP_TX action, dma_map is true */
> > > > > +	res = stmmac_xdp_xmit_xdpf(priv, queue, xdpf, zc);
> > > > 	Seems stmmac_xdp_xmit_xdpf is using dma_map_single if we pass zc is
> > > > true.
> > > >         Ideally in case of zc, driver can use
> > > > page_pool_get_dma_addr, may be you
> > > >         need pass zc param as false. Please check
> > > >
> > >
> > > No, the memory type of xdpf->data is MEM_TYPE_PAGE_ORDER0 rather than
> > > MEM_TYPE_PAGE_POOL, so we should use dma_map_single().
> > > Otherwise, it will lead to invalid mappings and cause the crash.
> > >
> > >
> >  ACK, found below code bit confusing
> > 		case STMMAC_XDP_CONSUMED:
> >  			xsk_buff_free(buf->xdp);
> > +			fallthrough;
> > +		case STMMAC_XSK_CONSUMED:
> >  			rx_dropped++;
> > 
> >      Ideally in case of STMMAC_XSK_CONSUMED, driver needs to call
> > xsk_buff_free.
> >      And in case of STMMAC_XDP_CONSUMED, driver needs to call
> > xdp_return_frame.
> >      May be you can move all buffer free logic to stmmac_rx_zc with above
> > suggested
> >      changes.
> 
> For zero copy, the xdp_buff is freed by xdp_convert_buff_to_frame()
> when converting the xdp_xdp to xdp_frame. So STMMAC_XSK_CONSUMED
> means the xdp_buff has been freed, it tells stmmac_rx_zc() no to free a
> xdp_buff that has been freed.
> 
> I have added a comment for STMMAC_XSK_CONSUMED, see
> 
> +       } else if (res == STMMAC_XDP_CONSUMED && zc) {
> +               /* xdp has been freed by xdp_convert_buff_to_frame(),
> +                * no need to call xsk_buff_free() again, so return
> +                * STMMAC_XSK_CONSUMED.
> +                */
> +               res = STMMAC_XSK_CONSUMED;
> +               xdp_return_frame(xdpf);
> +       }
> 
>
 ACK. 
Reviewed-by: Hariprasad Kelam <hkelam at marvell.com> 


From jie.gan at oss.qualcomm.com  Fri Dec 19 02:04:19 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Fri, 19 Dec 2025 18:04:19 +0800
Subject: [PATCH v5 1/3] coresight: tpda: add sysfs nodes for tpda
 cross-trigger configuration
In-Reply-To: <20251219-add_sysfs_nodes_to_configure_tpda-v5-0-ca93ddfe9d30@oss.qualcomm.com>
References: <20251219-add_sysfs_nodes_to_configure_tpda-v5-0-ca93ddfe9d30@oss.qualcomm.com>
Message-ID: <20251219-add_sysfs_nodes_to_configure_tpda-v5-1-ca93ddfe9d30@oss.qualcomm.com>

From: Tao Zhang <tao.zhang at oss.qualcomm.com>

Introduce sysfs nodes to configure cross-trigger parameters for TPDA.
These registers define the characteristics of cross-trigger packets,
including generation frequency and flag values.

Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
Reviewed-by: James Clark <james.clark at linaro.org>
Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 .../ABI/testing/sysfs-bus-coresight-devices-tpda   |  43 +++++++
 drivers/hwtracing/coresight/coresight-tpda.c       | 138 ++++++++++++++++++++-
 drivers/hwtracing/coresight/coresight-tpda.h       |  69 ++++++++++-
 3 files changed, 243 insertions(+), 7 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
new file mode 100644
index 000000000000..a7855922328e
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
@@ -0,0 +1,43 @@
+What:		/sys/bus/coresight/devices/<tpda-name>/global_cr/trig_async_enable
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Enable/disable cross trigger synchronization sequence interface.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/global_cr/trig_flag_ts_enable
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Enable/disable cross trigger FLAG packet request interface.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/global_cr/trig_freq_enable
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Enable/disable cross trigger FREQ packet request interface.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/global_cr/freq_ts_enable
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Enable/disable the timestamp for all FREQ packets.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/global_cr/global_flush_req
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Set global (all ports) flush request bit. The bit remains set until a
+		global flush request sequence completes.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/global_cr/cmbchan_mode
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Configure the CMB/MCMB channel mode for all enabled ports.
+		Value 0 means raw channel mapping mode. Value 1 means channel pair marking mode.
diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
index 3a3825d27f86..d25a8bcfb3d4 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.c
+++ b/drivers/hwtracing/coresight/coresight-tpda.c
@@ -137,12 +137,32 @@ static int tpda_get_element_size(struct tpda_drvdata *drvdata,
 /* Settings pre enabling port control register */
 static void tpda_enable_pre_port(struct tpda_drvdata *drvdata)
 {
-	u32 val;
+	u32 val = 0;
 
-	val = readl_relaxed(drvdata->base + TPDA_CR);
-	val &= ~TPDA_CR_ATID;
 	val |= FIELD_PREP(TPDA_CR_ATID, drvdata->atid);
+	if (drvdata->trig_async)
+		val |= TPDA_CR_SRIE;
+
+	if (drvdata->trig_flag_ts)
+		val |= TPDA_CR_FLRIE;
+
+	if (drvdata->trig_freq)
+		val |= TPDA_CR_FRIE;
+
+	if (drvdata->freq_ts)
+		val |= TPDA_CR_FREQTS;
+
+	if (drvdata->cmbchan_mode)
+		val |= TPDA_CR_CMBCHANMODE;
+
 	writel_relaxed(val, drvdata->base + TPDA_CR);
+
+	/*
+	 * If FLRIE bit is set, set the master and channel
+	 * id as zero
+	 */
+	if (drvdata->trig_flag_ts)
+		writel_relaxed(0x0, drvdata->base + TPDA_FPID_CR);
 }
 
 static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
@@ -258,6 +278,116 @@ static const struct coresight_ops tpda_cs_ops = {
 	.link_ops	= &tpda_link_ops,
 };
 
+/* Read cross-trigger register member */
+static ssize_t tpda_trig_sysfs_show(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	struct tpda_trig_sysfs_attribute *tpda_attr =
+		container_of(attr, struct tpda_trig_sysfs_attribute, attr);
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	guard(spinlock)(&drvdata->spinlock);
+	switch (tpda_attr->mem) {
+	case FLREQ:
+		if (!drvdata->csdev->refcnt)
+			return -EINVAL;
+
+		val = readl_relaxed(drvdata->base + TPDA_CR);
+		/* read global flush request bit only */
+		val &= TPDA_CR_FLREQ;
+		return sysfs_emit(buf, "%lu\n", val);
+	case FREQTS:
+		return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->freq_ts);
+	case FRIE:
+		return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_freq);
+	case FLRIE:
+		return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_flag_ts);
+	case SRIE:
+		return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_async);
+	case CMBCHANMODE:
+		return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->cmbchan_mode);
+
+	}
+	return -EINVAL;
+}
+
+static ssize_t tpda_trig_sysfs_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf,
+				     size_t size)
+{
+	struct tpda_trig_sysfs_attribute *tpda_attr =
+		container_of(attr, struct tpda_trig_sysfs_attribute, attr);
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	ssize_t ret = -EINVAL;
+	unsigned long val;
+
+	if (kstrtoul(buf, 0, &val))
+		return ret;
+
+	guard(spinlock)(&drvdata->spinlock);
+	switch (tpda_attr->mem) {
+	case FLREQ:
+		if (!drvdata->csdev->refcnt || !val)
+			return ret;
+
+		val = readl_relaxed(drvdata->base + TPDA_CR);
+		/* set global flush request bit */
+		val |= TPDA_CR_FLREQ;
+		CS_UNLOCK(drvdata->base);
+		writel_relaxed(val, drvdata->base + TPDA_CR);
+		CS_LOCK(drvdata->base);
+		ret = size;
+		break;
+	case FREQTS:
+		drvdata->freq_ts = !!val;
+		ret = size;
+		break;
+	case FRIE:
+		drvdata->trig_freq = !!val;
+		ret = size;
+		break;
+	case FLRIE:
+		drvdata->trig_flag_ts = !!val;
+		ret = size;
+		break;
+	case SRIE:
+		drvdata->trig_async = !!val;
+		ret = size;
+		break;
+	case CMBCHANMODE:
+		drvdata->cmbchan_mode = !!val;
+		ret = size;
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+static struct attribute *tpda_global_cr_attrs[] = {
+	tpda_trig_sysfs_rw(global_flush_req, FLREQ),
+	tpda_trig_sysfs_rw(freq_ts_enable, FREQTS),
+	tpda_trig_sysfs_rw(trig_freq_enable, FRIE),
+	tpda_trig_sysfs_rw(trig_flag_ts_enable, FLRIE),
+	tpda_trig_sysfs_rw(trig_async_enable, SRIE),
+	tpda_trig_sysfs_rw(cmbchan_mode, CMBCHANMODE),
+	NULL,
+};
+
+static struct attribute_group tpda_global_cr_attr_grp = {
+	.attrs	= tpda_global_cr_attrs,
+	.name	= "global_cr",
+};
+
+static const struct attribute_group *tpda_attr_grps[] = {
+	&tpda_global_cr_attr_grp,
+	NULL,
+};
+
 static int tpda_init_default_data(struct tpda_drvdata *drvdata)
 {
 	int atid;
@@ -273,6 +403,7 @@ static int tpda_init_default_data(struct tpda_drvdata *drvdata)
 		return atid;
 
 	drvdata->atid = atid;
+	drvdata->freq_ts = true;
 	return 0;
 }
 
@@ -316,6 +447,7 @@ static int tpda_probe(struct amba_device *adev, const struct amba_id *id)
 	desc.ops = &tpda_cs_ops;
 	desc.pdata = adev->dev.platform_data;
 	desc.dev = &adev->dev;
+	desc.groups = tpda_attr_grps;
 	desc.access = CSDEV_ACCESS_IOMEM(base);
 	drvdata->csdev = coresight_register(&desc);
 	if (IS_ERR(drvdata->csdev))
diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h
index c6af3d2da3ef..8a075cfbc3cc 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.h
+++ b/drivers/hwtracing/coresight/coresight-tpda.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 /*
- * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2023,2025 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CORESIGHT_CORESIGHT_TPDA_H
@@ -8,6 +8,30 @@
 
 #define TPDA_CR			(0x000)
 #define TPDA_Pn_CR(n)		(0x004 + (n * 4))
+#define TPDA_FPID_CR		(0x084)
+
+/* Cross trigger Global (all ports) flush request bit */
+#define TPDA_CR_FLREQ		BIT(0)
+/* Cross trigger FREQ packets timestamp bit */
+#define TPDA_CR_FREQTS		BIT(2)
+/* Cross trigger FREQ packet request bit */
+#define TPDA_CR_FRIE		BIT(3)
+/* Cross trigger FLAG packet request interface bit */
+#define TPDA_CR_FLRIE		BIT(4)
+/* Cross trigger synchronization bit */
+#define TPDA_CR_SRIE		BIT(5)
+/* Bits 6 ~ 12 is for atid value */
+#define TPDA_CR_ATID		GENMASK(12, 6)
+/* Bits 13 ~ 19 is for mid value */
+/* Assign a unique master ID to identify the TPDA device */
+#define TPDA_CR_MID		GENMASK(19, 13)
+/*
+ * Channel mode bit of the packetization of CMB/MCB traffic
+ * 0 - raw channel mapping mode
+ * 1 - channel pair marking mode
+ */
+#define TPDA_CR_CMBCHANMODE	BIT(20)
+
 /* Aggregator port enable bit */
 #define TPDA_Pn_CR_ENA		BIT(0)
 /* Aggregator port CMB data set element size bit */
@@ -17,9 +41,6 @@
 
 #define TPDA_MAX_INPORTS	32
 
-/* Bits 6 ~ 12 is for atid value */
-#define TPDA_CR_ATID		GENMASK(12, 6)
-
 /**
  * struct tpda_drvdata - specifics associated to an TPDA component
  * @base:       memory mapped base address for this component.
@@ -29,6 +50,11 @@
  * @enable:     enable status of the component.
  * @dsb_esize   Record the DSB element size.
  * @cmb_esize   Record the CMB element size.
+ * @trig_async:	Enable/disable cross trigger synchronization sequence interface.
+ * @trig_flag_ts: Enable/disable cross trigger FLAG packet request interface.
+ * @trig_freq:	Enable/disable cross trigger FREQ packet request interface.
+ * @freq_ts:	Enable/disable the timestamp for all FREQ packets.
+ * @cmbchan_mode: Configure the CMB/MCMB channel mode.
  */
 struct tpda_drvdata {
 	void __iomem		*base;
@@ -38,6 +64,41 @@ struct tpda_drvdata {
 	u8			atid;
 	u32			dsb_esize;
 	u32			cmb_esize;
+	bool			trig_async;
+	bool			trig_flag_ts;
+	bool			trig_freq;
+	bool			freq_ts;
+	bool			cmbchan_mode;
+};
+
+/* Enumerate members of global control register(cr) */
+enum tpda_cr_mem {
+	FLREQ,
+	FREQTS,
+	FRIE,
+	FLRIE,
+	SRIE,
+	CMBCHANMODE
+};
+
+/**
+ * struct tpda_trig_sysfs_attribute - Record the member variables of cross
+ * trigger register that need to be operated by sysfs file
+ * @attr:	The device attribute
+ * @mem:	The member in the control register data structure
+ */
+struct tpda_trig_sysfs_attribute {
+	struct device_attribute attr;
+	enum tpda_cr_mem mem;
 };
 
+#define tpda_trig_sysfs_rw(name, mem)				\
+	(&((struct tpda_trig_sysfs_attribute[]) {		\
+	   {							\
+		__ATTR(name, 0644, tpda_trig_sysfs_show,	\
+		tpda_trig_sysfs_store),				\
+		mem,						\
+	   }							\
+	   })[0].attr.attr)
+
 #endif  /* _CORESIGHT_CORESIGHT_TPDA_H */

-- 
2.34.1



From jie.gan at oss.qualcomm.com  Fri Dec 19 02:04:21 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Fri, 19 Dec 2025 18:04:21 +0800
Subject: [PATCH v5 3/3] coresight: tpda: add sysfs node to flush specific
 port
In-Reply-To: <20251219-add_sysfs_nodes_to_configure_tpda-v5-0-ca93ddfe9d30@oss.qualcomm.com>
References: <20251219-add_sysfs_nodes_to_configure_tpda-v5-0-ca93ddfe9d30@oss.qualcomm.com>
Message-ID: <20251219-add_sysfs_nodes_to_configure_tpda-v5-3-ca93ddfe9d30@oss.qualcomm.com>

From: Tao Zhang <tao.zhang at oss.qualcomm.com>

Setting bit i in the TPDA_FLUSH_CR register initiates a flush request
for port i, forcing the data to synchronize and be transmitted to the
sink device.

Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
Reviewed-by: James Clark <james.clark at linaro.org>
Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 .../ABI/testing/sysfs-bus-coresight-devices-tpda   |  7 ++++
 drivers/hwtracing/coresight/coresight-tpda.c       | 49 ++++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-tpda.h       |  1 +
 3 files changed, 57 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
index a7855922328e..ef2804f87d1e 100644
--- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
@@ -41,3 +41,10 @@ Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qu
 Description:
 		(RW) Configure the CMB/MCMB channel mode for all enabled ports.
 		Value 0 means raw channel mapping mode. Value 1 means channel pair marking mode.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/port_flush_req
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Configure the bit i to requests a flush operation of port i on the TPDA.
diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
index d378ff8ad77d..5b4a9e41b067 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.c
+++ b/drivers/hwtracing/coresight/coresight-tpda.c
@@ -375,6 +375,45 @@ static ssize_t tpda_trig_sysfs_store(struct device *dev,
 	return ret;
 }
 
+static ssize_t port_flush_req_show(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (!drvdata->csdev->refcnt)
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	val = readl_relaxed(drvdata->base + TPDA_FLUSH_CR);
+
+	return sysfs_emit(buf, "0x%lx\n", val);
+}
+
+static ssize_t port_flush_req_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf,
+				    size_t size)
+{
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	u32 val;
+
+	if (kstrtou32(buf, 0, &val))
+		return -EINVAL;
+
+	if (!drvdata->csdev->refcnt || !val)
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	CS_UNLOCK(drvdata->base);
+	writel_relaxed(val, drvdata->base + TPDA_FLUSH_CR);
+	CS_LOCK(drvdata->base);
+
+	return size;
+}
+static DEVICE_ATTR_RW(port_flush_req);
+
 static struct attribute *tpda_global_cr_attrs[] = {
 	tpda_trig_sysfs_rw(global_flush_req, FLREQ),
 	tpda_trig_sysfs_rw(freq_ts_enable, FREQTS),
@@ -385,13 +424,23 @@ static struct attribute *tpda_global_cr_attrs[] = {
 	NULL,
 };
 
+static struct attribute *tpda_attrs[] = {
+	&dev_attr_port_flush_req.attr,
+	NULL,
+};
+
 static struct attribute_group tpda_global_cr_attr_grp = {
 	.attrs	= tpda_global_cr_attrs,
 	.name	= "global_cr",
 };
 
+static struct attribute_group tpda_attr_grp = {
+	.attrs	= tpda_attrs,
+};
+
 static const struct attribute_group *tpda_attr_grps[] = {
 	&tpda_global_cr_attr_grp,
+	&tpda_attr_grp,
 	NULL,
 };
 
diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h
index 97e2729c15c9..ec93f9cb9648 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.h
+++ b/drivers/hwtracing/coresight/coresight-tpda.h
@@ -10,6 +10,7 @@
 #define TPDA_Pn_CR(n)		(0x004 + (n * 4))
 #define TPDA_FPID_CR		(0x084)
 #define TPDA_SYNCR		(0x08C)
+#define TPDA_FLUSH_CR		(0x090)
 
 /* Cross trigger Global (all ports) flush request bit */
 #define TPDA_CR_FLREQ		BIT(0)

-- 
2.34.1



From jie.gan at oss.qualcomm.com  Fri Dec 19 02:04:20 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Fri, 19 Dec 2025 18:04:20 +0800
Subject: [PATCH v5 2/3] coresight: tpda: add logic to configure TPDA_SYNCR
 register
In-Reply-To: <20251219-add_sysfs_nodes_to_configure_tpda-v5-0-ca93ddfe9d30@oss.qualcomm.com>
References: <20251219-add_sysfs_nodes_to_configure_tpda-v5-0-ca93ddfe9d30@oss.qualcomm.com>
Message-ID: <20251219-add_sysfs_nodes_to_configure_tpda-v5-2-ca93ddfe9d30@oss.qualcomm.com>

From: Tao Zhang <tao.zhang at oss.qualcomm.com>

The TPDA_SYNC counter tracks the number of bytes transferred from the
aggregator. When this count reaches the value programmed in the
TPDA_SYNCR register, an ASYNC request is triggered, allowing userspace
tools to accurately parse each valid packet.

Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
Reviewed-by: James Clark <james.clark at linaro.org>
Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 drivers/hwtracing/coresight/coresight-tpda.c | 7 +++++++
 drivers/hwtracing/coresight/coresight-tpda.h | 5 +++++
 2 files changed, 12 insertions(+)

diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
index d25a8bcfb3d4..d378ff8ad77d 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.c
+++ b/drivers/hwtracing/coresight/coresight-tpda.c
@@ -163,6 +163,13 @@ static void tpda_enable_pre_port(struct tpda_drvdata *drvdata)
 	 */
 	if (drvdata->trig_flag_ts)
 		writel_relaxed(0x0, drvdata->base + TPDA_FPID_CR);
+
+	val = readl_relaxed(drvdata->base + TPDA_SYNCR);
+	/* Reset the mode ctrl */
+	val &= ~TPDA_SYNCR_MODE_CTRL;
+	/* Program the counter value for TPDA_SYNCR */
+	val |= TPDA_SYNCR_COUNTER_MASK;
+	writel_relaxed(val, drvdata->base + TPDA_SYNCR);
 }
 
 static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h
index 8a075cfbc3cc..97e2729c15c9 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.h
+++ b/drivers/hwtracing/coresight/coresight-tpda.h
@@ -9,6 +9,7 @@
 #define TPDA_CR			(0x000)
 #define TPDA_Pn_CR(n)		(0x004 + (n * 4))
 #define TPDA_FPID_CR		(0x084)
+#define TPDA_SYNCR		(0x08C)
 
 /* Cross trigger Global (all ports) flush request bit */
 #define TPDA_CR_FLREQ		BIT(0)
@@ -38,6 +39,10 @@
 #define TPDA_Pn_CR_CMBSIZE		GENMASK(7, 6)
 /* Aggregator port DSB data set element size bit */
 #define TPDA_Pn_CR_DSBSIZE		BIT(8)
+/* TPDA_SYNCR mode control bit */
+#define TPDA_SYNCR_MODE_CTRL		BIT(12)
+/* TPDA_SYNCR counter mask */
+#define TPDA_SYNCR_COUNTER_MASK		GENMASK(11, 0)
 
 #define TPDA_MAX_INPORTS	32
 

-- 
2.34.1



From sudeep.holla at arm.com  Fri Dec 19 02:06:52 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Fri, 19 Dec 2025 10:06:52 +0000
Subject: [PATCH v2 00/12] coresight: Add CPU cluster
 funnel/replicator/tmc support
In-Reply-To: <3d4dd3d0-fca0-45ac-a833-e8f7f5d1aa95@arm.com>
References: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
 <47191600-260a-46aa-9af8-dff2b08dc2e8@arm.com>
 <8cb8fad9-c54e-43a3-a769-5452119cc2a1@oss.qualcomm.com>
 <3d4dd3d0-fca0-45ac-a833-e8f7f5d1aa95@arm.com>
Message-ID: <20251219-rugged-hamster-of-force-63bdc6@sudeepholla>

On Thu, Dec 18, 2025 at 05:04:07PM +0000, Suzuki K Poulose wrote:
> On 18/12/2025 16:18, yuanfang zhang wrote:
> > 
> > On 12/18/2025 5:32 PM, Suzuki K Poulose wrote:
> > > Cc: Sudeep
> > > 
> > > On 18/12/2025 08:09, Yuanfang Zhang wrote:
> > > > This patch series adds support for CoreSight components local to CPU clusters,
> > > > including funnel, replicator, and TMC, which reside within CPU cluster power
> > > > domains. These components require special handling due to power domain
> > > > constraints.
> > > > 
> > > > Unlike system-level CoreSight devices, these components share the CPU cluster's
> > > > power domain. When the cluster enters low-power mode (LPM), their registers
> > > > become inaccessible. Notably, `pm_runtime_get` alone cannot bring the cluster
> > > > out of LPM, making standard register access unreliable.
> > > 
> > > Why ? AFAIU, we have ways to tie the power-domain to that of the cluster
> > > and that can auto-magically keep the cluster power ON as long as you
> > > want to use them.
> > > 
> > > Suzuki
> > > 
> > Hi Suzuki
> > 
> > Runtime PM for CPU devices works little different, it is mostly used to manage hierarchical
> > CPU topology (PSCI OSI mode) to talk with genpd framework to manage the last CPU handling in
> > cluster.
> > It doesn?t really send IPI to wakeup CPU device (It don?t have .power_on/.power_off) callback
> > implemented which gets invoked from .runtime_resume callback. This behavior is aligned with
> > the upstream Kernel.
> 
> Why does it need to wake up the CPU ? The firmware can power up the
> cluster right? Anyways, to me this all looks like working around a
> firmware issue. I will let you sort this out with Sudeep's response
> , as I am not an expert on the cluster powermanagement and standards.
> 

Indeed smells like a some workaround, will respond in another email in the
thread to capture other points as well.

-- 
Regards,
Sudeep


From bartosz.golaszewski at oss.qualcomm.com  Fri Dec 19 02:07:39 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Fri, 19 Dec 2025 11:07:39 +0100
Subject: [PATCH v10 00/12] crypto/dmaengine: qce: introduce BAM locking and
 use DMA for register I/O
Message-ID: <20251219-qcom-qce-cmd-descr-v10-0-ff7e4bf7dad4@oss.qualcomm.com>

Vinod: I'm sending a v10 with some additional changes and a new patch
constifying the DMA descr metatada ops struct. This series has been on
the list for quite some time and has been positively reviewed by
a couple people. Unless you have a concrete suggestion on how to do it
better, I'd like to ask you to consider picking up patches 1-4 into an
immutable branch provided to the crypto maintainers. I would appreciate
if this series could make v6.20.

Currently the QCE crypto driver accesses the crypto engine registers
directly via CPU. Trust Zone may perform crypto operations simultaneously
resulting in a race condition. To remedy that, let's introduce support
for BAM locking/unlocking using DMA descriptor metadata as medium for
passing the relevant information from the QCE engine driver to the BAM
driver.

In the specific case of the BAM DMA this translates to sending command
descriptors performing dummy writes with the relevant flags set. The BAM
will then lock all other pipes not related to the current pipe group, and
keep handling the current pipe only until it sees the the unlock bit.

In order for the locking to work correctly, we also need to switch to
using DMA for all register I/O.

On top of this, the series contains some additional tweaks and
refactoring.

The goal of this is not to improve the performance but to prepare the
driver for supporting decryption into secure buffers in the future.

Tested with tcrypt.ko, kcapi and cryptsetup.

Shout out to Daniel and Udit from Qualcomm for helping me out with some
DMA issues we encountered.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at linaro.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
Changes in v10:
- Move DESC_FLAG_(UN)LOCK BIT definitions from patch 2 to 3
- Add a patch constifying the dma engine metadata as the first in the
  series
- Use the VERSION register for dummy lock/unlock writes
- Link to v9: https://lore.kernel.org/r/20251128-qcom-qce-cmd-descr-v9-0-9a5f72b89722 at linaro.org

Changes in v9:
- Drop the global, generic LOCK/UNLOCK flags and instead use DMA
  descriptor metadata ops to pass BAM-specific information from the QCE
  to the DMA engine
- Link to v8: https://lore.kernel.org/r/20251106-qcom-qce-cmd-descr-v8-0-ecddca23ca26 at linaro.org

Changes in v8:
- Rework the command descriptor logic and drop a lot of unneeded code
- Use the physical address for BAM command descriptor access, not the
  mapped DMA address
- Fix the problems with iommu faults on newer platforms
- Generalize the LOCK/UNLOCK flags in dmaengine and reword the docs and
  commit messages
- Make the BAM locking logic stricter in the DMA engine driver
- Add some additional minor QCE driver refactoring changes to the series
- Lots of small reworks and tweaks to rebase on current mainline and fix
  previous issues
- Link to v7: https://lore.kernel.org/all/20250311-qce-cmd-descr-v7-0-db613f5d9c9f at linaro.org/

Changes in v7:
- remove unused code: writing to multiple registers was not used in v6,
  neither were the functions for reading registers over BAM DMA-
- remove
- don't read the SW_VERSION register needlessly in the BAM driver,
  instead: encode the information on whether the IP supports BAM locking
  in device match data
- shrink code where possible with logic modifications (for instance:
  change the implementation of qce_write() instead of replacing it
  everywhere with a new symbol)
- remove duplicated error messages
- rework commit messages
- a lot of shuffling code around for easier review and a more
  streamlined series
- Link to v6: https://lore.kernel.org/all/20250115103004.3350561-1-quic_mdalam at quicinc.com/

Changes in v6:
- change "BAM" to "DMA"
- Ensured this series is compilable with the current Linux-next tip of
  the tree (TOT).

Changes in v5:
- Added DMA_PREP_LOCK and DMA_PREP_UNLOCK flag support in separate patch
- Removed DMA_PREP_LOCK & DMA_PREP_UNLOCK flag
- Added FIELD_GET and GENMASK macro to extract major and minor version

Changes in v4:
- Added feature description and test hardware
  with test command
- Fixed patch version numbering
- Dropped dt-binding patch
- Dropped device tree changes
- Added BAM_SW_VERSION register read
- Handled the error path for the api dma_map_resource()
  in probe
- updated the commit messages for batter redability
- Squash the change where qce_bam_acquire_lock() and
  qce_bam_release_lock() api got introduce to the change where
  the lock/unlock flag get introced
- changed cover letter subject heading to
  "dmaengine: qcom: bam_dma: add cmd descriptor support"
- Added the very initial post for BAM lock/unlock patch link
  as v1 to track this feature

Changes in v3:
- https://lore.kernel.org/lkml/183d4f5e-e00a-8ef6-a589-f5704bc83d4a at quicinc.com/
- Addressed all the comments from v2
- Added the dt-binding
- Fix alignment issue
- Removed type casting from qce_write_reg_dma()
  and qce_read_reg_dma()
- Removed qce_bam_txn = dma->qce_bam_txn; line from
  qce_alloc_bam_txn() api and directly returning
  dma->qce_bam_txn

Changes in v2:
- https://lore.kernel.org/lkml/20231214114239.2635325-1-quic_mdalam at quicinc.com/
- Initial set of patches for cmd descriptor support
- Add client driver to use BAM lock/unlock feature
- Added register read/write via BAM in QCE Crypto driver
  to use BAM lock/unlock feature

---
Bartosz Golaszewski (12):
      dmaengine: constify struct dma_descriptor_metadata_ops
      dmaengine: qcom: bam_dma: Extend the driver's device match data
      dmaengine: qcom: bam_dma: Add bam_pipe_lock flag support
      dmaengine: qcom: bam_dma: implement support for BAM locking
      crypto: qce - Include algapi.h in the core.h header
      crypto: qce - Remove unused ignore_buf
      crypto: qce - Simplify arguments of devm_qce_dma_request()
      crypto: qce - Use existing devres APIs in devm_qce_dma_request()
      crypto: qce - Map crypto memory for DMA
      crypto: qce - Add BAM DMA support for crypto register I/O
      crypto: qce - Add support for BAM locking
      crypto: qce - Switch to using BAM DMA for crypto I/O

 drivers/crypto/qce/aead.c        |  10 +++
 drivers/crypto/qce/common.c      |  39 ++++++---
 drivers/crypto/qce/core.c        |  28 ++++++-
 drivers/crypto/qce/core.h        |  11 +++
 drivers/crypto/qce/dma.c         | 174 +++++++++++++++++++++++++++++++++------
 drivers/crypto/qce/dma.h         |  15 +++-
 drivers/crypto/qce/sha.c         |   8 ++
 drivers/crypto/qce/skcipher.c    |   7 ++
 drivers/dma/qcom/bam_dma.c       |  92 +++++++++++++++++++--
 drivers/dma/ti/k3-udma.c         |   2 +-
 drivers/dma/xilinx/xilinx_dma.c  |   2 +-
 include/linux/dma/qcom_bam_dma.h |  12 +++
 include/linux/dmaengine.h        |   2 +-
 13 files changed, 347 insertions(+), 55 deletions(-)
---
base-commit: c138e425266a3f8fc801c82793a7084dfbc069b6
change-id: 20251103-qcom-qce-cmd-descr-c5e9b11fe609

Best regards,
-- 
Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>



From bartosz.golaszewski at oss.qualcomm.com  Fri Dec 19 02:07:41 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Fri, 19 Dec 2025 11:07:41 +0100
Subject: [PATCH v10 02/12] dmaengine: qcom: bam_dma: Extend the driver's
 device match data
In-Reply-To: <20251219-qcom-qce-cmd-descr-v10-0-ff7e4bf7dad4@oss.qualcomm.com>
References: <20251219-qcom-qce-cmd-descr-v10-0-ff7e4bf7dad4@oss.qualcomm.com>
Message-ID: <20251219-qcom-qce-cmd-descr-v10-2-ff7e4bf7dad4@oss.qualcomm.com>

From: Bartosz Golaszewski <bartosz.golaszewski at linaro.org>

In preparation for supporting the pipe locking feature flag, extend the
amount of information we can carry in device match data: create a
separate structure and make the register information one of its fields.
This way, in subsequent patches, it will be just a matter of adding a
new field to the device data.

Reviewed-by: Dmitry Baryshkov <lumag at kernel.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at linaro.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/dma/qcom/bam_dma.c | 28 ++++++++++++++++++++++------
 1 file changed, 22 insertions(+), 6 deletions(-)

diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c
index bcd8de9a9a12621a36b49c31bff96f474468be06..6f78e6b1674a0ff3deef4c3d1892a978555b3807 100644
--- a/drivers/dma/qcom/bam_dma.c
+++ b/drivers/dma/qcom/bam_dma.c
@@ -112,6 +112,10 @@ struct reg_offset_data {
 	unsigned int pipe_mult, evnt_mult, ee_mult;
 };
 
+struct bam_device_data {
+	const struct reg_offset_data *reg_info;
+};
+
 static const struct reg_offset_data bam_v1_3_reg_info[] = {
 	[BAM_CTRL]		= { 0x0F80, 0x00, 0x00, 0x00 },
 	[BAM_REVISION]		= { 0x0F84, 0x00, 0x00, 0x00 },
@@ -141,6 +145,10 @@ static const struct reg_offset_data bam_v1_3_reg_info[] = {
 	[BAM_P_FIFO_SIZES]	= { 0x1020, 0x00, 0x40, 0x00 },
 };
 
+static const struct bam_device_data bam_v1_3_data = {
+	.reg_info = bam_v1_3_reg_info,
+};
+
 static const struct reg_offset_data bam_v1_4_reg_info[] = {
 	[BAM_CTRL]		= { 0x0000, 0x00, 0x00, 0x00 },
 	[BAM_REVISION]		= { 0x0004, 0x00, 0x00, 0x00 },
@@ -170,6 +178,10 @@ static const struct reg_offset_data bam_v1_4_reg_info[] = {
 	[BAM_P_FIFO_SIZES]	= { 0x1820, 0x00, 0x1000, 0x00 },
 };
 
+static const struct bam_device_data bam_v1_4_data = {
+	.reg_info = bam_v1_4_reg_info,
+};
+
 static const struct reg_offset_data bam_v1_7_reg_info[] = {
 	[BAM_CTRL]		= { 0x00000, 0x00, 0x00, 0x00 },
 	[BAM_REVISION]		= { 0x01000, 0x00, 0x00, 0x00 },
@@ -199,6 +211,10 @@ static const struct reg_offset_data bam_v1_7_reg_info[] = {
 	[BAM_P_FIFO_SIZES]	= { 0x13820, 0x00, 0x1000, 0x00 },
 };
 
+static const struct bam_device_data bam_v1_7_data = {
+	.reg_info = bam_v1_7_reg_info,
+};
+
 /* BAM CTRL */
 #define BAM_SW_RST			BIT(0)
 #define BAM_EN				BIT(1)
@@ -392,7 +408,7 @@ struct bam_device {
 	bool powered_remotely;
 	u32 active_channels;
 
-	const struct reg_offset_data *layout;
+	const struct bam_device_data *dev_data;
 
 	struct clk *bamclk;
 	int irq;
@@ -410,7 +426,7 @@ struct bam_device {
 static inline void __iomem *bam_addr(struct bam_device *bdev, u32 pipe,
 		enum bam_reg reg)
 {
-	const struct reg_offset_data r = bdev->layout[reg];
+	const struct reg_offset_data r = bdev->dev_data->reg_info[reg];
 
 	return bdev->regs + r.base_offset +
 		r.pipe_mult * pipe +
@@ -1211,9 +1227,9 @@ static void bam_channel_init(struct bam_device *bdev, struct bam_chan *bchan,
 }
 
 static const struct of_device_id bam_of_match[] = {
-	{ .compatible = "qcom,bam-v1.3.0", .data = &bam_v1_3_reg_info },
-	{ .compatible = "qcom,bam-v1.4.0", .data = &bam_v1_4_reg_info },
-	{ .compatible = "qcom,bam-v1.7.0", .data = &bam_v1_7_reg_info },
+	{ .compatible = "qcom,bam-v1.3.0", .data = &bam_v1_3_data },
+	{ .compatible = "qcom,bam-v1.4.0", .data = &bam_v1_4_data },
+	{ .compatible = "qcom,bam-v1.7.0", .data = &bam_v1_7_data },
 	{}
 };
 
@@ -1237,7 +1253,7 @@ static int bam_dma_probe(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
-	bdev->layout = match->data;
+	bdev->dev_data = match->data;
 
 	bdev->regs = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(bdev->regs))

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Fri Dec 19 02:07:42 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Fri, 19 Dec 2025 11:07:42 +0100
Subject: [PATCH v10 03/12] dmaengine: qcom: bam_dma: Add bam_pipe_lock flag
 support
In-Reply-To: <20251219-qcom-qce-cmd-descr-v10-0-ff7e4bf7dad4@oss.qualcomm.com>
References: <20251219-qcom-qce-cmd-descr-v10-0-ff7e4bf7dad4@oss.qualcomm.com>
Message-ID: <20251219-qcom-qce-cmd-descr-v10-3-ff7e4bf7dad4@oss.qualcomm.com>

From: Bartosz Golaszewski <bartosz.golaszewski at linaro.org>

Extend the device match data with a flag indicating whether the IP
supports the BAM lock/unlock feature. Set it to true on BAM IP versions
1.4.0 and above.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at linaro.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/dma/qcom/bam_dma.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c
index 6f78e6b1674a0ff3deef4c3d1892a978555b3807..0ce9153da67032dc8ce910f68d1f80019d8b29f4 100644
--- a/drivers/dma/qcom/bam_dma.c
+++ b/drivers/dma/qcom/bam_dma.c
@@ -114,6 +114,7 @@ struct reg_offset_data {
 
 struct bam_device_data {
 	const struct reg_offset_data *reg_info;
+	bool bam_pipe_lock;
 };
 
 static const struct reg_offset_data bam_v1_3_reg_info[] = {
@@ -180,6 +181,7 @@ static const struct reg_offset_data bam_v1_4_reg_info[] = {
 
 static const struct bam_device_data bam_v1_4_data = {
 	.reg_info = bam_v1_4_reg_info,
+	.bam_pipe_lock = true,
 };
 
 static const struct reg_offset_data bam_v1_7_reg_info[] = {
@@ -213,6 +215,7 @@ static const struct reg_offset_data bam_v1_7_reg_info[] = {
 
 static const struct bam_device_data bam_v1_7_data = {
 	.reg_info = bam_v1_7_reg_info,
+	.bam_pipe_lock = true,
 };
 
 /* BAM CTRL */

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Fri Dec 19 02:07:43 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Fri, 19 Dec 2025 11:07:43 +0100
Subject: [PATCH v10 04/12] dmaengine: qcom: bam_dma: implement support for
 BAM locking
In-Reply-To: <20251219-qcom-qce-cmd-descr-v10-0-ff7e4bf7dad4@oss.qualcomm.com>
References: <20251219-qcom-qce-cmd-descr-v10-0-ff7e4bf7dad4@oss.qualcomm.com>
Message-ID: <20251219-qcom-qce-cmd-descr-v10-4-ff7e4bf7dad4@oss.qualcomm.com>

From: Bartosz Golaszewski <bartosz.golaszewski at linaro.org>

Use metadata operations in DMA descriptors to allow BAM users to pass
additional information to the engine. To that end: define a new
structure - struct bam_desc_metadata - as a medium and define two new
commands: for locking and unlocking the BAM respectively. Handle the
locking in the .attach() callback.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at linaro.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/dma/qcom/bam_dma.c       | 61 +++++++++++++++++++++++++++++++++++++++-
 include/linux/dma/qcom_bam_dma.h | 12 ++++++++
 2 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c
index 0ce9153da67032dc8ce910f68d1f80019d8b29f4..e35fc73a53aaa2a6b999b189add7d72df15ebf0b 100644
--- a/drivers/dma/qcom/bam_dma.c
+++ b/drivers/dma/qcom/bam_dma.c
@@ -28,6 +28,7 @@
 #include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
+#include <linux/dma/qcom_bam_dma.h>
 #include <linux/dmaengine.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
@@ -59,6 +60,8 @@ struct bam_desc_hw {
 #define DESC_FLAG_EOB BIT(13)
 #define DESC_FLAG_NWD BIT(12)
 #define DESC_FLAG_CMD BIT(11)
+#define DESC_FLAG_LOCK BIT(10)
+#define DESC_FLAG_UNLOCK BIT(9)
 
 struct bam_async_desc {
 	struct virt_dma_desc vd;
@@ -390,6 +393,8 @@ struct bam_chan {
 	struct list_head desc_list;
 
 	struct list_head node;
+
+	bool bam_locked;
 };
 
 static inline struct bam_chan *to_bam_chan(struct dma_chan *common)
@@ -651,6 +656,53 @@ static int bam_slave_config(struct dma_chan *chan,
 	return 0;
 }
 
+static int bam_metadata_attach(struct dma_async_tx_descriptor *desc, void *data, size_t len)
+{
+	struct virt_dma_desc *vd = container_of(desc, struct virt_dma_desc, tx);
+	struct bam_async_desc *async_desc = container_of(vd, struct bam_async_desc,  vd);
+	struct bam_desc_hw *hw_desc = async_desc->desc;
+	struct bam_desc_metadata *metadata = data;
+	struct bam_chan *bchan = to_bam_chan(metadata->chan);
+	struct bam_device *bdev = bchan->bdev;
+
+	if (!data)
+		return -EINVAL;
+
+	if (metadata->op == BAM_META_CMD_LOCK || metadata->op == BAM_META_CMD_UNLOCK) {
+		if (!bdev->dev_data->bam_pipe_lock)
+			return -EOPNOTSUPP;
+
+		/* Expecting a dummy write when locking, only one descriptor allowed. */
+		if (async_desc->num_desc != 1)
+			return -EINVAL;
+	}
+
+	switch (metadata->op) {
+	case BAM_META_CMD_LOCK:
+		if (bchan->bam_locked)
+			return -EBUSY;
+
+		hw_desc->flags |= DESC_FLAG_LOCK;
+		bchan->bam_locked = true;
+		break;
+	case BAM_META_CMD_UNLOCK:
+		if (!bchan->bam_locked)
+			return -EPERM;
+
+		hw_desc->flags |= DESC_FLAG_UNLOCK;
+		bchan->bam_locked = false;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static const struct dma_descriptor_metadata_ops bam_metadata_ops = {
+	.attach = bam_metadata_attach,
+};
+
 /**
  * bam_prep_slave_sg - Prep slave sg transaction
  *
@@ -667,6 +719,7 @@ static struct dma_async_tx_descriptor *bam_prep_slave_sg(struct dma_chan *chan,
 	void *context)
 {
 	struct bam_chan *bchan = to_bam_chan(chan);
+	struct dma_async_tx_descriptor *tx_desc;
 	struct bam_device *bdev = bchan->bdev;
 	struct bam_async_desc *async_desc;
 	struct scatterlist *sg;
@@ -728,7 +781,12 @@ static struct dma_async_tx_descriptor *bam_prep_slave_sg(struct dma_chan *chan,
 		} while (remainder > 0);
 	}
 
-	return vchan_tx_prep(&bchan->vc, &async_desc->vd, flags);
+	tx_desc = vchan_tx_prep(&bchan->vc, &async_desc->vd, flags);
+	if (!tx_desc)
+		return NULL;
+
+	tx_desc->metadata_ops = &bam_metadata_ops;
+	return tx_desc;
 }
 
 /**
@@ -1356,6 +1414,7 @@ static int bam_dma_probe(struct platform_device *pdev)
 	bdev->common.device_terminate_all = bam_dma_terminate_all;
 	bdev->common.device_issue_pending = bam_issue_pending;
 	bdev->common.device_tx_status = bam_tx_status;
+	bdev->common.desc_metadata_modes = DESC_METADATA_CLIENT;
 	bdev->common.dev = bdev->dev;
 
 	ret = dma_async_device_register(&bdev->common);
diff --git a/include/linux/dma/qcom_bam_dma.h b/include/linux/dma/qcom_bam_dma.h
index 68fc0e643b1b97fe4520d5878daa322b81f4f559..dd30bb9c520fac7bd98c5a47e56a5a286331461a 100644
--- a/include/linux/dma/qcom_bam_dma.h
+++ b/include/linux/dma/qcom_bam_dma.h
@@ -8,6 +8,8 @@
 
 #include <asm/byteorder.h>
 
+struct dma_chan;
+
 /*
  * This data type corresponds to the native Command Element
  * supported by BAM DMA Engine.
@@ -34,6 +36,16 @@ enum bam_command_type {
 	BAM_READ_COMMAND,
 };
 
+enum bam_desc_metadata_op {
+	BAM_META_CMD_LOCK = 1,
+	BAM_META_CMD_UNLOCK,
+};
+
+struct bam_desc_metadata {
+	enum bam_desc_metadata_op op;
+	struct dma_chan *chan;
+};
+
 /*
  * prep_bam_ce_le32 - Wrapper function to prepare a single BAM command
  * element with the data already in le32 format.

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Fri Dec 19 02:07:40 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Fri, 19 Dec 2025 11:07:40 +0100
Subject: [PATCH v10 01/12] dmaengine: constify struct
 dma_descriptor_metadata_ops
In-Reply-To: <20251219-qcom-qce-cmd-descr-v10-0-ff7e4bf7dad4@oss.qualcomm.com>
References: <20251219-qcom-qce-cmd-descr-v10-0-ff7e4bf7dad4@oss.qualcomm.com>
Message-ID: <20251219-qcom-qce-cmd-descr-v10-1-ff7e4bf7dad4@oss.qualcomm.com>

There's no reason for the instances of this struct to be modifiable.
Constify the pointer in struct dma_async_tx_descriptor and all drivers
currently using it.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/dma/ti/k3-udma.c        | 2 +-
 drivers/dma/xilinx/xilinx_dma.c | 2 +-
 include/linux/dmaengine.h       | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c
index aa2dc762140f6eee334f4506a592e72600ae9834..75c8eed063af8daf68cd68670abba211740dd11e 100644
--- a/drivers/dma/ti/k3-udma.c
+++ b/drivers/dma/ti/k3-udma.c
@@ -3408,7 +3408,7 @@ static int udma_set_metadata_len(struct dma_async_tx_descriptor *desc,
 	return 0;
 }
 
-static struct dma_descriptor_metadata_ops metadata_ops = {
+static const struct dma_descriptor_metadata_ops metadata_ops = {
 	.attach = udma_attach_metadata,
 	.get_ptr = udma_get_metadata_ptr,
 	.set_len = udma_set_metadata_len,
diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index fabff602065f6cba23cff7bb4f305a3504230a02..e2a40e8dd4b20379f337c1017f8accebeb914645 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -652,7 +652,7 @@ static void *xilinx_dma_get_metadata_ptr(struct dma_async_tx_descriptor *tx,
 	return seg->hw.app;
 }
 
-static struct dma_descriptor_metadata_ops xilinx_dma_metadata_ops = {
+static const struct dma_descriptor_metadata_ops xilinx_dma_metadata_ops = {
 	.get_ptr = xilinx_dma_get_metadata_ptr,
 };
 
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 99efe2b9b4ea9844ca6161208362ef18ef111d96..92566c4c100e98f48750de21249ae3b5de06c763 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -623,7 +623,7 @@ struct dma_async_tx_descriptor {
 	void *callback_param;
 	struct dmaengine_unmap_data *unmap;
 	enum dma_desc_metadata_mode desc_metadata_mode;
-	struct dma_descriptor_metadata_ops *metadata_ops;
+	const struct dma_descriptor_metadata_ops *metadata_ops;
 #ifdef CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH
 	struct dma_async_tx_descriptor *next;
 	struct dma_async_tx_descriptor *parent;

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Fri Dec 19 02:07:44 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Fri, 19 Dec 2025 11:07:44 +0100
Subject: [PATCH v10 05/12] crypto: qce - Include algapi.h in the core.h
 header
In-Reply-To: <20251219-qcom-qce-cmd-descr-v10-0-ff7e4bf7dad4@oss.qualcomm.com>
References: <20251219-qcom-qce-cmd-descr-v10-0-ff7e4bf7dad4@oss.qualcomm.com>
Message-ID: <20251219-qcom-qce-cmd-descr-v10-5-ff7e4bf7dad4@oss.qualcomm.com>

From: Bartosz Golaszewski <bartosz.golaszewski at linaro.org>

The header defines a struct embedding struct crypto_queue whose size
needs to be known and which is defined in crypto/algapi.h. Move the
inclusion from core.c to core.h.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at linaro.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/crypto/qce/core.c | 1 -
 drivers/crypto/qce/core.h | 1 +
 2 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/crypto/qce/core.c b/drivers/crypto/qce/core.c
index b966f3365b7de8d2a8f6707397a34aa4facdc4ac..65205100c3df961ffaa4b7bc9e217e8d3e08ed57 100644
--- a/drivers/crypto/qce/core.c
+++ b/drivers/crypto/qce/core.c
@@ -13,7 +13,6 @@
 #include <linux/mod_devicetable.h>
 #include <linux/platform_device.h>
 #include <linux/types.h>
-#include <crypto/algapi.h>
 #include <crypto/internal/hash.h>
 
 #include "core.h"
diff --git a/drivers/crypto/qce/core.h b/drivers/crypto/qce/core.h
index eb6fa7a8b64a81daf9ad5304a3ae4e5e597a70b8..f092ce2d3b04a936a37805c20ac5ba78d8fdd2df 100644
--- a/drivers/crypto/qce/core.h
+++ b/drivers/crypto/qce/core.h
@@ -8,6 +8,7 @@
 
 #include <linux/mutex.h>
 #include <linux/workqueue.h>
+#include <crypto/algapi.h>
 
 #include "dma.h"
 

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Fri Dec 19 02:07:45 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Fri, 19 Dec 2025 11:07:45 +0100
Subject: [PATCH v10 06/12] crypto: qce - Remove unused ignore_buf
In-Reply-To: <20251219-qcom-qce-cmd-descr-v10-0-ff7e4bf7dad4@oss.qualcomm.com>
References: <20251219-qcom-qce-cmd-descr-v10-0-ff7e4bf7dad4@oss.qualcomm.com>
Message-ID: <20251219-qcom-qce-cmd-descr-v10-6-ff7e4bf7dad4@oss.qualcomm.com>

From: Bartosz Golaszewski <bartosz.golaszewski at linaro.org>

It's unclear what the purpose of this field is. It has been here since
the initial commit but without any explanation. The driver works fine
without it. We still keep allocating more space in the result buffer, we
just don't need to store its address. While at it: move the
QCE_IGNORE_BUF_SZ definition into dma.c as it's not used outside of this
compilation unit.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at linaro.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/crypto/qce/dma.c | 4 ++--
 drivers/crypto/qce/dma.h | 2 --
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/crypto/qce/dma.c b/drivers/crypto/qce/dma.c
index 68cafd4741ad3d91906d39e817fc7873b028d498..08bf3e8ec12433c1a8ee17003f3487e41b7329e4 100644
--- a/drivers/crypto/qce/dma.c
+++ b/drivers/crypto/qce/dma.c
@@ -9,6 +9,8 @@
 
 #include "dma.h"
 
+#define QCE_IGNORE_BUF_SZ		(2 * QCE_BAM_BURST_SIZE)
+
 static void qce_dma_release(void *data)
 {
 	struct qce_dma_data *dma = data;
@@ -41,8 +43,6 @@ int devm_qce_dma_request(struct device *dev, struct qce_dma_data *dma)
 		goto error_nomem;
 	}
 
-	dma->ignore_buf = dma->result_buf + QCE_RESULT_BUF_SZ;
-
 	return devm_add_action_or_reset(dev, qce_dma_release, dma);
 
 error_nomem:
diff --git a/drivers/crypto/qce/dma.h b/drivers/crypto/qce/dma.h
index 31629185000e12242fa07c2cc08b95fcbd5d4b8c..fc337c435cd14917bdfb99febcf9119275afdeba 100644
--- a/drivers/crypto/qce/dma.h
+++ b/drivers/crypto/qce/dma.h
@@ -23,7 +23,6 @@ struct qce_result_dump {
 	u32 status2;
 };
 
-#define QCE_IGNORE_BUF_SZ	(2 * QCE_BAM_BURST_SIZE)
 #define QCE_RESULT_BUF_SZ	\
 		ALIGN(sizeof(struct qce_result_dump), QCE_BAM_BURST_SIZE)
 
@@ -31,7 +30,6 @@ struct qce_dma_data {
 	struct dma_chan *txchan;
 	struct dma_chan *rxchan;
 	struct qce_result_dump *result_buf;
-	void *ignore_buf;
 };
 
 int devm_qce_dma_request(struct device *dev, struct qce_dma_data *dma);

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Fri Dec 19 02:07:46 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Fri, 19 Dec 2025 11:07:46 +0100
Subject: [PATCH v10 07/12] crypto: qce - Simplify arguments of
 devm_qce_dma_request()
In-Reply-To: <20251219-qcom-qce-cmd-descr-v10-0-ff7e4bf7dad4@oss.qualcomm.com>
References: <20251219-qcom-qce-cmd-descr-v10-0-ff7e4bf7dad4@oss.qualcomm.com>
Message-ID: <20251219-qcom-qce-cmd-descr-v10-7-ff7e4bf7dad4@oss.qualcomm.com>

From: Bartosz Golaszewski <bartosz.golaszewski at linaro.org>

This function can extract all the information it needs from struct
qce_device alone so simplify its arguments. This is done in preparation
for adding support for register I/O over DMA which will require
accessing even more fields from struct qce_device.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at linaro.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/crypto/qce/core.c | 2 +-
 drivers/crypto/qce/dma.c  | 5 ++++-
 drivers/crypto/qce/dma.h  | 4 +++-
 3 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/drivers/crypto/qce/core.c b/drivers/crypto/qce/core.c
index 65205100c3df961ffaa4b7bc9e217e8d3e08ed57..8b7bcd0c420c45caf8b29e5455e0f384fd5c5616 100644
--- a/drivers/crypto/qce/core.c
+++ b/drivers/crypto/qce/core.c
@@ -226,7 +226,7 @@ static int qce_crypto_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	ret = devm_qce_dma_request(qce->dev, &qce->dma);
+	ret = devm_qce_dma_request(qce);
 	if (ret)
 		return ret;
 
diff --git a/drivers/crypto/qce/dma.c b/drivers/crypto/qce/dma.c
index 08bf3e8ec12433c1a8ee17003f3487e41b7329e4..c29b0abe9445381a019e0447d30acfd7319d5c1f 100644
--- a/drivers/crypto/qce/dma.c
+++ b/drivers/crypto/qce/dma.c
@@ -7,6 +7,7 @@
 #include <linux/dmaengine.h>
 #include <crypto/scatterwalk.h>
 
+#include "core.h"
 #include "dma.h"
 
 #define QCE_IGNORE_BUF_SZ		(2 * QCE_BAM_BURST_SIZE)
@@ -20,8 +21,10 @@ static void qce_dma_release(void *data)
 	kfree(dma->result_buf);
 }
 
-int devm_qce_dma_request(struct device *dev, struct qce_dma_data *dma)
+int devm_qce_dma_request(struct qce_device *qce)
 {
+	struct qce_dma_data *dma = &qce->dma;
+	struct device *dev = qce->dev;
 	int ret;
 
 	dma->txchan = dma_request_chan(dev, "tx");
diff --git a/drivers/crypto/qce/dma.h b/drivers/crypto/qce/dma.h
index fc337c435cd14917bdfb99febcf9119275afdeba..483789d9fa98e79d1283de8297bf2fc2a773f3a7 100644
--- a/drivers/crypto/qce/dma.h
+++ b/drivers/crypto/qce/dma.h
@@ -8,6 +8,8 @@
 
 #include <linux/dmaengine.h>
 
+struct qce_device;
+
 /* maximum data transfer block size between BAM and CE */
 #define QCE_BAM_BURST_SIZE		64
 
@@ -32,7 +34,7 @@ struct qce_dma_data {
 	struct qce_result_dump *result_buf;
 };
 
-int devm_qce_dma_request(struct device *dev, struct qce_dma_data *dma);
+int devm_qce_dma_request(struct qce_device *qce);
 int qce_dma_prep_sgs(struct qce_dma_data *dma, struct scatterlist *sg_in,
 		     int in_ents, struct scatterlist *sg_out, int out_ents,
 		     dma_async_tx_callback cb, void *cb_param);

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Fri Dec 19 02:07:47 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Fri, 19 Dec 2025 11:07:47 +0100
Subject: [PATCH v10 08/12] crypto: qce - Use existing devres APIs in
 devm_qce_dma_request()
In-Reply-To: <20251219-qcom-qce-cmd-descr-v10-0-ff7e4bf7dad4@oss.qualcomm.com>
References: <20251219-qcom-qce-cmd-descr-v10-0-ff7e4bf7dad4@oss.qualcomm.com>
Message-ID: <20251219-qcom-qce-cmd-descr-v10-8-ff7e4bf7dad4@oss.qualcomm.com>

From: Bartosz Golaszewski <bartosz.golaszewski at linaro.org>

Switch to devm_kmalloc() and devm_dma_alloc_chan() in
devm_qce_dma_request(). This allows us to drop two labels and shrink the
function.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at linaro.org>
Reviewed-by: Konrad Dybcio <konrad.dybcio at oss.qualcomm.com>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/crypto/qce/dma.c | 39 +++++++++------------------------------
 1 file changed, 9 insertions(+), 30 deletions(-)

diff --git a/drivers/crypto/qce/dma.c b/drivers/crypto/qce/dma.c
index c29b0abe9445381a019e0447d30acfd7319d5c1f..a46264735bb895b6199969e83391383ccbbacc5f 100644
--- a/drivers/crypto/qce/dma.c
+++ b/drivers/crypto/qce/dma.c
@@ -12,47 +12,26 @@
 
 #define QCE_IGNORE_BUF_SZ		(2 * QCE_BAM_BURST_SIZE)
 
-static void qce_dma_release(void *data)
-{
-	struct qce_dma_data *dma = data;
-
-	dma_release_channel(dma->txchan);
-	dma_release_channel(dma->rxchan);
-	kfree(dma->result_buf);
-}
-
 int devm_qce_dma_request(struct qce_device *qce)
 {
 	struct qce_dma_data *dma = &qce->dma;
 	struct device *dev = qce->dev;
-	int ret;
 
-	dma->txchan = dma_request_chan(dev, "tx");
+	dma->txchan = devm_dma_request_chan(dev, "tx");
 	if (IS_ERR(dma->txchan))
 		return dev_err_probe(dev, PTR_ERR(dma->txchan),
 				     "Failed to get TX DMA channel\n");
 
-	dma->rxchan = dma_request_chan(dev, "rx");
-	if (IS_ERR(dma->rxchan)) {
-		ret = dev_err_probe(dev, PTR_ERR(dma->rxchan),
-				    "Failed to get RX DMA channel\n");
-		goto error_rx;
-	}
-
-	dma->result_buf = kmalloc(QCE_RESULT_BUF_SZ + QCE_IGNORE_BUF_SZ,
-				  GFP_KERNEL);
-	if (!dma->result_buf) {
-		ret = -ENOMEM;
-		goto error_nomem;
-	}
+	dma->rxchan = devm_dma_request_chan(dev, "rx");
+	if (IS_ERR(dma->rxchan))
+		return dev_err_probe(dev, PTR_ERR(dma->rxchan),
+				     "Failed to get RX DMA channel\n");
 
-	return devm_add_action_or_reset(dev, qce_dma_release, dma);
+	dma->result_buf = devm_kmalloc(dev, QCE_RESULT_BUF_SZ + QCE_IGNORE_BUF_SZ, GFP_KERNEL);
+	if (!dma->result_buf)
+		return -ENOMEM;
 
-error_nomem:
-	dma_release_channel(dma->rxchan);
-error_rx:
-	dma_release_channel(dma->txchan);
-	return ret;
+	return 0;
 }
 
 struct scatterlist *

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Fri Dec 19 02:07:48 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Fri, 19 Dec 2025 11:07:48 +0100
Subject: [PATCH v10 09/12] crypto: qce - Map crypto memory for DMA
In-Reply-To: <20251219-qcom-qce-cmd-descr-v10-0-ff7e4bf7dad4@oss.qualcomm.com>
References: <20251219-qcom-qce-cmd-descr-v10-0-ff7e4bf7dad4@oss.qualcomm.com>
Message-ID: <20251219-qcom-qce-cmd-descr-v10-9-ff7e4bf7dad4@oss.qualcomm.com>

From: Bartosz Golaszewski <bartosz.golaszewski at linaro.org>

As the first step in converting the driver to using DMA for register
I/O, let's map the crypto memory range.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at linaro.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/crypto/qce/core.c | 25 +++++++++++++++++++++++--
 drivers/crypto/qce/core.h |  6 ++++++
 2 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/drivers/crypto/qce/core.c b/drivers/crypto/qce/core.c
index 8b7bcd0c420c45caf8b29e5455e0f384fd5c5616..2667fcd67fee826a44080da8f88a3e2abbb9b2cf 100644
--- a/drivers/crypto/qce/core.c
+++ b/drivers/crypto/qce/core.c
@@ -185,10 +185,19 @@ static int qce_check_version(struct qce_device *qce)
 	return 0;
 }
 
+static void qce_crypto_unmap_dma(void *data)
+{
+	struct qce_device *qce = data;
+
+	dma_unmap_resource(qce->dev, qce->base_dma, qce->dma_size,
+			   DMA_BIDIRECTIONAL, 0);
+}
+
 static int qce_crypto_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct qce_device *qce;
+	struct resource *res;
 	int ret;
 
 	qce = devm_kzalloc(dev, sizeof(*qce), GFP_KERNEL);
@@ -198,7 +207,7 @@ static int qce_crypto_probe(struct platform_device *pdev)
 	qce->dev = dev;
 	platform_set_drvdata(pdev, qce);
 
-	qce->base = devm_platform_ioremap_resource(pdev, 0);
+	qce->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
 	if (IS_ERR(qce->base))
 		return PTR_ERR(qce->base);
 
@@ -244,7 +253,19 @@ static int qce_crypto_probe(struct platform_device *pdev)
 	qce->async_req_enqueue = qce_async_request_enqueue;
 	qce->async_req_done = qce_async_request_done;
 
-	return devm_qce_register_algs(qce);
+	ret = devm_qce_register_algs(qce);
+	if (ret)
+		return ret;
+
+	qce->dma_size = resource_size(res);
+	qce->base_dma = dma_map_resource(dev, res->start, qce->dma_size,
+					 DMA_BIDIRECTIONAL, 0);
+	qce->base_phys = res->start;
+	ret = dma_mapping_error(dev, qce->base_dma);
+	if (ret)
+		return ret;
+
+	return devm_add_action_or_reset(qce->dev, qce_crypto_unmap_dma, qce);
 }
 
 static const struct of_device_id qce_crypto_of_match[] = {
diff --git a/drivers/crypto/qce/core.h b/drivers/crypto/qce/core.h
index f092ce2d3b04a936a37805c20ac5ba78d8fdd2df..a80e12eac6c87e5321cce16c56a4bf5003474ef0 100644
--- a/drivers/crypto/qce/core.h
+++ b/drivers/crypto/qce/core.h
@@ -27,6 +27,9 @@
  * @dma: pointer to dma data
  * @burst_size: the crypto burst size
  * @pipe_pair_id: which pipe pair id the device using
+ * @base_dma: base DMA address
+ * @base_phys: base physical address
+ * @dma_size: size of memory mapped for DMA
  * @async_req_enqueue: invoked by every algorithm to enqueue a request
  * @async_req_done: invoked by every algorithm to finish its request
  */
@@ -43,6 +46,9 @@ struct qce_device {
 	struct qce_dma_data dma;
 	int burst_size;
 	unsigned int pipe_pair_id;
+	dma_addr_t base_dma;
+	phys_addr_t base_phys;
+	size_t dma_size;
 	int (*async_req_enqueue)(struct qce_device *qce,
 				 struct crypto_async_request *req);
 	void (*async_req_done)(struct qce_device *qce, int ret);

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Fri Dec 19 02:07:50 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Fri, 19 Dec 2025 11:07:50 +0100
Subject: [PATCH v10 11/12] crypto: qce - Add support for BAM locking
In-Reply-To: <20251219-qcom-qce-cmd-descr-v10-0-ff7e4bf7dad4@oss.qualcomm.com>
References: <20251219-qcom-qce-cmd-descr-v10-0-ff7e4bf7dad4@oss.qualcomm.com>
Message-ID: <20251219-qcom-qce-cmd-descr-v10-11-ff7e4bf7dad4@oss.qualcomm.com>

From: Bartosz Golaszewski <bartosz.golaszewski at linaro.org>

Implement the infrastructure for using the new DMA controller lock/unlock
feature of the BAM driver. No functional change for now.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at linaro.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/crypto/qce/common.c | 18 ++++++++++++++++++
 drivers/crypto/qce/dma.c    | 39 ++++++++++++++++++++++++++++++++++-----
 drivers/crypto/qce/dma.h    |  4 ++++
 3 files changed, 56 insertions(+), 5 deletions(-)

diff --git a/drivers/crypto/qce/common.c b/drivers/crypto/qce/common.c
index 04253a8d33409a2a51db527435d09ae85a7880af..292fb3c7bbd3d6f096bbdc3c66d37d11e9ea109a 100644
--- a/drivers/crypto/qce/common.c
+++ b/drivers/crypto/qce/common.c
@@ -593,3 +593,21 @@ void qce_get_version(struct qce_device *qce, u32 *major, u32 *minor, u32 *step)
 	*minor = (val & CORE_MINOR_REV_MASK) >> CORE_MINOR_REV_SHIFT;
 	*step = (val & CORE_STEP_REV_MASK) >> CORE_STEP_REV_SHIFT;
 }
+
+int qce_bam_lock(struct qce_device *qce)
+{
+	qce_clear_bam_transaction(qce);
+	/* Dummy write to acquire the lock on the BAM pipe. */
+	qce_write(qce, REG_VERSION, 0);
+
+	return qce_submit_cmd_desc_lock(qce);
+}
+
+int qce_bam_unlock(struct qce_device *qce)
+{
+	qce_clear_bam_transaction(qce);
+	/* Dummy write to release the lock on the BAM pipe. */
+	qce_write(qce, REG_VERSION, 0);
+
+	return qce_submit_cmd_desc_unlock(qce);
+}
diff --git a/drivers/crypto/qce/dma.c b/drivers/crypto/qce/dma.c
index ba7a52fd4c6349d59c075c346f75741defeb6034..885053955ac3dc95efefef541907f57844b60a3d 100644
--- a/drivers/crypto/qce/dma.c
+++ b/drivers/crypto/qce/dma.c
@@ -41,7 +41,7 @@ void qce_clear_bam_transaction(struct qce_device *qce)
 	bam_txn->pre_bam_ce_idx = 0;
 }
 
-int qce_submit_cmd_desc(struct qce_device *qce)
+static int qce_do_submit_cmd_desc(struct qce_device *qce, struct bam_desc_metadata *meta)
 {
 	struct qce_desc_info *qce_desc = qce->dma.bam_txn->desc;
 	struct qce_bam_transaction *bam_txn = qce->dma.bam_txn;
@@ -50,7 +50,7 @@ int qce_submit_cmd_desc(struct qce_device *qce)
 	unsigned long attrs = DMA_PREP_CMD;
 	dma_cookie_t cookie;
 	unsigned int mapped;
-	int ret;
+	int ret = -ENOMEM;
 
 	mapped = dma_map_sg_attrs(qce->dev, bam_txn->wr_sgl, bam_txn->wr_sgl_cnt,
 				  DMA_TO_DEVICE, attrs);
@@ -59,9 +59,15 @@ int qce_submit_cmd_desc(struct qce_device *qce)
 
 	dma_desc = dmaengine_prep_slave_sg(chan, bam_txn->wr_sgl, bam_txn->wr_sgl_cnt,
 					   DMA_MEM_TO_DEV, attrs);
-	if (!dma_desc) {
-		dma_unmap_sg(qce->dev, bam_txn->wr_sgl, bam_txn->wr_sgl_cnt, DMA_TO_DEVICE);
-		return -ENOMEM;
+	if (!dma_desc)
+		goto err_out;
+
+	if (meta) {
+		meta->chan = chan;
+
+		ret = dmaengine_desc_attach_metadata(dma_desc, meta, 0);
+		if (ret)
+			goto err_out;
 	}
 
 	qce_desc->dma_desc = dma_desc;
@@ -74,6 +80,29 @@ int qce_submit_cmd_desc(struct qce_device *qce)
 	qce_dma_issue_pending(&qce->dma);
 
 	return 0;
+
+err_out:
+	dma_unmap_sg(qce->dev, bam_txn->wr_sgl, bam_txn->wr_sgl_cnt, DMA_TO_DEVICE);
+	return ret;
+}
+
+int qce_submit_cmd_desc(struct qce_device *qce)
+{
+	return qce_do_submit_cmd_desc(qce, NULL);
+}
+
+int qce_submit_cmd_desc_lock(struct qce_device *qce)
+{
+	struct bam_desc_metadata meta = { .op = BAM_META_CMD_LOCK, };
+
+	return qce_do_submit_cmd_desc(qce, &meta);
+}
+
+int qce_submit_cmd_desc_unlock(struct qce_device *qce)
+{
+	struct bam_desc_metadata meta = { .op = BAM_META_CMD_UNLOCK };
+
+	return qce_do_submit_cmd_desc(qce, &meta);
 }
 
 static void qce_prep_dma_cmd_desc(struct qce_device *qce, struct qce_dma_data *dma,
diff --git a/drivers/crypto/qce/dma.h b/drivers/crypto/qce/dma.h
index f05dfa9e6b25bd60e32f45079a8bc7e6a4cf81f9..4b3ee17db72e29b9f417994477ad8a0ec2294db1 100644
--- a/drivers/crypto/qce/dma.h
+++ b/drivers/crypto/qce/dma.h
@@ -47,6 +47,10 @@ qce_sgtable_add(struct sg_table *sgt, struct scatterlist *sg_add,
 		unsigned int max_len);
 void qce_write_dma(struct qce_device *qce, unsigned int offset, u32 val);
 int qce_submit_cmd_desc(struct qce_device *qce);
+int qce_submit_cmd_desc_lock(struct qce_device *qce);
+int qce_submit_cmd_desc_unlock(struct qce_device *qce);
 void qce_clear_bam_transaction(struct qce_device *qce);
+int qce_bam_lock(struct qce_device *qce);
+int qce_bam_unlock(struct qce_device *qce);
 
 #endif /* _DMA_H_ */

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Fri Dec 19 02:07:51 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Fri, 19 Dec 2025 11:07:51 +0100
Subject: [PATCH v10 12/12] crypto: qce - Switch to using BAM DMA for crypto
 I/O
In-Reply-To: <20251219-qcom-qce-cmd-descr-v10-0-ff7e4bf7dad4@oss.qualcomm.com>
References: <20251219-qcom-qce-cmd-descr-v10-0-ff7e4bf7dad4@oss.qualcomm.com>
Message-ID: <20251219-qcom-qce-cmd-descr-v10-12-ff7e4bf7dad4@oss.qualcomm.com>

From: Bartosz Golaszewski <bartosz.golaszewski at linaro.org>

With everything else in place, we can now switch to actually using the
BAM DMA for register I/O with DMA engine locking.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at linaro.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/crypto/qce/aead.c     | 10 ++++++++++
 drivers/crypto/qce/common.c   | 21 ++++++++++-----------
 drivers/crypto/qce/sha.c      |  8 ++++++++
 drivers/crypto/qce/skcipher.c |  7 +++++++
 4 files changed, 35 insertions(+), 11 deletions(-)

diff --git a/drivers/crypto/qce/aead.c b/drivers/crypto/qce/aead.c
index 11cec08544c912e562bf4b33d9a409f0e69a0ada..0fc69b019929342e14d3af8e24d7629ab171bc60 100644
--- a/drivers/crypto/qce/aead.c
+++ b/drivers/crypto/qce/aead.c
@@ -63,6 +63,10 @@ static void qce_aead_done(void *data)
 		sg_free_table(&rctx->dst_tbl);
 	}
 
+	error = qce_bam_unlock(qce);
+	if (error)
+		dev_err(qce->dev, "aead: failed to unlock the BAM\n");
+
 	error = qce_check_status(qce, &status);
 	if (error < 0 && (error != -EBADMSG))
 		dev_err(qce->dev, "aead operation error (%x)\n", status);
@@ -188,6 +192,8 @@ qce_aead_ccm_prepare_buf_assoclen(struct aead_request *req)
 	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
 	struct qce_aead_reqctx *rctx = aead_request_ctx_dma(req);
 	struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct qce_alg_template *tmpl = to_aead_tmpl(crypto_aead_reqtfm(req));
+	struct qce_device *qce = tmpl->qce;
 	unsigned int assoclen = rctx->assoclen;
 	unsigned int adata_header_len, cryptlen, totallen;
 	gfp_t gfp;
@@ -200,6 +206,10 @@ qce_aead_ccm_prepare_buf_assoclen(struct aead_request *req)
 		cryptlen = rctx->cryptlen;
 	totallen = cryptlen + req->assoclen;
 
+	ret = qce_bam_lock(qce);
+	if (ret)
+		return ret;
+
 	/* Get the msg */
 	msg_sg = scatterwalk_ffwd(__sg, req->src, req->assoclen);
 
diff --git a/drivers/crypto/qce/common.c b/drivers/crypto/qce/common.c
index 292fb3c7bbd3d6f096bbdc3c66d37d11e9ea109a..84d6d49a56378a84d2e54f35bbe69ce24ff8fe3e 100644
--- a/drivers/crypto/qce/common.c
+++ b/drivers/crypto/qce/common.c
@@ -14,6 +14,7 @@
 #include "cipher.h"
 #include "common.h"
 #include "core.h"
+#include "dma.h"
 #include "regs-v5.h"
 #include "sha.h"
 #include "aead.h"
@@ -25,7 +26,7 @@ static inline u32 qce_read(struct qce_device *qce, u32 offset)
 
 static inline void qce_write(struct qce_device *qce, u32 offset, u32 val)
 {
-	writel(val, qce->base + offset);
+	qce_write_dma(qce, offset, val);
 }
 
 static inline void qce_write_array(struct qce_device *qce, u32 offset,
@@ -82,6 +83,8 @@ static void qce_setup_config(struct qce_device *qce)
 {
 	u32 config;
 
+	qce_clear_bam_transaction(qce);
+
 	/* get big endianness */
 	config = qce_config_reg(qce, 0);
 
@@ -90,12 +93,14 @@ static void qce_setup_config(struct qce_device *qce)
 	qce_write(qce, REG_CONFIG, config);
 }
 
-static inline void qce_crypto_go(struct qce_device *qce, bool result_dump)
+static int qce_crypto_go(struct qce_device *qce, bool result_dump)
 {
 	if (result_dump)
 		qce_write(qce, REG_GOPROC, BIT(GO_SHIFT) | BIT(RESULTS_DUMP_SHIFT));
 	else
 		qce_write(qce, REG_GOPROC, BIT(GO_SHIFT));
+
+	return qce_submit_cmd_desc(qce);
 }
 
 #if defined(CONFIG_CRYPTO_DEV_QCE_SHA) || defined(CONFIG_CRYPTO_DEV_QCE_AEAD)
@@ -223,9 +228,7 @@ static int qce_setup_regs_ahash(struct crypto_async_request *async_req)
 	config = qce_config_reg(qce, 1);
 	qce_write(qce, REG_CONFIG, config);
 
-	qce_crypto_go(qce, true);
-
-	return 0;
+	return qce_crypto_go(qce, true);
 }
 #endif
 
@@ -386,9 +389,7 @@ static int qce_setup_regs_skcipher(struct crypto_async_request *async_req)
 	config = qce_config_reg(qce, 1);
 	qce_write(qce, REG_CONFIG, config);
 
-	qce_crypto_go(qce, true);
-
-	return 0;
+	return qce_crypto_go(qce, true);
 }
 #endif
 
@@ -535,9 +536,7 @@ static int qce_setup_regs_aead(struct crypto_async_request *async_req)
 	qce_write(qce, REG_CONFIG, config);
 
 	/* Start the process */
-	qce_crypto_go(qce, !IS_CCM(flags));
-
-	return 0;
+	return qce_crypto_go(qce, !IS_CCM(flags));
 }
 #endif
 
diff --git a/drivers/crypto/qce/sha.c b/drivers/crypto/qce/sha.c
index 0c7aab711b7b8434d5f89ab4565ef4123fc5322e..286477a3001248e745d79b209aebb6ed6bf11f62 100644
--- a/drivers/crypto/qce/sha.c
+++ b/drivers/crypto/qce/sha.c
@@ -60,6 +60,10 @@ static void qce_ahash_done(void *data)
 	rctx->byte_count[0] = cpu_to_be32(result->auth_byte_count[0]);
 	rctx->byte_count[1] = cpu_to_be32(result->auth_byte_count[1]);
 
+	error = qce_bam_unlock(qce);
+	if (error)
+		dev_err(qce->dev, "ahash: failed to unlock the BAM\n");
+
 	error = qce_check_status(qce, &status);
 	if (error < 0)
 		dev_dbg(qce->dev, "ahash operation error (%x)\n", status);
@@ -90,6 +94,10 @@ static int qce_ahash_async_req_handle(struct crypto_async_request *async_req)
 		rctx->authklen = AES_KEYSIZE_128;
 	}
 
+	ret = qce_bam_lock(qce);
+	if (ret)
+		return ret;
+
 	rctx->src_nents = sg_nents_for_len(req->src, req->nbytes);
 	if (rctx->src_nents < 0) {
 		dev_err(qce->dev, "Invalid numbers of src SG.\n");
diff --git a/drivers/crypto/qce/skcipher.c b/drivers/crypto/qce/skcipher.c
index cab796cd7e43c548a49df468b2dde84942c5bd87..8317c79fb9c2b209884187d65655d04c580e9cde 100644
--- a/drivers/crypto/qce/skcipher.c
+++ b/drivers/crypto/qce/skcipher.c
@@ -51,6 +51,9 @@ static void qce_skcipher_done(void *data)
 	dma_unmap_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst);
 
 	sg_free_table(&rctx->dst_tbl);
+	error = qce_bam_unlock(qce);
+	if (error)
+		dev_err(qce->dev, "skcipher: failed to unlock the BAM\n");
 
 	error = qce_check_status(qce, &status);
 	if (error < 0)
@@ -78,6 +81,10 @@ qce_skcipher_async_req_handle(struct crypto_async_request *async_req)
 	rctx->ivsize = crypto_skcipher_ivsize(skcipher);
 	rctx->cryptlen = req->cryptlen;
 
+	ret = qce_bam_lock(qce);
+	if (ret)
+		return ret;
+
 	diff_dst = (req->src != req->dst) ? true : false;
 	dir_src = diff_dst ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL;
 	dir_dst = diff_dst ? DMA_FROM_DEVICE : DMA_BIDIRECTIONAL;

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Fri Dec 19 02:07:49 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Fri, 19 Dec 2025 11:07:49 +0100
Subject: [PATCH v10 10/12] crypto: qce - Add BAM DMA support for crypto
 register I/O
In-Reply-To: <20251219-qcom-qce-cmd-descr-v10-0-ff7e4bf7dad4@oss.qualcomm.com>
References: <20251219-qcom-qce-cmd-descr-v10-0-ff7e4bf7dad4@oss.qualcomm.com>
Message-ID: <20251219-qcom-qce-cmd-descr-v10-10-ff7e4bf7dad4@oss.qualcomm.com>

From: Bartosz Golaszewski <bartosz.golaszewski at linaro.org>

Implement the infrastructure for performing register I/O over BAM DMA,
not CPU. No functional change yet.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at linaro.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/crypto/qce/core.h |   4 ++
 drivers/crypto/qce/dma.c  | 109 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/crypto/qce/dma.h  |   5 +++
 3 files changed, 118 insertions(+)

diff --git a/drivers/crypto/qce/core.h b/drivers/crypto/qce/core.h
index a80e12eac6c87e5321cce16c56a4bf5003474ef0..d238097f834e4605f3825f23d0316d4196439116 100644
--- a/drivers/crypto/qce/core.h
+++ b/drivers/crypto/qce/core.h
@@ -30,6 +30,8 @@
  * @base_dma: base DMA address
  * @base_phys: base physical address
  * @dma_size: size of memory mapped for DMA
+ * @read_buf: Buffer for DMA to write back to
+ * @read_buf_dma: Mapped address of the read buffer
  * @async_req_enqueue: invoked by every algorithm to enqueue a request
  * @async_req_done: invoked by every algorithm to finish its request
  */
@@ -49,6 +51,8 @@ struct qce_device {
 	dma_addr_t base_dma;
 	phys_addr_t base_phys;
 	size_t dma_size;
+	__le32 *read_buf;
+	dma_addr_t read_buf_dma;
 	int (*async_req_enqueue)(struct qce_device *qce,
 				 struct crypto_async_request *req);
 	void (*async_req_done)(struct qce_device *qce, int ret);
diff --git a/drivers/crypto/qce/dma.c b/drivers/crypto/qce/dma.c
index a46264735bb895b6199969e83391383ccbbacc5f..ba7a52fd4c6349d59c075c346f75741defeb6034 100644
--- a/drivers/crypto/qce/dma.c
+++ b/drivers/crypto/qce/dma.c
@@ -4,6 +4,8 @@
  */
 
 #include <linux/device.h>
+#include <linux/dma/qcom_bam_dma.h>
+#include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
 #include <crypto/scatterwalk.h>
 
@@ -11,6 +13,98 @@
 #include "dma.h"
 
 #define QCE_IGNORE_BUF_SZ		(2 * QCE_BAM_BURST_SIZE)
+#define QCE_BAM_CMD_SGL_SIZE		128
+#define QCE_BAM_CMD_ELEMENT_SIZE	128
+#define QCE_MAX_REG_READ		8
+
+struct qce_desc_info {
+	struct dma_async_tx_descriptor *dma_desc;
+	enum dma_data_direction dir;
+};
+
+struct qce_bam_transaction {
+	struct bam_cmd_element bam_ce[QCE_BAM_CMD_ELEMENT_SIZE];
+	struct scatterlist wr_sgl[QCE_BAM_CMD_SGL_SIZE];
+	struct qce_desc_info *desc;
+	u32 bam_ce_idx;
+	u32 pre_bam_ce_idx;
+	u32 wr_sgl_cnt;
+};
+
+void qce_clear_bam_transaction(struct qce_device *qce)
+{
+	struct qce_bam_transaction *bam_txn = qce->dma.bam_txn;
+
+	bam_txn->bam_ce_idx = 0;
+	bam_txn->wr_sgl_cnt = 0;
+	bam_txn->bam_ce_idx = 0;
+	bam_txn->pre_bam_ce_idx = 0;
+}
+
+int qce_submit_cmd_desc(struct qce_device *qce)
+{
+	struct qce_desc_info *qce_desc = qce->dma.bam_txn->desc;
+	struct qce_bam_transaction *bam_txn = qce->dma.bam_txn;
+	struct dma_async_tx_descriptor *dma_desc;
+	struct dma_chan *chan = qce->dma.rxchan;
+	unsigned long attrs = DMA_PREP_CMD;
+	dma_cookie_t cookie;
+	unsigned int mapped;
+	int ret;
+
+	mapped = dma_map_sg_attrs(qce->dev, bam_txn->wr_sgl, bam_txn->wr_sgl_cnt,
+				  DMA_TO_DEVICE, attrs);
+	if (!mapped)
+		return -ENOMEM;
+
+	dma_desc = dmaengine_prep_slave_sg(chan, bam_txn->wr_sgl, bam_txn->wr_sgl_cnt,
+					   DMA_MEM_TO_DEV, attrs);
+	if (!dma_desc) {
+		dma_unmap_sg(qce->dev, bam_txn->wr_sgl, bam_txn->wr_sgl_cnt, DMA_TO_DEVICE);
+		return -ENOMEM;
+	}
+
+	qce_desc->dma_desc = dma_desc;
+	cookie = dmaengine_submit(qce_desc->dma_desc);
+
+	ret = dma_submit_error(cookie);
+	if (ret)
+		return ret;
+
+	qce_dma_issue_pending(&qce->dma);
+
+	return 0;
+}
+
+static void qce_prep_dma_cmd_desc(struct qce_device *qce, struct qce_dma_data *dma,
+				  unsigned int addr, void *buf)
+{
+	struct qce_bam_transaction *bam_txn = dma->bam_txn;
+	struct bam_cmd_element *bam_ce_buf;
+	int bam_ce_size, cnt, idx;
+
+	idx = bam_txn->bam_ce_idx;
+	bam_ce_buf = &bam_txn->bam_ce[idx];
+	bam_prep_ce_le32(bam_ce_buf, addr, BAM_WRITE_COMMAND, *((__le32 *)buf));
+
+	bam_ce_buf = &bam_txn->bam_ce[bam_txn->pre_bam_ce_idx];
+	bam_txn->bam_ce_idx++;
+	bam_ce_size = (bam_txn->bam_ce_idx - bam_txn->pre_bam_ce_idx) * sizeof(*bam_ce_buf);
+
+	cnt = bam_txn->wr_sgl_cnt;
+
+	sg_set_buf(&bam_txn->wr_sgl[cnt], bam_ce_buf, bam_ce_size);
+
+	++bam_txn->wr_sgl_cnt;
+	bam_txn->pre_bam_ce_idx = bam_txn->bam_ce_idx;
+}
+
+void qce_write_dma(struct qce_device *qce, unsigned int offset, u32 val)
+{
+	unsigned int reg_addr = ((unsigned int)(qce->base_phys) + offset);
+
+	qce_prep_dma_cmd_desc(qce, &qce->dma, reg_addr, &val);
+}
 
 int devm_qce_dma_request(struct qce_device *qce)
 {
@@ -31,6 +125,21 @@ int devm_qce_dma_request(struct qce_device *qce)
 	if (!dma->result_buf)
 		return -ENOMEM;
 
+	dma->bam_txn = devm_kzalloc(dev, sizeof(*dma->bam_txn), GFP_KERNEL);
+	if (!dma->bam_txn)
+		return -ENOMEM;
+
+	dma->bam_txn->desc = devm_kzalloc(dev, sizeof(*dma->bam_txn->desc), GFP_KERNEL);
+	if (!dma->bam_txn->desc)
+		return -ENOMEM;
+
+	sg_init_table(dma->bam_txn->wr_sgl, QCE_BAM_CMD_SGL_SIZE);
+
+	qce->read_buf = dmam_alloc_coherent(qce->dev, QCE_MAX_REG_READ * sizeof(*qce->read_buf),
+					    &qce->read_buf_dma, GFP_KERNEL);
+	if (!qce->read_buf)
+		return -ENOMEM;
+
 	return 0;
 }
 
diff --git a/drivers/crypto/qce/dma.h b/drivers/crypto/qce/dma.h
index 483789d9fa98e79d1283de8297bf2fc2a773f3a7..f05dfa9e6b25bd60e32f45079a8bc7e6a4cf81f9 100644
--- a/drivers/crypto/qce/dma.h
+++ b/drivers/crypto/qce/dma.h
@@ -8,6 +8,7 @@
 
 #include <linux/dmaengine.h>
 
+struct qce_bam_transaction;
 struct qce_device;
 
 /* maximum data transfer block size between BAM and CE */
@@ -32,6 +33,7 @@ struct qce_dma_data {
 	struct dma_chan *txchan;
 	struct dma_chan *rxchan;
 	struct qce_result_dump *result_buf;
+	struct qce_bam_transaction *bam_txn;
 };
 
 int devm_qce_dma_request(struct qce_device *qce);
@@ -43,5 +45,8 @@ int qce_dma_terminate_all(struct qce_dma_data *dma);
 struct scatterlist *
 qce_sgtable_add(struct sg_table *sgt, struct scatterlist *sg_add,
 		unsigned int max_len);
+void qce_write_dma(struct qce_device *qce, unsigned int offset, u32 val);
+int qce_submit_cmd_desc(struct qce_device *qce);
+void qce_clear_bam_transaction(struct qce_device *qce);
 
 #endif /* _DMA_H_ */

-- 
2.47.3



From krzysztof.kozlowski at oss.qualcomm.com  Fri Dec 19 02:11:51 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 11:11:51 +0100
Subject: [PATCH v2 2/3] gpio: creg-snps: Simplify with
 of_device_get_match_data()
In-Reply-To: <20251219-gpio-of-match-v2-0-5c65cbb513ac@oss.qualcomm.com>
References: <20251219-gpio-of-match-v2-0-5c65cbb513ac@oss.qualcomm.com>
Message-ID: <20251219-gpio-of-match-v2-2-5c65cbb513ac@oss.qualcomm.com>

Driver's probe function matches against driver's of_device_id table,
where each entry has non-NULL match data, so of_match_node() can be
simplified with of_device_get_match_data().

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/gpio/gpio-creg-snps.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/gpio/gpio-creg-snps.c b/drivers/gpio/gpio-creg-snps.c
index f8ea961fa1de..157ab90f5ba8 100644
--- a/drivers/gpio/gpio-creg-snps.c
+++ b/drivers/gpio/gpio-creg-snps.c
@@ -134,7 +134,6 @@ static const struct of_device_id creg_gpio_ids[] = {
 
 static int creg_gpio_probe(struct platform_device *pdev)
 {
-	const struct of_device_id *match;
 	struct device *dev = &pdev->dev;
 	struct creg_gpio *hcg;
 	u32 ngpios;
@@ -148,8 +147,7 @@ static int creg_gpio_probe(struct platform_device *pdev)
 	if (IS_ERR(hcg->regs))
 		return PTR_ERR(hcg->regs);
 
-	match = of_match_node(creg_gpio_ids, pdev->dev.of_node);
-	hcg->layout = match->data;
+	hcg->layout = device_get_match_data(dev);
 	if (!hcg->layout)
 		return -EINVAL;
 

-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Fri Dec 19 02:11:50 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 11:11:50 +0100
Subject: [PATCH v2 1/3] gpio: aspeed: Simplify with
 of_device_get_match_data()
In-Reply-To: <20251219-gpio-of-match-v2-0-5c65cbb513ac@oss.qualcomm.com>
References: <20251219-gpio-of-match-v2-0-5c65cbb513ac@oss.qualcomm.com>
Message-ID: <20251219-gpio-of-match-v2-1-5c65cbb513ac@oss.qualcomm.com>

Driver's probe function matches against driver's of_device_id table,
where each entry has non-NULL match data, so of_match_node() can be
simplified with of_device_get_match_data().

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/gpio/gpio-aspeed.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c
index cbdf781994dc..9115e56a1626 100644
--- a/drivers/gpio/gpio-aspeed.c
+++ b/drivers/gpio/gpio-aspeed.c
@@ -1302,7 +1302,6 @@ MODULE_DEVICE_TABLE(of, aspeed_gpio_of_table);
 
 static int aspeed_gpio_probe(struct platform_device *pdev)
 {
-	const struct of_device_id *gpio_id;
 	struct gpio_irq_chip *girq;
 	struct aspeed_gpio *gpio;
 	int rc, irq, i, banks, err;
@@ -1320,8 +1319,8 @@ static int aspeed_gpio_probe(struct platform_device *pdev)
 
 	raw_spin_lock_init(&gpio->lock);
 
-	gpio_id = of_match_node(aspeed_gpio_of_table, pdev->dev.of_node);
-	if (!gpio_id)
+	gpio->config = device_get_match_data(&pdev->dev);
+	if (!gpio->config)
 		return -EINVAL;
 
 	gpio->clk = devm_clk_get_enabled(&pdev->dev, NULL);
@@ -1331,8 +1330,6 @@ static int aspeed_gpio_probe(struct platform_device *pdev)
 		gpio->clk = NULL;
 	}
 
-	gpio->config = gpio_id->data;
-
 	if (!gpio->config->llops->reg_bit_set || !gpio->config->llops->reg_bit_get ||
 	    !gpio->config->llops->reg_bank_get)
 		return -EINVAL;

-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Fri Dec 19 02:11:49 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 11:11:49 +0100
Subject: [PATCH v2 0/3] gpio: Simplify with of_device_get_match_data()
Message-ID: <20251219-gpio-of-match-v2-0-5c65cbb513ac@oss.qualcomm.com>

Changes in v2:
- Drop applied patch
- Use device_get_match_data() as suggested by Bartosz
- Link to v1: https://patch.msgid.link/20251106-gpio-of-match-v1-0-50c7115a045e at linaro.org

Few simple cleanups, not tested on the hardware.

Care has to be taken when converting of_match_data() into
of_device_get_match_data(), because first can check arbitrary
device_node and the latter checks device's node.  Cases here should be
safe because of_match_data() uses 'pdev->dev.of_node'.

Best regards,
Krzysztof

---
Krzysztof Kozlowski (3):
      gpio: aspeed: Simplify with of_device_get_match_data()
      gpio: creg-snps: Simplify with of_device_get_match_data()
      gpio: zynq: Simplify with of_device_get_match_data()

 drivers/gpio/gpio-aspeed.c    | 7 ++-----
 drivers/gpio/gpio-creg-snps.c | 4 +---
 drivers/gpio/gpio-zynq.c      | 8 +++-----
 3 files changed, 6 insertions(+), 13 deletions(-)
---
base-commit: 26ac2c4153a2c543a4ef3dee421b46bedb0f8f0f
change-id: 20251106-gpio-of-match-23b24cddf063

Best regards,
-- 
Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>



From krzysztof.kozlowski at oss.qualcomm.com  Fri Dec 19 02:11:52 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 11:11:52 +0100
Subject: [PATCH v2 3/3] gpio: zynq: Simplify with
 of_device_get_match_data()
In-Reply-To: <20251219-gpio-of-match-v2-0-5c65cbb513ac@oss.qualcomm.com>
References: <20251219-gpio-of-match-v2-0-5c65cbb513ac@oss.qualcomm.com>
Message-ID: <20251219-gpio-of-match-v2-3-5c65cbb513ac@oss.qualcomm.com>

Driver's probe function matches against driver's of_device_id table,
where each entry has non-NULL match data, so of_match_node() can be
simplified with of_device_get_match_data().

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/gpio/gpio-zynq.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c
index 97780c57ab56..d69773318888 100644
--- a/drivers/gpio/gpio-zynq.c
+++ b/drivers/gpio/gpio-zynq.c
@@ -903,18 +903,16 @@ static int zynq_gpio_probe(struct platform_device *pdev)
 	struct zynq_gpio *gpio;
 	struct gpio_chip *chip;
 	struct gpio_irq_chip *girq;
-	const struct of_device_id *match;
 
 	gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
 	if (!gpio)
 		return -ENOMEM;
 
-	match = of_match_node(zynq_gpio_of_match, pdev->dev.of_node);
-	if (!match) {
-		dev_err(&pdev->dev, "of_match_node() failed\n");
+	gpio->p_data = device_get_match_data(&pdev->dev);
+	if (!gpio->p_data) {
+		dev_err(&pdev->dev, "of_device_get_match_data() failed\n");
 		return -EINVAL;
 	}
-	gpio->p_data = match->data;
 	platform_set_drvdata(pdev, gpio);
 
 	gpio->base_addr = devm_platform_ioremap_resource(pdev, 0);

-- 
2.51.0



From michal.simek at amd.com  Fri Dec 19 02:14:35 2025
From: michal.simek at amd.com (Michal Simek)
Date: Fri, 19 Dec 2025 11:14:35 +0100
Subject: [PATCH v2 3/3] gpio: zynq: Simplify with
 of_device_get_match_data()
In-Reply-To: <20251219-gpio-of-match-v2-3-5c65cbb513ac@oss.qualcomm.com>
References: <20251219-gpio-of-match-v2-0-5c65cbb513ac@oss.qualcomm.com>
 <20251219-gpio-of-match-v2-3-5c65cbb513ac@oss.qualcomm.com>
Message-ID: <f9f3feec-2ed0-45c7-8467-2aea3222ffbc@amd.com>



On 12/19/25 11:11, Krzysztof Kozlowski wrote:
> Driver's probe function matches against driver's of_device_id table,
> where each entry has non-NULL match data, so of_match_node() can be
> simplified with of_device_get_match_data().

device_get_match_data() right?

> 
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
> ---
>   drivers/gpio/gpio-zynq.c | 8 +++-----
>   1 file changed, 3 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c
> index 97780c57ab56..d69773318888 100644
> --- a/drivers/gpio/gpio-zynq.c
> +++ b/drivers/gpio/gpio-zynq.c
> @@ -903,18 +903,16 @@ static int zynq_gpio_probe(struct platform_device *pdev)
>   	struct zynq_gpio *gpio;
>   	struct gpio_chip *chip;
>   	struct gpio_irq_chip *girq;
> -	const struct of_device_id *match;
>   
>   	gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
>   	if (!gpio)
>   		return -ENOMEM;
>   
> -	match = of_match_node(zynq_gpio_of_match, pdev->dev.of_node);
> -	if (!match) {
> -		dev_err(&pdev->dev, "of_match_node() failed\n");
> +	gpio->p_data = device_get_match_data(&pdev->dev);
> +	if (!gpio->p_data) {
> +		dev_err(&pdev->dev, "of_device_get_match_data() failed\n");

device_get_match_data() ?




>   		return -EINVAL;
>   	}
> -	gpio->p_data = match->data;
>   	platform_set_drvdata(pdev, gpio);
>   
>   	gpio->base_addr = devm_platform_ioremap_resource(pdev, 0);
> 

M


From brgl at kernel.org  Fri Dec 19 02:15:31 2025
From: brgl at kernel.org (Bartosz Golaszewski)
Date: Fri, 19 Dec 2025 11:15:31 +0100
Subject: [PATCH v2 3/3] gpio: zynq: Simplify with of_device_get_match_data()
In-Reply-To: <20251219-gpio-of-match-v2-3-5c65cbb513ac@oss.qualcomm.com>
References: <20251219-gpio-of-match-v2-0-5c65cbb513ac@oss.qualcomm.com> <20251219-gpio-of-match-v2-3-5c65cbb513ac@oss.qualcomm.com>
Message-ID: <CAMRc=Md=KvKaXZvdwRd_rTp-Oq1qrAo12ENcUqTTWSYnCYSZuA@mail.gmail.com>

On Fri, Dec 19, 2025 at 11:12?AM Krzysztof Kozlowski
<krzysztof.kozlowski at oss.qualcomm.com> wrote:
>
> Driver's probe function matches against driver's of_device_id table,
> where each entry has non-NULL match data, so of_match_node() can be
> simplified with of_device_get_match_data().
>
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
> ---

I think there are some copy-paste leftovers in your commit messages.
You're saying you're using of_ functions but you're really going for
the device_ ones. Also update error messages. And possibly use
dev_err_probe() too while at it?

Same elsewhere.

Bart


From sudeep.holla at arm.com  Fri Dec 19 02:21:24 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Fri, 19 Dec 2025 10:21:24 +0000
Subject: [PATCH v2 00/12] coresight: Add CPU cluster
 funnel/replicator/tmc support
In-Reply-To: <d0ce8306-84e0-4940-98aa-dbc356d87593@oss.qualcomm.com>
References: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
 <20251218-careful-ruby-wildebeest-a8babd@sudeepholla>
 <d0ce8306-84e0-4940-98aa-dbc356d87593@oss.qualcomm.com>
Message-ID: <20251219-hysterical-sparkling-meerkat-59c5eb@sudeepholla>

On Fri, Dec 19, 2025 at 10:13:14AM +0800, yuanfang zhang wrote:
> 
> 
> On 12/18/2025 7:33 PM, Sudeep Holla wrote:
> > On Thu, Dec 18, 2025 at 12:09:40AM -0800, Yuanfang Zhang wrote:
> >> This patch series adds support for CoreSight components local to CPU clusters,
> >> including funnel, replicator, and TMC, which reside within CPU cluster power
> >> domains. These components require special handling due to power domain
> >> constraints.
> >>
> > 
> > Could you clarify why PSCI-based power domains associated with clusters in
> > domain-idle-states cannot address these requirements, given that PSCI CPU-idle
> > OSI mode was originally intended to support them? My understanding of this
> > patch series is that OSI mode is unable to do so, which, if accurate, appears
> > to be a flaw that should be corrected.
> 
> It is due to the particular characteristics of the CPU cluster power
> domain.Runtime PM for CPU devices works little different, it is mostly used
> to manage hierarchicalCPU topology (PSCI OSI mode) to talk with genpd
> framework to manage the last CPU handling in cluster.

That is indeed the intended design. Could you clarify which specific
characteristics differentiate it here?

> It doesn?t really send IPI to wakeup CPU device (It don?t have
> .power_on/.power_off) callback implemented which gets invoked from
> .runtime_resume callback. This behavior is aligned with the upstream Kernel.
> 

I am quite lost here. Why is it necessary to wake up the CPU? If I understand
correctly, all of this complexity is meant to ensure that the cluster power
domain is enabled before any of the funnel registers are accessed. Is that
correct?

If so, and if the cluster domains are already defined as the power domains for
these funnel devices, then they should be requested to power on automatically
before any register access occurs. Is that not the case?

What am I missing in this reasoning?

The only explanation I can see is that the firmware does not properly honor
power-domain requests coming directly from the OS. I believe that may be the
case, but I would be glad to be proven wrong.

> > 
> >> Unlike system-level CoreSight devices, these components share the CPU cluster's
> >> power domain. When the cluster enters low-power mode (LPM), their registers
> >> become inaccessible. Notably, `pm_runtime_get` alone cannot bring the cluster
> >> out of LPM, making standard register access unreliable.
> >>
> > 
> > Are these devices the only ones on the system that are uniquely bound to
> > cluster-level power domains? If not, what additional devices share this
> > dependency so that we can understand how they are managed in comparison?
> > 
> 
> Yes, devices like ETM and TRBE also share this power domain and access constraint.
> Their drivers naturally handle enablement/disablement on the specific CPU they
> belong to (e.g., via hotplug callbacks or existing smp_call_function paths).

I understand many things are possible to implement, but the key question
remains: why doesn?t the existing OSI mechanism - added specifically to cover
cases like this solve the problem today?

Especially on platforms with OSI enabled, what concrete limitation forces us
into this additional ?wake-up? path instead of relying on OSI to manage the
dependency/power sequencing?

> >> To address this, the series introduces:
> >> - Identifying cluster-bound devices via a new `qcom,cpu-bound-components`
> >>   device tree property.
> > 
> > Really, no please.
> > 
> 
> Our objective is to determine which CoreSight components are physically locate
> within the CPU cluster power domain.
>
> Would it be acceptable to derive this relationship from the existing
> power-domains binding?

In my opinion, this is not merely a possibility but an explicit expectation.

> For example, if a Funnel or Replicator node is linked to a power-domains
> entry that specifies a cpumask, the driver could recognize this shared
> dependency and automatically apply the appropriate cluster-aware behavior.
> 

Sure, but for the driver to use that information, we need clear explanation
for all the questions above. In short, why it is not working with the existing
PSCI domain idle support.

-- 
Regards,
Sudeep


From suzuki.poulose at arm.com  Fri Dec 19 02:22:59 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Fri, 19 Dec 2025 10:22:59 +0000
Subject: [PATCH v5 1/3] coresight: tpda: add sysfs nodes for tpda
 cross-trigger configuration
In-Reply-To: <20251219-add_sysfs_nodes_to_configure_tpda-v5-1-ca93ddfe9d30@oss.qualcomm.com>
References: <20251219-add_sysfs_nodes_to_configure_tpda-v5-0-ca93ddfe9d30@oss.qualcomm.com>
 <20251219-add_sysfs_nodes_to_configure_tpda-v5-1-ca93ddfe9d30@oss.qualcomm.com>
Message-ID: <afc078d5-5855-4439-98ac-c132a2588627@arm.com>

On 19/12/2025 10:04, Jie Gan wrote:
> From: Tao Zhang <tao.zhang at oss.qualcomm.com>
> 
> Introduce sysfs nodes to configure cross-trigger parameters for TPDA.
> These registers define the characteristics of cross-trigger packets,
> including generation frequency and flag values.
> 
> Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
> Reviewed-by: James Clark <james.clark at linaro.org>
> Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
> ---
>   .../ABI/testing/sysfs-bus-coresight-devices-tpda   |  43 +++++++
>   drivers/hwtracing/coresight/coresight-tpda.c       | 138 ++++++++++++++++++++-
>   drivers/hwtracing/coresight/coresight-tpda.h       |  69 ++++++++++-
>   3 files changed, 243 insertions(+), 7 deletions(-)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
> new file mode 100644
> index 000000000000..a7855922328e
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
> @@ -0,0 +1,43 @@
> +What:		/sys/bus/coresight/devices/<tpda-name>/global_cr/trig_async_enable
> +Date:		December 2025
> +KernelVersion:	6.19
> +Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
> +Description:
> +		(RW) Enable/disable cross trigger synchronization sequence interface.
> +
> +What:		/sys/bus/coresight/devices/<tpda-name>/global_cr/trig_flag_ts_enable
> +Date:		December 2025
> +KernelVersion:	6.19
> +Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
> +Description:
> +		(RW) Enable/disable cross trigger FLAG packet request interface.
> +
> +What:		/sys/bus/coresight/devices/<tpda-name>/global_cr/trig_freq_enable
> +Date:		December 2025
> +KernelVersion:	6.19
> +Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
> +Description:
> +		(RW) Enable/disable cross trigger FREQ packet request interface.
> +
> +What:		/sys/bus/coresight/devices/<tpda-name>/global_cr/freq_ts_enable
> +Date:		December 2025
> +KernelVersion:	6.19
> +Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
> +Description:
> +		(RW) Enable/disable the timestamp for all FREQ packets.
> +
> +What:		/sys/bus/coresight/devices/<tpda-name>/global_cr/global_flush_req
> +Date:		December 2025
> +KernelVersion:	6.19
> +Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
> +Description:
> +		(RW) Set global (all ports) flush request bit. The bit remains set until a
> +		global flush request sequence completes.
> +
> +What:		/sys/bus/coresight/devices/<tpda-name>/global_cr/cmbchan_mode
> +Date:		December 2025
> +KernelVersion:	6.19
> +Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
> +Description:
> +		(RW) Configure the CMB/MCMB channel mode for all enabled ports.
> +		Value 0 means raw channel mapping mode. Value 1 means channel pair marking mode.
> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
> index 3a3825d27f86..d25a8bcfb3d4 100644
> --- a/drivers/hwtracing/coresight/coresight-tpda.c
> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
> @@ -137,12 +137,32 @@ static int tpda_get_element_size(struct tpda_drvdata *drvdata,
>   /* Settings pre enabling port control register */
>   static void tpda_enable_pre_port(struct tpda_drvdata *drvdata)
>   {
> -	u32 val;
> +	u32 val = 0;
>   
> -	val = readl_relaxed(drvdata->base + TPDA_CR);
> -	val &= ~TPDA_CR_ATID;
>   	val |= FIELD_PREP(TPDA_CR_ATID, drvdata->atid);
> +	if (drvdata->trig_async)
> +		val |= TPDA_CR_SRIE;
> +
> +	if (drvdata->trig_flag_ts)
> +		val |= TPDA_CR_FLRIE;
> +
> +	if (drvdata->trig_freq)
> +		val |= TPDA_CR_FRIE;
> +
> +	if (drvdata->freq_ts)
> +		val |= TPDA_CR_FREQTS;
> +
> +	if (drvdata->cmbchan_mode)
> +		val |= TPDA_CR_CMBCHANMODE;
> +
>   	writel_relaxed(val, drvdata->base + TPDA_CR);
> +
> +	/*
> +	 * If FLRIE bit is set, set the master and channel
> +	 * id as zero
> +	 */
> +	if (drvdata->trig_flag_ts)
> +		writel_relaxed(0x0, drvdata->base + TPDA_FPID_CR);
>   }
>   
>   static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
> @@ -258,6 +278,116 @@ static const struct coresight_ops tpda_cs_ops = {
>   	.link_ops	= &tpda_link_ops,
>   };
>   
> +/* Read cross-trigger register member */
> +static ssize_t tpda_trig_sysfs_show(struct device *dev,
> +				    struct device_attribute *attr,
> +				    char *buf)
> +{
> +	struct tpda_trig_sysfs_attribute *tpda_attr =
> +		container_of(attr, struct tpda_trig_sysfs_attribute, attr);
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	unsigned long val;
> +
> +	guard(spinlock)(&drvdata->spinlock);
> +	switch (tpda_attr->mem) {
> +	case FLREQ:
> +		if (!drvdata->csdev->refcnt)
> +			return -EINVAL;
> +
> +		val = readl_relaxed(drvdata->base + TPDA_CR);
> +		/* read global flush request bit only */
> +		val &= TPDA_CR_FLREQ;
> +		return sysfs_emit(buf, "%lu\n", val);
> +	case FREQTS:
> +		return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->freq_ts);
> +	case FRIE:
> +		return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_freq);
> +	case FLRIE:
> +		return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_flag_ts);
> +	case SRIE:
> +		return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_async);
> +	case CMBCHANMODE:
> +		return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->cmbchan_mode);
> +
> +	}
> +	return -EINVAL;
> +}
> +
> +static ssize_t tpda_trig_sysfs_store(struct device *dev,
> +				     struct device_attribute *attr,
> +				     const char *buf,
> +				     size_t size)
> +{
> +	struct tpda_trig_sysfs_attribute *tpda_attr =
> +		container_of(attr, struct tpda_trig_sysfs_attribute, attr);
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	ssize_t ret = -EINVAL;
   +	unsigned long val;
> +
> +	if (kstrtoul(buf, 0, &val))
> +		return ret;

		return -EINVAL;

> +
> +	guard(spinlock)(&drvdata->spinlock);
> +	switch (tpda_attr->mem) {
> +	case FLREQ:
> +		if (!drvdata->csdev->refcnt || !val)
> +			return ret;
			return -EINVAL;

> +
> +		val = readl_relaxed(drvdata->base + TPDA_CR);

CS_UNLOCK before readl ? I didn't mean the global_flush_req to be
unified with the rest. Obviously it has different access semantics.


> +		/* set global flush request bit */
> +		val |= TPDA_CR_FLREQ;
> +		CS_UNLOCK(drvdata->base);
> +		writel_relaxed(val, drvdata->base + TPDA_CR);
> +		CS_LOCK(drvdata->base);
> +		ret = size;

Please remove this from all the cases and explicitly return -EINVAL in
the error cases.

> +		break;
> +	case FREQTS:
> +		drvdata->freq_ts = !!val;
> +		ret = size;
> +		break;
> +	case FRIE:
> +		drvdata->trig_freq = !!val;
> +		ret = size;
> +		break;
> +	case FLRIE:
> +		drvdata->trig_flag_ts = !!val;
> +		ret = size;
> +		break;
> +	case SRIE:
> +		drvdata->trig_async = !!val;
> +		ret = size;
> +		break;
> +	case CMBCHANMODE:
> +		drvdata->cmbchan_mode = !!val;
> +		ret = size;
> +		break;
> +	default:
		return -EINVAL;

> +		break;
> +	}
> +


> +	return ret;

	return size;

> +}
> +
> +static struct attribute *tpda_global_cr_attrs[] = {
> +	tpda_trig_sysfs_rw(global_flush_req, FLREQ),
> +	tpda_trig_sysfs_rw(freq_ts_enable, FREQTS),
> +	tpda_trig_sysfs_rw(trig_freq_enable, FRIE),
> +	tpda_trig_sysfs_rw(trig_flag_ts_enable, FLRIE),
> +	tpda_trig_sysfs_rw(trig_async_enable, SRIE),
> +	tpda_trig_sysfs_rw(cmbchan_mode, CMBCHANMODE),
> +	NULL,
> +};
> +
> +static struct attribute_group tpda_global_cr_attr_grp = {
> +	.attrs	= tpda_global_cr_attrs,
> +	.name	= "global_cr",
> +};
> +
> +static const struct attribute_group *tpda_attr_grps[] = {
> +	&tpda_global_cr_attr_grp,
> +	NULL,
> +};
> +
>   static int tpda_init_default_data(struct tpda_drvdata *drvdata)
>   {
>   	int atid;
> @@ -273,6 +403,7 @@ static int tpda_init_default_data(struct tpda_drvdata *drvdata)
>   		return atid;
>   
>   	drvdata->atid = atid;
> +	drvdata->freq_ts = true;
>   	return 0;
>   }
>   
> @@ -316,6 +447,7 @@ static int tpda_probe(struct amba_device *adev, const struct amba_id *id)
>   	desc.ops = &tpda_cs_ops;
>   	desc.pdata = adev->dev.platform_data;
>   	desc.dev = &adev->dev;
> +	desc.groups = tpda_attr_grps;
>   	desc.access = CSDEV_ACCESS_IOMEM(base);
>   	drvdata->csdev = coresight_register(&desc);
>   	if (IS_ERR(drvdata->csdev))
> diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h
> index c6af3d2da3ef..8a075cfbc3cc 100644
> --- a/drivers/hwtracing/coresight/coresight-tpda.h
> +++ b/drivers/hwtracing/coresight/coresight-tpda.h
> @@ -1,6 +1,6 @@
>   /* SPDX-License-Identifier: GPL-2.0 */
>   /*
> - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
> + * Copyright (c) 2023,2025 Qualcomm Innovation Center, Inc. All rights reserved.
>    */
>   
>   #ifndef _CORESIGHT_CORESIGHT_TPDA_H
> @@ -8,6 +8,30 @@
>   
>   #define TPDA_CR			(0x000)
>   #define TPDA_Pn_CR(n)		(0x004 + (n * 4))
> +#define TPDA_FPID_CR		(0x084)
> +
> +/* Cross trigger Global (all ports) flush request bit */
> +#define TPDA_CR_FLREQ		BIT(0)
> +/* Cross trigger FREQ packets timestamp bit */
> +#define TPDA_CR_FREQTS		BIT(2)
> +/* Cross trigger FREQ packet request bit */
> +#define TPDA_CR_FRIE		BIT(3)
> +/* Cross trigger FLAG packet request interface bit */
> +#define TPDA_CR_FLRIE		BIT(4)
> +/* Cross trigger synchronization bit */
> +#define TPDA_CR_SRIE		BIT(5)
> +/* Bits 6 ~ 12 is for atid value */
> +#define TPDA_CR_ATID		GENMASK(12, 6)
> +/* Bits 13 ~ 19 is for mid value */
> +/* Assign a unique master ID to identify the TPDA device */
> +#define TPDA_CR_MID		GENMASK(19, 13)

Where do we use this ? Does this need to be preserved ?
Is this programmable ?

Suzuki

> +/*
> + * Channel mode bit of the packetization of CMB/MCB traffic
> + * 0 - raw channel mapping mode
> + * 1 - channel pair marking mode
> + */
> +#define TPDA_CR_CMBCHANMODE	BIT(20)
> +
>   /* Aggregator port enable bit */
>   #define TPDA_Pn_CR_ENA		BIT(0)
>   /* Aggregator port CMB data set element size bit */
> @@ -17,9 +41,6 @@
>   
>   #define TPDA_MAX_INPORTS	32
>   
> -/* Bits 6 ~ 12 is for atid value */
> -#define TPDA_CR_ATID		GENMASK(12, 6)
> -
>   /**
>    * struct tpda_drvdata - specifics associated to an TPDA component
>    * @base:       memory mapped base address for this component.
> @@ -29,6 +50,11 @@
>    * @enable:     enable status of the component.
>    * @dsb_esize   Record the DSB element size.
>    * @cmb_esize   Record the CMB element size.
> + * @trig_async:	Enable/disable cross trigger synchronization sequence interface.
> + * @trig_flag_ts: Enable/disable cross trigger FLAG packet request interface.
> + * @trig_freq:	Enable/disable cross trigger FREQ packet request interface.
> + * @freq_ts:	Enable/disable the timestamp for all FREQ packets.
> + * @cmbchan_mode: Configure the CMB/MCMB channel mode.
>    */
>   struct tpda_drvdata {
>   	void __iomem		*base;
> @@ -38,6 +64,41 @@ struct tpda_drvdata {
>   	u8			atid;
>   	u32			dsb_esize;
>   	u32			cmb_esize;
> +	bool			trig_async;
> +	bool			trig_flag_ts;
> +	bool			trig_freq;
> +	bool			freq_ts;
> +	bool			cmbchan_mode;
> +};
> +
> +/* Enumerate members of global control register(cr) */
> +enum tpda_cr_mem {
> +	FLREQ,
> +	FREQTS,
> +	FRIE,
> +	FLRIE,
> +	SRIE,
> +	CMBCHANMODE
> +};
> +
> +/**
> + * struct tpda_trig_sysfs_attribute - Record the member variables of cross
> + * trigger register that need to be operated by sysfs file
> + * @attr:	The device attribute
> + * @mem:	The member in the control register data structure
> + */
> +struct tpda_trig_sysfs_attribute {
> +	struct device_attribute attr;
> +	enum tpda_cr_mem mem;
>   };
>   
> +#define tpda_trig_sysfs_rw(name, mem)				\
> +	(&((struct tpda_trig_sysfs_attribute[]) {		\
> +	   {							\
> +		__ATTR(name, 0644, tpda_trig_sysfs_show,	\
> +		tpda_trig_sysfs_store),				\
> +		mem,						\
> +	   }							\
> +	   })[0].attr.attr)
> +
>   #endif  /* _CORESIGHT_CORESIGHT_TPDA_H */
> 



From suzuki.poulose at arm.com  Fri Dec 19 02:24:48 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Fri, 19 Dec 2025 10:24:48 +0000
Subject: [PATCH v5 2/3] coresight: tpda: add logic to configure TPDA_SYNCR
 register
In-Reply-To: <20251219-add_sysfs_nodes_to_configure_tpda-v5-2-ca93ddfe9d30@oss.qualcomm.com>
References: <20251219-add_sysfs_nodes_to_configure_tpda-v5-0-ca93ddfe9d30@oss.qualcomm.com>
 <20251219-add_sysfs_nodes_to_configure_tpda-v5-2-ca93ddfe9d30@oss.qualcomm.com>
Message-ID: <38dc6948-6233-4b0a-a769-538939abe345@arm.com>

On 19/12/2025 10:04, Jie Gan wrote:
> From: Tao Zhang <tao.zhang at oss.qualcomm.com>
> 
> The TPDA_SYNC counter tracks the number of bytes transferred from the
> aggregator. When this count reaches the value programmed in the
> TPDA_SYNCR register, an ASYNC request is triggered, allowing userspace
> tools to accurately parse each valid packet.
> 
> Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
> Reviewed-by: James Clark <james.clark at linaro.org>
> Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
> ---
>   drivers/hwtracing/coresight/coresight-tpda.c | 7 +++++++
>   drivers/hwtracing/coresight/coresight-tpda.h | 5 +++++
>   2 files changed, 12 insertions(+)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
> index d25a8bcfb3d4..d378ff8ad77d 100644
> --- a/drivers/hwtracing/coresight/coresight-tpda.c
> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
> @@ -163,6 +163,13 @@ static void tpda_enable_pre_port(struct tpda_drvdata *drvdata)
>   	 */
>   	if (drvdata->trig_flag_ts)
>   		writel_relaxed(0x0, drvdata->base + TPDA_FPID_CR);
> +
> +	val = readl_relaxed(drvdata->base + TPDA_SYNCR);
> +	/* Reset the mode ctrl */
> +	val &= ~TPDA_SYNCR_MODE_CTRL;
> +	/* Program the counter value for TPDA_SYNCR */
> +	val |= TPDA_SYNCR_COUNTER_MASK;

Do we plan to change this value via sysfs ? If not whats the point of
clearing the field. Why not simply set it (as it is all 1s anyways).

> +	writel_relaxed(val, drvdata->base + TPDA_SYNCR);
>   }
>   
>   static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
> diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h
> index 8a075cfbc3cc..97e2729c15c9 100644
> --- a/drivers/hwtracing/coresight/coresight-tpda.h
> +++ b/drivers/hwtracing/coresight/coresight-tpda.h
> @@ -9,6 +9,7 @@
>   #define TPDA_CR			(0x000)
>   #define TPDA_Pn_CR(n)		(0x004 + (n * 4))
>   #define TPDA_FPID_CR		(0x084)
> +#define TPDA_SYNCR		(0x08C)
>   
>   /* Cross trigger Global (all ports) flush request bit */
>   #define TPDA_CR_FLREQ		BIT(0)
> @@ -38,6 +39,10 @@
>   #define TPDA_Pn_CR_CMBSIZE		GENMASK(7, 6)
>   /* Aggregator port DSB data set element size bit */
>   #define TPDA_Pn_CR_DSBSIZE		BIT(8)

Newline to separate the defintions of different registers, please.

> +/* TPDA_SYNCR mode control bit */
> +#define TPDA_SYNCR_MODE_CTRL		BIT(12)
> +/* TPDA_SYNCR counter mask */
> +#define TPDA_SYNCR_COUNTER_MASK		GENMASK(11, 0)
>   
>   #define TPDA_MAX_INPORTS	32
>   

Suzuki


> 



From suzuki.poulose at arm.com  Fri Dec 19 02:28:01 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Fri, 19 Dec 2025 10:28:01 +0000
Subject: [PATCH v2 00/12] coresight: Add CPU cluster funnel/replicator/tmc
 support
In-Reply-To: <20251219-hysterical-sparkling-meerkat-59c5eb@sudeepholla>
References: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
 <20251218-careful-ruby-wildebeest-a8babd@sudeepholla>
 <d0ce8306-84e0-4940-98aa-dbc356d87593@oss.qualcomm.com>
 <20251219-hysterical-sparkling-meerkat-59c5eb@sudeepholla>
Message-ID: <e9df1140-989f-46e3-8edc-2013e520bfed@arm.com>

On 19/12/2025 10:21, Sudeep Holla wrote:
> On Fri, Dec 19, 2025 at 10:13:14AM +0800, yuanfang zhang wrote:
>>
>>
>> On 12/18/2025 7:33 PM, Sudeep Holla wrote:
>>> On Thu, Dec 18, 2025 at 12:09:40AM -0800, Yuanfang Zhang wrote:
>>>> This patch series adds support for CoreSight components local to CPU clusters,
>>>> including funnel, replicator, and TMC, which reside within CPU cluster power
>>>> domains. These components require special handling due to power domain
>>>> constraints.
>>>>
>>>
>>> Could you clarify why PSCI-based power domains associated with clusters in
>>> domain-idle-states cannot address these requirements, given that PSCI CPU-idle
>>> OSI mode was originally intended to support them? My understanding of this
>>> patch series is that OSI mode is unable to do so, which, if accurate, appears
>>> to be a flaw that should be corrected.
>>
>> It is due to the particular characteristics of the CPU cluster power
>> domain.Runtime PM for CPU devices works little different, it is mostly used
>> to manage hierarchicalCPU topology (PSCI OSI mode) to talk with genpd
>> framework to manage the last CPU handling in cluster.
> 
> That is indeed the intended design. Could you clarify which specific
> characteristics differentiate it here?
> 
>> It doesn?t really send IPI to wakeup CPU device (It don?t have
>> .power_on/.power_off) callback implemented which gets invoked from
>> .runtime_resume callback. This behavior is aligned with the upstream Kernel.
>>
> 
> I am quite lost here. Why is it necessary to wake up the CPU? If I understand
> correctly, all of this complexity is meant to ensure that the cluster power
> domain is enabled before any of the funnel registers are accessed. Is that
> correct?
> 
> If so, and if the cluster domains are already defined as the power domains for
> these funnel devices, then they should be requested to power on automatically
> before any register access occurs. Is that not the case?
> 
> What am I missing in this reasoning?

Exactly, this is what I am too. But then you get the "pre-formated 
standard response" without answering our questions.

Suzuki


From sudeep.holla at arm.com  Fri Dec 19 02:32:36 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Fri, 19 Dec 2025 10:32:36 +0000
Subject: [RFC PATCH 0/5] Arm LFA: Improvements and interrupt support
In-Reply-To: <8bca8c4b-52b8-4a1d-9f21-176c994a58bb@nvidia.com>
References: <20251208221319.1524888-1-vvidwans@nvidia.com>
 <20251209-miniature-curassow-of-energy-b6a303@sudeepholla>
 <8bca8c4b-52b8-4a1d-9f21-176c994a58bb@nvidia.com>
Message-ID: <20251219-visionary-hissing-sidewinder-5e95c5@sudeepholla>

On Fri, Dec 19, 2025 at 12:38:39AM -0800, Vedashree Vidwans wrote:
> 
> 
> On 12/9/25 03:39, Sudeep Holla wrote:
> > On Mon, Dec 08, 2025 at 10:13:10PM +0000, Vedashree Vidwans wrote:
> > > Hello,
> > > 
> > > The patches update the proposed Arm Live Firmware Activation (LFA)
> > > kernel driver [1] to incorporate review feedback [2] and refine the
> > > activation flow while remaining aligned with the LFA specification
> > > DEN0147 [3] and the SMCCC 1.2 calling convention. The series keeps
> > > the existing functionality but restructures and extends it to improve
> > > robustness, reviewability, and future extensibility.?
> > > 
> > > The SMCCC usage in the driver is updated to consistently use the
> > > SMCCC 1.2 register-based calling convention, consolidating arguments
> > > and results into a single struct to reduce stack usage and simplify
> > > the SMC interface. The patches also split the original changes into
> > > focused pieces and document the device node bindings in the commit
> > > messages, making it easier to follow and validate the implementation
> > > against the specification.?
> > > 
> > > The kernel driver is registered as a platform driver in accordence to
> > > the LFA device defined by the specification [3]. The driver now extends
> > > interface for interrupt-based enablement of LFA. During LFA, the
> > > interrupt
> > > thread refreshes firmware component details after each activation step
> > > and iterates over all activable components until no further activation
> > > is pending, matching the spec?s allowance for component detail changes
> > > after activation. This ensures that sysfs exposure of LFA components
> > > remains consistent with the authoritative information provided by the
> > > secure firmware.?
> > > 
> > > The handling of CPU rendezvous is adjusted so that the kernel now
> > > honors the rendezvous policy chosen by the firmware, instead of
> > > unconditionally forcing a rendezvous. This reflects experience with
> > > existing firmware deployments where mandatory rendezvous is not
> > > required, while still allowing the firmware to request it when
> > > needed.?
> > > 
> > > Thank you,
> > > Veda
> > > 
> > > [1] https://lore.kernel.org/lkml/20250926123145.268728-1-salman.nabi at arm.com/
> > > [2] https://lkml.org/lkml/2025/10/8/980
> > > [3] https://developer.arm.com/documentation/den0147/latest/
> > > 
> > > Vedashree Vidwans (5):
> > >    firmware: smccc: LFA: use smcc 1.2
> > >    firmware: smccc: LFA: refactor
> > >    firmware: smccc: add timeout, touch wdt
> > >    firmware: smccc: register as platform driver
> > >    firmware: smccc: lfa: refresh fw details
> > > 
> > >   drivers/firmware/smccc/Kconfig  |   3 +-
> > >   drivers/firmware/smccc/lfa_fw.c | 478 +++++++++++++++++++++++++-------
> > 
> > Same comment as before[1], looks like the feedback got ignored or missed.
> > 
> > -- 
> > Regards,
> > Sudeep
> > 
> > [1]https://lore.kernel.org/all/20251009-calculating-glorious-oriole-ceccf6 at sudeepholla
> 
> Thank you for your comment.
> I did include DT binding in commit message of the patch. Please let me know
> if there's anything else I can elaborate.
> 

Sure. I meant I don't see any patch titled "dt-bindings: firmware: Add LFA...."
or something similar. I also checked the delta for the files under
Documentation/devicetree/bindings/ to rule out the possibility that the
patch title may not be following the DT binding upstreaming process.

-- 
Regards,
Sudeep


From suzuki.poulose at arm.com  Fri Dec 19 02:33:19 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Fri, 19 Dec 2025 10:33:19 +0000
Subject: [PATCH v5 3/3] coresight: tpda: add sysfs node to flush specific
 port
In-Reply-To: <20251219-add_sysfs_nodes_to_configure_tpda-v5-3-ca93ddfe9d30@oss.qualcomm.com>
References: <20251219-add_sysfs_nodes_to_configure_tpda-v5-0-ca93ddfe9d30@oss.qualcomm.com>
 <20251219-add_sysfs_nodes_to_configure_tpda-v5-3-ca93ddfe9d30@oss.qualcomm.com>
Message-ID: <ec3804b5-30a1-404b-ae82-0b606a8b5d6a@arm.com>

On 19/12/2025 10:04, Jie Gan wrote:
> From: Tao Zhang <tao.zhang at oss.qualcomm.com>
> 
> Setting bit i in the TPDA_FLUSH_CR register initiates a flush request
> for port i, forcing the data to synchronize and be transmitted to the
> sink device.
> 
> Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
> Reviewed-by: James Clark <james.clark at linaro.org>
> Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
> ---
>   .../ABI/testing/sysfs-bus-coresight-devices-tpda   |  7 ++++
>   drivers/hwtracing/coresight/coresight-tpda.c       | 49 ++++++++++++++++++++++
>   drivers/hwtracing/coresight/coresight-tpda.h       |  1 +
>   3 files changed, 57 insertions(+)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
> index a7855922328e..ef2804f87d1e 100644
> --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
> +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
> @@ -41,3 +41,10 @@ Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qu
>   Description:
>   		(RW) Configure the CMB/MCMB channel mode for all enabled ports.
>   		Value 0 means raw channel mapping mode. Value 1 means channel pair marking mode.
> +
> +What:		/sys/bus/coresight/devices/<tpda-name>/port_flush_req
> +Date:		December 2025
> +KernelVersion:	6.19
> +Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
> +Description:
> +		(RW) Configure the bit i to requests a flush operation of port i on the TPDA.
> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
> index d378ff8ad77d..5b4a9e41b067 100644
> --- a/drivers/hwtracing/coresight/coresight-tpda.c
> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
> @@ -375,6 +375,45 @@ static ssize_t tpda_trig_sysfs_store(struct device *dev,
>   	return ret;
>   }
>   
> +static ssize_t port_flush_req_show(struct device *dev,
> +				   struct device_attribute *attr,
> +				   char *buf)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	unsigned long val;
> +
> +	if (!drvdata->csdev->refcnt)
> +		return -EINVAL;
> +
> +	guard(spinlock)(&drvdata->spinlock);
> +	val = readl_relaxed(drvdata->base + TPDA_FLUSH_CR);
> +
> +	return sysfs_emit(buf, "0x%lx\n", val);
> +}
> +
> +static ssize_t port_flush_req_store(struct device *dev,
> +				    struct device_attribute *attr,
> +				    const char *buf,
> +				    size_t size)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	u32 val;
> +
> +	if (kstrtou32(buf, 0, &val))
> +		return -EINVAL;
> +
> +	if (!drvdata->csdev->refcnt || !val)
> +		return -EINVAL;
> +
> +	guard(spinlock)(&drvdata->spinlock);
> +	CS_UNLOCK(drvdata->base);
> +	writel_relaxed(val, drvdata->base + TPDA_FLUSH_CR);
> +	CS_LOCK(drvdata->base);
> +
> +	return size;
> +}
> +static DEVICE_ATTR_RW(port_flush_req);
> +
>   static struct attribute *tpda_global_cr_attrs[] = {
>   	tpda_trig_sysfs_rw(global_flush_req, FLREQ),
>   	tpda_trig_sysfs_rw(freq_ts_enable, FREQTS),
> @@ -385,13 +424,23 @@ static struct attribute *tpda_global_cr_attrs[] = {
>   	NULL,
>   };
>   
> +static struct attribute *tpda_attrs[] = {
> +	&dev_attr_port_flush_req.attr,
> +	NULL,
> +};
> +

But why ? Why can't this be a part of the tpda_global_cr_attrs[] ?
For that matter, why is tpda_global_cr_attrs named as such and why not
tpda_attrs ?

Suzuki

>   static struct attribute_group tpda_global_cr_attr_grp = {
>   	.attrs	= tpda_global_cr_attrs,
>   	.name	= "global_cr",
>   };
>   
> +static struct attribute_group tpda_attr_grp = {
> +	.attrs	= tpda_attrs,
> +};
> +
>   static const struct attribute_group *tpda_attr_grps[] = {
>   	&tpda_global_cr_attr_grp,
> +	&tpda_attr_grp,
>   	NULL,
>   };
>   
> diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h
> index 97e2729c15c9..ec93f9cb9648 100644
> --- a/drivers/hwtracing/coresight/coresight-tpda.h
> +++ b/drivers/hwtracing/coresight/coresight-tpda.h
> @@ -10,6 +10,7 @@
>   #define TPDA_Pn_CR(n)		(0x004 + (n * 4))
>   #define TPDA_FPID_CR		(0x084)
>   #define TPDA_SYNCR		(0x08C)
> +#define TPDA_FLUSH_CR		(0x090)
>   
>   /* Cross trigger Global (all ports) flush request bit */
>   #define TPDA_CR_FLREQ		BIT(0)
> 



From dlemoal at kernel.org  Fri Dec 19 02:33:42 2025
From: dlemoal at kernel.org (Damien Le Moal)
Date: Fri, 19 Dec 2025 19:33:42 +0900
Subject: [PATCH v2 1/8] dmaengine: Add API to combine configuration and
 preparation (sg and single)
In-Reply-To: <20251218-dma_prep_config-v2-1-c07079836128@nxp.com>
References: <20251218-dma_prep_config-v2-0-c07079836128@nxp.com>
 <20251218-dma_prep_config-v2-1-c07079836128@nxp.com>
Message-ID: <b081d13b-4af2-4b60-83e5-3553939c1749@kernel.org>

On 12/19/25 00:56, Frank Li wrote:
> Previously, configuration and preparation required two separate calls. This
> works well when configuration is done only once during initialization.
> 
> However, in cases where the burst length or source/destination address must
> be adjusted for each transfer, calling two functions is verbose and
> requires additional locking to ensure both steps complete atomically.
> 
> Add a new API dmaengine_prep_config_single() and dmaengine_prep_config_sg()
> and callback device_prep_config_sg() that combines configuration and
> preparation into a single operation. If the configuration argument is
> passed as NULL, fall back to the existing implementation.
> 
> Add a new API dmaengine_prep_config_single_safe() and
> dmaengine_prep_config_sg_safe() for re-entrancy, which require driver
> implement callback device_prep_config_sg().
> 
> Tested-by: Niklas Cassel <cassel at kernel.org>
> Signed-off-by: Frank Li <Frank.Li at nxp.com>
> ---
> change in v2
> - add () for function
> - use short name device_prep_sg(), remove "slave" and "config". the 'slave'
> is reduntant. after remove slave, the function name is difference existed
> one, so remove _config suffix.
> ---
>  Documentation/driver-api/dmaengine/client.rst |   9 +++
>  include/linux/dmaengine.h                     | 103 ++++++++++++++++++++++++--
>  2 files changed, 105 insertions(+), 7 deletions(-)
> 
> diff --git a/Documentation/driver-api/dmaengine/client.rst b/Documentation/driver-api/dmaengine/client.rst
> index d491e385d61a98b8a804cd823caf254a2dc62cf4..02c45b7d7a779421411eb9c68325cdedafcfe3b1 100644
> --- a/Documentation/driver-api/dmaengine/client.rst
> +++ b/Documentation/driver-api/dmaengine/client.rst
> @@ -80,6 +80,10 @@ The details of these operations are:
>  
>    - slave_sg: DMA a list of scatter gather buffers from/to a peripheral
>  
> +  - config_sg: Similar with slave_sg, just pass down dma_slave_config
> +    struct to avoid call dmaengine_slave_config() every time if need

...struct to avoid calling dmaengine_slave_config() every time adjusting the
burst length or the FIFO address is needed.

> +    adjust burst length or FIFO address.
> +

> +static inline struct dma_async_tx_descriptor *
> +dmaengine_prep_config_single_safe(struct dma_chan *chan, dma_addr_t buf,
> +	size_t len, enum dma_transfer_direction dir, unsigned long flags,
> +	struct dma_slave_config *config)
>  {
>  	struct scatterlist sg;
> +
>  	sg_init_table(&sg, 1);
>  	sg_dma_address(&sg) = buf;
>  	sg_dma_len(&sg) = len;
>  
> -	if (!chan || !chan->device || !chan->device->device_prep_slave_sg)
> +	if (!chan || !chan->device || !chan->device->device_prep_config_sg)
> +		return NULL;

While at it, please move this arguments check before the sg initialization.
Otherwise, this is a little odd (argument checks generally are done first).

> +
> +	return chan->device->device_prep_config_sg(chan, &sg, 1, dir,
> +						   flags, config, NULL);
> +}
> +
> +static inline struct dma_async_tx_descriptor *
> +dmaengine_prep_config_single(struct dma_chan *chan, dma_addr_t buf, size_t len,
> +	enum dma_transfer_direction dir, unsigned long flags,
> +	struct dma_slave_config *config)
> +{
> +	struct scatterlist sg;
> +
> +	sg_init_table(&sg, 1);
> +	sg_dma_address(&sg) = buf;
> +	sg_dma_len(&sg) = len;
> +
> +	if (!chan || !chan->device)
> +		return NULL;

Same here. Check these before initializing sg.

> +
> +	if (chan->device->device_prep_config_sg)
> +		return dmaengine_prep_config_sg_safe(chan, &sg, 1, dir,
> +						     flags, config);
> +
> +	if (config)
> +		if (dmaengine_slave_config(chan, config))
> +			return NULL;
> +
> +	if (!chan->device->device_prep_slave_sg)
>  		return NULL;
>  
>  	return chan->device->device_prep_slave_sg(chan, &sg, 1,
>  						  dir, flags, NULL);
>  }
>  
> +static inline struct dma_async_tx_descriptor *
> +dmaengine_prep_slave_single(struct dma_chan *chan, dma_addr_t buf, size_t len,
> +			    enum dma_transfer_direction dir,
> +			    unsigned long flags)
> +{
> +	return dmaengine_prep_config_single(chan, buf, len, dir, flags, NULL);
> +}
> +
>  /**
>   * dmaengine_prep_peripheral_dma_vec() - Prepare a DMA scatter-gather descriptor
>   * @chan: The channel to be used for this descriptor
> @@ -1009,17 +1079,36 @@ static inline struct dma_async_tx_descriptor *dmaengine_prep_peripheral_dma_vec(
>  							    dir, flags);
>  }
>  
> -static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_sg(
> +static inline struct dma_async_tx_descriptor *dmaengine_prep_config_sg(

Very odd line split. Please split this after the "*" of the return type.

>  	struct dma_chan *chan, struct scatterlist *sgl,	unsigned int sg_len,
> -	enum dma_transfer_direction dir, unsigned long flags)
> +	enum dma_transfer_direction dir, unsigned long flags,
> +	struct dma_slave_config *config)
>  {
> -	if (!chan || !chan->device || !chan->device->device_prep_slave_sg)
> +	if (!chan || !chan->device)
> +		return NULL;
> +
> +	if (chan->device->device_prep_config_sg)
> +		return dmaengine_prep_config_sg_safe(chan, sgl, sg_len,
> +					dir, flags, config);
> +
> +	if (config)
> +		if (dmaengine_slave_config(chan, config))
> +			return NULL;
> +
> +	if (!chan->device->device_prep_slave_sg)
>  		return NULL;
>  
>  	return chan->device->device_prep_slave_sg(chan, sgl, sg_len,
>  						  dir, flags, NULL);
>  }
>  
> +static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_sg(

Same comment here.

> +	struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len,
> +	enum dma_transfer_direction dir, unsigned long flags)
> +{
> +	return dmaengine_prep_config_sg(chan, sgl, sg_len, dir, flags, NULL);
> +}
> +
>  #ifdef CONFIG_RAPIDIO_DMA_ENGINE
>  struct rio_dma_ext;
>  static inline struct dma_async_tx_descriptor *dmaengine_prep_rio_sg(
> 


-- 
Damien Le Moal
Western Digital Research


From dlemoal at kernel.org  Fri Dec 19 02:34:30 2025
From: dlemoal at kernel.org (Damien Le Moal)
Date: Fri, 19 Dec 2025 19:34:30 +0900
Subject: [PATCH v2 2/8] PCI: endpoint: pci-epf-test: Use
 dmaenigne_prep_config_single() to simplify code
In-Reply-To: <20251218-dma_prep_config-v2-2-c07079836128@nxp.com>
References: <20251218-dma_prep_config-v2-0-c07079836128@nxp.com>
 <20251218-dma_prep_config-v2-2-c07079836128@nxp.com>
Message-ID: <bb3a60d6-8503-4990-bdf7-7e14b13bddff@kernel.org>

On 12/19/25 00:56, Frank Li wrote:
> Use dmaenigne_prep_config_single() to simplify code.
> 
> No functional change.
> 
> Tested-by: Niklas Cassel <cassel at kernel.org>
> Signed-off-by: Frank Li <Frank.Li at nxp.com>

Looks good.

Reviewed-by: Damien Le Moal <dlemoal at kernel.org>

-- 
Damien Le Moal
Western Digital Research


From dlemoal at kernel.org  Fri Dec 19 02:35:22 2025
From: dlemoal at kernel.org (Damien Le Moal)
Date: Fri, 19 Dec 2025 19:35:22 +0900
Subject: [PATCH v2 3/8] dmaengine: dw-edma: Use new
 .device_prep_config_sg() callback
In-Reply-To: <20251218-dma_prep_config-v2-3-c07079836128@nxp.com>
References: <20251218-dma_prep_config-v2-0-c07079836128@nxp.com>
 <20251218-dma_prep_config-v2-3-c07079836128@nxp.com>
Message-ID: <69a9daf3-0439-4b6c-bc12-1b0ea7f01fba@kernel.org>

On 12/19/25 00:56, Frank Li wrote:
> Use the new .device_prep_config_sg() callback to combine configuration and
> descriptor preparation.
> 
> No functional changes.
> 
> Tested-by: Niklas Cassel <cassel at kernel.org>
> Signed-off-by: Frank Li <Frank.Li at nxp.com>

Looks good.

Reviewed-by: Damien Le Moal <dlemoal at kernel.org>

-- 
Damien Le Moal
Western Digital Research


From sudeep.holla at arm.com  Fri Dec 19 02:37:48 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Fri, 19 Dec 2025 10:37:48 +0000
Subject: [RFC PATCH 1/5] firmware: smccc: LFA: use smcc 1.2
In-Reply-To: <b8fdec67-584f-492e-b2a7-8c932871f459@nvidia.com>
References: <20251208221319.1524888-1-vvidwans@nvidia.com>
 <20251208221319.1524888-2-vvidwans@nvidia.com>
 <20251209-curvy-walrus-of-wonder-dbb178@sudeepholla>
 <b8fdec67-584f-492e-b2a7-8c932871f459@nvidia.com>
Message-ID: <20251219-thundering-striped-nightingale-db4ecf@sudeepholla>

On Fri, Dec 19, 2025 at 12:47:52AM -0800, Vedashree Vidwans wrote:
> 
> 
> On 12/9/25 03:42, Sudeep Holla wrote:
> > On Mon, Dec 08, 2025 at 10:13:11PM +0000, Vedashree Vidwans wrote:
> > > Update driver to use SMCCC 1.2+ version as mentioned in the LFA spec.
> > > 
> > 
> > I would prefer if you work with Salman Nabi and get this incorporated
> > in the original patch by providing this as a review feedback.
> > 
> > There is no point in having this independent of the original patch as it
> > is not yet merged.
> > 
> > -- 
> > Regards,
> > Sudeep
> 
> Thank you for the suggestion.
> 
> Hi Salman,
> Could we come up with a strategy to combine the LFA driver patches? I have
> been working on this recently and I would be happy to revise all the patches
> so that we are followiing the specification from the start.
> 
> Please let me know if you think of any other approach.
> 

Ideally, you should comment directly on the original submission, outlining the
specific changes you would like to see - just as you would when reviewing a
patch. This helps document your requests clearly and allows the author to
address them and post a revised version, ensuring that all changes are
properly tracked on the mailing list.

-- 
Regards,
Sudeep


From dlemoal at kernel.org  Fri Dec 19 02:38:07 2025
From: dlemoal at kernel.org (Damien Le Moal)
Date: Fri, 19 Dec 2025 19:38:07 +0900
Subject: [PATCH v2 4/8] dmaengine: dw-edma: Pass dma_slave_config to
 dw_edma_device_transfer()
In-Reply-To: <20251218-dma_prep_config-v2-4-c07079836128@nxp.com>
References: <20251218-dma_prep_config-v2-0-c07079836128@nxp.com>
 <20251218-dma_prep_config-v2-4-c07079836128@nxp.com>
Message-ID: <bff84f52-a23c-4a76-977b-9deb2306b154@kernel.org>

On 12/19/25 00:56, Frank Li wrote:
> Pass dma_slave_config to dw_edma_device_transfer() to support atomic
> configuration and descriptor preparation when a non-NULL config is
> provided to device_prep_config_sg().
> 
> Tested-by: Niklas Cassel <cassel at kernel.org>
> Signed-off-by: Frank Li <Frank.Li at nxp.com>
> ---
>  drivers/dma/dw-edma/dw-edma-core.c | 22 ++++++++++++++++------
>  1 file changed, 16 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index e005b7bdaee156a3f4573b4734f50e3e47553dd2..1863254bf61eb892cb0cf8934e53b40d32027dfa 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
> @@ -230,6 +230,15 @@ static int dw_edma_device_config(struct dma_chan *dchan,
>  	return 0;
>  }
>  
> +static struct dma_slave_config *
> +dw_edma_device_get_config(struct dma_chan *dchan,
> +			  struct dma_slave_config *config)
> +{
> +	struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
> +
> +	return config ? config : &chan->config;
> +}

I would rewrite this as:

static struct dma_slave_config *
dw_edma_device_get_config(struct dma_chan *dchan,
			  struct dma_slave_config *config)
{
	struct dw_edma_chan *chan;

	if (config)
		return config;

	chan = dchan2dw_edma_chan(dchan);

	return &chan->config;
}

That avoids the call to dchan2dw_edma_chan() if config is specified.

-- 
Damien Le Moal
Western Digital Research


From dlemoal at kernel.org  Fri Dec 19 02:38:53 2025
From: dlemoal at kernel.org (Damien Le Moal)
Date: Fri, 19 Dec 2025 19:38:53 +0900
Subject: [PATCH v2 5/8] nvmet: pci-epf: Remove unnecessary
 dmaengine_terminate_sync() on each DMA transfer
In-Reply-To: <20251218-dma_prep_config-v2-5-c07079836128@nxp.com>
References: <20251218-dma_prep_config-v2-0-c07079836128@nxp.com>
 <20251218-dma_prep_config-v2-5-c07079836128@nxp.com>
Message-ID: <8d4ae6b3-096a-4e12-8fa8-abaad2e953ad@kernel.org>

On 12/19/25 00:56, Frank Li wrote:
> dmaengine_terminate_sync() cancels all pending requests. Calling it for
> every DMA transfer is unnecessary and counterproductive. This function is
> generally intended for cleanup paths such as module removal, device close,
> or unbind operations.
> 
> Remove the redundant calls for success path and keep it only at error path.
> 
> Tested-by: Niklas Cassel <cassel at kernel.org>
> Signed-off-by: Frank Li <Frank.Li at nxp.com>

Looks good.

Reviewed-by: Damien Le Moal <dlemoal at kernel.org>

-- 
Damien Le Moal
Western Digital Research


From ahmed.tiba at arm.com  Fri Dec 19 02:37:57 2025
From: ahmed.tiba at arm.com (Ahmed Tiba)
Date: Fri, 19 Dec 2025 10:37:57 +0000
Subject: [PATCH 10/12] dt-bindings: ras: document estatus provider
In-Reply-To: <57772b40-e4d9-4152-9709-04ba897608d0@kernel.org>
Message-ID: <20251219103850.2722580-1-ahmed.tiba@arm.com>


On 19/12/2025 10:53, Krzysztof Kozlowski wrote:
>> On 17/12/2025 12:41, Krzysztof Kozlowski wrote:
>>>> +properties:
>>>> +  compatible:
>>>> +    const: arm,ras-ffh
>>>
>>> Again ras - what's that? Your patch or binding must explain that.
>>
>> That updated description will explicitly expand the Arm RAS acronym so the
>> compatible string is self-explanatory.
>>
>>>> +
>>>> +  reg:
>>>> +    minItems: 1
>>>
>>> Why is this flexible?
>>
>> I'll keep `reg` describing the CPER status buffer, cap it at two entries, and
>> document the second entry as the optional doorbell register that some firmware
>> requires before reusing the buffer.
>
> I still do not understand why this is flexible or in other words - why
> second address space appears and disappears.

The second address space is only present for firmware that exposes an ACK register.
Not all platforms require this extra handshake so that address shows up only
when the extra handshake exists. I?ll say that clearly in the binding
so it?s obvious the region is optional.

>>
>>>> +    items:
>>>> +      - description: CPER status block exposed by firmware
>>>> +      - description:
>>>> +          Optional 32- or 64-bit acknowledgment register. Firmware watches this
>>>> +          register and expects bit 0 to be written to 1 once the OS consumes the
>>>> +          status buffer so it can reuse the record.
>>>> +


Best regards,
Ahmed


From taniya.das at oss.qualcomm.com  Fri Dec 19 02:39:18 2025
From: taniya.das at oss.qualcomm.com (Taniya Das)
Date: Fri, 19 Dec 2025 16:09:18 +0530
Subject: [PATCH v2 07/11] dt-bindings: clock: qcom: document the Kaanapali
 GPU Clock Controller
In-Reply-To: <3e8128f4-3cba-4c13-a846-e5f1638a1e0f@kernel.org>
References: <20251125-kaanapali-mmcc-v2-v2-0-fb44e78f300b@oss.qualcomm.com>
 <20251125-kaanapali-mmcc-v2-v2-7-fb44e78f300b@oss.qualcomm.com>
 <20251126-elated-stoic-scorpion-25b630@kuoka>
 <de44560d-4ed8-41fe-be7b-56412b933a8c@oss.qualcomm.com>
 <fbe39eac-7c92-4a08-bafb-31e5c51a0613@kernel.org>
 <503f445e-0d12-407d-bc77-f48ad335639b@oss.qualcomm.com>
 <e8bdb176-b6fb-4dd2-8b5b-9da8073fa915@kernel.org>
 <ca118faf-3451-4b83-9074-82bc5e1f731e@oss.qualcomm.com>
 <3e8128f4-3cba-4c13-a846-e5f1638a1e0f@kernel.org>
Message-ID: <57ab2d5d-5aaa-4f9c-83ae-0f7ebc1e648b@oss.qualcomm.com>



On 12/17/2025 7:24 PM, Krzysztof Kozlowski wrote:
> On 17/12/2025 14:21, Konrad Dybcio wrote:
>> On 12/17/25 11:09 AM, Krzysztof Kozlowski wrote:
>>> On 17/12/2025 10:32, Taniya Das wrote:
>>>>>>
>>>>>> We would like to leverage the existing common clock driver(GDSC) code to
>>>>>
>>>>> Fix the driver code if it cannot handle other cells. Your drivers do not
>>>>> matter for choices made in bindings.
>>>>>
>>>>
>>>> As it is still a clock controller from hardware design and in SW I will
>>>> be map the entire hardware region and this way this clock controller
>>>> will also be aligned to the existing clock controllers and keep the
>>>> #power-domain-cells = <1> as other CCs.
>>>
>>> I don't see how this resolves my comment.
>>
>> Spanning the entire 0x6000-long block will remove your worry about this
>> description only being 2-register-wide
> 
> But that was not the comment here. Taniya replied under comment about
> cells. We are not discussing here some other things...
> 

I will review and add support for handling #power-domain-cells = <0> in
our common code of clock & gdsc. However, the initial intent was to keep
the GDSC phandle uniform across chipsets as this is a clock controller
by hardware design, which is why #power-domain-cells was originally set
to <1>.

-- 
Thanks,
Taniya Das



From sudeep.holla at arm.com  Fri Dec 19 02:40:40 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Fri, 19 Dec 2025 10:40:40 +0000
Subject: [RFC PATCH 4/5] firmware: smccc: register as platform driver
In-Reply-To: <29248f8c-b57d-4818-851c-7905dc9f8317@nvidia.com>
References: <20251208221319.1524888-1-vvidwans@nvidia.com>
 <20251208221319.1524888-5-vvidwans@nvidia.com>
 <20251209-hysterical-cobalt-viper-54433c@sudeepholla>
 <29248f8c-b57d-4818-851c-7905dc9f8317@nvidia.com>
Message-ID: <20251219-hairy-mighty-scorpion-fbed46@sudeepholla>

On Fri, Dec 19, 2025 at 12:26:30AM -0800, Vedashree Vidwans wrote:
> 
> On 12/9/25 03:47, Sudeep Holla wrote:
> > On Mon, Dec 08, 2025 at 10:13:14PM +0000, Vedashree Vidwans wrote:
> > > - Update driver to be in-built kernel module. This will ensure driver is
> > > installed in kernel and would not require any user intervention.
> > > - Register the LFA driver as a platform driver corresponding to
> > > 'armhf000' device. The driver will be invoked when the device is
> > > detected on a platform.
> > > - Add functionality to register LFA interrupt in the driver probe().
> > > This LFA IRQ number will be retrived from the LFA device node.
> > > - On IRQ, driver will query FW component details and trigger activation
> > > of capable and pending FW component. The driver will loop to update FW
> > > component details after every successful FW component activation.
> > > - Mutex synchronization is implemented to avoid concurrent LFA updates
> > > through interrupt and sysfs interfaces.
> > > 
> > > Device node snippet from LFA spec[1]:
> > > fwu0 {
> > >      compatible = "arm,armhf000";
> > >      memory-region = <&fwu_payload>;
> > >      interrupt-parent = <&ic>;
> > >      interrupts = <0 100 1>; // SPI, Interrupt #100, Edge Rising
> > > };
> > > 
> > 
> > This will be gone in the latest beta of LFA, so please discuss and get
> > an agreement for the LFA device tree bindings.
> > 
> > We don't just use ACPI HID as devicetree compatibles. There are more
> > aligned with ACPI CID IIUC but I don't expect you to use ACPI CID just to
> > match DT compatible as ACPI HID will be defined for LFA.
> > 
> Thank you for your comment.
> Sorry I haven't completely understood the concern here. I am using the ACPI
> HID and device node compatible string provided by the LFA spec.

Yes I know, but take a look at updated specification please [1].

> Please find below ACPI and device tree node from the spec for reference.

Yes they are obsolete as they no longer align with the latest specification.

> In case the LFA spec is updated, I will revise the driver implementation.

Indeed, that is the expectation. That's exactly what I meant.

-- 
Regards,
Sudeep

[1] https://developer.arm.com/documentation/den0147/1-0bet1


From leo.yan at arm.com  Fri Dec 19 02:42:41 2025
From: leo.yan at arm.com (Leo Yan)
Date: Fri, 19 Dec 2025 10:42:41 +0000
Subject: [PATCH v2 00/12] coresight: Add CPU cluster
 funnel/replicator/tmc support
In-Reply-To: <927f15d5-da2a-4282-b80f-c1c7563a4367@oss.qualcomm.com>
References: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
 <20251218104027.GA1790402@e132581.arm.com>
 <927f15d5-da2a-4282-b80f-c1c7563a4367@oss.qualcomm.com>
Message-ID: <20251219104241.GB9788@e132581.arm.com>

On Fri, Dec 19, 2025 at 09:50:18AM +0800, yuanfang zhang wrote:

[...]

> It is due to the particular characteristics of the CPU cluster power domain.
> Runtime PM for CPU devices works little different, it is mostly used to manage hierarchical
> CPU topology (PSCI OSI mode) to talk with genpd framework to manage the last CPU handling in
> cluster.
> It doesn?t really send IPI to wakeup CPU device (It don?t have .power_on/.power_off) callback
> implemented which gets invoked from .runtime_resume callback. This behavior is aligned with
> the upstream Kernel.

Just for easier understanding, let me give an example:

    funnel0: funnel at 10000000 {
        compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
        reg = <0x10000000 0x1000>;

        clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
        clock-names = "apb_pclk", "atclk";
        power-domains = <&cluster0_pd>;
    }

If funnel0 is bound to cluster's power domain, kernel's genPD will
automatically enable cluster power domain before access registers.

My understanding is your driver or firmware fails to turn on a cluster
power domain without waking up a CPU (and without sending IPI).  It is
not a kernel issue or limitation, and no any incorrect in PSCI OSI.

As Suzuki said, you might directly reply Sudeep's questions.  We would
confirm if any flaw in common code.

> > P.s., currently you can use "taskset" as a temporary solution without
> > any code change, something like:
> > 
> >   taskset -c 0 echo 1 > /sys/bus/coresight/devices/etm0/enable_source
> 
> This can address the runtime issue, but it does not resolve the problem during the probe phase.

Indeed.  If you insmod mode, you might can temporarily disable idle
states?

    exec 3<> /dev/cpu_dma_latency; echo 0 >&3
    insmod
    exec 3<>-

Thanks,
Leo


From dlemoal at kernel.org  Fri Dec 19 02:42:57 2025
From: dlemoal at kernel.org (Damien Le Moal)
Date: Fri, 19 Dec 2025 19:42:57 +0900
Subject: [PATCH v2 6/8] nvmet: pci-epf: Use
 dmaengine_prep_config_single_safe() API
In-Reply-To: <20251218-dma_prep_config-v2-6-c07079836128@nxp.com>
References: <20251218-dma_prep_config-v2-0-c07079836128@nxp.com>
 <20251218-dma_prep_config-v2-6-c07079836128@nxp.com>
Message-ID: <0fa95ea2-4539-472b-adae-300e46a78f20@kernel.org>

On 12/19/25 00:56, Frank Li wrote:
> Use the new dmaengine_prep_config_single_safe() API to combine the
> configuration and descriptor preparation into a single call.
> 
> Since dmaengine_prep_config_single_safe() performs the configuration and
> preparation atomically and dw edma driver implement prep_config_sg() call
> back, so dmaengine_prep_config_single() is reentriable, the mutex can be
> removed.

What about for platforms other than DesignWare EDMA ?
This is a generic endpoint driver that can work on any platform that is endpoint
capable and that has a DMA channel for the PCI endpoint.

The dmaengine_prep_config_single_safe() API should be handling everything
transparently for any platform, regardless of the DMA channel driver
implementing or not the prep_config_sg() callback.

For platforms that do not implement it, I suspect that the mutex will still be
needed here. So how to we resolve this ? Ideally, all of that should be hidden
by the DMA API. The endpoint driver should not need to deal with these differences.

> 
> Tested-by: Niklas Cassel <cassel at kernel.org>
> Signed-off-by: Frank Li <Frank.Li at nxp.com>
> ---
>  drivers/nvme/target/pci-epf.c | 18 ++++--------------
>  1 file changed, 4 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c
> index 56b1c6a7706a9e2dd9d8aaf17b440129b948486c..8b5ea5d4c79dfd461b767cfd4033a9e4604c94b1 100644
> --- a/drivers/nvme/target/pci-epf.c
> +++ b/drivers/nvme/target/pci-epf.c
> @@ -388,22 +388,15 @@ static int nvmet_pci_epf_dma_transfer(struct nvmet_pci_epf *nvme_epf,
>  		return -EINVAL;
>  	}
>  
> -	mutex_lock(lock);
> -
>  	dma_dev = dmaengine_get_dma_device(chan);
>  	dma_addr = dma_map_single(dma_dev, seg->buf, seg->length, dir);
>  	ret = dma_mapping_error(dma_dev, dma_addr);
>  	if (ret)
> -		goto unlock;
> -
> -	ret = dmaengine_slave_config(chan, &sconf);
> -	if (ret) {
> -		dev_err(dev, "Failed to configure DMA channel\n");
> -		goto unmap;
> -	}
> +		return ret;
>  
> -	desc = dmaengine_prep_slave_single(chan, dma_addr, seg->length,
> -					   sconf.direction, DMA_CTRL_ACK);
> +	desc = dmaengine_prep_config_single_safe(chan, dma_addr, seg->length,
> +						 sconf.direction,
> +						 DMA_CTRL_ACK, &sconf);
>  	if (!desc) {
>  		dev_err(dev, "Failed to prepare DMA\n");
>  		ret = -EIO;
> @@ -426,9 +419,6 @@ static int nvmet_pci_epf_dma_transfer(struct nvmet_pci_epf *nvme_epf,
>  unmap:
>  	dma_unmap_single(dma_dev, dma_addr, seg->length, dir);
>  
> -unlock:
> -	mutex_unlock(lock);
> -
>  	return ret;
>  }
>  
> 


-- 
Damien Le Moal
Western Digital Research


From ahmed.tiba at arm.com  Fri Dec 19 02:47:53 2025
From: ahmed.tiba at arm.com (Ahmed Tiba)
Date: Fri, 19 Dec 2025 10:47:53 +0000
Subject: [PATCH 10/12] dt-bindings: ras: document estatus provider
In-Reply-To: <57772b40-e4d9-4152-9709-04ba897608d0@kernel.org>
Message-ID: <20251219104759.2726164-1-ahmed.tiba@arm.com>


On 19/12/2025 10:53, Krzysztof Kozlowski wrote:
>> On 17/12/2025 12:41, Krzysztof Kozlowski wrote:
>>>> +properties:
>>>> +  compatible:
>>>> +    const: arm,ras-ffh
>>>
>>> Again ras - what's that? Your patch or binding must explain that.
>>
>> That updated description will explicitly expand the Arm RAS acronym so the
>> compatible string is self-explanatory.
>>
>>>> +
>>>> +  reg:
>>>> +    minItems: 1
>>>
>>> Why is this flexible?
>>
>> I'll keep `reg` describing the CPER status buffer, cap it at two entries, and
>> document the second entry as the optional doorbell register that some firmware
>> requires before reusing the buffer.
>
> I still do not understand why this is flexible or in other words - why
> second address space appears and disappears.

The second address space is only present for firmware that exposes an ACK register.
Not all platforms require this extra handshake so that address shows up only
when the extra handshake exists. I?ll say that clearly in the binding
so it?s obvious the region is optional.

>>
>>>> +    items:
>>>> +      - description: CPER status block exposed by firmware
>>>> +      - description:
>>>> +          Optional 32- or 64-bit acknowledgment register. Firmware watches this
>>>> +          register and expects bit 0 to be written to 1 once the OS consumes the
>>>> +          status buffer so it can reuse the record.
>>>> +


Best regards,
Ahmed


From jonathanh at nvidia.com  Fri Dec 19 02:48:22 2025
From: jonathanh at nvidia.com (Jon Hunter)
Date: Fri, 19 Dec 2025 10:48:22 +0000
Subject: [PATCH V7 2/4] iommu/arm-smmu-v3: Add device-tree support for
 CMDQV driver
In-Reply-To: <aUROk0jRQoLmBRo3@Asurada-Nvidia>
References: <20251215064819.3345361-1-amhetre@nvidia.com>
 <20251215064819.3345361-3-amhetre@nvidia.com>
 <23df682e-6d08-4827-994e-1bbd89e5c903@nvidia.com>
 <5e9a0ce1-a0ba-4a31-be95-99f349ec6028@nvidia.com>
 <e7d3e95f-a885-4b13-ab4d-bc82793c5396@nvidia.com>
 <aUROk0jRQoLmBRo3@Asurada-Nvidia>
Message-ID: <b2df8ce6-d336-457a-8169-f2eccec3c12e@nvidia.com>


On 18/12/2025 18:57, Nicolin Chen wrote:
> On Thu, Dec 18, 2025 at 08:48:32AM +0000, Jon Hunter wrote:
>> On 18/12/2025 06:32, Ashish Mhetre wrote:
>>> On 12/18/2025 2:13 AM, Jon Hunter wrote:
>>>>> +??? smmu->impl_dev = &pdev->dev;
>>>>> +??? smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
>>>>> +??? dev_info(smmu->dev, "found companion CMDQV device: %s\n",
>>>>> +???????? dev_name(smmu->impl_dev));
>>>>
>>>> This seems a bit noisy. dev_dbg?
>>>>
>>>
>>> This info print is similar to what is there in ACPI path as well.
>>> It's only a single print per SMMU at boot time. Should I still change
>>> it to dev_dbg?
>>
>> Yes, I would.
> 
> It's really not that bad IMHO, I am not against that though..
> 
> If we have to change that, we'd need another patch changing the
> one in the ACPI path as well to keep things aligned.

Regardless of what is already present, does not mean we need add more 
prints to just say everything is OK.

Jon

-- 
nvpublic



From leo.yan at arm.com  Fri Dec 19 03:38:03 2025
From: leo.yan at arm.com (Leo Yan)
Date: Fri, 19 Dec 2025 11:38:03 +0000
Subject: [PATCH v2 RESEND] coresight: etm-perf: Fix reference count leak
 in etm_setup_aux
In-Reply-To: <d4946831-fc8c-4727-abec-3edd92e357d1@arm.com>
References: <f85c7d37-4980-46f0-9136-353a35a8f0ed@oss.qualcomm.com>
 <20251219023949.12699-1-make24@iscas.ac.cn>
 <20251219094141.GA9788@e132581.arm.com>
 <d4946831-fc8c-4727-abec-3edd92e357d1@arm.com>
Message-ID: <20251219113803.GC9788@e132581.arm.com>

On Fri, Dec 19, 2025 at 09:59:54AM +0000, Suzuki K Poulose wrote:

[...]

> > diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c
> > index 0db64c5f4995..2b34f818ba88 100644
> > --- a/drivers/hwtracing/coresight/coresight-platform.c
> > +++ b/drivers/hwtracing/coresight/coresight-platform.c
> > @@ -107,14 +107,16 @@ coresight_find_device_by_fwnode(struct fwnode_handle *fwnode)
> >   	 * platform bus.
> >   	 */
> >   	dev = bus_find_device_by_fwnode(&platform_bus_type, fwnode);
> > -	if (dev)
> > -		return dev;
> >   	/*
> >   	 * We have a configurable component - circle through the AMBA bus
> >   	 * looking for the device that matches the endpoint node.
> >   	 */
> > -	return bus_find_device_by_fwnode(&amba_bustype, fwnode);
> > +	if (!dev)
> > +		dev = bus_find_device_by_fwnode(&amba_bustype, fwnode);
> > +
> > +	put_device(dev);
> 
> ^^ NAK, see below.
> 
> > +	return dev;
> >   }
> >   /*
> > @@ -274,7 +276,6 @@ static int of_coresight_parse_endpoint(struct device *dev,
> >   	of_node_put(rparent);
> >   	of_node_put(rep);
> > -	put_device(rdev);
> 
> This doesn't look good. We can't use the "dev" reliably without the
> reference count. We are opening up use-after-free.

My understanding is we don't grab a device from
coresight_find_device_by_fwnode().  The callers only check whether the
device is present on the bus; if it isn't, the driver defers probe.

This is similiar to coresight_find_csdev_by_fwnode(), which calls
put_device(dev) to release refcnt immediately.  This is why I
suggested the change, so the two functions behave consistently.

Thanks,
Leo


From a.shimko.dev at gmail.com  Fri Dec 19 03:46:16 2025
From: a.shimko.dev at gmail.com (Artem Shimko)
Date: Fri, 19 Dec 2025 14:46:16 +0300
Subject: [PATCH] firmware: arm_scmi: Fix raw mode async completion race
Message-ID: <20251219114617.2057576-1-a.shimko.dev@gmail.com>

A race condition exists in scmi_xfer_raw_worker() where async_done
completion can be accessed after being nullified by
scmi_xfer_raw_waiter_put() in scmi_handle_response(). This happens
because the worker skips wait_for_completion_timeout() when ret has
an error value and goes directly to nullify the async_done.

Fix by waiting for async_done unconditionally when it exists, without
checking the result of the ret variable. This ensures the worker
always synchronizes properly with the scmi_handle_response()'s complete
for async_done.

Fixes: 3c3d818a9317a ("firmware: arm_scmi: Add core raw transmission support")
Signed-off-by: Artem Shimko <a.shimko.dev at gmail.com>
---
Hello maintainers and reviewers,

This patch fixes a race condition in the SCMI raw mode implementation
that can lead to kernel crashes when handling asynchronous delayed
responses.

I temporarily added the trace_printk("%s\n", __func__) to track the problem.

# mount -t tracefs nodev /sys/kernel/tracing
# mount -t debugfs debugfs /sys/kernel/debug
# cd /sys/kernel/debug/tracing
# echo 1 > options/trace_printk
# echo 1 > tracing_on

Doing that until Oops
# echo -e -n 'sorry, but NDA raw msg' > /sys/kernel/debug/scmi/0/raw/message_async 

Without the changes:
[   19.513750] Unable to handle kernel NULL pointer dereference at virtual address NDA
[   19.524756] Oops [#1]
[   19.527034] Modules linked in:
[   19.530097] CPU: 0 UID: 0 PID: 124 Comm: irq/12-1e200000 Not tainted 6.12.0-NDA
...
[   19.638262] [<ffffffff8007af3c>] do_raw_spin_lock+0xa/0x10a
[   19.643843] [<ffffffff80b4e42e>] _raw_spin_lock_irqsave+0x20/0x2c
[   19.649941] [<ffffffff80072dc4>] complete+0x1e/0x76
[   19.654826] [<ffffffff808056bc>] scmi_rx_callback+0x66e/0x7cc
[   19.660589] [<ffffffff80800204>] transport_rx_callback+0x4e/0x56
[   19.666534] [<ffffffff8082f664>] mbox_chan_received_data+0x10/0x1a
[   19.672730] [<ffffffff80830624>] transport_chan_do_rx+0xea/0x136
[   19.678311] [<ffffffff808306c6>] transport_mbox_threaded_isr+0x42/0x9c
[   19.684408] [<ffffffff8008e8ee>] irq_thread_fn+0x1a/0x5a
[   19.689733] [<ffffffff8008e724>] irq_thread+0x16c/0x20a
[   19.694962] [<ffffffff80044032>] kthread+0xda/0xf6
[   19.699761] [<ffffffff80b4f8d6>] ret_from_fork+0xe/0x18
[   19.712403] ---[ end trace 0000000000000000 ]---

With the changes: we dont have the Oops

# echo 0 > tracing_on
# cat trace

Without the changes:
 irq/12-1e200000-120     [000] .....    23.368262: scmi_rx_callback: scmi_handle_response 
   kworker/u45:0-95      [003] .....    23.394836: scmi_xfer_raw_waiter_put: scmi_xfer_raw_waiter_put 
 irq/12-1e200000-120     [000] .....    25.625926: scmi_rx_callback: scmi_handle_response 
   kworker/u44:0-94      [002] .....    25.653884: scmi_xfer_raw_waiter_put: scmi_xfer_raw_waiter_put 
 irq/12-1e200000-120     [000] .....    27.202031: scmi_rx_callback: scmi_handle_response 
   kworker/u45:0-95      [001] .....    27.228216: scmi_xfer_raw_waiter_put: scmi_xfer_raw_waiter_put 
 irq/12-1e200000-120     [000] .....    28.504546: scmi_rx_callback: scmi_handle_response 
   kworker/u45:0-95      [002] .....    28.531534: scmi_xfer_raw_waiter_put: scmi_xfer_raw_waiter_put 
 irq/12-1e200000-120     [000] .....    30.102729: scmi_rx_callback: scmi_handle_response 
   kworker/u44:0-94      [003] .....    30.129688: scmi_xfer_raw_waiter_put: scmi_xfer_raw_waiter_put 
 irq/12-1e200000-120     [000] .....    31.108407: scmi_rx_callback: scmi_handle_response 
   kworker/u44:0-94      [003] .....    31.136012: scmi_xfer_raw_waiter_put: scmi_xfer_raw_waiter_put 
 irq/12-1e200000-120     [000] .....    32.388953: scmi_rx_callback: scmi_handle_response 
   kworker/u44:0-94      [003] .....    32.415700: scmi_xfer_raw_waiter_put: scmi_xfer_raw_waiter_put 
 irq/12-1e200000-120     [000] .....    33.737014: scmi_rx_callback: scmi_handle_response 
   kworker/u44:0-94      [002] .....    33.764977: scmi_xfer_raw_waiter_put: scmi_xfer_raw_waiter_put 
 irq/12-1e200000-120     [000] .....    34.979096: scmi_rx_callback: scmi_handle_response 
   kworker/u45:0-95      [002] .....    35.005377: scmi_xfer_raw_waiter_put: scmi_xfer_raw_waiter_put 
   kworker/u45:0-95      [003] .....    36.758043: scmi_xfer_raw_waiter_put: scmi_xfer_raw_waiter_put <- RC
 irq/12-1e200000-119     [000] .....    37.561734: scmi_rx_callback: scmi_handle_response 

Withthe changes:
irq/12-1e200000-120     [000] .....    23.368262: scmi_rx_callback: scmi_handle_response
   kworker/u45:0-95      [003] .....    23.394836: scmi_xfer_raw_waiter_put: scmi_xfer_raw_waiter_put
 irq/12-1e200000-120     [000] .....    25.625926: scmi_rx_callback: scmi_handle_response
   kworker/u44:0-94      [002] .....    25.653884: scmi_xfer_raw_waiter_put: scmi_xfer_raw_waiter_put
 irq/12-1e200000-120     [000] .....    27.202031: scmi_rx_callback: scmi_handle_response
   kworker/u45:0-95      [001] .....    27.228216: scmi_xfer_raw_waiter_put: scmi_xfer_raw_waiter_put
 irq/12-1e200000-120     [000] .....    28.504546: scmi_rx_callback: scmi_handle_response
   kworker/u45:0-95      [002] .....    28.531534: scmi_xfer_raw_waiter_put: scmi_xfer_raw_waiter_put
 irq/12-1e200000-120     [000] .....    30.102729: scmi_rx_callback: scmi_handle_response
   kworker/u44:0-94      [003] .....    30.129688: scmi_xfer_raw_waiter_put: scmi_xfer_raw_waiter_put
 irq/12-1e200000-120     [000] .....    31.108407: scmi_rx_callback: scmi_handle_response
   kworker/u44:0-94      [003] .....    31.136012: scmi_xfer_raw_waiter_put: scmi_xfer_raw_waiter_put
 irq/12-1e200000-120     [000] .....    32.388953: scmi_rx_callback: scmi_handle_response
   kworker/u44:0-94      [003] .....    32.415700: scmi_xfer_raw_waiter_put: scmi_xfer_raw_waiter_put
 irq/12-1e200000-120     [000] .....    33.737014: scmi_rx_callback: scmi_handle_response
   kworker/u44:0-94      [002] .....    33.764977: scmi_xfer_raw_waiter_put: scmi_xfer_raw_waiter_put
 irq/12-1e200000-120     [000] .....    34.979096: scmi_rx_callback: scmi_handle_response
   kworker/u45:0-95      [002] .....    35.005377: scmi_xfer_raw_waiter_put: scmi_xfer_raw_waiter_put
 irq/12-1e200000-120     [000] .....    36.028136: scmi_rx_callback: scmi_handle_response
   kworker/u45:0-95      [003] .....    36.055553: scmi_xfer_raw_waiter_put: scmi_xfer_raw_waiter_put
 irq/12-1e200000-120     [000] .....    36.906953: scmi_rx_callback: scmi_handle_response
   kworker/u45:0-95      [002] .....    36.933304: scmi_xfer_raw_waiter_put: scmi_xfer_raw_waiter_put
 irq/12-1e200000-120     [000] .....    37.548706: scmi_rx_callback: scmi_handle_response
   kworker/u44:0-94      [003] .....    37.577260: scmi_xfer_raw_waiter_put: scmi_xfer_raw_waiter_put
 irq/12-1e200000-120     [000] .....    38.079993: scmi_rx_callback: scmi_handle_response
   kworker/u44:0-94      [002] .....    38.108648: scmi_xfer_raw_waiter_put: scmi_xfer_raw_waiter_put
 irq/12-1e200000-120     [000] .....    38.512822: scmi_rx_callback: scmi_handle_response
   kworker/u44:0-94      [002] .....    38.540403: scmi_xfer_raw_waiter_put: scmi_xfer_raw_waiter_put
   ...

--
Regards,
Artem

 drivers/firmware/arm_scmi/raw_mode.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/firmware/arm_scmi/raw_mode.c b/drivers/firmware/arm_scmi/raw_mode.c
index 73db5492ab44..362773f3114d 100644
--- a/drivers/firmware/arm_scmi/raw_mode.c
+++ b/drivers/firmware/arm_scmi/raw_mode.c
@@ -479,7 +479,7 @@ static void scmi_xfer_raw_worker(struct work_struct *work)
 				    ret, scmi_inflight_count(raw->handle));
 
 		/* Wait also for an async delayed response if needed */
-		if (!ret && xfer->async_done) {
+		if (xfer->async_done) {
 			unsigned long tmo = msecs_to_jiffies(SCMI_MAX_RESPONSE_TIMEOUT);
 
 			if (!wait_for_completion_timeout(xfer->async_done, tmo))
-- 
2.43.0



From suzuki.poulose at arm.com  Fri Dec 19 03:48:35 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Fri, 19 Dec 2025 11:48:35 +0000
Subject: [PATCH v2 RESEND] coresight: etm-perf: Fix reference count leak
 in etm_setup_aux
In-Reply-To: <20251219113803.GC9788@e132581.arm.com>
References: <f85c7d37-4980-46f0-9136-353a35a8f0ed@oss.qualcomm.com>
 <20251219023949.12699-1-make24@iscas.ac.cn>
 <20251219094141.GA9788@e132581.arm.com>
 <d4946831-fc8c-4727-abec-3edd92e357d1@arm.com>
 <20251219113803.GC9788@e132581.arm.com>
Message-ID: <5a967265-b527-4ca0-bf63-f5f7cf9013a3@arm.com>

On 19/12/2025 11:38, Leo Yan wrote:
> On Fri, Dec 19, 2025 at 09:59:54AM +0000, Suzuki K Poulose wrote:
> 
> [...]
> 
>>> diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c
>>> index 0db64c5f4995..2b34f818ba88 100644
>>> --- a/drivers/hwtracing/coresight/coresight-platform.c
>>> +++ b/drivers/hwtracing/coresight/coresight-platform.c
>>> @@ -107,14 +107,16 @@ coresight_find_device_by_fwnode(struct fwnode_handle *fwnode)
>>>    	 * platform bus.
>>>    	 */
>>>    	dev = bus_find_device_by_fwnode(&platform_bus_type, fwnode);
>>> -	if (dev)
>>> -		return dev;
>>>    	/*
>>>    	 * We have a configurable component - circle through the AMBA bus
>>>    	 * looking for the device that matches the endpoint node.
>>>    	 */
>>> -	return bus_find_device_by_fwnode(&amba_bustype, fwnode);
>>> +	if (!dev)
>>> +		dev = bus_find_device_by_fwnode(&amba_bustype, fwnode);
>>> +
>>> +	put_device(dev);
>>
>> ^^ NAK, see below.
>>
>>> +	return dev;
>>>    }
>>>    /*
>>> @@ -274,7 +276,6 @@ static int of_coresight_parse_endpoint(struct device *dev,
>>>    	of_node_put(rparent);
>>>    	of_node_put(rep);
>>> -	put_device(rdev);
>>
>> This doesn't look good. We can't use the "dev" reliably without the
>> reference count. We are opening up use-after-free.
> 
> My understanding is we don't grab a device from
> coresight_find_device_by_fwnode().  The callers only check whether the
> device is present on the bus; if it isn't, the driver defers probe.
> 
> This is similiar to coresight_find_csdev_by_fwnode(), which calls
> put_device(dev) to release refcnt immediately.  This is why I
> suggested the change, so the two functions behave consistently.
> 

I see, sorry. I saw some other uses of the device, but clearly I was 
wrong. May be we should simply re-structure the function to :

bool coresight_fwnode_device_present(fwnode)
{

	// find and drop the ref if required.
	return true/false;
}

The name "find_device_by_fwnode" and returning a freed reference doesn't
look good to me.

Suzuki

> Thanks,
> Leo



From jakub.turek at elsta.tech  Fri Dec 19 03:48:26 2025
From: jakub.turek at elsta.tech (j.turek)
Date: Fri, 19 Dec 2025 12:48:26 +0100
Subject: [PATCH] serial: xilinx_uartps: fix rs485 delay_rts_after_send
Message-ID: <20251219114826.135017-1-jakub.turek@elsta.tech>

RTS line control with delay should be triggered when there is no more bytes
in kfifo and hardware buffer is empty. Without this patch RTS control is
scheduled right after feeding hardware buffer and this is too early.
RTS line may change state before hardware buffer is empty.
With this patch delayed RTS state change is triggered when function
cdns_uart_handle_tx is called from cdns_uart_isr on CDNS_UART_IXR_TXEMPTY
exactly when hardware completed transmission

Signed-off-by: Jakub Turek  <jakub.turek at elsta.tech>

Fixes: fccc9d9233f9 ("tty: serial: uartps: Add rs485 support to uartps driver")
---
 drivers/tty/serial/xilinx_uartps.c | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 1e4d54fd5762..923a8b57ec82 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -432,6 +432,12 @@ static void cdns_uart_handle_tx(void *dev_id)
 	if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
 		/* Disable the TX Empty interrupt */
 		writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR);
+		/* Set RTS line after delay */
+		if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) {
+			cdns_uart->tx_timer.function = &cdns_rs485_rx_callback;
+			rts_delay = ns_to_ktime(cdns_calc_after_tx_delay(cdns_uart));
+			hrtimer_start(&cdns_uart->tx_timer, rts_delay, HRTIMER_MODE_REL);
+		}
 		return;
 	}
 
@@ -448,13 +454,6 @@ static void cdns_uart_handle_tx(void *dev_id)
 
 	/* Enable the TX Empty interrupt */
 	writel(CDNS_UART_IXR_TXEMPTY, cdns_uart->port->membase + CDNS_UART_IER);
-
-	if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED &&
-	    (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port))) {
-		hrtimer_update_function(&cdns_uart->tx_timer, cdns_rs485_rx_callback);
-		hrtimer_start(&cdns_uart->tx_timer,
-			      ns_to_ktime(cdns_calc_after_tx_delay(cdns_uart)), HRTIMER_MODE_REL);
-	}
 }
 
 /**
-- 
2.34.1



From ben.horgan at arm.com  Fri Dec 19 03:56:17 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 11:56:17 +0000
Subject: [RFC PATCH 05/38] arm64: mpam: Add helpers to change a task or
 cpu's MPAM PARTID/PMG values
In-Reply-To: <20251218104433.00002196@huawei.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-6-james.morse@arm.com>
 <20251218104433.00002196@huawei.com>
Message-ID: <e959f679-9c3c-41d9-b607-ba2e59ed37ee@arm.com>

Hi Jonathan,

On 12/18/25 10:44, Jonathan Cameron wrote:
> On Fri, 5 Dec 2025 21:58:28 +0000
> James Morse <james.morse at arm.com> wrote:
> 
>> Care must be taken when modifying the PARTID and PMG of a task in any
>> per-task structure as writing these values may race with the task being
>> scheduled in, and reading the modified values.
>>
>> Add helpers to set the task properties, and the CPU default value.
>> These use WRITE_ONCE() that pairs with the READ_ONCE() in mpam_get_regval()
>> to avoid causing torn values.
>>
>> CC: Dave Martin <Dave.Martin at arm.com>
>> CC: Ben Horgan <ben.horgan at arm.com>
>> Signed-off-by: James Morse <james.morse at arm.com>
>> ---
>>  arch/arm64/include/asm/mpam.h | 30 ++++++++++++++++++++++++++++++
>>  1 file changed, 30 insertions(+)
>>
>> diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/mpam.h
>> index 86a55176f884..2960ffaf6574 100644
>> --- a/arch/arm64/include/asm/mpam.h
>> +++ b/arch/arm64/include/asm/mpam.h
>> @@ -5,6 +5,7 @@
>>  #define __ASM__MPAM_H
>>  
>>  #include <linux/bitops.h>
>> +#include <linux/bitfield.h>
>>  #include <linux/init.h>
>>  #include <linux/jump_label.h>
>>  #include <linux/percpu.h>
>> @@ -37,6 +38,35 @@ extern u64 arm64_mpam_global_default;
>>   * A value in struct thread_info is used instead of struct task_struct as the
>>   * cpu's u64 register format is used, but struct task_struct has two u32'.
>>   */
> I'd be tempted to reorder this so the comment ends up near at least
> one use of task_thread_info(tsk)->mpam_partid_pmg. Otherwise it is even
> less obvious what it is referring to.
> 
> Easiest might be to put the mpam_get_regval() before the mpam_set_task_partid_pmg()

Yes, this comment positioning was confusing.

> 
> 
>> +static inline void mpam_set_cpu_defaults(int cpu, u16 partid_d, u16 partid_i,
>> +					 u8 pmg_d, u8 pmg_i)
>> +{
>> +	u64 default_val;
>> +
>> +	default_val = FIELD_PREP(MPAM0_EL1_PARTID_D, partid_d);
>> +	default_val |= FIELD_PREP(MPAM0_EL1_PARTID_I, partid_i);
>> +	default_val |= FIELD_PREP(MPAM0_EL1_PMG_D, pmg_d);
>> +	default_val |= FIELD_PREP(MPAM0_EL1_PMG_I, pmg_i);
>> +
>> +	WRITE_ONCE(per_cpu(arm64_mpam_default, cpu), default_val);
>> +}
>> +
>> +static inline void mpam_set_task_partid_pmg(struct task_struct *tsk,
>> +					    u16 partid_d, u16 partid_i,
>> +					    u8 pmg_d, u8 pmg_i)
>> +{
>> +#ifdef CONFIG_ARM64_MPAM
>> +	u64 regval;
>> +
>> +	regval = FIELD_PREP(MPAM0_EL1_PARTID_D, partid_d);
>> +	regval |= FIELD_PREP(MPAM0_EL1_PARTID_I, partid_i);
>> +	regval |= FIELD_PREP(MPAM0_EL1_PMG_D, pmg_d);
>> +	regval |= FIELD_PREP(MPAM0_EL1_PMG_I, pmg_i);
> 
> Maybe a macro or helper to build regval given this replicates the block in
> mpam_set_cpu_defaults.  Obviously ignore if this changes in later patches!

I've added a helper.

> 
>> +
>> +	WRITE_ONCE(task_thread_info(tsk)->mpam_partid_pmg, regval);
>> +#endif
>> +}
>> +
>>  static inline u64 mpam_get_regval(struct task_struct *tsk)
>>  {
>>  #ifdef CONFIG_ARM64_MPAM
> 

Thanks,

Ben



From tomi.valkeinen at ideasonboard.com  Fri Dec 19 03:59:14 2025
From: tomi.valkeinen at ideasonboard.com (Tomi Valkeinen)
Date: Fri, 19 Dec 2025 13:59:14 +0200
Subject: [PATCH 0/2] drm: xlnx: zynqmp_kms: 16 bpp fixes for Xorg startup
 on AMD KV260
In-Reply-To: <20251205123751.2257694-1-mikko.rapeli@linaro.org>
References: <20251205123751.2257694-1-mikko.rapeli@linaro.org>
Message-ID: <533168f1-1655-4947-9032-b08463f502d7@ideasonboard.com>

Hi Mikko,

On 05/12/2025 14:37, Mikko Rapeli wrote:
> Hi,
> 
> Currently on default yocto images Xorg fails to start on AMD KV260
> because 24/32 color depth gets detected but does not actually work.
> 
> These two patches fix the issue and now 16 bpp gets detected
> and Xorg starts and draws on external HDMI display using
> kernel.org based linux-yocto kernel.
> 
> Anatoliy Klymenko (1):
>   drm: xlnx: zynqmp_kms: Init fbdev with 16 bit color
> 
> Mikko Rapeli (1):
>   drm: xlnx: zynqmp_kms: set preferred_depth to 16 bpp
> 
>  drivers/gpu/drm/xlnx/zynqmp_kms.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 

Did you notice the few already sent serieses on the list where the topic
has been discussed?

[PATCH] drm: xlnx: zynqmp_dp: Support DRM_FORMAT_XRGB8888
[PATCH 0/3] drm: zynqmp: Make the video plane primary

Or is there something else on KV260 that messes up the 24 bit color?

 Tomi



From ben.horgan at arm.com  Fri Dec 19 04:02:41 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 12:02:41 +0000
Subject: [RFC PATCH 07/38] arm_mpam: resctrl: Add boilerplate cpuhp and
 domain allocation
In-Reply-To: <20251218113014.00002691@huawei.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-8-james.morse@arm.com>
 <20251218113014.00002691@huawei.com>
Message-ID: <4495db3f-cfb8-4571-b83a-10a24f7b73a9@arm.com>

Hi Jonathan,

On 12/18/25 11:30, Jonathan Cameron wrote:
> On Fri, 5 Dec 2025 21:58:30 +0000
> James Morse <james.morse at arm.com> wrote:
> 
>> resctrl has its own data structures to describe its resources. We
>> can't use these directly as we play tricks with the 'MBA' resource,
>> picking the MPAM controls or monitors that best apply. We may export
>> the same component as both L3 and MBA.
>>
>> Add mpam_resctrl_exports[] as the array of class->resctrl mappings we
>> are exporting, and add the cpuhp hooks that allocated and free the
>> resctrl domain structures.
>>
>> While we're here, plumb in a few other obvious things.
>>
>> CONFIG_ARM_CPU_RESCTRL is used to allow this code to be built
>> even though it can't yet be linked against resctrl.
>>
>> Signed-off-by: James Morse <james.morse at arm.com>
> Hi,
> 
> A few code flow related comments. Fairly trivial stuff but I think
> some parts of this can be made more readable / maintainable with
> minor reorganization.
> 
> Jonathan
> 
> 
>> diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
>> index 2996ad93fc3e..efaf7633bc35 100644
>> --- a/drivers/resctrl/mpam_devices.c
>> +++ b/drivers/resctrl/mpam_devices.c
> ...
> 
>> @@ -2516,6 +2522,12 @@ static void mpam_enable_once(void)
>>  	mutex_unlock(&mpam_list_lock);
>>  	cpus_read_unlock();
>>  
>> +	if (!err) {
>> +		err = mpam_resctrl_setup();
>> +		if (err)
>> +			pr_err("Failed to initialise resctrl: %d\n", err);
>> +	}
>> +
>>  	if (err) {
>>  		mpam_disable_reason = "Failed to enable.";
>>  		schedule_work(&mpam_broken_work);
> 
> I'd be tempted to move this to an error handling block via a goto
> making this bit
> 	if (err)
> 		goto err_disable_mpam;
> 
> 	err = mpam_resctrl_setup();
> 	if (err) {
> 		pr_err();
> 		goto err_dsiable_mpam;
> 	}
> 
> Up to you though. Personally I like all my good paths as straight line
> code with the errors handled in if (err) as that consistency really helps
> readability.  
> 
>> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
>> new file mode 100644
>> index 000000000000..320cebbd37ce
>> --- /dev/null
>> +++ b/drivers/resctrl/mpam_resctrl.c
>> @@ -0,0 +1,329 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +// Copyright (C) 2025 Arm Ltd.
>> +
>> +#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__
>> +
>> +#include <linux/arm_mpam.h>
>> +#include <linux/cacheinfo.h>
>> +#include <linux/cpu.h>
>> +#include <linux/cpumask.h>
>> +#include <linux/errno.h>
>> +#include <linux/list.h>
>> +#include <linux/printk.h>
>> +#include <linux/rculist.h>
>> +#include <linux/resctrl.h>
>> +#include <linux/slab.h>
>> +#include <linux/types.h>
>> +
>> +#include <asm/mpam.h>
>> +
>> +#include "mpam_internal.h"
> 
> 
>> +static struct mpam_resctrl_dom *
>> +mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
>> +{
>> +	int err;
>> +	struct mpam_resctrl_dom *dom;
>> +	struct rdt_mon_domain *mon_d;
>> +	struct rdt_ctrl_domain *ctrl_d;
>> +	struct mpam_class *class = res->class;
>> +	struct mpam_component *comp_iter, *ctrl_comp;
>> +	struct rdt_resource *r = &res->resctrl_res;
>> +
>> +	lockdep_assert_held(&domain_list_lock);
>> +
>> +	ctrl_comp = NULL;
>> +	guard(srcu)(&mpam_srcu);
>> +	list_for_each_entry_srcu(comp_iter, &class->components, class_list,
>> +				 srcu_read_lock_held(&mpam_srcu)) {
>> +		if (cpumask_test_cpu(cpu, &comp_iter->affinity)) {
>> +			ctrl_comp = comp_iter;
>> +			break;
>> +		}
>> +	}
>> +
>> +	/* class has no component for this CPU */
>> +	if (WARN_ON_ONCE(!ctrl_comp))
>> +		return ERR_PTR(-EINVAL);
>> +
>> +	dom = kzalloc_node(sizeof(*dom), GFP_KERNEL, cpu_to_node(cpu));
>> +	if (!dom)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	if (exposed_alloc_capable) {
>> +		dom->ctrl_comp = ctrl_comp;
>> +
>> +		ctrl_d = &dom->resctrl_ctrl_dom;
>> +		mpam_resctrl_domain_hdr_init(cpu, ctrl_comp, &ctrl_d->hdr);
>> +		ctrl_d->hdr.type = RESCTRL_CTRL_DOMAIN;
>> +		/* TODO: this list should be sorted */
>> +		list_add_tail_rcu(&ctrl_d->hdr.list, &r->ctrl_domains);
>> +		err = resctrl_online_ctrl_domain(r, ctrl_d);
>> +		if (err) {
>> +			dom = ERR_PTR(err);
>> +			goto offline_ctrl_domain;
>> +		}
>> +	} else {
>> +		pr_debug("Skipped control domain online - no controls\n");
>> +	}
>> +
>> +	if (exposed_mon_capable) {
>> +		mon_d = &dom->resctrl_mon_dom;
>> +		mpam_resctrl_domain_hdr_init(cpu, ctrl_comp, &mon_d->hdr);
>> +		mon_d->hdr.type = RESCTRL_MON_DOMAIN;
>> +		/* TODO: this list should be sorted */
>> +		list_add_tail_rcu(&mon_d->hdr.list, &r->mon_domains);
>> +		err = resctrl_online_mon_domain(r, mon_d);
>> +		if (err) {
>> +			dom = ERR_PTR(err);
>> +			goto offline_mon_hdr;
>> +		}
>> +	} else {
>> +		pr_debug("Skipped monitor domain online - no monitors\n");
>> +	}
>> +	goto out;
> 
> To keep flow simple, return here.  I thought maybe there was more stuff
> that was always done (added in later patches) but not seeing that.
> If there were then it would be a fairly strong indicator that a different
> code structure makes more sense - probably with some helper functions.

Makes sense.

> 
>> +
>> +offline_mon_hdr:
>> +	mpam_resctrl_offline_domain_hdr(cpu, &mon_d->hdr);
>> +offline_ctrl_domain:
>> +	resctrl_offline_ctrl_domain(r, ctrl_d);
>> +out:
>> +	return dom;
>> +}
>> +
>> +static struct mpam_resctrl_dom *
>> +mpam_resctrl_get_domain_from_cpu(int cpu, struct mpam_resctrl_res *res)
>> +{
>> +	struct mpam_resctrl_dom *dom;
>> +	struct rdt_ctrl_domain *ctrl_d;
>> +
>> +	lockdep_assert_cpus_held();
>> +
>> +	list_for_each_entry_rcu(ctrl_d, &res->resctrl_res.ctrl_domains,
>> +				hdr.list) {
>> +		dom = container_of(ctrl_d, struct mpam_resctrl_dom,
>> +				   resctrl_ctrl_dom);
> 
> I'm lazy so haven't checked for more code here in later patches, but
> if not, why not iterate the list to access the domain directly rather
> than jumping through the rdt_ctrl_domain?
> 
> Something along lines of:
> 	
> 	list_for_each_entry_rcu(dom, &res->resctrl_res.ctrl_domains,
> 				resctrl_ctrl_dom.hdr.list) {
> 	}
>

Unless I've misunderstood I don't think this works because it's not what
the fs/resctrl code expects.


>> +
>> +		if (cpumask_test_cpu(cpu, &dom->ctrl_comp->affinity))
>> +			return dom;
>> +	}
>> +
>> +	return NULL;
>> +}
>> +
>> +int mpam_resctrl_online_cpu(unsigned int cpu)
>> +{
>> +	int i;
>> +	struct mpam_resctrl_dom *dom;
>> +	struct mpam_resctrl_res *res;
>> +
>> +	guard(mutex)(&domain_list_lock);
>> +	for (i = 0; i < RDT_NUM_RESOURCES; i++) {
> 
> I'd narrow the scope for dom and res to inside the loop.
> Maybe put the iterator in the for loop init (now considered
> acceptable in kernel code)
> 
> Similar applies in various other places.  No that important
> for functions that more or less just consist of a loop though.

I've done a bit of scope reducing here and in some other places.

> 
>> +		res = &mpam_resctrl_controls[i];
>> +		if (!res->class)
>> +			continue;	// dummy_resource;
>> +
>> +		dom = mpam_resctrl_get_domain_from_cpu(cpu, res);
>> +		if (!dom)
>> +			dom = mpam_resctrl_alloc_domain(cpu, res);
>> +		if (IS_ERR(dom))
>> +			return PTR_ERR(dom);
>> +	}
>> +
>> +	resctrl_online_cpu(cpu);
>> +
>> +	return 0;
>> +}
> 
>> +int mpam_resctrl_setup(void)
>> +{
>> +	int err = 0;
>> +	enum resctrl_res_level i;
>> +	struct mpam_resctrl_res *res;
>> +
>> +	cpus_read_lock();
>> +	for (i = 0; i < RDT_NUM_RESOURCES; i++) {
>> +		res = &mpam_resctrl_controls[i];
>> +		INIT_LIST_HEAD_RCU(&res->resctrl_res.ctrl_domains);
>> +		INIT_LIST_HEAD_RCU(&res->resctrl_res.mon_domains);
>> +		res->resctrl_res.rid = i;
>> +	}
>> +
>> +	/* TODO: pick MPAM classes to map to resctrl resources */
>> +
>> +	/* Initialise the resctrl structures from the classes */
>> +	for (i = 0; i < RDT_NUM_RESOURCES; i++) {
>> +		res = &mpam_resctrl_controls[i];
>> +		if (!res->class)
>> +			continue;	// dummy resource
>> +
>> +		err = mpam_resctrl_control_init(res, i);
>> +		if (err) {
>> +			pr_debug("Failed to initialise rid %u\n", i);
>> +			break;
>> +		}
>> +	}
>> +	cpus_read_unlock();
>> +
>> +	if (err || (!exposed_alloc_capable && !exposed_mon_capable)) {
>> +		if (err)
>> +			pr_debug("Internal error %d - resctrl not supported\n",
>> +				 err);
>> +		else
>> +			pr_debug("No alloc(%u) or monitor(%u) found - resctrl not supported\n",
>> +				 exposed_alloc_capable, exposed_mon_capable);
>> +		err = -EOPNOTSUPP;
> 
> return -EOPNOTSUPP; here to make the code flow simpler.
> Mind you nice to avoid eating err if it is set and the sharing here doesn't seem
> all that useful so perhaps just make this:
> 
> 	if (err) {
> 		pr_debug("Internal error %d - resctrl not supported\n", err);
> 		return err;
> 	}
> 
> 	if (!exposed_alloc_capable && !exposed_mon_capable) {
> 		pr_debug("No alloc(%u) or monitor(%u) found - resctrl not supported\n",
> 			 exposed_alloc_capable, exposed_mon_capable);
> 		return -EOPNOTSUPP;
> 	}

I've gone for the second option.

> 
> 
>> +	}
>> +
>> +	if (!err) {
>> +		if (!is_power_of_2(mpam_pmg_max + 1)) {
>> +			/*
>> +			 * If not all the partid*pmg values are valid indexes,
>> +			 * resctrl may allocate pmg that don't exist. This
>> +			 * should cause an error interrupt.
>> +			 */
>> +			pr_warn("Number of PMG is not a power of 2! resctrl may misbehave");
>> +		}
>> +
>> +		/* TODO: call resctrl_init() */
>> +	}
>> +
>> +	return err;
>> +}

Thanks,

Ben



From ben.horgan at arm.com  Fri Dec 19 04:04:10 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 12:04:10 +0000
Subject: [RFC PATCH 08/38] arm_mpam: resctrl: Pick the caches we will use
 as resctrl resources
In-Reply-To: <20251218113815.000055e7@huawei.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-9-james.morse@arm.com>
 <20251218113815.000055e7@huawei.com>
Message-ID: <931de5fc-d208-443d-a266-5cff580a66c0@arm.com>

Hi Jonathan,

On 12/18/25 11:38, Jonathan Cameron wrote:
> On Fri, 5 Dec 2025 21:58:31 +0000
> James Morse <james.morse at arm.com> wrote:
> 
>> Systems with MPAM support may have a variety of control types at any
>> point of their system layout. We can only expose certain types of
>> control, and only if they exist at particular locations.
>>
>> Start with the well-know caches. These have to be depth 2 or 3
>> and support MPAM's cache portion bitmap controls, with a number
>> of portions fewer than resctrl's limit.
> 
> Another one that is a bit random on wrap point.  Probably worth tidying
> up formatting of all the commit messages so fussy people like me stop
> moaning ;)

Will do.

> 
> Otherwise trivial stuff inline.
>>
>> Signed-off-by: James Morse <james.morse at arm.com>
>> ---
>>  drivers/resctrl/mpam_resctrl.c | 91 +++++++++++++++++++++++++++++++++-
>>  1 file changed, 89 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
>> index 320cebbd37ce..ceaf11af4fc1 100644
>> --- a/drivers/resctrl/mpam_resctrl.c
>> +++ b/drivers/resctrl/mpam_resctrl.c
>> @@ -60,10 +60,96 @@ struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l)
>>  	return &mpam_resctrl_controls[l].resctrl_res;
>>  }
>>  
>> +static bool cache_has_usable_cpor(struct mpam_class *class)
>> +{
>> +	struct mpam_props *cprops = &class->props;
>> +
>> +	if (!mpam_has_feature(mpam_feat_cpor_part, cprops))
>> +		return false;
>> +
>> +	/* resctrl uses u32 for all bitmap configurations */
>> +	return (class->props.cpbm_wd <= 32);
> 
> For me those brackets aren't adding anything. It's not like
> anyone forgets precedence wrt return vs operators.
> 
>> +}
>> +
>> +/* Test whether we can export MPAM_CLASS_CACHE:{2,3}? */
>> +static void mpam_resctrl_pick_caches(void)
>> +{
>> +	struct mpam_class *class;
>> +	struct mpam_resctrl_res *res;
>> +
>> +	lockdep_assert_cpus_held();
>> +
>> +	guard(srcu)(&mpam_srcu);
>> +	list_for_each_entry_srcu(class, &mpam_classes, classes_list,
>> +				 srcu_read_lock_held(&mpam_srcu)) {
>> +		if (class->type != MPAM_CLASS_CACHE) {
>> +			pr_debug("class %u is not a cache\n", class->level);
> 
> Lots of things aren't caches and seems unlikely that is a case that will
> make people wonder why pick caches didn't happen. So maybe this debug
> print is excessive?

Only memory or cache so far. I'll leave it here for now.

> 
>> +			continue;
>> +		}
>> +
>> +		if (class->level != 2 && class->level != 3) {
>> +			pr_debug("class %u is not L2 or L3\n", class->level);
>> +			continue;
>> +		}
>> +
>> +		if (!cache_has_usable_cpor(class)) {
>> +			pr_debug("class %u cache misses CPOR\n", class->level);
>> +			continue;
>> +		}
>> +
>> +		if (!cpumask_equal(&class->affinity, cpu_possible_mask)) {
>> +			pr_debug("class %u has missing CPUs\n", class->level);
>> +			pr_debug("class %u mask %*pb != %*pb\n", class->level,
>> +				 cpumask_pr_args(&class->affinity),
>> +				 cpumask_pr_args(cpu_possible_mask));
> 
> Unless this is getting more complex in later patches, doesn't seem like
> 			pr_debug("class %u has missing CPUs, mask %*pb != %*pb\n",
> is too much to put on one line.

Done.

> 
> 					 
>> +			continue;
>> +		}
>> +
>> +		if (class->level == 2)
>> +			res = &mpam_resctrl_controls[RDT_RESOURCE_L2];
>> +		else
>> +			res = &mpam_resctrl_controls[RDT_RESOURCE_L3];
>> +		res->class = class;
>> +		exposed_alloc_capable = true;
>> +	}
>> +}
>> +
>>  static int mpam_resctrl_control_init(struct mpam_resctrl_res *res,
>>  				     enum resctrl_res_level type)
>>  {
>> -	/* TODO: initialise the resctrl resources */
>> +	struct mpam_class *class = res->class;
>> +	struct rdt_resource *r = &res->resctrl_res;
>> +
>> +	switch (res->resctrl_res.rid) {
> 
> 	switch (r->rid) { ?
> 
>> +	case RDT_RESOURCE_L2:
>> +	case RDT_RESOURCE_L3:
>> +		r->alloc_capable = true;
>> +		r->schema_fmt = RESCTRL_SCHEMA_BITMAP;
>> +		r->cache.arch_has_sparse_bitmasks = true;
>> +
>> +		r->cache.cbm_len = class->props.cpbm_wd;
>> +		/* mpam_devices will reject empty bitmaps */
>> +		r->cache.min_cbm_bits = 1;
>> +
>> +		if (r->rid == RDT_RESOURCE_L2) {
>> +			r->name = "L2";
>> +			r->ctrl_scope = RESCTRL_L2_CACHE;
>> +		} else {
>> +			r->name = "L3";
>> +			r->ctrl_scope = RESCTRL_L3_CACHE;
>> +		}
>> +
>> +		/*
>> +		 * Which bits are shared with other ...things...
>> +		 * Unknown devices use partid-0 which uses all the bitmap
>> +		 * fields. Until we configured the SMMU and GIC not to do this
>> +		 * 'all the bits' is the correct answer here.
>> +		 */
>> +		r->cache.shareable_bits = resctrl_get_default_ctrl(r);
>> +		break;
>> +	default:
>> +		break;
>> +	}
>>  
>>  	return 0;
>>  }
>> @@ -286,7 +372,8 @@ int mpam_resctrl_setup(void)
>>  		res->resctrl_res.rid = i;
>>  	}
>>  
>> -	/* TODO: pick MPAM classes to map to resctrl resources */
>> +	/* Find some classes to use for controls */
>> +	mpam_resctrl_pick_caches();
>>  
>>  	/* Initialise the resctrl structures from the classes */
>>  	for (i = 0; i < RDT_NUM_RESOURCES; i++) {
> 

Thanks,

Ben



From ben.horgan at arm.com  Fri Dec 19 04:06:51 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 12:06:51 +0000
Subject: [RFC PATCH 18/38] arm_mpam: resctrl: Add support for csu counters
In-Reply-To: <20251218132059.00001a0d@huawei.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-19-james.morse@arm.com>
 <20251218132059.00001a0d@huawei.com>
Message-ID: <c2bee23a-517e-4d53-af26-eb0bb5795788@arm.com>

Hi Jonathan,

On 12/18/25 13:20, Jonathan Cameron wrote:
> On Fri, 5 Dec 2025 21:58:41 +0000
> James Morse <james.morse at arm.com> wrote:
> 
>> resctrl exposes a counter via a file named llc_occupancy. This isn't really
>> a counter as its value goes up and down, this is a snapshot of the cache
>> storage usage monitor.
>>
>> Add some picking code to find a cache as close as possible to the L3 that
>> supports the CSU monitor.
>>
>> If there is an L3, but it doesn't have any controls, force the L3 resource
>> to exist. The existing topology_matches_l3() and
>> mpam_resctrl_domain_hdr_init() code will ensure this looks like the L3,
>> even if the class belongs to a later cache.
>>
>> Signed-off-by: James Morse <james.morse at arm.com>
> 
> More triviality from me.  I'll take a separate look at whether this actually
> works for all the systems we care about.  It feels like maybe a top level
> MPAM to resctl mapping document might be useful as people are going to fall
> into traps around these various heuristics, particularly as more exciting
> topologies arrive in the future.

Seems sensible, this is one of the tricky things.

> 
> 
>> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
>> index fe830524639e..fc1f054f187e 100644
>> --- a/drivers/resctrl/mpam_resctrl.c
>> +++ b/drivers/resctrl/mpam_resctrl.c
> 
>>  /*
>>   * Calculate the worst-case percentage change from each implemented step
>>   * in the control.
>> @@ -499,6 +531,64 @@ static void mpam_resctrl_pick_mba(void)
>>  	}
>>  }
>>  
>> +static void counter_update_class(enum resctrl_event_id evt_id,
>> +				 struct mpam_class *class)
>> +{
>> +	struct mpam_class *existing_class = mpam_resctrl_counters[evt_id].class;
>> +
>> +	if (existing_class) {
>> +		if (class->level == 3) {
>> +			pr_debug("Existing class is L3 - L3 wins\n");
>> +			return;
> 
> As returned the else isn't adding anything much.
> 
>> +		} else if (existing_class->level < class->level) {
>> +			pr_debug("Existing class is closer to L3, %u versus %u - closer is better\n",
>> +				 existing_class->level, class->level);
>> +			return;
>> +		}
>> +	}
>> +
>> +	mpam_resctrl_counters[evt_id].class = class;
>> +	exposed_mon_capable = true;
>> +}
> 
> 

Thanks,

Ben



From krzysztof.kozlowski at oss.qualcomm.com  Fri Dec 19 04:10:01 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 13:10:01 +0100
Subject: [PATCH v2 3/3] gpio: zynq: Simplify with
 of_device_get_match_data()
In-Reply-To: <CAMRc=Md=KvKaXZvdwRd_rTp-Oq1qrAo12ENcUqTTWSYnCYSZuA@mail.gmail.com>
References: <20251219-gpio-of-match-v2-0-5c65cbb513ac@oss.qualcomm.com>
 <20251219-gpio-of-match-v2-3-5c65cbb513ac@oss.qualcomm.com>
 <CAMRc=Md=KvKaXZvdwRd_rTp-Oq1qrAo12ENcUqTTWSYnCYSZuA@mail.gmail.com>
Message-ID: <c60ec8e3-0ceb-478f-9c21-14f9faa0b7e5@oss.qualcomm.com>

On 19/12/2025 11:15, Bartosz Golaszewski wrote:
> On Fri, Dec 19, 2025 at 11:12?AM Krzysztof Kozlowski
> <krzysztof.kozlowski at oss.qualcomm.com> wrote:
>>
>> Driver's probe function matches against driver's of_device_id table,
>> where each entry has non-NULL match data, so of_match_node() can be
>> simplified with of_device_get_match_data().
>>
>> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
>> ---
> 
> I think there are some copy-paste leftovers in your commit messages.

I just did not update the commit msg.

> You're saying you're using of_ functions but you're really going for
> the device_ ones. Also update error messages. And possibly use
> dev_err_probe() too while at it?

Sure

> 
> Same elsewhere.
> 
> Bart


Best regards,
Krzysztof


From suzuki.poulose at arm.com  Fri Dec 19 04:11:32 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Fri, 19 Dec 2025 12:11:32 +0000
Subject: [PATCH v4 1/2] dt-bindings: arm: add CTCU device for monaco
In-Reply-To: <c6a75ea4-a36c-4f99-ae36-75f062937a66@oss.qualcomm.com>
References: <20251103-enable-ctcu-for-monaco-v4-0-92ff83201584@oss.qualcomm.com>
 <20251103-enable-ctcu-for-monaco-v4-1-92ff83201584@oss.qualcomm.com>
 <c6a75ea4-a36c-4f99-ae36-75f062937a66@oss.qualcomm.com>
Message-ID: <13141782-ba6e-4753-9613-2b128e008d56@arm.com>

On 19/12/2025 09:08, Jie Gan wrote:
> 
> 
> On 11/3/2025 3:06 PM, Jie Gan wrote:
>> The CTCU device for monaco shares the same configurations as SA8775p. Add
>> a fallback to enable the CTCU for monaco to utilize the compitable of the
>> SA8775p.
>>
> 
> Gentle reminder.

I was under the assumption that this was going via msm tree ? Sorry, I
misunderstood. I can pull this in for v6.20

Suzuki

> 
>> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
>> Acked-by: Suzuki K Poulose <suzuki.poulose at arm.com>
>> Reviewed-by: Bjorn Andersson <andersson at kernel.org>
>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> ---
>> ? Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml | 9 + 
>> ++++++--
>> ? 1 file changed, 7 insertions(+), 2 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight- 
>> ctcu.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight- 
>> ctcu.yaml
>> index c969c16c21ef..460f38ddbd73 100644
>> --- a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
>> +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
>> @@ -26,8 +26,13 @@ description: |
>> ? properties:
>> ??? compatible:
>> -??? enum:
>> -????? - qcom,sa8775p-ctcu
>> +??? oneOf:
>> +????? - items:
>> +????????? - enum:
>> +????????????? - qcom,qcs8300-ctcu
>> +????????? - const: qcom,sa8775p-ctcu
>> +????? - enum:
>> +????????? - qcom,sa8775p-ctcu
>> ??? reg:
>> ????? maxItems: 1
>>
> 



From krzysztof.kozlowski at oss.qualcomm.com  Fri Dec 19 04:13:11 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 13:13:11 +0100
Subject: [PATCH v3 0/3] gpio: Simplify with device_get_match_data()
Message-ID: <20251219-gpio-of-match-v3-0-6b84194a02a8@oss.qualcomm.com>

Changes in v3:
- Fix subjects and commit msg -> device_get_match_data
- Patch #3: Use dev_err_probe
- Link to v2: https://patch.msgid.link/20251219-gpio-of-match-v2-0-5c65cbb513ac at oss.qualcomm.com

Changes in v2:
- Drop applied patch
- Use device_get_match_data() as suggested by Bartosz
- Link to v1: https://patch.msgid.link/20251106-gpio-of-match-v1-0-50c7115a045e at linaro.org

Few simple cleanups, not tested on the hardware.

Care has to be taken when converting of_match_data() into
of_device_get_match_data(), because first can check arbitrary
device_node and the latter checks device's node.  Cases here should be
safe because of_match_data() uses 'pdev->dev.of_node'.

Best regards,
Krzysztof

---
Krzysztof Kozlowski (3):
      gpio: aspeed: Simplify with device_get_match_data()
      gpio: creg-snps: Simplify with device_get_match_data()
      gpio: zynq: Simplify with device_get_match_data()

 drivers/gpio/gpio-aspeed.c    |  7 ++-----
 drivers/gpio/gpio-creg-snps.c |  4 +---
 drivers/gpio/gpio-zynq.c      | 12 +++++-------
 3 files changed, 8 insertions(+), 15 deletions(-)
---
base-commit: 26ac2c4153a2c543a4ef3dee421b46bedb0f8f0f
change-id: 20251106-gpio-of-match-23b24cddf063

Best regards,
-- 
Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>



From krzysztof.kozlowski at oss.qualcomm.com  Fri Dec 19 04:13:12 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 13:13:12 +0100
Subject: [PATCH v3 1/3] gpio: aspeed: Simplify with device_get_match_data()
In-Reply-To: <20251219-gpio-of-match-v3-0-6b84194a02a8@oss.qualcomm.com>
References: <20251219-gpio-of-match-v3-0-6b84194a02a8@oss.qualcomm.com>
Message-ID: <20251219-gpio-of-match-v3-1-6b84194a02a8@oss.qualcomm.com>

Driver's probe function matches against driver's of_device_id table,
where each entry has non-NULL match data, so of_match_node() can be
simplified with device_get_match_data().

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/gpio/gpio-aspeed.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c
index cbdf781994dc..9115e56a1626 100644
--- a/drivers/gpio/gpio-aspeed.c
+++ b/drivers/gpio/gpio-aspeed.c
@@ -1302,7 +1302,6 @@ MODULE_DEVICE_TABLE(of, aspeed_gpio_of_table);
 
 static int aspeed_gpio_probe(struct platform_device *pdev)
 {
-	const struct of_device_id *gpio_id;
 	struct gpio_irq_chip *girq;
 	struct aspeed_gpio *gpio;
 	int rc, irq, i, banks, err;
@@ -1320,8 +1319,8 @@ static int aspeed_gpio_probe(struct platform_device *pdev)
 
 	raw_spin_lock_init(&gpio->lock);
 
-	gpio_id = of_match_node(aspeed_gpio_of_table, pdev->dev.of_node);
-	if (!gpio_id)
+	gpio->config = device_get_match_data(&pdev->dev);
+	if (!gpio->config)
 		return -EINVAL;
 
 	gpio->clk = devm_clk_get_enabled(&pdev->dev, NULL);
@@ -1331,8 +1330,6 @@ static int aspeed_gpio_probe(struct platform_device *pdev)
 		gpio->clk = NULL;
 	}
 
-	gpio->config = gpio_id->data;
-
 	if (!gpio->config->llops->reg_bit_set || !gpio->config->llops->reg_bit_get ||
 	    !gpio->config->llops->reg_bank_get)
 		return -EINVAL;

-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Fri Dec 19 04:13:13 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 13:13:13 +0100
Subject: [PATCH v3 2/3] gpio: creg-snps: Simplify with
 device_get_match_data()
In-Reply-To: <20251219-gpio-of-match-v3-0-6b84194a02a8@oss.qualcomm.com>
References: <20251219-gpio-of-match-v3-0-6b84194a02a8@oss.qualcomm.com>
Message-ID: <20251219-gpio-of-match-v3-2-6b84194a02a8@oss.qualcomm.com>

Driver's probe function matches against driver's of_device_id table,
where each entry has non-NULL match data, so of_match_node() can be
simplified with device_get_match_data().

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/gpio/gpio-creg-snps.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/gpio/gpio-creg-snps.c b/drivers/gpio/gpio-creg-snps.c
index f8ea961fa1de..157ab90f5ba8 100644
--- a/drivers/gpio/gpio-creg-snps.c
+++ b/drivers/gpio/gpio-creg-snps.c
@@ -134,7 +134,6 @@ static const struct of_device_id creg_gpio_ids[] = {
 
 static int creg_gpio_probe(struct platform_device *pdev)
 {
-	const struct of_device_id *match;
 	struct device *dev = &pdev->dev;
 	struct creg_gpio *hcg;
 	u32 ngpios;
@@ -148,8 +147,7 @@ static int creg_gpio_probe(struct platform_device *pdev)
 	if (IS_ERR(hcg->regs))
 		return PTR_ERR(hcg->regs);
 
-	match = of_match_node(creg_gpio_ids, pdev->dev.of_node);
-	hcg->layout = match->data;
+	hcg->layout = device_get_match_data(dev);
 	if (!hcg->layout)
 		return -EINVAL;
 

-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Fri Dec 19 04:13:14 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 13:13:14 +0100
Subject: [PATCH v3 3/3] gpio: zynq: Simplify with device_get_match_data()
In-Reply-To: <20251219-gpio-of-match-v3-0-6b84194a02a8@oss.qualcomm.com>
References: <20251219-gpio-of-match-v3-0-6b84194a02a8@oss.qualcomm.com>
Message-ID: <20251219-gpio-of-match-v3-3-6b84194a02a8@oss.qualcomm.com>

Driver's probe function matches against driver's of_device_id table,
where each entry has non-NULL match data, so of_match_node() can be
simplified with device_get_match_data().

While changing the error message, switch to dev_err_probe() so error
path is a bit simpler.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/gpio/gpio-zynq.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c
index 97780c57ab56..571e366624d2 100644
--- a/drivers/gpio/gpio-zynq.c
+++ b/drivers/gpio/gpio-zynq.c
@@ -903,18 +903,16 @@ static int zynq_gpio_probe(struct platform_device *pdev)
 	struct zynq_gpio *gpio;
 	struct gpio_chip *chip;
 	struct gpio_irq_chip *girq;
-	const struct of_device_id *match;
 
 	gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
 	if (!gpio)
 		return -ENOMEM;
 
-	match = of_match_node(zynq_gpio_of_match, pdev->dev.of_node);
-	if (!match) {
-		dev_err(&pdev->dev, "of_match_node() failed\n");
-		return -EINVAL;
-	}
-	gpio->p_data = match->data;
+	gpio->p_data = device_get_match_data(&pdev->dev);
+	if (!gpio->p_data)
+		return dev_err_probe(&pdev->dev, -EINVAL,
+				     "device_get_match_data() failed\n");
+
 	platform_set_drvdata(pdev, gpio);
 
 	gpio->base_addr = devm_platform_ioremap_resource(pdev, 0);

-- 
2.51.0



From ben.horgan at arm.com  Fri Dec 19 04:17:15 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 12:17:15 +0000
Subject: [RFC PATCH 07/38] arm_mpam: resctrl: Add boilerplate cpuhp and
 domain allocation
In-Reply-To: <20251218113014.00002691@huawei.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-8-james.morse@arm.com>
 <20251218113014.00002691@huawei.com>
Message-ID: <7100e3a7-4f08-4156-bf0b-6598570abecd@arm.com>

Hi Jonathan,

On 12/18/25 11:30, Jonathan Cameron wrote:
> On Fri, 5 Dec 2025 21:58:30 +0000
> James Morse <james.morse at arm.com> wrote:
> 
>> resctrl has its own data structures to describe its resources. We
>> can't use these directly as we play tricks with the 'MBA' resource,
>> picking the MPAM controls or monitors that best apply. We may export
>> the same component as both L3 and MBA.
>>
>> Add mpam_resctrl_exports[] as the array of class->resctrl mappings we
>> are exporting, and add the cpuhp hooks that allocated and free the
>> resctrl domain structures.
>>
>> While we're here, plumb in a few other obvious things.
>>
>> CONFIG_ARM_CPU_RESCTRL is used to allow this code to be built
>> even though it can't yet be linked against resctrl.
>>
>> Signed-off-by: James Morse <james.morse at arm.com>
> Hi,
> 
> A few code flow related comments. Fairly trivial stuff but I think
> some parts of this can be made more readable / maintainable with
> minor reorganization.
> 
> Jonathan
> 
> 
>> diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
>> index 2996ad93fc3e..efaf7633bc35 100644
>> --- a/drivers/resctrl/mpam_devices.c
>> +++ b/drivers/resctrl/mpam_devices.c
> ...
> 
>> @@ -2516,6 +2522,12 @@ static void mpam_enable_once(void)
>>  	mutex_unlock(&mpam_list_lock);
>>  	cpus_read_unlock();
>>  
>> +	if (!err) {
>> +		err = mpam_resctrl_setup();
>> +		if (err)
>> +			pr_err("Failed to initialise resctrl: %d\n", err);
>> +	}
>> +
>>  	if (err) {
>>  		mpam_disable_reason = "Failed to enable.";
>>  		schedule_work(&mpam_broken_work);
> 
> I'd be tempted to move this to an error handling block via a goto
> making this bit
> 	if (err)
> 		goto err_disable_mpam;
> 
> 	err = mpam_resctrl_setup();
> 	if (err) {
> 		pr_err();
> 		goto err_dsiable_mpam;
> 	}
> 
> Up to you though. Personally I like all my good paths as straight line
> code with the errors handled in if (err) as that consistency really helps
> readability.  
> 

I'll leave this one as is. It looks like James tried hard to avoid a goto.

Thanks,

Ben



From leo.yan at arm.com  Fri Dec 19 04:17:54 2025
From: leo.yan at arm.com (Leo Yan)
Date: Fri, 19 Dec 2025 12:17:54 +0000
Subject: [PATCH v2 RESEND] coresight: etm-perf: Fix reference count leak
 in etm_setup_aux
In-Reply-To: <5a967265-b527-4ca0-bf63-f5f7cf9013a3@arm.com>
References: <f85c7d37-4980-46f0-9136-353a35a8f0ed@oss.qualcomm.com>
 <20251219023949.12699-1-make24@iscas.ac.cn>
 <20251219094141.GA9788@e132581.arm.com>
 <d4946831-fc8c-4727-abec-3edd92e357d1@arm.com>
 <20251219113803.GC9788@e132581.arm.com>
 <5a967265-b527-4ca0-bf63-f5f7cf9013a3@arm.com>
Message-ID: <20251219121754.GD9788@e132581.arm.com>

On Fri, Dec 19, 2025 at 11:48:35AM +0000, Suzuki K Poulose wrote:

[...]

> > My understanding is we don't grab a device from
> > coresight_find_device_by_fwnode().  The callers only check whether the
> > device is present on the bus; if it isn't, the driver defers probe.
> > 
> > This is similiar to coresight_find_csdev_by_fwnode(), which calls
> > put_device(dev) to release refcnt immediately.  This is why I
> > suggested the change, so the two functions behave consistently.
> > 
> 
> I see, sorry. I saw some other uses of the device, but clearly I was wrong.
> May be we should simply re-structure the function to :

No worries and thanks for confirmation.

> bool coresight_fwnode_device_present(fwnode)
> {
> 
> 	// find and drop the ref if required.
> 	return true/false;
> }
> 
> The name "find_device_by_fwnode" and returning a freed reference doesn't
> look good to me.

Renaming is good.  Maybe use a separate patch to rename:

  coresight_find_csdev_by_fwnode() -> coresight_fwnode_csdev_present()

Thanks,
Leo


From ben.horgan at arm.com  Fri Dec 19 04:19:35 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 12:19:35 +0000
Subject: [RFC PATCH 34/38] arm_mpam: Add quirk framework
In-Reply-To: <20251218140401.000062ce@huawei.com>
References: <20251205215901.17772-1-james.morse@arm.com>
 <20251205215901.17772-35-james.morse@arm.com>
 <20251218140401.000062ce@huawei.com>
Message-ID: <36aae6f9-e819-4a12-bad3-d7f6b3c45caf@arm.com>

Hi Jonathan,

Thanks for your review. I haven't replied to every point but unless
commented I have acted on them.

On 12/18/25 14:04, Jonathan Cameron wrote:
> On Fri, 5 Dec 2025 21:58:57 +0000
> James Morse <james.morse at arm.com> wrote:
> 
>> From: Shanker Donthineni <sdonthineni at nvidia.com>
>>
>> The MPAM specification includes the MPAMF_IIDR, which serves to
>> uniquely identify the MSC implementation through a combination of
>> implementer details, product ID, variant, and revision. Certain
>> hardware issues/errata can be resolved using software workarounds.
>>
>> Introduce a quirk framework to allow workarounds to be enabled based
>> on the MPAMF_IIDR value.
>>
>> Signed-off-by: Shanker Donthineni <sdonthineni at nvidia.com>
>> [ morse: Stash the IIDR so this doesn't need an IPI, enable quirks only
>>   once, move the description to the callback so it can be pr_once()d, add
>>   an enum of workarounds for popular errata. Add macros for making lists
>>   of product/revision/vendor half readable ]
>> Signed-off-by: James Morse <james.morse at arm.com>
>> ---
>>  drivers/resctrl/mpam_devices.c  | 27 +++++++++++++++++++++++++++
>>  drivers/resctrl/mpam_internal.h | 26 ++++++++++++++++++++++++++
>>  2 files changed, 53 insertions(+)
>>
>> diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
>> index 741e14e1e6cf..f0f6f9b55ad4 100644
>> --- a/drivers/resctrl/mpam_devices.c
>> +++ b/drivers/resctrl/mpam_devices.c
>> @@ -630,6 +630,25 @@ static struct mpam_msc_ris *mpam_get_or_create_ris(struct mpam_msc *msc,
>>  	return ERR_PTR(-ENOENT);
>>  }
>>  
>> +static const struct mpam_quirk mpam_quirks[] = {
>> +	{ NULL }, /* Sentinel */
> 
> Drop the trailing , given I assume whole point is nothing after this?
> 
>> +};
>> +
>> +static void mpam_enable_quirks(struct mpam_msc *msc)
>> +{
>> +	const struct mpam_quirk *quirk;
>> +
>> +	for (quirk = &mpam_quirks[0]; quirk->iidr_mask; quirk++) {
>> +		if (quirk->iidr != (msc->iidr & quirk->iidr_mask))
>> +			continue;
>> +
>> +		if (quirk->init)
>> +			quirk->init(msc, quirk);
> 
> I'm curious why you don't return a bool from this and call
> mpam_set_quirk() if that's not indicating it should not be set.
> Seems a bit odd to push the tracking that is relevant to the generic
> framework (mpam_set_quirk) down into the particular quirk inits.

Good point. I've changed the init to return 0 or an error.

> 
>> +		else
>> +			mpam_set_quirk(quirk->workaround, msc);
>> +	}
>> +}
> 
>> diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
>> index d381906545ed..de3e5faa12b2 100644
>> --- a/drivers/resctrl/mpam_internal.h
>> +++ b/drivers/resctrl/mpam_internal.h
>> @@ -88,6 +88,8 @@ struct mpam_msc {
>>  	u8			pmg_max;
>>  	unsigned long		ris_idxs;
>>  	u32			ris_max;
>> +	u32			iidr;
>> +	u16			quirks;
>>  
>>  	/*
>>  	 * error_irq_lock is taken when registering/unregistering the error
>> @@ -215,6 +217,29 @@ struct mpam_props {
>>  #define mpam_set_feature(_feat, x)	set_bit(_feat, (x)->features)
>>  #define mpam_clear_feature(_feat, x)	clear_bit(_feat, (x)->features)
>>  
>> +/* Workaround bits for msc->quirks */
>> +enum mpam_device_quirks {
>> +	MPAM_QUIRK_LAST,
> 
> Dropping this comma should make it harder for anyone to stick an entry
> after this.

Commas removed.

Thanks,

Ben



From jie.gan at oss.qualcomm.com  Fri Dec 19 04:19:30 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Fri, 19 Dec 2025 20:19:30 +0800
Subject: [PATCH v5 1/3] coresight: tpda: add sysfs nodes for tpda
 cross-trigger configuration
In-Reply-To: <afc078d5-5855-4439-98ac-c132a2588627@arm.com>
References: <20251219-add_sysfs_nodes_to_configure_tpda-v5-0-ca93ddfe9d30@oss.qualcomm.com>
 <20251219-add_sysfs_nodes_to_configure_tpda-v5-1-ca93ddfe9d30@oss.qualcomm.com>
 <afc078d5-5855-4439-98ac-c132a2588627@arm.com>
Message-ID: <832fb36e-35e4-4c73-b32c-ee77489db951@oss.qualcomm.com>



On 12/19/2025 6:22 PM, Suzuki K Poulose wrote:
> On 19/12/2025 10:04, Jie Gan wrote:
>> From: Tao Zhang <tao.zhang at oss.qualcomm.com>
>>
>> Introduce sysfs nodes to configure cross-trigger parameters for TPDA.
>> These registers define the characteristics of cross-trigger packets,
>> including generation frequency and flag values.
>>
>> Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
>> Reviewed-by: James Clark <james.clark at linaro.org>
>> Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> ---
>> ? .../ABI/testing/sysfs-bus-coresight-devices-tpda?? |? 43 +++++++
>> ? drivers/hwtracing/coresight/coresight-tpda.c?????? | 138 +++++++++++ 
>> +++++++++-
>> ? drivers/hwtracing/coresight/coresight-tpda.h?????? |? 69 ++++++++++-
>> ? 3 files changed, 243 insertions(+), 7 deletions(-)
>>
>> diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices- 
>> tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
>> new file mode 100644
>> index 000000000000..a7855922328e
>> --- /dev/null
>> +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
>> @@ -0,0 +1,43 @@
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/global_cr/ 
>> trig_async_enable
>> +Date:??????? December 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Enable/disable cross trigger synchronization sequence 
>> interface.
>> +
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/global_cr/ 
>> trig_flag_ts_enable
>> +Date:??????? December 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Enable/disable cross trigger FLAG packet request interface.
>> +
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/global_cr/ 
>> trig_freq_enable
>> +Date:??????? December 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Enable/disable cross trigger FREQ packet request interface.
>> +
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/global_cr/ 
>> freq_ts_enable
>> +Date:??????? December 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Enable/disable the timestamp for all FREQ packets.
>> +
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/global_cr/ 
>> global_flush_req
>> +Date:??????? December 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Set global (all ports) flush request bit. The bit 
>> remains set until a
>> +??????? global flush request sequence completes.
>> +
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/global_cr/ 
>> cmbchan_mode
>> +Date:??????? December 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Configure the CMB/MCMB channel mode for all enabled ports.
>> +??????? Value 0 means raw channel mapping mode. Value 1 means channel 
>> pair marking mode.
>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/ 
>> hwtracing/coresight/coresight-tpda.c
>> index 3a3825d27f86..d25a8bcfb3d4 100644
>> --- a/drivers/hwtracing/coresight/coresight-tpda.c
>> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
>> @@ -137,12 +137,32 @@ static int tpda_get_element_size(struct 
>> tpda_drvdata *drvdata,
>> ? /* Settings pre enabling port control register */
>> ? static void tpda_enable_pre_port(struct tpda_drvdata *drvdata)
>> ? {
>> -??? u32 val;
>> +??? u32 val = 0;
>> -??? val = readl_relaxed(drvdata->base + TPDA_CR);
>> -??? val &= ~TPDA_CR_ATID;
>> ????? val |= FIELD_PREP(TPDA_CR_ATID, drvdata->atid);
>> +??? if (drvdata->trig_async)
>> +??????? val |= TPDA_CR_SRIE;
>> +
>> +??? if (drvdata->trig_flag_ts)
>> +??????? val |= TPDA_CR_FLRIE;
>> +
>> +??? if (drvdata->trig_freq)
>> +??????? val |= TPDA_CR_FRIE;
>> +
>> +??? if (drvdata->freq_ts)
>> +??????? val |= TPDA_CR_FREQTS;
>> +
>> +??? if (drvdata->cmbchan_mode)
>> +??????? val |= TPDA_CR_CMBCHANMODE;
>> +
>> ????? writel_relaxed(val, drvdata->base + TPDA_CR);
>> +
>> +??? /*
>> +???? * If FLRIE bit is set, set the master and channel
>> +???? * id as zero
>> +???? */
>> +??? if (drvdata->trig_flag_ts)
>> +??????? writel_relaxed(0x0, drvdata->base + TPDA_FPID_CR);
>> ? }
>> ? static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
>> @@ -258,6 +278,116 @@ static const struct coresight_ops tpda_cs_ops = {
>> ????? .link_ops??? = &tpda_link_ops,
>> ? };
>> +/* Read cross-trigger register member */
>> +static ssize_t tpda_trig_sysfs_show(struct device *dev,
>> +??????????????????? struct device_attribute *attr,
>> +??????????????????? char *buf)
>> +{
>> +??? struct tpda_trig_sysfs_attribute *tpda_attr =
>> +??????? container_of(attr, struct tpda_trig_sysfs_attribute, attr);
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +??? unsigned long val;
>> +
>> +??? guard(spinlock)(&drvdata->spinlock);
>> +??? switch (tpda_attr->mem) {
>> +??? case FLREQ:
>> +??????? if (!drvdata->csdev->refcnt)
>> +??????????? return -EINVAL;
>> +
>> +??????? val = readl_relaxed(drvdata->base + TPDA_CR);
>> +??????? /* read global flush request bit only */
>> +??????? val &= TPDA_CR_FLREQ;
>> +??????? return sysfs_emit(buf, "%lu\n", val);
>> +??? case FREQTS:
>> +??????? return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->freq_ts);
>> +??? case FRIE:
>> +??????? return sysfs_emit(buf, "%u\n", (unsigned int)drvdata- 
>> >trig_freq);
>> +??? case FLRIE:
>> +??????? return sysfs_emit(buf, "%u\n", (unsigned int)drvdata- 
>> >trig_flag_ts);
>> +??? case SRIE:
>> +??????? return sysfs_emit(buf, "%u\n", (unsigned int)drvdata- 
>> >trig_async);
>> +??? case CMBCHANMODE:
>> +??????? return sysfs_emit(buf, "%u\n", (unsigned int)drvdata- 
>> >cmbchan_mode);
>> +
>> +??? }
>> +??? return -EINVAL;
>> +}
>> +
>> +static ssize_t tpda_trig_sysfs_store(struct device *dev,
>> +???????????????????? struct device_attribute *attr,
>> +???????????????????? const char *buf,
>> +???????????????????? size_t size)
>> +{
>> +??? struct tpda_trig_sysfs_attribute *tpda_attr =
>> +??????? container_of(attr, struct tpda_trig_sysfs_attribute, attr);
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +??? ssize_t ret = -EINVAL;
>  ? +??? unsigned long val;
>> +
>> +??? if (kstrtoul(buf, 0, &val))
>> +??????? return ret;
> 
>  ??????? return -EINVAL;
> 
>> +
>> +??? guard(spinlock)(&drvdata->spinlock);
>> +??? switch (tpda_attr->mem) {
>> +??? case FLREQ:
>> +??????? if (!drvdata->csdev->refcnt || !val)
>> +??????????? return ret;
>  ??????????? return -EINVAL;
> 
>> +
>> +??????? val = readl_relaxed(drvdata->base + TPDA_CR);
> 
> CS_UNLOCK before readl ? I didn't mean the global_flush_req to be
> unified with the rest. Obviously it has different access semantics.

We dont need CS_UNLOCK for reading a register.

The global_flush_req is supposing access when the tpda is enabled. I 
will put it in a separate patch with detail description.

> 
> 
>> +??????? /* set global flush request bit */
>> +??????? val |= TPDA_CR_FLREQ;
>> +??????? CS_UNLOCK(drvdata->base);
>> +??????? writel_relaxed(val, drvdata->base + TPDA_CR);
>> +??????? CS_LOCK(drvdata->base);
>> +??????? ret = size;
> 
> Please remove this from all the cases and explicitly return -EINVAL in
> the error cases.

Will fix it.

> 
>> +??????? break;
>> +??? case FREQTS:
>> +??????? drvdata->freq_ts = !!val;
>> +??????? ret = size;
>> +??????? break;
>> +??? case FRIE:
>> +??????? drvdata->trig_freq = !!val;
>> +??????? ret = size;
>> +??????? break;
>> +??? case FLRIE:
>> +??????? drvdata->trig_flag_ts = !!val;
>> +??????? ret = size;
>> +??????? break;
>> +??? case SRIE:
>> +??????? drvdata->trig_async = !!val;
>> +??????? ret = size;
>> +??????? break;
>> +??? case CMBCHANMODE:
>> +??????? drvdata->cmbchan_mode = !!val;
>> +??????? ret = size;
>> +??????? break;
>> +??? default:
>  ??????? return -EINVAL;
> 
>> +??????? break;
>> +??? }
>> +
> 
> 
>> +??? return ret;
> 
>  ????return size;
> 
>> +}
>> +
>> +static struct attribute *tpda_global_cr_attrs[] = {
>> +??? tpda_trig_sysfs_rw(global_flush_req, FLREQ),
>> +??? tpda_trig_sysfs_rw(freq_ts_enable, FREQTS),
>> +??? tpda_trig_sysfs_rw(trig_freq_enable, FRIE),
>> +??? tpda_trig_sysfs_rw(trig_flag_ts_enable, FLRIE),
>> +??? tpda_trig_sysfs_rw(trig_async_enable, SRIE),
>> +??? tpda_trig_sysfs_rw(cmbchan_mode, CMBCHANMODE),
>> +??? NULL,
>> +};
>> +
>> +static struct attribute_group tpda_global_cr_attr_grp = {
>> +??? .attrs??? = tpda_global_cr_attrs,
>> +??? .name??? = "global_cr",
>> +};
>> +
>> +static const struct attribute_group *tpda_attr_grps[] = {
>> +??? &tpda_global_cr_attr_grp,
>> +??? NULL,
>> +};
>> +
>> ? static int tpda_init_default_data(struct tpda_drvdata *drvdata)
>> ? {
>> ????? int atid;
>> @@ -273,6 +403,7 @@ static int tpda_init_default_data(struct 
>> tpda_drvdata *drvdata)
>> ????????? return atid;
>> ????? drvdata->atid = atid;
>> +??? drvdata->freq_ts = true;
>> ????? return 0;
>> ? }
>> @@ -316,6 +447,7 @@ static int tpda_probe(struct amba_device *adev, 
>> const struct amba_id *id)
>> ????? desc.ops = &tpda_cs_ops;
>> ????? desc.pdata = adev->dev.platform_data;
>> ????? desc.dev = &adev->dev;
>> +??? desc.groups = tpda_attr_grps;
>> ????? desc.access = CSDEV_ACCESS_IOMEM(base);
>> ????? drvdata->csdev = coresight_register(&desc);
>> ????? if (IS_ERR(drvdata->csdev))
>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/ 
>> hwtracing/coresight/coresight-tpda.h
>> index c6af3d2da3ef..8a075cfbc3cc 100644
>> --- a/drivers/hwtracing/coresight/coresight-tpda.h
>> +++ b/drivers/hwtracing/coresight/coresight-tpda.h
>> @@ -1,6 +1,6 @@
>> ? /* SPDX-License-Identifier: GPL-2.0 */
>> ? /*
>> - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights 
>> reserved.
>> + * Copyright (c) 2023,2025 Qualcomm Innovation Center, Inc. All 
>> rights reserved.
>> ?? */
>> ? #ifndef _CORESIGHT_CORESIGHT_TPDA_H
>> @@ -8,6 +8,30 @@
>> ? #define TPDA_CR??????????? (0x000)
>> ? #define TPDA_Pn_CR(n)??????? (0x004 + (n * 4))
>> +#define TPDA_FPID_CR??????? (0x084)
>> +
>> +/* Cross trigger Global (all ports) flush request bit */
>> +#define TPDA_CR_FLREQ??????? BIT(0)
>> +/* Cross trigger FREQ packets timestamp bit */
>> +#define TPDA_CR_FREQTS??????? BIT(2)
>> +/* Cross trigger FREQ packet request bit */
>> +#define TPDA_CR_FRIE??????? BIT(3)
>> +/* Cross trigger FLAG packet request interface bit */
>> +#define TPDA_CR_FLRIE??????? BIT(4)
>> +/* Cross trigger synchronization bit */
>> +#define TPDA_CR_SRIE??????? BIT(5)
>> +/* Bits 6 ~ 12 is for atid value */
>> +#define TPDA_CR_ATID??????? GENMASK(12, 6)
>> +/* Bits 13 ~ 19 is for mid value */
>> +/* Assign a unique master ID to identify the TPDA device */
>> +#define TPDA_CR_MID??????? GENMASK(19, 13)
> 
> Where do we use this ? Does this need to be preserved ?
> Is this programmable ?
> 

We havent usage of this field. I will remove it in next version.

Thanks,
Jie

> Suzuki
> 
>> +/*
>> + * Channel mode bit of the packetization of CMB/MCB traffic
>> + * 0 - raw channel mapping mode
>> + * 1 - channel pair marking mode
>> + */
>> +#define TPDA_CR_CMBCHANMODE??? BIT(20)
>> +
>> ? /* Aggregator port enable bit */
>> ? #define TPDA_Pn_CR_ENA??????? BIT(0)
>> ? /* Aggregator port CMB data set element size bit */
>> @@ -17,9 +41,6 @@
>> ? #define TPDA_MAX_INPORTS??? 32
>> -/* Bits 6 ~ 12 is for atid value */
>> -#define TPDA_CR_ATID??????? GENMASK(12, 6)
>> -
>> ? /**
>> ?? * struct tpda_drvdata - specifics associated to an TPDA component
>> ?? * @base:?????? memory mapped base address for this component.
>> @@ -29,6 +50,11 @@
>> ?? * @enable:???? enable status of the component.
>> ?? * @dsb_esize?? Record the DSB element size.
>> ?? * @cmb_esize?? Record the CMB element size.
>> + * @trig_async:??? Enable/disable cross trigger synchronization 
>> sequence interface.
>> + * @trig_flag_ts: Enable/disable cross trigger FLAG packet request 
>> interface.
>> + * @trig_freq:??? Enable/disable cross trigger FREQ packet request 
>> interface.
>> + * @freq_ts:??? Enable/disable the timestamp for all FREQ packets.
>> + * @cmbchan_mode: Configure the CMB/MCMB channel mode.
>> ?? */
>> ? struct tpda_drvdata {
>> ????? void __iomem??????? *base;
>> @@ -38,6 +64,41 @@ struct tpda_drvdata {
>> ????? u8??????????? atid;
>> ????? u32??????????? dsb_esize;
>> ????? u32??????????? cmb_esize;
>> +??? bool??????????? trig_async;
>> +??? bool??????????? trig_flag_ts;
>> +??? bool??????????? trig_freq;
>> +??? bool??????????? freq_ts;
>> +??? bool??????????? cmbchan_mode;
>> +};
>> +
>> +/* Enumerate members of global control register(cr) */
>> +enum tpda_cr_mem {
>> +??? FLREQ,
>> +??? FREQTS,
>> +??? FRIE,
>> +??? FLRIE,
>> +??? SRIE,
>> +??? CMBCHANMODE
>> +};
>> +
>> +/**
>> + * struct tpda_trig_sysfs_attribute - Record the member variables of 
>> cross
>> + * trigger register that need to be operated by sysfs file
>> + * @attr:??? The device attribute
>> + * @mem:??? The member in the control register data structure
>> + */
>> +struct tpda_trig_sysfs_attribute {
>> +??? struct device_attribute attr;
>> +??? enum tpda_cr_mem mem;
>> ? };
>> +#define tpda_trig_sysfs_rw(name, mem)??????????????? \
>> +??? (&((struct tpda_trig_sysfs_attribute[]) {??????? \
>> +?????? {??????????????????????????? \
>> +??????? __ATTR(name, 0644, tpda_trig_sysfs_show,??? \
>> +??????? tpda_trig_sysfs_store),??????????????? \
>> +??????? mem,??????????????????????? \
>> +?????? }??????????????????????????? \
>> +?????? })[0].attr.attr)
>> +
>> ? #endif? /* _CORESIGHT_CORESIGHT_TPDA_H */
>>
> 



From robin.murphy at arm.com  Fri Dec 19 04:20:13 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Fri, 19 Dec 2025 12:20:13 +0000
Subject: [PATCH 1/6] arm64: Provide dcache_by_myline_op_nosync helper
In-Reply-To: <20251219053658.84978-2-21cnbao@gmail.com>
References: <20251219053658.84978-1-21cnbao@gmail.com>
 <20251219053658.84978-2-21cnbao@gmail.com>
Message-ID: <f43286ef-3dea-4637-a34e-b9b70d2741bf@arm.com>

On 2025-12-19 5:36 am, Barry Song wrote:
> From: Barry Song <v-songbaohua at oppo.com>
> 
> dcache_by_myline_op ensures completion of the data cache operations for a
> region, while dcache_by_myline_op_nosync only issues them without waiting.
> This enables deferred synchronization so completion for multiple regions
> can be handled together later.

This is a super-low-level internal macro with only two users... Frankly I'd
just do as below.

Thanks,
Robin.

----->8-----

diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index f0ca7196f6fa..26e983c331c5 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -367,18 +367,17 @@ alternative_endif
  	.endm
  
  /*
- * Macro to perform a data cache maintenance for the interval
- * [start, end) with dcache line size explicitly provided.
+ * Main loop for a data cache maintenance operation. Caller to provide the
+ * dcache line size and take care of relevant synchronisation afterwards.
   *
   * 	op:		operation passed to dc instruction
- * 	domain:		domain used in dsb instruction
   * 	start:          starting virtual address of the region
   * 	end:            end virtual address of the region
   *	linesz:		dcache line size
   * 	fixup:		optional label to branch to on user fault
   * 	Corrupts:       start, end, tmp
   */
-	.macro dcache_by_myline_op op, domain, start, end, linesz, tmp, fixup
+	.macro raw_dcache_by_line_op op, start, end, linesz, tmp, fixup
  	sub	\tmp, \linesz, #1
  	bic	\start, \start, \tmp
  .Ldcache_op\@:
@@ -402,7 +401,6 @@ alternative_endif
  	add	\start, \start, \linesz
  	cmp	\start, \end
  	b.lo	.Ldcache_op\@
-	dsb	\domain
  
  	_cond_uaccess_extable .Ldcache_op\@, \fixup
  	.endm
@@ -420,7 +418,8 @@ alternative_endif
   */
  	.macro dcache_by_line_op op, domain, start, end, tmp1, tmp2, fixup
  	dcache_line_size \tmp1, \tmp2
-	dcache_by_myline_op \op, \domain, \start, \end, \tmp1, \tmp2, \fixup
+	raw_dcache_by_line_op \op, \start, \end, \tmp1, \tmp2, \fixup
+	dsb \domain
  	.endm
  
  /*
diff --git a/arch/arm64/kernel/relocate_kernel.S b/arch/arm64/kernel/relocate_kernel.S
index 413f899e4ac6..efdb6884058e 100644
--- a/arch/arm64/kernel/relocate_kernel.S
+++ b/arch/arm64/kernel/relocate_kernel.S
@@ -64,7 +64,8 @@ SYM_CODE_START(arm64_relocate_new_kernel)
  	mov	x19, x13
  	copy_page x13, x12, x1, x2, x3, x4, x5, x6, x7, x8
  	add	x1, x19, #PAGE_SIZE
-	dcache_by_myline_op civac, sy, x19, x1, x15, x20
+	raw_dcache_by_line_op civac, x19, x1, x15, x20
+	dsb	sy
  	b	.Lnext
  .Ltest_indirection:
  	tbz	x16, IND_INDIRECTION_BIT, .Ltest_destination



From konrad.dybcio at oss.qualcomm.com  Fri Dec 19 04:27:02 2025
From: konrad.dybcio at oss.qualcomm.com (Konrad Dybcio)
Date: Fri, 19 Dec 2025 13:27:02 +0100
Subject: [PATCH v4 1/2] dt-bindings: arm: add CTCU device for monaco
In-Reply-To: <13141782-ba6e-4753-9613-2b128e008d56@arm.com>
References: <20251103-enable-ctcu-for-monaco-v4-0-92ff83201584@oss.qualcomm.com>
 <20251103-enable-ctcu-for-monaco-v4-1-92ff83201584@oss.qualcomm.com>
 <c6a75ea4-a36c-4f99-ae36-75f062937a66@oss.qualcomm.com>
 <13141782-ba6e-4753-9613-2b128e008d56@arm.com>
Message-ID: <21ed5d8a-803f-449f-bcd9-597d89118456@oss.qualcomm.com>

On 12/19/25 1:11 PM, Suzuki K Poulose wrote:
> On 19/12/2025 09:08, Jie Gan wrote:
>>
>>
>> On 11/3/2025 3:06 PM, Jie Gan wrote:
>>> The CTCU device for monaco shares the same configurations as SA8775p. Add
>>> a fallback to enable the CTCU for monaco to utilize the compitable of the
>>> SA8775p.
>>>
>>
>> Gentle reminder.
> 
> I was under the assumption that this was going via msm tree ? Sorry, I
> misunderstood. I can pull this in for v6.20

Please take it through your tree

Konrad


From mikko.rapeli at linaro.org  Fri Dec 19 04:30:11 2025
From: mikko.rapeli at linaro.org (Mikko Rapeli)
Date: Fri, 19 Dec 2025 14:30:11 +0200
Subject: [PATCH 0/2] drm: xlnx: zynqmp_kms: 16 bpp fixes for Xorg startup
 on AMD KV260
In-Reply-To: <533168f1-1655-4947-9032-b08463f502d7@ideasonboard.com>
References: <20251205123751.2257694-1-mikko.rapeli@linaro.org>
 <533168f1-1655-4947-9032-b08463f502d7@ideasonboard.com>
Message-ID: <aUVFUx55XTjb_2nO@nuoska>

Hi,

On Fri, Dec 19, 2025 at 01:59:14PM +0200, Tomi Valkeinen wrote:
> Hi Mikko,
> 
> On 05/12/2025 14:37, Mikko Rapeli wrote:
> > Hi,
> > 
> > Currently on default yocto images Xorg fails to start on AMD KV260
> > because 24/32 color depth gets detected but does not actually work.
> > 
> > These two patches fix the issue and now 16 bpp gets detected
> > and Xorg starts and draws on external HDMI display using
> > kernel.org based linux-yocto kernel.
> > 
> > Anatoliy Klymenko (1):
> >   drm: xlnx: zynqmp_kms: Init fbdev with 16 bit color
> > 
> > Mikko Rapeli (1):
> >   drm: xlnx: zynqmp_kms: set preferred_depth to 16 bpp
> > 
> >  drivers/gpu/drm/xlnx/zynqmp_kms.c | 3 ++-
> >  1 file changed, 2 insertions(+), 1 deletion(-)
> > 
> 
> Did you notice the few already sent serieses on the list where the topic
> has been discussed?

> [PATCH] drm: xlnx: zynqmp_dp: Support DRM_FORMAT_XRGB8888
> [PATCH 0/3] drm: zynqmp: Make the video plane primary

Oh I wasn't aware of these.

> Or is there something else on KV260 that messes up the 24 bit color?

These look very similar and likely fix the X11 startup. I will give them
a try.

Cheers,

-Mikko


From jie.gan at oss.qualcomm.com  Fri Dec 19 04:31:21 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Fri, 19 Dec 2025 20:31:21 +0800
Subject: [PATCH v5 2/3] coresight: tpda: add logic to configure TPDA_SYNCR
 register
In-Reply-To: <38dc6948-6233-4b0a-a769-538939abe345@arm.com>
References: <20251219-add_sysfs_nodes_to_configure_tpda-v5-0-ca93ddfe9d30@oss.qualcomm.com>
 <20251219-add_sysfs_nodes_to_configure_tpda-v5-2-ca93ddfe9d30@oss.qualcomm.com>
 <38dc6948-6233-4b0a-a769-538939abe345@arm.com>
Message-ID: <fb8084b1-858d-4942-9580-9a5f3016b7c0@oss.qualcomm.com>



On 12/19/2025 6:24 PM, Suzuki K Poulose wrote:
> On 19/12/2025 10:04, Jie Gan wrote:
>> From: Tao Zhang <tao.zhang at oss.qualcomm.com>
>>
>> The TPDA_SYNC counter tracks the number of bytes transferred from the
>> aggregator. When this count reaches the value programmed in the
>> TPDA_SYNCR register, an ASYNC request is triggered, allowing userspace
>> tools to accurately parse each valid packet.
>>
>> Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
>> Reviewed-by: James Clark <james.clark at linaro.org>
>> Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> ---
>> ? drivers/hwtracing/coresight/coresight-tpda.c | 7 +++++++
>> ? drivers/hwtracing/coresight/coresight-tpda.h | 5 +++++
>> ? 2 files changed, 12 insertions(+)
>>
>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/ 
>> hwtracing/coresight/coresight-tpda.c
>> index d25a8bcfb3d4..d378ff8ad77d 100644
>> --- a/drivers/hwtracing/coresight/coresight-tpda.c
>> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
>> @@ -163,6 +163,13 @@ static void tpda_enable_pre_port(struct 
>> tpda_drvdata *drvdata)
>> ?????? */
>> ????? if (drvdata->trig_flag_ts)
>> ????????? writel_relaxed(0x0, drvdata->base + TPDA_FPID_CR);
>> +
>> +??? val = readl_relaxed(drvdata->base + TPDA_SYNCR);
>> +??? /* Reset the mode ctrl */
>> +??? val &= ~TPDA_SYNCR_MODE_CTRL;
>> +??? /* Program the counter value for TPDA_SYNCR */
>> +??? val |= TPDA_SYNCR_COUNTER_MASK;
> 
> Do we plan to change this value via sysfs ? If not whats the point of
> clearing the field. Why not simply set it (as it is all 1s anyways).

We configure the value only once during enablement and do not intend to 
modify it through sysfs. The mode_ctrl is reset to reinitialize the counter.
For example, if the TPDA device has been enabled and then disabled, the 
counter may have already counted some packets. This could result in an 
async packet being triggered with an unexpected data size.

> 
>> +??? writel_relaxed(val, drvdata->base + TPDA_SYNCR);
>> ? }
>> ? static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/ 
>> hwtracing/coresight/coresight-tpda.h
>> index 8a075cfbc3cc..97e2729c15c9 100644
>> --- a/drivers/hwtracing/coresight/coresight-tpda.h
>> +++ b/drivers/hwtracing/coresight/coresight-tpda.h
>> @@ -9,6 +9,7 @@
>> ? #define TPDA_CR??????????? (0x000)
>> ? #define TPDA_Pn_CR(n)??????? (0x004 + (n * 4))
>> ? #define TPDA_FPID_CR??????? (0x084)
>> +#define TPDA_SYNCR??????? (0x08C)
>> ? /* Cross trigger Global (all ports) flush request bit */
>> ? #define TPDA_CR_FLREQ??????? BIT(0)
>> @@ -38,6 +39,10 @@
>> ? #define TPDA_Pn_CR_CMBSIZE??????? GENMASK(7, 6)
>> ? /* Aggregator port DSB data set element size bit */
>> ? #define TPDA_Pn_CR_DSBSIZE??????? BIT(8)
> 
> Newline to separate the defintions of different registers, please.

will fix it.

Thanks,
Jie

> 
>> +/* TPDA_SYNCR mode control bit */
>> +#define TPDA_SYNCR_MODE_CTRL??????? BIT(12)
>> +/* TPDA_SYNCR counter mask */
>> +#define TPDA_SYNCR_COUNTER_MASK??????? GENMASK(11, 0)
>> ? #define TPDA_MAX_INPORTS??? 32
> 
> Suzuki
> 
> 
>>
> 



From jie.gan at oss.qualcomm.com  Fri Dec 19 04:32:14 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Fri, 19 Dec 2025 20:32:14 +0800
Subject: [PATCH v5 3/3] coresight: tpda: add sysfs node to flush specific
 port
In-Reply-To: <ec3804b5-30a1-404b-ae82-0b606a8b5d6a@arm.com>
References: <20251219-add_sysfs_nodes_to_configure_tpda-v5-0-ca93ddfe9d30@oss.qualcomm.com>
 <20251219-add_sysfs_nodes_to_configure_tpda-v5-3-ca93ddfe9d30@oss.qualcomm.com>
 <ec3804b5-30a1-404b-ae82-0b606a8b5d6a@arm.com>
Message-ID: <2aa33df9-de5c-4db2-bc7e-28b15adda099@oss.qualcomm.com>



On 12/19/2025 6:33 PM, Suzuki K Poulose wrote:
> On 19/12/2025 10:04, Jie Gan wrote:
>> From: Tao Zhang <tao.zhang at oss.qualcomm.com>
>>
>> Setting bit i in the TPDA_FLUSH_CR register initiates a flush request
>> for port i, forcing the data to synchronize and be transmitted to the
>> sink device.
>>
>> Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
>> Reviewed-by: James Clark <james.clark at linaro.org>
>> Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> ---
>> ? .../ABI/testing/sysfs-bus-coresight-devices-tpda?? |? 7 ++++
>> ? drivers/hwtracing/coresight/coresight-tpda.c?????? | 49 ++++++++++++ 
>> ++++++++++
>> ? drivers/hwtracing/coresight/coresight-tpda.h?????? |? 1 +
>> ? 3 files changed, 57 insertions(+)
>>
>> diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices- 
>> tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
>> index a7855922328e..ef2804f87d1e 100644
>> --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
>> +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
>> @@ -41,3 +41,10 @@ Contact:??? Jinlong Mao 
>> <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qu
>> ? Description:
>> ????????? (RW) Configure the CMB/MCMB channel mode for all enabled ports.
>> ????????? Value 0 means raw channel mapping mode. Value 1 means 
>> channel pair marking mode.
>> +
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/port_flush_req
>> +Date:??????? December 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Configure the bit i to requests a flush operation of 
>> port i on the TPDA.
>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/ 
>> hwtracing/coresight/coresight-tpda.c
>> index d378ff8ad77d..5b4a9e41b067 100644
>> --- a/drivers/hwtracing/coresight/coresight-tpda.c
>> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
>> @@ -375,6 +375,45 @@ static ssize_t tpda_trig_sysfs_store(struct 
>> device *dev,
>> ????? return ret;
>> ? }
>> +static ssize_t port_flush_req_show(struct device *dev,
>> +?????????????????? struct device_attribute *attr,
>> +?????????????????? char *buf)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +??? unsigned long val;
>> +
>> +??? if (!drvdata->csdev->refcnt)
>> +??????? return -EINVAL;
>> +
>> +??? guard(spinlock)(&drvdata->spinlock);
>> +??? val = readl_relaxed(drvdata->base + TPDA_FLUSH_CR);
>> +
>> +??? return sysfs_emit(buf, "0x%lx\n", val);
>> +}
>> +
>> +static ssize_t port_flush_req_store(struct device *dev,
>> +??????????????????? struct device_attribute *attr,
>> +??????????????????? const char *buf,
>> +??????????????????? size_t size)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +??? u32 val;
>> +
>> +??? if (kstrtou32(buf, 0, &val))
>> +??????? return -EINVAL;
>> +
>> +??? if (!drvdata->csdev->refcnt || !val)
>> +??????? return -EINVAL;
>> +
>> +??? guard(spinlock)(&drvdata->spinlock);
>> +??? CS_UNLOCK(drvdata->base);
>> +??? writel_relaxed(val, drvdata->base + TPDA_FLUSH_CR);
>> +??? CS_LOCK(drvdata->base);
>> +
>> +??? return size;
>> +}
>> +static DEVICE_ATTR_RW(port_flush_req);
>> +
>> ? static struct attribute *tpda_global_cr_attrs[] = {
>> ????? tpda_trig_sysfs_rw(global_flush_req, FLREQ),
>> ????? tpda_trig_sysfs_rw(freq_ts_enable, FREQTS),
>> @@ -385,13 +424,23 @@ static struct attribute *tpda_global_cr_attrs[] = {
>> ????? NULL,
>> ? };
>> +static struct attribute *tpda_attrs[] = {
>> +??? &dev_attr_port_flush_req.attr,
>> +??? NULL,
>> +};
>> +
> 
> But why ? Why can't this be a part of the tpda_global_cr_attrs[] ?
> For that matter, why is tpda_global_cr_attrs named as such and why not
> tpda_attrs ?
> 

will move all attributes to tpda_attrs[].

Thanks,
Jie

> Suzuki
> 
>> ? static struct attribute_group tpda_global_cr_attr_grp = {
>> ????? .attrs??? = tpda_global_cr_attrs,
>> ????? .name??? = "global_cr",
>> ? };
>> +static struct attribute_group tpda_attr_grp = {
>> +??? .attrs??? = tpda_attrs,
>> +};
>> +
>> ? static const struct attribute_group *tpda_attr_grps[] = {
>> ????? &tpda_global_cr_attr_grp,
>> +??? &tpda_attr_grp,
>> ????? NULL,
>> ? };
>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/ 
>> hwtracing/coresight/coresight-tpda.h
>> index 97e2729c15c9..ec93f9cb9648 100644
>> --- a/drivers/hwtracing/coresight/coresight-tpda.h
>> +++ b/drivers/hwtracing/coresight/coresight-tpda.h
>> @@ -10,6 +10,7 @@
>> ? #define TPDA_Pn_CR(n)??????? (0x004 + (n * 4))
>> ? #define TPDA_FPID_CR??????? (0x084)
>> ? #define TPDA_SYNCR??????? (0x08C)
>> +#define TPDA_FLUSH_CR??????? (0x090)
>> ? /* Cross trigger Global (all ports) flush request bit */
>> ? #define TPDA_CR_FLREQ??????? BIT(0)
>>
> 



From robin.murphy at arm.com  Fri Dec 19 04:34:49 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Fri, 19 Dec 2025 12:34:49 +0000
Subject: [PATCH 3/6] arm64: Provide dcache_inval_poc_nosync helper
In-Reply-To: <20251219053658.84978-4-21cnbao@gmail.com>
References: <20251219053658.84978-1-21cnbao@gmail.com>
 <20251219053658.84978-4-21cnbao@gmail.com>
Message-ID: <99bb1797-06ba-440d-b173-db62d5f54e08@arm.com>

On 2025-12-19 5:36 am, Barry Song wrote:
> From: Barry Song <v-songbaohua at oppo.com>
> 
> dcache_inval_poc_nosync does not wait for the data cache invalidation to
> complete. Later, we defer the synchronization so we can wait for all SG
> entries together.
> 
> Cc: Catalin Marinas <catalin.marinas at arm.com>
> Cc: Will Deacon <will at kernel.org>
> Cc: Marek Szyprowski <m.szyprowski at samsung.com>
> Cc: Robin Murphy <robin.murphy at arm.com>
> Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
> Cc: Ard Biesheuvel <ardb at kernel.org>
> Cc: Marc Zyngier <maz at kernel.org>
> Cc: Anshuman Khandual <anshuman.khandual at arm.com>
> Cc: Ryan Roberts <ryan.roberts at arm.com>
> Cc: Suren Baghdasaryan <surenb at google.com>
> Cc: Tangquan Zheng <zhengtangquan at oppo.com>
> Signed-off-by: Barry Song <v-songbaohua at oppo.com>
> ---
>   arch/arm64/include/asm/cacheflush.h |  1 +
>   arch/arm64/mm/cache.S               | 43 +++++++++++++++++++++--------
>   2 files changed, 33 insertions(+), 11 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h
> index 9b6d0a62cf3d..382b4ac3734d 100644
> --- a/arch/arm64/include/asm/cacheflush.h
> +++ b/arch/arm64/include/asm/cacheflush.h
> @@ -74,6 +74,7 @@ extern void icache_inval_pou(unsigned long start, unsigned long end);
>   extern void dcache_clean_inval_poc(unsigned long start, unsigned long end);
>   extern void dcache_inval_poc(unsigned long start, unsigned long end);
>   extern void dcache_clean_poc(unsigned long start, unsigned long end);
> +extern void dcache_inval_poc_nosync(unsigned long start, unsigned long end);
>   extern void dcache_clean_poc_nosync(unsigned long start, unsigned long end);
>   extern void dcache_clean_pop(unsigned long start, unsigned long end);
>   extern void dcache_clean_pou(unsigned long start, unsigned long end);
> diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S
> index 4a7c7e03785d..8c1043c9b9e5 100644
> --- a/arch/arm64/mm/cache.S
> +++ b/arch/arm64/mm/cache.S
> @@ -132,17 +132,7 @@ alternative_else_nop_endif
>   	ret
>   SYM_FUNC_END(dcache_clean_pou)
>   
> -/*
> - *	dcache_inval_poc(start, end)
> - *
> - * 	Ensure that any D-cache lines for the interval [start, end)
> - * 	are invalidated. Any partial lines at the ends of the interval are
> - *	also cleaned to PoC to prevent data loss.
> - *
> - *	- start   - kernel start address of region
> - *	- end     - kernel end address of region
> - */
> -SYM_FUNC_START(__pi_dcache_inval_poc)
> +.macro _dcache_inval_poc_impl, do_sync
>   	dcache_line_size x2, x3
>   	sub	x3, x2, #1
>   	tst	x1, x3				// end cache line aligned?
> @@ -158,11 +148,42 @@ SYM_FUNC_START(__pi_dcache_inval_poc)
>   3:	add	x0, x0, x2
>   	cmp	x0, x1
>   	b.lo	2b
> +.if \do_sync
>   	dsb	sy
> +.endif

Similarly, don't bother with complication like this, just put the DSB in 
the one place it needs to be.

Thanks,
Robin.

>   	ret
> +.endm
> +
> +/*
> + *	dcache_inval_poc(start, end)
> + *
> + * 	Ensure that any D-cache lines for the interval [start, end)
> + * 	are invalidated. Any partial lines at the ends of the interval are
> + *	also cleaned to PoC to prevent data loss.
> + *
> + *	- start   - kernel start address of region
> + *	- end     - kernel end address of region
> + */
> +SYM_FUNC_START(__pi_dcache_inval_poc)
> +	_dcache_inval_poc_impl 1
>   SYM_FUNC_END(__pi_dcache_inval_poc)
>   SYM_FUNC_ALIAS(dcache_inval_poc, __pi_dcache_inval_poc)
>   
> +/*
> + *	dcache_inval_poc_nosync(start, end)
> + *
> + * 	Issue the instructions of D-cache lines for the interval [start, end)
> + * 	for invalidation. Not necessarily cleaned to PoC till an explicit dsb
> + *	sy later
> + *
> + *	- start   - kernel start address of region
> + *	- end     - kernel end address of region
> + */
> +SYM_FUNC_START(__pi_dcache_inval_poc_nosync)
> +	_dcache_inval_poc_impl 0
> +SYM_FUNC_END(__pi_dcache_inval_poc_nosync)
> +SYM_FUNC_ALIAS(dcache_inval_poc_nosync, __pi_dcache_inval_poc_nosync)
> +
>   /*
>    *	dcache_clean_poc(start, end)
>    *



From krzk at kernel.org  Fri Dec 19 04:56:02 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 13:56:02 +0100
Subject: [PATCH v2 07/11] dt-bindings: clock: qcom: document the Kaanapali
 GPU Clock Controller
In-Reply-To: <57ab2d5d-5aaa-4f9c-83ae-0f7ebc1e648b@oss.qualcomm.com>
References: <20251125-kaanapali-mmcc-v2-v2-0-fb44e78f300b@oss.qualcomm.com>
 <20251125-kaanapali-mmcc-v2-v2-7-fb44e78f300b@oss.qualcomm.com>
 <20251126-elated-stoic-scorpion-25b630@kuoka>
 <de44560d-4ed8-41fe-be7b-56412b933a8c@oss.qualcomm.com>
 <fbe39eac-7c92-4a08-bafb-31e5c51a0613@kernel.org>
 <503f445e-0d12-407d-bc77-f48ad335639b@oss.qualcomm.com>
 <e8bdb176-b6fb-4dd2-8b5b-9da8073fa915@kernel.org>
 <ca118faf-3451-4b83-9074-82bc5e1f731e@oss.qualcomm.com>
 <3e8128f4-3cba-4c13-a846-e5f1638a1e0f@kernel.org>
 <57ab2d5d-5aaa-4f9c-83ae-0f7ebc1e648b@oss.qualcomm.com>
Message-ID: <8b02a404-8c5a-4c0d-a80c-63fa401514b2@kernel.org>

On 19/12/2025 11:39, Taniya Das wrote:
> 
> 
> On 12/17/2025 7:24 PM, Krzysztof Kozlowski wrote:
>> On 17/12/2025 14:21, Konrad Dybcio wrote:
>>> On 12/17/25 11:09 AM, Krzysztof Kozlowski wrote:
>>>> On 17/12/2025 10:32, Taniya Das wrote:
>>>>>>>
>>>>>>> We would like to leverage the existing common clock driver(GDSC) code to
>>>>>>
>>>>>> Fix the driver code if it cannot handle other cells. Your drivers do not
>>>>>> matter for choices made in bindings.
>>>>>>
>>>>>
>>>>> As it is still a clock controller from hardware design and in SW I will
>>>>> be map the entire hardware region and this way this clock controller
>>>>> will also be aligned to the existing clock controllers and keep the
>>>>> #power-domain-cells = <1> as other CCs.
>>>>
>>>> I don't see how this resolves my comment.
>>>
>>> Spanning the entire 0x6000-long block will remove your worry about this
>>> description only being 2-register-wide
>>
>> But that was not the comment here. Taniya replied under comment about
>> cells. We are not discussing here some other things...
>>
> 
> I will review and add support for handling #power-domain-cells = <0> in
> our common code of clock & gdsc. However, the initial intent was to keep
> the GDSC phandle uniform across chipsets as this is a clock controller
> by hardware design, which is why #power-domain-cells was originally set
> to <1>.

Having cells=0 or =2 or =3 does not change "as this is a clock
controller by hardware design" at all.

I do not see any of these arguments relevant to discussion.

Best regards,
Krzysztof


From will at kernel.org  Fri Dec 19 05:00:08 2025
From: will at kernel.org (Will Deacon)
Date: Fri, 19 Dec 2025 13:00:08 +0000
Subject: [PATCH 11/12] ras: add DeviceTree estatus provider driver
In-Reply-To: <20251219090239.2692458-1-ahmed.tiba@arm.com>
References: <aUQbdZHkzumTnwVP@willie-the-truck>
 <20251219090239.2692458-1-ahmed.tiba@arm.com>
Message-ID: <aUVMWMMmiG8_I2I2@willie-the-truck>

On Fri, Dec 19, 2025 at 09:02:35AM +0000, Ahmed Tiba wrote:
> On Thu, 18 Dec 2025 03:19:17PM +0000, Will Deacon wrote:
> > On Thu, Dec 18, 2025 at 01:42:47PM +0000, Ahmed Tiba wrote:
> >> On Thu, 18 Dec 2025 12:13:25PM +0000, Will Deacon wrote:
> >> >> Introduce a platform driver that maps the CPER status block described
> >> >> in DeviceTree, feeds it into the estatus core and handles either IRQ- or
> >> >> poll-driven notifications. Arm64 gains a FIX_ESTATUS_IRQ slot so the
> >> >> driver can safely map the shared buffer while copying records.
> >> >>
> >> >> Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>
> >> >> ---
> >> >>  MAINTAINERS                     |   1 +
> >> >>  arch/arm64/include/asm/fixmap.h |   5 +
> >> >>  drivers/ras/Kconfig             |  14 ++
> >> >>  drivers/ras/Makefile            |   1 +
> >> >>  drivers/ras/estatus-dt.c        | 318 ++++++++++++++++++++++++++++++++
> >> >>  include/linux/estatus.h         |   3 +-
> >> >>  6 files changed, 341 insertions(+), 1 deletion(-)
> >> >>  create mode 100644 drivers/ras/estatus-dt.c
> >> >>
> >> >> diff --git a/MAINTAINERS b/MAINTAINERS
> >> >> index 6b2ef2ddc0c7..5567d5e82053 100644
> >> >> --- a/MAINTAINERS
> >> >> +++ b/MAINTAINERS
> >> >> @@ -21761,6 +21761,7 @@ RAS ERROR STATUS
> >> >>  M:   Ahmed Tiba <ahmed.tiba at arm.com>
> >> >>  S:   Maintained
> >> >>  F:   Documentation/devicetree/bindings/ras/arm,ras-ffh.yaml
> >> >> +F:   drivers/ras/estatus-dt.c
> >> >>  F:   drivers/firmware/efi/estatus.c
> >> >>  F:   include/linux/estatus.h
> >> >>
> >> >> diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h
> >> >> index 65555284446e..85ffba87bab9 100644
> >> >> --- a/arch/arm64/include/asm/fixmap.h
> >> >> +++ b/arch/arm64/include/asm/fixmap.h
> >> >> @@ -64,6 +64,11 @@ enum fixed_addresses {
> >> >>  #endif
> >> >>  #endif /* CONFIG_ACPI_APEI_GHES */
> >> >>
> >> >> +#ifdef CONFIG_RAS_ESTATUS_DT
> >> >> +     /* Used for ESTATUS mapping from assorted contexts */
> >> >> +     FIX_ESTATUS_IRQ,
> >> >> +#endif /* CONFIG_RAS_ESTATUS_DT */
> >> >
> >> > Why do we need this in addition to the four existing GHES slots? The DT
> >> > code doesn't use it and I was assuming that the ACPI code would continue
> >> > to use the existing irq; is that not the case?
> >>
> >>
> >> We still need a dedicated slot when only the DT provider is built.
> >> All four GHES slots are defined as part of the ACPI implementation,
> >> so they are not present in a DT-only configuration.
> >>
> >> The estatus core always requests a fixmap index from each provider
> >> before copying a CPER record. As a result, the DT driver must supply
> >> its own slot to return a valid enum value to satisfy the common code.
> >
> > Sorry, but I still don't follow this. The DT code doesn't use the fixmap,
> > does it? It looks like it maps the buffer ahead of time using
> > devm_ioremap_resource() and then the accessors don't use the fixmap
> > index at all, hence the horrible '(void)fixmap_idx;' cast which presumably
> > stops the compiler from complaining about an unused variable.
> 
> Correct. The current DT driver keeps the CPER buffer permanently mapped with
> devm_ioremap_resource() and that (void)fixmap_idx; line is just silencing
> the warning. I?ll fix that by dropping the permanent mapping and copying the
> status block via the fixmap entry, so the DT implementation mirrors GHES. That
> gets rid of the cast and makes FIX_ESTATUS_IRQ do real work.

Why can't you just drop FIX_ESTATUS_IRQ entirely? Your original
justification was:

> We still need a dedicated slot when only the DT provider is built.

but as above, the DT driver doesn't actually need it.

Will


From jie.gan at oss.qualcomm.com  Fri Dec 19 05:00:03 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Fri, 19 Dec 2025 21:00:03 +0800
Subject: [PATCH v5 2/3] coresight: tpda: add logic to configure TPDA_SYNCR
 register
In-Reply-To: <fb8084b1-858d-4942-9580-9a5f3016b7c0@oss.qualcomm.com>
References: <20251219-add_sysfs_nodes_to_configure_tpda-v5-0-ca93ddfe9d30@oss.qualcomm.com>
 <20251219-add_sysfs_nodes_to_configure_tpda-v5-2-ca93ddfe9d30@oss.qualcomm.com>
 <38dc6948-6233-4b0a-a769-538939abe345@arm.com>
 <fb8084b1-858d-4942-9580-9a5f3016b7c0@oss.qualcomm.com>
Message-ID: <9eaf823b-d18e-4067-8843-0c03530485a9@oss.qualcomm.com>



On 12/19/2025 8:31 PM, Jie Gan wrote:
> 
> 
> On 12/19/2025 6:24 PM, Suzuki K Poulose wrote:
>> On 19/12/2025 10:04, Jie Gan wrote:
>>> From: Tao Zhang <tao.zhang at oss.qualcomm.com>
>>>
>>> The TPDA_SYNC counter tracks the number of bytes transferred from the
>>> aggregator. When this count reaches the value programmed in the
>>> TPDA_SYNCR register, an ASYNC request is triggered, allowing userspace
>>> tools to accurately parse each valid packet.
>>>
>>> Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
>>> Reviewed-by: James Clark <james.clark at linaro.org>
>>> Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
>>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>>> ---
>>> ? drivers/hwtracing/coresight/coresight-tpda.c | 7 +++++++
>>> ? drivers/hwtracing/coresight/coresight-tpda.h | 5 +++++
>>> ? 2 files changed, 12 insertions(+)
>>>
>>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/ 
>>> hwtracing/coresight/coresight-tpda.c
>>> index d25a8bcfb3d4..d378ff8ad77d 100644
>>> --- a/drivers/hwtracing/coresight/coresight-tpda.c
>>> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
>>> @@ -163,6 +163,13 @@ static void tpda_enable_pre_port(struct 
>>> tpda_drvdata *drvdata)
>>> ?????? */
>>> ????? if (drvdata->trig_flag_ts)
>>> ????????? writel_relaxed(0x0, drvdata->base + TPDA_FPID_CR);
>>> +
>>> +??? val = readl_relaxed(drvdata->base + TPDA_SYNCR);
>>> +??? /* Reset the mode ctrl */
>>> +??? val &= ~TPDA_SYNCR_MODE_CTRL;
>>> +??? /* Program the counter value for TPDA_SYNCR */
>>> +??? val |= TPDA_SYNCR_COUNTER_MASK;
>>
>> Do we plan to change this value via sysfs ? If not whats the point of
>> clearing the field. Why not simply set it (as it is all 1s anyways).
> 
> We configure the value only once during enablement and do not intend to 
> modify it through sysfs. The mode_ctrl is reset to reinitialize the 
> counter.
> For example, if the TPDA device has been enabled and then disabled, the 
> counter may have already counted some packets. This could result in an 
> async packet being triggered with an unexpected data size.
> 

Missed for explaining the mode_ctrl bit. Set value 0 to the mode_ctrl 
means reset the counter and set the mode to 0.

We have two modes:

mode = 0:
COUNT[11:0] value represents the approximate number of bytes moved 
between two ASYNC packet requests

mode = 1:
the bits COUNT[11:7] are used as a power of 2. for example, we could 
insert an async packet every 8K data by writing a value 13 to the 
COUNT[11:7] field.

Thanks,
Jie

>>
>>> +??? writel_relaxed(val, drvdata->base + TPDA_SYNCR);
>>> ? }
>>> ? static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
>>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/ 
>>> hwtracing/coresight/coresight-tpda.h
>>> index 8a075cfbc3cc..97e2729c15c9 100644
>>> --- a/drivers/hwtracing/coresight/coresight-tpda.h
>>> +++ b/drivers/hwtracing/coresight/coresight-tpda.h
>>> @@ -9,6 +9,7 @@
>>> ? #define TPDA_CR??????????? (0x000)
>>> ? #define TPDA_Pn_CR(n)??????? (0x004 + (n * 4))
>>> ? #define TPDA_FPID_CR??????? (0x084)
>>> +#define TPDA_SYNCR??????? (0x08C)
>>> ? /* Cross trigger Global (all ports) flush request bit */
>>> ? #define TPDA_CR_FLREQ??????? BIT(0)
>>> @@ -38,6 +39,10 @@
>>> ? #define TPDA_Pn_CR_CMBSIZE??????? GENMASK(7, 6)
>>> ? /* Aggregator port DSB data set element size bit */
>>> ? #define TPDA_Pn_CR_DSBSIZE??????? BIT(8)
>>
>> Newline to separate the defintions of different registers, please.
> 
> will fix it.
> 
> Thanks,
> Jie
> 
>>
>>> +/* TPDA_SYNCR mode control bit */
>>> +#define TPDA_SYNCR_MODE_CTRL??????? BIT(12)
>>> +/* TPDA_SYNCR counter mask */
>>> +#define TPDA_SYNCR_COUNTER_MASK??????? GENMASK(11, 0)
>>> ? #define TPDA_MAX_INPORTS??? 32
>>
>> Suzuki
>>
>>
>>>
>>
> 



From broonie at kernel.org  Fri Dec 19 05:01:56 2025
From: broonie at kernel.org (Mark Brown)
Date: Fri, 19 Dec 2025 13:01:56 +0000
Subject: (subset) [PATCH v2 0/4] spi: stm32: stability & performance
 enhancements
In-Reply-To: <20251218-stm32-spi-enhancements-v2-0-3b69901ca9fe@foss.st.com>
References: <20251218-stm32-spi-enhancements-v2-0-3b69901ca9fe@foss.st.com>
Message-ID: <176614931636.368879.12913941748381812149.b4-ty@kernel.org>

On Thu, 18 Dec 2025 11:48:26 +0100, Alain Volmat wrote:
> The series fixes a stability issue when dealing with <8bpw
> transfers, as well as enforce an error if the DMA information
> provided within the DT are incorrect.
> 
> Performance enhancement is also provided by allowing a polling
> mode which is triggered when the transfer is so short that
> polling mode transfer would lead to faster transfer than
> if it was done in a interrupt driven manner.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next

Thanks!

[1/4] spi: stm32: properly fail on dma_request_chan error
      commit: c266d19b7d4e5ed993ed9fca25ab9d11789c41ee
[2/4] spi: stm32: fix Overrun issue at < 8bpw
      commit: 1ac3be217c01d5df55ec5052f81e4f1708f46552
[3/4] spi: stm32: perform small transfer in polling mode
      commit: b39ef93a2e5b5f4289a3486d8a94a09a1e6a4c67

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark



From konrad.dybcio at oss.qualcomm.com  Fri Dec 19 05:02:00 2025
From: konrad.dybcio at oss.qualcomm.com (Konrad Dybcio)
Date: Fri, 19 Dec 2025 14:02:00 +0100
Subject: [PATCH v2 07/11] dt-bindings: clock: qcom: document the Kaanapali
 GPU Clock Controller
In-Reply-To: <3e8128f4-3cba-4c13-a846-e5f1638a1e0f@kernel.org>
References: <20251125-kaanapali-mmcc-v2-v2-0-fb44e78f300b@oss.qualcomm.com>
 <20251125-kaanapali-mmcc-v2-v2-7-fb44e78f300b@oss.qualcomm.com>
 <20251126-elated-stoic-scorpion-25b630@kuoka>
 <de44560d-4ed8-41fe-be7b-56412b933a8c@oss.qualcomm.com>
 <fbe39eac-7c92-4a08-bafb-31e5c51a0613@kernel.org>
 <503f445e-0d12-407d-bc77-f48ad335639b@oss.qualcomm.com>
 <e8bdb176-b6fb-4dd2-8b5b-9da8073fa915@kernel.org>
 <ca118faf-3451-4b83-9074-82bc5e1f731e@oss.qualcomm.com>
 <3e8128f4-3cba-4c13-a846-e5f1638a1e0f@kernel.org>
Message-ID: <701a7b2f-848a-4cc0-8924-ec72155d93a7@oss.qualcomm.com>

On 12/17/25 2:54 PM, Krzysztof Kozlowski wrote:
> On 17/12/2025 14:21, Konrad Dybcio wrote:
>> On 12/17/25 11:09 AM, Krzysztof Kozlowski wrote:
>>> On 17/12/2025 10:32, Taniya Das wrote:
>>>>>>
>>>>>> We would like to leverage the existing common clock driver(GDSC) code to
>>>>>
>>>>> Fix the driver code if it cannot handle other cells. Your drivers do not
>>>>> matter for choices made in bindings.
>>>>>
>>>>
>>>> As it is still a clock controller from hardware design and in SW I will
>>>> be map the entire hardware region and this way this clock controller
>>>> will also be aligned to the existing clock controllers and keep the
>>>> #power-domain-cells = <1> as other CCs.
>>>
>>> I don't see how this resolves my comment.
>>
>> Spanning the entire 0x6000-long block will remove your worry about this
>> description only being 2-register-wide
> 
> But that was not the comment here. Taniya replied under comment about
> cells. We are not discussing here some other things...

Right, you omitted the part where I answered your comment from the
context, so I'll re-add it:

"""
This block provides more than one GDSC - although again, not all of them
need/should be accessed by Linux. I suppose just enumerating the "extra"
ones in bindings will be a good enough compromise?
"""

TLDR: cells=1 makes sense as per usual

Konrad


From nicolas.frattaroli at collabora.com  Fri Dec 19 05:06:12 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Fri, 19 Dec 2025 14:06:12 +0100
Subject: [PATCH v2] arm64: dts: rockchip: enable both 2.5GbE ports on Rock 5T
In-Reply-To: <034BDB37-34FB-441F-B79E-1631CA501576@probably.group>
References: <96516D1F-9787-47FE-A67E-4745D11D9207@probably.group>
 <034BDB37-34FB-441F-B79E-1631CA501576@probably.group>
Message-ID: <3903009.mvXUDI8C0e@workhorse>

On Thursday, 18 December 2025 07:27:06 Central European Standard Time Martin Holovsk? (Probably Nothing s.r.o.) wrote:
> The Radxa Rock 5T board features two RTL8125B 2.5GbE Ethernet controllers
> connected via PCIe lanes pcie2x1l0 (fe170000) and pcie2x1l2 (fe190000).
> Currently only one interface is functional because the PCIe controller
> nodes lack the necessary reset GPIO configuration.
> 
> Without the reset-gpios property, the RTL8125B PHYs remain in reset state
> and are not enumerated by the PCIe bus. This results in only one Ethernet
> interface being detected, or none at all depending on U-Boot initialization.
> 
> This patch adds the missing configuration for both PCIe controllers:
> - Enables both pcie2x1l0 and pcie2x1l2 nodes (status = "okay")
> - Configures reset GPIOs (GPIO4_PA5 and GPIO3_PB0 respectively)
> - Adds corresponding pinctrl definitions
> 
> With this change, both 2.5GbE interfaces are properly detected and
> functional on the Rock 5T.
> 
> Tested on Radxa Rock 5T v1.2 running Linux 6.12.
> 
> Signed-off-by: Martin Holovsky <mh at probably.group>
> ---
> Changes in v2:
> - Sorted pcie nodes alphanumerically
> - Sorted pinctrl nodes alphanumerically
> - Added Signed-off-by line
> 
>  .../boot/dts/rockchip/rk3588-rock-5t.dts      | 28 +++++++++++++++++++
>  1 file changed, 28 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts
> index 0dd90c744380..aeb8e0d42f09 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts
> +++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts
> @@ -68,10 +68,24 @@ &pcie2x1l1 {
>  	reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>;
>  	status = "okay";
>  };
>  
> +&pcie2x1l0 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pcie2_0_rst>;
> +	reset-gpios = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>;
> +	status = "okay";
> +};
> +
> +&pcie2x1l2 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pcie2_2_rst>;
> +	reset-gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_HIGH>;
> +	status = "okay";
> +};
> +
>  &pcie30phy {
>  	data-lanes = <1 1 2 2>;
>  };
> @@ -101,6 +115,14 @@ pcie2 {
> +		pcie2_0_rst: pcie2-0-rst {
> +			rockchip,pins = <4 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
> +		};
> +
>  		pcie2_1_rst: pcie2-1-rst {
>  			rockchip,pins = <4 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
>  		};
> +
> +		pcie2_2_rst: pcie2-2-rst {
> +			rockchip,pins = <3 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
> +		};
> +
>  		pcie2_0_vcc3v3_en: pcie2-0-vcc-en {
>  			rockchip,pins = <2 RK_PC0 RK_FUNC_GPIO &pcfg_pull_none>;
>  		};
> 

This stuff is already in rk3588-rock-5b-5bp-5t.dtsi. Ergo, this patch
does nothing at all. What are you actually trying to solve?

Heiko, please don't apply this.

Kind regards,
Nicolas Frattaroli




From naoki at radxa.com  Fri Dec 19 05:05:35 2025
From: naoki at radxa.com (FUKAUMI Naoki)
Date: Fri, 19 Dec 2025 22:05:35 +0900
Subject: [PATCH v2] arm64: dts: rockchip: enable both 2.5GbE ports on Rock
 5T
In-Reply-To: <034BDB37-34FB-441F-B79E-1631CA501576@probably.group>
References: <96516D1F-9787-47FE-A67E-4745D11D9207@probably.group>
 <034BDB37-34FB-441F-B79E-1631CA501576@probably.group>
Message-ID: <0758EFC1271A57A7+ededcd65-5064-479b-b4c0-1a2765d05a37@radxa.com>

Hi Martin,

Please check
  https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm64/boot/dts/rockchip/rk3588-rock-5b-5bp-5t.dtsi?h=v6.18#n469

Best regards,

--
FUKAUMI Naoki
Radxa Computer (Shenzhen) Co., Ltd.

On 12/18/25 15:27, "Martin Holovsk? (Probably Nothing s.r.o.)" wrote:
> The Radxa Rock 5T board features two RTL8125B 2.5GbE Ethernet controllers
> connected via PCIe lanes pcie2x1l0 (fe170000) and pcie2x1l2 (fe190000).
> Currently only one interface is functional because the PCIe controller
> nodes lack the necessary reset GPIO configuration.
> 
> Without the reset-gpios property, the RTL8125B PHYs remain in reset state
> and are not enumerated by the PCIe bus. This results in only one Ethernet
> interface being detected, or none at all depending on U-Boot initialization.
> 
> This patch adds the missing configuration for both PCIe controllers:
> - Enables both pcie2x1l0 and pcie2x1l2 nodes (status = "okay")
> - Configures reset GPIOs (GPIO4_PA5 and GPIO3_PB0 respectively)
> - Adds corresponding pinctrl definitions
> 
> With this change, both 2.5GbE interfaces are properly detected and
> functional on the Rock 5T.
> 
> Tested on Radxa Rock 5T v1.2 running Linux 6.12.
> 
> Signed-off-by: Martin Holovsky <mh at probably.group>
> ---
> Changes in v2:
> - Sorted pcie nodes alphanumerically
> - Sorted pinctrl nodes alphanumerically
> - Added Signed-off-by line
> 
>   .../boot/dts/rockchip/rk3588-rock-5t.dts      | 28 +++++++++++++++++++
>   1 file changed, 28 insertions(+)
> 
>   		};
> +
> +		pcie2_2_rst: pcie2-2-rst {
> +			rockchip,pins = <3 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
> +		};
> +
>   		pcie2_0_vcc3v3_en: pcie2-0-vcc-en {
>   			rockchip,pins = <2 RK_PC0 RK_FUNC_GPIO &pcfg_pull_none>;
>   		};
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts
> index 0dd90c744380..aeb8e0d42f09 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts
> +++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts
> @@ -68,10 +68,24 @@ &pcie2x1l1 {
>   	reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>;
>   	status = "okay";
>   };
>   
> +&pcie2x1l0 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pcie2_0_rst>;
> +	reset-gpios = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>;
> +	status = "okay";
> +};
> +
> +&pcie2x1l2 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pcie2_2_rst>;
> +	reset-gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_HIGH>;
> +	status = "okay";
> +};
> +
>   &pcie30phy {
>   	data-lanes = <1 1 2 2>;
>   };
> @@ -101,6 +115,14 @@ pcie2 {
> +		pcie2_0_rst: pcie2-0-rst {
> +			rockchip,pins = <4 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
> +		};
> +
>   		pcie2_1_rst: pcie2-1-rst {
>   			rockchip,pins = <4 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;




From konrad.dybcio at oss.qualcomm.com  Fri Dec 19 05:24:14 2025
From: konrad.dybcio at oss.qualcomm.com (Konrad Dybcio)
Date: Fri, 19 Dec 2025 14:24:14 +0100
Subject: [PATCH v2 08/11] clk: qcom: dispcc: Add support for display clock
 controller Kaanapali
In-Reply-To: <20251125-kaanapali-mmcc-v2-v2-8-fb44e78f300b@oss.qualcomm.com>
References: <20251125-kaanapali-mmcc-v2-v2-0-fb44e78f300b@oss.qualcomm.com>
 <20251125-kaanapali-mmcc-v2-v2-8-fb44e78f300b@oss.qualcomm.com>
Message-ID: <7038f5f7-e5c2-43c3-864c-e7ddd2e8c374@oss.qualcomm.com>

On 11/25/25 6:45 PM, Taniya Das wrote:
> Support the clock controller driver for Kaanapali to enable display SW to
> be able to control the clocks.
> 
> Signed-off-by: Taniya Das <taniya.das at oss.qualcomm.com>
> ---

Reviewed-by: Konrad Dybcio <konrad.dybcio at oss.qualcomm.com>

Konrad


From gary.yang at cixtech.com  Fri Dec 19 05:35:51 2025
From: gary.yang at cixtech.com (Gary Yang)
Date: Fri, 19 Dec 2025 21:35:51 +0800
Subject: [PATCH v2 0/2] Add OrangePi 6 Plus board
Message-ID: <20251219133553.1440970-1-gary.yang@cixtech.com>

Patch 1: add compatible strings for OrangePi 6 Plus board
Patch 2: add dts file for OrangePi 6 Plus board

OrangePi 6 Plus board is powered by Cix Sky1. You could find brief
introduction for SoC and related boards at:
http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/details/Orange-Pi-6-Plus.html

Currently, to run upstream kernel at OrangePi 6 Plus board, you need to
use BIOS released by OrangePi, and add "clk_ignore_unused=1" at bootargs.
http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/service-and-support/Orange-Pi-6-Plus.html

Gary Yang (2):
  dt-bindings: arm: cix: add OrangePi 6 Plus board
  arm64: dts: cix: Add OrangePi 6 Plus board support

 .../devicetree/bindings/arm/cix.yaml          |  4 +-
 arch/arm64/boot/dts/cix/Makefile              |  1 +
 arch/arm64/boot/dts/cix/sky1-xcp.dts          | 83 +++++++++++++++++++
 3 files changed, 87 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm64/boot/dts/cix/sky1-xcp.dts

-- 
2.49.0



From gary.yang at cixtech.com  Fri Dec 19 05:35:52 2025
From: gary.yang at cixtech.com (Gary Yang)
Date: Fri, 19 Dec 2025 21:35:52 +0800
Subject: [PATCH v2 1/2] dt-bindings: arm: cix: add OrangePi 6 Plus board
In-Reply-To: <20251219133553.1440970-1-gary.yang@cixtech.com>
References: <20251219133553.1440970-1-gary.yang@cixtech.com>
Message-ID: <20251219133553.1440970-2-gary.yang@cixtech.com>

OrangePi 6 Plus adopts CIX CD8180/CD8160 SoC,
built-in 12-core 64-bit processor + NPU processor,
integrated graphics processor, equipped with 16GB/32GB/64GB
LPDDR5, and provides two M.2 KEY-M interfaces 2280 for NVMe SSD,
as well as SPI FLASH and TF slots to meet the needs of fast
read/write and high-capacity storage;

Signed-off-by: Gary Yang <gary.yang at cixtech.com>
---
 Documentation/devicetree/bindings/arm/cix.yaml | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/arm/cix.yaml b/Documentation/devicetree/bindings/arm/cix.yaml
index 114dab4bc4d2..e2cc0bb8b908 100644
--- a/Documentation/devicetree/bindings/arm/cix.yaml
+++ b/Documentation/devicetree/bindings/arm/cix.yaml
@@ -18,7 +18,9 @@ properties:
 
       - description: Radxa Orion O6
         items:
-          - const: radxa,orion-o6
+          - enum:
+              - radxa,orion-o6
+              - xunlong,orangepi-6-plus
           - const: cix,sky1
 
 additionalProperties: true
-- 
2.49.0



From gary.yang at cixtech.com  Fri Dec 19 05:35:53 2025
From: gary.yang at cixtech.com (Gary Yang)
Date: Fri, 19 Dec 2025 21:35:53 +0800
Subject: [PATCH v2 2/2] arm64: dts: cix: Add OrangePi 6 Plus board support
In-Reply-To: <20251219133553.1440970-1-gary.yang@cixtech.com>
References: <20251219133553.1440970-1-gary.yang@cixtech.com>
Message-ID: <20251219133553.1440970-3-gary.yang@cixtech.com>

OrangePi 6 Plus adopts CIX CD8180/CD8160 SoC,
built-in 12-core 64-bit processor + NPU processor,
integrated graphics processor, equipped with 16GB/32GB/64GB
LPDDR5, and provides two M.2 KEY-M interfaces 2280 for NVMe SSD,
as well as SPI FLASH and TF slots to meet the needs of fast
read/write and high-capacity storage;

Signed-off-by: Gary Yang <gary.yang at cixtech.com>
---
 arch/arm64/boot/dts/cix/Makefile     |  1 +
 arch/arm64/boot/dts/cix/sky1-xcp.dts | 83 ++++++++++++++++++++++++++++
 2 files changed, 84 insertions(+)
 create mode 100644 arch/arm64/boot/dts/cix/sky1-xcp.dts

diff --git a/arch/arm64/boot/dts/cix/Makefile b/arch/arm64/boot/dts/cix/Makefile
index ed3713982012..8a6c6fdc4ec0 100644
--- a/arch/arm64/boot/dts/cix/Makefile
+++ b/arch/arm64/boot/dts/cix/Makefile
@@ -1,2 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0
 dtb-$(CONFIG_ARCH_CIX) += sky1-orion-o6.dtb
+dtb-$(CONFIG_ARCH_CIX) += sky1-xcp.dtb
diff --git a/arch/arm64/boot/dts/cix/sky1-xcp.dts b/arch/arm64/boot/dts/cix/sky1-xcp.dts
new file mode 100644
index 000000000000..1fae52dc9bb0
--- /dev/null
+++ b/arch/arm64/boot/dts/cix/sky1-xcp.dts
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright 2025 Cix Technology Group Co., Ltd.
+ *
+ */
+
+/dts-v1/;
+
+#include "sky1.dtsi"
+#include "sky1-pinfunc.h"
+
+/ {
+	model = "Xunlong,OrangePi 6 Plus";
+	compatible = "xunlong,orangepi-6-plus", "cix,sky1";
+
+	aliases {
+		serial2 = &uart2;
+	};
+
+	chosen {
+		stdout-path = &uart2;
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		linux,cma {
+			compatible = "shared-dma-pool";
+			reusable;
+			size = <0x0 0x28000000>;
+			linux,cma-default;
+		};
+	};
+
+};
+
+&iomuxc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_hog>;
+
+	pinctrl_hog: hog-cfg {
+		pins {
+			pinmux = <CIX_PAD_GPIO144_FUNC_GPIO144>,
+				<CIX_PAD_GPIO145_FUNC_GPIO145>,
+				<CIX_PAD_GPIO146_FUNC_GPIO146>,
+				<CIX_PAD_GPIO147_FUNC_GPIO147>;
+			bias-pull-down;
+			drive-strength = <8>;
+		};
+	};
+};
+
+&iomuxc_s5 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_hog_s5>;
+
+	pinctrl_hog_s5: hog-s5-cfg {
+		pins {
+			pinmux = <CIX_PAD_GPIO014_FUNC_GPIO014>;
+			bias-pull-up;
+			drive-strength = <8>;
+
+		};
+	};
+};
+
+&pcie_x8_rc {
+	status = "okay";
+};
+
+&pcie_x2_rc {
+	status = "okay";
+};
+
+&pcie_x1_1_rc {
+	status = "okay";
+};
+
+&uart2 {
+	status = "okay";
+};
-- 
2.49.0



From leo.bras at arm.com  Fri Dec 19 05:38:50 2025
From: leo.bras at arm.com (Leonardo Bras)
Date: Fri, 19 Dec 2025 13:38:50 +0000
Subject: [PATCH v2 1/6] KVM: arm64: Fix EL2 S1 XN handling for hVHE setups
In-Reply-To: <20251210173024.561160-2-maz@kernel.org>
References: <20251210173024.561160-1-maz@kernel.org> <20251210173024.561160-2-maz@kernel.org>
Message-ID: <aURFlcm6szeSfLmH@devkitleo>

On Wed, Dec 10, 2025 at 05:30:19PM +0000, Marc Zyngier wrote:
> The current XN implementation is tied to the EL2 translation regime,
> and fall flat on its face with the EL2&0 one that is used for hVHE,
> as the permission bit for privileged execution is a different one.
> 
> Fixes: 6537565fd9b7f ("KVM: arm64: Adjust EL2 stage-1 leaf AP bits when ARM64_KVM_HVHE is set")
> Signed-off-by: Marc Zyngier <maz at kernel.org>
> ---
>  arch/arm64/include/asm/kvm_pgtable.h | 10 +++++++++-
>  1 file changed, 9 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h
> index fc02de43c68dd..be68b89692065 100644
> --- a/arch/arm64/include/asm/kvm_pgtable.h
> +++ b/arch/arm64/include/asm/kvm_pgtable.h
> @@ -87,7 +87,15 @@ typedef u64 kvm_pte_t;
>  
>  #define KVM_PTE_LEAF_ATTR_HI_SW		GENMASK(58, 55)
>  
> -#define KVM_PTE_LEAF_ATTR_HI_S1_XN	BIT(54)
> +#define __KVM_PTE_LEAF_ATTR_HI_S1_XN	BIT(54)
> +#define __KVM_PTE_LEAF_ATTR_HI_S1_UXN	BIT(54)
> +#define __KVM_PTE_LEAF_ATTR_HI_S1_PXN	BIT(53)
> +
> +#define KVM_PTE_LEAF_ATTR_HI_S1_XN					\
> +	({ cpus_have_final_cap(ARM64_KVM_HVHE) ?			\
> +			(__KVM_PTE_LEAF_ATTR_HI_S1_UXN |		\
> +			 __KVM_PTE_LEAF_ATTR_HI_S1_PXN) :		\
> +			__KVM_PTE_LEAF_ATTR_HI_S1_XN; })
>  
>  #define KVM_PTE_LEAF_ATTR_HI_S2_XN	GENMASK(54, 53)
>  
> -- 
> 2.47.3
> 

Cool,
Is this according to the following in Arm ARM?

Figure D8-16
Stage 1 attribute fields in VMSAv8-64 Block and Page descriptors

Thanks!
Leo


From piotr.oniszczuk at gmail.com  Fri Dec 19 05:50:51 2025
From: piotr.oniszczuk at gmail.com (Piotr Oniszczuk)
Date: Fri, 19 Dec 2025 14:50:51 +0100
Subject: [PATCH v7 00/17] media: rkvdec: Add support for VDPU381 and
 VDPU383
In-Reply-To: <20251218232829.337811-1-detlev.casanova@collabora.com>
References: <20251218232829.337811-1-detlev.casanova@collabora.com>
Message-ID: <219DE002-BE77-4D28-9BC6-9124F099F211@gmail.com>



> Wiadomo?? napisana przez Detlev Casanova <detlev.casanova at collabora.com> w dniu 19 gru 2025, o godz. 00:28:
> 
> These variants are found respectively in the RK3588 and RK3576 SoCs.
> This patch only adds support for H264 and H265 in both variants.
> 
> As there is a considerable part of the code that can be shared with the
> already supported rkvdec decoder driver, the support for these variants
> is added here rather than writing a new driver.
> 
> This patch set uses the newly introduced hevc_ext_sps_[ls]t_rps v4l2
> controls for HEVC.
> Therefore, a patched version of userpace tools is needed for HEVC
> support (added for GStreamer[1] and in an early stage for FFmpeg[2]).
> 
> The DTS changes can be found in another patch set: [3]
> 
> [1]: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/9355
> [2]: https://gitlab.collabora.com/detlev/ffmpeg
> [3]: https://lore.kernel.org/all/20251020212009.8852-1-detlev.casanova at collabora.com/
> 

Detlev,

FYI:

In my testbed with 

i. v7 of [1] on mainline 6.18.2
ii ffmpeg8 v4l2_request [2]
iii. mythv as player [3]
iv. minimyth2 as distro [4]
v. NO applied yours ffmpeg sps/rps hinting [5] (as i'm on ffmpeg8)

I run set of my mpeg2/h264/hevc/vp8/vp9 samples on: rk3328. rk3399, rk3566, rk3576, rk3588 and h616 (just for brief test for potential cross-regressions)

Results:

a. rk3328: no any regressions; all samples are decoded ok

b. rk3399: no any regressions; all samples are decoded ok

c. rk3566: no any regressions (e.g. in vp9. v6 and older were regressing; v7 is ok)  
c.1 h264: all ok
c.2 hevc: samples without long-term sps/rps: all ok.
c.3 hevc: samples with long-tern sps/rps: v7 is a bit regressing here: it gives me sometimes kernel oops requiring hw. reset to bring decoder back to live. 
Exemplary oops: https://termbin.com/upju
Older vers of your code were handling such cases without needs of hw. reset

d. rk3576:
d.1: h264: works ok - but randomly i'm getting playback with distortions like this: https://postimg.cc/Yh8Djc3L. it is avd. 1 per few playbacks.
d.2: hevc: the same like c.1 and c.2

e. rk3588
e.1: h264: all ok
e.2: hevc: the same like c.1 and c.2
   
g. h616 with cedrus: all ok.

btw: 
Adding to [1] vp9 android code [6] offers me nice working vp9 hwdec accell on rk3566/3588.  

Great work!

[1] https://gitlab.collabora.com/detlev/linux/-/commits/add-vdpu381-and-383-to-rkvdec-v7
[2] https://code.ffmpeg.org/Kwiboo/FFmpeg/src/branch/v4l2-request-n8.0.1
[3] https://github.com/MythTV/mythtv
[4] https://github.com/warpme/minimyth2
[5] https://gitlab.collabora.com/detlev/ffmpeg
[6] https://github.com/dvab-sarma/android_kernel_rk_opi/commit/fd0b1b17cbdfcf0c15bc9f411cc7127105157e57
   
 



From piotr.oniszczuk at gmail.com  Fri Dec 19 05:50:51 2025
From: piotr.oniszczuk at gmail.com (Piotr Oniszczuk)
Date: Fri, 19 Dec 2025 14:50:51 +0100
Subject: [PATCH v7 00/17] media: rkvdec: Add support for VDPU381 and
 VDPU383
In-Reply-To: <20251218232829.337811-1-detlev.casanova@collabora.com>
References: <20251218232829.337811-1-detlev.casanova@collabora.com>
Message-ID: <219DE002-BE77-4D28-9BC6-9124F099F211@gmail.com>



> Wiadomo?? napisana przez Detlev Casanova <detlev.casanova at collabora.com> w dniu 19 gru 2025, o godz. 00:28:
> 
> These variants are found respectively in the RK3588 and RK3576 SoCs.
> This patch only adds support for H264 and H265 in both variants.
> 
> As there is a considerable part of the code that can be shared with the
> already supported rkvdec decoder driver, the support for these variants
> is added here rather than writing a new driver.
> 
> This patch set uses the newly introduced hevc_ext_sps_[ls]t_rps v4l2
> controls for HEVC.
> Therefore, a patched version of userpace tools is needed for HEVC
> support (added for GStreamer[1] and in an early stage for FFmpeg[2]).
> 
> The DTS changes can be found in another patch set: [3]
> 
> [1]: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/9355
> [2]: https://gitlab.collabora.com/detlev/ffmpeg
> [3]: https://lore.kernel.org/all/20251020212009.8852-1-detlev.casanova at collabora.com/
> 

Detlev,

FYI:

In my testbed with 

i. v7 of [1] on mainline 6.18.2
ii ffmpeg8 v4l2_request [2]
iii. mythv as player [3]
iv. minimyth2 as distro [4]
v. NO applied yours ffmpeg sps/rps hinting [5] (as i'm on ffmpeg8)

I run set of my mpeg2/h264/hevc/vp8/vp9 samples on: rk3328. rk3399, rk3566, rk3576, rk3588 and h616 (just for brief test for potential cross-regressions)

Results:

a. rk3328: no any regressions; all samples are decoded ok

b. rk3399: no any regressions; all samples are decoded ok

c. rk3566: no any regressions (e.g. in vp9. v6 and older were regressing; v7 is ok)  
c.1 h264: all ok
c.2 hevc: samples without long-term sps/rps: all ok.
c.3 hevc: samples with long-tern sps/rps: v7 is a bit regressing here: it gives me sometimes kernel oops requiring hw. reset to bring decoder back to live. 
Exemplary oops: https://termbin.com/upju
Older vers of your code were handling such cases without needs of hw. reset

d. rk3576:
d.1: h264: works ok - but randomly i'm getting playback with distortions like this: https://postimg.cc/Yh8Djc3L. it is avd. 1 per few playbacks.
d.2: hevc: the same like c.1 and c.2

e. rk3588
e.1: h264: all ok
e.2: hevc: the same like c.1 and c.2
   
g. h616 with cedrus: all ok.

btw: 
Adding to [1] vp9 android code [6] offers me nice working vp9 hwdec accell on rk3566/3588.  

Great work!

[1] https://gitlab.collabora.com/detlev/linux/-/commits/add-vdpu381-and-383-to-rkvdec-v7
[2] https://code.ffmpeg.org/Kwiboo/FFmpeg/src/branch/v4l2-request-n8.0.1
[3] https://github.com/MythTV/mythtv
[4] https://github.com/warpme/minimyth2
[5] https://gitlab.collabora.com/detlev/ffmpeg
[6] https://github.com/dvab-sarma/android_kernel_rk_opi/commit/fd0b1b17cbdfcf0c15bc9f411cc7127105157e57
   
 



From suzuki.poulose at arm.com  Fri Dec 19 06:01:53 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Fri, 19 Dec 2025 14:01:53 +0000
Subject: (subset) [PATCH v4 0/2] Enable CTCU device for QCS8300
In-Reply-To: <20251103-enable-ctcu-for-monaco-v4-0-92ff83201584@oss.qualcomm.com>
References: <20251103-enable-ctcu-for-monaco-v4-0-92ff83201584@oss.qualcomm.com>
Message-ID: <176615287813.688536.723538049922655005.b4-ty@arm.com>


On Mon, 03 Nov 2025 15:06:20 +0800, Jie Gan wrote:
> Enable CTCU device for QCS8300 platform. Add a fallback mechnasim in binding to utilize
> the compitable of the SA8775p platform becuase the CTCU for QCS8300 shares same
> configurations as SA8775p platform.
> 
> Changes in V4:
> 1. dtsi file has been renamed from qcs8300.dtsi -> monaco.dtsi
> Link to V3 - https://lore.kernel.org/all/20251013-enable-ctcu-for-qcs8300-v3-0-611e6e0d3085 at oss.qualcomm.com/
> 
> [...]

Applied, thanks!

[1/2] dt-bindings: arm: add CTCU device for monaco
      https://git.kernel.org/coresight/c/51cd1fb70e08

Best regards,
-- 
Suzuki K Poulose <suzuki.poulose at arm.com>


From maz at kernel.org  Fri Dec 19 06:13:39 2025
From: maz at kernel.org (Marc Zyngier)
Date: Fri, 19 Dec 2025 14:13:39 +0000
Subject: [PATCH v2 1/6] KVM: arm64: Fix EL2 S1 XN handling for hVHE setups
In-Reply-To: <aURFlcm6szeSfLmH@devkitleo>
References: <20251210173024.561160-1-maz@kernel.org>
	<20251210173024.561160-2-maz@kernel.org>
	<aURFlcm6szeSfLmH@devkitleo>
Message-ID: <86qzsqmuek.wl-maz@kernel.org>

On Fri, 19 Dec 2025 13:38:50 +0000,
Leonardo Bras <leo.bras at arm.com> wrote:
> 
> On Wed, Dec 10, 2025 at 05:30:19PM +0000, Marc Zyngier wrote:
> > The current XN implementation is tied to the EL2 translation regime,
> > and fall flat on its face with the EL2&0 one that is used for hVHE,
> > as the permission bit for privileged execution is a different one.
> > 
> > Fixes: 6537565fd9b7f ("KVM: arm64: Adjust EL2 stage-1 leaf AP bits when ARM64_KVM_HVHE is set")
> > Signed-off-by: Marc Zyngier <maz at kernel.org>
> > ---
> >  arch/arm64/include/asm/kvm_pgtable.h | 10 +++++++++-
> >  1 file changed, 9 insertions(+), 1 deletion(-)
> > 
> > diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h
> > index fc02de43c68dd..be68b89692065 100644
> > --- a/arch/arm64/include/asm/kvm_pgtable.h
> > +++ b/arch/arm64/include/asm/kvm_pgtable.h
> > @@ -87,7 +87,15 @@ typedef u64 kvm_pte_t;
> >  
> >  #define KVM_PTE_LEAF_ATTR_HI_SW		GENMASK(58, 55)
> >  
> > -#define KVM_PTE_LEAF_ATTR_HI_S1_XN	BIT(54)
> > +#define __KVM_PTE_LEAF_ATTR_HI_S1_XN	BIT(54)
> > +#define __KVM_PTE_LEAF_ATTR_HI_S1_UXN	BIT(54)
> > +#define __KVM_PTE_LEAF_ATTR_HI_S1_PXN	BIT(53)
> > +
> > +#define KVM_PTE_LEAF_ATTR_HI_S1_XN					\
> > +	({ cpus_have_final_cap(ARM64_KVM_HVHE) ?			\
> > +			(__KVM_PTE_LEAF_ATTR_HI_S1_UXN |		\
> > +			 __KVM_PTE_LEAF_ATTR_HI_S1_PXN) :		\
> > +			__KVM_PTE_LEAF_ATTR_HI_S1_XN; })
> >  
> >  #define KVM_PTE_LEAF_ATTR_HI_S2_XN	GENMASK(54, 53)
> >  
> > -- 
> > 2.47.3
> > 
> 
> Cool,
> Is this according to the following in Arm ARM?
> 
> Figure D8-16
> Stage 1 attribute fields in VMSAv8-64 Block and Page descriptors

In M.a (or M.a.a, as it is now called), this is all part of
I_GLMLD. But R_JJNHR is a much more interesting source of information,
as it clearly outlines in which conditions XN, UXN and PXN are all
sharing the same two bits in funky ways...

Thanks,

	M.

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


From alain.volmat at foss.st.com  Fri Dec 19 06:30:39 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Fri, 19 Dec 2025 15:30:39 +0100
Subject: [PATCH 5/6] media: stm32: dcmipp: byteproc: only allow compose
 with 8/16bit fmts
In-Reply-To: <20251219-stm32-dcmipp-enhancements-v1-0-e2f8d46f022c@foss.st.com>
References: <20251219-stm32-dcmipp-enhancements-v1-0-e2f8d46f022c@foss.st.com>
Message-ID: <20251219-stm32-dcmipp-enhancements-v1-5-e2f8d46f022c@foss.st.com>

Since the byteproc is working at byte level, it is not possible to
perform decimation with formats other than 8 or 16 bit per pixel.
Ensure any other format won't be able to set a compose.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 .../media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c   | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c
index f45a3027f8f3..f9e4a3a9ef3f 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c
@@ -131,6 +131,8 @@ static void dcmipp_byteproc_adjust_crop(struct v4l2_rect *r,
 static void dcmipp_byteproc_adjust_compose(struct v4l2_rect *r,
 					   const struct v4l2_mbus_framefmt *fmt)
 {
+	const struct dcmipp_byteproc_pix_map *vpix;
+
 	r->top = 0;
 	r->left = 0;
 
@@ -142,6 +144,14 @@ static void dcmipp_byteproc_adjust_compose(struct v4l2_rect *r,
 		return;
 	}
 
+	/* Prevent compose on formats which are not 1 or 2 bytes per pixel */
+	vpix = dcmipp_byteproc_pix_map_by_code(fmt->code);
+	if (vpix->bpp != 1 && vpix->bpp != 2) {
+		r->width = fmt->width;
+		r->height = fmt->height;
+		return;
+	}
+
 	/* Adjust height - we can only perform 1/2 decimation */
 	if (r->height <= (fmt->height / 2))
 		r->height = fmt->height / 2;
@@ -149,7 +159,7 @@ static void dcmipp_byteproc_adjust_compose(struct v4l2_rect *r,
 		r->height = fmt->height;
 
 	/* Adjust width /2 or /4 for 8bits formats and /2 for 16bits formats */
-	if (fmt->code == MEDIA_BUS_FMT_Y8_1X8 && r->width <= (fmt->width / 4))
+	if (vpix->bpp == 1 && r->width <= (fmt->width / 4))
 		r->width = fmt->width / 4;
 	else if (r->width <= (fmt->width / 2))
 		r->width = fmt->width / 2;

-- 
2.34.1



From alain.volmat at foss.st.com  Fri Dec 19 06:30:36 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Fri, 19 Dec 2025 15:30:36 +0100
Subject: [PATCH 2/6] media: stm32: dcmipp: byteproc: disable compose for
 all bayers
In-Reply-To: <20251219-stm32-dcmipp-enhancements-v1-0-e2f8d46f022c@foss.st.com>
References: <20251219-stm32-dcmipp-enhancements-v1-0-e2f8d46f022c@foss.st.com>
Message-ID: <20251219-stm32-dcmipp-enhancements-v1-2-e2f8d46f022c@foss.st.com>

Avoid possibility to perform compose on all frames which mbus code is
within the bayer range or jpeg format.

Fixes: 822c72eb1519 ("media: stm32: dcmipp: add bayer 10~14 bits formats")

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c
index db76a02a1848..ec1d773d5ad1 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c
@@ -130,11 +130,8 @@ static void dcmipp_byteproc_adjust_compose(struct v4l2_rect *r,
 	r->left = 0;
 
 	/* Compose is not possible for JPEG or Bayer formats */
-	if (fmt->code == MEDIA_BUS_FMT_JPEG_1X8 ||
-	    fmt->code == MEDIA_BUS_FMT_SBGGR8_1X8 ||
-	    fmt->code == MEDIA_BUS_FMT_SGBRG8_1X8 ||
-	    fmt->code == MEDIA_BUS_FMT_SGRBG8_1X8 ||
-	    fmt->code == MEDIA_BUS_FMT_SRGGB8_1X8) {
+	if (fmt->code >= MEDIA_BUS_FMT_SBGGR8_1X8 &&
+	    fmt->code <= MEDIA_BUS_FMT_JPEG_1X8) {
 		r->width = fmt->width;
 		r->height = fmt->height;
 		return;

-- 
2.34.1



From alain.volmat at foss.st.com  Fri Dec 19 06:30:34 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Fri, 19 Dec 2025 15:30:34 +0100
Subject: [PATCH 0/6] media: stm32: dcmipp: fixes & improvement on single
 pipe
Message-ID: <20251219-stm32-dcmipp-enhancements-v1-0-e2f8d46f022c@foss.st.com>

This series provides a set of fixes and enhancements
to the existing DCMIPP in its single-pipe version.

Those commits are done prior to addition of the multi-pipe
support of the DCMIPP which comes after those commits.
I splitted the overall series (including MP25 pixel pipes)
into 2 series so that it is easier to review.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
Alain Volmat (6):
      media: stm32: dcmipp: bytecap: clear all interrupts upon stream stop
      media: stm32: dcmipp: byteproc: disable compose for all bayers
      media: stm32: dcmipp: Add RGB888 format support overall
      media: stm32: dcmipp: add Y10-Y12-Y14 in all subdevs
      media: stm32: dcmipp: byteproc: only allow compose with 8/16bit fmts
      media: stm32: dcmipp: bytecap: remove useless cmier variable

 .../st/stm32/stm32-dcmipp/dcmipp-bytecap.c         | 24 ++++++++++++----------
 .../st/stm32/stm32-dcmipp/dcmipp-byteproc.c        | 24 ++++++++++++++++------
 .../platform/st/stm32/stm32-dcmipp/dcmipp-input.c  | 10 +++++++++
 3 files changed, 41 insertions(+), 17 deletions(-)
---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20251219-stm32-dcmipp-enhancements-b8ba6a1c7d8e

Best regards,
-- 
Alain Volmat <alain.volmat at foss.st.com>



From alain.volmat at foss.st.com  Fri Dec 19 06:30:35 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Fri, 19 Dec 2025 15:30:35 +0100
Subject: [PATCH 1/6] media: stm32: dcmipp: bytecap: clear all interrupts
 upon stream stop
In-Reply-To: <20251219-stm32-dcmipp-enhancements-v1-0-e2f8d46f022c@foss.st.com>
References: <20251219-stm32-dcmipp-enhancements-v1-0-e2f8d46f022c@foss.st.com>
Message-ID: <20251219-stm32-dcmipp-enhancements-v1-1-e2f8d46f022c@foss.st.com>

Ensure that there are no pending interrupts after we have stopped the
pipeline. Indeed, it could happen that new interrupt has been generated
during the stop_streaming processing hence clear them in order to avoid
getting a new interrupt right from the start of a next start_streaming.

Fixes: 28e0f3772296 ("media: stm32-dcmipp: STM32 DCMIPP camera interface driver")

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c
index 1c1b6b48918e..b18e273ef4a3 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c
@@ -512,6 +512,9 @@ static void dcmipp_bytecap_stop_streaming(struct vb2_queue *vq)
 	/* Disable pipe */
 	reg_clear(vcap, DCMIPP_P0FSCR, DCMIPP_P0FSCR_PIPEN);
 
+	/* Clear any pending interrupts */
+	reg_write(vcap, DCMIPP_CMFCR, DCMIPP_CMIER_P0ALL);
+
 	spin_lock_irq(&vcap->irqlock);
 
 	/* Return all queued buffers to vb2 in ERROR state */

-- 
2.34.1



From alain.volmat at foss.st.com  Fri Dec 19 06:30:40 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Fri, 19 Dec 2025 15:30:40 +0100
Subject: [PATCH 6/6] media: stm32: dcmipp: bytecap: remove useless cmier
 variable
In-Reply-To: <20251219-stm32-dcmipp-enhancements-v1-0-e2f8d46f022c@foss.st.com>
References: <20251219-stm32-dcmipp-enhancements-v1-0-e2f8d46f022c@foss.st.com>
Message-ID: <20251219-stm32-dcmipp-enhancements-v1-6-e2f8d46f022c@foss.st.com>

The struct dcmipp_bytecap_device embeds a cmier variable which is
actually only set once and then used in several places for interrupt
mask or interrupt enable/disable. Use the DCMIPP_CMIER_P0ALL
bitfield macro directly instead of using it through the cmier
variable.

There is also no need to mask again vcap->cmsr2 against enabled
interrupts bit since this has already been done when storing the
interrupt status into the cmsr2 variable.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 .../platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c     | 17 ++++++-----------
 1 file changed, 6 insertions(+), 11 deletions(-)

diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c
index dcb791c56d4c..19e6b187be22 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c
@@ -147,7 +147,6 @@ struct dcmipp_bytecap_device {
 
 	void __iomem *regs;
 
-	u32 cmier;
 	u32 cmsr2;
 
 	struct {
@@ -443,8 +442,7 @@ static int dcmipp_bytecap_start_streaming(struct vb2_queue *vq,
 	dcmipp_start_capture(vcap, vcap->next);
 
 	/* Enable interruptions */
-	vcap->cmier |= DCMIPP_CMIER_P0ALL;
-	reg_set(vcap, DCMIPP_CMIER, vcap->cmier);
+	reg_set(vcap, DCMIPP_CMIER, DCMIPP_CMIER_P0ALL);
 
 	vcap->state = DCMIPP_RUNNING;
 
@@ -500,7 +498,7 @@ static void dcmipp_bytecap_stop_streaming(struct vb2_queue *vq)
 	media_pipeline_stop(vcap->vdev.entity.pads);
 
 	/* Disable interruptions */
-	reg_clear(vcap, DCMIPP_CMIER, vcap->cmier);
+	reg_clear(vcap, DCMIPP_CMIER, DCMIPP_CMIER_P0ALL);
 
 	/* Stop capture */
 	reg_clear(vcap, DCMIPP_P0FCTCR, DCMIPP_P0FCTCR_CPTREQ);
@@ -749,23 +747,20 @@ static irqreturn_t dcmipp_bytecap_irq_thread(int irq, void *arg)
 	struct dcmipp_bytecap_device *vcap =
 			container_of(arg, struct dcmipp_bytecap_device, ved);
 	size_t bytesused = 0;
-	u32 cmsr2;
 
 	spin_lock_irq(&vcap->irqlock);
 
-	cmsr2 = vcap->cmsr2 & vcap->cmier;
-
 	/*
 	 * If we have an overrun, a frame-end will probably not be generated,
 	 * in that case the active buffer will be recycled as next buffer by
 	 * the VSYNC handler
 	 */
-	if (cmsr2 & DCMIPP_CMSR2_P0OVRF) {
+	if (vcap->cmsr2 & DCMIPP_CMSR2_P0OVRF) {
 		vcap->count.errors++;
 		vcap->count.overrun++;
 	}
 
-	if (cmsr2 & DCMIPP_CMSR2_P0FRAMEF) {
+	if (vcap->cmsr2 & DCMIPP_CMSR2_P0FRAMEF) {
 		vcap->count.frame++;
 
 		/* Read captured buffer size */
@@ -773,7 +768,7 @@ static irqreturn_t dcmipp_bytecap_irq_thread(int irq, void *arg)
 		dcmipp_bytecap_process_frame(vcap, bytesused);
 	}
 
-	if (cmsr2 & DCMIPP_CMSR2_P0VSYNCF) {
+	if (vcap->cmsr2 & DCMIPP_CMSR2_P0VSYNCF) {
 		vcap->count.vsync++;
 		if (vcap->state == DCMIPP_WAIT_FOR_BUFFER) {
 			vcap->count.underrun++;
@@ -804,7 +799,7 @@ static irqreturn_t dcmipp_bytecap_irq_callback(int irq, void *arg)
 			container_of(arg, struct dcmipp_bytecap_device, ved);
 
 	/* Store interrupt status register */
-	vcap->cmsr2 = reg_read(vcap, DCMIPP_CMSR2) & vcap->cmier;
+	vcap->cmsr2 = reg_read(vcap, DCMIPP_CMSR2) & DCMIPP_CMIER_P0ALL;
 	vcap->count.it++;
 
 	/* Clear interrupt */

-- 
2.34.1



From alain.volmat at foss.st.com  Fri Dec 19 06:30:37 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Fri, 19 Dec 2025 15:30:37 +0100
Subject: [PATCH 3/6] media: stm32: dcmipp: Add RGB888 format support
 overall
In-Reply-To: <20251219-stm32-dcmipp-enhancements-v1-0-e2f8d46f022c@foss.st.com>
References: <20251219-stm32-dcmipp-enhancements-v1-0-e2f8d46f022c@foss.st.com>
Message-ID: <20251219-stm32-dcmipp-enhancements-v1-3-e2f8d46f022c@foss.st.com>

Add entries within several subdevs in order to handle RGB888 format.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c  | 1 +
 drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c | 2 ++
 drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-input.c    | 4 ++++
 3 files changed, 7 insertions(+)

diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c
index b18e273ef4a3..6d42517817fd 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c
@@ -57,6 +57,7 @@ struct dcmipp_bytecap_pix_map {
 static const struct dcmipp_bytecap_pix_map dcmipp_bytecap_pix_map_list[] = {
 	PIXMAP_MBUS_PFMT(RGB565_2X8_LE, RGB565),
 	PIXMAP_MBUS_PFMT(RGB565_1X16, RGB565),
+	PIXMAP_MBUS_PFMT(RGB888_1X24, RGB24),
 	PIXMAP_MBUS_PFMT(YUYV8_2X8, YUYV),
 	PIXMAP_MBUS_PFMT(YUYV8_1X16, YUYV),
 	PIXMAP_MBUS_PFMT(YVYU8_2X8, YVYU),
diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c
index ec1d773d5ad1..dde28ed288cd 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c
@@ -49,6 +49,8 @@ struct dcmipp_byteproc_pix_map {
 static const struct dcmipp_byteproc_pix_map dcmipp_byteproc_pix_map_list[] = {
 	PIXMAP_MBUS_BPP(RGB565_2X8_LE, 2),
 	PIXMAP_MBUS_BPP(RGB565_1X16, 2),
+	PIXMAP_MBUS_BPP(RGB888_3X8, 3),
+	PIXMAP_MBUS_BPP(RGB888_1X24, 3),
 	PIXMAP_MBUS_BPP(YUYV8_2X8, 2),
 	PIXMAP_MBUS_BPP(YUYV8_1X16, 2),
 	PIXMAP_MBUS_BPP(YVYU8_2X8, 2),
diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-input.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-input.c
index 7e5311b67d7e..c44d664f6a0b 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-input.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-input.c
@@ -19,6 +19,7 @@
 #define DCMIPP_PRCR_FORMAT_SHIFT	16
 #define DCMIPP_PRCR_FORMAT_YUV422	0x1e
 #define DCMIPP_PRCR_FORMAT_RGB565	0x22
+#define DCMIPP_PRCR_FORMAT_RGB888	0x24
 #define DCMIPP_PRCR_FORMAT_RAW8		0x2a
 #define DCMIPP_PRCR_FORMAT_RAW10	0x2b
 #define DCMIPP_PRCR_FORMAT_RAW12	0x2c
@@ -72,6 +73,9 @@ static const struct dcmipp_inp_pix_map dcmipp_inp_pix_map_list[] = {
 	PIXMAP_SINK_SRC_PRCR_SWAP(RGB565_2X8_LE, RGB565_2X8_LE, RGB565, 1, MIPI_CSI2_DT_RGB565),
 	PIXMAP_SINK_SRC_PRCR_SWAP(RGB565_2X8_BE, RGB565_2X8_LE, RGB565, 0, MIPI_CSI2_DT_RGB565),
 	PIXMAP_SINK_SRC_PRCR_SWAP(RGB565_1X16, RGB565_1X16, RGB565, 0, MIPI_CSI2_DT_RGB565),
+	/* RGB888 */
+	PIXMAP_SINK_SRC_PRCR_SWAP(RGB888_3X8, RGB888_3X8, RGB888, 0, MIPI_CSI2_DT_RGB888),
+	PIXMAP_SINK_SRC_PRCR_SWAP(RGB888_1X24, RGB888_1X24, RGB888, 0, MIPI_CSI2_DT_RGB888),
 	/* YUV422 */
 	PIXMAP_SINK_SRC_PRCR_SWAP(YUYV8_2X8, YUYV8_2X8, YUV422, 1, MIPI_CSI2_DT_YUV422_8B),
 	PIXMAP_SINK_SRC_PRCR_SWAP(YUYV8_1X16, YUYV8_1X16, YUV422, 0, MIPI_CSI2_DT_YUV422_8B),

-- 
2.34.1



From alain.volmat at foss.st.com  Fri Dec 19 06:30:38 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Fri, 19 Dec 2025 15:30:38 +0100
Subject: [PATCH 4/6] media: stm32: dcmipp: add Y10-Y12-Y14 in all subdevs
In-Reply-To: <20251219-stm32-dcmipp-enhancements-v1-0-e2f8d46f022c@foss.st.com>
References: <20251219-stm32-dcmipp-enhancements-v1-0-e2f8d46f022c@foss.st.com>
Message-ID: <20251219-stm32-dcmipp-enhancements-v1-4-e2f8d46f022c@foss.st.com>

DCMIPP can handle Y8 to Y14 input formats however until now only
Y8 was handled. Add support for Y10-Y12-Y14 in all relevant
subdevs.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c  | 3 +++
 drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c | 3 +++
 drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-input.c    | 6 ++++++
 3 files changed, 12 insertions(+)

diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c
index 6d42517817fd..dcb791c56d4c 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c
@@ -67,6 +67,9 @@ static const struct dcmipp_bytecap_pix_map dcmipp_bytecap_pix_map_list[] = {
 	PIXMAP_MBUS_PFMT(VYUY8_2X8, VYUY),
 	PIXMAP_MBUS_PFMT(VYUY8_1X16, VYUY),
 	PIXMAP_MBUS_PFMT(Y8_1X8, GREY),
+	PIXMAP_MBUS_PFMT(Y10_1X10, Y10),
+	PIXMAP_MBUS_PFMT(Y12_1X12, Y12),
+	PIXMAP_MBUS_PFMT(Y14_1X14, Y14),
 	PIXMAP_MBUS_PFMT(SBGGR8_1X8, SBGGR8),
 	PIXMAP_MBUS_PFMT(SGBRG8_1X8, SGBRG8),
 	PIXMAP_MBUS_PFMT(SGRBG8_1X8, SGRBG8),
diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c
index dde28ed288cd..f45a3027f8f3 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c
@@ -60,6 +60,9 @@ static const struct dcmipp_byteproc_pix_map dcmipp_byteproc_pix_map_list[] = {
 	PIXMAP_MBUS_BPP(VYUY8_2X8, 2),
 	PIXMAP_MBUS_BPP(VYUY8_1X16, 2),
 	PIXMAP_MBUS_BPP(Y8_1X8, 1),
+	PIXMAP_MBUS_BPP(Y10_1X10, 2),
+	PIXMAP_MBUS_BPP(Y12_1X12, 2),
+	PIXMAP_MBUS_BPP(Y14_1X14, 2),
 	PIXMAP_MBUS_BPP(SBGGR8_1X8, 1),
 	PIXMAP_MBUS_BPP(SGBRG8_1X8, 1),
 	PIXMAP_MBUS_BPP(SGRBG8_1X8, 1),
diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-input.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-input.c
index c44d664f6a0b..c4bc76909b1c 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-input.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-input.c
@@ -25,6 +25,9 @@
 #define DCMIPP_PRCR_FORMAT_RAW12	0x2c
 #define DCMIPP_PRCR_FORMAT_RAW14	0x2d
 #define DCMIPP_PRCR_FORMAT_G8		0x4a
+#define DCMIPP_PRCR_FORMAT_G10		0x4b
+#define DCMIPP_PRCR_FORMAT_G12		0x4c
+#define DCMIPP_PRCR_FORMAT_G14		0x4d
 #define DCMIPP_PRCR_FORMAT_BYTE_STREAM	0x5a
 #define DCMIPP_PRCR_ESS			BIT(4)
 #define DCMIPP_PRCR_PCKPOL		BIT(5)
@@ -89,6 +92,9 @@ static const struct dcmipp_inp_pix_map dcmipp_inp_pix_map_list[] = {
 	PIXMAP_SINK_SRC_PRCR_SWAP(VYUY8_1X16, VYUY8_1X16, YUV422, 0, MIPI_CSI2_DT_YUV422_8B),
 	/* GREY */
 	PIXMAP_SINK_SRC_PRCR_SWAP(Y8_1X8, Y8_1X8, G8, 0, MIPI_CSI2_DT_RAW8),
+	PIXMAP_SINK_SRC_PRCR_SWAP(Y10_1X10, Y10_1X10, G10, 0, MIPI_CSI2_DT_RAW10),
+	PIXMAP_SINK_SRC_PRCR_SWAP(Y12_1X12, Y12_1X12, G12, 0, MIPI_CSI2_DT_RAW12),
+	PIXMAP_SINK_SRC_PRCR_SWAP(Y14_1X14, Y14_1X14, G14, 0, MIPI_CSI2_DT_RAW14),
 	/* Raw Bayer */
 	PIXMAP_SINK_SRC_PRCR_SWAP(SBGGR8_1X8, SBGGR8_1X8, RAW8, 0, MIPI_CSI2_DT_RAW8),
 	PIXMAP_SINK_SRC_PRCR_SWAP(SGBRG8_1X8, SGBRG8_1X8, RAW8, 0, MIPI_CSI2_DT_RAW8),

-- 
2.34.1



From ahmed.tiba at arm.com  Fri Dec 19 06:35:42 2025
From: ahmed.tiba at arm.com (Ahmed Tiba)
Date: Fri, 19 Dec 2025 14:35:42 +0000
Subject: [PATCH 02/12] ras: add estatus core implementation
In-Reply-To: <6vlj35rmfm7dzjdngxibaygcgmcj3h2ibhuqnoeqqrsrxmsqbt@qpqnm5xndok6>
Message-ID: <20251219143545.2792858-1-ahmed.tiba@arm.com>

On Wed, Dec 18, 2025 at 04:42:42PM +0100, Mauro Carvalho Chehab wrote:
>> Add estatus.c, hook it into the EFI Makefile, and register
>> the MAINTAINERS entry for the new code. The implementation provides the
>> memory-pool helpers, notifier plumbing, and utility functions that the
>> GHES and DeviceTree providers will reuse in later commits.
>>
>> Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>
>> ---
>>  MAINTAINERS                    |   1 +
>>  drivers/firmware/efi/Makefile  |   1 +
>>  drivers/firmware/efi/estatus.c | 560 +++++++++++++++++++++++++++++++++

> If I'm understanding this patch series, you will be basically moving more than
> half of the code from drivers/acpi/apei/ghes.c to drivers/firmware/efi/estatus.c:
> 
>  drivers/acpi/apei/ghes.c                   | 1292 ++-------------
>  drivers/firmware/efi/estatus.c             | 1056 ++++++++++++
> 
>  $ wc drivers/acpi/apei/ghes.c drivers/firmware/efi/estatus.c -l
>   894 drivers/acpi/apei/ghes.c
>  1056 drivers/firmware/efi/estatus.c
>  1950 total
> 
> The way you're doing of adding things first, and then removing on
> separate patches is error prone, makes it hard to review and
> it becomes a lot harder to identify whose are the original authors
> of the code.

I see your point. I tried staging the additions ahead of the removals so the new helpers
were readable, but I can see that makes review and authorship tracking painful.

> This will cause undetected conflicts with already-submitted patches
> that are under review.
> 
> You should instead be moving function per function as-is. Then,
> adjust the code to make it more generic.

I did try moving each helper first and doing the cleanup afterwards,
but the series quickly ballooned and the ordering became confusing
once later patches started depending on code that was still in transit.

I?m happy to try again, though I expect to run into the same issue
unless there?s a known pattern to follow. If you have a reference series or a preferred ordering
that you?d recommend, please point me to it so I can align with that approach.


>>  3 files changed, 562 insertions(+)
>>  create mode 100644 drivers/firmware/efi/estatus.c
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 501b6d300aa5..67d79d4e612d 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -21760,6 +21760,7 @@ F:    drivers/rapidio/
>>  RAS ERROR STATUS
>>  M:   Ahmed Tiba <ahmed.tiba at arm.com>
>>  S:   Maintained
>> +F:   drivers/firmware/efi/estatus.c
>>  F:   include/linux/estatus.h
>> 
>>  RAS INFRASTRUCTURE
>> diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile
>> index 8efbcf699e4f..03708d915bcf 100644
>> --- a/drivers/firmware/efi/Makefile
>> +++ b/drivers/firmware/efi/Makefile
>> @@ -20,6 +20,7 @@ obj-$(CONFIG_EFI_PARAMS_FROM_FDT)   += fdtparams.o
>>  obj-$(CONFIG_EFI_ESRT)                       += esrt.o
>>  obj-$(CONFIG_EFI_VARS_PSTORE)                += efi-pstore.o
>>  obj-$(CONFIG_UEFI_CPER)                      += cper.o cper_cxl.o
>> +obj-$(CONFIG_RAS_ESTATUS_CORE)               += estatus.o
>>  obj-$(CONFIG_EFI_RUNTIME_WRAPPERS)   += runtime-wrappers.o
>>  subdir-$(CONFIG_EFI_STUB)            += libstub
>>  obj-$(CONFIG_EFI_BOOTLOADER_CONTROL) += efibc.o
>> diff --git a/drivers/firmware/efi/estatus.c b/drivers/firmware/efi/estatus.c
>> new file mode 100644
>> index 000000000000..8dae5c73ce27
>> --- /dev/null
>> +++ b/drivers/firmware/efi/estatus.c
>> @@ -0,0 +1,560 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Firmware-first RAS: Generic Error Status Core
>> + *
>> + * Copyright (C) 2025 ARM Ltd.
>> + * Author: Ahmed Tiba <ahmed.tiba at arm.com>
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/cper.h>
>> +#include <linux/ratelimit.h>
>> +#include <linux/vmalloc.h>
>> +#include <linux/llist.h>
>> +#include <linux/genalloc.h>
>> +#include <linux/pci.h>
>> +#include <linux/pfn.h>
>> +#include <linux/aer.h>
>> +#include <linux/nmi.h>
>> +#include <linux/sched/clock.h>
>> +#include <linux/uuid.h>
>> +#include <linux/kconfig.h>
>> +#include <linux/ras.h>
>> +#include <linux/mutex.h>
>> +#include <linux/notifier.h>
>> +#include <linux/workqueue.h>
>> +#include <linux/task_work.h>
>> +#include <ras/ras_event.h>
>> +
>> +#include <linux/estatus.h>
>> +#include <asm/fixmap.h>
>> +
>> +void estatus_pool_region_free(unsigned long addr, u32 size);
>> +
>> +static void estatus_log_hw_error(char level, const char *seq_tag,
>> +                              const char *name)
>> +{
>> +     switch (level) {
>> +     case '0':
>> +             pr_emerg("%sHardware error from %s\n", seq_tag, name);
>> +             break;
>> +     case '1':
>> +             pr_alert("%sHardware error from %s\n", seq_tag, name);
>> +             break;
>> +     case '2':
>> +             pr_crit("%sHardware error from %s\n", seq_tag, name);
>> +             break;
>> +     case '3':
>> +             pr_err("%sHardware error from %s\n", seq_tag, name);
>> +             break;
>> +     case '4':
>> +             pr_warn("%sHardware error from %s\n", seq_tag, name);
>> +             break;
>> +     case '5':
>> +             pr_notice("%sHardware error from %s\n", seq_tag, name);
>> +             break;
>> +     case '6':
>> +             pr_info("%sHardware error from %s\n", seq_tag, name);
>> +             break;
>> +     default:
>> +             pr_debug("%sHardware error from %s\n", seq_tag, name);
>> +             break;
>> +     }
>> +}
>> +
>> +static inline u32 estatus_len(struct acpi_hest_generic_status *estatus)
>> +{
>> +     if (estatus->raw_data_length)
>> +             return estatus->raw_data_offset + estatus->raw_data_length;
>> +
>> +     return sizeof(*estatus) + estatus->data_length;
>> +}
>> +
>> +#define ESTATUS_PFX  "ESTATUS: "
>> +
>> +#define ESTATUS_ESOURCE_PREALLOC_MAX_SIZE_SIZE       65536
>> +
>> +#define ESTATUS_POOL_MIN_ALLOC_ORDER 3
>> +
>> +/* This is just an estimation for memory pool allocation */
>> +#define ESTATUS_CACHE_AVG_SIZE       512
>> +
>> +#define ESTATUS_CACHES_SIZE  4
>> +
>> +#define ESTATUS_IN_CACHE_MAX_NSEC    10000000000ULL
>> +/* Prevent too many caches are allocated because of RCU */
>> +#define ESTATUS_CACHE_ALLOCED_MAX    (ESTATUS_CACHES_SIZE * 3 / 2)
>> +
>> +#define ESTATUS_CACHE_LEN(estatus_len)                       \
>> +     (sizeof(struct estatus_cache) + (estatus_len))
>> +#define ESTATUS_FROM_CACHE(cache)                    \
>> +     ((struct acpi_hest_generic_status *)            \
>> +      ((struct estatus_cache *)(cache) + 1))
>> +
>> +#define ESTATUS_NODE_LEN(estatus_len)                        \
>> +     (sizeof(struct estatus_node) + (estatus_len))
>> +#define ESTATUS_FROM_NODE(node)                              \
>> +     ((struct acpi_hest_generic_status *)            \
>> +      ((struct estatus_node *)(node) + 1))
>> +
>> +#define ESTATUS_VENDOR_ENTRY_LEN(gdata_len)          \
>> +     (sizeof(struct estatus_vendor_record_entry) + (gdata_len))
>> +#define ESTATUS_GDATA_FROM_VENDOR_ENTRY(vendor_entry)        \
>> +     ((struct acpi_hest_generic_data *)              \
>> +     ((struct estatus_vendor_record_entry *)(vendor_entry) + 1))
>> +
>> +static ATOMIC_NOTIFIER_HEAD(estatus_report_chain);
>> +
>> +struct estatus_vendor_record_entry {
>> +     struct work_struct work;
>> +     int error_severity;
>> +     char vendor_record[];
>> +};
>> +
>> +static struct estatus_cache __rcu *estatus_caches[ESTATUS_CACHES_SIZE];
>> +static atomic_t estatus_cache_alloced;
>> +
>> +static int estatus_panic_timeout __read_mostly = 30;
>> +
>> +static struct gen_pool *estatus_pool;
>> +static DEFINE_MUTEX(estatus_pool_mutex);
>> +
>> +static inline const char *estatus_source_name(struct estatus_source *source)
>> +{
>> +     if (source->ops && source->ops->get_name)
>> +             return source->ops->get_name(source);
>> +
>> +     return "unknown";
>> +}
>> +
>> +static inline size_t estatus_source_max_len(struct estatus_source *source)
>> +{
>> +     if (source->ops && source->ops->get_max_len)
>> +             return source->ops->get_max_len(source);
>> +
>> +     return 0;
>> +}
>> +
>> +static inline enum estatus_notify_mode
>> +estatus_source_notify_mode(struct estatus_source *source)
>> +{
>> +     if (source->ops && source->ops->get_notify_mode)
>> +             return source->ops->get_notify_mode(source);
>> +
>> +     return ESTATUS_NOTIFY_ASYNC;
>> +}
>> +
>> +static inline int estatus_source_get_phys(struct estatus_source *source,
>> +                                       phys_addr_t *addr)
>> +{
>> +     if (!source->ops || !source->ops->get_phys)
>> +             return -EOPNOTSUPP;
>> +
>> +     return source->ops->get_phys(source, addr);
>> +}
>> +
>> +static inline int estatus_source_read(struct estatus_source *source,
>> +                                   phys_addr_t addr, void *buf, size_t len,
>> +                                   enum fixed_addresses fixmap_idx)
>> +{
>> +     if (!source->ops || !source->ops->read)
>> +             return -EOPNOTSUPP;
>> +
>> +     return source->ops->read(source, addr, buf, len, fixmap_idx);
>> +}
>> +
>> +static inline int estatus_source_write(struct estatus_source *source,
>> +                                    phys_addr_t addr, const void *buf,
>> +                                    size_t len,
>> +                                    enum fixed_addresses fixmap_idx)
>> +{
>> +     if (!source->ops || !source->ops->write)
>> +             return -EOPNOTSUPP;
>> +
>> +     return source->ops->write(source, addr, buf, len, fixmap_idx);
>> +}
>> +
>> +static inline void estatus_source_ack(struct estatus_source *source)
>> +{
>> +     if (source->ops && source->ops->ack)
>> +             source->ops->ack(source);
>> +}
>> +
>> +int estatus_pool_init(unsigned int num_ghes)
>> +{
>> +     unsigned long addr, len;
>> +     int rc = 0;
>> +
>> +     mutex_lock(&estatus_pool_mutex);
>> +     if (estatus_pool)
>> +             goto out_unlock;
>> +
>> +     estatus_pool = gen_pool_create(ESTATUS_POOL_MIN_ALLOC_ORDER, -1);
>> +     if (!estatus_pool) {
>> +             rc = -ENOMEM;
>> +             goto out_unlock;
>> +     }
>> +
>> +     if (!num_ghes)
>> +             num_ghes = 1;
>> +
>> +     len = ESTATUS_CACHE_AVG_SIZE * ESTATUS_CACHE_ALLOCED_MAX;
>> +     len += (num_ghes * ESTATUS_ESOURCE_PREALLOC_MAX_SIZE_SIZE);
>> +
>> +     addr = (unsigned long)vmalloc(PAGE_ALIGN(len));
>> +     if (!addr) {
>> +             rc = -ENOMEM;
>> +             goto err_pool_alloc;
>> +     }
>> +
>> +     rc = gen_pool_add(estatus_pool, addr, PAGE_ALIGN(len), -1);
>> +     if (rc)
>> +             goto err_pool_add;
>> +
>> +out_unlock:
>> +     mutex_unlock(&estatus_pool_mutex);
>> +     return rc;
>> +
>> +err_pool_add:
>> +     vfree((void *)addr);
>> +err_pool_alloc:
>> +     gen_pool_destroy(estatus_pool);
>> +     estatus_pool = NULL;
>> +     goto out_unlock;
>> +}
>> +
>> +/**
>> + * estatus_pool_region_free - free previously allocated memory
>> + *                              from the estatus_pool.
>> + * @addr: address of memory to free.
>> + * @size: size of memory to free.
>> + *
>> + * Returns none.
>> + */
>> +void estatus_pool_region_free(unsigned long addr, u32 size)
>> +{
>> +     gen_pool_free(estatus_pool, addr, size);
>> +}
>> +EXPORT_SYMBOL_GPL(estatus_pool_region_free);
>> +
>> +/* Check the top-level record header has an appropriate size. */
>> +static int __estatus_check_estatus(struct estatus_source *source,
>> +                                struct acpi_hest_generic_status *estatus)
>> +{
>> +     u32 len = estatus_len(estatus);
>> +     size_t max_len = estatus_source_max_len(source);
>> +
>> +     if (len < sizeof(*estatus)) {
>> +             pr_warn_ratelimited(FW_WARN ESTATUS_PFX "Truncated error status block!\n");
>> +             return -EIO;
>> +     }
>> +
>> +     if (max_len && len > max_len) {
>> +             pr_warn_ratelimited(FW_WARN ESTATUS_PFX "Invalid error status block length!\n");
>> +             return -EIO;
>> +     }
>> +
>> +     if (cper_estatus_check_header(estatus)) {
>> +             pr_warn_ratelimited(FW_WARN ESTATUS_PFX "Invalid CPER header!\n");
>> +             return -EIO;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +/* Read the CPER block, returning its address, and header in estatus. */
>> +static int __estatus_peek_estatus(struct estatus_source *source,
>> +                               struct acpi_hest_generic_status *estatus,
>> +                               phys_addr_t *buf_paddr,
>> +                               enum fixed_addresses fixmap_idx)
>> +{
>> +     int rc;
>> +
>> +     rc = estatus_source_get_phys(source, buf_paddr);
>> +     if (rc) {
>> +             *buf_paddr = 0;
>> +             pr_warn_ratelimited(FW_WARN ESTATUS_PFX
>> +                                 "Failed to get error status block address for provider %s: %d\n",
>> +                                 estatus_source_name(source), rc);
>> +             return rc;
>> +     }
>> +
>> +     if (!*buf_paddr)
>> +             return -ENOENT;
>> +
>> +     rc = estatus_source_read(source, *buf_paddr, estatus,
>> +                              sizeof(*estatus), fixmap_idx);
>> +     if (rc)
>> +             return rc;
>> +
>> +     if (!estatus->block_status) {
>> +             *buf_paddr = 0;
>> +             return -ENOENT;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static int __estatus_read_estatus(struct estatus_source *source,
>> +                               struct acpi_hest_generic_status *estatus,
>> +                               phys_addr_t buf_paddr,
>> +                               enum fixed_addresses fixmap_idx,
>> +                               size_t buf_len)
>> +{
>> +     int rc;
>> +
>> +     rc = estatus_source_read(source, buf_paddr, estatus, buf_len,
>> +                              fixmap_idx);
>> +     if (rc)
>> +             return rc;
>> +
>> +     if (cper_estatus_check(estatus)) {
>> +             pr_warn_ratelimited(FW_WARN ESTATUS_PFX
>> +                                 "Failed to read error status block for provider %s!\n",
>> +                                 estatus_source_name(source));
>> +             return -EIO;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static int estatus_read_estatus(struct estatus_source *source,
>> +                             struct acpi_hest_generic_status *estatus,
>> +                             phys_addr_t *buf_paddr,
>> +                             enum fixed_addresses fixmap_idx)
>> +{
>> +     int rc;
>> +
>> +     rc = __estatus_peek_estatus(source, estatus, buf_paddr, fixmap_idx);
>> +     if (rc)
>> +             return rc;
>> +
>> +     rc = __estatus_check_estatus(source, estatus);
>> +     if (rc)
>> +             return rc;
>> +
>> +     return __estatus_read_estatus(source, estatus, *buf_paddr,
>> +                                   fixmap_idx, estatus_len(estatus));
>> +}
>> +
>> +static void estatus_clear_estatus(struct estatus_source *source,
>> +                               struct acpi_hest_generic_status *estatus,
>> +                               phys_addr_t buf_paddr,
>> +                               enum fixed_addresses fixmap_idx)
>> +{
>> +     int rc;
>> +
>> +     estatus->block_status = 0;
>> +
>> +     if (!buf_paddr)
>> +             return;
>> +
>> +     rc = estatus_source_write(source, buf_paddr, estatus,
>> +                               sizeof(estatus->block_status), fixmap_idx);
>> +     if (rc)
>> +             pr_warn_ratelimited(FW_WARN ESTATUS_PFX
>> +                                 "Failed to clear error status block for provider %s: %d\n",
>> +                                 estatus_source_name(source), rc);
>> +
>> +     estatus_source_ack(source);
>> +}
>> +
>> +static inline int estatus_severity(int severity)
>> +{
>> +     switch (severity) {
>> +     case CPER_SEV_INFORMATIONAL:
>> +             return ESTATUS_SEV_NO;
>> +     case CPER_SEV_CORRECTED:
>> +             return ESTATUS_SEV_CORRECTED;
>> +     case CPER_SEV_RECOVERABLE:
>> +             return ESTATUS_SEV_RECOVERABLE;
>> +     case CPER_SEV_FATAL:
>> +             return ESTATUS_SEV_PANIC;
>> +     default:
>> +             /* Unknown, go panic */
>> +             return ESTATUS_SEV_PANIC;
>> +     }
>> +}
>> +
>> +static void __estatus_print_estatus(const char *pfx,
>> +                                 struct estatus_source *source,
>> +                                 const struct acpi_hest_generic_status *estatus)
>> +{
>> +     static atomic_t seqno;
>> +     unsigned int curr_seqno;
>> +     char pfx_seq[64];
>> +     char seq_tag[64];
>> +     const char *name = estatus_source_name(source);
>> +     const char *level = pfx;
>> +     char level_char = '4';
>> +
>> +     if (!level) {
>> +             if (estatus_severity(estatus->error_severity) <=
>> +                 ESTATUS_SEV_CORRECTED)
>> +                     level = KERN_WARNING;
>> +             else
>> +                     level = KERN_ERR;
>> +     }
>> +
>> +     if (level[0] == KERN_SOH_ASCII && level[1])
>> +             level_char = level[1];
>> +     else if (estatus_severity(estatus->error_severity) > ESTATUS_SEV_CORRECTED)
>> +             level_char = '3';
>> +
>> +     curr_seqno = atomic_inc_return(&seqno);
>> +     snprintf(seq_tag, sizeof(seq_tag), "{%u}" HW_ERR, curr_seqno);
>> +     snprintf(pfx_seq, sizeof(pfx_seq), "%s%s", level, seq_tag);
>> +     estatus_log_hw_error(level_char, seq_tag, name);
>> +     cper_estatus_print(pfx_seq, estatus);
>> +}
>> +
>> +static int estatus_print_estatus(const char *pfx,
>> +                              struct estatus_source *source,
>> +                              const struct acpi_hest_generic_status *estatus)
>> +{
>> +     /* Not more than 2 messages every 5 seconds */
>> +     static DEFINE_RATELIMIT_STATE(ratelimit_corrected, 5 * HZ, 2);
>> +     static DEFINE_RATELIMIT_STATE(ratelimit_uncorrected, 5 * HZ, 2);
>> +     struct ratelimit_state *ratelimit;
>> +
>> +     if (estatus_severity(estatus->error_severity) <= ESTATUS_SEV_CORRECTED)
>> +             ratelimit = &ratelimit_corrected;
>> +     else
>> +             ratelimit = &ratelimit_uncorrected;
>> +     if (__ratelimit(ratelimit)) {
>> +             __estatus_print_estatus(pfx, source, estatus);
>> +             return 1;
>> +     }
>> +     return 0;
>> +}
>> +
>> +/*
>> + * GHES error status reporting throttle, to report more kinds of
>> + * errors, instead of just most frequently occurred errors.
>> + */
>> +static int estatus_cached(struct acpi_hest_generic_status *estatus)
>> +{
>> +     u32 len;
>> +     int i, cached = 0;
>> +     unsigned long long now;
>> +     struct estatus_cache *cache;
>> +     struct acpi_hest_generic_status *cache_estatus;
>> +
>> +     len = estatus_len(estatus);
>> +     rcu_read_lock();
>> +     for (i = 0; i < ESTATUS_CACHES_SIZE; i++) {
>> +             cache = rcu_dereference(estatus_caches[i]);
>> +             if (!cache)
>> +                     continue;
>> +             if (len != cache->estatus_len)
>> +                     continue;
>> +             cache_estatus = ESTATUS_FROM_CACHE(cache);
>> +             if (memcmp(estatus, cache_estatus, len))
>> +                     continue;
>> +             atomic_inc(&cache->count);
>> +             now = sched_clock();
>> +             if (now - cache->time_in < ESTATUS_IN_CACHE_MAX_NSEC)
>> +                     cached = 1;
>> +             break;
>> +     }
>> +     rcu_read_unlock();
>> +     return cached;
>> +}
>> +
>> +static struct estatus_cache *estatus_cache_alloc(struct estatus_source *source,
>> +                                              struct acpi_hest_generic_status *estatus)
>> +{
>> +     int alloced;
>> +     u32 len, cache_len;
>> +     struct estatus_cache *cache;
>> +     struct acpi_hest_generic_status *cache_estatus;
>> +
>> +     alloced = atomic_add_return(1, &estatus_cache_alloced);
>> +     if (alloced > ESTATUS_CACHE_ALLOCED_MAX) {
>> +             atomic_dec(&estatus_cache_alloced);
>> +             return NULL;
>> +     }
>> +     len = estatus_len(estatus);
>> +     cache_len = ESTATUS_CACHE_LEN(len);
>> +     cache = (void *)gen_pool_alloc(estatus_pool, cache_len);
>> +     if (!cache) {
>> +             atomic_dec(&estatus_cache_alloced);
>> +             return NULL;
>> +     }
>> +     cache_estatus = ESTATUS_FROM_CACHE(cache);
>> +     memcpy(cache_estatus, estatus, len);
>> +     cache->estatus_len = len;
>> +     atomic_set(&cache->count, 0);
>> +     cache->source = source;
>> +     cache->time_in = sched_clock();
>> +     return cache;
>> +}
>> +
>> +static void estatus_cache_rcu_free(struct rcu_head *head)
>> +{
>> +     struct estatus_cache *cache;
>> +     u32 len;
>> +
>> +     cache = container_of(head, struct estatus_cache, rcu);
>> +     len = estatus_len(ESTATUS_FROM_CACHE(cache));
>> +     len = ESTATUS_CACHE_LEN(len);
>> +     gen_pool_free(estatus_pool, (unsigned long)cache, len);
>> +     atomic_dec(&estatus_cache_alloced);
>> +}
>> +
>> +static void estatus_cache_add(struct estatus_source *source,
>> +                           struct acpi_hest_generic_status *estatus)
>> +{
>> +     unsigned long long now, duration, period, max_period = 0;
>> +     struct estatus_cache *cache, *new_cache;
>> +     struct estatus_cache __rcu *victim;
>> +     int i, slot = -1, count;
>> +
>> +     new_cache = estatus_cache_alloc(source, estatus);
>> +     if (!new_cache)
>> +             return;
>> +
>> +     rcu_read_lock();
>> +     now = sched_clock();
>> +     for (i = 0; i < ESTATUS_CACHES_SIZE; i++) {
>> +             cache = rcu_dereference(estatus_caches[i]);
>> +             if (!cache) {
>> +                     slot = i;
>> +                     break;
>> +             }
>> +             duration = now - cache->time_in;
>> +             if (duration >= ESTATUS_IN_CACHE_MAX_NSEC) {
>> +                     slot = i;
>> +                     break;
>> +             }
>> +             count = atomic_read(&cache->count);
>> +             period = duration;
>> +             do_div(period, (count + 1));
>> +             if (period > max_period) {
>> +                     max_period = period;
>> +                     slot = i;
>> +             }
>> +     }
>> +     rcu_read_unlock();
>> +
>> +     if (slot != -1) {
>> +             /*
>> +              * Use release semantics to ensure that estatus_cached()
>> +              * running on another CPU will see the updated cache fields if
>> +              * it can see the new value of the pointer.
>> +              */
>> +             victim = xchg_release(&estatus_caches[slot],
>> +                                   RCU_INITIALIZER(new_cache));
>> +
>> +             /*
>> +              * At this point, victim may point to a cached item different
>> +              * from the one based on which we selected the slot. Instead of
>> +              * going to the loop again to pick another slot, let's just
>> +              * drop the other item anyway: this may cause a false cache
>> +              * miss later on, but that won't cause any problems.
>> +              */
>> +             if (victim)
>> +                     call_rcu(&unrcu_pointer(victim)->rcu,
>> +                              estatus_cache_rcu_free);
>> +     }
>> +}
>> --
>> 2.43.0
>>

Thanks,
Ahmed


From krzysztof.kozlowski at oss.qualcomm.com  Fri Dec 19 06:31:49 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 15:31:49 +0100
Subject: [PATCH 0/5] iio: adc: Simplify with dev_err_probe
Message-ID: <20251219-iio-dev-err-probe-v1-0-bd0fbc83c8a0@oss.qualcomm.com>

Use dev_err_probe() to make error code handling simpler and handle
deferred probe nicely (avoid spamming logs).

Best regards,
Krzysztof

---
Krzysztof Kozlowski (5):
      iio: adc: aspeed: Simplify with dev_err_probe
      iio: adc: exynos: Simplify with dev_err_probe
      iio: adc: qcom-spmi-rradc: Simplify with dev_err_probe
      iio: adc: rockchip: Simplify with dev_err_probe
      iio: adc: sc27xx: Simplify with dev_err_probe

 drivers/iio/adc/aspeed_adc.c      |  9 ++++---
 drivers/iio/adc/exynos_adc.c      | 29 ++++++++---------------
 drivers/iio/adc/qcom-spmi-rradc.c | 20 ++++++----------
 drivers/iio/adc/rockchip_saradc.c | 13 ++++-------
 drivers/iio/adc/sc27xx_adc.c      | 49 ++++++++++++++-------------------------
 5 files changed, 43 insertions(+), 77 deletions(-)
---
base-commit: cc3aa43b44bdb43dfbac0fcb51c56594a11338a8
change-id: 20251219-iio-dev-err-probe-59b3104c8d4b

Best regards,
-- 
Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>



From krzysztof.kozlowski at oss.qualcomm.com  Fri Dec 19 06:31:50 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 15:31:50 +0100
Subject: [PATCH 1/5] iio: adc: aspeed: Simplify with dev_err_probe
In-Reply-To: <20251219-iio-dev-err-probe-v1-0-bd0fbc83c8a0@oss.qualcomm.com>
References: <20251219-iio-dev-err-probe-v1-0-bd0fbc83c8a0@oss.qualcomm.com>
Message-ID: <20251219-iio-dev-err-probe-v1-1-bd0fbc83c8a0@oss.qualcomm.com>

Use dev_err_probe() to make error code handling simpler and handle
deferred probe nicely (avoid spamming logs).

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/iio/adc/aspeed_adc.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
index bf2bfd6bdc41..1ae45fe90e6c 100644
--- a/drivers/iio/adc/aspeed_adc.c
+++ b/drivers/iio/adc/aspeed_adc.c
@@ -535,11 +535,10 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 		return PTR_ERR(data->clk_scaler);
 
 	data->rst = devm_reset_control_get_shared(&pdev->dev, NULL);
-	if (IS_ERR(data->rst)) {
-		dev_err(&pdev->dev,
-			"invalid or missing reset controller device tree entry");
-		return PTR_ERR(data->rst);
-	}
+	if (IS_ERR(data->rst))
+		return dev_err_probe(&pdev->dev, PTR_ERR(data->rst),
+				     "invalid or missing reset controller device tree entry");
+
 	reset_control_deassert(data->rst);
 
 	ret = devm_add_action_or_reset(data->dev, aspeed_adc_reset_assert,

-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Fri Dec 19 06:31:51 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 15:31:51 +0100
Subject: [PATCH 2/5] iio: adc: exynos: Simplify with dev_err_probe
In-Reply-To: <20251219-iio-dev-err-probe-v1-0-bd0fbc83c8a0@oss.qualcomm.com>
References: <20251219-iio-dev-err-probe-v1-0-bd0fbc83c8a0@oss.qualcomm.com>
Message-ID: <20251219-iio-dev-err-probe-v1-2-bd0fbc83c8a0@oss.qualcomm.com>

Use dev_err_probe() to make error code handling simpler and handle
deferred probe nicely (avoid spamming logs).

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/iio/adc/exynos_adc.c | 29 ++++++++++-------------------
 1 file changed, 10 insertions(+), 19 deletions(-)

diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
index 1484adff00df..491e8dcfd91e 100644
--- a/drivers/iio/adc/exynos_adc.c
+++ b/drivers/iio/adc/exynos_adc.c
@@ -564,10 +564,8 @@ static int exynos_adc_probe(struct platform_device *pdev)
 	info = iio_priv(indio_dev);
 
 	info->data = exynos_adc_get_data(pdev);
-	if (!info->data) {
-		dev_err(&pdev->dev, "failed getting exynos_adc_data\n");
-		return -EINVAL;
-	}
+	if (!info->data)
+		return dev_err_probe(&pdev->dev, -EINVAL, "failed getting exynos_adc_data\n");
 
 	info->regs = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(info->regs))
@@ -578,10 +576,9 @@ static int exynos_adc_probe(struct platform_device *pdev)
 		info->pmu_map = syscon_regmap_lookup_by_phandle(
 					pdev->dev.of_node,
 					"samsung,syscon-phandle");
-		if (IS_ERR(info->pmu_map)) {
-			dev_err(&pdev->dev, "syscon regmap lookup failed.\n");
-			return PTR_ERR(info->pmu_map);
-		}
+		if (IS_ERR(info->pmu_map))
+			return dev_err_probe(&pdev->dev, PTR_ERR(info->pmu_map),
+					     "syscon regmap lookup failed.\n");
 	}
 
 	irq = platform_get_irq(pdev, 0);
@@ -593,20 +590,14 @@ static int exynos_adc_probe(struct platform_device *pdev)
 	init_completion(&info->completion);
 
 	info->clk = devm_clk_get(&pdev->dev, "adc");
-	if (IS_ERR(info->clk)) {
-		dev_err(&pdev->dev, "failed getting clock, err = %ld\n",
-							PTR_ERR(info->clk));
-		return PTR_ERR(info->clk);
-	}
+	if (IS_ERR(info->clk))
+		return dev_err_probe(&pdev->dev, PTR_ERR(info->clk), "failed getting clock\n");
 
 	if (info->data->needs_sclk) {
 		info->sclk = devm_clk_get(&pdev->dev, "sclk");
-		if (IS_ERR(info->sclk)) {
-			dev_err(&pdev->dev,
-				"failed getting sclk clock, err = %ld\n",
-				PTR_ERR(info->sclk));
-			return PTR_ERR(info->sclk);
-		}
+		if (IS_ERR(info->sclk))
+			return dev_err_probe(&pdev->dev, PTR_ERR(info->sclk),
+					     "failed getting sclk clock\n");
 	}
 
 	info->vdd = devm_regulator_get(&pdev->dev, "vdd");

-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Fri Dec 19 06:31:52 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 15:31:52 +0100
Subject: [PATCH 3/5] iio: adc: qcom-spmi-rradc: Simplify with dev_err_probe
In-Reply-To: <20251219-iio-dev-err-probe-v1-0-bd0fbc83c8a0@oss.qualcomm.com>
References: <20251219-iio-dev-err-probe-v1-0-bd0fbc83c8a0@oss.qualcomm.com>
Message-ID: <20251219-iio-dev-err-probe-v1-3-bd0fbc83c8a0@oss.qualcomm.com>

Use dev_err_probe() to make error code handling simpler.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/iio/adc/qcom-spmi-rradc.c | 20 +++++++-------------
 1 file changed, 7 insertions(+), 13 deletions(-)

diff --git a/drivers/iio/adc/qcom-spmi-rradc.c b/drivers/iio/adc/qcom-spmi-rradc.c
index b245416bae12..8e75665204d1 100644
--- a/drivers/iio/adc/qcom-spmi-rradc.c
+++ b/drivers/iio/adc/qcom-spmi-rradc.c
@@ -934,20 +934,15 @@ static int rradc_probe(struct platform_device *pdev)
 
 	chip = iio_priv(indio_dev);
 	chip->regmap = dev_get_regmap(pdev->dev.parent, NULL);
-	if (!chip->regmap) {
-		dev_err(dev, "Couldn't get parent's regmap\n");
-		return -EINVAL;
-	}
+	if (!chip->regmap)
+		return dev_err_probe(dev, -EINVAL, "Couldn't get parent's regmap\n");
 
 	chip->dev = dev;
 	mutex_init(&chip->conversion_lock);
 
 	ret = device_property_read_u32(dev, "reg", &chip->base);
-	if (ret < 0) {
-		dev_err(chip->dev, "Couldn't find reg address, ret = %d\n",
-			ret);
-		return ret;
-	}
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "Couldn't find reg address\n");
 
 	batt_id_delay = -1;
 	ret = device_property_read_u32(dev, "qcom,batt-id-delay-ms",
@@ -975,10 +970,9 @@ static int rradc_probe(struct platform_device *pdev)
 
 	/* Get the PMIC revision, we need it to handle some varying coefficients */
 	chip->pmic = qcom_pmic_get(chip->dev);
-	if (IS_ERR(chip->pmic)) {
-		dev_err(chip->dev, "Unable to get reference to PMIC device\n");
-		return PTR_ERR(chip->pmic);
-	}
+	if (IS_ERR(chip->pmic))
+		return dev_err_probe(dev, PTR_ERR(chip->pmic),
+				     "Unable to get reference to PMIC device\n");
 
 	switch (chip->pmic->subtype) {
 	case PMI8998_SUBTYPE:

-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Fri Dec 19 06:31:53 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 15:31:53 +0100
Subject: [PATCH 4/5] iio: adc: rockchip: Simplify with dev_err_probe
In-Reply-To: <20251219-iio-dev-err-probe-v1-0-bd0fbc83c8a0@oss.qualcomm.com>
References: <20251219-iio-dev-err-probe-v1-0-bd0fbc83c8a0@oss.qualcomm.com>
Message-ID: <20251219-iio-dev-err-probe-v1-4-bd0fbc83c8a0@oss.qualcomm.com>

Use dev_err_probe() to make error code handling simpler and handle
deferred probe nicely (avoid spamming logs).

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/iio/adc/rockchip_saradc.c | 13 +++++--------
 1 file changed, 5 insertions(+), 8 deletions(-)

diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c
index 6721da0ed7bb..263d80c5fc50 100644
--- a/drivers/iio/adc/rockchip_saradc.c
+++ b/drivers/iio/adc/rockchip_saradc.c
@@ -492,10 +492,9 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
 	 */
 	info->reset = devm_reset_control_get_optional_exclusive(&pdev->dev,
 								"saradc-apb");
-	if (IS_ERR(info->reset)) {
-		ret = PTR_ERR(info->reset);
-		return dev_err_probe(&pdev->dev, ret, "failed to get saradc-apb\n");
-	}
+	if (IS_ERR(info->reset))
+		return dev_err_probe(&pdev->dev, PTR_ERR(info->reset),
+				     "failed to get saradc-apb\n");
 
 	init_completion(&info->completion);
 
@@ -505,10 +504,8 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
 
 	ret = devm_request_irq(&pdev->dev, irq, rockchip_saradc_isr,
 			       0, dev_name(&pdev->dev), info);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "failed requesting irq %d\n", irq);
-		return ret;
-	}
+	if (ret < 0)
+		return dev_err_probe(&pdev->dev, ret, "failed requesting irq %d\n", irq);
 
 	info->vref = devm_regulator_get(&pdev->dev, "vref");
 	if (IS_ERR(info->vref))

-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Fri Dec 19 06:31:54 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 15:31:54 +0100
Subject: [PATCH 5/5] iio: adc: sc27xx: Simplify with dev_err_probe
In-Reply-To: <20251219-iio-dev-err-probe-v1-0-bd0fbc83c8a0@oss.qualcomm.com>
References: <20251219-iio-dev-err-probe-v1-0-bd0fbc83c8a0@oss.qualcomm.com>
Message-ID: <20251219-iio-dev-err-probe-v1-5-bd0fbc83c8a0@oss.qualcomm.com>

Use dev_err_probe() to make error code handling simpler and handle
deferred probe nicely (avoid spamming logs).

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/iio/adc/sc27xx_adc.c | 49 +++++++++++++++-----------------------------
 1 file changed, 17 insertions(+), 32 deletions(-)

diff --git a/drivers/iio/adc/sc27xx_adc.c b/drivers/iio/adc/sc27xx_adc.c
index 2535c2c3e60b..6209499c5c37 100644
--- a/drivers/iio/adc/sc27xx_adc.c
+++ b/drivers/iio/adc/sc27xx_adc.c
@@ -867,10 +867,8 @@ static int sc27xx_adc_probe(struct platform_device *pdev)
 	int ret;
 
 	pdata = of_device_get_match_data(dev);
-	if (!pdata) {
-		dev_err(dev, "No matching driver data found\n");
-		return -EINVAL;
-	}
+	if (!pdata)
+		return dev_err_probe(dev, -EINVAL, "No matching driver data found\n");
 
 	indio_dev = devm_iio_device_alloc(dev, sizeof(*sc27xx_data));
 	if (!indio_dev)
@@ -879,56 +877,43 @@ static int sc27xx_adc_probe(struct platform_device *pdev)
 	sc27xx_data = iio_priv(indio_dev);
 
 	sc27xx_data->regmap = dev_get_regmap(dev->parent, NULL);
-	if (!sc27xx_data->regmap) {
-		dev_err(dev, "failed to get ADC regmap\n");
-		return -ENODEV;
-	}
+	if (!sc27xx_data->regmap)
+		return dev_err_probe(dev, -ENODEV, "failed to get ADC regmap\n");
 
 	ret = of_property_read_u32(np, "reg", &sc27xx_data->base);
-	if (ret) {
-		dev_err(dev, "failed to get ADC base address\n");
-		return ret;
-	}
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to get ADC base address\n");
 
 	sc27xx_data->irq = platform_get_irq(pdev, 0);
 	if (sc27xx_data->irq < 0)
 		return sc27xx_data->irq;
 
 	ret = of_hwspin_lock_get_id(np, 0);
-	if (ret < 0) {
-		dev_err(dev, "failed to get hwspinlock id\n");
-		return ret;
-	}
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "failed to get hwspinlock id\n");
 
 	sc27xx_data->hwlock = devm_hwspin_lock_request_specific(dev, ret);
-	if (!sc27xx_data->hwlock) {
-		dev_err(dev, "failed to request hwspinlock\n");
-		return -ENXIO;
-	}
+	if (!sc27xx_data->hwlock)
+		return dev_err_probe(dev, -ENXIO, "failed to request hwspinlock\n");
 
 	sc27xx_data->dev = dev;
 	if (pdata->set_volref) {
 		sc27xx_data->volref = devm_regulator_get(dev, "vref");
-		if (IS_ERR(sc27xx_data->volref)) {
-			ret = PTR_ERR(sc27xx_data->volref);
-			return dev_err_probe(dev, ret, "failed to get ADC volref\n");
-		}
+		if (IS_ERR(sc27xx_data->volref))
+			return dev_err_probe(dev, PTR_ERR(sc27xx_data->volref),
+					     "failed to get ADC volref\n");
 	}
 
 	sc27xx_data->var_data = pdata;
 	sc27xx_data->var_data->init_scale(sc27xx_data);
 
 	ret = sc27xx_adc_enable(sc27xx_data);
-	if (ret) {
-		dev_err(dev, "failed to enable ADC module\n");
-		return ret;
-	}
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to enable ADC module\n");
 
 	ret = devm_add_action_or_reset(dev, sc27xx_adc_disable, sc27xx_data);
-	if (ret) {
-		dev_err(dev, "failed to add ADC disable action\n");
-		return ret;
-	}
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to add ADC disable action\n");
 
 	indio_dev->name = dev_name(dev);
 	indio_dev->modes = INDIO_DIRECT_MODE;

-- 
2.51.0



From krzk at kernel.org  Fri Dec 19 06:45:37 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 15:45:37 +0100
Subject: [PATCH v2 07/11] dt-bindings: clock: qcom: document the Kaanapali
 GPU Clock Controller
In-Reply-To: <701a7b2f-848a-4cc0-8924-ec72155d93a7@oss.qualcomm.com>
References: <20251125-kaanapali-mmcc-v2-v2-0-fb44e78f300b@oss.qualcomm.com>
 <20251125-kaanapali-mmcc-v2-v2-7-fb44e78f300b@oss.qualcomm.com>
 <20251126-elated-stoic-scorpion-25b630@kuoka>
 <de44560d-4ed8-41fe-be7b-56412b933a8c@oss.qualcomm.com>
 <fbe39eac-7c92-4a08-bafb-31e5c51a0613@kernel.org>
 <503f445e-0d12-407d-bc77-f48ad335639b@oss.qualcomm.com>
 <e8bdb176-b6fb-4dd2-8b5b-9da8073fa915@kernel.org>
 <ca118faf-3451-4b83-9074-82bc5e1f731e@oss.qualcomm.com>
 <3e8128f4-3cba-4c13-a846-e5f1638a1e0f@kernel.org>
 <701a7b2f-848a-4cc0-8924-ec72155d93a7@oss.qualcomm.com>
Message-ID: <65e5459b-7509-47db-9089-6efecead3f44@kernel.org>

On 19/12/2025 14:02, Konrad Dybcio wrote:
> On 12/17/25 2:54 PM, Krzysztof Kozlowski wrote:
>> On 17/12/2025 14:21, Konrad Dybcio wrote:
>>> On 12/17/25 11:09 AM, Krzysztof Kozlowski wrote:
>>>> On 17/12/2025 10:32, Taniya Das wrote:
>>>>>>>
>>>>>>> We would like to leverage the existing common clock driver(GDSC) code to
>>>>>>
>>>>>> Fix the driver code if it cannot handle other cells. Your drivers do not
>>>>>> matter for choices made in bindings.
>>>>>>
>>>>>
>>>>> As it is still a clock controller from hardware design and in SW I will
>>>>> be map the entire hardware region and this way this clock controller
>>>>> will also be aligned to the existing clock controllers and keep the
>>>>> #power-domain-cells = <1> as other CCs.
>>>>
>>>> I don't see how this resolves my comment.
>>>
>>> Spanning the entire 0x6000-long block will remove your worry about this
>>> description only being 2-register-wide
>>
>> But that was not the comment here. Taniya replied under comment about
>> cells. We are not discussing here some other things...
> 
> Right, you omitted the part where I answered your comment from the
> context, so I'll re-add it:
> 
> """
> This block provides more than one GDSC - although again, not all of them
> need/should be accessed by Linux. I suppose just enumerating the "extra"
> ones in bindings will be a good enough compromise?
> """
> 
> TLDR: cells=1 makes sense as per usual

Either list them in headers or at least explain that in the binding.

Best regards,
Krzysztof


From konrad.dybcio at oss.qualcomm.com  Fri Dec 19 06:47:07 2025
From: konrad.dybcio at oss.qualcomm.com (Konrad Dybcio)
Date: Fri, 19 Dec 2025 15:47:07 +0100
Subject: [PATCH 3/5] iio: adc: qcom-spmi-rradc: Simplify with
 dev_err_probe
In-Reply-To: <20251219-iio-dev-err-probe-v1-3-bd0fbc83c8a0@oss.qualcomm.com>
References: <20251219-iio-dev-err-probe-v1-0-bd0fbc83c8a0@oss.qualcomm.com>
 <20251219-iio-dev-err-probe-v1-3-bd0fbc83c8a0@oss.qualcomm.com>
Message-ID: <528cf0f7-6025-45de-a061-2d4f6fcc5bce@oss.qualcomm.com>

On 12/19/25 3:31 PM, Krzysztof Kozlowski wrote:
> Use dev_err_probe() to make error code handling simpler.
> 
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
> ---

Reviewed-by: Konrad Dybcio <konrad.dybcio at oss.qualcomm.com>

Konrad


From robh at kernel.org  Fri Dec 19 06:48:46 2025
From: robh at kernel.org (Rob Herring)
Date: Fri, 19 Dec 2025 08:48:46 -0600
Subject: [PATCH] arm64: dts: xilinx: Drop "label" property on dlg,slg7xl45106
In-Reply-To: <29b45cc2-e0df-4411-bfb9-cfe51ec4ec67@amd.com>
References: <20251216175914.2791200-1-robh@kernel.org> <aa064ecf-1714-4d40-8658-19952392cae8@amd.com>
 <CAL_JsqKdrN5UpUWQVQXpJjbTy1gN9_FhhwOoX6zVpG+zZVAptA@mail.gmail.com> <29b45cc2-e0df-4411-bfb9-cfe51ec4ec67@amd.com>
Message-ID: <CAL_JsqLYz8ZyCGGB_NjyrPdq0P-wjeSfwWPxu1kqCo0qbYFgbQ@mail.gmail.com>

On Thu, Dec 18, 2025 at 8:15?AM Michal Simek <michal.simek at amd.com> wrote:
>
>
>
> On 12/17/25 21:41, Rob Herring wrote:
> > On Wed, Dec 17, 2025 at 6:39?AM Michal Simek <michal.simek at amd.com> wrote:
> >> On 12/16/25 18:59, Rob Herring (Arm) wrote:
> >>> The "label" property is not documented for the dlg,slg7xl45106. Nor is
> >>> it common to use for GPIO controllers. So drop it.
> >>>
> >>
> >> Correct it is not documented but it is at least used in Linux also by
> >> drivers/gpio/gpio-mmio.c:810:   err = device_property_read_string(dev, "label",
> >> &label);
> >>
> >> which is also not documented in DT binding.
> >
> > It really should be for all GPIO providers or none of them. IMO, it
> > should be none of them as we already have "gpio-line-names" which is
> > essentially per line labels. I can't see why anyone should care about
> > a label for the controller.
> >
> >> I don't have a problem with it because I can't see it used anywhere.
> >>
> >> But there are other devices where label is the part of binding. And IMHO this
> >> should be more generic property.
> >
> > "label" is the generic property. Not sure what you are suggesting here.
>
> That schema should allow to define label in every node or some class of devices.

I don't care to enable it everywhere. It's allowed in some classes
where the use of it is well defined. I don't think a GPIO provider is
one of those cases.

Rob


From ahmed.tiba at arm.com  Fri Dec 19 06:49:02 2025
From: ahmed.tiba at arm.com (Ahmed Tiba)
Date: Fri, 19 Dec 2025 14:49:02 +0000
Subject: [PATCH 03/12] ras: add estatus vendor handling and processing
In-Reply-To: <20251218170453.23be9049@foz.lan>
Message-ID: <20251219144943.2798169-1-ahmed.tiba@arm.com>


On Wed, Dec 18, 2025 at 05:04:53PM +0100, Mauro Carvalho Chehab wrote:

>> Teach the estatus core how to walk CPER records and expose the vendor
>> record notification path. This adds the section iteration helpers,
>> the logging helpers that mirror the GHES behaviour, and the deferred
>> work used to hand vendor GUIDs to interested drivers. No users switch
>> over yet; this simply moves the common logic out of GHES so the next
>> patches can wire it up.
>>
>> Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>
>
>...
>
>> +static bool estatus_handle_arm_hw_error(estatus_generic_data *gdata, int sev, bool sync)
>
> Huh?
>
> This is a CPER record from GHES. Why are you moving CPER code out
> of ghes.c, placing in a file named estatus.c? Doesn't make much
> sense on my eyes...
>
> Same applies to to other GHES CPER record types.

GHES still fills in the CPER record, but the parsing and logging logic is
shared with the new DeviceTree provider so I pulled those helpers into the
estatus core. Both providers already call into the same notifier chain and
memory-pool helpers; this patch just moves the generic CPER walking routines
next to the rest of the common code so the DT path doesn?t have to grow its
own copy. If you?d prefer a different file layout or naming to make that
intent clearer, I?m happy to adjust.


Thanks,
Ahmed


From guohanjun at huawei.com  Fri Dec 19 06:49:06 2025
From: guohanjun at huawei.com (Hanjun Guo)
Date: Fri, 19 Dec 2025 22:49:06 +0800
Subject: [PATCH] MAINTAINERS: Update the maintainers for ARM64 ACPI
Message-ID: <20251219144906.348353-1-guohanjun@huawei.com>

ARM64 ACPI patches go via ARM64 tree, but the listed maintainers
for ARM64 ACPI don't include Catalin and Will, and there is no
F: line under the ARM64 architecture entry, so emails will not
route to Catalin and Will in an automatic way.

Adding Catalin and Will to the maintainers entry for ARM64 ACPI
to fix the problem, it will make life easy for merging ARM64 ACPI
patches.

Adding new maintainer entries for ARM64 ACPI doesn't mean the review
work will balance to the new maintainer, patches still need to be
acked by currently listed folks (Lorenzo, Hanjun, Sudeep) before
merging them.

Link: https://lore.kernel.org/linux-acpi/aS2ZTfS9YVO98Exe at willie-the-truck/
Signed-off-by: Hanjun Guo <guohanjun at huawei.com>
---
 MAINTAINERS | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 5b11839cba9d..6050d94a50ec 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -335,6 +335,8 @@ ACPI FOR ARM64 (ACPI/arm64)
 M:	Lorenzo Pieralisi <lpieralisi at kernel.org>
 M:	Hanjun Guo <guohanjun at huawei.com>
 M:	Sudeep Holla <sudeep.holla at arm.com>
+M:	Catalin Marinas <catalin.marinas at arm.com>
+M:	Will Deacon <will at kernel.org>
 L:	linux-acpi at vger.kernel.org
 L:	linux-arm-kernel at lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
-- 
2.25.1



From shawn.lin at rock-chips.com  Fri Dec 19 06:51:47 2025
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 19 Dec 2025 22:51:47 +0800
Subject: [PATCH 4/5] iio: adc: rockchip: Simplify with dev_err_probe
In-Reply-To: <20251219-iio-dev-err-probe-v1-4-bd0fbc83c8a0@oss.qualcomm.com>
References: <20251219-iio-dev-err-probe-v1-0-bd0fbc83c8a0@oss.qualcomm.com>
 <20251219-iio-dev-err-probe-v1-4-bd0fbc83c8a0@oss.qualcomm.com>
Message-ID: <1ca8f181-7784-469a-b498-622a39737e1e@rock-chips.com>

? 2025/12/19 ??? 22:31, Krzysztof Kozlowski ??:
> Use dev_err_probe() to make error code handling simpler and handle
> deferred probe nicely (avoid spamming logs).
> 

Reviewed-by: Shawn Lin <shawn.lin at rock-chips.com>

> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
> ---
>   drivers/iio/adc/rockchip_saradc.c | 13 +++++--------
>   1 file changed, 5 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c
> index 6721da0ed7bb..263d80c5fc50 100644
> --- a/drivers/iio/adc/rockchip_saradc.c
> +++ b/drivers/iio/adc/rockchip_saradc.c
> @@ -492,10 +492,9 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
>   	 */
>   	info->reset = devm_reset_control_get_optional_exclusive(&pdev->dev,
>   								"saradc-apb");
> -	if (IS_ERR(info->reset)) {
> -		ret = PTR_ERR(info->reset);
> -		return dev_err_probe(&pdev->dev, ret, "failed to get saradc-apb\n");
> -	}
> +	if (IS_ERR(info->reset))
> +		return dev_err_probe(&pdev->dev, PTR_ERR(info->reset),
> +				     "failed to get saradc-apb\n");
>   
>   	init_completion(&info->completion);
>   
> @@ -505,10 +504,8 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
>   
>   	ret = devm_request_irq(&pdev->dev, irq, rockchip_saradc_isr,
>   			       0, dev_name(&pdev->dev), info);
> -	if (ret < 0) {
> -		dev_err(&pdev->dev, "failed requesting irq %d\n", irq);
> -		return ret;
> -	}
> +	if (ret < 0)
> +		return dev_err_probe(&pdev->dev, ret, "failed requesting irq %d\n", irq);
>   
>   	info->vref = devm_regulator_get(&pdev->dev, "vref");
>   	if (IS_ERR(info->vref))
> 



From andre.draszik at linaro.org  Fri Dec 19 06:53:58 2025
From: andre.draszik at linaro.org (=?ISO-8859-1?Q?Andr=E9?= Draszik)
Date: Fri, 19 Dec 2025 14:53:58 +0000
Subject: [PATCH v3 1/6] soc: samsung: exynos-chipid: use devm action to
 unregister soc device
In-Reply-To: <20251120-gs101-chipid-v3-1-1aeaa8b7fe35@linaro.org>
References: <20251120-gs101-chipid-v3-0-1aeaa8b7fe35@linaro.org>
	 <20251120-gs101-chipid-v3-1-1aeaa8b7fe35@linaro.org>
Message-ID: <5b366a0c0d7f4dcb6a3daa793ec503a43ea754b4.camel@linaro.org>

On Thu, 2025-11-20 at 11:29 +0000, Tudor Ambarus wrote:
> Simplify the unwinding of the soc device by using a devm action.
> Add the action before the exynos_asv_init() to avoid an explicit call
> to soc_device_unregister().
> 
> Signed-off-by: Tudor Ambarus <tudor.ambarus at linaro.org>
> ---
> ?drivers/soc/samsung/exynos-chipid.c | 28 ++++++++++++----------------
> ?1 file changed, 12 insertions(+), 16 deletions(-)

Reviewed-by: Andr? Draszik <andre.draszik at linaro.org>


From andre.draszik at linaro.org  Fri Dec 19 06:57:13 2025
From: andre.draszik at linaro.org (=?ISO-8859-1?Q?Andr=E9?= Draszik)
Date: Fri, 19 Dec 2025 14:57:13 +0000
Subject: [PATCH v3 2/6] soc: samsung: exynos-chipid: use dev_err_probe
 where appropiate
In-Reply-To: <20251120-gs101-chipid-v3-2-1aeaa8b7fe35@linaro.org>
References: <20251120-gs101-chipid-v3-0-1aeaa8b7fe35@linaro.org>
	 <20251120-gs101-chipid-v3-2-1aeaa8b7fe35@linaro.org>
Message-ID: <da80f729ae5c8899181f3b35b0f30b59f11535a8.camel@linaro.org>

On Thu, 2025-11-20 at 11:29 +0000, Tudor Ambarus wrote:
> Use dev_err_probe() to benefit of the standardized format of the error
> code (e.g. "ENODEV" instead of -19), to get meanigful error messages, and
> for more compact error paths.
> 
> Signed-off-by: Tudor Ambarus <tudor.ambarus at linaro.org>
> ---
> ?drivers/soc/samsung/exynos-chipid.c | 26 ++++++++++++++------------
> ?1 file changed, 14 insertions(+), 12 deletions(-)

Reviewed-by: Andr? Draszik <andre.draszik at linaro.org>


From andre.draszik at linaro.org  Fri Dec 19 06:58:13 2025
From: andre.draszik at linaro.org (=?ISO-8859-1?Q?Andr=E9?= Draszik)
Date: Fri, 19 Dec 2025 14:58:13 +0000
Subject: [PATCH v3 4/6] soc: samsung: exynos-chipid: downgrade dev_info
 to dev_dbg for soc info
In-Reply-To: <20251120-gs101-chipid-v3-4-1aeaa8b7fe35@linaro.org>
References: <20251120-gs101-chipid-v3-0-1aeaa8b7fe35@linaro.org>
	 <20251120-gs101-chipid-v3-4-1aeaa8b7fe35@linaro.org>
Message-ID: <cda2b1668fd30cdabc9a0d722319fec4e0706c50.camel@linaro.org>

On Thu, 2025-11-20 at 11:29 +0000, Tudor Ambarus wrote:
> The SoC information is exposed to userspace using the standard soc
> interface. Downgrade to dev_dbg to stop polluting the console log.
> 
> Signed-off-by: Tudor Ambarus <tudor.ambarus at linaro.org>
> ---
> ?drivers/soc/samsung/exynos-chipid.c | 4 ++--
> ?1 file changed, 2 insertions(+), 2 deletions(-)

Reviewed-by: Andr? Draszik <andre.draszik at linaro.org>


From andre.draszik at linaro.org  Fri Dec 19 07:10:04 2025
From: andre.draszik at linaro.org (=?ISO-8859-1?Q?Andr=E9?= Draszik)
Date: Fri, 19 Dec 2025 15:10:04 +0000
Subject: [PATCH v3 5/6] soc: samsung: exynos-chipid: add
 google,gs101-otp support
In-Reply-To: <20251120-gs101-chipid-v3-5-1aeaa8b7fe35@linaro.org>
References: <20251120-gs101-chipid-v3-0-1aeaa8b7fe35@linaro.org>
	 <20251120-gs101-chipid-v3-5-1aeaa8b7fe35@linaro.org>
Message-ID: <653202f78f060b7e001b78604dd26d0f18ab76f9.camel@linaro.org>

On Thu, 2025-11-20 at 11:29 +0000, Tudor Ambarus wrote:
> GS101 is different (but also e850 and autov9 I assume) from the SoCs
> that are currently handled by the exynos-chipid driver because the
> chip ID info is part of the OTP registers. GS101 OTP has a clock, an
> interrupt line, a register space (that contains product and chip ID,
> TMU data, ASV, etc) and a 32Kbit memory space that can be
> read/program/locked with specific commands. On GS101 the "ChipID block"
> is just an abstraction, it's not a physical device. When the power-on
> sequence progresses, the OTP chipid values are loaded to the OTP
> registers.
> 
> Add the GS101 chip ID support. The support is intentionally added in the
> exynos-chipid driver, and not in a dedicated Exynos OTP driver, because
> we estimate that there will not be any OTP consumers in the kernel other
> than the chip ID/SoC interface. The downstream GS101 drivers confirm
> this supposition.
> 
> Signed-off-by: Tudor Ambarus <tudor.ambarus at linaro.org>
> ---
> ?drivers/soc/samsung/exynos-chipid.c | 87 ++++++++++++++++++++++++++++++++-----
> ?1 file changed, 75 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c
> index 5c8660374269c87ec38ebca242918bd7b1d362e5..06eb6ef8740d3f58eda52c8e71cf40074d2deb1f 100644
> --- a/drivers/soc/samsung/exynos-chipid.c
> +++ b/drivers/soc/samsung/exynos-chipid.c
> @@ -13,9 +13,11 @@
> ? */
> ?
> ?#include <linux/array_size.h>
> +#include <linux/clk.h>
> ?#include <linux/device.h>
> ?#include <linux/device/devres.h>
> -#include <linux/errno.h>
> +#include <linux/err.h>
> +#include <linux/ioport.h>
> ?#include <linux/mfd/syscon.h>
> ?#include <linux/module.h>
> ?#include <linux/of.h>
> @@ -28,9 +30,11 @@
> ?#include "exynos-asv.h"
> ?
> ?struct exynos_chipid_variant {
> -	unsigned int rev_reg;		/* revision register offset */
> +	unsigned int main_rev_reg;	/* main revision register offset */
> +	unsigned int sub_rev_reg;	/* sub revision register offset */
> ?	unsigned int main_rev_shift;	/* main revision offset in rev_reg */
> ?	unsigned int sub_rev_shift;	/* sub revision offset in rev_reg */
> +	bool efuse;
> ?};
> ?
> ?struct exynos_chipid_info {
> @@ -69,6 +73,8 @@ static const struct exynos_soc_id {
> ?	{ "EXYNOS990", 0xE9830000 },
> ?	{ "EXYNOSAUTOV9", 0xAAA80000 },
> ?	{ "EXYNOSAUTOV920", 0x0A920000 },
> +	/* Compatible with: google,gs101-otp */
> +	{ "GS101", 0x9845000 },
> ?};
> ?
> ?static const char *exynos_product_id_to_name(unsigned int product_id)
> @@ -93,19 +99,53 @@ static int exynos_chipid_get_chipid_info(struct device *dev,
> ?		return dev_err_probe(dev, ret, "failed to read Product ID\n");
> ?	soc_info->product_id = val & EXYNOS_MASK;
> ?
> -	if (data->rev_reg != EXYNOS_CHIPID_REG_PRO_ID) {
> -		ret = regmap_read(regmap, data->rev_reg, &val);
> +	if (data->sub_rev_reg == EXYNOS_CHIPID_REG_PRO_ID) {
> +		/* exynos4210 case */
> +		main_rev = (val >> data->main_rev_shift) & EXYNOS_REV_PART_MASK;
> +		sub_rev = (val >> data->sub_rev_shift) & EXYNOS_REV_PART_MASK;
> +	} else {
> +		unsigned int val2;
> +
> +		ret = regmap_read(regmap, data->sub_rev_reg, &val2);
> ?		if (ret < 0)
> ?			return dev_err_probe(dev, ret,
> ?					???? "failed to read revision\n");
> +
> +		if (data->main_rev_reg == EXYNOS_CHIPID_REG_PRO_ID)
> +			/* gs101 case */
> +			main_rev = (val >> data->main_rev_shift) & EXYNOS_REV_PART_MASK;
> +		else
> +			/* exynos850 case */
> +			main_rev = (val2 >> data->main_rev_shift) & EXYNOS_REV_PART_MASK;
> +
> +		sub_rev = (val2 >> data->sub_rev_shift) & EXYNOS_REV_PART_MASK;

The above looks a little fragile, comparing register offsets between different
hardware platforms and macros, but I guess it works for now and isn't really
much different to before.

> ?	}
> -	main_rev = (val >> data->main_rev_shift) & EXYNOS_REV_PART_MASK;
> -	sub_rev = (val >> data->sub_rev_shift) & EXYNOS_REV_PART_MASK;
> +
> ?	soc_info->revision = (main_rev << EXYNOS_REV_PART_SHIFT) | sub_rev;
> ?
> ?	return 0;
> ?}
> ?
> +static struct regmap *exynos_chipid_get_efuse_regmap(struct platform_device *pdev)
> +{
> +	struct resource *res;
> +	void __iomem *base;
> +
> +	base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
> +	if (IS_ERR(base))
> +		return ERR_CAST(base);
> +
> +	const struct regmap_config reg_config = {
> +		.reg_bits = 32,
> +		.reg_stride = 4,
> +		.val_bits = 32,
> +		.use_relaxed_mmio = true,
> +		.max_register = (resource_size(res) - reg_config.reg_stride),
> +	};
> +
> +	return devm_regmap_init_mmio(&pdev->dev, base, &reg_config);
> +}
> +
> ?static void exynos_chipid_unregister_soc(void *data)
> ?{
> ?	soc_device_unregister(data);
> @@ -127,10 +167,24 @@ static int exynos_chipid_probe(struct platform_device *pdev)
> ?		return dev_err_probe(dev, -EINVAL,
> ?				???? "failed to get match data\n");
> ?
> -	regmap = device_node_to_regmap(dev->of_node);
> -	if (IS_ERR(regmap))
> -		return dev_err_probe(dev, PTR_ERR(regmap),
> -				???? "failed to get regmap\n");
> +	if (drv_data->efuse) {
> +		struct clk *clk;
> +
> +		regmap = exynos_chipid_get_efuse_regmap(pdev);
> +		if (IS_ERR(regmap))
> +			return dev_err_probe(dev, PTR_ERR(regmap),
> +					???? "failed to get efuse regmap\n");
> +
> +		clk = devm_clk_get_enabled(dev, NULL);
> +		if (IS_ERR(clk))
> +			return dev_err_probe(dev, PTR_ERR(clk),
> +					???? "failed to get clock\n");

Could you use devm_regmap_init_mmio_clk() instead?

Cheers,
Andre'

> +	} else {
> +		regmap = device_node_to_regmap(dev->of_node);
> +		if (IS_ERR(regmap))
> +			return dev_err_probe(dev, PTR_ERR(regmap),
> +					???? "failed to get regmap\n");
> +	}
> ?
> ?	ret = exynos_chipid_get_chipid_info(dev, regmap, drv_data, &soc_info);
> ?	if (ret < 0)
> @@ -177,19 +231,28 @@ static int exynos_chipid_probe(struct platform_device *pdev)
> ?}
> ?
> ?static const struct exynos_chipid_variant exynos4210_chipid_drv_data = {
> -	.rev_reg	= 0x0,
> ?	.main_rev_shift	= 4,
> ?	.sub_rev_shift	= 0,
> ?};
> ?
> ?static const struct exynos_chipid_variant exynos850_chipid_drv_data = {
> -	.rev_reg	= 0x10,
> +	.main_rev_reg	= 0x10,
> +	.sub_rev_reg	= 0x10,
> ?	.main_rev_shift	= 20,
> ?	.sub_rev_shift	= 16,
> ?};
> ?
> +static const struct exynos_chipid_variant gs101_chipid_drv_data = {
> +	.sub_rev_reg	= 0x10,
> +	.sub_rev_shift	= 16,
> +	.efuse = true,
> +};
> +
> ?static const struct of_device_id exynos_chipid_of_device_ids[] = {
> ?	{
> +		.compatible	= "google,gs101-otp",
> +		.data		= &gs101_chipid_drv_data,
> +	}, {
> ?		.compatible	= "samsung,exynos4210-chipid",
> ?		.data		= &exynos4210_chipid_drv_data,
> ?	}, {


From linux at fw-web.de  Fri Dec 19 07:12:10 2025
From: linux at fw-web.de (Frank Wunderlich)
Date: Fri, 19 Dec 2025 16:12:10 +0100
Subject: [RFC net-next v5 1/3] net: ethernet: mtk_eth_soc: Add register definitions for RSS and LRO
In-Reply-To: <20251219151219.77115-1-linux@fw-web.de>
References: <20251219151219.77115-1-linux@fw-web.de>
Message-ID: <20251219151219.77115-2-linux@fw-web.de>

From: Mason Chang <mason-cw.chang at mediatek.com>

Add definitions for Receive Side Scaling and Large Receive Offload support.

Signed-off-by: Mason Chang <mason-cw.chang at mediatek.com>
Signed-off-by: Frank Wunderlich <frank-w at public-files.de>
---
 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 23 +++++++++++++++
 drivers/net/ethernet/mediatek/mtk_eth_soc.h | 32 +++++++++++++++------
 2 files changed, 46 insertions(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index e68997a29191..243ff16fd15e 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -50,13 +50,18 @@ static const struct mtk_reg_map mtk_reg_map = {
 		.rx_ptr		= 0x0900,
 		.rx_cnt_cfg	= 0x0904,
 		.pcrx_ptr	= 0x0908,
+		.lro_ctrl_dw0   = 0x0980,
 		.glo_cfg	= 0x0a04,
 		.rst_idx	= 0x0a08,
 		.delay_irq	= 0x0a0c,
 		.irq_status	= 0x0a20,
 		.irq_mask	= 0x0a28,
 		.adma_rx_dbg0	= 0x0a38,
+		.lro_alt_score_delta	= 0x0a4c,
 		.int_grp	= 0x0a50,
+		.lro_rx1_dly_int	= 0x0a70,
+		.lro_ring_dip_dw0	= 0x0b04,
+		.lro_ring_ctrl_dw1	= 0x0b28,
 	},
 	.qdma = {
 		.qtx_cfg	= 0x1800,
@@ -113,6 +118,7 @@ static const struct mtk_reg_map mt7986_reg_map = {
 	.tx_irq_mask		= 0x461c,
 	.tx_irq_status		= 0x4618,
 	.pdma = {
+		.rss_glo_cfg    = 0x2800,
 		.rx_ptr		= 0x4100,
 		.rx_cnt_cfg	= 0x4104,
 		.pcrx_ptr	= 0x4108,
@@ -123,6 +129,12 @@ static const struct mtk_reg_map mt7986_reg_map = {
 		.irq_mask	= 0x4228,
 		.adma_rx_dbg0	= 0x4238,
 		.int_grp	= 0x4250,
+		.int_grp3	= 0x422c,
+		.lro_ctrl_dw0	= 0x4180,
+		.lro_alt_score_delta	= 0x424c,
+		.lro_rx1_dly_int	= 0x4270,
+		.lro_ring_dip_dw0	= 0x4304,
+		.lro_ring_ctrl_dw1	= 0x4328,
 	},
 	.qdma = {
 		.qtx_cfg	= 0x4400,
@@ -170,10 +182,21 @@ static const struct mtk_reg_map mt7988_reg_map = {
 		.glo_cfg	= 0x6a04,
 		.rst_idx	= 0x6a08,
 		.delay_irq	= 0x6a0c,
+		.rx_cfg		= 0x6a10,
 		.irq_status	= 0x6a20,
 		.irq_mask	= 0x6a28,
 		.adma_rx_dbg0	= 0x6a38,
 		.int_grp	= 0x6a50,
+		.int_grp3	= 0x6a58,
+		.tx_delay_irq	= 0x6ab0,
+		.rx_delay_irq	= 0x6ac0,
+		.lro_ctrl_dw0	= 0x6c08,
+		.lro_alt_score_delta	= 0x6c1c,
+		.lro_ring_dip_dw0	= 0x6c14,
+		.lro_ring_ctrl_dw1	= 0x6c38,
+		.lro_alt_dbg	= 0x6c40,
+		.lro_alt_dbg_data	= 0x6c44,
+		.rss_glo_cfg	= 0x7000,
 	},
 	.qdma = {
 		.qtx_cfg	= 0x4400,
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index 0168e2fbc619..334625814b97 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -1143,16 +1143,30 @@ struct mtk_reg_map {
 	u32	tx_irq_mask;
 	u32	tx_irq_status;
 	struct {
-		u32	rx_ptr;		/* rx base pointer */
-		u32	rx_cnt_cfg;	/* rx max count configuration */
-		u32	pcrx_ptr;	/* rx cpu pointer */
-		u32	glo_cfg;	/* global configuration */
-		u32	rst_idx;	/* reset index */
-		u32	delay_irq;	/* delay interrupt */
-		u32	irq_status;	/* interrupt status */
-		u32	irq_mask;	/* interrupt mask */
+		u32	rx_ptr;			/* rx base pointer */
+		u32	rx_cnt_cfg;		/* rx max count configuration */
+		u32	pcrx_ptr;		/* rx cpu pointer */
+		u32	pdrx_ptr;		/* rx dma pointer */
+		u32	glo_cfg;		/* global configuration */
+		u32	rst_idx;		/* reset index */
+		u32	rx_cfg;			/* rx dma configuration */
+		u32	delay_irq;		/* delay interrupt */
+		u32	irq_status;		/* interrupt status */
+		u32	irq_mask;		/* interrupt mask */
 		u32	adma_rx_dbg0;
-		u32	int_grp;
+		u32	int_grp;		/* interrupt group1 */
+		u32	int_grp3;		/* interrupt group3 */
+		u32	tx_delay_irq;		/* tx delay interrupt */
+		u32	rx_delay_irq;		/* rx delay interrupt */
+		u32	lro_ctrl_dw0;		/* lro ctrl dword0 */
+		u32	lro_alt_score_delta;	/* lro auto-learn score delta */
+		u32	lro_rx1_dly_int;	/* lro rx ring1 delay interrupt */
+		u32	lro_ring_dip_dw0;	/* lro ring dip dword0 */
+		u32	lro_ring_ctrl_dw1;	/* lro ring ctrl dword1 */
+		u32	lro_alt_dbg;		/* lro auto-learn debug */
+		u32	lro_alt_dbg_data;	/* lro auto-learn debug data */
+		u32	rss_glo_cfg;		/* rss global configuration */
+
 	} pdma;
 	struct {
 		u32	qtx_cfg;	/* tx queue configuration */
-- 
2.43.0



From linux at fw-web.de  Fri Dec 19 07:12:09 2025
From: linux at fw-web.de (Frank Wunderlich)
Date: Fri, 19 Dec 2025 16:12:09 +0100
Subject: [RFC net-next v5 0/3] Add RSS and LRO support
Message-ID: <20251219151219.77115-1-linux@fw-web.de>

From: Frank Wunderlich <frank-w at public-files.de>

This series add RSS and LRO hardware acceleration for terminating
traffic on MT798x.

It is currently only for discussion to get the upported SDK driver
changes in a good shape.

patches are upported from mtk SDK:
- https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/refs/heads/master/master/files/target/linux/mediatek/patches-6.12/999-eth-08-mtk_eth_soc-add-register-definitions-for-rss-lro-reg.patch
- https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/refs/heads/master/master/files/target/linux/mediatek/patches-6.12/999-eth-09-mtk_eth_soc-add-rss-support.patch
- https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/refs/heads/master/master/files/target/linux/mediatek/patches-6.12/999-eth-10-mtk_eth_soc-add-hw-lro-support.patch
with additional fixes

changes:
v5:
- fix too long lines after macro changes reported by checkpatch

v4:
- drop unrelated file
- rss-changes suggested by andrew
  - fix MTK_HW_LRO_RING_NUM macro (add eth)
  - fix MTK_LRO_CTRL_DW[123]_CFG (add reg_map param)
  - fix MTK_RX_DONE_INT (add eth param)
- fix lro reverse christmas tree and LRO params suggested by andrew
- drop mtk_hwlro_stats_ebl and unused IS_HW_LRO_RING (only used in
  properitary debugfs)

v3:
- readded the change dropped in v2 because it was a fix
  for getting RSS working on mt7986
- changes requested by jakub
- reworked coverletter (dropped instructions for configuration)
- name all PDMA-IRQ the same way
- retested on
  - BPI-R3/mt7986 (RSS needs to be enabled)
  - BPI-R4/mt7988
  - BPI-R64/mt7622 and BPI-R2/mt7623 for not breaking network functionality

v2:
- drop wrong change (MTK_CDMP_IG_CTRL is only netsys v1)
- Fix immutable string IRQ setup (thx to Emilia Schotte)
- drop links to 6.6 patches/commits in sdk in comments

Mason Chang (3):
  net: ethernet: mtk_eth_soc: Add register definitions for RSS and LRO
  net: ethernet: mtk_eth_soc: Add RSS support
  net: ethernet: mtk_eth_soc: Add LRO support

 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 812 ++++++++++++++++----
 drivers/net/ethernet/mediatek/mtk_eth_soc.h | 173 +++--
 2 files changed, 778 insertions(+), 207 deletions(-)

-- 
2.43.0



From linux at fw-web.de  Fri Dec 19 07:12:12 2025
From: linux at fw-web.de (Frank Wunderlich)
Date: Fri, 19 Dec 2025 16:12:12 +0100
Subject: [RFC net-next v5 3/3] net: ethernet: mtk_eth_soc: Add LRO support
In-Reply-To: <20251219151219.77115-1-linux@fw-web.de>
References: <20251219151219.77115-1-linux@fw-web.de>
Message-ID: <20251219151219.77115-4-linux@fw-web.de>

From: Mason Chang <mason-cw.chang at mediatek.com>

Add Large Receive Offload support to mediatek ethernet driver and
activate it for MT7988.

Signed-off-by: Mason Chang <mason-cw.chang at mediatek.com>
Signed-off-by: Frank Wunderlich <frank-w at public-files.de>
---
v5:
- fix too long lines reported by checkpatch
  MTK_LRO_RING_RELINQUISH_REQ
  MTK_LRO_RING_RELINQUISH_DONE
  irq handling (MTK_HW_LRO_IRQ + MTK_HW_LRO_RING)

v4:
- fix lro reverse christmas tree and LRO params suggested by andrew
- drop mtk_hwlro_stats_ebl and unused IS_HW_LRO_RING (only used in
  properitary debugfs)

v2:
- drop link to commit for 6.6 patch
---
 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 247 +++++++++++++++++---
 drivers/net/ethernet/mediatek/mtk_eth_soc.h |  49 ++--
 2 files changed, 240 insertions(+), 56 deletions(-)

diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 4dfff59a3c8a..ae53b5d2787f 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -2772,7 +2772,7 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag)
 
 	if (rx_flag == MTK_RX_FLAGS_HWLRO) {
 		rx_data_len = MTK_MAX_LRO_RX_LENGTH;
-		rx_dma_size = MTK_HW_LRO_DMA_SIZE;
+		rx_dma_size = MTK_HW_LRO_DMA_SIZE(eth);
 	} else {
 		rx_data_len = ETH_DATA_LEN;
 		rx_dma_size = soc->rx.dma_size;
@@ -2785,7 +2785,7 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag)
 	if (!ring->data)
 		return -ENOMEM;
 
-	if (mtk_page_pool_enabled(eth)) {
+	if (mtk_page_pool_enabled(eth) && rcu_access_pointer(eth->prog))  {
 		struct page_pool *pp;
 
 		pp = mtk_create_page_pool(eth, &ring->xdp_q, ring_no,
@@ -2931,10 +2931,11 @@ static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring, bool in_
 
 static int mtk_hwlro_rx_init(struct mtk_eth *eth)
 {
-	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
-	int i;
 	u32 ring_ctrl_dw1 = 0, ring_ctrl_dw2 = 0, ring_ctrl_dw3 = 0;
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
+	const struct mtk_soc_data *soc = eth->soc;
 	u32 lro_ctrl_dw0 = 0, lro_ctrl_dw3 = 0;
+	int i, val;
 
 	/* set LRO rings to auto-learn modes */
 	ring_ctrl_dw2 |= MTK_RING_AUTO_LERAN_MODE;
@@ -2953,30 +2954,44 @@ static int mtk_hwlro_rx_init(struct mtk_eth *eth)
 	ring_ctrl_dw2 |= MTK_RING_MAX_AGG_CNT_L;
 	ring_ctrl_dw3 |= MTK_RING_MAX_AGG_CNT_H;
 
-	for (i = 1; i < MTK_MAX_RX_RING_NUM; i++) {
+	for (i = 1; i <= MTK_HW_LRO_RING_NUM(eth); i++) {
 		mtk_w32(eth, ring_ctrl_dw1, MTK_LRO_CTRL_DW1_CFG(reg_map, i));
 		mtk_w32(eth, ring_ctrl_dw2, MTK_LRO_CTRL_DW2_CFG(reg_map, i));
 		mtk_w32(eth, ring_ctrl_dw3, MTK_LRO_CTRL_DW3_CFG(reg_map, i));
 	}
 
 	/* IPv4 checksum update enable */
-	lro_ctrl_dw0 |= MTK_L3_CKS_UPD_EN;
+	lro_ctrl_dw0 |= MTK_L3_CKS_UPD_EN(eth);
 
 	/* switch priority comparison to packet count mode */
 	lro_ctrl_dw0 |= MTK_LRO_ALT_PKT_CNT_MODE;
 
 	/* bandwidth threshold setting */
-	mtk_w32(eth, MTK_HW_LRO_BW_THRE, MTK_PDMA_LRO_CTRL_DW2);
+	mtk_w32(eth, MTK_HW_LRO_BW_THRE, MTK_PDMA_LRO_CTRL_DW2(reg_map));
 
 	/* auto-learn score delta setting */
-	mtk_w32(eth, MTK_HW_LRO_REPLACE_DELTA, MTK_PDMA_LRO_ALT_SCORE_DELTA);
+	mtk_w32(eth, MTK_HW_LRO_REPLACE_DELTA, MTK_PDMA_LRO_ALT_SCORE_DELTA(reg_map));
 
 	/* set refresh timer for altering flows to 1 sec. (unit: 20us) */
 	mtk_w32(eth, (MTK_HW_LRO_TIMER_UNIT << 16) | MTK_HW_LRO_REFRESH_TIME,
 		MTK_PDMA_LRO_ALT_REFRESH_TIMER);
 
-	/* set HW LRO mode & the max aggregation count for rx packets */
-	lro_ctrl_dw3 |= MTK_ADMA_MODE | (MTK_HW_LRO_MAX_AGG_CNT & 0xff);
+	if (mtk_is_netsys_v3_or_greater(eth)) {
+		val = mtk_r32(eth, reg_map->pdma.rx_cfg);
+		mtk_w32(eth, val | ((MTK_PDMA_LRO_SDL + MTK_MAX_RX_LENGTH) <<
+			MTK_RX_CFG_SDL_OFFSET), reg_map->pdma.rx_cfg);
+
+		lro_ctrl_dw0 |= MTK_PDMA_LRO_SDL << MTK_CTRL_DW0_SDL_OFFSET;
+
+		/* enable cpu reason black list */
+		lro_ctrl_dw0 |= MTK_LRO_CRSN_BNW(eth);
+
+		/* no use PPE cpu reason */
+		mtk_w32(eth, 0xffffffff, MTK_PDMA_LRO_CTRL_DW1(reg_map));
+	} else {
+		/* set HW LRO mode & the max aggregation count for rx packets */
+		lro_ctrl_dw3 |= MTK_ADMA_MODE | (MTK_HW_LRO_MAX_AGG_CNT & 0xff);
+	}
 
 	/* the minimal remaining room of SDL0 in RXD for lro aggregation */
 	lro_ctrl_dw3 |= MTK_LRO_MIN_RXD_SDL;
@@ -2984,8 +2999,19 @@ static int mtk_hwlro_rx_init(struct mtk_eth *eth)
 	/* enable HW LRO */
 	lro_ctrl_dw0 |= MTK_LRO_EN;
 
-	mtk_w32(eth, lro_ctrl_dw3, MTK_PDMA_LRO_CTRL_DW3);
-	mtk_w32(eth, lro_ctrl_dw0, MTK_PDMA_LRO_CTRL_DW0);
+	mtk_w32(eth, lro_ctrl_dw3, MTK_PDMA_LRO_CTRL_DW3(reg_map));
+	mtk_w32(eth, lro_ctrl_dw0, MTK_PDMA_LRO_CTRL_DW0(reg_map));
+
+	if (mtk_is_netsys_v2_or_greater(eth)) {
+		i = (soc->rx.desc_size == sizeof(struct mtk_rx_dma_v2)) ? 1 : 0;
+		mtk_m32(eth, MTK_RX_DONE_INT(eth, MTK_HW_LRO_RING(eth, i)),
+			MTK_RX_DONE_INT(eth, MTK_HW_LRO_RING(eth, i)), reg_map->pdma.int_grp);
+		mtk_m32(eth, MTK_RX_DONE_INT(eth, MTK_HW_LRO_RING(eth, i + 1)),
+			MTK_RX_DONE_INT(eth, MTK_HW_LRO_RING(eth, i + 1)),
+			reg_map->pdma.int_grp + 0x4);
+		mtk_m32(eth, MTK_RX_DONE_INT(eth, MTK_HW_LRO_RING(eth, i + 2)),
+			MTK_RX_DONE_INT(eth, MTK_HW_LRO_RING(eth, i + 2)), reg_map->pdma.int_grp3);
+	}
 
 	return 0;
 }
@@ -2993,16 +3019,16 @@ static int mtk_hwlro_rx_init(struct mtk_eth *eth)
 static void mtk_hwlro_rx_uninit(struct mtk_eth *eth)
 {
 	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
-	int i;
 	u32 val;
+	int i;
 
 	/* relinquish lro rings, flush aggregated packets */
-	mtk_w32(eth, MTK_LRO_RING_RELINQUISH_REQ, MTK_PDMA_LRO_CTRL_DW0);
+	mtk_w32(eth, MTK_LRO_RING_RELINQUISH_REQ(eth), MTK_PDMA_LRO_CTRL_DW0(reg_map));
 
 	/* wait for relinquishments done */
 	for (i = 0; i < 10; i++) {
-		val = mtk_r32(eth, MTK_PDMA_LRO_CTRL_DW0);
-		if (val & MTK_LRO_RING_RELINQUISH_DONE) {
+		val = mtk_r32(eth, MTK_PDMA_LRO_CTRL_DW0(reg_map));
+		if (val & MTK_LRO_RING_RELINQUISH_DONE(eth)) {
 			msleep(20);
 			continue;
 		}
@@ -3010,11 +3036,11 @@ static void mtk_hwlro_rx_uninit(struct mtk_eth *eth)
 	}
 
 	/* invalidate lro rings */
-	for (i = 1; i < MTK_MAX_RX_RING_NUM; i++)
+	for (i = 1; i <= MTK_HW_LRO_RING_NUM(eth); i++)
 		mtk_w32(eth, 0, MTK_LRO_CTRL_DW2_CFG(reg_map, i));
 
 	/* disable HW LRO */
-	mtk_w32(eth, 0, MTK_PDMA_LRO_CTRL_DW0);
+	mtk_w32(eth, 0, MTK_PDMA_LRO_CTRL_DW0(reg_map));
 }
 
 static void mtk_hwlro_val_ipaddr(struct mtk_eth *eth, int idx, __be32 ip)
@@ -3027,7 +3053,7 @@ static void mtk_hwlro_val_ipaddr(struct mtk_eth *eth, int idx, __be32 ip)
 	/* invalidate the IP setting */
 	mtk_w32(eth, (reg_val & ~MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(reg_map, idx));
 
-	mtk_w32(eth, ip, MTK_LRO_DIP_DW0_CFG(idx));
+	mtk_w32(eth, ip, MTK_LRO_DIP_DW0_CFG(reg_map, idx));
 
 	/* validate the IP setting */
 	mtk_w32(eth, (reg_val | MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(reg_map, idx));
@@ -3043,7 +3069,7 @@ static void mtk_hwlro_inval_ipaddr(struct mtk_eth *eth, int idx)
 	/* invalidate the IP setting */
 	mtk_w32(eth, (reg_val & ~MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(reg_map, idx));
 
-	mtk_w32(eth, 0, MTK_LRO_DIP_DW0_CFG(idx));
+	mtk_w32(eth, 0, MTK_LRO_DIP_DW0_CFG(reg_map, idx));
 }
 
 static int mtk_hwlro_get_ip_cnt(struct mtk_mac *mac)
@@ -3059,6 +3085,65 @@ static int mtk_hwlro_get_ip_cnt(struct mtk_mac *mac)
 	return cnt;
 }
 
+static int mtk_hwlro_add_ipaddr_idx(struct net_device *dev, u32 ip4dst)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	const struct mtk_reg_map *reg_map;
+	struct mtk_eth *eth = mac->hw;
+	u32 reg_val;
+	int i;
+
+	reg_map = eth->soc->reg_map;
+
+	/* check for duplicate IP address in the current DIP list */
+	for (i = 1; i <= MTK_HW_LRO_DIP_NUM(eth); i++) {
+		reg_val = mtk_r32(eth, MTK_LRO_DIP_DW0_CFG(reg_map, i));
+		if (reg_val == ip4dst)
+			break;
+	}
+
+	if (i < MTK_HW_LRO_DIP_NUM(eth) + 1) {
+		netdev_warn(dev, "Duplicate IP address at DIP(%d)!\n", i);
+		return -EEXIST;
+	}
+
+	/* find out available DIP index */
+	for (i = 1; i <= MTK_HW_LRO_DIP_NUM(eth); i++) {
+		reg_val = mtk_r32(eth, MTK_LRO_DIP_DW0_CFG(reg_map, i));
+		if (reg_val == 0UL)
+			break;
+	}
+
+	if (i >= MTK_HW_LRO_DIP_NUM(eth) + 1) {
+		netdev_warn(dev, "DIP index is currently out of resource!\n");
+		return -EBUSY;
+	}
+
+	return i;
+}
+
+static int mtk_hwlro_get_ipaddr_idx(struct net_device *dev, u32 ip4dst)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	u32 reg_val;
+	int i;
+
+	/* find out DIP index that matches the given IP address */
+	for (i = 1; i <= MTK_HW_LRO_DIP_NUM(eth); i++) {
+		reg_val = mtk_r32(eth, MTK_LRO_DIP_DW0_CFG(eth->soc->reg_map, i));
+		if (reg_val == ip4dst)
+			break;
+	}
+
+	if (i >= MTK_HW_LRO_DIP_NUM(eth) + 1) {
+		netdev_warn(dev, "DIP address is not exist!\n");
+		return -ENOENT;
+	}
+
+	return i;
+}
+
 static int mtk_hwlro_add_ipaddr(struct net_device *dev,
 				struct ethtool_rxnfc *cmd)
 {
@@ -3067,15 +3152,19 @@ static int mtk_hwlro_add_ipaddr(struct net_device *dev,
 	struct mtk_mac *mac = netdev_priv(dev);
 	struct mtk_eth *eth = mac->hw;
 	int hwlro_idx;
+	u32 ip4dst;
 
 	if ((fsp->flow_type != TCP_V4_FLOW) ||
 	    (!fsp->h_u.tcp_ip4_spec.ip4dst) ||
 	    (fsp->location > 1))
 		return -EINVAL;
 
-	mac->hwlro_ip[fsp->location] = htonl(fsp->h_u.tcp_ip4_spec.ip4dst);
-	hwlro_idx = (mac->id * MTK_MAX_LRO_IP_CNT) + fsp->location;
+	ip4dst = htonl(fsp->h_u.tcp_ip4_spec.ip4dst);
+	hwlro_idx = mtk_hwlro_add_ipaddr_idx(dev, ip4dst);
+	if (hwlro_idx < 0)
+		return hwlro_idx;
 
+	mac->hwlro_ip[fsp->location] = ip4dst;
 	mac->hwlro_ip_cnt = mtk_hwlro_get_ip_cnt(mac);
 
 	mtk_hwlro_val_ipaddr(eth, hwlro_idx, mac->hwlro_ip[fsp->location]);
@@ -3091,13 +3180,17 @@ static int mtk_hwlro_del_ipaddr(struct net_device *dev,
 	struct mtk_mac *mac = netdev_priv(dev);
 	struct mtk_eth *eth = mac->hw;
 	int hwlro_idx;
+	u32 ip4dst;
 
 	if (fsp->location > 1)
 		return -EINVAL;
 
-	mac->hwlro_ip[fsp->location] = 0;
-	hwlro_idx = (mac->id * MTK_MAX_LRO_IP_CNT) + fsp->location;
+	ip4dst = mac->hwlro_ip[fsp->location];
+	hwlro_idx = mtk_hwlro_get_ipaddr_idx(dev, ip4dst);
+	if (hwlro_idx < 0)
+		return hwlro_idx;
 
+	mac->hwlro_ip[fsp->location] = 0;
 	mac->hwlro_ip_cnt = mtk_hwlro_get_ip_cnt(mac);
 
 	mtk_hwlro_inval_ipaddr(eth, hwlro_idx);
@@ -3105,6 +3198,24 @@ static int mtk_hwlro_del_ipaddr(struct net_device *dev,
 	return 0;
 }
 
+static void mtk_hwlro_netdev_enable(struct net_device *dev)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	int i, hwlro_idx;
+
+	for (i = 0; i < MTK_MAX_LRO_IP_CNT; i++) {
+		if (mac->hwlro_ip[i] == 0)
+			continue;
+
+		hwlro_idx = mtk_hwlro_get_ipaddr_idx(dev, mac->hwlro_ip[i]);
+		if (hwlro_idx < 0)
+			continue;
+
+		mtk_hwlro_val_ipaddr(eth, hwlro_idx, mac->hwlro_ip[i]);
+	}
+}
+
 static void mtk_hwlro_netdev_disable(struct net_device *dev)
 {
 	struct mtk_mac *mac = netdev_priv(dev);
@@ -3112,8 +3223,14 @@ static void mtk_hwlro_netdev_disable(struct net_device *dev)
 	int i, hwlro_idx;
 
 	for (i = 0; i < MTK_MAX_LRO_IP_CNT; i++) {
+		if (mac->hwlro_ip[i] == 0)
+			continue;
+
+		hwlro_idx = mtk_hwlro_get_ipaddr_idx(dev, mac->hwlro_ip[i]);
+		if (hwlro_idx < 0)
+			continue;
+
 		mac->hwlro_ip[i] = 0;
-		hwlro_idx = (mac->id * MTK_MAX_LRO_IP_CNT) + i;
 
 		mtk_hwlro_inval_ipaddr(eth, hwlro_idx);
 	}
@@ -3293,6 +3410,8 @@ static int mtk_set_features(struct net_device *dev, netdev_features_t features)
 
 	if ((diff & NETIF_F_LRO) && !(features & NETIF_F_LRO))
 		mtk_hwlro_netdev_disable(dev);
+	else if ((diff & NETIF_F_LRO) && (features & NETIF_F_LRO))
+		mtk_hwlro_netdev_enable(dev);
 
 	return 0;
 }
@@ -3350,8 +3469,8 @@ static int mtk_dma_init(struct mtk_eth *eth)
 		return err;
 
 	if (eth->hwlro) {
-		for (i = 1; i < MTK_MAX_RX_RING_NUM; i++) {
-			err = mtk_rx_alloc(eth, i, MTK_RX_FLAGS_HWLRO);
+		for (i = 0; i < MTK_HW_LRO_RING_NUM(eth); i++) {
+			err = mtk_rx_alloc(eth, MTK_HW_LRO_RING(eth, i), MTK_RX_FLAGS_HWLRO);
 			if (err)
 				return err;
 		}
@@ -3413,8 +3532,8 @@ static void mtk_dma_free(struct mtk_eth *eth)
 
 	if (eth->hwlro) {
 		mtk_hwlro_rx_uninit(eth);
-		for (i = 1; i < MTK_MAX_RX_RING_NUM; i++)
-			mtk_rx_clean(eth, &eth->rx_ring[i], false);
+		for (i = 0; i < MTK_HW_LRO_RING_NUM(eth); i++)
+			mtk_rx_clean(eth, &eth->rx_ring[MTK_HW_LRO_RING(eth, i)], false);
 	}
 
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
@@ -3609,16 +3728,21 @@ static int mtk_start_dma(struct mtk_eth *eth)
 			val |= MTK_RX_BT_32DWORDS;
 		mtk_w32(eth, val, reg_map->qdma.glo_cfg);
 
-		mtk_w32(eth,
-			MTK_RX_DMA_EN | rx_2b_offset |
-			MTK_RX_BT_32DWORDS | MTK_MULTI_EN,
-			reg_map->pdma.glo_cfg);
+		val = mtk_r32(eth, reg_map->pdma.glo_cfg);
+		val |= MTK_RX_DMA_EN | rx_2b_offset |
+		       MTK_RX_BT_32DWORDS | MTK_MULTI_EN;
+		mtk_w32(eth, val, reg_map->pdma.glo_cfg);
 	} else {
 		mtk_w32(eth, MTK_TX_WB_DDONE | MTK_TX_DMA_EN | MTK_RX_DMA_EN |
 			MTK_MULTI_EN | MTK_PDMA_SIZE_8DWORDS,
 			reg_map->pdma.glo_cfg);
 	}
 
+	if (eth->hwlro && mtk_is_netsys_v3_or_greater(eth)) {
+		val = mtk_r32(eth, reg_map->pdma.glo_cfg);
+		mtk_w32(eth, val | MTK_RX_DMA_LRO_EN, reg_map->pdma.glo_cfg);
+	}
+
 	return 0;
 }
 
@@ -3762,6 +3886,14 @@ static int mtk_open(struct net_device *dev)
 			}
 		}
 
+		if (eth->hwlro) {
+			for (i = 0; i < MTK_HW_LRO_RING_NUM(eth); i++) {
+				napi_enable(&eth->rx_napi[MTK_HW_LRO_RING(eth, i)].napi);
+				mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(eth,
+								       MTK_HW_LRO_RING(eth, i)));
+			}
+		}
+
 		refcount_set(&eth->dma_refcnt, 1);
 	} else {
 		refcount_inc(&eth->dma_refcnt);
@@ -3857,6 +3989,14 @@ static int mtk_stop(struct net_device *dev)
 		}
 	}
 
+	if (eth->hwlro) {
+		for (i = 0; i < MTK_HW_LRO_RING_NUM(eth); i++) {
+			mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(eth, MTK_HW_LRO_RING(eth, i)));
+			napi_synchronize(&eth->rx_napi[MTK_HW_LRO_RING(eth, i)].napi);
+			napi_disable(&eth->rx_napi[MTK_HW_LRO_RING(eth, i)].napi);
+		}
+	}
+
 	cancel_work_sync(&eth->rx_dim.work);
 	cancel_work_sync(&eth->tx_dim.work);
 
@@ -4256,6 +4396,14 @@ static int mtk_napi_init(struct mtk_eth *eth)
 		}
 	}
 
+	if (eth->hwlro) {
+		for (i = 0; i < MTK_HW_LRO_RING_NUM(eth); i++) {
+			rx_napi = &eth->rx_napi[MTK_HW_LRO_RING(eth, i)];
+			rx_napi->eth = eth;
+			rx_napi->rx_ring = &eth->rx_ring[MTK_HW_LRO_RING(eth, i)];
+		}
+	}
+
 	return 0;
 }
 
@@ -4818,7 +4966,7 @@ static int mtk_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
 	switch (cmd->cmd) {
 	case ETHTOOL_GRXRINGS:
 		if (dev->hw_features & NETIF_F_LRO) {
-			cmd->data = MTK_MAX_RX_RING_NUM;
+			cmd->data = MTK_HW_LRO_RING_NUM(eth);
 			ret = 0;
 		} else if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
 			cmd->data = MTK_RX_RSS_NUM(eth);
@@ -5298,6 +5446,7 @@ static int mtk_probe(struct platform_device *pdev)
 {
 	struct resource *res = NULL;
 	struct device_node *mac_np;
+	u8 lro_irq, lro_ring;
 	struct mtk_eth *eth;
 	char *irqname;
 	int err, i;
@@ -5523,6 +5672,23 @@ static int mtk_probe(struct platform_device *pdev)
 						goto err_free_dev;
 				}
 			}
+
+			if (eth->hwlro) {
+				for (i = 0; i < MTK_HW_LRO_RING_NUM(eth); i++) {
+					lro_irq = MTK_HW_LRO_IRQ(eth, i);
+					lro_ring = MTK_HW_LRO_RING(eth, i);
+					irqname = devm_kasprintf(eth->dev, GFP_KERNEL,
+								 "%s LRO RX %d",
+								 dev_name(eth->dev), i);
+					err = devm_request_irq(eth->dev,
+							       eth->irq_pdma[lro_irq],
+							       mtk_handle_irq_rx, IRQF_SHARED,
+							       irqname,
+							       &eth->rx_napi[lro_ring]);
+					if (err)
+						goto err_free_dev;
+				}
+			}
 		} else {
 			irqname = devm_kasprintf(eth->dev, GFP_KERNEL, "%s RX",
 						 dev_name(eth->dev));
@@ -5594,6 +5760,13 @@ static int mtk_probe(struct platform_device *pdev)
 				       mtk_napi_rx);
 	}
 
+	if (eth->hwlro) {
+		for (i = 0; i < MTK_HW_LRO_RING_NUM(eth); i++) {
+			netif_napi_add(eth->dummy_dev, &eth->rx_napi[MTK_HW_LRO_RING(eth, i)].napi,
+				       mtk_napi_rx);
+		}
+	}
+
 	platform_set_drvdata(pdev, eth);
 	schedule_delayed_work(&eth->reset.monitor_work,
 			      MTK_DMA_MONITOR_TIMEOUT);
@@ -5642,6 +5815,12 @@ static void mtk_remove(struct platform_device *pdev)
 		for (i = 1; i < MTK_RX_RSS_NUM(eth); i++)
 			netif_napi_del(&eth->rx_napi[MTK_RSS_RING(i)].napi);
 	}
+
+	if (eth->hwlro) {
+		for (i = 0; i < MTK_HW_LRO_RING_NUM(eth); i++)
+			netif_napi_del(&eth->rx_napi[MTK_HW_LRO_RING(eth, i)].napi);
+	}
+
 	mtk_cleanup(eth);
 	free_netdev(eth->dummy_dev);
 	mtk_mdio_cleanup(eth);
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index 987846d46151..f1b56a8d316c 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -35,7 +35,7 @@
 #define MTK_DMA_SIZE(x)		(SZ_##x)
 #define MTK_FQ_DMA_HEAD		32
 #define MTK_FQ_DMA_LENGTH	2048
-#define MTK_RX_ETH_HLEN		(ETH_HLEN + ETH_FCS_LEN)
+#define MTK_RX_ETH_HLEN		(VLAN_ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN)
 #define MTK_RX_HLEN		(NET_SKB_PAD + MTK_RX_ETH_HLEN + NET_IP_ALIGN)
 #define MTK_DMA_DUMMY_DESC	0xffffffff
 #define MTK_DEFAULT_MSG_ENABLE	(NETIF_MSG_DRV | \
@@ -63,10 +63,9 @@
 
 #define MTK_QRX_OFFSET		0x10
 
-#define MTK_MAX_RX_RING_NUM	4
-#define MTK_HW_LRO_DMA_SIZE	8
-
-#define	MTK_MAX_LRO_RX_LENGTH		(4096 * 3)
+#define MTK_MAX_RX_RING_NUM	(8)
+#define MTK_HW_LRO_DMA_SIZE(eth)	(mtk_is_netsys_v3_or_greater(eth) ? 64 : 8)
+#define	MTK_MAX_LRO_RX_LENGTH		(4096 * 3 + MTK_MAX_RX_LENGTH)
 #define	MTK_MAX_LRO_IP_CNT		2
 #define	MTK_HW_LRO_TIMER_UNIT		1	/* 20 us */
 #define	MTK_HW_LRO_REFRESH_TIME		50000	/* 1 sec. */
@@ -182,31 +181,37 @@
 #define MTK_CDMM_THRES		0x165c
 
 /* PDMA HW LRO Control Registers */
-#define MTK_PDMA_LRO_CTRL_DW0	0x980
-#define MTK_HW_LRO_RING_NUM(eth)		(mtk_is_netsys_v3_or_greater(eth) ? 4 : 3)
+#define MTK_HW_LRO_DIP_NUM(eth)		(mtk_is_netsys_v3_or_greater(eth) ? 4 : 3)
+#define MTK_HW_LRO_RING_NUM(eth)	(mtk_is_netsys_v3_or_greater(eth) ? 4 : 3)
+#define MTK_HW_LRO_RING(eth, x)		((x) + (mtk_is_netsys_v3_or_greater(eth) ? 4 : 1))
+#define MTK_HW_LRO_IRQ(eth, x)		((x) + (mtk_is_netsys_v3_or_greater(eth) ? 0 : 1))
+#define MTK_LRO_CRSN_BNW(eth)		BIT((mtk_is_netsys_v3_or_greater(eth) ? 22 : 6))
 #define MTK_LRO_EN			BIT(0)
 #define MTK_NON_LRO_MULTI_EN		BIT(2)
 #define MTK_LRO_DLY_INT_EN		BIT(5)
-#define MTK_L3_CKS_UPD_EN		BIT(7)
-#define MTK_L3_CKS_UPD_EN_V2		BIT(19)
+#define MTK_L3_CKS_UPD_EN(eth)		BIT(mtk_is_netsys_v3_or_greater(eth) ? 19 : 7)
 #define MTK_LRO_ALT_PKT_CNT_MODE	BIT(21)
-#define MTK_LRO_RING_RELINQUISH_REQ	(0x7 << 26)
-#define MTK_LRO_RING_RELINQUISH_REQ_V2	(0xf << 24)
-#define MTK_LRO_RING_RELINQUISH_DONE	(0x7 << 29)
-#define MTK_LRO_RING_RELINQUISH_DONE_V2	(0xf << 28)
-
-#define MTK_PDMA_LRO_CTRL_DW1	0x984
-#define MTK_PDMA_LRO_CTRL_DW2	0x988
-#define MTK_PDMA_LRO_CTRL_DW3	0x98c
+#define MTK_LRO_RING_RELINQUISH_REQ(eth)	(mtk_is_netsys_v3_or_greater(eth) ? \
+						0xf << 24 : 0x7 << 26)
+#define MTK_LRO_RING_RELINQUISH_DONE(eth)	(mtk_is_netsys_v3_or_greater(eth) ? \
+						0xf << 28 : 0x7 << 29)
+
+#define MTK_PDMA_LRO_CTRL_DW0(reg_map)	(reg_map->pdma.lro_ctrl_dw0)
+#define MTK_PDMA_LRO_CTRL_DW1(reg_map)	(reg_map->pdma.lro_ctrl_dw0 + 0x04)
+#define MTK_PDMA_LRO_CTRL_DW2(reg_map)	(reg_map->pdma.lro_ctrl_dw0 + 0x08)
+#define MTK_PDMA_LRO_CTRL_DW3(reg_map)	(reg_map->pdma.lro_ctrl_dw0 + 0x0c)
 #define MTK_ADMA_MODE		BIT(15)
 #define MTK_LRO_MIN_RXD_SDL	(MTK_HW_LRO_SDL_REMAIN_ROOM << 16)
 
+#define MTK_CTRL_DW0_SDL_OFFSET	(3)
+#define MTK_CTRL_DW0_SDL_MASK	BITS(3, 18)
+
 #define MTK_RX_DMA_LRO_EN	BIT(8)
 #define MTK_MULTI_EN		BIT(10)
 #define MTK_PDMA_SIZE_8DWORDS	(1 << 4)
 
 /* PDMA RSS Control Registers */
-#define MTK_RX_NAPI_NUM			(4)
+#define MTK_RX_NAPI_NUM			(8)
 #define MTK_RX_RSS_NUM(eth)		(eth->soc->rss_num)
 #define MTK_RSS_RING(x)			(x)
 #define MTK_RSS_EN			BIT(0)
@@ -242,11 +247,10 @@
 #define MTK_PDMA_DELAY_PTIME_MASK	0xff
 
 /* PDMA HW LRO Alter Flow Delta Register */
-#define MTK_PDMA_LRO_ALT_SCORE_DELTA	0xa4c
+#define MTK_PDMA_LRO_ALT_SCORE_DELTA(reg_map)	(reg_map->pdma.lro_alt_score_delta)
 
 /* PDMA HW LRO IP Setting Registers */
-#define MTK_LRO_RX_RING0_DIP_DW0	0xb04
-#define MTK_LRO_DIP_DW0_CFG(x)		(MTK_LRO_RX_RING0_DIP_DW0 + (x * 0x40))
+#define MTK_LRO_DIP_DW0_CFG(reg_map, x)	(reg_map->pdma.lro_ring_dip_dw0 + ((x) * 0x40))
 #define MTK_RING_MYIP_VLD		BIT(9)
 
 /* PDMA HW LRO Ring Control Registers */
@@ -1187,7 +1191,8 @@ enum mkt_eth_capabilities {
 
 #define MT7988_CAPS  (MTK_36BIT_DMA | MTK_GDM1_ESW | MTK_GMAC2_2P5GPHY | \
 		      MTK_MUX_GMAC2_TO_2P5GPHY | MTK_QDMA | MTK_RSTCTRL_PPE1 | \
-		      MTK_RSTCTRL_PPE2 | MTK_SRAM | MTK_PDMA_INT | MTK_RSS)
+		      MTK_RSTCTRL_PPE2 | MTK_SRAM | MTK_PDMA_INT | MTK_RSS | \
+		      MTK_HWLRO)
 
 struct mtk_tx_dma_desc_info {
 	dma_addr_t	addr;
-- 
2.43.0



From linux at fw-web.de  Fri Dec 19 07:12:11 2025
From: linux at fw-web.de (Frank Wunderlich)
Date: Fri, 19 Dec 2025 16:12:11 +0100
Subject: [RFC net-next v5 2/3] net: ethernet: mtk_eth_soc: Add RSS support
In-Reply-To: <20251219151219.77115-1-linux@fw-web.de>
References: <20251219151219.77115-1-linux@fw-web.de>
Message-ID: <20251219151219.77115-3-linux@fw-web.de>

From: Mason Chang <mason-cw.chang at mediatek.com>

Add support for Receive Side Scaling.

We can adjust SMP affinity with the following command:
echo [CPU bitmap num] > /proc/irq/[virtual IRQ ID]/smp_affinity,
with interrupts evenly assigned to 4 CPUs, we were able to measure
an RX throughput of 7.3Gbps using iperf3 on the MT7988. Further
optimizations will be carried out in the future.

The experimental command is as follows:
PC: iperf3 -c [IP] -P 10
DUT: iperf3 -s

The entire indirection table can be imagined as 128 buckets, we
can use the ethtool command to mark which RX ring we want to send
the packets in these buckets to.

Show RSS RX ring parameters in indirection table and RSS hash key:
ethtool -x [interface]
Change RSS RX rings weight under uniform distribution:
ethtool --set-rxfh-indir [interface] equal [ring num]
Change RSS RX rings weight under non-uniform distribution:
ethtool --set-rxfh-indir [interface] weight [ring0 weight]
[ring1 weight] [ring2 weight] [ring3 weight]

Signed-off-by: Mason Chang <mason-cw.chang at mediatek.com>
Signed-off-by: Frank Wunderlich <frank-w at public-files.de>
---
v5:
- fix too long line reported by checkpatch
  MTK_RSS_HASH_KEY_DW
  MTK_RSS_INDR_TABLE_DW
  MTK_LRO_CTRL_DW[123]_CFG

v4:
- drop unrelated file
- rss-changes suggested by andrew
  - fix MTK_HW_LRO_RING_NUM macro (add eth)
  - fix MTK_LRO_CTRL_DW[123]_CFG (add reg_map param)
  - fix MTK_RX_DONE_INT (add eth param)

v3:
- changes requested by jakub
- readded rss fix for mt7986
- name all PDMA-IRQ the same way

v2:
- drop wrong change (MTK_CDMP_IG_CTRL is only netsys v1)
- Fix immutable string IRQ setup (thx to Emilia Schotte)
- drop link to no more existent 6.6 patch in comment
---
 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 544 +++++++++++++++-----
 drivers/net/ethernet/mediatek/mtk_eth_soc.h |  98 +++-
 2 files changed, 496 insertions(+), 146 deletions(-)

diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 243ff16fd15e..4dfff59a3c8a 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -1275,6 +1275,7 @@ static bool mtk_rx_get_desc(struct mtk_eth *eth, struct mtk_rx_dma_v2 *rxd,
 	if (mtk_is_netsys_v3_or_greater(eth)) {
 		rxd->rxd5 = READ_ONCE(dma_rxd->rxd5);
 		rxd->rxd6 = READ_ONCE(dma_rxd->rxd6);
+		rxd->rxd7 = READ_ONCE(dma_rxd->rxd7);
 	}
 
 	return true;
@@ -1842,47 +1843,9 @@ static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	return NETDEV_TX_OK;
 }
 
-static struct mtk_rx_ring *mtk_get_rx_ring(struct mtk_eth *eth)
+static void mtk_update_rx_cpu_idx(struct mtk_eth *eth, struct mtk_rx_ring *ring)
 {
-	int i;
-	struct mtk_rx_ring *ring;
-	int idx;
-
-	if (!eth->hwlro)
-		return &eth->rx_ring[0];
-
-	for (i = 0; i < MTK_MAX_RX_RING_NUM; i++) {
-		struct mtk_rx_dma *rxd;
-
-		ring = &eth->rx_ring[i];
-		idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size);
-		rxd = ring->dma + idx * eth->soc->rx.desc_size;
-		if (rxd->rxd2 & RX_DMA_DONE) {
-			ring->calc_idx_update = true;
-			return ring;
-		}
-	}
-
-	return NULL;
-}
-
-static void mtk_update_rx_cpu_idx(struct mtk_eth *eth)
-{
-	struct mtk_rx_ring *ring;
-	int i;
-
-	if (!eth->hwlro) {
-		ring = &eth->rx_ring[0];
-		mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg);
-	} else {
-		for (i = 0; i < MTK_MAX_RX_RING_NUM; i++) {
-			ring = &eth->rx_ring[i];
-			if (ring->calc_idx_update) {
-				ring->calc_idx_update = false;
-				mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg);
-			}
-		}
-	}
+	mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg);
 }
 
 static bool mtk_page_pool_enabled(struct mtk_eth *eth)
@@ -1913,7 +1876,7 @@ static struct page_pool *mtk_create_page_pool(struct mtk_eth *eth,
 		return pp;
 
 	err = __xdp_rxq_info_reg(xdp_q, eth->dummy_dev, id,
-				 eth->rx_napi.napi_id, PAGE_SIZE);
+				 eth->rx_napi[id].napi.napi_id, PAGE_SIZE);
 	if (err < 0)
 		goto err_free_pp;
 
@@ -2202,7 +2165,8 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
 		       struct mtk_eth *eth)
 {
 	struct dim_sample dim_sample = {};
-	struct mtk_rx_ring *ring;
+	struct mtk_napi *rx_napi = container_of(napi, struct mtk_napi, napi);
+	struct mtk_rx_ring *ring = rx_napi->rx_ring;
 	bool xdp_flush = false;
 	int idx;
 	struct sk_buff *skb;
@@ -2213,16 +2177,15 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
 	dma_addr_t dma_addr = DMA_MAPPING_ERROR;
 	int ppe_idx = 0;
 
+	if (unlikely(!ring))
+		goto rx_done;
+
 	while (done < budget) {
 		unsigned int pktlen, *rxdcsum;
 		struct net_device *netdev;
 		u32 hash, reason;
 		int mac = 0;
 
-		ring = mtk_get_rx_ring(eth);
-		if (unlikely(!ring))
-			goto rx_done;
-
 		idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size);
 		rxd = ring->dma + idx * eth->soc->rx.desc_size;
 		data = ring->data[idx];
@@ -2414,7 +2377,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
 		 * we continue
 		 */
 		wmb();
-		mtk_update_rx_cpu_idx(eth);
+		mtk_update_rx_cpu_idx(eth, ring);
 	}
 
 	eth->rx_packets += done;
@@ -2623,7 +2586,9 @@ static int mtk_napi_tx(struct napi_struct *napi, int budget)
 
 static int mtk_napi_rx(struct napi_struct *napi, int budget)
 {
-	struct mtk_eth *eth = container_of(napi, struct mtk_eth, rx_napi);
+	struct mtk_napi *rx_napi = container_of(napi, struct mtk_napi, napi);
+	struct mtk_eth *eth = rx_napi->eth;
+	struct mtk_rx_ring *ring = rx_napi->rx_ring;
 	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
 	int rx_done_total = 0;
 
@@ -2632,7 +2597,7 @@ static int mtk_napi_rx(struct napi_struct *napi, int budget)
 	do {
 		int rx_done;
 
-		mtk_w32(eth, eth->soc->rx.irq_done_mask,
+		mtk_w32(eth, MTK_RX_DONE_INT(eth, ring->ring_no),
 			reg_map->pdma.irq_status);
 		rx_done = mtk_poll_rx(napi, budget - rx_done_total, eth);
 		rx_done_total += rx_done;
@@ -2648,10 +2613,10 @@ static int mtk_napi_rx(struct napi_struct *napi, int budget)
 			return budget;
 
 	} while (mtk_r32(eth, reg_map->pdma.irq_status) &
-		 eth->soc->rx.irq_done_mask);
+		 MTK_RX_DONE_INT(eth, ring->ring_no));
 
 	if (napi_complete_done(napi, rx_done_total))
-		mtk_rx_irq_enable(eth, eth->soc->rx.irq_done_mask);
+		mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(eth, ring->ring_no));
 
 	return rx_done_total;
 }
@@ -2897,6 +2862,7 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag)
 	else
 		ring->crx_idx_reg = reg_map->pdma.pcrx_ptr +
 				    ring_no * MTK_QRX_OFFSET;
+	ring->ring_no = ring_no;
 	/* make sure that all changes to the dma ring are flushed before we
 	 * continue
 	 */
@@ -2965,6 +2931,7 @@ static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring, bool in_
 
 static int mtk_hwlro_rx_init(struct mtk_eth *eth)
 {
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
 	int i;
 	u32 ring_ctrl_dw1 = 0, ring_ctrl_dw2 = 0, ring_ctrl_dw3 = 0;
 	u32 lro_ctrl_dw0 = 0, lro_ctrl_dw3 = 0;
@@ -2987,9 +2954,9 @@ static int mtk_hwlro_rx_init(struct mtk_eth *eth)
 	ring_ctrl_dw3 |= MTK_RING_MAX_AGG_CNT_H;
 
 	for (i = 1; i < MTK_MAX_RX_RING_NUM; i++) {
-		mtk_w32(eth, ring_ctrl_dw1, MTK_LRO_CTRL_DW1_CFG(i));
-		mtk_w32(eth, ring_ctrl_dw2, MTK_LRO_CTRL_DW2_CFG(i));
-		mtk_w32(eth, ring_ctrl_dw3, MTK_LRO_CTRL_DW3_CFG(i));
+		mtk_w32(eth, ring_ctrl_dw1, MTK_LRO_CTRL_DW1_CFG(reg_map, i));
+		mtk_w32(eth, ring_ctrl_dw2, MTK_LRO_CTRL_DW2_CFG(reg_map, i));
+		mtk_w32(eth, ring_ctrl_dw3, MTK_LRO_CTRL_DW3_CFG(reg_map, i));
 	}
 
 	/* IPv4 checksum update enable */
@@ -3025,6 +2992,7 @@ static int mtk_hwlro_rx_init(struct mtk_eth *eth)
 
 static void mtk_hwlro_rx_uninit(struct mtk_eth *eth)
 {
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
 	int i;
 	u32 val;
 
@@ -3043,7 +3011,7 @@ static void mtk_hwlro_rx_uninit(struct mtk_eth *eth)
 
 	/* invalidate lro rings */
 	for (i = 1; i < MTK_MAX_RX_RING_NUM; i++)
-		mtk_w32(eth, 0, MTK_LRO_CTRL_DW2_CFG(i));
+		mtk_w32(eth, 0, MTK_LRO_CTRL_DW2_CFG(reg_map, i));
 
 	/* disable HW LRO */
 	mtk_w32(eth, 0, MTK_PDMA_LRO_CTRL_DW0);
@@ -3051,27 +3019,29 @@ static void mtk_hwlro_rx_uninit(struct mtk_eth *eth)
 
 static void mtk_hwlro_val_ipaddr(struct mtk_eth *eth, int idx, __be32 ip)
 {
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
 	u32 reg_val;
 
-	reg_val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(idx));
+	reg_val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(reg_map, idx));
 
 	/* invalidate the IP setting */
-	mtk_w32(eth, (reg_val & ~MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(idx));
+	mtk_w32(eth, (reg_val & ~MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(reg_map, idx));
 
 	mtk_w32(eth, ip, MTK_LRO_DIP_DW0_CFG(idx));
 
 	/* validate the IP setting */
-	mtk_w32(eth, (reg_val | MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(idx));
+	mtk_w32(eth, (reg_val | MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(reg_map, idx));
 }
 
 static void mtk_hwlro_inval_ipaddr(struct mtk_eth *eth, int idx)
 {
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
 	u32 reg_val;
 
-	reg_val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(idx));
+	reg_val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(reg_map, idx));
 
 	/* invalidate the IP setting */
-	mtk_w32(eth, (reg_val & ~MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(idx));
+	mtk_w32(eth, (reg_val & ~MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(reg_map, idx));
 
 	mtk_w32(eth, 0, MTK_LRO_DIP_DW0_CFG(idx));
 }
@@ -3201,6 +3171,105 @@ static int mtk_hwlro_get_fdir_all(struct net_device *dev,
 	return 0;
 }
 
+static u32 mtk_rss_indr_table(struct mtk_rss_params *rss_params, int index)
+{
+	u32 val = 0;
+	int i;
+
+	for (i = 16 * index; i < 16 * index + 16; i++)
+		val |= (rss_params->indirection_table[i] << (2 * (i % 16)));
+
+	return val;
+}
+
+static int mtk_rss_init(struct mtk_eth *eth)
+{
+	const struct mtk_soc_data *soc = eth->soc;
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
+	struct mtk_rss_params *rss_params = &eth->rss_params;
+	u32 val;
+	int i;
+
+	netdev_rss_key_fill(rss_params->hash_key, MTK_RSS_HASH_KEYSIZE);
+
+	for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE; i++)
+		rss_params->indirection_table[i] = ethtool_rxfh_indir_default(i, eth->soc->rss_num);
+
+	if (soc->rx.desc_size == sizeof(struct mtk_rx_dma)) {
+		/* Set RSS rings to PSE modes */
+		for (i = 1; i <= MTK_HW_LRO_RING_NUM(eth); i++) {
+			val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(reg_map, i));
+			val |= MTK_RING_PSE_MODE;
+			mtk_w32(eth, val, MTK_LRO_CTRL_DW2_CFG(reg_map, i));
+		}
+
+		/* Enable non-lro multiple rx */
+		val = mtk_r32(eth, reg_map->pdma.lro_ctrl_dw0);
+		val |= MTK_NON_LRO_MULTI_EN;
+		mtk_w32(eth, val, reg_map->pdma.lro_ctrl_dw0);
+
+		/* Enable RSS dly int supoort */
+		val |= MTK_LRO_DLY_INT_EN;
+		mtk_w32(eth, val, reg_map->pdma.lro_ctrl_dw0);
+	}
+
+	/* Hash Type */
+	val = mtk_r32(eth, reg_map->pdma.rss_glo_cfg);
+	val |= MTK_RSS_IPV4_STATIC_HASH;
+	val |= MTK_RSS_IPV6_STATIC_HASH;
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+	/* Hash Key */
+	for (i = 0; i < MTK_RSS_HASH_KEYSIZE / sizeof(u32); i++)
+		mtk_w32(eth, rss_params->hash_key[i], MTK_RSS_HASH_KEY_DW(reg_map, i));
+
+	/* Select the size of indirection table */
+	for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE / 16; i++)
+		mtk_w32(eth, mtk_rss_indr_table(rss_params, i),
+			MTK_RSS_INDR_TABLE_DW(reg_map, i));
+
+	/* Pause */
+	val |= MTK_RSS_CFG_REQ;
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+	/* Enable RSS */
+	val |= MTK_RSS_EN;
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+	/* Release pause */
+	val &= ~(MTK_RSS_CFG_REQ);
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+	/* Set perRSS GRP INT */
+	mtk_m32(eth, MTK_RX_DONE_INT(eth, MTK_RSS_RING(1)),
+		MTK_RX_DONE_INT(eth, MTK_RSS_RING(1)), reg_map->pdma.int_grp);
+	mtk_m32(eth, MTK_RX_DONE_INT(eth, MTK_RSS_RING(2)),
+		MTK_RX_DONE_INT(eth, MTK_RSS_RING(2)), reg_map->pdma.int_grp + 0x4);
+	mtk_m32(eth, MTK_RX_DONE_INT(eth, MTK_RSS_RING(3)),
+		MTK_RX_DONE_INT(eth, MTK_RSS_RING(3)), reg_map->pdma.int_grp3);
+
+	return 0;
+}
+
+static void mtk_rss_uninit(struct mtk_eth *eth)
+{
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
+	u32 val;
+
+	/* Pause */
+	val = mtk_r32(eth, reg_map->pdma.rss_glo_cfg);
+	val |= MTK_RSS_CFG_REQ;
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+	/* Disable RSS */
+	val &= ~(MTK_RSS_EN);
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+	/* Release pause */
+	val &= ~(MTK_RSS_CFG_REQ);
+	mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+}
+
 static netdev_features_t mtk_fix_features(struct net_device *dev,
 					  netdev_features_t features)
 {
@@ -3291,6 +3360,17 @@ static int mtk_dma_init(struct mtk_eth *eth)
 			return err;
 	}
 
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		for (i = 1; i < MTK_RX_RSS_NUM(eth); i++) {
+			err = mtk_rx_alloc(eth, MTK_RSS_RING(i), MTK_RX_FLAGS_NORMAL);
+			if (err)
+				return err;
+		}
+		err = mtk_rss_init(eth);
+		if (err)
+			return err;
+	}
+
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {
 		/* Enable random early drop and set drop threshold
 		 * automatically
@@ -3337,6 +3417,12 @@ static void mtk_dma_free(struct mtk_eth *eth)
 			mtk_rx_clean(eth, &eth->rx_ring[i], false);
 	}
 
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		mtk_rss_uninit(eth);
+		for (i = 1; i < MTK_RX_RSS_NUM(eth); i++)
+			mtk_rx_clean(eth, &eth->rx_ring[MTK_RSS_RING(i)], true);
+	}
+
 	for (i = 0; i < DIV_ROUND_UP(soc->tx.fq_dma_size, MTK_FQ_DMA_LENGTH); i++) {
 		kfree(eth->scratch_head[i]);
 		eth->scratch_head[i] = NULL;
@@ -3369,23 +3455,23 @@ static void mtk_tx_timeout(struct net_device *dev, unsigned int txqueue)
 	schedule_work(&eth->pending_work);
 }
 
-static int mtk_get_irqs(struct platform_device *pdev, struct mtk_eth *eth)
+static int mtk_get_irqs_fe(struct platform_device *pdev, struct mtk_eth *eth)
 {
 	int i;
 
 	/* future SoCs beginning with MT7988 should use named IRQs in dts */
-	eth->irq[MTK_FE_IRQ_TX] = platform_get_irq_byname_optional(pdev, "fe1");
-	eth->irq[MTK_FE_IRQ_RX] = platform_get_irq_byname_optional(pdev, "fe2");
-	if (eth->irq[MTK_FE_IRQ_TX] >= 0 && eth->irq[MTK_FE_IRQ_RX] >= 0)
+	eth->irq_fe[MTK_FE_IRQ_TX] = platform_get_irq_byname_optional(pdev, "fe1");
+	eth->irq_fe[MTK_FE_IRQ_RX] = platform_get_irq_byname_optional(pdev, "fe2");
+	if (eth->irq_fe[MTK_FE_IRQ_TX] >= 0 && eth->irq_fe[MTK_FE_IRQ_RX] >= 0)
 		return 0;
 
 	/* only use legacy mode if platform_get_irq_byname_optional returned -ENXIO */
-	if (eth->irq[MTK_FE_IRQ_TX] != -ENXIO)
-		return dev_err_probe(&pdev->dev, eth->irq[MTK_FE_IRQ_TX],
+	if (eth->irq_fe[MTK_FE_IRQ_TX] != -ENXIO)
+		return dev_err_probe(&pdev->dev, eth->irq_fe[MTK_FE_IRQ_TX],
 				     "Error requesting FE TX IRQ\n");
 
-	if (eth->irq[MTK_FE_IRQ_RX] != -ENXIO)
-		return dev_err_probe(&pdev->dev, eth->irq[MTK_FE_IRQ_RX],
+	if (eth->irq_fe[MTK_FE_IRQ_RX] != -ENXIO)
+		return dev_err_probe(&pdev->dev, eth->irq_fe[MTK_FE_IRQ_RX],
 				     "Error requesting FE RX IRQ\n");
 
 	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT))
@@ -3400,14 +3486,14 @@ static int mtk_get_irqs(struct platform_device *pdev, struct mtk_eth *eth)
 	for (i = 0; i < MTK_FE_IRQ_NUM; i++) {
 		if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT)) {
 			if (i == MTK_FE_IRQ_SHARED)
-				eth->irq[MTK_FE_IRQ_SHARED] = platform_get_irq(pdev, i);
+				eth->irq_fe[MTK_FE_IRQ_SHARED] = platform_get_irq(pdev, i);
 			else
-				eth->irq[i] = eth->irq[MTK_FE_IRQ_SHARED];
+				eth->irq_fe[i] = eth->irq_fe[MTK_FE_IRQ_SHARED];
 		} else {
-			eth->irq[i] = platform_get_irq(pdev, i + 1);
+			eth->irq_fe[i] = platform_get_irq(pdev, i + 1);
 		}
 
-		if (eth->irq[i] < 0) {
+		if (eth->irq_fe[i] < 0) {
 			dev_err(&pdev->dev, "no IRQ%d resource found\n", i);
 			return -ENXIO;
 		}
@@ -3416,14 +3502,36 @@ static int mtk_get_irqs(struct platform_device *pdev, struct mtk_eth *eth)
 	return 0;
 }
 
-static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth)
+static int mtk_get_irqs_pdma(struct platform_device *pdev, struct mtk_eth *eth)
 {
-	struct mtk_eth *eth = _eth;
+	char rxring[] = "pdma0";
+	int i;
+
+	for (i = 0; i < MTK_PDMA_IRQ_NUM; i++) {
+		rxring[4] = '0' + i;
+		eth->irq_pdma[i] = platform_get_irq_byname(pdev, rxring);
+		if (eth->irq_pdma[i] < 0)
+			return eth->irq_pdma[i];
+	}
+
+	return 0;
+}
+
+static irqreturn_t mtk_handle_irq_rx(int irq, void *priv)
+{
+	struct mtk_napi *rx_napi = priv;
+	struct mtk_eth *eth = rx_napi->eth;
+	struct mtk_rx_ring *ring = rx_napi->rx_ring;
 
 	eth->rx_events++;
-	if (likely(napi_schedule_prep(&eth->rx_napi))) {
-		mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask);
-		__napi_schedule(&eth->rx_napi);
+	if (unlikely(!(mtk_r32(eth, eth->soc->reg_map->pdma.irq_status) &
+		       mtk_r32(eth, eth->soc->reg_map->pdma.irq_mask) &
+		       MTK_RX_DONE_INT(eth, ring->ring_no))))
+		return IRQ_NONE;
+
+	if (likely(napi_schedule_prep(&rx_napi->napi))) {
+		mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(eth, ring->ring_no));
+		__napi_schedule(&rx_napi->napi);
 	}
 
 	return IRQ_HANDLED;
@@ -3448,10 +3556,10 @@ static irqreturn_t mtk_handle_irq(int irq, void *_eth)
 	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
 
 	if (mtk_r32(eth, reg_map->pdma.irq_mask) &
-	    eth->soc->rx.irq_done_mask) {
+	    MTK_RX_DONE_INT(eth, 0)) {
 		if (mtk_r32(eth, reg_map->pdma.irq_status) &
-		    eth->soc->rx.irq_done_mask)
-			mtk_handle_irq_rx(irq, _eth);
+		    MTK_RX_DONE_INT(eth, 0))
+			mtk_handle_irq_rx(irq, &eth->rx_napi[0]);
 	}
 	if (mtk_r32(eth, reg_map->tx_irq_mask) & MTK_TX_DONE_INT) {
 		if (mtk_r32(eth, reg_map->tx_irq_status) & MTK_TX_DONE_INT)
@@ -3468,10 +3576,10 @@ static void mtk_poll_controller(struct net_device *dev)
 	struct mtk_eth *eth = mac->hw;
 
 	mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
-	mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask);
-	mtk_handle_irq_rx(eth->irq[MTK_FE_IRQ_RX], dev);
+	mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(eth, 0));
+	mtk_handle_irq_rx(eth->irq_fe[MTK_FE_IRQ_RX], &eth->rx_napi[0]);
 	mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
-	mtk_rx_irq_enable(eth, eth->soc->rx.irq_done_mask);
+	mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(eth, 0));
 }
 #endif
 
@@ -3643,9 +3751,17 @@ static int mtk_open(struct net_device *dev)
 		}
 
 		napi_enable(&eth->tx_napi);
-		napi_enable(&eth->rx_napi);
+		napi_enable(&eth->rx_napi[0].napi);
 		mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
-		mtk_rx_irq_enable(eth, soc->rx.irq_done_mask);
+		mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(eth, 0));
+
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+			for (i = 1; i < MTK_RX_RSS_NUM(eth); i++) {
+				napi_enable(&eth->rx_napi[MTK_RSS_RING(i)].napi);
+				mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(eth, MTK_RSS_RING(i)));
+			}
+		}
+
 		refcount_set(&eth->dma_refcnt, 1);
 	} else {
 		refcount_inc(&eth->dma_refcnt);
@@ -3730,9 +3846,16 @@ static int mtk_stop(struct net_device *dev)
 		mtk_gdm_config(eth, i, MTK_GDMA_DROP_ALL);
 
 	mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
-	mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask);
+	mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(eth, 0));
 	napi_disable(&eth->tx_napi);
-	napi_disable(&eth->rx_napi);
+	napi_disable(&eth->rx_napi[0].napi);
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		for (i = 1; i < MTK_RX_RSS_NUM(eth); i++) {
+			mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(eth, MTK_RSS_RING(i)));
+			napi_disable(&eth->rx_napi[MTK_RSS_RING(i)].napi);
+		}
+	}
 
 	cancel_work_sync(&eth->rx_dim.work);
 	cancel_work_sync(&eth->tx_dim.work);
@@ -3843,9 +3966,7 @@ static void mtk_dim_rx(struct work_struct *work)
 						dim->profile_ix);
 	spin_lock_bh(&eth->dim_lock);
 
-	val = mtk_r32(eth, reg_map->pdma.delay_irq);
-	val &= MTK_PDMA_DELAY_TX_MASK;
-	val |= MTK_PDMA_DELAY_RX_EN;
+	val = MTK_PDMA_DELAY_RX_EN;
 
 	cur = min_t(u32, DIV_ROUND_UP(cur_profile.usec, 20), MTK_PDMA_DELAY_PTIME_MASK);
 	val |= cur << MTK_PDMA_DELAY_RX_PTIME_SHIFT;
@@ -3853,9 +3974,19 @@ static void mtk_dim_rx(struct work_struct *work)
 	cur = min_t(u32, cur_profile.pkts, MTK_PDMA_DELAY_PINT_MASK);
 	val |= cur << MTK_PDMA_DELAY_RX_PINT_SHIFT;
 
-	mtk_w32(eth, val, reg_map->pdma.delay_irq);
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
-		mtk_w32(eth, val, reg_map->qdma.delay_irq);
+		mtk_m32(eth, MTK_PDMA_DELAY_TX_MASK,
+			val << MTK_PDMA_DELAY_TX_PTIME_SHIFT, reg_map->qdma.delay_irq);
+
+	if (eth->soc->rx.desc_size == sizeof(struct mtk_rx_dma)) {
+		mtk_m32(eth, MTK_PDMA_DELAY_RX_MASK, val, reg_map->pdma.delay_irq);
+		mtk_w32(eth, val, reg_map->pdma.lro_rx1_dly_int);
+		mtk_w32(eth, val, reg_map->pdma.lro_rx1_dly_int + 0x4);
+		mtk_w32(eth, val, reg_map->pdma.lro_rx1_dly_int + 0x8);
+	} else {
+		val = val | (val << MTK_PDMA_DELAY_RX_RING_SHIFT);
+		mtk_w32(eth, val, reg_map->pdma.rx_delay_irq);
+	}
 
 	spin_unlock_bh(&eth->dim_lock);
 
@@ -3874,9 +4005,7 @@ static void mtk_dim_tx(struct work_struct *work)
 						dim->profile_ix);
 	spin_lock_bh(&eth->dim_lock);
 
-	val = mtk_r32(eth, reg_map->pdma.delay_irq);
-	val &= MTK_PDMA_DELAY_RX_MASK;
-	val |= MTK_PDMA_DELAY_TX_EN;
+	val = MTK_PDMA_DELAY_TX_EN;
 
 	cur = min_t(u32, DIV_ROUND_UP(cur_profile.usec, 20), MTK_PDMA_DELAY_PTIME_MASK);
 	val |= cur << MTK_PDMA_DELAY_TX_PTIME_SHIFT;
@@ -3884,9 +4013,16 @@ static void mtk_dim_tx(struct work_struct *work)
 	cur = min_t(u32, cur_profile.pkts, MTK_PDMA_DELAY_PINT_MASK);
 	val |= cur << MTK_PDMA_DELAY_TX_PINT_SHIFT;
 
-	mtk_w32(eth, val, reg_map->pdma.delay_irq);
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
-		mtk_w32(eth, val, reg_map->qdma.delay_irq);
+		mtk_m32(eth, MTK_PDMA_DELAY_RX_MASK,
+			val >> MTK_PDMA_DELAY_TX_PTIME_SHIFT, reg_map->qdma.delay_irq);
+
+	if (eth->soc->rx.desc_size == sizeof(struct mtk_rx_dma)) {
+		mtk_m32(eth, MTK_PDMA_DELAY_TX_MASK, val, reg_map->pdma.delay_irq);
+	} else {
+		mtk_w32(eth, val >> MTK_PDMA_DELAY_TX_PTIME_SHIFT,
+			reg_map->pdma.tx_delay_irq);
+	}
 
 	spin_unlock_bh(&eth->dim_lock);
 
@@ -4104,6 +4240,25 @@ static void mtk_hw_reset_monitor_work(struct work_struct *work)
 			      MTK_DMA_MONITOR_TIMEOUT);
 }
 
+static int mtk_napi_init(struct mtk_eth *eth)
+{
+	struct mtk_napi *rx_napi = &eth->rx_napi[0];
+	int i;
+
+	rx_napi->eth = eth;
+	rx_napi->rx_ring = &eth->rx_ring[0];
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		for (i = 1; i < MTK_RX_RSS_NUM(eth); i++) {
+			rx_napi = &eth->rx_napi[MTK_RSS_RING(i)];
+			rx_napi->eth = eth;
+			rx_napi->rx_ring = &eth->rx_ring[MTK_RSS_RING(i)];
+		}
+	}
+
+	return 0;
+}
+
 static int mtk_hw_init(struct mtk_eth *eth, bool reset)
 {
 	u32 dma_mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA |
@@ -4193,12 +4348,11 @@ static int mtk_hw_init(struct mtk_eth *eth, bool reset)
 	 */
 	val = mtk_r32(eth, MTK_CDMQ_IG_CTRL);
 	mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL);
-	if (mtk_is_netsys_v1(eth)) {
-		val = mtk_r32(eth, MTK_CDMP_IG_CTRL);
-		mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL);
+	val = mtk_r32(eth, MTK_CDMP_IG_CTRL);
+	mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL);
 
+	if (mtk_is_netsys_v1(eth))
 		mtk_w32(eth, 1, MTK_CDMP_EG_CTRL);
-	}
 
 	/* set interrupt delays based on current Net DIM sample */
 	mtk_dim_rx(&eth->rx_dim.work);
@@ -4209,11 +4363,17 @@ static int mtk_hw_init(struct mtk_eth *eth, bool reset)
 	mtk_rx_irq_disable(eth, ~0);
 
 	/* FE int grouping */
-	mtk_w32(eth, MTK_TX_DONE_INT, reg_map->pdma.int_grp);
-	mtk_w32(eth, eth->soc->rx.irq_done_mask, reg_map->pdma.int_grp + 4);
+
 	mtk_w32(eth, MTK_TX_DONE_INT, reg_map->qdma.int_grp);
-	mtk_w32(eth, eth->soc->rx.irq_done_mask, reg_map->qdma.int_grp + 4);
-	mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP);
+	mtk_w32(eth, MTK_RX_DONE_INT(eth, 0), reg_map->qdma.int_grp + 4);
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_PDMA_INT)) {
+		mtk_w32(eth, 0x210FFFF2, MTK_FE_INT_GRP);
+	} else {
+		mtk_w32(eth, MTK_TX_DONE_INT, reg_map->pdma.int_grp);
+		mtk_w32(eth, MTK_RX_DONE_INT(eth, 0), reg_map->pdma.int_grp + 4);
+		mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP);
+	}
 
 	if (mtk_is_netsys_v3_or_greater(eth)) {
 		/* PSE dummy page mechanism */
@@ -4651,6 +4811,8 @@ static void mtk_get_ethtool_stats(struct net_device *dev,
 static int mtk_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
 			 u32 *rule_locs)
 {
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
 	int ret = -EOPNOTSUPP;
 
 	switch (cmd->cmd) {
@@ -4658,6 +4820,9 @@ static int mtk_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
 		if (dev->hw_features & NETIF_F_LRO) {
 			cmd->data = MTK_MAX_RX_RING_NUM;
 			ret = 0;
+		} else if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+			cmd->data = MTK_RX_RSS_NUM(eth);
+			ret = 0;
 		}
 		break;
 	case ETHTOOL_GRXCLSRLCNT:
@@ -4732,6 +4897,70 @@ static int mtk_set_eee(struct net_device *dev, struct ethtool_keee *eee)
 	return phylink_ethtool_set_eee(mac->phylink, eee);
 }
 
+static u32 mtk_get_rxfh_key_size(struct net_device *dev)
+{
+	return MTK_RSS_HASH_KEYSIZE;
+}
+
+static u32 mtk_get_rxfh_indir_size(struct net_device *dev)
+{
+	return MTK_RSS_MAX_INDIRECTION_TABLE;
+}
+
+static int mtk_get_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	struct mtk_rss_params *rss_params = &eth->rss_params;
+	int i;
+
+	rxfh->hfunc = ETH_RSS_HASH_TOP;	/* Toeplitz */
+
+	if (rxfh->key) {
+		memcpy(rxfh->key, rss_params->hash_key,
+		       sizeof(rss_params->hash_key));
+	}
+
+	if (rxfh->indir) {
+		for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE; i++)
+			rxfh->indir[i] = rss_params->indirection_table[i];
+	}
+
+	return 0;
+}
+
+static int mtk_set_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh,
+			struct netlink_ext_ack *extack)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	struct mtk_rss_params *rss_params = &eth->rss_params;
+	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
+	int i;
+
+	if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+	    rxfh->hfunc != ETH_RSS_HASH_TOP)
+		return -EOPNOTSUPP;
+
+	if (rxfh->key) {
+		memcpy(rss_params->hash_key, rxfh->key,
+		       sizeof(rss_params->hash_key));
+		for (i = 0; i < MTK_RSS_HASH_KEYSIZE / sizeof(u32); i++)
+			mtk_w32(eth, rss_params->hash_key[i],
+				MTK_RSS_HASH_KEY_DW(reg_map, i));
+	}
+
+	if (rxfh->indir) {
+		for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE; i++)
+			rss_params->indirection_table[i] = rxfh->indir[i];
+		for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE / 16; i++)
+			mtk_w32(eth, mtk_rss_indr_table(rss_params, i),
+				MTK_RSS_INDR_TABLE_DW(reg_map, i));
+	}
+
+	return 0;
+}
+
 static u16 mtk_select_queue(struct net_device *dev, struct sk_buff *skb,
 			    struct net_device *sb_dev)
 {
@@ -4766,6 +4995,10 @@ static const struct ethtool_ops mtk_ethtool_ops = {
 	.set_rxnfc		= mtk_set_rxnfc,
 	.get_eee		= mtk_get_eee,
 	.set_eee		= mtk_set_eee,
+	.get_rxfh_key_size	= mtk_get_rxfh_key_size,
+	.get_rxfh_indir_size	= mtk_get_rxfh_indir_size,
+	.get_rxfh		= mtk_get_rxfh,
+	.set_rxfh		= mtk_set_rxfh,
 };
 
 static const struct net_device_ops mtk_netdev_ops = {
@@ -4955,7 +5188,7 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
 	eth->netdev[id]->features |= eth->soc->hw_features;
 	eth->netdev[id]->ethtool_ops = &mtk_ethtool_ops;
 
-	eth->netdev[id]->irq = eth->irq[MTK_FE_IRQ_SHARED];
+	eth->netdev[id]->irq = eth->irq_fe[MTK_FE_IRQ_SHARED];
 	eth->netdev[id]->dev.of_node = np;
 
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628))
@@ -5066,6 +5299,7 @@ static int mtk_probe(struct platform_device *pdev)
 	struct resource *res = NULL;
 	struct device_node *mac_np;
 	struct mtk_eth *eth;
+	char *irqname;
 	int err, i;
 
 	eth = devm_kzalloc(&pdev->dev, sizeof(*eth), GFP_KERNEL);
@@ -5197,10 +5431,16 @@ static int mtk_probe(struct platform_device *pdev)
 		}
 	}
 
-	err = mtk_get_irqs(pdev, eth);
+	err = mtk_get_irqs_fe(pdev, eth);
 	if (err)
 		goto err_wed_exit;
 
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_PDMA_INT)) {
+		err = mtk_get_irqs_pdma(pdev, eth);
+		if (err)
+			goto err_wed_exit;
+	}
+
 	for (i = 0; i < ARRAY_SIZE(eth->clks); i++) {
 		eth->clks[i] = devm_clk_get(eth->dev,
 					    mtk_clks_source_name[i]);
@@ -5243,23 +5483,56 @@ static int mtk_probe(struct platform_device *pdev)
 		}
 	}
 
+	err = mtk_napi_init(eth);
+	if (err)
+		goto err_free_dev;
+
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT)) {
-		err = devm_request_irq(eth->dev, eth->irq[MTK_FE_IRQ_SHARED],
+		err = devm_request_irq(eth->dev, eth->irq_fe[MTK_FE_IRQ_SHARED],
 				       mtk_handle_irq, 0,
 				       dev_name(eth->dev), eth);
 	} else {
-		err = devm_request_irq(eth->dev, eth->irq[MTK_FE_IRQ_TX],
+		irqname = devm_kasprintf(eth->dev, GFP_KERNEL, "%s TX",
+					 dev_name(eth->dev));
+		err = devm_request_irq(eth->dev, eth->irq_fe[MTK_FE_IRQ_TX],
 				       mtk_handle_irq_tx, 0,
-				       dev_name(eth->dev), eth);
+				       irqname, eth);
 		if (err)
 			goto err_free_dev;
 
-		err = devm_request_irq(eth->dev, eth->irq[MTK_FE_IRQ_RX],
-				       mtk_handle_irq_rx, 0,
-				       dev_name(eth->dev), eth);
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_PDMA_INT)) {
+			irqname = devm_kasprintf(eth->dev, GFP_KERNEL, "%s PDMA RX %d",
+						 dev_name(eth->dev), 0);
+			err = devm_request_irq(eth->dev, eth->irq_pdma[0],
+					       mtk_handle_irq_rx, IRQF_SHARED,
+					       irqname, &eth->rx_napi[0]);
+			if (err)
+				goto err_free_dev;
+
+			if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+				for (i = 1; i < MTK_RX_RSS_NUM(eth); i++) {
+					irqname = devm_kasprintf(eth->dev, GFP_KERNEL,
+								 "%s PDMA RX %d",
+								 dev_name(eth->dev), i);
+					err = devm_request_irq(eth->dev,
+							       eth->irq_pdma[MTK_RSS_RING(i)],
+							       mtk_handle_irq_rx, IRQF_SHARED,
+							       irqname,
+							       &eth->rx_napi[MTK_RSS_RING(i)]);
+					if (err)
+						goto err_free_dev;
+				}
+			}
+		} else {
+			irqname = devm_kasprintf(eth->dev, GFP_KERNEL, "%s RX",
+						 dev_name(eth->dev));
+			err = devm_request_irq(eth->dev, eth->irq_fe[MTK_FE_IRQ_RX],
+					       mtk_handle_irq_rx, 0,
+					       irqname, &eth->rx_napi[0]);
+			if (err)
+				goto err_free_dev;
+		}
 	}
-	if (err)
-		goto err_free_dev;
 
 	/* No MT7628/88 support yet */
 	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) {
@@ -5300,7 +5573,7 @@ static int mtk_probe(struct platform_device *pdev)
 		} else
 			netif_info(eth, probe, eth->netdev[i],
 				   "mediatek frame engine at 0x%08lx, irq %d\n",
-				   eth->netdev[i]->base_addr, eth->irq[MTK_FE_IRQ_SHARED]);
+				   eth->netdev[i]->base_addr, eth->irq_fe[MTK_FE_IRQ_SHARED]);
 	}
 
 	/* we run 2 devices on the same DMA ring so we need a dummy device
@@ -5313,7 +5586,13 @@ static int mtk_probe(struct platform_device *pdev)
 		goto err_unreg_netdev;
 	}
 	netif_napi_add(eth->dummy_dev, &eth->tx_napi, mtk_napi_tx);
-	netif_napi_add(eth->dummy_dev, &eth->rx_napi, mtk_napi_rx);
+	netif_napi_add(eth->dummy_dev, &eth->rx_napi[0].napi, mtk_napi_rx);
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		for (i = 1; i < MTK_RX_RSS_NUM(eth); i++)
+			netif_napi_add(eth->dummy_dev, &eth->rx_napi[MTK_RSS_RING(i)].napi,
+				       mtk_napi_rx);
+	}
 
 	platform_set_drvdata(pdev, eth);
 	schedule_delayed_work(&eth->reset.monitor_work,
@@ -5357,7 +5636,12 @@ static void mtk_remove(struct platform_device *pdev)
 	mtk_hw_deinit(eth);
 
 	netif_napi_del(&eth->tx_napi);
-	netif_napi_del(&eth->rx_napi);
+	netif_napi_del(&eth->rx_napi[0].napi);
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		for (i = 1; i < MTK_RX_RSS_NUM(eth); i++)
+			netif_napi_del(&eth->rx_napi[MTK_RSS_RING(i)].napi);
+	}
 	mtk_cleanup(eth);
 	free_netdev(eth->dummy_dev);
 	mtk_mdio_cleanup(eth);
@@ -5370,6 +5654,7 @@ static const struct mtk_soc_data mt2701_data = {
 	.required_clks = MT7623_CLKS_BITMAP,
 	.required_pctl = true,
 	.version = 1,
+	.rss_num = 0,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5379,7 +5664,6 @@ static const struct mtk_soc_data mt2701_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID,
 		.dma_size = MTK_DMA_SIZE(2K),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5398,6 +5682,7 @@ static const struct mtk_soc_data mt7621_data = {
 	.ppe_num = 1,
 	.hash_offset = 2,
 	.foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
+	.rss_num = 0,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5407,7 +5692,6 @@ static const struct mtk_soc_data mt7621_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID,
 		.dma_size = MTK_DMA_SIZE(2K),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5428,6 +5712,7 @@ static const struct mtk_soc_data mt7622_data = {
 	.hash_offset = 2,
 	.has_accounting = true,
 	.foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
+	.rss_num = 0,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5437,7 +5722,6 @@ static const struct mtk_soc_data mt7622_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID,
 		.dma_size = MTK_DMA_SIZE(2K),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5457,6 +5741,7 @@ static const struct mtk_soc_data mt7623_data = {
 	.hash_offset = 2,
 	.foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
 	.disable_pll_modes = true,
+	.rss_num = 0,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5466,7 +5751,6 @@ static const struct mtk_soc_data mt7623_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID,
 		.dma_size = MTK_DMA_SIZE(2K),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5483,6 +5767,7 @@ static const struct mtk_soc_data mt7629_data = {
 	.required_pctl = false,
 	.has_accounting = true,
 	.version = 1,
+	.rss_num = 0,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5492,7 +5777,6 @@ static const struct mtk_soc_data mt7629_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID,
 		.dma_size = MTK_DMA_SIZE(2K),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5513,16 +5797,16 @@ static const struct mtk_soc_data mt7981_data = {
 	.hash_offset = 4,
 	.has_accounting = true,
 	.foe_entry_size = MTK_FOE_ENTRY_V2_SIZE,
+	.rss_num = 4,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma_v2),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
 		.dma_len_offset = 8,
-		.dma_size = MTK_DMA_SIZE(2K),
+		.dma_size = MTK_DMA_SIZE(4K),
 		.fq_dma_size = MTK_DMA_SIZE(2K),
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID_V2,
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
 		.dma_len_offset = 16,
@@ -5543,6 +5827,7 @@ static const struct mtk_soc_data mt7986_data = {
 	.hash_offset = 4,
 	.has_accounting = true,
 	.foe_entry_size = MTK_FOE_ENTRY_V2_SIZE,
+	.rss_num = 4,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma_v2),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
@@ -5552,7 +5837,6 @@ static const struct mtk_soc_data mt7986_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID_V2,
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
 		.dma_len_offset = 16,
@@ -5573,20 +5857,20 @@ static const struct mtk_soc_data mt7988_data = {
 	.hash_offset = 4,
 	.has_accounting = true,
 	.foe_entry_size = MTK_FOE_ENTRY_V3_SIZE,
+	.rss_num = 4,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma_v2),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
 		.dma_len_offset = 8,
-		.dma_size = MTK_DMA_SIZE(2K),
+		.dma_size = MTK_DMA_SIZE(4K),
 		.fq_dma_size = MTK_DMA_SIZE(4K),
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma_v2),
-		.irq_done_mask = MTK_RX_DONE_INT_V2,
 		.dma_l4_valid = RX_DMA_L4_VALID_V2,
 		.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
 		.dma_len_offset = 8,
-		.dma_size = MTK_DMA_SIZE(2K),
+		.dma_size = MTK_DMA_SIZE(1K),
 	},
 };
 
@@ -5597,6 +5881,7 @@ static const struct mtk_soc_data rt5350_data = {
 	.required_clks = MT7628_CLKS_BITMAP,
 	.required_pctl = false,
 	.version = 1,
+	.rss_num = 0,
 	.tx = {
 		.desc_size = sizeof(struct mtk_tx_dma),
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5605,7 +5890,6 @@ static const struct mtk_soc_data rt5350_data = {
 	},
 	.rx = {
 		.desc_size = sizeof(struct mtk_rx_dma),
-		.irq_done_mask = MTK_RX_DONE_INT,
 		.dma_l4_valid = RX_DMA_L4_VALID_PDMA,
 		.dma_max_len = MTK_TX_DMA_BUF_LEN,
 		.dma_len_offset = 16,
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index 334625814b97..987846d46151 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -76,6 +76,8 @@
 #define	MTK_HW_LRO_BW_THRE		3000
 #define	MTK_HW_LRO_REPLACE_DELTA	1000
 #define	MTK_HW_LRO_SDL_REMAIN_ROOM	1522
+#define MTK_RSS_HASH_KEYSIZE		40
+#define MTK_RSS_MAX_INDIRECTION_TABLE	128
 
 /* Frame Engine Global Configuration */
 #define MTK_FE_GLO_CFG(x)	(((x) == MTK_GMAC3_ID) ? 0x24 : 0x00)
@@ -97,6 +99,8 @@
 #define MTK_GDM1_AF		BIT(28)
 #define MTK_GDM2_AF		BIT(29)
 
+#define MTK_PDMA_IRQ_NUM	(4)
+
 /* PDMA HW LRO Alter Flow Timer Register */
 #define MTK_PDMA_LRO_ALT_REFRESH_TIMER	0x1c
 
@@ -179,7 +183,10 @@
 
 /* PDMA HW LRO Control Registers */
 #define MTK_PDMA_LRO_CTRL_DW0	0x980
+#define MTK_HW_LRO_RING_NUM(eth)		(mtk_is_netsys_v3_or_greater(eth) ? 4 : 3)
 #define MTK_LRO_EN			BIT(0)
+#define MTK_NON_LRO_MULTI_EN		BIT(2)
+#define MTK_LRO_DLY_INT_EN		BIT(5)
 #define MTK_L3_CKS_UPD_EN		BIT(7)
 #define MTK_L3_CKS_UPD_EN_V2		BIT(19)
 #define MTK_LRO_ALT_PKT_CNT_MODE	BIT(21)
@@ -198,6 +205,19 @@
 #define MTK_MULTI_EN		BIT(10)
 #define MTK_PDMA_SIZE_8DWORDS	(1 << 4)
 
+/* PDMA RSS Control Registers */
+#define MTK_RX_NAPI_NUM			(4)
+#define MTK_RX_RSS_NUM(eth)		(eth->soc->rss_num)
+#define MTK_RSS_RING(x)			(x)
+#define MTK_RSS_EN			BIT(0)
+#define MTK_RSS_CFG_REQ			BIT(2)
+#define MTK_RSS_IPV6_STATIC_HASH	(0x7 << 8)
+#define MTK_RSS_IPV4_STATIC_HASH	(0x7 << 12)
+#define MTK_RSS_HASH_KEY_DW(reg_map, x)		(reg_map->pdma.rss_glo_cfg + \
+						0x20 + ((x) * 0x4))
+#define MTK_RSS_INDR_TABLE_DW(reg_map, x)	(reg_map->pdma.rss_glo_cfg + \
+						0x50 + ((x) * 0x4))
+
 /* PDMA Global Configuration Register */
 #define MTK_PDMA_LRO_SDL	0x3000
 #define MTK_RX_CFG_SDL_OFFSET	16
@@ -209,6 +229,7 @@
 /* PDMA Delay Interrupt Register */
 #define MTK_PDMA_DELAY_RX_MASK		GENMASK(15, 0)
 #define MTK_PDMA_DELAY_RX_EN		BIT(15)
+#define MTK_PDMA_DELAY_RX_RING_SHIFT	16
 #define MTK_PDMA_DELAY_RX_PINT_SHIFT	8
 #define MTK_PDMA_DELAY_RX_PTIME_SHIFT	0
 
@@ -229,14 +250,15 @@
 #define MTK_RING_MYIP_VLD		BIT(9)
 
 /* PDMA HW LRO Ring Control Registers */
-#define MTK_LRO_RX_RING0_CTRL_DW1	0xb28
-#define MTK_LRO_RX_RING0_CTRL_DW2	0xb2c
-#define MTK_LRO_RX_RING0_CTRL_DW3	0xb30
-#define MTK_LRO_CTRL_DW1_CFG(x)		(MTK_LRO_RX_RING0_CTRL_DW1 + (x * 0x40))
-#define MTK_LRO_CTRL_DW2_CFG(x)		(MTK_LRO_RX_RING0_CTRL_DW2 + (x * 0x40))
-#define MTK_LRO_CTRL_DW3_CFG(x)		(MTK_LRO_RX_RING0_CTRL_DW3 + (x * 0x40))
+#define MTK_LRO_CTRL_DW1_CFG(reg_map, x)	(reg_map->pdma.lro_ring_ctrl_dw1 + \
+						((x) * 0x40))
+#define MTK_LRO_CTRL_DW2_CFG(reg_map, x)	(reg_map->pdma.lro_ring_ctrl_dw1 + \
+						0x4 + ((x) * 0x40))
+#define MTK_LRO_CTRL_DW3_CFG(reg_map, x)	(reg_map->pdma.lro_ring_ctrl_dw1 + \
+						0x8 + ((x) * 0x40))
 #define MTK_RING_AGE_TIME_L		((MTK_HW_LRO_AGE_TIME & 0x3ff) << 22)
 #define MTK_RING_AGE_TIME_H		((MTK_HW_LRO_AGE_TIME >> 10) & 0x3f)
+#define MTK_RING_PSE_MODE		BIT(6)
 #define MTK_RING_AUTO_LERAN_MODE	(3 << 6)
 #define MTK_RING_VLD			BIT(8)
 #define MTK_RING_MAX_AGG_TIME		((MTK_HW_LRO_AGG_TIME & 0xffff) << 10)
@@ -290,7 +312,20 @@
 #define FC_THRES_MIN		0x4444
 
 /* QDMA Interrupt Status Register */
-#define MTK_RX_DONE_DLY		BIT(30)
+#define MTK_RX_DONE_INT_V1(ring_no) \
+	( \
+		(ring_no) ? \
+		BIT(24 + (ring_no)) : \
+		BIT(30) \
+	)
+
+#define MTK_RX_DONE_INT_V2(ring_no)	BIT(24 + (ring_no))
+
+#define MTK_RX_DONE_INT(eth, ring_no)		\
+	(mtk_is_netsys_v3_or_greater(eth) ?  \
+	 MTK_RX_DONE_INT_V2(ring_no) : \
+	 MTK_RX_DONE_INT_V1(ring_no))
+
 #define MTK_TX_DONE_DLY		BIT(28)
 #define MTK_RX_DONE_INT3	BIT(19)
 #define MTK_RX_DONE_INT2	BIT(18)
@@ -300,11 +335,8 @@
 #define MTK_TX_DONE_INT2	BIT(2)
 #define MTK_TX_DONE_INT1	BIT(1)
 #define MTK_TX_DONE_INT0	BIT(0)
-#define MTK_RX_DONE_INT		MTK_RX_DONE_DLY
 #define MTK_TX_DONE_INT		MTK_TX_DONE_DLY
 
-#define MTK_RX_DONE_INT_V2	BIT(14)
-
 #define MTK_CDM_TXFIFO_RDY	BIT(7)
 
 /* QDMA Interrupt grouping registers */
@@ -942,6 +974,7 @@ struct mtk_tx_ring {
 	struct mtk_tx_dma *dma_pdma;	/* For MT7628/88 PDMA handling */
 	dma_addr_t phys_pdma;
 	int cpu_idx;
+	bool in_sram;
 };
 
 /* PDMA rx ring mode */
@@ -967,13 +1000,38 @@ struct mtk_rx_ring {
 	u16 buf_size;
 	u16 dma_size;
 	bool calc_idx_update;
+	bool in_sram;
 	u16 calc_idx;
 	u32 crx_idx_reg;
+	u32 ring_no;
 	/* page_pool */
 	struct page_pool *page_pool;
 	struct xdp_rxq_info xdp_q;
 };
 
+/* struct mtk_rss_params -	This is the structure holding parameters
+ *				for the RSS ring
+ * @hash_key			The element is used to record the
+ *				secret key for the RSS ring
+ * indirection_table		The element is used to record the
+ *				indirection table for the RSS ring
+ */
+struct mtk_rss_params {
+	u32		hash_key[MTK_RSS_HASH_KEYSIZE / sizeof(u32)];
+	u8		indirection_table[MTK_RSS_MAX_INDIRECTION_TABLE];
+};
+
+/* struct mtk_napi -	This is the structure holding NAPI-related information,
+ *			and a mtk_napi struct is binding to one interrupt group
+ * @napi:		The NAPI struct
+ * @rx_ring:		Pointer to the memory holding info about the RX ring
+ */
+struct mtk_napi {
+	struct napi_struct	napi;
+	struct mtk_eth		*eth;
+	struct mtk_rx_ring	*rx_ring;
+};
+
 enum mkt_eth_capabilities {
 	MTK_RGMII_BIT = 0,
 	MTK_TRGMII_BIT,
@@ -985,7 +1043,9 @@ enum mkt_eth_capabilities {
 	MTK_INFRA_BIT,
 	MTK_SHARED_SGMII_BIT,
 	MTK_HWLRO_BIT,
+	MTK_RSS_BIT,
 	MTK_SHARED_INT_BIT,
+	MTK_PDMA_INT_BIT,
 	MTK_TRGMII_MT7621_CLK_BIT,
 	MTK_QDMA_BIT,
 	MTK_SOC_MT7628_BIT,
@@ -1025,7 +1085,9 @@ enum mkt_eth_capabilities {
 #define MTK_INFRA		BIT_ULL(MTK_INFRA_BIT)
 #define MTK_SHARED_SGMII	BIT_ULL(MTK_SHARED_SGMII_BIT)
 #define MTK_HWLRO		BIT_ULL(MTK_HWLRO_BIT)
+#define MTK_RSS			BIT_ULL(MTK_RSS_BIT)
 #define MTK_SHARED_INT		BIT_ULL(MTK_SHARED_INT_BIT)
+#define MTK_PDMA_INT		BIT_ULL(MTK_PDMA_INT_BIT)
 #define MTK_TRGMII_MT7621_CLK	BIT_ULL(MTK_TRGMII_MT7621_CLK_BIT)
 #define MTK_QDMA		BIT_ULL(MTK_QDMA_BIT)
 #define MTK_SOC_MT7628		BIT_ULL(MTK_SOC_MT7628_BIT)
@@ -1117,15 +1179,15 @@ enum mkt_eth_capabilities {
 #define MT7981_CAPS  (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC2_GEPHY | \
 		      MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \
 		      MTK_MUX_U3_GMAC2_TO_QPHY | MTK_U3_COPHY_V2 | \
-		      MTK_RSTCTRL_PPE1 | MTK_SRAM)
+		      MTK_RSTCTRL_PPE1 | MTK_SRAM | MTK_PDMA_INT)
 
 #define MT7986_CAPS  (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \
 		      MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \
-		      MTK_RSTCTRL_PPE1 | MTK_SRAM)
+		      MTK_RSTCTRL_PPE1 | MTK_SRAM | MTK_PDMA_INT)
 
 #define MT7988_CAPS  (MTK_36BIT_DMA | MTK_GDM1_ESW | MTK_GMAC2_2P5GPHY | \
 		      MTK_MUX_GMAC2_TO_2P5GPHY | MTK_QDMA | MTK_RSTCTRL_PPE1 | \
-		      MTK_RSTCTRL_PPE2 | MTK_SRAM)
+		      MTK_RSTCTRL_PPE2 | MTK_SRAM | MTK_PDMA_INT | MTK_RSS)
 
 struct mtk_tx_dma_desc_info {
 	dma_addr_t	addr;
@@ -1223,6 +1285,7 @@ struct mtk_reg_map {
 struct mtk_soc_data {
 	const struct mtk_reg_map *reg_map;
 	u32             ana_rgc3;
+	u32		rss_num;
 	u64		caps;
 	u64		required_clks;
 	bool		required_pctl;
@@ -1270,7 +1333,8 @@ struct mtk_soc_data {
  *			dummy for NAPI to work
  * @netdev:		The netdev instances
  * @mac:		Each netdev is linked to a physical MAC
- * @irq:		The IRQ that we are using
+ * @irq_fe:		Array of IRQs of the frame engine
+ * @irq_pdma:		Array of IRQs of the PDMA used for RSS
  * @msg_enable:		Ethtool msg level
  * @ethsys:		The register map pointing at the range used to setup
  *			MII modes
@@ -1314,7 +1378,8 @@ struct mtk_eth {
 	struct net_device		*dummy_dev;
 	struct net_device		*netdev[MTK_MAX_DEVS];
 	struct mtk_mac			*mac[MTK_MAX_DEVS];
-	int				irq[MTK_FE_IRQ_NUM];
+	int				irq_fe[MTK_FE_IRQ_NUM];
+	int				irq_pdma[MTK_PDMA_IRQ_NUM];
 	u32				msg_enable;
 	unsigned long			sysclk;
 	struct regmap			*ethsys;
@@ -1327,7 +1392,8 @@ struct mtk_eth {
 	struct mtk_rx_ring		rx_ring[MTK_MAX_RX_RING_NUM];
 	struct mtk_rx_ring		rx_ring_qdma;
 	struct napi_struct		tx_napi;
-	struct napi_struct		rx_napi;
+	struct mtk_napi			rx_napi[MTK_RX_NAPI_NUM];
+	struct mtk_rss_params		rss_params;
 	void				*scratch_ring;
 	dma_addr_t			phy_scratch_ring;
 	void				*scratch_head[MTK_FQ_DMA_HEAD];
-- 
2.43.0



From lpieralisi at kernel.org  Fri Dec 19 07:16:09 2025
From: lpieralisi at kernel.org (Lorenzo Pieralisi)
Date: Fri, 19 Dec 2025 16:16:09 +0100
Subject: [PATCH] MAINTAINERS: Update the maintainers for ARM64 ACPI
In-Reply-To: <20251219144906.348353-1-guohanjun@huawei.com>
References: <20251219144906.348353-1-guohanjun@huawei.com>
Message-ID: <aUVsOXF75Sb7wL7n@lpieralisi>

On Fri, Dec 19, 2025 at 10:49:06PM +0800, Hanjun Guo wrote:
> ARM64 ACPI patches go via ARM64 tree, but the listed maintainers
> for ARM64 ACPI don't include Catalin and Will, and there is no
> F: line under the ARM64 architecture entry, so emails will not
> route to Catalin and Will in an automatic way.
> 
> Adding Catalin and Will to the maintainers entry for ARM64 ACPI
> to fix the problem, it will make life easy for merging ARM64 ACPI
> patches.
> 
> Adding new maintainer entries for ARM64 ACPI doesn't mean the review
> work will balance to the new maintainer, patches still need to be
> acked by currently listed folks (Lorenzo, Hanjun, Sudeep) before
> merging them.
> 
> Link: https://lore.kernel.org/linux-acpi/aS2ZTfS9YVO98Exe at willie-the-truck/
> Signed-off-by: Hanjun Guo <guohanjun at huawei.com>
> ---
>  MAINTAINERS | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 5b11839cba9d..6050d94a50ec 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -335,6 +335,8 @@ ACPI FOR ARM64 (ACPI/arm64)
>  M:	Lorenzo Pieralisi <lpieralisi at kernel.org>
>  M:	Hanjun Guo <guohanjun at huawei.com>
>  M:	Sudeep Holla <sudeep.holla at arm.com>
> +M:	Catalin Marinas <catalin.marinas at arm.com>
> +M:	Will Deacon <will at kernel.org>

:)

Acked-by: Lorenzo Pieralisi <lpieralisi at kernel.org>

>  L:	linux-acpi at vger.kernel.org
>  L:	linux-arm-kernel at lists.infradead.org (moderated for non-subscribers)
>  S:	Maintained
> -- 
> 2.25.1
> 


From jgg at nvidia.com  Fri Dec 19 07:16:08 2025
From: jgg at nvidia.com (Jason Gunthorpe)
Date: Fri, 19 Dec 2025 11:16:08 -0400
Subject: [PATCH v1 3/9] iommu/arm-smmu-v3: Store ASIDs and VMID in
 arm_smmu_master
In-Reply-To: <f7fa8725aab1fbd2c2a1d564e7493b16a586e88c.1766088962.git.nicolinc@nvidia.com>
References: <cover.1766088962.git.nicolinc@nvidia.com>
 <f7fa8725aab1fbd2c2a1d564e7493b16a586e88c.1766088962.git.nicolinc@nvidia.com>
Message-ID: <20251219151608.GE254720@nvidia.com>

On Thu, Dec 18, 2025 at 12:26:49PM -0800, Nicolin Chen wrote:
> Currently, ASID is allocated per smmu_domain, stored in the domain, and
> freed with the domain.
> 
> Practically, ASID is only used in a CD as an iotlb tag. Therefore, ASID
> doesn't really follow the life cycle of a domain but domain attachment.
> 
> On the other hand, the CD carrying ASID is installed to a device's STE.
> 
> This applies to the VMID as well, which is installed in an STE directly.
> 
> Since a device can only have one ASID per SSID and one VMID per SID, add
> an ASID array and VMID in the arm_smmu_master structure, to decouple the
> ASID/VMID from the domain structure.

I don't think this is entirely right..

When a S1 is attached to a master the master needs to store the VMID
it is using, as the VMID is global to the STE and effectively becomes
global to the master.

But the ASID should be stored in the invalidation list of the domain.

Jus search the list for the (instance, vmid) pair of the master to get
back the right ASID.

We don't need to store it again in another list, that's confusing.

Jason


From detlev.casanova at collabora.com  Fri Dec 19 07:15:51 2025
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Fri, 19 Dec 2025 10:15:51 -0500
Subject: [PATCH v7 00/17] media: rkvdec: Add support for VDPU381 and
 VDPU383
In-Reply-To: <219DE002-BE77-4D28-9BC6-9124F099F211@gmail.com>
References: <20251218232829.337811-1-detlev.casanova@collabora.com>
 <219DE002-BE77-4D28-9BC6-9124F099F211@gmail.com>
Message-ID: <47c45858-1af9-4614-b980-d8100a382a58@collabora.com>

Hi Piotr,

On 12/19/25 08:50, Piotr Oniszczuk wrote:
>
>> Wiadomo?? napisana przez Detlev Casanova <detlev.casanova at collabora.com> w dniu 19 gru 2025, o godz. 00:28:
>>
>> These variants are found respectively in the RK3588 and RK3576 SoCs.
>> This patch only adds support for H264 and H265 in both variants.
>>
>> As there is a considerable part of the code that can be shared with the
>> already supported rkvdec decoder driver, the support for these variants
>> is added here rather than writing a new driver.
>>
>> This patch set uses the newly introduced hevc_ext_sps_[ls]t_rps v4l2
>> controls for HEVC.
>> Therefore, a patched version of userpace tools is needed for HEVC
>> support (added for GStreamer[1] and in an early stage for FFmpeg[2]).
>>
>> The DTS changes can be found in another patch set: [3]
>>
>> [1]: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/9355
>> [2]: https://gitlab.collabora.com/detlev/ffmpeg
>> [3]: https://lore.kernel.org/all/20251020212009.8852-1-detlev.casanova at collabora.com/
>>
> Detlev,
>
> FYI:
>
> In my testbed with
>
> i. v7 of [1] on mainline 6.18.2
> ii ffmpeg8 v4l2_request [2]
> iii. mythv as player [3]
> iv. minimyth2 as distro [4]
> v. NO applied yours ffmpeg sps/rps hinting [5] (as i'm on ffmpeg8)
And [5] won't be compatible anymore actually, I'm waiting for the final 
version of the uapi to tackle that.
> I run set of my mpeg2/h264/hevc/vp8/vp9 samples on: rk3328. rk3399, rk3566, rk3576, rk3588 and h616 (just for brief test for potential cross-regressions)
>
> Results:
>
> a. rk3328: no any regressions; all samples are decoded ok
>
> b. rk3399: no any regressions; all samples are decoded ok
>
> c. rk3566: no any regressions (e.g. in vp9. v6 and older were regressing; v7 is ok)
VP9 improvement is expected as I added a missing reg_num multiplier in 
VP9 as spotted by Jonas.
> c.1 h264: all ok
> c.2 hevc: samples without long-term sps/rps: all ok.
> c.3 hevc: samples with long-tern sps/rps: v7 is a bit regressing here: it gives me sometimes kernel oops requiring hw. reset to bring decoder back to live.
> Exemplary oops: https://termbin.com/upju
> Older vers of your code were handling such cases without needs of hw. reset

The 3566 support doesn't need any driver changes, only device tree nodes 
using the "rockchip,rk3588-vdec" compatible ?

I'll check that oops, I haven't seen it yet.

>
> d. rk3576:
> d.1: h264: works ok - but randomly i'm getting playback with distortions like this: https://postimg.cc/Yh8Djc3L. it is avd. 1 per few playbacks.
> d.2: hevc: the same like c.1 and c.2
>
> e. rk3588
> e.1: h264: all ok
> e.2: hevc: the same like c.1 and c.2
>     
> g. h616 with cedrus: all ok.
>
> btw:
> Adding to [1] vp9 android code [6] offers me nice working vp9 hwdec accell on rk3566/3588.
>
> Great work!
Thank you, and thanks for your valuable testing !
>
> [1] https://gitlab.collabora.com/detlev/linux/-/commits/add-vdpu381-and-383-to-rkvdec-v7
> [2] https://code.ffmpeg.org/Kwiboo/FFmpeg/src/branch/v4l2-request-n8.0.1
> [3] https://github.com/MythTV/mythtv
> [4] https://github.com/warpme/minimyth2
> [5] https://gitlab.collabora.com/detlev/ffmpeg
> [6] https://github.com/dvab-sarma/android_kernel_rk_opi/commit/fd0b1b17cbdfcf0c15bc9f411cc7127105157e57
>     
>   
>
>
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip


From robh at kernel.org  Fri Dec 19 07:25:26 2025
From: robh at kernel.org (Rob Herring)
Date: Fri, 19 Dec 2025 09:25:26 -0600
Subject: [PATCH 0/4] Fix RP1 DeviceTree hierarchy and drop overlay support
In-Reply-To: <cover.1766077285.git.andrea.porta@suse.com>
References: <cover.1766077285.git.andrea.porta@suse.com>
Message-ID: <20251219152526.GA3333129-robh@kernel.org>

On Thu, Dec 18, 2025 at 08:09:05PM +0100, Andrea della Porta wrote:
> The current RP1 implementation is plagued by several issues, as follows:
> 
> - the node name for RP1 is too specific and should be generic instead
>   (see [1]).
> 
> - the fully defined DTS has its PCI hierarchy wrongly described. There
>   should be a PCI root port between the root complex and the endpoint
>   (see [1]).
> 
> - since CONFIG_PCI_DYNAMIC_OF_NODES can be dropped in the future
>   becoming an automatically enabled feature, it would be wise to not
>   depend on it (see [2]).
> 
> - overlay support has led to a lot of confusion. It's not really usable 
>   right now and users are not even used to it (see [3]).
> 
> This patch aims at solving the aforementioned problems by amending the
> PCI topology as follows:
> 
>   ...
>   pcie at 1000120000 {
>     ...
> 
>     pci at 0,0 {
>       device_type = "pci";
>       reg = <0x00 0x00 0x00 0x00 0x00>;
>       ...
> 
>       dev at 0,0 {
>         compatible = "pci1de4,1";
>         reg = <0x10000 0x00 0x00 0x00 0x00>;
>         ...
> 
>         pci-ep-bus at 1 {
>           compatible = "simple-bus";
>           ...
> 
>           /* peripherals child nodes */
>         }; 
>       }; 
>     }; 
>   }; 
> 
> The reg property is important since it permits the binding the OF
> device_node structure to the pci_dev, encoding the BDF in the upper
> portion of the address.
> 
> This patch also drops the overlay support in favor of the fully
> described DT while streamlining it as a result.
> 
> Links:
> [1] - https://lore.kernel.org/all/aTvz_OeVnciiqATz at apocalypse/
> [2] - https://lore.kernel.org/all/CAL_JsqJUzB71QdMcxJtNZ7raoPcK+SfTh7EVzGmk=syo8xLKQw at mail.gmail.com/
> [3] - https://lore.kernel.org/all/CAL_JsqJUzB71QdMcxJtNZ7raoPcK+SfTh7EVzGmk=syo8xLKQw at mail.gmail.com/
> 
> Andrea della Porta (4):
>   dt-bindings: misc: pci1de4,1: add required reg property for endpoint
>   misc: rp1: drop overlay support
>   arm64: dts: broadcom: bcm2712: fix RP1 endpoint PCI topology
>   arm64: dts: broadcom: rp1: drop RP1 overlay

Thanks for doing this.

Reviewed-by: Rob Herring <robh at kernel.org>


From robh at kernel.org  Fri Dec 19 07:27:43 2025
From: robh at kernel.org (Rob Herring)
Date: Fri, 19 Dec 2025 09:27:43 -0600
Subject: [PATCH v1 0/2] build full dtbs for BananaPi R3/R4(Pro)
In-Reply-To: <20251119175124.48947-1-linux@fw-web.de>
References: <20251119175124.48947-1-linux@fw-web.de>
Message-ID: <20251219152743.GA3410594-robh@kernel.org>

On Wed, Nov 19, 2025 at 06:51:21PM +0100, Frank Wunderlich wrote:
> From: Frank Wunderlich <frank-w at public-files.de>
> 
> Build devicetree binaries for testing overlays and providing users
> full dtb without using overlays for Bananapi R4 (pro) variants.
> 
> It is not required to build all possible combinations, only for
> common usecases and to test if all overlays can be applied.
> 
> This series is based on
> https://git.kernel.org/pub/scm/linux/kernel/git/mediatek/linux.git/log/?h=v6.18-next/dts64
> 
> Frank Wunderlich (2):
>   arm64: dts: mediatek: mt7986: add dtbs with applied overlays for
>     bpi-r3
>   arm64: dts: mediatek: mt7988: add dtbs with applied overlays for
>     bpi-r4 (pro)

Since there's been no movement on this, I've applied this series and the 
other patch and will send to Linus today.

Rob


From broonie at kernel.org  Fri Dec 19 07:29:42 2025
From: broonie at kernel.org (Mark Brown)
Date: Fri, 19 Dec 2025 15:29:42 +0000
Subject: [PATCH] kselftest/arm64: Support FORCE_TARGETS
Message-ID: <20251219-kselftest-arm64-force-targets-v1-1-cf72d6d27e99@kernel.org>

The top level kselftest Makefile supports an option FORCE_TARGETS which
causes any failures during the build to be propagated to the exit status
of the top level make, useful during build testing. Currently the recursion
done by the arm64 selftests ignores this option, meaning arm64 failures are
not reported via this mechanism. Add the logic to implement FORCE_TARGETS
so that it works for arm64.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 tools/testing/selftests/arm64/Makefile | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile
index c4c72ee2ef55..e456f3b62fa1 100644
--- a/tools/testing/selftests/arm64/Makefile
+++ b/tools/testing/selftests/arm64/Makefile
@@ -30,13 +30,15 @@ all:
 	@for DIR in $(ARM64_SUBTARGETS); do				\
 		BUILD_TARGET=$(OUTPUT)/$$DIR;			\
 		mkdir -p $$BUILD_TARGET;			\
-		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;		\
+		make OUTPUT=$$BUILD_TARGET -C $$DIR $@		\
+			$(if $(FORCE_TARGETS),|| exit); \
 	done
 
 install: all
 	@for DIR in $(ARM64_SUBTARGETS); do				\
 		BUILD_TARGET=$(OUTPUT)/$$DIR;			\
-		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;		\
+		make OUTPUT=$$BUILD_TARGET -C $$DIR $@		\
+			$(if $(FORCE_TARGETS),|| exit); \
 	done
 
 run_tests: all

---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20251219-kselftest-arm64-force-targets-2ba8cebd1748

Best regards,
--  
Mark Brown <broonie at kernel.org>



From mchehab+huawei at kernel.org  Fri Dec 19 07:30:40 2025
From: mchehab+huawei at kernel.org (Mauro Carvalho Chehab)
Date: Fri, 19 Dec 2025 16:30:40 +0100
Subject: [PATCH 03/12] ras: add estatus vendor handling and processing
In-Reply-To: <20251219144943.2798169-1-ahmed.tiba@arm.com>
References: <20251218170453.23be9049@foz.lan>
 <20251219144943.2798169-1-ahmed.tiba@arm.com>
Message-ID: <euhams5heiuaawxq4e5ty7iijuvwt5gvdx3flsm4npligjeulq@lv3cwekyb2o2>

On Fri, Dec 19, 2025 at 02:49:02PM +0000, Ahmed Tiba wrote:
> 
> On Wed, Dec 18, 2025 at 05:04:53PM +0100, Mauro Carvalho Chehab wrote:
> 
> >> Teach the estatus core how to walk CPER records and expose the vendor
> >> record notification path. This adds the section iteration helpers,
> >> the logging helpers that mirror the GHES behaviour, and the deferred
> >> work used to hand vendor GUIDs to interested drivers. No users switch
> >> over yet; this simply moves the common logic out of GHES so the next
> >> patches can wire it up.
> >>
> >> Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>
> >
> >...
> >
> >> +static bool estatus_handle_arm_hw_error(estatus_generic_data *gdata, int sev, bool sync)
> >
> > Huh?
> >
> > This is a CPER record from GHES. Why are you moving CPER code out
> > of ghes.c, placing in a file named estatus.c? Doesn't make much
> > sense on my eyes...
> >
> > Same applies to to other GHES CPER record types.
> 
> GHES still fills in the CPER record, but the parsing and logging logic is
> shared with the new DeviceTree provider so I pulled those helpers into the
> estatus core. 

I see, but this is not really estatus core. Instead, it is part of GHES CPER
handling logic, which is defined at ACPI and UEFI specs. moving it to estatus
sounds odd, at least on my eyes.

Perhaps I'm failing to see where at ACPI/UEFI specs how CPER would be
integrated with an OpenFirmware approach to handle CPER without GHES.
Care to point to the relevant specs, if any?

> Both providers already call into the same notifier chain and
> memory-pool helpers; this patch just moves the generic CPER walking routines
> next to the rest of the common code so the DT path doesn?t have to grow its
> own copy. If you?d prefer a different file layout or naming to make that
> intent clearer, I?m happy to adjust.

Moving the code from ghes.c to estatus.c or to elsewhere shouldn't make any
difference, as the DT handling logic could simply be calling the functions
from ghes.c (or estatus.c). I fail to see why they need to be moved.

-- 
Thanks,
Mauro


From steven.price at arm.com  Fri Dec 19 07:31:21 2025
From: steven.price at arm.com (Steven Price)
Date: Fri, 19 Dec 2025 15:31:21 +0000
Subject: [PATCH 3/4] drm/panthor: Implement reading shader_present from
 nvmem
In-Reply-To: <20251217-mt8196-shader-present-v1-3-f6f8f3aa1e93@collabora.com>
References: <20251217-mt8196-shader-present-v1-0-f6f8f3aa1e93@collabora.com>
 <20251217-mt8196-shader-present-v1-3-f6f8f3aa1e93@collabora.com>
Message-ID: <bdf5b4f9-d6f5-419d-9465-4f722bac06ef@arm.com>

On 17/12/2025 17:03, Nicolas Frattaroli wrote:
> On some platforms, notably MediaTek MT8196, the shader_present bitmask
> in the Mali GPU register for it has cores enabled that may be faulty.
> The true shader_present bitmask is found in an efuse instead.
> 
> Implement reading shader_present from an nvmem cell if one is present,
> falling back to the Mali register if it's absent. The error codes are
> trickled up through to the probe function so that probe deferral works.
> 
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>

Reviewed-by: Steven Price <steven.price at arm.com>

[Although I really hope other vendors don't do this - the hardware is
broken!]

Although one NIT below if you respin for other reasons...

> ---
>  drivers/gpu/drm/panthor/panthor_hw.c | 63 ++++++++++++++++++++++++++++++++----
>  1 file changed, 57 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c
> index 87ebb7ae42c4..eb44c8b108aa 100644
> --- a/drivers/gpu/drm/panthor/panthor_hw.c
> +++ b/drivers/gpu/drm/panthor/panthor_hw.c
> @@ -1,6 +1,7 @@
>  // SPDX-License-Identifier: GPL-2.0 or MIT
>  /* Copyright 2025 ARM Limited. All rights reserved. */
>  
> +#include <linux/nvmem-consumer.h>
>  #include <drm/drm_print.h>
>  
>  #include "panthor_device.h"
> @@ -109,7 +110,52 @@ static char *get_gpu_model_name(struct panthor_device *ptdev)
>  	return "(Unknown Mali GPU)";
>  }
>  
> -static void panthor_gpu_info_init(struct panthor_device *ptdev)
> +static int overload_shader_present(struct panthor_device *ptdev)
> +{
> +	struct device *dev = ptdev->base.dev;
> +	struct nvmem_cell *cell = nvmem_cell_get(dev, "shader-present");
> +	ssize_t len;
> +	void *buf;
> +	int ret;
> +
> +	if (IS_ERR(cell)) {
> +		/* On platforms without this cell, use the Mali register */
> +		if (PTR_ERR(cell) == -ENOENT)
> +			return 0;
> +
> +		return dev_err_probe(dev, PTR_ERR(cell),
> +				     "Failed to get shader-present nvmem cell\n");
> +	}
> +
> +	buf = nvmem_cell_read(cell, &len);
> +	if (IS_ERR(buf)) {
> +		ret = dev_err_probe(dev, PTR_ERR(buf),
> +				    "Failed to read shader-present nvmem cell\n");
> +		goto err_put_cell;
> +	}
> +
> +	if (!len || len > 8) {
> +		ret = dev_err_probe(dev, -EINVAL, "shader-present cell can't be length %ld\n",
> +				    len);
> +		goto err_free;
> +	}
> +
> +	memcpy(&ptdev->gpu_info.shader_present, buf, len);
> +
> +	kfree(buf);
> +	nvmem_cell_put(cell);
> +
> +	return 0;
> +
> +err_free:
> +	kfree(buf);
> +err_put_cell:
> +	nvmem_cell_put(cell);
> +
> +	return ret;
> +}

Rather than repeating the clean up, you can do something like:

{
	void *buf = NULL;
	int ret = 0

	if (IS_ERR(cell)) {
		ret = dev_err_probe(...);
		goto out;
	}

	buf = nvmem_cell_read();
	if (IS_ERR(buf)) {
		ret = dev_err_probe(...);
		goto out;
	}

	if (!len || len > 8) {
		ret = dev_err_probe(...);
		goto out;
	}

	memcpy();

out:
	if (!IS_ERR(buf))
		kfree(buf);
	if (!IS_ERR(cell))
		nvmem_cell_put(cell);

	return ret;
}

That avoids mistakes when adding a new operation into the sequence. Or
you can use the fancy new cleanup helpers, but that feels overkill here.
But equally I'm ok if you leave the code as is - it's simple enough and
the conversation can be done later if we need it.

Thanks,
Steve

> +
> +static int panthor_gpu_info_init(struct panthor_device *ptdev)
>  {
>  	unsigned int i;
>  
> @@ -143,13 +189,18 @@ static void panthor_gpu_info_init(struct panthor_device *ptdev)
>  		ptdev->gpu_info.tiler_present = gpu_read64(ptdev, GPU_TILER_PRESENT);
>  		ptdev->gpu_info.l2_present = gpu_read64(ptdev, GPU_L2_PRESENT);
>  	}
> +
> +	return overload_shader_present(ptdev);
>  }
>  
> -static void panthor_hw_info_init(struct panthor_device *ptdev)
> +static int panthor_hw_info_init(struct panthor_device *ptdev)
>  {
>  	u32 major, minor, status;
> +	int ret;
>  
> -	panthor_gpu_info_init(ptdev);
> +	ret = panthor_gpu_info_init(ptdev);
> +	if (ret)
> +		return ret;
>  
>  	major = GPU_VER_MAJOR(ptdev->gpu_info.gpu_id);
>  	minor = GPU_VER_MINOR(ptdev->gpu_info.gpu_id);
> @@ -172,6 +223,8 @@ static void panthor_hw_info_init(struct panthor_device *ptdev)
>  		 "shader_present=0x%0llx l2_present=0x%0llx tiler_present=0x%0llx",
>  		 ptdev->gpu_info.shader_present, ptdev->gpu_info.l2_present,
>  		 ptdev->gpu_info.tiler_present);
> +
> +	return 0;
>  }
>  
>  static int panthor_hw_bind_device(struct panthor_device *ptdev)
> @@ -218,7 +271,5 @@ int panthor_hw_init(struct panthor_device *ptdev)
>  	if (ret)
>  		return ret;
>  
> -	panthor_hw_info_init(ptdev);
> -
> -	return 0;
> +	return panthor_hw_info_init(ptdev);
>  }
> 



From m.felsch at pengutronix.de  Fri Dec 19 07:35:37 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Fri, 19 Dec 2025 16:35:37 +0100
Subject: [PATCH v7 1/3] dt-bindings: soc: imx93-media-blk-ctrl: Add PDFC
 subnode to schema and example
In-Reply-To: <7127040f-55ab-4bfa-8795-1df76085470c@kernel.org>
References: <20251202-v6-18-topic-imx93-parallel-display-v7-0-2cce31d64608@pengutronix.de>
 <20251202-v6-18-topic-imx93-parallel-display-v7-1-2cce31d64608@pengutronix.de>
 <705773fc-5aba-4bff-b05e-272e1cd0262c@nxp.com>
 <20251215161706.2ea3wtu3xlwcxxar@pengutronix.de>
 <7127040f-55ab-4bfa-8795-1df76085470c@kernel.org>
Message-ID: <20251219153537.zgxcokyhcqerw4jp@pengutronix.de>

Hi Krzysztof, Rob,

On 25-12-18, Krzysztof Kozlowski wrote:
> On 15/12/2025 17:17, Marco Felsch wrote:
> > Hi Liu,
> > 
> > On 25-12-08, Liu Ying wrote:
> >> Hi Marco,
> >>
> >> On 12/02/2025, Marco Felsch wrote:
> >>> From: Liu Ying <victor.liu at nxp.com>
> >>>
> >>> i.MX93 SoC mediamix blk-ctrl contains one DISPLAY_MUX register which
> >>> configures parallel display format by using the "PARALLEL_DISP_FORMAT"
> >>> field. Document the Parallel Display Format Configuration(PDFC) subnode
> >>> and add the subnode to example.
> >>>
> >>> Signed-off-by: Liu Ying <victor.liu at nxp.com>
> >>> [m.felsch at pengutronix.de: port to v6.18-rc1]
> >>> [m.felsch at pengutronix.de: add bus-width]
> >>> Signed-off-by: Marco Felsch <m.felsch at pengutronix.de>
> >>> ---
> >>>  .../bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml | 92 ++++++++++++++++++++++
> >>>  1 file changed, 92 insertions(+)
> >>>
> >>> diff --git a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> >>> index 34aea58094e55365a2f9c86092f637e533f954ff..6e2d86d9341c75108b492bcbabc8a560d8e707cd 100644
> >>> --- a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> >>> +++ b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
> >>> @@ -26,6 +26,12 @@ properties:
> >>>    reg:
> >>>      maxItems: 1
> >>>  
> >>> +  '#address-cells':
> >>> +    const: 1
> >>> +
> >>> +  '#size-cells':
> >>> +    const: 1
> >>> +
> >>>    '#power-domain-cells':
> >>>      const: 1
> >>>  
> >>> @@ -40,6 +46,60 @@ properties:
> >>>      minItems: 8
> >>>      maxItems: 10
> >>>  
> >>> +  bridge at 60:
> >>
> >> The dependency patch series mentioned in cover letter has two links in it's
> >> cover letter.  Reading the patch sets pointed by the two links, we may find
> >> Krzysztof's comments - the child nodes of the blk-ctrl should be completely
> >> documented.
> > 
> > Thanks for pointing this out.
> > 
> > @Krzysztof
> > Requesting to add everything seems not feasible if everything added
> > should be tested too.
> > I don't see why everything should be added in one step, since the base
> > .dtsi isn't added in one step too.
> 
> Because otherwise we do not see entire picture and people post incorrect
> bindings, claiming they are complete picture, like messing nodes with
> addressing and nodes without. So sure, if you do not want to post
> complete picture, we cannot review that complete picture, therefore YOU
> MUST POST CORRECT CODE.
> 
> I will not be taking excuses later "we did not know that such code is
> not allowed". You must know all rules.

We discussed the ranges/reg usage internally as well with the following
outcome:

- Situation

  With i.MX8M SoCs NXP introduced MIX domains. Each domain has a so
  called BLK-CTRL IP. There is no common register layout for the
  BLK-CTRL IPs. In addition to this, the register fields within one
  register may not related to the same IP. Please see my below example:
  
  The DISP_MUX register configures the DPI output routed to physical
  SoC pads as well as the internal MIPI-DSI DPI behavior. This PDFC
  bridge binding is only interested in the first part, not the 2nd.

  In other words, the BLK-CTRL IP can be seen as a bunch of loose
  register fields.

- Our outcome

  To be future compatible and extentible, we believe that the best
  abstraction is the syscon, no mappings (no ranges/regs). A BLK-CTRL
  sub-device has no address, just the node name. The driver needs to rely
  on the syscon parent device. All register(-field) handling is done
  within the sub-device driver.

  This way new functionallity like MIPI-DSI PLL clock provider driver
  can be added easily.

I will adapt this patchset accordingly, if you agree to rely on the
syscon (no regs/ranges).

Regards,
  Marco


> 
> 
> Best regards,
> Krzysztof
> 

-- 
#gernperDu 
#CallMeByMyFirstName

Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | https://www.pengutronix.de/ |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-9    |


From Frank.li at nxp.com  Fri Dec 19 07:45:07 2025
From: Frank.li at nxp.com (Frank Li)
Date: Fri, 19 Dec 2025 10:45:07 -0500
Subject: [PATCH] phy: fsl-imx8mq-usb: change ssc_range value for i.MX8MQ
In-Reply-To: <20251219081354.3806806-1-xu.yang_2@nxp.com>
References: <20251219081354.3806806-1-xu.yang_2@nxp.com>
Message-ID: <aUVzA+c6V+50TETP@lizhi-Precision-Tower-5810>

On Fri, Dec 19, 2025 at 04:13:54PM +0800, Xu Yang wrote:
> According to IC engineer suggestion, set ssc_range as -4003 ppm
> will have more tolerance for EMI, and suitable for more boards.
> Besides, it's confirmed that with this setting the TX SSC test
> will pass on one customer board.

nit: next time wrap at 75 char.

>
> Signed-off-by: Li Jun <jun.li at nxp.com>
> Signed-off-by: Xu Yang <xu.yang_2 at nxp.com>
> ---

Reviewed-by: Frank Li <Frank.Li at nxp.com>

>  drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 7 +++++++
>  1 file changed, 7 insertions(+)
>
> diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> index cb2392008ad2..02d9af409b08 100644
> --- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> +++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> @@ -18,6 +18,10 @@
>  #define PHY_CTRL0_FSEL_MASK		GENMASK(10, 5)
>  #define PHY_CTRL0_FSEL_24M		0x2a
>  #define PHY_CTRL0_FSEL_100M		0x27
> +#define PHY_CTRL0_SSC_RANGE_MASK	GENMASK(23, 21)
> +#define PHY_CTRL0_SSC_RANGE_4003PPM	0x2
> +#define PHY_CTRL0_SSC_RANGE_4492PPM	0x1
> +#define PHY_CTRL0_SSC_RANGE_4980PPM	0x0
>
>  #define PHY_CTRL1			0x4
>  #define PHY_CTRL1_RESET			BIT(0)
> @@ -780,6 +784,9 @@ static int imx8mq_usb_phy_init(struct phy *phy)
>
>  	value = readl(imx_phy->base + PHY_CTRL0);
>  	value |= PHY_CTRL0_REF_SSP_EN;
> +	value &= ~PHY_CTRL0_SSC_RANGE_MASK;
> +	value |= FIELD_PREP(PHY_CTRL0_SSC_RANGE_MASK,
> +			    PHY_CTRL0_SSC_RANGE_4003PPM);
>  	writel(value, imx_phy->base + PHY_CTRL0);
>
>  	value = readl(imx_phy->base + PHY_CTRL2);
> --
> 2.34.1
>
>
> --
> linux-phy mailing list
> linux-phy at lists.infradead.org
> https://lists.infradead.org/mailman/listinfo/linux-phy


From Liam.Howlett at oracle.com  Fri Dec 19 07:47:52 2025
From: Liam.Howlett at oracle.com (Liam R. Howlett)
Date: Fri, 19 Dec 2025 10:47:52 -0500
Subject: [PATCH v3 1/5] mm: rmap: support batched checks of the
 references for large folios
In-Reply-To: <24b9d33acad627997febe9b61d398fc53739a333.1766121341.git.baolin.wang@linux.alibaba.com>
References: <cover.1766121341.git.baolin.wang@linux.alibaba.com>
 <24b9d33acad627997febe9b61d398fc53739a333.1766121341.git.baolin.wang@linux.alibaba.com>
Message-ID: <x2s3l56rqwgcpkhpu77pjt65tfwgmchuy4fuyrj7h7uag5gja3@c3jbws4quxrd>

* Baolin Wang <baolin.wang at linux.alibaba.com> [251219 01:03]:
> Currently, folio_referenced_one() always checks the young flag for each PTE
> sequentially, which is inefficient for large folios. This inefficiency is
> especially noticeable when reclaiming clean file-backed large folios, where
> folio_referenced() is observed as a significant performance hotspot.
> 
> Moreover, on Arm64 architecture, which supports contiguous PTEs, there is already
> an optimization to clear the young flags for PTEs within a contiguous range.
> However, this is not sufficient. We can extend this to perform batched operations
> for the entire large folio (which might exceed the contiguous range: CONT_PTE_SIZE).
> 
> Introduce a new API: clear_flush_young_ptes() to facilitate batched checking
> of the young flags and flushing TLB entries, thereby improving performance
> during large folio reclamation. And it will be overridden by the architecture
> that implements a more efficient batch operation in the following patches.
> 
> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
> ---
>  include/linux/mmu_notifier.h |  9 +++++----
>  include/linux/pgtable.h      | 35 +++++++++++++++++++++++++++++++++++
>  mm/rmap.c                    | 29 +++++++++++++++++++++++++++--
>  3 files changed, 67 insertions(+), 6 deletions(-)
> 
> diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h
> index d1094c2d5fb6..be594b274729 100644
> --- a/include/linux/mmu_notifier.h
> +++ b/include/linux/mmu_notifier.h
> @@ -515,16 +515,17 @@ static inline void mmu_notifier_range_init_owner(
>  	range->owner = owner;
>  }
>  
> -#define ptep_clear_flush_young_notify(__vma, __address, __ptep)		\
> +#define ptep_clear_flush_young_notify(__vma, __address, __ptep, __nr)	\
>  ({									\
>  	int __young;							\
>  	struct vm_area_struct *___vma = __vma;				\
>  	unsigned long ___address = __address;				\
> -	__young = ptep_clear_flush_young(___vma, ___address, __ptep);	\
> +	unsigned int ___nr = __nr;					\
> +	__young = clear_flush_young_ptes(___vma, ___address, __ptep, ___nr);	\
>  	__young |= mmu_notifier_clear_flush_young(___vma->vm_mm,	\
>  						  ___address,		\
>  						  ___address +		\
> -							PAGE_SIZE);	\
> +						nr * PAGE_SIZE);	\

Did you mean nr * PAGE_SIZE here?  I think it should be __nr or ___nr?
I think this nr variable works because it exists where this macro is
expanded?

I am also not sure why you have ___nr  at all?

>  	__young;							\
>  })
>  
> @@ -650,7 +651,7 @@ static inline void mmu_notifier_subscriptions_destroy(struct mm_struct *mm)
>  
>  #define mmu_notifier_range_update_to_read_only(r) false
>  
> -#define ptep_clear_flush_young_notify ptep_clear_flush_young
> +#define ptep_clear_flush_young_notify clear_flush_young_ptes
>  #define pmdp_clear_flush_young_notify pmdp_clear_flush_young
>  #define ptep_clear_young_notify ptep_test_and_clear_young
>  #define pmdp_clear_young_notify pmdp_test_and_clear_young
> diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
> index b13b6f42be3c..7e659f4171e2 100644
> --- a/include/linux/pgtable.h
> +++ b/include/linux/pgtable.h
> @@ -947,6 +947,41 @@ static inline void wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
>  }
>  #endif
>  
> +#ifndef clear_flush_young_ptes
> +/**
> + * clear_flush_young_ptes - Clear the access bit and perform a TLB flush for PTEs
> + *			    that map consecutive pages of the same folio.
> + * @vma: The virtual memory area the pages are mapped into.
> + * @addr: Address the first page is mapped at.
> + * @ptep: Page table pointer for the first entry.
> + * @nr: Number of entries to clear access bit.
> + *
> + * May be overridden by the architecture; otherwise, implemented as a simple
> + * loop over ptep_clear_flush_young().
> + *
> + * Note that PTE bits in the PTE range besides the PFN can differ. For example,
> + * some PTEs might be write-protected.
> + *
> + * Context: The caller holds the page table lock.  The PTEs map consecutive
> + * pages that belong to the same folio.  The PTEs are all in the same PMD.
> + */
> +static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
> +					 unsigned long addr, pte_t *ptep,
> +					 unsigned int nr)
This is where nr is defined                         ^^^^^

> +{
> +	int young;
> +
> +	young = ptep_clear_flush_young(vma, addr, ptep);
> +	while (--nr) {
> +		ptep++;
> +		addr += PAGE_SIZE;
> +		young |= ptep_clear_flush_young(vma, addr, ptep);
> +	}
> +
> +	return young;
> +}
> +#endif
> +
>  /*
>   * On some architectures hardware does not set page access bit when accessing
>   * memory page, it is responsibility of software setting this bit. It brings
> diff --git a/mm/rmap.c b/mm/rmap.c
> index d6799afe1114..a0fc05f5966f 100644
> --- a/mm/rmap.c
> +++ b/mm/rmap.c
> @@ -827,9 +827,11 @@ static bool folio_referenced_one(struct folio *folio,
>  	struct folio_referenced_arg *pra = arg;
>  	DEFINE_FOLIO_VMA_WALK(pvmw, folio, vma, address, 0);
>  	int ptes = 0, referenced = 0;
> +	unsigned int nr;
and here            ^^^

>  
>  	while (page_vma_mapped_walk(&pvmw)) {
>  		address = pvmw.address;
> +		nr = 1;
>  
>  		if (vma->vm_flags & VM_LOCKED) {
>  			ptes++;
> @@ -874,9 +876,24 @@ static bool folio_referenced_one(struct folio *folio,
>  			if (lru_gen_look_around(&pvmw))
>  				referenced++;
>  		} else if (pvmw.pte) {
> +			if (folio_test_large(folio)) {
> +				unsigned long end_addr =
> +					pmd_addr_end(address, vma->vm_end);
> +				unsigned int max_nr =
> +					(end_addr - address) >> PAGE_SHIFT;
> +				pte_t pteval = ptep_get(pvmw.pte);
> +
> +				nr = folio_pte_batch(folio, pvmw.pte,
> +						     pteval, max_nr);
> +			}
> +
> +			ptes += nr;
>  			if (ptep_clear_flush_young_notify(vma, address,
> -						pvmw.pte))
> +						pvmw.pte, nr))
>  				referenced++;
> +			/* Skip the batched PTEs */
> +			pvmw.pte += nr - 1;
> +			pvmw.address += (nr - 1) * PAGE_SIZE;
>  		} else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) {
>  			if (pmdp_clear_flush_young_notify(vma, address,
>  						pvmw.pmd))
> @@ -886,7 +903,15 @@ static bool folio_referenced_one(struct folio *folio,
>  			WARN_ON_ONCE(1);
>  		}
>  
> -		pra->mapcount--;
> +		pra->mapcount -= nr;
> +		/*
> +		 * If we are sure that we batched the entire folio,
> +		 * we can just optimize and stop right here.
> +		 */
> +		if (ptes == pvmw.nr_pages) {
> +			page_vma_mapped_walk_done(&pvmw);
> +			break;
> +		}
>  	}
>  
>  	if (referenced)
> -- 
> 2.47.3
> 
> 


From andrew at lunn.ch  Fri Dec 19 07:49:27 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Fri, 19 Dec 2025 16:49:27 +0100
Subject: [PATCH v7 1/3] dt-bindings: soc: imx93-media-blk-ctrl: Add PDFC
 subnode to schema and example
In-Reply-To: <20251219153537.zgxcokyhcqerw4jp@pengutronix.de>
References: <20251202-v6-18-topic-imx93-parallel-display-v7-0-2cce31d64608@pengutronix.de>
 <20251202-v6-18-topic-imx93-parallel-display-v7-1-2cce31d64608@pengutronix.de>
 <705773fc-5aba-4bff-b05e-272e1cd0262c@nxp.com>
 <20251215161706.2ea3wtu3xlwcxxar@pengutronix.de>
 <7127040f-55ab-4bfa-8795-1df76085470c@kernel.org>
 <20251219153537.zgxcokyhcqerw4jp@pengutronix.de>
Message-ID: <033450ab-f14d-4bf7-b7ee-aaffd014820d@lunn.ch>

> We discussed the ranges/reg usage internally as well with the following
> outcome:
> 
> - Situation
> 
>   With i.MX8M SoCs NXP introduced MIX domains. Each domain has a so
>   called BLK-CTRL IP. There is no common register layout for the
>   BLK-CTRL IPs. In addition to this, the register fields within one
>   register may not related to the same IP. Please see my below example:
>   
>   The DISP_MUX register configures the DPI output routed to physical
>   SoC pads as well as the internal MIPI-DSI DPI behavior. This PDFC
>   bridge binding is only interested in the first part, not the 2nd.
> 
>   In other words, the BLK-CTRL IP can be seen as a bunch of loose
>   register fields.

Why do hardware engineers keep on insisting on doing this. And why
don't software engineers when asked to review the proposed registers
push back and say No?

I know this is out of you hands, but it is something we should
encourage software engineers at SoC vendors to do. Otherwise we will
have to continually live with such a mess.

     Andrew


From jgg at nvidia.com  Fri Dec 19 07:51:51 2025
From: jgg at nvidia.com (Jason Gunthorpe)
Date: Fri, 19 Dec 2025 11:51:51 -0400
Subject: [PATCH v8 5/7] iommu/arm-smmu-v3: Populate smmu_domain->invs
 when attaching masters
In-Reply-To: <79cd18a1a959ee2e54683e8c465b799d49ec48b5.1766013662.git.nicolinc@nvidia.com>
References: <cover.1766013662.git.nicolinc@nvidia.com>
 <79cd18a1a959ee2e54683e8c465b799d49ec48b5.1766013662.git.nicolinc@nvidia.com>
Message-ID: <20251219155151.GA373575@nvidia.com>

On Wed, Dec 17, 2025 at 03:24:30PM -0800, Nicolin Chen wrote:
> +	*cur = inv;
> +	switch (type) {
> +	case INV_TYPE_S1_ASID:
> +		if (master->smmu->features & ARM_SMMU_FEAT_E2H) {
> +			cur->size_opcode = CMDQ_OP_TLBI_EL2_VA;
> +			cur->nsize_opcode = CMDQ_OP_TLBI_EL2_ASID;
> +		} else {
> +			cur->size_opcode = CMDQ_OP_TLBI_NH_VA;
> +			cur->nsize_opcode = CMDQ_OP_TLBI_NH_ASID;

There is a tricky little gotcha here that probably requires a comment.

NH_VA and NH_ASID both take (VMID,ASID) as input since the ASID is
always scoped to a single VMID.

In this case the invalidation logic always wires the VMID to zero,
which is also the VMID the driver uses for S1 tables when the S2 is in
bypass.

Which is fine, we don't support an actual S1 table on top of a S2
table where we issue invalidations through the invs array.

So maybe:

 For S1 page tables the driver always uses VMID=0, and the
 invalidation logic for this type will set it as well.

Jason


From Frank.li at nxp.com  Fri Dec 19 07:52:30 2025
From: Frank.li at nxp.com (Frank Li)
Date: Fri, 19 Dec 2025 10:52:30 -0500
Subject: [PATCH] phy: fsl-imx8mq-usb: enable RxTermination_override_sel
In-Reply-To: <20251219083004.3883898-1-xu.yang_2@nxp.com>
References: <20251219083004.3883898-1-xu.yang_2@nxp.com>
Message-ID: <aUV0vn2VPWKAh5f7@lizhi-Precision-Tower-5810>

On Fri, Dec 19, 2025 at 04:30:04PM +0800, Xu Yang wrote:
> This is to resolve the problem of wakeup system by USB3 device
> insertion if HSIOMIX on, in that case, the USB3 device detects

Do you means USB3 device wrong regconized as USB2?

> RX term on so doesn't downgrade to USB2, so DP/DM wakeup can't
> happen, with this override bit we can force the RX term off when
> enters system suspend, and disable the override after system resume.

Enable RxTermination_override_sel to resolve the problem, which wrong
regongized as USB 2.0 device if USB3 device plug-in when HSIOMIX ON.

No clear why force RX term Off can resolve problem. Please rephrase it.

Frank

>
> Signed-off-by: Li Jun <jun.li at nxp.com>
> Signed-off-by: Xu Yang <xu.yang_2 at nxp.com>
> ---
>  drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 15 ++++++++++++++-
>  1 file changed, 14 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> index 02d9af409b08..0831ed465775 100644
> --- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> +++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> @@ -52,6 +52,7 @@
>  #define PHY_CTRL5_PCS_TX_SWING_FULL_MASK	GENMASK(6, 0)
>
>  #define PHY_CTRL6			0x18
> +#define PHY_CTRL6_RXTERM_OVERRIDE_SEL	BIT(29)
>  #define PHY_CTRL6_ALT_CLK_EN		BIT(1)
>  #define PHY_CTRL6_ALT_CLK_SEL		BIT(0)
>
> @@ -847,6 +848,7 @@ static int imx8mp_usb_phy_init(struct phy *phy)
>  static int imx8mq_phy_power_on(struct phy *phy)
>  {
>  	struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
> +	u32 value;
>  	int ret;
>
>  	ret = regulator_enable(imx_phy->vbus);
> @@ -863,12 +865,23 @@ static int imx8mq_phy_power_on(struct phy *phy)
>  		return ret;
>  	}
>
> -	return ret;
> +	/* Disable rx term override */
> +	value = readl(imx_phy->base + PHY_CTRL6);
> +	value &= ~PHY_CTRL6_RXTERM_OVERRIDE_SEL;
> +	writel(value, imx_phy->base + PHY_CTRL6);
> +
> +	return 0;
>  }
>
>  static int imx8mq_phy_power_off(struct phy *phy)
>  {
>  	struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
> +	u32 value;
> +
> +	/* Override rx term to be 0 */
> +	value = readl(imx_phy->base + PHY_CTRL6);
> +	value |= PHY_CTRL6_RXTERM_OVERRIDE_SEL;
> +	writel(value, imx_phy->base + PHY_CTRL6);
>
>  	clk_disable_unprepare(imx_phy->alt_clk);
>  	clk_disable_unprepare(imx_phy->clk);
> --
> 2.34.1
>


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:37 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:37 +0000
Subject: [PATCH v2 05/36] arm64/sysreg: Add GICR CDNMIA encoding
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-6-sascha.bischoff@arm.com>

The encoding for the GICR CDNMIA system instruction is thus far unused
(and shall remain unused for the time being). However, in order to
plumb the FGTs into KVM correctly, KVM needs to be made aware of the
encoding of this system instruction.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/include/asm/sysreg.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index b3b8b8cd7bf1e..e99acb6dbd5d8 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -1059,6 +1059,7 @@
 #define GICV5_OP_GIC_CDPRI		sys_insn(1, 0, 12, 1, 2)
 #define GICV5_OP_GIC_CDRCFG		sys_insn(1, 0, 12, 1, 5)
 #define GICV5_OP_GICR_CDIA		sys_insn(1, 0, 12, 3, 0)
+#define GICV5_OP_GICR_CDNMIA		sys_insn(1, 0, 12, 3, 1)
 
 /* Definitions for GIC CDAFF */
 #define GICV5_GIC_CDAFF_IAFFID_MASK	GENMASK_ULL(47, 32)
@@ -1105,6 +1106,12 @@
 #define GICV5_GIC_CDIA_TYPE_MASK	GENMASK_ULL(31, 29)
 #define GICV5_GIC_CDIA_ID_MASK		GENMASK_ULL(23, 0)
 
+/* Definitions for GICR CDNMIA */
+#define GICV5_GIC_CDNMIA_VALID_MASK	BIT_ULL(32)
+#define GICV5_GICR_CDNMIA_VALID(r)	FIELD_GET(GICV5_GIC_CDNMIA_VALID_MASK, r)
+#define GICV5_GIC_CDNMIA_TYPE_MASK	GENMASK_ULL(31, 29)
+#define GICV5_GIC_CDNMIA_ID_MASK	GENMASK_ULL(23, 0)
+
 #define gicr_insn(insn)			read_sysreg_s(GICV5_OP_GICR_##insn)
 #define gic_insn(v, insn)		write_sysreg_s(v, GICV5_OP_GIC_##insn)
 
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:35 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:35 +0000
Subject: [PATCH v2 00/36] KVM: arm64: Introduce vGIC-v5 with PPI support
Message-ID: <20251219155222.1383109-1-sascha.bischoff@arm.com>

This is the second version of the patch series to add the virtual
GICv5 [1] device (vgic_v5). Only PPIs are supported by this initial
series, and the vgic_v5 implementation is restricted to the CPU
interface, only. Further patch series are to follow in due course, and
will add support for SPIs, LPIs, the GICv5 IRS, and the GICv5 ITS.

The first version of this series can be found at [2].

The noteworthy changes since V1 of this series are:

1. Added detection of implemented PPIs on a GICv5 host at boot time.
2. Added masking for PPIs that are presented to guests. Only PPIs with
   owners and the SW_PPI (if present) are exposed.
3. Added trapping and masking for all guest writes to the writable
   ICC_PPI_x_EL1 registers. The writes are masked with the subset of
   PPIs exposed to the guest. This ensures that the guest cannot
   discover PPIs that are not intentionally exposed to it.
4. Added an new UAPI to allow userspace to query which PPIs can be
   driven via KVM_IRQ_LINE. For the time being, only the SW_ PPI is
   exposed for guest control.
5. Interrupt type checks are now re-worked to be more readable and
   scalable. Thanks, Marc.

I have addressed some, but alas not all (see below), review comments
against v1 of the series. Thanks a lot Marc, Joey, and Lorenzo!

I'm posting V2 even though I've yet to address all review comments as
I shall be out of office for the next 2 weeks. Therefore, I wanted to
make sure that the latest version was available for anyone to take a
look. Any outstanding and new comments will be addressed on my return.

The main outstanding changes are:

1. Rework the PPI save/restore mechanisms to remove the _entry/_exit
   from the vcpu, and instead use per-cpu data structures.
2. PPI injection needs clean up around shadow state tracking an
   manipulation.
3. PPI state tracking needs to be heaviliy optimised to reduce the
   number of locks taken and PPIs iterated over. This is now possible
   with the introduction of the masks, but remains to be implemented.
4. Allow for sparse PPI state storage. Given that most of the 128
   potential PPIs will never be used with a guest, it is extremely
   wasteful to allocate storage for them.

These changes are based on v6.19-rc1. As before, the first commit has
been cherry-picked from Marc's VTCR sanitisation series [3].

For those that are interested in the overall direction of the GICv5
KVM support, Marc Zyngier has very kindly agreed to host the full
*WIP* set of GICv5 KVM patches which can be found at [4]. These are
not intended for review, and require some serious clean up, but should
give a rough idea of what is still to come.

Thanks all for the feedback so far and any more you have,
Sascha

[1] https://developer.arm.com/documentation/aes0070/latest
[2] https://lore.kernel.org/all/20251212152215.675767-1-sascha.bischoff at arm.com/
[3] https://lore.kernel.org/all/20251210173024.561160-1-maz at kernel.org/
[4] https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git/log/?h=kvm-arm64/gicv5-full

Marc Zyngier (1):
  KVM: arm64: Account for RES1 bits in DECLARE_FEAT_MAP() and co

Sascha Bischoff (35):
  KVM: arm64: gic-v3: Switch vGIC-v3 to use generated ICH_VMCR_EL2
  arm64/sysreg: Drop ICH_HFGRTR_EL2.ICC_HAPR_EL1 and make RES1
  arm64/sysreg: Add remaining GICv5 ICC_ & ICH_ sysregs for KVM support
  arm64/sysreg: Add GICR CDNMIA encoding
  KVM: arm64: gic-v5: Add ARM_VGIC_V5 device to KVM headers
  KVM: arm64: gic: Introduce interrupt type helpers
  KVM: arm64: Introduce kvm_call_hyp_nvhe_res()
  KVM: arm64: gic-v5: Detect implemented PPIs on boot
  KVM: arm64: gic-v5: Sanitize ID_AA64PFR2_EL1.GCIE
  KVM: arm64: gic-v5: Support GICv5 FGTs & FGUs
  KVM: arm64: gic-v5: Add emulation for ICC_IAFFIDR_EL1 accesses
  KVM: arm64: gic: Set vgic_model before initing private IRQs
  KVM: arm64: gic-v5: Add vgic-v5 save/restore hyp interface
  KVM: arm64: gic-v5: Implement GICv5 load/put and save/restore
  KVM: arm64: gic-v5: Implement direct injection of PPIs
  KVM: arm64: gic: Introduce irq_queue and set_pending_state to irq_ops
  KVM: arm64: gic-v5: Implement PPI interrupt injection
  KVM: arm64: gic-v5: Check for pending PPIs
  KVM: arm64: gic-v5: Init Private IRQs (PPIs) for GICv5
  KVM: arm64: gic-v5: Finalize GICv5 PPIs and generate mask
  KVM: arm64: gic-v5: Trap and mask guest PPI register accesses
  KVM: arm64: gic-v5: Support GICv5 interrupts with KVM_IRQ_LINE
  KVM: arm64: gic-v5: Create, init vgic_v5
  KVM: arm64: gic-v5: Reset vcpu state
  KVM: arm64: gic-v5: Bump arch timer for GICv5
  KVM: arm64: gic-v5: Mandate architected PPI for PMU emulation on GICv5
  KVM: arm64: gic: Hide GICv5 for protected guests
  KVM: arm64: gic-v5: Hide FEAT_GCIE from NV GICv5 guests
  KVM: arm64: gic-v5: Introduce kvm_arm_vgic_v5_ops and register them
  KVM: arm64: gic-v5: Set ICH_VCTLR_EL2.En on boot
  irqchip/gic-v5: Check if impl is virt capable
  KVM: arm64: gic-v5: Probe for GICv5 device
  Documentation: KVM: Introduce documentation for VGICv5
  KVM: arm64: selftests: Introduce a minimal GICv5 PPI selftest
  KVM: arm64: gic-v5: Communicate userspace-drivable PPIs via a UAPI

 Documentation/virt/kvm/api.rst                |   6 +-
 .../virt/kvm/devices/arm-vgic-v5.rst          |  50 ++
 Documentation/virt/kvm/devices/index.rst      |   1 +
 arch/arm64/include/asm/el2_setup.h            |   3 +-
 arch/arm64/include/asm/kvm_asm.h              |   5 +
 arch/arm64/include/asm/kvm_host.h             |  35 +-
 arch/arm64/include/asm/kvm_hyp.h              |  10 +
 arch/arm64/include/asm/sysreg.h               |  28 +-
 arch/arm64/include/asm/vncr_mapping.h         |   3 +
 arch/arm64/include/uapi/asm/kvm.h             |   1 +
 arch/arm64/kvm/arch_timer.c                   | 112 +++-
 arch/arm64/kvm/arm.c                          |  29 +-
 arch/arm64/kvm/config.c                       | 145 ++++-
 arch/arm64/kvm/emulate-nested.c               | 123 +++-
 arch/arm64/kvm/hyp/include/hyp/switch.h       |  27 +
 arch/arm64/kvm/hyp/nvhe/Makefile              |   2 +-
 arch/arm64/kvm/hyp/nvhe/hyp-main.c            |  43 ++
 arch/arm64/kvm/hyp/nvhe/switch.c              |  15 +
 arch/arm64/kvm/hyp/nvhe/sys_regs.c            |   8 +
 arch/arm64/kvm/hyp/vgic-v3-sr.c               |  64 +-
 arch/arm64/kvm/hyp/vgic-v5-sr.c               | 146 +++++
 arch/arm64/kvm/hyp/vhe/Makefile               |   2 +-
 arch/arm64/kvm/nested.c                       |   5 +
 arch/arm64/kvm/pmu-emul.c                     |  21 +-
 arch/arm64/kvm/sys_regs.c                     | 190 +++++-
 arch/arm64/kvm/vgic/vgic-init.c               | 123 +++-
 arch/arm64/kvm/vgic/vgic-kvm-device.c         |  99 ++-
 arch/arm64/kvm/vgic/vgic-mmio.c               |  28 +-
 arch/arm64/kvm/vgic/vgic-v3-nested.c          |   8 +-
 arch/arm64/kvm/vgic/vgic-v3.c                 |  48 +-
 arch/arm64/kvm/vgic/vgic-v5.c                 | 571 +++++++++++++++++-
 arch/arm64/kvm/vgic/vgic.c                    | 125 +++-
 arch/arm64/kvm/vgic/vgic.h                    |  70 ++-
 arch/arm64/tools/sysreg                       | 482 ++++++++++++++-
 drivers/irqchip/irq-gic-v5-irs.c              |   4 +
 drivers/irqchip/irq-gic-v5.c                  |  10 +
 include/kvm/arm_arch_timer.h                  |   7 +-
 include/kvm/arm_pmu.h                         |   5 +-
 include/kvm/arm_vgic.h                        | 160 ++++-
 include/linux/irqchip/arm-gic-v5.h            |  15 +
 include/linux/kvm_host.h                      |   1 +
 include/uapi/linux/kvm.h                      |   2 +
 tools/arch/arm64/include/uapi/asm/kvm.h       |   1 +
 tools/include/uapi/linux/kvm.h                |   2 +
 tools/testing/selftests/kvm/Makefile.kvm      |   1 +
 tools/testing/selftests/kvm/arm64/vgic_v5.c   | 248 ++++++++
 .../selftests/kvm/include/arm64/gic_v5.h      | 148 +++++
 47 files changed, 2965 insertions(+), 267 deletions(-)
 create mode 100644 Documentation/virt/kvm/devices/arm-vgic-v5.rst
 create mode 100644 arch/arm64/kvm/hyp/vgic-v5-sr.c
 create mode 100644 tools/testing/selftests/kvm/arm64/vgic_v5.c
 create mode 100644 tools/testing/selftests/kvm/include/arm64/gic_v5.h

-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:38 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:38 +0000
Subject: [PATCH v2 09/36] KVM: arm64: gic-v5: Detect implemented PPIs on boot
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-10-sascha.bischoff@arm.com>

It is expected that most GICv5 implementations will only implement a
subset of the PPIs. GICv5 supports up to 128 PPIs in total, where the
first 64 are architecturally defined, and the second 64 are
implementation defined. This limitation applies to both physical and
virtual PPIs as the same set is implemented in each case, and
therefore KVM needs to determine a mask of implemented PPIs during
early KVM init.

The check involves writing all of the ICH_PPI_ENABLERx_EL2 bits and
reading those back again to determine which are stateful. If the bits
are stateful, the PPIs are implemented. Else, they are not.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/include/asm/kvm_asm.h   |  1 +
 arch/arm64/include/asm/kvm_hyp.h   |  3 +++
 arch/arm64/kvm/hyp/nvhe/Makefile   |  2 +-
 arch/arm64/kvm/hyp/nvhe/hyp-main.c | 11 +++++++++++
 arch/arm64/kvm/hyp/vgic-v5-sr.c    | 27 +++++++++++++++++++++++++++
 arch/arm64/kvm/hyp/vhe/Makefile    |  2 +-
 arch/arm64/kvm/vgic/vgic-init.c    |  4 ++++
 arch/arm64/kvm/vgic/vgic-v5.c      | 29 +++++++++++++++++++++++++++++
 arch/arm64/kvm/vgic/vgic.h         |  1 +
 include/kvm/arm_vgic.h             |  5 +++++
 10 files changed, 83 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm64/kvm/hyp/vgic-v5-sr.c

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index a1ad12c72ebf1..ada752e97c6aa 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -89,6 +89,7 @@ enum __kvm_host_smccc_func {
 	__KVM_HOST_SMCCC_FUNC___pkvm_vcpu_load,
 	__KVM_HOST_SMCCC_FUNC___pkvm_vcpu_put,
 	__KVM_HOST_SMCCC_FUNC___pkvm_tlb_flush_vmid,
+	__KVM_HOST_SMCCC_FUNC___vgic_v5_detect_ppis,
 };
 
 #define DECLARE_KVM_VHE_SYM(sym)	extern char sym[]
diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index 76ce2b94bd97e..80e5491de8e1e 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -87,6 +87,9 @@ void __vgic_v3_save_aprs(struct vgic_v3_cpu_if *cpu_if);
 void __vgic_v3_restore_vmcr_aprs(struct vgic_v3_cpu_if *cpu_if);
 int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);
 
+/* GICv5 */
+void __vgic_v5_detect_ppis(u64 *ppi);
+
 #ifdef __KVM_NVHE_HYPERVISOR__
 void __timer_enable_traps(struct kvm_vcpu *vcpu);
 void __timer_disable_traps(struct kvm_vcpu *vcpu);
diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile
index a244ec25f8c5b..84a3bf96def6b 100644
--- a/arch/arm64/kvm/hyp/nvhe/Makefile
+++ b/arch/arm64/kvm/hyp/nvhe/Makefile
@@ -26,7 +26,7 @@ hyp-obj-y := timer-sr.o sysreg-sr.o debug-sr.o switch.o tlb.o hyp-init.o host.o
 	 hyp-main.o hyp-smp.o psci-relay.o early_alloc.o page_alloc.o \
 	 cache.o setup.o mm.o mem_protect.o sys_regs.o pkvm.o stacktrace.o ffa.o
 hyp-obj-y += ../vgic-v3-sr.o ../aarch32.o ../vgic-v2-cpuif-proxy.o ../entry.o \
-	 ../fpsimd.o ../hyp-entry.o ../exception.o ../pgtable.o
+	 ../fpsimd.o ../hyp-entry.o ../exception.o ../pgtable.o ../vgic-v5-sr.o
 hyp-obj-y += ../../../kernel/smccc-call.o
 hyp-obj-$(CONFIG_LIST_HARDENED) += list_debug.o
 hyp-obj-y += $(lib-objs)
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index a7c689152f686..3d1d0807be6db 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -586,6 +586,16 @@ static void handle___pkvm_teardown_vm(struct kvm_cpu_context *host_ctxt)
 	cpu_reg(host_ctxt, 1) = __pkvm_teardown_vm(handle);
 }
 
+static void handle___vgic_v5_detect_ppis(struct kvm_cpu_context *host_ctxt)
+{
+	u64 ppi[2];
+
+	__vgic_v5_detect_ppis(ppi);
+
+	cpu_reg(host_ctxt, 1) = ppi[0];
+	cpu_reg(host_ctxt, 2) = ppi[1];
+}
+
 typedef void (*hcall_t)(struct kvm_cpu_context *);
 
 #define HANDLE_FUNC(x)	[__KVM_HOST_SMCCC_FUNC_##x] = (hcall_t)handle_##x
@@ -627,6 +637,7 @@ static const hcall_t host_hcall[] = {
 	HANDLE_FUNC(__pkvm_vcpu_load),
 	HANDLE_FUNC(__pkvm_vcpu_put),
 	HANDLE_FUNC(__pkvm_tlb_flush_vmid),
+	HANDLE_FUNC(__vgic_v5_detect_ppis),
 };
 
 static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
diff --git a/arch/arm64/kvm/hyp/vgic-v5-sr.c b/arch/arm64/kvm/hyp/vgic-v5-sr.c
new file mode 100644
index 0000000000000..4b088588757ea
--- /dev/null
+++ b/arch/arm64/kvm/hyp/vgic-v5-sr.c
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2025 - ARM Ltd
+ */
+
+#include <linux/irqchip/arm-gic-v5.h>
+
+#include <asm/kvm_hyp.h>
+
+void __vgic_v5_detect_ppis(u64 *impl_ppi_mask)
+{
+	/* Disable DVI for all PPIs */
+	write_sysreg_s(0, SYS_ICH_PPI_DVIR0_EL2);
+	write_sysreg_s(0, SYS_ICH_PPI_DVIR1_EL2);
+
+	/* Write all 1s to the PPI enable regs */
+	write_sysreg_s(GENMASK_ULL(63, 0), SYS_ICH_PPI_ENABLER0_EL2);
+	write_sysreg_s(GENMASK_ULL(63, 0), SYS_ICH_PPI_ENABLER1_EL2);
+
+	/* Read back to figure out which are stateful */
+	impl_ppi_mask[0] = read_sysreg_s(SYS_ICH_PPI_ENABLER0_EL2);
+	impl_ppi_mask[1] = read_sysreg_s(SYS_ICH_PPI_ENABLER1_EL2);
+
+	/* Disable them all again! */
+	write_sysreg_s(0, SYS_ICH_PPI_ENABLER0_EL2);
+	write_sysreg_s(0, SYS_ICH_PPI_ENABLER1_EL2);
+}
diff --git a/arch/arm64/kvm/hyp/vhe/Makefile b/arch/arm64/kvm/hyp/vhe/Makefile
index afc4aed9231ac..9695328bbd96e 100644
--- a/arch/arm64/kvm/hyp/vhe/Makefile
+++ b/arch/arm64/kvm/hyp/vhe/Makefile
@@ -10,4 +10,4 @@ CFLAGS_switch.o += -Wno-override-init
 
 obj-y := timer-sr.o sysreg-sr.o debug-sr.o switch.o tlb.o
 obj-y += ../vgic-v3-sr.o ../aarch32.o ../vgic-v2-cpuif-proxy.o ../entry.o \
-	 ../fpsimd.o ../hyp-entry.o ../exception.o
+	 ../fpsimd.o ../hyp-entry.o ../exception.o ../vgic-v5-sr.o
diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index dc9f9db310264..c602f24bab1bb 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -750,5 +750,9 @@ int kvm_vgic_hyp_init(void)
 	}
 
 	kvm_info("vgic interrupt IRQ%d\n", kvm_vgic_global_state.maint_irq);
+
+	/* Always safe to call */
+	vgic_v5_get_implemented_ppis();
+
 	return 0;
 }
diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index 2d3811f4e1174..1fe1790f1f874 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -5,6 +5,8 @@
 
 #include "vgic.h"
 
+static struct vgic_v5_ppi_caps *ppi_caps;
+
 /*
  * Probe for a vGICv5 compatible interrupt controller, returning 0 on success.
  * Currently only supports GICv3-based VMs on a GICv5 host, and hence only
@@ -50,3 +52,30 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
 
 	return 0;
 }
+
+/*
+ * Not all PPIs are guaranteed to be implemented for
+ * GICv5. Deterermine which ones are, and generate a mask. This is
+ * called early in boot, so we can just write directly to the ICH_PPI*
+ * regs and have no state to preserve.
+ */
+void vgic_v5_get_implemented_ppis(void)
+{
+	if (!cpus_have_final_cap(ARM64_HAS_GICV5_CPUIF))
+		return;
+
+	/* Never freed again */
+	ppi_caps = kzalloc(sizeof(*ppi_caps), GFP_KERNEL);
+	if (!ppi_caps)
+		return;
+
+	if (!has_vhe()) {
+		struct arm_smccc_res res;
+
+		kvm_call_hyp_nvhe_res(&res, __vgic_v5_detect_ppis);
+		ppi_caps->impl_ppi_mask[0] = res.a1;
+		ppi_caps->impl_ppi_mask[1] = res.a2;
+	} else {
+		__vgic_v5_detect_ppis(ppi_caps->impl_ppi_mask);
+	}
+}
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index 5f0fc96b4dc29..15f6afe6b75e1 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -362,6 +362,7 @@ void vgic_debug_init(struct kvm *kvm);
 void vgic_debug_destroy(struct kvm *kvm);
 
 int vgic_v5_probe(const struct gic_kvm_info *info);
+void vgic_v5_get_implemented_ppis(void);
 
 static inline int vgic_v3_max_apr_idx(struct kvm_vcpu *vcpu)
 {
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 6778f676eaf08..c7786a2607ecd 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -414,6 +414,11 @@ struct vgic_v3_cpu_if {
 	unsigned int used_lrs;
 };
 
+/* What PPI capabilities does a GICv5 host have */
+struct vgic_v5_ppi_caps {
+	u64	impl_ppi_mask[2];
+};
+
 struct vgic_cpu {
 	/* CPU vif control registers for world switch */
 	union {
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:37 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:37 +0000
Subject: [PATCH v2 06/36] KVM: arm64: gic-v5: Add ARM_VGIC_V5 device to KVM
 headers
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-7-sascha.bischoff@arm.com>

This is the base GICv5 device which is to be used with the
KVM_CREATE_DEVICE ioctl to create a GICv5-based vgic.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 include/uapi/linux/kvm.h       | 2 ++
 tools/include/uapi/linux/kvm.h | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index dddb781b0507d..f7dabbf17e1a7 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1209,6 +1209,8 @@ enum kvm_device_type {
 #define KVM_DEV_TYPE_LOONGARCH_EIOINTC	KVM_DEV_TYPE_LOONGARCH_EIOINTC
 	KVM_DEV_TYPE_LOONGARCH_PCHPIC,
 #define KVM_DEV_TYPE_LOONGARCH_PCHPIC	KVM_DEV_TYPE_LOONGARCH_PCHPIC
+	KVM_DEV_TYPE_ARM_VGIC_V5,
+#define KVM_DEV_TYPE_ARM_VGIC_V5	KVM_DEV_TYPE_ARM_VGIC_V5
 
 	KVM_DEV_TYPE_MAX,
 
diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h
index 52f6000ab0208..8303124973e2a 100644
--- a/tools/include/uapi/linux/kvm.h
+++ b/tools/include/uapi/linux/kvm.h
@@ -1198,6 +1198,8 @@ enum kvm_device_type {
 #define KVM_DEV_TYPE_LOONGARCH_EIOINTC	KVM_DEV_TYPE_LOONGARCH_EIOINTC
 	KVM_DEV_TYPE_LOONGARCH_PCHPIC,
 #define KVM_DEV_TYPE_LOONGARCH_PCHPIC	KVM_DEV_TYPE_LOONGARCH_PCHPIC
+	KVM_DEV_TYPE_ARM_VGIC_V5,
+#define KVM_DEV_TYPE_ARM_VGIC_V5	KVM_DEV_TYPE_ARM_VGIC_V5
 
 	KVM_DEV_TYPE_MAX,
 
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:36 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:36 +0000
Subject: [PATCH v2 01/36] KVM: arm64: Account for RES1 bits in
 DECLARE_FEAT_MAP() and co
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-2-sascha.bischoff@arm.com>

From: Marc Zyngier <maz at kernel.org>

None of the registers we manage in the feature dependency infrastructure
so far has any RES1 bit. This is about to change, as VTCR_EL2 has
its bit 31 being RES1.

In order to not fail the consistency checks by not describing a bit,
add RES1 bits to the set of immutable bits. This requires some extra
surgery for the FGT handling, as we now need to track RES1 bits there
as well.

There are no RES1 FGT bits *yet*. Watch this space.

Signed-off-by: Marc Zyngier <maz at kernel.org>
---
 arch/arm64/include/asm/kvm_host.h |  1 +
 arch/arm64/kvm/config.c           | 25 +++++++-------
 arch/arm64/kvm/emulate-nested.c   | 55 +++++++++++++++++--------------
 3 files changed, 45 insertions(+), 36 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index ac7f970c78830..b552a1e03848c 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -638,6 +638,7 @@ struct fgt_masks {
 	u64		mask;
 	u64		nmask;
 	u64		res0;
+	u64		res1;
 };
 
 extern struct fgt_masks hfgrtr_masks;
diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index 24bb3f36e9d59..3845b188551b6 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -16,14 +16,14 @@
  */
 struct reg_bits_to_feat_map {
 	union {
-		u64	bits;
-		u64	*res0p;
+		u64		 bits;
+		struct fgt_masks *masks;
 	};
 
 #define	NEVER_FGU	BIT(0)	/* Can trap, but never UNDEF */
 #define	CALL_FUNC	BIT(1)	/* Needs to evaluate tons of crap */
 #define	FIXED_VALUE	BIT(2)	/* RAZ/WI or RAO/WI in KVM */
-#define	RES0_POINTER	BIT(3)	/* Pointer to RES0 value instead of bits */
+#define	MASKS_POINTER	BIT(3)	/* Pointer to fgt_masks struct instead of bits */
 
 	unsigned long	flags;
 
@@ -92,8 +92,8 @@ struct reg_feat_map_desc {
 #define NEEDS_FEAT_FIXED(m, ...)			\
 	__NEEDS_FEAT_FLAG(m, FIXED_VALUE, bits, __VA_ARGS__, 0)
 
-#define NEEDS_FEAT_RES0(p, ...)				\
-	__NEEDS_FEAT_FLAG(p, RES0_POINTER, res0p, __VA_ARGS__)
+#define NEEDS_FEAT_MASKS(p, ...)				\
+	__NEEDS_FEAT_FLAG(p, MASKS_POINTER, masks, __VA_ARGS__)
 
 /*
  * Declare the dependency between a set of bits and a set of features,
@@ -109,19 +109,20 @@ struct reg_feat_map_desc {
 #define DECLARE_FEAT_MAP(n, r, m, f)					\
 	struct reg_feat_map_desc n = {					\
 		.name			= #r,				\
-		.feat_map		= NEEDS_FEAT(~r##_RES0, f), 	\
+		.feat_map		= NEEDS_FEAT(~(r##_RES0 |	\
+						       r##_RES1), f),	\
 		.bit_feat_map		= m,				\
 		.bit_feat_map_sz	= ARRAY_SIZE(m),		\
 	}
 
 /*
  * Specialised version of the above for FGT registers that have their
- * RES0 masks described as struct fgt_masks.
+ * RESx masks described as struct fgt_masks.
  */
 #define DECLARE_FEAT_MAP_FGT(n, msk, m, f)				\
 	struct reg_feat_map_desc n = {					\
 		.name			= #msk,				\
-		.feat_map		= NEEDS_FEAT_RES0(&msk.res0, f),\
+		.feat_map		= NEEDS_FEAT_MASKS(&msk, f),	\
 		.bit_feat_map		= m,				\
 		.bit_feat_map_sz	= ARRAY_SIZE(m),		\
 	}
@@ -1168,21 +1169,21 @@ static const DECLARE_FEAT_MAP(mdcr_el2_desc, MDCR_EL2,
 			      mdcr_el2_feat_map, FEAT_AA64EL2);
 
 static void __init check_feat_map(const struct reg_bits_to_feat_map *map,
-				  int map_size, u64 res0, const char *str)
+				  int map_size, u64 resx, const char *str)
 {
 	u64 mask = 0;
 
 	for (int i = 0; i < map_size; i++)
 		mask |= map[i].bits;
 
-	if (mask != ~res0)
+	if (mask != ~resx)
 		kvm_err("Undefined %s behaviour, bits %016llx\n",
-			str, mask ^ ~res0);
+			str, mask ^ ~resx);
 }
 
 static u64 reg_feat_map_bits(const struct reg_bits_to_feat_map *map)
 {
-	return map->flags & RES0_POINTER ? ~(*map->res0p) : map->bits;
+	return map->flags & MASKS_POINTER ? (map->masks->mask | map->masks->nmask) : map->bits;
 }
 
 static void __init check_reg_desc(const struct reg_feat_map_desc *r)
diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c
index 834f13fb1fb7d..75d49f83342a5 100644
--- a/arch/arm64/kvm/emulate-nested.c
+++ b/arch/arm64/kvm/emulate-nested.c
@@ -2105,23 +2105,24 @@ static u32 encoding_next(u32 encoding)
 }
 
 #define FGT_MASKS(__n, __m)						\
-	struct fgt_masks __n = { .str = #__m, .res0 = __m, }
-
-FGT_MASKS(hfgrtr_masks, HFGRTR_EL2_RES0);
-FGT_MASKS(hfgwtr_masks, HFGWTR_EL2_RES0);
-FGT_MASKS(hfgitr_masks, HFGITR_EL2_RES0);
-FGT_MASKS(hdfgrtr_masks, HDFGRTR_EL2_RES0);
-FGT_MASKS(hdfgwtr_masks, HDFGWTR_EL2_RES0);
-FGT_MASKS(hafgrtr_masks, HAFGRTR_EL2_RES0);
-FGT_MASKS(hfgrtr2_masks, HFGRTR2_EL2_RES0);
-FGT_MASKS(hfgwtr2_masks, HFGWTR2_EL2_RES0);
-FGT_MASKS(hfgitr2_masks, HFGITR2_EL2_RES0);
-FGT_MASKS(hdfgrtr2_masks, HDFGRTR2_EL2_RES0);
-FGT_MASKS(hdfgwtr2_masks, HDFGWTR2_EL2_RES0);
+	struct fgt_masks __n = { .str = #__m, .res0 = __m ## _RES0, .res1 = __m ## _RES1 }
+
+FGT_MASKS(hfgrtr_masks, HFGRTR_EL2);
+FGT_MASKS(hfgwtr_masks, HFGWTR_EL2);
+FGT_MASKS(hfgitr_masks, HFGITR_EL2);
+FGT_MASKS(hdfgrtr_masks, HDFGRTR_EL2);
+FGT_MASKS(hdfgwtr_masks, HDFGWTR_EL2);
+FGT_MASKS(hafgrtr_masks, HAFGRTR_EL2);
+FGT_MASKS(hfgrtr2_masks, HFGRTR2_EL2);
+FGT_MASKS(hfgwtr2_masks, HFGWTR2_EL2);
+FGT_MASKS(hfgitr2_masks, HFGITR2_EL2);
+FGT_MASKS(hdfgrtr2_masks, HDFGRTR2_EL2);
+FGT_MASKS(hdfgwtr2_masks, HDFGWTR2_EL2);
 
 static __init bool aggregate_fgt(union trap_config tc)
 {
 	struct fgt_masks *rmasks, *wmasks;
+	u64 rresx, wresx;
 
 	switch (tc.fgt) {
 	case HFGRTR_GROUP:
@@ -2154,24 +2155,27 @@ static __init bool aggregate_fgt(union trap_config tc)
 		break;
 	}
 
+	rresx = rmasks->res0 | rmasks->res1;
+	if (wmasks)
+		wresx = wmasks->res0 | wmasks->res1;
+
 	/*
 	 * A bit can be reserved in either the R or W register, but
 	 * not both.
 	 */
-	if ((BIT(tc.bit) & rmasks->res0) &&
-	    (!wmasks || (BIT(tc.bit) & wmasks->res0)))
+	if ((BIT(tc.bit) & rresx) && (!wmasks || (BIT(tc.bit) & wresx)))
 		return false;
 
 	if (tc.pol)
-		rmasks->mask |= BIT(tc.bit) & ~rmasks->res0;
+		rmasks->mask |= BIT(tc.bit) & ~rresx;
 	else
-		rmasks->nmask |= BIT(tc.bit) & ~rmasks->res0;
+		rmasks->nmask |= BIT(tc.bit) & ~rresx;
 
 	if (wmasks) {
 		if (tc.pol)
-			wmasks->mask |= BIT(tc.bit) & ~wmasks->res0;
+			wmasks->mask |= BIT(tc.bit) & ~wresx;
 		else
-			wmasks->nmask |= BIT(tc.bit) & ~wmasks->res0;
+			wmasks->nmask |= BIT(tc.bit) & ~wresx;
 	}
 
 	return true;
@@ -2180,7 +2184,6 @@ static __init bool aggregate_fgt(union trap_config tc)
 static __init int check_fgt_masks(struct fgt_masks *masks)
 {
 	unsigned long duplicate = masks->mask & masks->nmask;
-	u64 res0 = masks->res0;
 	int ret = 0;
 
 	if (duplicate) {
@@ -2194,10 +2197,14 @@ static __init int check_fgt_masks(struct fgt_masks *masks)
 		ret = -EINVAL;
 	}
 
-	masks->res0 = ~(masks->mask | masks->nmask);
-	if (masks->res0 != res0)
-		kvm_info("Implicit %s = %016llx, expecting %016llx\n",
-			 masks->str, masks->res0, res0);
+	if ((masks->res0 | masks->res1 | masks->mask | masks->nmask) != GENMASK(63, 0) ||
+	    (masks->res0 & masks->res1)  || (masks->res0 & masks->mask) ||
+	    (masks->res0 & masks->nmask) || (masks->res1 & masks->mask)  ||
+	    (masks->res1 & masks->nmask) || (masks->mask & masks->nmask)) {
+		kvm_info("Inconsistent masks for %s (%016llx, %016llx, %016llx, %016llx)\n",
+			 masks->str, masks->res0, masks->res1, masks->mask, masks->nmask);
+		masks->res0 = ~(masks->res1 | masks->mask | masks->nmask);
+	}
 
 	return ret;
 }
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:38 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:38 +0000
Subject: [PATCH v2 08/36] KVM: arm64: Introduce kvm_call_hyp_nvhe_res()
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-9-sascha.bischoff@arm.com>

There are times when it is desirable to have more than one return
value for a hyp call. Split out kvm_call_hyp_nvhe_res from
kvm_call_hyp_nvhe such that it is possible to directly provide struct
arm_smccc_res from the calling code. Thereby, additional return values
can be stored in res.a2, etc.

Suggested-by: Marc Zyngier <maz at kernel.org>
Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/include/asm/kvm_host.h | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index b552a1e03848c..971b153b0a3fa 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -1208,14 +1208,19 @@ void kvm_arm_resume_guest(struct kvm *kvm);
 #define vcpu_has_run_once(vcpu)	(!!READ_ONCE((vcpu)->pid))
 
 #ifndef __KVM_NVHE_HYPERVISOR__
-#define kvm_call_hyp_nvhe(f, ...)						\
+#define kvm_call_hyp_nvhe_res(res, f, ...)				\
 	({								\
-		struct arm_smccc_res res;				\
-									\
+		struct arm_smccc_res *__res = res;			\
 		arm_smccc_1_1_hvc(KVM_HOST_SMCCC_FUNC(f),		\
-				  ##__VA_ARGS__, &res);			\
-		WARN_ON(res.a0 != SMCCC_RET_SUCCESS);			\
+				  ##__VA_ARGS__, __res);		\
+		WARN_ON(__res->a0 != SMCCC_RET_SUCCESS);		\
+	})
+
+#define kvm_call_hyp_nvhe(f, ...)					\
+	({								\
+		struct arm_smccc_res res;				\
 									\
+		kvm_call_hyp_nvhe_res(&res, f, ##__VA_ARGS__);		\
 		res.a1;							\
 	})
 
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:38 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:38 +0000
Subject: [PATCH v2 07/36] KVM: arm64: gic: Introduce interrupt type helpers
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-8-sascha.bischoff@arm.com>

GICv5 has moved from using interrupt ranges for different interrupt
types to using some of the upper bits of the interrupt ID to denote
the interrupt type. This is not compatible with older GICs (which rely
on ranges of interrupts to determine the type), and hence a set of
helpers is introduced. These helpers take a struct kvm*, and use the
vgic model to determine how to interpret the interrupt ID.

Helpers are introduced for PPIs, SPIs, and LPIs. Additionally, a
helper is introduced to determine if an interrupt is private - SGIs
and PPIs for older GICs, and PPIs only for GICv5.

The helpers are plumbed into the core vgic code, as well as the Arch
Timer and PMU code.

There should be no functional changes as part of this change.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/arch_timer.c           |  2 +-
 arch/arm64/kvm/pmu-emul.c             |  7 ++-
 arch/arm64/kvm/vgic/vgic-kvm-device.c |  2 +-
 arch/arm64/kvm/vgic/vgic.c            | 14 ++---
 include/kvm/arm_vgic.h                | 82 +++++++++++++++++++++++++--
 5 files changed, 91 insertions(+), 16 deletions(-)

diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c
index 99a07972068d1..6f033f6644219 100644
--- a/arch/arm64/kvm/arch_timer.c
+++ b/arch/arm64/kvm/arch_timer.c
@@ -1598,7 +1598,7 @@ int kvm_arm_timer_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
 	if (get_user(irq, uaddr))
 		return -EFAULT;
 
-	if (!(irq_is_ppi(irq)))
+	if (!(irq_is_ppi(vcpu->kvm, irq)))
 		return -EINVAL;
 
 	mutex_lock(&vcpu->kvm->arch.config_lock);
diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c
index b03dbda7f1ab9..afc838ea2503e 100644
--- a/arch/arm64/kvm/pmu-emul.c
+++ b/arch/arm64/kvm/pmu-emul.c
@@ -939,7 +939,8 @@ int kvm_arm_pmu_v3_enable(struct kvm_vcpu *vcpu)
 		 * number against the dimensions of the vgic and make sure
 		 * it's valid.
 		 */
-		if (!irq_is_ppi(irq) && !vgic_valid_spi(vcpu->kvm, irq))
+		if (!irq_is_ppi(vcpu->kvm, irq) &&
+		    !vgic_valid_spi(vcpu->kvm, irq))
 			return -EINVAL;
 	} else if (kvm_arm_pmu_irq_initialized(vcpu)) {
 		   return -EINVAL;
@@ -991,7 +992,7 @@ static bool pmu_irq_is_valid(struct kvm *kvm, int irq)
 		if (!kvm_arm_pmu_irq_initialized(vcpu))
 			continue;
 
-		if (irq_is_ppi(irq)) {
+		if (irq_is_ppi(vcpu->kvm, irq)) {
 			if (vcpu->arch.pmu.irq_num != irq)
 				return false;
 		} else {
@@ -1142,7 +1143,7 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
 			return -EFAULT;
 
 		/* The PMU overflow interrupt can be a PPI or a valid SPI. */
-		if (!(irq_is_ppi(irq) || irq_is_spi(irq)))
+		if (!(irq_is_ppi(vcpu->kvm, irq) || irq_is_spi(vcpu->kvm, irq)))
 			return -EINVAL;
 
 		if (!pmu_irq_is_valid(kvm, irq))
diff --git a/arch/arm64/kvm/vgic/vgic-kvm-device.c b/arch/arm64/kvm/vgic/vgic-kvm-device.c
index 3d1a776b716d7..b12ba99a423e5 100644
--- a/arch/arm64/kvm/vgic/vgic-kvm-device.c
+++ b/arch/arm64/kvm/vgic/vgic-kvm-device.c
@@ -639,7 +639,7 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
 		if (vgic_initialized(dev->kvm))
 			return -EBUSY;
 
-		if (!irq_is_ppi(val))
+		if (!irq_is_ppi(dev->kvm, val))
 			return -EINVAL;
 
 		dev->kvm->arch.vgic.mi_intid = val;
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index 430aa98888fda..2c0e8803342e2 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -94,7 +94,7 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, u32 intid)
 	}
 
 	/* LPIs */
-	if (intid >= VGIC_MIN_LPI)
+	if (irq_is_lpi(kvm, intid))
 		return vgic_get_lpi(kvm, intid);
 
 	return NULL;
@@ -123,7 +123,7 @@ static void vgic_release_lpi_locked(struct vgic_dist *dist, struct vgic_irq *irq
 
 static __must_check bool __vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
 {
-	if (irq->intid < VGIC_MIN_LPI)
+	if (!irq_is_lpi(kvm, irq->intid))
 		return false;
 
 	return refcount_dec_and_test(&irq->refcount);
@@ -148,7 +148,7 @@ void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
 	 * Acquire/release it early on lockdep kernels to make locking issues
 	 * in rare release paths a bit more obvious.
 	 */
-	if (IS_ENABLED(CONFIG_LOCKDEP) && irq->intid >= VGIC_MIN_LPI) {
+	if (IS_ENABLED(CONFIG_LOCKDEP) && irq_is_lpi(kvm, irq->intid)) {
 		guard(spinlock_irqsave)(&dist->lpi_xa.xa_lock);
 	}
 
@@ -186,7 +186,7 @@ void vgic_flush_pending_lpis(struct kvm_vcpu *vcpu)
 	raw_spin_lock_irqsave(&vgic_cpu->ap_list_lock, flags);
 
 	list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
-		if (irq->intid >= VGIC_MIN_LPI) {
+		if (irq_is_lpi(vcpu->kvm, irq->intid)) {
 			raw_spin_lock(&irq->irq_lock);
 			list_del(&irq->ap_list);
 			irq->vcpu = NULL;
@@ -521,12 +521,12 @@ int kvm_vgic_inject_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 	if (ret)
 		return ret;
 
-	if (!vcpu && intid < VGIC_NR_PRIVATE_IRQS)
+	if (!vcpu && irq_is_private(kvm, intid))
 		return -EINVAL;
 
 	trace_vgic_update_irq_pending(vcpu ? vcpu->vcpu_idx : 0, intid, level);
 
-	if (intid < VGIC_NR_PRIVATE_IRQS)
+	if (irq_is_private(kvm, intid))
 		irq = vgic_get_vcpu_irq(vcpu, intid);
 	else
 		irq = vgic_get_irq(kvm, intid);
@@ -685,7 +685,7 @@ int kvm_vgic_set_owner(struct kvm_vcpu *vcpu, unsigned int intid, void *owner)
 		return -EAGAIN;
 
 	/* SGIs and LPIs cannot be wired up to any device */
-	if (!irq_is_ppi(intid) && !vgic_valid_spi(vcpu->kvm, intid))
+	if (!irq_is_ppi(vcpu->kvm, intid) && !vgic_valid_spi(vcpu->kvm, intid))
 		return -EINVAL;
 
 	irq = vgic_get_vcpu_irq(vcpu, intid);
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index b261fb3968d03..6778f676eaf08 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -19,6 +19,7 @@
 #include <linux/jump_label.h>
 
 #include <linux/irqchip/arm-gic-v4.h>
+#include <linux/irqchip/arm-gic-v5.h>
 
 #define VGIC_V3_MAX_CPUS	512
 #define VGIC_V2_MAX_CPUS	8
@@ -31,9 +32,78 @@
 #define VGIC_MIN_LPI		8192
 #define KVM_IRQCHIP_NUM_PINS	(1020 - 32)
 
-#define irq_is_ppi(irq) ((irq) >= VGIC_NR_SGIS && (irq) < VGIC_NR_PRIVATE_IRQS)
-#define irq_is_spi(irq) ((irq) >= VGIC_NR_PRIVATE_IRQS && \
-			 (irq) <= VGIC_MAX_SPI)
+#define is_v5_type(t, i)	(FIELD_GET(GICV5_HWIRQ_TYPE, (i)) == (t))
+
+#define __irq_is_sgi(t, i)						\
+	({								\
+		bool __ret;						\
+									\
+		switch (t) {						\
+		case KVM_DEV_TYPE_ARM_VGIC_V5:				\
+			__ret = false;					\
+			break;						\
+		default:						\
+			__ret  = (i) < VGIC_NR_SGIS;			\
+		}							\
+									\
+		__ret;							\
+	})
+
+#define __irq_is_ppi(t, i)						\
+	({								\
+		bool __ret;						\
+									\
+		switch (t) {						\
+		case KVM_DEV_TYPE_ARM_VGIC_V5:				\
+			__ret = is_v5_type(GICV5_HWIRQ_TYPE_PPI, (i));	\
+			break;						\
+		default:						\
+			__ret  = (i) >= VGIC_NR_SGIS;			\
+			__ret &= (i) < VGIC_NR_PRIVATE_IRQS;		\
+		}							\
+									\
+		__ret;							\
+	})
+
+#define __irq_is_spi(t, i)						\
+	({								\
+		bool __ret;						\
+									\
+		switch (t) {						\
+		case KVM_DEV_TYPE_ARM_VGIC_V5:				\
+			__ret = is_v5_type(GICV5_HWIRQ_TYPE_SPI, (i));	\
+			break;						\
+		default:						\
+			__ret  = (i) <= VGIC_MAX_SPI;			\
+			__ret &= (i) >= VGIC_NR_PRIVATE_IRQS;		\
+		}							\
+									\
+		__ret;							\
+	})
+
+#define __irq_is_lpi(t, i)						\
+	({								\
+		bool __ret;						\
+									\
+		switch (t) {						\
+		case KVM_DEV_TYPE_ARM_VGIC_V5:				\
+			__ret = is_v5_type(GICV5_HWIRQ_TYPE_LPI, (i));	\
+			break;						\
+		default:						\
+			__ret  = (i) >= 8192;				\
+		}							\
+									\
+		__ret;							\
+	})
+
+#define irq_is_sgi(k, i) __irq_is_sgi((k)->arch.vgic.vgic_model, i)
+#define irq_is_ppi(k, i) __irq_is_ppi((k)->arch.vgic.vgic_model, i)
+#define irq_is_spi(k, i) __irq_is_spi((k)->arch.vgic.vgic_model, i)
+#define irq_is_lpi(k, i) __irq_is_lpi((k)->arch.vgic.vgic_model, i)
+
+#define irq_is_private(k, i) (irq_is_ppi(k, i) || irq_is_sgi(k, i))
+
+#define vgic_is_v5(k) ((k)->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5)
 
 enum vgic_type {
 	VGIC_V2,		/* Good ol' GICv2 */
@@ -418,8 +488,12 @@ u64 vgic_v3_get_misr(struct kvm_vcpu *vcpu);
 
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
 #define vgic_initialized(k)	((k)->arch.vgic.initialized)
-#define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
+#define vgic_valid_nv5_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
 			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
+#define vgic_valid_v5_spi(k, i)	(irq_is_spi(k, i) && \
+				 (FIELD_GET(GICV5_HWIRQ_ID, i) < (k)->arch.vgic.nr_spis))
+#define vgic_valid_spi(k, i) (vgic_is_v5(k) ?				\
+			      vgic_valid_v5_spi(k, i) : vgic_valid_nv5_spi(k, i))
 
 bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
 void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:36 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:36 +0000
Subject: [PATCH v2 02/36] KVM: arm64: gic-v3: Switch vGIC-v3 to use generated
 ICH_VMCR_EL2
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-3-sascha.bischoff@arm.com>

From: Sascha Bischoff <Sascha.Bischoff at arm.com>

The VGIC-v3 code relied on hand-written definitions for the
ICH_VMCR_EL2 register. This register, and the associated fields, is
now generated as part of the sysreg framework. Move to using the
generated definitions instead of the hand-written ones.

There are no functional changes as part of this change.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/include/asm/sysreg.h      | 21 ---------
 arch/arm64/kvm/hyp/vgic-v3-sr.c      | 64 ++++++++++++----------------
 arch/arm64/kvm/vgic/vgic-v3-nested.c |  8 ++--
 arch/arm64/kvm/vgic/vgic-v3.c        | 48 ++++++++++-----------
 4 files changed, 54 insertions(+), 87 deletions(-)

diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 9df51accbb025..b3b8b8cd7bf1e 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -560,7 +560,6 @@
 #define SYS_ICC_SRE_EL2			sys_reg(3, 4, 12, 9, 5)
 #define SYS_ICH_EISR_EL2		sys_reg(3, 4, 12, 11, 3)
 #define SYS_ICH_ELRSR_EL2		sys_reg(3, 4, 12, 11, 5)
-#define SYS_ICH_VMCR_EL2		sys_reg(3, 4, 12, 11, 7)
 
 #define __SYS__LR0_EL2(x)		sys_reg(3, 4, 12, 12, x)
 #define SYS_ICH_LR0_EL2			__SYS__LR0_EL2(0)
@@ -988,26 +987,6 @@
 #define ICH_LR_PRIORITY_SHIFT	48
 #define ICH_LR_PRIORITY_MASK	(0xffULL << ICH_LR_PRIORITY_SHIFT)
 
-/* ICH_VMCR_EL2 bit definitions */
-#define ICH_VMCR_ACK_CTL_SHIFT	2
-#define ICH_VMCR_ACK_CTL_MASK	(1 << ICH_VMCR_ACK_CTL_SHIFT)
-#define ICH_VMCR_FIQ_EN_SHIFT	3
-#define ICH_VMCR_FIQ_EN_MASK	(1 << ICH_VMCR_FIQ_EN_SHIFT)
-#define ICH_VMCR_CBPR_SHIFT	4
-#define ICH_VMCR_CBPR_MASK	(1 << ICH_VMCR_CBPR_SHIFT)
-#define ICH_VMCR_EOIM_SHIFT	9
-#define ICH_VMCR_EOIM_MASK	(1 << ICH_VMCR_EOIM_SHIFT)
-#define ICH_VMCR_BPR1_SHIFT	18
-#define ICH_VMCR_BPR1_MASK	(7 << ICH_VMCR_BPR1_SHIFT)
-#define ICH_VMCR_BPR0_SHIFT	21
-#define ICH_VMCR_BPR0_MASK	(7 << ICH_VMCR_BPR0_SHIFT)
-#define ICH_VMCR_PMR_SHIFT	24
-#define ICH_VMCR_PMR_MASK	(0xffUL << ICH_VMCR_PMR_SHIFT)
-#define ICH_VMCR_ENG0_SHIFT	0
-#define ICH_VMCR_ENG0_MASK	(1 << ICH_VMCR_ENG0_SHIFT)
-#define ICH_VMCR_ENG1_SHIFT	1
-#define ICH_VMCR_ENG1_MASK	(1 << ICH_VMCR_ENG1_SHIFT)
-
 /*
  * Permission Indirection Extension (PIE) permission encodings.
  * Encodings with the _O suffix, have overlays applied (Permission Overlay Extension).
diff --git a/arch/arm64/kvm/hyp/vgic-v3-sr.c b/arch/arm64/kvm/hyp/vgic-v3-sr.c
index 0b670a033fd87..298101434fc75 100644
--- a/arch/arm64/kvm/hyp/vgic-v3-sr.c
+++ b/arch/arm64/kvm/hyp/vgic-v3-sr.c
@@ -569,11 +569,11 @@ static int __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu, u32 vmcr,
 			continue;
 
 		/* Group-0 interrupt, but Group-0 disabled? */
-		if (!(val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG0_MASK))
+		if (!(val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_EL2_VENG0_MASK))
 			continue;
 
 		/* Group-1 interrupt, but Group-1 disabled? */
-		if ((val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG1_MASK))
+		if ((val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_EL2_VENG1_MASK))
 			continue;
 
 		/* Not the highest priority? */
@@ -646,19 +646,19 @@ static int __vgic_v3_get_highest_active_priority(void)
 
 static unsigned int __vgic_v3_get_bpr0(u32 vmcr)
 {
-	return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
+	return FIELD_GET(ICH_VMCR_EL2_VBPR0, vmcr);
 }
 
 static unsigned int __vgic_v3_get_bpr1(u32 vmcr)
 {
 	unsigned int bpr;
 
-	if (vmcr & ICH_VMCR_CBPR_MASK) {
+	if (vmcr & ICH_VMCR_EL2_VCBPR_MASK) {
 		bpr = __vgic_v3_get_bpr0(vmcr);
 		if (bpr < 7)
 			bpr++;
 	} else {
-		bpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
+		bpr = FIELD_GET(ICH_VMCR_EL2_VBPR1, vmcr);
 	}
 
 	return bpr;
@@ -758,7 +758,7 @@ static void __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 	if (grp != !!(lr_val & ICH_LR_GROUP))
 		goto spurious;
 
-	pmr = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
+	pmr = FIELD_GET(ICH_VMCR_EL2_VPMR, vmcr);
 	lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
 	if (pmr <= lr_prio)
 		goto spurious;
@@ -806,7 +806,7 @@ static int ___vgic_v3_write_dir(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 	int lr;
 
 	/* EOImode == 0, nothing to be done here */
-	if (!(vmcr & ICH_VMCR_EOIM_MASK))
+	if (!(vmcr & ICH_VMCR_EL2_VEOIM_MASK))
 		return 1;
 
 	/* No deactivate to be performed on an LPI */
@@ -849,7 +849,7 @@ static void __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 	}
 
 	/* EOImode == 1 and not an LPI, nothing to be done here */
-	if ((vmcr & ICH_VMCR_EOIM_MASK) && !(vid >= VGIC_MIN_LPI))
+	if ((vmcr & ICH_VMCR_EL2_VEOIM_MASK) && !(vid >= VGIC_MIN_LPI))
 		return;
 
 	lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
@@ -865,12 +865,12 @@ static void __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 
 static void __vgic_v3_read_igrpen0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 {
-	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG0_MASK));
+	vcpu_set_reg(vcpu, rt, vmcr & ICH_VMCR_EL2_VENG0_MASK);
 }
 
 static void __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 {
-	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
+	vcpu_set_reg(vcpu, rt, vmcr & ICH_VMCR_EL2_VENG1_MASK);
 }
 
 static void __vgic_v3_write_igrpen0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
@@ -878,9 +878,9 @@ static void __vgic_v3_write_igrpen0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 	u64 val = vcpu_get_reg(vcpu, rt);
 
 	if (val & 1)
-		vmcr |= ICH_VMCR_ENG0_MASK;
+		vmcr |= ICH_VMCR_EL2_VENG0_MASK;
 	else
-		vmcr &= ~ICH_VMCR_ENG0_MASK;
+		vmcr &= ~ICH_VMCR_EL2_VENG0_MASK;
 
 	__vgic_v3_write_vmcr(vmcr);
 }
@@ -890,9 +890,9 @@ static void __vgic_v3_write_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 	u64 val = vcpu_get_reg(vcpu, rt);
 
 	if (val & 1)
-		vmcr |= ICH_VMCR_ENG1_MASK;
+		vmcr |= ICH_VMCR_EL2_VENG1_MASK;
 	else
-		vmcr &= ~ICH_VMCR_ENG1_MASK;
+		vmcr &= ~ICH_VMCR_EL2_VENG1_MASK;
 
 	__vgic_v3_write_vmcr(vmcr);
 }
@@ -916,10 +916,8 @@ static void __vgic_v3_write_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 	if (val < bpr_min)
 		val = bpr_min;
 
-	val <<= ICH_VMCR_BPR0_SHIFT;
-	val &= ICH_VMCR_BPR0_MASK;
-	vmcr &= ~ICH_VMCR_BPR0_MASK;
-	vmcr |= val;
+	vmcr &= ~ICH_VMCR_EL2_VBPR0_MASK;
+	vmcr |= FIELD_PREP(ICH_VMCR_EL2_VBPR0, val);
 
 	__vgic_v3_write_vmcr(vmcr);
 }
@@ -929,17 +927,15 @@ static void __vgic_v3_write_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 	u64 val = vcpu_get_reg(vcpu, rt);
 	u8 bpr_min = __vgic_v3_bpr_min();
 
-	if (vmcr & ICH_VMCR_CBPR_MASK)
+	if (FIELD_GET(ICH_VMCR_EL2_VCBPR_MASK, val))
 		return;
 
 	/* Enforce BPR limiting */
 	if (val < bpr_min)
 		val = bpr_min;
 
-	val <<= ICH_VMCR_BPR1_SHIFT;
-	val &= ICH_VMCR_BPR1_MASK;
-	vmcr &= ~ICH_VMCR_BPR1_MASK;
-	vmcr |= val;
+	vmcr &= ~ICH_VMCR_EL2_VBPR1_MASK;
+	vmcr |= FIELD_PREP(ICH_VMCR_EL2_VBPR1, val);
 
 	__vgic_v3_write_vmcr(vmcr);
 }
@@ -1029,19 +1025,15 @@ static void __vgic_v3_read_hppir(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 
 static void __vgic_v3_read_pmr(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 {
-	vmcr &= ICH_VMCR_PMR_MASK;
-	vmcr >>= ICH_VMCR_PMR_SHIFT;
-	vcpu_set_reg(vcpu, rt, vmcr);
+	vcpu_set_reg(vcpu, rt, FIELD_GET(ICH_VMCR_EL2_VPMR, vmcr));
 }
 
 static void __vgic_v3_write_pmr(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 {
 	u32 val = vcpu_get_reg(vcpu, rt);
 
-	val <<= ICH_VMCR_PMR_SHIFT;
-	val &= ICH_VMCR_PMR_MASK;
-	vmcr &= ~ICH_VMCR_PMR_MASK;
-	vmcr |= val;
+	vmcr &= ~ICH_VMCR_EL2_VPMR_MASK;
+	vmcr |= FIELD_PREP(ICH_VMCR_EL2_VPMR, val);
 
 	write_gicreg(vmcr, ICH_VMCR_EL2);
 }
@@ -1064,9 +1056,9 @@ static void __vgic_v3_read_ctlr(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 	/* A3V */
 	val |= ((vtr >> 21) & 1) << ICC_CTLR_EL1_A3V_SHIFT;
 	/* EOImode */
-	val |= ((vmcr & ICH_VMCR_EOIM_MASK) >> ICH_VMCR_EOIM_SHIFT) << ICC_CTLR_EL1_EOImode_SHIFT;
+	val |= FIELD_GET(ICH_VMCR_EL2_VEOIM, vmcr) << ICC_CTLR_EL1_EOImode_SHIFT;
 	/* CBPR */
-	val |= (vmcr & ICH_VMCR_CBPR_MASK) >> ICH_VMCR_CBPR_SHIFT;
+	val |= FIELD_GET(ICH_VMCR_EL2_VCBPR, vmcr);
 
 	vcpu_set_reg(vcpu, rt, val);
 }
@@ -1076,14 +1068,14 @@ static void __vgic_v3_write_ctlr(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 	u32 val = vcpu_get_reg(vcpu, rt);
 
 	if (val & ICC_CTLR_EL1_CBPR_MASK)
-		vmcr |= ICH_VMCR_CBPR_MASK;
+		vmcr |= ICH_VMCR_EL2_VCBPR_MASK;
 	else
-		vmcr &= ~ICH_VMCR_CBPR_MASK;
+		vmcr &= ~ICH_VMCR_EL2_VCBPR_MASK;
 
 	if (val & ICC_CTLR_EL1_EOImode_MASK)
-		vmcr |= ICH_VMCR_EOIM_MASK;
+		vmcr |= ICH_VMCR_EL2_VEOIM_MASK;
 	else
-		vmcr &= ~ICH_VMCR_EOIM_MASK;
+		vmcr &= ~ICH_VMCR_EL2_VEOIM_MASK;
 
 	write_gicreg(vmcr, ICH_VMCR_EL2);
 }
diff --git a/arch/arm64/kvm/vgic/vgic-v3-nested.c b/arch/arm64/kvm/vgic/vgic-v3-nested.c
index 61b44f3f2bf14..c9e35ec671173 100644
--- a/arch/arm64/kvm/vgic/vgic-v3-nested.c
+++ b/arch/arm64/kvm/vgic/vgic-v3-nested.c
@@ -202,16 +202,16 @@ u64 vgic_v3_get_misr(struct kvm_vcpu *vcpu)
 	if ((hcr & ICH_HCR_EL2_NPIE) && !mi_state.pend)
 		reg |= ICH_MISR_EL2_NP;
 
-	if ((hcr & ICH_HCR_EL2_VGrp0EIE) && (vmcr & ICH_VMCR_ENG0_MASK))
+	if ((hcr & ICH_HCR_EL2_VGrp0EIE) && (vmcr & ICH_VMCR_EL2_VENG0_MASK))
 		reg |= ICH_MISR_EL2_VGrp0E;
 
-	if ((hcr & ICH_HCR_EL2_VGrp0DIE) && !(vmcr & ICH_VMCR_ENG0_MASK))
+	if ((hcr & ICH_HCR_EL2_VGrp0DIE) && !(vmcr & ICH_VMCR_EL2_VENG0_MASK))
 		reg |= ICH_MISR_EL2_VGrp0D;
 
-	if ((hcr & ICH_HCR_EL2_VGrp1EIE) && (vmcr & ICH_VMCR_ENG1_MASK))
+	if ((hcr & ICH_HCR_EL2_VGrp1EIE) && (vmcr & ICH_VMCR_EL2_VENG1_MASK))
 		reg |= ICH_MISR_EL2_VGrp1E;
 
-	if ((hcr & ICH_HCR_EL2_VGrp1DIE) && !(vmcr & ICH_VMCR_ENG1_MASK))
+	if ((hcr & ICH_HCR_EL2_VGrp1DIE) && !(vmcr & ICH_VMCR_EL2_VENG1_MASK))
 		reg |= ICH_MISR_EL2_VGrp1D;
 
 	return reg;
diff --git a/arch/arm64/kvm/vgic/vgic-v3.c b/arch/arm64/kvm/vgic/vgic-v3.c
index 1d6dd1b545bdd..2afc041672311 100644
--- a/arch/arm64/kvm/vgic/vgic-v3.c
+++ b/arch/arm64/kvm/vgic/vgic-v3.c
@@ -41,9 +41,9 @@ void vgic_v3_configure_hcr(struct kvm_vcpu *vcpu,
 	if (!als->nr_sgi)
 		cpuif->vgic_hcr |= ICH_HCR_EL2_vSGIEOICount;
 
-	cpuif->vgic_hcr |= (cpuif->vgic_vmcr & ICH_VMCR_ENG0_MASK) ?
+	cpuif->vgic_hcr |= (cpuif->vgic_vmcr & ICH_VMCR_EL2_VENG0_MASK) ?
 		ICH_HCR_EL2_VGrp0DIE : ICH_HCR_EL2_VGrp0EIE;
-	cpuif->vgic_hcr |= (cpuif->vgic_vmcr & ICH_VMCR_ENG1_MASK) ?
+	cpuif->vgic_hcr |= (cpuif->vgic_vmcr & ICH_VMCR_EL2_VENG1_MASK) ?
 		ICH_HCR_EL2_VGrp1DIE : ICH_HCR_EL2_VGrp1EIE;
 
 	/*
@@ -215,7 +215,7 @@ void vgic_v3_deactivate(struct kvm_vcpu *vcpu, u64 val)
 	 * We only deal with DIR when EOIMode==1, and only for SGI,
 	 * PPI or SPI.
 	 */
-	if (!(cpuif->vgic_vmcr & ICH_VMCR_EOIM_MASK) ||
+	if (!(cpuif->vgic_vmcr & ICH_VMCR_EL2_VEOIM_MASK) ||
 	    val >= vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS)
 		return;
 
@@ -408,25 +408,23 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 	u32 vmcr;
 
 	if (model == KVM_DEV_TYPE_ARM_VGIC_V2) {
-		vmcr = (vmcrp->ackctl << ICH_VMCR_ACK_CTL_SHIFT) &
-			ICH_VMCR_ACK_CTL_MASK;
-		vmcr |= (vmcrp->fiqen << ICH_VMCR_FIQ_EN_SHIFT) &
-			ICH_VMCR_FIQ_EN_MASK;
+		vmcr = FIELD_PREP(ICH_VMCR_EL2_VAckCtl, vmcrp->ackctl);
+		vmcr |= FIELD_PREP(ICH_VMCR_EL2_VFIQEn, vmcrp->fiqen);
 	} else {
 		/*
 		 * When emulating GICv3 on GICv3 with SRE=1 on the
 		 * VFIQEn bit is RES1 and the VAckCtl bit is RES0.
 		 */
-		vmcr = ICH_VMCR_FIQ_EN_MASK;
+		vmcr = ICH_VMCR_EL2_VFIQEn_MASK;
 	}
 
-	vmcr |= (vmcrp->cbpr << ICH_VMCR_CBPR_SHIFT) & ICH_VMCR_CBPR_MASK;
-	vmcr |= (vmcrp->eoim << ICH_VMCR_EOIM_SHIFT) & ICH_VMCR_EOIM_MASK;
-	vmcr |= (vmcrp->abpr << ICH_VMCR_BPR1_SHIFT) & ICH_VMCR_BPR1_MASK;
-	vmcr |= (vmcrp->bpr << ICH_VMCR_BPR0_SHIFT) & ICH_VMCR_BPR0_MASK;
-	vmcr |= (vmcrp->pmr << ICH_VMCR_PMR_SHIFT) & ICH_VMCR_PMR_MASK;
-	vmcr |= (vmcrp->grpen0 << ICH_VMCR_ENG0_SHIFT) & ICH_VMCR_ENG0_MASK;
-	vmcr |= (vmcrp->grpen1 << ICH_VMCR_ENG1_SHIFT) & ICH_VMCR_ENG1_MASK;
+	vmcr |= FIELD_PREP(ICH_VMCR_EL2_VCBPR, vmcrp->cbpr);
+	vmcr |= FIELD_PREP(ICH_VMCR_EL2_VEOIM, vmcrp->eoim);
+	vmcr |= FIELD_PREP(ICH_VMCR_EL2_VBPR1, vmcrp->abpr);
+	vmcr |= FIELD_PREP(ICH_VMCR_EL2_VBPR0, vmcrp->bpr);
+	vmcr |= FIELD_PREP(ICH_VMCR_EL2_VPMR, vmcrp->pmr);
+	vmcr |= FIELD_PREP(ICH_VMCR_EL2_VENG0, vmcrp->grpen0);
+	vmcr |= FIELD_PREP(ICH_VMCR_EL2_VENG1, vmcrp->grpen1);
 
 	cpu_if->vgic_vmcr = vmcr;
 }
@@ -440,10 +438,8 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 	vmcr = cpu_if->vgic_vmcr;
 
 	if (model == KVM_DEV_TYPE_ARM_VGIC_V2) {
-		vmcrp->ackctl = (vmcr & ICH_VMCR_ACK_CTL_MASK) >>
-			ICH_VMCR_ACK_CTL_SHIFT;
-		vmcrp->fiqen = (vmcr & ICH_VMCR_FIQ_EN_MASK) >>
-			ICH_VMCR_FIQ_EN_SHIFT;
+		vmcrp->ackctl = FIELD_GET(ICH_VMCR_EL2_VAckCtl, vmcr);
+		vmcrp->fiqen = FIELD_GET(ICH_VMCR_EL2_VFIQEn, vmcr);
 	} else {
 		/*
 		 * When emulating GICv3 on GICv3 with SRE=1 on the
@@ -453,13 +449,13 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 		vmcrp->ackctl = 0;
 	}
 
-	vmcrp->cbpr = (vmcr & ICH_VMCR_CBPR_MASK) >> ICH_VMCR_CBPR_SHIFT;
-	vmcrp->eoim = (vmcr & ICH_VMCR_EOIM_MASK) >> ICH_VMCR_EOIM_SHIFT;
-	vmcrp->abpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
-	vmcrp->bpr  = (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
-	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
-	vmcrp->grpen0 = (vmcr & ICH_VMCR_ENG0_MASK) >> ICH_VMCR_ENG0_SHIFT;
-	vmcrp->grpen1 = (vmcr & ICH_VMCR_ENG1_MASK) >> ICH_VMCR_ENG1_SHIFT;
+	vmcrp->cbpr = FIELD_GET(ICH_VMCR_EL2_VCBPR, vmcr);
+	vmcrp->eoim = FIELD_GET(ICH_VMCR_EL2_VEOIM, vmcr);
+	vmcrp->abpr = FIELD_GET(ICH_VMCR_EL2_VBPR1, vmcr);
+	vmcrp->bpr  = FIELD_GET(ICH_VMCR_EL2_VBPR0, vmcr);
+	vmcrp->pmr  = FIELD_GET(ICH_VMCR_EL2_VPMR, vmcr);
+	vmcrp->grpen0 = FIELD_GET(ICH_VMCR_EL2_VENG0, vmcr);
+	vmcrp->grpen1 = FIELD_GET(ICH_VMCR_EL2_VENG1, vmcr);
 }
 
 #define INITIAL_PENDBASER_VALUE						  \
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:39 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:39 +0000
Subject: [PATCH v2 10/36] KVM: arm64: gic-v5: Sanitize ID_AA64PFR2_EL1.GCIE
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-11-sascha.bischoff@arm.com>

Set the guest's view of the GCIE field to IMP when running a GICv5 VM,
NI otherwise. Reject any writes to the register that try to do
anything but set GCIE to IMP when running a GICv5 VM.

As part of this change, we also introduce vgic_is_v5(kvm), in order to
check if the guest is a GICv5-native VM. We're also required to extend
vgic_is_v3_compat to check for the actual vgic_model. This has one
potential issue - if any of the vgic_is_v* checks are used prior to
setting the vgic_model (that is, before kvm_vgic_create) then
vgic_model will be set to 0, which can result in a false-positive.

Co-authored-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/sys_regs.c  | 39 ++++++++++++++++++++++++++++++--------
 arch/arm64/kvm/vgic/vgic.h | 10 +++++++++-
 2 files changed, 40 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index c8fd7c6a12a13..a065f8939bc8f 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1758,6 +1758,7 @@ static u8 pmuver_to_perfmon(u8 pmuver)
 
 static u64 sanitise_id_aa64pfr0_el1(const struct kvm_vcpu *vcpu, u64 val);
 static u64 sanitise_id_aa64pfr1_el1(const struct kvm_vcpu *vcpu, u64 val);
+static u64 sanitise_id_aa64pfr2_el1(const struct kvm_vcpu *vcpu, u64 val);
 static u64 sanitise_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val);
 
 /* Read a sanitised cpufeature ID register by sys_reg_desc */
@@ -1783,10 +1784,7 @@ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu,
 		val = sanitise_id_aa64pfr1_el1(vcpu, val);
 		break;
 	case SYS_ID_AA64PFR2_EL1:
-		val &= ID_AA64PFR2_EL1_FPMR |
-			(kvm_has_mte(vcpu->kvm) ?
-			 ID_AA64PFR2_EL1_MTEFAR | ID_AA64PFR2_EL1_MTESTOREONLY :
-			 0);
+		val = sanitise_id_aa64pfr2_el1(vcpu, val);
 		break;
 	case SYS_ID_AA64ISAR1_EL1:
 		if (!vcpu_has_ptrauth(vcpu))
@@ -2024,6 +2022,20 @@ static u64 sanitise_id_aa64pfr1_el1(const struct kvm_vcpu *vcpu, u64 val)
 	return val;
 }
 
+static u64 sanitise_id_aa64pfr2_el1(const struct kvm_vcpu *vcpu, u64 val)
+{
+	val &= ID_AA64PFR2_EL1_FPMR |
+		(kvm_has_mte(vcpu->kvm) ?
+			ID_AA64PFR2_EL1_MTEFAR | ID_AA64PFR2_EL1_MTESTOREONLY : 0);
+
+	if (vgic_is_v5(vcpu->kvm)) {
+		val &= ~ID_AA64PFR2_EL1_GCIE_MASK;
+		val |= SYS_FIELD_PREP_ENUM(ID_AA64PFR2_EL1, GCIE, IMP);
+	}
+
+	return val;
+}
+
 static u64 sanitise_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val)
 {
 	val = ID_REG_LIMIT_FIELD_ENUM(val, ID_AA64DFR0_EL1, DebugVer, V8P8);
@@ -2221,6 +2233,16 @@ static int set_id_aa64pfr1_el1(struct kvm_vcpu *vcpu,
 	return set_id_reg(vcpu, rd, user_val);
 }
 
+static int set_id_aa64pfr2_el1(struct kvm_vcpu *vcpu,
+			       const struct sys_reg_desc *rd, u64 user_val)
+{
+	if (vgic_is_v5(vcpu->kvm) &&
+	    FIELD_GET(ID_AA64PFR2_EL1_GCIE_MASK, user_val) != ID_AA64PFR2_EL1_GCIE_IMP)
+		return -EINVAL;
+
+	return set_id_reg(vcpu, rd, user_val);
+}
+
 /*
  * Allow userspace to de-feature a stage-2 translation granule but prevent it
  * from claiming the impossible.
@@ -3202,10 +3224,11 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 				       ID_AA64PFR1_EL1_RES0 |
 				       ID_AA64PFR1_EL1_MPAM_frac |
 				       ID_AA64PFR1_EL1_MTE)),
-	ID_WRITABLE(ID_AA64PFR2_EL1,
-		    ID_AA64PFR2_EL1_FPMR |
-		    ID_AA64PFR2_EL1_MTEFAR |
-		    ID_AA64PFR2_EL1_MTESTOREONLY),
+	ID_FILTERED(ID_AA64PFR2_EL1, id_aa64pfr2_el1,
+		    ~(ID_AA64PFR2_EL1_FPMR |
+		      ID_AA64PFR2_EL1_MTEFAR |
+		      ID_AA64PFR2_EL1_MTESTOREONLY |
+		      ID_AA64PFR2_EL1_GCIE)),
 	ID_UNALLOCATED(4,3),
 	ID_WRITABLE(ID_AA64ZFR0_EL1, ~ID_AA64ZFR0_EL1_RES0),
 	ID_HIDDEN(ID_AA64SMFR0_EL1),
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index 15f6afe6b75e1..eb16184c14cc5 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -456,8 +456,16 @@ void vgic_v3_nested_update_mi(struct kvm_vcpu *vcpu);
 
 static inline bool vgic_is_v3_compat(struct kvm *kvm)
 {
+	/*
+	 * We need to be careful here. This could be called early,
+	 * which means that there is no vgic_model set. For the time
+	 * being, fall back to assuming that we're trying run a legacy
+	 * VM in that case, which keeps existing software happy. Long
+	 * term, this will need to be revisited a little.
+	 */
 	return cpus_have_final_cap(ARM64_HAS_GICV5_CPUIF) &&
-		kvm_vgic_global_state.has_gcie_v3_compat;
+		kvm_vgic_global_state.has_gcie_v3_compat &&
+		kvm->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V5;
 }
 
 static inline bool vgic_is_v3(struct kvm *kvm)
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:36 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:36 +0000
Subject: [PATCH v2 03/36] arm64/sysreg: Drop ICH_HFGRTR_EL2.ICC_HAPR_EL1 and
 make RES1
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-4-sascha.bischoff@arm.com>

The GICv5 architecture is dropping the ICC_HAPR_EL1 and ICV_HAPR_EL1
system registers. These registers were never added to the sysregs, but
the traps for them were.

Drop the trap bit from the ICH_HFGRTR_EL2 and make it Res1 as per the
upcoming GICv5 spec change. Additionally, update the EL2 setup code to
not attempt to set that bit.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/include/asm/el2_setup.h | 1 -
 arch/arm64/tools/sysreg            | 2 +-
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h
index cacd20df1786e..07c12f4a69b41 100644
--- a/arch/arm64/include/asm/el2_setup.h
+++ b/arch/arm64/include/asm/el2_setup.h
@@ -225,7 +225,6 @@
 		     ICH_HFGRTR_EL2_ICC_ICSR_EL1		| \
 		     ICH_HFGRTR_EL2_ICC_PCR_EL1			| \
 		     ICH_HFGRTR_EL2_ICC_HPPIR_EL1		| \
-		     ICH_HFGRTR_EL2_ICC_HAPR_EL1		| \
 		     ICH_HFGRTR_EL2_ICC_CR0_EL1			| \
 		     ICH_HFGRTR_EL2_ICC_IDRn_EL1		| \
 		     ICH_HFGRTR_EL2_ICC_APR_EL1)
diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
index 8921b51866d64..dab5bfe8c9686 100644
--- a/arch/arm64/tools/sysreg
+++ b/arch/arm64/tools/sysreg
@@ -4579,7 +4579,7 @@ Field	7	ICC_IAFFIDR_EL1
 Field	6	ICC_ICSR_EL1
 Field	5	ICC_PCR_EL1
 Field	4	ICC_HPPIR_EL1
-Field	3	ICC_HAPR_EL1
+Res1	3
 Field	2	ICC_CR0_EL1
 Field	1	ICC_IDRn_EL1
 Field	0	ICC_APR_EL1
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:39 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:39 +0000
Subject: [PATCH v2 12/36] KVM: arm64: gic-v5: Add emulation for
 ICC_IAFFIDR_EL1 accesses
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-13-sascha.bischoff@arm.com>

GICv5 doesn't provide an ICV_IAFFIDR_EL1 or ICH_IAFFIDR_EL2 for
providing the IAFFID to the guest. A guest access to the
ICC_IAFFIDR_EL1 must therefore be trapped and emulated to avoid the
guest accessing the host's ICC_IAFFIDR_EL1.

The virtual IAFFID is provided to the guest when it reads
ICC_IAFFIDR_EL1 (which always traps back to the hypervisor). Writes are
rightly ignored. KVM treats the GICv5 VPEID, the virtual IAFFID, and
the vcpu_id as the same, and so the vcpu_id is returned.

The trapping for the ICC_IAFFIDR_EL1 is always enabled when in a guest
context.

Co-authored-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/config.c   | 10 +++++++++-
 arch/arm64/kvm/sys_regs.c | 16 ++++++++++++++++
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index 5f57dc07cc482..eb0c6f4d95b6d 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -1582,6 +1582,14 @@ static void __compute_hdfgwtr(struct kvm_vcpu *vcpu)
 		*vcpu_fgt(vcpu, HDFGWTR_EL2) |= HDFGWTR_EL2_MDSCR_EL1;
 }
 
+static void __compute_ich_hfgrtr(struct kvm_vcpu *vcpu)
+{
+	__compute_fgt(vcpu, ICH_HFGRTR_EL2);
+
+	/* ICC_IAFFIDR_EL1 *always* needs to be trapped when running a guest */
+	*vcpu_fgt(vcpu, ICH_HFGRTR_EL2) &= ~ICH_HFGRTR_EL2_ICC_IAFFIDR_EL1;
+}
+
 void kvm_vcpu_load_fgt(struct kvm_vcpu *vcpu)
 {
 	if (!cpus_have_final_cap(ARM64_HAS_FGT))
@@ -1607,7 +1615,7 @@ void kvm_vcpu_load_fgt(struct kvm_vcpu *vcpu)
 	if (!cpus_have_final_cap(ARM64_HAS_GICV5_CPUIF))
 		return;
 
-	__compute_fgt(vcpu, ICH_HFGRTR_EL2);
+	__compute_ich_hfgrtr(vcpu);
 	__compute_fgt(vcpu, ICH_HFGWTR_EL2);
 	__compute_fgt(vcpu, ICH_HFGITR_EL2);
 }
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index fbbd7b6ff6507..383ada0d75922 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -681,6 +681,21 @@ static bool access_gic_dir(struct kvm_vcpu *vcpu,
 	return true;
 }
 
+static bool access_gicv5_iaffid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+				const struct sys_reg_desc *r)
+{
+	if (p->is_write)
+		return ignore_write(vcpu, p);
+
+	/*
+	 * For GICv5 VMs, the IAFFID value is the same as the VPE ID. The VPE ID
+	 * is the same as the VCPU's ID.
+	 */
+	p->regval = FIELD_PREP(ICC_IAFFIDR_EL1_IAFFID, vcpu->vcpu_id);
+
+	return true;
+}
+
 static bool trap_raz_wi(struct kvm_vcpu *vcpu,
 			struct sys_reg_params *p,
 			const struct sys_reg_desc *r)
@@ -3411,6 +3426,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	{ SYS_DESC(SYS_ICC_AP1R1_EL1), undef_access },
 	{ SYS_DESC(SYS_ICC_AP1R2_EL1), undef_access },
 	{ SYS_DESC(SYS_ICC_AP1R3_EL1), undef_access },
+	{ SYS_DESC(SYS_ICC_IAFFIDR_EL1), access_gicv5_iaffid },
 	{ SYS_DESC(SYS_ICC_DIR_EL1), access_gic_dir },
 	{ SYS_DESC(SYS_ICC_RPR_EL1), undef_access },
 	{ SYS_DESC(SYS_ICC_SGI1R_EL1), access_gic_sgi },
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:39 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:39 +0000
Subject: [PATCH v2 11/36] KVM: arm64: gic-v5: Support GICv5 FGTs & FGUs
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-12-sascha.bischoff@arm.com>

Extend the existing FGT/FGU infrastructure to include the GICv5 trap
registers (ICH_HFGRTR_EL2, ICH_HFGWTR_EL2, ICH_HFGITR_EL2). This
involves mapping the trap registers and their bits to the
corresponding feature that introduces them (FEAT_GCIE for all, in this
case), and mapping each trap bit to the system register/instruction
controlled by it.

As of this change, none of the GICv5 instructions or register accesses
are being trapped.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/include/asm/kvm_host.h       | 19 +++++
 arch/arm64/include/asm/vncr_mapping.h   |  3 +
 arch/arm64/kvm/arm.c                    |  3 +
 arch/arm64/kvm/config.c                 | 94 ++++++++++++++++++++++++-
 arch/arm64/kvm/emulate-nested.c         | 68 ++++++++++++++++++
 arch/arm64/kvm/hyp/include/hyp/switch.h | 27 +++++++
 arch/arm64/kvm/hyp/nvhe/switch.c        |  3 +
 arch/arm64/kvm/sys_regs.c               |  2 +
 8 files changed, 218 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 971b153b0a3fa..f08c333d8b113 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -287,6 +287,9 @@ enum fgt_group_id {
 	HDFGRTR2_GROUP,
 	HDFGWTR2_GROUP = HDFGRTR2_GROUP,
 	HFGITR2_GROUP,
+	ICH_HFGRTR_GROUP,
+	ICH_HFGWTR_GROUP = ICH_HFGRTR_GROUP,
+	ICH_HFGITR_GROUP,
 
 	/* Must be last */
 	__NR_FGT_GROUP_IDS__
@@ -623,6 +626,10 @@ enum vcpu_sysreg {
 	VNCR(ICH_HCR_EL2),
 	VNCR(ICH_VMCR_EL2),
 
+	VNCR(ICH_HFGRTR_EL2),
+	VNCR(ICH_HFGWTR_EL2),
+	VNCR(ICH_HFGITR_EL2),
+
 	NR_SYS_REGS	/* Nothing after this line! */
 };
 
@@ -652,6 +659,9 @@ extern struct fgt_masks hfgwtr2_masks;
 extern struct fgt_masks hfgitr2_masks;
 extern struct fgt_masks hdfgrtr2_masks;
 extern struct fgt_masks hdfgwtr2_masks;
+extern struct fgt_masks ich_hfgrtr_masks;
+extern struct fgt_masks ich_hfgwtr_masks;
+extern struct fgt_masks ich_hfgitr_masks;
 
 extern struct fgt_masks kvm_nvhe_sym(hfgrtr_masks);
 extern struct fgt_masks kvm_nvhe_sym(hfgwtr_masks);
@@ -664,6 +674,9 @@ extern struct fgt_masks kvm_nvhe_sym(hfgwtr2_masks);
 extern struct fgt_masks kvm_nvhe_sym(hfgitr2_masks);
 extern struct fgt_masks kvm_nvhe_sym(hdfgrtr2_masks);
 extern struct fgt_masks kvm_nvhe_sym(hdfgwtr2_masks);
+extern struct fgt_masks kvm_nvhe_sym(ich_hfgrtr_masks);
+extern struct fgt_masks kvm_nvhe_sym(ich_hfgwtr_masks);
+extern struct fgt_masks kvm_nvhe_sym(ich_hfgitr_masks);
 
 struct kvm_cpu_context {
 	struct user_pt_regs regs;	/* sp = sp_el0 */
@@ -1637,6 +1650,11 @@ static __always_inline enum fgt_group_id __fgt_reg_to_group_id(enum vcpu_sysreg
 	case HDFGRTR2_EL2:
 	case HDFGWTR2_EL2:
 		return HDFGRTR2_GROUP;
+	case ICH_HFGRTR_EL2:
+	case ICH_HFGWTR_EL2:
+		return ICH_HFGRTR_GROUP;
+	case ICH_HFGITR_EL2:
+		return ICH_HFGITR_GROUP;
 	default:
 		BUILD_BUG_ON(1);
 	}
@@ -1651,6 +1669,7 @@ static __always_inline enum fgt_group_id __fgt_reg_to_group_id(enum vcpu_sysreg
 		case HDFGWTR_EL2:					\
 		case HFGWTR2_EL2:					\
 		case HDFGWTR2_EL2:					\
+		case ICH_HFGWTR_EL2:					\
 			p = &(vcpu)->arch.fgt[id].w;			\
 			break;						\
 		default:						\
diff --git a/arch/arm64/include/asm/vncr_mapping.h b/arch/arm64/include/asm/vncr_mapping.h
index c2485a862e690..14366d35ce82f 100644
--- a/arch/arm64/include/asm/vncr_mapping.h
+++ b/arch/arm64/include/asm/vncr_mapping.h
@@ -108,5 +108,8 @@
 #define VNCR_MPAMVPM5_EL2       0x968
 #define VNCR_MPAMVPM6_EL2       0x970
 #define VNCR_MPAMVPM7_EL2       0x978
+#define VNCR_ICH_HFGITR_EL2	0xB10
+#define VNCR_ICH_HFGRTR_EL2	0xB18
+#define VNCR_ICH_HFGWTR_EL2	0xB20
 
 #endif /* __ARM64_VNCR_MAPPING_H__ */
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 4f80da0c0d1de..b7cf9d86aabb7 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -2474,6 +2474,9 @@ static void kvm_hyp_init_symbols(void)
 	kvm_nvhe_sym(hfgitr2_masks) = hfgitr2_masks;
 	kvm_nvhe_sym(hdfgrtr2_masks)= hdfgrtr2_masks;
 	kvm_nvhe_sym(hdfgwtr2_masks)= hdfgwtr2_masks;
+	kvm_nvhe_sym(ich_hfgrtr_masks) = ich_hfgrtr_masks;
+	kvm_nvhe_sym(ich_hfgwtr_masks) = ich_hfgwtr_masks;
+	kvm_nvhe_sym(ich_hfgitr_masks) = ich_hfgitr_masks;
 
 	/*
 	 * Flush entire BSS since part of its data containing init symbols is read
diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index 3845b188551b6..5f57dc07cc482 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -219,6 +219,7 @@ struct reg_feat_map_desc {
 #define FEAT_FGT2		ID_AA64MMFR0_EL1, FGT, FGT2
 #define FEAT_MTPMU		ID_AA64DFR0_EL1, MTPMU, IMP
 #define FEAT_HCX		ID_AA64MMFR1_EL1, HCX, IMP
+#define FEAT_GCIE		ID_AA64PFR2_EL1, GCIE, IMP
 
 static bool not_feat_aa64el3(struct kvm *kvm)
 {
@@ -1168,6 +1169,58 @@ static const struct reg_bits_to_feat_map mdcr_el2_feat_map[] = {
 static const DECLARE_FEAT_MAP(mdcr_el2_desc, MDCR_EL2,
 			      mdcr_el2_feat_map, FEAT_AA64EL2);
 
+static const struct reg_bits_to_feat_map ich_hfgrtr_feat_map[] = {
+	NEEDS_FEAT(ICH_HFGRTR_EL2_ICC_APR_EL1 |
+		   ICH_HFGRTR_EL2_ICC_IDRn_EL1 |
+		   ICH_HFGRTR_EL2_ICC_CR0_EL1 |
+		   ICH_HFGRTR_EL2_ICC_HPPIR_EL1 |
+		   ICH_HFGRTR_EL2_ICC_PCR_EL1 |
+		   ICH_HFGRTR_EL2_ICC_ICSR_EL1 |
+		   ICH_HFGRTR_EL2_ICC_IAFFIDR_EL1 |
+		   ICH_HFGRTR_EL2_ICC_PPI_HMRn_EL1 |
+		   ICH_HFGRTR_EL2_ICC_PPI_ENABLERn_EL1 |
+		   ICH_HFGRTR_EL2_ICC_PPI_PENDRn_EL1 |
+		   ICH_HFGRTR_EL2_ICC_PPI_PRIORITYRn_EL1 |
+		   ICH_HFGRTR_EL2_ICC_PPI_ACTIVERn_EL1,
+		   FEAT_GCIE),
+};
+
+static const DECLARE_FEAT_MAP_FGT(ich_hfgrtr_desc, ich_hfgrtr_masks,
+				  ich_hfgrtr_feat_map, FEAT_GCIE);
+
+static const struct reg_bits_to_feat_map ich_hfgwtr_feat_map[] = {
+	NEEDS_FEAT(ICH_HFGWTR_EL2_ICC_APR_EL1 |
+		   ICH_HFGWTR_EL2_ICC_CR0_EL1 |
+		   ICH_HFGWTR_EL2_ICC_PCR_EL1 |
+		   ICH_HFGWTR_EL2_ICC_ICSR_EL1 |
+		   ICH_HFGWTR_EL2_ICC_PPI_ENABLERn_EL1 |
+		   ICH_HFGWTR_EL2_ICC_PPI_PENDRn_EL1 |
+		   ICH_HFGWTR_EL2_ICC_PPI_PRIORITYRn_EL1 |
+		   ICH_HFGWTR_EL2_ICC_PPI_ACTIVERn_EL1,
+		   FEAT_GCIE),
+};
+
+static const DECLARE_FEAT_MAP_FGT(ich_hfgwtr_desc, ich_hfgwtr_masks,
+				  ich_hfgwtr_feat_map, FEAT_GCIE);
+
+static const struct reg_bits_to_feat_map ich_hfgitr_feat_map[] = {
+	NEEDS_FEAT(ICH_HFGITR_EL2_GICCDEN |
+		   ICH_HFGITR_EL2_GICCDDIS |
+		   ICH_HFGITR_EL2_GICCDPRI |
+		   ICH_HFGITR_EL2_GICCDAFF |
+		   ICH_HFGITR_EL2_GICCDPEND |
+		   ICH_HFGITR_EL2_GICCDRCFG |
+		   ICH_HFGITR_EL2_GICCDHM |
+		   ICH_HFGITR_EL2_GICCDEOI |
+		   ICH_HFGITR_EL2_GICCDDI |
+		   ICH_HFGITR_EL2_GICRCDIA |
+		   ICH_HFGITR_EL2_GICRCDNMIA,
+		   FEAT_GCIE),
+};
+
+static const DECLARE_FEAT_MAP_FGT(ich_hfgitr_desc, ich_hfgitr_masks,
+				  ich_hfgitr_feat_map, FEAT_GCIE);
+
 static void __init check_feat_map(const struct reg_bits_to_feat_map *map,
 				  int map_size, u64 resx, const char *str)
 {
@@ -1211,6 +1264,9 @@ void __init check_feature_map(void)
 	check_reg_desc(&tcr2_el2_desc);
 	check_reg_desc(&sctlr_el1_desc);
 	check_reg_desc(&mdcr_el2_desc);
+	check_reg_desc(&ich_hfgrtr_desc);
+	check_reg_desc(&ich_hfgwtr_desc);
+	check_reg_desc(&ich_hfgitr_desc);
 }
 
 static bool idreg_feat_match(struct kvm *kvm, const struct reg_bits_to_feat_map *map)
@@ -1342,6 +1398,16 @@ void compute_fgu(struct kvm *kvm, enum fgt_group_id fgt)
 		val |= compute_reg_res0_bits(kvm, &hdfgwtr2_desc,
 					     0, NEVER_FGU);
 		break;
+	case ICH_HFGRTR_GROUP:
+		val |= compute_reg_res0_bits(kvm, &ich_hfgrtr_desc,
+					     0, NEVER_FGU);
+		val |= compute_reg_res0_bits(kvm, &ich_hfgwtr_desc,
+					     0, NEVER_FGU);
+		break;
+	case ICH_HFGITR_GROUP:
+		val |= compute_reg_res0_bits(kvm, &ich_hfgitr_desc,
+					     0, NEVER_FGU);
+		break;
 	default:
 		BUG();
 	}
@@ -1425,6 +1491,18 @@ void get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg, u64 *res0, u64 *r
 		*res0 = compute_reg_res0_bits(kvm, &mdcr_el2_desc, 0, 0);
 		*res1 = MDCR_EL2_RES1;
 		break;
+	case ICH_HFGRTR_EL2:
+		*res0 = compute_reg_res0_bits(kvm, &ich_hfgrtr_desc, 0, 0);
+		*res1 = ICH_HFGRTR_EL2_RES1;
+		break;
+	case ICH_HFGWTR_EL2:
+		*res0 = compute_reg_res0_bits(kvm, &ich_hfgwtr_desc, 0, 0);
+		*res1 = ICH_HFGWTR_EL2_RES1;
+		break;
+	case ICH_HFGITR_EL2:
+		*res0 = compute_reg_res0_bits(kvm, &ich_hfgitr_desc, 0, 0);
+		*res1 = ICH_HFGITR_EL2_RES1;
+		break;
 	default:
 		WARN_ON_ONCE(1);
 		*res0 = *res1 = 0;
@@ -1457,6 +1535,12 @@ static __always_inline struct fgt_masks *__fgt_reg_to_masks(enum vcpu_sysreg reg
 		return &hdfgrtr2_masks;
 	case HDFGWTR2_EL2:
 		return &hdfgwtr2_masks;
+	case ICH_HFGRTR_EL2:
+		return &ich_hfgrtr_masks;
+	case ICH_HFGWTR_EL2:
+		return &ich_hfgwtr_masks;
+	case ICH_HFGITR_EL2:
+		return &ich_hfgitr_masks;
 	default:
 		BUILD_BUG_ON(1);
 	}
@@ -1511,11 +1595,19 @@ void kvm_vcpu_load_fgt(struct kvm_vcpu *vcpu)
 	__compute_fgt(vcpu, HAFGRTR_EL2);
 
 	if (!cpus_have_final_cap(ARM64_HAS_FGT2))
-		return;
+		goto skip_fgt2;
 
 	__compute_fgt(vcpu, HFGRTR2_EL2);
 	__compute_fgt(vcpu, HFGWTR2_EL2);
 	__compute_fgt(vcpu, HFGITR2_EL2);
 	__compute_fgt(vcpu, HDFGRTR2_EL2);
 	__compute_fgt(vcpu, HDFGWTR2_EL2);
+
+skip_fgt2:
+	if (!cpus_have_final_cap(ARM64_HAS_GICV5_CPUIF))
+		return;
+
+	__compute_fgt(vcpu, ICH_HFGRTR_EL2);
+	__compute_fgt(vcpu, ICH_HFGWTR_EL2);
+	__compute_fgt(vcpu, ICH_HFGITR_EL2);
 }
diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c
index 75d49f83342a5..de316bdf90d46 100644
--- a/arch/arm64/kvm/emulate-nested.c
+++ b/arch/arm64/kvm/emulate-nested.c
@@ -2044,6 +2044,60 @@ static const struct encoding_to_trap_config encoding_to_fgt[] __initconst = {
 	SR_FGT(SYS_AMEVCNTR0_EL0(2),	HAFGRTR, AMEVCNTR02_EL0, 1),
 	SR_FGT(SYS_AMEVCNTR0_EL0(1),	HAFGRTR, AMEVCNTR01_EL0, 1),
 	SR_FGT(SYS_AMEVCNTR0_EL0(0),	HAFGRTR, AMEVCNTR00_EL0, 1),
+
+	/*
+	 * ICH_HFGRTR_EL2 & ICH_HFGWTR_EL2
+	 */
+	SR_FGT(SYS_ICC_APR_EL1,			ICH_HFGRTR, ICC_APR_EL1, 0),
+	SR_FGT(SYS_ICC_IDR0_EL1,		ICH_HFGRTR, ICC_IDRn_EL1, 0),
+	SR_FGT(SYS_ICC_CR0_EL1,			ICH_HFGRTR, ICC_CR0_EL1, 0),
+	SR_FGT(SYS_ICC_HPPIR_EL1,		ICH_HFGRTR, ICC_HPPIR_EL1, 0),
+	SR_FGT(SYS_ICC_PCR_EL1,			ICH_HFGRTR, ICC_PCR_EL1, 0),
+	SR_FGT(SYS_ICC_ICSR_EL1,		ICH_HFGRTR, ICC_ICSR_EL1, 0),
+	SR_FGT(SYS_ICC_IAFFIDR_EL1,		ICH_HFGRTR, ICC_IAFFIDR_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_HMR0_EL1,		ICH_HFGRTR, ICC_PPI_HMRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_HMR1_EL1,		ICH_HFGRTR, ICC_PPI_HMRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_ENABLER0_EL1,	ICH_HFGRTR, ICC_PPI_ENABLERn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_ENABLER1_EL1,	ICH_HFGRTR, ICC_PPI_ENABLERn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_CPENDR0_EL1,		ICH_HFGRTR, ICC_PPI_PENDRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_CPENDR1_EL1,		ICH_HFGRTR, ICC_PPI_PENDRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_SPENDR0_EL1,		ICH_HFGRTR, ICC_PPI_PENDRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_SPENDR1_EL1,		ICH_HFGRTR, ICC_PPI_PENDRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR0_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR1_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR2_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR3_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR4_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR5_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR6_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR7_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR8_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR9_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR10_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR11_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR12_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR13_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR14_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_PRIORITYR15_EL1,	ICH_HFGRTR, ICC_PPI_PRIORITYRn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_CACTIVER0_EL1,	ICH_HFGRTR, ICC_PPI_ACTIVERn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_CACTIVER1_EL1,	ICH_HFGRTR, ICC_PPI_ACTIVERn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_SACTIVER0_EL1,	ICH_HFGRTR, ICC_PPI_ACTIVERn_EL1, 0),
+	SR_FGT(SYS_ICC_PPI_SACTIVER1_EL1,	ICH_HFGRTR, ICC_PPI_ACTIVERn_EL1, 0),
+
+	/*
+	 * ICH_HFGITR_EL2
+	 */
+	SR_FGT(GICV5_OP_GIC_CDEN,	ICH_HFGITR, GICCDEN, 0),
+	SR_FGT(GICV5_OP_GIC_CDDIS,	ICH_HFGITR, GICCDDIS, 0),
+	SR_FGT(GICV5_OP_GIC_CDPRI,	ICH_HFGITR, GICCDPRI, 0),
+	SR_FGT(GICV5_OP_GIC_CDAFF,	ICH_HFGITR, GICCDAFF, 0),
+	SR_FGT(GICV5_OP_GIC_CDPEND,	ICH_HFGITR, GICCDPEND, 0),
+	SR_FGT(GICV5_OP_GIC_CDRCFG,	ICH_HFGITR, GICCDRCFG, 0),
+	SR_FGT(GICV5_OP_GIC_CDHM,	ICH_HFGITR, GICCDHM, 0),
+	SR_FGT(GICV5_OP_GIC_CDEOI,	ICH_HFGITR, GICCDEOI, 0),
+	SR_FGT(GICV5_OP_GIC_CDDI,	ICH_HFGITR, GICCDDI, 0),
+	SR_FGT(GICV5_OP_GICR_CDIA,	ICH_HFGITR, GICRCDIA, 0),
+	SR_FGT(GICV5_OP_GICR_CDNMIA,	ICH_HFGITR, GICRCDNMIA, 0),
 };
 
 /*
@@ -2118,6 +2172,9 @@ FGT_MASKS(hfgwtr2_masks, HFGWTR2_EL2);
 FGT_MASKS(hfgitr2_masks, HFGITR2_EL2);
 FGT_MASKS(hdfgrtr2_masks, HDFGRTR2_EL2);
 FGT_MASKS(hdfgwtr2_masks, HDFGWTR2_EL2);
+FGT_MASKS(ich_hfgrtr_masks, ICH_HFGRTR_EL2);
+FGT_MASKS(ich_hfgwtr_masks, ICH_HFGWTR_EL2);
+FGT_MASKS(ich_hfgitr_masks, ICH_HFGITR_EL2);
 
 static __init bool aggregate_fgt(union trap_config tc)
 {
@@ -2153,6 +2210,14 @@ static __init bool aggregate_fgt(union trap_config tc)
 		rmasks = &hfgitr2_masks;
 		wmasks = NULL;
 		break;
+	case ICH_HFGRTR_GROUP:
+		rmasks = &ich_hfgrtr_masks;
+		wmasks = &ich_hfgwtr_masks;
+		break;
+	case ICH_HFGITR_GROUP:
+		rmasks = &ich_hfgitr_masks;
+		wmasks = NULL;
+		break;
 	}
 
 	rresx = rmasks->res0 | rmasks->res1;
@@ -2223,6 +2288,9 @@ static __init int check_all_fgt_masks(int ret)
 		&hfgitr2_masks,
 		&hdfgrtr2_masks,
 		&hdfgwtr2_masks,
+		&ich_hfgrtr_masks,
+		&ich_hfgwtr_masks,
+		&ich_hfgitr_masks,
 	};
 	int err = 0;
 
diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index c5d5e5b86eaf0..14805336725f5 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -235,6 +235,18 @@ static inline void __activate_traps_hfgxtr(struct kvm_vcpu *vcpu)
 	__activate_fgt(hctxt, vcpu, HDFGWTR2_EL2);
 }
 
+static inline void __activate_traps_ich_hfgxtr(struct kvm_vcpu *vcpu)
+{
+	struct kvm_cpu_context *hctxt = host_data_ptr(host_ctxt);
+
+	if (!cpus_have_final_cap(ARM64_HAS_GICV5_CPUIF))
+		return;
+
+	__activate_fgt(hctxt, vcpu, ICH_HFGRTR_EL2);
+	__activate_fgt(hctxt, vcpu, ICH_HFGWTR_EL2);
+	__activate_fgt(hctxt, vcpu, ICH_HFGITR_EL2);
+}
+
 #define __deactivate_fgt(htcxt, vcpu, reg)				\
 	do {								\
 		write_sysreg_s(ctxt_sys_reg(hctxt, reg),		\
@@ -267,6 +279,19 @@ static inline void __deactivate_traps_hfgxtr(struct kvm_vcpu *vcpu)
 	__deactivate_fgt(hctxt, vcpu, HDFGWTR2_EL2);
 }
 
+static inline void __deactivate_traps_ich_hfgxtr(struct kvm_vcpu *vcpu)
+{
+	struct kvm_cpu_context *hctxt = host_data_ptr(host_ctxt);
+
+	if (!cpus_have_final_cap(ARM64_HAS_GICV5_CPUIF))
+		return;
+
+	__deactivate_fgt(hctxt, vcpu, ICH_HFGRTR_EL2);
+	__deactivate_fgt(hctxt, vcpu, ICH_HFGWTR_EL2);
+	__deactivate_fgt(hctxt, vcpu, ICH_HFGITR_EL2);
+
+}
+
 static inline void  __activate_traps_mpam(struct kvm_vcpu *vcpu)
 {
 	u64 r = MPAM2_EL2_TRAPMPAM0EL1 | MPAM2_EL2_TRAPMPAM1EL1;
@@ -330,6 +355,7 @@ static inline void __activate_traps_common(struct kvm_vcpu *vcpu)
 	}
 
 	__activate_traps_hfgxtr(vcpu);
+	__activate_traps_ich_hfgxtr(vcpu);
 	__activate_traps_mpam(vcpu);
 }
 
@@ -347,6 +373,7 @@ static inline void __deactivate_traps_common(struct kvm_vcpu *vcpu)
 		write_sysreg_s(ctxt_sys_reg(hctxt, HCRX_EL2), SYS_HCRX_EL2);
 
 	__deactivate_traps_hfgxtr(vcpu);
+	__deactivate_traps_ich_hfgxtr(vcpu);
 	__deactivate_traps_mpam();
 }
 
diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c
index d3b9ec8a7c283..c23e22ffac080 100644
--- a/arch/arm64/kvm/hyp/nvhe/switch.c
+++ b/arch/arm64/kvm/hyp/nvhe/switch.c
@@ -44,6 +44,9 @@ struct fgt_masks hfgwtr2_masks;
 struct fgt_masks hfgitr2_masks;
 struct fgt_masks hdfgrtr2_masks;
 struct fgt_masks hdfgwtr2_masks;
+struct fgt_masks ich_hfgrtr_masks;
+struct fgt_masks ich_hfgwtr_masks;
+struct fgt_masks ich_hfgitr_masks;
 
 extern void kvm_nvhe_prepare_backtrace(unsigned long fp, unsigned long pc);
 
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index a065f8939bc8f..fbbd7b6ff6507 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -5630,6 +5630,8 @@ void kvm_calculate_traps(struct kvm_vcpu *vcpu)
 	compute_fgu(kvm, HFGRTR2_GROUP);
 	compute_fgu(kvm, HFGITR2_GROUP);
 	compute_fgu(kvm, HDFGRTR2_GROUP);
+	compute_fgu(kvm, ICH_HFGRTR_GROUP);
+	compute_fgu(kvm, ICH_HFGITR_GROUP);
 
 	set_bit(KVM_ARCH_FLAG_FGU_INITIALIZED, &kvm->arch.flags);
 out:
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:40 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:40 +0000
Subject: [PATCH v2 13/36] KVM: arm64: gic: Set vgic_model before initing
 private IRQs
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-14-sascha.bischoff@arm.com>

Different GIC types require the private IRQs to be initialised
differently. GICv5 is the culprit as it supports both a different
number of private IRQs, and all of these are PPIs (there are no
SGIs). Moreover, as GICv5 uses the top bits of the interrupt ID to
encode the type, the intid also needs to computed differently.

Up until now, the GIC model has been set after initialising the
private IRQs for a VCPU. Move this earlier to ensure that the GIC
model is available when configuring the private IRQs.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/vgic/vgic-init.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index c602f24bab1bb..bcc2c79f7833c 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -140,6 +140,12 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
 		goto out_unlock;
 	}
 
+	kvm->arch.vgic.in_kernel = true;
+	kvm->arch.vgic.vgic_model = type;
+	kvm->arch.vgic.implementation_rev = KVM_VGIC_IMP_REV_LATEST;
+
+	kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
+
 	kvm_for_each_vcpu(i, vcpu, kvm) {
 		ret = vgic_allocate_private_irqs_locked(vcpu, type);
 		if (ret)
@@ -156,12 +162,6 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
 		goto out_unlock;
 	}
 
-	kvm->arch.vgic.in_kernel = true;
-	kvm->arch.vgic.vgic_model = type;
-	kvm->arch.vgic.implementation_rev = KVM_VGIC_IMP_REV_LATEST;
-
-	kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
-
 	aa64pfr0 = kvm_read_vm_id_reg(kvm, SYS_ID_AA64PFR0_EL1) & ~ID_AA64PFR0_EL1_GIC;
 	pfr1 = kvm_read_vm_id_reg(kvm, SYS_ID_PFR1_EL1) & ~ID_PFR1_EL1_GIC;
 
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:41 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:41 +0000
Subject: [PATCH v2 17/36] KVM: arm64: gic: Introduce irq_queue and
 set_pending_state to irq_ops
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-18-sascha.bischoff@arm.com>

There are times when the default behaviour of vgic_queue_irq_unlock is
undesirable. This is because some GICs, such a GICv5 which is the main
driver for this change, handle the majority of the interrupt lifecycle
in hardware. In this case, there is no need for a per-VCPU AP list as
the interrupt can be made pending directly. This is done either via
the ICH_PPI_x_EL2 registers for PPIs, or with the VDPEND system
instruction for SPIs and LPIs.

The queue_irq_unlock function is made overridable using a new function
pointer in struct irq_ops. In kvm_vgic_inject_irq,
vgic_queue_irq_unlock is overridden if the function pointer is
non-null.

Additionally, a new function is added via a function pointer -
set_pending_state. The intent is for this to be used to directly set
the pending state in hardware.

Both of these new irq_ops are unused in this change - it is purely
providing the infrastructure itself. The subsequent PPI injection
changes provide a demonstration of their usage.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/vgic/vgic.c | 11 +++++++++++
 include/kvm/arm_vgic.h     | 15 +++++++++++++++
 2 files changed, 26 insertions(+)

diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index d88570bb2f9f0..ac8cb0270e1e4 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -404,6 +404,13 @@ bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq,
 
 	lockdep_assert_held(&irq->irq_lock);
 
+	/*
+	 * If we have the queue_irq_unlock irq_op, we want to override
+	 * the default behaviour. Call that, and return early.
+	 */
+	if (irq->ops && irq->ops->queue_irq_unlock)
+		return irq->ops->queue_irq_unlock(kvm, irq, flags);
+
 retry:
 	vcpu = vgic_target_oracle(irq);
 	if (irq->vcpu || !vcpu) {
@@ -547,7 +554,11 @@ int kvm_vgic_inject_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 	else
 		irq->pending_latch = true;
 
+	if (irq->ops && irq->ops->set_pending_state)
+		WARN_ON_ONCE(!irq->ops->set_pending_state(vcpu, irq));
+
 	vgic_queue_irq_unlock(kvm, irq, flags);
+
 	vgic_put_irq(kvm, irq);
 
 	return 0;
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 17cd0295b135f..500709bd62c8d 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -171,6 +171,8 @@ enum vgic_irq_config {
 	VGIC_CONFIG_LEVEL
 };
 
+struct vgic_irq;
+
 /*
  * Per-irq ops overriding some common behavious.
  *
@@ -189,6 +191,19 @@ struct irq_ops {
 	 * peaking into the physical GIC.
 	 */
 	bool (*get_input_level)(int vintid);
+
+	/*
+	 * Function pointer to directly set the pending state for interrupts
+	 * that don't need to be enqueued on AP lists (for example, GICv5 PPIs).
+	 */
+	bool (*set_pending_state)(struct kvm_vcpu *vcpu, struct vgic_irq *irq);
+
+	/*
+	 * Function pointer to override the queuing of an IRQ.
+	 */
+	bool (*queue_irq_unlock)(struct kvm *kvm, struct vgic_irq *irq,
+				unsigned long flags) __releases(&irq->irq_lock);
+
 };
 
 struct vgic_irq {
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:41 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:41 +0000
Subject: [PATCH v2 16/36] KVM: arm64: gic-v5: Implement direct injection of
 PPIs
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-17-sascha.bischoff@arm.com>

GICv5 is able to directly inject PPI pending state into a guest using
a mechanism called DVI whereby the pending bit for a paticular PPI is
driven directly by the physically-connected hardware. This mechanism
itself doesn't allow for any ID translation, so the host interrupt is
directly mapped into a guest with the same interrupt ID.

When mapping a virtual interrupt to a physical interrupt via
kvm_vgic_map_irq for a GICv5 guest, check if the interrupt itself is a
PPI or not. If it is, and the host's interrupt ID matches that used
for the guest DVI is enabled, and the interrupt itself is marked as
directly_injected.

When the interrupt is unmapped again, this process is reversed, and
DVI is disabled for the interrupt again.

Note: the expectation is that a directly injected PPI is disabled on
the host while the guest state is loaded. The reason is that although
DVI is enabled to drive the guest's pending state directly, the host
pending state also remains driven. In order to avoid the same PPI
firing on both the host and the guest, the host's interrupt must be
disabled (masked). This is left up to the code that owns the device
generating the PPI as this needs to be handled on a per-VM basis. One
VM might use DVI, while another might not, in which case the physical
PPI should be enabled for the latter.

Co-authored-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/vgic/vgic-v5.c | 22 ++++++++++++++++++++++
 arch/arm64/kvm/vgic/vgic.c    | 13 +++++++++++++
 arch/arm64/kvm/vgic/vgic.h    |  1 +
 include/kvm/arm_vgic.h        |  1 +
 4 files changed, 37 insertions(+)

diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index 168447ee3fbed..46c70dfc7bb08 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -83,6 +83,28 @@ void vgic_v5_get_implemented_ppis(void)
 	}
 }
 
+/*
+ * Sets/clears the corresponding bit in the ICH_PPI_DVIR register.
+ */
+int vgic_v5_set_ppi_dvi(struct kvm_vcpu *vcpu, u32 irq, bool dvi)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+	u32 ppi = FIELD_GET(GICV5_HWIRQ_ID, irq);
+
+	if (ppi >= 128)
+		return -EINVAL;
+
+	if (dvi) {
+		/* Set the bit */
+		cpu_if->vgic_ppi_dvir[ppi / 64] |= 1UL << (ppi % 64);
+	} else {
+		/* Clear the bit */
+		cpu_if->vgic_ppi_dvir[ppi / 64] &= ~(1UL << (ppi % 64));
+	}
+
+	return 0;
+}
+
 void vgic_v5_load(struct kvm_vcpu *vcpu)
 {
 	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index 1005ff5f36235..d88570bb2f9f0 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -577,12 +577,25 @@ static int kvm_vgic_map_irq(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
 	irq->host_irq = host_irq;
 	irq->hwintid = data->hwirq;
 	irq->ops = ops;
+
+	if (!vgic_is_v5(vcpu->kvm) ||
+	    !__irq_is_ppi(KVM_DEV_TYPE_ARM_VGIC_V5, irq->intid))
+		return 0;
+
+	if (FIELD_GET(GICV5_HWIRQ_ID, irq->intid) == irq->hwintid)
+		irq->directly_injected = !vgic_v5_set_ppi_dvi(vcpu, irq->hwintid,
+							      true);
+
 	return 0;
 }
 
 /* @irq->irq_lock must be held */
 static inline void kvm_vgic_unmap_irq(struct vgic_irq *irq)
 {
+	if (irq->directly_injected && vgic_is_v5(irq->target_vcpu->kvm))
+		WARN_ON(vgic_v5_set_ppi_dvi(irq->target_vcpu, irq->hwintid, false));
+
+	irq->directly_injected = false;
 	irq->hw = false;
 	irq->hwintid = 0;
 	irq->ops = NULL;
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index 9905317c9d49d..d5d9264f0a1e9 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -364,6 +364,7 @@ void vgic_debug_destroy(struct kvm *kvm);
 
 int vgic_v5_probe(const struct gic_kvm_info *info);
 void vgic_v5_get_implemented_ppis(void);
+int vgic_v5_set_ppi_dvi(struct kvm_vcpu *vcpu, u32 irq, bool dvi);
 void vgic_v5_load(struct kvm_vcpu *vcpu);
 void vgic_v5_put(struct kvm_vcpu *vcpu);
 void vgic_v5_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index b9d96a8ea53fd..17cd0295b135f 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -219,6 +219,7 @@ struct vgic_irq {
 	bool enabled:1;
 	bool active:1;
 	bool hw:1;			/* Tied to HW IRQ */
+	bool directly_injected:1;	/* A directly injected HW IRQ */
 	bool on_lr:1;			/* Present in a CPU LR */
 	refcount_t refcount;		/* Used for LPIs */
 	u32 hwintid;			/* HW INTID number */
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:41 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:41 +0000
Subject: [PATCH v2 15/36] KVM: arm64: gic-v5: Implement GICv5 load/put and
 save/restore
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-16-sascha.bischoff@arm.com>

This change introduces GICv5 load/put. Additionally, it plumbs in
save/restore for:

* PPIs (ICH_PPI_x_EL2 regs)
* ICH_VMCR_EL2
* ICH_APR_EL2
* ICC_ICSR_EL1

A GICv5-specific enable bit is added to struct vgic_vmcr as this
differs from previous GICs. On GICv5-native systems, the VMCR only
contains the enable bit (driven by the guest via ICC_CR0_EL1.EN) and
the priority mask (PCR).

A struct gicv5_vpe is also introduced. This currently only contains a
single field - bool resident - which is used to track if a VPE is
currently running or not, and is used to avoid a case of double load
or double put on the WFI path for a vCPU. This struct will be extended
as additional GICv5 support is merged, specifically for VPE doorbells.

Co-authored-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/hyp/nvhe/switch.c   | 12 +++++
 arch/arm64/kvm/vgic/vgic-mmio.c    | 28 +++++++----
 arch/arm64/kvm/vgic/vgic-v5.c      | 77 ++++++++++++++++++++++++++++++
 arch/arm64/kvm/vgic/vgic.c         | 32 ++++++++-----
 arch/arm64/kvm/vgic/vgic.h         |  7 +++
 include/kvm/arm_vgic.h             |  2 +
 include/linux/irqchip/arm-gic-v5.h |  5 ++
 7 files changed, 144 insertions(+), 19 deletions(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c
index c23e22ffac080..bc446a5d94d68 100644
--- a/arch/arm64/kvm/hyp/nvhe/switch.c
+++ b/arch/arm64/kvm/hyp/nvhe/switch.c
@@ -113,6 +113,12 @@ static void __deactivate_traps(struct kvm_vcpu *vcpu)
 /* Save VGICv3 state on non-VHE systems */
 static void __hyp_vgic_save_state(struct kvm_vcpu *vcpu)
 {
+	if (kern_hyp_va(vcpu->kvm)->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5) {
+		__vgic_v5_save_state(&vcpu->arch.vgic_cpu.vgic_v5);
+		__vgic_v5_save_ppi_state(&vcpu->arch.vgic_cpu.vgic_v5);
+		return;
+	}
+
 	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif)) {
 		__vgic_v3_save_state(&vcpu->arch.vgic_cpu.vgic_v3);
 		__vgic_v3_deactivate_traps(&vcpu->arch.vgic_cpu.vgic_v3);
@@ -122,6 +128,12 @@ static void __hyp_vgic_save_state(struct kvm_vcpu *vcpu)
 /* Restore VGICv3 state on non-VHE systems */
 static void __hyp_vgic_restore_state(struct kvm_vcpu *vcpu)
 {
+	if (kern_hyp_va(vcpu->kvm)->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5) {
+		__vgic_v5_restore_state(&vcpu->arch.vgic_cpu.vgic_v5);
+		__vgic_v5_restore_ppi_state(&vcpu->arch.vgic_cpu.vgic_v5);
+		return;
+	}
+
 	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif)) {
 		__vgic_v3_activate_traps(&vcpu->arch.vgic_cpu.vgic_v3);
 		__vgic_v3_restore_state(&vcpu->arch.vgic_cpu.vgic_v3);
diff --git a/arch/arm64/kvm/vgic/vgic-mmio.c b/arch/arm64/kvm/vgic/vgic-mmio.c
index a573b1f0c6cbe..675c2844f5e5c 100644
--- a/arch/arm64/kvm/vgic/vgic-mmio.c
+++ b/arch/arm64/kvm/vgic/vgic-mmio.c
@@ -842,18 +842,30 @@ vgic_find_mmio_region(const struct vgic_register_region *regions,
 
 void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
 {
-	if (kvm_vgic_global_state.type == VGIC_V2)
-		vgic_v2_set_vmcr(vcpu, vmcr);
-	else
-		vgic_v3_set_vmcr(vcpu, vmcr);
+	const struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+
+	if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5) {
+		vgic_v5_set_vmcr(vcpu, vmcr);
+	} else {
+		if (kvm_vgic_global_state.type == VGIC_V2)
+			vgic_v2_set_vmcr(vcpu, vmcr);
+		else
+			vgic_v3_set_vmcr(vcpu, vmcr);
+	}
 }
 
 void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
 {
-	if (kvm_vgic_global_state.type == VGIC_V2)
-		vgic_v2_get_vmcr(vcpu, vmcr);
-	else
-		vgic_v3_get_vmcr(vcpu, vmcr);
+	const struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+
+	if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5) {
+		vgic_v5_get_vmcr(vcpu, vmcr);
+	} else {
+		if (kvm_vgic_global_state.type == VGIC_V2)
+			vgic_v2_get_vmcr(vcpu, vmcr);
+		else
+			vgic_v3_get_vmcr(vcpu, vmcr);
+	}
 }
 
 /*
diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index 1fe1790f1f874..168447ee3fbed 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -1,4 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2025 Arm Ltd.
+ */
 
 #include <kvm/arm_vgic.h>
 #include <linux/irqchip/arm-vgic-info.h>
@@ -79,3 +82,77 @@ void vgic_v5_get_implemented_ppis(void)
 		__vgic_v5_detect_ppis(ppi_caps->impl_ppi_mask);
 	}
 }
+
+void vgic_v5_load(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+
+	/*
+	 * On the WFI path, vgic_load is called a second time. The first is when
+	 * scheduling in the vcpu thread again, and the second is when leaving
+	 * WFI. Skip the second instance as it serves no purpose and just
+	 * restores the same state again.
+	 */
+	if (READ_ONCE(cpu_if->gicv5_vpe.resident))
+		return;
+
+	kvm_call_hyp(__vgic_v5_restore_vmcr_apr, cpu_if);
+
+	WRITE_ONCE(cpu_if->gicv5_vpe.resident, true);
+}
+
+void vgic_v5_put(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+
+	/*
+	 * Do nothing if we're not resident. This can happen in the WFI path
+	 * where we do a vgic_put in the WFI path and again later when
+	 * descheduling the thread. We risk losing VMCR state if we sync it
+	 * twice, so instead return early in this case.
+	 */
+	if (!READ_ONCE(cpu_if->gicv5_vpe.resident))
+		return;
+
+	kvm_call_hyp(__vgic_v5_save_apr, cpu_if);
+
+	WRITE_ONCE(cpu_if->gicv5_vpe.resident, false);
+}
+
+void vgic_v5_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+	u64 vmcr = cpu_if->vgic_vmcr;
+
+	vmcrp->en = FIELD_GET(FEAT_GCIE_ICH_VMCR_EL2_EN, vmcr);
+	vmcrp->pmr = FIELD_GET(FEAT_GCIE_ICH_VMCR_EL2_VPMR, vmcr);
+}
+
+void vgic_v5_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+	u64 vmcr;
+
+	vmcr = FIELD_PREP(FEAT_GCIE_ICH_VMCR_EL2_VPMR, vmcrp->pmr) |
+	       FIELD_PREP(FEAT_GCIE_ICH_VMCR_EL2_EN, vmcrp->en);
+
+	cpu_if->vgic_vmcr = vmcr;
+}
+
+void vgic_v5_restore_state(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+
+	__vgic_v5_restore_state(cpu_if);
+	kvm_call_hyp(__vgic_v5_restore_ppi_state, cpu_if);
+	dsb(sy);
+}
+
+void vgic_v5_save_state(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+
+	__vgic_v5_save_state(cpu_if);
+	kvm_call_hyp(__vgic_v5_save_ppi_state, cpu_if);
+	dsb(sy);
+}
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index 2c0e8803342e2..1005ff5f36235 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -996,7 +996,9 @@ static inline bool can_access_vgic_from_kernel(void)
 
 static inline void vgic_save_state(struct kvm_vcpu *vcpu)
 {
-	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
+	if (vgic_is_v5(vcpu->kvm))
+		vgic_v5_save_state(vcpu);
+	else if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		vgic_v2_save_state(vcpu);
 	else
 		__vgic_v3_save_state(&vcpu->arch.vgic_cpu.vgic_v3);
@@ -1005,14 +1007,16 @@ static inline void vgic_save_state(struct kvm_vcpu *vcpu)
 /* Sync back the hardware VGIC state into our emulation after a guest's run. */
 void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 {
-	/* If nesting, emulate the HW effect from L0 to L1 */
-	if (vgic_state_is_nested(vcpu)) {
-		vgic_v3_sync_nested(vcpu);
-		return;
-	}
+	if (!vgic_is_v5(vcpu->kvm)) {
+		/* If nesting, emulate the HW effect from L0 to L1 */
+		if (vgic_state_is_nested(vcpu)) {
+			vgic_v3_sync_nested(vcpu);
+			return;
+		}
 
-	if (vcpu_has_nv(vcpu))
-		vgic_v3_nested_update_mi(vcpu);
+		if (vcpu_has_nv(vcpu))
+			vgic_v3_nested_update_mi(vcpu);
+	}
 
 	if (can_access_vgic_from_kernel())
 		vgic_save_state(vcpu);
@@ -1034,7 +1038,9 @@ void kvm_vgic_process_async_update(struct kvm_vcpu *vcpu)
 
 static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
 {
-	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
+	if (vgic_is_v5(vcpu->kvm))
+		vgic_v5_restore_state(vcpu);
+	else if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		vgic_v2_restore_state(vcpu);
 	else
 		__vgic_v3_restore_state(&vcpu->arch.vgic_cpu.vgic_v3);
@@ -1094,7 +1100,9 @@ void kvm_vgic_load(struct kvm_vcpu *vcpu)
 		return;
 	}
 
-	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
+	if (vgic_is_v5(vcpu->kvm))
+		vgic_v5_load(vcpu);
+	else if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		vgic_v2_load(vcpu);
 	else
 		vgic_v3_load(vcpu);
@@ -1108,7 +1116,9 @@ void kvm_vgic_put(struct kvm_vcpu *vcpu)
 		return;
 	}
 
-	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
+	if (vgic_is_v5(vcpu->kvm))
+		vgic_v5_put(vcpu);
+	else if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		vgic_v2_put(vcpu);
 	else
 		vgic_v3_put(vcpu);
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index eb16184c14cc5..9905317c9d49d 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -187,6 +187,7 @@ static inline u64 vgic_ich_hcr_trap_bits(void)
  * registers regardless of the hardware backed GIC used.
  */
 struct vgic_vmcr {
+	u32	en; /* GICv5-specific */
 	u32	grpen0;
 	u32	grpen1;
 
@@ -363,6 +364,12 @@ void vgic_debug_destroy(struct kvm *kvm);
 
 int vgic_v5_probe(const struct gic_kvm_info *info);
 void vgic_v5_get_implemented_ppis(void);
+void vgic_v5_load(struct kvm_vcpu *vcpu);
+void vgic_v5_put(struct kvm_vcpu *vcpu);
+void vgic_v5_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_v5_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_v5_restore_state(struct kvm_vcpu *vcpu);
+void vgic_v5_save_state(struct kvm_vcpu *vcpu);
 
 static inline int vgic_v3_max_apr_idx(struct kvm_vcpu *vcpu)
 {
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index e3e3518b1f099..b9d96a8ea53fd 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -444,6 +444,8 @@ struct vgic_v5_cpu_if {
 	 * it is the hyp's responsibility to keep the state constistent.
 	 */
 	u64	vgic_icsr;
+
+	struct gicv5_vpe gicv5_vpe;
 };
 
 /* What PPI capabilities does a GICv5 host have */
diff --git a/include/linux/irqchip/arm-gic-v5.h b/include/linux/irqchip/arm-gic-v5.h
index 68ddcdb1cec5a..d2780fc99c344 100644
--- a/include/linux/irqchip/arm-gic-v5.h
+++ b/include/linux/irqchip/arm-gic-v5.h
@@ -354,6 +354,11 @@ int gicv5_spi_irq_set_type(struct irq_data *d, unsigned int type);
 int gicv5_irs_iste_alloc(u32 lpi);
 void gicv5_irs_syncr(void);
 
+/* Embedded in kvm.arch */
+struct gicv5_vpe {
+	bool			resident;
+};
+
 struct gicv5_its_devtab_cfg {
 	union {
 		struct {
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:44 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:44 +0000
Subject: [PATCH v2 25/36] KVM: arm64: gic-v5: Reset vcpu state
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-26-sascha.bischoff@arm.com>

Limit the number of ID and priority bits supported based on the
hardware capabilities when resetting the vcpu state.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/vgic/vgic-init.c |  6 +++++-
 arch/arm64/kvm/vgic/vgic-v5.c   | 30 ++++++++++++++++++++++++++++++
 arch/arm64/kvm/vgic/vgic.h      |  1 +
 3 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index afb5888cd8219..56cd5c05742df 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -396,7 +396,11 @@ int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
 
 static void kvm_vgic_vcpu_reset(struct kvm_vcpu *vcpu)
 {
-	if (kvm_vgic_global_state.type == VGIC_V2)
+	const struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+
+	if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5)
+		vgic_v5_reset(vcpu);
+	else if (kvm_vgic_global_state.type == VGIC_V2)
 		vgic_v2_reset(vcpu);
 	else
 		vgic_v3_reset(vcpu);
diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index 17001b06af600..feba175a5047d 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -56,6 +56,36 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
 	return 0;
 }
 
+void vgic_v5_reset(struct kvm_vcpu *vcpu)
+{
+	u64 idr0;
+
+	idr0 = read_sysreg_s(SYS_ICC_IDR0_EL1);
+	switch (FIELD_GET(ICC_IDR0_EL1_ID_BITS, idr0)) {
+	case ICC_IDR0_EL1_ID_BITS_16BITS:
+		vcpu->arch.vgic_cpu.num_id_bits = 16;
+		break;
+	case ICC_IDR0_EL1_ID_BITS_24BITS:
+		vcpu->arch.vgic_cpu.num_id_bits = 24;
+		break;
+	default:
+		pr_warn("unknown value for id_bits");
+		vcpu->arch.vgic_cpu.num_id_bits = 16;
+	}
+
+	switch (FIELD_GET(ICC_IDR0_EL1_PRI_BITS, idr0)) {
+	case ICC_IDR0_EL1_PRI_BITS_4BITS:
+		vcpu->arch.vgic_cpu.num_pri_bits = 4;
+		break;
+	case ICC_IDR0_EL1_PRI_BITS_5BITS:
+		vcpu->arch.vgic_cpu.num_pri_bits = 5;
+		break;
+	default:
+		pr_warn("unknown value for priority_bits");
+		vcpu->arch.vgic_cpu.num_pri_bits = 4;
+	}
+}
+
 int vgic_v5_init(struct kvm *kvm)
 {
 	struct kvm_vcpu *vcpu;
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index f974b55fb8058..c8ff545e777c2 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -386,6 +386,7 @@ void vgic_debug_destroy(struct kvm *kvm);
 
 int vgic_v5_probe(const struct gic_kvm_info *info);
 void vgic_v5_get_implemented_ppis(void);
+void vgic_v5_reset(struct kvm_vcpu *vcpu);
 int vgic_v5_init(struct kvm *kvm);
 int vgic_v5_map_resources(struct kvm *kvm);
 void vgic_v5_set_ppi_ops(struct vgic_irq *irq);
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:40 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:40 +0000
Subject: [PATCH v2 14/36] KVM: arm64: gic-v5: Add vgic-v5 save/restore hyp
 interface
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-15-sascha.bischoff@arm.com>

Introduce hyp functions to save/restore the following GICv5 state:

* ICC_ICSR_EL1
* ICH_APR_EL2
* ICH_PPI_ACTIVERx_EL2
* ICH_PPI_DVIRx_EL2
* ICH_PPI_ENABLERx_EL2
* ICH_PPI_PENDRRx_EL2
* ICH_PPI_PRIORITYRx_EL2
* ICH_VMCR_EL2

All of these are saved/restored to/from the KVM vgic_v5 CPUIF shadow
state.

The ICSR must be save/restored as this register is shared between host
and guest. Therefore, to avoid leaking host state to the guest, this
must be saved and restored. Moreover, as this can by used by the host
at any time, it must be save/restored eagerly. Note: the host state is
not preserved as the host should only use this register when
preemption is disabled.

As part of restoring the ICH_VMCR_EL2 and ICH_APR_EL2, GICv3-compat
mode is also disabled by setting the ICH_VCTLR_EL2.V3 bit to 0. The
correspoinding GICv3-compat mode enable is part of the VMCR & APR
restore for a GICv3 guest as it only takes effect when actually
running a guest.

Co-authored-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/include/asm/kvm_asm.h   |   4 +
 arch/arm64/include/asm/kvm_hyp.h   |   6 ++
 arch/arm64/kvm/hyp/nvhe/hyp-main.c |  32 ++++++++
 arch/arm64/kvm/hyp/vgic-v5-sr.c    | 119 +++++++++++++++++++++++++++++
 include/kvm/arm_vgic.h             |  33 ++++++++
 5 files changed, 194 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index ada752e97c6aa..328be86d36d51 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -90,6 +90,10 @@ enum __kvm_host_smccc_func {
 	__KVM_HOST_SMCCC_FUNC___pkvm_vcpu_put,
 	__KVM_HOST_SMCCC_FUNC___pkvm_tlb_flush_vmid,
 	__KVM_HOST_SMCCC_FUNC___vgic_v5_detect_ppis,
+	__KVM_HOST_SMCCC_FUNC___vgic_v5_save_apr,
+	__KVM_HOST_SMCCC_FUNC___vgic_v5_restore_vmcr_apr,
+	__KVM_HOST_SMCCC_FUNC___vgic_v5_save_ppi_state,
+	__KVM_HOST_SMCCC_FUNC___vgic_v5_restore_ppi_state,
 };
 
 #define DECLARE_KVM_VHE_SYM(sym)	extern char sym[]
diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index 80e5491de8e1e..c965f4e178cee 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -89,6 +89,12 @@ int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);
 
 /* GICv5 */
 void __vgic_v5_detect_ppis(u64 *ppi);
+void __vgic_v5_save_apr(struct vgic_v5_cpu_if *cpu_if);
+void __vgic_v5_restore_vmcr_apr(struct vgic_v5_cpu_if *cpu_if);
+void __vgic_v5_save_ppi_state(struct vgic_v5_cpu_if *cpu_if);
+void __vgic_v5_restore_ppi_state(struct vgic_v5_cpu_if *cpu_if);
+void __vgic_v5_save_state(struct vgic_v5_cpu_if *cpu_if);
+void __vgic_v5_restore_state(struct vgic_v5_cpu_if *cpu_if);
 
 #ifdef __KVM_NVHE_HYPERVISOR__
 void __timer_enable_traps(struct kvm_vcpu *vcpu);
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 3d1d0807be6db..e640776ca83ba 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -596,6 +596,34 @@ static void handle___vgic_v5_detect_ppis(struct kvm_cpu_context *host_ctxt)
 	cpu_reg(host_ctxt, 2) = ppi[1];
 }
 
+static void handle___vgic_v5_save_apr(struct kvm_cpu_context *host_ctxt)
+{
+	DECLARE_REG(struct vgic_v5_cpu_if *, cpu_if, host_ctxt, 1);
+
+	__vgic_v5_save_apr(kern_hyp_va(cpu_if));
+}
+
+static void handle___vgic_v5_restore_vmcr_apr(struct kvm_cpu_context *host_ctxt)
+{
+	DECLARE_REG(struct vgic_v5_cpu_if *, cpu_if, host_ctxt, 1);
+
+	__vgic_v5_restore_vmcr_apr(kern_hyp_va(cpu_if));
+}
+
+static void handle___vgic_v5_save_ppi_state(struct kvm_cpu_context *host_ctxt)
+{
+	DECLARE_REG(struct vgic_v5_cpu_if *, cpu_if, host_ctxt, 1);
+
+	__vgic_v5_save_ppi_state(kern_hyp_va(cpu_if));
+}
+
+static void handle___vgic_v5_restore_ppi_state(struct kvm_cpu_context *host_ctxt)
+{
+	DECLARE_REG(struct vgic_v5_cpu_if *, cpu_if, host_ctxt, 1);
+
+	__vgic_v5_restore_ppi_state(kern_hyp_va(cpu_if));
+}
+
 typedef void (*hcall_t)(struct kvm_cpu_context *);
 
 #define HANDLE_FUNC(x)	[__KVM_HOST_SMCCC_FUNC_##x] = (hcall_t)handle_##x
@@ -638,6 +666,10 @@ static const hcall_t host_hcall[] = {
 	HANDLE_FUNC(__pkvm_vcpu_put),
 	HANDLE_FUNC(__pkvm_tlb_flush_vmid),
 	HANDLE_FUNC(__vgic_v5_detect_ppis),
+	HANDLE_FUNC(__vgic_v5_save_apr),
+	HANDLE_FUNC(__vgic_v5_restore_vmcr_apr),
+	HANDLE_FUNC(__vgic_v5_save_ppi_state),
+	HANDLE_FUNC(__vgic_v5_restore_ppi_state),
 };
 
 static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
diff --git a/arch/arm64/kvm/hyp/vgic-v5-sr.c b/arch/arm64/kvm/hyp/vgic-v5-sr.c
index 4b088588757ea..310e49a2e6f45 100644
--- a/arch/arm64/kvm/hyp/vgic-v5-sr.c
+++ b/arch/arm64/kvm/hyp/vgic-v5-sr.c
@@ -25,3 +25,122 @@ void __vgic_v5_detect_ppis(u64 *impl_ppi_mask)
 	write_sysreg_s(0, SYS_ICH_PPI_ENABLER0_EL2);
 	write_sysreg_s(0, SYS_ICH_PPI_ENABLER1_EL2);
 }
+
+void __vgic_v5_save_apr(struct vgic_v5_cpu_if *cpu_if)
+{
+	cpu_if->vgic_apr = read_sysreg_s(SYS_ICH_APR_EL2);
+}
+
+static void  __vgic_v5_compat_mode_disable(void)
+{
+	sysreg_clear_set_s(SYS_ICH_VCTLR_EL2, ICH_VCTLR_EL2_V3, 0);
+	isb();
+}
+
+void __vgic_v5_restore_vmcr_apr(struct vgic_v5_cpu_if *cpu_if)
+{
+	__vgic_v5_compat_mode_disable();
+
+	write_sysreg_s(cpu_if->vgic_vmcr, SYS_ICH_VMCR_EL2);
+	write_sysreg_s(cpu_if->vgic_apr, SYS_ICH_APR_EL2);
+}
+
+void __vgic_v5_save_ppi_state(struct vgic_v5_cpu_if *cpu_if)
+{
+	cpu_if->vgic_ppi_activer_exit[0] = read_sysreg_s(SYS_ICH_PPI_ACTIVER0_EL2);
+	cpu_if->vgic_ppi_activer_exit[1] = read_sysreg_s(SYS_ICH_PPI_ACTIVER1_EL2);
+
+	cpu_if->vgic_ich_ppi_enabler_exit[0] = read_sysreg_s(SYS_ICH_PPI_ENABLER0_EL2);
+	cpu_if->vgic_ich_ppi_enabler_exit[1] = read_sysreg_s(SYS_ICH_PPI_ENABLER1_EL2);
+
+	cpu_if->vgic_ppi_pendr_exit[0] = read_sysreg_s(SYS_ICH_PPI_PENDR0_EL2);
+	cpu_if->vgic_ppi_pendr_exit[1] = read_sysreg_s(SYS_ICH_PPI_PENDR1_EL2);
+
+	cpu_if->vgic_ppi_priorityr[0] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR0_EL2);
+	cpu_if->vgic_ppi_priorityr[1] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR1_EL2);
+	cpu_if->vgic_ppi_priorityr[2] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR2_EL2);
+	cpu_if->vgic_ppi_priorityr[3] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR3_EL2);
+	cpu_if->vgic_ppi_priorityr[4] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR4_EL2);
+	cpu_if->vgic_ppi_priorityr[5] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR5_EL2);
+	cpu_if->vgic_ppi_priorityr[6] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR6_EL2);
+	cpu_if->vgic_ppi_priorityr[7] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR7_EL2);
+	cpu_if->vgic_ppi_priorityr[8] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR8_EL2);
+	cpu_if->vgic_ppi_priorityr[9] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR9_EL2);
+	cpu_if->vgic_ppi_priorityr[10] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR10_EL2);
+	cpu_if->vgic_ppi_priorityr[11] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR11_EL2);
+	cpu_if->vgic_ppi_priorityr[12] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR12_EL2);
+	cpu_if->vgic_ppi_priorityr[13] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR13_EL2);
+	cpu_if->vgic_ppi_priorityr[14] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR14_EL2);
+	cpu_if->vgic_ppi_priorityr[15] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR15_EL2);
+
+	/* Now that we are done, disable DVI */
+	write_sysreg_s(0, SYS_ICH_PPI_DVIR0_EL2);
+	write_sysreg_s(0, SYS_ICH_PPI_DVIR1_EL2);
+}
+
+void __vgic_v5_restore_ppi_state(struct vgic_v5_cpu_if *cpu_if)
+{
+	 /* Now enable DVI so that the guest's interrupt config takes over */
+	 write_sysreg_s(cpu_if->vgic_ppi_dvir[0], SYS_ICH_PPI_DVIR0_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_dvir[1], SYS_ICH_PPI_DVIR1_EL2);
+
+	 write_sysreg_s(cpu_if->vgic_ppi_activer_entry[0],
+			SYS_ICH_PPI_ACTIVER0_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_activer_entry[1],
+			SYS_ICH_PPI_ACTIVER1_EL2);
+
+	 write_sysreg_s(cpu_if->vgic_ich_ppi_enabler_entry[0],
+			SYS_ICH_PPI_ENABLER0_EL2);
+	 write_sysreg_s(cpu_if->vgic_ich_ppi_enabler_entry[1],
+			SYS_ICH_PPI_ENABLER1_EL2);
+
+	 /* Update the pending state of the NON-DVI'd PPIs, only */
+	 write_sysreg_s(cpu_if->vgic_ppi_pendr_entry[0] & ~cpu_if->vgic_ppi_dvir[0],
+			SYS_ICH_PPI_PENDR0_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_pendr_entry[1] & ~cpu_if->vgic_ppi_dvir[1],
+			SYS_ICH_PPI_PENDR1_EL2);
+
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[0],
+			SYS_ICH_PPI_PRIORITYR0_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[1],
+			SYS_ICH_PPI_PRIORITYR1_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[2],
+			SYS_ICH_PPI_PRIORITYR2_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[3],
+			SYS_ICH_PPI_PRIORITYR3_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[4],
+			SYS_ICH_PPI_PRIORITYR4_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[5],
+			SYS_ICH_PPI_PRIORITYR5_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[6],
+			SYS_ICH_PPI_PRIORITYR6_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[7],
+			SYS_ICH_PPI_PRIORITYR7_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[8],
+			SYS_ICH_PPI_PRIORITYR8_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[9],
+			SYS_ICH_PPI_PRIORITYR9_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[10],
+			SYS_ICH_PPI_PRIORITYR10_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[11],
+			SYS_ICH_PPI_PRIORITYR11_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[12],
+			SYS_ICH_PPI_PRIORITYR12_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[13],
+			SYS_ICH_PPI_PRIORITYR13_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[14],
+			SYS_ICH_PPI_PRIORITYR14_EL2);
+	 write_sysreg_s(cpu_if->vgic_ppi_priorityr[15],
+			SYS_ICH_PPI_PRIORITYR15_EL2);
+}
+
+void __vgic_v5_save_state(struct vgic_v5_cpu_if *cpu_if)
+{
+	cpu_if->vgic_vmcr = read_sysreg_s(SYS_ICH_VMCR_EL2);
+	cpu_if->vgic_icsr = read_sysreg_s(SYS_ICC_ICSR_EL1);
+}
+
+void __vgic_v5_restore_state(struct vgic_v5_cpu_if *cpu_if)
+{
+	write_sysreg_s(cpu_if->vgic_icsr, SYS_ICC_ICSR_EL1);
+}
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index c7786a2607ecd..e3e3518b1f099 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -414,6 +414,38 @@ struct vgic_v3_cpu_if {
 	unsigned int used_lrs;
 };
 
+struct vgic_v5_cpu_if {
+	u64	vgic_apr;
+	u64	vgic_vmcr;
+
+	/* PPI register state */
+	u64	vgic_ppi_hmr[2];
+	u64	vgic_ppi_dvir[2];
+	u64	vgic_ppi_priorityr[16];
+
+	/* The pending state of the guest. This is merged with the exit state */
+	u64	vgic_ppi_pendr[2];
+
+	/* The state flushed to the regs when entering the guest */
+	u64	vgic_ppi_activer_entry[2];
+	u64	vgic_ich_ppi_enabler_entry[2];
+	u64	vgic_ppi_pendr_entry[2];
+
+	/* The saved state of the regs when leaving the guest */
+	u64	vgic_ppi_activer_exit[2];
+	u64	vgic_ich_ppi_enabler_exit[2];
+	u64	vgic_ppi_pendr_exit[2];
+
+	/*
+	 * The ICSR is re-used across host and guest, and hence it needs to be
+	 * saved/restored. Only one copy is required as the host should block
+	 * preemption between executing GIC CDRCFG and acccessing the
+	 * ICC_ICSR_EL1. A guest, of course, can never guarantee this, and hence
+	 * it is the hyp's responsibility to keep the state constistent.
+	 */
+	u64	vgic_icsr;
+};
+
 /* What PPI capabilities does a GICv5 host have */
 struct vgic_v5_ppi_caps {
 	u64	impl_ppi_mask[2];
@@ -424,6 +456,7 @@ struct vgic_cpu {
 	union {
 		struct vgic_v2_cpu_if	vgic_v2;
 		struct vgic_v3_cpu_if	vgic_v3;
+		struct vgic_v5_cpu_if	vgic_v5;
 	};
 
 	struct vgic_irq *private_irqs;
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:42 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:42 +0000
Subject: [PATCH v2 18/36] KVM: arm64: gic-v5: Implement PPI interrupt
 injection
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-19-sascha.bischoff@arm.com>

This change introduces interrupt injection for PPIs for GICv5-based
guests.

The lifecycle of PPIs is largely managed by the hardware for a GICv5
system. The hypervisor injects pending state into the guest by using
the ICH_PPI_PENDRx_EL2 registers. These are used by the hardware to
pick a Highest Priority Pending Interrupt (HPPI) for the guest based
on the enable state of each individual interrupt. The enable state and
priority for each interrupt are provided by the guest itself (through
writes to the PPI registers).

When Direct Virtual Interrupt (DVI) is set for a particular PPI, the
hypervisor is even able to skip the injection of the pending state
altogether - it all happens in hardware.

The result of the above is that no AP lists are required for GICv5,
unlike for older GICs. Instead, for PPIs the ICH_PPI_* registers
fulfil the same purpose for all 128 PPIs. Hence, as long as the
ICH_PPI_* registers are populated prior to guest entry, and merged
back into the KVM shadow state on exit, the PPI state is preserved,
and interrupts can be injected.

When injecting the state of a PPI the state is merged into the KVM's
shadow state using the set_pending_state irq_op. The directly sets the
relevant bit in the shadow ICH_PPI_PENDRx_EL2, which is presented to
the guest (and GICv5 hardware) on next guest entry. The
queue_irq_unlock irq_op is required to kick the vCPU to ensure that it
seems the new state. The result is that no AP lists are used for
private interrupts on GICv5.

Prior to entering the guest, vgic_v5_flush_ppi_state is called from
kvm_vgic_flush_hwstate. The effectively snapshots the shadow PPI
pending state (twice - an entry and an exit copy) in order to track
any changes. These changes can come from a guest consuming an
interrupt or from a guest making an Edge-triggered interrupt pending.

When returning from running a guest, the guest's PPI state is merged
back into KVM's shadow state in vgic_v5_merge_ppi_state from
kvm_vgic_sync_hwstate. The Enable and Active state is synced back for
all PPIs, and the pending state is synced back for Edge PPIs (Level is
driven directly by the devices generating said levels). The incoming
pending state from the guest is merged with KVM's shadow state to
avoid losing any incoming interrupts.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/vgic/vgic-v5.c | 159 ++++++++++++++++++++++++++++++++++
 arch/arm64/kvm/vgic/vgic.c    |  46 +++++++---
 arch/arm64/kvm/vgic/vgic.h    |  47 ++++++++--
 include/kvm/arm_vgic.h        |   3 +
 4 files changed, 235 insertions(+), 20 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index 46c70dfc7bb08..cb3dd872d16a6 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -56,6 +56,165 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
 	return 0;
 }
 
+static bool vgic_v5_ppi_set_pending_state(struct kvm_vcpu *vcpu,
+					  struct vgic_irq *irq)
+{
+	struct vgic_v5_cpu_if *cpu_if;
+	const u64 id_bit = BIT_ULL(irq->intid % 64);
+	const u32 reg = FIELD_GET(GICV5_HWIRQ_ID, irq->intid) / 64;
+
+	if (!vcpu || !irq)
+		return false;
+
+	/* Skip injecting the state altogether */
+	if (irq->directly_injected)
+		return true;
+
+	cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+
+	if (irq_is_pending(irq))
+		cpu_if->vgic_ppi_pendr[reg] |= id_bit;
+	else
+		cpu_if->vgic_ppi_pendr[reg] &= ~id_bit;
+
+	return true;
+}
+
+/*
+ * For GICv5, the PPIs are mostly directly managed by the hardware. We
+ * (the hypervisor) handle the pending, active, enable state
+ * save/restore, but don't need the PPIs to be queued on a per-VCPU AP
+ * list. Therefore, sanity check the state, unlock, and return.
+ */
+static bool vgic_v5_ppi_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq,
+					 unsigned long flags)
+	__releases(&irq->irq_lock)
+{
+	struct kvm_vcpu *vcpu;
+
+	lockdep_assert_held(&irq->irq_lock);
+
+	if (WARN_ON_ONCE(!__irq_is_ppi(KVM_DEV_TYPE_ARM_VGIC_V5, irq->intid)))
+		goto out_unlock_fail;
+
+	vcpu = irq->target_vcpu;
+	if (WARN_ON_ONCE(!vcpu))
+		goto out_unlock_fail;
+
+	raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
+
+	/* Directly kick the target VCPU to make sure it sees the IRQ */
+	kvm_make_request(KVM_REQ_IRQ_PENDING, vcpu);
+	kvm_vcpu_kick(vcpu);
+
+	return true;
+
+out_unlock_fail:
+	raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
+
+	return false;
+}
+
+static struct irq_ops vgic_v5_ppi_irq_ops = {
+	.set_pending_state = vgic_v5_ppi_set_pending_state,
+	.queue_irq_unlock = vgic_v5_ppi_queue_irq_unlock,
+};
+
+void vgic_v5_set_ppi_ops(struct vgic_irq *irq)
+{
+	if (WARN_ON(!irq))
+		return;
+
+	scoped_guard(raw_spinlock, &irq->irq_lock) {
+		if (!WARN_ON(irq->ops))
+			irq->ops = &vgic_v5_ppi_irq_ops;
+	}
+}
+
+/*
+ * Detect any PPIs state changes, and propagate the state with KVM's
+ * shadow structures.
+ */
+void vgic_v5_fold_ppi_state(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+	int i, reg;
+
+	for (reg = 0; reg < 2; reg++) {
+		unsigned long changed_bits;
+		const unsigned long enabler = cpu_if->vgic_ich_ppi_enabler_exit[reg];
+		const unsigned long activer = cpu_if->vgic_ppi_activer_exit[reg];
+		const unsigned long pendr = cpu_if->vgic_ppi_pendr_exit[reg];
+
+		/*
+		 * Track what changed across enabler, activer, pendr, but mask
+		 * with ~DVI.
+		 */
+		changed_bits = cpu_if->vgic_ich_ppi_enabler_entry[reg] ^ enabler;
+		changed_bits |= cpu_if->vgic_ppi_activer_entry[reg] ^ activer;
+		changed_bits |= cpu_if->vgic_ppi_pendr_entry[reg] ^ pendr;
+		changed_bits &= ~cpu_if->vgic_ppi_dvir[reg];
+
+		for_each_set_bit(i, &changed_bits, 64) {
+			struct vgic_irq *irq;
+			u32 intid;
+
+			intid = FIELD_PREP(GICV5_HWIRQ_TYPE, GICV5_HWIRQ_TYPE_PPI);
+			intid |= FIELD_PREP(GICV5_HWIRQ_ID, reg * 64 + i);
+
+			irq = vgic_get_vcpu_irq(vcpu, intid);
+
+			scoped_guard(raw_spinlock, &irq->irq_lock) {
+				irq->enabled = !!(enabler & BIT(i));
+				irq->active = !!(activer & BIT(i));
+
+				/* This is an OR to avoid losing incoming edges! */
+				if (irq->config == VGIC_CONFIG_EDGE)
+					irq->pending_latch |= !!(pendr & BIT(i));
+			}
+
+			vgic_put_irq(vcpu->kvm, irq);
+		}
+
+		/* Re-inject the exit state as entry state next time! */
+		cpu_if->vgic_ich_ppi_enabler_entry[reg] = enabler;
+		cpu_if->vgic_ppi_activer_entry[reg] = activer;
+
+		/*
+		 * Pending state is a bit different. We only propagate back
+		 * pending state for Edge interrupts. Moreover, this is OR'd
+		 * with the incoming state to make sure we don't lose incoming
+		 * edges. Use the (inverse) HMR to mask off all Level bits, and
+		 * OR.
+		 */
+		cpu_if->vgic_ppi_pendr[reg] |= pendr & ~cpu_if->vgic_ppi_hmr[reg];
+	}
+}
+
+void vgic_v5_flush_ppi_state(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+
+	/*
+	 * We're about to enter the guest. Copy the shadow state to the pending
+	 * reg that will be written to the ICH_PPI_PENDRx_EL2 regs. While the
+	 * guest is running we track any incoming changes to the pending state in
+	 * vgic_ppi_pendr. The incoming changes are merged with the outgoing
+	 * changes on the return path.
+	 */
+	cpu_if->vgic_ppi_pendr_entry[0] = cpu_if->vgic_ppi_pendr[0];
+	cpu_if->vgic_ppi_pendr_entry[1] = cpu_if->vgic_ppi_pendr[1];
+
+	/*
+	 * Make sure that we can correctly detect "edges" in the PPI
+	 * state. There's a path where we never actually enter the guest, and
+	 * failure to do this risks losing pending state
+	 */
+	cpu_if->vgic_ppi_pendr_exit[0] = cpu_if->vgic_ppi_pendr[0];
+	cpu_if->vgic_ppi_pendr_exit[1] = cpu_if->vgic_ppi_pendr[1];
+
+}
+
 /*
  * Not all PPIs are guaranteed to be implemented for
  * GICv5. Deterermine which ones are, and generate a mask. This is
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index ac8cb0270e1e4..cb5d43b34462b 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -105,6 +105,14 @@ struct vgic_irq *vgic_get_vcpu_irq(struct kvm_vcpu *vcpu, u32 intid)
 	if (WARN_ON(!vcpu))
 		return NULL;
 
+	if (vgic_is_v5(vcpu->kvm) &&
+	    __irq_is_ppi(KVM_DEV_TYPE_ARM_VGIC_V5, intid)) {
+		u32 int_num = FIELD_GET(GICV5_HWIRQ_ID, intid);
+
+		int_num = array_index_nospec(int_num, VGIC_V5_NR_PRIVATE_IRQS);
+		return &vcpu->arch.vgic_cpu.private_irqs[int_num];
+	}
+
 	/* SGIs and PPIs */
 	if (intid < VGIC_NR_PRIVATE_IRQS) {
 		intid = array_index_nospec(intid, VGIC_NR_PRIVATE_IRQS);
@@ -258,10 +266,12 @@ struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
 	 * If the distributor is disabled, pending interrupts shouldn't be
 	 * forwarded.
 	 */
-	if (irq->enabled && irq_is_pending(irq)) {
-		if (unlikely(irq->target_vcpu &&
-			     !irq->target_vcpu->kvm->arch.vgic.enabled))
-			return NULL;
+	if (irq_is_enabled(irq) && irq_is_pending(irq)) {
+		if (irq->target_vcpu) {
+			if (!vgic_is_v5(irq->target_vcpu->kvm) &&
+			    unlikely(!irq->target_vcpu->kvm->arch.vgic.enabled))
+				return NULL;
+		}
 
 		return irq->target_vcpu;
 	}
@@ -836,9 +846,11 @@ static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
 		vgic_release_deleted_lpis(vcpu->kvm);
 }
 
-static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
+static void vgic_fold_state(struct kvm_vcpu *vcpu)
 {
-	if (kvm_vgic_global_state.type == VGIC_V2)
+	if (vgic_is_v5(vcpu->kvm))
+		vgic_v5_fold_ppi_state(vcpu);
+	else if (kvm_vgic_global_state.type == VGIC_V2)
 		vgic_v2_fold_lr_state(vcpu);
 	else
 		vgic_v3_fold_lr_state(vcpu);
@@ -1045,8 +1057,10 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 	if (can_access_vgic_from_kernel())
 		vgic_save_state(vcpu);
 
-	vgic_fold_lr_state(vcpu);
-	vgic_prune_ap_list(vcpu);
+	vgic_fold_state(vcpu);
+
+	if (!vgic_is_v5(vcpu->kvm))
+		vgic_prune_ap_list(vcpu);
 }
 
 /* Sync interrupts that were deactivated through a DIR trap */
@@ -1070,6 +1084,17 @@ static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
 		__vgic_v3_restore_state(&vcpu->arch.vgic_cpu.vgic_v3);
 }
 
+static void vgic_flush_state(struct kvm_vcpu *vcpu)
+{
+	if (vgic_is_v5(vcpu->kvm)) {
+		vgic_v5_flush_ppi_state(vcpu);
+		return;
+	}
+
+	scoped_guard(raw_spinlock, &vcpu->arch.vgic_cpu.ap_list_lock)
+		vgic_flush_lr_state(vcpu);
+}
+
 /* Flush our emulation state into the GIC hardware before entering the guest. */
 void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 {
@@ -1106,13 +1131,12 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 
 	DEBUG_SPINLOCK_BUG_ON(!irqs_disabled());
 
-	scoped_guard(raw_spinlock, &vcpu->arch.vgic_cpu.ap_list_lock)
-		vgic_flush_lr_state(vcpu);
+	vgic_flush_state(vcpu);
 
 	if (can_access_vgic_from_kernel())
 		vgic_restore_state(vcpu);
 
-	if (vgic_supports_direct_irqs(vcpu->kvm))
+	if (vgic_supports_direct_irqs(vcpu->kvm) && !vgic_is_v5(vcpu->kvm))
 		vgic_v4_commit(vcpu);
 }
 
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index d5d9264f0a1e9..978d7f8426361 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -132,6 +132,28 @@ static inline bool irq_is_pending(struct vgic_irq *irq)
 		return irq->pending_latch || irq->line_level;
 }
 
+/* Requires the irq_lock to be held by the caller. */
+static inline bool irq_is_enabled(struct vgic_irq *irq)
+{
+	if (irq->enabled)
+		return true;
+
+	/*
+	 * We always consider GICv5 interrupts as enabled as we can
+	 * always inject them. The state is handled by the hardware,
+	 * and the hardware will only signal the interrupt to the
+	 * guest once the guest enables it.
+	 */
+	if (irq->target_vcpu) {
+		u32 vgic_model = irq->target_vcpu->kvm->arch.vgic.vgic_model;
+
+		if (vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5)
+			return true;
+	}
+
+	return false;
+}
+
 static inline bool vgic_irq_is_mapped_level(struct vgic_irq *irq)
 {
 	return irq->config == VGIC_CONFIG_LEVEL && irq->hw;
@@ -364,7 +386,10 @@ void vgic_debug_destroy(struct kvm *kvm);
 
 int vgic_v5_probe(const struct gic_kvm_info *info);
 void vgic_v5_get_implemented_ppis(void);
+void vgic_v5_set_ppi_ops(struct vgic_irq *irq);
 int vgic_v5_set_ppi_dvi(struct kvm_vcpu *vcpu, u32 irq, bool dvi);
+void vgic_v5_flush_ppi_state(struct kvm_vcpu *vcpu);
+void vgic_v5_fold_ppi_state(struct kvm_vcpu *vcpu);
 void vgic_v5_load(struct kvm_vcpu *vcpu);
 void vgic_v5_put(struct kvm_vcpu *vcpu);
 void vgic_v5_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
@@ -433,15 +458,6 @@ void vgic_its_invalidate_all_caches(struct kvm *kvm);
 int vgic_its_inv_lpi(struct kvm *kvm, struct vgic_irq *irq);
 int vgic_its_invall(struct kvm_vcpu *vcpu);
 
-bool system_supports_direct_sgis(void);
-bool vgic_supports_direct_msis(struct kvm *kvm);
-bool vgic_supports_direct_sgis(struct kvm *kvm);
-
-static inline bool vgic_supports_direct_irqs(struct kvm *kvm)
-{
-	return vgic_supports_direct_msis(kvm) || vgic_supports_direct_sgis(kvm);
-}
-
 int vgic_v4_init(struct kvm *kvm);
 void vgic_v4_teardown(struct kvm *kvm);
 void vgic_v4_configure_vsgis(struct kvm *kvm);
@@ -481,6 +497,19 @@ static inline bool vgic_is_v3(struct kvm *kvm)
 	return kvm_vgic_global_state.type == VGIC_V3 || vgic_is_v3_compat(kvm);
 }
 
+bool system_supports_direct_sgis(void);
+bool vgic_supports_direct_msis(struct kvm *kvm);
+bool vgic_supports_direct_sgis(struct kvm *kvm);
+
+static inline bool vgic_supports_direct_irqs(struct kvm *kvm)
+{
+	/* GICv5 always supports direct IRQs */
+	if (vgic_is_v5(kvm))
+		return true;
+
+	return vgic_supports_direct_msis(kvm) || vgic_supports_direct_sgis(kvm);
+}
+
 int vgic_its_debug_init(struct kvm_device *dev);
 void vgic_its_debug_destroy(struct kvm_device *dev);
 
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 500709bd62c8d..b5180edbd1165 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -32,6 +32,9 @@
 #define VGIC_MIN_LPI		8192
 #define KVM_IRQCHIP_NUM_PINS	(1020 - 32)
 
+/* GICv5 constants */
+#define VGIC_V5_NR_PRIVATE_IRQS	128
+
 #define is_v5_type(t, i)	(FIELD_GET(GICV5_HWIRQ_TYPE, (i)) == (t))
 
 #define __irq_is_sgi(t, i)						\
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:42 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:42 +0000
Subject: [PATCH v2 19/36] KVM: arm64: gic-v5: Check for pending PPIs
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-20-sascha.bischoff@arm.com>

This change allows KVM to check for pending PPI interrupts. This has
two main components:

First of all, the effective priority mask is calculated.  This is a
combination of the priority mask in the VPEs ICC_PCR_EL1.PRIORITY and
the currently running priority as determined from the VPE's
ICH_APR_EL1. If an interrupt's prioirity is greater than or equal to
the effective priority mask, it can be signalled. Otherwise, it
cannot.

Secondly, any Enabled and Pending PPIs must be checked against this
compound priority mask. The reqires the PPI priorities to by synced
back to the KVM shadow state - this is skipped in general operation as
it isn't required and is rather expensive. If any Enabled and Pending
PPIs are of sufficient priority to be signalled, then there are
pending PPIs. Else, there are not.  This ensures that a VPE is not
woken when it cannot actually process the pending interrupts.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/vgic/vgic-v5.c | 121 ++++++++++++++++++++++++++++++++++
 arch/arm64/kvm/vgic/vgic.c    |   5 +-
 arch/arm64/kvm/vgic/vgic.h    |   1 +
 3 files changed, 126 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index cb3dd872d16a6..c7ecc4f40b1e5 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -56,6 +56,31 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
 	return 0;
 }
 
+static u32 vgic_v5_get_effective_priority_mask(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+	u32 highest_ap, priority_mask;
+
+	/*
+	 * Counting the number of trailing zeros gives the current
+	 * active priority. Explicitly use the 32-bit version here as
+	 * we have 32 priorities. 0x20 then means that there are no
+	 * active priorities.
+	 */
+	highest_ap = cpu_if->vgic_apr ? __builtin_ctz(cpu_if->vgic_apr) : 32;
+
+	/*
+	 * An interrupt is of sufficient priority if it is equal to or
+	 * greater than the priority mask. Add 1 to the priority mask
+	 * (i.e., lower priority) to match the APR logic before taking
+	 * the min. This gives us the lowest priority that is masked.
+	 */
+	priority_mask = FIELD_GET(FEAT_GCIE_ICH_VMCR_EL2_VPMR, cpu_if->vgic_vmcr);
+	priority_mask = min(highest_ap, priority_mask + 1);
+
+	return priority_mask;
+}
+
 static bool vgic_v5_ppi_set_pending_state(struct kvm_vcpu *vcpu,
 					  struct vgic_irq *irq)
 {
@@ -131,6 +156,102 @@ void vgic_v5_set_ppi_ops(struct vgic_irq *irq)
 	}
 }
 
+
+/*
+ * Sync back the PPI priorities to the vgic_irq shadow state
+ */
+static void vgic_v5_sync_ppi_priorities(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+	int i, reg;
+
+	/* We have 16 PPI Priority regs */
+	for (reg = 0; reg < 16; reg++) {
+		const unsigned long priorityr = cpu_if->vgic_ppi_priorityr[reg];
+
+		for (i = 0; i < 8; ++i) {
+			struct vgic_irq *irq;
+			u32 intid;
+			u8 priority;
+
+			priority = (priorityr >> (i * 8)) & 0x1f;
+
+			intid = FIELD_PREP(GICV5_HWIRQ_TYPE, GICV5_HWIRQ_TYPE_PPI);
+			intid |= FIELD_PREP(GICV5_HWIRQ_ID, reg * 8 + i);
+
+			irq = vgic_get_vcpu_irq(vcpu, intid);
+
+			scoped_guard(raw_spinlock, &irq->irq_lock)
+				irq->priority = priority;
+
+			vgic_put_irq(vcpu->kvm, irq);
+		}
+	}
+}
+
+bool vgic_v5_has_pending_ppi(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+	int i, reg;
+	unsigned int priority_mask;
+
+	/* If no pending bits are set, exit early */
+	if (likely(!cpu_if->vgic_ppi_pendr[0] && !cpu_if->vgic_ppi_pendr[1]))
+		return false;
+
+	priority_mask = vgic_v5_get_effective_priority_mask(vcpu);
+
+	/* If the combined priority mask is 0, nothing can be signalled! */
+	if (!priority_mask)
+		return false;
+
+	/* The shadow priority is only updated on demand, sync it across first */
+	vgic_v5_sync_ppi_priorities(vcpu);
+
+	for (reg = 0; reg < 2; reg++) {
+		unsigned long possible_bits;
+		const unsigned long enabler = cpu_if->vgic_ich_ppi_enabler_exit[reg];
+		const unsigned long pendr = cpu_if->vgic_ppi_pendr_exit[reg];
+		bool has_pending = false;
+
+		/* Check all interrupts that are enabled and pending */
+		possible_bits = enabler & pendr;
+
+		/*
+		 * Optimisation: pending and enabled with no active priorities
+		 */
+		if (possible_bits && priority_mask > 0x1f)
+			return true;
+
+		for_each_set_bit(i, &possible_bits, 64) {
+			struct vgic_irq *irq;
+			u32 intid;
+
+			intid = FIELD_PREP(GICV5_HWIRQ_TYPE, GICV5_HWIRQ_TYPE_PPI);
+			intid |= FIELD_PREP(GICV5_HWIRQ_ID, reg * 64 + i);
+
+			irq = vgic_get_vcpu_irq(vcpu, intid);
+
+			scoped_guard(raw_spinlock, &irq->irq_lock) {
+				/*
+				 * We know that the interrupt is
+				 * enabled and pending, so only check
+				 * the priority.
+				 */
+				if (irq->priority <= priority_mask)
+					has_pending = true;
+			}
+
+			vgic_put_irq(vcpu->kvm, irq);
+
+			if (has_pending)
+				return true;
+		}
+	}
+
+	return false;
+}
+
 /*
  * Detect any PPIs state changes, and propagate the state with KVM's
  * shadow structures.
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index cb5d43b34462b..dfec6ed7936ed 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -1180,9 +1180,12 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
 	unsigned long flags;
 	struct vgic_vmcr vmcr;
 
-	if (!vcpu->kvm->arch.vgic.enabled)
+	if (!vcpu->kvm->arch.vgic.enabled && !vgic_is_v5(vcpu->kvm))
 		return false;
 
+	if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5)
+		return vgic_v5_has_pending_ppi(vcpu);
+
 	if (vcpu->arch.vgic_cpu.vgic_v3.its_vpe.pending_last)
 		return true;
 
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index 978d7f8426361..65c031da83e78 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -388,6 +388,7 @@ int vgic_v5_probe(const struct gic_kvm_info *info);
 void vgic_v5_get_implemented_ppis(void);
 void vgic_v5_set_ppi_ops(struct vgic_irq *irq);
 int vgic_v5_set_ppi_dvi(struct kvm_vcpu *vcpu, u32 irq, bool dvi);
+bool vgic_v5_has_pending_ppi(struct kvm_vcpu *vcpu);
 void vgic_v5_flush_ppi_state(struct kvm_vcpu *vcpu);
 void vgic_v5_fold_ppi_state(struct kvm_vcpu *vcpu);
 void vgic_v5_load(struct kvm_vcpu *vcpu);
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:43 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:43 +0000
Subject: [PATCH v2 23/36] KVM: arm64: gic-v5: Support GICv5 interrupts with
 KVM_IRQ_LINE
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-24-sascha.bischoff@arm.com>

Interrupts under GICv5 look quite different to those from older Arm
GICs. Specifically, the type is encoded in the top bits of the
interrupt ID.

Extend KVM_IRQ_LINE to cope with GICv5 PPIs and SPIs. The requires
subtly changing the KVM_IRQ_LINE API for GICv5 guests. For older Arm
GICs, PPIs had to be in the range of 16-31, and SPIs had to be
32-1019, but this no longer holds true for GICv5. Instead, for a GICv5
guest support PPIs in the range of 0-127, and SPIs in the range
0-65535. The documentation is updated accordingly.

The SPI range doesn't cover the full SPI range that a GICv5 system can
potentially cope with (GICv5 provides up to 24-bits of SPI ID space,
and we only have 16 bits to work with in KVM_IRQ_LINE). However, 65k
SPIs is more than would be reasonably expected on systems for years to
come.

Note: As the GICv5 KVM implementation currently doesn't support
injecting SPIs attempts to do so will fail. This restruction will
lifted as the GICv5 KVM support evolves.

Co-authored-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 Documentation/virt/kvm/api.rst |  6 ++++--
 arch/arm64/kvm/arm.c           | 21 ++++++++++++++++++---
 arch/arm64/kvm/vgic/vgic.c     |  4 ++++
 3 files changed, 26 insertions(+), 5 deletions(-)

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 01a3abef8abb9..460a5511ebcec 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -907,10 +907,12 @@ The irq_type field has the following values:
 - KVM_ARM_IRQ_TYPE_CPU:
 	       out-of-kernel GIC: irq_id 0 is IRQ, irq_id 1 is FIQ
 - KVM_ARM_IRQ_TYPE_SPI:
-	       in-kernel GIC: SPI, irq_id between 32 and 1019 (incl.)
+	       in-kernel GICv2/GICv3: SPI, irq_id between 32 and 1019 (incl.)
                (the vcpu_index field is ignored)
+	       in-kernel GICv5: SPI, irq_id between 0 and 65535 (incl.)
 - KVM_ARM_IRQ_TYPE_PPI:
-	       in-kernel GIC: PPI, irq_id between 16 and 31 (incl.)
+	       in-kernel GICv2/GICv3: PPI, irq_id between 16 and 31 (incl.)
+	       in-kernel GICv5: PPI, irq_id between 0 and 127 (incl.)
 
 (The irq_id field thus corresponds nicely to the IRQ ID in the ARM GIC specs)
 
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 94f8d13ab3b58..4448e8a5fc076 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -45,6 +45,8 @@
 #include <kvm/arm_pmu.h>
 #include <kvm/arm_psci.h>
 
+#include <linux/irqchip/arm-gic-v5.h>
+
 #include "sys_regs.h"
 
 static enum kvm_mode kvm_mode = KVM_MODE_DEFAULT;
@@ -1430,16 +1432,29 @@ int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level,
 		if (!vcpu)
 			return -EINVAL;
 
-		if (irq_num < VGIC_NR_SGIS || irq_num >= VGIC_NR_PRIVATE_IRQS)
+		if (kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5) {
+			if (irq_num >= VGIC_V5_NR_PRIVATE_IRQS)
+				return -EINVAL;
+
+			/* Build a GICv5-style IntID here */
+			irq_num |= FIELD_PREP(GICV5_HWIRQ_TYPE, GICV5_HWIRQ_TYPE_PPI);
+		} else if (irq_num < VGIC_NR_SGIS ||
+			   irq_num >= VGIC_NR_PRIVATE_IRQS) {
 			return -EINVAL;
+		}
 
 		return kvm_vgic_inject_irq(kvm, vcpu, irq_num, level, NULL);
 	case KVM_ARM_IRQ_TYPE_SPI:
 		if (!irqchip_in_kernel(kvm))
 			return -ENXIO;
 
-		if (irq_num < VGIC_NR_PRIVATE_IRQS)
-			return -EINVAL;
+		if (kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5) {
+			/* Build a GICv5-style IntID here */
+			irq_num |= FIELD_PREP(GICV5_HWIRQ_TYPE, GICV5_HWIRQ_TYPE_SPI);
+		} else {
+			if (irq_num < VGIC_NR_PRIVATE_IRQS)
+				return -EINVAL;
+		}
 
 		return kvm_vgic_inject_irq(kvm, NULL, irq_num, level, NULL);
 	}
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index dfec6ed7936ed..d91f7039fed6c 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -86,6 +86,10 @@ static struct vgic_irq *vgic_get_lpi(struct kvm *kvm, u32 intid)
  */
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, u32 intid)
 {
+	/* Non-private IRQs are not yet implemented for GICv5 */
+	if (vgic_is_v5(kvm))
+		return NULL;
+
 	/* SPIs */
 	if (intid >= VGIC_NR_PRIVATE_IRQS &&
 	    intid < (kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS)) {
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:45 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:45 +0000
Subject: [PATCH v2 27/36] KVM: arm64: gic-v5: Mandate architected PPI for PMU
 emulation on GICv5
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-28-sascha.bischoff@arm.com>

Make it mandatory to use the architected PPI when running a GICv5
guest. Attempts to set anything other than the architected PPI (23)
are rejected.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/pmu-emul.c | 14 ++++++++++++--
 include/kvm/arm_pmu.h     |  5 ++++-
 2 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c
index afc838ea2503e..2d3b50dec6c5d 100644
--- a/arch/arm64/kvm/pmu-emul.c
+++ b/arch/arm64/kvm/pmu-emul.c
@@ -962,8 +962,13 @@ static int kvm_arm_pmu_v3_init(struct kvm_vcpu *vcpu)
 		if (!vgic_initialized(vcpu->kvm))
 			return -ENODEV;
 
-		if (!kvm_arm_pmu_irq_initialized(vcpu))
-			return -ENXIO;
+		if (!kvm_arm_pmu_irq_initialized(vcpu)) {
+			/* Use the architected irq number for GICv5. */
+			if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5)
+				vcpu->arch.pmu.irq_num = KVM_ARMV8_PMU_GICV5_IRQ;
+			else
+				return -ENXIO;
+		}
 
 		ret = kvm_vgic_set_owner(vcpu, vcpu->arch.pmu.irq_num,
 					 &vcpu->arch.pmu);
@@ -988,6 +993,11 @@ static bool pmu_irq_is_valid(struct kvm *kvm, int irq)
 	unsigned long i;
 	struct kvm_vcpu *vcpu;
 
+	/* On GICv5, the PMUIRQ is architecturally mandated to be PPI 23 */
+	if (kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5 &&
+	    irq != KVM_ARMV8_PMU_GICV5_IRQ)
+		return false;
+
 	kvm_for_each_vcpu(i, vcpu, kvm) {
 		if (!kvm_arm_pmu_irq_initialized(vcpu))
 			continue;
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 96754b51b4116..0a36a3d5c8944 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -12,6 +12,9 @@
 
 #define KVM_ARMV8_PMU_MAX_COUNTERS	32
 
+/* PPI #23 - architecturally specified for GICv5 */
+#define KVM_ARMV8_PMU_GICV5_IRQ		0x20000017
+
 #if IS_ENABLED(CONFIG_HW_PERF_EVENTS) && IS_ENABLED(CONFIG_KVM)
 struct kvm_pmc {
 	u8 idx;	/* index into the pmu->pmc array */
@@ -38,7 +41,7 @@ struct arm_pmu_entry {
 };
 
 bool kvm_supports_guest_pmuv3(void);
-#define kvm_arm_pmu_irq_initialized(v)	((v)->arch.pmu.irq_num >= VGIC_NR_SGIS)
+#define kvm_arm_pmu_irq_initialized(v)	((v)->arch.pmu.irq_num != 0)
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
 void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu, u64 select_idx, u64 val);
 void kvm_pmu_set_counter_value_user(struct kvm_vcpu *vcpu, u64 select_idx, u64 val);
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:45 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:45 +0000
Subject: [PATCH v2 28/36] KVM: arm64: gic: Hide GICv5 for protected guests
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-29-sascha.bischoff@arm.com>

We don't support running protected guest with GICv5 at the
moment. Therefore, be sure that we don't expose it to the guest at all
by actively hiding it when running a protected guest.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/include/asm/kvm_hyp.h   | 1 +
 arch/arm64/kvm/arm.c               | 1 +
 arch/arm64/kvm/hyp/nvhe/sys_regs.c | 8 ++++++++
 3 files changed, 10 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index c965f4e178cee..7322ea3faded7 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -145,6 +145,7 @@ void __noreturn __host_enter(struct kvm_cpu_context *host_ctxt);
 
 extern u64 kvm_nvhe_sym(id_aa64pfr0_el1_sys_val);
 extern u64 kvm_nvhe_sym(id_aa64pfr1_el1_sys_val);
+extern u64 kvm_nvhe_sym(id_aa64pfr2_el1_sys_val);
 extern u64 kvm_nvhe_sym(id_aa64isar0_el1_sys_val);
 extern u64 kvm_nvhe_sym(id_aa64isar1_el1_sys_val);
 extern u64 kvm_nvhe_sym(id_aa64isar2_el1_sys_val);
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 4448e8a5fc076..1d3f2f713769f 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -2471,6 +2471,7 @@ static void kvm_hyp_init_symbols(void)
 {
 	kvm_nvhe_sym(id_aa64pfr0_el1_sys_val) = get_hyp_id_aa64pfr0_el1();
 	kvm_nvhe_sym(id_aa64pfr1_el1_sys_val) = read_sanitised_ftr_reg(SYS_ID_AA64PFR1_EL1);
+	kvm_nvhe_sym(id_aa64pfr2_el1_sys_val) = read_sanitised_ftr_reg(SYS_ID_AA64PFR2_EL1);
 	kvm_nvhe_sym(id_aa64isar0_el1_sys_val) = read_sanitised_ftr_reg(SYS_ID_AA64ISAR0_EL1);
 	kvm_nvhe_sym(id_aa64isar1_el1_sys_val) = read_sanitised_ftr_reg(SYS_ID_AA64ISAR1_EL1);
 	kvm_nvhe_sym(id_aa64isar2_el1_sys_val) = read_sanitised_ftr_reg(SYS_ID_AA64ISAR2_EL1);
diff --git a/arch/arm64/kvm/hyp/nvhe/sys_regs.c b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
index 3108b5185c204..9652935a6ebdd 100644
--- a/arch/arm64/kvm/hyp/nvhe/sys_regs.c
+++ b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
@@ -20,6 +20,7 @@
  */
 u64 id_aa64pfr0_el1_sys_val;
 u64 id_aa64pfr1_el1_sys_val;
+u64 id_aa64pfr2_el1_sys_val;
 u64 id_aa64isar0_el1_sys_val;
 u64 id_aa64isar1_el1_sys_val;
 u64 id_aa64isar2_el1_sys_val;
@@ -108,6 +109,11 @@ static const struct pvm_ftr_bits pvmid_aa64pfr1[] = {
 	FEAT_END
 };
 
+static const struct pvm_ftr_bits pvmid_aa64pfr2[] = {
+	MAX_FEAT(ID_AA64PFR2_EL1, GCIE, NI),
+	FEAT_END
+};
+
 static const struct pvm_ftr_bits pvmid_aa64mmfr0[] = {
 	MAX_FEAT_ENUM(ID_AA64MMFR0_EL1, PARANGE, 40),
 	MAX_FEAT_ENUM(ID_AA64MMFR0_EL1, ASIDBITS, 16),
@@ -221,6 +227,8 @@ static u64 pvm_calc_id_reg(const struct kvm_vcpu *vcpu, u32 id)
 		return get_restricted_features(vcpu, id_aa64pfr0_el1_sys_val, pvmid_aa64pfr0);
 	case SYS_ID_AA64PFR1_EL1:
 		return get_restricted_features(vcpu, id_aa64pfr1_el1_sys_val, pvmid_aa64pfr1);
+	case SYS_ID_AA64PFR2_EL1:
+		return get_restricted_features(vcpu, id_aa64pfr2_el1_sys_val, pvmid_aa64pfr2);
 	case SYS_ID_AA64ISAR0_EL1:
 		return id_aa64isar0_el1_sys_val;
 	case SYS_ID_AA64ISAR1_EL1:
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:43 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:43 +0000
Subject: [PATCH v2 22/36] KVM: arm64: gic-v5: Trap and mask guest PPI register
 accesses
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-23-sascha.bischoff@arm.com>

A guest should not be able to detect if a PPI that is not exposed to
the guest is implemented or not. If the writes to the PPI registers
are not masked, it becomes possible for the guest to detect the
presence of all implemented PPIs on the host.

Guest writes to the following registers are masked:

ICC_CACTIVERx_EL1
ICC_SACTIVERx_EL1
ICC_CPENDRx_EL1
ICC_SPENDRx_EL1
ICC_ENABLERx_EL1
ICC_PRIORITYRx_EL1

When a guest writes these registers, the write is masked with the set
of PPIs actually exposed to the guest, and the state is written back
to KVM's shadow state..

Reads for the above registers are not masked. When the guest is
running and reads from the above registers, it is presented with what
KVM provides in the ICH_PPI_x_EL2 registers, which is the masked
version of what the guest last wrote.

The ICC_PPI_HMRx_EL1 register is used to determine which PPIs use
Level-sensitive semantics, and which use Edge. For a GICv5 guest, the
correct view of the virtual PPIs must be provided to the guest, and
hence this must also be trapped, but only for reads. The content of
the HMRs is calculated and masked when finalising the PPI state for
the guest.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/config.c   |  22 ++++++-
 arch/arm64/kvm/sys_regs.c | 133 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 153 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index eb0c6f4d95b6d..f81bfdadd12fb 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -1586,8 +1586,26 @@ static void __compute_ich_hfgrtr(struct kvm_vcpu *vcpu)
 {
 	__compute_fgt(vcpu, ICH_HFGRTR_EL2);
 
-	/* ICC_IAFFIDR_EL1 *always* needs to be trapped when running a guest */
+	/*
+	 * ICC_IAFFIDR_EL1 and ICH_PPI_HMRx_EL1 *always* needs to be
+	 * trapped when running a guest.
+	 **/
 	*vcpu_fgt(vcpu, ICH_HFGRTR_EL2) &= ~ICH_HFGRTR_EL2_ICC_IAFFIDR_EL1;
+	*vcpu_fgt(vcpu, ICH_HFGRTR_EL2) &= ~ICH_HFGRTR_EL2_ICC_PPI_HMRn_EL1;
+}
+
+static void __compute_ich_hfgwtr(struct kvm_vcpu *vcpu)
+{
+	__compute_fgt(vcpu, ICH_HFGWTR_EL2);
+
+	/*
+	 * We present a different subset of PPIs the guest from what
+	 * exist in real hardware. We only trap writes, not reads.
+	 */
+	*vcpu_fgt(vcpu, ICH_HFGWTR_EL2) &= ~(ICH_HFGWTR_EL2_ICC_PPI_ENABLERn_EL1 |
+					     ICH_HFGWTR_EL2_ICC_PPI_PENDRn_EL1 |
+					     ICH_HFGWTR_EL2_ICC_PPI_PRIORITYRn_EL1 |
+					     ICH_HFGWTR_EL2_ICC_PPI_ACTIVERn_EL1);
 }
 
 void kvm_vcpu_load_fgt(struct kvm_vcpu *vcpu)
@@ -1616,6 +1634,6 @@ void kvm_vcpu_load_fgt(struct kvm_vcpu *vcpu)
 		return;
 
 	__compute_ich_hfgrtr(vcpu);
-	__compute_fgt(vcpu, ICH_HFGWTR_EL2);
+	__compute_ich_hfgwtr(vcpu);
 	__compute_fgt(vcpu, ICH_HFGITR_EL2);
 }
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 383ada0d75922..cef13bf6bb3a1 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -696,6 +696,111 @@ static bool access_gicv5_iaffid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
+static bool access_gicv5_ppi_hmr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+				 const struct sys_reg_desc *r)
+{
+	if (p->is_write)
+		return ignore_write(vcpu, p);
+
+	if (p->Op2 == 0) {	/* ICC_PPI_HMR0_EL1 */
+		p->regval = vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_hmr[0];
+	} else {		/* ICC_PPI_HMR1_EL1 */
+		p->regval = vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_hmr[1];
+	}
+
+	return true;
+}
+
+static bool access_gicv5_ppi_enabler(struct kvm_vcpu *vcpu,
+				     struct sys_reg_params *p,
+				     const struct sys_reg_desc *r)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+	u64 masked_write;
+
+	/* We never expect to get here with a read! */
+	if (WARN_ON_ONCE(!p->is_write))
+		return undef_access(vcpu, p, r);
+
+	masked_write = p->regval & cpu_if->vgic_ppi_mask[p->Op2 % 2];
+	cpu_if->vgic_ich_ppi_enabler_entry[p->Op2 % 2] = masked_write;
+
+	return true;
+}
+
+static bool access_gicv5_ppi_pendr(struct kvm_vcpu *vcpu,
+				   struct sys_reg_params *p,
+				   const struct sys_reg_desc *r)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+	u64 masked_write;
+
+	/* We never expect to get here with a read! */
+	if (WARN_ON_ONCE(!p->is_write))
+		return undef_access(vcpu, p, r);
+
+	masked_write = p->regval & cpu_if->vgic_ppi_mask[p->Op2 % 2];
+
+	if (p->Op2 & 0x2) {	/* SPENDRx */
+		cpu_if->vgic_ppi_pendr_entry[p->Op2 % 2] |= masked_write;
+	} else {		/* CPENDRx */
+		cpu_if->vgic_ppi_pendr_entry[p->Op2 % 2] &= ~masked_write;
+	}
+
+	return true;
+}
+
+static bool access_gicv5_ppi_activer(struct kvm_vcpu *vcpu,
+				     struct sys_reg_params *p,
+				     const struct sys_reg_desc *r)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+	u64 masked_write;
+
+	/* We never expect to get here with a read! */
+	if (WARN_ON_ONCE(!p->is_write))
+		return undef_access(vcpu, p, r);
+
+	masked_write = p->regval & cpu_if->vgic_ppi_mask[p->Op2 % 2];
+
+	if (p->Op2 & 0x2) {	/* SACTIVERx */
+		cpu_if->vgic_ppi_activer_entry[p->Op2 % 2] |= masked_write;
+	} else {		/* CACTIVERx */
+		cpu_if->vgic_ppi_activer_entry[p->Op2 % 2] &= ~masked_write;
+	}
+
+	return true;
+}
+
+static bool access_gicv5_ppi_priorityr(struct kvm_vcpu *vcpu,
+				     struct sys_reg_params *p,
+				     const struct sys_reg_desc *r)
+{
+	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
+	u64 mask, masked_write;
+	unsigned long mask_slice;
+	int i;
+	int reg_idx = ((p->CRm & 0x1) << 3) | p->Op2;
+	int mask_idx = reg_idx >= 8;
+
+	/* We never expect to get here with a read! */
+	if (WARN_ON_ONCE(!p->is_write))
+		return undef_access(vcpu, p, r);
+
+	/* Get the 8 bits of the mask that we care about */
+	mask_slice = (cpu_if->vgic_ppi_mask[mask_idx] >> (reg_idx % 8) * 8) & 0xff;
+
+	/* Generate our mask for the PRIORITYR */
+	mask = 0;
+	for_each_set_bit(i, &mask_slice, 8)
+		mask |= 0x1f << i * 8;
+
+	masked_write = p->regval & mask;
+	vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_priorityr[reg_idx] = masked_write;
+
+	return true;
+}
+
 static bool trap_raz_wi(struct kvm_vcpu *vcpu,
 			struct sys_reg_params *p,
 			const struct sys_reg_desc *r)
@@ -3426,7 +3531,11 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	{ SYS_DESC(SYS_ICC_AP1R1_EL1), undef_access },
 	{ SYS_DESC(SYS_ICC_AP1R2_EL1), undef_access },
 	{ SYS_DESC(SYS_ICC_AP1R3_EL1), undef_access },
+	{ SYS_DESC(SYS_ICC_PPI_HMR0_EL1), access_gicv5_ppi_hmr },
+	{ SYS_DESC(SYS_ICC_PPI_HMR1_EL1), access_gicv5_ppi_hmr },
 	{ SYS_DESC(SYS_ICC_IAFFIDR_EL1), access_gicv5_iaffid },
+	{ SYS_DESC(SYS_ICC_PPI_ENABLER0_EL1), access_gicv5_ppi_enabler },
+	{ SYS_DESC(SYS_ICC_PPI_ENABLER1_EL1), access_gicv5_ppi_enabler },
 	{ SYS_DESC(SYS_ICC_DIR_EL1), access_gic_dir },
 	{ SYS_DESC(SYS_ICC_RPR_EL1), undef_access },
 	{ SYS_DESC(SYS_ICC_SGI1R_EL1), access_gic_sgi },
@@ -3440,6 +3549,30 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	{ SYS_DESC(SYS_ICC_SRE_EL1), access_gic_sre },
 	{ SYS_DESC(SYS_ICC_IGRPEN0_EL1), undef_access },
 	{ SYS_DESC(SYS_ICC_IGRPEN1_EL1), undef_access },
+	{ SYS_DESC(SYS_ICC_PPI_CACTIVER0_EL1), access_gicv5_ppi_activer },
+	{ SYS_DESC(SYS_ICC_PPI_CACTIVER1_EL1), access_gicv5_ppi_activer },
+	{ SYS_DESC(SYS_ICC_PPI_SACTIVER0_EL1), access_gicv5_ppi_activer },
+	{ SYS_DESC(SYS_ICC_PPI_SACTIVER1_EL1), access_gicv5_ppi_activer },
+	{ SYS_DESC(SYS_ICC_PPI_CPENDR0_EL1), access_gicv5_ppi_pendr },
+	{ SYS_DESC(SYS_ICC_PPI_CPENDR1_EL1), access_gicv5_ppi_pendr },
+	{ SYS_DESC(SYS_ICC_PPI_SPENDR0_EL1), access_gicv5_ppi_pendr },
+	{ SYS_DESC(SYS_ICC_PPI_SPENDR1_EL1), access_gicv5_ppi_pendr },
+	{ SYS_DESC(SYS_ICC_PPI_PRIORITYR0_EL1), access_gicv5_ppi_priorityr },
+	{ SYS_DESC(SYS_ICC_PPI_PRIORITYR1_EL1), access_gicv5_ppi_priorityr },
+	{ SYS_DESC(SYS_ICC_PPI_PRIORITYR2_EL1), access_gicv5_ppi_priorityr },
+	{ SYS_DESC(SYS_ICC_PPI_PRIORITYR3_EL1), access_gicv5_ppi_priorityr },
+	{ SYS_DESC(SYS_ICC_PPI_PRIORITYR4_EL1), access_gicv5_ppi_priorityr },
+	{ SYS_DESC(SYS_ICC_PPI_PRIORITYR5_EL1), access_gicv5_ppi_priorityr },
+	{ SYS_DESC(SYS_ICC_PPI_PRIORITYR6_EL1), access_gicv5_ppi_priorityr },
+	{ SYS_DESC(SYS_ICC_PPI_PRIORITYR7_EL1), access_gicv5_ppi_priorityr },
+	{ SYS_DESC(SYS_ICC_PPI_PRIORITYR8_EL1), access_gicv5_ppi_priorityr },
+	{ SYS_DESC(SYS_ICC_PPI_PRIORITYR9_EL1), access_gicv5_ppi_priorityr },
+	{ SYS_DESC(SYS_ICC_PPI_PRIORITYR10_EL1), access_gicv5_ppi_priorityr },
+	{ SYS_DESC(SYS_ICC_PPI_PRIORITYR11_EL1), access_gicv5_ppi_priorityr },
+	{ SYS_DESC(SYS_ICC_PPI_PRIORITYR12_EL1), access_gicv5_ppi_priorityr },
+	{ SYS_DESC(SYS_ICC_PPI_PRIORITYR13_EL1), access_gicv5_ppi_priorityr },
+	{ SYS_DESC(SYS_ICC_PPI_PRIORITYR14_EL1), access_gicv5_ppi_priorityr },
+	{ SYS_DESC(SYS_ICC_PPI_PRIORITYR15_EL1), access_gicv5_ppi_priorityr },
 
 	{ SYS_DESC(SYS_CONTEXTIDR_EL1), access_vm_reg, reset_val, CONTEXTIDR_EL1, 0 },
 	{ SYS_DESC(SYS_TPIDR_EL1), NULL, reset_unknown, TPIDR_EL1 },
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:44 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:44 +0000
Subject: [PATCH v2 24/36] KVM: arm64: gic-v5: Create, init vgic_v5
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-25-sascha.bischoff@arm.com>

Update kvm_vgic_create to create a vgic_v5 device. When creating a
vgic, FEAT_GCIE in the ID_AA64PFR2 is only exposed to vgic_v5-based
guests, and is hidden otherwise. GIC in ~ID_AA64PFR0_EL1 is never
exposed for a vgic_v5 guest.

When initialising a vgic_v5, skip kvm_vgic_dist_init as GICv5 doesn't
support one. The current vgic_v5 implementation only supports PPIs, so
no SPIs are initialised either.

The current vgic_v5 support doesn't extend to nested
guests. Therefore, the init of vgic_v5 for a nested guest is failed in
vgic_v5_init.

As the current vgic_v5 doesn't require any resources to be mapped,
vgic_v5_map_resources is simply used to check that the vgic has indeed
been initialised. Again, this will change as more GICv5 support is
merged in.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/vgic/vgic-init.c | 51 ++++++++++++++++++++++-----------
 arch/arm64/kvm/vgic/vgic-v5.c   | 26 +++++++++++++++++
 arch/arm64/kvm/vgic/vgic.h      |  2 ++
 include/kvm/arm_vgic.h          |  1 +
 4 files changed, 63 insertions(+), 17 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index 03f45816464b0..afb5888cd8219 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -66,12 +66,12 @@ static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu, u32 type);
  * or through the generic KVM_CREATE_DEVICE API ioctl.
  * irqchip_in_kernel() tells you if this function succeeded or not.
  * @kvm: kvm struct pointer
- * @type: KVM_DEV_TYPE_ARM_VGIC_V[23]
+ * @type: KVM_DEV_TYPE_ARM_VGIC_V[235]
  */
 int kvm_vgic_create(struct kvm *kvm, u32 type)
 {
 	struct kvm_vcpu *vcpu;
-	u64 aa64pfr0, pfr1;
+	u64 aa64pfr0, aa64pfr2, pfr1;
 	unsigned long i;
 	int ret;
 
@@ -132,8 +132,11 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
 
 	if (type == KVM_DEV_TYPE_ARM_VGIC_V2)
 		kvm->max_vcpus = VGIC_V2_MAX_CPUS;
-	else
+	else if (type == KVM_DEV_TYPE_ARM_VGIC_V3)
 		kvm->max_vcpus = VGIC_V3_MAX_CPUS;
+	else if (type == KVM_DEV_TYPE_ARM_VGIC_V5)
+		kvm->max_vcpus = min(VGIC_V5_MAX_CPUS,
+				     kvm_vgic_global_state.max_gic_vcpus);
 
 	if (atomic_read(&kvm->online_vcpus) > kvm->max_vcpus) {
 		ret = -E2BIG;
@@ -163,17 +166,21 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
 	}
 
 	aa64pfr0 = kvm_read_vm_id_reg(kvm, SYS_ID_AA64PFR0_EL1) & ~ID_AA64PFR0_EL1_GIC;
+	aa64pfr2 = kvm_read_vm_id_reg(kvm, SYS_ID_AA64PFR2_EL1) & ~ID_AA64PFR2_EL1_GCIE;
 	pfr1 = kvm_read_vm_id_reg(kvm, SYS_ID_PFR1_EL1) & ~ID_PFR1_EL1_GIC;
 
 	if (type == KVM_DEV_TYPE_ARM_VGIC_V2) {
 		kvm->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
-	} else {
+	} else if (type == KVM_DEV_TYPE_ARM_VGIC_V3) {
 		INIT_LIST_HEAD(&kvm->arch.vgic.rd_regions);
 		aa64pfr0 |= SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, GIC, IMP);
 		pfr1 |= SYS_FIELD_PREP_ENUM(ID_PFR1_EL1, GIC, GICv3);
+	} else {
+		aa64pfr2 |= SYS_FIELD_PREP_ENUM(ID_AA64PFR2_EL1, GCIE, IMP);
 	}
 
 	kvm_set_vm_id_reg(kvm, SYS_ID_AA64PFR0_EL1, aa64pfr0);
+	kvm_set_vm_id_reg(kvm, SYS_ID_AA64PFR2_EL1, aa64pfr2);
 	kvm_set_vm_id_reg(kvm, SYS_ID_PFR1_EL1, pfr1);
 
 	if (type == KVM_DEV_TYPE_ARM_VGIC_V3)
@@ -420,20 +427,26 @@ int vgic_init(struct kvm *kvm)
 	if (kvm->created_vcpus != atomic_read(&kvm->online_vcpus))
 		return -EBUSY;
 
-	/* freeze the number of spis */
-	if (!dist->nr_spis)
-		dist->nr_spis = VGIC_NR_IRQS_LEGACY - VGIC_NR_PRIVATE_IRQS;
+	if (!vgic_is_v5(kvm)) {
+		/* freeze the number of spis */
+		if (!dist->nr_spis)
+			dist->nr_spis = VGIC_NR_IRQS_LEGACY - VGIC_NR_PRIVATE_IRQS;
 
-	ret = kvm_vgic_dist_init(kvm, dist->nr_spis);
-	if (ret)
-		goto out;
+		ret = kvm_vgic_dist_init(kvm, dist->nr_spis);
+		if (ret)
+			goto out;
 
-	/*
-	 * Ensure vPEs are allocated if direct IRQ injection (e.g. vSGIs,
-	 * vLPIs) is supported.
-	 */
-	if (vgic_supports_direct_irqs(kvm)) {
-		ret = vgic_v4_init(kvm);
+		/*
+		 * Ensure vPEs are allocated if direct IRQ injection (e.g. vSGIs,
+		 * vLPIs) is supported.
+		 */
+		if (vgic_supports_direct_irqs(kvm)) {
+			ret = vgic_v4_init(kvm);
+			if (ret)
+				goto out;
+		}
+	} else {
+		ret = vgic_v5_init(kvm);
 		if (ret)
 			goto out;
 	}
@@ -610,9 +623,13 @@ int kvm_vgic_map_resources(struct kvm *kvm)
 	if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2) {
 		ret = vgic_v2_map_resources(kvm);
 		type = VGIC_V2;
-	} else {
+	} else if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) {
 		ret = vgic_v3_map_resources(kvm);
 		type = VGIC_V3;
+	} else {
+		ret = vgic_v5_map_resources(kvm);
+		type = VGIC_V5;
+		goto out;
 	}
 
 	if (ret)
diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index f1fa63e67c1f6..17001b06af600 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -56,6 +56,32 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
 	return 0;
 }
 
+int vgic_v5_init(struct kvm *kvm)
+{
+	struct kvm_vcpu *vcpu;
+	unsigned long idx;
+
+	if (vgic_initialized(kvm))
+		return 0;
+
+	kvm_for_each_vcpu(idx, vcpu, kvm) {
+		if (vcpu_has_nv(vcpu)) {
+			kvm_err("Nested GICv5 VMs are currently unsupported\n");
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+int vgic_v5_map_resources(struct kvm *kvm)
+{
+	if (!vgic_initialized(kvm))
+		return -EBUSY;
+
+	return 0;
+}
+
 static u32 vgic_v5_get_effective_priority_mask(struct kvm_vcpu *vcpu)
 {
 	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index 65c031da83e78..f974b55fb8058 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -386,6 +386,8 @@ void vgic_debug_destroy(struct kvm *kvm);
 
 int vgic_v5_probe(const struct gic_kvm_info *info);
 void vgic_v5_get_implemented_ppis(void);
+int vgic_v5_init(struct kvm *kvm);
+int vgic_v5_map_resources(struct kvm *kvm);
 void vgic_v5_set_ppi_ops(struct vgic_irq *irq);
 int vgic_v5_set_ppi_dvi(struct kvm_vcpu *vcpu, u32 irq, bool dvi);
 bool vgic_v5_has_pending_ppi(struct kvm_vcpu *vcpu);
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index dc7bac0226b3c..696e2316f1ea9 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -21,6 +21,7 @@
 #include <linux/irqchip/arm-gic-v4.h>
 #include <linux/irqchip/arm-gic-v5.h>
 
+#define VGIC_V5_MAX_CPUS	512
 #define VGIC_V3_MAX_CPUS	512
 #define VGIC_V2_MAX_CPUS	8
 #define VGIC_NR_IRQS_LEGACY     256
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:42 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:42 +0000
Subject: [PATCH v2 20/36] KVM: arm64: gic-v5: Init Private IRQs (PPIs) for
 GICv5
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-21-sascha.bischoff@arm.com>

Initialise the private interrupts (PPIs, only) for GICv5. This means
that a GICv5-style intid is generated (which encodes the PPI type in
the top bits) instead of the 0-based index that is used for older
GICs.

Additionally, set all of the GICv5 PPIs to use Level for the handling
mode, with the exception of the SW_PPI which uses Edge. This matches
the architecturally-defined set in the GICv5 specification (the CTIIRQ
handling mode is IMPDEF, so pick Level has been picked for that).

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/vgic/vgic-init.c    | 41 +++++++++++++++++++++++-------
 include/linux/irqchip/arm-gic-v5.h |  2 ++
 2 files changed, 34 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index bcc2c79f7833c..03f45816464b0 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -263,13 +263,19 @@ static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu, u32 type)
 {
 	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
 	int i;
+	u32 num_private_irqs;
+
+	if (vgic_is_v5(vcpu->kvm))
+		num_private_irqs = VGIC_V5_NR_PRIVATE_IRQS;
+	else
+		num_private_irqs = VGIC_NR_PRIVATE_IRQS;
 
 	lockdep_assert_held(&vcpu->kvm->arch.config_lock);
 
 	if (vgic_cpu->private_irqs)
 		return 0;
 
-	vgic_cpu->private_irqs = kcalloc(VGIC_NR_PRIVATE_IRQS,
+	vgic_cpu->private_irqs = kcalloc(num_private_irqs,
 					 sizeof(struct vgic_irq),
 					 GFP_KERNEL_ACCOUNT);
 
@@ -280,22 +286,39 @@ static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu, u32 type)
 	 * Enable and configure all SGIs to be edge-triggered and
 	 * configure all PPIs as level-triggered.
 	 */
-	for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) {
+	for (i = 0; i < num_private_irqs; i++) {
 		struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
 
 		INIT_LIST_HEAD(&irq->ap_list);
 		raw_spin_lock_init(&irq->irq_lock);
-		irq->intid = i;
 		irq->vcpu = NULL;
 		irq->target_vcpu = vcpu;
 		refcount_set(&irq->refcount, 0);
-		if (vgic_irq_is_sgi(i)) {
-			/* SGIs */
-			irq->enabled = 1;
-			irq->config = VGIC_CONFIG_EDGE;
+		if (!vgic_is_v5(vcpu->kvm)) {
+			irq->intid = i;
+			if (vgic_irq_is_sgi(i)) {
+				/* SGIs */
+				irq->enabled = 1;
+				irq->config = VGIC_CONFIG_EDGE;
+			} else {
+				/* PPIs */
+				irq->config = VGIC_CONFIG_LEVEL;
+			}
 		} else {
-			/* PPIs */
-			irq->config = VGIC_CONFIG_LEVEL;
+			irq->intid = i | FIELD_PREP(GICV5_HWIRQ_TYPE,
+						    GICV5_HWIRQ_TYPE_PPI);
+
+			/*
+			 * The only architected PPI that is Edge is
+			 * the SW PPI.
+			 */
+			if (irq->intid == GICV5_SW_PPI)
+				irq->config = VGIC_CONFIG_EDGE;
+			else
+				irq->config = VGIC_CONFIG_LEVEL;
+
+			/* Register the GICv5-specific PPI ops */
+			vgic_v5_set_ppi_ops(irq);
 		}
 
 		switch (type) {
diff --git a/include/linux/irqchip/arm-gic-v5.h b/include/linux/irqchip/arm-gic-v5.h
index d2780fc99c344..2ab7ec718aaea 100644
--- a/include/linux/irqchip/arm-gic-v5.h
+++ b/include/linux/irqchip/arm-gic-v5.h
@@ -13,6 +13,8 @@
 
 #define GICV5_IPIS_PER_CPU		MAX_IPI
 
+#define GICV5_SW_PPI			0x20000003
+
 /*
  * INTID handling
  */
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:46 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:46 +0000
Subject: [PATCH v2 29/36] KVM: arm64: gic-v5: Hide FEAT_GCIE from NV GICv5
 guests
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-30-sascha.bischoff@arm.com>

Currently, NV guests are not supported with GICv5. Therefore, make
sure that FEAT_GCIE is always hidden from such guests.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/nested.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
index cdeeb8f09e722..66404d48405e7 100644
--- a/arch/arm64/kvm/nested.c
+++ b/arch/arm64/kvm/nested.c
@@ -1547,6 +1547,11 @@ u64 limit_nv_id_reg(struct kvm *kvm, u32 reg, u64 val)
 			 ID_AA64PFR1_EL1_MTE);
 		break;
 
+	case SYS_ID_AA64PFR2_EL1:
+		/* GICv5 is not yet supported for NV */
+		val &= ~ID_AA64PFR2_EL1_GCIE;
+		break;
+
 	case SYS_ID_AA64MMFR0_EL1:
 		/* Hide ExS, Secure Memory */
 		val &= ~(ID_AA64MMFR0_EL1_EXS		|
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:43 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:43 +0000
Subject: [PATCH v2 21/36] KVM: arm64: gic-v5: Finalize GICv5 PPIs and generate
 mask
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-22-sascha.bischoff@arm.com>

We only want to expose a subset of the PPIs to a guest. If a PPI does
not have an owner, it is not being actively driven by a device. The
SW_PPI is a special case, as it is likely for userspace to wish to
inject that.

Therefore, just prior to running the guest for the first time, we need
to finalize the PPIs. A mask is generated which, when combined with
trapping a guest's PPI accesses, allows for the guest's view of the
PPI to be filtered.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/arm.c          |  4 +++
 arch/arm64/kvm/vgic/vgic-v5.c | 60 +++++++++++++++++++++++++++++++++++
 include/kvm/arm_vgic.h        |  9 ++++++
 3 files changed, 73 insertions(+)

diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index b7cf9d86aabb7..94f8d13ab3b58 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -888,6 +888,10 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
 			return ret;
 	}
 
+	ret = vgic_v5_finalize_ppi_state(kvm);
+	if (ret)
+		return ret;
+
 	if (is_protected_kvm_enabled()) {
 		ret = pkvm_create_hyp_vm(kvm);
 		if (ret)
diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index c7ecc4f40b1e5..f1fa63e67c1f6 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -81,6 +81,66 @@ static u32 vgic_v5_get_effective_priority_mask(struct kvm_vcpu *vcpu)
 	return priority_mask;
 }
 
+static int vgic_v5_finalize_state(struct kvm_vcpu *vcpu)
+{
+	if (!ppi_caps)
+		return -ENXIO;
+
+	vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_mask[0] = 0;
+	vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_mask[1] = 0;
+	vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_hmr[0] = 0;
+	vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_hmr[1] = 0;
+	for (int i = 0; i < VGIC_V5_NR_PRIVATE_IRQS; ++i) {
+		int reg = i / 64;
+		u64 bit = BIT_ULL(i % 64);
+		struct vgic_irq *irq = &vcpu->arch.vgic_cpu.private_irqs[i];
+
+		raw_spin_lock(&irq->irq_lock);
+
+		/*
+		 * We only expose PPIs with an owner or thw SW_PPI to
+		 * the guest.
+		 */
+		if (!irq->owner && irq->intid == GICV5_SW_PPI)
+			goto unlock;
+
+		/*
+		 * If the PPI isn't implemented, we can't pass it
+		 * through to a guest anyhow.
+		 */
+		if (!(ppi_caps->impl_ppi_mask[reg] & bit))
+			goto unlock;
+
+		vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_mask[reg] |= bit;
+
+		if (irq->config == VGIC_CONFIG_LEVEL)
+			vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_hmr[reg] |= bit;
+
+unlock:
+		raw_spin_unlock(&irq->irq_lock);
+	}
+
+	return 0;
+}
+
+int vgic_v5_finalize_ppi_state(struct kvm *kvm)
+{
+	struct kvm_vcpu *vcpu;
+	unsigned long c;
+	int ret;
+
+	if (!vgic_is_v5(kvm))
+		return 0;
+
+	kvm_for_each_vcpu(c, vcpu, kvm) {
+		ret = vgic_v5_finalize_state(vcpu);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
 static bool vgic_v5_ppi_set_pending_state(struct kvm_vcpu *vcpu,
 					  struct vgic_irq *irq)
 {
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index b5180edbd1165..dc7bac0226b3c 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -455,6 +455,13 @@ struct vgic_v5_cpu_if {
 	u64	vgic_ich_ppi_enabler_exit[2];
 	u64	vgic_ppi_pendr_exit[2];
 
+	/*
+	 * We only expose a subset of PPIs to the guest. This subset
+	 * is a combination of the PPIs that are actually implemented
+	 * and what we actually choose to expose.
+	 */
+	u64	vgic_ppi_mask[2];
+
 	/*
 	 * The ICSR is re-used across host and guest, and hence it needs to be
 	 * saved/restored. Only one copy is required as the host should block
@@ -592,6 +599,8 @@ int vgic_v4_load(struct kvm_vcpu *vcpu);
 void vgic_v4_commit(struct kvm_vcpu *vcpu);
 int vgic_v4_put(struct kvm_vcpu *vcpu);
 
+int vgic_v5_finalize_ppi_state(struct kvm *kvm);
+
 bool vgic_state_is_nested(struct kvm_vcpu *vcpu);
 
 /* CPU HP callbacks */
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:45 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:45 +0000
Subject: [PATCH v2 26/36] KVM: arm64: gic-v5: Bump arch timer for GICv5
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-27-sascha.bischoff@arm.com>

Now that GICv5 has arrived, the arch timer requires some TLC to
address some of the key differences introduced with GICv5.

For PPIs on GICv5, the set_pending_state and queue_irq_unlock irq_ops
are used as AP lists are not required at all for GICv5. The arch timer
also introduces an irq_op - get_input_level. Extend the
arch-timer-provided irq_ops to include the two PPI ops for vgic_v5
guests.

When possible, DVI (Direct Virtual Interrupt) is set for PPIs when
using a vgic_v5, which directly inject the pending state in to the
guest. This means that the host never sees the interrupt for the guest
for these interrupts. This has two impacts.

* First of all, the kvm_cpu_has_pending_timer check is updated to
  explicitly check if the timers are expected to fire.

* Secondly, for mapped timers (which use DVI) they must be masked on
  the host prior to entering a GICv5 guest, and unmasked on the return
  path. This is handled in set_timer_irq_phys_masked.

The final, but rather important, change is that the architected PPIs
for the timers are made mandatory for a GICv5 guest. Attempts to set
them to anything else are actively rejected. Once a vgic_v5 is
initialised, the arch timer PPIs are also explicitly reinitialised to
ensure the correct GICv5-compatible PPIs are used - this also adds in
the GICv5 PPI type to the intid.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/arch_timer.c     | 110 ++++++++++++++++++++++++++------
 arch/arm64/kvm/vgic/vgic-init.c |   9 +++
 arch/arm64/kvm/vgic/vgic-v5.c   |   8 +--
 include/kvm/arm_arch_timer.h    |   7 +-
 include/kvm/arm_vgic.h          |   4 ++
 5 files changed, 115 insertions(+), 23 deletions(-)

diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c
index 6f033f6644219..78d66a67b34ac 100644
--- a/arch/arm64/kvm/arch_timer.c
+++ b/arch/arm64/kvm/arch_timer.c
@@ -56,6 +56,12 @@ static struct irq_ops arch_timer_irq_ops = {
 	.get_input_level = kvm_arch_timer_get_input_level,
 };
 
+static struct irq_ops arch_timer_irq_ops_vgic_v5 = {
+	.get_input_level = kvm_arch_timer_get_input_level,
+	.set_pending_state = vgic_v5_ppi_set_pending_state,
+	.queue_irq_unlock = vgic_v5_ppi_queue_irq_unlock,
+};
+
 static int nr_timers(struct kvm_vcpu *vcpu)
 {
 	if (!vcpu_has_nv(vcpu))
@@ -396,7 +402,11 @@ static bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx)
 
 int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
 {
-	return vcpu_has_wfit_active(vcpu) && wfit_delay_ns(vcpu) == 0;
+	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
+	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
+
+	return kvm_timer_should_fire(vtimer) || kvm_timer_should_fire(ptimer) ||
+	       (vcpu_has_wfit_active(vcpu) && wfit_delay_ns(vcpu) == 0);
 }
 
 /*
@@ -657,6 +667,24 @@ static inline void set_timer_irq_phys_active(struct arch_timer_context *ctx, boo
 	WARN_ON(r);
 }
 
+/*
+ * On GICv5 we use DVI for the arch timer PPIs. This is restored later
+ * on as part of vgic_load. Therefore, in order to avoid the guest's
+ * interrupt making it to the host we mask it before entering the
+ * guest and unmask it again when we return.
+ */
+static inline void set_timer_irq_phys_masked(struct arch_timer_context *ctx, bool masked)
+{
+	if (masked) {
+		disable_percpu_irq(ctx->host_timer_irq);
+	} else {
+		if (ctx->host_timer_irq == host_vtimer_irq)
+			enable_percpu_irq(ctx->host_timer_irq, host_vtimer_irq_flags);
+		else
+			enable_percpu_irq(ctx->host_timer_irq, host_ptimer_irq_flags);
+	}
+}
+
 static void kvm_timer_vcpu_load_gic(struct arch_timer_context *ctx)
 {
 	struct kvm_vcpu *vcpu = timer_context_to_vcpu(ctx);
@@ -675,7 +703,10 @@ static void kvm_timer_vcpu_load_gic(struct arch_timer_context *ctx)
 
 	phys_active |= ctx->irq.level;
 
-	set_timer_irq_phys_active(ctx, phys_active);
+	if (!vgic_is_v5(vcpu->kvm))
+		set_timer_irq_phys_active(ctx, phys_active);
+	else
+		set_timer_irq_phys_masked(ctx, true);
 }
 
 static void kvm_timer_vcpu_load_nogic(struct kvm_vcpu *vcpu)
@@ -719,10 +750,14 @@ static void kvm_timer_vcpu_load_nested_switch(struct kvm_vcpu *vcpu,
 					      struct timer_map *map)
 {
 	int hw, ret;
+	struct irq_ops *ops;
 
 	if (!irqchip_in_kernel(vcpu->kvm))
 		return;
 
+	ops = vgic_is_v5(vcpu->kvm) ? &arch_timer_irq_ops_vgic_v5 :
+				      &arch_timer_irq_ops;
+
 	/*
 	 * We only ever unmap the vtimer irq on a VHE system that runs nested
 	 * virtualization, in which case we have both a valid emul_vtimer,
@@ -741,12 +776,12 @@ static void kvm_timer_vcpu_load_nested_switch(struct kvm_vcpu *vcpu,
 		ret = kvm_vgic_map_phys_irq(vcpu,
 					    map->direct_vtimer->host_timer_irq,
 					    timer_irq(map->direct_vtimer),
-					    &arch_timer_irq_ops);
+					    ops);
 		WARN_ON_ONCE(ret);
 		ret = kvm_vgic_map_phys_irq(vcpu,
 					    map->direct_ptimer->host_timer_irq,
 					    timer_irq(map->direct_ptimer),
-					    &arch_timer_irq_ops);
+					    ops);
 		WARN_ON_ONCE(ret);
 	}
 }
@@ -864,7 +899,8 @@ void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)
 	get_timer_map(vcpu, &map);
 
 	if (static_branch_likely(&has_gic_active_state)) {
-		if (vcpu_has_nv(vcpu))
+		/* We don't do NV on GICv5, yet */
+		if (vcpu_has_nv(vcpu) && !vgic_is_v5(vcpu->kvm))
 			kvm_timer_vcpu_load_nested_switch(vcpu, &map);
 
 		kvm_timer_vcpu_load_gic(map.direct_vtimer);
@@ -934,6 +970,15 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
 
 	if (kvm_vcpu_is_blocking(vcpu))
 		kvm_timer_blocking(vcpu);
+
+	/* Unmask again on GICV5 */
+	if (vgic_is_v5(vcpu->kvm)) {
+		set_timer_irq_phys_masked(map.direct_vtimer, false);
+
+		if (map.direct_ptimer)
+			set_timer_irq_phys_masked(map.direct_ptimer, false);
+
+	}
 }
 
 void kvm_timer_sync_nested(struct kvm_vcpu *vcpu)
@@ -1034,12 +1079,15 @@ void kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu)
 	if (timer->enabled) {
 		for (int i = 0; i < nr_timers(vcpu); i++)
 			kvm_timer_update_irq(vcpu, false,
-					     vcpu_get_timer(vcpu, i));
+					vcpu_get_timer(vcpu, i));
 
 		if (irqchip_in_kernel(vcpu->kvm)) {
-			kvm_vgic_reset_mapped_irq(vcpu, timer_irq(map.direct_vtimer));
+			kvm_vgic_reset_mapped_irq(
+				vcpu, timer_irq(map.direct_vtimer));
 			if (map.direct_ptimer)
-				kvm_vgic_reset_mapped_irq(vcpu, timer_irq(map.direct_ptimer));
+				kvm_vgic_reset_mapped_irq(
+					vcpu,
+					timer_irq(map.direct_ptimer));
 		}
 	}
 
@@ -1092,10 +1140,19 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
 		      HRTIMER_MODE_ABS_HARD);
 }
 
+/*
+ * This is always called during kvm_arch_init_vm, but will also be
+ * called from kvm_vgic_create if we have a vGICv5.
+ */
 void kvm_timer_init_vm(struct kvm *kvm)
 {
+	/*
+	 * Set up the default PPIs - note that we adjust them based on
+	 * the model of the GIC as GICv5 uses a different way to
+	 * describing interrupts.
+	 */
 	for (int i = 0; i < NR_KVM_TIMERS; i++)
-		kvm->arch.timer_data.ppi[i] = default_ppi[i];
+		kvm->arch.timer_data.ppi[i] = get_vgic_ppi(kvm, default_ppi[i]);
 }
 
 void kvm_timer_cpu_up(void)
@@ -1347,6 +1404,7 @@ static int kvm_irq_init(struct arch_timer_kvm_info *info)
 		}
 
 		arch_timer_irq_ops.flags |= VGIC_IRQ_SW_RESAMPLE;
+		arch_timer_irq_ops_vgic_v5.flags |= VGIC_IRQ_SW_RESAMPLE;
 		WARN_ON(irq_domain_push_irq(domain, host_vtimer_irq,
 					    (void *)TIMER_VTIMER));
 	}
@@ -1497,10 +1555,13 @@ static bool timer_irqs_are_valid(struct kvm_vcpu *vcpu)
 			break;
 
 		/*
-		 * We know by construction that we only have PPIs, so
-		 * all values are less than 32.
+		 * We know by construction that we only have PPIs, so all values
+		 * are less than 32 for non-GICv5 vgics. On GICv5, they are
+		 * architecturally defined to be under 32 too. However, we mask
+		 * off most of the bits as we might be presented with a GICv5
+		 * style PPI where the type is encoded in the top-bits.
 		 */
-		ppis |= BIT(irq);
+		ppis |= BIT(irq & 0x1f);
 	}
 
 	valid = hweight32(ppis) == nr_timers(vcpu);
@@ -1538,7 +1599,9 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
 {
 	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
 	struct timer_map map;
+	struct irq_ops *ops;
 	int ret;
+	int irq;
 
 	if (timer->enabled)
 		return 0;
@@ -1556,20 +1619,22 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
 		return -EINVAL;
 	}
 
+	ops = vgic_is_v5(vcpu->kvm) ? &arch_timer_irq_ops_vgic_v5 :
+				      &arch_timer_irq_ops;
+
 	get_timer_map(vcpu, &map);
 
-	ret = kvm_vgic_map_phys_irq(vcpu,
-				    map.direct_vtimer->host_timer_irq,
-				    timer_irq(map.direct_vtimer),
-				    &arch_timer_irq_ops);
+	irq = timer_irq(map.direct_vtimer);
+	ret = kvm_vgic_map_phys_irq(vcpu, map.direct_vtimer->host_timer_irq,
+				    irq, ops);
 	if (ret)
 		return ret;
 
 	if (map.direct_ptimer) {
+		irq = timer_irq(map.direct_ptimer);
 		ret = kvm_vgic_map_phys_irq(vcpu,
 					    map.direct_ptimer->host_timer_irq,
-					    timer_irq(map.direct_ptimer),
-					    &arch_timer_irq_ops);
+					    irq, ops);
 	}
 
 	if (ret)
@@ -1627,6 +1692,15 @@ int kvm_arm_timer_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
 		goto out;
 	}
 
+	/*
+	 * The PPIs for the Arch Timers arch architecturally defined for
+	 * GICv5. Reject anything that changes them from the specified value.
+	 */
+	if (vgic_is_v5(vcpu->kvm) && vcpu->kvm->arch.timer_data.ppi[idx] != irq) {
+		ret = -EINVAL;
+		goto out;
+	}
+
 	/*
 	 * We cannot validate the IRQ unicity before we run, so take it at
 	 * face value. The verdict will be given on first vcpu run, for each
diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index 56cd5c05742df..cca0b5fb5a465 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -177,6 +177,15 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
 		pfr1 |= SYS_FIELD_PREP_ENUM(ID_PFR1_EL1, GIC, GICv3);
 	} else {
 		aa64pfr2 |= SYS_FIELD_PREP_ENUM(ID_AA64PFR2_EL1, GCIE, IMP);
+
+		/*
+		 * We now know that we have a GICv5. The Arch Timer PPI
+		 * interrupts may have been initialised at this stage, but will
+		 * have done so assuming that we have an older GIC, meaning that
+		 * the IntIDs won't be correct. We init them again, and this
+		 * time they will be correct.
+		 */
+		kvm_timer_init_vm(kvm);
 	}
 
 	kvm_set_vm_id_reg(kvm, SYS_ID_AA64PFR0_EL1, aa64pfr0);
diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index feba175a5047d..97d67c1d16541 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -197,8 +197,8 @@ int vgic_v5_finalize_ppi_state(struct kvm *kvm)
 	return 0;
 }
 
-static bool vgic_v5_ppi_set_pending_state(struct kvm_vcpu *vcpu,
-					  struct vgic_irq *irq)
+bool vgic_v5_ppi_set_pending_state(struct kvm_vcpu *vcpu,
+				   struct vgic_irq *irq)
 {
 	struct vgic_v5_cpu_if *cpu_if;
 	const u64 id_bit = BIT_ULL(irq->intid % 64);
@@ -227,8 +227,8 @@ static bool vgic_v5_ppi_set_pending_state(struct kvm_vcpu *vcpu,
  * save/restore, but don't need the PPIs to be queued on a per-VCPU AP
  * list. Therefore, sanity check the state, unlock, and return.
  */
-static bool vgic_v5_ppi_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq,
-					 unsigned long flags)
+bool vgic_v5_ppi_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq,
+				  unsigned long flags)
 	__releases(&irq->irq_lock)
 {
 	struct kvm_vcpu *vcpu;
diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index 7310841f45121..6cb9c20f9db65 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -10,6 +10,8 @@
 #include <linux/clocksource.h>
 #include <linux/hrtimer.h>
 
+#include <linux/irqchip/arm-gic-v5.h>
+
 enum kvm_arch_timers {
 	TIMER_PTIMER,
 	TIMER_VTIMER,
@@ -47,7 +49,7 @@ struct arch_timer_vm_data {
 	u64	poffset;
 
 	/* The PPI for each timer, global to the VM */
-	u8	ppi[NR_KVM_TIMERS];
+	u32	ppi[NR_KVM_TIMERS];
 };
 
 struct arch_timer_context {
@@ -130,6 +132,9 @@ void kvm_timer_init_vhe(void);
 #define timer_vm_data(ctx)		(&(timer_context_to_vcpu(ctx)->kvm->arch.timer_data))
 #define timer_irq(ctx)			(timer_vm_data(ctx)->ppi[arch_timer_ctx_index(ctx)])
 
+#define get_vgic_ppi(k, i) (((k)->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V5) ? \
+				(i) : ((i) | FIELD_PREP(GICV5_HWIRQ_TYPE, GICV5_HWIRQ_TYPE_PPI)))
+
 u64 kvm_arm_timer_read_sysreg(struct kvm_vcpu *vcpu,
 			      enum kvm_arch_timers tmr,
 			      enum kvm_arch_timer_regs treg);
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 696e2316f1ea9..22f979b561054 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -601,6 +601,10 @@ void vgic_v4_commit(struct kvm_vcpu *vcpu);
 int vgic_v4_put(struct kvm_vcpu *vcpu);
 
 int vgic_v5_finalize_ppi_state(struct kvm *kvm);
+bool vgic_v5_ppi_set_pending_state(struct kvm_vcpu *vcpu,
+				   struct vgic_irq *irq);
+bool vgic_v5_ppi_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq,
+				  unsigned long flags);
 
 bool vgic_state_is_nested(struct kvm_vcpu *vcpu);
 
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:37 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:37 +0000
Subject: [PATCH v2 04/36] arm64/sysreg: Add remaining GICv5 ICC_ & ICH_
 sysregs for KVM support
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-5-sascha.bischoff@arm.com>

Add the GICv5 system registers required to support native GICv5 guests
with KVM. Many of the GICv5 sysregs have already been added as part of
the host GICv5 driver, keeping this set relatively small. The
registers added in this change complete the set by adding those
required by KVM either directly (ICH_) or indirectly (FGTs for the
ICC_ sysregs).

The following system registers and their fields are added:

	ICC_APR_EL1
	ICC_HPPIR_EL1
	ICC_IAFFIDR_EL1
	ICH_APR_EL2
	ICH_CONTEXTR_EL2
	ICH_PPI_ACTIVER<n>_EL2
	ICH_PPI_DVI<n>_EL2
	ICH_PPI_ENABLER<n>_EL2
	ICH_PPI_PENDR<n>_EL2
	ICH_PPI_PRIORITYR<n>_EL2

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/tools/sysreg | 480 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 480 insertions(+)

diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
index dab5bfe8c9686..2f44a568ebf4e 100644
--- a/arch/arm64/tools/sysreg
+++ b/arch/arm64/tools/sysreg
@@ -3248,6 +3248,14 @@ UnsignedEnum	3:0	ID_BITS
 EndEnum
 EndSysreg
 
+Sysreg	ICC_HPPIR_EL1	3	0	12	10	3
+Res0	63:33
+Field	32	HPPIV
+Field	31:29	TYPE
+Res0	28:24
+Field	23:0	ID
+EndSysreg
+
 Sysreg	ICC_ICSR_EL1	3	0	12	10	4
 Res0	63:48
 Field	47:32	IAFFID
@@ -3262,6 +3270,11 @@ Field	1	Enabled
 Field	0	F
 EndSysreg
 
+Sysreg	ICC_IAFFIDR_EL1	3	0	12	10	5
+Res0	63:16
+Field	15:0	IAFFID
+EndSysreg
+
 SysregFields	ICC_PPI_ENABLERx_EL1
 Field	63	EN63
 Field	62	EN62
@@ -3668,6 +3681,42 @@ Res0	14:12
 Field	11:0	AFFINITY
 EndSysreg
 
+Sysreg	ICC_APR_EL1	3	1	12	0	0
+Res0	63:32
+Field	31	P31
+Field	30	P30
+Field	29	P29
+Field	28	P28
+Field	27	P27
+Field	26	P26
+Field	25	P25
+Field	24	P24
+Field	23	P23
+Field	22	P22
+Field	21	P21
+Field	20	P20
+Field	19	P19
+Field	18	P18
+Field	17	P17
+Field	16	P16
+Field	15	P15
+Field	14	P14
+Field	13	P13
+Field	12	P12
+Field	11	P11
+Field	10	P10
+Field	9	P9
+Field	8	P8
+Field	7	P7
+Field	6	P6
+Field	5	P5
+Field	4	P4
+Field	3	P3
+Field	2	P2
+Field	1	P1
+Field	0	P0
+EndSysreg
+
 Sysreg	ICC_CR0_EL1	3	1	12	0	1
 Res0	63:39
 Field	38	PID
@@ -4567,6 +4616,42 @@ Field	31:16	PhyPARTID29
 Field	15:0	PhyPARTID28
 EndSysreg
 
+Sysreg	ICH_APR_EL2	3	4	12	8	4
+Res0	63:32
+Field	31	P31
+Field	30	P30
+Field	29	P29
+Field	28	P28
+Field	27	P27
+Field	26	P26
+Field	25	P25
+Field	24	P24
+Field	23	P23
+Field	22	P22
+Field	21	P21
+Field	20	P20
+Field	19	P19
+Field	18	P18
+Field	17	P17
+Field	16	P16
+Field	15	P15
+Field	14	P14
+Field	13	P13
+Field	12	P12
+Field	11	P11
+Field	10	P10
+Field	9	P9
+Field	8	P8
+Field	7	P7
+Field	6	P6
+Field	5	P5
+Field	4	P4
+Field	3	P3
+Field	2	P2
+Field	1	P1
+Field	0	P0
+EndSysreg
+
 Sysreg	ICH_HFGRTR_EL2	3	4	12	9	4
 Res0	63:21
 Field	20	ICC_PPI_ACTIVERn_EL1
@@ -4615,6 +4700,306 @@ Field	1	GICCDDIS
 Field	0	GICCDEN
 EndSysreg
 
+SysregFields	ICH_PPI_DVIRx_EL2
+Field	63	DVI63
+Field	62	DVI62
+Field	61	DVI61
+Field	60	DVI60
+Field	59	DVI59
+Field	58	DVI58
+Field	57	DVI57
+Field	56	DVI56
+Field	55	DVI55
+Field	54	DVI54
+Field	53	DVI53
+Field	52	DVI52
+Field	51	DVI51
+Field	50	DVI50
+Field	49	DVI49
+Field	48	DVI48
+Field	47	DVI47
+Field	46	DVI46
+Field	45	DVI45
+Field	44	DVI44
+Field	43	DVI43
+Field	42	DVI42
+Field	41	DVI41
+Field	40	DVI40
+Field	39	DVI39
+Field	38	DVI38
+Field	37	DVI37
+Field	36	DVI36
+Field	35	DVI35
+Field	34	DVI34
+Field	33	DVI33
+Field	32	DVI32
+Field	31	DVI31
+Field	30	DVI30
+Field	29	DVI29
+Field	28	DVI28
+Field	27	DVI27
+Field	26	DVI26
+Field	25	DVI25
+Field	24	DVI24
+Field	23	DVI23
+Field	22	DVI22
+Field	21	DVI21
+Field	20	DVI20
+Field	19	DVI19
+Field	18	DVI18
+Field	17	DVI17
+Field	16	DVI16
+Field	15	DVI15
+Field	14	DVI14
+Field	13	DVI13
+Field	12	DVI12
+Field	11	DVI11
+Field	10	DVI10
+Field	9	DVI9
+Field	8	DVI8
+Field	7	DVI7
+Field	6	DVI6
+Field	5	DVI5
+Field	4	DVI4
+Field	3	DVI3
+Field	2	DVI2
+Field	1	DVI1
+Field	0	DVI0
+EndSysregFields
+
+Sysreg	ICH_PPI_DVIR0_EL2	3	4	12	10	0
+Fields ICH_PPI_DVIx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_DVIR1_EL2	3	4	12	10	1
+Fields ICH_PPI_DVIx_EL2
+EndSysreg
+
+SysregFields	ICH_PPI_ENABLERx_EL2
+Field	63	EN63
+Field	62	EN62
+Field	61	EN61
+Field	60	EN60
+Field	59	EN59
+Field	58	EN58
+Field	57	EN57
+Field	56	EN56
+Field	55	EN55
+Field	54	EN54
+Field	53	EN53
+Field	52	EN52
+Field	51	EN51
+Field	50	EN50
+Field	49	EN49
+Field	48	EN48
+Field	47	EN47
+Field	46	EN46
+Field	45	EN45
+Field	44	EN44
+Field	43	EN43
+Field	42	EN42
+Field	41	EN41
+Field	40	EN40
+Field	39	EN39
+Field	38	EN38
+Field	37	EN37
+Field	36	EN36
+Field	35	EN35
+Field	34	EN34
+Field	33	EN33
+Field	32	EN32
+Field	31	EN31
+Field	30	EN30
+Field	29	EN29
+Field	28	EN28
+Field	27	EN27
+Field	26	EN26
+Field	25	EN25
+Field	24	EN24
+Field	23	EN23
+Field	22	EN22
+Field	21	EN21
+Field	20	EN20
+Field	19	EN19
+Field	18	EN18
+Field	17	EN17
+Field	16	EN16
+Field	15	EN15
+Field	14	EN14
+Field	13	EN13
+Field	12	EN12
+Field	11	EN11
+Field	10	EN10
+Field	9	EN9
+Field	8	EN8
+Field	7	EN7
+Field	6	EN6
+Field	5	EN5
+Field	4	EN4
+Field	3	EN3
+Field	2	EN2
+Field	1	EN1
+Field	0	EN0
+EndSysregFields
+
+Sysreg	ICH_PPI_ENABLER0_EL2	3	4	12	10	2
+Fields ICH_PPI_ENABLERx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_ENABLER1_EL2	3	4	12	10	3
+Fields ICH_PPI_ENABLERx_EL2
+EndSysreg
+
+SysregFields	ICH_PPI_PENDRx_EL2
+Field	63	PEND63
+Field	62	PEND62
+Field	61	PEND61
+Field	60	PEND60
+Field	59	PEND59
+Field	58	PEND58
+Field	57	PEND57
+Field	56	PEND56
+Field	55	PEND55
+Field	54	PEND54
+Field	53	PEND53
+Field	52	PEND52
+Field	51	PEND51
+Field	50	PEND50
+Field	49	PEND49
+Field	48	PEND48
+Field	47	PEND47
+Field	46	PEND46
+Field	45	PEND45
+Field	44	PEND44
+Field	43	PEND43
+Field	42	PEND42
+Field	41	PEND41
+Field	40	PEND40
+Field	39	PEND39
+Field	38	PEND38
+Field	37	PEND37
+Field	36	PEND36
+Field	35	PEND35
+Field	34	PEND34
+Field	33	PEND33
+Field	32	PEND32
+Field	31	PEND31
+Field	30	PEND30
+Field	29	PEND29
+Field	28	PEND28
+Field	27	PEND27
+Field	26	PEND26
+Field	25	PEND25
+Field	24	PEND24
+Field	23	PEND23
+Field	22	PEND22
+Field	21	PEND21
+Field	20	PEND20
+Field	19	PEND19
+Field	18	PEND18
+Field	17	PEND17
+Field	16	PEND16
+Field	15	PEND15
+Field	14	PEND14
+Field	13	PEND13
+Field	12	PEND12
+Field	11	PEND11
+Field	10	PEND10
+Field	9	PEND9
+Field	8	PEND8
+Field	7	PEND7
+Field	6	PEND6
+Field	5	PEND5
+Field	4	PEND4
+Field	3	PEND3
+Field	2	PEND2
+Field	1	PEND1
+Field	0	PEND0
+EndSysregFields
+
+Sysreg	ICH_PPI_PENDR0_EL2	3	4	12	10	4
+Fields ICH_PPI_PENDRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PENDR1_EL2	3	4	12	10	5
+Fields ICH_PPI_PENDRx_EL2
+EndSysreg
+
+SysregFields	ICH_PPI_ACTIVERx_EL2
+Field	63	ACTIVE63
+Field	62	ACTIVE62
+Field	61	ACTIVE61
+Field	60	ACTIVE60
+Field	59	ACTIVE59
+Field	58	ACTIVE58
+Field	57	ACTIVE57
+Field	56	ACTIVE56
+Field	55	ACTIVE55
+Field	54	ACTIVE54
+Field	53	ACTIVE53
+Field	52	ACTIVE52
+Field	51	ACTIVE51
+Field	50	ACTIVE50
+Field	49	ACTIVE49
+Field	48	ACTIVE48
+Field	47	ACTIVE47
+Field	46	ACTIVE46
+Field	45	ACTIVE45
+Field	44	ACTIVE44
+Field	43	ACTIVE43
+Field	42	ACTIVE42
+Field	41	ACTIVE41
+Field	40	ACTIVE40
+Field	39	ACTIVE39
+Field	38	ACTIVE38
+Field	37	ACTIVE37
+Field	36	ACTIVE36
+Field	35	ACTIVE35
+Field	34	ACTIVE34
+Field	33	ACTIVE33
+Field	32	ACTIVE32
+Field	31	ACTIVE31
+Field	30	ACTIVE30
+Field	29	ACTIVE29
+Field	28	ACTIVE28
+Field	27	ACTIVE27
+Field	26	ACTIVE26
+Field	25	ACTIVE25
+Field	24	ACTIVE24
+Field	23	ACTIVE23
+Field	22	ACTIVE22
+Field	21	ACTIVE21
+Field	20	ACTIVE20
+Field	19	ACTIVE19
+Field	18	ACTIVE18
+Field	17	ACTIVE17
+Field	16	ACTIVE16
+Field	15	ACTIVE15
+Field	14	ACTIVE14
+Field	13	ACTIVE13
+Field	12	ACTIVE12
+Field	11	ACTIVE11
+Field	10	ACTIVE10
+Field	9	ACTIVE9
+Field	8	ACTIVE8
+Field	7	ACTIVE7
+Field	6	ACTIVE6
+Field	5	ACTIVE5
+Field	4	ACTIVE4
+Field	3	ACTIVE3
+Field	2	ACTIVE2
+Field	1	ACTIVE1
+Field	0	ACTIVE0
+EndSysregFields
+
+Sysreg	ICH_PPI_ACTIVER0_EL2	3	4	12	10	6
+Fields ICH_PPI_ACTIVERx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_ACTIVER1_EL2	3	4	12	10	7
+Fields ICH_PPI_ACTIVERx_EL2
+EndSysreg
+
 Sysreg	ICH_HCR_EL2	3	4	12	11	0
 Res0	63:32
 Field	31:27	EOIcount
@@ -4669,6 +5054,18 @@ Field	1	V3
 Field	0	En
 EndSysreg
 
+Sysreg	ICH_CONTEXTR_EL2	3	4	12	11	6
+Field	63	V
+Field	62	F
+Field	61	IRICHPPIDIS
+Field	60	DB
+Field	59:55	DBPM
+Res0	54:48
+Field	47:32	VPE
+Res0	31:16
+Field	15:0	VM
+EndSysreg
+
 Sysreg	ICH_VMCR_EL2	3	4	12	11	7
 Prefix	FEAT_GCIE
 Res0	63:32
@@ -4690,6 +5087,89 @@ Field	1	VENG1
 Field	0	VENG0
 EndSysreg
 
+SysregFields	ICH_PPI_PRIORITYRx_EL2
+Res0	63:61
+Field	60:56	Priority7
+Res0	55:53
+Field	52:48	Priority6
+Res0	47:45
+Field	44:40	Priority5
+Res0	39:37
+Field	36:32	Priority4
+Res0	31:29
+Field	28:24	Priority3
+Res0	23:21
+Field	20:16	Priority2
+Res0	15:13
+Field	12:8	Priority1
+Res0	7:5
+Field	4:0	Priority0
+EndSysregFields
+
+Sysreg	ICH_PPI_PRIORITYR0_EL2	3	4	12	14	0
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR1_EL2	3	4	12	14	1
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR2_EL2	3	4	12	14	2
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR3_EL2	3	4	12	14	3
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR4_EL2	3	4	12	14	4
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR5_EL2	3	4	12	14	5
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR6_EL2	3	4	12	14	6
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR7_EL2	3	4	12	14	7
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR8_EL2	3	4	12	15	0
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR9_EL2	3	4	12	15	1
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR10_EL2	3	4	12	15	2
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR11_EL2	3	4	12	15	3
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR12_EL2	3	4	12	15	4
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR13_EL2	3	4	12	15	5
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR14_EL2	3	4	12	15	6
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
+Sysreg	ICH_PPI_PRIORITYR15_EL2	3	4	12	15	7
+Fields	ICH_PPI_PRIORITYRx_EL2
+EndSysreg
+
 Sysreg	CONTEXTIDR_EL2	3	4	13	0	1
 Fields	CONTEXTIDR_ELx
 EndSysreg
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:46 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:46 +0000
Subject: [PATCH v2 30/36] KVM: arm64: gic-v5: Introduce kvm_arm_vgic_v5_ops
 and register them
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-31-sascha.bischoff@arm.com>

Only the KVM_DEV_ARM_VGIC_GRP_CTRL->KVM_DEV_ARM_VGIC_CTRL_INIT op is
currently supported. All other ops are stubbed out.

Co-authored-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/vgic/vgic-kvm-device.c | 72 +++++++++++++++++++++++++++
 include/linux/kvm_host.h              |  1 +
 2 files changed, 73 insertions(+)

diff --git a/arch/arm64/kvm/vgic/vgic-kvm-device.c b/arch/arm64/kvm/vgic/vgic-kvm-device.c
index b12ba99a423e5..78903182bba08 100644
--- a/arch/arm64/kvm/vgic/vgic-kvm-device.c
+++ b/arch/arm64/kvm/vgic/vgic-kvm-device.c
@@ -336,6 +336,9 @@ int kvm_register_vgic_device(unsigned long type)
 			break;
 		ret = kvm_vgic_register_its_device();
 		break;
+	case KVM_DEV_TYPE_ARM_VGIC_V5:
+		ret = kvm_register_device_ops(&kvm_arm_vgic_v5_ops,
+					      KVM_DEV_TYPE_ARM_VGIC_V5);
 	}
 
 	return ret;
@@ -715,3 +718,72 @@ struct kvm_device_ops kvm_arm_vgic_v3_ops = {
 	.get_attr = vgic_v3_get_attr,
 	.has_attr = vgic_v3_has_attr,
 };
+
+static int vgic_v5_set_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_ADDR:
+	case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS:
+	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
+		break;
+	case KVM_DEV_ARM_VGIC_GRP_CTRL:
+		switch (attr->attr) {
+		case KVM_DEV_ARM_VGIC_CTRL_INIT:
+			return  vgic_set_common_attr(dev, attr);
+		default:
+			break;
+		}
+	}
+
+	return -ENXIO;
+}
+
+static int vgic_v5_get_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_ADDR:
+	case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS:
+	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
+		break;
+	case KVM_DEV_ARM_VGIC_GRP_CTRL:
+		switch (attr->attr) {
+		case KVM_DEV_ARM_VGIC_CTRL_INIT:
+			return vgic_get_common_attr(dev, attr);
+		default:
+			break;
+		}
+	}
+
+	return -ENXIO;
+}
+
+static int vgic_v5_has_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_ADDR:
+	case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS:
+	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
+		break;
+	case KVM_DEV_ARM_VGIC_GRP_CTRL:
+		switch (attr->attr) {
+		case KVM_DEV_ARM_VGIC_CTRL_INIT:
+			return 0;
+		default:
+			break;
+		}
+	}
+
+	return -ENXIO;
+}
+
+struct kvm_device_ops kvm_arm_vgic_v5_ops = {
+	.name = "kvm-arm-vgic-v5",
+	.create = vgic_create,
+	.destroy = vgic_destroy,
+	.set_attr = vgic_v5_set_attr,
+	.get_attr = vgic_v5_get_attr,
+	.has_attr = vgic_v5_has_attr,
+};
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index d93f75b05ae22..d6082f06ccae3 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -2368,6 +2368,7 @@ void kvm_unregister_device_ops(u32 type);
 extern struct kvm_device_ops kvm_mpic_ops;
 extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
 extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
+extern struct kvm_device_ops kvm_arm_vgic_v5_ops;
 
 #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
 
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:47 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:47 +0000
Subject: [PATCH v2 32/36] irqchip/gic-v5: Check if impl is virt capable
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-33-sascha.bischoff@arm.com>

Now that there is support for creating a GICv5-based guest with KVM,
check that the hardware itself supports virtualisation, skipping the
setting of struct gic_kvm_info if not.

Note: If native GICv5 virt is not supported, then nor is
FEAT_GCIE_LEGACY, so we are able to skip altogether.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
Reviewed-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
---
 drivers/irqchip/irq-gic-v5-irs.c   |  4 ++++
 drivers/irqchip/irq-gic-v5.c       | 10 ++++++++++
 include/linux/irqchip/arm-gic-v5.h |  4 ++++
 3 files changed, 18 insertions(+)

diff --git a/drivers/irqchip/irq-gic-v5-irs.c b/drivers/irqchip/irq-gic-v5-irs.c
index ce2732d649a3e..eebf9f219ac8c 100644
--- a/drivers/irqchip/irq-gic-v5-irs.c
+++ b/drivers/irqchip/irq-gic-v5-irs.c
@@ -744,6 +744,10 @@ static int __init gicv5_irs_init(struct device_node *node)
 	 */
 	if (list_empty(&irs_nodes)) {
 
+		idr = irs_readl_relaxed(irs_data, GICV5_IRS_IDR0);
+		gicv5_global_data.virt_capable =
+			!!FIELD_GET(GICV5_IRS_IDR0_VIRT, idr);
+
 		idr = irs_readl_relaxed(irs_data, GICV5_IRS_IDR1);
 		irs_setup_pri_bits(idr);
 
diff --git a/drivers/irqchip/irq-gic-v5.c b/drivers/irqchip/irq-gic-v5.c
index 41ef286c4d781..3c86bbc057615 100644
--- a/drivers/irqchip/irq-gic-v5.c
+++ b/drivers/irqchip/irq-gic-v5.c
@@ -1064,6 +1064,16 @@ static struct gic_kvm_info gic_v5_kvm_info __initdata;
 
 static void __init gic_of_setup_kvm_info(struct device_node *node)
 {
+	/*
+	 * If we don't have native GICv5 virtualisation support, then
+	 * we also don't have FEAT_GCIE_LEGACY - the architecture
+	 * forbids this combination.
+	 */
+	if (!gicv5_global_data.virt_capable) {
+		pr_info("GIC implementation is not virtualization capable\n");
+		return;
+	}
+
 	gic_v5_kvm_info.type = GIC_V5;
 
 	/* GIC Virtual CPU interface maintenance interrupt */
diff --git a/include/linux/irqchip/arm-gic-v5.h b/include/linux/irqchip/arm-gic-v5.h
index 2ab7ec718aaea..06ebb2a1cfb1d 100644
--- a/include/linux/irqchip/arm-gic-v5.h
+++ b/include/linux/irqchip/arm-gic-v5.h
@@ -45,6 +45,7 @@
 /*
  * IRS registers and tables structures
  */
+#define GICV5_IRS_IDR0			0x0000
 #define GICV5_IRS_IDR1			0x0004
 #define GICV5_IRS_IDR2			0x0008
 #define GICV5_IRS_IDR5			0x0014
@@ -65,6 +66,8 @@
 #define GICV5_IRS_IST_STATUSR		0x0194
 #define GICV5_IRS_MAP_L2_ISTR		0x01c0
 
+#define GICV5_IRS_IDR0_VIRT		BIT(6)
+
 #define GICV5_IRS_IDR1_PRIORITY_BITS	GENMASK(22, 20)
 #define GICV5_IRS_IDR1_IAFFID_BITS	GENMASK(19, 16)
 
@@ -280,6 +283,7 @@ struct gicv5_chip_data {
 	u8			cpuif_pri_bits;
 	u8			cpuif_id_bits;
 	u8			irs_pri_bits;
+	bool			virt_capable;
 	struct {
 		__le64 *l1ist_addr;
 		u32 l2_size;
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:48 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:48 +0000
Subject: [PATCH v2 35/36] KVM: arm64: selftests: Introduce a minimal GICv5 PPI
 selftest
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-36-sascha.bischoff@arm.com>

This basic selftest creates a vgic_v5 device (if supported), and tests
that one of the PPI interrupts works as expected with a basic
single-vCPU guest.

Upon starting, the guest enables interrupts. That means that it is
initialising all PPIs to have reasonable priorities, but marking them
as disabled. Then the priority mask in the ICC_PCR_EL1 is set, and
interrupts are enable in ICC_CR0_EL1. At this stage the guest is able
to recieve interrupts. The first IMPDEF PPI (64) is enabled and
kvm_irq_line is used to inject the state into the guest.

The guest's interrupt handler has an explicit WFI in order to ensure
that the guest skips WFI when there are pending and enabled PPI
interrupts.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 tools/testing/selftests/kvm/Makefile.kvm      |   1 +
 tools/testing/selftests/kvm/arm64/vgic_v5.c   | 248 ++++++++++++++++++
 .../selftests/kvm/include/arm64/gic_v5.h      | 148 +++++++++++
 3 files changed, 397 insertions(+)
 create mode 100644 tools/testing/selftests/kvm/arm64/vgic_v5.c
 create mode 100644 tools/testing/selftests/kvm/include/arm64/gic_v5.h

diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index ba5c2b643efaa..5c325b8a0766d 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -173,6 +173,7 @@ TEST_GEN_PROGS_arm64 += arm64/vcpu_width_config
 TEST_GEN_PROGS_arm64 += arm64/vgic_init
 TEST_GEN_PROGS_arm64 += arm64/vgic_irq
 TEST_GEN_PROGS_arm64 += arm64/vgic_lpi_stress
+TEST_GEN_PROGS_arm64 += arm64/vgic_v5
 TEST_GEN_PROGS_arm64 += arm64/vpmu_counter_access
 TEST_GEN_PROGS_arm64 += arm64/no-vgic-v3
 TEST_GEN_PROGS_arm64 += arm64/kvm-uuid
diff --git a/tools/testing/selftests/kvm/arm64/vgic_v5.c b/tools/testing/selftests/kvm/arm64/vgic_v5.c
new file mode 100644
index 0000000000000..5879fbd71042d
--- /dev/null
+++ b/tools/testing/selftests/kvm/arm64/vgic_v5.c
@@ -0,0 +1,248 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/kernel.h>
+#include <sys/syscall.h>
+#include <asm/kvm.h>
+#include <asm/kvm_para.h>
+
+#include <arm64/gic_v5.h>
+
+#include "test_util.h"
+#include "kvm_util.h"
+#include "processor.h"
+#include "vgic.h"
+
+#define NR_VCPUS		1
+
+struct vm_gic {
+	struct kvm_vm *vm;
+	int gic_fd;
+	uint32_t gic_dev_type;
+};
+
+static uint64_t max_phys_size;
+
+#define GUEST_CMD_IRQ_CDIA	10
+#define GUEST_CMD_IRQ_DIEOI	11
+#define GUEST_CMD_IS_AWAKE	12
+#define GUEST_CMD_IS_READY	13
+
+static void guest_irq_handler(struct ex_regs *regs)
+{
+	bool valid;
+	u32 hwirq;
+	u64 ia;
+	static int count;
+
+	/*
+	 * We have pending interrupts. Should never actually enter WFI
+	 * here!
+	 */
+	wfi();
+	GUEST_SYNC(GUEST_CMD_IS_AWAKE);
+
+	ia = gicr_insn(CDIA);
+	valid = GICV5_GICR_CDIA_VALID(ia);
+
+	GUEST_SYNC(GUEST_CMD_IRQ_CDIA);
+
+	if (!valid)
+		return;
+
+	gsb_ack();
+	isb();
+
+	hwirq = FIELD_GET(GICV5_GIC_CDIA_INTID, ia);
+
+	gic_insn(hwirq, CDDI);
+	gic_insn(0, CDEOI);
+
+	++count;
+	GUEST_SYNC(GUEST_CMD_IRQ_DIEOI);
+
+	if (count >= 2)
+		GUEST_DONE();
+
+	/* Ask for the next interrupt to be injected */
+	GUEST_SYNC(GUEST_CMD_IS_READY);
+}
+
+static void guest_code(void)
+{
+	local_irq_disable();
+
+	gicv5_cpu_enable_interrupts();
+	local_irq_enable();
+
+	/* Enable PPI 64 */
+	write_sysreg_s(1UL, SYS_ICC_PPI_ENABLER1_EL1);
+
+	/* Ask for the first interrupt to be injected */
+	GUEST_SYNC(GUEST_CMD_IS_READY);
+
+	/* Loop forever waiting for interrupts */
+	while (1);
+}
+
+
+/* we don't want to assert on run execution, hence that helper */
+static int run_vcpu(struct kvm_vcpu *vcpu)
+{
+	return __vcpu_run(vcpu) ? -errno : 0;
+}
+
+static void vm_gic_destroy(struct vm_gic *v)
+{
+	close(v->gic_fd);
+	kvm_vm_free(v->vm);
+}
+
+static void test_vgic_v5_ppis(uint32_t gic_dev_type)
+{
+	struct ucall uc;
+	struct kvm_vcpu *vcpus[NR_VCPUS];
+	struct vm_gic v;
+	int ret, i;
+
+	v.gic_dev_type = gic_dev_type;
+	v.vm = __vm_create(VM_SHAPE_DEFAULT, NR_VCPUS, 0);
+
+	v.gic_fd = kvm_create_device(v.vm, gic_dev_type);
+
+	for (i = 0; i < NR_VCPUS; ++i)
+		vcpus[i] = vm_vcpu_add(v.vm, i, guest_code);
+
+	vm_init_descriptor_tables(v.vm);
+	vm_install_exception_handler(v.vm, VECTOR_IRQ_CURRENT, guest_irq_handler);
+
+	for (i = 0; i < NR_VCPUS; i++)
+		vcpu_init_descriptor_tables(vcpus[i]);
+
+	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
+			    KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
+
+	while (1) {
+		ret = run_vcpu(vcpus[0]);
+
+		switch (get_ucall(vcpus[0], &uc)) {
+		case UCALL_SYNC:
+			/*
+			 * The guest is ready for the next level
+			 * change. Set high if ready, and lower if it
+			 * has been consumed.
+			 */
+			if (uc.args[1] == GUEST_CMD_IS_READY ||
+			    uc.args[1] == GUEST_CMD_IRQ_DIEOI) {
+				u64 irq = 64;
+				bool level = uc.args[1] == GUEST_CMD_IRQ_DIEOI ? 0 : 1;
+
+				irq &= KVM_ARM_IRQ_NUM_MASK;
+				irq |= KVM_ARM_IRQ_TYPE_PPI << KVM_ARM_IRQ_TYPE_SHIFT;
+
+				_kvm_irq_line(v.vm, irq, level);
+			} else if (uc.args[1] == GUEST_CMD_IS_AWAKE) {
+				pr_info("Guest skipping WFI due to pending IRQ\n");
+			} else if (uc.args[1] == GUEST_CMD_IRQ_CDIA) {
+				pr_info("Guest acknowledged IRQ\n");
+			}
+
+			continue;
+		case UCALL_ABORT:
+			REPORT_GUEST_ASSERT(uc);
+			break;
+		case UCALL_DONE:
+			goto done;
+		default:
+			TEST_FAIL("Unknown ucall %lu", uc.cmd);
+		}
+	}
+
+done:
+	TEST_ASSERT(ret == 0, "Failed to test GICv5 PPIs");
+
+	vm_gic_destroy(&v);
+}
+
+/*
+ * Returns 0 if it's possible to create GIC device of a given type (V2 or V3).
+ */
+int test_kvm_device(uint32_t gic_dev_type)
+{
+	struct kvm_vcpu *vcpus[NR_VCPUS];
+	struct vm_gic v;
+	uint32_t other;
+	int ret;
+
+	v.vm = vm_create_with_vcpus(NR_VCPUS, guest_code, vcpus);
+
+	/* try to create a non existing KVM device */
+	ret = __kvm_test_create_device(v.vm, 0);
+	TEST_ASSERT(ret && errno == ENODEV, "unsupported device");
+
+	/* trial mode */
+	ret = __kvm_test_create_device(v.vm, gic_dev_type);
+	if (ret)
+		return ret;
+	v.gic_fd = kvm_create_device(v.vm, gic_dev_type);
+
+	ret = __kvm_create_device(v.vm, gic_dev_type);
+	TEST_ASSERT(ret < 0 && errno == EEXIST, "create GIC device twice");
+
+	/* try to create the other gic_dev_types */
+	other = KVM_DEV_TYPE_ARM_VGIC_V2;
+	if (!__kvm_test_create_device(v.vm, other)) {
+		ret = __kvm_create_device(v.vm, other);
+		TEST_ASSERT(ret < 0 && (errno == EINVAL || errno == EEXIST),
+				"create GIC device while other version exists");
+	}
+
+	other = KVM_DEV_TYPE_ARM_VGIC_V3;
+	if (!__kvm_test_create_device(v.vm, other)) {
+		ret = __kvm_create_device(v.vm, other);
+		TEST_ASSERT(ret < 0 && (errno == EINVAL || errno == EEXIST),
+				"create GIC device while other version exists");
+	}
+
+	other = KVM_DEV_TYPE_ARM_VGIC_V5;
+	if (!__kvm_test_create_device(v.vm, other)) {
+		ret = __kvm_create_device(v.vm, other);
+		TEST_ASSERT(ret < 0 && (errno == EINVAL || errno == EEXIST),
+				"create GIC device while other version exists");
+	}
+
+	vm_gic_destroy(&v);
+
+	return 0;
+}
+
+void run_tests(uint32_t gic_dev_type)
+{
+	pr_info("Test VGICv5 PPIs\n");
+	test_vgic_v5_ppis(gic_dev_type);
+}
+
+int main(int ac, char **av)
+{
+	int ret;
+	int pa_bits;
+	int cnt_impl = 0;
+
+	test_disable_default_vgic();
+
+	pa_bits = vm_guest_mode_params[VM_MODE_DEFAULT].pa_bits;
+	max_phys_size = 1ULL << pa_bits;
+
+	ret = test_kvm_device(KVM_DEV_TYPE_ARM_VGIC_V5);
+	if (!ret) {
+		pr_info("Running VGIC_V5 tests.\n");
+		run_tests(KVM_DEV_TYPE_ARM_VGIC_V5);
+		cnt_impl++;
+	} else {
+		pr_info("No GICv5 support; Not running GIC_v5 tests.\n");
+		exit(KSFT_SKIP);
+	}
+
+	return 0;
+}
+
+
diff --git a/tools/testing/selftests/kvm/include/arm64/gic_v5.h b/tools/testing/selftests/kvm/include/arm64/gic_v5.h
new file mode 100644
index 0000000000000..5daaa84318bb1
--- /dev/null
+++ b/tools/testing/selftests/kvm/include/arm64/gic_v5.h
@@ -0,0 +1,148 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SELFTESTS_GIC_V5_H
+#define __SELFTESTS_GIC_V5_H
+
+#include <asm/barrier.h>
+#include <asm/sysreg.h>
+
+#include <linux/bitfield.h>
+
+#include "processor.h"
+
+/*
+ * Definitions for GICv5 instructions for the Current Domain
+ */
+#define GICV5_OP_GIC_CDAFF		sys_insn(1, 0, 12, 1, 3)
+#define GICV5_OP_GIC_CDDI		sys_insn(1, 0, 12, 2, 0)
+#define GICV5_OP_GIC_CDDIS		sys_insn(1, 0, 12, 1, 0)
+#define GICV5_OP_GIC_CDHM		sys_insn(1, 0, 12, 2, 1)
+#define GICV5_OP_GIC_CDEN		sys_insn(1, 0, 12, 1, 1)
+#define GICV5_OP_GIC_CDEOI		sys_insn(1, 0, 12, 1, 7)
+#define GICV5_OP_GIC_CDPEND		sys_insn(1, 0, 12, 1, 4)
+#define GICV5_OP_GIC_CDPRI		sys_insn(1, 0, 12, 1, 2)
+#define GICV5_OP_GIC_CDRCFG		sys_insn(1, 0, 12, 1, 5)
+#define GICV5_OP_GICR_CDIA		sys_insn(1, 0, 12, 3, 0)
+#define GICV5_OP_GICR_CDNMIA		sys_insn(1, 0, 12, 3, 1)
+
+/* Definitions for GIC CDAFF */
+#define GICV5_GIC_CDAFF_IAFFID_MASK	GENMASK_ULL(47, 32)
+#define GICV5_GIC_CDAFF_TYPE_MASK	GENMASK_ULL(31, 29)
+#define GICV5_GIC_CDAFF_IRM_MASK	BIT_ULL(28)
+#define GICV5_GIC_CDAFF_ID_MASK		GENMASK_ULL(23, 0)
+
+/* Definitions for GIC CDDI */
+#define GICV5_GIC_CDDI_TYPE_MASK	GENMASK_ULL(31, 29)
+#define GICV5_GIC_CDDI_ID_MASK		GENMASK_ULL(23, 0)
+
+/* Definitions for GIC CDDIS */
+#define GICV5_GIC_CDDIS_TYPE_MASK	GENMASK_ULL(31, 29)
+#define GICV5_GIC_CDDIS_TYPE(r)		FIELD_GET(GICV5_GIC_CDDIS_TYPE_MASK, r)
+#define GICV5_GIC_CDDIS_ID_MASK		GENMASK_ULL(23, 0)
+#define GICV5_GIC_CDDIS_ID(r)		FIELD_GET(GICV5_GIC_CDDIS_ID_MASK, r)
+
+/* Definitions for GIC CDEN */
+#define GICV5_GIC_CDEN_TYPE_MASK	GENMASK_ULL(31, 29)
+#define GICV5_GIC_CDEN_ID_MASK		GENMASK_ULL(23, 0)
+
+/* Definitions for GIC CDHM */
+#define GICV5_GIC_CDHM_HM_MASK		BIT_ULL(32)
+#define GICV5_GIC_CDHM_TYPE_MASK	GENMASK_ULL(31, 29)
+#define GICV5_GIC_CDHM_ID_MASK		GENMASK_ULL(23, 0)
+
+/* Definitions for GIC CDPEND */
+#define GICV5_GIC_CDPEND_PENDING_MASK	BIT_ULL(32)
+#define GICV5_GIC_CDPEND_TYPE_MASK	GENMASK_ULL(31, 29)
+#define GICV5_GIC_CDPEND_ID_MASK	GENMASK_ULL(23, 0)
+
+/* Definitions for GIC CDPRI */
+#define GICV5_GIC_CDPRI_PRIORITY_MASK	GENMASK_ULL(39, 35)
+#define GICV5_GIC_CDPRI_TYPE_MASK	GENMASK_ULL(31, 29)
+#define GICV5_GIC_CDPRI_ID_MASK		GENMASK_ULL(23, 0)
+
+/* Definitions for GIC CDRCFG */
+#define GICV5_GIC_CDRCFG_TYPE_MASK	GENMASK_ULL(31, 29)
+#define GICV5_GIC_CDRCFG_ID_MASK	GENMASK_ULL(23, 0)
+
+/* Definitions for GICR CDIA */
+#define GICV5_GIC_CDIA_VALID_MASK	BIT_ULL(32)
+#define GICV5_GICR_CDIA_VALID(r)	FIELD_GET(GICV5_GIC_CDIA_VALID_MASK, r)
+#define GICV5_GIC_CDIA_TYPE_MASK	GENMASK_ULL(31, 29)
+#define GICV5_GIC_CDIA_ID_MASK		GENMASK_ULL(23, 0)
+#define GICV5_GIC_CDIA_INTID		GENMASK_ULL(31, 0)
+
+/* Definitions for GICR CDNMIA */
+#define GICV5_GIC_CDNMIA_VALID_MASK	BIT_ULL(32)
+#define GICV5_GICR_CDNMIA_VALID(r)	FIELD_GET(GICV5_GIC_CDNMIA_VALID_MASK, r)
+#define GICV5_GIC_CDNMIA_TYPE_MASK	GENMASK_ULL(31, 29)
+#define GICV5_GIC_CDNMIA_ID_MASK	GENMASK_ULL(23, 0)
+
+#define gicr_insn(insn)			read_sysreg_s(GICV5_OP_GICR_##insn)
+#define gic_insn(v, insn)		write_sysreg_s(v, GICV5_OP_GIC_##insn)
+
+#define __GIC_BARRIER_INSN(op0, op1, CRn, CRm, op2, Rt)			\
+	__emit_inst(0xd5000000					|	\
+		    sys_insn((op0), (op1), (CRn), (CRm), (op2))	|	\
+		    ((Rt) & 0x1f))
+
+#define GSB_SYS_BARRIER_INSN		__GIC_BARRIER_INSN(1, 0, 12, 0, 0, 31)
+#define GSB_ACK_BARRIER_INSN		__GIC_BARRIER_INSN(1, 0, 12, 0, 1, 31)
+
+#define gsb_ack()	asm volatile(GSB_ACK_BARRIER_INSN : : : "memory")
+#define gsb_sys()	asm volatile(GSB_SYS_BARRIER_INSN : : : "memory")
+
+#define REPEAT_BYTE(x)	((~0ul / 0xff) * (x))
+
+#define GICV5_IRQ_DEFAULT_PRI 0b10000
+
+void gicv5_ppi_priority_init(void)
+{
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR0_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR1_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR2_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR3_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR4_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR5_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR6_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR7_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR8_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR9_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR10_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR11_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR12_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR13_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR14_EL1);
+	write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR15_EL1);
+
+	/*
+	 * Context syncronization required to make sure system register writes
+	 * effects are synchronised.
+	 */
+	isb();
+}
+
+void gicv5_cpu_disable_interrupts(void)
+{
+	u64 cr0;
+
+	cr0 = FIELD_PREP(ICC_CR0_EL1_EN, 0);
+	write_sysreg_s(cr0, SYS_ICC_CR0_EL1);
+}
+
+void gicv5_cpu_enable_interrupts(void)
+{
+	u64 cr0, pcr;
+
+	write_sysreg_s(0, SYS_ICC_PPI_ENABLER0_EL1);
+	write_sysreg_s(0, SYS_ICC_PPI_ENABLER1_EL1);
+
+	gicv5_ppi_priority_init();
+
+	pcr = FIELD_PREP(ICC_PCR_EL1_PRIORITY, GICV5_IRQ_DEFAULT_PRI);
+	write_sysreg_s(pcr, SYS_ICC_PCR_EL1);
+
+	cr0 = FIELD_PREP(ICC_CR0_EL1_EN, 1);
+	write_sysreg_s(cr0, SYS_ICC_CR0_EL1);
+}
+
+#endif
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:46 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:46 +0000
Subject: [PATCH v2 31/36] KVM: arm64: gic-v5: Set ICH_VCTLR_EL2.En on boot
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-32-sascha.bischoff@arm.com>

This control enables virtual HPPI selection, i.e., selection and
delivery of interrupts for a guest (assuming that the guest itself has
opted to receive interrupts). This is set to enabled on boot as there
is no reason for disabling it in normal operation as virtual interrupt
signalling itself is still controlled via the HCR_EL2.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/include/asm/el2_setup.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h
index 07c12f4a69b41..e7e39117c79e5 100644
--- a/arch/arm64/include/asm/el2_setup.h
+++ b/arch/arm64/include/asm/el2_setup.h
@@ -238,6 +238,8 @@
 		     ICH_HFGWTR_EL2_ICC_CR0_EL1			| \
 		     ICH_HFGWTR_EL2_ICC_APR_EL1)
 	msr_s	SYS_ICH_HFGWTR_EL2, x0		// Disable reg write traps
+	mov	x0, #(ICH_VCTLR_EL2_En)
+	msr_s	SYS_ICH_VCTLR_EL2, x0		// Enable vHPPI selection
 .Lskip_gicv5_\@:
 .endm
 
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:48 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:48 +0000
Subject: [PATCH v2 36/36] KVM: arm64: gic-v5: Communicate userspace-drivable
 PPIs via a UAPI
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-37-sascha.bischoff@arm.com>

GICv5 systems will likely not support the full set of PPIs. The
presence of any virtual PPI is tied to the presence of the physical
PPI. Therefore, the available PPIs will be limited by the physical
host. Userspace cannot drive any PPIs that are not implemented.

Moreover, it is not desirable to expose all PPIs to the guest in the
first place, even if they are supported in hardware. Some devices,
such as the arch timer, are implemented in KVM, and hence those PPIs
shouldn't be driven by userspace, either.

Provided a new UAPI:
  KVM_DEV_ARM_VGIC_GRP_CTRL => KVM_DEV_ARM_VGIC_USERPSPACE_PPIs

This allows userspace to query which PPIs it is able to drive via
KVM_IRQ_LINE.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 .../virt/kvm/devices/arm-vgic-v5.rst          | 13 ++++++++++
 arch/arm64/include/uapi/asm/kvm.h             |  1 +
 arch/arm64/kvm/vgic/vgic-kvm-device.c         | 25 +++++++++++++++++++
 arch/arm64/kvm/vgic/vgic-v5.c                 |  8 ++++++
 include/kvm/arm_vgic.h                        |  5 ++++
 include/linux/irqchip/arm-gic-v5.h            |  4 +++
 tools/arch/arm64/include/uapi/asm/kvm.h       |  1 +
 7 files changed, 57 insertions(+)

diff --git a/Documentation/virt/kvm/devices/arm-vgic-v5.rst b/Documentation/virt/kvm/devices/arm-vgic-v5.rst
index 9904cb888277d..d9f2917b609c5 100644
--- a/Documentation/virt/kvm/devices/arm-vgic-v5.rst
+++ b/Documentation/virt/kvm/devices/arm-vgic-v5.rst
@@ -25,6 +25,19 @@ Groups:
       request the initialization of the VGIC, no additional parameter in
       kvm_device_attr.addr. Must be called after all VCPUs have been created.
 
+   KVM_DEV_ARM_VGIC_USERPSPACE_PPIs
+      request the mask of userspace-drivable PPIs. Only a subset of the PPIs can
+      be directly driven from userspace with GICv5, and the returned mask
+      informs userspace of which it is allowed to drive via KVM_IRQ_LINE.
+
+      Userspace must allocate and point to __u64[2] with of data in
+      kvm_device_attr.addr. When this call returns, the provided memory will be
+      populated with the userspace PPI mask. The lower __u64 contains the mask
+      for the lower 64 PPIS, with the remaining 64 being in the second __u64.
+
+      This is a read-only attribute, and cannot be set. Attempts to set it are
+      rejected.
+
   Errors:
 
     =======  ========================================================
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index a792a599b9d68..1c13bfa2d38aa 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -428,6 +428,7 @@ enum {
 #define   KVM_DEV_ARM_ITS_RESTORE_TABLES        2
 #define   KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES	3
 #define   KVM_DEV_ARM_ITS_CTRL_RESET		4
+#define   KVM_DEV_ARM_VGIC_USERSPACE_PPIS	5
 
 /* Device Control API on vcpu fd */
 #define KVM_ARM_VCPU_PMU_V3_CTRL	0
diff --git a/arch/arm64/kvm/vgic/vgic-kvm-device.c b/arch/arm64/kvm/vgic/vgic-kvm-device.c
index 78903182bba08..360c78ed4f104 100644
--- a/arch/arm64/kvm/vgic/vgic-kvm-device.c
+++ b/arch/arm64/kvm/vgic/vgic-kvm-device.c
@@ -719,6 +719,25 @@ struct kvm_device_ops kvm_arm_vgic_v3_ops = {
 	.has_attr = vgic_v3_has_attr,
 };
 
+static int vgic_v5_get_userspace_ppis(struct kvm_device *dev,
+				      struct kvm_device_attr *attr)
+{
+	u64 __user *uaddr = (u64 __user *)(long)attr->addr;
+	struct gicv5_vm *gicv5_vm = &dev->kvm->arch.vgic.gicv5_vm;
+	int i, ret;
+
+	guard(mutex)(&dev->kvm->arch.config_lock);
+
+	for (i = 0; i < 2; ++i) {
+		ret = put_user(gicv5_vm->userspace_ppis[i], uaddr);
+		if (ret)
+			return ret;
+		uaddr++;
+	}
+
+	return 0;
+}
+
 static int vgic_v5_set_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
@@ -731,6 +750,8 @@ static int vgic_v5_set_attr(struct kvm_device *dev,
 		switch (attr->attr) {
 		case KVM_DEV_ARM_VGIC_CTRL_INIT:
 			return  vgic_set_common_attr(dev, attr);
+		case KVM_DEV_ARM_VGIC_USERSPACE_PPIS:
+			break;
 		default:
 			break;
 		}
@@ -751,6 +772,8 @@ static int vgic_v5_get_attr(struct kvm_device *dev,
 		switch (attr->attr) {
 		case KVM_DEV_ARM_VGIC_CTRL_INIT:
 			return vgic_get_common_attr(dev, attr);
+		case KVM_DEV_ARM_VGIC_USERSPACE_PPIS:
+			return vgic_v5_get_userspace_ppis(dev, attr);
 		default:
 			break;
 		}
@@ -771,6 +794,8 @@ static int vgic_v5_has_attr(struct kvm_device *dev,
 		switch (attr->attr) {
 		case KVM_DEV_ARM_VGIC_CTRL_INIT:
 			return 0;
+		case KVM_DEV_ARM_VGIC_USERSPACE_PPIS:
+			return 0;
 		default:
 			break;
 		}
diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index bf72982d6a2e8..04300926683b6 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -122,6 +122,14 @@ int vgic_v5_init(struct kvm *kvm)
 		}
 	}
 
+	/*
+	 * We only allow userspace to drive the SW_PPI, if it is
+	 * implemented.
+	 */
+	kvm->arch.vgic.gicv5_vm.userspace_ppis[0] = GICV5_SW_PPI & GICV5_HWIRQ_ID;
+	kvm->arch.vgic.gicv5_vm.userspace_ppis[0] &= ppi_caps->impl_ppi_mask[0];
+	kvm->arch.vgic.gicv5_vm.userspace_ppis[1] = 0;
+
 	return 0;
 }
 
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 22f979b561054..5a7de3b74a99d 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -404,6 +404,11 @@ struct vgic_dist {
 	 * else.
 	 */
 	struct its_vm		its_vm;
+
+	/*
+	 * GICv5 per-VM data.
+	 */
+	struct gicv5_vm		gicv5_vm;
 };
 
 struct vgic_v2_cpu_if {
diff --git a/include/linux/irqchip/arm-gic-v5.h b/include/linux/irqchip/arm-gic-v5.h
index 06ebb2a1cfb1d..123c6cfc344c5 100644
--- a/include/linux/irqchip/arm-gic-v5.h
+++ b/include/linux/irqchip/arm-gic-v5.h
@@ -365,6 +365,10 @@ struct gicv5_vpe {
 	bool			resident;
 };
 
+struct gicv5_vm {
+	u64			userspace_ppis[2];
+};
+
 struct gicv5_its_devtab_cfg {
 	union {
 		struct {
diff --git a/tools/arch/arm64/include/uapi/asm/kvm.h b/tools/arch/arm64/include/uapi/asm/kvm.h
index a792a599b9d68..1c13bfa2d38aa 100644
--- a/tools/arch/arm64/include/uapi/asm/kvm.h
+++ b/tools/arch/arm64/include/uapi/asm/kvm.h
@@ -428,6 +428,7 @@ enum {
 #define   KVM_DEV_ARM_ITS_RESTORE_TABLES        2
 #define   KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES	3
 #define   KVM_DEV_ARM_ITS_CTRL_RESET		4
+#define   KVM_DEV_ARM_VGIC_USERSPACE_PPIS	5
 
 /* Device Control API on vcpu fd */
 #define KVM_ARM_VCPU_PMU_V3_CTRL	0
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:47 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:47 +0000
Subject: [PATCH v2 33/36] KVM: arm64: gic-v5: Probe for GICv5 device
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-34-sascha.bischoff@arm.com>

The basic GICv5 PPI support is now complete. Allow probing for a
native GICv5 rather than just the legacy support.

The implementation doesn't support protected VMs with GICv5 at this
time. Therefore, if KVM has protected mode enabled the native GICv5
init is skipped, but legacy VMs are allowed if the hardware supports
it.

At this stage the GICv5 KVM implementation only supports PPIs, and
doesn't interact with the host IRS at all. This means that there is no
need to check how many concurrent VMs or vCPUs per VM are supported by
the IRS - the PPI support only requires the CPUIF. The support is
artificially limited to VGIC_V5_MAX_CPUS, i.e. 512, vCPUs per VM.

With this change it becomes possible to run basic GICv5-based VMs,
provided that they only use PPIs.

Co-authored-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Timothy Hayes <timothy.hayes at arm.com>
Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/vgic/vgic-v5.c | 39 +++++++++++++++++++++++++++--------
 1 file changed, 30 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index 97d67c1d16541..bf72982d6a2e8 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -12,22 +12,13 @@ static struct vgic_v5_ppi_caps *ppi_caps;
 
 /*
  * Probe for a vGICv5 compatible interrupt controller, returning 0 on success.
- * Currently only supports GICv3-based VMs on a GICv5 host, and hence only
- * registers a VGIC_V3 device.
  */
 int vgic_v5_probe(const struct gic_kvm_info *info)
 {
 	u64 ich_vtr_el2;
 	int ret;
 
-	if (!cpus_have_final_cap(ARM64_HAS_GICV5_LEGACY))
-		return -ENODEV;
-
 	kvm_vgic_global_state.type = VGIC_V5;
-	kvm_vgic_global_state.has_gcie_v3_compat = true;
-
-	/* We only support v3 compat mode - use vGICv3 limits */
-	kvm_vgic_global_state.max_gic_vcpus = VGIC_V3_MAX_CPUS;
 
 	kvm_vgic_global_state.vcpu_base = 0;
 	kvm_vgic_global_state.vctrl_base = NULL;
@@ -35,6 +26,32 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
 	kvm_vgic_global_state.has_gicv4 = false;
 	kvm_vgic_global_state.has_gicv4_1 = false;
 
+	/*
+	 * GICv5 is currently not supported in Protected mode. Skip the
+	 * registration of GICv5 completely to make sure no guests can create a
+	 * GICv5-based guest.
+	 */
+	if (is_protected_kvm_enabled()) {
+		kvm_info("GICv5-based guests are not supported with pKVM\n");
+		goto skip_v5;
+	}
+
+	kvm_vgic_global_state.max_gic_vcpus = VGIC_V5_MAX_CPUS;
+
+	ret = kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V5);
+	if (ret) {
+		kvm_err("Cannot register GICv5 KVM device.\n");
+		goto skip_v5;
+	}
+
+	kvm_info("GCIE system register CPU interface\n");
+
+skip_v5:
+	/* If we don't support the GICv3 compat mode we're done. */
+	if (!cpus_have_final_cap(ARM64_HAS_GICV5_LEGACY))
+		return 0;
+
+	kvm_vgic_global_state.has_gcie_v3_compat = true;
 	ich_vtr_el2 =  kvm_call_hyp_ret(__vgic_v3_get_gic_config);
 	kvm_vgic_global_state.ich_vtr_el2 = (u32)ich_vtr_el2;
 
@@ -50,6 +67,10 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
 		return ret;
 	}
 
+	/* We potentially limit the max VCPUs further than we need to here */
+	kvm_vgic_global_state.max_gic_vcpus = min(VGIC_V3_MAX_CPUS,
+						  VGIC_V5_MAX_CPUS);
+
 	static_branch_enable(&kvm_vgic_global_state.gicv3_cpuif);
 	kvm_info("GCIE legacy system register CPU interface\n");
 
-- 
2.34.1


From Sascha.Bischoff at arm.com  Fri Dec 19 07:52:47 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 15:52:47 +0000
Subject: [PATCH v2 34/36] Documentation: KVM: Introduce documentation for
 VGICv5
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <20251219155222.1383109-35-sascha.bischoff@arm.com>

Now that it is possible to create a VGICv5 device, provide initial
documentation for it. At this stage, there is little to document.

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 .../virt/kvm/devices/arm-vgic-v5.rst          | 37 +++++++++++++++++++
 Documentation/virt/kvm/devices/index.rst      |  1 +
 2 files changed, 38 insertions(+)
 create mode 100644 Documentation/virt/kvm/devices/arm-vgic-v5.rst

diff --git a/Documentation/virt/kvm/devices/arm-vgic-v5.rst b/Documentation/virt/kvm/devices/arm-vgic-v5.rst
new file mode 100644
index 0000000000000..9904cb888277d
--- /dev/null
+++ b/Documentation/virt/kvm/devices/arm-vgic-v5.rst
@@ -0,0 +1,37 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+====================================================
+ARM Virtual Generic Interrupt Controller v5 (VGICv5)
+====================================================
+
+
+Device types supported:
+  - KVM_DEV_TYPE_ARM_VGIC_V5     ARM Generic Interrupt Controller v5.0
+
+Only one VGIC instance may be instantiated through this API.  The created VGIC
+will act as the VM interrupt controller, requiring emulated user-space devices
+to inject interrupts to the VGIC instead of directly to CPUs.
+
+Creating a guest GICv5 device requires a host GICv5 host.  The current VGICv5
+device only supports PPI interrupts.  These can either be injected from emulated
+in-kernel devices (such as the Arch Timer, or PMU), or via the KVM_IRQ_LINE
+ioctl.
+
+Groups:
+  KVM_DEV_ARM_VGIC_GRP_CTRL
+   Attributes:
+
+    KVM_DEV_ARM_VGIC_CTRL_INIT
+      request the initialization of the VGIC, no additional parameter in
+      kvm_device_attr.addr. Must be called after all VCPUs have been created.
+
+  Errors:
+
+    =======  ========================================================
+    -ENXIO   VGIC not properly configured as required prior to calling
+             this attribute
+    -ENODEV  no online VCPU
+    -ENOMEM  memory shortage when allocating vgic internal data
+    -EFAULT  Invalid guest ram access
+    -EBUSY   One or more VCPUS are running
+    =======  ========================================================
diff --git a/Documentation/virt/kvm/devices/index.rst b/Documentation/virt/kvm/devices/index.rst
index 192cda7405c84..70845aba38f45 100644
--- a/Documentation/virt/kvm/devices/index.rst
+++ b/Documentation/virt/kvm/devices/index.rst
@@ -10,6 +10,7 @@ Devices
    arm-vgic-its
    arm-vgic
    arm-vgic-v3
+   arm-vgic-v5
    mpic
    s390_flic
    vcpu
-- 
2.34.1


From yilun.xu at linux.intel.com  Fri Dec 19 07:40:12 2025
From: yilun.xu at linux.intel.com (Xu Yilun)
Date: Fri, 19 Dec 2025 23:40:12 +0800
Subject: [PATCH] fpga: xilinx: Switch Michal Simek's email to new one
In-Reply-To: <49de9536c9952a3a36bb996f2fb0a1f0efb1ba6f.1765787307.git.michal.simek@amd.com>
References: <49de9536c9952a3a36bb996f2fb0a1f0efb1ba6f.1765787307.git.michal.simek@amd.com>
Message-ID: <aUVx3PtC1Hho5RbK@yilunxu-OptiPlex-7050>

On Mon, Dec 15, 2025 at 09:28:29AM +0100, Michal Simek wrote:
> @xilinx.com is still working but better to switch to new amd.com after
> AMD/Xilinx acquisition.
> 
> Signed-off-by: Michal Simek <michal.simek at amd.com>

Reviewed-by: Xu Yilun <yilun.xu at intel.com>

Applied to for-next, thanks.


From Frank.li at nxp.com  Fri Dec 19 07:57:16 2025
From: Frank.li at nxp.com (Frank Li)
Date: Fri, 19 Dec 2025 10:57:16 -0500
Subject: [PATCH v3 1/2] media: dt-bindings: Add CSI Pixel Formatter DT
 bindings
In-Reply-To: <20251219-csi_formatter-v3-1-8680d6d87091@nxp.com>
References: <20251219-csi_formatter-v3-0-8680d6d87091@nxp.com>
 <20251219-csi_formatter-v3-1-8680d6d87091@nxp.com>
Message-ID: <aUV13BHFn71ZIXfv@lizhi-Precision-Tower-5810>

On Fri, Dec 19, 2025 at 09:50:57AM +0800, Guoniu Zhou wrote:
> From: Guoniu Zhou <guoniu.zhou at nxp.com>
>
> The i.MX9 CSI pixel formatting module uses packet info, pixel and
> non-pixel data from the CSI-2 host controller and reformat them to
> match Pixel Link(PL) definition.
>
> Signed-off-by: Guoniu Zhou <guoniu.zhou at nxp.com>
> ---

Reviewed-by: Frank Li <Frank.Li at nxp.com>

>  .../bindings/media/fsl,imx9-csi-formatter.yaml     | 87 ++++++++++++++++++++++
>  1 file changed, 87 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/media/fsl,imx9-csi-formatter.yaml b/Documentation/devicetree/bindings/media/fsl,imx9-csi-formatter.yaml
> new file mode 100644
> index 0000000000000000000000000000000000000000..774d37d2b987a679f0bb6378897a6dd196ea4f13
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/fsl,imx9-csi-formatter.yaml
> @@ -0,0 +1,87 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/media/fsl,imx9-csi-formatter.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: i.MX9 CSI Pixel Formatter
> +
> +maintainers:
> +  - Guoniu Zhou <guoniu.zhou at nxp.com>
> +
> +description:
> +  The CSI pixel formatting module uses packet info, pixel and non-pixel
> +  data from the CSI-2 host controller and reformat them to match Pixel
> +  Link(PL) definition.
> +
> +properties:
> +  compatible:
> +    const: fsl,imx9-csi-formatter
> +
> +  reg:
> +    maxItems: 1
> +
> +  clocks:
> +    maxItems: 1
> +
> +  power-domains:
> +    maxItems: 1
> +
> +  ports:
> +    $ref: /schemas/graph.yaml#/properties/ports
> +
> +    properties:
> +      port at 0:
> +        $ref: /schemas/graph.yaml#/$defs/port-base
> +        unevaluatedProperties: false
> +        description: MIPI CSI-2 RX IDI interface
> +
> +        properties:
> +          endpoint:
> +            $ref: video-interfaces.yaml#
> +            unevaluatedProperties: false
> +
> +      port at 1:
> +        $ref: /schemas/graph.yaml#/properties/port
> +        description: Pixel Link Interface
> +
> +required:
> +  - compatible
> +  - reg
> +  - clocks
> +  - power-domains
> +  - ports
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/clock/nxp,imx95-clock.h>
> +
> +    formatter at 20 {
> +        compatible = "fsl,imx9-csi-formatter";
> +        reg = <0x20 0x100>;
> +        clocks = <&cameramix_csr IMX95_CLK_CAMBLK_CSI2_FOR0>;
> +        power-domains = <&scmi_devpd 3>;
> +
> +        ports {
> +            #address-cells = <1>;
> +            #size-cells = <0>;
> +
> +            port at 0 {
> +                reg = <0>;
> +
> +                endpoint {
> +                    remote-endpoint = <&mipi_csi_0_out>;
> +                };
> +            };
> +
> +            port at 1 {
> +                reg = <1>;
> +
> +                endpoint {
> +                    remote-endpoint = <&isi_in_2>;
> +                };
> +            };
> +        };
> +    };
>
> --
> 2.34.1
>


From alain.volmat at foss.st.com  Fri Dec 19 07:58:03 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Fri, 19 Dec 2025 16:58:03 +0100
Subject: [PATCH 1/6] dt-bindings: media: st: csi: add 'power-domains'
 property
In-Reply-To: <20251219-stm32-mp2x-dcmipp-csi-power-domain-v1-0-a6edb2aa8154@foss.st.com>
References: <20251219-stm32-mp2x-dcmipp-csi-power-domain-v1-0-a6edb2aa8154@foss.st.com>
Message-ID: <20251219-stm32-mp2x-dcmipp-csi-power-domain-v1-1-a6edb2aa8154@foss.st.com>

STM32 CSI may be in a power domain which is the case for the STM32MP2x
based boards. Allow a single 'power-domains' entry for STM32 CSI.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 Documentation/devicetree/bindings/media/st,stm32mp25-csi.yaml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/media/st,stm32mp25-csi.yaml b/Documentation/devicetree/bindings/media/st,stm32mp25-csi.yaml
index e9fa3cfea5d2..2ac7c9670c62 100644
--- a/Documentation/devicetree/bindings/media/st,stm32mp25-csi.yaml
+++ b/Documentation/devicetree/bindings/media/st,stm32mp25-csi.yaml
@@ -46,6 +46,9 @@ properties:
     minItems: 1
     maxItems: 2
 
+  power-domains:
+    maxItems: 1
+
   ports:
     $ref: /schemas/graph.yaml#/properties/ports
 

-- 
2.34.1



From alain.volmat at foss.st.com  Fri Dec 19 07:58:05 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Fri, 19 Dec 2025 16:58:05 +0100
Subject: [PATCH 3/6] arm64: dts: st: add power-domain of csi in
 stm32mp231.dtsi
In-Reply-To: <20251219-stm32-mp2x-dcmipp-csi-power-domain-v1-0-a6edb2aa8154@foss.st.com>
References: <20251219-stm32-mp2x-dcmipp-csi-power-domain-v1-0-a6edb2aa8154@foss.st.com>
Message-ID: <20251219-stm32-mp2x-dcmipp-csi-power-domain-v1-3-a6edb2aa8154@foss.st.com>

Add the power-domain property in the csi node of stm32mp231.dtsi

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 arch/arm64/boot/dts/st/stm32mp231.dtsi | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/boot/dts/st/stm32mp231.dtsi b/arch/arm64/boot/dts/st/stm32mp231.dtsi
index 88e214d395ab..be9dd882ce79 100644
--- a/arch/arm64/boot/dts/st/stm32mp231.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp231.dtsi
@@ -676,6 +676,7 @@ csi: csi at 48020000 {
 					 <&rcc CK_KER_CSIPHY>;
 				clock-names = "pclk", "txesc", "csi2phy";
 				access-controllers = <&rifsc 86>;
+				power-domains = <&cluster_pd>;
 				status = "disabled";
 			};
 

-- 
2.34.1



From alain.volmat at foss.st.com  Fri Dec 19 07:58:02 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Fri, 19 Dec 2025 16:58:02 +0100
Subject: [PATCH 0/6] media: stm32: add dcmipp/csi power-domain support for
 mp2x
Message-ID: <20251219-stm32-mp2x-dcmipp-csi-power-domain-v1-0-a6edb2aa8154@foss.st.com>

This series adds the bindings & dtsi updates related to the power-domain
properties for CSI & DCMIPP of the STM32MP2x.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
Alain Volmat (6):
      dt-bindings: media: st: csi: add 'power-domains' property
      arm64: dts: st: add power-domain of csi in stm32mp251.dtsi
      arm64: dts: st: add power-domain of csi in stm32mp231.dtsi
      dt-bindings: media: st: dcmipp: add 'power-domains' property
      arm64: dts: st: add power-domain of dcmipp in stm32mp251.dtsi
      arm64: dts: st: add power-domain of dcmipp in stm32mp231.dtsi

 Documentation/devicetree/bindings/media/st,stm32-dcmipp.yaml  | 3 +++
 Documentation/devicetree/bindings/media/st,stm32mp25-csi.yaml | 3 +++
 arch/arm64/boot/dts/st/stm32mp231.dtsi                        | 2 ++
 arch/arm64/boot/dts/st/stm32mp251.dtsi                        | 2 ++
 4 files changed, 10 insertions(+)
---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20251219-stm32-mp2x-dcmipp-csi-power-domain-7d57c8ce622f

Best regards,
-- 
Alain Volmat <alain.volmat at foss.st.com>



From alain.volmat at foss.st.com  Fri Dec 19 07:58:07 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Fri, 19 Dec 2025 16:58:07 +0100
Subject: [PATCH 5/6] arm64: dts: st: add power-domain of dcmipp in
 stm32mp251.dtsi
In-Reply-To: <20251219-stm32-mp2x-dcmipp-csi-power-domain-v1-0-a6edb2aa8154@foss.st.com>
References: <20251219-stm32-mp2x-dcmipp-csi-power-domain-v1-0-a6edb2aa8154@foss.st.com>
Message-ID: <20251219-stm32-mp2x-dcmipp-csi-power-domain-v1-5-a6edb2aa8154@foss.st.com>

Add the power-domain property in the dcmipp node of stm32mp251.dtsi

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 arch/arm64/boot/dts/st/stm32mp251.dtsi | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/boot/dts/st/stm32mp251.dtsi b/arch/arm64/boot/dts/st/stm32mp251.dtsi
index c83fa864eb3d..e8b6a593f237 100644
--- a/arch/arm64/boot/dts/st/stm32mp251.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp251.dtsi
@@ -1601,6 +1601,7 @@ dcmipp: dcmipp at 48030000 {
 				clocks = <&rcc CK_BUS_DCMIPP>, <&rcc CK_KER_CSI>;
 				clock-names = "kclk", "mclk";
 				access-controllers = <&rifsc 87>;
+				power-domains = <&CLUSTER_PD>;
 				status = "disabled";
 			};
 

-- 
2.34.1



From alain.volmat at foss.st.com  Fri Dec 19 07:58:04 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Fri, 19 Dec 2025 16:58:04 +0100
Subject: [PATCH 2/6] arm64: dts: st: add power-domain of csi in
 stm32mp251.dtsi
In-Reply-To: <20251219-stm32-mp2x-dcmipp-csi-power-domain-v1-0-a6edb2aa8154@foss.st.com>
References: <20251219-stm32-mp2x-dcmipp-csi-power-domain-v1-0-a6edb2aa8154@foss.st.com>
Message-ID: <20251219-stm32-mp2x-dcmipp-csi-power-domain-v1-2-a6edb2aa8154@foss.st.com>

Add the power-domain property in the csi node of stm32mp251.dtsi

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 arch/arm64/boot/dts/st/stm32mp251.dtsi | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/boot/dts/st/stm32mp251.dtsi b/arch/arm64/boot/dts/st/stm32mp251.dtsi
index a8e6e0f77b83..c83fa864eb3d 100644
--- a/arch/arm64/boot/dts/st/stm32mp251.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp251.dtsi
@@ -1589,6 +1589,7 @@ csi: csi at 48020000 {
 					 <&rcc CK_KER_CSIPHY>;
 				clock-names = "pclk", "txesc", "csi2phy";
 				access-controllers = <&rifsc 86>;
+				power-domains = <&CLUSTER_PD>;
 				status = "disabled";
 			};
 

-- 
2.34.1



From alain.volmat at foss.st.com  Fri Dec 19 07:58:08 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Fri, 19 Dec 2025 16:58:08 +0100
Subject: [PATCH 6/6] arm64: dts: st: add power-domain of dcmipp in
 stm32mp231.dtsi
In-Reply-To: <20251219-stm32-mp2x-dcmipp-csi-power-domain-v1-0-a6edb2aa8154@foss.st.com>
References: <20251219-stm32-mp2x-dcmipp-csi-power-domain-v1-0-a6edb2aa8154@foss.st.com>
Message-ID: <20251219-stm32-mp2x-dcmipp-csi-power-domain-v1-6-a6edb2aa8154@foss.st.com>

Add the power-domain property in the dcmipp node of stm32mp231.dtsi

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 arch/arm64/boot/dts/st/stm32mp231.dtsi | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/boot/dts/st/stm32mp231.dtsi b/arch/arm64/boot/dts/st/stm32mp231.dtsi
index be9dd882ce79..577cd5b4cbb6 100644
--- a/arch/arm64/boot/dts/st/stm32mp231.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp231.dtsi
@@ -688,6 +688,7 @@ dcmipp: dcmipp at 48030000 {
 				clocks = <&rcc CK_BUS_DCMIPP>, <&rcc CK_KER_CSI>;
 				clock-names = "kclk", "mclk";
 				access-controllers = <&rifsc 87>;
+				power-domains = <&cluster_pd>;
 				status = "disabled";
 			};
 

-- 
2.34.1



From alain.volmat at foss.st.com  Fri Dec 19 07:58:06 2025
From: alain.volmat at foss.st.com (Alain Volmat)
Date: Fri, 19 Dec 2025 16:58:06 +0100
Subject: [PATCH 4/6] dt-bindings: media: st: dcmipp: add 'power-domains'
 property
In-Reply-To: <20251219-stm32-mp2x-dcmipp-csi-power-domain-v1-0-a6edb2aa8154@foss.st.com>
References: <20251219-stm32-mp2x-dcmipp-csi-power-domain-v1-0-a6edb2aa8154@foss.st.com>
Message-ID: <20251219-stm32-mp2x-dcmipp-csi-power-domain-v1-4-a6edb2aa8154@foss.st.com>

STM32 DCMIPP may be in a power domain which is the case for the
STM32MP2x based boards.
Allow a single 'power-domains' entry for STM32 DCMIPP.

Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
---
 Documentation/devicetree/bindings/media/st,stm32-dcmipp.yaml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/media/st,stm32-dcmipp.yaml b/Documentation/devicetree/bindings/media/st,stm32-dcmipp.yaml
index 7b03a77adbce..162a0c526d5d 100644
--- a/Documentation/devicetree/bindings/media/st,stm32-dcmipp.yaml
+++ b/Documentation/devicetree/bindings/media/st,stm32-dcmipp.yaml
@@ -37,6 +37,9 @@ properties:
   resets:
     maxItems: 1
 
+  power-domains:
+    maxItems: 1
+
   access-controllers:
     minItems: 1
     maxItems: 2

-- 
2.34.1



From Frank.li at nxp.com  Fri Dec 19 08:08:26 2025
From: Frank.li at nxp.com (Frank Li)
Date: Fri, 19 Dec 2025 11:08:26 -0500
Subject: [PATCH v3 2/2] media: nxp: Add i.MX9 CSI pixel formatter v4l2
 driver
In-Reply-To: <20251219-csi_formatter-v3-2-8680d6d87091@nxp.com>
References: <20251219-csi_formatter-v3-0-8680d6d87091@nxp.com>
 <20251219-csi_formatter-v3-2-8680d6d87091@nxp.com>
Message-ID: <aUV4enryGRDdIkIb@lizhi-Precision-Tower-5810>

On Fri, Dec 19, 2025 at 09:50:58AM +0800, Guoniu Zhou wrote:
> From: Guoniu Zhou <guoniu.zhou at nxp.com>
>
> The CSI pixel formatter is a module found on i.MX95 used to reformat
> packet info, pixel and non-pixel data from CSI-2 host controller to
> match Pixel Link(PL) definition.
>
> Add data formatting support.
>
> Signed-off-by: Guoniu Zhou <guoniu.zhou at nxp.com>
> ---
>  MAINTAINERS                                     |   8 +
>  drivers/media/platform/nxp/Kconfig              |  14 +
>  drivers/media/platform/nxp/Makefile             |   1 +
>  drivers/media/platform/nxp/imx9-csi-formatter.c | 880 ++++++++++++++++++++++++
>  4 files changed, 903 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 4205ca007e076f869613032b51e8cc5bff06b98e..3878957b81156e5cb41da2699b2f588e49521724 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -18626,6 +18626,14 @@ S:	Maintained
>  F:	Documentation/devicetree/bindings/media/nxp,imx8-jpeg.yaml
>  F:	drivers/media/platform/nxp/imx-jpeg
>
> +NXP i.MX 9 CSI PIXEL FORMATTER V4L2 DRIVER
> +M:	Guoniu Zhou <guoniu.zhou at nxp.com>
> +L:	imx at lists.linux.dev
> +L:	linux-media at vger.kernel.org
> +S:	Maintained
> +F:	Documentation/devicetree/bindings/media/fsl,imx9-csi-formatter.yaml
> +F:	drivers/media/platform/nxp/imx9-csi-formatter.c
> +
>  NXP i.MX CLOCK DRIVERS
>  M:	Abel Vesa <abelvesa at kernel.org>
>  R:	Peng Fan <peng.fan at nxp.com>
> diff --git a/drivers/media/platform/nxp/Kconfig b/drivers/media/platform/nxp/Kconfig
> index 40e3436669e213fdc5da70821dc0b420e1821f4f..a7bb62a2b0249659ffdfeac50fa488aee9590a87 100644
> --- a/drivers/media/platform/nxp/Kconfig
> +++ b/drivers/media/platform/nxp/Kconfig
> @@ -28,6 +28,20 @@ config VIDEO_IMX8MQ_MIPI_CSI2
>  	  Video4Linux2 driver for the MIPI CSI-2 receiver found on the i.MX8MQ
>  	  SoC.
>
> +config VIDEO_IMX9_CSI_FORMATTER
> +	tristate "NXP i.MX9 CSI Pixel Formatter driver"
> +	depends on ARCH_MXC || COMPILE_TEST
> +	depends on VIDEO_DEV
> +	select MEDIA_CONTROLLER
> +	select V4L2_FWNODE
> +	select VIDEO_V4L2_SUBDEV_API
> +	help
> +	  This driver provides support for the CSI Pixel Formatter found on
> +	  i.MX9 series SoC. This module unpacks the pixels received by the
> +	  formatter and reformats them to meet the pixel link format requirement.
> +
> +	  Say Y here to enable CSI Pixel Formater module for i.MX9 SoC.
> +
>  config VIDEO_IMX_MIPI_CSIS
>  	tristate "NXP MIPI CSI-2 CSIS receiver found on i.MX7 and i.MX8 models"
>  	depends on ARCH_MXC || COMPILE_TEST
> diff --git a/drivers/media/platform/nxp/Makefile b/drivers/media/platform/nxp/Makefile
> index 4d90eb71365259ebdda84ea58483e1c4131d3ac7..39ba5660ba923141e7637b01b5b34a021dad7bb3 100644
> --- a/drivers/media/platform/nxp/Makefile
> +++ b/drivers/media/platform/nxp/Makefile
> @@ -6,6 +6,7 @@ obj-y += imx8-isi/
>
>  obj-$(CONFIG_VIDEO_IMX7_CSI) += imx7-media-csi.o
>  obj-$(CONFIG_VIDEO_IMX8MQ_MIPI_CSI2) += imx8mq-mipi-csi2.o
> +obj-$(CONFIG_VIDEO_IMX9_CSI_FORMATTER) += imx9-csi-formatter.o
>  obj-$(CONFIG_VIDEO_IMX_MIPI_CSIS) += imx-mipi-csis.o
>  obj-$(CONFIG_VIDEO_IMX_PXP) += imx-pxp.o
>  obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o
> diff --git a/drivers/media/platform/nxp/imx9-csi-formatter.c b/drivers/media/platform/nxp/imx9-csi-formatter.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..5786e4690e31ee471caf8201329c8e02a2cc0ee6
> --- /dev/null
> +++ b/drivers/media/platform/nxp/imx9-csi-formatter.c
> @@ -0,0 +1,880 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright 2025 NXP
> + */
> +
...
> +
> +static const struct dt_index formatter_dt_to_index_map[] = {
> +	{ .dtype = MIPI_CSI2_DT_YUV420_8B,        .index = 0 },
> +	{ .dtype = MIPI_CSI2_DT_YUV420_8B_LEGACY, .index = 2 },
> +	{ .dtype = MIPI_CSI2_DT_YUV422_8B,        .index = 6 },
> +	{ .dtype = MIPI_CSI2_DT_RGB444,		  .index = 8 },
> +	{ .dtype = MIPI_CSI2_DT_RGB555,           .index = 9 },
> +	{ .dtype = MIPI_CSI2_DT_RGB565,           .index = 10 },
> +	{ .dtype = MIPI_CSI2_DT_RGB666,           .index = 11 },
> +	{ .dtype = MIPI_CSI2_DT_RGB888,           .index = 12 },
> +	{ .dtype = MIPI_CSI2_DT_RAW6,             .index = 16 },
> +	{ .dtype = MIPI_CSI2_DT_RAW7,             .index = 17 },
> +	{ .dtype = MIPI_CSI2_DT_RAW8,             .index = 18 },
> +	{ .dtype = MIPI_CSI2_DT_RAW10,            .index = 19 },
> +	{ .dtype = MIPI_CSI2_DT_RAW12,            .index = 20 },
> +	{ .dtype = MIPI_CSI2_DT_RAW14,            .index = 21 },
> +	{ .dtype = MIPI_CSI2_DT_RAW16,            .index = 22 },

what's these index value from? register bit?

Frank
> +
> +static u8 get_index_by_dt(u8 data_type)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(formatter_dt_to_index_map); ++i)
> +		if (data_type == formatter_dt_to_index_map[i].dtype)
> +			break;
> +
> +	if (i == ARRAY_SIZE(formatter_dt_to_index_map))
> +		return formatter_dt_to_index_map[0].index;
> +
> +	return formatter_dt_to_index_map[i].index;
> +}
> +
...
>
> --
> 2.34.1
>


From willy at infradead.org  Fri Dec 19 08:09:31 2025
From: willy at infradead.org (Matthew Wilcox)
Date: Fri, 19 Dec 2025 16:09:31 +0000
Subject: [PATCH v3 1/5] mm: rmap: support batched checks of the
 references for large folios
In-Reply-To: <x2s3l56rqwgcpkhpu77pjt65tfwgmchuy4fuyrj7h7uag5gja3@c3jbws4quxrd>
References: <cover.1766121341.git.baolin.wang@linux.alibaba.com>
 <24b9d33acad627997febe9b61d398fc53739a333.1766121341.git.baolin.wang@linux.alibaba.com>
 <x2s3l56rqwgcpkhpu77pjt65tfwgmchuy4fuyrj7h7uag5gja3@c3jbws4quxrd>
Message-ID: <aUV4u9pOHxvQiDcP@casper.infradead.org>

On Fri, Dec 19, 2025 at 10:47:52AM -0500, Liam R. Howlett wrote:
> > -#define ptep_clear_flush_young_notify(__vma, __address, __ptep)		\
> > +#define ptep_clear_flush_young_notify(__vma, __address, __ptep, __nr)	\
> >  ({									\
> >  	int __young;							\
> >  	struct vm_area_struct *___vma = __vma;				\
> >  	unsigned long ___address = __address;				\
> > -	__young = ptep_clear_flush_young(___vma, ___address, __ptep);	\
> > +	unsigned int ___nr = __nr;					\
> > +	__young = clear_flush_young_ptes(___vma, ___address, __ptep, ___nr);	\
> >  	__young |= mmu_notifier_clear_flush_young(___vma->vm_mm,	\
> >  						  ___address,		\
> >  						  ___address +		\
> > -							PAGE_SIZE);	\
> > +						nr * PAGE_SIZE);	\
> 
> Did you mean nr * PAGE_SIZE here?  I think it should be __nr or ___nr?
> I think this nr variable works because it exists where this macro is
> expanded?

Yes, this should clearly be ___nr.

> I am also not sure why you have ___nr  at all?

It's a macro cleanliness thing.  Imagine that we have a caller:

	a = ptep_clear_flush_young_notify(vma, addr, ptep, nr++);

If you have two references to the __nr macro argument, then you end up
incrementing nr twice.  Assigning __nr to ___nr and then referring to
___nr within the macro prevents this.

That said, I'm not sure why ptep_clear_flush_young_notify() needs
to be a macro instead of a static inline?


From arnd at kernel.org  Fri Dec 19 08:15:55 2025
From: arnd at kernel.org (Arnd Bergmann)
Date: Fri, 19 Dec 2025 17:15:55 +0100
Subject: [PATCH 0/4] mm: increase lowmem size in linux-7.0
Message-ID: <20251219161559.556737-1-arnd@kernel.org>

From: Arnd Bergmann <arnd at arndb.de>

At the kernel summit in Tokyo last week, I hosted a session on dealing
with highmem in the long run, see the link below.

My feeling was that we got sufficient consensus on the plan to keep the
funcationality present for the time being but instead reduce the scope
of highmem in the kernel as much as we can without hurting users.

The short summary is a three stage process:

 1. Nudge users towards using a larger lowmem zone with the
    CONFIG_VMSPLIT_* options if at all possible.

 2. Drop most __GFP_HIGHMEM allocations and corresponding kmap()
    calls from the kernel, leaving only the subset that is likely
    to contain the majority of the actual allocations.
    Specifically we will keep anonymous and regular file backed
    user mappings, zsmalloc, and huge pages.

 3. In a few years, also drop the page cache allocations and leave
    perhaps only zsmalloc using a much simpler interface.  I suggested
    five years as the time until we do this, but the timing depends a
    lot on how the first two stages work out in practice, and how long
    the remaining highmem users plan to keep updating their kernels.

This series implements stage 1, mostly using Kconfig changes to the
default settings but leaving the traditional behavior as a CONFIG_EXPERT
choice in Kconfig. With the new defaults, most installations that use
highmem today with 1 GiB or 2 GiB of system RAM will see all of their
RAM in the lowmem zone after upgrading their kernels. My estimate is
that instead of 80% to 90% of maintained embedded 32-bit systems, this
should cover over 98%.

As I don't actually have hardware in the category that still needs
highmem, I tested this using a qemu-system for Armv7 and PPC6xx running a
Debian userland with all combinations of VMSPLIT and HIGHMEM options. I
ran some kernel builds on the Arm guest to ensure that the new options
don't cause functional or performance regressions for regular workloads
that don't exceed the virtual address space. I also ran some tests
with Firefox and was positively surprised to see that this still works
on the VMSPLIT_2G_OPT configuration without highmem, though it gets
close to both the address space and lowmem size limits.

The change to use VMSPLIT_3G_OPT by default on Armv5 means that I could
include a patch to no longer support highmem at all on VIVT caches,
as suggested by Jason Gunthorpe.

     Arnd

Link: https://lpc.events/event/19/contributions/2261/

Arnd Bergmann (4):
  arch/*: increase lowmem size to avoid highmem use
  ARM: add CONFIG_VMSPLIT_2G_OPT option
  ARM: remove support for highmem on VIVT
  mm: remove ARCH_NEEDS_KMAP_HIGH_GET

 arch/arm/Kconfig                            |  12 ++-
 arch/arm/configs/aspeed_g5_defconfig        |   1 -
 arch/arm/configs/dove_defconfig             |   2 -
 arch/arm/configs/gemini_defconfig           |   1 -
 arch/arm/configs/multi_v5_defconfig         |   1 -
 arch/arm/configs/mv78xx0_defconfig          |   2 -
 arch/arm/configs/mvebu_v5_defconfig         |   1 -
 arch/arm/configs/u8500_defconfig            |   1 -
 arch/arm/configs/vt8500_v6_v7_defconfig     |   3 -
 arch/arm/include/asm/highmem.h              |  56 +----------
 arch/arm/mach-omap2/Kconfig                 |   1 -
 arch/arm/mm/cache-feroceon-l2.c             |  31 +-----
 arch/arm/mm/cache-xsc3l2.c                  |  47 +--------
 arch/arm/mm/dma-mapping.c                   |  12 +--
 arch/arm/mm/flush.c                         |  19 +---
 arch/microblaze/Kconfig                     |   9 +-
 arch/microblaze/configs/mmu_defconfig       |   1 -
 arch/powerpc/Kconfig                        |  17 ++--
 arch/powerpc/configs/44x/akebono_defconfig  |   1 -
 arch/powerpc/configs/85xx/ksi8560_defconfig |   1 -
 arch/powerpc/configs/85xx/stx_gp3_defconfig |   1 -
 arch/x86/Kconfig                            |   4 +-
 mm/highmem.c                                | 100 ++------------------
 23 files changed, 56 insertions(+), 268 deletions(-)

-- 
2.39.5

Cc: Andrew Morton <akpm at linux-foundation.org>
Cc: Andreas Larsson <andreas at gaisler.com>
Cc: Christophe Leroy (CS GROUP) <chleroy at kernel.org>
Cc: Dave Hansen <dave.hansen at linux.intel.com>
Cc: Jason Gunthorpe <jgg at nvidia.com>
Cc: Linus Walleij <linus.walleij at linaro.org>
Cc: Matthew Wilcox <willy at infradead.org>
Cc: Richard Weinberger <richard at nod.at>
Cc: Russell King <linux at armlinux.org.uk>
Cc: linux-mm at kvack.org
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-fsdevel at vger.kernel.org
Cc: linuxppc-dev at lists.ozlabs.org
Cc: x86 at kernel.org
Signed-off-by: Arnd Bergmann <arnd at arndb.de>



From arnd at kernel.org  Fri Dec 19 08:15:56 2025
From: arnd at kernel.org (Arnd Bergmann)
Date: Fri, 19 Dec 2025 17:15:56 +0100
Subject: [PATCH 1/4] arch/*: increase lowmem size to avoid highmem use
In-Reply-To: <20251219161559.556737-1-arnd@kernel.org>
References: <20251219161559.556737-1-arnd@kernel.org>
Message-ID: <20251219161559.556737-2-arnd@kernel.org>

From: Arnd Bergmann <arnd at arndb.de>

Most of the common 32-bit architectures (x86, arm, powerpc) all use the
default virtual memory layout that was already in place for i386 systems
in the 1990s, using exactly 3GiB of user TASK_SIZE, with the upper 1GiB
of addresses split between (at most 896MiB) lowmem and vmalloc.

Linux-2.3 introduced CONFIG_HIGHMEM for large x86 server machines that
had 4GiB of RAM or more, with the VMSPLIT_3G/2G/1G options added in
v2.6.16 for machines that had one or two gigabytes of memory but wanted
to avoid the overhead from managing highmem. Over time, similar options
appeared on other 32-bit architectures.

Twenty years later, it makes sense to reconsider the default settings,
as the tradeoffs have changed a bit:

 - Configurations with more than 2GiB have become extremely rare,
   as any users with large memory have moved on to 64-bit systems.
   There were only ever a few Laptop models in this category: Apple
   Powerbook G4 (2005), Macbook (2006), IBM Thinkpad X60 (2006), Arm
   Chromebooks based on Exynos 5800 (2014), Tegra K1 (2014) and RK3288
   (2015), and manufacturer support for all of these has ended in 2020
   or (much) earlier.
   Embedded systems with more than 2GiB use additional SoCs of a
   similar vintage: Intel Atom Z5xx (2008), Freescale QorIQ (2008),
   Marvell Armada XP (2010), Freescale i.MX6Q (2011), LSI Axxia (2013),
   TI Keystone2 (2014), Renesas RZ/G1M (2015). Most boards based on
   these have stopped receiving kernel upgrades. Newer 32-bit chips
   only support smaller memory configurations, though in particular the
   i.MX6Q and Keystone2 families have expected support cycles past 2035.
   While 32-bit server installations used to support even larger memory,
   none of those seem to still be used in production on any architecture.

 - While general-purpose distributes for 32-bit targets were common,
   it was rather risky to change the CONFIG_VMSPLIT setting because
   there is always a possibility of running into device driver bugs or
   applications that need a large virtual memory size. Presumably
   a lot of these issues have been resolved now, so most setups should
   be fine using a custom vmsplit instead of highmem now.

 - As fewer users test highmem, the expectation is that it will
   increasingly break in the future, so getting users to change the
   vmsplit means that even if there is a bug to fix initially,
   it improves the situation in the long run.

 - Highmem will ultimately need to be removed, at least for the page
   cache and most other code using it today. In a previous discussion, I
   had suggested doing this as early as 2029, but based on the discussions
   since ELC, the plan is now to leave highmem-enabled page cache as an
   option until at least 2029, at which point remaining users will have
   the choice between no longer updating kernels or using a combination of
   a custom vmsplit and zram/zswap. Changing the defaults now should both
   speed up the highmem deprecation and make it less painful for users.

 - The most VM space intensive applications tend to be web browsers,
   specifcally Chrome/ChromeOS and Firefox. Both have now stopped
   providing binary updates, but Firefox can still be built from source.
   Testing various combinations on Debian/armhf, I found that Firefox 140
   can still show complex websites with VMSPLIT_2G_OPT with and without
   HIGHMEM, though it failed for me both with the small address space
   of VMSPLIT_1G and the small lowmem of VMSPLIT_3G_OPT when HIGHMEM
   is disabled.
   This is likely to get worse with future versions, so embedded users
   may still be forced to migrate to specialized browsers like WPE Webkit
   when HIGHMEM pagecache is finally removed.

Based on the above observations and the discussion at the kernel summit,
change the defaults to the most appropriate values: use 1GiB of lowmem on
non-highmem configurations, and either 2GiB or 1.75GiB of lowmem on highmem
builds, depending on what is available on the architecture.  As ARM_LPAE
and X86_PAE builds both require a gigabyte-aligned vmsplit, those get
to use VMSPLIT_2G. The result is that the majority of previous highmem
users now only need lowmem. For platform specific defconfig files that
are known to only support up to 1GiB of RAM, drop the CONFIG_HIGHMEM line
as well as a simplification.

On PowerPC and Microblaze, the options have somewhat different names but
should have the same effect. MIPS and Xtensa cannot support a larger
than 512MB of lowmem but are limited to small DDR2 memory in most
implementations, with MT7621 being a notable exception. ARC and C-Sky
could support a configurable vmsplit in theory, but it's not clear
if anyone still cares.
SPARC is currently limited to 192MB of lowmem and should get patched
to behave either like arm/x86 or powerpc/microblaze to support 2GiB
of lowmem.

There are likely going to be regressions from the changed defaults,
in particular when hitting previously hidden device driver bugs
that fail to set the correct DMA mask, or from applications that
need a large virtual address space.
Ideally the in-kernel problems should all be fixable, but the previous
behavior is still selectable as a fallback with CONFIG_EXPERT=y

Cc: Russell King <linux at armlinux.org.uk>
Cc: linux-arm-kernel at lists.infradead.org
Cc: Thomas Gleixner <tglx at linutronix.de>
Cc: Ingo Molnar <mingo at redhat.com>
Cc: Borislav Petkov <bp at alien8.de>
Cc: Dave Hansen <dave.hansen at linux.intel.com>
Cc: x86 at kernel.org
Cc: "H. Peter Anvin" <hpa at zytor.com>
Cc: Madhavan Srinivasan <maddy at linux.ibm.com>
Cc: Michael Ellerman <mpe at ellerman.id.au>
Cc: Nicholas Piggin <npiggin at gmail.com>
Cc: Christophe Leroy (CS GROUP) <chleroy at kernel.org>
Cc: linuxppc-dev at lists.ozlabs.org
Cc: Michal Simek <monstr at monstr.eu>
Cc: Andrew Morton <akpm at linux-foundation.org>
Cc: David Hildenbrand <david at kernel.org>
Cc: Lorenzo Stoakes <lorenzo.stoakes at oracle.com>
Cc: Liam R. Howlett <Liam.Howlett at oracle.com>
Cc: Vlastimil Babka <vbabka at suse.cz>
Cc: Mike Rapoport <rppt at kernel.org>
Cc: Suren Baghdasaryan <surenb at google.com>
Cc: Michal Hocko <mhocko at suse.com>
Cc: Matthew Wilcox <willy at infradead.org>
Cc: linux-mm at kvack.org
Cc: Richard Weinberger <richard at nod.at>
Cc: Linus Walleij <linus.walleij at linaro.org>
Cc: Nishanth Menon <nm at ti.com>
Cc: Andreas Larsson <andreas at gaisler.com>
Cc: Lucas Stach <l.stach at pengutronix.de>
Signed-off-by: Arnd Bergmann <arnd at arndb.de>
---
 arch/arm/Kconfig                            |  5 ++++-
 arch/arm/configs/aspeed_g5_defconfig        |  1 -
 arch/arm/configs/dove_defconfig             |  2 --
 arch/arm/configs/mv78xx0_defconfig          |  2 --
 arch/arm/configs/u8500_defconfig            |  1 -
 arch/arm/configs/vt8500_v6_v7_defconfig     |  3 ---
 arch/arm/mach-omap2/Kconfig                 |  1 -
 arch/microblaze/Kconfig                     |  9 ++++++---
 arch/microblaze/configs/mmu_defconfig       |  1 -
 arch/powerpc/Kconfig                        | 17 +++++++++++------
 arch/powerpc/configs/44x/akebono_defconfig  |  1 -
 arch/powerpc/configs/85xx/ksi8560_defconfig |  1 -
 arch/powerpc/configs/85xx/stx_gp3_defconfig |  1 -
 arch/x86/Kconfig                            |  4 +++-
 14 files changed, 24 insertions(+), 25 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index fa83c040ee2d..7c0ac017e086 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1009,7 +1009,8 @@ config BL_SWITCHER_DUMMY_IF
 choice
 	prompt "Memory split"
 	depends on MMU
-	default VMSPLIT_3G
+	default VMSPLIT_2G if HIGHMEM || ARM_LPAE
+	default VMSPLIT_3G_OPT
 	help
 	  Select the desired split between kernel and user memory.
 
@@ -1018,8 +1019,10 @@ choice
 
 	config VMSPLIT_3G
 		bool "3G/1G user/kernel split"
+		depends on !HIGHMEM || EXPERT
 	config VMSPLIT_3G_OPT
 		depends on !ARM_LPAE
+		depends on !HIGHMEM || EXPERT
 		bool "3G/1G user/kernel split (for full 1G low memory)"
 	config VMSPLIT_2G
 		bool "2G/2G user/kernel split"
diff --git a/arch/arm/configs/aspeed_g5_defconfig b/arch/arm/configs/aspeed_g5_defconfig
index 2e6ea13c1e9b..be5ea1775b3f 100644
--- a/arch/arm/configs/aspeed_g5_defconfig
+++ b/arch/arm/configs/aspeed_g5_defconfig
@@ -27,7 +27,6 @@ CONFIG_SMP=y
 # CONFIG_ARM_CPU_TOPOLOGY is not set
 CONFIG_VMSPLIT_2G=y
 CONFIG_NR_CPUS=2
-CONFIG_HIGHMEM=y
 CONFIG_UACCESS_WITH_MEMCPY=y
 # CONFIG_ATAGS is not set
 CONFIG_VFP=y
diff --git a/arch/arm/configs/dove_defconfig b/arch/arm/configs/dove_defconfig
index e98c35df675e..75c67678c4ba 100644
--- a/arch/arm/configs/dove_defconfig
+++ b/arch/arm/configs/dove_defconfig
@@ -7,8 +7,6 @@ CONFIG_EXPERT=y
 CONFIG_ARCH_MULTI_V7=y
 CONFIG_ARCH_DOVE=y
 CONFIG_MACH_CM_A510=y
-CONFIG_AEABI=y
-CONFIG_HIGHMEM=y
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_VFP=y
diff --git a/arch/arm/configs/mv78xx0_defconfig b/arch/arm/configs/mv78xx0_defconfig
index d3a26efe766c..cbd47155eca9 100644
--- a/arch/arm/configs/mv78xx0_defconfig
+++ b/arch/arm/configs/mv78xx0_defconfig
@@ -11,7 +11,6 @@ CONFIG_ARCH_MULTI_V5=y
 CONFIG_ARCH_MV78XX0=y
 CONFIG_MACH_TERASTATION_WXL=y
 CONFIG_AEABI=y
-CONFIG_HIGHMEM=y
 CONFIG_FPE_NWFPE=y
 CONFIG_VFP=y
 CONFIG_KPROBES=y
diff --git a/arch/arm/configs/u8500_defconfig b/arch/arm/configs/u8500_defconfig
index e88533b78327..a53269cbe475 100644
--- a/arch/arm/configs/u8500_defconfig
+++ b/arch/arm/configs/u8500_defconfig
@@ -6,7 +6,6 @@ CONFIG_KALLSYMS_ALL=y
 CONFIG_ARCH_U8500=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=2
-CONFIG_HIGHMEM=y
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_CMDLINE="root=/dev/ram0 console=ttyAMA2,115200n8"
diff --git a/arch/arm/configs/vt8500_v6_v7_defconfig b/arch/arm/configs/vt8500_v6_v7_defconfig
index 41607a84abc8..1f6dca21d569 100644
--- a/arch/arm/configs/vt8500_v6_v7_defconfig
+++ b/arch/arm/configs/vt8500_v6_v7_defconfig
@@ -8,8 +8,6 @@ CONFIG_ARM_ERRATA_720789=y
 CONFIG_ARM_ERRATA_775420=y
 CONFIG_HAVE_ARM_ARCH_TIMER=y
 CONFIG_AEABI=y
-CONFIG_HIGHMEM=y
-CONFIG_HIGHPTE=y
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_VFP=y
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 821727eefd5a..4a2591985ff3 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -135,7 +135,6 @@ config ARCH_OMAP2PLUS_TYPICAL
 	bool "Typical OMAP configuration"
 	default y
 	select AEABI
-	select HIGHMEM
 	select I2C
 	select I2C_OMAP
 	select MENELAUS if ARCH_OMAP2
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig
index 484ebb3baedf..c25b8185bbbd 100644
--- a/arch/microblaze/Kconfig
+++ b/arch/microblaze/Kconfig
@@ -163,7 +163,8 @@ config LOWMEM_SIZE_BOOL
 
 config LOWMEM_SIZE
 	hex "Maximum low memory size (in bytes)" if LOWMEM_SIZE_BOOL
-	default "0x30000000"
+	default "0x80000000" if HIGHMEM
+	default "0x40000000"
 
 config MANUAL_RESET_VECTOR
 	hex "Microblaze reset vector address setup"
@@ -189,7 +190,8 @@ config KERNEL_START_BOOL
 
 config KERNEL_START
 	hex "Virtual address of kernel base" if KERNEL_START_BOOL
-	default "0xc0000000"
+	default "0x70000000" if HIGHMEM
+	default "0xb0000000"
 
 config TASK_SIZE_BOOL
 	bool "Set custom user task size"
@@ -203,7 +205,8 @@ config TASK_SIZE_BOOL
 
 config TASK_SIZE
 	hex "Size of user task space" if TASK_SIZE_BOOL
-	default "0x80000000"
+	default "0x70000000" if HIGHMEM
+	default "0xb0000000"
 
 config MB_MANAGER
 	bool "Support for Microblaze Manager"
diff --git a/arch/microblaze/configs/mmu_defconfig b/arch/microblaze/configs/mmu_defconfig
index fbbdcb394ca2..255fa7b69117 100644
--- a/arch/microblaze/configs/mmu_defconfig
+++ b/arch/microblaze/configs/mmu_defconfig
@@ -15,7 +15,6 @@ CONFIG_XILINX_MICROBLAZE0_USE_FPU=2
 CONFIG_HZ_100=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE_FORCE=y
-CONFIG_HIGHMEM=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_PARTITION_ADVANCED=y
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 9537a61ebae0..1fa92ed8f28c 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -490,6 +490,7 @@ menu "Kernel options"
 config HIGHMEM
 	bool "High memory support"
 	depends on PPC32
+	depends on PPC_BOOK3S_32 || PPC_85xx || 44x
 	select KMAP_LOCAL
 
 source "kernel/Kconfig.hz"
@@ -1190,7 +1191,8 @@ config LOWMEM_SIZE_BOOL
 
 config LOWMEM_SIZE
 	hex "Maximum low memory size (in bytes)" if LOWMEM_SIZE_BOOL
-	default "0x30000000"
+	default "0x80000000" if HIGHMEM
+	default "0x40000000"
 
 config LOWMEM_CAM_NUM_BOOL
 	bool "Set number of CAMs to use to map low memory"
@@ -1242,7 +1244,8 @@ config PAGE_OFFSET_BOOL
 
 config PAGE_OFFSET
 	hex "Virtual address of memory base" if PAGE_OFFSET_BOOL
-	default "0xc0000000"
+	default "0x70000000" if HIGHMEM
+	default "0xb0000000"
 
 config KERNEL_START_BOOL
 	bool "Set custom kernel base address"
@@ -1258,8 +1261,9 @@ config KERNEL_START_BOOL
 config KERNEL_START
 	hex "Virtual address of kernel base" if KERNEL_START_BOOL
 	default PAGE_OFFSET if PAGE_OFFSET_BOOL
-	default "0xc2000000" if CRASH_DUMP && !NONSTATIC_KERNEL
-	default "0xc0000000"
+	default "0x72000000" if HIGHMEM && CRASH_DUMP && !NONSTATIC_KERNEL
+	default "0xb2000000" if CRASH_DUMP && !NONSTATIC_KERNEL
+	default PAGE_OFFSET
 
 config PHYSICAL_START_BOOL
 	bool "Set physical address where the kernel is loaded"
@@ -1295,8 +1299,9 @@ config TASK_SIZE_BOOL
 config TASK_SIZE
 	hex "Size of user task space" if TASK_SIZE_BOOL
 	default "0x80000000" if PPC_8xx
-	default "0xb0000000" if PPC_BOOK3S_32 && EXECMEM
-	default "0xc0000000"
+	default "0x60000000" if PPC_BOOK3S_32 && EXECMEM && HIGHMEM
+	default "0xa0000000" if PPC_BOOK3S_32 && EXECMEM
+	default PAGE_OFFSET
 
 config MODULES_SIZE_BOOL
 	bool "Set custom size for modules/execmem area"
diff --git a/arch/powerpc/configs/44x/akebono_defconfig b/arch/powerpc/configs/44x/akebono_defconfig
index 02e88648a2e6..992db368848f 100644
--- a/arch/powerpc/configs/44x/akebono_defconfig
+++ b/arch/powerpc/configs/44x/akebono_defconfig
@@ -14,7 +14,6 @@ CONFIG_MODULE_UNLOAD=y
 CONFIG_PPC_47x=y
 # CONFIG_EBONY is not set
 CONFIG_AKEBONO=y
-CONFIG_HIGHMEM=y
 CONFIG_HZ_100=y
 CONFIG_IRQ_ALL_CPUS=y
 # CONFIG_COMPACTION is not set
diff --git a/arch/powerpc/configs/85xx/ksi8560_defconfig b/arch/powerpc/configs/85xx/ksi8560_defconfig
index 9cb211fb6d1e..f2ac1fc41303 100644
--- a/arch/powerpc/configs/85xx/ksi8560_defconfig
+++ b/arch/powerpc/configs/85xx/ksi8560_defconfig
@@ -9,7 +9,6 @@ CONFIG_PARTITION_ADVANCED=y
 CONFIG_KSI8560=y
 CONFIG_CPM2=y
 CONFIG_GEN_RTC=y
-CONFIG_HIGHMEM=y
 CONFIG_BINFMT_MISC=y
 CONFIG_MATH_EMULATION=y
 # CONFIG_SECCOMP is not set
diff --git a/arch/powerpc/configs/85xx/stx_gp3_defconfig b/arch/powerpc/configs/85xx/stx_gp3_defconfig
index 0a42072fa23c..1033977711d6 100644
--- a/arch/powerpc/configs/85xx/stx_gp3_defconfig
+++ b/arch/powerpc/configs/85xx/stx_gp3_defconfig
@@ -7,7 +7,6 @@ CONFIG_MODULES=y
 CONFIG_MODVERSIONS=y
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_STX_GP3=y
-CONFIG_HIGHMEM=y
 CONFIG_BINFMT_MISC=m
 CONFIG_MATH_EMULATION=y
 CONFIG_PCI=y
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 80527299f859..b40c8fd6cac1 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1416,7 +1416,9 @@ config HIGHMEM4G
 
 choice
 	prompt "Memory split" if EXPERT
-	default VMSPLIT_3G
+	default VMSPLIT_2G_OPT if HIGHMEM && !X86_PAE
+	default VMSPLIT_2G if X86_PAE
+	default VMSPLIT_3G_OPT
 	depends on X86_32
 	help
 	  Select the desired split between kernel and user memory.
-- 
2.39.5



From arnd at kernel.org  Fri Dec 19 08:15:57 2025
From: arnd at kernel.org (Arnd Bergmann)
Date: Fri, 19 Dec 2025 17:15:57 +0100
Subject: [PATCH 2/4] ARM: add CONFIG_VMSPLIT_2G_OPT option
In-Reply-To: <20251219161559.556737-1-arnd@kernel.org>
References: <20251219161559.556737-1-arnd@kernel.org>
Message-ID: <20251219161559.556737-3-arnd@kernel.org>

From: Arnd Bergmann <arnd at arndb.de>

Unlike x86 and powerpc, there is currently no option to use exactly 2GiB
of lowmem on Arm. Since 2GiB is still a relatively common configuration
on embedded systems, it makes sense to allow this to be used in
non-highmem builds.

Add the Kconfig option and make this the default for non-LPAE builds
with highmem enabled instead of CONFIG_VMSPLIT_2G.  LPAE still requires
the vmsplit to be on a gigabyte boundary, so this is only available for
classic pagetables at the moment, same as CONFIG_VMSPLIT_3G_OPT.

Tested in qemu -M virt, both with and without HIGHMEM enabled.

Signed-off-by: Arnd Bergmann <arnd at arndb.de>
---
 arch/arm/Kconfig | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 7c0ac017e086..921ea61aa96e 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1009,7 +1009,8 @@ config BL_SWITCHER_DUMMY_IF
 choice
 	prompt "Memory split"
 	depends on MMU
-	default VMSPLIT_2G if HIGHMEM || ARM_LPAE
+	default VMSPLIT_2G if ARM_LPAE
+	default VMSPLIT_2G_OPT if HIGHMEM
 	default VMSPLIT_3G_OPT
 	help
 	  Select the desired split between kernel and user memory.
@@ -1026,6 +1027,9 @@ choice
 		bool "3G/1G user/kernel split (for full 1G low memory)"
 	config VMSPLIT_2G
 		bool "2G/2G user/kernel split"
+	config VMSPLIT_2G_OPT
+		depends on !ARM_LPAE
+		bool "2G/2G user/kernel split (for full 2G low memory)"
 	config VMSPLIT_1G
 		bool "1G/3G user/kernel split"
 endchoice
@@ -1034,6 +1038,7 @@ config PAGE_OFFSET
 	hex
 	default PHYS_OFFSET if !MMU
 	default 0x40000000 if VMSPLIT_1G
+	default 0x70000000 if VMSPLIT_2G_OPT
 	default 0x80000000 if VMSPLIT_2G
 	default 0xB0000000 if VMSPLIT_3G_OPT
 	default 0xC0000000
@@ -1042,6 +1047,7 @@ config KASAN_SHADOW_OFFSET
 	hex
 	depends on KASAN
 	default 0x1f000000 if PAGE_OFFSET=0x40000000
+	default 0x4f000000 if PAGE_OFFSET=0x70000000
 	default 0x5f000000 if PAGE_OFFSET=0x80000000
 	default 0x9f000000 if PAGE_OFFSET=0xC0000000
 	default 0x8f000000 if PAGE_OFFSET=0xB0000000
-- 
2.39.5



From arnd at kernel.org  Fri Dec 19 08:15:58 2025
From: arnd at kernel.org (Arnd Bergmann)
Date: Fri, 19 Dec 2025 17:15:58 +0100
Subject: [PATCH 3/4] ARM: remove support for highmem on VIVT
In-Reply-To: <20251219161559.556737-1-arnd@kernel.org>
References: <20251219161559.556737-1-arnd@kernel.org>
Message-ID: <20251219161559.556737-4-arnd@kernel.org>

From: Arnd Bergmann <arnd at arndb.de>

As Jason Gunthorpe noticed, supporting VIVT caches adds some complications
to highmem that can be avoided these days:

While all ARMv4 and ARMv5 CPUs use virtually indexed caches, they no
longer really need highmem because we have practically discontinued
support for large-memory configurations already.  The only machines I
could find anywhere for memory on ARMv5 are:

 - The Intel IOP platform was used on relatively large memory
   configurations but we dropped kernel support in 2019 and 2022,
   respectively.

 - The Marvell mv78xx0 platform was the initial user of Arm highmem,
   with the DB-78x00-BP supporting 2GB of memory. While the platform
   is still around, the only remaining board file is for
   Buffalo WLX (Terastation Duo), which has only 512MB.

 - The Kirkwood platform supports 2GB, and there are actually boards
   with that configuration that can still work. However, there are
   no known users of the OpenBlocks A7, and the Freebox V6 is already
   using CONFIG_VMSPLIT_2G to avoid enabling highmem.

Remove the Arm specific portions here, making CONFIG_HIGHMEM conditional
on modern caches.

Suggested-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Arnd Bergmann <arnd at arndb.de>
---
 arch/arm/Kconfig                    |  1 +
 arch/arm/configs/gemini_defconfig   |  1 -
 arch/arm/configs/multi_v5_defconfig |  1 -
 arch/arm/configs/mvebu_v5_defconfig |  1 -
 arch/arm/include/asm/highmem.h      | 56 ++---------------------------
 arch/arm/mm/cache-feroceon-l2.c     | 31 ++--------------
 arch/arm/mm/cache-xsc3l2.c          | 47 +++---------------------
 arch/arm/mm/dma-mapping.c           | 12 ++-----
 arch/arm/mm/flush.c                 | 19 +++-------
 9 files changed, 16 insertions(+), 153 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 921ea61aa96e..790897a457d4 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1204,6 +1204,7 @@ config ARCH_SPARSEMEM_ENABLE
 config HIGHMEM
 	bool "High Memory Support"
 	depends on MMU
+	depends on !CPU_CACHE_VIVT
 	select KMAP_LOCAL
 	select KMAP_LOCAL_NON_LINEAR_PTE_ARRAY
 	help
diff --git a/arch/arm/configs/gemini_defconfig b/arch/arm/configs/gemini_defconfig
index 7b1daec630cb..1bb4f47ea3c8 100644
--- a/arch/arm/configs/gemini_defconfig
+++ b/arch/arm/configs/gemini_defconfig
@@ -12,7 +12,6 @@ CONFIG_ARCH_MULTI_V4=y
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_GEMINI=y
 CONFIG_AEABI=y
-CONFIG_HIGHMEM=y
 CONFIG_CMDLINE="console=ttyS0,115200n8"
 CONFIG_PM=y
 CONFIG_PARTITION_ADVANCED=y
diff --git a/arch/arm/configs/multi_v5_defconfig b/arch/arm/configs/multi_v5_defconfig
index 59b020e66a0b..5106fc2d2a00 100644
--- a/arch/arm/configs/multi_v5_defconfig
+++ b/arch/arm/configs/multi_v5_defconfig
@@ -37,7 +37,6 @@ CONFIG_MACH_MSS2_DT=y
 CONFIG_ARCH_SUNXI=y
 CONFIG_ARCH_VERSATILE=y
 CONFIG_AEABI=y
-CONFIG_HIGHMEM=y
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_CPU_FREQ=y
diff --git a/arch/arm/configs/mvebu_v5_defconfig b/arch/arm/configs/mvebu_v5_defconfig
index d1742a7cae6a..ba17bd3237fb 100644
--- a/arch/arm/configs/mvebu_v5_defconfig
+++ b/arch/arm/configs/mvebu_v5_defconfig
@@ -24,7 +24,6 @@ CONFIG_MACH_D2NET_DT=y
 CONFIG_MACH_NET2BIG=y
 CONFIG_MACH_MSS2_DT=y
 CONFIG_AEABI=y
-CONFIG_HIGHMEM=y
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_CPU_FREQ=y
diff --git a/arch/arm/include/asm/highmem.h b/arch/arm/include/asm/highmem.h
index bdb209e002a4..67ed46d1922b 100644
--- a/arch/arm/include/asm/highmem.h
+++ b/arch/arm/include/asm/highmem.h
@@ -11,66 +11,14 @@
 #define PKMAP_NR(virt)		(((virt) - PKMAP_BASE) >> PAGE_SHIFT)
 #define PKMAP_ADDR(nr)		(PKMAP_BASE + ((nr) << PAGE_SHIFT))
 
-#define flush_cache_kmaps() \
-	do { \
-		if (cache_is_vivt()) \
-			flush_cache_all(); \
-	} while (0)
+#define flush_cache_kmaps() do { } while (0)
 
 extern pte_t *pkmap_page_table;
 
-/*
- * The reason for kmap_high_get() is to ensure that the currently kmap'd
- * page usage count does not decrease to zero while we're using its
- * existing virtual mapping in an atomic context.  With a VIVT cache this
- * is essential to do, but with a VIPT cache this is only an optimization
- * so not to pay the price of establishing a second mapping if an existing
- * one can be used.  However, on platforms without hardware TLB maintenance
- * broadcast, we simply cannot use ARCH_NEEDS_KMAP_HIGH_GET at all since
- * the locking involved must also disable IRQs which is incompatible with
- * the IPI mechanism used by global TLB operations.
- */
-#define ARCH_NEEDS_KMAP_HIGH_GET
-#if defined(CONFIG_SMP) && defined(CONFIG_CPU_TLB_V6)
-#undef ARCH_NEEDS_KMAP_HIGH_GET
-#if defined(CONFIG_HIGHMEM) && defined(CONFIG_CPU_CACHE_VIVT)
-#error "The sum of features in your kernel config cannot be supported together"
-#endif
-#endif
-
-/*
- * Needed to be able to broadcast the TLB invalidation for kmap.
- */
-#ifdef CONFIG_ARM_ERRATA_798181
-#undef ARCH_NEEDS_KMAP_HIGH_GET
-#endif
-
-#ifdef ARCH_NEEDS_KMAP_HIGH_GET
-extern void *kmap_high_get(const struct page *page);
-
-static inline void *arch_kmap_local_high_get(const struct page *page)
-{
-	if (IS_ENABLED(CONFIG_DEBUG_HIGHMEM) && !cache_is_vivt())
-		return NULL;
-	return kmap_high_get(page);
-}
-#define arch_kmap_local_high_get arch_kmap_local_high_get
-
-#else /* ARCH_NEEDS_KMAP_HIGH_GET */
-static inline void *kmap_high_get(const struct page *page)
-{
-	return NULL;
-}
-#endif /* !ARCH_NEEDS_KMAP_HIGH_GET */
-
 #define arch_kmap_local_post_map(vaddr, pteval)				\
 	local_flush_tlb_kernel_page(vaddr)
 
-#define arch_kmap_local_pre_unmap(vaddr)				\
-do {									\
-	if (cache_is_vivt())						\
-		__cpuc_flush_dcache_area((void *)vaddr, PAGE_SIZE);	\
-} while (0)
+#define arch_kmap_local_pre_unmap(vaddr) do { } while (0)
 
 #define arch_kmap_local_post_unmap(vaddr)				\
 	local_flush_tlb_kernel_page(vaddr)
diff --git a/arch/arm/mm/cache-feroceon-l2.c b/arch/arm/mm/cache-feroceon-l2.c
index 2bfefb252ffd..1316b6ab295a 100644
--- a/arch/arm/mm/cache-feroceon-l2.c
+++ b/arch/arm/mm/cache-feroceon-l2.c
@@ -12,7 +12,6 @@
 #include <linux/init.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
-#include <linux/highmem.h>
 #include <linux/io.h>
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
@@ -38,30 +37,6 @@
  * between which we don't want to be preempted.
  */
 
-static inline unsigned long l2_get_va(unsigned long paddr)
-{
-#ifdef CONFIG_HIGHMEM
-	/*
-	 * Because range ops can't be done on physical addresses,
-	 * we simply install a virtual mapping for it only for the
-	 * TLB lookup to occur, hence no need to flush the untouched
-	 * memory mapping afterwards (note: a cache flush may happen
-	 * in some circumstances depending on the path taken in kunmap_atomic).
-	 */
-	void *vaddr = kmap_atomic_pfn(paddr >> PAGE_SHIFT);
-	return (unsigned long)vaddr + (paddr & ~PAGE_MASK);
-#else
-	return __phys_to_virt(paddr);
-#endif
-}
-
-static inline void l2_put_va(unsigned long vaddr)
-{
-#ifdef CONFIG_HIGHMEM
-	kunmap_atomic((void *)vaddr);
-#endif
-}
-
 static inline void l2_clean_pa(unsigned long addr)
 {
 	__asm__("mcr p15, 1, %0, c15, c9, 3" : : "r" (addr));
@@ -78,14 +53,13 @@ static inline void l2_clean_pa_range(unsigned long start, unsigned long end)
 	 */
 	BUG_ON((start ^ end) >> PAGE_SHIFT);
 
-	va_start = l2_get_va(start);
+	va_start = __phys_to_virt(start);
 	va_end = va_start + (end - start);
 	raw_local_irq_save(flags);
 	__asm__("mcr p15, 1, %0, c15, c9, 4\n\t"
 		"mcr p15, 1, %1, c15, c9, 5"
 		: : "r" (va_start), "r" (va_end));
 	raw_local_irq_restore(flags);
-	l2_put_va(va_start);
 }
 
 static inline void l2_clean_inv_pa(unsigned long addr)
@@ -109,14 +83,13 @@ static inline void l2_inv_pa_range(unsigned long start, unsigned long end)
 	 */
 	BUG_ON((start ^ end) >> PAGE_SHIFT);
 
-	va_start = l2_get_va(start);
+	va_start = __phys_to_virt(start);
 	va_end = va_start + (end - start);
 	raw_local_irq_save(flags);
 	__asm__("mcr p15, 1, %0, c15, c11, 4\n\t"
 		"mcr p15, 1, %1, c15, c11, 5"
 		: : "r" (va_start), "r" (va_end));
 	raw_local_irq_restore(flags);
-	l2_put_va(va_start);
 }
 
 static inline void l2_inv_all(void)
diff --git a/arch/arm/mm/cache-xsc3l2.c b/arch/arm/mm/cache-xsc3l2.c
index d20d7af02d10..477077387039 100644
--- a/arch/arm/mm/cache-xsc3l2.c
+++ b/arch/arm/mm/cache-xsc3l2.c
@@ -5,7 +5,6 @@
  * Copyright (C) 2007 ARM Limited
  */
 #include <linux/init.h>
-#include <linux/highmem.h>
 #include <asm/cp15.h>
 #include <asm/cputype.h>
 #include <asm/cacheflush.h>
@@ -55,34 +54,6 @@ static inline void xsc3_l2_inv_all(void)
 	dsb();
 }
 
-static inline void l2_unmap_va(unsigned long va)
-{
-#ifdef CONFIG_HIGHMEM
-	if (va != -1)
-		kunmap_atomic((void *)va);
-#endif
-}
-
-static inline unsigned long l2_map_va(unsigned long pa, unsigned long prev_va)
-{
-#ifdef CONFIG_HIGHMEM
-	unsigned long va = prev_va & PAGE_MASK;
-	unsigned long pa_offset = pa << (32 - PAGE_SHIFT);
-	if (unlikely(pa_offset < (prev_va << (32 - PAGE_SHIFT)))) {
-		/*
-		 * Switching to a new page.  Because cache ops are
-		 * using virtual addresses only, we must put a mapping
-		 * in place for it.
-		 */
-		l2_unmap_va(prev_va);
-		va = (unsigned long)kmap_atomic_pfn(pa >> PAGE_SHIFT);
-	}
-	return va + (pa_offset >> (32 - PAGE_SHIFT));
-#else
-	return __phys_to_virt(pa);
-#endif
-}
-
 static void xsc3_l2_inv_range(unsigned long start, unsigned long end)
 {
 	unsigned long vaddr;
@@ -92,13 +63,11 @@ static void xsc3_l2_inv_range(unsigned long start, unsigned long end)
 		return;
 	}
 
-	vaddr = -1;  /* to force the first mapping */
-
 	/*
 	 * Clean and invalidate partial first cache line.
 	 */
 	if (start & (CACHE_LINE_SIZE - 1)) {
-		vaddr = l2_map_va(start & ~(CACHE_LINE_SIZE - 1), vaddr);
+		vaddr = __phys_to_virt(start & ~(CACHE_LINE_SIZE - 1));
 		xsc3_l2_clean_mva(vaddr);
 		xsc3_l2_inv_mva(vaddr);
 		start = (start | (CACHE_LINE_SIZE - 1)) + 1;
@@ -108,7 +77,7 @@ static void xsc3_l2_inv_range(unsigned long start, unsigned long end)
 	 * Invalidate all full cache lines between 'start' and 'end'.
 	 */
 	while (start < (end & ~(CACHE_LINE_SIZE - 1))) {
-		vaddr = l2_map_va(start, vaddr);
+		vaddr = __phys_to_virt(start);
 		xsc3_l2_inv_mva(vaddr);
 		start += CACHE_LINE_SIZE;
 	}
@@ -117,13 +86,11 @@ static void xsc3_l2_inv_range(unsigned long start, unsigned long end)
 	 * Clean and invalidate partial last cache line.
 	 */
 	if (start < end) {
-		vaddr = l2_map_va(start, vaddr);
+		vaddr = __phys_to_virt(start);
 		xsc3_l2_clean_mva(vaddr);
 		xsc3_l2_inv_mva(vaddr);
 	}
 
-	l2_unmap_va(vaddr);
-
 	dsb();
 }
 
@@ -135,13 +102,11 @@ static void xsc3_l2_clean_range(unsigned long start, unsigned long end)
 
 	start &= ~(CACHE_LINE_SIZE - 1);
 	while (start < end) {
-		vaddr = l2_map_va(start, vaddr);
+		vaddr = __phys_to_virt(start);
 		xsc3_l2_clean_mva(vaddr);
 		start += CACHE_LINE_SIZE;
 	}
 
-	l2_unmap_va(vaddr);
-
 	dsb();
 }
 
@@ -178,14 +143,12 @@ static void xsc3_l2_flush_range(unsigned long start, unsigned long end)
 
 	start &= ~(CACHE_LINE_SIZE - 1);
 	while (start < end) {
-		vaddr = l2_map_va(start, vaddr);
+		vaddr = __phys_to_virt(start);
 		xsc3_l2_clean_mva(vaddr);
 		xsc3_l2_inv_mva(vaddr);
 		start += CACHE_LINE_SIZE;
 	}
 
-	l2_unmap_va(vaddr);
-
 	dsb();
 }
 
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index a4c765d24692..696f6f1f259e 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -647,18 +647,10 @@ static void dma_cache_maint_page(phys_addr_t phys, size_t size,
 			if (len + offset > PAGE_SIZE)
 				len = PAGE_SIZE - offset;
 
-			if (cache_is_vipt_nonaliasing()) {
-				vaddr = kmap_atomic_pfn(pfn);
+			vaddr = kmap_atomic(phys_to_page(phys));
+			if (vaddr) {
 				op(vaddr + offset, len, dir);
 				kunmap_atomic(vaddr);
-			} else {
-				struct page *page = phys_to_page(phys);
-
-				vaddr = kmap_high_get(page);
-				if (vaddr) {
-					op(vaddr + offset, len, dir);
-					kunmap_high(page);
-				}
 			}
 		} else {
 			phys += offset;
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
index 19470d938b23..998b75f77364 100644
--- a/arch/arm/mm/flush.c
+++ b/arch/arm/mm/flush.c
@@ -208,21 +208,10 @@ void __flush_dcache_folio(struct address_space *mapping, struct folio *folio)
 					folio_size(folio));
 	} else {
 		unsigned long i;
-		if (cache_is_vipt_nonaliasing()) {
-			for (i = 0; i < folio_nr_pages(folio); i++) {
-				void *addr = kmap_local_folio(folio,
-								i * PAGE_SIZE);
-				__cpuc_flush_dcache_area(addr, PAGE_SIZE);
-				kunmap_local(addr);
-			}
-		} else {
-			for (i = 0; i < folio_nr_pages(folio); i++) {
-				void *addr = kmap_high_get(folio_page(folio, i));
-				if (addr) {
-					__cpuc_flush_dcache_area(addr, PAGE_SIZE);
-					kunmap_high(folio_page(folio, i));
-				}
-			}
+		for (i = 0; i < folio_nr_pages(folio); i++) {
+			void *addr = kmap_local_folio(folio, i * PAGE_SIZE);
+			__cpuc_flush_dcache_area(addr, PAGE_SIZE);
+			kunmap_local(addr);
 		}
 	}
 
-- 
2.39.5



From arnd at kernel.org  Fri Dec 19 08:15:59 2025
From: arnd at kernel.org (Arnd Bergmann)
Date: Fri, 19 Dec 2025 17:15:59 +0100
Subject: [PATCH 4/4] mm: remove ARCH_NEEDS_KMAP_HIGH_GET
In-Reply-To: <20251219161559.556737-1-arnd@kernel.org>
References: <20251219161559.556737-1-arnd@kernel.org>
Message-ID: <20251219161559.556737-5-arnd@kernel.org>

From: Arnd Bergmann <arnd at arndb.de>

Arm has stopped setting ARCH_NEEDS_KMAP_HIGH_GET, so this
is handled using the same wrappers across all architectures
now, which leaves room for simplification.

Replace lock_kmap()/unlock_kmap() with open-coded spinlocks
and drop the now empty arch_kmap_local_high_get() and
kmap_high_unmap_local() helpers.

Signed-off-by: Arnd Bergmann <arnd at arndb.de>
---
 mm/highmem.c | 100 ++++++---------------------------------------------
 1 file changed, 10 insertions(+), 90 deletions(-)

diff --git a/mm/highmem.c b/mm/highmem.c
index b5c8e4c2d5d4..bdeec56471c9 100644
--- a/mm/highmem.c
+++ b/mm/highmem.c
@@ -143,25 +143,6 @@ static  __cacheline_aligned_in_smp DEFINE_SPINLOCK(kmap_lock);
 
 pte_t *pkmap_page_table;
 
-/*
- * Most architectures have no use for kmap_high_get(), so let's abstract
- * the disabling of IRQ out of the locking in that case to save on a
- * potential useless overhead.
- */
-#ifdef ARCH_NEEDS_KMAP_HIGH_GET
-#define lock_kmap()             spin_lock_irq(&kmap_lock)
-#define unlock_kmap()           spin_unlock_irq(&kmap_lock)
-#define lock_kmap_any(flags)    spin_lock_irqsave(&kmap_lock, flags)
-#define unlock_kmap_any(flags)  spin_unlock_irqrestore(&kmap_lock, flags)
-#else
-#define lock_kmap()             spin_lock(&kmap_lock)
-#define unlock_kmap()           spin_unlock(&kmap_lock)
-#define lock_kmap_any(flags)    \
-		do { spin_lock(&kmap_lock); (void)(flags); } while (0)
-#define unlock_kmap_any(flags)  \
-		do { spin_unlock(&kmap_lock); (void)(flags); } while (0)
-#endif
-
 struct page *__kmap_to_page(void *vaddr)
 {
 	unsigned long base = (unsigned long) vaddr & PAGE_MASK;
@@ -237,9 +218,9 @@ static void flush_all_zero_pkmaps(void)
 
 void __kmap_flush_unused(void)
 {
-	lock_kmap();
+	spin_lock(&kmap_lock);
 	flush_all_zero_pkmaps();
-	unlock_kmap();
+	spin_unlock(&kmap_lock);
 }
 
 static inline unsigned long map_new_virtual(struct page *page)
@@ -273,10 +254,10 @@ static inline unsigned long map_new_virtual(struct page *page)
 
 			__set_current_state(TASK_UNINTERRUPTIBLE);
 			add_wait_queue(pkmap_map_wait, &wait);
-			unlock_kmap();
+			spin_unlock(&kmap_lock);
 			schedule();
 			remove_wait_queue(pkmap_map_wait, &wait);
-			lock_kmap();
+			spin_lock(&kmap_lock);
 
 			/* Somebody else might have mapped it while we slept */
 			if (page_address(page))
@@ -312,60 +293,32 @@ void *kmap_high(struct page *page)
 	 * For highmem pages, we can't trust "virtual" until
 	 * after we have the lock.
 	 */
-	lock_kmap();
+	spin_lock(&kmap_lock);
 	vaddr = (unsigned long)page_address(page);
 	if (!vaddr)
 		vaddr = map_new_virtual(page);
 	pkmap_count[PKMAP_NR(vaddr)]++;
 	BUG_ON(pkmap_count[PKMAP_NR(vaddr)] < 2);
-	unlock_kmap();
+	spin_unlock(&kmap_lock);
 	return (void *) vaddr;
 }
 EXPORT_SYMBOL(kmap_high);
 
-#ifdef ARCH_NEEDS_KMAP_HIGH_GET
-/**
- * kmap_high_get - pin a highmem page into memory
- * @page: &struct page to pin
- *
- * Returns the page's current virtual memory address, or NULL if no mapping
- * exists.  If and only if a non null address is returned then a
- * matching call to kunmap_high() is necessary.
- *
- * This can be called from any context.
- */
-void *kmap_high_get(const struct page *page)
-{
-	unsigned long vaddr, flags;
-
-	lock_kmap_any(flags);
-	vaddr = (unsigned long)page_address(page);
-	if (vaddr) {
-		BUG_ON(pkmap_count[PKMAP_NR(vaddr)] < 1);
-		pkmap_count[PKMAP_NR(vaddr)]++;
-	}
-	unlock_kmap_any(flags);
-	return (void *) vaddr;
-}
-#endif
-
 /**
  * kunmap_high - unmap a highmem page into memory
  * @page: &struct page to unmap
  *
- * If ARCH_NEEDS_KMAP_HIGH_GET is not defined then this may be called
- * only from user context.
+ * This may be called only from user context.
  */
 void kunmap_high(const struct page *page)
 {
 	unsigned long vaddr;
 	unsigned long nr;
-	unsigned long flags;
 	int need_wakeup;
 	unsigned int color = get_pkmap_color(page);
 	wait_queue_head_t *pkmap_map_wait;
 
-	lock_kmap_any(flags);
+	spin_lock(&kmap_lock);
 	vaddr = (unsigned long)page_address(page);
 	BUG_ON(!vaddr);
 	nr = PKMAP_NR(vaddr);
@@ -392,7 +345,7 @@ void kunmap_high(const struct page *page)
 		pkmap_map_wait = get_pkmap_wait_queue_head(color);
 		need_wakeup = waitqueue_active(pkmap_map_wait);
 	}
-	unlock_kmap_any(flags);
+	spin_unlock(&kmap_lock);
 
 	/* do wake-up, if needed, race-free outside of the spin lock */
 	if (need_wakeup)
@@ -507,30 +460,11 @@ static inline void kmap_local_idx_pop(void)
 #define arch_kmap_local_unmap_idx(idx, vaddr)	kmap_local_calc_idx(idx)
 #endif
 
-#ifndef arch_kmap_local_high_get
-static inline void *arch_kmap_local_high_get(const struct page *page)
-{
-	return NULL;
-}
-#endif
-
 #ifndef arch_kmap_local_set_pte
 #define arch_kmap_local_set_pte(mm, vaddr, ptep, ptev)	\
 	set_pte_at(mm, vaddr, ptep, ptev)
 #endif
 
-/* Unmap a local mapping which was obtained by kmap_high_get() */
-static inline bool kmap_high_unmap_local(unsigned long vaddr)
-{
-#ifdef ARCH_NEEDS_KMAP_HIGH_GET
-	if (vaddr >= PKMAP_ADDR(0) && vaddr < PKMAP_ADDR(LAST_PKMAP)) {
-		kunmap_high(pte_page(ptep_get(&pkmap_page_table[PKMAP_NR(vaddr)])));
-		return true;
-	}
-#endif
-	return false;
-}
-
 static pte_t *__kmap_pte;
 
 static pte_t *kmap_get_pte(unsigned long vaddr, int idx)
@@ -574,8 +508,6 @@ EXPORT_SYMBOL_GPL(__kmap_local_pfn_prot);
 
 void *__kmap_local_page_prot(const struct page *page, pgprot_t prot)
 {
-	void *kmap;
-
 	/*
 	 * To broaden the usage of the actual kmap_local() machinery always map
 	 * pages when debugging is enabled and the architecture has no problems
@@ -584,11 +516,6 @@ void *__kmap_local_page_prot(const struct page *page, pgprot_t prot)
 	if (!IS_ENABLED(CONFIG_DEBUG_KMAP_LOCAL_FORCE_MAP) && !PageHighMem(page))
 		return page_address(page);
 
-	/* Try kmap_high_get() if architecture has it enabled */
-	kmap = arch_kmap_local_high_get(page);
-	if (kmap)
-		return kmap;
-
 	return __kmap_local_pfn_prot(page_to_pfn(page), prot);
 }
 EXPORT_SYMBOL(__kmap_local_page_prot);
@@ -606,14 +533,7 @@ void kunmap_local_indexed(const void *vaddr)
 			WARN_ON_ONCE(1);
 			return;
 		}
-		/*
-		 * Handle mappings which were obtained by kmap_high_get()
-		 * first as the virtual address of such mappings is below
-		 * PAGE_OFFSET. Warn for all other addresses which are in
-		 * the user space part of the virtual address space.
-		 */
-		if (!kmap_high_unmap_local(addr))
-			WARN_ON_ONCE(addr < PAGE_OFFSET);
+		WARN_ON_ONCE(addr < PAGE_OFFSET);
 		return;
 	}
 
-- 
2.39.5



From Sascha.Bischoff at arm.com  Fri Dec 19 08:17:57 2025
From: Sascha.Bischoff at arm.com (Sascha Bischoff)
Date: Fri, 19 Dec 2025 16:17:57 +0000
Subject: [PATCH v2 00/36] KVM: arm64: Introduce vGIC-v5 with PPI support
In-Reply-To: <20251219155222.1383109-1-sascha.bischoff@arm.com>
References: <20251219155222.1383109-1-sascha.bischoff@arm.com>
Message-ID: <b2eac7bfb03b112ee5ea917cfe7f7be725408bd4.camel@arm.com>

On Fri, 2025-12-19 at 15:51 +0000, Sascha Bischoff wrote:
> This is the second version of the patch series to add the virtual
> GICv5 [1] device (vgic_v5). Only PPIs are supported by this initial
> series, and the vgic_v5 implementation is restricted to the CPU
> interface, only. Further patch series are to follow in due course,
> and
> will add support for SPIs, LPIs, the GICv5 IRS, and the GICv5 ITS.
> 
> The first version of this series can be found at [2].
> 
> The noteworthy changes since V1 of this series are:
> 
> 1. Added detection of implemented PPIs on a GICv5 host at boot time.
> 2. Added masking for PPIs that are presented to guests. Only PPIs
> with
> ?? owners and the SW_PPI (if present) are exposed.
> 3. Added trapping and masking for all guest writes to the writable
> ?? ICC_PPI_x_EL1 registers. The writes are masked with the subset of
> ?? PPIs exposed to the guest. This ensures that the guest cannot
> ?? discover PPIs that are not intentionally exposed to it.
> 4. Added an new UAPI to allow userspace to query which PPIs can be
> ?? driven via KVM_IRQ_LINE. For the time being, only the SW_ PPI is
> ?? exposed for guest control.
> 5. Interrupt type checks are now re-worked to be more readable and
> ?? scalable. Thanks, Marc.
> 
> I have addressed some, but alas not all (see below), review comments
> against v1 of the series. Thanks a lot Marc, Joey, and Lorenzo!
> 
> I'm posting V2 even though I've yet to address all review comments as
> I shall be out of office for the next 2 weeks. Therefore, I wanted to
> make sure that the latest version was available for anyone to take a
> look. Any outstanding and new comments will be addressed on my
> return.
> 
> The main outstanding changes are:
> 
> 1. Rework the PPI save/restore mechanisms to remove the _entry/_exit
> ?? from the vcpu, and instead use per-cpu data structures.
> 2. PPI injection needs clean up around shadow state tracking an
> ?? manipulation.
> 3. PPI state tracking needs to be heaviliy optimised to reduce the
> ?? number of locks taken and PPIs iterated over. This is now possible
> ?? with the introduction of the masks, but remains to be implemented.
> 4. Allow for sparse PPI state storage. Given that most of the 128
> ?? potential PPIs will never be used with a guest, it is extremely
> ?? wasteful to allocate storage for them.
> 
> These changes are based on v6.19-rc1. As before, the first commit has
> been cherry-picked from Marc's VTCR sanitisation series [3].
> 
> For those that are interested in the overall direction of the GICv5
> KVM support, Marc Zyngier has very kindly agreed to host the full
> *WIP* set of GICv5 KVM patches which can be found at [4]. These are
> not intended for review, and require some serious clean up, but
> should
> give a rough idea of what is still to come.
> 
> Thanks all for the feedback so far and any more you have,
> Sascha
> 
> [1] https://developer.arm.com/documentation/aes0070/latest
> [2]
> https://lore.kernel.org/all/20251212152215.675767-1-sascha.bischoff at arm.com/
> [3]
> https://lore.kernel.org/all/20251210173024.561160-1-maz at kernel.org/
> [4]
> https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git/log/?h=kvm-arm64/gicv5-full
> 

As an FYI, I've just posted the GICv5 kvmtool support for review here:

https://lore.kernel.org/all/20251219161240.1385034-1-sascha.bischoff at arm.com

Thanks,
Sascha

From bmork at telenor.net  Fri Dec 19 08:23:47 2025
From: bmork at telenor.net (=?utf-8?Q?Bj=C3=B8rn_Mork?=)
Date: Fri, 19 Dec 2025 17:23:47 +0100
Subject: [PATCH 1/1] wifi: mt76: mt7996: fix mixed FEM check of mt7996
 chipset
In-Reply-To: <20251110120110.193562-1-amadeus@jmu.edu.cn> (Chukun Pan's
	message of "Mon, 10 Nov 2025 20:01:10 +0800")
References: <20251110120110.193562-1-amadeus@jmu.edu.cn>
Message-ID: <87fr96tp7w.fsf@miraculix.mork.no>

Chukun Pan <amadeus at jmu.edu.cn> writes:

> To support the following varaint of the mt7996 chipset:
> - tri-band: band0 iFEM and band1/band2 eFEM
>
> We should read band1 for the determination, using band0
> will incorrectly identify it as iFEM.
> This is also the judgment logic of the mt7992 chipset.
>
> This fixes the load error on the Quantum Fiber W1701K:
> mt7996e 0000:01:00.0: eeprom load fail, use default bin
> mt7996e 0000:01:00.0: Message 0012002d (seq 5) timeout
>
> Fixes: e8cb33ad546a ("wifi: mt76: mt7996: add support for more variants")
> Signed-off-by: Chukun Pan <amadeus at jmu.edu.cn>
> ---
>  drivers/net/wireless/mediatek/mt76/mt7996/init.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
> index 5e95a36b42d1..143400541746 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
> @@ -1137,7 +1137,7 @@ static int mt7996_variant_fem_init(struct mt7996_dev *dev)
>  		adie_idx = (val & MT_PAD_GPIO_ADIE_SINGLE) ? 0 : 1;
>  		adie_comb = u32_get_bits(val, MT_PAD_GPIO_ADIE_COMB_7992);
>  	} else {
> -		adie_idx = 0;
> +		adie_idx = 1;
>  		adie_comb = u32_get_bits(val, MT_PAD_GPIO_ADIE_COMB);
>  	}

Thanks for this.  It solves half the puzzle I have.  But unfortunately
it adds new questions too.

I have two closely related devices from Zyxel, where one is supposed to
be iFEM and the other eFEM.  Looking at the eeprom data provided by
Zyxel, it seems that the eFEM device is actually mixed like your
example.  And indeed - your patch makes that device work properly.

The problem is that the patch breaks the other device variant, which
used to work before.  If we assume the eeprom data from Zyxel is
correct, then this variant is iFEM.

I added some debug printk's to mt7996_variant_fem_init() so I could see
what detection data we have.  I read both MT_ADIE_CHIP_ID(0) and
MT_ADIE_CHIP_ID(1) to be able to compare logic input before and after
your patch.

The two devices are almost identical, except for BIT(0) of
MT_ADIE_CHIP_ID(1).

iFEM device, working before, broken after this patch:

 mt7996e 0000:01:00.0: MT_PAD_GPIO=0x00008400, adie_comb=1
 mt7996e 0000:01:00.0: MT_ADIE_CHIP_ID(0)=0x79758a02
 mt7996e 0000:01:00.0: MT_ADIE_CHIP_ID(adie_idx)=0x79778a11, adie_idx=1

Mixed iFEM/eFEM device, broken before, working after this patch:

 mt7996e 0000:01:00.0: MT_PAD_GPIO=0x00008400, adie_comb=1
 mt7996e 0000:01:00.0: MT_ADIE_CHIP_ID(0)=0x79758a02
 mt7996e 0000:01:00.0: MT_ADIE_CHIP_ID(adie_idx)=0x79778a10, adie_idx=1

Looking at mt7996_eeprom_variant_valid() I understand that the
MT_EE_WIFI_PA_LNA_CONFIG is given by the two lowest bits of bytes 0x196
and 0x197 for band0 and band1/band2 respectively. 0 for iFEM and 3 for
eFEM.

And the Zyxel provided eeprom on my iFEM device has indeed 0 in the
MT_EE_WIFI_PA_LNA_CONFIG field of both bytes:

 00000190  11 23 24 24 25 24 08 a0  e0 0c 08 08 00 00 00 38

While the mixed iFEM/eFEM device has 0 for band0 and 3 for band1/band2:

 00000190  11 23 24 24 25 24 08 0b  4b 0c 22 22 00 00 80 38


Any idea how this should be fixed?  Is there still something missing in
mt7996_variant_fem_init()? Is the ADIE chip id difference significant
here?  Or is there something wrong with the devices/eeproms I have?



Bj?rn



From jgg at nvidia.com  Fri Dec 19 08:30:47 2025
From: jgg at nvidia.com (Jason Gunthorpe)
Date: Fri, 19 Dec 2025 12:30:47 -0400
Subject: [PATCH v8 5/7] iommu/arm-smmu-v3: Populate smmu_domain->invs
 when attaching masters
In-Reply-To: <79cd18a1a959ee2e54683e8c465b799d49ec48b5.1766013662.git.nicolinc@nvidia.com>
References: <cover.1766013662.git.nicolinc@nvidia.com>
 <79cd18a1a959ee2e54683e8c465b799d49ec48b5.1766013662.git.nicolinc@nvidia.com>
Message-ID: <20251219163047.GA376568@nvidia.com>

On Wed, Dec 17, 2025 at 03:24:30PM -0800, Nicolin Chen wrote:
> +static struct arm_smmu_inv *
> +arm_smmu_master_build_inv(struct arm_smmu_master *master,
> +			  enum arm_smmu_inv_type type, u32 id, ioasid_t ssid,
> +			  size_t pgsize)
> +{

ssid is not used in this function

Jason


From diederik at cknow-tech.com  Fri Dec 19 08:33:31 2025
From: diederik at cknow-tech.com (Diederik de Haas)
Date: Fri, 19 Dec 2025 17:33:31 +0100
Subject: [PATCH v7 14/17] media: rkvdec: Add H264 support for the
 VDPU381 variant
In-Reply-To: <20251218232829.337811-15-detlev.casanova@collabora.com>
References: <20251218232829.337811-1-detlev.casanova@collabora.com>
 <20251218232829.337811-15-detlev.casanova@collabora.com>
Message-ID: <DF2C6J4R30IJ.30D8549V3ML48@cknow-tech.com>

Hi Detlev,

On Fri Dec 19, 2025 at 12:28 AM CET, Detlev Casanova wrote:
> This decoder variant is found in Rockchip RK3588 SoC family.
>
> Like for rkvdec on rk3399, it supports the NV12, NV15, NV16 and NV20
> output formats and level up to 5.1.

Minor nit: It actually supports up to level 6.0.
See page 367 and/or 374 of RK3588 TRM Part 1.
(RK3568 supports up to level 5.1 (page 463/469 of RK3568 TRM Part 2)

Cheers,
  Diederik

> The maximum width and height have been significantly increased
> supporting up to 65520 pixels for both.
>
> Support for named register sections is added for this variant and future
> ones.
>
> Fluster score for JVT-AVC_V1 is 129/135.
>
> Tested-by: Diederik de Haas <didi.debian at cknow.org>  # Rock 5B
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
> ---
>  .../media/platform/rockchip/rkvdec/Makefile   |   1 +
>  .../rockchip/rkvdec/rkvdec-h264-common.h      |   2 +
>  .../rockchip/rkvdec/rkvdec-vdpu381-h264.c     | 465 ++++++++++++++++++
>  .../rockchip/rkvdec/rkvdec-vdpu381-regs.h     | 424 ++++++++++++++++
>  .../media/platform/rockchip/rkvdec/rkvdec.c   |  97 +++-
>  .../media/platform/rockchip/rkvdec/rkvdec.h   |  11 +
>  6 files changed, 997 insertions(+), 3 deletions(-)
>  create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c
>  create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h
>
> diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
> index 3d75103e536d2..7bfd95151e404 100644
> --- a/drivers/media/platform/rockchip/rkvdec/Makefile
> +++ b/drivers/media/platform/rockchip/rkvdec/Makefile
> @@ -8,4 +8,5 @@ rockchip-vdec-y += \
>  		   rkvdec-hevc.o \
>  		   rkvdec-hevc-common.o \
>  		   rkvdec-rcb.o \
> +		   rkvdec-vdpu381-h264.o \
>  		   rkvdec-vp9.o
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h
> index bd0c0081365b1..3be6cea3a7585 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264-common.h
> @@ -74,6 +74,8 @@ struct rkvdec_rps {
>  	u32 reserved1[66];
>  } __packed;
>  
> +extern const s8 rkvdec_h264_cabac_table[4][464][2];
> +
>  void lookup_ref_buf_idx(struct rkvdec_ctx *ctx, struct rkvdec_h264_run *run);
>  void assemble_hw_rps(struct v4l2_h264_reflist_builder *builder,
>  		     struct rkvdec_h264_run *run,
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c
> new file mode 100644
> index 0000000000000..eaa0f7aac08e3
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c
> @@ -0,0 +1,465 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Rockchip VDPU381 Video Decoder H264 backend
> + *
> + * Copyright (C) 2024 Collabora, Ltd.
> + *  Detlev Casanova <detlev.casanova at collabora.com>
> + */
> +
> +#include <media/v4l2-h264.h>
> +#include <media/v4l2-mem2mem.h>
> +
> +#include "rkvdec.h"
> +#include "rkvdec-rcb.h"
> +#include "rkvdec-h264-common.h"
> +#include "rkvdec-vdpu381-regs.h"
> +
> +struct rkvdec_sps {
> +	u16 seq_parameter_set_id:			4;
> +	u16 profile_idc:				8;
> +	u16 constraint_set3_flag:			1;
> +	u16 chroma_format_idc:				2;
> +	u16 bit_depth_luma:				3;
> +	u16 bit_depth_chroma:				3;
> +	u16 qpprime_y_zero_transform_bypass_flag:	1;
> +	u16 log2_max_frame_num_minus4:			4;
> +	u16 max_num_ref_frames:				5;
> +	u16 pic_order_cnt_type:				2;
> +	u16 log2_max_pic_order_cnt_lsb_minus4:		4;
> +	u16 delta_pic_order_always_zero_flag:		1;
> +	u16 pic_width_in_mbs:				12;
> +	u16 pic_height_in_mbs:				12;
> +	u16 frame_mbs_only_flag:			1;
> +	u16 mb_adaptive_frame_field_flag:		1;
> +	u16 direct_8x8_inference_flag:			1;
> +	u16 mvc_extension_enable:			1;
> +	u16 num_views:					2;
> +
> +	u16 reserved_bits:				12;
> +	u16 reserved[11];
> +} __packed;
> +
> +struct rkvdec_pps {
> +	u16 pic_parameter_set_id:				8;
> +	u16 pps_seq_parameter_set_id:				5;
> +	u16 entropy_coding_mode_flag:				1;
> +	u16 bottom_field_pic_order_in_frame_present_flag:	1;
> +	u16 num_ref_idx_l0_default_active_minus1:		5;
> +	u16 num_ref_idx_l1_default_active_minus1:		5;
> +	u16 weighted_pred_flag:					1;
> +	u16 weighted_bipred_idc:				2;
> +	u16 pic_init_qp_minus26:				7;
> +	u16 pic_init_qs_minus26:				6;
> +	u16 chroma_qp_index_offset:				5;
> +	u16 deblocking_filter_control_present_flag:		1;
> +	u16 constrained_intra_pred_flag:			1;
> +	u16 redundant_pic_cnt_present:				1;
> +	u16 transform_8x8_mode_flag:				1;
> +	u16 second_chroma_qp_index_offset:			5;
> +	u16 scaling_list_enable_flag:				1;
> +	u32 scaling_list_address;
> +	u16 is_longterm;
> +
> +	u8 reserved[3];
> +} __packed;
> +
> +struct rkvdec_sps_pps {
> +	struct rkvdec_sps sps;
> +	struct rkvdec_pps pps;
> +} __packed;
> +
> +/* Data structure describing auxiliary buffer format. */
> +struct rkvdec_h264_priv_tbl {
> +	s8 cabac_table[4][464][2];
> +	struct rkvdec_h264_scaling_list scaling_list;
> +	struct rkvdec_sps_pps param_set[256];
> +	struct rkvdec_rps rps;
> +};
> +
> +struct rkvdec_h264_ctx {
> +	struct rkvdec_aux_buf priv_tbl;
> +	struct rkvdec_h264_reflists reflists;
> +	struct rkvdec_vdpu381_regs_h264 regs;
> +};
> +
> +static void assemble_hw_pps(struct rkvdec_ctx *ctx,
> +			    struct rkvdec_h264_run *run)
> +{
> +	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
> +	const struct v4l2_ctrl_h264_sps *sps = run->sps;
> +	const struct v4l2_ctrl_h264_pps *pps = run->pps;
> +	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
> +	const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb;
> +	struct rkvdec_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu;
> +	struct rkvdec_sps_pps *hw_ps;
> +	dma_addr_t scaling_list_address;
> +	u32 scaling_distance;
> +	u32 i;
> +
> +	/*
> +	 * HW read the SPS/PPS information from PPS packet index by PPS id.
> +	 * offset from the base can be calculated by PPS_id * 32 (size per PPS
> +	 * packet unit). so the driver copy SPS/PPS information to the exact PPS
> +	 * packet unit for HW accessing.
> +	 */
> +	hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id];
> +	memset(hw_ps, 0, sizeof(*hw_ps));
> +
> +	/* write sps */
> +	hw_ps->sps.seq_parameter_set_id = sps->seq_parameter_set_id;
> +	hw_ps->sps.profile_idc = sps->profile_idc;
> +	hw_ps->sps.constraint_set3_flag = !!(sps->constraint_set_flags & (1 << 3));
> +	hw_ps->sps.chroma_format_idc = sps->chroma_format_idc;
> +	hw_ps->sps.bit_depth_luma = sps->bit_depth_luma_minus8;
> +	hw_ps->sps.bit_depth_chroma = sps->bit_depth_chroma_minus8;
> +	hw_ps->sps.qpprime_y_zero_transform_bypass_flag =
> +		!!(sps->flags & V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS);
> +	hw_ps->sps.log2_max_frame_num_minus4 = sps->log2_max_frame_num_minus4;
> +	hw_ps->sps.max_num_ref_frames = sps->max_num_ref_frames;
> +	hw_ps->sps.pic_order_cnt_type = sps->pic_order_cnt_type;
> +	hw_ps->sps.log2_max_pic_order_cnt_lsb_minus4 =
> +		sps->log2_max_pic_order_cnt_lsb_minus4;
> +	hw_ps->sps.delta_pic_order_always_zero_flag =
> +		!!(sps->flags & V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO);
> +	hw_ps->sps.mvc_extension_enable = 1;
> +	hw_ps->sps.num_views = 1;
> +
> +	/*
> +	 * Use the SPS values since they are already in macroblocks
> +	 * dimensions, height can be field height (halved) if
> +	 * V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY is not set and also it allows
> +	 * decoding smaller images into larger allocation which can be used
> +	 * to implementing SVC spatial layer support.
> +	 */
> +	hw_ps->sps.pic_width_in_mbs = sps->pic_width_in_mbs_minus1 + 1;
> +	hw_ps->sps.pic_height_in_mbs = sps->pic_height_in_map_units_minus1 + 1;
> +	hw_ps->sps.frame_mbs_only_flag =
> +		!!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY);
> +	hw_ps->sps.mb_adaptive_frame_field_flag =
> +		!!(sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD);
> +	hw_ps->sps.direct_8x8_inference_flag =
> +		!!(sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE);
> +
> +	/* write pps */
> +	hw_ps->pps.pic_parameter_set_id = pps->pic_parameter_set_id;
> +	hw_ps->pps.pps_seq_parameter_set_id = pps->seq_parameter_set_id;
> +	hw_ps->pps.entropy_coding_mode_flag =
> +		!!(pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE);
> +	hw_ps->pps.bottom_field_pic_order_in_frame_present_flag =
> +		!!(pps->flags & V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT);
> +	hw_ps->pps.num_ref_idx_l0_default_active_minus1 =
> +		pps->num_ref_idx_l0_default_active_minus1;
> +	hw_ps->pps.num_ref_idx_l1_default_active_minus1 =
> +		pps->num_ref_idx_l1_default_active_minus1;
> +	hw_ps->pps.weighted_pred_flag =
> +		!!(pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED);
> +	hw_ps->pps.weighted_bipred_idc = pps->weighted_bipred_idc;
> +	hw_ps->pps.pic_init_qp_minus26 = pps->pic_init_qp_minus26;
> +	hw_ps->pps.pic_init_qs_minus26 = pps->pic_init_qs_minus26;
> +	hw_ps->pps.chroma_qp_index_offset = pps->chroma_qp_index_offset;
> +	hw_ps->pps.deblocking_filter_control_present_flag =
> +		!!(pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT);
> +	hw_ps->pps.constrained_intra_pred_flag =
> +		!!(pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED);
> +	hw_ps->pps.redundant_pic_cnt_present =
> +		!!(pps->flags & V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT);
> +	hw_ps->pps.transform_8x8_mode_flag =
> +		!!(pps->flags & V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE);
> +	hw_ps->pps.second_chroma_qp_index_offset = pps->second_chroma_qp_index_offset;
> +	hw_ps->pps.scaling_list_enable_flag =
> +		!!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT);
> +
> +	/*
> +	 * To be on the safe side, program the scaling matrix address
> +	 */
> +	scaling_distance = offsetof(struct rkvdec_h264_priv_tbl, scaling_list);
> +	scaling_list_address = h264_ctx->priv_tbl.dma + scaling_distance;
> +	hw_ps->pps.scaling_list_address = scaling_list_address;
> +
> +	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
> +		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
> +			hw_ps->pps.is_longterm |= (1 << i);
> +	}
> +}
> +
> +static void rkvdec_write_regs(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
> +
> +	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_REGS,
> +			   &h264_ctx->regs.common,
> +			   sizeof(h264_ctx->regs.common));
> +	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_PARAMS_REGS,
> +			   &h264_ctx->regs.h264_param,
> +			   sizeof(h264_ctx->regs.h264_param));
> +	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_ADDR_REGS,
> +			   &h264_ctx->regs.common_addr,
> +			   sizeof(h264_ctx->regs.common_addr));
> +	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_ADDR_REGS,
> +			   &h264_ctx->regs.h264_addr,
> +			   sizeof(h264_ctx->regs.h264_addr));
> +	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_POC_HIGHBIT_REGS,
> +			   &h264_ctx->regs.h264_highpoc,
> +			   sizeof(h264_ctx->regs.h264_highpoc));
> +}
> +
> +static void config_registers(struct rkvdec_ctx *ctx,
> +			     struct rkvdec_h264_run *run)
> +{
> +	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
> +	const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb;
> +	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
> +	dma_addr_t priv_start_addr = h264_ctx->priv_tbl.dma;
> +	const struct v4l2_pix_format_mplane *dst_fmt;
> +	struct vb2_v4l2_buffer *src_buf = run->base.bufs.src;
> +	struct vb2_v4l2_buffer *dst_buf = run->base.bufs.dst;
> +	struct rkvdec_vdpu381_regs_h264 *regs = &h264_ctx->regs;
> +	const struct v4l2_format *f;
> +	dma_addr_t rlc_addr;
> +	dma_addr_t dst_addr;
> +	u32 hor_virstride;
> +	u32 ver_virstride;
> +	u32 y_virstride;
> +	u32 offset;
> +	u32 pixels;
> +	u32 i;
> +
> +	memset(regs, 0, sizeof(*regs));
> +
> +	/* Set H264 mode */
> +	regs->common.reg009.dec_mode = VDPU381_MODE_H264;
> +
> +	/* Set config */
> +	regs->common.reg011.buf_empty_en = 1;
> +	regs->common.reg011.dec_clkgate_e = 1;
> +	regs->common.reg011.dec_timeout_e = 1;
> +	regs->common.reg011.pix_range_detection_e = 1;
> +
> +	/*
> +	 * Even though the scan list address can be set in RPS,
> +	 * with some frames, it will try to use the address set in the register.
> +	 */
> +	regs->common.reg012.scanlist_addr_valid_en = 1;
> +
> +	/* Set IDR flag */
> +	regs->common.reg013.cur_pic_is_idr =
> +		!!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC);
> +
> +	/* Set input stream length */
> +	regs->common.stream_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
> +
> +	/* Set max slice number */
> +	regs->common.reg017.slice_num = MAX_SLICE_NUMBER;
> +
> +	/* Set strides */
> +	f = &ctx->decoded_fmt;
> +	dst_fmt = &f->fmt.pix_mp;
> +	hor_virstride = dst_fmt->plane_fmt[0].bytesperline;
> +	ver_virstride = dst_fmt->height;
> +	y_virstride = hor_virstride * ver_virstride;
> +
> +	pixels = dst_fmt->height * dst_fmt->width;
> +
> +	regs->common.reg018.y_hor_virstride = hor_virstride / 16;
> +	regs->common.reg019.uv_hor_virstride = hor_virstride / 16;
> +	regs->common.reg020.y_virstride = y_virstride / 16;
> +
> +	/* Activate block gating */
> +	regs->common.reg026.swreg_block_gating_e = 0xfffef;
> +	regs->common.reg026.reg_cfg_gating_en = 1;
> +
> +	/* Set timeout threshold */
> +	if (pixels < RKVDEC_1080P_PIXELS)
> +		regs->common.timeout_threshold = RKVDEC_TIMEOUT_1080p;
> +	else if (pixels < RKVDEC_4K_PIXELS)
> +		regs->common.timeout_threshold = RKVDEC_TIMEOUT_4K;
> +	else if (pixels < RKVDEC_8K_PIXELS)
> +		regs->common.timeout_threshold = RKVDEC_TIMEOUT_8K;
> +	else
> +		regs->common.timeout_threshold = RKVDEC_TIMEOUT_MAX;
> +
> +	/* Set TOP and BOTTOM POCs */
> +	regs->h264_param.cur_top_poc = dec_params->top_field_order_cnt;
> +	regs->h264_param.cur_bot_poc = dec_params->bottom_field_order_cnt;
> +
> +	/* Set ref pic address & poc */
> +	for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
> +		struct vb2_buffer *vb_buf = run->ref_buf[i];
> +		dma_addr_t buf_dma;
> +
> +		/*
> +		 * If a DPB entry is unused or invalid, address of current destination
> +		 * buffer is returned.
> +		 */
> +		if (!vb_buf)
> +			vb_buf = &dst_buf->vb2_buf;
> +
> +		buf_dma = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
> +
> +		/* Set reference addresses */
> +		regs->h264_addr.ref_base[i] = buf_dma;
> +
> +		/* Set COLMV addresses */
> +		regs->h264_addr.colmv_base[i] = buf_dma + ctx->colmv_offset;
> +
> +		struct rkvdec_vdpu381_h264_ref_info *ref_info =
> +			&regs->h264_param.ref_info_regs[i / 4].ref_info[i % 4];
> +
> +		ref_info->ref_field =
> +			!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD);
> +		ref_info->ref_colmv_use_flag =
> +			!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE);
> +		ref_info->ref_topfield_used =
> +			!!(dpb[i].fields & V4L2_H264_TOP_FIELD_REF);
> +		ref_info->ref_botfield_used =
> +			!!(dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF);
> +
> +		regs->h264_param.ref_pocs[i * 2] =
> +			dpb[i].top_field_order_cnt;
> +		regs->h264_param.ref_pocs[i * 2 + 1] =
> +			dpb[i].bottom_field_order_cnt;
> +	}
> +
> +	/* Set rlc base address (input stream) */
> +	rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
> +	regs->common_addr.rlc_base = rlc_addr;
> +	regs->common_addr.rlcwrite_base = rlc_addr;
> +
> +	/* Set output base address */
> +	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
> +	regs->common_addr.decout_base = dst_addr;
> +	regs->common_addr.error_ref_base = dst_addr;
> +
> +	/* Set colmv address */
> +	regs->common_addr.colmv_cur_base = dst_addr + ctx->colmv_offset;
> +
> +	/* Set RCB addresses */
> +	for (i = 0; i < rkvdec_rcb_buf_count(ctx); i++)
> +		regs->common_addr.rcb_base[i] = rkvdec_rcb_buf_dma_addr(ctx, i);
> +
> +	/* Set hw pps address */
> +	offset = offsetof(struct rkvdec_h264_priv_tbl, param_set);
> +	regs->h264_addr.pps_base = priv_start_addr + offset;
> +
> +	/* Set hw rps address */
> +	offset = offsetof(struct rkvdec_h264_priv_tbl, rps);
> +	regs->h264_addr.rps_base = priv_start_addr + offset;
> +
> +	/* Set cabac table */
> +	offset = offsetof(struct rkvdec_h264_priv_tbl, cabac_table);
> +	regs->h264_addr.cabactbl_base = priv_start_addr + offset;
> +
> +	offset = offsetof(struct rkvdec_h264_priv_tbl, scaling_list);
> +	regs->h264_addr.scanlist_addr = priv_start_addr + offset;
> +
> +	rkvdec_write_regs(ctx);
> +}
> +
> +static int rkvdec_h264_start(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	struct rkvdec_h264_priv_tbl *priv_tbl;
> +	struct rkvdec_h264_ctx *h264_ctx;
> +	struct v4l2_ctrl *ctrl;
> +	int ret;
> +
> +	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> +			      V4L2_CID_STATELESS_H264_SPS);
> +	if (!ctrl)
> +		return -EINVAL;
> +
> +	h264_ctx = kzalloc(sizeof(*h264_ctx), GFP_KERNEL);
> +	if (!h264_ctx)
> +		return -ENOMEM;
> +
> +	priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl),
> +				      &h264_ctx->priv_tbl.dma, GFP_KERNEL);
> +	if (!priv_tbl) {
> +		ret = -ENOMEM;
> +		goto err_free_ctx;
> +	}
> +
> +	h264_ctx->priv_tbl.size = sizeof(*priv_tbl);
> +	h264_ctx->priv_tbl.cpu = priv_tbl;
> +	memcpy(priv_tbl->cabac_table, rkvdec_h264_cabac_table,
> +	       sizeof(rkvdec_h264_cabac_table));
> +
> +	ctx->priv = h264_ctx;
> +	return 0;
> +
> +err_free_ctx:
> +	kfree(h264_ctx);
> +	return ret;
> +}
> +
> +static void rkvdec_h264_stop(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +
> +	dma_free_coherent(rkvdec->dev, h264_ctx->priv_tbl.size,
> +			  h264_ctx->priv_tbl.cpu, h264_ctx->priv_tbl.dma);
> +	kfree(h264_ctx);
> +}
> +
> +static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
> +{
> +	struct v4l2_h264_reflist_builder reflist_builder;
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
> +	struct rkvdec_h264_priv_tbl *tbl = h264_ctx->priv_tbl.cpu;
> +	struct rkvdec_h264_run run;
> +	u32 watchdog_time;
> +
> +	rkvdec_h264_run_preamble(ctx, &run);
> +
> +	/* Build the P/B{0,1} ref lists. */
> +	v4l2_h264_init_reflist_builder(&reflist_builder, run.decode_params,
> +				       run.sps, run.decode_params->dpb);
> +	v4l2_h264_build_p_ref_list(&reflist_builder, h264_ctx->reflists.p);
> +	v4l2_h264_build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0,
> +				    h264_ctx->reflists.b1);
> +
> +	assemble_hw_scaling_list(&run, &tbl->scaling_list);
> +	assemble_hw_pps(ctx, &run);
> +	lookup_ref_buf_idx(ctx, &run);
> +	assemble_hw_rps(&reflist_builder, &run, &h264_ctx->reflists, &tbl->rps);
> +
> +	config_registers(ctx, &run);
> +
> +	rkvdec_run_postamble(ctx, &run.base);
> +
> +	/* Set watchdog at 2 times the hardware timeout threshold */
> +	u64 timeout_threshold = h264_ctx->regs.common.timeout_threshold;
> +	unsigned long axi_rate = clk_get_rate(rkvdec->axi_clk);
> +
> +	if (axi_rate)
> +		watchdog_time = 2 * (1000 * timeout_threshold) / axi_rate;
> +	else
> +		watchdog_time = 2000;
> +	schedule_delayed_work(&rkvdec->watchdog_work,
> +			      msecs_to_jiffies(watchdog_time));
> +
> +	/* Start decoding! */
> +	writel(VDPU381_DEC_E_BIT, rkvdec->regs + VDPU381_REG_DEC_E);
> +
> +	return 0;
> +}
> +
> +static int rkvdec_h264_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
> +{
> +	if (ctrl->id == V4L2_CID_STATELESS_H264_SPS)
> +		return rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps);
> +
> +	return 0;
> +}
> +
> +const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_h264_fmt_ops = {
> +	.adjust_fmt = rkvdec_h264_adjust_fmt,
> +	.get_image_fmt = rkvdec_h264_get_image_fmt,
> +	.start = rkvdec_h264_start,
> +	.stop = rkvdec_h264_stop,
> +	.run = rkvdec_h264_run,
> +	.try_ctrl = rkvdec_h264_try_ctrl,
> +};
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h
> new file mode 100644
> index 0000000000000..a9a2daa24048b
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-regs.h
> @@ -0,0 +1,424 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Rockchip VDPU381 Video Decoder driver registers description
> + *
> + * Copyright (C) 2024 Collabora, Ltd.
> + *  Detlev Casanova <detlev.casanova at collabora.com>
> + */
> +
> +#include <linux/types.h>
> +
> +#ifndef _RKVDEC_REGS_H_
> +#define _RKVDEC_REGS_H_
> +
> +#define OFFSET_COMMON_REGS		(8 * sizeof(u32))
> +#define OFFSET_CODEC_PARAMS_REGS	(64 * sizeof(u32))
> +#define OFFSET_COMMON_ADDR_REGS		(128 * sizeof(u32))
> +#define OFFSET_CODEC_ADDR_REGS		(160 * sizeof(u32))
> +#define OFFSET_POC_HIGHBIT_REGS		(200 * sizeof(u32))
> +
> +#define VDPU381_MODE_HEVC	0
> +#define VDPU381_MODE_H264	1
> +#define VDPU381_MODE_VP9	2
> +#define VDPU381_MODE_AVS2	3
> +
> +#define MAX_SLICE_NUMBER	0x3fff
> +
> +#define RKVDEC_TIMEOUT_1080p		(0xefffff)
> +#define RKVDEC_TIMEOUT_4K		(0x2cfffff)
> +#define RKVDEC_TIMEOUT_8K		(0x4ffffff)
> +#define RKVDEC_TIMEOUT_MAX		(0xffffffff)
> +
> +#define VDPU381_REG_DEC_E		0x028
> +#define VDPU381_DEC_E_BIT		1
> +
> +#define VDPU381_REG_IMPORTANT_EN	0x02c
> +#define VDPU381_DEC_IRQ_DISABLE	BIT(4)
> +
> +#define VDPU381_REG_STA_INT		0x380
> +#define VDPU381_STA_INT_DEC_RDY_STA	BIT(2)
> +#define VDPU381_STA_INT_ERROR		BIT(4)
> +#define VDPU381_STA_INT_TIMEOUT		BIT(5)
> +#define VDPU381_STA_INT_SOFTRESET_RDY	BIT(9)
> +
> +/* base: OFFSET_COMMON_REGS */
> +struct rkvdec_vdpu381_regs_common {
> +	struct rkvdec_vdpu381_in_out {
> +		u32 in_endian		: 1;
> +		u32 in_swap32_e		: 1;
> +		u32 in_swap64_e		: 1;
> +		u32 str_endian		: 1;
> +		u32 str_swap32_e	: 1;
> +		u32 str_swap64_e	: 1;
> +		u32 out_endian		: 1;
> +		u32 out_swap32_e	: 1;
> +		u32 out_cbcr_swap	: 1;
> +		u32 out_swap64_e	: 1;
> +		u32 reserved		: 22;
> +	} reg008;
> +
> +	struct rkvdec_vdpu381_dec_mode {
> +		u32 dec_mode	: 10;
> +		u32 reserved	: 22;
> +	} reg009;
> +
> +	struct rkvdec_vdpu381_dec_e {
> +		u32 dec_e	: 1;
> +		u32 reserved	: 31;
> +	} reg010;
> +
> +	struct rkvdec_vdpu381_important_en {
> +		u32 reserved			: 1;
> +		u32 dec_clkgate_e		: 1;
> +		u32 dec_e_strmd_clkgate_dis	: 1;
> +		u32 reserved0			: 1;
> +
> +		u32 dec_irq_dis			: 1;
> +		u32 dec_timeout_e		: 1;
> +		u32 buf_empty_en		: 1;
> +		u32 reserved1			: 3;
> +
> +		u32 dec_e_rewrite_valid		: 1;
> +		u32 reserved2			: 9;
> +		u32 softrst_en_p		: 1;
> +		u32 force_softreset_valid	: 1;
> +		u32 reserved3			: 2;
> +		u32 pix_range_detection_e	: 1;
> +		u32 reserved4			: 7;
> +	} reg011;
> +
> +	struct rkvdec_vdpu381_secondary_en {
> +		u32 wr_ddr_align_en		: 1;
> +		u32 colmv_compress_en		: 1;
> +		u32 fbc_e			: 1;
> +		u32 reserved0			: 1;
> +
> +		u32 buspr_slot_disable		: 1;
> +		u32 error_info_en		: 1;
> +		u32 info_collect_en		: 1;
> +		u32 wait_reset_en		: 1;
> +
> +		u32 scanlist_addr_valid_en	: 1;
> +		u32 scale_down_en		: 1;
> +		u32 error_cfg_wr_disable	: 1;
> +		u32 reserved1			: 21;
> +	} reg012;
> +
> +	struct rkvdec_vdpu381_en_mode_set {
> +		u32 timeout_mode		: 1;
> +		u32 req_timeout_rst_sel		: 1;
> +		u32 reserved0			: 1;
> +		u32 dec_commonirq_mode		: 1;
> +		u32 reserved1			: 2;
> +		u32 stmerror_waitdecfifo_empty	: 1;
> +		u32 reserved2			: 2;
> +		u32 h26x_streamd_error_mode	: 1;
> +		u32 reserved3			: 2;
> +		u32 allow_not_wr_unref_bframe	: 1;
> +		u32 fbc_output_wr_disable	: 1;
> +		u32 reserved4			: 1;
> +		u32 colmv_error_mode		: 1;
> +
> +		u32 reserved5			: 2;
> +		u32 h26x_error_mode		: 1;
> +		u32 reserved6			: 2;
> +		u32 ycacherd_prior		: 1;
> +		u32 reserved7			: 2;
> +		u32 cur_pic_is_idr		: 1;
> +		u32 reserved8			: 1;
> +		u32 right_auto_rst_disable	: 1;
> +		u32 frame_end_err_rst_flag	: 1;
> +		u32 rd_prior_mode		: 1;
> +		u32 rd_ctrl_prior_mode		: 1;
> +		u32 reserved9			: 1;
> +		u32 filter_outbuf_mode		: 1;
> +	} reg013;
> +
> +	struct rkvdec_vdpu381_fbc_param_set {
> +		u32 fbc_force_uncompress	: 1;
> +
> +		u32 reserved0			: 2;
> +		u32 allow_16x8_cp_flag		: 1;
> +		u32 reserved1			: 2;
> +
> +		u32 fbc_h264_exten_4or8_flag	: 1;
> +		u32 reserved2			: 25;
> +	} reg014;
> +
> +	struct rkvdec_vdpu381_stream_param_set {
> +		u32 rlc_mode_direct_write	: 1;
> +		u32 rlc_mode			: 1;
> +		u32 reserved0			: 3;
> +
> +		u32 strm_start_bit		: 7;
> +		u32 reserved1			: 20;
> +	} reg015;
> +
> +	u32 stream_len;
> +
> +	struct rkvdec_vdpu381_slice_number {
> +		u32 slice_num	: 25;
> +		u32 reserved	: 7;
> +	} reg017;
> +
> +	struct rkvdec_vdpu381_y_hor_stride {
> +		u32 y_hor_virstride	: 16;
> +		u32 reserved		: 16;
> +	} reg018;
> +
> +	struct rkvdec_vdpu381_uv_hor_stride {
> +		u32 uv_hor_virstride	: 16;
> +		u32 reserved		: 16;
> +	} reg019;
> +
> +	struct rkvdec_vdpu381_y_stride {
> +		u32 y_virstride		: 28;
> +		u32 reserved		: 4;
> +	} reg020;
> +
> +	struct rkvdec_vdpu381_error_ctrl_set {
> +		u32 inter_error_prc_mode		: 1;
> +		u32 error_intra_mode			: 1;
> +		u32 error_deb_en			: 1;
> +		u32 picidx_replace			: 5;
> +		u32 error_spread_e			: 1;
> +		u32 reserved0				: 3;
> +		u32 error_inter_pred_cross_slice	: 1;
> +		u32 reserved1				: 11;
> +		u32 roi_error_ctu_cal_en		: 1;
> +		u32 reserved2				: 7;
> +	} reg021;
> +
> +	struct rkvdec_vdpu381_err_roi_ctu_offset_start {
> +		u32 roi_x_ctu_offset_st	: 12;
> +		u32 reserved0		: 4;
> +		u32 roi_y_ctu_offset_st	: 12;
> +		u32 reserved1		: 4;
> +	} reg022;
> +
> +	struct rkvdec_vdpu381_err_roi_ctu_offset_end {
> +		u32 roi_x_ctu_offset_end	: 12;
> +		u32 reserved0			: 4;
> +		u32 roi_y_ctu_offset_end	: 12;
> +		u32 reserved1			: 4;
> +	} reg023;
> +
> +	struct rkvdec_vdpu381_cabac_error_en_lowbits {
> +		u32 cabac_err_en_lowbits	: 32;
> +	} reg024;
> +
> +	struct rkvdec_vdpu381_cabac_error_en_highbits {
> +		u32 cabac_err_en_highbits	: 30;
> +		u32 reserved			: 2;
> +	} reg025;
> +
> +	struct rkvdec_vdpu381_block_gating_en {
> +		u32 swreg_block_gating_e	: 20;
> +		u32 reserved			: 11;
> +		u32 reg_cfg_gating_en		: 1;
> +	} reg026;
> +
> +	struct SW027_CORE_SAFE_PIXELS {
> +		u32 core_safe_x_pixels	: 16;
> +		u32 core_safe_y_pixels	: 16;
> +	} reg027;
> +
> +	struct rkvdec_vdpu381_multiply_core_ctrl {
> +		u32 swreg_vp9_wr_prob_idx	: 3;
> +		u32 reserved0			: 1;
> +		u32 swreg_vp9_rd_prob_idx	: 3;
> +		u32 reserved1			: 1;
> +
> +		u32 swreg_ref_req_advance_flag	: 1;
> +		u32 sw_colmv_req_advance_flag	: 1;
> +		u32 sw_poc_only_highbit_flag	: 1;
> +		u32 sw_poc_arb_flag		: 1;
> +
> +		u32 reserved2			: 4;
> +		u32 sw_film_idx			: 10;
> +		u32 reserved3			: 2;
> +		u32 sw_pu_req_mismatch_dis	: 1;
> +		u32 sw_colmv_req_mismatch_dis	: 1;
> +		u32 reserved4			: 2;
> +	} reg028;
> +
> +	struct SW029_SCALE_DOWN_CTRL {
> +		u32 scale_down_hor_ratio	: 2;
> +		u32 reserved0			: 6;
> +		u32 scale_down_vrz_ratio	: 2;
> +		u32 reserved1			: 22;
> +	} reg029;
> +
> +	struct SW032_Y_SCALE_DOWN_TILE8x8_HOR_STRIDE {
> +		u32 y_scale_down_hor_stride	: 20;
> +		u32 reserved0			: 12;
> +	} reg030;
> +
> +	struct SW031_UV_SCALE_DOWN_TILE8x8_HOR_STRIDE {
> +		u32 uv_scale_down_hor_stride	: 20;
> +		u32 reserved0			: 12;
> +	} reg031;
> +
> +	u32 timeout_threshold;
> +} __packed;
> +
> +/* base: OFFSET_COMMON_ADDR_REGS */
> +struct rkvdec_vdpu381_regs_common_addr {
> +	u32 rlc_base;
> +	u32 rlcwrite_base;
> +	u32 decout_base;
> +	u32 colmv_cur_base;
> +	u32 error_ref_base;
> +	u32 rcb_base[10];
> +} __packed;
> +
> +struct rkvdec_vdpu381_h26x_set {
> +	u32 h26x_frame_orslice		: 1;
> +	u32 h26x_rps_mode		: 1;
> +	u32 h26x_stream_mode		: 1;
> +	u32 h26x_stream_lastpacket	: 1;
> +	u32 h264_firstslice_flag	: 1;
> +	u32 reserved			: 27;
> +} __packed;
> +
> +/* base: OFFSET_CODEC_PARAMS_REGS */
> +struct rkvdec_vdpu381_regs_h264_params {
> +	struct rkvdec_vdpu381_h26x_set reg064;
> +
> +	u32 cur_top_poc;
> +	u32 cur_bot_poc;
> +	u32 ref_pocs[32];
> +
> +	struct rkvdec_vdpu381_h264_info {
> +		struct rkvdec_vdpu381_h264_ref_info {
> +			u32 ref_field		: 1;
> +			u32 ref_topfield_used	: 1;
> +			u32 ref_botfield_used	: 1;
> +			u32 ref_colmv_use_flag	: 1;
> +			u32 ref_reserved	: 4;
> +		} __packed ref_info[4];
> +	} __packed ref_info_regs[4];
> +
> +	u32 reserved_103_111[9];
> +
> +	struct rkvdec_vdpu381_error_ref_info {
> +		u32 avs2_ref_error_field	: 1;
> +		u32 avs2_ref_error_topfield	: 1;
> +		u32 ref_error_topfield_used	: 1;
> +		u32 ref_error_botfield_used	: 1;
> +		u32 reserved			: 28;
> +	} reg112;
> +} __packed;
> +
> +struct rkvdec_vdpu381_regs_hevc_params {
> +	struct rkvdec_vdpu381_h26x_set reg064;
> +
> +	u32 cur_top_poc;
> +	u32 cur_bot_poc;
> +
> +	u32 reg067_082_ref_poc[16];
> +
> +	u32 reserved_083_098[16];
> +
> +	struct rkvdec_vdpu381_hevc_ref_valid {
> +		u32 hevc_ref_valid_0    : 1;
> +		u32 hevc_ref_valid_1    : 1;
> +		u32 hevc_ref_valid_2    : 1;
> +		u32 hevc_ref_valid_3    : 1;
> +		u32 reserve0            : 4;
> +		u32 hevc_ref_valid_4    : 1;
> +		u32 hevc_ref_valid_5    : 1;
> +		u32 hevc_ref_valid_6    : 1;
> +		u32 hevc_ref_valid_7    : 1;
> +		u32 reserve1            : 4;
> +		u32 hevc_ref_valid_8    : 1;
> +		u32 hevc_ref_valid_9    : 1;
> +		u32 hevc_ref_valid_10   : 1;
> +		u32 hevc_ref_valid_11   : 1;
> +		u32 reserve2            : 4;
> +		u32 hevc_ref_valid_12   : 1;
> +		u32 hevc_ref_valid_13   : 1;
> +		u32 hevc_ref_valid_14   : 1;
> +		u32 reserve3            : 5;
> +	} reg099;
> +
> +	u32 reserved_100_102[3];
> +
> +	struct rkvdec_vdpu381_hevc_mvc0 {
> +		u32 ref_pic_layer_same_with_cur : 16;
> +		u32 reserve                     : 16;
> +	} reg103;
> +
> +	struct rkvdec_vdpu381_hevc_mvc1 {
> +		u32 poc_lsb_not_present_flag        : 1;
> +		u32 num_direct_ref_layers           : 6;
> +		u32 reserve0                        : 1;
> +
> +		u32 num_reflayer_pics               : 6;
> +		u32 default_ref_layers_active_flag  : 1;
> +		u32 max_one_active_ref_layer_flag   : 1;
> +
> +		u32 poc_reset_info_present_flag     : 1;
> +		u32 vps_poc_lsb_aligned_flag        : 1;
> +		u32 mvc_poc15_valid_flag            : 1;
> +		u32 reserve1                        : 13;
> +	} reg104;
> +
> +	u32 reserved_105_111[7];
> +
> +	struct rkvdec_vdpu381_hevc_ref_info {
> +		u32 avs2_ref_error_field        : 1;
> +		u32 avs2_ref_error_topfield     : 1;
> +		u32 ref_error_topfield_used     : 1;
> +		u32 ref_error_botfield_used     : 1;
> +		u32 reserve                     : 28;
> +	} reg112;
> +
> +} __packed;
> +
> +/* base: OFFSET_CODEC_ADDR_REGS */
> +struct rkvdec_vdpu381_regs_h26x_addr {
> +	u32 reserved_160;
> +	u32 pps_base;
> +	u32 reserved_162;
> +	u32 rps_base;
> +	u32 ref_base[16];
> +	u32 scanlist_addr;
> +	u32 colmv_base[16];
> +	u32 cabactbl_base;
> +} __packed;
> +
> +struct rkvdec_vdpu381_regs_h26x_highpoc {
> +	struct rkvdec_vdpu381_ref_poc_highbit {
> +		u32 ref0_poc_highbit	: 4;
> +		u32 ref1_poc_highbit	: 4;
> +		u32 ref2_poc_highbit	: 4;
> +		u32 ref3_poc_highbit	: 4;
> +		u32 ref4_poc_highbit	: 4;
> +		u32 ref5_poc_highbit	: 4;
> +		u32 ref6_poc_highbit	: 4;
> +		u32 ref7_poc_highbit	: 4;
> +	} reg200[4];
> +	struct rkvdec_vdpu381_cur_poc_highbit {
> +		u32 cur_poc_highbit	: 4;
> +		u32 reserved		: 28;
> +	} reg204;
> +} __packed;
> +
> +struct rkvdec_vdpu381_regs_h264 {
> +	struct rkvdec_vdpu381_regs_common		common;
> +	struct rkvdec_vdpu381_regs_h264_params		h264_param;
> +	struct rkvdec_vdpu381_regs_common_addr		common_addr;
> +	struct rkvdec_vdpu381_regs_h26x_addr		h264_addr;
> +	struct rkvdec_vdpu381_regs_h26x_highpoc		h264_highpoc;
> +} __packed;
> +
> +struct rkvdec_vdpu381_regs_hevc {
> +	struct rkvdec_vdpu381_regs_common		common;
> +	struct rkvdec_vdpu381_regs_hevc_params		hevc_param;
> +	struct rkvdec_vdpu381_regs_common_addr		common_addr;
> +	struct rkvdec_vdpu381_regs_h26x_addr		hevc_addr;
> +	struct rkvdec_vdpu381_regs_h26x_highpoc		hevc_highpoc;
> +} __packed;
> +
> +#endif /* __RKVDEC_REGS_H__ */
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> index af2eced900269..3d243b6e11445 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> @@ -29,6 +29,7 @@
>  
>  #include "rkvdec.h"
>  #include "rkvdec-regs.h"
> +#include "rkvdec-vdpu381-regs.h"
>  #include "rkvdec-rcb.h"
>  
>  static bool rkvdec_image_fmt_match(enum rkvdec_image_fmt fmt1,
> @@ -90,6 +91,9 @@ static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx,
>  {
>  	v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat,
>  			    pix_mp->width, pix_mp->height);
> +
> +	ctx->colmv_offset = pix_mp->plane_fmt[0].sizeimage;
> +
>  	pix_mp->plane_fmt[0].sizeimage += 128 *
>  		DIV_ROUND_UP(pix_mp->width, 16) *
>  		DIV_ROUND_UP(pix_mp->height, 16);
> @@ -382,6 +386,25 @@ static const struct rkvdec_coded_fmt_desc rk3288_coded_fmts[] = {
>  	}
>  };
>  
> +static const struct rkvdec_coded_fmt_desc vdpu381_coded_fmts[] = {
> +	{
> +		.fourcc = V4L2_PIX_FMT_H264_SLICE,
> +		.frmsize = {
> +			.min_width = 64,
> +			.max_width =  65520,
> +			.step_width = 64,
> +			.min_height = 64,
> +			.max_height =  65520,
> +			.step_height = 16,
> +		},
> +		.ctrls = &rkvdec_h264_ctrls,
> +		.ops = &rkvdec_vdpu381_h264_fmt_ops,
> +		.num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts),
> +		.decoded_fmts = rkvdec_h264_decoded_fmts,
> +		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
> +	},
> +};
> +
>  static const struct rkvdec_coded_fmt_desc *
>  rkvdec_enum_coded_fmt_desc(struct rkvdec_ctx *ctx, int index)
>  {
> @@ -1245,6 +1268,35 @@ static irqreturn_t rk3399_irq_handler(struct rkvdec_ctx *ctx)
>  	return IRQ_HANDLED;
>  }
>  
> +static irqreturn_t vdpu381_irq_handler(struct rkvdec_ctx *ctx)
> +{
> +	struct rkvdec_dev *rkvdec = ctx->dev;
> +	enum vb2_buffer_state state;
> +	bool need_reset = 0;
> +	u32 status;
> +
> +	status = readl(rkvdec->regs + VDPU381_REG_STA_INT);
> +	writel(0, rkvdec->regs + VDPU381_REG_STA_INT);
> +
> +	if (status & VDPU381_STA_INT_DEC_RDY_STA) {
> +		state = VB2_BUF_STATE_DONE;
> +	} else {
> +		state = VB2_BUF_STATE_ERROR;
> +		if (status & (VDPU381_STA_INT_SOFTRESET_RDY |
> +			      VDPU381_STA_INT_TIMEOUT |
> +			      VDPU381_STA_INT_ERROR))
> +			rkvdec_iommu_restore(rkvdec);
> +	}
> +
> +	if (need_reset)
> +		rkvdec_iommu_restore(rkvdec);
> +
> +	if (cancel_delayed_work(&rkvdec->watchdog_work))
> +		rkvdec_job_finish(ctx, state);
> +
> +	return IRQ_HANDLED;
> +}
> +
>  static irqreturn_t rkvdec_irq_handler(int irq, void *priv)
>  {
>  	struct rkvdec_dev *rkvdec = priv;
> @@ -1321,6 +1373,7 @@ static const struct rkvdec_variant rk3288_rkvdec_variant = {
>  	.coded_fmts = rk3288_coded_fmts,
>  	.num_coded_fmts = ARRAY_SIZE(rk3288_coded_fmts),
>  	.ops = &rk3399_variant_ops,
> +	.has_single_reg_region = true,
>  };
>  
>  static const struct rkvdec_variant rk3328_rkvdec_variant = {
> @@ -1328,6 +1381,7 @@ static const struct rkvdec_variant rk3328_rkvdec_variant = {
>  	.coded_fmts = rkvdec_coded_fmts,
>  	.num_coded_fmts = ARRAY_SIZE(rkvdec_coded_fmts),
>  	.ops = &rk3399_variant_ops,
> +	.has_single_reg_region = true,
>  	.quirks = RKVDEC_QUIRK_DISABLE_QOS,
>  };
>  
> @@ -1336,6 +1390,32 @@ static const struct rkvdec_variant rk3399_rkvdec_variant = {
>  	.coded_fmts = rkvdec_coded_fmts,
>  	.num_coded_fmts = ARRAY_SIZE(rkvdec_coded_fmts),
>  	.ops = &rk3399_variant_ops,
> +	.has_single_reg_region = true,
> +};
> +
> +static const struct rcb_size_info vdpu381_rcb_sizes[] = {
> +	{6,	PIC_WIDTH},	// intrar
> +	{1,	PIC_WIDTH},	// transdr (Is actually 0.4*pic_width)
> +	{1,	PIC_HEIGHT},	// transdc (Is actually 0.1*pic_height)
> +	{3,	PIC_WIDTH},	// streamdr
> +	{6,	PIC_WIDTH},	// interr
> +	{3,	PIC_HEIGHT},	// interc
> +	{22,	PIC_WIDTH},	// dblkr
> +	{6,	PIC_WIDTH},	// saor
> +	{11,	PIC_WIDTH},	// fbcr
> +	{67,	PIC_HEIGHT},	// filtc col
> +};
> +
> +static const struct rkvdec_variant_ops vdpu381_variant_ops = {
> +	.irq_handler = vdpu381_irq_handler,
> +};
> +
> +static const struct rkvdec_variant vdpu381_variant = {
> +	.coded_fmts = vdpu381_coded_fmts,
> +	.num_coded_fmts = ARRAY_SIZE(vdpu381_coded_fmts),
> +	.rcb_sizes = vdpu381_rcb_sizes,
> +	.num_rcb_sizes = ARRAY_SIZE(vdpu381_rcb_sizes),
> +	.ops = &vdpu381_variant_ops,
>  };
>  
>  static const struct of_device_id of_rkvdec_match[] = {
> @@ -1351,6 +1431,10 @@ static const struct of_device_id of_rkvdec_match[] = {
>  		.compatible = "rockchip,rk3399-vdec",
>  		.data = &rk3399_rkvdec_variant,
>  	},
> +	{
> +		.compatible = "rockchip,rk3588-vdec",
> +		.data = &vdpu381_variant,
> +	},
>  	{ /* sentinel */ }
>  };
>  MODULE_DEVICE_TABLE(of, of_rkvdec_match);
> @@ -1384,10 +1468,17 @@ static int rkvdec_probe(struct platform_device *pdev)
>  		return ret;
>  
>  	rkvdec->num_clocks = ret;
> +	rkvdec->axi_clk = devm_clk_get(&pdev->dev, "axi");
>  
> -	rkvdec->regs = devm_platform_ioremap_resource(pdev, 0);
> -	if (IS_ERR(rkvdec->regs))
> -		return PTR_ERR(rkvdec->regs);
> +	if (rkvdec->variant->has_single_reg_region) {
> +		rkvdec->regs = devm_platform_ioremap_resource(pdev, 0);
> +		if (IS_ERR(rkvdec->regs))
> +			return PTR_ERR(rkvdec->regs);
> +	} else {
> +		rkvdec->regs = devm_platform_ioremap_resource_byname(pdev, "function");
> +		if (IS_ERR(rkvdec->regs))
> +			return PTR_ERR(rkvdec->regs);
> +	}
>  
>  	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
>  	if (ret) {
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> index 7766a79caf68b..401221061e081 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> @@ -25,6 +25,10 @@
>  
>  #define RKVDEC_QUIRK_DISABLE_QOS	BIT(0)
>  
> +#define RKVDEC_1080P_PIXELS		(1920 * 1088)
> +#define RKVDEC_4K_PIXELS		(4096 * 2304)
> +#define RKVDEC_8K_PIXELS		(7680 * 4320)
> +
>  struct rkvdec_ctx;
>  struct rkvdec_rcb_config;
>  
> @@ -78,6 +82,7 @@ struct rkvdec_variant {
>  	const struct rcb_size_info *rcb_sizes;
>  	size_t num_rcb_sizes;
>  	const struct rkvdec_variant_ops *ops;
> +	bool has_single_reg_region;
>  	unsigned int quirks;
>  };
>  
> @@ -126,6 +131,7 @@ struct rkvdec_dev {
>  	struct device *dev;
>  	struct clk_bulk_data *clocks;
>  	unsigned int num_clocks;
> +	struct clk *axi_clk;
>  	void __iomem *regs;
>  	struct mutex vdev_lock; /* serializes ioctls */
>  	struct delayed_work watchdog_work;
> @@ -144,6 +150,7 @@ struct rkvdec_ctx {
>  	struct rkvdec_dev *dev;
>  	enum rkvdec_image_fmt image_fmt;
>  	struct rkvdec_rcb_config *rcb_config;
> +	u32 colmv_offset;
>  	void *priv;
>  };
>  
> @@ -170,8 +177,12 @@ void rkvdec_memcpy_toio(void __iomem *dst, void *src, size_t len);
>  
>  void rkvdec_quirks_disable_qos(struct rkvdec_ctx *ctx);
>  
> +/* RKVDEC ops */
>  extern const struct rkvdec_coded_fmt_ops rkvdec_h264_fmt_ops;
>  extern const struct rkvdec_coded_fmt_ops rkvdec_hevc_fmt_ops;
>  extern const struct rkvdec_coded_fmt_ops rkvdec_vp9_fmt_ops;
>  
> +/* VDPU381 ops */
> +extern const struct rkvdec_coded_fmt_ops rkvdec_vdpu381_h264_fmt_ops;
> +
>  #endif /* RKVDEC_H_ */



From puranjay at kernel.org  Fri Dec 19 08:40:45 2025
From: puranjay at kernel.org (Puranjay Mohan)
Date: Fri, 19 Dec 2025 16:40:45 +0000
Subject: [PATCH bpf-next v2 2/2] bpf: arm64: Optimize recursion detection
 by not using atomics
In-Reply-To: <1728d4e1-ce5c-476e-b057-b8a9a7621e1b@linux.dev>
References: <20251217233608.2374187-1-puranjay@kernel.org> <20251217233608.2374187-3-puranjay@kernel.org>
 <1728d4e1-ce5c-476e-b057-b8a9a7621e1b@linux.dev>
Message-ID: <CANk7y0gRJ4u-R+Pzv9M1LTJtRgTR+BxxFJia8q_u0cY-kM0JzA@mail.gmail.com>

On Thu, Dec 18, 2025 at 5:56?PM Yonghong Song <yonghong.song at linux.dev> wrote:
>
>
>
> On 12/17/25 3:35 PM, Puranjay Mohan wrote:
> > BPF programs detect recursion using a per-CPU 'active' flag in struct
> > bpf_prog. The trampoline currently sets/clears this flag with atomic
> > operations.
> >
> > On some arm64 platforms (e.g., Neoverse V2 with LSE), per-CPU atomic
> > operations are relatively slow. Unlike x86_64 - where per-CPU updates
> > can avoid cross-core atomicity, arm64 LSE atomics are always atomic
> > across all cores, which is unnecessary overhead for strictly per-CPU
> > state.
> >
> > This patch removes atomics from the recursion detection path on arm64 by
> > changing 'active' to a per-CPU array of four u8 counters, one per
> > context: {NMI, hard-irq, soft-irq, normal}. The running context uses a
> > non-atomic increment/decrement on its element.  After increment,
> > recursion is detected by reading the array as a u32 and verifying that
> > only the expected element changed; any change in another element
> > indicates inter-context recursion, and a value > 1 in the same element
> > indicates same-context recursion.
> >
> > For example, starting from {0,0,0,0}, a normal-context trigger changes
> > the array to {0,0,0,1}.  If an NMI arrives on the same CPU and triggers
> > the program, the array becomes {1,0,0,1}. When the NMI context checks
> > the u32 against the expected mask for normal (0x00000001), it observes
> > 0x01000001 and correctly reports recursion. Same-context recursion is
> > detected analogously.
> >
> > Signed-off-by: Puranjay Mohan <puranjay at kernel.org>
>
> LGTM with a few nits below.
>
> Acked-by: Yonghong Song <yonghong.song at linux.dev>
>
> > ---
> >   include/linux/bpf.h | 33 ++++++++++++++++++++++++++++++---
> >   kernel/bpf/core.c   |  3 ++-
> >   2 files changed, 32 insertions(+), 4 deletions(-)
> >
> > diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> > index 2da986136d26..5ca2a761d9a1 100644
> > --- a/include/linux/bpf.h
> > +++ b/include/linux/bpf.h
> > @@ -31,6 +31,7 @@
> >   #include <linux/static_call.h>
> >   #include <linux/memcontrol.h>
> >   #include <linux/cfi.h>
> > +#include <linux/unaligned.h>
> >   #include <asm/rqspinlock.h>
> >
> >   struct bpf_verifier_env;
> > @@ -1746,6 +1747,8 @@ struct bpf_prog_aux {
> >       struct bpf_map __rcu *st_ops_assoc;
> >   };
> >
> > +#define BPF_NR_CONTEXTS        4       /* normal, softirq, hardirq, NMI */
> > +
> >   struct bpf_prog {
> >       u16                     pages;          /* Number of allocated pages */
> >       u16                     jited:1,        /* Is our filter JIT'ed? */
> > @@ -1772,7 +1775,7 @@ struct bpf_prog {
> >               u8 tag[BPF_TAG_SIZE];
> >       };
> >       struct bpf_prog_stats __percpu *stats;
> > -     int __percpu            *active;
> > +     u8 __percpu             *active;        /* u8[BPF_NR_CONTEXTS] for rerecursion protection */
> >       unsigned int            (*bpf_func)(const void *ctx,
> >                                           const struct bpf_insn *insn);
> >       struct bpf_prog_aux     *aux;           /* Auxiliary fields */
> > @@ -2006,12 +2009,36 @@ struct bpf_struct_ops_common_value {
> >
> >   static inline bool bpf_prog_get_recursion_context(struct bpf_prog *prog)
> >   {
> > -     return this_cpu_inc_return(*(prog->active)) == 1;
> > +#ifdef CONFIG_ARM64
> > +     u8 rctx = interrupt_context_level();
> > +     u8 *active = this_cpu_ptr(prog->active);
> > +     u32 val;
> > +
> > +     preempt_disable();
> > +     active[rctx]++;
> > +     val = get_unaligned_le32(active);
>
> The 'active' already aligned with 8 (or 4 with my below suggestion).
> The get_unaligned_le32() works, but maybe we could use le32_to_cpu()
> instead. Maybe there is no performance difference between
> get_unaligned_le32() and le32_to_cpu() so you pick get_unaligned_le32()?
> It would be good to clarify in commit message if get_unaligned_le32()
> is used.
>
> > +     preempt_enable();
> > +     if (val != BIT(rctx * 8))
> > +             return false;
> > +
> > +     return true;
> > +#else
> > +     return this_cpu_inc_return(*(int __percpu *)(prog->active)) == 1;
> > +#endif
> >   }
> >
> >   static inline void bpf_prog_put_recursion_context(struct bpf_prog *prog)
> >   {
> > -     this_cpu_dec(*(prog->active));
> > +#ifdef CONFIG_ARM64
> > +     u8 rctx = interrupt_context_level();
> > +     u8 *active = this_cpu_ptr(prog->active);
> > +
> > +     preempt_disable();
> > +     active[rctx]--;
> > +     preempt_enable();
> > +#else
> > +     this_cpu_dec(*(int __percpu *)(prog->active));
> > +#endif
> >   }
> >
> >   #if defined(CONFIG_BPF_JIT) && defined(CONFIG_BPF_SYSCALL)
> > diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> > index c66316e32563..b5063acfcf92 100644
> > --- a/kernel/bpf/core.c
> > +++ b/kernel/bpf/core.c
> > @@ -112,7 +112,8 @@ struct bpf_prog *bpf_prog_alloc_no_stats(unsigned int size, gfp_t gfp_extra_flag
> >               vfree(fp);
> >               return NULL;
> >       }
> > -     fp->active = alloc_percpu_gfp(int, bpf_memcg_flags(GFP_KERNEL | gfp_extra_flags));
> > +     fp->active = __alloc_percpu_gfp(sizeof(u8[BPF_NR_CONTEXTS]), 8,
> > +                                     bpf_memcg_flags(GFP_KERNEL | gfp_extra_flags));
>
> Here, the alignment is 8. Can it be 4 since the above reads a 32bit value?

Yes, It should be 4. Will change in next version and add your acked by.

Thanks,
Puranjay


From robh at kernel.org  Fri Dec 19 08:49:03 2025
From: robh at kernel.org (Rob Herring)
Date: Fri, 19 Dec 2025 10:49:03 -0600
Subject: [PATCH 0/6] Support TQMa8QM
In-Reply-To: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
References: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
Message-ID: <176616243172.3584134.12135958492433215984.robh@kernel.org>


On Thu, 18 Dec 2025 16:20:47 +0100, Alexander Stein wrote:
> Hi,
> 
> this series adds support for TQ's TQMa8QM. The first 3 patches are prepatory:
> 1. Add support for clock-output-names for clk-renesas-pcie. This is necessary
> as clk-imx8qxp-lpcg.c (driver for phyx1 phyx2 clock gating) reqiures that
> property on the parent clock.
> 
> 2. Add support for USB devices in cdns USB3 host controller, namely
> onboard-devices as USB hubs. Implemented similarily to snps,dwc3-common.yaml.
> 
> 3. Add DMA IRQ for PCIe controller. Similar to commit 0b4c46f9ad79c
> ("arm64: dts: imx8qm-ss-hsio: Wire up DMA IRQ for PCIe") which was only tested
> on imx8qxp which just has one PCIe controller.
> 
> 4 & 5. Device bindings and platform DT
> 
> 6. Workaround for missing "ERR050104: Arm/A53: Cache coherency issue"
> workaround. See [1] for details. Split into separate commit for easy revert
> once an errata workaround has been integrated.
> 
> Best regards,
> Alexander
> 
> [1] https://lore.kernel.org/all/20230420112952.28340-1-iivanov at suse.de/
> 
> Alexander Stein (6):
>   dt-bindings: clk: rs9: add clock-output-names property
>   dt-bindings: usb: cdns,usb3: support USB devices in DT
>   arm64: dts: imx8qm-ss-hsio: Wire up DMA IRQ for PCIe
>   dt-bindings: arm: fsl: add bindings for TQMa8x
>   arm64: dts: Add TQ imx8qm based board
>   arm64: dts: imx8qm-tqma8qm-mba8x: Disable Cortex-A72 cluster
> 
>  .../devicetree/bindings/arm/fsl.yaml          |  10 +
>  .../bindings/clock/renesas,9series.yaml       |  37 +
>  .../devicetree/bindings/usb/cdns,usb3.yaml    |  11 +
>  arch/arm64/boot/dts/freescale/Makefile        |   1 +
>  .../boot/dts/freescale/imx8qm-ss-hsio.dtsi    |   5 +-
>  .../dts/freescale/imx8qm-tqma8qm-mba8x.dts    | 869 ++++++++++++++++++
>  .../boot/dts/freescale/imx8qm-tqma8qm.dtsi    | 322 +++++++
>  7 files changed, 1253 insertions(+), 2 deletions(-)
>  create mode 100644 arch/arm64/boot/dts/freescale/imx8qm-tqma8qm-mba8x.dts
>  create mode 100644 arch/arm64/boot/dts/freescale/imx8qm-tqma8qm.dtsi
> 
> --
> 2.43.0
> 
> 
> 


My bot found new DTB warnings on the .dts files added or changed in this
series.

Some warnings may be from an existing SoC .dtsi. Or perhaps the warnings
are fixed by another series. Ultimately, it is up to the platform
maintainer whether these warnings are acceptable or not. No need to reply
unless the platform maintainer has comments.

If you already ran DT checks and didn't see these error(s), then
make sure dt-schema is up to date:

  pip3 install dtschema --upgrade


This patch series was applied (using b4) to base:
 Base: attempting to guess base-commit...
 Base: tags/v6.18-rc7-1585-gfa10d5a2b8f9 (best guess, 3/5 blobs matched)
 Base: tags/v6.18-rc7-1585-gfa10d5a2b8f9 (use --merge-base to override)

If this is not the correct base, please add 'base-commit' tag
(or use b4 which does this automatically)

New warnings running 'make CHECK_DTBS=y for arch/arm64/boot/dts/freescale/' for 20251218152058.1521806-1-alexander.stein at ew.tq-group.com:

Error: arch/arm64/boot/dts/freescale/imx8qm-tqma8qm.dtsi:180.1-15 Label or path thermal_zones not found
FATAL ERROR: Syntax error parsing input tree
make[3]: *** [scripts/Makefile.dtbs:132: arch/arm64/boot/dts/freescale/imx8qm-tqma8qm-mba8x.dtb] Error 1
make[2]: *** [scripts/Makefile.build:556: arch/arm64/boot/dts/freescale] Error 2
make[2]: Target 'arch/arm64/boot/dts/freescale/imx8qm-tqma8qm-mba8x.dtb' not remade because of errors.
make[1]: *** [/home/rob/proj/linux-dt-testing/Makefile:1478: freescale/imx8qm-tqma8qm-mba8x.dtb] Error 2
make: *** [Makefile:248: __sub-make] Error 2
make: Target 'freescale/imx8dx-colibri-eval-v3.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-var-som-symphony.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-nitrogen-enc-carrier-board.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1046a-qds.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-prt8mm.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1028a-kontron-sl28.dtb' not remade because of errors.
make: Target 'freescale/imx8qxp-tqma8xqp-mba8xx.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-beacon-kit.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-venice-gw73xx-2x.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-var-som-symphony.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-icore-mx8mp-edimm2.2.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-innocomm-wb15-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8qm-apalis-v1.1-eval.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-aristainetos3-proton2s.dtb' not remade because of errors.
make: Target 'freescale/imx8dx-colibri-iris-v2.dtb' not remade because of errors.
make: Target 'freescale/imx8mn-ddr3l-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-icore-mx8mm-edimm2.2.dtb' not remade because of errors.
make: Target 'freescale/imx8mn-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-dhcom-pdk3.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1028a-kontron-kbox-a-230-ls.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-phyboard-polis-rdk.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-venice-gw72xx-2x.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-venice-gw7901.dtb' not remade because of errors.
make: Target 'freescale/imx8mn-beacon-kit.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1028a-kontron-sl28-var1.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1028a-kontron-sl28-var3.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-debix-som-a-bmb-08.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-verdin-nonwifi-dahlia.dtb' not remade because of errors.
make: Target 'freescale/imx8qxp-ai_ml.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-verdin-wifi-dev.dtb' not remade because of errors.
make: Target 'freescale/s32v234-evb.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-skov-revb-lt6.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-phg.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-nitrogen-smarc-universal-board.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-venice-gw71xx-0x.dtb' not remade because of errors.
make: Target 'freescale/imx8ulp-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8qxp-colibri-iris.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-emtop-baseboard.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-hummingboard-pro.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1028a-kontron-sl28-var4.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-librem5-r4.dtb' not remade because of errors.
make: Target 'freescale/imx8dx-colibri-aster.dtb' not remade because of errors.
make: Target 'freescale/imx8mn-rve-gateway.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-venice-gw71xx-2x.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls2080a-rdb.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-pico-pi.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-verdin-wifi-mallow.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-msc-sm2s-ep1.dtb' not remade because of errors.
make: Target 'freescale/imx8dxl-evk.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1043a-qds.dtb' not remade because of errors.
make: Target 'freescale/s32g399a-rdb3.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-venice-gw72xx-0x.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-verdin-wifi-ivy.dtb' not remade because of errors.
make: Target 'freescale/imx8mn-bsh-smm-s2.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-aristainetos3-adpismarc.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-tx8p-ml81-moduline-display-106.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-verdin-nonwifi-mallow.dtb' not remade because of errors.
make: Target 'freescale/imx8qxp-tqma8xqps-mb-smarc-2.dtb' not remade because of errors.
make: Target 'freescale/imx8mn-dimonoff-gateway-evk.dtb' not remade because of errors.
make: Target 'freescale/imx93-tqma9352-mba93xxca.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-tqma8mq-mba8mx.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1012a-oxalis.dtb' not remade because of errors.
make: Target 'freescale/imx93-14x14-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8dx-colibri-iris.dtb' not remade because of errors.
make: Target 'freescale/imx8mn-var-som-symphony.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-kontron-smarc-eval-carrier.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls2080a-simu.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1046a-frwy.dtb' not remade because of errors.
make: Target 'freescale/imx93-9x9-qsb.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-verdin-wifi-yavia.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-verdin-nonwifi-yavia.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-verdin-wifi-mallow.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-debix-model-a.dtb' not remade because of errors.
make: Target 'freescale/imx8qm-apalis-v1.1-ixora-v1.2.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-icore-mx8mm-ctouch2.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-zii-ultra-rmb3.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-phygate-tauri-l.dtb' not remade because of errors.
make: Target 'freescale/imx8qm-apalis-v1.1-eval-v1.2.dtb' not remade because of errors.
make: Target 'freescale/fsl-lx2162a-clearfog.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-data-modul-edm-sbc.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-librem5-devkit.dtb' not remade because of errors.
make: Target 'freescale/fsl-lx2160a-tqmlx2160a-mblx2160a.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1012a-tqmls1012al-mbls1012al-emmc.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-cubox-m.dtb' not remade because of errors.
make: Target 'freescale/fsl-lx2160a-honeycomb.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-skov-revb-hdmi.dtb' not remade because of errors.
make: Target 'freescale/imx8qm-apalis-eval.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-venice-gw7904.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-skov-revb-mi1010ait-1cp1.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-navqp.dtb' not remade because of errors.
make: Target 'freescale/fsl-lx2160a-qds.dtb' not remade because of errors.
make: Target 'freescale/fsl-lx2160a-bluebox3.dtb' not remade because of errors.
make: Target 'freescale/imx93-var-som-symphony.dtb' not remade because of errors.
make: Target 'freescale/imx8dxp-tqma8xdps-mb-smarc-2.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-nitrogen-r2.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1028a-kontron-sl28-var3-ads2.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1046a-rdb.dtb' not remade because of errors.
make: Target 'freescale/imx93-tqma9352-mba91xxca.dtb' not remade because of errors.
make: Target 'freescale/imx95-tqma9596sa-mb-smarc-2.dtb' not remade because of errors.
make: Target 'freescale/imx8mn-ddr4-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8mn-bsh-smm-s2pro.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-phanbell.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-venice-gw7903.dtb' not remade because of errors.
make: Target 'freescale/s32g274a-evb.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-ddr4-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-dhcom-pdk2.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1012a-frdm.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1012a-qds.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1043a-rdb.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-phyboard-pollux-rdk.dtb' not remade because of errors.
make: Target 'freescale/imx8qm-mek.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1088a-qds.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1088a-rdb.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-verdin-wifi-dev.dtb' not remade because of errors.
make: Target 'freescale/imx8qm-apalis-v1.1-ixora-v1.1.dtb' not remade because of errors.
make: Target 'freescale/imx91-tqma9131-mba91xxca.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-hummingboard-mate.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-venice-gw75xx-0x.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-venice-gw74xx.dtb' not remade because of errors.
make: Target 'freescale/imx8qm-apalis-ixora-v1.1.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-aristainetos3-helios.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-skov-revc-bd500.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-verdin-nonwifi-dahlia.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-iot-gateway.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-librem5-r2.dtb' not remade because of errors.
make: Target 'freescale/imx95-libra-rdk-fpsc.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1088a-ten64.dtb' not remade because of errors.
make: Target 'freescale/imx8ulp-9x9-evk.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1028a-qds.dtb' not remade because of errors.
make: Target 'freescale/imx8qm-tqma8qm-mba8x.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-verdin-wifi-dahlia.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-beacon-kit.dtb' not remade because of errors.
make: Target 'freescale/fsl-lx2162a-qds.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1046a-tqmls1046a-mbls10xxa.dtb' not remade because of errors.
make: Target 'freescale/imx91-11x11-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-verdin-wifi-dahlia.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-evkb.dtb' not remade because of errors.
make: Target 'freescale/imx93-tqma9352-mba93xxla.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-emcon-avari.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-edm-g-wb.dtb' not remade because of errors.
make: Target 'freescale/imx93-11x11-evk.dtb' not remade because of errors.
make: Target 'freescale/imx95-19x19-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-hummingboard-ripple.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1012a-tqmls1012al-mbls1012al.dtb' not remade because of errors.
make: Target 'freescale/fsl-lx2160a-clearfog-cx.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-tqma8mqml-mba8mx.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-verdin-nonwifi-ivy.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-dhcom-drc02.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-toradex-smarc-dev.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-verdin-wifi-ivy.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-tqma8mpql-mba8mp-ras314.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-verdin-nonwifi-yavia.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1012a-rdb.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1012a-frwy.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1028a-kontron-sl28-var2.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-verdin-nonwifi-mallow.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-venice-gw73xx-0x.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1043a-tqmls1043a-mbls10xxa.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-kontron-bl-osm-s.dtb' not remade because of errors.
make: Target 'freescale/fsl-lx2160a-bluebox3-rev-a.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1088a-tqmls1088a-mbls10xxa.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-verdin-wifi-yavia.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-mx8menlo.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls2081a-rdb.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-mnt-reform2.dtb' not remade because of errors.
make: Target 'freescale/imx8qxp-colibri-iris-v2.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls2088a-rdb.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-zii-ultra-zest.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-tqma8mpql-mba8mpxl.dtb' not remade because of errors.
make: Target 'freescale/imx8qm-apalis-eval-v1.2.dtb' not remade because of errors.
make: Target 'freescale/s32g274a-rdb2.dtb' not remade because of errors.
make: Target 'freescale/imx93-phyboard-nash.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-verdin-nonwifi-dev.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-ultra-mach-sbc.dtb' not remade because of errors.
make: Target 'freescale/imx8mn-tqma8mqnl-mba8mx.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-kontron-bl-osm-s.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls2080a-qds.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-verdin-nonwifi-ivy.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-data-modul-edm-sbc.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-librem5-r3.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls2088a-qds.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-kontron-pitx-imx8m.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-venice-gw7902.dtb' not remade because of errors.
make: Target 'freescale/fsl-lx2160a-rdb.dtb' not remade because of errors.
make: Target 'freescale/imx95-19x19-evk-sof.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-venice-gw82xx-2x.dtb' not remade because of errors.
make: Target 'freescale/imx93-phyboard-segin.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-verdin-nonwifi-dev.dtb' not remade because of errors.
make: Target 'freescale/imx8mm-kontron-bl.dtb' not remade because of errors.
make: Target 'freescale/imx8dxp-tqma8xdp-mba8xx.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-hummingboard-pulse.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-libra-rdk-fpsc.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-venice-gw75xx-2x.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8qxp-colibri-eval-v3.dtb' not remade because of errors.
make: Target 'freescale/imx943-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8qxp-colibri-aster.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-nitrogen.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-skov-basic.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-thor96.dtb' not remade because of errors.
make: Target 'freescale/fsl-ls1028a-rdb.dtb' not remade because of errors.
make: Target 'freescale/imx8mq-hummingboard-pulse.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-iota2-lumpy.dtb' not remade because of errors.
make: Target 'freescale/imx8mn-venice-gw7902.dtb' not remade because of errors.
make: Target 'freescale/imx8qxp-mek.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-skov-revc-tian-g07017.dtb' not remade because of errors.
make: Target 'freescale/imx93-kontron-bl-osm-s.dtb' not remade because of errors.
make: Target 'freescale/imx95-15x15-evk.dtb' not remade because of errors.
make: Target 'freescale/imx8mp-dhcom-picoitx.dtb' not remade because of errors.







From Paul-pl.Chen at mediatek.com  Fri Dec 19 09:00:24 2025
From: Paul-pl.Chen at mediatek.com (=?utf-8?B?UGF1bC1wbCBDaGVuICjpmbPmn4/pnJYp?=)
Date: Fri, 19 Dec 2025 17:00:24 +0000
Subject: [PATCH v4 13/19] drm/mediatek: Export OVL Blend function
In-Reply-To: <a13a968227214194b7033795a07ad554bfacfc8a.camel@mediatek.com>
References: <20250828080855.3502514-1-paul-pl.chen@mediatek.com>
	 <20250828080855.3502514-14-paul-pl.chen@mediatek.com>
	 <a13a968227214194b7033795a07ad554bfacfc8a.camel@mediatek.com>
Message-ID: <7d5a8d4e8648540b7d644c1614b169ddd7ceaab5.camel@mediatek.com>

On Wed, 2025-09-10 at 09:18 +0000, CK Hu (???) wrote:
> On Thu, 2025-08-28 at 16:07 +0800, Paul Chen wrote:
> > From: Paul-pl Chen <paul-pl.chen at mediatek.com>
> > 
> > For the new BLENDER component, the OVL ignore pixel alpha logic
> > should be exported as a function and reused it.
> > 
> > Signed-off-by: Nancy Lin <nancy.lin at mediatek.com>
> > Signed-off-by: Paul-pl Chen <paul-pl.chen at mediatek.com>
> > ---
> > ?drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 68 +++++++++++++++++----
> > ----
> > ?drivers/gpu/drm/mediatek/mtk_disp_ovl.h |? 8 +++
> > ?2 files changed, 56 insertions(+), 20 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> > b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> > index e3ee3f60f4ba..7cd3978beb98 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> > @@ -228,6 +228,23 @@ void mtk_ovl_disable_vblank(struct device
> > *dev)
> > ?	writel_relaxed(0x0, ovl->regs + DISP_REG_OVL_INTEN);
> > ?}
> > ?
> > +bool mtk_ovl_is_ignore_pixel_alpha(struct mtk_plane_state *state,
> > unsigned int blend_mode)
> > +{
> > +	if (!state->base.fb)
> > +		return false;
> > +
> > +	/*
> > +	 * Although the alpha channel can be ignored, CONST_BLD
> > must be enabled
> > +	 * for XRGB format, otherwise OVL will still read the
> > value from memory.
> > +	 * For RGB888 related formats, whether CONST_BLD is
> > enabled or not won't
> > +	 * affect the result. Therefore we use !has_alpha as the
> > condition.
> > +	 */
> > +	if (blend_mode == DRM_MODE_BLEND_PIXEL_NONE || !state-
> > >base.fb->format->has_alpha)
> > +		return true;
> > +
> > +	return false;
> > +}
> > +
> > ?u32 mtk_ovl_get_blend_modes(struct device *dev)
> > ?{
> > ?	struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
> > @@ -414,6 +431,29 @@ void mtk_ovl_layer_off(struct device *dev,
> > unsigned int idx,
> > ?		????? DISP_REG_OVL_RDMA_CTRL(idx));
> > ?}
> > ?
> > +unsigned int mtk_ovl_get_blend_mode(struct mtk_plane_state *state,
> > unsigned int blend_modes)
> > +{
> > +	unsigned int blend_mode = DRM_MODE_BLEND_COVERAGE;
> > +
> > +	/*
> > +	 * For the platforms where OVL_CON_CLRFMT_MAN is defined
> > in the hardware data sheet
> > +	 * and supports premultiplied color formats, such as
> > OVL_CON_CLRFMT_PARGB888
> > +	 * and supports premultiplied color formats, such as
> > OVL_CON_CLRFMT_PARGB8888.
> > +	 *
> > +	 * Check blend_modes in the driver data to see if
> > premultiplied mode is supported.
> > +	 * If not, use coverage mode instead to set it to the
> > supported color formats.
> > +	 *
> > +	 * Current DRM assumption is that alpha is default
> > premultiplied, so the bitmask of
> > +	 * blend_modes must include BIT(DRM_MODE_BLEND_PREMULTI).
> > Otherwise, mtk_plane_init()
> > +	 * will get an error return from
> > drm_plane_create_blend_mode_property() and
> > +	 * state->base.pixel_blend_mode should not be used.
> > +	 */
> > +	if (blend_modes & BIT(DRM_MODE_BLEND_PREMULTI))
> > +		blend_mode = state->base.pixel_blend_mode;
> > +
> > +	return blend_mode;
> > +}
> > +
> > ?unsigned int mtk_ovl_fmt_convert(unsigned int fmt, unsigned int
> > blend_mode,
> > ?				 bool fmt_rgb565_is_0, bool
> > color_convert,
> > ?				 u8 clrfmt_shift, u32 clrfmt_man,
> > u32 byte_swap, u32 rgb_swap)
> > @@ -541,7 +581,7 @@ void mtk_ovl_layer_config(struct device *dev,
> > unsigned int idx,
> > ?	unsigned int rotation = pending->rotation;
> > ?	unsigned int offset = (pending->y << 16) | pending->x;
> > ?	unsigned int src_size = (pending->height << 16) | pending-
> > >width;
> > -	unsigned int blend_mode = state->base.pixel_blend_mode;
> > +	unsigned int blend_mode = mtk_ovl_get_blend_mode(state,
> > ovl->data->blend_modes);
> 
> Why you change behavior here?
> Originally, 'blend_mode = state->base.pixel_blend_mode' directly.
> But this patch add a check and blend_mode may be
> DRM_MODE_BLEND_COVERAGE.
> The behavior changes. Why change this behavior?
> 
It's for convenient to optimize the logic design. 
> > ?	unsigned int ignore_pixel_alpha = 0;
> > ?	unsigned int con;
> > ?
> > @@ -566,17 +606,8 @@ void mtk_ovl_layer_config(struct device *dev,
> > unsigned int idx,
> > ?		 * For blend_modes supported SoCs, always enable
> > alpha blending.
> > ?		 * For blend_modes unsupported SoCs, enable alpha
> > blending when has_alpha is set.
> > ?		 */
> > -		if (blend_mode || state->base.fb->format-
> > >has_alpha)
> > +		if (state->base.pixel_blend_mode || state-
> > >base.fb->format->has_alpha)
> > ?			con |= OVL_CON_AEN;
> > -
> > -		/*
> > -		 * Although the alpha channel can be ignored,
> > CONST_BLD must be enabled
> > -		 * for XRGB format, otherwise OVL will still read
> > the value from memory.
> > -		 * For RGB888 related formats, whether CONST_BLD
> > is enabled or not won't
> > -		 * affect the result. Therefore we use !has_alpha
> > as the condition.
> > -		 */
> > -		if (blend_mode == DRM_MODE_BLEND_PIXEL_NONE ||
> > !state->base.fb->format->has_alpha)
> > -			ignore_pixel_alpha = OVL_CONST_BLEND;
> > ?	}
> > ?
> > ?	/*
> > @@ -602,6 +633,9 @@ void mtk_ovl_layer_config(struct device *dev,
> > unsigned int idx,
> > ?
> > ?	mtk_ddp_write_relaxed(cmdq_pkt, con, &ovl->cmdq_reg, ovl-
> > >regs,
> > ?			????? DISP_REG_OVL_CON(idx));
> > +
> > +	if (mtk_ovl_is_ignore_pixel_alpha(state, blend_mode))
> > +		ignore_pixel_alpha = OVL_CONST_BLEND;
> > ?	mtk_ddp_write_relaxed(cmdq_pkt, pitch_lsb |
> > ignore_pixel_alpha,
> > ?			????? &ovl->cmdq_reg, ovl->regs,
> > DISP_REG_OVL_PITCH(idx));
> > ?	mtk_ddp_write_relaxed(cmdq_pkt, src_size, &ovl->cmdq_reg,
> > ovl->regs,
> 


From Paul-pl.Chen at mediatek.com  Fri Dec 19 09:03:50 2025
From: Paul-pl.Chen at mediatek.com (=?utf-8?B?UGF1bC1wbCBDaGVuICjpmbPmn4/pnJYp?=)
Date: Fri, 19 Dec 2025 17:03:50 +0000
Subject: [PATCH v4 15/19] drm/mediatek: add BLENDER support for MT8196
In-Reply-To: <41974a26982bf441230ba49f9c8c5ba21cf1336c.camel@mediatek.com>
References: <20250828080855.3502514-1-paul-pl.chen@mediatek.com>
	 <20250828080855.3502514-16-paul-pl.chen@mediatek.com>
	 <41974a26982bf441230ba49f9c8c5ba21cf1336c.camel@mediatek.com>
Message-ID: <edf5da411c480f0e2337ed62a393d4cf66d17577.camel@mediatek.com>

On Fri, 2025-09-12 at 02:27 +0000, CK Hu (???) wrote:
> On Thu, 2025-08-28 at 16:07 +0800, Paul Chen wrote:
> > From: Nancy Lin <nancy.lin at mediatek.com>
> > 
> > BLENDER executes the alpha blending function for overlapping
> > layers from different sources, which is the primary function
> > of the overlapping system.
> > 
> > Signed-off-by: Nancy Lin <nancy.lin at mediatek.com>
> > Signed-off-by: Paul-pl Chen <paul-pl.chen at mediatek.com>
> > ---
> 
> [snip]
> 
> > diff --git a/drivers/gpu/drm/mediatek/mtk_disp_blender.c
> > b/drivers/gpu/drm/mediatek/mtk_disp_blender.c
> > new file mode 100644
> > index 000000000000..9212d2e19ca7
> > --- /dev/null
> > +++ b/drivers/gpu/drm/mediatek/mtk_disp_blender.c
> > @@ -0,0 +1,274 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Copyright (c) 2025 MediaTek Inc.
> > + */
> > +
> > +#include <drm/drm_fourcc.h>
> > +#include <drm/drm_blend.h>
> 
> Alphabetic order.
> 
> > +#include <drm/drm_framebuffer.h>
> > +#include <linux/clk.h>
> > +#include <linux/component.h>
> > +#include <linux/of.h>
> > +#include <linux/of_device.h>
> 
> Alphabetic order.
> 
> > +#include <linux/of_address.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/reset.h>
> > +#include <linux/soc/mediatek/mtk-cmdq.h>
> > +#include <linux/soc/mediatek/mtk-mmsys.h>
> > +
> > +#include "mtk_crtc.h"
> > +#include "mtk_ddp_comp.h"
> > +#include "mtk_disp_blender.h"
> > +#include "mtk_disp_drv.h"
> > +#include "mtk_disp_ovl.h"
> > +#include "mtk_drm_drv.h"
> > +
> > +#define DISP_REG_OVL_BLD_DATAPATH_CON			0x010
> > +#define
> > OVL_BLD_BGCLR_IN_SEL					BIT(0)
> > +#define
> > OVL_BLD_BGCLR_OUT_TO_PROC				BIT(4)
> > +#define
> > OVL_BLD_BGCLR_OUT_TO_NEXT_LAYER				BIT(5)
> > +#define DISP_REG_OVL_BLD_EN				0x020
> > +#define
> > OVL_BLD_EN						BIT(0)
> > +#define
> > OVL_BLD_FORCE_RELAY_MODE				BIT(4)
> > +#define
> > OVL_BLD_RELAY_MODE					BIT(5)
> > +#define DISP_REG_OVL_BLD_RST				0x024
> > +#define
> > OVL_BLD_RST						BIT(0)
> > +#define DISP_REG_OVL_BLD_SHADOW_CTRL			0x028
> > +#define
> > OVL_BLD_BYPASS_SHADOW					BIT(2)
> > +#define DISP_REG_OVL_BLD_BGCLR_BALCK			0xff000000
> 
> Move this after DISP_REG_OVL_BLD_BGCLR_CLR, and this name has typo.
> It should be DISP_REG_OVL_BLD_BGCLR_BLACK
> 
> > +#define DISP_REG_OVL_BLD_ROI_SIZE			0x030
> > +#define DISP_REG_OVL_BLD_L_EN				0x040
> > +#define
> > OVL_BLD_L_EN						BIT(0)
> > +#define
> > DISP_REG_OVL_BLD_OFFSET				0x044
> > +#define DISP_REG_OVL_BLD_SRC_SIZE			0x048
> > +#define DISP_REG_OVL_BLD_L0_CLRFMT			0x050
> > +#define
> > OVL_BLD_CON_FLD_CLRFMT					GENMASK(3, 0)
> > +#define
> > OVL_BLD_CON_CLRFMT_MAN					BIT(4)
> > +#define
> > OVL_BLD_CON_FLD_CLRFMT_NB				GENMASK(9, 8)
> > +#define
> > OVL_BLD_CON_CLRFMT_NB_10_BIT				BIT(8)
> > +#define
> > OVL_BLD_CON_BYTE_SWAP					BIT(16)
> > +#define
> > OVL_BLD_CON_RGB_SWAP					BIT(17)
> > +#define DISP_REG_OVL_BLD_BGCLR_CLR			0x104
> > +#define
> > DISP_REG_OVL_BLD_L_CON2				0x200
> > +#define
> > OVL_BLD_L_ALPHA						GENMASK(7, 0)
> > +#define
> > OVL_BLD_L_ALPHA_EN					BIT(12)
> > +#define DISP_REG_OVL_BLD_L0_ALPHA_SEL			0x208
> > +#define
> > OVL_BLD_L0_CONST					BIT(24)
> > +#define
> > DISP_REG_OVL_BLD_L0_CLR				0x20c
> > +#define
> > OVL_BLD_CON_CLRFMT_MAN					BIT(4)
> 
> You have already define OVL_BLD_CON_CLRFMT_MAN. Drop this one.
> 
> > +
> > +struct mtk_disp_blender_data {
> > +	unsigned int max_size;
> > +};
> > +
> > +struct mtk_disp_blender {
> > +	void __iomem *regs;
> > +	struct clk *clk;
> > +	struct cmdq_client_reg cmdq_reg;
> > +	const struct mtk_disp_blender_data *data;
> > +};
> > +
> > +void mtk_disp_blender_layer_config(struct device *dev, struct
> > mtk_plane_state *state,
> > +				?? struct cmdq_pkt *cmdq_pkt)
> > +{
> > +	struct mtk_disp_blender *priv = dev_get_drvdata(dev);
> > +	struct mtk_plane_pending_state *pending = &state->pending;
> > +	u32 alpha, clrfmt, ignore_pixel_alpha = 0;
> > +	u32 blend_mode = mtk_ovl_get_blend_mode(state,
> > MTK_OVL_SUPPORT_BLEND_MODES);
> > +
> > +	if (!pending->enable || pending->height == 0 || pending-
> > >width == 0 ||
> > +	??? pending->x > priv->data->max_size || pending->y >
> > priv->data->max_size) {
> > +		mtk_ddp_write(cmdq_pkt, 0, &priv->cmdq_reg, priv-
> > >regs, DISP_REG_OVL_BLD_L_EN);
> > +		return;
> > +	}
> > +
> > +	mtk_ddp_write(cmdq_pkt, pending->y << 16 | pending->x,
> > &priv->cmdq_reg, priv->regs,
> > +		????? DISP_REG_OVL_BLD_OFFSET);
> > +
> > +	mtk_ddp_write(cmdq_pkt, pending->height << 16 | pending-
> > >width, &priv->cmdq_reg,
> > +		????? priv->regs, DISP_REG_OVL_BLD_SRC_SIZE);
> > +
> > +	clrfmt = mtk_ovl_fmt_convert(pending->format, blend_mode,
> > true, false, 0,
> > +				???? OVL_BLD_CON_CLRFMT_MAN,
> > OVL_BLD_CON_BYTE_SWAP,
> > +				???? OVL_BLD_CON_RGB_SWAP);
> 
> The blender data input from exdma.
> exdma would convert YUV format to RGB, so blender would always
> receive RGB format, right?
> If pending->format is YUV, and set YUV format to blender, what does
> this mean?
> 
> 
This is the mechanism of hardware design, we will use the
ignore_pixel_alpha to close it
> > +	clrfmt |= mtk_ovl_is_10bit_rgb(pending->format) ?
> > OVL_BLD_CON_CLRFMT_NB_10_BIT : 0;
> > +	mtk_ddp_write_mask(cmdq_pkt, clrfmt, &priv->cmdq_reg,
> > priv->regs,
> > +			?? DISP_REG_OVL_BLD_L0_CLRFMT,
> > OVL_BLD_CON_CLRFMT_MAN |
> > +			?? OVL_BLD_CON_RGB_SWAP |?
> > OVL_BLD_CON_BYTE_SWAP |
> > +			?? OVL_BLD_CON_FLD_CLRFMT |
> > OVL_BLD_CON_FLD_CLRFMT_NB);
> 
> The mask should include OVL_BLD_CON_CLRFMT_NB_10_BIT
> 
> > +
> > +	if (mtk_ovl_is_ignore_pixel_alpha(state, blend_mode))
> > +		ignore_pixel_alpha = OVL_BLD_L0_CONST;
> > +	mtk_ddp_write_mask(cmdq_pkt, ignore_pixel_alpha, &priv-
> > >cmdq_reg, priv->regs,
> > +			?? DISP_REG_OVL_BLD_L0_ALPHA_SEL,
> > OVL_BLD_L0_CONST);
> > +
> > +	alpha = (OVL_BLD_L_ALPHA & (state->base.alpha >> 8)) |
> > OVL_BLD_L_ALPHA_EN;
> 
> Why do you always enable alpha?
> In ovl driver, it depend on state->base.fb->format->has_alpha to
> enable alpha.
> 
> > +	mtk_ddp_write_mask(cmdq_pkt, alpha, &priv->cmdq_reg, priv-
> > >regs,
> > +			?? DISP_REG_OVL_BLD_L_CON2,
> > OVL_BLD_L_ALPHA_EN | OVL_BLD_L_ALPHA);
> > +
> > +	mtk_ddp_write(cmdq_pkt, OVL_BLD_L_EN, &priv->cmdq_reg,
> > priv->regs, DISP_REG_OVL_BLD_L_EN);
> > +}
> > +
> 
> [snip]
> 
> > +static const struct mtk_disp_blender_data
> > mt8196_disp_blender_driver_data = {
> > +	.max_size = 8191,
> 
> Remove this SoC data. and
> 
> #define BLENDER_MAX_SIZE 8181
> 
> > +};
> > +
> > +static const struct of_device_id
> > mtk_disp_blender_driver_dt_match[] = {
> > +	{ .compatible = "mediatek,mt8196-blender",
> > +	? .data = &mt8196_disp_blender_driver_data},
> > +	{},
> > +};
> > +
> 
> [snip]
> 
> > diff --git a/drivers/gpu/drm/mediatek/mtk_disp_blender.h
> > b/drivers/gpu/drm/mediatek/mtk_disp_blender.h
> > new file mode 100644
> > index 000000000000..a47ab128649d
> > --- /dev/null
> > +++ b/drivers/gpu/drm/mediatek/mtk_disp_blender.h
> > @@ -0,0 +1,10 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +/*
> > + * Copyright (c) 2025 MediaTek Inc.
> > + */
> > +
> > +#ifndef __MTK_DISP_BLENDER_H__
> > +#define __MTK_DISP_BLENDER_H__
> > +
> > +u32 mtk_disp_blender_get_blend_modes(struct device *dev);
> 
> Move this prototype to mtk_disp_drv.h
> 
> > +#endif // __MTK_DISP_BLENDER_H__
> > diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
> > b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
> > index b9d8f17c4f31..e0aeb87f0a5b 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
> > +++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
> > @@ -9,6 +9,7 @@
> > ?#include <linux/soc/mediatek/mtk-cmdq.h>
> > ?#include <linux/soc/mediatek/mtk-mmsys.h>
> > ?#include <linux/soc/mediatek/mtk-mutex.h>
> > +#include "mtk_disp_blender.h"
> > ?#include "mtk_mdp_rdma.h"
> > ?#include "mtk_plane.h"
> > ?
> 


From jgg at nvidia.com  Fri Dec 19 09:05:51 2025
From: jgg at nvidia.com (Jason Gunthorpe)
Date: Fri, 19 Dec 2025 13:05:51 -0400
Subject: [PATCH v1 2/9] iommu/arm-smmu-v3: Add alloc_id/free_id functions
 to arm_smmu_invs
In-Reply-To: <1541ea4a9e9c935c2f907c0c5f13a4af2bdc2114.1766088962.git.nicolinc@nvidia.com>
References: <cover.1766088962.git.nicolinc@nvidia.com>
 <1541ea4a9e9c935c2f907c0c5f13a4af2bdc2114.1766088962.git.nicolinc@nvidia.com>
Message-ID: <20251219170551.GF254720@nvidia.com>

On Thu, Dec 18, 2025 at 12:26:48PM -0800, Nicolin Chen wrote:
> @@ -720,6 +723,9 @@ struct arm_smmu_invs {
>  	rwlock_t rwlock;
>  	bool has_ats;
>  	struct rcu_head rcu;
> +	struct arm_smmu_domain *smmu_domain;
> +	int (*alloc_id)(struct arm_smmu_inv *inv, void *data);
> +	void (*free_id)(struct arm_smmu_inv *inv, bool flush);
>  	struct arm_smmu_inv inv[] __counted_by(max_invs);
>  };

I'm not keen on this at all..

On the allocation side everything should be stored inside the
invalidation list, we don't need function callbacks, just get the
information from the list in the first place.

You could probably split it up a bit, introduce arm_smmu_iotlb_tag
first and spread it around, filling it from the domain, then the below
to use the invs array to fill it. But this whole series
should basically just be this:

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index d7c492ee093602..5cd71a9690e292 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1188,8 +1188,7 @@ EXPORT_SYMBOL_IF_KUNIT(arm_smmu_invs_merge);
  */
 VISIBLE_IF_KUNIT
 void arm_smmu_invs_unref(struct arm_smmu_invs *invs,
-			 struct arm_smmu_invs *to_unref,
-			 void (*free_fn)(struct arm_smmu_inv *inv))
+			 struct arm_smmu_invs *to_unref)
 {
 	unsigned long flags;
 	size_t num_invs = 0;
@@ -1200,16 +1199,16 @@ void arm_smmu_invs_unref(struct arm_smmu_invs *invs,
 		if (cmp < 0) {
 			/* not found in to_unref, leave alone */
 			num_invs = i + 1;
+			refcount_set(&to_unref->inv[j].users, 1);
 		} else if (cmp == 0) {
 			/* same item */
 			if (!refcount_dec_and_test(&invs->inv[i].users)) {
 				num_invs = i + 1;
+				refcount_set(&to_unref->inv[j].users, 1);
 				continue;
 			}
 
-			/* KUNIT test doesn't pass in a free_fn */
-			if (free_fn)
-				free_fn(&invs->inv[i]);
+			refcount_set(&to_unref->inv[j].users, 0);
 			invs->num_trashes++;
 		} else {
 			/* item in to_unref is not in invs or already a trash */
@@ -3046,6 +3045,13 @@ arm_smmu_find_master_domain(struct arm_smmu_domain *smmu_domain,
 	return NULL;
 }
 
+static struct arm_vsmmu *to_vsmmu(struct iommu_domain *domain)
+{
+	if (domain->type == IOMMU_DOMAIN_NESTED)
+		return to_smmu_nested_domain(domain)->vsmmu;
+	return NULL;
+}
+
 /*
  * If the domain uses the smmu_domain->devices list return the arm_smmu_domain
  * structure, otherwise NULL. These domains track attached devices so they can
@@ -3156,12 +3162,136 @@ arm_smmu_master_build_inv(struct arm_smmu_master *master,
 	case INV_TYPE_ATS:
 	case INV_TYPE_ATS_FULL:
 		cur->size_opcode = cur->nsize_opcode = CMDQ_OP_ATC_INV;
+		cur->ssid = ssid;
 		break;
 	}
 
 	return cur;
 }
 
+static int arm_smmu_get_id_from_invs(struct arm_smmu_domain *smmu_domain,
+				     struct arm_smmu_device *smmu,
+				     unsigned int type)
+{
+	struct arm_smmu_invs *invs = rcu_dereference_protected(
+		smmu_domain->invs, lockdep_is_held(&arm_smmu_asid_lock));
+	size_t i;
+
+	for (i = 0; i != invs->num_invs; i++) {
+		if (invs->inv[i].type == type &&
+		    invs->inv[i].smmu == smmu &&
+		    refcount_read(&invs->inv[i].users))
+		    return invs->inv[i].id;
+	}
+
+	return -ENOENT;
+}
+
+static int arm_smmu_get_tag(struct arm_smmu_domain *smmu_domain,
+			    struct arm_smmu_master *master,
+			    struct arm_vsmmu *vsmmu,
+			    struct arm_smmu_iotlb_tag *tag, bool no_alloc)
+{
+	struct arm_smmu_device *smmu = master->smmu;
+	int ret;
+	int id;
+
+	lockdep_assert_held(&arm_smmu_asid_lock);
+
+	switch (smmu_domain->stage) {
+	case ARM_SMMU_DOMAIN_SVA:
+	case ARM_SMMU_DOMAIN_S1: {
+		u32 asid;
+
+		if (WARN_ON(vsmmu))
+			return -EINVAL;
+
+		id = arm_smmu_get_id_from_invs(smmu_domain, smmu,
+					       INV_TYPE_S1_ASID);
+		if (id > 0) {
+			tag->asid = id;
+			return 0;
+		}
+
+		if (no_alloc)
+			return -ENOENT;
+
+		ret = xa_alloc(&arm_smmu_asid_xa, &asid, smmu_domain,
+			       XA_LIMIT(1, (1 << smmu->asid_bits) - 1),
+			       GFP_KERNEL);
+		if (ret)
+			return ret;
+		tag->asid = asid;
+		tag->need_free = 1;
+		return 0;
+	}
+
+	case ARM_SMMU_DOMAIN_S2:
+		if (smmu_domain->nest_parent) {
+			/* FIXME we can support attaching a nest_parent without
+			 * a vsmmu, but to do that we need to fix
+			 * arm_smmu_get_id_from_invs() to never return the vmid
+			 * of a vsmmu. Probably by making a
+			 * INV_TYPE_S2_VMID_VSMMU */
+			id = vsmmu->vmid;
+			return 0;
+		}
+
+		id = arm_smmu_get_id_from_invs(smmu_domain, smmu,
+					       INV_TYPE_S2_VMID);
+		if (id > 0) {
+			tag->vmid = id;
+			break;
+		}
+
+		if (no_alloc)
+			return -ENOENT;
+
+		/* Reserve VMID 0 for stage-2 bypass STEs */
+		id = ida_alloc_range(&smmu->vmid_map, 1,
+				     (1 << smmu->vmid_bits) - 1, GFP_KERNEL);
+		if (id < 0)
+			return id;
+		tag->vmid = id;
+		tag->need_free = 1;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static void arm_smmu_free_tag(struct arm_smmu_master *master,
+			      struct arm_smmu_domain *smmu_domain,
+			      struct arm_smmu_iotlb_tag *tag,
+			      struct arm_smmu_inv *inv)
+{
+	struct arm_smmu_device *smmu = master->smmu;
+	struct arm_smmu_cmdq_ent cmd = {};
+
+	switch (smmu_domain->stage) {
+	case ARM_SMMU_DOMAIN_SVA:
+	case ARM_SMMU_DOMAIN_S1:
+		cmd.opcode = inv->nsize_opcode;
+		cmd.tlbi.asid = tag->asid;
+		arm_smmu_cmdq_issue_cmd_with_sync(smmu, &cmd);
+		xa_erase(&arm_smmu_asid_xa, tag->asid);
+		return;
+
+	case ARM_SMMU_DOMAIN_S2:
+		cmd.opcode = inv->nsize_opcode;
+		cmd.tlbi.vmid = tag->vmid;
+		arm_smmu_cmdq_issue_cmd_with_sync(smmu, &cmd);
+
+		/*
+		 * Even though the VMID remains with the viommu and is not freed
+		 * we are stopping invalidations of it so it has to be cleared.
+		 */
+		if (smmu_domain->nest_parent)
+			return;
+		ida_free(&smmu->vmid_map, tag->vmid);
+		return;
+	}
+}
+
 /*
  * Use the preallocated scratch array at master->build_invs, to build a to_merge
  * or to_unref array, to pass into a following arm_smmu_invs_merge/unref() call.
@@ -3171,7 +3301,8 @@ arm_smmu_master_build_inv(struct arm_smmu_master *master,
  */
 static struct arm_smmu_invs *
 arm_smmu_master_build_invs(struct arm_smmu_master *master, bool ats_enabled,
-			   ioasid_t ssid, struct arm_smmu_domain *smmu_domain)
+			   ioasid_t ssid, struct arm_smmu_domain *smmu_domain,
+			   struct arm_smmu_iotlb_tag *tag)
 {
 	const bool nesting = smmu_domain->nest_parent;
 	size_t pgsize = 0, i;
@@ -3188,14 +3319,14 @@ arm_smmu_master_build_invs(struct arm_smmu_master *master, bool ats_enabled,
 	case ARM_SMMU_DOMAIN_SVA:
 	case ARM_SMMU_DOMAIN_S1:
 		if (!arm_smmu_master_build_inv(master, INV_TYPE_S1_ASID,
-					       smmu_domain->cd.asid,
-					       IOMMU_NO_PASID, pgsize))
+					       tag->asid, IOMMU_NO_PASID,
+					       pgsize))
 			return NULL;
 		break;
 	case ARM_SMMU_DOMAIN_S2:
 		if (!arm_smmu_master_build_inv(master, INV_TYPE_S2_VMID,
-					       smmu_domain->s2_cfg.vmid,
-					       IOMMU_NO_PASID, pgsize))
+					       tag->vmid, IOMMU_NO_PASID,
+					       pgsize))
 			return NULL;
 		break;
 	default:
@@ -3205,9 +3336,9 @@ arm_smmu_master_build_invs(struct arm_smmu_master *master, bool ats_enabled,
 
 	/* All the nested S1 ASIDs have to be flushed when S2 parent changes */
 	if (nesting) {
-		if (!arm_smmu_master_build_inv(
-			    master, INV_TYPE_S2_VMID_S1_CLEAR,
-			    smmu_domain->s2_cfg.vmid, IOMMU_NO_PASID, 0))
+		if (!arm_smmu_master_build_inv(master,
+					       INV_TYPE_S2_VMID_S1_CLEAR,
+					       tag->vmid, IOMMU_NO_PASID, 0))
 			return NULL;
 	}
 
@@ -3270,12 +3401,14 @@ static void arm_smmu_remove_master_domain(struct arm_smmu_master *master,
  * we are sequencing to update them.
  */
 static int arm_smmu_attach_prepare_invs(struct arm_smmu_attach_state *state,
+					struct iommu_domain *new_domain,
 					struct arm_smmu_domain *new_smmu_domain)
 {
 	struct arm_smmu_domain *old_smmu_domain =
 		to_smmu_domain_devices(state->old_domain);
 	struct arm_smmu_master *master = state->master;
 	ioasid_t ssid = state->ssid;
+	int ret;
 
 	/*
 	 * At this point a NULL domain indicates the domain doesn't use the
@@ -3289,8 +3422,18 @@ static int arm_smmu_attach_prepare_invs(struct arm_smmu_attach_state *state,
 		invst->old_invs = rcu_dereference_protected(
 			new_smmu_domain->invs,
 			lockdep_is_held(&arm_smmu_asid_lock));
-		build_invs = arm_smmu_master_build_invs(
-			master, state->ats_enabled, ssid, new_smmu_domain);
+
+		/* Re-use or allocate an IOTLB cache tag */
+		ret = arm_smmu_get_tag(new_smmu_domain, master,
+				       to_vsmmu(new_domain), &invst->tag,
+				       false);
+		if (ret)
+			return ret;
+
+		build_invs = arm_smmu_master_build_invs(master,
+							state->ats_enabled,
+							ssid, new_smmu_domain,
+							&invst->tag);
 		if (!build_invs)
 			return -EINVAL;
 
@@ -3311,9 +3454,18 @@ static int arm_smmu_attach_prepare_invs(struct arm_smmu_attach_state *state,
 			invst->old_invs = rcu_dereference_protected(
 				old_smmu_domain->invs,
 				lockdep_is_held(&arm_smmu_asid_lock));
+
+		/* Find the IOTLB cache tag this master was using */
+		ret = arm_smmu_get_tag(old_smmu_domain, master,
+				       to_vsmmu(state->old_domain), &invst->tag,
+				       true);
+		if (WARN_ON(ret))
+			return ret;
+
 		/* For old_smmu_domain, new_invs points to master->build_invs */
 		invst->new_invs = arm_smmu_master_build_invs(
-			master, master->ats_enabled, ssid, old_smmu_domain);
+			master, master->ats_enabled, ssid, old_smmu_domain,
+			&invst->tag);
 	}
 
 	return 0;
@@ -3349,36 +3501,13 @@ arm_smmu_install_new_domain_invs(struct arm_smmu_attach_state *state)
 	kfree_rcu(invst->old_invs, rcu);
 }
 
-/*
- * When an array entry's users count reaches zero, it means the ASID/VMID is no
- * longer being invalidated by map/unmap and must be cleaned. The rule is that
- * all ASIDs/VMIDs not in an invalidation array are left cleared in the IOTLB.
- */
-static void arm_smmu_inv_flush_iotlb_tag(struct arm_smmu_inv *inv)
-{
-	struct arm_smmu_cmdq_ent cmd = {};
-
-	switch (inv->type) {
-	case INV_TYPE_S1_ASID:
-		cmd.tlbi.asid = inv->id;
-		break;
-	case INV_TYPE_S2_VMID:
-		/* S2_VMID using nsize_opcode covers S2_VMID_S1_CLEAR */
-		cmd.tlbi.vmid = inv->id;
-		break;
-	default:
-		return;
-	}
-
-	cmd.opcode = inv->nsize_opcode;
-	arm_smmu_cmdq_issue_cmd_with_sync(inv->smmu, &cmd);
-}
-
 /* Should be installed after arm_smmu_install_ste_for_dev() */
 static void
 arm_smmu_install_old_domain_invs(struct arm_smmu_attach_state *state)
 {
 	struct arm_smmu_inv_state *invst = &state->old_domain_invst;
+	struct arm_smmu_domain *old_smmu_domain =
+		to_smmu_domain_devices(state->old_domain);
 	struct arm_smmu_invs *old_invs = invst->old_invs;
 	struct arm_smmu_invs *new_invs;
 
@@ -3387,8 +3516,10 @@ arm_smmu_install_old_domain_invs(struct arm_smmu_attach_state *state)
 	if (!invst->invs_ptr)
 		return;
 
-	arm_smmu_invs_unref(old_invs, invst->new_invs,
-			    arm_smmu_inv_flush_iotlb_tag);
+	arm_smmu_invs_unref(old_invs, invst->new_invs);
+	if (old_smmu_domain && !refcount_read(&invst->new_invs->inv[0].users))
+		arm_smmu_free_tag(state->master, old_smmu_domain, &invst->tag,
+				  invst->new_invs->inv);
 
 	new_invs = arm_smmu_invs_purge(old_invs);
 	if (!new_invs)
@@ -3472,9 +3603,9 @@ int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state,
 				     arm_smmu_ats_supported(master);
 	}
 
-	ret = arm_smmu_attach_prepare_invs(state, smmu_domain);
+	ret = arm_smmu_attach_prepare_invs(state, new_domain, smmu_domain);
 	if (ret)
-		return ret;
+		goto err_unprepare_invs;
 
 	if (smmu_domain) {
 		if (new_domain->type == IOMMU_DOMAIN_NESTED) {
@@ -3551,6 +3682,10 @@ int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state,
 err_free_vmaster:
 	kfree(state->vmaster);
 err_unprepare_invs:
+	if (state->new_domain_invst.tag.need_free)
+		arm_smmu_free_tag(master, smmu_domain,
+				  &state->new_domain_invst.tag,
+				  state->new_domain_invst.new_invs.inv);
 	kfree(state->new_domain_invst.new_invs);
 	return ret;
 }
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index 4f104c1baa67a2..689b5ca7d61525 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -1103,6 +1103,12 @@ static inline bool arm_smmu_master_canwbs(struct arm_smmu_master *master)
 	       IOMMU_FWSPEC_PCI_RC_CANWBS;
 }
 
+struct arm_smmu_iotlb_tag {
+	u16 need_free : 1;
+	u16 asid;
+	u16 vmid;
+};
+
 /**
  * struct arm_smmu_inv_state - Per-domain invalidation array state
  * @invs_ptr: points to the domain->invs (unwinding nesting/etc.) or is NULL if
@@ -1116,6 +1122,7 @@ struct arm_smmu_inv_state {
 	struct arm_smmu_invs __rcu **invs_ptr;
 	struct arm_smmu_invs *old_invs;
 	struct arm_smmu_invs *new_invs;
+	struct arm_smmu_iotlb_tag tag;
 };
 
 struct arm_smmu_attach_state {


From jgg at nvidia.com  Fri Dec 19 09:14:12 2025
From: jgg at nvidia.com (Jason Gunthorpe)
Date: Fri, 19 Dec 2025 13:14:12 -0400
Subject: [PATCH 3/4] ARM: remove support for highmem on VIVT
In-Reply-To: <20251219161559.556737-4-arnd@kernel.org>
References: <20251219161559.556737-1-arnd@kernel.org>
 <20251219161559.556737-4-arnd@kernel.org>
Message-ID: <20251219171412.GG254720@nvidia.com>

On Fri, Dec 19, 2025 at 05:15:58PM +0100, Arnd Bergmann wrote:
> From: Arnd Bergmann <arnd at arndb.de>
> 
> As Jason Gunthorpe noticed, supporting VIVT caches adds some complications
> to highmem that can be avoided these days:
> 
> While all ARMv4 and ARMv5 CPUs use virtually indexed caches, they no
> longer really need highmem because we have practically discontinued
> support for large-memory configurations already.  The only machines I
> could find anywhere for memory on ARMv5 are:
> 
>  - The Intel IOP platform was used on relatively large memory
>    configurations but we dropped kernel support in 2019 and 2022,
>    respectively.
> 
>  - The Marvell mv78xx0 platform was the initial user of Arm highmem,
>    with the DB-78x00-BP supporting 2GB of memory. While the platform
>    is still around, the only remaining board file is for
>    Buffalo WLX (Terastation Duo), which has only 512MB.
> 
>  - The Kirkwood platform supports 2GB, and there are actually boards
>    with that configuration that can still work. However, there are
>    no known users of the OpenBlocks A7, and the Freebox V6 is already
>    using CONFIG_VMSPLIT_2G to avoid enabling highmem.
> 
> Remove the Arm specific portions here, making CONFIG_HIGHMEM conditional
> on modern caches.
> 
> Suggested-by: Jason Gunthorpe <jgg at nvidia.com>
> Signed-off-by: Arnd Bergmann <arnd at arndb.de>
> ---
>  arch/arm/Kconfig                    |  1 +
>  arch/arm/configs/gemini_defconfig   |  1 -
>  arch/arm/configs/multi_v5_defconfig |  1 -
>  arch/arm/configs/mvebu_v5_defconfig |  1 -
>  arch/arm/include/asm/highmem.h      | 56 ++---------------------------
>  arch/arm/mm/cache-feroceon-l2.c     | 31 ++--------------
>  arch/arm/mm/cache-xsc3l2.c          | 47 +++---------------------
>  arch/arm/mm/dma-mapping.c           | 12 ++-----
>  arch/arm/mm/flush.c                 | 19 +++-------
>  9 files changed, 16 insertions(+), 153 deletions(-)

This looks great, but do you think there should be a boot time crash
if a VIVT and HIGHMEM are enabled, just incase?

Jason


From robin.murphy at arm.com  Fri Dec 19 09:19:06 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Fri, 19 Dec 2025 17:19:06 +0000
Subject: [PATCH v2] Faster Arm64 __arch_copy_from_user and
 __arch_copy_to_user
In-Reply-To: <20251018052237.1368504-2-benniu@meta.com>
References: <20251018052237.1368504-2-benniu@meta.com>
Message-ID: <5fc3d97e-2736-468a-8038-8ae411385590@arm.com>

On 18/10/2025 6:22 am, Ben Niu wrote:
> Summary:
> 
> This patch adapted arch/arm64/lib/memcpy.S to __arch_copy_from_user
> and __arch_copy_to_user and the new implementations seemed faster
> than the current implementations.
> 
> For __arch_copy_from_user, two new versions are provided: one for
> when PAN is enabled, in which case memcpy.S's ldp/ldr are replaced
> with ldtr; the other for when PAN is disabled. In both cases, proper
> fault handling code is added to handle exceptions when reading from
> unmapped user-mode pages.
> 
> Similarly, __arch_copy_to_user's PAN version has memcpy.S's stp/str
> replaced with sttr and also fault handling code is added.
> 
> In addition, a new test case usercopy_test_init is added in
> lib/tests/usercopy_kunit.c to exhaustively test all possible cases
> in which the new implementations could fault against user-mode
> pages.
> 
> Test Plan:
> 
> For functionality, I booted private kernels with the new impls w/wo
> PAN and usercopy_kunit. All the tests passed. Also, I tested the new
> functions using Arm's memcpy test (string/test/memcpy.c) on
> https://github.com/ARM-software/optimized-routines.
> 
> For performance, I used Arm's memcpy benchmark (string/bench/memcpy.c)
> on https://github.com/ARM-software/optimized-routines. See below for
> results on Neoverse V2:
> 
> Baseline:
> Random memcpy (bytes/ns):
>     __arch_copy_to_user 32K: 12.10 64K: 11.98 128K: 12.11 256K: 11.50 512K: 10.88 1024K:  8.60 avg 11.03
>   __arch_copy_from_user 32K: 12.04 64K: 11.82 128K: 12.11 256K: 11.94 512K: 10.99 1024K:  8.81 avg 11.15
> 
> Medium memcpy aligned (bytes/ns):
>     __arch_copy_to_user 8B:  5.25 16B:  7.52 32B: 15.05 64B: 26.27 128B: 46.56 256B: 50.71 512B: 51.66
>   __arch_copy_from_user 8B:  5.26 16B:  7.53 32B: 15.04 64B: 33.32 128B: 46.57 256B: 51.89 512B: 52.10
> 
> Medium memcpy unaligned (bytes/ns):
>     __arch_copy_to_user 8B:  5.27 16B:  6.57 32B: 11.63 64B: 23.28 128B: 27.17 256B: 40.80 512B: 46.52
>   __arch_copy_from_user 8B:  5.27 16B:  6.55 32B: 11.64 64B: 23.28 128B: 34.95 256B: 43.54 512B: 47.02
> 
> Large memcpy (bytes/ns):
>     __arch_copy_to_user 1K: 51.70 2K: 52.36 4K: 52.12 8K: 52.36 16K: 51.87 32K: 52.07 64K: 51.01
>   __arch_copy_from_user 1K: 52.43 2K: 52.35 4K: 52.34 8K: 52.27 16K: 51.86 32K: 52.14 64K: 52.17
> 
> New (with PAN):
> Random memcpy (bytes/ns):
>     __arch_copy_to_user 32K: 20.81 64K: 20.22 128K: 19.63 256K: 18.89 512K: 12.84 1024K:  9.83 avg 15.74
>   __arch_copy_from_user 32K: 23.28 64K: 22.21 128K: 21.49 256K: 21.07 512K: 14.60 1024K: 10.82 avg 17.52
> 
> Medium memcpy aligned (bytes/ns):
>     __arch_copy_to_user 8B:  7.53 16B: 17.57 32B: 21.11 64B: 26.91 128B: 46.80 256B: 46.33 512B: 49.32
>   __arch_copy_from_user 8B:  7.53 16B: 17.53 32B: 30.21 64B: 31.24 128B: 52.03 256B: 49.61 512B: 51.11
> 
> Medium memcpy unaligned (bytes/ns):
>     __arch_copy_to_user 8B:  7.53 16B: 13.16 32B: 26.30 64B: 24.06 128B: 30.10 256B: 30.15 512B: 30.38
>   __arch_copy_from_user 8B:  7.53 16B: 17.58 32B: 35.12 64B: 26.36 128B: 38.66 256B: 45.64 512B: 47.18
> 
> Large memcpy (bytes/ns):
>     __arch_copy_to_user 1K: 50.90 2K: 51.85 4K: 51.86 8K: 52.32 16K: 52.44 32K: 52.53 64K: 52.51
>   __arch_copy_from_user 1K: 51.92 2K: 52.32 4K: 52.47 8K: 52.27 16K: 52.51 32K: 52.62 64K: 52.57
> 
> New (without PAN):
> NoPAN
> Random memcpy (bytes/ns):
>     __arch_copy_to_user 32K: 23.20 64K: 22.02 128K: 21.06 256K: 19.34 512K: 17.46 1024K: 11.76 avg 18.18
>   __arch_copy_from_user 32K: 24.44 64K: 23.41 128K: 22.53 256K: 21.23 512K: 17.84 1024K: 11.71 avg 18.97
> 
> Medium memcpy aligned (bytes/ns):
>     __arch_copy_to_user 8B:  7.56 16B: 17.64 32B: 33.65 64B: 33.10 128B: 57.97 256B: 70.43 512B: 75.89
>   __arch_copy_from_user 8B:  7.57 16B: 17.67 32B: 32.89 64B: 31.40 128B: 52.93 256B: 71.36 512B: 75.97
> 
> Medium memcpy unaligned (bytes/ns):
>     __arch_copy_to_user 8B:  7.57 16B: 17.65 32B: 35.29 64B: 31.01 128B: 38.93 256B: 44.58 512B: 46.24
>   __arch_copy_from_user 8B:  7.57 16B: 17.67 32B: 35.23 64B: 29.51 128B: 40.30 256B: 44.57 512B: 46.26
> 
> Large memcpy (bytes/ns):
>     __arch_copy_to_user 1K: 77.33 2K: 77.89 4K: 78.19 8K: 76.36 16K: 77.39 32K: 77.94 64K: 77.72
>   __arch_copy_from_user 1K: 77.40 2K: 77.94 4K: 78.28 8K: 76.56 16K: 77.56 32K: 77.92 64K: 77.69
> 
> As can be seen, the new verions are faster than the baseline in almost all tests. The only slower
> cases 256B and 512B unaligned copies with PAN, and I hope the reviewers from Arm and the community
> could offer some suggestions on how to mitigate them.

In fairness it's quite hard *not* to be at least somewhat faster than 
the current code, but beware that big cores like Neoverse V are going to 
be the most forgiving, and the results could be quite different for 
something like Cortex-A53, and even those older CPUs are still very 
widely used so they do matter.

Certainly I found that a straight transliteration to ldrt/strt pairs in 
our memcpy routine is less than optimal across a range of 
microarchitectures, and it's possible to do a fair bit better still for 
many cases. Furthermore, microbenchmarks are one thing, but even a 100% 
improvement here may only equate to 0.1% on an overall workload (based 
on squinting at some numbers from our CI that would need orders of 
magnitude more runs to reach any statistical significance), so there 
would really need to be an overwhelmingly strong justification for 
having a separate !CONFIG_PAN version to chase a relatively small 
fraction more at the potential cost of weakening security/robustness (or 
at the very least, the ongoing cost of having to *reason* about security 
more than we currently have to with the architectural guarantees of 
unprivileged accesses).

As for the patch itself, from a quick look I have to say I find the mass 
of numeric labels even harder to follow that the monstrosity I came up 
with 2 years ago, and while it looks like you don't quite have the same 
copy_to_user bug I had (missing the adjustment of src in the copy_long 
retry case), I think what you've done instead won't work for big-endian.

Thanks,
Robin.

> ---
> v2:
>    - Added linux-arm-kernel at lists.infradead.org and linux-kernel at vger.kernel.org
>      to recipient lists for public submission
>    - No code changes
> ---
>   arch/arm64/lib/copy_from_user.S | 434 ++++++++++++++++++++--
>   arch/arm64/lib/copy_template.S  | 191 ----------
>   arch/arm64/lib/copy_to_user.S   | 615 ++++++++++++++++++++++++++++++--
>   lib/tests/usercopy_kunit.c      | 303 ++++++++++++----
>   4 files changed, 1199 insertions(+), 344 deletions(-)
>   delete mode 100644 arch/arm64/lib/copy_template.S
> 
> diff --git a/arch/arm64/lib/copy_from_user.S b/arch/arm64/lib/copy_from_user.S
> index 400057d607ec..a4e8dbd10336 100644
> --- a/arch/arm64/lib/copy_from_user.S
> +++ b/arch/arm64/lib/copy_from_user.S
> @@ -20,38 +20,6 @@
>    *	x0 - bytes not copied
>    */
>   
> -	.macro ldrb1 reg, ptr, val
> -	user_ldst 9998f, ldtrb, \reg, \ptr, \val
> -	.endm
> -
> -	.macro strb1 reg, ptr, val
> -	strb \reg, [\ptr], \val
> -	.endm
> -
> -	.macro ldrh1 reg, ptr, val
> -	user_ldst 9997f, ldtrh, \reg, \ptr, \val
> -	.endm
> -
> -	.macro strh1 reg, ptr, val
> -	strh \reg, [\ptr], \val
> -	.endm
> -
> -	.macro ldr1 reg, ptr, val
> -	user_ldst 9997f, ldtr, \reg, \ptr, \val
> -	.endm
> -
> -	.macro str1 reg, ptr, val
> -	str \reg, [\ptr], \val
> -	.endm
> -
> -	.macro ldp1 reg1, reg2, ptr, val
> -	user_ldp 9997f, \reg1, \reg2, \ptr, \val
> -	.endm
> -
> -	.macro stp1 reg1, reg2, ptr, val
> -	stp \reg1, \reg2, [\ptr], \val
> -	.endm
> -
>   	.macro cpy1 dst, src, count
>   	.arch_extension mops
>   	USER_CPY(9997f, 0, cpyfprt [\dst]!, [\src]!, \count!)
> @@ -59,13 +27,45 @@
>   	USER_CPY(9996f, 0, cpyfert [\dst]!, [\src]!, \count!)
>   	.endm
>   
> -end	.req	x5
> -srcin	.req	x15
> +dstin	.req	x0
> +src	.req	x1
> +count	.req	x2
> +dst	.req	x3
> +srcend	.req	x4
> +dstend	.req	x5
> +srcin	.req	x6
> +A_l	.req	x6
> +A_lw	.req	w6
> +A_h	.req	x7
> +B_l	.req	x8
> +B_lw	.req	w8
> +B_h	.req	x9
> +C_l	.req	x10
> +C_lw	.req	w10
> +C_h	.req	x11
> +D_l	.req	x12
> +D_h	.req	x13
> +E_l	.req	x14
> +E_h	.req	x15
> +F_l	.req	x16
> +F_h	.req	x17
> +G_l	.req	count
> +G_h	.req	dst
> +H_l	.req	src
> +H_h	.req	srcend
> +tmp1	.req	x14
> +tmp2	.req	x15
> +
>   SYM_FUNC_START(__arch_copy_from_user)
> -	add	end, x0, x2
> +#ifdef CONFIG_AS_HAS_MOPS
> +alternative_if_not ARM64_HAS_MOPS
> +	b	.Lno_mops
> +alternative_else_nop_endif
> +	add	dstend, x0, x2
>   	mov	srcin, x1
> -#include "copy_template.S"
> -	mov	x0, #0				// Nothing to copy
> +	mov	dst, dstin
> +	cpy1	dst, src, count
> +	mov	x0, #0				// Nothing left to copy
>   	ret
>   
>   	// Exception fixups
> @@ -79,5 +79,365 @@ USER(9998f, ldtrb tmp1w, [srcin])
>   	strb	tmp1w, [dst], #1
>   9998:	sub	x0, end, dst			// bytes not copied
>   	ret
> +
> +.Lno_mops:
> +#endif
> +
> +#ifdef CONFIG_ARM64_PAN
> +	add	srcend, src, count
> +	add	dstend, dstin, count
> +	cmp	count, 128
> +	b.hi	.Lcopy_long
> +	cmp	count, 32
> +	b.hi	.Lcopy32_128
> +
> +	/* Small copies: 0..32 bytes.  */
> +	cmp	count, 16
> +	b.lo	.Lcopy16
> +	USER(9000f, ldtr A_l, [src])
> +	USER(9000f, ldtr A_h, [src, 8])
> +	USER(9000f, ldtr D_l, [srcend, -16])
> +	USER(9000f, ldtr D_h, [srcend, -8])
> +	stp	A_l, A_h, [dstin]
> +	stp	D_l, D_h, [dstend, -16]
> +	mov	x0, #0
> +	ret
> +
> +	/* Copy 8-15 bytes.  */
> +.Lcopy16:
> +	tbz	count, 3, .Lcopy8
> +	USER(9000f, ldtr	A_l, [src])
> +	USER(9000f, ldtr	A_h, [srcend, -8])
> +	str	A_l, [dstin]
> +	str	A_h, [dstend, -8]
> +	mov	x0, #0
> +	ret
> +
> +	.p2align 3
> +	/* Copy 4-7 bytes.  */
> +.Lcopy8:
> +	tbz	count, 2, .Lcopy4
> +	USER(9000f, ldtr	A_lw, [src])
> +	USER(9000f, ldtr	B_lw, [srcend, -4])
> +	str	A_lw, [dstin]
> +	str	B_lw, [dstend, -4]
> +	mov	x0, #0
> +	ret
> +
> +	/* Copy 0..3 bytes using a branchless sequence.  */
> +.Lcopy4:
> +	cbz	count, .Lcopy0
> +	lsr	tmp1, count, 1
> +	add tmp2, src, count, lsr 1
> +	USER(9000f, ldtrb	A_lw, [src])
> +	USER(9000f, ldtrb	B_lw, [tmp2])
> +	USER(9000f, ldtrb	C_lw, [srcend, -1])
> +	strb	A_lw, [dstin]
> +	strb	B_lw, [dstin, tmp1]
> +	strb	C_lw, [dstend, -1]
> +.Lcopy0:
> +	mov	x0, #0
> +	ret
> +
> +	.p2align 4
> +	/* Medium copies: 33..128 bytes.  */
> +.Lcopy32_128:
> +	USER(9000f, ldtr A_l, [src])
> +	USER(9000f, ldtr A_h, [src, 8])
> +	USER(9000f, ldtr B_l, [src, 16])
> +	USER(9000f, ldtr B_h, [src, 24])
> +	stp	A_l, A_h, [dstin]
> +	stp	B_l, B_h, [dstin, 16]
> +	cmp	count, 64
> +	b.hi	.Lcopy128
> +	USER(9001f, ldtr C_l, [srcend, -32])
> +	USER(9001f, ldtr C_h, [srcend, -24])
> +	USER(9001f, ldtr D_l, [srcend, -16])
> +	USER(9001f, ldtr D_h, [srcend, -8])
> +	stp	C_l, C_h, [dstend, -32]
> +	stp	D_l, D_h, [dstend, -16]
> +	mov	x0, #0
> +	ret
> +
> +	.p2align 4
> +	/* Copy 65..128 bytes.  */
> +.Lcopy128:
> +	USER(9001f, ldtr E_l, [src, 32])
> +	USER(9001f, ldtr E_h, [src, 40])
> +	USER(9001f, ldtr F_l, [src, 48])
> +	USER(9001f, ldtr F_h, [src, 56])
> +	stp	E_l, E_h, [dstin, 32]
> +	stp	F_l, F_h, [dstin, 48]
> +	cmp	count, 96
> +	b.ls	.Lcopy96
> +	USER(9002f, ldtr C_l, [srcend, -64])
> +	USER(9002f, ldtr C_h, [srcend, -56])
> +	USER(9002f, ldtr D_l, [srcend, -48])
> +	USER(9002f, ldtr D_h, [srcend, -40])
> +	stp	C_l, C_h, [dstend, -64]
> +	stp	D_l, D_h, [dstend, -48]
> +.Lcopy96:
> +	USER(9002f, ldtr G_l, [srcend, -32])
> +	USER(9002f, ldtr G_h, [srcend, -24])
> +	USER(9002f, ldtr H_l, [srcend, -16])
> +	USER(9002f, ldtr H_h, [srcend, -8])
> +	stp	G_l, G_h, [dstend, -32]
> +	stp	H_l, H_h, [dstend, -16]
> +	mov	x0, #0
> +	ret
> +
> +	.p2align 4
> +	/* Copy more than 128 bytes.  */
> +.Lcopy_long:
> +	/* Copy 16 bytes and then align dst to 16-byte alignment.  */
> +	USER(9000f, ldtr	D_l, [src])
> +	USER(9000f, ldtr	D_h, [src, 8])
> +	and	tmp1, dstin, 15
> +	bic	dst, dstin, 15
> +	sub	src, src, tmp1
> +	add	count, count, tmp1	/* Count is now 16 too large.  */
> +	USER(9003f, ldtr	A_l, [src, 16])
> +	USER(9003f, ldtr	A_h, [src, 24])
> +	stp	D_l, D_h, [dstin]
> +	USER(9004f, ldtr	B_l, [src, 32])
> +	USER(9004f, ldtr	B_h, [src, 40])
> +	USER(9004f, ldtr	C_l, [src, 48])
> +	USER(9004f, ldtr	C_h, [src, 56])
> +	USER(9004f, ldtr	D_l, [src, 64])
> +	USER(9004f, ldtr	D_h, [src, 72])
> +	add		src, src, 64
> +	subs	count, count, 128 + 16	/* Test and readjust count.  */
> +	b.ls	.Lcopy64_from_end
> +.Lloop64:
> +	stp	A_l, A_h, [dst, 16]
> +	USER(9005f, ldtr	A_l, [src, 16])
> +	USER(9005f, ldtr	A_h, [src, 24])
> +	stp	B_l, B_h, [dst, 32]
> +	USER(9006f, ldtr	B_l, [src, 32])
> +	USER(9006f, ldtr	B_h, [src, 40])
> +	stp	C_l, C_h, [dst, 48]
> +	USER(9007f, ldtr	C_l, [src, 48])
> +	USER(9007f, ldtr	C_h, [src, 56])
> +	stp	D_l, D_h, [dst, 64]!
> +	USER(9008f, ldtr	D_l, [src, 64])
> +	USER(9008f, ldtr	D_h, [src, 72])
> +	add		src, src, 64
> +	subs	count, count, 64
> +	b.hi	.Lloop64
> +
> +	/* Write the last iteration and copy 64 bytes from the end.  */
> +.Lcopy64_from_end:
> +	USER(9005f, ldtr	E_l, [srcend, -64])
> +	USER(9005f, ldtr	E_h, [srcend, -56])
> +	stp	A_l, A_h, [dst, 16]
> +	USER(9006f, ldtr	A_l, [srcend, -48])
> +	USER(9006f, ldtr	A_h, [srcend, -40])
> +	stp	B_l, B_h, [dst, 32]
> +	USER(9007f, ldtr	B_l, [srcend, -32])
> +	USER(9007f, ldtr	B_h, [srcend, -24])
> +	stp	C_l, C_h, [dst, 48]
> +	USER(9009f, ldtr	C_l, [srcend, -16])
> +	USER(9009f, ldtr	C_h, [srcend, -8])
> +	stp	D_l, D_h, [dst, 64]
> +	stp	E_l, E_h, [dstend, -64]
> +	stp	A_l, A_h, [dstend, -48]
> +	stp	B_l, B_h, [dstend, -32]
> +	stp	C_l, C_h, [dstend, -16]
> + 	mov	x0, #0				// Nothing to copy
> + 	ret
> +
> +#else
> +
> +	add	srcend, src, count
> +	add	dstend, dstin, count
> +	cmp	count, 128
> +	b.hi	.Lcopy_long
> +	cmp	count, 32
> +	b.hi	.Lcopy32_128
> +
> +	/* Small copies: 0..32 bytes.  */
> +	cmp	count, 16
> +	b.lo	.Lcopy16
> +	USER(9000f, ldp	A_l, A_h, [src])
> +	USER(9000f, ldp	D_l, D_h, [srcend, -16])
> +	stp	A_l, A_h, [dstin]
> +	stp	D_l, D_h, [dstend, -16]
> +	mov	x0, #0
> +	ret
> +
> +	/* Copy 8-15 bytes.  */
> +.Lcopy16:
> +	tbz	count, 3, .Lcopy8
> +	USER(9000f, ldr	A_l, [src])
> +	USER(9000f, ldr	A_h, [srcend, -8])
> +	str	A_l, [dstin]
> +	str	A_h, [dstend, -8]
> +	mov	x0, #0
> +	ret
> +
> +	.p2align 3
> +	/* Copy 4-7 bytes.  */
> +.Lcopy8:
> +	tbz	count, 2, .Lcopy4
> +	USER(9000f, ldr	A_lw, [src])
> +	USER(9000f, ldr	B_lw, [srcend, -4])
> +	str	A_lw, [dstin]
> +	str	B_lw, [dstend, -4]
> +	mov	x0, #0
> +	ret
> +
> +	/* Copy 0..3 bytes using a branchless sequence.  */
> +.Lcopy4:
> +	cbz	count, .Lcopy0
> +	lsr	tmp1, count, 1
> +	USER(9000f, ldrb	A_lw, [src])
> +	USER(9000f, ldrb	B_lw, [src, tmp1])
> +	USER(9000f, ldrb	C_lw, [srcend, -1])
> +	strb	A_lw, [dstin]
> +	strb	B_lw, [dstin, tmp1]
> +	strb	C_lw, [dstend, -1]
> +.Lcopy0:
> +	mov	x0, #0
> +	ret
> +
> +	.p2align 4
> +	/* Medium copies: 33..128 bytes.  */
> +.Lcopy32_128:
> +	USER(9000f, ldp	A_l, A_h, [src])
> +	USER(9000f, ldp	B_l, B_h, [src, 16])
> +	stp	A_l, A_h, [dstin]
> +	stp	B_l, B_h, [dstin, 16]
> +	cmp	count, 64
> +	b.hi	.Lcopy128
> +	USER(9001f, ldp	C_l, C_h, [srcend, -32])
> +	USER(9001f, ldp	D_l, D_h, [srcend, -16])
> +	stp	C_l, C_h, [dstend, -32]
> +	stp	D_l, D_h, [dstend, -16]
> +	mov	x0, #0
> +	ret
> +
> +	.p2align 4
> +	/* Copy 65..128 bytes.  */
> +.Lcopy128:
> +	USER(9001f, ldp	E_l, E_h, [src, 32])
> +	USER(9001f, ldp	F_l, F_h, [src, 48])
> +	stp	E_l, E_h, [dstin, 32]
> +	stp	F_l, F_h, [dstin, 48]
> +	cmp	count, 96
> +	b.ls	.Lcopy96
> +	USER(9002f, ldp	C_l, C_h, [srcend, -64])
> +	USER(9002f, ldp	D_l, D_h, [srcend, -48])
> +	stp	C_l, C_h, [dstend, -64]
> +	stp	D_l, D_h, [dstend, -48]
> +.Lcopy96:
> +	USER(9002f, ldp	G_l, G_h, [srcend, -32])
> +	USER(9002f, ldp	H_l, H_h, [srcend, -16])
> +	stp	G_l, G_h, [dstend, -32]
> +	stp	H_l, H_h, [dstend, -16]
> +	mov	x0, #0
> +	ret
> +
> +	.p2align 4
> +	/* Copy more than 128 bytes.  */
> +.Lcopy_long:
> +	/* Copy 16 bytes and then align dst to 16-byte alignment.  */
> +
> +	USER(9000f, ldp	D_l, D_h, [src])
> +	and	tmp1, dstin, 15
> +	bic	dst, dstin, 15
> +	sub	src, src, tmp1
> +	add	count, count, tmp1	/* Count is now 16 too large.  */
> +	USER(9003f, ldp	A_l, A_h, [src, 16])
> +	stp	D_l, D_h, [dstin]
> +	USER(9004f, ldp	B_l, B_h, [src, 32])
> +	USER(9004f, ldp	C_l, C_h, [src, 48])
> +	USER(9004f, ldp	D_l, D_h, [src, 64]!)
> +	subs	count, count, 128 + 16	/* Test and readjust count.  */
> +	b.ls	.Lcopy64_from_end
> +
> +.Lloop64:
> +	stp	A_l, A_h, [dst, 16]
> +	USER(9005f, ldp	A_l, A_h, [src, 16])
> +	stp	B_l, B_h, [dst, 32]
> +	USER(9006f, ldp	B_l, B_h, [src, 32])
> +	stp	C_l, C_h, [dst, 48]
> +	USER(9007f, ldp	C_l, C_h, [src, 48])
> +	stp	D_l, D_h, [dst, 64]!
> +	USER(9008f, ldp	D_l, D_h, [src, 64]!)
> +	subs	count, count, 64
> +	b.hi	.Lloop64
> +
> +	/* Write the last iteration and copy 64 bytes from the end.  */
> +.Lcopy64_from_end:
> +	USER(9005f, ldp	E_l, E_h, [srcend, -64])
> +	stp	A_l, A_h, [dst, 16]
> +	USER(9006f, ldp	A_l, A_h, [srcend, -48])
> +	stp	B_l, B_h, [dst, 32]
> +	USER(9007f, ldp	B_l, B_h, [srcend, -32])
> +	stp	C_l, C_h, [dst, 48]
> +	USER(9009f, ldp	C_l, C_h, [srcend, -16])
> +	stp	D_l, D_h, [dst, 64]
> +	stp	E_l, E_h, [dstend, -64]
> +	stp	A_l, A_h, [dstend, -48]
> +	stp	B_l, B_h, [dstend, -32]
> +	stp	C_l, C_h, [dstend, -16]
> +	mov	x0, #0				// Nothing to copy
> +	ret
> +
> +#endif
> +
> + 	// non-mops exception fixups
> +9003:
> +	sub count, count, tmp1
> +9000:
> + 	// Before being absolutely sure we couldn't copy anything, try harder
> +	USER(.Lcopy_none, ldtrb A_lw, [src])
> +	strb A_lw, [dstin]
> +	sub x0, count, 1
> +	ret
> +
> +9001:
> +	sub x0, count, 32
> +	ret
> +
> +9002:
> +	sub count, dstend, dstin
> +	sub x0, count, 64
> +	ret
> +
> +9004:
> +	sub count, count, tmp1
> +	sub x0, count, 16
> +	ret
> +
> +9005:
> +	add tmp1, dstin, 16
> +	add x0, dst, 16
> +	cmp x0, tmp1
> +	csel x0, x0, tmp1, hi
> +	b	.Lsub_destend_x0
> +
> +9006:
> +	add x0, dst, 32
> +	b	.Lsub_destend_x0
> +
> +9007:
> +	add x0, dst, 48
> +	b	.Lsub_destend_x0
> +
> +9008:
> +	sub x0, dstend, dst
> +    ret
> +
> +9009:
> +	add x0, dst, 64
> +.Lsub_destend_x0:
> +	sub x0, dstend, x0
> + 	ret
> +
> +.Lcopy_none: // bytes not copied at all
> +	mov x0, count
> +	ret
> +
>   SYM_FUNC_END(__arch_copy_from_user)
>   EXPORT_SYMBOL(__arch_copy_from_user)
> diff --git a/arch/arm64/lib/copy_template.S b/arch/arm64/lib/copy_template.S
> deleted file mode 100644
> index 7f2f5a0e2fb9..000000000000
> --- a/arch/arm64/lib/copy_template.S
> +++ /dev/null
> @@ -1,191 +0,0 @@
> -/* SPDX-License-Identifier: GPL-2.0-only */
> -/*
> - * Copyright (C) 2013 ARM Ltd.
> - * Copyright (C) 2013 Linaro.
> - *
> - * This code is based on glibc cortex strings work originally authored by Linaro
> - * be found @
> - *
> - * http://bazaar.launchpad.net/~linaro-toolchain-dev/cortex-strings/trunk/
> - * files/head:/src/aarch64/
> - */
> -
> -
> -/*
> - * Copy a buffer from src to dest (alignment handled by the hardware)
> - *
> - * Parameters:
> - *	x0 - dest
> - *	x1 - src
> - *	x2 - n
> - * Returns:
> - *	x0 - dest
> - */
> -dstin	.req	x0
> -src	.req	x1
> -count	.req	x2
> -tmp1	.req	x3
> -tmp1w	.req	w3
> -tmp2	.req	x4
> -tmp2w	.req	w4
> -dst	.req	x6
> -
> -A_l	.req	x7
> -A_h	.req	x8
> -B_l	.req	x9
> -B_h	.req	x10
> -C_l	.req	x11
> -C_h	.req	x12
> -D_l	.req	x13
> -D_h	.req	x14
> -
> -	mov	dst, dstin
> -
> -#ifdef CONFIG_AS_HAS_MOPS
> -alternative_if_not ARM64_HAS_MOPS
> -	b	.Lno_mops
> -alternative_else_nop_endif
> -	cpy1	dst, src, count
> -	b	.Lexitfunc
> -.Lno_mops:
> -#endif
> -
> -	cmp	count, #16
> -	/*When memory length is less than 16, the accessed are not aligned.*/
> -	b.lo	.Ltiny15
> -
> -	neg	tmp2, src
> -	ands	tmp2, tmp2, #15/* Bytes to reach alignment. */
> -	b.eq	.LSrcAligned
> -	sub	count, count, tmp2
> -	/*
> -	* Copy the leading memory data from src to dst in an increasing
> -	* address order.By this way,the risk of overwriting the source
> -	* memory data is eliminated when the distance between src and
> -	* dst is less than 16. The memory accesses here are alignment.
> -	*/
> -	tbz	tmp2, #0, 1f
> -	ldrb1	tmp1w, src, #1
> -	strb1	tmp1w, dst, #1
> -1:
> -	tbz	tmp2, #1, 2f
> -	ldrh1	tmp1w, src, #2
> -	strh1	tmp1w, dst, #2
> -2:
> -	tbz	tmp2, #2, 3f
> -	ldr1	tmp1w, src, #4
> -	str1	tmp1w, dst, #4
> -3:
> -	tbz	tmp2, #3, .LSrcAligned
> -	ldr1	tmp1, src, #8
> -	str1	tmp1, dst, #8
> -
> -.LSrcAligned:
> -	cmp	count, #64
> -	b.ge	.Lcpy_over64
> -	/*
> -	* Deal with small copies quickly by dropping straight into the
> -	* exit block.
> -	*/
> -.Ltail63:
> -	/*
> -	* Copy up to 48 bytes of data. At this point we only need the
> -	* bottom 6 bits of count to be accurate.
> -	*/
> -	ands	tmp1, count, #0x30
> -	b.eq	.Ltiny15
> -	cmp	tmp1w, #0x20
> -	b.eq	1f
> -	b.lt	2f
> -	ldp1	A_l, A_h, src, #16
> -	stp1	A_l, A_h, dst, #16
> -1:
> -	ldp1	A_l, A_h, src, #16
> -	stp1	A_l, A_h, dst, #16
> -2:
> -	ldp1	A_l, A_h, src, #16
> -	stp1	A_l, A_h, dst, #16
> -.Ltiny15:
> -	/*
> -	* Prefer to break one ldp/stp into several load/store to access
> -	* memory in an increasing address order,rather than to load/store 16
> -	* bytes from (src-16) to (dst-16) and to backward the src to aligned
> -	* address,which way is used in original cortex memcpy. If keeping
> -	* the original memcpy process here, memmove need to satisfy the
> -	* precondition that src address is at least 16 bytes bigger than dst
> -	* address,otherwise some source data will be overwritten when memove
> -	* call memcpy directly. To make memmove simpler and decouple the
> -	* memcpy's dependency on memmove, withdrew the original process.
> -	*/
> -	tbz	count, #3, 1f
> -	ldr1	tmp1, src, #8
> -	str1	tmp1, dst, #8
> -1:
> -	tbz	count, #2, 2f
> -	ldr1	tmp1w, src, #4
> -	str1	tmp1w, dst, #4
> -2:
> -	tbz	count, #1, 3f
> -	ldrh1	tmp1w, src, #2
> -	strh1	tmp1w, dst, #2
> -3:
> -	tbz	count, #0, .Lexitfunc
> -	ldrb1	tmp1w, src, #1
> -	strb1	tmp1w, dst, #1
> -
> -	b	.Lexitfunc
> -
> -.Lcpy_over64:
> -	subs	count, count, #128
> -	b.ge	.Lcpy_body_large
> -	/*
> -	* Less than 128 bytes to copy, so handle 64 here and then jump
> -	* to the tail.
> -	*/
> -	ldp1	A_l, A_h, src, #16
> -	stp1	A_l, A_h, dst, #16
> -	ldp1	B_l, B_h, src, #16
> -	ldp1	C_l, C_h, src, #16
> -	stp1	B_l, B_h, dst, #16
> -	stp1	C_l, C_h, dst, #16
> -	ldp1	D_l, D_h, src, #16
> -	stp1	D_l, D_h, dst, #16
> -
> -	tst	count, #0x3f
> -	b.ne	.Ltail63
> -	b	.Lexitfunc
> -
> -	/*
> -	* Critical loop.  Start at a new cache line boundary.  Assuming
> -	* 64 bytes per line this ensures the entire loop is in one line.
> -	*/
> -	.p2align	L1_CACHE_SHIFT
> -.Lcpy_body_large:
> -	/* pre-get 64 bytes data. */
> -	ldp1	A_l, A_h, src, #16
> -	ldp1	B_l, B_h, src, #16
> -	ldp1	C_l, C_h, src, #16
> -	ldp1	D_l, D_h, src, #16
> -1:
> -	/*
> -	* interlace the load of next 64 bytes data block with store of the last
> -	* loaded 64 bytes data.
> -	*/
> -	stp1	A_l, A_h, dst, #16
> -	ldp1	A_l, A_h, src, #16
> -	stp1	B_l, B_h, dst, #16
> -	ldp1	B_l, B_h, src, #16
> -	stp1	C_l, C_h, dst, #16
> -	ldp1	C_l, C_h, src, #16
> -	stp1	D_l, D_h, dst, #16
> -	ldp1	D_l, D_h, src, #16
> -	subs	count, count, #64
> -	b.ge	1b
> -	stp1	A_l, A_h, dst, #16
> -	stp1	B_l, B_h, dst, #16
> -	stp1	C_l, C_h, dst, #16
> -	stp1	D_l, D_h, dst, #16
> -
> -	tst	count, #0x3f
> -	b.ne	.Ltail63
> -.Lexitfunc:
> diff --git a/arch/arm64/lib/copy_to_user.S b/arch/arm64/lib/copy_to_user.S
> index 819f2e3fc7a9..e50bdcef7cdf 100644
> --- a/arch/arm64/lib/copy_to_user.S
> +++ b/arch/arm64/lib/copy_to_user.S
> @@ -19,37 +19,6 @@
>    * Returns:
>    *	x0 - bytes not copied
>    */
> -	.macro ldrb1 reg, ptr, val
> -	ldrb  \reg, [\ptr], \val
> -	.endm
> -
> -	.macro strb1 reg, ptr, val
> -	user_ldst 9998f, sttrb, \reg, \ptr, \val
> -	.endm
> -
> -	.macro ldrh1 reg, ptr, val
> -	ldrh  \reg, [\ptr], \val
> -	.endm
> -
> -	.macro strh1 reg, ptr, val
> -	user_ldst 9997f, sttrh, \reg, \ptr, \val
> -	.endm
> -
> -	.macro ldr1 reg, ptr, val
> -	ldr \reg, [\ptr], \val
> -	.endm
> -
> -	.macro str1 reg, ptr, val
> -	user_ldst 9997f, sttr, \reg, \ptr, \val
> -	.endm
> -
> -	.macro ldp1 reg1, reg2, ptr, val
> -	ldp \reg1, \reg2, [\ptr], \val
> -	.endm
> -
> -	.macro stp1 reg1, reg2, ptr, val
> -	user_stp 9997f, \reg1, \reg2, \ptr, \val
> -	.endm
>   
>   	.macro cpy1 dst, src, count
>   	.arch_extension mops
> @@ -58,16 +27,48 @@
>   	USER_CPY(9996f, 1, cpyfewt [\dst]!, [\src]!, \count!)
>   	.endm
>   
> -end	.req	x5
> -srcin	.req	x15
> +dstin	.req	x0
> +src	.req	x1
> +count	.req	x2
> +dst	.req	x3
> +srcend	.req	x4
> +dstend	.req	x5
> +srcin	.req	x6
> +A_l	.req	x6
> +A_lw	.req	w6
> +A_h	.req	x7
> +B_l	.req	x8
> +B_lw	.req	w8
> +B_h	.req	x9
> +C_l	.req	x10
> +C_lw	.req	w10
> +C_h	.req	x11
> +D_l	.req	x12
> +D_lw	.req	w12
> +D_h	.req	x13
> +E_l	.req	x14
> +E_h	.req	x15
> +F_l	.req	x16
> +F_h	.req	x17
> +G_l	.req	count
> +G_h	.req	dst
> +H_l	.req	src
> +H_h	.req	srcend
> +tmp1	.req	x14
> +
>   SYM_FUNC_START(__arch_copy_to_user)
> -	add	end, x0, x2
> +#ifdef CONFIG_AS_HAS_MOPS
> +alternative_if_not ARM64_HAS_MOPS
> +	b	.Lno_mops
> +alternative_else_nop_endif
> +	add	dstend, x0, x2
>   	mov	srcin, x1
> -#include "copy_template.S"
> -	mov	x0, #0
> +	mov	dst, dstin
> +	cpy1	dst, src, count
> +	mov	x0, #0				// Nothing left to copy
>   	ret
>   
> -	// Exception fixups
> +	// mops exception fixups
>   9996:	b.cs	9997f
>   	// Registers are in Option A format
>   	add	dst, dst, count
> @@ -77,7 +78,545 @@ SYM_FUNC_START(__arch_copy_to_user)
>   	ldrb	tmp1w, [srcin]
>   USER(9998f, sttrb tmp1w, [dst])
>   	add	dst, dst, #1
> -9998:	sub	x0, end, dst			// bytes not copied
> +9998:	sub	x0, dstend, dst			// bytes not copied
> +	ret
> +
> +.Lno_mops:
> +#endif
> +
> +#ifdef CONFIG_ARM64_PAN
> +	add	srcend, src, count
> +	add	dstend, dstin, count
> +	cmp	count, 128
> +	b.hi	.Lcopy_long
> +	cmp	count, 32
> +	b.hi	.Lcopy32_128
> +
> +	/* Small copies: 0..32 bytes.  */
> +	cmp	count, 16
> +	b.lo	.Lcopy16
> +	ldp	A_l, A_h, [src]
> +	ldp	D_l, D_h, [srcend, -16]
> +	USER(9000f, sttr A_l, [dstin])
> +	USER(9001f, sttr A_h, [dstin, 8])
> +	USER(9002f, sttr D_l, [dstend, -16])
> +	USER(9003f, sttr D_h, [dstend, -8])
> +	mov	x0, #0
> +	ret
> +
> +	/* Copy 8-15 bytes.  */
> +.Lcopy16:
> +	tbz	count, 3, .Lcopy8
> +	ldr	A_l, [src]
> +	ldr	A_h, [srcend, -8]
> +	USER(9004f, sttr A_l, [dstin])
> +	USER(9005f, sttr A_h, [dstend, -8])
> +	mov	x0, #0
> +	ret
> +
> +	.p2align 3
> +	/* Copy 4-7 bytes.  */
> +.Lcopy8:
> +	tbz	count, 2, .Lcopy4
> +	ldr	A_lw, [src]
> +	ldr	B_lw, [srcend, -4]
> +	USER(9006f, sttr A_lw, [dstin])
> +	USER(9007f, sttr B_lw, [dstend, -4])
> +	mov	x0, #0
> +	ret
> +
> +	/* Copy 0..3 bytes using a branchless sequence.  */
> +.Lcopy4:
> +	cbz	count, .Lcopy0
> +	lsr tmp1, count, #1
> +	add dst, dstin, count, lsr #1
> +	ldrb A_lw, [src]
> +	ldrb C_lw, [srcend, -1]
> +	ldrb B_lw, [src, tmp1]
> +	USER(9008f, sttrb A_lw, [dstin])
> +	USER(9009f, sttrb B_lw, [dst])
> +	USER(9010f, sttrb C_lw, [dstend, -1])
> +.Lcopy0:
> +	mov	x0, #0
> +	ret
> +
> +	.p2align 4
> +	/* Medium copies: 33..128 bytes.  */
> +.Lcopy32_128:
> +	ldp	A_l, A_h, [src]
> +	ldp	B_l, B_h, [src, 16]
> +	ldp	C_l, C_h, [srcend, -32]
> +	ldp	D_l, D_h, [srcend, -16]
> +	USER(9011f, sttr A_l, [dstin])
> +	USER(9012f, sttr A_h, [dstin, 8])
> +	USER(9013f, sttr B_l, [dstin, 16])
> +	USER(9014f, sttr B_h, [dstin, 24])
> +	cmp	count, 64
> +	b.hi	.Lcopy128
> +	USER(9015f, sttr C_l, [dstend, -32])
> +	USER(9016f, sttr C_h, [dstend, -24])
> +	USER(9017f, sttr D_l, [dstend, -16])
> +	USER(9018f, sttr D_h, [dstend, -8])
> +	mov	x0, #0
> +	ret
> +
> +	.p2align 4
> +	/* Copy 65..128 bytes.  */
> +.Lcopy128:
> +	ldp	E_l, E_h, [src, 32]
> +	ldp	F_l, F_h, [src, 48]
> +	USER(9023f, sttr E_l, [dstin, 32])
> +	USER(9024f, sttr E_h, [dstin, 40])
> +	USER(9025f, sttr F_l, [dstin, 48])
> +	USER(9026f, sttr F_h, [dstin, 56])
> +	cmp	count, 96
> +	b.ls	.Lcopy96
> +	ldp	G_l, G_h, [srcend, -64]
> +	ldp	H_l, H_h, [srcend, -48]
> +	USER(9027f, sttr G_l, [dstend, -64])
> +	USER(9028f, sttr G_h, [dstend, -56])
> +	USER(9029f, sttr H_l, [dstend, -48])
> +	USER(9030f, sttr H_h, [dstend, -40])
> +.Lcopy96:
> +	USER(9043f, sttr C_l, [dstend, -32])
> +	USER(9044f, sttr C_h, [dstend, -24])
> +	USER(9045f, sttr D_l, [dstend, -16])
> +	USER(9046f, sttr D_h, [dstend, -8])
> +	mov	x0, #0
> +	ret
> +
> +	.p2align 4
> +	/* Copy more than 128 bytes.  */
> +.Lcopy_long:
> +	/* Copy 16 bytes and then align dst to 16-byte alignment.  */
> +	ldp	D_l, D_h, [src]
> +	and	tmp1, dstin, 15
> +	bic	dst, dstin, 15
> +	sub	src, src, tmp1
> +	add	count, count, tmp1	/* Count is now 16 too large.  */
> +	ldp	A_l, A_h, [src, 16]
> +	USER(9047f, sttr D_l, [dstin])
> +	USER(9048f, sttr D_h, [dstin, 8])
> +	ldp	B_l, B_h, [src, 32]
> +	ldp	C_l, C_h, [src, 48]
> +	ldp	D_l, D_h, [src, 64]!
> +	subs	count, count, 128 + 16	/* Test and readjust count.  */
> +	b.ls	.Lcopy64_from_end
> +
> +.Lloop64:
> +	USER(9049f, sttr A_l, [dst, 16])
> +	USER(9050f, sttr A_h, [dst, 24])
> +	ldp	A_l, A_h, [src, 16]
> +	USER(9051f, sttr B_l, [dst, 32])
> +	USER(9052f, sttr B_h, [dst, 40])
> +	ldp	B_l, B_h, [src, 32]
> +	USER(9053f, sttr C_l, [dst, 48])
> +	USER(9054f, sttr C_h, [dst, 56])
> +	ldp	C_l, C_h, [src, 48]
> +	USER(9055f, sttr D_l, [dst, 64])
> +	USER(9056f, sttr D_h, [dst, 72])
> +	add dst, dst, 64
> +	ldp	D_l, D_h, [src, 64]!
> +	subs	count, count, 64
> +	b.hi	.Lloop64
> +
> +	/* Write the last iteration and copy 64 bytes from the end.  */
> +.Lcopy64_from_end:
> +	ldp	E_l, E_h, [srcend, -64]
> +	USER(9057f, sttr A_l, [dst, 16])
> +	USER(9058f, sttr A_h, [dst, 24])
> +	ldp	A_l, A_h, [srcend, -48]
> +	USER(9059f, sttr B_l, [dst, 32])
> +	USER(9060f, sttr B_h, [dst, 40])
> +	ldp	B_l, B_h, [srcend, -32]
> +	USER(9061f, sttr C_l, [dst, 48])
> +	USER(9062f, sttr C_h, [dst, 56])
> +	ldp	C_l, C_h, [srcend, -16]
> +	USER(9063f, sttr D_l, [dst, 64])
> +	USER(9064f, sttr D_h, [dst, 72])
> +	USER(9065f, sttr E_l, [dstend, -64])
> +	USER(9066f, sttr E_h, [dstend, -56])
> +	USER(9067f, sttr A_l, [dstend, -48])
> +	USER(9068f, sttr A_h, [dstend, -40])
> +	USER(9069f, sttr B_l, [dstend, -32])
> +	USER(9070f, sttr B_h, [dstend, -24])
> +	USER(9071f, sttr C_l, [dstend, -16])
> +	USER(9072f, sttr C_h, [dstend, -8])
> + 	mov	x0, #0
> + 	ret
> +
> +#else
> +
> +	add	srcend, src, count
> +	add	dstend, dstin, count
> +	cmp	count, 128
> +	b.hi	.Lcopy_long
> +	cmp	count, 32
> +	b.hi	.Lcopy32_128
> +
> +	/* Small copies: 0..32 bytes.  */
> +	cmp	count, 16
> +	b.lo	.Lcopy16
> +	ldp	A_l, A_h, [src]
> +	ldp	D_l, D_h, [srcend, -16]
> +	USER(9000f, stp	A_l, A_h, [dstin])
> +	USER(9002f, stp	D_l, D_h, [dstend, -16])
> +	mov x0, #0
> +	ret
> +
> +	/* Copy 8-15 bytes.  */
> +.Lcopy16:
> +	tbz	count, 3, .Lcopy8
> +	ldr	A_l, [src]
> +	ldr	A_h, [srcend, -8]
> +	USER(9004f, str	A_l, [dstin])
> +	USER(9005f, str	A_h, [dstend, -8])
> +	mov x0, #0
> +	ret
> +
> +	.p2align 3
> +	/* Copy 4-7 bytes.  */
> +.Lcopy8:
> +	tbz	count, 2, .Lcopy4
> +	ldr	A_lw, [src]
> +	ldr	B_lw, [srcend, -4]
> +	USER(9006f, str	A_lw, [dstin])
> +	USER(9007f, str	B_lw, [dstend, -4])
> +	mov x0, #0
> +	ret
> +
> +	/* Copy 0..3 bytes using a branchless sequence.  */
> +.Lcopy4:
> +	cbz	count, .Lcopy0
> +	lsr	tmp1, count, 1
> +	ldrb	A_lw, [src]
> +	ldrb	C_lw, [srcend, -1]
> +	ldrb	B_lw, [src, tmp1]
> +	USER(9008f, strb	A_lw, [dstin])
> +	USER(9009f, strb	B_lw, [dstin, tmp1])
> +	USER(9010f, strb	C_lw, [dstend, -1])
> +.Lcopy0:
> +	mov x0, #0
> +	ret
> +
> +	.p2align 4
> +	/* Medium copies: 33..128 bytes.  */
> +.Lcopy32_128:
> +	ldp	A_l, A_h, [src]
> +	ldp	B_l, B_h, [src, 16]
> +	ldp	C_l, C_h, [srcend, -32]
> +	ldp	D_l, D_h, [srcend, -16]
> +	USER(9011f, stp	A_l, A_h, [dstin])
> +	USER(9013f, stp	B_l, B_h, [dstin, 16])
> +	cmp	count, 64
> +	b.hi	.Lcopy128
> +	USER(9015f, stp	C_l, C_h, [dstend, -32])
> +	USER(9017f, stp	D_l, D_h, [dstend, -16])
> +	mov x0, #0
>   	ret
> +
> +	.p2align 4
> +	/* Copy 65..128 bytes.  */
> +.Lcopy128:
> +	ldp	E_l, E_h, [src, 32]
> +	ldp	F_l, F_h, [src, 48]
> +	USER(9023f, stp	E_l, E_h, [dstin, 32])
> +	USER(9025f, stp	F_l, F_h, [dstin, 48])
> +	cmp	count, 96
> +	b.ls	.Lcopy96
> +	ldp	G_l, G_h, [srcend, -64]
> +	ldp	H_l, H_h, [srcend, -48]
> +	USER(9027f, stp	G_l, G_h, [dstend, -64])
> +	USER(9029f, stp	H_l, H_h, [dstend, -48])
> +.Lcopy96:
> +	USER(9043f, stp	C_l, C_h, [dstend, -32])
> +	USER(9045f, stp	D_l, D_h, [dstend, -16])
> +	mov x0, #0
> +	ret
> +
> +	.p2align 4
> +	/* Copy more than 128 bytes.  */
> +.Lcopy_long:
> +	/* Copy 16 bytes and then align dst to 16-byte alignment.  */
> +
> +	ldp	D_l, D_h, [src]
> +	and	tmp1, dstin, 15
> +	bic	dst, dstin, 15
> +	sub	src, src, tmp1
> +	add	count, count, tmp1	/* Count is now 16 too large.  */
> +	ldp	A_l, A_h, [src, 16]
> +	USER(9047f, stp	D_l, D_h, [dstin])
> +	ldp	B_l, B_h, [src, 32]
> +	ldp	C_l, C_h, [src, 48]
> +	ldp	D_l, D_h, [src, 64]!
> +	subs	count, count, 128 + 16	/* Test and readjust count.  */
> +	b.ls	.Lcopy64_from_end
> +
> +.Lloop64:
> +	USER(9049f, stp	A_l, A_h, [dst, 16])
> +	ldp	A_l, A_h, [src, 16]
> +	USER(9051f, stp	B_l, B_h, [dst, 32])
> +	ldp	B_l, B_h, [src, 32]
> +	USER(9053f, stp	C_l, C_h, [dst, 48])
> +	ldp	C_l, C_h, [src, 48]
> +	USER(9055f, stp	D_l, D_h, [dst, 64]!)
> +	ldp	D_l, D_h, [src, 64]!
> +	subs	count, count, 64
> +	b.hi	.Lloop64
> +
> +	/* Write the last iteration and copy 64 bytes from the end.  */
> +.Lcopy64_from_end:
> +	ldp	E_l, E_h, [srcend, -64]
> +	USER(9057f, stp	A_l, A_h, [dst, 16])
> +	ldp	A_l, A_h, [srcend, -48]
> +	USER(9059f, stp	B_l, B_h, [dst, 32])
> +	ldp	B_l, B_h, [srcend, -32]
> +	USER(9061f, stp	C_l, C_h, [dst, 48])
> +	ldp	C_l, C_h, [srcend, -16]
> +	USER(9063f, stp	D_l, D_h, [dst, 64])
> +	USER(9065f, stp	E_l, E_h, [dstend, -64])
> +	USER(9067f, stp	A_l, A_h, [dstend, -48])
> +	USER(9069f, stp	B_l, B_h, [dstend, -32])
> +	USER(9071f, stp	C_l, C_h, [dstend, -16])
> +	mov x0, #0
> +	ret
> +
> +#endif
> +
> + 	// non-mops exception fixups
> +9000:
> +9004:
> +9006:
> +9011:
> +	// Before being absolutely sure we couldn't copy anything, try harder
> +	USER(.Lcopy_none, sttrb A_lw, [dstin])
> +	b	.Lcount_minus_one
> +
> +9020:
> +	sub count, dstend, dstin
> +	b	.Lcount_minus_8
> +
> +9021:
> +	sub count, dstend, dstin
> +	b	.Lcount_minus_16
> +
> +9022:
> +	sub count, dstend, dstin
> +	b	.Lcount_minus_24
> +
> +9023:
> +	sub count, dstend, dstin
> +	b	.Lcount_minus_32
> +
> +9024:
> +	sub count, dstend, dstin
> +	b	.Lcount_minus_40
> +
> +9025:
> +	sub count, dstend, dstin
> +	b	.Lcount_minus_48
> +
> +9026:
> +	sub count, dstend, dstin
> +	b	.Lcount_minus_56
> +
> +9007:
> +	sub x0, count, #4
> +	ret
> +
> +9047:
> +	sub	count, count, tmp1
> +	USER(.Lcopy_none, sttrb D_lw, [dstin])
> +9009:
> +.Lcount_minus_one:
> +	sub x0, count, #1
> +	ret
> +
> +9001:
> +9005:
> +9012:
> +.Lcount_minus_8:
> +	sub x0, count, #8
> +	ret
> +
> +9003:
> +	add tmp1, dstin, #16
> +	sub x0, dstend, #8
> +	b	.Lmax
> +
> +9049:
> +9057:
> +	sub count, dstend, dst
> +9002:
> +9013:
> +.Lcount_minus_16:
> +	sub x0, count, #16
> +	ret
> +
> +9050:
> +9058:
> +	sub count, dstend, dst
> +9014:
> +.Lcount_minus_24:
> +	sub x0, count, #24
> +	ret
> +
> +9048:
> +	sub count, count, tmp1
> +	b	.Lcount_minus_8
> +
> +9010:
> +	mov x0, #1
> +	ret
> +
> +9018:
> +	add tmp1, dstin, #32
> +	sub x0, dstend, #8
> +	b	.Lmax
> +
> +9046:
> +	add tmp1, dstin, #64
> +	sub x0, dstend, #8
> +	b	.Lmax
> +
> +9072:
> +	add tmp1, dst, #80
> +	sub x0, dstend, #8
> +	b	.Lmax
> +
> +9017:
> +	add tmp1, dstin, #32
> +	sub x0, dstend, #16
> +	b	.Lmax
> +
> +9045:
> +	add tmp1, dstin, #64
> +	sub x0, dstend, #16
> +	b	.Lmax
> +
> +9071:
> +	add tmp1, dst, #80
> +	sub x0, dstend, #16
> +	b	.Lmax
> +
> +9016:
> +	add tmp1, dstin, #32
> +	sub x0, dstend, #24
> +	b	.Lmax
> +
> +9044:
> +	add tmp1, dstin, #64
> +	sub x0, dstend, #24
> +	b	.Lmax
> +
> +9070:
> +	add tmp1, dst, #80
> +	sub x0, dstend, #24
> +	b	.Lmax
> +
> +9015:
> +	add tmp1, dstin, #32
> +	sub x0, dstend, #32
> +	b	.Lmax
> +
> +9043:
> +	add tmp1, dstin, #64
> +	sub x0, dstend, #32
> +	b	.Lmax
> +
> +9069:
> +	add tmp1, dst, #80
> +	sub x0, dstend, #32
> +	b	.Lmax
> +
> +9030:
> +	add tmp1, dstin, #64
> +	sub x0, dstend, #40
> +	b	.Lmax
> +
> +9068:
> +	add tmp1, dst, #80
> +	sub x0, dstend, #40
> +	b	.Lmax
> +
> +9029:
> +	add tmp1, dstin, #64
> +	sub x0, dstend, #48
> +	b	.Lmax
> +
> +9067:
> +	add tmp1, dst, #80
> +	sub x0, dstend, #48
> +	b	.Lmax
> +
> +9028:
> +	add tmp1, dstin, #64
> +	sub x0, dstend, #56
> +	b	.Lmax
> +
> +9066:
> +	add tmp1, dst, #80
> +	sub x0, dstend, #56
> +	b	.Lmax
> +
> +9027:
> +	sub count, dstend, dstin
> +	b	.Lcount_minus_64
> +
> +9065:
> +	add tmp1, dst, #80
> +	sub x0, dstend, #64
> +.Lmax:
> +	cmp x0, tmp1
> +	csel x0, x0, tmp1, hi
> +	sub x0, dstend, x0
> +	ret
> +
> +9051:
> +9059:
> +	sub count, dstend, dst
> +.Lcount_minus_32:
> +	sub x0, count, #32
> +	ret
> +
> +9052:
> +9060:
> +	sub count, dstend, dst
> +.Lcount_minus_40:
> +	sub x0, count, #40
> +	ret
> +
> +9053:
> +9061:
> +	sub count, dstend, dst
> +.Lcount_minus_48:
> +	sub x0, count, #48
> +	ret
> +
> +9054:
> +9062:
> +	sub count, dstend, dst
> +.Lcount_minus_56:
> +	sub x0, count, #56
> +	ret
> +
> +9055:
> +9063:
> +	sub count, dstend, dst
> +.Lcount_minus_64:
> +	sub x0, count, #64
> +	ret
> +
> +9056:
> +9064:
> +	sub count, dstend, dst
> +	sub x0, count, #72
> +	ret
> +
> +9008:
> +.Lcopy_none: // bytes not copied at all
> +	mov x0, count
> +	ret
> +
>   SYM_FUNC_END(__arch_copy_to_user)
>   EXPORT_SYMBOL(__arch_copy_to_user)
> diff --git a/lib/tests/usercopy_kunit.c b/lib/tests/usercopy_kunit.c
> index 80f8abe10968..d4f4f9ee5f48 100644
> --- a/lib/tests/usercopy_kunit.c
> +++ b/lib/tests/usercopy_kunit.c
> @@ -22,14 +22,12 @@
>    * As there doesn't appear to be anything that can safely determine
>    * their capability at compile-time, we just have to opt-out certain archs.
>    */
> -#if BITS_PER_LONG == 64 || (!(defined(CONFIG_ARM) && !defined(MMU)) && \
> -			    !defined(CONFIG_M68K) &&		\
> -			    !defined(CONFIG_MICROBLAZE) &&	\
> -			    !defined(CONFIG_NIOS2) &&		\
> -			    !defined(CONFIG_PPC32) &&		\
> -			    !defined(CONFIG_SPARC32) &&		\
> -			    !defined(CONFIG_SUPERH))
> -# define TEST_U64
> +#if BITS_PER_LONG == 64 ||                                                   \
> +	(!(defined(CONFIG_ARM) && !defined(MMU)) && !defined(CONFIG_M68K) && \
> +	 !defined(CONFIG_MICROBLAZE) && !defined(CONFIG_NIOS2) &&            \
> +	 !defined(CONFIG_PPC32) && !defined(CONFIG_SPARC32) &&               \
> +	 !defined(CONFIG_SUPERH))
> +#define TEST_U64
>   #endif
>   
>   struct usercopy_test_priv {
> @@ -87,7 +85,7 @@ static void usercopy_test_check_nonzero_user(struct kunit *test)
>   		kmem[i] = 0xff;
>   
>   	KUNIT_EXPECT_EQ_MSG(test, copy_to_user(umem, kmem, size), 0,
> -		"legitimate copy_to_user failed");
> +			    "legitimate copy_to_user failed");
>   
>   	for (start = 0; start <= size; start++) {
>   		for (end = start; end <= size; end++) {
> @@ -95,7 +93,8 @@ static void usercopy_test_check_nonzero_user(struct kunit *test)
>   			int retval = check_zeroed_user(umem + start, len);
>   			int expected = is_zeroed(kmem + start, len);
>   
> -			KUNIT_ASSERT_EQ_MSG(test, retval, expected,
> +			KUNIT_ASSERT_EQ_MSG(
> +				test, retval, expected,
>   				"check_nonzero_user(=%d) != memchr_inv(=%d) mismatch (start=%zu, end=%zu)",
>   				retval, expected, start, end);
>   		}
> @@ -121,7 +120,7 @@ static void usercopy_test_copy_struct_from_user(struct kunit *test)
>   	/* Fill umem with a fixed byte pattern. */
>   	memset(umem_src, 0x3e, size);
>   	KUNIT_ASSERT_EQ_MSG(test, copy_to_user(umem, umem_src, size), 0,
> -		    "legitimate copy_to_user failed");
> +			    "legitimate copy_to_user failed");
>   
>   	/* Check basic case -- (usize == ksize). */
>   	ksize = size;
> @@ -130,10 +129,12 @@ static void usercopy_test_copy_struct_from_user(struct kunit *test)
>   	memcpy(expected, umem_src, ksize);
>   
>   	memset(kmem, 0x0, size);
> -	KUNIT_EXPECT_EQ_MSG(test, copy_struct_from_user(kmem, ksize, umem, usize), 0,
> -		    "copy_struct_from_user(usize == ksize) failed");
> -	KUNIT_EXPECT_MEMEQ_MSG(test, kmem, expected, ksize,
> -		    "copy_struct_from_user(usize == ksize) gives unexpected copy");
> +	KUNIT_EXPECT_EQ_MSG(test,
> +			    copy_struct_from_user(kmem, ksize, umem, usize), 0,
> +			    "copy_struct_from_user(usize == ksize) failed");
> +	KUNIT_EXPECT_MEMEQ_MSG(
> +		test, kmem, expected, ksize,
> +		"copy_struct_from_user(usize == ksize) gives unexpected copy");
>   
>   	/* Old userspace case -- (usize < ksize). */
>   	ksize = size;
> @@ -143,18 +144,21 @@ static void usercopy_test_copy_struct_from_user(struct kunit *test)
>   	memset(expected + usize, 0x0, ksize - usize);
>   
>   	memset(kmem, 0x0, size);
> -	KUNIT_EXPECT_EQ_MSG(test, copy_struct_from_user(kmem, ksize, umem, usize), 0,
> -		    "copy_struct_from_user(usize < ksize) failed");
> -	KUNIT_EXPECT_MEMEQ_MSG(test, kmem, expected, ksize,
> -		    "copy_struct_from_user(usize < ksize) gives unexpected copy");
> +	KUNIT_EXPECT_EQ_MSG(test,
> +			    copy_struct_from_user(kmem, ksize, umem, usize), 0,
> +			    "copy_struct_from_user(usize < ksize) failed");
> +	KUNIT_EXPECT_MEMEQ_MSG(
> +		test, kmem, expected, ksize,
> +		"copy_struct_from_user(usize < ksize) gives unexpected copy");
>   
>   	/* New userspace (-E2BIG) case -- (usize > ksize). */
>   	ksize = size / 2;
>   	usize = size;
>   
>   	memset(kmem, 0x0, size);
> -	KUNIT_EXPECT_EQ_MSG(test, copy_struct_from_user(kmem, ksize, umem, usize), -E2BIG,
> -		    "copy_struct_from_user(usize > ksize) didn't give E2BIG");
> +	KUNIT_EXPECT_EQ_MSG(
> +		test, copy_struct_from_user(kmem, ksize, umem, usize), -E2BIG,
> +		"copy_struct_from_user(usize > ksize) didn't give E2BIG");
>   
>   	/* New userspace (success) case -- (usize > ksize). */
>   	ksize = size / 2;
> @@ -162,13 +166,15 @@ static void usercopy_test_copy_struct_from_user(struct kunit *test)
>   
>   	memcpy(expected, umem_src, ksize);
>   	KUNIT_EXPECT_EQ_MSG(test, clear_user(umem + ksize, usize - ksize), 0,
> -		    "legitimate clear_user failed");
> +			    "legitimate clear_user failed");
>   
>   	memset(kmem, 0x0, size);
> -	KUNIT_EXPECT_EQ_MSG(test, copy_struct_from_user(kmem, ksize, umem, usize), 0,
> -		    "copy_struct_from_user(usize > ksize) failed");
> -	KUNIT_EXPECT_MEMEQ_MSG(test, kmem, expected, ksize,
> -		    "copy_struct_from_user(usize > ksize) gives unexpected copy");
> +	KUNIT_EXPECT_EQ_MSG(test,
> +			    copy_struct_from_user(kmem, ksize, umem, usize), 0,
> +			    "copy_struct_from_user(usize > ksize) failed");
> +	KUNIT_EXPECT_MEMEQ_MSG(
> +		test, kmem, expected, ksize,
> +		"copy_struct_from_user(usize > ksize) gives unexpected copy");
>   }
>   
>   /*
> @@ -182,28 +188,29 @@ static void usercopy_test_valid(struct kunit *test)
>   
>   	memset(kmem, 0x3a, PAGE_SIZE * 2);
>   	KUNIT_EXPECT_EQ_MSG(test, 0, copy_to_user(usermem, kmem, PAGE_SIZE),
> -	     "legitimate copy_to_user failed");
> +			    "legitimate copy_to_user failed");
>   	memset(kmem, 0x0, PAGE_SIZE);
>   	KUNIT_EXPECT_EQ_MSG(test, 0, copy_from_user(kmem, usermem, PAGE_SIZE),
> -	     "legitimate copy_from_user failed");
> +			    "legitimate copy_from_user failed");
>   	KUNIT_EXPECT_MEMEQ_MSG(test, kmem, kmem + PAGE_SIZE, PAGE_SIZE,
> -	     "legitimate usercopy failed to copy data");
> -
> -#define test_legit(size, check)						\
> -	do {								\
> -		size val_##size = (check);				\
> -		KUNIT_EXPECT_EQ_MSG(test, 0,				\
> -			put_user(val_##size, (size __user *)usermem),	\
> -			"legitimate put_user (" #size ") failed");	\
> -		val_##size = 0;						\
> -		KUNIT_EXPECT_EQ_MSG(test, 0,				\
> -			get_user(val_##size, (size __user *)usermem),	\
> -			"legitimate get_user (" #size ") failed");	\
> -		KUNIT_EXPECT_EQ_MSG(test, val_##size, check,		\
> -			"legitimate get_user (" #size ") failed to do copy"); \
> +			       "legitimate usercopy failed to copy data");
> +
> +#define test_legit(size, check)                                                \
> +	do {                                                                   \
> +		size val_##size = (check);                                     \
> +		KUNIT_EXPECT_EQ_MSG(                                           \
> +			test, 0, put_user(val_##size, (size __user *)usermem), \
> +			"legitimate put_user (" #size ") failed");             \
> +		val_##size = 0;                                                \
> +		KUNIT_EXPECT_EQ_MSG(                                           \
> +			test, 0, get_user(val_##size, (size __user *)usermem), \
> +			"legitimate get_user (" #size ") failed");             \
> +		KUNIT_EXPECT_EQ_MSG(test, val_##size, check,                   \
> +				    "legitimate get_user (" #size              \
> +				    ") failed to do copy");                    \
>   	} while (0)
>   
> -	test_legit(u8,  0x5a);
> +	test_legit(u8, 0x5a);
>   	test_legit(u16, 0x5a5b);
>   	test_legit(u32, 0x5a5b5c5d);
>   #ifdef TEST_U64
> @@ -225,7 +232,9 @@ static void usercopy_test_invalid(struct kunit *test)
>   
>   	if (IS_ENABLED(CONFIG_ALTERNATE_USER_ADDRESS_SPACE) ||
>   	    !IS_ENABLED(CONFIG_MMU)) {
> -		kunit_skip(test, "Testing for kernel/userspace address confusion is only sensible on architectures with a shared address space");
> +		kunit_skip(
> +			test,
> +			"Testing for kernel/userspace address confusion is only sensible on architectures with a shared address space");
>   		return;
>   	}
>   
> @@ -234,13 +243,16 @@ static void usercopy_test_invalid(struct kunit *test)
>   	memset(kmem + PAGE_SIZE, 0, PAGE_SIZE);
>   
>   	/* Reject kernel-to-kernel copies through copy_from_user(). */
> -	KUNIT_EXPECT_NE_MSG(test, copy_from_user(kmem, (char __user *)(kmem + PAGE_SIZE),
> -						 PAGE_SIZE), 0,
> -		    "illegal all-kernel copy_from_user passed");
> +	KUNIT_EXPECT_NE_MSG(test,
> +			    copy_from_user(kmem,
> +					   (char __user *)(kmem + PAGE_SIZE),
> +					   PAGE_SIZE),
> +			    0, "illegal all-kernel copy_from_user passed");
>   
>   	/* Destination half of buffer should have been zeroed. */
> -	KUNIT_EXPECT_MEMEQ_MSG(test, kmem + PAGE_SIZE, kmem, PAGE_SIZE,
> -		    "zeroing failure for illegal all-kernel copy_from_user");
> +	KUNIT_EXPECT_MEMEQ_MSG(
> +		test, kmem + PAGE_SIZE, kmem, PAGE_SIZE,
> +		"zeroing failure for illegal all-kernel copy_from_user");
>   
>   #if 0
>   	/*
> @@ -253,31 +265,36 @@ static void usercopy_test_invalid(struct kunit *test)
>   						 PAGE_SIZE), 0,
>   		    "illegal reversed copy_from_user passed");
>   #endif
> -	KUNIT_EXPECT_NE_MSG(test, copy_to_user((char __user *)kmem, kmem + PAGE_SIZE,
> -					       PAGE_SIZE), 0,
> -		    "illegal all-kernel copy_to_user passed");
> -
> -	KUNIT_EXPECT_NE_MSG(test, copy_to_user((char __user *)kmem, bad_usermem,
> -					       PAGE_SIZE), 0,
> -		    "illegal reversed copy_to_user passed");
> -
> -#define test_illegal(size, check)							\
> -	do {										\
> -		size val_##size = (check);						\
> -		/* get_user() */							\
> -		KUNIT_EXPECT_NE_MSG(test, get_user(val_##size, (size __user *)kmem), 0,	\
> -		    "illegal get_user (" #size ") passed");				\
> -		KUNIT_EXPECT_EQ_MSG(test, val_##size, 0,				\
> -		    "zeroing failure for illegal get_user (" #size ")");		\
> -		/* put_user() */							\
> -		*kmem_u64 = 0xF09FA4AFF09FA4AF;						\
> -		KUNIT_EXPECT_NE_MSG(test, put_user(val_##size, (size __user *)kmem), 0,	\
> -		    "illegal put_user (" #size ") passed");				\
> -		KUNIT_EXPECT_EQ_MSG(test, *kmem_u64, 0xF09FA4AFF09FA4AF,		\
> -		    "illegal put_user (" #size ") wrote to kernel memory!");		\
> +	KUNIT_EXPECT_NE_MSG(test,
> +			    copy_to_user((char __user *)kmem, kmem + PAGE_SIZE,
> +					 PAGE_SIZE),
> +			    0, "illegal all-kernel copy_to_user passed");
> +
> +	KUNIT_EXPECT_NE_MSG(
> +		test, copy_to_user((char __user *)kmem, bad_usermem, PAGE_SIZE),
> +		0, "illegal reversed copy_to_user passed");
> +
> +#define test_illegal(size, check)                                              \
> +	do {                                                                   \
> +		size val_##size = (check);                                     \
> +		/* get_user() */                                               \
> +		KUNIT_EXPECT_NE_MSG(test,                                      \
> +				    get_user(val_##size, (size __user *)kmem), \
> +				    0, "illegal get_user (" #size ") passed"); \
> +		KUNIT_EXPECT_EQ_MSG(                                           \
> +			test, val_##size, 0,                                   \
> +			"zeroing failure for illegal get_user (" #size ")");   \
> +		/* put_user() */                                               \
> +		*kmem_u64 = 0xF09FA4AFF09FA4AF;                                \
> +		KUNIT_EXPECT_NE_MSG(test,                                      \
> +				    put_user(val_##size, (size __user *)kmem), \
> +				    0, "illegal put_user (" #size ") passed"); \
> +		KUNIT_EXPECT_EQ_MSG(test, *kmem_u64, 0xF09FA4AFF09FA4AF,       \
> +				    "illegal put_user (" #size                 \
> +				    ") wrote to kernel memory!");              \
>   	} while (0)
>   
> -	test_illegal(u8,  0x5a);
> +	test_illegal(u8, 0x5a);
>   	test_illegal(u16, 0x5a5b);
>   	test_illegal(u32, 0x5a5b5c5d);
>   #ifdef TEST_U64
> @@ -286,13 +303,136 @@ static void usercopy_test_invalid(struct kunit *test)
>   #undef test_illegal
>   }
>   
> +/* Test fault handling when copying from/to user mode */
> +static void usercopy_test_fault_handling(struct kunit *test)
> +{
> +	size_t start, len;
> +	struct usercopy_test_priv *priv = test->priv;
> +	const size_t size = 256;
> +	char __user *umem_gp = priv->umem + 2 * PAGE_SIZE;
> +	char __user *umem = umem_gp - size;
> +	char *kmem0 = priv->kmem;
> +	char *kmem1 = priv->kmem + size;
> +	const char fill_char = 0xff;
> +	const char override_char = 0xcc; /* cannot be 0 */
> +
> +	KUNIT_ASSERT_LT_MSG(test, size * 2, PAGE_SIZE,
> +			    "size * 2 is larger than PAGE_SIZE");
> +
> +	/* Copy to the guard page should fail with no byte copied */
> +	for (len = 1; len < size; len++) {
> +		KUNIT_ASSERT_EQ_MSG(
> +			test, copy_to_user(umem_gp, kmem1, len), len,
> +			"copy_to_user copied more than 1 byte to guard page");
> +	}
> +
> +	for (start = size - 1; start != 0; start--) {
> +		for (len = size - start + 1; len <= size; len++) {
> +			memset(kmem1, fill_char, size);
> +			KUNIT_EXPECT_EQ_MSG(test,
> +					    copy_to_user(umem, kmem1, size), 0,
> +					    "legitimate copy_to_user failed");
> +			memset(kmem1 + start, override_char, len);
> +
> +			/*
> +			 * This copy_to_user should partially fail with retval containing the
> +			 * number of bytes not copied
> +			 */
> +			unsigned long retval =
> +				copy_to_user(umem + start, kmem1 + start, len);
> +
> +			KUNIT_EXPECT_NE_MSG(
> +				test, retval, 0,
> +				"copy_to_user should not copy all the bytes (start=%zu, len=%zu)",
> +				start, len);
> +			KUNIT_EXPECT_LE_MSG(
> +				test, retval, len - 1,
> +				"copy_to_user should at least copy 1 byte (start=%zu, len=%zu)",
> +				start, len);
> +
> +			/* copy the umem page to kernel to check */
> +			KUNIT_EXPECT_EQ_MSG(test,
> +					    copy_from_user(kmem0, umem, size),
> +					    0,
> +					    "legitimate copy_to_user failed");
> +
> +			char *tmp =
> +				memchr_inv(kmem0 + start, override_char, len);
> +
> +			KUNIT_EXPECT_TRUE_MSG(
> +				test, tmp,
> +				"memchr_inv returned NULL (start=%zu, len=%zu)",
> +				start, len);
> +
> +			unsigned long expected = len - (tmp - (kmem0 + start));
> +
> +			KUNIT_EXPECT_EQ_MSG(
> +				test, retval, expected,
> +				"copy_to_user(=%zu) != memchr_inv(=%zu) mismatch (start=%zu, len=%zu)",
> +				retval, expected, start, len);
> +		}
> +	}
> +
> +	for (len = 1; len < size; len++) {
> +		/* Copy from the guard page should fail immediately */
> +		KUNIT_ASSERT_EQ_MSG(
> +			test, copy_from_user(kmem0, umem_gp, len), len,
> +			"copy_from_user copied more than 1 byte to guard page");
> +	}
> +
> +	for (start = size - 1; start != 0; start--) {
> +		for (len = size - start + 1; len <= size; len++) {
> +			memset(kmem0, override_char, size);
> +			KUNIT_EXPECT_EQ_MSG(test,
> +					    copy_to_user(umem, kmem0, size), 0,
> +					    "legitimate copy_to_user failed");
> +			memset(kmem0 + start, fill_char, len);
> +
> +			/*
> +			 * This copy_from_user should partially fail with retval containing
> +			 * the number of bytes not copied
> +			 */
> +			unsigned long retval = copy_from_user(
> +				kmem0 + start, umem + start, len);
> +
> +			KUNIT_EXPECT_NE_MSG(
> +				test, retval, 0,
> +				"copy_from_user should not copy all the bytes (start=%zu, len=%zu)",
> +				start, len);
> +			KUNIT_EXPECT_LE_MSG(
> +				test, retval, len - 1,
> +				"copy_from_user should at least copy 1 byte (start=%zu, len=%zu)",
> +				start, len);
> +
> +			char *tmp =
> +				memchr_inv(kmem0 + start, override_char, len);
> +
> +			KUNIT_EXPECT_TRUE_MSG(
> +				test, tmp,
> +				"memchr_inv returned NULL (start=%zu, len=%zu)",
> +				start, len);
> +
> +			unsigned long expected = len - (tmp - (kmem0 + start));
> +
> +			KUNIT_EXPECT_EQ_MSG(
> +				test, retval, expected,
> +				"copy_from_user(=%zu) != memchr_inv(=%zu) mismatch (start=%zu, len=%zu)",
> +				retval, expected, start, len);
> +		}
> +	}
> +}
> +
>   static int usercopy_test_init(struct kunit *test)
>   {
>   	struct usercopy_test_priv *priv;
>   	unsigned long user_addr;
> +	int ret;
> +	size_t total_size;
>   
>   	if (!IS_ENABLED(CONFIG_MMU)) {
> -		kunit_skip(test, "Userspace allocation testing not available on non-MMU systems");
> +		kunit_skip(
> +			test,
> +			"Userspace allocation testing not available on non-MMU systems");
>   		return 0;
>   	}
>   
> @@ -304,13 +444,19 @@ static int usercopy_test_init(struct kunit *test)
>   	priv->kmem = kunit_kmalloc(test, priv->size, GFP_KERNEL);
>   	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->kmem);
>   
> -	user_addr = kunit_vm_mmap(test, NULL, 0, priv->size,
> -			    PROT_READ | PROT_WRITE | PROT_EXEC,
> -			    MAP_ANONYMOUS | MAP_PRIVATE, 0);
> +	/* add an extra guard page */
> +	total_size = priv->size + PAGE_SIZE;
> +	user_addr = kunit_vm_mmap(test, NULL, 0, total_size,
> +				  PROT_READ | PROT_WRITE,
> +				  MAP_ANONYMOUS | MAP_PRIVATE, 0);
>   	KUNIT_ASSERT_NE_MSG(test, user_addr, 0,
> -		"Could not create userspace mm");
> +			    "Could not create userspace mm");
>   	KUNIT_ASSERT_LT_MSG(test, user_addr, (unsigned long)TASK_SIZE,
> -		"Failed to allocate user memory");
> +			    "Failed to allocate user memory");
> +
> +	ret = vm_munmap(user_addr + priv->size, PAGE_SIZE);
> +	KUNIT_ASSERT_EQ_MSG(test, ret, 0, "Failed to unmap guard page");
> +
>   	priv->umem = (char __user *)user_addr;
>   
>   	return 0;
> @@ -321,6 +467,7 @@ static struct kunit_case usercopy_test_cases[] = {
>   	KUNIT_CASE(usercopy_test_invalid),
>   	KUNIT_CASE(usercopy_test_check_nonzero_user),
>   	KUNIT_CASE(usercopy_test_copy_struct_from_user),
> +	KUNIT_CASE(usercopy_test_fault_handling),
>   	{}
>   };
>   



From ahmed.tiba at arm.com  Fri Dec 19 09:21:54 2025
From: ahmed.tiba at arm.com (Ahmed Tiba)
Date: Fri, 19 Dec 2025 17:21:54 +0000
Subject: [PATCH 11/12] ras: add DeviceTree estatus provider driver
In-Reply-To: <aUVMWMMmiG8_I2I2@willie-the-truck>
Message-ID: <20251219172212.2844694-1-ahmed.tiba@arm.com>

On Fri, 19 Dec 2025 13:00:08 +0000, Will Deacon wrote:
>On Fri, Dec 19, 2025 at 09:02:35AM +0000, Ahmed Tiba wrote:
>> On Thu, 18 Dec 2025 03:19:17PM +0000, Will Deacon wrote:
>> > On Thu, Dec 18, 2025 at 01:42:47PM +0000, Ahmed Tiba wrote:
>> >> On Thu, 18 Dec 2025 12:13:25PM +0000, Will Deacon wrote:
>> >> >> Introduce a platform driver that maps the CPER status block described
>> >> >> in DeviceTree, feeds it into the estatus core and handles either IRQ- or
>> >> >> poll-driven notifications. Arm64 gains a FIX_ESTATUS_IRQ slot so the
>> >> >> driver can safely map the shared buffer while copying records.
>> >> >>
>> >> >> Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>
>> >> >> ---
>> >> >>  MAINTAINERS                     |   1 +
>> >> >>  arch/arm64/include/asm/fixmap.h |   5 +
>> >> >>  drivers/ras/Kconfig             |  14 ++
>> >> >>  drivers/ras/Makefile            |   1 +
>> >> >>  drivers/ras/estatus-dt.c        | 318 ++++++++++++++++++++++++++++++++
>> >> >>  include/linux/estatus.h         |   3 +-
>> >> >>  6 files changed, 341 insertions(+), 1 deletion(-)
>> >> >>  create mode 100644 drivers/ras/estatus-dt.c
>> >> >>
>> >> >> diff --git a/MAINTAINERS b/MAINTAINERS
>> >> >> index 6b2ef2ddc0c7..5567d5e82053 100644
>> >> >> --- a/MAINTAINERS
>> >> >> +++ b/MAINTAINERS
>> >> >> @@ -21761,6 +21761,7 @@ RAS ERROR STATUS
>> >> >>  M:   Ahmed Tiba <ahmed.tiba at arm.com>
>> >> >>  S:   Maintained
>> >> >>  F:   Documentation/devicetree/bindings/ras/arm,ras-ffh.yaml
>> >> >> +F:   drivers/ras/estatus-dt.c
>> >> >>  F:   drivers/firmware/efi/estatus.c
>> >> >>  F:   include/linux/estatus.h
>> >> >>
>> >> >> diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h
>> >> >> index 65555284446e..85ffba87bab9 100644
>> >> >> --- a/arch/arm64/include/asm/fixmap.h
>> >> >> +++ b/arch/arm64/include/asm/fixmap.h
>> >> >> @@ -64,6 +64,11 @@ enum fixed_addresses {
>> >> >>  #endif
>> >> >>  #endif /* CONFIG_ACPI_APEI_GHES */
>> >> >>
>> >> >> +#ifdef CONFIG_RAS_ESTATUS_DT
>> >> >> +     /* Used for ESTATUS mapping from assorted contexts */
>> >> >> +     FIX_ESTATUS_IRQ,
>> >> >> +#endif /* CONFIG_RAS_ESTATUS_DT */
>> >> >
>> >> > Why do we need this in addition to the four existing GHES slots? The DT
>> >> > code doesn't use it and I was assuming that the ACPI code would continue
>> >> > to use the existing irq; is that not the case?
>> >>
>> >>
>> >> We still need a dedicated slot when only the DT provider is built.
>> >> All four GHES slots are defined as part of the ACPI implementation,
>> >> so they are not present in a DT-only configuration.
>> >>
>> >> The estatus core always requests a fixmap index from each provider
>> >> before copying a CPER record. As a result, the DT driver must supply
>> >> its own slot to return a valid enum value to satisfy the common code.
>> >
>> > Sorry, but I still don't follow this. The DT code doesn't use the fixmap,
>> > does it? It looks like it maps the buffer ahead of time using
>> > devm_ioremap_resource() and then the accessors don't use the fixmap
>> > index at all, hence the horrible '(void)fixmap_idx;' cast which presumably
>> > stops the compiler from complaining about an unused variable.
>> 
>> Correct. The current DT driver keeps the CPER buffer permanently mapped with
>> devm_ioremap_resource() and that (void)fixmap_idx; line is just silencing
>> the warning. I?ll fix that by dropping the permanent mapping and copying the
>> status block via the fixmap entry, so the DT implementation mirrors GHES. That
>> gets rid of the cast and makes FIX_ESTATUS_IRQ do real work.

> Why can't you just drop FIX_ESTATUS_IRQ entirely? Your original
> justification was:
>
>> We still need a dedicated slot when only the DT provider is built.
>
> but as above, the DT driver doesn't actually need it.

The DT provider is intended to mirror the GHES path, so both need to supply a
fixmap slot to satisfy the estatus core interface.

I could drop FIX_ESTATUS_IRQ entirely, but that would require relaxing the
estatus core so a provider can explicitly indicate that it does not use a
fixmap and instead relies on a permanent mapping. If we want to stay aligned
with the ACPI/GHES model, keeping the fixmap-based approach seems preferable.

Thanks,
Ahmed


From krzk at kernel.org  Fri Dec 19 09:58:56 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 19 Dec 2025 18:58:56 +0100
Subject: [PATCH v3 1/2] media: dt-bindings: Add CSI Pixel Formatter DT
 bindings
In-Reply-To: <20251219-csi_formatter-v3-1-8680d6d87091@nxp.com>
References: <20251219-csi_formatter-v3-0-8680d6d87091@nxp.com>
 <20251219-csi_formatter-v3-1-8680d6d87091@nxp.com>
Message-ID: <72c8f3bd-03c2-46df-a28b-65b7fbfd2095@kernel.org>

On 19/12/2025 02:50, Guoniu Zhou wrote:
> From: Guoniu Zhou <guoniu.zhou at nxp.com>
> 
> The i.MX9 CSI pixel formatting module uses packet info, pixel and
> non-pixel data from the CSI-2 host controller and reformat them to
> match Pixel Link(PL) definition.
> 
> Signed-off-by: Guoniu Zhou <guoniu.zhou at nxp.com>


Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof


From dave.hansen at intel.com  Fri Dec 19 10:02:43 2025
From: dave.hansen at intel.com (Dave Hansen)
Date: Fri, 19 Dec 2025 10:02:43 -0800
Subject: [PATCH 1/4] arch/*: increase lowmem size to avoid highmem use
In-Reply-To: <20251219161559.556737-2-arnd@kernel.org>
References: <20251219161559.556737-1-arnd@kernel.org>
 <20251219161559.556737-2-arnd@kernel.org>
Message-ID: <a3f22579-13ee-4479-a5fd-81c29145c3f3@intel.com>

On 12/19/25 08:15, Arnd Bergmann wrote:
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -1416,7 +1416,9 @@ config HIGHMEM4G
>  
>  choice
>  	prompt "Memory split" if EXPERT
> -	default VMSPLIT_3G
> +	default VMSPLIT_2G_OPT if HIGHMEM && !X86_PAE
> +	default VMSPLIT_2G if X86_PAE
> +	default VMSPLIT_3G_OPT
>  	depends on X86_32

For simplicity, I think this can just be:

-	default VMSPLIT_3G
+	default VMSPLIT_2G

I doubt the 2G vs. 2G_OPT matters in very many cases. If it does, folks
can just set it in their config manually.

But, in the end, I don't this this matters all that much. If you think
having x86 be consistent with ARM, for example, is more important and
ARM really wants this complexity, I can live with it.

Either way:

Acked-by: Dave Hansen <dave.hansen at linux.intel.com>


From ben.horgan at arm.com  Fri Dec 19 10:11:02 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:02 +0000
Subject: [PATCH v2 00/45] arm_mpam: Add KVM/arm64 and resctrl glue code
Message-ID: <20251219181147.3404071-1-ben.horgan@arm.com>

Hi all,

As James is otherwise engaged this version of the MPAM missing pieces comes
from me. I hope this does justice to all his hardwork. The changes that
I've brought to this version are the handling of systems with SME, some rework
of the KVM parts, a few small bug fixes and some tidying.

This may be the first time you are seeing this series as James spared some
of you as the rfc was posted during merge window.

One major departure from the previous snapshot branches referenced in the
base driver series is that the same MPAM setting are used for kernel-space
and user-space. That is, MPAM1_EL1 is set to the same value as MPAM0_EL1
rather than keeping the default value. The advantages of this are that it
is closer to the x86 model where the closid is globally applicable, all
partids are usable from user-space and user-space can't bypass MPAM
controls by doing the work in the kernel. However, this causes some
priority inversion where a high priority task waits to take a mutex held by
another whose resources are restricted by MPAM. It also adds some extra
isb(). I would be interested in opinions/data on the policy for MPAM in
kernel space, i.e how MPAM1_EL1 is set.

Change list in patches.

>From James' cover letter:

This is the missing piece to make MPAM usable resctrl in user-space. This has
shed its debugfs code and the read/write 'event configuration' for the monitors
to make the series smaller.

This adds the arch code and KVM support first. I anticipate the whole thing
going via arm64, but if goes via tip instead, the an immutable branch with those
patches should be easy to do.

Generally the resctrl glue code works by picking what MPAM features it can expose
from the MPAM drive, then configuring the structs that back the resctrl helpers.
If your platform is sufficiently Xeon shaped, you should be able to get L2/L3 CPOR
bitmaps exposed via resctrl. CSU counters work if they are on/after the L3. MBWU
counters are considerably more hairy, and depend on hueristics around the topology,
and a bunch of stuff trying to emulate ABMC.
If it didn't pick what you wanted it to, please share the debug messages produced
when enabling dynamic debug and booting with:
| dyndbg="file mpam_resctrl.c +pl"

I've not found a platform that can test all the behaviours around the monitors,
so this is where I'd expect the most bugs.

The MPAM spec that describes all the system and MMIO registers can be found here:
https://developer.arm.com/documentation/ddi0598/db/?lang=en
(Ignored the 'RETIRED' warning - that is just arm moving the documentation around.
 This document has the best overview)


Based on v6.19-rc1
This series can be retrieved from:
https://gitlab.arm.com/linux-arm/linux-bh.git mpam_resctrl_glue_v2

Ben Horgan (7):
  arm_mpam: Stop using uninitialized variables in __ris_msmon_read()
  arm_mpam: Use non-atomic bitops when modifying feature bitmap
  arm64/sysreg: Add MPAMSM_EL1 register
  KVM: arm64: Preserve host MPAM configuration when changing traps
  KVM: arm64: Make MPAMSM_EL1 accesses UNDEF
  arm64: mpam: Initialise and context switch the MPAMSM_EL1 register
  KVM: arm64: Use kernel-space partid configuration for hypercalls

Dave Martin (2):
  arm_mpam: resctrl: Convert to/from MPAMs fixed-point formats
  arm_mpam: resctrl: Add kunit test for control format conversions

James Morse (31):
  arm64: mpam: Context switch the MPAM registers
  arm64: mpam: Re-initialise MPAM regs when CPU comes online
  arm64: mpam: Advertise the CPUs MPAM limits to the driver
  arm64: mpam: Add cpu_pm notifier to restore MPAM sysregs
  arm64: mpam: Add helpers to change a task or cpu's MPAM PARTID/PMG
    values
  KVM: arm64: Force guest EL1 to use user-space's partid configuration
  arm_mpam: resctrl: Add boilerplate cpuhp and domain allocation
  arm_mpam: resctrl: Sort the order of the domain lists
  arm_mpam: resctrl: Pick the caches we will use as resctrl resources
  arm_mpam: resctrl: Implement resctrl_arch_reset_all_ctrls()
  arm_mpam: resctrl: Add resctrl_arch_get_config()
  arm_mpam: resctrl: Implement helpers to update configuration
  arm_mpam: resctrl: Add plumbing against arm64 task and cpu hooks
  arm_mpam: resctrl: Add CDP emulation
  arm_mpam: resctrl: Add rmid index helpers
  arm_mpam: resctrl: Add support for 'MB' resource
  arm_mpam: resctrl: Add support for csu counters
  arm_mpam: resctrl: Pick classes for use as mbm counters
  arm_mpam: resctrl: Pre-allocate free running monitors
  arm_mpam: resctrl: Pre-allocate assignable monitors
  arm_mpam: resctrl: Add kunit test for ABMC/CDP interactions
  arm_mpam: resctrl: Add resctrl_arch_config_cntr() for ABMC use
  arm_mpam: resctrl: Allow resctrl to allocate monitors
  arm_mpam: resctrl: Add resctrl_arch_rmid_read() and
    resctrl_arch_reset_rmid()
  arm_mpam: resctrl: Add resctrl_arch_cntr_read() &
    resctrl_arch_reset_cntr()
  arm_mpam: resctrl: Update the rmid reallocation limit
  arm_mpam: resctrl: Add empty definitions for assorted resctrl
    functions
  arm64: mpam: Select ARCH_HAS_CPU_RESCTRL
  arm_mpam: resctrl: Call resctrl_init() on platforms that can support
    resctrl
  arm_mpam: Generate a configuration for min controls
  arm_mpam: Quirk CMN-650's CSU NRDY behaviour

Jiapeng Chong (1):
  arm_mpam: Remove duplicate linux/srcu.h header

Shanker Donthineni (4):
  arm_mpam: Add quirk framework
  arm_mpam: Add workaround for T241-MPAM-1
  arm_mpam: Add workaround for T241-MPAM-4
  arm_mpam: Add workaround for T241-MPAM-6

 Documentation/arch/arm64/silicon-errata.rst |    9 +
 arch/arm64/Kconfig                          |    6 +-
 arch/arm64/include/asm/el2_setup.h          |    3 +-
 arch/arm64/include/asm/mpam.h               |  104 +
 arch/arm64/include/asm/resctrl.h            |    2 +
 arch/arm64/include/asm/thread_info.h        |    3 +
 arch/arm64/kernel/Makefile                  |    1 +
 arch/arm64/kernel/cpufeature.c              |   21 +-
 arch/arm64/kernel/mpam.c                    |   58 +
 arch/arm64/kernel/process.c                 |    7 +
 arch/arm64/kvm/hyp/include/hyp/switch.h     |   12 +-
 arch/arm64/kvm/hyp/nvhe/hyp-main.c          |    5 +
 arch/arm64/kvm/hyp/vhe/sysreg-sr.c          |   11 +
 arch/arm64/kvm/sys_regs.c                   |    2 +
 arch/arm64/tools/sysreg                     |    8 +
 drivers/resctrl/Kconfig                     |    9 +-
 drivers/resctrl/Makefile                    |    1 +
 drivers/resctrl/mpam_devices.c              |  314 ++-
 drivers/resctrl/mpam_internal.h             |  128 +-
 drivers/resctrl/mpam_resctrl.c              | 1941 +++++++++++++++++++
 drivers/resctrl/test_mpam_devices.c         |   66 +
 drivers/resctrl/test_mpam_resctrl.c         |  374 ++++
 include/linux/arm_mpam.h                    |   32 +
 23 files changed, 3080 insertions(+), 37 deletions(-)
 create mode 100644 arch/arm64/include/asm/mpam.h
 create mode 100644 arch/arm64/include/asm/resctrl.h
 create mode 100644 arch/arm64/kernel/mpam.c
 create mode 100644 drivers/resctrl/mpam_resctrl.c
 create mode 100644 drivers/resctrl/test_mpam_resctrl.c

-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:03 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:03 +0000
Subject: [PATCH v2 01/45] arm_mpam: Stop using uninitialized variables in __ris_msmon_read()
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-2-ben.horgan@arm.com>

Dan has reported two uses of uninitialized variables in __ris_msmon_read().
If an unknown monitor type is encountered then the local variable, now, is
used uninitialized. Fix this by returning early on error. If a non-mbwu
monitor is being read then the local variable, overflow, is not initialized
but still read. Initialize it to false as overflow is not relevant for csu
monitors.

Reported-by: kernel test robot <lkp at intel.com>
Reported-by: Dan Carpenter <dan.carpenter at linaro.org>
Closes: https://lore.kernel.org/r/202512091519.RBwiJcSq-lkp at intel.com/
Closes: https://lore.kernel.org/r/202512100547.N7QPYgfb-lkp at intel.com/
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
 drivers/resctrl/mpam_devices.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index 0b5b158e1aaf..b495d5291868 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -1072,7 +1072,7 @@ static void __ris_msmon_read(void *arg)
 	u64 now;
 	bool nrdy = false;
 	bool config_mismatch;
-	bool overflow;
+	bool overflow = false;
 	struct mon_read *m = arg;
 	struct mon_cfg *ctx = m->ctx;
 	bool reset_on_next_read = false;
@@ -1176,10 +1176,11 @@ static void __ris_msmon_read(void *arg)
 	}
 	mpam_mon_sel_unlock(msc);
 
-	if (nrdy) {
+	if (nrdy)
 		m->err = -EBUSY;
+
+	if (m->err)
 		return;
-	}
 
 	*m->val += now;
 }
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:04 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:04 +0000
Subject: [PATCH v2 02/45] arm_mpam: Remove duplicate linux/srcu.h header
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-3-ben.horgan@arm.com>

From: Jiapeng Chong <jiapeng.chong at linux.alibaba.com>

./drivers/resctrl/mpam_internal.h: linux/srcu.h is included more than once.

Reported-by: Abaci Robot <abaci at linux.alibaba.com>
Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=27328
Signed-off-by: Jiapeng Chong <jiapeng.chong at linux.alibaba.com>
Acked-by: James Morse <james.morse at arm.com>
[BH: Keep alphabetical order]
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
 drivers/resctrl/mpam_internal.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index e79c3c47259c..17cdc3080d58 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -12,7 +12,6 @@
 #include <linux/jump_label.h>
 #include <linux/llist.h>
 #include <linux/mutex.h>
-#include <linux/srcu.h>
 #include <linux/spinlock.h>
 #include <linux/srcu.h>
 #include <linux/types.h>
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:05 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:05 +0000
Subject: [PATCH v2 03/45] arm_mpam: Use non-atomic bitops when modifying feature bitmap
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-4-ben.horgan@arm.com>

In the test__props_mismatch() kunit test we rely on the struct mpam_props
being packed to ensure memcmp doesn't consider packing. Making it packed
reduces the alignment of the features bitmap and so breaks a requirement
for the use of atomics. As we don't rely on the set/clear of these bits
being atomic, just make them non-atomic.

Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
 drivers/resctrl/mpam_internal.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index 17cdc3080d58..aaaf31ca9210 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -200,8 +200,8 @@ struct mpam_props {
 } PACKED_FOR_KUNIT;
 
 #define mpam_has_feature(_feat, x)	test_bit(_feat, (x)->features)
-#define mpam_set_feature(_feat, x)	set_bit(_feat, (x)->features)
-#define mpam_clear_feature(_feat, x)	clear_bit(_feat, (x)->features)
+#define mpam_set_feature(_feat, x)	__set_bit(_feat, (x)->features)
+#define mpam_clear_feature(_feat, x)	__clear_bit(_feat, (x)->features)
 
 /* The values for MSMON_CFG_MBWU_FLT.RWBW */
 enum mon_filter_options {
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:06 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:06 +0000
Subject: [PATCH v2 04/45] arm64/sysreg: Add MPAMSM_EL1 register
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-5-ben.horgan@arm.com>

The MPAMSM_EL1 register determines the MPAM configuration for an SMCU. Add
the register definition.

Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
 arch/arm64/tools/sysreg | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
index 8921b51866d6..afbb55c9b038 100644
--- a/arch/arm64/tools/sysreg
+++ b/arch/arm64/tools/sysreg
@@ -5052,6 +5052,14 @@ Field	31:16	PARTID_D
 Field	15:0	PARTID_I
 EndSysreg
 
+Sysreg	MPAMSM_EL1	3	0	10	5	3
+Res0	63:48
+Field	47:40	PMG_D
+Res0	39:32
+Field	31:16	PARTID_D
+Res0	15:0
+EndSysreg
+
 Sysreg	ISR_EL1	3	0	12	1	0
 Res0	63:11
 Field	10	IS
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:07 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:07 +0000
Subject: [PATCH v2 05/45] KVM: arm64: Preserve host MPAM configuration when changing traps
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-6-ben.horgan@arm.com>

When kvm enables or disables MPAM traps to EL2 it clears all other bits in
MPAM2_EL2.  Notably, it clears the partition ids (PARTIDs) and performance
monitoring groups (PMGs). Avoid changing these bits in anticipation of
adding support for MPAM in the kernel. Otherwise, on a VHE system with the
host running at EL2 where MPAM2_EL2 and MPAM1_EL1 access the same register,
any attempt to use MPAM to monitor or partition resources for kernel space
would be foiled by running a KVM guest. Additionally, MPAM2_EL2.EnMPAMSM is
always set to 0 which causes MPAMSM_EL1 to always trap. Keep EnMPAMSM set
to 1 when not in a guest so that the kernel can use MPAMSM_EL1.

Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
 arch/arm64/kvm/hyp/include/hyp/switch.h | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index c5d5e5b86eaf..63195275a8b8 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -269,7 +269,8 @@ static inline void __deactivate_traps_hfgxtr(struct kvm_vcpu *vcpu)
 
 static inline void  __activate_traps_mpam(struct kvm_vcpu *vcpu)
 {
-	u64 r = MPAM2_EL2_TRAPMPAM0EL1 | MPAM2_EL2_TRAPMPAM1EL1;
+	u64 clr = MPAM2_EL2_EnMPAMSM;
+	u64 set = MPAM2_EL2_TRAPMPAM0EL1 | MPAM2_EL2_TRAPMPAM1EL1;
 
 	if (!system_supports_mpam())
 		return;
@@ -279,18 +280,21 @@ static inline void  __activate_traps_mpam(struct kvm_vcpu *vcpu)
 		write_sysreg_s(MPAMHCR_EL2_TRAP_MPAMIDR_EL1, SYS_MPAMHCR_EL2);
 	} else {
 		/* From v1.1 TIDR can trap MPAMIDR, set it unconditionally */
-		r |= MPAM2_EL2_TIDR;
+		set |= MPAM2_EL2_TIDR;
 	}
 
-	write_sysreg_s(r, SYS_MPAM2_EL2);
+	sysreg_clear_set_s(SYS_MPAM2_EL2, clr, set);
 }
 
 static inline void __deactivate_traps_mpam(void)
 {
+	u64 clr = MPAM2_EL2_TRAPMPAM0EL1 | MPAM2_EL2_TRAPMPAM1EL1 | MPAM2_EL2_TIDR;
+	u64 set = MPAM2_EL2_EnMPAMSM;
+
 	if (!system_supports_mpam())
 		return;
 
-	write_sysreg_s(0, SYS_MPAM2_EL2);
+	sysreg_clear_set_s(SYS_MPAM2_EL2, clr, set);
 
 	if (system_supports_mpam_hcr())
 		write_sysreg_s(MPAMHCR_HOST_FLAGS, SYS_MPAMHCR_EL2);
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:08 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:08 +0000
Subject: [PATCH v2 06/45] KVM: arm64: Make MPAMSM_EL1 accesses UNDEF
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-7-ben.horgan@arm.com>

The MPAMSM_EL1 controls the MPAM labeling for an SMCU, Streaming Mode
Compute Unit. As there is on MPAM support in kvm, make sure MPAMSM_EL1
accesses trigger an UNDEF.

The range of valid configurations for the PARTID and PMG in MPAMSM_EL1 is
not currently specified in Arm Architectural Reference Manual but the
architect has confirmed that it is intended to be the same as that for the
cpu configuration in the MPAMy_ELx registers.

Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
 arch/arm64/kvm/sys_regs.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index c8fd7c6a12a1..72654ab984ee 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -3373,6 +3373,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 
 	{ SYS_DESC(SYS_MPAM1_EL1), undef_access },
 	{ SYS_DESC(SYS_MPAM0_EL1), undef_access },
+	{ SYS_DESC(SYS_MPAMSM_EL1), undef_access },
+
 	{ SYS_DESC(SYS_VBAR_EL1), access_rw, reset_val, VBAR_EL1, 0 },
 	{ SYS_DESC(SYS_DISR_EL1), NULL, reset_val, DISR_EL1, 0 },
 
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:09 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:09 +0000
Subject: [PATCH v2 07/45] arm64: mpam: Context switch the MPAM registers
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-8-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

MPAM allows traffic in the SoC to be labeled by the OS, these labels are
used to apply policy in caches and bandwidth regulators, and to monitor
traffic in the SoC. The label is made up of a PARTID and PMG value. The x86
equivalent calls these CLOSID and RMID, but they don't map precisely.

MPAM has two CPU system registers that is used to hold the PARTID and PMG
values that traffic generated at each exception level will use. These can
be set per-task by the resctrl file system. (resctrl is the defacto
interface for controlling this stuff).

Add a helper to switch this.

struct task_struct's separate CLOSID and RMID fields are insufficient to
implement resctrl using MPAM, as resctrl can change the PARTID (CLOSID) and
PMG (sort of like the RMID) separately. On x86, the rmid is an independent
number, so a race that writes a mismatched closid and rmid into hardware is
benign. On arm64, the pmg bits extend the partid.
(i.e. partid-5 has a pmg-0 that is not the same as partid-6's pmg-0).  In
this case, mismatching the values will 'dirty' a pmg value that resctrl
believes is clean, and is not tracking with its 'limbo' code.

To avoid this, the partid and pmg are always read and written as a pair.
Instead of making struct task_struct's closid and rmid fields an
endian-unsafe union, add the value to struct thread_info and always use
READ_ONCE()/WRITE_ONCE() when accessing this field.

Resctrl allows a per-cpu 'default' value to be set, this overrides the
values when scheduling a task in the default control-group, which has
PARTID 0. The way 'code data prioritisation' gets emulated means the
register value for the default group needs to be a variable.

The current system register value is kept in a per-cpu variable to avoid
writing to the system register if the value isn't going to change.  Writes
to this register may reset the hardware state for regulating bandwidth.

Finally, there is no reason to context switch these registers unless there
is a driver changing the values in struct task_struct. Hide the whole thing
behind a static key. This also allows the driver to disable MPAM in
response to errors reported by hardware. Move the existing static key to
belong to the arch code, as in the future the MPAM driver may become a
loadable module.

All this should depend on whether there is an MPAM driver, hide it behind
CONFIG_ARM64_MPAM.

CC: Amit Singh Tomar <amitsinght at marvell.com>
Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
CONFIG_MPAM -> CONFIG_ARM64_MPAM in commit message
Remove extra DECLARE_STATIC_KEY_FALSE
Function name in comment, __mpam_sched_in() -> mpam_thread_switch()
Remove unused headers
Expand comment (Jonathan)
---
 arch/arm64/Kconfig                   |  2 +
 arch/arm64/include/asm/mpam.h        | 73 ++++++++++++++++++++++++++++
 arch/arm64/include/asm/thread_info.h |  3 ++
 arch/arm64/kernel/Makefile           |  1 +
 arch/arm64/kernel/mpam.c             | 13 +++++
 arch/arm64/kernel/process.c          |  7 +++
 drivers/resctrl/mpam_devices.c       |  2 -
 drivers/resctrl/mpam_internal.h      |  4 +-
 8 files changed, 101 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm64/include/asm/mpam.h
 create mode 100644 arch/arm64/kernel/mpam.c

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 93173f0a09c7..cdcc5b76a110 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -2049,6 +2049,8 @@ config ARM64_MPAM
 
 	  MPAM is exposed to user-space via the resctrl pseudo filesystem.
 
+	  This option enables the extra context switch code.
+
 endmenu # "ARMv8.4 architectural features"
 
 menu "ARMv8.5 architectural features"
diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/mpam.h
new file mode 100644
index 000000000000..2ab3dca6977c
--- /dev/null
+++ b/arch/arm64/include/asm/mpam.h
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2025 Arm Ltd. */
+
+#ifndef __ASM__MPAM_H
+#define __ASM__MPAM_H
+
+#include <linux/jump_label.h>
+#include <linux/percpu.h>
+#include <linux/sched.h>
+
+#include <asm/sysreg.h>
+
+DECLARE_STATIC_KEY_FALSE(mpam_enabled);
+DECLARE_PER_CPU(u64, arm64_mpam_default);
+DECLARE_PER_CPU(u64, arm64_mpam_current);
+
+/*
+ * The value of the MPAM0_EL1 sysreg when a task is in resctrl's default group.
+ * This is used by the context switch code to use the resctrl CPU property
+ * instead. The value is modified when CDP is enabled/disabled by mounting
+ * the resctrl filesystem.
+ */
+extern u64 arm64_mpam_global_default;
+
+/*
+ * The resctrl filesystem writes to the partid/pmg values for threads and CPUs,
+ * which may race with reads in mpam_thread_switch(). Ensure only one of the old
+ * or new values are used. Particular care should be taken with the pmg field as
+ * mpam_thread_switch() may read a partid and pmg that don't match, causing this
+ * value to be stored with cache allocations, despite being considered 'free' by
+ * resctrl.
+ *
+ * A value in struct thread_info is used instead of struct task_struct as the
+ * cpu's u64 register format is used. In struct task_struct there are two u32,
+ * rmid and closid for the x86 case, but as we can't use them here do something
+ * else. Creating a union would mean only accesses from the created u64 would be
+ * endian safe and so be less clear.
+ */
+static inline u64 mpam_get_regval(struct task_struct *tsk)
+{
+#ifdef CONFIG_ARM64_MPAM
+	return READ_ONCE(task_thread_info(tsk)->mpam_partid_pmg);
+#else
+	return 0;
+#endif
+}
+
+static inline void mpam_thread_switch(struct task_struct *tsk)
+{
+	u64 oldregval;
+	int cpu = smp_processor_id();
+	u64 regval = mpam_get_regval(tsk);
+
+	if (!IS_ENABLED(CONFIG_ARM64_MPAM) ||
+	    !static_branch_likely(&mpam_enabled))
+		return;
+
+	if (regval == READ_ONCE(arm64_mpam_global_default))
+		regval = READ_ONCE(per_cpu(arm64_mpam_default, cpu));
+
+	oldregval = READ_ONCE(per_cpu(arm64_mpam_current, cpu));
+	if (oldregval == regval)
+		return;
+
+	write_sysreg_s(regval, SYS_MPAM1_EL1);
+	isb();
+
+	/* Synchronising the EL0 write is left until the ERET to EL0 */
+	write_sysreg_s(regval, SYS_MPAM0_EL1);
+
+	WRITE_ONCE(per_cpu(arm64_mpam_current, cpu), regval);
+}
+#endif /* __ASM__MPAM_H */
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index a803b887b0b4..fc801a26ff9e 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -41,6 +41,9 @@ struct thread_info {
 #ifdef CONFIG_SHADOW_CALL_STACK
 	void			*scs_base;
 	void			*scs_sp;
+#endif
+#ifdef CONFIG_ARM64_MPAM
+	u64			mpam_partid_pmg;
 #endif
 	u32			cpu;
 };
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 76f32e424065..15979f366519 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_CRASH_DUMP)		+= crash_dump.o
 obj-$(CONFIG_VMCORE_INFO)		+= vmcore_info.o
 obj-$(CONFIG_ARM_SDE_INTERFACE)		+= sdei.o
 obj-$(CONFIG_ARM64_PTR_AUTH)		+= pointer_auth.o
+obj-$(CONFIG_ARM64_MPAM)		+= mpam.o
 obj-$(CONFIG_ARM64_MTE)			+= mte.o
 obj-y					+= vdso-wrap.o
 obj-$(CONFIG_COMPAT_VDSO)		+= vdso32-wrap.o
diff --git a/arch/arm64/kernel/mpam.c b/arch/arm64/kernel/mpam.c
new file mode 100644
index 000000000000..9866d2ca0faa
--- /dev/null
+++ b/arch/arm64/kernel/mpam.c
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2025 Arm Ltd. */
+
+#include <asm/mpam.h>
+
+#include <linux/jump_label.h>
+#include <linux/percpu.h>
+
+DEFINE_STATIC_KEY_FALSE(mpam_enabled);
+DEFINE_PER_CPU(u64, arm64_mpam_default);
+DEFINE_PER_CPU(u64, arm64_mpam_current);
+
+u64 arm64_mpam_global_default;
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index fba7ca102a8c..b510c0699313 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -51,6 +51,7 @@
 #include <asm/fpsimd.h>
 #include <asm/gcs.h>
 #include <asm/mmu_context.h>
+#include <asm/mpam.h>
 #include <asm/mte.h>
 #include <asm/processor.h>
 #include <asm/pointer_auth.h>
@@ -737,6 +738,12 @@ struct task_struct *__switch_to(struct task_struct *prev,
 	if (prev->thread.sctlr_user != next->thread.sctlr_user)
 		update_sctlr_el1(next->thread.sctlr_user);
 
+	/*
+	 * MPAM thread switch happens after the DSB to ensure prev's accesses
+	 * use prev's MPAM settings.
+	 */
+	mpam_thread_switch(next);
+
 	/* the actual thread switch */
 	last = cpu_switch_to(prev, next);
 
diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index b495d5291868..860181266b15 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -29,8 +29,6 @@
 
 #include "mpam_internal.h"
 
-DEFINE_STATIC_KEY_FALSE(mpam_enabled); /* This moves to arch code */
-
 /*
  * mpam_list_lock protects the SRCU lists when writing. Once the
  * mpam_enabled key is enabled these lists are read-only,
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index aaaf31ca9210..e6e7ba4342d6 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -16,12 +16,12 @@
 #include <linux/srcu.h>
 #include <linux/types.h>
 
+#include <asm/mpam.h>
+
 #define MPAM_MSC_MAX_NUM_RIS	16
 
 struct platform_device;
 
-DECLARE_STATIC_KEY_FALSE(mpam_enabled);
-
 #ifdef CONFIG_MPAM_KUNIT_TEST
 #define PACKED_FOR_KUNIT __packed
 #else
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:10 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:10 +0000
Subject: [PATCH v2 08/45] arm64: mpam: Re-initialise MPAM regs when CPU comes online
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-9-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

Now that the MPAM system registers are expected to have values that change,
reprogram them based on the previous value when a CPU is brought online.

Previously MPAM's 'default PARTID' of 0 was always used for MPAM in
kernel-space as this is the PARTID that hardware guarantees to
reset. Because there are a limited number of PARTID, this value is exposed
to user-space, meaning resctrl changes to the resctrl default group would
also affect kernel threads.  Instead, use the task's PARTID value for
kernel work on behalf of user-space too. The default of 0 is kept for both
user-space and kernel-space when MPAM is not enabled.

Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
Changes since rfc:
CONFIG_MPAM -> CONFIG_ARM64_MPAM
Check mpam_enabled
Comment about relying on ERET for synchronisation
Update commit message
---
 arch/arm64/kernel/cpufeature.c | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index c840a93b9ef9..0cdfb3728f43 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -86,6 +86,7 @@
 #include <asm/kvm_host.h>
 #include <asm/mmu.h>
 #include <asm/mmu_context.h>
+#include <asm/mpam.h>
 #include <asm/mte.h>
 #include <asm/hypervisor.h>
 #include <asm/processor.h>
@@ -2483,13 +2484,17 @@ test_has_mpam(const struct arm64_cpu_capabilities *entry, int scope)
 static void
 cpu_enable_mpam(const struct arm64_cpu_capabilities *entry)
 {
-	/*
-	 * Access by the kernel (at EL1) should use the reserved PARTID
-	 * which is configured unrestricted. This avoids priority-inversion
-	 * where latency sensitive tasks have to wait for a task that has
-	 * been throttled to release the lock.
-	 */
-	write_sysreg_s(0, SYS_MPAM1_EL1);
+	int cpu = smp_processor_id();
+	u64 regval = 0;
+
+	if (IS_ENABLED(CONFIG_ARM64_MPAM) && static_branch_likely(&mpam_enabled))
+		regval = READ_ONCE(per_cpu(arm64_mpam_current, cpu));
+
+	write_sysreg_s(regval, SYS_MPAM1_EL1);
+	isb();
+
+	/* Synchronising the EL0 write is left until the ERET to EL0 */
+	write_sysreg_s(regval, SYS_MPAM0_EL1);
 }
 
 static bool
-- 
2.43.0



From ahmed.tiba at arm.com  Fri Dec 19 10:11:54 2025
From: ahmed.tiba at arm.com (Ahmed Tiba)
Date: Fri, 19 Dec 2025 18:11:54 +0000
Subject: [PATCH 03/12] ras: add estatus vendor handling and processing
In-Reply-To: <euhams5heiuaawxq4e5ty7iijuvwt5gvdx3flsm4npligjeulq@lv3cwekyb2o2>
Message-ID: <20251219181226.2859763-1-ahmed.tiba@arm.com>


On Fri, Dec 19, 2025 at 04:30:40PM +0100, Mauro Carvalho Chehab wrote:
>On Fri, Dec 19, 2025 at 02:49:02PM +0000, Ahmed Tiba wrote:
>>
>> On Wed, Dec 18, 2025 at 05:04:53PM +0100, Mauro Carvalho Chehab wrote:
>>
>> >> Teach the estatus core how to walk CPER records and expose the vendor
>> >> record notification path. This adds the section iteration helpers,
>> >> the logging helpers that mirror the GHES behaviour, and the deferred
>> >> work used to hand vendor GUIDs to interested drivers. No users switch
>> >> over yet; this simply moves the common logic out of GHES so the next
>> >> patches can wire it up.
>> >>
>> >> Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>
>> >
>> >...
>> >
>> >> +static bool estatus_handle_arm_hw_error(estatus_generic_data *gdata, int sev, bool sync)
>> >
>> > Huh?
>> >
>> > This is a CPER record from GHES. Why are you moving CPER code out
>> > of ghes.c, placing in a file named estatus.c? Doesn't make much
>> > sense on my eyes...
>> >
>> > Same applies to to other GHES CPER record types.
>>
>> GHES still fills in the CPER record, but the parsing and logging logic is
>> shared with the new DeviceTree provider so I pulled those helpers into the
>> estatus core.
>
> I see, but this is not really estatus core. Instead, it is part of GHES CPER
> handling logic, which is defined at ACPI and UEFI specs. moving it to estatus
> sounds odd, at least on my eyes.
> 
> Perhaps I'm failing to see where at ACPI/UEFI specs how CPER would be
> integrated with an OpenFirmware approach to handle CPER without GHES.
> Care to point to the relevant specs, if any?

ACPI/APEI (via GHES) defines how CPER records are discovered and notified on ACPI systems,
but there is no ACPI or UEFI-defined equivalent for OpenFirmware/DeviceTree platforms.
UEFI standardises the CPER record format itself, not the transport or discovery mechanism.

On non-ACPI systems we still receive the same UEFI-defined CPER payload
from firmware, but Linux needs a different, platform-specific contract
to locate and acknowledge it. The DT binding is a Linux-side description
of that contract rather than something defined by ACPI/UEFI.

>> Both providers already call into the same notifier chain and
>> memory-pool helpers; this patch just moves the generic CPER walking routines
>> next to the rest of the common code so the DT path doesn?t have to grow its
>> own copy. If you?d prefer a different file layout or naming to make that
>> intent clearer, I?m happy to adjust.

> Moving the code from ghes.c to estatus.c or to elsewhere shouldn't make any
> difference, as the DT handling logic could simply be calling the functions
> from ghes.c (or estatus.c). I fail to see why they need to be moved.

The motivation is to provide a shared implementation for non-ACPI providers,
so that the DT path does not depend on ACPI/APEI.

While the helpers currently live in ghes.c, they are CPER-specific and do not rely on ACPI tables,
APEI infrastructure, or GHES notification semantics. Keeping them there effectively makes GHES
the only place those helpers can live, even though the logic itself is provider-agnostic.

By moving the CPER parsing and logging pieces into a common location,
both GHES and the DT provider can reuse the same implementation,
while the ACPI-specific discovery and notification code remains under drivers/acpi/apei/.
This avoids having the DT provider reach into GHES internals or duplicate CPER handling code.

If the current naming or file layout makes that separation unclear, I?m happy to adjust it.

Thanks,
Ahmed


From ben.horgan at arm.com  Fri Dec 19 10:11:11 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:11 +0000
Subject: [PATCH v2 09/45] arm64: mpam: Advertise the CPUs MPAM limits to the driver
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-10-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

Requestors need to populate the MPAM fields for any traffic they send on
the interconnect. For the CPUs these values are taken from the
corresponding MPAMy_ELx register. Each requestor may have a limit on the
largest PARTID or PMG value that can be used. The MPAM driver has to
determine the system-wide minimum supported PARTID and PMG values.

To do this, the driver needs to be told what each requestor's limit is.

CPUs are special, but this infrastructure is also needed for the SMMU and
GIC ITS. Call the helper to tell the MPAM driver what the CPUs can do.

The return value can be ignored by the arch code as it runs well before the
MPAM driver starts probing.

Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
 arch/arm64/kernel/mpam.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/arm64/kernel/mpam.c b/arch/arm64/kernel/mpam.c
index 9866d2ca0faa..e6feff2324ac 100644
--- a/arch/arm64/kernel/mpam.c
+++ b/arch/arm64/kernel/mpam.c
@@ -3,6 +3,7 @@
 
 #include <asm/mpam.h>
 
+#include <linux/arm_mpam.h>
 #include <linux/jump_label.h>
 #include <linux/percpu.h>
 
@@ -11,3 +12,14 @@ DEFINE_PER_CPU(u64, arm64_mpam_default);
 DEFINE_PER_CPU(u64, arm64_mpam_current);
 
 u64 arm64_mpam_global_default;
+
+static int __init arm64_mpam_register_cpus(void)
+{
+	u64 mpamidr = read_sanitised_ftr_reg(SYS_MPAMIDR_EL1);
+	u16 partid_max = FIELD_GET(MPAMIDR_EL1_PARTID_MAX, mpamidr);
+	u8 pmg_max = FIELD_GET(MPAMIDR_EL1_PMG_MAX, mpamidr);
+
+	return mpam_register_requestor(partid_max, pmg_max);
+}
+/* Must occur before mpam_msc_driver_init() from subsys_initcall() */
+arch_initcall(arm64_mpam_register_cpus)
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:12 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:12 +0000
Subject: [PATCH v2 10/45] arm64: mpam: Add cpu_pm notifier to restore MPAM sysregs
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-11-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

The MPAM system registers will be lost if the CPU is reset during PSCI's
CPU_SUSPEND.

Add a PM notifier to restore them.

mpam_thread_switch(current) can't be used as this won't make any changes if
the in-memory copy says the register already has the correct value. In
reality the system register is UNKNOWN out of reset.

Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
 arch/arm64/kernel/mpam.c | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/arch/arm64/kernel/mpam.c b/arch/arm64/kernel/mpam.c
index e6feff2324ac..dbe0a2d05abb 100644
--- a/arch/arm64/kernel/mpam.c
+++ b/arch/arm64/kernel/mpam.c
@@ -4,6 +4,7 @@
 #include <asm/mpam.h>
 
 #include <linux/arm_mpam.h>
+#include <linux/cpu_pm.h>
 #include <linux/jump_label.h>
 #include <linux/percpu.h>
 
@@ -13,12 +14,41 @@ DEFINE_PER_CPU(u64, arm64_mpam_current);
 
 u64 arm64_mpam_global_default;
 
+static int mpam_pm_notifier(struct notifier_block *self,
+			    unsigned long cmd, void *v)
+{
+	u64 regval;
+	int cpu = smp_processor_id();
+
+	switch (cmd) {
+	case CPU_PM_EXIT:
+		/*
+		 * Don't use mpam_thread_switch() as the system register
+		 * value has changed under our feet.
+		 */
+		regval = READ_ONCE(per_cpu(arm64_mpam_current, cpu));
+		write_sysreg_s(regval, SYS_MPAM1_EL1);
+		isb();
+
+		write_sysreg_s(regval, SYS_MPAM0_EL1);
+
+		return NOTIFY_OK;
+	default:
+		return NOTIFY_DONE;
+	}
+}
+
+static struct notifier_block mpam_pm_nb = {
+	.notifier_call = mpam_pm_notifier,
+};
+
 static int __init arm64_mpam_register_cpus(void)
 {
 	u64 mpamidr = read_sanitised_ftr_reg(SYS_MPAMIDR_EL1);
 	u16 partid_max = FIELD_GET(MPAMIDR_EL1_PARTID_MAX, mpamidr);
 	u8 pmg_max = FIELD_GET(MPAMIDR_EL1_PMG_MAX, mpamidr);
 
+	cpu_pm_register_notifier(&mpam_pm_nb);
 	return mpam_register_requestor(partid_max, pmg_max);
 }
 /* Must occur before mpam_msc_driver_init() from subsys_initcall() */
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:13 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:13 +0000
Subject: [PATCH v2 11/45] arm64: mpam: Initialise and context switch the MPAMSM_EL1 register
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-12-ben.horgan@arm.com>

The MPAMSM_EL1 sets the MPAM labels, PMG and PARTID, for loads and stores
generated by a shared SMCU. Disable the traps so the kernel can use it and
set it to the same configuration as the per-EL cpu MPAM configuration.

If an SMCU is not shared with other cpus then it is implementation defined
whether the configuration from MPAMSM_EL1 is used or that from the
appropriate MPAMy_ELx. As we set the same configuration for MPAM0_EL1,
MPAM1_EL1 and MPAMSM_EL1 the resulting configuration is the same
regardless.

Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
 arch/arm64/include/asm/el2_setup.h | 3 ++-
 arch/arm64/include/asm/mpam.h      | 2 ++
 arch/arm64/kernel/cpufeature.c     | 2 ++
 arch/arm64/kernel/mpam.c           | 3 +++
 4 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h
index cacd20df1786..d37984c09799 100644
--- a/arch/arm64/include/asm/el2_setup.h
+++ b/arch/arm64/include/asm/el2_setup.h
@@ -504,7 +504,8 @@
 	check_override id_aa64pfr0, ID_AA64PFR0_EL1_MPAM_SHIFT, .Linit_mpam_\@, .Lskip_mpam_\@, x1, x2
 
 .Linit_mpam_\@:
-	msr_s	SYS_MPAM2_EL2, xzr		// use the default partition
+	mov	x0, #MPAM2_EL2_EnMPAMSM_MASK
+	msr_s	SYS_MPAM2_EL2, x0		// use the default partition,
 						// and disable lower traps
 	mrs_s	x0, SYS_MPAMIDR_EL1
 	tbz	x0, #MPAMIDR_EL1_HAS_HCR_SHIFT, .Lskip_mpam_\@  // skip if no MPAMHCR reg
diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/mpam.h
index 2ab3dca6977c..c4cb015e8d8f 100644
--- a/arch/arm64/include/asm/mpam.h
+++ b/arch/arm64/include/asm/mpam.h
@@ -63,6 +63,8 @@ static inline void mpam_thread_switch(struct task_struct *tsk)
 		return;
 
 	write_sysreg_s(regval, SYS_MPAM1_EL1);
+	if (system_supports_sme())
+		write_sysreg_s(regval & (MPAMSM_EL1_PARTID_D | MPAMSM_EL1_PMG_D), SYS_MPAMSM_EL1);
 	isb();
 
 	/* Synchronising the EL0 write is left until the ERET to EL0 */
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 0cdfb3728f43..2ede543b3eeb 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -2491,6 +2491,8 @@ cpu_enable_mpam(const struct arm64_cpu_capabilities *entry)
 		regval = READ_ONCE(per_cpu(arm64_mpam_current, cpu));
 
 	write_sysreg_s(regval, SYS_MPAM1_EL1);
+	if (system_supports_sme())
+		write_sysreg_s(regval & (MPAMSM_EL1_PARTID_D | MPAMSM_EL1_PMG_D), SYS_MPAMSM_EL1);
 	isb();
 
 	/* Synchronising the EL0 write is left until the ERET to EL0 */
diff --git a/arch/arm64/kernel/mpam.c b/arch/arm64/kernel/mpam.c
index dbe0a2d05abb..6ce4a36469ce 100644
--- a/arch/arm64/kernel/mpam.c
+++ b/arch/arm64/kernel/mpam.c
@@ -28,6 +28,9 @@ static int mpam_pm_notifier(struct notifier_block *self,
 		 */
 		regval = READ_ONCE(per_cpu(arm64_mpam_current, cpu));
 		write_sysreg_s(regval, SYS_MPAM1_EL1);
+		if (system_supports_sme())
+			write_sysreg_s(regval & (MPAMSM_EL1_PARTID_D | MPAMSM_EL1_PMG_D),
+				       SYS_MPAMSM_EL1);
 		isb();
 
 		write_sysreg_s(regval, SYS_MPAM0_EL1);
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:15 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:15 +0000
Subject: [PATCH v2 13/45] KVM: arm64: Force guest EL1 to use user-space's partid configuration
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-14-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

While we trap the guest's attempts to read/write the MPAM control
registers, the hardware continues to use them. Guest-EL0 uses KVM's
user-space's configuration, as the value is left in the register, and
guest-EL1 uses either the host kernel's configuration, or in the case of
VHE, the UNKNOWN reset value of MPAM1_EL1.

We want to force the guest-EL1 to use KVM's user-space's MPAM
configuration. On nVHE rely on MPAM0_EL1 and MPAM1_EL1 always being
programmed the same and on VHE copy MPAM0_EL1 into the guest's
MPAM1_EL1. There is no need to restore as this is out of context once TGE
is set.

Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
Changes since rfc:
Drop the unneeded __mpam_guest_load() in nvhre and the MPAM1_EL1 save restore
Defer EL2 handling until next patch
---
 arch/arm64/kvm/hyp/vhe/sysreg-sr.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm64/kvm/hyp/vhe/sysreg-sr.c b/arch/arm64/kvm/hyp/vhe/sysreg-sr.c
index f28c6cf4fe1b..a2e8f6187675 100644
--- a/arch/arm64/kvm/hyp/vhe/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/vhe/sysreg-sr.c
@@ -183,6 +183,16 @@ void sysreg_restore_guest_state_vhe(struct kvm_cpu_context *ctxt)
 }
 NOKPROBE_SYMBOL(sysreg_restore_guest_state_vhe);
 
+/*
+ * The _EL0 value was written by the host's context switch and belongs to the
+ * VMM. Copy this into the guest's _EL1 register.
+ */
+static inline void __mpam_guest_load(void)
+{
+	if (system_supports_mpam())
+		write_sysreg_el1(read_sysreg_s(SYS_MPAM0_EL1), SYS_MPAM1);
+}
+
 /**
  * __vcpu_load_switch_sysregs - Load guest system registers to the physical CPU
  *
@@ -222,6 +232,7 @@ void __vcpu_load_switch_sysregs(struct kvm_vcpu *vcpu)
 	 */
 	__sysreg32_restore_state(vcpu);
 	__sysreg_restore_user_state(guest_ctxt);
+	__mpam_guest_load();
 
 	if (unlikely(is_hyp_ctxt(vcpu))) {
 		__sysreg_restore_vel2_state(vcpu);
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:14 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:14 +0000
Subject: [PATCH v2 12/45] arm64: mpam: Add helpers to change a task or cpu's MPAM PARTID/PMG values
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-13-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

Care must be taken when modifying the PARTID and PMG of a task in any
per-task structure as writing these values may race with the task being
scheduled in, and reading the modified values.

Add helpers to set the task properties, and the CPU default value.  These
use WRITE_ONCE() that pairs with the READ_ONCE() in mpam_get_regval() to
avoid causing torn values.

CC: Dave Martin <Dave.Martin at arm.com>
Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
Changes since rfc:
Keep comment attached to mpam_get_regval()
Add internal helper, __mpam_regval() (Jonathan)
---
 arch/arm64/include/asm/mpam.h | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/mpam.h
index c4cb015e8d8f..a7fd0656bf90 100644
--- a/arch/arm64/include/asm/mpam.h
+++ b/arch/arm64/include/asm/mpam.h
@@ -4,6 +4,7 @@
 #ifndef __ASM__MPAM_H
 #define __ASM__MPAM_H
 
+#include <linux/bitfield.h>
 #include <linux/jump_label.h>
 #include <linux/percpu.h>
 #include <linux/sched.h>
@@ -22,6 +23,22 @@ DECLARE_PER_CPU(u64, arm64_mpam_current);
  */
 extern u64 arm64_mpam_global_default;
 
+static inline u64 __mpam_regval(u16 partid_d, u16 partid_i, u8 pmg_d, u8 pmg_i)
+{
+	return FIELD_PREP(MPAM0_EL1_PARTID_D, partid_d) |
+		FIELD_PREP(MPAM0_EL1_PARTID_I, partid_i) |
+		FIELD_PREP(MPAM0_EL1_PMG_D, pmg_d) |
+		FIELD_PREP(MPAM0_EL1_PMG_I, pmg_i);
+}
+
+static inline void mpam_set_cpu_defaults(int cpu, u16 partid_d, u16 partid_i,
+					 u8 pmg_d, u8 pmg_i)
+{
+	u64 default_val = __mpam_regval(partid_d, partid_i, pmg_d, pmg_i);
+
+	WRITE_ONCE(per_cpu(arm64_mpam_default, cpu), default_val);
+}
+
 /*
  * The resctrl filesystem writes to the partid/pmg values for threads and CPUs,
  * which may race with reads in mpam_thread_switch(). Ensure only one of the old
@@ -45,6 +62,17 @@ static inline u64 mpam_get_regval(struct task_struct *tsk)
 #endif
 }
 
+static inline void mpam_set_task_partid_pmg(struct task_struct *tsk,
+					    u16 partid_d, u16 partid_i,
+					    u8 pmg_d, u8 pmg_i)
+{
+#ifdef CONFIG_ARM64_MPAM
+	u64 regval = __mpam_regval(partid_d, partid_i, pmg_d, pmg_i);
+
+	WRITE_ONCE(task_thread_info(tsk)->mpam_partid_pmg, regval);
+#endif
+}
+
 static inline void mpam_thread_switch(struct task_struct *tsk)
 {
 	u64 oldregval;
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:16 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:16 +0000
Subject: [PATCH v2 14/45] KVM: arm64: Use kernel-space partid configuration for hypercalls
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-15-ben.horgan@arm.com>

On nVHE systems whether or not MPAM is enabled, EL2 continues to use
partid-0 for hypercalls, even when the host may have configured its kernel
threads to use a different partid. 0 may have been assigned to another
task. Copy the EL1 MPAM register to EL2. This ensures hypercalls use the
same partid as the kernel thread does on the host.

Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
 arch/arm64/kvm/hyp/nvhe/hyp-main.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index a7c689152f68..5c1de7e7dd38 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -635,6 +635,11 @@ static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
 	unsigned long hcall_min = 0;
 	hcall_t hfn;
 
+	if (system_supports_mpam()) {
+		write_sysreg_s(read_sysreg_s(SYS_MPAM1_EL1), SYS_MPAM2_EL2);
+		isb();
+	}
+
 	/*
 	 * If pKVM has been initialised then reject any calls to the
 	 * early "privileged" hypercalls. Note that we cannot reject
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:17 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:17 +0000
Subject: [PATCH v2 15/45] arm_mpam: resctrl: Add boilerplate cpuhp and domain allocation
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-16-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

resctrl has its own data structures to describe its resources. We can't use
these directly as we play tricks with the 'MBA' resource, picking the MPAM
controls or monitors that best apply. We may export the same component as
both L3 and MBA.

Add mpam_resctrl_exports[] as the array of class->resctrl mappings we are
exporting, and add the cpuhp hooks that allocated and free the resctrl
domain structures.

While we're here, plumb in a few other obvious things.

CONFIG_ARM_CPU_RESCTRL is used to allow this code to be built even though
it can't yet be linked against resctrl.

Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
Domain list is an rcu list
Add synchronize_rcu() to free the deleted element
Code flow simplification (Jonathan)
---
 drivers/resctrl/Makefile        |   1 +
 drivers/resctrl/mpam_devices.c  |  12 ++
 drivers/resctrl/mpam_internal.h |  22 +++
 drivers/resctrl/mpam_resctrl.c  | 329 ++++++++++++++++++++++++++++++++
 include/linux/arm_mpam.h        |   3 +
 5 files changed, 367 insertions(+)
 create mode 100644 drivers/resctrl/mpam_resctrl.c

diff --git a/drivers/resctrl/Makefile b/drivers/resctrl/Makefile
index 898199dcf80d..40beaf999582 100644
--- a/drivers/resctrl/Makefile
+++ b/drivers/resctrl/Makefile
@@ -1,4 +1,5 @@
 obj-$(CONFIG_ARM64_MPAM_DRIVER)			+= mpam.o
 mpam-y						+= mpam_devices.o
+mpam-$(CONFIG_ARM_CPU_RESCTRL)			+= mpam_resctrl.o
 
 ccflags-$(CONFIG_ARM64_MPAM_DRIVER_DEBUG)	+= -DDEBUG
diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index 860181266b15..303aacfcb9d6 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -1628,6 +1628,9 @@ static int mpam_cpu_online(unsigned int cpu)
 			mpam_reprogram_msc(msc);
 	}
 
+	if (mpam_is_enabled())
+		mpam_resctrl_online_cpu(cpu);
+
 	return 0;
 }
 
@@ -1671,6 +1674,9 @@ static int mpam_cpu_offline(unsigned int cpu)
 {
 	struct mpam_msc *msc;
 
+	if (mpam_is_enabled())
+		mpam_resctrl_offline_cpu(cpu);
+
 	guard(srcu)(&mpam_srcu);
 	list_for_each_entry_srcu(msc, &mpam_all_msc, all_msc_list,
 				 srcu_read_lock_held(&mpam_srcu)) {
@@ -2517,6 +2523,12 @@ static void mpam_enable_once(void)
 	mutex_unlock(&mpam_list_lock);
 	cpus_read_unlock();
 
+	if (!err) {
+		err = mpam_resctrl_setup();
+		if (err)
+			pr_err("Failed to initialise resctrl: %d\n", err);
+	}
+
 	if (err) {
 		mpam_disable_reason = "Failed to enable.";
 		schedule_work(&mpam_broken_work);
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index e6e7ba4342d6..554e4887ba81 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -12,6 +12,7 @@
 #include <linux/jump_label.h>
 #include <linux/llist.h>
 #include <linux/mutex.h>
+#include <linux/resctrl.h>
 #include <linux/spinlock.h>
 #include <linux/srcu.h>
 #include <linux/types.h>
@@ -333,6 +334,17 @@ struct mpam_msc_ris {
 	struct mpam_garbage	garbage;
 };
 
+struct mpam_resctrl_dom {
+	struct mpam_component	*ctrl_comp;
+	struct rdt_ctrl_domain	resctrl_ctrl_dom;
+	struct rdt_mon_domain	resctrl_mon_dom;
+};
+
+struct mpam_resctrl_res {
+	struct mpam_class	*class;
+	struct rdt_resource	resctrl_res;
+};
+
 static inline int mpam_alloc_csu_mon(struct mpam_class *class)
 {
 	struct mpam_props *cprops = &class->props;
@@ -387,6 +399,16 @@ void mpam_msmon_reset_mbwu(struct mpam_component *comp, struct mon_cfg *ctx);
 int mpam_get_cpumask_from_cache_id(unsigned long cache_id, u32 cache_level,
 				   cpumask_t *affinity);
 
+#ifdef CONFIG_RESCTRL_FS
+int mpam_resctrl_setup(void);
+int mpam_resctrl_online_cpu(unsigned int cpu);
+void mpam_resctrl_offline_cpu(unsigned int cpu);
+#else
+static inline int mpam_resctrl_setup(void) { return 0; }
+static inline int mpam_resctrl_online_cpu(unsigned int cpu) { return 0; }
+static inline void mpam_resctrl_offline_cpu(unsigned int cpu) { }
+#endif /* CONFIG_RESCTRL_FS */
+
 /*
  * MPAM MSCs have the following register layout. See:
  * Arm Memory System Resource Partitioning and Monitoring (MPAM) System
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
new file mode 100644
index 000000000000..4beeeded00ff
--- /dev/null
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -0,0 +1,329 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2025 Arm Ltd.
+
+#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__
+
+#include <linux/arm_mpam.h>
+#include <linux/cacheinfo.h>
+#include <linux/cpu.h>
+#include <linux/cpumask.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/printk.h>
+#include <linux/rculist.h>
+#include <linux/resctrl.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <asm/mpam.h>
+
+#include "mpam_internal.h"
+
+/*
+ * The classes we've picked to map to resctrl resources, wrapped
+ * in with their resctrl structure.
+ * Class pointer may be NULL.
+ */
+static struct mpam_resctrl_res mpam_resctrl_controls[RDT_NUM_RESOURCES];
+
+/* The lock for modifying resctrl's domain lists from cpuhp callbacks. */
+static DEFINE_MUTEX(domain_list_lock);
+
+static bool exposed_alloc_capable;
+static bool exposed_mon_capable;
+
+bool resctrl_arch_alloc_capable(void)
+{
+	return exposed_alloc_capable;
+}
+
+bool resctrl_arch_mon_capable(void)
+{
+	return exposed_mon_capable;
+}
+
+/*
+ * MSC may raise an error interrupt if it sees an out or range partid/pmg,
+ * and go on to truncate the value. Regardless of what the hardware supports,
+ * only the system wide safe value is safe to use.
+ */
+u32 resctrl_arch_get_num_closid(struct rdt_resource *ignored)
+{
+	return mpam_partid_max + 1;
+}
+
+struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l)
+{
+	if (l >= RDT_NUM_RESOURCES)
+		return NULL;
+
+	return &mpam_resctrl_controls[l].resctrl_res;
+}
+
+static int mpam_resctrl_control_init(struct mpam_resctrl_res *res,
+				     enum resctrl_res_level type)
+{
+	/* TODO: initialise the resctrl resources */
+
+	return 0;
+}
+
+static int mpam_resctrl_pick_domain_id(int cpu, struct mpam_component *comp)
+{
+	struct mpam_class *class = comp->class;
+
+	if (class->type == MPAM_CLASS_CACHE)
+		return comp->comp_id;
+
+	/* TODO: repaint domain ids to match the L3 domain ids */
+	/*
+	 * Otherwise, expose the ID used by the firmware table code.
+	 */
+	return comp->comp_id;
+}
+
+static void mpam_resctrl_domain_hdr_init(int cpu, struct mpam_component *comp,
+					 struct rdt_domain_hdr *hdr)
+{
+	lockdep_assert_cpus_held();
+
+	INIT_LIST_HEAD(&hdr->list);
+	hdr->id = mpam_resctrl_pick_domain_id(cpu, comp);
+	cpumask_set_cpu(cpu, &hdr->cpu_mask);
+}
+
+/**
+ * mpam_resctrl_offline_domain_hdr() - Update the domain header to remove a CPU.
+ * @cpu:	The CPU to remove from the domain.
+ * @hdr:	The domain's header.
+ *
+ * Removes @cpu from the header mask. If this was the last CPU in the domain,
+ * the domain header is removed from its parent list and true is returned,
+ * indicating the parent structure can be freed.
+ * If there are other CPUs in the domain, returns false.
+ */
+static bool mpam_resctrl_offline_domain_hdr(unsigned int cpu,
+					    struct rdt_domain_hdr *hdr)
+{
+	lockdep_assert_held(&domain_list_lock);
+
+	cpumask_clear_cpu(cpu, &hdr->cpu_mask);
+	if (cpumask_empty(&hdr->cpu_mask)) {
+		list_del_rcu(&hdr->list);
+		synchronize_rcu();
+		return true;
+	}
+
+	return false;
+}
+
+static struct mpam_resctrl_dom *
+mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
+{
+	int err;
+	struct mpam_resctrl_dom *dom;
+	struct rdt_mon_domain *mon_d;
+	struct rdt_ctrl_domain *ctrl_d;
+	struct mpam_class *class = res->class;
+	struct mpam_component *comp_iter, *ctrl_comp;
+	struct rdt_resource *r = &res->resctrl_res;
+
+	lockdep_assert_held(&domain_list_lock);
+
+	ctrl_comp = NULL;
+	guard(srcu)(&mpam_srcu);
+	list_for_each_entry_srcu(comp_iter, &class->components, class_list,
+				 srcu_read_lock_held(&mpam_srcu)) {
+		if (cpumask_test_cpu(cpu, &comp_iter->affinity)) {
+			ctrl_comp = comp_iter;
+			break;
+		}
+	}
+
+	/* class has no component for this CPU */
+	if (WARN_ON_ONCE(!ctrl_comp))
+		return ERR_PTR(-EINVAL);
+
+	dom = kzalloc_node(sizeof(*dom), GFP_KERNEL, cpu_to_node(cpu));
+	if (!dom)
+		return ERR_PTR(-ENOMEM);
+
+	if (exposed_alloc_capable) {
+		dom->ctrl_comp = ctrl_comp;
+
+		ctrl_d = &dom->resctrl_ctrl_dom;
+		mpam_resctrl_domain_hdr_init(cpu, ctrl_comp, &ctrl_d->hdr);
+		ctrl_d->hdr.type = RESCTRL_CTRL_DOMAIN;
+		/* TODO: this list should be sorted */
+		list_add_tail_rcu(&ctrl_d->hdr.list, &r->ctrl_domains);
+		err = resctrl_online_ctrl_domain(r, ctrl_d);
+		if (err) {
+			dom = ERR_PTR(err);
+			goto offline_ctrl_domain;
+		}
+	} else {
+		pr_debug("Skipped control domain online - no controls\n");
+	}
+
+	if (exposed_mon_capable) {
+		mon_d = &dom->resctrl_mon_dom;
+		mpam_resctrl_domain_hdr_init(cpu, ctrl_comp, &mon_d->hdr);
+		mon_d->hdr.type = RESCTRL_MON_DOMAIN;
+		/* TODO: this list should be sorted */
+		list_add_tail_rcu(&mon_d->hdr.list, &r->mon_domains);
+		err = resctrl_online_mon_domain(r, mon_d);
+		if (err) {
+			dom = ERR_PTR(err);
+			goto offline_mon_hdr;
+		}
+	} else {
+		pr_debug("Skipped monitor domain online - no monitors\n");
+	}
+
+	return dom;
+
+offline_mon_hdr:
+	mpam_resctrl_offline_domain_hdr(cpu, &mon_d->hdr);
+offline_ctrl_domain:
+	resctrl_offline_ctrl_domain(r, ctrl_d);
+
+	return dom;
+}
+
+static struct mpam_resctrl_dom *
+mpam_resctrl_get_domain_from_cpu(int cpu, struct mpam_resctrl_res *res)
+{
+	struct mpam_resctrl_dom *dom;
+	struct rdt_ctrl_domain *ctrl_d;
+	struct rdt_resource *r = &res->resctrl_res;
+
+	lockdep_assert_cpus_held();
+
+	list_for_each_entry_rcu(ctrl_d, &r->ctrl_domains, hdr.list) {
+		dom = container_of(ctrl_d, struct mpam_resctrl_dom,
+				   resctrl_ctrl_dom);
+
+		if (cpumask_test_cpu(cpu, &dom->ctrl_comp->affinity))
+			return dom;
+	}
+
+	return NULL;
+}
+
+int mpam_resctrl_online_cpu(unsigned int cpu)
+{
+	guard(mutex)(&domain_list_lock);
+	for (int i = 0; i < RDT_NUM_RESOURCES; i++) {
+		struct mpam_resctrl_dom *dom;
+		struct mpam_resctrl_res *res;
+
+		res = &mpam_resctrl_controls[i];
+		if (!res->class)
+			continue;	// dummy_resource;
+
+		dom = mpam_resctrl_get_domain_from_cpu(cpu, res);
+		if (!dom)
+			dom = mpam_resctrl_alloc_domain(cpu, res);
+		if (IS_ERR(dom))
+			return PTR_ERR(dom);
+	}
+
+	resctrl_online_cpu(cpu);
+
+	return 0;
+}
+
+void mpam_resctrl_offline_cpu(unsigned int cpu)
+{
+	resctrl_offline_cpu(cpu);
+
+	guard(mutex)(&domain_list_lock);
+	for (int i = 0; i < RDT_NUM_RESOURCES; i++) {
+		struct mpam_resctrl_res *res;
+		struct mpam_resctrl_dom *dom;
+		struct rdt_mon_domain *mon_d;
+		struct rdt_ctrl_domain *ctrl_d;
+		bool ctrl_dom_empty, mon_dom_empty;
+
+		res = &mpam_resctrl_controls[i];
+		if (!res->class)
+			continue;	// dummy resource
+
+		dom = mpam_resctrl_get_domain_from_cpu(cpu, res);
+		if (WARN_ON_ONCE(!dom))
+			continue;
+
+		ctrl_dom_empty = true;
+		if (exposed_alloc_capable) {
+			ctrl_d = &dom->resctrl_ctrl_dom;
+			ctrl_dom_empty = mpam_resctrl_offline_domain_hdr(cpu, &ctrl_d->hdr);
+			if (ctrl_dom_empty)
+				resctrl_offline_ctrl_domain(&res->resctrl_res, ctrl_d);
+		}
+
+		mon_dom_empty = true;
+		if (exposed_mon_capable) {
+			mon_d = &dom->resctrl_mon_dom;
+			mon_dom_empty = mpam_resctrl_offline_domain_hdr(cpu, &mon_d->hdr);
+			if (mon_dom_empty)
+				resctrl_offline_mon_domain(&res->resctrl_res, mon_d);
+		}
+
+		if (ctrl_dom_empty && mon_dom_empty)
+			kfree(dom);
+	}
+}
+
+int mpam_resctrl_setup(void)
+{
+	int err = 0;
+	struct mpam_resctrl_res *res;
+
+	cpus_read_lock();
+	for (enum resctrl_res_level i = 0; i < RDT_NUM_RESOURCES; i++) {
+		res = &mpam_resctrl_controls[i];
+		INIT_LIST_HEAD_RCU(&res->resctrl_res.ctrl_domains);
+		INIT_LIST_HEAD_RCU(&res->resctrl_res.mon_domains);
+		res->resctrl_res.rid = i;
+	}
+
+	/* TODO: pick MPAM classes to map to resctrl resources */
+
+	/* Initialise the resctrl structures from the classes */
+	for (enum resctrl_res_level i = 0; i < RDT_NUM_RESOURCES; i++) {
+		res = &mpam_resctrl_controls[i];
+		if (!res->class)
+			continue;	// dummy resource
+
+		err = mpam_resctrl_control_init(res, i);
+		if (err) {
+			pr_debug("Failed to initialise rid %u\n", i);
+			break;
+		}
+	}
+	cpus_read_unlock();
+
+	if (err) {
+		pr_debug("Internal error %d - resctrl not supported\n", err);
+		return err;
+	}
+
+	if (!exposed_alloc_capable && !exposed_mon_capable) {
+		pr_debug("No alloc(%u) or monitor(%u) found - resctrl not supported\n",
+			 exposed_alloc_capable, exposed_mon_capable);
+		return -EOPNOTSUPP;
+	}
+
+	if (!is_power_of_2(mpam_pmg_max + 1)) {
+		/*
+		 * If not all the partid*pmg values are valid indexes,
+		 * resctrl may allocate pmg that don't exist. This
+		 * should cause an error interrupt.
+		 */
+		pr_warn("Number of PMG is not a power of 2! resctrl may misbehave");
+	}
+
+	/* TODO: call resctrl_init() */
+
+	return err;
+}
diff --git a/include/linux/arm_mpam.h b/include/linux/arm_mpam.h
index 7f00c5285a32..2c7d1413a401 100644
--- a/include/linux/arm_mpam.h
+++ b/include/linux/arm_mpam.h
@@ -49,6 +49,9 @@ static inline int mpam_ris_create(struct mpam_msc *msc, u8 ris_idx,
 }
 #endif
 
+bool resctrl_arch_alloc_capable(void);
+bool resctrl_arch_mon_capable(void);
+
 /**
  * mpam_register_requestor() - Register a requestor with the MPAM driver
  * @partid_max:		The maximum PARTID value the requestor can generate.
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:18 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:18 +0000
Subject: [PATCH v2 16/45] arm_mpam: resctrl: Sort the order of the domain lists
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-17-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

resctrl documents that the domains appear in numeric order in the schemata
file. This means a little more work is needed when bringing a domain
online.

Add the support for this, using resctrl_find_domain() to find the point to
insert in the list.

Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
 drivers/resctrl/mpam_resctrl.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 4beeeded00ff..5481d9cc69d9 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -117,6 +117,21 @@ static bool mpam_resctrl_offline_domain_hdr(unsigned int cpu,
 	return false;
 }
 
+static void mpam_resctrl_domain_insert(struct list_head *list,
+				       struct rdt_domain_hdr *new)
+{
+	struct rdt_domain_hdr *err;
+	struct list_head *pos = NULL;
+
+	lockdep_assert_held(&domain_list_lock);
+
+	err = resctrl_find_domain(list, new->id, &pos);
+	if (WARN_ON_ONCE(err))
+		return;
+
+	list_add_tail_rcu(&new->list, pos);
+}
+
 static struct mpam_resctrl_dom *
 mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
 {
@@ -154,8 +169,7 @@ mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
 		ctrl_d = &dom->resctrl_ctrl_dom;
 		mpam_resctrl_domain_hdr_init(cpu, ctrl_comp, &ctrl_d->hdr);
 		ctrl_d->hdr.type = RESCTRL_CTRL_DOMAIN;
-		/* TODO: this list should be sorted */
-		list_add_tail_rcu(&ctrl_d->hdr.list, &r->ctrl_domains);
+		mpam_resctrl_domain_insert(&r->ctrl_domains, &ctrl_d->hdr);
 		err = resctrl_online_ctrl_domain(r, ctrl_d);
 		if (err) {
 			dom = ERR_PTR(err);
@@ -169,8 +183,7 @@ mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
 		mon_d = &dom->resctrl_mon_dom;
 		mpam_resctrl_domain_hdr_init(cpu, ctrl_comp, &mon_d->hdr);
 		mon_d->hdr.type = RESCTRL_MON_DOMAIN;
-		/* TODO: this list should be sorted */
-		list_add_tail_rcu(&mon_d->hdr.list, &r->mon_domains);
+		mpam_resctrl_domain_insert(&r->mon_domains, &mon_d->hdr);
 		err = resctrl_online_mon_domain(r, mon_d);
 		if (err) {
 			dom = ERR_PTR(err);
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:19 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:19 +0000
Subject: [PATCH v2 17/45] arm_mpam: resctrl: Pick the caches we will use as resctrl resources
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-18-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

Systems with MPAM support may have a variety of control types at any point
of their system layout. We can only expose certain types of control, and
only if they exist at particular locations.

Start with the well-known caches. These have to be depth 2 or 3 and support
MPAM's cache portion bitmap controls, with a number of portions fewer than
resctrl's limit.

Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
Changes since rfc:
Jonathan:
Remove brackets
Compress debug message
Use temp var, r
---
 drivers/resctrl/mpam_resctrl.c | 90 +++++++++++++++++++++++++++++++++-
 1 file changed, 88 insertions(+), 2 deletions(-)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 5481d9cc69d9..bc4f1c80eab5 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -60,10 +60,95 @@ struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l)
 	return &mpam_resctrl_controls[l].resctrl_res;
 }
 
+static bool cache_has_usable_cpor(struct mpam_class *class)
+{
+	struct mpam_props *cprops = &class->props;
+
+	if (!mpam_has_feature(mpam_feat_cpor_part, cprops))
+		return false;
+
+	/* resctrl uses u32 for all bitmap configurations */
+	return class->props.cpbm_wd <= 32;
+}
+
+/* Test whether we can export MPAM_CLASS_CACHE:{2,3}? */
+static void mpam_resctrl_pick_caches(void)
+{
+	struct mpam_class *class;
+	struct mpam_resctrl_res *res;
+
+	lockdep_assert_cpus_held();
+
+	guard(srcu)(&mpam_srcu);
+	list_for_each_entry_srcu(class, &mpam_classes, classes_list,
+				 srcu_read_lock_held(&mpam_srcu)) {
+		if (class->type != MPAM_CLASS_CACHE) {
+			pr_debug("class %u is not a cache\n", class->level);
+			continue;
+		}
+
+		if (class->level != 2 && class->level != 3) {
+			pr_debug("class %u is not L2 or L3\n", class->level);
+			continue;
+		}
+
+		if (!cache_has_usable_cpor(class)) {
+			pr_debug("class %u cache misses CPOR\n", class->level);
+			continue;
+		}
+
+		if (!cpumask_equal(&class->affinity, cpu_possible_mask)) {
+			pr_debug("class %u has missing CPUs, mask %*pb != %*pb\n", class->level,
+				 cpumask_pr_args(&class->affinity),
+				 cpumask_pr_args(cpu_possible_mask));
+			continue;
+		}
+
+		if (class->level == 2)
+			res = &mpam_resctrl_controls[RDT_RESOURCE_L2];
+		else
+			res = &mpam_resctrl_controls[RDT_RESOURCE_L3];
+		res->class = class;
+		exposed_alloc_capable = true;
+	}
+}
+
 static int mpam_resctrl_control_init(struct mpam_resctrl_res *res,
 				     enum resctrl_res_level type)
 {
-	/* TODO: initialise the resctrl resources */
+	struct mpam_class *class = res->class;
+	struct rdt_resource *r = &res->resctrl_res;
+
+	switch (r->rid) {
+	case RDT_RESOURCE_L2:
+	case RDT_RESOURCE_L3:
+		r->alloc_capable = true;
+		r->schema_fmt = RESCTRL_SCHEMA_BITMAP;
+		r->cache.arch_has_sparse_bitmasks = true;
+
+		r->cache.cbm_len = class->props.cpbm_wd;
+		/* mpam_devices will reject empty bitmaps */
+		r->cache.min_cbm_bits = 1;
+
+		if (r->rid == RDT_RESOURCE_L2) {
+			r->name = "L2";
+			r->ctrl_scope = RESCTRL_L2_CACHE;
+		} else {
+			r->name = "L3";
+			r->ctrl_scope = RESCTRL_L3_CACHE;
+		}
+
+		/*
+		 * Which bits are shared with other ...things...
+		 * Unknown devices use partid-0 which uses all the bitmap
+		 * fields. Until we configured the SMMU and GIC not to do this
+		 * 'all the bits' is the correct answer here.
+		 */
+		r->cache.shareable_bits = resctrl_get_default_ctrl(r);
+		break;
+	default:
+		break;
+	}
 
 	return 0;
 }
@@ -300,7 +385,8 @@ int mpam_resctrl_setup(void)
 		res->resctrl_res.rid = i;
 	}
 
-	/* TODO: pick MPAM classes to map to resctrl resources */
+	/* Find some classes to use for controls */
+	mpam_resctrl_pick_caches();
 
 	/* Initialise the resctrl structures from the classes */
 	for (enum resctrl_res_level i = 0; i < RDT_NUM_RESOURCES; i++) {
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:20 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:20 +0000
Subject: [PATCH v2 18/45] arm_mpam: resctrl: Implement resctrl_arch_reset_all_ctrls()
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-19-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

We already have a helper for resetting an mpam class and component.  Hook
it up to resctrl_arch_reset_all_ctrls() and the domain offline path.

Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
 drivers/resctrl/mpam_devices.c  |  6 +++---
 drivers/resctrl/mpam_internal.h |  7 +++++++
 drivers/resctrl/mpam_resctrl.c  | 15 +++++++++++++++
 3 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index 303aacfcb9d6..4f5d908d02a9 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -2544,7 +2544,7 @@ static void mpam_enable_once(void)
 	       mpam_partid_max + 1, mpam_pmg_max + 1);
 }
 
-static void mpam_reset_component_locked(struct mpam_component *comp)
+void mpam_reset_component_locked(struct mpam_component *comp)
 {
 	struct mpam_vmsc *vmsc;
 
@@ -2568,7 +2568,7 @@ static void mpam_reset_component_locked(struct mpam_component *comp)
 	}
 }
 
-static void mpam_reset_class_locked(struct mpam_class *class)
+void mpam_reset_class_locked(struct mpam_class *class)
 {
 	struct mpam_component *comp;
 
@@ -2580,7 +2580,7 @@ static void mpam_reset_class_locked(struct mpam_class *class)
 		mpam_reset_component_locked(comp);
 }
 
-static void mpam_reset_class(struct mpam_class *class)
+void mpam_reset_class(struct mpam_class *class)
 {
 	cpus_read_lock();
 	mpam_reset_class_locked(class);
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index 554e4887ba81..b9a739abb101 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -389,6 +389,13 @@ extern u8 mpam_pmg_max;
 void mpam_enable(struct work_struct *work);
 void mpam_disable(struct work_struct *work);
 
+/* Reset all the RIS in a class, optionally while holding cpus_read_lock() */
+void mpam_reset_class_locked(struct mpam_class *class);
+void mpam_reset_class(struct mpam_class *class);
+
+/* Reset all the RIS in a component under cpus_read_lock() */
+void mpam_reset_component_locked(struct mpam_component *comp);
+
 int mpam_apply_config(struct mpam_component *comp, u16 partid,
 		      struct mpam_config *cfg);
 
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index bc4f1c80eab5..d32e87002457 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -167,6 +167,19 @@ static int mpam_resctrl_pick_domain_id(int cpu, struct mpam_component *comp)
 	return comp->comp_id;
 }
 
+void resctrl_arch_reset_all_ctrls(struct rdt_resource *r)
+{
+	struct mpam_resctrl_res *res;
+
+	lockdep_assert_cpus_held();
+
+	if (!mpam_is_enabled())
+		return;
+
+	res = container_of(r, struct mpam_resctrl_res, resctrl_res);
+	mpam_reset_class_locked(res->class);
+}
+
 static void mpam_resctrl_domain_hdr_init(int cpu, struct mpam_component *comp,
 					 struct rdt_domain_hdr *hdr)
 {
@@ -353,6 +366,8 @@ void mpam_resctrl_offline_cpu(unsigned int cpu)
 
 		ctrl_dom_empty = true;
 		if (exposed_alloc_capable) {
+			mpam_reset_component_locked(dom->ctrl_comp);
+
 			ctrl_d = &dom->resctrl_ctrl_dom;
 			ctrl_dom_empty = mpam_resctrl_offline_domain_hdr(cpu, &ctrl_d->hdr);
 			if (ctrl_dom_empty)
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:21 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:21 +0000
Subject: [PATCH v2 19/45] arm_mpam: resctrl: Add resctrl_arch_get_config()
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-20-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

Implement resctrl_arch_get_config() by testing the live configuration for a
CPOR bitmap. For any other configuration type return the default.

Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
 drivers/resctrl/mpam_resctrl.c | 43 ++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index d32e87002457..607e5f41f9e7 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -167,6 +167,49 @@ static int mpam_resctrl_pick_domain_id(int cpu, struct mpam_component *comp)
 	return comp->comp_id;
 }
 
+u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
+			    u32 closid, enum resctrl_conf_type type)
+{
+	u32 partid;
+	struct mpam_config *cfg;
+	struct mpam_props *cprops;
+	struct mpam_resctrl_res *res;
+	struct mpam_resctrl_dom *dom;
+	enum mpam_device_features configured_by;
+
+	lockdep_assert_cpus_held();
+
+	if (!mpam_is_enabled())
+		return resctrl_get_default_ctrl(r);
+
+	res = container_of(r, struct mpam_resctrl_res, resctrl_res);
+	dom = container_of(d, struct mpam_resctrl_dom, resctrl_ctrl_dom);
+	cprops = &res->class->props;
+
+	partid = resctrl_get_config_index(closid, type);
+	cfg = &dom->ctrl_comp->cfg[partid];
+
+	switch (r->rid) {
+	case RDT_RESOURCE_L2:
+	case RDT_RESOURCE_L3:
+		configured_by = mpam_feat_cpor_part;
+		break;
+	default:
+		return resctrl_get_default_ctrl(r);
+	}
+
+	if (!r->alloc_capable || partid >= resctrl_arch_get_num_closid(r) ||
+	    !mpam_has_feature(configured_by, cfg))
+		return resctrl_get_default_ctrl(r);
+
+	switch (configured_by) {
+	case mpam_feat_cpor_part:
+		return cfg->cpbm;
+	default:
+		return resctrl_get_default_ctrl(r);
+	}
+}
+
 void resctrl_arch_reset_all_ctrls(struct rdt_resource *r)
 {
 	struct mpam_resctrl_res *res;
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:22 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:22 +0000
Subject: [PATCH v2 20/45] arm_mpam: resctrl: Implement helpers to update configuration
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-21-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

resctrl has two helpers for updating the configuration.
resctrl_arch_update_one() updates a single value, and is used by the
software-controller to apply feedback to the bandwidth controls, it has to
be called on one of the CPUs in the resctrl:domain.

resctrl_arch_update_domains() copies multiple staged configurations, it can
be called from anywhere.

Both helpers should update any changes to the underlying hardware.

Implement resctrl_arch_update_domains() to use
resctrl_arch_update_one(). Neither need to be called on a specific CPU as
the mpam driver will send IPIs as needed.

Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
list_for_each_entry -> list_for_each_entry_rcu
return 0
Restrict scope of local variables
---
 drivers/resctrl/mpam_resctrl.c | 70 ++++++++++++++++++++++++++++++++++
 1 file changed, 70 insertions(+)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 607e5f41f9e7..e5ec5438eca8 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -210,6 +210,76 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 	}
 }
 
+int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
+			    u32 closid, enum resctrl_conf_type t, u32 cfg_val)
+{
+	u32 partid;
+	struct mpam_config cfg;
+	struct mpam_props *cprops;
+	struct mpam_resctrl_res *res;
+	struct mpam_resctrl_dom *dom;
+
+	lockdep_assert_cpus_held();
+	lockdep_assert_irqs_enabled();
+
+	/*
+	 * No need to check the CPU as mpam_apply_config() doesn't care, and
+	 * resctrl_arch_update_domains() relies on this.
+	 */
+	res = container_of(r, struct mpam_resctrl_res, resctrl_res);
+	dom = container_of(d, struct mpam_resctrl_dom, resctrl_ctrl_dom);
+	cprops = &res->class->props;
+
+	partid = resctrl_get_config_index(closid, t);
+	if (!r->alloc_capable || partid >= resctrl_arch_get_num_closid(r)) {
+		pr_debug("Not alloc capable or computed PARTID out of range\n");
+		return -EINVAL;
+	}
+
+       /*
+	* Copy the current config to avoid clearing other resources when the
+	* same component is exposed multiple times through resctrl.
+	*/
+	cfg = dom->ctrl_comp->cfg[partid];
+
+	switch (r->rid) {
+	case RDT_RESOURCE_L2:
+	case RDT_RESOURCE_L3:
+		cfg.cpbm = cfg_val;
+		mpam_set_feature(mpam_feat_cpor_part, &cfg);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return mpam_apply_config(dom->ctrl_comp, partid, &cfg);
+}
+
+int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid)
+{
+	int err;
+	struct rdt_ctrl_domain *d;
+
+	lockdep_assert_cpus_held();
+	lockdep_assert_irqs_enabled();
+
+	list_for_each_entry_rcu(d, &r->ctrl_domains, hdr.list) {
+		for (enum resctrl_conf_type t = 0; t < CDP_NUM_TYPES; t++) {
+			struct resctrl_staged_config *cfg = &d->staged_config[t];
+
+			if (!cfg->have_new_ctrl)
+				continue;
+
+			err = resctrl_arch_update_one(r, d, closid, t,
+						      cfg->new_ctrl);
+			if (err)
+				return err;
+		}
+	}
+
+	return 0;
+}
+
 void resctrl_arch_reset_all_ctrls(struct rdt_resource *r)
 {
 	struct mpam_resctrl_res *res;
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:23 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:23 +0000
Subject: [PATCH v2 21/45] arm_mpam: resctrl: Add plumbing against arm64 task and cpu hooks
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-22-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

arm64 provides helpers for changing a tasks and a cpus mpam partid/pmg
values.

These are used to back a number of resctrl_arch_ functions. Connect them
up.

Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
 drivers/resctrl/mpam_resctrl.c | 58 ++++++++++++++++++++++++++++++++++
 include/linux/arm_mpam.h       |  5 +++
 2 files changed, 63 insertions(+)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index e5ec5438eca8..2f72ca66fb8c 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -8,6 +8,7 @@
 #include <linux/cpu.h>
 #include <linux/cpumask.h>
 #include <linux/errno.h>
+#include <linux/limits.h>
 #include <linux/list.h>
 #include <linux/printk.h>
 #include <linux/rculist.h>
@@ -32,6 +33,8 @@ static DEFINE_MUTEX(domain_list_lock);
 static bool exposed_alloc_capable;
 static bool exposed_mon_capable;
 
+static bool cdp_enabled;
+
 bool resctrl_arch_alloc_capable(void)
 {
 	return exposed_alloc_capable;
@@ -52,6 +55,61 @@ u32 resctrl_arch_get_num_closid(struct rdt_resource *ignored)
 	return mpam_partid_max + 1;
 }
 
+void resctrl_arch_sched_in(struct task_struct *tsk)
+{
+	lockdep_assert_preemption_disabled();
+
+	mpam_thread_switch(tsk);
+}
+
+void resctrl_arch_set_cpu_default_closid_rmid(int cpu, u32 closid, u32 rmid)
+{
+	WARN_ON_ONCE(closid > U16_MAX);
+	WARN_ON_ONCE(rmid > U8_MAX);
+
+	if (!cdp_enabled) {
+		mpam_set_cpu_defaults(cpu, closid, closid, rmid, rmid);
+	} else {
+		/*
+		 * When CDP is enabled, resctrl halves the closid range and we
+		 * use odd/even partid for one closid.
+		 */
+		u32 partid_d = resctrl_get_config_index(closid, CDP_DATA);
+		u32 partid_i = resctrl_get_config_index(closid, CDP_CODE);
+
+		mpam_set_cpu_defaults(cpu, partid_d, partid_i, rmid, rmid);
+	}
+}
+
+void resctrl_arch_sync_cpu_closid_rmid(void *info)
+{
+	struct resctrl_cpu_defaults *r = info;
+
+	lockdep_assert_preemption_disabled();
+
+	if (r) {
+		resctrl_arch_set_cpu_default_closid_rmid(smp_processor_id(),
+							 r->closid, r->rmid);
+	}
+
+	resctrl_arch_sched_in(current);
+}
+
+void resctrl_arch_set_closid_rmid(struct task_struct *tsk, u32 closid, u32 rmid)
+{
+	WARN_ON_ONCE(closid > U16_MAX);
+	WARN_ON_ONCE(rmid > U8_MAX);
+
+	if (!cdp_enabled) {
+		mpam_set_task_partid_pmg(tsk, closid, closid, rmid, rmid);
+	} else {
+		u32 partid_d = resctrl_get_config_index(closid, CDP_DATA);
+		u32 partid_i = resctrl_get_config_index(closid, CDP_CODE);
+
+		mpam_set_task_partid_pmg(tsk, partid_d, partid_i, rmid, rmid);
+	}
+}
+
 struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l)
 {
 	if (l >= RDT_NUM_RESOURCES)
diff --git a/include/linux/arm_mpam.h b/include/linux/arm_mpam.h
index 2c7d1413a401..5a78299ec464 100644
--- a/include/linux/arm_mpam.h
+++ b/include/linux/arm_mpam.h
@@ -52,6 +52,11 @@ static inline int mpam_ris_create(struct mpam_msc *msc, u8 ris_idx,
 bool resctrl_arch_alloc_capable(void);
 bool resctrl_arch_mon_capable(void);
 
+void resctrl_arch_set_cpu_default_closid(int cpu, u32 closid);
+void resctrl_arch_set_closid_rmid(struct task_struct *tsk, u32 closid, u32 rmid);
+void resctrl_arch_set_cpu_default_closid_rmid(int cpu, u32 closid, u32 rmid);
+void resctrl_arch_sched_in(struct task_struct *tsk);
+
 /**
  * mpam_register_requestor() - Register a requestor with the MPAM driver
  * @partid_max:		The maximum PARTID value the requestor can generate.
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:24 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:24 +0000
Subject: [PATCH v2 22/45] arm_mpam: resctrl: Add CDP emulation
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-23-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

Intel RDT's CDP feature allows the cache to use a different control value
depending on whether the accesses was for instruction fetch or a data
access. MPAM's equivalent feature is the other way up: the CPU assigns a
different partid label to traffic depending on whether it was instruction
fetch or a data access, which causes the cache to use a different control
value based solely on the partid.

MPAM can emulate CDP, with the side effect that the alternative partid is
seen by all MSC, it can't be enabled per-MSC.

Add the resctrl hooks to turn this on or off. Add the helpers that match a
closid against a task, which need to be aware that the value written to
hardware is not the same as the one resctrl is using.

Update the 'arm64_mpam_global_default' variable the arch code uses during
context switch to know when the per-cpu value should be used instead.

Awkwardly, the MB controls don't implement CDP. To emulate this, the MPAM
equivalent needs programming twice by the resctrl glue, as resctrl expects
the bandwidth controls to be applied independently for both data and
instruction-fetch.

CC: Dave Martin <Dave.Martin at arm.com>
CC: Amit Singh Tomar <amitsinght at marvell.com>
Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
Changes since rfc:
Fail cdp initialisation if there is only one partid
Correct data/code confusion
---
 arch/arm64/include/asm/mpam.h  |   1 +
 drivers/resctrl/mpam_resctrl.c | 112 +++++++++++++++++++++++++++++++++
 include/linux/arm_mpam.h       |   3 +
 3 files changed, 116 insertions(+)

diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/mpam.h
index a7fd0656bf90..09ab1492695d 100644
--- a/arch/arm64/include/asm/mpam.h
+++ b/arch/arm64/include/asm/mpam.h
@@ -4,6 +4,7 @@
 #ifndef __ASM__MPAM_H
 #define __ASM__MPAM_H
 
+#include <linux/arm_mpam.h>
 #include <linux/bitfield.h>
 #include <linux/jump_label.h>
 #include <linux/percpu.h>
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 2f72ca66fb8c..4275b1a85887 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -33,6 +33,10 @@ static DEFINE_MUTEX(domain_list_lock);
 static bool exposed_alloc_capable;
 static bool exposed_mon_capable;
 
+/*
+ * MPAM emulates CDP by setting different PARTID in the I/D fields of MPAM0_EL1.
+ * This applies globally to all traffic the CPU generates.
+ */
 static bool cdp_enabled;
 
 bool resctrl_arch_alloc_capable(void)
@@ -45,6 +49,67 @@ bool resctrl_arch_mon_capable(void)
 	return exposed_mon_capable;
 }
 
+bool resctrl_arch_get_cdp_enabled(enum resctrl_res_level rid)
+{
+	switch (rid) {
+	case RDT_RESOURCE_L2:
+	case RDT_RESOURCE_L3:
+		return cdp_enabled;
+	case RDT_RESOURCE_MBA:
+	default:
+		/*
+		 * x86's MBA control doesn't support CDP, so user-space doesn't
+		 * expect it.
+		 */
+		return false;
+	}
+}
+
+/**
+ * resctrl_reset_task_closids() - Reset the PARTID/PMG values for all tasks.
+ *
+ * At boot, all existing tasks use partid zero for D and I.
+ * To enable/disable CDP emulation, all these tasks need relabelling.
+ */
+static void resctrl_reset_task_closids(void)
+{
+	struct task_struct *p, *t;
+
+	read_lock(&tasklist_lock);
+	for_each_process_thread(p, t) {
+		resctrl_arch_set_closid_rmid(t, RESCTRL_RESERVED_CLOSID,
+					     RESCTRL_RESERVED_RMID);
+	}
+	read_unlock(&tasklist_lock);
+}
+
+int resctrl_arch_set_cdp_enabled(enum resctrl_res_level ignored, bool enable)
+{
+	u32 partid_i = RESCTRL_RESERVED_CLOSID, partid_d = RESCTRL_RESERVED_CLOSID;
+
+	cdp_enabled = enable;
+
+	if (enable) {
+		if (mpam_partid_max < 1)
+			return -EINVAL;
+
+		partid_d = resctrl_get_config_index(RESCTRL_RESERVED_CLOSID, CDP_DATA);
+		partid_i = resctrl_get_config_index(RESCTRL_RESERVED_CLOSID, CDP_CODE);
+	}
+
+	mpam_set_task_partid_pmg(current, partid_d, partid_i, 0, 0);
+	WRITE_ONCE(arm64_mpam_global_default, mpam_get_regval(current));
+
+	resctrl_reset_task_closids();
+
+	return 0;
+}
+
+static bool mpam_resctrl_hide_cdp(enum resctrl_res_level rid)
+{
+	return cdp_enabled && !resctrl_arch_get_cdp_enabled(rid);
+}
+
 /*
  * MSC may raise an error interrupt if it sees an out or range partid/pmg,
  * and go on to truncate the value. Regardless of what the hardware supports,
@@ -110,6 +175,30 @@ void resctrl_arch_set_closid_rmid(struct task_struct *tsk, u32 closid, u32 rmid)
 	}
 }
 
+bool resctrl_arch_match_closid(struct task_struct *tsk, u32 closid)
+{
+	u64 regval = mpam_get_regval(tsk);
+	u32 tsk_closid = FIELD_GET(MPAM0_EL1_PARTID_D, regval);
+
+	if (cdp_enabled)
+		tsk_closid >>= 1;
+
+	return tsk_closid == closid;
+}
+
+/* The task's pmg is not unique, the partid must be considered too */
+bool resctrl_arch_match_rmid(struct task_struct *tsk, u32 closid, u32 rmid)
+{
+	u64 regval = mpam_get_regval(tsk);
+	u32 tsk_closid = FIELD_GET(MPAM0_EL1_PARTID_D, regval);
+	u32 tsk_rmid = FIELD_GET(MPAM0_EL1_PMG_D, regval);
+
+	if (cdp_enabled)
+		tsk_closid >>= 1;
+
+	return (tsk_closid == closid) && (tsk_rmid == rmid);
+}
+
 struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l)
 {
 	if (l >= RDT_NUM_RESOURCES)
@@ -244,6 +333,14 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 	dom = container_of(d, struct mpam_resctrl_dom, resctrl_ctrl_dom);
 	cprops = &res->class->props;
 
+	/*
+	 * When CDP is enabled, but the resource doesn't support it,
+	 * the control is cloned across both partids.
+	 * Pick one at random to read:
+	 */
+	if (mpam_resctrl_hide_cdp(r->rid))
+		type = CDP_DATA;
+
 	partid = resctrl_get_config_index(closid, type);
 	cfg = &dom->ctrl_comp->cfg[partid];
 
@@ -271,6 +368,7 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 			    u32 closid, enum resctrl_conf_type t, u32 cfg_val)
 {
+	int err;
 	u32 partid;
 	struct mpam_config cfg;
 	struct mpam_props *cprops;
@@ -310,6 +408,20 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 		return -EINVAL;
 	}
 
+	/*
+	 * When CDP is enabled, but the resource doesn't support it, we need to
+	 * apply the same configuration to the other partid.
+	 */
+	if (mpam_resctrl_hide_cdp(r->rid)) {
+		partid = resctrl_get_config_index(closid, CDP_CODE);
+		err = mpam_apply_config(dom->ctrl_comp, partid, &cfg);
+		if (err)
+			return err;
+
+		partid = resctrl_get_config_index(closid, CDP_DATA);
+		return mpam_apply_config(dom->ctrl_comp, partid, &cfg);
+	}
+
 	return mpam_apply_config(dom->ctrl_comp, partid, &cfg);
 }
 
diff --git a/include/linux/arm_mpam.h b/include/linux/arm_mpam.h
index 5a78299ec464..ba0312b55d9f 100644
--- a/include/linux/arm_mpam.h
+++ b/include/linux/arm_mpam.h
@@ -5,6 +5,7 @@
 #define __LINUX_ARM_MPAM_H
 
 #include <linux/acpi.h>
+#include <linux/resctrl_types.h>
 #include <linux/types.h>
 
 struct mpam_msc;
@@ -56,6 +57,8 @@ void resctrl_arch_set_cpu_default_closid(int cpu, u32 closid);
 void resctrl_arch_set_closid_rmid(struct task_struct *tsk, u32 closid, u32 rmid);
 void resctrl_arch_set_cpu_default_closid_rmid(int cpu, u32 closid, u32 rmid);
 void resctrl_arch_sched_in(struct task_struct *tsk);
+bool resctrl_arch_match_closid(struct task_struct *tsk, u32 closid);
+bool resctrl_arch_match_rmid(struct task_struct *tsk, u32 closid, u32 rmid);
 
 /**
  * mpam_register_requestor() - Register a requestor with the MPAM driver
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:25 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:25 +0000
Subject: [PATCH v2 23/45] arm_mpam: resctrl: Add rmid index helpers
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-24-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

Because MPAM's pmg aren't identical to RDT's rmid, resctrl handles some
data structures by index. This allows x86 to map indexes to RMID, and MPAM
to map them to partid-and-pmg.

Add the helpers to do this.

Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
Changes since rfc:
Use ~0U instead of ~0 in lhs of left shift
---
 drivers/resctrl/mpam_resctrl.c | 28 ++++++++++++++++++++++++++++
 include/linux/arm_mpam.h       |  3 +++
 2 files changed, 31 insertions(+)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 4275b1a85887..bdbc5504964b 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -120,6 +120,34 @@ u32 resctrl_arch_get_num_closid(struct rdt_resource *ignored)
 	return mpam_partid_max + 1;
 }
 
+u32 resctrl_arch_system_num_rmid_idx(void)
+{
+	u8 closid_shift = fls(mpam_pmg_max);
+	u32 num_partid = resctrl_arch_get_num_closid(NULL);
+
+	return num_partid << closid_shift;
+}
+
+u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid)
+{
+	u8 closid_shift = fls(mpam_pmg_max);
+
+	WARN_ON_ONCE(closid_shift > 8);
+
+	return (closid << closid_shift) | rmid;
+}
+
+void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid)
+{
+	u8 closid_shift = fls(mpam_pmg_max);
+	u32 pmg_mask = ~(~0U << closid_shift);
+
+	WARN_ON_ONCE(closid_shift > 8);
+
+	*closid = idx >> closid_shift;
+	*rmid = idx & pmg_mask;
+}
+
 void resctrl_arch_sched_in(struct task_struct *tsk)
 {
 	lockdep_assert_preemption_disabled();
diff --git a/include/linux/arm_mpam.h b/include/linux/arm_mpam.h
index ba0312b55d9f..385554ceb452 100644
--- a/include/linux/arm_mpam.h
+++ b/include/linux/arm_mpam.h
@@ -59,6 +59,9 @@ void resctrl_arch_set_cpu_default_closid_rmid(int cpu, u32 closid, u32 rmid);
 void resctrl_arch_sched_in(struct task_struct *tsk);
 bool resctrl_arch_match_closid(struct task_struct *tsk, u32 closid);
 bool resctrl_arch_match_rmid(struct task_struct *tsk, u32 closid, u32 rmid);
+u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid);
+void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid);
+u32 resctrl_arch_system_num_rmid_idx(void);
 
 /**
  * mpam_register_requestor() - Register a requestor with the MPAM driver
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:26 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:26 +0000
Subject: [PATCH v2 24/45] arm_mpam: resctrl: Convert to/from MPAMs fixed-point formats
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-25-ben.horgan@arm.com>

From: Dave Martin <Dave.Martin at arm.com>

MPAM uses a fixed-point formats for some hardware controls.  Resctrl
provides the bandwidth controls as a percentage. Add helpers to convert
between these.

Signed-off-by: Dave Martin <Dave.Martin at arm.com>
Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
 drivers/resctrl/mpam_resctrl.c | 41 ++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index bdbc5504964b..a20656e49edc 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -10,6 +10,7 @@
 #include <linux/errno.h>
 #include <linux/limits.h>
 #include <linux/list.h>
+#include <linux/math.h>
 #include <linux/printk.h>
 #include <linux/rculist.h>
 #include <linux/resctrl.h>
@@ -246,6 +247,46 @@ static bool cache_has_usable_cpor(struct mpam_class *class)
 	return class->props.cpbm_wd <= 32;
 }
 
+/*
+ * Each fixed-point hardware value architecturally represents a range
+ * of values: the full range 0% - 100% is split contiguously into
+ * (1 << cprops->bwa_wd) equal bands.
+ * Find the nearest percentage value to the upper bound of the selected band:
+ */
+static u32 mbw_max_to_percent(u16 mbw_max, struct mpam_props *cprops)
+{
+	u32 val = mbw_max;
+
+	val >>= 16 - cprops->bwa_wd;
+	val += 1;
+	val *= MAX_MBA_BW;
+	val = DIV_ROUND_CLOSEST(val, 1 << cprops->bwa_wd);
+
+	return val;
+}
+
+/*
+ * Find the band whose upper bound is closest to the specified percentage.
+ *
+ * A round-to-nearest policy is followed here as a balanced compromise
+ * between unexpected under-commit of the resource (where the total of
+ * a set of resource allocations after conversion is less than the
+ * expected total, due to rounding of the individual converted
+ * percentages) and over-commit (where the total of the converted
+ * allocations is greater than expected).
+ */
+static u16 percent_to_mbw_max(u8 pc, struct mpam_props *cprops)
+{
+	u32 val = pc;
+
+	val <<= cprops->bwa_wd;
+	val = DIV_ROUND_CLOSEST(val, MAX_MBA_BW);
+	val = max(val, 1) - 1;
+	val <<= 16 - cprops->bwa_wd;
+
+	return val;
+}
+
 /* Test whether we can export MPAM_CLASS_CACHE:{2,3}? */
 static void mpam_resctrl_pick_caches(void)
 {
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:27 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:27 +0000
Subject: [PATCH v2 25/45] arm_mpam: resctrl: Add support for 'MB' resource
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-26-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

resctrl supports 'MB', as a percentage throttling of traffic somewhere
after the L3. This is the control that mba_sc uses, so ideally the class
chosen should be as close as possible to the counters used for mba_local.

MB's percentage control should be backed either with the fixed point
fraction MBW_MAX. The bandwidth portion bitmaps is not used as its tricky
to pick which bits to use to avoid contention, and may be possible to
expose this as something other than a percentage in the future.

CC: Zeng Heng <zengheng4 at huawei.com>
Co-developed-by: Dave Martin <Dave.Martin at arm.com>
Signed-off-by: Dave Martin <Dave.Martin at arm.com>
Signed-off-by: James Morse <james.morse at arm.com>>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
 drivers/resctrl/mpam_resctrl.c | 212 ++++++++++++++++++++++++++++++++-
 1 file changed, 211 insertions(+), 1 deletion(-)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index a20656e49edc..e376841c5596 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -247,6 +247,33 @@ static bool cache_has_usable_cpor(struct mpam_class *class)
 	return class->props.cpbm_wd <= 32;
 }
 
+static bool mba_class_use_mbw_max(struct mpam_props *cprops)
+{
+	return (mpam_has_feature(mpam_feat_mbw_max, cprops) &&
+		cprops->bwa_wd);
+}
+
+static bool class_has_usable_mba(struct mpam_props *cprops)
+{
+	return mba_class_use_mbw_max(cprops);
+}
+
+/*
+ * Calculate the worst-case percentage change from each implemented step
+ * in the control.
+ */
+static u32 get_mba_granularity(struct mpam_props *cprops)
+{
+	if (!mba_class_use_mbw_max(cprops))
+		return 0;
+
+	/*
+	 * bwa_wd is the number of bits implemented in the 0.xxx
+	 * fixed point fraction. 1 bit is 50%, 2 is 25% etc.
+	 */
+	return DIV_ROUND_UP(MAX_MBA_BW, 1 << cprops->bwa_wd);
+}
+
 /*
  * Each fixed-point hardware value architecturally represents a range
  * of values: the full range 0% - 100% is split contiguously into
@@ -287,6 +314,96 @@ static u16 percent_to_mbw_max(u8 pc, struct mpam_props *cprops)
 	return val;
 }
 
+static u32 get_mba_min(struct mpam_props *cprops)
+{
+	u32 val = 0;
+
+	if (mba_class_use_mbw_max(cprops))
+		val = mbw_max_to_percent(val, cprops);
+	else
+		WARN_ON_ONCE(1);
+
+	return val;
+}
+
+/* Find the L3 cache that has affinity with this CPU */
+static int find_l3_equivalent_bitmask(int cpu, cpumask_var_t tmp_cpumask)
+{
+	u32 cache_id = get_cpu_cacheinfo_id(cpu, 3);
+
+	lockdep_assert_cpus_held();
+
+	return mpam_get_cpumask_from_cache_id(cache_id, 3, tmp_cpumask);
+}
+
+/*
+ * topology_matches_l3() - Is the provided class the same shape as L3
+ * @victim:		The class we'd like to pretend is L3.
+ *
+ * resctrl expects all the world's a Xeon, and all counters are on the
+ * L3. We play fast and loose with this, mapping counters on other
+ * classes - provided the CPU->domain mapping is the same kind of shape.
+ *
+ * Using cacheinfo directly would make this work even if resctrl can't
+ * use the L3 - but cacheinfo can't tell us anything about offline CPUs.
+ * Using the L3 resctrl domain list also depends on CPUs being online.
+ * Using the mpam_class we picked for L3 so we can use its domain list
+ * assumes that there are MPAM controls on the L3.
+ * Instead, this path eventually uses the mpam_get_cpumask_from_cache_id()
+ * helper which can tell us about offline CPUs ... but getting the cache_id
+ * to start with relies on at least one CPU per L3 cache being online at
+ * boot.
+ *
+ * Walk the victim component list and compare the affinity mask with the
+ * corresponding L3. The topology matches if each victim:component's affinity
+ * mask is the same as the CPU's corresponding L3's. These lists/masks are
+ * computed from firmware tables so don't change at runtime.
+ */
+static bool topology_matches_l3(struct mpam_class *victim)
+{
+	int cpu, err;
+	struct mpam_component *victim_iter;
+	cpumask_var_t __free(free_cpumask_var) tmp_cpumask;
+
+	if (!alloc_cpumask_var(&tmp_cpumask, GFP_KERNEL))
+		return false;
+
+	guard(srcu)(&mpam_srcu);
+	list_for_each_entry_srcu(victim_iter, &victim->components, class_list,
+				 srcu_read_lock_held(&mpam_srcu)) {
+		if (cpumask_empty(&victim_iter->affinity)) {
+			pr_debug("class %u has CPU-less component %u - can't match L3!\n",
+				 victim->level, victim_iter->comp_id);
+			return false;
+		}
+
+		cpu = cpumask_any(&victim_iter->affinity);
+		if (WARN_ON_ONCE(cpu >= nr_cpu_ids))
+			return false;
+
+		cpumask_clear(tmp_cpumask);
+		err = find_l3_equivalent_bitmask(cpu, tmp_cpumask);
+		if (err) {
+			pr_debug("Failed to find L3's equivalent component to class %u component %u\n",
+				 victim->level, victim_iter->comp_id);
+			return false;
+		}
+
+		/* Any differing bits in the affinity mask? */
+		if (!cpumask_equal(tmp_cpumask, &victim_iter->affinity)) {
+			pr_debug("class %u component %u has Mismatched CPU mask with L3 equivalent\n"
+				 "L3:%*pbl != victim:%*pbl\n",
+				 victim->level, victim_iter->comp_id,
+				 cpumask_pr_args(tmp_cpumask),
+				 cpumask_pr_args(&victim_iter->affinity));
+
+			return false;
+		}
+	}
+
+	return true;
+}
+
 /* Test whether we can export MPAM_CLASS_CACHE:{2,3}? */
 static void mpam_resctrl_pick_caches(void)
 {
@@ -329,10 +446,63 @@ static void mpam_resctrl_pick_caches(void)
 	}
 }
 
+static void mpam_resctrl_pick_mba(void)
+{
+	struct mpam_class *class, *candidate_class = NULL;
+	struct mpam_resctrl_res *res;
+
+	lockdep_assert_cpus_held();
+
+	guard(srcu)(&mpam_srcu);
+	list_for_each_entry_srcu(class, &mpam_classes, classes_list,
+				 srcu_read_lock_held(&mpam_srcu)) {
+		struct mpam_props *cprops = &class->props;
+
+		if (class->level < 3) {
+			pr_debug("class %u is before L3\n", class->level);
+			continue;
+		}
+
+		if (!class_has_usable_mba(cprops)) {
+			pr_debug("class %u has no bandwidth control\n",
+				 class->level);
+			continue;
+		}
+
+		if (!cpumask_equal(&class->affinity, cpu_possible_mask)) {
+			pr_debug("class %u has missing CPUs\n", class->level);
+			continue;
+		}
+
+		if (!topology_matches_l3(class)) {
+			pr_debug("class %u topology doesn't match L3\n",
+				 class->level);
+			continue;
+		}
+
+		/*
+		 * mba_sc reads the mbm_local counter, and waggles the MBA
+		 * controls. mbm_local is implicitly part of the L3, pick a
+		 * resource to be MBA that as close as possible to the L3.
+		 */
+		if (!candidate_class || class->level < candidate_class->level)
+			candidate_class = class;
+	}
+
+	if (candidate_class) {
+		pr_debug("selected class %u to back MBA\n",
+			 candidate_class->level);
+		res = &mpam_resctrl_controls[RDT_RESOURCE_MBA];
+		res->class = candidate_class;
+		exposed_alloc_capable = true;
+	}
+}
+
 static int mpam_resctrl_control_init(struct mpam_resctrl_res *res,
 				     enum resctrl_res_level type)
 {
 	struct mpam_class *class = res->class;
+	struct mpam_props *cprops = &class->props;
 	struct rdt_resource *r = &res->resctrl_res;
 
 	switch (r->rid) {
@@ -361,6 +531,20 @@ static int mpam_resctrl_control_init(struct mpam_resctrl_res *res,
 		 * 'all the bits' is the correct answer here.
 		 */
 		r->cache.shareable_bits = resctrl_get_default_ctrl(r);
+		break;
+	case RDT_RESOURCE_MBA:
+		r->alloc_capable = true;
+		r->schema_fmt = RESCTRL_SCHEMA_RANGE;
+		r->ctrl_scope = RESCTRL_L3_CACHE;
+
+		r->membw.delay_linear = true;
+		r->membw.throttle_mode = THREAD_THROTTLE_UNDEFINED;
+		r->membw.min_bw = get_mba_min(cprops);
+		r->membw.max_bw = MAX_MBA_BW;
+		r->membw.bw_gran = get_mba_granularity(cprops);
+
+		r->name = "MB";
+
 		break;
 	default:
 		break;
@@ -376,7 +560,17 @@ static int mpam_resctrl_pick_domain_id(int cpu, struct mpam_component *comp)
 	if (class->type == MPAM_CLASS_CACHE)
 		return comp->comp_id;
 
-	/* TODO: repaint domain ids to match the L3 domain ids */
+	if (topology_matches_l3(class)) {
+		/* Use the corresponding L3 component ID as the domain ID */
+		int id = get_cpu_cacheinfo_id(cpu, 3);
+
+		/* Implies topology_matches_l3() made a mistake */
+		if (WARN_ON_ONCE(id == -1))
+			return comp->comp_id;
+
+		return id;
+	}
+
 	/*
 	 * Otherwise, expose the ID used by the firmware table code.
 	 */
@@ -418,6 +612,12 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 	case RDT_RESOURCE_L3:
 		configured_by = mpam_feat_cpor_part;
 		break;
+	case RDT_RESOURCE_MBA:
+		if (mpam_has_feature(mpam_feat_mbw_max, cprops)) {
+			configured_by = mpam_feat_mbw_max;
+			break;
+		}
+		fallthrough;
 	default:
 		return resctrl_get_default_ctrl(r);
 	}
@@ -429,6 +629,8 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 	switch (configured_by) {
 	case mpam_feat_cpor_part:
 		return cfg->cpbm;
+	case mpam_feat_mbw_max:
+		return mbw_max_to_percent(cfg->mbw_max, cprops);
 	default:
 		return resctrl_get_default_ctrl(r);
 	}
@@ -473,6 +675,13 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 		cfg.cpbm = cfg_val;
 		mpam_set_feature(mpam_feat_cpor_part, &cfg);
 		break;
+	case RDT_RESOURCE_MBA:
+		if (mpam_has_feature(mpam_feat_mbw_max, cprops)) {
+			cfg.mbw_max = percent_to_mbw_max(cfg_val, cprops);
+			mpam_set_feature(mpam_feat_mbw_max, &cfg);
+			break;
+		}
+		fallthrough;
 	default:
 		return -EINVAL;
 	}
@@ -754,6 +963,7 @@ int mpam_resctrl_setup(void)
 
 	/* Find some classes to use for controls */
 	mpam_resctrl_pick_caches();
+	mpam_resctrl_pick_mba();
 
 	/* Initialise the resctrl structures from the classes */
 	for (enum resctrl_res_level i = 0; i < RDT_NUM_RESOURCES; i++) {
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:28 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:28 +0000
Subject: [PATCH v2 26/45] arm_mpam: resctrl: Add kunit test for control format conversions
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-27-ben.horgan@arm.com>

From: Dave Martin <Dave.Martin at arm.com>

resctrl specifies the format of the control schemes, and these don't match
the hardware.

Some of the conversions are a bit hairy - add some kunit tests.

Signed-off-by: Dave Martin <Dave.Martin at arm.com>
[morse: squashed enough of Dave's fixes in here that it's his patch now!]
Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
 drivers/resctrl/mpam_resctrl.c      |   4 +
 drivers/resctrl/test_mpam_resctrl.c | 312 ++++++++++++++++++++++++++++
 2 files changed, 316 insertions(+)
 create mode 100644 drivers/resctrl/test_mpam_resctrl.c

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index e376841c5596..f8d8c241797a 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -1003,3 +1003,7 @@ int mpam_resctrl_setup(void)
 
 	return err;
 }
+
+#ifdef CONFIG_MPAM_KUNIT_TEST
+#include "test_mpam_resctrl.c"
+#endif
diff --git a/drivers/resctrl/test_mpam_resctrl.c b/drivers/resctrl/test_mpam_resctrl.c
new file mode 100644
index 000000000000..d0615aa7671c
--- /dev/null
+++ b/drivers/resctrl/test_mpam_resctrl.c
@@ -0,0 +1,312 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2025 Arm Ltd.
+/* This file is intended to be included into mpam_resctrl.c */
+
+#include <kunit/test.h>
+#include <linux/array_size.h>
+#include <linux/bits.h>
+#include <linux/math.h>
+#include <linux/sprintf.h>
+
+struct percent_value_case {
+	u8	pc;
+	u8	width;
+	u16	value;
+};
+
+/*
+ * Mysterious inscriptions taken from ARM DDI 0598D.b,
+ * "Arm Architecture Reference Manual Supplement - Memory System
+ * Resource Partitioning and Monitoring (MPAM), for A-profile
+ * architecture", Section 9.8, "About the fixed-point fractional
+ * format" (exact percentage entries only):
+ */
+static const struct percent_value_case percent_value_cases[] = {
+	/* Architectural cases: */
+	{   1,  8,    1 },	{   1, 12,  0x27 },	{   1, 16,  0x28e },
+	{  25,  8, 0x3f },	{  25, 12, 0x3ff },	{  25, 16, 0x3fff },
+	{  35,  8, 0x58 },	{  35, 12, 0x598 },	{  35, 16, 0x5998 },
+	{  45,  8, 0x72 },	{  45, 12, 0x732 },	{  45, 16, 0x7332 },
+	{  50,  8, 0x7f },	{  50, 12, 0x7ff },	{  50, 16, 0x7fff },
+	{  52,  8, 0x84 },	{  52, 12, 0x850 },	{  52, 16, 0x851d },
+	{  55,  8, 0x8b },	{  55, 12, 0x8cb },	{  55, 16, 0x8ccb },
+	{  58,  8, 0x93 },	{  58, 12, 0x946 },	{  58, 16, 0x9479 },
+	{  75,  8, 0xbf },	{  75, 12, 0xbff },	{  75, 16, 0xbfff },
+	{  88,  8, 0xe0 },	{  88, 12, 0xe13 },	{  88, 16, 0xe146 },
+	{  95,  8, 0xf2 },	{  95, 12, 0xf32 },	{  95, 16, 0xf332 },
+	{ 100,  8, 0xff },	{ 100, 12, 0xfff },	{ 100, 16, 0xffff },
+
+};
+
+static void test_percent_value_desc(const struct percent_value_case *param,
+				    char *desc)
+{
+	snprintf(desc, KUNIT_PARAM_DESC_SIZE,
+		 "pc=%d, width=%d, value=0x%.*x\n",
+		 param->pc, param->width,
+		 DIV_ROUND_UP(param->width, 4), param->value);
+}
+
+KUNIT_ARRAY_PARAM(test_percent_value, percent_value_cases,
+		  test_percent_value_desc);
+
+struct percent_value_test_info {
+	u32 pc;			/* result of value-to-percent conversion */
+	u32 value;		/* result of percent-to-value conversion */
+	u32 max_value;		/* maximum raw value allowed by test params */
+	unsigned int shift;	/* promotes raw testcase value to 16 bits */
+};
+
+/*
+ * Convert a reference percentage to a fixed-point MAX value and
+ * vice-versa, based on param (not test->param_value!)
+ */
+static void __prepare_percent_value_test(struct kunit *test,
+					 struct percent_value_test_info *res,
+					 const struct percent_value_case *param)
+{
+	struct mpam_props fake_props = { };
+
+	/* Reject bogus test parameters that would break the tests: */
+	KUNIT_ASSERT_GE(test, param->width, 1);
+	KUNIT_ASSERT_LE(test, param->width, 16);
+	KUNIT_ASSERT_LT(test, param->value, 1 << param->width);
+
+	mpam_set_feature(mpam_feat_mbw_max, &fake_props);
+	fake_props.bwa_wd = param->width;
+
+	res->shift = 16 - param->width;
+	res->max_value = GENMASK_U32(param->width - 1, 0);
+	res->value = percent_to_mbw_max(param->pc, &fake_props);
+	res->pc = mbw_max_to_percent(param->value << res->shift, &fake_props);
+}
+
+static void test_get_mba_granularity(struct kunit *test)
+{
+	int ret;
+	struct mpam_props fake_props = { };
+
+	/* Use MBW_MAX */
+	mpam_set_feature(mpam_feat_mbw_max, &fake_props);
+
+	fake_props.bwa_wd = 0;
+	KUNIT_EXPECT_FALSE(test, mba_class_use_mbw_max(&fake_props));
+
+	fake_props.bwa_wd = 1;
+	KUNIT_EXPECT_TRUE(test, mba_class_use_mbw_max(&fake_props));
+
+	/* Architectural maximum: */
+	fake_props.bwa_wd = 16;
+	KUNIT_EXPECT_TRUE(test, mba_class_use_mbw_max(&fake_props));
+
+	/* No usable control... */
+	fake_props.bwa_wd = 0;
+	ret = get_mba_granularity(&fake_props);
+	KUNIT_EXPECT_EQ(test, ret, 0);
+
+	fake_props.bwa_wd = 1;
+	ret = get_mba_granularity(&fake_props);
+	KUNIT_EXPECT_EQ(test, ret, 50);	/* DIV_ROUND_UP(100, 1 << 1)% = 50% */
+
+	fake_props.bwa_wd = 2;
+	ret = get_mba_granularity(&fake_props);
+	KUNIT_EXPECT_EQ(test, ret, 25);	/* DIV_ROUND_UP(100, 1 << 2)% = 25% */
+
+	fake_props.bwa_wd = 3;
+	ret = get_mba_granularity(&fake_props);
+	KUNIT_EXPECT_EQ(test, ret, 13);	/* DIV_ROUND_UP(100, 1 << 3)% = 13% */
+
+	fake_props.bwa_wd = 6;
+	ret = get_mba_granularity(&fake_props);
+	KUNIT_EXPECT_EQ(test, ret, 2);	/* DIV_ROUND_UP(100, 1 << 6)% = 2% */
+
+	fake_props.bwa_wd = 7;
+	ret = get_mba_granularity(&fake_props);
+	KUNIT_EXPECT_EQ(test, ret, 1);	/* DIV_ROUND_UP(100, 1 << 7)% = 1% */
+
+	/* Granularity saturates at 1% */
+	fake_props.bwa_wd = 16; /* architectural maximum */
+	ret = get_mba_granularity(&fake_props);
+	KUNIT_EXPECT_EQ(test, ret, 1);	/* DIV_ROUND_UP(100, 1 << 16)% = 1% */
+}
+
+static void test_mbw_max_to_percent(struct kunit *test)
+{
+	const struct percent_value_case *param = test->param_value;
+	struct percent_value_test_info res;
+
+	/*
+	 * Since the reference values in percent_value_cases[] all
+	 * correspond to exact percentages, round-to-nearest will
+	 * always give the exact percentage back when the MPAM max
+	 * value has precision of 0.5% or finer.  (Always true for the
+	 * reference data, since they all specify 8 bits or more of
+	 * precision.
+	 *
+	 * So, keep it simple and demand an exact match:
+	 */
+	__prepare_percent_value_test(test, &res, param);
+	KUNIT_EXPECT_EQ(test, res.pc, param->pc);
+}
+
+static void test_percent_to_mbw_max(struct kunit *test)
+{
+	const struct percent_value_case *param = test->param_value;
+	struct percent_value_test_info res;
+
+	__prepare_percent_value_test(test, &res, param);
+
+	KUNIT_EXPECT_GE(test, res.value, param->value << res.shift);
+	KUNIT_EXPECT_LE(test, res.value, (param->value + 1) << res.shift);
+	KUNIT_EXPECT_LE(test, res.value, res.max_value << res.shift);
+
+	/* No flexibility allowed for 0% and 100%! */
+
+	if (param->pc == 0)
+		KUNIT_EXPECT_EQ(test, res.value, 0);
+
+	if (param->pc == 100)
+		KUNIT_EXPECT_EQ(test, res.value, res.max_value << res.shift);
+}
+
+static const void *test_all_bwa_wd_gen_params(struct kunit *test, const void *prev,
+					      char *desc)
+{
+	uintptr_t param = (uintptr_t)prev;
+
+	if (param > 15)
+		return NULL;
+
+	param++;
+
+	snprintf(desc, KUNIT_PARAM_DESC_SIZE, "wd=%u\n", (unsigned int)param);
+
+	return (void *)param;
+}
+
+static unsigned int test_get_bwa_wd(struct kunit *test)
+{
+	uintptr_t param = (uintptr_t)test->param_value;
+
+	KUNIT_ASSERT_GE(test, param, 1);
+	KUNIT_ASSERT_LE(test, param, 16);
+
+	return param;
+}
+
+static void test_mbw_max_to_percent_limits(struct kunit *test)
+{
+	struct mpam_props fake_props = {0};
+	u32 max_value;
+
+	mpam_set_feature(mpam_feat_mbw_max, &fake_props);
+	fake_props.bwa_wd = test_get_bwa_wd(test);
+	max_value = GENMASK(15, 16 - fake_props.bwa_wd);
+
+	KUNIT_EXPECT_EQ(test, mbw_max_to_percent(max_value, &fake_props),
+			MAX_MBA_BW);
+	KUNIT_EXPECT_EQ(test, mbw_max_to_percent(0, &fake_props),
+			get_mba_min(&fake_props));
+
+	/*
+	 * Rounding policy dependent 0% sanity-check:
+	 * With round-to-nearest, the minimum mbw_max value really
+	 * should map to 0% if there are at least 200 steps.
+	 * (100 steps may be enough for some other rounding policies.)
+	 */
+	if (fake_props.bwa_wd >= 8)
+		KUNIT_EXPECT_EQ(test, mbw_max_to_percent(0, &fake_props), 0);
+
+	if (fake_props.bwa_wd < 8 &&
+	    mbw_max_to_percent(0, &fake_props) == 0)
+		kunit_warn(test, "wd=%d: Testsuite/driver Rounding policy mismatch?",
+			   fake_props.bwa_wd);
+}
+
+/*
+ * Check that converting a percentage to mbw_max and back again (or, as
+ * appropriate, vice-versa) always restores the original value:
+ */
+static void test_percent_max_roundtrip_stability(struct kunit *test)
+{
+	struct mpam_props fake_props = {0};
+	unsigned int shift;
+	u32 pc, max, pc2, max2;
+
+	mpam_set_feature(mpam_feat_mbw_max, &fake_props);
+	fake_props.bwa_wd = test_get_bwa_wd(test);
+	shift = 16 - fake_props.bwa_wd;
+
+	/*
+	 * Converting a valid value from the coarser scale to the finer
+	 * scale and back again must yield the original value:
+	 */
+	if (fake_props.bwa_wd >= 7) {
+		/* More than 100 steps: only test exact pc values: */
+		for (pc = get_mba_min(&fake_props); pc <= MAX_MBA_BW; pc++) {
+			max = percent_to_mbw_max(pc, &fake_props);
+			pc2 = mbw_max_to_percent(max, &fake_props);
+			KUNIT_EXPECT_EQ(test, pc2, pc);
+		}
+	} else {
+		/* Fewer than 100 steps: only test exact mbw_max values: */
+		for (max = 0; max < 1 << 16; max += 1 << shift) {
+			pc = mbw_max_to_percent(max, &fake_props);
+			max2 = percent_to_mbw_max(pc, &fake_props);
+			KUNIT_EXPECT_EQ(test, max2, max);
+		}
+	}
+}
+
+static void test_percent_to_max_rounding(struct kunit *test)
+{
+	const struct percent_value_case *param = test->param_value;
+	unsigned int num_rounded_up = 0, total = 0;
+	struct percent_value_test_info res;
+
+	for (param = percent_value_cases, total = 0;
+	     param < &percent_value_cases[ARRAY_SIZE(percent_value_cases)];
+	     param++, total++) {
+		__prepare_percent_value_test(test, &res, param);
+		if (res.value > param->value << res.shift)
+			num_rounded_up++;
+	}
+
+	/*
+	 * The MPAM driver applies a round-to-nearest policy, whereas a
+	 * round-down policy seems to have been applied in the
+	 * reference table from which the test vectors were selected.
+	 *
+	 * For a large and well-distributed suite of test vectors,
+	 * about half should be rounded up and half down compared with
+	 * the reference table.  The actual test vectors are few in
+	 * number and probably not very well distributed however, so
+	 * tolerate a round-up rate of between 1/4 and 3/4 before
+	 * crying foul:
+	 */
+
+	kunit_info(test, "Round-up rate: %u%% (%u/%u)\n",
+		   DIV_ROUND_CLOSEST(num_rounded_up * 100, total),
+		   num_rounded_up, total);
+
+	KUNIT_EXPECT_GE(test, 4 * num_rounded_up, 1 * total);
+	KUNIT_EXPECT_LE(test, 4 * num_rounded_up, 3 * total);
+}
+
+static struct kunit_case mpam_resctrl_test_cases[] = {
+	KUNIT_CASE(test_get_mba_granularity),
+	KUNIT_CASE_PARAM(test_mbw_max_to_percent, test_percent_value_gen_params),
+	KUNIT_CASE_PARAM(test_percent_to_mbw_max, test_percent_value_gen_params),
+	KUNIT_CASE_PARAM(test_mbw_max_to_percent_limits, test_all_bwa_wd_gen_params),
+	KUNIT_CASE(test_percent_to_max_rounding),
+	KUNIT_CASE_PARAM(test_percent_max_roundtrip_stability,
+			 test_all_bwa_wd_gen_params),
+	{}
+};
+
+static struct kunit_suite mpam_resctrl_test_suite = {
+	.name = "mpam_resctrl_test_suite",
+	.test_cases = mpam_resctrl_test_cases,
+};
+
+kunit_test_suites(&mpam_resctrl_test_suite);
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:29 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:29 +0000
Subject: [PATCH v2 27/45] arm_mpam: resctrl: Add support for csu counters
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-28-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

resctrl exposes a counter via a file named llc_occupancy. This isn't really
a counter as its value goes up and down, this is a snapshot of the cache
storage usage monitor.

Add some picking code to find a cache as close as possible to the L3 that
supports the CSU monitor.

If there is an L3, but it doesn't have any controls, force the L3 resource
to exist. The existing topology_matches_l3() and
mpam_resctrl_domain_hdr_init() code will ensure this looks like the L3,
even if the class belongs to a later cache.

Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
Changes since rfc:
Allow csu counters however many partid or pmg there are
else if -> if
reduce scope of local variables
drop has_csu
---
 drivers/resctrl/mpam_internal.h |   6 ++
 drivers/resctrl/mpam_resctrl.c  | 148 ++++++++++++++++++++++++++++++++
 2 files changed, 154 insertions(+)

diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index b9a739abb101..9cb9eb97893b 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -345,6 +345,12 @@ struct mpam_resctrl_res {
 	struct rdt_resource	resctrl_res;
 };
 
+struct mpam_resctrl_mon {
+	struct mpam_class	*class;
+
+	/* per-class data that resctrl needs will live here */
+};
+
 static inline int mpam_alloc_csu_mon(struct mpam_class *class)
 {
 	struct mpam_props *cprops = &class->props;
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index f8d8c241797a..5fde610cc9d7 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -31,6 +31,16 @@ static struct mpam_resctrl_res mpam_resctrl_controls[RDT_NUM_RESOURCES];
 /* The lock for modifying resctrl's domain lists from cpuhp callbacks. */
 static DEFINE_MUTEX(domain_list_lock);
 
+/*
+ * The classes we've picked to map to resctrl events.
+ * Resctrl believes all the worlds a Xeon, and these are all on the L3. This
+ * array lets us find the actual class backing the event counters. e.g.
+ * the only memory bandwidth counters may be on the memory controller, but to
+ * make use of them, we pretend they are on L3.
+ * Class pointer may be NULL.
+ */
+static struct mpam_resctrl_mon mpam_resctrl_counters[QOS_NUM_EVENTS];
+
 static bool exposed_alloc_capable;
 static bool exposed_mon_capable;
 
@@ -258,6 +268,28 @@ static bool class_has_usable_mba(struct mpam_props *cprops)
 	return mba_class_use_mbw_max(cprops);
 }
 
+static bool cache_has_usable_csu(struct mpam_class *class)
+{
+	struct mpam_props *cprops;
+
+	if (!class)
+		return false;
+
+	cprops = &class->props;
+
+	if (!mpam_has_feature(mpam_feat_msmon_csu, cprops))
+		return false;
+
+	/*
+	 * CSU counters settle on the value, so we can get away with
+	 * having only one.
+	 */
+	if (!cprops->num_csu_mon)
+		return false;
+
+	return true;
+}
+
 /*
  * Calculate the worst-case percentage change from each implemented step
  * in the control.
@@ -498,6 +530,64 @@ static void mpam_resctrl_pick_mba(void)
 	}
 }
 
+static void counter_update_class(enum resctrl_event_id evt_id,
+				 struct mpam_class *class)
+{
+	struct mpam_class *existing_class = mpam_resctrl_counters[evt_id].class;
+
+	if (existing_class) {
+		if (class->level == 3) {
+			pr_debug("Existing class is L3 - L3 wins\n");
+			return;
+		}
+
+		if (existing_class->level < class->level) {
+			pr_debug("Existing class is closer to L3, %u versus %u - closer is better\n",
+				 existing_class->level, class->level);
+			return;
+		}
+	}
+
+	mpam_resctrl_counters[evt_id].class = class;
+	exposed_mon_capable = true;
+}
+
+static void mpam_resctrl_pick_counters(void)
+{
+	struct mpam_class *class;
+
+	lockdep_assert_cpus_held();
+
+	guard(srcu)(&mpam_srcu);
+	list_for_each_entry_srcu(class, &mpam_classes, classes_list,
+				 srcu_read_lock_held(&mpam_srcu)) {
+		if (class->level < 3) {
+			pr_debug("class %u is before L3", class->level);
+			continue;
+		}
+
+		if (!cpumask_equal(&class->affinity, cpu_possible_mask)) {
+			pr_debug("class %u does not cover all CPUs",
+				 class->level);
+			continue;
+		}
+
+		if (cache_has_usable_csu(class) && topology_matches_l3(class)) {
+			pr_debug("class %u has usable CSU, and matches L3 topology",
+				 class->level);
+
+			/* CSU counters only make sense on a cache. */
+			switch (class->type) {
+			case MPAM_CLASS_CACHE:
+				counter_update_class(QOS_L3_OCCUP_EVENT_ID, class);
+				return;
+			default:
+				return;
+			}
+		}
+	}
+}
+
 static int mpam_resctrl_control_init(struct mpam_resctrl_res *res,
 				     enum resctrl_res_level type)
 {
@@ -577,6 +667,50 @@ static int mpam_resctrl_pick_domain_id(int cpu, struct mpam_component *comp)
 	return comp->comp_id;
 }
 
+static void mpam_resctrl_monitor_init(struct mpam_resctrl_mon *mon,
+				      enum resctrl_event_id type)
+{
+	struct mpam_resctrl_res *res = &mpam_resctrl_controls[RDT_RESOURCE_L3];
+	struct rdt_resource *l3 = &res->resctrl_res;
+
+	lockdep_assert_cpus_held();
+
+	/* There also needs to be an L3 cache present */
+	if (get_cpu_cacheinfo_id(smp_processor_id(), 3) == -1)
+		return;
+
+	/*
+	 * If there are no MPAM resources on L3, force it into existence.
+	 * topology_matches_l3() already ensures this looks like the L3.
+	 * The domain-ids will be fixed up by mpam_resctrl_domain_hdr_init().
+	 */
+	if (!res->class) {
+		pr_warn_once("Faking L3 MSC to enable counters.\n");
+		res->class = mpam_resctrl_counters[type].class;
+	}
+
+	/* Called multiple times!, once per event type */
+	if (exposed_mon_capable) {
+		l3->mon_capable = true;
+
+		/* Setting name is necessary on monitor only platforms */
+		l3->name = "L3";
+		l3->mon_scope = RESCTRL_L3_CACHE;
+
+		resctrl_enable_mon_event(type);
+
+		/*
+		 * Unfortunately, num_rmid doesn't mean anything for
+		 * mpam, and its exposed to user-space!
+		 * num-rmid is supposed to mean the number of groups
+		 * that can be created, both control or monitor groups.
+		 * For mpam, each control group has its own pmg/rmid
+		 * space.
+		 */
+		l3->mon.num_rmid = 1;
+	}
+}
+
 u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 			    u32 closid, enum resctrl_conf_type type)
 {
@@ -977,6 +1111,20 @@ int mpam_resctrl_setup(void)
 			break;
 		}
 	}
+
+	/* Find some classes to use for monitors */
+	mpam_resctrl_pick_counters();
+
+	for (enum resctrl_event_id j = 0; j < QOS_NUM_EVENTS; j++) {
+		struct mpam_resctrl_mon *mon;
+
+		mon = &mpam_resctrl_counters[j];
+		if (!mon->class)
+			continue;	// dummy resource
+
+		mpam_resctrl_monitor_init(mon, j);
+	}
+
 	cpus_read_unlock();
 
 	if (err) {
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:30 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:30 +0000
Subject: [PATCH v2 28/45] arm_mpam: resctrl: Pick classes for use as mbm counters
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-29-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

resctrl has two types of counters, NUMA-local and global. MPAM has only
bandwidth counters, but the position of the MSC may mean it counts
NUMA-local, or global traffic.

But the topology information is not available.

Apply a heuristic: the L2 or L3 supports bandwidth monitors, these are
probably NUMA-local. If the memory controller supports bandwidth monitors,
they are probably global.

This also allows us to assert that we don't have the same class backing two
different resctrl events.

Because the class or component backing the event may not be 'the L3', it is
necessary for mpam_resctrl_get_domain_from_cpu() to search the monitor
domains too. This matters the most for 'monitor only' systems, where 'the
L3' control domains may be empty, and the ctrl_comp pointer NULL.

resctrl expects there to be enough monitors for every possible control and
monitor group to have one. Such a system gets called 'free running' as the
monitors can be programmed once and left running.  Any other platform will
need to emulate ABMC.

Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
Changes since rfc:
drop has_mbwu
---
 drivers/resctrl/mpam_internal.h |   8 ++
 drivers/resctrl/mpam_resctrl.c  | 136 +++++++++++++++++++++++++++++++-
 2 files changed, 142 insertions(+), 2 deletions(-)

diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index 9cb9eb97893b..6a2231b28cad 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -336,6 +336,14 @@ struct mpam_msc_ris {
 
 struct mpam_resctrl_dom {
 	struct mpam_component	*ctrl_comp;
+
+	/*
+	 * There is no single mon_comp because different events may be backed
+	 * by different class/components. mon_comp is indexed by the event
+	 * number.
+	 */
+	struct mpam_component   *mon_comp[QOS_NUM_EVENTS];
+
 	struct rdt_ctrl_domain	resctrl_ctrl_dom;
 	struct rdt_mon_domain	resctrl_mon_dom;
 };
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 5fde610cc9d7..51caf3b82392 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -50,6 +50,14 @@ static bool exposed_mon_capable;
  */
 static bool cdp_enabled;
 
+/* Whether this num_mbw_mon could result in a free_running system */
+static int __mpam_monitors_free_running(u16 num_mbwu_mon)
+{
+	if (num_mbwu_mon >= resctrl_arch_system_num_rmid_idx())
+		return resctrl_arch_system_num_rmid_idx();
+	return 0;
+}
+
 bool resctrl_arch_alloc_capable(void)
 {
 	return exposed_alloc_capable;
@@ -290,6 +298,26 @@ static bool cache_has_usable_csu(struct mpam_class *class)
 	return true;
 }
 
+static bool class_has_usable_mbwu(struct mpam_class *class)
+{
+	struct mpam_props *cprops = &class->props;
+
+	if (!mpam_has_feature(mpam_feat_msmon_mbwu, cprops))
+		return false;
+
+	/*
+	 * resctrl expects the bandwidth counters to be free running,
+	 * which means we need as many monitors as resctrl has
+	 * control/monitor groups.
+	 */
+	if (__mpam_monitors_free_running(cprops->num_mbwu_mon)) {
+		pr_debug("monitors usable in free-running mode\n");
+		return true;
+	}
+
+	return false;
+}
+
 /*
  * Calculate the worst-case percentage change from each implemented step
  * in the control.
@@ -585,7 +613,36 @@ static void mpam_resctrl_pick_counters(void)
 				return;
 			}
 		}
+
+		if (class_has_usable_mbwu(class) && topology_matches_l3(class)) {
+			pr_debug("class %u has usable MBWU, and matches L3 topology",
+				 class->level);
+
+			/*
+			 * MBWU counters may be 'local' or 'total' depending on
+			 * where they are in the topology. Counters on caches
+			 * are assumed to be local. If it's on the memory
+			 * controller, its assumed to be global.
+			 */
+			switch (class->type) {
+			case MPAM_CLASS_CACHE:
+				counter_update_class(QOS_L3_MBM_LOCAL_EVENT_ID,
+						     class);
+				break;
+			case MPAM_CLASS_MEMORY:
+				counter_update_class(QOS_L3_MBM_TOTAL_EVENT_ID,
+						     class);
+				break;
+			default:
+				break;
+			}
+		}
 	}
+
+	/* Allocation of MBWU monitors assumes that the class is unique... */
+	if (mpam_resctrl_counters[QOS_L3_MBM_LOCAL_EVENT_ID].class)
+		WARN_ON_ONCE(mpam_resctrl_counters[QOS_L3_MBM_LOCAL_EVENT_ID].class ==
+			     mpam_resctrl_counters[QOS_L3_MBM_TOTAL_EVENT_ID].class);
 }
 
 static int mpam_resctrl_control_init(struct mpam_resctrl_res *res,
@@ -925,6 +982,20 @@ static void mpam_resctrl_domain_insert(struct list_head *list,
 	list_add_tail_rcu(&new->list, pos);
 }
 
+static struct mpam_component *find_component(struct mpam_class *victim, int cpu)
+{
+	struct mpam_component *victim_comp;
+
+	guard(srcu)(&mpam_srcu);
+	list_for_each_entry_srcu(victim_comp, &victim->components, class_list,
+				 srcu_read_lock_held(&mpam_srcu)) {
+		if (cpumask_test_cpu(cpu, &victim_comp->affinity))
+			return victim_comp;
+	}
+
+	return NULL;
+}
+
 static struct mpam_resctrl_dom *
 mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
 {
@@ -973,8 +1044,32 @@ mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
 	}
 
 	if (exposed_mon_capable) {
+		int i;
+		struct mpam_component *mon_comp, *any_mon_comp;
+
+		/*
+		 * Even if the monitor domain is backed by a different
+		 * component, the L3 component IDs need to be used... only
+		 * there may be no ctrl_comp for the L3.
+		 * Search each event's class list for a component with
+		 * overlapping CPUs and set up the dom->mon_comp array.
+		 */
+		for (i = 0; i < QOS_NUM_EVENTS; i++) {
+			struct mpam_resctrl_mon *mon;
+
+			mon = &mpam_resctrl_counters[i];
+			if (!mon->class)
+				continue;       // dummy resource
+
+			mon_comp = find_component(mon->class, cpu);
+			dom->mon_comp[i] = mon_comp;
+			if (mon_comp)
+				any_mon_comp = mon_comp;
+		}
+		WARN_ON_ONCE(!any_mon_comp);
+
 		mon_d = &dom->resctrl_mon_dom;
-		mpam_resctrl_domain_hdr_init(cpu, ctrl_comp, &mon_d->hdr);
+		mpam_resctrl_domain_hdr_init(cpu, any_mon_comp, &mon_d->hdr);
 		mon_d->hdr.type = RESCTRL_MON_DOMAIN;
 		mpam_resctrl_domain_insert(&r->mon_domains, &mon_d->hdr);
 		err = resctrl_online_mon_domain(r, mon_d);
@@ -996,6 +1091,39 @@ mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
 	return dom;
 }
 
+/*
+ * We know all the monitors are associated with the L3, even if there are no
+ * controls and therefore no control component. Find the cache-id for the CPU
+ * and use that to search for existing resctrl domains.
+ * This relies on mpam_resctrl_pick_domain_id() using the L3 cache-id
+ * for anything that is not a cache.
+ */
+static struct mpam_resctrl_dom *mpam_resctrl_get_mon_domain_from_cpu(int cpu)
+{
+	u32 cache_id;
+	struct rdt_mon_domain *mon_d;
+	struct mpam_resctrl_dom *dom;
+	struct mpam_resctrl_res *l3 = &mpam_resctrl_controls[RDT_RESOURCE_L3];
+
+	lockdep_assert_cpus_held();
+
+	if (!l3->class)
+		return NULL;
+	/* TODO: how does this order with cacheinfo updates under cpuhp? */
+	cache_id = get_cpu_cacheinfo_id(cpu, 3);
+	if (cache_id == ~0)
+		return NULL;
+
+	list_for_each_entry_rcu(mon_d, &l3->resctrl_res.mon_domains, hdr.list) {
+		dom = container_of(mon_d, struct mpam_resctrl_dom, resctrl_mon_dom);
+
+		if (mon_d->hdr.id == cache_id)
+			return dom;
+	}
+
+	return NULL;
+}
+
 static struct mpam_resctrl_dom *
 mpam_resctrl_get_domain_from_cpu(int cpu, struct mpam_resctrl_res *res)
 {
@@ -1013,7 +1141,11 @@ mpam_resctrl_get_domain_from_cpu(int cpu, struct mpam_resctrl_res *res)
 			return dom;
 	}
 
-	return NULL;
+	if (r->rid != RDT_RESOURCE_L3)
+		return NULL;
+
+	/* Search the mon domain list too - needed on monitor only platforms. */
+	return mpam_resctrl_get_mon_domain_from_cpu(cpu);
 }
 
 int mpam_resctrl_online_cpu(unsigned int cpu)
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:31 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:31 +0000
Subject: [PATCH v2 29/45] arm_mpam: resctrl: Pre-allocate free running monitors
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-30-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

When there are enough monitors, the resctrl mbm local and total files can
be exposed. These need all the monitors that resctrl may use to be
allocated up front.

Add helpers to do this.

If a different candidate class is discovered, the old array should be
free'd and the allocated monitors returned to the driver.

Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
 drivers/resctrl/mpam_internal.h |  8 +++-
 drivers/resctrl/mpam_resctrl.c  | 84 ++++++++++++++++++++++++++++++++-
 2 files changed, 89 insertions(+), 3 deletions(-)

diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index 6a2231b28cad..c25524f75c2e 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -356,7 +356,13 @@ struct mpam_resctrl_res {
 struct mpam_resctrl_mon {
 	struct mpam_class	*class;
 
-	/* per-class data that resctrl needs will live here */
+	/*
+	 * Array of allocated MBWU monitors, indexed by (closid, rmid).
+	 * When ABMC is not in use, this array directly maps (closid, rmid)
+	 * to the allocated monitor. Otherwise this array is sparse, and
+	 * un-assigned (closid, rmid) are -1.
+	 */
+	int			*mbwu_idx_to_mon;
 };
 
 static inline int mpam_alloc_csu_mon(struct mpam_class *class)
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 51caf3b82392..bea16bc096f7 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -558,10 +558,58 @@ static void mpam_resctrl_pick_mba(void)
 	}
 }
 
+static void __free_mbwu_mon(struct mpam_class *class, int *array,
+			    u16 num_mbwu_mon)
+{
+	for (int i = 0; i < num_mbwu_mon; i++) {
+		if (array[i] < 0)
+			continue;
+
+		mpam_free_mbwu_mon(class, array[i]);
+		array[i] = ~0;
+	}
+}
+
+static int __alloc_mbwu_mon(struct mpam_class *class, int *array,
+			    u16 num_mbwu_mon)
+{
+	for (int i = 0; i < num_mbwu_mon; i++) {
+		int mbwu_mon = mpam_alloc_mbwu_mon(class);
+
+		if (mbwu_mon < 0) {
+			__free_mbwu_mon(class, array, num_mbwu_mon);
+			return mbwu_mon;
+		}
+		array[i] = mbwu_mon;
+	}
+
+	return 0;
+}
+
+static int *__alloc_mbwu_array(struct mpam_class *class, u16 num_mbwu_mon)
+{
+	int err;
+	size_t array_size = num_mbwu_mon * sizeof(int);
+	int *array __free(kfree) = kmalloc(array_size, GFP_KERNEL);
+
+	if (!array)
+		return ERR_PTR(-ENOMEM);
+
+	memset(array, -1, array_size);
+
+	err = __alloc_mbwu_mon(class, array, num_mbwu_mon);
+	if (err)
+		return ERR_PTR(err);
+	return_ptr(array);
+}
+
 static void counter_update_class(enum resctrl_event_id evt_id,
 				 struct mpam_class *class)
 {
-	struct mpam_class *existing_class = mpam_resctrl_counters[evt_id].class;
+	struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[evt_id];
+	struct mpam_class *existing_class = mon->class;
+	u16 num_mbwu_mon = class->props.num_mbwu_mon;
+	int *existing_array = mon->mbwu_idx_to_mon;
 
 	if (existing_class) {
 		if (class->level == 3) {
@@ -576,8 +624,40 @@ static void counter_update_class(enum resctrl_event_id evt_id,
 		}
 	}
 
-	mpam_resctrl_counters[evt_id].class = class;
+	pr_debug("Updating event %u to use class %u\n", evt_id, class->level);
+	mon->class = class;
 	exposed_mon_capable = true;
+
+	if (evt_id == QOS_L3_OCCUP_EVENT_ID)
+		return;
+
+	/* Might not need all the monitors */
+	num_mbwu_mon = __mpam_monitors_free_running(num_mbwu_mon);
+	if (!num_mbwu_mon) {
+		pr_debug("Not pre-allocating free-running counters\n");
+		return;
+	}
+
+	/*
+	 * This is the pre-allocated free-running monitors path. It always
+	 * allocates one monitor per PARTID * PMG.
+	 */
+	WARN_ON_ONCE(num_mbwu_mon != resctrl_arch_system_num_rmid_idx());
+
+	mon->mbwu_idx_to_mon = __alloc_mbwu_array(class, num_mbwu_mon);
+	if (IS_ERR(mon->mbwu_idx_to_mon)) {
+		pr_debug("Failed to allocate MBWU array\n");
+		mon->class = existing_class;
+		mon->mbwu_idx_to_mon = existing_array;
+		return;
+	}
+
+	if (existing_array) {
+		pr_debug("Releasing previous class %u's monitors\n",
+			 existing_class->level);
+		__free_mbwu_mon(existing_class, existing_array, num_mbwu_mon);
+		kfree(existing_array);
+	}
 }
 
 static void mpam_resctrl_pick_counters(void)
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:32 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:32 +0000
Subject: [PATCH v2 30/45] arm_mpam: resctrl: Pre-allocate assignable monitors
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-31-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

When there are not enough monitors, MPAM is able to emulate ABMC by making
a smaller number of monitors assignable. These monitors still need to be
allocated from the driver, and mapped to whichever control/monitor group
resctrl wants to use them with.

Add a second array to hold the monitor values indexed by resctrl's cntr_id.

When CDP is in use, two monitors are needed so the available number of
counters halves. Platforms with one monitor will have zero monitors when
CDP is in use.

Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
Changes since rfc:
Move __free
kmalloc -> kcalloc
---
 drivers/resctrl/mpam_internal.h |   7 +++
 drivers/resctrl/mpam_resctrl.c  | 103 ++++++++++++++++++++++++++++++++
 2 files changed, 110 insertions(+)

diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index c25524f75c2e..a2f6956d9236 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -363,6 +363,13 @@ struct mpam_resctrl_mon {
 	 * un-assigned (closid, rmid) are -1.
 	 */
 	int			*mbwu_idx_to_mon;
+
+	/*
+	 * Array of assigned MBWU monitors, indexed by idx argument.
+	 * When ABMC is not in use, this array can be NULL. Otherwise
+	 * it maps idx to the allocated monitor.
+	 */
+	int			*assigned_counters;
 };
 
 static inline int mpam_alloc_csu_mon(struct mpam_class *class)
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index bea16bc096f7..e96d320c219c 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -50,6 +50,12 @@ static bool exposed_mon_capable;
  */
 static bool cdp_enabled;
 
+/*
+ * L3 local/total may come from different classes - what is the number of MBWU
+ * 'on L3'?
+ */
+static unsigned int l3_num_allocated_mbwu = ~0;
+
 /* Whether this num_mbw_mon could result in a free_running system */
 static int __mpam_monitors_free_running(u16 num_mbwu_mon)
 {
@@ -58,6 +64,15 @@ static int __mpam_monitors_free_running(u16 num_mbwu_mon)
 	return 0;
 }
 
+/*
+ * If l3_num_allocated_mbwu is forced below PARTID * PMG, then the counters
+ * are not free running, and ABMC's user-interface must be used to assign them.
+ */
+static bool mpam_resctrl_abmc_enabled(void)
+{
+	return l3_num_allocated_mbwu < resctrl_arch_system_num_rmid_idx();
+}
+
 bool resctrl_arch_alloc_capable(void)
 {
 	return exposed_alloc_capable;
@@ -102,9 +117,26 @@ static void resctrl_reset_task_closids(void)
 	read_unlock(&tasklist_lock);
 }
 
+static void mpam_resctrl_monitor_sync_abmc_vals(struct rdt_resource *l3)
+{
+	l3->mon.num_mbm_cntrs = l3_num_allocated_mbwu;
+	if (cdp_enabled)
+		l3->mon.num_mbm_cntrs /= 2;
+
+	if (l3->mon.num_mbm_cntrs) {
+		l3->mon.mbm_cntr_assignable = mpam_resctrl_abmc_enabled();
+		l3->mon.mbm_assign_on_mkdir = mpam_resctrl_abmc_enabled();
+	} else {
+		l3->mon.mbm_cntr_assignable = false;
+		l3->mon.mbm_assign_on_mkdir = false;
+	}
+}
+
 int resctrl_arch_set_cdp_enabled(enum resctrl_res_level ignored, bool enable)
 {
 	u32 partid_i = RESCTRL_RESERVED_CLOSID, partid_d = RESCTRL_RESERVED_CLOSID;
+	struct mpam_resctrl_res *res = &mpam_resctrl_controls[RDT_RESOURCE_L3];
+	struct rdt_resource *l3 = &res->resctrl_res;
 
 	cdp_enabled = enable;
 
@@ -120,6 +152,7 @@ int resctrl_arch_set_cdp_enabled(enum resctrl_res_level ignored, bool enable)
 	WRITE_ONCE(arm64_mpam_global_default, mpam_get_regval(current));
 
 	resctrl_reset_task_closids();
+	mpam_resctrl_monitor_sync_abmc_vals(l3);
 
 	return 0;
 }
@@ -315,6 +348,11 @@ static bool class_has_usable_mbwu(struct mpam_class *class)
 		return true;
 	}
 
+	if (cprops->num_mbwu_mon) {
+		pr_debug("monitors usable via ABMC assignment\n");
+		return true;
+	}
+
 	return false;
 }
 
@@ -583,6 +621,8 @@ static int __alloc_mbwu_mon(struct mpam_class *class, int *array,
 		array[i] = mbwu_mon;
 	}
 
+	l3_num_allocated_mbwu = min(l3_num_allocated_mbwu, num_mbwu_mon);
+
 	return 0;
 }
 
@@ -725,6 +765,23 @@ static void mpam_resctrl_pick_counters(void)
 			     mpam_resctrl_counters[QOS_L3_MBM_TOTAL_EVENT_ID].class);
 }
 
+bool resctrl_arch_mbm_cntr_assign_enabled(struct rdt_resource *r)
+{
+	if (r != &mpam_resctrl_controls[RDT_RESOURCE_L3].resctrl_res)
+		return false;
+
+	return mpam_resctrl_abmc_enabled();
+}
+
+int resctrl_arch_mbm_cntr_assign_set(struct rdt_resource *r, bool enable)
+{
+	lockdep_assert_cpus_held();
+
+	WARN_ON_ONCE(1);
+
+	return 0;
+}
+
 static int mpam_resctrl_control_init(struct mpam_resctrl_res *res,
 				     enum resctrl_res_level type)
 {
@@ -804,6 +861,42 @@ static int mpam_resctrl_pick_domain_id(int cpu, struct mpam_component *comp)
 	return comp->comp_id;
 }
 
+/*
+ * This must run after all event counters have been picked so that any free
+ * running counters have already been allocated.
+ */
+static int mpam_resctrl_monitor_init_abmc(struct mpam_resctrl_mon *mon)
+{
+	struct mpam_resctrl_res *res = &mpam_resctrl_controls[RDT_RESOURCE_L3];
+	struct rdt_resource *l3 = &res->resctrl_res;
+	struct mpam_class *class = mon->class;
+	u16 num_mbwu_mon;
+
+	if (mon->mbwu_idx_to_mon) {
+		pr_debug("monitors free running\n");
+		return 0;
+	}
+
+	int *rmid_array __free(kfree) =
+		kcalloc(resctrl_arch_system_num_rmid_idx(), sizeof(int), GFP_KERNEL);
+
+	if (!rmid_array) {
+		pr_debug("Failed to allocate RMID array\n");
+		return -ENOMEM;
+	}
+	memset(rmid_array, -1, resctrl_arch_system_num_rmid_idx() * sizeof(int));
+
+	num_mbwu_mon = class->props.num_mbwu_mon;
+	mon->assigned_counters = __alloc_mbwu_array(mon->class, num_mbwu_mon);
+	if (IS_ERR(mon->assigned_counters))
+		return PTR_ERR(mon->assigned_counters);
+	mon->mbwu_idx_to_mon = no_free_ptr(rmid_array);
+
+	mpam_resctrl_monitor_sync_abmc_vals(l3);
+
+	return 0;
+}
+
 static void mpam_resctrl_monitor_init(struct mpam_resctrl_mon *mon,
 				      enum resctrl_event_id type)
 {
@@ -845,6 +938,16 @@ static void mpam_resctrl_monitor_init(struct mpam_resctrl_mon *mon,
 		 * space.
 		 */
 		l3->mon.num_rmid = 1;
+
+		switch (type) {
+		case QOS_L3_MBM_LOCAL_EVENT_ID:
+		case QOS_L3_MBM_TOTAL_EVENT_ID:
+			mpam_resctrl_monitor_init_abmc(mon);
+
+			return;
+		default:
+			return;
+		}
 	}
 }
 
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:33 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:33 +0000
Subject: [PATCH v2 31/45] arm_mpam: resctrl: Add kunit test for ABMC/CDP interactions
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-32-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

ABMC exposes a fun corner case where a platform with one monitor can use
ABMC for assignable counters - but not when CDP is enabled.

Add some tests.

Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
 drivers/resctrl/test_mpam_resctrl.c | 62 +++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)

diff --git a/drivers/resctrl/test_mpam_resctrl.c b/drivers/resctrl/test_mpam_resctrl.c
index d0615aa7671c..c83d54f21fa0 100644
--- a/drivers/resctrl/test_mpam_resctrl.c
+++ b/drivers/resctrl/test_mpam_resctrl.c
@@ -293,6 +293,67 @@ static void test_percent_to_max_rounding(struct kunit *test)
 	KUNIT_EXPECT_LE(test, 4 * num_rounded_up, 3 * total);
 }
 
+static void test_num_assignable_counters(struct kunit *test)
+{
+	unsigned int orig_l3_num_allocated_mbwu = l3_num_allocated_mbwu;
+	u32 orig_mpam_partid_max = mpam_partid_max;
+	u32 orig_mpam_pmg_max = mpam_pmg_max;
+	bool orig_cdp_enabled = cdp_enabled;
+	struct rdt_resource fake_l3;
+
+	/* Force there to be some PARTID/PMG */
+	mpam_partid_max = 3;
+	mpam_pmg_max = 1;
+
+	cdp_enabled = false;
+
+	/* ABMC off, CDP off */
+	l3_num_allocated_mbwu = resctrl_arch_system_num_rmid_idx();
+	mpam_resctrl_monitor_sync_abmc_vals(&fake_l3);
+	KUNIT_EXPECT_EQ(test, fake_l3.mon.num_mbm_cntrs, resctrl_arch_system_num_rmid_idx());
+	KUNIT_EXPECT_FALSE(test, fake_l3.mon.mbm_cntr_assignable);
+	KUNIT_EXPECT_FALSE(test, fake_l3.mon.mbm_assign_on_mkdir);
+
+	/* ABMC on, CDP off */
+	l3_num_allocated_mbwu = 4;
+	mpam_resctrl_monitor_sync_abmc_vals(&fake_l3);
+	KUNIT_EXPECT_EQ(test, fake_l3.mon.num_mbm_cntrs, 4);
+	KUNIT_EXPECT_TRUE(test, fake_l3.mon.mbm_cntr_assignable);
+	KUNIT_EXPECT_TRUE(test, fake_l3.mon.mbm_assign_on_mkdir);
+
+	cdp_enabled = true;
+
+	/* ABMC off, CDP on */
+	l3_num_allocated_mbwu = resctrl_arch_system_num_rmid_idx();
+	mpam_resctrl_monitor_sync_abmc_vals(&fake_l3);
+
+	/* (value not consumed by resctrl) */
+	KUNIT_EXPECT_EQ(test, fake_l3.mon.num_mbm_cntrs, resctrl_arch_system_num_rmid_idx() / 2);
+
+	KUNIT_EXPECT_FALSE(test, fake_l3.mon.mbm_cntr_assignable);
+	KUNIT_EXPECT_FALSE(test, fake_l3.mon.mbm_assign_on_mkdir);
+
+	/* ABMC on, CDP on */
+	l3_num_allocated_mbwu = 4;
+	mpam_resctrl_monitor_sync_abmc_vals(&fake_l3);
+	KUNIT_EXPECT_EQ(test, fake_l3.mon.num_mbm_cntrs, 2);
+	KUNIT_EXPECT_TRUE(test, fake_l3.mon.mbm_cntr_assignable);
+	KUNIT_EXPECT_TRUE(test, fake_l3.mon.mbm_assign_on_mkdir);
+
+	/* ABMC 'on', CDP on - but not enough counters */
+	l3_num_allocated_mbwu = 1;
+	mpam_resctrl_monitor_sync_abmc_vals(&fake_l3);
+	KUNIT_EXPECT_EQ(test, fake_l3.mon.num_mbm_cntrs, 0);
+	KUNIT_EXPECT_FALSE(test, fake_l3.mon.mbm_cntr_assignable);
+	KUNIT_EXPECT_FALSE(test, fake_l3.mon.mbm_assign_on_mkdir);
+
+	/* Restore global variables that were messed with */
+	l3_num_allocated_mbwu = orig_l3_num_allocated_mbwu;
+	mpam_partid_max = orig_mpam_partid_max;
+	mpam_pmg_max = orig_mpam_pmg_max;
+	cdp_enabled = orig_cdp_enabled;
+}
+
 static struct kunit_case mpam_resctrl_test_cases[] = {
 	KUNIT_CASE(test_get_mba_granularity),
 	KUNIT_CASE_PARAM(test_mbw_max_to_percent, test_percent_value_gen_params),
@@ -301,6 +362,7 @@ static struct kunit_case mpam_resctrl_test_cases[] = {
 	KUNIT_CASE(test_percent_to_max_rounding),
 	KUNIT_CASE_PARAM(test_percent_max_roundtrip_stability,
 			 test_all_bwa_wd_gen_params),
+	KUNIT_CASE(test_num_assignable_counters),
 	{}
 };
 
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:34 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:34 +0000
Subject: [PATCH v2 32/45] arm_mpam: resctrl: Add resctrl_arch_config_cntr() for ABMC use
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-33-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

ABMC has a helper resctrl_arch_config_cntr() for changing the mapping
between 'cntr_id' and a CLOSID/RMID pair.

Add the helper.

For MPAM this is done by updating the mon->mbwu_idx_to_mon[] array, and as
usual CDP means it needs doing in three different ways.

Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
 drivers/resctrl/mpam_resctrl.c | 37 ++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index e96d320c219c..328a81ab68b4 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -765,6 +765,43 @@ static void mpam_resctrl_pick_counters(void)
 			     mpam_resctrl_counters[QOS_L3_MBM_TOTAL_EVENT_ID].class);
 }
 
+static void __config_cntr(struct mpam_resctrl_mon *mon, u32 cntr_id,
+			  enum resctrl_conf_type cdp_type, u32 closid, u32 rmid,
+			  bool assign)
+{
+	u32 mbwu_idx, mon_idx = resctrl_get_config_index(cntr_id, cdp_type);
+
+	closid = resctrl_get_config_index(closid, cdp_type);
+	mbwu_idx = resctrl_arch_rmid_idx_encode(closid, rmid);
+	WARN_ON_ONCE(mon_idx > l3_num_allocated_mbwu);
+
+	if (assign)
+		mon->mbwu_idx_to_mon[mbwu_idx] = mon->assigned_counters[mon_idx];
+	else
+		mon->mbwu_idx_to_mon[mbwu_idx] = -1;
+}
+
+void resctrl_arch_config_cntr(struct rdt_resource *r, struct rdt_mon_domain *d,
+			      enum resctrl_event_id evtid, u32 rmid, u32 closid,
+			      u32 cntr_id, bool assign)
+{
+	struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[evtid];
+
+	if (!mon->mbwu_idx_to_mon || !mon->assigned_counters) {
+		pr_debug("monitor arrays not allocated\n");
+		return;
+	}
+
+	if (cdp_enabled) {
+		__config_cntr(mon, cntr_id, CDP_CODE, closid, rmid, assign);
+		__config_cntr(mon, cntr_id, CDP_DATA, closid, rmid, assign);
+	} else {
+		__config_cntr(mon, cntr_id, CDP_NONE, closid, rmid, assign);
+	}
+
+	resctrl_arch_reset_rmid(r, d, closid, rmid, evtid);
+}
+
 bool resctrl_arch_mbm_cntr_assign_enabled(struct rdt_resource *r)
 {
 	if (r != &mpam_resctrl_controls[RDT_RESOURCE_L3].resctrl_res)
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:35 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:35 +0000
Subject: [PATCH v2 33/45] arm_mpam: resctrl: Allow resctrl to allocate monitors
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-34-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

When resctrl wants to read a domain's 'QOS_L3_OCCUP', it needs to allocate
a monitor on the corresponding resource. Monitors are allocated by class
instead of component.

MBM monitors are much more complicated, if there are enough monitors, they
will be pre-allocated and free-running. If ABMC is in use instead then
'some' are pre-allocated in a different way, and need assigning.

Add helpers to allocate a CSU monitor. These helper return an out of range
value for MBM counters.

Allocating a montitor context is expected to block until hardware resources
become available. This only makes sense for QOS_L3_OCCUP as unallocated MBM
counters are losing data.

Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
Changes since rfc:
USE_RMID_IDX -> USE_PRE_ALLOCATED in comment
Remove unnecessary arch_mon_ctx = NULL
---
 drivers/resctrl/mpam_internal.h | 14 ++++++-
 drivers/resctrl/mpam_resctrl.c  | 67 +++++++++++++++++++++++++++++++++
 include/linux/arm_mpam.h        |  4 ++
 3 files changed, 84 insertions(+), 1 deletion(-)

diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index a2f6956d9236..b907bec96ba5 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -29,6 +29,14 @@ struct platform_device;
 #define PACKED_FOR_KUNIT
 #endif
 
+/*
+ * This 'mon' values must not alias an actual monitor, so must be larger than
+ * U16_MAX, but not be confused with an errno value, so smaller than
+ * (u32)-SZ_4K.
+ * USE_PRE_ALLOCATED is used to avoid confusion with an actual monitor.
+ */
+#define USE_PRE_ALLOCATED	(U16_MAX + 1)
+
 static inline bool mpam_is_enabled(void)
 {
 	return static_branch_likely(&mpam_enabled);
@@ -212,7 +220,11 @@ enum mon_filter_options {
 };
 
 struct mon_cfg {
-	u16			mon;
+	/*
+	 * mon must be large enough to hold out of range values like
+	 * USE_PRE_ALLOCATED
+	 */
+	u32			mon;
 	u8			pmg;
 	bool			match_pmg;
 	bool			csu_exclude_clean;
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 328a81ab68b4..638c84cdcfb6 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -21,6 +21,8 @@
 
 #include "mpam_internal.h"
 
+DECLARE_WAIT_QUEUE_HEAD(resctrl_mon_ctx_waiters);
+
 /*
  * The classes we've picked to map to resctrl resources, wrapped
  * in with their resctrl structure.
@@ -287,6 +289,71 @@ struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l)
 	return &mpam_resctrl_controls[l].resctrl_res;
 }
 
+static int resctrl_arch_mon_ctx_alloc_no_wait(enum resctrl_event_id evtid)
+{
+	struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[evtid];
+
+	if (!mon->class)
+		return -EINVAL;
+
+	switch (evtid) {
+	case QOS_L3_OCCUP_EVENT_ID:
+		/* With CDP, one monitor gets used for both code/data reads */
+		return mpam_alloc_csu_mon(mon->class);
+	case QOS_L3_MBM_LOCAL_EVENT_ID:
+	case QOS_L3_MBM_TOTAL_EVENT_ID:
+		return USE_PRE_ALLOCATED;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r,
+				 enum resctrl_event_id evtid)
+{
+	DEFINE_WAIT(wait);
+	int *ret;
+
+	ret = kmalloc(sizeof(*ret), GFP_KERNEL);
+	if (!ret)
+		return ERR_PTR(-ENOMEM);
+
+	do {
+		prepare_to_wait(&resctrl_mon_ctx_waiters, &wait,
+				TASK_INTERRUPTIBLE);
+		*ret = resctrl_arch_mon_ctx_alloc_no_wait(evtid);
+		if (*ret == -ENOSPC)
+			schedule();
+	} while (*ret == -ENOSPC && !signal_pending(current));
+	finish_wait(&resctrl_mon_ctx_waiters, &wait);
+
+	return ret;
+}
+
+static void resctrl_arch_mon_ctx_free_no_wait(enum resctrl_event_id evtid,
+					      u32 mon_idx)
+{
+	struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[evtid];
+
+	if (!mon->class)
+		return;
+
+	if (evtid == QOS_L3_OCCUP_EVENT_ID)
+		mpam_free_csu_mon(mon->class, mon_idx);
+
+	wake_up(&resctrl_mon_ctx_waiters);
+}
+
+void resctrl_arch_mon_ctx_free(struct rdt_resource *r,
+			       enum resctrl_event_id evtid, void *arch_mon_ctx)
+{
+	u32 mon_idx = *(u32 *)arch_mon_ctx;
+
+	kfree(arch_mon_ctx);
+
+	resctrl_arch_mon_ctx_free_no_wait(evtid, mon_idx);
+}
+
 static bool cache_has_usable_cpor(struct mpam_class *class)
 {
 	struct mpam_props *cprops = &class->props;
diff --git a/include/linux/arm_mpam.h b/include/linux/arm_mpam.h
index 385554ceb452..e1461e32af75 100644
--- a/include/linux/arm_mpam.h
+++ b/include/linux/arm_mpam.h
@@ -63,6 +63,10 @@ u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid);
 void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid);
 u32 resctrl_arch_system_num_rmid_idx(void);
 
+struct rdt_resource;
+void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r, enum resctrl_event_id evtid);
+void resctrl_arch_mon_ctx_free(struct rdt_resource *r, enum resctrl_event_id evtid, void *ctx);
+
 /**
  * mpam_register_requestor() - Register a requestor with the MPAM driver
  * @partid_max:		The maximum PARTID value the requestor can generate.
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:36 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:36 +0000
Subject: [PATCH v2 34/45] arm_mpam: resctrl: Add resctrl_arch_rmid_read() and resctrl_arch_reset_rmid()
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-35-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

resctrl uses resctrl_arch_rmid_read() to read counters. CDP emulation means
the counter may need reading in three different ways. The same goes for
reset.

The helpers behind the resctrl_arch_ functions will be re-used for the ABMC
equivalent functions.

Add the rounding helper for checking monitor values while we're here.

Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
Changes since rfc:
cfg intialisation style
code flow at end of read_mon_cdp_safe()
---
 drivers/resctrl/mpam_resctrl.c | 159 +++++++++++++++++++++++++++++++++
 include/linux/arm_mpam.h       |   5 ++
 2 files changed, 164 insertions(+)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 638c84cdcfb6..8a1263986145 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -354,6 +354,165 @@ void resctrl_arch_mon_ctx_free(struct rdt_resource *r,
 	resctrl_arch_mon_ctx_free_no_wait(evtid, mon_idx);
 }
 
+static int
+__read_mon(struct mpam_resctrl_mon *mon, struct mpam_component *mon_comp,
+	   enum mpam_device_features mon_type,
+	   int mon_idx,
+	   enum resctrl_conf_type cdp_type, u32 closid, u32 rmid, u64 *val)
+{
+	struct mon_cfg cfg;
+
+	if (!mpam_is_enabled())
+		return -EINVAL;
+
+	/* Shift closid to account for CDP */
+	closid = resctrl_get_config_index(closid, cdp_type);
+
+	if (mon_idx == USE_PRE_ALLOCATED) {
+		int mbwu_idx = resctrl_arch_rmid_idx_encode(closid, rmid);
+
+		mon_idx = mon->mbwu_idx_to_mon[mbwu_idx];
+		if (mon_idx == -1) {
+			if (mpam_resctrl_abmc_enabled()) {
+				/* Report Unassigned */
+				return -ENOENT;
+			}
+			/* Report Unavailable */
+			return -EINVAL;
+		}
+	}
+
+	if (irqs_disabled()) {
+		/* Check if we can access this domain without an IPI */
+		return -EIO;
+	}
+
+	cfg = (struct mon_cfg) {
+		.mon = mon_idx,
+		.match_pmg = true,
+		.partid = closid,
+		.pmg = rmid,
+	};
+
+	return mpam_msmon_read(mon_comp, &cfg, mon_type, val);
+}
+
+static int read_mon_cdp_safe(struct mpam_resctrl_mon *mon, struct mpam_component *mon_comp,
+			     enum mpam_device_features mon_type,
+			     int mon_idx, u32 closid, u32 rmid, u64 *val)
+{
+	if (cdp_enabled) {
+		u64 code_val = 0, data_val = 0;
+		int err;
+
+		err = __read_mon(mon, mon_comp, mon_type, mon_idx,
+				 CDP_CODE, closid, rmid, &code_val);
+		if (err)
+			return err;
+
+		err = __read_mon(mon, mon_comp, mon_type, mon_idx,
+				 CDP_DATA, closid, rmid, &data_val);
+		if (err)
+			return err;
+
+		*val += code_val + data_val;
+		return 0;
+	}
+
+	return __read_mon(mon, mon_comp, mon_type, mon_idx,
+			  CDP_NONE, closid, rmid, val);
+}
+
+/* MBWU when not in ABMC mode, and CSU counters. */
+int resctrl_arch_rmid_read(struct rdt_resource	*r, struct rdt_mon_domain *d,
+			   u32 closid, u32 rmid, enum resctrl_event_id eventid,
+			   u64 *val, void *arch_mon_ctx)
+{
+	struct mpam_resctrl_dom *l3_dom;
+	struct mpam_component *mon_comp;
+	u32 mon_idx = *(u32 *)arch_mon_ctx;
+	enum mpam_device_features mon_type;
+	struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[eventid];
+
+	resctrl_arch_rmid_read_context_check();
+
+	if (eventid >= QOS_NUM_EVENTS || !mon->class)
+		return -EINVAL;
+
+	l3_dom = container_of(d, struct mpam_resctrl_dom, resctrl_mon_dom);
+	mon_comp = l3_dom->mon_comp[eventid];
+
+	switch (eventid) {
+	case QOS_L3_OCCUP_EVENT_ID:
+		mon_type = mpam_feat_msmon_csu;
+		break;
+	case QOS_L3_MBM_LOCAL_EVENT_ID:
+	case QOS_L3_MBM_TOTAL_EVENT_ID:
+		mon_type = mpam_feat_msmon_mbwu;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return read_mon_cdp_safe(mon, mon_comp, mon_type, mon_idx,
+				 closid, rmid, val);
+}
+
+static void __reset_mon(struct mpam_resctrl_mon *mon, struct mpam_component *mon_comp,
+			int mon_idx,
+			enum resctrl_conf_type cdp_type, u32 closid, u32 rmid)
+{
+	struct mon_cfg cfg = { };
+
+	if (!mpam_is_enabled())
+		return;
+
+	/* Shift closid to account for CDP */
+	closid = resctrl_get_config_index(closid, cdp_type);
+
+	if (mon_idx == USE_PRE_ALLOCATED) {
+		int mbwu_idx = resctrl_arch_rmid_idx_encode(closid, rmid);
+		mon_idx = mon->mbwu_idx_to_mon[mbwu_idx];
+	}
+
+	if (mon_idx == -1)
+		return;
+	cfg.mon = mon_idx;
+	mpam_msmon_reset_mbwu(mon_comp, &cfg);
+}
+
+static void reset_mon_cdp_safe(struct mpam_resctrl_mon *mon, struct mpam_component *mon_comp,
+			       int mon_idx, u32 closid, u32 rmid)
+{
+	if (cdp_enabled) {
+		__reset_mon(mon, mon_comp, mon_idx, CDP_CODE, closid, rmid);
+		__reset_mon(mon, mon_comp, mon_idx, CDP_DATA, closid, rmid);
+	} else {
+		__reset_mon(mon, mon_comp, mon_idx, CDP_NONE, closid, rmid);
+	}
+}
+
+/* Called via IPI. Call with read_cpus_lock() held. */
+void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_mon_domain *d,
+			     u32 closid, u32 rmid, enum resctrl_event_id eventid)
+{
+	struct mpam_resctrl_dom *l3_dom;
+	struct mpam_component *mon_comp;
+	struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[eventid];
+
+	if (!mpam_is_enabled())
+		return;
+
+	/* Only MBWU counters are relevant, and for supported event types. */
+	if (eventid == QOS_L3_OCCUP_EVENT_ID || !mon->class)
+		return;
+
+	l3_dom = container_of(d, struct mpam_resctrl_dom, resctrl_mon_dom);
+	mon_comp = l3_dom->mon_comp[eventid];
+
+	reset_mon_cdp_safe(mon, mon_comp, USE_PRE_ALLOCATED, closid, rmid);
+}
+
 static bool cache_has_usable_cpor(struct mpam_class *class)
 {
 	struct mpam_props *cprops = &class->props;
diff --git a/include/linux/arm_mpam.h b/include/linux/arm_mpam.h
index e1461e32af75..86d5e326d2bd 100644
--- a/include/linux/arm_mpam.h
+++ b/include/linux/arm_mpam.h
@@ -67,6 +67,11 @@ struct rdt_resource;
 void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r, enum resctrl_event_id evtid);
 void resctrl_arch_mon_ctx_free(struct rdt_resource *r, enum resctrl_event_id evtid, void *ctx);
 
+static inline unsigned int resctrl_arch_round_mon_val(unsigned int val)
+{
+	return val;
+}
+
 /**
  * mpam_register_requestor() - Register a requestor with the MPAM driver
  * @partid_max:		The maximum PARTID value the requestor can generate.
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:37 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:37 +0000
Subject: [PATCH v2 35/45] arm_mpam: resctrl: Add resctrl_arch_cntr_read() & resctrl_arch_reset_cntr()
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-36-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

When used in ABMC mode, resctrl uses a different set of helpers to read and
reset the counters.

Add these.

Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
 drivers/resctrl/mpam_resctrl.c | 43 ++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 8a1263986145..ef60bc0c7bd8 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -458,6 +458,28 @@ int resctrl_arch_rmid_read(struct rdt_resource	*r, struct rdt_mon_domain *d,
 				 closid, rmid, val);
 }
 
+/* MBWU counters when in ABMC mode */
+int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_mon_domain *d,
+			   u32 closid, u32 rmid, int mon_idx,
+			   enum resctrl_event_id eventid, u64 *val)
+{
+	struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[eventid];
+	struct mpam_resctrl_dom *l3_dom;
+	struct mpam_component *mon_comp;
+
+	if (!mpam_is_enabled())
+		return -EINVAL;
+
+	if (eventid == QOS_L3_OCCUP_EVENT_ID || !mon->class)
+		return -EINVAL;
+
+	l3_dom = container_of(d, struct mpam_resctrl_dom, resctrl_mon_dom);
+	mon_comp = l3_dom->mon_comp[eventid];
+
+	return read_mon_cdp_safe(mon, mon_comp, mpam_feat_msmon_mbwu, mon_idx,
+				 closid, rmid, val);
+}
+
 static void __reset_mon(struct mpam_resctrl_mon *mon, struct mpam_component *mon_comp,
 			int mon_idx,
 			enum resctrl_conf_type cdp_type, u32 closid, u32 rmid)
@@ -513,6 +535,27 @@ void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_mon_domain *d,
 	reset_mon_cdp_safe(mon, mon_comp, USE_PRE_ALLOCATED, closid, rmid);
 }
 
+/* Reset an assigned counter */
+void resctrl_arch_reset_cntr(struct rdt_resource *r, struct rdt_mon_domain *d,
+			     u32 closid, u32 rmid, int cntr_id,
+			     enum resctrl_event_id eventid)
+{
+	struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[eventid];
+	struct mpam_resctrl_dom *l3_dom;
+	struct mpam_component *mon_comp;
+
+	if (!mpam_is_enabled())
+		return;
+
+	if (eventid == QOS_L3_OCCUP_EVENT_ID || !mon->class)
+		return;
+
+	l3_dom = container_of(d, struct mpam_resctrl_dom, resctrl_mon_dom);
+	mon_comp = l3_dom->mon_comp[eventid];
+
+	reset_mon_cdp_safe(mon, mon_comp, USE_PRE_ALLOCATED, closid, rmid);
+}
+
 static bool cache_has_usable_cpor(struct mpam_class *class)
 {
 	struct mpam_props *cprops = &class->props;
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:38 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:38 +0000
Subject: [PATCH v2 36/45] arm_mpam: resctrl: Update the rmid reallocation limit
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-37-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

resctrl's limbo code needs to be told when the data left in a cache is
small enough for the partid+pmg value to be re-allocated.

x86 uses the cache size divided by the number of rmid users the cache may
have. Do the same, but for the smallest cache, and with the number of
partid-and-pmg users.

Querying the cache size can't happen until after cacheinfo_sysfs_init() has
run, so mpam_resctrl_setup() must wait until then.

Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
 drivers/resctrl/mpam_resctrl.c | 54 ++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index ef60bc0c7bd8..84f517cb047a 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -16,6 +16,7 @@
 #include <linux/resctrl.h>
 #include <linux/slab.h>
 #include <linux/types.h>
+#include <linux/wait.h>
 
 #include <asm/mpam.h>
 
@@ -52,6 +53,13 @@ static bool exposed_mon_capable;
  */
 static bool cdp_enabled;
 
+/*
+ * mpam_resctrl_pick_caches() needs to know the size of the caches. cacheinfo
+ * populates this from a device_initcall(). mpam_resctrl_setup() must wait.
+ */
+static bool cacheinfo_ready;
+static DECLARE_WAIT_QUEUE_HEAD(wait_cacheinfo_ready);
+
 /*
  * L3 local/total may come from different classes - what is the number of MBWU
  * 'on L3'?
@@ -556,6 +564,38 @@ void resctrl_arch_reset_cntr(struct rdt_resource *r, struct rdt_mon_domain *d,
 	reset_mon_cdp_safe(mon, mon_comp, USE_PRE_ALLOCATED, closid, rmid);
 }
 
+/*
+ * The rmid realloc threshold should be for the smallest cache exposed to
+ * resctrl.
+ */
+static int update_rmid_limits(struct mpam_class *class)
+{
+	u32 num_unique_pmg = resctrl_arch_system_num_rmid_idx();
+	struct mpam_props *cprops = &class->props;
+	struct cacheinfo *ci;
+
+	lockdep_assert_cpus_held();
+
+	/* Assume cache levels are the same size for all CPUs... */
+	ci = get_cpu_cacheinfo_level(smp_processor_id(), class->level);
+	if (!ci || ci->size == 0) {
+		pr_debug("Could not read cache size for class %u\n",
+			 class->level);
+		return -EINVAL;
+	}
+
+	if (!mpam_has_feature(mpam_feat_msmon_csu, cprops))
+		return 0;
+
+	if (!resctrl_rmid_realloc_limit ||
+	    ci->size < resctrl_rmid_realloc_limit) {
+		resctrl_rmid_realloc_limit = ci->size;
+		resctrl_rmid_realloc_threshold = ci->size / num_unique_pmg;
+	}
+
+	return 0;
+}
+
 static bool cache_has_usable_cpor(struct mpam_class *class)
 {
 	struct mpam_props *cprops = &class->props;
@@ -996,6 +1036,9 @@ static void mpam_resctrl_pick_counters(void)
 			/* CSU counters only make sense on a cache. */
 			switch (class->type) {
 			case MPAM_CLASS_CACHE:
+				if (update_rmid_limits(class))
+					continue;
+
 				counter_update_class(QOS_L3_OCCUP_EVENT_ID, class);
 				return;
 			default:
@@ -1708,6 +1751,8 @@ int mpam_resctrl_setup(void)
 	int err = 0;
 	struct mpam_resctrl_res *res;
 
+	wait_event(wait_cacheinfo_ready, cacheinfo_ready);
+
 	cpus_read_lock();
 	for (enum resctrl_res_level i = 0; i < RDT_NUM_RESOURCES; i++) {
 		res = &mpam_resctrl_controls[i];
@@ -1773,6 +1818,15 @@ int mpam_resctrl_setup(void)
 	return err;
 }
 
+static int __init __cacheinfo_ready(void)
+{
+	cacheinfo_ready = true;
+	wake_up(&wait_cacheinfo_ready);
+
+	return 0;
+}
+device_initcall_sync(__cacheinfo_ready);
+
 #ifdef CONFIG_MPAM_KUNIT_TEST
 #include "test_mpam_resctrl.c"
 #endif
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:39 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:39 +0000
Subject: [PATCH v2 37/45] arm_mpam: resctrl: Add empty definitions for assorted resctrl functions
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-38-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

A few resctrl features and hooks need to be provided, but aren't needed or
supported on MPAM platforms.

resctrl has individual hooks to separately enable and disable the
closid/partid and rmid/pmg context switching code. For MPAM this is all the
same thing, as the value in struct task_struct is used to cache the value
that should be written to hardware. arm64's context switching code is
enabled once MPAM is usable, but doesn't touch the hardware unless the
value has changed.

For now event configuration is not supported, and can be turned off by
returning 'false' from resctrl_arch_is_evt_configurable().

The new io_alloc feature is not supported either, always return false from
the enable helper to indicate and fail the enable.

Add this, and empty definitions for the other hooks.

Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
 drivers/resctrl/mpam_resctrl.c | 27 +++++++++++++++++++++++++++
 include/linux/arm_mpam.h       |  9 +++++++++
 2 files changed, 36 insertions(+)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 84f517cb047a..059148c38a38 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -93,6 +93,23 @@ bool resctrl_arch_mon_capable(void)
 	return exposed_mon_capable;
 }
 
+bool resctrl_arch_is_evt_configurable(enum resctrl_event_id evt)
+{
+	return false;
+}
+
+void resctrl_arch_mon_event_config_read(void *info)
+{
+}
+
+void resctrl_arch_mon_event_config_write(void *info)
+{
+}
+
+void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_mon_domain *d)
+{
+}
+
 bool resctrl_arch_get_cdp_enabled(enum resctrl_res_level rid)
 {
 	switch (rid) {
@@ -1131,6 +1148,16 @@ int resctrl_arch_mbm_cntr_assign_set(struct rdt_resource *r, bool enable)
 	return 0;
 }
 
+int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable)
+{
+	return -EOPNOTSUPP;
+}
+
+bool resctrl_arch_get_io_alloc_enabled(struct rdt_resource *r)
+{
+	return false;
+}
+
 static int mpam_resctrl_control_init(struct mpam_resctrl_res *res,
 				     enum resctrl_res_level type)
 {
diff --git a/include/linux/arm_mpam.h b/include/linux/arm_mpam.h
index 86d5e326d2bd..f92a36187a52 100644
--- a/include/linux/arm_mpam.h
+++ b/include/linux/arm_mpam.h
@@ -67,6 +67,15 @@ struct rdt_resource;
 void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r, enum resctrl_event_id evtid);
 void resctrl_arch_mon_ctx_free(struct rdt_resource *r, enum resctrl_event_id evtid, void *ctx);
 
+/*
+ * The CPU configuration for MPAM is cheap to write, and is only written if it
+ * has changed. No need for fine grained enables.
+ */
+static inline void resctrl_arch_enable_mon(void) { }
+static inline void resctrl_arch_disable_mon(void) { }
+static inline void resctrl_arch_enable_alloc(void) { }
+static inline void resctrl_arch_disable_alloc(void) { }
+
 static inline unsigned int resctrl_arch_round_mon_val(unsigned int val)
 {
 	return val;
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:41 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:41 +0000
Subject: [PATCH v2 39/45] arm_mpam: resctrl: Call resctrl_init() on platforms that can support resctrl
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-40-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

Now that MPAM links against resctrl, call resctrl_init() to register the
filesystem and setup resctrl's structures.

Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
 drivers/resctrl/mpam_devices.c  | 32 +++++++++++--
 drivers/resctrl/mpam_internal.h |  4 ++
 drivers/resctrl/mpam_resctrl.c  | 82 ++++++++++++++++++++++++++++++++-
 3 files changed, 113 insertions(+), 5 deletions(-)

diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index 4f5d908d02a9..c20b2757b86b 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -73,6 +73,14 @@ static DECLARE_WORK(mpam_broken_work, &mpam_disable);
 /* When mpam is disabled, the printed reason to aid debugging */
 static char *mpam_disable_reason;
 
+/*
+ * Whether resctrl has been setup. Used by cpuhp in preference to
+ * mpam_is_enabled(). The disable call after an error interrupt makes
+ * mpam_is_enabled() false before the cpuhp callbacks are made.
+ * Reads/writes should hold mpam_cpuhp_state_lock, (or be cpuhp callbacks).
+ */
+static bool mpam_resctrl_enabled;
+
 /*
  * An MSC is a physical container for controls and monitors, each identified by
  * their RIS index. These share a base-address, interrupts and some MMIO
@@ -1628,7 +1636,7 @@ static int mpam_cpu_online(unsigned int cpu)
 			mpam_reprogram_msc(msc);
 	}
 
-	if (mpam_is_enabled())
+	if (mpam_resctrl_enabled)
 		mpam_resctrl_online_cpu(cpu);
 
 	return 0;
@@ -1674,7 +1682,7 @@ static int mpam_cpu_offline(unsigned int cpu)
 {
 	struct mpam_msc *msc;
 
-	if (mpam_is_enabled())
+	if (mpam_resctrl_enabled)
 		mpam_resctrl_offline_cpu(cpu);
 
 	guard(srcu)(&mpam_srcu);
@@ -2536,6 +2544,7 @@ static void mpam_enable_once(void)
 	}
 
 	static_branch_enable(&mpam_enabled);
+	mpam_resctrl_enabled = true;
 	mpam_register_cpuhp_callbacks(mpam_cpu_online, mpam_cpu_offline,
 				      "mpam:online");
 
@@ -2595,24 +2604,39 @@ void mpam_reset_class(struct mpam_class *class)
 void mpam_disable(struct work_struct *ignored)
 {
 	int idx;
+	bool do_resctrl_exit;
 	struct mpam_class *class;
 	struct mpam_msc *msc, *tmp;
 
+	if (mpam_is_enabled())
+		static_branch_disable(&mpam_enabled);
+
 	mutex_lock(&mpam_cpuhp_state_lock);
 	if (mpam_cpuhp_state) {
 		cpuhp_remove_state(mpam_cpuhp_state);
 		mpam_cpuhp_state = 0;
 	}
+
+	/*
+	 * Removing the cpuhp state called mpam_cpu_offline() and told resctrl
+	 * all the CPUs are offline.
+	 */
+	do_resctrl_exit = mpam_resctrl_enabled;
+	mpam_resctrl_enabled = false;
 	mutex_unlock(&mpam_cpuhp_state_lock);
 
-	static_branch_disable(&mpam_enabled);
+	if (do_resctrl_exit)
+		mpam_resctrl_exit();
 
 	mpam_unregister_irqs();
 
 	idx = srcu_read_lock(&mpam_srcu);
 	list_for_each_entry_srcu(class, &mpam_classes, classes_list,
-				 srcu_read_lock_held(&mpam_srcu))
+				 srcu_read_lock_held(&mpam_srcu)) {
 		mpam_reset_class(class);
+		if (do_resctrl_exit)
+			mpam_resctrl_teardown_class(class);
+	}
 	srcu_read_unlock(&mpam_srcu, idx);
 
 	mutex_lock(&mpam_list_lock);
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index b907bec96ba5..9a3996decda5 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -447,12 +447,16 @@ int mpam_get_cpumask_from_cache_id(unsigned long cache_id, u32 cache_level,
 
 #ifdef CONFIG_RESCTRL_FS
 int mpam_resctrl_setup(void);
+void mpam_resctrl_exit(void);
 int mpam_resctrl_online_cpu(unsigned int cpu);
 void mpam_resctrl_offline_cpu(unsigned int cpu);
+void mpam_resctrl_teardown_class(struct mpam_class *class);
 #else
 static inline int mpam_resctrl_setup(void) { return 0; }
+static inline void mpam_resctrl_exit(void) { }
 static inline int mpam_resctrl_online_cpu(unsigned int cpu) { return 0; }
 static inline void mpam_resctrl_offline_cpu(unsigned int cpu) { }
+static inline void mpam_resctrl_teardown_class(struct mpam_class *class) { }
 #endif /* CONFIG_RESCTRL_FS */
 
 /*
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 059148c38a38..bbb12b5dfd8c 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -53,6 +53,12 @@ static bool exposed_mon_capable;
  */
 static bool cdp_enabled;
 
+/*
+ * If resctrl_init() succeeded, resctrl_exit() can be used to remove support
+ * for the filesystem in the event of an error.
+ */
+static bool resctrl_enabled;
+
 /*
  * mpam_resctrl_pick_caches() needs to know the size of the caches. cacheinfo
  * populates this from a device_initcall(). mpam_resctrl_setup() must wait.
@@ -318,6 +324,9 @@ static int resctrl_arch_mon_ctx_alloc_no_wait(enum resctrl_event_id evtid)
 {
 	struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[evtid];
 
+	if (!mpam_is_enabled())
+		return -EINVAL;
+
 	if (!mon->class)
 		return -EINVAL;
 
@@ -360,6 +369,9 @@ static void resctrl_arch_mon_ctx_free_no_wait(enum resctrl_event_id evtid,
 {
 	struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[evtid];
 
+	if (!mpam_is_enabled())
+		return;
+
 	if (!mon->class)
 		return;
 
@@ -461,6 +473,9 @@ int resctrl_arch_rmid_read(struct rdt_resource	*r, struct rdt_mon_domain *d,
 
 	resctrl_arch_rmid_read_context_check();
 
+	if (!mpam_is_enabled())
+		return -EINVAL;
+
 	if (eventid >= QOS_NUM_EVENTS || !mon->class)
 		return -EINVAL;
 
@@ -1399,6 +1414,9 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 	lockdep_assert_cpus_held();
 	lockdep_assert_irqs_enabled();
 
+	if (!mpam_is_enabled())
+		return -EINVAL;
+
 	/*
 	 * No need to check the CPU as mpam_apply_config() doesn't care, and
 	 * resctrl_arch_update_domains() relies on this.
@@ -1461,6 +1479,9 @@ int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid)
 	lockdep_assert_cpus_held();
 	lockdep_assert_irqs_enabled();
 
+	if (!mpam_is_enabled())
+		return -EINVAL;
+
 	list_for_each_entry_rcu(d, &r->ctrl_domains, hdr.list) {
 		for (enum resctrl_conf_type t = 0; t < CDP_NUM_TYPES; t++) {
 			struct resctrl_staged_config *cfg = &d->staged_config[t];
@@ -1840,11 +1861,70 @@ int mpam_resctrl_setup(void)
 		pr_warn("Number of PMG is not a power of 2! resctrl may misbehave");
 	}
 
-	/* TODO: call resctrl_init() */
+	err = resctrl_init();
+	if (!err)
+		WRITE_ONCE(resctrl_enabled, true);
 
 	return err;
 }
 
+void mpam_resctrl_exit(void)
+{
+	if (!READ_ONCE(resctrl_enabled))
+		return;
+
+	WRITE_ONCE(resctrl_enabled, false);
+	resctrl_exit();
+}
+
+static void mpam_resctrl_teardown_mon(struct mpam_resctrl_mon *mon, struct mpam_class *class)
+{
+	u32 num_mbwu_mon = l3_num_allocated_mbwu;
+
+	if (!mon->mbwu_idx_to_mon)
+		return;
+
+	if (mon->assigned_counters) {
+		__free_mbwu_mon(class, mon->assigned_counters, num_mbwu_mon);
+		mon->assigned_counters = NULL;
+		kfree(mon->mbwu_idx_to_mon);
+	} else {
+		__free_mbwu_mon(class, mon->mbwu_idx_to_mon, num_mbwu_mon);
+	}
+	mon->mbwu_idx_to_mon = NULL;
+}
+
+/*
+ * The driver is detaching an MSC from this class, if resctrl was using it,
+ * pull on resctrl_exit().
+ */
+void mpam_resctrl_teardown_class(struct mpam_class *class)
+{
+	int i;
+	struct mpam_resctrl_res *res;
+	struct mpam_resctrl_mon *mon;
+
+	might_sleep();
+
+	for (i = 0; i < RDT_NUM_RESOURCES; i++) {
+		res = &mpam_resctrl_controls[i];
+		if (res->class == class) {
+			res->class = NULL;
+			break;
+		}
+	}
+	for (i = 0; i < QOS_NUM_EVENTS; i++) {
+		mon = &mpam_resctrl_counters[i];
+		if (mon->class == class) {
+			mon->class = NULL;
+
+			mpam_resctrl_teardown_mon(mon, class);
+
+			break;
+		}
+	}
+}
+
 static int __init __cacheinfo_ready(void)
 {
 	cacheinfo_ready = true;
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:40 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:40 +0000
Subject: [PATCH v2 38/45] arm64: mpam: Select ARCH_HAS_CPU_RESCTRL
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-39-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

Enough MPAM support is present to enable ARCH_HAS_CPU_RESCTRL.  Let it
rip^Wlink!

ARCH_HAS_CPU_RESCTRL indicates resctrl can be enabled. It is enabled by the
arch code simply because it has 'arch' in its name.

This removes ARM_CPU_RESCTRL as a mimic of X86_CPU_RESCTRL.  While here,
move the ACPI dependency to the driver's Kconfig file.

In anticipation of MPAM being useful remove the CONFIG_EXPERT restriction.

Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
 arch/arm64/Kconfig               | 4 ++--
 arch/arm64/include/asm/resctrl.h | 2 ++
 drivers/resctrl/Kconfig          | 9 ++++++++-
 drivers/resctrl/Makefile         | 2 +-
 4 files changed, 13 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm64/include/asm/resctrl.h

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index cdcc5b76a110..baeecb88771d 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -2026,8 +2026,8 @@ config ARM64_TLB_RANGE
 
 config ARM64_MPAM
 	bool "Enable support for MPAM"
-	select ARM64_MPAM_DRIVER if EXPERT	# does nothing yet
-	select ACPI_MPAM if ACPI
+	select ARM64_MPAM_DRIVER
+	select ARCH_HAS_CPU_RESCTRL
 	help
 	  Memory System Resource Partitioning and Monitoring (MPAM) is an
 	  optional extension to the Arm architecture that allows each
diff --git a/arch/arm64/include/asm/resctrl.h b/arch/arm64/include/asm/resctrl.h
new file mode 100644
index 000000000000..b506e95cf6e3
--- /dev/null
+++ b/arch/arm64/include/asm/resctrl.h
@@ -0,0 +1,2 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/arm_mpam.h>
diff --git a/drivers/resctrl/Kconfig b/drivers/resctrl/Kconfig
index c808e0470394..672abea3b03c 100644
--- a/drivers/resctrl/Kconfig
+++ b/drivers/resctrl/Kconfig
@@ -1,6 +1,7 @@
 menuconfig ARM64_MPAM_DRIVER
 	bool "MPAM driver"
-	depends on ARM64 && ARM64_MPAM && EXPERT
+	depends on ARM64 && ARM64_MPAM
+	select ACPI_MPAM if ACPI
 	help
 	  Memory System Resource Partitioning and Monitoring (MPAM) driver for
 	  System IP, e.g. caches and memory controllers.
@@ -22,3 +23,9 @@ config MPAM_KUNIT_TEST
 	  If unsure, say N.
 
 endif
+
+config ARM64_MPAM_RESCTRL_FS
+	bool
+	default y if ARM64_MPAM_DRIVER && RESCTRL_FS
+	select RESCTRL_RMID_DEPENDS_ON_CLOSID
+	select RESCTRL_ASSIGN_FIXED
diff --git a/drivers/resctrl/Makefile b/drivers/resctrl/Makefile
index 40beaf999582..4f6d0e81f9b8 100644
--- a/drivers/resctrl/Makefile
+++ b/drivers/resctrl/Makefile
@@ -1,5 +1,5 @@
 obj-$(CONFIG_ARM64_MPAM_DRIVER)			+= mpam.o
 mpam-y						+= mpam_devices.o
-mpam-$(CONFIG_ARM_CPU_RESCTRL)			+= mpam_resctrl.o
+mpam-$(CONFIG_ARM64_MPAM_RESCTRL_FS)		+= mpam_resctrl.o
 
 ccflags-$(CONFIG_ARM64_MPAM_DRIVER_DEBUG)	+= -DDEBUG
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:42 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:42 +0000
Subject: [PATCH v2 40/45] arm_mpam: Generate a configuration for min controls
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-41-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

MPAM supports a minimum and maximum control for memory bandwidth. The
purpose of the minimum control is to give priority to tasks that are below
their minimum value. Resctrl only provides one value for the bandwidth
configuration, which is used for the maximum.

The minimum control is always programmed to zero on hardware that supports
it.

Generate a minimum bandwidth value that is 5% lower than the value provided
by resctrl. This means tasks that are not receiving their target bandwidth
can be prioritised by the hardware.

For component reset reuse the same calculation so that the default is a
value resctrl can set.

CC: Zeng Heng <zengheng4 at huawei.com>
Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
Add reset_mbw_min
Clear min cfg when setting max
use mpam_extend_config on component reset
---
 drivers/resctrl/mpam_devices.c      | 76 +++++++++++++++++++++++++++--
 drivers/resctrl/mpam_internal.h     |  3 ++
 drivers/resctrl/mpam_resctrl.c      |  2 +
 drivers/resctrl/test_mpam_devices.c | 66 +++++++++++++++++++++++++
 4 files changed, 142 insertions(+), 5 deletions(-)

diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index c20b2757b86b..deea46c2a6c3 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -721,6 +721,13 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris)
 			mpam_set_feature(mpam_feat_mbw_part, props);
 
 		props->bwa_wd = FIELD_GET(MPAMF_MBW_IDR_BWA_WD, mbw_features);
+
+		/*
+		 * The BWA_WD field can represent 0-63, but the control fields it
+		 * describes have a maximum of 16 bits.
+		 */
+		props->bwa_wd = min(props->bwa_wd, 16);
+
 		if (props->bwa_wd && FIELD_GET(MPAMF_MBW_IDR_HAS_MAX, mbw_features))
 			mpam_set_feature(mpam_feat_mbw_max, props);
 
@@ -1387,8 +1394,12 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
 	}
 
 	if (mpam_has_feature(mpam_feat_mbw_min, rprops) &&
-	    mpam_has_feature(mpam_feat_mbw_min, cfg))
-		mpam_write_partsel_reg(msc, MBW_MIN, 0);
+	    mpam_has_feature(mpam_feat_mbw_min, cfg)) {
+		if (cfg->reset_mbw_min)
+			mpam_write_partsel_reg(msc, MBW_MIN, 0);
+		else
+			mpam_write_partsel_reg(msc, MBW_MIN, cfg->mbw_min);
+	}
 
 	if (mpam_has_feature(mpam_feat_mbw_max, rprops) &&
 	    mpam_has_feature(mpam_feat_mbw_max, cfg)) {
@@ -1503,6 +1514,7 @@ static void mpam_init_reset_cfg(struct mpam_config *reset_cfg)
 		.reset_cpbm = true,
 		.reset_mbw_pbm = true,
 		.reset_mbw_max = true,
+		.reset_mbw_min = true,
 	};
 	bitmap_fill(reset_cfg->features, MPAM_FEATURE_LAST);
 }
@@ -2401,6 +2413,45 @@ static void __destroy_component_cfg(struct mpam_component *comp)
 	}
 }
 
+static void mpam_extend_config(struct mpam_class *class, struct mpam_config *cfg)
+{
+	struct mpam_props *cprops = &class->props;
+	u16 min, min_hw_granule, delta;
+	u16 max_hw_value, res0_bits;
+
+	/*
+	 * MAX and MIN should be set together. If only one is provided,
+	 * generate a configuration for the other. If only one control
+	 * type is supported, the other value will be ignored.
+	 *
+	 * Resctrl can only configure the MAX.
+	 */
+	if (mpam_has_feature(mpam_feat_mbw_max, cfg) &&
+	    !mpam_has_feature(mpam_feat_mbw_min, cfg)) {
+		/*
+		 * Calculate the values the 'min' control can hold.
+		 * e.g. on a platform with bwa_wd = 8, min_hw_granule is 0x00ff
+		 * because those bits are RES0. Configurations of this value
+		 * are effectively zero. But configurations need to saturate
+		 * at min_hw_granule on systems with mismatched bwa_wd, where
+		 * the 'less than 0' values are implemented on some MSC, but
+		 * not others.
+		 */
+		res0_bits = 16 - cprops->bwa_wd;
+		max_hw_value = ((1 << cprops->bwa_wd) - 1) << res0_bits;
+		min_hw_granule = ~max_hw_value;
+
+		delta = ((5 * MPAMCFG_MBW_MAX_MAX) / 100) - 1;
+		if (cfg->mbw_max > delta)
+			min = cfg->mbw_max - delta;
+		else
+			min = 0;
+
+		cfg->mbw_min = max(min, min_hw_granule);
+		mpam_set_feature(mpam_feat_mbw_min, cfg);
+	}
+}
+
 static void mpam_reset_component_cfg(struct mpam_component *comp)
 {
 	int i;
@@ -2419,6 +2470,8 @@ static void mpam_reset_component_cfg(struct mpam_component *comp)
 			comp->cfg[i].mbw_pbm = GENMASK(cprops->mbw_pbm_bits - 1, 0);
 		if (cprops->bwa_wd)
 			comp->cfg[i].mbw_max = GENMASK(15, 16 - cprops->bwa_wd);
+
+		mpam_extend_config(comp->class, &comp->cfg[i]);
 	}
 }
 
@@ -2694,24 +2747,37 @@ static bool mpam_update_config(struct mpam_config *cfg,
 	maybe_update_config(cfg, mpam_feat_cpor_part, newcfg, cpbm, has_changes);
 	maybe_update_config(cfg, mpam_feat_mbw_part, newcfg, mbw_pbm, has_changes);
 	maybe_update_config(cfg, mpam_feat_mbw_max, newcfg, mbw_max, has_changes);
+	maybe_update_config(cfg, mpam_feat_mbw_min, newcfg, mbw_min, has_changes);
 
 	return has_changes;
 }
 
 int mpam_apply_config(struct mpam_component *comp, u16 partid,
-		      struct mpam_config *cfg)
+		      struct mpam_config *user_cfg)
 {
 	struct mpam_write_config_arg arg;
 	struct mpam_msc_ris *ris;
+	struct mpam_config cfg;
 	struct mpam_vmsc *vmsc;
 	struct mpam_msc *msc;
 
 	lockdep_assert_cpus_held();
 
 	/* Don't pass in the current config! */
-	WARN_ON_ONCE(&comp->cfg[partid] == cfg);
+	WARN_ON_ONCE(&comp->cfg[partid] == user_cfg);
+
+	/*
+	 * Copy the config to avoid writing back the 'extended' version to
+	 * the caller.
+	 * This avoids mpam_devices.c setting a mbm_min that mpam_resctrl.c
+	 * is unaware of ... when it then changes mbm_max to be lower than
+	 * mbm_min.
+	 */
+	cfg = *user_cfg;
+
+	mpam_extend_config(comp->class, &cfg);
 
-	if (!mpam_update_config(&comp->cfg[partid], cfg))
+	if (!mpam_update_config(&comp->cfg[partid], &cfg))
 		return 0;
 
 	arg.comp = comp;
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index 9a3996decda5..cc580dea9430 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -274,10 +274,12 @@ struct mpam_config {
 	u32	cpbm;
 	u32	mbw_pbm;
 	u16	mbw_max;
+	u16	mbw_min;
 
 	bool	reset_cpbm;
 	bool	reset_mbw_pbm;
 	bool	reset_mbw_max;
+	bool	reset_mbw_min;
 
 	struct mpam_garbage	garbage;
 };
@@ -615,6 +617,7 @@ static inline void mpam_resctrl_teardown_class(struct mpam_class *class) { }
  * MPAMCFG_MBW_MAX - MPAM memory maximum bandwidth partitioning configuration
  *                   register
  */
+#define MPAMCFG_MBW_MAX_MAX_NR_BITS	16
 #define MPAMCFG_MBW_MAX_MAX		GENMASK(15, 0)
 #define MPAMCFG_MBW_MAX_HARDLIM		BIT(31)
 
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index bbb12b5dfd8c..b24ae75ec6f0 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -1447,6 +1447,8 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 		if (mpam_has_feature(mpam_feat_mbw_max, cprops)) {
 			cfg.mbw_max = percent_to_mbw_max(cfg_val, cprops);
 			mpam_set_feature(mpam_feat_mbw_max, &cfg);
+			/* Allow the min to be calculated from the max */
+			mpam_clear_feature(mpam_feat_mbw_min, &cfg);
 			break;
 		}
 		fallthrough;
diff --git a/drivers/resctrl/test_mpam_devices.c b/drivers/resctrl/test_mpam_devices.c
index 3e8d564a0c64..2f802fd9f249 100644
--- a/drivers/resctrl/test_mpam_devices.c
+++ b/drivers/resctrl/test_mpam_devices.c
@@ -322,6 +322,71 @@ static void test_mpam_enable_merge_features(struct kunit *test)
 	mutex_unlock(&mpam_list_lock);
 }
 
+static void test_mpam_extend_config(struct kunit *test)
+{
+	struct mpam_config fake_cfg = { };
+	struct mpam_class fake_class = { };
+
+	/* Configurations with both are not modified */
+	fake_class.props.bwa_wd = 16;
+	fake_cfg.mbw_max = 0xfeef;
+	fake_cfg.mbw_min = 0xfeef;
+	bitmap_zero(fake_cfg.features, MPAM_FEATURE_LAST);
+	mpam_set_feature(mpam_feat_mbw_max, &fake_cfg);
+	mpam_set_feature(mpam_feat_mbw_min, &fake_cfg);
+	mpam_extend_config(&fake_class, &fake_cfg);
+	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_max, &fake_cfg));
+	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_min, &fake_cfg));
+	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_max, 0xfeef);
+	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_min, 0xfeef);
+
+	/* When a min is missing, it is generated */
+	fake_class.props.bwa_wd = 16;
+	fake_cfg.mbw_max = 0xfeef;
+	fake_cfg.mbw_min = 0;
+	bitmap_zero(fake_cfg.features, MPAM_FEATURE_LAST);
+	mpam_set_feature(mpam_feat_mbw_max, &fake_cfg);
+	mpam_extend_config(&fake_class, &fake_cfg);
+	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_max, &fake_cfg));
+	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_min, &fake_cfg));
+	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_max, 0xfeef);
+	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_min, 0xf224);
+
+	fake_class.props.bwa_wd = 8;
+	fake_cfg.mbw_max = 0xfeef;
+	fake_cfg.mbw_min = 0;
+	bitmap_zero(fake_cfg.features, MPAM_FEATURE_LAST);
+	mpam_set_feature(mpam_feat_mbw_max, &fake_cfg);
+	mpam_extend_config(&fake_class, &fake_cfg);
+	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_max, &fake_cfg));
+	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_min, &fake_cfg));
+	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_max, 0xfeef);
+	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_min, 0xf224);
+
+	/* 5% below the minimum granule, is still the minimum granule */
+	fake_class.props.bwa_wd = 12;
+	fake_cfg.mbw_max = 0xf;
+	fake_cfg.mbw_min = 0;
+	bitmap_zero(fake_cfg.features, MPAM_FEATURE_LAST);
+	mpam_set_feature(mpam_feat_mbw_max, &fake_cfg);
+	mpam_extend_config(&fake_class, &fake_cfg);
+	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_max, &fake_cfg));
+	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_min, &fake_cfg));
+	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_max, 0xf);
+	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_min, 0xf);
+
+	fake_class.props.bwa_wd = 16;
+	fake_cfg.mbw_max = 0x4;
+	fake_cfg.mbw_min = 0;
+	bitmap_zero(fake_cfg.features, MPAM_FEATURE_LAST);
+	mpam_set_feature(mpam_feat_mbw_max, &fake_cfg);
+	mpam_extend_config(&fake_class, &fake_cfg);
+	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_max, &fake_cfg));
+	KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_min, &fake_cfg));
+	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_max, 0x4);
+	KUNIT_EXPECT_EQ(test, fake_cfg.mbw_min, 0x0);
+}
+
 static void test_mpam_reset_msc_bitmap(struct kunit *test)
 {
 	char __iomem *buf = kunit_kzalloc(test, SZ_16K, GFP_KERNEL);
@@ -378,6 +443,7 @@ static struct kunit_case mpam_devices_test_cases[] = {
 	KUNIT_CASE(test_mpam_reset_msc_bitmap),
 	KUNIT_CASE(test_mpam_enable_merge_features),
 	KUNIT_CASE(test__props_mismatch),
+	KUNIT_CASE(test_mpam_extend_config),
 	{}
 };
 
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:43 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:43 +0000
Subject: [PATCH v2 41/45] arm_mpam: Add quirk framework
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-42-ben.horgan@arm.com>

From: Shanker Donthineni <sdonthineni at nvidia.com>

The MPAM specification includes the MPAMF_IIDR, which serves to uniquely
identify the MSC implementation through a combination of implementer
details, product ID, variant, and revision. Certain hardware issues/errata
can be resolved using software workarounds.

Introduce a quirk framework to allow workarounds to be enabled based on the
MPAMF_IIDR value.

[ morse: Stash the IIDR so this doesn't need an IPI, enable quirks only
once, move the description to the callback so it can be pr_once()d, add an
enum of workarounds for popular errata. Add macros for making lists of
product/revision/vendor half readable ]

Signed-off-by: Shanker Donthineni <sdonthineni at nvidia.com>
Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
Changes since rfc:
remove trailing commas in last element of enums
Make mpam_enable_quirks() in charge of mpam_set_quirk() even if there
is an enable.
---
 drivers/resctrl/mpam_devices.c  | 32 ++++++++++++++++++++++++++++++++
 drivers/resctrl/mpam_internal.h | 25 +++++++++++++++++++++++++
 2 files changed, 57 insertions(+)

diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index deea46c2a6c3..1c574b5710d8 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -630,6 +630,30 @@ static struct mpam_msc_ris *mpam_get_or_create_ris(struct mpam_msc *msc,
 	return ERR_PTR(-ENOENT);
 }
 
+static const struct mpam_quirk mpam_quirks[] = {
+	{ NULL } /* Sentinel */
+};
+
+static void mpam_enable_quirks(struct mpam_msc *msc)
+{
+	const struct mpam_quirk *quirk;
+
+	for (quirk = &mpam_quirks[0]; quirk->iidr_mask; quirk++) {
+		int err = 0;
+
+		if (quirk->iidr != (msc->iidr & quirk->iidr_mask))
+			continue;
+
+		if (quirk->init)
+			err = quirk->init(msc, quirk);
+
+		if (err)
+			continue;
+
+		mpam_set_quirk(quirk->workaround, msc);
+	}
+}
+
 /*
  * IHI009A.a has this nugget: "If a monitor does not support automatic behaviour
  * of NRDY, software can use this bit for any purpose" - so hardware might not
@@ -864,8 +888,11 @@ static int mpam_msc_hw_probe(struct mpam_msc *msc)
 	/* Grab an IDR value to find out how many RIS there are */
 	mutex_lock(&msc->part_sel_lock);
 	idr = mpam_msc_read_idr(msc);
+	msc->iidr = mpam_read_partsel_reg(msc, IIDR);
 	mutex_unlock(&msc->part_sel_lock);
 
+	mpam_enable_quirks(msc);
+
 	msc->ris_max = FIELD_GET(MPAMF_IDR_RIS_MAX, idr);
 
 	/* Use these values so partid/pmg always starts with a valid value */
@@ -1993,6 +2020,7 @@ static bool mpam_has_cmax_wd_feature(struct mpam_props *props)
  * resulting safe value must be compatible with both. When merging values in
  * the tree, all the aliasing resources must be handled first.
  * On mismatch, parent is modified.
+ * Quirks on an MSC will apply to all MSC in that class.
  */
 static void __props_mismatch(struct mpam_props *parent,
 			     struct mpam_props *child, bool alias)
@@ -2112,6 +2140,7 @@ static void __props_mismatch(struct mpam_props *parent,
  * nobble the class feature, as we can't configure all the resources.
  * e.g. The L3 cache is composed of two resources with 13 and 17 portion
  * bitmaps respectively.
+ * Quirks on an MSC will apply to all MSC in that class.
  */
 static void
 __class_props_mismatch(struct mpam_class *class, struct mpam_vmsc *vmsc)
@@ -2125,6 +2154,9 @@ __class_props_mismatch(struct mpam_class *class, struct mpam_vmsc *vmsc)
 	dev_dbg(dev, "Merging features for class:0x%lx &= vmsc:0x%lx\n",
 		(long)cprops->features, (long)vprops->features);
 
+	/* Merge quirks */
+	class->quirks |= vmsc->msc->quirks;
+
 	/* Take the safe value for any common features */
 	__props_mismatch(cprops, vprops, false);
 }
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index cc580dea9430..5989f3670af3 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -85,6 +85,8 @@ struct mpam_msc {
 	u8			pmg_max;
 	unsigned long		ris_idxs;
 	u32			ris_max;
+	u32			iidr;
+	u16			quirks;
 
 	/*
 	 * error_irq_lock is taken when registering/unregistering the error
@@ -212,6 +214,28 @@ struct mpam_props {
 #define mpam_set_feature(_feat, x)	__set_bit(_feat, (x)->features)
 #define mpam_clear_feature(_feat, x)	__clear_bit(_feat, (x)->features)
 
+/* Workaround bits for msc->quirks */
+enum mpam_device_quirks {
+	MPAM_QUIRK_LAST
+};
+
+#define mpam_has_quirk(_quirk, x)	((1 << (_quirk) & (x)->quirks))
+#define mpam_set_quirk(_quirk, x)	((x)->quirks |= (1 << (_quirk)))
+
+struct mpam_quirk {
+	int (*init)(struct mpam_msc *msc, const struct mpam_quirk *quirk);
+
+	u32 iidr;
+	u32 iidr_mask;
+
+	enum mpam_device_quirks workaround;
+};
+
+#define MPAM_IIDR_MATCH_ONE	FIELD_PREP_CONST(MPAMF_IIDR_PRODUCTID,   0xfff)	| \
+				FIELD_PREP_CONST(MPAMF_IIDR_VARIANT,     0xf)	| \
+				FIELD_PREP_CONST(MPAMF_IIDR_REVISION,    0xf)	| \
+				FIELD_PREP_CONST(MPAMF_IIDR_IMPLEMENTER, 0xfff)
+
 /* The values for MSMON_CFG_MBWU_FLT.RWBW */
 enum mon_filter_options {
 	COUNT_BOTH	= 0,
@@ -255,6 +279,7 @@ struct mpam_class {
 
 	struct mpam_props	props;
 	u32			nrdy_usec;
+	u16			quirks;
 	u8			level;
 	enum mpam_class_types	type;
 
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:44 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:44 +0000
Subject: [PATCH v2 42/45] arm_mpam: Add workaround for T241-MPAM-1
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-43-ben.horgan@arm.com>

From: Shanker Donthineni <sdonthineni at nvidia.com>

The MPAM bandwidth partitioning controls will not be correctly configured,
and hardware will retain default configuration register values, meaning
generally that bandwidth will remain unprovisioned.

To address the issue, follow the below steps after updating the MBW_MIN
and/or MBW_MAX registers.

 - Perform 64b reads from all 12 bridge MPAM shadow registers at offsets
   (0x360048 + slice*0x10000 + partid*8). These registers are read-only.
 - Continue iterating until all 12 shadow register values match in a loop.
   pr_warn_once if the values fail to match within the loop count 1000.
 - Perform 64b writes with the value 0x0 to the two spare registers at
   offsets 0x1b0000 and 0x1c0000.

In the hardware, writes to the MPAMCFG_MBW_MAX MPAMCFG_MBW_MIN registers
are transformed into broadcast writes to the 12 shadow registers. The
final two writes to the spare registers cause a final rank of downstream
micro-architectural MPAM registers to be updated from the shadow copies.
The intervening loop to read the 12 shadow registers helps avoid a race
condition where writes to the spare registers occur before all shadow
registers have been updated.

[ morse: Merged the min/max update into a single
  mpam_quirk_post_config_change() helper. Stashed the t241_id in the msc
  instead of carrying the physical address around. Test the msc quirk bit
  instead of a static key. ]

Signed-off-by: Shanker Donthineni <sdonthineni at nvidia.com>
Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
Changes since rfc:
MPAM_IIDR_NVIDIA_T421 -> MPAM_IIDR_NVIDIA_T241
return err from init
Be specific about the errata in the init name,
  mpam_enable_quirk_nvidia_t241 -> mpam_enable_quirk_nvidia_t241_1
---
 Documentation/arch/arm64/silicon-errata.rst |  2 +
 drivers/resctrl/mpam_devices.c              | 88 +++++++++++++++++++++
 drivers/resctrl/mpam_internal.h             |  9 +++
 3 files changed, 99 insertions(+)

diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst
index a7ec57060f64..4e86b85fe3d6 100644
--- a/Documentation/arch/arm64/silicon-errata.rst
+++ b/Documentation/arch/arm64/silicon-errata.rst
@@ -246,6 +246,8 @@ stable kernels.
 +----------------+-----------------+-----------------+-----------------------------+
 | NVIDIA         | T241 GICv3/4.x  | T241-FABRIC-4   | N/A                         |
 +----------------+-----------------+-----------------+-----------------------------+
+| NVIDIA         | T241 MPAM       | T241-MPAM-1     | N/A                         |
++----------------+-----------------+-----------------+-----------------------------+
 +----------------+-----------------+-----------------+-----------------------------+
 | Freescale/NXP  | LS2080A/LS1043A | A-008585        | FSL_ERRATUM_A008585         |
 +----------------+-----------------+-----------------+-----------------------------+
diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index 1c574b5710d8..1b923a44f304 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -29,6 +29,16 @@
 
 #include "mpam_internal.h"
 
+/* Values for the T241 errata workaround */
+#define T241_CHIPS_MAX			4
+#define T241_CHIP_NSLICES		12
+#define T241_SPARE_REG0_OFF		0x1b0000
+#define T241_SPARE_REG1_OFF		0x1c0000
+#define T241_CHIP_ID(phys)		FIELD_GET(GENMASK_ULL(44, 43), phys)
+#define T241_SHADOW_REG_OFF(sidx, pid)	(0x360048 + (sidx) * 0x10000 + (pid) * 8)
+#define SMCCC_SOC_ID_T241		0x036b0241
+static void __iomem *t241_scratch_regs[T241_CHIPS_MAX];
+
 /*
  * mpam_list_lock protects the SRCU lists when writing. Once the
  * mpam_enabled key is enabled these lists are read-only,
@@ -630,7 +640,45 @@ static struct mpam_msc_ris *mpam_get_or_create_ris(struct mpam_msc *msc,
 	return ERR_PTR(-ENOENT);
 }
 
+static int mpam_enable_quirk_nvidia_t241_1(struct mpam_msc *msc,
+					  const struct mpam_quirk *quirk)
+{
+	s32 soc_id = arm_smccc_get_soc_id_version();
+	struct resource *r;
+	phys_addr_t phys;
+
+	/*
+	 * A mapping to a device other than the MSC is needed, check
+	 * SOC_ID is  NVIDIA T241 chip (036b:0241)
+	 */
+	if (soc_id < 0 || soc_id != SMCCC_SOC_ID_T241)
+		return -EINVAL;
+
+	r = platform_get_resource(msc->pdev, IORESOURCE_MEM, 0);
+	if (!r)
+		return -EINVAL;
+
+	/* Find the internal registers base addr from the CHIP ID */
+	msc->t241_id = T241_CHIP_ID(r->start);
+	phys = FIELD_PREP(GENMASK_ULL(45, 44), msc->t241_id) | 0x19000000ULL;
+
+	t241_scratch_regs[msc->t241_id] = ioremap(phys, SZ_8M);
+	if (WARN_ON_ONCE(!t241_scratch_regs[msc->t241_id]))
+		return -EINVAL;
+
+	pr_info_once("Enabled workaround for NVIDIA T241 erratum T241-MPAM-1\n");
+
+	return 0;
+}
+
 static const struct mpam_quirk mpam_quirks[] = {
+	{
+	/* NVIDIA t241 erratum T241-MPAM-1 */
+	.init       = mpam_enable_quirk_nvidia_t241_1,
+	.iidr       = MPAM_IIDR_NVIDIA_T241,
+	.iidr_mask  = MPAM_IIDR_MATCH_ONE,
+	.workaround = T241_SCRUB_SHADOW_REGS,
+	},
 	{ NULL } /* Sentinel */
 };
 
@@ -1378,6 +1426,44 @@ static void mpam_reset_msc_bitmap(struct mpam_msc *msc, u16 reg, u16 wd)
 	__mpam_write_reg(msc, reg, bm);
 }
 
+static void mpam_apply_t241_erratum(struct mpam_msc_ris *ris, u16 partid)
+{
+	int sidx, i, lcount = 1000;
+	void __iomem *regs;
+	u64 val0, val;
+
+	regs = t241_scratch_regs[ris->vmsc->msc->t241_id];
+
+	for (i = 0; i < lcount; i++) {
+		/* Read the shadow register at index 0 */
+		val0 = readq_relaxed(regs + T241_SHADOW_REG_OFF(0, partid));
+
+		/* Check if all the shadow registers have the same value */
+		for (sidx = 1; sidx < T241_CHIP_NSLICES; sidx++) {
+			val = readq_relaxed(regs +
+					    T241_SHADOW_REG_OFF(sidx, partid));
+			if (val != val0)
+				break;
+		}
+		if (sidx == T241_CHIP_NSLICES)
+			break;
+	}
+
+	if (i == lcount)
+		pr_warn_once("t241: inconsistent values in shadow regs");
+
+	/* Write a value zero to spare registers to take effect of MBW conf */
+	writeq_relaxed(0, regs + T241_SPARE_REG0_OFF);
+	writeq_relaxed(0, regs + T241_SPARE_REG1_OFF);
+}
+
+static void mpam_quirk_post_config_change(struct mpam_msc_ris *ris, u16 partid,
+					  struct mpam_config *cfg)
+{
+	if (mpam_has_quirk(T241_SCRUB_SHADOW_REGS, ris->vmsc->msc))
+		mpam_apply_t241_erratum(ris, partid);
+}
+
 /* Called via IPI. Call while holding an SRCU reference */
 static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
 				      struct mpam_config *cfg)
@@ -1465,6 +1551,8 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
 		mpam_write_partsel_reg(msc, PRI, pri_val);
 	}
 
+	mpam_quirk_post_config_change(ris, partid, cfg);
+
 	mutex_unlock(&msc->part_sel_lock);
 }
 
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index 5989f3670af3..871ca2169173 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -130,6 +130,9 @@ struct mpam_msc {
 	void __iomem		*mapped_hwpage;
 	size_t			mapped_hwpage_sz;
 
+	/* Values only used on some platforms for quirks */
+	u32			t241_id;
+
 	struct mpam_garbage	garbage;
 };
 
@@ -216,6 +219,7 @@ struct mpam_props {
 
 /* Workaround bits for msc->quirks */
 enum mpam_device_quirks {
+	T241_SCRUB_SHADOW_REGS,
 	MPAM_QUIRK_LAST
 };
 
@@ -236,6 +240,11 @@ struct mpam_quirk {
 				FIELD_PREP_CONST(MPAMF_IIDR_REVISION,    0xf)	| \
 				FIELD_PREP_CONST(MPAMF_IIDR_IMPLEMENTER, 0xfff)
 
+#define MPAM_IIDR_NVIDIA_T241	FIELD_PREP_CONST(MPAMF_IIDR_PRODUCTID,   0x241)	| \
+				FIELD_PREP_CONST(MPAMF_IIDR_VARIANT,     0)	| \
+				FIELD_PREP_CONST(MPAMF_IIDR_REVISION,    0)	| \
+				FIELD_PREP_CONST(MPAMF_IIDR_IMPLEMENTER, 0x36b)
+
 /* The values for MSMON_CFG_MBWU_FLT.RWBW */
 enum mon_filter_options {
 	COUNT_BOTH	= 0,
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:46 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:46 +0000
Subject: [PATCH v2 44/45] arm_mpam: Add workaround for T241-MPAM-6
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-45-ben.horgan@arm.com>

From: Shanker Donthineni <sdonthineni at nvidia.com>

The registers MSMON_MBWU_L and MSMON_MBWU return the number of requests
rather than the number of bytes transferred.

Bandwidth resource monitoring is performed at the last level cache, where
each request arrive in 64Byte granularity. The current implementation
returns the number of transactions received at the last level cache but
does not provide the value in bytes. Scaling by 64 gives an accurate byte
count to match the MPAM specification for the MSMON_MBWU and MSMON_MBWU_L
registers. This patch fixes the issue by reporting the actual number of
bytes instead of the number of transactions from __ris_msmon_read().

Signed-off-by: Shanker Donthineni <sdonthineni at nvidia.com>
Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
Changes since rfc:
MPAM_IIDR_NVIDIA_T421 -> MPAM_IIDR_NVIDIA_T241
Don't apply workaround to MSMON_MBWU_LWD
---
 Documentation/arch/arm64/silicon-errata.rst |  2 ++
 drivers/resctrl/mpam_devices.c              | 26 +++++++++++++++++++--
 drivers/resctrl/mpam_internal.h             |  1 +
 3 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst
index b18bc704d4a1..e810b2a8f40e 100644
--- a/Documentation/arch/arm64/silicon-errata.rst
+++ b/Documentation/arch/arm64/silicon-errata.rst
@@ -250,6 +250,8 @@ stable kernels.
 +----------------+-----------------+-----------------+-----------------------------+
 | NVIDIA         | T241 MPAM       | T241-MPAM-4     | N/A                         |
 +----------------+-----------------+-----------------+-----------------------------+
+| NVIDIA         | T241 MPAM       | T241-MPAM-6     | N/A                         |
++----------------+-----------------+-----------------+-----------------------------+
 +----------------+-----------------+-----------------+-----------------------------+
 | Freescale/NXP  | LS2080A/LS1043A | A-008585        | FSL_ERRATUM_A008585         |
 +----------------+-----------------+-----------------+-----------------------------+
diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index 76aa8654fc74..912736cd86b6 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -685,6 +685,12 @@ static const struct mpam_quirk mpam_quirks[] = {
 	.iidr_mask  = MPAM_IIDR_MATCH_ONE,
 	.workaround = T241_FORCE_MBW_MIN_TO_ONE,
 	},
+	{
+	/* NVIDIA t241 erratum T241-MPAM-6 */
+	.iidr       = MPAM_IIDR_NVIDIA_T241,
+	.iidr_mask  = MPAM_IIDR_MATCH_ONE,
+	.workaround = T241_MBW_COUNTER_SCALE_64,
+	},
 	{ NULL } /* Sentinel */
 };
 
@@ -1146,7 +1152,7 @@ static void write_msmon_ctl_flt_vals(struct mon_read *m, u32 ctl_val,
 	}
 }
 
-static u64 mpam_msmon_overflow_val(enum mpam_device_features type)
+static u64 __mpam_msmon_overflow_val(enum mpam_device_features type)
 {
 	/* TODO: implement scaling counters */
 	switch (type) {
@@ -1161,6 +1167,18 @@ static u64 mpam_msmon_overflow_val(enum mpam_device_features type)
 	}
 }
 
+static u64 mpam_msmon_overflow_val(enum mpam_device_features type,
+				   struct mpam_msc *msc)
+{
+	u64 overflow_val = __mpam_msmon_overflow_val(type);
+
+	if (mpam_has_quirk(T241_MBW_COUNTER_SCALE_64, msc) &&
+	    type != mpam_feat_msmon_mbwu_63counter)
+		overflow_val *= 64;
+
+	return overflow_val;
+}
+
 static void __ris_msmon_read(void *arg)
 {
 	u64 now;
@@ -1251,13 +1269,17 @@ static void __ris_msmon_read(void *arg)
 			now = FIELD_GET(MSMON___VALUE, now);
 		}
 
+		if (mpam_has_quirk(T241_MBW_COUNTER_SCALE_64, msc) &&
+		    m->type != mpam_feat_msmon_mbwu_63counter)
+			now *= 64;
+
 		if (nrdy)
 			break;
 
 		mbwu_state = &ris->mbwu_state[ctx->mon];
 
 		if (overflow)
-			mbwu_state->correction += mpam_msmon_overflow_val(m->type);
+			mbwu_state->correction += mpam_msmon_overflow_val(m->type, msc);
 
 		/*
 		 * Include bandwidth consumed before the last hardware reset and
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index b4f2505519b2..1e7574a9d244 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -221,6 +221,7 @@ struct mpam_props {
 enum mpam_device_quirks {
 	T241_SCRUB_SHADOW_REGS,
 	T241_FORCE_MBW_MIN_TO_ONE,
+	T241_MBW_COUNTER_SCALE_64,
 	MPAM_QUIRK_LAST
 };
 
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:45 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:45 +0000
Subject: [PATCH v2 43/45] arm_mpam: Add workaround for T241-MPAM-4
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-44-ben.horgan@arm.com>

From: Shanker Donthineni <sdonthineni at nvidia.com>

In the T241 implementation of memory-bandwidth partitioning, in the absence
of contention for bandwidth, the minimum bandwidth setting can affect the
amount of achieved bandwidth. Specifically, the achieved bandwidth in the
absence of contention can settle to any value between the values of
MPAMCFG_MBW_MIN and MPAMCFG_MBW_MAX.  Also, if MPAMCFG_MBW_MIN is set
zero (below 0.78125%), once a core enters a throttled state, it will never
leave that state.

The first issue is not a cocern if the MPAM software allows to program
MPAMCFG_MBW_MIN through the sysfs interface. This patch ensures program
MBW_MIN=1 (0.78125%) whenever MPAMCFG_MBW_MIN=0 is programmed.

In the scenario where the resctrl doesn't support the MBW_MIN interface via
sysfs, to achieve bandwidth closer to MW_MAX in the absence of contention,
software should configure a relatively narrow gap between MBW_MIN and
MBW_MAX. The recommendation is to use a 5% gap to mitigate the problem.

[ morse: Added as second quirk, adapted to use the new intermediate values
in mpam_extend_config() ]

Signed-off-by: Shanker Donthineni <sdonthineni at nvidia.com>
Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
Changes since rfc:
MPAM_IIDR_NVIDIA_T421 -> MPAM_IIDR_NVIDIA_T241
Handling when reset_mbw_min is set
---
 Documentation/arch/arm64/silicon-errata.rst |  2 +
 drivers/resctrl/mpam_devices.c              | 59 +++++++++++++++------
 drivers/resctrl/mpam_internal.h             |  1 +
 3 files changed, 46 insertions(+), 16 deletions(-)

diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst
index 4e86b85fe3d6..b18bc704d4a1 100644
--- a/Documentation/arch/arm64/silicon-errata.rst
+++ b/Documentation/arch/arm64/silicon-errata.rst
@@ -248,6 +248,8 @@ stable kernels.
 +----------------+-----------------+-----------------+-----------------------------+
 | NVIDIA         | T241 MPAM       | T241-MPAM-1     | N/A                         |
 +----------------+-----------------+-----------------+-----------------------------+
+| NVIDIA         | T241 MPAM       | T241-MPAM-4     | N/A                         |
++----------------+-----------------+-----------------+-----------------------------+
 +----------------+-----------------+-----------------+-----------------------------+
 | Freescale/NXP  | LS2080A/LS1043A | A-008585        | FSL_ERRATUM_A008585         |
 +----------------+-----------------+-----------------+-----------------------------+
diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index 1b923a44f304..76aa8654fc74 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -679,6 +679,12 @@ static const struct mpam_quirk mpam_quirks[] = {
 	.iidr_mask  = MPAM_IIDR_MATCH_ONE,
 	.workaround = T241_SCRUB_SHADOW_REGS,
 	},
+	{
+	/* NVIDIA t241 erratum T241-MPAM-4 */
+	.iidr       = MPAM_IIDR_NVIDIA_T241,
+	.iidr_mask  = MPAM_IIDR_MATCH_ONE,
+	.workaround = T241_FORCE_MBW_MIN_TO_ONE,
+	},
 	{ NULL } /* Sentinel */
 };
 
@@ -1464,6 +1470,17 @@ static void mpam_quirk_post_config_change(struct mpam_msc_ris *ris, u16 partid,
 		mpam_apply_t241_erratum(ris, partid);
 }
 
+static u16 mpam_wa_t241_force_mbw_min_to_one(struct mpam_props *props)
+{
+	u16 max_hw_value, min_hw_granule, res0_bits;
+
+	res0_bits = 16 - props->bwa_wd;
+	max_hw_value = ((1 << props->bwa_wd) - 1) << res0_bits;
+	min_hw_granule = ~max_hw_value;
+
+	return min_hw_granule + 1;
+}
+
 /* Called via IPI. Call while holding an SRCU reference */
 static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
 				      struct mpam_config *cfg)
@@ -1508,10 +1525,15 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
 
 	if (mpam_has_feature(mpam_feat_mbw_min, rprops) &&
 	    mpam_has_feature(mpam_feat_mbw_min, cfg)) {
-		if (cfg->reset_mbw_min)
-			mpam_write_partsel_reg(msc, MBW_MIN, 0);
-		else
+		if (cfg->reset_mbw_min) {
+			u16 reset = 0;
+
+			if (mpam_has_quirk(T241_FORCE_MBW_MIN_TO_ONE, msc))
+				reset = mpam_wa_t241_force_mbw_min_to_one(rprops);
+			mpam_write_partsel_reg(msc, MBW_MIN, reset);
+		} else {
 			mpam_write_partsel_reg(msc, MBW_MIN, cfg->mbw_min);
+		}
 	}
 
 	if (mpam_has_feature(mpam_feat_mbw_max, rprops) &&
@@ -2539,6 +2561,18 @@ static void mpam_extend_config(struct mpam_class *class, struct mpam_config *cfg
 	u16 min, min_hw_granule, delta;
 	u16 max_hw_value, res0_bits;
 
+	/*
+	 * Calculate the values the 'min' control can hold.
+	 * e.g. on a platform with bwa_wd = 8, min_hw_granule is 0x00ff because
+	 * those bits are RES0. Configurations of this value are effectively
+	 * zero. But configurations need to saturate at min_hw_granule on
+	 * systems with mismatched bwa_wd, where the 'less than 0' values are
+	 * implemented on some MSC, but not others.
+	 */
+	res0_bits = 16 - cprops->bwa_wd;
+	max_hw_value = ((1 << cprops->bwa_wd) - 1) << res0_bits;
+	min_hw_granule = ~max_hw_value;
+
 	/*
 	 * MAX and MIN should be set together. If only one is provided,
 	 * generate a configuration for the other. If only one control
@@ -2548,19 +2582,6 @@ static void mpam_extend_config(struct mpam_class *class, struct mpam_config *cfg
 	 */
 	if (mpam_has_feature(mpam_feat_mbw_max, cfg) &&
 	    !mpam_has_feature(mpam_feat_mbw_min, cfg)) {
-		/*
-		 * Calculate the values the 'min' control can hold.
-		 * e.g. on a platform with bwa_wd = 8, min_hw_granule is 0x00ff
-		 * because those bits are RES0. Configurations of this value
-		 * are effectively zero. But configurations need to saturate
-		 * at min_hw_granule on systems with mismatched bwa_wd, where
-		 * the 'less than 0' values are implemented on some MSC, but
-		 * not others.
-		 */
-		res0_bits = 16 - cprops->bwa_wd;
-		max_hw_value = ((1 << cprops->bwa_wd) - 1) << res0_bits;
-		min_hw_granule = ~max_hw_value;
-
 		delta = ((5 * MPAMCFG_MBW_MAX_MAX) / 100) - 1;
 		if (cfg->mbw_max > delta)
 			min = cfg->mbw_max - delta;
@@ -2570,6 +2591,12 @@ static void mpam_extend_config(struct mpam_class *class, struct mpam_config *cfg
 		cfg->mbw_min = max(min, min_hw_granule);
 		mpam_set_feature(mpam_feat_mbw_min, cfg);
 	}
+
+	if (mpam_has_quirk(T241_FORCE_MBW_MIN_TO_ONE, class) &&
+	    cfg->mbw_min <= min_hw_granule) {
+		cfg->mbw_min = min_hw_granule + 1;
+		mpam_set_feature(mpam_feat_mbw_min, cfg);
+	}
 }
 
 static void mpam_reset_component_cfg(struct mpam_component *comp)
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index 871ca2169173..b4f2505519b2 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -220,6 +220,7 @@ struct mpam_props {
 /* Workaround bits for msc->quirks */
 enum mpam_device_quirks {
 	T241_SCRUB_SHADOW_REGS,
+	T241_FORCE_MBW_MIN_TO_ONE,
 	MPAM_QUIRK_LAST
 };
 
-- 
2.43.0



From ben.horgan at arm.com  Fri Dec 19 10:11:47 2025
From: ben.horgan at arm.com (Ben Horgan)
Date: Fri, 19 Dec 2025 18:11:47 +0000
Subject: [PATCH v2 45/45] arm_mpam: Quirk CMN-650's CSU NRDY behaviour
In-Reply-To: <20251219181147.3404071-1-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
Message-ID: <20251219181147.3404071-46-ben.horgan@arm.com>

From: James Morse <james.morse at arm.com>

CMN-650 is afflicted with an erratum where the CSU NRDY bit never clears.
This tells us the monitor never finishes scanning the cache. The erratum
document says to wait the maximum time, then ignore the field.

Add a flag to indicate whether this is the final attempt to read the
counter, and when this quirk is applied, ignore the NRDY field.

This means accesses to this counter will always retry, even if the counter
was previously programmed to the same values.

The counter value is not expected to be stable, it drifts up and down with
each allocation and eviction. The CSU register provides the value for a
point in time.

Signed-off-by: James Morse <james.morse at arm.com>
Signed-off-by: Ben Horgan <ben.horgan at arm.com>
---
 Documentation/arch/arm64/silicon-errata.rst |  3 +++
 drivers/resctrl/mpam_devices.c              | 12 ++++++++++++
 drivers/resctrl/mpam_internal.h             |  6 ++++++
 3 files changed, 21 insertions(+)

diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst
index e810b2a8f40e..3667650036fb 100644
--- a/Documentation/arch/arm64/silicon-errata.rst
+++ b/Documentation/arch/arm64/silicon-errata.rst
@@ -213,6 +213,9 @@ stable kernels.
 | ARM            | GIC-700         | #2941627        | ARM64_ERRATUM_2941627       |
 +----------------+-----------------+-----------------+-----------------------------+
 +----------------+-----------------+-----------------+-----------------------------+
+| ARM            | CMN-650         | #3642720        | N/A                         |
++----------------+-----------------+-----------------+-----------------------------+
++----------------+-----------------+-----------------+-----------------------------+
 | Broadcom       | Brahma-B53      | N/A             | ARM64_ERRATUM_845719        |
 +----------------+-----------------+-----------------+-----------------------------+
 | Broadcom       | Brahma-B53      | N/A             | ARM64_ERRATUM_843419        |
diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index 912736cd86b6..e0b27eb77fa7 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -691,6 +691,12 @@ static const struct mpam_quirk mpam_quirks[] = {
 	.iidr_mask  = MPAM_IIDR_MATCH_ONE,
 	.workaround = T241_MBW_COUNTER_SCALE_64,
 	},
+	{
+	/* ARM CMN-650 CSU erratum 3642720 */
+	.iidr       = MPAM_IIDR_ARM_CMN_650,
+	.iidr_mask  = MPAM_IIDR_MATCH_ONE,
+	.workaround = IGNORE_CSU_NRDY,
+	},
 	{ NULL } /* Sentinel */
 };
 
@@ -1003,6 +1009,7 @@ struct mon_read {
 	enum mpam_device_features	type;
 	u64				*val;
 	int				err;
+	bool				waited_timeout;
 };
 
 static bool mpam_ris_has_mbwu_long_counter(struct mpam_msc_ris *ris)
@@ -1249,6 +1256,10 @@ static void __ris_msmon_read(void *arg)
 		if (mpam_has_feature(mpam_feat_msmon_csu_hw_nrdy, rprops))
 			nrdy = now & MSMON___NRDY;
 		now = FIELD_GET(MSMON___VALUE, now);
+
+		if (mpam_has_quirk(IGNORE_CSU_NRDY, msc) && m->waited_timeout)
+			nrdy = false;
+
 		break;
 	case mpam_feat_msmon_mbwu_31counter:
 	case mpam_feat_msmon_mbwu_44counter:
@@ -1386,6 +1397,7 @@ int mpam_msmon_read(struct mpam_component *comp, struct mon_cfg *ctx,
 			.ctx = ctx,
 			.type = type,
 			.val = val,
+			.waited_timeout = true,
 		};
 		*val = 0;
 
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index 1e7574a9d244..e206decd3048 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -222,6 +222,7 @@ enum mpam_device_quirks {
 	T241_SCRUB_SHADOW_REGS,
 	T241_FORCE_MBW_MIN_TO_ONE,
 	T241_MBW_COUNTER_SCALE_64,
+	IGNORE_CSU_NRDY,
 	MPAM_QUIRK_LAST
 };
 
@@ -247,6 +248,11 @@ struct mpam_quirk {
 				FIELD_PREP_CONST(MPAMF_IIDR_REVISION,    0)	| \
 				FIELD_PREP_CONST(MPAMF_IIDR_IMPLEMENTER, 0x36b)
 
+#define MPAM_IIDR_ARM_CMN_650	FIELD_PREP_CONST(MPAMF_IIDR_PRODUCTID,   0)	| \
+				FIELD_PREP_CONST(MPAMF_IIDR_VARIANT,     0)	| \
+				FIELD_PREP_CONST(MPAMF_IIDR_REVISION,    0)	| \
+				FIELD_PREP_CONST(MPAMF_IIDR_IMPLEMENTER, 0x43b)
+
 /* The values for MSMON_CFG_MBWU_FLT.RWBW */
 enum mon_filter_options {
 	COUNT_BOTH	= 0,
-- 
2.43.0



From bvanassche at acm.org  Fri Dec 19 10:16:16 2025
From: bvanassche at acm.org (Bart Van Assche)
Date: Fri, 19 Dec 2025 10:16:16 -0800
Subject: [PATCH v2 0/8] scsi: Make use of bus callbacks
In-Reply-To: <cover.1766133330.git.u.kleine-koenig@baylibre.com>
References: <cover.1766133330.git.u.kleine-koenig@baylibre.com>
Message-ID: <4594adaa-6ff5-4157-ad40-df2009126f89@acm.org>

On 12/19/25 1:25 AM, Uwe Kleine-K?nig wrote:
> this is v2 of the series to make the scsi subsystem stop using the
> callbacks .probe(), .remove() and .shutdown() of struct device_driver.
> Instead use their designated alternatives in struct bus_type.
> 
> The eventual goal is to drop the callbacks from struct device_driver.
> 
> The 2nd patch introduces some legacy handling for drivers still using
> the device_driver callbacks. This results in a runtime warning (in
> driver_register()). The following patches convert all in-tree drivers
> (and thus fix the warnings one after another).
> Conceptually this legacy handling could be dropped at the end of the
> series, but I think this is a bad idea because this silently breaks
> out-of-tree drivers (which also covers drivers that are currently
> prepared for mainline submission) and in-tree drivers I might have
> missed (though I'm convinced I catched them all). That convinces me that
> keeping the legacy handling for at least one development cycle is the
> right choice. I'll care for that at the latest when I remove the
> callbacks from struct device_driver.

For the entire series:

Reviewed-by: Bart Van Assche <bvanassche at acm.org>


From bvanassche at acm.org  Fri Dec 19 10:18:29 2025
From: bvanassche at acm.org (Bart Van Assche)
Date: Fri, 19 Dec 2025 10:18:29 -0800
Subject: [PATCH v2 2/8] scsi: Make use of bus callbacks
In-Reply-To: <a54e363a3fd2054fb924afd7df44bca7f444b5f1.1766133330.git.u.kleine-koenig@baylibre.com>
References: <cover.1766133330.git.u.kleine-koenig@baylibre.com>
 <a54e363a3fd2054fb924afd7df44bca7f444b5f1.1766133330.git.u.kleine-koenig@baylibre.com>
Message-ID: <e49c1ea8-bc13-4881-bc6b-2e1a08b1184f@acm.org>

On 12/19/25 1:25 AM, Uwe Kleine-K?nig wrote:
> +static int scsi_bus_probe(struct device *dev)
> +{
> +	struct scsi_device *sdp = to_scsi_device(dev);
> +	struct scsi_driver *drv = to_scsi_driver(dev->driver);
> +
> +	if (drv->probe)
> +		return drv->probe(sdp);
> +	else
> +		return 0;
> +}

If this series has to be reposted, please leave out the "else" statement
from the above function. It is uncommon in Linux kernel code to have an
"else" statement after a "return" statement.

Thanks,

Bart.


From puranjay at kernel.org  Fri Dec 19 10:23:38 2025
From: puranjay at kernel.org (Puranjay Mohan)
Date: Fri, 19 Dec 2025 18:23:38 +0000
Subject: [PATCH bpf-next v2 2/2] bpf: arm64: Optimize recursion detection
 by not using atomics
In-Reply-To: <1728d4e1-ce5c-476e-b057-b8a9a7621e1b@linux.dev>
References: <20251217233608.2374187-1-puranjay@kernel.org> <20251217233608.2374187-3-puranjay@kernel.org>
 <1728d4e1-ce5c-476e-b057-b8a9a7621e1b@linux.dev>
Message-ID: <CANk7y0iGCwKss5Mbdq8+-Xp8d_TRr1tPY4DcAFCPgpFiQW8otg@mail.gmail.com>

On Thu, Dec 18, 2025 at 5:56?PM Yonghong Song <yonghong.song at linux.dev> wrote:
>
>
>
> On 12/17/25 3:35 PM, Puranjay Mohan wrote:
> > BPF programs detect recursion using a per-CPU 'active' flag in struct
> > bpf_prog. The trampoline currently sets/clears this flag with atomic
> > operations.
> >
> > On some arm64 platforms (e.g., Neoverse V2 with LSE), per-CPU atomic
> > operations are relatively slow. Unlike x86_64 - where per-CPU updates
> > can avoid cross-core atomicity, arm64 LSE atomics are always atomic
> > across all cores, which is unnecessary overhead for strictly per-CPU
> > state.
> >
> > This patch removes atomics from the recursion detection path on arm64 by
> > changing 'active' to a per-CPU array of four u8 counters, one per
> > context: {NMI, hard-irq, soft-irq, normal}. The running context uses a
> > non-atomic increment/decrement on its element.  After increment,
> > recursion is detected by reading the array as a u32 and verifying that
> > only the expected element changed; any change in another element
> > indicates inter-context recursion, and a value > 1 in the same element
> > indicates same-context recursion.
> >
> > For example, starting from {0,0,0,0}, a normal-context trigger changes
> > the array to {0,0,0,1}.  If an NMI arrives on the same CPU and triggers
> > the program, the array becomes {1,0,0,1}. When the NMI context checks
> > the u32 against the expected mask for normal (0x00000001), it observes
> > 0x01000001 and correctly reports recursion. Same-context recursion is
> > detected analogously.
> >
> > Signed-off-by: Puranjay Mohan <puranjay at kernel.org>
>
> LGTM with a few nits below.
>
> Acked-by: Yonghong Song <yonghong.song at linux.dev>
>
> > ---
> >   include/linux/bpf.h | 33 ++++++++++++++++++++++++++++++---
> >   kernel/bpf/core.c   |  3 ++-
> >   2 files changed, 32 insertions(+), 4 deletions(-)
> >
> > diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> > index 2da986136d26..5ca2a761d9a1 100644
> > --- a/include/linux/bpf.h
> > +++ b/include/linux/bpf.h
> > @@ -31,6 +31,7 @@
> >   #include <linux/static_call.h>
> >   #include <linux/memcontrol.h>
> >   #include <linux/cfi.h>
> > +#include <linux/unaligned.h>
> >   #include <asm/rqspinlock.h>
> >
> >   struct bpf_verifier_env;
> > @@ -1746,6 +1747,8 @@ struct bpf_prog_aux {
> >       struct bpf_map __rcu *st_ops_assoc;
> >   };
> >
> > +#define BPF_NR_CONTEXTS        4       /* normal, softirq, hardirq, NMI */
> > +
> >   struct bpf_prog {
> >       u16                     pages;          /* Number of allocated pages */
> >       u16                     jited:1,        /* Is our filter JIT'ed? */
> > @@ -1772,7 +1775,7 @@ struct bpf_prog {
> >               u8 tag[BPF_TAG_SIZE];
> >       };
> >       struct bpf_prog_stats __percpu *stats;
> > -     int __percpu            *active;
> > +     u8 __percpu             *active;        /* u8[BPF_NR_CONTEXTS] for rerecursion protection */
> >       unsigned int            (*bpf_func)(const void *ctx,
> >                                           const struct bpf_insn *insn);
> >       struct bpf_prog_aux     *aux;           /* Auxiliary fields */
> > @@ -2006,12 +2009,36 @@ struct bpf_struct_ops_common_value {
> >
> >   static inline bool bpf_prog_get_recursion_context(struct bpf_prog *prog)
> >   {
> > -     return this_cpu_inc_return(*(prog->active)) == 1;
> > +#ifdef CONFIG_ARM64
> > +     u8 rctx = interrupt_context_level();
> > +     u8 *active = this_cpu_ptr(prog->active);
> > +     u32 val;
> > +
> > +     preempt_disable();
> > +     active[rctx]++;
> > +     val = get_unaligned_le32(active);
>
> The 'active' already aligned with 8 (or 4 with my below suggestion).
> The get_unaligned_le32() works, but maybe we could use le32_to_cpu()
> instead. Maybe there is no performance difference between
> get_unaligned_le32() and le32_to_cpu() so you pick get_unaligned_le32()?
> It would be good to clarify in commit message if get_unaligned_le32()
> is used.

I will just use val = le32_to_cpu(*(__le32 *)active);

Thanks,
Puranjay


From puranjay at kernel.org  Fri Dec 19 10:44:16 2025
From: puranjay at kernel.org (Puranjay Mohan)
Date: Fri, 19 Dec 2025 10:44:16 -0800
Subject: [PATCH bpf-next v3 0/2] bpf: Optimize recursion detection on arm64
Message-ID: <20251219184422.2899902-1-puranjay@kernel.org>

V2: https://lore.kernel.org/all/20251217233608.2374187-1-puranjay at kernel.org/
Changes in v2->v3:
- Added acked by Yonghong
- Patch 2:
        - Change alignment of active from 8 to 4
        - Use le32_to_cpu in place of get_unaligned_le32()

V1: https://lore.kernel.org/all/20251217162830.2597286-1-puranjay at kernel.org/
Changes in V1->V2:
- Patch 2:
        - Put preempt_enable()/disable() around RMW accesses to mitigate
          race conditions. Because on CONFIG_PREEMPT_RCU and sleepable
	  bpf programs, preemption can cause no bpf prog to execute in
	  case of recursion.

BPF programs detect recursion using a per-CPU 'active' flag in struct
bpf_prog. The trampoline currently sets/clears this flag with atomic
operations.

On some arm64 platforms (e.g., Neoverse V2 with LSE), per-CPU atomic
operations are relatively slow. Unlike x86_64 - where per-CPU updates
can avoid cross-core atomicity, arm64 LSE atomics are always atomic
across all cores, which is unnecessary overhead for strictly per-CPU
state.

This patch removes atomics from the recursion detection path on arm64.

It was discovered in [1] that per-CPU atomics that don't return a value
were extremely slow on some arm64 platforms, Catalin added a fix in
commit 535fdfc5a228 ("arm64: Use load LSE atomics for the non-return
per-CPU atomic operations") to solve this issue, but it seems to have
caused a regression on the fentry benchmark.

Using the fentry benchmark from the bpf selftests shows the following:

  ./tools/testing/selftests/bpf/bench trig-fentry

 +---------------------------------------------+------------------------+
 |               Configuration                 | Total Operations (M/s) |
 +---------------------------------------------+------------------------+
 | bpf-next/master with Catalin?s fix reverted |         51.770         |
 |---------------------------------------------|------------------------|
 | bpf-next/master                             |         43.271         |
 | bpf-next/master with this change            |         43.271         |
 +---------------------------------------------+------------------------+

All benchmarks were run on a KVM based vm with Neoverse-V2 and 8 cpus.

This patch yields a 25% improvement in this benchmark compared to
bpf-next. Notably, reverting Catalin's fix also results in a performance
gain for this benchmark, which is interesting but expected.

For completeness, this benchmark was also run with the change enabled on
x86-64, which resulted in a 30% regression in the fentry benchmark. So,
it is only enabled on arm64.

P.S. - Here is more data with other program types:

 +-----------------+-----------+-----------+----------+
 |     Metric      |  Before   |   After   | % Diff   |
 +-----------------+-----------+-----------+----------+
 | fentry          |   43.149  |   53.948  | +25.03%  |
 | fentry.s        |   41.831  |   50.937  | +21.76%  |
 | rawtp           |   50.834  |   58.731  | +15.53%  |
 | fexit           |   31.118  |   34.360  | +10.42%  |
 | tp              |   39.536  |   41.632  |  +5.30%  |
 | syscall-count   |    8.053  |    8.305  |  +3.13%  |
 | fmodret         |   33.940  |   34.769  |  +2.44%  |
 | kprobe          |    9.970  |    9.998  |  +0.28%  |
 | usermode-count  |  224.886  |  224.839  |  -0.02%  |
 | kernel-count    |  154.229  |  153.043  |  -0.77%  |
 +-----------------+-----------+-----------+----------+

[1] https://lore.kernel.org/all/e7d539ed-ced0-4b96-8ecd-048a5b803b85 at paulmck-laptop/

Puranjay Mohan (2):
  bpf: move recursion detection logic to helpers
  bpf: arm64: Optimize recursion detection by not using atomics

 include/linux/bpf.h      | 38 +++++++++++++++++++++++++++++++++++++-
 kernel/bpf/core.c        |  3 ++-
 kernel/bpf/trampoline.c  |  8 ++++----
 kernel/trace/bpf_trace.c |  4 ++--
 4 files changed, 45 insertions(+), 8 deletions(-)


base-commit: ec439c38013550420aecc15988ae6acb670838c1
-- 
2.47.3



From puranjay at kernel.org  Fri Dec 19 10:44:17 2025
From: puranjay at kernel.org (Puranjay Mohan)
Date: Fri, 19 Dec 2025 10:44:17 -0800
Subject: [PATCH bpf-next v3 1/2] bpf: move recursion detection logic to helpers
In-Reply-To: <20251219184422.2899902-1-puranjay@kernel.org>
References: <20251219184422.2899902-1-puranjay@kernel.org>
Message-ID: <20251219184422.2899902-2-puranjay@kernel.org>

BPF programs detect recursion by doing atomic inc/dec on a per-cpu
active counter from the trampoline. Create two helpers for operations on
this active counter, this makes it easy to changes the recursion
detection logic in future.

This commit makes no functional changes.

Acked-by: Yonghong Song <yonghong.song at linux.dev>
Signed-off-by: Puranjay Mohan <puranjay at kernel.org>
---
 include/linux/bpf.h      | 10 ++++++++++
 kernel/bpf/trampoline.c  |  8 ++++----
 kernel/trace/bpf_trace.c |  4 ++--
 3 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index bb3847caeae1..2da986136d26 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -2004,6 +2004,16 @@ struct bpf_struct_ops_common_value {
 	enum bpf_struct_ops_state state;
 };
 
+static inline bool bpf_prog_get_recursion_context(struct bpf_prog *prog)
+{
+	return this_cpu_inc_return(*(prog->active)) == 1;
+}
+
+static inline void bpf_prog_put_recursion_context(struct bpf_prog *prog)
+{
+	this_cpu_dec(*(prog->active));
+}
+
 #if defined(CONFIG_BPF_JIT) && defined(CONFIG_BPF_SYSCALL)
 /* This macro helps developer to register a struct_ops type and generate
  * type information correctly. Developers should use this macro to register
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index 976d89011b15..2a125d063e62 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -949,7 +949,7 @@ static u64 notrace __bpf_prog_enter_recur(struct bpf_prog *prog, struct bpf_tram
 
 	run_ctx->saved_run_ctx = bpf_set_run_ctx(&run_ctx->run_ctx);
 
-	if (unlikely(this_cpu_inc_return(*(prog->active)) != 1)) {
+	if (unlikely(!bpf_prog_get_recursion_context(prog))) {
 		bpf_prog_inc_misses_counter(prog);
 		if (prog->aux->recursion_detected)
 			prog->aux->recursion_detected(prog);
@@ -993,7 +993,7 @@ static void notrace __bpf_prog_exit_recur(struct bpf_prog *prog, u64 start,
 	bpf_reset_run_ctx(run_ctx->saved_run_ctx);
 
 	update_prog_stats(prog, start);
-	this_cpu_dec(*(prog->active));
+	bpf_prog_put_recursion_context(prog);
 	rcu_read_unlock_migrate();
 }
 
@@ -1029,7 +1029,7 @@ u64 notrace __bpf_prog_enter_sleepable_recur(struct bpf_prog *prog,
 
 	run_ctx->saved_run_ctx = bpf_set_run_ctx(&run_ctx->run_ctx);
 
-	if (unlikely(this_cpu_inc_return(*(prog->active)) != 1)) {
+	if (unlikely(!bpf_prog_get_recursion_context(prog))) {
 		bpf_prog_inc_misses_counter(prog);
 		if (prog->aux->recursion_detected)
 			prog->aux->recursion_detected(prog);
@@ -1044,7 +1044,7 @@ void notrace __bpf_prog_exit_sleepable_recur(struct bpf_prog *prog, u64 start,
 	bpf_reset_run_ctx(run_ctx->saved_run_ctx);
 
 	update_prog_stats(prog, start);
-	this_cpu_dec(*(prog->active));
+	bpf_prog_put_recursion_context(prog);
 	migrate_enable();
 	rcu_read_unlock_trace();
 }
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index fe28d86f7c35..6e076485bf70 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -2063,7 +2063,7 @@ void __bpf_trace_run(struct bpf_raw_tp_link *link, u64 *args)
 	struct bpf_trace_run_ctx run_ctx;
 
 	cant_sleep();
-	if (unlikely(this_cpu_inc_return(*(prog->active)) != 1)) {
+	if (unlikely(!bpf_prog_get_recursion_context(prog))) {
 		bpf_prog_inc_misses_counter(prog);
 		goto out;
 	}
@@ -2077,7 +2077,7 @@ void __bpf_trace_run(struct bpf_raw_tp_link *link, u64 *args)
 
 	bpf_reset_run_ctx(old_run_ctx);
 out:
-	this_cpu_dec(*(prog->active));
+	bpf_prog_put_recursion_context(prog);
 }
 
 #define UNPACK(...)			__VA_ARGS__
-- 
2.47.3



From puranjay at kernel.org  Fri Dec 19 10:44:18 2025
From: puranjay at kernel.org (Puranjay Mohan)
Date: Fri, 19 Dec 2025 10:44:18 -0800
Subject: [PATCH bpf-next v3 2/2] bpf: arm64: Optimize recursion detection by not using atomics
In-Reply-To: <20251219184422.2899902-1-puranjay@kernel.org>
References: <20251219184422.2899902-1-puranjay@kernel.org>
Message-ID: <20251219184422.2899902-3-puranjay@kernel.org>

BPF programs detect recursion using a per-CPU 'active' flag in struct
bpf_prog. The trampoline currently sets/clears this flag with atomic
operations.

On some arm64 platforms (e.g., Neoverse V2 with LSE), per-CPU atomic
operations are relatively slow. Unlike x86_64 - where per-CPU updates
can avoid cross-core atomicity, arm64 LSE atomics are always atomic
across all cores, which is unnecessary overhead for strictly per-CPU
state.

This patch removes atomics from the recursion detection path on arm64 by
changing 'active' to a per-CPU array of four u8 counters, one per
context: {NMI, hard-irq, soft-irq, normal}. The running context uses a
non-atomic increment/decrement on its element.  After increment,
recursion is detected by reading the array as a u32 and verifying that
only the expected element changed; any change in another element
indicates inter-context recursion, and a value > 1 in the same element
indicates same-context recursion.

For example, starting from {0,0,0,0}, a normal-context trigger changes
the array to {0,0,0,1}.  If an NMI arrives on the same CPU and triggers
the program, the array becomes {1,0,0,1}. When the NMI context checks
the u32 against the expected mask for normal (0x00000001), it observes
0x01000001 and correctly reports recursion. Same-context recursion is
detected analogously.

Acked-by: Yonghong Song <yonghong.song at linux.dev>
Signed-off-by: Puranjay Mohan <puranjay at kernel.org>
---
 include/linux/bpf.h | 32 +++++++++++++++++++++++++++++---
 kernel/bpf/core.c   |  3 ++-
 2 files changed, 31 insertions(+), 4 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 2da986136d26..da6a00dd313f 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -1746,6 +1746,8 @@ struct bpf_prog_aux {
 	struct bpf_map __rcu *st_ops_assoc;
 };
 
+#define BPF_NR_CONTEXTS        4       /* normal, softirq, hardirq, NMI */
+
 struct bpf_prog {
 	u16			pages;		/* Number of allocated pages */
 	u16			jited:1,	/* Is our filter JIT'ed? */
@@ -1772,7 +1774,7 @@ struct bpf_prog {
 		u8 tag[BPF_TAG_SIZE];
 	};
 	struct bpf_prog_stats __percpu *stats;
-	int __percpu		*active;
+	u8 __percpu		*active;	/* u8[BPF_NR_CONTEXTS] for recursion protection */
 	unsigned int		(*bpf_func)(const void *ctx,
 					    const struct bpf_insn *insn);
 	struct bpf_prog_aux	*aux;		/* Auxiliary fields */
@@ -2006,12 +2008,36 @@ struct bpf_struct_ops_common_value {
 
 static inline bool bpf_prog_get_recursion_context(struct bpf_prog *prog)
 {
-	return this_cpu_inc_return(*(prog->active)) == 1;
+#ifdef CONFIG_ARM64
+	u8 rctx = interrupt_context_level();
+	u8 *active = this_cpu_ptr(prog->active);
+	u32 val;
+
+	preempt_disable();
+	active[rctx]++;
+	val = le32_to_cpu(*(__le32 *)active);
+	preempt_enable();
+	if (val != BIT(rctx * 8))
+		return false;
+
+	return true;
+#else
+	return this_cpu_inc_return(*(int __percpu *)(prog->active)) == 1;
+#endif
 }
 
 static inline void bpf_prog_put_recursion_context(struct bpf_prog *prog)
 {
-	this_cpu_dec(*(prog->active));
+#ifdef CONFIG_ARM64
+	u8 rctx = interrupt_context_level();
+	u8 *active = this_cpu_ptr(prog->active);
+
+	preempt_disable();
+	active[rctx]--;
+	preempt_enable();
+#else
+	this_cpu_dec(*(int __percpu *)(prog->active));
+#endif
 }
 
 #if defined(CONFIG_BPF_JIT) && defined(CONFIG_BPF_SYSCALL)
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index c66316e32563..e0b8a8a5aaa9 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -112,7 +112,8 @@ struct bpf_prog *bpf_prog_alloc_no_stats(unsigned int size, gfp_t gfp_extra_flag
 		vfree(fp);
 		return NULL;
 	}
-	fp->active = alloc_percpu_gfp(int, bpf_memcg_flags(GFP_KERNEL | gfp_extra_flags));
+	fp->active = __alloc_percpu_gfp(sizeof(u8[BPF_NR_CONTEXTS]), 4,
+					bpf_memcg_flags(GFP_KERNEL | gfp_extra_flags));
 	if (!fp->active) {
 		vfree(fp);
 		kfree(aux);
-- 
2.47.3



From nicolinc at nvidia.com  Fri Dec 19 10:49:53 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Fri, 19 Dec 2025 10:49:53 -0800
Subject: [PATCH V7 2/4] iommu/arm-smmu-v3: Add device-tree support for
 CMDQV driver
In-Reply-To: <b2df8ce6-d336-457a-8169-f2eccec3c12e@nvidia.com>
References: <20251215064819.3345361-1-amhetre@nvidia.com>
 <20251215064819.3345361-3-amhetre@nvidia.com>
 <23df682e-6d08-4827-994e-1bbd89e5c903@nvidia.com>
 <5e9a0ce1-a0ba-4a31-be95-99f349ec6028@nvidia.com>
 <e7d3e95f-a885-4b13-ab4d-bc82793c5396@nvidia.com>
 <aUROk0jRQoLmBRo3@Asurada-Nvidia>
 <b2df8ce6-d336-457a-8169-f2eccec3c12e@nvidia.com>
Message-ID: <aUWeUapsFo3KZP7i@Asurada-Nvidia>

On Fri, Dec 19, 2025 at 10:48:22AM +0000, Jon Hunter wrote:
> On 18/12/2025 18:57, Nicolin Chen wrote:
> > On Thu, Dec 18, 2025 at 08:48:32AM +0000, Jon Hunter wrote:
> > > On 18/12/2025 06:32, Ashish Mhetre wrote:
> > > > On 12/18/2025 2:13 AM, Jon Hunter wrote:
> > > > > > +??? smmu->impl_dev = &pdev->dev;
> > > > > > +??? smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
> > > > > > +??? dev_info(smmu->dev, "found companion CMDQV device: %s\n",
> > > > > > +???????? dev_name(smmu->impl_dev));
> > > > > 
> > > > > This seems a bit noisy. dev_dbg?
> > > > > 
> > > > 
> > > > This info print is similar to what is there in ACPI path as well.
> > > > It's only a single print per SMMU at boot time. Should I still change
> > > > it to dev_dbg?
> > > 
> > > Yes, I would.
> > 
> > It's really not that bad IMHO, I am not against that though..
> > 
> > If we have to change that, we'd need another patch changing the
> > one in the ACPI path as well to keep things aligned.
> 
> Regardless of what is already present, does not mean we need add more prints
> to just say everything is OK.

This is how it looks like for each instance probe():

[    2.709269] arm-smmu-v3 arm-smmu-v3.10.auto: found companion CMDQV device: NVDA200C:00
[    2.709273] arm-smmu-v3 arm-smmu-v3.10.auto: option mask 0x10
[    2.709618] arm-smmu-v3 arm-smmu-v3.10.auto: ias 48-bit, oas 48-bit (features 0x001e1fbf)
[    2.716236] arm-smmu-v3 arm-smmu-v3.10.auto: allocated 524288 entries for cmdq
[    2.719432] arm-smmu-v3 arm-smmu-v3.10.auto: allocated 524288 entries for evtq
[    2.725898] arm-smmu-v3 arm-smmu-v3.10.auto: allocated 524288 entries for priq
[    2.736051] arm-smmu-v3 arm-smmu-v3.10.auto: allocated 524288 entries for vcmdq0
[    2.742553] arm-smmu-v3 arm-smmu-v3.10.auto: allocated 524288 entries for vcmdq1
[    2.742586] arm-smmu-v3 arm-smmu-v3.10.auto: msi_domain absent - falling back to wired irqs
[    2.742759] arm-smmu-v3 arm-smmu-v3.10.auto: no priq irq - PRI will be broken

On a second thought: The CMDQV device has a very unclear naming in
ACPI path: "NVDA200C:00". So, printing it gives us a hint for any
later warning/error tagged with "NVDA200C:00".

Now, for DT, it might be okay to not print it. But making the two
paths asymmetric feels odd. So, is it really worth nitpicking here
given that each SMMU already prints quite a few lines on probe()?

Nicolin


From nicolinc at nvidia.com  Fri Dec 19 10:54:15 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Fri, 19 Dec 2025 10:54:15 -0800
Subject: [PATCH v8 5/7] iommu/arm-smmu-v3: Populate smmu_domain->invs
 when attaching masters
In-Reply-To: <20251219155151.GA373575@nvidia.com>
References: <cover.1766013662.git.nicolinc@nvidia.com>
 <79cd18a1a959ee2e54683e8c465b799d49ec48b5.1766013662.git.nicolinc@nvidia.com>
 <20251219155151.GA373575@nvidia.com>
Message-ID: <aUWfVzhVZ+Qo1efT@Asurada-Nvidia>

On Fri, Dec 19, 2025 at 11:51:51AM -0400, Jason Gunthorpe wrote:
> On Wed, Dec 17, 2025 at 03:24:30PM -0800, Nicolin Chen wrote:
> > +	*cur = inv;
> > +	switch (type) {
> > +	case INV_TYPE_S1_ASID:
> > +		if (master->smmu->features & ARM_SMMU_FEAT_E2H) {
> > +			cur->size_opcode = CMDQ_OP_TLBI_EL2_VA;
> > +			cur->nsize_opcode = CMDQ_OP_TLBI_EL2_ASID;
> > +		} else {
> > +			cur->size_opcode = CMDQ_OP_TLBI_NH_VA;
> > +			cur->nsize_opcode = CMDQ_OP_TLBI_NH_ASID;
> 
> There is a tricky little gotcha here that probably requires a comment.
> 
> NH_VA and NH_ASID both take (VMID,ASID) as input since the ASID is
> always scoped to a single VMID.
> 
> In this case the invalidation logic always wires the VMID to zero,
> which is also the VMID the driver uses for S1 tables when the S2 is in
> bypass.
> 
> Which is fine, we don't support an actual S1 table on top of a S2
> table where we issue invalidations through the invs array.
> 
> So maybe:
> 
>  For S1 page tables the driver always uses VMID=0, and the
>  invalidation logic for this type will set it as well.

Ack. And I will drop that ssid too.

Thanks
Nicolin


From jgg at nvidia.com  Fri Dec 19 10:56:05 2025
From: jgg at nvidia.com (Jason Gunthorpe)
Date: Fri, 19 Dec 2025 14:56:05 -0400
Subject: [PATCH v8 5/7] iommu/arm-smmu-v3: Populate smmu_domain->invs
 when attaching masters
In-Reply-To: <aUWfVzhVZ+Qo1efT@Asurada-Nvidia>
References: <cover.1766013662.git.nicolinc@nvidia.com>
 <79cd18a1a959ee2e54683e8c465b799d49ec48b5.1766013662.git.nicolinc@nvidia.com>
 <20251219155151.GA373575@nvidia.com>
 <aUWfVzhVZ+Qo1efT@Asurada-Nvidia>
Message-ID: <20251219185605.GI254720@nvidia.com>

On Fri, Dec 19, 2025 at 10:54:15AM -0800, Nicolin Chen wrote:
> On Fri, Dec 19, 2025 at 11:51:51AM -0400, Jason Gunthorpe wrote:
> > On Wed, Dec 17, 2025 at 03:24:30PM -0800, Nicolin Chen wrote:
> > > +	*cur = inv;
> > > +	switch (type) {
> > > +	case INV_TYPE_S1_ASID:
> > > +		if (master->smmu->features & ARM_SMMU_FEAT_E2H) {
> > > +			cur->size_opcode = CMDQ_OP_TLBI_EL2_VA;
> > > +			cur->nsize_opcode = CMDQ_OP_TLBI_EL2_ASID;
> > > +		} else {
> > > +			cur->size_opcode = CMDQ_OP_TLBI_NH_VA;
> > > +			cur->nsize_opcode = CMDQ_OP_TLBI_NH_ASID;
> > 
> > There is a tricky little gotcha here that probably requires a comment.
> > 
> > NH_VA and NH_ASID both take (VMID,ASID) as input since the ASID is
> > always scoped to a single VMID.
> > 
> > In this case the invalidation logic always wires the VMID to zero,
> > which is also the VMID the driver uses for S1 tables when the S2 is in
> > bypass.
> > 
> > Which is fine, we don't support an actual S1 table on top of a S2
> > table where we issue invalidations through the invs array.
> > 
> > So maybe:
> > 
> >  For S1 page tables the driver always uses VMID=0, and the
> >  invalidation logic for this type will set it as well.
> 
> Ack. And I will drop that ssid too.

It looks like the ssid is needed for ats:

@@ -3156,12 +3162,136 @@ arm_smmu_master_build_inv(struct arm_smmu_master *master,
        case INV_TYPE_ATS:
        case INV_TYPE_ATS_FULL:
                cur->size_opcode = cur->nsize_opcode = CMDQ_OP_ATC_INV;
+               cur->ssid = ssid;
                break;

Jason


From nicolinc at nvidia.com  Fri Dec 19 11:00:20 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Fri, 19 Dec 2025 11:00:20 -0800
Subject: [PATCH v8 5/7] iommu/arm-smmu-v3: Populate smmu_domain->invs
 when attaching masters
In-Reply-To: <20251219185605.GI254720@nvidia.com>
References: <cover.1766013662.git.nicolinc@nvidia.com>
 <79cd18a1a959ee2e54683e8c465b799d49ec48b5.1766013662.git.nicolinc@nvidia.com>
 <20251219155151.GA373575@nvidia.com>
 <aUWfVzhVZ+Qo1efT@Asurada-Nvidia>
 <20251219185605.GI254720@nvidia.com>
Message-ID: <aUWgxJpG8nXRv0hG@Asurada-Nvidia>

On Fri, Dec 19, 2025 at 02:56:05PM -0400, Jason Gunthorpe wrote:
> On Fri, Dec 19, 2025 at 10:54:15AM -0800, Nicolin Chen wrote:
> > On Fri, Dec 19, 2025 at 11:51:51AM -0400, Jason Gunthorpe wrote:
> > > On Wed, Dec 17, 2025 at 03:24:30PM -0800, Nicolin Chen wrote:
> > > > +	*cur = inv;
> > > > +	switch (type) {
> > > > +	case INV_TYPE_S1_ASID:
> > > > +		if (master->smmu->features & ARM_SMMU_FEAT_E2H) {
> > > > +			cur->size_opcode = CMDQ_OP_TLBI_EL2_VA;
> > > > +			cur->nsize_opcode = CMDQ_OP_TLBI_EL2_ASID;
> > > > +		} else {
> > > > +			cur->size_opcode = CMDQ_OP_TLBI_NH_VA;
> > > > +			cur->nsize_opcode = CMDQ_OP_TLBI_NH_ASID;
> > > 
> > > There is a tricky little gotcha here that probably requires a comment.
> > > 
> > > NH_VA and NH_ASID both take (VMID,ASID) as input since the ASID is
> > > always scoped to a single VMID.
> > > 
> > > In this case the invalidation logic always wires the VMID to zero,
> > > which is also the VMID the driver uses for S1 tables when the S2 is in
> > > bypass.
> > > 
> > > Which is fine, we don't support an actual S1 table on top of a S2
> > > table where we issue invalidations through the invs array.
> > > 
> > > So maybe:
> > > 
> > >  For S1 page tables the driver always uses VMID=0, and the
> > >  invalidation logic for this type will set it as well.
> > 
> > Ack. And I will drop that ssid too.
> 
> It looks like the ssid is needed for ats:
> 
> @@ -3156,12 +3162,136 @@ arm_smmu_master_build_inv(struct arm_smmu_master *master,
>         case INV_TYPE_ATS:
>         case INV_TYPE_ATS_FULL:
>                 cur->size_opcode = cur->nsize_opcode = CMDQ_OP_ATC_INV;
> +               cur->ssid = ssid;
>                 break;

Oh, right. I'll fix this.

Thanks
Nicolin


From robin.murphy at arm.com  Fri Dec 19 11:03:52 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Fri, 19 Dec 2025 19:03:52 +0000
Subject: [RFC PATCH] arm64: introduce NEON based copy to/from user
In-Reply-To: <20251129065846.1656987-1-tujinjiang@huawei.com>
References: <20251129065846.1656987-1-tujinjiang@huawei.com>
Message-ID: <fa925447-9bab-4429-ba9f-d708f6db0bb6@arm.com>

On 29/11/2025 6:58 am, Jinjiang Tu wrote:
> From: Alexander Kozhevnikov <alexander.kozhevnikov at huawei-partners.com>
> 
> This implementation use st1/ld1 4-vector instrutions which allow to copy
> 64 bytes at once, and can be used on any ARMv8 variant.
> 
> During NEON instructions accessing user address, we must disable PAN
> temporarily, mark FPSIMD in use, and save FPSIMD context.
> 1) We only save the used FPSIMD registers context instead of all registers.
> 2) Trapped in FPSIMD context does not support user address page fault.
>     fallback to retry copy left at this point.
> 3) We find that although we have disabled PAN temporarily, performance will
>     decrease if copy size is below 4KB under CONFIG_ARM64_PAN=y, so use NEON
>     copy when not less than 4K bytes.
> 4) Add a /proc/sys/kernel/neon_copy_user switch that users can turn on as
>     needed.
> 
> The following table shows the performance testing of the copy_to/from_user
> based on Kunpeng platform. In addition, copy_to_user 1024KB has
> deteriorated, and the cause is still being investigated.
> 
> --------------------------------------------------------------------------
>            |           copy_from_user      |           copy_to_user
>            |           nsecs/call          |           nsecs/call
> --------------------------------------------------------------------------
>     size   | baseline  neon_copy  increase | baseline  neon_copy  increase
> --------------------------------------------------------------------------
>      1 KB  |     161      162     -0.62%   |    156       155      0.64%
>     16 KB  |     613      326     46.82%   |    549       325     40.80%
>     32 KB  |    1057      491     53.55%   |    991       486     50.96%
>     64 KB  |    2017      976     51.61%   |   1854       959     48.27%
>    128 KB  |    3737     1885     49.56%   |   3520      1870     46.88%
>    256 KB  |    7667     3744     51.17%   |   7106      3714     47.73%
>    512 KB  |   16518     9972     39.63%   |  14102     10583     24.95%
>   1024 KB  |   49843    46409      6.89%   |  32264     37082    -14.93%
>   1536 KB  |   94641    80999     14.41%   |  56756     57202     -0.79%
>   2048 KB  |  134955   116348     13.79%   |  81314     76292      6.18%
>   3072 KB  |  215230   188738     12.31%   | 123061    116767      5.11%
>   4096 KB  |  302353   264942     12.37%   | 167716    158134      5.71%
>   5120 KB  |  444801   348909     21.56%   | 213730    206918      3.19%
>   6144 KB  |  561146   428615     23.62%   | 271235    255034      5.97%
>   7168 KB  |  624656   521106     16.58%   | 326677    307703      5.81%
>   8192 KB  |  766439   603728     21.23%   | 391038    365387      6.56%
> --------------------------------------------------------------------------

FWIW at first glance these numbers don't look all that different from my
tests of different scalar code - hwo much of this is actually from using
NEON, and how much is just from *not* using ldtr/sttr? For instance on
my Neoverse N1, from about 4KB up to 64KB (I've not tried hacking the
microbenchmark to go larger), it's clearly bottlenecked on issue
capacity before actual data throughput, so gets a ~40% win just from
going to 2 load/store ops per 16B (ldp/stp) from 3 (ldp/sttr/sttr or
vice versa), and in fact NEON only seems to suffer some extra overhead:

Large memcpy (bytes/ns):
    __arch_copy_to_user 1K: 25.88 2K: 26.77 4K: 27.28 8K: 27.48 16K: 27.52 32K: 27.43 64K: 27.34
       copy_to_user_new 1K: 27.15 2K: 27.09 4K: 27.62 8K: 27.54 16K: 27.67 32K: 27.52 64K: 27.17
       __memcpy_aarch64 1K: 37.79 2K: 39.80 4K: 40.59 8K: 41.08 16K: 41.29 32K: 41.17 64K: 40.19
  __memcpy_aarch64_simd 1K: 36.43 2K: 38.26 4K: 39.34 8K: 39.91 16K: 39.87 32K: 39.89 64K: 39.63


And once again, while a best-case ~50% improvement in a targeted
microbenchmark is nice, it's still not exactly jaw-dropping when the
baseline is known to not necessarily be all that great to begin with.
Plus it's still likely to translate to a real-world effect 3 or 4 orders
of magnitude smaller, so the big question remains: Is there any real
workload that's significantly bottlenecked on large multi-page copies in
and out of userspace, without being able to use even more effective
mechanisms like mmap(), that actually justfies reviving the need to
reason about the potential security implications of PAN-toggling? (Which
IIRC we were all rather happy to finally get rid of a while back...)

Thanks,
Robin.

> Signed-off-by: Alexander Kozhevnikov <alexander.kozhevnikov at huawei-partners.com>
> Signed-off-by: Lemmy Huang <huangliming5 at huawei.com>
> ---
>   arch/arm64/Kconfig                   | 10 +++
>   arch/arm64/include/asm/asm-uaccess.h | 17 +++++
>   arch/arm64/include/asm/neon.h        |  7 ++
>   arch/arm64/include/asm/uaccess.h     | 65 +++++++++++++++++++
>   arch/arm64/kernel/fpsimd.c           | 91 ++++++++++++++++++++++++++
>   arch/arm64/lib/Makefile              |  2 +
>   arch/arm64/lib/copy_from_user.S      | 13 ++++
>   arch/arm64/lib/copy_from_user_neon.S | 96 ++++++++++++++++++++++++++++
>   arch/arm64/lib/copy_template.S       | 52 ++++++++++++++-
>   arch/arm64/lib/copy_to_user.S        | 13 ++++
>   arch/arm64/lib/copy_to_user_neon.S   | 96 ++++++++++++++++++++++++++++
>   11 files changed, 459 insertions(+), 3 deletions(-)
>   create mode 100644 arch/arm64/lib/copy_from_user_neon.S
>   create mode 100644 arch/arm64/lib/copy_to_user_neon.S
> 
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 6663ffd23f..cf8f1d4d57 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -388,6 +388,16 @@ config SMP
>   config KERNEL_MODE_NEON
>   	def_bool y
>   
> +config NEON_COPY_USER
> +	bool "Use NEON instructions in copy_to/from_user"
> +	depends on KERNEL_MODE_NEON
> +	default n
> +	help
> +	  This option turns on using NEON instructions to speed up copy_to/from_user
> +	  routines. This implementation use st1/ld1 4-vector instrutions which allow
> +	  to copy 64 bytes at once, and is used only if size of data block to copy
> +	  is more than 4096 bytes.
> +
>   config FIX_EARLYCON_MEM
>   	def_bool y
>   
> diff --git a/arch/arm64/include/asm/asm-uaccess.h b/arch/arm64/include/asm/asm-uaccess.h
> index 9148f5a319..b2657d31cc 100644
> --- a/arch/arm64/include/asm/asm-uaccess.h
> +++ b/arch/arm64/include/asm/asm-uaccess.h
> @@ -94,4 +94,21 @@ alternative_else_nop_endif
>   
>   		_asm_extable_uaccess	8888b, \l;
>   	.endm
> +
> +#ifdef CONFIG_NEON_COPY_USER
> +	.macro user_ldneon l, reg1, reg2, reg3, reg4, ptr, post_inc
> +8888 :		ld1 {\reg1, \reg2, \reg3, \reg4}, [\ptr];
> +		add		\ptr, \ptr, \post_inc;
> +
> +		_asm_extable_uaccess	8888b, \l;
> +	.endm
> +
> +	.macro user_stneon l, reg1, reg2, reg3, reg4, ptr, post_inc
> +8888 :		st1 {\reg1, \reg2, \reg3, \reg4}, [\ptr];
> +		add		\ptr, \ptr, \post_inc;
> +
> +		_asm_extable_uaccess	8888b, \l;
> +	.endm
> +#endif
> +
>   #endif
> diff --git a/arch/arm64/include/asm/neon.h b/arch/arm64/include/asm/neon.h
> index d4b1d172a7..0c75baeba8 100644
> --- a/arch/arm64/include/asm/neon.h
> +++ b/arch/arm64/include/asm/neon.h
> @@ -16,4 +16,11 @@
>   void kernel_neon_begin(void);
>   void kernel_neon_end(void);
>   
> +#ifdef CONFIG_NEON_COPY_USER
> +bool kernel_neon_copy_enabled(void);
> +
> +void kernel_neon_copy_begin(void);
> +void kernel_neon_copy_end(void);
> +#endif
> +
>   #endif /* ! __ASM_NEON_H */
> diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
> index 1aa4ecb734..c6e0f9adba 100644
> --- a/arch/arm64/include/asm/uaccess.h
> +++ b/arch/arm64/include/asm/uaccess.h
> @@ -25,6 +25,10 @@
>   #include <asm/ptrace.h>
>   #include <asm/memory.h>
>   #include <asm/extable.h>
> +#ifdef CONFIG_NEON_COPY_USER
> +#include <asm/neon.h>
> +#include <asm/simd.h>
> +#endif
>   
>   static inline int __access_ok(const void __user *ptr, unsigned long size);
>   
> @@ -391,6 +395,66 @@ do {									\
>   	} while (0);							\
>   } while(0)
>   
> +
> +#ifdef CONFIG_NEON_COPY_USER
> +extern unsigned long __must_check __arch_copy_from_user(
> +	void *to, const void __user *from, unsigned long n);
> +extern unsigned long __must_check __arch_copy_from_user_neon(
> +	void *to, const void __user *from, unsigned long n);
> +#define raw_copy_from_user(to, from, n)					\
> +({										\
> +	unsigned long __acfu_ret = n;		\
> +	if ((n) >= 4096 && kernel_neon_copy_enabled()) {	\
> +		if (may_use_simd()) {			\
> +			kernel_neon_copy_begin();		\
> +			uaccess_enable_privileged();	\
> +			__acfu_ret = __arch_copy_from_user_neon((to),	\
> +							__uaccess_mask_ptr(from), (n));	\
> +			uaccess_disable_privileged();	\
> +			kernel_neon_copy_end();			\
> +		}							\
> +	}								\
> +	/* fallback to retry copy left */	\
> +	if (__acfu_ret) {				\
> +		uaccess_ttbr0_enable();		\
> +		__acfu_ret = __arch_copy_from_user((u8 *)(to) + (n) - __acfu_ret,	\
> +			__uaccess_mask_ptr((u8 __user *)(from) + (n) - __acfu_ret),	\
> +			__acfu_ret);			\
> +		uaccess_ttbr0_disable();	\
> +	}								\
> +	__acfu_ret;						\
> +})
> +
> +extern unsigned long __must_check __arch_copy_to_user(
> +	void __user *to, const void *from, unsigned long n);
> +extern unsigned long __must_check __arch_copy_to_user_neon(
> +	void __user *to, const void *from, unsigned long n);
> +#define raw_copy_to_user(to, from, n)					\
> +({										\
> +	unsigned long __actu_ret = n;		\
> +	if ((n) >= 4096 && kernel_neon_copy_enabled()) {	\
> +		if (may_use_simd()) {			\
> +			kernel_neon_copy_begin();		\
> +			uaccess_enable_privileged();	\
> +			__actu_ret = __arch_copy_to_user_neon(__uaccess_mask_ptr(to),	\
> +							(from), (n));	\
> +			uaccess_disable_privileged();	\
> +			kernel_neon_copy_end();			\
> +		}							\
> +	}								\
> +	/* fallback to retry copy left */	\
> +	if (__actu_ret) {				\
> +		uaccess_ttbr0_enable();		\
> +		__actu_ret = __arch_copy_to_user(	\
> +			__uaccess_mask_ptr((u8 __user *)(to) + (n) - __actu_ret),	\
> +			(u8 *)(from)  + (n) - __actu_ret, __actu_ret);	\
> +		uaccess_ttbr0_disable();	\
> +	}								\
> +	__actu_ret;						\
> +})
> +
> +#else  /* CONFIG_NEON_COPY_USER */
> +
>   extern unsigned long __must_check __arch_copy_from_user(void *to, const void __user *from, unsigned long n);
>   #define raw_copy_from_user(to, from, n)					\
>   ({									\
> @@ -412,6 +476,7 @@ extern unsigned long __must_check __arch_copy_to_user(void __user *to, const voi
>   	uaccess_ttbr0_disable();					\
>   	__actu_ret;							\
>   })
> +#endif  /* CONFIG_NEON_COPY_USER */
>   
>   static __must_check __always_inline bool user_access_begin(const void __user *ptr, size_t len)
>   {
> diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
> index e3f8f51748..ab71ffe5c7 100644
> --- a/arch/arm64/kernel/fpsimd.c
> +++ b/arch/arm64/kernel/fpsimd.c
> @@ -1905,6 +1905,97 @@ void kernel_neon_end(void)
>   }
>   EXPORT_SYMBOL_GPL(kernel_neon_end);
>   
> +#ifdef CONFIG_NEON_COPY_USER
> +DEFINE_STATIC_KEY_FALSE(kernel_neon_copy_user_used);
> +bool kernel_neon_copy_enabled(void)
> +{
> +	return static_key_enabled(&kernel_neon_copy_user_used);
> +}
> +EXPORT_SYMBOL_GPL(kernel_neon_copy_enabled);
> +
> +/*
> + * kernel_neon_copy_begin(): only set FPSIMD context busy
> + *
> + * The caller must save the used FPSIMD registers to stack and restore registers
> + */
> +void kernel_neon_copy_begin(void)
> +{
> +	get_cpu_fpsimd_context();
> +}
> +EXPORT_SYMBOL_GPL(kernel_neon_copy_begin);
> +
> +/*
> + * kernel_neon_copy_end(): relase FPSIMD context
> + *
> + * Must be called from a context in which kernel_neon_copy_begin() was previously
> + * called.
> + */
> +void kernel_neon_copy_end(void)
> +{
> +	put_cpu_fpsimd_context();
> +}
> +EXPORT_SYMBOL_GPL(kernel_neon_copy_end);
> +
> +static int neon_copy_sysctl_handler(const struct ctl_table *table, int write,
> +	void *buffer, size_t *lenp, loff_t *ppos)
> +{
> +	int ret, val;
> +	const struct ctl_table tmp = {
> +		.data	= &val,
> +		.maxlen	= sizeof(val),
> +		.mode	= table->mode,
> +		.extra1	= SYSCTL_ZERO,
> +		.extra2	= SYSCTL_ONE,
> +	};
> +	/* List of CPUs that support NEON copy */
> +	static const struct midr_range hip12_cpus[] = {
> +		MIDR_ALL_VERSIONS(MIDR_HISI_HIP12),
> +		{ }
> +	};
> +
> +	if (write && !capable(CAP_SYS_ADMIN))
> +		return -EPERM;
> +
> +	if (!system_supports_fpsimd())
> +		return -EPERM;
> +
> +	if (!is_midr_in_range_list(hip12_cpus))
> +		return -EPERM;
> +
> +	if (!write) {
> +		if (static_key_enabled(&kernel_neon_copy_user_used))
> +			val = 1;
> +		else
> +			val = 0;
> +	}
> +	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
> +	if (write && !ret) {
> +		if (val)
> +			static_branch_enable(&kernel_neon_copy_user_used);
> +		else
> +			static_branch_disable(&kernel_neon_copy_user_used);
> +	}
> +	return 0;
> +}
> +
> +static const struct ctl_table neon_copy_sysctl_table[] = {
> +	{
> +		.procname = "neon_copy_user",
> +		.mode = 0644,
> +		.proc_handler = neon_copy_sysctl_handler,
> +	},
> +	{ }
> +};
> +
> +static int __init neon_copy_sysctl_init(void)
> +{
> +	if (!register_sysctl("kernel", neon_copy_sysctl_table))
> +		return -EINVAL;
> +	return 0;
> +}
> +core_initcall(neon_copy_sysctl_init);
> +#endif
> +
>   #ifdef CONFIG_EFI
>   
>   static struct user_fpsimd_state efi_fpsimd_state;
> diff --git a/arch/arm64/lib/Makefile b/arch/arm64/lib/Makefile
> index 633e5223d9..2a92ae7bd7 100644
> --- a/arch/arm64/lib/Makefile
> +++ b/arch/arm64/lib/Makefile
> @@ -13,6 +13,8 @@ endif
>   
>   lib-$(CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE) += uaccess_flushcache.o
>   
> +lib-$(CONFIG_NEON_COPY_USER) += copy_to_user_neon.o copy_from_user_neon.o
> +
>   obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
>   
>   obj-$(CONFIG_ARM64_MTE) += mte.o
> diff --git a/arch/arm64/lib/copy_from_user.S b/arch/arm64/lib/copy_from_user.S
> index 400057d607..db861eff78 100644
> --- a/arch/arm64/lib/copy_from_user.S
> +++ b/arch/arm64/lib/copy_from_user.S
> @@ -59,11 +59,24 @@
>   	USER_CPY(9996f, 0, cpyfert [\dst]!, [\src]!, \count!)
>   	.endm
>   
> +#ifdef CONFIG_NEON_COPY_USER
> +	.macro ldneon reg1, reg2, reg3, reg4, ptr, val
> +	b	9997f
> +	.endm
> +
> +	.macro stneon reg1, reg2, reg3, reg4, ptr, val
> +	b	9997f
> +	.endm
> +#endif
> +
>   end	.req	x5
>   srcin	.req	x15
>   SYM_FUNC_START(__arch_copy_from_user)
>   	add	end, x0, x2
>   	mov	srcin, x1
> +#ifdef CONFIG_NEON_COPY_USER
> +	mov	x3, #0		/* disable neon copy */
> +#endif
>   #include "copy_template.S"
>   	mov	x0, #0				// Nothing to copy
>   	ret
> diff --git a/arch/arm64/lib/copy_from_user_neon.S b/arch/arm64/lib/copy_from_user_neon.S
> new file mode 100644
> index 0000000000..4dc2b3dfdd
> --- /dev/null
> +++ b/arch/arm64/lib/copy_from_user_neon.S
> @@ -0,0 +1,96 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (C) 2012 ARM Ltd.
> + * Copyright (C) 2025 Huawei Ltd.
> + */
> +
> +#include <linux/linkage.h>
> +
> +#include <asm/asm-uaccess.h>
> +#include <asm/assembler.h>
> +#include <asm/cache.h>
> +
> +/*
> + * Copy from user space to a kernel buffer (alignment handled by the hardware)
> + *
> + * Parameters:
> + *	x0 - to
> + *	x1 - from
> + *	x2 - n
> + * Returns:
> + *	x0 - bytes not copied
> + */
> +
> +	.macro ldrb1 reg, ptr, val
> +	user_ldst 9998f, ldtrb, \reg, \ptr, \val
> +	.endm
> +
> +	.macro strb1 reg, ptr, val
> +	strb \reg, [\ptr], \val
> +	.endm
> +
> +	.macro ldrh1 reg, ptr, val
> +	user_ldst 9997f, ldtrh, \reg, \ptr, \val
> +	.endm
> +
> +	.macro strh1 reg, ptr, val
> +	strh \reg, [\ptr], \val
> +	.endm
> +
> +	.macro ldr1 reg, ptr, val
> +	user_ldst 9997f, ldtr, \reg, \ptr, \val
> +	.endm
> +
> +	.macro str1 reg, ptr, val
> +	str \reg, [\ptr], \val
> +	.endm
> +
> +	.macro ldp1 reg1, reg2, ptr, val
> +	user_ldp 9997f, \reg1, \reg2, \ptr, \val
> +	.endm
> +
> +	.macro stp1 reg1, reg2, ptr, val
> +	stp \reg1, \reg2, [\ptr], \val
> +	.endm
> +
> +	.macro cpy1 dst, src, count
> +	.arch_extension mops
> +	USER_CPY(9997f, 0, cpyfprt [\dst]!, [\src]!, \count!)
> +	USER_CPY(9996f, 0, cpyfmrt [\dst]!, [\src]!, \count!)
> +	USER_CPY(9996f, 0, cpyfert [\dst]!, [\src]!, \count!)
> +	.endm
> +
> +	.macro ldneon reg1, reg2, reg3, reg4, ptr, val
> +	user_ldneon 9987f, \reg1, \reg2, \reg3, \reg4, \ptr, \val
> +	.endm
> +
> +	.macro stneon reg1, reg2, reg3, reg4, ptr, val
> +	st1 {\reg1, \reg2, \reg3, \reg4}, [\ptr]
> +	add \ptr, \ptr, \val
> +	.endm
> +
> +end	.req	x5
> +srcin	.req	x15
> +SYM_FUNC_START(__arch_copy_from_user_neon)
> +	add	end, x0, x2
> +	mov	srcin, x1
> +	mov	x3, #1		/* enable neon copy */
> +#include "copy_template.S"
> +	mov	x0, #0				// Nothing to copy
> +	ret
> +
> +	// Exception fixups
> +9987:	ld1	{V_a.16b, V_b.16b, V_c.16b, V_d.16b}, [sp]  /* restore current regs */
> +	add	sp, sp, #64
> +9996:	b.cs	9997f
> +	// Registers are in Option A format
> +	add	dst, dst, count
> +9997:	cmp	dst, dstin
> +	b.ne	9998f
> +	// Before being absolutely sure we couldn't copy anything, try harder
> +USER(9998f, ldtrb tmp1w, [srcin])
> +	strb	tmp1w, [dst], #1
> +9998:	sub	x0, end, dst			// bytes not copied
> +	ret
> +SYM_FUNC_END(__arch_copy_from_user_neon)
> +EXPORT_SYMBOL(__arch_copy_from_user_neon)
> diff --git a/arch/arm64/lib/copy_template.S b/arch/arm64/lib/copy_template.S
> index 7f2f5a0e2f..c92f967f96 100644
> --- a/arch/arm64/lib/copy_template.S
> +++ b/arch/arm64/lib/copy_template.S
> @@ -18,14 +18,16 @@
>    *	x0 - dest
>    *	x1 - src
>    *	x2 - n
> + *	x3 - useneon
>    * Returns:
>    *	x0 - dest
>    */
>   dstin	.req	x0
>   src	.req	x1
>   count	.req	x2
> -tmp1	.req	x3
> -tmp1w	.req	w3
> +useneon	.req	x3
> +tmp1	.req	x16
> +tmp1w	.req	w16
>   tmp2	.req	x4
>   tmp2w	.req	w4
>   dst	.req	x6
> @@ -38,6 +40,12 @@ C_l	.req	x11
>   C_h	.req	x12
>   D_l	.req	x13
>   D_h	.req	x14
> +#ifdef CONFIG_NEON_COPY_USER
> +V_a	.req	v20
> +V_b	.req	v21
> +V_c	.req	v22
> +V_d	.req	v23
> +#endif
>   
>   	mov	dst, dstin
>   
> @@ -155,12 +163,16 @@ alternative_else_nop_endif
>   	b.ne	.Ltail63
>   	b	.Lexitfunc
>   
> +.Lcpy_body_large:
> +#ifdef CONFIG_NEON_COPY_USER
> +	tbnz	useneon, #0, .Lcpy_body_large_useneon
> +#endif
>   	/*
>   	* Critical loop.  Start at a new cache line boundary.  Assuming
>   	* 64 bytes per line this ensures the entire loop is in one line.
>   	*/
>   	.p2align	L1_CACHE_SHIFT
> -.Lcpy_body_large:
> +.Lcpy_body_large_usex:
>   	/* pre-get 64 bytes data. */
>   	ldp1	A_l, A_h, src, #16
>   	ldp1	B_l, B_h, src, #16
> @@ -188,4 +200,38 @@ alternative_else_nop_endif
>   
>   	tst	count, #0x3f
>   	b.ne	.Ltail63
> +
> +#ifdef CONFIG_NEON_COPY_USER
> +	b	.Lexitfunc
> +
> +.Lcpy_body_large_useneon:
> +	/*
> +	* Critical loop.  Start at a new cache line boundary.  Assuming
> +	* 64 bytes per line this ensures the entire loop is in one line.
> +	*/
> +	.p2align	L1_CACHE_SHIFT
> +	sub	sp, sp, #64
> +	st1	{V_a.16b, V_b.16b, V_c.16b, V_d.16b}, [sp]  /* save current regs */
> +	/* pre-get 64 bytes data. */
> +	ldneon	V_a.16b, V_b.16b, V_c.16b, V_d.16b, src, #64
> +
> +1:
> +	/*
> +	* interlace the load of next 64 bytes data block with store of the last
> +	* loaded 64 bytes data.
> +	*/
> +	stneon	V_a.16b, V_b.16b, V_c.16b, V_d.16b, dst, #64
> +	ldneon	V_a.16b, V_b.16b, V_c.16b, V_d.16b, src, #64
> +
> +	subs	count, count, #64
> +	b.ge	1b
> +
> +	stneon	V_a.16b, V_b.16b, V_c.16b, V_d.16b, dst, #64
> +
> +	ld1	{V_a.16b, V_b.16b, V_c.16b, V_d.16b}, [sp]  /* restore current regs */
> +	add	sp, sp, #64
> +
> +	tst	count, #0x3f
> +	b.ne	.Ltail63
> +#endif
>   .Lexitfunc:
> diff --git a/arch/arm64/lib/copy_to_user.S b/arch/arm64/lib/copy_to_user.S
> index 819f2e3fc7..fbf058dfd5 100644
> --- a/arch/arm64/lib/copy_to_user.S
> +++ b/arch/arm64/lib/copy_to_user.S
> @@ -58,11 +58,24 @@
>   	USER_CPY(9996f, 1, cpyfewt [\dst]!, [\src]!, \count!)
>   	.endm
>   
> +#ifdef CONFIG_NEON_COPY_USER
> +	.macro ldneon reg1, reg2, reg3, reg4, ptr, val
> +	b	9997f
> +	.endm
> +
> +	.macro stneon reg1, reg2, reg3, reg4, ptr, val
> +	b	9997f
> +	.endm
> +#endif
> +
>   end	.req	x5
>   srcin	.req	x15
>   SYM_FUNC_START(__arch_copy_to_user)
>   	add	end, x0, x2
>   	mov	srcin, x1
> +#ifdef CONFIG_NEON_COPY_USER
> +	mov	x3, #0		/* disable neon copy */
> +#endif
>   #include "copy_template.S"
>   	mov	x0, #0
>   	ret
> diff --git a/arch/arm64/lib/copy_to_user_neon.S b/arch/arm64/lib/copy_to_user_neon.S
> new file mode 100644
> index 0000000000..51c2aba8a6
> --- /dev/null
> +++ b/arch/arm64/lib/copy_to_user_neon.S
> @@ -0,0 +1,96 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (C) 2012 ARM Ltd.
> + * Copyright (C) 2025 Huawei Ltd.
> + */
> +
> +#include <linux/linkage.h>
> +
> +#include <asm/asm-uaccess.h>
> +#include <asm/assembler.h>
> +#include <asm/cache.h>
> +
> +/*
> + * Copy to user space from a kernel buffer (alignment handled by the hardware)
> + *
> + * Parameters:
> + *	x0 - to
> + *	x1 - from
> + *	x2 - n
> + * Returns:
> + *	x0 - bytes not copied
> + */
> +	.macro ldrb1 reg, ptr, val
> +	ldrb  \reg, [\ptr], \val
> +	.endm
> +
> +	.macro strb1 reg, ptr, val
> +	user_ldst 9998f, sttrb, \reg, \ptr, \val
> +	.endm
> +
> +	.macro ldrh1 reg, ptr, val
> +	ldrh  \reg, [\ptr], \val
> +	.endm
> +
> +	.macro strh1 reg, ptr, val
> +	user_ldst 9997f, sttrh, \reg, \ptr, \val
> +	.endm
> +
> +	.macro ldr1 reg, ptr, val
> +	ldr \reg, [\ptr], \val
> +	.endm
> +
> +	.macro str1 reg, ptr, val
> +	user_ldst 9997f, sttr, \reg, \ptr, \val
> +	.endm
> +
> +	.macro ldp1 reg1, reg2, ptr, val
> +	ldp \reg1, \reg2, [\ptr], \val
> +	.endm
> +
> +	.macro stp1 reg1, reg2, ptr, val
> +	user_stp 9997f, \reg1, \reg2, \ptr, \val
> +	.endm
> +
> +	.macro cpy1 dst, src, count
> +	.arch_extension mops
> +	USER_CPY(9997f, 1, cpyfpwt [\dst]!, [\src]!, \count!)
> +	USER_CPY(9996f, 1, cpyfmwt [\dst]!, [\src]!, \count!)
> +	USER_CPY(9996f, 1, cpyfewt [\dst]!, [\src]!, \count!)
> +	.endm
> +
> +	.macro stneon reg1, reg2, reg3, reg4, ptr, val
> +	user_stneon 9987f, \reg1, \reg2, \reg3, \reg4, \ptr, \val
> +	.endm
> +
> +	.macro ldneon reg1, reg2, reg3, reg4, ptr, val
> +	ld1 {\reg1, \reg2, \reg3, \reg4}, [\ptr]
> +	add \ptr, \ptr, \val
> +	.endm
> +
> +end	.req	x5
> +srcin	.req	x15
> +SYM_FUNC_START(__arch_copy_to_user_neon)
> +	add	end, x0, x2
> +	mov	srcin, x1
> +	mov	x3, #1		/* enable neon copy */
> +#include "copy_template.S"
> +	mov	x0, #0
> +	ret
> +
> +	// Exception fixups
> +9987:	ld1	{V_a.16b, V_b.16b, V_c.16b, V_d.16b}, [sp]  /* restore current regs */
> +	add	sp, sp, #64
> +9996:	b.cs	9997f
> +	// Registers are in Option A format
> +	add	dst, dst, count
> +9997:	cmp	dst, dstin
> +	b.ne	9998f
> +	// Before being absolutely sure we couldn't copy anything, try harder
> +	ldrb	tmp1w, [srcin]
> +USER(9998f, sttrb tmp1w, [dst])
> +	add	dst, dst, #1
> +9998:	sub	x0, end, dst			// bytes not copied
> +	ret
> +SYM_FUNC_END(__arch_copy_to_user_neon)
> +EXPORT_SYMBOL(__arch_copy_to_user_neon)



From puranjay at kernel.org  Fri Dec 19 11:13:08 2025
From: puranjay at kernel.org (Puranjay Mohan)
Date: Fri, 19 Dec 2025 11:13:08 -0800
Subject: [PATCH bpf-next] bpf: arm64: fix sparse warnings
Message-ID: <20251219191310.3204425-1-puranjay@kernel.org>

ctx->image is declared as __le32 because arm64 instructions are LE
regardless of CPU's runtime endianness. emit_u32_data() emits raw data
and not instructions so cast the value to __le32 to fix the sparse
warning.

Cast function pointer to void * before doing arithmetic.

Signed-off-by: Puranjay Mohan <puranjay at kernel.org>
---
 arch/arm64/net/bpf_jit_comp.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
index b6eb7a465ad2..0c4d44bcfbf4 100644
--- a/arch/arm64/net/bpf_jit_comp.c
+++ b/arch/arm64/net/bpf_jit_comp.c
@@ -118,7 +118,7 @@ static inline void emit(const u32 insn, struct jit_ctx *ctx)
 static inline void emit_u32_data(const u32 data, struct jit_ctx *ctx)
 {
 	if (ctx->image != NULL && ctx->write)
-		ctx->image[ctx->idx] = data;
+		ctx->image[ctx->idx] = (__force __le32)data;
 
 	ctx->idx++;
 }
@@ -3139,7 +3139,7 @@ void bpf_jit_free(struct bpf_prog *prog)
 			bpf_jit_binary_pack_finalize(jit_data->ro_header, jit_data->header);
 			kfree(jit_data);
 		}
-		prog->bpf_func -= cfi_get_offset();
+		prog->bpf_func = (void *)prog->bpf_func - cfi_get_offset();
 		hdr = bpf_jit_binary_pack_hdr(prog);
 		bpf_jit_binary_pack_free(hdr, NULL);
 		priv_stack_ptr = prog->aux->priv_stack_ptr;

base-commit: ec439c38013550420aecc15988ae6acb670838c1
-- 
2.47.3



From nicolinc at nvidia.com  Fri Dec 19 11:17:03 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Fri, 19 Dec 2025 11:17:03 -0800
Subject: [PATCH v1 3/9] iommu/arm-smmu-v3: Store ASIDs and VMID in
 arm_smmu_master
In-Reply-To: <20251219151608.GE254720@nvidia.com>
References: <cover.1766088962.git.nicolinc@nvidia.com>
 <f7fa8725aab1fbd2c2a1d564e7493b16a586e88c.1766088962.git.nicolinc@nvidia.com>
 <20251219151608.GE254720@nvidia.com>
Message-ID: <aUWkr5e+C11mbx0X@Asurada-Nvidia>

On Fri, Dec 19, 2025 at 11:16:08AM -0400, Jason Gunthorpe wrote:
> On Thu, Dec 18, 2025 at 12:26:49PM -0800, Nicolin Chen wrote:
> > Currently, ASID is allocated per smmu_domain, stored in the domain, and
> > freed with the domain.
> > 
> > Practically, ASID is only used in a CD as an iotlb tag. Therefore, ASID
> > doesn't really follow the life cycle of a domain but domain attachment.
> > 
> > On the other hand, the CD carrying ASID is installed to a device's STE.
> > 
> > This applies to the VMID as well, which is installed in an STE directly.
> > 
> > Since a device can only have one ASID per SSID and one VMID per SID, add
> > an ASID array and VMID in the arm_smmu_master structure, to decouple the
> > ASID/VMID from the domain structure.
> 
> I don't think this is entirely right..
> 
> When a S1 is attached to a master the master needs to store the VMID
> it is using, as the VMID is global to the STE and effectively becomes
> global to the master.
>
> But the ASID should be stored in the invalidation list of the domain.

Hmm, you mean the nested case (host VMID + guest ASID), right?

But in that case, the guest-level ASID isn't needed anywhere in
the host driver? The ASID should be configured in a guest-level
CD. And the invalidation command directly coming from the guest
is already filled with the guest-level ASID.

Also, the invalidation array stores either ASID or VMID, there
is no case of storing both, right?

> Jus search the list for the (instance, vmid) pair of the master to get
> back the right ASID.
> 
> We don't need to store it again in another list, that's confusing.

Okay. I was trying to get rid of the extra for loop searching
for an ID in the array. That's why I had the alloc_id/free_id
ops too, so everything would be done in existing two loops in
the merge/unref functions.

Nicolin


From broonie at kernel.org  Fri Dec 19 11:28:06 2025
From: broonie at kernel.org (Mark Brown)
Date: Fri, 19 Dec 2025 19:28:06 +0000
Subject: [PATCH v3 0/4] KVM: selftests: arm64: Improve diagnostics from
 set_id_regs
Message-ID: <20251219-kvm-arm64-set-id-regs-aarch64-v3-0-bfa474ec3218@kernel.org>

While debugging issues related to aarch64 only systems I ran into
speedbumps due to the lack of detail in the results reported when the
guest register read and reset value preservation tests were run, they
generated an immediately fatal assert without indicating which register
was being tested. Update these tests to report a result per register,
making it much easier to see what the problem being reported is.

A similar, though less severe, issue exists with the validation of the
individual bitfields in registers due to the use of immediately fatal
asserts. Update those asserts to be standard kselftest reports.

Finally we have a fix for spurious errors on some NV systems.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
Changes in v3:
- Rebase onto v6.19-rc1.
- Link to v2: https://patch.msgid.link/20251114-kvm-arm64-set-id-regs-aarch64-v2-0-672f214f41bf at kernel.org

Changes in v2:
- Add a fix for spurious failures with 64 bit only guests.
- Link to v1: https://patch.msgid.link/20251030-kvm-arm64-set-id-regs-aarch64-v1-0-96fe0d2b178e at kernel.org

---
Mark Brown (4):
      KVM: selftests: arm64: Report set_id_reg reads of test registers as tests
      KVM: selftests: arm64: Report register reset tests individually
      KVM: selftests: arm64: Make set_id_regs bitfield validatity checks non-fatal
      KVM: selftests: arm64: Skip all 32 bit IDs when set_id_regs is aarch64 only

 tools/testing/selftests/kvm/arm64/set_id_regs.c | 150 ++++++++++++++++++------
 1 file changed, 111 insertions(+), 39 deletions(-)
---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20251028-kvm-arm64-set-id-regs-aarch64-ebb77969401c

Best regards,
--  
Mark Brown <broonie at kernel.org>



From broonie at kernel.org  Fri Dec 19 11:28:07 2025
From: broonie at kernel.org (Mark Brown)
Date: Fri, 19 Dec 2025 19:28:07 +0000
Subject: [PATCH v3 1/4] KVM: selftests: arm64: Report set_id_reg reads of
 test registers as tests
In-Reply-To: <20251219-kvm-arm64-set-id-regs-aarch64-v3-0-bfa474ec3218@kernel.org>
References: <20251219-kvm-arm64-set-id-regs-aarch64-v3-0-bfa474ec3218@kernel.org>
Message-ID: <20251219-kvm-arm64-set-id-regs-aarch64-v3-1-bfa474ec3218@kernel.org>

Currently when we run guest code to validate that the values we wrote to
the registers are seen by the guest we assert that these values match using
a KVM selftests level assert, resulting in unclear diagnostics if the test
fails. Replace this assert with reporting a kselftest test per register.

In order to support getting the names of the registers we repaint the array
of ID_ registers to store the names and open code the rest.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 tools/testing/selftests/kvm/arm64/set_id_regs.c | 74 +++++++++++++++++++------
 1 file changed, 57 insertions(+), 17 deletions(-)

diff --git a/tools/testing/selftests/kvm/arm64/set_id_regs.c b/tools/testing/selftests/kvm/arm64/set_id_regs.c
index c4815d365816..84e9484a4899 100644
--- a/tools/testing/selftests/kvm/arm64/set_id_regs.c
+++ b/tools/testing/selftests/kvm/arm64/set_id_regs.c
@@ -40,6 +40,7 @@ struct reg_ftr_bits {
 };
 
 struct test_feature_reg {
+	const char *name;
 	uint32_t reg;
 	const struct reg_ftr_bits *ftr_bits;
 };
@@ -218,24 +219,25 @@ static const struct reg_ftr_bits ftr_id_aa64zfr0_el1[] = {
 
 #define TEST_REG(id, table)			\
 	{					\
-		.reg = id,			\
+		.name = #id,			\
+		.reg = SYS_ ## id,		\
 		.ftr_bits = &((table)[0]),	\
 	}
 
 static struct test_feature_reg test_regs[] = {
-	TEST_REG(SYS_ID_AA64DFR0_EL1, ftr_id_aa64dfr0_el1),
-	TEST_REG(SYS_ID_DFR0_EL1, ftr_id_dfr0_el1),
-	TEST_REG(SYS_ID_AA64ISAR0_EL1, ftr_id_aa64isar0_el1),
-	TEST_REG(SYS_ID_AA64ISAR1_EL1, ftr_id_aa64isar1_el1),
-	TEST_REG(SYS_ID_AA64ISAR2_EL1, ftr_id_aa64isar2_el1),
-	TEST_REG(SYS_ID_AA64ISAR3_EL1, ftr_id_aa64isar3_el1),
-	TEST_REG(SYS_ID_AA64PFR0_EL1, ftr_id_aa64pfr0_el1),
-	TEST_REG(SYS_ID_AA64PFR1_EL1, ftr_id_aa64pfr1_el1),
-	TEST_REG(SYS_ID_AA64MMFR0_EL1, ftr_id_aa64mmfr0_el1),
-	TEST_REG(SYS_ID_AA64MMFR1_EL1, ftr_id_aa64mmfr1_el1),
-	TEST_REG(SYS_ID_AA64MMFR2_EL1, ftr_id_aa64mmfr2_el1),
-	TEST_REG(SYS_ID_AA64MMFR3_EL1, ftr_id_aa64mmfr3_el1),
-	TEST_REG(SYS_ID_AA64ZFR0_EL1, ftr_id_aa64zfr0_el1),
+	TEST_REG(ID_AA64DFR0_EL1, ftr_id_aa64dfr0_el1),
+	TEST_REG(ID_DFR0_EL1, ftr_id_dfr0_el1),
+	TEST_REG(ID_AA64ISAR0_EL1, ftr_id_aa64isar0_el1),
+	TEST_REG(ID_AA64ISAR1_EL1, ftr_id_aa64isar1_el1),
+	TEST_REG(ID_AA64ISAR2_EL1, ftr_id_aa64isar2_el1),
+	TEST_REG(ID_AA64ISAR3_EL1, ftr_id_aa64isar3_el1),
+	TEST_REG(ID_AA64PFR0_EL1, ftr_id_aa64pfr0_el1),
+	TEST_REG(ID_AA64PFR1_EL1, ftr_id_aa64pfr1_el1),
+	TEST_REG(ID_AA64MMFR0_EL1, ftr_id_aa64mmfr0_el1),
+	TEST_REG(ID_AA64MMFR1_EL1, ftr_id_aa64mmfr1_el1),
+	TEST_REG(ID_AA64MMFR2_EL1, ftr_id_aa64mmfr2_el1),
+	TEST_REG(ID_AA64MMFR3_EL1, ftr_id_aa64mmfr3_el1),
+	TEST_REG(ID_AA64ZFR0_EL1, ftr_id_aa64zfr0_el1),
 };
 
 #define GUEST_REG_SYNC(id) GUEST_SYNC_ARGS(0, id, read_sysreg_s(id), 0, 0);
@@ -265,6 +267,34 @@ static void guest_code(void)
 	GUEST_DONE();
 }
 
+#define GUEST_READ_TEST (ARRAY_SIZE(test_regs) + 6)
+
+static const char *get_reg_name(u64 id)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(test_regs); i++)
+		if (test_regs[i].reg == id)
+			return test_regs[i].name;
+
+	switch (id) {
+	case SYS_MPIDR_EL1:
+		return "MPIDR_EL1";
+	case SYS_CLIDR_EL1:
+		return "CLIDR_EL1";
+	case SYS_CTR_EL0:
+		return "CTR_EL0";
+	case SYS_MIDR_EL1:
+		return "MIDR_EL1";
+	case SYS_REVIDR_EL1:
+		return "REVIDR_EL1";
+	case SYS_AIDR_EL1:
+		return "AIDR_EL1";
+	default:
+		TEST_FAIL("Unknown register");
+	}
+}
+
 /* Return a safe value to a given ftr_bits an ftr value */
 uint64_t get_safe_value(const struct reg_ftr_bits *ftr_bits, uint64_t ftr)
 {
@@ -639,6 +669,8 @@ static void test_guest_reg_read(struct kvm_vcpu *vcpu)
 {
 	bool done = false;
 	struct ucall uc;
+	uint64_t reg_id, expected_val, guest_val;
+	bool match;
 
 	while (!done) {
 		vcpu_run(vcpu);
@@ -649,8 +681,16 @@ static void test_guest_reg_read(struct kvm_vcpu *vcpu)
 			break;
 		case UCALL_SYNC:
 			/* Make sure the written values are seen by guest */
-			TEST_ASSERT_EQ(test_reg_vals[encoding_to_range_idx(uc.args[2])],
-				       uc.args[3]);
+			reg_id = uc.args[2];
+			guest_val = uc.args[3];
+			expected_val = test_reg_vals[encoding_to_range_idx(reg_id)];
+			match = expected_val == guest_val;
+			if (!match)
+				ksft_print_msg("%lx != %lx\n",
+					       expected_val, guest_val);
+			ksft_test_result(match,
+					 "%s value seen in guest\n",
+					 get_reg_name(reg_id));
 			break;
 		case UCALL_DONE:
 			done = true;
@@ -790,7 +830,7 @@ int main(void)
 
 	ksft_print_header();
 
-	test_cnt = 3 + MPAM_IDREG_TEST + MTE_IDREG_TEST;
+	test_cnt = 3 + MPAM_IDREG_TEST + MTE_IDREG_TEST + GUEST_READ_TEST;
 	for (i = 0; i < ARRAY_SIZE(test_regs); i++)
 		for (j = 0; test_regs[i].ftr_bits[j].type != FTR_END; j++)
 			test_cnt++;

-- 
2.47.3



From broonie at kernel.org  Fri Dec 19 11:28:08 2025
From: broonie at kernel.org (Mark Brown)
Date: Fri, 19 Dec 2025 19:28:08 +0000
Subject: [PATCH v3 2/4] KVM: selftests: arm64: Report register reset tests
 individually
In-Reply-To: <20251219-kvm-arm64-set-id-regs-aarch64-v3-0-bfa474ec3218@kernel.org>
References: <20251219-kvm-arm64-set-id-regs-aarch64-v3-0-bfa474ec3218@kernel.org>
Message-ID: <20251219-kvm-arm64-set-id-regs-aarch64-v3-2-bfa474ec3218@kernel.org>

set_id_regs tests that registers have their values preserved over reset.
Currently it reports all registers in a single test with an instantly fatal
assert which isn't great for diagnostics, it's hard to tell which register
failed or if it's just one register. Change this to report each register as
a separate test so that it's clear from the program output which registers
have problems.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 tools/testing/selftests/kvm/arm64/set_id_regs.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/tools/testing/selftests/kvm/arm64/set_id_regs.c b/tools/testing/selftests/kvm/arm64/set_id_regs.c
index 84e9484a4899..b61942895808 100644
--- a/tools/testing/selftests/kvm/arm64/set_id_regs.c
+++ b/tools/testing/selftests/kvm/arm64/set_id_regs.c
@@ -779,11 +779,18 @@ static void test_assert_id_reg_unchanged(struct kvm_vcpu *vcpu, uint32_t encodin
 {
 	size_t idx = encoding_to_range_idx(encoding);
 	uint64_t observed;
+	bool pass;
 
 	observed = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(encoding));
-	TEST_ASSERT_EQ(test_reg_vals[idx], observed);
+	pass = test_reg_vals[idx] == observed;
+	if (!pass)
+		ksft_print_msg("%lx != %lx\n", test_reg_vals[idx], observed);
+	ksft_test_result(pass, "%s unchanged by reset\n",
+			 get_reg_name(encoding));
 }
 
+#define ID_REG_RESET_UNCHANGED_TEST (ARRAY_SIZE(test_regs) + 6)
+
 static void test_reset_preserves_id_regs(struct kvm_vcpu *vcpu)
 {
 	/*
@@ -801,8 +808,6 @@ static void test_reset_preserves_id_regs(struct kvm_vcpu *vcpu)
 	test_assert_id_reg_unchanged(vcpu, SYS_MIDR_EL1);
 	test_assert_id_reg_unchanged(vcpu, SYS_REVIDR_EL1);
 	test_assert_id_reg_unchanged(vcpu, SYS_AIDR_EL1);
-
-	ksft_test_result_pass("%s\n", __func__);
 }
 
 int main(void)
@@ -830,7 +835,8 @@ int main(void)
 
 	ksft_print_header();
 
-	test_cnt = 3 + MPAM_IDREG_TEST + MTE_IDREG_TEST + GUEST_READ_TEST;
+	test_cnt = 2 + MPAM_IDREG_TEST + MTE_IDREG_TEST + GUEST_READ_TEST +
+		ID_REG_RESET_UNCHANGED_TEST;
 	for (i = 0; i < ARRAY_SIZE(test_regs); i++)
 		for (j = 0; test_regs[i].ftr_bits[j].type != FTR_END; j++)
 			test_cnt++;

-- 
2.47.3



From broonie at kernel.org  Fri Dec 19 11:28:09 2025
From: broonie at kernel.org (Mark Brown)
Date: Fri, 19 Dec 2025 19:28:09 +0000
Subject: [PATCH v3 3/4] KVM: selftests: arm64: Make set_id_regs bitfield
 validatity checks non-fatal
In-Reply-To: <20251219-kvm-arm64-set-id-regs-aarch64-v3-0-bfa474ec3218@kernel.org>
References: <20251219-kvm-arm64-set-id-regs-aarch64-v3-0-bfa474ec3218@kernel.org>
Message-ID: <20251219-kvm-arm64-set-id-regs-aarch64-v3-3-bfa474ec3218@kernel.org>

Currently when set_id_regs encounters a problem checking validation of
writes to feature registers it uses an immediately fatal assert to report
the problem. This is not idiomatic for kselftest, and it is also not great
for usability. The affected bitfield is not clearly reported and further
tests do not have their results reported.

Switch to using standard kselftest result reporting for the two asserts
we do, these are non-fatal asserts so allow the program to continue and the
test names include the affected field.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 tools/testing/selftests/kvm/arm64/set_id_regs.c | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/tools/testing/selftests/kvm/arm64/set_id_regs.c b/tools/testing/selftests/kvm/arm64/set_id_regs.c
index b61942895808..5837da63e9b9 100644
--- a/tools/testing/selftests/kvm/arm64/set_id_regs.c
+++ b/tools/testing/selftests/kvm/arm64/set_id_regs.c
@@ -409,6 +409,7 @@ static uint64_t test_reg_set_success(struct kvm_vcpu *vcpu, uint64_t reg,
 	uint8_t shift = ftr_bits->shift;
 	uint64_t mask = ftr_bits->mask;
 	uint64_t val, new_val, ftr;
+	bool match;
 
 	val = vcpu_get_reg(vcpu, reg);
 	ftr = (val & mask) >> shift;
@@ -421,7 +422,10 @@ static uint64_t test_reg_set_success(struct kvm_vcpu *vcpu, uint64_t reg,
 
 	vcpu_set_reg(vcpu, reg, val);
 	new_val = vcpu_get_reg(vcpu, reg);
-	TEST_ASSERT_EQ(new_val, val);
+	match = new_val == val;
+	if (!match)
+		ksft_print_msg("%lx != %lx\n", new_val, val);
+	ksft_test_result(match, "%s valid write succeeded\n", ftr_bits->name);
 
 	return new_val;
 }
@@ -433,6 +437,7 @@ static void test_reg_set_fail(struct kvm_vcpu *vcpu, uint64_t reg,
 	uint64_t mask = ftr_bits->mask;
 	uint64_t val, old_val, ftr;
 	int r;
+	bool match;
 
 	val = vcpu_get_reg(vcpu, reg);
 	ftr = (val & mask) >> shift;
@@ -449,7 +454,10 @@ static void test_reg_set_fail(struct kvm_vcpu *vcpu, uint64_t reg,
 		    "Unexpected KVM_SET_ONE_REG error: r=%d, errno=%d", r, errno);
 
 	val = vcpu_get_reg(vcpu, reg);
-	TEST_ASSERT_EQ(val, old_val);
+	match = val == old_val;
+	if (!match)
+		ksft_print_msg("%lx != %lx\n", val, old_val);
+	ksft_test_result(match, "%s invalid write rejected\n", ftr_bits->name);
 }
 
 static uint64_t test_reg_vals[KVM_ARM_FEATURE_ID_RANGE_SIZE];
@@ -489,7 +497,11 @@ static void test_vm_ftr_id_regs(struct kvm_vcpu *vcpu, bool aarch64_only)
 		for (int j = 0;  ftr_bits[j].type != FTR_END; j++) {
 			/* Skip aarch32 reg on aarch64 only system, since they are RAZ/WI. */
 			if (aarch64_only && sys_reg_CRm(reg_id) < 4) {
-				ksft_test_result_skip("%s on AARCH64 only system\n",
+				ksft_print_msg("%s on AARCH64 only system\n",
+					       ftr_bits[j].name);
+				ksft_test_result_skip("%s invalid write rejected\n",
+						      ftr_bits[j].name);
+				ksft_test_result_skip("%s valid write succeeded\n",
 						      ftr_bits[j].name);
 				continue;
 			}
@@ -501,8 +513,6 @@ static void test_vm_ftr_id_regs(struct kvm_vcpu *vcpu, bool aarch64_only)
 
 			test_reg_vals[idx] = test_reg_set_success(vcpu, reg,
 								  &ftr_bits[j]);
-
-			ksft_test_result_pass("%s\n", ftr_bits[j].name);
 		}
 	}
 }
@@ -839,7 +849,7 @@ int main(void)
 		ID_REG_RESET_UNCHANGED_TEST;
 	for (i = 0; i < ARRAY_SIZE(test_regs); i++)
 		for (j = 0; test_regs[i].ftr_bits[j].type != FTR_END; j++)
-			test_cnt++;
+			test_cnt += 2;
 
 	ksft_set_plan(test_cnt);
 

-- 
2.47.3



From broonie at kernel.org  Fri Dec 19 11:28:10 2025
From: broonie at kernel.org (Mark Brown)
Date: Fri, 19 Dec 2025 19:28:10 +0000
Subject: [PATCH v3 4/4] KVM: selftests: arm64: Skip all 32 bit IDs when
 set_id_regs is aarch64 only
In-Reply-To: <20251219-kvm-arm64-set-id-regs-aarch64-v3-0-bfa474ec3218@kernel.org>
References: <20251219-kvm-arm64-set-id-regs-aarch64-v3-0-bfa474ec3218@kernel.org>
Message-ID: <20251219-kvm-arm64-set-id-regs-aarch64-v3-4-bfa474ec3218@kernel.org>

On an aarch64 only system the 32 bit ID registers have UNDEFINED values.
As a result set_id_regs skips tests for setting fields in these registers
when testing an aarch64 only guest. This has the side effect of meaning
that we don't record an expected value for these registers, meaning that
when the subsequent tests for values being visible in guests and preserved
over reset check the value they can spuriously fail. This can be seen by
running on an emulated system with both NV and 32 bit enabled, NV will
result in the guests created by the test program being 64 bit only but
the 32 bit ID registers will have values.

Also skip those tests that use the values set in the field setting tests
for aarch64 only guests in order to avoid these spurious failures.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 tools/testing/selftests/kvm/arm64/set_id_regs.c | 42 +++++++++++++++++--------
 1 file changed, 29 insertions(+), 13 deletions(-)

diff --git a/tools/testing/selftests/kvm/arm64/set_id_regs.c b/tools/testing/selftests/kvm/arm64/set_id_regs.c
index 5837da63e9b9..f19ba949aa18 100644
--- a/tools/testing/selftests/kvm/arm64/set_id_regs.c
+++ b/tools/testing/selftests/kvm/arm64/set_id_regs.c
@@ -675,7 +675,7 @@ static void test_user_set_mte_reg(struct kvm_vcpu *vcpu)
 		ksft_test_result_pass("ID_AA64PFR1_EL1.MTE_frac no longer 0xF\n");
 }
 
-static void test_guest_reg_read(struct kvm_vcpu *vcpu)
+static void test_guest_reg_read(struct kvm_vcpu *vcpu, bool aarch64_only)
 {
 	bool done = false;
 	struct ucall uc;
@@ -694,6 +694,13 @@ static void test_guest_reg_read(struct kvm_vcpu *vcpu)
 			reg_id = uc.args[2];
 			guest_val = uc.args[3];
 			expected_val = test_reg_vals[encoding_to_range_idx(reg_id)];
+
+			if (aarch64_only && sys_reg_CRm(reg_id) < 4) {
+				ksft_test_result_skip("%s value seen in guest\n",
+						      get_reg_name(reg_id));
+				break;
+			}
+
 			match = expected_val == guest_val;
 			if (!match)
 				ksft_print_msg("%lx != %lx\n",
@@ -785,12 +792,19 @@ static void test_vcpu_non_ftr_id_regs(struct kvm_vcpu *vcpu)
 	ksft_test_result_pass("%s\n", __func__);
 }
 
-static void test_assert_id_reg_unchanged(struct kvm_vcpu *vcpu, uint32_t encoding)
+static void test_assert_id_reg_unchanged(struct kvm_vcpu *vcpu, uint32_t encoding,
+					 bool aarch64_only)
 {
 	size_t idx = encoding_to_range_idx(encoding);
 	uint64_t observed;
 	bool pass;
 
+	if (aarch64_only && sys_reg_CRm(encoding) < 4) {
+		ksft_test_result_skip("%s unchanged by reset\n",
+				      get_reg_name(encoding));
+		return;
+	}
+
 	observed = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(encoding));
 	pass = test_reg_vals[idx] == observed;
 	if (!pass)
@@ -801,7 +815,8 @@ static void test_assert_id_reg_unchanged(struct kvm_vcpu *vcpu, uint32_t encodin
 
 #define ID_REG_RESET_UNCHANGED_TEST (ARRAY_SIZE(test_regs) + 6)
 
-static void test_reset_preserves_id_regs(struct kvm_vcpu *vcpu)
+static void test_reset_preserves_id_regs(struct kvm_vcpu *vcpu,
+					 bool aarch64_only)
 {
 	/*
 	 * Calls KVM_ARM_VCPU_INIT behind the scenes, which will do an
@@ -810,14 +825,15 @@ static void test_reset_preserves_id_regs(struct kvm_vcpu *vcpu)
 	aarch64_vcpu_setup(vcpu, NULL);
 
 	for (int i = 0; i < ARRAY_SIZE(test_regs); i++)
-		test_assert_id_reg_unchanged(vcpu, test_regs[i].reg);
-
-	test_assert_id_reg_unchanged(vcpu, SYS_MPIDR_EL1);
-	test_assert_id_reg_unchanged(vcpu, SYS_CLIDR_EL1);
-	test_assert_id_reg_unchanged(vcpu, SYS_CTR_EL0);
-	test_assert_id_reg_unchanged(vcpu, SYS_MIDR_EL1);
-	test_assert_id_reg_unchanged(vcpu, SYS_REVIDR_EL1);
-	test_assert_id_reg_unchanged(vcpu, SYS_AIDR_EL1);
+		test_assert_id_reg_unchanged(vcpu, test_regs[i].reg,
+					     aarch64_only);
+
+	test_assert_id_reg_unchanged(vcpu, SYS_MPIDR_EL1, aarch64_only);
+	test_assert_id_reg_unchanged(vcpu, SYS_CLIDR_EL1, aarch64_only);
+	test_assert_id_reg_unchanged(vcpu, SYS_CTR_EL0, aarch64_only);
+	test_assert_id_reg_unchanged(vcpu, SYS_MIDR_EL1, aarch64_only);
+	test_assert_id_reg_unchanged(vcpu, SYS_REVIDR_EL1, aarch64_only);
+	test_assert_id_reg_unchanged(vcpu, SYS_AIDR_EL1, aarch64_only);
 }
 
 int main(void)
@@ -859,9 +875,9 @@ int main(void)
 	test_user_set_mpam_reg(vcpu);
 	test_user_set_mte_reg(vcpu);
 
-	test_guest_reg_read(vcpu);
+	test_guest_reg_read(vcpu, aarch64_only);
 
-	test_reset_preserves_id_regs(vcpu);
+	test_reset_preserves_id_regs(vcpu, aarch64_only);
 
 	kvm_vm_free(vm);
 

-- 
2.47.3



From bmasney at redhat.com  Fri Dec 19 11:48:56 2025
From: bmasney at redhat.com (Brian Masney)
Date: Fri, 19 Dec 2025 14:48:56 -0500
Subject: [PATCH v6 0/6] clk: Support spread spectrum and use it in
 clk-scmi
In-Reply-To: <aTvpmQAPE6HfIy+r@shlinux89>
References: <20251128-clk-ssc-v6-2-v6-0-cfafdb5d6811@nxp.com>
 <aTvpmQAPE6HfIy+r@shlinux89>
Message-ID: <aUWsKAMDm9_5jxsg@redhat.com>

On Fri, Dec 12, 2025 at 06:08:25PM +0800, Peng Fan wrote:
> Sorry for top-posting. There is only one comment from Krzysztof regarding
> cleanup API usage. Since 6.19 rc1 still not out, I will wait two more weeks
> to collect comments, then post v7. Hopefully, you are ok with current
> clk-scmi-oem stuff.

I can't speak to the SCMI OEM extensions, however the other clk patches
look good to me FWIW. My Reviewed-by tags still apply.

Brian



From oupton at kernel.org  Fri Dec 19 12:01:30 2025
From: oupton at kernel.org (Oliver Upton)
Date: Fri, 19 Dec 2025 12:01:30 -0800
Subject: [PATCH v2 05/45] KVM: arm64: Preserve host MPAM configuration
 when changing traps
In-Reply-To: <20251219181147.3404071-6-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
 <20251219181147.3404071-6-ben.horgan@arm.com>
Message-ID: <aUWvGjGyU7DUW8MI@kernel.org>

Hi Ben,

On Fri, Dec 19, 2025 at 06:11:07PM +0000, Ben Horgan wrote:
> When kvm enables or disables MPAM traps to EL2 it clears all other bits in
> MPAM2_EL2.  Notably, it clears the partition ids (PARTIDs) and performance
> monitoring groups (PMGs). Avoid changing these bits in anticipation of
> adding support for MPAM in the kernel. Otherwise, on a VHE system with the
> host running at EL2 where MPAM2_EL2 and MPAM1_EL1 access the same register,
> any attempt to use MPAM to monitor or partition resources for kernel space
> would be foiled by running a KVM guest. Additionally, MPAM2_EL2.EnMPAMSM is
> always set to 0 which causes MPAMSM_EL1 to always trap. Keep EnMPAMSM set
> to 1 when not in a guest so that the kernel can use MPAMSM_EL1.
> 
> Signed-off-by: Ben Horgan <ben.horgan at arm.com>
> ---
>  arch/arm64/kvm/hyp/include/hyp/switch.h | 12 ++++++++----
>  1 file changed, 8 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
> index c5d5e5b86eaf..63195275a8b8 100644
> --- a/arch/arm64/kvm/hyp/include/hyp/switch.h
> +++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
> @@ -269,7 +269,8 @@ static inline void __deactivate_traps_hfgxtr(struct kvm_vcpu *vcpu)
>  
>  static inline void  __activate_traps_mpam(struct kvm_vcpu *vcpu)
>  {
> -	u64 r = MPAM2_EL2_TRAPMPAM0EL1 | MPAM2_EL2_TRAPMPAM1EL1;
> +	u64 clr = MPAM2_EL2_EnMPAMSM;
> +	u64 set = MPAM2_EL2_TRAPMPAM0EL1 | MPAM2_EL2_TRAPMPAM1EL1;
>  
>  	if (!system_supports_mpam())
>  		return;
> @@ -279,18 +280,21 @@ static inline void  __activate_traps_mpam(struct kvm_vcpu *vcpu)
>  		write_sysreg_s(MPAMHCR_EL2_TRAP_MPAMIDR_EL1, SYS_MPAMHCR_EL2);
>  	} else {
>  		/* From v1.1 TIDR can trap MPAMIDR, set it unconditionally */
> -		r |= MPAM2_EL2_TIDR;
> +		set |= MPAM2_EL2_TIDR;
>  	}
>  
> -	write_sysreg_s(r, SYS_MPAM2_EL2);
> +	sysreg_clear_set_s(SYS_MPAM2_EL2, clr, set);

I'd recommend documenting that writes to MPAM1_EL1 are followed by an
ISB. Otherwise it isn't obvious here where context synchronization is
happening (if at all).

Thanks,
Oliver


From oupton at kernel.org  Fri Dec 19 12:10:22 2025
From: oupton at kernel.org (Oliver Upton)
Date: Fri, 19 Dec 2025 12:10:22 -0800
Subject: [PATCH v2 13/45] KVM: arm64: Force guest EL1 to use user-space's
 partid configuration
In-Reply-To: <20251219181147.3404071-14-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
 <20251219181147.3404071-14-ben.horgan@arm.com>
Message-ID: <aUWxLp2GUk2_p58e@kernel.org>

On Fri, Dec 19, 2025 at 06:11:15PM +0000, Ben Horgan wrote:
> From: James Morse <james.morse at arm.com>
> 
> While we trap the guest's attempts to read/write the MPAM control
> registers, the hardware continues to use them. Guest-EL0 uses KVM's
> user-space's configuration, as the value is left in the register, and
> guest-EL1 uses either the host kernel's configuration, or in the case of
> VHE, the UNKNOWN reset value of MPAM1_EL1.
> 
> We want to force the guest-EL1 to use KVM's user-space's MPAM
> configuration. On nVHE rely on MPAM0_EL1 and MPAM1_EL1 always being
> programmed the same and on VHE copy MPAM0_EL1 into the guest's
> MPAM1_EL1. There is no need to restore as this is out of context once TGE
> is set.
> 
> Signed-off-by: James Morse <james.morse at arm.com>
> Signed-off-by: Ben Horgan <ben.horgan at arm.com>
> ---
> Changes since rfc:
> Drop the unneeded __mpam_guest_load() in nvhre and the MPAM1_EL1 save restore
> Defer EL2 handling until next patch
> ---
>  arch/arm64/kvm/hyp/vhe/sysreg-sr.c | 11 +++++++++++
>  1 file changed, 11 insertions(+)
> 
> diff --git a/arch/arm64/kvm/hyp/vhe/sysreg-sr.c b/arch/arm64/kvm/hyp/vhe/sysreg-sr.c
> index f28c6cf4fe1b..a2e8f6187675 100644
> --- a/arch/arm64/kvm/hyp/vhe/sysreg-sr.c
> +++ b/arch/arm64/kvm/hyp/vhe/sysreg-sr.c
> @@ -183,6 +183,16 @@ void sysreg_restore_guest_state_vhe(struct kvm_cpu_context *ctxt)
>  }
>  NOKPROBE_SYMBOL(sysreg_restore_guest_state_vhe);
>  
> +/*
> + * The _EL0 value was written by the host's context switch and belongs to the
> + * VMM. Copy this into the guest's _EL1 register.
> + */
> +static inline void __mpam_guest_load(void)
> +{
> +	if (system_supports_mpam())
> +		write_sysreg_el1(read_sysreg_s(SYS_MPAM0_EL1), SYS_MPAM1);

nit: I'd prefer using a mask to extract the fields of interest, guarding
against future architecture doing something silly with the RES0 fields
of these registers.

Thanks,
Oliver


From nicolinc at nvidia.com  Fri Dec 19 12:11:23 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Fri, 19 Dec 2025 12:11:23 -0800
Subject: [PATCH v9 1/7] iommu/arm-smmu-v3: Explicitly set smmu_domain->stage for SVA
In-Reply-To: <cover.1766174731.git.nicolinc@nvidia.com>
References: <cover.1766174731.git.nicolinc@nvidia.com>
Message-ID: <df4b8cbc0d67a0bfcccb09be868e0da5f0cbb743.1766174731.git.nicolinc@nvidia.com>

Both the ARM_SMMU_DOMAIN_S1 case and the SVA case use ASID, requiring ASID
based invalidation commands to flush the TLB.

Define an ARM_SMMU_DOMAIN_SVA to make the SVA case clear to share the same
path with the ARM_SMMU_DOMAIN_S1 case, which will be a part of the routine
to build a new per-domain invalidation array.

There is no function change.

Suggested-by: Jason Gunthorpe <jgg at nvidia.com>
Acked-by: Balbir Singh <balbirs at nvidia.com>
Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h     | 1 +
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 1 +
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c     | 3 +++
 3 files changed, 5 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index ae23aacc3840..5c0b38595d20 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -858,6 +858,7 @@ struct arm_smmu_master {
 enum arm_smmu_domain_stage {
 	ARM_SMMU_DOMAIN_S1 = 0,
 	ARM_SMMU_DOMAIN_S2,
+	ARM_SMMU_DOMAIN_SVA,
 };
 
 struct arm_smmu_domain {
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index 59a480974d80..6097f1f540d8 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -346,6 +346,7 @@ struct iommu_domain *arm_smmu_sva_domain_alloc(struct device *dev,
 	 * ARM_SMMU_FEAT_RANGE_INV is present
 	 */
 	smmu_domain->domain.pgsize_bitmap = PAGE_SIZE;
+	smmu_domain->stage = ARM_SMMU_DOMAIN_SVA;
 	smmu_domain->smmu = smmu;
 
 	ret = xa_alloc(&arm_smmu_asid_xa, &asid, smmu_domain,
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index d16d35c78c06..9d9f24a08062 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -3065,6 +3065,9 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev,
 		arm_smmu_install_ste_for_dev(master, &target);
 		arm_smmu_clear_cd(master, IOMMU_NO_PASID);
 		break;
+	default:
+		WARN_ON(true);
+		break;
 	}
 
 	arm_smmu_attach_commit(&state);
-- 
2.43.0



From nicolinc at nvidia.com  Fri Dec 19 12:11:24 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Fri, 19 Dec 2025 12:11:24 -0800
Subject: [PATCH v9 2/7] iommu/arm-smmu-v3: Add an inline arm_smmu_domain_free()
In-Reply-To: <cover.1766174731.git.nicolinc@nvidia.com>
References: <cover.1766174731.git.nicolinc@nvidia.com>
Message-ID: <b516338bdde0bc6f06e2719b9292ffa260085a67.1766174731.git.nicolinc@nvidia.com>

There will be a bit more things to free than smmu_domain itself. So keep a
simple inline function in the header to share aross files.

Suggested-by: Jason Gunthorpe <jgg at nvidia.com>
Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
Acked-by: Balbir Singh <balbirs at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h     | 5 +++++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 5 +++--
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c     | 4 ++--
 3 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index 5c0b38595d20..96a23ca633cb 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -954,6 +954,11 @@ extern struct mutex arm_smmu_asid_lock;
 
 struct arm_smmu_domain *arm_smmu_domain_alloc(void);
 
+static inline void arm_smmu_domain_free(struct arm_smmu_domain *smmu_domain)
+{
+	kfree(smmu_domain);
+}
+
 void arm_smmu_clear_cd(struct arm_smmu_master *master, ioasid_t ssid);
 struct arm_smmu_cd *arm_smmu_get_cd_ptr(struct arm_smmu_master *master,
 					u32 ssid);
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index 6097f1f540d8..440ad8cc07de 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -197,7 +197,8 @@ static void arm_smmu_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
 
 static void arm_smmu_mmu_notifier_free(struct mmu_notifier *mn)
 {
-	kfree(container_of(mn, struct arm_smmu_domain, mmu_notifier));
+	arm_smmu_domain_free(
+		container_of(mn, struct arm_smmu_domain, mmu_notifier));
 }
 
 static const struct mmu_notifier_ops arm_smmu_mmu_notifier_ops = {
@@ -365,6 +366,6 @@ struct iommu_domain *arm_smmu_sva_domain_alloc(struct device *dev,
 err_asid:
 	xa_erase(&arm_smmu_asid_xa, smmu_domain->cd.asid);
 err_free:
-	kfree(smmu_domain);
+	arm_smmu_domain_free(smmu_domain);
 	return ERR_PTR(ret);
 }
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 9d9f24a08062..e9759e8af0c0 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2492,7 +2492,7 @@ static void arm_smmu_domain_free_paging(struct iommu_domain *domain)
 			ida_free(&smmu->vmid_map, cfg->vmid);
 	}
 
-	kfree(smmu_domain);
+	arm_smmu_domain_free(smmu_domain);
 }
 
 static int arm_smmu_domain_finalise_s1(struct arm_smmu_device *smmu,
@@ -3359,7 +3359,7 @@ arm_smmu_domain_alloc_paging_flags(struct device *dev, u32 flags,
 	return &smmu_domain->domain;
 
 err_free:
-	kfree(smmu_domain);
+	arm_smmu_domain_free(smmu_domain);
 	return ERR_PTR(ret);
 }
 
-- 
2.43.0



From nicolinc at nvidia.com  Fri Dec 19 12:11:22 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Fri, 19 Dec 2025 12:11:22 -0800
Subject: [PATCH v9 0/7] iommu/arm-smmu-v3: Introduce an RCU-protected invalidation array
Message-ID: <cover.1766174731.git.nicolinc@nvidia.com>

This is a work based on Jason's design and algorithm. This implementation
follows his initial draft and revising as well.

The new arm_smmu_invs array is an RCU-protected array, mutated when device
attach to the domain, iterated when an invalidation is required for IOPTE
changes in this domain. This keeps the current invalidation efficiency of
a smb_mb() followed by a conditional rwlock replacing the atomic/spinlock
combination.

A new data structure is defined for the array and its entry, representing
invalidation operations, such as S1_ASID, S2_VMID, and ATS. The algorithm
adds and deletes array entries efficiently and also keeps the array sorted
so as to group similar invalidations into batches.

During an invalidation, a new invalidation function iterates domain->invs,
and converts each entry to the corresponding invalidation command(s). This
new function is fully compatible with all the existing use cases, allowing
a simple rework/replacement.

Some races to keep in mind:

1) A domain can be shared across SMMU instances. When an SMMU instance is
   removed, the updated invs array has to be sync-ed via synchronize_rcu()
   to prevent an concurrent invalidation routine that is accessing the old
   array from issuing commands to the removed SMMU instance.

2) When there are concurrent IOPTE changes (followed by invalidations) and
   a domain attachment, the new attachment must not become out of sync at
   the HW level, meaning that an STE store and invalidation array load must
   be sequenced by the CPU's memory model.

3) When an ATS-enabled device attaches to a blocking domain, the core code
   requires a hard fence to ensure all ATS invalidations to the device are
   completed. Relying on RCU alone requires calling synchronize_rcu() that
   can be too slow. Instead, when ATS is in use, hold a conditional rwlock
   till all concurrent invalidations are finished.

Related future work and dependent projects:

 * NVIDIA is building systems with > 10 SMMU instances where > 8 are being
   used concurrently in a single VM. So having 8 copies of an identical S2
   page table is not efficient. Instead, all vSMMU instances should check
   compatibility on a shared S2 iopt, to eliminate 7 copies.

   Previous attempt based on the list/spinlock design:
     iommu/arm-smmu-v3: Allocate vmid per vsmmu instead of s2_parent
     https://lore.kernel.org/all/cover.1744692494.git.nicolinc at nvidia.com/
   now can adopt this invs array, avoiding adding complex lists/locks.

 * The guest support for BTM requires temporarily invalidating two ASIDs
   for a single instance. When it renumbers ASIDs this can now be done via
   the invs array.

 * SVA with multiple devices being used by a single process (NVIDIA today
   has 4-8) sequentially iterates the invalidations through all instances.
   This ignores the HW concurrency available in each instance. It would be
   nice to not spin on each sync but go forward and issue batches to other
   instances also. Reducing to a single SVA domain shared across instances
   is required to look at this.

This is on Github:
https://github.com/nicolinc/iommufd/commits/arm_smmu_invs-v9

Changelog
v9:
 * Set cur->ssid correctly in arm_smmu_master_build_inv()
 * Add comments for INV_TYPE_S1_ASID in arm_smmu_master_build_inv()
v8:
 https://lore.kernel.org/all/cover.1766013662.git.nicolinc at nvidia.com/
 * Update comments for smp_mb() in arm_smmu_install_new/old_domain_invs()
v7:
 https://lore.kernel.org/all/cover.1765850465.git.nicolinc at nvidia.com/
 * Rebase on v6.19-rc1
 * Fix has_ats in arm_smmu_invs_merge()
 * Fix a re-attach case with a different ats_enabled
 * Constify the inv parameter in arm_smmu_inv_is_ats()
 * Update kunit test data to be closer to real-world use cases
 * Clean up SVA domain's invs in arm_smmu_blocking_set_dev_pasid()
v6:
 https://lore.kernel.org/all/cover.1764119291.git.nicolinc at nvidia.com/
 * Fix typo in kdocs
 * Fix arm_smmu_domain_free() in SVA
 * Add arm_smmu_master_build_inv() helper
 * Add max_invs and __counted_by(max_invs)
 * Return NULL if arm_smmu_invs_alloc() fails
 * Sort master->streams instead of fwspec->ids
 * s/flush_fn/free_fn (prepare for future patches)
 * s/arm_smmu_invs_flush_iotlb_tags/arm_smmu_inv_flush_iotlb_tag
 * Define arm_smmu_invs macros and helpers to reduce duplications
 * Save num_trashes in "struct arm_smmu_invs" (to avoid a re-scan)
 * Move smp_mb() in install() to PATCH-6 that adds the pairing barrier
   and description
v5:
 https://lore.kernel.org/all/cover.1762588839.git.nicolinc at nvidia.com/
 * Add Reviewed/Acked-by from Jason and Balbir
 * Add two inline comments
 * Move cmp after the trash entry validation
 * Batch commands in arm_smmu_inv_size_too_big case
 * Replace kfree_rcu() with kfree() in arm_smmu_domain_free()
v4:
 https://lore.kernel.org/all/cover.1761590851.git.nicolinc at nvidia.com/
 * Fix build errors with CONFIG_KUNIT=n
 * Fix uninitialized cmp in arm_smmu_invs_unref()
 * Add missing "__rcu" in struct arm_smmu_inv_state
 * Add missing rcu_derference_protected() in arm_smmu_domain_free()
 * Bisect two paths for the conditional lock in arm_smmu_domain_inv_range()
   to fix a sparse waring
v3:
 https://lore.kernel.org/all/cover.1760555863.git.nicolinc at nvidia.com/
 * Add Reviewed/Acked-by from Jason and Balbir
 * Rebase on v6.18-rc1
 * Drop arm_smmu_invs_dbg()
 * Improve kdocs and inline/commit comments
 * Rename arm_smmu_invs_cmp to arm_smmu_inv_cmp
 * Rename arm_smmu_invs_merge_cmp to arm_smmu_invs_cmp
 * Call arm_smmu_invs_flush_iotlb_tags() from arm_smmu_invs_unref()
 * Unconditionally trim the invs->num_invs inside arm_smmu_invs_unref(),
   and simplify arm_smmu_install_old_domain_invs().
v2:
 https://lore.kernel.org/all/cover.1757373449.git.nicolinc at nvidia.com/
 * Rebase on v6.17-rc5
 * Improve kdocs and inline comments
 * Add arm_smmu_invs_dbg() for tracing
 * Use users refcount to replace todel flag
 * Initialize num_invs in arm_smmu_invs_alloc()
 * Add a struct arm_smmu_inv_state to group invs pointers
 * Add in struct arm_smmu_invs two flags (has_ats and old)
 * Rename master->invs to master->build_invs, and sort the array
 * Rework arm_smmu_domain_inv_range() and arm_smmu_invs_end_batch()
 * Copy entries by struct arm_smmu_inv in arm_smmu_master_build_invs()
 * Add arm_smmu_invs_flush_iotlb_tags() for IOTLB flush by last device
 * Rework three invs mutation helpers, and prioritize use the in-place
   mutation for detach
 * Take writer's lock unconditionally but keep it short, and only take
   reader's lock conditionally on a has_ats flag
v1:
 https://lore.kernel.org/all/cover.1755131672.git.nicolinc at nvidia.com/

Thanks
Nicolin

Jason Gunthorpe (1):
  iommu/arm-smmu-v3: Introduce a per-domain arm_smmu_invs array

Nicolin Chen (6):
  iommu/arm-smmu-v3: Explicitly set smmu_domain->stage for SVA
  iommu/arm-smmu-v3: Add an inline arm_smmu_domain_free()
  iommu/arm-smmu-v3: Pre-allocate a per-master invalidation array
  iommu/arm-smmu-v3: Populate smmu_domain->invs when attaching masters
  iommu/arm-smmu-v3: Add arm_smmu_invs based arm_smmu_domain_inv_range()
  iommu/arm-smmu-v3: Perform per-domain invalidations using
    arm_smmu_invs

 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   | 143 ++-
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c   |  35 +-
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  |  92 ++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 925 +++++++++++++++---
 4 files changed, 1015 insertions(+), 180 deletions(-)

-- 
2.43.0



From nicolinc at nvidia.com  Fri Dec 19 12:11:29 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Fri, 19 Dec 2025 12:11:29 -0800
Subject: [PATCH v9 7/7] iommu/arm-smmu-v3: Perform per-domain invalidations using arm_smmu_invs
In-Reply-To: <cover.1766174731.git.nicolinc@nvidia.com>
References: <cover.1766174731.git.nicolinc@nvidia.com>
Message-ID: <308ed579c724879a4a20b19ccdcb33e917597d77.1766174731.git.nicolinc@nvidia.com>

Replace the old invalidation functions with arm_smmu_domain_inv_range() in
all the existing invalidation routines. And deprecate the old functions.

The new arm_smmu_domain_inv_range() handles the CMDQ_MAX_TLBI_OPS as well,
so drop it in the SVA function.

Since arm_smmu_cmdq_batch_add_range() has only one caller now, and it must
be given a valid size, add a WARN_ON_ONCE to catch any missed case.

Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |   7 -
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c   |  29 +--
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 165 +-----------------
 3 files changed, 11 insertions(+), 190 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index c3fee7f14480..4f104c1baa67 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -1079,13 +1079,6 @@ int arm_smmu_set_pasid(struct arm_smmu_master *master,
 		       struct arm_smmu_domain *smmu_domain, ioasid_t pasid,
 		       struct arm_smmu_cd *cd, struct iommu_domain *old);
 
-void arm_smmu_tlb_inv_asid(struct arm_smmu_device *smmu, u16 asid);
-void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,
-				 size_t granule, bool leaf,
-				 struct arm_smmu_domain *smmu_domain);
-int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain,
-			    unsigned long iova, size_t size);
-
 void arm_smmu_domain_inv_range(struct arm_smmu_domain *smmu_domain,
 			       unsigned long iova, size_t size,
 			       unsigned int granule, bool leaf);
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index 440ad8cc07de..f1f8e01a7e91 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -122,15 +122,6 @@ void arm_smmu_make_sva_cd(struct arm_smmu_cd *target,
 }
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_make_sva_cd);
 
-/*
- * Cloned from the MAX_TLBI_OPS in arch/arm64/include/asm/tlbflush.h, this
- * is used as a threshold to replace per-page TLBI commands to issue in the
- * command queue with an address-space TLBI command, when SMMU w/o a range
- * invalidation feature handles too many per-page TLBI commands, which will
- * otherwise result in a soft lockup.
- */
-#define CMDQ_MAX_TLBI_OPS		(1 << (PAGE_SHIFT - 3))
-
 static void arm_smmu_mm_arch_invalidate_secondary_tlbs(struct mmu_notifier *mn,
 						struct mm_struct *mm,
 						unsigned long start,
@@ -146,21 +137,8 @@ static void arm_smmu_mm_arch_invalidate_secondary_tlbs(struct mmu_notifier *mn,
 	 * range. So do a simple translation here by calculating size correctly.
 	 */
 	size = end - start;
-	if (!(smmu_domain->smmu->features & ARM_SMMU_FEAT_RANGE_INV)) {
-		if (size >= CMDQ_MAX_TLBI_OPS * PAGE_SIZE)
-			size = 0;
-	} else {
-		if (size == ULONG_MAX)
-			size = 0;
-	}
-
-	if (!size)
-		arm_smmu_tlb_inv_asid(smmu_domain->smmu, smmu_domain->cd.asid);
-	else
-		arm_smmu_tlb_inv_range_asid(start, size, smmu_domain->cd.asid,
-					    PAGE_SIZE, false, smmu_domain);
 
-	arm_smmu_atc_inv_domain(smmu_domain, start, size);
+	arm_smmu_domain_inv_range(smmu_domain, start, size, PAGE_SIZE, false);
 }
 
 static void arm_smmu_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
@@ -191,8 +169,7 @@ static void arm_smmu_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
 	}
 	spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
 
-	arm_smmu_tlb_inv_asid(smmu_domain->smmu, smmu_domain->cd.asid);
-	arm_smmu_atc_inv_domain(smmu_domain, 0, 0);
+	arm_smmu_domain_inv(smmu_domain);
 }
 
 static void arm_smmu_mmu_notifier_free(struct mmu_notifier *mn)
@@ -302,7 +279,7 @@ static void arm_smmu_sva_domain_free(struct iommu_domain *domain)
 	/*
 	 * Ensure the ASID is empty in the iommu cache before allowing reuse.
 	 */
-	arm_smmu_tlb_inv_asid(smmu_domain->smmu, smmu_domain->cd.asid);
+	arm_smmu_domain_inv(smmu_domain);
 
 	/*
 	 * Notice that the arm_smmu_mm_arch_invalidate_secondary_tlbs op can
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 6e1082e6d164..9912262a0e3b 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1266,16 +1266,6 @@ struct arm_smmu_invs *arm_smmu_invs_purge(struct arm_smmu_invs *invs)
 EXPORT_SYMBOL_IF_KUNIT(arm_smmu_invs_purge);
 
 /* Context descriptor manipulation functions */
-void arm_smmu_tlb_inv_asid(struct arm_smmu_device *smmu, u16 asid)
-{
-	struct arm_smmu_cmdq_ent cmd = {
-		.opcode	= smmu->features & ARM_SMMU_FEAT_E2H ?
-			CMDQ_OP_TLBI_EL2_ASID : CMDQ_OP_TLBI_NH_ASID,
-		.tlbi.asid = asid,
-	};
-
-	arm_smmu_cmdq_issue_cmd_with_sync(smmu, &cmd);
-}
 
 /*
  * Based on the value of ent report which bits of the STE the HW will access. It
@@ -2430,74 +2420,10 @@ static int arm_smmu_atc_inv_master(struct arm_smmu_master *master,
 	return arm_smmu_cmdq_batch_submit(master->smmu, &cmds);
 }
 
-int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain,
-			    unsigned long iova, size_t size)
-{
-	struct arm_smmu_master_domain *master_domain;
-	int i;
-	unsigned long flags;
-	struct arm_smmu_cmdq_ent cmd = {
-		.opcode = CMDQ_OP_ATC_INV,
-	};
-	struct arm_smmu_cmdq_batch cmds;
-
-	if (!(smmu_domain->smmu->features & ARM_SMMU_FEAT_ATS))
-		return 0;
-
-	/*
-	 * Ensure that we've completed prior invalidation of the main TLBs
-	 * before we read 'nr_ats_masters' in case of a concurrent call to
-	 * arm_smmu_enable_ats():
-	 *
-	 *	// unmap()			// arm_smmu_enable_ats()
-	 *	TLBI+SYNC			atomic_inc(&nr_ats_masters);
-	 *	smp_mb();			[...]
-	 *	atomic_read(&nr_ats_masters);	pci_enable_ats() // writel()
-	 *
-	 * Ensures that we always see the incremented 'nr_ats_masters' count if
-	 * ATS was enabled at the PCI device before completion of the TLBI.
-	 */
-	smp_mb();
-	if (!atomic_read(&smmu_domain->nr_ats_masters))
-		return 0;
-
-	arm_smmu_cmdq_batch_init(smmu_domain->smmu, &cmds, &cmd);
-
-	spin_lock_irqsave(&smmu_domain->devices_lock, flags);
-	list_for_each_entry(master_domain, &smmu_domain->devices,
-			    devices_elm) {
-		struct arm_smmu_master *master = master_domain->master;
-
-		if (!master->ats_enabled)
-			continue;
-
-		if (master_domain->nested_ats_flush) {
-			/*
-			 * If a S2 used as a nesting parent is changed we have
-			 * no option but to completely flush the ATC.
-			 */
-			arm_smmu_atc_inv_to_cmd(IOMMU_NO_PASID, 0, 0, &cmd);
-		} else {
-			arm_smmu_atc_inv_to_cmd(master_domain->ssid, iova, size,
-						&cmd);
-		}
-
-		for (i = 0; i < master->num_streams; i++) {
-			cmd.atc.sid = master->streams[i].id;
-			arm_smmu_cmdq_batch_add(smmu_domain->smmu, &cmds, &cmd);
-		}
-	}
-	spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
-
-	return arm_smmu_cmdq_batch_submit(smmu_domain->smmu, &cmds);
-}
-
 /* IO_PGTABLE API */
 static void arm_smmu_tlb_inv_context(void *cookie)
 {
 	struct arm_smmu_domain *smmu_domain = cookie;
-	struct arm_smmu_device *smmu = smmu_domain->smmu;
-	struct arm_smmu_cmdq_ent cmd;
 
 	/*
 	 * NOTE: when io-pgtable is in non-strict mode, we may get here with
@@ -2506,14 +2432,7 @@ static void arm_smmu_tlb_inv_context(void *cookie)
 	 * insertion to guarantee those are observed before the TLBI. Do be
 	 * careful, 007.
 	 */
-	if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
-		arm_smmu_tlb_inv_asid(smmu, smmu_domain->cd.asid);
-	} else {
-		cmd.opcode	= CMDQ_OP_TLBI_S12_VMALL;
-		cmd.tlbi.vmid	= smmu_domain->s2_cfg.vmid;
-		arm_smmu_cmdq_issue_cmd_with_sync(smmu, &cmd);
-	}
-	arm_smmu_atc_inv_domain(smmu_domain, 0, 0);
+	arm_smmu_domain_inv(smmu_domain);
 }
 
 static void arm_smmu_cmdq_batch_add_range(struct arm_smmu_device *smmu,
@@ -2525,7 +2444,7 @@ static void arm_smmu_cmdq_batch_add_range(struct arm_smmu_device *smmu,
 	unsigned long end = iova + size, num_pages = 0, tg = pgsize;
 	size_t inv_range = granule;
 
-	if (!size)
+	if (WARN_ON_ONCE(!size))
 		return;
 
 	if (smmu->features & ARM_SMMU_FEAT_RANGE_INV) {
@@ -2580,76 +2499,6 @@ static void arm_smmu_cmdq_batch_add_range(struct arm_smmu_device *smmu,
 	}
 }
 
-static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd,
-				     unsigned long iova, size_t size,
-				     size_t granule,
-				     struct arm_smmu_domain *smmu_domain)
-{
-	struct arm_smmu_device *smmu = smmu_domain->smmu;
-	struct arm_smmu_cmdq_batch cmds;
-	size_t pgsize;
-
-	/* Get the leaf page size */
-	pgsize = __ffs(smmu_domain->domain.pgsize_bitmap);
-
-	arm_smmu_cmdq_batch_init(smmu, &cmds, cmd);
-	arm_smmu_cmdq_batch_add_range(smmu, &cmds, cmd, iova, size, granule,
-				      pgsize);
-	arm_smmu_cmdq_batch_submit(smmu, &cmds);
-}
-
-static void arm_smmu_tlb_inv_range_domain(unsigned long iova, size_t size,
-					  size_t granule, bool leaf,
-					  struct arm_smmu_domain *smmu_domain)
-{
-	struct arm_smmu_cmdq_ent cmd = {
-		.tlbi = {
-			.leaf	= leaf,
-		},
-	};
-
-	if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
-		cmd.opcode	= smmu_domain->smmu->features & ARM_SMMU_FEAT_E2H ?
-				  CMDQ_OP_TLBI_EL2_VA : CMDQ_OP_TLBI_NH_VA;
-		cmd.tlbi.asid	= smmu_domain->cd.asid;
-	} else {
-		cmd.opcode	= CMDQ_OP_TLBI_S2_IPA;
-		cmd.tlbi.vmid	= smmu_domain->s2_cfg.vmid;
-	}
-	__arm_smmu_tlb_inv_range(&cmd, iova, size, granule, smmu_domain);
-
-	if (smmu_domain->nest_parent) {
-		/*
-		 * When the S2 domain changes all the nested S1 ASIDs have to be
-		 * flushed too.
-		 */
-		cmd.opcode = CMDQ_OP_TLBI_NH_ALL;
-		arm_smmu_cmdq_issue_cmd_with_sync(smmu_domain->smmu, &cmd);
-	}
-
-	/*
-	 * Unfortunately, this can't be leaf-only since we may have
-	 * zapped an entire table.
-	 */
-	arm_smmu_atc_inv_domain(smmu_domain, iova, size);
-}
-
-void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,
-				 size_t granule, bool leaf,
-				 struct arm_smmu_domain *smmu_domain)
-{
-	struct arm_smmu_cmdq_ent cmd = {
-		.opcode	= smmu_domain->smmu->features & ARM_SMMU_FEAT_E2H ?
-			  CMDQ_OP_TLBI_EL2_VA : CMDQ_OP_TLBI_NH_VA,
-		.tlbi = {
-			.asid	= asid,
-			.leaf	= leaf,
-		},
-	};
-
-	__arm_smmu_tlb_inv_range(&cmd, iova, size, granule, smmu_domain);
-}
-
 static bool arm_smmu_inv_size_too_big(struct arm_smmu_device *smmu, size_t size,
 				      size_t granule)
 {
@@ -2850,7 +2699,9 @@ static void arm_smmu_tlb_inv_page_nosync(struct iommu_iotlb_gather *gather,
 static void arm_smmu_tlb_inv_walk(unsigned long iova, size_t size,
 				  size_t granule, void *cookie)
 {
-	arm_smmu_tlb_inv_range_domain(iova, size, granule, false, cookie);
+	struct arm_smmu_domain *smmu_domain = cookie;
+
+	arm_smmu_domain_inv_range(smmu_domain, iova, size, granule, false);
 }
 
 static const struct iommu_flush_ops arm_smmu_flush_ops = {
@@ -4150,9 +4001,9 @@ static void arm_smmu_iotlb_sync(struct iommu_domain *domain,
 	if (!gather->pgsize)
 		return;
 
-	arm_smmu_tlb_inv_range_domain(gather->start,
-				      gather->end - gather->start + 1,
-				      gather->pgsize, true, smmu_domain);
+	arm_smmu_domain_inv_range(smmu_domain, gather->start,
+				  gather->end - gather->start + 1,
+				  gather->pgsize, true);
 }
 
 static phys_addr_t
-- 
2.43.0



From nicolinc at nvidia.com  Fri Dec 19 12:11:27 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Fri, 19 Dec 2025 12:11:27 -0800
Subject: [PATCH v9 5/7] iommu/arm-smmu-v3: Populate smmu_domain->invs when attaching masters
In-Reply-To: <cover.1766174731.git.nicolinc@nvidia.com>
References: <cover.1766174731.git.nicolinc@nvidia.com>
Message-ID: <2232710c544e9319d8e47b474c1fd1f04b0628b6.1766174731.git.nicolinc@nvidia.com>

Update the invs array with the invalidations required by each domain type
during attachment operations.

Only an SVA domain or a paging domain will have an invs array:
 a. SVA domain will add an INV_TYPE_S1_ASID per SMMU and an INV_TYPE_ATS
    per SID

 b. Non-nesting-parent paging domain with no ATS-enabled master will add
    a single INV_TYPE_S1_ASID or INV_TYPE_S2_VMID per SMMU

 c. Non-nesting-parent paging domain with ATS-enabled master(s) will do
    (b) and add an INV_TYPE_ATS per SID

 d. Nesting-parent paging domain will add an INV_TYPE_S2_VMID followed by
    an INV_TYPE_S2_VMID_S1_CLEAR per vSMMU. For an ATS-enabled master, it
    will add an INV_TYPE_ATS_FULL per SID

 Note that case #d prepares for a future implementation of VMID allocation
 which requires a followup series for S2 domain sharing. So when a nesting
 parent domain is attached through a vSMMU instance using a nested domain.
 VMID will be allocated per vSMMU instance v.s. currectly per S2 domain.

The per-domain invalidation is not needed until the domain is attached to
a master (when it starts to possibly use TLB). This will make it possible
to attach the domain to multiple SMMUs and avoid unnecessary invalidation
overhead during teardown if no STEs/CDs refer to the domain. It also means
that when the last device is detached, the old domain must flush its ASID
or VMID, since any new iommu_unmap() call would not trigger invalidations
given an empty domain->invs array.

Introduce some arm_smmu_invs helper functions for building scratch arrays,
preparing and installing old/new domain's invalidation arrays.

Co-developed-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h |  17 ++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 258 +++++++++++++++++++-
 2 files changed, 274 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index f98774962012..f8dc96476c43 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -1101,6 +1101,21 @@ static inline bool arm_smmu_master_canwbs(struct arm_smmu_master *master)
 	       IOMMU_FWSPEC_PCI_RC_CANWBS;
 }
 
+/**
+ * struct arm_smmu_inv_state - Per-domain invalidation array state
+ * @invs_ptr: points to the domain->invs (unwinding nesting/etc.) or is NULL if
+ *            no change should be made
+ * @old_invs: the original invs array
+ * @new_invs: for new domain, this is the new invs array to update domain->invs;
+ *            for old domain, this is the master->build_invs to pass in as the
+ *            to_unref argument to an arm_smmu_invs_unref() call
+ */
+struct arm_smmu_inv_state {
+	struct arm_smmu_invs __rcu **invs_ptr;
+	struct arm_smmu_invs *old_invs;
+	struct arm_smmu_invs *new_invs;
+};
+
 struct arm_smmu_attach_state {
 	/* Inputs */
 	struct iommu_domain *old_domain;
@@ -1110,6 +1125,8 @@ struct arm_smmu_attach_state {
 	ioasid_t ssid;
 	/* Resulting state */
 	struct arm_smmu_vmaster *vmaster;
+	struct arm_smmu_inv_state old_domain_invst;
+	struct arm_smmu_inv_state new_domain_invst;
 	bool ats_enabled;
 };
 
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index cc85e7a10ea8..fb45359680d2 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -3068,6 +3068,121 @@ static void arm_smmu_disable_iopf(struct arm_smmu_master *master,
 		iopf_queue_remove_device(master->smmu->evtq.iopf, master->dev);
 }
 
+static struct arm_smmu_inv *
+arm_smmu_master_build_inv(struct arm_smmu_master *master,
+			  enum arm_smmu_inv_type type, u32 id, ioasid_t ssid,
+			  size_t pgsize)
+{
+	struct arm_smmu_invs *build_invs = master->build_invs;
+	struct arm_smmu_inv *cur, inv = {
+		.smmu = master->smmu,
+		.type = type,
+		.id = id,
+		.pgsize = pgsize,
+	};
+
+	if (WARN_ON(build_invs->num_invs >= build_invs->max_invs))
+		return NULL;
+	cur = &build_invs->inv[build_invs->num_invs];
+	build_invs->num_invs++;
+
+	*cur = inv;
+	switch (type) {
+	case INV_TYPE_S1_ASID:
+		/*
+		 * For S1 page tables the driver always uses VMID=0, and the
+		 * invalidation logic for this type will set it as well.
+		 */
+		if (master->smmu->features & ARM_SMMU_FEAT_E2H) {
+			cur->size_opcode = CMDQ_OP_TLBI_EL2_VA;
+			cur->nsize_opcode = CMDQ_OP_TLBI_EL2_ASID;
+		} else {
+			cur->size_opcode = CMDQ_OP_TLBI_NH_VA;
+			cur->nsize_opcode = CMDQ_OP_TLBI_NH_ASID;
+		}
+		break;
+	case INV_TYPE_S2_VMID:
+		cur->size_opcode = CMDQ_OP_TLBI_S2_IPA;
+		cur->nsize_opcode = CMDQ_OP_TLBI_S12_VMALL;
+		break;
+	case INV_TYPE_S2_VMID_S1_CLEAR:
+		cur->size_opcode = cur->nsize_opcode = CMDQ_OP_TLBI_NH_ALL;
+		break;
+	case INV_TYPE_ATS:
+	case INV_TYPE_ATS_FULL:
+		cur->size_opcode = cur->nsize_opcode = CMDQ_OP_ATC_INV;
+		cur->ssid = ssid;
+		break;
+	}
+
+	return cur;
+}
+
+/*
+ * Use the preallocated scratch array at master->build_invs, to build a to_merge
+ * or to_unref array, to pass into a following arm_smmu_invs_merge/unref() call.
+ *
+ * Do not free the returned invs array. It is reused, and will be overwritten by
+ * the next arm_smmu_master_build_invs() call.
+ */
+static struct arm_smmu_invs *
+arm_smmu_master_build_invs(struct arm_smmu_master *master, bool ats_enabled,
+			   ioasid_t ssid, struct arm_smmu_domain *smmu_domain)
+{
+	const bool nesting = smmu_domain->nest_parent;
+	size_t pgsize = 0, i;
+
+	iommu_group_mutex_assert(master->dev);
+
+	master->build_invs->num_invs = 0;
+
+	/* Range-based invalidation requires the leaf pgsize for calculation */
+	if (master->smmu->features & ARM_SMMU_FEAT_RANGE_INV)
+		pgsize = __ffs(smmu_domain->domain.pgsize_bitmap);
+
+	switch (smmu_domain->stage) {
+	case ARM_SMMU_DOMAIN_SVA:
+	case ARM_SMMU_DOMAIN_S1:
+		if (!arm_smmu_master_build_inv(master, INV_TYPE_S1_ASID,
+					       smmu_domain->cd.asid,
+					       IOMMU_NO_PASID, pgsize))
+			return NULL;
+		break;
+	case ARM_SMMU_DOMAIN_S2:
+		if (!arm_smmu_master_build_inv(master, INV_TYPE_S2_VMID,
+					       smmu_domain->s2_cfg.vmid,
+					       IOMMU_NO_PASID, pgsize))
+			return NULL;
+		break;
+	default:
+		WARN_ON(true);
+		return NULL;
+	}
+
+	/* All the nested S1 ASIDs have to be flushed when S2 parent changes */
+	if (nesting) {
+		if (!arm_smmu_master_build_inv(
+			    master, INV_TYPE_S2_VMID_S1_CLEAR,
+			    smmu_domain->s2_cfg.vmid, IOMMU_NO_PASID, 0))
+			return NULL;
+	}
+
+	for (i = 0; ats_enabled && i < master->num_streams; i++) {
+		/*
+		 * If an S2 used as a nesting parent is changed we have no
+		 * option but to completely flush the ATC.
+		 */
+		if (!arm_smmu_master_build_inv(
+			    master, nesting ? INV_TYPE_ATS_FULL : INV_TYPE_ATS,
+			    master->streams[i].id, ssid, 0))
+			return NULL;
+	}
+
+	/* Note this build_invs must have been sorted */
+
+	return master->build_invs;
+}
+
 static void arm_smmu_remove_master_domain(struct arm_smmu_master *master,
 					  struct iommu_domain *domain,
 					  ioasid_t ssid)
@@ -3097,6 +3212,131 @@ static void arm_smmu_remove_master_domain(struct arm_smmu_master *master,
 	kfree(master_domain);
 }
 
+/*
+ * During attachment, the updates of the two domain->invs arrays are sequenced:
+ *  1. new domain updates its invs array, merging master->build_invs
+ *  2. new domain starts to include the master during its invalidation
+ *  3. master updates its STE switching from the old domain to the new domain
+ *  4. old domain still includes the master during its invalidation
+ *  5. old domain updates its invs array, unreferencing master->build_invs
+ *
+ * For 1 and 5, prepare the two updated arrays in advance, handling any changes
+ * that can possibly failure. So the actual update of either 1 or 5 won't fail.
+ * arm_smmu_asid_lock ensures that the old invs in the domains are intact while
+ * we are sequencing to update them.
+ */
+static int arm_smmu_attach_prepare_invs(struct arm_smmu_attach_state *state,
+					struct arm_smmu_domain *new_smmu_domain)
+{
+	struct arm_smmu_domain *old_smmu_domain =
+		to_smmu_domain_devices(state->old_domain);
+	struct arm_smmu_master *master = state->master;
+	ioasid_t ssid = state->ssid;
+
+	/*
+	 * At this point a NULL domain indicates the domain doesn't use the
+	 * IOTLB, see to_smmu_domain_devices().
+	 */
+	if (new_smmu_domain) {
+		struct arm_smmu_inv_state *invst = &state->new_domain_invst;
+		struct arm_smmu_invs *build_invs;
+
+		invst->invs_ptr = &new_smmu_domain->invs;
+		invst->old_invs = rcu_dereference_protected(
+			new_smmu_domain->invs,
+			lockdep_is_held(&arm_smmu_asid_lock));
+		build_invs = arm_smmu_master_build_invs(
+			master, state->ats_enabled, ssid, new_smmu_domain);
+		if (!build_invs)
+			return -EINVAL;
+
+		invst->new_invs =
+			arm_smmu_invs_merge(invst->old_invs, build_invs);
+		if (IS_ERR(invst->new_invs))
+			return PTR_ERR(invst->new_invs);
+	}
+
+	if (old_smmu_domain) {
+		struct arm_smmu_inv_state *invst = &state->old_domain_invst;
+
+		invst->invs_ptr = &old_smmu_domain->invs;
+		/* A re-attach case might have a different ats_enabled state */
+		if (new_smmu_domain == old_smmu_domain)
+			invst->old_invs = state->new_domain_invst.new_invs;
+		else
+			invst->old_invs = rcu_dereference_protected(
+				old_smmu_domain->invs,
+				lockdep_is_held(&arm_smmu_asid_lock));
+		/* For old_smmu_domain, new_invs points to master->build_invs */
+		invst->new_invs = arm_smmu_master_build_invs(
+			master, master->ats_enabled, ssid, old_smmu_domain);
+	}
+
+	return 0;
+}
+
+/* Must be installed before arm_smmu_install_ste_for_dev() */
+static void
+arm_smmu_install_new_domain_invs(struct arm_smmu_attach_state *state)
+{
+	struct arm_smmu_inv_state *invst = &state->new_domain_invst;
+
+	if (!invst->invs_ptr)
+		return;
+
+	rcu_assign_pointer(*invst->invs_ptr, invst->new_invs);
+	kfree_rcu(invst->old_invs, rcu);
+}
+
+/*
+ * When an array entry's users count reaches zero, it means the ASID/VMID is no
+ * longer being invalidated by map/unmap and must be cleaned. The rule is that
+ * all ASIDs/VMIDs not in an invalidation array are left cleared in the IOTLB.
+ */
+static void arm_smmu_inv_flush_iotlb_tag(struct arm_smmu_inv *inv)
+{
+	struct arm_smmu_cmdq_ent cmd = {};
+
+	switch (inv->type) {
+	case INV_TYPE_S1_ASID:
+		cmd.tlbi.asid = inv->id;
+		break;
+	case INV_TYPE_S2_VMID:
+		/* S2_VMID using nsize_opcode covers S2_VMID_S1_CLEAR */
+		cmd.tlbi.vmid = inv->id;
+		break;
+	default:
+		return;
+	}
+
+	cmd.opcode = inv->nsize_opcode;
+	arm_smmu_cmdq_issue_cmd_with_sync(inv->smmu, &cmd);
+}
+
+/* Should be installed after arm_smmu_install_ste_for_dev() */
+static void
+arm_smmu_install_old_domain_invs(struct arm_smmu_attach_state *state)
+{
+	struct arm_smmu_inv_state *invst = &state->old_domain_invst;
+	struct arm_smmu_invs *old_invs = invst->old_invs;
+	struct arm_smmu_invs *new_invs;
+
+	lockdep_assert_held(&arm_smmu_asid_lock);
+
+	if (!invst->invs_ptr)
+		return;
+
+	arm_smmu_invs_unref(old_invs, invst->new_invs,
+			    arm_smmu_inv_flush_iotlb_tag);
+
+	new_invs = arm_smmu_invs_purge(old_invs);
+	if (!new_invs)
+		return;
+
+	rcu_assign_pointer(*invst->invs_ptr, new_invs);
+	kfree_rcu(old_invs, rcu);
+}
+
 /*
  * Start the sequence to attach a domain to a master. The sequence contains three
  * steps:
@@ -3154,12 +3394,16 @@ int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state,
 				     arm_smmu_ats_supported(master);
 	}
 
+	ret = arm_smmu_attach_prepare_invs(state, smmu_domain);
+	if (ret)
+		return ret;
+
 	if (smmu_domain) {
 		if (new_domain->type == IOMMU_DOMAIN_NESTED) {
 			ret = arm_smmu_attach_prepare_vmaster(
 				state, to_smmu_nested_domain(new_domain));
 			if (ret)
-				return ret;
+				goto err_unprepare_invs;
 		}
 
 		master_domain = kzalloc(sizeof(*master_domain), GFP_KERNEL);
@@ -3207,6 +3451,8 @@ int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state,
 			atomic_inc(&smmu_domain->nr_ats_masters);
 		list_add(&master_domain->devices_elm, &smmu_domain->devices);
 		spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
+
+		arm_smmu_install_new_domain_invs(state);
 	}
 
 	if (!state->ats_enabled && master->ats_enabled) {
@@ -3226,6 +3472,8 @@ int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state,
 	kfree(master_domain);
 err_free_vmaster:
 	kfree(state->vmaster);
+err_unprepare_invs:
+	kfree(state->new_domain_invst.new_invs);
 	return ret;
 }
 
@@ -3257,6 +3505,7 @@ void arm_smmu_attach_commit(struct arm_smmu_attach_state *state)
 	}
 
 	arm_smmu_remove_master_domain(master, state->old_domain, state->ssid);
+	arm_smmu_install_old_domain_invs(state);
 	master->ats_enabled = state->ats_enabled;
 }
 
@@ -3438,12 +3687,19 @@ static int arm_smmu_blocking_set_dev_pasid(struct iommu_domain *new_domain,
 {
 	struct arm_smmu_domain *smmu_domain = to_smmu_domain(old_domain);
 	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
+	struct arm_smmu_attach_state state = {
+		.master = master,
+		.old_domain = old_domain,
+		.ssid = pasid,
+	};
 
 	mutex_lock(&arm_smmu_asid_lock);
+	arm_smmu_attach_prepare_invs(&state, NULL);
 	arm_smmu_clear_cd(master, pasid);
 	if (master->ats_enabled)
 		arm_smmu_atc_inv_master(master, pasid);
 	arm_smmu_remove_master_domain(master, &smmu_domain->domain, pasid);
+	arm_smmu_install_old_domain_invs(&state);
 	mutex_unlock(&arm_smmu_asid_lock);
 
 	/*
-- 
2.43.0



From nicolinc at nvidia.com  Fri Dec 19 12:11:26 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Fri, 19 Dec 2025 12:11:26 -0800
Subject: [PATCH v9 4/7] iommu/arm-smmu-v3: Pre-allocate a per-master invalidation array
In-Reply-To: <cover.1766174731.git.nicolinc@nvidia.com>
References: <cover.1766174731.git.nicolinc@nvidia.com>
Message-ID: <d6565a84698d93d6a2842b32bed492f87179af5e.1766174731.git.nicolinc@nvidia.com>

When a master is attached from an old domain to a new domain, it needs to
build an invalidation array to delete and add the array entries from/onto
the invalidation arrays of those two domains, passed via the to_merge and
to_unref arguments into arm_smmu_invs_merge/unref() respectively.

Since the master->num_streams might differ across masters, a memory would
have to be allocated when building an to_merge/to_unref array which might
fail with -ENOMEM.

On the other hand, an attachment to arm_smmu_blocked_domain must not fail
so it's the best to avoid any memory allocation in that path.

Pre-allocate a fixed size invalidation array for every master. This array
will be used as a scratch to fill dynamically when building a to_merge or
to_unref invs array. Sort fwspec->ids in an ascending order to fit to the
arm_smmu_invs_merge() function.

Co-developed-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h |  8 ++++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 41 +++++++++++++++++++--
 2 files changed, 45 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index a9441dc9070e..f98774962012 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -930,6 +930,14 @@ struct arm_smmu_master {
 	struct arm_smmu_device		*smmu;
 	struct device			*dev;
 	struct arm_smmu_stream		*streams;
+	/*
+	 * Scratch memory for a to_merge or to_unref array to build a per-domain
+	 * invalidation array. It'll be pre-allocated with enough enries for all
+	 * possible build scenarios. It can be used by only one caller at a time
+	 * until the arm_smmu_invs_merge/unref() finishes. Must be locked by the
+	 * iommu_group mutex.
+	 */
+	struct arm_smmu_invs		*build_invs;
 	struct arm_smmu_vmaster		*vmaster; /* use smmu->streams_mutex */
 	/* Locked by the iommu core using the group mutex */
 	struct arm_smmu_ctx_desc_cfg	cd_table;
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 39e89176fa87..cc85e7a10ea8 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -3709,12 +3709,22 @@ static int arm_smmu_init_sid_strtab(struct arm_smmu_device *smmu, u32 sid)
 	return 0;
 }
 
+static int arm_smmu_stream_id_cmp(const void *_l, const void *_r)
+{
+	const typeof_member(struct arm_smmu_stream, id) *l = _l;
+	const typeof_member(struct arm_smmu_stream, id) *r = _r;
+
+	return cmp_int(*l, *r);
+}
+
 static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
 				  struct arm_smmu_master *master)
 {
 	int i;
 	int ret = 0;
 	struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(master->dev);
+	bool ats_supported = dev_is_pci(master->dev) &&
+			     pci_ats_supported(to_pci_dev(master->dev));
 
 	master->streams = kcalloc(fwspec->num_ids, sizeof(*master->streams),
 				  GFP_KERNEL);
@@ -3722,14 +3732,35 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
 		return -ENOMEM;
 	master->num_streams = fwspec->num_ids;
 
-	mutex_lock(&smmu->streams_mutex);
+	if (!ats_supported) {
+		/* Base case has 1 ASID entry or maximum 2 VMID entries */
+		master->build_invs = arm_smmu_invs_alloc(2);
+	} else {
+		/* ATS case adds num_ids of entries, on top of the base case */
+		master->build_invs = arm_smmu_invs_alloc(2 + fwspec->num_ids);
+	}
+	if (!master->build_invs) {
+		kfree(master->streams);
+		return -ENOMEM;
+	}
+
 	for (i = 0; i < fwspec->num_ids; i++) {
 		struct arm_smmu_stream *new_stream = &master->streams[i];
-		struct rb_node *existing;
-		u32 sid = fwspec->ids[i];
 
-		new_stream->id = sid;
+		new_stream->id = fwspec->ids[i];
 		new_stream->master = master;
+	}
+
+	/* Put the ids into order for sorted to_merge/to_unref arrays */
+	sort_nonatomic(master->streams, master->num_streams,
+		       sizeof(master->streams[0]), arm_smmu_stream_id_cmp,
+		       NULL);
+
+	mutex_lock(&smmu->streams_mutex);
+	for (i = 0; i < fwspec->num_ids; i++) {
+		struct arm_smmu_stream *new_stream = &master->streams[i];
+		struct rb_node *existing;
+		u32 sid = new_stream->id;
 
 		ret = arm_smmu_init_sid_strtab(smmu, sid);
 		if (ret)
@@ -3759,6 +3790,7 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
 		for (i--; i >= 0; i--)
 			rb_erase(&master->streams[i].node, &smmu->streams);
 		kfree(master->streams);
+		kfree(master->build_invs);
 	}
 	mutex_unlock(&smmu->streams_mutex);
 
@@ -3780,6 +3812,7 @@ static void arm_smmu_remove_master(struct arm_smmu_master *master)
 	mutex_unlock(&smmu->streams_mutex);
 
 	kfree(master->streams);
+	kfree(master->build_invs);
 }
 
 static struct iommu_device *arm_smmu_probe_device(struct device *dev)
-- 
2.43.0



From nicolinc at nvidia.com  Fri Dec 19 12:11:28 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Fri, 19 Dec 2025 12:11:28 -0800
Subject: [PATCH v9 6/7] iommu/arm-smmu-v3: Add arm_smmu_invs based arm_smmu_domain_inv_range()
In-Reply-To: <cover.1766174731.git.nicolinc@nvidia.com>
References: <cover.1766174731.git.nicolinc@nvidia.com>
Message-ID: <06999367d001283744fd98eb7c1823afd516ce84.1766174731.git.nicolinc@nvidia.com>

Each smmu_domain now has an arm_smmu_invs that specifies the invalidation
steps to perform after any change the IOPTEs. This includes supports for
basic ASID/VMID, the special case for nesting, and ATC invalidations.

Introduce a new arm_smmu_domain_inv helper iterating smmu_domain->invs to
convert the invalidation array to commands. Any invalidation request with
no size specified means an entire flush over a range based one.

Take advantage of the sorted array to compatible batch operations together
to the same SMMU. For instance, ATC invaliations for multiple SIDs can be
pushed as a batch.

ATC invalidations must be completed before the driver disables ATS. Or the
device is permitted to ignore any racing invalidation that would cause an
SMMU timeout. The sequencing is done with a rwlock where holding the write
side of the rwlock means that there are no outstanding ATC invalidations.
If ATS is not used the rwlock is ignored, similar to the existing code.

Co-developed-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h |   9 +
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 258 +++++++++++++++++++-
 2 files changed, 254 insertions(+), 13 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index f8dc96476c43..c3fee7f14480 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -1086,6 +1086,15 @@ void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,
 int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain,
 			    unsigned long iova, size_t size);
 
+void arm_smmu_domain_inv_range(struct arm_smmu_domain *smmu_domain,
+			       unsigned long iova, size_t size,
+			       unsigned int granule, bool leaf);
+
+static inline void arm_smmu_domain_inv(struct arm_smmu_domain *smmu_domain)
+{
+	arm_smmu_domain_inv_range(smmu_domain, 0, 0, 0, false);
+}
+
 void __arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu,
 			      struct arm_smmu_cmdq *cmdq);
 int arm_smmu_init_one_queue(struct arm_smmu_device *smmu,
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index fb45359680d2..6e1082e6d164 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2516,23 +2516,19 @@ static void arm_smmu_tlb_inv_context(void *cookie)
 	arm_smmu_atc_inv_domain(smmu_domain, 0, 0);
 }
 
-static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd,
-				     unsigned long iova, size_t size,
-				     size_t granule,
-				     struct arm_smmu_domain *smmu_domain)
+static void arm_smmu_cmdq_batch_add_range(struct arm_smmu_device *smmu,
+					  struct arm_smmu_cmdq_batch *cmds,
+					  struct arm_smmu_cmdq_ent *cmd,
+					  unsigned long iova, size_t size,
+					  size_t granule, size_t pgsize)
 {
-	struct arm_smmu_device *smmu = smmu_domain->smmu;
-	unsigned long end = iova + size, num_pages = 0, tg = 0;
+	unsigned long end = iova + size, num_pages = 0, tg = pgsize;
 	size_t inv_range = granule;
-	struct arm_smmu_cmdq_batch cmds;
 
 	if (!size)
 		return;
 
 	if (smmu->features & ARM_SMMU_FEAT_RANGE_INV) {
-		/* Get the leaf page size */
-		tg = __ffs(smmu_domain->domain.pgsize_bitmap);
-
 		num_pages = size >> tg;
 
 		/* Convert page size of 12,14,16 (log2) to 1,2,3 */
@@ -2552,8 +2548,6 @@ static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd,
 			num_pages++;
 	}
 
-	arm_smmu_cmdq_batch_init(smmu, &cmds, cmd);
-
 	while (iova < end) {
 		if (smmu->features & ARM_SMMU_FEAT_RANGE_INV) {
 			/*
@@ -2581,9 +2575,26 @@ static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd,
 		}
 
 		cmd->tlbi.addr = iova;
-		arm_smmu_cmdq_batch_add(smmu, &cmds, cmd);
+		arm_smmu_cmdq_batch_add(smmu, cmds, cmd);
 		iova += inv_range;
 	}
+}
+
+static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd,
+				     unsigned long iova, size_t size,
+				     size_t granule,
+				     struct arm_smmu_domain *smmu_domain)
+{
+	struct arm_smmu_device *smmu = smmu_domain->smmu;
+	struct arm_smmu_cmdq_batch cmds;
+	size_t pgsize;
+
+	/* Get the leaf page size */
+	pgsize = __ffs(smmu_domain->domain.pgsize_bitmap);
+
+	arm_smmu_cmdq_batch_init(smmu, &cmds, cmd);
+	arm_smmu_cmdq_batch_add_range(smmu, &cmds, cmd, iova, size, granule,
+				      pgsize);
 	arm_smmu_cmdq_batch_submit(smmu, &cmds);
 }
 
@@ -2639,6 +2650,193 @@ void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,
 	__arm_smmu_tlb_inv_range(&cmd, iova, size, granule, smmu_domain);
 }
 
+static bool arm_smmu_inv_size_too_big(struct arm_smmu_device *smmu, size_t size,
+				      size_t granule)
+{
+	size_t max_tlbi_ops;
+
+	/* 0 size means invalidate all */
+	if (!size || size == SIZE_MAX)
+		return true;
+
+	if (smmu->features & ARM_SMMU_FEAT_RANGE_INV)
+		return false;
+
+	/*
+	 * Borrowed from the MAX_TLBI_OPS in arch/arm64/include/asm/tlbflush.h,
+	 * this is used as a threshold to replace "size_opcode" commands with a
+	 * single "nsize_opcode" command, when SMMU doesn't implement the range
+	 * invalidation feature, where there can be too many per-granule TLBIs,
+	 * resulting in a soft lockup.
+	 */
+	max_tlbi_ops = 1 << (ilog2(granule) - 3);
+	return size >= max_tlbi_ops * granule;
+}
+
+/* Used by non INV_TYPE_ATS* invalidations */
+static void arm_smmu_inv_to_cmdq_batch(struct arm_smmu_inv *inv,
+				       struct arm_smmu_cmdq_batch *cmds,
+				       struct arm_smmu_cmdq_ent *cmd,
+				       unsigned long iova, size_t size,
+				       unsigned int granule)
+{
+	if (arm_smmu_inv_size_too_big(inv->smmu, size, granule)) {
+		cmd->opcode = inv->nsize_opcode;
+		arm_smmu_cmdq_batch_add(inv->smmu, cmds, cmd);
+		return;
+	}
+
+	cmd->opcode = inv->size_opcode;
+	arm_smmu_cmdq_batch_add_range(inv->smmu, cmds, cmd, iova, size, granule,
+				      inv->pgsize);
+}
+
+static inline bool arm_smmu_invs_end_batch(struct arm_smmu_inv *cur,
+					   struct arm_smmu_inv *next)
+{
+	/* Changing smmu means changing command queue */
+	if (cur->smmu != next->smmu)
+		return true;
+	/* The batch for S2 TLBI must be done before nested S1 ASIDs */
+	if (cur->type != INV_TYPE_S2_VMID_S1_CLEAR &&
+	    next->type == INV_TYPE_S2_VMID_S1_CLEAR)
+		return true;
+	/* ATS must be after a sync of the S1/S2 invalidations */
+	if (!arm_smmu_inv_is_ats(cur) && arm_smmu_inv_is_ats(next))
+		return true;
+	return false;
+}
+
+static void __arm_smmu_domain_inv_range(struct arm_smmu_invs *invs,
+					unsigned long iova, size_t size,
+					unsigned int granule, bool leaf)
+{
+	struct arm_smmu_cmdq_batch cmds = {};
+	struct arm_smmu_inv *cur;
+	struct arm_smmu_inv *end;
+
+	cur = invs->inv;
+	end = cur + READ_ONCE(invs->num_invs);
+	/* Skip any leading entry marked as a trash */
+	for (; cur != end; cur++)
+		if (refcount_read(&cur->users))
+			break;
+	while (cur != end) {
+		struct arm_smmu_device *smmu = cur->smmu;
+		struct arm_smmu_cmdq_ent cmd = {
+			/*
+			 * Pick size_opcode to run arm_smmu_get_cmdq(). This can
+			 * be changed to nsize_opcode, which would result in the
+			 * same CMDQ pointer.
+			 */
+			.opcode = cur->size_opcode,
+		};
+		struct arm_smmu_inv *next;
+
+		if (!cmds.num)
+			arm_smmu_cmdq_batch_init(smmu, &cmds, &cmd);
+
+		switch (cur->type) {
+		case INV_TYPE_S1_ASID:
+			cmd.tlbi.asid = cur->id;
+			cmd.tlbi.leaf = leaf;
+			arm_smmu_inv_to_cmdq_batch(cur, &cmds, &cmd, iova, size,
+						   granule);
+			break;
+		case INV_TYPE_S2_VMID:
+			cmd.tlbi.vmid = cur->id;
+			cmd.tlbi.leaf = leaf;
+			arm_smmu_inv_to_cmdq_batch(cur, &cmds, &cmd, iova, size,
+						   granule);
+			break;
+		case INV_TYPE_S2_VMID_S1_CLEAR:
+			/* CMDQ_OP_TLBI_S12_VMALL already flushed S1 entries */
+			if (arm_smmu_inv_size_too_big(cur->smmu, size, granule))
+				continue;
+			cmd.tlbi.vmid = cur->id;
+			arm_smmu_cmdq_batch_add(smmu, &cmds, &cmd);
+			break;
+		case INV_TYPE_ATS:
+			arm_smmu_atc_inv_to_cmd(cur->ssid, iova, size, &cmd);
+			cmd.atc.sid = cur->id;
+			arm_smmu_cmdq_batch_add(smmu, &cmds, &cmd);
+			break;
+		case INV_TYPE_ATS_FULL:
+			arm_smmu_atc_inv_to_cmd(IOMMU_NO_PASID, 0, 0, &cmd);
+			cmd.atc.sid = cur->id;
+			arm_smmu_cmdq_batch_add(smmu, &cmds, &cmd);
+			break;
+		default:
+			WARN_ON_ONCE(1);
+			continue;
+		}
+
+		/* Skip any trash entry in-between */
+		for (next = cur + 1; next != end; next++)
+			if (refcount_read(&next->users))
+				break;
+
+		if (cmds.num &&
+		    (next == end || arm_smmu_invs_end_batch(cur, next))) {
+			arm_smmu_cmdq_batch_submit(smmu, &cmds);
+			cmds.num = 0;
+		}
+		cur = next;
+	}
+}
+
+void arm_smmu_domain_inv_range(struct arm_smmu_domain *smmu_domain,
+			       unsigned long iova, size_t size,
+			       unsigned int granule, bool leaf)
+{
+	struct arm_smmu_invs *invs;
+
+	/*
+	 * An invalidation request must follow some IOPTE change and then load
+	 * an invalidation array. In the meantime, a domain attachment mutates
+	 * the array and then stores an STE/CD asking SMMU HW to acquire those
+	 * changed IOPTEs. In other word, these two are interdependent and can
+	 * race.
+	 *
+	 * In a race, the RCU design (with its underlying memory barriers) can
+	 * ensure the invalidation array to always get updated before loaded.
+	 *
+	 * smp_mb() is used here, paired with the smp_mb() following the array
+	 * update in a concurrent attach, to ensure:
+	 *  - HW sees the new IOPTEs if it walks after STE installation
+	 *  - Invalidation thread sees the updated array with the new ASID.
+	 *
+	 *  [CPU0]                        | [CPU1]
+	 *                                |
+	 *  change IOPTEs and TLB flush:  |
+	 *  arm_smmu_domain_inv_range() { | arm_smmu_install_new_domain_invs {
+	 *    ...                         |   rcu_assign_pointer(new_invs);
+	 *    smp_mb(); // ensure IOPTEs  |   smp_mb(); // ensure new_invs
+	 *    ...                         |   kfree_rcu(old_invs, rcu);
+	 *    // load invalidation array  | }
+	 *    invs = rcu_dereference();   | arm_smmu_install_ste_for_dev {
+	 *                                |   STE = TTB0 // read new IOPTEs
+	 */
+	smp_mb();
+
+	rcu_read_lock();
+	invs = rcu_dereference(smmu_domain->invs);
+
+	/*
+	 * Avoid locking unless ATS is being used. No ATC invalidation can be
+	 * going on after a domain is detached.
+	 */
+	if (invs->has_ats) {
+		read_lock(&invs->rwlock);
+		__arm_smmu_domain_inv_range(invs, iova, size, granule, leaf);
+		read_unlock(&invs->rwlock);
+	} else {
+		__arm_smmu_domain_inv_range(invs, iova, size, granule, leaf);
+	}
+
+	rcu_read_unlock();
+}
+
 static void arm_smmu_tlb_inv_page_nosync(struct iommu_iotlb_gather *gather,
 					 unsigned long iova, size_t granule,
 					 void *cookie)
@@ -3285,6 +3483,23 @@ arm_smmu_install_new_domain_invs(struct arm_smmu_attach_state *state)
 		return;
 
 	rcu_assign_pointer(*invst->invs_ptr, invst->new_invs);
+	/*
+	 * We are committed to updating the STE. Ensure the invalidation array
+	 * is visible to concurrent map/unmap threads, and acquire any racing
+	 * IOPTE updates.
+	 *
+	 *  [CPU0]                        | [CPU1]
+	 *                                |
+	 *  change IOPTEs and TLB flush:  |
+	 *  arm_smmu_domain_inv_range() { | arm_smmu_install_new_domain_invs {
+	 *    ...                         |   rcu_assign_pointer(new_invs);
+	 *    smp_mb(); // ensure IOPTEs  |   smp_mb(); // ensure new_invs
+	 *    ...                         |   kfree_rcu(old_invs, rcu);
+	 *    // load invalidation array  | }
+	 *    invs = rcu_dereference();   | arm_smmu_install_ste_for_dev {
+	 *                                |   STE = TTB0 // read new IOPTEs
+	 */
+	smp_mb();
 	kfree_rcu(invst->old_invs, rcu);
 }
 
@@ -3334,6 +3549,23 @@ arm_smmu_install_old_domain_invs(struct arm_smmu_attach_state *state)
 		return;
 
 	rcu_assign_pointer(*invst->invs_ptr, new_invs);
+	/*
+	 * We are committed to updating the STE. Ensure the invalidation array
+	 * is visible to concurrent map/unmap threads, and acquire any racing
+	 * IOPTE updates.
+	 *
+	 *  [CPU0]                        | [CPU1]
+	 *                                |
+	 *  change IOPTEs and TLB flush:  |
+	 *  arm_smmu_domain_inv_range() { | arm_smmu_install_old_domain_invs {
+	 *    ...                         |   rcu_assign_pointer(new_invs);
+	 *    smp_mb(); // ensure IOPTEs  |   smp_mb(); // ensure new_invs
+	 *    ...                         |   kfree_rcu(old_invs, rcu);
+	 *    // load invalidation array  | }
+	 *    invs = rcu_dereference();   | arm_smmu_install_ste_for_dev {
+	 *                                |   STE = TTB0 // read new IOPTEs
+	 */
+	smp_mb();
 	kfree_rcu(old_invs, rcu);
 }
 
-- 
2.43.0



From nicolinc at nvidia.com  Fri Dec 19 12:11:25 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Fri, 19 Dec 2025 12:11:25 -0800
Subject: [PATCH v9 3/7] iommu/arm-smmu-v3: Introduce a per-domain arm_smmu_invs array
In-Reply-To: <cover.1766174731.git.nicolinc@nvidia.com>
References: <cover.1766174731.git.nicolinc@nvidia.com>
Message-ID: <8c94c5194871ee1a0f3a6b49e18818b88f51226d.1766174731.git.nicolinc@nvidia.com>

From: Jason Gunthorpe <jgg at nvidia.com>

Create a new data structure to hold an array of invalidations that need to
be performed for the domain based on what masters are attached, to replace
the single smmu pointer and linked list of masters in the current design.

Each array entry holds one of the invalidation actions - S1_ASID, S2_VMID,
ATS or their variant with information to feed invalidation commands to HW.
It is structured so that multiple SMMUs can participate in the same array,
removing one key limitation of the current system.

To maximize performance, a sorted array is used as the data structure. It
allows grouping SYNCs together to parallelize invalidations. For instance,
it will group all the ATS entries after the ASID/VMID entry, so they will
all be pushed to the PCI devices in parallel with one SYNC.

To minimize the locking cost on the invalidation fast path (reader of the
invalidation array), the array is managed with RCU.

Provide a set of APIs to add/delete entries to/from an array, which cover
cannot-fail attach cases, e.g. attaching to arm_smmu_blocked_domain. Also
add kunit coverage for those APIs.

Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
Reviewed-by: Jason Gunthorpe <jgg at nvidia.com>
Co-developed-by: Nicolin Chen <nicolinc at nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  98 +++++++
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c  |  92 +++++++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 258 ++++++++++++++++++
 3 files changed, 448 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index 96a23ca633cb..a9441dc9070e 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -649,6 +649,93 @@ struct arm_smmu_cmdq_batch {
 	int				num;
 };
 
+/*
+ * The order here also determines the sequence in which commands are sent to the
+ * command queue. E.g. TLBI must be done before ATC_INV.
+ */
+enum arm_smmu_inv_type {
+	INV_TYPE_S1_ASID,
+	INV_TYPE_S2_VMID,
+	INV_TYPE_S2_VMID_S1_CLEAR,
+	INV_TYPE_ATS,
+	INV_TYPE_ATS_FULL,
+};
+
+struct arm_smmu_inv {
+	struct arm_smmu_device *smmu;
+	u8 type;
+	u8 size_opcode;
+	u8 nsize_opcode;
+	u32 id; /* ASID or VMID or SID */
+	union {
+		size_t pgsize; /* ARM_SMMU_FEAT_RANGE_INV */
+		u32 ssid; /* INV_TYPE_ATS */
+	};
+
+	refcount_t users; /* users=0 to mark as a trash to be purged */
+};
+
+static inline bool arm_smmu_inv_is_ats(const struct arm_smmu_inv *inv)
+{
+	return inv->type == INV_TYPE_ATS || inv->type == INV_TYPE_ATS_FULL;
+}
+
+/**
+ * struct arm_smmu_invs - Per-domain invalidation array
+ * @max_invs: maximum capacity of the flexible array
+ * @num_invs: number of invalidations in the flexible array. May be smaller than
+ *            @max_invs after a tailing trash entry is excluded, but must not be
+ *            greater than @max_invs
+ * @num_trashes: number of trash entries in the array for arm_smmu_invs_purge().
+ *               Must not be greater than @num_invs
+ * @rwlock: optional rwlock to fench ATS operations
+ * @has_ats: flag if the array contains an INV_TYPE_ATS or INV_TYPE_ATS_FULL
+ * @rcu: rcu head for kfree_rcu()
+ * @inv: flexible invalidation array
+ *
+ * The arm_smmu_invs is an RCU data structure. During a ->attach_dev callback,
+ * arm_smmu_invs_merge(), arm_smmu_invs_unref() and arm_smmu_invs_purge() will
+ * be used to allocate a new copy of an old array for addition and deletion in
+ * the old domain's and new domain's invs arrays.
+ *
+ * The arm_smmu_invs_unref() mutates a given array, by internally reducing the
+ * users counts of some given entries. This exists to support a no-fail routine
+ * like attaching to an IOMMU_DOMAIN_BLOCKED. And it could pair with a followup
+ * arm_smmu_invs_purge() call to generate a new clean array.
+ *
+ * Concurrent invalidation thread will push every invalidation described in the
+ * array into the command queue for each invalidation event. It is designed like
+ * this to optimize the invalidation fast path by avoiding locks.
+ *
+ * A domain can be shared across SMMU instances. When an instance gets removed,
+ * it would delete all the entries that belong to that SMMU instance. Then, a
+ * synchronize_rcu() would have to be called to sync the array, to prevent any
+ * concurrent invalidation thread accessing the old array from issuing commands
+ * to the command queue of a removed SMMU instance.
+ */
+struct arm_smmu_invs {
+	size_t max_invs;
+	size_t num_invs;
+	size_t num_trashes;
+	rwlock_t rwlock;
+	bool has_ats;
+	struct rcu_head rcu;
+	struct arm_smmu_inv inv[] __counted_by(max_invs);
+};
+
+static inline struct arm_smmu_invs *arm_smmu_invs_alloc(size_t num_invs)
+{
+	struct arm_smmu_invs *new_invs;
+
+	new_invs = kzalloc(struct_size(new_invs, inv, num_invs), GFP_KERNEL);
+	if (!new_invs)
+		return NULL;
+	new_invs->max_invs = num_invs;
+	new_invs->num_invs = num_invs;
+	rwlock_init(&new_invs->rwlock);
+	return new_invs;
+}
+
 struct arm_smmu_evtq {
 	struct arm_smmu_queue		q;
 	struct iopf_queue		*iopf;
@@ -875,6 +962,8 @@ struct arm_smmu_domain {
 
 	struct iommu_domain		domain;
 
+	struct arm_smmu_invs __rcu	*invs;
+
 	/* List of struct arm_smmu_master_domain */
 	struct list_head		devices;
 	spinlock_t			devices_lock;
@@ -923,6 +1012,13 @@ void arm_smmu_make_cdtable_ste(struct arm_smmu_ste *target,
 void arm_smmu_make_sva_cd(struct arm_smmu_cd *target,
 			  struct arm_smmu_master *master, struct mm_struct *mm,
 			  u16 asid);
+
+struct arm_smmu_invs *arm_smmu_invs_merge(struct arm_smmu_invs *invs,
+					  struct arm_smmu_invs *to_merge);
+void arm_smmu_invs_unref(struct arm_smmu_invs *invs,
+			 struct arm_smmu_invs *to_unref,
+			 void (*free_fn)(struct arm_smmu_inv *inv));
+struct arm_smmu_invs *arm_smmu_invs_purge(struct arm_smmu_invs *invs);
 #endif
 
 struct arm_smmu_master_domain {
@@ -956,6 +1052,8 @@ struct arm_smmu_domain *arm_smmu_domain_alloc(void);
 
 static inline void arm_smmu_domain_free(struct arm_smmu_domain *smmu_domain)
 {
+	/* No concurrency with invalidation is possible at this point */
+	kfree(rcu_dereference_protected(smmu_domain->invs, true));
 	kfree(smmu_domain);
 }
 
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
index d2671bfd3798..238bfd328b5b 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c
@@ -567,6 +567,97 @@ static void arm_smmu_v3_write_cd_test_sva_release(struct kunit *test)
 						      NUM_EXPECTED_SYNCS(2));
 }
 
+static void arm_smmu_v3_invs_test_verify(struct kunit *test,
+					 struct arm_smmu_invs *invs, int num,
+					 const int *ids, const int *users)
+{
+	KUNIT_EXPECT_EQ(test, invs->num_invs, num);
+	while (num--) {
+		KUNIT_EXPECT_EQ(test, invs->inv[num].id, ids[num]);
+		KUNIT_EXPECT_EQ(test, refcount_read(&invs->inv[num].users),
+				users[num]);
+	}
+}
+
+static struct arm_smmu_invs invs1 = {
+	.num_invs = 3,
+	.inv = { { .type = INV_TYPE_S2_VMID, .id = 1, },
+		 { .type = INV_TYPE_S2_VMID_S1_CLEAR, .id = 1, },
+		 { .type = INV_TYPE_ATS, .id = 3, }, },
+};
+
+static struct arm_smmu_invs invs2 = {
+	.num_invs = 3,
+	.inv = { { .type = INV_TYPE_S2_VMID, .id = 1, }, /* duplicated */
+		 { .type = INV_TYPE_ATS, .id = 4, },
+		 { .type = INV_TYPE_ATS, .id = 5, }, },
+};
+
+static struct arm_smmu_invs invs3 = {
+	.num_invs = 3,
+	.inv = { { .type = INV_TYPE_S2_VMID, .id = 1, }, /* duplicated */
+		 { .type = INV_TYPE_ATS, .id = 5, }, /* recover a trash */
+		 { .type = INV_TYPE_ATS, .id = 6, }, },
+};
+
+static void arm_smmu_v3_invs_test(struct kunit *test)
+{
+	const int results1[2][3] = { { 1, 1, 3, }, { 1, 1, 1, }, };
+	const int results2[2][5] = { { 1, 1, 3, 4, 5, }, { 2, 1, 1, 1, 1, }, };
+	const int results3[2][3] = { { 1, 1, 3, }, { 1, 1, 1, }, };
+	const int results4[2][5] = { { 1, 1, 3, 5, 6, }, { 2, 1, 1, 1, 1, }, };
+	const int results5[2][5] = { { 1, 1, 3, 5, 6, }, { 1, 0, 0, 1, 1, }, };
+	const int results6[2][3] = { { 1, 5, 6, }, { 1, 1, 1, }, };
+	struct arm_smmu_invs *test_a, *test_b;
+
+	/* New array */
+	test_a = arm_smmu_invs_alloc(0);
+	KUNIT_EXPECT_EQ(test, test_a->num_invs, 0);
+
+	/* Test1: merge invs1 (new array) */
+	test_b = arm_smmu_invs_merge(test_a, &invs1);
+	kfree(test_a);
+	arm_smmu_v3_invs_test_verify(test, test_b, ARRAY_SIZE(results1[0]),
+				     results1[0], results1[1]);
+
+	/* Test2: merge invs2 (new array) */
+	test_a = arm_smmu_invs_merge(test_b, &invs2);
+	kfree(test_b);
+	arm_smmu_v3_invs_test_verify(test, test_a, ARRAY_SIZE(results2[0]),
+				     results2[0], results2[1]);
+
+	/* Test3: unref invs2 (same array) */
+	arm_smmu_invs_unref(test_a, &invs2, NULL);
+	arm_smmu_v3_invs_test_verify(test, test_a, ARRAY_SIZE(results3[0]),
+				     results3[0], results3[1]);
+	KUNIT_EXPECT_EQ(test, test_a->num_trashes, 0);
+
+	/* Test4: merge invs3 (new array) */
+	test_b = arm_smmu_invs_merge(test_a, &invs3);
+	kfree(test_a);
+	arm_smmu_v3_invs_test_verify(test, test_b, ARRAY_SIZE(results4[0]),
+				     results4[0], results4[1]);
+
+	/* Test5: unref invs1 (same array) */
+	arm_smmu_invs_unref(test_b, &invs1, NULL);
+	arm_smmu_v3_invs_test_verify(test, test_b, ARRAY_SIZE(results5[0]),
+				     results5[0], results5[1]);
+	KUNIT_EXPECT_EQ(test, test_b->num_trashes, 2);
+
+	/* Test6: purge test_b (new array) */
+	test_a = arm_smmu_invs_purge(test_b);
+	kfree(test_b);
+	arm_smmu_v3_invs_test_verify(test, test_a, ARRAY_SIZE(results6[0]),
+				     results6[0], results6[1]);
+
+	/* Test7: unref invs3 (same array) */
+	arm_smmu_invs_unref(test_a, &invs3, NULL);
+	KUNIT_EXPECT_EQ(test, test_a->num_invs, 0);
+	KUNIT_EXPECT_EQ(test, test_a->num_trashes, 0);
+
+	kfree(test_a);
+}
+
 static struct kunit_case arm_smmu_v3_test_cases[] = {
 	KUNIT_CASE(arm_smmu_v3_write_ste_test_bypass_to_abort),
 	KUNIT_CASE(arm_smmu_v3_write_ste_test_abort_to_bypass),
@@ -590,6 +681,7 @@ static struct kunit_case arm_smmu_v3_test_cases[] = {
 	KUNIT_CASE(arm_smmu_v3_write_ste_test_s2_to_s1_stall),
 	KUNIT_CASE(arm_smmu_v3_write_cd_test_sva_clear),
 	KUNIT_CASE(arm_smmu_v3_write_cd_test_sva_release),
+	KUNIT_CASE(arm_smmu_v3_invs_test),
 	{},
 };
 
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index e9759e8af0c0..39e89176fa87 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -26,6 +26,7 @@
 #include <linux/pci.h>
 #include <linux/pci-ats.h>
 #include <linux/platform_device.h>
+#include <linux/sort.h>
 #include <linux/string_choices.h>
 #include <kunit/visibility.h>
 #include <uapi/linux/iommufd.h>
@@ -1015,6 +1016,255 @@ static void arm_smmu_page_response(struct device *dev, struct iopf_fault *unused
 	 */
 }
 
+/* Invalidation array manipulation functions */
+static inline struct arm_smmu_inv *
+arm_smmu_invs_iter_next(struct arm_smmu_invs *invs, size_t next, size_t *idx)
+{
+	while (true) {
+		if (next >= invs->num_invs) {
+			*idx = next;
+			return NULL;
+		}
+		if (!refcount_read(&invs->inv[next].users)) {
+			next++;
+			continue;
+		}
+		*idx = next;
+		return &invs->inv[next];
+	}
+}
+
+/**
+ * arm_smmu_invs_for_each_entry - Iterate over all non-trash entries in invs
+ * @invs: the base invalidation array
+ * @idx: a stack variable of 'size_t', to store the array index
+ * @cur: a stack variable of 'struct arm_smmu_inv *'
+ */
+#define arm_smmu_invs_for_each_entry(invs, idx, cur)                           \
+	for (cur = arm_smmu_invs_iter_next(invs, 0, &(idx)); cur;              \
+	     cur = arm_smmu_invs_iter_next(invs, idx + 1, &(idx)))
+
+static int arm_smmu_inv_cmp(const struct arm_smmu_inv *inv_l,
+			    const struct arm_smmu_inv *inv_r)
+{
+	if (inv_l->smmu != inv_r->smmu)
+		return cmp_int((uintptr_t)inv_l->smmu, (uintptr_t)inv_r->smmu);
+	if (inv_l->type != inv_r->type)
+		return cmp_int(inv_l->type, inv_r->type);
+	return cmp_int(inv_l->id, inv_r->id);
+}
+
+static inline int arm_smmu_invs_iter_next_cmp(struct arm_smmu_invs *invs_l,
+					      size_t next_l, size_t *idx_l,
+					      struct arm_smmu_invs *invs_r,
+					      size_t next_r, size_t *idx_r)
+{
+	struct arm_smmu_inv *cur_l =
+		arm_smmu_invs_iter_next(invs_l, next_l, idx_l);
+
+	/*
+	 * We have to update the idx_r manually, because the invs_r cannot call
+	 * arm_smmu_invs_iter_next() as the invs_r never sets any users counter.
+	 */
+	*idx_r = next_r;
+
+	/*
+	 * Compare of two sorted arrays items. If one side is past the end of
+	 * the array, return the other side to let it run out the iteration.
+	 *
+	 * If the left entry is empty, return 1 to pick the right entry.
+	 * If the right entry is empty, return -1 to pick the left entry.
+	 */
+	if (!cur_l)
+		return 1;
+	if (next_r >= invs_r->num_invs)
+		return -1;
+	return arm_smmu_inv_cmp(cur_l, &invs_r->inv[next_r]);
+}
+
+/**
+ * arm_smmu_invs_for_each_entry - Iterate over two sorted arrays computing for
+ *                                arm_smmu_invs_merge() or arm_smmu_invs_unref()
+ * @invs_l: the base invalidation array
+ * @idx_l: a stack variable of 'size_t', to store the base array index
+ * @invs_r: the build_invs array as to_merge or to_unref
+ * @idx_r: a stack variable of 'size_t', to store the build_invs index
+ * @cmp: a stack variable of 'int', to store return value (-1, 0, or 1)
+ */
+#define arm_smmu_invs_for_each_cmp(invs_l, idx_l, invs_r, idx_r, cmp)          \
+	for (idx_l = idx_r = 0,                                                \
+	     cmp = arm_smmu_invs_iter_next_cmp(invs_l, 0, &(idx_l),            \
+					       invs_r, 0, &(idx_r));           \
+	     idx_l < invs_l->num_invs || idx_r < invs_r->num_invs;             \
+	     cmp = arm_smmu_invs_iter_next_cmp(                                \
+		     invs_l, idx_l + (cmp <= 0 ? 1 : 0), &(idx_l),             \
+		     invs_r, idx_r + (cmp >= 0 ? 1 : 0), &(idx_r)))
+
+/**
+ * arm_smmu_invs_merge() - Merge @to_merge into @invs and generate a new array
+ * @invs: the base invalidation array
+ * @to_merge: an array of invlidations to merge
+ *
+ * Return: a newly allocated array on success, or ERR_PTR
+ *
+ * This function must be locked and serialized with arm_smmu_invs_unref() and
+ * arm_smmu_invs_purge(), but do not lockdep on any lock for KUNIT test.
+ *
+ * Both @invs and @to_merge must be sorted, to ensure the returned array will be
+ * sorted as well.
+ *
+ * Caller is resposible for freeing the @invs and the returned new one.
+ *
+ * Entries marked as trash will be purged in the returned array.
+ */
+VISIBLE_IF_KUNIT
+struct arm_smmu_invs *arm_smmu_invs_merge(struct arm_smmu_invs *invs,
+					  struct arm_smmu_invs *to_merge)
+{
+	struct arm_smmu_invs *new_invs;
+	struct arm_smmu_inv *new;
+	size_t num_invs = 0;
+	size_t i, j;
+	int cmp;
+
+	arm_smmu_invs_for_each_cmp(invs, i, to_merge, j, cmp)
+		num_invs++;
+
+	new_invs = arm_smmu_invs_alloc(num_invs);
+	if (!new_invs)
+		return ERR_PTR(-ENOMEM);
+
+	new = new_invs->inv;
+	arm_smmu_invs_for_each_cmp(invs, i, to_merge, j, cmp) {
+		if (cmp < 0) {
+			*new = invs->inv[i];
+		} else if (cmp == 0) {
+			*new = invs->inv[i];
+			refcount_inc(&new->users);
+		} else {
+			*new = to_merge->inv[j];
+			refcount_set(&new->users, 1);
+		}
+
+		/*
+		 * Check that the new array is sorted. This also validates that
+		 * to_merge is sorted.
+		 */
+		if (new != new_invs->inv)
+			WARN_ON_ONCE(arm_smmu_inv_cmp(new - 1, new) == 1);
+		if (arm_smmu_inv_is_ats(new))
+			new_invs->has_ats = true;
+		new++;
+	}
+
+	WARN_ON(new != new_invs->inv + new_invs->num_invs);
+
+	return new_invs;
+}
+EXPORT_SYMBOL_IF_KUNIT(arm_smmu_invs_merge);
+
+/**
+ * arm_smmu_invs_unref() - Find in @invs for all entries in @to_unref, decrease
+ *                         the user counts without deletions
+ * @invs: the base invalidation array
+ * @to_unref: an array of invlidations to decrease their user counts
+ * @free_fn: A callback function to invoke, when an entry's user count reduces
+ *           to 0
+ *
+ * Return: the number of trash entries in the array, for arm_smmu_invs_purge()
+ *
+ * This function will not fail. Any entry with users=0 will be marked as trash.
+ * All tailing trash entries in the array will be dropped. And the size of the
+ * array will be trimmed properly. All trash entries in-between will remain in
+ * the @invs until being completely deleted by the next arm_smmu_invs_merge()
+ * or an arm_smmu_invs_purge() function call.
+ *
+ * This function must be locked and serialized with arm_smmu_invs_merge() and
+ * arm_smmu_invs_purge(), but do not lockdep on any mutex for KUNIT test.
+ *
+ * Note that the final @invs->num_invs might not reflect the actual number of
+ * invalidations due to trash entries. Any reader should take the read lock to
+ * iterate each entry and check its users counter till the last entry.
+ */
+VISIBLE_IF_KUNIT
+void arm_smmu_invs_unref(struct arm_smmu_invs *invs,
+			 struct arm_smmu_invs *to_unref,
+			 void (*free_fn)(struct arm_smmu_inv *inv))
+{
+	unsigned long flags;
+	size_t num_invs = 0;
+	size_t i, j;
+	int cmp;
+
+	arm_smmu_invs_for_each_cmp(invs, i, to_unref, j, cmp) {
+		if (cmp < 0) {
+			/* not found in to_unref, leave alone */
+			num_invs = i + 1;
+		} else if (cmp == 0) {
+			/* same item */
+			if (!refcount_dec_and_test(&invs->inv[i].users)) {
+				num_invs = i + 1;
+				continue;
+			}
+
+			/* KUNIT test doesn't pass in a free_fn */
+			if (free_fn)
+				free_fn(&invs->inv[i]);
+			invs->num_trashes++;
+		} else {
+			/* item in to_unref is not in invs or already a trash */
+			WARN_ON(true);
+		}
+	}
+
+	/* Exclude any tailing trash */
+	invs->num_trashes -= invs->num_invs - num_invs;
+
+	/* The lock is required to fence concurrent ATS operations. */
+	write_lock_irqsave(&invs->rwlock, flags);
+	WRITE_ONCE(invs->num_invs, num_invs); /* Remove tailing trash entries */
+	write_unlock_irqrestore(&invs->rwlock, flags);
+}
+EXPORT_SYMBOL_IF_KUNIT(arm_smmu_invs_unref);
+
+/**
+ * arm_smmu_invs_purge() - Purge all the trash entries in the @invs
+ * @invs: the base invalidation array
+ *
+ * Return: a newly allocated array on success removing all the trash entries, or
+ *         NULL if there is no trash entry in the array or there is a bug
+ *
+ * This function must be locked and serialized with arm_smmu_invs_merge() and
+ * arm_smmu_invs_unref(), but do not lockdep on any lock for KUNIT test.
+ *
+ * Caller is resposible for freeing the @invs and the returned new one.
+ */
+VISIBLE_IF_KUNIT
+struct arm_smmu_invs *arm_smmu_invs_purge(struct arm_smmu_invs *invs)
+{
+	struct arm_smmu_invs *new_invs;
+	struct arm_smmu_inv *inv;
+	size_t i, num_invs = 0;
+
+	if (WARN_ON(invs->num_invs < invs->num_trashes))
+		return NULL;
+	if (!invs->num_invs || !invs->num_trashes)
+		return NULL;
+
+	new_invs = arm_smmu_invs_alloc(invs->num_invs - invs->num_trashes);
+	if (!new_invs)
+		return ERR_PTR(-ENOMEM);
+
+	arm_smmu_invs_for_each_entry(invs, i, inv) {
+		new_invs->inv[num_invs] = *inv;
+		num_invs++;
+	}
+
+	WARN_ON(num_invs != new_invs->num_invs);
+	return new_invs;
+}
+EXPORT_SYMBOL_IF_KUNIT(arm_smmu_invs_purge);
+
 /* Context descriptor manipulation functions */
 void arm_smmu_tlb_inv_asid(struct arm_smmu_device *smmu, u16 asid)
 {
@@ -2462,13 +2712,21 @@ static bool arm_smmu_enforce_cache_coherency(struct iommu_domain *domain)
 struct arm_smmu_domain *arm_smmu_domain_alloc(void)
 {
 	struct arm_smmu_domain *smmu_domain;
+	struct arm_smmu_invs *new_invs;
 
 	smmu_domain = kzalloc(sizeof(*smmu_domain), GFP_KERNEL);
 	if (!smmu_domain)
 		return ERR_PTR(-ENOMEM);
 
+	new_invs = arm_smmu_invs_alloc(0);
+	if (!new_invs) {
+		kfree(smmu_domain);
+		return ERR_PTR(-ENOMEM);
+	}
+
 	INIT_LIST_HEAD(&smmu_domain->devices);
 	spin_lock_init(&smmu_domain->devices_lock);
+	rcu_assign_pointer(smmu_domain->invs, new_invs);
 
 	return smmu_domain;
 }
-- 
2.43.0



From arnd at arndb.de  Fri Dec 19 12:20:20 2025
From: arnd at arndb.de (Arnd Bergmann)
Date: Fri, 19 Dec 2025 21:20:20 +0100
Subject: [PATCH 1/4] arch/*: increase lowmem size to avoid highmem use
In-Reply-To: <a3f22579-13ee-4479-a5fd-81c29145c3f3@intel.com>
References: <20251219161559.556737-1-arnd@kernel.org>
 <20251219161559.556737-2-arnd@kernel.org>
 <a3f22579-13ee-4479-a5fd-81c29145c3f3@intel.com>
Message-ID: <bad18ad8-93e8-4150-a85e-a2852e243363@app.fastmail.com>

On Fri, Dec 19, 2025, at 19:02, Dave Hansen wrote:
> On 12/19/25 08:15, Arnd Bergmann wrote:
>> --- a/arch/x86/Kconfig
>> +++ b/arch/x86/Kconfig
>> @@ -1416,7 +1416,9 @@ config HIGHMEM4G
>>  
>>  choice
>>  	prompt "Memory split" if EXPERT
>> -	default VMSPLIT_3G
>> +	default VMSPLIT_2G_OPT if HIGHMEM && !X86_PAE
>> +	default VMSPLIT_2G if X86_PAE
>> +	default VMSPLIT_3G_OPT
>>  	depends on X86_32
>
> For simplicity, I think this can just be:
>
> -	default VMSPLIT_3G
> +	default VMSPLIT_2G
>
> I doubt the 2G vs. 2G_OPT matters in very many cases. If it does, folks
> can just set it in their config manually.
>
> But, in the end, I don't this this matters all that much. If you think
> having x86 be consistent with ARM, for example, is more important and
> ARM really wants this complexity, I can live with it.

Yes, I think we do want the default of VMSPLIT_3G_OPT for
configs that have neither highmem nor lpae, otherwise the most
common embedded configs go from 3072 MiB to 1792 MiB of virtual
addressing, and that is much more likely to cause regressions
than the 2816 MiB default.

It would be nice to not need the VMSPLIT_2G default for PAE/LPAE,
but that seems like a larger change.

     Arnd


From arnd at arndb.de  Fri Dec 19 12:34:33 2025
From: arnd at arndb.de (Arnd Bergmann)
Date: Fri, 19 Dec 2025 21:34:33 +0100
Subject: [PATCH 3/4] ARM: remove support for highmem on VIVT
In-Reply-To: <20251219171412.GG254720@nvidia.com>
References: <20251219161559.556737-1-arnd@kernel.org>
 <20251219161559.556737-4-arnd@kernel.org>
 <20251219171412.GG254720@nvidia.com>
Message-ID: <513078d3-976a-4e6d-b311-dcfcfea99238@app.fastmail.com>

On Fri, Dec 19, 2025, at 18:14, Jason Gunthorpe wrote:
> On Fri, Dec 19, 2025 at 05:15:58PM +0100, Arnd Bergmann wrote:
>>  arch/arm/Kconfig                    |  1 +
>>  arch/arm/configs/gemini_defconfig   |  1 -
>>  arch/arm/configs/multi_v5_defconfig |  1 -
>>  arch/arm/configs/mvebu_v5_defconfig |  1 -
>>  arch/arm/include/asm/highmem.h      | 56 ++---------------------------
>>  arch/arm/mm/cache-feroceon-l2.c     | 31 ++--------------
>>  arch/arm/mm/cache-xsc3l2.c          | 47 +++---------------------
>>  arch/arm/mm/dma-mapping.c           | 12 ++-----
>>  arch/arm/mm/flush.c                 | 19 +++-------
>>  9 files changed, 16 insertions(+), 153 deletions(-)
>
> This looks great, but do you think there should be a boot time crash
> if a VIVT and HIGHMEM are enabled, just incase?

Do you mean in the common code or just for Arm?

We could use the Arm specific cache_is_vivt() macro, but it feels like
the 'dpends on !CPU_CACHE_VIVT' Kconfig check I added is both
safer and simpler.

In common code I don't see a way to detect vivt caches. There is
cpu_dcache_is_aliasing(), but that also seems to cover ARM11
processors with aliasing VIPT caches, which are otherwise fine
here.

     Arnd


From florian.fainelli at broadcom.com  Fri Dec 19 12:41:11 2025
From: florian.fainelli at broadcom.com (Florian Fainelli)
Date: Fri, 19 Dec 2025 12:41:11 -0800
Subject: [PATCH 1/4] dt-bindings: misc: pci1de4,1: add required reg property for endpoint
In-Reply-To: <b58bfcd957b2270fcf932d463f2db534b2ae1a6d.1766077285.git.andrea.porta@suse.com>
References: <cover.1766077285.git.andrea.porta@suse.com> <b58bfcd957b2270fcf932d463f2db534b2ae1a6d.1766077285.git.andrea.porta@suse.com>
Message-ID: <20251219204111.1015295-1-florian.fainelli@broadcom.com>

From: Florian Fainelli <f.fainelli at gmail.com>

On Thu, 18 Dec 2025 20:09:06 +0100, Andrea della Porta <andrea.porta at suse.com> wrote:
> The PCI subsystem links an endpoint Device Tree node to its corresponding
> pci_dev structure only if the Bus/Device/Function (BDF) encoded in the
> 'reg' property matches the actual hardware topology.
> 
> Add the 'reg' property and mark it as required to ensure proper binding
> between the device_node and the pci_dev.
> 
> Update the example to reflect this requirement.
> 
> Signed-off-by: Andrea della Porta <andrea.porta at suse.com>
> ---

Applied to https://github.com/Broadcom/stblinux/commits/devicetree-arm64/fixes, thanks!
--
Florian


From florian.fainelli at broadcom.com  Fri Dec 19 12:41:38 2025
From: florian.fainelli at broadcom.com (Florian Fainelli)
Date: Fri, 19 Dec 2025 12:41:38 -0800
Subject: [PATCH 3/4] arm64: dts: broadcom: bcm2712: fix RP1 endpoint PCI topology
In-Reply-To: <827b12ba48bb47bc77a0f5e5617aea961c8bc6b5.1766077285.git.andrea.porta@suse.com>
References: <cover.1766077285.git.andrea.porta@suse.com> <827b12ba48bb47bc77a0f5e5617aea961c8bc6b5.1766077285.git.andrea.porta@suse.com>
Message-ID: <20251219204138.1015487-1-florian.fainelli@broadcom.com>

From: Florian Fainelli <f.fainelli at gmail.com>

On Thu, 18 Dec 2025 20:09:08 +0100, Andrea della Porta <andrea.porta at suse.com> wrote:
> The node describing the RP1 endpoint currently uses a specific name
> ('rp1_nexus') that does not correctly reflect the PCI topology.
> 
> Update the DT with the correct topology and use generic node names.
> 
> Additionally, since the driver dropped overlay support in favor of a
> fully described DT, rename '...-ovl-rp1.dts' to '...-base.dtsi' for
> inclusion in the board DTB, as it is no longer compiled as a
> standalone DTB.
> 
> Signed-off-by: Andrea della Porta <andrea.porta at suse.com>
> ---

Applied to https://github.com/Broadcom/stblinux/commits/devicetree-arm64/fixes, thanks!
--
Florian


From florian.fainelli at broadcom.com  Fri Dec 19 12:41:53 2025
From: florian.fainelli at broadcom.com (Florian Fainelli)
Date: Fri, 19 Dec 2025 12:41:53 -0800
Subject: [PATCH 4/4] arm64: dts: broadcom: rp1: drop RP1 overlay
In-Reply-To: <85167b815d41ed9ed690ad239a19de5cd2e8be1c.1766077285.git.andrea.porta@suse.com>
References: <cover.1766077285.git.andrea.porta@suse.com> <85167b815d41ed9ed690ad239a19de5cd2e8be1c.1766077285.git.andrea.porta@suse.com>
Message-ID: <20251219204153.1015582-1-florian.fainelli@broadcom.com>

From: Florian Fainelli <f.fainelli at gmail.com>

On Thu, 18 Dec 2025 20:09:09 +0100, Andrea della Porta <andrea.porta at suse.com> wrote:
> RP1 support loaded from overlay has been dropped from the driver and
> the DTB intended to be loaded with the overlay no longer exists.
> 
> Drop unused include file and overlay.
> 
> Signed-off-by: Andrea della Porta <andrea.porta at suse.com>
> ---

Applied to https://github.com/Broadcom/stblinux/commits/devicetree-arm64/fixes, thanks!
--
Florian


From florian.fainelli at broadcom.com  Fri Dec 19 12:41:27 2025
From: florian.fainelli at broadcom.com (Florian Fainelli)
Date: Fri, 19 Dec 2025 12:41:27 -0800
Subject: [PATCH 2/4] misc: rp1: drop overlay support
In-Reply-To: <4b0aa7160877cf128b9bc713776bcac73c46eb24.1766077285.git.andrea.porta@suse.com>
References: <cover.1766077285.git.andrea.porta@suse.com> <4b0aa7160877cf128b9bc713776bcac73c46eb24.1766077285.git.andrea.porta@suse.com>
Message-ID: <20251219204127.1015395-1-florian.fainelli@broadcom.com>

From: Florian Fainelli <f.fainelli at gmail.com>

On Thu, 18 Dec 2025 20:09:07 +0100, Andrea della Porta <andrea.porta at suse.com> wrote:
> The RP1 driver can load an overlay at runtime to describe the inner
> peripherals. This has led to a lot of confusion regarding the naming
> of nodes, their topology and the reclaiming of related node resources.
> 
> Since the overlay is currently not fully functional, drop its support
> in the driver in favor of the fully described static DT.
> 
> This also means that this driver does not depend on CONFIG_PCI_DYNAMIC_OF_NODES
> and no longer requires PCI quirks to dynamically create the intermediate
> PCI nodes.
> 
> Signed-off-by: Andrea della Porta <andrea.porta at suse.com>
> ---

Applied to https://github.com/Broadcom/stblinux/commits/devicetree-arm64/fixes, thanks!
--
Florian


From florian.fainelli at broadcom.com  Fri Dec 19 12:46:03 2025
From: florian.fainelli at broadcom.com (Florian Fainelli)
Date: Fri, 19 Dec 2025 12:46:03 -0800
Subject: [GIT PULL 1/1] Broadcom devicetree-arm64 fixes for 6.19
Message-ID: <20251219204603.1016528-1-florian.fainelli@broadcom.com>

The following changes since commit 8f0b4cce4481fb22653697cced8d0d04027cb1e8:

  Linux 6.19-rc1 (2025-12-14 16:05:07 +1200)

are available in the Git repository at:

  https://github.com/Broadcom/stblinux.git tags/arm-soc/for-6.19/devicetree-arm64-fixes

for you to fetch changes up to 9a96cc8bbeefbc64654ac9c3da619443c22f6d32:

  arm64: dts: broadcom: rp1: drop RP1 overlay (2025-12-19 12:42:36 -0800)

----------------------------------------------------------------
This pull request contains Broadcom ARM64-SoC Device Tree fixes for
6.19, please pull the following:

- Andrea fixes the RP1 DeviceTree hierarchy and drop overlay support,
  this resolves a number of DTC warnings and other issues

----------------------------------------------------------------
Andrea della Porta (4):
      dt-bindings: misc: pci1de4,1: add required reg property for endpoint
      misc: rp1: drop overlay support
      arm64: dts: broadcom: bcm2712: fix RP1 endpoint PCI topology
      arm64: dts: broadcom: rp1: drop RP1 overlay

 .../devicetree/bindings/misc/pci1de4,1.yaml        |  8 ++++-
 arch/arm64/boot/dts/broadcom/Makefile              |  4 +--
 ...i-5-b-ovl-rp1.dts => bcm2712-rpi-5-b-base.dtsi} |  0
 arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts   | 39 ++++++++++++++--------
 arch/arm64/boot/dts/broadcom/rp1-nexus.dtsi        | 14 --------
 arch/arm64/boot/dts/broadcom/rp1.dtso              | 11 ------
 drivers/misc/rp1/Kconfig                           |  6 +---
 drivers/misc/rp1/Makefile                          |  3 +-
 drivers/misc/rp1/rp1-pci.dtso                      | 25 --------------
 drivers/misc/rp1/rp1_pci.c                         | 37 +++-----------------
 drivers/pci/quirks.c                               |  1 -
 11 files changed, 40 insertions(+), 108 deletions(-)
 rename arch/arm64/boot/dts/broadcom/{bcm2712-rpi-5-b-ovl-rp1.dts => bcm2712-rpi-5-b-base.dtsi} (100%)
 delete mode 100644 arch/arm64/boot/dts/broadcom/rp1-nexus.dtsi
 delete mode 100644 arch/arm64/boot/dts/broadcom/rp1.dtso
 delete mode 100644 drivers/misc/rp1/rp1-pci.dtso


From robh at kernel.org  Fri Dec 19 12:52:08 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Fri, 19 Dec 2025 14:52:08 -0600
Subject: [PATCH v2 02/12] dt-bindings: phy: mediatek,hdmi-phy: Add
 support for MT8188 SoC
In-Reply-To: <20251217-mtk-genio-evk-hdmi-support-v2-2-a994976bb39a@collabora.com>
References: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
 <20251217-mtk-genio-evk-hdmi-support-v2-2-a994976bb39a@collabora.com>
Message-ID: <176617752769.3912550.11182398487708653155.robh@kernel.org>


On Wed, 17 Dec 2025 11:19:01 +0100, Louis-Alexis Eyraud wrote:
> Add compatible string for the HDMI PHY IP on MT8188 SoC, that is
> compatible with the one found on MT8195 SoC.
> 
> Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
> ---
>  Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml | 4 ++++
>  1 file changed, 4 insertions(+)
> 

Reviewed-by: Rob Herring (Arm) <robh at kernel.org>



From dave.hansen at intel.com  Fri Dec 19 12:52:21 2025
From: dave.hansen at intel.com (Dave Hansen)
Date: Fri, 19 Dec 2025 12:52:21 -0800
Subject: [PATCH 1/4] arch/*: increase lowmem size to avoid highmem use
In-Reply-To: <bad18ad8-93e8-4150-a85e-a2852e243363@app.fastmail.com>
References: <20251219161559.556737-1-arnd@kernel.org>
 <20251219161559.556737-2-arnd@kernel.org>
 <a3f22579-13ee-4479-a5fd-81c29145c3f3@intel.com>
 <bad18ad8-93e8-4150-a85e-a2852e243363@app.fastmail.com>
Message-ID: <a2ce2849-e572-404c-9713-9283a43c09fe@intel.com>

On 12/19/25 12:20, Arnd Bergmann wrote:
>> For simplicity, I think this can just be:
>>
>> -	default VMSPLIT_3G
>> +	default VMSPLIT_2G
>>
>> I doubt the 2G vs. 2G_OPT matters in very many cases. If it does, folks
>> can just set it in their config manually.
>>
>> But, in the end, I don't this this matters all that much. If you think
>> having x86 be consistent with ARM, for example, is more important and
>> ARM really wants this complexity, I can live with it.
> Yes, I think we do want the default of VMSPLIT_3G_OPT for
> configs that have neither highmem nor lpae, otherwise the most
> common embedded configs go from 3072 MiB to 1792 MiB of virtual
> addressing, and that is much more likely to cause regressions
> than the 2816 MiB default.
> 
> It would be nice to not need the VMSPLIT_2G default for PAE/LPAE,
> but that seems like a larger change.

The only thing we'd "regress" would be someone who is repeatedly
starting from scratch with a defconfig and expecting defconfig to be the
same all the time. I honestly think that's highly unlikely.

If folks are upgrading and _actually_ exposed to regressions, they've
got an existing config and won't be hit by these defaults at *all*. They
won't actually regress.

In other words, I think we can be a lot more aggressive about defaults
than with the feature set we support. I'd much rather add complexity in
here for solving a real problem, like if we have armies of 32-bit x86
users constantly starting new projects from scratch and using defconfigs.

I'd _really_ like to keep the defaults as simple as possible.


From robh at kernel.org  Fri Dec 19 12:52:38 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Fri, 19 Dec 2025 14:52:38 -0600
Subject: [PATCH v2 03/12] dt-bindings: phy: mediatek,hdmi-phy: Document
 extra clocks for MT8195
In-Reply-To: <20251217-mtk-genio-evk-hdmi-support-v2-3-a994976bb39a@collabora.com>
References: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
 <20251217-mtk-genio-evk-hdmi-support-v2-3-a994976bb39a@collabora.com>
Message-ID: <176617755777.3913354.15520009809669313727.robh@kernel.org>


On Wed, 17 Dec 2025 11:19:02 +0100, Louis-Alexis Eyraud wrote:
> From: "N?colas F. R. A. Prado" <nfraprado at collabora.com>
> 
> MT8195's HDMI PHY block has 4 clocks instead of just a single one.
> Describe the extra clocks for it.
> 
> Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
> [Louis-Alexis Eyraud: addressed feedback from mailing list]
> Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
> ---
>  .../devicetree/bindings/phy/mediatek,hdmi-phy.yaml | 22 ++++++++++++++++++++++
>  1 file changed, 22 insertions(+)
> 

Reviewed-by: Rob Herring (Arm) <robh at kernel.org>



From nicolinc at nvidia.com  Fri Dec 19 12:56:17 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Fri, 19 Dec 2025 12:56:17 -0800
Subject: [PATCH v1 2/9] iommu/arm-smmu-v3: Add alloc_id/free_id functions
 to arm_smmu_invs
In-Reply-To: <20251219170551.GF254720@nvidia.com>
References: <cover.1766088962.git.nicolinc@nvidia.com>
 <1541ea4a9e9c935c2f907c0c5f13a4af2bdc2114.1766088962.git.nicolinc@nvidia.com>
 <20251219170551.GF254720@nvidia.com>
Message-ID: <aUW78ZV2D5aM75yN@Asurada-Nvidia>

On Fri, Dec 19, 2025 at 01:05:51PM -0400, Jason Gunthorpe wrote:
> On Thu, Dec 18, 2025 at 12:26:48PM -0800, Nicolin Chen wrote:
> > @@ -720,6 +723,9 @@ struct arm_smmu_invs {
> >  	rwlock_t rwlock;
> >  	bool has_ats;
> >  	struct rcu_head rcu;
> > +	struct arm_smmu_domain *smmu_domain;
> > +	int (*alloc_id)(struct arm_smmu_inv *inv, void *data);
> > +	void (*free_id)(struct arm_smmu_inv *inv, bool flush);
> >  	struct arm_smmu_inv inv[] __counted_by(max_invs);
> >  };
> 
> I'm not keen on this at all..
> 
> On the allocation side everything should be stored inside the
> invalidation list, we don't need function callbacks, just get the
> information from the list in the first place.
[...]
> @@ -3289,8 +3422,18 @@ static int arm_smmu_attach_prepare_invs(struct arm_smmu_attach_state *state,
>  		invst->old_invs = rcu_dereference_protected(
>  			new_smmu_domain->invs,
>  			lockdep_is_held(&arm_smmu_asid_lock));
> -		build_invs = arm_smmu_master_build_invs(
> -			master, state->ats_enabled, ssid, new_smmu_domain);
> +
> +		/* Re-use or allocate an IOTLB cache tag */
> +		ret = arm_smmu_get_tag(new_smmu_domain, master,
> +				       to_vsmmu(new_domain), &invst->tag,
> +				       false);
> +		if (ret)
> +			return ret;
> +
> +		build_invs = arm_smmu_master_build_invs(master,
> +							state->ats_enabled,
> +							ssid, new_smmu_domain,
> +							&invst->tag);
>  		if (!build_invs)
>  			return -EINVAL;

I had this when I was drafting the series in the beginning, but
later changed to the callback functions :-/

Again, my intention is to avoid iterating the array since merge
and unref functions are already doing that in their first loops.

That being said, if this get-before-build is the preferred way,
let's do that.

Thanks
Nicolin


From nathan at kernel.org  Fri Dec 19 13:11:47 2025
From: nathan at kernel.org (Nathan Chancellor)
Date: Fri, 19 Dec 2025 14:11:47 -0700
Subject: ARMv7 Linux + Rust doesn't boot when compiling with only LLVM=1
In-Reply-To: <1910f4b6-db74-4c86-9010-28ab4462c5a7@gmail.com>
References: <1286af8e-f908-45db-af7c-d9c5d592abfd@gmail.com>
 <0705db10-3cbb-4958-a116-112457f9af6c@gmail.com>
 <1910f4b6-db74-4c86-9010-28ab4462c5a7@gmail.com>
Message-ID: <20251219211147.GA1407372@ax162>

Hi Rudraksha,

On Wed, Dec 17, 2025 at 02:21:11AM -0800, Rudraksha Gupta wrote:
> On 12/16/25 06:41, Christian Schrefl wrote:
> > On 12/14/25 12:54 AM, Rudraksha Gupta wrote:
> > > Hello all,
> > > 
> > > 
> > > I have the following problem: https://gitlab.postmarketos.org/postmarketOS/pmbootstrap/-/issues/2635
> > > 
> > > 
> > > In short, what is happening is the following:
> > > 
> > > 
> > > - The kernel boots and outputs via UART when I build the kernel with the following:
> > > 
> > > make LLVM=1 ARCH="$arm" CC="${CC:-gcc}"
> > > 
> > > 
> > > - The kernel doesn't boot and there is no output via UART when I build the kernel with the following:
> > > 
> > > make LLVM=1 ARCH="$arm"
> > > 
> > > 
> > > The only difference being:?CC="${CC:-gcc}". Is this expected? I think this was present in the Linux kernel ever since Rust was enabled for ARMv7, and I never encountered it because postmarketOS was originally building the first way.
> > 
> > I've managed to the get the build setup for qemu-armv7. For some reason
> > I could not get past the initrd even on kernels that are supposed to work,
> > but I think that is unrelated (and not a kernel issue).
> 
> Yep, I just got qemu-arm working to drop into a debug shell for now. I have
> to look into why other things aren't behaving nicely (but that's a problem
> for later me :P). For now, it seems to demonstrate the problem nicely:
> 
> https://gitlab.postmarketos.org/postmarketOS/pmbootstrap/-/issues/2635#note_521740
> 
> 
> > On the linux-next kernel I didn't get any output on the console from qemu so I
> > think I've reproduced the issue. Changing CONFIG_RUST=n did not change the behavior.
> > 
> > So I this is almost certainly a LLVM/clang issue and not a Rust issue. I'll try to
> > do a bit more digging, but I'm not sure how much I'll get done.
> 
> Did a little more testing in addition to the testing in the gitlab issue
> mentioned above:
> 
> - Removed Rust configs from linux-next/pmos.config -> didn't boot on
> qemu-arm and my phone
> 
> - Then I removed Rust dependencies from linux-next/APKBUILD -> didn't boot
> on qemu-arm and my phone
> 
> - used linux-stable instead of linux-next -> booted on qemu-arm to a debug
> shell
> 
> linux-stable is built via gcc:
> https://gitlab.alpinelinux.org/alpine/aports/-/blob/master/community/linux-stable/APKBUILD#L179
> 
> linux-next is built via clang:
> https://gitlab.postmarketos.org/postmarketOS/pmaports/-/blob/master/device/testing/linux-next/APKBUILD#L68

It certainly seems like LLVM / clang is a factor here based on the fact
that LLVM binutils were being used with GCC based on the original report
using 'LLVM=1 CC=gcc'. A few additional ideas for narrowing this down:

  * Does this reproduce with GNU binutils + clang (i.e.,
    CROSS_COMPILE=... CC=clang)? This would further confirm that clang
    is the cuplrit since GNU binutils and GCC are confirmed working with
    linux-stable, correct?

  * Does this reproduce when linux-stable is built with clang / LLVM=1?
    This would rule out a -next specific regression as well as allow
    diffing the linux-stable GCC configuration with the clang
    configuration to see if there are any configurations that get
    enabled only with clang, which could be another reason no issue is
    seen with GCC.

  * Our continuous integration boot tests several ARM configurations in
    QEMU, including Alpine Linux's:

    https://github.com/ClangBuiltLinux/continuous-integration2/actions/runs/20379046102/job/58575229973

    So it is possible that a postmarketOS configuration option
    introduces this?

The results of that testing might give us a more obvious direction to go
for troubleshooting, especially since this appears to reproduce in QEMU,
which should make debugging in gdb possible.

Also, what version of clang is this?

Cheers,
Nathan


From cristian.ciocaltea at collabora.com  Fri Dec 19 13:27:58 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Fri, 19 Dec 2025 23:27:58 +0200
Subject: [PATCH i-g-t v3] tests: (Re)add kms_crtc_background_color test
Message-ID: <20251219-crtc-bgcolor-v3-1-31b589911588@collabora.com>

Provide test to verify the behavior of BACKGROUND_COLOR DRM CRTC
property.

This is achieved by filling a full-screen primary plane with a given
color and comparing the resulting CRC with the one obtained after
turning off all planes while having the CRTC background set to the same
color.

Also note this is a reworked version of the test that has been dropped
over 5 years ago via commit 33f07391e5f6 ("tests: Remove
kms_crtc_background_color test"), as the required kernel changes never
landed because of missing support in userland.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
This has been tested on both VKMS and the Rockchip RK3588 SoC based
Radxa ROCK 5B board.  It relies on the kernel series [1] introducing the
BACKGROUND_COLOR CRTC property and a few additional patches from [2]
enabling the required CRC functionality for the Rockchip platform.

It's worth noting CRC is only supported by the display controller (VOP2)
present in the RK3576 SoC variant.  However, the computation is done by
the hardware before applying the background color, hence it has limited
usage in IGT testing.

Luckily, the frame CRCs can be captured through DPCD, i.e. at
DisplayPort AUX channel level, hence I used the USB-C DP AltMode capable
port of the aforementioned board to perform the actual validation.

[1] https://lore.kernel.org/all/20251118-rk3588-bgcolor-v3-0-a2cc909428ea at collabora.com/
[2] https://gitlab.collabora.com/hardware-enablement/rockchip-3588/linux/-/commits/cristicc/rk3588-vop2-crc

* Test results on VKMS

virtme-ng$ IGT_FORCE_DRIVER=vkms build/tests/kms_crtc_background_color

IGT-Version: 2.2-gf50583245 (x86_64) (Linux: 6.18.0-rc5-next-20251111+ x86_64)
Using IGT_SRANDOM=1763159189 for randomisation
Opened device: /dev/dri/card0
Starting subtest: background-color-red
Starting dynamic subtest: pipe-A-Virtual-1
Dynamic subtest pipe-A-Virtual-1: SUCCESS (0.071s)
Subtest background-color-red: SUCCESS (0.072s)
Starting subtest: background-color-green
Starting dynamic subtest: pipe-A-Virtual-1
Dynamic subtest pipe-A-Virtual-1: SUCCESS (0.072s)
Subtest background-color-green: SUCCESS (0.072s)
Starting subtest: background-color-blue
Starting dynamic subtest: pipe-A-Virtual-1
Dynamic subtest pipe-A-Virtual-1: SUCCESS (0.072s)
Subtest background-color-blue: SUCCESS (0.072s)
Starting subtest: background-color-yellow
Starting dynamic subtest: pipe-A-Virtual-1
Dynamic subtest pipe-A-Virtual-1: SUCCESS (0.073s)
Subtest background-color-yellow: SUCCESS (0.073s)
Starting subtest: background-color-purple
Starting dynamic subtest: pipe-A-Virtual-1
Dynamic subtest pipe-A-Virtual-1: SUCCESS (0.073s)
Subtest background-color-purple: SUCCESS (0.073s)
Starting subtest: background-color-cyan
Starting dynamic subtest: pipe-A-Virtual-1
Dynamic subtest pipe-A-Virtual-1: SUCCESS (0.073s)
Subtest background-color-cyan: SUCCESS (0.073s)
Starting subtest: background-color-black
Starting dynamic subtest: pipe-A-Virtual-1
Dynamic subtest pipe-A-Virtual-1: SUCCESS (0.073s)
Subtest background-color-black: SUCCESS (0.073s)
Starting subtest: background-color-white
Starting dynamic subtest: pipe-A-Virtual-1
Dynamic subtest pipe-A-Virtual-1: SUCCESS (0.072s)
Subtest background-color-white: SUCCESS (0.072s)

* Test results on ROCK5B

rock5b$ cat /sys/kernel/debug/dri/1/vop2/summary

Video Port0: DISABLED
Video Port1: DISABLED
Video Port2: ACTIVE
    Connector: DP-1
	bus_format[1018]: RGB101010_1X30
	output_mode[f] color_space[0]
	background color (10bpc): r=0x0 g=0x0 b=0x0
    Display mode: 3840x2160p60
	clk[594000] real_clk[594000] type[48] flag[9]
	H: 3840 4016 4104 4400
	V: 2160 2164 2174 2250
    Cluster2-win0: ACTIVE
	win_id: 2
	format: XR24 little-endian (0x34325258) glb_alpha[0xff]
	rotate: xmirror: 0 ymirror: 0 rotate_90: 0 rotate_270: 0
	zpos: 0
	src: pos[0, 0] rect[3840 x 2160]
	dst: pos[0, 0] rect[3840 x 2160]
	buf[0]: addr: 0x0000000000000000 pitch: 15360 offset: 0

rock5b$ build/tests/kms_crtc_background_color --device drm:/dev/dri/card1

IGT-Version: 2.2-g3e4ec308e (aarch64) (Linux: 6.18.0-rc1 aarch64)
Using IGT_SRANDOM=1762774806 for randomisation
Opened device: /dev/dri/card1
Starting subtest: background-color-red
Starting dynamic subtest: pipe-C-DP-1
Dynamic subtest pipe-C-DP-1: SUCCESS (0.491s)
Subtest background-color-red: SUCCESS (0.493s)
Starting subtest: background-color-green
Starting dynamic subtest: pipe-C-DP-1
Dynamic subtest pipe-C-DP-1: SUCCESS (0.533s)
Subtest background-color-green: SUCCESS (0.535s)
Starting subtest: background-color-blue
Starting dynamic subtest: pipe-C-DP-1
Dynamic subtest pipe-C-DP-1: SUCCESS (0.541s)
Subtest background-color-blue: SUCCESS (0.544s)
Starting subtest: background-color-yellow
Starting dynamic subtest: pipe-C-DP-1
Dynamic subtest pipe-C-DP-1: SUCCESS (0.535s)
Subtest background-color-yellow: SUCCESS (0.537s)
Starting subtest: background-color-purple
Starting dynamic subtest: pipe-C-DP-1
Dynamic subtest pipe-C-DP-1: SUCCESS (0.536s)
Subtest background-color-purple: SUCCESS (0.538s)
Starting subtest: background-color-cyan
Starting dynamic subtest: pipe-C-DP-1
Dynamic subtest pipe-C-DP-1: SUCCESS (0.539s)
Subtest background-color-cyan: SUCCESS (0.541s)
Starting subtest: background-color-black
Starting dynamic subtest: pipe-C-DP-1
(kms_crtc_background_color:744) igt_pipe_crc-WARNING: Warning on condition all_zero in function crc_sanity_checks, file ../lib/igt_pipe_crc.c:475
(kms_crtc_background_color:744) igt_pipe_crc-WARNING: Suspicious CRC: All values are 0.
(kms_crtc_background_color:744) igt_pipe_crc-WARNING: Warning on condition all_zero in function crc_sanity_checks, file ../lib/igt_pipe_crc.c:475
(kms_crtc_background_color:744) igt_pipe_crc-WARNING: Suspicious CRC: All values are 0.
Dynamic subtest pipe-C-DP-1: SUCCESS (0.535s)
Subtest background-color-black: SUCCESS (0.537s)
Starting subtest: background-color-white
Starting dynamic subtest: pipe-C-DP-1
Dynamic subtest pipe-C-DP-1: SUCCESS (0.540s)
Subtest background-color-white: SUCCESS (0.542s)
---
Changes in v3:
- Added TEST & SUBTEST comment blocks to enable Intel CI testing (Kamil)
- Updated cover letter to reference a newer revision of the kernel
  series [1] which includes VKMS support
- Rebased onto latest upstream changes
  * Made igt_fixture look like an iterator
  * Made igt_main() look like normal function definition
  * Dropped igt_pipe_has_prop()
  * Replaced igt_output_set_pipe() with igt_output_set_crtc()
- Link to v2: https://lore.kernel.org/r/20251118-crtc-bgcolor-v2-1-dce4063f85a9 at collabora.com

Changes in v2:
- Added VKMS test report
- Set the value of the CRTC background color property with 16bpc instead
  of 8bpc, to avoid CRC check failures because of framebuffer format
  precision mismatch - display controller drivers shall convert it back
  from 16bpc to their internal representation of the pixel color if
  necessary, e.g. VKMS already uses 16bpc, hence no conversion is
  required in that case
- Replaced deprecated DRM_FORMAT_MOD_NONE with DRM_FORMAT_MOD_LINEAR
- Updated copyright section
- Link to v1: https://lore.kernel.org/r/20251110-crtc-bgcolor-v1-1-28669b692970 at collabora.com
---
 lib/igt_kms.c                     |   1 +
 lib/igt_kms.h                     |   3 +-
 tests/kms_crtc_background_color.c | 163 ++++++++++++++++++++++++++++++++++++++
 tests/meson.build                 |   1 +
 4 files changed, 167 insertions(+), 1 deletion(-)

diff --git a/lib/igt_kms.c b/lib/igt_kms.c
index e3e9bf9bce07..546bb3dc1047 100644
--- a/lib/igt_kms.c
+++ b/lib/igt_kms.c
@@ -718,6 +718,7 @@ const char * const igt_colorop_prop_names[IGT_NUM_COLOROP_PROPS] = {
 };
 
 const char * const igt_crtc_prop_names[IGT_NUM_CRTC_PROPS] = {
+	[IGT_CRTC_BACKGROUND] = "BACKGROUND_COLOR",
 	[IGT_CRTC_CTM] = "CTM",
 	[IGT_CRTC_GAMMA_LUT] = "GAMMA_LUT",
 	[IGT_CRTC_GAMMA_LUT_SIZE] = "GAMMA_LUT_SIZE",
diff --git a/lib/igt_kms.h b/lib/igt_kms.h
index b00884640e16..8c1ac5a545a7 100644
--- a/lib/igt_kms.h
+++ b/lib/igt_kms.h
@@ -154,7 +154,8 @@ void kmstest_restore_vt_mode(void);
 void kmstest_set_vt_text_mode(void);
 
 enum igt_atomic_crtc_properties {
-       IGT_CRTC_CTM = 0,
+       IGT_CRTC_BACKGROUND = 0,
+       IGT_CRTC_CTM,
        IGT_CRTC_GAMMA_LUT,
        IGT_CRTC_GAMMA_LUT_SIZE,
        IGT_CRTC_DEGAMMA_LUT,
diff --git a/tests/kms_crtc_background_color.c b/tests/kms_crtc_background_color.c
new file mode 100644
index 000000000000..b1859964291f
--- /dev/null
+++ b/tests/kms_crtc_background_color.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright ? 2013,2014 Intel Corporation
+ * Copyright ? 2025 Amazon.com, Inc. or its affiliates.
+ * Copyright ? 2025 Collabora, Ltd.
+ */
+
+/**
+ * TEST: crtc background color
+ * Category: Display
+ * Description: Test background color feature with CRC at CRTC
+ * Driver requirement: i915, xe
+ * Mega feature: General Display Features
+ */
+
+#include "igt.h"
+
+IGT_TEST_DESCRIPTION("Test crtc background color feature");
+
+typedef struct {
+	int drm_fd;
+	int debugfs;
+	igt_display_t display;
+} data_t;
+
+#define __DRM_ARGB64_PREP(c, shift)					\
+	(((__u64)(c) & 0xffffU) << (shift))
+
+#define DRM_ARGB64_PREP(alpha, red, green, blue)			\
+	(__DRM_ARGB64_PREP(alpha, 48) |					\
+	 __DRM_ARGB64_PREP(red,   32) |					\
+	 __DRM_ARGB64_PREP(green, 16) |					\
+	 __DRM_ARGB64_PREP(blue,   0))
+
+static void test_background(data_t *data, enum pipe pipe, igt_output_t *output,
+			    __u16 red, __u16 green, __u16 blue)
+{
+	igt_display_t *display = &data->display;
+	igt_crc_t plane_crc, bg_crc;
+	igt_pipe_crc_t *pipe_crc;
+	igt_plane_t *plane;
+	drmModeModeInfo *mode;
+	struct igt_fb fb;
+
+	igt_display_reset(display);
+
+	igt_output_set_crtc(output, igt_crtc_for_pipe(output->display, pipe));
+	mode = igt_output_get_mode(output);
+
+	plane = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+
+	/* Fill the primary plane and set the background to the same color */
+	igt_create_color_fb(data->drm_fd,
+			    mode->hdisplay, mode->vdisplay,
+			    DRM_FORMAT_XRGB8888,
+			    DRM_FORMAT_MOD_LINEAR,
+			    (double)red / 0xffff,
+			    (double)green / 0xffff,
+			    (double)blue / 0xffff,
+			    &fb);
+
+	igt_plane_set_fb(plane, &fb);
+	igt_pipe_set_prop_value(&data->display, pipe, IGT_CRTC_BACKGROUND,
+				DRM_ARGB64_PREP(0xffff, red, green, blue));
+	igt_display_commit2(&data->display, COMMIT_ATOMIC);
+
+	pipe_crc = igt_pipe_crc_new(data->drm_fd, pipe, IGT_PIPE_CRC_SOURCE_AUTO);
+	igt_pipe_crc_collect_crc(pipe_crc, &plane_crc);
+
+	/* Turn off the primary plane so that only the background is visible */
+	igt_plane_set_fb(plane, NULL);
+	igt_display_commit2(&data->display, COMMIT_ATOMIC);
+	igt_pipe_crc_collect_crc(pipe_crc, &bg_crc);
+
+	/*
+	 * The test assumes hardware is able to generate valid CRCs when setting
+	 * the background color. Some platforms, e.g. Intel, might require at
+	 * least one plane to be visible before reading the pipe-level ("dmux")
+	 * CRC. Other platforms, e.g. Rockchip, do not take background color
+	 * into account when computing CRC at CRTC level.
+	 * A possible workaround would be to use alternative CRC sources, e.g.
+	 * where computation is performed at encoder or sink level.
+	 */
+	igt_assert_crc_equal(&plane_crc, &bg_crc);
+
+	/* Clean-up */
+	igt_pipe_set_prop_value(&data->display, pipe, IGT_CRTC_BACKGROUND,
+				DRM_ARGB64_PREP(0xffff, 0, 0, 0));
+	igt_pipe_crc_free(pipe_crc);
+	igt_output_set_crtc(output, NULL);
+	igt_display_commit(display);
+	igt_remove_fb(data->drm_fd, &fb);
+}
+
+/**
+ * SUBTEST: background-color-%s
+ * Description: Tests %arg[1] in background color
+ *
+ * arg[1]:
+ *
+ * @red:      red
+ * @green:    green
+ * @blue:     blue
+ * @yellow:   yellow
+ * @purple:   purple
+ * @cyan:     cyan
+ * @black:    black
+ * @white:    white
+ */
+
+int igt_main()
+{
+	igt_output_t *output;
+	data_t data = {};
+	enum pipe pipe;
+	int i;
+
+	struct {
+		const char *color;
+		__u16 red;
+		__u16 green;
+		__u16 blue;
+	} tests[] = {
+		{ "red",    0xffff, 0x0000, 0x0000, },
+		{ "green",  0x0000, 0xffff, 0x0000, },
+		{ "blue",   0x0000, 0x0000, 0xffff, },
+		{ "yellow", 0xffff, 0xffff, 0x0000, },
+		{ "purple", 0xffff, 0x0000, 0xffff, },
+		{ "cyan",   0x0000, 0xffff, 0xffff, },
+		{ "black",  0x0000, 0x0000, 0x0000, },
+		{ "white",  0xffff, 0xffff, 0xffff, },
+	};
+
+	igt_fixture() {
+		data.drm_fd = drm_open_driver_master(DRIVER_ANY);
+
+		kmstest_set_vt_graphics_mode();
+
+		igt_display_require(&data.display, data.drm_fd);
+		igt_display_require_output(&data.display);
+		igt_require_pipe_crc(data.drm_fd);
+
+		data.debugfs = igt_debugfs_dir(data.drm_fd);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(tests); i++) {
+		igt_describe_f("Test crtc background color %s", tests[i].color);
+		igt_subtest_with_dynamic_f("background-color-%s", tests[i].color) {
+			for_each_pipe_with_single_output(&data.display, pipe, output) {
+				igt_require(data.display.pipes[pipe].props[IGT_CRTC_BACKGROUND]);
+
+				igt_dynamic_f("pipe-%s-%s", kmstest_pipe_name(pipe), output->name)
+					test_background(&data, pipe, output, tests[i].red,
+							tests[i].green, tests[i].blue);
+			}
+		}
+	}
+
+	igt_fixture() {
+		igt_display_fini(&data.display);
+		drm_close_driver(data.drm_fd);
+	}
+}
diff --git a/tests/meson.build b/tests/meson.build
index 8847070252ce..045acb5973fd 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -28,6 +28,7 @@ test_progs = [
 	'kms_concurrent',
 	'kms_colorop',
 	'kms_content_protection',
+	'kms_crtc_background_color',
 	'kms_cursor_crc',
 	'kms_cursor_edge_walk',
 	'kms_cursor_legacy',

---
base-commit: f38f4d8e9c65aff45ac807e646d06e38bc3193a2
change-id: 20251110-crtc-bgcolor-f6ed9a58e0bf



From colin.i.king at gmail.com  Fri Dec 19 13:44:28 2025
From: colin.i.king at gmail.com (Colin Ian King)
Date: Fri, 19 Dec 2025 21:44:28 +0000
Subject: [PATCH][next] scsi: ufs: host: mediatek: make read-only array scale_us static const
Message-ID: <20251219214428.492744-1-colin.i.king@gmail.com>

Don't populate the read-only array scale_us on the stack at run time,
instead make it static const.

Signed-off-by: Colin Ian King <colin.i.king at gmail.com>
---
 drivers/ufs/host/ufs-mediatek.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index ecbbf52bf734..66b11cc0703b 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -1112,7 +1112,7 @@ static void ufs_mtk_setup_clk_gating(struct ufs_hba *hba)
 	unsigned long flags;
 	u32 ah_ms = 10;
 	u32 ah_scale, ah_timer;
-	u32 scale_us[] = {1, 10, 100, 1000, 10000, 100000};
+	static const u32 scale_us[] = {1, 10, 100, 1000, 10000, 100000};
 
 	if (ufshcd_is_clkgating_allowed(hba)) {
 		if (ufshcd_is_auto_hibern8_supported(hba) && hba->ahit) {
-- 
2.51.0



From cristian.ciocaltea at collabora.com  Fri Dec 19 13:46:58 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Fri, 19 Dec 2025 23:46:58 +0200
Subject: [PATCH v4 1/4] uapi: Provide DIV_ROUND_CLOSEST()
In-Reply-To: <20251219-rk3588-bgcolor-v4-0-2ff1127ea757@collabora.com>
References: <20251219-rk3588-bgcolor-v4-0-2ff1127ea757@collabora.com>
Message-ID: <20251219-rk3588-bgcolor-v4-1-2ff1127ea757@collabora.com>

Currently DIV_ROUND_CLOSEST() is only available for the kernel via
include/linux/math.h.

Expose it to userland as well by adding __KERNEL_DIV_ROUND_CLOSEST() as
a common definition in uapi.

Additionally, ensure it allows building ISO C applications by switching
from the 'typeof' GNU extension to the ISO-friendly __typeof__.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 include/linux/math.h       | 18 +-----------------
 include/uapi/linux/const.h | 17 +++++++++++++++++
 2 files changed, 18 insertions(+), 17 deletions(-)

diff --git a/include/linux/math.h b/include/linux/math.h
index 6dc1d1d32fbc..1e8fb3efbc8c 100644
--- a/include/linux/math.h
+++ b/include/linux/math.h
@@ -89,23 +89,7 @@
 }							\
 )
 
-/*
- * Divide positive or negative dividend by positive or negative divisor
- * and round to closest integer. Result is undefined for negative
- * divisors if the dividend variable type is unsigned and for negative
- * dividends if the divisor variable type is unsigned.
- */
-#define DIV_ROUND_CLOSEST(x, divisor)(			\
-{							\
-	typeof(x) __x = x;				\
-	typeof(divisor) __d = divisor;			\
-	(((typeof(x))-1) > 0 ||				\
-	 ((typeof(divisor))-1) > 0 ||			\
-	 (((__x) > 0) == ((__d) > 0))) ?		\
-		(((__x) + ((__d) / 2)) / (__d)) :	\
-		(((__x) - ((__d) / 2)) / (__d));	\
-}							\
-)
+#define DIV_ROUND_CLOSEST __KERNEL_DIV_ROUND_CLOSEST
 /*
  * Same as above but for u64 dividends. divisor must be a 32-bit
  * number.
diff --git a/include/uapi/linux/const.h b/include/uapi/linux/const.h
index b8f629ef135f..471877322f47 100644
--- a/include/uapi/linux/const.h
+++ b/include/uapi/linux/const.h
@@ -50,4 +50,21 @@
 
 #define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
 
+/*
+ * Divide positive or negative dividend by positive or negative divisor
+ * and round to closest integer. Result is undefined for negative
+ * divisors if the dividend variable type is unsigned and for negative
+ * dividends if the divisor variable type is unsigned.
+ */
+#define __KERNEL_DIV_ROUND_CLOSEST(x, divisor)(		\
+{							\
+	__typeof__(x) __x = x;				\
+	__typeof__(divisor) __d = divisor;		\
+	(((__typeof__(x))-1) > 0 ||			\
+	 ((__typeof__(divisor))-1) > 0 ||		\
+	 (((__x) > 0) == ((__d) > 0))) ?		\
+		(((__x) + ((__d) / 2)) / (__d)) :	\
+		(((__x) - ((__d) / 2)) / (__d));	\
+}							\
+)
 #endif /* _UAPI_LINUX_CONST_H */

-- 
2.51.2



From cristian.ciocaltea at collabora.com  Fri Dec 19 13:46:57 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Fri, 19 Dec 2025 23:46:57 +0200
Subject: [PATCH v4 0/4] Introduce BACKGROUND_COLOR DRM CRTC property
Message-ID: <20251219-rk3588-bgcolor-v4-0-2ff1127ea757@collabora.com>

Some display controllers can be hardware-configured to present non-black
colors for pixels which are not covered by any plane (or are exposed
through transparent regions of higher planes).

The 1st patch of the series provides DIV_ROUND_CLOSEST() to uapi, as a
prerequisite to the 2nd patch introducing the BACKGROUND_COLOR DRM
property that can be attached to a CRTC via a dedicated helper function.
A 64-bit ARGB color value format is also defined and can be manipulated
with the help of a few utility macros.

Note this is a reworked version of the patch [1] submitted (many) years
ago by Matt Roper.  The main changes are:

* Renamed DRM_ARGB_<COMP>() to DRM_ARGB64_GET<C>_BPC() while providing
  convenience wrappers to extract all 16 bits of a specific color via
  DRM_ARGB64_GET<C>()
* Replaced drm_argb() function with DRM_ARGB64_PREP_BPC() macro, to
  improve uAPI consistency and readability; additionally fixed a bug in
  case of using bpc < 16: the unused least-significant bits of a given
  component in the output value would contain the unused
  most-significant bits of the following component in the input value,
  instead of being set to 0
* Replaced GENMASK_ULL(63, 0) with U64_MAX when calling
  drm_property_create_range() to create the BACKGROUND_COLOR property
* Moved crtc_state->bgcolor initialization from
  __drm_atomic_helper_crtc_reset() to
  __drm_atomic_helper_crtc_state_reset()
* Replaced '*bgcolor*' occurrences to '*background_color*' for
  consistency with the actual property name in both storage field and
  helper functions names

The subsequent patches add background color support to VKMS and the VOP2
display controller used in the RK3568, RK3576, and RK3588 Rockchip SoC
families.

The validation has been done using a dedicated IGT test [2] - see the
reported results below.

On the userland side, a Weston merge request [3] is available, providing
support for the BACKGROUND_COLOR CRTC property to the DRM backend.  It
relies on the already existing background-color setting in weston.ini:

  [shell]
  background-color=0xAARRGGBB

[1] https://lore.kernel.org/all/20190930224707.14904-2-matthew.d.roper at intel.com/
[2] https://lore.kernel.org/all/20251219-crtc-bgcolor-v3-1-31b589911588 at collabora.com/
[3] https://gitlab.freedesktop.org/wayland/weston/-/merge_requests/1845

IGT kms_crtc_background_color test results
==========================================

* VKMS

virtme-ng$ IGT_FORCE_DRIVER=vkms build/tests/kms_crtc_background_color

IGT-Version: 2.3-g6b07138e8 (x86_64) (Linux: 6.19.0-rc1-virtme x86_64)
Using IGT_SRANDOM=1766149634 for randomisation
Opened device: /dev/dri/card0
Starting subtest: background-color-red
Starting dynamic subtest: pipe-A-Virtual-1
Dynamic subtest pipe-A-Virtual-1: SUCCESS (0.071s)
Subtest background-color-red: SUCCESS (0.073s)
Starting subtest: background-color-green
Starting dynamic subtest: pipe-A-Virtual-1
Dynamic subtest pipe-A-Virtual-1: SUCCESS (0.074s)
Subtest background-color-green: SUCCESS (0.074s)
Starting subtest: background-color-blue
Starting dynamic subtest: pipe-A-Virtual-1
Dynamic subtest pipe-A-Virtual-1: SUCCESS (0.074s)
Subtest background-color-blue: SUCCESS (0.074s)
Starting subtest: background-color-yellow
Starting dynamic subtest: pipe-A-Virtual-1
Dynamic subtest pipe-A-Virtual-1: SUCCESS (0.072s)
Subtest background-color-yellow: SUCCESS (0.073s)
Starting subtest: background-color-purple
Starting dynamic subtest: pipe-A-Virtual-1
Dynamic subtest pipe-A-Virtual-1: SUCCESS (0.072s)
Subtest background-color-purple: SUCCESS (0.074s)
Starting subtest: background-color-cyan
Starting dynamic subtest: pipe-A-Virtual-1
Dynamic subtest pipe-A-Virtual-1: SUCCESS (0.074s)
Subtest background-color-cyan: SUCCESS (0.074s)
Starting subtest: background-color-black
Starting dynamic subtest: pipe-A-Virtual-1
Dynamic subtest pipe-A-Virtual-1: SUCCESS (0.072s)
Subtest background-color-black: SUCCESS (0.072s)
Starting subtest: background-color-white
Starting dynamic subtest: pipe-A-Virtual-1
Dynamic subtest pipe-A-Virtual-1: SUCCESS (0.073s)
Subtest background-color-white: SUCCESS (0.074s)

* Radxa ROCK 5B (RK3588)

rock5b$ build/tests/kms_crtc_background_color --device drm:/dev/dri/card1

IGT-Version: 2.2-g3e4ec308e (aarch64) (Linux: 6.18.0-rc1 aarch64)
Using IGT_SRANDOM=1762774806 for randomisation
Opened device: /dev/dri/card1
Starting subtest: background-color-red
Starting dynamic subtest: pipe-C-DP-1
Dynamic subtest pipe-C-DP-1: SUCCESS (0.491s)
Subtest background-color-red: SUCCESS (0.493s)
Starting subtest: background-color-green
Starting dynamic subtest: pipe-C-DP-1
Dynamic subtest pipe-C-DP-1: SUCCESS (0.533s)
Subtest background-color-green: SUCCESS (0.535s)
Starting subtest: background-color-blue
Starting dynamic subtest: pipe-C-DP-1
Dynamic subtest pipe-C-DP-1: SUCCESS (0.541s)
Subtest background-color-blue: SUCCESS (0.544s)
Starting subtest: background-color-yellow
Starting dynamic subtest: pipe-C-DP-1
Dynamic subtest pipe-C-DP-1: SUCCESS (0.535s)
Subtest background-color-yellow: SUCCESS (0.537s)
Starting subtest: background-color-purple
Starting dynamic subtest: pipe-C-DP-1
Dynamic subtest pipe-C-DP-1: SUCCESS (0.536s)
Subtest background-color-purple: SUCCESS (0.538s)
Starting subtest: background-color-cyan
Starting dynamic subtest: pipe-C-DP-1
Dynamic subtest pipe-C-DP-1: SUCCESS (0.539s)
Subtest background-color-cyan: SUCCESS (0.541s)
Starting subtest: background-color-black
Starting dynamic subtest: pipe-C-DP-1
(kms_crtc_background_color:744) igt_pipe_crc-WARNING: Warning on condition all_zero in function crc_sanity_checks, file ../lib/igt_pipe_crc.c:475
(kms_crtc_background_color:744) igt_pipe_crc-WARNING: Suspicious CRC: All values are 0.
(kms_crtc_background_color:744) igt_pipe_crc-WARNING: Warning on condition all_zero in function crc_sanity_checks, file ../lib/igt_pipe_crc.c:475
(kms_crtc_background_color:744) igt_pipe_crc-WARNING: Suspicious CRC: All values are 0.
Dynamic subtest pipe-C-DP-1: SUCCESS (0.535s)
Subtest background-color-black: SUCCESS (0.537s)
Starting subtest: background-color-white
Starting dynamic subtest: pipe-C-DP-1
Dynamic subtest pipe-C-DP-1: SUCCESS (0.540s)
Subtest background-color-white: SUCCESS (0.542s)

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
Changes in v4:
- Switched to simple bit-shifting approach when performing the bpc
  conversion in the vop2 driver, to avoid the expensive division since
  we shouldn't be concerned anymore about the precision (Chaoyi)
- Rebased series onto latest drm-misc-next
- Link to v3: https://lore.kernel.org/r/20251118-rk3588-bgcolor-v3-0-a2cc909428ea at collabora.com

Changes in v3:
- Added new patches:
  * uapi: Provide DIV_ROUND_CLOSEST()
  * drm/vkms: Support setting custom background color
- Improved DRM_ARGB64_{PREP|GET}*() helpers by using a conversion ratio
  for better color approximation when dealing with less than 16 bits of
  precision
- Mentioned the IGT test in the cover letter while documenting the
  validation results; also dropped references to the now useless
  modetest wrapper script and its generated report
- Rebased series onto latest drm-misc-next
- Link to v2: https://lore.kernel.org/r/20251013-rk3588-bgcolor-v2-0-25cc3810ba8c at collabora.com

Changes in v2:
- Improved uAPI consistency and readability by introducing
  DRM_ARGB64_PREP*() and DRM_ARGB64_GET*() helper macros
- Updated several code comment sections
- Referenced the counterpart Weston support in the cover letter
- Rebased series onto v6.18-rc1
- Link to v1: https://lore.kernel.org/r/20250902-rk3588-bgcolor-v1-0-fd97df91d89f at collabora.com

---
Cristian Ciocaltea (4):
      uapi: Provide DIV_ROUND_CLOSEST()
      drm: Add CRTC background color property
      drm/vkms: Support setting custom background color
      drm/rockchip: vop2: Support setting custom background color

 drivers/gpu/drm/drm_atomic_state_helper.c    |  1 +
 drivers/gpu/drm/drm_atomic_uapi.c            |  4 ++
 drivers/gpu/drm/drm_blend.c                  | 39 ++++++++++++++--
 drivers/gpu/drm/drm_mode_config.c            |  6 +++
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 13 +++++-
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.h |  4 ++
 drivers/gpu/drm/vkms/vkms_composer.c         | 10 ++++-
 drivers/gpu/drm/vkms/vkms_crtc.c             |  3 ++
 include/drm/drm_blend.h                      |  4 +-
 include/drm/drm_crtc.h                       | 12 +++++
 include/drm/drm_mode_config.h                |  5 +++
 include/linux/math.h                         | 18 +-------
 include/uapi/drm/drm_mode.h                  | 67 ++++++++++++++++++++++++++++
 include/uapi/linux/const.h                   | 17 +++++++
 14 files changed, 178 insertions(+), 25 deletions(-)
---
base-commit: 8e7460eac786c72f48c4e04ce9be692b939428ce
change-id: 20250829-rk3588-bgcolor-c1a7b9a507bc



From cristian.ciocaltea at collabora.com  Fri Dec 19 13:46:59 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Fri, 19 Dec 2025 23:46:59 +0200
Subject: [PATCH v4 2/4] drm: Add CRTC background color property
In-Reply-To: <20251219-rk3588-bgcolor-v4-0-2ff1127ea757@collabora.com>
References: <20251219-rk3588-bgcolor-v4-0-2ff1127ea757@collabora.com>
Message-ID: <20251219-rk3588-bgcolor-v4-2-2ff1127ea757@collabora.com>

Some display controllers can be hardware programmed to show non-black
colors for pixels that are either not covered by any plane or are
exposed through transparent regions of higher planes.  This feature can
help reduce memory bandwidth usage, e.g. in compositors managing a UI
with a solid background color while using smaller planes to render the
remaining content.

To support this capability, introduce the BACKGROUND_COLOR standard DRM
mode property, which can be attached to a CRTC through the
drm_crtc_attach_background_color_property() helper function.

Additionally, define a 64-bit ARGB format value to be built with the
help of a couple of dedicated DRM_ARGB64_PREP*() helpers.  Individual
color components can be extracted with desired precision using the
corresponding DRM_ARGB64_GET*() macros.

Co-developed-by: Matt Roper <matthew.d.roper at intel.com>
Signed-off-by: Matt Roper <matthew.d.roper at intel.com>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/drm_atomic_state_helper.c |  1 +
 drivers/gpu/drm/drm_atomic_uapi.c         |  4 ++
 drivers/gpu/drm/drm_blend.c               | 39 ++++++++++++++++--
 drivers/gpu/drm/drm_mode_config.c         |  6 +++
 include/drm/drm_blend.h                   |  4 +-
 include/drm/drm_crtc.h                    | 12 ++++++
 include/drm/drm_mode_config.h             |  5 +++
 include/uapi/drm/drm_mode.h               | 67 +++++++++++++++++++++++++++++++
 8 files changed, 133 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
index cee6d8fc44ad..57668f1c9460 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -75,6 +75,7 @@ __drm_atomic_helper_crtc_state_reset(struct drm_crtc_state *crtc_state,
 				     struct drm_crtc *crtc)
 {
 	crtc_state->crtc = crtc;
+	crtc_state->background_color = DRM_ARGB64_PREP(0xffff, 0, 0, 0);
 }
 EXPORT_SYMBOL(__drm_atomic_helper_crtc_state_reset);
 
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
index 7320db4b8489..db8fdfea7409 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -436,6 +436,8 @@ static int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
 					&replaced);
 		state->color_mgmt_changed |= replaced;
 		return ret;
+	} else if (property == config->background_color_property) {
+		state->background_color = val;
 	} else if (property == config->prop_out_fence_ptr) {
 		s32 __user *fence_ptr = u64_to_user_ptr(val);
 
@@ -483,6 +485,8 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc,
 		*val = (state->ctm) ? state->ctm->base.id : 0;
 	else if (property == config->gamma_lut_property)
 		*val = (state->gamma_lut) ? state->gamma_lut->base.id : 0;
+	else if (property == config->background_color_property)
+		*val = state->background_color;
 	else if (property == config->prop_out_fence_ptr)
 		*val = 0;
 	else if (property == crtc->scaling_filter_property)
diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c
index 6852d73c931c..f249af2a11af 100644
--- a/drivers/gpu/drm/drm_blend.c
+++ b/drivers/gpu/drm/drm_blend.c
@@ -191,10 +191,6 @@
  *		 plane does not expose the "alpha" property, then this is
  *		 assumed to be 1.0
  *
- * Note that all the property extensions described here apply either to the
- * plane or the CRTC (e.g. for the background color, which currently is not
- * exposed and assumed to be black).
- *
  * SCALING_FILTER:
  *     Indicates scaling filter to be used for plane scaler
  *
@@ -207,6 +203,25 @@
  *
  * Drivers can set up this property for a plane by calling
  * drm_plane_create_scaling_filter_property
+ *
+ * The property extensions described above all apply to the plane.  Drivers
+ * may also expose the following crtc property extension:
+ *
+ * BACKGROUND_COLOR:
+ *	Background color is set up with drm_crtc_attach_background_color_property(),
+ *	and expects a 64-bit ARGB value following DRM_FORMAT_ARGB16161616, as
+ *	generated by the DRM_ARGB64_PREP*() helpers. It controls the color of a
+ *	full-screen layer that exists below all planes. This color will be used
+ *	for pixels not covered by any plane and may also be blended with plane
+ *	contents as allowed by a plane's alpha values.
+ *	The background color defaults to black, and is assumed to be black for
+ *	drivers that do not expose this property. Although background color
+ *	isn't a plane, it is assumed that the color provided here undergoes the
+ *	CRTC degamma/CSC/gamma transformations applied after the planes blending.
+ *	Note that the color value includes an alpha channel, hence non-opaque
+ *	background color values are allowed, but since physically transparent
+ *	monitors do not (yet) exists, the final alpha value may not reach the
+ *	video sink or it may simply ignore it.
  */
 
 /**
@@ -621,3 +636,19 @@ int drm_plane_create_blend_mode_property(struct drm_plane *plane,
 	return 0;
 }
 EXPORT_SYMBOL(drm_plane_create_blend_mode_property);
+
+/**
+ * drm_crtc_attach_background_color_property - attach background color property
+ * @crtc: drm crtc
+ *
+ * Attaches the background color property to @crtc.  The property defaults to
+ * solid black and will accept 64-bit ARGB values in the format generated by
+ * DRM_ARGB64_PREP*() helpers.
+ */
+void drm_crtc_attach_background_color_property(struct drm_crtc *crtc)
+{
+	drm_object_attach_property(&crtc->base,
+				   crtc->dev->mode_config.background_color_property,
+				   DRM_ARGB64_PREP(0xffff, 0, 0, 0));
+}
+EXPORT_SYMBOL(drm_crtc_attach_background_color_property);
diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c
index d12db9b0bab8..dba7aa871246 100644
--- a/drivers/gpu/drm/drm_mode_config.c
+++ b/drivers/gpu/drm/drm_mode_config.c
@@ -380,6 +380,12 @@ static int drm_mode_create_standard_properties(struct drm_device *dev)
 		return -ENOMEM;
 	dev->mode_config.gamma_lut_size_property = prop;
 
+	prop = drm_property_create_range(dev, 0,
+					 "BACKGROUND_COLOR", 0, U64_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.background_color_property = prop;
+
 	prop = drm_property_create(dev,
 				   DRM_MODE_PROP_IMMUTABLE | DRM_MODE_PROP_BLOB,
 				   "IN_FORMATS", 0);
diff --git a/include/drm/drm_blend.h b/include/drm/drm_blend.h
index 88bdfec3bd88..c7e888767c81 100644
--- a/include/drm/drm_blend.h
+++ b/include/drm/drm_blend.h
@@ -31,8 +31,9 @@
 #define DRM_MODE_BLEND_COVERAGE		1
 #define DRM_MODE_BLEND_PIXEL_NONE	2
 
-struct drm_device;
 struct drm_atomic_state;
+struct drm_crtc;
+struct drm_device;
 struct drm_plane;
 
 static inline bool drm_rotation_90_or_270(unsigned int rotation)
@@ -58,4 +59,5 @@ int drm_atomic_normalize_zpos(struct drm_device *dev,
 			      struct drm_atomic_state *state);
 int drm_plane_create_blend_mode_property(struct drm_plane *plane,
 					 unsigned int supported_modes);
+void drm_crtc_attach_background_color_property(struct drm_crtc *crtc);
 #endif
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 66278ffeebd6..d99a74258d3d 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -274,6 +274,18 @@ struct drm_crtc_state {
 	 */
 	struct drm_property_blob *gamma_lut;
 
+	/**
+	 * @background_color:
+	 *
+	 * RGB value representing the pipe's background color.  The background
+	 * color (aka "canvas color") of a pipe is the color that will be used
+	 * for pixels not covered by a plane, or covered by transparent pixels
+	 * of a plane.  The value here should be built using DRM_ARGB64_PREP*()
+	 * helpers, while the individual color components can be extracted with
+	 * desired precision via the DRM_ARGB64_GET*() macros.
+	 */
+	u64 background_color;
+
 	/**
 	 * @target_vblank:
 	 *
diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h
index 895fb820dba0..14fc41da2ae6 100644
--- a/include/drm/drm_mode_config.h
+++ b/include/drm/drm_mode_config.h
@@ -832,6 +832,11 @@ struct drm_mode_config {
 	 * gamma LUT as supported by the driver (read-only).
 	 */
 	struct drm_property *gamma_lut_size_property;
+	/**
+	 * @background_color_property: Optional CRTC property to set the
+	 * background color.
+	 */
+	struct drm_property *background_color_property;
 
 	/**
 	 * @suggested_x_property: Optional connector property with a hint for
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index cbbbfc1dfe2b..dd9ef5af982f 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -27,6 +27,8 @@
 #ifndef _DRM_MODE_H
 #define _DRM_MODE_H
 
+#include <linux/const.h>
+
 #include "drm.h"
 
 #if defined(__cplusplus)
@@ -1545,6 +1547,71 @@ struct drm_mode_closefb {
 	__u32 pad;
 };
 
+/*
+ * Put 16-bit ARGB values into a standard 64-bit representation that can be
+ * used for ioctl parameters, inter-driver communication, etc.
+ *
+ * If the component values being provided contain less than 16 bits of
+ * precision, use a conversion ratio to get a better color approximation.
+ * The ratio is computed as (2^16 - 1) / (2^bpc - 1), where bpc and 16 are
+ * the input and output precision, respectively.
+ */
+#define __DRM_ARGB64_PREP(c, shift)					\
+	(((__u64)(c) & 0xffffU) << (shift))
+
+#define __DRM_ARGB64_PREP_BPC(c, shift, bpc)(				\
+{									\
+	__u16 mask = (1U << (bpc)) - 1;					\
+	__u16 conv = __KERNEL_DIV_ROUND_CLOSEST((mask & (c)) *		\
+						0xffffU, mask);		\
+	__DRM_ARGB64_PREP(conv, shift);					\
+}									\
+)
+
+#define DRM_ARGB64_PREP_BPC(alpha, red, green, blue, bpc)(		\
+{									\
+	__typeof__(bpc) __bpc = bpc;					\
+	__DRM_ARGB64_PREP_BPC(alpha, 48, __bpc) |			\
+	__DRM_ARGB64_PREP_BPC(red,   32, __bpc) |			\
+	__DRM_ARGB64_PREP_BPC(green, 16, __bpc) |			\
+	__DRM_ARGB64_PREP_BPC(blue,   0, __bpc);			\
+}									\
+)
+
+#define DRM_ARGB64_PREP(alpha, red, green, blue)			\
+	(__DRM_ARGB64_PREP(alpha, 48) |					\
+	 __DRM_ARGB64_PREP(red,   32) |					\
+	 __DRM_ARGB64_PREP(green, 16) |					\
+	 __DRM_ARGB64_PREP(blue,   0))
+
+/*
+ * Extract the specified color component from a standard 64-bit ARGB value.
+ *
+ * If the requested precision is less than 16 bits, make use of a conversion
+ * ratio calculated as (2^bpc - 1) / (2^16 - 1), where bpc and 16 are the
+ * output and input precision, respectively.
+ */
+#define __DRM_ARGB64_GET(c, shift)					\
+	((__u16)(((__u64)(c) >> (shift)) & 0xffffU))
+
+#define __DRM_ARGB64_GET_BPC(c, shift, bpc)(				\
+{									\
+	__u16 comp = __DRM_ARGB64_GET(c, shift);			\
+	__KERNEL_DIV_ROUND_CLOSEST(comp * ((1U << (bpc)) - 1),		\
+				   0xffffU);				\
+}									\
+)
+
+#define DRM_ARGB64_GETA_BPC(c, bpc)	__DRM_ARGB64_GET_BPC(c, 48, bpc)
+#define DRM_ARGB64_GETR_BPC(c, bpc)	__DRM_ARGB64_GET_BPC(c, 32, bpc)
+#define DRM_ARGB64_GETG_BPC(c, bpc)	__DRM_ARGB64_GET_BPC(c, 16, bpc)
+#define DRM_ARGB64_GETB_BPC(c, bpc)	__DRM_ARGB64_GET_BPC(c, 0, bpc)
+
+#define DRM_ARGB64_GETA(c)		__DRM_ARGB64_GET(c, 48)
+#define DRM_ARGB64_GETR(c)		__DRM_ARGB64_GET(c, 32)
+#define DRM_ARGB64_GETG(c)		__DRM_ARGB64_GET(c, 16)
+#define DRM_ARGB64_GETB(c)		__DRM_ARGB64_GET(c, 0)
+
 #if defined(__cplusplus)
 }
 #endif

-- 
2.51.2



From cristian.ciocaltea at collabora.com  Fri Dec 19 13:47:00 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Fri, 19 Dec 2025 23:47:00 +0200
Subject: [PATCH v4 3/4] drm/vkms: Support setting custom background color
In-Reply-To: <20251219-rk3588-bgcolor-v4-0-2ff1127ea757@collabora.com>
References: <20251219-rk3588-bgcolor-v4-0-2ff1127ea757@collabora.com>
Message-ID: <20251219-rk3588-bgcolor-v4-3-2ff1127ea757@collabora.com>

Make use of the BACKGROUND_COLOR CRTC property when filling the
background during blending.  It already defaults to solid black.

Since the internal representation of the pixel color in VKMS relies on
16 bits of precision, use the newly introduced DRM_ARGB64_GET{R|G|B}()
helpers to access the individual components of the background color
property, which is compliant with DRM_FORMAT_ARGB16161616.

It's worth noting the alpha component is ignored, hence non-opaque
background colors are not supported.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/vkms/vkms_composer.c | 10 ++++++++--
 drivers/gpu/drm/vkms/vkms_crtc.c     |  3 +++
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c
index 3cf3f26e0d8e..03dd1815dab8 100644
--- a/drivers/gpu/drm/vkms/vkms_composer.c
+++ b/drivers/gpu/drm/vkms/vkms_composer.c
@@ -474,8 +474,14 @@ static void blend(struct vkms_writeback_job *wb,
 {
 	struct vkms_plane_state **plane = crtc_state->active_planes;
 	u32 n_active_planes = crtc_state->num_active_planes;
-
-	const struct pixel_argb_u16 background_color = { .a = 0xffff };
+	u64 bgcolor = crtc_state->base.background_color;
+
+	const struct pixel_argb_u16 background_color = {
+		.a = 0xffff,
+		.r = DRM_ARGB64_GETR(bgcolor),
+		.g = DRM_ARGB64_GETG(bgcolor),
+		.b = DRM_ARGB64_GETB(bgcolor),
+	};
 
 	int crtc_y_limit = crtc_state->base.mode.vdisplay;
 	int crtc_x_limit = crtc_state->base.mode.hdisplay;
diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c
index 9a7db1d51022..2514c367f710 100644
--- a/drivers/gpu/drm/vkms/vkms_crtc.c
+++ b/drivers/gpu/drm/vkms/vkms_crtc.c
@@ -4,6 +4,7 @@
 
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_blend.h>
 #include <drm/drm_managed.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
@@ -228,6 +229,8 @@ struct vkms_output *vkms_crtc_init(struct drm_device *dev, struct drm_plane *pri
 
 	drm_crtc_enable_color_mgmt(crtc, 0, false, VKMS_LUT_SIZE);
 
+	drm_crtc_attach_background_color_property(crtc);
+
 	spin_lock_init(&vkms_out->lock);
 	spin_lock_init(&vkms_out->composer_lock);
 

-- 
2.51.2



From cristian.ciocaltea at collabora.com  Fri Dec 19 13:47:01 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Fri, 19 Dec 2025 23:47:01 +0200
Subject: [PATCH v4 4/4] drm/rockchip: vop2: Support setting custom
 background color
In-Reply-To: <20251219-rk3588-bgcolor-v4-0-2ff1127ea757@collabora.com>
References: <20251219-rk3588-bgcolor-v4-0-2ff1127ea757@collabora.com>
Message-ID: <20251219-rk3588-bgcolor-v4-4-2ff1127ea757@collabora.com>

The Rockchip VOP2 display controller allows configuring the background
color of each video output port.

Since a previous patch introduced the BACKGROUND_COLOR CRTC property,
which defaults to solid black, make use of it when programming the
hardware.

Note the maximum precision allowed by the display controller is 10bpc,
while the alpha component is not supported, hence ignored.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 13 ++++++++++++-
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.h |  4 ++++
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 498df0ce4680..3a232d0d4acb 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1554,6 +1554,7 @@ static void vop2_post_config(struct drm_crtc *crtc)
 	struct vop2_video_port *vp = to_vop2_video_port(crtc);
 	struct vop2 *vop2 = vp->vop2;
 	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+	u64 bgcolor = crtc->state->background_color;
 	u16 vtotal = mode->crtc_vtotal;
 	u16 hdisplay = mode->crtc_hdisplay;
 	u16 hact_st = mode->crtc_htotal - mode->crtc_hsync_start;
@@ -1599,7 +1600,11 @@ static void vop2_post_config(struct drm_crtc *crtc)
 		vop2_vp_write(vp, RK3568_VP_POST_DSP_VACT_INFO_F1, val);
 	}
 
-	vop2_vp_write(vp, RK3568_VP_DSP_BG, 0);
+	/* Background color is programmed with 10 bits of precision */
+	val = FIELD_PREP(RK3568_VP_DSP_BG__DSP_BG_RED, DRM_ARGB64_GETR(bgcolor) >> 6);
+	val |= FIELD_PREP(RK3568_VP_DSP_BG__DSP_BG_GREEN, DRM_ARGB64_GETG(bgcolor) >> 6);
+	val |= FIELD_PREP(RK3568_VP_DSP_BG__DSP_BG_BLUE, DRM_ARGB64_GETB(bgcolor) >> 6);
+	vop2_vp_write(vp, RK3568_VP_DSP_BG, val);
 }
 
 static int us_to_vertical_line(struct drm_display_mode *mode, int us)
@@ -1984,6 +1989,10 @@ static int vop2_crtc_state_dump(struct drm_crtc *crtc, struct seq_file *s)
 		   drm_get_bus_format_name(vcstate->bus_format));
 	seq_printf(s, "\toutput_mode[%x]", vcstate->output_mode);
 	seq_printf(s, " color_space[%d]\n", vcstate->color_space);
+	seq_printf(s, "\tbackground color (10bpc): r=0x%x g=0x%x b=0x%x\n",
+		   DRM_ARGB64_GETR(cstate->background_color) >> 6,
+		   DRM_ARGB64_GETG(cstate->background_color) >> 6,
+		   DRM_ARGB64_GETB(cstate->background_color) >> 6);
 	seq_printf(s, "    Display mode: %dx%d%s%d\n",
 		   mode->hdisplay, mode->vdisplay, interlaced ? "i" : "p",
 		   drm_mode_vrefresh(mode));
@@ -2473,6 +2482,8 @@ static int vop2_create_crtcs(struct vop2 *vop2)
 			return dev_err_probe(drm->dev, ret,
 					     "crtc init for video_port%d failed\n", i);
 
+		drm_crtc_attach_background_color_property(&vp->crtc);
+
 		drm_crtc_helper_add(&vp->crtc, &vop2_crtc_helper_funcs);
 		if (vop2->lut_regs) {
 			const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id];
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
index 9124191899ba..37722652844a 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
@@ -658,6 +658,10 @@ enum dst_factor_mode {
 #define RK3588_VP_CLK_CTRL__DCLK_OUT_DIV		GENMASK(3, 2)
 #define RK3588_VP_CLK_CTRL__DCLK_CORE_DIV		GENMASK(1, 0)
 
+#define RK3568_VP_DSP_BG__DSP_BG_RED			GENMASK(29, 20)
+#define RK3568_VP_DSP_BG__DSP_BG_GREEN			GENMASK(19, 10)
+#define RK3568_VP_DSP_BG__DSP_BG_BLUE			GENMASK(9, 0)
+
 #define RK3568_VP_POST_SCL_CTRL__VSCALEDOWN		BIT(1)
 #define RK3568_VP_POST_SCL_CTRL__HSCALEDOWN		BIT(0)
 

-- 
2.51.2



From cristian.ciocaltea at collabora.com  Fri Dec 19 14:33:39 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Sat, 20 Dec 2025 00:33:39 +0200
Subject: [PATCH v3 4/4] drm/rockchip: vop2: Support setting custom
 background color
In-Reply-To: <4a6443b8-d440-4921-8a43-7c20e4e265e7@collabora.com>
References: <20251118-rk3588-bgcolor-v3-0-a2cc909428ea@collabora.com>
 <20251118-rk3588-bgcolor-v3-4-a2cc909428ea@collabora.com>
 <0ed71b8d-5a2e-4213-bd2f-7ba317d1e4cb@rock-chips.com>
 <4a6443b8-d440-4921-8a43-7c20e4e265e7@collabora.com>
Message-ID: <7fb25158-5053-43d9-99df-59cab371d746@collabora.com>

On 11/28/25 11:44 AM, Cristian Ciocaltea wrote:
> Hi Chaoyi,
> 
> On 11/28/25 10:46 AM, Chaoyi Chen wrote:
>> Hello Cristian,
>>
>> On 11/18/2025 7:52 AM, Cristian Ciocaltea wrote:
>>> The Rockchip VOP2 display controller allows configuring the background
>>> color of each video output port.
>>>
>>> Since a previous patch introduced the BACKGROUND_COLOR CRTC property,
>>> which defaults to solid black, make use of it when programming the
>>> hardware.
>>>
>>> Note the maximum precision allowed by the display controller is 10bpc,
>>> while the alpha component is not supported, hence ignored.
>>>
>>> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
>>> ---
>>>  drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 13 ++++++++++++-
>>>  drivers/gpu/drm/rockchip/rockchip_drm_vop2.h |  4 ++++
>>>  2 files changed, 16 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
>>> index 498df0ce4680..87110beba366 100644
>>> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
>>> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
>>> @@ -1554,6 +1554,7 @@ static void vop2_post_config(struct drm_crtc *crtc)
>>>  	struct vop2_video_port *vp = to_vop2_video_port(crtc);
>>>  	struct vop2 *vop2 = vp->vop2;
>>>  	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
>>> +	u64 bgcolor = crtc->state->background_color;
>>>  	u16 vtotal = mode->crtc_vtotal;
>>>  	u16 hdisplay = mode->crtc_hdisplay;
>>>  	u16 hact_st = mode->crtc_htotal - mode->crtc_hsync_start;
>>> @@ -1599,7 +1600,11 @@ static void vop2_post_config(struct drm_crtc *crtc)
>>>  		vop2_vp_write(vp, RK3568_VP_POST_DSP_VACT_INFO_F1, val);
>>>  	}
>>>  
>>> -	vop2_vp_write(vp, RK3568_VP_DSP_BG, 0);
>>> +	/* Background color is programmed with 10 bits of precision */
>>> +	val = FIELD_PREP(RK3568_VP_DSP_BG__DSP_BG_RED, DRM_ARGB64_GETR_BPC(bgcolor, 10));
>>> +	val |= FIELD_PREP(RK3568_VP_DSP_BG__DSP_BG_GREEN, DRM_ARGB64_GETG_BPC(bgcolor, 10));
>>> +	val |= FIELD_PREP(RK3568_VP_DSP_BG__DSP_BG_BLUE, DRM_ARGB64_GETB_BPC(bgcolor, 10));
>>
>> Division is expensive. If we convert a 16 bpc value to 10 bpc using
>> direct bit-shifts, that is "DRM_ARGB64_GETX(bgcolor) >> 6" will
>> keep the relative error within 1 compared to DIV_ROUND_CLOSEST().
>>
>> Should we be concerned about the precision problem here?
> 
> The precision was something I initially looked into for CRC verification, in the
> context of the related IGT test.  But since I've added the VKMS support, I think
> we should not worry about that anymore. 
> 
> Moreover, as already pointed out in [1], only RK3576 supports CRC generation at
> display controller level, and that is not particularly useful because it doesn't
> take the background color into account.  Therefore I had to capture the frame
> CRCs at DisplayPort AUX channel level, by using the USB-C DP AltMode capable
> port of my RK3588-based board.  However, that solution is not yet available
> upstream, as it requires further work for cleanup and improving the overall
> USB-C reliability. 
> 
> Hence I'll move on with your suggestion and switch to the simple bit-shifting
> approach for the next revision.

Done in v4:
https://lore.kernel.org/all/20251219-rk3588-bgcolor-v4-0-2ff1127ea757 at collabora.com/



From cristian.ciocaltea at collabora.com  Fri Dec 19 14:42:05 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Sat, 20 Dec 2025 00:42:05 +0200
Subject: [PATCH v3 4/4] drm/rockchip: vop2: Support setting custom
 background color
In-Reply-To: <292ed476-2b5a-4b61-97e5-3b8d8a24c324@rock-chips.com>
References: <20251118-rk3588-bgcolor-v3-0-a2cc909428ea@collabora.com>
 <20251118-rk3588-bgcolor-v3-4-a2cc909428ea@collabora.com>
 <0ed71b8d-5a2e-4213-bd2f-7ba317d1e4cb@rock-chips.com>
 <4a6443b8-d440-4921-8a43-7c20e4e265e7@collabora.com>
 <b8819463-cc61-432f-b451-db90e3b43884@rock-chips.com>
 <058027df-1b1b-4c46-b8e1-ec53fc809e82@collabora.com>
 <292ed476-2b5a-4b61-97e5-3b8d8a24c324@rock-chips.com>
Message-ID: <012994e7-0e69-4885-8050-a404b7ae7608@collabora.com>

On 11/30/25 5:01 AM, Chaoyi Chen wrote:
> On 11/29/2025 5:50 PM, Cristian Ciocaltea wrote:
>> Hi Chaoyi,
>>
>> On 11/29/25 5:49 AM, Chaoyi Chen wrote:
>>> Hello Cristian, 
>>>
>>> On 11/28/2025 5:44 PM, Cristian Ciocaltea wrote:
>>>> The precision was something I initially looked into for CRC verification, in the
>>>> context of the related IGT test.  But since I've added the VKMS support, I think
>>>> we should not worry about that anymore. 
>>>>
>>>> Moreover, as already pointed out in [1], only RK3576 supports CRC generation at
>>>> display controller level, and that is not particularly useful because it doesn't
>>>
>>> I believe you can get the CRTC CRC on the RK3576, even when only the 
>>> background is visible and all plane is disabled. Feel free to let me
>>> know if you run into any issues :)
>>
>> Yes, CRTC CRC works on RK3576 for the planes, but not for the background, i.e.
>> the CRC is not updated when setting a different background color.  Unless
>> there's a way to change this default behavior, which I'm not aware of. 
>>
>> My current understanding is that the background color is applied at a later
>> stage in the display pipeline, *after* blending the planes and computing CRC.
>>
> 
> Which CRTC are you using? If you're using VP0, you might run into this
> problem. Please try VP1 instead.

Yeah, that's VP0 as there's only one HDMI output port on my Radxa ROCK 4D board.
I'll check if it's possible to switch to VP1.


From bwicaksono at nvidia.com  Fri Dec 19 15:13:23 2025
From: bwicaksono at nvidia.com (Besar Wicaksono)
Date: Fri, 19 Dec 2025 23:13:23 +0000
Subject: [PATCH 0/2] arm64: Support NVIDIA Olympus for Perf Arm SPE 
Message-ID: <20251219231325.2742580-1-bwicaksono@nvidia.com>

This series support NVIDIA Olympus CPU in Perf Arm SPE.
The first patch syncs the kernel header to the tools header.
The second patch adds NVIDIA Olympus into perf's Neoverse SPE data source list.

Besar Wicaksono (2):
  tools headers arm64: Add NVIDIA Olympus part
  perf arm-spe: Add NVIDIA Olympus to neoverse list

 tools/arch/arm64/include/asm/cputype.h | 2 ++
 tools/perf/util/arm-spe.c              | 1 +
 2 files changed, 3 insertions(+)

-- 
2.43.0



From bwicaksono at nvidia.com  Fri Dec 19 15:13:24 2025
From: bwicaksono at nvidia.com (Besar Wicaksono)
Date: Fri, 19 Dec 2025 23:13:24 +0000
Subject: [PATCH 1/2] tools headers arm64: Add NVIDIA Olympus part
In-Reply-To: <20251219231325.2742580-1-bwicaksono@nvidia.com>
References: <20251219231325.2742580-1-bwicaksono@nvidia.com>
Message-ID: <20251219231325.2742580-2-bwicaksono@nvidia.com>

Add the part number and MIDR for NVIDIA Olympus.

Signed-off-by: Besar Wicaksono <bwicaksono at nvidia.com>
---
 tools/arch/arm64/include/asm/cputype.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/tools/arch/arm64/include/asm/cputype.h b/tools/arch/arm64/include/asm/cputype.h
index 139d5e87dc95..45ec0d4fba71 100644
--- a/tools/arch/arm64/include/asm/cputype.h
+++ b/tools/arch/arm64/include/asm/cputype.h
@@ -129,6 +129,7 @@
 
 #define NVIDIA_CPU_PART_DENVER		0x003
 #define NVIDIA_CPU_PART_CARMEL		0x004
+#define NVIDIA_CPU_PART_OLYMPUS		0x010
 
 #define FUJITSU_CPU_PART_A64FX		0x001
 
@@ -220,6 +221,7 @@
 
 #define MIDR_NVIDIA_DENVER MIDR_CPU_MODEL(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_DENVER)
 #define MIDR_NVIDIA_CARMEL MIDR_CPU_MODEL(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_CARMEL)
+#define MIDR_NVIDIA_OLYMPUS MIDR_CPU_MODEL(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_OLYMPUS)
 #define MIDR_FUJITSU_A64FX MIDR_CPU_MODEL(ARM_CPU_IMP_FUJITSU, FUJITSU_CPU_PART_A64FX)
 #define MIDR_HISI_TSV110 MIDR_CPU_MODEL(ARM_CPU_IMP_HISI, HISI_CPU_PART_TSV110)
 #define MIDR_HISI_HIP09 MIDR_CPU_MODEL(ARM_CPU_IMP_HISI, HISI_CPU_PART_HIP09)
-- 
2.43.0



From bwicaksono at nvidia.com  Fri Dec 19 15:13:25 2025
From: bwicaksono at nvidia.com (Besar Wicaksono)
Date: Fri, 19 Dec 2025 23:13:25 +0000
Subject: [PATCH 2/2] perf arm-spe: Add NVIDIA Olympus to neoverse list
In-Reply-To: <20251219231325.2742580-1-bwicaksono@nvidia.com>
References: <20251219231325.2742580-1-bwicaksono@nvidia.com>
Message-ID: <20251219231325.2742580-3-bwicaksono@nvidia.com>

Add NVIDIA Olympus MIDR to neoverse_spe range list.

Signed-off-by: Besar Wicaksono <bwicaksono at nvidia.com>
---
 tools/perf/util/arm-spe.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c
index 71be979f5077..75208935d2c5 100644
--- a/tools/perf/util/arm-spe.c
+++ b/tools/perf/util/arm-spe.c
@@ -579,6 +579,7 @@ static const struct midr_range common_ds_encoding_cpus[] = {
 	MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2),
 	MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V1),
 	MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V2),
+	MIDR_ALL_VERSIONS(MIDR_NVIDIA_OLYMPUS),
 	{},
 };
 
-- 
2.43.0



From ckulkarnilinux at gmail.com  Fri Dec 19 15:28:58 2025
From: ckulkarnilinux at gmail.com (Chaitanya Kulkarni)
Date: Fri, 19 Dec 2025 15:28:58 -0800
Subject: [PATCH] iommu/io-pgtable-arm: fix size_t signedness bug in unmap path
Message-ID: <20251219232858.51902-1-ckulkarnilinux@gmail.com>

__arm_lpae_unmap() returns size_t but was returning -ENOENT (negative
error code) when encountering an unmapped PTE. Since size_t is unsigned,
-ENOENT (typically -2) becomes a huge positive value (0xFFFFFFFFFFFFFFFE
on 64-bit systems).

This corrupted value propagates through the call chain:
  __arm_lpae_unmap() returns -ENOENT as size_t
  -> arm_lpae_unmap_pages() returns it
  -> __iommu_unmap() adds it to iova address
  -> iommu_pgsize() triggers BUG_ON due to corrupted iova

This can cause IOVA address overflow in __iommu_unmap() loop and
trigger BUG_ON in iommu_pgsize() from invalid address alignment.

Fix by returning 0 instead of -ENOENT. The WARN_ON already signals
the error condition, and returning 0 (meaning "nothing unmapped")
is the correct semantic for size_t return type. This matches the
behavior of other io-pgtable implementations (io-pgtable-arm-v7s,
io-pgtable-dart) which return 0 on error conditions.

Fixes: 3318f7b5cefb ("iommu/io-pgtable-arm: Add quirk to quiet WARN_ON()")
Cc: stable at vger.kernel.org
Signed-off-by: Chaitanya Kulkarni <ckulkarnilinux at gmail.com>
---
 drivers/iommu/io-pgtable-arm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
index e6626004b323..05d63fe92e43 100644
--- a/drivers/iommu/io-pgtable-arm.c
+++ b/drivers/iommu/io-pgtable-arm.c
@@ -637,7 +637,7 @@ static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
 	pte = READ_ONCE(*ptep);
 	if (!pte) {
 		WARN_ON(!(data->iop.cfg.quirks & IO_PGTABLE_QUIRK_NO_WARN));
-		return -ENOENT;
+		return 0;
 	}
 
 	/* If the size matches this level, we're in the right place */
-- 
2.40.0



From olvaffe at gmail.com  Fri Dec 19 16:45:16 2025
From: olvaffe at gmail.com (Chia-I Wu)
Date: Fri, 19 Dec 2025 16:45:16 -0800
Subject: [PATCH 3/4] drm/panthor: Implement reading shader_present from nvmem
In-Reply-To: <bdf5b4f9-d6f5-419d-9465-4f722bac06ef@arm.com>
References: <20251217-mt8196-shader-present-v1-0-f6f8f3aa1e93@collabora.com>
 <20251217-mt8196-shader-present-v1-3-f6f8f3aa1e93@collabora.com> <bdf5b4f9-d6f5-419d-9465-4f722bac06ef@arm.com>
Message-ID: <CAPaKu7So4BeEyUGSS3ZAHi+Z=Sh6Kpy_W8eEtX4UQs=__MpPEA@mail.gmail.com>

On Fri, Dec 19, 2025 at 7:31?AM Steven Price <steven.price at arm.com> wrote:
>
> On 17/12/2025 17:03, Nicolas Frattaroli wrote:
> > On some platforms, notably MediaTek MT8196, the shader_present bitmask
> > in the Mali GPU register for it has cores enabled that may be faulty.
> > The true shader_present bitmask is found in an efuse instead.
> >
> > Implement reading shader_present from an nvmem cell if one is present,
> > falling back to the Mali register if it's absent. The error codes are
> > trickled up through to the probe function so that probe deferral works.
> >
> > Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
>
> Reviewed-by: Steven Price <steven.price at arm.com>
>
> [Although I really hope other vendors don't do this - the hardware is
> broken!]
>
> Although one NIT below if you respin for other reasons...
>
> > ---
> >  drivers/gpu/drm/panthor/panthor_hw.c | 63 ++++++++++++++++++++++++++++++++----
> >  1 file changed, 57 insertions(+), 6 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c
> > index 87ebb7ae42c4..eb44c8b108aa 100644
> > --- a/drivers/gpu/drm/panthor/panthor_hw.c
> > +++ b/drivers/gpu/drm/panthor/panthor_hw.c
> > @@ -1,6 +1,7 @@
> >  // SPDX-License-Identifier: GPL-2.0 or MIT
> >  /* Copyright 2025 ARM Limited. All rights reserved. */
> >
> > +#include <linux/nvmem-consumer.h>
> >  #include <drm/drm_print.h>
> >
> >  #include "panthor_device.h"
> > @@ -109,7 +110,52 @@ static char *get_gpu_model_name(struct panthor_device *ptdev)
> >       return "(Unknown Mali GPU)";
> >  }
> >
> > -static void panthor_gpu_info_init(struct panthor_device *ptdev)
> > +static int overload_shader_present(struct panthor_device *ptdev)
> > +{
> > +     struct device *dev = ptdev->base.dev;
> > +     struct nvmem_cell *cell = nvmem_cell_get(dev, "shader-present");
> > +     ssize_t len;
> > +     void *buf;
> > +     int ret;
> > +
> > +     if (IS_ERR(cell)) {
> > +             /* On platforms without this cell, use the Mali register */
> > +             if (PTR_ERR(cell) == -ENOENT)
> > +                     return 0;
> > +
> > +             return dev_err_probe(dev, PTR_ERR(cell),
> > +                                  "Failed to get shader-present nvmem cell\n");
> > +     }
> > +
> > +     buf = nvmem_cell_read(cell, &len);
> > +     if (IS_ERR(buf)) {
> > +             ret = dev_err_probe(dev, PTR_ERR(buf),
> > +                                 "Failed to read shader-present nvmem cell\n");
> > +             goto err_put_cell;
> > +     }
> > +
> > +     if (!len || len > 8) {
> > +             ret = dev_err_probe(dev, -EINVAL, "shader-present cell can't be length %ld\n",
> > +                                 len);
> > +             goto err_free;
> > +     }
> > +
> > +     memcpy(&ptdev->gpu_info.shader_present, buf, len);
When len is 4, this is neither overriding nor masking. I might suggest
switching to nvmem_cell_read_variable_le_u64 for simplicity.

Either way, Reviewed-by: Chia-I Wu <olvaffe at gmail.com>


> > +
> > +     kfree(buf);
> > +     nvmem_cell_put(cell);
> > +
> > +     return 0;
> > +
> > +err_free:
> > +     kfree(buf);
> > +err_put_cell:
> > +     nvmem_cell_put(cell);
> > +
> > +     return ret;
> > +}
>
> Rather than repeating the clean up, you can do something like:
>
> {
>         void *buf = NULL;
>         int ret = 0
>
>         if (IS_ERR(cell)) {
>                 ret = dev_err_probe(...);
>                 goto out;
>         }
>
>         buf = nvmem_cell_read();
>         if (IS_ERR(buf)) {
>                 ret = dev_err_probe(...);
>                 goto out;
>         }
>
>         if (!len || len > 8) {
>                 ret = dev_err_probe(...);
>                 goto out;
>         }
>
>         memcpy();
>
> out:
>         if (!IS_ERR(buf))
>                 kfree(buf);
>         if (!IS_ERR(cell))
>                 nvmem_cell_put(cell);
>
>         return ret;
> }
>
> That avoids mistakes when adding a new operation into the sequence. Or
> you can use the fancy new cleanup helpers, but that feels overkill here.
> But equally I'm ok if you leave the code as is - it's simple enough and
> the conversation can be done later if we need it.
>
> Thanks,
> Steve
>
> > +
> > +static int panthor_gpu_info_init(struct panthor_device *ptdev)
> >  {
> >       unsigned int i;
> >
> > @@ -143,13 +189,18 @@ static void panthor_gpu_info_init(struct panthor_device *ptdev)
> >               ptdev->gpu_info.tiler_present = gpu_read64(ptdev, GPU_TILER_PRESENT);
> >               ptdev->gpu_info.l2_present = gpu_read64(ptdev, GPU_L2_PRESENT);
> >       }
> > +
> > +     return overload_shader_present(ptdev);
> >  }
> >
> > -static void panthor_hw_info_init(struct panthor_device *ptdev)
> > +static int panthor_hw_info_init(struct panthor_device *ptdev)
> >  {
> >       u32 major, minor, status;
> > +     int ret;
> >
> > -     panthor_gpu_info_init(ptdev);
> > +     ret = panthor_gpu_info_init(ptdev);
> > +     if (ret)
> > +             return ret;
> >
> >       major = GPU_VER_MAJOR(ptdev->gpu_info.gpu_id);
> >       minor = GPU_VER_MINOR(ptdev->gpu_info.gpu_id);
> > @@ -172,6 +223,8 @@ static void panthor_hw_info_init(struct panthor_device *ptdev)
> >                "shader_present=0x%0llx l2_present=0x%0llx tiler_present=0x%0llx",
> >                ptdev->gpu_info.shader_present, ptdev->gpu_info.l2_present,
> >                ptdev->gpu_info.tiler_present);
> > +
> > +     return 0;
> >  }
> >
> >  static int panthor_hw_bind_device(struct panthor_device *ptdev)
> > @@ -218,7 +271,5 @@ int panthor_hw_init(struct panthor_device *ptdev)
> >       if (ret)
> >               return ret;
> >
> > -     panthor_hw_info_init(ptdev);
> > -
> > -     return 0;
> > +     return panthor_hw_info_init(ptdev);
> >  }
> >
>


From Thinh.Nguyen at synopsys.com  Fri Dec 19 16:57:53 2025
From: Thinh.Nguyen at synopsys.com (Thinh Nguyen)
Date: Sat, 20 Dec 2025 00:57:53 +0000
Subject: [PATCH v10 2/2] usb: dwc3: Add Google Tensor SoC DWC3 glue driver
In-Reply-To: <20251218-controller-v10-2-4047c9077274@google.com>
References: <20251218-controller-v10-0-4047c9077274@google.com>
 <20251218-controller-v10-2-4047c9077274@google.com>
Message-ID: <20251220005742.tmir3mpadnwe5rtr@synopsys.com>

On Thu, Dec 18, 2025, Roy Luo wrote:
> Add support for the DWC3 USB controller found on Google Tensor G5
> (codename: laguna). The controller features dual-role functionality
> and hibernation.
> 
> The primary focus is implementing hibernation support in host mode,
> enabling the controller to enter a low-power state (D3). This is
> particularly relevant during system power state transition and
> runtime power management for power efficiency.
> Highlights:
> - Align suspend callback with dwc3_suspend_common() for deciding
>   between a full teardown and hibernation in host mode.
> - Integration with `psw` (power switchable) and `top` power domains,
>   managing their states and device links to support hibernation.
> - A notifier callback dwc3_google_usb_psw_pd_notifier() for
>   `psw` power domain events to manage controller state
>   transitions to/from D3.
> - Coordination of the `non_sticky` reset during power state
>   transitions, asserting it on D3 entry and deasserting on D0 entry
>   in hibernation scenario.
> - Handling of high-speed and super-speed PME interrupts
>   that are generated by remote wakeup during hibernation.
> 
> Co-developed-by: Joy Chakraborty <joychakr at google.com>
> Signed-off-by: Joy Chakraborty <joychakr at google.com>
> Co-developed-by: Naveen Kumar <mnkumar at google.com>
> Signed-off-by: Naveen Kumar <mnkumar at google.com>
> Reviewed-by: Peter Griffin <peter.griffin at linaro.org>
> Signed-off-by: Roy Luo <royluo at google.com>
> ---
>  MAINTAINERS                    |   1 +
>  drivers/usb/dwc3/Kconfig       |  11 +
>  drivers/usb/dwc3/Makefile      |   1 +
>  drivers/usb/dwc3/dwc3-google.c | 628 +++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 641 insertions(+)
> 

Acked-by: Thinh Nguyen <Thinh.Nguyen at synopsys.com>

BR,
Thinh

From olvaffe at gmail.com  Fri Dec 19 17:04:22 2025
From: olvaffe at gmail.com (Chia-I Wu)
Date: Fri, 19 Dec 2025 17:04:22 -0800
Subject: [PATCH 4/4] pmdomain: mediatek: mtk-mfg: Expose shader_present as
 nvmem cell
In-Reply-To: <20251217-mt8196-shader-present-v1-4-f6f8f3aa1e93@collabora.com>
References: <20251217-mt8196-shader-present-v1-0-f6f8f3aa1e93@collabora.com> <20251217-mt8196-shader-present-v1-4-f6f8f3aa1e93@collabora.com>
Message-ID: <CAPaKu7TVeaEFRWBt7rF_uVUyYO72GHqFwKi7D52juPTRAk7URw@mail.gmail.com>

On Wed, Dec 17, 2025 at 9:04?AM Nicolas Frattaroli
<nicolas.frattaroli at collabora.com> wrote:
>
> Implement nvmem-provider functionality in mtk-mfg-pmdomain, such that it
> can expose its GF_REG_SHADER_PRESENT value in the shared memory as an
> nvmem cell for panthor.
>
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
> ---
>  drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c | 57 ++++++++++++++++++++++++++++
>  1 file changed, 57 insertions(+)
>
> diff --git a/drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c b/drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c
> index 9bad577b3ae4..725ebc678f1b 100644
> --- a/drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c
> +++ b/drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c
> @@ -10,6 +10,7 @@
>  #include <linux/clk-provider.h>
>  #include <linux/container_of.h>
>  #include <linux/iopoll.h>
> +#include <linux/nvmem-provider.h>
>  #include <linux/mailbox_client.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
> @@ -872,6 +873,58 @@ static int mtk_mfg_init_clk_provider(struct mtk_mfg *mfg)
>         return 0;
>  }
>
> +static int mtk_mfg_read_nvmem(void *priv, unsigned int offset, void *val, size_t bytes)
> +{
> +       struct mtk_mfg *mfg = priv;
> +       u32 *buf = val;
> +
> +       if (bytes != 4)
> +               return -EINVAL;
> +
> +       if (!mfg->shared_mem)
> +               return -ENODEV;
> +
> +       if (offset + bytes >= mfg->shared_mem_size)
> +               return -EINVAL;
> +
> +       *buf = readl(mfg->shared_mem + offset);
> +
> +       return 0;
> +}
> +
> +static int mtk_mfg_init_nvmem_provider(struct mtk_mfg *mfg)
> +{
> +       struct device *dev = &mfg->pdev->dev;
> +       struct nvmem_cell_info cell = {};
> +       struct nvmem_config config = {};
> +       struct nvmem_device *nvdev;
> +       int ret;
> +
> +       config.reg_read = mtk_mfg_read_nvmem;
> +       config.dev = dev;
> +       config.read_only = true;
> +       config.priv = mfg;
> +       config.size = 4;
> +       config.word_size = 4;
> +
> +       nvdev = devm_nvmem_register(dev, &config);
> +       of_node_put(config.of_node);
This looks like a dead line.
> +       if (IS_ERR(nvdev))
> +               return dev_err_probe(dev, PTR_ERR(nvdev), "Couldn't register nvmem provider\n");
> +
> +       cell.name = "shader-present";
> +       cell.offset = GF_REG_SHADER_PRESENT;
> +       cell.bytes = 4;
> +       cell.np = of_get_child_by_name(dev->of_node, cell.name);
> +
> +       ret = nvmem_add_one_cell(nvdev, &cell);
> +       /* cell.np purposefully not put as nvmem_add_one_cell does not increase refcount */
I think you still need to of_node_put on errors.
> +       if (ret)
> +               return dev_err_probe(dev, ret, "Couldn't add cell %s\n", cell.name);
> +
> +       return 0;
> +}
> +
>  static int mtk_mfg_probe(struct platform_device *pdev)
>  {
>         struct mtk_mfg *mfg;
> @@ -984,6 +1037,10 @@ static int mtk_mfg_probe(struct platform_device *pdev)
>         if (ret)
>                 goto err_power_off;
>
> +       ret = mtk_mfg_init_nvmem_provider(mfg);
> +       if (ret)
> +               goto err_power_off;
> +
>         ret = of_genpd_add_provider_simple(dev->of_node, &mfg->pd);
>         if (ret) {
>                 dev_err_probe(dev, ret, "Failed to add pmdomain provider\n");
>
> --
> 2.52.0
>


From chrisi.schrefl at gmail.com  Fri Dec 19 17:19:38 2025
From: chrisi.schrefl at gmail.com (Christian Schrefl)
Date: Sat, 20 Dec 2025 02:19:38 +0100
Subject: ARMv7 Linux + Rust doesn't boot when compiling with only LLVM=1
In-Reply-To: <20251219211147.GA1407372@ax162>
References: <1286af8e-f908-45db-af7c-d9c5d592abfd@gmail.com>
 <0705db10-3cbb-4958-a116-112457f9af6c@gmail.com>
 <1910f4b6-db74-4c86-9010-28ab4462c5a7@gmail.com>
 <20251219211147.GA1407372@ax162>
Message-ID: <0169d4f7-1a31-4ec6-a456-a6dfe2d99886@gmail.com>

On 12/19/25 10:11 PM, Nathan Chancellor wrote:
> Hi Rudraksha,
> 
> On Wed, Dec 17, 2025 at 02:21:11AM -0800, Rudraksha Gupta wrote:
>> On 12/16/25 06:41, Christian Schrefl wrote:
>>> On 12/14/25 12:54 AM, Rudraksha Gupta wrote:
>>>> Hello all,
>>>>
>>>>
>>>> I have the following problem: https://gitlab.postmarketos.org/postmarketOS/pmbootstrap/-/issues/2635
>>>>
>>>>
>>>> In short, what is happening is the following:
>>>>
>>>>
>>>> - The kernel boots and outputs via UART when I build the kernel with the following:
>>>>
>>>> make LLVM=1 ARCH="$arm" CC="${CC:-gcc}"
>>>>
>>>>
>>>> - The kernel doesn't boot and there is no output via UART when I build the kernel with the following:
>>>>
>>>> make LLVM=1 ARCH="$arm"
>>>>
>>>>
>>>> The only difference being:?CC="${CC:-gcc}". Is this expected? I think this was present in the Linux kernel ever since Rust was enabled for ARMv7, and I never encountered it because postmarketOS was originally building the first way.
>>>
>>> I've managed to the get the build setup for qemu-armv7. For some reason
>>> I could not get past the initrd even on kernels that are supposed to work,
>>> but I think that is unrelated (and not a kernel issue).
>>
>> Yep, I just got qemu-arm working to drop into a debug shell for now. I have
>> to look into why other things aren't behaving nicely (but that's a problem
>> for later me :P). For now, it seems to demonstrate the problem nicely:
>>
>> https://gitlab.postmarketos.org/postmarketOS/pmbootstrap/-/issues/2635#note_521740
>>
>>
>>> On the linux-next kernel I didn't get any output on the console from qemu so I
>>> think I've reproduced the issue. Changing CONFIG_RUST=n did not change the behavior.
>>>
>>> So I this is almost certainly a LLVM/clang issue and not a Rust issue. I'll try to
>>> do a bit more digging, but I'm not sure how much I'll get done.
>>
>> Did a little more testing in addition to the testing in the gitlab issue
>> mentioned above:
>>
>> - Removed Rust configs from linux-next/pmos.config -> didn't boot on
>> qemu-arm and my phone
>>
>> - Then I removed Rust dependencies from linux-next/APKBUILD -> didn't boot
>> on qemu-arm and my phone
>>
>> - used linux-stable instead of linux-next -> booted on qemu-arm to a debug
>> shell
>>
>> linux-stable is built via gcc:
>> https://gitlab.alpinelinux.org/alpine/aports/-/blob/master/community/linux-stable/APKBUILD#L179
>>
>> linux-next is built via clang:
>> https://gitlab.postmarketos.org/postmarketOS/pmaports/-/blob/master/device/testing/linux-next/APKBUILD#L68
> 
> It certainly seems like LLVM / clang is a factor here based on the fact
> that LLVM binutils were being used with GCC based on the original report
> using 'LLVM=1 CC=gcc'. A few additional ideas for narrowing this down:
> 
>   * Does this reproduce with GNU binutils + clang (i.e.,
>     CROSS_COMPILE=... CC=clang)? This would further confirm that clang
>     is the cuplrit since GNU binutils and GCC are confirmed working with
>     linux-stable, correct?
> 
>   * Does this reproduce when linux-stable is built with clang / LLVM=1?
>     This would rule out a -next specific regression as well as allow
>     diffing the linux-stable GCC configuration with the clang
>     configuration to see if there are any configurations that get
>     enabled only with clang, which could be another reason no issue is
>     seen with GCC.
> 
>   * Our continuous integration boot tests several ARM configurations in
>     QEMU, including Alpine Linux's:
> 
>     https://github.com/ClangBuiltLinux/continuous-integration2/actions/runs/20379046102/job/58575229973
> 
>     So it is possible that a postmarketOS configuration option
>     introduces this?
> 
> The results of that testing might give us a more obvious direction to go
> for troubleshooting, especially since this appears to reproduce in QEMU,
> which should make debugging in gdb possible.

I've found the issue (at least on qemu), it was just that the driver for
the PL011 serial was not included in the config.

I don't know why Rudraksha would have observed any difference disabling
Rust or clang though.
Maybe it's an entirely different issue on Hardware?

> 
> Also, what version of clang is this?
>

Alpine clang version 21.1.8

Cheers,
Christian



From robh at kernel.org  Fri Dec 19 17:58:17 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Fri, 19 Dec 2025 19:58:17 -0600
Subject: [PATCH 1/4] dt-bindings: gpu: mali-valhall-csf: Add
 shader-present nvmem cell
In-Reply-To: <20251217-mt8196-shader-present-v1-1-f6f8f3aa1e93@collabora.com>
References: <20251217-mt8196-shader-present-v1-0-f6f8f3aa1e93@collabora.com>
 <20251217-mt8196-shader-present-v1-1-f6f8f3aa1e93@collabora.com>
Message-ID: <176619589672.357311.747766699419646929.robh@kernel.org>


On Wed, 17 Dec 2025 18:03:27 +0100, Nicolas Frattaroli wrote:
> On the MediaTek MT8196 SoC, the bitmask for which shader cores are
> present and functional is not the one in the Mali GPU's registers, but
> in an external efuse.
> 
> Add the nvmem cell properties to describe such a setup, and make them
> required on MT8196.
> 
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
> ---
>  .../devicetree/bindings/gpu/arm,mali-valhall-csf.yaml      | 14 ++++++++++++++
>  1 file changed, 14 insertions(+)
> 

Reviewed-by: Rob Herring (Arm) <robh at kernel.org>



From robh at kernel.org  Fri Dec 19 17:59:48 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Fri, 19 Dec 2025 19:59:48 -0600
Subject: [PATCH 2/4] dt-bindings: power: mt8196-gpufreq: Describe nvmem
 provider ability
In-Reply-To: <20251217-mt8196-shader-present-v1-2-f6f8f3aa1e93@collabora.com>
References: <20251217-mt8196-shader-present-v1-0-f6f8f3aa1e93@collabora.com>
 <20251217-mt8196-shader-present-v1-2-f6f8f3aa1e93@collabora.com>
Message-ID: <176619598779.359396.11418181120053228697.robh@kernel.org>


On Wed, 17 Dec 2025 18:03:28 +0100, Nicolas Frattaroli wrote:
> On the MediaTek MT8196 SoC, the Mali GPU's "shader_present" hardware
> register may also include a non-functional shader core, along with the
> present shader cores. An efuse elsewhere in the SoC provides the
> shader_present mask with the fused off core omitted.
> 
> However, the efuse address is not publicly disclosed. What is known
> though is that the GPUEB MCU reads this efuse, and exposes its contents
> in the memory it shares with the application processor.
> 
> We can therefore describe the mediatek,mt8196-gpufreq device as being an
> nvmem provider for this purpose, as it does provide nvmem access in an
> indirect way.
> 
> The shader-present child node is left out of the list of required
> properties as we may one day be able to describe the actual efuse region
> this value comes from, so the gpufreq device isn't necessarily the only
> device that can provide this cell, and implementations shouldn't need to
> implement this functionality once this is the case.
> 
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
> ---
>  .../devicetree/bindings/power/mediatek,mt8196-gpufreq.yaml  | 13 +++++++++++++
>  1 file changed, 13 insertions(+)
> 

Reviewed-by: Rob Herring (Arm) <robh at kernel.org>



From robh at kernel.org  Fri Dec 19 18:04:12 2025
From: robh at kernel.org (Rob Herring)
Date: Fri, 19 Dec 2025 20:04:12 -0600
Subject: [PATCH 1/6] dt-bindings: clk: rs9: add clock-output-names
 property
In-Reply-To: <3357591.tdWV9SEqCh@steina-w>
References: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
 <20251218152058.1521806-2-alexander.stein@ew.tq-group.com>
 <CAMuHMdWEJ-eYwUTnotsTVEtKrujYVsEB4kFVjRYh3wXZvyjfGQ@mail.gmail.com>
 <3357591.tdWV9SEqCh@steina-w>
Message-ID: <20251220020412.GA361483-robh@kernel.org>

On Fri, Dec 19, 2025 at 09:09:23AM +0100, Alexander Stein wrote:
> Am Donnerstag, 18. Dezember 2025, 16:26:10 CET schrieb Geert Uytterhoeven:
> > Hi Alexander,
> > 
> > On Thu, 18 Dec 2025 at 16:21, Alexander Stein
> > <alexander.stein at ew.tq-group.com> wrote:
> > > Add "clock-output-names" which is a standard property for clock
> > > providers.
> > 
> > Why? Isn't that property sort of deprecated?
> 
> It is? Oh, I wasn't aware of that. Maybe the property should be
> marked deprecated in dt schema then.

I knew it was pointless, but not deprecated... I guess not much 
difference.

Rob


From robh at kernel.org  Fri Dec 19 18:06:59 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Fri, 19 Dec 2025 20:06:59 -0600
Subject: [PATCH 4/6] dt-bindings: arm: fsl: add bindings for TQMa8x
In-Reply-To: <20251218152058.1521806-5-alexander.stein@ew.tq-group.com>
References: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
 <20251218152058.1521806-5-alexander.stein@ew.tq-group.com>
Message-ID: <176619641876.374149.1170239999077862047.robh@kernel.org>


On Thu, 18 Dec 2025 16:20:51 +0100, Alexander Stein wrote:
> TQMa8x is a SOM family using NXP i.MX8QM CPU family
> MBa8x is an evaluation mainboard for this SOM.
> 
> Signed-off-by: Markus Niebel <Markus.Niebel at tq-group.com>
> Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
> ---
>  Documentation/devicetree/bindings/arm/fsl.yaml | 10 ++++++++++
>  1 file changed, 10 insertions(+)
> 

Reviewed-by: Rob Herring (Arm) <robh at kernel.org>



From baolin.wang at linux.alibaba.com  Fri Dec 19 20:29:11 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Sat, 20 Dec 2025 12:29:11 +0800
Subject: [PATCH v3 1/5] mm: rmap: support batched checks of the references
 for large folios
In-Reply-To: <aUV4u9pOHxvQiDcP@casper.infradead.org>
References: <cover.1766121341.git.baolin.wang@linux.alibaba.com>
 <24b9d33acad627997febe9b61d398fc53739a333.1766121341.git.baolin.wang@linux.alibaba.com>
 <x2s3l56rqwgcpkhpu77pjt65tfwgmchuy4fuyrj7h7uag5gja3@c3jbws4quxrd>
 <aUV4u9pOHxvQiDcP@casper.infradead.org>
Message-ID: <17b923c4-48cc-45f0-93fe-84a13568c1bf@linux.alibaba.com>



On 2025/12/20 00:09, Matthew Wilcox wrote:
> On Fri, Dec 19, 2025 at 10:47:52AM -0500, Liam R. Howlett wrote:
>>> -#define ptep_clear_flush_young_notify(__vma, __address, __ptep)		\
>>> +#define ptep_clear_flush_young_notify(__vma, __address, __ptep, __nr)	\
>>>   ({									\
>>>   	int __young;							\
>>>   	struct vm_area_struct *___vma = __vma;				\
>>>   	unsigned long ___address = __address;				\
>>> -	__young = ptep_clear_flush_young(___vma, ___address, __ptep);	\
>>> +	unsigned int ___nr = __nr;					\
>>> +	__young = clear_flush_young_ptes(___vma, ___address, __ptep, ___nr);	\
>>>   	__young |= mmu_notifier_clear_flush_young(___vma->vm_mm,	\
>>>   						  ___address,		\
>>>   						  ___address +		\
>>> -							PAGE_SIZE);	\
>>> +						nr * PAGE_SIZE);	\
>>
>> Did you mean nr * PAGE_SIZE here?  I think it should be __nr or ___nr?
>> I think this nr variable works because it exists where this macro is
>> expanded?
> 
> Yes, this should clearly be ___nr.

Ah, yes, my mistake. Thanks for pointing it out. Will fix.

> 
>> I am also not sure why you have ___nr  at all?
> 
> It's a macro cleanliness thing.  Imagine that we have a caller:
> 
> 	a = ptep_clear_flush_young_notify(vma, addr, ptep, nr++);
> 
> If you have two references to the __nr macro argument, then you end up
> incrementing nr twice.  Assigning __nr to ___nr and then referring to
> ___nr within the macro prevents this.

Yes.

> That said, I'm not sure why ptep_clear_flush_young_notify() needs
> to be a macro instead of a static inline?

Lorenzo also mentioned this. I'll clean up these macros in a follow-up 
after this patchset. Thanks.


From mikhail.kshevetskiy at iopsys.eu  Fri Dec 19 21:34:29 2025
From: mikhail.kshevetskiy at iopsys.eu (Mikhail Kshevetskiy)
Date: Sat, 20 Dec 2025 08:34:29 +0300
Subject: [PATCH RESEND v2 1/2] ARM: dts: airoha: en7523: add node to support spinand flashes
In-Reply-To: <20251220053431.288158-1-mikhail.kshevetskiy@iopsys.eu>
References: <20251220053431.288158-1-mikhail.kshevetskiy@iopsys.eu>
Message-ID: <20251220053431.288158-2-mikhail.kshevetskiy@iopsys.eu>

Add SNAND node to enable support of attached SPI-NAND on the EN7523 SoC.

Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy at iopsys.eu>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
---
 arch/arm/boot/dts/airoha/en7523.dtsi | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/arch/arm/boot/dts/airoha/en7523.dtsi b/arch/arm/boot/dts/airoha/en7523.dtsi
index b523a868c4ad..31191b8d1430 100644
--- a/arch/arm/boot/dts/airoha/en7523.dtsi
+++ b/arch/arm/boot/dts/airoha/en7523.dtsi
@@ -203,4 +203,24 @@ pcie_intc1: interrupt-controller {
 			#interrupt-cells = <1>;
 		};
 	};
+
+	spi_ctrl: spi at 1fa10000 {
+		compatible = "airoha,en7523-snand", "airoha,en7581-snand";
+		reg = <0x1fa10000 0x140>,
+		      <0x1fa11000 0x160>;
+
+		clocks = <&scu EN7523_CLK_SPI>;
+		clock-names = "spi";
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		nand: nand at 0 {
+			compatible = "spi-nand";
+			reg = <0>;
+			spi-max-frequency = <50000000>;
+			spi-tx-bus-width = <1>;
+			spi-rx-bus-width = <2>;
+		};
+	};
 };
-- 
2.51.0



From mikhail.kshevetskiy at iopsys.eu  Fri Dec 19 21:34:28 2025
From: mikhail.kshevetskiy at iopsys.eu (Mikhail Kshevetskiy)
Date: Sat, 20 Dec 2025 08:34:28 +0300
Subject: [PATCH RESEND v2 0/2] ARM: dts: airoha: en7523: update dts
Message-ID: <20251220053431.288158-1-mikhail.kshevetskiy@iopsys.eu>

These two patches updates dts for en7523 SoC with the recently (linux-6.19)
added features:
 * reset controller support
 * spinand flashes support

Unfortunately none of these changes will be activated without dts change.

Initially these patches were parts of the following series:

  https://lore.kernel.org/lkml/20251012121707.2296160-1-mikhail.kshevetskiy at iopsys.eu/
  https://lore.kernel.org/lkml/20251017201126.493496-1-mikhail.kshevetskiy at iopsys.eu/

All other patches (except patches from this series) were already merged
to upsrtream linux. This series just groups remaining patches together.

The series was resend because of no any activity for almost 2 weeks.
If it's possible, I'd like to see these changes being merged to linux-6.19
before its final release.

Changes v2:
 * update cover letter
 * update patches description a bit

Mikhail Kshevetskiy (2):
  ARM: dts: airoha: en7523: add node to support spinand flashes
  ARM: dts: airoha: en7523: add reset-controller support

 arch/arm/boot/dts/airoha/en7523.dtsi | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

-- 
2.51.0



From mikhail.kshevetskiy at iopsys.eu  Fri Dec 19 21:34:30 2025
From: mikhail.kshevetskiy at iopsys.eu (Mikhail Kshevetskiy)
Date: Sat, 20 Dec 2025 08:34:30 +0300
Subject: [PATCH RESEND v2 2/2] ARM: dts: airoha: en7523: add reset-controller support
In-Reply-To: <20251220053431.288158-1-mikhail.kshevetskiy@iopsys.eu>
References: <20251220053431.288158-1-mikhail.kshevetskiy@iopsys.eu>
Message-ID: <20251220053431.288158-3-mikhail.kshevetskiy@iopsys.eu>

This patch updates EN7523 dtsi to reflect the reset-controller
support for EN7523 SoC.

Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy at iopsys.eu>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
---
 arch/arm/boot/dts/airoha/en7523.dtsi | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/boot/dts/airoha/en7523.dtsi b/arch/arm/boot/dts/airoha/en7523.dtsi
index 31191b8d1430..115cc44093ab 100644
--- a/arch/arm/boot/dts/airoha/en7523.dtsi
+++ b/arch/arm/boot/dts/airoha/en7523.dtsi
@@ -4,6 +4,7 @@
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/clock/en7523-clk.h>
+#include <dt-bindings/reset/airoha,en7523-reset.h>
 
 / {
 	interrupt-parent = <&gic>;
@@ -91,6 +92,7 @@ scu: system-controller at 1fa20000 {
 		reg = <0x1fa20000 0x400>,
 		      <0x1fb00000 0x1000>;
 		#clock-cells = <1>;
+		#reset-cells = <1>;
 	};
 
 	gic: interrupt-controller at 9000000 {
-- 
2.51.0



From peter.griffin at linaro.org  Sat Dec 20 01:05:38 2025
From: peter.griffin at linaro.org (Peter Griffin)
Date: Sat, 20 Dec 2025 09:05:38 +0000
Subject: [PATCH v6 0/4] Implement hardware automatic clock gating (HWACG)
 for gs101
Message-ID: <20251220-automatic-clocks-v6-0-36c2f276a135@linaro.org>

Hi folks,

This series addresses an issue with Samsung Exynos based upstream clock driver
whereby the upstream clock driver sets all the clock gates into "manual mode"
(which uses a bit that is documented as reserved in the gate registers).

Another issue with the current "manual clock gating" approach upstream is
there are many bus/interconnect clocks whose relationships to the IPs
are not well documented or defined in the specs. When adding a new CMU until
now we have tried to label these clocks appropriately with CLK_IS_CRITICAL and
CLK_IGNORE_UNUSED but doing so is both error prone and time consuming. If
your lucky disabling a critical bus clock causes an immediate hang. Other
clocks however aren't so obvious and show up through random instability
some period of time later.

Fortunately each CMU (at least on newer Exynos) provides a "hardware
automatic clock gating" HWACG feature that is used by the downstream
Samsung clock drivers. Hardware automatic clock gating uses a hardware
interface between the CMU and IP to control all clocks required by the
IP. This interface is called Q-channel, and is part of the Arm AMBA low
power interface specification [1].

The advantage of using this Qchannel hardware interface for
enabling/disabling the clocks is that it takes care of all clocks
(including bus/interconnect) ones for the IP automatically thereby reducing
the dynamic power.

Whilst each clock component (GATE, MUX, DIV, QCH etc) has a HWACG enable
bit there are also some "global enable override" bits for the entire CMU in
the CMU_CONTROLLER_OPTION register.

This series makes use of those "global enable" override bits to enable auto
clock mode for the entire CMU and every component within it. Through
experimentation we can see that setting the "manual mode" reserved gate bit
on a particular gate register overides the global enable bits. So the code
is updated accordingly not to do that.

Auto clock mode has been implemented as a "opt in" by setting a new
auto_clock_gate flag in the CMU static data. The intention is existing
platforms in manual mode should not be effected by any of these changes.

If auto_clock_mode flag is set and the option_offset field is specified
then the global enable override bits will be written for the
CMU (to avoid relying on any prior bootstage configuration). Again if auto
mode is enabled the code no longer sets MANUAL and clears HWACG bits on
each gate register.

To ensure compatibility with older DTs (that specified an incorrect CMU
size) the resource size is checked and the driver falls back to manual
clock gate mode in such cases. As the CLK_IGNORE_UNUSED and CLK_IS_CRITICAL
flags are required for manual clock gate mode, the patch removing these
flags has been dropped from v2. I tested with an old DT and we successfully
switch to manual clock gate mode and the system correctly boots.

To have dynamic root clock gating (drcg) of bus components and memclk
enabled, it is required to set the bus_component_drcg and memclk registers
in the correspondingly named sysreg controller. If auto clock mode is
enabled the clock driver will now attempt to get the sysreg syscon via the
samsung,sysreg property (as used by other Exynos drivers upstream) and set
the registers accordingly. The suspend/resume code paths are also updated
to handle saving/restoring registers using a regmap. Note cmu_top is an
exception and does not have a corresondingly named sysreg_top.

As all clock gates are currently exposed in the gs101 drivers and DT, we
continue to register all of these gates in auto clock mode, but with some new
samsung_auto_clk_gate_ops. As clk enable and clk disable are now handled by
Q-channel interface the .enable and .disable implementations are
no-ops. However by using some CMU qchannel debug registers we can report
the current clock status (enabled or disabled) of every clock gate in the
system. This has the nice effect of still being able to dump the entire
clock tree from /sys/kernel/debug/clk/clk_summary and see a live view of
every auto clock in the system.

With the infrastructure in place, all the CMUs registered in clk-gs101 are
now updated to enable auto clock mode. From dumping
/sys/kernel/debug/clk/clk_summary it is possible to see that after enabling
auto clock mode approximately 305 clocks are enabled, and 299 are now
disabled. This number goes up and down a bit by 3-5 clocks just on a idle
system sat at a console.

With auto clock mode enabled it is now also possible to boot without the
clk_ignore_unused kernel command line property for the first time!

For future CMUs in gs101 I propose we continue to expose all gates, but
register the CMU in "auto mode". For new device drivers or updates to
existing dt bindings related to clocks to support gs101 I suggest we only
use the "obviously correct" clock(s). By "obviously correct" I mean a clock
has the IP name in the clock register name, but not try to deduce other
obsucurely named bus/interconnect clocks which will now all be handled
automatically. Note it is still possible to test whether the "obviously
correct" clock is indeed correct by putting the individual gate in manual
mode and disabling the clock (e.g. by using devmem).

Note: As everything here will go via one of Krzysztof's trees I've sent it
as one series.

regards,

Peter

[1] https://documentation-service.arm.com/static/5f915e69f86e16515cdc3b3e?token=

Signed-off-by: Peter Griffin <peter.griffin at linaro.org>
---
Changes in v6:
- Rebased onto next-20251219 (Krzysztof)
- NOTE: linux-next has a regression atm 
  24ec03cc5512 ("serial: core: Restore sysfs fwnode information") needs to be
  reverted for boot testing this series on Pixel 6.
- Link to v5: https://lore.kernel.org/r/20251114-automatic-clocks-v5-0-efb9202ffcd7 at linaro.org

Changes in v5:
- Invert the test in dt-bindings: clock: google,gs101-clock (Andre)
- Link to v4: https://lore.kernel.org/r/20251110-automatic-clocks-v4-0-8f46929f50b7 at linaro.org

Changes in v4:
- Update commit description with additional requested details (Krzysztof)
- Remove unnecessary header of_address.h (Peter)
- Link to v3: https://lore.kernel.org/r/20251102-automatic-clocks-v3-0-ff10eafe61c8 at linaro.org

Changes in v3:
- Add missing 'np' func param to kerneldoc in samsung_cmu_register_clocks
(0-DAY CI )
- Link to v2: https://lore.kernel.org/r/20251029-automatic-clocks-v2-0-f8edd3a2d82b at linaro.org

Changes in v2:
- Rebased onto next-20251024
- Fallback to manual clock gate mode for old DTs with incorrect CMU reg
  size (added samsung_is_auto_capable(). Tested with old DT and it works as
  expected. It does require keeping all the CLK_IS_CRITICAL
  CLK_IGNORE_UNUSED flags in clk-gs101 so patch removing those is
  dropped. (Krzysztof)
- Rename OPT_UNKNOWN bit to OPT_EN_LAYER2_CTRL (Andre)
- Rename OPT_EN_MEM_PM_GATING to OPT_EN_MEM_PWR_GATING (Peter)
- Reverse Option bit definitions LSB -> MSB (Krzysztof)
- Update kerneldoc init_clk_regs comment (Andre)
- Fix space on various comments (Andre)
- Fix regmap typo on samsung_clk_save/restore calls (Andre)
- Include error code in pr_err message (Andre)
- Add macros for dcrg and memclk (Andre)
- Avoid confusing !IS_ERR_OR_NULL(ctx->sysreg) test (Krzysztof)
- Update kerneldoc to mention drcg_offset & memclk_offset are in sysreg
(Andre)
- Update bindings commit description as to why the sysreg is required
(Krzysztof)
- Link to v1: https://lore.kernel.org/r/20251013-automatic-clocks-v1-0-72851ee00300 at linaro.org

---
Peter Griffin (4):
      dt-bindings: clock: google,gs101-clock: add samsung,sysreg property as required
      arm64: dts: exynos: gs101: add samsung,sysreg property to CMU nodes
      clk: samsung: Implement automatic clock gating mode for CMUs
      clk: samsung: gs101: Enable auto_clock_gate mode for each gs101 CMU

 .../bindings/clock/google,gs101-clock.yaml         |  19 +-
 arch/arm64/boot/dts/exynos/google/gs101.dtsi       |   6 +
 drivers/clk/samsung/clk-exynos-arm64.c             |  62 ++++++-
 drivers/clk/samsung/clk-exynos4.c                  |  12 +-
 drivers/clk/samsung/clk-exynos4412-isp.c           |   4 +-
 drivers/clk/samsung/clk-exynos5250.c               |   2 +-
 drivers/clk/samsung/clk-exynos5420.c               |   4 +-
 drivers/clk/samsung/clk-gs101.c                    |  55 ++++++
 drivers/clk/samsung/clk-s3c64xx.c                  |   4 +-
 drivers/clk/samsung/clk-s5pv210.c                  |   2 +-
 drivers/clk/samsung/clk.c                          | 200 +++++++++++++++++++--
 drivers/clk/samsung/clk.h                          |  55 +++++-
 12 files changed, 381 insertions(+), 44 deletions(-)
---
base-commit: cc3aa43b44bdb43dfbac0fcb51c56594a11338a8
change-id: 20251008-automatic-clocks-249ab60f62ce

Best regards,
-- 
Peter Griffin <peter.griffin at linaro.org>



From peter.griffin at linaro.org  Sat Dec 20 01:05:39 2025
From: peter.griffin at linaro.org (Peter Griffin)
Date: Sat, 20 Dec 2025 09:05:39 +0000
Subject: [PATCH v6 1/4] dt-bindings: clock: google,gs101-clock: add
 samsung,sysreg property as required
In-Reply-To: <20251220-automatic-clocks-v6-0-36c2f276a135@linaro.org>
References: <20251220-automatic-clocks-v6-0-36c2f276a135@linaro.org>
Message-ID: <20251220-automatic-clocks-v6-1-36c2f276a135@linaro.org>

Each CMU (with the exception of cmu_top) has a corresponding sysreg bank
that contains the BUSCOMPONENT_DRCG_EN and optional MEMCLK registers.
The BUSCOMPONENT_DRCG_EN register enables dynamic root clock gating of
bus components and MEMCLK gates the sram clock.

Now the clock driver supports automatic clock mode, to fully enable dynamic
root clock gating it is required to configure these registers. Update the
bindings documentation so that all CMUs (with the exception of
gs101-cmu-top) have samsung,sysreg as a required property.

Note this is NOT an ABI break, as if the property isn't specified the
clock driver will fallback to the current behaviour of not initializing
the registers. The system still boots, but bus components won't benefit
from dynamic root clock gating and dynamic power will be higher (which has
been the case until now anyway).

Additionally update the DT example to included the correct CMU size as
registers in that region are used for automatic clock mode.

Signed-off-by: Peter Griffin <peter.griffin at linaro.org>
---
Changes in v5:
- Invert the test for google,gs101-cmu-top (Andre)

Changes in v4
- Update commit description with additional requested details (Krzysztof)

Changes in v3:
- Update commit description as to why the sysreg is required (Krzysztof)

Changes in v2:
- Update commit description regarding updated example (Andre)
---
 .../devicetree/bindings/clock/google,gs101-clock.yaml | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml b/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
index 31e106ef913dead9a038b3b6d8b43b950587f6aa..09e679c1a9def03d53b8b493929911ea902a1763 100644
--- a/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
+++ b/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
@@ -52,6 +52,11 @@ properties:
   reg:
     maxItems: 1
 
+  samsung,sysreg:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      Phandle to system registers interface.
+
 required:
   - compatible
   - "#clock-cells"
@@ -166,6 +171,18 @@ allOf:
             - const: bus
             - const: ip
 
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: google,gs101-cmu-top
+    then:
+      properties:
+        samsung,sysreg: false
+    else:
+      required:
+        - samsung,sysreg
+
 additionalProperties: false
 
 examples:
@@ -175,7 +192,7 @@ examples:
 
     cmu_top: clock-controller at 1e080000 {
         compatible = "google,gs101-cmu-top";
-        reg = <0x1e080000 0x8000>;
+        reg = <0x1e080000 0x10000>;
         #clock-cells = <1>;
         clocks = <&ext_24_5m>;
         clock-names = "oscclk";

-- 
2.52.0.351.gbe84eed79e-goog



From peter.griffin at linaro.org  Sat Dec 20 01:05:40 2025
From: peter.griffin at linaro.org (Peter Griffin)
Date: Sat, 20 Dec 2025 09:05:40 +0000
Subject: [PATCH v6 2/4] arm64: dts: exynos: gs101: add samsung,sysreg
 property to CMU nodes
In-Reply-To: <20251220-automatic-clocks-v6-0-36c2f276a135@linaro.org>
References: <20251220-automatic-clocks-v6-0-36c2f276a135@linaro.org>
Message-ID: <20251220-automatic-clocks-v6-2-36c2f276a135@linaro.org>

With the exception of cmu_top, each CMU has a corresponding sysreg bank
that contains the BUSCOMPONENT_DRCG_EN and optional MEMCLK registers.
The BUSCOMPONENT_DRCG_EN register enables dynamic root clock gating of
bus components and MEMCLK gates the sram clock.

Now the clock driver supports automatic clock mode, provide the
samsung,sysreg property so the driver can enable dynamic root clock
gating of bus components and gate sram clock.

Note without the property specified the driver simply falls back to
previous behaviour of not configuring these registers so it is not an ABI
break.

Signed-off-by: Peter Griffin <peter.griffin at linaro.org>
---
Changes in v4:
- Update commit message (Peter)
---
 arch/arm64/boot/dts/exynos/google/gs101.dtsi | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm64/boot/dts/exynos/google/gs101.dtsi b/arch/arm64/boot/dts/exynos/google/gs101.dtsi
index 9b38c2248016aa65293c0abf9ccaf20857d89693..2e25eeb0c2590b99ef98c7bdac3caa0c34161706 100644
--- a/arch/arm64/boot/dts/exynos/google/gs101.dtsi
+++ b/arch/arm64/boot/dts/exynos/google/gs101.dtsi
@@ -578,6 +578,7 @@ cmu_misc: clock-controller at 10010000 {
 			clocks = <&cmu_top CLK_DOUT_CMU_MISC_BUS>,
 				 <&cmu_top CLK_DOUT_CMU_MISC_SSS>;
 			clock-names = "bus", "sss";
+			samsung,sysreg = <&sysreg_misc>;
 		};
 
 		sysreg_misc: syscon at 10030000 {
@@ -671,6 +672,7 @@ cmu_peric0: clock-controller at 10800000 {
 				 <&cmu_top CLK_DOUT_CMU_PERIC0_BUS>,
 				 <&cmu_top CLK_DOUT_CMU_PERIC0_IP>;
 			clock-names = "oscclk", "bus", "ip";
+			samsung,sysreg = <&sysreg_peric0>;
 		};
 
 		sysreg_peric0: syscon at 10820000 {
@@ -1217,6 +1219,7 @@ cmu_peric1: clock-controller at 10c00000 {
 				 <&cmu_top CLK_DOUT_CMU_PERIC1_BUS>,
 				 <&cmu_top CLK_DOUT_CMU_PERIC1_IP>;
 			clock-names = "oscclk", "bus", "ip";
+			samsung,sysreg = <&sysreg_peric1>;
 		};
 
 		sysreg_peric1: syscon at 10c20000 {
@@ -1575,6 +1578,7 @@ cmu_hsi0: clock-controller at 11000000 {
 				 <&cmu_top CLK_DOUT_CMU_HSI0_USBDPDBG>;
 			clock-names = "oscclk", "bus", "dpgtc", "usb31drd",
 				      "usbdpdbg";
+			samsung,sysreg = <&sysreg_hsi0>;
 		};
 
 		sysreg_hsi0: syscon at 11020000 {
@@ -1646,6 +1650,7 @@ cmu_hsi2: clock-controller at 14400000 {
 				 <&cmu_top CLK_DOUT_CMU_HSI2_UFS_EMBD>,
 				 <&cmu_top CLK_DOUT_CMU_HSI2_MMC_CARD>;
 			clock-names = "oscclk", "bus", "pcie", "ufs", "mmc";
+			samsung,sysreg = <&sysreg_hsi2>;
 		};
 
 		sysreg_hsi2: syscon at 14420000 {
@@ -1706,6 +1711,7 @@ cmu_apm: clock-controller at 17400000 {
 
 			clocks = <&ext_24_5m>;
 			clock-names = "oscclk";
+			samsung,sysreg = <&sysreg_apm>;
 		};
 
 		sysreg_apm: syscon at 17420000 {

-- 
2.52.0.351.gbe84eed79e-goog



From peter.griffin at linaro.org  Sat Dec 20 01:05:41 2025
From: peter.griffin at linaro.org (Peter Griffin)
Date: Sat, 20 Dec 2025 09:05:41 +0000
Subject: [PATCH v6 3/4] clk: samsung: Implement automatic clock gating mode
 for CMUs
In-Reply-To: <20251220-automatic-clocks-v6-0-36c2f276a135@linaro.org>
References: <20251220-automatic-clocks-v6-0-36c2f276a135@linaro.org>
Message-ID: <20251220-automatic-clocks-v6-3-36c2f276a135@linaro.org>

Update exynos_arm64_init_clocks() so that it enables the automatic clock
mode bits in the CMU option register if the auto_clock_gate flag and
option_offset fields are set for the CMU. To ensure compatibility with
older DTs (that specified an incorrect CMU reg size), detect this and
fallback to manual clock gate mode as the auto clock mode feature depends
on registers in this area.

The CMU option register bits are global and effect every clock component in
the CMU, as such clearing the GATE_ENABLE_HWACG bit and setting GATE_MANUAL
bit on every gate register is only required if auto_clock_gate is false.

Additionally if auto_clock_gate is enabled the dynamic root clock gating
and memclk registers will be configured in the corresponding CMUs sysreg
bank. These registers are exposed via syscon, so the register
samsung_clk_save/restore paths are updated to also take a regmap.

As many gates for various Samsung SoCs are already exposed in the Samsung
clock drivers a new samsung_auto_clk_gate_ops is implemented. This uses
some CMU debug registers to report whether clocks are enabled or disabled
when operating in automatic mode. This allows
/sys/kernel/debug/clk/clk_summary to still dump the entire clock tree and
correctly report the status of each clock in the system.

Signed-off-by: Peter Griffin <peter.griffin at linaro.org>
---
Changes in v3:
- Add missing 'np' func param to kerneldoc in samsung_cmu_register_clocks
(0-DAY CI)

Changes in v2:
- Fallback to manual clock gate mode for old DTs with incorrect CMU size
(added samsung_is_auto_capable()) (Krzysztof)
- Rename OPT_UNKNOWN bit to OPT_EN_LAYER2_CTRL (Andre)
- Rename OPT_EN_MEM_PM_GATING to OPT_EN_MEM_PWR_GATING (Andre)
- Reverse Option bit definitions LSB -> MSB (Krzysztof)
- Update kerneldoc init_clk_regs comment (Andre)
- Fix space on various comments (Andre)
- Fix regmap typo on samsung_clk_save/restore calls (Andre)
- Include error code in pr_err message (Andre)
- Add macros for dcrg and memclk (Andre)
- Avoid confusing !IS_ERR_OR_NULL(ctx->sysreg) test (Krzysztof)
- Update kerneldoc to mention drcg_offset & memclk_offset are in sysreg (Andre)
- Fix 0-DAY CI randconfig warning (0-DAY CI)
- Update clk-s5pv210 and clk-s3c64xx.c samsung_clk_sleep_init call sites (Peter)
---
 drivers/clk/samsung/clk-exynos-arm64.c   |  62 ++++++++--
 drivers/clk/samsung/clk-exynos4.c        |  12 +-
 drivers/clk/samsung/clk-exynos4412-isp.c |   4 +-
 drivers/clk/samsung/clk-exynos5250.c     |   2 +-
 drivers/clk/samsung/clk-exynos5420.c     |   4 +-
 drivers/clk/samsung/clk-s3c64xx.c        |   4 +-
 drivers/clk/samsung/clk-s5pv210.c        |   2 +-
 drivers/clk/samsung/clk.c                | 200 ++++++++++++++++++++++++++++---
 drivers/clk/samsung/clk.h                |  55 ++++++++-
 9 files changed, 302 insertions(+), 43 deletions(-)

diff --git a/drivers/clk/samsung/clk-exynos-arm64.c b/drivers/clk/samsung/clk-exynos-arm64.c
index bf7de21f329ec89069dcf817ca578fcf9b2d9809..11e4d49f2390ba714eff5a329bb1f427cd6437b9 100644
--- a/drivers/clk/samsung/clk-exynos-arm64.c
+++ b/drivers/clk/samsung/clk-exynos-arm64.c
@@ -24,6 +24,16 @@
 #define GATE_MANUAL		BIT(20)
 #define GATE_ENABLE_HWACG	BIT(28)
 
+/* Option register bits */
+#define OPT_EN_MEM_PWR_GATING		BIT(24)
+#define OPT_EN_AUTO_GATING		BIT(28)
+#define OPT_EN_PWR_MANAGEMENT		BIT(29)
+#define OPT_EN_LAYER2_CTRL		BIT(30)
+#define OPT_EN_DBG			BIT(31)
+
+#define CMU_OPT_GLOBAL_EN_AUTO_GATING	(OPT_EN_DBG | OPT_EN_LAYER2_CTRL | \
+	OPT_EN_PWR_MANAGEMENT | OPT_EN_AUTO_GATING | OPT_EN_MEM_PWR_GATING)
+
 /* PLL_CONx_PLL register offsets range */
 #define PLL_CON_OFF_START	0x100
 #define PLL_CON_OFF_END		0x600
@@ -37,6 +47,8 @@ struct exynos_arm64_cmu_data {
 	unsigned int nr_clk_save;
 	const struct samsung_clk_reg_dump *clk_suspend;
 	unsigned int nr_clk_suspend;
+	struct samsung_clk_reg_dump *clk_sysreg_save;
+	unsigned int nr_clk_sysreg;
 
 	struct clk *clk;
 	struct clk **pclks;
@@ -76,19 +88,41 @@ static void __init exynos_arm64_init_clocks(struct device_node *np,
 	const unsigned long *reg_offs = cmu->clk_regs;
 	size_t reg_offs_len = cmu->nr_clk_regs;
 	void __iomem *reg_base;
+	bool init_auto;
 	size_t i;
 
 	reg_base = of_iomap(np, 0);
 	if (!reg_base)
 		panic("%s: failed to map registers\n", __func__);
 
+	/* ensure compatibility with older DTs */
+	if (cmu->auto_clock_gate && samsung_is_auto_capable(np))
+		init_auto = true;
+	else
+		init_auto = false;
+
+	if (cmu->option_offset && init_auto) {
+		/*
+		 * Enable the global automatic mode for the entire CMU.
+		 * This overrides the individual HWACG bits in each of the
+		 * individual gate, mux and qch registers.
+		 */
+		writel(CMU_OPT_GLOBAL_EN_AUTO_GATING,
+		       reg_base + cmu->option_offset);
+	}
+
 	for (i = 0; i < reg_offs_len; ++i) {
 		void __iomem *reg = reg_base + reg_offs[i];
 		u32 val;
 
 		if (cmu->manual_plls && is_pll_con1_reg(reg_offs[i])) {
 			writel(PLL_CON1_MANUAL, reg);
-		} else if (is_gate_reg(reg_offs[i])) {
+		} else if (is_gate_reg(reg_offs[i]) && !init_auto) {
+			/*
+			 * Setting GATE_MANUAL bit (which is described in TRM as
+			 * reserved!) overrides the global CMU automatic mode
+			 * option.
+			 */
 			val = readl(reg);
 			val |= GATE_MANUAL;
 			val &= ~GATE_ENABLE_HWACG;
@@ -210,8 +244,8 @@ void __init exynos_arm64_register_cmu(struct device *dev,
 /**
  * exynos_arm64_register_cmu_pm - Register Exynos CMU domain with PM support
  *
- * @pdev:	Platform device object
- * @set_manual:	If true, set gate clocks to manual mode
+ * @pdev:		Platform device object
+ * @init_clk_regs:	If true, initialize CMU registers
  *
  * It's a version of exynos_arm64_register_cmu() with PM support. Should be
  * called from probe function of platform driver.
@@ -219,7 +253,7 @@ void __init exynos_arm64_register_cmu(struct device *dev,
  * Return: 0 on success, or negative error code on error.
  */
 int __init exynos_arm64_register_cmu_pm(struct platform_device *pdev,
-					bool set_manual)
+					bool init_clk_regs)
 {
 	const struct samsung_cmu_info *cmu;
 	struct device *dev = &pdev->dev;
@@ -249,7 +283,7 @@ int __init exynos_arm64_register_cmu_pm(struct platform_device *pdev,
 		dev_err(dev, "%s: could not enable bus clock %s; err = %d\n",
 		       __func__, cmu->clk_name, ret);
 
-	if (set_manual)
+	if (init_clk_regs)
 		exynos_arm64_init_clocks(np, cmu);
 
 	reg_base = devm_platform_ioremap_resource(pdev, 0);
@@ -268,8 +302,10 @@ int __init exynos_arm64_register_cmu_pm(struct platform_device *pdev,
 	pm_runtime_set_active(dev);
 	pm_runtime_enable(dev);
 
-	samsung_cmu_register_clocks(data->ctx, cmu);
+	samsung_cmu_register_clocks(data->ctx, cmu, np);
 	samsung_clk_of_add_provider(dev->of_node, data->ctx);
+	/* sysreg DT nodes reference a clock in this CMU */
+	samsung_en_dyn_root_clk_gating(np, data->ctx, cmu);
 	pm_runtime_put_sync(dev);
 
 	return 0;
@@ -280,14 +316,17 @@ int exynos_arm64_cmu_suspend(struct device *dev)
 	struct exynos_arm64_cmu_data *data = dev_get_drvdata(dev);
 	int i;
 
-	samsung_clk_save(data->ctx->reg_base, data->clk_save,
+	samsung_clk_save(data->ctx->reg_base, NULL, data->clk_save,
 			 data->nr_clk_save);
 
+	samsung_clk_save(NULL, data->ctx->sysreg, data->clk_sysreg_save,
+			 data->nr_clk_sysreg);
+
 	for (i = 0; i < data->nr_pclks; i++)
 		clk_prepare_enable(data->pclks[i]);
 
 	/* For suspend some registers have to be set to certain values */
-	samsung_clk_restore(data->ctx->reg_base, data->clk_suspend,
+	samsung_clk_restore(data->ctx->reg_base, NULL, data->clk_suspend,
 			    data->nr_clk_suspend);
 
 	for (i = 0; i < data->nr_pclks; i++)
@@ -308,9 +347,14 @@ int exynos_arm64_cmu_resume(struct device *dev)
 	for (i = 0; i < data->nr_pclks; i++)
 		clk_prepare_enable(data->pclks[i]);
 
-	samsung_clk_restore(data->ctx->reg_base, data->clk_save,
+	samsung_clk_restore(data->ctx->reg_base, NULL, data->clk_save,
 			    data->nr_clk_save);
 
+	if (data->ctx->sysreg)
+		samsung_clk_restore(NULL, data->ctx->sysreg,
+				    data->clk_sysreg_save,
+				    data->nr_clk_sysreg);
+
 	for (i = 0; i < data->nr_pclks; i++)
 		clk_disable_unprepare(data->pclks[i]);
 
diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c
index cc5c1644c41c08b27bc48d809a08cd8a006cbe8f..246bd28bac2d577a58a7b9e0e93b700548370a36 100644
--- a/drivers/clk/samsung/clk-exynos4.c
+++ b/drivers/clk/samsung/clk-exynos4.c
@@ -1361,12 +1361,12 @@ static void __init exynos4_clk_init(struct device_node *np,
 					ARRAY_SIZE(exynos4x12_plls));
 	}
 
-	samsung_cmu_register_clocks(ctx, &cmu_info_exynos4);
+	samsung_cmu_register_clocks(ctx, &cmu_info_exynos4, np);
 
 	if (exynos4_soc == EXYNOS4210) {
-		samsung_cmu_register_clocks(ctx, &cmu_info_exynos4210);
+		samsung_cmu_register_clocks(ctx, &cmu_info_exynos4210, np);
 	} else {
-		samsung_cmu_register_clocks(ctx, &cmu_info_exynos4x12);
+		samsung_cmu_register_clocks(ctx, &cmu_info_exynos4x12, np);
 		if (soc == EXYNOS4412)
 			samsung_clk_register_cpu(ctx, exynos4412_cpu_clks,
 					ARRAY_SIZE(exynos4412_cpu_clks));
@@ -1378,15 +1378,15 @@ static void __init exynos4_clk_init(struct device_node *np,
 	if (soc == EXYNOS4212 || soc == EXYNOS4412)
 		exynos4x12_core_down_clock();
 
-	samsung_clk_extended_sleep_init(reg_base,
+	samsung_clk_extended_sleep_init(reg_base, NULL,
 			exynos4_clk_regs, ARRAY_SIZE(exynos4_clk_regs),
 			src_mask_suspend, ARRAY_SIZE(src_mask_suspend));
 	if (exynos4_soc == EXYNOS4210)
-		samsung_clk_extended_sleep_init(reg_base,
+		samsung_clk_extended_sleep_init(reg_base, NULL,
 		    exynos4210_clk_save, ARRAY_SIZE(exynos4210_clk_save),
 		    src_mask_suspend_e4210, ARRAY_SIZE(src_mask_suspend_e4210));
 	else
-		samsung_clk_sleep_init(reg_base, exynos4x12_clk_save,
+		samsung_clk_sleep_init(reg_base, NULL, exynos4x12_clk_save,
 				       ARRAY_SIZE(exynos4x12_clk_save));
 
 	samsung_clk_of_add_provider(np, ctx);
diff --git a/drivers/clk/samsung/clk-exynos4412-isp.c b/drivers/clk/samsung/clk-exynos4412-isp.c
index fa915057e109e0008ebe0b1b5d1652fd5804e82b..772bc18a1e686f23b11bf160b803becff6279637 100644
--- a/drivers/clk/samsung/clk-exynos4412-isp.c
+++ b/drivers/clk/samsung/clk-exynos4412-isp.c
@@ -94,7 +94,7 @@ static int __maybe_unused exynos4x12_isp_clk_suspend(struct device *dev)
 {
 	struct samsung_clk_provider *ctx = dev_get_drvdata(dev);
 
-	samsung_clk_save(ctx->reg_base, exynos4x12_save_isp,
+	samsung_clk_save(ctx->reg_base, NULL, exynos4x12_save_isp,
 			 ARRAY_SIZE(exynos4x12_clk_isp_save));
 	return 0;
 }
@@ -103,7 +103,7 @@ static int __maybe_unused exynos4x12_isp_clk_resume(struct device *dev)
 {
 	struct samsung_clk_provider *ctx = dev_get_drvdata(dev);
 
-	samsung_clk_restore(ctx->reg_base, exynos4x12_save_isp,
+	samsung_clk_restore(ctx->reg_base, NULL, exynos4x12_save_isp,
 			    ARRAY_SIZE(exynos4x12_clk_isp_save));
 	return 0;
 }
diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c
index e90d3a0848cbc24b2709c10795f6affcda404567..f97f30b29be7317db8186bac39cf52e1893eb106 100644
--- a/drivers/clk/samsung/clk-exynos5250.c
+++ b/drivers/clk/samsung/clk-exynos5250.c
@@ -854,7 +854,7 @@ static void __init exynos5250_clk_init(struct device_node *np)
 		PWR_CTRL2_CORE2_UP_RATIO | PWR_CTRL2_CORE1_UP_RATIO);
 	__raw_writel(tmp, reg_base + PWR_CTRL2);
 
-	samsung_clk_sleep_init(reg_base, exynos5250_clk_regs,
+	samsung_clk_sleep_init(reg_base, NULL, exynos5250_clk_regs,
 			       ARRAY_SIZE(exynos5250_clk_regs));
 	exynos5_subcmus_init(ctx, ARRAY_SIZE(exynos5250_subcmus),
 			     exynos5250_subcmus);
diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c
index a9df4e6db82fa7831d4e5c7210b0163d7d301ec1..1982e0751ceec7e57f9e82d96dcbadce1f691092 100644
--- a/drivers/clk/samsung/clk-exynos5420.c
+++ b/drivers/clk/samsung/clk-exynos5420.c
@@ -1649,12 +1649,12 @@ static void __init exynos5x_clk_init(struct device_node *np,
 				ARRAY_SIZE(exynos5800_cpu_clks));
 	}
 
-	samsung_clk_extended_sleep_init(reg_base,
+	samsung_clk_extended_sleep_init(reg_base, NULL,
 		exynos5x_clk_regs, ARRAY_SIZE(exynos5x_clk_regs),
 		exynos5420_set_clksrc, ARRAY_SIZE(exynos5420_set_clksrc));
 
 	if (soc == EXYNOS5800) {
-		samsung_clk_sleep_init(reg_base, exynos5800_clk_regs,
+		samsung_clk_sleep_init(reg_base, NULL, exynos5800_clk_regs,
 				       ARRAY_SIZE(exynos5800_clk_regs));
 
 		exynos5_subcmus_init(ctx, ARRAY_SIZE(exynos5800_subcmus),
diff --git a/drivers/clk/samsung/clk-s3c64xx.c b/drivers/clk/samsung/clk-s3c64xx.c
index 397a057af5d1e704e7ead7ba04b477fdc28c45bf..5a2d5a5703ffc5ed48b9a18a20c39be2de827920 100644
--- a/drivers/clk/samsung/clk-s3c64xx.c
+++ b/drivers/clk/samsung/clk-s3c64xx.c
@@ -449,10 +449,10 @@ void __init s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f,
 	samsung_clk_register_alias(ctx, s3c64xx_clock_aliases,
 					ARRAY_SIZE(s3c64xx_clock_aliases));
 
-	samsung_clk_sleep_init(reg_base, s3c64xx_clk_regs,
+	samsung_clk_sleep_init(reg_base, NULL, s3c64xx_clk_regs,
 			       ARRAY_SIZE(s3c64xx_clk_regs));
 	if (!is_s3c6400)
-		samsung_clk_sleep_init(reg_base, s3c6410_clk_regs,
+		samsung_clk_sleep_init(reg_base, NULL, s3c6410_clk_regs,
 				       ARRAY_SIZE(s3c6410_clk_regs));
 
 	samsung_clk_of_add_provider(np, ctx);
diff --git a/drivers/clk/samsung/clk-s5pv210.c b/drivers/clk/samsung/clk-s5pv210.c
index 9a4217cc1908aa60ebbe51b2b5c841138cc46ef3..4ee4f2b5efbc1d4770fefff22de21f7d4e5e9506 100644
--- a/drivers/clk/samsung/clk-s5pv210.c
+++ b/drivers/clk/samsung/clk-s5pv210.c
@@ -782,7 +782,7 @@ static void __init __s5pv210_clk_init(struct device_node *np,
 	samsung_clk_register_alias(ctx, s5pv210_aliases,
 						ARRAY_SIZE(s5pv210_aliases));
 
-	samsung_clk_sleep_init(reg_base, s5pv210_clk_regs,
+	samsung_clk_sleep_init(reg_base, NULL, s5pv210_clk_regs,
 			       ARRAY_SIZE(s5pv210_clk_regs));
 
 	samsung_clk_of_add_provider(np, ctx);
diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c
index c149ca6c221725195faeb76b0d73374c3b48261b..06ea5deef4ee2ffb87dcd14102561886ea80b7bc 100644
--- a/drivers/clk/samsung/clk.c
+++ b/drivers/clk/samsung/clk.c
@@ -12,8 +12,10 @@
 #include <linux/clkdev.h>
 #include <linux/clk-provider.h>
 #include <linux/io.h>
+#include <linux/mfd/syscon.h>
 #include <linux/mod_devicetable.h>
 #include <linux/of_address.h>
+#include <linux/regmap.h>
 #include <linux/syscore_ops.h>
 
 #include "clk.h"
@@ -21,19 +23,29 @@
 static LIST_HEAD(clock_reg_cache_list);
 
 void samsung_clk_save(void __iomem *base,
+				    struct regmap *regmap,
 				    struct samsung_clk_reg_dump *rd,
 				    unsigned int num_regs)
 {
-	for (; num_regs > 0; --num_regs, ++rd)
-		rd->value = readl(base + rd->offset);
+	for (; num_regs > 0; --num_regs, ++rd) {
+		if (base)
+			rd->value = readl(base + rd->offset);
+		else if (regmap)
+			regmap_read(regmap, rd->offset, &rd->value);
+	}
 }
 
 void samsung_clk_restore(void __iomem *base,
+				      struct regmap *regmap,
 				      const struct samsung_clk_reg_dump *rd,
 				      unsigned int num_regs)
 {
-	for (; num_regs > 0; --num_regs, ++rd)
-		writel(rd->value, base + rd->offset);
+	for (; num_regs > 0; --num_regs, ++rd) {
+		if (base)
+			writel(rd->value, base + rd->offset);
+		else if (regmap)
+			regmap_write(regmap, rd->offset, rd->value);
+	}
 }
 
 struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump(
@@ -227,6 +239,103 @@ void __init samsung_clk_register_div(struct samsung_clk_provider *ctx,
 	}
 }
 
+/*
+ * Some older DT's have an incorrect CMU resource size which is incompatible
+ * with the auto clock mode feature. In such cases we switch back to manual
+ * clock gating mode.
+ */
+bool samsung_is_auto_capable(struct device_node *np)
+{
+	struct resource res;
+	resource_size_t size;
+
+	if (of_address_to_resource(np, 0, &res))
+		return false;
+
+	size = resource_size(&res);
+	if (size != 0x10000) {
+		pr_warn("%pOF: incorrect res size for automatic clocks\n", np);
+		return false;
+	}
+	return true;
+}
+
+#define ACG_MSK GENMASK(6, 4)
+#define CLK_IDLE GENMASK(5, 4)
+static int samsung_auto_clk_gate_is_en(struct clk_hw *hw)
+{
+	u32 reg;
+	struct clk_gate *gate = to_clk_gate(hw);
+
+	reg = readl(gate->reg);
+	return ((reg & ACG_MSK) == CLK_IDLE) ? 0 : 1;
+}
+
+/* enable and disable are nops in automatic clock mode */
+static int samsung_auto_clk_gate_en(struct clk_hw *hw)
+{
+	return 0;
+}
+
+static void samsung_auto_clk_gate_dis(struct clk_hw *hw)
+{
+}
+
+static const struct clk_ops samsung_auto_clk_gate_ops = {
+	.enable = samsung_auto_clk_gate_en,
+	.disable = samsung_auto_clk_gate_dis,
+	.is_enabled = samsung_auto_clk_gate_is_en,
+};
+
+struct clk_hw *samsung_register_auto_gate(struct device *dev,
+		struct device_node *np, const char *name,
+		const char *parent_name, const struct clk_hw *parent_hw,
+		const struct clk_parent_data *parent_data,
+		unsigned long flags,
+		void __iomem *reg, u8 bit_idx,
+		u8 clk_gate_flags, spinlock_t *lock)
+{
+	struct clk_gate *gate;
+	struct clk_hw *hw;
+	struct clk_init_data init = {};
+	int ret = -EINVAL;
+
+	/* allocate the gate */
+	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+	if (!gate)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &samsung_auto_clk_gate_ops;
+	init.flags = flags;
+	init.parent_names = parent_name ? &parent_name : NULL;
+	init.parent_hws = parent_hw ? &parent_hw : NULL;
+	init.parent_data = parent_data;
+	if (parent_name || parent_hw || parent_data)
+		init.num_parents = 1;
+	else
+		init.num_parents = 0;
+
+	/* struct clk_gate assignments */
+	gate->reg = reg;
+	gate->bit_idx = bit_idx;
+	gate->flags = clk_gate_flags;
+	gate->lock = lock;
+	gate->hw.init = &init;
+
+	hw = &gate->hw;
+	if (dev || !np)
+		ret = clk_hw_register(dev, hw);
+	else if (np)
+		ret = of_clk_hw_register(np, hw);
+	if (ret) {
+		kfree(gate);
+		hw = ERR_PTR(ret);
+	}
+
+	return hw;
+}
+
 /* register a list of gate clocks */
 void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx,
 				const struct samsung_gate_clock *list,
@@ -234,14 +343,24 @@ void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx,
 {
 	struct clk_hw *clk_hw;
 	unsigned int idx;
+	void __iomem *reg_offs;
 
 	for (idx = 0; idx < nr_clk; idx++, list++) {
-		clk_hw = clk_hw_register_gate(ctx->dev, list->name, list->parent_name,
-				list->flags, ctx->reg_base + list->offset,
+		reg_offs = ctx->reg_base + list->offset;
+
+		if (ctx->auto_clock_gate && ctx->gate_dbg_offset)
+			clk_hw = samsung_register_auto_gate(ctx->dev, NULL,
+				list->name, list->parent_name, NULL, NULL,
+				list->flags, reg_offs + ctx->gate_dbg_offset,
 				list->bit_idx, list->gate_flags, &ctx->lock);
+		else
+			clk_hw = clk_hw_register_gate(ctx->dev, list->name,
+				list->parent_name, list->flags,
+				ctx->reg_base + list->offset, list->bit_idx,
+				list->gate_flags, &ctx->lock);
 		if (IS_ERR(clk_hw)) {
-			pr_err("%s: failed to register clock %s\n", __func__,
-				list->name);
+			pr_err("%s: failed to register clock %s: %ld\n", __func__,
+				list->name, PTR_ERR(clk_hw));
 			continue;
 		}
 
@@ -276,10 +395,11 @@ static int samsung_clk_suspend(void *data)
 	struct samsung_clock_reg_cache *reg_cache;
 
 	list_for_each_entry(reg_cache, &clock_reg_cache_list, node) {
-		samsung_clk_save(reg_cache->reg_base, reg_cache->rdump,
-				reg_cache->rd_num);
-		samsung_clk_restore(reg_cache->reg_base, reg_cache->rsuspend,
-				reg_cache->rsuspend_num);
+		samsung_clk_save(reg_cache->reg_base, reg_cache->sysreg,
+				 reg_cache->rdump, reg_cache->rd_num);
+		samsung_clk_restore(reg_cache->reg_base, reg_cache->sysreg,
+				    reg_cache->rsuspend,
+				    reg_cache->rsuspend_num);
 	}
 	return 0;
 }
@@ -289,8 +409,8 @@ static void samsung_clk_resume(void *data)
 	struct samsung_clock_reg_cache *reg_cache;
 
 	list_for_each_entry(reg_cache, &clock_reg_cache_list, node)
-		samsung_clk_restore(reg_cache->reg_base, reg_cache->rdump,
-				reg_cache->rd_num);
+		samsung_clk_restore(reg_cache->reg_base, reg_cache->sysreg,
+				    reg_cache->rdump, reg_cache->rd_num);
 }
 
 static const struct syscore_ops samsung_clk_syscore_ops = {
@@ -303,6 +423,7 @@ static struct syscore samsung_clk_syscore = {
 };
 
 void samsung_clk_extended_sleep_init(void __iomem *reg_base,
+			struct regmap *sysreg,
 			const unsigned long *rdump,
 			unsigned long nr_rdump,
 			const struct samsung_clk_reg_dump *rsuspend,
@@ -323,6 +444,7 @@ void samsung_clk_extended_sleep_init(void __iomem *reg_base,
 		register_syscore(&samsung_clk_syscore);
 
 	reg_cache->reg_base = reg_base;
+	reg_cache->sysreg = sysreg;
 	reg_cache->rd_num = nr_rdump;
 	reg_cache->rsuspend = rsuspend;
 	reg_cache->rsuspend_num = nr_rsuspend;
@@ -334,10 +456,20 @@ void samsung_clk_extended_sleep_init(void __iomem *reg_base,
  * samsung_cmu_register_clocks() - Register all clocks provided in CMU object
  * @ctx: Clock provider object
  * @cmu: CMU object with clocks to register
+ * @np:  CMU device tree node
  */
 void __init samsung_cmu_register_clocks(struct samsung_clk_provider *ctx,
-					const struct samsung_cmu_info *cmu)
+					const struct samsung_cmu_info *cmu,
+					struct device_node *np)
 {
+	if (samsung_is_auto_capable(np) && cmu->auto_clock_gate)
+		ctx->auto_clock_gate = cmu->auto_clock_gate;
+
+	ctx->gate_dbg_offset = cmu->gate_dbg_offset;
+	ctx->option_offset = cmu->option_offset;
+	ctx->drcg_offset = cmu->drcg_offset;
+	ctx->memclk_offset = cmu->memclk_offset;
+
 	if (cmu->pll_clks)
 		samsung_clk_register_pll(ctx, cmu->pll_clks, cmu->nr_pll_clks);
 	if (cmu->mux_clks)
@@ -357,6 +489,37 @@ void __init samsung_cmu_register_clocks(struct samsung_clk_provider *ctx,
 		samsung_clk_register_cpu(ctx, cmu->cpu_clks, cmu->nr_cpu_clks);
 }
 
+/* Each bit enable/disables DRCG of a bus component */
+#define DRCG_EN_MSK	GENMASK(31, 0)
+#define MEMCLK_EN	BIT(0)
+
+/* Enable Dynamic Root Clock Gating (DRCG) of bus components */
+void samsung_en_dyn_root_clk_gating(struct device_node *np,
+				    struct samsung_clk_provider *ctx,
+				    const struct samsung_cmu_info *cmu)
+{
+	if (!ctx->auto_clock_gate)
+		return;
+
+	ctx->sysreg = syscon_regmap_lookup_by_phandle(np, "samsung,sysreg");
+	if (IS_ERR(ctx->sysreg)) {
+		pr_warn("%pOF: Unable to get CMU sysreg\n", np);
+		ctx->sysreg = NULL;
+	} else {
+		/* Enable DRCG for all bus components */
+		regmap_write(ctx->sysreg, ctx->drcg_offset, DRCG_EN_MSK);
+		/* Enable memclk gate (not present on all sysreg) */
+		if (ctx->memclk_offset)
+			regmap_write_bits(ctx->sysreg, ctx->memclk_offset,
+					  MEMCLK_EN, 0x0);
+
+		samsung_clk_extended_sleep_init(NULL, ctx->sysreg,
+						cmu->sysreg_clk_regs,
+						cmu->nr_sysreg_clk_regs,
+						NULL, 0);
+	}
+}
+
 /*
  * Common function which registers plls, muxes, dividers and gates
  * for each CMU. It also add CMU register list to register cache.
@@ -375,14 +538,17 @@ struct samsung_clk_provider * __init samsung_cmu_register_one(
 	}
 
 	ctx = samsung_clk_init(NULL, reg_base, cmu->nr_clk_ids);
-	samsung_cmu_register_clocks(ctx, cmu);
+	samsung_cmu_register_clocks(ctx, cmu, np);
 
 	if (cmu->clk_regs)
-		samsung_clk_extended_sleep_init(reg_base,
+		samsung_clk_extended_sleep_init(reg_base, NULL,
 			cmu->clk_regs, cmu->nr_clk_regs,
 			cmu->suspend_regs, cmu->nr_suspend_regs);
 
 	samsung_clk_of_add_provider(np, ctx);
 
+	/* sysreg DT nodes reference a clock in this CMU */
+	samsung_en_dyn_root_clk_gating(np, ctx, cmu);
+
 	return ctx;
 }
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
index 18660c1ac6f0106b17b9efc9c6b3cd62d46f7b82..a56aa3be54d817cd24bf2bc29427e783a1a9a859 100644
--- a/drivers/clk/samsung/clk.h
+++ b/drivers/clk/samsung/clk.h
@@ -12,6 +12,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/mod_devicetable.h>
+#include <linux/regmap.h>
 #include "clk-pll.h"
 #include "clk-cpu.h"
 
@@ -19,13 +20,25 @@
  * struct samsung_clk_provider - information about clock provider
  * @reg_base: virtual address for the register base
  * @dev: clock provider device needed for runtime PM
+ * @sysreg: syscon regmap for clock-provider sysreg controller
  * @lock: maintains exclusion between callbacks for a given clock-provider
+ * @auto_clock_gate: enable auto clk mode for all clocks in clock-provider
+ * @gate_dbg_offset: gate debug reg offset. Used for all gates in auto clk mode
+ * @option_offset: option reg offset. Enables auto mode for clock-provider
+ * @drcg_offset: dynamic root clk gate enable register offset in sysreg
+ * @memclk_offset: memclk enable register offset in sysreg
  * @clk_data: holds clock related data like clk_hw* and number of clocks
  */
 struct samsung_clk_provider {
 	void __iomem *reg_base;
 	struct device *dev;
+	struct regmap *sysreg;
 	spinlock_t lock;
+	bool auto_clock_gate;
+	u32 gate_dbg_offset;
+	u32 option_offset;
+	u32 drcg_offset;
+	u32 memclk_offset;
 	/* clk_data must be the last entry due to variable length 'hws' array */
 	struct clk_hw_onecell_data clk_data;
 };
@@ -310,6 +323,7 @@ struct samsung_cpu_clock {
 struct samsung_clock_reg_cache {
 	struct list_head node;
 	void __iomem *reg_base;
+	struct regmap *sysreg;
 	struct samsung_clk_reg_dump *rdump;
 	unsigned int rd_num;
 	const struct samsung_clk_reg_dump *rsuspend;
@@ -338,7 +352,14 @@ struct samsung_clock_reg_cache {
  * @suspend_regs: list of clock registers to set before suspend
  * @nr_suspend_regs: count of clock registers in @suspend_regs
  * @clk_name: name of the parent clock needed for CMU register access
+ * @sysreg_clk_regs: list of sysreg clock registers
+ * @nr_sysreg_clk_regs: count of clock registers in @sysreg_clk_regs
  * @manual_plls: Enable manual control for PLL clocks
+ * @auto_clock_gate: enable auto clock mode for all components in CMU
+ * @gate_dbg_offset: gate debug reg offset. Used by all gates in auto clk mode
+ * @option_offset: option reg offset. Enables auto clk mode for entire CMU
+ * @drcg_offset: dynamic root clk gate enable register offset in sysreg
+ * @memclk_offset: memclk enable register offset in sysreg
  */
 struct samsung_cmu_info {
 	const struct samsung_pll_clock *pll_clks;
@@ -364,8 +385,16 @@ struct samsung_cmu_info {
 	unsigned int nr_suspend_regs;
 	const char *clk_name;
 
+	const unsigned long *sysreg_clk_regs;
+	unsigned int nr_sysreg_clk_regs;
+
 	/* ARM64 Exynos CMUs */
 	bool manual_plls;
+	bool auto_clock_gate;
+	u32 gate_dbg_offset;
+	u32 option_offset;
+	u32 drcg_offset;
+	u32 memclk_offset;
 };
 
 struct samsung_clk_provider *samsung_clk_init(struct device *dev,
@@ -408,35 +437,55 @@ void samsung_clk_register_cpu(struct samsung_clk_provider *ctx,
 		const struct samsung_cpu_clock *list, unsigned int nr_clk);
 
 void samsung_cmu_register_clocks(struct samsung_clk_provider *ctx,
-				 const struct samsung_cmu_info *cmu);
+				 const struct samsung_cmu_info *cmu,
+				 struct device_node *np);
 struct samsung_clk_provider *samsung_cmu_register_one(
 			struct device_node *,
 			const struct samsung_cmu_info *);
 
 #ifdef CONFIG_PM_SLEEP
 void samsung_clk_extended_sleep_init(void __iomem *reg_base,
+			struct regmap *sysreg,
 			const unsigned long *rdump,
 			unsigned long nr_rdump,
 			const struct samsung_clk_reg_dump *rsuspend,
 			unsigned long nr_rsuspend);
 #else
 static inline void samsung_clk_extended_sleep_init(void __iomem *reg_base,
+			struct regmap *sysreg,
 			const unsigned long *rdump,
 			unsigned long nr_rdump,
 			const struct samsung_clk_reg_dump *rsuspend,
 			unsigned long nr_rsuspend) {}
 #endif
-#define samsung_clk_sleep_init(reg_base, rdump, nr_rdump) \
-	samsung_clk_extended_sleep_init(reg_base, rdump, nr_rdump, NULL, 0)
+#define samsung_clk_sleep_init(reg_base, sysreg, rdump, nr_rdump)	   \
+	samsung_clk_extended_sleep_init(reg_base, sysreg, rdump, nr_rdump, \
+					NULL, 0)
 
 void samsung_clk_save(void __iomem *base,
+			struct regmap *regmap,
 			struct samsung_clk_reg_dump *rd,
 			unsigned int num_regs);
 void samsung_clk_restore(void __iomem *base,
+			struct regmap *regmap,
 			const struct samsung_clk_reg_dump *rd,
 			unsigned int num_regs);
 struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump(
 			const unsigned long *rdump,
 			unsigned long nr_rdump);
 
+void samsung_en_dyn_root_clk_gating(struct device_node *np,
+				struct samsung_clk_provider *ctx,
+				const struct samsung_cmu_info *cmu);
+
+struct clk_hw *samsung_register_auto_gate(struct device *dev,
+		struct device_node *np, const char *name,
+		const char *parent_name, const struct clk_hw *parent_hw,
+		const struct clk_parent_data *parent_data,
+		unsigned long flags,
+		void __iomem *reg, u8 bit_idx,
+		u8 clk_gate_flags, spinlock_t *lock);
+
+bool samsung_is_auto_capable(struct device_node *np);
+
 #endif /* __SAMSUNG_CLK_H */

-- 
2.52.0.351.gbe84eed79e-goog



From peter.griffin at linaro.org  Sat Dec 20 01:05:42 2025
From: peter.griffin at linaro.org (Peter Griffin)
Date: Sat, 20 Dec 2025 09:05:42 +0000
Subject: [PATCH v6 4/4] clk: samsung: gs101: Enable auto_clock_gate mode
 for each gs101 CMU
In-Reply-To: <20251220-automatic-clocks-v6-0-36c2f276a135@linaro.org>
References: <20251220-automatic-clocks-v6-0-36c2f276a135@linaro.org>
Message-ID: <20251220-automatic-clocks-v6-4-36c2f276a135@linaro.org>

Enable auto clock mode, and define the additional fields which are used
when this mode is enabled.

/sys/kernel/debug/clk/clk_summary now reports approximately 308 running
clocks and 298 disabled clocks. Prior to this commit 586 clocks were
running and 17 disabled.

Signed-off-by: Peter Griffin <peter.griffin at linaro.org>
---
Changes in v4:
- Remove unnecessary header of_address.h (Peter)
---
 drivers/clk/samsung/clk-gs101.c | 55 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/drivers/clk/samsung/clk-gs101.c b/drivers/clk/samsung/clk-gs101.c
index 70b26db9b95ad0b376d23f637c7683fbc8c8c600..8551289b46eb88ec61dd1914d0fe782ae6794000 100644
--- a/drivers/clk/samsung/clk-gs101.c
+++ b/drivers/clk/samsung/clk-gs101.c
@@ -26,6 +26,10 @@
 #define CLKS_NR_PERIC0	(CLK_GOUT_PERIC0_SYSREG_PERIC0_PCLK + 1)
 #define CLKS_NR_PERIC1	(CLK_GOUT_PERIC1_SYSREG_PERIC1_PCLK + 1)
 
+#define GS101_GATE_DBG_OFFSET 0x4000
+#define GS101_DRCG_EN_OFFSET  0x104
+#define GS101_MEMCLK_OFFSET   0x108
+
 /* ---- CMU_TOP ------------------------------------------------------------- */
 
 /* Register Offset definitions for CMU_TOP (0x1e080000) */
@@ -1433,6 +1437,9 @@ static const struct samsung_cmu_info top_cmu_info __initconst = {
 	.nr_clk_ids		= CLKS_NR_TOP,
 	.clk_regs		= cmu_top_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(cmu_top_clk_regs),
+	.auto_clock_gate	= true,
+	.gate_dbg_offset	= GS101_GATE_DBG_OFFSET,
+	.option_offset		= CMU_CMU_TOP_CONTROLLER_OPTION,
 };
 
 static void __init gs101_cmu_top_init(struct device_node *np)
@@ -1900,6 +1907,11 @@ static const struct samsung_gate_clock apm_gate_clks[] __initconst = {
 	     CLK_CON_GAT_GOUT_BLK_APM_UID_XIU_DP_APM_IPCLKPORT_ACLK, 21, CLK_IS_CRITICAL, 0),
 };
 
+static const unsigned long dcrg_memclk_sysreg[] __initconst = {
+	GS101_DRCG_EN_OFFSET,
+	GS101_MEMCLK_OFFSET,
+};
+
 static const struct samsung_cmu_info apm_cmu_info __initconst = {
 	.mux_clks		= apm_mux_clks,
 	.nr_mux_clks		= ARRAY_SIZE(apm_mux_clks),
@@ -1912,6 +1924,12 @@ static const struct samsung_cmu_info apm_cmu_info __initconst = {
 	.nr_clk_ids		= CLKS_NR_APM,
 	.clk_regs		= apm_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(apm_clk_regs),
+	.sysreg_clk_regs	= dcrg_memclk_sysreg,
+	.nr_sysreg_clk_regs	= ARRAY_SIZE(dcrg_memclk_sysreg),
+	.auto_clock_gate	= true,
+	.gate_dbg_offset	= GS101_GATE_DBG_OFFSET,
+	.drcg_offset		= GS101_DRCG_EN_OFFSET,
+	.memclk_offset		= GS101_MEMCLK_OFFSET,
 };
 
 /* ---- CMU_HSI0 ------------------------------------------------------------ */
@@ -2375,7 +2393,14 @@ static const struct samsung_cmu_info hsi0_cmu_info __initconst = {
 	.nr_clk_ids		= CLKS_NR_HSI0,
 	.clk_regs		= hsi0_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(hsi0_clk_regs),
+	.sysreg_clk_regs	= dcrg_memclk_sysreg,
+	.nr_sysreg_clk_regs	= ARRAY_SIZE(dcrg_memclk_sysreg),
 	.clk_name		= "bus",
+	.auto_clock_gate        = true,
+	.gate_dbg_offset        = GS101_GATE_DBG_OFFSET,
+	.option_offset		= HSI0_CMU_HSI0_CONTROLLER_OPTION,
+	.drcg_offset		= GS101_DRCG_EN_OFFSET,
+	.memclk_offset		= GS101_MEMCLK_OFFSET,
 };
 
 /* ---- CMU_HSI2 ------------------------------------------------------------ */
@@ -2863,7 +2888,14 @@ static const struct samsung_cmu_info hsi2_cmu_info __initconst = {
 	.nr_clk_ids		= CLKS_NR_HSI2,
 	.clk_regs		= cmu_hsi2_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(cmu_hsi2_clk_regs),
+	.sysreg_clk_regs	= dcrg_memclk_sysreg,
+	.nr_sysreg_clk_regs	= ARRAY_SIZE(dcrg_memclk_sysreg),
 	.clk_name		= "bus",
+	.auto_clock_gate        = true,
+	.gate_dbg_offset        = GS101_GATE_DBG_OFFSET,
+	.option_offset		= HSI2_CMU_HSI2_CONTROLLER_OPTION,
+	.drcg_offset		= GS101_DRCG_EN_OFFSET,
+	.memclk_offset		= GS101_MEMCLK_OFFSET,
 };
 
 /* ---- CMU_MISC ------------------------------------------------------------ */
@@ -3423,7 +3455,14 @@ static const struct samsung_cmu_info misc_cmu_info __initconst = {
 	.nr_clk_ids		= CLKS_NR_MISC,
 	.clk_regs		= misc_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(misc_clk_regs),
+	.sysreg_clk_regs	= dcrg_memclk_sysreg,
+	.nr_sysreg_clk_regs	= ARRAY_SIZE(dcrg_memclk_sysreg),
 	.clk_name		= "bus",
+	.auto_clock_gate	= true,
+	.gate_dbg_offset	= GS101_GATE_DBG_OFFSET,
+	.option_offset		= MISC_CMU_MISC_CONTROLLER_OPTION,
+	.drcg_offset		= GS101_DRCG_EN_OFFSET,
+	.memclk_offset		= GS101_MEMCLK_OFFSET,
 };
 
 static void __init gs101_cmu_misc_init(struct device_node *np)
@@ -4010,6 +4049,10 @@ static const struct samsung_gate_clock peric0_gate_clks[] __initconst = {
 	     21, 0, 0),
 };
 
+static const unsigned long dcrg_sysreg[] __initconst = {
+	GS101_DRCG_EN_OFFSET,
+};
+
 static const struct samsung_cmu_info peric0_cmu_info __initconst = {
 	.mux_clks		= peric0_mux_clks,
 	.nr_mux_clks		= ARRAY_SIZE(peric0_mux_clks),
@@ -4020,7 +4063,13 @@ static const struct samsung_cmu_info peric0_cmu_info __initconst = {
 	.nr_clk_ids		= CLKS_NR_PERIC0,
 	.clk_regs		= peric0_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(peric0_clk_regs),
+	.sysreg_clk_regs	= dcrg_sysreg,
+	.nr_sysreg_clk_regs	= ARRAY_SIZE(dcrg_sysreg),
 	.clk_name		= "bus",
+	.auto_clock_gate        = true,
+	.gate_dbg_offset        = GS101_GATE_DBG_OFFSET,
+	.option_offset		= PERIC0_CMU_PERIC0_CONTROLLER_OPTION,
+	.drcg_offset		= GS101_DRCG_EN_OFFSET,
 };
 
 /* ---- CMU_PERIC1 ---------------------------------------------------------- */
@@ -4368,7 +4417,13 @@ static const struct samsung_cmu_info peric1_cmu_info __initconst = {
 	.nr_clk_ids		= CLKS_NR_PERIC1,
 	.clk_regs		= peric1_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(peric1_clk_regs),
+	.sysreg_clk_regs	= dcrg_sysreg,
+	.nr_sysreg_clk_regs	= ARRAY_SIZE(dcrg_sysreg),
 	.clk_name		= "bus",
+	.auto_clock_gate        = true,
+	.gate_dbg_offset        = GS101_GATE_DBG_OFFSET,
+	.option_offset		= PERIC1_CMU_PERIC1_CONTROLLER_OPTION,
+	.drcg_offset		= GS101_DRCG_EN_OFFSET,
 };
 
 /* ---- platform_driver ----------------------------------------------------- */

-- 
2.52.0.351.gbe84eed79e-goog



From zhenglifeng1 at huawei.com  Sat Dec 20 01:09:52 2025
From: zhenglifeng1 at huawei.com (zhenglifeng (A))
Date: Sat, 20 Dec 2025 17:09:52 +0800
Subject: [PATCH v6 0/3] arm64: topology: Handle AMU FIE setup on CPU
 hotplug
In-Reply-To: <aTx2V4am0FNHm03R@google.com>
References: <20251119081356.2495290-1-zhenglifeng1@huawei.com>
 <aS2z0EURwHbbGZab@arm.com> <9b6882dc-a91a-42d6-bf76-347338930d71@huawei.com>
 <aS8GZOuaS1-j14MD@arm.com> <29253319-ced9-4ab6-a58e-28afdf235cde@huawei.com>
 <aTx2V4am0FNHm03R@google.com>
Message-ID: <62ad0257-aa50-4ab6-bd46-64c3963e4b94@huawei.com>

On 2025/12/13 4:08, Will Deacon wrote:
> On Fri, Dec 12, 2025 at 05:27:09PM +0800, zhenglifeng (A) wrote:
>> On 2025/12/2 23:31, Beata Michalska wrote:
>>> On Tue, Dec 02, 2025 at 11:05:25AM +0800, zhenglifeng (A) wrote:
>>>> On 2025/12/1 23:27, Beata Michalska wrote:
>>>>> Hi,
>>>>>
>>>>> Apologies for the delay in reviewing this - currently in progress....
>>>>> Out of curiosity: what's the cpufreq driver used for testing this series ?
>>>>
>>>> I used cppc_cpufreq for testing this. But with some modifications in
>>>> processor_driver.c, or you'll find that the driver will fail to load with
>>>> maxcpus set. The modification below is only a temporary solution. I'm still
>>>> working on that.
>>>>
>>> Right, so overall the implementation looks good - thanks for that.
>>> There are two issues though with the cppc cpufreq driver.
>>>
>>> One: as you have already noticed - it fails to register when
>>> cpumask_present != cpumask_online.
>>>
>>> Second: it will mix the sources of the freq scale if not all CPUs within the
>>> policy have AMUs enabled/valid. This is due to the fact that at the time of
>>> registering the driver and initializing the FIE support policy->cpus ==
>>> policy->related_cpus. Assuming scenario when there are two CPUs within the
>>> policy, one being offline and missing valid AMU counters,
>>> the topology_set_scale_freq_source from cppc cpufreq driver will register
>>> the tick handler for both CPUs, whereas AMU support will (rightly so) register
>>> only for the firs one. When the second CPU comes online, the mismatch will be
>>> detected and the arch callback will get cleared for the first CPU, but the
>>> second one will remain unchanged.
>>>
>>> That said, I do not think any of those issues is a blocker for this series.
>>> But both would need fixing.
>>
>> I believe Beata is OK with this series. So I think we can move ahead with it
>> now.
> 
> Please repost at -rc1. It would be nice to have an Ack from Beata...

Hi Beata,

It would be nice if you could give this patch an Ack.

Thanks.

> 
> Will
> 



From peter.griffin at linaro.org  Sat Dec 20 01:14:01 2025
From: peter.griffin at linaro.org (Peter Griffin)
Date: Sat, 20 Dec 2025 09:14:01 +0000
Subject: [PATCH v5 3/4] clk: samsung: Implement automatic clock gating
 mode for CMUs
In-Reply-To: <e402ac33-c23a-46a1-b67e-097eb2ea7752@kernel.org>
References: <20251114-automatic-clocks-v5-0-efb9202ffcd7@linaro.org>
 <20251114-automatic-clocks-v5-3-efb9202ffcd7@linaro.org> <e402ac33-c23a-46a1-b67e-097eb2ea7752@kernel.org>
Message-ID: <CADrjBPq2oTz=PomQ08rWgYiQ40ResAUiKg4QVGoYCTYX20dKNA@mail.gmail.com>

Hi Krzysztof,

On Thu, 18 Dec 2025 at 16:06, Krzysztof Kozlowski <krzk at kernel.org> wrote:
>
> On 14/11/2025 15:16, Peter Griffin wrote:
> > Update exynos_arm64_init_clocks() so that it enables the automatic clock
> > mode bits in the CMU option register if the auto_clock_gate flag and
> > option_offset fields are set for the CMU. To ensure compatibility with
> > older DTs (that specified an incorrect CMU reg size), detect this and
> > fallback to manual clock gate mode as the auto clock mode feature depends
> > on registers in this area.
> >
> > The CMU option register bits are global and effect every clock component in
> > the CMU, as such clearing the GATE_ENABLE_HWACG bit and setting GATE_MANUAL
> > bit on every gate register is only required if auto_clock_gate is false.
> >
> > Additionally if auto_clock_gate is enabled the dynamic root clock gating
> > and memclk registers will be configured in the corresponding CMUs sysreg
> > bank. These registers are exposed via syscon, so the register
> > samsung_clk_save/restore paths are updated to also take a regmap.
> >
> > As many gates for various Samsung SoCs are already exposed in the Samsung
> > clock drivers a new samsung_auto_clk_gate_ops is implemented. This uses
> > some CMU debug registers to report whether clocks are enabled or disabled
> > when operating in automatic mode. This allows
> > /sys/kernel/debug/clk/clk_summary to still dump the entire clock tree and
> > correctly report the status of each clock in the system.
> >
> > Signed-off-by: Peter Griffin <peter.griffin at linaro.org>
> > ---
> > Changes in v3:
> > - Add missing 'np' func param to kerneldoc in samsung_cmu_register_clocks
> > (0-DAY CI)
> >
> > Changes in v2:
> > - Fallback to manual clock gate mode for old DTs with incorrect CMU size
> > (added samsung_is_auto_capable()) (Krzysztof)
> > - Rename OPT_UNKNOWN bit to OPT_EN_LAYER2_CTRL (Andre)
> > - Rename OPT_EN_MEM_PM_GATING to OPT_EN_MEM_PWR_GATING (Andre)
> > - Reverse Option bit definitions LSB -> MSB (Krzysztof)
> > - Update kerneldoc init_clk_regs comment (Andre)
> > - Fix space on various comments (Andre)
> > - Fix regmap typo on samsung_clk_save/restore calls (Andre)
> > - Include error code in pr_err message (Andre)
> > - Add macros for dcrg and memclk (Andre)
> > - Avoid confusing !IS_ERR_OR_NULL(ctx->sysreg) test (Krzysztof)
> > - Update kerneldoc to mention drcg_offset & memclk_offset are in sysreg (Andre)
> > - Fix 0-DAY CI randconfig warning (0-DAY CI)
> > - Update clk-s5pv210 and clk-s3c64xx.c samsung_clk_sleep_init call sites (Peter)
> > ---
>
> This does not apply, please rebase entire set:

Sure thing, I just sent a v6 rebased onto next-20251219

Just a heads up I hit a regression in serial on linux-next that I bisected to
24ec03cc5512 ("serial: core: Restore sysfs fwnode information")

It is unrelated to this series, but I guess you may also see this in
your exynos board farm. Now I have identified the culprit commit I see
others are also hitting it as well
https://lore.kernel.org/linux-serial/713aa37f-161d-4f08-9417-d7d2abdcdfd9 at sirena.org.uk/

Thanks,

Peter


From krzk at kernel.org  Sat Dec 20 01:27:04 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sat, 20 Dec 2025 10:27:04 +0100
Subject: [PATCH 1/6] dt-bindings: media: st: csi: add 'power-domains'
 property
In-Reply-To: <20251219-stm32-mp2x-dcmipp-csi-power-domain-v1-1-a6edb2aa8154@foss.st.com>
References: <20251219-stm32-mp2x-dcmipp-csi-power-domain-v1-0-a6edb2aa8154@foss.st.com>
 <20251219-stm32-mp2x-dcmipp-csi-power-domain-v1-1-a6edb2aa8154@foss.st.com>
Message-ID: <20251220-impartial-stereotyped-horse-70999f@quoll>

On Fri, Dec 19, 2025 at 04:58:03PM +0100, Alain Volmat wrote:
> STM32 CSI may be in a power domain which is the case for the STM32MP2x
> based boards. Allow a single 'power-domains' entry for STM32 CSI.
> 
> Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
> ---
>  Documentation/devicetree/bindings/media/st,stm32mp25-csi.yaml | 3 +++
>  1 file changed, 3 insertions(+)

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof



From krzk at kernel.org  Sat Dec 20 01:34:21 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sat, 20 Dec 2025 10:34:21 +0100
Subject: [PATCH 4/6] dt-bindings: media: st: dcmipp: add 'power-domains'
 property
In-Reply-To: <20251219-stm32-mp2x-dcmipp-csi-power-domain-v1-4-a6edb2aa8154@foss.st.com>
References: <20251219-stm32-mp2x-dcmipp-csi-power-domain-v1-0-a6edb2aa8154@foss.st.com>
 <20251219-stm32-mp2x-dcmipp-csi-power-domain-v1-4-a6edb2aa8154@foss.st.com>
Message-ID: <20251220-sociable-bald-partridge-7a67ab@quoll>

On Fri, Dec 19, 2025 at 04:58:06PM +0100, Alain Volmat wrote:
> STM32 DCMIPP may be in a power domain which is the case for the
> STM32MP2x based boards.
> Allow a single 'power-domains' entry for STM32 DCMIPP.
> 
> Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
> ---
>  Documentation/devicetree/bindings/media/st,stm32-dcmipp.yaml | 3 +++
>  1 file changed, 3 insertions(+)

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof



From cmarinas at kernel.org  Sat Dec 20 01:49:08 2025
From: cmarinas at kernel.org (Catalin Marinas)
Date: Sat, 20 Dec 2025 09:49:08 +0000
Subject: [GIT PULL] arm64 updates/fixes for 6.19-rc2
Message-ID: <aUZxFI1CtSF2R5HX@arm.com>

Hi Linus,

Please pull the arm64 updates below. There are two cleanups that I did
not push during the merging window because of conflicts with other
series going in via the tip and crypto trees. The other is a GCS fix.

Thanks.

The following changes since commit 8f0b4cce4481fb22653697cced8d0d04027cb1e8:

  Linux 6.19-rc1 (2025-12-14 16:05:07 +1200)

are available in the Git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux tags/arm64-fixes

for you to fetch changes up to f4ea8e05f2a857d5447c25f7daf00807d38b307d:

  lkdtm/bugs: Do not confuse the clang/objtool with busy wait loop (2025-12-19 15:09:09 +0000)

----------------------------------------------------------------
Two left-over updates that could not go into -rc1 due to conflicts with
other series:

 - Simplify checks in arch_kfence_init_pool() since force_pte_mapping()
   already takes BBML2-noabort (break-before-make Level 2 with no aborts
   generated) into account

 - Remove unneeded SVE/SME fallback preserve/store handling in the arm64
   EFI. With the recent updates, the fallback path is only taken for EFI
   runtime calls from hardirq or NMI contexts. In practice, this only
   happens under panic/oops/emergency_restart() and no restoring of the
   user state expected. There's a corresponding lkdtm update to trigger
   a BUG() or panic() from hardirq context together with a fixup not to
   confuse clang/objtool about the control flow

GCS (guarded control stacks) fix: flush the GCS locking state on exec,
otherwise the new task will not be able to enable GCS (locked as
disabled).

----------------------------------------------------------------
Ard Biesheuvel (2):
      lkdtm/bugs: Add cases for BUG and PANIC occurring in hardirq context
      arm64/efi: Remove unneeded SVE/SME fallback preserve/store handling

Catalin Marinas (1):
      lkdtm/bugs: Do not confuse the clang/objtool with busy wait loop

Kevin Brodsky (1):
      arm64: mm: Simplify check in arch_kfence_init_pool()

Mark Brown (1):
      arm64/gcs: Flush the GCS locking state on exec

 arch/arm64/kernel/fpsimd.c              | 130 +++++---------------------------
 arch/arm64/kernel/process.c             |   1 +
 arch/arm64/mm/mmu.c                     |  33 ++++----
 drivers/misc/lkdtm/bugs.c               |  53 +++++++++++++
 tools/testing/selftests/lkdtm/tests.txt |   2 +
 5 files changed, 92 insertions(+), 127 deletions(-)

-- 
Catalin


From amadeus at jmu.edu.cn  Sat Dec 20 02:00:09 2025
From: amadeus at jmu.edu.cn (Chukun Pan)
Date: Sat, 20 Dec 2025 18:00:09 +0800
Subject: [PATCH 2/3] arm64: dts: rockchip: fix hp-det pin for ArmSoM Sige5
In-Reply-To: <20251220100010.26643-1-amadeus@jmu.edu.cn>
References: <20251220100010.26643-1-amadeus@jmu.edu.cn>
Message-ID: <20251220100010.26643-2-amadeus@jmu.edu.cn>

Although the hp_det pin is not used, according to the schematic,
the headphone detection pin is GPIO4_B0. Fix the incorrect pin.

Signed-off-by: Chukun Pan <amadeus at jmu.edu.cn>
---
 arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts b/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts
index 392ba83ab05a..a0d8f52a706f 100644
--- a/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts
@@ -812,8 +812,8 @@ gmac1_rst: gmac1-rst {
 	};
 
 	headphone {
-		hp_det: hp-det {
-			rockchip,pins = <0 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up>;
+		hp_det_l: hp-det-l {
+			rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
 		};
 	};
 
-- 
2.25.1



From amadeus at jmu.edu.cn  Sat Dec 20 02:00:08 2025
From: amadeus at jmu.edu.cn (Chukun Pan)
Date: Sat, 20 Dec 2025 18:00:08 +0800
Subject: [PATCH 1/3] arm64: dts: rockchip: remove rtc regulator for ArmSoM Sige5
Message-ID: <20251220100010.26643-1-amadeus@jmu.edu.cn>

According to the schematic, RTC is powered by vcc_3v3_s3.
The vcc_3v3_rtc_s5 regulator does not exist, remove it.

Signed-off-by: Chukun Pan <amadeus at jmu.edu.cn>
---
 arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts | 10 ----------
 1 file changed, 10 deletions(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts b/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts
index 3386084f6318..392ba83ab05a 100644
--- a/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts
@@ -156,16 +156,6 @@ vcc_3v3_pcie: regulator-vcc-3v3-pcie {
 		vin-supply = <&vcc_5v0_sys>;
 	};
 
-	vcc_3v3_rtc_s5: regulator-vcc-3v3-rtc-s5 {
-		compatible = "regulator-fixed";
-		regulator-name = "vcc_3v3_rtc_s5";
-		regulator-boot-on;
-		regulator-always-on;
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		vin-supply = <&vcc_5v0_sys>;
-	};
-
 	vcc_3v3_s0: regulator-vcc-3v3-s0 {
 		compatible = "regulator-fixed";
 		regulator-name = "vcc_3v3_s0";
-- 
2.25.1



From amadeus at jmu.edu.cn  Sat Dec 20 02:00:10 2025
From: amadeus at jmu.edu.cn (Chukun Pan)
Date: Sat, 20 Dec 2025 18:00:10 +0800
Subject: [PATCH 3/3] arm64: dts: rockchip: enable saradc for ArmSoM Sige5
In-Reply-To: <20251220100010.26643-1-amadeus@jmu.edu.cn>
References: <20251220100010.26643-1-amadeus@jmu.edu.cn>
Message-ID: <20251220100010.26643-3-amadeus@jmu.edu.cn>

Add ADC support to ArmSoM Sige5 board.

Signed-off-by: Chukun Pan <amadeus at jmu.edu.cn>
---
 arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts b/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts
index a0d8f52a706f..d372ba252af8 100644
--- a/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts
@@ -897,6 +897,11 @@ &sai6 {
 	status = "okay";
 };
 
+&saradc {
+	vref-supply = <&vcca_1v8_s0>;
+	status = "okay";
+};
+
 &sdhci {
 	bus-width = <8>;
 	full-pwr-cycle-in-suspend;
-- 
2.25.1



From arnd at arndb.de  Sat Dec 20 04:17:14 2025
From: arnd at arndb.de (Arnd Bergmann)
Date: Sat, 20 Dec 2025 13:17:14 +0100
Subject: [PATCH 1/4] arch/*: increase lowmem size to avoid highmem use
In-Reply-To: <a2ce2849-e572-404c-9713-9283a43c09fe@intel.com>
References: <20251219161559.556737-1-arnd@kernel.org>
 <20251219161559.556737-2-arnd@kernel.org>
 <a3f22579-13ee-4479-a5fd-81c29145c3f3@intel.com>
 <bad18ad8-93e8-4150-a85e-a2852e243363@app.fastmail.com>
 <a2ce2849-e572-404c-9713-9283a43c09fe@intel.com>
Message-ID: <25642e76-43d6-4b17-94a9-e7dc53512223@app.fastmail.com>

On Fri, Dec 19, 2025, at 21:52, Dave Hansen wrote:
> On 12/19/25 12:20, Arnd Bergmann wrote:
>>> But, in the end, I don't this this matters all that much. If you think
>>> having x86 be consistent with ARM, for example, is more important and
>>> ARM really wants this complexity, I can live with it.
>> Yes, I think we do want the default of VMSPLIT_3G_OPT for
>> configs that have neither highmem nor lpae, otherwise the most
>> common embedded configs go from 3072 MiB to 1792 MiB of virtual
>> addressing, and that is much more likely to cause regressions
>> than the 2816 MiB default.
>
> The only thing we'd "regress" would be someone who is repeatedly
> starting from scratch with a defconfig and expecting defconfig to be the
> same all the time. I honestly think that's highly unlikely.

The entire vmsplit selection is guarded by a CONFIG_EXPERT conditional,
so I would expect it to change both for embedded distros that store
a project specific defconfig and for individual users that have a full
.config. If someone sets CONFIG_EXPERT, they do indeed keep any
previous defaults, but I'm also less worried about them.

In the Arm version, the 'choice' statement itself does not depend
on CONFIG_EXPERT, but I've added 'depends on !HIGHMEM || EXPERT'
in VMSPLIT_3G and VMSPLIT_3G_OPT for a similar effect.

> If folks are upgrading and _actually_ exposed to regressions, they've
> got an existing config and won't be hit by these defaults at *all*. They
> won't actually regress.
>
> In other words, I think we can be a lot more aggressive about defaults
> than with the feature set we support. I'd much rather add complexity in
> here for solving a real problem, like if we have armies of 32-bit x86
> users constantly starting new projects from scratch and using defconfigs.
>
> I'd _really_ like to keep the defaults as simple as possible.

I'm fine with 

	default VMSPLIT_2G_OPT if !X86_LPAE
	default VMSPLIT_2G

and dropping the VMSPLIT_3G_OPT default for non-highmem x86
builds if you think that's better. I still think we need the
special case for X86_LPAE/NX users to get to the point of having
VMSPLIT_2G_OPT as the default across architectures for current
HIGHMEM users that have exactly 2GB.

I honestly don't know enough about x86-32 users to have
a good idea who should be optimizing for. The embedded systems
(vortex86 and geode) seem to mostly have 512MB or less and no
PAE, so it probably works either way. As with similar
Arm configurations, these seemed like the highest priority
to me.

I see there are a few rare vortex86dx3 boards and the
upcoming vortex86ex3 that can have 2GB and would be using
HIGHMEM=y but PAE=n today, and these really want the 2G_OPT
split by default, not VMSPLIT_2G.

Hobbyists running on vintage PC systems instead may have
intentionally seeked out the few machines that actually support
2GB or 3.5GB of RAM on late Pentium-M or early Atom CPUs,
though most of the historic machines between the i486 and
the last 32-bit desktops would likely have much less.

    Arnd


From lkp at intel.com  Sat Dec 20 05:46:50 2025
From: lkp at intel.com (kernel test robot)
Date: Sat, 20 Dec 2025 21:46:50 +0800
Subject: [PATCH v12 19/46] KVM: arm64: Expose support for private memory
In-Reply-To: <20251217101125.91098-20-steven.price@arm.com>
References: <20251217101125.91098-20-steven.price@arm.com>
Message-ID: <202512202102.XFW5Jfym-lkp@intel.com>

Hi Steven,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on v6.19-rc1 next-20251219]
[cannot apply to kvmarm/next kvm/queue kvm/next arm64/for-next/core kvm/linux-next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Steven-Price/kvm-arm64-Include-kvm_emulate-h-in-kvm-arm_psci-h/20251218-030351
base:   linus/master
patch link:    https://lore.kernel.org/r/20251217101125.91098-20-steven.price%40arm.com
patch subject: [PATCH v12 19/46] KVM: arm64: Expose support for private memory
config: arm64-allnoconfig (https://download.01.org/0day-ci/archive/20251220/202512202102.XFW5Jfym-lkp at intel.com/config)
compiler: aarch64-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251220/202512202102.XFW5Jfym-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512202102.XFW5Jfym-lkp at intel.com/

All errors (new ones prefixed by >>):

   In file included from include/linux/kvm_host.h:45,
                    from arch/arm64/kernel/asm-offsets.c:16:
>> include/linux/kvm_host.h:725:45: error: expected identifier or '(' before 'struct'
     725 | static inline bool kvm_arch_has_private_mem(struct kvm *kvm)
         |                                             ^~~~~~
   arch/arm64/include/asm/kvm_host.h:1465:41: note: in definition of macro 'kvm_arch_has_private_mem'
    1465 | #define kvm_arch_has_private_mem(kvm) ((kvm)->arch.is_realm)
         |                                         ^~~
>> arch/arm64/include/asm/kvm_host.h:1465:45: error: expected ')' before '->' token
    1465 | #define kvm_arch_has_private_mem(kvm) ((kvm)->arch.is_realm)
         |                                             ^~
   include/linux/kvm_host.h:725:20: note: in expansion of macro 'kvm_arch_has_private_mem'
     725 | static inline bool kvm_arch_has_private_mem(struct kvm *kvm)
         |                    ^~~~~~~~~~~~~~~~~~~~~~~~
   make[3]: *** [scripts/Makefile.build:182: arch/arm64/kernel/asm-offsets.s] Error 1
   make[3]: Target 'prepare' not remade because of errors.
   make[2]: *** [Makefile:1314: prepare0] Error 2
   make[2]: Target 'prepare' not remade because of errors.
   make[1]: *** [Makefile:248: __sub-make] Error 2
   make[1]: Target 'prepare' not remade because of errors.
   make: *** [Makefile:248: __sub-make] Error 2
   make: Target 'prepare' not remade because of errors.


vim +725 include/linux/kvm_host.h

f481b069e67437 Paolo Bonzini       2015-05-17  723  
d1e54dd08f163a Fuad Tabba          2025-07-29  724  #ifndef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES
a7800aa80ea4d5 Sean Christopherson 2023-11-13 @725  static inline bool kvm_arch_has_private_mem(struct kvm *kvm)
a7800aa80ea4d5 Sean Christopherson 2023-11-13  726  {
a7800aa80ea4d5 Sean Christopherson 2023-11-13  727  	return false;
a7800aa80ea4d5 Sean Christopherson 2023-11-13  728  }
a7800aa80ea4d5 Sean Christopherson 2023-11-13  729  #endif
a7800aa80ea4d5 Sean Christopherson 2023-11-13  730  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From lkp at intel.com  Sat Dec 20 05:59:51 2025
From: lkp at intel.com (kernel test robot)
Date: Sat, 20 Dec 2025 21:59:51 +0800
Subject: [PATCH v12 19/46] KVM: arm64: Expose support for private memory
In-Reply-To: <20251217101125.91098-20-steven.price@arm.com>
References: <20251217101125.91098-20-steven.price@arm.com>
Message-ID: <202512202152.gapj1OD5-lkp@intel.com>

Hi Steven,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on v6.19-rc1 next-20251219]
[cannot apply to kvmarm/next kvm/queue kvm/next arm64/for-next/core kvm/linux-next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Steven-Price/kvm-arm64-Include-kvm_emulate-h-in-kvm-arm_psci-h/20251218-030351
base:   linus/master
patch link:    https://lore.kernel.org/r/20251217101125.91098-20-steven.price%40arm.com
patch subject: [PATCH v12 19/46] KVM: arm64: Expose support for private memory
config: arm64-randconfig-001-20251219 (https://download.01.org/0day-ci/archive/20251220/202512202152.gapj1OD5-lkp at intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project b324c9f4fa112d61a553bf489b5f4f7ceea05ea8)
rustc: rustc 1.88.0 (6b00bc388 2025-06-23)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251220/202512202152.gapj1OD5-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512202152.gapj1OD5-lkp at intel.com/

All errors (new ones prefixed by >>):

   In file included from arch/arm64/kernel/asm-offsets.c:16:
>> include/linux/kvm_host.h:725:45: error: expected identifier or '('
     725 | static inline bool kvm_arch_has_private_mem(struct kvm *kvm)
         |                                             ^
>> include/linux/kvm_host.h:725:45: error: expected ')'
   include/linux/kvm_host.h:725:20: note: to match this '('
     725 | static inline bool kvm_arch_has_private_mem(struct kvm *kvm)
         |                    ^
   arch/arm64/include/asm/kvm_host.h:1465:40: note: expanded from macro 'kvm_arch_has_private_mem'
    1465 | #define kvm_arch_has_private_mem(kvm) ((kvm)->arch.is_realm)
         |                                        ^
   In file included from arch/arm64/kernel/asm-offsets.c:16:
   include/linux/kvm_host.h:725:20: error: expected ')'
     725 | static inline bool kvm_arch_has_private_mem(struct kvm *kvm)
         |                    ^
   arch/arm64/include/asm/kvm_host.h:1465:45: note: expanded from macro 'kvm_arch_has_private_mem'
    1465 | #define kvm_arch_has_private_mem(kvm) ((kvm)->arch.is_realm)
         |                                             ^
   include/linux/kvm_host.h:725:20: note: to match this '('
   arch/arm64/include/asm/kvm_host.h:1465:39: note: expanded from macro 'kvm_arch_has_private_mem'
    1465 | #define kvm_arch_has_private_mem(kvm) ((kvm)->arch.is_realm)
         |                                       ^
   3 errors generated.
   make[3]: *** [scripts/Makefile.build:182: arch/arm64/kernel/asm-offsets.s] Error 1 shuffle=1976660145
   make[3]: Target 'prepare' not remade because of errors.
   make[2]: *** [Makefile:1314: prepare0] Error 2 shuffle=1976660145
   make[2]: Target 'prepare' not remade because of errors.
   make[1]: *** [Makefile:248: __sub-make] Error 2 shuffle=1976660145
   make[1]: Target 'prepare' not remade because of errors.
   make: *** [Makefile:248: __sub-make] Error 2 shuffle=1976660145
   make: Target 'prepare' not remade because of errors.


vim +725 include/linux/kvm_host.h

f481b069e67437 Paolo Bonzini       2015-05-17  723  
d1e54dd08f163a Fuad Tabba          2025-07-29  724  #ifndef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES
a7800aa80ea4d5 Sean Christopherson 2023-11-13 @725  static inline bool kvm_arch_has_private_mem(struct kvm *kvm)
a7800aa80ea4d5 Sean Christopherson 2023-11-13  726  {
a7800aa80ea4d5 Sean Christopherson 2023-11-13  727  	return false;
a7800aa80ea4d5 Sean Christopherson 2023-11-13  728  }
a7800aa80ea4d5 Sean Christopherson 2023-11-13  729  #endif
a7800aa80ea4d5 Sean Christopherson 2023-11-13  730  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From lkp at intel.com  Sat Dec 20 06:18:35 2025
From: lkp at intel.com (kernel test robot)
Date: Sat, 20 Dec 2025 15:18:35 +0100
Subject: [PATCH v12 19/46] KVM: arm64: Expose support for private memory
In-Reply-To: <20251217101125.91098-20-steven.price@arm.com>
References: <20251217101125.91098-20-steven.price@arm.com>
Message-ID: <202512201539.ZhAox5t9-lkp@intel.com>

Hi Steven,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on next-20251219]
[cannot apply to kvmarm/next kvm/queue kvm/next arm64/for-next/core kvm/linux-next v6.16-rc1]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Steven-Price/kvm-arm64-Include-kvm_emulate-h-in-kvm-arm_psci-h/20251217-224409
base:   linus/master
patch link:    https://lore.kernel.org/r/20251217101125.91098-20-steven.price%40arm.com
patch subject: [PATCH v12 19/46] KVM: arm64: Expose support for private memory
config: arm64-allnoconfig-bpf (https://download.01.org/0day-ci/archive/20251220/202512201539.ZhAox5t9-lkp at intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project ecaf673850beb241957352bd61e95ed34256635f)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251220/202512201539.ZhAox5t9-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512201539.ZhAox5t9-lkp at intel.com/

All errors (new ones prefixed by >>):

   In file included from arch/arm64/kernel/asm-offsets.c:16:
>> ./include/linux/kvm_host.h:725:45: error: expected identifier or '('
     725 | static inline bool kvm_arch_has_private_mem(struct kvm *kvm)
         |                                             ^
>> ./include/linux/kvm_host.h:725:45: error: expected ')'
   ./include/linux/kvm_host.h:725:20: note: to match this '('
     725 | static inline bool kvm_arch_has_private_mem(struct kvm *kvm)
         |                    ^
   ./arch/arm64/include/asm/kvm_host.h:1465:40: note: expanded from macro 'kvm_arch_has_private_mem'
    1465 | #define kvm_arch_has_private_mem(kvm) ((kvm)->arch.is_realm)
         |                                        ^
   In file included from arch/arm64/kernel/asm-offsets.c:16:
   ./include/linux/kvm_host.h:725:20: error: expected ')'
     725 | static inline bool kvm_arch_has_private_mem(struct kvm *kvm)
         |                    ^
   ./arch/arm64/include/asm/kvm_host.h:1465:45: note: expanded from macro 'kvm_arch_has_private_mem'
    1465 | #define kvm_arch_has_private_mem(kvm) ((kvm)->arch.is_realm)
         |                                             ^
   ./include/linux/kvm_host.h:725:20: note: to match this '('
   ./arch/arm64/include/asm/kvm_host.h:1465:39: note: expanded from macro 'kvm_arch_has_private_mem'
    1465 | #define kvm_arch_has_private_mem(kvm) ((kvm)->arch.is_realm)
         |                                       ^
   3 errors generated.


vim +725 ./include/linux/kvm_host.h

f481b069e67437 Paolo Bonzini       2015-05-17  723  
d1e54dd08f163a Fuad Tabba          2025-07-29  724  #ifndef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES
a7800aa80ea4d5 Sean Christopherson 2023-11-13 @725  static inline bool kvm_arch_has_private_mem(struct kvm *kvm)
a7800aa80ea4d5 Sean Christopherson 2023-11-13  726  {
a7800aa80ea4d5 Sean Christopherson 2023-11-13  727  	return false;
a7800aa80ea4d5 Sean Christopherson 2023-11-13  728  }
a7800aa80ea4d5 Sean Christopherson 2023-11-13  729  #endif
a7800aa80ea4d5 Sean Christopherson 2023-11-13  730  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From lkp at intel.com  Sat Dec 20 06:34:50 2025
From: lkp at intel.com (kernel test robot)
Date: Sat, 20 Dec 2025 22:34:50 +0800
Subject: [PATCH v12 20/46] arm64: RMI: Allow populating initial contents
In-Reply-To: <20251217101125.91098-21-steven.price@arm.com>
References: <20251217101125.91098-21-steven.price@arm.com>
Message-ID: <202512202203.1g4jywFB-lkp@intel.com>

Hi Steven,

kernel test robot noticed the following build warnings:

[auto build test WARNING on linus/master]
[also build test WARNING on v6.19-rc1 next-20251219]
[cannot apply to kvmarm/next kvm/queue kvm/next arm64/for-next/core kvm/linux-next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Steven-Price/kvm-arm64-Include-kvm_emulate-h-in-kvm-arm_psci-h/20251218-030351
base:   linus/master
patch link:    https://lore.kernel.org/r/20251217101125.91098-21-steven.price%40arm.com
patch subject: [PATCH v12 20/46] arm64: RMI: Allow populating initial contents
config: arm64-allmodconfig (https://download.01.org/0day-ci/archive/20251220/202512202203.1g4jywFB-lkp at intel.com/config)
compiler: clang version 19.1.7 (https://github.com/llvm/llvm-project cd708029e0b2869e80abe31ddb175f7c35361f90)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251220/202512202203.1g4jywFB-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512202203.1g4jywFB-lkp at intel.com/

All warnings (new ones prefixed by >>):

>> arch/arm64/kvm/rmi.c:805:16: warning: variable 'data_flags' set but not used [-Wunused-but-set-variable]
     805 |         unsigned long data_flags = 0;
         |                       ^
   1 warning generated.


vim +/data_flags +805 arch/arm64/kvm/rmi.c

   801	
   802	int kvm_arm_rmi_populate(struct kvm *kvm,
   803				 struct kvm_arm_rmi_populate *args)
   804	{
 > 805		unsigned long data_flags = 0;
   806		unsigned long ipa_start = args->base;
   807		unsigned long ipa_end = ipa_start + args->size;
   808		int ret;
   809	
   810		if (args->reserved ||
   811		    (args->flags & ~KVM_ARM_RMI_POPULATE_FLAGS_MEASURE) ||
   812		    !IS_ALIGNED(ipa_start, PAGE_SIZE) ||
   813		    !IS_ALIGNED(ipa_end, PAGE_SIZE))
   814			return -EINVAL;
   815	
   816		ret = realm_ensure_created(kvm);
   817		if (ret)
   818			return ret;
   819	
   820		if (args->flags & KVM_ARM_RMI_POPULATE_FLAGS_MEASURE)
   821			data_flags |= RMI_MEASURE_CONTENT;
   822	
   823		ret = populate_region(kvm, gpa_to_gfn(ipa_start),
   824				      args->size >> PAGE_SHIFT,
   825				      args->source_uaddr, args->flags);
   826	
   827		if (ret < 0)
   828			return ret;
   829	
   830		return ret * PAGE_SIZE;
   831	}
   832	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From rob.clark at oss.qualcomm.com  Sat Dec 20 06:35:20 2025
From: rob.clark at oss.qualcomm.com (Rob Clark)
Date: Sat, 20 Dec 2025 06:35:20 -0800
Subject: [PATCH] iommu/io-pgtable-arm: fix size_t signedness bug in unmap path
In-Reply-To: <20251219232858.51902-1-ckulkarnilinux@gmail.com>
References: <20251219232858.51902-1-ckulkarnilinux@gmail.com>
Message-ID: <CACSVV00zVbcwwZss-e52TS=aAfbWKHPGisXAVPB858CgHoNHcA@mail.gmail.com>

On Fri, Dec 19, 2025 at 3:29?PM Chaitanya Kulkarni
<ckulkarnilinux at gmail.com> wrote:
>
> __arm_lpae_unmap() returns size_t but was returning -ENOENT (negative
> error code) when encountering an unmapped PTE. Since size_t is unsigned,
> -ENOENT (typically -2) becomes a huge positive value (0xFFFFFFFFFFFFFFFE
> on 64-bit systems).
>
> This corrupted value propagates through the call chain:
>   __arm_lpae_unmap() returns -ENOENT as size_t
>   -> arm_lpae_unmap_pages() returns it
>   -> __iommu_unmap() adds it to iova address
>   -> iommu_pgsize() triggers BUG_ON due to corrupted iova
>
> This can cause IOVA address overflow in __iommu_unmap() loop and
> trigger BUG_ON in iommu_pgsize() from invalid address alignment.
>
> Fix by returning 0 instead of -ENOENT. The WARN_ON already signals
> the error condition, and returning 0 (meaning "nothing unmapped")
> is the correct semantic for size_t return type. This matches the
> behavior of other io-pgtable implementations (io-pgtable-arm-v7s,
> io-pgtable-dart) which return 0 on error conditions.
>
> Fixes: 3318f7b5cefb ("iommu/io-pgtable-arm: Add quirk to quiet WARN_ON()")
> Cc: stable at vger.kernel.org
> Signed-off-by: Chaitanya Kulkarni <ckulkarnilinux at gmail.com>

Reviewed-by: Rob Clark <robin.clark at oss.qualcomm.com>

> ---
>  drivers/iommu/io-pgtable-arm.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
> index e6626004b323..05d63fe92e43 100644
> --- a/drivers/iommu/io-pgtable-arm.c
> +++ b/drivers/iommu/io-pgtable-arm.c
> @@ -637,7 +637,7 @@ static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
>         pte = READ_ONCE(*ptep);
>         if (!pte) {
>                 WARN_ON(!(data->iop.cfg.quirks & IO_PGTABLE_QUIRK_NO_WARN));
> -               return -ENOENT;
> +               return 0;
>         }
>
>         /* If the size matches this level, we're in the right place */
> --
> 2.40.0
>


From kmal at cock.li  Sat Dec 20 06:53:08 2025
From: kmal at cock.li (kemal)
Date: Sat, 20 Dec 2025 17:53:08 +0300
Subject: [PATCH v9 16/16] selftests: sud_test: Support aarch64
In-Reply-To: <20251204082123.2792067-17-ruanjinjie@huawei.com>
References: <20251204082123.2792067-17-ruanjinjie@huawei.com>
Message-ID: <20251220145308.35716-1-kmal@cock.li>

You should also make sure TEST_BLOCKED_RETURN is defined in
sud_benchmark.c:

/*
 * To test returning from a sigsys with selector blocked, the test
 * requires some per-architecture support (i.e. knowledge about the
 * signal trampoline address).  On i386, we know it is on the vdso, and
 * a small trampoline is open-coded for x86_64.  Other architectures
 * that have a trampoline in the vdso will support TEST_BLOCKED_RETURN
 * out of the box, but don't enable them until they support syscall user
 * dispatch.
 */
#if defined(__x86_64__) || defined(__i386__) || defined(__aarch64__)
#define TEST_BLOCKED_RETURN
#endif



From lkp at intel.com  Sat Dec 20 06:59:30 2025
From: lkp at intel.com (kernel test robot)
Date: Sat, 20 Dec 2025 22:59:30 +0800
Subject: [PATCH] serial: xilinx_uartps: fix rs485 delay_rts_after_send
In-Reply-To: <20251219114826.135017-1-jakub.turek@elsta.tech>
References: <20251219114826.135017-1-jakub.turek@elsta.tech>
Message-ID: <202512202222.7nCGPOv4-lkp@intel.com>

Hi j.turek,

kernel test robot noticed the following build errors:

[auto build test ERROR on tty/tty-testing]
[also build test ERROR on tty/tty-next tty/tty-linus usb/usb-testing usb/usb-next usb/usb-linus linus/master v6.19-rc1 next-20251219]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/j-turek/serial-xilinx_uartps-fix-rs485-delay_rts_after_send/20251219-203016
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
patch link:    https://lore.kernel.org/r/20251219114826.135017-1-jakub.turek%40elsta.tech
patch subject: [PATCH] serial: xilinx_uartps: fix rs485 delay_rts_after_send
config: sh-allmodconfig (https://download.01.org/0day-ci/archive/20251220/202512202222.7nCGPOv4-lkp at intel.com/config)
compiler: sh4-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251220/202512202222.7nCGPOv4-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512202222.7nCGPOv4-lkp at intel.com/

All errors (new ones prefixed by >>):

   drivers/tty/serial/xilinx_uartps.c: In function 'cdns_uart_handle_tx':
>> drivers/tty/serial/xilinx_uartps.c:438:25: error: 'rts_delay' undeclared (first use in this function)
     438 |                         rts_delay = ns_to_ktime(cdns_calc_after_tx_delay(cdns_uart));
         |                         ^~~~~~~~~
   drivers/tty/serial/xilinx_uartps.c:438:25: note: each undeclared identifier is reported only once for each function it appears in


vim +/rts_delay +438 drivers/tty/serial/xilinx_uartps.c

   418	
   419	/**
   420	 * cdns_uart_handle_tx - Handle the bytes to be transmitted.
   421	 * @dev_id: Id of the UART port
   422	 * Return: None
   423	 */
   424	static void cdns_uart_handle_tx(void *dev_id)
   425	{
   426		struct uart_port *port = (struct uart_port *)dev_id;
   427		struct cdns_uart *cdns_uart = port->private_data;
   428		struct tty_port *tport = &port->state->port;
   429		unsigned int numbytes;
   430		unsigned char ch;
   431	
   432		if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
   433			/* Disable the TX Empty interrupt */
   434			writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR);
   435			/* Set RTS line after delay */
   436			if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) {
   437				cdns_uart->tx_timer.function = &cdns_rs485_rx_callback;
 > 438				rts_delay = ns_to_ktime(cdns_calc_after_tx_delay(cdns_uart));
   439				hrtimer_start(&cdns_uart->tx_timer, rts_delay, HRTIMER_MODE_REL);
   440			}
   441			return;
   442		}
   443	
   444		numbytes = port->fifosize;
   445		while (numbytes &&
   446		       !(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL) &&
   447		       uart_fifo_get(port, &ch)) {
   448			writel(ch, port->membase + CDNS_UART_FIFO);
   449			numbytes--;
   450		}
   451	
   452		if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
   453			uart_write_wakeup(port);
   454	
   455		/* Enable the TX Empty interrupt */
   456		writel(CDNS_UART_IXR_TXEMPTY, cdns_uart->port->membase + CDNS_UART_IER);
   457	}
   458	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From lkp at intel.com  Sat Dec 20 07:22:25 2025
From: lkp at intel.com (kernel test robot)
Date: Sat, 20 Dec 2025 23:22:25 +0800
Subject: [PATCH] serial: xilinx_uartps: fix rs485 delay_rts_after_send
In-Reply-To: <20251219114826.135017-1-jakub.turek@elsta.tech>
References: <20251219114826.135017-1-jakub.turek@elsta.tech>
Message-ID: <202512202351.ovK2vDUR-lkp@intel.com>

Hi j.turek,

kernel test robot noticed the following build errors:

[auto build test ERROR on tty/tty-testing]
[also build test ERROR on tty/tty-next tty/tty-linus usb/usb-testing usb/usb-next usb/usb-linus linus/master v6.19-rc1 next-20251219]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/j-turek/serial-xilinx_uartps-fix-rs485-delay_rts_after_send/20251219-203016
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
patch link:    https://lore.kernel.org/r/20251219114826.135017-1-jakub.turek%40elsta.tech
patch subject: [PATCH] serial: xilinx_uartps: fix rs485 delay_rts_after_send
config: hexagon-allmodconfig (https://download.01.org/0day-ci/archive/20251220/202512202351.ovK2vDUR-lkp at intel.com/config)
compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251220/202512202351.ovK2vDUR-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512202351.ovK2vDUR-lkp at intel.com/

All errors (new ones prefixed by >>):

>> drivers/tty/serial/xilinx_uartps.c:438:4: error: use of undeclared identifier 'rts_delay'
     438 |                         rts_delay = ns_to_ktime(cdns_calc_after_tx_delay(cdns_uart));
         |                         ^
   drivers/tty/serial/xilinx_uartps.c:439:40: error: use of undeclared identifier 'rts_delay'; did you mean '__delay'?
     439 |                         hrtimer_start(&cdns_uart->tx_timer, rts_delay, HRTIMER_MODE_REL);
         |                                                             ^~~~~~~~~
         |                                                             __delay
   arch/hexagon/include/asm/delay.h:11:13: note: '__delay' declared here
      11 | extern void __delay(unsigned long cycles);
         |             ^
   2 errors generated.


vim +/rts_delay +438 drivers/tty/serial/xilinx_uartps.c

   418	
   419	/**
   420	 * cdns_uart_handle_tx - Handle the bytes to be transmitted.
   421	 * @dev_id: Id of the UART port
   422	 * Return: None
   423	 */
   424	static void cdns_uart_handle_tx(void *dev_id)
   425	{
   426		struct uart_port *port = (struct uart_port *)dev_id;
   427		struct cdns_uart *cdns_uart = port->private_data;
   428		struct tty_port *tport = &port->state->port;
   429		unsigned int numbytes;
   430		unsigned char ch;
   431	
   432		if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
   433			/* Disable the TX Empty interrupt */
   434			writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR);
   435			/* Set RTS line after delay */
   436			if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) {
   437				cdns_uart->tx_timer.function = &cdns_rs485_rx_callback;
 > 438				rts_delay = ns_to_ktime(cdns_calc_after_tx_delay(cdns_uart));
   439				hrtimer_start(&cdns_uart->tx_timer, rts_delay, HRTIMER_MODE_REL);
   440			}
   441			return;
   442		}
   443	
   444		numbytes = port->fifosize;
   445		while (numbytes &&
   446		       !(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL) &&
   447		       uart_fifo_get(port, &ch)) {
   448			writel(ch, port->membase + CDNS_UART_FIFO);
   449			numbytes--;
   450		}
   451	
   452		if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
   453			uart_write_wakeup(port);
   454	
   455		/* Enable the TX Empty interrupt */
   456		writel(CDNS_UART_IXR_TXEMPTY, cdns_uart->port->membase + CDNS_UART_IER);
   457	}
   458	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From h.jain at amd.com  Sat Dec 20 07:58:51 2025
From: h.jain at amd.com (Harsh Jain)
Date: Sat, 20 Dec 2025 21:28:51 +0530
Subject: [PATCH v2 00/14] crypto: zynqmp-aes-gcm: Bug fixes and aes-gcm support for Versal
Message-ID: <20251220155905.346790-1-h.jain@amd.com>

This series includes bug fixes and adds aes-gcm support for Versal device.
It is based on cryptodev-2.6 tree.

Changes in V2:
- Rebase series to cryptodev-2.6
- Register H/W keys with gcm(paes) 

Harsh Jain (14):
  firmware: zynqmp: Move crypto API's to separate file
  crypto: zynqmp-aes-gcm: cleanup: Remove union from zynqmp_aead_drv_ctx
  firmware: zynqmp: Add helper API to self discovery the device
  dt-bindings: crypto: Mark zynqmp-aes as Deprecated
  crypto: zynqmp-aes-gcm: Update probe to self discover the device
  crypto: zynqmp-aes-gcm: Return linux error code instead of firmware
    error code
  crypto: zynqmp-aes-gcm: Avoid Encrypt request to fallback for authsize
    < 16
  crypto: zynqmp-aes-gcm: Avoid submitting fallback requests to engine
  crypto: zynqmp-aes-gcm: Register H/W key support with paes
  crypto: xilinx: Replace zynqmp prefix with xilinx
  crypto: zynqmp-aes-gcm: Change coherent DMA to streaming DMA API
  firmware: xilinx: Add firmware API's to support aes-gcm in Versal
    device
  crypto: xilinx: cleanup: Remove un-necessary typecast operation
  crypto: xilinx: Add gcm(aes) support for AMD/Xilinx Versal device

 .../bindings/crypto/xlnx,zynqmp-aes.yaml      |    2 +
 .../firmware/xilinx/xlnx,zynqmp-firmware.yaml |    1 +
 drivers/crypto/xilinx/zynqmp-aes-gcm.c        | 1007 +++++++++++++----
 drivers/firmware/xilinx/Makefile              |    2 +-
 drivers/firmware/xilinx/zynqmp-crypto.c       |  239 ++++
 drivers/firmware/xilinx/zynqmp.c              |   49 -
 include/linux/firmware/xlnx-zynqmp-crypto.h   |  119 ++
 include/linux/firmware/xlnx-zynqmp.h          |   14 +-
 8 files changed, 1155 insertions(+), 278 deletions(-)
 create mode 100644 drivers/firmware/xilinx/zynqmp-crypto.c
 create mode 100644 include/linux/firmware/xlnx-zynqmp-crypto.h

-- 
2.49.1



From h.jain at amd.com  Sat Dec 20 07:58:52 2025
From: h.jain at amd.com (Harsh Jain)
Date: Sat, 20 Dec 2025 21:28:52 +0530
Subject: [PATCH v2 01/14] firmware: zynqmp: Move crypto API's to separate file
In-Reply-To: <20251220155905.346790-1-h.jain@amd.com>
References: <20251220155905.346790-1-h.jain@amd.com>
Message-ID: <20251220155905.346790-2-h.jain@amd.com>

For better maintainability move crypto related API's to
new zynqmp-crypto.c file.

Signed-off-by: Harsh Jain <h.jain at amd.com>
---
 drivers/firmware/xilinx/Makefile            |  2 +-
 drivers/firmware/xilinx/zynqmp-crypto.c     | 59 +++++++++++++++++++++
 drivers/firmware/xilinx/zynqmp.c            | 49 -----------------
 include/linux/firmware/xlnx-zynqmp-crypto.h | 28 ++++++++++
 include/linux/firmware/xlnx-zynqmp.h        | 14 +----
 5 files changed, 89 insertions(+), 63 deletions(-)
 create mode 100644 drivers/firmware/xilinx/zynqmp-crypto.c
 create mode 100644 include/linux/firmware/xlnx-zynqmp-crypto.h

diff --git a/drivers/firmware/xilinx/Makefile b/drivers/firmware/xilinx/Makefile
index 70f8f02f14a3..8db0e66b6b7e 100644
--- a/drivers/firmware/xilinx/Makefile
+++ b/drivers/firmware/xilinx/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
 # Makefile for Xilinx firmwares
 
-obj-$(CONFIG_ZYNQMP_FIRMWARE) += zynqmp.o zynqmp-ufs.o
+obj-$(CONFIG_ZYNQMP_FIRMWARE) += zynqmp.o zynqmp-ufs.o zynqmp-crypto.o
 obj-$(CONFIG_ZYNQMP_FIRMWARE_DEBUG) += zynqmp-debug.o
diff --git a/drivers/firmware/xilinx/zynqmp-crypto.c b/drivers/firmware/xilinx/zynqmp-crypto.c
new file mode 100644
index 000000000000..ea9cac6a1052
--- /dev/null
+++ b/drivers/firmware/xilinx/zynqmp-crypto.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Firmware layer for XilSecure APIs.
+ *
+ * Copyright (C) 2014-2022 Xilinx, Inc.
+ * Copyright (C) 2022-2025 Advanced Micro Devices, Inc.
+ */
+
+#include <linux/firmware/xlnx-zynqmp.h>
+#include <linux/module.h>
+
+/**
+ * zynqmp_pm_aes_engine - Access AES hardware to encrypt/decrypt the data using
+ * AES-GCM core.
+ * @address:	Address of the AesParams structure.
+ * @out:	Returned output value
+ *
+ * Return:	Returns status, either success or error code.
+ */
+int zynqmp_pm_aes_engine(const u64 address, u32 *out)
+{
+	u32 ret_payload[PAYLOAD_ARG_CNT];
+	int ret;
+
+	if (!out)
+		return -EINVAL;
+
+	ret = zynqmp_pm_invoke_fn(PM_SECURE_AES, ret_payload, 2, upper_32_bits(address),
+				  lower_32_bits(address));
+	*out = ret_payload[1];
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(zynqmp_pm_aes_engine);
+
+/**
+ * zynqmp_pm_sha_hash - Access the SHA engine to calculate the hash
+ * @address:	Address of the data/ Address of output buffer where
+ *		hash should be stored.
+ * @size:	Size of the data.
+ * @flags:
+ *		BIT(0) - for initializing csudma driver and SHA3(Here address
+ *		and size inputs can be NULL).
+ *		BIT(1) - to call Sha3_Update API which can be called multiple
+ *		times when data is not contiguous.
+ *		BIT(2) - to get final hash of the whole updated data.
+ *		Hash will be overwritten at provided address with
+ *		48 bytes.
+ *
+ * Return:	Returns status, either success or error code.
+ */
+int zynqmp_pm_sha_hash(const u64 address, const u32 size, const u32 flags)
+{
+	u32 lower_addr = lower_32_bits(address);
+	u32 upper_addr = upper_32_bits(address);
+
+	return zynqmp_pm_invoke_fn(PM_SECURE_SHA, NULL, 4, upper_addr, lower_addr, size, flags);
+}
+EXPORT_SYMBOL_GPL(zynqmp_pm_sha_hash);
diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c
index ad811f40e059..f15db1a818dc 100644
--- a/drivers/firmware/xilinx/zynqmp.c
+++ b/drivers/firmware/xilinx/zynqmp.c
@@ -1521,30 +1521,6 @@ int zynqmp_pm_load_pdi(const u32 src, const u64 address)
 }
 EXPORT_SYMBOL_GPL(zynqmp_pm_load_pdi);
 
-/**
- * zynqmp_pm_aes_engine - Access AES hardware to encrypt/decrypt the data using
- * AES-GCM core.
- * @address:	Address of the AesParams structure.
- * @out:	Returned output value
- *
- * Return:	Returns status, either success or error code.
- */
-int zynqmp_pm_aes_engine(const u64 address, u32 *out)
-{
-	u32 ret_payload[PAYLOAD_ARG_CNT];
-	int ret;
-
-	if (!out)
-		return -EINVAL;
-
-	ret = zynqmp_pm_invoke_fn(PM_SECURE_AES, ret_payload, 2, upper_32_bits(address),
-				  lower_32_bits(address));
-	*out = ret_payload[1];
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(zynqmp_pm_aes_engine);
-
 /**
  * zynqmp_pm_efuse_access - Provides access to efuse memory.
  * @address:	Address of the efuse params structure
@@ -1569,31 +1545,6 @@ int zynqmp_pm_efuse_access(const u64 address, u32 *out)
 }
 EXPORT_SYMBOL_GPL(zynqmp_pm_efuse_access);
 
-/**
- * zynqmp_pm_sha_hash - Access the SHA engine to calculate the hash
- * @address:	Address of the data/ Address of output buffer where
- *		hash should be stored.
- * @size:	Size of the data.
- * @flags:
- *	BIT(0) - for initializing csudma driver and SHA3(Here address
- *		 and size inputs can be NULL).
- *	BIT(1) - to call Sha3_Update API which can be called multiple
- *		 times when data is not contiguous.
- *	BIT(2) - to get final hash of the whole updated data.
- *		 Hash will be overwritten at provided address with
- *		 48 bytes.
- *
- * Return:	Returns status, either success or error code.
- */
-int zynqmp_pm_sha_hash(const u64 address, const u32 size, const u32 flags)
-{
-	u32 lower_addr = lower_32_bits(address);
-	u32 upper_addr = upper_32_bits(address);
-
-	return zynqmp_pm_invoke_fn(PM_SECURE_SHA, NULL, 4, upper_addr, lower_addr, size, flags);
-}
-EXPORT_SYMBOL_GPL(zynqmp_pm_sha_hash);
-
 /**
  * zynqmp_pm_register_notifier() - PM API for register a subsystem
  *                                to be notified about specific
diff --git a/include/linux/firmware/xlnx-zynqmp-crypto.h b/include/linux/firmware/xlnx-zynqmp-crypto.h
new file mode 100644
index 000000000000..f9eb523ba6a0
--- /dev/null
+++ b/include/linux/firmware/xlnx-zynqmp-crypto.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Firmware layer for XilSECURE APIs.
+ *
+ *  Copyright (C) 2014-2022 Xilinx, Inc.
+ *  Copyright (C) 2022-2025 Advanced Micro Devices, Inc.
+ */
+
+#ifndef __FIRMWARE_XLNX_ZYNQMP_CRYPTO_H__
+#define __FIRMWARE_XLNX_ZYNQMP_CRYPTO_H__
+
+#if IS_REACHABLE(CONFIG_ZYNQMP_FIRMWARE)
+int zynqmp_pm_aes_engine(const u64 address, u32 *out);
+int zynqmp_pm_sha_hash(const u64 address, const u32 size, const u32 flags);
+#else
+static inline int zynqmp_pm_aes_engine(const u64 address, u32 *out)
+{
+	return -ENODEV;
+}
+
+static inline int zynqmp_pm_sha_hash(const u64 address, const u32 size,
+				     const u32 flags)
+{
+	return -ENODEV;
+}
+#endif
+
+#endif /* __FIRMWARE_XLNX_ZYNQMP_CRYPTO_H__ */
diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h
index 15fdbd089bbf..d70dcd462b44 100644
--- a/include/linux/firmware/xlnx-zynqmp.h
+++ b/include/linux/firmware/xlnx-zynqmp.h
@@ -17,6 +17,7 @@
 
 #include <linux/err.h>
 #include <linux/firmware/xlnx-zynqmp-ufs.h>
+#include <linux/firmware/xlnx-zynqmp-crypto.h>
 
 #define ZYNQMP_PM_VERSION_MAJOR	1
 #define ZYNQMP_PM_VERSION_MINOR	0
@@ -589,9 +590,7 @@ int zynqmp_pm_release_node(const u32 node);
 int zynqmp_pm_set_requirement(const u32 node, const u32 capabilities,
 			      const u32 qos,
 			      const enum zynqmp_pm_request_ack ack);
-int zynqmp_pm_aes_engine(const u64 address, u32 *out);
 int zynqmp_pm_efuse_access(const u64 address, u32 *out);
-int zynqmp_pm_sha_hash(const u64 address, const u32 size, const u32 flags);
 int zynqmp_pm_fpga_load(const u64 address, const u32 size, const u32 flags);
 int zynqmp_pm_fpga_get_status(u32 *value);
 int zynqmp_pm_fpga_get_config_status(u32 *value);
@@ -772,22 +771,11 @@ static inline int zynqmp_pm_set_requirement(const u32 node,
 	return -ENODEV;
 }
 
-static inline int zynqmp_pm_aes_engine(const u64 address, u32 *out)
-{
-	return -ENODEV;
-}
-
 static inline int zynqmp_pm_efuse_access(const u64 address, u32 *out)
 {
 	return -ENODEV;
 }
 
-static inline int zynqmp_pm_sha_hash(const u64 address, const u32 size,
-				     const u32 flags)
-{
-	return -ENODEV;
-}
-
 static inline int zynqmp_pm_fpga_load(const u64 address, const u32 size,
 				      const u32 flags)
 {
-- 
2.49.1



From h.jain at amd.com  Sat Dec 20 07:58:54 2025
From: h.jain at amd.com (Harsh Jain)
Date: Sat, 20 Dec 2025 21:28:54 +0530
Subject: [PATCH v2 03/14] firmware: zynqmp: Add helper API to self discovery the device
In-Reply-To: <20251220155905.346790-1-h.jain@amd.com>
References: <20251220155905.346790-1-h.jain@amd.com>
Message-ID: <20251220155905.346790-4-h.jain@amd.com>

Add API to get SoC version and family info.

Signed-off-by: Harsh Jain <h.jain at amd.com>
---
 drivers/firmware/xilinx/zynqmp-crypto.c     | 31 +++++++++++++++++++++
 include/linux/firmware/xlnx-zynqmp-crypto.h | 19 +++++++++++++
 2 files changed, 50 insertions(+)

diff --git a/drivers/firmware/xilinx/zynqmp-crypto.c b/drivers/firmware/xilinx/zynqmp-crypto.c
index ea9cac6a1052..6d17cb8b27b3 100644
--- a/drivers/firmware/xilinx/zynqmp-crypto.c
+++ b/drivers/firmware/xilinx/zynqmp-crypto.c
@@ -57,3 +57,34 @@ int zynqmp_pm_sha_hash(const u64 address, const u32 size, const u32 flags)
 	return zynqmp_pm_invoke_fn(PM_SECURE_SHA, NULL, 4, upper_addr, lower_addr, size, flags);
 }
 EXPORT_SYMBOL_GPL(zynqmp_pm_sha_hash);
+
+/**
+ * xlnx_get_crypto_dev_data() - Get crypto dev data of platform
+ * @feature_map:       List of available feature map of all platform
+ *
+ * Return: Returns crypto dev data, either address crypto dev or ERR PTR
+ */
+void *xlnx_get_crypto_dev_data(struct xlnx_feature *feature_map)
+{
+	struct xlnx_feature *feature;
+	u32 pm_family_code;
+	int ret;
+
+	/* Get the Family code and sub family code of platform */
+	ret = zynqmp_pm_get_family_info(&pm_family_code);
+	if (ret < 0)
+		return ERR_PTR(ret);
+
+	feature = feature_map;
+	for (; feature->family; feature++) {
+		if (feature->family == pm_family_code) {
+			ret = zynqmp_pm_feature(feature->feature_id);
+			if (ret < 0)
+				return ERR_PTR(ret);
+
+			return feature->data;
+		}
+	}
+	return ERR_PTR(-ENODEV);
+}
+EXPORT_SYMBOL_GPL(xlnx_get_crypto_dev_data);
diff --git a/include/linux/firmware/xlnx-zynqmp-crypto.h b/include/linux/firmware/xlnx-zynqmp-crypto.h
index f9eb523ba6a0..cb08f412e931 100644
--- a/include/linux/firmware/xlnx-zynqmp-crypto.h
+++ b/include/linux/firmware/xlnx-zynqmp-crypto.h
@@ -9,9 +9,23 @@
 #ifndef __FIRMWARE_XLNX_ZYNQMP_CRYPTO_H__
 #define __FIRMWARE_XLNX_ZYNQMP_CRYPTO_H__
 
+/**
+ * struct xlnx_feature - Feature data
+ * @family:	Family code of platform
+ * @subfamily:	Subfamily code of platform
+ * @feature_id:	Feature id of module
+ * @data:	Collection of all supported platform data
+ */
+struct xlnx_feature {
+	u32 family;
+	u32 feature_id;
+	void *data;
+};
+
 #if IS_REACHABLE(CONFIG_ZYNQMP_FIRMWARE)
 int zynqmp_pm_aes_engine(const u64 address, u32 *out);
 int zynqmp_pm_sha_hash(const u64 address, const u32 size, const u32 flags);
+void *xlnx_get_crypto_dev_data(struct xlnx_feature *feature_map);
 #else
 static inline int zynqmp_pm_aes_engine(const u64 address, u32 *out)
 {
@@ -23,6 +37,11 @@ static inline int zynqmp_pm_sha_hash(const u64 address, const u32 size,
 {
 	return -ENODEV;
 }
+
+static inline void *xlnx_get_crypto_dev_data(struct xlnx_feature *feature_map)
+{
+	return ERR_PTR(-ENODEV);
+}
 #endif
 
 #endif /* __FIRMWARE_XLNX_ZYNQMP_CRYPTO_H__ */
-- 
2.49.1



From h.jain at amd.com  Sat Dec 20 07:58:53 2025
From: h.jain at amd.com (Harsh Jain)
Date: Sat, 20 Dec 2025 21:28:53 +0530
Subject: [PATCH v2 02/14] crypto: zynqmp-aes-gcm: cleanup: Remove union from zynqmp_aead_drv_ctx
In-Reply-To: <20251220155905.346790-1-h.jain@amd.com>
References: <20251220155905.346790-1-h.jain@amd.com>
Message-ID: <20251220155905.346790-3-h.jain@amd.com>

"alg" in zynqmp_aead_drv_ctx is single field union variable.
Remove unnecessary alg union from structure.

Signed-off-by: Harsh Jain <h.jain at amd.com>
---
 drivers/crypto/xilinx/zynqmp-aes-gcm.c | 24 +++++++++++-------------
 1 file changed, 11 insertions(+), 13 deletions(-)

diff --git a/drivers/crypto/xilinx/zynqmp-aes-gcm.c b/drivers/crypto/xilinx/zynqmp-aes-gcm.c
index 6e72d9229410..3ce1319d1a1a 100644
--- a/drivers/crypto/xilinx/zynqmp-aes-gcm.c
+++ b/drivers/crypto/xilinx/zynqmp-aes-gcm.c
@@ -43,9 +43,7 @@ enum zynqmp_aead_keysrc {
 };
 
 struct zynqmp_aead_drv_ctx {
-	union {
-		struct aead_engine_alg aead;
-	} alg;
+	struct aead_engine_alg aead;
 	struct device *dev;
 	struct crypto_engine *engine;
 };
@@ -289,7 +287,7 @@ static int zynqmp_aes_aead_encrypt(struct aead_request *req)
 	struct zynqmp_aead_req_ctx *rq_ctx = aead_request_ctx(req);
 
 	rq_ctx->op = ZYNQMP_AES_ENCRYPT;
-	drv_ctx = container_of(alg, struct zynqmp_aead_drv_ctx, alg.aead.base);
+	drv_ctx = container_of(alg, struct zynqmp_aead_drv_ctx, aead.base);
 
 	return crypto_transfer_aead_request_to_engine(drv_ctx->engine, req);
 }
@@ -302,7 +300,7 @@ static int zynqmp_aes_aead_decrypt(struct aead_request *req)
 	struct zynqmp_aead_req_ctx *rq_ctx = aead_request_ctx(req);
 
 	rq_ctx->op = ZYNQMP_AES_DECRYPT;
-	drv_ctx = container_of(alg, struct zynqmp_aead_drv_ctx, alg.aead.base);
+	drv_ctx = container_of(alg, struct zynqmp_aead_drv_ctx, aead.base);
 
 	return crypto_transfer_aead_request_to_engine(drv_ctx->engine, req);
 }
@@ -315,16 +313,16 @@ static int zynqmp_aes_aead_init(struct crypto_aead *aead)
 	struct zynqmp_aead_drv_ctx *drv_ctx;
 	struct aead_alg *alg = crypto_aead_alg(aead);
 
-	drv_ctx = container_of(alg, struct zynqmp_aead_drv_ctx, alg.aead.base);
+	drv_ctx = container_of(alg, struct zynqmp_aead_drv_ctx, aead.base);
 	tfm_ctx->dev = drv_ctx->dev;
 
-	tfm_ctx->fbk_cipher = crypto_alloc_aead(drv_ctx->alg.aead.base.base.cra_name,
+	tfm_ctx->fbk_cipher = crypto_alloc_aead(drv_ctx->aead.base.base.cra_name,
 						0,
 						CRYPTO_ALG_NEED_FALLBACK);
 
 	if (IS_ERR(tfm_ctx->fbk_cipher)) {
 		pr_err("%s() Error: failed to allocate fallback for %s\n",
-		       __func__, drv_ctx->alg.aead.base.base.cra_name);
+		       __func__, drv_ctx->aead.base.base.cra_name);
 		return PTR_ERR(tfm_ctx->fbk_cipher);
 	}
 
@@ -349,7 +347,7 @@ static void zynqmp_aes_aead_exit(struct crypto_aead *aead)
 }
 
 static struct zynqmp_aead_drv_ctx aes_drv_ctx = {
-	.alg.aead.base = {
+	.aead.base = {
 		.setkey		= zynqmp_aes_aead_setkey,
 		.setauthsize	= zynqmp_aes_aead_setauthsize,
 		.encrypt	= zynqmp_aes_aead_encrypt,
@@ -372,7 +370,7 @@ static struct zynqmp_aead_drv_ctx aes_drv_ctx = {
 		.cra_module		= THIS_MODULE,
 		}
 	},
-	.alg.aead.op = {
+	.aead.op = {
 		.do_one_request = zynqmp_handle_aes_req,
 	},
 };
@@ -407,7 +405,7 @@ static int zynqmp_aes_aead_probe(struct platform_device *pdev)
 		goto err_engine;
 	}
 
-	err = crypto_engine_register_aead(&aes_drv_ctx.alg.aead);
+	err = crypto_engine_register_aead(&aes_drv_ctx.aead);
 	if (err < 0) {
 		dev_err(dev, "Failed to register AEAD alg.\n");
 		goto err_aead;
@@ -415,7 +413,7 @@ static int zynqmp_aes_aead_probe(struct platform_device *pdev)
 	return 0;
 
 err_aead:
-	crypto_engine_unregister_aead(&aes_drv_ctx.alg.aead);
+	crypto_engine_unregister_aead(&aes_drv_ctx.aead);
 
 err_engine:
 	if (aes_drv_ctx.engine)
@@ -427,7 +425,7 @@ static int zynqmp_aes_aead_probe(struct platform_device *pdev)
 static void zynqmp_aes_aead_remove(struct platform_device *pdev)
 {
 	crypto_engine_exit(aes_drv_ctx.engine);
-	crypto_engine_unregister_aead(&aes_drv_ctx.alg.aead);
+	crypto_engine_unregister_aead(&aes_drv_ctx.aead);
 }
 
 static const struct of_device_id zynqmp_aes_dt_ids[] = {
-- 
2.49.1



From h.jain at amd.com  Sat Dec 20 07:58:56 2025
From: h.jain at amd.com (Harsh Jain)
Date: Sat, 20 Dec 2025 21:28:56 +0530
Subject: [PATCH v2 05/14] crypto: zynqmp-aes-gcm: Update probe to self discover the device
In-Reply-To: <20251220155905.346790-1-h.jain@amd.com>
References: <20251220155905.346790-1-h.jain@amd.com>
Message-ID: <20251220155905.346790-6-h.jain@amd.com>

Update driver to self discover the device.

Signed-off-by: Harsh Jain <h.jain at amd.com>
---
 drivers/crypto/xilinx/zynqmp-aes-gcm.c | 86 +++++++++++++++++++-------
 1 file changed, 62 insertions(+), 24 deletions(-)

diff --git a/drivers/crypto/xilinx/zynqmp-aes-gcm.c b/drivers/crypto/xilinx/zynqmp-aes-gcm.c
index 3ce1319d1a1a..04473ed9f08d 100644
--- a/drivers/crypto/xilinx/zynqmp-aes-gcm.c
+++ b/drivers/crypto/xilinx/zynqmp-aes-gcm.c
@@ -346,7 +346,7 @@ static void zynqmp_aes_aead_exit(struct crypto_aead *aead)
 	memzero_explicit(tfm_ctx, sizeof(struct zynqmp_aead_tfm_ctx));
 }
 
-static struct zynqmp_aead_drv_ctx aes_drv_ctx = {
+static struct zynqmp_aead_drv_ctx zynqmp_aes_drv_ctx = {
 	.aead.base = {
 		.setkey		= zynqmp_aes_aead_setkey,
 		.setauthsize	= zynqmp_aes_aead_setauthsize,
@@ -375,74 +375,112 @@ static struct zynqmp_aead_drv_ctx aes_drv_ctx = {
 	},
 };
 
+static struct xlnx_feature aes_feature_map[] = {
+	{
+		.family = PM_ZYNQMP_FAMILY_CODE,
+		.feature_id = PM_SECURE_AES,
+		.data = &zynqmp_aes_drv_ctx,
+	},
+	{ /* sentinel */ }
+};
+
 static int zynqmp_aes_aead_probe(struct platform_device *pdev)
 {
+	struct zynqmp_aead_drv_ctx *aes_drv_ctx;
 	struct device *dev = &pdev->dev;
 	int err;
 
+	/* Verify the hardware is present */
+	aes_drv_ctx = xlnx_get_crypto_dev_data(aes_feature_map);
+	if (IS_ERR(aes_drv_ctx)) {
+		dev_err(dev, "AES is not supported on the platform\n");
+		return PTR_ERR(aes_drv_ctx);
+	}
+
 	/* ZynqMP AES driver supports only one instance */
-	if (!aes_drv_ctx.dev)
-		aes_drv_ctx.dev = dev;
+	if (!aes_drv_ctx->dev)
+		aes_drv_ctx->dev = dev;
 	else
 		return -ENODEV;
 
+	platform_set_drvdata(pdev, aes_drv_ctx);
 	err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(ZYNQMP_DMA_BIT_MASK));
 	if (err < 0) {
 		dev_err(dev, "No usable DMA configuration\n");
 		return err;
 	}
 
-	aes_drv_ctx.engine = crypto_engine_alloc_init(dev, 1);
-	if (!aes_drv_ctx.engine) {
+	aes_drv_ctx->engine = crypto_engine_alloc_init(dev, 1);
+	if (!aes_drv_ctx->engine) {
 		dev_err(dev, "Cannot alloc AES engine\n");
 		err = -ENOMEM;
 		goto err_engine;
 	}
 
-	err = crypto_engine_start(aes_drv_ctx.engine);
+	err = crypto_engine_start(aes_drv_ctx->engine);
 	if (err) {
 		dev_err(dev, "Cannot start AES engine\n");
 		goto err_engine;
 	}
 
-	err = crypto_engine_register_aead(&aes_drv_ctx.aead);
+	err = crypto_engine_register_aead(&aes_drv_ctx->aead);
 	if (err < 0) {
 		dev_err(dev, "Failed to register AEAD alg.\n");
-		goto err_aead;
+		goto err_engine;
 	}
 	return 0;
 
-err_aead:
-	crypto_engine_unregister_aead(&aes_drv_ctx.aead);
-
 err_engine:
-	if (aes_drv_ctx.engine)
-		crypto_engine_exit(aes_drv_ctx.engine);
+	if (aes_drv_ctx->engine)
+		crypto_engine_exit(aes_drv_ctx->engine);
 
 	return err;
 }
 
 static void zynqmp_aes_aead_remove(struct platform_device *pdev)
 {
-	crypto_engine_exit(aes_drv_ctx.engine);
-	crypto_engine_unregister_aead(&aes_drv_ctx.aead);
-}
+	struct zynqmp_aead_drv_ctx *aes_drv_ctx;
 
-static const struct of_device_id zynqmp_aes_dt_ids[] = {
-	{ .compatible = "xlnx,zynqmp-aes" },
-	{ /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, zynqmp_aes_dt_ids);
+	aes_drv_ctx = platform_get_drvdata(pdev);
+	crypto_engine_exit(aes_drv_ctx->engine);
+	crypto_engine_unregister_aead(&aes_drv_ctx->aead);
+}
 
 static struct platform_driver zynqmp_aes_driver = {
 	.probe	= zynqmp_aes_aead_probe,
 	.remove = zynqmp_aes_aead_remove,
 	.driver = {
 		.name		= "zynqmp-aes",
-		.of_match_table = zynqmp_aes_dt_ids,
 	},
 };
 
-module_platform_driver(zynqmp_aes_driver);
-MODULE_DESCRIPTION("Xilinx ZynqMP AES Driver");
+static struct platform_device *platform_dev;
+
+static int __init aes_driver_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&zynqmp_aes_driver);
+	if (ret)
+		return ret;
+
+	platform_dev = platform_device_register_simple(zynqmp_aes_driver.driver.name,
+						       0, NULL, 0);
+	if (IS_ERR(platform_dev)) {
+		ret = PTR_ERR(platform_dev);
+		platform_driver_unregister(&zynqmp_aes_driver);
+	}
+
+	return ret;
+}
+
+static void __exit aes_driver_exit(void)
+{
+	platform_device_unregister(platform_dev);
+	platform_driver_unregister(&zynqmp_aes_driver);
+}
+
+module_init(aes_driver_init);
+module_exit(aes_driver_exit);
+MODULE_DESCRIPTION("zynqmp aes-gcm hardware acceleration support.");
 MODULE_LICENSE("GPL");
-- 
2.49.1



From h.jain at amd.com  Sat Dec 20 07:58:55 2025
From: h.jain at amd.com (Harsh Jain)
Date: Sat, 20 Dec 2025 21:28:55 +0530
Subject: [PATCH v2 04/14] dt-bindings: crypto: Mark zynqmp-aes as Deprecated
In-Reply-To: <20251220155905.346790-1-h.jain@amd.com>
References: <20251220155905.346790-1-h.jain@amd.com>
Message-ID: <20251220155905.346790-5-h.jain@amd.com>

zynqmp-aes-gcm updated to self discover, corresponding dt binding
can be mark deprecated.

Signed-off-by: Harsh Jain <h.jain at amd.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
---
 Documentation/devicetree/bindings/crypto/xlnx,zynqmp-aes.yaml   | 2 ++
 .../bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml          | 1 +
 2 files changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/crypto/xlnx,zynqmp-aes.yaml b/Documentation/devicetree/bindings/crypto/xlnx,zynqmp-aes.yaml
index 8aead97a585b..20134d1d0f49 100644
--- a/Documentation/devicetree/bindings/crypto/xlnx,zynqmp-aes.yaml
+++ b/Documentation/devicetree/bindings/crypto/xlnx,zynqmp-aes.yaml
@@ -14,6 +14,8 @@ description: |
   The ZynqMP AES-GCM hardened cryptographic accelerator is used to
   encrypt or decrypt the data with provided key and initialization vector.
 
+deprecated: true
+
 properties:
   compatible:
     const: xlnx,zynqmp-aes
diff --git a/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml b/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml
index ab8f32c440df..9b6066c7ffe4 100644
--- a/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml
+++ b/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml
@@ -104,6 +104,7 @@ properties:
       used to encrypt or decrypt the data with provided key and initialization
       vector.
     type: object
+    deprecated: true
 
 required:
   - compatible
-- 
2.49.1



From h.jain at amd.com  Sat Dec 20 07:58:57 2025
From: h.jain at amd.com (Harsh Jain)
Date: Sat, 20 Dec 2025 21:28:57 +0530
Subject: [PATCH v2 06/14] crypto: zynqmp-aes-gcm: Return linux error code instead of firmware error code
In-Reply-To: <20251220155905.346790-1-h.jain@amd.com>
References: <20251220155905.346790-1-h.jain@amd.com>
Message-ID: <20251220155905.346790-7-h.jain@amd.com>

Convert FW error code to linux error code and remove dmesg error print for
authentication tag mismatch failure.

Signed-off-by: Harsh Jain <h.jain at amd.com>
---
 drivers/crypto/xilinx/zynqmp-aes-gcm.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/crypto/xilinx/zynqmp-aes-gcm.c b/drivers/crypto/xilinx/zynqmp-aes-gcm.c
index 04473ed9f08d..e64316d9cabf 100644
--- a/drivers/crypto/xilinx/zynqmp-aes-gcm.c
+++ b/drivers/crypto/xilinx/zynqmp-aes-gcm.c
@@ -85,7 +85,6 @@ static int zynqmp_aes_aead_cipher(struct aead_request *req)
 	int ret;
 	size_t dma_size;
 	char *kbuf;
-	int err;
 
 	if (tfm_ctx->keysrc == ZYNQMP_AES_KUP_KEY)
 		dma_size = req->cryptlen + ZYNQMP_AES_KEY_SIZE
@@ -132,23 +131,23 @@ static int zynqmp_aes_aead_cipher(struct aead_request *req)
 
 	if (ret) {
 		dev_err(dev, "ERROR: AES PM API failed\n");
-		err = ret;
 	} else if (status) {
 		switch (status) {
 		case ZYNQMP_AES_GCM_TAG_MISMATCH_ERR:
-			dev_err(dev, "ERROR: Gcm Tag mismatch\n");
+			ret = -EBADMSG;
 			break;
 		case ZYNQMP_AES_WRONG_KEY_SRC_ERR:
+			ret = -EINVAL;
 			dev_err(dev, "ERROR: Wrong KeySrc, enable secure mode\n");
 			break;
 		case ZYNQMP_AES_PUF_NOT_PROGRAMMED:
+			ret = -EINVAL;
 			dev_err(dev, "ERROR: PUF is not registered\n");
 			break;
 		default:
-			dev_err(dev, "ERROR: Unknown error\n");
+			ret = -EINVAL;
 			break;
 		}
-		err = -status;
 	} else {
 		if (hwreq->op == ZYNQMP_AES_ENCRYPT)
 			data_size = data_size + ZYNQMP_AES_AUTH_SIZE;
@@ -157,7 +156,7 @@ static int zynqmp_aes_aead_cipher(struct aead_request *req)
 
 		sg_copy_from_buffer(req->dst, sg_nents(req->dst),
 				    kbuf, data_size);
-		err = 0;
+		ret = 0;
 	}
 
 	if (kbuf) {
@@ -169,7 +168,8 @@ static int zynqmp_aes_aead_cipher(struct aead_request *req)
 		dma_free_coherent(dev, sizeof(struct zynqmp_aead_hw_req),
 				  hwreq, dma_addr_hw_req);
 	}
-	return err;
+
+	return ret;
 }
 
 static int zynqmp_fallback_check(struct zynqmp_aead_tfm_ctx *tfm_ctx,
-- 
2.49.1



From h.jain at amd.com  Sat Dec 20 07:58:58 2025
From: h.jain at amd.com (Harsh Jain)
Date: Sat, 20 Dec 2025 21:28:58 +0530
Subject: [PATCH v2 07/14] crypto: zynqmp-aes-gcm: Avoid Encrypt request to fallback for authsize < 16
In-Reply-To: <20251220155905.346790-1-h.jain@amd.com>
References: <20251220155905.346790-1-h.jain@amd.com>
Message-ID: <20251220155905.346790-8-h.jain@amd.com>

Encrypt requests can be handled by driver when authsize is less than 16.

Signed-off-by: Harsh Jain <h.jain at amd.com>
---
 drivers/crypto/xilinx/zynqmp-aes-gcm.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/crypto/xilinx/zynqmp-aes-gcm.c b/drivers/crypto/xilinx/zynqmp-aes-gcm.c
index e64316d9cabf..3b346a1c9f7e 100644
--- a/drivers/crypto/xilinx/zynqmp-aes-gcm.c
+++ b/drivers/crypto/xilinx/zynqmp-aes-gcm.c
@@ -150,7 +150,7 @@ static int zynqmp_aes_aead_cipher(struct aead_request *req)
 		}
 	} else {
 		if (hwreq->op == ZYNQMP_AES_ENCRYPT)
-			data_size = data_size + ZYNQMP_AES_AUTH_SIZE;
+			data_size = data_size + crypto_aead_authsize(aead);
 		else
 			data_size = data_size - ZYNQMP_AES_AUTH_SIZE;
 
@@ -178,8 +178,8 @@ static int zynqmp_fallback_check(struct zynqmp_aead_tfm_ctx *tfm_ctx,
 	int need_fallback = 0;
 	struct zynqmp_aead_req_ctx *rq_ctx = aead_request_ctx(req);
 
-	if (tfm_ctx->authsize != ZYNQMP_AES_AUTH_SIZE)
-		need_fallback = 1;
+	if (tfm_ctx->authsize != ZYNQMP_AES_AUTH_SIZE && rq_ctx->op == ZYNQMP_AES_DECRYPT)
+		return 1;
 
 	if (tfm_ctx->keysrc == ZYNQMP_AES_KUP_KEY &&
 	    tfm_ctx->keylen != ZYNQMP_AES_KEY_SIZE) {
-- 
2.49.1



From h.jain at amd.com  Sat Dec 20 07:58:59 2025
From: h.jain at amd.com (Harsh Jain)
Date: Sat, 20 Dec 2025 21:28:59 +0530
Subject: [PATCH v2 08/14] crypto: zynqmp-aes-gcm: Avoid submitting fallback requests to engine
In-Reply-To: <20251220155905.346790-1-h.jain@amd.com>
References: <20251220155905.346790-1-h.jain@amd.com>
Message-ID: <20251220155905.346790-9-h.jain@amd.com>

Don't enqueue requests which are supposed to fallback to s/w crypto.

Signed-off-by: Harsh Jain <h.jain at amd.com>
---
 drivers/crypto/xilinx/zynqmp-aes-gcm.c | 62 +++++++++++++++-----------
 1 file changed, 35 insertions(+), 27 deletions(-)

diff --git a/drivers/crypto/xilinx/zynqmp-aes-gcm.c b/drivers/crypto/xilinx/zynqmp-aes-gcm.c
index 3b346a1c9f7e..b8574e144f48 100644
--- a/drivers/crypto/xilinx/zynqmp-aes-gcm.c
+++ b/drivers/crypto/xilinx/zynqmp-aes-gcm.c
@@ -204,31 +204,9 @@ static int zynqmp_handle_aes_req(struct crypto_engine *engine,
 {
 	struct aead_request *areq =
 				container_of(req, struct aead_request, base);
-	struct crypto_aead *aead = crypto_aead_reqtfm(req);
-	struct zynqmp_aead_tfm_ctx *tfm_ctx = crypto_aead_ctx(aead);
-	struct zynqmp_aead_req_ctx *rq_ctx = aead_request_ctx(areq);
-	struct aead_request *subreq = aead_request_ctx(req);
-	int need_fallback;
 	int err;
 
-	need_fallback = zynqmp_fallback_check(tfm_ctx, areq);
-
-	if (need_fallback) {
-		aead_request_set_tfm(subreq, tfm_ctx->fbk_cipher);
-
-		aead_request_set_callback(subreq, areq->base.flags,
-					  NULL, NULL);
-		aead_request_set_crypt(subreq, areq->src, areq->dst,
-				       areq->cryptlen, areq->iv);
-		aead_request_set_ad(subreq, areq->assoclen);
-		if (rq_ctx->op == ZYNQMP_AES_ENCRYPT)
-			err = crypto_aead_encrypt(subreq);
-		else
-			err = crypto_aead_decrypt(subreq);
-	} else {
-		err = zynqmp_aes_aead_cipher(areq);
-	}
-
+	err = zynqmp_aes_aead_cipher(areq);
 	local_bh_disable();
 	crypto_finalize_aead_request(engine, areq, err);
 	local_bh_enable();
@@ -279,28 +257,58 @@ static int zynqmp_aes_aead_setauthsize(struct crypto_aead *aead,
 	return crypto_aead_setauthsize(tfm_ctx->fbk_cipher, authsize);
 }
 
+static int xilinx_aes_fallback_crypt(struct aead_request *req, bool encrypt)
+{
+	struct aead_request *subreq = aead_request_ctx(req);
+	struct crypto_aead *aead = crypto_aead_reqtfm(req);
+	struct zynqmp_aead_tfm_ctx *tfm_ctx = crypto_aead_ctx(aead);
+
+	aead_request_set_tfm(subreq, tfm_ctx->fbk_cipher);
+	aead_request_set_callback(subreq, req->base.flags, NULL, NULL);
+	aead_request_set_crypt(subreq, req->src, req->dst,
+			       req->cryptlen, req->iv);
+	aead_request_set_ad(subreq, req->assoclen);
+
+	return encrypt ? crypto_aead_encrypt(subreq) : crypto_aead_decrypt(subreq);
+}
+
 static int zynqmp_aes_aead_encrypt(struct aead_request *req)
 {
-	struct zynqmp_aead_drv_ctx *drv_ctx;
+	struct zynqmp_aead_req_ctx *rq_ctx = aead_request_ctx(req);
 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
+	struct zynqmp_aead_tfm_ctx *tfm_ctx = crypto_aead_ctx(aead);
 	struct aead_alg *alg = crypto_aead_alg(aead);
-	struct zynqmp_aead_req_ctx *rq_ctx = aead_request_ctx(req);
+	struct zynqmp_aead_drv_ctx *drv_ctx;
+	int err;
 
 	rq_ctx->op = ZYNQMP_AES_ENCRYPT;
 	drv_ctx = container_of(alg, struct zynqmp_aead_drv_ctx, aead.base);
+	err = zynqmp_fallback_check(tfm_ctx, req);
+	if (err && tfm_ctx->keysrc != ZYNQMP_AES_KUP_KEY)
+		return -EOPNOTSUPP;
+
+	if (err)
+		return xilinx_aes_fallback_crypt(req, true);
 
 	return crypto_transfer_aead_request_to_engine(drv_ctx->engine, req);
 }
 
 static int zynqmp_aes_aead_decrypt(struct aead_request *req)
 {
-	struct zynqmp_aead_drv_ctx *drv_ctx;
+	struct zynqmp_aead_req_ctx *rq_ctx = aead_request_ctx(req);
 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
+	struct zynqmp_aead_tfm_ctx *tfm_ctx = crypto_aead_ctx(aead);
 	struct aead_alg *alg = crypto_aead_alg(aead);
-	struct zynqmp_aead_req_ctx *rq_ctx = aead_request_ctx(req);
+	struct zynqmp_aead_drv_ctx *drv_ctx;
+	int err;
 
 	rq_ctx->op = ZYNQMP_AES_DECRYPT;
 	drv_ctx = container_of(alg, struct zynqmp_aead_drv_ctx, aead.base);
+	err = zynqmp_fallback_check(tfm_ctx, req);
+	if (err && tfm_ctx->keysrc != ZYNQMP_AES_KUP_KEY)
+		return -EOPNOTSUPP;
+	if (err)
+		return xilinx_aes_fallback_crypt(req, false);
 
 	return crypto_transfer_aead_request_to_engine(drv_ctx->engine, req);
 }
-- 
2.49.1



From h.jain at amd.com  Sat Dec 20 07:59:00 2025
From: h.jain at amd.com (Harsh Jain)
Date: Sat, 20 Dec 2025 21:29:00 +0530
Subject: [PATCH v2 09/14] crypto: zynqmp-aes-gcm: Register H/W key support with paes
In-Reply-To: <20251220155905.346790-1-h.jain@amd.com>
References: <20251220155905.346790-1-h.jain@amd.com>
Message-ID: <20251220155905.346790-10-h.jain@amd.com>

Register gcm(paes) for hardware supported keys.

Signed-off-by: Harsh Jain <h.jain at amd.com>
---
 drivers/crypto/xilinx/zynqmp-aes-gcm.c | 304 +++++++++++++++++--------
 1 file changed, 204 insertions(+), 100 deletions(-)

diff --git a/drivers/crypto/xilinx/zynqmp-aes-gcm.c b/drivers/crypto/xilinx/zynqmp-aes-gcm.c
index b8574e144f48..179595b24f4f 100644
--- a/drivers/crypto/xilinx/zynqmp-aes-gcm.c
+++ b/drivers/crypto/xilinx/zynqmp-aes-gcm.c
@@ -22,14 +22,14 @@
 
 #define ZYNQMP_AES_KEY_SIZE		AES_KEYSIZE_256
 #define ZYNQMP_AES_AUTH_SIZE		16U
-#define ZYNQMP_KEY_SRC_SEL_KEY_LEN	1U
 #define ZYNQMP_AES_BLK_SIZE		1U
 #define ZYNQMP_AES_MIN_INPUT_BLK_SIZE	4U
 #define ZYNQMP_AES_WORD_LEN		4U
 
-#define ZYNQMP_AES_GCM_TAG_MISMATCH_ERR		0x01
-#define ZYNQMP_AES_WRONG_KEY_SRC_ERR		0x13
-#define ZYNQMP_AES_PUF_NOT_PROGRAMMED		0xE300
+#define ZYNQMP_AES_GCM_TAG_MISMATCH_ERR	0x01
+#define ZYNQMP_AES_WRONG_KEY_SRC_ERR	0x13
+#define ZYNQMP_AES_PUF_NOT_PROGRAMMED	0xE300
+#define XILINX_KEY_MAGIC		0x3EA0
 
 enum zynqmp_aead_op {
 	ZYNQMP_AES_DECRYPT = 0,
@@ -42,12 +42,23 @@ enum zynqmp_aead_keysrc {
 	ZYNQMP_AES_PUF_KEY
 };
 
-struct zynqmp_aead_drv_ctx {
-	struct aead_engine_alg aead;
+struct xilinx_aead_dev {
 	struct device *dev;
 	struct crypto_engine *engine;
+	struct xilinx_aead_alg *aead_algs;
+};
+
+struct xilinx_aead_alg {
+	struct xilinx_aead_dev *aead_dev;
+	struct aead_engine_alg aead;
+	u8 dma_bit_mask;
 };
 
+struct xilinx_hwkey_info {
+	u16 magic;
+	u16 type;
+} __packed;
+
 struct zynqmp_aead_hw_req {
 	u64 src;
 	u64 iv;
@@ -64,7 +75,7 @@ struct zynqmp_aead_tfm_ctx {
 	u8 *iv;
 	u32 keylen;
 	u32 authsize;
-	enum zynqmp_aead_keysrc keysrc;
+	u8 keysrc;
 	struct crypto_aead *fbk_cipher;
 };
 
@@ -72,6 +83,8 @@ struct zynqmp_aead_req_ctx {
 	enum zynqmp_aead_op op;
 };
 
+static struct xilinx_aead_dev *aead_dev;
+
 static int zynqmp_aes_aead_cipher(struct aead_request *req)
 {
 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
@@ -175,32 +188,29 @@ static int zynqmp_aes_aead_cipher(struct aead_request *req)
 static int zynqmp_fallback_check(struct zynqmp_aead_tfm_ctx *tfm_ctx,
 				 struct aead_request *req)
 {
-	int need_fallback = 0;
 	struct zynqmp_aead_req_ctx *rq_ctx = aead_request_ctx(req);
 
 	if (tfm_ctx->authsize != ZYNQMP_AES_AUTH_SIZE && rq_ctx->op == ZYNQMP_AES_DECRYPT)
 		return 1;
 
-	if (tfm_ctx->keysrc == ZYNQMP_AES_KUP_KEY &&
-	    tfm_ctx->keylen != ZYNQMP_AES_KEY_SIZE) {
-		need_fallback = 1;
-	}
 	if (req->assoclen != 0 ||
-	    req->cryptlen < ZYNQMP_AES_MIN_INPUT_BLK_SIZE) {
-		need_fallback = 1;
-	}
+	    req->cryptlen < ZYNQMP_AES_MIN_INPUT_BLK_SIZE)
+		return 1;
+	if (tfm_ctx->keylen == AES_KEYSIZE_128 ||
+	    tfm_ctx->keylen == AES_KEYSIZE_192)
+		return 1;
+
 	if ((req->cryptlen % ZYNQMP_AES_WORD_LEN) != 0)
-		need_fallback = 1;
+		return 1;
 
 	if (rq_ctx->op == ZYNQMP_AES_DECRYPT &&
-	    req->cryptlen <= ZYNQMP_AES_AUTH_SIZE) {
-		need_fallback = 1;
-	}
-	return need_fallback;
+	    req->cryptlen <= ZYNQMP_AES_AUTH_SIZE)
+		return 1;
+
+	return 0;
 }
 
-static int zynqmp_handle_aes_req(struct crypto_engine *engine,
-				 void *req)
+static int zynqmp_handle_aes_req(struct crypto_engine *engine, void *req)
 {
 	struct aead_request *areq =
 				container_of(req, struct aead_request, base);
@@ -218,32 +228,49 @@ static int zynqmp_aes_aead_setkey(struct crypto_aead *aead, const u8 *key,
 				  unsigned int keylen)
 {
 	struct crypto_tfm *tfm = crypto_aead_tfm(aead);
-	struct zynqmp_aead_tfm_ctx *tfm_ctx =
-			(struct zynqmp_aead_tfm_ctx *)crypto_tfm_ctx(tfm);
-	unsigned char keysrc;
+	struct zynqmp_aead_tfm_ctx *tfm_ctx = crypto_tfm_ctx(tfm);
+	int err;
 
-	if (keylen == ZYNQMP_KEY_SRC_SEL_KEY_LEN) {
-		keysrc = *key;
-		if (keysrc == ZYNQMP_AES_KUP_KEY ||
-		    keysrc == ZYNQMP_AES_DEV_KEY ||
-		    keysrc == ZYNQMP_AES_PUF_KEY) {
-			tfm_ctx->keysrc = (enum zynqmp_aead_keysrc)keysrc;
-		} else {
-			tfm_ctx->keylen = keylen;
-		}
-	} else {
-		tfm_ctx->keylen = keylen;
-		if (keylen == ZYNQMP_AES_KEY_SIZE) {
-			tfm_ctx->keysrc = ZYNQMP_AES_KUP_KEY;
-			memcpy(tfm_ctx->key, key, keylen);
-		}
+	if (keylen == ZYNQMP_AES_KEY_SIZE) {
+		memcpy(tfm_ctx->key, key, keylen);
 	}
 
 	tfm_ctx->fbk_cipher->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
 	tfm_ctx->fbk_cipher->base.crt_flags |= (aead->base.crt_flags &
-					CRYPTO_TFM_REQ_MASK);
+						CRYPTO_TFM_REQ_MASK);
 
-	return crypto_aead_setkey(tfm_ctx->fbk_cipher, key, keylen);
+	err = crypto_aead_setkey(tfm_ctx->fbk_cipher, key, keylen);
+	if (err)
+		goto err;
+	tfm_ctx->keylen = keylen;
+	tfm_ctx->keysrc = ZYNQMP_AES_KUP_KEY;
+err:
+	return err;
+}
+
+static int zynqmp_paes_aead_setkey(struct crypto_aead *aead, const u8 *key,
+				   unsigned int keylen)
+{
+	struct crypto_tfm *tfm = crypto_aead_tfm(aead);
+	struct zynqmp_aead_tfm_ctx *tfm_ctx = crypto_tfm_ctx(tfm);
+	struct xilinx_hwkey_info hwkey;
+	unsigned char keysrc;
+	int err = -EINVAL;
+
+	if (keylen != sizeof(struct xilinx_hwkey_info))
+		return -EINVAL;
+	memcpy(&hwkey, key, sizeof(struct xilinx_hwkey_info));
+	if (hwkey.magic != XILINX_KEY_MAGIC)
+		return -EINVAL;
+	keysrc = hwkey.type;
+	if (keysrc == ZYNQMP_AES_DEV_KEY ||
+	    keysrc == ZYNQMP_AES_PUF_KEY) {
+		tfm_ctx->keysrc = keysrc;
+		tfm_ctx->keylen = sizeof(struct xilinx_hwkey_info);
+		err = 0;
+	}
+
+	return err;
 }
 
 static int zynqmp_aes_aead_setauthsize(struct crypto_aead *aead,
@@ -254,7 +281,7 @@ static int zynqmp_aes_aead_setauthsize(struct crypto_aead *aead,
 			(struct zynqmp_aead_tfm_ctx *)crypto_tfm_ctx(tfm);
 
 	tfm_ctx->authsize = authsize;
-	return crypto_aead_setauthsize(tfm_ctx->fbk_cipher, authsize);
+	return tfm_ctx->fbk_cipher ? crypto_aead_setauthsize(tfm_ctx->fbk_cipher, authsize) : 0;
 }
 
 static int xilinx_aes_fallback_crypt(struct aead_request *req, bool encrypt)
@@ -278,11 +305,15 @@ static int zynqmp_aes_aead_encrypt(struct aead_request *req)
 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
 	struct zynqmp_aead_tfm_ctx *tfm_ctx = crypto_aead_ctx(aead);
 	struct aead_alg *alg = crypto_aead_alg(aead);
-	struct zynqmp_aead_drv_ctx *drv_ctx;
+	struct xilinx_aead_alg *drv_ctx;
 	int err;
 
+	drv_ctx = container_of(alg, struct xilinx_aead_alg, aead.base);
+	if (tfm_ctx->keysrc == ZYNQMP_AES_KUP_KEY &&
+	    tfm_ctx->keylen == sizeof(struct xilinx_hwkey_info))
+		return -EINVAL;
+
 	rq_ctx->op = ZYNQMP_AES_ENCRYPT;
-	drv_ctx = container_of(alg, struct zynqmp_aead_drv_ctx, aead.base);
 	err = zynqmp_fallback_check(tfm_ctx, req);
 	if (err && tfm_ctx->keysrc != ZYNQMP_AES_KUP_KEY)
 		return -EOPNOTSUPP;
@@ -290,7 +321,7 @@ static int zynqmp_aes_aead_encrypt(struct aead_request *req)
 	if (err)
 		return xilinx_aes_fallback_crypt(req, true);
 
-	return crypto_transfer_aead_request_to_engine(drv_ctx->engine, req);
+	return crypto_transfer_aead_request_to_engine(drv_ctx->aead_dev->engine, req);
 }
 
 static int zynqmp_aes_aead_decrypt(struct aead_request *req)
@@ -299,18 +330,38 @@ static int zynqmp_aes_aead_decrypt(struct aead_request *req)
 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
 	struct zynqmp_aead_tfm_ctx *tfm_ctx = crypto_aead_ctx(aead);
 	struct aead_alg *alg = crypto_aead_alg(aead);
-	struct zynqmp_aead_drv_ctx *drv_ctx;
+	struct xilinx_aead_alg *drv_ctx;
 	int err;
 
 	rq_ctx->op = ZYNQMP_AES_DECRYPT;
-	drv_ctx = container_of(alg, struct zynqmp_aead_drv_ctx, aead.base);
+	drv_ctx = container_of(alg, struct xilinx_aead_alg, aead.base);
+	if (tfm_ctx->keysrc == ZYNQMP_AES_KUP_KEY &&
+	    tfm_ctx->keylen == sizeof(struct xilinx_hwkey_info))
+		return -EINVAL;
 	err = zynqmp_fallback_check(tfm_ctx, req);
 	if (err && tfm_ctx->keysrc != ZYNQMP_AES_KUP_KEY)
 		return -EOPNOTSUPP;
 	if (err)
 		return xilinx_aes_fallback_crypt(req, false);
 
-	return crypto_transfer_aead_request_to_engine(drv_ctx->engine, req);
+	return crypto_transfer_aead_request_to_engine(drv_ctx->aead_dev->engine, req);
+}
+
+static int xilinx_paes_aead_init(struct crypto_aead *aead)
+{
+	struct crypto_tfm *tfm = crypto_aead_tfm(aead);
+	struct zynqmp_aead_tfm_ctx *tfm_ctx = crypto_tfm_ctx(tfm);
+	struct xilinx_aead_alg *drv_alg;
+	struct aead_alg *alg = crypto_aead_alg(aead);
+
+	drv_alg = container_of(alg, struct xilinx_aead_alg, aead.base);
+	tfm_ctx->dev = drv_alg->aead_dev->dev;
+	tfm_ctx->keylen = 0;
+
+	tfm_ctx->fbk_cipher = NULL;
+	crypto_aead_set_reqsize(aead, sizeof(struct zynqmp_aead_req_ctx));
+
+	return 0;
 }
 
 static int zynqmp_aes_aead_init(struct crypto_aead *aead)
@@ -318,11 +369,12 @@ static int zynqmp_aes_aead_init(struct crypto_aead *aead)
 	struct crypto_tfm *tfm = crypto_aead_tfm(aead);
 	struct zynqmp_aead_tfm_ctx *tfm_ctx =
 		(struct zynqmp_aead_tfm_ctx *)crypto_tfm_ctx(tfm);
-	struct zynqmp_aead_drv_ctx *drv_ctx;
+	struct xilinx_aead_alg *drv_ctx;
 	struct aead_alg *alg = crypto_aead_alg(aead);
 
-	drv_ctx = container_of(alg, struct zynqmp_aead_drv_ctx, aead.base);
-	tfm_ctx->dev = drv_ctx->dev;
+	drv_ctx = container_of(alg, struct xilinx_aead_alg, aead.base);
+	tfm_ctx->dev = drv_ctx->aead_dev->dev;
+	tfm_ctx->keylen = 0;
 
 	tfm_ctx->fbk_cipher = crypto_alloc_aead(drv_ctx->aead.base.base.cra_name,
 						0,
@@ -341,6 +393,14 @@ static int zynqmp_aes_aead_init(struct crypto_aead *aead)
 	return 0;
 }
 
+static void xilinx_paes_aead_exit(struct crypto_aead *aead)
+{
+	struct crypto_tfm *tfm = crypto_aead_tfm(aead);
+	struct zynqmp_aead_tfm_ctx *tfm_ctx = crypto_tfm_ctx(tfm);
+
+	memzero_explicit(tfm_ctx, sizeof(struct zynqmp_aead_tfm_ctx));
+}
+
 static void zynqmp_aes_aead_exit(struct crypto_aead *aead)
 {
 	struct crypto_tfm *tfm = crypto_aead_tfm(aead);
@@ -354,104 +414,148 @@ static void zynqmp_aes_aead_exit(struct crypto_aead *aead)
 	memzero_explicit(tfm_ctx, sizeof(struct zynqmp_aead_tfm_ctx));
 }
 
-static struct zynqmp_aead_drv_ctx zynqmp_aes_drv_ctx = {
-	.aead.base = {
-		.setkey		= zynqmp_aes_aead_setkey,
-		.setauthsize	= zynqmp_aes_aead_setauthsize,
-		.encrypt	= zynqmp_aes_aead_encrypt,
-		.decrypt	= zynqmp_aes_aead_decrypt,
-		.init		= zynqmp_aes_aead_init,
-		.exit		= zynqmp_aes_aead_exit,
-		.ivsize		= GCM_AES_IV_SIZE,
-		.maxauthsize	= ZYNQMP_AES_AUTH_SIZE,
-		.base = {
-		.cra_name		= "gcm(aes)",
-		.cra_driver_name	= "xilinx-zynqmp-aes-gcm",
-		.cra_priority		= 200,
-		.cra_flags		= CRYPTO_ALG_TYPE_AEAD |
-					  CRYPTO_ALG_ASYNC |
-					  CRYPTO_ALG_ALLOCATES_MEMORY |
-					  CRYPTO_ALG_KERN_DRIVER_ONLY |
-					  CRYPTO_ALG_NEED_FALLBACK,
-		.cra_blocksize		= ZYNQMP_AES_BLK_SIZE,
-		.cra_ctxsize		= sizeof(struct zynqmp_aead_tfm_ctx),
-		.cra_module		= THIS_MODULE,
-		}
+static struct xilinx_aead_alg zynqmp_aes_algs[] = {
+	{
+		.aead.base = {
+			.setkey		= zynqmp_aes_aead_setkey,
+			.setauthsize	= zynqmp_aes_aead_setauthsize,
+			.encrypt	= zynqmp_aes_aead_encrypt,
+			.decrypt	= zynqmp_aes_aead_decrypt,
+			.init		= zynqmp_aes_aead_init,
+			.exit		= zynqmp_aes_aead_exit,
+			.ivsize		= GCM_AES_IV_SIZE,
+			.maxauthsize	= ZYNQMP_AES_AUTH_SIZE,
+			.base = {
+				.cra_name		= "gcm(aes)",
+				.cra_driver_name	= "xilinx-zynqmp-aes-gcm",
+				.cra_priority		= 200,
+			.cra_flags		= CRYPTO_ALG_TYPE_AEAD |
+				CRYPTO_ALG_ASYNC |
+				CRYPTO_ALG_ALLOCATES_MEMORY |
+				CRYPTO_ALG_KERN_DRIVER_ONLY |
+				CRYPTO_ALG_NEED_FALLBACK,
+			.cra_blocksize		= ZYNQMP_AES_BLK_SIZE,
+			.cra_ctxsize		= sizeof(struct zynqmp_aead_tfm_ctx),
+			.cra_module		= THIS_MODULE,
+			}
+		},
+		.aead.op = {
+			.do_one_request = zynqmp_handle_aes_req,
+		},
+		.dma_bit_mask = ZYNQMP_DMA_BIT_MASK,
 	},
-	.aead.op = {
-		.do_one_request = zynqmp_handle_aes_req,
+	{
+		.aead.base = {
+			.setkey		= zynqmp_paes_aead_setkey,
+			.setauthsize	= zynqmp_aes_aead_setauthsize,
+			.encrypt	= zynqmp_aes_aead_encrypt,
+			.decrypt	= zynqmp_aes_aead_decrypt,
+			.init		= xilinx_paes_aead_init,
+			.exit		= xilinx_paes_aead_exit,
+			.ivsize		= GCM_AES_IV_SIZE,
+			.maxauthsize	= ZYNQMP_AES_AUTH_SIZE,
+			.base = {
+				.cra_name		= "gcm(paes)",
+				.cra_driver_name	= "xilinx-zynqmp-paes-gcm",
+				.cra_priority		= 200,
+			.cra_flags		= CRYPTO_ALG_TYPE_AEAD |
+				CRYPTO_ALG_ASYNC |
+				CRYPTO_ALG_ALLOCATES_MEMORY |
+				CRYPTO_ALG_KERN_DRIVER_ONLY,
+			.cra_blocksize		= ZYNQMP_AES_BLK_SIZE,
+			.cra_ctxsize		= sizeof(struct zynqmp_aead_tfm_ctx),
+			.cra_module		= THIS_MODULE,
+			}
+		},
+		.aead.op = {
+			.do_one_request = zynqmp_handle_aes_req,
+		},
+		.dma_bit_mask = ZYNQMP_DMA_BIT_MASK,
 	},
+	{ /* sentinel */ }
 };
 
 static struct xlnx_feature aes_feature_map[] = {
 	{
 		.family = PM_ZYNQMP_FAMILY_CODE,
 		.feature_id = PM_SECURE_AES,
-		.data = &zynqmp_aes_drv_ctx,
+		.data = zynqmp_aes_algs,
 	},
 	{ /* sentinel */ }
 };
 
 static int zynqmp_aes_aead_probe(struct platform_device *pdev)
 {
-	struct zynqmp_aead_drv_ctx *aes_drv_ctx;
+	struct xilinx_aead_alg *aead_algs;
 	struct device *dev = &pdev->dev;
 	int err;
+	int i;
 
 	/* Verify the hardware is present */
-	aes_drv_ctx = xlnx_get_crypto_dev_data(aes_feature_map);
-	if (IS_ERR(aes_drv_ctx)) {
+	aead_algs = xlnx_get_crypto_dev_data(aes_feature_map);
+	if (IS_ERR(aead_algs)) {
 		dev_err(dev, "AES is not supported on the platform\n");
-		return PTR_ERR(aes_drv_ctx);
+		return PTR_ERR(aead_algs);
 	}
 
 	/* ZynqMP AES driver supports only one instance */
-	if (!aes_drv_ctx->dev)
-		aes_drv_ctx->dev = dev;
-	else
+	if (aead_dev)
 		return -ENODEV;
 
-	platform_set_drvdata(pdev, aes_drv_ctx);
-	err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(ZYNQMP_DMA_BIT_MASK));
+	aead_dev = devm_kzalloc(dev, sizeof(*aead_dev), GFP_KERNEL);
+	if (!aead_dev)
+		return -ENOMEM;
+	aead_dev->dev = dev;
+	aead_dev->aead_algs = aead_algs;
+	platform_set_drvdata(pdev, aead_dev);
+	err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(aead_algs[0].dma_bit_mask));
 	if (err < 0) {
 		dev_err(dev, "No usable DMA configuration\n");
 		return err;
 	}
 
-	aes_drv_ctx->engine = crypto_engine_alloc_init(dev, 1);
-	if (!aes_drv_ctx->engine) {
+	aead_dev->engine = crypto_engine_alloc_init(dev, 1);
+	if (!aead_dev->engine) {
 		dev_err(dev, "Cannot alloc AES engine\n");
 		err = -ENOMEM;
 		goto err_engine;
 	}
 
-	err = crypto_engine_start(aes_drv_ctx->engine);
+	err = crypto_engine_start(aead_dev->engine);
 	if (err) {
 		dev_err(dev, "Cannot start AES engine\n");
 		goto err_engine;
 	}
 
-	err = crypto_engine_register_aead(&aes_drv_ctx->aead);
-	if (err < 0) {
-		dev_err(dev, "Failed to register AEAD alg.\n");
-		goto err_engine;
+	for (i = 0; aead_dev->aead_algs[i].dma_bit_mask; i++) {
+		aead_dev->aead_algs[i].aead_dev = aead_dev;
+		err = crypto_engine_register_aead(&aead_dev->aead_algs[i].aead);
+		if (err < 0) {
+			dev_err(dev, "Failed to register AEAD alg %d.\n", i);
+			goto err_alg_register;
+		}
 	}
 	return 0;
 
+	return 0;
+
+err_alg_register:
+	while (i > 0)
+		crypto_engine_unregister_aead(&aead_dev->aead_algs[--i].aead);
 err_engine:
-	if (aes_drv_ctx->engine)
-		crypto_engine_exit(aes_drv_ctx->engine);
+	crypto_engine_exit(aead_dev->engine);
 
 	return err;
 }
 
 static void zynqmp_aes_aead_remove(struct platform_device *pdev)
 {
-	struct zynqmp_aead_drv_ctx *aes_drv_ctx;
+	aead_dev = platform_get_drvdata(pdev);
+	crypto_engine_exit(aead_dev->engine);
+	for (int i = 0; aead_dev->aead_algs[i].dma_bit_mask; i++)
+		crypto_engine_unregister_aead(&aead_dev->aead_algs[i].aead);
 
-	aes_drv_ctx = platform_get_drvdata(pdev);
-	crypto_engine_exit(aes_drv_ctx->engine);
-	crypto_engine_unregister_aead(&aes_drv_ctx->aead);
+	 aead_dev = NULL;
 }
 
 static struct platform_driver zynqmp_aes_driver = {
-- 
2.49.1



From h.jain at amd.com  Sat Dec 20 07:59:01 2025
From: h.jain at amd.com (Harsh Jain)
Date: Sat, 20 Dec 2025 21:29:01 +0530
Subject: [PATCH v2 10/14] crypto: xilinx: Replace zynqmp prefix with xilinx
In-Reply-To: <20251220155905.346790-1-h.jain@amd.com>
References: <20251220155905.346790-1-h.jain@amd.com>
Message-ID: <20251220155905.346790-11-h.jain@amd.com>

Replace zynqmp with xilinx to have more generic name.

Signed-off-by: Harsh Jain <h.jain at amd.com>
---
 drivers/crypto/xilinx/zynqmp-aes-gcm.c | 140 ++++++++++++-------------
 1 file changed, 69 insertions(+), 71 deletions(-)

diff --git a/drivers/crypto/xilinx/zynqmp-aes-gcm.c b/drivers/crypto/xilinx/zynqmp-aes-gcm.c
index 179595b24f4f..34dbb8b7d3a8 100644
--- a/drivers/crypto/xilinx/zynqmp-aes-gcm.c
+++ b/drivers/crypto/xilinx/zynqmp-aes-gcm.c
@@ -19,10 +19,8 @@
 #include <linux/string.h>
 
 #define ZYNQMP_DMA_BIT_MASK	32U
-
-#define ZYNQMP_AES_KEY_SIZE		AES_KEYSIZE_256
-#define ZYNQMP_AES_AUTH_SIZE		16U
-#define ZYNQMP_AES_BLK_SIZE		1U
+#define XILINX_AES_AUTH_SIZE		16U
+#define XILINX_AES_BLK_SIZE		1U
 #define ZYNQMP_AES_MIN_INPUT_BLK_SIZE	4U
 #define ZYNQMP_AES_WORD_LEN		4U
 
@@ -31,9 +29,9 @@
 #define ZYNQMP_AES_PUF_NOT_PROGRAMMED	0xE300
 #define XILINX_KEY_MAGIC		0x3EA0
 
-enum zynqmp_aead_op {
-	ZYNQMP_AES_DECRYPT = 0,
-	ZYNQMP_AES_ENCRYPT
+enum xilinx_aead_op {
+	XILINX_AES_DECRYPT = 0,
+	XILINX_AES_ENCRYPT
 };
 
 enum zynqmp_aead_keysrc {
@@ -69,9 +67,9 @@ struct zynqmp_aead_hw_req {
 	u64 keysrc;
 };
 
-struct zynqmp_aead_tfm_ctx {
+struct xilinx_aead_tfm_ctx {
 	struct device *dev;
-	u8 key[ZYNQMP_AES_KEY_SIZE];
+	u8 key[AES_KEYSIZE_256];
 	u8 *iv;
 	u32 keylen;
 	u32 authsize;
@@ -79,8 +77,8 @@ struct zynqmp_aead_tfm_ctx {
 	struct crypto_aead *fbk_cipher;
 };
 
-struct zynqmp_aead_req_ctx {
-	enum zynqmp_aead_op op;
+struct xilinx_aead_req_ctx {
+	enum xilinx_aead_op op;
 };
 
 static struct xilinx_aead_dev *aead_dev;
@@ -88,8 +86,8 @@ static struct xilinx_aead_dev *aead_dev;
 static int zynqmp_aes_aead_cipher(struct aead_request *req)
 {
 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
-	struct zynqmp_aead_tfm_ctx *tfm_ctx = crypto_aead_ctx(aead);
-	struct zynqmp_aead_req_ctx *rq_ctx = aead_request_ctx(req);
+	struct xilinx_aead_tfm_ctx *tfm_ctx = crypto_aead_ctx(aead);
+	struct xilinx_aead_req_ctx *rq_ctx = aead_request_ctx(req);
 	struct device *dev = tfm_ctx->dev;
 	struct zynqmp_aead_hw_req *hwreq;
 	dma_addr_t dma_addr_data, dma_addr_hw_req;
@@ -100,7 +98,7 @@ static int zynqmp_aes_aead_cipher(struct aead_request *req)
 	char *kbuf;
 
 	if (tfm_ctx->keysrc == ZYNQMP_AES_KUP_KEY)
-		dma_size = req->cryptlen + ZYNQMP_AES_KEY_SIZE
+		dma_size = req->cryptlen + AES_KEYSIZE_256
 			   + GCM_AES_IV_SIZE;
 	else
 		dma_size = req->cryptlen + GCM_AES_IV_SIZE;
@@ -126,14 +124,14 @@ static int zynqmp_aes_aead_cipher(struct aead_request *req)
 	hwreq->keysrc = tfm_ctx->keysrc;
 	hwreq->op = rq_ctx->op;
 
-	if (hwreq->op == ZYNQMP_AES_ENCRYPT)
+	if (hwreq->op == XILINX_AES_ENCRYPT)
 		hwreq->size = data_size;
 	else
-		hwreq->size = data_size - ZYNQMP_AES_AUTH_SIZE;
+		hwreq->size = data_size - XILINX_AES_AUTH_SIZE;
 
 	if (hwreq->keysrc == ZYNQMP_AES_KUP_KEY) {
 		memcpy(kbuf + data_size + GCM_AES_IV_SIZE,
-		       tfm_ctx->key, ZYNQMP_AES_KEY_SIZE);
+		       tfm_ctx->key, AES_KEYSIZE_256);
 
 		hwreq->key = hwreq->src + data_size + GCM_AES_IV_SIZE;
 	} else {
@@ -162,10 +160,10 @@ static int zynqmp_aes_aead_cipher(struct aead_request *req)
 			break;
 		}
 	} else {
-		if (hwreq->op == ZYNQMP_AES_ENCRYPT)
+		if (hwreq->op == XILINX_AES_ENCRYPT)
 			data_size = data_size + crypto_aead_authsize(aead);
 		else
-			data_size = data_size - ZYNQMP_AES_AUTH_SIZE;
+			data_size = data_size - XILINX_AES_AUTH_SIZE;
 
 		sg_copy_from_buffer(req->dst, sg_nents(req->dst),
 				    kbuf, data_size);
@@ -185,12 +183,12 @@ static int zynqmp_aes_aead_cipher(struct aead_request *req)
 	return ret;
 }
 
-static int zynqmp_fallback_check(struct zynqmp_aead_tfm_ctx *tfm_ctx,
+static int zynqmp_fallback_check(struct xilinx_aead_tfm_ctx *tfm_ctx,
 				 struct aead_request *req)
 {
-	struct zynqmp_aead_req_ctx *rq_ctx = aead_request_ctx(req);
+	struct xilinx_aead_req_ctx *rq_ctx = aead_request_ctx(req);
 
-	if (tfm_ctx->authsize != ZYNQMP_AES_AUTH_SIZE && rq_ctx->op == ZYNQMP_AES_DECRYPT)
+	if (tfm_ctx->authsize != XILINX_AES_AUTH_SIZE && rq_ctx->op == XILINX_AES_DECRYPT)
 		return 1;
 
 	if (req->assoclen != 0 ||
@@ -203,14 +201,14 @@ static int zynqmp_fallback_check(struct zynqmp_aead_tfm_ctx *tfm_ctx,
 	if ((req->cryptlen % ZYNQMP_AES_WORD_LEN) != 0)
 		return 1;
 
-	if (rq_ctx->op == ZYNQMP_AES_DECRYPT &&
-	    req->cryptlen <= ZYNQMP_AES_AUTH_SIZE)
+	if (rq_ctx->op == XILINX_AES_DECRYPT &&
+	    req->cryptlen <= XILINX_AES_AUTH_SIZE)
 		return 1;
 
 	return 0;
 }
 
-static int zynqmp_handle_aes_req(struct crypto_engine *engine, void *req)
+static int xilinx_handle_aes_req(struct crypto_engine *engine, void *req)
 {
 	struct aead_request *areq =
 				container_of(req, struct aead_request, base);
@@ -228,10 +226,10 @@ static int zynqmp_aes_aead_setkey(struct crypto_aead *aead, const u8 *key,
 				  unsigned int keylen)
 {
 	struct crypto_tfm *tfm = crypto_aead_tfm(aead);
-	struct zynqmp_aead_tfm_ctx *tfm_ctx = crypto_tfm_ctx(tfm);
+	struct xilinx_aead_tfm_ctx *tfm_ctx = crypto_tfm_ctx(tfm);
 	int err;
 
-	if (keylen == ZYNQMP_AES_KEY_SIZE) {
+	if (keylen == AES_KEYSIZE_256) {
 		memcpy(tfm_ctx->key, key, keylen);
 	}
 
@@ -252,7 +250,7 @@ static int zynqmp_paes_aead_setkey(struct crypto_aead *aead, const u8 *key,
 				   unsigned int keylen)
 {
 	struct crypto_tfm *tfm = crypto_aead_tfm(aead);
-	struct zynqmp_aead_tfm_ctx *tfm_ctx = crypto_tfm_ctx(tfm);
+	struct xilinx_aead_tfm_ctx *tfm_ctx = crypto_tfm_ctx(tfm);
 	struct xilinx_hwkey_info hwkey;
 	unsigned char keysrc;
 	int err = -EINVAL;
@@ -273,12 +271,12 @@ static int zynqmp_paes_aead_setkey(struct crypto_aead *aead, const u8 *key,
 	return err;
 }
 
-static int zynqmp_aes_aead_setauthsize(struct crypto_aead *aead,
+static int xilinx_aes_aead_setauthsize(struct crypto_aead *aead,
 				       unsigned int authsize)
 {
 	struct crypto_tfm *tfm = crypto_aead_tfm(aead);
-	struct zynqmp_aead_tfm_ctx *tfm_ctx =
-			(struct zynqmp_aead_tfm_ctx *)crypto_tfm_ctx(tfm);
+	struct xilinx_aead_tfm_ctx *tfm_ctx =
+			(struct xilinx_aead_tfm_ctx *)crypto_tfm_ctx(tfm);
 
 	tfm_ctx->authsize = authsize;
 	return tfm_ctx->fbk_cipher ? crypto_aead_setauthsize(tfm_ctx->fbk_cipher, authsize) : 0;
@@ -288,7 +286,7 @@ static int xilinx_aes_fallback_crypt(struct aead_request *req, bool encrypt)
 {
 	struct aead_request *subreq = aead_request_ctx(req);
 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
-	struct zynqmp_aead_tfm_ctx *tfm_ctx = crypto_aead_ctx(aead);
+	struct xilinx_aead_tfm_ctx *tfm_ctx = crypto_aead_ctx(aead);
 
 	aead_request_set_tfm(subreq, tfm_ctx->fbk_cipher);
 	aead_request_set_callback(subreq, req->base.flags, NULL, NULL);
@@ -301,9 +299,9 @@ static int xilinx_aes_fallback_crypt(struct aead_request *req, bool encrypt)
 
 static int zynqmp_aes_aead_encrypt(struct aead_request *req)
 {
-	struct zynqmp_aead_req_ctx *rq_ctx = aead_request_ctx(req);
+	struct xilinx_aead_req_ctx *rq_ctx = aead_request_ctx(req);
 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
-	struct zynqmp_aead_tfm_ctx *tfm_ctx = crypto_aead_ctx(aead);
+	struct xilinx_aead_tfm_ctx *tfm_ctx = crypto_aead_ctx(aead);
 	struct aead_alg *alg = crypto_aead_alg(aead);
 	struct xilinx_aead_alg *drv_ctx;
 	int err;
@@ -313,7 +311,7 @@ static int zynqmp_aes_aead_encrypt(struct aead_request *req)
 	    tfm_ctx->keylen == sizeof(struct xilinx_hwkey_info))
 		return -EINVAL;
 
-	rq_ctx->op = ZYNQMP_AES_ENCRYPT;
+	rq_ctx->op = XILINX_AES_ENCRYPT;
 	err = zynqmp_fallback_check(tfm_ctx, req);
 	if (err && tfm_ctx->keysrc != ZYNQMP_AES_KUP_KEY)
 		return -EOPNOTSUPP;
@@ -326,14 +324,14 @@ static int zynqmp_aes_aead_encrypt(struct aead_request *req)
 
 static int zynqmp_aes_aead_decrypt(struct aead_request *req)
 {
-	struct zynqmp_aead_req_ctx *rq_ctx = aead_request_ctx(req);
+	struct xilinx_aead_req_ctx *rq_ctx = aead_request_ctx(req);
 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
-	struct zynqmp_aead_tfm_ctx *tfm_ctx = crypto_aead_ctx(aead);
+	struct xilinx_aead_tfm_ctx *tfm_ctx = crypto_aead_ctx(aead);
 	struct aead_alg *alg = crypto_aead_alg(aead);
 	struct xilinx_aead_alg *drv_ctx;
 	int err;
 
-	rq_ctx->op = ZYNQMP_AES_DECRYPT;
+	rq_ctx->op = XILINX_AES_DECRYPT;
 	drv_ctx = container_of(alg, struct xilinx_aead_alg, aead.base);
 	if (tfm_ctx->keysrc == ZYNQMP_AES_KUP_KEY &&
 	    tfm_ctx->keylen == sizeof(struct xilinx_hwkey_info))
@@ -350,7 +348,7 @@ static int zynqmp_aes_aead_decrypt(struct aead_request *req)
 static int xilinx_paes_aead_init(struct crypto_aead *aead)
 {
 	struct crypto_tfm *tfm = crypto_aead_tfm(aead);
-	struct zynqmp_aead_tfm_ctx *tfm_ctx = crypto_tfm_ctx(tfm);
+	struct xilinx_aead_tfm_ctx *tfm_ctx = crypto_tfm_ctx(tfm);
 	struct xilinx_aead_alg *drv_alg;
 	struct aead_alg *alg = crypto_aead_alg(aead);
 
@@ -359,16 +357,16 @@ static int xilinx_paes_aead_init(struct crypto_aead *aead)
 	tfm_ctx->keylen = 0;
 
 	tfm_ctx->fbk_cipher = NULL;
-	crypto_aead_set_reqsize(aead, sizeof(struct zynqmp_aead_req_ctx));
+	crypto_aead_set_reqsize(aead, sizeof(struct xilinx_aead_req_ctx));
 
 	return 0;
 }
 
-static int zynqmp_aes_aead_init(struct crypto_aead *aead)
+static int xilinx_aes_aead_init(struct crypto_aead *aead)
 {
 	struct crypto_tfm *tfm = crypto_aead_tfm(aead);
-	struct zynqmp_aead_tfm_ctx *tfm_ctx =
-		(struct zynqmp_aead_tfm_ctx *)crypto_tfm_ctx(tfm);
+	struct xilinx_aead_tfm_ctx *tfm_ctx =
+		(struct xilinx_aead_tfm_ctx *)crypto_tfm_ctx(tfm);
 	struct xilinx_aead_alg *drv_ctx;
 	struct aead_alg *alg = crypto_aead_alg(aead);
 
@@ -387,7 +385,7 @@ static int zynqmp_aes_aead_init(struct crypto_aead *aead)
 	}
 
 	crypto_aead_set_reqsize(aead,
-				max(sizeof(struct zynqmp_aead_req_ctx),
+				max(sizeof(struct xilinx_aead_req_ctx),
 				    sizeof(struct aead_request) +
 				    crypto_aead_reqsize(tfm_ctx->fbk_cipher)));
 	return 0;
@@ -396,35 +394,35 @@ static int zynqmp_aes_aead_init(struct crypto_aead *aead)
 static void xilinx_paes_aead_exit(struct crypto_aead *aead)
 {
 	struct crypto_tfm *tfm = crypto_aead_tfm(aead);
-	struct zynqmp_aead_tfm_ctx *tfm_ctx = crypto_tfm_ctx(tfm);
+	struct xilinx_aead_tfm_ctx *tfm_ctx = crypto_tfm_ctx(tfm);
 
-	memzero_explicit(tfm_ctx, sizeof(struct zynqmp_aead_tfm_ctx));
+	memzero_explicit(tfm_ctx, sizeof(struct xilinx_aead_tfm_ctx));
 }
 
-static void zynqmp_aes_aead_exit(struct crypto_aead *aead)
+static void xilinx_aes_aead_exit(struct crypto_aead *aead)
 {
 	struct crypto_tfm *tfm = crypto_aead_tfm(aead);
-	struct zynqmp_aead_tfm_ctx *tfm_ctx =
-			(struct zynqmp_aead_tfm_ctx *)crypto_tfm_ctx(tfm);
+	struct xilinx_aead_tfm_ctx *tfm_ctx =
+			(struct xilinx_aead_tfm_ctx *)crypto_tfm_ctx(tfm);
 
 	if (tfm_ctx->fbk_cipher) {
 		crypto_free_aead(tfm_ctx->fbk_cipher);
 		tfm_ctx->fbk_cipher = NULL;
 	}
-	memzero_explicit(tfm_ctx, sizeof(struct zynqmp_aead_tfm_ctx));
+	memzero_explicit(tfm_ctx, sizeof(struct xilinx_aead_tfm_ctx));
 }
 
 static struct xilinx_aead_alg zynqmp_aes_algs[] = {
 	{
 		.aead.base = {
 			.setkey		= zynqmp_aes_aead_setkey,
-			.setauthsize	= zynqmp_aes_aead_setauthsize,
+			.setauthsize	= xilinx_aes_aead_setauthsize,
 			.encrypt	= zynqmp_aes_aead_encrypt,
 			.decrypt	= zynqmp_aes_aead_decrypt,
-			.init		= zynqmp_aes_aead_init,
-			.exit		= zynqmp_aes_aead_exit,
+			.init		= xilinx_aes_aead_init,
+			.exit		= xilinx_aes_aead_exit,
 			.ivsize		= GCM_AES_IV_SIZE,
-			.maxauthsize	= ZYNQMP_AES_AUTH_SIZE,
+			.maxauthsize	= XILINX_AES_AUTH_SIZE,
 			.base = {
 				.cra_name		= "gcm(aes)",
 				.cra_driver_name	= "xilinx-zynqmp-aes-gcm",
@@ -434,26 +432,26 @@ static struct xilinx_aead_alg zynqmp_aes_algs[] = {
 				CRYPTO_ALG_ALLOCATES_MEMORY |
 				CRYPTO_ALG_KERN_DRIVER_ONLY |
 				CRYPTO_ALG_NEED_FALLBACK,
-			.cra_blocksize		= ZYNQMP_AES_BLK_SIZE,
-			.cra_ctxsize		= sizeof(struct zynqmp_aead_tfm_ctx),
+			.cra_blocksize		= XILINX_AES_BLK_SIZE,
+			.cra_ctxsize		= sizeof(struct xilinx_aead_tfm_ctx),
 			.cra_module		= THIS_MODULE,
 			}
 		},
 		.aead.op = {
-			.do_one_request = zynqmp_handle_aes_req,
+			.do_one_request = xilinx_handle_aes_req,
 		},
 		.dma_bit_mask = ZYNQMP_DMA_BIT_MASK,
 	},
 	{
 		.aead.base = {
 			.setkey		= zynqmp_paes_aead_setkey,
-			.setauthsize	= zynqmp_aes_aead_setauthsize,
+			.setauthsize	= xilinx_aes_aead_setauthsize,
 			.encrypt	= zynqmp_aes_aead_encrypt,
 			.decrypt	= zynqmp_aes_aead_decrypt,
 			.init		= xilinx_paes_aead_init,
 			.exit		= xilinx_paes_aead_exit,
 			.ivsize		= GCM_AES_IV_SIZE,
-			.maxauthsize	= ZYNQMP_AES_AUTH_SIZE,
+			.maxauthsize	= XILINX_AES_AUTH_SIZE,
 			.base = {
 				.cra_name		= "gcm(paes)",
 				.cra_driver_name	= "xilinx-zynqmp-paes-gcm",
@@ -462,13 +460,13 @@ static struct xilinx_aead_alg zynqmp_aes_algs[] = {
 				CRYPTO_ALG_ASYNC |
 				CRYPTO_ALG_ALLOCATES_MEMORY |
 				CRYPTO_ALG_KERN_DRIVER_ONLY,
-			.cra_blocksize		= ZYNQMP_AES_BLK_SIZE,
-			.cra_ctxsize		= sizeof(struct zynqmp_aead_tfm_ctx),
+			.cra_blocksize		= XILINX_AES_BLK_SIZE,
+			.cra_ctxsize		= sizeof(struct xilinx_aead_tfm_ctx),
 			.cra_module		= THIS_MODULE,
 			}
 		},
 		.aead.op = {
-			.do_one_request = zynqmp_handle_aes_req,
+			.do_one_request = xilinx_handle_aes_req,
 		},
 		.dma_bit_mask = ZYNQMP_DMA_BIT_MASK,
 	},
@@ -484,7 +482,7 @@ static struct xlnx_feature aes_feature_map[] = {
 	{ /* sentinel */ }
 };
 
-static int zynqmp_aes_aead_probe(struct platform_device *pdev)
+static int xilinx_aes_aead_probe(struct platform_device *pdev)
 {
 	struct xilinx_aead_alg *aead_algs;
 	struct device *dev = &pdev->dev;
@@ -548,7 +546,7 @@ static int zynqmp_aes_aead_probe(struct platform_device *pdev)
 	return err;
 }
 
-static void zynqmp_aes_aead_remove(struct platform_device *pdev)
+static void xilinx_aes_aead_remove(struct platform_device *pdev)
 {
 	aead_dev = platform_get_drvdata(pdev);
 	crypto_engine_exit(aead_dev->engine);
@@ -558,9 +556,9 @@ static void zynqmp_aes_aead_remove(struct platform_device *pdev)
 	 aead_dev = NULL;
 }
 
-static struct platform_driver zynqmp_aes_driver = {
-	.probe	= zynqmp_aes_aead_probe,
-	.remove = zynqmp_aes_aead_remove,
+static struct platform_driver xilinx_aes_driver = {
+	.probe	= xilinx_aes_aead_probe,
+	.remove = xilinx_aes_aead_remove,
 	.driver = {
 		.name		= "zynqmp-aes",
 	},
@@ -572,15 +570,15 @@ static int __init aes_driver_init(void)
 {
 	int ret;
 
-	ret = platform_driver_register(&zynqmp_aes_driver);
+	ret = platform_driver_register(&xilinx_aes_driver);
 	if (ret)
 		return ret;
 
-	platform_dev = platform_device_register_simple(zynqmp_aes_driver.driver.name,
+	platform_dev = platform_device_register_simple(xilinx_aes_driver.driver.name,
 						       0, NULL, 0);
 	if (IS_ERR(platform_dev)) {
 		ret = PTR_ERR(platform_dev);
-		platform_driver_unregister(&zynqmp_aes_driver);
+		platform_driver_unregister(&xilinx_aes_driver);
 	}
 
 	return ret;
@@ -589,7 +587,7 @@ static int __init aes_driver_init(void)
 static void __exit aes_driver_exit(void)
 {
 	platform_device_unregister(platform_dev);
-	platform_driver_unregister(&zynqmp_aes_driver);
+	platform_driver_unregister(&xilinx_aes_driver);
 }
 
 module_init(aes_driver_init);
-- 
2.49.1



From h.jain at amd.com  Sat Dec 20 07:59:02 2025
From: h.jain at amd.com (Harsh Jain)
Date: Sat, 20 Dec 2025 21:29:02 +0530
Subject: [PATCH v2 11/14] crypto: zynqmp-aes-gcm: Change coherent DMA to streaming DMA API
In-Reply-To: <20251220155905.346790-1-h.jain@amd.com>
References: <20251220155905.346790-1-h.jain@amd.com>
Message-ID: <20251220155905.346790-12-h.jain@amd.com>

Update the driver to use streaming DMA API.

Signed-off-by: Harsh Jain <h.jain at amd.com>
---
 drivers/crypto/xilinx/zynqmp-aes-gcm.c | 94 ++++++++++++++++----------
 1 file changed, 58 insertions(+), 36 deletions(-)

diff --git a/drivers/crypto/xilinx/zynqmp-aes-gcm.c b/drivers/crypto/xilinx/zynqmp-aes-gcm.c
index 34dbb8b7d3a8..c2563c6837e4 100644
--- a/drivers/crypto/xilinx/zynqmp-aes-gcm.c
+++ b/drivers/crypto/xilinx/zynqmp-aes-gcm.c
@@ -69,8 +69,8 @@ struct zynqmp_aead_hw_req {
 
 struct xilinx_aead_tfm_ctx {
 	struct device *dev;
-	u8 key[AES_KEYSIZE_256];
-	u8 *iv;
+	dma_addr_t key_dma_addr;
+	u8 *key;
 	u32 keylen;
 	u32 authsize;
 	u8 keysrc;
@@ -88,39 +88,38 @@ static int zynqmp_aes_aead_cipher(struct aead_request *req)
 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
 	struct xilinx_aead_tfm_ctx *tfm_ctx = crypto_aead_ctx(aead);
 	struct xilinx_aead_req_ctx *rq_ctx = aead_request_ctx(req);
+	dma_addr_t dma_addr_data, dma_addr_hw_req;
 	struct device *dev = tfm_ctx->dev;
 	struct zynqmp_aead_hw_req *hwreq;
-	dma_addr_t dma_addr_data, dma_addr_hw_req;
 	unsigned int data_size;
 	unsigned int status;
 	int ret;
 	size_t dma_size;
+	void *dmabuf;
 	char *kbuf;
 
-	if (tfm_ctx->keysrc == ZYNQMP_AES_KUP_KEY)
-		dma_size = req->cryptlen + AES_KEYSIZE_256
-			   + GCM_AES_IV_SIZE;
-	else
-		dma_size = req->cryptlen + GCM_AES_IV_SIZE;
-
-	kbuf = dma_alloc_coherent(dev, dma_size, &dma_addr_data, GFP_KERNEL);
+	dma_size = req->cryptlen + XILINX_AES_AUTH_SIZE;
+	kbuf = kmalloc(dma_size, GFP_KERNEL);
 	if (!kbuf)
 		return -ENOMEM;
 
-	hwreq = dma_alloc_coherent(dev, sizeof(struct zynqmp_aead_hw_req),
-				   &dma_addr_hw_req, GFP_KERNEL);
-	if (!hwreq) {
-		dma_free_coherent(dev, dma_size, kbuf, dma_addr_data);
+	dmabuf = kmalloc(sizeof(*hwreq) + GCM_AES_IV_SIZE, GFP_KERNEL);
+	if (!dmabuf) {
+		kfree(kbuf);
 		return -ENOMEM;
 	}
-
+	hwreq = dmabuf;
 	data_size = req->cryptlen;
 	scatterwalk_map_and_copy(kbuf, req->src, 0, req->cryptlen, 0);
-	memcpy(kbuf + data_size, req->iv, GCM_AES_IV_SIZE);
+	memcpy(dmabuf + sizeof(struct zynqmp_aead_hw_req), req->iv, GCM_AES_IV_SIZE);
+	dma_addr_data = dma_map_single(dev, kbuf, dma_size, DMA_BIDIRECTIONAL);
+	if (unlikely(dma_mapping_error(dev, dma_addr_data))) {
+		ret = -ENOMEM;
+		goto freemem;
+	}
 
 	hwreq->src = dma_addr_data;
 	hwreq->dst = dma_addr_data;
-	hwreq->iv = hwreq->src + data_size;
 	hwreq->keysrc = tfm_ctx->keysrc;
 	hwreq->op = rq_ctx->op;
 
@@ -129,17 +128,26 @@ static int zynqmp_aes_aead_cipher(struct aead_request *req)
 	else
 		hwreq->size = data_size - XILINX_AES_AUTH_SIZE;
 
-	if (hwreq->keysrc == ZYNQMP_AES_KUP_KEY) {
-		memcpy(kbuf + data_size + GCM_AES_IV_SIZE,
-		       tfm_ctx->key, AES_KEYSIZE_256);
-
-		hwreq->key = hwreq->src + data_size + GCM_AES_IV_SIZE;
-	} else {
+	if (hwreq->keysrc == ZYNQMP_AES_KUP_KEY)
+		hwreq->key = tfm_ctx->key_dma_addr;
+	else
 		hwreq->key = 0;
-	}
 
+	dma_addr_hw_req = dma_map_single(dev, dmabuf, sizeof(struct zynqmp_aead_hw_req) +
+					 GCM_AES_IV_SIZE,
+					 DMA_TO_DEVICE);
+	if (unlikely(dma_mapping_error(dev, dma_addr_hw_req))) {
+		ret = -ENOMEM;
+		dma_unmap_single(dev, dma_addr_data, dma_size, DMA_BIDIRECTIONAL);
+		goto freemem;
+	}
+	hwreq->iv = dma_addr_hw_req + sizeof(struct zynqmp_aead_hw_req);
+	dma_sync_single_for_device(dev, dma_addr_hw_req, sizeof(struct zynqmp_aead_hw_req) +
+				   GCM_AES_IV_SIZE, DMA_TO_DEVICE);
 	ret = zynqmp_pm_aes_engine(dma_addr_hw_req, &status);
-
+	dma_unmap_single(dev, dma_addr_hw_req, sizeof(struct zynqmp_aead_hw_req) + GCM_AES_IV_SIZE,
+			 DMA_TO_DEVICE);
+	dma_unmap_single(dev, dma_addr_data, dma_size, DMA_BIDIRECTIONAL);
 	if (ret) {
 		dev_err(dev, "ERROR: AES PM API failed\n");
 	} else if (status) {
@@ -170,15 +178,11 @@ static int zynqmp_aes_aead_cipher(struct aead_request *req)
 		ret = 0;
 	}
 
-	if (kbuf) {
-		memzero_explicit(kbuf, dma_size);
-		dma_free_coherent(dev, dma_size, kbuf, dma_addr_data);
-	}
-	if (hwreq) {
-		memzero_explicit(hwreq, sizeof(struct zynqmp_aead_hw_req));
-		dma_free_coherent(dev, sizeof(struct zynqmp_aead_hw_req),
-				  hwreq, dma_addr_hw_req);
-	}
+freemem:
+	memzero_explicit(kbuf, dma_size);
+	kfree(kbuf);
+	memzero_explicit(dmabuf, sizeof(struct zynqmp_aead_hw_req) + GCM_AES_IV_SIZE);
+	kfree(dmabuf);
 
 	return ret;
 }
@@ -231,6 +235,9 @@ static int zynqmp_aes_aead_setkey(struct crypto_aead *aead, const u8 *key,
 
 	if (keylen == AES_KEYSIZE_256) {
 		memcpy(tfm_ctx->key, key, keylen);
+		dma_sync_single_for_device(tfm_ctx->dev, tfm_ctx->key_dma_addr,
+					   AES_KEYSIZE_256,
+					   DMA_TO_DEVICE);
 	}
 
 	tfm_ctx->fbk_cipher->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
@@ -355,7 +362,7 @@ static int xilinx_paes_aead_init(struct crypto_aead *aead)
 	drv_alg = container_of(alg, struct xilinx_aead_alg, aead.base);
 	tfm_ctx->dev = drv_alg->aead_dev->dev;
 	tfm_ctx->keylen = 0;
-
+	tfm_ctx->key = NULL;
 	tfm_ctx->fbk_cipher = NULL;
 	crypto_aead_set_reqsize(aead, sizeof(struct xilinx_aead_req_ctx));
 
@@ -383,7 +390,20 @@ static int xilinx_aes_aead_init(struct crypto_aead *aead)
 		       __func__, drv_ctx->aead.base.base.cra_name);
 		return PTR_ERR(tfm_ctx->fbk_cipher);
 	}
-
+	tfm_ctx->key = kmalloc(AES_KEYSIZE_256, GFP_KERNEL);
+	if (!tfm_ctx->key) {
+		crypto_free_aead(tfm_ctx->fbk_cipher);
+		return -ENOMEM;
+	}
+	tfm_ctx->key_dma_addr = dma_map_single(tfm_ctx->dev, tfm_ctx->key,
+					       AES_KEYSIZE_256,
+					       DMA_TO_DEVICE);
+	if (unlikely(dma_mapping_error(tfm_ctx->dev, tfm_ctx->key_dma_addr))) {
+		kfree(tfm_ctx->key);
+		crypto_free_aead(tfm_ctx->fbk_cipher);
+		tfm_ctx->fbk_cipher = NULL;
+		return -ENOMEM;
+	}
 	crypto_aead_set_reqsize(aead,
 				max(sizeof(struct xilinx_aead_req_ctx),
 				    sizeof(struct aead_request) +
@@ -405,6 +425,8 @@ static void xilinx_aes_aead_exit(struct crypto_aead *aead)
 	struct xilinx_aead_tfm_ctx *tfm_ctx =
 			(struct xilinx_aead_tfm_ctx *)crypto_tfm_ctx(tfm);
 
+	dma_unmap_single(tfm_ctx->dev, tfm_ctx->key_dma_addr, AES_KEYSIZE_256, DMA_TO_DEVICE);
+	kfree(tfm_ctx->key);
 	if (tfm_ctx->fbk_cipher) {
 		crypto_free_aead(tfm_ctx->fbk_cipher);
 		tfm_ctx->fbk_cipher = NULL;
-- 
2.49.1



From h.jain at amd.com  Sat Dec 20 07:59:04 2025
From: h.jain at amd.com (Harsh Jain)
Date: Sat, 20 Dec 2025 21:29:04 +0530
Subject: [PATCH v2 13/14] crypto: xilinx: cleanup: Remove un-necessary typecast operation
In-Reply-To: <20251220155905.346790-1-h.jain@amd.com>
References: <20251220155905.346790-1-h.jain@amd.com>
Message-ID: <20251220155905.346790-14-h.jain@amd.com>

Return type of crypto_tfm_ctx() is void *. Remove explicit type cast.

Signed-off-by: Harsh Jain <h.jain at amd.com>
---
 drivers/crypto/xilinx/zynqmp-aes-gcm.c | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/drivers/crypto/xilinx/zynqmp-aes-gcm.c b/drivers/crypto/xilinx/zynqmp-aes-gcm.c
index c2563c6837e4..80b0ace7b5ca 100644
--- a/drivers/crypto/xilinx/zynqmp-aes-gcm.c
+++ b/drivers/crypto/xilinx/zynqmp-aes-gcm.c
@@ -282,8 +282,7 @@ static int xilinx_aes_aead_setauthsize(struct crypto_aead *aead,
 				       unsigned int authsize)
 {
 	struct crypto_tfm *tfm = crypto_aead_tfm(aead);
-	struct xilinx_aead_tfm_ctx *tfm_ctx =
-			(struct xilinx_aead_tfm_ctx *)crypto_tfm_ctx(tfm);
+	struct xilinx_aead_tfm_ctx *tfm_ctx = crypto_tfm_ctx(tfm);
 
 	tfm_ctx->authsize = authsize;
 	return tfm_ctx->fbk_cipher ? crypto_aead_setauthsize(tfm_ctx->fbk_cipher, authsize) : 0;
@@ -372,8 +371,7 @@ static int xilinx_paes_aead_init(struct crypto_aead *aead)
 static int xilinx_aes_aead_init(struct crypto_aead *aead)
 {
 	struct crypto_tfm *tfm = crypto_aead_tfm(aead);
-	struct xilinx_aead_tfm_ctx *tfm_ctx =
-		(struct xilinx_aead_tfm_ctx *)crypto_tfm_ctx(tfm);
+	struct xilinx_aead_tfm_ctx *tfm_ctx = crypto_tfm_ctx(tfm);
 	struct xilinx_aead_alg *drv_ctx;
 	struct aead_alg *alg = crypto_aead_alg(aead);
 
@@ -422,8 +420,7 @@ static void xilinx_paes_aead_exit(struct crypto_aead *aead)
 static void xilinx_aes_aead_exit(struct crypto_aead *aead)
 {
 	struct crypto_tfm *tfm = crypto_aead_tfm(aead);
-	struct xilinx_aead_tfm_ctx *tfm_ctx =
-			(struct xilinx_aead_tfm_ctx *)crypto_tfm_ctx(tfm);
+	struct xilinx_aead_tfm_ctx *tfm_ctx = crypto_tfm_ctx(tfm);
 
 	dma_unmap_single(tfm_ctx->dev, tfm_ctx->key_dma_addr, AES_KEYSIZE_256, DMA_TO_DEVICE);
 	kfree(tfm_ctx->key);
-- 
2.49.1



From h.jain at amd.com  Sat Dec 20 07:59:03 2025
From: h.jain at amd.com (Harsh Jain)
Date: Sat, 20 Dec 2025 21:29:03 +0530
Subject: [PATCH v2 12/14] firmware: xilinx: Add firmware API's to support aes-gcm in Versal device
In-Reply-To: <20251220155905.346790-1-h.jain@amd.com>
References: <20251220155905.346790-1-h.jain@amd.com>
Message-ID: <20251220155905.346790-13-h.jain@amd.com>

Add aes-gcm crypto API's for AMD/Xilinx Versal device.

Signed-off-by: Harsh Jain <h.jain at amd.com>
---
 drivers/firmware/xilinx/zynqmp-crypto.c     | 151 +++++++++++++++++++-
 include/linux/firmware/xlnx-zynqmp-crypto.h |  76 +++++++++-
 2 files changed, 224 insertions(+), 3 deletions(-)

diff --git a/drivers/firmware/xilinx/zynqmp-crypto.c b/drivers/firmware/xilinx/zynqmp-crypto.c
index 6d17cb8b27b3..4260d6fa2536 100644
--- a/drivers/firmware/xilinx/zynqmp-crypto.c
+++ b/drivers/firmware/xilinx/zynqmp-crypto.c
@@ -60,7 +60,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_sha_hash);
 
 /**
  * xlnx_get_crypto_dev_data() - Get crypto dev data of platform
- * @feature_map:       List of available feature map of all platform
+ * @feature_map:	List of available feature map of all platform
  *
  * Return: Returns crypto dev data, either address crypto dev or ERR PTR
  */
@@ -88,3 +88,152 @@ void *xlnx_get_crypto_dev_data(struct xlnx_feature *feature_map)
 	return ERR_PTR(-ENODEV);
 }
 EXPORT_SYMBOL_GPL(xlnx_get_crypto_dev_data);
+
+/**
+ * versal_pm_aes_key_write - Write AES key registers
+ * @keylen:	Size of the input key to be written
+ * @keysrc:	Key Source to be selected to which provided
+ *		key should be updated
+ * @keyaddr:	Address of a buffer which should contain the key
+ *		to be written
+ *
+ * This function provides support to write AES volatile user keys.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+int versal_pm_aes_key_write(const u32 keylen,
+			    const u32 keysrc, const u64 keyaddr)
+{
+	return zynqmp_pm_invoke_fn(XSECURE_API_AES_WRITE_KEY, NULL, 4,
+				   keylen, keysrc,
+				   lower_32_bits(keyaddr),
+				   upper_32_bits(keyaddr));
+}
+EXPORT_SYMBOL_GPL(versal_pm_aes_key_write);
+
+/**
+ * versal_pm_aes_key_zero - Zeroise AES User key registers
+ * @keysrc:	Key Source to be selected to which provided
+ *		key should be updated
+ *
+ * This function provides support to zeroise AES volatile user keys.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+int versal_pm_aes_key_zero(const u32 keysrc)
+{
+	return zynqmp_pm_invoke_fn(XSECURE_API_AES_KEY_ZERO, NULL, 1, keysrc);
+}
+EXPORT_SYMBOL_GPL(versal_pm_aes_key_zero);
+
+/**
+ * versal_pm_aes_op_init - Init AES operation
+ * @hw_req:	AES op init structure address
+ *
+ * This function provides support to init AES operation.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+int versal_pm_aes_op_init(const u64 hw_req)
+{
+	return zynqmp_pm_invoke_fn(XSECURE_API_AES_OP_INIT, NULL, 2,
+				   lower_32_bits(hw_req),
+				   upper_32_bits(hw_req));
+}
+EXPORT_SYMBOL_GPL(versal_pm_aes_op_init);
+
+/**
+ * versal_pm_aes_update_aad - AES update aad
+ * @aad_addr:	AES aad address
+ * @aad_len:	AES aad data length
+ *
+ * This function provides support to update AAD data.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+int versal_pm_aes_update_aad(const u64 aad_addr, const u32 aad_len)
+{
+	return zynqmp_pm_invoke_fn(XSECURE_API_AES_UPDATE_AAD, NULL, 3,
+				   lower_32_bits(aad_addr),
+				   upper_32_bits(aad_addr),
+				   aad_len);
+}
+EXPORT_SYMBOL_GPL(versal_pm_aes_update_aad);
+
+/**
+ * versal_pm_aes_enc_update - Access AES hardware to encrypt the data using
+ * AES-GCM core.
+ * @in_params:	Address of the AesParams structure
+ * @in_addr:	Address of input buffer
+ *
+ * Return:	Returns status, either success or error code.
+ */
+int versal_pm_aes_enc_update(const u64 in_params, const u64 in_addr)
+{
+	return zynqmp_pm_invoke_fn(XSECURE_API_AES_ENCRYPT_UPDATE, NULL, 4,
+				   lower_32_bits(in_params),
+				   upper_32_bits(in_params),
+				   lower_32_bits(in_addr),
+				   upper_32_bits(in_addr));
+}
+EXPORT_SYMBOL_GPL(versal_pm_aes_enc_update);
+
+/**
+ * versal_pm_aes_enc_final - Access AES hardware to store the GCM tag
+ * @gcm_addr:	Address of the gcm tag
+ *
+ * Return:	Returns status, either success or error code.
+ */
+int versal_pm_aes_enc_final(const u64 gcm_addr)
+{
+	return zynqmp_pm_invoke_fn(XSECURE_API_AES_ENCRYPT_FINAL, NULL, 2,
+				   lower_32_bits(gcm_addr),
+				   upper_32_bits(gcm_addr));
+}
+EXPORT_SYMBOL_GPL(versal_pm_aes_enc_final);
+
+/**
+ * versal_pm_aes_dec_update - Access AES hardware to decrypt the data using
+ * AES-GCM core.
+ * @in_params:	Address of the AesParams structure
+ * @in_addr:	Address of input buffer
+ *
+ * Return:	Returns status, either success or error code.
+ */
+int versal_pm_aes_dec_update(const u64 in_params, const u64 in_addr)
+{
+	return zynqmp_pm_invoke_fn(XSECURE_API_AES_DECRYPT_UPDATE, NULL, 4,
+				   lower_32_bits(in_params),
+				   upper_32_bits(in_params),
+				   lower_32_bits(in_addr),
+				   upper_32_bits(in_addr));
+}
+EXPORT_SYMBOL_GPL(versal_pm_aes_dec_update);
+
+/**
+ * versal_pm_aes_dec_final - Access AES hardware to get the GCM tag
+ * @gcm_addr:	Address of the gcm tag
+ *
+ * Return:	Returns status, either success or error code.
+ */
+int versal_pm_aes_dec_final(const u64 gcm_addr)
+{
+	return zynqmp_pm_invoke_fn(XSECURE_API_AES_DECRYPT_FINAL, NULL, 2,
+				   lower_32_bits(gcm_addr),
+				   upper_32_bits(gcm_addr));
+}
+EXPORT_SYMBOL_GPL(versal_pm_aes_dec_final);
+
+/**
+ * versal_pm_aes_init - Init AES block
+ *
+ * This function initialise AES block.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+int versal_pm_aes_init(void)
+{
+	return zynqmp_pm_invoke_fn(XSECURE_API_AES_INIT, NULL, 0);
+}
+EXPORT_SYMBOL_GPL(versal_pm_aes_init);
+
diff --git a/include/linux/firmware/xlnx-zynqmp-crypto.h b/include/linux/firmware/xlnx-zynqmp-crypto.h
index cb08f412e931..56595ab37c43 100644
--- a/include/linux/firmware/xlnx-zynqmp-crypto.h
+++ b/include/linux/firmware/xlnx-zynqmp-crypto.h
@@ -2,8 +2,8 @@
 /*
  * Firmware layer for XilSECURE APIs.
  *
- *  Copyright (C) 2014-2022 Xilinx, Inc.
- *  Copyright (C) 2022-2025 Advanced Micro Devices, Inc.
+ * Copyright (C) 2014-2022 Xilinx, Inc.
+ * Copyright (C) 2022-2025 Advanced Micro Devices, Inc.
  */
 
 #ifndef __FIRMWARE_XLNX_ZYNQMP_CRYPTO_H__
@@ -22,10 +22,32 @@ struct xlnx_feature {
 	void *data;
 };
 
+/* xilSecure API commands module id + api id */
+#define XSECURE_API_AES_INIT		0x509
+#define XSECURE_API_AES_OP_INIT		0x50a
+#define XSECURE_API_AES_UPDATE_AAD	0x50b
+#define XSECURE_API_AES_ENCRYPT_UPDATE	0x50c
+#define XSECURE_API_AES_ENCRYPT_FINAL	0x50d
+#define XSECURE_API_AES_DECRYPT_UPDATE	0x50e
+#define XSECURE_API_AES_DECRYPT_FINAL	0x50f
+#define XSECURE_API_AES_KEY_ZERO	0x510
+#define XSECURE_API_AES_WRITE_KEY	0x511
+
 #if IS_REACHABLE(CONFIG_ZYNQMP_FIRMWARE)
 int zynqmp_pm_aes_engine(const u64 address, u32 *out);
 int zynqmp_pm_sha_hash(const u64 address, const u32 size, const u32 flags);
 void *xlnx_get_crypto_dev_data(struct xlnx_feature *feature_map);
+int versal_pm_aes_key_write(const u32 keylen,
+			    const u32 keysrc, const u64 keyaddr);
+int versal_pm_aes_key_zero(const u32 keysrc);
+int versal_pm_aes_op_init(const u64 hw_req);
+int versal_pm_aes_update_aad(const u64 aad_addr, const u32 aad_len);
+int versal_pm_aes_enc_update(const u64 in_params, const u64 in_addr);
+int versal_pm_aes_dec_update(const u64 in_params, const u64 in_addr);
+int versal_pm_aes_dec_final(const u64 gcm_addr);
+int versal_pm_aes_enc_final(const u64 gcm_addr);
+int versal_pm_aes_init(void);
+
 #else
 static inline int zynqmp_pm_aes_engine(const u64 address, u32 *out)
 {
@@ -42,6 +64,56 @@ static inline void *xlnx_get_crypto_dev_data(struct xlnx_feature *feature_map)
 {
 	return ERR_PTR(-ENODEV);
 }
+
+static inline int versal_pm_aes_key_write(const u32 keylen,
+					  const u32 keysrc, const u64 keyaddr)
+{
+	return -ENODEV;
+}
+
+static inline int versal_pm_aes_key_zero(const u32 keysrc)
+{
+	return -ENODEV;
+}
+
+static inline int versal_pm_aes_op_init(const u64 hw_req)
+{
+	return -ENODEV;
+}
+
+static inline int versal_pm_aes_update_aad(const u64 aad_addr,
+					   const u32 aad_len)
+{
+	return -ENODEV;
+}
+
+static inline int versal_pm_aes_enc_update(const u64 in_params,
+					   const u64 in_addr)
+{
+	return -ENODEV;
+}
+
+static inline int versal_pm_aes_dec_update(const u64 in_params,
+					   const u64 in_addr)
+{
+	return -ENODEV;
+}
+
+static inline int versal_pm_aes_enc_final(const u64 gcm_addr)
+{
+	return -ENODEV;
+}
+
+static inline int versal_pm_aes_dec_final(const u64 gcm_addr)
+{
+	return -ENODEV;
+}
+
+static inline int versal_pm_aes_init(void)
+{
+	return -ENODEV;
+}
+
 #endif
 
 #endif /* __FIRMWARE_XLNX_ZYNQMP_CRYPTO_H__ */
-- 
2.49.1



From h.jain at amd.com  Sat Dec 20 07:59:05 2025
From: h.jain at amd.com (Harsh Jain)
Date: Sat, 20 Dec 2025 21:29:05 +0530
Subject: [PATCH v2 14/14] crypto: xilinx: Add gcm(aes) support for AMD/Xilinx Versal device
In-Reply-To: <20251220155905.346790-1-h.jain@amd.com>
References: <20251220155905.346790-1-h.jain@amd.com>
Message-ID: <20251220155905.346790-15-h.jain@amd.com>

Add gcm(aes) algorithm support for AMD/Xilinx Versal devices.

Signed-off-by: Harsh Jain <h.jain at amd.com>
---
 drivers/crypto/xilinx/zynqmp-aes-gcm.c | 430 ++++++++++++++++++++++++-
 1 file changed, 421 insertions(+), 9 deletions(-)

diff --git a/drivers/crypto/xilinx/zynqmp-aes-gcm.c b/drivers/crypto/xilinx/zynqmp-aes-gcm.c
index 80b0ace7b5ca..53c9cb2224bd 100644
--- a/drivers/crypto/xilinx/zynqmp-aes-gcm.c
+++ b/drivers/crypto/xilinx/zynqmp-aes-gcm.c
@@ -1,7 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
  * Xilinx ZynqMP AES Driver.
- * Copyright (c) 2020 Xilinx Inc.
+ * Copyright (C) 2020-2022 Xilinx Inc.
+ * Copyright (C) 2022-2025 Advanced Micro Devices, Inc.
  */
 
 #include <crypto/aes.h>
@@ -19,11 +20,13 @@
 #include <linux/string.h>
 
 #define ZYNQMP_DMA_BIT_MASK	32U
+#define VERSAL_DMA_BIT_MASK		64U
 #define XILINX_AES_AUTH_SIZE		16U
 #define XILINX_AES_BLK_SIZE		1U
 #define ZYNQMP_AES_MIN_INPUT_BLK_SIZE	4U
 #define ZYNQMP_AES_WORD_LEN		4U
 
+#define VERSAL_AES_QWORD_LEN		16U
 #define ZYNQMP_AES_GCM_TAG_MISMATCH_ERR	0x01
 #define ZYNQMP_AES_WRONG_KEY_SRC_ERR	0x13
 #define ZYNQMP_AES_PUF_NOT_PROGRAMMED	0xE300
@@ -49,6 +52,7 @@ struct xilinx_aead_dev {
 struct xilinx_aead_alg {
 	struct xilinx_aead_dev *aead_dev;
 	struct aead_engine_alg aead;
+	int (*aes_aead_cipher)(struct aead_request *areq);
 	u8 dma_bit_mask;
 };
 
@@ -83,6 +87,54 @@ struct xilinx_aead_req_ctx {
 
 static struct xilinx_aead_dev *aead_dev;
 
+enum versal_aead_keysrc {
+	VERSAL_AES_BBRAM_KEY = 0,
+	VERSAL_AES_BBRAM_RED_KEY,
+	VERSAL_AES_BH_KEY,
+	VERSAL_AES_BH_RED_KEY,
+	VERSAL_AES_EFUSE_KEY,
+	VERSAL_AES_EFUSE_RED_KEY,
+	VERSAL_AES_EFUSE_USER_KEY_0,
+	VERSAL_AES_EFUSE_USER_KEY_1,
+	VERSAL_AES_EFUSE_USER_RED_KEY_0,
+	VERSAL_AES_EFUSE_USER_RED_KEY_1,
+	VERSAL_AES_KUP_KEY,
+	VERSAL_AES_PUF_KEY,
+	VERSAL_AES_USER_KEY_0,
+	VERSAL_AES_USER_KEY_1,
+	VERSAL_AES_USER_KEY_2,
+	VERSAL_AES_USER_KEY_3,
+	VERSAL_AES_USER_KEY_4,
+	VERSAL_AES_USER_KEY_5,
+	VERSAL_AES_USER_KEY_6,
+	VERSAL_AES_USER_KEY_7,
+	VERSAL_AES_EXPANDED_KEYS,
+	VERSAL_AES_ALL_KEYS,
+};
+
+enum versal_aead_op {
+	VERSAL_AES_ENCRYPT = 0,
+	VERSAL_AES_DECRYPT
+};
+
+enum versal_aes_keysize {
+	HW_AES_KEY_SIZE_128 = 0,
+	HW_AES_KEY_SIZE_256 = 2,
+};
+
+struct versal_init_ops {
+	u64 iv;
+	u32 op;
+	u32 keysrc;
+	u32 size;
+};
+
+struct versal_in_params {
+	u64 in_data_addr;
+	u32 size;
+	u32 is_last;
+};
+
 static int zynqmp_aes_aead_cipher(struct aead_request *req)
 {
 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
@@ -187,6 +239,141 @@ static int zynqmp_aes_aead_cipher(struct aead_request *req)
 	return ret;
 }
 
+static int versal_aes_aead_cipher(struct aead_request *req)
+{
+	struct crypto_aead *aead = crypto_aead_reqtfm(req);
+	struct xilinx_aead_tfm_ctx *tfm_ctx = crypto_aead_ctx(aead);
+	struct xilinx_aead_req_ctx *rq_ctx = aead_request_ctx(req);
+	dma_addr_t dma_addr_data, dma_addr_hw_req, dma_addr_in;
+	u32 total_len = req->assoclen + req->cryptlen;
+	struct device *dev = tfm_ctx->dev;
+	struct versal_init_ops *hwreq;
+	struct versal_in_params *in;
+	u32 gcm_offset, out_len;
+	size_t dmabuf_size;
+	size_t kbuf_size;
+	void *dmabuf;
+	char *kbuf;
+	int ret;
+
+	kbuf_size = total_len + XILINX_AES_AUTH_SIZE;
+	kbuf = kmalloc(kbuf_size, GFP_KERNEL);
+	if (unlikely(!kbuf)) {
+		ret = -ENOMEM;
+		goto err;
+	}
+	dmabuf_size = sizeof(struct versal_init_ops) +
+		      sizeof(struct versal_in_params) +
+		      GCM_AES_IV_SIZE;
+	dmabuf = kmalloc(dmabuf_size, GFP_KERNEL);
+	if (unlikely(!dmabuf)) {
+		ret = -ENOMEM;
+		goto buf1_free;
+	}
+
+	dma_addr_hw_req = dma_map_single(dev, dmabuf, dmabuf_size, DMA_BIDIRECTIONAL);
+	if (unlikely(dma_mapping_error(dev, dma_addr_hw_req))) {
+		ret = -ENOMEM;
+		goto buf2_free;
+	}
+	scatterwalk_map_and_copy(kbuf, req->src, 0, total_len, 0);
+	dma_addr_data = dma_map_single(dev, kbuf, kbuf_size, DMA_BIDIRECTIONAL);
+	if (unlikely(dma_mapping_error(dev, dma_addr_data))) {
+		dma_unmap_single(dev, dma_addr_hw_req, dmabuf_size, DMA_BIDIRECTIONAL);
+		ret = -ENOMEM;
+		goto buf2_free;
+	}
+	hwreq = dmabuf;
+	in = dmabuf + sizeof(struct versal_init_ops);
+	memcpy(dmabuf + sizeof(struct versal_init_ops) +
+	       sizeof(struct versal_in_params), req->iv, GCM_AES_IV_SIZE);
+	hwreq->iv = dma_addr_hw_req + sizeof(struct versal_init_ops) +
+		    sizeof(struct versal_in_params);
+	hwreq->keysrc = tfm_ctx->keysrc;
+	dma_addr_in = dma_addr_hw_req + sizeof(struct versal_init_ops);
+	if (rq_ctx->op == XILINX_AES_ENCRYPT) {
+		hwreq->op = VERSAL_AES_ENCRYPT;
+		out_len = total_len + crypto_aead_authsize(aead);
+		in->size = req->cryptlen;
+	} else {
+		hwreq->op = VERSAL_AES_DECRYPT;
+		out_len = total_len - XILINX_AES_AUTH_SIZE;
+		in->size = req->cryptlen - XILINX_AES_AUTH_SIZE;
+	}
+
+	if (tfm_ctx->keylen == AES_KEYSIZE_128)
+		hwreq->size = HW_AES_KEY_SIZE_128;
+	else
+		hwreq->size = HW_AES_KEY_SIZE_256;
+
+	/* Request aes key write for volatile user keys */
+	if (hwreq->keysrc >= VERSAL_AES_USER_KEY_0 && hwreq->keysrc <= VERSAL_AES_USER_KEY_7) {
+		ret = versal_pm_aes_key_write(hwreq->size, hwreq->keysrc,
+					      tfm_ctx->key_dma_addr);
+		if (ret)
+			goto unmap;
+	}
+
+	in->in_data_addr = dma_addr_data + req->assoclen;
+	in->is_last = 1;
+	gcm_offset = req->assoclen + in->size;
+	dma_sync_single_for_device(dev, dma_addr_hw_req, dmabuf_size, DMA_BIDIRECTIONAL);
+	ret = versal_pm_aes_op_init(dma_addr_hw_req);
+	if (ret)
+		goto clearkey;
+
+	if (req->assoclen > 0) {
+		/* Currently GMAC is OFF by default */
+		ret = versal_pm_aes_update_aad(dma_addr_data, req->assoclen);
+		if (ret)
+			goto clearkey;
+	}
+	if (rq_ctx->op == XILINX_AES_ENCRYPT) {
+		ret = versal_pm_aes_enc_update(dma_addr_in,
+					       dma_addr_data + req->assoclen);
+		if (ret)
+			goto clearkey;
+
+		ret = versal_pm_aes_enc_final(dma_addr_data + gcm_offset);
+		if (ret)
+			goto clearkey;
+	} else {
+		ret = versal_pm_aes_dec_update(dma_addr_in,
+					       dma_addr_data + req->assoclen);
+		if (ret)
+			goto clearkey;
+
+		ret = versal_pm_aes_dec_final(dma_addr_data + gcm_offset);
+		if (ret) {
+			ret = -EBADMSG;
+			goto clearkey;
+		}
+	}
+	dma_unmap_single(dev, dma_addr_data, kbuf_size, DMA_BIDIRECTIONAL);
+	dma_unmap_single(dev, dma_addr_hw_req, dmabuf_size, DMA_BIDIRECTIONAL);
+	sg_copy_from_buffer(req->dst, sg_nents(req->dst),
+			    kbuf, out_len);
+	dma_addr_data = 0;
+	dma_addr_hw_req = 0;
+
+clearkey:
+	if (hwreq->keysrc >= VERSAL_AES_USER_KEY_0 && hwreq->keysrc <= VERSAL_AES_USER_KEY_7)
+		versal_pm_aes_key_zero(hwreq->keysrc);
+unmap:
+	if (unlikely(dma_addr_data))
+		dma_unmap_single(dev, dma_addr_data, kbuf_size, DMA_BIDIRECTIONAL);
+	if (unlikely(dma_addr_hw_req))
+		dma_unmap_single(dev, dma_addr_hw_req, dmabuf_size, DMA_BIDIRECTIONAL);
+buf2_free:
+	memzero_explicit(dmabuf, dmabuf_size);
+	kfree(dmabuf);
+buf1_free:
+	memzero_explicit(kbuf, kbuf_size);
+	kfree(kbuf);
+err:
+	return ret;
+}
+
 static int zynqmp_fallback_check(struct xilinx_aead_tfm_ctx *tfm_ctx,
 				 struct aead_request *req)
 {
@@ -212,13 +399,40 @@ static int zynqmp_fallback_check(struct xilinx_aead_tfm_ctx *tfm_ctx,
 	return 0;
 }
 
+static int versal_fallback_check(struct xilinx_aead_tfm_ctx *tfm_ctx,
+				 struct aead_request *req)
+{
+	struct xilinx_aead_req_ctx *rq_ctx = aead_request_ctx(req);
+
+	if (tfm_ctx->authsize != XILINX_AES_AUTH_SIZE && rq_ctx->op == XILINX_AES_DECRYPT)
+		return 1;
+
+	if (tfm_ctx->keylen == AES_KEYSIZE_192)
+		return 1;
+
+	if (req->cryptlen < ZYNQMP_AES_MIN_INPUT_BLK_SIZE ||
+	    req->cryptlen % ZYNQMP_AES_WORD_LEN ||
+	    req->assoclen % VERSAL_AES_QWORD_LEN)
+		return 1;
+
+	if (rq_ctx->op == XILINX_AES_DECRYPT &&
+	    req->cryptlen <= XILINX_AES_AUTH_SIZE)
+		return 1;
+
+	return 0;
+}
+
 static int xilinx_handle_aes_req(struct crypto_engine *engine, void *req)
 {
 	struct aead_request *areq =
 				container_of(req, struct aead_request, base);
+	struct crypto_aead *aead = crypto_aead_reqtfm(req);
+	struct aead_alg *alg = crypto_aead_alg(aead);
+	struct xilinx_aead_alg *drv_ctx;
 	int err;
 
-	err = zynqmp_aes_aead_cipher(areq);
+	drv_ctx = container_of(alg, struct xilinx_aead_alg, aead.base);
+	err = drv_ctx->aes_aead_cipher(areq);
 	local_bh_disable();
 	crypto_finalize_aead_request(engine, areq, err);
 	local_bh_enable();
@@ -278,6 +492,84 @@ static int zynqmp_paes_aead_setkey(struct crypto_aead *aead, const u8 *key,
 	return err;
 }
 
+static int versal_aes_aead_setkey(struct crypto_aead *aead, const u8 *key,
+				  unsigned int keylen)
+{
+	struct crypto_tfm *tfm = crypto_aead_tfm(aead);
+	struct xilinx_aead_tfm_ctx *tfm_ctx = crypto_tfm_ctx(tfm);
+	struct xilinx_hwkey_info hwkey;
+	unsigned char keysrc;
+	int err;
+
+	tfm_ctx->keysrc = VERSAL_AES_USER_KEY_0;
+	if (keylen == sizeof(struct xilinx_hwkey_info)) {
+		memcpy(&hwkey, key, sizeof(struct xilinx_hwkey_info));
+		if (hwkey.magic != XILINX_KEY_MAGIC)
+			return -EINVAL;
+
+		keysrc = hwkey.type;
+		if (keysrc >= VERSAL_AES_USER_KEY_1 &&
+		    keysrc  <= VERSAL_AES_USER_KEY_7) {
+			tfm_ctx->keysrc = keysrc;
+			tfm_ctx->keylen = sizeof(struct xilinx_hwkey_info);
+			return 0;
+		}
+		return -EINVAL;
+	}
+
+	if (keylen == AES_KEYSIZE_256 || keylen == AES_KEYSIZE_128) {
+		tfm_ctx->keylen = keylen;
+		memcpy(tfm_ctx->key, key, keylen);
+		dma_sync_single_for_device(tfm_ctx->dev, tfm_ctx->key_dma_addr,
+					   AES_KEYSIZE_256,
+					   DMA_TO_DEVICE);
+	}
+
+	tfm_ctx->fbk_cipher->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
+	tfm_ctx->fbk_cipher->base.crt_flags |= (aead->base.crt_flags &
+						CRYPTO_TFM_REQ_MASK);
+	err = crypto_aead_setkey(tfm_ctx->fbk_cipher, key, keylen);
+	if (!err)
+		tfm_ctx->keylen = keylen;
+
+	return err;
+}
+
+static int versal_paes_aead_setkey(struct crypto_aead *aead, const u8 *key,
+				   unsigned int keylen)
+{
+	struct crypto_tfm *tfm = crypto_aead_tfm(aead);
+	struct xilinx_aead_tfm_ctx *tfm_ctx = crypto_tfm_ctx(tfm);
+	struct xilinx_hwkey_info hwkey;
+	unsigned char keysrc;
+	int err = 0;
+
+	if (keylen != sizeof(struct xilinx_hwkey_info))
+		return -EINVAL;
+
+	memcpy(&hwkey, key, sizeof(struct xilinx_hwkey_info));
+	if (hwkey.magic != XILINX_KEY_MAGIC)
+		return -EINVAL;
+
+	keysrc = hwkey.type;
+
+	switch (keysrc) {
+	case VERSAL_AES_EFUSE_USER_KEY_0:
+	case VERSAL_AES_EFUSE_USER_KEY_1:
+	case VERSAL_AES_EFUSE_USER_RED_KEY_0:
+	case VERSAL_AES_EFUSE_USER_RED_KEY_1:
+	case VERSAL_AES_PUF_KEY:
+		tfm_ctx->keysrc = keysrc;
+		tfm_ctx->keylen = sizeof(struct xilinx_hwkey_info);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
 static int xilinx_aes_aead_setauthsize(struct crypto_aead *aead,
 				       unsigned int authsize)
 {
@@ -328,6 +620,31 @@ static int zynqmp_aes_aead_encrypt(struct aead_request *req)
 	return crypto_transfer_aead_request_to_engine(drv_ctx->aead_dev->engine, req);
 }
 
+static int versal_aes_aead_encrypt(struct aead_request *req)
+{
+	struct xilinx_aead_req_ctx *rq_ctx = aead_request_ctx(req);
+	struct crypto_aead *aead = crypto_aead_reqtfm(req);
+	struct xilinx_aead_tfm_ctx *tfm_ctx = crypto_aead_ctx(aead);
+	struct aead_alg *alg = crypto_aead_alg(aead);
+	struct xilinx_aead_alg *drv_ctx;
+	int err;
+
+	drv_ctx = container_of(alg, struct xilinx_aead_alg, aead.base);
+	rq_ctx->op = XILINX_AES_ENCRYPT;
+	if (tfm_ctx->keysrc >= VERSAL_AES_USER_KEY_0 &&
+	    tfm_ctx->keysrc <= VERSAL_AES_USER_KEY_7 &&
+	    tfm_ctx->keylen == sizeof(struct xilinx_hwkey_info))
+		return -EINVAL;
+	err = versal_fallback_check(tfm_ctx, req);
+	if (err && (tfm_ctx->keysrc < VERSAL_AES_USER_KEY_0 ||
+		    tfm_ctx->keysrc > VERSAL_AES_USER_KEY_7))
+		return -EOPNOTSUPP;
+	if (err)
+		return xilinx_aes_fallback_crypt(req, true);
+
+	return crypto_transfer_aead_request_to_engine(drv_ctx->aead_dev->engine, req);
+}
+
 static int zynqmp_aes_aead_decrypt(struct aead_request *req)
 {
 	struct xilinx_aead_req_ctx *rq_ctx = aead_request_ctx(req);
@@ -368,6 +685,33 @@ static int xilinx_paes_aead_init(struct crypto_aead *aead)
 	return 0;
 }
 
+static int versal_aes_aead_decrypt(struct aead_request *req)
+{
+	struct xilinx_aead_req_ctx *rq_ctx = aead_request_ctx(req);
+	struct crypto_aead *aead = crypto_aead_reqtfm(req);
+	struct xilinx_aead_tfm_ctx *tfm_ctx = crypto_aead_ctx(aead);
+	struct aead_alg *alg = crypto_aead_alg(aead);
+	struct xilinx_aead_alg *drv_ctx;
+	int err;
+
+	drv_ctx = container_of(alg, struct xilinx_aead_alg, aead.base);
+	rq_ctx->op = XILINX_AES_DECRYPT;
+	if (tfm_ctx->keysrc >= VERSAL_AES_USER_KEY_0 &&
+	    tfm_ctx->keysrc <= VERSAL_AES_USER_KEY_7 &&
+	    tfm_ctx->keylen == sizeof(struct xilinx_hwkey_info))
+		return -EINVAL;
+
+	err = versal_fallback_check(tfm_ctx, req);
+	if (err &&
+	    (tfm_ctx->keysrc < VERSAL_AES_USER_KEY_0 ||
+	    tfm_ctx->keysrc > VERSAL_AES_USER_KEY_7))
+		return -EOPNOTSUPP;
+	if (err)
+		return xilinx_aes_fallback_crypt(req, false);
+
+	return crypto_transfer_aead_request_to_engine(drv_ctx->aead_dev->engine, req);
+}
+
 static int xilinx_aes_aead_init(struct crypto_aead *aead)
 {
 	struct crypto_tfm *tfm = crypto_aead_tfm(aead);
@@ -384,8 +728,8 @@ static int xilinx_aes_aead_init(struct crypto_aead *aead)
 						CRYPTO_ALG_NEED_FALLBACK);
 
 	if (IS_ERR(tfm_ctx->fbk_cipher)) {
-		pr_err("%s() Error: failed to allocate fallback for %s\n",
-		       __func__, drv_ctx->aead.base.base.cra_name);
+		dev_err(tfm_ctx->dev, "failed to allocate fallback for %s\n",
+			drv_ctx->aead.base.base.cra_name);
 		return PTR_ERR(tfm_ctx->fbk_cipher);
 	}
 	tfm_ctx->key = kmalloc(AES_KEYSIZE_256, GFP_KERNEL);
@@ -433,6 +777,7 @@ static void xilinx_aes_aead_exit(struct crypto_aead *aead)
 
 static struct xilinx_aead_alg zynqmp_aes_algs[] = {
 	{
+		.aes_aead_cipher = zynqmp_aes_aead_cipher,
 		.aead.base = {
 			.setkey		= zynqmp_aes_aead_setkey,
 			.setauthsize	= xilinx_aes_aead_setauthsize,
@@ -462,6 +807,7 @@ static struct xilinx_aead_alg zynqmp_aes_algs[] = {
 		.dma_bit_mask = ZYNQMP_DMA_BIT_MASK,
 	},
 	{
+		.aes_aead_cipher = zynqmp_aes_aead_cipher,
 		.aead.base = {
 			.setkey		= zynqmp_paes_aead_setkey,
 			.setauthsize	= xilinx_aes_aead_setauthsize,
@@ -492,12 +838,80 @@ static struct xilinx_aead_alg zynqmp_aes_algs[] = {
 	{ /* sentinel */ }
 };
 
+static struct xilinx_aead_alg versal_aes_algs[] = {
+	{
+		.aes_aead_cipher = versal_aes_aead_cipher,
+		.aead.base = {
+			.setkey		= versal_aes_aead_setkey,
+			.setauthsize	= xilinx_aes_aead_setauthsize,
+			.encrypt	= versal_aes_aead_encrypt,
+			.decrypt	= versal_aes_aead_decrypt,
+			.init		= xilinx_aes_aead_init,
+			.exit		= xilinx_aes_aead_exit,
+			.ivsize		= GCM_AES_IV_SIZE,
+			.maxauthsize	= XILINX_AES_AUTH_SIZE,
+			.base = {
+			.cra_name		= "gcm(aes)",
+			.cra_driver_name	= "versal-aes-gcm",
+			.cra_priority		= 300,
+			.cra_flags		= CRYPTO_ALG_TYPE_AEAD |
+						  CRYPTO_ALG_ASYNC |
+						  CRYPTO_ALG_ALLOCATES_MEMORY |
+						  CRYPTO_ALG_KERN_DRIVER_ONLY |
+						  CRYPTO_ALG_NEED_FALLBACK,
+			.cra_blocksize		= XILINX_AES_BLK_SIZE,
+			.cra_ctxsize		= sizeof(struct xilinx_aead_tfm_ctx),
+			.cra_module		= THIS_MODULE,
+			}
+		},
+		.aead.op = {
+			.do_one_request = xilinx_handle_aes_req,
+		},
+		.dma_bit_mask = VERSAL_DMA_BIT_MASK,
+	},
+	{
+		.aes_aead_cipher = versal_aes_aead_cipher,
+		.aead.base = {
+			.setkey		= versal_paes_aead_setkey,
+			.setauthsize	= xilinx_aes_aead_setauthsize,
+			.encrypt	= versal_aes_aead_encrypt,
+			.decrypt	= versal_aes_aead_decrypt,
+			.init		= xilinx_paes_aead_init,
+			.exit		= xilinx_paes_aead_exit,
+			.ivsize		= GCM_AES_IV_SIZE,
+			.maxauthsize	= XILINX_AES_AUTH_SIZE,
+			.base = {
+			.cra_name		= "gcm(paes)",
+			.cra_driver_name	= "versal-paes-gcm",
+			.cra_priority		= 300,
+			.cra_flags		= CRYPTO_ALG_TYPE_AEAD |
+						  CRYPTO_ALG_ASYNC |
+						  CRYPTO_ALG_ALLOCATES_MEMORY |
+						  CRYPTO_ALG_KERN_DRIVER_ONLY,
+			.cra_blocksize		= XILINX_AES_BLK_SIZE,
+			.cra_ctxsize		= sizeof(struct xilinx_aead_tfm_ctx),
+			.cra_module		= THIS_MODULE,
+			}
+		},
+		.aead.op = {
+			.do_one_request = xilinx_handle_aes_req,
+		},
+		.dma_bit_mask = VERSAL_DMA_BIT_MASK,
+	},
+	{ /* sentinel */ }
+};
+
 static struct xlnx_feature aes_feature_map[] = {
 	{
 		.family = PM_ZYNQMP_FAMILY_CODE,
 		.feature_id = PM_SECURE_AES,
 		.data = zynqmp_aes_algs,
 	},
+	{
+		.family = PM_VERSAL_FAMILY_CODE,
+		.feature_id = XSECURE_API_AES_OP_INIT,
+		.data = versal_aes_algs,
+	},
 	{ /* sentinel */ }
 };
 
@@ -534,14 +948,13 @@ static int xilinx_aes_aead_probe(struct platform_device *pdev)
 	aead_dev->engine = crypto_engine_alloc_init(dev, 1);
 	if (!aead_dev->engine) {
 		dev_err(dev, "Cannot alloc AES engine\n");
-		err = -ENOMEM;
-		goto err_engine;
+		return -ENOMEM;
 	}
 
 	err = crypto_engine_start(aead_dev->engine);
 	if (err) {
 		dev_err(dev, "Cannot start AES engine\n");
-		goto err_engine;
+		goto err_engine_start;
 	}
 
 	for (i = 0; aead_dev->aead_algs[i].dma_bit_mask; i++) {
@@ -552,14 +965,13 @@ static int xilinx_aes_aead_probe(struct platform_device *pdev)
 			goto err_alg_register;
 		}
 	}
-	return 0;
 
 	return 0;
 
 err_alg_register:
 	while (i > 0)
 		crypto_engine_unregister_aead(&aead_dev->aead_algs[--i].aead);
-err_engine:
+err_engine_start:
 	crypto_engine_exit(aead_dev->engine);
 
 	return err;
-- 
2.49.1



From liujianfeng1994 at gmail.com  Sat Dec 20 08:46:04 2025
From: liujianfeng1994 at gmail.com (Jianfeng Liu)
Date: Sun, 21 Dec 2025 00:46:04 +0800
Subject: [PATCH v7 14/17] media: rkvdec: Add H264 support for the VDPU381 variant
In-Reply-To: <20251218232829.337811-15-detlev.casanova@collabora.com>
References: <20251218232829.337811-15-detlev.casanova@collabora.com>
Message-ID: <20251220164604.10052-1-liujianfeng1994@gmail.com>

Hi,

On Thu, 18 Dec 2025 18:28:24 -0500, Detlev Casanova wrote:
>+static int rkvdec_h264_start(struct rkvdec_ctx *ctx)
>+{
>+	struct rkvdec_dev *rkvdec = ctx->dev;
>+	struct rkvdec_h264_priv_tbl *priv_tbl;
>+	struct rkvdec_h264_ctx *h264_ctx;
>+	struct v4l2_ctrl *ctrl;
>+	int ret;
>+
>+	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
>+			      V4L2_CID_STATELESS_H264_SPS);
>+	if (!ctrl)
>+		return -EINVAL;
>+
>+	h264_ctx = kzalloc(sizeof(*h264_ctx), GFP_KERNEL);
>+	if (!h264_ctx)
>+		return -ENOMEM;

I can see the sps validation is removed:

	ret = rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps);
	if (ret)
		return ret;

This should fix decoding issue with chromium when minimum size of h264
decoder is lower than 32. While I find this issue is caused by chromium
not following v4l2 stateless spec, and I think checking sps at start
should be still necessary.

I have sent a fix to chromium[1] and it should get merged later.

[1] https://chromium-review.googlesource.com/c/chromium/src/+/7274555

Best regards,
Jianfeng


From lkp at intel.com  Sat Dec 20 09:15:12 2025
From: lkp at intel.com (kernel test robot)
Date: Sun, 21 Dec 2025 01:15:12 +0800
Subject: [PATCH 01/12] media: stm32: dcmi: Switch from __maybe_unused to
 pm_sleep_ptr()
In-Reply-To: <20251218-stm32-dcmi-dma-chaining-v1-1-39948ca6cbf6@foss.st.com>
References: <20251218-stm32-dcmi-dma-chaining-v1-1-39948ca6cbf6@foss.st.com>
Message-ID: <202512210044.xNNW6QJZ-lkp@intel.com>

Hi Alain,

kernel test robot noticed the following build warnings:

[auto build test WARNING on atorgue-stm32/stm32-next]
[also build test WARNING on robh/for-next linus/master v6.19-rc1 next-20251219]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Alain-Volmat/media-stm32-dcmi-Switch-from-__maybe_unused-to-pm_sleep_ptr/20251219-024836
base:   https://git.kernel.org/pub/scm/linux/kernel/git/atorgue/stm32.git stm32-next
patch link:    https://lore.kernel.org/r/20251218-stm32-dcmi-dma-chaining-v1-1-39948ca6cbf6%40foss.st.com
patch subject: [PATCH 01/12] media: stm32: dcmi: Switch from __maybe_unused to pm_sleep_ptr()
config: arc-allyesconfig (https://download.01.org/0day-ci/archive/20251221/202512210044.xNNW6QJZ-lkp at intel.com/config)
compiler: arc-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251221/202512210044.xNNW6QJZ-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512210044.xNNW6QJZ-lkp at intel.com/

All warnings (new ones prefixed by >>):

>> drivers/media/platform/st/stm32/stm32-dcmi.c:2127:12: warning: 'dcmi_resume' defined but not used [-Wunused-function]
    2127 | static int dcmi_resume(struct device *dev)
         |            ^~~~~~~~~~~
>> drivers/media/platform/st/stm32/stm32-dcmi.c:2116:12: warning: 'dcmi_suspend' defined but not used [-Wunused-function]
    2116 | static int dcmi_suspend(struct device *dev)
         |            ^~~~~~~~~~~~


vim +/dcmi_resume +2127 drivers/media/platform/st/stm32/stm32-dcmi.c

  2115	
> 2116	static int dcmi_suspend(struct device *dev)
  2117	{
  2118		/* disable clock */
  2119		pm_runtime_force_suspend(dev);
  2120	
  2121		/* change pinctrl state */
  2122		pinctrl_pm_select_sleep_state(dev);
  2123	
  2124		return 0;
  2125	}
  2126	
> 2127	static int dcmi_resume(struct device *dev)
  2128	{
  2129		/* restore pinctl default state */
  2130		pinctrl_pm_select_default_state(dev);
  2131	
  2132		/* clock enable */
  2133		pm_runtime_force_resume(dev);
  2134	
  2135		return 0;
  2136	}
  2137	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From lkp at intel.com  Sat Dec 20 09:37:38 2025
From: lkp at intel.com (kernel test robot)
Date: Sat, 20 Dec 2025 18:37:38 +0100
Subject: [PATCH 5/6] dma-mapping: Allow batched DMA sync operations if
 supported by the arch
In-Reply-To: <20251219053658.84978-6-21cnbao@gmail.com>
References: <20251219053658.84978-6-21cnbao@gmail.com>
Message-ID: <202512201836.f6KX6WMH-lkp@intel.com>

Hi Barry,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on next-20251219]
[cannot apply to arm64/for-next/core v6.16-rc1]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Barry-Song/arm64-Provide-dcache_by_myline_op_nosync-helper/20251219-195810
base:   linus/master
patch link:    https://lore.kernel.org/r/20251219053658.84978-6-21cnbao%40gmail.com
patch subject: [PATCH 5/6] dma-mapping: Allow batched DMA sync operations if supported by the arch
config: x86_64-kexec (https://download.01.org/0day-ci/archive/20251220/202512201836.f6KX6WMH-lkp at intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251220/202512201836.f6KX6WMH-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512201836.f6KX6WMH-lkp at intel.com/

All errors (new ones prefixed by >>):

>> kernel/dma/direct.c:456:4: error: call to undeclared function 'dma_direct_unmap_phys_batch_add'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     456 |                         dma_direct_unmap_phys_batch_add(dev, sg->dma_address,
         |                         ^
   kernel/dma/direct.c:456:4: note: did you mean 'dma_direct_unmap_phys'?
   kernel/dma/direct.h:188:20: note: 'dma_direct_unmap_phys' declared here
     188 | static inline void dma_direct_unmap_phys(struct device *dev, dma_addr_t addr,
         |                    ^
>> kernel/dma/direct.c:484:22: error: call to undeclared function 'dma_direct_map_phys_batch_add'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     484 |                         sg->dma_address = dma_direct_map_phys_batch_add(dev, sg_phys(sg),
         |                                           ^
   2 errors generated.


vim +/dma_direct_unmap_phys_batch_add +456 kernel/dma/direct.c

   439	
   440	/*
   441	 * Unmaps segments, except for ones marked as pci_p2pdma which do not
   442	 * require any further action as they contain a bus address.
   443	 */
   444	void dma_direct_unmap_sg(struct device *dev, struct scatterlist *sgl,
   445			int nents, enum dma_data_direction dir, unsigned long attrs)
   446	{
   447		struct scatterlist *sg;
   448		int i;
   449		bool need_sync = false;
   450	
   451		for_each_sg(sgl,  sg, nents, i) {
   452			if (sg_dma_is_bus_address(sg)) {
   453				sg_dma_unmark_bus_address(sg);
   454			} else {
   455				need_sync = true;
 > 456				dma_direct_unmap_phys_batch_add(dev, sg->dma_address,
   457						      sg_dma_len(sg), dir, attrs);
   458			}
   459		}
   460		if (need_sync && !dev_is_dma_coherent(dev))
   461			arch_sync_dma_batch_flush();
   462	}
   463	#endif
   464	
   465	int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
   466			enum dma_data_direction dir, unsigned long attrs)
   467	{
   468		struct pci_p2pdma_map_state p2pdma_state = {};
   469		struct scatterlist *sg;
   470		int i, ret;
   471		bool need_sync = false;
   472	
   473		for_each_sg(sgl, sg, nents, i) {
   474			switch (pci_p2pdma_state(&p2pdma_state, dev, sg_page(sg))) {
   475			case PCI_P2PDMA_MAP_THRU_HOST_BRIDGE:
   476				/*
   477				 * Any P2P mapping that traverses the PCI host bridge
   478				 * must be mapped with CPU physical address and not PCI
   479				 * bus addresses.
   480				 */
   481				break;
   482			case PCI_P2PDMA_MAP_NONE:
   483				need_sync = true;
 > 484				sg->dma_address = dma_direct_map_phys_batch_add(dev, sg_phys(sg),
   485						sg->length, dir, attrs);
   486				if (sg->dma_address == DMA_MAPPING_ERROR) {
   487					ret = -EIO;
   488					goto out_unmap;
   489				}
   490				break;
   491			case PCI_P2PDMA_MAP_BUS_ADDR:
   492				sg->dma_address = pci_p2pdma_bus_addr_map(
   493					p2pdma_state.mem, sg_phys(sg));
   494				sg_dma_len(sg) = sg->length;
   495				sg_dma_mark_bus_address(sg);
   496				continue;
   497			default:
   498				ret = -EREMOTEIO;
   499				goto out_unmap;
   500			}
   501			sg_dma_len(sg) = sg->length;
   502		}
   503	
   504		if (need_sync && !dev_is_dma_coherent(dev))
   505			arch_sync_dma_batch_flush();
   506		return nents;
   507	
   508	out_unmap:
   509		dma_direct_unmap_sg(dev, sgl, i, dir, attrs | DMA_ATTR_SKIP_CPU_SYNC);
   510		return ret;
   511	}
   512	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From nicolas.frattaroli at collabora.com  Sat Dec 20 10:49:51 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Sat, 20 Dec 2025 19:49:51 +0100
Subject: [PATCH v2 0/4] Make MT8196 get its Mali GPU shader_present from
 nvmem
Message-ID: <20251220-mt8196-shader-present-v2-0-45b1ff1dfab0@collabora.com>

The MediaTek MT8196 SoC's Mali SHADER_PRESENT register does not list
only functional shader cores, but also those that are fused off to
improve yield.

The SHADER_PRESENT bitmask with the one fused off core omitted is to be
found in an efuse. However, the efuse address is considered
confidential, and is not public knowledge.

The MT8196 GPUEB MCU, which does the power management for the Mali GPU
on this SoC, knows and reads the efuse however, and exposes it in the
shared memory intended to communicate state to the application
processor. Reading the bitmask from this shared memory area is the
vendor's intended solution.

This series models this in the binding and implements it in the
corresponding Linux drivers:
- the mali-valhall-csf binding gets an nvmem-cells/nvmem-cell-names
  property to declare that shader-present is in a different castle
- the mt8196-gpufreq binding requires nodes to expose the shader-present
  cell
- panthor checks for the presence of the shader-present cell and uses it
  as the shader-present value if it's found, instead of the Mali GPU
  register contents
- mtk-mfg-pmdomain becomes an nvmem provider and will happily serve
  queries for the shader-present cell

While it would be preferable if we could read the efuse directly, it's
not possible as things stand, and insisting on it will just keep this
hardware from working in mainline. Running a GPU workload with a
SHADER_PRESENT bitmask that includes a faulty core results in corrupt
GPU rendering output.

Modelling the mt8196-gpufreq device as a nvmem-cell provider however is
not lying about the hardware's capabilities, as it truly does provide
access to the nvmem-cell, even if it acts as a proxy.

>From a bindings and panthor perspective, this is also generic enough to
where hypothetical other vendors doing the same thing (even with direct
efuse access) can rely on the same cell name and implementation.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
Changes in v2:
- panthor: move to nvmem_cell_read_variable_le_u64
- mtk-mfg-pmdomain: put of_node in error path
- mtk-mfg-pmdomain: remove leftover stray of_node_put on NULL
- Link to v1: https://lore.kernel.org/r/20251217-mt8196-shader-present-v1-0-f6f8f3aa1e93 at collabora.com

---
Nicolas Frattaroli (4):
      dt-bindings: gpu: mali-valhall-csf: Add shader-present nvmem cell
      dt-bindings: power: mt8196-gpufreq: Describe nvmem provider ability
      drm/panthor: Implement reading shader_present from nvmem
      pmdomain: mediatek: mtk-mfg: Expose shader_present as nvmem cell

 .../bindings/gpu/arm,mali-valhall-csf.yaml         | 14 +++++
 .../bindings/power/mediatek,mt8196-gpufreq.yaml    | 13 +++++
 drivers/gpu/drm/panthor/panthor_hw.c               | 36 ++++++++++---
 drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c       | 59 ++++++++++++++++++++++
 4 files changed, 116 insertions(+), 6 deletions(-)
---
base-commit: 638148c6ffa31d2e4958d51708ff3675221e2da7
change-id: 20251217-mt8196-shader-present-e2dc3f97fc74

Best regards,
-- 
Nicolas Frattaroli <nicolas.frattaroli at collabora.com>



From nicolas.frattaroli at collabora.com  Sat Dec 20 10:49:54 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Sat, 20 Dec 2025 19:49:54 +0100
Subject: [PATCH v2 3/4] drm/panthor: Implement reading shader_present from
 nvmem
In-Reply-To: <20251220-mt8196-shader-present-v2-0-45b1ff1dfab0@collabora.com>
References: <20251220-mt8196-shader-present-v2-0-45b1ff1dfab0@collabora.com>
Message-ID: <20251220-mt8196-shader-present-v2-3-45b1ff1dfab0@collabora.com>

On some platforms, notably MediaTek MT8196, the shader_present bitmask
in the Mali GPU register for it has cores enabled that may be faulty.
The true shader_present bitmask is found in an efuse instead.

Implement reading shader_present from an nvmem cell if one is present,
falling back to the Mali register if it's absent. The error codes are
trickled up through to the probe function so that probe deferral works.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/panthor/panthor_hw.c | 36 ++++++++++++++++++++++++++++++------
 1 file changed, 30 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c
index 87ebb7ae42c4..80c521784cd3 100644
--- a/drivers/gpu/drm/panthor/panthor_hw.c
+++ b/drivers/gpu/drm/panthor/panthor_hw.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0 or MIT
 /* Copyright 2025 ARM Limited. All rights reserved. */
 
+#include <linux/nvmem-consumer.h>
 #include <drm/drm_print.h>
 
 #include "panthor_device.h"
@@ -109,7 +110,25 @@ static char *get_gpu_model_name(struct panthor_device *ptdev)
 	return "(Unknown Mali GPU)";
 }
 
-static void panthor_gpu_info_init(struct panthor_device *ptdev)
+static int overload_shader_present(struct panthor_device *ptdev)
+{
+	u64 contents;
+	int ret;
+
+	ret = nvmem_cell_read_variable_le_u64(ptdev->base.dev, "shader-present",
+					      &contents);
+	if (!ret)
+		ptdev->gpu_info.shader_present = contents;
+	else if (ret == -ENOENT)
+		return 0;
+	else
+		return dev_err_probe(ptdev->base.dev, ret,
+				     "Failed to read shader-present nvmem cell\n");
+
+	return 0;
+}
+
+static int panthor_gpu_info_init(struct panthor_device *ptdev)
 {
 	unsigned int i;
 
@@ -143,13 +162,18 @@ static void panthor_gpu_info_init(struct panthor_device *ptdev)
 		ptdev->gpu_info.tiler_present = gpu_read64(ptdev, GPU_TILER_PRESENT);
 		ptdev->gpu_info.l2_present = gpu_read64(ptdev, GPU_L2_PRESENT);
 	}
+
+	return overload_shader_present(ptdev);
 }
 
-static void panthor_hw_info_init(struct panthor_device *ptdev)
+static int panthor_hw_info_init(struct panthor_device *ptdev)
 {
 	u32 major, minor, status;
+	int ret;
 
-	panthor_gpu_info_init(ptdev);
+	ret = panthor_gpu_info_init(ptdev);
+	if (ret)
+		return ret;
 
 	major = GPU_VER_MAJOR(ptdev->gpu_info.gpu_id);
 	minor = GPU_VER_MINOR(ptdev->gpu_info.gpu_id);
@@ -172,6 +196,8 @@ static void panthor_hw_info_init(struct panthor_device *ptdev)
 		 "shader_present=0x%0llx l2_present=0x%0llx tiler_present=0x%0llx",
 		 ptdev->gpu_info.shader_present, ptdev->gpu_info.l2_present,
 		 ptdev->gpu_info.tiler_present);
+
+	return 0;
 }
 
 static int panthor_hw_bind_device(struct panthor_device *ptdev)
@@ -218,7 +244,5 @@ int panthor_hw_init(struct panthor_device *ptdev)
 	if (ret)
 		return ret;
 
-	panthor_hw_info_init(ptdev);
-
-	return 0;
+	return panthor_hw_info_init(ptdev);
 }

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Sat Dec 20 10:49:53 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Sat, 20 Dec 2025 19:49:53 +0100
Subject: [PATCH v2 2/4] dt-bindings: power: mt8196-gpufreq: Describe nvmem
 provider ability
In-Reply-To: <20251220-mt8196-shader-present-v2-0-45b1ff1dfab0@collabora.com>
References: <20251220-mt8196-shader-present-v2-0-45b1ff1dfab0@collabora.com>
Message-ID: <20251220-mt8196-shader-present-v2-2-45b1ff1dfab0@collabora.com>

On the MediaTek MT8196 SoC, the Mali GPU's "shader_present" hardware
register may also include a non-functional shader core, along with the
present shader cores. An efuse elsewhere in the SoC provides the
shader_present mask with the fused off core omitted.

However, the efuse address is not publicly disclosed. What is known
though is that the GPUEB MCU reads this efuse, and exposes its contents
in the memory it shares with the application processor.

We can therefore describe the mediatek,mt8196-gpufreq device as being an
nvmem provider for this purpose, as it does provide nvmem access in an
indirect way.

The shader-present child node is left out of the list of required
properties as we may one day be able to describe the actual efuse region
this value comes from, so the gpufreq device isn't necessarily the only
device that can provide this cell, and implementations shouldn't need to
implement this functionality once this is the case.

Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 .../devicetree/bindings/power/mediatek,mt8196-gpufreq.yaml  | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/Documentation/devicetree/bindings/power/mediatek,mt8196-gpufreq.yaml b/Documentation/devicetree/bindings/power/mediatek,mt8196-gpufreq.yaml
index b9e43abaf8a4..66fc59b3c8b4 100644
--- a/Documentation/devicetree/bindings/power/mediatek,mt8196-gpufreq.yaml
+++ b/Documentation/devicetree/bindings/power/mediatek,mt8196-gpufreq.yaml
@@ -74,9 +74,18 @@ properties:
   "#clock-cells":
     const: 1
 
+  "#nvmem-cell-cells":
+    const: 0
+
   "#power-domain-cells":
     const: 0
 
+  shader-present:
+    type: object
+
+dependencies:
+  shader-present: [ "#nvmem-cell-cells" ]
+
 required:
   - compatible
   - reg
@@ -113,5 +122,9 @@ examples:
                      "ccf", "fast-dvfs";
         memory-region = <&gpueb_shared_memory>;
         #clock-cells = <1>;
+        #nvmem-cell-cells = <0>;
         #power-domain-cells = <0>;
+
+        shader-present {
+        };
     };

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Sat Dec 20 10:49:55 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Sat, 20 Dec 2025 19:49:55 +0100
Subject: [PATCH v2 4/4] pmdomain: mediatek: mtk-mfg: Expose shader_present
 as nvmem cell
In-Reply-To: <20251220-mt8196-shader-present-v2-0-45b1ff1dfab0@collabora.com>
References: <20251220-mt8196-shader-present-v2-0-45b1ff1dfab0@collabora.com>
Message-ID: <20251220-mt8196-shader-present-v2-4-45b1ff1dfab0@collabora.com>

Implement nvmem-provider functionality in mtk-mfg-pmdomain, such that it
can expose its GF_REG_SHADER_PRESENT value in the shared memory as an
nvmem cell for panthor.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c | 59 ++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)

diff --git a/drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c b/drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c
index 9bad577b3ae4..3ce6fb74dd53 100644
--- a/drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c
+++ b/drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c
@@ -10,6 +10,7 @@
 #include <linux/clk-provider.h>
 #include <linux/container_of.h>
 #include <linux/iopoll.h>
+#include <linux/nvmem-provider.h>
 #include <linux/mailbox_client.h>
 #include <linux/module.h>
 #include <linux/of.h>
@@ -872,6 +873,60 @@ static int mtk_mfg_init_clk_provider(struct mtk_mfg *mfg)
 	return 0;
 }
 
+static int mtk_mfg_read_nvmem(void *priv, unsigned int offset, void *val, size_t bytes)
+{
+	struct mtk_mfg *mfg = priv;
+	u32 *buf = val;
+
+	if (bytes != 4)
+		return -EINVAL;
+
+	if (!mfg->shared_mem)
+		return -ENODEV;
+
+	if (offset + bytes >= mfg->shared_mem_size)
+		return -EINVAL;
+
+	*buf = readl(mfg->shared_mem + offset);
+
+	return 0;
+}
+
+static int mtk_mfg_init_nvmem_provider(struct mtk_mfg *mfg)
+{
+	struct device *dev = &mfg->pdev->dev;
+	struct nvmem_cell_info cell = {};
+	struct nvmem_config config = {};
+	struct nvmem_device *nvdev;
+	int ret;
+
+	config.reg_read = mtk_mfg_read_nvmem;
+	config.dev = dev;
+	config.read_only = true;
+	config.priv = mfg;
+	config.size = 4;
+	config.word_size = 4;
+
+	nvdev = devm_nvmem_register(dev, &config);
+	if (IS_ERR(nvdev))
+		return dev_err_probe(dev, PTR_ERR(nvdev), "Couldn't register nvmem provider\n");
+
+	cell.name = "shader-present";
+	cell.offset = GF_REG_SHADER_PRESENT;
+	cell.bytes = 4;
+	cell.np = of_get_child_by_name(dev->of_node, cell.name);
+
+	ret = nvmem_add_one_cell(nvdev, &cell);
+	if (ret) {
+		of_node_put(cell.np);
+		return dev_err_probe(dev, ret, "Couldn't add cell %s\n", cell.name);
+	}
+
+	/* cell.np purposefully not put as nvmem_add_one_cell does not increase refcount */
+
+	return 0;
+}
+
 static int mtk_mfg_probe(struct platform_device *pdev)
 {
 	struct mtk_mfg *mfg;
@@ -984,6 +1039,10 @@ static int mtk_mfg_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_power_off;
 
+	ret = mtk_mfg_init_nvmem_provider(mfg);
+	if (ret)
+		goto err_power_off;
+
 	ret = of_genpd_add_provider_simple(dev->of_node, &mfg->pd);
 	if (ret) {
 		dev_err_probe(dev, ret, "Failed to add pmdomain provider\n");

-- 
2.52.0



From nicolas.frattaroli at collabora.com  Sat Dec 20 10:49:52 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Sat, 20 Dec 2025 19:49:52 +0100
Subject: [PATCH v2 1/4] dt-bindings: gpu: mali-valhall-csf: Add
 shader-present nvmem cell
In-Reply-To: <20251220-mt8196-shader-present-v2-0-45b1ff1dfab0@collabora.com>
References: <20251220-mt8196-shader-present-v2-0-45b1ff1dfab0@collabora.com>
Message-ID: <20251220-mt8196-shader-present-v2-1-45b1ff1dfab0@collabora.com>

On the MediaTek MT8196 SoC, the bitmask for which shader cores are
present and functional is not the one in the Mali GPU's registers, but
in an external efuse.

Add the nvmem cell properties to describe such a setup, and make them
required on MT8196.

Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 .../devicetree/bindings/gpu/arm,mali-valhall-csf.yaml      | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/Documentation/devicetree/bindings/gpu/arm,mali-valhall-csf.yaml b/Documentation/devicetree/bindings/gpu/arm,mali-valhall-csf.yaml
index bee9faf1d3f8..8eccd4338a2b 100644
--- a/Documentation/devicetree/bindings/gpu/arm,mali-valhall-csf.yaml
+++ b/Documentation/devicetree/bindings/gpu/arm,mali-valhall-csf.yaml
@@ -51,6 +51,14 @@ properties:
           - stacks
       - const: stacks
 
+  nvmem-cells:
+    items:
+      - description: bitmask of functional shader cores
+
+  nvmem-cell-names:
+    items:
+      - const: shader-present
+
   mali-supply: true
 
   operating-points-v2: true
@@ -108,6 +116,8 @@ allOf:
       properties:
         clocks:
           minItems: 3
+        nvmem-cells: false
+        nvmem-cell-names: false
         power-domains:
           maxItems: 1
         power-domain-names: false
@@ -133,6 +143,8 @@ allOf:
             - const: core
             - const: stacks
       required:
+        - nvmem-cells
+        - nvmem-cell-names
         - power-domains
 
 examples:
@@ -179,6 +191,8 @@ examples:
                      <GIC_SPI 605 IRQ_TYPE_LEVEL_HIGH 0>,
                      <GIC_SPI 604 IRQ_TYPE_LEVEL_HIGH 0>;
         interrupt-names = "job", "mmu", "gpu";
+        nvmem-cells = <&shader_present>;
+        nvmem-cell-names = "shader-present";
         power-domains = <&gpufreq>;
     };
 

-- 
2.52.0



From wsa+renesas at sang-engineering.com  Sat Dec 20 11:24:49 2025
From: wsa+renesas at sang-engineering.com (Wolfram Sang)
Date: Sat, 20 Dec 2025 20:24:49 +0100
Subject: [PATCH] ARM: dts: microchip: Drop usb_a9g20-dab-mmx.dtsi
In-Reply-To: <0ec01064-2755-401a-b2c8-76ad6ce686af@microchip.com>
References: <20251212203226.458694-8-robh@kernel.org>
 <aTytWyyZiYFnyauo@shikoro>
 <20251213010934353f1efe@mail.local>
 <0ec01064-2755-401a-b2c8-76ad6ce686af@microchip.com>
Message-ID: <aUb4AfDf8Ouh6vtD@shikoro>


> > I don't think this will be missed by anyone. Unless you actually have
> > one of the boards, I would simply drop this.
> 
> +1

Okay, then



From lkp at intel.com  Sat Dec 20 11:38:24 2025
From: lkp at intel.com (kernel test robot)
Date: Sun, 21 Dec 2025 03:38:24 +0800
Subject: [PATCHv5 bpf-next 9/9] bpf,x86: Use single ftrace_ops for direct
 calls
In-Reply-To: <20251215211402.353056-10-jolsa@kernel.org>
References: <20251215211402.353056-10-jolsa@kernel.org>
Message-ID: <202512210241.4wuAmCHu-lkp@intel.com>

Hi Jiri,

kernel test robot noticed the following build errors:

[auto build test ERROR on bpf-next/master]

url:    https://github.com/intel-lab-lkp/linux/commits/Jiri-Olsa/ftrace-bpf-Remove-FTRACE_OPS_FL_JMP-ftrace_ops-flag/20251216-052916
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master
patch link:    https://lore.kernel.org/r/20251215211402.353056-10-jolsa%40kernel.org
patch subject: [PATCHv5 bpf-next 9/9] bpf,x86: Use single ftrace_ops for direct calls
config: riscv-allmodconfig (https://download.01.org/0day-ci/archive/20251221/202512210241.4wuAmCHu-lkp at intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project b324c9f4fa112d61a553bf489b5f4f7ceea05ea8)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251221/202512210241.4wuAmCHu-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512210241.4wuAmCHu-lkp at intel.com/

All errors (new ones prefixed by >>):

>> kernel/bpf/trampoline.c:367:9: error: call to undeclared function 'direct_ops_del'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     367 |                 ret = direct_ops_del(tr, old_addr);
         |                       ^
   kernel/bpf/trampoline.c:367:9: note: did you mean 'direct_ops_free'?
   kernel/bpf/trampoline.c:298:13: note: 'direct_ops_free' declared here
     298 | static void direct_ops_free(struct bpf_trampoline *tr) { }
         |             ^
>> kernel/bpf/trampoline.c:381:9: error: call to undeclared function 'direct_ops_mod'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     381 |                 ret = direct_ops_mod(tr, new_addr, lock_direct_mutex);
         |                       ^
   kernel/bpf/trampoline.c:381:9: note: did you mean 'direct_ops_free'?
   kernel/bpf/trampoline.c:298:13: note: 'direct_ops_free' declared here
     298 | static void direct_ops_free(struct bpf_trampoline *tr) { }
         |             ^
>> kernel/bpf/trampoline.c:404:9: error: call to undeclared function 'direct_ops_add'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     404 |                 ret = direct_ops_add(tr, new_addr);
         |                       ^
   kernel/bpf/trampoline.c:404:9: note: did you mean 'direct_ops_free'?
   kernel/bpf/trampoline.c:298:13: note: 'direct_ops_free' declared here
     298 | static void direct_ops_free(struct bpf_trampoline *tr) { }
         |             ^
   3 errors generated.


vim +/direct_ops_del +367 kernel/bpf/trampoline.c

   360	
   361	static int unregister_fentry(struct bpf_trampoline *tr, u32 orig_flags,
   362				     void *old_addr)
   363	{
   364		int ret;
   365	
   366		if (tr->func.ftrace_managed)
 > 367			ret = direct_ops_del(tr, old_addr);
   368		else
   369			ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr, NULL);
   370	
   371		return ret;
   372	}
   373	
   374	static int modify_fentry(struct bpf_trampoline *tr, u32 orig_flags,
   375				 void *old_addr, void *new_addr,
   376				 bool lock_direct_mutex)
   377	{
   378		int ret;
   379	
   380		if (tr->func.ftrace_managed) {
 > 381			ret = direct_ops_mod(tr, new_addr, lock_direct_mutex);
   382		} else {
   383			ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr,
   384							   new_addr);
   385		}
   386		return ret;
   387	}
   388	
   389	/* first time registering */
   390	static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
   391	{
   392		void *ip = tr->func.addr;
   393		unsigned long faddr;
   394		int ret;
   395	
   396		faddr = ftrace_location((unsigned long)ip);
   397		if (faddr) {
   398			if (!tr->fops)
   399				return -ENOTSUPP;
   400			tr->func.ftrace_managed = true;
   401		}
   402	
   403		if (tr->func.ftrace_managed) {
 > 404			ret = direct_ops_add(tr, new_addr);
   405		} else {
   406			ret = bpf_trampoline_update_fentry(tr, 0, NULL, new_addr);
   407		}
   408	
   409		return ret;
   410	}
   411	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From pr-tracker-bot at kernel.org  Sat Dec 20 11:42:42 2025
From: pr-tracker-bot at kernel.org (pr-tracker-bot at kernel.org)
Date: Sat, 20 Dec 2025 19:42:42 +0000
Subject: [GIT PULL] arm64 updates/fixes for 6.19-rc2
In-Reply-To: <aUZxFI1CtSF2R5HX@arm.com>
References: <aUZxFI1CtSF2R5HX@arm.com>
Message-ID: <176625976290.123080.3526231548931362785.pr-tracker-bot@kernel.org>

The pull request you sent on Sat, 20 Dec 2025 09:49:08 +0000:

> git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux tags/arm64-fixes

has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/18dfd1cbf6a633c39256c76ca13114de46435e22

Thank you!

-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html


From sean at mess.org  Sat Dec 20 14:27:50 2025
From: sean at mess.org (Sean Young)
Date: Sat, 20 Dec 2025 22:27:50 +0000
Subject: [PATCH] media: rc: rc_unregister_device() should not call rc_free_device()
Message-ID: <20251220222757.7063-1-sean@mess.org>

rc_unregister_device() does two things: it marks the device as
unregistered, so no new commands can be issued via the lirc chardev,
and also frees the rc device. Device drivers want to both cancel
in-flight commands (i.e. kill urbs) and prevent further commands from
being issued. Only once both are done, can we really free the rc device,
because it might be referenced in urb callbacks. This is impossible to
do with the current way of things.

This change removes the implicit call to rc_free_device() from
rc_unregister_device(). This means that device drivers can call
rc_unregister_device() in their remove or disconnect function, then cancel
all the urbs and interrupts before explicitly calling rc_free_device().

Note this is an alternative fix for an issue found by Haotian Zhang, see
the Closes: tags.

Reported-by: Haotian Zhang <vulab at iscas.ac.cn>
Closes: https://lore.kernel.org/linux-media/20251114101432.2566-1-vulab at iscas.ac.cn
Closes: https://lore.kernel.org/linux-media/20251114101418.2548-1-vulab at iscas.ac.cn
Closes: https://lore.kernel.org/linux-media/20251114101346.2530-1-vulab at iscas.ac.cn/
Closes: https://lore.kernel.org/linux-media/20251114090605.2413-1-vulab at iscas.ac.cn/
Signed-off-by: Sean Young <sean at mess.org>
---
 drivers/gpu/drm/bridge/sil-sii8620.c        | 1 +
 drivers/hid/hid-picolcd_cir.c               | 1 +
 drivers/media/cec/core/cec-core.c           | 2 +-
 drivers/media/common/siano/smsir.c          | 1 +
 drivers/media/i2c/ir-kbd-i2c.c              | 2 ++
 drivers/media/pci/bt8xx/bttv-input.c        | 1 +
 drivers/media/pci/cx23885/cx23885-input.c   | 1 +
 drivers/media/pci/cx88/cx88-input.c         | 1 +
 drivers/media/pci/dm1105/dm1105.c           | 1 +
 drivers/media/pci/mantis/mantis_input.c     | 1 +
 drivers/media/pci/saa7134/saa7134-input.c   | 1 +
 drivers/media/pci/smipcie/smipcie-ir.c      | 1 +
 drivers/media/pci/ttpci/budget-ci.c         | 1 +
 drivers/media/rc/ati_remote.c               | 4 ++--
 drivers/media/rc/ene_ir.c                   | 2 +-
 drivers/media/rc/fintek-cir.c               | 3 ++-
 drivers/media/rc/igorplugusb.c              | 1 +
 drivers/media/rc/iguanair.c                 | 1 +
 drivers/media/rc/img-ir/img-ir-hw.c         | 3 ++-
 drivers/media/rc/img-ir/img-ir-raw.c        | 3 ++-
 drivers/media/rc/imon.c                     | 3 ++-
 drivers/media/rc/ir-hix5hd2.c               | 2 +-
 drivers/media/rc/ir_toy.c                   | 1 +
 drivers/media/rc/ite-cir.c                  | 2 +-
 drivers/media/rc/mceusb.c                   | 1 +
 drivers/media/rc/rc-ir-raw.c                | 5 -----
 drivers/media/rc/rc-loopback.c              | 1 +
 drivers/media/rc/rc-main.c                  | 6 +-----
 drivers/media/rc/redrat3.c                  | 4 +++-
 drivers/media/rc/st_rc.c                    | 2 +-
 drivers/media/rc/streamzap.c                | 3 ++-
 drivers/media/rc/sunxi-cir.c                | 1 +
 drivers/media/rc/ttusbir.c                  | 2 +-
 drivers/media/rc/winbond-cir.c              | 2 +-
 drivers/media/rc/xbox_remote.c              | 3 ++-
 drivers/media/usb/au0828/au0828-input.c     | 1 +
 drivers/media/usb/dvb-usb-v2/dvb_usb_core.c | 1 +
 drivers/media/usb/dvb-usb/dvb-usb-remote.c  | 6 ++++--
 drivers/media/usb/em28xx/em28xx-input.c     | 1 +
 drivers/staging/media/av7110/av7110_ir.c    | 1 +
 include/media/rc-core.h                     | 2 --
 41 files changed, 52 insertions(+), 30 deletions(-)

diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c
index 9e48ad39e1cc9..923e2ed30624b 100644
--- a/drivers/gpu/drm/bridge/sil-sii8620.c
+++ b/drivers/gpu/drm/bridge/sil-sii8620.c
@@ -2221,6 +2221,7 @@ static void sii8620_detach(struct drm_bridge *bridge)
 		return;
 
 	rc_unregister_device(ctx->rc_dev);
+	rc_free_device(ctx->rc_dev);
 }
 
 static int sii8620_is_packing_required(struct sii8620 *ctx,
diff --git a/drivers/hid/hid-picolcd_cir.c b/drivers/hid/hid-picolcd_cir.c
index d6faa0e00f95a..6d4c636e1c9f7 100644
--- a/drivers/hid/hid-picolcd_cir.c
+++ b/drivers/hid/hid-picolcd_cir.c
@@ -134,5 +134,6 @@ void picolcd_exit_cir(struct picolcd_data *data)
 
 	data->rc_dev = NULL;
 	rc_unregister_device(rdev);
+	rc_free_device(rdev);
 }
 
diff --git a/drivers/media/cec/core/cec-core.c b/drivers/media/cec/core/cec-core.c
index dd6e24a0899bd..1b8a33c05b3c9 100644
--- a/drivers/media/cec/core/cec-core.c
+++ b/drivers/media/cec/core/cec-core.c
@@ -338,8 +338,8 @@ int cec_register_adapter(struct cec_adapter *adap,
 	res = cec_devnode_register(&adap->devnode, adap->owner);
 	if (res) {
 #ifdef CONFIG_MEDIA_CEC_RC
-		/* Note: rc_unregister also calls rc_free */
 		rc_unregister_device(adap->rc);
+		rc_free_device(adap->rc);
 		adap->rc = NULL;
 #endif
 		return res;
diff --git a/drivers/media/common/siano/smsir.c b/drivers/media/common/siano/smsir.c
index af07fed21ae12..283770d583d56 100644
--- a/drivers/media/common/siano/smsir.c
+++ b/drivers/media/common/siano/smsir.c
@@ -92,6 +92,7 @@ int sms_ir_init(struct smscore_device_t *coredev)
 void sms_ir_exit(struct smscore_device_t *coredev)
 {
 	rc_unregister_device(coredev->ir.dev);
+	rc_free_device(coredev->ir.dev);
 
 	pr_debug("\n");
 }
diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c
index 5588cdd7ec20d..6047453170043 100644
--- a/drivers/media/i2c/ir-kbd-i2c.c
+++ b/drivers/media/i2c/ir-kbd-i2c.c
@@ -355,6 +355,7 @@ static void ir_work(struct work_struct *work)
 		mutex_unlock(&ir->lock);
 		if (rc == -ENODEV) {
 			rc_unregister_device(ir->rc);
+			rc_free_device(ir->rc);
 			ir->rc = NULL;
 			return;
 		}
@@ -972,6 +973,7 @@ static void ir_remove(struct i2c_client *client)
 	i2c_unregister_device(ir->tx_c);
 
 	rc_unregister_device(ir->rc);
+	rc_free_device(ir->rc);
 }
 
 static const struct i2c_device_id ir_kbd_id[] = {
diff --git a/drivers/media/pci/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c
index 84aa269248fd3..660788080cbe2 100644
--- a/drivers/media/pci/bt8xx/bttv-input.c
+++ b/drivers/media/pci/bt8xx/bttv-input.c
@@ -574,6 +574,7 @@ void bttv_input_fini(struct bttv *btv)
 
 	bttv_ir_stop(btv);
 	rc_unregister_device(btv->remote->dev);
+	rc_free_device(btv->remote->dev);
 	kfree(btv->remote);
 	btv->remote = NULL;
 }
diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c
index d2e84c6457e0a..722329ef3fd2c 100644
--- a/drivers/media/pci/cx23885/cx23885-input.c
+++ b/drivers/media/pci/cx23885/cx23885-input.c
@@ -402,6 +402,7 @@ void cx23885_input_fini(struct cx23885_dev *dev)
 	if (dev->kernel_ir == NULL)
 		return;
 	rc_unregister_device(dev->kernel_ir->rc);
+	rc_free_device(dev->kernel_ir->rc);
 	kfree(dev->kernel_ir->phys);
 	kfree(dev->kernel_ir->name);
 	kfree(dev->kernel_ir);
diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c
index b9f2c14d62b40..16c56d19f916d 100644
--- a/drivers/media/pci/cx88/cx88-input.c
+++ b/drivers/media/pci/cx88/cx88-input.c
@@ -511,6 +511,7 @@ int cx88_ir_fini(struct cx88_core *core)
 
 	cx88_ir_stop(core);
 	rc_unregister_device(ir->dev);
+	rc_free_device(ir->dev);
 	kfree(ir);
 
 	/* done */
diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c
index 9e9c7c071accc..e1185aa669f48 100644
--- a/drivers/media/pci/dm1105/dm1105.c
+++ b/drivers/media/pci/dm1105/dm1105.c
@@ -763,6 +763,7 @@ static int dm1105_ir_init(struct dm1105_dev *dm1105)
 static void dm1105_ir_exit(struct dm1105_dev *dm1105)
 {
 	rc_unregister_device(dm1105->ir.dev);
+	rc_free_device(dm1105->ir.dev);
 }
 
 static int dm1105_hw_init(struct dm1105_dev *dev)
diff --git a/drivers/media/pci/mantis/mantis_input.c b/drivers/media/pci/mantis/mantis_input.c
index 34c0d979240fd..edb4cacf55d22 100644
--- a/drivers/media/pci/mantis/mantis_input.c
+++ b/drivers/media/pci/mantis/mantis_input.c
@@ -72,5 +72,6 @@ EXPORT_SYMBOL_GPL(mantis_input_init);
 void mantis_input_exit(struct mantis_pci *mantis)
 {
 	rc_unregister_device(mantis->rc);
+	rc_free_device(mantis->rc);
 }
 EXPORT_SYMBOL_GPL(mantis_input_exit);
diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c
index 468dbe8d552f8..d39537c95d9d3 100644
--- a/drivers/media/pci/saa7134/saa7134-input.c
+++ b/drivers/media/pci/saa7134/saa7134-input.c
@@ -834,6 +834,7 @@ void saa7134_input_fini(struct saa7134_dev *dev)
 		return;
 
 	rc_unregister_device(dev->remote->dev);
+	rc_free_device(dev->remote->dev);
 	kfree(dev->remote);
 	dev->remote = NULL;
 }
diff --git a/drivers/media/pci/smipcie/smipcie-ir.c b/drivers/media/pci/smipcie/smipcie-ir.c
index c0604d9c70119..2949cc97462d4 100644
--- a/drivers/media/pci/smipcie/smipcie-ir.c
+++ b/drivers/media/pci/smipcie/smipcie-ir.c
@@ -180,6 +180,7 @@ void smi_ir_exit(struct smi_dev *dev)
 	struct rc_dev *rc_dev = ir->rc_dev;
 
 	rc_unregister_device(rc_dev);
+	rc_free_device(rc_dev);
 	smi_ir_stop(ir);
 	ir->rc_dev = NULL;
 }
diff --git a/drivers/media/pci/ttpci/budget-ci.c b/drivers/media/pci/ttpci/budget-ci.c
index 33f08adf4feb1..16973ac8e6a92 100644
--- a/drivers/media/pci/ttpci/budget-ci.c
+++ b/drivers/media/pci/ttpci/budget-ci.c
@@ -249,6 +249,7 @@ static void msp430_ir_deinit(struct budget_ci *budget_ci)
 	cancel_work_sync(&budget_ci->ir.msp430_irq_bh_work);
 
 	rc_unregister_device(budget_ci->ir.dev);
+	rc_free_device(budget_ci->ir.dev);
 }
 
 static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index a733914a25742..1dd1edb3702c6 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -921,7 +921,6 @@ static int ati_remote_probe(struct usb_interface *interface,
 	input_free_device(input_dev);
  exit_unregister_device:
 	rc_unregister_device(rc_dev);
-	rc_dev = NULL;
  exit_kill_urbs:
 	usb_kill_urb(ati_remote->irq_urb);
 	usb_kill_urb(ati_remote->out_urb);
@@ -941,6 +940,7 @@ static void ati_remote_disconnect(struct usb_interface *interface)
 	struct ati_remote *ati_remote;
 
 	ati_remote = usb_get_intfdata(interface);
+	rc_unregister_device(ati_remote->rdev);
 	usb_set_intfdata(interface, NULL);
 	if (!ati_remote) {
 		dev_warn(&interface->dev, "%s - null device?\n", __func__);
@@ -951,8 +951,8 @@ static void ati_remote_disconnect(struct usb_interface *interface)
 	usb_kill_urb(ati_remote->out_urb);
 	if (ati_remote->idev)
 		input_unregister_device(ati_remote->idev);
-	rc_unregister_device(ati_remote->rdev);
 	ati_remote_free_buffers(ati_remote);
+	rc_free_device(ati_remote->rdev);
 	kfree(ati_remote);
 }
 
diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
index d6c54a3bccc26..136fc4192265d 100644
--- a/drivers/media/rc/ene_ir.c
+++ b/drivers/media/rc/ene_ir.c
@@ -1090,7 +1090,6 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
 	release_region(dev->hw_io, ENE_IO_SIZE);
 exit_unregister_device:
 	rc_unregister_device(rdev);
-	rdev = NULL;
 exit_free_dev_rdev:
 	rc_free_device(rdev);
 	kfree(dev);
@@ -1110,6 +1109,7 @@ static void ene_remove(struct pnp_dev *pnp_dev)
 	ene_rx_restore_hw_buffer(dev);
 	spin_unlock_irqrestore(&dev->hw_lock, flags);
 
+	rc_free_device(dev->rdev);
 	free_irq(dev->irq, dev);
 	release_region(dev->hw_io, ENE_IO_SIZE);
 	kfree(dev);
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
index 3fb0968efd57d..9b789097cdd4c 100644
--- a/drivers/media/rc/fintek-cir.c
+++ b/drivers/media/rc/fintek-cir.c
@@ -568,6 +568,7 @@ static void fintek_remove(struct pnp_dev *pdev)
 	struct fintek_dev *fintek = pnp_get_drvdata(pdev);
 	unsigned long flags;
 
+	rc_unregister_device(fintek->rdev);
 	spin_lock_irqsave(&fintek->fintek_lock, flags);
 	/* disable CIR */
 	fintek_disable_cir(fintek);
@@ -580,7 +581,7 @@ static void fintek_remove(struct pnp_dev *pdev)
 	free_irq(fintek->cir_irq, fintek);
 	release_region(fintek->cir_addr, fintek->cir_port_len);
 
-	rc_unregister_device(fintek->rdev);
+	rc_free_device(fintek->rdev);
 
 	kfree(fintek);
 }
diff --git a/drivers/media/rc/igorplugusb.c b/drivers/media/rc/igorplugusb.c
index e034c93d57cf0..5ceb5ca44e235 100644
--- a/drivers/media/rc/igorplugusb.c
+++ b/drivers/media/rc/igorplugusb.c
@@ -242,6 +242,7 @@ static void igorplugusb_disconnect(struct usb_interface *intf)
 	usb_set_intfdata(intf, NULL);
 	usb_unpoison_urb(ir->urb);
 	usb_free_urb(ir->urb);
+	rc_free_device(ir->rc);
 	kfree(ir->buf_in);
 }
 
diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
index 8af94246e5916..7bd6dd7254157 100644
--- a/drivers/media/rc/iguanair.c
+++ b/drivers/media/rc/iguanair.c
@@ -500,6 +500,7 @@ static void iguanair_disconnect(struct usb_interface *intf)
 	usb_set_intfdata(intf, NULL);
 	usb_kill_urb(ir->urb_in);
 	usb_kill_urb(ir->urb_out);
+	rc_free_device(ir->rc);
 	usb_free_urb(ir->urb_in);
 	usb_free_urb(ir->urb_out);
 	usb_free_coherent(ir->udev, MAX_IN_PACKET, ir->buf_in, ir->dma_in);
diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c
index 63f6f5b36838d..f30adf4d8444d 100644
--- a/drivers/media/rc/img-ir/img-ir-hw.c
+++ b/drivers/media/rc/img-ir/img-ir-hw.c
@@ -1118,9 +1118,10 @@ void img_ir_remove_hw(struct img_ir_priv *priv)
 	struct rc_dev *rdev = hw->rdev;
 	if (!rdev)
 		return;
+	rc_unregister_device(rdev);
 	img_ir_set_decoder(priv, NULL, 0);
 	hw->rdev = NULL;
-	rc_unregister_device(rdev);
+	rc_free_device(rdev);
 #ifdef CONFIG_COMMON_CLK
 	if (!IS_ERR(priv->clk))
 		clk_notifier_unregister(priv->clk, &hw->clk_nb);
diff --git a/drivers/media/rc/img-ir/img-ir-raw.c b/drivers/media/rc/img-ir/img-ir-raw.c
index 92fb7b555a0f6..f1460d4acf3e8 100644
--- a/drivers/media/rc/img-ir/img-ir-raw.c
+++ b/drivers/media/rc/img-ir/img-ir-raw.c
@@ -136,6 +136,7 @@ void img_ir_remove_raw(struct img_ir_priv *priv)
 	if (!rdev)
 		return;
 
+	rc_unregister_device(rdev);
 	/* switch off and disable raw (edge) interrupts */
 	spin_lock_irq(&priv->lock);
 	raw->rdev = NULL;
@@ -145,7 +146,7 @@ void img_ir_remove_raw(struct img_ir_priv *priv)
 	img_ir_write(priv, IMG_IR_IRQ_CLEAR, IMG_IR_IRQ_EDGE);
 	spin_unlock_irq(&priv->lock);
 
-	rc_unregister_device(rdev);
+	rc_free_device(rdev);
 
 	timer_delete_sync(&raw->timer);
 }
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index 35b9e07003d88..48534bb52e4d0 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -2541,9 +2541,10 @@ static void imon_disconnect(struct usb_interface *interface)
 
 	if (ifnum == 0) {
 		ictx->dev_present_intf0 = false;
+		rc_unregister_device(ictx->rdev);
 		usb_kill_urb(ictx->rx_urb_intf0);
 		input_unregister_device(ictx->idev);
-		rc_unregister_device(ictx->rdev);
+		rc_free_device(ictx->rdev);
 		if (ictx->display_supported) {
 			if (ictx->display_type == IMON_DISPLAY_TYPE_LCD)
 				usb_deregister_dev(interface, &imon_lcd_class);
diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c
index edc46828509c8..1b061e4a3dcfa 100644
--- a/drivers/media/rc/ir-hix5hd2.c
+++ b/drivers/media/rc/ir-hix5hd2.c
@@ -331,7 +331,6 @@ static int hix5hd2_ir_probe(struct platform_device *pdev)
 
 regerr:
 	rc_unregister_device(rdev);
-	rdev = NULL;
 clkerr:
 	clk_disable_unprepare(priv->clock);
 err:
@@ -346,6 +345,7 @@ static void hix5hd2_ir_remove(struct platform_device *pdev)
 
 	clk_disable_unprepare(priv->clock);
 	rc_unregister_device(priv->rdev);
+	rc_free_device(priv->rdev);
 }
 
 #ifdef CONFIG_PM_SLEEP
diff --git a/drivers/media/rc/ir_toy.c b/drivers/media/rc/ir_toy.c
index 533faa1175174..e79de56997a42 100644
--- a/drivers/media/rc/ir_toy.c
+++ b/drivers/media/rc/ir_toy.c
@@ -536,6 +536,7 @@ static void irtoy_disconnect(struct usb_interface *intf)
 	usb_free_urb(ir->urb_out);
 	usb_kill_urb(ir->urb_in);
 	usb_free_urb(ir->urb_in);
+	rc_free_device(ir->rc);
 	kfree(ir->in);
 	kfree(ir->out);
 	kfree(ir);
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
index 2bacecb022623..23afbafb55748 100644
--- a/drivers/media/rc/ite-cir.c
+++ b/drivers/media/rc/ite-cir.c
@@ -1414,7 +1414,6 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
 	release_region(itdev->cir_addr, itdev->params->io_region_size);
 exit_unregister_device:
 	rc_unregister_device(rdev);
-	rdev = NULL;
 exit_free_dev_rdev:
 	rc_free_device(rdev);
 	kfree(itdev);
@@ -1439,6 +1438,7 @@ static void ite_remove(struct pnp_dev *pdev)
 	release_region(dev->cir_addr, dev->params->io_region_size);
 
 	rc_unregister_device(dev->rdev);
+	rc_free_device(dev->rdev);
 
 	kfree(dev);
 }
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 044767eb3a38c..a4c94fdf767ca 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -1850,6 +1850,7 @@ static void mceusb_dev_disconnect(struct usb_interface *intf)
 	usb_free_urb(ir->urb_in);
 	usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in);
 	usb_put_dev(dev);
+	rc_free_device(ir->rc);
 
 	kfree(ir);
 }
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index 5dafe11f61c6b..76c3d1307f9f1 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -648,9 +648,6 @@ int ir_raw_event_register(struct rc_dev *dev)
 
 void ir_raw_event_free(struct rc_dev *dev)
 {
-	if (!dev)
-		return;
-
 	kfree(dev->raw);
 	dev->raw = NULL;
 }
@@ -674,8 +671,6 @@ void ir_raw_event_unregister(struct rc_dev *dev)
 
 	lirc_bpf_free(dev);
 
-	ir_raw_event_free(dev);
-
 	/*
 	 * A user can be calling bpf(BPF_PROG_{QUERY|ATTACH|DETACH}), so
 	 * ensure that the raw member is null on unlock; this is how
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index 8288366f891fc..a108b057b5fd5 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -263,6 +263,7 @@ static int __init loop_init(void)
 static void __exit loop_exit(void)
 {
 	rc_unregister_device(loopdev.dev);
+	rc_free_device(loopdev.dev);
 }
 
 module_init(loop_init);
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index b9bf5cdcde4ae..6bdf32cb4a17d 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1611,6 +1611,7 @@ static void rc_dev_release(struct device *device)
 {
 	struct rc_dev *dev = to_rc_dev(device);
 
+	ir_raw_event_free(dev);
 	kfree(dev);
 }
 
@@ -1773,7 +1774,6 @@ struct rc_dev *devm_rc_allocate_device(struct device *dev,
 	}
 
 	rc->dev.parent = dev;
-	rc->managed_alloc = true;
 	*dr = rc;
 	devres_add(dev, dr);
 
@@ -2042,11 +2042,7 @@ void rc_unregister_device(struct rc_dev *dev)
 	device_del(&dev->dev);
 
 	ida_free(&rc_ida, dev->minor);
-
-	if (!dev->managed_alloc)
-		rc_free_device(dev);
 }
-
 EXPORT_SYMBOL_GPL(rc_unregister_device);
 
 /*
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index a49173f54a4d0..b8289327f6a20 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -1133,11 +1133,13 @@ static void redrat3_dev_disconnect(struct usb_interface *intf)
 {
 	struct usb_device *udev = interface_to_usbdev(intf);
 	struct redrat3_dev *rr3 = usb_get_intfdata(intf);
+	struct rc_dev *rc = rr3->rc;
 
 	usb_set_intfdata(intf, NULL);
-	rc_unregister_device(rr3->rc);
+	rc_unregister_device(rc);
 	led_classdev_unregister(&rr3->led);
 	redrat3_delete(rr3, udev);
+	rc_free_device(rc);
 }
 
 static int redrat3_dev_suspend(struct usb_interface *intf, pm_message_t message)
diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c
index 6b70bac5f45d6..0ba06bfc9e14b 100644
--- a/drivers/media/rc/st_rc.c
+++ b/drivers/media/rc/st_rc.c
@@ -203,6 +203,7 @@ static void st_rc_remove(struct platform_device *pdev)
 	device_init_wakeup(&pdev->dev, false);
 	clk_disable_unprepare(rc_dev->sys_clock);
 	rc_unregister_device(rc_dev->rdev);
+	rc_free_device(rc_dev->rdev);
 }
 
 static int st_rc_open(struct rc_dev *rdev)
@@ -334,7 +335,6 @@ static int st_rc_probe(struct platform_device *pdev)
 	return ret;
 rcerr:
 	rc_unregister_device(rdev);
-	rdev = NULL;
 clkerr:
 	clk_disable_unprepare(rc_dev->sys_clock);
 err:
diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
index d3b48a0dd1f47..b9b241fe46ea1 100644
--- a/drivers/media/rc/streamzap.c
+++ b/drivers/media/rc/streamzap.c
@@ -388,15 +388,16 @@ static void streamzap_disconnect(struct usb_interface *interface)
 	struct streamzap_ir *sz = usb_get_intfdata(interface);
 	struct usb_device *usbdev = interface_to_usbdev(interface);
 
+	rc_unregister_device(sz->rdev);
 	usb_set_intfdata(interface, NULL);
 
 	if (!sz)
 		return;
 
 	usb_kill_urb(sz->urb_in);
-	rc_unregister_device(sz->rdev);
 	usb_free_urb(sz->urb_in);
 	usb_free_coherent(usbdev, sz->buf_in_len, sz->buf_in, sz->dma_in);
+	rc_free_device(sz->rdev);
 
 	kfree(sz);
 }
diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c
index 92ef4e7c6f69f..cb4c56bf0752a 100644
--- a/drivers/media/rc/sunxi-cir.c
+++ b/drivers/media/rc/sunxi-cir.c
@@ -371,6 +371,7 @@ static void sunxi_ir_remove(struct platform_device *pdev)
 	struct sunxi_ir *ir = platform_get_drvdata(pdev);
 
 	rc_unregister_device(ir->rc);
+	rc_free_device(ir->rc);
 	sunxi_ir_hw_exit(&pdev->dev);
 }
 
diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c
index 560a26f3965cf..5234c1e9a58ea 100644
--- a/drivers/media/rc/ttusbir.c
+++ b/drivers/media/rc/ttusbir.c
@@ -333,7 +333,6 @@ static int ttusbir_probe(struct usb_interface *intf,
 	return 0;
 out3:
 	rc_unregister_device(rc);
-	rc = NULL;
 out2:
 	led_classdev_unregister(&tt->led);
 out:
@@ -373,6 +372,7 @@ static void ttusbir_disconnect(struct usb_interface *intf)
 	}
 	usb_kill_urb(tt->bulk_urb);
 	usb_free_urb(tt->bulk_urb);
+	rc_free_device(tt->rc);
 	usb_set_intfdata(intf, NULL);
 	kfree(tt);
 }
diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
index 25884a79985c8..14d8b58e28398 100644
--- a/drivers/media/rc/winbond-cir.c
+++ b/drivers/media/rc/winbond-cir.c
@@ -1132,7 +1132,6 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
 	release_region(data->wbase, WAKEUP_IOMEM_LEN);
 exit_unregister_device:
 	rc_unregister_device(data->dev);
-	data->dev = NULL;
 exit_free_rc:
 	rc_free_device(data->dev);
 exit_unregister_led:
@@ -1163,6 +1162,7 @@ wbcir_remove(struct pnp_dev *device)
 	wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07);
 
 	rc_unregister_device(data->dev);
+	rc_free_device(data->dev);
 
 	led_classdev_unregister(&data->led);
 
diff --git a/drivers/media/rc/xbox_remote.c b/drivers/media/rc/xbox_remote.c
index a1572381d0971..027e75e170a1f 100644
--- a/drivers/media/rc/xbox_remote.c
+++ b/drivers/media/rc/xbox_remote.c
@@ -277,6 +277,7 @@ static void xbox_remote_disconnect(struct usb_interface *interface)
 	struct xbox_remote *xbox_remote;
 
 	xbox_remote = usb_get_intfdata(interface);
+	rc_unregister_device(xbox_remote->rdev);
 	usb_set_intfdata(interface, NULL);
 	if (!xbox_remote) {
 		dev_warn(&interface->dev, "%s - null device?\n", __func__);
@@ -284,7 +285,7 @@ static void xbox_remote_disconnect(struct usb_interface *interface)
 	}
 
 	usb_kill_urb(xbox_remote->irq_urb);
-	rc_unregister_device(xbox_remote->rdev);
+	rc_free_device(xbox_remote->rdev);
 	usb_free_urb(xbox_remote->irq_urb);
 	kfree(xbox_remote);
 }
diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c
index 3d3368202cd01..283ad2c6288cd 100644
--- a/drivers/media/usb/au0828/au0828-input.c
+++ b/drivers/media/usb/au0828/au0828-input.c
@@ -357,6 +357,7 @@ void au0828_rc_unregister(struct au0828_dev *dev)
 		return;
 
 	rc_unregister_device(ir->rc);
+	rc_free_device(ir->rc);
 
 	/* done */
 	kfree(ir);
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
index f1c79f351ec8d..17e8961179d14 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
@@ -187,6 +187,7 @@ static int dvb_usbv2_remote_exit(struct dvb_usb_device *d)
 	if (d->rc_dev) {
 		cancel_delayed_work_sync(&d->rc_query_work);
 		rc_unregister_device(d->rc_dev);
+		rc_free_device(d->rc_dev);
 		d->rc_dev = NULL;
 	}
 
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-remote.c b/drivers/media/usb/dvb-usb/dvb-usb-remote.c
index 65e2c9e2cdc99..6dc11718dfb98 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-remote.c
@@ -347,10 +347,12 @@ int dvb_usb_remote_exit(struct dvb_usb_device *d)
 {
 	if (d->state & DVB_USB_STATE_REMOTE) {
 		cancel_delayed_work_sync(&d->rc_query_work);
-		if (d->props.rc.mode == DVB_RC_LEGACY)
+		if (d->props.rc.mode == DVB_RC_LEGACY) {
 			input_unregister_device(d->input_dev);
-		else
+		} else {
 			rc_unregister_device(d->rc_dev);
+			rc_free_device(d->rc_dev);
+		}
 	}
 	d->state &= ~DVB_USB_STATE_REMOTE;
 	return 0;
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index 5f3b00869bdbc..26f333b5be732 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -853,6 +853,7 @@ static int em28xx_ir_fini(struct em28xx *dev)
 		goto ref_put;
 
 	rc_unregister_device(ir->rc);
+	rc_free_device(ir->rc);
 
 	kfree(ir->i2c_client);
 
diff --git a/drivers/staging/media/av7110/av7110_ir.c b/drivers/staging/media/av7110/av7110_ir.c
index 68b3979ba5f20..fdae467fd7ab8 100644
--- a/drivers/staging/media/av7110/av7110_ir.c
+++ b/drivers/staging/media/av7110/av7110_ir.c
@@ -151,6 +151,7 @@ int av7110_ir_init(struct av7110 *av7110)
 void av7110_ir_exit(struct av7110 *av7110)
 {
 	rc_unregister_device(av7110->ir.rcdev);
+	rc_free_device(av7110->ir.rcdev);
 }
 
 //MODULE_AUTHOR("Holger Waechtler <holger at convergence.de>, Oliver Endriss <o.endriss at gmx.de>");
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 35c7a0546f02e..7c964b5ad7926 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -81,7 +81,6 @@ struct lirc_fh {
 /**
  * struct rc_dev - represents a remote control device
  * @dev: driver model's view of this device
- * @managed_alloc: devm_rc_allocate_device was used to create rc_dev
  * @registered: set to true by rc_register_device(), false by
  *	rc_unregister_device
  * @idle: used to keep track of RX state
@@ -156,7 +155,6 @@ struct lirc_fh {
  */
 struct rc_dev {
 	struct device			dev;
-	bool				managed_alloc;
 	bool				registered;
 	bool				idle;
 	bool				encode_wakeup;
-- 
2.52.0



From olvaffe at gmail.com  Sat Dec 20 16:33:26 2025
From: olvaffe at gmail.com (Chia-I Wu)
Date: Sat, 20 Dec 2025 16:33:26 -0800
Subject: [PATCH v2 0/4] Make MT8196 get its Mali GPU shader_present from nvmem
In-Reply-To: <20251220-mt8196-shader-present-v2-0-45b1ff1dfab0@collabora.com>
References: <20251220-mt8196-shader-present-v2-0-45b1ff1dfab0@collabora.com>
Message-ID: <CAPaKu7QST65NPQ7rZAGhqLsb4FN21D-rOvUf-UzgsBCrOv1skA@mail.gmail.com>

On Sat, Dec 20, 2025 at 10:50?AM Nicolas Frattaroli
<nicolas.frattaroli at collabora.com> wrote:
>
> The MediaTek MT8196 SoC's Mali SHADER_PRESENT register does not list
> only functional shader cores, but also those that are fused off to
> improve yield.
>
> The SHADER_PRESENT bitmask with the one fused off core omitted is to be
> found in an efuse. However, the efuse address is considered
> confidential, and is not public knowledge.
>
> The MT8196 GPUEB MCU, which does the power management for the Mali GPU
> on this SoC, knows and reads the efuse however, and exposes it in the
> shared memory intended to communicate state to the application
> processor. Reading the bitmask from this shared memory area is the
> vendor's intended solution.
>
> This series models this in the binding and implements it in the
> corresponding Linux drivers:
> - the mali-valhall-csf binding gets an nvmem-cells/nvmem-cell-names
>   property to declare that shader-present is in a different castle
> - the mt8196-gpufreq binding requires nodes to expose the shader-present
>   cell
> - panthor checks for the presence of the shader-present cell and uses it
>   as the shader-present value if it's found, instead of the Mali GPU
>   register contents
> - mtk-mfg-pmdomain becomes an nvmem provider and will happily serve
>   queries for the shader-present cell
>
> While it would be preferable if we could read the efuse directly, it's
> not possible as things stand, and insisting on it will just keep this
> hardware from working in mainline. Running a GPU workload with a
> SHADER_PRESENT bitmask that includes a faulty core results in corrupt
> GPU rendering output.
>
> Modelling the mt8196-gpufreq device as a nvmem-cell provider however is
> not lying about the hardware's capabilities, as it truly does provide
> access to the nvmem-cell, even if it acts as a proxy.
>
> From a bindings and panthor perspective, this is also generic enough to
> where hypothetical other vendors doing the same thing (even with direct
> efuse access) can rely on the same cell name and implementation.
>
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
Series is Reviewed-by: Chia-I Wu <olvaffe at gmail.com>
> ---
> Changes in v2:
> - panthor: move to nvmem_cell_read_variable_le_u64
> - mtk-mfg-pmdomain: put of_node in error path
> - mtk-mfg-pmdomain: remove leftover stray of_node_put on NULL
> - Link to v1: https://lore.kernel.org/r/20251217-mt8196-shader-present-v1-0-f6f8f3aa1e93 at collabora.com
>
> ---
> Nicolas Frattaroli (4):
>       dt-bindings: gpu: mali-valhall-csf: Add shader-present nvmem cell
>       dt-bindings: power: mt8196-gpufreq: Describe nvmem provider ability
>       drm/panthor: Implement reading shader_present from nvmem
>       pmdomain: mediatek: mtk-mfg: Expose shader_present as nvmem cell
>
>  .../bindings/gpu/arm,mali-valhall-csf.yaml         | 14 +++++
>  .../bindings/power/mediatek,mt8196-gpufreq.yaml    | 13 +++++
>  drivers/gpu/drm/panthor/panthor_hw.c               | 36 ++++++++++---
>  drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c       | 59 ++++++++++++++++++++++
>  4 files changed, 116 insertions(+), 6 deletions(-)
> ---
> base-commit: 638148c6ffa31d2e4958d51708ff3675221e2da7
> change-id: 20251217-mt8196-shader-present-e2dc3f97fc74
>
> Best regards,
> --
> Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
>


From bp at alien8.de  Sat Dec 20 17:35:34 2025
From: bp at alien8.de (Borislav Petkov)
Date: Sun, 21 Dec 2025 02:35:34 +0100
Subject: [PATCH 00/12] ras: share firmware-first estatus handling
In-Reply-To: <20251217112845.1814119-1-ahmed.tiba@arm.com>
References: <20251217112845.1814119-1-ahmed.tiba@arm.com>
Message-ID: <20251221013534.GAaUdO5vWqMWAdbWbd@renoirsky.local>

On Wed, Dec 17, 2025 at 11:28:33AM +0000, Ahmed Tiba wrote:
> Platforms that rely on firmware-first RAS today only get the full Linux
> handling pipeline when the records arrive through ACPI/APEI GHES. This
> series lifts the generic parts of GHES into a reusable estatus core, wires

Why is this thing called "error status"?

Why is error status so significant so that you need to call it a thing,
much less a "core"?

It looks like you basically want to dump error records from a system
which doesn't support GHES into the common path so they get decoded?

I mean, I'm only guessing because I don't get any wiser from this text.

So how about you give the high-level, practical use spiel first? What's
the use case?

Then we can talk implementation details.

Thx.

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette


From 21cnbao at gmail.com  Sat Dec 20 21:15:23 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Sun, 21 Dec 2025 13:15:23 +0800
Subject: [PATCH 5/6] dma-mapping: Allow batched DMA sync operations if supported by the arch
In-Reply-To: <202512201836.f6KX6WMH-lkp@intel.com>
References: <202512201836.f6KX6WMH-lkp@intel.com>
Message-ID: <20251221051523.18557-1-21cnbao@gmail.com>

>
> All errors (new ones prefixed by >>):
>
> >> kernel/dma/direct.c:456:4: error: call to undeclared function 'dma_direct_unmap_phys_batch_add'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
> ? ? ?456 | ? ? ? ? ? ? ? ? ? ? ? ? dma_direct_unmap_phys_batch_add(dev, sg->dma_address,
> ? ? ? ? ?| ? ? ? ? ? ? ? ? ? ? ? ? ^
> ? ?kernel/dma/direct.c:456:4: note: did you mean 'dma_direct_unmap_phys'?
> ? ?kernel/dma/direct.h:188:20: note: 'dma_direct_unmap_phys' declared here
> ? ? ?188 | static inline void dma_direct_unmap_phys(struct device *dev, dma_addr_t addr,
> ? ? ? ? ?| ? ? ? ? ? ? ? ? ? ?^
> >> kernel/dma/direct.c:484:22: error: call to undeclared function 'dma_direct_map_phys_batch_add'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
> ? ? ?484 | ? ? ? ? ? ? ? ? ? ? ? ? sg->dma_address = dma_direct_map_phys_batch_add(dev, sg_phys(sg),
> ? ? ? ? ?| ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ^
> ? ?2 errors generated.
>
>

Thanks very much for the report.
Can you please check if the below diff fix the build issue?

>From 5541aa1efa19777e435c9f3cca7cd2c6a490d9f1 Mon Sep 17 00:00:00 2001
From: Barry Song <v-songbaohua at oppo.com>
Date: Sun, 21 Dec 2025 13:09:36 +0800
Subject: [PATCH] kernel/dma: Fix build errors for dma_direct_map_phys

Reported-by: kernel test robot <lkp at intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202512201836.f6KX6WMH-lkp at intel.com/
Signed-off-by: Barry Song <v-songbaohua at oppo.com>
---
 kernel/dma/direct.h | 38 ++++++++++++++++++++++++++------------
 1 file changed, 26 insertions(+), 12 deletions(-)

diff --git a/kernel/dma/direct.h b/kernel/dma/direct.h
index a211bab26478..bcc398b5aa6b 100644
--- a/kernel/dma/direct.h
+++ b/kernel/dma/direct.h
@@ -138,8 +138,7 @@ static inline dma_addr_t __dma_direct_map_phys(struct device *dev,
 	return DMA_MAPPING_ERROR;
 }
 
-#ifdef CONFIG_ARCH_WANT_BATCHED_DMA_SYNC
-static inline dma_addr_t dma_direct_map_phys_batch_add(struct device *dev,
+static inline dma_addr_t dma_direct_map_phys(struct device *dev,
 		phys_addr_t phys, size_t size, enum dma_data_direction dir,
 		unsigned long attrs)
 {
@@ -147,13 +146,13 @@ static inline dma_addr_t dma_direct_map_phys_batch_add(struct device *dev,
 
 	if (dma_addr != DMA_MAPPING_ERROR && !dev_is_dma_coherent(dev) &&
 	    !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO)))
-		arch_sync_dma_for_device_batch_add(phys, size, dir);
+		arch_sync_dma_for_device(phys, size, dir);
 
 	return dma_addr;
 }
-#endif
 
-static inline dma_addr_t dma_direct_map_phys(struct device *dev,
+#ifdef CONFIG_ARCH_WANT_BATCHED_DMA_SYNC
+static inline dma_addr_t dma_direct_map_phys_batch_add(struct device *dev,
 		phys_addr_t phys, size_t size, enum dma_data_direction dir,
 		unsigned long attrs)
 {
@@ -161,13 +160,20 @@ static inline dma_addr_t dma_direct_map_phys(struct device *dev,
 
 	if (dma_addr != DMA_MAPPING_ERROR && !dev_is_dma_coherent(dev) &&
 	    !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO)))
-		arch_sync_dma_for_device(phys, size, dir);
+		arch_sync_dma_for_device_batch_add(phys, size, dir);
 
 	return dma_addr;
 }
+#else
+static inline dma_addr_t dma_direct_map_phys_batch_add(struct device *dev,
+		phys_addr_t phys, size_t size, enum dma_data_direction dir,
+		unsigned long attrs)
+{
+	return dma_direct_map_phys(dev, phys, size, dir, attrs);
+}
+#endif
 
-#ifdef CONFIG_ARCH_WANT_BATCHED_DMA_SYNC
-static inline void dma_direct_unmap_phys_batch_add(struct device *dev, dma_addr_t addr,
+static inline void dma_direct_unmap_phys(struct device *dev, dma_addr_t addr,
 		size_t size, enum dma_data_direction dir, unsigned long attrs)
 {
 	phys_addr_t phys;
@@ -178,14 +184,14 @@ static inline void dma_direct_unmap_phys_batch_add(struct device *dev, dma_addr_
 
 	phys = dma_to_phys(dev, addr);
 	if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
-		dma_direct_sync_single_for_cpu_batch_add(dev, addr, size, dir);
+		dma_direct_sync_single_for_cpu(dev, addr, size, dir);
 
 	swiotlb_tbl_unmap_single(dev, phys, size, dir,
 					 attrs | DMA_ATTR_SKIP_CPU_SYNC);
 }
-#endif
 
-static inline void dma_direct_unmap_phys(struct device *dev, dma_addr_t addr,
+#ifdef CONFIG_ARCH_WANT_BATCHED_DMA_SYNC
+static inline void dma_direct_unmap_phys_batch_add(struct device *dev, dma_addr_t addr,
 		size_t size, enum dma_data_direction dir, unsigned long attrs)
 {
 	phys_addr_t phys;
@@ -196,9 +202,17 @@ static inline void dma_direct_unmap_phys(struct device *dev, dma_addr_t addr,
 
 	phys = dma_to_phys(dev, addr);
 	if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
-		dma_direct_sync_single_for_cpu(dev, addr, size, dir);
+		dma_direct_sync_single_for_cpu_batch_add(dev, addr, size, dir);
 
 	swiotlb_tbl_unmap_single(dev, phys, size, dir,
 					 attrs | DMA_ATTR_SKIP_CPU_SYNC);
 }
+#else
+static inline void dma_direct_unmap_phys_batch_add(struct device *dev, dma_addr_t addr,
+		size_t size, enum dma_data_direction dir, unsigned long attrs)
+{
+	dma_direct_unmap_phys(dev, addr, size, dir, attrs);
+}
+#endif
+
 #endif /* _KERNEL_DMA_DIRECT_H */
-- 
2.39.3 (Apple Git-146)

Thanks
Barry



From wens at kernel.org  Sat Dec 20 22:47:52 2025
From: wens at kernel.org (Chen-Yu Tsai)
Date: Sun, 21 Dec 2025 14:47:52 +0800
Subject: [PATCH RESEND] dmaengine: sun6i: Add debug messages for cyclic DMA prepare
Message-ID: <20251221064754.1783369-1-wens@kernel.org>

The driver already has debug messages for memcpy and linear transfers,
but is missing them for cyclic transfers.

Cyclic transfers are one of the main uses of the DMA controller, used
for audio data transfers. And since these are likely the first DMA
peripherals to be enabled, it helps to have these debug messages.

Acked-by: Jernej Skrabec <jernej.skrabec at gmail.com>
Signed-off-by: Chen-Yu Tsai <wens at kernel.org>
---
Hi Vinod,

This patch seems to have fallen through the cracks.


 drivers/dma/sun6i-dma.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
index 2215ff877bf7..2e03c587bd2e 100644
--- a/drivers/dma/sun6i-dma.c
+++ b/drivers/dma/sun6i-dma.c
@@ -826,6 +826,11 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_cyclic(
 			v_lli->cfg = lli_cfg;
 			sdev->cfg->set_drq(&v_lli->cfg, DRQ_SDRAM, vchan->port);
 			sdev->cfg->set_mode(&v_lli->cfg, LINEAR_MODE, IO_MODE);
+			dev_dbg(chan2dev(chan),
+				"%s; chan: %d, dest: %pad, src: %pad, len: %zu. flags: 0x%08lx\n",
+				__func__, vchan->vc.chan.chan_id,
+				&sconfig->dst_addr, &buf_addr,
+				buf_len, flags);
 		} else {
 			sun6i_dma_set_addr(sdev, v_lli,
 					   sconfig->src_addr,
@@ -833,6 +838,11 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_cyclic(
 			v_lli->cfg = lli_cfg;
 			sdev->cfg->set_drq(&v_lli->cfg, vchan->port, DRQ_SDRAM);
 			sdev->cfg->set_mode(&v_lli->cfg, IO_MODE, LINEAR_MODE);
+			dev_dbg(chan2dev(chan),
+				"%s; chan: %d, dest: %pad, src: %pad, len: %zu. flags: 0x%08lx\n",
+				__func__, vchan->vc.chan.chan_id,
+				&buf_addr, &sconfig->src_addr,
+				buf_len, flags);
 		}
 
 		prev = sun6i_dma_lli_add(prev, v_lli, p_lli, txd);
-- 
2.47.3



From 21cnbao at gmail.com  Sat Dec 20 23:22:03 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Sun, 21 Dec 2025 15:22:03 +0800
Subject: [PATCH 1/6] arm64: Provide dcache_by_myline_op_nosync helper
In-Reply-To: <f43286ef-3dea-4637-a34e-b9b70d2741bf@arm.com>
References: <20251219053658.84978-1-21cnbao@gmail.com> <20251219053658.84978-2-21cnbao@gmail.com>
 <f43286ef-3dea-4637-a34e-b9b70d2741bf@arm.com>
Message-ID: <CAGsJ_4wRcz7NFw2PiBCb54gmJwTt7=UG1fn2UEJ9_gR687Y4Uw@mail.gmail.com>

On Fri, Dec 19, 2025 at 8:20?PM Robin Murphy <robin.murphy at arm.com> wrote:
>
> On 2025-12-19 5:36 am, Barry Song wrote:
> > From: Barry Song <v-songbaohua at oppo.com>
> >
> > dcache_by_myline_op ensures completion of the data cache operations for a
> > region, while dcache_by_myline_op_nosync only issues them without waiting.
> > This enables deferred synchronization so completion for multiple regions
> > can be handled together later.
>
> This is a super-low-level internal macro with only two users... Frankly I'd
> just do as below.
>
> Thanks,
> Robin.
>
> ----->8-----
>
> diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
> index f0ca7196f6fa..26e983c331c5 100644
> --- a/arch/arm64/include/asm/assembler.h
> +++ b/arch/arm64/include/asm/assembler.h
> @@ -367,18 +367,17 @@ alternative_endif
>         .endm
>
>   /*
> - * Macro to perform a data cache maintenance for the interval
> - * [start, end) with dcache line size explicitly provided.
> + * Main loop for a data cache maintenance operation. Caller to provide the
> + * dcache line size and take care of relevant synchronisation afterwards.
>    *
>    *    op:             operation passed to dc instruction
> - *     domain:         domain used in dsb instruction
>    *    start:          starting virtual address of the region
>    *    end:            end virtual address of the region
>    *    linesz:         dcache line size
>    *    fixup:          optional label to branch to on user fault
>    *    Corrupts:       start, end, tmp
>    */
> -       .macro dcache_by_myline_op op, domain, start, end, linesz, tmp, fixup
> +       .macro raw_dcache_by_line_op op, start, end, linesz, tmp, fixup
>         sub     \tmp, \linesz, #1
>         bic     \start, \start, \tmp
>   .Ldcache_op\@:
> @@ -402,7 +401,6 @@ alternative_endif
>         add     \start, \start, \linesz
>         cmp     \start, \end
>         b.lo    .Ldcache_op\@
> -       dsb     \domain
>
>         _cond_uaccess_extable .Ldcache_op\@, \fixup
>         .endm
> @@ -420,7 +418,8 @@ alternative_endif
>    */
>         .macro dcache_by_line_op op, domain, start, end, tmp1, tmp2, fixup
>         dcache_line_size \tmp1, \tmp2
> -       dcache_by_myline_op \op, \domain, \start, \end, \tmp1, \tmp2, \fixup
> +       raw_dcache_by_line_op \op, \start, \end, \tmp1, \tmp2, \fixup
> +       dsb \domain
>         .endm
>
>   /*
> diff --git a/arch/arm64/kernel/relocate_kernel.S b/arch/arm64/kernel/relocate_kernel.S
> index 413f899e4ac6..efdb6884058e 100644
> --- a/arch/arm64/kernel/relocate_kernel.S
> +++ b/arch/arm64/kernel/relocate_kernel.S
> @@ -64,7 +64,8 @@ SYM_CODE_START(arm64_relocate_new_kernel)
>         mov     x19, x13
>         copy_page x13, x12, x1, x2, x3, x4, x5, x6, x7, x8
>         add     x1, x19, #PAGE_SIZE
> -       dcache_by_myline_op civac, sy, x19, x1, x15, x20
> +       raw_dcache_by_line_op civac, x19, x1, x15, x20
> +       dsb     sy
>         b       .Lnext
>   .Ltest_indirection:
>         tbz     x16, IND_INDIRECTION_BIT, .Ltest_destination
>

Thanks, Robin.  Really much better!
dcache_by_line_op_nosync could be:

/*
 * Macro to perform a data cache maintenance for the interval
 * [start, end) without waiting for completion
 *
 *      op:             operation passed to dc instruction
 *      start:          starting virtual address of the region
 *      end:            end virtual address of the region
 *      fixup:          optional label to branch to on user fault
 *      Corrupts:       start, end, tmp1, tmp2
 */
        .macro dcache_by_line_op_nosync op, start, end, tmp1, tmp2, fixup
        dcache_line_size \tmp1, \tmp2
        raw_dcache_by_myline_op \op, \start, \end, \tmp1, \tmp2, \fixup
        .endm

Thanks
Barry


From lkp at intel.com  Sat Dec 20 23:31:59 2025
From: lkp at intel.com (kernel test robot)
Date: Sun, 21 Dec 2025 08:31:59 +0100
Subject: [PATCH v2 4/5] power: supply: max77759: add charger driver
In-Reply-To: <20251218-max77759-charger-v2-4-2b259980a686@google.com>
References: <20251218-max77759-charger-v2-4-2b259980a686@google.com>
Message-ID: <202512210844.O8gAG2p9-lkp@intel.com>

Hi Amit,

kernel test robot noticed the following build warnings:

[auto build test WARNING on lee-mfd/for-mfd-fixes]
[also build test WARNING on sre-power-supply/for-next usb/usb-testing usb/usb-next usb/usb-linus v6.16-rc1 next-20251219]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Amit-Sunil-Dhamne-via-B4-Relay/dt-bindings-mfd-maxim-max77759-add-charger-child-node/20251219-065531
base:   https://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git for-mfd-fixes
patch link:    https://lore.kernel.org/r/20251218-max77759-charger-v2-4-2b259980a686%40google.com
patch subject: [PATCH v2 4/5] power: supply: max77759: add charger driver
reproduce: (https://download.01.org/0day-ci/archive/20251221/202512210844.O8gAG2p9-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512210844.O8gAG2p9-lkp at intel.com/

All warnings (new ones prefixed by >>):

   Warning: Documentation/translations/zh_CN/admin-guide/README.rst references a file that doesn't exist: Documentation/dev-tools/kgdb.rst
   Warning: Documentation/translations/zh_CN/dev-tools/gdb-kernel-debugging.rst references a file that doesn't exist: Documentation/dev-tools/gdb-kernel-debugging.rst
   Warning: Documentation/translations/zh_CN/how-to.rst references a file that doesn't exist: Documentation/xxx/xxx.rst
   Warning: Documentation/translations/zh_TW/admin-guide/README.rst references a file that doesn't exist: Documentation/dev-tools/kgdb.rst
   Warning: Documentation/translations/zh_TW/dev-tools/gdb-kernel-debugging.rst references a file that doesn't exist: Documentation/dev-tools/gdb-kernel-debugging.rst
>> Warning: MAINTAINERS references a file that doesn't exist: Documentation/devicetree/bindings/power/supply/maxim,max77759-charger.yaml
   Warning: arch/riscv/kernel/kexec_image.c references a file that doesn't exist: Documentation/riscv/boot-image-header.rst
   Warning: drivers/clocksource/timer-armada-370-xp.c references a file that doesn't exist: Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt
   Warning: include/rv/da_monitor.h references a file that doesn't exist: Documentation/trace/rv/da_monitor_synthesis.rst
   Using alabaster theme
   ERROR: Cannot find file ./include/linux/pci.h

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From 21cnbao at gmail.com  Sat Dec 20 23:59:25 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Sun, 21 Dec 2025 15:59:25 +0800
Subject: [PATCH 3/6] arm64: Provide dcache_inval_poc_nosync helper
In-Reply-To: <99bb1797-06ba-440d-b173-db62d5f54e08@arm.com>
References: <99bb1797-06ba-440d-b173-db62d5f54e08@arm.com>
Message-ID: <20251221075925.65445-1-21cnbao@gmail.com>

On Fri, Dec 19, 2025 at 8:50?PM Robin Murphy <robin.murphy at arm.com> wrote:
[...]
> > diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S
> > index 4a7c7e03785d..8c1043c9b9e5 100644
> > --- a/arch/arm64/mm/cache.S
> > +++ b/arch/arm64/mm/cache.S
> > @@ -132,17 +132,7 @@ alternative_else_nop_endif
> > ? ? ? ret
> > ? SYM_FUNC_END(dcache_clean_pou)
> > ?
> > -/*
> > - * ? dcache_inval_poc(start, end)
> > - *
> > - * ? Ensure that any D-cache lines for the interval [start, end)
> > - * ? are invalidated. Any partial lines at the ends of the interval are
> > - * ? also cleaned to PoC to prevent data loss.
> > - *
> > - * ? - start ? - kernel start address of region
> > - * ? - end ? ? - kernel end address of region
> > - */
> > -SYM_FUNC_START(__pi_dcache_inval_poc)
> > +.macro _dcache_inval_poc_impl, do_sync
> > ? ? ? dcache_line_size x2, x3
> > ? ? ? sub ? ? x3, x2, #1
> > ? ? ? tst ? ? x1, x3 ? ? ? ? ? ? ? ? ? ? ? ? ?// end cache line aligned?
> > @@ -158,11 +148,42 @@ SYM_FUNC_START(__pi_dcache_inval_poc)
> > ? 3: ?add ? ? x0, x0, x2
> > ? ? ? cmp ? ? x0, x1
> > ? ? ? b.lo ? ?2b
> > +.if \do_sync
> > ? ? ? dsb ? ? sy
> > +.endif
>
> Similarly, don't bother with complication like this, just put the DSB in
> the one place it needs to be.
>

Thanks, Robin ? great suggestion. I assume it can be:

diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S
index 4a7c7e03785d..99a093d3aecb 100644
--- a/arch/arm64/mm/cache.S
+++ b/arch/arm64/mm/cache.S
@@ -132,17 +132,7 @@ alternative_else_nop_endif
 	ret
 SYM_FUNC_END(dcache_clean_pou)
 
-/*
- *	dcache_inval_poc(start, end)
- *
- * 	Ensure that any D-cache lines for the interval [start, end)
- * 	are invalidated. Any partial lines at the ends of the interval are
- *	also cleaned to PoC to prevent data loss.
- *
- *	- start   - kernel start address of region
- *	- end     - kernel end address of region
- */
-SYM_FUNC_START(__pi_dcache_inval_poc)
+.macro raw_dcache_inval_poc_macro
 	dcache_line_size x2, x3
 	sub	x3, x2, #1
 	tst	x1, x3				// end cache line aligned?
@@ -158,11 +148,41 @@ SYM_FUNC_START(__pi_dcache_inval_poc)
 3:	add	x0, x0, x2
 	cmp	x0, x1
 	b.lo	2b
+.endm
+
+/*
+ *	dcache_inval_poc(start, end)
+ *
+ * 	Ensure that any D-cache lines for the interval [start, end)
+ * 	are invalidated. Any partial lines at the ends of the interval are
+ *	also cleaned to PoC to prevent data loss.
+ *
+ *	- start   - kernel start address of region
+ *	- end     - kernel end address of region
+ */
+SYM_FUNC_START(__pi_dcache_inval_poc)
+	raw_dcache_inval_poc_macro
 	dsb	sy
 	ret
 SYM_FUNC_END(__pi_dcache_inval_poc)
 SYM_FUNC_ALIAS(dcache_inval_poc, __pi_dcache_inval_poc)
 
+/*
+ *	dcache_inval_poc_nosync(start, end)
+ *
+ * 	Issue the instructions of D-cache lines for the interval [start, end)
+ * 	for invalidation. Not necessarily cleaned to PoC till an explicit dsb
+ *	sy is issued later
+ *
+ *	- start   - kernel start address of region
+ *	- end     - kernel end address of region
+ */
+SYM_FUNC_START(__pi_dcache_inval_poc_nosync)
+	raw_dcache_inval_poc_macro
+	ret
+SYM_FUNC_END(__pi_dcache_inval_poc_nosync)
+SYM_FUNC_ALIAS(dcache_inval_poc_nosync, __pi_dcache_inval_poc_nosync)
+
 /*
  *	dcache_clean_poc(start, end)
  *
-- 

Does it look good to you?

Thanks
Barry


From wens at kernel.org  Sun Dec 21 00:04:48 2025
From: wens at kernel.org (Chen-Yu Tsai)
Date: Sun, 21 Dec 2025 16:04:48 +0800
Subject: [PATCH] dmaengine: sun6i: Choose appropriate burst length under maxburst
Message-ID: <20251221080450.1813479-1-wens@kernel.org>

maxburst, as provided by the client, specifies the largest amount of
data that is allowed to be transferred in one burst. This limit is
normally provided to avoid a data burst overflowing the target FIFO.
It does not mean that the DMA engine can only do bursts in that size.

Let the driver pick the largest supported burst length within the
given limit. This lets the driver work correctly with some clients that
give a large maxburst value. In particular, the 8250_dw driver will give
a quarter of the UART's FIFO size as maxburst. On some systems the FIFO
size is 256 bytes, giving a maxburst of 64 bytes, while the hardware
only supports bursts of up to 16 bytes.

Signed-off-by: Chen-Yu Tsai <wens at kernel.org>
---
 drivers/dma/sun6i-dma.c | 26 ++++++++++++++++++++------
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
index 2215ff877bf7..f9d876deb1f0 100644
--- a/drivers/dma/sun6i-dma.c
+++ b/drivers/dma/sun6i-dma.c
@@ -583,6 +583,22 @@ static irqreturn_t sun6i_dma_interrupt(int irq, void *dev_id)
 	return ret;
 }
 
+static u32 find_burst_size(const u32 burst_lengths, u32 maxburst)
+{
+	if (!maxburst)
+		return 1;
+
+	if (BIT(maxburst) & burst_lengths)
+		return maxburst;
+
+	/* Hardware only does power-of-two bursts. */
+	for (u32 burst = rounddown_pow_of_two(maxburst); burst > 0; burst /= 2)
+		if (BIT(burst) & burst_lengths)
+			return burst;
+
+	return 1;
+}
+
 static int set_config(struct sun6i_dma_dev *sdev,
 			struct dma_slave_config *sconfig,
 			enum dma_transfer_direction direction,
@@ -616,15 +632,13 @@ static int set_config(struct sun6i_dma_dev *sdev,
 		return -EINVAL;
 	if (!(BIT(dst_addr_width) & sdev->slave.dst_addr_widths))
 		return -EINVAL;
-	if (!(BIT(src_maxburst) & sdev->cfg->src_burst_lengths))
-		return -EINVAL;
-	if (!(BIT(dst_maxburst) & sdev->cfg->dst_burst_lengths))
-		return -EINVAL;
 
 	src_width = convert_buswidth(src_addr_width);
 	dst_width = convert_buswidth(dst_addr_width);
-	dst_burst = convert_burst(dst_maxburst);
-	src_burst = convert_burst(src_maxburst);
+	src_burst = find_burst_size(sdev->cfg->src_burst_lengths, src_maxburst);
+	dst_burst = find_burst_size(sdev->cfg->dst_burst_lengths, dst_maxburst);
+	dst_burst = convert_burst(dst_burst);
+	src_burst = convert_burst(src_burst);
 
 	*p_cfg = DMA_CHAN_CFG_SRC_WIDTH(src_width) |
 		DMA_CHAN_CFG_DST_WIDTH(dst_width);
-- 
2.47.3



From david at kernel.org  Sun Dec 21 01:30:15 2025
From: david at kernel.org (David Hildenbrand (Red Hat))
Date: Sun, 21 Dec 2025 10:30:15 +0100
Subject: [PATCH 1/4] arch/*: increase lowmem size to avoid highmem use
In-Reply-To: <a2ce2849-e572-404c-9713-9283a43c09fe@intel.com>
References: <20251219161559.556737-1-arnd@kernel.org>
 <20251219161559.556737-2-arnd@kernel.org>
 <a3f22579-13ee-4479-a5fd-81c29145c3f3@intel.com>
 <bad18ad8-93e8-4150-a85e-a2852e243363@app.fastmail.com>
 <a2ce2849-e572-404c-9713-9283a43c09fe@intel.com>
Message-ID: <4aecb94f-e283-4720-96e5-1837352c3329@kernel.org>

On 12/19/25 21:52, Dave Hansen wrote:
> On 12/19/25 12:20, Arnd Bergmann wrote:
>>> For simplicity, I think this can just be:
>>>
>>> -	default VMSPLIT_3G
>>> +	default VMSPLIT_2G
>>>
>>> I doubt the 2G vs. 2G_OPT matters in very many cases. If it does, folks
>>> can just set it in their config manually.
>>>
>>> But, in the end, I don't this this matters all that much. If you think
>>> having x86 be consistent with ARM, for example, is more important and
>>> ARM really wants this complexity, I can live with it.
>> Yes, I think we do want the default of VMSPLIT_3G_OPT for
>> configs that have neither highmem nor lpae, otherwise the most
>> common embedded configs go from 3072 MiB to 1792 MiB of virtual
>> addressing, and that is much more likely to cause regressions
>> than the 2816 MiB default.
>>
>> It would be nice to not need the VMSPLIT_2G default for PAE/LPAE,
>> but that seems like a larger change.
> 
> The only thing we'd "regress" would be someone who is repeatedly
> starting from scratch with a defconfig and expecting defconfig to be the
> same all the time. I honestly think that's highly unlikely.
> 
> If folks are upgrading and _actually_ exposed to regressions, they've
> got an existing config and won't be hit by these defaults at *all*. They
> won't actually regress.
> 
> In other words, I think we can be a lot more aggressive about defaults
> than with the feature set we support. I'd much rather add complexity in
> here for solving a real problem, like if we have armies of 32-bit x86
> users constantly starting new projects from scratch and using defconfigs.
> 
> I'd _really_ like to keep the defaults as simple as possible.

I agree with that. In particular in areas where there is the chance that 
we could count the number of people that actually care about that with 
one hand (in binary ;) ).

-- 
Cheers

David


From jcalligeros99 at gmail.com  Sun Dec 21 01:35:56 2025
From: jcalligeros99 at gmail.com (James Calligeros)
Date: Sun, 21 Dec 2025 19:35:56 +1000
Subject: [PATCH v2 0/7] ASoC: basic support for configuring bus keepers
Message-ID: <20251221-tdm-idle-slots-v2-0-ed4d96413aec@gmail.com>

Hi all,

This series introduces some infrastructure to allow platform drivers
to specify what a DAI should be doing when it is not active on the
bus. The primary use case for this is configuring bus keepers which
may be integrated into various codecs. The instigating use case for
this functionality is an interesting bus topology on Apple Silicon
laptops with multiple codecs.

Most Apple Silicon laptops have six codecs split into groups of
three, driving a pair of dual opposed woofers and a tweeter for
L/R stereo sound. These codecs report the voltage and current across
their connected voice coils back to the SoC via the SDOUT pin,
represented as PCM data sent via configurable TDM slots. This data is
used in conjunction with the connected speaker's Thiele/Small Parameters
to ensure that the speaker is not being driven to levels that would
permanently damage them. This is integrated into CoreAudio on macOS.
speakersafetyd[1] handles this for Linux.

All of the codec SDOUT pins are attached to a single receiver port
on the SoC's I2S peripheral, however are split across two physical
data lines (one each for the left and right codec groups). The receiver
has an OR gate in front of it, which is used to sum the two lines.

If at any point a codec is trying to transmit data, and the "opposite"
line ends up floating high, the transmitting codec's data will be
corrupted. We need to guarantee that the idle line stays idle.

In the downstream Asahi Linux kernel[2], we set up one codec in each
group to zero-fill or pull down its line while a codec on the opposite
line is actively transmitting. This is done entirely in the codec
driver, however this approach is over-fit for this one use case. This
sort of functionality may also be of use for other hardware, so following
previous mailing list discussions[3], I have tried to expose the
functionality in a more configurable and generic way.

I have integrated this approach into our downstream platform driver
and select Devicetrees as an example of how this mechanism is intended
to be used[4].

Regards,
James

[1] https://github.com/AsahiLinux/speakersafetyd
[2] https://github.com/AsahiLinux/linux/tree/bits/070-audio
[3] https://lore.kernel.org/asahi/20250227-apple-codec-changes-v3-17-cbb130030acf at gmail.com/
[4] https://github.com/chadmed/tree/tdm-revised2

---
Changes in v2:
- Reworked tdm-slot.yaml schema to silence dtschema warnings
- Properly referenced new tdm-slot.yaml schema in affected bindings,
  again silencing dtschema warnings
- Add PULLUP and DRIVE_HIGH as possible bus keeper modes
- Reworded commit messages and cover letter to more clearly explain
  what the goal is here
- Link to v1: https://lore.kernel.org/r/20251209-tdm-idle-slots-v1-0-38dabf6bc01e at gmail.com

---
James Calligeros (7):
      ASoC: dt-bindings: convert tdm-slot to YAML
      ASoC: dt-bindings: update tdm-slot.txt references to tdm-slot.yaml
      ASoC: dt-bindings: add TDM slot idle mode properties
      ASoC: soc-dai: define possible idle TDM slot modes
      ASoC: soc-dai: add common operation to set TDM idle mode
      ASoC: tas2764: expose SDOUT bus keeper via set_tdm_idle operation
      ASoC: tas2770: expose SDOUT bus keeper via set_tdm_idle

 .../bindings/sound/imx-audio-card.yaml   | 14 ++--
 .../bindings/sound/simple-card.yaml      | 14 +---
 .../bindings/sound/tdm-slot.txt          | 29 --------
 .../bindings/sound/tdm-slot.yaml         | 82 +++++++++++++++++++++
 include/sound/soc-dai.h                  | 22 ++++++
 sound/soc/codecs/tas2764.c               | 95 +++++++++++++++++++++++++
 sound/soc/codecs/tas2764.h               | 11 +++
 sound/soc/codecs/tas2770.c               | 75 +++++++++++++++++++
 sound/soc/codecs/tas2770.h               | 12 ++++
 sound/soc/soc-dai.c                      | 40 +++++++++++
 10 files changed, 345 insertions(+), 49 deletions(-)
---
base-commit: c8d8605fc53e8072848aadc7a5aa00c2f5143cac
change-id: 20251201-tdm-idle-slots-10ba92516da4

Best regards,
-- 
James Calligeros <jcalligeros99 at gmail.com>



From jcalligeros99 at gmail.com  Sun Dec 21 01:35:57 2025
From: jcalligeros99 at gmail.com (James Calligeros)
Date: Sun, 21 Dec 2025 19:35:57 +1000
Subject: [PATCH v2 1/7] ASoC: dt-bindings: convert tdm-slot to YAML
In-Reply-To: <20251221-tdm-idle-slots-v2-0-ed4d96413aec@gmail.com>
References: <20251221-tdm-idle-slots-v2-0-ed4d96413aec@gmail.com>
Message-ID: <20251221-tdm-idle-slots-v2-1-ed4d96413aec@gmail.com>

This schema was still in plaintext form. Convert to YAML format.

Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
---
 .../bindings/sound/tdm-slot.txt          | 29 ---------------
 .../bindings/sound/tdm-slot.yaml         | 49 +++++++++++++++++++++++++
 2 files changed, 49 insertions(+), 29 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/tdm-slot.txt b/Documentation/devicetree/bindings/sound/tdm-slot.txt
deleted file mode 100644
index 4bb513ae62fc..000000000000
--- a/Documentation/devicetree/bindings/sound/tdm-slot.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-TDM slot:
-
-This specifies audio DAI's TDM slot.
-
-TDM slot properties:
-dai-tdm-slot-num : Number of slots in use.
-dai-tdm-slot-width : Width in bits for each slot.
-dai-tdm-slot-tx-mask : Transmit direction slot mask, optional
-dai-tdm-slot-rx-mask : Receive direction slot mask, optional
-
-For instance:
-	dai-tdm-slot-num = <2>;
-	dai-tdm-slot-width = <8>;
-	dai-tdm-slot-tx-mask = <0 1>;
-	dai-tdm-slot-rx-mask = <1 0>;
-
-And for each specified driver, there could be one .of_xlate_tdm_slot_mask()
-to specify an explicit mapping of the channels and the slots. If it's absent
-the default snd_soc_of_xlate_tdm_slot_mask() will be used to generating the
-tx and rx masks.
-
-For snd_soc_of_xlate_tdm_slot_mask(), the tx and rx masks will use a 1 bit
-for an active slot as default, and the default active bits are at the LSB of
-the masks.
-
-The explicit masks are given as array of integers, where the first
-number presents bit-0 (LSB), second presents bit-1, etc. Any non zero
-number is considered 1 and 0 is 0. snd_soc_of_xlate_tdm_slot_mask()
-does not do anything, if either mask is set non zero value.
diff --git a/Documentation/devicetree/bindings/sound/tdm-slot.yaml b/Documentation/devicetree/bindings/sound/tdm-slot.yaml
new file mode 100644
index 000000000000..5bc46048d689
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/tdm-slot.yaml
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/tdm-slot.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Time Division Multiplexing (TDM) Slot Parameters
+
+maintainers:
+  - Liam Girdwood <lgirdwood at gmail.com>
+
+select: false
+
+$defs:
+  dai-tdm-slot-num:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Number of slots in use
+
+  dai-tdm-slot-width:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Width, in bits, of each slot
+
+  dai-tdm-slot-tx-mask:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    description: Transmit direction slot mask. Optional. Drivers may specify an
+      .xlate_tdm_slot_mask() to generate a slot mask dynamically. If neither
+      this property nor a driver-specific function are specified, the default
+      snd_soc_xlate_tdm_slot_mask() function will be used to generate a mask.
+      The first element of the array is slot 0 (LSB). Any nonzero value will be
+      treated as 1.
+
+  dai-tdm-slot-rx-mask:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    description: Receive direction slot mask. Optional. Identical to TX mask.
+
+properties:
+  dai-tdm-slot-num:
+    $ref: "#/$defs/dai-tdm-slot-num"
+
+  dai-tdm-slot-width:
+    $ref: "#/$defs/dai-tdm-slot-width"
+
+  dai-tdm-slot-tx-mask:
+    $ref: "#/$defs/dai-tdm-slot-tx-mask"
+
+  dai-tdm-slot-rx-mask:
+    $ref: "#/$defs/dai-tdm-slot-rx-mask"
+
+additionalProperties: true

-- 
2.52.0



From jcalligeros99 at gmail.com  Sun Dec 21 01:35:58 2025
From: jcalligeros99 at gmail.com (James Calligeros)
Date: Sun, 21 Dec 2025 19:35:58 +1000
Subject: [PATCH v2 2/7] ASoC: dt-bindings: update tdm-slot.txt references
 to tdm-slot.yaml
In-Reply-To: <20251221-tdm-idle-slots-v2-0-ed4d96413aec@gmail.com>
References: <20251221-tdm-idle-slots-v2-0-ed4d96413aec@gmail.com>
Message-ID: <20251221-tdm-idle-slots-v2-2-ed4d96413aec@gmail.com>

Ensure that all references to tdm-slot.txt have been updated to
tdm-slot.yaml, and are schema-compliant.

Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
---
 .../bindings/sound/imx-audio-card.yaml   | 14 ++++++--------
 .../bindings/sound/simple-card.yaml      | 14 ++------------
 2 files changed, 8 insertions(+), 20 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/imx-audio-card.yaml b/Documentation/devicetree/bindings/sound/imx-audio-card.yaml
index 3c75c8c78987..eb702f48d694 100644
--- a/Documentation/devicetree/bindings/sound/imx-audio-card.yaml
+++ b/Documentation/devicetree/bindings/sound/imx-audio-card.yaml
@@ -31,6 +31,12 @@ patternProperties:
         $ref: /schemas/types.yaml#/definitions/string
         maxItems: 1
 
+      dai-tdm-slot-num:
+        $ref: tdm-slot.yaml#/$defs/dai-tdm-slot-num
+
+      dai-tdm-slot-width:
+        $ref: tdm-slot.yaml#/$defs/dai-tdm-slot-width
+
       format:
         description: audio format.
         items:
@@ -38,14 +44,6 @@ patternProperties:
             - i2s
             - dsp_b
 
-      dai-tdm-slot-num:
-        description: see tdm-slot.txt.
-        $ref: /schemas/types.yaml#/definitions/uint32
-
-      dai-tdm-slot-width:
-        description: see tdm-slot.txt.
-        $ref: /schemas/types.yaml#/definitions/uint32
-
       playback-only:
         description: link is used only for playback
         $ref: /schemas/types.yaml#/definitions/flag
diff --git a/Documentation/devicetree/bindings/sound/simple-card.yaml b/Documentation/devicetree/bindings/sound/simple-card.yaml
index 533d0a1da56e..a14716b2732f 100644
--- a/Documentation/devicetree/bindings/sound/simple-card.yaml
+++ b/Documentation/devicetree/bindings/sound/simple-card.yaml
@@ -27,14 +27,6 @@ definitions:
     description: dai-link uses bit clock inversion
     $ref: /schemas/types.yaml#/definitions/flag
 
-  dai-tdm-slot-num:
-    description: see tdm-slot.txt.
-    $ref: /schemas/types.yaml#/definitions/uint32
-
-  dai-tdm-slot-width:
-    description: see tdm-slot.txt.
-    $ref: /schemas/types.yaml#/definitions/uint32
-
   system-clock-frequency:
     description: |
       If a clock is specified and a multiplication factor is given with
@@ -115,6 +107,8 @@ definitions:
 
   dai:
     type: object
+    $ref: tdm-slot.yaml#
+
     properties:
       sound-dai:
         maxItems: 1
@@ -133,10 +127,6 @@ definitions:
       bitclock-master:
         $ref: /schemas/types.yaml#/definitions/flag
 
-      dai-tdm-slot-num:
-        $ref: "#/definitions/dai-tdm-slot-num"
-      dai-tdm-slot-width:
-        $ref: "#/definitions/dai-tdm-slot-width"
       clocks:
         maxItems: 1
       system-clock-frequency:

-- 
2.52.0



From jcalligeros99 at gmail.com  Sun Dec 21 01:35:59 2025
From: jcalligeros99 at gmail.com (James Calligeros)
Date: Sun, 21 Dec 2025 19:35:59 +1000
Subject: [PATCH v2 3/7] ASoC: dt-bindings: add TDM slot idle mode
 properties
In-Reply-To: <20251221-tdm-idle-slots-v2-0-ed4d96413aec@gmail.com>
References: <20251221-tdm-idle-slots-v2-0-ed4d96413aec@gmail.com>
Message-ID: <20251221-tdm-idle-slots-v2-3-ed4d96413aec@gmail.com>

Add properties to describe TDM slot idle behaviour. These properties can
be used to describe how a DAI is supposed to behave when not active.

For example, Apple Silicon laptops split a single I2S bus between two
physical lines which are combined at an OR gate in front of the
receiving port. One codec on each line is expected to transmit zeroes
during the active TDM slots of the opposite line, or we will have corrupted
data at the receiver.

Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
---
 .../bindings/sound/tdm-slot.yaml         | 33 +++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/Documentation/devicetree/bindings/sound/tdm-slot.yaml b/Documentation/devicetree/bindings/sound/tdm-slot.yaml
index 5bc46048d689..e8b2d35a7c37 100644
--- a/Documentation/devicetree/bindings/sound/tdm-slot.yaml
+++ b/Documentation/devicetree/bindings/sound/tdm-slot.yaml
@@ -33,6 +33,17 @@ $defs:
     $ref: /schemas/types.yaml#/definitions/uint32-array
     description: Receive direction slot mask. Optional. Identical to TX mask.
 
+  dai-tdm-idle-mode:
+    $ref: /schemas/types.yaml#/definitions/string
+    enum:
+      - none
+      - off
+      - zero
+      - pulldown
+      - hiz
+      - pullup
+      - drivehigh
+
 properties:
   dai-tdm-slot-num:
     $ref: "#/$defs/dai-tdm-slot-num"
@@ -46,4 +57,26 @@ properties:
   dai-tdm-slot-rx-mask:
     $ref: "#/$defs/dai-tdm-slot-rx-mask"
 
+  dai-tdm-slot-tx-idle-mode:
+    $ref: "#/$defs/dai-tdm-idle-mode"
+    description: Transmit direction idle slot mode. Optional. For hardware
+      that can configure its behaviour during idle TDM slots via
+      .set_tdm_idle(). "None" represents UB/unspecified behaviour and is the
+      same as not setting this property.
+
+  dai-tdm-slot-rx-idle-mode:
+    $ref: "#/$defs/dai-tdm-idle-mode"
+    description: Receive direction idle slot mode. Optional. Identical to TX
+      idle slot mode.
+
+  dai-tdm-slot-tx-idle-mask:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Transmit direction idle slot mask. Optional. 1 represents
+      an idle slot.
+
+  dai-tdm-slot-rx-idle-mask:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Receive direction idle slot mask. Optional. Identical to
+      TX mask.
+
 additionalProperties: true

-- 
2.52.0



From jcalligeros99 at gmail.com  Sun Dec 21 01:36:00 2025
From: jcalligeros99 at gmail.com (James Calligeros)
Date: Sun, 21 Dec 2025 19:36:00 +1000
Subject: [PATCH v2 4/7] ASoC: soc-dai: define possible idle TDM slot modes
In-Reply-To: <20251221-tdm-idle-slots-v2-0-ed4d96413aec@gmail.com>
References: <20251221-tdm-idle-slots-v2-0-ed4d96413aec@gmail.com>
Message-ID: <20251221-tdm-idle-slots-v2-4-ed4d96413aec@gmail.com>

Some audio devices, such as certain Texas Instruments codecs,
include configurable bus keepers. We currently don't have
a standardised way to configure such hardware, and instead
rely on the hardware initialising setting itself up into a
sane state. There are situations where this is insufficient,
however, and some platforms require more concrete guarantees
as to the state of the bus, and being able to explicitly
configure bus keepers enables this.

For example, some Apple Silicon machines have an odd bus topology where
the SDOUT pins of all codecs are split across two data lines, which
are summed via an OR gate in front of the receiving port on the
SoC's I2S peripheral. Each line must transmit 0 while a codec
on the other line is actively transmitting data, or the SoC
will receive garbage data. To do this, one codec on each line
must be configured to transmit zeroes during the other line's
active TDM slots.

Thus, we define seven possible bus-keeping modes that a device can
be in: NONE (UB/as initialised), OFF (explicitly disabled), ZERO
(actively transmit a 0), PULLDOWN, HIZ (floating), PULLUP, and
DRIVE_HIGH.

These will be consumed by CODEC/CPU drivers via a common DAI
op, enabling the explicit configuration of bus keepers where
required.

Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
---
 include/sound/soc-dai.h | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 224396927aef..44dd06add52e 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -52,6 +52,21 @@ struct snd_compr_stream;
 #define SND_SOC_POSSIBLE_DAIFMT_AC97		(1 << SND_SOC_DAI_FORMAT_AC97)
 #define SND_SOC_POSSIBLE_DAIFMT_PDM		(1 << SND_SOC_DAI_FORMAT_PDM)
 
+/*
+ * DAI TDM slot idle modes
+ *
+ * Describes a CODEC/CPU's behaviour when not actively receiving or
+ * transmitting on a given TDM slot. NONE is undefined behaviour.
+ * Add new modes to the end.
+ */
+#define SND_SOC_DAI_TDM_IDLE_NONE	0
+#define SND_SOC_DAI_TDM_IDLE_OFF	1
+#define SND_SOC_DAI_TDM_IDLE_ZERO	2
+#define SND_SOC_DAI_TDM_IDLE_PULLDOWN	3
+#define SND_SOC_DAI_TDM_IDLE_HIZ	4
+#define SND_SOC_DAI_TDM_IDLE_PULLUP	5
+#define SND_SOC_DAI_TDM_IDLE_DRIVE_HIGH	6
+
 /*
  * DAI Clock gating.
  *

-- 
2.52.0



From jcalligeros99 at gmail.com  Sun Dec 21 01:36:01 2025
From: jcalligeros99 at gmail.com (James Calligeros)
Date: Sun, 21 Dec 2025 19:36:01 +1000
Subject: [PATCH v2 5/7] ASoC: soc-dai: add common operation to set TDM idle
 mode
In-Reply-To: <20251221-tdm-idle-slots-v2-0-ed4d96413aec@gmail.com>
References: <20251221-tdm-idle-slots-v2-0-ed4d96413aec@gmail.com>
Message-ID: <20251221-tdm-idle-slots-v2-5-ed4d96413aec@gmail.com>

Some audio devices, like certain Texas Instruments codecs, integrate
configurable bus keepers that dictate the codec's behaviour during
idle TDM slots. Now that we have definitions for various idle modes,
add a snd_soc_dai_set_tdm_idle() operation to control this in a
standardised way.

This is useful on Apple Silicon laptops, where a single I2S bus is
comprised of two physical lines which are ORed just before the
receiving port. When a codec on one line is transmitting, we must
guarantee that the other line is low. We can achieve this by
configuring one codec on each line to use its bus keeper to fill
its line with zeroes during the active slots of the other line.

Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
---
 include/sound/soc-dai.h |  7 +++++
 sound/soc/soc-dai.c     | 40 +++++++++++++++++++++++++
 2 files changed, 47 insertions(+)

diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 44dd06add52e..6a42812bba8c 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -196,6 +196,10 @@ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt);
 int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
 	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width);
 
+int snd_soc_dai_set_tdm_idle(struct snd_soc_dai *dai,
+			     unsigned int tx_mask, unsigned int rx_mask,
+			     int tx_mode, int rx_mode);
+
 int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
 	unsigned int tx_num, const unsigned int *tx_slot,
 	unsigned int rx_num, const unsigned int *rx_slot);
@@ -312,6 +316,9 @@ struct snd_soc_dai_ops {
 	int (*set_tdm_slot)(struct snd_soc_dai *dai,
 		unsigned int tx_mask, unsigned int rx_mask,
 		int slots, int slot_width);
+	int (*set_tdm_idle)(struct snd_soc_dai *dai,
+			    unsigned int tx_mask, unsigned int rx_mask,
+			    int tx_mode, int rx_mode);
 	int (*set_channel_map)(struct snd_soc_dai *dai,
 		unsigned int tx_num, const unsigned int *tx_slot,
 		unsigned int rx_num, const unsigned int *rx_slot);
diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
index a1e05307067d..2f370fda1266 100644
--- a/sound/soc/soc-dai.c
+++ b/sound/soc/soc-dai.c
@@ -282,6 +282,46 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
 
+/**
+ * snd_soc_dai_set_tdm_idle() - Configure a DAI's TDM idle mode
+ * @dai: The DAI to configure
+ * @tx_mask: bitmask representing idle TX slots.
+ * @rx_mask: bitmask representing idle RX slots.
+ * @tx_mode: idle mode to set for TX slots.
+ * @rx_mode: idle mode to set for RX slots.
+ *
+ * This function configures the DAI to handle idle TDM slots in the
+ * specified manner. @tx_mode and @rx_mode can be one of
+ * SND_SOC_DAI_TDM_IDLE_NONE, SND_SOC_DAI_TDM_IDLE_ZERO,
+ * SND_SOC_DAI_TDM_IDLE_PULLDOWN, or SND_SOC_DAI_TDM_IDLE_HIZ.
+ * SND_SOC_TDM_IDLE_NONE represents the DAI's default/unset idle slot
+ * handling state and could be any of the other modes depending on the
+ * hardware behind the DAI. It is therefore undefined behaviour when set
+ * explicitly.
+ *
+ * Mode and mask can be set independently for both the TX and RX direction.
+ * Some hardware may ignore both TX and RX masks depending on its
+ * capabilities.
+ */
+int snd_soc_dai_set_tdm_idle(struct snd_soc_dai *dai,
+			     unsigned int tx_mask, unsigned int rx_mask,
+			     int tx_mode, int rx_mode)
+{
+	int ret = -EOPNOTSUPP;
+
+	/* You can't write to the RX line */
+	if (rx_mode == SND_SOC_DAI_TDM_IDLE_ZERO)
+		return soc_dai_ret(dai, -EINVAL);
+
+	if (dai->driver->ops &&
+	    dai->driver->ops->set_tdm_idle)
+		ret = dai->driver->ops->set_tdm_idle(dai, tx_mask, rx_mask,
+						     tx_mode, rx_mode);
+
+	return soc_dai_ret(dai, ret);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_idle);
+
 /**
  * snd_soc_dai_set_channel_map - configure DAI audio channel map
  * @dai: DAI

-- 
2.52.0



From jcalligeros99 at gmail.com  Sun Dec 21 01:36:02 2025
From: jcalligeros99 at gmail.com (James Calligeros)
Date: Sun, 21 Dec 2025 19:36:02 +1000
Subject: [PATCH v2 6/7] ASoC: tas2764: expose SDOUT bus keeper via
 set_tdm_idle operation
In-Reply-To: <20251221-tdm-idle-slots-v2-0-ed4d96413aec@gmail.com>
References: <20251221-tdm-idle-slots-v2-0-ed4d96413aec@gmail.com>
Message-ID: <20251221-tdm-idle-slots-v2-6-ed4d96413aec@gmail.com>

TAS2764, and the Apple-exclusive variant SN012776, include bus keepers
on the SDOUT pin that can be configured to alter the behaviour of the
SDOUT pin during specified TDM slots. The chip can either leave the
bus floating (default/uninitialised behaviour) or fill the specified
slots with zeroes.

Expose the SDOUT bus keeper and allow it to be configured using the
set_tdm_idle DAI op. The mask must be cropped to only cover slots
valid for the configured BCLK ratio, so introduce a set_bclk_ratio
op that properly configures this.

Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
---
 sound/soc/codecs/tas2764.c | 95 +++++++++++++++++++++++++
 sound/soc/codecs/tas2764.h | 11 +++
 2 files changed, 106 insertions(+)

diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c
index 36e25e48b354..423b7073b302 100644
--- a/sound/soc/codecs/tas2764.c
+++ b/sound/soc/codecs/tas2764.c
@@ -44,6 +44,11 @@ struct tas2764_priv {
 
 	bool dac_powered;
 	bool unmuted;
+
+	struct {
+		int tx_mode;
+		unsigned int tx_mask;
+	} idle_slot_config;
 };
 
 #include "tas2764-quirks.h"
@@ -509,11 +514,101 @@ static int tas2764_set_dai_tdm_slot(struct snd_soc_dai *dai,
 	return 0;
 }
 
+static int tas2764_write_sdout_idle_mask(struct tas2764_priv *tas2764, u32 mask)
+{
+	struct snd_soc_component *component = tas2764->component;
+	int i, ret;
+
+	/* Hardware supports up to 64 slots, but we don't */
+	for (i = 0; i < 4; i++) {
+		ret = snd_soc_component_write(component,
+					      TAS2764_SDOUT_HIZ_1 + i,
+					      (mask >> (i * 8)) & 0xff);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int tas2764_set_dai_tdm_idle(struct snd_soc_dai *dai,
+				    unsigned int tx_mask, unsigned int rx_mask,
+				    int tx_mode, int rx_mode)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	/* We don't support setting anything on SDIN */
+	if (rx_mode)
+		return -EOPNOTSUPP;
+
+	if (tas2764->idle_slot_config.tx_mask == tx_mask &&
+	    tas2764->idle_slot_config.tx_mode == tx_mode)
+		return 0;
+
+	switch (tx_mode) {
+	case SND_SOC_DAI_TDM_IDLE_ZERO:
+		if (!tx_mask)
+			return -EINVAL;
+
+		ret = tas2764_write_sdout_idle_mask(tas2764, tx_mask);
+		if (ret < 0)
+			return ret;
+
+		ret = snd_soc_component_update_bits(component,
+						    TAS2764_SDOUT_HIZ_9,
+						    TAS2764_SDOUT_HIZ_9_FORCE_0_EN,
+						    TAS2764_SDOUT_HIZ_9_FORCE_0_EN);
+		if (ret < 0)
+			return ret;
+
+		tas2764->idle_slot_config.tx_mask = tx_mask;
+		tas2764->idle_slot_config.tx_mode = tx_mode;
+		break;
+	case SND_SOC_DAI_TDM_IDLE_HIZ:
+	case SND_SOC_DAI_TDM_IDLE_OFF:
+		/* HiZ mode does not support a slot mask */
+		ret = tas2764_write_sdout_idle_mask(tas2764, 0);
+		if (ret < 0)
+			return ret;
+
+		ret = snd_soc_component_update_bits(component,
+						    TAS2764_SDOUT_HIZ_9,
+						    TAS2764_SDOUT_HIZ_9_FORCE_0_EN, 0);
+		if (ret < 0)
+			return ret;
+
+		tas2764->idle_slot_config.tx_mask = 0;
+		tas2764->idle_slot_config.tx_mode = tx_mode;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+/* The SDOUT idle slot mask must be cropped based on the BCLK ratio */
+static int tas2764_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+	struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(dai->component);
+
+	if (!tas2764->idle_slot_config.tx_mask)
+		return 0;
+
+	tas2764->idle_slot_config.tx_mask &= GENMASK((ratio / 8) - 1, 0);
+
+	return tas2764_write_sdout_idle_mask(tas2764, tas2764->idle_slot_config.tx_mask);
+}
+
 static const struct snd_soc_dai_ops tas2764_dai_ops = {
 	.mute_stream = tas2764_mute,
 	.hw_params  = tas2764_hw_params,
 	.set_fmt    = tas2764_set_fmt,
+	.set_bclk_ratio = tas2764_set_bclk_ratio,
 	.set_tdm_slot = tas2764_set_dai_tdm_slot,
+	.set_tdm_idle = tas2764_set_dai_tdm_idle,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/tas2764.h b/sound/soc/codecs/tas2764.h
index 538290ed3d92..4494bc4889dc 100644
--- a/sound/soc/codecs/tas2764.h
+++ b/sound/soc/codecs/tas2764.h
@@ -126,4 +126,15 @@
 
 #define TAS2764_BOP_CFG0                TAS2764_REG(0X0, 0x1d)
 
+#define TAS2764_SDOUT_HIZ_1            TAS2764_REG(0x1, 0x3d)
+#define TAS2764_SDOUT_HIZ_2            TAS2764_REG(0x1, 0x3e)
+#define TAS2764_SDOUT_HIZ_3            TAS2764_REG(0x1, 0x3f)
+#define TAS2764_SDOUT_HIZ_4            TAS2764_REG(0x1, 0x40)
+#define TAS2764_SDOUT_HIZ_5            TAS2764_REG(0x1, 0x41)
+#define TAS2764_SDOUT_HIZ_6            TAS2764_REG(0x1, 0x42)
+#define TAS2764_SDOUT_HIZ_7            TAS2764_REG(0x1, 0x43)
+#define TAS2764_SDOUT_HIZ_8            TAS2764_REG(0x1, 0x44)
+#define TAS2764_SDOUT_HIZ_9            TAS2764_REG(0x1, 0x45)
+#define TAS2764_SDOUT_HIZ_9_FORCE_0_EN BIT(7)
+
 #endif /* __TAS2764__ */

-- 
2.52.0



From jcalligeros99 at gmail.com  Sun Dec 21 01:36:03 2025
From: jcalligeros99 at gmail.com (James Calligeros)
Date: Sun, 21 Dec 2025 19:36:03 +1000
Subject: [PATCH v2 7/7] ASoC: tas2770: expose SDOUT bus keeper via
 set_tdm_idle
In-Reply-To: <20251221-tdm-idle-slots-v2-0-ed4d96413aec@gmail.com>
References: <20251221-tdm-idle-slots-v2-0-ed4d96413aec@gmail.com>
Message-ID: <20251221-tdm-idle-slots-v2-7-ed4d96413aec@gmail.com>

TAS2770 includes a bus keeper which can be used to control the behaviour
of the SDOUT pin during specified TDM slots. The chip can either pull
the pin to ground, actively transmit zeroes, or keep the pin floating
(default/uninitialised behaviour).

Expose the bus keeper via the set_tdm_idle DAI op so that it can be
configured by consumers.

Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
---
 sound/soc/codecs/tas2770.c | 75 +++++++++++++++++++++++++
 sound/soc/codecs/tas2770.h | 12 ++++
 2 files changed, 87 insertions(+)

diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c
index 6f878b01716f..d4d7d056141b 100644
--- a/sound/soc/codecs/tas2770.c
+++ b/sound/soc/codecs/tas2770.c
@@ -492,11 +492,86 @@ static int tas2770_set_dai_tdm_slot(struct snd_soc_dai *dai,
 	return 0;
 }
 
+static int tas2770_set_dai_tdm_idle(struct snd_soc_dai *dai,
+				    unsigned int tx_mask,
+				    unsigned int rx_mask,
+				    int tx_mode, int rx_mode)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas2770_priv *tas2770 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	/* We don't support setting anything for SDIN */
+	if (rx_mode)
+		return -EOPNOTSUPP;
+
+	if (tas2770->idle_tx_mode == tx_mode)
+		return 0;
+
+	switch (tx_mode) {
+	case SND_SOC_DAI_TDM_IDLE_PULLDOWN:
+		ret = snd_soc_component_update_bits(component, TAS2770_DIN_PD,
+						    TAS2770_DIN_PD_SDOUT,
+						    TAS2770_DIN_PD_SDOUT);
+		if (ret)
+			return ret;
+
+		break;
+	case SND_SOC_DAI_TDM_IDLE_ZERO:
+		ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG4,
+						    TAS2770_TDM_CFG_REG4_TX_KEEPER,
+						    TAS2770_TDM_CFG_REG4_TX_KEEPER);
+		if (ret)
+			return ret;
+
+		ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG4,
+						    TAS2770_TDM_CFG_REG4_TX_FILL, 0);
+		if (ret)
+			return ret;
+
+		break;
+	case SND_SOC_DAI_TDM_IDLE_HIZ:
+		ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG4,
+						    TAS2770_TDM_CFG_REG4_TX_KEEPER,
+						    TAS2770_TDM_CFG_REG4_TX_KEEPER);
+		if (ret)
+			return ret;
+
+		ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG4,
+						    TAS2770_TDM_CFG_REG4_TX_FILL,
+						    TAS2770_TDM_CFG_REG4_TX_FILL);
+		if (ret)
+			return ret;
+
+		break;
+	case SND_SOC_DAI_TDM_IDLE_OFF:
+		ret = snd_soc_component_update_bits(component, TAS2770_DIN_PD,
+						    TAS2770_DIN_PD_SDOUT, 0);
+		if (ret)
+			return ret;
+
+		ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG4,
+						    TAS2770_TDM_CFG_REG4_TX_KEEPER, 0);
+		if (ret)
+			return ret;
+
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	tas2770->idle_tx_mode = tx_mode;
+
+	return 0;
+}
+
 static const struct snd_soc_dai_ops tas2770_dai_ops = {
 	.mute_stream = tas2770_mute,
 	.hw_params  = tas2770_hw_params,
 	.set_fmt    = tas2770_set_fmt,
 	.set_tdm_slot = tas2770_set_dai_tdm_slot,
+	.set_tdm_idle = tas2770_set_dai_tdm_idle,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/tas2770.h b/sound/soc/codecs/tas2770.h
index 3fd2e7003c50..102040b6bdf8 100644
--- a/sound/soc/codecs/tas2770.h
+++ b/sound/soc/codecs/tas2770.h
@@ -67,6 +67,14 @@
 #define TAS2770_TDM_CFG_REG3_RXS_SHIFT 0x4
 #define TAS2770_TDM_CFG_REG3_30_MASK  GENMASK(3, 0)
 #define TAS2770_TDM_CFG_REG3_30_SHIFT 0
+    /* TDM Configuration Reg4 */
+#define TAS2770_TDM_CFG_REG4  TAS2770_REG(0X0, 0x0E)
+#define TAS2770_TDM_CFG_REG4_TX_LSB_CFG BIT(7)
+#define TAS2770_TDM_CFG_REG4_TX_KEEPER_CFG BIT(6)
+#define TAS2770_TDM_CFG_REG4_TX_KEEPER BIT(5)
+#define TAS2770_TDM_CFG_REG4_TX_FILL BIT(4)
+#define TAS2770_TDM_CFG_REG4_TX_OFFSET_MASK GENMASK(3, 1)
+#define TAS2770_TDM_CFG_REG4_TX_EDGE_FALLING BIT(0)
     /* TDM Configuration Reg5 */
 #define TAS2770_TDM_CFG_REG5  TAS2770_REG(0X0, 0x0F)
 #define TAS2770_TDM_CFG_REG5_VSNS_MASK  BIT(6)
@@ -115,6 +123,9 @@
 #define TAS2770_TEMP_LSB  TAS2770_REG(0X0, 0x2A)
     /* Interrupt Configuration */
 #define TAS2770_INT_CFG  TAS2770_REG(0X0, 0x30)
+    /* Data In Pull-Down */
+#define TAS2770_DIN_PD  TAS2770_REG(0X0, 0x31)
+#define TAS2770_DIN_PD_SDOUT BIT(7)
     /* Misc IRQ */
 #define TAS2770_MISC_IRQ  TAS2770_REG(0X0, 0x32)
     /* Clock Configuration */
@@ -146,6 +157,7 @@ struct tas2770_priv {
 	int pdm_slot;
 	bool dac_powered;
 	bool unmuted;
+	int idle_tx_mode;
 };
 
 #endif /* __TAS2770__ */

-- 
2.52.0



From jakub.turek at elsta.tech  Sun Dec 21 02:32:21 2025
From: jakub.turek at elsta.tech (j.turek)
Date: Sun, 21 Dec 2025 11:32:21 +0100
Subject: [PATCH v2] serial:xilinx_uartps:fix rs485 delay_rts_after_send
Message-ID: <20251221103221.1971125-1-jakub.turek@elsta.tech>

RTS line control with delay should be triggered when there is no more bytes
in kfifo and hardware buffer is empty. Without this patch RTS control is
scheduled right after feeding hardware buffer and this is too early.
RTS line may change state before hardware buffer is empty.
With this patch delayed RTS state change is triggered when function
cdns_uart_handle_tx is called from cdns_uart_isr on CDNS_UART_IXR_TXEMPTY
exactly when hardware completed transmission

Signed-off-by: Jakub Turek  <jakub.turek at elsta.tech>

Fixes: fccc9d9233f9 ("tty: serial: uartps: Add rs485 support to uartps driver")
---
 drivers/tty/serial/xilinx_uartps.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

v2:
 - Fix build error by declaring rts_delay as ktime_t

diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 1e4d54fd5762..8b08f478253e 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -428,10 +428,17 @@ static void cdns_uart_handle_tx(void *dev_id)
 	struct tty_port *tport = &port->state->port;
 	unsigned int numbytes;
 	unsigned char ch;
+	ktime_t rts_delay;
 
 	if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
 		/* Disable the TX Empty interrupt */
 		writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR);
+		/* Set RTS line after delay */
+		if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) {
+			cdns_uart->tx_timer.function = &cdns_rs485_rx_callback;
+			rts_delay = ns_to_ktime(cdns_calc_after_tx_delay(cdns_uart));
+			hrtimer_start(&cdns_uart->tx_timer, rts_delay, HRTIMER_MODE_REL);
+		}
 		return;
 	}
 
@@ -448,13 +455,6 @@ static void cdns_uart_handle_tx(void *dev_id)
 
 	/* Enable the TX Empty interrupt */
 	writel(CDNS_UART_IXR_TXEMPTY, cdns_uart->port->membase + CDNS_UART_IER);
-
-	if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED &&
-	    (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port))) {
-		hrtimer_update_function(&cdns_uart->tx_timer, cdns_rs485_rx_callback);
-		hrtimer_start(&cdns_uart->tx_timer,
-			      ns_to_ktime(cdns_calc_after_tx_delay(cdns_uart)), HRTIMER_MODE_REL);
-	}
 }
 
 /**
-- 
2.34.1



From cristian.ciocaltea at collabora.com  Sun Dec 21 02:36:24 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Sun, 21 Dec 2025 12:36:24 +0200
Subject: [PATCH v2 2/2] phy: rockchip: samsung-hdptx: Cleanup TMDS PLL
 config table
In-Reply-To: <20251221-phy-hdptx-pll-fix-v2-0-ae4abf7f75a1@collabora.com>
References: <20251221-phy-hdptx-pll-fix-v2-0-ae4abf7f75a1@collabora.com>
Message-ID: <20251221-phy-hdptx-pll-fix-v2-2-ae4abf7f75a1@collabora.com>

Drop a bunch of unused members from struct ropll_config and make the
static ropll_tmds_cfg table more readable:

* add a table header
* sort rows by rate
* convert hex values to decimal (for consistency)

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 82 +++++++----------------
 1 file changed, 24 insertions(+), 58 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index cafa618d70fd..e3d817e81d6d 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -336,27 +336,13 @@ struct ropll_config {
 	u8 pms_pdiv;
 	u8 pms_refdiv;
 	u8 pms_sdiv;
-	u8 pms_iqdiv_rstn;
-	u8 ref_clk_sel;
 	u8 sdm_en;
-	u8 sdm_rstn;
-	u8 sdc_frac_en;
-	u8 sdc_rstn;
-	u8 sdm_clk_div;
 	u8 sdm_deno;
 	u8 sdm_num_sign;
 	u8 sdm_num;
 	u8 sdc_n;
 	u8 sdc_num;
 	u8 sdc_deno;
-	u8 sdc_ndiv_rstn;
-	u8 ssc_en;
-	u8 ssc_fm_dev;
-	u8 ssc_fm_freq;
-	u8 ssc_clk_div_sel;
-	u8 ana_cpp_ctrl;
-	u8 ana_lpf_c_sel;
-	u8 cd_tx_ser_rate_sel;
 };
 
 struct tx_drv_ctrl {
@@ -412,50 +398,30 @@ struct rk_hdptx_phy {
 };
 
 static const struct ropll_config ropll_tmds_cfg[] = {
-	{ 594000000ULL, 124, 124, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
-	  1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 461101250ULL, 97, 97, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 71, 1, 53, 2, 6,
-	  35, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 371250000ULL, 155, 155, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
-	  1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 297000000ULL, 124, 124, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
-	  1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 162000000ULL, 135, 135, 1, 1, 3, 1, 1, 0, 1, 1, 1, 1, 4, 0, 3, 5, 5, 0x10,
-	  1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 185625000ULL, 155, 155, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
-	  1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 154000000ULL, 193, 193, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 193, 1, 32, 2, 1,
-	  1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 148500000ULL, 0x7b, 0x7b, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 4, 0, 3, 5, 5,
-	  0x10, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 146250000ULL, 122, 122, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 244, 1, 16, 2, 1, 1,
-	  1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 119000000ULL, 149, 149, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 149, 1, 16, 2, 1, 1,
-	  1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 106500000ULL, 89, 89, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 89, 1, 16, 1, 0, 1,
-	  1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 108000000ULL, 135, 135, 1, 1, 5, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0,
-	  0x14, 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 85500000ULL, 214, 214, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 214, 1, 16, 2, 1,
-	  1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 83500000ULL, 105, 105, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 42, 1, 16, 1, 0,
-	  1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 92812500ULL, 155, 155, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
-	  1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 74250000ULL, 124, 124, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
-	  1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 65000000ULL, 162, 162, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 54, 0, 16, 4, 1,
-	  1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 50250000ULL, 84, 84, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 11, 1, 4, 5,
-	  4, 11, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 33750000ULL, 0x70, 0x70, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 0x2, 0, 0x01, 5,
-	  1, 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 40000000ULL, 100, 100, 1, 1, 11, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0,
-	  0x14, 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 27000000ULL, 0x5a, 0x5a, 1, 1, 0xf, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0,
-	  0x14, 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
-	{ 25175000ULL, 84, 84, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 168, 1, 16, 4, 1, 1,
-	  1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
+	/*             |              pms             |        sdm         |     sdc     | */
+	/*        rate, mdiv, mdafc, pdiv, rdiv, sdiv, en, deno, nsig, num,  n, num, deno, */
+	{ 594000000ULL,  124,   124,    1,    1,    0,  1,   62,    1,  16,  5,   0,    1, },
+	{ 461101250ULL,   97,    97,    1,    1,    0,  1,   71,    1,  53,  2,   6,   35, },
+	{ 371250000ULL,  155,   155,    1,    1,    1,  1,   62,    1,  16,  5,   0,    1, },
+	{ 297000000ULL,  124,   124,    1,    1,    1,  1,   62,    1,  16,  5,   0,    1, },
+	{ 185625000ULL,  155,   155,    1,    1,    3,  1,   62,    1,  16,  5,   0,    1, },
+	{ 162000000ULL,  135,   135,    1,    1,    3,  0,    4,    0,   3,  5,   5,   16, },
+	{ 154000000ULL,  193,   193,    1,    1,    5,  1,  193,    1,  32,  2,   1,    1, },
+	{ 148500000ULL,  123,   123,    1,    1,    3,  1,    4,    0,   3,  5,   5,   16, },
+	{ 146250000ULL,  122,   122,    1,    1,    3,  1,  244,    1,  16,  2,   1,    1, },
+	{ 119000000ULL,  149,   149,    1,    1,    5,  1,  149,    1,  16,  2,   1,    1, },
+	{ 108000000ULL,  135,   135,    1,    1,    5,  0,    9,    0,   5,  0,  20,   24, },
+	{ 106500000ULL,   89,    89,    1,    1,    3,  1,   89,    1,  16,  1,   0,    1, },
+	{  92812500ULL,  155,   155,    1,    1,    7,  1,   62,    1,  16,  5,   0,    1, },
+	{  85500000ULL,  214,   214,    1,    1,   11,  1,  214,    1,  16,  2,   1,    1, },
+	{  83500000ULL,  105,   105,    1,    1,    5,  1,   42,    1,  16,  1,   0,    1, },
+	{  74250000ULL,  124,   124,    1,    1,    7,  1,   62,    1,  16,  5,   0,    1, },
+	{  65000000ULL,  162,   162,    1,    1,   11,  1,   54,    0,  16,  4,   1,    1, },
+	{  50250000ULL,   84,    84,    1,    1,    7,  1,   11,    1,   4,  5,   4,   11, },
+	{  40000000ULL,  100,   100,    1,    1,   11,  0,    9,    0,   5,  0,  20,   24, },
+	{  33750000ULL,  112,   112,    1,    1,   15,  1,    2,    0,   1,  5,   1,    1, },
+	{  27000000ULL,   90,    90,    1,    1,   15,  0,    9,    0,   5,  0,  20,   24, },
+	{  25175000ULL,   84,    84,    1,    1,   15,  1,  168,    1,  16,  4,   1,    1, },
 };
 
 static const struct reg_sequence rk_hdtpx_common_cmn_init_seq[] = {

-- 
2.51.2



From cristian.ciocaltea at collabora.com  Sun Dec 21 02:36:22 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Sun, 21 Dec 2025 12:36:22 +0200
Subject: [PATCH v2 0/2] Fixup HDMI PLL for phy-rockchip-samsung-hdptx
Message-ID: <20251221-phy-hdptx-pll-fix-v2-0-ae4abf7f75a1@collabora.com>

The Samsung HDMI/eDP TX PHY is currently not able to provide an accurate
enough PLL output frequency to match the TMDS rate of a 1080p at 120Hz
display mode, when used with 10 bpc RGB.

This patch set adds a new entry to the TMDS configuration table,
providing the necessary frequency division coefficients for the PHY PLL
to generate the expected 461.101250 MHz output.

Additionally, it drops a bunch of unused members from struct
ropll_config and makes the configuration table more readable.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
Changes in v2:
- Dropped one more unused member from struct ropll_config (sdm_clk_div)
- Swapped the TMDS config entry corresponding to the 108000000ULL rate
  with 106500000ULL, to fix an unspotted ordering issue
- Collected Tested-by tag from Derek
- Rebased series onto v6.19-rc1
- Link to v1: https://lore.kernel.org/r/20251204-phy-hdptx-pll-fix-v1-0-d94fd6cfd59b at collabora.com

---
Cristian Ciocaltea (2):
      phy: rockchip: samsung-hdptx: Pre-compute HDMI PLL config for 461.10125 MHz output
      phy: rockchip: samsung-hdptx: Cleanup TMDS PLL config table

 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 80 +++++++----------------
 1 file changed, 24 insertions(+), 56 deletions(-)
---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20251204-phy-hdptx-pll-fix-0787c92e0cfe



From cristian.ciocaltea at collabora.com  Sun Dec 21 02:36:23 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Sun, 21 Dec 2025 12:36:23 +0200
Subject: [PATCH v2 1/2] phy: rockchip: samsung-hdptx: Pre-compute HDMI PLL
 config for 461.10125 MHz output
In-Reply-To: <20251221-phy-hdptx-pll-fix-v2-0-ae4abf7f75a1@collabora.com>
References: <20251221-phy-hdptx-pll-fix-v2-0-ae4abf7f75a1@collabora.com>
Message-ID: <20251221-phy-hdptx-pll-fix-v2-1-ae4abf7f75a1@collabora.com>

Attempting to make use of a 1080p at 120Hz display mode with 10 bpc RGB on
my Acer XV275K P3 monitor results in a blank image.  A similar behavior
has been reported on Philips 279M1RV.

The faulty modeline is created by drm_gtf_mode_complex() based on the
following EDID entry from the Standard Timings block:

  GTF:  1920x1080  119.999987 Hz  16:9    138.840 kHz    368.759000 MHz

It's worth noting the computed pixel clock ends up being slightly higher
at 368.881000 MHz.  Nevertheless, this seems to work consistently fine
with 8 bpc RGB.

After switching to 10 bpc, the TMDS character rate expected for the mode
increases to 461.101250 MHz, as per drm_hdmi_compute_mode_clock().

Since there is no entry for this rate in the ropll_tmds_cfg table, the
necessary HDMI PLL configuration parameters are calculated dynamically
by rk_hdptx_phy_clk_pll_calc().  However, the resulting output rate is
not quite a perfect match, i.e. 461.100000 MHz.  That proved to be the
actual root cause of the problem.

Add a new entry to the TMDS configuration table and provide the
necessary frequency division coefficients for the PHY PLL to generate
the expected 461.101250 MHz output.

Fixes: 9d0ec51d7c22 ("phy: rockchip: samsung-hdptx: Add high color depth management")
Tested-by: Derek Foreman <derek.foreman at collabora.com>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index 29de2f7bdae8..cafa618d70fd 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -414,6 +414,8 @@ struct rk_hdptx_phy {
 static const struct ropll_config ropll_tmds_cfg[] = {
 	{ 594000000ULL, 124, 124, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
 	  1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
+	{ 461101250ULL, 97, 97, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 71, 1, 53, 2, 6,
+	  35, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
 	{ 371250000ULL, 155, 155, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
 	  1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
 	{ 297000000ULL, 124, 124, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,

-- 
2.51.2



From cristian.ciocaltea at collabora.com  Sun Dec 21 02:46:47 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Sun, 21 Dec 2025 12:46:47 +0200
Subject: [PATCH v5 00/11] Add HDMI 2.1 FRL support to
 phy-rockchip-samsung-hdptx
Message-ID: <20251221-phy-hdptx-frl-v5-0-dac390a780be@collabora.com>

The Samsung HDMI/eDP Transmitter Combo PHY is capable of handling four
HDMI 2.1 Fixed Rate Link (FRL) lanes, while each lane can operate at
3Gbps, 6Gbps, 8Gbps, 10Gbps or 12Gbps.

This patchset extends the HDMI PHY configuration API to manage the FRL
mode and provides all the required HDMI driver changes to enable FRL in
addition to the already supported TMDS mode.

Also note that since v5 the series depends on the fixes provided by [2].

[1] https://lore.kernel.org/r/20250902-phy-hdptx-fixes-v1-0-e8d9ef9748d6 at collabora.com
[2] https://lore.kernel.org/r/20251221-phy-hdptx-pll-fix-v2-0-ae4abf7f75a1 at collabora.com/

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
Changes in v5:
- Dropped all unused members from struct lcpll_config and improved the
  readability of the rk_hdptx_frl_lcpll_cfg table
- Rebased series onto v6.19-rc1 and replaced dependency [1] with [2]
  (the former got merged)
- Link to v4: https://lore.kernel.org/r/20250902-phy-hdptx-frl-v4-0-7d69176373ce at collabora.com

Changes in v4:
- Moved the following fixup patches into a separate series [1]:
  * Fix reported clock rate in high bpc mode
  * Reduce ROPLL loop bandwidth
  * Prevent Inter-Pair Skew from exceeding the limits
- Renamed enum phy_mode_hdmi to phy_hdmi_mode and
  PHY_MODE_HDMI_{TMDS|FRL} to PHY_HDMI_MODE_{TMDS|FRL} (Dmitry)
- Rebased remaining patches onto next-20250901
- Link to v3: https://lore.kernel.org/r/20250818-phy-hdptx-frl-v3-0-c79997d8bb2b at collabora.com

Changes in v3:
- Reworked patch "phy: hdmi: Add HDMI 2.1 FRL configuration options"
  according to Dmitry's feedback
  * Updated commit message providing a brief description of FRL mode
  * Kept PHY_MODE_HDMI in enum phy_mode and introduced enum
    phy_mode_hdmi defining the TMDS and FRL submodes
- Updated "phy: rockchip: samsung-hdptx: Add HDMI 2.1 FRL support"
  * Implemented .set_mode() callback in rk_hdptx_phy_ops
  * Introduced .mode member in struct rk_hdptx_hdmi_cfg and used it
    instead of phy_get_mode() to verify PHY_MODE_HDMI_FRL
- Rebased series onto next-20250818
- Link to v2: https://lore.kernel.org/r/20250805-phy-hdptx-frl-v2-0-d118bd4b6e0b at collabora.com

Changes in v2:
- Added a couple of new patches:
  * Fix reported clock rate in high bpc mode
  * Drop hw_rate driver data
- Applied several tweaks to the following patches:
  * Compute clk rate from PLL config
  * Switch to driver specific HDMI config
  * Add HDMI 2.1 FRL support
- Rebased series onto next-20250804
- Link to v1: https://lore.kernel.org/r/20250708-phy-hdptx-frl-v1-0-cfe096e224f4 at collabora.com

---
Cristian Ciocaltea (11):
      phy: hdmi: Add HDMI 2.1 FRL configuration options
      phy: rockchip: samsung-hdptx: Use usleep_range() instead of udelay()
      phy: rockchip: samsung-hdptx: Fix coding style alignment
      phy: rockchip: samsung-hdptx: Consistently use [rk_]hdptx_[tmds_] prefixes
      phy: rockchip: samsung-hdptx: Enable lane output in common helper
      phy: rockchip: samsung-hdptx: Cleanup *_cmn_init_seq lists
      phy: rockchip: samsung-hdptx: Compute clk rate from PLL config
      phy: rockchip: samsung-hdptx: Drop hw_rate driver data
      phy: rockchip: samsung-hdptx: Switch to driver specific HDMI config
      phy: rockchip: samsung-hdptx: Extend rk_hdptx_phy_verify_hdmi_config() helper
      phy: rockchip: samsung-hdptx: Add HDMI 2.1 FRL support

 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 666 ++++++++++++++++++----
 include/linux/phy/phy-hdmi.h                      |  19 +-
 2 files changed, 585 insertions(+), 100 deletions(-)
---
base-commit: 3e7f562e20ee87a25e104ef4fce557d39d62fa85
change-id: 20250708-phy-hdptx-frl-fc3377db9f2e
prerequisite-change-id: 20251204-phy-hdptx-pll-fix-0787c92e0cfe:v2
prerequisite-patch-id: 957a51ef580cfd4ae6d9e431a1d7a29c9f87ecc7
prerequisite-patch-id: 0e5e89b08b36a5dc0b204ec4eb654f434b842ec6



From cristian.ciocaltea at collabora.com  Sun Dec 21 02:46:48 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Sun, 21 Dec 2025 12:46:48 +0200
Subject: [PATCH v5 01/11] phy: hdmi: Add HDMI 2.1 FRL configuration options
In-Reply-To: <20251221-phy-hdptx-frl-v5-0-dac390a780be@collabora.com>
References: <20251221-phy-hdptx-frl-v5-0-dac390a780be@collabora.com>
Message-ID: <20251221-phy-hdptx-frl-v5-1-dac390a780be@collabora.com>

The HDMI 2.1 specification introduced the Fixed Rate Link (FRL) mode,
aiming to replace the older Transition-Minimized Differential Signaling
(TMDS) mode used in previous HDMI versions to support much higher
bandwidths (up to 48 Gbps) for modern video and audio formats.

FRL has been designed to support ultra high resolution formats at high
refresh rates like 8K at 60Hz or 4K at 120Hz, and eliminates the need for
dynamic bandwidth adjustments, which reduces latency.  It operates with
3 or 4 lanes at different link rates: 3Gbps, 6Gbps, 8Gbps, 10Gbps or
12Gbps.

Add support for configuring the FRL mode for HDMI PHYs.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 include/linux/phy/phy-hdmi.h | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/include/linux/phy/phy-hdmi.h b/include/linux/phy/phy-hdmi.h
index f0ec963c6e84..d4cf4430ee8f 100644
--- a/include/linux/phy/phy-hdmi.h
+++ b/include/linux/phy/phy-hdmi.h
@@ -6,16 +6,31 @@
 #ifndef __PHY_HDMI_H_
 #define __PHY_HDMI_H_
 
+#include <linux/types.h>
+
+enum phy_hdmi_mode {
+	PHY_HDMI_MODE_TMDS,
+	PHY_HDMI_MODE_FRL,
+};
+
 /**
  * struct phy_configure_opts_hdmi - HDMI configuration set
- * @tmds_char_rate: HDMI TMDS Character Rate in Hertz.
  * @bpc: Bits per color channel.
+ * @tmds_char_rate: HDMI TMDS Character Rate in Hertz.
+ * @frl.rate_per_lane: HDMI FRL Rate per Lane in Gbps.
+ * @frl.lanes: HDMI FRL lanes count.
  *
  * This structure is used to represent the configuration state of a HDMI phy.
  */
 struct phy_configure_opts_hdmi {
-	unsigned long long tmds_char_rate;
 	unsigned int bpc;
+	union {
+		unsigned long long tmds_char_rate;
+		struct {
+			u8 rate_per_lane;
+			u8 lanes;
+		} frl;
+	};
 };
 
 #endif /* __PHY_HDMI_H_ */

-- 
2.51.2



From cristian.ciocaltea at collabora.com  Sun Dec 21 02:46:49 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Sun, 21 Dec 2025 12:46:49 +0200
Subject: [PATCH v5 02/11] phy: rockchip: samsung-hdptx: Use usleep_range()
 instead of udelay()
In-Reply-To: <20251221-phy-hdptx-frl-v5-0-dac390a780be@collabora.com>
References: <20251221-phy-hdptx-frl-v5-0-dac390a780be@collabora.com>
Message-ID: <20251221-phy-hdptx-frl-v5-2-dac390a780be@collabora.com>

rk_hdptx_dp_reset() is allowed to sleep, hence replace the busy waiting
with usleep_range(), to allow other threads to run.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index e3d817e81d6d..a6981b222c8b 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -1042,7 +1042,7 @@ static void rk_hdptx_dp_reset(struct rk_hdptx_phy *hdptx)
 	reset_control_assert(hdptx->rsts[RST_INIT].rstc);
 
 	reset_control_assert(hdptx->rsts[RST_APB].rstc);
-	udelay(10);
+	usleep_range(10, 15);
 	reset_control_deassert(hdptx->rsts[RST_APB].rstc);
 
 	regmap_update_bits(hdptx->regmap, LANE_REG(0301),

-- 
2.51.2



From cristian.ciocaltea at collabora.com  Sun Dec 21 02:46:50 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Sun, 21 Dec 2025 12:46:50 +0200
Subject: [PATCH v5 03/11] phy: rockchip: samsung-hdptx: Fix coding style
 alignment
In-Reply-To: <20251221-phy-hdptx-frl-v5-0-dac390a780be@collabora.com>
References: <20251221-phy-hdptx-frl-v5-0-dac390a780be@collabora.com>
Message-ID: <20251221-phy-hdptx-frl-v5-3-dac390a780be@collabora.com>

Handle a bunch of reported checkpatch.pl complaints:

  CHECK: Alignment should match open parenthesis

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index a6981b222c8b..b2c9df761861 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -1624,11 +1624,11 @@ static void rk_hdptx_phy_set_voltage(struct rk_hdptx_phy *hdptx,
 		regmap_update_bits(hdptx->regmap, LANE_REG(030a) + offset,
 				   LN_TX_JEQ_EVEN_CTRL_RBR_MASK,
 				   FIELD_PREP(LN_TX_JEQ_EVEN_CTRL_RBR_MASK,
-				   ctrl->tx_jeq_even_ctrl));
+					      ctrl->tx_jeq_even_ctrl));
 		regmap_update_bits(hdptx->regmap, LANE_REG(030c) + offset,
 				   LN_TX_JEQ_ODD_CTRL_RBR_MASK,
 				   FIELD_PREP(LN_TX_JEQ_ODD_CTRL_RBR_MASK,
-				   ctrl->tx_jeq_odd_ctrl));
+					      ctrl->tx_jeq_odd_ctrl));
 		regmap_update_bits(hdptx->regmap, LANE_REG(0311) + offset,
 				   LN_TX_SER_40BIT_EN_RBR_MASK,
 				   FIELD_PREP(LN_TX_SER_40BIT_EN_RBR_MASK, 0x1));
@@ -1638,11 +1638,11 @@ static void rk_hdptx_phy_set_voltage(struct rk_hdptx_phy *hdptx,
 		regmap_update_bits(hdptx->regmap, LANE_REG(030b) + offset,
 				   LN_TX_JEQ_EVEN_CTRL_HBR_MASK,
 				   FIELD_PREP(LN_TX_JEQ_EVEN_CTRL_HBR_MASK,
-				   ctrl->tx_jeq_even_ctrl));
+					      ctrl->tx_jeq_even_ctrl));
 		regmap_update_bits(hdptx->regmap, LANE_REG(030d) + offset,
 				   LN_TX_JEQ_ODD_CTRL_HBR_MASK,
 				   FIELD_PREP(LN_TX_JEQ_ODD_CTRL_HBR_MASK,
-				   ctrl->tx_jeq_odd_ctrl));
+					      ctrl->tx_jeq_odd_ctrl));
 		regmap_update_bits(hdptx->regmap, LANE_REG(0311) + offset,
 				   LN_TX_SER_40BIT_EN_HBR_MASK,
 				   FIELD_PREP(LN_TX_SER_40BIT_EN_HBR_MASK, 0x1));
@@ -1653,11 +1653,11 @@ static void rk_hdptx_phy_set_voltage(struct rk_hdptx_phy *hdptx,
 		regmap_update_bits(hdptx->regmap, LANE_REG(030b) + offset,
 				   LN_TX_JEQ_EVEN_CTRL_HBR2_MASK,
 				   FIELD_PREP(LN_TX_JEQ_EVEN_CTRL_HBR2_MASK,
-				   ctrl->tx_jeq_even_ctrl));
+					      ctrl->tx_jeq_even_ctrl));
 		regmap_update_bits(hdptx->regmap, LANE_REG(030d) + offset,
 				   LN_TX_JEQ_ODD_CTRL_HBR2_MASK,
 				   FIELD_PREP(LN_TX_JEQ_ODD_CTRL_HBR2_MASK,
-				   ctrl->tx_jeq_odd_ctrl));
+					      ctrl->tx_jeq_odd_ctrl));
 		regmap_update_bits(hdptx->regmap, LANE_REG(0311) + offset,
 				   LN_TX_SER_40BIT_EN_HBR2_MASK,
 				   FIELD_PREP(LN_TX_SER_40BIT_EN_HBR2_MASK, 0x1));

-- 
2.51.2



From cristian.ciocaltea at collabora.com  Sun Dec 21 02:46:51 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Sun, 21 Dec 2025 12:46:51 +0200
Subject: [PATCH v5 04/11] phy: rockchip: samsung-hdptx: Consistently use
 [rk_]hdptx_[tmds_] prefixes
In-Reply-To: <20251221-phy-hdptx-frl-v5-0-dac390a780be@collabora.com>
References: <20251221-phy-hdptx-frl-v5-0-dac390a780be@collabora.com>
Message-ID: <20251221-phy-hdptx-frl-v5-4-dac390a780be@collabora.com>

Fix the naming inconsistencies for some of the functions and global
variables:

* Add the missing 'rk_hdptx_' prefix to ropll_tmds_cfg variable
* Replace '_ropll_tmds_' with '_tmds_ropll_' globally
* Replace 'hdtpx' with 'hdptx' globally

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 62 +++++++++++------------
 1 file changed, 31 insertions(+), 31 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index b2c9df761861..ac315061b6ee 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -32,17 +32,17 @@
 #define HDPTX_O_PHY_RDY			BIT(1)
 #define HDPTX_O_SB_RDY			BIT(0)
 
-#define HDTPX_REG(_n, _min, _max)				\
+#define HDPTX_REG(_n, _min, _max)				\
 	(							\
 		BUILD_BUG_ON_ZERO((0x##_n) < (0x##_min)) +	\
 		BUILD_BUG_ON_ZERO((0x##_n) > (0x##_max)) +	\
 		((0x##_n) * 4)					\
 	)
 
-#define CMN_REG(n)			HDTPX_REG(n, 0000, 00a7)
-#define SB_REG(n)			HDTPX_REG(n, 0100, 0129)
-#define LNTOP_REG(n)			HDTPX_REG(n, 0200, 0229)
-#define LANE_REG(n)			HDTPX_REG(n, 0300, 062d)
+#define CMN_REG(n)			HDPTX_REG(n, 0000, 00a7)
+#define SB_REG(n)			HDPTX_REG(n, 0100, 0129)
+#define LNTOP_REG(n)			HDPTX_REG(n, 0200, 0229)
+#define LANE_REG(n)			HDPTX_REG(n, 0300, 062d)
 
 /* CMN_REG(0008) */
 #define OVRD_LCPLL_EN_MASK		BIT(7)
@@ -397,7 +397,7 @@ struct rk_hdptx_phy {
 	unsigned int lanes;
 };
 
-static const struct ropll_config ropll_tmds_cfg[] = {
+static const struct ropll_config rk_hdptx_tmds_ropll_cfg[] = {
 	/*             |              pms             |        sdm         |     sdc     | */
 	/*        rate, mdiv, mdafc, pdiv, rdiv, sdiv, en, deno, nsig, num,  n, num, deno, */
 	{ 594000000ULL,  124,   124,    1,    1,    0,  1,   62,    1,  16,  5,   0,    1, },
@@ -424,7 +424,7 @@ static const struct ropll_config ropll_tmds_cfg[] = {
 	{  25175000ULL,   84,    84,    1,    1,   15,  1,  168,    1,  16,  4,   1,    1, },
 };
 
-static const struct reg_sequence rk_hdtpx_common_cmn_init_seq[] = {
+static const struct reg_sequence rk_hdptx_common_cmn_init_seq[] = {
 	REG_SEQ0(CMN_REG(0009), 0x0c),
 	REG_SEQ0(CMN_REG(000a), 0x83),
 	REG_SEQ0(CMN_REG(000b), 0x06),
@@ -514,7 +514,7 @@ static const struct reg_sequence rk_hdtpx_common_cmn_init_seq[] = {
 	REG_SEQ0(CMN_REG(009b), 0x10),
 };
 
-static const struct reg_sequence rk_hdtpx_tmds_cmn_init_seq[] = {
+static const struct reg_sequence rk_hdptx_tmds_cmn_init_seq[] = {
 	REG_SEQ0(CMN_REG(0008), 0x00),
 	REG_SEQ0(CMN_REG(0011), 0x01),
 	REG_SEQ0(CMN_REG(0017), 0x20),
@@ -556,14 +556,14 @@ static const struct reg_sequence rk_hdtpx_tmds_cmn_init_seq[] = {
 	REG_SEQ0(CMN_REG(009b), 0x00),
 };
 
-static const struct reg_sequence rk_hdtpx_common_sb_init_seq[] = {
+static const struct reg_sequence rk_hdptx_common_sb_init_seq[] = {
 	REG_SEQ0(SB_REG(0114), 0x00),
 	REG_SEQ0(SB_REG(0115), 0x00),
 	REG_SEQ0(SB_REG(0116), 0x00),
 	REG_SEQ0(SB_REG(0117), 0x00),
 };
 
-static const struct reg_sequence rk_hdtpx_tmds_lntop_highbr_seq[] = {
+static const struct reg_sequence rk_hdptx_tmds_lntop_highbr_seq[] = {
 	REG_SEQ0(LNTOP_REG(0201), 0x00),
 	REG_SEQ0(LNTOP_REG(0202), 0x00),
 	REG_SEQ0(LNTOP_REG(0203), 0x0f),
@@ -571,7 +571,7 @@ static const struct reg_sequence rk_hdtpx_tmds_lntop_highbr_seq[] = {
 	REG_SEQ0(LNTOP_REG(0205), 0xff),
 };
 
-static const struct reg_sequence rk_hdtpx_tmds_lntop_lowbr_seq[] = {
+static const struct reg_sequence rk_hdptx_tmds_lntop_lowbr_seq[] = {
 	REG_SEQ0(LNTOP_REG(0201), 0x07),
 	REG_SEQ0(LNTOP_REG(0202), 0xc1),
 	REG_SEQ0(LNTOP_REG(0203), 0xf0),
@@ -579,7 +579,7 @@ static const struct reg_sequence rk_hdtpx_tmds_lntop_lowbr_seq[] = {
 	REG_SEQ0(LNTOP_REG(0205), 0x1f),
 };
 
-static const struct reg_sequence rk_hdtpx_common_lane_init_seq[] = {
+static const struct reg_sequence rk_hdptx_common_lane_init_seq[] = {
 	REG_SEQ0(LANE_REG(0303), 0x0c),
 	REG_SEQ0(LANE_REG(0307), 0x20),
 	REG_SEQ0(LANE_REG(030a), 0x17),
@@ -634,7 +634,7 @@ static const struct reg_sequence rk_hdtpx_common_lane_init_seq[] = {
 	REG_SEQ0(LANE_REG(0620), 0xa0),
 };
 
-static const struct reg_sequence rk_hdtpx_tmds_lane_init_seq[] = {
+static const struct reg_sequence rk_hdptx_tmds_lane_init_seq[] = {
 	REG_SEQ0(LANE_REG(0312), 0x00),
 	REG_SEQ0(LANE_REG(0412), 0x00),
 	REG_SEQ0(LANE_REG(0512), 0x00),
@@ -938,7 +938,7 @@ static bool rk_hdptx_phy_clk_pll_calc(unsigned long long rate,
 	return true;
 }
 
-static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx)
+static int rk_hdptx_tmds_ropll_cmn_config(struct rk_hdptx_phy *hdptx)
 {
 	const struct ropll_config *cfg = NULL;
 	struct ropll_config rc = {0};
@@ -947,9 +947,9 @@ static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx)
 	if (!hdptx->hdmi_cfg.tmds_char_rate)
 		return 0;
 
-	for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++)
-		if (hdptx->hdmi_cfg.tmds_char_rate == ropll_tmds_cfg[i].rate) {
-			cfg = &ropll_tmds_cfg[i];
+	for (i = 0; i < ARRAY_SIZE(rk_hdptx_tmds_ropll_cfg); i++)
+		if (hdptx->hdmi_cfg.tmds_char_rate == rk_hdptx_tmds_ropll_cfg[i].rate) {
+			cfg = &rk_hdptx_tmds_ropll_cfg[i];
 			break;
 		}
 
@@ -969,8 +969,8 @@ static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx)
 
 	rk_hdptx_pre_power_up(hdptx);
 
-	rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_cmn_init_seq);
-	rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_cmn_init_seq);
+	rk_hdptx_multi_reg_write(hdptx, rk_hdptx_common_cmn_init_seq);
+	rk_hdptx_multi_reg_write(hdptx, rk_hdptx_tmds_cmn_init_seq);
 
 	regmap_write(hdptx->regmap, CMN_REG(0051), cfg->pms_mdiv);
 	regmap_write(hdptx->regmap, CMN_REG(0055), cfg->pms_mdiv_afc);
@@ -1012,25 +1012,25 @@ static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx)
 	return ret;
 }
 
-static int rk_hdptx_ropll_tmds_mode_config(struct rk_hdptx_phy *hdptx)
+static int rk_hdptx_tmds_ropll_mode_config(struct rk_hdptx_phy *hdptx)
 {
-	rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_sb_init_seq);
+	rk_hdptx_multi_reg_write(hdptx, rk_hdptx_common_sb_init_seq);
 
 	regmap_write(hdptx->regmap, LNTOP_REG(0200), 0x06);
 
 	if (hdptx->hdmi_cfg.tmds_char_rate > HDMI14_MAX_RATE) {
 		/* For 1/40 bitrate clk */
-		rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_lntop_highbr_seq);
+		rk_hdptx_multi_reg_write(hdptx, rk_hdptx_tmds_lntop_highbr_seq);
 	} else {
 		/* For 1/10 bitrate clk */
-		rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_lntop_lowbr_seq);
+		rk_hdptx_multi_reg_write(hdptx, rk_hdptx_tmds_lntop_lowbr_seq);
 	}
 
 	regmap_write(hdptx->regmap, LNTOP_REG(0206), 0x07);
 	regmap_write(hdptx->regmap, LNTOP_REG(0207), 0x0f);
 
-	rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_lane_init_seq);
-	rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_lane_init_seq);
+	rk_hdptx_multi_reg_write(hdptx, rk_hdptx_common_lane_init_seq);
+	rk_hdptx_multi_reg_write(hdptx, rk_hdptx_tmds_lane_init_seq);
 
 	return rk_hdptx_post_enable_lane(hdptx);
 }
@@ -1089,7 +1089,7 @@ static int rk_hdptx_phy_consumer_get(struct rk_hdptx_phy *hdptx)
 	if (mode == PHY_MODE_DP) {
 		rk_hdptx_dp_reset(hdptx);
 	} else {
-		ret = rk_hdptx_ropll_tmds_cmn_config(hdptx);
+		ret = rk_hdptx_tmds_ropll_cmn_config(hdptx);
 		if (ret)
 			goto dec_usage;
 	}
@@ -1436,7 +1436,7 @@ static int rk_hdptx_phy_power_on(struct phy *phy)
 		regmap_write(hdptx->grf, GRF_HDPTX_CON0,
 			     HDPTX_MODE_SEL << 16 | FIELD_PREP(HDPTX_MODE_SEL, 0x0));
 
-		ret = rk_hdptx_ropll_tmds_mode_config(hdptx);
+		ret = rk_hdptx_tmds_ropll_mode_config(hdptx);
 		if (ret)
 			rk_hdptx_phy_consumer_put(hdptx, true);
 	}
@@ -1459,11 +1459,11 @@ static int rk_hdptx_phy_verify_hdmi_config(struct rk_hdptx_phy *hdptx,
 	if (!hdmi->tmds_char_rate || hdmi->tmds_char_rate > HDMI20_MAX_RATE)
 		return -EINVAL;
 
-	for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++)
-		if (hdmi->tmds_char_rate == ropll_tmds_cfg[i].rate)
+	for (i = 0; i < ARRAY_SIZE(rk_hdptx_tmds_ropll_cfg); i++)
+		if (hdmi->tmds_char_rate == rk_hdptx_tmds_ropll_cfg[i].rate)
 			break;
 
-	if (i == ARRAY_SIZE(ropll_tmds_cfg) &&
+	if (i == ARRAY_SIZE(rk_hdptx_tmds_ropll_cfg) &&
 	    !rk_hdptx_phy_clk_pll_calc(hdmi->tmds_char_rate, NULL))
 		return -EINVAL;
 
@@ -1888,7 +1888,7 @@ static int rk_hdptx_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate,
 	 * while the latter being executed only once, i.e. when clock remains
 	 * in the prepared state during rate changes.
 	 */
-	return rk_hdptx_ropll_tmds_cmn_config(hdptx);
+	return rk_hdptx_tmds_ropll_cmn_config(hdptx);
 }
 
 static const struct clk_ops hdptx_phy_clk_ops = {

-- 
2.51.2



From cristian.ciocaltea at collabora.com  Sun Dec 21 02:46:52 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Sun, 21 Dec 2025 12:46:52 +0200
Subject: [PATCH v5 05/11] phy: rockchip: samsung-hdptx: Enable lane output
 in common helper
In-Reply-To: <20251221-phy-hdptx-frl-v5-0-dac390a780be@collabora.com>
References: <20251221-phy-hdptx-frl-v5-0-dac390a780be@collabora.com>
Message-ID: <20251221-phy-hdptx-frl-v5-5-dac390a780be@collabora.com>

In preparation to support FRL mode, move the PHY lane output enablement
from the TMDS specific configuration to the common *_post_enable_lane()
helper and make sure it gets turned off in *_phy_disable().

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index ac315061b6ee..7e5e0332f3bf 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -797,6 +797,8 @@ static int rk_hdptx_post_enable_lane(struct rk_hdptx_phy *hdptx)
 	       HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN;
 	regmap_write(hdptx->grf, GRF_HDPTX_CON0, val);
 
+	regmap_write(hdptx->regmap, LNTOP_REG(0207), 0x0f);
+
 	ret = regmap_read_poll_timeout(hdptx->grf, GRF_HDPTX_STATUS, val,
 				       (val & HDPTX_O_PHY_RDY) &&
 				       (val & HDPTX_O_PLL_LOCK_DONE),
@@ -850,6 +852,7 @@ static void rk_hdptx_phy_disable(struct rk_hdptx_phy *hdptx)
 	usleep_range(20, 30);
 	reset_control_deassert(hdptx->rsts[RST_APB].rstc);
 
+	regmap_write(hdptx->regmap, LNTOP_REG(0207), 0x0);
 	regmap_write(hdptx->regmap, LANE_REG(0300), 0x82);
 	regmap_write(hdptx->regmap, SB_REG(010f), 0xc1);
 	regmap_write(hdptx->regmap, SB_REG(0110), 0x1);
@@ -1027,7 +1030,6 @@ static int rk_hdptx_tmds_ropll_mode_config(struct rk_hdptx_phy *hdptx)
 	}
 
 	regmap_write(hdptx->regmap, LNTOP_REG(0206), 0x07);
-	regmap_write(hdptx->regmap, LNTOP_REG(0207), 0x0f);
 
 	rk_hdptx_multi_reg_write(hdptx, rk_hdptx_common_lane_init_seq);
 	rk_hdptx_multi_reg_write(hdptx, rk_hdptx_tmds_lane_init_seq);

-- 
2.51.2



From cristian.ciocaltea at collabora.com  Sun Dec 21 02:46:53 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Sun, 21 Dec 2025 12:46:53 +0200
Subject: [PATCH v5 06/11] phy: rockchip: samsung-hdptx: Cleanup
 *_cmn_init_seq lists
In-Reply-To: <20251221-phy-hdptx-frl-v5-0-dac390a780be@collabora.com>
References: <20251221-phy-hdptx-frl-v5-0-dac390a780be@collabora.com>
Message-ID: <20251221-phy-hdptx-frl-v5-6-dac390a780be@collabora.com>

Drop redundant reg_sequence entries from rk_hdptx_common_cmn_init_seq[],
i.e. those that are either duplicated or overridden in
rk_hdptx_tmds_cmn_init_seq[].

Additionally, a few items do not really belong to the former, hence move
them to the latter.  That's mostly a preparatory step for adding FRL
support.

No functional changes intended at this point.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 22 ++++------------------
 1 file changed, 4 insertions(+), 18 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index 7e5e0332f3bf..42f0ac5a74b1 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -433,13 +433,11 @@ static const struct reg_sequence rk_hdptx_common_cmn_init_seq[] = {
 	REG_SEQ0(CMN_REG(000e), 0x0f),
 	REG_SEQ0(CMN_REG(000f), 0x0f),
 	REG_SEQ0(CMN_REG(0010), 0x04),
-	REG_SEQ0(CMN_REG(0011), 0x00),
 	REG_SEQ0(CMN_REG(0012), 0x26),
 	REG_SEQ0(CMN_REG(0013), 0x22),
 	REG_SEQ0(CMN_REG(0014), 0x24),
 	REG_SEQ0(CMN_REG(0015), 0x77),
 	REG_SEQ0(CMN_REG(0016), 0x08),
-	REG_SEQ0(CMN_REG(0017), 0x00),
 	REG_SEQ0(CMN_REG(0018), 0x04),
 	REG_SEQ0(CMN_REG(0019), 0x48),
 	REG_SEQ0(CMN_REG(001a), 0x01),
@@ -447,13 +445,7 @@ static const struct reg_sequence rk_hdptx_common_cmn_init_seq[] = {
 	REG_SEQ0(CMN_REG(001c), 0x01),
 	REG_SEQ0(CMN_REG(001d), 0x64),
 	REG_SEQ0(CMN_REG(001f), 0x00),
-	REG_SEQ0(CMN_REG(0026), 0x53),
 	REG_SEQ0(CMN_REG(0029), 0x01),
-	REG_SEQ0(CMN_REG(0030), 0x00),
-	REG_SEQ0(CMN_REG(0031), 0x20),
-	REG_SEQ0(CMN_REG(0032), 0x30),
-	REG_SEQ0(CMN_REG(0033), 0x0b),
-	REG_SEQ0(CMN_REG(0034), 0x23),
 	REG_SEQ0(CMN_REG(0035), 0x00),
 	REG_SEQ0(CMN_REG(0038), 0x00),
 	REG_SEQ0(CMN_REG(0039), 0x00),
@@ -464,7 +456,6 @@ static const struct reg_sequence rk_hdptx_common_cmn_init_seq[] = {
 	REG_SEQ0(CMN_REG(003f), 0x83),
 	REG_SEQ0(CMN_REG(0040), 0x06),
 	REG_SEQ0(CMN_REG(0041), 0x20),
-	REG_SEQ0(CMN_REG(0042), 0xb8),
 	REG_SEQ0(CMN_REG(0043), 0x00),
 	REG_SEQ0(CMN_REG(0044), 0x46),
 	REG_SEQ0(CMN_REG(0045), 0x24),
@@ -474,14 +465,9 @@ static const struct reg_sequence rk_hdptx_common_cmn_init_seq[] = {
 	REG_SEQ0(CMN_REG(004b), 0x00),
 	REG_SEQ0(CMN_REG(004c), 0x01),
 	REG_SEQ0(CMN_REG(004d), 0x64),
-	REG_SEQ0(CMN_REG(004e), 0x14),
 	REG_SEQ0(CMN_REG(004f), 0x00),
 	REG_SEQ0(CMN_REG(0050), 0x00),
-	REG_SEQ0(CMN_REG(005d), 0x0c),
 	REG_SEQ0(CMN_REG(005f), 0x01),
-	REG_SEQ0(CMN_REG(006b), 0x04),
-	REG_SEQ0(CMN_REG(0073), 0x30),
-	REG_SEQ0(CMN_REG(0074), 0x00),
 	REG_SEQ0(CMN_REG(0075), 0x20),
 	REG_SEQ0(CMN_REG(0076), 0x30),
 	REG_SEQ0(CMN_REG(0077), 0x08),
@@ -493,13 +479,10 @@ static const struct reg_sequence rk_hdptx_common_cmn_init_seq[] = {
 	REG_SEQ0(CMN_REG(007e), 0x00),
 	REG_SEQ0(CMN_REG(007f), 0x00),
 	REG_SEQ0(CMN_REG(0080), 0x00),
-	REG_SEQ0(CMN_REG(0081), 0x09),
 	REG_SEQ0(CMN_REG(0082), 0x04),
 	REG_SEQ0(CMN_REG(0083), 0x24),
 	REG_SEQ0(CMN_REG(0084), 0x20),
 	REG_SEQ0(CMN_REG(0085), 0x03),
-	REG_SEQ0(CMN_REG(0086), 0x01),
-	REG_SEQ0(CMN_REG(0087), 0x0c),
 	REG_SEQ0(CMN_REG(008a), 0x55),
 	REG_SEQ0(CMN_REG(008b), 0x25),
 	REG_SEQ0(CMN_REG(008c), 0x2c),
@@ -511,7 +494,6 @@ static const struct reg_sequence rk_hdptx_common_cmn_init_seq[] = {
 	REG_SEQ0(CMN_REG(0092), 0x00),
 	REG_SEQ0(CMN_REG(0093), 0x00),
 	REG_SEQ0(CMN_REG(009a), 0x11),
-	REG_SEQ0(CMN_REG(009b), 0x10),
 };
 
 static const struct reg_sequence rk_hdptx_tmds_cmn_init_seq[] = {
@@ -545,9 +527,13 @@ static const struct reg_sequence rk_hdptx_tmds_cmn_init_seq[] = {
 	REG_SEQ0(CMN_REG(0048), 0x11),
 	REG_SEQ0(CMN_REG(004e), 0x34),
 	REG_SEQ0(CMN_REG(005c), 0x25),
+	REG_SEQ0(CMN_REG(005d), 0x0c),
 	REG_SEQ0(CMN_REG(005e), 0x4f),
+	REG_SEQ0(CMN_REG(006b), 0x04),
+	REG_SEQ0(CMN_REG(0073), 0x30),
 	REG_SEQ0(CMN_REG(0074), 0x04),
 	REG_SEQ0(CMN_REG(0081), 0x01),
+	REG_SEQ0(CMN_REG(0086), 0x01),
 	REG_SEQ0(CMN_REG(0087), 0x04),
 	REG_SEQ0(CMN_REG(0089), 0x00),
 	REG_SEQ0(CMN_REG(0095), 0x00),

-- 
2.51.2



From cristian.ciocaltea at collabora.com  Sun Dec 21 02:46:55 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Sun, 21 Dec 2025 12:46:55 +0200
Subject: [PATCH v5 08/11] phy: rockchip: samsung-hdptx: Drop hw_rate driver
 data
In-Reply-To: <20251221-phy-hdptx-frl-v5-0-dac390a780be@collabora.com>
References: <20251221-phy-hdptx-frl-v5-0-dac390a780be@collabora.com>
Message-ID: <20251221-phy-hdptx-frl-v5-8-dac390a780be@collabora.com>

The ->hw_rate member of struct rk_hdptx_phy was mainly used to keep
track of the clock rate programmed in hardware and support implementing
the ->recalc_rate() callback in hdptx_phy_clk_ops.

Computing the clock rate from the actual PHY PLL configuration seems to
work reliably, hence remove the now redundant struct member.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 13 ++-----------
 1 file changed, 2 insertions(+), 11 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index c2d2f2468ba2..5a534c53a52d 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -387,7 +387,6 @@ struct rk_hdptx_phy {
 
 	/* clk provider */
 	struct clk_hw hw;
-	unsigned long hw_rate;
 	bool restrict_rate_change;
 
 	atomic_t usage_count;
@@ -931,7 +930,7 @@ static int rk_hdptx_tmds_ropll_cmn_config(struct rk_hdptx_phy *hdptx)
 {
 	const struct ropll_config *cfg = NULL;
 	struct ropll_config rc = {0};
-	int ret, i;
+	int i;
 
 	if (!hdptx->hdmi_cfg.tmds_char_rate)
 		return 0;
@@ -993,12 +992,7 @@ static int rk_hdptx_tmds_ropll_cmn_config(struct rk_hdptx_phy *hdptx)
 	regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_CLK_EN_MASK,
 			   FIELD_PREP(PLL_PCG_CLK_EN_MASK, 0x1));
 
-	ret = rk_hdptx_post_enable_pll(hdptx);
-	if (!ret)
-		hdptx->hw_rate = DIV_ROUND_CLOSEST_ULL(hdptx->hdmi_cfg.tmds_char_rate * 8,
-						       hdptx->hdmi_cfg.bpc);
-
-	return ret;
+	return rk_hdptx_post_enable_pll(hdptx);
 }
 
 static int rk_hdptx_tmds_ropll_mode_config(struct rk_hdptx_phy *hdptx)
@@ -1903,9 +1897,6 @@ static unsigned long rk_hdptx_phy_clk_recalc_rate(struct clk_hw *hw,
 	u64 rate;
 	int ret;
 
-	if (hdptx->hw_rate)
-		return hdptx->hw_rate;
-
 	ret = regmap_read(hdptx->grf, GRF_HDPTX_CON0, &status);
 	if (ret || !(status & HDPTX_I_PLL_EN))
 		return 0;

-- 
2.51.2



From cristian.ciocaltea at collabora.com  Sun Dec 21 02:46:56 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Sun, 21 Dec 2025 12:46:56 +0200
Subject: [PATCH v5 09/11] phy: rockchip: samsung-hdptx: Switch to driver
 specific HDMI config
In-Reply-To: <20251221-phy-hdptx-frl-v5-0-dac390a780be@collabora.com>
References: <20251221-phy-hdptx-frl-v5-0-dac390a780be@collabora.com>
Message-ID: <20251221-phy-hdptx-frl-v5-9-dac390a780be@collabora.com>

In preparation to support the FRL operation mode which gets configured
via the lanes and rate per lane tuple, switch to a driver specific
struct for configuring the link rate and bpc.

This simplifies and optimizes the implementation by allowing implicit
switches between TMDS and FRL rates, without requiring additional checks
of the active PHY mode followed by recalculations of the link rate when
operating in FRL mode.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 44 +++++++++++++----------
 1 file changed, 25 insertions(+), 19 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index 5a534c53a52d..3bec69058f7b 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -373,6 +373,11 @@ struct rk_hdptx_phy_cfg {
 	unsigned int phy_ids[MAX_HDPTX_PHY_NUM];
 };
 
+struct rk_hdptx_hdmi_cfg {
+	unsigned long long rate;
+	unsigned int bpc;
+};
+
 struct rk_hdptx_phy {
 	struct device *dev;
 	struct regmap *regmap;
@@ -380,7 +385,7 @@ struct rk_hdptx_phy {
 
 	int phy_id;
 	struct phy *phy;
-	struct phy_configure_opts_hdmi hdmi_cfg;
+	struct rk_hdptx_hdmi_cfg hdmi_cfg;
 	struct clk_bulk_data *clks;
 	int nr_clks;
 	struct reset_control_bulk_data rsts[RST_MAX];
@@ -932,19 +937,19 @@ static int rk_hdptx_tmds_ropll_cmn_config(struct rk_hdptx_phy *hdptx)
 	struct ropll_config rc = {0};
 	int i;
 
-	if (!hdptx->hdmi_cfg.tmds_char_rate)
+	if (!hdptx->hdmi_cfg.rate)
 		return 0;
 
 	for (i = 0; i < ARRAY_SIZE(rk_hdptx_tmds_ropll_cfg); i++)
-		if (hdptx->hdmi_cfg.tmds_char_rate == rk_hdptx_tmds_ropll_cfg[i].rate) {
+		if (hdptx->hdmi_cfg.rate == rk_hdptx_tmds_ropll_cfg[i].rate) {
 			cfg = &rk_hdptx_tmds_ropll_cfg[i];
 			break;
 		}
 
 	if (!cfg) {
-		if (!rk_hdptx_phy_clk_pll_calc(hdptx->hdmi_cfg.tmds_char_rate, &rc)) {
+		if (!rk_hdptx_phy_clk_pll_calc(hdptx->hdmi_cfg.rate, &rc)) {
 			dev_err(hdptx->dev, "%s cannot find pll cfg for rate=%llu\n",
-				__func__, hdptx->hdmi_cfg.tmds_char_rate);
+				__func__, hdptx->hdmi_cfg.rate);
 			return -EINVAL;
 		}
 
@@ -952,7 +957,7 @@ static int rk_hdptx_tmds_ropll_cmn_config(struct rk_hdptx_phy *hdptx)
 	}
 
 	dev_dbg(hdptx->dev, "%s rate=%llu mdiv=%u sdiv=%u sdm_en=%u k_sign=%u k=%u lc=%u\n",
-		__func__, hdptx->hdmi_cfg.tmds_char_rate, cfg->pms_mdiv, cfg->pms_sdiv + 1,
+		__func__, hdptx->hdmi_cfg.rate, cfg->pms_mdiv, cfg->pms_sdiv + 1,
 		cfg->sdm_en, cfg->sdm_num_sign, cfg->sdm_num, cfg->sdm_deno);
 
 	rk_hdptx_pre_power_up(hdptx);
@@ -1001,7 +1006,7 @@ static int rk_hdptx_tmds_ropll_mode_config(struct rk_hdptx_phy *hdptx)
 
 	regmap_write(hdptx->regmap, LNTOP_REG(0200), 0x06);
 
-	if (hdptx->hdmi_cfg.tmds_char_rate > HDMI14_MAX_RATE) {
+	if (hdptx->hdmi_cfg.rate > HDMI14_MAX_RATE) {
 		/* For 1/40 bitrate clk */
 		rk_hdptx_multi_reg_write(hdptx, rk_hdptx_tmds_lntop_highbr_seq);
 	} else {
@@ -1372,19 +1377,19 @@ static int rk_hdptx_phy_power_on(struct phy *phy)
 	int ret, lane;
 
 	if (mode != PHY_MODE_DP) {
-		if (!hdptx->hdmi_cfg.tmds_char_rate) {
+		if (!hdptx->hdmi_cfg.rate) {
 			/*
 			 * FIXME: Temporary workaround to setup TMDS char rate
 			 * from the RK DW HDMI QP bridge driver.
 			 * Will be removed as soon the switch to the HDMI PHY
 			 * configuration API has been completed on both ends.
 			 */
-			hdptx->hdmi_cfg.tmds_char_rate = phy_get_bus_width(hdptx->phy) & 0xfffffff;
-			hdptx->hdmi_cfg.tmds_char_rate *= 100;
+			hdptx->hdmi_cfg.rate = phy_get_bus_width(hdptx->phy) & 0xfffffff;
+			hdptx->hdmi_cfg.rate *= 100;
 		}
 
 		dev_dbg(hdptx->dev, "%s rate=%llu bpc=%u\n", __func__,
-			hdptx->hdmi_cfg.tmds_char_rate, hdptx->hdmi_cfg.bpc);
+			hdptx->hdmi_cfg.rate, hdptx->hdmi_cfg.bpc);
 	}
 
 	ret = rk_hdptx_phy_consumer_get(hdptx);
@@ -1731,12 +1736,13 @@ static int rk_hdptx_phy_configure(struct phy *phy, union phy_configure_opts *opt
 		if (ret) {
 			dev_err(hdptx->dev, "invalid hdmi params for phy configure\n");
 		} else {
-			hdptx->hdmi_cfg = opts->hdmi;
+			hdptx->hdmi_cfg.rate = opts->hdmi.tmds_char_rate;
+			hdptx->hdmi_cfg.bpc = opts->hdmi.bpc;
 			hdptx->restrict_rate_change = true;
 		}
 
 		dev_dbg(hdptx->dev, "%s rate=%llu bpc=%u\n", __func__,
-			hdptx->hdmi_cfg.tmds_char_rate, hdptx->hdmi_cfg.bpc);
+			hdptx->hdmi_cfg.rate, hdptx->hdmi_cfg.bpc);
 		return ret;
 	}
 
@@ -1916,7 +1922,7 @@ static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate,
 	 * To be dropped as soon as the RK DW HDMI QP bridge driver
 	 * switches to make use of phy_configure().
 	 */
-	if (!hdptx->restrict_rate_change && rate != hdptx->hdmi_cfg.tmds_char_rate) {
+	if (!hdptx->restrict_rate_change && rate != hdptx->hdmi_cfg.rate) {
 		struct phy_configure_opts_hdmi hdmi = {
 			.tmds_char_rate = rate,
 		};
@@ -1925,7 +1931,7 @@ static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate,
 		if (ret)
 			return ret;
 
-		hdptx->hdmi_cfg = hdmi;
+		hdptx->hdmi_cfg.rate = rate;
 	}
 
 	/*
@@ -1933,7 +1939,7 @@ static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate,
 	 * hence ensure rk_hdptx_phy_clk_set_rate() won't be invoked with
 	 * a different rate argument.
 	 */
-	return DIV_ROUND_CLOSEST_ULL(hdptx->hdmi_cfg.tmds_char_rate * 8, hdptx->hdmi_cfg.bpc);
+	return DIV_ROUND_CLOSEST_ULL(hdptx->hdmi_cfg.rate * 8, hdptx->hdmi_cfg.bpc);
 }
 
 static int rk_hdptx_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -1943,10 +1949,10 @@ static int rk_hdptx_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate,
 	unsigned long long tmds_rate = DIV_ROUND_CLOSEST_ULL(rate * hdptx->hdmi_cfg.bpc, 8);
 
 	/* Revert any unlikely TMDS char rate change since round_rate() */
-	if (hdptx->hdmi_cfg.tmds_char_rate != tmds_rate) {
+	if (hdptx->hdmi_cfg.rate != tmds_rate) {
 		dev_warn(hdptx->dev, "Reverting unexpected rate change from %llu to %llu\n",
-			 tmds_rate, hdptx->hdmi_cfg.tmds_char_rate);
-		hdptx->hdmi_cfg.tmds_char_rate = tmds_rate;
+			 tmds_rate, hdptx->hdmi_cfg.rate);
+		hdptx->hdmi_cfg.rate = tmds_rate;
 	}
 
 	/*

-- 
2.51.2



From cristian.ciocaltea at collabora.com  Sun Dec 21 02:46:57 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Sun, 21 Dec 2025 12:46:57 +0200
Subject: [PATCH v5 10/11] phy: rockchip: samsung-hdptx: Extend
 rk_hdptx_phy_verify_hdmi_config() helper
In-Reply-To: <20251221-phy-hdptx-frl-v5-0-dac390a780be@collabora.com>
References: <20251221-phy-hdptx-frl-v5-0-dac390a780be@collabora.com>
Message-ID: <20251221-phy-hdptx-frl-v5-10-dac390a780be@collabora.com>

In order to facilitate introduction of HDMI 2.1 FRL support and to avoid
recomputing the link rate after verifying the HDMI configuration given
as input, extend rk_hdptx_phy_verify_hdmi_config() by providing an
optional output parameter to store the validated configuration.

For improved code readability, also rename the existing hdmi input
parameter.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 35 ++++++++++++-----------
 1 file changed, 18 insertions(+), 17 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index 3bec69058f7b..ecf024b5414f 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -1439,25 +1439,24 @@ static int rk_hdptx_phy_power_off(struct phy *phy)
 }
 
 static int rk_hdptx_phy_verify_hdmi_config(struct rk_hdptx_phy *hdptx,
-					   struct phy_configure_opts_hdmi *hdmi)
+					   struct phy_configure_opts_hdmi *hdmi_in,
+					   struct rk_hdptx_hdmi_cfg *hdmi_out)
 {
 	int i;
 
-	if (!hdmi->tmds_char_rate || hdmi->tmds_char_rate > HDMI20_MAX_RATE)
+	if (!hdmi_in->tmds_char_rate || hdmi_in->tmds_char_rate > HDMI20_MAX_RATE)
 		return -EINVAL;
 
 	for (i = 0; i < ARRAY_SIZE(rk_hdptx_tmds_ropll_cfg); i++)
-		if (hdmi->tmds_char_rate == rk_hdptx_tmds_ropll_cfg[i].rate)
+		if (hdmi_in->tmds_char_rate == rk_hdptx_tmds_ropll_cfg[i].rate)
 			break;
 
 	if (i == ARRAY_SIZE(rk_hdptx_tmds_ropll_cfg) &&
-	    !rk_hdptx_phy_clk_pll_calc(hdmi->tmds_char_rate, NULL))
+	    !rk_hdptx_phy_clk_pll_calc(hdmi_in->tmds_char_rate, NULL))
 		return -EINVAL;
 
-	if (!hdmi->bpc)
-		hdmi->bpc = 8;
-
-	switch (hdmi->bpc) {
+	switch (hdmi_in->bpc) {
+	case 0:
 	case 8:
 	case 10:
 	case 12:
@@ -1467,6 +1466,11 @@ static int rk_hdptx_phy_verify_hdmi_config(struct rk_hdptx_phy *hdptx,
 		return -EINVAL;
 	}
 
+	if (hdmi_out) {
+		hdmi_out->rate = hdmi_in->tmds_char_rate;
+		hdmi_out->bpc = hdmi_in->bpc ?: 8;
+	}
+
 	return 0;
 }
 
@@ -1732,17 +1736,15 @@ static int rk_hdptx_phy_configure(struct phy *phy, union phy_configure_opts *opt
 	int ret;
 
 	if (mode != PHY_MODE_DP) {
-		ret = rk_hdptx_phy_verify_hdmi_config(hdptx, &opts->hdmi);
+		ret = rk_hdptx_phy_verify_hdmi_config(hdptx, &opts->hdmi, &hdptx->hdmi_cfg);
 		if (ret) {
 			dev_err(hdptx->dev, "invalid hdmi params for phy configure\n");
 		} else {
-			hdptx->hdmi_cfg.rate = opts->hdmi.tmds_char_rate;
-			hdptx->hdmi_cfg.bpc = opts->hdmi.bpc;
 			hdptx->restrict_rate_change = true;
+			dev_dbg(hdptx->dev, "%s rate=%llu bpc=%u\n", __func__,
+				hdptx->hdmi_cfg.rate, hdptx->hdmi_cfg.bpc);
 		}
 
-		dev_dbg(hdptx->dev, "%s rate=%llu bpc=%u\n", __func__,
-			hdptx->hdmi_cfg.rate, hdptx->hdmi_cfg.bpc);
 		return ret;
 	}
 
@@ -1786,7 +1788,7 @@ static int rk_hdptx_phy_validate(struct phy *phy, enum phy_mode mode,
 	struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy);
 
 	if (mode != PHY_MODE_DP)
-		return rk_hdptx_phy_verify_hdmi_config(hdptx, &opts->hdmi);
+		return rk_hdptx_phy_verify_hdmi_config(hdptx, &opts->hdmi, NULL);
 
 	return rk_hdptx_phy_verify_dp_config(hdptx, &opts->dp);
 }
@@ -1926,12 +1928,11 @@ static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate,
 		struct phy_configure_opts_hdmi hdmi = {
 			.tmds_char_rate = rate,
 		};
-		int ret = rk_hdptx_phy_verify_hdmi_config(hdptx, &hdmi);
+
+		int ret = rk_hdptx_phy_verify_hdmi_config(hdptx, &hdmi, &hdptx->hdmi_cfg);
 
 		if (ret)
 			return ret;
-
-		hdptx->hdmi_cfg.rate = rate;
 	}
 
 	/*

-- 
2.51.2



From cristian.ciocaltea at collabora.com  Sun Dec 21 02:46:54 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Sun, 21 Dec 2025 12:46:54 +0200
Subject: [PATCH v5 07/11] phy: rockchip: samsung-hdptx: Compute clk rate
 from PLL config
In-Reply-To: <20251221-phy-hdptx-frl-v5-0-dac390a780be@collabora.com>
References: <20251221-phy-hdptx-frl-v5-0-dac390a780be@collabora.com>
Message-ID: <20251221-phy-hdptx-frl-v5-7-dac390a780be@collabora.com>

Improve ->recalc_rate() callback of hdptx_phy_clk_ops to calculate the
initial clock rate based on the actual PHY PLL configuration as
retrieved from the related hardware registers.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 91 ++++++++++++++++++++++-
 1 file changed, 90 insertions(+), 1 deletion(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index 42f0ac5a74b1..c2d2f2468ba2 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -1818,12 +1818,101 @@ static void rk_hdptx_phy_clk_unprepare(struct clk_hw *hw)
 	rk_hdptx_phy_consumer_put(hdptx, true);
 }
 
+#define PLL_REF_CLK 24000000ULL
+
+static u64 rk_hdptx_phy_clk_calc_rate_from_pll_cfg(struct rk_hdptx_phy *hdptx)
+{
+	struct ropll_config ropll_hw;
+	u64 fout, sdm;
+	u32 mode, val;
+	int ret;
+
+	ret = regmap_read(hdptx->regmap, CMN_REG(0008), &mode);
+	if (ret)
+		return 0;
+
+	if (mode & LCPLL_LCVCO_MODE_EN_MASK)
+		return 0;
+
+	ret = regmap_read(hdptx->regmap, CMN_REG(0051), &val);
+	if (ret)
+		return 0;
+	ropll_hw.pms_mdiv = val;
+
+	ret = regmap_read(hdptx->regmap, CMN_REG(005E), &val);
+	if (ret)
+		return 0;
+	ropll_hw.sdm_en = val & ROPLL_SDM_EN_MASK;
+
+	ret = regmap_read(hdptx->regmap, CMN_REG(0064), &val);
+	if (ret)
+		return 0;
+	ropll_hw.sdm_num_sign = val & ROPLL_SDM_NUM_SIGN_RBR_MASK;
+
+	ret = regmap_read(hdptx->regmap, CMN_REG(0065), &val);
+	if (ret)
+		return 0;
+	ropll_hw.sdm_num = val;
+
+	ret = regmap_read(hdptx->regmap, CMN_REG(0060), &val);
+	if (ret)
+		return 0;
+	ropll_hw.sdm_deno = val;
+
+	ret = regmap_read(hdptx->regmap, CMN_REG(0069), &val);
+	if (ret)
+		return 0;
+	ropll_hw.sdc_n = (val & ROPLL_SDC_N_RBR_MASK) + 3;
+
+	ret = regmap_read(hdptx->regmap, CMN_REG(006c), &val);
+	if (ret)
+		return 0;
+	ropll_hw.sdc_num = val;
+
+	ret = regmap_read(hdptx->regmap, CMN_REG(0070), &val);
+	if (ret)
+		return 0;
+	ropll_hw.sdc_deno = val;
+
+	ret = regmap_read(hdptx->regmap, CMN_REG(0086), &val);
+	if (ret)
+		return 0;
+	ropll_hw.pms_sdiv = ((val & PLL_PCG_POSTDIV_SEL_MASK) >> 4) + 1;
+
+	fout = PLL_REF_CLK * ropll_hw.pms_mdiv;
+	if (ropll_hw.sdm_en) {
+		sdm = div_u64(PLL_REF_CLK * ropll_hw.sdc_deno *
+			      ropll_hw.pms_mdiv * ropll_hw.sdm_num,
+			      16 * ropll_hw.sdm_deno *
+			      (ropll_hw.sdc_deno * ropll_hw.sdc_n - ropll_hw.sdc_num));
+
+		if (ropll_hw.sdm_num_sign)
+			fout = fout - sdm;
+		else
+			fout = fout + sdm;
+	}
+
+	return div_u64(fout * 2, ropll_hw.pms_sdiv * 10);
+}
+
 static unsigned long rk_hdptx_phy_clk_recalc_rate(struct clk_hw *hw,
 						  unsigned long parent_rate)
 {
 	struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
+	u32 status;
+	u64 rate;
+	int ret;
+
+	if (hdptx->hw_rate)
+		return hdptx->hw_rate;
+
+	ret = regmap_read(hdptx->grf, GRF_HDPTX_CON0, &status);
+	if (ret || !(status & HDPTX_I_PLL_EN))
+		return 0;
+
+	rate = rk_hdptx_phy_clk_calc_rate_from_pll_cfg(hdptx);
 
-	return hdptx->hw_rate;
+	return DIV_ROUND_CLOSEST_ULL(rate * 8, hdptx->hdmi_cfg.bpc);
 }
 
 static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate,

-- 
2.51.2



From cristian.ciocaltea at collabora.com  Sun Dec 21 02:46:58 2025
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Sun, 21 Dec 2025 12:46:58 +0200
Subject: [PATCH v5 11/11] phy: rockchip: samsung-hdptx: Add HDMI 2.1 FRL
 support
In-Reply-To: <20251221-phy-hdptx-frl-v5-0-dac390a780be@collabora.com>
References: <20251221-phy-hdptx-frl-v5-0-dac390a780be@collabora.com>
Message-ID: <20251221-phy-hdptx-frl-v5-11-dac390a780be@collabora.com>

The PHY is capable of handling four HDMI 2.1 Fixed Rate Link (FRL)
lanes, and each one can operate at any of the rates of 3Gbps, 6Gbps,
8Gbps, 10Gbps or 12Gbps.

Add the necessary driver changes to support the feature.

Co-developed-by: Algea Cao <algea.cao at rock-chips.com>
Signed-off-by: Algea Cao <algea.cao at rock-chips.com>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 441 ++++++++++++++++++++--
 1 file changed, 418 insertions(+), 23 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index ecf024b5414f..cfa9fcb82c1f 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -22,6 +22,7 @@
 #include <linux/reset.h>
 
 #define GRF_HDPTX_CON0			0x00
+#define LC_REF_CLK_SEL			BIT(11)
 #define HDPTX_I_PLL_EN			BIT(7)
 #define HDPTX_I_BIAS_EN			BIT(6)
 #define HDPTX_I_BGR_EN			BIT(5)
@@ -322,6 +323,9 @@
 
 #define HDMI14_MAX_RATE			340000000
 #define HDMI20_MAX_RATE			600000000
+#define FRL_3G3L_RATE			900000000
+#define FRL_6G3L_RATE			1800000000
+#define FRL_8G4L_RATE			3200000000
 
 enum dp_link_rate {
 	DP_BW_RBR,
@@ -329,6 +333,22 @@ enum dp_link_rate {
 	DP_BW_HBR2,
 };
 
+struct lcpll_config {
+	unsigned long long rate;
+	u8 lcvco_mode_en;
+	u8 pi_en;
+	u8 clk_en_100m;
+	u8 pms_mdiv;
+	u8 pms_mdiv_afc;
+	u8 pms_pdiv;
+	u8 pms_refdiv;
+	u8 pms_sdiv;
+	u8 sdm_deno;
+	u8 sdm_num_sign;
+	u8 sdm_num;
+	u8 sdc_n;
+};
+
 struct ropll_config {
 	unsigned long long rate;
 	u8 pms_mdiv;
@@ -374,6 +394,7 @@ struct rk_hdptx_phy_cfg {
 };
 
 struct rk_hdptx_hdmi_cfg {
+	enum phy_hdmi_mode mode;
 	unsigned long long rate;
 	unsigned int bpc;
 };
@@ -401,6 +422,16 @@ struct rk_hdptx_phy {
 	unsigned int lanes;
 };
 
+static const struct lcpll_config rk_hdptx_frl_lcpll_cfg[] = {
+	/*                                |              pms             |      sdm       |      */
+	/*         rate, lcen, pien, cken, mdiv, mdafc, pdiv, rdiv, sdiv, deno, nsig, num, sdcn, */
+	{ 4800000000ULL,    1,    0,    0,  125,   125,    1,    1,    0,    1,    0,   0,    2, },
+	{ 4000000000ULL,    1,    1,    0,  104,   104,    1,    1,    0,    9,    0,   1,    1, },
+	{ 2400000000ULL,    1,    0,    0,  125,   125,    1,    1,    1,    1,    0,   0,    2, },
+	{ 1800000000ULL,    1,    0,    0,  125,   125,    1,    1,    1,    1,    0,   0,    2, },
+	{  900000000ULL,    1,    0,    0,  125,   125,    1,    1,    3,    1,    0,   0,    2, },
+};
+
 static const struct ropll_config rk_hdptx_tmds_ropll_cfg[] = {
 	/*             |              pms             |        sdm         |     sdc     | */
 	/*        rate, mdiv, mdafc, pdiv, rdiv, sdiv, en, deno, nsig, num,  n, num, deno, */
@@ -500,6 +531,110 @@ static const struct reg_sequence rk_hdptx_common_cmn_init_seq[] = {
 	REG_SEQ0(CMN_REG(009a), 0x11),
 };
 
+static const struct reg_sequence rk_hdptx_frl_lcpll_cmn_init_seq[] = {
+	REG_SEQ0(CMN_REG(0011), 0x00),
+	REG_SEQ0(CMN_REG(0017), 0x00),
+	REG_SEQ0(CMN_REG(0025), 0x10),
+	REG_SEQ0(CMN_REG(0026), 0x53),
+	REG_SEQ0(CMN_REG(0027), 0x01),
+	REG_SEQ0(CMN_REG(0028), 0x0d),
+	REG_SEQ0(CMN_REG(002e), 0x02),
+	REG_SEQ0(CMN_REG(002f), 0x0d),
+	REG_SEQ0(CMN_REG(0030), 0x00),
+	REG_SEQ0(CMN_REG(0031), 0x20),
+	REG_SEQ0(CMN_REG(0032), 0x30),
+	REG_SEQ0(CMN_REG(0033), 0x0b),
+	REG_SEQ0(CMN_REG(0034), 0x23),
+	REG_SEQ0(CMN_REG(003d), 0x00),
+	REG_SEQ0(CMN_REG(0042), 0xb8),
+	REG_SEQ0(CMN_REG(0046), 0xff),
+	REG_SEQ0(CMN_REG(0048), 0x44),
+	REG_SEQ0(CMN_REG(004e), 0x14),
+	REG_SEQ0(CMN_REG(0051), 0x00),
+	REG_SEQ0(CMN_REG(0055), 0x00),
+	REG_SEQ0(CMN_REG(0059), 0x11),
+	REG_SEQ0(CMN_REG(005a), 0x03),
+	REG_SEQ0(CMN_REG(005c), 0x05),
+	REG_SEQ0(CMN_REG(005d), 0x0c),
+	REG_SEQ0(CMN_REG(005e), 0x07),
+	REG_SEQ0(CMN_REG(0060), 0x01),
+	REG_SEQ0(CMN_REG(0064), 0x07),
+	REG_SEQ0(CMN_REG(0065), 0x00),
+	REG_SEQ0(CMN_REG(0069), 0x00),
+	REG_SEQ0(CMN_REG(006b), 0x04),
+	REG_SEQ0(CMN_REG(006c), 0x00),
+	REG_SEQ0(CMN_REG(0070), 0x01),
+	REG_SEQ0(CMN_REG(0073), 0x30),
+	REG_SEQ0(CMN_REG(0074), 0x00),
+	REG_SEQ0(CMN_REG(0081), 0x09),
+	REG_SEQ0(CMN_REG(0086), 0x01),
+	REG_SEQ0(CMN_REG(0087), 0x0c),
+	REG_SEQ0(CMN_REG(0089), 0x02),
+	REG_SEQ0(CMN_REG(0095), 0x00),
+	REG_SEQ0(CMN_REG(0097), 0x00),
+	REG_SEQ0(CMN_REG(0099), 0x00),
+	REG_SEQ0(CMN_REG(009b), 0x10),
+};
+
+static const struct reg_sequence rk_hdptx_frl_lcpll_ropll_cmn_init_seq[] = {
+	REG_SEQ0(CMN_REG(0008), 0xd0),
+	REG_SEQ0(CMN_REG(0011), 0x00),
+	REG_SEQ0(CMN_REG(0017), 0x00),
+	REG_SEQ0(CMN_REG(001e), 0x35),
+	REG_SEQ0(CMN_REG(0020), 0x6b),
+	REG_SEQ0(CMN_REG(0021), 0x6b),
+	REG_SEQ0(CMN_REG(0022), 0x11),
+	REG_SEQ0(CMN_REG(0024), 0x00),
+	REG_SEQ0(CMN_REG(0025), 0x10),
+	REG_SEQ0(CMN_REG(0026), 0x53),
+	REG_SEQ0(CMN_REG(0027), 0x15),
+	REG_SEQ0(CMN_REG(0028), 0x0d),
+	REG_SEQ0(CMN_REG(002a), 0x09),
+	REG_SEQ0(CMN_REG(002b), 0x01),
+	REG_SEQ0(CMN_REG(002c), 0x02),
+	REG_SEQ0(CMN_REG(002d), 0x02),
+	REG_SEQ0(CMN_REG(002e), 0x0d),
+	REG_SEQ0(CMN_REG(002f), 0x61),
+	REG_SEQ0(CMN_REG(0030), 0x00),
+	REG_SEQ0(CMN_REG(0031), 0x20),
+	REG_SEQ0(CMN_REG(0032), 0x30),
+	REG_SEQ0(CMN_REG(0033), 0x0b),
+	REG_SEQ0(CMN_REG(0034), 0x23),
+	REG_SEQ0(CMN_REG(0037), 0x00),
+	REG_SEQ0(CMN_REG(003d), 0xc0),
+	REG_SEQ0(CMN_REG(0042), 0xb8),
+	REG_SEQ0(CMN_REG(0046), 0xff),
+	REG_SEQ0(CMN_REG(0048), 0x44),
+	REG_SEQ0(CMN_REG(004e), 0x14),
+	REG_SEQ0(CMN_REG(0054), 0x19),
+	REG_SEQ0(CMN_REG(0058), 0x19),
+	REG_SEQ0(CMN_REG(0059), 0x11),
+	REG_SEQ0(CMN_REG(005b), 0x30),
+	REG_SEQ0(CMN_REG(005c), 0x25),
+	REG_SEQ0(CMN_REG(005d), 0x14),
+	REG_SEQ0(CMN_REG(005e), 0x0e),
+	REG_SEQ0(CMN_REG(0063), 0x01),
+	REG_SEQ0(CMN_REG(0064), 0x0e),
+	REG_SEQ0(CMN_REG(0068), 0x00),
+	REG_SEQ0(CMN_REG(0069), 0x02),
+	REG_SEQ0(CMN_REG(006b), 0x00),
+	REG_SEQ0(CMN_REG(006f), 0x00),
+	REG_SEQ0(CMN_REG(0073), 0x02),
+	REG_SEQ0(CMN_REG(0074), 0x00),
+	REG_SEQ0(CMN_REG(007a), 0x00),
+	REG_SEQ0(CMN_REG(0081), 0x09),
+	REG_SEQ0(CMN_REG(0086), 0x11),
+	REG_SEQ0(CMN_REG(0087), 0x0c),
+	REG_SEQ0(CMN_REG(0089), 0x00),
+	REG_SEQ0(CMN_REG(0095), 0x03),
+	REG_SEQ0(CMN_REG(0097), 0x00),
+	REG_SEQ0(CMN_REG(0099), 0x00),
+	REG_SEQ0(CMN_REG(009b), 0x10),
+	REG_SEQ0(CMN_REG(009e), 0x03),
+	REG_SEQ0(CMN_REG(009f), 0xff),
+	REG_SEQ0(CMN_REG(00a0), 0x60),
+};
+
 static const struct reg_sequence rk_hdptx_tmds_cmn_init_seq[] = {
 	REG_SEQ0(CMN_REG(0008), 0x00),
 	REG_SEQ0(CMN_REG(0011), 0x01),
@@ -553,6 +688,16 @@ static const struct reg_sequence rk_hdptx_common_sb_init_seq[] = {
 	REG_SEQ0(SB_REG(0117), 0x00),
 };
 
+static const struct reg_sequence rk_hdptx_frl_lntop_init_seq[] = {
+	REG_SEQ0(LNTOP_REG(0200), 0x04),
+	REG_SEQ0(LNTOP_REG(0201), 0x00),
+	REG_SEQ0(LNTOP_REG(0202), 0x00),
+	REG_SEQ0(LNTOP_REG(0203), 0xf0),
+	REG_SEQ0(LNTOP_REG(0204), 0xff),
+	REG_SEQ0(LNTOP_REG(0205), 0xff),
+	REG_SEQ0(LNTOP_REG(0206), 0x05),
+};
+
 static const struct reg_sequence rk_hdptx_tmds_lntop_highbr_seq[] = {
 	REG_SEQ0(LNTOP_REG(0201), 0x00),
 	REG_SEQ0(LNTOP_REG(0202), 0x00),
@@ -624,6 +769,38 @@ static const struct reg_sequence rk_hdptx_common_lane_init_seq[] = {
 	REG_SEQ0(LANE_REG(0620), 0xa0),
 };
 
+static const struct reg_sequence rk_hdptx_frl_lane_init_seq[] = {
+	REG_SEQ0(LANE_REG(0312), 0x3c),
+	REG_SEQ0(LANE_REG(0412), 0x3c),
+	REG_SEQ0(LANE_REG(0512), 0x3c),
+	REG_SEQ0(LANE_REG(0612), 0x3c),
+	REG_SEQ0(LANE_REG(0303), 0x2f),
+	REG_SEQ0(LANE_REG(0403), 0x2f),
+	REG_SEQ0(LANE_REG(0503), 0x2f),
+	REG_SEQ0(LANE_REG(0603), 0x2f),
+	REG_SEQ0(LANE_REG(0305), 0x03),
+	REG_SEQ0(LANE_REG(0405), 0x03),
+	REG_SEQ0(LANE_REG(0505), 0x03),
+	REG_SEQ0(LANE_REG(0605), 0x03),
+	REG_SEQ0(LANE_REG(0306), 0xfc),
+	REG_SEQ0(LANE_REG(0406), 0xfc),
+	REG_SEQ0(LANE_REG(0506), 0xfc),
+	REG_SEQ0(LANE_REG(0606), 0xfc),
+	REG_SEQ0(LANE_REG(0305), 0x4f),
+	REG_SEQ0(LANE_REG(0405), 0x4f),
+	REG_SEQ0(LANE_REG(0505), 0x4f),
+	REG_SEQ0(LANE_REG(0605), 0x4f),
+	REG_SEQ0(LANE_REG(0304), 0x14),
+	REG_SEQ0(LANE_REG(0404), 0x14),
+	REG_SEQ0(LANE_REG(0504), 0x14),
+	REG_SEQ0(LANE_REG(0604), 0x14),
+	/* Keep Inter-Pair Skew in the limits */
+	REG_SEQ0(LANE_REG(031e), 0x02),
+	REG_SEQ0(LANE_REG(041e), 0x02),
+	REG_SEQ0(LANE_REG(051e), 0x02),
+	REG_SEQ0(LANE_REG(061e), 0x02),
+};
+
 static const struct reg_sequence rk_hdptx_tmds_lane_init_seq[] = {
 	REG_SEQ0(LANE_REG(0312), 0x00),
 	REG_SEQ0(LANE_REG(0412), 0x00),
@@ -787,7 +964,12 @@ static int rk_hdptx_post_enable_lane(struct rk_hdptx_phy *hdptx)
 	       HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN;
 	regmap_write(hdptx->grf, GRF_HDPTX_CON0, val);
 
-	regmap_write(hdptx->regmap, LNTOP_REG(0207), 0x0f);
+	/* 3 lanes FRL mode */
+	if (hdptx->hdmi_cfg.rate == FRL_6G3L_RATE ||
+	    hdptx->hdmi_cfg.rate == FRL_3G3L_RATE)
+		regmap_write(hdptx->regmap, LNTOP_REG(0207), 0x07);
+	else
+		regmap_write(hdptx->regmap, LNTOP_REG(0207), 0x0f);
 
 	ret = regmap_read_poll_timeout(hdptx->grf, GRF_HDPTX_STATUS, val,
 				       (val & HDPTX_O_PHY_RDY) &&
@@ -931,6 +1113,80 @@ static bool rk_hdptx_phy_clk_pll_calc(unsigned long long rate,
 	return true;
 }
 
+static int rk_hdptx_frl_lcpll_cmn_config(struct rk_hdptx_phy *hdptx)
+{
+	const struct lcpll_config *cfg = NULL;
+	int i;
+
+	dev_dbg(hdptx->dev, "%s rate=%llu\n", __func__, hdptx->hdmi_cfg.rate);
+
+	for (i = 0; i < ARRAY_SIZE(rk_hdptx_frl_lcpll_cfg); i++) {
+		if (hdptx->hdmi_cfg.rate == rk_hdptx_frl_lcpll_cfg[i].rate) {
+			cfg = &rk_hdptx_frl_lcpll_cfg[i];
+			break;
+		}
+	}
+
+	if (!cfg) {
+		dev_err(hdptx->dev, "%s cannot find pll cfg for rate=%llu\n",
+			__func__, hdptx->hdmi_cfg.rate);
+		return -EINVAL;
+	}
+
+	rk_hdptx_pre_power_up(hdptx);
+
+	regmap_write(hdptx->grf, GRF_HDPTX_CON0, LC_REF_CLK_SEL << 16);
+
+	rk_hdptx_multi_reg_write(hdptx, rk_hdptx_common_cmn_init_seq);
+	rk_hdptx_multi_reg_write(hdptx, rk_hdptx_frl_lcpll_cmn_init_seq);
+
+	regmap_update_bits(hdptx->regmap, CMN_REG(0008),
+			   LCPLL_EN_MASK | LCPLL_LCVCO_MODE_EN_MASK,
+			   FIELD_PREP(LCPLL_EN_MASK, 1) |
+			   FIELD_PREP(LCPLL_LCVCO_MODE_EN_MASK, cfg->lcvco_mode_en));
+
+	regmap_update_bits(hdptx->regmap, CMN_REG(001e),
+			   LCPLL_PI_EN_MASK | LCPLL_100M_CLK_EN_MASK,
+			   FIELD_PREP(LCPLL_PI_EN_MASK, cfg->pi_en) |
+			   FIELD_PREP(LCPLL_100M_CLK_EN_MASK, cfg->clk_en_100m));
+
+	regmap_write(hdptx->regmap, CMN_REG(0020), cfg->pms_mdiv);
+	regmap_write(hdptx->regmap, CMN_REG(0021), cfg->pms_mdiv_afc);
+	regmap_write(hdptx->regmap, CMN_REG(0022),
+		     (cfg->pms_pdiv << 4) | cfg->pms_refdiv);
+	regmap_write(hdptx->regmap, CMN_REG(0023),
+		     (cfg->pms_sdiv << 4) | cfg->pms_sdiv);
+	regmap_write(hdptx->regmap, CMN_REG(002a), cfg->sdm_deno);
+	regmap_write(hdptx->regmap, CMN_REG(002b), cfg->sdm_num_sign);
+	regmap_write(hdptx->regmap, CMN_REG(002c), cfg->sdm_num);
+
+	regmap_update_bits(hdptx->regmap, CMN_REG(002d), LCPLL_SDC_N_MASK,
+			   FIELD_PREP(LCPLL_SDC_N_MASK, cfg->sdc_n));
+
+	regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_POSTDIV_SEL_MASK,
+			   FIELD_PREP(PLL_PCG_POSTDIV_SEL_MASK, cfg->pms_sdiv));
+	regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_CLK_SEL_MASK,
+			   FIELD_PREP(PLL_PCG_CLK_SEL_MASK, (hdptx->hdmi_cfg.bpc - 8) >> 1));
+
+	return rk_hdptx_post_enable_pll(hdptx);
+}
+
+static int rk_hdptx_frl_lcpll_ropll_cmn_config(struct rk_hdptx_phy *hdptx)
+{
+	dev_dbg(hdptx->dev, "%s rate=%llu\n", __func__, hdptx->hdmi_cfg.rate);
+
+	rk_hdptx_pre_power_up(hdptx);
+
+	/* ROPLL input reference clock from LCPLL (cascade mode) */
+	regmap_write(hdptx->grf, GRF_HDPTX_CON0,
+		     (LC_REF_CLK_SEL << 16) | LC_REF_CLK_SEL);
+
+	rk_hdptx_multi_reg_write(hdptx, rk_hdptx_common_cmn_init_seq);
+	rk_hdptx_multi_reg_write(hdptx, rk_hdptx_frl_lcpll_ropll_cmn_init_seq);
+
+	return rk_hdptx_post_enable_pll(hdptx);
+}
+
 static int rk_hdptx_tmds_ropll_cmn_config(struct rk_hdptx_phy *hdptx)
 {
 	const struct ropll_config *cfg = NULL;
@@ -962,6 +1218,8 @@ static int rk_hdptx_tmds_ropll_cmn_config(struct rk_hdptx_phy *hdptx)
 
 	rk_hdptx_pre_power_up(hdptx);
 
+	regmap_write(hdptx->grf, GRF_HDPTX_CON0, LC_REF_CLK_SEL << 16);
+
 	rk_hdptx_multi_reg_write(hdptx, rk_hdptx_common_cmn_init_seq);
 	rk_hdptx_multi_reg_write(hdptx, rk_hdptx_tmds_cmn_init_seq);
 
@@ -1000,6 +1258,28 @@ static int rk_hdptx_tmds_ropll_cmn_config(struct rk_hdptx_phy *hdptx)
 	return rk_hdptx_post_enable_pll(hdptx);
 }
 
+static int rk_hdptx_pll_cmn_config(struct rk_hdptx_phy *hdptx)
+{
+	if (hdptx->hdmi_cfg.rate <= HDMI20_MAX_RATE)
+		return rk_hdptx_tmds_ropll_cmn_config(hdptx);
+
+	if (hdptx->hdmi_cfg.rate == FRL_8G4L_RATE)
+		return rk_hdptx_frl_lcpll_ropll_cmn_config(hdptx);
+
+	return rk_hdptx_frl_lcpll_cmn_config(hdptx);
+}
+
+static int rk_hdptx_frl_lcpll_mode_config(struct rk_hdptx_phy *hdptx)
+{
+	rk_hdptx_multi_reg_write(hdptx, rk_hdptx_common_sb_init_seq);
+	rk_hdptx_multi_reg_write(hdptx, rk_hdptx_frl_lntop_init_seq);
+
+	rk_hdptx_multi_reg_write(hdptx, rk_hdptx_common_lane_init_seq);
+	rk_hdptx_multi_reg_write(hdptx, rk_hdptx_frl_lane_init_seq);
+
+	return rk_hdptx_post_enable_lane(hdptx);
+}
+
 static int rk_hdptx_tmds_ropll_mode_config(struct rk_hdptx_phy *hdptx)
 {
 	rk_hdptx_multi_reg_write(hdptx, rk_hdptx_common_sb_init_seq);
@@ -1076,7 +1356,7 @@ static int rk_hdptx_phy_consumer_get(struct rk_hdptx_phy *hdptx)
 	if (mode == PHY_MODE_DP) {
 		rk_hdptx_dp_reset(hdptx);
 	} else {
-		ret = rk_hdptx_tmds_ropll_cmn_config(hdptx);
+		ret = rk_hdptx_pll_cmn_config(hdptx);
 		if (ret)
 			goto dec_usage;
 	}
@@ -1377,7 +1657,7 @@ static int rk_hdptx_phy_power_on(struct phy *phy)
 	int ret, lane;
 
 	if (mode != PHY_MODE_DP) {
-		if (!hdptx->hdmi_cfg.rate) {
+		if (!hdptx->hdmi_cfg.rate && hdptx->hdmi_cfg.mode != PHY_HDMI_MODE_FRL) {
 			/*
 			 * FIXME: Temporary workaround to setup TMDS char rate
 			 * from the RK DW HDMI QP bridge driver.
@@ -1423,7 +1703,11 @@ static int rk_hdptx_phy_power_on(struct phy *phy)
 		regmap_write(hdptx->grf, GRF_HDPTX_CON0,
 			     HDPTX_MODE_SEL << 16 | FIELD_PREP(HDPTX_MODE_SEL, 0x0));
 
-		ret = rk_hdptx_tmds_ropll_mode_config(hdptx);
+		if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL)
+			ret = rk_hdptx_frl_lcpll_mode_config(hdptx);
+		else
+			ret = rk_hdptx_tmds_ropll_mode_config(hdptx);
+
 		if (ret)
 			rk_hdptx_phy_consumer_put(hdptx, true);
 	}
@@ -1444,16 +1728,49 @@ static int rk_hdptx_phy_verify_hdmi_config(struct rk_hdptx_phy *hdptx,
 {
 	int i;
 
-	if (!hdmi_in->tmds_char_rate || hdmi_in->tmds_char_rate > HDMI20_MAX_RATE)
-		return -EINVAL;
+	if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL) {
+		unsigned long long frl_rate = 100000000ULL * hdmi_in->frl.lanes *
+					      hdmi_in->frl.rate_per_lane;
 
-	for (i = 0; i < ARRAY_SIZE(rk_hdptx_tmds_ropll_cfg); i++)
-		if (hdmi_in->tmds_char_rate == rk_hdptx_tmds_ropll_cfg[i].rate)
+		switch (hdmi_in->frl.rate_per_lane) {
+		case 3:
+		case 6:
+		case 8:
+		case 10:
+		case 12:
 			break;
+		default:
+			return -EINVAL;
+		}
 
-	if (i == ARRAY_SIZE(rk_hdptx_tmds_ropll_cfg) &&
-	    !rk_hdptx_phy_clk_pll_calc(hdmi_in->tmds_char_rate, NULL))
-		return -EINVAL;
+		if (!hdmi_in->frl.lanes || hdmi_in->frl.lanes > 4)
+			return -EINVAL;
+
+		if (frl_rate != FRL_8G4L_RATE) {
+			for (i = 0; i < ARRAY_SIZE(rk_hdptx_frl_lcpll_cfg); i++)
+				if (frl_rate == rk_hdptx_frl_lcpll_cfg[i].rate)
+					break;
+			if (i == ARRAY_SIZE(rk_hdptx_frl_lcpll_cfg))
+				return -EINVAL;
+		}
+
+		if (hdmi_out)
+			hdmi_out->rate = frl_rate;
+	} else {
+		if (!hdmi_in->tmds_char_rate || hdmi_in->tmds_char_rate > HDMI20_MAX_RATE)
+			return -EINVAL;
+
+		for (i = 0; i < ARRAY_SIZE(rk_hdptx_tmds_ropll_cfg); i++)
+			if (hdmi_in->tmds_char_rate == rk_hdptx_tmds_ropll_cfg[i].rate)
+				break;
+
+		if (i == ARRAY_SIZE(rk_hdptx_tmds_ropll_cfg) &&
+		    !rk_hdptx_phy_clk_pll_calc(hdmi_in->tmds_char_rate, NULL))
+			return -EINVAL;
+
+		if (hdmi_out)
+			hdmi_out->rate = hdmi_in->tmds_char_rate;
+	}
 
 	switch (hdmi_in->bpc) {
 	case 0:
@@ -1466,10 +1783,8 @@ static int rk_hdptx_phy_verify_hdmi_config(struct rk_hdptx_phy *hdptx,
 		return -EINVAL;
 	}
 
-	if (hdmi_out) {
-		hdmi_out->rate = hdmi_in->tmds_char_rate;
+	if (hdmi_out)
 		hdmi_out->bpc = hdmi_in->bpc ?: 8;
-	}
 
 	return 0;
 }
@@ -1729,6 +2044,31 @@ static int rk_hdptx_phy_set_voltages(struct rk_hdptx_phy *hdptx,
 	return 0;
 }
 
+static int rk_hdptx_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode)
+{
+	struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy);
+
+	if (mode == PHY_MODE_DP)
+		return 0;
+
+	if (mode != PHY_MODE_HDMI) {
+		dev_err(&phy->dev, "invalid PHY mode: %d\n", mode);
+		return -EINVAL;
+	}
+
+	switch (submode) {
+	case PHY_HDMI_MODE_TMDS:
+	case PHY_HDMI_MODE_FRL:
+		hdptx->hdmi_cfg.mode = submode;
+		break;
+	default:
+		dev_err(&phy->dev, "invalid HDMI mode: %d\n", submode);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int rk_hdptx_phy_configure(struct phy *phy, union phy_configure_opts *opts)
 {
 	struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy);
@@ -1796,6 +2136,7 @@ static int rk_hdptx_phy_validate(struct phy *phy, enum phy_mode mode,
 static const struct phy_ops rk_hdptx_phy_ops = {
 	.power_on  = rk_hdptx_phy_power_on,
 	.power_off = rk_hdptx_phy_power_off,
+	.set_mode = rk_hdptx_phy_set_mode,
 	.configure = rk_hdptx_phy_configure,
 	.validate  = rk_hdptx_phy_validate,
 	.owner	   = THIS_MODULE,
@@ -1824,17 +2165,62 @@ static void rk_hdptx_phy_clk_unprepare(struct clk_hw *hw)
 
 static u64 rk_hdptx_phy_clk_calc_rate_from_pll_cfg(struct rk_hdptx_phy *hdptx)
 {
+	struct lcpll_config lcpll_hw;
 	struct ropll_config ropll_hw;
 	u64 fout, sdm;
 	u32 mode, val;
-	int ret;
+	int ret, i;
 
 	ret = regmap_read(hdptx->regmap, CMN_REG(0008), &mode);
 	if (ret)
 		return 0;
 
-	if (mode & LCPLL_LCVCO_MODE_EN_MASK)
+	if (mode & LCPLL_LCVCO_MODE_EN_MASK) {
+		ret = regmap_read(hdptx->regmap, CMN_REG(0020), &val);
+		if (ret)
+			return 0;
+		lcpll_hw.pms_mdiv = val;
+
+		ret = regmap_read(hdptx->regmap, CMN_REG(0023), &val);
+		if (ret)
+			return 0;
+		lcpll_hw.pms_sdiv = val & 0xf;
+
+		ret = regmap_read(hdptx->regmap, CMN_REG(002B), &val);
+		if (ret)
+			return 0;
+		lcpll_hw.sdm_num_sign = val;
+
+		ret = regmap_read(hdptx->regmap, CMN_REG(002C), &val);
+		if (ret)
+			return 0;
+		lcpll_hw.sdm_num = val;
+
+		ret = regmap_read(hdptx->regmap, CMN_REG(002A), &val);
+		if (ret)
+			return 0;
+		lcpll_hw.sdm_deno = val;
+
+		ret = regmap_read(hdptx->regmap, CMN_REG(002D), &val);
+		if (ret)
+			return 0;
+		lcpll_hw.sdc_n = (val & LCPLL_SDC_N_MASK) >> 1;
+
+		for (i = 0; i < ARRAY_SIZE(rk_hdptx_frl_lcpll_cfg); i++) {
+			const struct lcpll_config *cfg = &rk_hdptx_frl_lcpll_cfg[i];
+
+			if (cfg->pms_mdiv == lcpll_hw.pms_mdiv &&
+			    cfg->pms_sdiv == lcpll_hw.pms_sdiv &&
+			    cfg->sdm_num_sign == lcpll_hw.sdm_num_sign &&
+			    cfg->sdm_num == lcpll_hw.sdm_num &&
+			    cfg->sdm_deno == lcpll_hw.sdm_deno &&
+			    cfg->sdc_n == lcpll_hw.sdc_n)
+				return cfg->rate;
+		}
+
+		dev_dbg(hdptx->dev, "%s no FRL match found\n", __func__);
 		return 0;
+	}
 
 	ret = regmap_read(hdptx->regmap, CMN_REG(0051), &val);
 	if (ret)
@@ -1911,6 +2297,9 @@ static unsigned long rk_hdptx_phy_clk_recalc_rate(struct clk_hw *hw,
 
 	rate = rk_hdptx_phy_clk_calc_rate_from_pll_cfg(hdptx);
 
+	if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL)
+		return rate;
+
 	return DIV_ROUND_CLOSEST_ULL(rate * 8, hdptx->hdmi_cfg.bpc);
 }
 
@@ -1919,6 +2308,9 @@ static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate,
 {
 	struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
 
+	if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL)
+		return hdptx->hdmi_cfg.rate;
+
 	/*
 	 * FIXME: Temporarily allow altering TMDS char rate via CCF.
 	 * To be dropped as soon as the RK DW HDMI QP bridge driver
@@ -1947,23 +2339,26 @@ static int rk_hdptx_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate,
 				     unsigned long parent_rate)
 {
 	struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
-	unsigned long long tmds_rate = DIV_ROUND_CLOSEST_ULL(rate * hdptx->hdmi_cfg.bpc, 8);
+	unsigned long long link_rate = rate;
+
+	if (hdptx->hdmi_cfg.mode != PHY_HDMI_MODE_FRL)
+		link_rate = DIV_ROUND_CLOSEST_ULL(rate * hdptx->hdmi_cfg.bpc, 8);
 
-	/* Revert any unlikely TMDS char rate change since round_rate() */
-	if (hdptx->hdmi_cfg.rate != tmds_rate) {
+	/* Revert any unlikely link rate change since round_rate() */
+	if (hdptx->hdmi_cfg.rate != link_rate) {
 		dev_warn(hdptx->dev, "Reverting unexpected rate change from %llu to %llu\n",
-			 tmds_rate, hdptx->hdmi_cfg.rate);
-		hdptx->hdmi_cfg.rate = tmds_rate;
+			 link_rate, hdptx->hdmi_cfg.rate);
+		hdptx->hdmi_cfg.rate = link_rate;
 	}
 
 	/*
-	 * The TMDS char rate would be normally programmed in HW during
+	 * The link rate would be normally programmed in HW during
 	 * phy_ops.power_on() or clk_ops.prepare() callbacks, but it might
 	 * happen that the former gets fired too late, i.e. after this call,
 	 * while the latter being executed only once, i.e. when clock remains
 	 * in the prepared state during rate changes.
 	 */
-	return rk_hdptx_tmds_ropll_cmn_config(hdptx);
+	return rk_hdptx_pll_cmn_config(hdptx);
 }
 
 static const struct clk_ops hdptx_phy_clk_ops = {

-- 
2.51.2



From wens at kernel.org  Sun Dec 21 03:05:08 2025
From: wens at kernel.org (Chen-Yu Tsai)
Date: Sun, 21 Dec 2025 19:05:08 +0800
Subject: [PATCH 1/4] spi: dt-bindings: sun6i: Add compatibles for A523's SPI controllers
In-Reply-To: <20251221110513.1850535-1-wens@kernel.org>
References: <20251221110513.1850535-1-wens@kernel.org>
Message-ID: <20251221110513.1850535-2-wens@kernel.org>

The A523 has four SPI controllers. One of them supports MIPI DBI mode
in addition to standard SPI.

Compared to older generations, this newer controller now has a combined
counter for the RX FIFO ad buffer levels. In older generations, the
RX buffer level was a separate bitfield in the FIFO status register.

In practice this difference is negligible. The buffer is mostly
invisible to the implementation. If programmed I/O transfers are limited
to the FIFO size, then the contents of the buffer seem to always be
flushed over to the FIFO. For DMA, the DRQ trigger levels are only tied
to the FIFO levels. In all other aspects, the controller is the same as
the one in the R329.

Add new compatible strings for the new controllers.

Signed-off-by: Chen-Yu Tsai <wens at kernel.org>
---
 .../devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml      | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml b/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml
index 3b47b68b92cb..1b91d1566c95 100644
--- a/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml
+++ b/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml
@@ -17,6 +17,7 @@ properties:
   compatible:
     oneOf:
       - const: allwinner,sun50i-r329-spi
+      - const: allwinner,sun55i-a523-spi
       - const: allwinner,sun6i-a31-spi
       - const: allwinner,sun8i-h3-spi
       - items:
@@ -35,6 +36,9 @@ properties:
           - const: allwinner,sun20i-d1-spi-dbi
           - const: allwinner,sun50i-r329-spi-dbi
           - const: allwinner,sun50i-r329-spi
+      - items:
+          - const: allwinner,sun55i-a523-spi-dbi
+          - const: allwinner,sun55i-a523-spi
 
   reg:
     maxItems: 1
-- 
2.47.3



From wens at kernel.org  Sun Dec 21 03:05:07 2025
From: wens at kernel.org (Chen-Yu Tsai)
Date: Sun, 21 Dec 2025 19:05:07 +0800
Subject: [PATCH 0/4] arm64: allwinner: a523: Support SPI controllers
Message-ID: <20251221110513.1850535-1-wens@kernel.org>

Hi folks,

This series adds support for the SPI controllers found in the Allwinner
A523 SoC family. The SPI controller is almost the same as the ones in
previous generations, except that it moved the "RX buffer count"
register field to a separate register, and that register now reports
the total count for RX buffer and FIFO.

In practice the driver has never cared about the buffer count, but if
any implementation were to use it, this counts as a non-backward
compatible change.

Also, one of the SPI controllers supports DBI mode, acting as a display
interface. There is no infrastructure for DBI interface controllers in
the kernel, so only a separate compatible is added for it.

Patch 1 adds compatible strings for the new variants.

Patch 2 adds driver support for the new SPI controller variant.

Patch 3 adds device nodes for the SPI controllers to the dtsi file,
along with pinmux settings for spi0 on the PC pins, a common usage for
SPI-NOR flashes to boot from.

Patch 4 enables the SPI-NOR flash found on the Radxa Cubie A5E.


Please take a look and try it out.


Thanks
ChenYu


Chen-Yu Tsai (4):
  spi: dt-bindings: sun6i: Add compatibles for A523's SPI controllers
  spi: sun6i: Support A523's SPI controllers
  arm64: dts: allwinner: sun55i: Add SPI controllers
  arm64: dts: allwinner: t527: orangepi-4a: Enable SPI-NOR flash

 .../bindings/spi/allwinner,sun6i-a31-spi.yaml |  4 +
 .../arm64/boot/dts/allwinner/sun55i-a523.dtsi | 94 +++++++++++++++++++
 .../dts/allwinner/sun55i-t527-orangepi-4a.dts | 15 +++
 drivers/spi/spi-sun6i.c                       | 11 ++-
 4 files changed, 120 insertions(+), 4 deletions(-)

-- 
2.47.3



From wens at kernel.org  Sun Dec 21 03:05:09 2025
From: wens at kernel.org (Chen-Yu Tsai)
Date: Sun, 21 Dec 2025 19:05:09 +0800
Subject: [PATCH 2/4] spi: sun6i: Support A523's SPI controllers
In-Reply-To: <20251221110513.1850535-1-wens@kernel.org>
References: <20251221110513.1850535-1-wens@kernel.org>
Message-ID: <20251221110513.1850535-3-wens@kernel.org>

The A523 has four SPI controllers. One of them supports MIPI DBI mode
in addition to standard SPI.

Compared to older generations, this newer controller now has a combined
counter for the RX FIFO ad buffer levels. In older generations, the
RX buffer level was a separate bitfield in the FIFO status register.

In practice this difference is negligible. The buffer is mostly
invisible to the implementation. If programmed I/O transfers are limited
to the FIFO size, then the contents of the buffer seem to always be
flushed over to the FIFO. For DMA, the DRQ trigger levels are only tied
to the FIFO levels. In all other aspects, the controller is the same as
the one in the R329.

Support the standard SPI mode controllers using the settings for R329.
DBI is left out as there currently is no infrastructure for enabling a
DBI host controller, as was the case for the R329.

Also fold the entry for the R329 to make the style consistent.

Signed-off-by: Chen-Yu Tsai <wens at kernel.org>
---
 drivers/spi/spi-sun6i.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 871dfd3e77be..d1de6c99e762 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -795,10 +795,13 @@ static const struct sun6i_spi_cfg sun50i_r329_spi_cfg = {
 static const struct of_device_id sun6i_spi_match[] = {
 	{ .compatible = "allwinner,sun6i-a31-spi", .data = &sun6i_a31_spi_cfg },
 	{ .compatible = "allwinner,sun8i-h3-spi",  .data = &sun8i_h3_spi_cfg },
-	{
-		.compatible = "allwinner,sun50i-r329-spi",
-		.data = &sun50i_r329_spi_cfg
-	},
+	{ .compatible = "allwinner,sun50i-r329-spi", .data = &sun50i_r329_spi_cfg },
+	/*
+	 * A523's SPI controller has a combined RX buffer + FIFO counter
+	 * at offset 0x400, instead of split buffer count in FIFO status
+	 * register. But in practice we only care about the FIFO level.
+	 */
+	{ .compatible = "allwinner,sun55i-a523-spi", .data = &sun50i_r329_spi_cfg },
 	{}
 };
 MODULE_DEVICE_TABLE(of, sun6i_spi_match);
-- 
2.47.3



From wens at kernel.org  Sun Dec 21 03:05:11 2025
From: wens at kernel.org (Chen-Yu Tsai)
Date: Sun, 21 Dec 2025 19:05:11 +0800
Subject: [PATCH 4/4] arm64: dts: allwinner: t527: orangepi-4a: Enable SPI-NOR flash
In-Reply-To: <20251221110513.1850535-1-wens@kernel.org>
References: <20251221110513.1850535-1-wens@kernel.org>
Message-ID: <20251221110513.1850535-5-wens@kernel.org>

The Orangepi 4A has a SPI-NOR flash connected to spi0 on the PC pins.
The HOLD and WP pins are not connected, and are instead pulled up by the
supply rail.

Enable spi0 and add a device node for the SPI-NOR flash.

Signed-off-by: Chen-Yu Tsai <wens at kernel.org>
---
 .../dts/allwinner/sun55i-t527-orangepi-4a.dts     | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/arch/arm64/boot/dts/allwinner/sun55i-t527-orangepi-4a.dts b/arch/arm64/boot/dts/allwinner/sun55i-t527-orangepi-4a.dts
index 9e6b21cf293e..055be86e5fae 100644
--- a/arch/arm64/boot/dts/allwinner/sun55i-t527-orangepi-4a.dts
+++ b/arch/arm64/boot/dts/allwinner/sun55i-t527-orangepi-4a.dts
@@ -400,6 +400,21 @@ &rtc {
 	assigned-clock-rates = <32768>;
 };
 
+&spi0  {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi0_pc_pins>, <&spi0_cs0_pc_pin>;
+	status = "okay";
+
+	flash at 0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <20000000>;
+		vcc-supply = <&reg_cldo1>;
+	};
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_pb_pins>;
-- 
2.47.3



From wens at kernel.org  Sun Dec 21 03:05:10 2025
From: wens at kernel.org (Chen-Yu Tsai)
Date: Sun, 21 Dec 2025 19:05:10 +0800
Subject: [PATCH 3/4] arm64: dts: allwinner: sun55i: Add SPI controllers
In-Reply-To: <20251221110513.1850535-1-wens@kernel.org>
References: <20251221110513.1850535-1-wens@kernel.org>
Message-ID: <20251221110513.1850535-4-wens@kernel.org>

The A523 family SoCs have four SPI controllers. One of them also
supports DBI mode.

Add device nodes for all of them. Also add pinmux nodes for spi0 on the
PC pins, which is commonly used for SPI-NOR boot flash.

Signed-off-by: Chen-Yu Tsai <wens at kernel.org>
---
 .../arm64/boot/dts/allwinner/sun55i-a523.dtsi | 94 +++++++++++++++++++
 1 file changed, 94 insertions(+)

diff --git a/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi b/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi
index 42dab01e3f56..9335977751e2 100644
--- a/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi
@@ -214,6 +214,43 @@ spdif_out_pi_pin: spdif-pi-pin {
 				allwinner,pinmux = <2>;
 			};
 
+			/omit-if-no-ref/
+			spi0_pc_pins: spi0-pc-pins {
+				pins = "PC2", "PC4", "PC12";
+				function = "spi0";
+				allwinner,pinmux = <4>;
+			};
+
+			/omit-if-no-ref/
+			spi0_cs0_pc_pin: spi0-cs0-pc-pin {
+				pins = "PC3";
+				function = "spi0";
+				allwinner,pinmux = <4>;
+			};
+
+			/omit-if-no-ref/
+			spi0_cs1_pc_pin: spi0-cs1-pc-pin {
+				pins = "PC7";
+				function = "spi0";
+				allwinner,pinmux = <4>;
+			};
+
+			/omit-if-no-ref/
+			spi0_hold_pc_pin: spi0-hold-pc-pin {
+				/* conflicts with eMMC D7 */
+				pins = "PC16";
+				function = "spi0";
+				allwinner,pinmux = <4>;
+			};
+
+			/omit-if-no-ref/
+			spi0_wp_pc_pin: spi0-wp-pc-pin {
+				/* conflicts with eMMC D2 */
+				pins = "PC15";
+				function = "spi0";
+				allwinner,pinmux = <4>;
+			};
+
 			uart0_pb_pins: uart0-pb-pins {
 				pins = "PB9", "PB10";
 				allwinner,pinmux = <2>;
@@ -563,6 +600,49 @@ mmc2: mmc at 4022000 {
 			#size-cells = <0>;
 		};
 
+		spi0: spi at 4025000 {
+			compatible = "allwinner,sun55i-a523-spi";
+			reg = <0x04025000 0x1000>;
+			interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_SPI0>;
+			clock-names = "ahb", "mod";
+			dmas = <&dma 22>, <&dma 22>;
+			dma-names = "rx", "tx";
+			resets = <&ccu RST_BUS_SPI0>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		spi1: spi at 4026000 {
+			compatible = "allwinner,sun55i-a523-spi-dbi",
+				     "allwinner,sun55i-a523-spi";
+			reg = <0x04026000 0x1000>;
+			interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_SPI1>, <&ccu CLK_SPI1>;
+			clock-names = "ahb", "mod";
+			dmas = <&dma 23>, <&dma 23>;
+			dma-names = "rx", "tx";
+			resets = <&ccu RST_BUS_SPI1>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		spi2: spi at 4027000 {
+			compatible = "allwinner,sun55i-a523-spi";
+			reg = <0x04027000 0x1000>;
+			interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_SPI2>, <&ccu CLK_SPI2>;
+			clock-names = "ahb", "mod";
+			dmas = <&dma 24>, <&dma 24>;
+			dma-names = "rx", "tx";
+			resets = <&ccu RST_BUS_SPI2>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
 		usb_otg: usb at 4100000 {
 			compatible = "allwinner,sun55i-a523-musb",
 				     "allwinner,sun8i-a33-musb";
@@ -815,6 +895,20 @@ rtc: rtc at 7090000 {
 			#clock-cells = <1>;
 		};
 
+		r_spi0: spi at 7092000 {
+			compatible = "allwinner,sun55i-a523-spi";
+			reg = <0x07092000 0x1000>;
+			interrupts = <GIC_SPI 172 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&r_ccu CLK_BUS_R_SPI>, <&r_ccu CLK_R_SPI>;
+			clock-names = "ahb", "mod";
+			dmas = <&dma 53>, <&dma 53>;
+			dma-names = "rx", "tx";
+			resets = <&r_ccu RST_BUS_R_SPI>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
 		mcu_ccu: clock-controller at 7102000 {
 			compatible = "allwinner,sun55i-a523-mcu-ccu";
 			reg = <0x7102000 0x200>;
-- 
2.47.3



From lkp at intel.com  Sun Dec 21 03:09:48 2025
From: lkp at intel.com (kernel test robot)
Date: Sun, 21 Dec 2025 19:09:48 +0800
Subject: [PATCHv5 bpf-next 9/9] bpf,x86: Use single ftrace_ops for direct
 calls
In-Reply-To: <20251215211402.353056-10-jolsa@kernel.org>
References: <20251215211402.353056-10-jolsa@kernel.org>
Message-ID: <202512211826.gtdm52TX-lkp@intel.com>

Hi Jiri,

kernel test robot noticed the following build errors:

[auto build test ERROR on bpf-next/master]

url:    https://github.com/intel-lab-lkp/linux/commits/Jiri-Olsa/ftrace-bpf-Remove-FTRACE_OPS_FL_JMP-ftrace_ops-flag/20251216-052916
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master
patch link:    https://lore.kernel.org/r/20251215211402.353056-10-jolsa%40kernel.org
patch subject: [PATCHv5 bpf-next 9/9] bpf,x86: Use single ftrace_ops for direct calls
config: arc-allyesconfig (https://download.01.org/0day-ci/archive/20251221/202512211826.gtdm52TX-lkp at intel.com/config)
compiler: arc-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251221/202512211826.gtdm52TX-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512211826.gtdm52TX-lkp at intel.com/

All errors (new ones prefixed by >>):

   kernel/bpf/trampoline.c: In function 'unregister_fentry':
>> kernel/bpf/trampoline.c:367:23: error: implicit declaration of function 'direct_ops_del'; did you mean 'direct_ops_free'? [-Wimplicit-function-declaration]
     367 |                 ret = direct_ops_del(tr, old_addr);
         |                       ^~~~~~~~~~~~~~
         |                       direct_ops_free
   kernel/bpf/trampoline.c: In function 'modify_fentry':
>> kernel/bpf/trampoline.c:381:23: error: implicit declaration of function 'direct_ops_mod'; did you mean 'direct_ops_free'? [-Wimplicit-function-declaration]
     381 |                 ret = direct_ops_mod(tr, new_addr, lock_direct_mutex);
         |                       ^~~~~~~~~~~~~~
         |                       direct_ops_free
   kernel/bpf/trampoline.c: In function 'register_fentry':
>> kernel/bpf/trampoline.c:404:23: error: implicit declaration of function 'direct_ops_add'; did you mean 'direct_ops_free'? [-Wimplicit-function-declaration]
     404 |                 ret = direct_ops_add(tr, new_addr);
         |                       ^~~~~~~~~~~~~~
         |                       direct_ops_free


vim +367 kernel/bpf/trampoline.c

   360	
   361	static int unregister_fentry(struct bpf_trampoline *tr, u32 orig_flags,
   362				     void *old_addr)
   363	{
   364		int ret;
   365	
   366		if (tr->func.ftrace_managed)
 > 367			ret = direct_ops_del(tr, old_addr);
   368		else
   369			ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr, NULL);
   370	
   371		return ret;
   372	}
   373	
   374	static int modify_fentry(struct bpf_trampoline *tr, u32 orig_flags,
   375				 void *old_addr, void *new_addr,
   376				 bool lock_direct_mutex)
   377	{
   378		int ret;
   379	
   380		if (tr->func.ftrace_managed) {
 > 381			ret = direct_ops_mod(tr, new_addr, lock_direct_mutex);
   382		} else {
   383			ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr,
   384							   new_addr);
   385		}
   386		return ret;
   387	}
   388	
   389	/* first time registering */
   390	static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
   391	{
   392		void *ip = tr->func.addr;
   393		unsigned long faddr;
   394		int ret;
   395	
   396		faddr = ftrace_location((unsigned long)ip);
   397		if (faddr) {
   398			if (!tr->fops)
   399				return -ENOTSUPP;
   400			tr->func.ftrace_managed = true;
   401		}
   402	
   403		if (tr->func.ftrace_managed) {
 > 404			ret = direct_ops_add(tr, new_addr);
   405		} else {
   406			ret = bpf_trampoline_update_fentry(tr, 0, NULL, new_addr);
   407		}
   408	
   409		return ret;
   410	}
   411	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From josua at solid-run.com  Sun Dec 21 03:28:50 2025
From: josua at solid-run.com (Josua Mayer)
Date: Sun, 21 Dec 2025 12:28:50 +0100
Subject: [PATCH v5 1/7] dt-bindings: arm: fsl: Add various solidrun i.mx8m
 boards
In-Reply-To: <20251221-imx8mp-hb-iiot-v5-0-4a4dad916348@solid-run.com>
References: <20251221-imx8mp-hb-iiot-v5-0-4a4dad916348@solid-run.com>
Message-ID: <20251221-imx8mp-hb-iiot-v5-1-4a4dad916348@solid-run.com>

Add bindings for various SolidRun boards:

- i.MX8MP HummingBoard IIoT - based on the SolidRun i.MX8M Plus SoM
- SolidSense N8 - single-board design with i.MX8M Nano
- i.MX8M Mini System on Module
- i.MX8M Mini HummingBoard Ripple

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
Signed-off-by: Josua Mayer <josua at solid-run.com>
---
 Documentation/devicetree/bindings/arm/fsl.yaml | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
index 68a2d5fecc43b..97144a52d5a67 100644
--- a/Documentation/devicetree/bindings/arm/fsl.yaml
+++ b/Documentation/devicetree/bindings/arm/fsl.yaml
@@ -1041,6 +1041,13 @@ properties:
           - const: phytec,imx8mm-phycore-som        # phyCORE-i.MX8MM SoM
           - const: fsl,imx8mm
 
+      - description: SolidRun i.MX8MM SoM based boards
+        items:
+          - enum:
+              - solidrun,imx8mm-hummingboard-ripple # SolidRun i.MX8MM SoM on HummingBoard Ripple
+          - const: solidrun,imx8mm-sr-som
+          - const: fsl,imx8mm
+
       - description: Variscite VAR-SOM-MX8MM based boards
         items:
           - const: variscite,var-som-mx8mm-symphony
@@ -1069,6 +1076,7 @@ properties:
               - fsl,imx8mn-ddr4-evk       # i.MX8MN DDR4 EVK Board
               - fsl,imx8mn-evk            # i.MX8MN LPDDR4 EVK Board
               - gw,imx8mn-gw7902          # i.MX8MM Gateworks Board
+              - solidrun,solidsense-n8-compact # SolidRun SolidSense N8 Compact
           - const: fsl,imx8mn
 
       - description: Variscite VAR-SOM-MX8MN based boards
@@ -1208,6 +1216,7 @@ properties:
         items:
           - enum:
               - solidrun,imx8mp-cubox-m             # SolidRun i.MX8MP SoM on CuBox-M
+              - solidrun,imx8mp-hummingboard-iiot   # SolidRun i.MX8MP SoM on HummingBoard IIoT
               - solidrun,imx8mp-hummingboard-mate   # SolidRun i.MX8MP SoM on HummingBoard Mate
               - solidrun,imx8mp-hummingboard-pro    # SolidRun i.MX8MP SoM on HummingBoard Pro
               - solidrun,imx8mp-hummingboard-pulse  # SolidRun i.MX8MP SoM on HummingBoard Pulse

-- 
2.51.0




From josua at solid-run.com  Sun Dec 21 03:28:49 2025
From: josua at solid-run.com (Josua Mayer)
Date: Sun, 21 Dec 2025 12:28:49 +0100
Subject: [PATCH v5 0/7] arm64: dts: add description for solidrun imx8mp
 hummingboard-iiot
Message-ID: <20251221-imx8mp-hb-iiot-v5-0-4a4dad916348@solid-run.com>

This patchset mainly adds description for 3 SolidRun boards:
- i.MX8MP Hummingboard IIoT
- SolidSense N8 Compact
- i.MX8MM Hummingboard Ripple

This includes dt bindings and a range of bug-fixes:

- dt bindings for the boards
- fix to dsi panel bindings referncing panel-common and adding port
  property
- cosmetic fix to some  solidrun imx8mp boards for regulator gpio
   polarity
- fix dsi hdmi bridge on hummingboard pulse
- compile dtbs with symbols to support overlays
- gpiod_set_value _can_sleep conversion for panel and touchscreen
   drivers

Open Questions:

- How to describe HX3 USB-2.0/3.0 Hub placed on a USB-2.0-only Bus
  (affects imx8mm-hummingboard-ripple.dts)
- Is "description for" implied not only on dt-bindings patches, but also
  dts? E.g. is this commit subject acceptable?:
  "arm64: dts: add solidrun solidsense-n8 board"

Signed-off-by: Josua Mayer <josua at solid-run.com>
---
Changes in v5:
- rebased on v6.19-rc1
- dropped ilitek-ts patch already picked into input-next
- solidsense-n8 / imx8mm-sr-som: drop untested wake-on-lan support
- hb-iiot: disable software unsupported rtc timer irq
- hb-iiot: fix wrong pins selected for uart4
- Link to v4: https://lore.kernel.org/r/20251201-imx8mp-hb-iiot-v4-0-53a4cd6c21bf at solid-run.com

Changes in v4:
- dropped patches already picked into drm-misc-next
- ronbo panel: picked up reviewed-by tag
  (Reviewed-by: Neil Armstrong <neil.armstrong at linaro.org>)
- ilitek-ts: changed mdelay calls on reset path to fsleep
  (Note Dmitry requested msleep/usleep_range)
  (Reported-by: Dmitry Torokhov <dmitry.torokhov at gmail.com>)
- changed hummingboard-iiot tpm irq type to level
- Link to v3: https://lore.kernel.org/r/20251117-imx8mp-hb-iiot-v3-0-bf1a4cf5fa8e at solid-run.com

Changes in v3:
- sinmplified language in gpiod_can_sleep patches.
  (Reported-By: Frank Li <Frank.li at nxp.com>)
- collected ack on winstar lvds panel binding
  (Acked-by: Conor Dooley <conor.dooley at microchip.com>)
- Link to v2: https://lore.kernel.org/r/20251107-imx8mp-hb-iiot-v2-0-d8233ded999e at solid-run.com

Changes in v2:
- fix spelling mistakes in commit descriptions.
- remove redundant "binding for" from subject:
  https://elixir.bootlin.com/linux/v6.17-rc3/source/Documentation/devicetree/bindings/submitting-patches.rst
  (Reported-by: Krzysztof Kozlowski <krzk at kernel.org>)
- remove one useless comment from imx8mm-sr-som.dtsi to fix long line
  warning.
- change ronbo panel binding to inherit panel-common and switch
  additionalProperties to unevaluatedProperties.
  (Reported-by: Krzysztof Kozlowski <krzk at kernel.org>)
- add dt binding for winstar lvds panel
- fix dtbs_check for dsi & lvds panel addons
- change n8 board dts comment-style in header
- collected ack on solidrun boards bindings patch (patch 1 in the series)
  (Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>)
- added standard led label property to hb-iiot multi-purpose leds
  ensuring consistent names in case lp5562 driver starts using it.
- Link to v1: https://lore.kernel.org/r/20251027-imx8mp-hb-iiot-v1-0-683f86357818 at solid-run.com

---
Josua Mayer (7):
      dt-bindings: arm: fsl: Add various solidrun i.mx8m boards
      arm64: dts: imx8mp-hummingboard-pulse/cubox-m: fix vmmc gpio polarity
      arm64: dts: imx8mp-hummingboard-pulse: fix mini-hdmi dsi port reference
      arm64: dts: imx8mp-sr-som: build dtbs with symbols for overlay support
      arm64: dts: add description for solidrun imx8mp hummingboard-iiot
      arm64: dts: add description for solidrun solidsense-n8 board
      arm64: dts: add description for solidrun i.mx8mm som and evb

 Documentation/devicetree/bindings/arm/fsl.yaml     |   9 +
 arch/arm64/boot/dts/freescale/Makefile             |  15 +
 .../dts/freescale/imx8mm-hummingboard-ripple.dts   | 335 ++++++++
 arch/arm64/boot/dts/freescale/imx8mm-sr-som.dtsi   | 394 ++++++++++
 .../dts/freescale/imx8mn-solidsense-n8-compact.dts | 851 +++++++++++++++++++++
 arch/arm64/boot/dts/freescale/imx8mp-cubox-m.dts   |   2 +-
 ...hummingboard-iiot-panel-dsi-WJ70N3TYJHMNG0.dtso |  69 ++
 ...ummingboard-iiot-panel-lvds-WF70A8SYJHLNGA.dtso | 105 +++
 .../imx8mp-hummingboard-iiot-rs485-a.dtso          |  18 +
 .../imx8mp-hummingboard-iiot-rs485-b.dtso          |  18 +
 .../dts/freescale/imx8mp-hummingboard-iiot.dts     | 719 +++++++++++++++++
 .../imx8mp-hummingboard-pulse-common.dtsi          |   2 +-
 .../imx8mp-hummingboard-pulse-mini-hdmi.dtsi       |  11 +-
 13 files changed, 2539 insertions(+), 9 deletions(-)
---
base-commit: 0f54ecdab3be8e6161f42980617d2d9677095999
change-id: 20251026-imx8mp-hb-iiot-525b03beea62

Best regards,
-- 
Josua Mayer <josua at solid-run.com>




From josua at solid-run.com  Sun Dec 21 03:28:52 2025
From: josua at solid-run.com (Josua Mayer)
Date: Sun, 21 Dec 2025 12:28:52 +0100
Subject: [PATCH v5 3/7] arm64: dts: imx8mp-hummingboard-pulse: fix
 mini-hdmi dsi port reference
In-Reply-To: <20251221-imx8mp-hb-iiot-v5-0-4a4dad916348@solid-run.com>
References: <20251221-imx8mp-hb-iiot-v5-0-4a4dad916348@solid-run.com>
Message-ID: <20251221-imx8mp-hb-iiot-v5-3-4a4dad916348@solid-run.com>

imx8mp.dtsi includes a default port at 1 node with an empty placeholder
endpoint intended for linking to a dsi bridge or panel.
HummingBoard Pulse mini-hdmi dtsi added and linked hdmi brodge to yet
another endpoint.

This duplicate endpoint can cause dsi_attach to fail.

Remove the duplicate node and link to the one defined in soc dtsi.
Further remove the unnecessary attach-bridge property.

Fixes: 2a222aa2bee9 ("arm64: dts: add description for solidrun imx8mp hummingboard variants")
Signed-off-by Josua Mayer <josua at solid-run.com>
---
 .../dts/freescale/imx8mp-hummingboard-pulse-mini-hdmi.dtsi    | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-mini-hdmi.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-mini-hdmi.dtsi
index 46916ddc05335..0e5f4607c7c1b 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-mini-hdmi.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-mini-hdmi.dtsi
@@ -41,7 +41,7 @@ port at 0 {
 				reg = <0>;
 
 				adv7535_from_dsim: endpoint {
-					remote-endpoint = <&dsim_to_adv7535>;
+					remote-endpoint = <&mipi_dsi_out>;
 				};
 			};
 
@@ -71,11 +71,8 @@ &lcdif1 {
 &mipi_dsi {
 	samsung,esc-clock-frequency = <10000000>;
 	status = "okay";
+};
 
-	port at 1 {
-		dsim_to_adv7535: endpoint {
-			remote-endpoint = <&adv7535_from_dsim>;
-			attach-bridge;
-		};
-	};
+&mipi_dsi_out {
+	remote-endpoint = <&adv7535_from_dsim>;
 };

-- 
2.51.0




From josua at solid-run.com  Sun Dec 21 03:28:51 2025
From: josua at solid-run.com (Josua Mayer)
Date: Sun, 21 Dec 2025 12:28:51 +0100
Subject: [PATCH v5 2/7] arm64: dts: imx8mp-hummingboard-pulse/cubox-m: fix
 vmmc gpio polarity
In-Reply-To: <20251221-imx8mp-hb-iiot-v5-0-4a4dad916348@solid-run.com>
References: <20251221-imx8mp-hb-iiot-v5-0-4a4dad916348@solid-run.com>
Message-ID: <20251221-imx8mp-hb-iiot-v5-2-4a4dad916348@solid-run.com>

Fix the polarity in vmmc regulator node for the gpio from active-high to
active-low. This is a cosmetic change as regulator default to active-low
unless property enable-active-high was also specified - ignoring the
flag on gpio handle.

Fixes: a009c0c66ecb ("arm64: dts: add description for solidrun imx8mp som and cubox-m")
Fixes: 2a222aa2bee9 ("arm64: dts: add description for solidrun imx8mp hummingboard variants")
Signed-off-by: Josua Mayer <josua at solid-run.com>
---
 arch/arm64/boot/dts/freescale/imx8mp-cubox-m.dts                    | 2 +-
 arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-common.dtsi | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-cubox-m.dts b/arch/arm64/boot/dts/freescale/imx8mp-cubox-m.dts
index 8290f187b79fd..7bc213499f094 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-cubox-m.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-cubox-m.dts
@@ -68,7 +68,7 @@ vmmc: regulator-mmc {
 		regulator-name = "vmmc";
 		regulator-min-microvolt = <3300000>;
 		regulator-max-microvolt = <3300000>;
-		gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+		gpio = <&gpio2 19 GPIO_ACTIVE_LOW>;
 		startup-delay-us = <250>;
 	};
 };
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-common.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-common.dtsi
index 825ad6a2ba14e..5b8c8489713c4 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-common.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-common.dtsi
@@ -73,7 +73,7 @@ vmmc: regulator-mmc {
 		regulator-name = "vmmc";
 		regulator-min-microvolt = <3300000>;
 		regulator-max-microvolt = <3300000>;
-		gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+		gpio = <&gpio2 19 GPIO_ACTIVE_LOW>;
 		startup-delay-us = <250>;
 	};
 

-- 
2.51.0




From josua at solid-run.com  Sun Dec 21 03:28:53 2025
From: josua at solid-run.com (Josua Mayer)
Date: Sun, 21 Dec 2025 12:28:53 +0100
Subject: [PATCH v5 4/7] arm64: dts: imx8mp-sr-som: build dtbs with symbols
 for overlay support
In-Reply-To: <20251221-imx8mp-hb-iiot-v5-0-4a4dad916348@solid-run.com>
References: <20251221-imx8mp-hb-iiot-v5-0-4a4dad916348@solid-run.com>
Message-ID: <20251221-imx8mp-hb-iiot-v5-4-4a4dad916348@solid-run.com>

Build all dtbs based on SolidRun i.MX8MP SoM with symbols (adding -@ to
dtc flags) to enable support for device-tree addons.

The SoM has a camera connector for basler cameras that can be enabled by
downstream dtbo.
Hence by extension all boards based on this SoM should support addons.

Signed-off-by: Josua Mayer <josua at solid-run.com>
---
 arch/arm64/boot/dts/freescale/Makefile | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index f30d3fd724d0c..c4c6fd6de9637 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -203,6 +203,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mp-aristainetos3-helios-lvds.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-aristainetos3-proton2s.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-beacon-kit.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-cubox-m.dtb
+DTC_FLAGS_imx8mp-cubox-m := -@
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-data-modul-edm-sbc.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-debix-model-a.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-debix-som-a-bmb-08.dtb
@@ -213,9 +214,13 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mp-dhcom-picoitx.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-edm-g-wb.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-mate.dtb
+DTC_FLAGS_imx8mp-hummingboard-mate := -@
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-pro.dtb
+DTC_FLAGS_imx8mp-hummingboard-pro := -@
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-pulse.dtb
+DTC_FLAGS_imx8mp-hummingboard-pulse := -@
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-ripple.dtb
+DTC_FLAGS_imx8mp-hummingboard-ripple := -@
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-icore-mx8mp-edimm2.2.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-iota2-lumpy.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-kontron-bl-osm-s.dtb

-- 
2.51.0




From josua at solid-run.com  Sun Dec 21 03:28:55 2025
From: josua at solid-run.com (Josua Mayer)
Date: Sun, 21 Dec 2025 12:28:55 +0100
Subject: [PATCH v5 6/7] arm64: dts: add description for solidrun
 solidsense-n8 board
In-Reply-To: <20251221-imx8mp-hb-iiot-v5-0-4a4dad916348@solid-run.com>
References: <20251221-imx8mp-hb-iiot-v5-0-4a4dad916348@solid-run.com>
Message-ID: <20251221-imx8mp-hb-iiot-v5-6-4a4dad916348@solid-run.com>

Add description for the SolidRun SolidSense N8 Compact.
The board is designed around the i.MX8MN SoC and comes as a complete
product including enclosure and labels.

Features:
- USB-2.0 Type A connector
- 1Gbps RJ45 Ethernet with PoE
- microSD connector
- eMMC
- Cellular Modem + SIM holder
- WiFi + Bluetooth
- RS485
- CAN
- 802.15.1 radio
- supercapacitor backup power supply

This is a headless design without display.
The board includes an internal expansion connector for daughterboards
which may be described by dt addon.

The supercap is not currently described due to lack of suitable bindings.
Vendor BSP uses gpio-keys driver to trigger shutdown on power loss.

Signed-off-by: Josua Mayer <josua at solid-run.com>
---
 arch/arm64/boot/dts/freescale/Makefile             |   2 +
 .../dts/freescale/imx8mn-solidsense-n8-compact.dts | 851 +++++++++++++++++++++
 2 files changed, 853 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index 97e6000154640..73c3d234149cd 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -187,6 +187,8 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mn-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-ddr3l-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-ddr4-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-rve-gateway.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mn-solidsense-n8-compact.dtb
+DTC_FLAGS_imx8mn-solidsense-n8-compact += -@
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-tqma8mqnl-mba8mx.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-var-som-symphony.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-venice-gw7902.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-solidsense-n8-compact.dts b/arch/arm64/boot/dts/freescale/imx8mn-solidsense-n8-compact.dts
new file mode 100644
index 0000000000000..1d512cf7422ff
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mn-solidsense-n8-compact.dts
@@ -0,0 +1,851 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Device Tree file for SolidSense N8 Compact
+ *
+ * Copyright 2024 Josua Mayer <josua at solid-run.com>
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/leds/common.h>
+
+#include "imx8mn.dtsi"
+
+/ {
+	model = "SolidRun SolidSense N8 Compact";
+	compatible = "solidrun,solidsense-n8-compact", "fsl,imx8mn";
+
+	aliases {
+		gpio5 = &expander;
+		rtc0 = &rtc;
+		rtc1 = &snvs_rtc;
+		usb0 = &usbotg1;
+		watchdog0 = &wdog1;
+		watchdog1 = &rtc;
+	};
+
+	chosen {
+		stdout-path = &uart2;
+	};
+
+	/* LED labels based on enclosure, schematic names differ. */
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&led_pins>;
+
+		/* D20 */
+		led1 {
+			label = "led1";
+			gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>;
+			default-state = "off";
+		};
+
+		/* D18 */
+		led2 {
+			label = "led2";
+			gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>;
+			default-state = "off";
+		};
+
+		/* D19 */
+		led3 {
+			label = "led3";
+			gpios = <&gpio1 12 GPIO_ACTIVE_HIGH>;
+			default-state = "off";
+		};
+	};
+
+	memory at 40000000 {
+		reg = <0x0 0x40000000 0 0x80000000>;
+		device_type = "memory";
+	};
+
+	reg_modem_vbat: regulator-modem-vbat {
+		compatible = "regulator-fixed";
+		regulator-name = "modem-vbat";
+		pinctrl-names = "default";
+		pinctrl-0 = <&regulator_modem_vbat_pins>;
+		regulator-min-microvolt = <3800000>;
+		regulator-max-microvolt = <3800000>;
+		gpio = <&gpio3 25 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-always-on;
+	};
+
+	/* power to lte modems behind hub ports 2/3 */
+	reg_modem_vbus: regulator-modem-vbus {
+		compatible = "regulator-fixed";
+		regulator-name = "modem-vbus";
+		pinctrl-names = "default";
+		pinctrl-0 = <&regulator_modem_vbus_pins>;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&gpio5 4 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-always-on;
+	};
+
+	/* power to usb hub, and type-a behind hub port 1 */
+	reg_usb1_vbus: regulator-usb1-vbus {
+		compatible = "regulator-fixed";
+		regulator-name = "usb1-vbus";
+		pinctrl-names = "default";
+		pinctrl-0 = <&regulator_usb1_vbus_pins>;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&gpio5 5 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_vdd_1v8: regulator-vdd-1v8 {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd-1v8";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	reg_vdd_3v3: regulator-vdd-3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd-3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	reg_usdhc2_vmmc: regulator-usdhc2-vmmc {
+		compatible = "regulator-fixed";
+		regulator-name = "usdhc2-vmmc";
+		pinctrl-names = "default";
+		pinctrl-0 = <&regulator_usdhc2_vmmc_pins>;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		vin-supply = <&reg_vdd_3v3>;
+		gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		off-on-delay-us = <250>;
+	};
+
+	rfkill {
+		compatible = "rfkill-gpio";
+		label = "rfkill-wwan";
+		radio-type = "wwan";
+		pinctrl-names = "default";
+		pinctrl-0 = <&modem_pins>;
+		/* rfkill-gpio inverts internally */
+		shutdown-gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
+	};
+
+	usdhc1_pwrseq: usdhc1-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&A53_0 {
+	cpu-supply = <&buck2_reg>;
+};
+
+&A53_1 {
+	cpu-supply = <&buck2_reg>;
+};
+
+&A53_2 {
+	cpu-supply = <&buck2_reg>;
+};
+
+&A53_3 {
+	cpu-supply = <&buck2_reg>;
+};
+
+&ddrc {
+	operating-points-v2 = <&ddrc_opp_table>;
+
+	ddrc_opp_table: opp-table {
+		compatible = "operating-points-v2";
+
+		opp-266500000 {
+			opp-hz = /bits/ 64 <266500000>;
+		};
+
+		opp-600000000 {
+			opp-hz = /bits/ 64 <600000000>;
+		};
+	};
+};
+
+&ecspi2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&ecspi2_pins>;
+	/* native chip-select causes reading 0xffffffff */
+	cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
+	num-cs = <1>;
+	status = "okay";
+
+	can at 0 {
+		compatible = "microchip,mcp2518fd";
+		reg = <0>;
+		spi-max-frequency = <20000000>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&can_pins>;
+		interrupt-parent = <&gpio5>;
+		interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
+		clocks = <&clk IMX8MN_CLK_CLKOUT1>;
+		/* generate 8MHz clock from soc-internal 24mhz reference */
+		assigned-clocks = <&clk IMX8MN_CLK_CLKOUT1_SEL>,
+			  <&clk IMX8MN_CLK_CLKOUT1_DIV>;
+		assigned-clock-rates = <0>, <8000000>;
+		assigned-clock-parents = <&clk IMX8MN_CLK_24M>, <0>;
+	};
+};
+
+&fec1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&fec1_pins>;
+	phy-mode = "rgmii-id";
+	phy-handle = <&phy4>;
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		/*
+		 * Depending on board revision two different phys are used:
+		 * - v1.1: atheros phy at address 4
+		 * - v1.2+: analog devices phy at address 0
+		 * Configure first version by default.
+		 * On v1.2 and later, U-Boot will enable the correct phy
+		 * based on runtime detection and patch dtb accordingly.
+		 */
+
+		/* ADIN1300 */
+		phy0: ethernet-phy at 0 {
+			reg = <0>;
+			reset-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>;
+			reset-assert-us = <10>;
+			reset-deassert-us = <5000>;
+			interrupt-parent = <&gpio1>;
+			interrupts = <10 IRQ_TYPE_LEVEL_LOW>;
+			adi,link-st-polarity = <GPIO_ACTIVE_LOW>;
+			adi,led-polarity = <GPIO_ACTIVE_LOW>;
+			status = "disabled";
+
+			leds {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				led at 0 {
+					reg = <0>;
+					color = <LED_COLOR_ID_YELLOW>;
+					function = LED_FUNCTION_LAN;
+					default-state = "keep";
+					active-low;
+				};
+			};
+		};
+
+		/* AR8035 */
+		phy4: ethernet-phy at 4 {
+			reg = <4>;
+			reset-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>;
+			reset-assert-us = <10000>;
+			status = "okay";
+		};
+	};
+};
+
+&gpio5 {
+	usb-hub-reset-hog {
+		gpio-hog;
+		gpios = <3 GPIO_ACTIVE_LOW>;
+		output-low; /* deasserted */
+		line-name = "usb-hub-reset";
+	};
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	status = "okay";
+
+	pmic at 4b {
+		compatible = "rohm,bd71847";
+		reg = <0x4b>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pmic_pins>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+		rohm,reset-snvs-powered;
+
+		#clock-cells = <0>;
+		clocks = <&osc_32k>;
+		clock-output-names = "clk-32k-out";
+
+		regulators {
+			BUCK1 {
+				// supplies soc vdd, soc mipi vdd @ 0.9V
+				regulator-name = "buck1";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <1250>;
+				rohm,dvs-run-voltage = <850000>;
+				rohm,dvs-suspend-voltage = <750000>;
+			};
+
+			buck2_reg: BUCK2 {
+				regulator-name = "buck2";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <1250>;
+				rohm,dvs-run-voltage = <1000000>;
+				rohm,dvs-idle-voltage = <900000>;
+				rohm,dvs-suspend-voltage = <0>;
+			};
+
+			BUCK3 {
+				// BUCK5 in datasheet
+				// output floating
+				regulator-name = "buck3";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1350000>;
+			};
+
+			BUCK4 {
+				// BUCK6 in datasheet
+				// supplies ldo3, ldo5, muxsw
+				regulator-name = "buck4";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			BUCK5 {
+				// BUCK7 in datasheet
+				// supplies ldo4, ldo6, muxsw
+				// enables dram vpp @ 2.5V
+				regulator-name = "buck5";
+				regulator-min-microvolt = <1605000>;
+				regulator-max-microvolt = <1995000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			BUCK6 {
+				// BUCK8 in datasheet
+				// supplies dram @ 1.2V
+				regulator-name = "buck6";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1400000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			LDO1 {
+				// supplies soc snvs @ 1.8V
+				regulator-name = "ldo1";
+				regulator-min-microvolt = <1600000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			LDO2 {
+				// supplies soc snvs @ 0.8V
+				regulator-name = "ldo2";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <900000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			LDO3 {
+				// supplies soc vdd @ 1.8V
+				regulator-name = "ldo3";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			LDO4 {
+				// output floating
+				regulator-name = "ldo4";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1800000>;
+			};
+
+			LDO5 {
+				// output floating
+				regulator-name = "ldo5";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <3300000>;
+			};
+
+			LDO6 {
+				// supplies soc vdd mipi @ 1.2V
+				regulator-name = "ldo6";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+		};
+	};
+};
+
+&i2c2 {
+	/*
+	 * routed to various connectors:
+	 * - basler camera (CON2)
+	 * - touchscreen (J3)
+	 * - expansion connector (J14)
+	 */
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_pins>;
+	status = "okay";
+};
+
+&i2c3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c3_pins>;
+	status = "okay";
+
+	expander: gpio at 20 {
+		compatible = "ti,tca6408";
+		reg = <0x20>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&gpio_expander_pins>;
+		reset-gpios = <&gpio3 16 GPIO_ACTIVE_LOW>;
+		interrupt-parent = <&gpio2>;
+		interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		gpio-line-names = "SYSGD", "PFO#", "CAPGD", "CAPFLT#",
+				  "CHGEN#", "BSTEN#", "", "";
+	};
+
+	light-sensor at 44 {
+		compatible = "isil,isl29023";
+		reg = <0x44>;
+	};
+
+	accelerometer at 53 {
+		compatible = "adi,adxl345";
+		reg = <0x53>;
+	};
+
+	/* battery-charger at 68 */
+
+	rtc: rtc at 69 {
+		compatible = "abracon,abx80x";
+		reg = <0x69>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&rtc_pins>;
+		abracon,tc-diode = "schottky";
+		abracon,tc-resistor = <3>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
+	};
+};
+
+&i2c4 {
+	/* routed to expansion connector (J14) */
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c4_pins>;
+	status = "okay";
+};
+
+&iomuxc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&tamper_pins>, <&usb_hub_pins>;
+
+	ieee802151_radio_pins: pinctrl-ieee802151-radio-grp {
+		fsl,pins = <
+			/* RESETN */
+			MX8MN_IOMUXC_GPIO1_IO05_GPIO1_IO5	0x0
+			/* VDD_EN */
+			MX8MN_IOMUXC_GPIO1_IO06_GPIO1_IO6	0x0
+			/* SWDCLK */
+			MX8MN_IOMUXC_GPIO1_IO14_GPIO1_IO14	0x0
+			/* SDIO */
+			MX8MN_IOMUXC_GPIO1_IO15_GPIO1_IO15	0x0
+		>;
+	};
+
+	can_pins: pinctrl-can-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SAI3_TXD_GPIO5_IO1		0x140
+		>;
+	};
+
+	ecspi2_pins: pinctrl-ecspi2-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_ECSPI2_SCLK_ECSPI2_SCLK	0x96
+			MX8MN_IOMUXC_ECSPI2_MOSI_ECSPI2_MOSI	0x1d6
+			MX8MN_IOMUXC_ECSPI2_MISO_ECSPI2_MISO	0x1d6
+			MX8MN_IOMUXC_ECSPI2_SS0_GPIO5_IO13	0x1d6
+		>;
+	};
+
+	fec1_pins: pinctrl-fec1-grp {
+		/*
+		 * Some pins are sampled at phy reset to apply configuration:
+		 * - AR803x PHY (revision 1.1)
+		 *   - RXD[1:0]: phy address bits [1:0]
+		 *   - RXD[3:2],RX_CTL: mac interface select bits 3,1,0
+		 * - ADIN1300 PHY (revision 1.2 or later)
+		 *   - RXD[3:0]: phy address bits [3:0]
+		 *   - RX_CTL,RXC: mac interface select bits 1,0
+		 * SoC enables pull-down at reset, PHYs have internal
+		 * pull-down, so pinmux may unset pull-enable.
+		 */
+		fsl,pins = <
+			MX8MN_IOMUXC_ENET_MDC_ENET1_MDC			0x2
+			MX8MN_IOMUXC_ENET_MDIO_ENET1_MDIO		0x2
+			MX8MN_IOMUXC_ENET_TD3_ENET1_RGMII_TD3		0x1e
+			MX8MN_IOMUXC_ENET_TD2_ENET1_RGMII_TD2		0x1e
+			MX8MN_IOMUXC_ENET_TD1_ENET1_RGMII_TD1		0x1e
+			MX8MN_IOMUXC_ENET_TD0_ENET1_RGMII_TD0		0x1e
+			/* RD[3:0] sampled at phy reset for address bits [3:0] */
+			MX8MN_IOMUXC_ENET_RD3_ENET1_RGMII_RD3		0x90
+			MX8MN_IOMUXC_ENET_RD2_ENET1_RGMII_RD2		0x90
+			MX8MN_IOMUXC_ENET_RD1_ENET1_RGMII_RD1		0x90
+			MX8MN_IOMUXC_ENET_RD0_ENET1_RGMII_RD0		0x90
+			MX8MN_IOMUXC_ENET_TXC_ENET1_RGMII_TXC		0x10
+			MX8MN_IOMUXC_ENET_RXC_ENET1_RGMII_RXC		0x90
+			MX8MN_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x90
+			MX8MN_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x10
+			/* phy reset */
+			MX8MN_IOMUXC_SAI5_RXFS_GPIO3_IO19		0x0
+			/* phy interrupt */
+			MX8MN_IOMUXC_GPIO1_IO10_GPIO1_IO10		0x140
+		>;
+	};
+
+	gpio_expander_pins: pinctrl-gpio-expander-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_NAND_READY_B_GPIO3_IO16	0x140
+			MX8MN_IOMUXC_SD1_STROBE_GPIO2_IO11	0x140
+		>;
+	};
+
+	i2c1_pins: pinctrl-i2c1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C1_SCL_I2C1_SCL		0x400001c2
+			MX8MN_IOMUXC_I2C1_SDA_I2C1_SDA		0x400001c2
+		>;
+	};
+
+	i2c2_pins: pinctrl-i2c2-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C2_SCL_I2C2_SCL		0x400001c2
+			MX8MN_IOMUXC_I2C2_SDA_I2C2_SDA		0x400001c2
+		>;
+	};
+
+	i2c3_pins: pinctrl-i2c3-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C3_SCL_I2C3_SCL		0x400001c2
+			MX8MN_IOMUXC_I2C3_SDA_I2C3_SDA		0x400001c2
+		>;
+	};
+
+	i2c4_pins: pinctrl-i2c4-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C4_SCL_I2C4_SCL		0x400001c2
+			MX8MN_IOMUXC_I2C4_SDA_I2C4_SDA		0x400001c2
+		>;
+	};
+
+	led_pins: pinctrl-led-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_GPIO1_IO11_GPIO1_IO11	0x100
+			MX8MN_IOMUXC_GPIO1_IO12_GPIO1_IO12	0x100
+			MX8MN_IOMUXC_GPIO1_IO13_GPIO1_IO13	0x100
+		>;
+	};
+
+	modem_pins: pinctrl-modem-grp {
+		fsl,pins = <
+			/* RESET_N: modem-internal pull-down */
+			MX8MN_IOMUXC_GPIO1_IO07_GPIO1_IO7	0x0
+			/* PWRKEY: pull-down ensures always-on */
+			MX8MN_IOMUXC_GPIO1_IO08_GPIO1_IO8	0x100
+		>;
+	};
+
+	pmic_pins: pinctrl-pmic-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_GPIO1_IO03_GPIO1_IO3	0x140
+		>;
+	};
+
+	regulator_modem_vbat_pins: pinctrl-regulator-modem-vbat-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SAI5_MCLK_GPIO3_IO25	0x0
+		>;
+	};
+
+	regulator_modem_vbus_pins: pinctrl-regulator-modem-vbus-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SPDIF_RX_GPIO5_IO4		0x0
+		>;
+	};
+
+	regulator_usb1_vbus_pins: pinctrl-regulator-usb1-vbus-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SPDIF_EXT_CLK_GPIO5_IO5	0x0
+		>;
+	};
+
+	regulator_usdhc2_vmmc_pins: pinctrl-regulator-usdhc2-vmmc-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD2_RESET_B_GPIO2_IO19	0x0
+		>;
+	};
+
+	rtc_pins: pinctrl-rtc-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_GPIO1_IO01_GPIO1_IO1	0x140
+			MX8MN_IOMUXC_SAI3_RXFS_GPIO4_IO28	0x100
+		>;
+	};
+
+	tamper_pins: pinctrl-tamper-grp {
+		/*
+		 * Routed to physical tamper input (J12),
+		 * accelerometer and light-sensor interrupts.
+		 */
+		fsl,pins = <
+			MX8MN_IOMUXC_GPIO1_IO09_GPIO1_IO9	0x140
+		>;
+	};
+
+	uart1_pins: pinctrl-uart1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_UART1_RXD_UART1_DCE_RX	0x140
+			MX8MN_IOMUXC_UART1_TXD_UART1_DCE_TX	0x140
+			MX8MN_IOMUXC_UART3_RXD_UART1_DCE_CTS_B	0x140
+			MX8MN_IOMUXC_UART3_TXD_UART1_DCE_RTS_B	0x140
+			/* BT_REG_ON */
+			MX8MN_IOMUXC_SD1_DATA4_GPIO2_IO6	0x0
+			/* BT_WAKE_DEV */
+			MX8MN_IOMUXC_SD1_DATA5_GPIO2_IO7	0x0
+			/* BT_WAKE_HOST */
+			MX8MN_IOMUXC_SD1_DATA6_GPIO2_IO8	0x100
+		>;
+	};
+
+	uart2_pins: pinctrl-uart2-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_UART2_RXD_UART2_DCE_RX	0x140
+			MX8MN_IOMUXC_UART2_TXD_UART2_DCE_TX	0x140
+		>;
+	};
+
+	uart3_pins: pinctrl-uart3-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_ECSPI1_MOSI_UART3_DTE_RX	0x140
+			MX8MN_IOMUXC_ECSPI1_SCLK_UART3_DTE_TX	0x140
+			MX8MN_IOMUXC_ECSPI1_MISO_UART3_DTE_RTS_B	0x140
+			MX8MN_IOMUXC_ECSPI1_SS0_UART3_DTE_CTS_B	0x140
+		>;
+	};
+
+	uart4_pins: pinctrl-uart4-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_UART4_RXD_UART4_DCE_RX	0x140
+			MX8MN_IOMUXC_UART4_TXD_UART4_DCE_TX	0x140
+		>;
+	};
+
+	usb_hub_pins: pinctrl-usb-hub-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SPDIF_TX_GPIO5_IO3		0x0
+		>;
+	};
+
+	usdhc1_pins: pinctrl-usdhc1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD1_CLK_USDHC1_CLK		0x190
+			MX8MN_IOMUXC_SD1_CMD_USDHC1_CMD		0x1d0
+			MX8MN_IOMUXC_SD1_DATA0_USDHC1_DATA0	0x1d0
+			MX8MN_IOMUXC_SD1_DATA1_USDHC1_DATA1	0x1d0
+			MX8MN_IOMUXC_SD1_DATA2_USDHC1_DATA2	0x1d0
+			MX8MN_IOMUXC_SD1_DATA3_USDHC1_DATA3	0x1d0
+			/* wifi refclk */
+			MX8MN_IOMUXC_GPIO1_IO00_ANAMIX_REF_CLK_32K	0x0
+			/* WL_WAKE_HOST */
+			MX8MN_IOMUXC_SD1_DATA7_GPIO2_IO9	0x100
+			/* WL_REG_ON */
+			MX8MN_IOMUXC_SD1_RESET_B_GPIO2_IO10	0x0
+		>;
+	};
+
+	usdhc2_pins: pinctrl-usdhc2-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD2_CLK_USDHC2_CLK		0x190
+			MX8MN_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d0
+			MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d0
+			MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d0
+			MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d0
+			MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d0
+			MX8MN_IOMUXC_SD2_CD_B_USDHC2_CD_B	0x0
+			/* usdhc2 signalling voltage pmic control */
+			MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x140
+		>;
+	};
+
+	usdhc2_100mhz_pins: pinctrl-usdhc2-100mhz-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD2_CLK_USDHC2_CLK		0x194
+			MX8MN_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d4
+			MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d4
+			MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d4
+			MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d4
+			MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d4
+			MX8MN_IOMUXC_SD2_CD_B_USDHC2_CD_B	0x0
+			/* usdhc2 signalling voltage pmic control */
+			MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x140
+		>;
+	};
+
+	usdhc2_200mhz_pins: pinctrl-usdhc2-100mhz-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD2_CLK_USDHC2_CLK		0x196
+			MX8MN_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d6
+			MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d6
+			MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d6
+			MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d6
+			MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d6
+			MX8MN_IOMUXC_SD2_CD_B_USDHC2_CD_B	0x0
+			/* usdhc2 signalling voltage pmic control */
+			MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x140
+		>;
+	};
+
+	usdhc3_pins: pinctrl-usdhc3-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK	0x190
+			MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD	0x1d0
+			MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0	0x1d0
+			MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1	0x1d0
+			MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2	0x1d0
+			MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3	0x1d0
+			MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4	0x1d0
+			MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5	0x1d0
+			MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6	0x1d0
+			MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7	0x1d0
+			MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE	0x190
+		>;
+	};
+
+	wdog1_pins: pinctrl-wdog1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B	0x140
+		>;
+	};
+};
+
+/* Bluetooth */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	uart-has-rtscts;
+	/* select 80MHz parent clock to support maximum baudrate 4Mbps */
+	assigned-clocks = <&clk IMX8MN_CLK_UART1>;
+	assigned-clock-parents = <&clk IMX8MN_SYS_PLL1_80M>;
+	status = "okay";
+
+	bluetooth {
+		compatible = "brcm,bcm4330-bt";
+		device-wakeup-gpios = <&gpio2 7 GPIO_ACTIVE_HIGH>;
+		host-wakeup-gpios = <&gpio2 8 GPIO_ACTIVE_HIGH>;
+		shutdown-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>;
+		max-speed = <3000000>;
+	};
+};
+
+/* console */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "okay";
+};
+
+/* RS485 */
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart3_pins>;
+	uart-has-rtscts;
+	linux,rs485-enabled-at-boot-time;
+	fsl,dte-mode;
+	status = "okay";
+};
+
+/* 802.15.1 radio */
+&uart4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart4_pins &ieee802151_radio_pins>;
+	status = "okay";
+};
+
+&usbotg1 {
+	vbus-supply = <&reg_usb1_vbus>;
+	dr_mode = "host";
+	disable-over-current;
+	status  = "okay";
+};
+
+/* WiFi */
+&usdhc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&usdhc1_pins>;
+	vmmc-supply = <&reg_vdd_3v3>;
+	vqmmc-supply = <&reg_vdd_1v8>;
+	bus-width = <4>;
+	mmc-pwrseq = <&usdhc1_pwrseq>;
+	status = "okay";
+};
+
+/* microSD */
+&usdhc2 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&usdhc2_pins>;
+	pinctrl-1 = <&usdhc2_100mhz_pins>;
+	pinctrl-2 = <&usdhc2_200mhz_pins>;
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	bus-width = <4>;
+	broken-cd;
+	status = "okay";
+};
+
+/* eMMC */
+&usdhc3 {
+	/*
+	 * Use lowest drive strength for all high-speed modes to minimise
+	 * electro-magnetic emissions.
+	 * In this particular design HS-400 still works okay, no extra
+	 * pinctrl for 100mhz and 200mhz are required.
+	 */
+	pinctrl-names = "default";
+	pinctrl-0 = <&usdhc3_pins>;
+	vmmc-supply = <&reg_vdd_3v3>;
+	vqmmc-supply = <&reg_vdd_1v8>;
+	bus-width = <8>;
+	non-removable;
+	status = "okay";
+};
+
+&wdog1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&wdog1_pins>;
+	status = "okay";
+};

-- 
2.51.0




From josua at solid-run.com  Sun Dec 21 03:28:56 2025
From: josua at solid-run.com (Josua Mayer)
Date: Sun, 21 Dec 2025 12:28:56 +0100
Subject: [PATCH v5 7/7] arm64: dts: add description for solidrun i.mx8mm
 som and evb
In-Reply-To: <20251221-imx8mp-hb-iiot-v5-0-4a4dad916348@solid-run.com>
References: <20251221-imx8mp-hb-iiot-v5-0-4a4dad916348@solid-run.com>
Message-ID: <20251221-imx8mp-hb-iiot-v5-7-4a4dad916348@solid-run.com>

Add description for the SolidRun i.MX8M Mini SoM on HummingBoard Ripple.

The SoM features:
- 1Gbps Ethernet with PHY
- eMMC
- 1/2GB DDR
- NPU (assembly option)
- WiFi + Bluetooth

The HummingBoard Ripple features:
- 2x USB-2.0 Type-A connector
- 1Gbps RJ45 Ethernet with PoE
- microSD connector
- microHDMI connector
- mpcie connector with USB-2.0 interface + SIM card holder
- microUSB connector for console (using fdtdi chip)
- RTC with backup battery

Signed-off-by: Josua Mayer <josua at solid-run.com>
---
 arch/arm64/boot/dts/freescale/Makefile             |   2 +
 .../dts/freescale/imx8mm-hummingboard-ripple.dts   | 335 ++++++++++++++++++
 arch/arm64/boot/dts/freescale/imx8mm-sr-som.dtsi   | 394 +++++++++++++++++++++
 3 files changed, 731 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index 73c3d234149cd..6be7de1f0e1c4 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -124,6 +124,8 @@ imx8mm-evk-pcie-ep-dtbs += imx8mm-evk.dtb imx-pcie0-ep.dtbo
 imx8mm-evkb-pcie-ep-dtbs += imx8mm-evkb.dtb imx-pcie0-ep.dtbo
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-evk-pcie-ep.dtb imx8mm-evkb-pcie-ep.dtb
 
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-hummingboard-ripple.dtb
+DTC_FLAGS_imx8mm-hummingboard-ripple += -@
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-icore-mx8mm-ctouch2.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-icore-mx8mm-edimm2.2.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-iot-gateway.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-hummingboard-ripple.dts b/arch/arm64/boot/dts/freescale/imx8mm-hummingboard-ripple.dts
new file mode 100644
index 0000000000000..110e7ff1ff135
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mm-hummingboard-ripple.dts
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2025 Josua Mayer <josua at solid-run.com>
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/leds/common.h>
+
+#include "imx8mm-sr-som.dtsi"
+
+/ {
+	model = "SolidRun i.MX8MM HummingBoard Ripple";
+	compatible = "solidrun,imx8mm-hummingboard-ripple",
+		     "solidrun,imx8mm-sr-som", "fsl,imx8mm";
+
+	aliases {
+		rtc0 = &carrier_rtc;
+		rtc1 = &snvs_rtc;
+	};
+
+	hdmi-connector {
+		compatible = "hdmi-connector";
+		label = "hdmi";
+		type = "c";
+
+		port {
+			hdmi_connector_in: endpoint {
+				remote-endpoint = <&adv7535_out>;
+			};
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&led_pins>;
+
+		led-0 {
+			label = "D30";
+			color = <LED_COLOR_ID_GREEN>;
+			gpios = <&gpio5 29 GPIO_ACTIVE_LOW>;
+			default-state = "on";
+		};
+
+		led-1 {
+			label = "D31";
+			color = <LED_COLOR_ID_GREEN>;
+			gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
+			default-state = "on";
+		};
+
+		led-2 {
+			label = "D32";
+			color = <LED_COLOR_ID_GREEN>;
+			gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
+			default-state = "on";
+		};
+
+		led-3 {
+			label = "D33";
+			color = <LED_COLOR_ID_GREEN>;
+			gpios = <&gpio5 7 GPIO_ACTIVE_LOW>;
+			default-state = "on";
+		};
+
+		led-4 {
+			label = "D34";
+			color = <LED_COLOR_ID_GREEN>;
+			gpios = <&gpio5 6 GPIO_ACTIVE_LOW>;
+			default-state = "on";
+		};
+	};
+
+	rfkill-mpcie-wifi {
+		compatible = "rfkill-gpio";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pcie_rfkill_pins>;
+		label = "mpcie WiFi";
+		radio-type = "wlan";
+		/* rfkill-gpio inverts internally */
+		shutdown-gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>;
+	};
+
+	vmmc: regulator-mmc {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&vmmc_pins>;
+		regulator-name = "vmmc";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio2 19 GPIO_ACTIVE_LOW>;
+		startup-delay-us = <250>;
+	};
+
+	vbus1: regulator-vbus-1 {
+		compatible = "regulator-fixed";
+		regulator-name = "vbus1";
+		gpio = <&gpio2 11 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		pinctrl-names = "default";
+		pinctrl-0 = <&vbus1_pins>;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+	};
+
+	vbus2: regulator-vbus-2 {
+		compatible = "regulator-fixed";
+		regulator-name = "vbus2";
+		gpio = <&gpio4 21 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		pinctrl-names = "default";
+		pinctrl-0 = <&vbus2_pins>;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+	};
+
+	v_1_2: regulator-1-2 {
+		compatible = "regulator-fixed";
+		regulator-name = "1v2";
+		regulator-min-microvolt = <1200000>;
+		regulator-max-microvolt = <1200000>;
+	};
+};
+
+&i2c3 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c3_pins>;
+	status = "okay";
+
+	carrier_rtc: rtc at 69 {
+		compatible = "abracon,ab1805";
+		reg = <0x69>;
+		abracon,tc-diode = "schottky";
+		abracon,tc-resistor = <3>;
+	};
+
+	carrier_eeprom: eeprom at 57{
+		compatible = "st,24c02", "atmel,24c02";
+		reg = <0x57>;
+		pagesize = <16>;
+	};
+
+	hdmi at 3d {
+		compatible = "adi,adv7535";
+		reg = <0x3d>, <0x3f>, <0x3c>, <0x38>;
+		reg-names = "main", "edid", "cec", "packet";
+		adi,dsi-lanes = <4>;
+		avdd-supply = <&v_1_8>;
+		dvdd-supply = <&v_1_8>;
+		pvdd-supply = <&v_1_8>;
+		a2vdd-supply = <&v_1_8>;
+		v3p3-supply = <&v_3_3>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&hdmi_pins>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
+		pd-gpios = <&gpio3 22 GPIO_ACTIVE_LOW>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+
+				adv7535_from_dsim: endpoint {
+					remote-endpoint = <&mipi_dsi_out>;
+				};
+			};
+
+			port at 1 {
+				reg = <1>;
+
+				adv7535_out: endpoint {
+					remote-endpoint = <&hdmi_connector_in>;
+				};
+			};
+		};
+	};
+};
+
+&iomuxc {
+	hdmi_pins: pinctrl-hdmi-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_GPIO1_IO07_GPIO1_IO7	0x0
+			MX8MM_IOMUXC_SAI5_RXD1_GPIO3_IO22	0x0
+		>;
+	};
+
+	i2c3_pins: pinctrl-i2c3-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_I2C3_SCL_I2C3_SCL		0x400001c3
+			MX8MM_IOMUXC_I2C3_SDA_I2C3_SDA		0x400001c3
+		>;
+	};
+
+	led_pins: pinctrl-led-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_UART4_TXD_GPIO5_IO29	0x0
+			MX8MM_IOMUXC_ECSPI1_SS0_GPIO5_IO9	0x0
+			MX8MM_IOMUXC_ECSPI1_MISO_GPIO5_IO8	0x0
+			MX8MM_IOMUXC_ECSPI1_MOSI_GPIO5_IO7	0x0
+			MX8MM_IOMUXC_ECSPI1_SCLK_GPIO5_IO6	0x0
+		>;
+	};
+
+	pcie_rfkill_pins: pinctrl-pcie-rfkill-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SD2_WP_GPIO2_IO20		0x0
+		>;
+	};
+
+	usb_hub_pins: pinctrl-usb-hub-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SAI3_RXD_GPIO4_IO30	0x0
+		>;
+	};
+
+	usdhc2_pins: pinctrl-usdhc2-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK		0x190
+			MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d0
+			MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d0
+			MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d0
+			MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d0
+			MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d0
+			MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x140
+			MX8MM_IOMUXC_SD2_CD_B_USDHC2_CD_B	0x0
+		>;
+	};
+
+	usdhc2_100mhz_pins: pinctrl-usdhc2-100mhz-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK		0x194
+			MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d4
+			MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d4
+			MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d4
+			MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d4
+			MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d4
+			MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x140
+			MX8MM_IOMUXC_SD2_CD_B_USDHC2_CD_B	0x0
+		>;
+	};
+
+	usdhc2_200mhz_pins: pinctrl-usdhc2-100mhz-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK		0x196
+			MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d6
+			MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d6
+			MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d6
+			MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d6
+			MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d6
+			MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x140
+			MX8MM_IOMUXC_SD2_CD_B_USDHC2_CD_B	0x0
+		>;
+	};
+
+	vbus1_pins: pinctrl-vbus-1-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SD1_STROBE_GPIO2_IO11	0x20
+		>;
+	};
+
+	vbus2_pins: pinctrl-vbus-2-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SAI2_RXFS_GPIO4_IO21	0x20
+		>;
+	};
+
+	vmmc_pins: pinctrl-vmmc-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SD2_RESET_B_GPIO2_IO19	0x41
+		>;
+	};
+};
+
+&lcdif {
+	status = "okay";
+};
+
+&mipi_dsi {
+	samsung,esc-clock-frequency = <10000000>;
+	status = "okay";
+};
+
+&mipi_dsi_out {
+	remote-endpoint = <&adv7535_from_dsim>;
+};
+
+&usbotg1 {
+	dr_mode = "host";
+	vbus-supply = <&vbus2>;
+	status = "okay";
+};
+
+&usbotg2 {
+	status = "okay";
+	dr_mode = "host";
+	vbus-supply = <&vbus1>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&usb_hub_pins>;
+
+	hub_2_0: hub at 1 {
+		compatible = "usb4b4,6502", "usb4b4,6506";
+		reg = <1>;
+		peer-hub = <&hub_3_0>;
+		reset-gpios = <&gpio4 30 GPIO_ACTIVE_LOW>;
+		vdd-supply = <&v_1_2>;
+		vdd2-supply = <&v_3_3>;
+	};
+
+	/* this device is not visible because host supports 2.0 only */
+	hub_3_0: hub at 2 {
+		compatible = "usb4b4,6500", "usb4b4,6504";
+		reg = <2>;
+		peer-hub = <&hub_2_0>;
+		reset-gpios = <&gpio4 30 GPIO_ACTIVE_LOW>;
+		vdd-supply = <&v_1_2>;
+		vdd2-supply = <&v_3_3>;
+	};
+};
+
+&usdhc2 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&usdhc2_pins>;
+	pinctrl-1 = <&usdhc2_100mhz_pins>;
+	pinctrl-2 = <&usdhc2_200mhz_pins>;
+	vmmc-supply = <&vmmc>;
+	bus-width = <4>;
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-sr-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-sr-som.dtsi
new file mode 100644
index 0000000000000..0bc1b6fa8e994
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mm-sr-som.dtsi
@@ -0,0 +1,394 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2025 Josua Mayer <josua at solid-run.com>
+ */
+
+#include <dt-bindings/phy/phy-imx8-pcie.h>
+
+#include "imx8mm.dtsi"
+
+/ {
+	model = "SolidRun i.MX8MM SoM";
+	compatible = "solidrun,imx8mm-sr-som", "fsl,imx8mm";
+
+	chosen {
+		bootargs = "earlycon=ec_imx6q,0x30890000,115200";
+		stdout-path = &uart2;
+	};
+
+	memory at 40000000 {
+		device_type = "memory";
+		reg = <0x0 0x40000000 0 0x80000000>;
+	};
+
+	usdhc1_pwrseq: usdhc1-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>;
+	};
+
+	v_1_8: regulator-1-8 {
+		compatible = "regulator-fixed";
+		regulator-name = "1v8";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	v_3_3: regulator-3-3 {
+		compatible = "regulator-fixed";
+		regulator-name = "3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+};
+
+&fec1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&fec1_pins>;
+	phy-mode = "rgmii-id";
+	phy = <&phy0>;
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy0: ethernet-phy at 4 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <0x4>;
+			reset-gpios = <&gpio4 22 GPIO_ACTIVE_LOW>;
+			phy-reset-duration = <10>;
+			qca,smarteee-tw-us-1g = <24>;
+			vddio-supply = <&vddio>;
+
+			vddio: vddio-regulator {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+		};
+	};
+};
+
+&i2c1 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	status = "okay";
+
+	som_eeprom: eeprom at 50{
+		compatible = "st,24c01", "atmel,24c01";
+		reg = <0x50>;
+		pagesize = <16>;
+	};
+
+	pmic at 4b {
+		compatible = "rohm,bd71847";
+		reg = <0x4b>;
+		pinctrl-0 = <&pmic_pins>;
+		pinctrl-names = "default";
+		interrupt-parent = <&gpio1>;
+		interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+		rohm,reset-snvs-powered;
+
+		#clock-cells = <0>;
+		clocks = <&osc_32k>;
+		clock-output-names = "clk-32k-out";
+
+		regulators {
+			buck1_reg: BUCK1 {
+				regulator-name = "buck1";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <1250>;
+			};
+
+			buck2_reg: BUCK2 {
+				regulator-name = "buck2";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <1250>;
+				rohm,dvs-run-voltage = <1000000>;
+				rohm,dvs-idle-voltage = <900000>;
+			};
+
+			buck3_reg: BUCK3 {
+				// BUCK5 in datasheet
+				regulator-name = "buck3";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			buck4_reg: BUCK4 {
+				// BUCK6 in datasheet
+				regulator-name = "buck4";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			buck5_reg: BUCK5 {
+				// BUCK7 in datasheet
+				regulator-name = "buck5";
+				regulator-min-microvolt = <1605000>;
+				regulator-max-microvolt = <1995000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			buck6_reg: BUCK6 {
+				// BUCK8 in datasheet
+				regulator-name = "buck6";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1400000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo1_reg: LDO1 {
+				regulator-name = "ldo1";
+				regulator-min-microvolt = <1600000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo2_reg: LDO2 {
+				regulator-name = "ldo2";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <900000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo3_reg: LDO3 {
+				regulator-name = "ldo3";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo4_reg: LDO4 {
+				regulator-name = "ldo4";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo6_reg: LDO6 {
+				regulator-name = "ldo6";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+		};
+	};
+};
+
+&iomuxc {
+	fec1_pins: pinctrl-fec1-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_ENET_MDC_ENET1_MDC			0x3
+			MX8MM_IOMUXC_ENET_MDIO_ENET1_MDIO		0x3
+			MX8MM_IOMUXC_ENET_TD3_ENET1_RGMII_TD3		0x1f
+			MX8MM_IOMUXC_ENET_TD2_ENET1_RGMII_TD2		0x1f
+			MX8MM_IOMUXC_ENET_TD1_ENET1_RGMII_TD1		0x1f
+			MX8MM_IOMUXC_ENET_TD0_ENET1_RGMII_TD0		0x1f
+			MX8MM_IOMUXC_ENET_RD3_ENET1_RGMII_RD3		0x91
+			MX8MM_IOMUXC_ENET_RD2_ENET1_RGMII_RD2		0x91
+			MX8MM_IOMUXC_ENET_RD1_ENET1_RGMII_RD1		0x91
+			MX8MM_IOMUXC_ENET_RD0_ENET1_RGMII_RD0		0x91
+			MX8MM_IOMUXC_ENET_TXC_ENET1_RGMII_TXC		0x1f
+			MX8MM_IOMUXC_ENET_RXC_ENET1_RGMII_RXC		0x91
+			MX8MM_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x91
+			MX8MM_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x1f
+			MX8MM_IOMUXC_SAI2_RXC_GPIO4_IO22		0x19
+		>;
+	};
+
+	i2c1_pins: pinctrl-i2c1-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_I2C1_SCL_I2C1_SCL			0x400001c3
+			MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA			0x400001c3
+		>;
+	};
+
+	pcie_pins: pinctrl-pcie-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_GPIO1_IO15_GPIO1_IO15		0x0
+		>;
+	};
+
+	pmic_pins: pinctrl-pmic-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3		0x140
+		>;
+	};
+
+	uart1_pins: pinctrl-uart1-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_UART1_RXD_UART1_DCE_RX	0x140
+			MX8MM_IOMUXC_UART1_TXD_UART1_DCE_TX	0x140
+			MX8MM_IOMUXC_UART3_RXD_UART1_DCE_CTS_B	0x140
+			MX8MM_IOMUXC_UART3_TXD_UART1_DCE_RTS_B	0x140
+			/* BT_REG_ON */
+			MX8MM_IOMUXC_SD1_DATA4_GPIO2_IO6	0x0
+			/* BT_WAKE_DEV */
+			MX8MM_IOMUXC_SD1_DATA5_GPIO2_IO7	0x0
+			/* BT_WAKE_HOST */
+			MX8MM_IOMUXC_SD1_DATA6_GPIO2_IO8	0x100
+		>;
+	};
+
+	uart2_pins: pinctrl-uart2-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_UART2_RXD_UART2_DCE_RX		0x140
+			MX8MM_IOMUXC_UART2_TXD_UART2_DCE_TX		0x140
+		>;
+	};
+
+	usdhc1_pins: pinctrl-usdhc1-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SD1_CLK_USDHC1_CLK			0x190
+			MX8MM_IOMUXC_SD1_CMD_USDHC1_CMD			0x1d0
+			MX8MM_IOMUXC_SD1_DATA0_USDHC1_DATA0		0x1d0
+			MX8MM_IOMUXC_SD1_DATA1_USDHC1_DATA1		0x1d0
+			MX8MM_IOMUXC_SD1_DATA2_USDHC1_DATA2		0x1d0
+			MX8MM_IOMUXC_SD1_DATA3_USDHC1_DATA3		0x1d0
+			/* wifi refclk */
+			MX8MM_IOMUXC_GPIO1_IO00_ANAMIX_REF_CLK_32K	0x0
+			/* WL_REG_ON */
+			MX8MM_IOMUXC_SD1_RESET_B_GPIO2_IO10		0x0
+			/* WL_WAKE_HOST */
+			MX8MM_IOMUXC_SD1_DATA7_GPIO2_IO9		0x100
+		>;
+	};
+
+	usdhc3_pins: pinctrl-usdhc3-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK		0x190
+			MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d0
+			MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d0
+			MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d0
+			MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d0
+			MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d0
+			MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d0
+			MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d0
+			MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d0
+			MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d0
+			MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x190
+		>;
+	};
+
+	usdhc3_100mhz_pins: pinctrl-usdhc3-100mhz-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK		0x194
+			MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d4
+			MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d4
+			MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d4
+			MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d4
+			MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d4
+			MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d4
+			MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d4
+			MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d4
+			MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d4
+			MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x194
+		>;
+	};
+
+	usdhc3_200mhz_pins: pinctrl-usdhc3-200mhz-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK		0x196
+			MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d6
+			MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d6
+			MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d6
+			MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d6
+			MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d6
+			MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d6
+			MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d6
+			MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d6
+			MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d6
+			MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x196
+		>;
+	};
+
+	wdog1_pins: pinctrl-wdog1-grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B	0x140
+		>;
+	};
+};
+
+&pcie_phy {
+	fsl,clkreq-unsupported;
+	fsl,refclk-pad-mode = <IMX8_PCIE_REFCLK_PAD_OUTPUT>;
+	status = "okay";
+};
+
+/* assembly-option for AI accelerator on SoM, otherwise routed to carrier */
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie_pins>;
+	reset-gpios = <&gpio1 15 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>;
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	uart-has-rtscts;
+	/* select 80MHz parent clock to support maximum baudrate 4Mbps */
+	assigned-clocks = <&clk IMX8MM_CLK_UART1>;
+	assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_80M>;
+	status = "okay";
+
+	bluetooth {
+		compatible = "brcm,bcm4330-bt";
+		device-wakeup-gpios = <&gpio2 7 GPIO_ACTIVE_HIGH>;
+		host-wakeup-gpios = <&gpio2 8 GPIO_ACTIVE_HIGH>;
+		shutdown-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>;
+		max-speed = <3000000>;
+	};
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "okay";
+};
+
+&usdhc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&usdhc1_pins>;
+	vmmc-supply = <&v_3_3>;
+	vqmmc-supply = <&v_1_8>;
+	bus-width = <4>;
+	mmc-pwrseq = <&usdhc1_pwrseq>;
+	status = "okay";
+};
+
+&usdhc3 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&usdhc3_pins>;
+	pinctrl-1 = <&usdhc3_100mhz_pins>;
+	pinctrl-2 = <&usdhc3_200mhz_pins>;
+	vmmc-supply = <&v_3_3>;
+	vqmmc-supply = <&v_1_8>;
+	bus-width = <8>;
+	non-removable;
+	status = "okay";
+};
+
+&wdog1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&wdog1_pins>;
+	status = "okay";
+};

-- 
2.51.0




From josua at solid-run.com  Sun Dec 21 03:28:54 2025
From: josua at solid-run.com (Josua Mayer)
Date: Sun, 21 Dec 2025 12:28:54 +0100
Subject: [PATCH v5 5/7] arm64: dts: add description for solidrun imx8mp
 hummingboard-iiot
In-Reply-To: <20251221-imx8mp-hb-iiot-v5-0-4a4dad916348@solid-run.com>
References: <20251221-imx8mp-hb-iiot-v5-0-4a4dad916348@solid-run.com>
Message-ID: <20251221-imx8mp-hb-iiot-v5-5-4a4dad916348@solid-run.com>

Add description for the SolidRun i.MX8MP HummingBoard IIoT.
The board is a new design around the i.MX8MP System on Module, not
sharing much with previous HummingBoards.

It comes with some common features:
- 3x USB-3.0 Type A connector
- 2x 1Gbps RJ45 Ethernet
- USB Type-C Console Port
- microSD connector
- RTC with backup battery
- RGB Status LED
- 1x M.2 M-Key connector with PCI-E Gen. 3 x1
- 1x M.2 B-Key connector with USB-2.0/3.0 + SIM card holder
- 1x LVDS Display Connector
- 1x DSI Display Connector
- GPIO header
- 2x RS232/RS485 ports (configurable)
- 2x CAN

In addition there is a board-to-board expansion connector to support
custom daughter boards with access to SPI, a range of GPIOs and -
notably - CAN and UART. Both 2x CAN and 2x UART can be muxed either
to this b2b connector, or a termianl block connector on the base board.

The routing choice for UART and CAN is expressed through gpio
mux-controllers in DT and can be changed by applying dtb addons.

Four dtb addons are provided:

- dsi panel Winstar WJ70N3TYJHMNG0
- lvds panel Winstar WF70A8SYJHLNGA
- RS485 on UART port "A" (default rs232)
- RS485 on UART port "B" (default rs232)

Signed-off-by: Josua Mayer <josua at solid-run.com>
---
 arch/arm64/boot/dts/freescale/Makefile             |   6 +
 ...hummingboard-iiot-panel-dsi-WJ70N3TYJHMNG0.dtso |  69 ++
 ...ummingboard-iiot-panel-lvds-WF70A8SYJHLNGA.dtso | 105 +++
 .../imx8mp-hummingboard-iiot-rs485-a.dtso          |  18 +
 .../imx8mp-hummingboard-iiot-rs485-b.dtso          |  18 +
 .../dts/freescale/imx8mp-hummingboard-iiot.dts     | 719 +++++++++++++++++++++
 6 files changed, 935 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index c4c6fd6de9637..97e6000154640 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -213,6 +213,12 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mp-dhcom-pdk3.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-dhcom-picoitx.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-edm-g-wb.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-iiot.dtb
+DTC_FLAGS_imx8mp-hummingboard-iiot := -@
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-iiot-panel-dsi-WJ70N3TYJHMNG0.dtbo
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-iiot-panel-lvds-WF70A8SYJHLNGA.dtbo
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-iiot-rs485-a.dtbo
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-iiot-rs485-b.dtbo
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-mate.dtb
 DTC_FLAGS_imx8mp-hummingboard-mate := -@
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-pro.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-panel-dsi-WJ70N3TYJHMNG0.dtso b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-panel-dsi-WJ70N3TYJHMNG0.dtso
new file mode 100644
index 0000000000000..e66ee2ce69d8d
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-panel-dsi-WJ70N3TYJHMNG0.dtso
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2025 Josua Mayer <josua at solid-run.com>
+ *
+ * Overlay for enabling HummingBoard IIoT MIPI-DSI connector
+ * with Winstar WJ70N3TYJHMNG0 panel.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+&{/} {
+	dsi_backlight: dsi-backlight {
+		compatible = "gpio-backlight";
+		gpios = <&tca6408_u48 3 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&i2c_dsi {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	touchscreen at 41 {
+		compatible = "ilitek,ili2130";
+		reg = <0x41>;
+		reset-gpios = <&tca6408_u48 6 GPIO_ACTIVE_LOW>;
+		interrupts-extended = <&tca6416_u21 13 IRQ_TYPE_LEVEL_LOW>;
+	};
+};
+
+&lcdif1 {
+	status = "okay";
+};
+
+&mipi_dsi {
+	samsung,esc-clock-frequency = <10000000>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+
+	panel at 0 {
+		/* This is a Winstar panel, but the ronbo panel uses same controls. */
+		compatible = "ronbo,rb070d30";
+		reg = <0>;
+		vcc-lcd-supply = <&reg_dsi_panel>;
+		power-gpios = <&tca6408_u48 2 GPIO_ACTIVE_HIGH>;
+		/* reset is active-low but driver inverts it internally */
+		reset-gpios = <&tca6408_u48 1 GPIO_ACTIVE_HIGH>;
+		updn-gpios = <&tca6408_u48 5 GPIO_ACTIVE_HIGH>;
+		shlr-gpios = <&tca6408_u48 4 GPIO_ACTIVE_LOW>;
+		backlight = <&dsi_backlight>;
+
+		port {
+			panel_from_dsim: endpoint {
+				remote-endpoint = <&dsim_to_panel>;
+			};
+		};
+	};
+
+	port at 1 {
+		dsim_to_panel: endpoint {
+			remote-endpoint = <&panel_from_dsim>;
+			data-lanes = <1 2 3 4>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-panel-lvds-WF70A8SYJHLNGA.dtso b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-panel-lvds-WF70A8SYJHLNGA.dtso
new file mode 100644
index 0000000000000..f8fb7fd0e4e49
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-panel-lvds-WF70A8SYJHLNGA.dtso
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2025 Josua Mayer <josua at solid-run.com>
+ *
+ * Overlay for enabling HummingBoard IIoT LVDS connector
+ * with Winstar WF70A8SYJHLNGA panel.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+&{/} {
+	lvds_backlight: lvds-backlight {
+		compatible = "gpio-backlight";
+		gpios = <&tca6408_u37 3 GPIO_ACTIVE_LOW>;
+	};
+
+	panel-lvds {
+		compatible = "winstar,wf70a8syjhlnga", "panel-lvds";
+		backlight = <&lvds_backlight>;
+		power-supply = <&reg_dsi_panel>;
+		enable-gpios = <&tca6408_u37 2 GPIO_ACTIVE_HIGH>;
+		reset-gpios = <&tca6408_u37 1 GPIO_ACTIVE_HIGH>;
+		data-mapping = "vesa-24";
+		width-mm = <154>;
+		height-mm = <86>;
+
+		panel-timing {
+			/*
+			 * Note: NXP BSP hard-codes 74MHz clock in ldb driver:
+			 * drivers/gpu/drm/imx/imx8mp-ldb.c
+			 * SolidRun BSP carries patch.
+			 */
+			clock-frequency = <49500000>;
+			hactive = <1024>;
+			vactive = <600>;
+			hfront-porch = <40>;
+			hback-porch = <144>;
+			hsync-len = <104>;
+			hsync-active = <0>;
+			vfront-porch = <3>;
+			vback-porch = <11>;
+			vsync-len = <10>;
+			vsync-active = <1>;
+			de-active = <1>;
+		};
+
+		port {
+			panel_from_lvds: endpoint {
+				remote-endpoint = <&lvds_ch0_out>;
+			};
+		};
+	};
+};
+
+&i2c_lvds {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	touchscreen at 41 {
+		compatible = "ilitek,ili2130";
+		reg = <0x41>;
+		reset-gpios = <&tca6408_u37 6 GPIO_ACTIVE_LOW>;
+		interrupts-extended = <&tca6416_u21 13 IRQ_TYPE_LEVEL_LOW>;
+	};
+};
+
+&lcdif2 {
+	status = "okay";
+};
+
+&lvds_bridge {
+	status = "okay";
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "okay";
+
+		port at 1 {
+			lvds_ch0_out: endpoint {
+				remote-endpoint = <&panel_from_lvds>;
+			};
+		};
+	};
+};
+
+&tca6408_u37 {
+	lvds-lr-hog {
+		gpio-hog;
+		gpios = <4 GPIO_ACTIVE_HIGH>;
+		output-high;
+		line-name = "lvds-l/r";
+	};
+
+	lvds-ud-hog {
+		gpio-hog;
+		gpios = <5 GPIO_ACTIVE_HIGH>;
+		output-high;
+		line-name = "lvds-u/d";
+	};
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-rs485-a.dtso b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-rs485-a.dtso
new file mode 100644
index 0000000000000..7bbf800b78fb1
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-rs485-a.dtso
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2025 Josua Mayer <josua at solid-run.com>
+ *
+ * Overlay for enabling HummingBoard IIoT on-board RS485 Port A on connector J5004.
+ */
+
+/dts-v1/;
+/plugin/;
+
+&uart3_rs_232_485_mux {
+	/* select rs485 */
+	idle-state = <1>;
+};
+
+&uart3 {
+	linux,rs485-enabled-at-boot-time;
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-rs485-b.dtso b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-rs485-b.dtso
new file mode 100644
index 0000000000000..d4bfea886ad12
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-rs485-b.dtso
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2025 Josua Mayer <josua at solid-run.com>
+ *
+ * Overlay for enabling HummingBoard IIoT on-board RS485 Port B on connector J5004.
+ */
+
+/dts-v1/;
+/plugin/;
+
+&uart4_rs_232_485_mux {
+	/* select rs485 */
+	idle-state = <1>;
+};
+
+&uart4 {
+	linux,rs485-enabled-at-boot-time;
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot.dts b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot.dts
new file mode 100644
index 0000000000000..32351d4db9ced
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot.dts
@@ -0,0 +1,719 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2024 Yazan Shhady <yazan.shhady at solid-run.com>
+ * Copyright 2025 Josua Mayer <josua at solid-run.com>
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/phy/phy-imx8-pcie.h>
+
+#include "imx8mp-sr-som.dtsi"
+
+/ {
+	model = "SolidRun i.MX8MP HummingBoard IIoT";
+	compatible = "solidrun,imx8mp-hummingboard-iiot",
+		     "solidrun,imx8mp-sr-som", "fsl,imx8mp";
+
+	aliases {
+		ethernet0 = &eqos; /* J10 */
+		ethernet1 = &fec; /* J11 */
+		rtc0 = &carrier_rtc;
+		rtc1 = &snvs_rtc;
+		gpio5 = &tca6408_u48;
+		gpio6 = &tca6408_u37;
+		gpio7 = &tca6416_u20;
+		gpio8 = &tca6416_u21;
+		i2c6 = &i2c_exp;
+		i2c7 = &i2c_csi;
+		i2c8 = &i2c_dsi;
+		i2c9 = &i2c_lvds;
+	};
+
+	v_1_2: regulator-1-2 {
+		compatible = "regulator-fixed";
+		regulator-name = "1v2";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	reg_dsi_panel: regulator-dsi-panel {
+		compatible = "regulator-fixed";
+		regulator-name = "dsi-panel";
+		regulator-min-microvolt = <11200000>;
+		regulator-max-microvolt = <11200000>;
+		gpios = <&tca6416_u20 15 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	/* power for M.2 B-Key connector (J6) */
+	regulator-m2-b {
+		compatible = "regulator-fixed";
+		regulator-name = "m2-b";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpios = <&tca6416_u20 5 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-always-on;
+	};
+
+	/* power for M.2 M-Key connector (J4) */
+	regulator-m2-m {
+		compatible = "regulator-fixed";
+		regulator-name = "m2-m";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpios = <&tca6416_u20 6 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-always-on;
+	};
+
+	vmmc: regulator-mmc {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&vmmc_pins>;
+		regulator-name = "vmmc";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio2 19 GPIO_ACTIVE_LOW>;
+		enable-active-high;
+		startup-delay-us = <250>;
+	};
+
+	/* power for USB-A J5003 */
+	vbus1: regulator-vbus-1 {
+		compatible = "regulator-fixed";
+		regulator-name = "vbus1";
+		gpio = <&tca6416_u20 14 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+	};
+
+	/* power for USB-A J27 behind USB Hub Port 3 */
+	regulator-vbus-2 {
+		compatible = "regulator-fixed";
+		regulator-name = "vbus2";
+		gpio = <&tca6416_u20 12 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+	};
+
+	/* power for USB-A J27 behind USB Hub Port 4 */
+	regulator-vbus-3 {
+		compatible = "regulator-fixed";
+		regulator-name = "vbus3";
+		gpio = <&tca6416_u20 13 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+	};
+
+	rfkill-m2-b-gnss {
+		compatible = "rfkill-gpio";
+		label = "m2-b gnss";
+		radio-type = "gps";
+		/* rfkill-gpio inverts internally */
+		shutdown-gpios = <&tca6416_u20 10 GPIO_ACTIVE_HIGH>;
+	};
+
+	rfkill-m2-b-wwan {
+		compatible = "rfkill-gpio";
+		label = "m2-b radio";
+		radio-type = "wwan";
+		/* rfkill-gpio inverts internally */
+		shutdown-gpios = <&tca6416_u20 9 GPIO_ACTIVE_HIGH>;
+	};
+
+	flexcan1_flexcan2_b2b_mux: mux-controller-0 {
+		compatible = "gpio-mux";
+		#mux-control-cells = <0>;
+		/*
+		 * Mux switches both flexcan1 and flexcan2 tx/rx between
+		 * expansion connector (J22) and on-board transceivers
+		 * using one GPIO: 0 = on-board, 1 connector.
+		 */
+		mux-gpios = <&tca6416_u20 3 GPIO_ACTIVE_HIGH>;
+		/* default on-board */
+		idle-state = <0>;
+	};
+
+	mux-controller-1 {
+		compatible = "gpio-mux";
+		#mux-control-cells = <0>;
+		/*
+		 * Mux switches can bus between different SoM board-to-board
+		 * connector pins which is used to support different SoMs.
+		 * i.MX8M Plus uses J7-12/16 and J9-54/56 for 2x flexcan.
+		 */
+		mux-gpios = <&tca6416_u20 4 GPIO_ACTIVE_HIGH>;
+		idle-state = <1>;
+	};
+
+	spi_mux: mux-controller-2 {
+		compatible = "gpio-mux";
+		#mux-control-cells = <0>;
+		/*
+		 * Mux switches spi bus between on-board tpm
+		 * and expansion connector (J22).
+		 */
+		mux-gpios = <&tca6416_u21 0 GPIO_ACTIVE_HIGH>;
+		/* default on-board */
+		idle-state = <0>;
+	};
+
+	uart3_uart4_b2b_mux: mux-controller-3 {
+		compatible = "gpio-mux";
+		#mux-control-cells = <0>;
+		/*
+		 * Mux switches both uart3 and uart4 tx/rx between expansion
+		 * connector (J22) and on-board rs232/rs485 transceivers
+		 * using one GPIO: 0 = on-board, 1 connector.
+		 */
+		mux-gpios = <&tca6416_u20 0 GPIO_ACTIVE_HIGH>;
+		/* default on-board */
+		idle-state = <0>;
+	};
+
+	uart3_rs_232_485_mux: mux-controller-4 {
+		compatible = "gpio-mux";
+		#mux-control-cells = <0>;
+		/*
+		 * Mux switches uart3 tx/rx between rs232 and rs485
+		 * transceivers. using one GPIO: 0 = rs232; 1 = rs485.
+		 */
+		mux-gpios = <&tca6416_u20 1 GPIO_ACTIVE_HIGH>;
+		/* default rs232 */
+		idle-state = <0>;
+	};
+
+	uart4_rs_232_485_mux: mux-controller-5 {
+		compatible = "gpio-mux";
+		#mux-control-cells = <0>;
+		/*
+		 * Mux switches uart4 tx/rx between rs232 and rs485
+		 * transceivers. using one GPIO: 0 = rs232; 1 = rs485.
+		 */
+		mux-gpios = <&tca6416_u20 2 GPIO_ACTIVE_HIGH>;
+		/* default rs232 */
+		idle-state = <0>;
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		wakeup-event {
+			label = "m2-m-wakeup";
+			interrupts-extended = <&tca6416_u21 11 IRQ_TYPE_EDGE_FALLING>;
+			linux,code = <KEY_WAKEUP>;
+			wakeup-source;
+		};
+	};
+};
+
+&ecspi2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&ecspi2_pins>;
+	num-cs = <1>;
+	cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	ecspi2_muxed: spi at 0 {
+		compatible = "spi-mux";
+		reg = <0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		/* mux bandwidth is 2GHz, soc max. spi clock is 166MHz */
+		spi-max-frequency = <166000000>;
+		mux-controls = <&spi_mux>;
+
+		tpm at 0 {
+			compatible = "infineon,slb9670", "tcg,tpm_tis-spi";
+			reg = <0>;
+			spi-max-frequency = <43000000>;
+			reset-gpios = <&tca6416_u21 1 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>;
+			interrupts-extended = <&tca6416_u21 9 IRQ_TYPE_LEVEL_LOW>;
+		};
+	};
+};
+
+&flexcan1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&can1_pins>;
+	status = "okay";
+
+	can-transceiver {
+		max-bitrate = <8000000>;
+	};
+};
+
+&flexcan2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&can2_pins>;
+	status = "okay";
+
+	can-transceiver {
+		max-bitrate = <8000000>;
+	};
+};
+
+&i2c2 {
+	i2c-mux at 70 {
+		compatible = "nxp,pca9546";
+		reg = <0x70>;
+		/*
+		 * This reset is open drain,
+		 * but reset core does not support GPIO_OPEN_DRAIN flag.
+		 */
+		reset-gpios = <&tca6416_u21 2 GPIO_ACTIVE_LOW>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		/* channel 0 routed to expansion connector (J22) */
+		i2c_exp: i2c at 0 {
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		/* channel 1 routed to mipi-csi connector (J23) */
+		i2c_csi: i2c at 1 {
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		/* channel 2 routed to mipi-dsi connector (J25) */
+		i2c_dsi: i2c at 2 {
+			reg = <2>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			tca6408_u48: gpio at 21 {
+				compatible = "ti,tca6408";
+				reg = <0x21>;
+				/*
+				 * reset shared between U37 and U48, to be
+				 * supported once gpio-pca953x switches to
+				 * reset framework.
+				 *
+				 * reset-gpios = <&tca6416_u21 4 (GPIO_ACTIVE_LOW|GPIO_PULL_UP|GPIO_OPEN_DRAIN)>;
+				 */
+				gpio-controller;
+				#gpio-cells = <2>;
+				gpio-line-names = "CAM_RST#", "DSI_RESET",
+						  "DSI_STBYB", "DSI_PWM_BL",
+						  "DSI_L/R", "DSI_U/D",
+						  "DSI_CTP_/RST", "CAM_TRIG";
+			};
+		};
+
+		/* channel 2 routed to lvds connector (J24) */
+		i2c_lvds: i2c at 3 {
+			reg = <3>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			tca6408_u37: gpio at 20 {
+				compatible = "ti,tca6408";
+				reg = <0x20>;
+				/*
+				 * reset shared between U37 and U48, to be
+				 * supported once gpio-pca953x switches to
+				 * reset framework.
+				 *
+				 * reset-gpios = <&tca6416_u21 4 (GPIO_ACTIVE_LOW|GPIO_PULL_UP|GPIO_OPEN_DRAIN)>;
+				 */
+				gpio-controller;
+				#gpio-cells = <2>;
+				gpio-line-names = "SELB", "LVDS_RESET",
+						  "LVDS_STBYB", "LVDS_PWM_BL",
+						  "LVDS_L/R", "LVDS_U/D",
+						  "LVDS_CTP_/RST", "";
+			};
+		};
+	};
+};
+
+&i2c3 {
+	/* highest i2c clock supported by all peripherals is 400kHz */
+	clock-frequency = <400000>;
+
+	tca6416_u20: gpio at 20 {
+		/*
+		 * This is a TI TCAL6416 using same programming model as
+		 * NXP PCAL6416, not to be confused with TI TCA6416.
+		 */
+		compatible = "nxp,pcal6416";
+		reg = <0x20>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		gpio-line-names = "TCA_INT/EXT_UART", "TCA_UARTA_232/485",
+				  "TCA_UARTB_232/485", "TCA_INT/EXT_CAN",
+				  "TCA_NXP/REN", "TCA_M.2B_3V3_EN",
+				  "TCA_M.2M_3V3_EN", "TCA_M.2M_RESET#",
+				  "TCA_M.2B_RESET#", "TCA_M.2B_W_DIS#",
+				  "TCA_M.2B_GPS_EN#", "TCA_USB-HUB_RST#",
+				  "TCA_USB_HUB3_PWR_EN", "TCA_USB_HUB4_PWR_EN",
+				  "TCA_USB1_PWR_EN", "TCA_VIDEO_PWR_EN";
+
+		m2-b-reset-hog {
+			gpio-hog;
+			gpios = <8 GPIO_ACTIVE_LOW>;
+			output-low;
+			line-name = "m2-b-reset";
+		};
+	};
+
+	tca6416_u21: gpio at 21 {
+		/*
+		 * This is a TI TCAL6416 using same programming model as
+		 * NXP PCAL6416, not to be confused with TI TCA6416.
+		 */
+		compatible = "nxp,pcal6416";
+		reg = <0x21>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&tca6416_u21_int_pins>;
+		interrupts-extended = <&gpio1 15 IRQ_TYPE_EDGE_FALLING>;
+		gpio-line-names = "TCA_SPI_TPM/EXT", "TCA_TPM_RST#",
+				  "TCA_I2C_RST", "TCA_RS232_SHTD#",
+				  "TCA_LCD_I2C_RST", "TCA_DIG_OUT1",
+				  "TCA_bDIG_IN1", "TCA_SENS_INT",
+				  "TCA_ALERT#", "TCA_TPM_PIRQ#",
+				  "TCA_RTC_INT", "TCA_M.2M_WAKW_ON_LAN",
+				  "TCA_M.2M_CLKREQ#", "TCA_LVDS_INT#",
+				  "", "TCA_POE_AT";
+
+		rs232_shutdown: rs232-shutdown-hog {
+			gpio-hog;
+			gpios = <3 GPIO_ACTIVE_LOW>;
+			output-low;
+			line-name = "rs232-shutdown";
+		};
+
+		lcd-i2c-reset-hog {
+			/*
+			 * reset shared between U37 and U48, to be
+			 * supported once gpio-pca953x switches to
+			 * reset framework.
+			 */
+			gpio-hog;
+			gpios = <4 (GPIO_ACTIVE_LOW|GPIO_PULL_UP|GPIO_OPEN_DRAIN)>;
+			output-low;
+			line-name = "lcd-i2c-reset";
+		};
+
+		m2-m-clkreq-hog {
+			gpio-hog;
+			gpios = <12 GPIO_ACTIVE_LOW>;
+			input;
+			line-name = "m2-m-clkreq";
+		};
+	};
+
+	led-controller at 30 {
+		compatible = "ti,lp5562";
+		reg = <0x30>;
+		/* use internal clock, could use external generated by rtc */
+		clock-mode = /bits/ 8 <1>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		multi-led at 0 {
+			reg = <0x0>;
+			label = "D7";
+			color = <LED_COLOR_ID_RGB>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			led at 0 {
+				reg = <0x0>;
+				color = <LED_COLOR_ID_RED>;
+				led-cur = /bits/ 8 <0x32>;
+				max-cur = /bits/ 8 <0x64>;
+			};
+
+			led at 1 {
+				reg = <0x1>;
+				color = <LED_COLOR_ID_GREEN>;
+				led-cur = /bits/ 8 <0x19>;
+				max-cur = /bits/ 8 <0x32>;
+			};
+
+			led at 2 {
+				reg = <0x2>;
+				color = <LED_COLOR_ID_BLUE>;
+				led-cur = /bits/ 8 <0x19>;
+				max-cur = /bits/ 8 <0x32>;
+			};
+		};
+
+		led at 3 {
+			reg = <3>;
+			chan-name = "D8";
+			label = "D8";
+			color = <LED_COLOR_ID_GREEN>;
+			led-cur = /bits/ 8 <0x19>;
+			max-cur = /bits/ 8 <0x64>;
+		};
+	};
+
+	light-sensor at 44 {
+		compatible = "isil,isl29023";
+		reg = <0x44>;
+		/* IRQ shared between accelerometer, light-sensor and Tamper input (J5007) */
+		interrupts-extended = <&tca6416_u21 7 IRQ_TYPE_EDGE_FALLING>;
+	};
+
+	accelerometer at 53 {
+		compatible = "adi,adxl345";
+		reg = <0x53>;
+		/* IRQ shared between accelerometer, light-sensor and Tamper input (J5007) */
+		interrupt-names = "INT1";
+		interrupts-extended = <&tca6416_u21 7 IRQ_TYPE_EDGE_FALLING>;
+	};
+
+	carrier_eeprom: eeprom at 57{
+		compatible = "atmel,24c02";
+		reg = <0x57>;
+		pagesize = <8>;
+	};
+
+	carrier_rtc: rtc at 69 {
+		compatible = "abracon,ab1805";
+		reg = <0x69>;
+		abracon,tc-diode = "schottky";
+		abracon,tc-resistor = <3>;
+		/*
+		 * AM1805 RTC used on this board has only nTIRQ pins wired,
+		 * which is for countdown timer irqs only.
+		 * Driver does not support this, disable for now.
+		 *
+		 * interrupts-extended = <&tca6416_u21 10 IRQ_TYPE_EDGE_FALLING>;
+		 */
+	};
+};
+
+&iomuxc {
+	can1_pins: pinctrl-can1-grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SPDIF_RX__CAN1_RX			0x154
+			MX8MP_IOMUXC_SPDIF_TX__CAN1_TX			0x154
+		>;
+	};
+
+	can2_pins: pinctrl-can2-grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI5_MCLK__CAN2_RX			0x154
+			MX8MP_IOMUXC_SAI5_RXD3__CAN2_TX			0x154
+		>;
+	};
+
+	ecspi2_pins: pinctrl-ecspi2-grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_ECSPI2_SCLK__ECSPI2_SCLK		0x140
+			MX8MP_IOMUXC_ECSPI2_MOSI__ECSPI2_MOSI		0x140
+			MX8MP_IOMUXC_ECSPI2_MISO__ECSPI2_MISO		0x140
+			MX8MP_IOMUXC_ECSPI2_SS0__GPIO5_IO13		0x140
+		>;
+	};
+
+	tca6416_u21_int_pins: pinctrl-tca6416-u21-int-grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO15__GPIO1_IO15		0x0
+		>;
+	};
+
+	/* UARTA */
+	uart3_pins: pinctrl-uart3-grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_ECSPI1_SCLK__UART3_DCE_RX		0x140
+			MX8MP_IOMUXC_ECSPI1_MOSI__UART3_DCE_TX		0x140
+			MX8MP_IOMUXC_ECSPI1_SS0__GPIO5_IO09		0x140
+		>;
+	};
+
+	/* UARTB */
+	uart4_pins: pinctrl-uart4-grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_UART4_RXD__UART4_DCE_RX		0x140
+			MX8MP_IOMUXC_UART4_TXD__UART4_DCE_TX		0x140
+			MX8MP_IOMUXC_ECSPI1_MISO__GPIO5_IO08		0x140
+		>;
+	};
+
+	usdhc2_pins: pinctrl-usdhc2-grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK		0x190
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD		0x1d0
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0		0x1d0
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1		0x1d0
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2		0x1d0
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3		0x1d0
+			MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT		0x140
+			MX8MP_IOMUXC_SD2_CD_B__USDHC2_CD_B		0x140
+		>;
+	};
+
+	usdhc2_100mhz_pins: pinctrl-usdhc2-100mhz-grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK		0x194
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD		0x1d4
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0		0x1d4
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1		0x1d4
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2		0x1d4
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3		0x1d4
+			MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT		0x140
+			MX8MP_IOMUXC_SD2_CD_B__USDHC2_CD_B		0x140
+		>;
+	};
+
+	usdhc2_200mhz_pins: pinctrl-usdhc2-200mhz-grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK		0x196
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD		0x1d6
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0		0x1d6
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1		0x1d6
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2		0x1d6
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3		0x1d6
+			MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT		0x140
+			MX8MP_IOMUXC_SD2_CD_B__USDHC2_CD_B		0x140
+		>;
+	};
+
+	vmmc_pins: pinctrl-vmmc-grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19		0x0
+		>;
+	};
+};
+
+&pcie {
+	reset-gpio = <&tca6416_u20 7 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+/* M.2 M-Key (J4) */
+&pcie_phy {
+	clocks = <&hsio_blk_ctrl>;
+	clock-names = "ref";
+	fsl,clkreq-unsupported;
+	fsl,refclk-pad-mode = <IMX8_PCIE_REFCLK_PAD_OUTPUT>;
+	status = "okay";
+};
+
+&phy0 {
+	leds {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		/* ADIN1300 LED_0 pin */
+		led at 0 {
+			reg = <0>;
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_LAN;
+			default-state = "keep";
+		};
+	};
+};
+
+&phy1 {
+	leds {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		/* ADIN1300 LED_0 pin */
+		led at 0 {
+			reg = <0>;
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_LAN;
+			default-state = "keep";
+		};
+	};
+};
+
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart3_pins>;
+	rts-gpios = <&gpio5 9 GPIO_ACTIVE_HIGH>;
+	/* select 80MHz parent clock to support maximum baudrate 4Mbps */
+	assigned-clocks = <&clk IMX8MP_CLK_UART3>;
+	assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_80M>;
+	status = "okay";
+};
+
+&uart4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart4_pins>;
+	rts-gpios = <&gpio5 8 GPIO_ACTIVE_HIGH>;
+	/* select 80MHz parent clock to support maximum baudrate 4Mbps */
+	assigned-clocks = <&clk IMX8MP_CLK_UART4>;
+	assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_80M>;
+	status = "okay";
+};
+
+&usb3_phy0 {
+	fsl,phy-tx-preemp-amp-tune-microamp = <1200>;
+	vbus-supply = <&vbus1>;
+	status = "okay";
+};
+
+&usb3_0 {
+	status = "okay";
+};
+
+&usb3_phy1 {
+	status = "okay";
+};
+
+&usb3_1 {
+	status = "okay";
+};
+
+&usb_dwc3_0 {
+	dr_mode = "host";
+};
+
+&usb_dwc3_1 {
+	dr_mode = "host";
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	hub_2_0: hub at 1 {
+		compatible = "usb4b4,6502", "usb4b4,6506";
+		reg = <1>;
+		peer-hub = <&hub_3_0>;
+		reset-gpios = <&tca6416_u20 11 GPIO_ACTIVE_LOW>;
+		vdd-supply = <&v_1_2>;
+		vdd2-supply = <&v_3_3>;
+	};
+
+	hub_3_0: hub at 2 {
+		compatible = "usb4b4,6500", "usb4b4,6504";
+		reg = <2>;
+		peer-hub = <&hub_2_0>;
+		reset-gpios = <&tca6416_u20 11 GPIO_ACTIVE_LOW>;
+		vdd-supply = <&v_1_2>;
+		vdd2-supply = <&v_3_3>;
+	};
+};
+
+&usdhc2 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&usdhc2_pins>;
+	pinctrl-1 = <&usdhc2_100mhz_pins>;
+	pinctrl-2 = <&usdhc2_200mhz_pins>;
+	vmmc-supply = <&vmmc>;
+	bus-width = <4>;
+	cap-power-off-card;
+	full-pwr-cycle;
+	status = "okay";
+};

-- 
2.51.0




From leon at kernel.org  Sun Dec 21 03:55:23 2025
From: leon at kernel.org (Leon Romanovsky)
Date: Sun, 21 Dec 2025 13:55:23 +0200
Subject: [PATCH 5/6] dma-mapping: Allow batched DMA sync operations if
 supported by the arch
In-Reply-To: <20251219053658.84978-6-21cnbao@gmail.com>
References: <20251219053658.84978-1-21cnbao@gmail.com>
 <20251219053658.84978-6-21cnbao@gmail.com>
Message-ID: <20251221115523.GI13030@unreal>

On Fri, Dec 19, 2025 at 01:36:57PM +0800, Barry Song wrote:
> From: Barry Song <v-songbaohua at oppo.com>
> 
> This enables dma_direct_sync_sg_for_device, dma_direct_sync_sg_for_cpu,
> dma_direct_map_sg, and dma_direct_unmap_sg to use batched DMA sync
> operations when possible. This significantly improves performance on
> devices without hardware cache coherence.
> 
> Tangquan's initial results show that batched synchronization can reduce
> dma_map_sg() time by 64.61% and dma_unmap_sg() time by 66.60% on an MTK
> phone platform (MediaTek Dimensity 9500). The tests were performed by
> pinning the task to CPU7 and fixing the CPU frequency at 2.6 GHz,
> running dma_map_sg() and dma_unmap_sg() on 10 MB buffers (10 MB / 4 KB
> sg entries per buffer) for 200 iterations and then averaging the
> results.
> 
> Cc: Catalin Marinas <catalin.marinas at arm.com>
> Cc: Will Deacon <will at kernel.org>
> Cc: Marek Szyprowski <m.szyprowski at samsung.com>
> Cc: Robin Murphy <robin.murphy at arm.com>
> Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
> Cc: Ard Biesheuvel <ardb at kernel.org>
> Cc: Marc Zyngier <maz at kernel.org>
> Cc: Anshuman Khandual <anshuman.khandual at arm.com>
> Cc: Ryan Roberts <ryan.roberts at arm.com>
> Cc: Suren Baghdasaryan <surenb at google.com>
> Cc: Tangquan Zheng <zhengtangquan at oppo.com>
> Signed-off-by: Barry Song <v-songbaohua at oppo.com>
> ---
>  kernel/dma/direct.c | 28 ++++++++++-----
>  kernel/dma/direct.h | 86 +++++++++++++++++++++++++++++++++++++++------
>  2 files changed, 95 insertions(+), 19 deletions(-)

<...>

>  		if (!dev_is_dma_coherent(dev))
> -			arch_sync_dma_for_device(paddr, sg->length,
> -					dir);
> +			arch_sync_dma_for_device_batch_add(paddr, sg->length, dir);

<...>

> -static inline dma_addr_t dma_direct_map_phys(struct device *dev,
> +#ifdef CONFIG_ARCH_WANT_BATCHED_DMA_SYNC
> +static inline void dma_direct_sync_single_for_cpu_batch_add(struct device *dev,
> +		dma_addr_t addr, size_t size, enum dma_data_direction dir)
> +{
> +	phys_addr_t paddr = dma_to_phys(dev, addr);
> +
> +	if (!dev_is_dma_coherent(dev))
> +		arch_sync_dma_for_cpu_batch_add(paddr, size, dir);
> +
> +	__dma_direct_sync_single_for_cpu(dev, paddr, size, dir);
> +}
> +#endif
> +
> +static inline void dma_direct_sync_single_for_cpu(struct device *dev,
> +		dma_addr_t addr, size_t size, enum dma_data_direction dir)
> +{
> +	phys_addr_t paddr = dma_to_phys(dev, addr);
> +
> +	if (!dev_is_dma_coherent(dev))
> +		arch_sync_dma_for_cpu(paddr, size, dir);
> +
> +	__dma_direct_sync_single_for_cpu(dev, paddr, size, dir);
> +}
> +

I'm wondering why you don't implement this batch?sync support inside the
arch_sync_dma_*() functions. Doing so would minimize changes to the generic
kernel/dma/* code and reduce the amount of #ifdef?based spaghetti.

Thanks."


From jic23 at kernel.org  Sun Dec 21 04:04:13 2025
From: jic23 at kernel.org (Jonathan Cameron)
Date: Sun, 21 Dec 2025 12:04:13 +0000
Subject: [PATCH 1/5] iio: adc: aspeed: Simplify with dev_err_probe
In-Reply-To: <20251219-iio-dev-err-probe-v1-1-bd0fbc83c8a0@oss.qualcomm.com>
References: <20251219-iio-dev-err-probe-v1-0-bd0fbc83c8a0@oss.qualcomm.com>
	<20251219-iio-dev-err-probe-v1-1-bd0fbc83c8a0@oss.qualcomm.com>
Message-ID: <20251221120413.7f1fa877@jic23-huawei>

On Fri, 19 Dec 2025 15:31:50 +0100
Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com> wrote:

> Use dev_err_probe() to make error code handling simpler and handle
> deferred probe nicely (avoid spamming logs).
> 
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
Not a comment on this patch as such, but this would benefit from a local
struct device *dev


> ---
>  drivers/iio/adc/aspeed_adc.c | 9 ++++-----
>  1 file changed, 4 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
> index bf2bfd6bdc41..1ae45fe90e6c 100644
> --- a/drivers/iio/adc/aspeed_adc.c
> +++ b/drivers/iio/adc/aspeed_adc.c
> @@ -535,11 +535,10 @@ static int aspeed_adc_probe(struct platform_device *pdev)
>  		return PTR_ERR(data->clk_scaler);
>  
>  	data->rst = devm_reset_control_get_shared(&pdev->dev, NULL);
> -	if (IS_ERR(data->rst)) {
> -		dev_err(&pdev->dev,
> -			"invalid or missing reset controller device tree entry");
> -		return PTR_ERR(data->rst);
> -	}
> +	if (IS_ERR(data->rst))
> +		return dev_err_probe(&pdev->dev, PTR_ERR(data->rst),
> +				     "invalid or missing reset controller device tree entry");
> +
>  	reset_control_deassert(data->rst);
>  
>  	ret = devm_add_action_or_reset(data->dev, aspeed_adc_reset_assert,
> 



From jic23 at kernel.org  Sun Dec 21 04:04:39 2025
From: jic23 at kernel.org (Jonathan Cameron)
Date: Sun, 21 Dec 2025 12:04:39 +0000
Subject: [PATCH 0/5] iio: adc: Simplify with dev_err_probe
In-Reply-To: <20251219-iio-dev-err-probe-v1-0-bd0fbc83c8a0@oss.qualcomm.com>
References: <20251219-iio-dev-err-probe-v1-0-bd0fbc83c8a0@oss.qualcomm.com>
Message-ID: <20251221120439.3aa841ca@jic23-huawei>

On Fri, 19 Dec 2025 15:31:49 +0100
Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com> wrote:

> Use dev_err_probe() to make error code handling simpler and handle
> deferred probe nicely (avoid spamming logs).
> 
> Best regards,
> Krzysztof
Thanks. Series applied.

Jonathan

> 
> ---
> Krzysztof Kozlowski (5):
>       iio: adc: aspeed: Simplify with dev_err_probe
>       iio: adc: exynos: Simplify with dev_err_probe
>       iio: adc: qcom-spmi-rradc: Simplify with dev_err_probe
>       iio: adc: rockchip: Simplify with dev_err_probe
>       iio: adc: sc27xx: Simplify with dev_err_probe
> 
>  drivers/iio/adc/aspeed_adc.c      |  9 ++++---
>  drivers/iio/adc/exynos_adc.c      | 29 ++++++++---------------
>  drivers/iio/adc/qcom-spmi-rradc.c | 20 ++++++----------
>  drivers/iio/adc/rockchip_saradc.c | 13 ++++-------
>  drivers/iio/adc/sc27xx_adc.c      | 49 ++++++++++++++-------------------------
>  5 files changed, 43 insertions(+), 77 deletions(-)
> ---
> base-commit: cc3aa43b44bdb43dfbac0fcb51c56594a11338a8
> change-id: 20251219-iio-dev-err-probe-59b3104c8d4b
> 
> Best regards,



From lkp at intel.com  Sun Dec 21 04:36:16 2025
From: lkp at intel.com (kernel test robot)
Date: Sun, 21 Dec 2025 13:36:16 +0100
Subject: [PATCH 5/6] dma-mapping: Allow batched DMA sync operations if
 supported by the arch
In-Reply-To: <20251219053658.84978-6-21cnbao@gmail.com>
References: <20251219053658.84978-6-21cnbao@gmail.com>
Message-ID: <202512211320.LaiSSLAc-lkp@intel.com>

Hi Barry,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on v6.19-rc1 next-20251219]
[cannot apply to arm64/for-next/core]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Barry-Song/arm64-Provide-dcache_by_myline_op_nosync-helper/20251219-195810
base:   linus/master
patch link:    https://lore.kernel.org/r/20251219053658.84978-6-21cnbao%40gmail.com
patch subject: [PATCH 5/6] dma-mapping: Allow batched DMA sync operations if supported by the arch
config: x86_64-rhel-9.4 (https://download.01.org/0day-ci/archive/20251221/202512211320.LaiSSLAc-lkp at intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251221/202512211320.LaiSSLAc-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512211320.LaiSSLAc-lkp at intel.com/

All errors (new ones prefixed by >>):

   kernel/dma/direct.c: In function 'dma_direct_unmap_sg':
>> kernel/dma/direct.c:456:25: error: implicit declaration of function 'dma_direct_unmap_phys_batch_add'; did you mean 'dma_direct_unmap_phys'? [-Wimplicit-function-declaration]
     456 |                         dma_direct_unmap_phys_batch_add(dev, sg->dma_address,
         |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         |                         dma_direct_unmap_phys
   kernel/dma/direct.c: In function 'dma_direct_map_sg':
>> kernel/dma/direct.c:484:43: error: implicit declaration of function 'dma_direct_map_phys_batch_add'; did you mean 'dma_direct_map_phys'? [-Wimplicit-function-declaration]
     484 |                         sg->dma_address = dma_direct_map_phys_batch_add(dev, sg_phys(sg),
         |                                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         |                                           dma_direct_map_phys


vim +456 kernel/dma/direct.c

   439	
   440	/*
   441	 * Unmaps segments, except for ones marked as pci_p2pdma which do not
   442	 * require any further action as they contain a bus address.
   443	 */
   444	void dma_direct_unmap_sg(struct device *dev, struct scatterlist *sgl,
   445			int nents, enum dma_data_direction dir, unsigned long attrs)
   446	{
   447		struct scatterlist *sg;
   448		int i;
   449		bool need_sync = false;
   450	
   451		for_each_sg(sgl,  sg, nents, i) {
   452			if (sg_dma_is_bus_address(sg)) {
   453				sg_dma_unmark_bus_address(sg);
   454			} else {
   455				need_sync = true;
 > 456				dma_direct_unmap_phys_batch_add(dev, sg->dma_address,
   457						      sg_dma_len(sg), dir, attrs);
   458			}
   459		}
   460		if (need_sync && !dev_is_dma_coherent(dev))
   461			arch_sync_dma_batch_flush();
   462	}
   463	#endif
   464	
   465	int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
   466			enum dma_data_direction dir, unsigned long attrs)
   467	{
   468		struct pci_p2pdma_map_state p2pdma_state = {};
   469		struct scatterlist *sg;
   470		int i, ret;
   471		bool need_sync = false;
   472	
   473		for_each_sg(sgl, sg, nents, i) {
   474			switch (pci_p2pdma_state(&p2pdma_state, dev, sg_page(sg))) {
   475			case PCI_P2PDMA_MAP_THRU_HOST_BRIDGE:
   476				/*
   477				 * Any P2P mapping that traverses the PCI host bridge
   478				 * must be mapped with CPU physical address and not PCI
   479				 * bus addresses.
   480				 */
   481				break;
   482			case PCI_P2PDMA_MAP_NONE:
   483				need_sync = true;
 > 484				sg->dma_address = dma_direct_map_phys_batch_add(dev, sg_phys(sg),
   485						sg->length, dir, attrs);
   486				if (sg->dma_address == DMA_MAPPING_ERROR) {
   487					ret = -EIO;
   488					goto out_unmap;
   489				}
   490				break;
   491			case PCI_P2PDMA_MAP_BUS_ADDR:
   492				sg->dma_address = pci_p2pdma_bus_addr_map(
   493					p2pdma_state.mem, sg_phys(sg));
   494				sg_dma_len(sg) = sg->length;
   495				sg_dma_mark_bus_address(sg);
   496				continue;
   497			default:
   498				ret = -EREMOTEIO;
   499				goto out_unmap;
   500			}
   501			sg_dma_len(sg) = sg->length;
   502		}
   503	
   504		if (need_sync && !dev_is_dma_coherent(dev))
   505			arch_sync_dma_batch_flush();
   506		return nents;
   507	
   508	out_unmap:
   509		dma_direct_unmap_sg(dev, sgl, i, dir, attrs | DMA_ATTR_SKIP_CPU_SYNC);
   510		return ret;
   511	}
   512	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From krzk at kernel.org  Sun Dec 21 05:26:28 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sun, 21 Dec 2025 14:26:28 +0100
Subject: [PATCH v6 1/4] dt-bindings: clock: google,gs101-clock: add
 samsung,sysreg property as required
In-Reply-To: <20251220-automatic-clocks-v6-1-36c2f276a135@linaro.org>
References: <20251220-automatic-clocks-v6-0-36c2f276a135@linaro.org>
 <20251220-automatic-clocks-v6-1-36c2f276a135@linaro.org>
Message-ID: <215eb434-683f-4cf2-9bcd-0860991ae23e@kernel.org>

On 20/12/2025 10:05, Peter Griffin wrote:
> Each CMU (with the exception of cmu_top) has a corresponding sysreg bank
> that contains the BUSCOMPONENT_DRCG_EN and optional MEMCLK registers.
> The BUSCOMPONENT_DRCG_EN register enables dynamic root clock gating of
> bus components and MEMCLK gates the sram clock.
> 
> Now the clock driver supports automatic clock mode, to fully enable dynamic
> root clock gating it is required to configure these registers. Update the
> bindings documentation so that all CMUs (with the exception of
> gs101-cmu-top) have samsung,sysreg as a required property.
> 
> Note this is NOT an ABI break, as if the property isn't specified the
> clock driver will fallback to the current behaviour of not initializing
> the registers. The system still boots, but bus components won't benefit
> from dynamic root clock gating and dynamic power will be higher (which has
> been the case until now anyway).
> 
> Additionally update the DT example to included the correct CMU size as
> registers in that region are used for automatic clock mode.
> 
> Signed-off-by: Peter Griffin <peter.griffin at linaro.org>
> ---
> Changes in v5:
> - Invert the test for google,gs101-cmu-top (Andre)
> 


<form letter>
This is a friendly reminder during the review process.

It looks like you received a tag and forgot to add it.

If you do not know the process, here is a short explanation:
Please add Acked-by/Reviewed-by/Tested-by tags when posting new versions
of patchset, under or above your Signed-off-by tag, unless patch changed
significantly (e.g. new properties added to the DT bindings). Tag is
"received", when provided in a message replied to you on the mailing
list. Tools like b4 can help here. However, there's no need to repost
patches *only* to add the tags. The upstream maintainer will do that for
tags received on the version they apply.

Please read:
https://elixir.bootlin.com/linux/v6.12-rc3/source/Documentation/process/submitting-patches.rst#L577

If a tag was not added on purpose, please state why and what changed.
</form letter>


Best regards,
Krzysztof


From krzk at kernel.org  Sun Dec 21 05:30:52 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sun, 21 Dec 2025 14:30:52 +0100
Subject: (subset) [PATCH 0/3] Add clock support for CMU_MFD
In-Reply-To: <20251119114744.1914416-1-raghav.s@samsung.com>
References: <CGME20251119113922epcas5p1f9593dbc6cd51d9fa04613d9120eceef@epcas5p1.samsung.com>
 <20251119114744.1914416-1-raghav.s@samsung.com>
Message-ID: <176632385218.12602.17940267617216000945.b4-ty@kernel.org>


On Wed, 19 Nov 2025 17:17:41 +0530, Raghav Sharma wrote:
> This series adds clock support for the CMU_MFD block.
> MFD stands for Multi-Format Decoder
> 
> Patch[1/3]: dt-bindings: clock: exynosautov920: add mfd clock definitions
>         - Adds DT binding for CMU_MFD and clock definitions
> 
> Patch[2/3]: clk: samsung: exynosautov920: add block mfd clock support
>         - Adds CMU_MFD clock driver support
> 
> [...]

Applied, thanks!

[1/3] dt-bindings: clock: exynosautov920: add MFD clock definitions
      https://git.kernel.org/krzk/linux/c/db1cc4902f2f51977e427f796ea8daf49ba93c69
[2/3] clk: samsung: exynosautov920: add clock support
      https://git.kernel.org/krzk/linux/c/efa45bcc73e1a30705eed28933e341d36a08bb84

Best regards,
-- 
Krzysztof Kozlowski <krzk at kernel.org>



From krzk at kernel.org  Sun Dec 21 05:50:38 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sun, 21 Dec 2025 14:50:38 +0100
Subject: [PATCH v3 0/6] soc: samsung: exynos-chipid: add gs101 support
In-Reply-To: <20251120-gs101-chipid-v3-0-1aeaa8b7fe35@linaro.org>
References: <20251120-gs101-chipid-v3-0-1aeaa8b7fe35@linaro.org>
Message-ID: <5314fc2e-e21f-4a2b-8970-c856049edb72@kernel.org>

On 20/11/2025 12:29, Tudor Ambarus wrote:
> Dependency
> ==========
> Typical dependency of the DT patch depending on the bindings patch,
> thus the bindings patch could go via the Samsung SoC tree with
> Srinivas's ack.
> 
> Description
> ===========
> GS101 is different (but also e850 and autov9 I assume) from the SoCs
> that are currently handled by the exynos-chipid driver because the
> chip ID info is part of the OTP registers. GS101 OTP has a clock, an
> interrupt line, a register space (that contains product and chip ID,
> TMU data, ASV, etc) and a 32Kbit memory space that can be
> read/program/locked with specific commands. On GS101 the "ChipID block"
> is just an abstraction, it's not a physical device. When the power-on
> sequence progresses, the OTP chipid values are loaded to the OTP
> registers.
> 
> Add the GS101 chip ID support. The support is intentionally added in the
> exynos-chipid driver, and not in a dedicated Exynos OTP driver, because
> we estimate that there will not be any OTP consumers in the kernel other
> than the chip ID/SoC interface. The downstream GS101 drivers confirm
> this supposition.
> 

Patches look fine to me, I took already two, but the rest please send
new version after implementing Andre's feedback (thanks for review!).

Best regards,
Krzysztof


From krzk at kernel.org  Sun Dec 21 05:52:43 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sun, 21 Dec 2025 14:52:43 +0100
Subject: (subset) [PATCH 0/3] Add clock support for CMU_MFD
In-Reply-To: <20251119114744.1914416-1-raghav.s@samsung.com>
References: <CGME20251119113922epcas5p1f9593dbc6cd51d9fa04613d9120eceef@epcas5p1.samsung.com>
 <20251119114744.1914416-1-raghav.s@samsung.com>
Message-ID: <176632516371.32657.3772424458194925472.b4-ty@kernel.org>


On Wed, 19 Nov 2025 17:17:41 +0530, Raghav Sharma wrote:
> This series adds clock support for the CMU_MFD block.
> MFD stands for Multi-Format Decoder
> 
> Patch[1/3]: dt-bindings: clock: exynosautov920: add mfd clock definitions
>         - Adds DT binding for CMU_MFD and clock definitions
> 
> Patch[2/3]: clk: samsung: exynosautov920: add block mfd clock support
>         - Adds CMU_MFD clock driver support
> 
> [...]

Applied, thanks!

[3/3] arm64: dts: exynosautov920: add CMU_MFD clock DT nodes
      https://git.kernel.org/krzk/linux/c/abc6930a3150003e1a436e906ffd1cafd679acfc

Best regards,
-- 
Krzysztof Kozlowski <krzk at kernel.org>



From krzk at kernel.org  Sun Dec 21 05:52:49 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sun, 21 Dec 2025 14:52:49 +0100
Subject: (subset) [PATCH v3 0/6] soc: samsung: exynos-chipid: add gs101
 support
In-Reply-To: <20251120-gs101-chipid-v3-0-1aeaa8b7fe35@linaro.org>
References: <20251120-gs101-chipid-v3-0-1aeaa8b7fe35@linaro.org>
Message-ID: <176632516971.32657.9705305853301180066.b4-ty@kernel.org>


On Thu, 20 Nov 2025 11:29:34 +0000, Tudor Ambarus wrote:
> Dependency
> ==========
> Typical dependency of the DT patch depending on the bindings patch,
> thus the bindings patch could go via the Samsung SoC tree with
> Srinivas's ack.
> 
> Description
> ===========
> GS101 is different (but also e850 and autov9 I assume) from the SoCs
> that are currently handled by the exynos-chipid driver because the
> chip ID info is part of the OTP registers. GS101 OTP has a clock, an
> interrupt line, a register space (that contains product and chip ID,
> TMU data, ASV, etc) and a 32Kbit memory space that can be
> read/program/locked with specific commands. On GS101 the "ChipID block"
> is just an abstraction, it's not a physical device. When the power-on
> sequence progresses, the OTP chipid values are loaded to the OTP
> registers.
> 
> [...]

Applied, thanks!

[1/6] soc: samsung: exynos-chipid: use devm action to unregister soc device
      https://git.kernel.org/krzk/linux/c/1b3376d2167766e9f5ac05a03ca4625777090ce7
[2/6] soc: samsung: exynos-chipid: use dev_err_probe where appropiate
      https://git.kernel.org/krzk/linux/c/8dfbb5fcb773a6481407ec890280cc3b1ff8e234

Best regards,
-- 
Krzysztof Kozlowski <krzk at kernel.org>



From krzysztof.kozlowski at oss.qualcomm.com  Sun Dec 21 06:05:38 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Sun, 21 Dec 2025 15:05:38 +0100
Subject: [PATCH 1/5] iio: adc: aspeed: Simplify with dev_err_probe
In-Reply-To: <20251221120413.7f1fa877@jic23-huawei>
References: <20251219-iio-dev-err-probe-v1-0-bd0fbc83c8a0@oss.qualcomm.com>
 <20251219-iio-dev-err-probe-v1-1-bd0fbc83c8a0@oss.qualcomm.com>
 <20251221120413.7f1fa877@jic23-huawei>
Message-ID: <9b363736-ac88-45bb-a428-7d3bccdc4d12@oss.qualcomm.com>

On 21/12/2025 13:04, Jonathan Cameron wrote:
> On Fri, 19 Dec 2025 15:31:50 +0100
> Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com> wrote:
> 
>> Use dev_err_probe() to make error code handling simpler and handle
>> deferred probe nicely (avoid spamming logs).
>>
>> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
> Not a comment on this patch as such, but this would benefit from a local
> struct device *dev

Ack

Best regards,
Krzysztof


From krzysztof.kozlowski at oss.qualcomm.com  Sun Dec 21 06:26:03 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Sun, 21 Dec 2025 15:26:03 +0100
Subject: [PATCH 1/3] iio: adc: aspeed: Simplify probe() with local 'dev' and 'np'
Message-ID: <20251221142602.47368-4-krzysztof.kozlowski@oss.qualcomm.com>

Simplify the probe function by using local 'dev' and 'np' variables
instead of full pointer dereferences.  This makes several lines shorter,
which allows to avoid wrapping making code more readable.  While
touching the return line, simplify by avoiding unnecessary 'ret'
assignment.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/iio/adc/aspeed_adc.c | 42 ++++++++++++++++--------------------
 1 file changed, 19 insertions(+), 23 deletions(-)

diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
index 1ae45fe90e6c..4be44c524b4d 100644
--- a/drivers/iio/adc/aspeed_adc.c
+++ b/drivers/iio/adc/aspeed_adc.c
@@ -472,16 +472,18 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 	struct aspeed_adc_data *data;
 	int ret;
 	u32 adc_engine_control_reg_val;
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev_of_node(dev);
 	unsigned long scaler_flags = 0;
 	char clk_name[32], clk_parent_name[32];
 
-	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*data));
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
 	if (!indio_dev)
 		return -ENOMEM;
 
 	data = iio_priv(indio_dev);
-	data->dev = &pdev->dev;
-	data->model_data = of_device_get_match_data(&pdev->dev);
+	data->dev = dev;
+	data->model_data = of_device_get_match_data(dev);
 	platform_set_drvdata(pdev, indio_dev);
 
 	data->base = devm_platform_ioremap_resource(pdev, 0);
@@ -491,16 +493,15 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 	/* Register ADC clock prescaler with source specified by device tree. */
 	spin_lock_init(&data->clk_lock);
 	snprintf(clk_parent_name, ARRAY_SIZE(clk_parent_name), "%s",
-		 of_clk_get_parent_name(pdev->dev.of_node, 0));
+		 of_clk_get_parent_name(np, 0));
 	snprintf(clk_name, ARRAY_SIZE(clk_name), "%s-fixed-div",
 		 data->model_data->model_name);
-	data->fixed_div_clk = clk_hw_register_fixed_factor(
-		&pdev->dev, clk_name, clk_parent_name, 0, 1, 2);
+	data->fixed_div_clk = clk_hw_register_fixed_factor(dev, clk_name,
+							   clk_parent_name, 0, 1, 2);
 	if (IS_ERR(data->fixed_div_clk))
 		return PTR_ERR(data->fixed_div_clk);
 
-	ret = devm_add_action_or_reset(data->dev,
-				       aspeed_adc_unregister_fixed_divider,
+	ret = devm_add_action_or_reset(dev, aspeed_adc_unregister_fixed_divider,
 				       data->fixed_div_clk);
 	if (ret)
 		return ret;
@@ -510,7 +511,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 		snprintf(clk_name, ARRAY_SIZE(clk_name), "%s-prescaler",
 			 data->model_data->model_name);
 		data->clk_prescaler = devm_clk_hw_register_divider(
-			&pdev->dev, clk_name, clk_parent_name, 0,
+			dev, clk_name, clk_parent_name, 0,
 			data->base + ASPEED_REG_CLOCK_CONTROL, 17, 15, 0,
 			&data->clk_lock);
 		if (IS_ERR(data->clk_prescaler))
@@ -526,7 +527,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 	snprintf(clk_name, ARRAY_SIZE(clk_name), "%s-scaler",
 		 data->model_data->model_name);
 	data->clk_scaler = devm_clk_hw_register_divider(
-		&pdev->dev, clk_name, clk_parent_name, scaler_flags,
+		dev, clk_name, clk_parent_name, scaler_flags,
 		data->base + ASPEED_REG_CLOCK_CONTROL, 0,
 		data->model_data->scaler_bit_width,
 		data->model_data->need_prescaler ? CLK_DIVIDER_ONE_BASED : 0,
@@ -534,15 +535,14 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 	if (IS_ERR(data->clk_scaler))
 		return PTR_ERR(data->clk_scaler);
 
-	data->rst = devm_reset_control_get_shared(&pdev->dev, NULL);
+	data->rst = devm_reset_control_get_shared(dev, NULL);
 	if (IS_ERR(data->rst))
-		return dev_err_probe(&pdev->dev, PTR_ERR(data->rst),
+		return dev_err_probe(dev, PTR_ERR(data->rst),
 				     "invalid or missing reset controller device tree entry");
 
 	reset_control_deassert(data->rst);
 
-	ret = devm_add_action_or_reset(data->dev, aspeed_adc_reset_assert,
-				       data->rst);
+	ret = devm_add_action_or_reset(dev, aspeed_adc_reset_assert, data->rst);
 	if (ret)
 		return ret;
 
@@ -554,7 +554,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	if (of_property_present(data->dev->of_node, "aspeed,battery-sensing")) {
+	if (of_property_present(np, "aspeed,battery-sensing")) {
 		if (data->model_data->bat_sense_sup) {
 			data->battery_sensing = 1;
 			if (readl(data->base + ASPEED_REG_ENGINE_CONTROL) &
@@ -566,15 +566,13 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 				data->battery_mode_gain.div = 2;
 			}
 		} else
-			dev_warn(&pdev->dev,
-				 "Failed to enable battery-sensing mode\n");
+			dev_warn(dev, "Failed to enable battery-sensing mode\n");
 	}
 
 	ret = clk_prepare_enable(data->clk_scaler->clk);
 	if (ret)
 		return ret;
-	ret = devm_add_action_or_reset(data->dev,
-				       aspeed_adc_clk_disable_unprepare,
+	ret = devm_add_action_or_reset(dev, aspeed_adc_clk_disable_unprepare,
 				       data->clk_scaler->clk);
 	if (ret)
 		return ret;
@@ -592,8 +590,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 	writel(adc_engine_control_reg_val,
 	       data->base + ASPEED_REG_ENGINE_CONTROL);
 
-	ret = devm_add_action_or_reset(data->dev, aspeed_adc_power_down,
-					data);
+	ret = devm_add_action_or_reset(dev, aspeed_adc_power_down, data);
 	if (ret)
 		return ret;
 
@@ -625,8 +622,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 					    aspeed_adc_iio_channels;
 	indio_dev->num_channels = data->model_data->num_channels;
 
-	ret = devm_iio_device_register(data->dev, indio_dev);
-	return ret;
+	return devm_iio_device_register(dev, indio_dev);
 }
 
 static const struct aspeed_adc_trim_locate ast2500_adc_trim = {
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Sun Dec 21 06:26:04 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Sun, 21 Dec 2025 15:26:04 +0100
Subject: [PATCH 2/3] iio: adc: exynos: Simplify probe() with local 'dev' and 'np'
In-Reply-To: <20251221142602.47368-4-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251221142602.47368-4-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <20251221142602.47368-5-krzysztof.kozlowski@oss.qualcomm.com>

Simplify the probe function by using local 'dev' and 'np' variables
instead of full pointer dereferences.  This makes several lines shorter,
which allows to avoid wrapping making code more readable.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/iio/adc/exynos_adc.c | 36 ++++++++++++++++--------------------
 1 file changed, 16 insertions(+), 20 deletions(-)

diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
index 491e8dcfd91e..aa287132a369 100644
--- a/drivers/iio/adc/exynos_adc.c
+++ b/drivers/iio/adc/exynos_adc.c
@@ -552,12 +552,13 @@ static int exynos_adc_remove_devices(struct device *dev, void *c)
 static int exynos_adc_probe(struct platform_device *pdev)
 {
 	struct exynos_adc *info = NULL;
+	struct device *dev = &pdev->dev;
 	struct device_node *np = pdev->dev.of_node;
 	struct iio_dev *indio_dev = NULL;
 	int ret;
 	int irq;
 
-	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct exynos_adc));
+	indio_dev = devm_iio_device_alloc(dev, sizeof(struct exynos_adc));
 	if (!indio_dev)
 		return -ENOMEM;
 
@@ -565,7 +566,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
 
 	info->data = exynos_adc_get_data(pdev);
 	if (!info->data)
-		return dev_err_probe(&pdev->dev, -EINVAL, "failed getting exynos_adc_data\n");
+		return dev_err_probe(dev, -EINVAL, "failed getting exynos_adc_data\n");
 
 	info->regs = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(info->regs))
@@ -573,11 +574,9 @@ static int exynos_adc_probe(struct platform_device *pdev)
 
 
 	if (info->data->needs_adc_phy) {
-		info->pmu_map = syscon_regmap_lookup_by_phandle(
-					pdev->dev.of_node,
-					"samsung,syscon-phandle");
+		info->pmu_map = syscon_regmap_lookup_by_phandle(np, "samsung,syscon-phandle");
 		if (IS_ERR(info->pmu_map))
-			return dev_err_probe(&pdev->dev, PTR_ERR(info->pmu_map),
+			return dev_err_probe(dev, PTR_ERR(info->pmu_map),
 					     "syscon regmap lookup failed.\n");
 	}
 
@@ -585,25 +584,24 @@ static int exynos_adc_probe(struct platform_device *pdev)
 	if (irq < 0)
 		return irq;
 	info->irq = irq;
-	info->dev = &pdev->dev;
+	info->dev = dev;
 
 	init_completion(&info->completion);
 
-	info->clk = devm_clk_get(&pdev->dev, "adc");
+	info->clk = devm_clk_get(dev, "adc");
 	if (IS_ERR(info->clk))
-		return dev_err_probe(&pdev->dev, PTR_ERR(info->clk), "failed getting clock\n");
+		return dev_err_probe(dev, PTR_ERR(info->clk), "failed getting clock\n");
 
 	if (info->data->needs_sclk) {
-		info->sclk = devm_clk_get(&pdev->dev, "sclk");
+		info->sclk = devm_clk_get(dev, "sclk");
 		if (IS_ERR(info->sclk))
-			return dev_err_probe(&pdev->dev, PTR_ERR(info->sclk),
+			return dev_err_probe(dev, PTR_ERR(info->sclk),
 					     "failed getting sclk clock\n");
 	}
 
-	info->vdd = devm_regulator_get(&pdev->dev, "vdd");
+	info->vdd = devm_regulator_get(dev, "vdd");
 	if (IS_ERR(info->vdd))
-		return dev_err_probe(&pdev->dev, PTR_ERR(info->vdd),
-				     "failed getting regulator");
+		return dev_err_probe(dev, PTR_ERR(info->vdd), "failed getting regulator");
 
 	ret = regulator_enable(info->vdd);
 	if (ret)
@@ -619,7 +617,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, indio_dev);
 
-	indio_dev->name = dev_name(&pdev->dev);
+	indio_dev->name = dev_name(dev);
 	indio_dev->info = &exynos_adc_iio_info;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->channels = exynos_adc_iio_channels;
@@ -627,11 +625,9 @@ static int exynos_adc_probe(struct platform_device *pdev)
 
 	mutex_init(&info->lock);
 
-	ret = request_irq(info->irq, exynos_adc_isr,
-					0, dev_name(&pdev->dev), info);
+	ret = request_irq(info->irq, exynos_adc_isr, 0, dev_name(dev), info);
 	if (ret < 0) {
-		dev_err(&pdev->dev, "failed requesting irq, irq = %d\n",
-							info->irq);
+		dev_err(dev, "failed requesting irq, irq = %d\n", info->irq);
 		goto err_disable_clk;
 	}
 
@@ -644,7 +640,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
 
 	ret = of_platform_populate(np, exynos_adc_match, NULL, &indio_dev->dev);
 	if (ret < 0) {
-		dev_err(&pdev->dev, "failed adding child nodes\n");
+		dev_err(dev, "failed adding child nodes\n");
 		goto err_of_populate;
 	}
 
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Sun Dec 21 06:26:05 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Sun, 21 Dec 2025 15:26:05 +0100
Subject: [PATCH 3/3] iio: adc: rockchip: Simplify probe() with local 'dev'
In-Reply-To: <20251221142602.47368-4-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251221142602.47368-4-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <20251221142602.47368-6-krzysztof.kozlowski@oss.qualcomm.com>

Simplify the probe function by using a local 'dev' variable instead of
full pointer dereference.  This makes several lines shorter, which
allows to avoid wrapping making code more readable.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/iio/adc/rockchip_saradc.c | 50 ++++++++++++++-----------------
 1 file changed, 22 insertions(+), 28 deletions(-)

diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c
index 263d80c5fc50..0f0bf2906af0 100644
--- a/drivers/iio/adc/rockchip_saradc.c
+++ b/drivers/iio/adc/rockchip_saradc.c
@@ -456,6 +456,7 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
 {
 	const struct rockchip_saradc_data *match_data;
 	struct rockchip_saradc *info = NULL;
+	struct device *dev = &pdev->dev;
 	struct device_node *np = pdev->dev.of_node;
 	struct iio_dev *indio_dev = NULL;
 	int ret;
@@ -464,23 +465,21 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
 	if (!np)
 		return -ENODEV;
 
-	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*info));
 	if (!indio_dev)
 		return -ENOMEM;
 
 	info = iio_priv(indio_dev);
 
-	match_data = of_device_get_match_data(&pdev->dev);
+	match_data = of_device_get_match_data(dev);
 	if (!match_data)
-		return dev_err_probe(&pdev->dev, -ENODEV,
-				     "failed to match device\n");
+		return dev_err_probe(dev, -ENODEV, "failed to match device\n");
 
 	info->data = match_data;
 
 	/* Sanity check for possible later IP variants with more channels */
 	if (info->data->num_channels > SARADC_MAX_CHANNELS)
-		return dev_err_probe(&pdev->dev, -EINVAL,
-				     "max channels exceeded");
+		return dev_err_probe(dev, -EINVAL, "max channels exceeded");
 
 	info->regs = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(info->regs))
@@ -490,10 +489,9 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
 	 * The reset should be an optional property, as it should work
 	 * with old devicetrees as well
 	 */
-	info->reset = devm_reset_control_get_optional_exclusive(&pdev->dev,
-								"saradc-apb");
+	info->reset = devm_reset_control_get_optional_exclusive(dev, "saradc-apb");
 	if (IS_ERR(info->reset))
-		return dev_err_probe(&pdev->dev, PTR_ERR(info->reset),
+		return dev_err_probe(dev, PTR_ERR(info->reset),
 				     "failed to get saradc-apb\n");
 
 	init_completion(&info->completion);
@@ -502,14 +500,14 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
 	if (irq < 0)
 		return irq;
 
-	ret = devm_request_irq(&pdev->dev, irq, rockchip_saradc_isr,
+	ret = devm_request_irq(dev, irq, rockchip_saradc_isr,
 			       0, dev_name(&pdev->dev), info);
 	if (ret < 0)
-		return dev_err_probe(&pdev->dev, ret, "failed requesting irq %d\n", irq);
+		return dev_err_probe(dev, ret, "failed requesting irq %d\n", irq);
 
-	info->vref = devm_regulator_get(&pdev->dev, "vref");
+	info->vref = devm_regulator_get(dev, "vref");
 	if (IS_ERR(info->vref))
-		return dev_err_probe(&pdev->dev, PTR_ERR(info->vref),
+		return dev_err_probe(dev, PTR_ERR(info->vref),
 				     "failed to get regulator\n");
 
 	if (info->reset)
@@ -517,11 +515,9 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
 
 	ret = regulator_enable(info->vref);
 	if (ret < 0)
-		return dev_err_probe(&pdev->dev, ret,
-				     "failed to enable vref regulator\n");
+		return dev_err_probe(dev, ret, "failed to enable vref regulator\n");
 
-	ret = devm_add_action_or_reset(&pdev->dev,
-				       rockchip_saradc_regulator_disable, info);
+	ret = devm_add_action_or_reset(dev, rockchip_saradc_regulator_disable, info);
 	if (ret)
 		return ret;
 
@@ -531,14 +527,13 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
 
 	info->uv_vref = ret;
 
-	info->pclk = devm_clk_get_enabled(&pdev->dev, "apb_pclk");
+	info->pclk = devm_clk_get_enabled(dev, "apb_pclk");
 	if (IS_ERR(info->pclk))
-		return dev_err_probe(&pdev->dev, PTR_ERR(info->pclk),
-				     "failed to get pclk\n");
+		return dev_err_probe(dev, PTR_ERR(info->pclk), "failed to get pclk\n");
 
-	info->clk = devm_clk_get_enabled(&pdev->dev, "saradc");
+	info->clk = devm_clk_get_enabled(dev, "saradc");
 	if (IS_ERR(info->clk))
-		return dev_err_probe(&pdev->dev, PTR_ERR(info->clk),
+		return dev_err_probe(dev, PTR_ERR(info->clk),
 				     "failed to get adc clock\n");
 	/*
 	 * Use a default value for the converter clock.
@@ -546,18 +541,17 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
 	 */
 	ret = clk_set_rate(info->clk, info->data->clk_rate);
 	if (ret < 0)
-		return dev_err_probe(&pdev->dev, ret,
-				     "failed to set adc clk rate\n");
+		return dev_err_probe(dev, ret, "failed to set adc clk rate\n");
 
 	platform_set_drvdata(pdev, indio_dev);
 
-	indio_dev->name = dev_name(&pdev->dev);
+	indio_dev->name = dev_name(dev);
 	indio_dev->info = &rockchip_saradc_iio_info;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 
 	indio_dev->channels = info->data->channels;
 	indio_dev->num_channels = info->data->num_channels;
-	ret = devm_iio_triggered_buffer_setup(&indio_dev->dev, indio_dev, NULL,
+	ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
 					      rockchip_saradc_trigger_handler,
 					      NULL);
 	if (ret)
@@ -568,7 +562,7 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	ret = devm_add_action_or_reset(&pdev->dev,
+	ret = devm_add_action_or_reset(dev,
 				       rockchip_saradc_regulator_unreg_notifier,
 				       info);
 	if (ret)
@@ -576,7 +570,7 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
 
 	mutex_init(&info->lock);
 
-	return devm_iio_device_register(&pdev->dev, indio_dev);
+	return devm_iio_device_register(dev, indio_dev);
 }
 
 static int rockchip_saradc_suspend(struct device *dev)
-- 
2.51.0



From krzk at kernel.org  Sun Dec 21 06:57:15 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sun, 21 Dec 2025 15:57:15 +0100
Subject: [PATCH v2 1/2] dt-bindings: arm: cix: add OrangePi 6 Plus board
In-Reply-To: <20251219133553.1440970-2-gary.yang@cixtech.com>
References: <20251219133553.1440970-1-gary.yang@cixtech.com>
 <20251219133553.1440970-2-gary.yang@cixtech.com>
Message-ID: <20251221-conscious-apricot-crayfish-8df20b@quoll>

On Fri, Dec 19, 2025 at 09:35:52PM +0800, Gary Yang wrote:
> OrangePi 6 Plus adopts CIX CD8180/CD8160 SoC,
> built-in 12-core 64-bit processor + NPU processor,
> integrated graphics processor, equipped with 16GB/32GB/64GB

If there is going to be resend/new version, please re-wrap it.

Please wrap commit message according to Linux coding style / submission
process (neither too early nor over the limit):
https://elixir.bootlin.com/linux/v6.4-rc1/source/Documentation/process/submitting-patches.rst#L597

No need to resend just for this.

> LPDDR5, and provides two M.2 KEY-M interfaces 2280 for NVMe SSD,
> as well as SPI FLASH and TF slots to meet the needs of fast
> read/write and high-capacity storage;
> 
> Signed-off-by: Gary Yang <gary.yang at cixtech.com>

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof



From krzk at kernel.org  Sun Dec 21 07:10:44 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sun, 21 Dec 2025 16:10:44 +0100
Subject: [PATCH 1/4] spi: dt-bindings: sun6i: Add compatibles for A523's
 SPI controllers
In-Reply-To: <20251221110513.1850535-2-wens@kernel.org>
References: <20251221110513.1850535-1-wens@kernel.org>
 <20251221110513.1850535-2-wens@kernel.org>
Message-ID: <20251221-tunneling-intelligent-dogfish-d44a01@quoll>

On Sun, Dec 21, 2025 at 07:05:08PM +0800, Chen-Yu Tsai wrote:
> The A523 has four SPI controllers. One of them supports MIPI DBI mode
> in addition to standard SPI.
> 
> Compared to older generations, this newer controller now has a combined
> counter for the RX FIFO ad buffer levels. In older generations, the
> RX buffer level was a separate bitfield in the FIFO status register.
> 
> In practice this difference is negligible. The buffer is mostly
> invisible to the implementation. If programmed I/O transfers are limited
> to the FIFO size, then the contents of the buffer seem to always be
> flushed over to the FIFO. For DMA, the DRQ trigger levels are only tied
> to the FIFO levels. In all other aspects, the controller is the same as
> the one in the R329.
> 
> Add new compatible strings for the new controllers.
> 
> Signed-off-by: Chen-Yu Tsai <wens at kernel.org>
> ---
>  .../devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml      | 4 ++++
>  1 file changed, 4 insertions(+)

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof



From hpa at zytor.com  Sun Dec 21 07:26:10 2025
From: hpa at zytor.com (H. Peter Anvin)
Date: Sun, 21 Dec 2025 07:26:10 -0800
Subject: [PATCH 1/4] arch/*: increase lowmem size to avoid highmem use
In-Reply-To: <4aecb94f-e283-4720-96e5-1837352c3329@kernel.org>
References: <20251219161559.556737-1-arnd@kernel.org> <20251219161559.556737-2-arnd@kernel.org> <a3f22579-13ee-4479-a5fd-81c29145c3f3@intel.com> <bad18ad8-93e8-4150-a85e-a2852e243363@app.fastmail.com> <a2ce2849-e572-404c-9713-9283a43c09fe@intel.com> <4aecb94f-e283-4720-96e5-1837352c3329@kernel.org>
Message-ID: <D1726374-3075-47CF-B2FF-FBAC11BC962C@zytor.com>

On December 21, 2025 1:30:15 AM PST, "David Hildenbrand (Red Hat)" <david at kernel.org> wrote:
>On 12/19/25 21:52, Dave Hansen wrote:
>> On 12/19/25 12:20, Arnd Bergmann wrote:
>>>> For simplicity, I think this can just be:
>>>> 
>>>> -	default VMSPLIT_3G
>>>> +	default VMSPLIT_2G
>>>> 
>>>> I doubt the 2G vs. 2G_OPT matters in very many cases. If it does, folks
>>>> can just set it in their config manually.
>>>> 
>>>> But, in the end, I don't this this matters all that much. If you think
>>>> having x86 be consistent with ARM, for example, is more important and
>>>> ARM really wants this complexity, I can live with it.
>>> Yes, I think we do want the default of VMSPLIT_3G_OPT for
>>> configs that have neither highmem nor lpae, otherwise the most
>>> common embedded configs go from 3072 MiB to 1792 MiB of virtual
>>> addressing, and that is much more likely to cause regressions
>>> than the 2816 MiB default.
>>> 
>>> It would be nice to not need the VMSPLIT_2G default for PAE/LPAE,
>>> but that seems like a larger change.
>> 
>> The only thing we'd "regress" would be someone who is repeatedly
>> starting from scratch with a defconfig and expecting defconfig to be the
>> same all the time. I honestly think that's highly unlikely.
>> 
>> If folks are upgrading and _actually_ exposed to regressions, they've
>> got an existing config and won't be hit by these defaults at *all*. They
>> won't actually regress.
>> 
>> In other words, I think we can be a lot more aggressive about defaults
>> than with the feature set we support. I'd much rather add complexity in
>> here for solving a real problem, like if we have armies of 32-bit x86
>> users constantly starting new projects from scratch and using defconfigs.
>> 
>> I'd _really_ like to keep the defaults as simple as possible.
>
>I agree with that. In particular in areas where there is the chance that we could count the number of people that actually care about that with one hand (in binary ;) ).
>

So, maximum 31? ;)


From jernej.skrabec at gmail.com  Sun Dec 21 07:50:54 2025
From: jernej.skrabec at gmail.com (Jernej =?UTF-8?B?xaBrcmFiZWM=?=)
Date: Sun, 21 Dec 2025 16:50:54 +0100
Subject: [PATCH 2/4] spi: sun6i: Support A523's SPI controllers
In-Reply-To: <20251221110513.1850535-3-wens@kernel.org>
References: <20251221110513.1850535-1-wens@kernel.org>
 <20251221110513.1850535-3-wens@kernel.org>
Message-ID: <2391651.ElGaqSPkdT@jernej-laptop>

Dne nedelja, 21. december 2025 ob 12:05:09 Srednjeevropski standardni ?as je Chen-Yu Tsai napisal(a):
> The A523 has four SPI controllers. One of them supports MIPI DBI mode
> in addition to standard SPI.
> 
> Compared to older generations, this newer controller now has a combined
> counter for the RX FIFO ad buffer levels. In older generations, the
> RX buffer level was a separate bitfield in the FIFO status register.
> 
> In practice this difference is negligible. The buffer is mostly
> invisible to the implementation. If programmed I/O transfers are limited
> to the FIFO size, then the contents of the buffer seem to always be
> flushed over to the FIFO. For DMA, the DRQ trigger levels are only tied
> to the FIFO levels. In all other aspects, the controller is the same as
> the one in the R329.
> 
> Support the standard SPI mode controllers using the settings for R329.
> DBI is left out as there currently is no infrastructure for enabling a
> DBI host controller, as was the case for the R329.
> 
> Also fold the entry for the R329 to make the style consistent.
> 
> Signed-off-by: Chen-Yu Tsai <wens at kernel.org>

Reviewed-by: Jernej Skrabec <jernej.skrabec at gmail.com>

Best regards,
Jernej




From jernej.skrabec at gmail.com  Sun Dec 21 07:51:50 2025
From: jernej.skrabec at gmail.com (Jernej =?UTF-8?B?xaBrcmFiZWM=?=)
Date: Sun, 21 Dec 2025 16:51:50 +0100
Subject: [PATCH 3/4] arm64: dts: allwinner: sun55i: Add SPI controllers
In-Reply-To: <20251221110513.1850535-4-wens@kernel.org>
References: <20251221110513.1850535-1-wens@kernel.org>
 <20251221110513.1850535-4-wens@kernel.org>
Message-ID: <1940379.tdWV9SEqCh@jernej-laptop>

Dne nedelja, 21. december 2025 ob 12:05:10 Srednjeevropski standardni ?as je Chen-Yu Tsai napisal(a):
> The A523 family SoCs have four SPI controllers. One of them also
> supports DBI mode.
> 
> Add device nodes for all of them. Also add pinmux nodes for spi0 on the
> PC pins, which is commonly used for SPI-NOR boot flash.
> 
> Signed-off-by: Chen-Yu Tsai <wens at kernel.org>

Acked-by: Jernej Skrabec <jernej.skrabec at gmail.com>

Best regards,
Jernej




From jernej.skrabec at gmail.com  Sun Dec 21 07:52:49 2025
From: jernej.skrabec at gmail.com (Jernej =?UTF-8?B?xaBrcmFiZWM=?=)
Date: Sun, 21 Dec 2025 16:52:49 +0100
Subject: [PATCH 4/4] arm64: dts: allwinner: t527: orangepi-4a: Enable SPI-NOR
 flash
In-Reply-To: <20251221110513.1850535-5-wens@kernel.org>
References: <20251221110513.1850535-1-wens@kernel.org>
 <20251221110513.1850535-5-wens@kernel.org>
Message-ID: <13909614.uLZWGnKmhe@jernej-laptop>

Dne nedelja, 21. december 2025 ob 12:05:11 Srednjeevropski standardni ?as je Chen-Yu Tsai napisal(a):
> The Orangepi 4A has a SPI-NOR flash connected to spi0 on the PC pins.
> The HOLD and WP pins are not connected, and are instead pulled up by the
> supply rail.
> 
> Enable spi0 and add a device node for the SPI-NOR flash.
> 
> Signed-off-by: Chen-Yu Tsai <wens at kernel.org>

Acked-by: Jernej Skrabec <jernej.skrabec at gmail.com>

Best regards,
Jernej




From jernej.skrabec at gmail.com  Sun Dec 21 07:57:07 2025
From: jernej.skrabec at gmail.com (Jernej =?UTF-8?B?xaBrcmFiZWM=?=)
Date: Sun, 21 Dec 2025 16:57:07 +0100
Subject: [PATCH] dmaengine: sun6i: Choose appropriate burst length under maxburst
In-Reply-To: <20251221080450.1813479-1-wens@kernel.org>
References: <20251221080450.1813479-1-wens@kernel.org>
Message-ID: <3385264.aeNJFYEL58@jernej-laptop>

Dne nedelja, 21. december 2025 ob 09:04:48 Srednjeevropski standardni ?as je Chen-Yu Tsai napisal(a):
> maxburst, as provided by the client, specifies the largest amount of
> data that is allowed to be transferred in one burst. This limit is
> normally provided to avoid a data burst overflowing the target FIFO.
> It does not mean that the DMA engine can only do bursts in that size.
> 
> Let the driver pick the largest supported burst length within the
> given limit. This lets the driver work correctly with some clients that
> give a large maxburst value. In particular, the 8250_dw driver will give
> a quarter of the UART's FIFO size as maxburst. On some systems the FIFO
> size is 256 bytes, giving a maxburst of 64 bytes, while the hardware
> only supports bursts of up to 16 bytes.
> 
> Signed-off-by: Chen-Yu Tsai <wens at kernel.org>

Reviewed-by: Jernej Skrabec <jernej.skrabec at gmail.com>

Best regards,
Jernej




From tzimmermann at suse.de  Sun Dec 21 08:18:28 2025
From: tzimmermann at suse.de (Thomas Zimmermann)
Date: Sun, 21 Dec 2025 17:18:28 +0100
Subject: [PATCH v3 9/9] efi: libstub: Simplify interfaces for
 primary_display
In-Reply-To: <CAMj1kXFeBS7O5A-CPds3UfFnjegGTpVsuF7VznBc-zZ+gjygtw@mail.gmail.com>
References: <20251126160854.553077-1-tzimmermann@suse.de>
 <20251126160854.553077-10-tzimmermann@suse.de>
 <CAMj1kXFeBS7O5A-CPds3UfFnjegGTpVsuF7VznBc-zZ+gjygtw@mail.gmail.com>
Message-ID: <0204b4f2-98b3-4463-9ae7-fc3657ce2fc1@suse.de>

Hi

Am 16.12.25 um 14:23 schrieb Ard Biesheuvel:
> Hi Thomas
>
> On Wed, 26 Nov 2025 at 17:09, Thomas Zimmermann <tzimmermann at suse.de> wrote:
>> Rename alloc_primary_display() and __alloc_primary_display(), clarify
>> free semantics to make interfaces easier to understand.
>>
>> Rename alloc_primary_display() to lookup_primary_display() as it
>> does not necessarily allocate. Then rename __alloc_primary_display()
>> to the new alloc_primary_display(). The helper belongs to
>> free_primary_display), so it should be named without underscores.
>>
>> The lookup helper does not necessarily allocate, so the output
>> parameter needs_free to indicate when free should be called.
> I don't understand why we need this. Whether or not the helper
> allocates is a compile time decision, and in builds where it doesn't,
> the free helper doesn't do anything.
>
> I'm all for making things simpler, but I don't think this patch
> achieves that tbh.
>
> I've queued up this series now up until this patch - once we converge
> on the simplification, I'm happy to apply it on top.

If you don't want this patch, just leave it out then. Coming from 
another subsystem, I found the current logic and naming confusing THB.

Best regards
Thomas


>
> Thanks,
>
>
>
>> Pass
>> an argument through the calls to track this state. Put the free
>> handling into release_primary_display() for simplificy.
>>
>> Also move the comment fro primary_display.c to efi-stub-entry.c,
>> where it now describes lookup_primary_display().
>>
>> Signed-off-by: Thomas Zimmermann <tzimmermann at suse.de>
>> ---
>>   drivers/firmware/efi/libstub/efi-stub-entry.c | 23 +++++++++++++++++--
>>   drivers/firmware/efi/libstub/efi-stub.c       | 22 ++++++++++++------
>>   drivers/firmware/efi/libstub/efistub.h        |  2 +-
>>   .../firmware/efi/libstub/primary_display.c    | 17 +-------------
>>   drivers/firmware/efi/libstub/zboot.c          |  6 +++--
>>   5 files changed, 42 insertions(+), 28 deletions(-)
>>
>> diff --git a/drivers/firmware/efi/libstub/efi-stub-entry.c b/drivers/firmware/efi/libstub/efi-stub-entry.c
>> index aa85e910fe59..3077b51fe0b2 100644
>> --- a/drivers/firmware/efi/libstub/efi-stub-entry.c
>> +++ b/drivers/firmware/efi/libstub/efi-stub-entry.c
>> @@ -14,10 +14,29 @@ static void *kernel_image_addr(void *addr)
>>          return addr + kernel_image_offset;
>>   }
>>
>> -struct sysfb_display_info *alloc_primary_display(void)
>> +/*
>> + * There are two ways of populating the core kernel's sysfb_primary_display
>> + * via the stub:
>> + *
>> + *   - using a configuration table, which relies on the EFI init code to
>> + *     locate the table and copy the contents; or
>> + *
>> + *   - by linking directly to the core kernel's copy of the global symbol.
>> + *
>> + * The latter is preferred because it makes the EFIFB earlycon available very
>> + * early, but it only works if the EFI stub is part of the core kernel image
>> + * itself. The zboot decompressor can only use the configuration table
>> + * approach.
>> + */
>> +
>> +struct sysfb_display_info *lookup_primary_display(bool *needs_free)
>>   {
>> +       *needs_free = true;
>> +
>>          if (IS_ENABLED(CONFIG_ARM))
>> -               return __alloc_primary_display();
>> +               return alloc_primary_display();
>> +
>> +       *needs_free = false;
>>
>>          if (IS_ENABLED(CONFIG_X86) ||
>>              IS_ENABLED(CONFIG_EFI_EARLYCON) ||
>> diff --git a/drivers/firmware/efi/libstub/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c
>> index 42d6073bcd06..dc545f62c62b 100644
>> --- a/drivers/firmware/efi/libstub/efi-stub.c
>> +++ b/drivers/firmware/efi/libstub/efi-stub.c
>> @@ -51,14 +51,14 @@ static bool flat_va_mapping = (EFI_RT_VIRTUAL_OFFSET != 0);
>>   void __weak free_primary_display(struct sysfb_display_info *dpy)
>>   { }
>>
>> -static struct sysfb_display_info *setup_primary_display(void)
>> +static struct sysfb_display_info *setup_primary_display(bool *dpy_needs_free)
>>   {
>>          struct sysfb_display_info *dpy;
>>          struct screen_info *screen = NULL;
>>          struct edid_info *edid = NULL;
>>          efi_status_t status;
>>
>> -       dpy = alloc_primary_display();
>> +       dpy = lookup_primary_display(dpy_needs_free);
>>          if (!dpy)
>>                  return NULL;
>>          screen = &dpy->screen;
>> @@ -68,15 +68,22 @@ static struct sysfb_display_info *setup_primary_display(void)
>>
>>          status = efi_setup_graphics(screen, edid);
>>          if (status != EFI_SUCCESS)
>> -               goto err_free_primary_display;
>> +               goto err___free_primary_display;
>>
>>          return dpy;
>>
>> -err_free_primary_display:
>> -       free_primary_display(dpy);
>> +err___free_primary_display:
>> +       if (*dpy_needs_free)
>> +               free_primary_display(dpy);
>>          return NULL;
>>   }
>>
>> +static void release_primary_display(struct sysfb_display_info *dpy, bool dpy_needs_free)
>> +{
>> +       if (dpy && dpy_needs_free)
>> +               free_primary_display(dpy);
>> +}
>> +
>>   static void install_memreserve_table(void)
>>   {
>>          struct linux_efi_memreserve *rsv;
>> @@ -156,13 +163,14 @@ efi_status_t efi_stub_common(efi_handle_t handle,
>>                               char *cmdline_ptr)
>>   {
>>          struct sysfb_display_info *dpy;
>> +       bool dpy_needs_free;
>>          efi_status_t status;
>>
>>          status = check_platform_features();
>>          if (status != EFI_SUCCESS)
>>                  return status;
>>
>> -       dpy = setup_primary_display();
>> +       dpy = setup_primary_display(&dpy_needs_free);
>>
>>          efi_retrieve_eventlog();
>>
>> @@ -182,7 +190,7 @@ efi_status_t efi_stub_common(efi_handle_t handle,
>>
>>          status = efi_boot_kernel(handle, image, image_addr, cmdline_ptr);
>>
>> -       free_primary_display(dpy);
>> +       release_primary_display(dpy, dpy_needs_free);
>>
>>          return status;
>>   }
>> diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
>> index 979a21818cc1..1503ffb82903 100644
>> --- a/drivers/firmware/efi/libstub/efistub.h
>> +++ b/drivers/firmware/efi/libstub/efistub.h
>> @@ -1176,8 +1176,8 @@ efi_enable_reset_attack_mitigation(void) { }
>>
>>   void efi_retrieve_eventlog(void);
>>
>> +struct sysfb_display_info *lookup_primary_display(bool *needs_free);
>>   struct sysfb_display_info *alloc_primary_display(void);
>> -struct sysfb_display_info *__alloc_primary_display(void);
>>   void free_primary_display(struct sysfb_display_info *dpy);
>>
>>   void efi_cache_sync_image(unsigned long image_base,
>> diff --git a/drivers/firmware/efi/libstub/primary_display.c b/drivers/firmware/efi/libstub/primary_display.c
>> index cdaebab26514..34c54ac1e02a 100644
>> --- a/drivers/firmware/efi/libstub/primary_display.c
>> +++ b/drivers/firmware/efi/libstub/primary_display.c
>> @@ -7,24 +7,9 @@
>>
>>   #include "efistub.h"
>>
>> -/*
>> - * There are two ways of populating the core kernel's sysfb_primary_display
>> - * via the stub:
>> - *
>> - *   - using a configuration table, which relies on the EFI init code to
>> - *     locate the table and copy the contents; or
>> - *
>> - *   - by linking directly to the core kernel's copy of the global symbol.
>> - *
>> - * The latter is preferred because it makes the EFIFB earlycon available very
>> - * early, but it only works if the EFI stub is part of the core kernel image
>> - * itself. The zboot decompressor can only use the configuration table
>> - * approach.
>> - */
>> -
>>   static efi_guid_t primary_display_guid = LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID;
>>
>> -struct sysfb_display_info *__alloc_primary_display(void)
>> +struct sysfb_display_info *alloc_primary_display(void)
>>   {
>>          struct sysfb_display_info *dpy;
>>          efi_status_t status;
>> diff --git a/drivers/firmware/efi/libstub/zboot.c b/drivers/firmware/efi/libstub/zboot.c
>> index 4b76f74c56da..c1fd1fdbcb08 100644
>> --- a/drivers/firmware/efi/libstub/zboot.c
>> +++ b/drivers/firmware/efi/libstub/zboot.c
>> @@ -26,9 +26,11 @@ void __weak efi_cache_sync_image(unsigned long image_base,
>>          // executable code loaded into memory to be safe for execution.
>>   }
>>
>> -struct sysfb_display_info *alloc_primary_display(void)
>> +struct sysfb_display_info *lookup_primary_display(bool *needs_free)
>>   {
>> -       return __alloc_primary_display();
>> +       *needs_free = true;
>> +
>> +       return alloc_primary_display();
>>   }
>>
>>   asmlinkage efi_status_t __efiapi
>> --
>> 2.51.1
>>

-- 
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstr. 146, 90461 N?rnberg, Germany, www.suse.com
GF: Jochen Jaser, Andrew McDonald, Werner Knoblich, (HRB 36809, AG N?rnberg)




From jernej.skrabec at gmail.com  Sun Dec 21 10:52:50 2025
From: jernej.skrabec at gmail.com (Jernej =?UTF-8?B?xaBrcmFiZWM=?=)
Date: Sun, 21 Dec 2025 19:52:50 +0100
Subject: [PATCH v2 1/4] dt-bindings: pwm: allwinner: add h616 pwm compatible
In-Reply-To: <20251217082504.80226-2-richard.genoud@bootlin.com>
References: <20251217082504.80226-1-richard.genoud@bootlin.com>
 <20251217082504.80226-2-richard.genoud@bootlin.com>
Message-ID: <10771871.nUPlyArG6x@jernej-laptop>

Dne sreda, 17. december 2025 ob 09:25:01 Srednjeevropski standardni ?as je Richard Genoud napisal(a):
> Allwinner H616 PWM block is quite different from the A10 or H6, but at
> the end, it uses the same clocks as the H6; so the sun4i pwm binding can
> be used.
> It has 6 channels than can generate PWM waveforms or clocks if bypass is
> enabled.
> 
> Suggested-by: Krzysztof Kozlowski <krzk at kernel.org>
> Signed-off-by: Richard Genoud <richard.genoud at bootlin.com>
> ---
>  .../bindings/pwm/allwinner,sun4i-a10-pwm.yaml | 19 ++++++++++++++++++-
>  1 file changed, 18 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml b/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml
> index 1197858e431f..4f58110ec98f 100644
> --- a/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml
> +++ b/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml
> @@ -14,6 +14,9 @@ properties:
>    "#pwm-cells":
>      const: 3
>  
> +  "#clock-cells":
> +    const: 1

Why #clock-cells? I don't see any reason to add it.

Other properties seem fine.

Best regards,
Jernej

> +
>    compatible:
>      oneOf:
>        - const: allwinner,sun4i-a10-pwm
> @@ -36,6 +39,7 @@ properties:
>            - const: allwinner,sun50i-h5-pwm
>            - const: allwinner,sun5i-a13-pwm
>        - const: allwinner,sun50i-h6-pwm
> +      - const: allwinner,sun50i-h616-pwm
>  
>    reg:
>      maxItems: 1
> @@ -62,7 +66,9 @@ allOf:
>        properties:
>          compatible:
>            contains:
> -            const: allwinner,sun50i-h6-pwm
> +            enum:
> +              - allwinner,sun50i-h6-pwm
> +              - allwinner,sun50i-h616-pwm
>  
>      then:
>        properties:
> @@ -83,6 +89,17 @@ allOf:
>          clocks:
>            maxItems: 1
>  
> +  - if:
> +      not:
> +        properties:
> +          compatible:
> +            contains:
> +              const: allwinner,sun50i-h616-pwm
> +
> +    then:
> +      properties:
> +        "#clock-cells": false
> +
>  required:
>    - compatible
>    - reg
> 






From jernej.skrabec at gmail.com  Sun Dec 21 11:12:18 2025
From: jernej.skrabec at gmail.com (Jernej =?UTF-8?B?xaBrcmFiZWM=?=)
Date: Sun, 21 Dec 2025 20:12:18 +0100
Subject: [PATCH v2 0/4] Introduce Allwinner H616 PWM controller
In-Reply-To: <20251217082504.80226-1-richard.genoud@bootlin.com>
References: <20251217082504.80226-1-richard.genoud@bootlin.com>
Message-ID: <6113404.MhkbZ0Pkbq@jernej-laptop>

Dne sreda, 17. december 2025 ob 09:25:00 Srednjeevropski standardni ?as je Richard Genoud napisal(a):
> Allwinner H616 PWM controller is quite different from the A10 one.
> 
> It can drive 6 PWM channels, and like for the A10, each channel has a
> bypass that permits to output a clock, bypassing the PWM logic, when
> enabled.
> 
> But, the channels are paired 2 by 2, sharing a first set of
> MUX/prescaler/gate.
> Then, for each channel, there's another prescaler (that will be bypassed
> if the bypass is enabled for this channel).
> 
> It looks like that:
>             _____      ______      ________
> OSC24M --->|     |    |      |    |        |
> APB1 ----->| Mux |--->| Gate |--->| /div_m |-----> PWM_clock_src_xy
>            |_____|    |______|    |________|
>                           ________
>                          |        |
>                       +->| /div_k |---> PWM_clock_x
>                       |  |________|
>                       |    ______
>                       |   |      |
>                       +-->| Gate |----> PWM_bypass_clock_x
>                       |   |______|
> PWM_clock_src_xy -----+   ________
>                       |  |        |
>                       +->| /div_k |---> PWM_clock_y
>                       |  |________|
>                       |    ______
>                       |   |      |
>                       +-->| Gate |----> PWM_bypass_clock_y
>                           |______|
> 
> Where xy can be 0/1, 2/3, 4/5
> 
> PWM_clock_x/y serve for the PWM purpose.
> PWM_bypass_clock_x/y serve for the clock-provider purpose.
> The common clock framework has been used to manage those clocks.
> 
> This PWM driver serves as a clock-provider for PWM_bypass_clocks.
> This is needed for example by the embedded AC300 PHY which clock comes
> from PMW5 pin (PB12).

No. Drop all clocks related code and make this pure PWM driver, like pwm-sun4i
is. For AC300, AC200 or whatever other device may need clock produced by PWM,
pwm-clock can be used like this:

ac300_pwm_clk: ac300-clk {
	compatible = "pwm-clock";
	#clock-cells = <0>;
	clock-frequency = <24000000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pwm1_pin>;
	pwms = <&pwm 1 42 0>;
};

ac300 {
	...
	clocks = <&ac300_pwm_clk>;
	...
};

Best regards,
Jernej

> 
> This series is based onto v6.19-rc1
> 
> Changes since v1:
> - rebase onto v6.19-rc1
> - add missing headers
> - remove MODULE_ALIAS (suggested by Krzysztof)
> - use sun4i-pwm binding instead of creating a new one (suggested by Krzysztof)
> - retrieve the parent clocks from the devicetree
> - switch num_parents to unsigned int
> 
> Richard Genoud (4):
>   dt-bindings: pwm: allwinner: add h616 pwm compatible
>   pwm: sun50i: Add H616 PWM support
>   arm64: dts: allwinner: h616: add PWM controller
>   MAINTAINERS: Add entry on Allwinner H616 PWM driver
> 
>  .../bindings/pwm/allwinner,sun4i-a10-pwm.yaml |  19 +-
>  MAINTAINERS                                   |   5 +
>  .../arm64/boot/dts/allwinner/sun50i-h616.dtsi |  47 +
>  drivers/pwm/Kconfig                           |  12 +
>  drivers/pwm/Makefile                          |   1 +
>  drivers/pwm/pwm-sun50i-h616.c                 | 892 ++++++++++++++++++
>  6 files changed, 975 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/pwm/pwm-sun50i-h616.c
> 
> 
> base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
> 






From 21cnbao at gmail.com  Sun Dec 21 11:24:58 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Mon, 22 Dec 2025 03:24:58 +0800
Subject: [PATCH 5/6] dma-mapping: Allow batched DMA sync operations if supported by the arch
In-Reply-To: <20251221115523.GI13030@unreal>
References: <20251221115523.GI13030@unreal>
Message-ID: <20251221192458.1320-1-21cnbao@gmail.com>

On Sun, Dec 21, 2025 at 7:55?PM Leon Romanovsky <leon at kernel.org> wrote:
[...]
> > +
>
> I'm wondering why you don't implement this batch?sync support inside the
> arch_sync_dma_*() functions. Doing so would minimize changes to the generic
> kernel/dma/* code and reduce the amount of #ifdef?based spaghetti.
>

There are two cases: mapping an sg list and mapping a single
buffer. The former can be batched with
arch_sync_dma_*_batch_add() and flushed via
arch_sync_dma_batch_flush(), while the latter requires all work to
be done inside arch_sync_dma_*(). Therefore,
arch_sync_dma_*() cannot always batch and flush.

But yes, I can drop the ifdef in this patch. I have rewritten the entire
patch as shown below, and it will be tested today prior to
resending v2. Before I send v2, you are very welcome to comment.


>From c03aae12c608b25fc1a84931ce78dbe3ef0f1ebe Mon Sep 17 00:00:00 2001
From: Barry Song <v-songbaohua at oppo.com>
Date: Wed, 29 Oct 2025 10:31:15 +0800
Subject: [PATCH v2 FOR DISCUSION 5/6] dma-mapping: Allow batched DMA sync operations

This enables dma_direct_sync_sg_for_device, dma_direct_sync_sg_for_cpu,
dma_direct_map_sg, and dma_direct_unmap_sg to use batched DMA sync
operations when possible. This significantly improves performance on
devices without hardware cache coherence.

Tangquan's initial results show that batched synchronization can reduce
dma_map_sg() time by 64.61% and dma_unmap_sg() time by 66.60% on an MTK
phone platform (MediaTek Dimensity 9500). The tests were performed by
pinning the task to CPU7 and fixing the CPU frequency at 2.6 GHz,
running dma_map_sg() and dma_unmap_sg() on 10 MB buffers (10 MB / 4 KB
sg entries per buffer) for 200 iterations and then averaging the
results.

Signed-off-by: Barry Song <v-songbaohua at oppo.com>
---
 kernel/dma/direct.c | 28 +++++++++++++++------
 kernel/dma/direct.h | 59 +++++++++++++++++++++++++++++++++++++--------
 2 files changed, 69 insertions(+), 18 deletions(-)

diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index 50c3fe2a1d55..ed2339b0c5e7 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -403,9 +403,10 @@ void dma_direct_sync_sg_for_device(struct device *dev,
 		swiotlb_sync_single_for_device(dev, paddr, sg->length, dir);
 
 		if (!dev_is_dma_coherent(dev))
-			arch_sync_dma_for_device(paddr, sg->length,
-					dir);
+			arch_sync_dma_for_device_batch_add(paddr, sg->length, dir);
 	}
+	if (!dev_is_dma_coherent(dev))
+		arch_sync_dma_batch_flush();
 }
 #endif
 
@@ -422,7 +423,7 @@ void dma_direct_sync_sg_for_cpu(struct device *dev,
 		phys_addr_t paddr = dma_to_phys(dev, sg_dma_address(sg));
 
 		if (!dev_is_dma_coherent(dev))
-			arch_sync_dma_for_cpu(paddr, sg->length, dir);
+			arch_sync_dma_for_cpu_batch_add(paddr, sg->length, dir);
 
 		swiotlb_sync_single_for_cpu(dev, paddr, sg->length, dir);
 
@@ -430,8 +431,10 @@ void dma_direct_sync_sg_for_cpu(struct device *dev,
 			arch_dma_mark_clean(paddr, sg->length);
 	}
 
-	if (!dev_is_dma_coherent(dev))
+	if (!dev_is_dma_coherent(dev)) {
 		arch_sync_dma_for_cpu_all();
+		arch_sync_dma_batch_flush();
+	}
 }
 
 /*
@@ -443,14 +446,19 @@ void dma_direct_unmap_sg(struct device *dev, struct scatterlist *sgl,
 {
 	struct scatterlist *sg;
 	int i;
+	bool need_sync = false;
 
 	for_each_sg(sgl,  sg, nents, i) {
-		if (sg_dma_is_bus_address(sg))
+		if (sg_dma_is_bus_address(sg)) {
 			sg_dma_unmark_bus_address(sg);
-		else
-			dma_direct_unmap_phys(dev, sg->dma_address,
+		} else {
+			need_sync = true;
+			dma_direct_unmap_phys_batch_add(dev, sg->dma_address,
 					      sg_dma_len(sg), dir, attrs);
+		}
 	}
+	if (need_sync && !dev_is_dma_coherent(dev))
+		arch_sync_dma_batch_flush();
 }
 #endif
 
@@ -460,6 +468,7 @@ int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
 	struct pci_p2pdma_map_state p2pdma_state = {};
 	struct scatterlist *sg;
 	int i, ret;
+	bool need_sync = false;
 
 	for_each_sg(sgl, sg, nents, i) {
 		switch (pci_p2pdma_state(&p2pdma_state, dev, sg_page(sg))) {
@@ -471,7 +480,8 @@ int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
 			 */
 			break;
 		case PCI_P2PDMA_MAP_NONE:
-			sg->dma_address = dma_direct_map_phys(dev, sg_phys(sg),
+			need_sync = true;
+			sg->dma_address = dma_direct_map_phys_batch_add(dev, sg_phys(sg),
 					sg->length, dir, attrs);
 			if (sg->dma_address == DMA_MAPPING_ERROR) {
 				ret = -EIO;
@@ -491,6 +501,8 @@ int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
 		sg_dma_len(sg) = sg->length;
 	}
 
+	if (need_sync && !dev_is_dma_coherent(dev))
+		arch_sync_dma_batch_flush();
 	return nents;
 
 out_unmap:
diff --git a/kernel/dma/direct.h b/kernel/dma/direct.h
index da2fadf45bcd..2e25af887204 100644
--- a/kernel/dma/direct.h
+++ b/kernel/dma/direct.h
@@ -64,13 +64,16 @@ static inline void dma_direct_sync_single_for_device(struct device *dev,
 		arch_sync_dma_for_device(paddr, size, dir);
 }
 
-static inline void dma_direct_sync_single_for_cpu(struct device *dev,
-		dma_addr_t addr, size_t size, enum dma_data_direction dir)
+static inline void __dma_direct_sync_single_for_cpu(struct device *dev,
+		dma_addr_t addr, size_t size, enum dma_data_direction dir,
+		bool flush)
 {
 	phys_addr_t paddr = dma_to_phys(dev, addr);
 
 	if (!dev_is_dma_coherent(dev)) {
-		arch_sync_dma_for_cpu(paddr, size, dir);
+		arch_sync_dma_for_cpu_batch_add(paddr, size, dir);
+		if (flush)
+			arch_sync_dma_batch_flush();
 		arch_sync_dma_for_cpu_all();
 	}
 
@@ -80,9 +83,15 @@ static inline void dma_direct_sync_single_for_cpu(struct device *dev,
 		arch_dma_mark_clean(paddr, size);
 }
 
-static inline dma_addr_t dma_direct_map_phys(struct device *dev,
+static inline void dma_direct_sync_single_for_cpu(struct device *dev,
+		dma_addr_t addr, size_t size, enum dma_data_direction dir)
+{
+	__dma_direct_sync_single_for_cpu(dev, addr, size, dir, true);
+}
+
+static inline dma_addr_t __dma_direct_map_phys(struct device *dev,
 		phys_addr_t phys, size_t size, enum dma_data_direction dir,
-		unsigned long attrs)
+		unsigned long attrs, bool flush)
 {
 	dma_addr_t dma_addr;
 
@@ -109,8 +118,11 @@ static inline dma_addr_t dma_direct_map_phys(struct device *dev,
 	}
 
 	if (!dev_is_dma_coherent(dev) &&
-	    !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO)))
-		arch_sync_dma_for_device(phys, size, dir);
+	    !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO))) {
+		arch_sync_dma_for_device_batch_add(phys, size, dir);
+		if (flush)
+			arch_sync_dma_batch_flush();
+	}
 	return dma_addr;
 
 err_overflow:
@@ -121,8 +133,23 @@ static inline dma_addr_t dma_direct_map_phys(struct device *dev,
 	return DMA_MAPPING_ERROR;
 }
 
-static inline void dma_direct_unmap_phys(struct device *dev, dma_addr_t addr,
-		size_t size, enum dma_data_direction dir, unsigned long attrs)
+static inline dma_addr_t dma_direct_map_phys(struct device *dev,
+		phys_addr_t phys, size_t size, enum dma_data_direction dir,
+		unsigned long attrs)
+{
+	return __dma_direct_map_phys(dev, phys, size, dir, attrs, true);
+}
+
+static inline dma_addr_t dma_direct_map_phys_batch_add(struct device *dev,
+		phys_addr_t phys, size_t size, enum dma_data_direction dir,
+		unsigned long attrs)
+{
+	return __dma_direct_map_phys(dev, phys, size, dir, attrs, false);
+}
+
+static inline void __dma_direct_unmap_phys(struct device *dev, dma_addr_t addr,
+		size_t size, enum dma_data_direction dir, unsigned long attrs,
+		bool flush)
 {
 	phys_addr_t phys;
 
@@ -132,9 +159,21 @@ static inline void dma_direct_unmap_phys(struct device *dev, dma_addr_t addr,
 
 	phys = dma_to_phys(dev, addr);
 	if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
-		dma_direct_sync_single_for_cpu(dev, addr, size, dir);
+		__dma_direct_sync_single_for_cpu(dev, addr, size, dir, flush);
 
 	swiotlb_tbl_unmap_single(dev, phys, size, dir,
 					 attrs | DMA_ATTR_SKIP_CPU_SYNC);
 }
+
+static inline void dma_direct_unmap_phys(struct device *dev, dma_addr_t addr,
+		size_t size, enum dma_data_direction dir, unsigned long attrs)
+{
+	__dma_direct_unmap_phys(dev, addr, size, dir, attrs, true);
+}
+
+static inline void dma_direct_unmap_phys_batch_add(struct device *dev, dma_addr_t addr,
+		size_t size, enum dma_data_direction dir, unsigned long attrs)
+{
+	__dma_direct_unmap_phys(dev, addr, size, dir, attrs, false);
+}
 #endif /* _KERNEL_DMA_DIRECT_H */
-- 
2.39.3 (Apple Git-146)


From lkp at intel.com  Sun Dec 21 11:31:25 2025
From: lkp at intel.com (kernel test robot)
Date: Sun, 21 Dec 2025 20:31:25 +0100
Subject: [PATCH 02/12] ras: add estatus core implementation
In-Reply-To: <20251217112845.1814119-3-ahmed.tiba@arm.com>
References: <20251217112845.1814119-3-ahmed.tiba@arm.com>
Message-ID: <202512212012.arq4zqYv-lkp@intel.com>

Hi Ahmed,

kernel test robot noticed the following build warnings:

[auto build test WARNING on efi/next]
[also build test WARNING on rafael-pm/linux-next rafael-pm/bleeding-edge robh/for-next linus/master v6.19-rc1 next-20251219]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Ahmed-Tiba/ras-add-estatus-core-interfaces/20251217-200718
base:   https://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git next
patch link:    https://lore.kernel.org/r/20251217112845.1814119-3-ahmed.tiba%40arm.com
patch subject: [PATCH 02/12] ras: add estatus core implementation
config: x86_64-rhel-9.4 (https://download.01.org/0day-ci/archive/20251221/202512212012.arq4zqYv-lkp at intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251221/202512212012.arq4zqYv-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512212012.arq4zqYv-lkp at intel.com/

All warnings (new ones prefixed by >>):

   drivers/firmware/efi/estatus.c:505:13: warning: 'estatus_cache_add' defined but not used [-Wunused-function]
     505 | static void estatus_cache_add(struct estatus_source *source,
         |             ^~~~~~~~~~~~~~~~~
   drivers/firmware/efi/estatus.c:435:12: warning: 'estatus_cached' defined but not used [-Wunused-function]
     435 | static int estatus_cached(struct acpi_hest_generic_status *estatus)
         |            ^~~~~~~~~~~~~~
   drivers/firmware/efi/estatus.c:411:12: warning: 'estatus_print_estatus' defined but not used [-Wunused-function]
     411 | static int estatus_print_estatus(const char *pfx,
         |            ^~~~~~~~~~~~~~~~~~~~~
   drivers/firmware/efi/estatus.c:340:13: warning: 'estatus_clear_estatus' defined but not used [-Wunused-function]
     340 | static void estatus_clear_estatus(struct estatus_source *source,
         |             ^~~~~~~~~~~~~~~~~~~~~
   drivers/firmware/efi/estatus.c:321:12: warning: 'estatus_read_estatus' defined but not used [-Wunused-function]
     321 | static int estatus_read_estatus(struct estatus_source *source,
         |            ^~~~~~~~~~~~~~~~~~~~
>> drivers/firmware/efi/estatus.c:117:12: warning: 'estatus_panic_timeout' defined but not used [-Wunused-variable]
     117 | static int estatus_panic_timeout __read_mostly = 30;
         |            ^~~~~~~~~~~~~~~~~~~~~
   In file included from arch/x86/include/asm/uprobes.h:13,
                    from include/linux/uprobes.h:66,
                    from include/linux/mm_types.h:16,
                    from include/linux/mmzone.h:22,
                    from include/linux/gfp.h:7,
                    from include/linux/xarray.h:16,
                    from include/linux/list_lru.h:14,
                    from include/linux/fs/super_types.h:7,
                    from include/linux/fs/super.h:5,
                    from include/linux/fs.h:5,
                    from include/linux/seq_file.h:11,
                    from include/linux/seq_buf.h:7,
                    from include/linux/trace_seq.h:5,
                    from include/linux/cper.h:13,
                    from drivers/firmware/efi/estatus.c:10:
   drivers/firmware/efi/estatus.c:106:29: warning: 'estatus_report_chain' defined but not used [-Wunused-variable]
     106 | static ATOMIC_NOTIFIER_HEAD(estatus_report_chain);
         |                             ^~~~~~~~~~~~~~~~~~~~
   include/linux/notifier.h:116:37: note: in definition of macro 'ATOMIC_NOTIFIER_HEAD'
     116 |         struct atomic_notifier_head name =                      \
         |                                     ^~~~


vim +/estatus_panic_timeout +117 drivers/firmware/efi/estatus.c

   116	
 > 117	static int estatus_panic_timeout __read_mostly = 30;
   118	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From joel-linux at jmay.us  Sun Dec 21 13:48:56 2025
From: joel-linux at jmay.us (Joel May)
Date: Sun, 21 Dec 2025 13:48:56 -0800
Subject: [PATCH] arm64: perf: fix syscalltbl path base
In-Reply-To: <20251215112818.GB681384@e132581.arm.com>
References: <b2651f20-6f3a-49f5-9cd8-3fb028b2cab5@app.fastmail.com>
 <fcefc3c0-541d-40cc-84e3-9c2460308bdb@linaro.org>
 <23c07ac4-ff13-47a5-824a-e7af1d1847a3@app.fastmail.com>
 <bda366b4-fa53-4feb-a7ce-ee47cfc404b5@linaro.org>
 <20251215112818.GB681384@e132581.arm.com>
Message-ID: <c8161700-ad9d-43d3-8c45-cfc110ebcd49@app.fastmail.com>

On Mon, Dec 15, 2025, at 03:28, Leo Yan wrote:
> On Mon, Dec 15, 2025 at 12:52:24PM +0200, James Clark wrote:
> > On 15/12/2025 11:33, Arnd Bergmann wrote:
> > > On Mon, Dec 15, 2025, at 09:47, James Clark wrote:
> > > > On 15/12/2025 00:12, Joel May wrote:
> > > > 
> > > > Hi Joel,
> > > > 
> > > > There is a similar fix on the list here:
> > > > 
> > > > https://lore.kernel.org/linux-perf-users/20251204-perf_fix_syscall_header-v1-1-b8e27f74ed6a at arm.com/
> > > > 
> > > > I'm not sure if commit 1 alone will also fix your issue, or we'd need to
> > > > collapse both of the commits in that set.
> 
> We need to apply both patches in the share link - we need to apply the
> second patch to revert generating unistd_64.h in libperf.

Yes, applying both of those patches will mitigate my problem.

Neither of those patches update syscalltbl in
arm/arm64/kernel/Makefile.syscalls though.  Based on the context in
scripts/Makefile.asm-headers, it looks like syscalltbl is always intended
to be relative to srctree.  So, my patch increases consistency, even if
it's not fixing any known problem (after the other patches are applied).

Whether headers are dynamically generated or not, it seems like this is
something that can be improved anyway.

This is my first time contributing to the Linux kernel, so please bare with
my ignorance.  I don't know whether it's acceptable to consider patches
that conceptually improve something without an actual problem they're
solving.

Thanks,
--Joel


From martin.blumenstingl at googlemail.com  Sun Dec 21 13:50:23 2025
From: martin.blumenstingl at googlemail.com (Martin Blumenstingl)
Date: Sun, 21 Dec 2025 22:50:23 +0100
Subject: [PATCH v3 10/22] drm/meson: encoder_cvbs: get/put the next bridge
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-10-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
 <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-10-b5165fab8058@bootlin.com>
Message-ID: <CAFBinCDt=9H1ccXatr8JYA=atG+vDCBX9x0xor9kibUfo1NKpA@mail.gmail.com>

On Tue, Dec 16, 2025 at 7:00?PM Luca Ceresoli <luca.ceresoli at bootlin.com> wrote:
>
> This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
> function and stores it until driver removal. of_drm_find_bridge() is
> deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
> refcounted and use bridge->next_bridge to put the reference on
> deallocation.
>
> Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
Reviewed-by: Martin Blumenstingl <martin.blumenstingl at googlemail.com>


From martin.blumenstingl at googlemail.com  Sun Dec 21 13:50:39 2025
From: martin.blumenstingl at googlemail.com (Martin Blumenstingl)
Date: Sun, 21 Dec 2025 22:50:39 +0100
Subject: [PATCH v3 11/22] drm/meson: encoder_dsi: get/put the next bridge
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-11-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
 <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-11-b5165fab8058@bootlin.com>
Message-ID: <CAFBinCArG=-pNRHZTdZX1CDDPrs02zpRJ29GSEUA6TcUckQvww@mail.gmail.com>

On Tue, Dec 16, 2025 at 7:00?PM Luca Ceresoli <luca.ceresoli at bootlin.com> wrote:
>
> This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
> function and stores it until driver removal. of_drm_find_bridge() is
> deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
> refcounted and use bridge->next_bridge to put the reference on
> deallocation.
>
> Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
Reviewed-by: Martin Blumenstingl <martin.blumenstingl at googlemail.com>


From martin.blumenstingl at googlemail.com  Sun Dec 21 13:51:46 2025
From: martin.blumenstingl at googlemail.com (Martin Blumenstingl)
Date: Sun, 21 Dec 2025 22:51:46 +0100
Subject: [PATCH v3 12/22] drm/meson: encoder_hdmi: get/put the next bridge
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-12-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
 <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-12-b5165fab8058@bootlin.com>
Message-ID: <CAFBinCCUVOYsiwwVmyGtxN=MdqYatAaj-piVO9_E_iZX9gwiMQ@mail.gmail.com>

On Tue, Dec 16, 2025 at 7:00?PM Luca Ceresoli <luca.ceresoli at bootlin.com> wrote:
>
> This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
> function and stores it until driver removal. of_drm_find_bridge() is
> deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
> refcounted and use bridge->next_bridge to put the reference on
> deallocation.
>
> Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
Reviewed-by: Martin Blumenstingl <martin.blumenstingl at googlemail.com>
And additionally I runtime tested this on meson-gxl-s905x-libretech-cc
where I still have HDMI output, so:
Tested-by: Martin Blumenstingl <martin.blumenstingl at googlemail.com>


From lkp at intel.com  Sun Dec 21 14:04:51 2025
From: lkp at intel.com (kernel test robot)
Date: Mon, 22 Dec 2025 06:04:51 +0800
Subject: [PATCH] drm/mediatek: Convert legacy DRM logging to drm_*
 helpers in mtk_crtc.c
In-Reply-To: <20251217070303.689913-1-abhiraj21put@gmail.com>
References: <20251217070303.689913-1-abhiraj21put@gmail.com>
Message-ID: <202512220515.z3QybJ8I-lkp@intel.com>

Hi Abhishek,

kernel test robot noticed the following build warnings:

[auto build test WARNING on drm-misc/drm-misc-next]
[also build test WARNING on pza/reset/next linus/master v6.19-rc1 next-20251219]
[cannot apply to pza/imx-drm/next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Abhishek-Rajput/drm-mediatek-Convert-legacy-DRM-logging-to-drm_-helpers-in-mtk_crtc-c/20251217-150453
base:   https://gitlab.freedesktop.org/drm/misc/kernel.git drm-misc-next
patch link:    https://lore.kernel.org/r/20251217070303.689913-1-abhiraj21put%40gmail.com
patch subject: [PATCH] drm/mediatek: Convert legacy DRM logging to drm_* helpers in mtk_crtc.c
config: loongarch-randconfig-r062-20251218 (https://download.01.org/0day-ci/archive/20251222/202512220515.z3QybJ8I-lkp at intel.com/config)
compiler: loongarch64-linux-gcc (GCC) 12.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251222/202512220515.z3QybJ8I-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512220515.z3QybJ8I-lkp at intel.com/

All warnings (new ones prefixed by >>):

   In file included from include/linux/lockdep.h:15,
                    from include/linux/mutex.h:17,
                    from include/linux/notifier.h:14,
                    from include/linux/clk.h:14,
                    from drivers/gpu/drm/mediatek/mtk_crtc.c:6:
   arch/loongarch/include/asm/percpu.h:20:4: error: #error compiler support for the model attribute is necessary when a recent assembler is used
      20 | #  error compiler support for the model attribute is necessary when a recent assembler is used
         |    ^~~~~
   drivers/gpu/drm/mediatek/mtk_crtc.c: In function 'mtk_crtc_ddp_irq':
>> drivers/gpu/drm/mediatek/mtk_crtc.c:651:28: warning: unused variable 'dev' [-Wunused-variable]
     651 |         struct drm_device *dev = mtk_crtc->base.dev;
         |                            ^~~


vim +/dev +651 drivers/gpu/drm/mediatek/mtk_crtc.c

   645	
   646	static void mtk_crtc_ddp_irq(void *data)
   647	{
   648		struct drm_crtc *crtc = data;
   649		struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
   650		struct mtk_drm_private *priv = crtc->dev->dev_private;
 > 651		struct drm_device *dev = mtk_crtc->base.dev;
   652	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From lkp at intel.com  Sun Dec 21 15:39:10 2025
From: lkp at intel.com (kernel test robot)
Date: Mon, 22 Dec 2025 00:39:10 +0100
Subject: [PATCH 03/12] ras: add estatus vendor handling and processing
In-Reply-To: <20251217112845.1814119-4-ahmed.tiba@arm.com>
References: <20251217112845.1814119-4-ahmed.tiba@arm.com>
Message-ID: <202512220010.sdcS5LYV-lkp@intel.com>

Hi Ahmed,

kernel test robot noticed the following build errors:

[auto build test ERROR on efi/next]
[also build test ERROR on rafael-pm/linux-next rafael-pm/bleeding-edge robh/for-next arm64/for-next/core linus/master v6.19-rc1 next-20251219]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Ahmed-Tiba/ras-add-estatus-core-interfaces/20251217-200718
base:   https://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git next
patch link:    https://lore.kernel.org/r/20251217112845.1814119-4-ahmed.tiba%40arm.com
patch subject: [PATCH 03/12] ras: add estatus vendor handling and processing
config: x86_64-rhel-9.4 (https://download.01.org/0day-ci/archive/20251222/202512220010.sdcS5LYV-lkp at intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251222/202512220010.sdcS5LYV-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512220010.sdcS5LYV-lkp at intel.com/

All errors (new ones prefixed by >>):

   drivers/firmware/efi/estatus.c: In function 'estatus_source_fixmap':
>> drivers/firmware/efi/estatus.c:126:24: error: 'FIX_HOLE' undeclared (first use in this function)
     126 |                 return FIX_HOLE;
         |                        ^~~~~~~~
   drivers/firmware/efi/estatus.c:126:24: note: each undeclared identifier is reported only once for each function it appears in
   drivers/firmware/efi/estatus.c: In function 'estatus_handle_arm_hw_error':
   drivers/firmware/efi/estatus.c:656:9: error: too few arguments to function 'log_arm_hw_error'
     656 |         log_arm_hw_error(err);
         |         ^~~~~~~~~~~~~~~~
   In file included from drivers/firmware/efi/estatus.c:23:
   include/linux/ras.h:27:6: note: declared here
      27 | void log_arm_hw_error(struct cper_sec_proc_arm *err, const u8 sev);
         |      ^~~~~~~~~~~~~~~~
   In file included from drivers/firmware/efi/estatus.c:30:
   drivers/firmware/efi/estatus.c: In function 'estatus_do_proc':
   include/linux/estatus.h:231:71: warning: passing argument 2 of 'estatus_section_iter_next' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
     231 |              ((_section) = estatus_section_iter_next(&__estatus_iter, (_estatus))); \
         |                                                                       ^~~~~~~~~~
   drivers/firmware/efi/estatus.c:817:9: note: in expansion of macro 'estatus_for_each_section'
     817 |         estatus_for_each_section(estatus, gdata) {
         |         ^~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/estatus.h:208:51: note: expected 'struct acpi_hest_generic_status *' but argument is of type 'const struct acpi_hest_generic_status *'
     208 |                           estatus_generic_status *estatus)
         |                                                   ^
   drivers/firmware/efi/estatus.c: At top level:
   drivers/firmware/efi/estatus.c:947:13: warning: 'estatus_print_queued_estatus' defined but not used [-Wunused-function]
     947 | static void estatus_print_queued_estatus(void)
         |             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/firmware/efi/estatus.c:118:12: warning: 'estatus_panic_timeout' defined but not used [-Wunused-variable]
     118 | static int estatus_panic_timeout __read_mostly = 30;
         |            ^~~~~~~~~~~~~~~~~~~~~


vim +/FIX_HOLE +126 drivers/firmware/efi/estatus.c

   122	
   123	static enum fixed_addresses estatus_source_fixmap(struct estatus_source *source)
   124	{
   125		if (WARN_ON_ONCE(!source->fixmap_idx))
 > 126			return FIX_HOLE;
   127	
   128		return source->fixmap_idx;
   129	}
   130	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From guptarud at gmail.com  Sun Dec 21 16:00:30 2025
From: guptarud at gmail.com (Rudraksha Gupta)
Date: Sun, 21 Dec 2025 16:00:30 -0800
Subject: ARMv7 Linux + Rust doesn't boot when compiling with only LLVM=1
In-Reply-To: <0169d4f7-1a31-4ec6-a456-a6dfe2d99886@gmail.com>
References: <1286af8e-f908-45db-af7c-d9c5d592abfd@gmail.com>
 <0705db10-3cbb-4958-a116-112457f9af6c@gmail.com>
 <1910f4b6-db74-4c86-9010-28ab4462c5a7@gmail.com>
 <20251219211147.GA1407372@ax162>
 <0169d4f7-1a31-4ec6-a456-a6dfe2d99886@gmail.com>
Message-ID: <aa453636-dcbc-4ac1-8733-d9d992de82ce@gmail.com>

Hi all,


So it seems that the boot.img size was getting too large for lk2nd (the 
bootloader) to handle and was giving these errors as described. Seems 
like lk2nd can't handle ~21 MB boot.img.


After removing networking from the Linux kernel (as it was the simplest 
way to massively reduce the Linux kernel size) as well as building the 
rust modules into the kernel itself, it seems to boot fine now:

[? ? 0.000000] Booting Linux on physical CPU 0x0
[? ? 0.000000] Linux version 6.18.0 (root at 9e6cbc09906e) (Alpine clang 
version 20.1.8, LLD 20.1.8) #4 SMP PREEMPT Sun Dec 21 23:44:57 UTC 2025
[? ? 0.000000] CPU: ARMv7 Processor [511f04d4] revision 4 (ARMv7), 
cr=10c5787d
[? ? 0.000000] CPU: div instructions available: patching division code
[? ? 0.000000] CPU: PIPT / VIPT nonaliasing data cache, PIPT instruction 
cache
[? ? 0.000000] OF: fdt: Machine model: Samsung Galaxy Express SGH-I437

[ ... ]


[? ? 1.487035] rust_minimal: Rust minimal sample (init)
[? ? 1.487297] rust_minimal: Am I built-in? true
[? ? 1.492632] rust_print: Rust printing macros sample (init)
[? ? 1.496873] rust_print: Emergency message (level 0) without args
[? ? 1.502244] rust_print: Alert message (level 1) without args
[? ? 1.508439] rust_print: Critical message (level 2) without args
[? ? 1.514025] rust_print: Error message (level 3) without args
[? ? 1.519702] rust_print: Warning message (level 4) without args
[? ? 1.525592] rust_print: Notice message (level 5) without args
[? ? 1.531239] rust_print: Info message (level 6) without args
[? ? 1.537037] rust_print: A line that is continued without args
[? ? 1.542440] rust_print: Emergency message (level 0) with args
[? ? 1.548348] rust_print: Alert message (level 1) with args
[? ? 1.554069] rust_print: Critical message (level 2) with args
[? ? 1.559470] rust_print: Error message (level 3) with args
[? ? 1.565177] rust_print: Warning message (level 4) with args
[? ? 1.570458] rust_print: Notice message (level 5) with args
[? ? 1.575829] rust_print: Info message (level 6) with args
[? ? 1.581444] rust_print: A line that is continued with args
[? ? 1.586893] rust_print: 1
[? ? 1.586925] rust_print: "hello, world"
[? ? 1.592188] rust_print: [../samples/rust/rust_print_main.rs:35:5] c = 
"hello, world"
[? ? 1.598511] rust_print: Arc<dyn Display> says 42
[? ? 1.598542] rust_print: Arc<dyn Display> says hello, world
[? ? 1.606445] rust_print: "hello, world"


[ ... ]

Welcome to postmarketOS
Kernel 6.18.0 on an armv7l (/dev/ttyMSM0)
samsung-expressatt login: user
Password:
login: can't set groups: Function not implemented


Sorry for wasting everyone's time. I appreciate the helpful responses :)


Thanks,

Rudraksha



From alexei.starovoitov at gmail.com  Sun Dec 21 16:54:56 2025
From: alexei.starovoitov at gmail.com (Alexei Starovoitov)
Date: Sun, 21 Dec 2025 16:54:56 -0800
Subject: [PATCH bpf-next v3 0/2] bpf: Optimize recursion detection on arm64
In-Reply-To: <20251219184422.2899902-1-puranjay@kernel.org>
References: <20251219184422.2899902-1-puranjay@kernel.org>
Message-ID: <CAADnVQJ91+B=BQ4BC02uqtm+PDerUOfYHDdVGTEbHyi+MCV6bw@mail.gmail.com>

On Fri, Dec 19, 2025 at 8:45?AM Puranjay Mohan <puranjay at kernel.org> wrote:
>
> V2: https://lore.kernel.org/all/20251217233608.2374187-1-puranjay at kernel.org/
> Changes in v2->v3:
> - Added acked by Yonghong
> - Patch 2:
>         - Change alignment of active from 8 to 4
>         - Use le32_to_cpu in place of get_unaligned_le32()
>
> V1: https://lore.kernel.org/all/20251217162830.2597286-1-puranjay at kernel.org/
> Changes in V1->V2:
> - Patch 2:
>         - Put preempt_enable()/disable() around RMW accesses to mitigate
>           race conditions. Because on CONFIG_PREEMPT_RCU and sleepable
>           bpf programs, preemption can cause no bpf prog to execute in
>           case of recursion.
>
> BPF programs detect recursion using a per-CPU 'active' flag in struct
> bpf_prog. The trampoline currently sets/clears this flag with atomic
> operations.
>
> On some arm64 platforms (e.g., Neoverse V2 with LSE), per-CPU atomic
> operations are relatively slow. Unlike x86_64 - where per-CPU updates
> can avoid cross-core atomicity, arm64 LSE atomics are always atomic
> across all cores, which is unnecessary overhead for strictly per-CPU
> state.
>
> This patch removes atomics from the recursion detection path on arm64.
>
> It was discovered in [1] that per-CPU atomics that don't return a value
> were extremely slow on some arm64 platforms, Catalin added a fix in
> commit 535fdfc5a228 ("arm64: Use load LSE atomics for the non-return
> per-CPU atomic operations") to solve this issue, but it seems to have
> caused a regression on the fentry benchmark.
>
> Using the fentry benchmark from the bpf selftests shows the following:
>
>   ./tools/testing/selftests/bpf/bench trig-fentry
>
>  +---------------------------------------------+------------------------+
>  |               Configuration                 | Total Operations (M/s) |
>  +---------------------------------------------+------------------------+
>  | bpf-next/master with Catalin?s fix reverted |         51.770         |
>  |---------------------------------------------|------------------------|
>  | bpf-next/master                             |         43.271         |
>  | bpf-next/master with this change            |         43.271         |
>  +---------------------------------------------+------------------------+
>
> All benchmarks were run on a KVM based vm with Neoverse-V2 and 8 cpus.
>
> This patch yields a 25% improvement in this benchmark compared to
> bpf-next. Notably, reverting Catalin's fix also results in a performance
> gain for this benchmark, which is interesting but expected.
>
> For completeness, this benchmark was also run with the change enabled on
> x86-64, which resulted in a 30% regression in the fentry benchmark. So,
> it is only enabled on arm64.
>
> P.S. - Here is more data with other program types:
>
>  +-----------------+-----------+-----------+----------+
>  |     Metric      |  Before   |   After   | % Diff   |
>  +-----------------+-----------+-----------+----------+
>  | fentry          |   43.149  |   53.948  | +25.03%  |
>  | fentry.s        |   41.831  |   50.937  | +21.76%  |
>  | rawtp           |   50.834  |   58.731  | +15.53%  |
>  | fexit           |   31.118  |   34.360  | +10.42%  |
>  | tp              |   39.536  |   41.632  |  +5.30%  |
>  | syscall-count   |    8.053  |    8.305  |  +3.13%  |
>  | fmodret         |   33.940  |   34.769  |  +2.44%  |
>  | kprobe          |    9.970  |    9.998  |  +0.28%  |
>  | usermode-count  |  224.886  |  224.839  |  -0.02%  |
>  | kernel-count    |  154.229  |  153.043  |  -0.77%  |
>  +-----------------+-----------+-----------+----------+
>
> [1] https://lore.kernel.org/all/e7d539ed-ced0-4b96-8ecd-048a5b803b85 at paulmck-laptop/
>
> Puranjay Mohan (2):
>   bpf: move recursion detection logic to helpers
>   bpf: arm64: Optimize recursion detection by not using atomics
>
>  include/linux/bpf.h      | 38 +++++++++++++++++++++++++++++++++++++-
>  kernel/bpf/core.c        |  3 ++-
>  kernel/bpf/trampoline.c  |  8 ++++----
>  kernel/trace/bpf_trace.c |  4 ++--
>  4 files changed, 45 insertions(+), 8 deletions(-)

It was applied to bpf-next.
pw-bot is asleep.


From peng.fan at oss.nxp.com  Sun Dec 21 17:42:13 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Mon, 22 Dec 2025 09:42:13 +0800
Subject: [PATCH v2 0/3] arm64: dts: Initial support for i.MX952
Message-ID: <20251222-imx952-v1-v2-0-8793ec8bad6e@nxp.com>

Initial device tree for i.MX952 and i.MX952-EVK.
i.MX952 is designed for AI-powered sensor fusion and vision sensing
applications, it features 4 Corte-A55, 1 Cortex-M33, 1 Cortex-M7 and
NXP eIQ NPU and advanced graphics, video and advanced security with
edgelock.

Product info could be found at[1].

Note:
There is checkpatch error for the pin headers:
ERROR: Macros with complex values should be enclosed in parentheses
checkpatch.pl maintainer said "Just ignore the message instead", see[2]

[1]https://www.nxp.com/products/i.MX-952
[2]https://lore.kernel.org/all/fce65a7761fb0e880beb469e2521598f at perches.com/

Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
Changes in v2:
- Patch 1: Add A-b from Krzysztof
- Patch 2: Per Daniel, update commit msg to include product info. 
- Link to v1: https://lore.kernel.org/r/20251217-imx952-v1-v1-0-a55a7fe2df0b at nxp.com

---
Peng Fan (3):
      dt-bindings: arm: fsl: add i.MX952 EVK board
      arm64: dts: freescale: Add initial device tree for i.MX952
      arm64: dts: freescale: Add i.MX952 EVK basic device tree

 Documentation/devicetree/bindings/arm/fsl.yaml |    6 +
 arch/arm64/boot/dts/freescale/Makefile         |    2 +
 arch/arm64/boot/dts/freescale/imx952-clock.h   |  215 ++++
 arch/arm64/boot/dts/freescale/imx952-evk.dts   |  217 ++++
 arch/arm64/boot/dts/freescale/imx952-pinfunc.h |  867 ++++++++++++++++
 arch/arm64/boot/dts/freescale/imx952-power.h   |   44 +
 arch/arm64/boot/dts/freescale/imx952.dtsi      | 1248 ++++++++++++++++++++++++
 7 files changed, 2599 insertions(+)
---
base-commit: 563c8dd425b59e44470e28519107b1efc99f4c7b
change-id: 20251216-imx952-v1-e5c2debf20c4

Best regards,
-- 
Peng Fan <peng.fan at nxp.com>



From peng.fan at oss.nxp.com  Sun Dec 21 17:42:14 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Mon, 22 Dec 2025 09:42:14 +0800
Subject: [PATCH v2 1/3] dt-bindings: arm: fsl: add i.MX952 EVK board
In-Reply-To: <20251222-imx952-v1-v2-0-8793ec8bad6e@nxp.com>
References: <20251222-imx952-v1-v2-0-8793ec8bad6e@nxp.com>
Message-ID: <20251222-imx952-v1-v2-1-8793ec8bad6e@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

Add DT compatible string for NXP i.MX952 EVK board.

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 Documentation/devicetree/bindings/arm/fsl.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
index 68a2d5fecc43b06711e2efce61ac1fc2794b79bc..b3a6f72341fcddd05ec21912e975878c9d0fed73 100644
--- a/Documentation/devicetree/bindings/arm/fsl.yaml
+++ b/Documentation/devicetree/bindings/arm/fsl.yaml
@@ -1436,6 +1436,12 @@ properties:
               - toradex,verdin-imx95-19x19-evk  # i.MX95 Verdin Evaluation Kit (EVK)
           - const: fsl,imx95
 
+      - description: i.MX952 based Boards
+        items:
+          - enum:
+              - fsl,imx952-evk            # i.MX952 EVK Board
+          - const: fsl,imx952
+
       - description: PHYTEC i.MX 95 FPSC based Boards
         items:
           - enum:

-- 
2.37.1



From peng.fan at oss.nxp.com  Sun Dec 21 17:42:16 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Mon, 22 Dec 2025 09:42:16 +0800
Subject: [PATCH v2 3/3] arm64: dts: freescale: Add i.MX952 EVK basic device
 tree
In-Reply-To: <20251222-imx952-v1-v2-0-8793ec8bad6e@nxp.com>
References: <20251222-imx952-v1-v2-0-8793ec8bad6e@nxp.com>
Message-ID: <20251222-imx952-v1-v2-3-8793ec8bad6e@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

Add i.MX952 EVK basic device tree, with UART1, SDHC[1,2] supported.

Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 arch/arm64/boot/dts/freescale/Makefile       |   2 +
 arch/arm64/boot/dts/freescale/imx952-evk.dts | 217 +++++++++++++++++++++++++++
 2 files changed, 219 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index f30d3fd724d0ce6b38f7bef10e3970ac34f70f4a..05d8ccd89186478ad4310f56a02783b51034f839 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -414,6 +414,8 @@ dtb-$(CONFIG_ARCH_MXC) += imx95-libra-rdk-fpsc.dtb
 
 dtb-$(CONFIG_ARCH_MXC) += imx95-19x19-verdin-evk.dtb
 
+dtb-$(CONFIG_ARCH_MXC) += imx952-evk.dtb
+
 imx8mm-kontron-dl-dtbs			:= imx8mm-kontron-bl.dtb imx8mm-kontron-dl.dtbo
 imx8mm-kontron-bl-lte-dtbs		:= imx8mm-kontron-bl.dtb imx8mm-kontron-bl-lte.dtbo
 
diff --git a/arch/arm64/boot/dts/freescale/imx952-evk.dts b/arch/arm64/boot/dts/freescale/imx952-evk.dts
new file mode 100644
index 0000000000000000000000000000000000000000..2c753fcbae3c5d545f5d835bd70492667061d626
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx952-evk.dts
@@ -0,0 +1,217 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2025 NXP
+ */
+
+/dts-v1/;
+
+#include "imx952.dtsi"
+
+/ {
+	model = "NXP i.MX952 EVK board";
+	compatible = "fsl,imx952-evk", "fsl,imx952";
+
+	aliases {
+		gpio0 = &gpio1;
+		gpio1 = &gpio2;
+		gpio2 = &gpio3;
+		gpio3 = &gpio4;
+		gpio4 = &gpio5;
+		mmc0 = &usdhc1;
+		mmc1 = &usdhc2;
+		serial0 = &lpuart1;
+	};
+
+	chosen {
+		stdout-path = &lpuart1;
+	};
+
+	memory at 80000000 {
+		device_type = "memory";
+		reg = <0x0 0x80000000 0 0x80000000>;
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		linux_cma: linux,cma {
+			compatible = "shared-dma-pool";
+			alloc-ranges = <0 0x80000000 0 0x7f000000>;
+			size = <0 0x3c000000>;
+			linux,cma-default;
+			reusable;
+		};
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "+V3.3_SW";
+	};
+
+	reg_1p8v: regulator-1p8v {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <1800000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-name = "+V1.8_SW";
+	};
+
+	reg_vref_1v8: regulator-adc-vref {
+		compatible = "regulator-fixed";
+		regulator-name = "vref_1v8";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	reg_usdhc2_vmmc: regulator-usdhc2 {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
+		regulator-name = "VDD_SD2_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio3 7 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		off-on-delay-us = <12000>;
+	};
+};
+
+&lpuart1 {
+	/* console */
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart1>;
+	status = "okay";
+};
+
+&usdhc1 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
+	pinctrl-0 = <&pinctrl_usdhc1>;
+	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
+	pinctrl-3 = <&pinctrl_usdhc1>;
+	bus-width = <8>;
+	non-removable;
+	no-sdio;
+	no-sd;
+	status = "okay";
+};
+
+&usdhc2 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
+	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-3 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	cd-gpios = <&gpio3 0 GPIO_ACTIVE_LOW>;
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	bus-width = <4>;
+	status = "okay";
+};
+
+&scmi_iomuxc {
+	pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
+		fsl,pins = <
+			IMX952_PAD_SD2_RESET_B__WAKEUPMIX_TOP_GPIO3_IO_7	0x31e
+		>;
+	};
+
+	pinctrl_uart1: uart1grp {
+		fsl,pins = <
+			IMX952_PAD_UART1_RXD__AONMIX_TOP_LPUART1_RX		0x31e
+			IMX952_PAD_UART1_TXD__AONMIX_TOP_LPUART1_TX		0x31e
+		>;
+	};
+
+	pinctrl_usdhc1: usdhc1grp {
+		fsl,pins = <
+			IMX952_PAD_SD1_CLK__WAKEUPMIX_TOP_USDHC1_CLK		0x158e
+			IMX952_PAD_SD1_CMD__WAKEUPMIX_TOP_USDHC1_CMD		0x138e
+			IMX952_PAD_SD1_DATA0__WAKEUPMIX_TOP_USDHC1_DATA0	0x138e
+			IMX952_PAD_SD1_DATA1__WAKEUPMIX_TOP_USDHC1_DATA1	0x138e
+			IMX952_PAD_SD1_DATA2__WAKEUPMIX_TOP_USDHC1_DATA2	0x138e
+			IMX952_PAD_SD1_DATA3__WAKEUPMIX_TOP_USDHC1_DATA3	0x138e
+			IMX952_PAD_SD1_DATA4__WAKEUPMIX_TOP_USDHC1_DATA4	0x138e
+			IMX952_PAD_SD1_DATA5__WAKEUPMIX_TOP_USDHC1_DATA5	0x138e
+			IMX952_PAD_SD1_DATA6__WAKEUPMIX_TOP_USDHC1_DATA6	0x138e
+			IMX952_PAD_SD1_DATA7__WAKEUPMIX_TOP_USDHC1_DATA7	0x138e
+			IMX952_PAD_SD1_STROBE__WAKEUPMIX_TOP_USDHC1_STROBE	0x158e
+		>;
+	};
+
+	pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp {
+		fsl,pins = <
+			IMX952_PAD_SD1_CLK__WAKEUPMIX_TOP_USDHC1_CLK		0x158e
+			IMX952_PAD_SD1_CMD__WAKEUPMIX_TOP_USDHC1_CMD		0x138e
+			IMX952_PAD_SD1_DATA0__WAKEUPMIX_TOP_USDHC1_DATA0	0x138e
+			IMX952_PAD_SD1_DATA1__WAKEUPMIX_TOP_USDHC1_DATA1	0x138e
+			IMX952_PAD_SD1_DATA2__WAKEUPMIX_TOP_USDHC1_DATA2	0x138e
+			IMX952_PAD_SD1_DATA3__WAKEUPMIX_TOP_USDHC1_DATA3	0x138e
+			IMX952_PAD_SD1_DATA4__WAKEUPMIX_TOP_USDHC1_DATA4	0x138e
+			IMX952_PAD_SD1_DATA5__WAKEUPMIX_TOP_USDHC1_DATA5	0x138e
+			IMX952_PAD_SD1_DATA6__WAKEUPMIX_TOP_USDHC1_DATA6	0x138e
+			IMX952_PAD_SD1_DATA7__WAKEUPMIX_TOP_USDHC1_DATA7	0x138e
+			IMX952_PAD_SD1_STROBE__WAKEUPMIX_TOP_USDHC1_STROBE	0x158e
+		>;
+	};
+
+	pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp {
+		fsl,pins = <
+			IMX952_PAD_SD1_CLK__WAKEUPMIX_TOP_USDHC1_CLK		0x15fe
+			IMX952_PAD_SD1_CMD__WAKEUPMIX_TOP_USDHC1_CMD		0x13fe
+			IMX952_PAD_SD1_DATA0__WAKEUPMIX_TOP_USDHC1_DATA0	0x13fe
+			IMX952_PAD_SD1_DATA1__WAKEUPMIX_TOP_USDHC1_DATA1	0x13fe
+			IMX952_PAD_SD1_DATA2__WAKEUPMIX_TOP_USDHC1_DATA2	0x13fe
+			IMX952_PAD_SD1_DATA3__WAKEUPMIX_TOP_USDHC1_DATA3	0x13fe
+			IMX952_PAD_SD1_DATA4__WAKEUPMIX_TOP_USDHC1_DATA4	0x13fe
+			IMX952_PAD_SD1_DATA5__WAKEUPMIX_TOP_USDHC1_DATA5	0x13fe
+			IMX952_PAD_SD1_DATA6__WAKEUPMIX_TOP_USDHC1_DATA6	0x13fe
+			IMX952_PAD_SD1_DATA7__WAKEUPMIX_TOP_USDHC1_DATA7	0x13fe
+			IMX952_PAD_SD1_STROBE__WAKEUPMIX_TOP_USDHC1_STROBE	0x15fe
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			IMX952_PAD_SD2_CLK__WAKEUPMIX_TOP_USDHC2_CLK		0x158e
+			IMX952_PAD_SD2_CMD__WAKEUPMIX_TOP_USDHC2_CMD		0x138e
+			IMX952_PAD_SD2_DATA0__WAKEUPMIX_TOP_USDHC2_DATA0	0x138e
+			IMX952_PAD_SD2_DATA1__WAKEUPMIX_TOP_USDHC2_DATA1	0x138e
+			IMX952_PAD_SD2_DATA2__WAKEUPMIX_TOP_USDHC2_DATA2	0x138e
+			IMX952_PAD_SD2_DATA3__WAKEUPMIX_TOP_USDHC2_DATA3	0x138e
+			IMX952_PAD_SD2_VSELECT__WAKEUPMIX_TOP_USDHC2_VSELECT	0x51e
+		>;
+	};
+
+	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+		fsl,pins = <
+			IMX952_PAD_SD2_CLK__WAKEUPMIX_TOP_USDHC2_CLK		0x158e
+			IMX952_PAD_SD2_CMD__WAKEUPMIX_TOP_USDHC2_CMD		0x138e
+			IMX952_PAD_SD2_DATA0__WAKEUPMIX_TOP_USDHC2_DATA0	0x138e
+			IMX952_PAD_SD2_DATA1__WAKEUPMIX_TOP_USDHC2_DATA1	0x138e
+			IMX952_PAD_SD2_DATA2__WAKEUPMIX_TOP_USDHC2_DATA2	0x138e
+			IMX952_PAD_SD2_DATA3__WAKEUPMIX_TOP_USDHC2_DATA3	0x138e
+			IMX952_PAD_SD2_VSELECT__WAKEUPMIX_TOP_USDHC2_VSELECT	0x51e
+		>;
+	};
+
+	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+		fsl,pins = <
+			IMX952_PAD_SD2_CLK__WAKEUPMIX_TOP_USDHC2_CLK		0x158e
+			IMX952_PAD_SD2_CMD__WAKEUPMIX_TOP_USDHC2_CMD		0x138e
+			IMX952_PAD_SD2_DATA0__WAKEUPMIX_TOP_USDHC2_DATA0	0x138e
+			IMX952_PAD_SD2_DATA1__WAKEUPMIX_TOP_USDHC2_DATA1	0x138e
+			IMX952_PAD_SD2_DATA2__WAKEUPMIX_TOP_USDHC2_DATA2	0x138e
+			IMX952_PAD_SD2_DATA3__WAKEUPMIX_TOP_USDHC2_DATA3	0x138e
+			IMX952_PAD_SD2_VSELECT__WAKEUPMIX_TOP_USDHC2_VSELECT	0x51e
+		>;
+	};
+
+	pinctrl_usdhc2_gpio: usdhc2gpiogrp {
+		fsl,pins = <
+			IMX952_PAD_SD2_CD_B__WAKEUPMIX_TOP_GPIO3_IO_0		0x31e
+		>;
+	};
+};

-- 
2.37.1



From lkp at intel.com  Sun Dec 21 18:03:00 2025
From: lkp at intel.com (kernel test robot)
Date: Mon, 22 Dec 2025 10:03:00 +0800
Subject: [PATCH v23 3/7] firmware: imx: add driver for NXP EdgeLock
 Enclave
In-Reply-To: <20251219-imx-se-if-v23-3-5c6773d00318@nxp.com>
References: <20251219-imx-se-if-v23-3-5c6773d00318@nxp.com>
Message-ID: <202512220932.Gu4LnMge-lkp@intel.com>

Hi Pankaj,

kernel test robot noticed the following build errors:

[auto build test ERROR on 4a26e7032d7d57c998598c08a034872d6f0d3945]

url:    https://github.com/intel-lab-lkp/linux/commits/Pankaj-Gupta/Documentation-firmware-add-imx-se-to-other_interfaces/20251219-132830
base:   4a26e7032d7d57c998598c08a034872d6f0d3945
patch link:    https://lore.kernel.org/r/20251219-imx-se-if-v23-3-5c6773d00318%40nxp.com
patch subject: [PATCH v23 3/7] firmware: imx: add driver for NXP EdgeLock Enclave
config: xtensa-randconfig-001-20251221 (https://download.01.org/0day-ci/archive/20251222/202512220932.Gu4LnMge-lkp at intel.com/config)
compiler: xtensa-linux-gcc (GCC) 8.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251222/202512220932.Gu4LnMge-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512220932.Gu4LnMge-lkp at intel.com/

All errors (new ones prefixed by >>):

   In file included from drivers/firmware/imx/ele_base_msg.h:14,
                    from drivers/firmware/imx/ele_common.c:6:
   drivers/firmware/imx/ele_common.c: In function 'se_val_rsp_hdr_n_status':
>> drivers/firmware/imx/se_ctrl.h:16:25: error: implicit declaration of function 'FIELD_GET' [-Werror=implicit-function-declaration]
    #define RES_STATUS(x)   FIELD_GET(0x000000ff, x)
                            ^~~~~~~~~
   drivers/firmware/imx/ele_common.c:241:11: note: in expansion of macro 'RES_STATUS'
     status = RES_STATUS(msg->data[0]);
              ^~~~~~~~~~
   cc1: some warnings being treated as errors
--
   drivers/firmware/imx/se_ctrl.c: In function 'get_se_soc_info':
>> drivers/firmware/imx/se_ctrl.c:168:6: error: implicit declaration of function 'FIELD_GET' [-Werror=implicit-function-declaration]
     if (FIELD_GET(DEV_GETINFO_MIN_VER_MASK, var_se_info.soc_rev))
         ^~~~~~~~~
   At top level:
   drivers/firmware/imx/se_ctrl.c:374:12: warning: 'se_resume' defined but not used [-Wunused-function]
    static int se_resume(struct device *dev)
               ^~~~~~~~~
   drivers/firmware/imx/se_ctrl.c:357:12: warning: 'se_suspend' defined but not used [-Wunused-function]
    static int se_suspend(struct device *dev)
               ^~~~~~~~~~
   cc1: some warnings being treated as errors


vim +/FIELD_GET +16 drivers/firmware/imx/se_ctrl.h

    15	
  > 16	#define RES_STATUS(x)			FIELD_GET(0x000000ff, x)
    17	#define MAX_NVM_MSG_LEN			(256)
    18	#define MESSAGING_VERSION_6		0x6
    19	#define MESSAGING_VERSION_7		0x7
    20	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From xu.yang_2 at nxp.com  Sun Dec 21 17:59:43 2025
From: xu.yang_2 at nxp.com (Xu Yang)
Date: Mon, 22 Dec 2025 09:59:43 +0800
Subject: [PATCH] phy: fsl-imx8mq-usb: add debugfs to access control
 register
In-Reply-To: <CAEnQRZCZJnkXCM2ACf3dXQ-ZynRB1q2zcarWLAZO_1TsL-1GcA@mail.gmail.com>
References: <20251219075447.3672833-1-xu.yang_2@nxp.com>
 <CAEnQRZCZJnkXCM2ACf3dXQ-ZynRB1q2zcarWLAZO_1TsL-1GcA@mail.gmail.com>
Message-ID: <6aj4j6sh2rystvtup7wmte557nhknwqs6n5qsa5lbd44sn3km7@ktkxzugnv777>

On Fri, Dec 19, 2025 at 11:34:56AM +0200, Daniel Baluta wrote:
> On Fri, Dec 19, 2025 at 9:56?AM Xu Yang <xu.yang_2 at nxp.com> wrote:
> >
> > The CR port is a simple 16-bit data/address parallel port that is
> > provided for on-chip access to the control registers inside the
> > USB 3.0 femtoPHY. While access to these registers is not required
> > for normal PHY operation, this interface enables you to access
> > some of the PHY?s diagnostic features during normal operation or
> > to override some basic PHY control signals.
> >
> > 3 debugfs files are created to read and write control registers,
> > all use hexadecimal format:
> > ctrl_reg_base: the register offset to write, or the start offset
> >                to read.
> > ctrl_reg_count: how many continuous registers to be read.
> > ctrl_reg_value: read to show the continuous registers value from
> >                 the offset in ctrl_reg_base, to ctrl_reg_base
> >                 + ctrl_reg_count - 1, one line for one register.
> >                 when write, override the register at ctrl_reg_base,
> >                 one time can only change one 16bits register.
> >
> > Signed-off-by: Li Jun <jun.li at nxp.com>
> > Signed-off-by: Xu Yang <xu.yang_2 at nxp.com>
> > ---
> >  drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 221 ++++++++++++++++++++-
> >  1 file changed, 220 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> > index ad8a55012e42..cb2392008ad2 100644
> > --- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> > +++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> > @@ -1,8 +1,9 @@
> >  // SPDX-License-Identifier: GPL-2.0+
> > -/* Copyright (c) 2017 NXP. */
> > +/* Copyright (c) 2017-2025 NXP. */
> 
> While you are at it can you remove the (c). New policy
> from NXP is to use directly:
> 
> Copyright 2017-2025 NXP.


Sure. Will do.

Thanks,
Xu Yang


From xu.yang_2 at nxp.com  Sun Dec 21 18:48:32 2025
From: xu.yang_2 at nxp.com (Xu Yang)
Date: Mon, 22 Dec 2025 10:48:32 +0800
Subject: [PATCH] phy: fsl-imx8mq-usb: enable RxTermination_override_sel
In-Reply-To: <aUV0vn2VPWKAh5f7@lizhi-Precision-Tower-5810>
References: <20251219083004.3883898-1-xu.yang_2@nxp.com>
 <aUV0vn2VPWKAh5f7@lizhi-Precision-Tower-5810>
Message-ID: <iik2dnzkw7fxqm3qlzt3vegyoabgefveopdmwzxwejof2ytrho@dbnq2xj5suaw>

On Fri, Dec 19, 2025 at 10:52:30AM -0500, Frank Li wrote:
> On Fri, Dec 19, 2025 at 04:30:04PM +0800, Xu Yang wrote:
> > This is to resolve the problem of wakeup system by USB3 device
> > insertion if HSIOMIX on, in that case, the USB3 device detects
> 
> Do you means USB3 device wrong regconized as USB2?

No. This patch is to support wakeup by connecting an usb3 device.

If the HSIOMIX power is OFF during the system suspend, the USB3 device
will downgrade to High-speed because the link training does not
happen at all. Then DPDM wakeup can be triggered. 
Otherwise, the USB3 device will still work at SuperSpeed, but the connect
wakeup (different one from DPDM) can't be triggered because the 24MHz OSC
clock is required to be on. Therefore the system can't be waken up.

> 
> > RX term on so doesn't downgrade to USB2, so DP/DM wakeup can't
> > happen, with this override bit we can force the RX term off when
> > enters system suspend, and disable the override after system resume.
> 
> Enable RxTermination_override_sel to resolve the problem, which wrong
> regongized as USB 2.0 device if USB3 device plug-in when HSIOMIX ON.
> 
> No clear why force RX term Off can resolve problem. Please rephrase it.

Force RX term off will force the USB3 device works at high-speed from the
beginning. Then it will switch to super-speed when the host reset it after
system resume. OK, I will rephrase it.

Thanks,
Xu Yang

> 
> Frank
> 
> >
> > Signed-off-by: Li Jun <jun.li at nxp.com>
> > Signed-off-by: Xu Yang <xu.yang_2 at nxp.com>
> > ---
> >  drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 15 ++++++++++++++-
> >  1 file changed, 14 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> > index 02d9af409b08..0831ed465775 100644
> > --- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> > +++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> > @@ -52,6 +52,7 @@
> >  #define PHY_CTRL5_PCS_TX_SWING_FULL_MASK	GENMASK(6, 0)
> >
> >  #define PHY_CTRL6			0x18
> > +#define PHY_CTRL6_RXTERM_OVERRIDE_SEL	BIT(29)
> >  #define PHY_CTRL6_ALT_CLK_EN		BIT(1)
> >  #define PHY_CTRL6_ALT_CLK_SEL		BIT(0)
> >
> > @@ -847,6 +848,7 @@ static int imx8mp_usb_phy_init(struct phy *phy)
> >  static int imx8mq_phy_power_on(struct phy *phy)
> >  {
> >  	struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
> > +	u32 value;
> >  	int ret;
> >
> >  	ret = regulator_enable(imx_phy->vbus);
> > @@ -863,12 +865,23 @@ static int imx8mq_phy_power_on(struct phy *phy)
> >  		return ret;
> >  	}
> >
> > -	return ret;
> > +	/* Disable rx term override */
> > +	value = readl(imx_phy->base + PHY_CTRL6);
> > +	value &= ~PHY_CTRL6_RXTERM_OVERRIDE_SEL;
> > +	writel(value, imx_phy->base + PHY_CTRL6);
> > +
> > +	return 0;
> >  }
> >
> >  static int imx8mq_phy_power_off(struct phy *phy)
> >  {
> >  	struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
> > +	u32 value;
> > +
> > +	/* Override rx term to be 0 */
> > +	value = readl(imx_phy->base + PHY_CTRL6);
> > +	value |= PHY_CTRL6_RXTERM_OVERRIDE_SEL;
> > +	writel(value, imx_phy->base + PHY_CTRL6);
> >
> >  	clk_disable_unprepare(imx_phy->alt_clk);
> >  	clk_disable_unprepare(imx_phy->clk);
> > --
> > 2.34.1
> >


From jie.gan at oss.qualcomm.com  Sun Dec 21 19:06:49 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Mon, 22 Dec 2025 11:06:49 +0800
Subject: [PATCH v4 2/2] arm64: dts: qcom: monaco: Add CTCU and ETR nodes
In-Reply-To: <20251103-enable-ctcu-for-monaco-v4-2-92ff83201584@oss.qualcomm.com>
References: <20251103-enable-ctcu-for-monaco-v4-0-92ff83201584@oss.qualcomm.com>
 <20251103-enable-ctcu-for-monaco-v4-2-92ff83201584@oss.qualcomm.com>
Message-ID: <0d3064be-c333-4ec4-9607-5122baa0f256@oss.qualcomm.com>



On 11/3/2025 3:06 PM, Jie Gan wrote:
> Add CTCU and ETR nodes in DT to enable expected functionalities.
> 
> Acked-by: Konrad Dybcio <konrad.dybcio at oss.qualcomm.com>
> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
> ---
>   arch/arm64/boot/dts/qcom/monaco.dtsi | 153 +++++++++++++++++++++++++++++++++++
>   1 file changed, 153 insertions(+)
> 

Gentle reminder.

The dt-binding patch has applied to Coresight tree.

> diff --git a/arch/arm64/boot/dts/qcom/monaco.dtsi b/arch/arm64/boot/dts/qcom/monaco.dtsi
> index 816fa2af8a9a..1966dfad2dcc 100644
> --- a/arch/arm64/boot/dts/qcom/monaco.dtsi
> +++ b/arch/arm64/boot/dts/qcom/monaco.dtsi
> @@ -2483,6 +2483,35 @@ lpass_ag_noc: interconnect at 3c40000 {
>   			qcom,bcm-voters = <&apps_bcm_voter>;
>   		};
>   
> +		ctcu at 4001000 {
> +			compatible = "qcom,qcs8300-ctcu", "qcom,sa8775p-ctcu";
> +			reg = <0x0 0x04001000 0x0 0x1000>;
> +
> +			clocks = <&aoss_qmp>;
> +			clock-names = "apb";
> +
> +			in-ports {
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +
> +				port at 0 {
> +					reg = <0>;
> +
> +					ctcu_in0: endpoint {
> +						remote-endpoint = <&etr0_out>;
> +					};
> +				};
> +
> +				port at 1 {
> +					reg = <1>;
> +
> +					ctcu_in1: endpoint {
> +						remote-endpoint = <&etr1_out>;
> +					};
> +				};
> +			};
> +		};
> +
>   		stm at 4002000 {
>   			compatible = "arm,coresight-stm", "arm,primecell";
>   			reg = <0x0 0x04002000 0x0 0x1000>,
> @@ -2677,6 +2706,122 @@ qdss_funnel_out: endpoint {
>   			};
>   		};
>   
> +		replicator at 4046000 {
> +			compatible = "arm,coresight-dynamic-replicator", "arm,primecell";
> +			reg = <0x0 0x04046000 0x0 0x1000>;
> +
> +			clocks = <&aoss_qmp>;
> +			clock-names = "apb_pclk";
> +
> +			in-ports {
> +				port {
> +					qdss_rep_in: endpoint {
> +						remote-endpoint = <&swao_rep_out0>;
> +					};
> +				};
> +			};
> +
> +			out-ports {
> +				port {
> +					qdss_rep_out0: endpoint {
> +						remote-endpoint = <&etr_rep_in>;
> +					};
> +				};
> +			};
> +		};
> +
> +		tmc at 4048000 {
> +			compatible = "arm,coresight-tmc", "arm,primecell";
> +			reg = <0x0 0x04048000 0x0 0x1000>;
> +
> +			clocks = <&aoss_qmp>;
> +			clock-names = "apb_pclk";
> +			iommus = <&apps_smmu 0x04c0 0x00>;
> +
> +			arm,scatter-gather;
> +
> +			in-ports {
> +				port {
> +					etr0_in: endpoint {
> +						remote-endpoint = <&etr_rep_out0>;
> +					};
> +				};
> +			};
> +
> +			out-ports {
> +				port {
> +					etr0_out: endpoint {
> +						remote-endpoint = <&ctcu_in0>;
> +					};
> +				};
> +			};
> +		};
> +
> +		replicator at 404e000 {
> +			compatible = "arm,coresight-dynamic-replicator", "arm,primecell";
> +			reg = <0x0 0x0404e000 0x0 0x1000>;
> +
> +			clocks = <&aoss_qmp>;
> +			clock-names = "apb_pclk";
> +
> +			in-ports {
> +				port {
> +					etr_rep_in: endpoint {
> +						remote-endpoint = <&qdss_rep_out0>;
> +					};
> +				};
> +			};
> +
> +			out-ports {
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +
> +				port at 0 {
> +					reg = <0>;
> +
> +					etr_rep_out0: endpoint {
> +						remote-endpoint = <&etr0_in>;
> +					};
> +				};
> +
> +				port at 1 {
> +					reg = <1>;
> +
> +					etr_rep_out1: endpoint {
> +						remote-endpoint = <&etr1_in>;
> +					};
> +				};
> +			};
> +		};
> +
> +		tmc at 404f000 {
> +			compatible = "arm,coresight-tmc", "arm,primecell";
> +			reg = <0x0 0x0404f000 0x0 0x1000>;
> +
> +			clocks = <&aoss_qmp>;
> +			clock-names = "apb_pclk";
> +			iommus = <&apps_smmu 0x04a0 0x40>;
> +
> +			arm,scatter-gather;
> +			arm,buffer-size = <0x400000>;
> +
> +			in-ports {
> +				port {
> +					etr1_in: endpoint {
> +						remote-endpoint = <&etr_rep_out1>;
> +					};
> +				};
> +			};
> +
> +			out-ports {
> +				port {
> +					etr1_out: endpoint {
> +						remote-endpoint = <&ctcu_in1>;
> +					};
> +				};
> +			};
> +		};
> +
>   		tpdm at 4841000 {
>   			compatible = "qcom,coresight-tpdm", "arm,primecell";
>   			reg = <0x0 0x04841000 0x0 0x1000>;
> @@ -3106,6 +3251,14 @@ out-ports {
>   				#address-cells = <1>;
>   				#size-cells = <0>;
>   
> +				port at 0 {
> +					reg = <0>;
> +
> +					swao_rep_out0: endpoint {
> +						remote-endpoint = <&qdss_rep_in>;
> +					};
> +				};
> +
>   				port at 1 {
>   					reg = <1>;
>   
> 



From guoniu.zhou at nxp.com  Sun Dec 21 19:29:10 2025
From: guoniu.zhou at nxp.com (G.N. Zhou)
Date: Mon, 22 Dec 2025 03:29:10 +0000
Subject: [PATCH v3 2/2] media: nxp: Add i.MX9 CSI pixel formatter v4l2
 driver
In-Reply-To: <aUV4enryGRDdIkIb@lizhi-Precision-Tower-5810>
References: <20251219-csi_formatter-v3-0-8680d6d87091@nxp.com>
 <20251219-csi_formatter-v3-2-8680d6d87091@nxp.com>
 <aUV4enryGRDdIkIb@lizhi-Precision-Tower-5810>
Message-ID: <AS8PR04MB9080817D9A557B9D96F55066FAB4A@AS8PR04MB9080.eurprd04.prod.outlook.com>

Hi Frank,

Thanks for your review.

> -----Original Message-----
> From: Frank Li <frank.li at nxp.com>
> Sent: Saturday, December 20, 2025 12:08 AM
> To: G.N. Zhou (OSS) <guoniu.zhou at oss.nxp.com>
> Cc: Mauro Carvalho Chehab <mchehab at kernel.org>; Rob Herring
> <robh at kernel.org>; Krzysztof Kozlowski <krzk+dt at kernel.org>; Conor Dooley
> <conor+dt at kernel.org>; Shawn Guo <shawnguo at kernel.org>; Sascha Hauer
> <s.hauer at pengutronix.de>; Pengutronix Kernel Team
> <kernel at pengutronix.de>; Fabio Estevam <festevam at gmail.com>; Laurent
> Pinchart <laurent.pinchart at ideasonboard.com>; imx at lists.linux.dev; linux-
> media at vger.kernel.org; devicetree at vger.kernel.org; linux-arm-
> kernel at lists.infradead.org; linux-kernel at vger.kernel.org; G.N. Zhou
> <guoniu.zhou at nxp.com>
> Subject: Re: [PATCH v3 2/2] media: nxp: Add i.MX9 CSI pixel formatter v4l2
> driver
> 
> On Fri, Dec 19, 2025 at 09:50:58AM +0800, Guoniu Zhou wrote:
> > From: Guoniu Zhou <guoniu.zhou at nxp.com>
> >
> > The CSI pixel formatter is a module found on i.MX95 used to reformat
> > packet info, pixel and non-pixel data from CSI-2 host controller to
> > match Pixel Link(PL) definition.
> >
> > Add data formatting support.
> >
> > Signed-off-by: Guoniu Zhou <guoniu.zhou at nxp.com>
> > ---
> >  MAINTAINERS                                     |   8 +
> >  drivers/media/platform/nxp/Kconfig              |  14 +
> >  drivers/media/platform/nxp/Makefile             |   1 +
> >  drivers/media/platform/nxp/imx9-csi-formatter.c | 880
> > ++++++++++++++++++++++++
> >  4 files changed, 903 insertions(+)
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS index
> >
> 4205ca007e076f869613032b51e8cc5bff06b98e..3878957b81156e5cb41da26
> 99b2f
> > 588e49521724 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -18626,6 +18626,14 @@ S:	Maintained
> >  F:	Documentation/devicetree/bindings/media/nxp,imx8-jpeg.yaml
> >  F:	drivers/media/platform/nxp/imx-jpeg
> >
> > +NXP i.MX 9 CSI PIXEL FORMATTER V4L2 DRIVER
> > +M:	Guoniu Zhou <guoniu.zhou at nxp.com>
> > +L:	imx at lists.linux.dev
> > +L:	linux-media at vger.kernel.org
> > +S:	Maintained
> > +F:	Documentation/devicetree/bindings/media/fsl,imx9-csi-formatter.yaml
> > +F:	drivers/media/platform/nxp/imx9-csi-formatter.c
> > +
> >  NXP i.MX CLOCK DRIVERS
> >  M:	Abel Vesa <abelvesa at kernel.org>
> >  R:	Peng Fan <peng.fan at nxp.com>
> > diff --git a/drivers/media/platform/nxp/Kconfig
> > b/drivers/media/platform/nxp/Kconfig
> > index
> >
> 40e3436669e213fdc5da70821dc0b420e1821f4f..a7bb62a2b0249659ffdfeac50
> fa4
> > 88aee9590a87 100644
> > --- a/drivers/media/platform/nxp/Kconfig
> > +++ b/drivers/media/platform/nxp/Kconfig
> > @@ -28,6 +28,20 @@ config VIDEO_IMX8MQ_MIPI_CSI2
> >  	  Video4Linux2 driver for the MIPI CSI-2 receiver found on the i.MX8MQ
> >  	  SoC.
> >
> > +config VIDEO_IMX9_CSI_FORMATTER
> > +	tristate "NXP i.MX9 CSI Pixel Formatter driver"
> > +	depends on ARCH_MXC || COMPILE_TEST
> > +	depends on VIDEO_DEV
> > +	select MEDIA_CONTROLLER
> > +	select V4L2_FWNODE
> > +	select VIDEO_V4L2_SUBDEV_API
> > +	help
> > +	  This driver provides support for the CSI Pixel Formatter found on
> > +	  i.MX9 series SoC. This module unpacks the pixels received by the
> > +	  formatter and reformats them to meet the pixel link format
> requirement.
> > +
> > +	  Say Y here to enable CSI Pixel Formater module for i.MX9 SoC.
> > +
> >  config VIDEO_IMX_MIPI_CSIS
> >  	tristate "NXP MIPI CSI-2 CSIS receiver found on i.MX7 and i.MX8
> models"
> >  	depends on ARCH_MXC || COMPILE_TEST
> > diff --git a/drivers/media/platform/nxp/Makefile
> > b/drivers/media/platform/nxp/Makefile
> > index
> >
> 4d90eb71365259ebdda84ea58483e1c4131d3ac7..39ba5660ba923141e7637b
> 01b5b3
> > 4a021dad7bb3 100644
> > --- a/drivers/media/platform/nxp/Makefile
> > +++ b/drivers/media/platform/nxp/Makefile
> > @@ -6,6 +6,7 @@ obj-y += imx8-isi/
> >
> >  obj-$(CONFIG_VIDEO_IMX7_CSI) += imx7-media-csi.o
> >  obj-$(CONFIG_VIDEO_IMX8MQ_MIPI_CSI2) += imx8mq-mipi-csi2.o
> > +obj-$(CONFIG_VIDEO_IMX9_CSI_FORMATTER) += imx9-csi-formatter.o
> >  obj-$(CONFIG_VIDEO_IMX_MIPI_CSIS) += imx-mipi-csis.o
> >  obj-$(CONFIG_VIDEO_IMX_PXP) += imx-pxp.o
> >  obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o diff --git
> > a/drivers/media/platform/nxp/imx9-csi-formatter.c
> > b/drivers/media/platform/nxp/imx9-csi-formatter.c
> > new file mode 100644
> > index
> >
> 0000000000000000000000000000000000000000..5786e4690e31ee471caf82
> 01329c
> > 8e02a2cc0ee6
> > --- /dev/null
> > +++ b/drivers/media/platform/nxp/imx9-csi-formatter.c
> > @@ -0,0 +1,880 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright 2025 NXP
> > + */
> > +
> ...
> > +
> > +static const struct dt_index formatter_dt_to_index_map[] = {
> > +	{ .dtype = MIPI_CSI2_DT_YUV420_8B,        .index = 0 },
> > +	{ .dtype = MIPI_CSI2_DT_YUV420_8B_LEGACY, .index = 2 },
> > +	{ .dtype = MIPI_CSI2_DT_YUV422_8B,        .index = 6 },
> > +	{ .dtype = MIPI_CSI2_DT_RGB444,		  .index = 8 },
> > +	{ .dtype = MIPI_CSI2_DT_RGB555,           .index = 9 },
> > +	{ .dtype = MIPI_CSI2_DT_RGB565,           .index = 10 },
> > +	{ .dtype = MIPI_CSI2_DT_RGB666,           .index = 11 },
> > +	{ .dtype = MIPI_CSI2_DT_RGB888,           .index = 12 },
> > +	{ .dtype = MIPI_CSI2_DT_RAW6,             .index = 16 },
> > +	{ .dtype = MIPI_CSI2_DT_RAW7,             .index = 17 },
> > +	{ .dtype = MIPI_CSI2_DT_RAW8,             .index = 18 },
> > +	{ .dtype = MIPI_CSI2_DT_RAW10,            .index = 19 },
> > +	{ .dtype = MIPI_CSI2_DT_RAW12,            .index = 20 },
> > +	{ .dtype = MIPI_CSI2_DT_RAW14,            .index = 21 },
> > +	{ .dtype = MIPI_CSI2_DT_RAW16,            .index = 22 },
> 
> what's these index value from? register bit?

Yes, they represent pixel data type for each virtual channel. You could refer to
i.MX95 RM Rev2 section "142.5.1.55 Table 913" for more details.

Best Regards
G.N Zhou


> 
> Frank
> > +
> > +static u8 get_index_by_dt(u8 data_type) {
> > +	unsigned int i;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(formatter_dt_to_index_map); ++i)
> > +		if (data_type == formatter_dt_to_index_map[i].dtype)
> > +			break;
> > +
> > +	if (i == ARRAY_SIZE(formatter_dt_to_index_map))
> > +		return formatter_dt_to_index_map[0].index;
> > +
> > +	return formatter_dt_to_index_map[i].index;
> > +}
> > +
> ...
> >
> > --
> > 2.34.1
> >


From harini.t at amd.com  Sun Dec 21 20:46:53 2025
From: harini.t at amd.com (Harini T)
Date: Mon, 22 Dec 2025 10:16:53 +0530
Subject: [PATCH] dt-bindings: mailbox: xlnx,zynqmp-ipi-mailbox: Document msg region requirement
Message-ID: <20251222044653.1757886-1-harini.t@amd.com>

Add description clarifying that for Versal IPI mailboxes, both host and
remote agents must have the "msg" register region defined for successful
message passing. Without both, only notification-based communication
works.

Signed-off-by: Harini T <harini.t at amd.com>
---
 .../bindings/mailbox/xlnx,zynqmp-ipi-mailbox.yaml           | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-mailbox.yaml b/Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-mailbox.yaml
index 04d6473d666f..8fdf77c7935c 100644
--- a/Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-mailbox.yaml
+++ b/Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-mailbox.yaml
@@ -165,6 +165,12 @@ allOf:
         reg-names: false
 
     else:
+      description:
+        For Versal IPI mailboxes, the "msg" register region is optional.
+        However, for successful message passing via mailbox, both the host IPI
+        agent and the remote IPI agent must have the "msg" register region
+        defined. If either agent lacks the "msg" field, only notification-based
+        communication (without message buffers) will work.
       properties:
         reg:
           items:
-- 
2.43.0



From moonafterrain at outlook.com  Sun Dec 21 20:55:02 2025
From: moonafterrain at outlook.com (Junrui Luo)
Date: Mon, 22 Dec 2025 12:55:02 +0800
Subject: [PATCH] serial: digicolor: fix use-after-free on driver unbind
Message-ID: <SYBPR01MB7881327BF7F679E76A7315DEAFB4A@SYBPR01MB7881.ausprd01.prod.outlook.com>

The digicolor_uart_console_write() function accesses the global
digicolor_ports[] array to retrieve the uart port pointer, which
can lead to a use-after-free if the console write occurs after
the port has been removed via unbind.

digicolor_uart_remove() leaves a dangling pointer in the array.

Fix by clearing the array entry in digicolor_uart_remove() and
adding a NULL check in digicolor_uart_console_write().

Reported-by: Yuhao Jiang <danisjiang at gmail.com>
Reported-by: Junrui Luo <moonafterrain at outlook.com>
Fixes: 5930cb3511df ("serial: driver for Conexant Digicolor USART")
Signed-off-by: Junrui Luo <moonafterrain at outlook.com>
---
 drivers/tty/serial/digicolor-usart.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/tty/serial/digicolor-usart.c b/drivers/tty/serial/digicolor-usart.c
index d2482df5cb9b..5861be2072c4 100644
--- a/drivers/tty/serial/digicolor-usart.c
+++ b/drivers/tty/serial/digicolor-usart.c
@@ -397,6 +397,9 @@ static void digicolor_uart_console_write(struct console *co, const char *c,
 	unsigned long flags;
 	int locked = 1;
 
+	if (!port)
+		return;
+
 	if (oops_in_progress)
 		locked = uart_port_trylock_irqsave(port, &flags);
 	else
@@ -508,6 +511,7 @@ static void digicolor_uart_remove(struct platform_device *pdev)
 	struct uart_port *port = platform_get_drvdata(pdev);
 
 	uart_remove_one_port(&digicolor_uart, port);
+	digicolor_ports[port->line] = NULL;
 }
 
 static const struct of_device_id digicolor_uart_dt_ids[] = {

---
base-commit: ea1013c1539270e372fc99854bc6e4d94eaeff66
change-id: 20251222-fixes-74e6b26513d1

Best regards,
-- 
Junrui Luo <moonafterrain at outlook.com>



From baruch at tkos.co.il  Sun Dec 21 21:41:46 2025
From: baruch at tkos.co.il (Baruch Siach)
Date: Mon, 22 Dec 2025 07:41:46 +0200
Subject: [PATCH] serial: digicolor: fix use-after-free on driver unbind
In-Reply-To: <SYBPR01MB7881327BF7F679E76A7315DEAFB4A@SYBPR01MB7881.ausprd01.prod.outlook.com>
	(Junrui Luo's message of "Mon, 22 Dec 2025 12:55:02 +0800")
References: <SYBPR01MB7881327BF7F679E76A7315DEAFB4A@SYBPR01MB7881.ausprd01.prod.outlook.com>
Message-ID: <871pkndqed.fsf@tarshish>

Hi Junrui,

On Mon, Dec 22 2025, Junrui Luo wrote:
> The digicolor_uart_console_write() function accesses the global
> digicolor_ports[] array to retrieve the uart port pointer, which
> can lead to a use-after-free if the console write occurs after
> the port has been removed via unbind.
>
> digicolor_uart_remove() leaves a dangling pointer in the array.
>
> Fix by clearing the array entry in digicolor_uart_remove() and
> adding a NULL check in digicolor_uart_console_write().

Thanks for the patch.

Is this .write/.remove callbacks race actually possible? Can you refer
me to similar fixes in other drivers?

> Reported-by: Yuhao Jiang <danisjiang at gmail.com>

Where can I find this report?

Thanks,
baruch

> Reported-by: Junrui Luo <moonafterrain at outlook.com>
> Fixes: 5930cb3511df ("serial: driver for Conexant Digicolor USART")
> Signed-off-by: Junrui Luo <moonafterrain at outlook.com>
> ---
>  drivers/tty/serial/digicolor-usart.c | 4 ++++
>  1 file changed, 4 insertions(+)
>
> diff --git a/drivers/tty/serial/digicolor-usart.c b/drivers/tty/serial/digicolor-usart.c
> index d2482df5cb9b..5861be2072c4 100644
> --- a/drivers/tty/serial/digicolor-usart.c
> +++ b/drivers/tty/serial/digicolor-usart.c
> @@ -397,6 +397,9 @@ static void digicolor_uart_console_write(struct console *co, const char *c,
>  	unsigned long flags;
>  	int locked = 1;
>  
> +	if (!port)
> +		return;
> +
>  	if (oops_in_progress)
>  		locked = uart_port_trylock_irqsave(port, &flags);
>  	else
> @@ -508,6 +511,7 @@ static void digicolor_uart_remove(struct platform_device *pdev)
>  	struct uart_port *port = platform_get_drvdata(pdev);
>  
>  	uart_remove_one_port(&digicolor_uart, port);
> +	digicolor_ports[port->line] = NULL;
>  }
>  
>  static const struct of_device_id digicolor_uart_dt_ids[] = {
>
> ---
> base-commit: ea1013c1539270e372fc99854bc6e4d94eaeff66
> change-id: 20251222-fixes-74e6b26513d1
>
> Best regards,

-- 
                                                     ~. .~   Tk Open Systems
=}------------------------------------------------ooO--U--Ooo------------{=
   - baruch at tkos.co.il - tel: +972.52.368.4656, http://www.tkos.co.il -


From pavan.kondeti at oss.qualcomm.com  Sun Dec 21 22:00:19 2025
From: pavan.kondeti at oss.qualcomm.com (Pavan Kondeti)
Date: Mon, 22 Dec 2025 11:30:19 +0530
Subject: SMP boot issue during system resume
Message-ID: <dfa19ca7-c4c6-4386-a54d-44d623c8d3ed@quicinc.com>

Hi

We are seeing a SMP boot issue during system resume when CPUs are brought 
online via pm_sleep_enable_secondary_cpus()->thaw_secondary_cpus()->_cpu_up() 
on ARM64.

The _cpu_up() sets a global variable

secondary_data.task = idle;

and wait for the secondary CPU to come online. A 5 second timeout is
used here. If at all, the secondary CPU comes online after this timeout,
we expect it to loop in kernel via __secondary_too_slow(). However, this
depends on secondary_data.task value. Since we are bringing all disabled
cores, after timeout, we set this global variable to the next CPU idle
task and the late secondary CPU thinks the value is its idle task and
does not enter __secondary_too_slow().

An earlier attempt [1] to fix similar issue incrased the timout to 5
seconds. We could reproduce this issue in Linux guest where vCPU
scheduling latency can be higher under heavy load on the host.

I would like to seek your inputs on how we can improve the current
situation. We would like to avoid __secondary_too_slow() spin even when
the CPU comes late. This is probably not a desired behavior for other cases like 
Linux running bare metal or some guests. Having a Kconfig option or
kernel param might help here.

[1] https://lore.kernel.org/all/20190827151815.2160-1-will at kernel.org/


From jie.gan at oss.qualcomm.com  Sun Dec 21 22:02:20 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Mon, 22 Dec 2025 14:02:20 +0800
Subject: [PATCH v6 0/4] add sysfs nodes to configure TPDA's registers
Message-ID: <20251222-add_sysfs_nodes_to_configure_tpda-v6-0-b27143d45c86@oss.qualcomm.com>

Patchset 1 introduces configuration of the global control register with
appropriate values to enable proper generation of cross-trigger packets.

Patchset 2 introduces a sysfs node for triggering global flush for all
ports.

Patchset 3 introduces a logic to configure the TPDA_SYNCR register,
which determines the frequency of ASYNC packet generation. These packets
assist userspace tools in accurately identifying each valid packet.

Patchset 4 introduces a sysfs node to initiate a flush request for the
specific port, forcing the data to synchronize and be transmitted to the
sink device.

Changes in v6:
1. Create a new patch for introducing gloabl_flush_req sysfs node.
2. Add a syncr_mode sysfs node for TPDA_SYNCR.
3. Remove the redundant attr_grp and consolidate all attributes under tpda_attr_grp.
Link to v5: https://lore.kernel.org/r/20251219-add_sysfs_nodes_to_configure_tpda-v5-0-ca93ddfe9d30 at oss.qualcomm.com

Chnages in V5:
1. Optimizing the solution to creat sysfs nodes.
2. Optimizing the logic for configuring bits of the global control
   register.
Link to V4 - https://lore.kernel.org/all/20251028-configure_tpda_reg-v4-0-23000805d21d at oss.qualcomm.com/

Changes in V4:
1. Document sysfs nodes with correct kernel version and date.
Link to V3 - https://lore.kernel.org/linux-arm-kernel/20250827105545.7140-1-jie.gan at oss.qualcomm.com/

Changes in V3:
1. Optimizing codes according to James's comment.
Link to V2 - https://lore.kernel.org/all/20250827042042.6786-1-jie.gan at oss.qualcomm.com/

Changes in V2:
1. Refactoring the code based on James's comment for optimization.
Link to V1 - https://lore.kernel.org/all/20250826070150.5603-1-jie.gan at oss.qualcomm.com/

Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
Jie Gan (1):
      coresight: tpda: add global_flush_req sysfs node

Tao Zhang (3):
      coresight: tpda: add sysfs nodes for tpda cross-trigger configuration
      coresight: tpda: add logic to configure TPDA_SYNCR register
      coresight: tpda: add sysfs node to flush specific port

 .../ABI/testing/sysfs-bus-coresight-devices-tpda   |  60 ++++++
 drivers/hwtracing/coresight/coresight-tpda.c       | 240 ++++++++++++++++++++-
 drivers/hwtracing/coresight/coresight-tpda.h       |  74 ++++++-
 3 files changed, 367 insertions(+), 7 deletions(-)
---
base-commit: 12b95d29eb979e5c4f4f31bb05817bc935c52050
change-id: 20251219-add_sysfs_nodes_to_configure_tpda-f54636512817

Best regards,
-- 
Jie Gan <jie.gan at oss.qualcomm.com>



From jie.gan at oss.qualcomm.com  Sun Dec 21 22:02:21 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Mon, 22 Dec 2025 14:02:21 +0800
Subject: [PATCH v6 1/4] coresight: tpda: add sysfs nodes for tpda
 cross-trigger configuration
In-Reply-To: <20251222-add_sysfs_nodes_to_configure_tpda-v6-0-b27143d45c86@oss.qualcomm.com>
References: <20251222-add_sysfs_nodes_to_configure_tpda-v6-0-b27143d45c86@oss.qualcomm.com>
Message-ID: <20251222-add_sysfs_nodes_to_configure_tpda-v6-1-b27143d45c86@oss.qualcomm.com>

From: Tao Zhang <tao.zhang at oss.qualcomm.com>

Introduce sysfs nodes to configure cross-trigger parameters for TPDA.
These registers define the characteristics of cross-trigger packets,
including generation frequency and flag values.

Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
Reviewed-by: James Clark <james.clark at linaro.org>
Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 .../ABI/testing/sysfs-bus-coresight-devices-tpda   |  35 +++++++
 drivers/hwtracing/coresight/coresight-tpda.c       | 109 ++++++++++++++++++++-
 drivers/hwtracing/coresight/coresight-tpda.h       |  63 +++++++++++-
 3 files changed, 200 insertions(+), 7 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
new file mode 100644
index 000000000000..735ce0e494da
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
@@ -0,0 +1,35 @@
+What:		/sys/bus/coresight/devices/<tpda-name>/trig_async_enable
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Enable/disable cross trigger synchronization sequence interface.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/trig_flag_ts_enable
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Enable/disable cross trigger FLAG packet request interface.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/trig_freq_enable
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Enable/disable cross trigger FREQ packet request interface.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/freq_ts_enable
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Enable/disable the timestamp for all FREQ packets.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/cmbchan_mode
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Configure the CMB/MCMB channel mode for all enabled ports.
+		Value 0 means raw channel mapping mode. Value 1 means channel pair marking mode.
diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
index 3a3825d27f86..2186223ad33e 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.c
+++ b/drivers/hwtracing/coresight/coresight-tpda.c
@@ -137,12 +137,32 @@ static int tpda_get_element_size(struct tpda_drvdata *drvdata,
 /* Settings pre enabling port control register */
 static void tpda_enable_pre_port(struct tpda_drvdata *drvdata)
 {
-	u32 val;
+	u32 val = 0;
 
-	val = readl_relaxed(drvdata->base + TPDA_CR);
-	val &= ~TPDA_CR_ATID;
 	val |= FIELD_PREP(TPDA_CR_ATID, drvdata->atid);
+	if (drvdata->trig_async)
+		val |= TPDA_CR_SRIE;
+
+	if (drvdata->trig_flag_ts)
+		val |= TPDA_CR_FLRIE;
+
+	if (drvdata->trig_freq)
+		val |= TPDA_CR_FRIE;
+
+	if (drvdata->freq_ts)
+		val |= TPDA_CR_FREQTS;
+
+	if (drvdata->cmbchan_mode)
+		val |= TPDA_CR_CMBCHANMODE;
+
 	writel_relaxed(val, drvdata->base + TPDA_CR);
+
+	/*
+	 * If FLRIE bit is set, set the master and channel
+	 * id as zero
+	 */
+	if (drvdata->trig_flag_ts)
+		writel_relaxed(0x0, drvdata->base + TPDA_FPID_CR);
 }
 
 static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
@@ -258,6 +278,87 @@ static const struct coresight_ops tpda_cs_ops = {
 	.link_ops	= &tpda_link_ops,
 };
 
+/* Read cross-trigger register member */
+static ssize_t tpda_trig_sysfs_show(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	struct tpda_trig_sysfs_attribute *tpda_attr =
+		container_of(attr, struct tpda_trig_sysfs_attribute, attr);
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	guard(spinlock)(&drvdata->spinlock);
+	switch (tpda_attr->mem) {
+	case FREQTS:
+		return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->freq_ts);
+	case FRIE:
+		return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_freq);
+	case FLRIE:
+		return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_flag_ts);
+	case SRIE:
+		return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_async);
+	case CMBCHANMODE:
+		return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->cmbchan_mode);
+
+	}
+	return -EINVAL;
+}
+
+static ssize_t tpda_trig_sysfs_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf,
+				     size_t size)
+{
+	struct tpda_trig_sysfs_attribute *tpda_attr =
+		container_of(attr, struct tpda_trig_sysfs_attribute, attr);
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (kstrtoul(buf, 0, &val))
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	switch (tpda_attr->mem) {
+	case FREQTS:
+		drvdata->freq_ts = !!val;
+		break;
+	case FRIE:
+		drvdata->trig_freq = !!val;
+		break;
+	case FLRIE:
+		drvdata->trig_flag_ts = !!val;
+		break;
+	case SRIE:
+		drvdata->trig_async = !!val;
+		break;
+	case CMBCHANMODE:
+		drvdata->cmbchan_mode = !!val;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return size;
+}
+
+static struct attribute *tpda_attrs[] = {
+	tpda_trig_sysfs_rw(freq_ts_enable, FREQTS),
+	tpda_trig_sysfs_rw(trig_freq_enable, FRIE),
+	tpda_trig_sysfs_rw(trig_flag_ts_enable, FLRIE),
+	tpda_trig_sysfs_rw(trig_async_enable, SRIE),
+	tpda_trig_sysfs_rw(cmbchan_mode, CMBCHANMODE),
+	NULL,
+};
+
+static struct attribute_group tpda_attr_grp = {
+	.attrs	= tpda_attrs,
+};
+
+static const struct attribute_group *tpda_attr_grps[] = {
+	&tpda_attr_grp,
+	NULL,
+};
+
 static int tpda_init_default_data(struct tpda_drvdata *drvdata)
 {
 	int atid;
@@ -273,6 +374,7 @@ static int tpda_init_default_data(struct tpda_drvdata *drvdata)
 		return atid;
 
 	drvdata->atid = atid;
+	drvdata->freq_ts = true;
 	return 0;
 }
 
@@ -316,6 +418,7 @@ static int tpda_probe(struct amba_device *adev, const struct amba_id *id)
 	desc.ops = &tpda_cs_ops;
 	desc.pdata = adev->dev.platform_data;
 	desc.dev = &adev->dev;
+	desc.groups = tpda_attr_grps;
 	desc.access = CSDEV_ACCESS_IOMEM(base);
 	drvdata->csdev = coresight_register(&desc);
 	if (IS_ERR(drvdata->csdev))
diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h
index c6af3d2da3ef..c93732e04af2 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.h
+++ b/drivers/hwtracing/coresight/coresight-tpda.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 /*
- * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2023,2025 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CORESIGHT_CORESIGHT_TPDA_H
@@ -8,6 +8,25 @@
 
 #define TPDA_CR			(0x000)
 #define TPDA_Pn_CR(n)		(0x004 + (n * 4))
+#define TPDA_FPID_CR		(0x084)
+
+/* Cross trigger FREQ packets timestamp bit */
+#define TPDA_CR_FREQTS		BIT(2)
+/* Cross trigger FREQ packet request bit */
+#define TPDA_CR_FRIE		BIT(3)
+/* Cross trigger FLAG packet request interface bit */
+#define TPDA_CR_FLRIE		BIT(4)
+/* Cross trigger synchronization bit */
+#define TPDA_CR_SRIE		BIT(5)
+/* Bits 6 ~ 12 is for atid value */
+#define TPDA_CR_ATID		GENMASK(12, 6)
+/*
+ * Channel mode bit of the packetization of CMB/MCB traffic
+ * 0 - raw channel mapping mode
+ * 1 - channel pair marking mode
+ */
+#define TPDA_CR_CMBCHANMODE	BIT(20)
+
 /* Aggregator port enable bit */
 #define TPDA_Pn_CR_ENA		BIT(0)
 /* Aggregator port CMB data set element size bit */
@@ -17,9 +36,6 @@
 
 #define TPDA_MAX_INPORTS	32
 
-/* Bits 6 ~ 12 is for atid value */
-#define TPDA_CR_ATID		GENMASK(12, 6)
-
 /**
  * struct tpda_drvdata - specifics associated to an TPDA component
  * @base:       memory mapped base address for this component.
@@ -29,6 +45,11 @@
  * @enable:     enable status of the component.
  * @dsb_esize   Record the DSB element size.
  * @cmb_esize   Record the CMB element size.
+ * @trig_async:	Enable/disable cross trigger synchronization sequence interface.
+ * @trig_flag_ts: Enable/disable cross trigger FLAG packet request interface.
+ * @trig_freq:	Enable/disable cross trigger FREQ packet request interface.
+ * @freq_ts:	Enable/disable the timestamp for all FREQ packets.
+ * @cmbchan_mode: Configure the CMB/MCMB channel mode.
  */
 struct tpda_drvdata {
 	void __iomem		*base;
@@ -38,6 +59,40 @@ struct tpda_drvdata {
 	u8			atid;
 	u32			dsb_esize;
 	u32			cmb_esize;
+	bool			trig_async;
+	bool			trig_flag_ts;
+	bool			trig_freq;
+	bool			freq_ts;
+	bool			cmbchan_mode;
+};
+
+/* Enumerate members of global control register(cr) */
+enum tpda_cr_mem {
+	FREQTS,
+	FRIE,
+	FLRIE,
+	SRIE,
+	CMBCHANMODE
+};
+
+/**
+ * struct tpda_trig_sysfs_attribute - Record the member variables of cross
+ * trigger register that need to be operated by sysfs file
+ * @attr:	The device attribute
+ * @mem:	The member in the control register data structure
+ */
+struct tpda_trig_sysfs_attribute {
+	struct device_attribute attr;
+	enum tpda_cr_mem mem;
 };
 
+#define tpda_trig_sysfs_rw(name, mem)				\
+	(&((struct tpda_trig_sysfs_attribute[]) {		\
+	   {							\
+		__ATTR(name, 0644, tpda_trig_sysfs_show,	\
+		tpda_trig_sysfs_store),				\
+		mem,						\
+	   }							\
+	   })[0].attr.attr)
+
 #endif  /* _CORESIGHT_CORESIGHT_TPDA_H */

-- 
2.34.1



From jie.gan at oss.qualcomm.com  Sun Dec 21 22:02:22 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Mon, 22 Dec 2025 14:02:22 +0800
Subject: [PATCH v6 2/4] coresight: tpda: add global_flush_req sysfs node
In-Reply-To: <20251222-add_sysfs_nodes_to_configure_tpda-v6-0-b27143d45c86@oss.qualcomm.com>
References: <20251222-add_sysfs_nodes_to_configure_tpda-v6-0-b27143d45c86@oss.qualcomm.com>
Message-ID: <20251222-add_sysfs_nodes_to_configure_tpda-v6-2-b27143d45c86@oss.qualcomm.com>

Setting the global_flush_req register to 1 initiates a flush request for
all enabled TPDA input ports. The register remains set until the flush
operation is complete.

Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 .../ABI/testing/sysfs-bus-coresight-devices-tpda   |  8 ++++
 drivers/hwtracing/coresight/coresight-tpda.c       | 45 ++++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-tpda.h       |  2 +
 3 files changed, 55 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
index 735ce0e494da..c8bc7b19ab25 100644
--- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
@@ -33,3 +33,11 @@ Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qu
 Description:
 		(RW) Configure the CMB/MCMB channel mode for all enabled ports.
 		Value 0 means raw channel mapping mode. Value 1 means channel pair marking mode.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/global_flush_req
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Set global (all ports) flush request bit. The bit remains set until a
+		global flush request sequence completes.
diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
index 2186223ad33e..d24a9098f1b1 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.c
+++ b/drivers/hwtracing/coresight/coresight-tpda.c
@@ -341,7 +341,52 @@ static ssize_t tpda_trig_sysfs_store(struct device *dev,
 	return size;
 }
 
+static ssize_t global_flush_req_show(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (!drvdata->csdev->refcnt)
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	val = readl_relaxed(drvdata->base + TPDA_CR);
+	/* read global_flush_req bit */
+	val &= TPDA_CR_FLREQ;
+
+	return sysfs_emit(buf, "%lu\n", val);
+}
+
+static ssize_t global_flush_req_store(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf,
+				      size_t size)
+{
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (kstrtoul(buf, 0, &val))
+		return -EINVAL;
+
+	if (!drvdata->csdev->refcnt || !val)
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	val = readl_relaxed(drvdata->base + TPDA_CR);
+	/* set global_flush_req bit */
+	val |= TPDA_CR_FLREQ;
+	CS_UNLOCK(drvdata->base);
+	writel_relaxed(val, drvdata->base + TPDA_CR);
+	CS_LOCK(drvdata->base);
+
+	return size;
+}
+static DEVICE_ATTR_RW(global_flush_req);
+
 static struct attribute *tpda_attrs[] = {
+	&dev_attr_global_flush_req.attr,
 	tpda_trig_sysfs_rw(freq_ts_enable, FREQTS),
 	tpda_trig_sysfs_rw(trig_freq_enable, FRIE),
 	tpda_trig_sysfs_rw(trig_flag_ts_enable, FLRIE),
diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h
index c93732e04af2..1cc9253293ec 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.h
+++ b/drivers/hwtracing/coresight/coresight-tpda.h
@@ -10,6 +10,8 @@
 #define TPDA_Pn_CR(n)		(0x004 + (n * 4))
 #define TPDA_FPID_CR		(0x084)
 
+/* Cross trigger global (all ports) flush request bit */
+#define TPDA_CR_FLREQ		BIT(0)
 /* Cross trigger FREQ packets timestamp bit */
 #define TPDA_CR_FREQTS		BIT(2)
 /* Cross trigger FREQ packet request bit */

-- 
2.34.1



From jie.gan at oss.qualcomm.com  Sun Dec 21 22:02:23 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Mon, 22 Dec 2025 14:02:23 +0800
Subject: [PATCH v6 3/4] coresight: tpda: add logic to configure TPDA_SYNCR
 register
In-Reply-To: <20251222-add_sysfs_nodes_to_configure_tpda-v6-0-b27143d45c86@oss.qualcomm.com>
References: <20251222-add_sysfs_nodes_to_configure_tpda-v6-0-b27143d45c86@oss.qualcomm.com>
Message-ID: <20251222-add_sysfs_nodes_to_configure_tpda-v6-3-b27143d45c86@oss.qualcomm.com>

From: Tao Zhang <tao.zhang at oss.qualcomm.com>

The TPDA_SYNC counter tracks the number of bytes transferred from the
aggregator. When this count reaches the value programmed in the
TPDA_SYNCR register, an ASYNC request is triggered, allowing userspace
tools to accurately parse each valid packet.

Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
Reviewed-by: James Clark <james.clark at linaro.org>
Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 .../ABI/testing/sysfs-bus-coresight-devices-tpda   | 10 +++++
 drivers/hwtracing/coresight/coresight-tpda.c       | 46 ++++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-tpda.h       |  8 ++++
 3 files changed, 64 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
index c8bc7b19ab25..d359d90dca72 100644
--- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
@@ -41,3 +41,13 @@ Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qu
 Description:
 		(RW) Set global (all ports) flush request bit. The bit remains set until a
 		global flush request sequence completes.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/syncr_mode
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Set mode the of the syncr counter.
+		mode 0 - COUNT[11:0] value represents the approximate number of bytes moved between two ASYNC packet requests
+		mode 1 - the bits COUNT[11:7] are used as a power of 2. for example, we could insert an async packet every 8K
+		         data by writing a value 13 to the COUNT[11:7] field.
diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
index d24a9098f1b1..7baa8a0965d3 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.c
+++ b/drivers/hwtracing/coresight/coresight-tpda.c
@@ -163,6 +163,15 @@ static void tpda_enable_pre_port(struct tpda_drvdata *drvdata)
 	 */
 	if (drvdata->trig_flag_ts)
 		writel_relaxed(0x0, drvdata->base + TPDA_FPID_CR);
+
+	/* Initialize with a value of 0 */
+	val = 0;
+	if (drvdata->syncr_mode)
+		val |= TPDA_SYNCR_MODE_CTRL_MASK;
+
+	/* Program the counter to its MAX value by default */
+	val |= TPDA_SYNCR_COUNTER_MASK;
+	writel_relaxed(val, drvdata->base + TPDA_SYNCR);
 }
 
 static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
@@ -385,8 +394,45 @@ static ssize_t global_flush_req_store(struct device *dev,
 }
 static DEVICE_ATTR_RW(global_flush_req);
 
+static ssize_t syncr_mode_show(struct device *dev,
+			       struct device_attribute *attr,
+			       char *buf)
+{
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val, syncr_val;
+
+	if (!drvdata->csdev->refcnt)
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	syncr_val = readl_relaxed(drvdata->base + TPDA_SYNCR);
+	val = FIELD_GET(TPDA_SYNCR_MODE_CTRL_MASK, syncr_val);
+
+	return sysfs_emit(buf, "%lu\n", val);
+}
+
+static ssize_t syncr_mode_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf,
+				size_t size)
+{
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (kstrtoul(buf, 0, &val))
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	/* set the mode when first enabling the device */
+	drvdata->syncr_mode = !!val;
+
+	return size;
+}
+static DEVICE_ATTR_RW(syncr_mode);
+
 static struct attribute *tpda_attrs[] = {
 	&dev_attr_global_flush_req.attr,
+	&dev_attr_syncr_mode.attr,
 	tpda_trig_sysfs_rw(freq_ts_enable, FREQTS),
 	tpda_trig_sysfs_rw(trig_freq_enable, FRIE),
 	tpda_trig_sysfs_rw(trig_flag_ts_enable, FLRIE),
diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h
index 1cc9253293ec..1d2de50bb9f9 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.h
+++ b/drivers/hwtracing/coresight/coresight-tpda.h
@@ -9,6 +9,7 @@
 #define TPDA_CR			(0x000)
 #define TPDA_Pn_CR(n)		(0x004 + (n * 4))
 #define TPDA_FPID_CR		(0x084)
+#define TPDA_SYNCR		(0x08C)
 
 /* Cross trigger global (all ports) flush request bit */
 #define TPDA_CR_FLREQ		BIT(0)
@@ -36,6 +37,11 @@
 /* Aggregator port DSB data set element size bit */
 #define TPDA_Pn_CR_DSBSIZE		BIT(8)
 
+/* TPDA_SYNCR counter mask */
+#define TPDA_SYNCR_COUNTER_MASK		GENMASK(11, 0)
+/* TPDA_SYNCR mode control bit */
+#define TPDA_SYNCR_MODE_CTRL_MASK	GENMASK(12, 12)
+
 #define TPDA_MAX_INPORTS	32
 
 /**
@@ -52,6 +58,7 @@
  * @trig_freq:	Enable/disable cross trigger FREQ packet request interface.
  * @freq_ts:	Enable/disable the timestamp for all FREQ packets.
  * @cmbchan_mode: Configure the CMB/MCMB channel mode.
+ * @syncr_mode:	Configure the mode for counting packets.
  */
 struct tpda_drvdata {
 	void __iomem		*base;
@@ -66,6 +73,7 @@ struct tpda_drvdata {
 	bool			trig_freq;
 	bool			freq_ts;
 	bool			cmbchan_mode;
+	bool			syncr_mode;
 };
 
 /* Enumerate members of global control register(cr) */

-- 
2.34.1



From jie.gan at oss.qualcomm.com  Sun Dec 21 22:02:24 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Mon, 22 Dec 2025 14:02:24 +0800
Subject: [PATCH v6 4/4] coresight: tpda: add sysfs node to flush specific
 port
In-Reply-To: <20251222-add_sysfs_nodes_to_configure_tpda-v6-0-b27143d45c86@oss.qualcomm.com>
References: <20251222-add_sysfs_nodes_to_configure_tpda-v6-0-b27143d45c86@oss.qualcomm.com>
Message-ID: <20251222-add_sysfs_nodes_to_configure_tpda-v6-4-b27143d45c86@oss.qualcomm.com>

From: Tao Zhang <tao.zhang at oss.qualcomm.com>

Setting bit i in the TPDA_FLUSH_CR register initiates a flush request
for port i, forcing the data to synchronize and be transmitted to the
sink device.

Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
Reviewed-by: James Clark <james.clark at linaro.org>
Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 .../ABI/testing/sysfs-bus-coresight-devices-tpda   |  7 ++++
 drivers/hwtracing/coresight/coresight-tpda.c       | 40 ++++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-tpda.h       |  1 +
 3 files changed, 48 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
index d359d90dca72..df8f03d4b573 100644
--- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
@@ -51,3 +51,10 @@ Description:
 		mode 0 - COUNT[11:0] value represents the approximate number of bytes moved between two ASYNC packet requests
 		mode 1 - the bits COUNT[11:7] are used as a power of 2. for example, we could insert an async packet every 8K
 		         data by writing a value 13 to the COUNT[11:7] field.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/port_flush_req
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Configure the bit i to requests a flush operation of port i on the TPDA.
diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
index 7baa8a0965d3..f79fea4fbb2c 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.c
+++ b/drivers/hwtracing/coresight/coresight-tpda.c
@@ -430,9 +430,49 @@ static ssize_t syncr_mode_store(struct device *dev,
 }
 static DEVICE_ATTR_RW(syncr_mode);
 
+static ssize_t port_flush_req_show(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (!drvdata->csdev->refcnt)
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	val = readl_relaxed(drvdata->base + TPDA_FLUSH_CR);
+
+	return sysfs_emit(buf, "0x%lx\n", val);
+}
+
+static ssize_t port_flush_req_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf,
+				    size_t size)
+{
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	u32 val;
+
+	if (kstrtou32(buf, 0, &val))
+		return -EINVAL;
+
+	if (!drvdata->csdev->refcnt || !val)
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	CS_UNLOCK(drvdata->base);
+	writel_relaxed(val, drvdata->base + TPDA_FLUSH_CR);
+	CS_LOCK(drvdata->base);
+
+	return size;
+}
+static DEVICE_ATTR_RW(port_flush_req);
+
 static struct attribute *tpda_attrs[] = {
 	&dev_attr_global_flush_req.attr,
 	&dev_attr_syncr_mode.attr,
+	&dev_attr_port_flush_req.attr,
 	tpda_trig_sysfs_rw(freq_ts_enable, FREQTS),
 	tpda_trig_sysfs_rw(trig_freq_enable, FRIE),
 	tpda_trig_sysfs_rw(trig_flag_ts_enable, FLRIE),
diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h
index 1d2de50bb9f9..ef1ce2ce36a9 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.h
+++ b/drivers/hwtracing/coresight/coresight-tpda.h
@@ -10,6 +10,7 @@
 #define TPDA_Pn_CR(n)		(0x004 + (n * 4))
 #define TPDA_FPID_CR		(0x084)
 #define TPDA_SYNCR		(0x08C)
+#define TPDA_FLUSH_CR		(0x090)
 
 /* Cross trigger global (all ports) flush request bit */
 #define TPDA_CR_FLREQ		BIT(0)

-- 
2.34.1



From mani at kernel.org  Sun Dec 21 22:15:09 2025
From: mani at kernel.org (Manivannan Sadhasivam)
Date: Mon, 22 Dec 2025 11:45:09 +0530
Subject: [PATCH v2] PCI: dwc: Make Link Up IRQ logic handle already
 powered on PCIe switches
In-Reply-To: <aTu4JgDcfb_58qBK@fedora>
References: <20251201063634.4115762-2-cassel@kernel.org>
 <f1059d5d-3fa5-423a-8093-0e99b65d5f4c@oss.qualcomm.com>
 <aTev28wihes6iJqs@dhcp-10-89-81-223>
 <dad4957c-ca13-4742-b46d-03f0478911d5@oss.qualcomm.com>
 <aTe1bA7lcVzFD5L7@dhcp-10-89-81-223>
 <pjn2gs43rqbe3odh6zvh4qaftxxl6qvdzpm6pgpadxeeid42ko@4a2qradscaqd>
 <aTu4JgDcfb_58qBK@fedora>
Message-ID: <fle74skju2rorxmfdvosmeyrx3g75rysuszov5ofvde2exj4ir@3kfjyfyhczmn>

On Fri, Dec 12, 2025 at 03:37:26PM +0900, Niklas Cassel wrote:
> Hello Mani,
> 
> On Fri, Dec 12, 2025 at 12:52:35PM +0900, Manivannan Sadhasivam wrote:
> > > This patch missed the v6.19 merge window (and so did the pwrctrl rework
> > > series), so as long as Mani queues up both for v6.20 (with the pwrctrl
> > > rework series getting applied first), I think we are good.
> > > 
> > 
> > The plan is to merge pwrctrl series to v6.20 (unless we get strong objections),
> > but once that happens, Qcom doesn't need this patch.
> > 
> > So it'd be good if you can just limit this patch to just Rockchip. Then once the
> > Rockchip also moves to pwrctrl, we can revert this patch (also the whole IRQ
> > based link up since the Root Port is not hotplug capable).
> 
> The main reason why I did not like a revert, was because it would remove
> the nice feature where the bus is enumerated automatically on link up.
> 
> I assumed that the plan was to add Link Up IRQ support in pwrctrl in the
> future.
> 

As I dig more and more into pwrctrl, it becomes clear to me that emulating
hotplug on non-hotplug capable hw is a bad idea. Though it gives a nice user
experience in majority of the cases, it also gives issue in some cases like
switch. So pwrctrl will just power on all devices/slots before initial bus scan
and will not do any link up based enumeration later. And neither the controller
driver.

> If that is not the case, and the plan is instead to eventually remove the
> existing Link Up IRQ support, then perhaps you could simply apply patches
> from:
> https://lore.kernel.org/linux-pci/20251111105100.869997-8-cassel at kernel.org/
> 
> Either the whole series or just patch 1 and 2, maintainer's choice :)
> 

I tried applying the whole series, but it fails at patch 2. Could you please
rebase against, pci/controller/dwc and repost?

- Mani

-- 
????????? ????????


From mani at kernel.org  Sun Dec 21 22:16:57 2025
From: mani at kernel.org (Manivannan Sadhasivam)
Date: Mon, 22 Dec 2025 11:46:57 +0530
Subject: [PATCH 0/6] PCI: dwc: Revert Link Up IRQ support
In-Reply-To: <20251111105100.869997-8-cassel@kernel.org>
References: <20251111105100.869997-8-cassel@kernel.org>
Message-ID: <cngg5kifjqmrmb5ufyrv4k6dwo5tgatqssaeoog5aqpe7m253c@krov7axlplkw>

On Tue, Nov 11, 2025 at 11:51:00AM +0100, Niklas Cassel wrote:
> Revert all patches related to pcie-designware Root Complex Link Up IRQ
> support.
> 
> While this fake hotplugging was a nice idea, it has shown that this feature
> does not handle PCIe switches correctly:
> pci_bus 0004:43: busn_res: can not insert [bus 43-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci_bus 0004:43: busn_res: [bus 43-41] end is updated to 43
> pci_bus 0004:43: busn_res: can not insert [bus 43] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci 0004:42:00.0: devices behind bridge are unusable because [bus 43] cannot be assigned for them
> pci_bus 0004:44: busn_res: can not insert [bus 44-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci_bus 0004:44: busn_res: [bus 44-41] end is updated to 44
> pci_bus 0004:44: busn_res: can not insert [bus 44] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci 0004:42:02.0: devices behind bridge are unusable because [bus 44] cannot be assigned for them
> pci_bus 0004:45: busn_res: can not insert [bus 45-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci_bus 0004:45: busn_res: [bus 45-41] end is updated to 45
> pci_bus 0004:45: busn_res: can not insert [bus 45] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci 0004:42:06.0: devices behind bridge are unusable because [bus 45] cannot be assigned for them
> pci_bus 0004:46: busn_res: can not insert [bus 46-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci_bus 0004:46: busn_res: [bus 46-41] end is updated to 46
> pci_bus 0004:46: busn_res: can not insert [bus 46] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci 0004:42:0e.0: devices behind bridge are unusable because [bus 46] cannot be assigned for them
> pci_bus 0004:42: busn_res: [bus 42-41] end is updated to 46
> pci_bus 0004:42: busn_res: can not insert [bus 42-46] under [bus 41] (conflicts with (null) [bus 41])
> pci 0004:41:00.0: devices behind bridge are unusable because [bus 42-46] cannot be assigned for them
> pcieport 0004:40:00.0: bridge has subordinate 41 but max busn 46
> 
> During the initial scan, PCI core doesn't see the switch and since the Root
> Port is not hot plug capable, the secondary bus number gets assigned as the
> subordinate bus number. This means, the PCI core assumes that only one bus
> will appear behind the Root Port since the Root Port is not hot plug
> capable.
> 
> This works perfectly fine for PCIe endpoints connected to the Root Port,
> since they don't extend the bus. However, if a PCIe switch is connected,
> then there is a problem when the downstream busses starts showing up and
> the PCI core doesn't extend the subordinate bus number after initial scan
> during boot.
> 
> The long term plan is to migrate this driver to the pwrctrl framework,
> once it adds proper support for powering up and enumerating PCIe switches.
> 

Could you please rebase this series on top of pci/controller/dwc branch and
repost?

- Mani

> Niklas Cassel (6):
>   Revert "PCI: dw-rockchip: Don't wait for link since we can detect Link
>     Up"
>   Revert "PCI: dw-rockchip: Enumerate endpoints based on dll_link_up
>     IRQ"
>   Revert "PCI: qcom: Don't wait for link if we can detect Link Up"
>   Revert "PCI: qcom: Enable MSI interrupts together with Link up if
>     'Global IRQ' is supported"
>   Revert "PCI: qcom: Enumerate endpoints based on Link up event in
>     'global_irq' interrupt"
>   Revert "PCI: dwc: Don't wait for link up if driver can detect Link Up
>     event"
> 
>  .../pci/controller/dwc/pcie-designware-host.c | 10 +--
>  drivers/pci/controller/dwc/pcie-designware.h  |  1 -
>  drivers/pci/controller/dwc/pcie-dw-rockchip.c | 60 +-----------------
>  drivers/pci/controller/dwc/pcie-qcom.c        | 63 +------------------
>  4 files changed, 6 insertions(+), 128 deletions(-)
> 
> -- 
> 2.51.1
> 

-- 
????????? ????????


From gregkh at linuxfoundation.org  Sun Dec 21 22:22:14 2025
From: gregkh at linuxfoundation.org (Greg Kroah-Hartman)
Date: Mon, 22 Dec 2025 07:22:14 +0100
Subject: [PATCH] serial: digicolor: fix use-after-free on driver unbind
In-Reply-To: <SYBPR01MB7881327BF7F679E76A7315DEAFB4A@SYBPR01MB7881.ausprd01.prod.outlook.com>
References: <SYBPR01MB7881327BF7F679E76A7315DEAFB4A@SYBPR01MB7881.ausprd01.prod.outlook.com>
Message-ID: <2025122232-grass-stoppage-6645@gregkh>

On Mon, Dec 22, 2025 at 12:55:02PM +0800, Junrui Luo wrote:
> The digicolor_uart_console_write() function accesses the global
> digicolor_ports[] array to retrieve the uart port pointer, which
> can lead to a use-after-free if the console write occurs after
> the port has been removed via unbind.
> 
> digicolor_uart_remove() leaves a dangling pointer in the array.
> 
> Fix by clearing the array entry in digicolor_uart_remove() and
> adding a NULL check in digicolor_uart_console_write().
> 
> Reported-by: Yuhao Jiang <danisjiang at gmail.com>
> Reported-by: Junrui Luo <moonafterrain at outlook.com>
> Fixes: 5930cb3511df ("serial: driver for Conexant Digicolor USART")
> Signed-off-by: Junrui Luo <moonafterrain at outlook.com>
> ---
>  drivers/tty/serial/digicolor-usart.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/drivers/tty/serial/digicolor-usart.c b/drivers/tty/serial/digicolor-usart.c
> index d2482df5cb9b..5861be2072c4 100644
> --- a/drivers/tty/serial/digicolor-usart.c
> +++ b/drivers/tty/serial/digicolor-usart.c
> @@ -397,6 +397,9 @@ static void digicolor_uart_console_write(struct console *co, const char *c,
>  	unsigned long flags;
>  	int locked = 1;
>  
> +	if (!port)
> +		return;
> +

What prevents port from changing right after you tested this?

And who is calling unbind on a port?  Why?  That's a debuggging thing
that a developer could do, it should not be part of any normal system
operation.

thanks,

greg k-h


From cassel at kernel.org  Sun Dec 21 22:42:07 2025
From: cassel at kernel.org (Niklas Cassel)
Date: Mon, 22 Dec 2025 07:42:07 +0100
Subject: [PATCH v2 0/6] PCI: dwc: Revert Link Up IRQ support
Message-ID: <20251222064207.3246632-8-cassel@kernel.org>

Revert all patches related to pcie-designware Root Complex Link Up IRQ
support.

While this fake hotplugging was a nice idea, it has shown that this feature
does not handle PCIe switches correctly:
pci_bus 0004:43: busn_res: can not insert [bus 43-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
pci_bus 0004:43: busn_res: [bus 43-41] end is updated to 43
pci_bus 0004:43: busn_res: can not insert [bus 43] under [bus 42-41] (conflicts with (null) [bus 42-41])
pci 0004:42:00.0: devices behind bridge are unusable because [bus 43] cannot be assigned for them
pci_bus 0004:44: busn_res: can not insert [bus 44-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
pci_bus 0004:44: busn_res: [bus 44-41] end is updated to 44
pci_bus 0004:44: busn_res: can not insert [bus 44] under [bus 42-41] (conflicts with (null) [bus 42-41])
pci 0004:42:02.0: devices behind bridge are unusable because [bus 44] cannot be assigned for them
pci_bus 0004:45: busn_res: can not insert [bus 45-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
pci_bus 0004:45: busn_res: [bus 45-41] end is updated to 45
pci_bus 0004:45: busn_res: can not insert [bus 45] under [bus 42-41] (conflicts with (null) [bus 42-41])
pci 0004:42:06.0: devices behind bridge are unusable because [bus 45] cannot be assigned for them
pci_bus 0004:46: busn_res: can not insert [bus 46-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
pci_bus 0004:46: busn_res: [bus 46-41] end is updated to 46
pci_bus 0004:46: busn_res: can not insert [bus 46] under [bus 42-41] (conflicts with (null) [bus 42-41])
pci 0004:42:0e.0: devices behind bridge are unusable because [bus 46] cannot be assigned for them
pci_bus 0004:42: busn_res: [bus 42-41] end is updated to 46
pci_bus 0004:42: busn_res: can not insert [bus 42-46] under [bus 41] (conflicts with (null) [bus 41])
pci 0004:41:00.0: devices behind bridge are unusable because [bus 42-46] cannot be assigned for them
pcieport 0004:40:00.0: bridge has subordinate 41 but max busn 46

During the initial scan, PCI core doesn't see the switch and since the Root
Port is not hot plug capable, the secondary bus number gets assigned as the
subordinate bus number. This means, the PCI core assumes that only one bus
will appear behind the Root Port since the Root Port is not hot plug
capable.

This works perfectly fine for PCIe endpoints connected to the Root Port,
since they don't extend the bus. However, if a PCIe switch is connected,
then there is a problem when the downstream busses starts showing up and
the PCI core doesn't extend the subordinate bus number after initial scan
during boot.

The long term plan is to migrate this driver to the pwrctrl framework,
once it adds proper support for powering up and enumerating PCIe switches.


Changes since v1:
-Rebased against latest pci/controller/dwc
-Picked up tags.


Niklas Cassel (6):
  Revert "PCI: dw-rockchip: Don't wait for link since we can detect Link
    Up"
  Revert "PCI: dw-rockchip: Enumerate endpoints based on dll_link_up
    IRQ"
  Revert "PCI: qcom: Don't wait for link if we can detect Link Up"
  Revert "PCI: qcom: Enable MSI interrupts together with Link up if
    'Global IRQ' is supported"
  Revert "PCI: qcom: Enumerate endpoints based on Link up event in
    'global_irq' interrupt"
  Revert "PCI: dwc: Don't wait for link up if driver can detect Link Up
    event"

 .../pci/controller/dwc/pcie-designware-host.c | 10 +--
 drivers/pci/controller/dwc/pcie-designware.h  |  1 -
 drivers/pci/controller/dwc/pcie-dw-rockchip.c | 60 +-----------------
 drivers/pci/controller/dwc/pcie-qcom.c        | 63 +------------------
 4 files changed, 6 insertions(+), 128 deletions(-)


base-commit: cfd2fdfd0a8da2e5bbfdc4009b9c4b8bf164c937
-- 
2.52.0



From cassel at kernel.org  Sun Dec 21 22:42:08 2025
From: cassel at kernel.org (Niklas Cassel)
Date: Mon, 22 Dec 2025 07:42:08 +0100
Subject: [PATCH v2 1/6] Revert "PCI: dw-rockchip: Don't wait for link since we can detect Link Up"
In-Reply-To: <20251222064207.3246632-8-cassel@kernel.org>
References: <20251222064207.3246632-8-cassel@kernel.org>
Message-ID: <20251222064207.3246632-9-cassel@kernel.org>

This reverts commit ec9fd499b9c60a187ac8d6414c3c343c77d32e42.

While this fake hotplugging was a nice idea, it has shown that this feature
does not handle PCIe switches correctly:
pci_bus 0004:43: busn_res: can not insert [bus 43-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
pci_bus 0004:43: busn_res: [bus 43-41] end is updated to 43
pci_bus 0004:43: busn_res: can not insert [bus 43] under [bus 42-41] (conflicts with (null) [bus 42-41])
pci 0004:42:00.0: devices behind bridge are unusable because [bus 43] cannot be assigned for them
pci_bus 0004:44: busn_res: can not insert [bus 44-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
pci_bus 0004:44: busn_res: [bus 44-41] end is updated to 44
pci_bus 0004:44: busn_res: can not insert [bus 44] under [bus 42-41] (conflicts with (null) [bus 42-41])
pci 0004:42:02.0: devices behind bridge are unusable because [bus 44] cannot be assigned for them
pci_bus 0004:45: busn_res: can not insert [bus 45-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
pci_bus 0004:45: busn_res: [bus 45-41] end is updated to 45
pci_bus 0004:45: busn_res: can not insert [bus 45] under [bus 42-41] (conflicts with (null) [bus 42-41])
pci 0004:42:06.0: devices behind bridge are unusable because [bus 45] cannot be assigned for them
pci_bus 0004:46: busn_res: can not insert [bus 46-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
pci_bus 0004:46: busn_res: [bus 46-41] end is updated to 46
pci_bus 0004:46: busn_res: can not insert [bus 46] under [bus 42-41] (conflicts with (null) [bus 42-41])
pci 0004:42:0e.0: devices behind bridge are unusable because [bus 46] cannot be assigned for them
pci_bus 0004:42: busn_res: [bus 42-41] end is updated to 46
pci_bus 0004:42: busn_res: can not insert [bus 42-46] under [bus 41] (conflicts with (null) [bus 41])
pci 0004:41:00.0: devices behind bridge are unusable because [bus 42-46] cannot be assigned for them
pcieport 0004:40:00.0: bridge has subordinate 41 but max busn 46

During the initial scan, PCI core doesn't see the switch and since the Root
Port is not hot plug capable, the secondary bus number gets assigned as the
subordinate bus number. This means, the PCI core assumes that only one bus
will appear behind the Root Port since the Root Port is not hot plug
capable.

This works perfectly fine for PCIe endpoints connected to the Root Port,
since they don't extend the bus. However, if a PCIe switch is connected,
then there is a problem when the downstream busses starts showing up and
the PCI core doesn't extend the subordinate bus number after initial scan
during boot.

The long term plan is to migrate this driver to the pwrctrl framework,
once it adds proper support for powering up and enumerating PCIe switches.

Cc: stable at vger.kernel.org
Suggested-by: Manivannan Sadhasivam <mani at kernel.org>
Acked-by: Shawn Lin <shawn.lin at rock-chips.com>
Tested-by: Shawn Lin <shawn.lin at rock-chips.com>
Signed-off-by: Niklas Cassel <cassel at kernel.org>
---
 drivers/pci/controller/dwc/pcie-dw-rockchip.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
index 8c1c92208802..ca808d8f7975 100644
--- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c
+++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
@@ -601,7 +601,6 @@ static int rockchip_pcie_configure_rc(struct platform_device *pdev,
 
 	pp = &rockchip->pci.pp;
 	pp->ops = &rockchip_pcie_host_ops;
-	pp->use_linkup_irq = true;
 
 	ret = dw_pcie_host_init(pp);
 	if (ret) {
-- 
2.52.0



From cassel at kernel.org  Sun Dec 21 22:42:09 2025
From: cassel at kernel.org (Niklas Cassel)
Date: Mon, 22 Dec 2025 07:42:09 +0100
Subject: [PATCH v2 2/6] Revert "PCI: dw-rockchip: Enumerate endpoints based on dll_link_up IRQ"
In-Reply-To: <20251222064207.3246632-8-cassel@kernel.org>
References: <20251222064207.3246632-8-cassel@kernel.org>
Message-ID: <20251222064207.3246632-10-cassel@kernel.org>

This reverts commit 0e0b45ab5d770a748487ba0ae8f77d1fb0f0de3e.

While this fake hotplugging was a nice idea, it has shown that this feature
does not handle PCIe switches correctly:
pci_bus 0004:43: busn_res: can not insert [bus 43-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
pci_bus 0004:43: busn_res: [bus 43-41] end is updated to 43
pci_bus 0004:43: busn_res: can not insert [bus 43] under [bus 42-41] (conflicts with (null) [bus 42-41])
pci 0004:42:00.0: devices behind bridge are unusable because [bus 43] cannot be assigned for them
pci_bus 0004:44: busn_res: can not insert [bus 44-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
pci_bus 0004:44: busn_res: [bus 44-41] end is updated to 44
pci_bus 0004:44: busn_res: can not insert [bus 44] under [bus 42-41] (conflicts with (null) [bus 42-41])
pci 0004:42:02.0: devices behind bridge are unusable because [bus 44] cannot be assigned for them
pci_bus 0004:45: busn_res: can not insert [bus 45-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
pci_bus 0004:45: busn_res: [bus 45-41] end is updated to 45
pci_bus 0004:45: busn_res: can not insert [bus 45] under [bus 42-41] (conflicts with (null) [bus 42-41])
pci 0004:42:06.0: devices behind bridge are unusable because [bus 45] cannot be assigned for them
pci_bus 0004:46: busn_res: can not insert [bus 46-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
pci_bus 0004:46: busn_res: [bus 46-41] end is updated to 46
pci_bus 0004:46: busn_res: can not insert [bus 46] under [bus 42-41] (conflicts with (null) [bus 42-41])
pci 0004:42:0e.0: devices behind bridge are unusable because [bus 46] cannot be assigned for them
pci_bus 0004:42: busn_res: [bus 42-41] end is updated to 46
pci_bus 0004:42: busn_res: can not insert [bus 42-46] under [bus 41] (conflicts with (null) [bus 41])
pci 0004:41:00.0: devices behind bridge are unusable because [bus 42-46] cannot be assigned for them
pcieport 0004:40:00.0: bridge has subordinate 41 but max busn 46

During the initial scan, PCI core doesn't see the switch and since the Root
Port is not hot plug capable, the secondary bus number gets assigned as the
subordinate bus number. This means, the PCI core assumes that only one bus
will appear behind the Root Port since the Root Port is not hot plug
capable.

This works perfectly fine for PCIe endpoints connected to the Root Port,
since they don't extend the bus. However, if a PCIe switch is connected,
then there is a problem when the downstream busses starts showing up and
the PCI core doesn't extend the subordinate bus number after initial scan
during boot.

The long term plan is to migrate this driver to the pwrctrl framework,
once it adds proper support for powering up and enumerating PCIe switches.

Cc: stable at vger.kernel.org
Suggested-by: Manivannan Sadhasivam <mani at kernel.org>
Acked-by: Shawn Lin <shawn.lin at rock-chips.com>
Tested-by: Shawn Lin <shawn.lin at rock-chips.com>
Signed-off-by: Niklas Cassel <cassel at kernel.org>
---
 drivers/pci/controller/dwc/pcie-dw-rockchip.c | 59 +------------------
 1 file changed, 3 insertions(+), 56 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
index ca808d8f7975..352f513ebf03 100644
--- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c
+++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
@@ -508,34 +508,6 @@ static const struct dw_pcie_ops dw_pcie_ops = {
 	.get_ltssm = rockchip_pcie_get_ltssm,
 };
 
-static irqreturn_t rockchip_pcie_rc_sys_irq_thread(int irq, void *arg)
-{
-	struct rockchip_pcie *rockchip = arg;
-	struct dw_pcie *pci = &rockchip->pci;
-	struct dw_pcie_rp *pp = &pci->pp;
-	struct device *dev = pci->dev;
-	u32 reg;
-
-	reg = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_INTR_STATUS_MISC);
-	rockchip_pcie_writel_apb(rockchip, reg, PCIE_CLIENT_INTR_STATUS_MISC);
-
-	dev_dbg(dev, "PCIE_CLIENT_INTR_STATUS_MISC: %#x\n", reg);
-	dev_dbg(dev, "LTSSM_STATUS: %#x\n", rockchip_pcie_get_ltssm_reg(rockchip));
-
-	if (reg & PCIE_RDLH_LINK_UP_CHGED) {
-		if (rockchip_pcie_link_up(pci)) {
-			msleep(PCIE_RESET_CONFIG_WAIT_MS);
-			dev_dbg(dev, "Received Link up event. Starting enumeration!\n");
-			/* Rescan the bus to enumerate endpoint devices */
-			pci_lock_rescan_remove();
-			pci_rescan_bus(pp->bridge->bus);
-			pci_unlock_rescan_remove();
-		}
-	}
-
-	return IRQ_HANDLED;
-}
-
 static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg)
 {
 	struct rockchip_pcie *rockchip = arg;
@@ -568,29 +540,14 @@ static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg)
 	return IRQ_HANDLED;
 }
 
-static int rockchip_pcie_configure_rc(struct platform_device *pdev,
-				      struct rockchip_pcie *rockchip)
+static int rockchip_pcie_configure_rc(struct rockchip_pcie *rockchip)
 {
-	struct device *dev = &pdev->dev;
 	struct dw_pcie_rp *pp;
-	int irq, ret;
 	u32 val;
 
 	if (!IS_ENABLED(CONFIG_PCIE_ROCKCHIP_DW_HOST))
 		return -ENODEV;
 
-	irq = platform_get_irq_byname(pdev, "sys");
-	if (irq < 0)
-		return irq;
-
-	ret = devm_request_threaded_irq(dev, irq, NULL,
-					rockchip_pcie_rc_sys_irq_thread,
-					IRQF_ONESHOT, "pcie-sys-rc", rockchip);
-	if (ret) {
-		dev_err(dev, "failed to request PCIe sys IRQ\n");
-		return ret;
-	}
-
 	/* LTSSM enable control mode */
 	val = FIELD_PREP_WM16(PCIE_LTSSM_ENABLE_ENHANCE, 1);
 	rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_HOT_RESET_CTRL);
@@ -602,17 +559,7 @@ static int rockchip_pcie_configure_rc(struct platform_device *pdev,
 	pp = &rockchip->pci.pp;
 	pp->ops = &rockchip_pcie_host_ops;
 
-	ret = dw_pcie_host_init(pp);
-	if (ret) {
-		dev_err(dev, "failed to initialize host\n");
-		return ret;
-	}
-
-	/* unmask DLL up/down indicator */
-	val = FIELD_PREP_WM16(PCIE_RDLH_LINK_UP_CHGED, 0);
-	rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_INTR_MASK_MISC);
-
-	return ret;
+	return dw_pcie_host_init(pp);
 }
 
 static int rockchip_pcie_configure_ep(struct platform_device *pdev,
@@ -731,7 +678,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
 
 	switch (data->mode) {
 	case DW_PCIE_RC_TYPE:
-		ret = rockchip_pcie_configure_rc(pdev, rockchip);
+		ret = rockchip_pcie_configure_rc(rockchip);
 		if (ret)
 			goto deinit_clk;
 		break;
-- 
2.52.0



From fj1078ii at aa.jp.fujitsu.com  Sun Dec 21 22:53:34 2025
From: fj1078ii at aa.jp.fujitsu.com (Kazuhiro Abe)
Date: Mon, 22 Dec 2025 15:53:34 +0900
Subject: [PATCH v5] ACPI: AGDI: Add interrupt signaling mode support
Message-ID: <20251222065359.27330-1-fj1078ii@aa.jp.fujitsu.com>

AGDI has two types of signaling modes: SDEI and interrupt.
Currently, the AGDI driver only supports SDEI.
Therefore, add support for interrupt signaling mode.
The interrupt vector is retrieved from the AGDI table, and call panic
function when an interrupt occurs.

Acked-by: Hanjun Guo <guohanjun at huawei.com>
Reviewed-by: Ilkka Koskinen <ilkka at os.amperecomputing.com>
Signed-off-by: Kazuhiro Abe <fj1078ii at aa.jp.fujitsu.com>

---
This patch (v5) has been rebased to align with the 6.19-rc1 release.
There are no functional changes since v4.
The IRQF_NO_AUTOEN flag discussed in the v4 patch review was ultimately left unchanged.
It has been tested and confirmed to work without issues.
Please let us know if you have any questions or concerns.

v4->v5
 - Rebase to 6.19-rc1.
 - Add acked-by from Hanjun Guo.

v4: https://lore.kernel.org/all/20251017073935.1746365-1-fj1078ii at aa.jp.fujitsu.com/
v3->v4
 - Add a comment to the flags member.
 - Fix agdi_interrupt_probe.
 - Fix agdi_interrupt_remove.
 - Add space in struct initializsation.
 - Delete curly braces.

v3: https://lore.kernel.org/all/20250905042751.945616-1-fj1078ii at aa.jp.fujitsu.com/
v2->v3
 - Fix bug in the return value of agdi_probe function.
 - Remove unnecessary curly braces in the agdi_remove function.

v2: https://lore.kernel.org/all/20250829101154.2377800-1-fj1078ii at aa.jp.fujitsu.com/
v1->v2
 - Remove acpica update since there is no need to update define value
   for this patch.
---
 drivers/acpi/arm64/agdi.c | 114 +++++++++++++++++++++++++++++++++++---
 include/acpi/actbl2.h     |   4 +-
 2 files changed, 110 insertions(+), 8 deletions(-)

diff --git a/drivers/acpi/arm64/agdi.c b/drivers/acpi/arm64/agdi.c
index e0df3daa4abf..c514bb874c5d 100644
--- a/drivers/acpi/arm64/agdi.c
+++ b/drivers/acpi/arm64/agdi.c
@@ -16,7 +16,11 @@
 #include "init.h"
 
 struct agdi_data {
+	unsigned char flags;
 	int sdei_event;
+	unsigned int gsiv;
+	bool use_nmi;
+	int irq;
 };
 
 static int agdi_sdei_handler(u32 sdei_event, struct pt_regs *regs, void *arg)
@@ -48,6 +52,55 @@ static int agdi_sdei_probe(struct platform_device *pdev,
 	return 0;
 }
 
+static irqreturn_t agdi_interrupt_handler_nmi(int irq, void *dev_id)
+{
+	nmi_panic(NULL, "Arm Generic Diagnostic Dump and Reset NMI Interrupt event issued\n");
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t agdi_interrupt_handler_irq(int irq, void *dev_id)
+{
+	panic("Arm Generic Diagnostic Dump and Reset Interrupt event issued\n");
+	return IRQ_HANDLED;
+}
+
+static int agdi_interrupt_probe(struct platform_device *pdev,
+				struct agdi_data *adata)
+{
+	unsigned long irq_flags;
+	int ret;
+	int irq;
+
+	irq = acpi_register_gsi(NULL, adata->gsiv, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_HIGH);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "cannot register GSI#%d (%d)\n", adata->gsiv, irq);
+		return irq;
+	}
+
+	irq_flags = IRQF_PERCPU | IRQF_NOBALANCING | IRQF_NO_AUTOEN |
+		    IRQF_NO_THREAD;
+	/* try NMI first */
+	ret = request_nmi(irq, &agdi_interrupt_handler_nmi, irq_flags,
+			  "agdi_interrupt_nmi", NULL);
+	if (ret) {
+		ret = request_irq(irq, &agdi_interrupt_handler_irq,
+				  irq_flags, "agdi_interrupt_irq", NULL);
+		if (ret) {
+			dev_err(&pdev->dev, "cannot register IRQ %d\n", ret);
+			acpi_unregister_gsi(adata->gsiv);
+			return ret;
+		}
+		enable_irq(irq);
+		adata->irq = irq;
+	} else {
+		enable_nmi(irq);
+		adata->irq = irq;
+		adata->use_nmi = true;
+	}
+
+	return 0;
+}
+
 static int agdi_probe(struct platform_device *pdev)
 {
 	struct agdi_data *adata = dev_get_platdata(&pdev->dev);
@@ -55,12 +108,20 @@ static int agdi_probe(struct platform_device *pdev)
 	if (!adata)
 		return -EINVAL;
 
-	return agdi_sdei_probe(pdev, adata);
+	switch (adata->flags & ACPI_AGDI_SIGNALING_MODE_MASK) {
+	case ACPI_AGDI_SIGNALING_MODE_SDEI:
+		return agdi_sdei_probe(pdev, adata);
+
+	case ACPI_AGDI_SIGNALING_MODE_INTERRUPT:
+		return agdi_interrupt_probe(pdev, adata);
+	}
+
+	return 0;
 }
 
-static void agdi_remove(struct platform_device *pdev)
+static void agdi_sdei_remove(struct platform_device *pdev,
+			     struct agdi_data *adata)
 {
-	struct agdi_data *adata = dev_get_platdata(&pdev->dev);
 	int err, i;
 
 	err = sdei_event_disable(adata->sdei_event);
@@ -83,6 +144,34 @@ static void agdi_remove(struct platform_device *pdev)
 			adata->sdei_event, ERR_PTR(err));
 }
 
+static void agdi_interrupt_remove(struct platform_device *pdev,
+				  struct agdi_data *adata)
+{
+	if (adata->irq != -1) {
+		if (adata->use_nmi)
+			free_nmi(adata->irq, NULL);
+		else
+			free_irq(adata->irq, NULL);
+
+		acpi_unregister_gsi(adata->gsiv);
+	}
+}
+
+static void agdi_remove(struct platform_device *pdev)
+{
+	struct agdi_data *adata = dev_get_platdata(&pdev->dev);
+
+	switch (adata->flags & ACPI_AGDI_SIGNALING_MODE_MASK) {
+	case ACPI_AGDI_SIGNALING_MODE_SDEI:
+		agdi_sdei_remove(pdev, adata);
+		break;
+
+	case ACPI_AGDI_SIGNALING_MODE_INTERRUPT:
+		agdi_interrupt_remove(pdev, adata);
+		break;
+	}
+}
+
 static struct platform_driver agdi_driver = {
 	.driver = {
 		.name = "agdi",
@@ -94,7 +183,7 @@ static struct platform_driver agdi_driver = {
 void __init acpi_agdi_init(void)
 {
 	struct acpi_table_agdi *agdi_table;
-	struct agdi_data pdata;
+	struct agdi_data pdata = {0};
 	struct platform_device *pdev;
 	acpi_status status;
 
@@ -103,12 +192,23 @@ void __init acpi_agdi_init(void)
 	if (ACPI_FAILURE(status))
 		return;
 
-	if (agdi_table->flags & ACPI_AGDI_SIGNALING_MODE) {
-		pr_warn("Interrupt signaling is not supported");
+	switch (agdi_table->flags & ACPI_AGDI_SIGNALING_MODE_MASK) {
+	case ACPI_AGDI_SIGNALING_MODE_SDEI:
+		pdata.sdei_event = agdi_table->sdei_event;
+		break;
+
+	case ACPI_AGDI_SIGNALING_MODE_INTERRUPT:
+		pdata.gsiv = agdi_table->gsiv;
+		break;
+
+	default:
+		pr_warn("Signaling mode(%d) is not supported",
+			agdi_table->flags & ACPI_AGDI_SIGNALING_MODE_MASK);
 		goto err_put_table;
 	}
 
-	pdata.sdei_event = agdi_table->sdei_event;
+	pdata.irq = -1;
+	pdata.flags = agdi_table->flags;
 
 	pdev = platform_device_register_data(NULL, "agdi", 0, &pdata, sizeof(pdata));
 	if (IS_ERR(pdev))
diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
index f726bce3eb84..706699f3f294 100644
--- a/include/acpi/actbl2.h
+++ b/include/acpi/actbl2.h
@@ -340,7 +340,9 @@ struct acpi_table_agdi {
 
 /* Mask for Flags field above */
 
-#define ACPI_AGDI_SIGNALING_MODE (1)
+#define ACPI_AGDI_SIGNALING_MODE_MASK (3)
+#define ACPI_AGDI_SIGNALING_MODE_SDEI (0)
+#define ACPI_AGDI_SIGNALING_MODE_INTERRUPT (1)
 
 /*******************************************************************************
  *
-- 
2.43.0



From jie.gan at oss.qualcomm.com  Sun Dec 21 22:58:47 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Mon, 22 Dec 2025 14:58:47 +0800
Subject: [PATCH v8 5/8] dt-bindings: arm: add an interrupt property for
 Coresight CTCU
In-Reply-To: <95ac571a-1c8f-45d9-9874-648d4123ce18@arm.com>
References: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
 <20251211-enable-byte-cntr-for-ctcu-v8-5-3e12ff313191@oss.qualcomm.com>
 <20251211133723.GA859302-robh@kernel.org>
 <dfa43a63-ca14-4dd7-a7ab-acd95748a8b9@oss.qualcomm.com>
 <a9537dc9-c767-4909-8b1c-6e939ce4f3fc@kernel.org>
 <2db74a3e-4aeb-4e87-9fe8-5c9693bfb67c@arm.com>
 <46afd4f6-f287-4d19-bc68-f2f6eac36e6a@oss.qualcomm.com>
 <95ac571a-1c8f-45d9-9874-648d4123ce18@arm.com>
Message-ID: <097dbefb-f679-40da-bce4-d6e09dc4cf08@oss.qualcomm.com>



On 12/19/2025 5:54 PM, Suzuki K Poulose wrote:
> On 19/12/2025 02:05, Jie Gan wrote:
>>
>>
>> On 12/19/2025 7:19 AM, Suzuki K Poulose wrote:
>>> On 18/12/2025 10:17, Krzysztof Kozlowski wrote:
>>>> On 12/12/2025 02:12, Jie Gan wrote:
>>>>>
>>>>>
>>>>> On 12/11/2025 9:37 PM, Rob Herring wrote:
>>>>>> On Thu, Dec 11, 2025 at 02:10:44PM +0800, Jie Gan wrote:
>>>>>>> Add an interrupt property to CTCU device. The interrupt will be 
>>>>>>> triggered
>>>>>>> when the data size in the ETR buffer exceeds the threshold of the
>>>>>>> BYTECNTRVAL register. Programming a threshold in the BYTECNTRVAL 
>>>>>>> register
>>>>>>> of CTCU device will enable the interrupt.
>>>>>>>
>>>>>>> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
>>>>>>> Reviewed-by: Mike Leach <mike.leach at linaro.org>
>>>>>>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>>>>>>> ---
>>>>>>> ?? .../devicetree/bindings/arm/qcom,coresight-ctcu.yaml??? | 17 + 
>>>>>>> + + ++++++++++++++
>>>>>>> ?? 1 file changed, 17 insertions(+)
>>>>>>>
>>>>>>> diff --git a/Documentation/devicetree/bindings/arm/ 
>>>>>>> qcom,coresight- ctcu.yaml b/Documentation/devicetree/bindings/ 
>>>>>>> arm/qcom,coresight- ctcu.yaml
>>>>>>> index c969c16c21ef..90f88cc6cd3e 100644
>>>>>>> --- a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
>>>>>>> +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
>>>>>>> @@ -39,6 +39,16 @@ properties:
>>>>>>> ?????? items:
>>>>>>> ???????? - const: apb
>>>>>>> +? interrupts:
>>>>>>> +??? items:
>>>>>>> +????? - description: Byte cntr interrupt for the first etr device
>>>>>>> +????? - description: Byte cntr interrupt for the second etr device
>>>
>>> This is really vague. How do you define first vs second ? Probe order ?
>>> No way. This must be the "port" number to which the ETR is connected
>>> to the CTCU. IIUC, there is a config area for each ETR (e.g., trace id
>>> filter) connected to the CTCU. I was under the assumption that they
>>> are identified as "ports" (input ports). I don't really understand how
>>> this interrupt mapping works now. Please explain it clearly.
>>>
>>
>> Sorry for the misunderstanding.
>>
>> Each ETR device should have its own interrupt line and an IRQ register 
>> within the CTCU device, as defined by the specification. In existing 
>> projects, the maximum supported number of ETR devices is 2.
>>
>> Each interrupt is directly mapped to a specific ETR device, for example:
>> tmc at 1000 ? interrupt line 0
>> tmc at 1001 ? interrupt line 1
>>
>> The suggestion to identify devices by ?ports? is much clearer than my 
>> previous explanation, as it explicitly shows which device is connected 
>> to which port.
> 
> Thanks for confirming.
> 
>>
>>>>>>> +
>>>>>>> +? interrupt-names:
>>>>>>> +??? items:
>>>>>>> +????? - const: etrirq0
>>>>>>> +????? - const: etrirq1
>>>>>>
>>>>>> Names are kind of pointless when it is just foo<index>.
>>>>>
>>>>> Hi Rob,
>>>>>
>>>>> I was naming them as etr0/etr1. Are these names acceptable?
>>>>
>>>> Obviously irq is redundant, but how does etr0 solves the problem of
>>>> calling it foo0?
>>>>
>>>> I don't think you really read Rob's comment.
>>>>
>>>>> The interrupts are assigned exclusively to a specific ETR device.
>>>>>
>>>>> But Suzuki is concerned that this might cause confusion because the 
>>>>> ETR
>>>>> device is named randomly in the driver. Suzuki suggested using 
>>>>> ?port-0?
>>>>> and ?port-1? and would also like to hear your feedback on these names.
>>>>
>>>> There is no confusion here. Writing bindings luckily clarifies this 
>>>> what
>>>> the indices in the array mean.
>>>
>>> The point is there are "n" interrupts. Question is, could there be more
>>> devices(ETRs) connected to the CTCU than "n".
>>>
>>> e.g., Lets CTCU can control upto 4 ETRs and on a particular system, the
>>>
>>> TMC-ETR0 -> CTCU-Port0
>>>
>>> TMC-ETR1 -> CTCU-Port2
>>> TMC-ETR2 -> CTCU-Port3
>>>
>>> Now, how many interrupts are described in the DT ? How do we map which
>>> interrupts correspond to the CTCU-Portn. (Finding the TMC-ETRx back
>>> from the port is possible, with the topology).
>>>
>>
>> Got your point and it's much clearer.
>>
>>> This is what I raised in the previous version. Again, happy to hear
>>> if there is a standard way to describe the interrupts.
>>>
>>> Suzuki
>>>
>>>
>>>>
>>>>>
>>>>> Usually, the probe sequence follows the order of the addresses. In our
>>>>> specification, ?ETR0? is always probed before ?ETR1? because its 
>>>>> address
>>>>> is lower.
>>>>
>>>> How is this even relevant? You are answering to something completely
>>>> different, so I don't think you really tried to understand review.
>>>>
>>
>> My previous explanation was definitely unclear. As Suzuki suggested, 
>> mapping the interrupt to the port number (to identify the relevant 
>> device based on topology) makes sense and provides a much easier way 
>> to understand the relationship between the interrupt and the ETR device.
>>
>> So with the suggestion, here is the new description about the interrupts:
>>
>> ?? interrupts:
>> ???? items:
>> ?????? - description: Interrupt for the ETR device connected to in-port0.
>> ?????? - description: Interrupt for the ETR device connected to in-port1.
>>
>> ??interrupt-names:
>> ???? items:
>> ????? - const: port0
>> ????? - const: port1
> 
> Which brings us back to the question I posted in the previous version. 
> Do we really need a "name" or are there other ways to define, a sparse
> list of interrupts ?
> 

Each interrupt is dedicated to a specific ETR device. While we can 
retrieve the list of interrupts using of_irq_get, we cannot guarantee 
that the obtained interrupt corresponds to the correct ETR device?
I believe it would be better to have an interrupt-name property, so we 
can assign the name in the data structure and retrieve the interrupt by 
its name, ensuring it maps to the correct ETR device.

Thanks,
Jie




From luca.ceresoli at bootlin.com  Sun Dec 21 23:30:53 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Mon, 22 Dec 2025 08:30:53 +0100
Subject: [PATCH v3 12/22] drm/meson: encoder_hdmi: get/put the next
 bridge
In-Reply-To: <CAFBinCCUVOYsiwwVmyGtxN=MdqYatAaj-piVO9_E_iZX9gwiMQ@mail.gmail.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com> <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-12-b5165fab8058@bootlin.com> <CAFBinCCUVOYsiwwVmyGtxN=MdqYatAaj-piVO9_E_iZX9gwiMQ@mail.gmail.com>
Message-ID: <DF4KIOREQYK3.2JEGF51OECQCE@bootlin.com>

Hello Martin,

On Sun Dec 21, 2025 at 10:51 PM CET, Martin Blumenstingl wrote:
> On Tue, Dec 16, 2025 at 7:00?PM Luca Ceresoli <luca.ceresoli at bootlin.com> wrote:
>>
>> This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
>> function and stores it until driver removal. of_drm_find_bridge() is
>> deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
>> refcounted and use bridge->next_bridge to put the reference on
>> deallocation.
>>
>> Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
> Reviewed-by: Martin Blumenstingl <martin.blumenstingl at googlemail.com>
> And additionally I runtime tested this on meson-gxl-s905x-libretech-cc
> where I still have HDMI output, so:
> Tested-by: Martin Blumenstingl <martin.blumenstingl at googlemail.com>

Thank you for the quick testing!

I think I can append '# meson-gxl-s905x-libretech-cc' to your 'Tested-by:'
line when I'll apply the patch, to make it more informative.

Best regards,
Luca

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From kylehsieh1995 at gmail.com  Sun Dec 21 23:45:42 2025
From: kylehsieh1995 at gmail.com (Kyle Hsieh)
Date: Mon, 22 Dec 2025 15:45:42 +0800
Subject: [PATCH 0/2] Add Meta(Facebook) ventura2 BMC(AST2600)
Message-ID: <20251222-ventura2_initial_dts-v1-0-1f06166c78a3@gmail.com>

Summary:
Add linux device tree entry related to Meta(Facebook) ventura2.
specific devices connected to BMC(AST2600) SoC.

Signed-off-by: Kyle Hsieh <kylehsieh1995 at gmail.com>
---
Kyle Hsieh (2):
      dt-bindings: arm: aspeed: add Meta ventura2 board
      ARM: dts: aspeed: ventura2: Add Meta ventura2 BMC

 .../devicetree/bindings/arm/aspeed/aspeed.yaml     |    1 +
 arch/arm/boot/dts/aspeed/Makefile                  |    1 +
 .../dts/aspeed/aspeed-bmc-facebook-ventura2.dts    | 2950 ++++++++++++++++++++
 3 files changed, 2952 insertions(+)
---
base-commit: 9448598b22c50c8a5bb77a9103e2d49f134c9578
change-id: 20251222-ventura2_initial_dts-909b3277d665

Best regards,
-- 
Kyle Hsieh <kylehsieh1995 at gmail.com>



From kylehsieh1995 at gmail.com  Sun Dec 21 23:45:43 2025
From: kylehsieh1995 at gmail.com (Kyle Hsieh)
Date: Mon, 22 Dec 2025 15:45:43 +0800
Subject: [PATCH 1/2] dt-bindings: arm: aspeed: add Meta ventura2 board
In-Reply-To: <20251222-ventura2_initial_dts-v1-0-1f06166c78a3@gmail.com>
References: <20251222-ventura2_initial_dts-v1-0-1f06166c78a3@gmail.com>
Message-ID: <20251222-ventura2_initial_dts-v1-1-1f06166c78a3@gmail.com>

Document the new compatibles used on Facebook ventura2.

Signed-off-by: Kyle Hsieh <kylehsieh1995 at gmail.com>
---
 Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
index 9298c1a75dd1..24e19b8d108a 100644
--- a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
+++ b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
@@ -92,6 +92,7 @@ properties:
               - facebook,harma-bmc
               - facebook,minerva-cmc
               - facebook,santabarbara-bmc
+              - facebook,ventura2-bmc
               - facebook,yosemite4-bmc
               - facebook,yosemite5-bmc
               - ibm,balcones-bmc

-- 
2.34.1



From kylehsieh1995 at gmail.com  Sun Dec 21 23:45:44 2025
From: kylehsieh1995 at gmail.com (Kyle Hsieh)
Date: Mon, 22 Dec 2025 15:45:44 +0800
Subject: [PATCH 2/2] ARM: dts: aspeed: ventura2: Add Meta ventura2 BMC
In-Reply-To: <20251222-ventura2_initial_dts-v1-0-1f06166c78a3@gmail.com>
References: <20251222-ventura2_initial_dts-v1-0-1f06166c78a3@gmail.com>
Message-ID: <20251222-ventura2_initial_dts-v1-2-1f06166c78a3@gmail.com>

Add linux device tree entry related to the Meta(Facebook) rmc-node.
The system use an AT2600 BMC.
This node is named "ventura2".

Signed-off-by: Kyle Hsieh <kylehsieh1995 at gmail.com>
---
 arch/arm/boot/dts/aspeed/Makefile                  |    1 +
 .../dts/aspeed/aspeed-bmc-facebook-ventura2.dts    | 2950 ++++++++++++++++++++
 2 files changed, 2951 insertions(+)

diff --git a/arch/arm/boot/dts/aspeed/Makefile b/arch/arm/boot/dts/aspeed/Makefile
index 9adf9278dc94..6b96997629d4 100644
--- a/arch/arm/boot/dts/aspeed/Makefile
+++ b/arch/arm/boot/dts/aspeed/Makefile
@@ -32,6 +32,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \
 	aspeed-bmc-facebook-minipack.dtb \
 	aspeed-bmc-facebook-santabarbara.dtb \
 	aspeed-bmc-facebook-tiogapass.dtb \
+	aspeed-bmc-facebook-ventura2.dtb \
 	aspeed-bmc-facebook-wedge40.dtb \
 	aspeed-bmc-facebook-wedge100.dtb \
 	aspeed-bmc-facebook-wedge400-data64.dtb \
diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-ventura2.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-ventura2.dts
new file mode 100644
index 000000000000..1c8c4dc393fc
--- /dev/null
+++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-ventura2.dts
@@ -0,0 +1,2950 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2023 Facebook Inc.
+/dts-v1/;
+
+#include "aspeed-g6.dtsi"
+#include <dt-bindings/i2c/i2c.h>
+#include <dt-bindings/gpio/aspeed-gpio.h>
+
+/ {
+	model = "Facebook ventura2 RMC";
+	compatible = "facebook,ventura2-rmc", "aspeed,ast2600";
+	aliases {
+		serial4 = &uart5;
+
+		/*
+		 * i2c switch 0-0077, pca9548, 8 child channels assigned
+		 * with bus number 16-23.
+		 */
+		i2c16 = &i2c0mux0ch0;
+		i2c17 = &i2c0mux0ch1;
+		i2c18 = &i2c0mux0ch2;
+		i2c19 = &i2c0mux0ch3;
+		i2c20 = &i2c0mux0ch4;
+		i2c21 = &i2c0mux0ch5;
+		i2c22 = &i2c0mux0ch6;
+		i2c23 = &i2c0mux0ch7;
+
+		/*
+		 * i2c switch 1-0077, pca9548, 8 child channels assigned
+		 * with bus number 24-31.
+		 */
+		i2c24 = &i2c1mux0ch0;
+		i2c25 = &i2c1mux0ch1;
+		i2c26 = &i2c1mux0ch2;
+		i2c27 = &i2c1mux0ch3;
+		i2c28 = &i2c1mux0ch4;
+		i2c29 = &i2c1mux0ch5;
+		i2c30 = &i2c1mux0ch6;
+		i2c31 = &i2c1mux0ch7;
+
+		/*
+		 * i2c switch 4-0077, pca9548, 8 child channels assigned
+		 * with bus number 32-39.
+		 */
+		i2c32 = &i2c4mux0ch0;
+		i2c33 = &i2c4mux0ch1;
+		i2c34 = &i2c4mux0ch2;
+		i2c35 = &i2c4mux0ch3;
+		i2c36 = &i2c4mux0ch4;
+		i2c37 = &i2c4mux0ch5;
+		i2c38 = &i2c4mux0ch6;
+		i2c39 = &i2c4mux0ch7;
+
+		/*
+		 * i2c switch 5-0077, pca9548, 8 child channels assigned
+		 * with bus number 40-47.
+		 */
+		i2c40 = &i2c5mux0ch0;
+		i2c41 = &i2c5mux0ch1;
+		i2c42 = &i2c5mux0ch2;
+		i2c43 = &i2c5mux0ch3;
+		i2c44 = &i2c5mux0ch4;
+		i2c45 = &i2c5mux0ch5;
+		i2c46 = &i2c5mux0ch6;
+		i2c47 = &i2c5mux0ch7;
+
+		/*
+		 * i2c switch 8-0077, pca9548, 8 child channels assigned
+		 * with bus number 48-55.
+		 */
+		i2c48 = &i2c8mux0ch0;
+		i2c49 = &i2c8mux0ch1;
+		i2c50 = &i2c8mux0ch2;
+		i2c51 = &i2c8mux0ch3;
+		i2c52 = &i2c8mux0ch4;
+		i2c53 = &i2c8mux0ch5;
+		i2c54 = &i2c8mux0ch6;
+		i2c55 = &i2c8mux0ch7;
+
+		/*
+		 * i2c switch 11-0077, pca9548, 8 child channels assigned
+		 * with bus number 56-63.
+		 */
+		i2c56 = &i2c11mux0ch0;
+		i2c57 = &i2c11mux0ch1;
+		i2c58 = &i2c11mux0ch2;
+		i2c59 = &i2c11mux0ch3;
+		i2c60 = &i2c11mux0ch4;
+		i2c61 = &i2c11mux0ch5;
+		i2c62 = &i2c11mux0ch6;
+		i2c63 = &i2c11mux0ch7;
+
+		/*
+		 * i2c switch 13-0077, pca9548, 8 child channels assigned
+		 * with bus number 64-71.
+		 */
+		i2c64 = &i2c13mux0ch0;
+		i2c65 = &i2c13mux0ch1;
+		i2c66 = &i2c13mux0ch2;
+		i2c67 = &i2c13mux0ch3;
+		i2c68 = &i2c13mux0ch4;
+		i2c69 = &i2c13mux0ch5;
+		i2c70 = &i2c13mux0ch6;
+		i2c71 = &i2c13mux0ch7;
+
+		/*
+		 * i2c switch 15-0077, pca9548, 8 child channels assigned
+		 * with bus number 72-79.
+		 */
+		i2c72 = &i2c15mux0ch0;
+		i2c73 = &i2c15mux0ch1;
+		i2c74 = &i2c15mux0ch2;
+		i2c75 = &i2c15mux0ch3;
+		i2c76 = &i2c15mux0ch4;
+		i2c77 = &i2c15mux0ch5;
+		i2c78 = &i2c15mux0ch6;
+		i2c79 = &i2c15mux0ch7;
+	};
+
+	chosen {
+		stdout-path = "serial4:57600n8";
+	};
+
+	iio-hwmon {
+		compatible = "iio-hwmon";
+		io-channels = <&adc0 0>, <&adc0 1>, <&adc0 2>, <&adc0 3>,
+		<&adc0 4>, <&adc0 5>, <&adc0 6>, <&adc0 7>,
+		<&adc1 2>;
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		led-0 {
+			label = "bmc_heartbeat_amber";
+			gpios = <&gpio0 ASPEED_GPIO(P, 7) GPIO_ACTIVE_LOW>;
+			linux,default-trigger = "heartbeat";
+		};
+
+		led-1 {
+			label = "fp_id_amber";
+			default-state = "off";
+			gpios = <&gpio0 ASPEED_GPIO(B, 5) GPIO_ACTIVE_HIGH>;
+		};
+
+		led-2 {
+			label = "bmc_ready_noled";
+			default-state = "on";
+			gpios = <&gpio0 ASPEED_GPIO(B, 3) (GPIO_ACTIVE_HIGH|GPIO_TRANSITORY)>;
+		};
+
+		led-3 {
+			label = "power_blue";
+			default-state = "off";
+			gpios = <&gpio0 ASPEED_GPIO(P, 4) GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	fan_leds {
+		compatible = "gpio-leds";
+
+		led-0 {
+			label = "fcb0fan0_ledd1_blue";
+			default-state = "off";
+			gpios = <&fan_io_expander0 0 GPIO_ACTIVE_LOW>;
+		};
+
+		led-1 {
+			label = "fcb0fan1_ledd2_blue";
+			default-state = "off";
+			gpios = <&fan_io_expander0 1 GPIO_ACTIVE_LOW>;
+		};
+
+		led-2 {
+			label = "fcb0fan2_ledd3_blue";
+			default-state = "off";
+			gpios = <&fan_io_expander1 0 GPIO_ACTIVE_LOW>;
+		};
+
+		led-3 {
+			label = "fcb0fan3_ledd4_blue";
+			default-state = "off";
+			gpios = <&fan_io_expander1 1 GPIO_ACTIVE_LOW>;
+		};
+
+		led-4 {
+			label = "fcb0fan0_ledd1_amber";
+			default-state = "off";
+			gpios = <&fan_io_expander0 4 GPIO_ACTIVE_LOW>;
+		};
+
+		led-5 {
+			label = "fcb0fan1_ledd2_amber";
+			default-state = "off";
+			gpios = <&fan_io_expander0 5 GPIO_ACTIVE_LOW>;
+		};
+
+		led-6 {
+			label = "fcb0fan2_ledd3_amber";
+			default-state = "off";
+			gpios = <&fan_io_expander1 4 GPIO_ACTIVE_LOW>;
+		};
+
+		led-7 {
+			label = "fcb0fan3_ledd4_amber";
+			default-state = "off";
+			gpios = <&fan_io_expander1 5 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	memory at 80000000 {
+		device_type = "memory";
+		reg = <0x80000000 0x80000000>;
+	};
+
+	p1v8_bmc_aux: regulator-p1v8-bmc-aux {
+		compatible = "regulator-fixed";
+		regulator-name = "p1v8_bmc_aux";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-always-on;
+	};
+
+	p2v5_bmc_aux: regulator-p2v5-bmc-aux {
+		compatible = "regulator-fixed";
+		regulator-name = "p2v5_bmc_aux";
+		regulator-min-microvolt = <2500000>;
+		regulator-max-microvolt = <2500000>;
+		regulator-always-on;
+	};
+
+	p5v_dac_aux: regulator-p5v-bmc-aux {
+		compatible = "regulator-fixed";
+		regulator-name = "p5v_dac_aux";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+	};
+
+	spi1_gpio: spi {
+		compatible = "spi-gpio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		sck-gpios = <&gpio0 ASPEED_GPIO(Z, 3) GPIO_ACTIVE_HIGH>;
+		mosi-gpios = <&gpio0 ASPEED_GPIO(Z, 4) GPIO_ACTIVE_HIGH>;
+		miso-gpios = <&gpio0 ASPEED_GPIO(Z, 5) GPIO_ACTIVE_HIGH>;
+		cs-gpios = <&gpio0 ASPEED_GPIO(Z, 0) GPIO_ACTIVE_LOW>;
+		num-chipselects = <1>;
+
+		tpm at 0 {
+			compatible = "infineon,slb9670", "tcg,tpm_tis-spi";
+			spi-max-frequency = <33000000>;
+			reg = <0>;
+		};
+	};
+};
+
+&fmc {
+	status = "okay";
+	flash at 0 {
+		status = "okay";
+		m25p,fast-read;
+		label = "bmc";
+		spi-max-frequency = <50000000>;
+		#include "openbmc-flash-layout-128.dtsi"
+	};
+	flash at 1 {
+		status = "okay";
+		m25p,fast-read;
+		label = "alt-bmc";
+		spi-max-frequency = <50000000>;
+	};
+};
+
+&mdio0 {
+	status = "okay";
+};
+
+&peci0 {
+	status = "okay";
+};
+
+&mac2 {
+	status = "okay";
+	phy-mode = "rmii";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_rmii3_default>;
+	fixed-link {
+		speed = <100>;
+		full-duplex;
+	};
+};
+
+&mac3 {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_rmii4_default>;
+	use-ncsi;
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&ehci1 {
+	status = "okay";
+};
+
+&adc0 {
+	vref-supply = <&p1v8_bmc_aux>;
+	status = "okay";
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_adc0_default &pinctrl_adc1_default
+	&pinctrl_adc2_default &pinctrl_adc3_default
+	&pinctrl_adc4_default &pinctrl_adc5_default
+	&pinctrl_adc6_default &pinctrl_adc7_default>;
+};
+
+&adc1 {
+	vref-supply = <&p2v5_bmc_aux>;
+	status = "okay";
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_adc8_default &pinctrl_adc10_default>;
+};
+
+&gpio0 {
+	gpio-line-names =
+	/*A0-A7*/	"","","","","","","","",
+	/*B0-B7*/	"BATTERY_DETECT","","","BMC_READY_R",
+				"","FM_ID_LED","","",
+	/*C0-C7*/	"","","","","","","","",
+	/*D0-D7*/	"","","","","","","","",
+	/*E0-E7*/	"","","","","","","","",
+	/*F0-F7*/	"","","","","","","","",
+	/*G0-G7*/	"FM_MUX1_SEL_R","","","",
+				"","","","",
+	/*H0-H7*/	"","","","","","","","",
+	/*I0-I7*/	"","","","","","","","",
+	/*J0-J7*/	"","","","","","","","",
+	/*K0-K7*/	"","","","","","","","",
+	/*L0-L7*/	"","","","","","","","",
+	/*M0-M7*/	"","","","","","","","",
+	/*N0-N7*/	"LED_POSTCODE_0","LED_POSTCODE_1",
+				"LED_POSTCODE_2","LED_POSTCODE_3",
+				"LED_POSTCODE_4","LED_POSTCODE_5",
+				"LED_POSTCODE_6","LED_POSTCODE_7",
+	/*O0-O7*/	"","","","","","","","",
+	/*P0-P7*/	"PWR_BTN_BMC_BUF_N","","ID_RST_BTN_BMC_N","",
+				"PWR_LED","","","BMC_HEARTBEAT_N",
+	/*Q0-Q7*/	"","","","","","","","",
+	/*R0-R7*/	"","","","","","","","",
+	/*S0-S7*/	"","","","","","","","",
+	/*T0-T7*/	"","","","","","","","",
+	/*U0-U7*/	"","","","","","","","",
+	/*V0-V7*/	"","","","","","","","",
+	/*W0-W7*/	"","","","","","","","",
+	/*X0-X7*/	"","","","","","","","",
+	/*Y0-Y7*/	"","","","","","","","",
+	/*Z0-Z7*/	"","","","","","","","";
+};
+
+&gpio1 {
+	gpio-line-names =
+	/*18A0-18A7*/	"","","","","","","","",
+	/*18B0-18B7*/	"","","","",
+					"FM_BOARD_BMC_REV_ID0","FM_BOARD_BMC_REV_ID1",
+					"FM_BOARD_BMC_REV_ID2","",
+	/*18C0-18C7*/	"SPI_BMC_BIOS_ROM_IRQ0_R_N","","","","","","","",
+	/*18D0-18D7*/	"","","","","","","","",
+	/*18E0-18E3*/	"FM_BMC_PROT_LS_EN","AC_PWR_BMC_BTN_R_N","","";
+};
+
+&sgpiom0 {
+	status = "okay";
+	ngpios = <128>;
+	bus-frequency = <2000000>;
+	gpio-line-names =
+	/*"input pin","output pin"*/
+	/*A0 - A7*/
+	"power-chassis-good","FM_PLD_HEARTBEAT_LVC3_R",
+	"host0-ready","",
+	"CONTROL_VT2_SUPPLY1_CLOSE","FM_MDIO_SW_SEL_PLD",
+	"CONTROL_VT2_SUPPLY2_CLOSE","FM_88E6393X_BIN_UPDATE_EN_N",
+	"CONTROL_VT2_SUPPLY3_CLOSE","Sequence_TransFR_Alert",
+	"RETURN_CNTL1_FB","WATER_VALVE1_OPEN",
+	"RETURN_CNTL2_FB","WATER_VALVE2_OPEN",
+	"RETURN_CNTL3_FB","WATER_VALVE3_OPEN",
+	/*B0 - B7*/
+	"IT_STOP_PUMP_R_CPLD","WATER_VALVE1_CLOSE",
+	"IT_STOP_PUMP_SPARE_R_CPLD","WATER_VALVE2_CLOSE",
+	"IT_STOP_PUMP_2_R_CPLD","WATER_VALVE3_CLOSE",
+	"IT_STOP_PUMP_SPARE_2_R_CPLD","REPORT_VT2_SUPPLY1_CLOSE",
+	"RPU_2_READY_SPARE_PLD_R","REPORT_VT2_SUPPLY2_CLOSE",
+	"RPU_2_READY_PLD_R","REPORT_VT2_SUPPLY3_CLOSE",
+	"RPU_READY_SPARE_PLD_R","PCIE_SSD1_PRSNT_N",
+	"RPU_READY_PLD_R","",
+	/*C0 - C7*/
+	"IOEXP8_INT_N","",
+	"SUPPLY_CNTL1_FB","",
+	"SUPPLY_CNTL2_FB","",
+	"SUPPLY_CNTL3_FB","",
+	"PRSNT_TRAY1_TO_40_R_BUF_N","",
+	"PWRGD_TRAY1_TO_40_R_BUF","",
+	"SMALL_LEAK_TRAY1_TO_40_R_BUF_N","",
+	"LEAK_DETECT_TRAY1_TO_40_R_BUF_N","",
+	/*D0 - D7*/
+	"PRSNT_CANBUSP1_TRAY1_TO_32_N","",
+	"PWRGD_CANBUSP1_TRAY1_TO_32_PWROK","",
+	"SMALL_LEAK_CANBUSP1_TRAY1_TO_32_N","",
+	"LEAK_DETECT_CANBUSP1_TRAY1_TO_32_N","",
+	"PRSNT_CANBUSP2_TRAY1_TO_32_N","",
+	"PWRGD_CANBUSP2_TRAY1_TO_32_PWROK","",
+	"SMALL_LEAK_CANBUSP2_TRAY1_TO_32_N","",
+	"LEAK_DETECT_CANBUSP2_TRAY1_TO_32_N","",
+	/*E0 - E7*/
+	"PRSNT_CANBUSP3_TRAY1_TO_32_N","",
+	"PWRGD_CANBUSP3_TRAY1_TO_32_PWROK","",
+	"SMALL_LEAK_CANBUSP3_TRAY1_TO_32_N","",
+	"LEAK_DETECT_CANBUSP3_TRAY1_TO_32_N","",
+	"PRSNT_CANBUSP4_TRAY1_TO_32_N","",
+	"PWRGD_CANBUSP4_TRAY1_TO_32_PWROK","",
+	"SMALL_LEAK_CANBUSP4_TRAY1_TO_32_N","",
+	"LEAK_DETECT_CANBUSP4_TRAY1_TO_32_N","",
+	/*F0 - F7*/
+	"PRSNT_CANBUSP5_TRAY1_TO_32_N","",
+	"PWRGD_CANBUSP5_TRAY1_TO_32_PWROK","",
+	"SMALL_LEAK_CANBUSP5_TRAY1_TO_32_N","",
+	"LEAK_DETECT_CANBUSP5_TRAY1_TO_32_N","",
+	"PRSNT_CANBUSP6_TRAY1_TO_32_N","",
+	"PWRGD_CANBUSP6_TRAY1_TO_32_PWROK","",
+	"SMALL_LEAK_CANBUSP6_TRAY1_TO_32_N","",
+	"LEAK_DETECT_CANBUSP6_TRAY1_TO_32_N","",
+	/*G0 - G7*/
+	"PRSNT_CANBUSP7_TRAY1_TO_32_N","",
+	"PWRGD_CANBUSP7_TRAY1_TO_32_PWROK","",
+	"SMALL_LEAK_CANBUSP7_TRAY1_TO_32_N","",
+	"LEAK_DETECT_CANBUSP7_TRAY1_TO_32_N","",
+	"PRSNT_CANBUSP8_TRAY1_TO_32_N","",
+	"PWRGD_CANBUSP8_TRAY1_TO_32_PWROK","",
+	"SMALL_LEAK_CANBUSP8_TRAY1_TO_32_N","",
+	"LEAK_DETECT_CANBUSP8_TRAY1_TO_32_N","",
+	/*H0 - H7*/
+	"wCHASSIS0_LEAK_Q_N_R","",
+	"wCHASSIS1_LEAK_Q_N_R","",
+	"wCHASSIS2_LEAK_Q_N_R","",
+	"wCHASSIS3_LEAK_Q_N_R","",
+	"wCHASSIS4_LEAK_Q_N_R","",
+	"wCHASSIS5_LEAK_Q_N_R","",
+	"wCHASSIS6_LEAK_Q_N_R","",
+	"wCHASSIS7_LEAK_Q_N_R","",
+	/*I0 - I7*/
+	"wCHASSIS8_LEAK_Q_N_R","",
+	"wCHASSIS9_LEAK_Q_N_R","",
+	"wCHASSIS10_LEAK_Q_N_R","",
+	"wCHASSIS11_LEAK_Q_N_R","",
+	"wAALC_RPU_READY","",
+	"","",
+	"","",
+	"","",
+	/*J0 - J7*/
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
+	/*K0 - K7*/
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
+	/*L0 - L7*/
+	"wIT_GEAR_RPU_2_LINK_PRSNT_SPARE_N_R","",
+	"wIT_GEAR_RPU_2_LINK_PRSNT_N_R","",
+	"wIT_GEAR_RPU_LINK_PRSNT_SPARE_N_R","",
+	"wIT_GEAR_RPU_LINK_PRSNT_N_R","",
+	"","",
+	"","",
+	"","",
+	"","",
+	/*M0 - M7*/
+	"","",
+	"","",
+	"wPRSNT_SENSOR_N","",
+	"wPRSNT3_VT2_PLD_N","",
+	"wPRSNT2_VT2_PLD_N","",
+	"wPRSNT1_VT2_PLD_N","",
+	"wPRSNT3_RETURN_PLD_N","",
+	"wPRSNT2_RETURN_PLD_N","",
+	/*N0 - N7*/
+	"wPRSNT1_RETURN_PLD_N","",
+	"wPRSNT3_SUPPLY_PLD_N","",
+	"wPRSNT2_SUPPLY_PLD_N","",
+	"wPRSNT1_SUPPLY_PLD_N","",
+	"wPRSNT_LEAK11_SENSOR_R_PLD_N","",
+	"wPRSNT_LEAK10_SENSOR_R_PLD_N","",
+	"wPRSNT_LEAK9_SENSOR_R_PLD_N","",
+	"wPRSNT_LEAK8_SENSOR_R_PLD_N","",
+	/*O0 - O7*/
+	"wPRSNT_LEAK7_SENSOR_R_PLD_N","",
+	"wPRSNT_LEAK6_SENSOR_R_PLD_N","",
+	"wPRSNT_LEAK5_SENSOR_R_PLD_N","",
+	"wPRSNT_LEAK4_SENSOR_R_PLD_N","",
+	"wPRSNT_LEAK3_SENSOR_R_PLD_N","",
+	"wPRSNT_LEAK2_SENSOR_R_PLD_N","",
+	"wPRSNT_LEAK1_SENSOR_R_PLD_N","",
+	"wPRSNT_LEAK0_SENSOR_R_PLD_N","",
+	/*P0 - P7*/
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
+	"","";
+};
+
+&wdt1 {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_wdtrst1_default>;
+	aspeed,reset-type = "soc";
+	aspeed,external-signal;
+	aspeed,ext-push-pull;
+	aspeed,ext-active-high;
+	aspeed,ext-pulse-duration = <256>;
+};
+
+&i2c0 {
+	status = "okay";
+
+	i2c-mux at 77 {
+		compatible = "nxp,pca9548";
+		reg = <0x77>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		i2c0mux0ch0: i2c at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+			temp-sensor at 4c {
+				compatible = "adi,adt7461";
+				reg = <0x4c>;
+			};
+		};
+
+		i2c0mux0ch1: i2c at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+			temp-sensor at 4c {
+				compatible = "adi,adt7461";
+				reg = <0x4c>;
+			};
+		};
+
+		i2c0mux0ch2: i2c at 2 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2>;
+			status = "okay";
+		};
+
+		i2c0mux0ch3: i2c at 3 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <3>;
+			status = "okay";
+		};
+
+		i2c0mux0ch4: i2c at 4 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <4>;
+			status = "okay";
+		};
+
+		i2c0mux0ch5: i2c at 5 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <5>;
+			status = "okay";
+
+			eeprom at 56 {
+				compatible = "atmel,24c128";
+				reg = <0x56>;
+			};
+		};
+
+		i2c0mux0ch6: i2c at 6 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <6>;
+
+			eeprom at 56 {
+				compatible = "atmel,24c128";
+				reg = <0x56>;
+			};
+
+			fan_io_expander0: gpio at 20 {
+				compatible = "nxp,pca9555";
+				reg = <0x20>;
+				gpio-controller;
+				#gpio-cells = <2>;
+			};
+
+			fan_io_expander1: gpio at 21 {
+				compatible = "nxp,pca9555";
+				reg = <0x21>;
+				gpio-controller;
+				#gpio-cells = <2>;
+			};
+
+			adc at 1d {
+				compatible = "ti,adc128d818";
+				reg = <0x1d>;
+				ti,mode = /bits/ 8 <1>;
+			};
+
+			adc at 35 {
+				compatible = "maxim,max11617";
+				reg = <0x35>;
+			};
+		};
+
+		i2c0mux0ch7: i2c at 7 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <7>;
+
+			fanctl0: fan-controller at 20 {
+				compatible = "maxim,max31790";
+				reg = <0x20>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+
+			fanctl1: fan-controller at 23 {
+				compatible = "nuvoton,nct7363";
+				reg = <0x23>;
+				#pwm-cells = <2>;
+
+				fan-9 {
+					pwms = <&fanctl1 0 20000>;
+					tach-ch = /bits/ 8 <0x09>;
+				};
+
+				fan-11 {
+					pwms = <&fanctl1 0 20000>;
+					tach-ch = /bits/ 8 <0x0B>;
+				};
+
+				fan-10 {
+					pwms = <&fanctl1 4 20000>;
+					tach-ch = /bits/ 8 <0x0A>;
+				};
+
+				fan-13 {
+					pwms = <&fanctl1 4 20000>;
+					tach-ch = /bits/ 8 <0x0D>;
+				};
+
+				fan-15 {
+					pwms = <&fanctl1 6 20000>;
+					tach-ch = /bits/ 8 <0x0F>;
+				};
+
+				fan-1 {
+					pwms = <&fanctl1 6 20000>;
+					tach-ch = /bits/ 8 <0x01>;
+				};
+
+				fan-0 {
+					pwms = <&fanctl1 10 20000>;
+					tach-ch = /bits/ 8 <0x00>;
+				};
+
+				fan-3 {
+					pwms = <&fanctl1 10 20000>;
+					tach-ch = /bits/ 8 <0x03>;
+				};
+			};
+		};
+	};
+};
+
+&i2c1 {
+	status = "okay";
+
+	i2c-mux at 77 {
+		compatible = "nxp,pca9548";
+		reg = <0x77>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		i2c1mux0ch0: i2c at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+			status = "okay";
+		};
+
+		i2c1mux0ch1: i2c at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+			status = "okay";
+		};
+
+		i2c1mux0ch2: i2c at 2 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2>;
+			status = "okay";
+		};
+
+		i2c1mux0ch3: i2c at 3 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <3>;
+			status = "okay";
+		};
+
+		i2c1mux0ch4: i2c at 4 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <4>;
+			status = "okay";
+		};
+
+		i2c1mux0ch5: i2c at 5 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <5>;
+			status = "okay";
+		};
+
+		i2c1mux0ch6: i2c at 6 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <6>;
+			status = "okay";
+		};
+
+		i2c1mux0ch7: i2c at 7 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <7>;
+			status = "okay";
+		};
+	};
+};
+
+&i2c2 {
+	status = "okay";
+	bus-frequency = <400000>;
+};
+
+&i2c3 {
+	status = "okay";
+	bus-frequency = <400000>;
+
+	dac at c {
+		reg = <0x0c>;
+		compatible = "adi,ad5612";
+		vcc-supply = <&p5v_dac_aux>;
+	};
+
+	dac at e {
+		reg = <0x0e>;
+		compatible = "adi,ad5612";
+		vcc-supply = <&p5v_dac_aux>;
+	};
+
+	dac at f {
+		reg = <0x0f>;
+		compatible = "adi,ad5612";
+		vcc-supply = <&p5v_dac_aux>;
+	};
+
+	prsnt_io_expander0: gpio at 30 {
+		compatible = "nxp,pca9698";
+		reg = <0x30>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <48 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	prsnt_io_expander1: gpio at 31 {
+		compatible = "nxp,pca9698";
+		reg = <0x31>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <56 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	prsnt_io_expander2: gpio at 32 {
+		compatible = "nxp,pca9698";
+		reg = <0x32>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <64 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	prsnt_io_expander3: gpio at 33 {
+		compatible = "nxp,pca9698";
+		reg = <0x33>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <72 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	prsnt_io_expander4: gpio at 34 {
+		compatible = "nxp,pca9698";
+		reg = <0x34>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <80 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	prsnt_io_expander5: gpio at 35 {
+		compatible = "nxp,pca9698";
+		reg = <0x35>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <88 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	prsnt_io_expander6: gpio at 36 {
+		compatible = "nxp,pca9698";
+		reg = <0x36>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <96 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	prsnt_io_expander7: gpio at 37 {
+		compatible = "nxp,pca9698";
+		reg = <0x37>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <104 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	pwrgd_io_expander0: gpio at 38 {
+		compatible = "nxp,pca9698";
+		reg = <0x38>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <50 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	pwrgd_io_expander1: gpio at 39 {
+		compatible = "nxp,pca9698";
+		reg = <0x39>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <58 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	pwrgd_io_expander2: gpio at 3a {
+		compatible = "nxp,pca9698";
+		reg = <0x3a>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <66 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	pwrgd_io_expander3: gpio at 3b {
+		compatible = "nxp,pca9698";
+		reg = <0x3b>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <74 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	pwrgd_io_expander4: gpio at 3c {
+		compatible = "nxp,pca9698";
+		reg = <0x3c>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <82 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	pwrgd_io_expander5: gpio at 3d {
+		compatible = "nxp,pca9698";
+		reg = <0x3d>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <90 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	pwrgd_io_expander6: gpio at 3e {
+		compatible = "nxp,pca9698";
+		reg = <0x3e>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <98 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	pwrgd_io_expander7: gpio at 3f {
+		compatible = "nxp,pca9698";
+		reg = <0x3f>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <106 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	large_leak_io_expander0: gpio at 40 {
+		compatible = "nxp,pca9698";
+		reg = <0x40>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <54 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	large_leak_io_expander1: gpio at 41 {
+		compatible = "nxp,pca9698";
+		reg = <0x41>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <62 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	large_leak_io_expander2: gpio at 42 {
+		compatible = "nxp,pca9698";
+		reg = <0x42>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <70 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	large_leak_io_expander3: gpio at 43 {
+		compatible = "nxp,pca9698";
+		reg = <0x43>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <78 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	large_leak_io_expander4: gpio at 44 {
+		compatible = "nxp,pca9698";
+		reg = <0x44>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <86 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	large_leak_io_expander5: gpio at 45 {
+		compatible = "nxp,pca9698";
+		reg = <0x45>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <94 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	large_leak_io_expander6: gpio at 46 {
+		compatible = "nxp,pca9698";
+		reg = <0x46>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <102 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	large_leak_io_expander7: gpio at 47 {
+		compatible = "nxp,pca9698";
+		reg = <0x47>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <110 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	small_leak_io_expander0: gpio at 48 {
+		compatible = "nxp,pca9698";
+		reg = <0x48>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <52 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	small_leak_io_expander1: gpio at 49 {
+		compatible = "nxp,pca9698";
+		reg = <0x49>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <60 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	small_leak_io_expander2: gpio at 4a {
+		compatible = "nxp,pca9698";
+		reg = <0x4a>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <68 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	small_leak_io_expander3: gpio at 4b {
+		compatible = "nxp,pca9698";
+		reg = <0x4b>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <76 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	small_leak_io_expander4: gpio at 4c {
+		compatible = "nxp,pca9698";
+		reg = <0x4c>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <84 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	small_leak_io_expander5: gpio at 4d {
+		compatible = "nxp,pca9698";
+		reg = <0x4d>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <92 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	small_leak_io_expander6: gpio at 4e {
+		compatible = "nxp,pca9698";
+		reg = <0x4e>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <100 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	small_leak_io_expander7: gpio at 4f {
+		compatible = "nxp,pca9698";
+		reg = <0x4f>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <108 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	io_expander6: gpio at 23 {
+		compatible = "nxp,pca9555";
+		reg = <0x23>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+};
+
+&i2c4 {
+	status = "okay";
+
+	i2c-mux at 77 {
+		compatible = "nxp,pca9548";
+		reg = <0x77>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		i2c4mux0ch0: i2c at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			io_expander3: gpio at 23 {
+				compatible = "nxp,pca9555";
+				reg = <0x23>;
+				gpio-controller;
+				#gpio-cells = <2>;
+			};
+		};
+
+		i2c4mux0ch1: i2c at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			temp-sensor at 48 {
+				compatible = "ti,tmp75";
+				reg = <0x48>;
+			};
+
+			temp-sensor at 4a {
+				compatible = "ti,tmp75";
+				reg = <0x4a>;
+			};
+
+			eeprom at 56 {
+				compatible = "atmel,24c128";
+				reg = <0x56>;
+			};
+
+			power-monitor at 76 {
+				compatible = "infineon,xdpe15284";
+				reg = <0x76>;
+			};
+		};
+
+		i2c4mux0ch2: i2c at 2 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2>;
+			status = "okay";
+		};
+
+		i2c4mux0ch3: i2c at 3 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <3>;
+			status = "okay";
+		};
+
+		i2c4mux0ch4: i2c at 4 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <4>;
+			status = "okay";
+		};
+
+		i2c4mux0ch5: i2c at 5 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <5>;
+			status = "okay";
+		};
+
+		i2c4mux0ch6: i2c at 6 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <6>;
+			status = "okay";
+		};
+
+		i2c4mux0ch7: i2c at 7 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <7>;
+			status = "okay";
+		};
+	};
+};
+
+&i2c5 {
+	status = "okay";
+
+	io_expander4: gpio at 22 {
+		compatible = "nxp,pca9555";
+		reg = <0x22>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	io_expander5: gpio at 23 {
+		compatible = "nxp,pca9555";
+		reg = <0x23>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	temp-sensor at 4f {
+		compatible = "ti,tmp75";
+		reg = <0x4f>;
+	};
+
+	eeprom at 54 {
+		compatible = "atmel,24c128";
+		reg = <0x54>;
+	};
+
+	i2c-mux at 77 {
+		compatible = "nxp,pca9548";
+		reg = <0x77>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		i2c5mux0ch0: i2c at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+		};
+
+		i2c5mux0ch1: i2c at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+		};
+
+		i2c5mux0ch2: i2c at 2 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2>;
+
+			eeprom at 56 {
+				compatible = "atmel,24c128";
+				reg = <0x56>;
+			};
+		};
+
+		i2c5mux0ch3: i2c at 3 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <3>;
+
+			eeprom at 56 {
+				compatible = "atmel,24c128";
+				reg = <0x56>;
+			};
+		};
+
+		i2c5mux0ch4: i2c at 4 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <4>;
+
+			eeprom at 56 {
+				compatible = "atmel,24c128";
+				reg = <0x56>;
+			};
+		};
+
+		i2c5mux0ch5: i2c at 5 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <5>;
+
+			eeprom at 56 {
+				compatible = "atmel,24c128";
+				reg = <0x56>;
+			};
+		};
+
+		i2c5mux0ch6: i2c at 6 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <6>;
+
+			eeprom at 56 {
+				compatible = "atmel,24c128";
+				reg = <0x56>;
+			};
+		};
+
+		i2c5mux0ch7: i2c at 7 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <7>;
+
+			eeprom at 56 {
+				compatible = "atmel,24c128";
+				reg = <0x56>;
+			};
+		};
+	};
+};
+
+&i2c6 {
+	status = "okay";
+
+	eeprom at 50 {
+		compatible = "atmel,24c64";
+		reg = <0x50>;
+	};
+
+	io_expander0: gpio at 20 {
+		compatible = "nxp,pca9555";
+		reg = <0x20>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	io_expander1: gpio at 21 {
+		compatible = "nxp,pca9555";
+		reg = <0x21>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	io_expander2: gpio at 22 {
+		compatible = "nxp,pca9555";
+		reg = <0x22>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	io_expander7: gpio at 23 {
+		compatible = "nxp,pca9555";
+		reg = <0x23>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	rtc at 51 {
+		compatible = "nxp,pcf8563";
+		reg = <0x51>;
+	};
+};
+
+&i2c7 {
+	status = "okay";
+	bus-frequency = <100000>;
+	multi-master;
+	aspeed,hw-timeout-ms = <1000>;
+
+	ipmb at 10 {
+		compatible = "ipmb-dev";
+		reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>;
+		i2c-protocol;
+	};
+};
+
+&i2c8 {
+	status = "okay";
+
+	i2c-mux at 77 {
+		compatible = "nxp,pca9548";
+		reg = <0x77>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		i2c8mux0ch0: i2c at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+			status = "okay";
+		};
+
+		i2c8mux0ch1: i2c at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+			status = "okay";
+		};
+
+		i2c8mux0ch2: i2c at 2 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2>;
+			status = "okay";
+		};
+
+		i2c8mux0ch3: i2c at 3 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <3>;
+			status = "okay";
+		};
+
+		i2c8mux0ch4: i2c at 4 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <4>;
+			status = "okay";
+		};
+
+		i2c8mux0ch5: i2c at 5 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <5>;
+			status = "okay";
+		};
+
+		i2c8mux0ch6: i2c at 6 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <6>;
+			status = "okay";
+		};
+
+		i2c8mux0ch7: i2c at 7 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <7>;
+			status = "okay";
+		};
+	};
+};
+
+&i2c9 {
+	status = "okay";
+
+	temperature-sensor at 4b {
+		compatible = "ti,tmp75";
+		reg = <0x4b>;
+	};
+
+	eeprom at 50 {
+		compatible = "atmel,24c128";
+		reg = <0x50>;
+	};
+
+	eeprom at 51 {
+		compatible = "atmel,24c128";
+		reg = <0x51>;
+	};
+
+	eeprom at 56 {
+		compatible = "atmel,24c64";
+		reg = <0x56>;
+	};
+};
+
+&i2c10 {
+	status = "okay";
+
+	power-sensor at 41 {
+		compatible = "ti,ina238";
+		reg = <0x41>;
+		shunt-resistor = <20000>;
+	};
+
+	power-sensor at 42 {
+		compatible = "ti,ina238";
+		reg = <0x42>;
+		shunt-resistor = <1000>;
+	};
+
+	power-sensor at 43 {
+		compatible = "ti,ina238";
+		reg = <0x43>;
+		shunt-resistor = <20000>;
+	};
+
+	power-sensor at 46 {
+		compatible = "ti,ina238";
+		reg = <0x46>;
+		shunt-resistor = <1000>;
+	};
+
+	adc at 35 {
+		compatible = "maxim,max11617";
+		reg = <0x35>;
+	};
+
+	power-monitor at 14 {
+		compatible = "infineon,xdp710";
+		reg = <0x14>;
+	};
+
+	power-monitor at 44 {
+		compatible = "lltc,ltc4287";
+		reg = <0x44>;
+	};
+
+	power-monitor at 40 {
+		compatible = "ti,ina230";
+		reg = <0x40>;
+		shunt-resistor = <1000>;
+	};
+
+	power-monitor at 45 {
+		compatible = "ti,ina230";
+		reg = <0x45>;
+		shunt-resistor = <1000>;
+	};
+
+	adc at 48 {
+		compatible = "ti,ads1015";
+		reg = <0x48>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
+
+	power-monitor at 69 {
+		compatible = "pmbus";
+		reg = <0x69>;
+	};
+
+	temp-sensor at 4d {
+		compatible = "ti,tmp75";
+		reg = <0x4d>;
+	};
+
+	temp-sensor at 4c {
+		compatible = "ti,tmp75";
+		reg = <0x4c>;
+	};
+
+	temp-sensor at 4e {
+		compatible = "ti,tmp75";
+		reg = <0x4e>;
+	};
+
+	legacy_prsnt_io_expander0: gpio at 11 {
+		compatible = "nxp,pca9555";
+		reg = <0x11>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <40 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	legacy_prsnt_io_expander1: gpio at 12 {
+		compatible = "nxp,pca9555";
+		reg = <0x12>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <40 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	legacy_prsnt_io_expander2: gpio at 13 {
+		compatible = "nxp,pca9555";
+		reg = <0x13>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <40 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	legacy_pwrgd_io_expander0: gpio at 28 {
+		compatible = "nxp,pca9555";
+		reg = <0x28>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	legacy_pwrgd_io_expander1: gpio at 15 {
+		compatible = "nxp,pca9555";
+		reg = <0x15>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	legacy_pwrgd_io_expander2: gpio at 16 {
+		compatible = "nxp,pca9555";
+		reg = <0x16>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	legacy_leak_io_expander0: gpio at 17 {
+		compatible = "nxp,pca9555";
+		reg = <0x17>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <46 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	legacy_leak_io_expander1: gpio at 18 {
+		compatible = "nxp,pca9555";
+		reg = <0x18>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <46 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	legacy_leak_io_expander2: gpio at 19 {
+		compatible = "nxp,pca9555";
+		reg = <0x19>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <46 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	legacy_small_leak_io_expander0: gpio at 1a {
+		compatible = "nxp,pca9555";
+		reg = <0x1a>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <44 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	legacy_small_leak_io_expander1: gpio at 1b {
+		compatible = "nxp,pca9555";
+		reg = <0x1b>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <44 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	legacy_small_leak_io_expander2: gpio at 1c {
+		compatible = "nxp,pca9555";
+		reg = <0x1c>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <44 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	sku_info_io_expander: gpio at 61 {
+		compatible = "nxp,pca9555";
+		reg = <0x61>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	fpga_io_expander64: gpio at 64 {
+		compatible = "nxp,pca9555";
+		reg = <0x64>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	fpga_io_expander65: gpio at 65 {
+		compatible = "nxp,pca9555";
+		reg = <0x65>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+};
+
+&i2c11 {
+	status = "okay";
+
+	i2c-mux at 77 {
+		compatible = "nxp,pca9548";
+		reg = <0x77>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		i2c11mux0ch0: i2c at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+			status = "okay";
+		};
+
+		i2c11mux0ch1: i2c at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+			status = "okay";
+		};
+
+		i2c11mux0ch2: i2c at 2 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2>;
+			status = "okay";
+		};
+
+		i2c11mux0ch3: i2c at 3 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <3>;
+			status = "okay";
+		};
+
+		i2c11mux0ch4: i2c at 4 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <4>;
+			status = "okay";
+		};
+
+		i2c11mux0ch5: i2c at 5 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <5>;
+			status = "okay";
+		};
+
+		i2c11mux0ch6: i2c at 6 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <6>;
+			status = "okay";
+		};
+
+		i2c11mux0ch7: i2c at 7 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <7>;
+			status = "okay";
+		};
+	};
+};
+
+&i2c12 {
+	status = "okay";
+	bus-frequency = <400000>;
+};
+
+&i2c13 {
+	status = "okay";
+
+	i2c-mux at 77 {
+		compatible = "nxp,pca9548";
+		reg = <0x77>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		i2c13mux0ch0: i2c at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+			status = "okay";
+		};
+
+		i2c13mux0ch1: i2c at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+			status = "okay";
+		};
+
+		i2c13mux0ch2: i2c at 2 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2>;
+			status = "okay";
+		};
+
+		i2c13mux0ch3: i2c at 3 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <3>;
+			status = "okay";
+		};
+
+		i2c13mux0ch4: i2c at 4 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <4>;
+			status = "okay";
+		};
+
+		i2c13mux0ch5: i2c at 5 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <5>;
+			status = "okay";
+		};
+
+		i2c13mux0ch6: i2c at 6 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <6>;
+			status = "okay";
+		};
+
+		i2c13mux0ch7: i2c at 7 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <7>;
+			status = "okay";
+		};
+	};
+};
+
+&i2c14 {
+	status = "okay";
+};
+
+&i2c15 {
+	status = "okay";
+
+	i2c-mux at 77 {
+		compatible = "nxp,pca9548";
+		reg = <0x77>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		i2c15mux0ch0: i2c at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+			status = "okay";
+		};
+
+		i2c15mux0ch1: i2c at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+			status = "okay";
+		};
+
+		i2c15mux0ch2: i2c at 2 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2>;
+			status = "okay";
+		};
+
+		i2c15mux0ch3: i2c at 3 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <3>;
+			status = "okay";
+		};
+
+		i2c15mux0ch4: i2c at 4 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <4>;
+			status = "okay";
+		};
+
+		i2c15mux0ch5: i2c at 5 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <5>;
+			status = "okay";
+		};
+
+		i2c15mux0ch6: i2c at 6 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <6>;
+			status = "okay";
+		};
+
+		i2c15mux0ch7: i2c at 7 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <7>;
+			status = "okay";
+		};
+	};
+};
+
+&spi2 {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_spi2_default>;
+
+	flash at 0 {
+		status = "okay";
+		m25p,fast-read;
+		label = "pnor";
+		spi-max-frequency = <12000000>;
+		spi-tx-bus-width = <2>;
+		spi-rx-bus-width = <2>;
+	};
+};
+
+&io_expander0 {
+	gpio-line-names =
+	"RST_POE_BMC_N", "POE_DISABLE_BMC_N_R",
+	"RST_FT4232_1_BMC_N_R", "RST_FT4232_2_BMC_N_R",
+	"RST_FT4232_3_BMC_N_R", "PRSNT_FANBP_0_PWR_N",
+	"PRSNT_FANBP_0_SIG_N", "PRSNT_POE_PWR_N",
+	"PRSNT_POE_SIG_N", "IRQ_POE_BMC_N_R",
+	"PWRGD_P3V3_ISO_POE_BMC_R", "88E6393X_INT_N_R",
+	"P48V_HSC_ALERT_N", "SMB_TMC75_TEMP_ALERT_N_R",
+	"DEV_DIS_N", "PCI_DIS_N";
+};
+
+&io_expander1 {
+	gpio-line-names =
+	"PWRGD_CPU_LVC3_BMC", "R_FM_BIOS_POST_CMPLT_BMC",
+	"RSVD_GPIO_BMC_B16_R", "",
+	"R_FM_CPU_ERR1_LVT3_L", "R_FM_CPU_ERR2_LVT3_L",
+	"", "ISO_FM_BMC_ONCTL_L",
+	"R_COME_THERM_L", "BMC_RST_BTN_N",
+	"", "PCIE_SSD1_PRSNT_N",
+	"", "wTRAY_PWRGD23_N_BUF_R",
+	"wTRAY_PWRGD24_N_BUF_R", "wTRAY_PWRGD29_N_BUF_R";
+};
+
+&io_expander2 {
+	gpio-line-names =
+	"BOARD_ID_0", "BOARD_ID_1",
+	"BOARD_ID_2", "BOARD_ID_3",
+	"SKU_ID_3", "SKU_ID_2",
+	"SKU_ID_1", "SKU_ID_0",
+	"FT4232_1_SUSPEND_BMC_N", "FT4232_1_PWREN_BMC_N",
+	"FT4232_2_SUSPEND_BMC_N", "FT4232_2_PWREN_BMC_N",
+	"FT4232_3_SUSPEND_BMC_N", "FT4232_3_PWREN_BMC_N",
+	"P12V_AUX_SMBALERT_R", "P52V_SENSE_ALERT";
+};
+
+&io_expander3 {
+	gpio-line-names =
+	"RSVD_GPIO_BMC_A12_R", "RSVD_GPIO_BMC_E14_R",
+	"", "RST_I2CRST_MUX1_N",
+	"RST_I2CRST_MUX2_N", "RST_I2CRST_MUX3_N",
+	"RST_I2CRST_MUX4_N", "RST_I2CRST_MUX5_N",
+	"RST_I2CRST_MUX6_N", "RST_I2CRST_MUX7_N",
+	"RST_I2CRST_MUX8_N", "P24V_EFUSE9_FAULT",
+	"wTRAY_PWRGD30_N_BUF_R", "wTRAY_PWRGD31_N_BUF_R",
+	"wTRAY_PWRGD32_N_BUF_R", "wTRAY_PWRGD37_N_BUF_R";
+};
+
+&io_expander4 {
+	gpio-line-names =
+	"R_COME_THERMTRIP_L", "R_PWRGD_PCH_PWROK",
+	"PWRGD_P3V3_STBY_D2", "R_H_MEMHOT_OUT_FET_L",
+	"", "R_FM_SOC_BMC_RST_L",
+	"", "R_FM_PCHHOT_L",
+	"R_FM_CPU_ERR0_LVT3_L", "FM_CPU_DIMM_EVENT_COD_BUF",
+	"R_ISO_FM_USB_OC0_L", "BIOS_DEBUG_MSG_DIS_L",
+	"R_IRQ_BMC_PCH_SMI_N", "wTRAY_PWRGD38_N_BUF_R",
+	"wTRAY_PWRGD39_N_BUF_R", "wTRAY_PWRGD40_N_BUF_R";
+};
+
+&io_expander5 {
+	gpio-line-names =
+	"PWRGD_P5V_AUX_R2", "",
+	"PWRGD_P1V5_AUX_R", "PWRGD_P1V05_AUX_R",
+	"PWRGD_P52V_HSC_PWROK_R", "PWRGD_P24V_AUX_2_R",
+	"PWRGD_P24V_AUX_R", "PWRGD_P12V_AUX_R2",
+	"PWRGD_P12V_SCM_R", "P24V_AUX_INA230_ALERT_N_R",
+	"P24V_AUX_2_INA230_ALERT_N_R", "PRSNT_CAN1_MCIO_N",
+	"PRSNT_CAN2_MCIO_N", "PRSNT_AALC_MCIO_N",
+	"PRSNT_RACKMON_MCIO_N", "PRSNT_RIO_RACKMON_N";
+};
+
+
+&io_expander6 {
+	gpio-line-names =
+	"P24V_EFUSE1_FAULT", "P24V_EFUSE2_FAULT",
+	"P24V_EFUSE3_FAULT", "P24V_EFUSE4_FAULT",
+	"P24V_EFUSE5_FAULT", "P24V_EFUSE6_FAULT",
+	"TEMP1_ALERT_N_R", "TEMP2_ALERT_N_R",
+	"RST_FT2232_N", "PRSNT_COME_N",
+	"FM_COME_BMC_RM_DEBUG_EN", "SMB_TMC75_TEMP2_ALERT_N_R",
+	"SMB_TMC75_TEMP3_ALERT_N_R", "SMB_TMC75_TEMP4_ALERT_N_R",
+	"P24V_EFUSE7_FAULT", "P24V_EFUSE8_FAULT";
+};
+
+&io_expander7 {
+	gpio-line-names =
+	"IOEXP1_INT_N", "IOEXP2_INT_N",
+	"IOEXP3_INT_N", "IOEXP4_INT_N",
+	"IOEXP5_INT_N", "IOEXP6_INT_N",
+	"IOEXP7_INT_N", "",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&prsnt_io_expander0 {
+	gpio-line-names =
+	"CAN1_TRAY1_PRSNT", "CAN1_TRAY2_PRSNT",
+	"CAN1_TRAY3_PRSNT", "CAN1_TRAY4_PRSNT",
+	"CAN1_TRAY5_PRSNT", "CAN1_TRAY6_PRSNT",
+	"CAN1_TRAY7_PRSNT", "CAN1_TRAY8_PRSNT",
+	"CAN1_TRAY9_PRSNT", "CAN1_TRAY10_PRSNT",
+	"CAN1_TRAY11_PRSNT", "CAN1_TRAY12_PRSNT",
+	"CAN1_TRAY13_PRSNT", "CAN1_TRAY14_PRSNT",
+	"CAN1_TRAY15_PRSNT", "CAN1_TRAY16_PRSNT",
+	"CAN1_TRAY17_PRSNT", "CAN1_TRAY18_PRSNT",
+	"CAN1_TRAY19_PRSNT", "CAN1_TRAY20_PRSNT",
+	"CAN1_TRAY21_PRSNT", "CAN1_TRAY22_PRSNT",
+	"CAN1_TRAY23_PRSNT", "CAN1_TRAY24_PRSNT",
+	"CAN1_TRAY25_PRSNT", "CAN1_TRAY26_PRSNT",
+	"CAN1_TRAY27_PRSNT", "CAN1_TRAY28_PRSNT",
+	"CAN1_TRAY29_PRSNT", "CAN1_TRAY30_PRSNT",
+	"CAN1_TRAY31_PRSNT", "CAN1_TRAY32_PRSNT",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&prsnt_io_expander1 {
+	gpio-line-names =
+	"CAN2_TRAY1_PRSNT", "CAN2_TRAY2_PRSNT",
+	"CAN2_TRAY3_PRSNT", "CAN2_TRAY4_PRSNT",
+	"CAN2_TRAY5_PRSNT", "CAN2_TRAY6_PRSNT",
+	"CAN2_TRAY7_PRSNT", "CAN2_TRAY8_PRSNT",
+	"CAN2_TRAY9_PRSNT", "CAN2_TRAY10_PRSNT",
+	"CAN2_TRAY11_PRSNT", "CAN2_TRAY12_PRSNT",
+	"CAN2_TRAY13_PRSNT", "CAN2_TRAY14_PRSNT",
+	"CAN2_TRAY15_PRSNT", "CAN2_TRAY16_PRSNT",
+	"CAN2_TRAY17_PRSNT", "CAN2_TRAY18_PRSNT",
+	"CAN2_TRAY19_PRSNT", "CAN2_TRAY20_PRSNT",
+	"CAN2_TRAY21_PRSNT", "CAN2_TRAY22_PRSNT",
+	"CAN2_TRAY23_PRSNT", "CAN2_TRAY24_PRSNT",
+	"CAN2_TRAY25_PRSNT", "CAN2_TRAY26_PRSNT",
+	"CAN2_TRAY27_PRSNT", "CAN2_TRAY28_PRSNT",
+	"CAN2_TRAY29_PRSNT", "CAN2_TRAY30_PRSNT",
+	"CAN2_TRAY31_PRSNT", "CAN2_TRAY32_PRSNT",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&prsnt_io_expander2 {
+	gpio-line-names =
+	"CAN3_TRAY1_PRSNT", "CAN3_TRAY2_PRSNT",
+	"CAN3_TRAY3_PRSNT", "CAN3_TRAY4_PRSNT",
+	"CAN3_TRAY5_PRSNT", "CAN3_TRAY6_PRSNT",
+	"CAN3_TRAY7_PRSNT", "CAN3_TRAY8_PRSNT",
+	"CAN3_TRAY9_PRSNT", "CAN3_TRAY10_PRSNT",
+	"CAN3_TRAY11_PRSNT", "CAN3_TRAY12_PRSNT",
+	"CAN3_TRAY13_PRSNT", "CAN3_TRAY14_PRSNT",
+	"CAN3_TRAY15_PRSNT", "CAN3_TRAY16_PRSNT",
+	"CAN3_TRAY17_PRSNT", "CAN3_TRAY18_PRSNT",
+	"CAN3_TRAY19_PRSNT", "CAN3_TRAY20_PRSNT",
+	"CAN3_TRAY21_PRSNT", "CAN3_TRAY22_PRSNT",
+	"CAN3_TRAY23_PRSNT", "CAN3_TRAY24_PRSNT",
+	"CAN3_TRAY25_PRSNT", "CAN3_TRAY26_PRSNT",
+	"CAN3_TRAY27_PRSNT", "CAN3_TRAY28_PRSNT",
+	"CAN3_TRAY29_PRSNT", "CAN3_TRAY30_PRSNT",
+	"CAN3_TRAY31_PRSNT", "CAN3_TRAY32_PRSNT",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&prsnt_io_expander3 {
+	gpio-line-names =
+	"CAN4_TRAY1_PRSNT", "CAN4_TRAY2_PRSNT",
+	"CAN4_TRAY3_PRSNT", "CAN4_TRAY4_PRSNT",
+	"CAN4_TRAY5_PRSNT", "CAN4_TRAY6_PRSNT",
+	"CAN4_TRAY7_PRSNT", "CAN4_TRAY8_PRSNT",
+	"CAN4_TRAY9_PRSNT", "CAN4_TRAY10_PRSNT",
+	"CAN4_TRAY11_PRSNT", "CAN4_TRAY12_PRSNT",
+	"CAN4_TRAY13_PRSNT", "CAN4_TRAY14_PRSNT",
+	"CAN4_TRAY15_PRSNT", "CAN4_TRAY16_PRSNT",
+	"CAN4_TRAY17_PRSNT", "CAN4_TRAY18_PRSNT",
+	"CAN4_TRAY19_PRSNT", "CAN4_TRAY20_PRSNT",
+	"CAN4_TRAY21_PRSNT", "CAN4_TRAY22_PRSNT",
+	"CAN4_TRAY23_PRSNT", "CAN4_TRAY24_PRSNT",
+	"CAN4_TRAY25_PRSNT", "CAN4_TRAY26_PRSNT",
+	"CAN4_TRAY27_PRSNT", "CAN4_TRAY28_PRSNT",
+	"CAN4_TRAY29_PRSNT", "CAN4_TRAY30_PRSNT",
+	"CAN4_TRAY31_PRSNT", "CAN4_TRAY32_PRSNT",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&prsnt_io_expander4 {
+	gpio-line-names =
+	"CAN5_TRAY1_PRSNT", "CAN5_TRAY2_PRSNT",
+	"CAN5_TRAY3_PRSNT", "CAN5_TRAY4_PRSNT",
+	"CAN5_TRAY5_PRSNT", "CAN5_TRAY6_PRSNT",
+	"CAN5_TRAY7_PRSNT", "CAN5_TRAY8_PRSNT",
+	"CAN5_TRAY9_PRSNT", "CAN5_TRAY10_PRSNT",
+	"CAN5_TRAY11_PRSNT", "CAN5_TRAY12_PRSNT",
+	"CAN5_TRAY13_PRSNT", "CAN5_TRAY14_PRSNT",
+	"CAN5_TRAY15_PRSNT", "CAN5_TRAY16_PRSNT",
+	"CAN5_TRAY17_PRSNT", "CAN5_TRAY18_PRSNT",
+	"CAN5_TRAY19_PRSNT", "CAN5_TRAY20_PRSNT",
+	"CAN5_TRAY21_PRSNT", "CAN5_TRAY22_PRSNT",
+	"CAN5_TRAY23_PRSNT", "CAN5_TRAY24_PRSNT",
+	"CAN5_TRAY25_PRSNT", "CAN5_TRAY26_PRSNT",
+	"CAN5_TRAY27_PRSNT", "CAN5_TRAY28_PRSNT",
+	"CAN5_TRAY29_PRSNT", "CAN5_TRAY30_PRSNT",
+	"CAN5_TRAY31_PRSNT", "CAN5_TRAY32_PRSNT",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&prsnt_io_expander5 {
+	gpio-line-names =
+	"CAN6_TRAY1_PRSNT", "CAN6_TRAY2_PRSNT",
+	"CAN6_TRAY3_PRSNT", "CAN6_TRAY4_PRSNT",
+	"CAN6_TRAY5_PRSNT", "CAN6_TRAY6_PRSNT",
+	"CAN6_TRAY7_PRSNT", "CAN6_TRAY8_PRSNT",
+	"CAN6_TRAY9_PRSNT", "CAN6_TRAY10_PRSNT",
+	"CAN6_TRAY11_PRSNT", "CAN6_TRAY12_PRSNT",
+	"CAN6_TRAY13_PRSNT", "CAN6_TRAY14_PRSNT",
+	"CAN6_TRAY15_PRSNT", "CAN6_TRAY16_PRSNT",
+	"CAN6_TRAY17_PRSNT", "CAN6_TRAY18_PRSNT",
+	"CAN6_TRAY19_PRSNT", "CAN6_TRAY20_PRSNT",
+	"CAN6_TRAY21_PRSNT", "CAN6_TRAY22_PRSNT",
+	"CAN6_TRAY23_PRSNT", "CAN6_TRAY24_PRSNT",
+	"CAN6_TRAY25_PRSNT", "CAN6_TRAY26_PRSNT",
+	"CAN6_TRAY27_PRSNT", "CAN6_TRAY28_PRSNT",
+	"CAN6_TRAY29_PRSNT", "CAN6_TRAY30_PRSNT",
+	"CAN6_TRAY31_PRSNT", "CAN6_TRAY32_PRSNT",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&prsnt_io_expander6 {
+	gpio-line-names =
+	"CAN7_TRAY1_PRSNT", "CAN7_TRAY2_PRSNT",
+	"CAN7_TRAY3_PRSNT", "CAN7_TRAY4_PRSNT",
+	"CAN7_TRAY5_PRSNT", "CAN7_TRAY6_PRSNT",
+	"CAN7_TRAY7_PRSNT", "CAN7_TRAY8_PRSNT",
+	"CAN7_TRAY9_PRSNT", "CAN7_TRAY10_PRSNT",
+	"CAN7_TRAY11_PRSNT", "CAN7_TRAY12_PRSNT",
+	"CAN7_TRAY13_PRSNT", "CAN7_TRAY14_PRSNT",
+	"CAN7_TRAY15_PRSNT", "CAN7_TRAY16_PRSNT",
+	"CAN7_TRAY17_PRSNT", "CAN7_TRAY18_PRSNT",
+	"CAN7_TRAY19_PRSNT", "CAN7_TRAY20_PRSNT",
+	"CAN7_TRAY21_PRSNT", "CAN7_TRAY22_PRSNT",
+	"CAN7_TRAY23_PRSNT", "CAN7_TRAY24_PRSNT",
+	"CAN7_TRAY25_PRSNT", "CAN7_TRAY26_PRSNT",
+	"CAN7_TRAY27_PRSNT", "CAN7_TRAY28_PRSNT",
+	"CAN7_TRAY29_PRSNT", "CAN7_TRAY30_PRSNT",
+	"CAN7_TRAY31_PRSNT", "CAN7_TRAY32_PRSNT",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&prsnt_io_expander7 {
+	gpio-line-names =
+	"CAN8_TRAY1_PRSNT", "CAN8_TRAY2_PRSNT",
+	"CAN8_TRAY3_PRSNT", "CAN8_TRAY4_PRSNT",
+	"CAN8_TRAY5_PRSNT", "CAN8_TRAY6_PRSNT",
+	"CAN8_TRAY7_PRSNT", "CAN8_TRAY8_PRSNT",
+	"CAN8_TRAY9_PRSNT", "CAN8_TRAY10_PRSNT",
+	"CAN8_TRAY11_PRSNT", "CAN8_TRAY12_PRSNT",
+	"CAN8_TRAY13_PRSNT", "CAN8_TRAY14_PRSNT",
+	"CAN8_TRAY15_PRSNT", "CAN8_TRAY16_PRSNT",
+	"CAN8_TRAY17_PRSNT", "CAN8_TRAY18_PRSNT",
+	"CAN8_TRAY19_PRSNT", "CAN8_TRAY20_PRSNT",
+	"CAN8_TRAY21_PRSNT", "CAN8_TRAY22_PRSNT",
+	"CAN8_TRAY23_PRSNT", "CAN8_TRAY24_PRSNT",
+	"CAN8_TRAY25_PRSNT", "CAN8_TRAY26_PRSNT",
+	"CAN8_TRAY27_PRSNT", "CAN8_TRAY28_PRSNT",
+	"CAN8_TRAY29_PRSNT", "CAN8_TRAY30_PRSNT",
+	"CAN8_TRAY31_PRSNT", "CAN8_TRAY32_PRSNT",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&pwrgd_io_expander0 {
+	gpio-line-names =
+	"CAN1_TRAY1_PWRGD", "CAN1_TRAY2_PWRGD",
+	"CAN1_TRAY3_PWRGD", "CAN1_TRAY4_PWRGD",
+	"CAN1_TRAY5_PWRGD", "CAN1_TRAY6_PWRGD",
+	"CAN1_TRAY7_PWRGD", "CAN1_TRAY8_PWRGD",
+	"CAN1_TRAY9_PWRGD", "CAN1_TRAY10_PWRGD",
+	"CAN1_TRAY11_PWRGD", "CAN1_TRAY12_PWRGD",
+	"CAN1_TRAY13_PWRGD", "CAN1_TRAY14_PWRGD",
+	"CAN1_TRAY15_PWRGD", "CAN1_TRAY16_PWRGD",
+	"CAN1_TRAY17_PWRGD", "CAN1_TRAY18_PWRGD",
+	"CAN1_TRAY19_PWRGD", "CAN1_TRAY20_PWRGD",
+	"CAN1_TRAY21_PWRGD", "CAN1_TRAY22_PWRGD",
+	"CAN1_TRAY23_PWRGD", "CAN1_TRAY24_PWRGD",
+	"CAN1_TRAY25_PWRGD", "CAN1_TRAY26_PWRGD",
+	"CAN1_TRAY27_PWRGD", "CAN1_TRAY28_PWRGD",
+	"CAN1_TRAY29_PWRGD", "CAN1_TRAY30_PWRGD",
+	"CAN1_TRAY31_PWRGD", "CAN1_TRAY32_PWRGD",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&pwrgd_io_expander1 {
+	gpio-line-names =
+	"CAN2_TRAY1_PWRGD", "CAN2_TRAY2_PWRGD",
+	"CAN2_TRAY3_PWRGD", "CAN2_TRAY4_PWRGD",
+	"CAN2_TRAY5_PWRGD", "CAN2_TRAY6_PWRGD",
+	"CAN2_TRAY7_PWRGD", "CAN2_TRAY8_PWRGD",
+	"CAN2_TRAY9_PWRGD", "CAN2_TRAY10_PWRGD",
+	"CAN2_TRAY11_PWRGD", "CAN2_TRAY12_PWRGD",
+	"CAN2_TRAY13_PWRGD", "CAN2_TRAY14_PWRGD",
+	"CAN2_TRAY15_PWRGD", "CAN2_TRAY16_PWRGD",
+	"CAN2_TRAY17_PWRGD", "CAN2_TRAY18_PWRGD",
+	"CAN2_TRAY19_PWRGD", "CAN2_TRAY20_PWRGD",
+	"CAN2_TRAY21_PWRGD", "CAN2_TRAY22_PWRGD",
+	"CAN2_TRAY23_PWRGD", "CAN2_TRAY24_PWRGD",
+	"CAN2_TRAY25_PWRGD", "CAN2_TRAY26_PWRGD",
+	"CAN2_TRAY27_PWRGD", "CAN2_TRAY28_PWRGD",
+	"CAN2_TRAY29_PWRGD", "CAN2_TRAY30_PWRGD",
+	"CAN2_TRAY31_PWRGD", "CAN2_TRAY32_PWRGD",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&pwrgd_io_expander2 {
+	gpio-line-names =
+	"CAN3_TRAY1_PWRGD", "CAN3_TRAY2_PWRGD",
+	"CAN3_TRAY3_PWRGD", "CAN3_TRAY4_PWRGD",
+	"CAN3_TRAY5_PWRGD", "CAN3_TRAY6_PWRGD",
+	"CAN3_TRAY7_PWRGD", "CAN3_TRAY8_PWRGD",
+	"CAN3_TRAY9_PWRGD", "CAN3_TRAY10_PWRGD",
+	"CAN3_TRAY11_PWRGD", "CAN3_TRAY12_PWRGD",
+	"CAN3_TRAY13_PWRGD", "CAN3_TRAY14_PWRGD",
+	"CAN3_TRAY15_PWRGD", "CAN3_TRAY16_PWRGD",
+	"CAN3_TRAY17_PWRGD", "CAN3_TRAY18_PWRGD",
+	"CAN3_TRAY19_PWRGD", "CAN3_TRAY20_PWRGD",
+	"CAN3_TRAY21_PWRGD", "CAN3_TRAY22_PWRGD",
+	"CAN3_TRAY23_PWRGD", "CAN3_TRAY24_PWRGD",
+	"CAN3_TRAY25_PWRGD", "CAN3_TRAY26_PWRGD",
+	"CAN3_TRAY27_PWRGD", "CAN3_TRAY28_PWRGD",
+	"CAN3_TRAY29_PWRGD", "CAN3_TRAY30_PWRGD",
+	"CAN3_TRAY31_PWRGD", "CAN3_TRAY32_PWRGD",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&pwrgd_io_expander3 {
+	gpio-line-names =
+	"CAN4_TRAY1_PWRGD", "CAN4_TRAY2_PWRGD",
+	"CAN4_TRAY3_PWRGD", "CAN4_TRAY4_PWRGD",
+	"CAN4_TRAY5_PWRGD", "CAN4_TRAY6_PWRGD",
+	"CAN4_TRAY7_PWRGD", "CAN4_TRAY8_PWRGD",
+	"CAN4_TRAY9_PWRGD", "CAN4_TRAY10_PWRGD",
+	"CAN4_TRAY11_PWRGD", "CAN4_TRAY12_PWRGD",
+	"CAN4_TRAY13_PWRGD", "CAN4_TRAY14_PWRGD",
+	"CAN4_TRAY15_PWRGD", "CAN4_TRAY16_PWRGD",
+	"CAN4_TRAY17_PWRGD", "CAN4_TRAY18_PWRGD",
+	"CAN4_TRAY19_PWRGD", "CAN4_TRAY20_PWRGD",
+	"CAN4_TRAY21_PWRGD", "CAN4_TRAY22_PWRGD",
+	"CAN4_TRAY23_PWRGD", "CAN4_TRAY24_PWRGD",
+	"CAN4_TRAY25_PWRGD", "CAN4_TRAY26_PWRGD",
+	"CAN4_TRAY27_PWRGD", "CAN4_TRAY28_PWRGD",
+	"CAN4_TRAY29_PWRGD", "CAN4_TRAY30_PWRGD",
+	"CAN4_TRAY31_PWRGD", "CAN4_TRAY32_PWRGD",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&pwrgd_io_expander4 {
+	gpio-line-names =
+	"CAN5_TRAY1_PWRGD", "CAN5_TRAY2_PWRGD",
+	"CAN5_TRAY3_PWRGD", "CAN5_TRAY4_PWRGD",
+	"CAN5_TRAY5_PWRGD", "CAN5_TRAY6_PWRGD",
+	"CAN5_TRAY7_PWRGD", "CAN5_TRAY8_PWRGD",
+	"CAN5_TRAY9_PWRGD", "CAN5_TRAY10_PWRGD",
+	"CAN5_TRAY11_PWRGD", "CAN5_TRAY12_PWRGD",
+	"CAN5_TRAY13_PWRGD", "CAN5_TRAY14_PWRGD",
+	"CAN5_TRAY15_PWRGD", "CAN5_TRAY16_PWRGD",
+	"CAN5_TRAY17_PWRGD", "CAN5_TRAY18_PWRGD",
+	"CAN5_TRAY19_PWRGD", "CAN5_TRAY20_PWRGD",
+	"CAN5_TRAY21_PWRGD", "CAN5_TRAY22_PWRGD",
+	"CAN5_TRAY23_PWRGD", "CAN5_TRAY24_PWRGD",
+	"CAN5_TRAY25_PWRGD", "CAN5_TRAY26_PWRGD",
+	"CAN5_TRAY27_PWRGD", "CAN5_TRAY28_PWRGD",
+	"CAN5_TRAY29_PWRGD", "CAN5_TRAY30_PWRGD",
+	"CAN5_TRAY31_PWRGD", "CAN5_TRAY32_PWRGD",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&pwrgd_io_expander5 {
+	gpio-line-names =
+	"CAN6_TRAY1_PWRGD", "CAN6_TRAY2_PWRGD",
+	"CAN6_TRAY3_PWRGD", "CAN6_TRAY4_PWRGD",
+	"CAN6_TRAY5_PWRGD", "CAN6_TRAY6_PWRGD",
+	"CAN6_TRAY7_PWRGD", "CAN6_TRAY8_PWRGD",
+	"CAN6_TRAY9_PWRGD", "CAN6_TRAY10_PWRGD",
+	"CAN6_TRAY11_PWRGD", "CAN6_TRAY12_PWRGD",
+	"CAN6_TRAY13_PWRGD", "CAN6_TRAY14_PWRGD",
+	"CAN6_TRAY15_PWRGD", "CAN6_TRAY16_PWRGD",
+	"CAN6_TRAY17_PWRGD", "CAN6_TRAY18_PWRGD",
+	"CAN6_TRAY19_PWRGD", "CAN6_TRAY20_PWRGD",
+	"CAN6_TRAY21_PWRGD", "CAN6_TRAY22_PWRGD",
+	"CAN6_TRAY23_PWRGD", "CAN6_TRAY24_PWRGD",
+	"CAN6_TRAY25_PWRGD", "CAN6_TRAY26_PWRGD",
+	"CAN6_TRAY27_PWRGD", "CAN6_TRAY28_PWRGD",
+	"CAN6_TRAY29_PWRGD", "CAN6_TRAY30_PWRGD",
+	"CAN6_TRAY31_PWRGD", "CAN6_TRAY32_PWRGD",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&pwrgd_io_expander6 {
+	gpio-line-names =
+	"CAN7_TRAY1_PWRGD", "CAN7_TRAY2_PWRGD",
+	"CAN7_TRAY3_PWRGD", "CAN7_TRAY4_PWRGD",
+	"CAN7_TRAY5_PWRGD", "CAN7_TRAY6_PWRGD",
+	"CAN7_TRAY7_PWRGD", "CAN7_TRAY8_PWRGD",
+	"CAN7_TRAY9_PWRGD", "CAN7_TRAY10_PWRGD",
+	"CAN7_TRAY11_PWRGD", "CAN7_TRAY12_PWRGD",
+	"CAN7_TRAY13_PWRGD", "CAN7_TRAY14_PWRGD",
+	"CAN7_TRAY15_PWRGD", "CAN7_TRAY16_PWRGD",
+	"CAN7_TRAY17_PWRGD", "CAN7_TRAY18_PWRGD",
+	"CAN7_TRAY19_PWRGD", "CAN7_TRAY20_PWRGD",
+	"CAN7_TRAY21_PWRGD", "CAN7_TRAY22_PWRGD",
+	"CAN7_TRAY23_PWRGD", "CAN7_TRAY24_PWRGD",
+	"CAN7_TRAY25_PWRGD", "CAN7_TRAY26_PWRGD",
+	"CAN7_TRAY27_PWRGD", "CAN7_TRAY28_PWRGD",
+	"CAN7_TRAY29_PWRGD", "CAN7_TRAY30_PWRGD",
+	"CAN7_TRAY31_PWRGD", "CAN7_TRAY32_PWRGD",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&pwrgd_io_expander7 {
+	gpio-line-names =
+	"CAN8_TRAY1_PWRGD", "CAN8_TRAY2_PWRGD",
+	"CAN8_TRAY3_PWRGD", "CAN8_TRAY4_PWRGD",
+	"CAN8_TRAY5_PWRGD", "CAN8_TRAY6_PWRGD",
+	"CAN8_TRAY7_PWRGD", "CAN8_TRAY8_PWRGD",
+	"CAN8_TRAY9_PWRGD", "CAN8_TRAY10_PWRGD",
+	"CAN8_TRAY11_PWRGD", "CAN8_TRAY12_PWRGD",
+	"CAN8_TRAY13_PWRGD", "CAN8_TRAY14_PWRGD",
+	"CAN8_TRAY15_PWRGD", "CAN8_TRAY16_PWRGD",
+	"CAN8_TRAY17_PWRGD", "CAN8_TRAY18_PWRGD",
+	"CAN8_TRAY19_PWRGD", "CAN8_TRAY20_PWRGD",
+	"CAN8_TRAY21_PWRGD", "CAN8_TRAY22_PWRGD",
+	"CAN8_TRAY23_PWRGD", "CAN8_TRAY24_PWRGD",
+	"CAN8_TRAY25_PWRGD", "CAN8_TRAY26_PWRGD",
+	"CAN8_TRAY27_PWRGD", "CAN8_TRAY28_PWRGD",
+	"CAN8_TRAY29_PWRGD", "CAN8_TRAY30_PWRGD",
+	"CAN8_TRAY31_PWRGD", "CAN8_TRAY32_PWRGD",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&large_leak_io_expander0 {
+	gpio-line-names =
+	"CAN1_TRAY1_LARGE_LEAK", "CAN1_TRAY2_LARGE_LEAK",
+	"CAN1_TRAY3_LARGE_LEAK", "CAN1_TRAY4_LARGE_LEAK",
+	"CAN1_TRAY5_LARGE_LEAK", "CAN1_TRAY6_LARGE_LEAK",
+	"CAN1_TRAY7_LARGE_LEAK", "CAN1_TRAY8_LARGE_LEAK",
+	"CAN1_TRAY9_LARGE_LEAK", "CAN1_TRAY10_LARGE_LEAK",
+	"CAN1_TRAY11_LARGE_LEAK", "CAN1_TRAY12_LARGE_LEAK",
+	"CAN1_TRAY13_LARGE_LEAK", "CAN1_TRAY14_LARGE_LEAK",
+	"CAN1_TRAY15_LARGE_LEAK", "CAN1_TRAY16_LARGE_LEAK",
+	"CAN1_TRAY17_LARGE_LEAK", "CAN1_TRAY18_LARGE_LEAK",
+	"CAN1_TRAY19_LARGE_LEAK", "CAN1_TRAY20_LARGE_LEAK",
+	"CAN1_TRAY21_LARGE_LEAK", "CAN1_TRAY22_LARGE_LEAK",
+	"CAN1_TRAY23_LARGE_LEAK", "CAN1_TRAY24_LARGE_LEAK",
+	"CAN1_TRAY25_LARGE_LEAK", "CAN1_TRAY26_LARGE_LEAK",
+	"CAN1_TRAY27_LARGE_LEAK", "CAN1_TRAY28_LARGE_LEAK",
+	"CAN1_TRAY29_LARGE_LEAK", "CAN1_TRAY30_LARGE_LEAK",
+	"CAN1_TRAY31_LARGE_LEAK", "CAN1_TRAY32_LARGE_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&large_leak_io_expander1 {
+	gpio-line-names =
+	"CAN2_TRAY1_LARGE_LEAK", "CAN2_TRAY2_LARGE_LEAK",
+	"CAN2_TRAY3_LARGE_LEAK", "CAN2_TRAY4_LARGE_LEAK",
+	"CAN2_TRAY5_LARGE_LEAK", "CAN2_TRAY6_LARGE_LEAK",
+	"CAN2_TRAY7_LARGE_LEAK", "CAN2_TRAY8_LARGE_LEAK",
+	"CAN2_TRAY9_LARGE_LEAK", "CAN2_TRAY10_LARGE_LEAK",
+	"CAN2_TRAY11_LARGE_LEAK", "CAN2_TRAY12_LARGE_LEAK",
+	"CAN2_TRAY13_LARGE_LEAK", "CAN2_TRAY14_LARGE_LEAK",
+	"CAN2_TRAY15_LARGE_LEAK", "CAN2_TRAY16_LARGE_LEAK",
+	"CAN2_TRAY17_LARGE_LEAK", "CAN2_TRAY18_LARGE_LEAK",
+	"CAN2_TRAY19_LARGE_LEAK", "CAN2_TRAY20_LARGE_LEAK",
+	"CAN2_TRAY21_LARGE_LEAK", "CAN2_TRAY22_LARGE_LEAK",
+	"CAN2_TRAY23_LARGE_LEAK", "CAN2_TRAY24_LARGE_LEAK",
+	"CAN2_TRAY25_LARGE_LEAK", "CAN2_TRAY26_LARGE_LEAK",
+	"CAN2_TRAY27_LARGE_LEAK", "CAN2_TRAY28_LARGE_LEAK",
+	"CAN2_TRAY29_LARGE_LEAK", "CAN2_TRAY30_LARGE_LEAK",
+	"CAN2_TRAY31_LARGE_LEAK", "CAN2_TRAY32_LARGE_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&large_leak_io_expander2 {
+	gpio-line-names =
+	"CAN3_TRAY1_LARGE_LEAK", "CAN3_TRAY2_LARGE_LEAK",
+	"CAN3_TRAY3_LARGE_LEAK", "CAN3_TRAY4_LARGE_LEAK",
+	"CAN3_TRAY5_LARGE_LEAK", "CAN3_TRAY6_LARGE_LEAK",
+	"CAN3_TRAY7_LARGE_LEAK", "CAN3_TRAY8_LARGE_LEAK",
+	"CAN3_TRAY9_LARGE_LEAK", "CAN3_TRAY10_LARGE_LEAK",
+	"CAN3_TRAY11_LARGE_LEAK", "CAN3_TRAY12_LARGE_LEAK",
+	"CAN3_TRAY13_LARGE_LEAK", "CAN3_TRAY14_LARGE_LEAK",
+	"CAN3_TRAY15_LARGE_LEAK", "CAN3_TRAY16_LARGE_LEAK",
+	"CAN3_TRAY17_LARGE_LEAK", "CAN3_TRAY18_LARGE_LEAK",
+	"CAN3_TRAY19_LARGE_LEAK", "CAN3_TRAY20_LARGE_LEAK",
+	"CAN3_TRAY21_LARGE_LEAK", "CAN3_TRAY22_LARGE_LEAK",
+	"CAN3_TRAY23_LARGE_LEAK", "CAN3_TRAY24_LARGE_LEAK",
+	"CAN3_TRAY25_LARGE_LEAK", "CAN3_TRAY26_LARGE_LEAK",
+	"CAN3_TRAY27_LARGE_LEAK", "CAN3_TRAY28_LARGE_LEAK",
+	"CAN3_TRAY29_LARGE_LEAK", "CAN3_TRAY30_LARGE_LEAK",
+	"CAN3_TRAY31_LARGE_LEAK", "CAN3_TRAY32_LARGE_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&large_leak_io_expander3 {
+	gpio-line-names =
+	"CAN4_TRAY1_LARGE_LEAK", "CAN4_TRAY2_LARGE_LEAK",
+	"CAN4_TRAY3_LARGE_LEAK", "CAN4_TRAY4_LARGE_LEAK",
+	"CAN4_TRAY5_LARGE_LEAK", "CAN4_TRAY6_LARGE_LEAK",
+	"CAN4_TRAY7_LARGE_LEAK", "CAN4_TRAY8_LARGE_LEAK",
+	"CAN4_TRAY9_LARGE_LEAK", "CAN4_TRAY10_LARGE_LEAK",
+	"CAN4_TRAY11_LARGE_LEAK", "CAN4_TRAY12_LARGE_LEAK",
+	"CAN4_TRAY13_LARGE_LEAK", "CAN4_TRAY14_LARGE_LEAK",
+	"CAN4_TRAY15_LARGE_LEAK", "CAN4_TRAY16_LARGE_LEAK",
+	"CAN4_TRAY17_LARGE_LEAK", "CAN4_TRAY18_LARGE_LEAK",
+	"CAN4_TRAY19_LARGE_LEAK", "CAN4_TRAY20_LARGE_LEAK",
+	"CAN4_TRAY21_LARGE_LEAK", "CAN4_TRAY22_LARGE_LEAK",
+	"CAN4_TRAY23_LARGE_LEAK", "CAN4_TRAY24_LARGE_LEAK",
+	"CAN4_TRAY25_LARGE_LEAK", "CAN4_TRAY26_LARGE_LEAK",
+	"CAN4_TRAY27_LARGE_LEAK", "CAN4_TRAY28_LARGE_LEAK",
+	"CAN4_TRAY29_LARGE_LEAK", "CAN4_TRAY30_LARGE_LEAK",
+	"CAN4_TRAY31_LARGE_LEAK", "CAN4_TRAY32_LARGE_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&large_leak_io_expander4 {
+	gpio-line-names =
+	"CAN5_TRAY1_LARGE_LEAK", "CAN5_TRAY2_LARGE_LEAK",
+	"CAN5_TRAY3_LARGE_LEAK", "CAN5_TRAY4_LARGE_LEAK",
+	"CAN5_TRAY5_LARGE_LEAK", "CAN5_TRAY6_LARGE_LEAK",
+	"CAN5_TRAY7_LARGE_LEAK", "CAN5_TRAY8_LARGE_LEAK",
+	"CAN5_TRAY9_LARGE_LEAK", "CAN5_TRAY10_LARGE_LEAK",
+	"CAN5_TRAY11_LARGE_LEAK", "CAN5_TRAY12_LARGE_LEAK",
+	"CAN5_TRAY13_LARGE_LEAK", "CAN5_TRAY14_LARGE_LEAK",
+	"CAN5_TRAY15_LARGE_LEAK", "CAN5_TRAY16_LARGE_LEAK",
+	"CAN5_TRAY17_LARGE_LEAK", "CAN5_TRAY18_LARGE_LEAK",
+	"CAN5_TRAY19_LARGE_LEAK", "CAN5_TRAY20_LARGE_LEAK",
+	"CAN5_TRAY21_LARGE_LEAK", "CAN5_TRAY22_LARGE_LEAK",
+	"CAN5_TRAY23_LARGE_LEAK", "CAN5_TRAY24_LARGE_LEAK",
+	"CAN5_TRAY25_LARGE_LEAK", "CAN5_TRAY26_LARGE_LEAK",
+	"CAN5_TRAY27_LARGE_LEAK", "CAN5_TRAY28_LARGE_LEAK",
+	"CAN5_TRAY29_LARGE_LEAK", "CAN5_TRAY30_LARGE_LEAK",
+	"CAN5_TRAY31_LARGE_LEAK", "CAN5_TRAY32_LARGE_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&large_leak_io_expander5 {
+	gpio-line-names =
+	"CAN6_TRAY1_LARGE_LEAK", "CAN6_TRAY2_LARGE_LEAK",
+	"CAN6_TRAY3_LARGE_LEAK", "CAN6_TRAY4_LARGE_LEAK",
+	"CAN6_TRAY5_LARGE_LEAK", "CAN6_TRAY6_LARGE_LEAK",
+	"CAN6_TRAY7_LARGE_LEAK", "CAN6_TRAY8_LARGE_LEAK",
+	"CAN6_TRAY9_LARGE_LEAK", "CAN6_TRAY10_LARGE_LEAK",
+	"CAN6_TRAY11_LARGE_LEAK", "CAN6_TRAY12_LARGE_LEAK",
+	"CAN6_TRAY13_LARGE_LEAK", "CAN6_TRAY14_LARGE_LEAK",
+	"CAN6_TRAY15_LARGE_LEAK", "CAN6_TRAY16_LARGE_LEAK",
+	"CAN6_TRAY17_LARGE_LEAK", "CAN6_TRAY18_LARGE_LEAK",
+	"CAN6_TRAY19_LARGE_LEAK", "CAN6_TRAY20_LARGE_LEAK",
+	"CAN6_TRAY21_LARGE_LEAK", "CAN6_TRAY22_LARGE_LEAK",
+	"CAN6_TRAY23_LARGE_LEAK", "CAN6_TRAY24_LARGE_LEAK",
+	"CAN6_TRAY25_LARGE_LEAK", "CAN6_TRAY26_LARGE_LEAK",
+	"CAN6_TRAY27_LARGE_LEAK", "CAN6_TRAY28_LARGE_LEAK",
+	"CAN6_TRAY29_LARGE_LEAK", "CAN6_TRAY30_LARGE_LEAK",
+	"CAN6_TRAY31_LARGE_LEAK", "CAN6_TRAY32_LARGE_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&large_leak_io_expander6 {
+	gpio-line-names =
+	"CAN7_TRAY1_LARGE_LEAK", "CAN7_TRAY2_LARGE_LEAK",
+	"CAN7_TRAY3_LARGE_LEAK", "CAN7_TRAY4_LARGE_LEAK",
+	"CAN7_TRAY5_LARGE_LEAK", "CAN7_TRAY6_LARGE_LEAK",
+	"CAN7_TRAY7_LARGE_LEAK", "CAN7_TRAY8_LARGE_LEAK",
+	"CAN7_TRAY9_LARGE_LEAK", "CAN7_TRAY10_LARGE_LEAK",
+	"CAN7_TRAY11_LARGE_LEAK", "CAN7_TRAY12_LARGE_LEAK",
+	"CAN7_TRAY13_LARGE_LEAK", "CAN7_TRAY14_LARGE_LEAK",
+	"CAN7_TRAY15_LARGE_LEAK", "CAN7_TRAY16_LARGE_LEAK",
+	"CAN7_TRAY17_LARGE_LEAK", "CAN7_TRAY18_LARGE_LEAK",
+	"CAN7_TRAY19_LARGE_LEAK", "CAN7_TRAY20_LARGE_LEAK",
+	"CAN7_TRAY21_LARGE_LEAK", "CAN7_TRAY22_LARGE_LEAK",
+	"CAN7_TRAY23_LARGE_LEAK", "CAN7_TRAY24_LARGE_LEAK",
+	"CAN7_TRAY25_LARGE_LEAK", "CAN7_TRAY26_LARGE_LEAK",
+	"CAN7_TRAY27_LARGE_LEAK", "CAN7_TRAY28_LARGE_LEAK",
+	"CAN7_TRAY29_LARGE_LEAK", "CAN7_TRAY30_LARGE_LEAK",
+	"CAN7_TRAY31_LARGE_LEAK", "CAN7_TRAY32_LARGE_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&large_leak_io_expander7 {
+	gpio-line-names =
+	"CAN8_TRAY1_LARGE_LEAK", "CAN8_TRAY2_LARGE_LEAK",
+	"CAN8_TRAY3_LARGE_LEAK", "CAN8_TRAY4_LARGE_LEAK",
+	"CAN8_TRAY5_LARGE_LEAK", "CAN8_TRAY6_LARGE_LEAK",
+	"CAN8_TRAY7_LARGE_LEAK", "CAN8_TRAY8_LARGE_LEAK",
+	"CAN8_TRAY9_LARGE_LEAK", "CAN8_TRAY10_LARGE_LEAK",
+	"CAN8_TRAY11_LARGE_LEAK", "CAN8_TRAY12_LARGE_LEAK",
+	"CAN8_TRAY13_LARGE_LEAK", "CAN8_TRAY14_LARGE_LEAK",
+	"CAN8_TRAY15_LARGE_LEAK", "CAN8_TRAY16_LARGE_LEAK",
+	"CAN8_TRAY17_LARGE_LEAK", "CAN8_TRAY18_LARGE_LEAK",
+	"CAN8_TRAY19_LARGE_LEAK", "CAN8_TRAY20_LARGE_LEAK",
+	"CAN8_TRAY21_LARGE_LEAK", "CAN8_TRAY22_LARGE_LEAK",
+	"CAN8_TRAY23_LARGE_LEAK", "CAN8_TRAY24_LARGE_LEAK",
+	"CAN8_TRAY25_LARGE_LEAK", "CAN8_TRAY26_LARGE_LEAK",
+	"CAN8_TRAY27_LARGE_LEAK", "CAN8_TRAY28_LARGE_LEAK",
+	"CAN8_TRAY29_LARGE_LEAK", "CAN8_TRAY30_LARGE_LEAK",
+	"CAN8_TRAY31_LARGE_LEAK", "CAN8_TRAY32_LARGE_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&small_leak_io_expander0 {
+	gpio-line-names =
+	"CAN1_TRAY1_SMALL_LEAK", "CAN1_TRAY2_SMALL_LEAK",
+	"CAN1_TRAY3_SMALL_LEAK", "CAN1_TRAY4_SMALL_LEAK",
+	"CAN1_TRAY5_SMALL_LEAK", "CAN1_TRAY6_SMALL_LEAK",
+	"CAN1_TRAY7_SMALL_LEAK", "CAN1_TRAY8_SMALL_LEAK",
+	"CAN1_TRAY9_SMALL_LEAK", "CAN1_TRAY10_SMALL_LEAK",
+	"CAN1_TRAY11_SMALL_LEAK", "CAN1_TRAY12_SMALL_LEAK",
+	"CAN1_TRAY13_SMALL_LEAK", "CAN1_TRAY14_SMALL_LEAK",
+	"CAN1_TRAY15_SMALL_LEAK", "CAN1_TRAY16_SMALL_LEAK",
+	"CAN1_TRAY17_SMALL_LEAK", "CAN1_TRAY18_SMALL_LEAK",
+	"CAN1_TRAY19_SMALL_LEAK", "CAN1_TRAY20_SMALL_LEAK",
+	"CAN1_TRAY21_SMALL_LEAK", "CAN1_TRAY22_SMALL_LEAK",
+	"CAN1_TRAY23_SMALL_LEAK", "CAN1_TRAY24_SMALL_LEAK",
+	"CAN1_TRAY25_SMALL_LEAK", "CAN1_TRAY26_SMALL_LEAK",
+	"CAN1_TRAY27_SMALL_LEAK", "CAN1_TRAY28_SMALL_LEAK",
+	"CAN1_TRAY29_SMALL_LEAK", "CAN1_TRAY30_SMALL_LEAK",
+	"CAN1_TRAY31_SMALL_LEAK", "CAN1_TRAY32_SMALL_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&small_leak_io_expander1 {
+	gpio-line-names =
+	"CAN2_TRAY1_SMALL_LEAK", "CAN2_TRAY2_SMALL_LEAK",
+	"CAN2_TRAY3_SMALL_LEAK", "CAN2_TRAY4_SMALL_LEAK",
+	"CAN2_TRAY5_SMALL_LEAK", "CAN2_TRAY6_SMALL_LEAK",
+	"CAN2_TRAY7_SMALL_LEAK", "CAN2_TRAY8_SMALL_LEAK",
+	"CAN2_TRAY9_SMALL_LEAK", "CAN2_TRAY10_SMALL_LEAK",
+	"CAN2_TRAY11_SMALL_LEAK", "CAN2_TRAY12_SMALL_LEAK",
+	"CAN2_TRAY13_SMALL_LEAK", "CAN2_TRAY14_SMALL_LEAK",
+	"CAN2_TRAY15_SMALL_LEAK", "CAN2_TRAY16_SMALL_LEAK",
+	"CAN2_TRAY17_SMALL_LEAK", "CAN2_TRAY18_SMALL_LEAK",
+	"CAN2_TRAY19_SMALL_LEAK", "CAN2_TRAY20_SMALL_LEAK",
+	"CAN2_TRAY21_SMALL_LEAK", "CAN2_TRAY22_SMALL_LEAK",
+	"CAN2_TRAY23_SMALL_LEAK", "CAN2_TRAY24_SMALL_LEAK",
+	"CAN2_TRAY25_SMALL_LEAK", "CAN2_TRAY26_SMALL_LEAK",
+	"CAN2_TRAY27_SMALL_LEAK", "CAN2_TRAY28_SMALL_LEAK",
+	"CAN2_TRAY29_SMALL_LEAK", "CAN2_TRAY30_SMALL_LEAK",
+	"CAN2_TRAY31_SMALL_LEAK", "CAN2_TRAY32_SMALL_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&small_leak_io_expander2 {
+	gpio-line-names =
+	"CAN3_TRAY1_SMALL_LEAK", "CAN3_TRAY2_SMALL_LEAK",
+	"CAN3_TRAY3_SMALL_LEAK", "CAN3_TRAY4_SMALL_LEAK",
+	"CAN3_TRAY5_SMALL_LEAK", "CAN3_TRAY6_SMALL_LEAK",
+	"CAN3_TRAY7_SMALL_LEAK", "CAN3_TRAY8_SMALL_LEAK",
+	"CAN3_TRAY9_SMALL_LEAK", "CAN3_TRAY10_SMALL_LEAK",
+	"CAN3_TRAY11_SMALL_LEAK", "CAN3_TRAY12_SMALL_LEAK",
+	"CAN3_TRAY13_SMALL_LEAK", "CAN3_TRAY14_SMALL_LEAK",
+	"CAN3_TRAY15_SMALL_LEAK", "CAN3_TRAY16_SMALL_LEAK",
+	"CAN3_TRAY17_SMALL_LEAK", "CAN3_TRAY18_SMALL_LEAK",
+	"CAN3_TRAY19_SMALL_LEAK", "CAN3_TRAY20_SMALL_LEAK",
+	"CAN3_TRAY21_SMALL_LEAK", "CAN3_TRAY22_SMALL_LEAK",
+	"CAN3_TRAY23_SMALL_LEAK", "CAN3_TRAY24_SMALL_LEAK",
+	"CAN3_TRAY25_SMALL_LEAK", "CAN3_TRAY26_SMALL_LEAK",
+	"CAN3_TRAY27_SMALL_LEAK", "CAN3_TRAY28_SMALL_LEAK",
+	"CAN3_TRAY29_SMALL_LEAK", "CAN3_TRAY30_SMALL_LEAK",
+	"CAN3_TRAY31_SMALL_LEAK", "CAN3_TRAY32_SMALL_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&small_leak_io_expander3 {
+	gpio-line-names =
+	"CAN4_TRAY1_SMALL_LEAK", "CAN4_TRAY2_SMALL_LEAK",
+	"CAN4_TRAY3_SMALL_LEAK", "CAN4_TRAY4_SMALL_LEAK",
+	"CAN4_TRAY5_SMALL_LEAK", "CAN4_TRAY6_SMALL_LEAK",
+	"CAN4_TRAY7_SMALL_LEAK", "CAN4_TRAY8_SMALL_LEAK",
+	"CAN4_TRAY9_SMALL_LEAK", "CAN4_TRAY10_SMALL_LEAK",
+	"CAN4_TRAY11_SMALL_LEAK", "CAN4_TRAY12_SMALL_LEAK",
+	"CAN4_TRAY13_SMALL_LEAK", "CAN4_TRAY14_SMALL_LEAK",
+	"CAN4_TRAY15_SMALL_LEAK", "CAN4_TRAY16_SMALL_LEAK",
+	"CAN4_TRAY17_SMALL_LEAK", "CAN4_TRAY18_SMALL_LEAK",
+	"CAN4_TRAY19_SMALL_LEAK", "CAN4_TRAY20_SMALL_LEAK",
+	"CAN4_TRAY21_SMALL_LEAK", "CAN4_TRAY22_SMALL_LEAK",
+	"CAN4_TRAY23_SMALL_LEAK", "CAN4_TRAY24_SMALL_LEAK",
+	"CAN4_TRAY25_SMALL_LEAK", "CAN4_TRAY26_SMALL_LEAK",
+	"CAN4_TRAY27_SMALL_LEAK", "CAN4_TRAY28_SMALL_LEAK",
+	"CAN4_TRAY29_SMALL_LEAK", "CAN4_TRAY30_SMALL_LEAK",
+	"CAN4_TRAY31_SMALL_LEAK", "CAN4_TRAY32_SMALL_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&small_leak_io_expander4 {
+	gpio-line-names =
+	"CAN5_TRAY1_SMALL_LEAK", "CAN5_TRAY2_SMALL_LEAK",
+	"CAN5_TRAY3_SMALL_LEAK", "CAN5_TRAY4_SMALL_LEAK",
+	"CAN5_TRAY5_SMALL_LEAK", "CAN5_TRAY6_SMALL_LEAK",
+	"CAN5_TRAY7_SMALL_LEAK", "CAN5_TRAY8_SMALL_LEAK",
+	"CAN5_TRAY9_SMALL_LEAK", "CAN5_TRAY10_SMALL_LEAK",
+	"CAN5_TRAY11_SMALL_LEAK", "CAN5_TRAY12_SMALL_LEAK",
+	"CAN5_TRAY13_SMALL_LEAK", "CAN5_TRAY14_SMALL_LEAK",
+	"CAN5_TRAY15_SMALL_LEAK", "CAN5_TRAY16_SMALL_LEAK",
+	"CAN5_TRAY17_SMALL_LEAK", "CAN5_TRAY18_SMALL_LEAK",
+	"CAN5_TRAY19_SMALL_LEAK", "CAN5_TRAY20_SMALL_LEAK",
+	"CAN5_TRAY21_SMALL_LEAK", "CAN5_TRAY22_SMALL_LEAK",
+	"CAN5_TRAY23_SMALL_LEAK", "CAN5_TRAY24_SMALL_LEAK",
+	"CAN5_TRAY25_SMALL_LEAK", "CAN5_TRAY26_SMALL_LEAK",
+	"CAN5_TRAY27_SMALL_LEAK", "CAN5_TRAY28_SMALL_LEAK",
+	"CAN5_TRAY29_SMALL_LEAK", "CAN5_TRAY30_SMALL_LEAK",
+	"CAN5_TRAY31_SMALL_LEAK", "CAN5_TRAY32_SMALL_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&small_leak_io_expander5 {
+	gpio-line-names =
+	"CAN6_TRAY1_SMALL_LEAK", "CAN6_TRAY2_SMALL_LEAK",
+	"CAN6_TRAY3_SMALL_LEAK", "CAN6_TRAY4_SMALL_LEAK",
+	"CAN6_TRAY5_SMALL_LEAK", "CAN6_TRAY6_SMALL_LEAK",
+	"CAN6_TRAY7_SMALL_LEAK", "CAN6_TRAY8_SMALL_LEAK",
+	"CAN6_TRAY9_SMALL_LEAK", "CAN6_TRAY10_SMALL_LEAK",
+	"CAN6_TRAY11_SMALL_LEAK", "CAN6_TRAY12_SMALL_LEAK",
+	"CAN6_TRAY13_SMALL_LEAK", "CAN6_TRAY14_SMALL_LEAK",
+	"CAN6_TRAY15_SMALL_LEAK", "CAN6_TRAY16_SMALL_LEAK",
+	"CAN6_TRAY17_SMALL_LEAK", "CAN6_TRAY18_SMALL_LEAK",
+	"CAN6_TRAY19_SMALL_LEAK", "CAN6_TRAY20_SMALL_LEAK",
+	"CAN6_TRAY21_SMALL_LEAK", "CAN6_TRAY22_SMALL_LEAK",
+	"CAN6_TRAY23_SMALL_LEAK", "CAN6_TRAY24_SMALL_LEAK",
+	"CAN6_TRAY25_SMALL_LEAK", "CAN6_TRAY26_SMALL_LEAK",
+	"CAN6_TRAY27_SMALL_LEAK", "CAN6_TRAY28_SMALL_LEAK",
+	"CAN6_TRAY29_SMALL_LEAK", "CAN6_TRAY30_SMALL_LEAK",
+	"CAN6_TRAY31_SMALL_LEAK", "CAN6_TRAY32_SMALL_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&small_leak_io_expander6 {
+	gpio-line-names =
+	"CAN7_TRAY1_SMALL_LEAK", "CAN7_TRAY2_SMALL_LEAK",
+	"CAN7_TRAY3_SMALL_LEAK", "CAN7_TRAY4_SMALL_LEAK",
+	"CAN7_TRAY5_SMALL_LEAK", "CAN7_TRAY6_SMALL_LEAK",
+	"CAN7_TRAY7_SMALL_LEAK", "CAN7_TRAY8_SMALL_LEAK",
+	"CAN7_TRAY9_SMALL_LEAK", "CAN7_TRAY10_SMALL_LEAK",
+	"CAN7_TRAY11_SMALL_LEAK", "CAN7_TRAY12_SMALL_LEAK",
+	"CAN7_TRAY13_SMALL_LEAK", "CAN7_TRAY14_SMALL_LEAK",
+	"CAN7_TRAY15_SMALL_LEAK", "CAN7_TRAY16_SMALL_LEAK",
+	"CAN7_TRAY17_SMALL_LEAK", "CAN7_TRAY18_SMALL_LEAK",
+	"CAN7_TRAY19_SMALL_LEAK", "CAN7_TRAY20_SMALL_LEAK",
+	"CAN7_TRAY21_SMALL_LEAK", "CAN7_TRAY22_SMALL_LEAK",
+	"CAN7_TRAY23_SMALL_LEAK", "CAN7_TRAY24_SMALL_LEAK",
+	"CAN7_TRAY25_SMALL_LEAK", "CAN7_TRAY26_SMALL_LEAK",
+	"CAN7_TRAY27_SMALL_LEAK", "CAN7_TRAY28_SMALL_LEAK",
+	"CAN7_TRAY29_SMALL_LEAK", "CAN7_TRAY30_SMALL_LEAK",
+	"CAN7_TRAY31_SMALL_LEAK", "CAN7_TRAY32_SMALL_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&small_leak_io_expander7 {
+	gpio-line-names =
+	"CAN8_TRAY1_SMALL_LEAK", "CAN8_TRAY2_SMALL_LEAK",
+	"CAN8_TRAY3_SMALL_LEAK", "CAN8_TRAY4_SMALL_LEAK",
+	"CAN8_TRAY5_SMALL_LEAK", "CAN8_TRAY6_SMALL_LEAK",
+	"CAN8_TRAY7_SMALL_LEAK", "CAN8_TRAY8_SMALL_LEAK",
+	"CAN8_TRAY9_SMALL_LEAK", "CAN8_TRAY10_SMALL_LEAK",
+	"CAN8_TRAY11_SMALL_LEAK", "CAN8_TRAY12_SMALL_LEAK",
+	"CAN8_TRAY13_SMALL_LEAK", "CAN8_TRAY14_SMALL_LEAK",
+	"CAN8_TRAY15_SMALL_LEAK", "CAN8_TRAY16_SMALL_LEAK",
+	"CAN8_TRAY17_SMALL_LEAK", "CAN8_TRAY18_SMALL_LEAK",
+	"CAN8_TRAY19_SMALL_LEAK", "CAN8_TRAY20_SMALL_LEAK",
+	"CAN8_TRAY21_SMALL_LEAK", "CAN8_TRAY22_SMALL_LEAK",
+	"CAN8_TRAY23_SMALL_LEAK", "CAN8_TRAY24_SMALL_LEAK",
+	"CAN8_TRAY25_SMALL_LEAK", "CAN8_TRAY26_SMALL_LEAK",
+	"CAN8_TRAY27_SMALL_LEAK", "CAN8_TRAY28_SMALL_LEAK",
+	"CAN8_TRAY29_SMALL_LEAK", "CAN8_TRAY30_SMALL_LEAK",
+	"CAN8_TRAY31_SMALL_LEAK", "CAN8_TRAY32_SMALL_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&legacy_prsnt_io_expander0 {
+	gpio-line-names =
+	"wTRAY_PRSNT1_N_BUF_R", "wTRAY_PRSNT2_N_BUF_R",
+	"wTRAY_PRSNT3_N_BUF_R", "wTRAY_PRSNT4_N_BUF_R",
+	"wTRAY_PRSNT5_N_BUF_R", "wTRAY_PRSNT6_N_BUF_R",
+	"wTRAY_PRSNT7_N_BUF_R", "wTRAY_PRSNT8_N_BUF_R",
+	"wTRAY_PRSNT9_N_BUF_R", "wTRAY_PRSNT10_N_BUF_R",
+	"wTRAY_PRSNT11_N_BUF_R", "wTRAY_PRSNT12_N_BUF_R",
+	"wTRAY_PRSNT13_N_BUF_R", "wTRAY_PRSNT14_N_BUF_R",
+	"wTRAY_PRSNT15_N_BUF_R", "wTRAY_PRSNT16_N_BUF_R";
+};
+
+&legacy_prsnt_io_expander1 {
+	gpio-line-names =
+	"wTRAY_PRSNT17_N_BUF_R", "wTRAY_PRSNT18_N_BUF_R",
+	"wTRAY_PRSNT19_N_BUF_R", "wTRAY_PRSNT20_N_BUF_R",
+	"wTRAY_PRSNT21_N_BUF_R", "wTRAY_PRSNT22_N_BUF_R",
+	"wTRAY_PRSNT23_N_BUF_R", "wTRAY_PRSNT24_N_BUF_R",
+	"wTRAY_PRSNT25_N_BUF_R", "wTRAY_PRSNT26_N_BUF_R",
+	"wTRAY_PRSNT27_N_BUF_R", "wTRAY_PRSNT28_N_BUF_R",
+	"wTRAY_PRSNT29_N_BUF_R", "wTRAY_PRSNT30_N_BUF_R",
+	"wTRAY_PRSNT31_N_BUF_R", "wTRAY_PRSNT32_N_BUF_R";
+};
+
+&legacy_prsnt_io_expander2 {
+	gpio-line-names =
+	"wTRAY_PRSNT33_N_BUF_R", "wTRAY_PRSNT34_N_BUF_R",
+	"wTRAY_PRSNT35_N_BUF_R", "wTRAY_PRSNT36_N_BUF_R",
+	"wTRAY_PRSNT37_N_BUF_R", "wTRAY_PRSNT38_N_BUF_R",
+	"wTRAY_PRSNT39_N_BUF_R", "wTRAY_PRSNT40_N_BUF_R",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&legacy_pwrgd_io_expander0 {
+	gpio-line-names =
+	"wTRAY_PWRGD1_N_BUF_R", "wTRAY_PWRGD2_N_BUF_R",
+	"wTRAY_PWRGD3_N_BUF_R", "wTRAY_PWRGD4_N_BUF_R",
+	"wTRAY_PWRGD5_N_BUF_R", "wTRAY_PWRGD6_N_BUF_R",
+	"wTRAY_PWRGD7_N_BUF_R", "wTRAY_PWRGD8_N_BUF_R",
+	"wTRAY_PWRGD9_N_BUF_R", "wTRAY_PWRGD10_N_BUF_R",
+	"wTRAY_PWRGD11_N_BUF_R", "wTRAY_PWRGD12_N_BUF_R",
+	"wTRAY_PWRGD13_N_BUF_R", "wTRAY_PWRGD14_N_BUF_R",
+	"wTRAY_PWRGD15_N_BUF_R", "wTRAY_PWRGD16_N_BUF_R";
+};
+
+&legacy_pwrgd_io_expander1 {
+	gpio-line-names =
+	"wTRAY_PWRGD17_N_BUF_R", "wTRAY_PWRGD18_N_BUF_R",
+	"wTRAY_PWRGD19_N_BUF_R", "wTRAY_PWRGD20_N_BUF_R",
+	"wTRAY_PWRGD21_N_BUF_R", "wTRAY_PWRGD22_N_BUF_R",
+	"", "",
+	"wTRAY_PWRGD25_N_BUF_R", "wTRAY_PWRGD26_N_BUF_R",
+	"wTRAY_PWRGD27_N_BUF_R", "wTRAY_PWRGD28_N_BUF_R",
+	"", "",
+	"", "";
+};
+
+&legacy_pwrgd_io_expander2 {
+	gpio-line-names =
+	"wTRAY_PWRGD33_N_BUF_R", "wTRAY_PWRGD34_N_BUF_R",
+	"wTRAY_PWRGD35_N_BUF_R", "wTRAY_PWRGD36_N_BUF_R",
+	"", "",
+	"", "",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&legacy_leak_io_expander0 {
+	gpio-line-names =
+	"wTRAY_LEAK_DETECT1_N_BUF_R", "wTRAY_LEAK_DETECT2_N_BUF_R",
+	"wTRAY_LEAK_DETECT3_N_BUF_R", "wTRAY_LEAK_DETECT4_N_BUF_R",
+	"wTRAY_LEAK_DETECT5_N_BUF_R", "wTRAY_LEAK_DETECT6_N_BUF_R",
+	"wTRAY_LEAK_DETECT7_N_BUF_R", "wTRAY_LEAK_DETECT8_N_BUF_R",
+	"wTRAY_LEAK_DETECT9_N_BUF_R", "wTRAY_LEAK_DETECT10_N_BUF_R",
+	"wTRAY_LEAK_DETECT11_N_BUF_R", "wTRAY_LEAK_DETECT12_N_BUF_R",
+	"wTRAY_LEAK_DETECT13_N_BUF_R", "wTRAY_LEAK_DETECT14_N_BUF_R",
+	"wTRAY_LEAK_DETECT15_N_BUF_R", "wTRAY_LEAK_DETECT16_N_BUF_R";
+};
+
+&legacy_leak_io_expander1 {
+	gpio-line-names =
+	"wTRAY_LEAK_DETECT17_N_BUF_R", "wTRAY_LEAK_DETECT18_N_BUF_R",
+	"wTRAY_LEAK_DETECT19_N_BUF_R", "wTRAY_LEAK_DETECT20_N_BUF_R",
+	"wTRAY_LEAK_DETECT21_N_BUF_R", "wTRAY_LEAK_DETECT22_N_BUF_R",
+	"wTRAY_LEAK_DETECT23_N_BUF_R", "wTRAY_LEAK_DETECT24_N_BUF_R",
+	"wTRAY_LEAK_DETECT25_N_BUF_R", "wTRAY_LEAK_DETECT26_N_BUF_R",
+	"wTRAY_LEAK_DETECT27_N_BUF_R", "wTRAY_LEAK_DETECT28_N_BUF_R",
+	"wTRAY_LEAK_DETECT29_N_BUF_R", "wTRAY_LEAK_DETECT30_N_BUF_R",
+	"wTRAY_LEAK_DETECT31_N_BUF_R", "wTRAY_LEAK_DETECT32_N_BUF_R";
+};
+
+&legacy_leak_io_expander2 {
+	gpio-line-names =
+	"wTRAY_LEAK_DETECT33_N_BUF_R", "wTRAY_LEAK_DETECT34_N_BUF_R",
+	"wTRAY_LEAK_DETECT35_N_BUF_R", "wTRAY_LEAK_DETECT36_N_BUF_R",
+	"wTRAY_LEAK_DETECT37_N_BUF_R", "wTRAY_LEAK_DETECT38_N_BUF_R",
+	"wTRAY_LEAK_DETECT39_N_BUF_R", "wTRAY_LEAK_DETECT40_N_BUF_R",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&legacy_small_leak_io_expander0 {
+	gpio-line-names =
+	"wTRAY_SMALL_LEAK1_N_BUF_R", "wTRAY_SMALL_LEAK2_N_BUF_R",
+	"wTRAY_SMALL_LEAK3_N_BUF_R", "wTRAY_SMALL_LEAK4_N_BUF_R",
+	"wTRAY_SMALL_LEAK5_N_BUF_R", "wTRAY_SMALL_LEAK6_N_BUF_R",
+	"wTRAY_SMALL_LEAK7_N_BUF_R", "wTRAY_SMALL_LEAK8_N_BUF_R",
+	"wTRAY_SMALL_LEAK9_N_BUF_R", "wTRAY_SMALL_LEAK10_N_BUF_R",
+	"wTRAY_SMALL_LEAK11_N_BUF_R", "wTRAY_SMALL_LEAK12_N_BUF_R",
+	"wTRAY_SMALL_LEAK13_N_BUF_R", "wTRAY_SMALL_LEAK14_N_BUF_R",
+	"wTRAY_SMALL_LEAK15_N_BUF_R", "wTRAY_SMALL_LEAK16_N_BUF_R";
+};
+
+&legacy_small_leak_io_expander1 {
+	gpio-line-names =
+	"wTRAY_SMALL_LEAK17_N_BUF_R", "wTRAY_SMALL_LEAK18_N_BUF_R",
+	"wTRAY_SMALL_LEAK19_N_BUF_R", "wTRAY_SMALL_LEAK20_N_BUF_R",
+	"wTRAY_SMALL_LEAK21_N_BUF_R", "wTRAY_SMALL_LEAK22_N_BUF_R",
+	"wTRAY_SMALL_LEAK23_N_BUF_R", "wTRAY_SMALL_LEAK24_N_BUF_R",
+	"wTRAY_SMALL_LEAK25_N_BUF_R", "wTRAY_SMALL_LEAK26_N_BUF_R",
+	"wTRAY_SMALL_LEAK27_N_BUF_R", "wTRAY_SMALL_LEAK28_N_BUF_R",
+	"wTRAY_SMALL_LEAK29_N_BUF_R", "wTRAY_SMALL_LEAK30_N_BUF_R",
+	"wTRAY_SMALL_LEAK31_N_BUF_R", "wTRAY_SMALL_LEAK32_N_BUF_R";
+};
+
+&fpga_io_expander64 {
+	gpio-line-names =
+	"wTRAY_PWRGD_TEST", "wprovision_done",
+	"", "",
+	"", "",
+	"LEAK_CONFIG0", "LEAK_CONFIG1",
+	"FPGA_PWRGD_P24V_AUX_R", "FPGA_PWRGD_P24V_AUX_2_R",
+	"FPGA_PWRGD_P12V_SCM_R", "FPGA_PWRGD_P12V_AUX_R2",
+	"FPGA_PRSNT_FANBP_0_SIG_R_PLD_N", "FPGA_PRSNT_FANBP_0_PWR_R_PLD_N",
+	"FPGA_P24V_AUX_INA230_ALERT_N_R", "FPGA_SMB_TMC75_TEMP_ALERT_N_R";
+};
+
+&fpga_io_expander65 {
+	gpio-line-names =
+	"FPGA_PCI_DIS_N", "FPGA_DEV_DIS_N",
+	"FPGA_PWRGD_P3V3_AUX_R", "FPGA_PWRGD_P5V_AUX_R2",
+	"FPGA_PWRGD_P1V05_AUX_R", "FPGA_P48V_HSC_ALERT_N",
+	"FPGA_PWRGD_P1V5_AUX_R", "FPGA_PWRGD_P52V_HSC_PWROK_R",
+	"FPGA_R_COME_THERMTRIP_L", "FPGA_PRSNT_POE_SIG_PLD_N",
+	"FPGA_PRSNT_POE_PWR_PLD_N", "FPGA_PRSNT_RIO_RACKMON_N",
+	"FPGA_PRSNT_CAN2_MCIO_N", "FPGA_PRSNT_CAN1_MCIO_N",
+	"FPGA_PRSNT_RACKMON_MCIO_N", "FPGA_PRSNT_AALC_MCIO_N";
+};
+
+&legacy_small_leak_io_expander2 {
+	gpio-line-names =
+	"wTRAY_SMALL_LEAK33_N_BUF_R", "wTRAY_SMALL_LEAK34_N_BUF_R",
+	"wTRAY_SMALL_LEAK35_N_BUF_R", "wTRAY_SMALL_LEAK36_N_BUF_R",
+	"wTRAY_SMALL_LEAK37_N_BUF_R", "wTRAY_SMALL_LEAK38_N_BUF_R",
+	"wTRAY_SMALL_LEAK39_N_BUF_R", "wTRAY_SMALL_LEAK40_N_BUF_R",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&sku_info_io_expander {
+	gpio-line-names =
+	"", "",
+	"", "",
+	"", "",
+	"", "",
+	"support_miniSAS", "support_CAN_Bus",
+	"support_AALC", "support_Front_VT1_2",
+	"support_Front_VT1_3", "support_Rear_VT2",
+	"", "";
+};
+
+&fan_io_expander0 {
+	gpio-line-names =
+	"FM_FAN0_POWER_LED_N", "FM_FAN1_POWER_LED_N",
+	"P12V_FAN0_PWR_GD", "P12V_FAN1_PWR_GD",
+	"FM_FAN0_FAULT_LED_N", "FM_FAN1_FAULT_LED_N",
+	"P12V_FAN0_FLTB", "P12V_FAN1_FLTB",
+	"FM_FAN0_BUF_PRESENT_R", "FM_FAN1_BUF_PRESENT_R",
+	"", "",
+	"FM_FAN0_P12V_EN", "FM_FAN1_P12V_EN",
+	"", "";
+};
+
+&fan_io_expander1 {
+	gpio-line-names =
+	"FM_FAN2_POWER_LED_N", "FM_FAN3_POWER_LED_N",
+	"P12V_FAN2_PWR_GD", "P12V_FAN3_PWR_GD",
+	"FM_FAN2_FAULT_LED_N", "FM_FAN3_FAULT_LED_N",
+	"P12V_FAN2_FLTB", "P12V_FAN3_FLTB",
+	"FM_FAN2_BUF_PRESENT_R", "FM_FAN3_BUF_PRESENT_R",
+	"", "",
+	"FM_FAN2_P12V_EN", "FM_FAN3_P12V_EN",
+	"", "";
+};

-- 
2.34.1



From ankur.a.arora at oracle.com  Sun Dec 21 23:47:09 2025
From: ankur.a.arora at oracle.com (Ankur Arora)
Date: Sun, 21 Dec 2025 23:47:09 -0800
Subject: [PATCH v8 01/12] asm-generic: barrier: Add
 smp_cond_load_relaxed_timeout()
In-Reply-To: <20251215044919.460086-2-ankur.a.arora@oracle.com>
References: <20251215044919.460086-1-ankur.a.arora@oracle.com>
 <20251215044919.460086-2-ankur.a.arora@oracle.com>
Message-ID: <87cy47t0ua.fsf@oracle.com>


Ankur Arora <ankur.a.arora at oracle.com> writes:

> Add smp_cond_load_relaxed_timeout(), which extends
> smp_cond_load_relaxed() to allow waiting for a duration.
>
> We loop around waiting for the condition variable to change while
> peridically doing a time-check. The loop uses cpu_poll_relax()
> to slow down the busy-waiting, which, unless overridden by the
> architecture code, amounts to a cpu_relax().
>
> Note that there are two ways for the time-check to fail: once we have
> timed out or, if the time_expr_ns returns an invalid value (negative
> or zero).
>
> The number of times we spin before doing the time-check is specified
> by SMP_TIMEOUT_POLL_COUNT (chosen to be 200 by default) which,
> assuming each cpu_poll_relax() iteration takes ~20-30 cycles (measured
> on a variety of x86 platforms), for a total of ~4000-6000 cycles.
>
> That is also the outer limit of the overshoot when working with the
> parameters above. This might be higher or lesser depending on the
> implementation of cpu_poll_relax() across architectures.
>
> Cc: Arnd Bergmann <arnd at arndb.de>
> Cc: Will Deacon <will at kernel.org>
> Cc: Catalin Marinas <catalin.marinas at arm.com>
> Cc: Peter Zijlstra <peterz at infradead.org>
> Cc: linux-arch at vger.kernel.org
> Signed-off-by: Ankur Arora <ankur.a.arora at oracle.com>
> ---
>
> Notes:
>
>    - the interface now breaks the time_check_expr into two parts:
>      time_expr_ns (evaluates to current time) and remaining_ns. The main
>      reason for doing this was to support WFET and similar primitives
>      which can do timed waiting.
>
>    - cpu_poll_relax() now takes an additional paramater to handle that.
>
>    - time_expr_ns can now return failure which needs a little more change
>      in organization. This was needed because rqspinlock check_timeout()
>      logic mapped naturally to the unified check in time_check_expr.
>      Breaking up the time_check_expr, however needed check_timeout() to
>      separate a clock interface (which could fail on deadlock or its
>      internal timeout check) and the timeout duration.
>
>    - given the changes in logic I've removed Catalin and Haris' R-by and
>      Tested-by.
>
>  include/asm-generic/barrier.h | 58 +++++++++++++++++++++++++++++++++++
>  1 file changed, 58 insertions(+)
>
> diff --git a/include/asm-generic/barrier.h b/include/asm-generic/barrier.h
> index d4f581c1e21d..e25592f9fcbf 100644
> --- a/include/asm-generic/barrier.h
> +++ b/include/asm-generic/barrier.h
> @@ -273,6 +273,64 @@ do {									\
>  })
>  #endif
>
> +/*
> + * Number of times we iterate in the loop before doing the time check.
> + */
> +#ifndef SMP_TIMEOUT_POLL_COUNT
> +#define SMP_TIMEOUT_POLL_COUNT		200
> +#endif
> +
> +#ifndef cpu_poll_relax
> +#define cpu_poll_relax(ptr, val, timeout_ns)	cpu_relax()
> +#endif
> +
> +/**
> + * smp_cond_load_relaxed_timeout() - (Spin) wait for cond with no ordering
> + * guarantees until a timeout expires.
> + * @ptr: pointer to the variable to wait on
> + * @cond: boolean expression to wait for
> + * @time_expr_ns: expression that evaluates to monotonic time (in ns) or,
> + *  on failure, returns a negative value.
> + * @timeout_ns: timeout value in ns
> + * (Both of the above are assumed to be compatible with s64.)
> + *
> + * Equivalent to using READ_ONCE() on the condition variable.
> + */
> +#ifndef smp_cond_load_relaxed_timeout
> +#define smp_cond_load_relaxed_timeout(ptr, cond_expr,			\
> +				      time_expr_ns, timeout_ns)		\
> +({									\
> +	__label__ __out, __done;					\
> +	typeof(ptr) __PTR = (ptr);					\
> +	__unqual_scalar_typeof(*ptr) VAL;				\
> +	u32 __n = 0, __spin = SMP_TIMEOUT_POLL_COUNT;			\
> +	s64 __time_now = (s64)(time_expr_ns);				\
> +	s64 __timeout = (s64)timeout_ns;				\
> +	s64 __time_end = __time_now + __timeout;			\
> +									\
> +	if (__time_now <= 0)						\
> +		goto __out;						\
> +									\
> +	for (;;) {							\
> +		VAL = READ_ONCE(*__PTR);				\
> +		if (cond_expr)						\
> +			goto __done;					\
> +		cpu_poll_relax(__PTR, VAL, __timeout);			\
> +		if (++__n < __spin)					\
> +			continue;					\
> +		__time_now = (s64)(time_expr_ns);			\
> +		__timeout = __time_end - __time_now;			\
> +		if (__time_now <= 0 || __timeout <= 0)			\
> +			goto __out;					\
> +		__n = 0;						\
> +	}								\
> +__out:									\
> +	VAL = READ_ONCE(*__PTR);					\
> +__done:								\
> +	(typeof(*ptr))VAL;						\
> +})
> +#endif
> +
>  /*
>   * pmem_wmb() ensures that all stores for which the modification
>   * are written to persistent storage by preceding instructions have

Alexei Starovoitov pointed out in his review comment on patch-10 that
evaluating time_expr_ns on entry means that this is unusable in the
fastpath of something like lock acquisition (as rqspinlock does).

Something like the following should work better (it also gets rid of the
gotos.)  The only negative is that in the slowpath this would have a
larger overshoot but I think that's a reasonable tradeoff.

I'll be sending out the next version with this changed but just wanted to
gauge any preliminary opinions on this.

Thanks
Ankur

---

diff --git a/include/asm-generic/barrier.h b/include/asm-generic/barrier.h
index d4f581c1e21d..278eb51cf354 100644
--- a/include/asm-generic/barrier.h
+++ b/include/asm-generic/barrier.h
@@ -273,6 +273,73 @@ do {									\
 })
 #endif

+/*
+ * Number of times we iterate in the loop before doing the time check.
+ */
+#ifndef SMP_TIMEOUT_POLL_COUNT
+#define SMP_TIMEOUT_POLL_COUNT		200
+#endif
+
+#ifndef cpu_poll_relax
+#define cpu_poll_relax(ptr, val, timeout_ns)	cpu_relax()
+#endif
+
+/**
+ * smp_cond_load_relaxed_timeout() - (Spin) wait for cond with no ordering
+ * guarantees until a timeout expires.
+ * @ptr: pointer to the variable to wait on
+ * @cond: boolean expression to wait for
+ * @time_expr_ns: expression that evaluates to monotonic time (in ns) or,
+ *  on failure, returns a negative value.
+ * @timeout_ns: timeout value in ns
+ * (Both of the above are assumed to be compatible with s64.)
+ *
+ * Equivalent to using READ_ONCE() on the condition variable.
+ *
+ * Note on timeout overshoot: in the fastpath, we want to keep this as close
+ * to performance as smp_cond_load_relaxed(). To do that we want to defer
+ * the evaluation of the potentially expensive @time_expr_ns to the
+ * earliest time that is needed.
+ *
+ * This means that there will always be some hardware dependent duration
+ * that has already passed inside cpu_poll_relax() at the time of first
+ * evaluation. In addition, cpu_poll_relax() is not guaranteed to return
+ * at timeout boundary.
+ *
+ * In sum, expect timeout overshoot when we return due to expiration of
+ * the timeout.
+ */
+#ifndef smp_cond_load_relaxed_timeout
+#define smp_cond_load_relaxed_timeout(ptr, cond_expr,			\
+				      time_expr_ns, timeout_ns)		\
+({									\
+	typeof(ptr) __PTR = (ptr);					\
+	__unqual_scalar_typeof(*ptr) VAL;				\
+	u32 __n = 0, __spin = SMP_TIMEOUT_POLL_COUNT;			\
+	s64 __timeout = (s64)timeout_ns;				\
+	s64 __time_now, __time_end = 0;					\
+									\
+	for (;;) {							\
+		VAL = READ_ONCE(*__PTR);				\
+		if (cond_expr) 						\
+			break;						\
+		cpu_poll_relax(__PTR, VAL, __timeout);			\
+		if (++__n < __spin)					\
+			continue;					\
+		__time_now = (s64)(time_expr_ns);			\
+		if (unlikely(__time_end == 0))				\
+			__time_end = __time_now + __timeout;		\
+		__timeout = __time_end - __time_now;			\
+		if (__time_now <= 0 || __timeout <= 0) {		\
+			VAL = READ_ONCE(*__PTR);			\
+			break;						\
+		}							\
+		__n = 0;						\
+	}								\
+	(typeof(*ptr))VAL;						\
+})
+#endif
+
 /*
  * pmem_wmb() ensures that all stores for which the modification
  * are written to persistent storage by preceding instructions have


From daniel.baluta at gmail.com  Sun Dec 21 23:48:22 2025
From: daniel.baluta at gmail.com (Daniel Baluta)
Date: Mon, 22 Dec 2025 09:48:22 +0200
Subject: [PATCH v2 1/3] dt-bindings: arm: fsl: add i.MX952 EVK board
In-Reply-To: <20251222-imx952-v1-v2-1-8793ec8bad6e@nxp.com>
References: <20251222-imx952-v1-v2-0-8793ec8bad6e@nxp.com> <20251222-imx952-v1-v2-1-8793ec8bad6e@nxp.com>
Message-ID: <CAEnQRZC44ftit9y3hj3x9tLn7G+o_PFnJUOy6cGkD9iGSJGHXw@mail.gmail.com>

On Mon, Dec 22, 2025 at 3:44?AM Peng Fan (OSS) <peng.fan at oss.nxp.com> wrote:
>
> From: Peng Fan <peng.fan at nxp.com>
>
> Add DT compatible string for NXP i.MX952 EVK board.
>
> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
> Signed-off-by: Peng Fan <peng.fan at nxp.com>

Reviewed-by: Daniel Baluta <daniel.baluta at nxp.com>


From peter.wang at mediatek.com  Mon Dec 22 00:13:00 2025
From: peter.wang at mediatek.com (=?utf-8?B?UGV0ZXIgV2FuZyAo546L5L+h5Y+LKQ==?=)
Date: Mon, 22 Dec 2025 08:13:00 +0000
Subject: [PATCH][next] scsi: ufs: host: mediatek: make read-only array
 scale_us static const
In-Reply-To: <20251219214428.492744-1-colin.i.king@gmail.com>
References: <20251219214428.492744-1-colin.i.king@gmail.com>
Message-ID: <65daa0cefe5c09d138bdc545be23be9e58d7e762.camel@mediatek.com>

On Fri, 2025-12-19 at 21:44 +0000, Colin Ian King wrote:
> Don't populate the read-only array scale_us on the stack at run time,
> instead make it static const.
> 
> Signed-off-by: Colin Ian King <colin.i.king at gmail.com>
> ---
> ?drivers/ufs/host/ufs-mediatek.c | 2 +-
> ?1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-
> mediatek.c
> index ecbbf52bf734..66b11cc0703b 100644
> --- a/drivers/ufs/host/ufs-mediatek.c
> +++ b/drivers/ufs/host/ufs-mediatek.c
> @@ -1112,7 +1112,7 @@ static void ufs_mtk_setup_clk_gating(struct
> ufs_hba *hba)
> ??????? unsigned long flags;
> ??????? u32 ah_ms = 10;
> ??????? u32 ah_scale, ah_timer;
> -?????? u32 scale_us[] = {1, 10, 100, 1000, 10000, 100000};
> +?????? static const u32 scale_us[] = {1, 10, 100, 1000, 10000,
> 100000};
> 

Reviewed-by: Peter Wang <peter.wang at mediatek.com>



From mchehab+huawei at kernel.org  Mon Dec 22 00:13:34 2025
From: mchehab+huawei at kernel.org (Mauro Carvalho Chehab)
Date: Mon, 22 Dec 2025 09:13:34 +0100
Subject: [PATCH 03/12] ras: add estatus vendor handling and processing
In-Reply-To: <20251219181226.2859763-1-ahmed.tiba@arm.com>
References: <euhams5heiuaawxq4e5ty7iijuvwt5gvdx3flsm4npligjeulq@lv3cwekyb2o2>
	<20251219181226.2859763-1-ahmed.tiba@arm.com>
Message-ID: <20251222091334.5cb8465f@foz.lan>

Em Fri, 19 Dec 2025 18:11:54 +0000
Ahmed Tiba <ahmed.tiba at arm.com> escreveu:

> On Fri, Dec 19, 2025 at 04:30:40PM +0100, Mauro Carvalho Chehab wrote:
> >On Fri, Dec 19, 2025 at 02:49:02PM +0000, Ahmed Tiba wrote:  
> >>
> >> On Wed, Dec 18, 2025 at 05:04:53PM +0100, Mauro Carvalho Chehab wrote:
> >>  
> >> >> Teach the estatus core how to walk CPER records and expose the vendor
> >> >> record notification path. This adds the section iteration helpers,
> >> >> the logging helpers that mirror the GHES behaviour, and the deferred
> >> >> work used to hand vendor GUIDs to interested drivers. No users switch
> >> >> over yet; this simply moves the common logic out of GHES so the next
> >> >> patches can wire it up.
> >> >>
> >> >> Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com>  
> >> >
> >> >...
> >> >  
> >> >> +static bool estatus_handle_arm_hw_error(estatus_generic_data *gdata, int sev, bool sync)  
> >> >
> >> > Huh?
> >> >
> >> > This is a CPER record from GHES. Why are you moving CPER code out
> >> > of ghes.c, placing in a file named estatus.c? Doesn't make much
> >> > sense on my eyes...
> >> >
> >> > Same applies to to other GHES CPER record types.  
> >>
> >> GHES still fills in the CPER record, but the parsing and logging logic is
> >> shared with the new DeviceTree provider so I pulled those helpers into the
> >> estatus core.  
> >
> > I see, but this is not really estatus core. Instead, it is part of GHES CPER
> > handling logic, which is defined at ACPI and UEFI specs. moving it to estatus
> > sounds odd, at least on my eyes.
> > 
> > Perhaps I'm failing to see where at ACPI/UEFI specs how CPER would be
> > integrated with an OpenFirmware approach to handle CPER without GHES.
> > Care to point to the relevant specs, if any?  
> 
> ACPI/APEI (via GHES) defines how CPER records are discovered and notified on ACPI systems,
> but there is no ACPI or UEFI-defined equivalent for OpenFirmware/DeviceTree platforms.
> UEFI standardises the CPER record format itself, not the transport or discovery mechanism.
> 
> On non-ACPI systems we still receive the same UEFI-defined CPER payload
> from firmware, but Linux needs a different, platform-specific contract
> to locate and acknowledge it. The DT binding is a Linux-side description
> of that contract rather than something defined by ACPI/UEFI.

That's where I'm failing to understand: CPER is part of UEFI spec, and
the only deliverable mechanism I'm aware of for CPER is via GHES or
GHESv2 - e.g. via ACPI.

Within the scope of https://uefi.org/specifications, I'm failing
to see any other deliverable mechanism.
 
> >> Both providers already call into the same notifier chain and
> >> memory-pool helpers; this patch just moves the generic CPER walking routines
> >> next to the rest of the common code so the DT path doesn?t have to grow its
> >> own copy. If you?d prefer a different file layout or naming to make that
> >> intent clearer, I?m happy to adjust.  
> 
> > Moving the code from ghes.c to estatus.c or to elsewhere shouldn't make any
> > difference, as the DT handling logic could simply be calling the functions
> > from ghes.c (or estatus.c). I fail to see why they need to be moved.  
> 
> The motivation is to provide a shared implementation for non-ACPI providers,
> so that the DT path does not depend on ACPI/APEI.
> 
> While the helpers currently live in ghes.c, they are CPER-specific and do not rely on ACPI tables,
> APEI infrastructure, or GHES notification semantics. Keeping them there effectively makes GHES
> the only place those helpers can live, even though the logic itself is provider-agnostic.

The logic is related to GHES, as this seems to be the only standardized
mechanism to report CPER records. As it is part of APEI, get_maintainers
points to the people that have been maintaining it as:

	$ ./scripts/get_maintainer.pl -f ./drivers/acpi/apei/ghes.c
	"Rafael J. Wysocki" <rafael at kernel.org> (maintainer:ACPI APEI,commit_signer:6/13=46%)
	Tony Luck <tony.luck at intel.com> (reviewer:ACPI APEI,commit_signer:3/13=23%)
	Borislav Petkov <bp at alien8.de> (reviewer:ACPI APEI,removed_lines:5/62=8%)
	Hanjun Guo <guohanjun at huawei.com> (reviewer:ACPI APEI,commit_signer:4/13=31%)
	Mauro Carvalho Chehab <mchehab at kernel.org> (reviewer:ACPI APEI,authored:1/13=8%,removed_lines:6/62=10%)
	Shuai Xue <xueshuai at linux.alibaba.com> (reviewer:ACPI APEI,commit_signer:5/13=38%,authored:2/13=15%,added_lines:56/218=26%,removed_lines:34/62=55%)
	Len Brown <lenb at kernel.org> (reviewer:ACPI)
	Jonathan Cameron <Jonathan.Cameron at huawei.com> (commit_signer:5/13=38%)
	Breno Leitao <leitao at debian.org> (authored:2/13=15%,added_lines:38/218=17%)
	Smita Koralahalli <Smita.KoralahalliChannabasappa at amd.com> (authored:2/13=15%,added_lines:103/218=47%)
	Ankit Agrawal <ankita at nvidia.com> (authored:1/13=8%,removed_lines:6/62=10%)
	Jason Tian <jason at os.amperecomputing.com> (removed_lines:7/62=11%)
	linux-acpi at vger.kernel.org (open list:ACPI APEI)
	linux-kernel at vger.kernel.org (open list)

Moving it elsewhere would make it confusing, as the expected deliverable
mechanism for CPER is via GHES - as this is the only one defined at the
uefi.org specs.

While it might be moved to EFI and placed under cper.c, 
get_maintainers.pl would point to:

	$ ./scripts/get_maintainer.pl -f ./drivers/firmware/efi/cper.c
	Ard Biesheuvel <ardb at kernel.org> (maintainer:EXTENSIBLE FIRMWARE INTERFACE (EFI))
	linux-efi at vger.kernel.org (open list:EXTENSIBLE FIRMWARE INTERFACE (EFI))
	linux-kernel at vger.kernel.org (open list)

which is not the people that have been maintaining RAS.

Placing it under a "estatus.c" file would make it completely
dissociated with UEFI/ACPI specs, as this name means nothing at
the specs.

Also, adding a new maintainer's entry won't make any sense, as the
people that currently reviews and maintains GHES/CPER records
should be kept.

> By moving the CPER parsing and logging pieces into a common location,
> both GHES and the DT provider can reuse the same implementation,
> while the ACPI-specific discovery and notification code remains under drivers/acpi/apei/.
> This avoids having the DT provider reach into GHES internals or duplicate CPER handling code.

As Boris mentioned on patch 00/12, we need to better understand
the high level scenario, as it is still not clear to me how a
firmware-first notification would happen without ACPI.

> If the current naming or file layout makes that separation unclear, I?m happy to adjust it.

Thanks,
Mauro


From alexander.stein at ew.tq-group.com  Mon Dec 22 00:18:08 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Mon, 22 Dec 2025 09:18:08 +0100
Subject: [PATCH 1/2] arm64: dts: tqma8mpql-mba8mpxl: Configure multiple queues on eqos
Message-ID: <20251222081812.1120998-1-alexander.stein@ew.tq-group.com>

The MBa8MPxL mainboard has an integrated PHY connected to the EQOS
ethernet controller which can support up to five queues. Configure
these queues in the same manor as done on the imx8mp-evk.
Setting DMA to threas mode is necessary to prevent FIFO overflows, see
commit 0bc3e333a0c82 ("arm64: dts: imx8mp-evk: configure multiple queues
on eqos")

Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 .../freescale/imx8mp-tqma8mpql-mba8mpxl.dts   | 67 +++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
index 68cecb0987b6b..eb25828f3b26d 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
@@ -360,6 +360,9 @@ &eqos {
 	pinctrl-0 = <&pinctrl_eqos>, <&pinctrl_eqos_phy>;
 	phy-mode = "rgmii-id";
 	phy-handle = <&ethphy3>;
+	snps,force_thresh_dma_mode;
+	snps,mtl-tx-config = <&mtl_tx_setup>;
+	snps,mtl-rx-config = <&mtl_rx_setup>;
 	status = "okay";
 
 	mdio {
@@ -404,6 +407,70 @@ led at 2 {
 			};
 		};
 	};
+
+	mtl_tx_setup: tx-queues-config {
+		snps,tx-queues-to-use = <5>;
+
+		queue0 {
+			snps,dcb-algorithm;
+			snps,priority = <0x1>;
+		};
+
+		queue1 {
+			snps,dcb-algorithm;
+			snps,priority = <0x2>;
+		};
+
+		queue2 {
+			snps,dcb-algorithm;
+			snps,priority = <0x4>;
+		};
+
+		queue3 {
+			snps,dcb-algorithm;
+			snps,priority = <0x8>;
+		};
+
+		queue4 {
+			snps,dcb-algorithm;
+			snps,priority = <0xf0>;
+		};
+	};
+
+	mtl_rx_setup: rx-queues-config {
+		snps,rx-queues-to-use = <5>;
+		snps,rx-sched-sp;
+
+		queue0 {
+			snps,dcb-algorithm;
+			snps,priority = <0x1>;
+			snps,map-to-dma-channel = <0>;
+		};
+
+		queue1 {
+			snps,dcb-algorithm;
+			snps,priority = <0x2>;
+			snps,map-to-dma-channel = <1>;
+		};
+
+		queue2 {
+			snps,dcb-algorithm;
+			snps,priority = <0x4>;
+			snps,map-to-dma-channel = <2>;
+		};
+
+		queue3 {
+			snps,dcb-algorithm;
+			snps,priority = <0x8>;
+			snps,map-to-dma-channel = <3>;
+		};
+
+		queue4 {
+			snps,dcb-algorithm;
+			snps,priority = <0xf0>;
+			snps,map-to-dma-channel = <4>;
+		};
+	};
 };
 
 &fec {
-- 
2.43.0



From alexander.stein at ew.tq-group.com  Mon Dec 22 00:18:09 2025
From: alexander.stein at ew.tq-group.com (Alexander Stein)
Date: Mon, 22 Dec 2025 09:18:09 +0100
Subject: [PATCH 2/2] arm64: dts: tqma8mpql-mba8mp-ras314: Configure multiple queues on eqos
In-Reply-To: <20251222081812.1120998-1-alexander.stein@ew.tq-group.com>
References: <20251222081812.1120998-1-alexander.stein@ew.tq-group.com>
Message-ID: <20251222081812.1120998-2-alexander.stein@ew.tq-group.com>

The MBa8MP-RAS314 mainboard has an integrated PHY connected to the EQOS
ethernet controller which can support up to five queues. Configure
these queues in the same manor as done on the imx8mp-evk.
Setting DMA to threas mode is necessary to prevent FIFO overflows, see
commit 0bc3e333a0c82 ("arm64: dts: imx8mp-evk: configure multiple queues
on eqos")

Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
---
 .../imx8mp-tqma8mpql-mba8mp-ras314.dts        | 67 +++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts
index 204bbf0719890..b0d058833fbbb 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts
@@ -184,6 +184,9 @@ &eqos {
 	pinctrl-0 = <&pinctrl_eqos>;
 	phy-mode = "rgmii-id";
 	phy-handle = <&ethphy3>;
+	snps,force_thresh_dma_mode;
+	snps,mtl-tx-config = <&mtl_tx_setup>;
+	snps,mtl-rx-config = <&mtl_rx_setup>;
 	status = "okay";
 
 	mdio {
@@ -209,6 +212,70 @@ ethphy3: ethernet-phy at 3 {
 			ti,clk-output-sel = <DP83867_CLK_O_SEL_OFF>;
 		};
 	};
+
+	mtl_tx_setup: tx-queues-config {
+		snps,tx-queues-to-use = <5>;
+
+		queue0 {
+			snps,dcb-algorithm;
+			snps,priority = <0x1>;
+		};
+
+		queue1 {
+			snps,dcb-algorithm;
+			snps,priority = <0x2>;
+		};
+
+		queue2 {
+			snps,dcb-algorithm;
+			snps,priority = <0x4>;
+		};
+
+		queue3 {
+			snps,dcb-algorithm;
+			snps,priority = <0x8>;
+		};
+
+		queue4 {
+			snps,dcb-algorithm;
+			snps,priority = <0xf0>;
+		};
+	};
+
+	mtl_rx_setup: rx-queues-config {
+		snps,rx-queues-to-use = <5>;
+		snps,rx-sched-sp;
+
+		queue0 {
+			snps,dcb-algorithm;
+			snps,priority = <0x1>;
+			snps,map-to-dma-channel = <0>;
+		};
+
+		queue1 {
+			snps,dcb-algorithm;
+			snps,priority = <0x2>;
+			snps,map-to-dma-channel = <1>;
+		};
+
+		queue2 {
+			snps,dcb-algorithm;
+			snps,priority = <0x4>;
+			snps,map-to-dma-channel = <2>;
+		};
+
+		queue3 {
+			snps,dcb-algorithm;
+			snps,priority = <0x8>;
+			snps,map-to-dma-channel = <3>;
+		};
+
+		queue4 {
+			snps,dcb-algorithm;
+			snps,priority = <0xf0>;
+			snps,map-to-dma-channel = <4>;
+		};
+	};
 };
 
 &fec {
-- 
2.43.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:19 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:19 +1300
Subject: [PATCH v7 02/31] dyndbg: add stub macro for DECLARE_DYNDBG_CLASSMAP
Message-ID: <20251222082049.1782440-3-jim.cromie@gmail.com>

Add the stub macro for !DYNAMIC_DEBUG builds, after moving the
original macro-defn down under the big ifdef.  Do it now so future
changes have a cleaner starting point.

Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 include/linux/dynamic_debug.h | 43 ++++++++++++++++++-----------------
 1 file changed, 22 insertions(+), 21 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index ff44ec346162..98a36e2f94b6 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -92,27 +92,6 @@ struct ddebug_class_map {
 	enum class_map_type map_type;
 };
 
-/**
- * DECLARE_DYNDBG_CLASSMAP - declare classnames known by a module
- * @_var:   a struct ddebug_class_map, passed to module_param_cb
- * @_type:  enum class_map_type, chooses bits/verbose, numeric/symbolic
- * @_base:  offset of 1st class-name. splits .class_id space
- * @classes: class-names used to control class'd prdbgs
- */
-#define DECLARE_DYNDBG_CLASSMAP(_var, _maptype, _base, ...)		\
-	static const char *_var##_classnames[] = { __VA_ARGS__ };	\
-	static struct ddebug_class_map __aligned(8) __used		\
-		__section("__dyndbg_classes") _var = {			\
-		.mod = THIS_MODULE,					\
-		.mod_name = KBUILD_MODNAME,				\
-		.base = _base,						\
-		.map_type = _maptype,					\
-		.length = NUM_TYPE_ARGS(char*, __VA_ARGS__),		\
-		.class_names = _var##_classnames,			\
-	}
-#define NUM_TYPE_ARGS(eltype, ...)				\
-        (sizeof((eltype[]){__VA_ARGS__}) / sizeof(eltype))
-
 /* encapsulate linker provided built-in (or module) dyndbg data */
 struct _ddebug_info {
 	struct _ddebug *descs;
@@ -137,6 +116,27 @@ struct ddebug_class_param {
 #if defined(CONFIG_DYNAMIC_DEBUG) || \
 	(defined(CONFIG_DYNAMIC_DEBUG_CORE) && defined(DYNAMIC_DEBUG_MODULE))
 
+/**
+ * DECLARE_DYNDBG_CLASSMAP - declare classnames known by a module
+ * @_var:   a struct ddebug_class_map, passed to module_param_cb
+ * @_type:  enum class_map_type, chooses bits/verbose, numeric/symbolic
+ * @_base:  offset of 1st class-name. splits .class_id space
+ * @classes: class-names used to control class'd prdbgs
+ */
+#define DECLARE_DYNDBG_CLASSMAP(_var, _maptype, _base, ...)		\
+	static const char *_var##_classnames[] = { __VA_ARGS__ };	\
+	static struct ddebug_class_map __aligned(8) __used		\
+		__section("__dyndbg_classes") _var = {			\
+		.mod = THIS_MODULE,					\
+		.mod_name = KBUILD_MODNAME,				\
+		.base = _base,						\
+		.map_type = _maptype,					\
+		.length = NUM_TYPE_ARGS(char*, __VA_ARGS__),		\
+		.class_names = _var##_classnames,			\
+	}
+#define NUM_TYPE_ARGS(eltype, ...)				\
+	(sizeof((eltype[]) {__VA_ARGS__}) / sizeof(eltype))
+
 extern __printf(2, 3)
 void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...);
 
@@ -303,6 +303,7 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
 
 #define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt)
 #define DYNAMIC_DEBUG_BRANCH(descriptor) false
+#define DECLARE_DYNDBG_CLASSMAP(...)
 
 #define dynamic_pr_debug(fmt, ...)					\
 	no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:20 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:20 +1300
Subject: [PATCH v7 03/31] docs/dyndbg: update examples \012 to \n
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-4-jim.cromie@gmail.com>

commit 47ea6f99d06e ("dyndbg: use ESCAPE_SPACE for cat control")
changed the control-file to display format strings with "\n" rather
than "\012".  Update the docs to match the new reality.

Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
Tested-by: Louis Chauvet <louis.chauvet at bootlin.com>
Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 .../admin-guide/dynamic-debug-howto.rst       | 20 +++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst
index 7c036590cd07..4ac18c0a1d95 100644
--- a/Documentation/admin-guide/dynamic-debug-howto.rst
+++ b/Documentation/admin-guide/dynamic-debug-howto.rst
@@ -38,12 +38,12 @@ You can view the currently configured behaviour in the *prdbg* catalog::
 
   :#> head -n7 /proc/dynamic_debug/control
   # filename:lineno [module]function flags format
-  init/main.c:1179 [main]initcall_blacklist =_ "blacklisting initcall %s\012
-  init/main.c:1218 [main]initcall_blacklisted =_ "initcall %s blacklisted\012"
-  init/main.c:1424 [main]run_init_process =_ "  with arguments:\012"
-  init/main.c:1426 [main]run_init_process =_ "    %s\012"
-  init/main.c:1427 [main]run_init_process =_ "  with environment:\012"
-  init/main.c:1429 [main]run_init_process =_ "    %s\012"
+  init/main.c:1179 [main]initcall_blacklist =_ "blacklisting initcall %s\n"
+  init/main.c:1218 [main]initcall_blacklisted =_ "initcall %s blacklisted\n"
+  init/main.c:1424 [main]run_init_process =_ "  with arguments:\n"
+  init/main.c:1426 [main]run_init_process =_ "    %s\n"
+  init/main.c:1427 [main]run_init_process =_ "  with environment:\n"
+  init/main.c:1429 [main]run_init_process =_ "    %s\n"
 
 The 3rd space-delimited column shows the current flags, preceded by
 a ``=`` for easy use with grep/cut. ``=p`` shows enabled callsites.
@@ -59,10 +59,10 @@ query/commands to the control file.  Example::
 
   :#> ddcmd '-p; module main func run* +p'
   :#> grep =p /proc/dynamic_debug/control
-  init/main.c:1424 [main]run_init_process =p "  with arguments:\012"
-  init/main.c:1426 [main]run_init_process =p "    %s\012"
-  init/main.c:1427 [main]run_init_process =p "  with environment:\012"
-  init/main.c:1429 [main]run_init_process =p "    %s\012"
+  init/main.c:1424 [main]run_init_process =p "  with arguments:\n"
+  init/main.c:1426 [main]run_init_process =p "    %s\n"
+  init/main.c:1427 [main]run_init_process =p "  with environment:\n"
+  init/main.c:1429 [main]run_init_process =p "    %s\n"
 
 Error messages go to console/syslog::
 
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:21 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:21 +1300
Subject: [PATCH v7 04/31] docs/dyndbg: explain flags parse 1st
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-5-jim.cromie@gmail.com>

When writing queries to >control, flags are parsed 1st, since they are
the only required field, and they require specific compositions.  So
if the flags draw an error (on those specifics), then keyword errors
aren't reported.  This can be mildly confusing/annoying, so explain it
instead.

cc: linux-doc at vger.kernel.org
Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 .../admin-guide/dynamic-debug-howto.rst         | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst
index 4ac18c0a1d95..e76ccd987704 100644
--- a/Documentation/admin-guide/dynamic-debug-howto.rst
+++ b/Documentation/admin-guide/dynamic-debug-howto.rst
@@ -109,10 +109,19 @@ The match-spec's select *prdbgs* from the catalog, upon which to apply
 the flags-spec, all constraints are ANDed together.  An absent keyword
 is the same as keyword "*".
 
-
-A match specification is a keyword, which selects the attribute of
-the callsite to be compared, and a value to compare against.  Possible
-keywords are:::
+Note that since the match-spec can be empty, the flags are checked 1st,
+then the pairs of keyword and value.  Flag errs will hide keyword errs::
+
+  bash-5.2# ddcmd mod bar +foo
+  dyndbg: read 13 bytes from userspace
+  dyndbg: query 0: "mod bar +foo" mod:*
+  dyndbg: unknown flag 'o'
+  dyndbg: flags parse failed
+  dyndbg: processed 1 queries, with 0 matches, 1 errs
+
+So a match-spec is a keyword, which selects the attribute of the
+callsite to be compared, and a value to compare against.  Possible
+keywords are::
 
   match-spec ::= 'func' string |
 		 'file' string |
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:22 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:22 +1300
Subject: [PATCH v7 05/31] test-dyndbg: fixup CLASSMAP usage error
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-6-jim.cromie@gmail.com>

commit 6ea3bf466ac6 ("dyndbg: test DECLARE_DYNDBG_CLASSMAP, sysfs nodes")

A closer look at test_dynamic_debug.ko logging output reveals a macro
usage error:

lib/test_dynamic_debug.c:105 [test_dynamic_debug]do_cats =p "LOW msg\n" class:MID
lib/test_dynamic_debug.c:106 [test_dynamic_debug]do_cats =p "MID msg\n" class:HI
lib/test_dynamic_debug.c:107 [test_dynamic_debug]do_cats =_ "HI msg\n" class unknown, _id:13

107 says: HI is unknown, and 105,106 have a LOW/MID and MID/HI skew.

DECLARE_DYNDBG_CLASSMAP() _base arg must equal the enum's 1st value,
in this case it was _base + 1.  This leaves HI class un-selectable.

NB: the macro could better validate its arguments.

Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
Tested-by: Louis Chauvet <louis.chauvet at bootlin.com>
Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 lib/test_dynamic_debug.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
index 77c2a669b6af..396144cf351b 100644
--- a/lib/test_dynamic_debug.c
+++ b/lib/test_dynamic_debug.c
@@ -75,7 +75,7 @@ DD_SYS_WRAP(disjoint_bits, p);
 DD_SYS_WRAP(disjoint_bits, T);
 
 /* symbolic input, independent bits */
-enum cat_disjoint_names { LOW = 11, MID, HI };
+enum cat_disjoint_names { LOW = 10, MID, HI };
 DECLARE_DYNDBG_CLASSMAP(map_disjoint_names, DD_CLASS_TYPE_DISJOINT_NAMES, 10,
 			"LOW", "MID", "HI");
 DD_SYS_WRAP(disjoint_names, p);
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:23 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:23 +1300
Subject: [PATCH v7 06/31] dyndbg: reword "class unknown," to "class:_UNKNOWN_"
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-7-jim.cromie@gmail.com>

When a dyndbg classname is unknown to a kernel module (as before
previous patch), the callsite is un-addressable via >control queries.

The control-file displays this condition as "class unknown,"
currently.  That spelling is sub-optimal/too-generic, so change it to
"class:_UNKNOWN_" to loudly announce the erroneous situation, and to
make it uniquely greppable.

Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 lib/dynamic_debug.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index eb5146bcfaca..cb171088850c 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -1165,7 +1165,7 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
 		if (class)
 			seq_printf(m, " class:%s", class);
 		else
-			seq_printf(m, " class unknown, _id:%d", dp->class_id);
+			seq_printf(m, " class:_UNKNOWN_ _id:%d", dp->class_id);
 	}
 	seq_putc(m, '\n');
 
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:24 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:24 +1300
Subject: [PATCH v7 07/31] dyndbg: make ddebug_class_param union members same size
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-8-jim.cromie@gmail.com>

struct ddebug_class_param keeps a ref to the state-storage of the
param; make both class-types use the same unsigned long storage type.

ISTM this is simpler and safer; it avoids an irrelevant difference,
and if 2 users somehow get class-type mixed up (or refer to the wrong
union member), at least they will both see the same value.

Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 include/linux/dynamic_debug.h | 2 +-
 lib/dynamic_debug.c           | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 98a36e2f94b6..4b7c3b997657 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -103,7 +103,7 @@ struct _ddebug_info {
 struct ddebug_class_param {
 	union {
 		unsigned long *bits;
-		unsigned int *lvl;
+		unsigned long *lvl;
 	};
 	char flags[8];
 	const struct ddebug_class_map *map;
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index cb171088850c..d2ff203d0873 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -810,7 +810,7 @@ int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp)
 
 	case DD_CLASS_TYPE_LEVEL_NAMES:
 	case DD_CLASS_TYPE_LEVEL_NUM:
-		return scnprintf(buffer, PAGE_SIZE, "%d\n", *dcp->lvl);
+		return scnprintf(buffer, PAGE_SIZE, "%ld\n", *dcp->lvl);
 	default:
 		return -1;
 	}
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:25 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:25 +1300
Subject: [PATCH v7 08/31] dyndbg: drop NUM_TYPE_ARRAY
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-9-jim.cromie@gmail.com>

ARRAY_SIZE works here, since array decl is complete.

no functional change

Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 include/linux/dynamic_debug.h | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 4b7c3b997657..c4ae79f934d9 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -131,11 +131,9 @@ struct ddebug_class_param {
 		.mod_name = KBUILD_MODNAME,				\
 		.base = _base,						\
 		.map_type = _maptype,					\
-		.length = NUM_TYPE_ARGS(char*, __VA_ARGS__),		\
+		.length = ARRAY_SIZE(_var##_classnames),		\
 		.class_names = _var##_classnames,			\
 	}
-#define NUM_TYPE_ARGS(eltype, ...)				\
-	(sizeof((eltype[]) {__VA_ARGS__}) / sizeof(eltype))
 
 extern __printf(2, 3)
 void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...);
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:26 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:26 +1300
Subject: [PATCH v7 09/31] dyndbg: tweak pr_fmt to avoid expansion conflicts
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-10-jim.cromie@gmail.com>

Disambiguate pr_fmt(fmt) arg, by changing it to _FMT_, to avoid naming
confusion with many later macros also using that argname.

no functional change

Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 lib/dynamic_debug.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index d2ff203d0873..21c1db7e8705 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -11,7 +11,7 @@
  * Copyright (C) 2013 Du, Changbin <changbin.du at gmail.com>
  */
 
-#define pr_fmt(fmt) "dyndbg: " fmt
+#define pr_fmt(_FMT_) "dyndbg: " _FMT_
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:27 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:27 +1300
Subject: [PATCH v7 10/31] dyndbg: reduce verbose/debug clutter
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-11-jim.cromie@gmail.com>

currently, for verbose=3, these are logged (blank lines for clarity):

 dyndbg: query 0: "class DRM_UT_CORE +p" mod:*
 dyndbg: split into words: "class" "DRM_UT_CORE" "+p"

 dyndbg: op='+'
 dyndbg: flags=0x1
 dyndbg: *flagsp=0x1 *maskp=0xffffffff

 dyndbg: parsed: func="" file="" module="" format="" lineno=0-0 class=...
 dyndbg: no matches for query
 dyndbg: no-match: func="" file="" module="" format="" lineno=0-0 class=...
 dyndbg: processed 1 queries, with 0 matches, 0 errs

That is excessive, so this patch:
 - shrinks 3 lines of 2nd stanza to single line
 - drops 1st 2 lines of 3rd stanza
   3rd line is like 1st, with result, not procedure.
   2nd line is just status, retold in 4th, with more info.

New output:

 dyndbg: query 0: "class DRM_UT_CORE +p" mod:*
 dyndbg: split into words: "class" "DRM_UT_CORE" "+p"
 dyndbg: op='+' flags=0x1 *flagsp=0x1 *maskp=0xffffffff
 dyndbg: no-match: func="" file="" module="" format="" lineno=0-0 class=...
 dyndbg: processed 1 queries, with 0 matches, 0 errs

Also reduce verbose=3 messages in ddebug_add_module

When modprobing a module, dyndbg currently logs/says "add-module", and
then "skipping" if the module has no prdbgs.  Instead just check 1st
and return quietly.

no functional change

Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 lib/dynamic_debug.c | 21 ++++++---------------
 1 file changed, 6 insertions(+), 15 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 21c1db7e8705..1db2f627237a 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -275,9 +275,6 @@ static int ddebug_change(const struct ddebug_query *query,
 	}
 	mutex_unlock(&ddebug_lock);
 
-	if (!nfound && verbose)
-		pr_info("no matches for query\n");
-
 	return nfound;
 }
 
@@ -510,7 +507,6 @@ static int ddebug_parse_flags(const char *str, struct flag_settings *modifiers)
 		pr_err("bad flag-op %c, at start of %s\n", *str, str);
 		return -EINVAL;
 	}
-	v3pr_info("op='%c'\n", op);
 
 	for (; *str ; ++str) {
 		for (i = ARRAY_SIZE(opt_array) - 1; i >= 0; i--) {
@@ -524,7 +520,6 @@ static int ddebug_parse_flags(const char *str, struct flag_settings *modifiers)
 			return -EINVAL;
 		}
 	}
-	v3pr_info("flags=0x%x\n", modifiers->flags);
 
 	/* calculate final flags, mask based upon op */
 	switch (op) {
@@ -540,7 +535,7 @@ static int ddebug_parse_flags(const char *str, struct flag_settings *modifiers)
 		modifiers->flags = 0;
 		break;
 	}
-	v3pr_info("*flagsp=0x%x *maskp=0x%x\n", modifiers->flags, modifiers->mask);
+	v3pr_info("op='%c' flags=0x%x maskp=0x%x\n", op, modifiers->flags, modifiers->mask);
 
 	return 0;
 }
@@ -550,7 +545,7 @@ static int ddebug_exec_query(char *query_string, const char *modname)
 	struct flag_settings modifiers = {};
 	struct ddebug_query query = {};
 #define MAXWORDS 9
-	int nwords, nfound;
+	int nwords;
 	char *words[MAXWORDS];
 
 	nwords = ddebug_tokenize(query_string, words, MAXWORDS);
@@ -568,10 +563,7 @@ static int ddebug_exec_query(char *query_string, const char *modname)
 		return -EINVAL;
 	}
 	/* actually go and implement the change */
-	nfound = ddebug_change(&query, &modifiers);
-	vpr_info_dq(&query, nfound ? "applied" : "no-match");
-
-	return nfound;
+	return ddebug_change(&query, &modifiers);
 }
 
 /* handle multiple queries in query string, continue on error, return
@@ -1245,11 +1237,10 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
 {
 	struct ddebug_table *dt;
 
-	v3pr_info("add-module: %s.%d sites\n", modname, di->num_descs);
-	if (!di->num_descs) {
-		v3pr_info(" skip %s\n", modname);
+	if (!di->num_descs)
 		return 0;
-	}
+
+	v3pr_info("add-module: %s %d sites\n", modname, di->num_descs);
 
 	dt = kzalloc(sizeof(*dt), GFP_KERNEL);
 	if (dt == NULL) {
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:28 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:28 +1300
Subject: [PATCH v7 11/31] dyndbg: refactor param_set_dyndbg_classes and below
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-12-jim.cromie@gmail.com>

Refactor callchain below param_set_dyndbg_classes(1) to allow mod-name
specific settings.  Split (1) into upper/lower fns, adding modname
param to lower, and passing NULL in from upper.  Below that, add the
same param to ddebug_apply_class_bitmap(), and pass it thru to
_ddebug_queries(), replacing NULL with the param.

This allows the callchain to update the classmap in just one module,
vs just all as currently done.  While the sysfs param is unlikely to
ever update just one module, the callchain will be used for modprobe
handling, which should update only that just-probed module.

In ddebug_apply_class_bitmap(), also check for actual changes to the
bits before announcing them, to declutter logs.

No functional change.

Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 lib/dynamic_debug.c | 65 ++++++++++++++++++++++++++++-----------------
 1 file changed, 40 insertions(+), 25 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 1db2f627237a..64d69f5cba1b 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -604,9 +604,10 @@ static int ddebug_exec_queries(char *query, const char *modname)
 	return nfound;
 }
 
-/* apply a new bitmap to the sys-knob's current bit-state */
+/* apply a new class-param setting */
 static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
-				     unsigned long *new_bits, unsigned long *old_bits)
+				     unsigned long *new_bits, unsigned long *old_bits,
+				     const char *query_modname)
 {
 #define QUERY_SIZE 128
 	char query[QUERY_SIZE];
@@ -614,7 +615,9 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
 	int matches = 0;
 	int bi, ct;
 
-	v2pr_info("apply: 0x%lx to: 0x%lx\n", *new_bits, *old_bits);
+	if (*new_bits != *old_bits)
+		v2pr_info("apply bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits,
+			  *old_bits, query_modname ?: "'*'");
 
 	for (bi = 0; bi < map->length; bi++) {
 		if (test_bit(bi, new_bits) == test_bit(bi, old_bits))
@@ -623,12 +626,16 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
 		snprintf(query, QUERY_SIZE, "class %s %c%s", map->class_names[bi],
 			 test_bit(bi, new_bits) ? '+' : '-', dcp->flags);
 
-		ct = ddebug_exec_queries(query, NULL);
+		ct = ddebug_exec_queries(query, query_modname);
 		matches += ct;
 
 		v2pr_info("bit_%d: %d matches on class: %s -> 0x%lx\n", bi,
 			  ct, map->class_names[bi], *new_bits);
 	}
+	if (*new_bits != *old_bits)
+		v2pr_info("applied bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits,
+			  *old_bits, query_modname ?: "'*'");
+
 	return matches;
 }
 
@@ -683,7 +690,7 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa
 				continue;
 			}
 			curr_bits ^= BIT(cls_id);
-			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, dcp->bits);
+			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, dcp->bits, NULL);
 			*dcp->bits = curr_bits;
 			v2pr_info("%s: changed bit %d:%s\n", KP_NAME(kp), cls_id,
 				  map->class_names[cls_id]);
@@ -693,7 +700,7 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa
 			old_bits = CLASSMAP_BITMASK(*dcp->lvl);
 			curr_bits = CLASSMAP_BITMASK(cls_id + (wanted ? 1 : 0 ));
 
-			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, &old_bits);
+			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, &old_bits, NULL);
 			*dcp->lvl = (cls_id + (wanted ? 1 : 0));
 			v2pr_info("%s: changed bit-%d: \"%s\" %lx->%lx\n", KP_NAME(kp), cls_id,
 				  map->class_names[cls_id], old_bits, curr_bits);
@@ -707,18 +714,9 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa
 	return 0;
 }
 
-/**
- * param_set_dyndbg_classes - class FOO >control
- * @instr: string echo>d to sysfs, input depends on map_type
- * @kp:    kp->arg has state: bits/lvl, map, map_type
- *
- * Enable/disable prdbgs by their class, as given in the arguments to
- * DECLARE_DYNDBG_CLASSMAP.  For LEVEL map-types, enforce relative
- * levels by bitpos.
- *
- * Returns: 0 or <0 if error.
- */
-int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
+static int param_set_dyndbg_module_classes(const char *instr,
+					   const struct kernel_param *kp,
+					   const char *mod_name)
 {
 	const struct ddebug_class_param *dcp = kp->arg;
 	const struct ddebug_class_map *map = dcp->map;
@@ -755,8 +753,8 @@ int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
 				KP_NAME(kp), inrep, CLASSMAP_BITMASK(map->length));
 			inrep &= CLASSMAP_BITMASK(map->length);
 		}
-		v2pr_info("bits:%lx > %s\n", inrep, KP_NAME(kp));
-		totct += ddebug_apply_class_bitmap(dcp, &inrep, dcp->bits);
+		v2pr_info("bits:0x%lx > %s.%s\n", inrep, mod_name ?: "*", KP_NAME(kp));
+		totct += ddebug_apply_class_bitmap(dcp, &inrep, dcp->bits, mod_name);
 		*dcp->bits = inrep;
 		break;
 	case DD_CLASS_TYPE_LEVEL_NUM:
@@ -769,7 +767,7 @@ int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
 		old_bits = CLASSMAP_BITMASK(*dcp->lvl);
 		new_bits = CLASSMAP_BITMASK(inrep);
 		v2pr_info("lvl:%ld bits:0x%lx > %s\n", inrep, new_bits, KP_NAME(kp));
-		totct += ddebug_apply_class_bitmap(dcp, &new_bits, &old_bits);
+		totct += ddebug_apply_class_bitmap(dcp, &new_bits, &old_bits, mod_name);
 		*dcp->lvl = inrep;
 		break;
 	default:
@@ -778,16 +776,33 @@ int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
 	vpr_info("%s: total matches: %d\n", KP_NAME(kp), totct);
 	return 0;
 }
+
+/**
+ * param_set_dyndbg_classes - classmap kparam setter
+ * @instr: string echo>d to sysfs, input depends on map_type
+ * @kp:    kp->arg has state: bits/lvl, map, map_type
+ *
+ * enable/disable all class'd pr_debugs in the classmap. For LEVEL
+ * map-types, enforce * relative levels by bitpos.
+ *
+ * Returns: 0 or <0 if error.
+ */
+int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
+{
+	return param_set_dyndbg_module_classes(instr, kp, NULL);
+}
 EXPORT_SYMBOL(param_set_dyndbg_classes);
 
 /**
- * param_get_dyndbg_classes - classes reader
+ * param_get_dyndbg_classes - classmap kparam getter
  * @buffer: string description of controlled bits -> classes
  * @kp:     kp->arg has state: bits, map
  *
- * Reads last written state, underlying prdbg state may have been
- * altered by direct >control.  Displays 0x for DISJOINT, 0-N for
- * LEVEL Returns: #chars written or <0 on error
+ * Reads last written state, underlying pr_debug states may have been
+ * altered by direct >control.  Displays 0x for DISJOINT classmap
+ * types, 0-N for LEVEL types.
+ *
+ * Returns: ct of chars written or <0 on error
  */
 int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp)
 {
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:29 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:29 +1300
Subject: [PATCH v7 12/31] dyndbg: tighten fn-sig of ddebug_apply_class_bitmap
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-13-jim.cromie@gmail.com>

old_bits arg is currently a pointer to the input bits, but this could
allow inadvertent changes to the input by the fn.  Disallow this.
And constify new_bits while here.

Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 lib/dynamic_debug.c | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 64d69f5cba1b..db0559763e60 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -606,7 +606,8 @@ static int ddebug_exec_queries(char *query, const char *modname)
 
 /* apply a new class-param setting */
 static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
-				     unsigned long *new_bits, unsigned long *old_bits,
+				     const unsigned long *new_bits,
+				     const unsigned long old_bits,
 				     const char *query_modname)
 {
 #define QUERY_SIZE 128
@@ -615,12 +616,12 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
 	int matches = 0;
 	int bi, ct;
 
-	if (*new_bits != *old_bits)
+	if (*new_bits != old_bits)
 		v2pr_info("apply bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits,
-			  *old_bits, query_modname ?: "'*'");
+			  old_bits, query_modname ?: "'*'");
 
 	for (bi = 0; bi < map->length; bi++) {
-		if (test_bit(bi, new_bits) == test_bit(bi, old_bits))
+		if (test_bit(bi, new_bits) == test_bit(bi, &old_bits))
 			continue;
 
 		snprintf(query, QUERY_SIZE, "class %s %c%s", map->class_names[bi],
@@ -632,9 +633,9 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
 		v2pr_info("bit_%d: %d matches on class: %s -> 0x%lx\n", bi,
 			  ct, map->class_names[bi], *new_bits);
 	}
-	if (*new_bits != *old_bits)
+	if (*new_bits != old_bits)
 		v2pr_info("applied bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits,
-			  *old_bits, query_modname ?: "'*'");
+			  old_bits, query_modname ?: "'*'");
 
 	return matches;
 }
@@ -690,7 +691,7 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa
 				continue;
 			}
 			curr_bits ^= BIT(cls_id);
-			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, dcp->bits, NULL);
+			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, *dcp->bits, NULL);
 			*dcp->bits = curr_bits;
 			v2pr_info("%s: changed bit %d:%s\n", KP_NAME(kp), cls_id,
 				  map->class_names[cls_id]);
@@ -700,7 +701,7 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa
 			old_bits = CLASSMAP_BITMASK(*dcp->lvl);
 			curr_bits = CLASSMAP_BITMASK(cls_id + (wanted ? 1 : 0 ));
 
-			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, &old_bits, NULL);
+			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, old_bits, NULL);
 			*dcp->lvl = (cls_id + (wanted ? 1 : 0));
 			v2pr_info("%s: changed bit-%d: \"%s\" %lx->%lx\n", KP_NAME(kp), cls_id,
 				  map->class_names[cls_id], old_bits, curr_bits);
@@ -754,7 +755,7 @@ static int param_set_dyndbg_module_classes(const char *instr,
 			inrep &= CLASSMAP_BITMASK(map->length);
 		}
 		v2pr_info("bits:0x%lx > %s.%s\n", inrep, mod_name ?: "*", KP_NAME(kp));
-		totct += ddebug_apply_class_bitmap(dcp, &inrep, dcp->bits, mod_name);
+		totct += ddebug_apply_class_bitmap(dcp, &inrep, *dcp->bits, mod_name);
 		*dcp->bits = inrep;
 		break;
 	case DD_CLASS_TYPE_LEVEL_NUM:
@@ -767,7 +768,7 @@ static int param_set_dyndbg_module_classes(const char *instr,
 		old_bits = CLASSMAP_BITMASK(*dcp->lvl);
 		new_bits = CLASSMAP_BITMASK(inrep);
 		v2pr_info("lvl:%ld bits:0x%lx > %s\n", inrep, new_bits, KP_NAME(kp));
-		totct += ddebug_apply_class_bitmap(dcp, &new_bits, &old_bits, mod_name);
+		totct += ddebug_apply_class_bitmap(dcp, &new_bits, old_bits, mod_name);
 		*dcp->lvl = inrep;
 		break;
 	default:
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:30 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:30 +1300
Subject: [PATCH v7 13/31] dyndbg: replace classmap list with a vector
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-14-jim.cromie@gmail.com>

Classmaps are stored in an elf section/array, but currently are
individually list-linked onto dyndbg's per-module ddebug_table for
operation. This is unnecessary.

Just like dyndbg's descriptors, classes are packed in compile order;
so even with many builtin modules employing multiple classmaps, each
modules' maps are packed contiguously, and can be treated as a
array-start-address & array-length.

So this drops the whole list building operation done in
ddebug_attach_module_classes(), and removes the list-head members.
The "select-by-modname" condition is reused to find the start,end of
the subrange.

NOTE: This "filter-by-modname" on classmaps should really be done in
ddebug_add_module(1); ie at least one step closer to ddebug_init(2),
which already splits up pr-debug descriptors into subranges by
modname, then calls (1) on each.  (2) knows nothing of classmaps
currently, and doesn't need to.  For now, just add comment.

Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 include/linux/dynamic_debug.h |  1 -
 lib/dynamic_debug.c           | 62 ++++++++++++++++++-----------------
 2 files changed, 32 insertions(+), 31 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index c4ae79f934d9..51ed26e42032 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -83,7 +83,6 @@ enum class_map_type {
 };
 
 struct ddebug_class_map {
-	struct list_head link;
 	struct module *mod;
 	const char *mod_name;	/* needed for builtins */
 	const char **class_names;
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index db0559763e60..e882e951d585 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -45,10 +45,11 @@ extern struct ddebug_class_map __start___dyndbg_classes[];
 extern struct ddebug_class_map __stop___dyndbg_classes[];
 
 struct ddebug_table {
-	struct list_head link, maps;
+	struct list_head link;
 	const char *mod_name;
-	unsigned int num_ddebugs;
 	struct _ddebug *ddebugs;
+	struct ddebug_class_map *classes;
+	unsigned int num_ddebugs, num_classes;
 };
 
 struct ddebug_query {
@@ -148,12 +149,13 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
 }
 
 static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table const *dt,
-							  const char *class_string, int *class_id)
+							const char *class_string,
+							int *class_id)
 {
 	struct ddebug_class_map *map;
-	int idx;
+	int i, idx;
 
-	list_for_each_entry(map, &dt->maps, link) {
+	for (map = dt->classes, i = 0; i < dt->num_classes; i++, map++) {
 		idx = match_string(map->class_names, map->length, class_string);
 		if (idx >= 0) {
 			*class_id = idx + map->base;
@@ -164,7 +166,6 @@ static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table cons
 	return NULL;
 }
 
-#define __outvar /* filled by callee */
 /*
  * Search the tables for _ddebug's which match the given `query' and
  * apply the `flags' and `mask' to them.  Returns number of matching
@@ -226,7 +227,7 @@ static int ddebug_change(const struct ddebug_query *query,
 	unsigned int nfound = 0;
 	struct flagsbuf fbuf, nbuf;
 	struct ddebug_class_map *map = NULL;
-	int __outvar valid_class;
+	int valid_class;
 
 	/* search for matching ddebugs */
 	mutex_lock(&ddebug_lock);
@@ -1133,9 +1134,10 @@ static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos)
 
 static const char *ddebug_class_name(struct ddebug_iter *iter, struct _ddebug *dp)
 {
-	struct ddebug_class_map *map;
+	struct ddebug_class_map *map = iter->table->classes;
+	int i, nc = iter->table->num_classes;
 
-	list_for_each_entry(map, &iter->table->maps, link)
+	for (i = 0; i < nc; i++, map++)
 		if (class_in_range(dp->class_id, map))
 			return map->class_names[dp->class_id - map->base];
 
@@ -1219,30 +1221,31 @@ static const struct proc_ops proc_fops = {
 	.proc_write = ddebug_proc_write
 };
 
-static void ddebug_attach_module_classes(struct ddebug_table *dt,
-					 struct ddebug_class_map *classes,
-					 int num_classes)
+static void ddebug_attach_module_classes(struct ddebug_table *dt, struct _ddebug_info *di)
 {
 	struct ddebug_class_map *cm;
-	int i, j, ct = 0;
+	int i, nc = 0;
 
-	for (cm = classes, i = 0; i < num_classes; i++, cm++) {
+	/*
+	 * Find this module's classmaps in a subrange/wholerange of
+	 * the builtin/modular classmap vector/section.  Save the start
+	 * and length of the subrange at its edges.
+	 */
+	for (cm = di->classes, i = 0; i < di->num_classes; i++, cm++) {
 
 		if (!strcmp(cm->mod_name, dt->mod_name)) {
-
-			v2pr_info("class[%d]: module:%s base:%d len:%d ty:%d\n", i,
-				  cm->mod_name, cm->base, cm->length, cm->map_type);
-
-			for (j = 0; j < cm->length; j++)
-				v3pr_info(" %d: %d %s\n", j + cm->base, j,
-					  cm->class_names[j]);
-
-			list_add(&cm->link, &dt->maps);
-			ct++;
+			if (!nc) {
+				v2pr_info("start subrange, class[%d]: module:%s base:%d len:%d ty:%d\n",
+					  i, cm->mod_name, cm->base, cm->length, cm->map_type);
+				dt->classes = cm;
+			}
+			nc++;
 		}
 	}
-	if (ct)
-		vpr_info("module:%s attached %d classes\n", dt->mod_name, ct);
+	if (nc) {
+		dt->num_classes = nc;
+		vpr_info("module:%s attached %d classes\n", dt->mod_name, nc);
+	}
 }
 
 /*
@@ -1274,10 +1277,9 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
 	dt->num_ddebugs = di->num_descs;
 
 	INIT_LIST_HEAD(&dt->link);
-	INIT_LIST_HEAD(&dt->maps);
 
 	if (di->classes && di->num_classes)
-		ddebug_attach_module_classes(dt, di->classes, di->num_classes);
+		ddebug_attach_module_classes(dt, di);
 
 	mutex_lock(&ddebug_lock);
 	list_add_tail(&dt->link, &ddebug_tables);
@@ -1390,8 +1392,8 @@ static void ddebug_remove_all_tables(void)
 	mutex_lock(&ddebug_lock);
 	while (!list_empty(&ddebug_tables)) {
 		struct ddebug_table *dt = list_entry(ddebug_tables.next,
-						      struct ddebug_table,
-						      link);
+						     struct ddebug_table,
+						     link);
 		ddebug_table_free(dt);
 	}
 	mutex_unlock(&ddebug_lock);
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:31 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:31 +1300
Subject: [PATCH v7 14/31] dyndbg: macrofy a 2-index for-loop pattern
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-15-jim.cromie@gmail.com>

dynamic-debug currently has 2 __sections (__dyndbg, __dyndb_classes),
struct _ddebug_info keeps track of them both, with 2 members each:
_vec and _vec#_len.

We need to loop over these sections, with index and record pointer,
making ref to both _vec and _vec_len.  This is already fiddly and
error-prone, and will get worse as we add a 3rd section.

Lets instead embed/abstract the fiddly-ness in the `for_subvec()`
macro, and avoid repeating it going forward.

This is a for-loop macro expander, so it syntactically expects to
precede either a single statement or a { block } of them, and the
usual typeof or do-while-0 tricks are unavailable to fix the
multiple-expansion warning.

The macro needs a lot from its caller: it needs 2 local vars, 1 of
which is a ref to a contained struct with named members.  To support
these requirements, add:

1. __ASSERT_IS_LVALUE(_X):
   ie: ((void)sizeof((void)0, &(x)))

2. __ASSERT_HAS_VEC_MEMBERS(_X, _Y):
   compile-time check that the _Y "vector" exists
   ie: _X->_Y and _X->num##_Y are lvalues.

The for_subvec() macro then invokes these before the for-loop itself;
they disappear at runtime.  They do cause a "complex macro" CHECK from
checkpatch --strict.

Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 lib/dynamic_debug.c | 27 ++++++++++++++++++++++++---
 1 file changed, 24 insertions(+), 3 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index e882e951d585..94d05d09a128 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -128,6 +128,28 @@ do {								\
 #define v3pr_info(fmt, ...)	vnpr_info(3, fmt, ##__VA_ARGS__)
 #define v4pr_info(fmt, ...)	vnpr_info(4, fmt, ##__VA_ARGS__)
 
+/*
+ * simplify a repeated for-loop pattern walking N steps in a T _vec
+ * member inside a struct _box.  It expects int i and T *_sp to be
+ * declared in the caller.
+ * @_i:  caller provided counter.
+ * @_sp: cursor into _vec, to examine each item.
+ * @_box: ptr to a struct containing @_vec member
+ * @_vec: name of a member in @_box
+ */
+#define __ASSERT_IS_LVALUE(x) ((void)sizeof((void)0, &(x)))
+#define __ASSERT_HAS_VEC_MEMBER(_box, _vec) ({	\
+	(void)sizeof((_box)->_vec);		\
+	(void)sizeof((_box)->num_##_vec);	\
+})
+#define for_subvec(_i, _sp, _box, _vec)			\
+	__ASSERT_IS_LVALUE(_i);				\
+	__ASSERT_IS_LVALUE(_sp);			\
+	__ASSERT_HAS_VEC_MEMBER(_box, _vec);		\
+	for ((_i) = 0, (_sp) = (_box)->_vec;		\
+	     (_i) < (_box)->num_##_vec;			\
+	     (_i)++, (_sp)++)
+
 static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
 {
 	/* trim any trailing newlines */
@@ -155,7 +177,7 @@ static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table cons
 	struct ddebug_class_map *map;
 	int i, idx;
 
-	for (map = dt->classes, i = 0; i < dt->num_classes; i++, map++) {
+	for_subvec(i, map, dt, classes) {
 		idx = match_string(map->class_names, map->length, class_string);
 		if (idx >= 0) {
 			*class_id = idx + map->base;
@@ -1231,8 +1253,7 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt, struct _ddebug
 	 * the builtin/modular classmap vector/section.  Save the start
 	 * and length of the subrange at its edges.
 	 */
-	for (cm = di->classes, i = 0; i < di->num_classes; i++, cm++) {
-
+	for_subvec(i, cm, di, classes) {
 		if (!strcmp(cm->mod_name, dt->mod_name)) {
 			if (!nc) {
 				v2pr_info("start subrange, class[%d]: module:%s base:%d len:%d ty:%d\n",
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:32 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:32 +1300
Subject: [PATCH v7 15/31] dyndbg,module: make proper substructs in _ddebug_info
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-16-jim.cromie@gmail.com>

recompose struct _ddebug_info, inserting proper sub-structs.

The struct _ddebug_info has 2 pairs of _vec, num##_vec fields, for
descs and classes respectively.  for_subvec() makes walking these
vectors less cumbersome, now lets move those field pairs into their
own "vec" structs: _ddebug_descs & _ddebug_class_maps, and re-compose
struct _ddebug_info to contain them cleanly.  This also lets us rid
for_subvec() of its num##_vec paste-up.

Also recompose struct ddebug_table to contain a _ddebug_info.  This
reinforces its use as a cursor into relevant data for a builtin
module, and access to the full _ddebug state for modules.

NOTES:

Invariant: These vectors ref a contiguous subrange of __section memory
in builtin/DATA or in loadable modules via mod->dyndbg_info; with
guaranteed life-time for us.

Fixup names: Normalize all struct names to "struct _ddebug_*"
eliminating the minor/stupid variations created in classmaps-v1.
Also normalize the __section names to "__dyndbg_*".

struct module contains a _ddebug_info field and module/main.c sets it
up, so that gets adjusted rather obviously.

Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 include/asm-generic/vmlinux.lds.h |   4 +-
 include/linux/dynamic_debug.h     |  42 ++++++----
 kernel/module/main.c              |  12 +--
 lib/dynamic_debug.c               | 127 +++++++++++++++---------------
 lib/test_dynamic_debug.c          |   2 +-
 5 files changed, 100 insertions(+), 87 deletions(-)

diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index e04d56a5332e..da15cf0c16d0 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -366,8 +366,8 @@ defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG)
 	*(__tracepoints)						\
 	/* implement dynamic printk debug */				\
 	. = ALIGN(8);							\
-	BOUNDED_SECTION_BY(__dyndbg_classes, ___dyndbg_classes)		\
-	BOUNDED_SECTION_BY(__dyndbg, ___dyndbg)				\
+	BOUNDED_SECTION_BY(__dyndbg_class_maps, ___dyndbg_class_maps)	\
+	BOUNDED_SECTION_BY(__dyndbg_descriptors, ___dyndbg_descs)	\
 	CODETAG_SECTIONS()						\
 	LIKELY_PROFILE()		       				\
 	BRANCH_PROFILE()						\
diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 51ed26e42032..4775f66e96dd 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -82,30 +82,42 @@ enum class_map_type {
 	 */
 };
 
-struct ddebug_class_map {
-	struct module *mod;
-	const char *mod_name;	/* needed for builtins */
+struct _ddebug_class_map {
+	struct module *mod;	/* NULL for builtins */
+	const char *mod_name;
 	const char **class_names;
 	const int length;
 	const int base;		/* index of 1st .class_id, allows split/shared space */
 	enum class_map_type map_type;
 };
 
-/* encapsulate linker provided built-in (or module) dyndbg data */
+/*
+ * @_ddebug_info: gathers module/builtin dyndbg_* __sections together.
+ * For builtins, it is used as a cursor, with the inner structs
+ * marking sub-vectors of the builtin __sections in DATA.
+ */
+struct _ddebug_descs {
+	struct _ddebug *start;
+	int len;
+};
+
+struct _ddebug_class_maps {
+	struct _ddebug_class_map *start;
+	int len;
+};
+
 struct _ddebug_info {
-	struct _ddebug *descs;
-	struct ddebug_class_map *classes;
-	unsigned int num_descs;
-	unsigned int num_classes;
+	struct _ddebug_descs descs;
+	struct _ddebug_class_maps maps;
 };
 
-struct ddebug_class_param {
+struct _ddebug_class_param {
 	union {
 		unsigned long *bits;
 		unsigned long *lvl;
 	};
 	char flags[8];
-	const struct ddebug_class_map *map;
+	const struct _ddebug_class_map *map;
 };
 
 /*
@@ -124,8 +136,8 @@ struct ddebug_class_param {
  */
 #define DECLARE_DYNDBG_CLASSMAP(_var, _maptype, _base, ...)		\
 	static const char *_var##_classnames[] = { __VA_ARGS__ };	\
-	static struct ddebug_class_map __aligned(8) __used		\
-		__section("__dyndbg_classes") _var = {			\
+	static struct _ddebug_class_map __aligned(8) __used		\
+		__section("__dyndbg_class_maps") _var = {		\
 		.mod = THIS_MODULE,					\
 		.mod_name = KBUILD_MODNAME,				\
 		.base = _base,						\
@@ -159,7 +171,7 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
 
 #define DEFINE_DYNAMIC_DEBUG_METADATA_CLS(name, cls, fmt)	\
 	static struct _ddebug  __aligned(8)			\
-	__section("__dyndbg") name = {				\
+	__section("__dyndbg_descriptors") name = {		\
 		.modname = KBUILD_MODNAME,			\
 		.function = __func__,				\
 		.filename = __FILE__,				\
@@ -242,7 +254,7 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
  * macro.
  */
 #define _dynamic_func_call_cls(cls, fmt, func, ...)			\
-	__dynamic_func_call_cls(__UNIQUE_ID(ddebug), cls, fmt, func, ##__VA_ARGS__)
+	__dynamic_func_call_cls(__UNIQUE_ID(_ddebug), cls, fmt, func, ##__VA_ARGS__)
 #define _dynamic_func_call(fmt, func, ...)				\
 	_dynamic_func_call_cls(_DPRINTK_CLASS_DFLT, fmt, func, ##__VA_ARGS__)
 
@@ -252,7 +264,7 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
  * with precisely the macro's varargs.
  */
 #define _dynamic_func_call_cls_no_desc(cls, fmt, func, ...)		\
-	__dynamic_func_call_cls_no_desc(__UNIQUE_ID(ddebug), cls, fmt,	\
+	__dynamic_func_call_cls_no_desc(__UNIQUE_ID(_ddebug), cls, fmt,	\
 					func, ##__VA_ARGS__)
 #define _dynamic_func_call_no_desc(fmt, func, ...)			\
 	_dynamic_func_call_cls_no_desc(_DPRINTK_CLASS_DFLT, fmt,	\
diff --git a/kernel/module/main.c b/kernel/module/main.c
index c66b26184936..1ccc5d4399c3 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -2710,12 +2710,12 @@ static int find_module_sections(struct module *mod, struct load_info *info)
 		pr_warn("%s: Ignoring obsolete parameters\n", mod->name);
 
 #ifdef CONFIG_DYNAMIC_DEBUG_CORE
-	mod->dyndbg_info.descs = section_objs(info, "__dyndbg",
-					      sizeof(*mod->dyndbg_info.descs),
-					      &mod->dyndbg_info.num_descs);
-	mod->dyndbg_info.classes = section_objs(info, "__dyndbg_classes",
-						sizeof(*mod->dyndbg_info.classes),
-						&mod->dyndbg_info.num_classes);
+	mod->dyndbg_info.descs.start = section_objs(info, "__dyndbg_descriptors",
+						    sizeof(*mod->dyndbg_info.descs.start),
+						    &mod->dyndbg_info.descs.len);
+	mod->dyndbg_info.maps.start = section_objs(info, "__dyndbg_class_maps",
+						   sizeof(*mod->dyndbg_info.maps.start),
+						   &mod->dyndbg_info.maps.len);
 #endif
 
 	return 0;
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 94d05d09a128..c9377a444fc8 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -39,17 +39,15 @@
 
 #include <rdma/ib_verbs.h>
 
-extern struct _ddebug __start___dyndbg[];
-extern struct _ddebug __stop___dyndbg[];
-extern struct ddebug_class_map __start___dyndbg_classes[];
-extern struct ddebug_class_map __stop___dyndbg_classes[];
+extern struct _ddebug __start___dyndbg_descs[];
+extern struct _ddebug __stop___dyndbg_descs[];
+extern struct _ddebug_class_map __start___dyndbg_class_maps[];
+extern struct _ddebug_class_map __stop___dyndbg_class_maps[];
 
 struct ddebug_table {
 	struct list_head link;
 	const char *mod_name;
-	struct _ddebug *ddebugs;
-	struct ddebug_class_map *classes;
-	unsigned int num_ddebugs, num_classes;
+	struct _ddebug_info info;
 };
 
 struct ddebug_query {
@@ -135,20 +133,21 @@ do {								\
  * @_i:  caller provided counter.
  * @_sp: cursor into _vec, to examine each item.
  * @_box: ptr to a struct containing @_vec member
- * @_vec: name of a member in @_box
+ * @_vec: name of a a vector member in @_box
  */
+
 #define __ASSERT_IS_LVALUE(x) ((void)sizeof((void)0, &(x)))
-#define __ASSERT_HAS_VEC_MEMBER(_box, _vec) ({	\
-	(void)sizeof((_box)->_vec);		\
-	(void)sizeof((_box)->num_##_vec);	\
+#define __ASSERT_HAS_VEC_MEMBER(_box, _vec) ({		\
+	(void)sizeof((_box)->_vec.start);		\
+	(void)sizeof((_box)->_vec.len);			\
 })
 #define for_subvec(_i, _sp, _box, _vec)			\
 	__ASSERT_IS_LVALUE(_i);				\
 	__ASSERT_IS_LVALUE(_sp);			\
 	__ASSERT_HAS_VEC_MEMBER(_box, _vec);		\
-	for ((_i) = 0, (_sp) = (_box)->_vec;		\
-	     (_i) < (_box)->num_##_vec;			\
-	     (_i)++, (_sp)++)
+	for ((_i) = 0, (_sp) = (_box)->_vec.start;	\
+	     (_i) < (_box)->_vec.len;			\
+	     (_i)++, (_sp)++)		/* { block } */
 
 static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
 {
@@ -170,14 +169,14 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
 		  query->first_lineno, query->last_lineno, query->class_string);
 }
 
-static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table const *dt,
+static struct _ddebug_class_map *ddebug_find_valid_class(struct ddebug_table const *dt,
 							const char *class_string,
 							int *class_id)
 {
-	struct ddebug_class_map *map;
+	struct _ddebug_class_map *map;
 	int i, idx;
 
-	for_subvec(i, map, dt, classes) {
+	for_subvec(i, map, &dt->info, maps) {
 		idx = match_string(map->class_names, map->length, class_string);
 		if (idx >= 0) {
 			*class_id = idx + map->base;
@@ -248,7 +247,7 @@ static int ddebug_change(const struct ddebug_query *query,
 	unsigned int newflags;
 	unsigned int nfound = 0;
 	struct flagsbuf fbuf, nbuf;
-	struct ddebug_class_map *map = NULL;
+	struct _ddebug_class_map *map = NULL;
 	int valid_class;
 
 	/* search for matching ddebugs */
@@ -269,8 +268,8 @@ static int ddebug_change(const struct ddebug_query *query,
 			valid_class = _DPRINTK_CLASS_DFLT;
 		}
 
-		for (i = 0; i < dt->num_ddebugs; i++) {
-			struct _ddebug *dp = &dt->ddebugs[i];
+		for (i = 0; i < dt->info.descs.len; i++) {
+			struct _ddebug *dp = &dt->info.descs.start[i];
 
 			if (!ddebug_match_desc(query, dp, valid_class))
 				continue;
@@ -628,14 +627,14 @@ static int ddebug_exec_queries(char *query, const char *modname)
 }
 
 /* apply a new class-param setting */
-static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
+static int ddebug_apply_class_bitmap(const struct _ddebug_class_param *dcp,
 				     const unsigned long *new_bits,
 				     const unsigned long old_bits,
 				     const char *query_modname)
 {
 #define QUERY_SIZE 128
 	char query[QUERY_SIZE];
-	const struct ddebug_class_map *map = dcp->map;
+	const struct _ddebug_class_map *map = dcp->map;
 	int matches = 0;
 	int bi, ct;
 
@@ -671,8 +670,8 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
 /* accept comma-separated-list of [+-] classnames */
 static int param_set_dyndbg_classnames(const char *instr, const struct kernel_param *kp)
 {
-	const struct ddebug_class_param *dcp = kp->arg;
-	const struct ddebug_class_map *map = dcp->map;
+	const struct _ddebug_class_param *dcp = kp->arg;
+	const struct _ddebug_class_map *map = dcp->map;
 	unsigned long curr_bits, old_bits;
 	char *cl_str, *p, *tmp;
 	int cls_id, totct = 0;
@@ -742,8 +741,8 @@ static int param_set_dyndbg_module_classes(const char *instr,
 					   const struct kernel_param *kp,
 					   const char *mod_name)
 {
-	const struct ddebug_class_param *dcp = kp->arg;
-	const struct ddebug_class_map *map = dcp->map;
+	const struct _ddebug_class_param *dcp = kp->arg;
+	const struct _ddebug_class_map *map = dcp->map;
 	unsigned long inrep, new_bits, old_bits;
 	int rc, totct = 0;
 
@@ -830,8 +829,8 @@ EXPORT_SYMBOL(param_set_dyndbg_classes);
  */
 int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp)
 {
-	const struct ddebug_class_param *dcp = kp->arg;
-	const struct ddebug_class_map *map = dcp->map;
+	const struct _ddebug_class_param *dcp = kp->arg;
+	const struct _ddebug_class_map *map = dcp->map;
 
 	switch (map->map_type) {
 
@@ -1082,8 +1081,8 @@ static struct _ddebug *ddebug_iter_first(struct ddebug_iter *iter)
 	}
 	iter->table = list_entry(ddebug_tables.next,
 				 struct ddebug_table, link);
-	iter->idx = iter->table->num_ddebugs;
-	return &iter->table->ddebugs[--iter->idx];
+	iter->idx = iter->table->info.descs.len;
+	return &iter->table->info.descs.start[--iter->idx];
 }
 
 /*
@@ -1104,10 +1103,10 @@ static struct _ddebug *ddebug_iter_next(struct ddebug_iter *iter)
 		}
 		iter->table = list_entry(iter->table->link.next,
 					 struct ddebug_table, link);
-		iter->idx = iter->table->num_ddebugs;
+		iter->idx = iter->table->info.descs.len;
 		--iter->idx;
 	}
-	return &iter->table->ddebugs[iter->idx];
+	return &iter->table->info.descs.start[iter->idx];
 }
 
 /*
@@ -1151,16 +1150,19 @@ static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos)
 	return dp;
 }
 
-#define class_in_range(class_id, map)					\
-	(class_id >= map->base && class_id < map->base + map->length)
+static bool ddebug_class_in_range(const int class_id, const struct _ddebug_class_map *map)
+{
+	return (class_id >= map->base &&
+		class_id < map->base + map->length);
+}
 
-static const char *ddebug_class_name(struct ddebug_iter *iter, struct _ddebug *dp)
+static const char *ddebug_class_name(struct ddebug_table *dt, struct _ddebug *dp)
 {
-	struct ddebug_class_map *map = iter->table->classes;
-	int i, nc = iter->table->num_classes;
+	struct _ddebug_class_map *map;
+	int i;
 
-	for (i = 0; i < nc; i++, map++)
-		if (class_in_range(dp->class_id, map))
+	for_subvec(i, map, &dt->info, maps)
+		if (ddebug_class_in_range(dp->class_id, map))
 			return map->class_names[dp->class_id - map->base];
 
 	return NULL;
@@ -1193,7 +1195,7 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
 	seq_putc(m, '"');
 
 	if (dp->class_id != _DPRINTK_CLASS_DFLT) {
-		class = ddebug_class_name(iter, dp);
+		class = ddebug_class_name(iter->table, dp);
 		if (class)
 			seq_printf(m, " class:%s", class);
 		else
@@ -1245,7 +1247,7 @@ static const struct proc_ops proc_fops = {
 
 static void ddebug_attach_module_classes(struct ddebug_table *dt, struct _ddebug_info *di)
 {
-	struct ddebug_class_map *cm;
+	struct _ddebug_class_map *cm;
 	int i, nc = 0;
 
 	/*
@@ -1253,18 +1255,18 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt, struct _ddebug
 	 * the builtin/modular classmap vector/section.  Save the start
 	 * and length of the subrange at its edges.
 	 */
-	for_subvec(i, cm, di, classes) {
+	for_subvec(i, cm, di, maps) {
 		if (!strcmp(cm->mod_name, dt->mod_name)) {
 			if (!nc) {
 				v2pr_info("start subrange, class[%d]: module:%s base:%d len:%d ty:%d\n",
 					  i, cm->mod_name, cm->base, cm->length, cm->map_type);
-				dt->classes = cm;
+				dt->info.maps.start = cm;
 			}
 			nc++;
 		}
 	}
 	if (nc) {
-		dt->num_classes = nc;
+		dt->info.maps.len = nc;
 		vpr_info("module:%s attached %d classes\n", dt->mod_name, nc);
 	}
 }
@@ -1277,10 +1279,10 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
 {
 	struct ddebug_table *dt;
 
-	if (!di->num_descs)
+	if (!di->descs.len)
 		return 0;
 
-	v3pr_info("add-module: %s %d sites\n", modname, di->num_descs);
+	v3pr_info("add-module: %s %d sites\n", modname, di->descs.len);
 
 	dt = kzalloc(sizeof(*dt), GFP_KERNEL);
 	if (dt == NULL) {
@@ -1294,19 +1296,18 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
 	 * this struct ddebug_table.
 	 */
 	dt->mod_name = modname;
-	dt->ddebugs = di->descs;
-	dt->num_ddebugs = di->num_descs;
+	dt->info = *di;
 
 	INIT_LIST_HEAD(&dt->link);
 
-	if (di->classes && di->num_classes)
+	if (di->maps.len)
 		ddebug_attach_module_classes(dt, di);
 
 	mutex_lock(&ddebug_lock);
 	list_add_tail(&dt->link, &ddebug_tables);
 	mutex_unlock(&ddebug_lock);
 
-	vpr_info("%3u debug prints in module %s\n", di->num_descs, modname);
+	vpr_info("%3u debug prints in module %s\n", di->descs.len, modname);
 	return 0;
 }
 
@@ -1453,10 +1454,10 @@ static int __init dynamic_debug_init(void)
 	char *cmdline;
 
 	struct _ddebug_info di = {
-		.descs = __start___dyndbg,
-		.classes = __start___dyndbg_classes,
-		.num_descs = __stop___dyndbg - __start___dyndbg,
-		.num_classes = __stop___dyndbg_classes - __start___dyndbg_classes,
+		.descs.start = __start___dyndbg_descs,
+		.maps.start  = __start___dyndbg_class_maps,
+		.descs.len = __stop___dyndbg_descs - __start___dyndbg_descs,
+		.maps.len  = __stop___dyndbg_class_maps - __start___dyndbg_class_maps,
 	};
 
 #ifdef CONFIG_MODULES
@@ -1467,7 +1468,7 @@ static int __init dynamic_debug_init(void)
 	}
 #endif /* CONFIG_MODULES */
 
-	if (&__start___dyndbg == &__stop___dyndbg) {
+	if (&__start___dyndbg_descs == &__stop___dyndbg_descs) {
 		if (IS_ENABLED(CONFIG_DYNAMIC_DEBUG)) {
 			pr_warn("_ddebug table is empty in a CONFIG_DYNAMIC_DEBUG build\n");
 			return 1;
@@ -1477,16 +1478,16 @@ static int __init dynamic_debug_init(void)
 		return 0;
 	}
 
-	iter = iter_mod_start = __start___dyndbg;
+	iter = iter_mod_start = __start___dyndbg_descs;
 	modname = iter->modname;
 	i = mod_sites = mod_ct = 0;
 
-	for (; iter < __stop___dyndbg; iter++, i++, mod_sites++) {
+	for (; iter < __stop___dyndbg_descs; iter++, i++, mod_sites++) {
 
 		if (strcmp(modname, iter->modname)) {
 			mod_ct++;
-			di.num_descs = mod_sites;
-			di.descs = iter_mod_start;
+			di.descs.len = mod_sites;
+			di.descs.start = iter_mod_start;
 			ret = ddebug_add_module(&di, modname);
 			if (ret)
 				goto out_err;
@@ -1496,8 +1497,8 @@ static int __init dynamic_debug_init(void)
 			iter_mod_start = iter;
 		}
 	}
-	di.num_descs = mod_sites;
-	di.descs = iter_mod_start;
+	di.descs.len = mod_sites;
+	di.descs.start = iter_mod_start;
 	ret = ddebug_add_module(&di, modname);
 	if (ret)
 		goto out_err;
@@ -1507,8 +1508,8 @@ static int __init dynamic_debug_init(void)
 		 i, mod_ct, (int)((mod_ct * sizeof(struct ddebug_table)) >> 10),
 		 (int)((i * sizeof(struct _ddebug)) >> 10));
 
-	if (di.num_classes)
-		v2pr_info("  %d builtin ddebug class-maps\n", di.num_classes);
+	if (di.maps.len)
+		v2pr_info("  %d builtin ddebug class-maps\n", di.maps.len);
 
 	/* now that ddebug tables are loaded, process all boot args
 	 * again to find and activate queries given in dyndbg params.
diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
index 396144cf351b..8434f70b51bb 100644
--- a/lib/test_dynamic_debug.c
+++ b/lib/test_dynamic_debug.c
@@ -41,7 +41,7 @@ module_param_cb(do_prints, &param_ops_do_prints, NULL, 0600);
  */
 #define DD_SYS_WRAP(_model, _flags)					\
 	static unsigned long bits_##_model;				\
-	static struct ddebug_class_param _flags##_model = {		\
+	static struct _ddebug_class_param _flags##_model = {		\
 		.bits = &bits_##_model,					\
 		.flags = #_flags,					\
 		.map = &map_##_model,					\
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:33 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:33 +1300
Subject: [PATCH v7 16/31] dyndbg: hoist classmap-filter-by-modname up to ddebug_add_module
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-17-jim.cromie@gmail.com>

The body of ddebug_attach_module_classes() is dominated by a
code-block that finds the contiguous subrange of classmaps matching on
modname, and saves it into the ddebug_table's info record.

Implement this block in a macro to accommodate different component
vectors in the "box" (as named in the for_subvec macro).  We will
reuse this macro shortly.

And hoist its invocation out of ddebug_attach_module_classes() up into
ddebug_add_module().  This moves the filtering step up closer to
dynamic_debug_init(), which already segments the builtin pr_debug
descriptors on their mod_name boundaries.

Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
reordered params to match kdoc
---
 lib/dynamic_debug.c | 57 ++++++++++++++++++++++++++-------------------
 1 file changed, 33 insertions(+), 24 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index c9377a444fc8..d668140794ac 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -170,8 +170,8 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
 }
 
 static struct _ddebug_class_map *ddebug_find_valid_class(struct ddebug_table const *dt,
-							const char *class_string,
-							int *class_id)
+							 const char *class_string,
+							 int *class_id)
 {
 	struct _ddebug_class_map *map;
 	int i, idx;
@@ -1247,30 +1247,35 @@ static const struct proc_ops proc_fops = {
 
 static void ddebug_attach_module_classes(struct ddebug_table *dt, struct _ddebug_info *di)
 {
-	struct _ddebug_class_map *cm;
-	int i, nc = 0;
-
-	/*
-	 * Find this module's classmaps in a subrange/wholerange of
-	 * the builtin/modular classmap vector/section.  Save the start
-	 * and length of the subrange at its edges.
-	 */
-	for_subvec(i, cm, di, maps) {
-		if (!strcmp(cm->mod_name, dt->mod_name)) {
-			if (!nc) {
-				v2pr_info("start subrange, class[%d]: module:%s base:%d len:%d ty:%d\n",
-					  i, cm->mod_name, cm->base, cm->length, cm->map_type);
-				dt->info.maps.start = cm;
-			}
-			nc++;
-		}
-	}
-	if (nc) {
-		dt->info.maps.len = nc;
-		vpr_info("module:%s attached %d classes\n", dt->mod_name, nc);
-	}
+	vpr_info("module:%s attached %d classes\n", dt->mod_name, dt->info.maps.len);
 }
 
+/*
+ * Walk the @_box->@_vec member, over @_vec.start[0..len], and find
+ * the contiguous subrange of elements matching on ->mod_name.  Copy
+ * the subrange into @_dst.  This depends on vars defd by caller.
+ *
+ * @_i:   caller provided counter var, init'd by macro
+ * @_sp:  cursor into @_vec.
+ * @_box: contains member named @_vec
+ * @_vec: member-name of a type with: .start .len fields.
+ * @_dst: an array-ref: to remember the module's subrange
+ */
+#define dd_mark_vector_subrange(_i, _sp, _box, _vec, _dst) ({		\
+	typeof(_dst) __dst = (_dst);					\
+	int __nc = 0;							\
+	for_subvec(_i, _sp, _box, _vec) {				\
+		if (!strcmp((_sp)->mod_name, (_dst)->mod_name)) {	\
+			if (!__nc++)					\
+				(__dst)->info._vec.start = (_sp);	\
+		} else {						\
+			if (__nc)					\
+				break; /* end of consecutive matches */ \
+		}							\
+	}								\
+	(__dst)->info._vec.len = __nc;					\
+})
+
 /*
  * Allocate a new ddebug_table for the given module
  * and add it to the global list.
@@ -1278,6 +1283,8 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt, struct _ddebug
 static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
 {
 	struct ddebug_table *dt;
+	struct _ddebug_class_map *cm;
+	int i;
 
 	if (!di->descs.len)
 		return 0;
@@ -1300,6 +1307,8 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
 
 	INIT_LIST_HEAD(&dt->link);
 
+	dd_mark_vector_subrange(i, cm, di, maps, dt);
+
 	if (di->maps.len)
 		ddebug_attach_module_classes(dt, di);
 
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:34 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:34 +1300
Subject: [PATCH v7 17/31] dyndbg: move mod_name down from struct ddebug_table to _ddebug_info
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-18-jim.cromie@gmail.com>

struct _ddebug_info already has most of dyndbg's info for a module;
push debug_table.mod_name down into it, finishing the encapsulation.

This allows refactoring several callchains, passing &_ddebug_info
instead of &ddebug_table, and hoisting the "&dt->info" deref up
instead of repeating it thru the callchans

ddebug_table contains a _ddebug_info member, so its users keep access
to mod_name, just now with "->info." added in.

In static ddebug_add_module(&di), reinforce the cursor-model by
dropping the modname arg, and setting di->mod_name at each caller.

Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 include/linux/dynamic_debug.h |  1 +
 lib/dynamic_debug.c           | 50 ++++++++++++++++++-----------------
 2 files changed, 27 insertions(+), 24 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 4775f66e96dd..10f1a2a1bee4 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -107,6 +107,7 @@ struct _ddebug_class_maps {
 };
 
 struct _ddebug_info {
+	const char *mod_name;
 	struct _ddebug_descs descs;
 	struct _ddebug_class_maps maps;
 };
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index d668140794ac..77972da271ee 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -46,7 +46,6 @@ extern struct _ddebug_class_map __stop___dyndbg_class_maps[];
 
 struct ddebug_table {
 	struct list_head link;
-	const char *mod_name;
 	struct _ddebug_info info;
 };
 
@@ -253,10 +252,11 @@ static int ddebug_change(const struct ddebug_query *query,
 	/* search for matching ddebugs */
 	mutex_lock(&ddebug_lock);
 	list_for_each_entry(dt, &ddebug_tables, link) {
+		struct _ddebug_info *di = &dt->info;
 
 		/* match against the module name */
 		if (query->module &&
-		    !match_wildcard(query->module, dt->mod_name))
+		    !match_wildcard(query->module, di->mod_name))
 			continue;
 
 		if (query->class_string) {
@@ -268,8 +268,8 @@ static int ddebug_change(const struct ddebug_query *query,
 			valid_class = _DPRINTK_CLASS_DFLT;
 		}
 
-		for (i = 0; i < dt->info.descs.len; i++) {
-			struct _ddebug *dp = &dt->info.descs.start[i];
+		for (i = 0; i < di->descs.len; i++) {
+			struct _ddebug *dp = &di->descs.start[i];
 
 			if (!ddebug_match_desc(query, dp, valid_class))
 				continue;
@@ -289,7 +289,7 @@ static int ddebug_change(const struct ddebug_query *query,
 #endif
 			v4pr_info("changed %s:%d [%s]%s %s => %s\n",
 				  trim_prefix(dp->filename), dp->lineno,
-				  dt->mod_name, dp->function,
+				  di->mod_name, dp->function,
 				  ddebug_describe_flags(dp->flags, &fbuf),
 				  ddebug_describe_flags(newflags, &nbuf));
 			dp->flags = newflags;
@@ -1156,12 +1156,12 @@ static bool ddebug_class_in_range(const int class_id, const struct _ddebug_class
 		class_id < map->base + map->length);
 }
 
-static const char *ddebug_class_name(struct ddebug_table *dt, struct _ddebug *dp)
+static const char *ddebug_class_name(struct _ddebug_info *di, struct _ddebug *dp)
 {
 	struct _ddebug_class_map *map;
 	int i;
 
-	for_subvec(i, map, &dt->info, maps)
+	for_subvec(i, map, di, maps)
 		if (ddebug_class_in_range(dp->class_id, map))
 			return map->class_names[dp->class_id - map->base];
 
@@ -1189,13 +1189,13 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
 
 	seq_printf(m, "%s:%u [%s]%s =%s \"",
 		   trim_prefix(dp->filename), dp->lineno,
-		   iter->table->mod_name, dp->function,
+		   iter->table->info.mod_name, dp->function,
 		   ddebug_describe_flags(dp->flags, &flags));
 	seq_escape_str(m, dp->format, ESCAPE_SPACE, "\t\r\n\"");
 	seq_putc(m, '"');
 
 	if (dp->class_id != _DPRINTK_CLASS_DFLT) {
-		class = ddebug_class_name(iter->table, dp);
+		class = ddebug_class_name(&iter->table->info, dp);
 		if (class)
 			seq_printf(m, " class:%s", class);
 		else
@@ -1247,7 +1247,7 @@ static const struct proc_ops proc_fops = {
 
 static void ddebug_attach_module_classes(struct ddebug_table *dt, struct _ddebug_info *di)
 {
-	vpr_info("module:%s attached %d classes\n", dt->mod_name, dt->info.maps.len);
+	vpr_info("module:%s attached %d classes\n", dt->info.mod_name, dt->info.maps.len);
 }
 
 /*
@@ -1265,7 +1265,7 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt, struct _ddebug
 	typeof(_dst) __dst = (_dst);					\
 	int __nc = 0;							\
 	for_subvec(_i, _sp, _box, _vec) {				\
-		if (!strcmp((_sp)->mod_name, (_dst)->mod_name)) {	\
+		if (!strcmp((_sp)->mod_name, (__dst)->info.mod_name)) {	\
 			if (!__nc++)					\
 				(__dst)->info._vec.start = (_sp);	\
 		} else {						\
@@ -1280,7 +1280,7 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt, struct _ddebug
  * Allocate a new ddebug_table for the given module
  * and add it to the global list.
  */
-static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
+static int ddebug_add_module(struct _ddebug_info *di)
 {
 	struct ddebug_table *dt;
 	struct _ddebug_class_map *cm;
@@ -1289,20 +1289,19 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
 	if (!di->descs.len)
 		return 0;
 
-	v3pr_info("add-module: %s %d sites\n", modname, di->descs.len);
+	v3pr_info("add-module: %s %d sites\n", di->mod_name, di->descs.len);
 
 	dt = kzalloc(sizeof(*dt), GFP_KERNEL);
 	if (dt == NULL) {
-		pr_err("error adding module: %s\n", modname);
+		pr_err("error adding module: %s\n", di->mod_name);
 		return -ENOMEM;
 	}
 	/*
-	 * For built-in modules, name lives in .rodata and is
-	 * immortal. For loaded modules, name points at the name[]
-	 * member of struct module, which lives at least as long as
-	 * this struct ddebug_table.
+	 * For built-in modules, name (as supplied in di by its
+	 * callers) lives in .rodata and is immortal. For loaded
+	 * modules, name points at the name[] member of struct module,
+	 * which lives at least as long as this struct ddebug_table.
 	 */
-	dt->mod_name = modname;
 	dt->info = *di;
 
 	INIT_LIST_HEAD(&dt->link);
@@ -1316,7 +1315,7 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
 	list_add_tail(&dt->link, &ddebug_tables);
 	mutex_unlock(&ddebug_lock);
 
-	vpr_info("%3u debug prints in module %s\n", di->descs.len, modname);
+	vpr_info("%3u debug prints in module %s\n", di->descs.len, di->mod_name);
 	return 0;
 }
 
@@ -1379,7 +1378,7 @@ static int ddebug_remove_module(const char *mod_name)
 
 	mutex_lock(&ddebug_lock);
 	list_for_each_entry_safe(dt, nextdt, &ddebug_tables, link) {
-		if (dt->mod_name == mod_name) {
+		if (dt->info.mod_name == mod_name) {
 			ddebug_table_free(dt);
 			ret = 0;
 			break;
@@ -1399,7 +1398,8 @@ static int ddebug_module_notify(struct notifier_block *self, unsigned long val,
 
 	switch (val) {
 	case MODULE_STATE_COMING:
-		ret = ddebug_add_module(&mod->dyndbg_info, mod->name);
+		mod->dyndbg_info.mod_name = mod->name;
+		ret = ddebug_add_module(&mod->dyndbg_info);
 		if (ret)
 			WARN(1, "Failed to allocate memory: dyndbg may not work properly.\n");
 		break;
@@ -1497,7 +1497,8 @@ static int __init dynamic_debug_init(void)
 			mod_ct++;
 			di.descs.len = mod_sites;
 			di.descs.start = iter_mod_start;
-			ret = ddebug_add_module(&di, modname);
+			di.mod_name = modname;
+			ret = ddebug_add_module(&di);
 			if (ret)
 				goto out_err;
 
@@ -1508,7 +1509,8 @@ static int __init dynamic_debug_init(void)
 	}
 	di.descs.len = mod_sites;
 	di.descs.start = iter_mod_start;
-	ret = ddebug_add_module(&di, modname);
+	di.mod_name = modname;
+	ret = ddebug_add_module(&di);
 	if (ret)
 		goto out_err;
 
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:35 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:35 +1300
Subject: [PATCH v7 18/31] dyndbg-API: remove DD_CLASS_TYPE_(DISJOINT|LEVEL)_NAMES and code
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-19-jim.cromie@gmail.com>

Remove the DD_CLASS_TYPE_*_NAMES classmap types and code.

These 2 classmap types accept class names at the PARAM interface, for
example:

  echo +DRM_UT_CORE,-DRM_UT_KMS > /sys/module/drm/parameters/debug_names

The code works, but its only used by test-dynamic-debug, and wasn't
asked for by anyone else, so reduce LOC & test-surface; simplify things.

Also rename enum class_map_type to enum ddebug_class_map_type.

Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 include/linux/dynamic_debug.h |  23 ++------
 lib/dynamic_debug.c           | 102 +++-------------------------------
 lib/test_dynamic_debug.c      |  26 ---------
 3 files changed, 14 insertions(+), 137 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 10f1a2a1bee4..d543b84d447e 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -58,27 +58,16 @@ struct _ddebug {
 #endif
 } __attribute__((aligned(8)));
 
-enum class_map_type {
+enum ddebug_class_map_type {
 	DD_CLASS_TYPE_DISJOINT_BITS,
 	/**
-	 * DD_CLASS_TYPE_DISJOINT_BITS: classes are independent, one per bit.
-	 * expecting hex input. Built for drm.debug, basis for other types.
+	 * DD_CLASS_TYPE_DISJOINT_BITS: classes are independent, mapped to bits[0..N].
+	 * Expects hex input. Built for drm.debug, basis for other types.
 	 */
 	DD_CLASS_TYPE_LEVEL_NUM,
 	/**
-	 * DD_CLASS_TYPE_LEVEL_NUM: input is numeric level, 0-N.
-	 * N turns on just bits N-1 .. 0, so N=0 turns all bits off.
-	 */
-	DD_CLASS_TYPE_DISJOINT_NAMES,
-	/**
-	 * DD_CLASS_TYPE_DISJOINT_NAMES: input is a CSV of [+-]CLASS_NAMES,
-	 * classes are independent, like _DISJOINT_BITS.
-	 */
-	DD_CLASS_TYPE_LEVEL_NAMES,
-	/**
-	 * DD_CLASS_TYPE_LEVEL_NAMES: input is a CSV of [+-]CLASS_NAMES,
-	 * intended for names like: INFO,DEBUG,TRACE, with a module prefix
-	 * avoid EMERG,ALERT,CRIT,ERR,WARNING: they're not debug
+	 * DD_CLASS_TYPE_LEVEL_NUM: input is numeric level, 0..N.
+	 * Input N turns on bits 0..N-1
 	 */
 };
 
@@ -88,7 +77,7 @@ struct _ddebug_class_map {
 	const char **class_names;
 	const int length;
 	const int base;		/* index of 1st .class_id, allows split/shared space */
-	enum class_map_type map_type;
+	enum ddebug_class_map_type map_type;
 };
 
 /*
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 77972da271ee..63bfe1891a9e 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -667,76 +667,6 @@ static int ddebug_apply_class_bitmap(const struct _ddebug_class_param *dcp,
 
 #define CLASSMAP_BITMASK(width) ((1UL << (width)) - 1)
 
-/* accept comma-separated-list of [+-] classnames */
-static int param_set_dyndbg_classnames(const char *instr, const struct kernel_param *kp)
-{
-	const struct _ddebug_class_param *dcp = kp->arg;
-	const struct _ddebug_class_map *map = dcp->map;
-	unsigned long curr_bits, old_bits;
-	char *cl_str, *p, *tmp;
-	int cls_id, totct = 0;
-	bool wanted;
-
-	cl_str = tmp = kstrdup_and_replace(instr, '\n', '\0', GFP_KERNEL);
-	if (!tmp)
-		return -ENOMEM;
-
-	/* start with previously set state-bits, then modify */
-	curr_bits = old_bits = *dcp->bits;
-	vpr_info("\"%s\" > %s:0x%lx\n", cl_str, KP_NAME(kp), curr_bits);
-
-	for (; cl_str; cl_str = p) {
-		p = strchr(cl_str, ',');
-		if (p)
-			*p++ = '\0';
-
-		if (*cl_str == '-') {
-			wanted = false;
-			cl_str++;
-		} else {
-			wanted = true;
-			if (*cl_str == '+')
-				cl_str++;
-		}
-		cls_id = match_string(map->class_names, map->length, cl_str);
-		if (cls_id < 0) {
-			pr_err("%s unknown to %s\n", cl_str, KP_NAME(kp));
-			continue;
-		}
-
-		/* have one or more valid class_ids of one *_NAMES type */
-		switch (map->map_type) {
-		case DD_CLASS_TYPE_DISJOINT_NAMES:
-			/* the +/- pertains to a single bit */
-			if (test_bit(cls_id, &curr_bits) == wanted) {
-				v3pr_info("no change on %s\n", cl_str);
-				continue;
-			}
-			curr_bits ^= BIT(cls_id);
-			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, *dcp->bits, NULL);
-			*dcp->bits = curr_bits;
-			v2pr_info("%s: changed bit %d:%s\n", KP_NAME(kp), cls_id,
-				  map->class_names[cls_id]);
-			break;
-		case DD_CLASS_TYPE_LEVEL_NAMES:
-			/* cls_id = N in 0..max. wanted +/- determines N or N-1 */
-			old_bits = CLASSMAP_BITMASK(*dcp->lvl);
-			curr_bits = CLASSMAP_BITMASK(cls_id + (wanted ? 1 : 0 ));
-
-			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, old_bits, NULL);
-			*dcp->lvl = (cls_id + (wanted ? 1 : 0));
-			v2pr_info("%s: changed bit-%d: \"%s\" %lx->%lx\n", KP_NAME(kp), cls_id,
-				  map->class_names[cls_id], old_bits, curr_bits);
-			break;
-		default:
-			pr_err("illegal map-type value %d\n", map->map_type);
-		}
-	}
-	kfree(tmp);
-	vpr_info("total matches: %d\n", totct);
-	return 0;
-}
-
 static int param_set_dyndbg_module_classes(const char *instr,
 					   const struct kernel_param *kp,
 					   const char *mod_name)
@@ -745,29 +675,17 @@ static int param_set_dyndbg_module_classes(const char *instr,
 	const struct _ddebug_class_map *map = dcp->map;
 	unsigned long inrep, new_bits, old_bits;
 	int rc, totct = 0;
-
-	switch (map->map_type) {
-
-	case DD_CLASS_TYPE_DISJOINT_NAMES:
-	case DD_CLASS_TYPE_LEVEL_NAMES:
-		/* handle [+-]classnames list separately, we are done here */
-		return param_set_dyndbg_classnames(instr, kp);
-
-	case DD_CLASS_TYPE_DISJOINT_BITS:
-	case DD_CLASS_TYPE_LEVEL_NUM:
-		/* numeric input, accept and fall-thru */
-		rc = kstrtoul(instr, 0, &inrep);
-		if (rc) {
-			pr_err("expecting numeric input: %s > %s\n", instr, KP_NAME(kp));
-			return -EINVAL;
-		}
-		break;
-	default:
-		pr_err("%s: bad map type: %d\n", KP_NAME(kp), map->map_type);
+	char *nl;
+
+	rc = kstrtoul(instr, 0, &inrep);
+	if (rc) {
+		nl = strchr(instr, '\n');
+		if (nl)
+			*nl = '\0';
+		pr_err("expecting numeric input, not: %s > %s\n", instr, KP_NAME(kp));
 		return -EINVAL;
 	}
 
-	/* only _BITS,_NUM (numeric) map-types get here */
 	switch (map->map_type) {
 	case DD_CLASS_TYPE_DISJOINT_BITS:
 		/* expect bits. mask and warn if too many */
@@ -833,12 +751,8 @@ int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp)
 	const struct _ddebug_class_map *map = dcp->map;
 
 	switch (map->map_type) {
-
-	case DD_CLASS_TYPE_DISJOINT_NAMES:
 	case DD_CLASS_TYPE_DISJOINT_BITS:
 		return scnprintf(buffer, PAGE_SIZE, "0x%lx\n", *dcp->bits);
-
-	case DD_CLASS_TYPE_LEVEL_NAMES:
 	case DD_CLASS_TYPE_LEVEL_NUM:
 		return scnprintf(buffer, PAGE_SIZE, "%ld\n", *dcp->lvl);
 	default:
diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
index 8434f70b51bb..9c3e53cd26bd 100644
--- a/lib/test_dynamic_debug.c
+++ b/lib/test_dynamic_debug.c
@@ -74,13 +74,6 @@ DECLARE_DYNDBG_CLASSMAP(map_disjoint_bits, DD_CLASS_TYPE_DISJOINT_BITS, 0,
 DD_SYS_WRAP(disjoint_bits, p);
 DD_SYS_WRAP(disjoint_bits, T);
 
-/* symbolic input, independent bits */
-enum cat_disjoint_names { LOW = 10, MID, HI };
-DECLARE_DYNDBG_CLASSMAP(map_disjoint_names, DD_CLASS_TYPE_DISJOINT_NAMES, 10,
-			"LOW", "MID", "HI");
-DD_SYS_WRAP(disjoint_names, p);
-DD_SYS_WRAP(disjoint_names, T);
-
 /* numeric verbosity, V2 > V1 related */
 enum cat_level_num { V0 = 14, V1, V2, V3, V4, V5, V6, V7 };
 DECLARE_DYNDBG_CLASSMAP(map_level_num, DD_CLASS_TYPE_LEVEL_NUM, 14,
@@ -88,13 +81,6 @@ DECLARE_DYNDBG_CLASSMAP(map_level_num, DD_CLASS_TYPE_LEVEL_NUM, 14,
 DD_SYS_WRAP(level_num, p);
 DD_SYS_WRAP(level_num, T);
 
-/* symbolic verbosity */
-enum cat_level_names { L0 = 22, L1, L2, L3, L4, L5, L6, L7 };
-DECLARE_DYNDBG_CLASSMAP(map_level_names, DD_CLASS_TYPE_LEVEL_NAMES, 22,
-			"L0", "L1", "L2", "L3", "L4", "L5", "L6", "L7");
-DD_SYS_WRAP(level_names, p);
-DD_SYS_WRAP(level_names, T);
-
 /* stand-in for all pr_debug etc */
 #define prdbg(SYM) __pr_debug_cls(SYM, #SYM " msg\n")
 
@@ -102,10 +88,6 @@ static void do_cats(void)
 {
 	pr_debug("doing categories\n");
 
-	prdbg(LOW);
-	prdbg(MID);
-	prdbg(HI);
-
 	prdbg(D2_CORE);
 	prdbg(D2_DRIVER);
 	prdbg(D2_KMS);
@@ -129,14 +111,6 @@ static void do_levels(void)
 	prdbg(V5);
 	prdbg(V6);
 	prdbg(V7);
-
-	prdbg(L1);
-	prdbg(L2);
-	prdbg(L3);
-	prdbg(L4);
-	prdbg(L5);
-	prdbg(L6);
-	prdbg(L7);
 }
 
 static void do_prints(void)
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:37 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:37 +1300
Subject: [PATCH v7 20/31] dyndbg: change __dynamic_func_call_cls* macros into expressions
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-21-jim.cromie@gmail.com>

The Xe driver's XE_IOCTL_DBG macro calls drm_dbg() from inside an if
(expression).  This breaks when CONFIG_DRM_USE_DYNAMIC_DEBUG=y because
the invoked macro has a do-while-0 wrapper, and is not an expression.

   if (cond && (drm_dbg("expr-form"),1)) {
      ... do some more stuff
   }

Fix for this usage by changing __dynamic_func_call_cls{,_no_desc}
macros into expressions, by replacing the do-while-0s with a ({ })
wrapper.  In the common usage, the trailing ';' converts the
expression into a statement.

   drm_dbg("statement form");

Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 include/linux/dynamic_debug.h | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index d543b84d447e..c4ebbccca5d1 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -217,20 +217,20 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
  * (|_cls):	adds in _DPRINT_CLASS_DFLT as needed
  * (|_no_desc):	former gets callsite descriptor as 1st arg (for prdbgs)
  */
-#define __dynamic_func_call_cls(id, cls, fmt, func, ...) do {	\
+#define __dynamic_func_call_cls(id, cls, fmt, func, ...) ({	\
 	DEFINE_DYNAMIC_DEBUG_METADATA_CLS(id, cls, fmt);	\
 	if (DYNAMIC_DEBUG_BRANCH(id))				\
 		func(&id, ##__VA_ARGS__);			\
-} while (0)
+})
 #define __dynamic_func_call(id, fmt, func, ...)				\
 	__dynamic_func_call_cls(id, _DPRINTK_CLASS_DFLT, fmt,		\
 				func, ##__VA_ARGS__)
 
-#define __dynamic_func_call_cls_no_desc(id, cls, fmt, func, ...) do {	\
+#define __dynamic_func_call_cls_no_desc(id, cls, fmt, func, ...) ({	\
 	DEFINE_DYNAMIC_DEBUG_METADATA_CLS(id, cls, fmt);		\
 	if (DYNAMIC_DEBUG_BRANCH(id))					\
 		func(__VA_ARGS__);					\
-} while (0)
+})
 #define __dynamic_func_call_no_desc(id, fmt, func, ...)			\
 	__dynamic_func_call_cls_no_desc(id, _DPRINTK_CLASS_DFLT,	\
 					fmt, func, ##__VA_ARGS__)
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:38 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:38 +1300
Subject: [PATCH v7 21/31] dyndbg-API: replace DECLARE_DYNDBG_CLASSMAP
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-22-jim.cromie@gmail.com>

commit aad0214f3026 ("dyndbg: add DECLARE_DYNDBG_CLASSMAP macro")

DECLARE_DYNDBG_CLASSMAP() has a design error; its usage fails a
basic K&R rule: "define once, refer many times".

When CONFIG_DRM_USE_DYNAMIC_DEBUG=y, it is used across DRM core &
drivers; each invocation allocates/inits the classmap understood by
that module.  They *all* must match for the DRM modules to respond
consistently when drm.debug categories are enabled.  This is at least
a maintenance hassle.

Worse, its the root-cause of the CONFIG_DRM_USE_DYNAMIC_DEBUG=Y
regression; its use in both core & drivers obfuscates the 2 roles,
muddling the design, yielding an incomplete initialization when
modprobing drivers:

1st drm.ko loads, and dyndbg initializes its drm.debug callsites, then
a drm-driver loads, but too late for the drm.debug enablement.

And that gave us:
commit bb2ff6c27bc9 ("drm: Disable dynamic debug as broken")

So retire it, replace with 2 macros:
  DYNAMIC_DEBUG_CLASSMAP_DEFINE - invoked once from core - drm.ko
  DYNAMIC_DEBUG_CLASSMAP_USE    - from all drm drivers and helpers.
  NB: name-space de-noise

DYNAMIC_DEBUG_CLASSMAP_DEFINE: this reworks DECLARE_DYNDBG_CLASSMAP,
basically by dropping the static qualifier on the classmap, and
exporting it instead.

DYNAMIC_DEBUG_CLASSMAP_USE: then refers to the exported var by name:
  used from drivers, helper-mods
  lets us drop the repetitive "classname" declarations
  fixes 2nd-defn problem
  creates a ddebug_class_user record in new __dyndbg_class_users section
  new section is scanned "differently"

DECLARE_DYNDBG_CLASSMAP is preserved temporarily, to decouple DRM
adaptation work and avoid compile-errs before its done.

The DEFINE,USE distinction, and the separate classmap-use record,
allows dyndbg to initialize the driver's & helper's drm.debug
callsites separately after each is modprobed.

Basically, the classmap initial scan is repeated for classmap-users.

dyndbg's existing __dyndbg_classes[] section does:

. catalogs the module's classmaps
. tells dyndbg about them, allowing >control
. DYNAMIC_DEBUG_CLASSMAP_DEFINE creates section records.
. we rename it to: __dyndbg_class_maps[]

this patch adds __dyndbg_class_users[] section:

. catalogs users of classmap definitions from elsewhere
. authorizes dyndbg to >control user's class'd prdbgs
. DYNAMIC_DEBUG_CLASSMAP_USE() creates section records.

Now ddebug_add_module(etal) can handle classmap-uses similar to (and
after) classmaps; when a dependent module is loaded, if it has
classmap-uses (to a classmap-def in another module), that module's
kernel params are scanned to find if it has a kparam that is wired to
dyndbg's param-ops, and whose classmap is the one being ref'd.

To support this, theres a few data/header changes:

new struct ddebug_class_user
  contains: user-module-name, &classmap-defn
  it records drm-driver's use of a classmap in the section, allowing lookup

struct ddebug_info gets 2 new fields for the new sections:
  class_users, num_class_users.
  set by dynamic_debug_init() for builtins.
  or by kernel/module/main:load_info() for loadable modules.

vmlinux.lds.h: new BOUNDED_SECTION for __dyndbg_class_users.
this creates start,len C symbol-names for the section.

TLDR ?

dynamic_debug.c: 2 changes from ddebug_add_module() & ddebug_change():

ddebug_add_module():

ddebug_attach_module_classes() is reworked/renamed/split into
debug_apply_class_maps(), ddebug_apply_class_users(), which both call
ddebug_apply_params().

ddebug_apply_params(new fn):

It scans module's/builtin kernel-params, calls ddebug_match_apply_kparam
for each to find any params/sysfs-nodes which may be wired to a classmap.

ddebug_match_apply_kparam(new fn):

1st, it tests the kernel-param.ops is dyndbg's; this guarantees that
the attached arg is a struct ddebug_class_param, which has a ref to
the param's state, and to the classmap defining the param's handling.

2nd, it requires that the classmap ref'd by the kparam is the one
we've been called for; modules can use many separate classmaps (as
test_dynamic_debug does).

Then apply the "parent" kparam's setting to the dependent module,
using ddebug_apply_class_bitmap().

ddebug_change(and callees) also gets adjustments:

ddebug_find_valid_class(): This does a search over the module's
classmaps, looking for the class FOO echo'd to >control.  So now it
searches over __dyndbg_class_users[] after __dyndbg_classes[].

ddebug_class_name(): return class-names for defined OR used classes.

test_dynamic_debug.c, test_dynamic_debug_submod.c:

This demonstrates the 2 types of classmaps & sysfs-params, following
the 4-part recipe:

0. define an enum for the classmap's class_ids
   drm.debug gives us DRM_UT_<*> (aka <T>)
   multiple classmaps in a module(s) must share 0-62 classid space.

1. DYNAMIC_DEBUG_CLASSMAP_DEFINE(classmap_name, .. "<T>")
   names the classes, maps them to consecutive class-ids.
   convention here is stringified ENUM_SYMBOLS
   these become API/ABI if 2 is done.

2. DYNAMIC_DEBUG_CLASSMAP_PARAM* (classmap_name)
   adds a controlling kparam to the class

3. DYNAMIC_DEBUG_CLASSMAP_USE(classmap_name)
   for subsystem/group/drivers to use extern created by 1.

Move all the enum declarations together, to better explain how they
share the 0..62 class-id space available to a module (non-overlapping
subranges).

reorg macros 2,3 by name.  This gives a tabular format, making it easy
to see the pattern of repetition, and the points of change.

And extend the test to replicate the 2-module (parent & dependent)
scenario which caused the CONFIG_DRM_USE_DYNAMIC_DEBUG=y regression
seen in drm & drivers.

The _submod.c is a 2-line file: #define _SUBMOD, #include parent.

This gives identical complements of prdbgs in parent & _submod, and
thus identical print behavior when all of: >control, >params, and
parent->_submod propagation are working correctly.

It also puts all the parent/_submod declarations together in the same
source; the new ifdef _SUBMOD block invokes DYNAMIC_DEBUG_CLASSMAP_USE
for the 2 test-interfaces.  I think this is clearer.

These 2 modules are both tristate, allowing 3 super/sub combos: Y/Y,
Y/M, M/M (not N/Y, since this is disallowed by dependence).

Y/Y, Y/M testing once exposed a missing __align(8) in the _METADATA
macro, which M/M didn't see, probably because the module-loader memory
placement constrained it from misalignment.

Fixes: aad0214f3026 ("dyndbg: add DECLARE_DYNDBG_CLASSMAP macro")
cc: linux-doc at vger.kernel.org
Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
replace di with &dt->info, since its stale
fix dd_mark_vector_subrange macro param ordering to match kdoc
---
 MAINTAINERS                       |   2 +-
 include/asm-generic/vmlinux.lds.h |   1 +
 include/linux/dynamic_debug.h     | 139 +++++++++++++++++++++---
 kernel/module/main.c              |   3 +
 lib/Kconfig.debug                 |  24 ++++-
 lib/Makefile                      |   5 +
 lib/dynamic_debug.c               | 172 +++++++++++++++++++++++++-----
 lib/test_dynamic_debug.c          | 132 ++++++++++++++++-------
 lib/test_dynamic_debug_submod.c   |  14 +++
 9 files changed, 413 insertions(+), 79 deletions(-)
 create mode 100644 lib/test_dynamic_debug_submod.c

diff --git a/MAINTAINERS b/MAINTAINERS
index b9d38a5b4f12..b6c549cc27e6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8771,7 +8771,7 @@ M:	Jim Cromie <jim.cromie at gmail.com>
 S:	Maintained
 F:	include/linux/dynamic_debug.h
 F:	lib/dynamic_debug.c
-F:	lib/test_dynamic_debug.c
+F:	lib/test_dynamic_debug*.c
 F:	tools/testing/selftests/dynamic_debug/*
 
 DYNAMIC INTERRUPT MODERATION
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index da15cf0c16d0..c7d85b857997 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -367,6 +367,7 @@ defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG)
 	/* implement dynamic printk debug */				\
 	. = ALIGN(8);							\
 	BOUNDED_SECTION_BY(__dyndbg_class_maps, ___dyndbg_class_maps)	\
+	BOUNDED_SECTION_BY(__dyndbg_class_users, ___dyndbg_class_users)	\
 	BOUNDED_SECTION_BY(__dyndbg_descriptors, ___dyndbg_descs)	\
 	CODETAG_SECTIONS()						\
 	LIKELY_PROFILE()		       				\
diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index c4ebbccca5d1..905db0b49104 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -71,8 +71,11 @@ enum ddebug_class_map_type {
 	 */
 };
 
+/*
+ * map @class_names 0..N to consecutive constants starting at @base.
+ */
 struct _ddebug_class_map {
-	struct module *mod;	/* NULL for builtins */
+	const struct module *mod;	/* NULL for builtins */
 	const char *mod_name;
 	const char **class_names;
 	const int length;
@@ -80,10 +83,18 @@ struct _ddebug_class_map {
 	enum ddebug_class_map_type map_type;
 };
 
+struct _ddebug_class_user {
+	char *mod_name;
+	struct _ddebug_class_map *map;
+	const int base;		/* user offset to re-number the used map */
+};
+
 /*
- * @_ddebug_info: gathers module/builtin dyndbg_* __sections together.
+ * @_ddebug_info: gathers module/builtin __dyndbg_<T> __sections
+ * together, each is a vec_<T>: a struct { struct T start[], int len }.
+ *
  * For builtins, it is used as a cursor, with the inner structs
- * marking sub-vectors of the builtin __sections in DATA.
+ * marking sub-vectors of the builtin __sections in DATA_DATA
  */
 struct _ddebug_descs {
 	struct _ddebug *start;
@@ -95,10 +106,16 @@ struct _ddebug_class_maps {
 	int len;
 };
 
+struct _ddebug_class_users {
+	struct _ddebug_class_user *start;
+	int len;
+};
+
 struct _ddebug_info {
 	const char *mod_name;
 	struct _ddebug_descs descs;
 	struct _ddebug_class_maps maps;
+	struct _ddebug_class_users users;
 };
 
 struct _ddebug_class_param {
@@ -117,12 +134,81 @@ struct _ddebug_class_param {
 #if defined(CONFIG_DYNAMIC_DEBUG) || \
 	(defined(CONFIG_DYNAMIC_DEBUG_CORE) && defined(DYNAMIC_DEBUG_MODULE))
 
+/*
+ * dyndbg classmaps is modelled closely upon drm.debug:
+ *
+ *  1. run-time control via sysfs node (api/abi)
+ *  2. each bit 0..N controls a single "category"
+ *  3. a pr_debug can have only 1 category, not several.
+ *  4. "kind" is a compile-time constant: 0..N or BIT() thereof
+ *  5. macro impls - give compile-time resolution or fail.
+ *
+ * dyndbg classmaps design axioms/constraints:
+ *
+ *  . optimizing compilers use 1-5 above, so preserve them.
+ *  . classmaps.class_id *is* the category.
+ *  . classmap definers/users are modules.
+ *  . every user wants 0..N
+ *  . 0..N exposes as ABI
+ *  . no 1 use-case wants N > 32, 16 is more usable
+ *  . N <= 64 in *all* cases
+ *  . modules/subsystems make category/classmap decisions
+ *  . ie an enum: DRM has DRM_UT_CORE..DRM_UT_DRMRES
+ *  . some categories are exposed to user: ABI
+ *  . making modules change their numbering is bogus, avoid if possible
+ *
+ * We can solve for all these at once:
+ *  A: map class-names to a .class_id range at compile-time
+ *  B: allow only "class NAME" changes to class'd callsites at run-time
+ *  C: users/modules must manage 0..62 hardcoded .class_id range limit.
+ *  D: existing pr_debugs get CLASS_DFLT=63
+ *
+ * By mapping class-names at >control to class-ids underneath, and
+ * responding only to class-names DEFINEd or USEd by the module, we
+ * can private-ize the class-id, and adjust class'd pr_debugs only by
+ * their names.
+ *
+ * This give us:
+ *  E: class_ids without classnames are unreachable
+ *  F: user modules opt-in by DEFINEing a classmap and/or USEing another
+ *
+ * Multi-classmap modules/groups are supported, if the classmaps share
+ * the class_id space [0..62] without overlap/conflict.
+ *
+ * NOTE: Due to the integer class_id, this api cannot disallow these:
+ * __pr_debug_cls(0, "fake CORE msg");  works only if a classmap maps 0.
+ * __pr_debug_cls(22, "no such class"); compiles but is not reachable
+ */
+
 /**
- * DECLARE_DYNDBG_CLASSMAP - declare classnames known by a module
- * @_var:   a struct ddebug_class_map, passed to module_param_cb
- * @_type:  enum class_map_type, chooses bits/verbose, numeric/symbolic
- * @_base:  offset of 1st class-name. splits .class_id space
- * @classes: class-names used to control class'd prdbgs
+ * DYNAMIC_DEBUG_CLASSMAP_DEFINE - define debug classes used by a module.
+ * @_var:   name of the classmap, exported for other modules coordinated use.
+ * @_mapty: enum ddebug_class_map_type: 0:DISJOINT - independent, 1:LEVEL - v2>v1
+ * @_base:  reserve N classids starting at _base, to split 0..62 classid space
+ * @classes: names of the N classes.
+ *
+ * This tells dyndbg what class_ids the module is using: _base..+N, by
+ * mapping names onto them.  This qualifies "class NAME" >controls on
+ * the defining module, ignoring unknown names.
+ */
+#define DYNAMIC_DEBUG_CLASSMAP_DEFINE(_var, _mapty, _base, ...)		\
+	static const char *_var##_classnames[] = { __VA_ARGS__ };	\
+	extern struct _ddebug_class_map _var;				\
+	struct _ddebug_class_map __aligned(8) __used			\
+		__section("__dyndbg_class_maps") _var = {		\
+		.mod = THIS_MODULE,					\
+		.mod_name = KBUILD_MODNAME,				\
+		.base = (_base),					\
+		.map_type = (_mapty),					\
+		.length = ARRAY_SIZE(_var##_classnames),		\
+		.class_names = _var##_classnames,			\
+	};								\
+	EXPORT_SYMBOL(_var)
+
+/*
+ * XXX: keep this until DRM adapts to use the DEFINE/USE api, it
+ * differs from DYNAMIC_DEBUG_CLASSMAP_DEFINE by the lack of the
+ * extern/EXPORT on the struct init, and cascading thinkos.
  */
 #define DECLARE_DYNDBG_CLASSMAP(_var, _maptype, _base, ...)		\
 	static const char *_var##_classnames[] = { __VA_ARGS__ };	\
@@ -136,6 +222,26 @@ struct _ddebug_class_param {
 		.class_names = _var##_classnames,			\
 	}
 
+/**
+ * DYNAMIC_DEBUG_CLASSMAP_USE - refer to a classmap, DEFINEd elsewhere.
+ * @_var: name of the exported classmap var
+ * @_not_yet: _base-like, but applies only to this USEr. (if needed)
+ *
+ * This tells dyndbg that the module has prdbgs with classids defined
+ * in the named classmap.  This qualifies "class NAME" >controls on
+ * the user module, and ignores unknown names.
+ */
+#define DYNAMIC_DEBUG_CLASSMAP_USE(_var)				\
+	DYNAMIC_DEBUG_CLASSMAP_USE_(_var, 0, __UNIQUE_ID(_ddebug_class_user))
+#define DYNAMIC_DEBUG_CLASSMAP_USE_(_var, _base, _uname)		\
+	extern struct _ddebug_class_map _var;				\
+	static struct _ddebug_class_user __aligned(8) __used		\
+	__section("__dyndbg_class_users") _uname = {			\
+		.mod_name = KBUILD_MODNAME,				\
+		.map = &(_var),						\
+		.base = _base						\
+	}
+
 extern __printf(2, 3)
 void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...);
 
@@ -287,12 +393,18 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
 				   KERN_DEBUG, prefix_str, prefix_type,	\
 				   rowsize, groupsize, buf, len, ascii)
 
-/* for test only, generally expect drm.debug style macro wrappers */
-#define __pr_debug_cls(cls, fmt, ...) do {			\
+/*
+ * This is the "model" class variant of pr_debug.  It is not really
+ * intended for direct use; I'd encourage DRM-style drm_dbg_<T>
+ * macros for the interface, along with an enum for the <T>
+ *
+ * __printf(2, 3) would apply.
+ */
+#define __pr_debug_cls(cls, fmt, ...) ({			\
 	BUILD_BUG_ON_MSG(!__builtin_constant_p(cls),		\
 			 "expecting constant class int/enum");	\
 	dynamic_pr_debug_cls(cls, fmt, ##__VA_ARGS__);		\
-	} while (0)
+})
 
 #else /* !(CONFIG_DYNAMIC_DEBUG || (CONFIG_DYNAMIC_DEBUG_CORE && DYNAMIC_DEBUG_MODULE)) */
 
@@ -300,6 +412,8 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
 #include <linux/errno.h>
 #include <linux/printk.h>
 
+#define DYNAMIC_DEBUG_CLASSMAP_DEFINE(_var, _mapty, _base, ...)
+#define DYNAMIC_DEBUG_CLASSMAP_USE(_var)
 #define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt)
 #define DYNAMIC_DEBUG_BRANCH(descriptor) false
 #define DECLARE_DYNDBG_CLASSMAP(...)
@@ -346,8 +460,7 @@ static inline int param_set_dyndbg_classes(const char *instr, const struct kerne
 static inline int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp)
 { return 0; }
 
-#endif
-
+#endif /* !CONFIG_DYNAMIC_DEBUG_CORE */
 
 extern const struct kernel_param_ops param_ops_dyndbg_classes;
 
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 1ccc5d4399c3..ee35238d2d0a 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -2716,6 +2716,9 @@ static int find_module_sections(struct module *mod, struct load_info *info)
 	mod->dyndbg_info.maps.start = section_objs(info, "__dyndbg_class_maps",
 						   sizeof(*mod->dyndbg_info.maps.start),
 						   &mod->dyndbg_info.maps.len);
+	mod->dyndbg_info.users.start = section_objs(info, "__dyndbg_class_users",
+						   sizeof(*mod->dyndbg_info.users.start),
+						   &mod->dyndbg_info.users.len);
 #endif
 
 	return 0;
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 713cc94caa02..9bc6f76830a6 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2979,12 +2979,26 @@ config TEST_STATIC_KEYS
 	  If unsure, say N.
 
 config TEST_DYNAMIC_DEBUG
-	tristate "Test DYNAMIC_DEBUG"
-	depends on DYNAMIC_DEBUG
+	tristate "Build test-dynamic-debug module"
+	depends on DYNAMIC_DEBUG || DYNAMIC_DEBUG_CORE
 	help
-	  This module registers a tracer callback to count enabled
-	  pr_debugs in a 'do_debugging' function, then alters their
-	  enablements, calls the function, and compares counts.
+	  This module exercises/demonstrates dyndbg's classmap API, by
+	  creating 2 classes: a DISJOINT classmap (supporting DRM.debug)
+	  and a LEVELS/VERBOSE classmap (like verbose2 > verbose1).
+
+	  If unsure, say N.
+
+config TEST_DYNAMIC_DEBUG_SUBMOD
+	tristate "Build test-dynamic-debug submodule"
+	default m
+	depends on DYNAMIC_DEBUG || DYNAMIC_DEBUG_CORE
+	depends on TEST_DYNAMIC_DEBUG
+	help
+	  This sub-module uses a classmap defined and exported by the
+	  parent module, recapitulating drm & driver's shared use of
+	  drm.debug to control enabled debug-categories.
+	  It is tristate, independent of parent, to allow testing all
+	  proper combinations of parent=y/m submod=y/m.
 
 	  If unsure, say N.
 
diff --git a/lib/Makefile b/lib/Makefile
index 1ab2c4be3b66..63ed5fabada2 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -82,6 +82,9 @@ obj-$(CONFIG_TEST_RHASHTABLE) += test_rhashtable.o
 obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_keys.o
 obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_key_base.o
 obj-$(CONFIG_TEST_DYNAMIC_DEBUG) += test_dynamic_debug.o
+obj-$(CONFIG_TEST_DYNAMIC_DEBUG_SUBMOD) += test_dynamic_debug_submod.o
+obj-$(CONFIG_TEST_PRINTF) += test_printf.o
+obj-$(CONFIG_TEST_SCANF) += test_scanf.o
 
 obj-$(CONFIG_TEST_BITMAP) += test_bitmap.o
 ifeq ($(CONFIG_CC_IS_CLANG)$(CONFIG_KASAN),yy)
@@ -204,6 +207,8 @@ obj-$(CONFIG_ARCH_NEED_CMPXCHG_1_EMU) += cmpxchg-emu.o
 obj-$(CONFIG_DYNAMIC_DEBUG_CORE) += dynamic_debug.o
 #ensure exported functions have prototypes
 CFLAGS_dynamic_debug.o := -DDYNAMIC_DEBUG_MODULE
+CFLAGS_test_dynamic_debug.o := -DDYNAMIC_DEBUG_MODULE
+CFLAGS_test_dynamic_debug_submod.o := -DDYNAMIC_DEBUG_MODULE
 
 obj-$(CONFIG_SYMBOLIC_ERRNAME) += errname.o
 
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 63bfe1891a9e..c60c2142f8ac 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -29,6 +29,7 @@
 #include <linux/string_helpers.h>
 #include <linux/uaccess.h>
 #include <linux/dynamic_debug.h>
+
 #include <linux/debugfs.h>
 #include <linux/slab.h>
 #include <linux/jump_label.h>
@@ -43,6 +44,8 @@ extern struct _ddebug __start___dyndbg_descs[];
 extern struct _ddebug __stop___dyndbg_descs[];
 extern struct _ddebug_class_map __start___dyndbg_class_maps[];
 extern struct _ddebug_class_map __stop___dyndbg_class_maps[];
+extern struct _ddebug_class_user __start___dyndbg_class_users[];
+extern struct _ddebug_class_user __stop___dyndbg_class_users[];
 
 struct ddebug_table {
 	struct list_head link;
@@ -168,20 +171,37 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
 		  query->first_lineno, query->last_lineno, query->class_string);
 }
 
-static struct _ddebug_class_map *ddebug_find_valid_class(struct ddebug_table const *dt,
-							 const char *class_string,
-							 int *class_id)
+#define vpr_di_info(di_p, msg_p, ...) ({				\
+	struct _ddebug_info const *_di = di_p;				\
+	v2pr_info(msg_p "module:%s nd:%d nc:%d nu:%d\n", ##__VA_ARGS__, \
+		  _di->mod_name, _di->descs.len, _di->maps.len,		\
+		  _di->users.len);					\
+	})
+
+static struct _ddebug_class_map *
+ddebug_find_valid_class(struct _ddebug_info const *di, const char *query_class, int *class_id)
 {
 	struct _ddebug_class_map *map;
+	struct _ddebug_class_user *cli;
 	int i, idx;
 
-	for_subvec(i, map, &dt->info, maps) {
-		idx = match_string(map->class_names, map->length, class_string);
+	for_subvec(i, map, di, maps) {
+		idx = match_string(map->class_names, map->length, query_class);
 		if (idx >= 0) {
+			vpr_di_info(di, "good-class: %s.%s ", map->mod_name, query_class);
 			*class_id = idx + map->base;
 			return map;
 		}
 	}
+	for_subvec(i, cli, di, users) {
+		idx = match_string(cli->map->class_names, cli->map->length, query_class);
+		if (idx >= 0) {
+			vpr_di_info(di, "class-ref: %s -> %s.%s ",
+				    cli->mod_name, cli->map->mod_name, query_class);
+			*class_id = idx + cli->map->base;
+			return cli->map;
+		}
+	}
 	*class_id = -ENOENT;
 	return NULL;
 }
@@ -238,8 +258,7 @@ static bool ddebug_match_desc(const struct ddebug_query *query,
 	return true;
 }
 
-static int ddebug_change(const struct ddebug_query *query,
-			 struct flag_settings *modifiers)
+static int ddebug_change(const struct ddebug_query *query, struct flag_settings *modifiers)
 {
 	int i;
 	struct ddebug_table *dt;
@@ -260,7 +279,8 @@ static int ddebug_change(const struct ddebug_query *query,
 			continue;
 
 		if (query->class_string) {
-			map = ddebug_find_valid_class(dt, query->class_string, &valid_class);
+			map = ddebug_find_valid_class(&dt->info, query->class_string,
+						      &valid_class);
 			if (!map)
 				continue;
 		} else {
@@ -590,7 +610,7 @@ static int ddebug_exec_query(char *query_string, const char *modname)
 
 /* handle multiple queries in query string, continue on error, return
    last error or number of matching callsites.  Module name is either
-   in param (for boot arg) or perhaps in query string.
+   in the modname arg (for boot args) or perhaps in query string.
 */
 static int ddebug_exec_queries(char *query, const char *modname)
 {
@@ -721,7 +741,7 @@ static int param_set_dyndbg_module_classes(const char *instr,
 /**
  * param_set_dyndbg_classes - classmap kparam setter
  * @instr: string echo>d to sysfs, input depends on map_type
- * @kp:    kp->arg has state: bits/lvl, map, map_type
+ * @kp:    kp->arg has state: bits/lvl, classmap, map_type
  *
  * enable/disable all class'd pr_debugs in the classmap. For LEVEL
  * map-types, enforce * relative levels by bitpos.
@@ -758,6 +778,7 @@ int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp)
 	default:
 		return -1;
 	}
+	return 0;
 }
 EXPORT_SYMBOL(param_get_dyndbg_classes);
 
@@ -1073,12 +1094,17 @@ static bool ddebug_class_in_range(const int class_id, const struct _ddebug_class
 static const char *ddebug_class_name(struct _ddebug_info *di, struct _ddebug *dp)
 {
 	struct _ddebug_class_map *map;
+	struct _ddebug_class_user *cli;
 	int i;
 
 	for_subvec(i, map, di, maps)
 		if (ddebug_class_in_range(dp->class_id, map))
 			return map->class_names[dp->class_id - map->base];
 
+	for_subvec(i, cli, di, users)
+		if (ddebug_class_in_range(dp->class_id, cli->map))
+			return cli->map->class_names[dp->class_id - cli->map->base];
+
 	return NULL;
 }
 
@@ -1159,9 +1185,85 @@ static const struct proc_ops proc_fops = {
 	.proc_write = ddebug_proc_write
 };
 
-static void ddebug_attach_module_classes(struct ddebug_table *dt, struct _ddebug_info *di)
+#define vpr_cm_info(cm_p, msg_fmt, ...) ({				\
+	struct _ddebug_class_map const *_cm = cm_p;			\
+	v2pr_info(msg_fmt "%s [%d..%d] %s..%s\n", ##__VA_ARGS__,	\
+		  _cm->mod_name, _cm->base, _cm->base + _cm->length,	\
+		  _cm->class_names[0], _cm->class_names[_cm->length - 1]); \
+	})
+
+static void ddebug_sync_classbits(const struct kernel_param *kp, const char *modname)
+{
+	const struct _ddebug_class_param *dcp = kp->arg;
+
+	/* clamp initial bitvec, mask off hi-bits */
+	if (*dcp->bits & ~CLASSMAP_BITMASK(dcp->map->length)) {
+		*dcp->bits &= CLASSMAP_BITMASK(dcp->map->length);
+		v2pr_info("preset classbits: %lx\n", *dcp->bits);
+	}
+	/* force class'd prdbgs (in USEr module) to match (DEFINEr module) class-param */
+	ddebug_apply_class_bitmap(dcp, dcp->bits, ~0, modname);
+	ddebug_apply_class_bitmap(dcp, dcp->bits, 0, modname);
+}
+
+static void ddebug_match_apply_kparam(const struct kernel_param *kp,
+				      const struct _ddebug_class_map *map,
+				      const char *mod_name)
+{
+	struct _ddebug_class_param *dcp;
+
+	if (kp->ops != &param_ops_dyndbg_classes)
+		return;
+
+	dcp = (struct _ddebug_class_param *)kp->arg;
+
+	if (map == dcp->map) {
+		v2pr_info(" kp:%s.%s =0x%lx", mod_name, kp->name, *dcp->bits);
+		vpr_cm_info(map, " %s maps ", mod_name);
+		ddebug_sync_classbits(kp, mod_name);
+	}
+}
+
+static void ddebug_apply_params(const struct _ddebug_class_map *cm, const char *mod_name)
+{
+	const struct kernel_param *kp;
+#if IS_ENABLED(CONFIG_MODULES)
+	int i;
+
+	if (cm->mod) {
+		vpr_cm_info(cm, "loaded classmap: %s ", mod_name);
+		/* ifdef protects the cm->mod->kp deref */
+		for (i = 0, kp = cm->mod->kp; i < cm->mod->num_kp; i++, kp++)
+			ddebug_match_apply_kparam(kp, cm, mod_name);
+	}
+#endif
+	if (!cm->mod) {
+		vpr_cm_info(cm, "builtin classmap: %s ", mod_name);
+		for (kp = __start___param; kp < __stop___param; kp++)
+			ddebug_match_apply_kparam(kp, cm, mod_name);
+	}
+}
+
+static void ddebug_apply_class_maps(const struct _ddebug_info *di)
 {
-	vpr_info("module:%s attached %d classes\n", dt->info.mod_name, dt->info.maps.len);
+	struct _ddebug_class_map *cm;
+	int i;
+
+	for_subvec(i, cm, di, maps)
+		ddebug_apply_params(cm, cm->mod_name);
+
+	vpr_di_info(di, "attached %d class-maps to ", i);
+}
+
+static void ddebug_apply_class_users(const struct _ddebug_info *di)
+{
+	struct _ddebug_class_user *cli;
+	int i;
+
+	for_subvec(i, cli, di, users)
+		ddebug_apply_params(cli->map, cli->mod_name);
+
+	vpr_di_info(di, "attached %d class-users to ", i);
 }
 
 /*
@@ -1190,6 +1292,22 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt, struct _ddebug
 	(__dst)->info._vec.len = __nc;					\
 })
 
+static int __maybe_unused
+ddebug_class_range_overlap(struct _ddebug_class_map *cm,
+			   u64 *reserved_ids)
+{
+	u64 range = (((1ULL << cm->length) - 1) << cm->base);
+
+	if (range & *reserved_ids) {
+		pr_err("[%d..%d] on %s conflicts with %llx\n", cm->base,
+		       cm->base + cm->length - 1, cm->class_names[0],
+		       *reserved_ids);
+		return -EINVAL;
+	}
+	*reserved_ids |= range;
+	return 0;
+}
+
 /*
  * Allocate a new ddebug_table for the given module
  * and add it to the global list.
@@ -1198,6 +1316,7 @@ static int ddebug_add_module(struct _ddebug_info *di)
 {
 	struct ddebug_table *dt;
 	struct _ddebug_class_map *cm;
+	struct _ddebug_class_user *cli;
 	int i;
 
 	if (!di->descs.len)
@@ -1210,26 +1329,29 @@ static int ddebug_add_module(struct _ddebug_info *di)
 		pr_err("error adding module: %s\n", di->mod_name);
 		return -ENOMEM;
 	}
+	INIT_LIST_HEAD(&dt->link);
 	/*
-	 * For built-in modules, name (as supplied in di by its
-	 * callers) lives in .rodata and is immortal. For loaded
-	 * modules, name points at the name[] member of struct module,
-	 * which lives at least as long as this struct ddebug_table.
+	 * For built-in modules, di-> referents live in .*data and are
+	 * immortal. For loaded modules, di points at the dyndbg_info
+	 * member of its struct module, which lives at least as
+	 * long as this struct ddebug_table.
 	 */
 	dt->info = *di;
-
-	INIT_LIST_HEAD(&dt->link);
-
-	dd_mark_vector_subrange(i, cm, di, maps, dt);
-
-	if (di->maps.len)
-		ddebug_attach_module_classes(dt, di);
+	dd_mark_vector_subrange(i, cm, &dt->info, maps, dt);
+	dd_mark_vector_subrange(i, cli, &dt->info, users, dt);
+	/* now di is stale */
 
 	mutex_lock(&ddebug_lock);
 	list_add_tail(&dt->link, &ddebug_tables);
 	mutex_unlock(&ddebug_lock);
 
-	vpr_info("%3u debug prints in module %s\n", di->descs.len, di->mod_name);
+	if (dt->info.maps.len)
+		ddebug_apply_class_maps(&dt->info);
+	if (dt->info.users.len)
+		ddebug_apply_class_users(&dt->info);
+
+	vpr_info("%3u debug prints in module %s\n",
+		 dt->info.descs.len, dt->info.mod_name);
 	return 0;
 }
 
@@ -1379,8 +1501,10 @@ static int __init dynamic_debug_init(void)
 	struct _ddebug_info di = {
 		.descs.start = __start___dyndbg_descs,
 		.maps.start  = __start___dyndbg_class_maps,
+		.users.start = __start___dyndbg_class_users,
 		.descs.len = __stop___dyndbg_descs - __start___dyndbg_descs,
 		.maps.len  = __stop___dyndbg_class_maps - __start___dyndbg_class_maps,
+		.users.len = __stop___dyndbg_class_users - __start___dyndbg_class_users,
 	};
 
 #ifdef CONFIG_MODULES
diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
index 9c3e53cd26bd..6c4548f63512 100644
--- a/lib/test_dynamic_debug.c
+++ b/lib/test_dynamic_debug.c
@@ -6,11 +6,30 @@
  *      Jim Cromie	<jim.cromie at gmail.com>
  */
 
-#define pr_fmt(fmt) "test_dd: " fmt
+/*
+ * This file is built 2x, also making test_dynamic_debug_submod.ko,
+ * whose 2-line src file #includes this file.  This gives us a _submod
+ * clone with identical pr_debugs, without further maintenance.
+ *
+ * If things are working properly, they should operate identically
+ * when printed or adjusted by >control.  This eases visual perusal of
+ * the logs, and simplifies testing, by easing the proper accounting
+ * of expectations.
+ *
+ * It also puts both halves of the subsystem _DEFINE & _USE use case
+ * together, and integrates the common ENUM providing both class_ids
+ * and class-names to both _DEFINErs and _USERs.  I think this makes
+ * the usage clearer.
+ */
+#if defined(TEST_DYNAMIC_DEBUG_SUBMOD)
+  #define pr_fmt(fmt) "test_dd_submod: " fmt
+#else
+  #define pr_fmt(fmt) "test_dd: " fmt
+#endif
 
 #include <linux/module.h>
 
-/* run tests by reading or writing sysfs node: do_prints */
+/* re-gen output by reading or writing sysfs node: do_prints */
 
 static void do_prints(void); /* device under test */
 static int param_set_do_prints(const char *instr, const struct kernel_param *kp)
@@ -29,24 +48,39 @@ static const struct kernel_param_ops param_ops_do_prints = {
 };
 module_param_cb(do_prints, &param_ops_do_prints, NULL, 0600);
 
-/*
- * Using the CLASSMAP api:
- * - classmaps must have corresponding enum
- * - enum symbols must match/correlate with class-name strings in the map.
- * - base must equal enum's 1st value
- * - multiple maps must set their base to share the 0-30 class_id space !!
- *   (build-bug-on tips welcome)
- * Additionally, here:
- * - tie together sysname, mapname, bitsname, flagsname
- */
-#define DD_SYS_WRAP(_model, _flags)					\
-	static unsigned long bits_##_model;				\
-	static struct _ddebug_class_param _flags##_model = {		\
+#define CLASSMAP_BITMASK(width, base) (((1UL << (width)) - 1) << (base))
+
+/* sysfs param wrapper, proto-API */
+#define DYNAMIC_DEBUG_CLASSMAP_PARAM_(_model, _flags, _init)		\
+	static unsigned long bits_##_model = _init;			\
+	static struct _ddebug_class_param _flags##_##_model = {		\
 		.bits = &bits_##_model,					\
 		.flags = #_flags,					\
 		.map = &map_##_model,					\
 	};								\
-	module_param_cb(_flags##_##_model, &param_ops_dyndbg_classes, &_flags##_model, 0600)
+	module_param_cb(_flags##_##_model, &param_ops_dyndbg_classes,	\
+			&_flags##_##_model, 0600)
+#ifdef DEBUG
+#define DYNAMIC_DEBUG_CLASSMAP_PARAM(_model, _flags)		\
+	DYNAMIC_DEBUG_CLASSMAP_PARAM_(_model, _flags, ~0)
+#else
+#define DYNAMIC_DEBUG_CLASSMAP_PARAM(_model, _flags)		\
+	DYNAMIC_DEBUG_CLASSMAP_PARAM_(_model, _flags, 0)
+#endif
+
+/*
+ * Demonstrate/test DISJOINT & LEVEL typed classmaps with a sys-param.
+ *
+ * To comport with DRM debug-category (an int), classmaps map names to
+ * ids (also an int).  So a classmap starts with an enum; DRM has enum
+ * debug_category: with DRM_UT_<CORE,DRIVER,KMS,etc>.  We use the enum
+ * values as class-ids, and stringified enum-symbols as classnames.
+ *
+ * Modules with multiple CLASSMAPS must have enums with distinct
+ * value-ranges, as arranged below with explicit enum_sym = X inits.
+ * To clarify this sharing, declare the 2 enums now, for the 2
+ * different classmap types
+ */
 
 /* numeric input, independent bits */
 enum cat_disjoint_bits {
@@ -60,26 +94,51 @@ enum cat_disjoint_bits {
 	D2_LEASE,
 	D2_DP,
 	D2_DRMRES };
-DECLARE_DYNDBG_CLASSMAP(map_disjoint_bits, DD_CLASS_TYPE_DISJOINT_BITS, 0,
-			"D2_CORE",
-			"D2_DRIVER",
-			"D2_KMS",
-			"D2_PRIME",
-			"D2_ATOMIC",
-			"D2_VBL",
-			"D2_STATE",
-			"D2_LEASE",
-			"D2_DP",
-			"D2_DRMRES");
-DD_SYS_WRAP(disjoint_bits, p);
-DD_SYS_WRAP(disjoint_bits, T);
-
-/* numeric verbosity, V2 > V1 related */
-enum cat_level_num { V0 = 14, V1, V2, V3, V4, V5, V6, V7 };
-DECLARE_DYNDBG_CLASSMAP(map_level_num, DD_CLASS_TYPE_LEVEL_NUM, 14,
-		       "V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7");
-DD_SYS_WRAP(level_num, p);
-DD_SYS_WRAP(level_num, T);
+
+/* numeric verbosity, V2 > V1 related.  V0 is > D2_DRMRES */
+enum cat_level_num { V0 = 16, V1, V2, V3, V4, V5, V6, V7 };
+
+/* recapitulate DRM's multi-classmap setup */
+#if !defined(TEST_DYNAMIC_DEBUG_SUBMOD)
+/*
+ * In single user, or parent / coordinator (drm.ko) modules, define
+ * classmaps on the client enums above, and then declares the PARAMS
+ * ref'g the classmaps.  Each is exported.
+ */
+DYNAMIC_DEBUG_CLASSMAP_DEFINE(map_disjoint_bits, DD_CLASS_TYPE_DISJOINT_BITS,
+			      D2_CORE,
+			      "D2_CORE",
+			      "D2_DRIVER",
+			      "D2_KMS",
+			      "D2_PRIME",
+			      "D2_ATOMIC",
+			      "D2_VBL",
+			      "D2_STATE",
+			      "D2_LEASE",
+			      "D2_DP",
+			      "D2_DRMRES");
+
+DYNAMIC_DEBUG_CLASSMAP_DEFINE(map_level_num, DD_CLASS_TYPE_LEVEL_NUM,
+			      V0, "V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7");
+
+/*
+ * now add the sysfs-params
+ */
+
+DYNAMIC_DEBUG_CLASSMAP_PARAM(disjoint_bits, p);
+DYNAMIC_DEBUG_CLASSMAP_PARAM(level_num, p);
+
+#else /* TEST_DYNAMIC_DEBUG_SUBMOD */
+
+/*
+ * in submod/drm-drivers, use the classmaps defined in top/parent
+ * module above.
+ */
+
+DYNAMIC_DEBUG_CLASSMAP_USE(map_disjoint_bits);
+DYNAMIC_DEBUG_CLASSMAP_USE(map_level_num);
+
+#endif
 
 /* stand-in for all pr_debug etc */
 #define prdbg(SYM) __pr_debug_cls(SYM, #SYM " msg\n")
@@ -115,6 +174,7 @@ static void do_levels(void)
 
 static void do_prints(void)
 {
+	pr_debug("do_prints:\n");
 	do_cats();
 	do_levels();
 }
diff --git a/lib/test_dynamic_debug_submod.c b/lib/test_dynamic_debug_submod.c
new file mode 100644
index 000000000000..672aabf40160
--- /dev/null
+++ b/lib/test_dynamic_debug_submod.c
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kernel module for testing dynamic_debug
+ *
+ * Authors:
+ *      Jim Cromie	<jim.cromie at gmail.com>
+ */
+
+/*
+ * clone the parent, inherit all the properties, for consistency and
+ * simpler accounting in test expectations.
+ */
+#define TEST_DYNAMIC_DEBUG_SUBMOD
+#include "test_dynamic_debug.c"
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:39 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:39 +1300
Subject: [PATCH v7 22/31] dyndbg: detect class_id reservation conflicts
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-23-jim.cromie@gmail.com>

If a module _DEFINEs 2 or more classmaps, it must devise them to share
the per-module 0..62 class-id space; ie their respective base,+length
reservations cannot overlap.

To detect conflicts at modprobe, add ddebug_class_range_overlap(),
call it from ddebug_add_module(), and WARN and return -EINVAL when
they're detected.

This insures that class_id -> classname lookup has just 1 answer, so
the 1st-found search in find-class-name works properly.

test_dynamic_debug.c:

If built with -DFORCE_CLASSID_CONFLICT, the test-modules invoke 2
conflicting DYNAMIC_DEBUG_CLASSMAP_DEFINE() declarations, into parent
and the _submod.  These conflict with one of the good ones in the
parent (D2_CORE..etc), causing the modprobe(s) to warn

Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 lib/dynamic_debug.c      | 10 ++++++++++
 lib/test_dynamic_debug.c |  8 ++++++++
 2 files changed, 18 insertions(+)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index c60c2142f8ac..e5a18a7d3780 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -1317,6 +1317,7 @@ static int ddebug_add_module(struct _ddebug_info *di)
 	struct ddebug_table *dt;
 	struct _ddebug_class_map *cm;
 	struct _ddebug_class_user *cli;
+	u64 reserved_ids = 0;
 	int i;
 
 	if (!di->descs.len)
@@ -1341,6 +1342,11 @@ static int ddebug_add_module(struct _ddebug_info *di)
 	dd_mark_vector_subrange(i, cli, &dt->info, users, dt);
 	/* now di is stale */
 
+	/* insure 2+ classmaps share the per-module 0..62 class_id space */
+	for_subvec(i, cm, &dt->info, maps)
+		if (ddebug_class_range_overlap(cm, &reserved_ids))
+			goto cleanup;
+
 	mutex_lock(&ddebug_lock);
 	list_add_tail(&dt->link, &ddebug_tables);
 	mutex_unlock(&ddebug_lock);
@@ -1353,6 +1359,10 @@ static int ddebug_add_module(struct _ddebug_info *di)
 	vpr_info("%3u debug prints in module %s\n",
 		 dt->info.descs.len, dt->info.mod_name);
 	return 0;
+cleanup:
+	WARN_ONCE("dyndbg multi-classmap conflict in %s\n", di->mod_name);
+	kfree(dt);
+	return -EINVAL;
 }
 
 /* helper for ddebug_dyndbg_(boot|module)_param_cb */
diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
index 6c4548f63512..1ba4be9a403a 100644
--- a/lib/test_dynamic_debug.c
+++ b/lib/test_dynamic_debug.c
@@ -128,6 +128,14 @@ DYNAMIC_DEBUG_CLASSMAP_DEFINE(map_level_num, DD_CLASS_TYPE_LEVEL_NUM,
 DYNAMIC_DEBUG_CLASSMAP_PARAM(disjoint_bits, p);
 DYNAMIC_DEBUG_CLASSMAP_PARAM(level_num, p);
 
+#ifdef FORCE_CLASSID_CONFLICT
+/*
+ * Enable with -Dflag on compile to test overlapping class-id range
+ * detection.  This should warn on modprobes.
+ */
+DYNDBG_CLASSMAP_DEFINE(classid_range_conflict, 0, D2_CORE + 1, "D3_CORE");
+#endif
+
 #else /* TEST_DYNAMIC_DEBUG_SUBMOD */
 
 /*
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:40 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:40 +1300
Subject: [PATCH v7 23/31] dyndbg: check DYNAMIC_DEBUG_CLASSMAP_DEFINE args at compile-time
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-24-jim.cromie@gmail.com>

Add __DYNAMIC_DEBUG_CLASSMAP_CHECK to implement the following
arg-checks at compile-time:

	0 <= _base < 63
	class_names is not empty
	class_names[0] is a string
	(class_names.length + _base) < 63

These compile-time checks will prevent several simple misuses, and
will issue obvious errors if violated.

4 such examples are added to test_dynamic_debug_submod.ko, and will
fail compilation if -DDD_MACRO_ARGCHECK is added to cflags.  This
wouldn't be a useful CONFIG_ item, since it breaks the build.

Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 include/linux/dynamic_debug.h |  9 +++++++++
 lib/test_dynamic_debug.c      | 13 ++++++++++++-
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 905db0b49104..b19c9b1d53b6 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -180,6 +180,14 @@ struct _ddebug_class_param {
  * __pr_debug_cls(22, "no such class"); compiles but is not reachable
  */
 
+#define __DYNAMIC_DEBUG_CLASSMAP_CHECK(_clnames, _base)			\
+	static_assert(((_base) >= 0 && (_base) < _DPRINTK_CLASS_DFLT),	\
+		      "_base must be in 0..62");			\
+	static_assert(ARRAY_SIZE(_clnames) > 0,				\
+		      "classnames array size must be > 0");		\
+	static_assert((ARRAY_SIZE(_clnames) + (_base)) < _DPRINTK_CLASS_DFLT, \
+		      "_base + classnames.length exceeds range")
+
 /**
  * DYNAMIC_DEBUG_CLASSMAP_DEFINE - define debug classes used by a module.
  * @_var:   name of the classmap, exported for other modules coordinated use.
@@ -193,6 +201,7 @@ struct _ddebug_class_param {
  */
 #define DYNAMIC_DEBUG_CLASSMAP_DEFINE(_var, _mapty, _base, ...)		\
 	static const char *_var##_classnames[] = { __VA_ARGS__ };	\
+	__DYNAMIC_DEBUG_CLASSMAP_CHECK(_var##_classnames, (_base));	\
 	extern struct _ddebug_class_map _var;				\
 	struct _ddebug_class_map __aligned(8) __used			\
 		__section("__dyndbg_class_maps") _var = {		\
diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
index 1ba4be9a403a..b2bdfdfb6ba1 100644
--- a/lib/test_dynamic_debug.c
+++ b/lib/test_dynamic_debug.c
@@ -133,7 +133,7 @@ DYNAMIC_DEBUG_CLASSMAP_PARAM(level_num, p);
  * Enable with -Dflag on compile to test overlapping class-id range
  * detection.  This should warn on modprobes.
  */
-DYNDBG_CLASSMAP_DEFINE(classid_range_conflict, 0, D2_CORE + 1, "D3_CORE");
+DYNAMIC_DEBUG_CLASSMAP_DEFINE(classid_range_conflict, 0, D2_CORE + 1, "D3_CORE");
 #endif
 
 #else /* TEST_DYNAMIC_DEBUG_SUBMOD */
@@ -146,8 +146,19 @@ DYNDBG_CLASSMAP_DEFINE(classid_range_conflict, 0, D2_CORE + 1, "D3_CORE");
 DYNAMIC_DEBUG_CLASSMAP_USE(map_disjoint_bits);
 DYNAMIC_DEBUG_CLASSMAP_USE(map_level_num);
 
+#if defined(DD_MACRO_ARGCHECK)
+/*
+ * Exersize compile-time arg-checks in DYNAMIC_DEBUG_CLASSMAP_DEFINE.
+ * These will break compilation.
+ */
+DYNAMIC_DEBUG_CLASSMAP_DEFINE(fail_base_neg, 0, -1, "NEGATIVE_BASE_ARG");
+DYNAMIC_DEBUG_CLASSMAP_DEFINE(fail_base_big, 0, 100, "TOOBIG_BASE_ARG");
+DYNAMIC_DEBUG_CLASSMAP_DEFINE(fail_str_type, 0, 0, 1 /* not a string */);
+DYNAMIC_DEBUG_CLASSMAP_DEFINE(fail_emptyclass, 0, 0 /* ,empty */);
 #endif
 
+#endif /* TEST_DYNAMIC_DEBUG_SUBMOD */
+
 /* stand-in for all pr_debug etc */
 #define prdbg(SYM) __pr_debug_cls(SYM, #SYM " msg\n")
 
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:41 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:41 +1300
Subject: [PATCH v7 24/31] dyndbg-test: change do_prints testpoint to accept a loopct
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-25-jim.cromie@gmail.com>

echo 1000 > /sys/module/test_dynamic_debug/parameters/do_prints

This allows its use as a scriptable load generator, to generate
dynamic-prefix-emits for flag combinations vs undecorated messages.
This will make it easy to assess the cost of the prefixing.

Reading the ./do_prints node also prints messages (once) to the-log.

Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 lib/test_dynamic_debug.c | 32 +++++++++++++++++++++-----------
 1 file changed, 21 insertions(+), 11 deletions(-)

diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
index b2bdfdfb6ba1..fa81177e8089 100644
--- a/lib/test_dynamic_debug.c
+++ b/lib/test_dynamic_debug.c
@@ -29,18 +29,25 @@
 
 #include <linux/module.h>
 
-/* re-gen output by reading or writing sysfs node: do_prints */
-
-static void do_prints(void); /* device under test */
+/* re-trigger debug output by reading or writing sysfs node: do_prints */
+static void do_prints(unsigned int); /* device under test */
 static int param_set_do_prints(const char *instr, const struct kernel_param *kp)
 {
-	do_prints();
+	int rc;
+	unsigned int ct;
+
+	rc = kstrtouint(instr, 0, &ct);
+	if (rc) {
+		pr_err("expecting numeric input, using 1 instead\n");
+		ct = 1;
+	}
+	do_prints(ct);
 	return 0;
 }
 static int param_get_do_prints(char *buffer, const struct kernel_param *kp)
 {
-	do_prints();
-	return scnprintf(buffer, PAGE_SIZE, "did do_prints\n");
+	do_prints(1);
+	return scnprintf(buffer, PAGE_SIZE, "did 1 do_prints\n");
 }
 static const struct kernel_param_ops param_ops_do_prints = {
 	.set = param_set_do_prints,
@@ -191,17 +198,20 @@ static void do_levels(void)
 	prdbg(V7);
 }
 
-static void do_prints(void)
+static void do_prints(unsigned int ct)
 {
-	pr_debug("do_prints:\n");
-	do_cats();
-	do_levels();
+	/* maybe clamp this */
+	pr_debug("do-prints %d times:\n", ct);
+	for (; ct; ct--) {
+		do_cats();
+		do_levels();
+	}
 }
 
 static int __init test_dynamic_debug_init(void)
 {
 	pr_debug("init start\n");
-	do_prints();
+	do_prints(1);
 	pr_debug("init done\n");
 	return 0;
 }
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:42 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:42 +1300
Subject: [PATCH v7 25/31] dyndbg-API: promote DYNAMIC_DEBUG_CLASSMAP_PARAM to API
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-26-jim.cromie@gmail.com>

move the DYNAMIC_DEBUG_CLASSMAP_PARAM macro from test-dynamic-debug.c into
the header, and refine it, by distinguishing the 2 use cases:

1.DYNAMIC_DEBUG_CLASSMAP_PARAM_REF
    for DRM, to pass in extern __drm_debug by name.
    dyndbg keeps bits in it, so drm can still use it as before

2.DYNAMIC_DEBUG_CLASSMAP_PARAM
    new user (test_dynamic_debug) doesn't need to share state,
    decls a static long unsigned int to store the bitvec.

__DYNAMIC_DEBUG_CLASSMAP_PARAM
   bottom layer - allocate,init a ddebug-class-param, module-param-cb.

Modify ddebug_sync_classbits() argtype deref inside the fn, to give
access to all kp members.

Also add stub macros, clean up and improve comments in test-code, and
add MODULE_DESCRIPTIONs.

cc: linux-doc at vger.kernel.org
Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 include/linux/dynamic_debug.h   | 40 ++++++++++++++++++++++
 lib/dynamic_debug.c             | 60 ++++++++++++++++++++++-----------
 lib/test_dynamic_debug.c        | 47 ++++++++++----------------
 lib/test_dynamic_debug_submod.c |  9 ++++-
 4 files changed, 106 insertions(+), 50 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index b19c9b1d53b6..b1d11d946780 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -251,6 +251,44 @@ struct _ddebug_class_param {
 		.base = _base						\
 	}
 
+/**
+ * DYNAMIC_DEBUG_CLASSMAP_PARAM - control a ddebug-classmap from a sys-param
+ * @_name:  sysfs node name
+ * @_var:   name of the classmap var defining the controlled classes/bits
+ * @_flags: flags to be toggled, typically just 'p'
+ *
+ * Creates a sysfs-param to control the classes defined by the
+ * exported classmap, with bits 0..N-1 mapped to the classes named.
+ * This version keeps class-state in a private long int.
+ */
+#define DYNAMIC_DEBUG_CLASSMAP_PARAM(_name, _var, _flags)		\
+	static unsigned long _name##_bvec;				\
+	__DYNAMIC_DEBUG_CLASSMAP_PARAM(_name, _name##_bvec, _var, _flags)
+
+/**
+ * DYNAMIC_DEBUG_CLASSMAP_PARAM_REF - wrap a classmap with a controlling sys-param
+ * @_name:  sysfs node name
+ * @_bits:  name of the module's unsigned long bit-vector, ex: __drm_debug
+ * @_var:   name of the (exported) classmap var defining the classes/bits
+ * @_flags: flags to be toggled, typically just 'p'
+ *
+ * Creates a sysfs-param to control the classes defined by the
+ * exported clasmap, with bits 0..N-1 mapped to the classes named.
+ * This version keeps class-state in user @_bits.  This lets drm check
+ * __drm_debug elsewhere too.
+ */
+#define DYNAMIC_DEBUG_CLASSMAP_PARAM_REF(_name, _bits, _var, _flags)	\
+	__DYNAMIC_DEBUG_CLASSMAP_PARAM(_name, _bits, _var, _flags)
+
+#define __DYNAMIC_DEBUG_CLASSMAP_PARAM(_name, _bits, _var, _flags)	\
+	static struct _ddebug_class_param _name##_##_flags = {		\
+		.bits = &(_bits),					\
+		.flags = #_flags,					\
+		.map = &(_var),						\
+	};								\
+	module_param_cb(_name, &param_ops_dyndbg_classes,		\
+			&_name##_##_flags, 0600)
+
 extern __printf(2, 3)
 void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...);
 
@@ -423,6 +461,8 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
 
 #define DYNAMIC_DEBUG_CLASSMAP_DEFINE(_var, _mapty, _base, ...)
 #define DYNAMIC_DEBUG_CLASSMAP_USE(_var)
+#define DYNAMIC_DEBUG_CLASSMAP_PARAM(_name, _var, _flags)
+#define DYNAMIC_DEBUG_CLASSMAP_PARAM_REF(_name, _var, _flags)
 #define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt)
 #define DYNAMIC_DEBUG_BRANCH(descriptor) false
 #define DECLARE_DYNDBG_CLASSMAP(...)
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index e5a18a7d3780..1da2de7b1769 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -687,6 +687,30 @@ static int ddebug_apply_class_bitmap(const struct _ddebug_class_param *dcp,
 
 #define CLASSMAP_BITMASK(width) ((1UL << (width)) - 1)
 
+static void ddebug_class_param_clamp_input(unsigned long *inrep, const struct kernel_param *kp)
+{
+	const struct _ddebug_class_param *dcp = kp->arg;
+	const struct _ddebug_class_map *map = dcp->map;
+
+	switch (map->map_type) {
+	case DD_CLASS_TYPE_DISJOINT_BITS:
+		/* expect bits. mask and warn if too many */
+		if (*inrep & ~CLASSMAP_BITMASK(map->length)) {
+			pr_warn("%s: input: 0x%lx exceeds mask: 0x%lx, masking\n",
+				KP_NAME(kp), *inrep, CLASSMAP_BITMASK(map->length));
+			*inrep &= CLASSMAP_BITMASK(map->length);
+		}
+		break;
+	case DD_CLASS_TYPE_LEVEL_NUM:
+		/* input is bitpos, of highest verbosity to be enabled */
+		if (*inrep > map->length) {
+			pr_warn("%s: level:%ld exceeds max:%d, clamping\n",
+				KP_NAME(kp), *inrep, map->length);
+			*inrep = map->length;
+		}
+		break;
+	}
+}
 static int param_set_dyndbg_module_classes(const char *instr,
 					   const struct kernel_param *kp,
 					   const char *mod_name)
@@ -705,26 +729,15 @@ static int param_set_dyndbg_module_classes(const char *instr,
 		pr_err("expecting numeric input, not: %s > %s\n", instr, KP_NAME(kp));
 		return -EINVAL;
 	}
+	ddebug_class_param_clamp_input(&inrep, kp);
 
 	switch (map->map_type) {
 	case DD_CLASS_TYPE_DISJOINT_BITS:
-		/* expect bits. mask and warn if too many */
-		if (inrep & ~CLASSMAP_BITMASK(map->length)) {
-			pr_warn("%s: input: 0x%lx exceeds mask: 0x%lx, masking\n",
-				KP_NAME(kp), inrep, CLASSMAP_BITMASK(map->length));
-			inrep &= CLASSMAP_BITMASK(map->length);
-		}
 		v2pr_info("bits:0x%lx > %s.%s\n", inrep, mod_name ?: "*", KP_NAME(kp));
 		totct += ddebug_apply_class_bitmap(dcp, &inrep, *dcp->bits, mod_name);
 		*dcp->bits = inrep;
 		break;
 	case DD_CLASS_TYPE_LEVEL_NUM:
-		/* input is bitpos, of highest verbosity to be enabled */
-		if (inrep > map->length) {
-			pr_warn("%s: level:%ld exceeds max:%d, clamping\n",
-				KP_NAME(kp), inrep, map->length);
-			inrep = map->length;
-		}
 		old_bits = CLASSMAP_BITMASK(*dcp->lvl);
 		new_bits = CLASSMAP_BITMASK(inrep);
 		v2pr_info("lvl:%ld bits:0x%lx > %s\n", inrep, new_bits, KP_NAME(kp));
@@ -1195,15 +1208,24 @@ static const struct proc_ops proc_fops = {
 static void ddebug_sync_classbits(const struct kernel_param *kp, const char *modname)
 {
 	const struct _ddebug_class_param *dcp = kp->arg;
+	unsigned long new_bits;
 
-	/* clamp initial bitvec, mask off hi-bits */
-	if (*dcp->bits & ~CLASSMAP_BITMASK(dcp->map->length)) {
-		*dcp->bits &= CLASSMAP_BITMASK(dcp->map->length);
-		v2pr_info("preset classbits: %lx\n", *dcp->bits);
+	ddebug_class_param_clamp_input(dcp->bits, kp);
+
+	switch (dcp->map->map_type) {
+	case DD_CLASS_TYPE_DISJOINT_BITS:
+		v2pr_info("  %s: classbits: 0x%lx\n", KP_NAME(kp), *dcp->bits);
+		ddebug_apply_class_bitmap(dcp, dcp->bits, 0UL, modname);
+		break;
+	case DD_CLASS_TYPE_LEVEL_NUM:
+		new_bits = CLASSMAP_BITMASK(*dcp->lvl);
+		v2pr_info("  %s: lvl:%ld bits:0x%lx\n", KP_NAME(kp), *dcp->lvl, new_bits);
+		ddebug_apply_class_bitmap(dcp, &new_bits, 0UL, modname);
+		break;
+	default:
+		pr_err("bad map type %d\n", dcp->map->map_type);
+		return;
 	}
-	/* force class'd prdbgs (in USEr module) to match (DEFINEr module) class-param */
-	ddebug_apply_class_bitmap(dcp, dcp->bits, ~0, modname);
-	ddebug_apply_class_bitmap(dcp, dcp->bits, 0, modname);
 }
 
 static void ddebug_match_apply_kparam(const struct kernel_param *kp,
diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
index fa81177e8089..83c4d571a8c9 100644
--- a/lib/test_dynamic_debug.c
+++ b/lib/test_dynamic_debug.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Kernel module for testing dynamic_debug
+ * Kernel module to test/demonstrate dynamic_debug features,
+ * particularly classmaps and their support for subsystems like DRM.
  *
  * Authors:
  *      Jim Cromie	<jim.cromie at gmail.com>
@@ -57,24 +58,6 @@ module_param_cb(do_prints, &param_ops_do_prints, NULL, 0600);
 
 #define CLASSMAP_BITMASK(width, base) (((1UL << (width)) - 1) << (base))
 
-/* sysfs param wrapper, proto-API */
-#define DYNAMIC_DEBUG_CLASSMAP_PARAM_(_model, _flags, _init)		\
-	static unsigned long bits_##_model = _init;			\
-	static struct _ddebug_class_param _flags##_##_model = {		\
-		.bits = &bits_##_model,					\
-		.flags = #_flags,					\
-		.map = &map_##_model,					\
-	};								\
-	module_param_cb(_flags##_##_model, &param_ops_dyndbg_classes,	\
-			&_flags##_##_model, 0600)
-#ifdef DEBUG
-#define DYNAMIC_DEBUG_CLASSMAP_PARAM(_model, _flags)		\
-	DYNAMIC_DEBUG_CLASSMAP_PARAM_(_model, _flags, ~0)
-#else
-#define DYNAMIC_DEBUG_CLASSMAP_PARAM(_model, _flags)		\
-	DYNAMIC_DEBUG_CLASSMAP_PARAM_(_model, _flags, 0)
-#endif
-
 /*
  * Demonstrate/test DISJOINT & LEVEL typed classmaps with a sys-param.
  *
@@ -105,12 +88,15 @@ enum cat_disjoint_bits {
 /* numeric verbosity, V2 > V1 related.  V0 is > D2_DRMRES */
 enum cat_level_num { V0 = 16, V1, V2, V3, V4, V5, V6, V7 };
 
-/* recapitulate DRM's multi-classmap setup */
+/*
+ * use/demonstrate multi-module-group classmaps, as for DRM
+ */
 #if !defined(TEST_DYNAMIC_DEBUG_SUBMOD)
 /*
- * In single user, or parent / coordinator (drm.ko) modules, define
- * classmaps on the client enums above, and then declares the PARAMS
- * ref'g the classmaps.  Each is exported.
+ * For module-groups of 1+, define classmaps with names (stringified
+ * enum-symbols) copied from above. 1-to-1 mapping is recommended.
+ * The classmap is exported, so that other modules in the group can
+ * link to it and control their prdbgs.
  */
 DYNAMIC_DEBUG_CLASSMAP_DEFINE(map_disjoint_bits, DD_CLASS_TYPE_DISJOINT_BITS,
 			      D2_CORE,
@@ -129,11 +115,13 @@ DYNAMIC_DEBUG_CLASSMAP_DEFINE(map_level_num, DD_CLASS_TYPE_LEVEL_NUM,
 			      V0, "V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7");
 
 /*
- * now add the sysfs-params
+ * for use-cases that want it, provide a sysfs-param to set the
+ * classes in the classmap.  It is at this interface where the
+ * "v3>v2" property is applied to DD_CLASS_TYPE_LEVEL_NUM inputs.
  */
 
-DYNAMIC_DEBUG_CLASSMAP_PARAM(disjoint_bits, p);
-DYNAMIC_DEBUG_CLASSMAP_PARAM(level_num, p);
+DYNAMIC_DEBUG_CLASSMAP_PARAM(p_disjoint_bits,	map_disjoint_bits, p);
+DYNAMIC_DEBUG_CLASSMAP_PARAM(p_level_num,	map_level_num, p);
 
 #ifdef FORCE_CLASSID_CONFLICT
 /*
@@ -144,12 +132,10 @@ DYNAMIC_DEBUG_CLASSMAP_DEFINE(classid_range_conflict, 0, D2_CORE + 1, "D3_CORE")
 #endif
 
 #else /* TEST_DYNAMIC_DEBUG_SUBMOD */
-
 /*
- * in submod/drm-drivers, use the classmaps defined in top/parent
- * module above.
+ * the +1 members of a multi-module group refer to the classmap
+ * DEFINEd (and exported) above.
  */
-
 DYNAMIC_DEBUG_CLASSMAP_USE(map_disjoint_bits);
 DYNAMIC_DEBUG_CLASSMAP_USE(map_level_num);
 
@@ -224,6 +210,7 @@ static void __exit test_dynamic_debug_exit(void)
 module_init(test_dynamic_debug_init);
 module_exit(test_dynamic_debug_exit);
 
+MODULE_DESCRIPTION("test/demonstrate dynamic-debug features");
 MODULE_AUTHOR("Jim Cromie <jim.cromie at gmail.com>");
 MODULE_DESCRIPTION("Kernel module for testing dynamic_debug");
 MODULE_LICENSE("GPL");
diff --git a/lib/test_dynamic_debug_submod.c b/lib/test_dynamic_debug_submod.c
index 672aabf40160..3adf3925fb86 100644
--- a/lib/test_dynamic_debug_submod.c
+++ b/lib/test_dynamic_debug_submod.c
@@ -1,6 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Kernel module for testing dynamic_debug
+ * Kernel module to test/demonstrate dynamic_debug features,
+ * particularly classmaps and their support for subsystems, like DRM,
+ * which defines its drm_debug classmap in drm module, and uses it in
+ * helpers & drivers.
  *
  * Authors:
  *      Jim Cromie	<jim.cromie at gmail.com>
@@ -12,3 +15,7 @@
  */
 #define TEST_DYNAMIC_DEBUG_SUBMOD
 #include "test_dynamic_debug.c"
+
+MODULE_DESCRIPTION("test/demonstrate dynamic-debug subsystem support");
+MODULE_AUTHOR("Jim Cromie <jim.cromie at gmail.com>");
+MODULE_LICENSE("GPL");
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:43 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:43 +1300
Subject: [PATCH v7 26/31] dyndbg: treat comma as a token separator
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-27-jim.cromie@gmail.com>

Treat comma as a token terminator, just like a space.  This allows a
user to avoid quoting hassles when spaces are otherwise needed:

 :#> modprobe drm dyndbg=class,DRM_UT_CORE,+p\;class,DRM_UT_KMS,+p

or as a boot arg:

 drm.dyndbg=class,DRM_UT_CORE,+p  # todo: support multi-query here

Given the many ways a boot-line +args can be assembled and then passed
in/down/around shell based tools, this may allow side-stepping all
sorts of quoting hassles thru those layers.

existing query format:

 modprobe test_dynamic_debug dyndbg="class D2_CORE +p"

new format:

 modprobe test_dynamic_debug dyndbg=class,D2_CORE,+p

ALSO

selftests-dyndbg: add comma_terminator_tests

New fn validates parsing and effect of queries using combinations of
commas and spaces to delimit the tokens.

It manipulates pr-debugs in builtin module/params, so might have deps
I havent foreseen on odd configurations.

Co-developed-by: ?ukasz Bartosik <ukaszb at chromium.org>
Signed-off-by: ?ukasz Bartosik <ukaszb at chromium.org>
Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 .../admin-guide/dynamic-debug-howto.rst       |  9 +++++---
 lib/dynamic_debug.c                           | 17 +++++++++++----
 .../dynamic_debug/dyndbg_selftest.sh          | 21 ++++++++++++++++++-
 3 files changed, 39 insertions(+), 8 deletions(-)

diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst
index e76ccd987704..350d93834e19 100644
--- a/Documentation/admin-guide/dynamic-debug-howto.rst
+++ b/Documentation/admin-guide/dynamic-debug-howto.rst
@@ -78,11 +78,12 @@ Command Language Reference
 ==========================
 
 At the basic lexical level, a command is a sequence of words separated
-by spaces or tabs.  So these are all equivalent::
+by spaces, tabs, or commas.  So these are all equivalent::
 
   :#> ddcmd file svcsock.c line 1603 +p
   :#> ddcmd "file svcsock.c line 1603 +p"
   :#> ddcmd '  file   svcsock.c     line  1603 +p  '
+  :#> ddcmd file,svcsock.c,line,1603,+p
 
 Command submissions are bounded by a write() system call.
 Multiple commands can be written together, separated by ``;`` or ``\n``::
@@ -167,9 +168,11 @@ module
     The given string is compared against the module name
     of each callsite.  The module name is the string as
     seen in ``lsmod``, i.e. without the directory or the ``.ko``
-    suffix and with ``-`` changed to ``_``.  Examples::
+    suffix and with ``-`` changed to ``_``.
 
-	module sunrpc
+    Examples::
+
+	module,sunrpc	# with ',' as token separator
 	module nfsd
 	module drm*	# both drm, drm_kms_helper
 
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 1da2de7b1769..5ac7248d51bb 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -320,6 +320,14 @@ static int ddebug_change(const struct ddebug_query *query, struct flag_settings
 	return nfound;
 }
 
+static char *skip_spaces_and_commas(const char *str)
+{
+	str = skip_spaces(str);
+	while (*str == ',')
+		str = skip_spaces(++str);
+	return (char *)str;
+}
+
 /*
  * Split the buffer `buf' into space-separated words.
  * Handles simple " and ' quoting, i.e. without nested,
@@ -333,8 +341,8 @@ static int ddebug_tokenize(char *buf, char *words[], int maxwords)
 	while (*buf) {
 		char *end;
 
-		/* Skip leading whitespace */
-		buf = skip_spaces(buf);
+		/* Skip leading whitespace and comma */
+		buf = skip_spaces_and_commas(buf);
 		if (!*buf)
 			break;	/* oh, it was trailing whitespace */
 		if (*buf == '#')
@@ -350,7 +358,7 @@ static int ddebug_tokenize(char *buf, char *words[], int maxwords)
 				return -EINVAL;	/* unclosed quote */
 			}
 		} else {
-			for (end = buf; *end && !isspace(*end); end++)
+			for (end = buf; *end && !isspace(*end) && *end != ','; end++)
 				;
 			if (end == buf) {
 				pr_err("parse err after word:%d=%s\n", nwords,
@@ -622,7 +630,8 @@ static int ddebug_exec_queries(char *query, const char *modname)
 		if (split)
 			*split++ = '\0';
 
-		query = skip_spaces(query);
+		query = skip_spaces_and_commas(query);
+
 		if (!query || !*query || *query == '#')
 			continue;
 
diff --git a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh
index 465fad3f392c..c7bf521f36ee 100755
--- a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh
+++ b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh
@@ -216,7 +216,7 @@ function check_err_msg() {
 function basic_tests {
     echo -e "${GREEN}# BASIC_TESTS ${NC}"
     if [ $LACK_DD_BUILTIN -eq 1 ]; then
-	echo "SKIP"
+	echo "SKIP - test requires params, which is a builtin module"
 	return
     fi
     ddcmd =_ # zero everything
@@ -238,8 +238,27 @@ EOF
     ddcmd =_
 }
 
+function comma_terminator_tests {
+    echo -e "${GREEN}# COMMA_TERMINATOR_TESTS ${NC}"
+    if [ $LACK_DD_BUILTIN -eq 1 ]; then
+	echo "SKIP - test requires params, which is a builtin module"
+	return
+    fi
+    # try combos of spaces & commas
+    check_match_ct '\[params\]' 4 -r
+    ddcmd module,params,=_		# commas as spaces
+    ddcmd module,params,+mpf		# turn on module's pr-debugs
+    check_match_ct =pmf 4
+    ddcmd ,module ,, ,  params, -p
+    check_match_ct =mf 4
+    ddcmd " , module ,,, ,  params, -m"	#
+    check_match_ct =f 4
+    ddcmd =_
+}
+
 tests_list=(
     basic_tests
+    comma_terminator_tests
 )
 
 # Run tests
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:44 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:44 +1300
Subject: [PATCH v7 27/31] dyndbg: split multi-query strings with %
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-28-jim.cromie@gmail.com>

Since commit
85f7f6c0edb8 ("dynamic_debug: process multiple debug-queries on a line")

Multi-query commands have been allowed:

  modprobe drm dyndbg="class DRM_UT_CORE +p; class DRM_UT_KMS +p"
  modprobe drm dyndbg=<<EOX
     class DRM_UT_CORE +p
     class DRM_UT_KMS +p
  EOX

More recently, the need for quoting was avoided by treating a comma
like a space/token-terminator:

  modprobe drm dyndbg=class,DRM_UT_CORE,+p\;class,DRM_UT_KMS,+p

That works, but it needs the escaped semicolon, which is a shell
special-char (one of the bash control operators), so it is brittle
when passed in/down/around scripts.  In particular, it fails when
passed to vng (virtme-ng).

So this patch adds '%' to the existing ';' and '\n' multi-command
separators, which is more shell-friendly, so you can more fully avoid
quoting and escaping hassles.

NOTE: it does break format matching on '%' patterns:

bash-5.2# ddcmd 'format "find-me: %foo" +p'
[  203.900581] dyndbg: read 26 bytes from userspace
[  203.900883] dyndbg: query 0: "format "find-me: " mod:*
[  203.901118] dyndbg: unclosed quote: find-me:
[  203.901355] dyndbg: tokenize failed
[  203.901529] dyndbg: query 1: "foo" +p" mod:*
[  203.901957] dyndbg: split into words: "foo"" "+p"
[  203.902243] dyndbg: op='+' flags=0x1 maskp=0xffffffff
[  203.902458] dyndbg: expecting pairs of match-spec <value>
[  203.902703] dyndbg: query parse failed
[  203.902871] dyndbg: processed 2 queries, with 0 matches, 2 errs
bash: echo: write error: Invalid argument

The '%' splits the input into 2 queries, and both fail.  Given the
limited utility of matching against the working parts of a format
string "foo: %d bar %s", nothing is actually lost here.

selftests-dyndbg: test_percent_splitting

This does basic testing of classmaps using '%' separated
multi-queries.  It modprobes test_dynamic_debug with several classes
enabled, and counts to verify that the expected sites show the
enablement in the control file.

Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 .../admin-guide/dynamic-debug-howto.rst       |  8 ++++---
 lib/dynamic_debug.c                           |  2 +-
 .../dynamic_debug/dyndbg_selftest.sh          | 24 +++++++++++++++++++
 3 files changed, 30 insertions(+), 4 deletions(-)

diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst
index 350d93834e19..89ee15d7ae58 100644
--- a/Documentation/admin-guide/dynamic-debug-howto.rst
+++ b/Documentation/admin-guide/dynamic-debug-howto.rst
@@ -85,10 +85,12 @@ by spaces, tabs, or commas.  So these are all equivalent::
   :#> ddcmd '  file   svcsock.c     line  1603 +p  '
   :#> ddcmd file,svcsock.c,line,1603,+p
 
-Command submissions are bounded by a write() system call.
-Multiple commands can be written together, separated by ``;`` or ``\n``::
+Command submissions are bounded by a write() system call.  Multiple
+commands can be written together, separated by ``%``, ``;`` or ``\n``::
 
-  :#> ddcmd "func pnpacpi_get_resources +p; func pnp_assign_mem +p"
+  :#> ddcmd func foo +p % func bar +p
+  :#> ddcmd func foo +p \; func bar +p
+  :#> ddcmd "func foo +p ; func bar +p"
   :#> ddcmd <<"EOC"
   func pnpacpi_get_resources +p
   func pnp_assign_mem +p
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 5ac7248d51bb..c50836c262b4 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -626,7 +626,7 @@ static int ddebug_exec_queries(char *query, const char *modname)
 	int i, errs = 0, exitcode = 0, rc, nfound = 0;
 
 	for (i = 0; query; query = split) {
-		split = strpbrk(query, ";\n");
+		split = strpbrk(query, "%;\n");
 		if (split)
 			*split++ = '\0';
 
diff --git a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh
index c7bf521f36ee..513f6cb1db1d 100755
--- a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh
+++ b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh
@@ -256,9 +256,33 @@ function comma_terminator_tests {
     ddcmd =_
 }
 
+function test_percent_splitting {
+    echo -e "${GREEN}# TEST_PERCENT_SPLITTING - multi-command splitting on % ${NC}"
+    if [ $LACK_TMOD -eq 1 ]; then
+	echo "SKIP - test requires test-dynamic-debug.ko"
+	return
+    fi
+    ifrmmod test_dynamic_debug_submod
+    ifrmmod test_dynamic_debug
+    ddcmd =_
+    modprobe test_dynamic_debug dyndbg=class,D2_CORE,+pf%class,D2_KMS,+pt%class,D2_ATOMIC,+pm
+    check_match_ct =pf 1
+    check_match_ct =pt 1
+    check_match_ct =pm 1
+    check_match_ct test_dynamic_debug 23 -r
+    # add flags to those callsites
+    ddcmd class,D2_CORE,+mf%class,D2_KMS,+lt%class,D2_ATOMIC,+ml
+    check_match_ct =pmf 1
+    check_match_ct =plt 1
+    check_match_ct =pml 1
+    check_match_ct test_dynamic_debug 23 -r
+    ifrmmod test_dynamic_debug
+}
+
 tests_list=(
     basic_tests
     comma_terminator_tests
+    test_percent_splitting
 )
 
 # Run tests
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:45 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:45 +1300
Subject: [PATCH v7 28/31] selftests-dyndbg: add test_mod_submod
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-29-jim.cromie@gmail.com>

This new test-fn runs 3 module/submodule modprobe scenarios, variously
using both the generic dyndbg=<queries> modprobe arg, and the
test-module's classmap-params to manipulate the test-mod*'s pr_debugs.
In all cases, the current flag-settings are counted and tested vs
expectations.

The 3rd scenario recapitulates the DRM_USE_DYNAMIC_DEBUG=y failure.

1. 2 modprobes (super then sub), with separate dyndbg=class-settings
   check module specific flag settings

2. modprobe submod, supermod is auto-loaded
   set supermod class-params
   check expected enablements in super & submod

3. modprobe super, with param=setting (like drm.debug=0x1ef)
   modprobe submod
   validate submod's class'd pr_debugs get properly enabled

The test uses multi-queries, with both commas and percents (to avoid
spaces and quoting).  This is the main reason the test wasn't earlier
in the patchset, closer to the classmap patches its validating.

With some tedium, the tests could be refactored to split out early
tests which avoid multi-cmds, and test only the class-params.

Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 .../dynamic_debug/dyndbg_selftest.sh          | 73 +++++++++++++++++++
 1 file changed, 73 insertions(+)

diff --git a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh
index 513f6cb1db1d..09937dca3056 100755
--- a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh
+++ b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh
@@ -279,10 +279,83 @@ function test_percent_splitting {
     ifrmmod test_dynamic_debug
 }
 
+function test_mod_submod {
+    echo -e "${GREEN}# TEST_MOD_SUBMOD ${NC}"
+    if [ $LACK_TMOD -eq 1 ]; then
+	echo "SKIP - test requires test-dynamic-debug.ko"
+	return
+    fi
+    ifrmmod test_dynamic_debug_submod
+    ifrmmod test_dynamic_debug
+    ddcmd =_
+
+    # modprobe with class enablements
+    modprobe test_dynamic_debug \
+	dyndbg=class,D2_CORE,+pf%class,D2_KMS,+pt%class,D2_ATOMIC,+pm
+
+    check_match_ct '\[test_dynamic_debug\]' 23 -r
+    check_match_ct =pf 1
+    check_match_ct =pt 1
+    check_match_ct =pm 1
+
+    modprobe test_dynamic_debug_submod
+    check_match_ct test_dynamic_debug_submod 23 -r
+    check_match_ct '\[test_dynamic_debug\]' 23 -r
+    check_match_ct test_dynamic_debug 46 -r
+
+    # no enablements propagate here
+    check_match_ct =pf 1
+    check_match_ct =pt 1
+    check_match_ct =pm 1
+
+    # change classes again, this time submod too
+    ddcmd class,D2_CORE,+mf%class,D2_KMS,+lt%class,D2_ATOMIC,+ml "# add some prefixes"
+    check_match_ct =pmf 1
+    check_match_ct =plt 1
+    check_match_ct =pml 1
+    #  submod changed too
+    check_match_ct =mf 1
+    check_match_ct =lt 1
+    check_match_ct =ml 1
+
+    # now work the classmap-params
+    # fresh start, to clear all above flags (test-fn limits)
+    ifrmmod test_dynamic_debug_submod
+    ifrmmod test_dynamic_debug
+    modprobe test_dynamic_debug_submod # get supermod too
+
+    echo 1 > /sys/module/test_dynamic_debug/parameters/p_disjoint_bits
+    echo 4 > /sys/module/test_dynamic_debug/parameters/p_level_num
+    # 2 mods * ( V1-3 + D2_CORE )
+    check_match_ct =p 8
+    echo 3 > /sys/module/test_dynamic_debug/parameters/p_disjoint_bits
+    echo 0 > /sys/module/test_dynamic_debug/parameters/p_level_num
+    # 2 mods * ( D2_CORE, D2_DRIVER )
+    check_match_ct =p 4
+    echo 0x16 > /sys/module/test_dynamic_debug/parameters/p_disjoint_bits
+    echo 0 > /sys/module/test_dynamic_debug/parameters/p_level_num
+    # 2 mods * ( D2_DRIVER, D2_KMS, D2_ATOMIC )
+    check_match_ct =p 6
+
+    # recap DRM_USE_DYNAMIC_DEBUG regression
+    ifrmmod test_dynamic_debug_submod
+    ifrmmod test_dynamic_debug
+    # set super-mod params
+    modprobe test_dynamic_debug p_disjoint_bits=0x16 p_level_num=5
+    check_match_ct =p 7
+    modprobe test_dynamic_debug_submod
+    # see them picked up by submod
+    check_match_ct =p 14
+    ifrmmod test_dynamic_debug_submod
+    ifrmmod test_dynamic_debug
+}
+
 tests_list=(
     basic_tests
+    # these require test_dynamic_debug*.ko
     comma_terminator_tests
     test_percent_splitting
+    test_mod_submod
 )
 
 # Run tests
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:47 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:47 +1300
Subject: [PATCH v7 30/31] dyndbg: add DYNAMIC_DEBUG_CLASSMAP_USE_(dd_class_name, offset)
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-31-jim.cromie@gmail.com>

Allow a module to use 2 classmaps together that would otherwise have a
class_id range conflict.

Suppose drm-driver does:

  DYNAMIC_DEBUG_CLASSMAP_USE(drm_debug_classes);
  DYNAMIC_DEBUG_CLASSMAP_USE(drm_accel_xfer_debug);

And (for some reason) drm-accel will not define their constants to
avoid DRM's 0..10 reservations (seems a long stretch).

So I dont think this potential conflict would become an issue until we
have at least a 3-X-3 of classmap-defns X classmap-users

So drop this if its too speculative, knowing theres at least a
notional solution should the situation arise.

Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 include/linux/dynamic_debug.h | 30 +++++++++++++++++++++++-------
 lib/dynamic_debug.c           | 19 ++++++++++++-------
 2 files changed, 35 insertions(+), 14 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index b22da40e2583..5307be8da5c1 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -87,7 +87,7 @@ struct _ddebug_class_map {
 struct _ddebug_class_user {
 	char *mod_name;
 	struct _ddebug_class_map *map;
-	const int base;		/* user offset to re-number the used map */
+	const int offset;	/* offset from map->base */
 };
 
 /*
@@ -235,21 +235,37 @@ struct _ddebug_class_param {
 /**
  * DYNAMIC_DEBUG_CLASSMAP_USE - refer to a classmap, DEFINEd elsewhere.
  * @_var: name of the exported classmap var
- * @_not_yet: _base-like, but applies only to this USEr. (if needed)
  *
  * This tells dyndbg that the module has prdbgs with classids defined
  * in the named classmap.  This qualifies "class NAME" >controls on
- * the user module, and ignores unknown names.
+ * the user module, and ignores unknown names. This is a wrapper for
+ * DYNAMIC_DEBUG_CLASSMAP_USE_() with a base offset of 0.
  */
-#define DYNAMIC_DEBUG_CLASSMAP_USE(_var)				\
-	DYNAMIC_DEBUG_CLASSMAP_USE_(_var, 0, __UNIQUE_ID(_ddebug_class_user))
-#define DYNAMIC_DEBUG_CLASSMAP_USE_(_var, _base, _uname)		\
+#define DYNAMIC_DEBUG_CLASSMAP_USE(_var) \
+	DYNAMIC_DEBUG_CLASSMAP_USE_(_var, 0)
+
+/**
+ * DYNAMIC_DEBUG_CLASSMAP_USE_ - refer to a classmap with a manual offset.
+ * @_var:   name of the exported classmap var to use.
+ * @_offset:  an integer offset to add to the class IDs of the used map.
+ *
+ * This is an extended version of DYNAMIC_DEBUG_CLASSMAP_USE(). It should
+ * only be used to resolve class ID conflicts when a module uses multiple
+ * classmaps that have overlapping ID ranges.
+ *
+ * The final class IDs for the used map will be calculated as:
+ * original_map_base + class_index + @_base.
+ */
+#define DYNAMIC_DEBUG_CLASSMAP_USE_(_var, _offset)			\
+	__DYNAMIC_DEBUG_CLASSMAP_USE(_var, _offset, __UNIQUE_ID(_ddebug_class_user))
+
+#define __DYNAMIC_DEBUG_CLASSMAP_USE(_var, _offset, _uname)		\
 	extern struct _ddebug_class_map _var;				\
 	static struct _ddebug_class_user __aligned(8) __used		\
 	__section("__dyndbg_class_users") _uname = {			\
 		.mod_name = KBUILD_MODNAME,				\
 		.map = &(_var),						\
-		.base = _base						\
+		.offset = _offset						\
 	}
 
 /**
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index f60a723a441b..b0da3dd4ac44 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -198,7 +198,7 @@ ddebug_find_valid_class(struct _ddebug_info const *di, const char *query_class,
 		if (idx >= 0) {
 			vpr_di_info(di, "class-ref: %s -> %s.%s ",
 				    cli->mod_name, cli->map->mod_name, query_class);
-			*class_id = idx + cli->map->base;
+			*class_id = idx + cli->map->base - cli->offset;
 			return cli->map;
 		}
 	}
@@ -206,12 +206,17 @@ ddebug_find_valid_class(struct _ddebug_info const *di, const char *query_class,
 	return NULL;
 }
 
-static bool ddebug_class_in_range(const int class_id, const struct _ddebug_class_map *map)
+static bool ddebug_class_map_in_range(const int class_id, const struct _ddebug_class_map *map)
 {
 	return (class_id >= map->base &&
 		class_id < map->base + map->length);
 }
 
+static bool ddebug_class_user_in_range(const int class_id, const struct _ddebug_class_user *user)
+{
+	return ddebug_class_map_in_range(class_id - user->offset, user->map);
+}
+
 static struct _ddebug_class_map *
 ddebug_find_map_by_class_id(struct _ddebug_info *di, int class_id)
 {
@@ -220,11 +225,11 @@ ddebug_find_map_by_class_id(struct _ddebug_info *di, int class_id)
 	int i;
 
 	for_subvec(i, map, di, maps)
-		if (ddebug_class_in_range(class_id, map))
+		if (ddebug_class_map_in_range(class_id, map))
 			return map;
 
 	for_subvec(i, cli, di, users)
-		if (ddebug_class_in_range(class_id, cli->map))
+		if (ddebug_class_user_in_range(class_id, cli))
 			return cli->map;
 
 	return NULL;
@@ -1177,12 +1182,12 @@ static const char *ddebug_class_name(struct _ddebug_info *di, struct _ddebug *dp
 	int i;
 
 	for_subvec(i, map, di, maps)
-		if (ddebug_class_in_range(dp->class_id, map))
+		if (ddebug_class_map_in_range(dp->class_id, map))
 			return map->class_names[dp->class_id - map->base];
 
 	for_subvec(i, cli, di, users)
-		if (ddebug_class_in_range(dp->class_id, cli->map))
-			return cli->map->class_names[dp->class_id - cli->map->base];
+		if (ddebug_class_user_in_range(dp->class_id, cli))
+			return cli->map->class_names[dp->class_id - cli->map->base - cli->offset];
 
 	return NULL;
 }
-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:20:48 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:48 +1300
Subject: [PATCH v7 31/31] docs/dyndbg: add classmap info to howto
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-32-jim.cromie@gmail.com>

Describe the 3 API macros providing dynamic_debug's classmaps

DYNAMIC_DEBUG_CLASSMAP_DEFINE - create & export a classmap
DYNAMIC_DEBUG_CLASSMAP_USE    - refer to exported map
DYNAMIC_DEBUG_CLASSMAP_PARAM  - bind control param to the classmap
DYNAMIC_DEBUG_CLASSMAP_PARAM_REF + use module's storage - __drm_debug

NB: The _DEFINE & _USE model makes the user dependent on the definer,
just like EXPORT_SYMBOL(__drm_debug) already does.

cc: linux-doc at vger.kernel.org
Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 .../admin-guide/dynamic-debug-howto.rst       | 135 ++++++++++++++++--
 1 file changed, 123 insertions(+), 12 deletions(-)

diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst
index 89ee15d7ae58..c85266ee8eed 100644
--- a/Documentation/admin-guide/dynamic-debug-howto.rst
+++ b/Documentation/admin-guide/dynamic-debug-howto.rst
@@ -146,6 +146,9 @@ keywords are::
   "1-30" is valid range but "1 - 30" is not.
 
 
+Keywords
+--------
+
 The meanings of each keyword are:
 
 func
@@ -194,16 +197,6 @@ format
 	format "nfsd: SETATTR"  // a neater way to match a format with whitespace
 	format 'nfsd: SETATTR'  // yet another way to match a format with whitespace
 
-class
-    The given class_name is validated against each module, which may
-    have declared a list of known class_names.  If the class_name is
-    found for a module, callsite & class matching and adjustment
-    proceeds.  Examples::
-
-	class DRM_UT_KMS	# a DRM.debug category
-	class JUNK		# silent non-match
-	// class TLD_*		# NOTICE: no wildcard in class names
-
 line
     The given line number or range of line numbers is compared
     against the line number of each ``pr_debug()`` callsite.  A single
@@ -218,6 +211,25 @@ line
 	line -1605          // the 1605 lines from line 1 to line 1605
 	line 1600-          // all lines from line 1600 to the end of the file
 
+class
+
+    The given class_name is validated against each module, which may
+    have declared a list of class_names it accepts.  If the class_name
+    accepted by a module, callsite & class matching and adjustment
+    proceeds.  Examples::
+
+	class DRM_UT_KMS	# a drm.debug category
+	class JUNK		# silent non-match
+	// class TLD_*		# NOTICE: no wildcard in class names
+
+.. note::
+
+    Unlike other keywords, classes are "name-to-change", not
+    "omitting-constraint-allows-change".  See Dynamic Debug Classmaps
+
+Flags
+-----
+
 The flags specification comprises a change operation followed
 by one or more flag characters.  The change operation is one
 of the characters::
@@ -238,11 +250,15 @@ The flags are::
   s    Include the source file name
   l    Include line number
 
+.. note::
+
+   * To query without changing	``+_`` or ``-_``.
+   * To clear all flags		``=_`` or ``-fslmpt``.
+
 For ``print_hex_dump_debug()`` and ``print_hex_dump_bytes()``, only
 the ``p`` flag has meaning, other flags are ignored.
 
-Note the regexp ``^[-+=][fslmpt_]+$`` matches a flags specification.
-To clear all flags at once, use ``=_`` or ``-fslmpt``.
+The regexp ``^[-+=][fslmpt_]+$`` matches a flags specification.
 
 
 Debug messages during Boot Process
@@ -394,3 +410,98 @@ just a shortcut for ``print_hex_dump(KERN_DEBUG)``.
 For ``print_hex_dump_debug()``/``print_hex_dump_bytes()``, format string is
 its ``prefix_str`` argument, if it is constant string; or ``hexdump``
 in case ``prefix_str`` is built dynamically.
+
+.. _dyndbg-classmaps:
+
+Dynamic Debug Classmaps
+=======================
+
+The "class" keyword selects prdbgs based on author supplied,
+domain-oriented names.  This complements the nested-scope keywords:
+module, file, function, line.
+
+The main difference from the others: classes must be named to be
+changed.  This protects them from unintended overwrite::
+
+  # IOW this cannot undo any drm.debug settings
+  :#> ddcmd -p
+
+This protection is needed; /sys/module/drm/parameters/debug is ABI.
+drm.debug is authoritative when dyndbg is not used, dyndbg-under-DRM
+is an implementation detail, and must not behave erratically, just
+because another admin fed >control something unrelated.
+
+So each class must be enabled individually (no wildcards)::
+
+  :#> ddcmd class DRM_UT_CORE +p
+  :#> ddcmd class DRM_UT_KMS +p
+  # or more selectively
+  :#> ddcmd class DRM_UT_CORE module drm +p
+
+That makes direct >control wordy and annoying, but it is a secondary
+interface; it is not intended to replace the ABI, just slide in
+underneath and reimplement the guaranteed behavior.  So DRM would keep
+using the convenient way, and be able to trust it::
+
+  :#> echo 0x1ff > /sys/module/drm/parameters/debug
+
+That said, since the sysfs/kparam is the ABI, if the author omits the
+CLASSMAP_PARAM, theres no ABI to guard, and he probably wants a less
+pedantic >control interface.  In this case, protection is dropped.
+
+Dynamic Debug Classmap API
+==========================
+
+DYNAMIC_DEBUG_CLASSMAP_DEFINE(clname,type,_base,classnames) - this maps
+classnames (a list of strings) onto class-ids consecutively, starting
+at _base.
+
+DYNAMIC_DEBUG_CLASSMAP_USE(clname) & _USE_(clname,_base) - modules
+call this to refer to the var _DEFINEd elsewhere (and exported).
+
+DYNAMIC_DEBUG_CLASSMAP_PARAM(clname) - creates the sysfs/kparam,
+maps/exposes bits 0..N as class-names.
+
+Classmaps are opt-in: modules invoke _DEFINE or _USE to authorize
+dyndbg to update those named classes.  "class FOO" queries are
+validated against the classes defined or used by the module, this
+finds the classid to alter; classes are not directly selectable by
+their classid.
+
+Classnames are global in scope, so subsystems (module-groups) should
+prepend a subsystem name; unqualified names like "CORE" are discouraged.
+
+NB: It is an inherent API limitation (due to class_id's int type) that
+the following are possible:
+
+  // these errors should be caught in review
+  __pr_debug_cls(0, "fake DRM_UT_CORE msg");  // this works
+  __pr_debug_cls(62, "un-known classid msg"); // this compiles, does nothing
+
+There are 2 types of classmaps:
+
+* DD_CLASS_TYPE_DISJOINT_BITS: classes are independent, like drm.debug
+* DD_CLASS_TYPE_LEVEL_NUM: classes are relative, ordered (V3 > V2)
+
+DYNAMIC_DEBUG_CLASSMAP_PARAM - modelled after module_param_cb, it
+refers to a DEFINEd classmap, and associates it to the param's
+data-store.  This state is then applied to DEFINEr and USEr modules
+when they're modprobed.
+
+The PARAM interface also enforces the DD_CLASS_TYPE_LEVEL_NUM relation
+amongst the contained classnames; all classes are independent in the
+control parser itself.  There is no implied meaning in names like "V4"
+or "PL_ERROR" vs "PL_WARNING".
+
+Modules or subsystems (drm & drivers) can define multiple classmaps,
+as long as they (all the classmaps) share the limited 0..62
+per-module-group _class_id range, without overlap.
+
+If a module encounters a conflict between 2 classmaps it is _USEing or
+_DEFINEing, it can invoke the extended _USE_(name,_base) macro to
+de-conflict the respective ranges.
+
+``#define DEBUG`` will enable all pr_debugs in scope, including any
+class'd ones.  This won't be reflected in the PARAM readback value,
+but the class'd pr_debug callsites can be forced off by toggling the
+classmap-kparam all-on then all-off.
-- 
2.52.0



From peter.wang at mediatek.com  Mon Dec 22 00:28:37 2025
From: peter.wang at mediatek.com (=?utf-8?B?UGV0ZXIgV2FuZyAo546L5L+h5Y+LKQ==?=)
Date: Mon, 22 Dec 2025 08:28:37 +0000
Subject: [PATCH v2 2/8] scsi: Make use of bus callbacks
In-Reply-To: <a54e363a3fd2054fb924afd7df44bca7f444b5f1.1766133330.git.u.kleine-koenig@baylibre.com>
References: <cover.1766133330.git.u.kleine-koenig@baylibre.com>
	 <a54e363a3fd2054fb924afd7df44bca7f444b5f1.1766133330.git.u.kleine-koenig@baylibre.com>
Message-ID: <ba48917452f4bb168a2b76deb64d2edeace2c836.camel@mediatek.com>

On Fri, 2025-12-19 at 10:25 +0100, Uwe Kleine-K?nig wrote:
> Introduce a bus specific probe, remove and shutdown function. For now
> this only allows to get rid of a cast of the generic device to an
> scsi
> device in the drivers and changes the remove prototype to return
> void---a non-zero return value is ignored anyhow.
> 
> The objective is to get rid of users of struct device_driver
> callbacks
> .probe(), .remove() and .shutdown() to eventually remove these. Until
> all scsi drivers are converted this results in a runtime warning
> about
> the drivers needing an update because there is a bus probe function
> and
> a driver probe function. The in-tree drivers are fixed by the
> following
> commits.
> 
> Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig at baylibre.com>

Reviewed-by: Peter Wang <peter.wang at mediatek.com>


From jim.cromie at gmail.com  Mon Dec 22 00:28:12 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:28:12 +1300
Subject: [PATCH v7 00/31] drm/dyndbg: Fix dynamic debug classmap regression
Message-ID: <20251222082843.1816701-1-jim.cromie@gmail.com>

hello all,

commit aad0214f3026 ("dyndbg: add DECLARE_DYNDBG_CLASSMAP macro")

added dyndbg's "classmaps" feature, which brought dyndbg's 0-off-cost
debug to DRM.  Dyndbg wired to /sys/module/drm/parameters/debug,
mapped its bits to classes named "DRM_UT_*", and effected the callsite
enablements only on updates to the sys-node (and underlying >control).

Sadly, it hit a CI failure, resulting in:
commit bb2ff6c27bc9 ("drm: Disable dynamic debug as broken")

The regression was that drivers, when modprobed, did not get the
drm.debug=0xff turn-on action, because that had already been done for
drm.ko itself.

The core design bug is in the DECLARE_DYNDBG_CLASSMAP macro.  Its use
in both drm.ko (ie core) and all drivers.ko meant that they couldn't
fundamentally distinguish their respective roles.  They each
"re-defined" the classmap separately, breaking K&R-101.

My ad-hoc test scripting helped to hide the error from me, by 1st
testing various combos of boot-time module.dyndbg=... and
drm.debug=... configurations, and then inadvertently relying upon
those initializations.

This series addresses both failings:

It replaces DECLARE_DYNDBG_CLASSMAP with

- `DYNAMIC_DEBUG_CLASSMAP_DEFINE`: Used by core modules (e.g.,
  `drm.ko`) to define their classmaps.  Based upon DECLARE, it exports
  the classmap so USE can use it.

- `DYNAMIC_DEBUG_CLASSMAP_USE`: this lets other "subsystem" users
  create a linkage to the classmap defined elsewhere (ie drm.ko).
  These users can then find their "parent" and apply its settings.

It adds a selftest script, and a 2nd "sub-module" to recapitulate
DRM's multi-module "subsystem" use-case, including the specific
failure scenario.

It also adds minor parsing enhancements, allowing easier construction
of multi-part debug configurations.  These enhancements are used to
test classmaps in particular, but are not otherwize required.

v7 adds:
. WARN_ONCE when classmap isnt found for a class'd callsite, JBaron
. reorder macro args to match kdoc, JBaron
. Doc formatting fixes, by Bagas

Thank you for your review.

P.S. Id also like to "tease" some other work:

1. patchset to send pr_debugs to tracefs on +T flag

   allows 63 "private" tracebufs, 1 "common" one (at 0)
   "drm.debug_2trace=0x1ff" is possible
   from Lukas Bartoski

2. patchset to save 40% of DATA_DATA footprint

   move (modname,filename,function) to struct _ddebug_site
   save their descriptor intervals to 3 maple-trees
   3 accessors fetch on descriptor, from trees
   move __dyndbg_sites __section to INIT_DATA

3. patchset to cache dynamic-prefixes
   should hide 2.s cost increase.


Jim Cromie (31):

fixes, cleanups, simple stuff::

Jim Cromie (31):
  dyndbg: factor ddebug_match_desc out from ddebug_change
  dyndbg: add stub macro for DECLARE_DYNDBG_CLASSMAP
  docs/dyndbg: update examples \012 to \n
  docs/dyndbg: explain flags parse 1st
  test-dyndbg: fixup CLASSMAP usage error
  dyndbg: reword "class unknown," to "class:_UNKNOWN_"
  dyndbg: make ddebug_class_param union members same size
  dyndbg: drop NUM_TYPE_ARRAY
  dyndbg: tweak pr_fmt to avoid expansion conflicts
  dyndbg: reduce verbose/debug clutter

callchain grooming, re-structs, code simplify/dedup by macros::

  dyndbg: refactor param_set_dyndbg_classes and below
  dyndbg: tighten fn-sig of ddebug_apply_class_bitmap
  dyndbg: replace classmap list with a vector
  dyndbg: macrofy a 2-index for-loop pattern
  dyndbg,module: make proper substructs in _ddebug_info
  dyndbg: hoist classmap-filter-by-modname up to ddebug_add_module
  dyndbg: move mod_name down from struct ddebug_table to _ddebug_info
  dyndbg-API: remove DD_CLASS_TYPE_(DISJOINT|LEVEL)_NAMES and code
  selftests-dyndbg: add a dynamic_debug run_tests target
  dyndbg: change __dynamic_func_call_cls* macros into expressions

core fix, detect api misuse errors, etc::

  dyndbg-API: replace DECLARE_DYNDBG_CLASSMAP
  dyndbg: detect class_id reservation conflicts
  dyndbg: check DYNAMIC_DEBUG_CLASSMAP_DEFINE args at compile-time
  dyndbg-test: change do_prints testpoint to accept a loopct
  dyndbg-API: promote DYNAMIC_DEBUG_CLASSMAP_PARAM to API
  dyndbg: treat comma as a token separator
  dyndbg: split multi-query strings with %
  selftests-dyndbg: add test_mod_submod
  dyndbg: resolve "protection" of class'd pr_debug
  dyndbg: add DYNAMIC_DEBUG_CLASSMAP_USE_(dd_class_name, offset)
  docs/dyndbg: add classmap info to howto

 .../admin-guide/dynamic-debug-howto.rst       | 187 ++++-
 MAINTAINERS                                   |   3 +-
 include/asm-generic/vmlinux.lds.h             |   5 +-
 include/linux/dynamic_debug.h                 | 302 +++++--
 kernel/module/main.c                          |  15 +-
 lib/Kconfig.debug                             |  24 +-
 lib/Makefile                                  |   5 +
 lib/dynamic_debug.c                           | 776 +++++++++++-------
 lib/test_dynamic_debug.c                      | 198 +++--
 lib/test_dynamic_debug_submod.c               |  21 +
 tools/testing/selftests/Makefile              |   1 +
 .../testing/selftests/dynamic_debug/Makefile  |   9 +
 tools/testing/selftests/dynamic_debug/config  |   7 +
 .../dynamic_debug/dyndbg_selftest.sh          | 373 +++++++++
 14 files changed, 1465 insertions(+), 461 deletions(-)
 create mode 100644 lib/test_dynamic_debug_submod.c
 create mode 100644 tools/testing/selftests/dynamic_debug/Makefile
 create mode 100644 tools/testing/selftests/dynamic_debug/config
 create mode 100755 tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh

-- 
2.52.0



From jim.cromie at gmail.com  Mon Dec 22 00:28:13 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:28:13 +1300
Subject: [PATCH v7 01/31] dyndbg: factor ddebug_match_desc out from ddebug_change
In-Reply-To: <20251222082843.1816701-1-jim.cromie@gmail.com>
References: <20251222082843.1816701-1-jim.cromie@gmail.com>
Message-ID: <20251222082843.1816701-2-jim.cromie@gmail.com>

ddebug_change() is a big (~100 lines) function with a nested for loop.

The outer loop walks the per-module ddebug_tables list, and does
module stuff: it filters on a query's "module FOO*" and "class BAR",
failures here skip the entire inner loop.

The inner loop (60 lines) scans a module's descriptors.  It starts
with a long block of filters on function, line, format, and the
validated "BAR" class (or the legacy/_DPRINTK_CLASS_DFLT).

These filters "continue" past pr_debugs that don't match the query
criteria, before it falls through the code below that counts matches,
then adjusts the flags and static-keys.  This is unnecessarily hard to
think about.

So move the per-descriptor filter-block into a boolean function:
ddebug_match_desc(desc), and change each "continue" to "return false".
This puts a clear interface in place, so any future changes are either
inside, outside, or across this interface.

also fix checkpatch complaints about spaces and braces.

Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 lib/dynamic_debug.c | 83 +++++++++++++++++++++++++--------------------
 1 file changed, 47 insertions(+), 36 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 5a007952f7f2..eb5146bcfaca 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -171,6 +171,52 @@ static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table cons
  * callsites, normally the same as number of changes.  If verbose,
  * logs the changes.  Takes ddebug_lock.
  */
+static bool ddebug_match_desc(const struct ddebug_query *query,
+			      struct _ddebug *dp,
+			      int valid_class)
+{
+	/* match site against query-class */
+	if (dp->class_id != valid_class)
+		return false;
+
+	/* match against the source filename */
+	if (query->filename &&
+	    !match_wildcard(query->filename, dp->filename) &&
+	    !match_wildcard(query->filename,
+			    kbasename(dp->filename)) &&
+	    !match_wildcard(query->filename,
+			    trim_prefix(dp->filename)))
+		return false;
+
+	/* match against the function */
+	if (query->function &&
+	    !match_wildcard(query->function, dp->function))
+		return false;
+
+	/* match against the format */
+	if (query->format) {
+		if (*query->format == '^') {
+			char *p;
+			/* anchored search. match must be at beginning */
+			p = strstr(dp->format, query->format + 1);
+			if (p != dp->format)
+				return false;
+		} else if (!strstr(dp->format, query->format)) {
+			return false;
+		}
+	}
+
+	/* match against the line number range */
+	if (query->first_lineno &&
+	    dp->lineno < query->first_lineno)
+		return false;
+	if (query->last_lineno &&
+	    dp->lineno > query->last_lineno)
+		return false;
+
+	return true;
+}
+
 static int ddebug_change(const struct ddebug_query *query,
 			 struct flag_settings *modifiers)
 {
@@ -203,42 +249,7 @@ static int ddebug_change(const struct ddebug_query *query,
 		for (i = 0; i < dt->num_ddebugs; i++) {
 			struct _ddebug *dp = &dt->ddebugs[i];
 
-			/* match site against query-class */
-			if (dp->class_id != valid_class)
-				continue;
-
-			/* match against the source filename */
-			if (query->filename &&
-			    !match_wildcard(query->filename, dp->filename) &&
-			    !match_wildcard(query->filename,
-					   kbasename(dp->filename)) &&
-			    !match_wildcard(query->filename,
-					   trim_prefix(dp->filename)))
-				continue;
-
-			/* match against the function */
-			if (query->function &&
-			    !match_wildcard(query->function, dp->function))
-				continue;
-
-			/* match against the format */
-			if (query->format) {
-				if (*query->format == '^') {
-					char *p;
-					/* anchored search. match must be at beginning */
-					p = strstr(dp->format, query->format+1);
-					if (p != dp->format)
-						continue;
-				} else if (!strstr(dp->format, query->format))
-					continue;
-			}
-
-			/* match against the line number range */
-			if (query->first_lineno &&
-			    dp->lineno < query->first_lineno)
-				continue;
-			if (query->last_lineno &&
-			    dp->lineno > query->last_lineno)
+			if (!ddebug_match_desc(query, dp, valid_class))
 				continue;
 
 			nfound++;
-- 
2.52.0



From wens at kernel.org  Mon Dec 22 00:33:08 2025
From: wens at kernel.org (Chen-Yu Tsai)
Date: Mon, 22 Dec 2025 16:33:08 +0800
Subject: [PATCH 0/4] arm64: allwinner: a523: Support SPI controllers
In-Reply-To: <20251221110513.1850535-1-wens@kernel.org>
References: <20251221110513.1850535-1-wens@kernel.org>
Message-ID: <CAGb2v67NbSA8Fq16EL-zY9WKVxnYUosk6z7NrGtAXt6UY8xdMw@mail.gmail.com>

On Sun, Dec 21, 2025 at 7:05?PM Chen-Yu Tsai <wens at kernel.org> wrote:
>
> Hi folks,
>
> This series adds support for the SPI controllers found in the Allwinner
> A523 SoC family. The SPI controller is almost the same as the ones in
> previous generations, except that it moved the "RX buffer count"
> register field to a separate register, and that register now reports
> the total count for RX buffer and FIFO.
>
> In practice the driver has never cared about the buffer count, but if
> any implementation were to use it, this counts as a non-backward
> compatible change.
>
> Also, one of the SPI controllers supports DBI mode, acting as a display
> interface. There is no infrastructure for DBI interface controllers in
> the kernel, so only a separate compatible is added for it.
>
> Patch 1 adds compatible strings for the new variants.
>
> Patch 2 adds driver support for the new SPI controller variant.
>
> Patch 3 adds device nodes for the SPI controllers to the dtsi file,
> along with pinmux settings for spi0 on the PC pins, a common usage for
> SPI-NOR flashes to boot from.
>
> Patch 4 enables the SPI-NOR flash found on the Radxa Cubie A5E.

As pointed out to me on IRC, this change targets the Orangepi 4A, not
the Radxa Cubie A5E. The latter has circuits for SPI-NOR, but the whole
block is left unpopulated.

ChenYu

>
> Please take a look and try it out.
>
>
> Thanks
> ChenYu
>
>
> Chen-Yu Tsai (4):
>   spi: dt-bindings: sun6i: Add compatibles for A523's SPI controllers
>   spi: sun6i: Support A523's SPI controllers
>   arm64: dts: allwinner: sun55i: Add SPI controllers
>   arm64: dts: allwinner: t527: orangepi-4a: Enable SPI-NOR flash
>
>  .../bindings/spi/allwinner,sun6i-a31-spi.yaml |  4 +
>  .../arm64/boot/dts/allwinner/sun55i-a523.dtsi | 94 +++++++++++++++++++
>  .../dts/allwinner/sun55i-t527-orangepi-4a.dts | 15 +++
>  drivers/spi/spi-sun6i.c                       | 11 ++-
>  4 files changed, 120 insertions(+), 4 deletions(-)
>
> --
> 2.47.3
>


From anshuld at ti.com  Mon Dec 22 00:43:14 2025
From: anshuld at ti.com (Anshul Dalal)
Date: Mon, 22 Dec 2025 14:13:14 +0530
Subject: [PATCH v6] dt-bindings: arm: keystone: add boot_* mboxes to ti,sci
Message-ID: <20251222-k3_syscon_add_boot_mailboxes-v6-1-b93ada9f1d47@ti.com>

The bootloader on K3 devices makes use of mailboxes as per the ROM spec
which might be different than one's available to the kernel (firmware
spec).

Therefore, this patch adds the missing mailbox entries to the DT binding
if the matching compatible is ti,am654-sci to represent the mailboxes
exposed by the hardware during boot for the purpose of loading the
firmware.

The new ti,am642-sci compatible is also added to represent SoCs which do
not expose a "notify" channel as part of their TI-SCI spec such as AM64x
or the AM62 family. The newly added mboxes are made optional by keeping
minItems as 2 to remain compliant with existing device-trees.

Signed-off-by: Anshul Dalal <anshuld at ti.com>
---
Changes in v6:
- Added ti,am642-sci compatible to represent SoCs without a "notify" channel
- Added new examples instead of editing existing ones
- Link to v5: https://lore.kernel.org/r/20251215-k3_syscon_add_boot_mailboxes-v5-1-5a8fe567fd31 at ti.com

Changes in v5:
- Added commit description for the optional mailboxes
- Link to v4: https://lore.kernel.org/r/20251205-k3_syscon_add_boot_mailboxes-v4-1-8e216fb88941 at ti.com

Changes in v4:
- Make new boot_* mboxes conditional on ti,am654-sci compatible
- Link to v3: https://lore.kernel.org/r/20251112-k3_syscon_add_boot_mailboxes-v3-1-66155a4236dc at ti.com

Changes in v3:
- Drop [1/2] of the last patch series
- Update existing example with boot_* mailboxes instead of adding a new one
- Link to v2: https://lore.kernel.org/r/20251112-k3_syscon_add_boot_mailboxes-v2-0-aebc1e47b391 at ti.com

Changes in v2:
- Remove maxItems entry
- Remove RFC tag from patch (added by mistake in v1)
- Document the new mailboxes in mboxes instead of mbox-names
- Provide example with all the mailboxes set
- Update commit title to have "ti,sci"
- Split into two patches
- Link to v1: https://lore.kernel.org/r/20251111-k3_syscon_add_boot_mailboxes-v1-1-529a27f21076 at ti.com
---
 .../devicetree/bindings/arm/keystone/ti,sci.yaml   | 94 +++++++++++++++++++++-
 1 file changed, 91 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
index 25a2b42105e5..0f2c764eae5a 100644
--- a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
+++ b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
@@ -40,6 +40,9 @@ properties:
       - description: System controller on TI AM654 SoC
         items:
           - const: ti,am654-sci
+      - description: System controller on TI AM642 SoC
+        items:
+          - const: ti,am642-sci
 
   reg-names:
     description: |
@@ -51,15 +54,15 @@ properties:
     minItems: 1
 
   mbox-names:
+    minItems: 2
+    maxItems: 6
     description: |
       Specifies the mailboxes used to communicate with TI-SCI Controller
       made available from TI-SCI controller.
-    items:
-      - const: rx
-      - const: tx
 
   mboxes:
     minItems: 2
+    maxItems: 6
 
   ti,host-id:
     $ref: /schemas/types.yaml#/definitions/uint32
@@ -79,6 +82,66 @@ properties:
     type: object
     $ref: /schemas/reset/ti,sci-reset.yaml#
 
+if:
+  properties:
+    compatible:
+      contains:
+        const: ti,am654-sci
+then:
+  properties:
+    mbox-names:
+      minItems: 2
+      items:
+        - const: rx
+        - const: tx
+        - const: notify
+        - const: boot_rx
+        - const: boot_tx
+        - const: boot_notify
+    mboxes:
+      minItems: 2
+      items:
+        - description: RX thread
+        - description: TX thread
+        - description: Notify thread
+        - description: boot stage RX thread
+        - description: boot stage TX thread
+        - description: boot stage Notify thread
+else:
+  if:
+    properties:
+      compatible:
+        contains:
+          const: ti,am642-sci
+  then:
+    properties:
+      mbox-names:
+        minItems: 2
+        items:
+          - const: rx
+          - const: tx
+          - const: boot_rx
+          - const: boot_tx
+          - const: boot_notify
+      mboxes:
+        minItems: 2
+        items:
+          - description: RX thread
+          - description: TX thread
+          - description: boot stage RX thread
+          - description: boot stage TX thread
+          - description: boot stage Notify thread
+  else:
+    properties:
+      mbox-names:
+        items:
+          - const: rx
+          - const: tx
+      mboxes:
+        items:
+          - description: RX thread
+          - description: TX thread
+
 required:
   - compatible
   - mbox-names
@@ -122,3 +185,28 @@ examples:
         #reset-cells = <2>;
       };
     };
+
+  - |
+    system-controller at 44083000 {
+      compatible = "ti,am654-sci";
+      ti,host-id = <4>;
+      mbox-names = "rx", "tx", "notify", "boot_rx", "boot_tx";
+      mboxes = <&secure_proxy_mcu 6>, <&secure_proxy_mcu 8>,
+        <&secure_proxy_mcu 5>, <&secure_proxy_mcu 5>, <&secure_proxy_mcu 4>;
+
+      reg-names = "debug_messages";
+      reg = <0x44083000 0x1000>;
+    };
+
+  - |
+    system-controller at 44083000 {
+      compatible = "ti,am642-sci";
+      ti,host-id = <35>;
+      mbox-names = "rx", "tx", "boot_rx", "boot_tx";
+      mboxes = <&secure_proxy_main 0>, <&secure_proxy_main 1>,
+        <&secure_proxy_main 0>, <&secure_proxy_main 1>;
+
+      reg-names = "debug_messages";
+      reg = <0x44083000 0x1000>;
+    };
+

---
base-commit: 4427259cc7f7571a157fbc9b5011e1ef6fe0a4a8
change-id: 20251105-k3_syscon_add_boot_mailboxes-8452bdd98962

Best regards,
-- 
Anshul Dalal <anshuld at ti.com>



From twei at axiado.com  Mon Dec 22 00:44:59 2025
From: twei at axiado.com (Tzu-Hao Wei)
Date: Mon, 22 Dec 2025 16:44:59 +0800
Subject: [PATCH 0/8] Add Axiado AX3000 eMMC Host Controller Support
Message-ID: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-0-5457d0ebcdb4@axiado.com>

This patch series adds support for the eMMC host controller found on
the Axiado AX3000 SoC. The implementation includes support for an
external Arasan eMMC PHY that enables HS200 mode operation at 200 MHz,
significantly improving performance over the default 25 MHz operation.

Hardware Details:

Arasan eMMC host controller on AX3000 SoC
External Arasan eMMC PHY (different from internal PHY supported
by the standard sdhci-of-arasan driver)
Support for HS200 mode (200 MHz) operation
Integration with existing SDHCI framework
Implementation Overview:
The series adds support for the external eMMC PHY required for HS200
mode. The existing sdhci-of-arasan.c driver supports internal PHY
configurations, but the AX3000 uses an external PHY that requires
different configuration. The PHY driver was implemented based on the
reference code in sdhci-pci-arasan.c as recommended by the Arasan team.

This series includes:
1. Device tree bindings for the eMMC PHY
2. PHY driver implementation for the external Arasan eMMC PHY
3. Integration of PHY support into the sdhci-of-arasan host driver
4. Device tree bindings for the eMMC host controller variant
5. Device tree source files for the SoC and EVK board
6. MAINTAINERS file update

Patch series structure:
[1/8] dt-bindings: phy: axiado,ax3000-emmc-phy: add Axiado eMMC PHY document
[2/8] phy: axiado: add Arasan eMMC-PHY for Axiado
[3/8] arm64: dts: axiado: Add eMMC-PHY node support
[4/8] MAINTAINERS: Update entry for Axiado eMMC PHY
[5/8] dt-bindings: mmc: axiado: Add axiado eMMC variant
[6/8] mmc: host: axiado: add AX3000 eMMC PHY support to sdhci-of-arasan
[7/8] arm64: dts: axiado: add common sdhci host node in dtsi
[8/8] arm64: dts: axiado: enable sdhci host

The driver follows the standard Linux PHY framework and integrates
seamlessly with the existing SDHCI subsystem. The implementation
maintains compatibility with the standard Arasan host controller
driver while adding the necessary support for the external PHY.

Signed-off-by: Tzu-Hao Wei <twei at axiado.com>
---
SriNavmani A (8):
      dt-bindings: phy: axiado,ax3000-emmc-phy: add Axiado eMMC PHY document
      phy: axiado: add Arasan eMMC-PHY for Axiado
      arm64: dts: axiado: Add eMMC-PHY node support
      MAINTAINERS: Update entry for Axiado eMMC PHY
      dt-bindings: mmc: axiado: Add axiado eMMC variant
      mmc: host: axiado: add AX3000 eMMC PHY support to sdhci-of-arasan
      arm64: dts: axiado: add common sdhci host node in dtsi
      arm64: dts: axiado: enable sdhci host

 .../devicetree/bindings/mmc/arasan,sdhci.yaml      |  18 ++
 .../bindings/phy/axiado,ax3000-emmc-phy.yaml       |  46 ++++
 MAINTAINERS                                        |  10 +
 arch/arm64/boot/dts/axiado/ax3000-evk.dts          |   8 +
 arch/arm64/boot/dts/axiado/ax3000.dtsi             |  20 ++
 drivers/mmc/host/sdhci-of-arasan.c                 |  20 +-
 drivers/phy/Kconfig                                |   1 +
 drivers/phy/Makefile                               |   1 +
 drivers/phy/axiado/Kconfig                         |  15 ++
 drivers/phy/axiado/Makefile                        |   1 +
 drivers/phy/axiado/phy-axiado-emmc.c               | 260 +++++++++++++++++++++
 11 files changed, 393 insertions(+), 7 deletions(-)
---
base-commit: 9448598b22c50c8a5bb77a9103e2d49f134c9578
change-id: 20251222-axiado-ax3000-add-emmc-host-driver-support-2cc84a8f889a

Best regards,
-- 
Tzu-Hao Wei <twei at axiado.com>



From twei at axiado.com  Mon Dec 22 00:45:00 2025
From: twei at axiado.com (Tzu-Hao Wei)
Date: Mon, 22 Dec 2025 16:45:00 +0800
Subject: [PATCH 1/8] dt-bindings: phy: axiado,ax3000-emmc-phy: add Axiado
 eMMC PHY document
In-Reply-To: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-0-5457d0ebcdb4@axiado.com>
References: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-0-5457d0ebcdb4@axiado.com>
Message-ID: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-1-5457d0ebcdb4@axiado.com>

From: SriNavmani A <srinavmani at axiado.com>

Add device tree bindings for the Axiado AX3000 eMMC PHY. The bindings
define the required properties for configuring the external Arasan
eMMC PHY, including register base addresses and clock references
needed for HS200 mode operation.

Signed-off-by: SriNavmani A <srinavmani at axiado.com>
Signed-off-by: Tzu-Hao Wei <twei at axiado.com>
---
 .../bindings/phy/axiado,ax3000-emmc-phy.yaml       | 46 ++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/Documentation/devicetree/bindings/phy/axiado,ax3000-emmc-phy.yaml b/Documentation/devicetree/bindings/phy/axiado,ax3000-emmc-phy.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f88941ce60cbd99a73e8c504e0bf36c626bbf674
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/axiado,ax3000-emmc-phy.yaml
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/axiado,ax3000-emmc-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Axiado AX3000 Arasan eMMC PHY
+
+maintainers:
+  - SriNavmani A <srinavmani at axiado.com>
+  - Tzu-Hao Wei <twei at axiado.com>
+  - Prasad Bolisetty <pbolisetty at axiado.com>
+
+description: |+
+  Bindings for eMMC PHY on Axiado AX3000 SoC.
+
+  - compatible:         Should be one of the following:
+                        "axiado,ax3000-emmc-phy"
+  - reg:
+      maxItems: 1
+
+properties:
+  compatible:
+    enum:
+      - axiado,ax3000-emmc-phy
+
+  "#phy-cells":
+    const: 0
+
+  reg:
+    maxItems: 1
+
+required:
+  - "#phy-cells"
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    emmc_phy: emmc-phy at 80801C00 {
+        compatible = "axiado,ax3000-emmc-phy";
+        reg = <0x80801C00 0x1000>;
+        #phy-cells = <0>;
+    };

-- 
2.48.1



From twei at axiado.com  Mon Dec 22 00:45:01 2025
From: twei at axiado.com (Tzu-Hao Wei)
Date: Mon, 22 Dec 2025 16:45:01 +0800
Subject: [PATCH 2/8] phy: axiado: add Arasan eMMC-PHY for Axiado
In-Reply-To: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-0-5457d0ebcdb4@axiado.com>
References: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-0-5457d0ebcdb4@axiado.com>
Message-ID: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-2-5457d0ebcdb4@axiado.com>

From: SriNavmani A <srinavmani at axiado.com>

Add support for the Arasan eMMC PHY found on the AX3000 SoC. This
external PHY is required to achieve HS200 mode operation (200 MHz)
on the eMMC interface.

The existing sdhci-of-arasan.c driver supports internal PHY
configurations, but the AX3000 uses an external PHY that requires
different configuration. This driver was written based on the
reference implementation in sdhci-pci-arasan.c as suggested by the
Arasan team to provide the necessary PHY configuration for HS200
high-speed mode support.

Signed-off-by: SriNavmani A <srinavmani at axiado.com>
Signed-off-by: Tzu-Hao Wei <twei at axiado.com>
---
 drivers/phy/Kconfig                  |   1 +
 drivers/phy/Makefile                 |   1 +
 drivers/phy/axiado/Kconfig           |  15 ++
 drivers/phy/axiado/Makefile          |   1 +
 drivers/phy/axiado/phy-axiado-emmc.c | 260 +++++++++++++++++++++++++++++++++++
 5 files changed, 278 insertions(+)

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 678dd0452f0aa0597773433f04d2a9ba77474d2a..b802274ea45a84bd36d7c0b7fb90e368a5c018b4 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -103,6 +103,7 @@ config PHY_NXP_PTN3222
 
 source "drivers/phy/allwinner/Kconfig"
 source "drivers/phy/amlogic/Kconfig"
+source "drivers/phy/axiado/Kconfig"
 source "drivers/phy/broadcom/Kconfig"
 source "drivers/phy/cadence/Kconfig"
 source "drivers/phy/freescale/Kconfig"
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index bfb27fb5a494283d7fd05dd670ebd1b12df8b1a1..f1b9e4a8673bcde3fdc0fdc06a3deddb5785ced1 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_PHY_AIROHA_PCIE)		+= phy-airoha-pcie.o
 obj-$(CONFIG_PHY_NXP_PTN3222)		+= phy-nxp-ptn3222.o
 obj-y					+= allwinner/	\
 					   amlogic/	\
+					   axiado/	\
 					   broadcom/	\
 					   cadence/	\
 					   freescale/	\
diff --git a/drivers/phy/axiado/Kconfig b/drivers/phy/axiado/Kconfig
new file mode 100644
index 0000000000000000000000000000000000000000..824114e6068da327308321b9884552ad33db9efc
--- /dev/null
+++ b/drivers/phy/axiado/Kconfig
@@ -0,0 +1,15 @@
+#
+# PHY drivers for Axiado platforms
+#
+
+config PHY_AX3000_EMMC
+	tristate "Axiado eMMC PHY driver"
+	select GENERIC_PHY
+	help
+	  This enables support for the eMMC PHY block found on the
+	  Axiado AX3000 SoCs. The PHY provides the physical layer
+	  interface used by the Arasan SDHCI host controller for emmc
+	  signaling and timing adjustment.
+
+	  If you are building a kernel for AX3000 platform with
+	  eMMC storage, say Y or N.
diff --git a/drivers/phy/axiado/Makefile b/drivers/phy/axiado/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..1e2b1ba016092eaffdbd7acbd9cdc8577d79b35c
--- /dev/null
+++ b/drivers/phy/axiado/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_PHY_AX3000_EMMC)		+= phy-axiado-emmc.o
diff --git a/drivers/phy/axiado/phy-axiado-emmc.c b/drivers/phy/axiado/phy-axiado-emmc.c
new file mode 100644
index 0000000000000000000000000000000000000000..a61a458c9a65915cd576b431bc6a0cf7e8b18add
--- /dev/null
+++ b/drivers/phy/axiado/phy-axiado-emmc.c
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Axiado eMMC PHY driver
+ *
+ * Copyright (C) 2022-2025 Axiado Corporation (or its affiliates).
+ *
+ * Based on Arasan Driver (sdhci-pci-arasan.c)
+ * sdhci-pci-arasan.c - Driver for Arasan PCI Controller with integrated phy.
+ *
+ * Copyright (C) 2017 Arasan Chip Systems Inc.
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+
+/* Arasan eMMC 5.1 - PHY configuration registers */
+#define CAP_REG_IN_S1_LSB		0x00
+#define CAP_REG_IN_S1_MSB		0x04
+#define PHY_CTRL_1			0x38
+#define PHY_CTRL_2			0x3C
+#define PHY_CTRL_3			0x40
+#define STATUS				0x50
+
+#define DLL_ENBL	BIT(26)
+#define RTRIM_EN	BIT(21)
+#define PDB_ENBL	BIT(23)
+#define RETB_ENBL	BIT(1)
+
+#define REN_STRB	BIT(27)
+#define REN_CMD		BIT(12)
+#define REN_DAT0	BIT(13)
+#define REN_DAT1	BIT(14)
+#define REN_DAT2	BIT(15)
+#define REN_DAT3	BIT(16)
+#define REN_DAT4	BIT(17)
+#define REN_DAT5	BIT(18)
+#define REN_DAT6	BIT(19)
+#define REN_DAT7	BIT(20)
+#define REN_CMD_EN	(REN_CMD | REN_DAT0 | REN_DAT1 | REN_DAT2 | \
+		REN_DAT3 | REN_DAT4 | REN_DAT5 | REN_DAT6 | REN_DAT7)
+
+/* Pull-UP Enable on CMD Line */
+#define PU_CMD		BIT(3)
+#define PU_DAT0		BIT(4)
+#define PU_DAT1		BIT(5)
+#define PU_DAT2		BIT(6)
+#define PU_DAT3		BIT(7)
+#define PU_DAT4		BIT(8)
+#define PU_DAT5		BIT(9)
+#define PU_DAT6		BIT(10)
+#define PU_DAT7		BIT(11)
+#define PU_CMD_EN (PU_CMD | PU_DAT0 | PU_DAT1 | PU_DAT2 | PU_DAT3 | \
+		PU_DAT4 | PU_DAT5 | PU_DAT6 | PU_DAT7)
+
+/* Slection value for the optimum delay from 1-32 output tap lines */
+#define OTAP_DLY	0x02
+/* DLL charge pump current trim default [1000] */
+#define DLL_TRM_ICP	0x08
+/* Select the frequency range of DLL Operation */
+#define FRQ_SEL	0x01
+
+#define OTAP_SEL(x)		(((x) << 7) | OTAPDLY_EN)
+#define DLL_TRM(x)		(((x) << 22) | DLL_ENBL)
+#define DLL_FRQSEL(x)	((x) << 25)
+
+#define OTAPDLY_EN	BIT(11)
+
+#define SEL_DLY_RXCLK	BIT(18)
+#define SEL_DLY_TXCLK	BIT(19)
+
+#define CALDONE_MASK	0x40
+#define DLL_RDY_MASK	0x1
+#define MAX_CLK_BUF0	BIT(20)
+#define MAX_CLK_BUF1	BIT(21)
+#define MAX_CLK_BUF2	BIT(22)
+
+#define CLK_MULTIPLIER	0xC008E
+#define LOOP_TIMEOUT	3000
+#define TIMEOUT_DELAY	100
+
+struct axiado_emmc_phy {
+	void __iomem    *reg_base;
+};
+
+static void arasan_emmc_phy_write(struct axiado_emmc_phy *ax_phy, u32 offset, u32 data)
+{
+	writel(data, ax_phy->reg_base + offset);
+}
+
+static int arasan_emmc_phy_read(struct axiado_emmc_phy *ax_phy, u32 offset)
+{
+	u32 val = readl(ax_phy->reg_base + offset);
+
+	return val;
+}
+
+static int axiado_emmc_phy_init(struct phy *phy)
+{
+	u32 val;
+	ktime_t timeout;
+
+	struct axiado_emmc_phy *ax_phy = phy_get_drvdata(phy);
+
+	val = arasan_emmc_phy_read(ax_phy, PHY_CTRL_1);
+	arasan_emmc_phy_write(ax_phy, PHY_CTRL_1, val | RETB_ENBL | RTRIM_EN);
+
+	val = arasan_emmc_phy_read(ax_phy, PHY_CTRL_3);
+	arasan_emmc_phy_write(ax_phy, PHY_CTRL_3, val | PDB_ENBL);
+
+	/* Wait max 3000 ms */
+	timeout = ktime_add_ms(ktime_get(), LOOP_TIMEOUT);
+
+	while (1) {
+		bool timedout = ktime_after(ktime_get(), timeout);
+
+		if (arasan_emmc_phy_read(ax_phy, STATUS) & CALDONE_MASK)
+			break;
+
+		if (timedout) {
+			dev_err(&phy->dev, "CALDONE_MASK bit is not cleared.");
+			return -ETIMEDOUT;
+		}
+		udelay(TIMEOUT_DELAY);
+	}
+
+	val = arasan_emmc_phy_read(ax_phy, PHY_CTRL_1);
+
+	arasan_emmc_phy_write(ax_phy, PHY_CTRL_1, val | REN_CMD_EN | PU_CMD_EN);
+
+	val = arasan_emmc_phy_read(ax_phy, PHY_CTRL_2);
+	arasan_emmc_phy_write(ax_phy, PHY_CTRL_2, val | REN_STRB);
+
+	val = arasan_emmc_phy_read(ax_phy, PHY_CTRL_3);
+	arasan_emmc_phy_write(ax_phy, PHY_CTRL_3, val | MAX_CLK_BUF0 |
+			MAX_CLK_BUF1 | MAX_CLK_BUF2);
+
+	val = arasan_emmc_phy_read(ax_phy, CAP_REG_IN_S1_MSB);
+	arasan_emmc_phy_write(ax_phy, CAP_REG_IN_S1_MSB, CLK_MULTIPLIER);
+
+	val = arasan_emmc_phy_read(ax_phy, PHY_CTRL_3);
+	arasan_emmc_phy_write(ax_phy, PHY_CTRL_3, val | SEL_DLY_RXCLK |
+			SEL_DLY_TXCLK);
+
+	return 0;
+}
+
+static int axiado_emmc_phy_power_on(struct phy *phy)
+{
+	struct axiado_emmc_phy *ax_phy = phy_get_drvdata(phy);
+
+	u32 val;
+	ktime_t timeout;
+
+	val = arasan_emmc_phy_read(ax_phy, PHY_CTRL_1);
+	arasan_emmc_phy_write(ax_phy, PHY_CTRL_1, val | RETB_ENBL);
+
+	val = arasan_emmc_phy_read(ax_phy, PHY_CTRL_3);
+	arasan_emmc_phy_write(ax_phy, PHY_CTRL_3, val | PDB_ENBL);
+
+	val = arasan_emmc_phy_read(ax_phy, PHY_CTRL_2);
+	arasan_emmc_phy_write(ax_phy, PHY_CTRL_2, val | OTAP_SEL(OTAP_DLY));
+
+	arasan_emmc_phy_read(ax_phy, PHY_CTRL_2);
+
+	val = arasan_emmc_phy_read(ax_phy, PHY_CTRL_1);
+	arasan_emmc_phy_write(ax_phy, PHY_CTRL_1, val | DLL_TRM(DLL_TRM_ICP));
+
+	arasan_emmc_phy_write(ax_phy, STATUS, 0x00);
+
+	val = arasan_emmc_phy_read(ax_phy, PHY_CTRL_3);
+	arasan_emmc_phy_write(ax_phy, PHY_CTRL_3, val | DLL_FRQSEL(FRQ_SEL));
+
+	/* Wait max 3000 ms */
+	timeout = ktime_add_ms(ktime_get(), LOOP_TIMEOUT);
+
+	while (1) {
+		bool timedout = ktime_after(ktime_get(), timeout);
+
+		if (arasan_emmc_phy_read(ax_phy, STATUS) & DLL_RDY_MASK)
+			break;
+
+		if (timedout) {
+			dev_err(&phy->dev, "DLL_RDY_MASK bit is not cleared.");
+			return -ETIMEDOUT;
+		}
+		udelay(TIMEOUT_DELAY);
+	}
+	return 0;
+}
+
+static const struct phy_ops axiado_emmc_phy_ops = {
+	.init		= axiado_emmc_phy_init,
+	.power_on	= axiado_emmc_phy_power_on,
+	.owner		= THIS_MODULE,
+};
+
+static const struct of_device_id axiado_emmc_phy_of_match[] = {
+	{ .compatible = "axiado,ax3000-emmc-phy"},
+	{}
+};
+MODULE_DEVICE_TABLE(of, axiado_emmc_phy_of_match);
+
+static int axiado_emmc_phy_probe(struct platform_device *pdev)
+{
+	struct axiado_emmc_phy *ax_phy;
+	struct phy_provider *phy_provider;
+	struct device *dev = &pdev->dev;
+	const struct of_device_id *id;
+	struct phy *generic_phy;
+	struct resource *res;
+
+	if (!dev->of_node)
+		return -ENODEV;
+
+	ax_phy = devm_kzalloc(dev, sizeof(*ax_phy), GFP_KERNEL);
+	if (!ax_phy)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	ax_phy->reg_base = devm_ioremap_resource(&pdev->dev, res);
+
+	if (IS_ERR(ax_phy->reg_base))
+		return PTR_ERR(ax_phy->reg_base);
+
+	id = of_match_node(axiado_emmc_phy_of_match, pdev->dev.of_node);
+	if (!id) {
+		dev_err(dev, "failed to get match_node\n");
+		return -EINVAL;
+	}
+
+	generic_phy = devm_phy_create(dev, dev->of_node, &axiado_emmc_phy_ops);
+	if (IS_ERR(generic_phy)) {
+		dev_err(dev, "failed to create PHY\n");
+		return PTR_ERR(generic_phy);
+	}
+
+	phy_set_drvdata(generic_phy, ax_phy);
+	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+	return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static struct platform_driver axiado_emmc_phy_driver = {
+	.probe		 = axiado_emmc_phy_probe,
+	.driver		 = {
+		.name	 = "axiado-emmc-phy",
+		.of_match_table = axiado_emmc_phy_of_match,
+	},
+};
+module_platform_driver(axiado_emmc_phy_driver);
+
+MODULE_DESCRIPTION("AX3000 eMMC PHY Driver");
+MODULE_AUTHOR("Axiado Corporation");
+MODULE_LICENSE("GPL");

-- 
2.48.1



From twei at axiado.com  Mon Dec 22 00:45:02 2025
From: twei at axiado.com (Tzu-Hao Wei)
Date: Mon, 22 Dec 2025 16:45:02 +0800
Subject: [PATCH 3/8] arm64: dts: axiado: Add eMMC-PHY node support
In-Reply-To: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-0-5457d0ebcdb4@axiado.com>
References: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-0-5457d0ebcdb4@axiado.com>
Message-ID: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-3-5457d0ebcdb4@axiado.com>

From: SriNavmani A <srinavmani at axiado.com>

Add the eMMC PHY device tree node to the AX3000 SoC device tree
include file. This node defines the external Arasan eMMC PHY
configuration required for HS200 mode operation.

Signed-off-by: Tzu-Hao Wei <twei at axiado.com>
---
 arch/arm64/boot/dts/axiado/ax3000.dtsi | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm64/boot/dts/axiado/ax3000.dtsi b/arch/arm64/boot/dts/axiado/ax3000.dtsi
index 792f52e0c7dd42cbc54b0eb47e25b0fbf1a706b8..0b64cf1245211ab0e9380dc27dae37dd9f3082e8 100644
--- a/arch/arm64/boot/dts/axiado/ax3000.dtsi
+++ b/arch/arm64/boot/dts/axiado/ax3000.dtsi
@@ -507,6 +507,13 @@ uart3: serial at 80520800 {
 			clocks = <&refclk &refclk>;
 			status = "disabled";
 		};
+
+		emmc_phy: emmc-phy at 80801C00 {
+			compatible = "axiado,ax3000-emmc-phy";
+			reg = <0x00 0x80801C00 0x00 0x1000>;
+			#phy-cells = <0>;
+			status = "disabled";
+		};
 	};
 
 	timer {

-- 
2.48.1



From twei at axiado.com  Mon Dec 22 00:45:03 2025
From: twei at axiado.com (Tzu-Hao Wei)
Date: Mon, 22 Dec 2025 16:45:03 +0800
Subject: [PATCH 4/8] MAINTAINERS: Update entry for Axiado eMMC PHY
In-Reply-To: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-0-5457d0ebcdb4@axiado.com>
References: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-0-5457d0ebcdb4@axiado.com>
Message-ID: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-4-5457d0ebcdb4@axiado.com>

From: SriNavmani A <srinavmani at axiado.com>

Update the MAINTAINERS file to include the Axiado eMMC PHY driver
files. This includes the PHY driver source files, device tree
bindings, and related configuration files for the AX3000 eMMC PHY
support.

Signed-off-by: Tzu-Hao Wei <twei at axiado.com>
---
 MAINTAINERS | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index dc731d37c8feeff25613c59fe9c929927dadaa7e..d14f2d1c94bc65879c922401366f98a812dd3ba9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4250,6 +4250,16 @@ W:	https://ez.analog.com/linux-software-drivers
 F:	Documentation/devicetree/bindings/hwmon/adi,axi-fan-control.yaml
 F:	drivers/hwmon/axi-fan-control.c
 
+AXIADO EMMC PHY DRIVER
+M:	SriNavmani A <srinavmani at axiado.com>
+M:	Tzu-Hao Wei <twei at axiado.com>
+M:	Prasad Bolisetty <pbolisetty at axiado.com>
+L:	linux-phy at lists.infradead.org (moderated for non-subscribers)
+S:	Maintained
+F:	Documentation/devicetree/bindings/phy/axiado,ax3000-emmc-phy.yaml
+F:	drivers/phy/axiado/Kconfig
+F:	drivers/phy/axiado/phy-axiado-emmc.c
+
 AXI SPI ENGINE
 M:	Michael Hennerich <michael.hennerich at analog.com>
 M:	Nuno S? <nuno.sa at analog.com>

-- 
2.48.1



From twei at axiado.com  Mon Dec 22 00:45:04 2025
From: twei at axiado.com (Tzu-Hao Wei)
Date: Mon, 22 Dec 2025 16:45:04 +0800
Subject: [PATCH 5/8] dt-bindings: mmc: axiado: Add axiado eMMC variant
In-Reply-To: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-0-5457d0ebcdb4@axiado.com>
References: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-0-5457d0ebcdb4@axiado.com>
Message-ID: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-5-5457d0ebcdb4@axiado.com>

From: SriNavmani A <srinavmani at axiado.com>

Add device tree binding variant for the Axiado AX3000 Arasan eMMC
controller. This variant identifies the specific eMMC controller
implementation used on the AX3000 SoC and enables the appropriate
driver configuration.

Signed-off-by: Tzu-Hao Wei <twei at axiado.com>
---
 .../devicetree/bindings/mmc/arasan,sdhci.yaml          | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml b/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml
index 8e79de97b242a698a2c555b0b94e2975b1761710..47d0e35efea00bf7b1927bd0cfa39c86f0137d44 100644
--- a/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml
+++ b/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml
@@ -106,6 +106,12 @@ properties:
         description:
           For this device it is strongly suggested to include
           arasan,soc-ctl-syscon.
+      - items:
+          - const: axiado,ax3000-sdhci-5.1-emmc
+          - const: arasan,sdhci-5.1
+        description:
+          For this device it is strongly suggested to include
+          clock-output-names and '#clock-cells'.
 
   reg:
     maxItems: 1
@@ -334,3 +340,15 @@ examples:
                    <&scmi_clk KEEM_BAY_PSS_SD0>;
           arasan,soc-ctl-syscon = <&sd0_phy_syscon>;
     };
+
+  - |
+    mmc at 86000000 {
+          compatible = "axiado,ax3000-sdhci-5.1-emmc", "arasan,sdhci-5.1";
+          reg = <0x86000000 0x1000>;
+          clock-names = "clk_xin", "clk_ahb";
+          clocks = <&clk_xin &clk_ahb>;
+          interrupt-parent = <&gic500>;
+          interrupts = <0 123 4>;
+          phys = <&emmc_phy>;
+          phy-names = "phy_arasan";
+    };

-- 
2.48.1



From twei at axiado.com  Mon Dec 22 00:45:05 2025
From: twei at axiado.com (Tzu-Hao Wei)
Date: Mon, 22 Dec 2025 16:45:05 +0800
Subject: [PATCH 6/8] mmc: host: axiado: add AX3000 eMMC PHY support to
 sdhci-of-arasan
In-Reply-To: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-0-5457d0ebcdb4@axiado.com>
References: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-0-5457d0ebcdb4@axiado.com>
Message-ID: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-6-5457d0ebcdb4@axiado.com>

From: SriNavmani A <srinavmani at axiado.com>

Add support for the external eMMC PHY used on the AX3000 SoC in the
sdhci-of-arasan driver. The default Arasan host driver operates at
25 MHz, but with the external PHY support, the controller can achieve
HS200 mode operation at 200 MHz.

This change integrates the AX3000 eMMC PHY driver with the existing
sdhci-of-arasan host controller driver to enable high-speed eMMC
operations.

Signed-off-by: Tzu-Hao Wei <twei at axiado.com>
---
 drivers/mmc/host/sdhci-of-arasan.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index ab7f0ffe7b4f007a58eb0a26868b08b0b02b40f3..2d4f64e9014ae168957113478edc11209cd76b64 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -1547,6 +1547,10 @@ static const struct of_device_id sdhci_arasan_of_match[] = {
 		.compatible = "arasan,sdhci-5.1",
 		.data = &sdhci_arasan_generic_data,
 	},
+	{
+		.compatible = "axiado,ax3000-sdhci-5.1-emmc",
+		.data = &sdhci_arasan_generic_data,
+	},
 	{
 		.compatible = "arasan,sdhci-4.9a",
 		.data = &sdhci_arasan_generic_data,
@@ -2019,15 +2023,17 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
 			goto unreg_clk;
 		}
 
-		host->mmc_host_ops.hs400_enhanced_strobe =
+		if (!of_device_is_compatible(np, "axiado,ax3000-sdhci-5.1-emmc")) {
+			host->mmc_host_ops.hs400_enhanced_strobe =
 					sdhci_arasan_hs400_enhanced_strobe;
-		host->mmc_host_ops.start_signal_voltage_switch =
-					sdhci_arasan_voltage_switch;
-		sdhci_arasan->has_cqe = true;
-		host->mmc->caps2 |= MMC_CAP2_CQE;
+			host->mmc_host_ops.start_signal_voltage_switch =
+				sdhci_arasan_voltage_switch;
+			sdhci_arasan->has_cqe = true;
+			host->mmc->caps2 |= MMC_CAP2_CQE;
 
-		if (!of_property_read_bool(np, "disable-cqe-dcmd"))
-			host->mmc->caps2 |= MMC_CAP2_CQE_DCMD;
+			if (!of_property_read_bool(np, "disable-cqe-dcmd"))
+				host->mmc->caps2 |= MMC_CAP2_CQE_DCMD;
+		}
 	}
 
 	if (of_device_is_compatible(np, "xlnx,versal-net-emmc"))

-- 
2.48.1



From twei at axiado.com  Mon Dec 22 00:45:06 2025
From: twei at axiado.com (Tzu-Hao Wei)
Date: Mon, 22 Dec 2025 16:45:06 +0800
Subject: [PATCH 7/8] arm64: dts: axiado: add common sdhci host node in dtsi
In-Reply-To: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-0-5457d0ebcdb4@axiado.com>
References: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-0-5457d0ebcdb4@axiado.com>
Message-ID: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-7-5457d0ebcdb4@axiado.com>

From: SriNavmani A <srinavmani at axiado.com>

Add the SDHCI host controller device tree node to the AX3000 SoC
device tree include file. This node defines the Arasan eMMC host
controller configuration, including register mappings, interrupts,
and clock references for the AX3000 SoC.

Signed-off-by: Tzu-Hao Wei <twei at axiado.com>
---
 arch/arm64/boot/dts/axiado/ax3000.dtsi | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/arch/arm64/boot/dts/axiado/ax3000.dtsi b/arch/arm64/boot/dts/axiado/ax3000.dtsi
index 0b64cf1245211ab0e9380dc27dae37dd9f3082e8..b963537001155d825f878156b2f930b202da1723 100644
--- a/arch/arm64/boot/dts/axiado/ax3000.dtsi
+++ b/arch/arm64/boot/dts/axiado/ax3000.dtsi
@@ -514,6 +514,19 @@ emmc_phy: emmc-phy at 80801C00 {
 			#phy-cells = <0>;
 			status = "disabled";
 		};
+
+		sdhci0: mmc at 86000000 {
+			compatible = "axiado,ax3000-sdhci-5.1-emmc", "arasan,sdhci-5.1";
+			reg = <0x0 0x86000000 0x00 0x1000>;
+			clock-names = "clk_xin", "clk_ahb";
+			clocks = <&clk_xin &clk_xin>;
+			interrupt-parent = <&gic500>;
+			interrupts = <0 123 4>;
+			bus-width = <8>;
+			phys = <&emmc_phy>;
+			phy-names = "phy_arasan";
+			status = "disabled";
+		};
 	};
 
 	timer {

-- 
2.48.1



From twei at axiado.com  Mon Dec 22 00:45:07 2025
From: twei at axiado.com (Tzu-Hao Wei)
Date: Mon, 22 Dec 2025 16:45:07 +0800
Subject: [PATCH 8/8] arm64: dts: axiado: enable sdhci host
In-Reply-To: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-0-5457d0ebcdb4@axiado.com>
References: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-0-5457d0ebcdb4@axiado.com>
Message-ID: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-8-5457d0ebcdb4@axiado.com>

From: SriNavmani A <srinavmani at axiado.com>

Enable the SDHCI host controller for eMMC support on the AX3000 EVK
evaluation board by referencing the SDHCI node defined in the SoC
device tree include file. This enables eMMC functionality on the
evaluation board.

Signed-off-by: Tzu-Hao Wei <twei at axiado.com>
---
 arch/arm64/boot/dts/axiado/ax3000-evk.dts | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/boot/dts/axiado/ax3000-evk.dts b/arch/arm64/boot/dts/axiado/ax3000-evk.dts
index b86e969625573bf92bdd5e4435ea571dd7500de2..a5cc75dfbe554749201b0910ec268c899bc5246c 100644
--- a/arch/arm64/boot/dts/axiado/ax3000-evk.dts
+++ b/arch/arm64/boot/dts/axiado/ax3000-evk.dts
@@ -80,3 +80,11 @@ &uart2 {
 &uart3 {
 	status = "okay";
 };
+
+&emmc_phy {
+	status = "okay";
+};
+
+&sdhci0 {
+	status = "okay";
+};

-- 
2.48.1



From leon at kernel.org  Mon Dec 22 00:49:21 2025
From: leon at kernel.org (Leon Romanovsky)
Date: Mon, 22 Dec 2025 10:49:21 +0200
Subject: [PATCH 5/6] dma-mapping: Allow batched DMA sync operations if
 supported by the arch
In-Reply-To: <20251221192458.1320-1-21cnbao@gmail.com>
References: <20251221115523.GI13030@unreal>
 <20251221192458.1320-1-21cnbao@gmail.com>
Message-ID: <20251222084921.GA13529@unreal>

On Mon, Dec 22, 2025 at 03:24:58AM +0800, Barry Song wrote:
> On Sun, Dec 21, 2025 at 7:55?PM Leon Romanovsky <leon at kernel.org> wrote:
> [...]
> > > +
> >
> > I'm wondering why you don't implement this batch?sync support inside the
> > arch_sync_dma_*() functions. Doing so would minimize changes to the generic
> > kernel/dma/* code and reduce the amount of #ifdef?based spaghetti.
> >
> 
> There are two cases: mapping an sg list and mapping a single
> buffer. The former can be batched with
> arch_sync_dma_*_batch_add() and flushed via
> arch_sync_dma_batch_flush(), while the latter requires all work to
> be done inside arch_sync_dma_*(). Therefore,
> arch_sync_dma_*() cannot always batch and flush.

Probably in all cases you can call the _batch_ variant, followed by _flush_,  
even when handling a single page. This keeps the code consistent across all  
paths. On platforms that do not support _batch_, the _flush_ operation will be  
a NOP anyway.

I would also rename arch_sync_dma_batch_flush() to arch_sync_dma_flush().

You can also minimize changes in dma_direct_map_phys() too, by extending
it's signature to provide if flush is needed or not.

dma_direct_map_phys(....) -> dma_direct_map_phys(...., bool flush):

static inline dma_addr_t dma_direct_map_phys(...., bool flush)
{
	....

	if (dma_addr != DMA_MAPPING_ERROR && !dev_is_dma_coherent(dev) &&
	    !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO)))
        {
	    	arch_sync_dma_for_device(phys, size, dir);
		if (flush)
			arch_sync_dma_flush();
	}
}

Thanks


From ming.qian at oss.nxp.com  Mon Dec 22 00:49:10 2025
From: ming.qian at oss.nxp.com (ming.qian at oss.nxp.com)
Date: Mon, 22 Dec 2025 16:49:10 +0800
Subject: [PATCH] media: amphion: Use kmalloc instead of vmalloc
Message-ID: <20251222084912.747-1-ming.qian@oss.nxp.com>

From: Ming Qian <ming.qian at oss.nxp.com>

Replace vmalloc/vfree with kmalloc/kfree for allocating small
driver structures (vpu_inst, vdec_t, venc_t, vpu_cmd_t, and
frame objects).

vmalloc() is designed for large memory allocations and incurs
unnecessary overhead for small objects due to virtual memory
mapping. kmalloc() is more appropriate as it allocates physically
contiguous memory with lower overhead.

ftrace measurements of vpu_alloc_cmd() show significant improvement:

  Before (vmalloc):  35-72 us   (avg ~45.7 us)
  After (kmalloc):   11-26 us   (avg ~16.8 us)

This reduces allocation time by approximately 63%.

No functional changes are intended.

Signed-off-by: Ming Qian <ming.qian at oss.nxp.com>
---
 drivers/media/platform/amphion/vdec.c     | 16 +++++++---------
 drivers/media/platform/amphion/venc.c     | 20 +++++++++-----------
 drivers/media/platform/amphion/vpu_cmds.c | 15 +++++++--------
 drivers/media/platform/amphion/vpu_core.c | 11 ++++-------
 4 files changed, 27 insertions(+), 35 deletions(-)

diff --git a/drivers/media/platform/amphion/vdec.c b/drivers/media/platform/amphion/vdec.c
index c0d2aabb9e0e..7a1c58cac02d 100644
--- a/drivers/media/platform/amphion/vdec.c
+++ b/drivers/media/platform/amphion/vdec.c
@@ -9,7 +9,6 @@
 #include <linux/list.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/vmalloc.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-event.h>
@@ -17,7 +16,6 @@
 #include <media/v4l2-ioctl.h>
 #include <media/videobuf2-v4l2.h>
 #include <media/videobuf2-dma-contig.h>
-#include <media/videobuf2-vmalloc.h>
 #include "vpu.h"
 #include "vpu_defs.h"
 #include "vpu_core.h"
@@ -1642,9 +1640,9 @@ static void vdec_cleanup(struct vpu_inst *inst)
 		vdec->slots = NULL;
 		vdec->slot_count = 0;
 	}
-	vfree(vdec);
+	kfree(vdec);
 	inst->priv = NULL;
-	vfree(inst);
+	kfree(inst);
 }
 
 static void vdec_init_params(struct vdec_t *vdec)
@@ -1909,13 +1907,13 @@ static int vdec_open(struct file *file)
 	struct vdec_t *vdec;
 	int ret;
 
-	inst = vzalloc(sizeof(*inst));
+	inst = kzalloc(sizeof(*inst), GFP_KERNEL);
 	if (!inst)
 		return -ENOMEM;
 
-	vdec = vzalloc(sizeof(*vdec));
+	vdec = kzalloc(sizeof(*vdec), GFP_KERNEL);
 	if (!vdec) {
-		vfree(inst);
+		kfree(inst);
 		return -ENOMEM;
 	}
 
@@ -1923,8 +1921,8 @@ static int vdec_open(struct file *file)
 				    sizeof(*vdec->slots),
 				    GFP_KERNEL | __GFP_ZERO);
 	if (!vdec->slots) {
-		vfree(vdec);
-		vfree(inst);
+		kfree(vdec);
+		kfree(inst);
 		return -ENOMEM;
 	}
 	vdec->slot_count = VDEC_SLOT_CNT_DFT;
diff --git a/drivers/media/platform/amphion/venc.c b/drivers/media/platform/amphion/venc.c
index aced76401b69..9e5cbc2b0d3f 100644
--- a/drivers/media/platform/amphion/venc.c
+++ b/drivers/media/platform/amphion/venc.c
@@ -13,14 +13,12 @@
 #include <linux/videodev2.h>
 #include <linux/ktime.h>
 #include <linux/rational.h>
-#include <linux/vmalloc.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-event.h>
 #include <media/v4l2-mem2mem.h>
 #include <media/v4l2-ioctl.h>
 #include <media/videobuf2-v4l2.h>
 #include <media/videobuf2-dma-contig.h>
-#include <media/videobuf2-vmalloc.h>
 #include "vpu.h"
 #include "vpu_defs.h"
 #include "vpu_core.h"
@@ -844,7 +842,7 @@ static int venc_get_encoded_frames(struct vpu_inst *inst)
 					       v4l2_m2m_dst_buf_remove(inst->fh.m2m_ctx)))
 			break;
 		list_del_init(&frame->list);
-		vfree(frame);
+		kfree(frame);
 	}
 
 	return 0;
@@ -860,7 +858,7 @@ static int venc_frame_encoded(struct vpu_inst *inst, void *arg)
 	if (!info)
 		return -EINVAL;
 	venc = inst->priv;
-	frame = vzalloc(sizeof(*frame));
+	frame = kzalloc(sizeof(*frame), GFP_KERNEL);
 	if (!frame)
 		return -ENOMEM;
 
@@ -912,9 +910,9 @@ static void venc_cleanup(struct vpu_inst *inst)
 		return;
 
 	venc = inst->priv;
-	vfree(venc);
+	kfree(venc);
 	inst->priv = NULL;
-	vfree(inst);
+	kfree(inst);
 }
 
 static int venc_start_session(struct vpu_inst *inst, u32 type)
@@ -1067,7 +1065,7 @@ static void venc_cleanup_frames(struct venc_t *venc)
 
 	list_for_each_entry_safe(frame, tmp, &venc->frames, list) {
 		list_del_init(&frame->list);
-		vfree(frame);
+		kfree(frame);
 	}
 }
 
@@ -1151,7 +1149,7 @@ static int venc_process_capture(struct vpu_inst *inst, struct vb2_buffer *vb)
 		return ret;
 
 	list_del_init(&frame->list);
-	vfree(frame);
+	kfree(frame);
 	return 0;
 }
 
@@ -1309,13 +1307,13 @@ static int venc_open(struct file *file)
 	struct venc_t *venc;
 	int ret;
 
-	inst = vzalloc(sizeof(*inst));
+	inst = kzalloc(sizeof(*inst), GFP_KERNEL);
 	if (!inst)
 		return -ENOMEM;
 
-	venc = vzalloc(sizeof(*venc));
+	venc = kzalloc(sizeof(*venc), GFP_KERNEL);
 	if (!venc) {
-		vfree(inst);
+		kfree(inst);
 		return -ENOMEM;
 	}
 
diff --git a/drivers/media/platform/amphion/vpu_cmds.c b/drivers/media/platform/amphion/vpu_cmds.c
index 5695f5c1cb3e..ab69412e0aa7 100644
--- a/drivers/media/platform/amphion/vpu_cmds.c
+++ b/drivers/media/platform/amphion/vpu_cmds.c
@@ -13,7 +13,6 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/delay.h>
-#include <linux/vmalloc.h>
 #include "vpu.h"
 #include "vpu_defs.h"
 #include "vpu_cmds.h"
@@ -84,13 +83,13 @@ static struct vpu_cmd_t *vpu_alloc_cmd(struct vpu_inst *inst, u32 id, void *data
 	int i;
 	int ret;
 
-	cmd = vzalloc(sizeof(*cmd));
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
 	if (!cmd)
 		return NULL;
 
-	cmd->pkt = vzalloc(sizeof(*cmd->pkt));
+	cmd->pkt = kzalloc(sizeof(*cmd->pkt), GFP_KERNEL);
 	if (!cmd->pkt) {
-		vfree(cmd);
+		kfree(cmd);
 		return NULL;
 	}
 
@@ -98,8 +97,8 @@ static struct vpu_cmd_t *vpu_alloc_cmd(struct vpu_inst *inst, u32 id, void *data
 	ret = vpu_iface_pack_cmd(inst->core, cmd->pkt, inst->id, id, data);
 	if (ret) {
 		dev_err(inst->dev, "iface pack cmd %s fail\n", vpu_id_name(id));
-		vfree(cmd->pkt);
-		vfree(cmd);
+		kfree(cmd->pkt);
+		kfree(cmd);
 		return NULL;
 	}
 	for (i = 0; i < ARRAY_SIZE(vpu_cmd_requests); i++) {
@@ -118,8 +117,8 @@ static void vpu_free_cmd(struct vpu_cmd_t *cmd)
 		return;
 	if (cmd->last_response_cmd)
 		atomic_long_set(cmd->last_response_cmd, cmd->key);
-	vfree(cmd->pkt);
-	vfree(cmd);
+	kfree(cmd->pkt);
+	kfree(cmd);
 }
 
 static int vpu_session_process_cmd(struct vpu_inst *inst, struct vpu_cmd_t *cmd)
diff --git a/drivers/media/platform/amphion/vpu_core.c b/drivers/media/platform/amphion/vpu_core.c
index 168f0514851e..85cc4a14f8ed 100644
--- a/drivers/media/platform/amphion/vpu_core.c
+++ b/drivers/media/platform/amphion/vpu_core.c
@@ -17,7 +17,6 @@
 #include <linux/pm_runtime.h>
 #include <linux/pm_domain.h>
 #include <linux/firmware.h>
-#include <linux/vmalloc.h>
 #include "vpu.h"
 #include "vpu_defs.h"
 #include "vpu_core.h"
@@ -265,7 +264,7 @@ static int vpu_core_register(struct device *dev, struct vpu_core *core)
 	INIT_WORK(&core->msg_work, vpu_msg_run_work);
 	INIT_DELAYED_WORK(&core->msg_delayed_work, vpu_msg_delayed_work);
 	buffer_size = roundup_pow_of_two(VPU_MSG_BUFFER_SIZE);
-	core->msg_buffer = vzalloc(buffer_size);
+	core->msg_buffer = kzalloc(buffer_size, GFP_KERNEL);
 	if (!core->msg_buffer) {
 		dev_err(core->dev, "failed allocate buffer for fifo\n");
 		ret = -ENOMEM;
@@ -282,10 +281,8 @@ static int vpu_core_register(struct device *dev, struct vpu_core *core)
 
 	return 0;
 error:
-	if (core->msg_buffer) {
-		vfree(core->msg_buffer);
-		core->msg_buffer = NULL;
-	}
+	kfree(core->msg_buffer);
+	core->msg_buffer = NULL;
 	if (core->workqueue) {
 		destroy_workqueue(core->workqueue);
 		core->workqueue = NULL;
@@ -308,7 +305,7 @@ static int vpu_core_unregister(struct device *dev, struct vpu_core *core)
 
 	vpu_core_put_vpu(core);
 	core->vpu = NULL;
-	vfree(core->msg_buffer);
+	kfree(core->msg_buffer);
 	core->msg_buffer = NULL;
 
 	if (core->workqueue) {

base-commit: b70886ff5833cf499e77af77d2324ce8f68b60ce
-- 
2.52.0



From krzk at kernel.org  Mon Dec 22 00:53:53 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 22 Dec 2025 09:53:53 +0100
Subject: [PATCH v6] dt-bindings: arm: keystone: add boot_* mboxes to
 ti,sci
In-Reply-To: <20251222-k3_syscon_add_boot_mailboxes-v6-1-b93ada9f1d47@ti.com>
References: <20251222-k3_syscon_add_boot_mailboxes-v6-1-b93ada9f1d47@ti.com>
Message-ID: <1844147d-543d-4739-a1ec-a59f8a4564fb@kernel.org>

On 22/12/2025 09:43, Anshul Dalal wrote:
> The bootloader on K3 devices makes use of mailboxes as per the ROM spec
> which might be different than one's available to the kernel (firmware
> spec).
> 
> Therefore, this patch adds the missing mailbox entries to the DT binding
> if the matching compatible is ti,am654-sci to represent the mailboxes
> exposed by the hardware during boot for the purpose of loading the
> firmware.
> 
> The new ti,am642-sci compatible is also added to represent SoCs which do
> not expose a "notify" channel as part of their TI-SCI spec such as AM64x
> or the AM62 family. The newly added mboxes are made optional by keeping
> minItems as 2 to remain compliant with existing device-trees.
> 
> Signed-off-by: Anshul Dalal <anshuld at ti.com>
> ---
> Changes in v6:
> - Added ti,am642-sci compatible to represent SoCs without a "notify" channel
> - Added new examples instead of editing existing ones

Why? Rob asked not to.

> - Link to v5: https://lore.kernel.org/r/20251215-k3_syscon_add_boot_mailboxes-v5-1-5a8fe567fd31 at ti.com
> 
> Changes in v5:
> - Added commit description for the optional mailboxes
> - Link to v4: https://lore.kernel.org/r/20251205-k3_syscon_add_boot_mailboxes-v4-1-8e216fb88941 at ti.com
> 
> Changes in v4:
> - Make new boot_* mboxes conditional on ti,am654-sci compatible
> - Link to v3: https://lore.kernel.org/r/20251112-k3_syscon_add_boot_mailboxes-v3-1-66155a4236dc at ti.com
> 
> Changes in v3:
> - Drop [1/2] of the last patch series
> - Update existing example with boot_* mailboxes instead of adding a new one
> - Link to v2: https://lore.kernel.org/r/20251112-k3_syscon_add_boot_mailboxes-v2-0-aebc1e47b391 at ti.com
> 
> Changes in v2:
> - Remove maxItems entry
> - Remove RFC tag from patch (added by mistake in v1)
> - Document the new mailboxes in mboxes instead of mbox-names
> - Provide example with all the mailboxes set
> - Update commit title to have "ti,sci"
> - Split into two patches
> - Link to v1: https://lore.kernel.org/r/20251111-k3_syscon_add_boot_mailboxes-v1-1-529a27f21076 at ti.com
> ---
>  .../devicetree/bindings/arm/keystone/ti,sci.yaml   | 94 +++++++++++++++++++++-
>  1 file changed, 91 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
> index 25a2b42105e5..0f2c764eae5a 100644
> --- a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
> +++ b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
> @@ -40,6 +40,9 @@ properties:
>        - description: System controller on TI AM654 SoC
>          items:
>            - const: ti,am654-sci
> +      - description: System controller on TI AM642 SoC
> +        items:
> +          - const: ti,am642-sci

Why this is not part of enum with previous entries like that?

>  
>    reg-names:
>      description: |
> @@ -51,15 +54,15 @@ properties:
>      minItems: 1
>  
>    mbox-names:
> +    minItems: 2
> +    maxItems: 6
>      description: |
>        Specifies the mailboxes used to communicate with TI-SCI Controller
>        made available from TI-SCI controller.
> -    items:
> -      - const: rx
> -      - const: tx
>  
>    mboxes:
>      minItems: 2
> +    maxItems: 6
>  
>    ti,host-id:
>      $ref: /schemas/types.yaml#/definitions/uint32
> @@ -79,6 +82,66 @@ properties:
>      type: object
>      $ref: /schemas/reset/ti,sci-reset.yaml#
>  
> +if:
> +  properties:
> +    compatible:
> +      contains:
> +        const: ti,am654-sci
> +then:
> +  properties:
> +    mbox-names:
> +      minItems: 2
> +      items:
> +        - const: rx
> +        - const: tx
> +        - const: notify

Move the notify to the end, so you have only one common list defined at
the top and you only change number of items per variant.

> +        - const: boot_rx
> +        - const: boot_tx
> +        - const: boot_notify
> +    mboxes:
> +      minItems: 2
> +      items:
> +        - description: RX thread
> +        - description: TX thread
> +        - description: Notify thread
> +        - description: boot stage RX thread
> +        - description: boot stage TX thread
> +        - description: boot stage Notify thread
> +else:
> +  if:

No, that's not readable. Don't nest these.

> +    properties:
> +      compatible:
> +        contains:
> +          const: ti,am642-sci
> +  then:
> +    properties:
> +      mbox-names:
> +        minItems: 2
> +        items:
> +          - const: rx
> +          - const: tx
> +          - const: boot_rx
> +          - const: boot_tx
> +          - const: boot_notify
> +      mboxes:
> +        minItems: 2
> +        items:
> +          - description: RX thread
> +          - description: TX thread
> +          - description: boot stage RX thread
> +          - description: boot stage TX thread
> +          - description: boot stage Notify thread
> +  else:
> +    properties:
> +      mbox-names:
> +        items:
> +          - const: rx
> +          - const: tx
> +      mboxes:
> +        items:
> +          - description: RX thread
> +          - description: TX thread
> +
>  required:
>    - compatible
>    - mbox-names
> @@ -122,3 +185,28 @@ examples:
>          #reset-cells = <2>;
>        };
>      };
> +
> +  - |
> +    system-controller at 44083000 {
> +      compatible = "ti,am654-sci";
> +      ti,host-id = <4>;
> +      mbox-names = "rx", "tx", "notify", "boot_rx", "boot_tx";
> +      mboxes = <&secure_proxy_mcu 6>, <&secure_proxy_mcu 8>,
> +        <&secure_proxy_mcu 5>, <&secure_proxy_mcu 5>, <&secure_proxy_mcu 4>;
> +
> +      reg-names = "debug_messages";
> +      reg = <0x44083000 0x1000>;
> +    };

You already have there two examples. You do not need three and for sure
you do not need four of which two are exactly the same. Rob already
commented on this.

Best regards,
Krzysztof


From adam.drzewiecki at vexro.pl  Mon Dec 22 00:55:52 2025
From: adam.drzewiecki at vexro.pl (Adam Drzewiecki)
Date: Mon, 22 Dec 2025 08:55:52 GMT
Subject: W sprawie samochodu 
Message-ID: <20251222084500-0.1.pc.4shx6.0.w6gldrnq76@vexro.pl>

Dzie? dobry,

czy istnieje mo?liwo?? porozmawiania z Pa?stwem o wsp??pracy?

Dostarczamy i wdra?amy system, kt?rego efektem jest obni?enie koszt?w za paliwo, szybsze pokonywanie tras, skr?cenie czasu dostaw oraz wi?ksze bezpiecze?stwo kierowc?w na drodze.

Prosz? o kontakt, je?li interesuje Pa?stwa poznanie mo?liwo?ci lub bezp?atny test tego typu narz?dzia.


Pozdrawiam
Adam Drzewiecki


From mikko.rapeli at linaro.org  Mon Dec 22 00:58:42 2025
From: mikko.rapeli at linaro.org (Mikko Rapeli)
Date: Mon, 22 Dec 2025 10:58:42 +0200
Subject: [PATCH 0/2] drm: xlnx: zynqmp_kms: 16 bpp fixes for Xorg startup
 on AMD KV260
In-Reply-To: <aUVFUx55XTjb_2nO@nuoska>
References: <20251205123751.2257694-1-mikko.rapeli@linaro.org>
 <533168f1-1655-4947-9032-b08463f502d7@ideasonboard.com>
 <aUVFUx55XTjb_2nO@nuoska>
Message-ID: <aUkIQjKpd3MhNHjk@nuoska>

Hi,

On Fri, Dec 19, 2025 at 02:30:11PM +0200, Mikko Rapeli wrote:
> On Fri, Dec 19, 2025 at 01:59:14PM +0200, Tomi Valkeinen wrote:
> > On 05/12/2025 14:37, Mikko Rapeli wrote:
> > > Currently on default yocto images Xorg fails to start on AMD KV260
> > > because 24/32 color depth gets detected but does not actually work.
> > > 
> > > These two patches fix the issue and now 16 bpp gets detected
> > > and Xorg starts and draws on external HDMI display using
> > > kernel.org based linux-yocto kernel.
> > > 
> > > Anatoliy Klymenko (1):
> > >   drm: xlnx: zynqmp_kms: Init fbdev with 16 bit color
> > > 
> > > Mikko Rapeli (1):
> > >   drm: xlnx: zynqmp_kms: set preferred_depth to 16 bpp
> > > 
> > >  drivers/gpu/drm/xlnx/zynqmp_kms.c | 3 ++-
> > >  1 file changed, 2 insertions(+), 1 deletion(-)
> > > 
> > 
> > Did you notice the few already sent serieses on the list where the topic
> > has been discussed?
> 
> > [PATCH] drm: xlnx: zynqmp_dp: Support DRM_FORMAT_XRGB8888
> > [PATCH 0/3] drm: zynqmp: Make the video plane primary
> 
> Oh I wasn't aware of these.
> 
> > Or is there something else on KV260 that messes up the 24 bit color?
> 
> These look very similar and likely fix the X11 startup. I will give them
> a try.

Right, now I've tested:

 * these patches from Anatoliy and me to help X11 use 16bpp mode by default
   and removes the need to manually setup Xorg for 16bpp
 * "drm: xlnx: zynqmp_dp: Support DRM_FORMAT_XRGB8888" which enables the X11 default
   24bpp to work, no need to set Xorg config to 16bpp
 * "drm: zynqmp: Make the video plane primary" which also fixes the X11 default
   24bpp to work, no need to set Xorg config to 16bpp

All of these fix HDMI graphics output on AMD KV260 board with yocto genericarm64 machine
and core-image-sato image which includes Xorg. The graphics rendering is still
very slow but I think that is a different problem.

I guess the last series from Sean Anderson is moving forward so I'll
reply to that thread separately.

Tested-by: Mikko Rapeli <mikko.rapeli at linaro.org>

Cheers,
-Mikko


From krzk at kernel.org  Mon Dec 22 01:09:08 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 22 Dec 2025 10:09:08 +0100
Subject: [PATCH] dt-bindings: mailbox: xlnx,zynqmp-ipi-mailbox: Document
 msg region requirement
In-Reply-To: <20251222044653.1757886-1-harini.t@amd.com>
References: <20251222044653.1757886-1-harini.t@amd.com>
Message-ID: <20251222-funny-aspiring-seal-05c4ae@quoll>

On Mon, Dec 22, 2025 at 10:16:53AM +0530, Harini T wrote:
> Add description clarifying that for Versal IPI mailboxes, both host and
> remote agents must have the "msg" register region defined for successful
> message passing. Without both, only notification-based communication
> works.
> 
> Signed-off-by: Harini T <harini.t at amd.com>
> ---
>  .../bindings/mailbox/xlnx,zynqmp-ipi-mailbox.yaml           | 6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-mailbox.yaml b/Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-mailbox.yaml
> index 04d6473d666f..8fdf77c7935c 100644
> --- a/Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-mailbox.yaml
> +++ b/Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-mailbox.yaml
> @@ -165,6 +165,12 @@ allOf:
>          reg-names: false
>  
>      else:
> +      description:

Else block cannot have description.

> +        For Versal IPI mailboxes, the "msg" register region is optional.

So it is optional...

> +        However, for successful message passing via mailbox, both the host IPI

And it is not optional. If nothing works, then it is not optional.

And why would it be optional in the first place? You generate your same
IP with different settings?

Best regards,
Krzysztof



From geert+renesas at glider.be  Mon Dec 22 01:14:27 2025
From: geert+renesas at glider.be (Geert Uytterhoeven)
Date: Mon, 22 Dec 2025 10:14:27 +0100
Subject: [PATCH] ARM: shmobile: defconfig: Refresh for v6.19-rc1
Message-ID: <2dc339bee5bee0a425e2b00bbb784b0ec21a0a33.1766394793.git.geert+renesas@glider.be>

Refresh the defconfig for Renesas ARM systems:
  - Enable Renesas RZ/N1 ADC support,
  - Drop CONFIG_RPCSEC_GSS_KRB5=n (no longer auto-enabled since now
    commit 324be6dcbf09133a ('Revert "SUNRPC: Make RPCSEC_GSS_KRB5
    select CRYPTO instead of depending on it"')).

Signed-off-by: Geert Uytterhoeven <geert+renesas at glider.be>
---
To be queued in renesas-devel for v6.20.
---
 arch/arm/configs/shmobile_defconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/configs/shmobile_defconfig b/arch/arm/configs/shmobile_defconfig
index 0085921833c3e832..ef487eab17cc70aa 100644
--- a/arch/arm/configs/shmobile_defconfig
+++ b/arch/arm/configs/shmobile_defconfig
@@ -202,6 +202,7 @@ CONFIG_RZ_DMAC=y
 CONFIG_ARM_GT_INITIAL_PRESCALER_VAL=1
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_IIO=y
+CONFIG_RZN1_ADC=y
 CONFIG_AK8975=y
 CONFIG_PWM=y
 CONFIG_PWM_RENESAS_RCAR=y
@@ -218,7 +219,6 @@ CONFIG_NFS_V3_ACL=y
 CONFIG_NFS_V4=y
 CONFIG_NFS_V4_1=y
 CONFIG_ROOT_NFS=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_DMA_CMA=y
-- 
2.43.0



From Ankit.Soni at amd.com  Mon Dec 22 01:16:55 2025
From: Ankit.Soni at amd.com (Ankit Soni)
Date: Mon, 22 Dec 2025 09:16:55 +0000
Subject: [PATCH v3 38/62] KVM: SVM: Take and hold ir_list_lock across
 IRTE updates in IOMMU
In-Reply-To: <20250611224604.313496-40-seanjc@google.com>
References: <20250611224604.313496-2-seanjc@google.com>
 <20250611224604.313496-40-seanjc@google.com>
Message-ID: <njhjud3e6wbdftzr3ziyuh5bhyvc5ndt5qvmg7rlvh5isoop2l@f2uxctws2c7d>

On Wed, Jun 11, 2025 at 03:45:41PM -0700, Sean Christopherson wrote:
> Now that svm_ir_list_add() isn't overloaded with all manner of weird
> things, fold it into avic_pi_update_irte(), and more importantly take
> ir_list_lock across the irq_set_vcpu_affinity() calls to ensure the info
> that's shoved into the IRTE is fresh.  While preemption (and IRQs) is
> disabled on the task performing the IRTE update, thanks to irqfds.lock,
> that task doesn't hold the vCPU's mutex, i.e. preemption being disabled
> is irrelevant.
> 
> Signed-off-by: Sean Christopherson <seanjc at google.com>
> ---
>  arch/x86/kvm/svm/avic.c | 55 +++++++++++++++++------------------------
>  1 file changed, 22 insertions(+), 33 deletions(-)
> 
> diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c
> index f1e9f0dd43e8..4747fb09aca4 100644
> --- a/arch/x86/kvm/svm/avic.c
> +++ b/arch/x86/kvm/svm/avic.c
>  
>  int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
>  			unsigned int host_irq, uint32_t guest_irq,
>  			struct kvm_vcpu *vcpu, u32 vector)
> @@ -823,8 +797,18 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
>  			.vapic_addr = avic_get_backing_page_address(to_svm(vcpu)),
>  			.vector = vector,
>  		};
> +		struct vcpu_svm *svm = to_svm(vcpu);
> +		u64 entry;
>  		int ret;
>  
> +		/*
> +		 * Prevent the vCPU from being scheduled out or migrated until
> +		 * the IRTE is updated and its metadata has been added to the
> +		 * list of IRQs being posted to the vCPU, to ensure the IRTE
> +		 * isn't programmed with stale pCPU/IsRunning information.
> +		 */
> +		guard(spinlock_irqsave)(&svm->ir_list_lock);
> +

Hi,

I?m seeing a lockdep warning about a possible circular locking dependency
involving svm->ir_list_lock and irq_desc_lock when using AMD SVM with AVIC
enabled and a VFIO passthrough device, on 6.19-rc2.

Environment
===========

  - Kernel: 6.19.0-rc2
  - QEMU: 10.1.94
  - CPU: AMD EPYC 9965
  - Modules involved: kvm_amd, kvm, vfio_pci, vfio, irqbypass, mlx5_core
  - Workload: QEMU guest with an mlx5 PCI device passed through.

Lockdep warning
===============

The warning is:

  ======================================================
  WARNING: possible circular locking dependency detected
  6.19.0-rc2 #20 Tainted: G            E
  ------------------------------------------------------
  CPU 58/KVM/28597 is trying to acquire lock:
    ff12c47d4b1f34c0 (&irq_desc_lock_class){-.-.}-{2:2}, at: __irq_get_desc_lock+0x58/0xa0

    but task is already holding lock:
    ff12c49b28552110 (&svm->ir_list_lock){....}-{2:2}, at: avic_pi_update_irte+0x147/0x270 [kvm_amd]

    which lock already depends on the new lock.

  the existing dependency chain (in reverse order) is:

    -> #3 (&svm->ir_list_lock){....}-{2:2}:
         _raw_spin_lock_irqsave+0x4e/0xb0
         __avic_vcpu_put+0x7a/0x150 [kvm_amd]
         avic_vcpu_put+0x50/0x70 [kvm_amd]
         svm_vcpu_put+0x38/0x70 [kvm_amd]
         kvm_arch_vcpu_put+0x21b/0x330 [kvm]
         kvm_sched_out+0x62/0x90 [kvm]
         __schedule+0x8d3/0x1d10
         __cond_resched+0x5c/0x80
         __mutex_lock+0x83/0x10b0
         mutex_lock_nested+0x1b/0x30
         kvm_hv_set_msr_common+0x199/0x12a0 [kvm]
         kvm_set_msr_common+0x468/0x1310 [kvm]
         svm_set_msr+0x645/0x730 [kvm_amd]
         __kvm_set_msr+0xa3/0x2f0 [kvm]
         kvm_set_msr_ignored_check+0x23/0x1b0 [kvm]
         do_set_msr+0x76/0xd0 [kvm]
         msr_io+0xbe/0x1c0 [kvm]
         kvm_arch_vcpu_ioctl+0x700/0x2090 [kvm]
         kvm_vcpu_ioctl+0x632/0xc60 [kvm]
         __x64_sys_ioctl+0xa5/0x100
         x64_sys_call+0x1243/0x26b0
         do_syscall_64+0x93/0x1470
         entry_SYSCALL_64_after_hwframe+0x76/0x7e

    -> #2 (&rq->__lock){-.-.}-{2:2}:
         _raw_spin_lock_nested+0x32/0x80
         raw_spin_rq_lock_nested+0x22/0xa0
         task_rq_lock+0x5f/0x150
         cgroup_move_task+0x46/0x110
         css_set_move_task+0xe1/0x240
         cgroup_post_fork+0x98/0x2d0
         copy_process+0x1ea8/0x2330
         kernel_clone+0xa7/0x440
         user_mode_thread+0x63/0x90
         rest_init+0x28/0x200
         start_kernel+0xae0/0xcd0
         x86_64_start_reservations+0x18/0x30
         x86_64_start_kernel+0xfd/0x150
         common_startup_64+0x13e/0x141

    -> #1 (&p->pi_lock){-.-.}-{2:2}:
         _raw_spin_lock_irqsave+0x4e/0xb0
         try_to_wake_up+0x59/0xaa0
         wake_up_process+0x15/0x30
         irq_do_set_affinity+0x145/0x270
         irq_set_affinity_locked+0x172/0x250
         irq_set_affinity+0x47/0x80
         write_irq_affinity.isra.0+0xfe/0x120
         irq_affinity_proc_write+0x1d/0x30
         proc_reg_write+0x69/0xa0
         vfs_write+0x110/0x560
         ksys_write+0x77/0x100
         __x64_sys_write+0x19/0x30
         x64_sys_call+0x79/0x26b0
         do_syscall_64+0x93/0x1470
         entry_SYSCALL_64_after_hwframe+0x76/0x7e

    -> #0 (&irq_desc_lock_class){-.-.}-{2:2}:
         __lock_acquire+0x1595/0x2640
         lock_acquire+0xc4/0x2c0
         _raw_spin_lock_irqsave+0x4e/0xb0
         __irq_get_desc_lock+0x58/0xa0
         irq_set_vcpu_affinity+0x4a/0x100
         avic_pi_update_irte+0x170/0x270 [kvm_amd]
         kvm_pi_update_irte+0xea/0x220 [kvm]
         kvm_arch_irq_bypass_add_producer+0x9b/0xb0 [kvm]
         __connect+0x5f/0x100 [irqbypass]
         irq_bypass_register_producer+0xe4/0xb90 [irqbypass]
         vfio_msi_set_vector_signal+0x1b0/0x330 [vfio_pci_core]
         vfio_msi_set_block+0x5a/0xd0 [vfio_pci_core]
         vfio_pci_set_msi_trigger+0x19e/0x260 [vfio_pci_core]
         vfio_pci_set_irqs_ioctl+0x46/0x140 [vfio_pci_core]
         vfio_pci_core_ioctl+0x6ea/0xc20 [vfio_pci_core]
         vfio_device_fops_unl_ioctl+0xb1/0x9d0 [vfio]
         __x64_sys_ioctl+0xa5/0x100
         x64_sys_call+0x1243/0x26b0
         do_syscall_64+0x93/0x1470
         entry_SYSCALL_64_after_hwframe+0x76/0x7e

  Chain exists of:
    &irq_desc_lock_class --> &rq->__lock --> &svm->ir_list_lock

  Possible unsafe locking scenario:

        CPU0                            CPU1
        ----                            ----
   lock(&svm->ir_list_lock);
                                      lock(&rq->__lock);
                                      lock(&svm->ir_list_lock);
   lock(&irq_desc_lock_class);

        *** DEADLOCK ***

At the point of the warning, the following locks are held:

  #0: &vdev->igate           (vfio_pci_core)
  #1: lock#10                (irqbypass)
  #2: &kvm->irqfds.lock      (kvm)
  #3: &svm->ir_list_lock     (kvm_amd)

and the stack backtrace has:

  __irq_get_desc_lock
  irq_set_vcpu_affinity
  avic_pi_update_irte               [kvm_amd]
  kvm_pi_update_irte                [kvm]
  kvm_arch_irq_bypass_add_producer  [kvm]
  __connect                         [irqbypass]
  irq_bypass_register_producer      [irqbypass]
  vfio_msi_set_vector_signal        [vfio_pci_core]
  vfio_pci_set_irqs_ioctl           [vfio_pci_core]
  vfio_pci_core_ioctl               [vfio_pci_core]
  vfio_device_fops_unl_ioctl        [vfio]
  __x64_sys_ioctl
  x64_sys_call
  do_syscall_64
  entry_SYSCALL_64_after_hwframe

So lockdep sees:

  &irq_desc_lock_class -> &rq->__lock -> &svm->ir_list_lock

while avic_pi_update_irte() currently holds svm->ir_list_lock and then
takes irq_desc_lock via irq_set_vcpu_affinity(), which creates the
potential inversion.

Reproduction
============

Host:

  - AMD EPYC + AVIC enabled
  - Kernel 6.19-rc2 with lockdep
  - VFIO passthrough of an mlx5 device (mlx5_core loaded)

Launch command with Passthrough device, with AVIC mode.

The warning triggers when enabling MSI/MSI-X for the passthrough device
from the guest, i.e. via VFIO ioctl on the host that goes through
irq_bypass and eventually calls avic_pi_update_irte().

I can reproduce this reliably when starting the guest with the VFIO
device assigned after every host reboot.

Questions
=========

  - Is this lockdep warning expected/benign in this code path, or does it
    indicate a real potential deadlock between svm->ir_list_lock and
    irq_desc_lock with AVIC + irq_bypass + VFIO?

  - If this is considered a real issue, is the expected direction to:
      * change the locking around avic_pi_update_irte()/svm->ir_list_lock, or
      * adjust how irq_bypass / VFIO interacts with vCPU affinity updates
        on AMD/AVIC, or
      * annotate the locking somehow if lockdep is over-reporting here?

I?m happy to:

  - Provide my full .config
  - Share the exact QEMU command line
  - Test any proposed patches or instrumentation

Thanks,
Ankit Soni
Ankit.Soni at amd.com

> -- 
> 2.50.0.rc1.591.g9c95f17f64-goog
> 


From richard.genoud at bootlin.com  Mon Dec 22 01:17:07 2025
From: richard.genoud at bootlin.com (Richard GENOUD)
Date: Mon, 22 Dec 2025 10:17:07 +0100
Subject: [PATCH v2 0/4] Introduce Allwinner H616 PWM controller
In-Reply-To: <6113404.MhkbZ0Pkbq@jernej-laptop>
References: <20251217082504.80226-1-richard.genoud@bootlin.com>
 <6113404.MhkbZ0Pkbq@jernej-laptop>
Message-ID: <160e221e-98a8-4097-8340-94ac7d208136@bootlin.com>

Hi Jernej,

Le 21/12/2025 ? 20:12, Jernej ?krabec a ?crit?:
> Dne sreda, 17. december 2025 ob 09:25:00 Srednjeevropski standardni ?as je Richard Genoud napisal(a):
>> Allwinner H616 PWM controller is quite different from the A10 one.
>>
>> It can drive 6 PWM channels, and like for the A10, each channel has a
>> bypass that permits to output a clock, bypassing the PWM logic, when
>> enabled.
>>
>> But, the channels are paired 2 by 2, sharing a first set of
>> MUX/prescaler/gate.
>> Then, for each channel, there's another prescaler (that will be bypassed
>> if the bypass is enabled for this channel).
>>
>> It looks like that:
>>              _____      ______      ________
>> OSC24M --->|     |    |      |    |        |
>> APB1 ----->| Mux |--->| Gate |--->| /div_m |-----> PWM_clock_src_xy
>>             |_____|    |______|    |________|
>>                            ________
>>                           |        |
>>                        +->| /div_k |---> PWM_clock_x
>>                        |  |________|
>>                        |    ______
>>                        |   |      |
>>                        +-->| Gate |----> PWM_bypass_clock_x
>>                        |   |______|
>> PWM_clock_src_xy -----+   ________
>>                        |  |        |
>>                        +->| /div_k |---> PWM_clock_y
>>                        |  |________|
>>                        |    ______
>>                        |   |      |
>>                        +-->| Gate |----> PWM_bypass_clock_y
>>                            |______|
>>
>> Where xy can be 0/1, 2/3, 4/5
>>
>> PWM_clock_x/y serve for the PWM purpose.
>> PWM_bypass_clock_x/y serve for the clock-provider purpose.
>> The common clock framework has been used to manage those clocks.
>>
>> This PWM driver serves as a clock-provider for PWM_bypass_clocks.
>> This is needed for example by the embedded AC300 PHY which clock comes
>> from PMW5 pin (PB12).
> 
> No. Drop all clocks related code and make this pure PWM driver, like pwm-sun4i
> is. For AC300, AC200 or whatever other device may need clock produced by PWM,
> pwm-clock can be used like this:
> 
> ac300_pwm_clk: ac300-clk {
> 	compatible = "pwm-clock";
> 	#clock-cells = <0>;
> 	clock-frequency = <24000000>;
> 	pinctrl-names = "default";
> 	pinctrl-0 = <&pwm1_pin>;
> 	pwms = <&pwm 1 42 0>;
> };
> 
> ac300 {
> 	...
> 	clocks = <&ac300_pwm_clk>;
> 	...
> };
Yes, that was my first move, but after trying quite hard, I came to the 
conclusion that pwm-clock is not fit for this precise case.
If we had only one source clock, this would be a perfect fit though.

Here's the problem: the pwm-clock request a period from the PWM driver, 
without any clue that it actually wants a clock at a specific frequency, 
and not a PWM signal with duty cycle capability.
So, the PWM driver doesn't know if it can use the bypass or not, it 
doesn't even have the real accurate frequency information (23809524 Hz 
instead of 24MHz) because the pwm_apply only deals with periods.
With pwm-clock, we loose a precious information along the way (that we 
actually want a clock and not a PWM signal).
That's ok with simple PWM drivers that don't have multiple input clocks, 
but in this case, without this information, we can't know for sure which 
clock to use.
And here, for instance, if pwm-clock requests 42ns, the logic is to 
select the highest clock (100MHz), with no prescaler, and a duty cycle 
value of 2/4 => we have 25MHz instead of 24MHz.
And that's a perfectly fine choice for a PMW, because we still can 
change the duty cycle in the range [0-4]/4.
But obviously for a clock, we don't care about the duty cycle, but more 
about the clock accuracy.
When I tried to use pwm-clock, I ended up making assumptions on what was 
the intended use (if the asked period is 42 with a duty cycle of 50% 
maybe the consumer wants a clock), but that was too hack-ish.

That's why I put aside the pwm-clock and I went for this instead.


Thanks for the review!

Regards,
Richard

> 
> Best regards,
> Jernej
> 
>>
>> This series is based onto v6.19-rc1
>>
>> Changes since v1:
>> - rebase onto v6.19-rc1
>> - add missing headers
>> - remove MODULE_ALIAS (suggested by Krzysztof)
>> - use sun4i-pwm binding instead of creating a new one (suggested by Krzysztof)
>> - retrieve the parent clocks from the devicetree
>> - switch num_parents to unsigned int
>>
>> Richard Genoud (4):
>>    dt-bindings: pwm: allwinner: add h616 pwm compatible
>>    pwm: sun50i: Add H616 PWM support
>>    arm64: dts: allwinner: h616: add PWM controller
>>    MAINTAINERS: Add entry on Allwinner H616 PWM driver
>>
>>   .../bindings/pwm/allwinner,sun4i-a10-pwm.yaml |  19 +-
>>   MAINTAINERS                                   |   5 +
>>   .../arm64/boot/dts/allwinner/sun50i-h616.dtsi |  47 +
>>   drivers/pwm/Kconfig                           |  12 +
>>   drivers/pwm/Makefile                          |   1 +
>>   drivers/pwm/pwm-sun50i-h616.c                 | 892 ++++++++++++++++++
>>   6 files changed, 975 insertions(+), 1 deletion(-)
>>   create mode 100644 drivers/pwm/pwm-sun50i-h616.c
>>
>>
>> base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
>>
> 
> 
> 
> 


-- 
Richard Genoud, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From jie.gan at oss.qualcomm.com  Mon Dec 22 01:17:48 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Mon, 22 Dec 2025 17:17:48 +0800
Subject: [PATCH v8 5/8] dt-bindings: arm: add an interrupt property for
 Coresight CTCU
In-Reply-To: <097dbefb-f679-40da-bce4-d6e09dc4cf08@oss.qualcomm.com>
References: <20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191@oss.qualcomm.com>
 <20251211-enable-byte-cntr-for-ctcu-v8-5-3e12ff313191@oss.qualcomm.com>
 <20251211133723.GA859302-robh@kernel.org>
 <dfa43a63-ca14-4dd7-a7ab-acd95748a8b9@oss.qualcomm.com>
 <a9537dc9-c767-4909-8b1c-6e939ce4f3fc@kernel.org>
 <2db74a3e-4aeb-4e87-9fe8-5c9693bfb67c@arm.com>
 <46afd4f6-f287-4d19-bc68-f2f6eac36e6a@oss.qualcomm.com>
 <95ac571a-1c8f-45d9-9874-648d4123ce18@arm.com>
 <097dbefb-f679-40da-bce4-d6e09dc4cf08@oss.qualcomm.com>
Message-ID: <01072c94-3a13-459c-baba-0cc2f3611ff9@oss.qualcomm.com>



On 12/22/2025 2:58 PM, Jie Gan wrote:
> 
> 
> On 12/19/2025 5:54 PM, Suzuki K Poulose wrote:
>> On 19/12/2025 02:05, Jie Gan wrote:
>>>
>>>
>>> On 12/19/2025 7:19 AM, Suzuki K Poulose wrote:
>>>> On 18/12/2025 10:17, Krzysztof Kozlowski wrote:
>>>>> On 12/12/2025 02:12, Jie Gan wrote:
>>>>>>
>>>>>>
>>>>>> On 12/11/2025 9:37 PM, Rob Herring wrote:
>>>>>>> On Thu, Dec 11, 2025 at 02:10:44PM +0800, Jie Gan wrote:
>>>>>>>> Add an interrupt property to CTCU device. The interrupt will be 
>>>>>>>> triggered
>>>>>>>> when the data size in the ETR buffer exceeds the threshold of the
>>>>>>>> BYTECNTRVAL register. Programming a threshold in the BYTECNTRVAL 
>>>>>>>> register
>>>>>>>> of CTCU device will enable the interrupt.
>>>>>>>>
>>>>>>>> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
>>>>>>>> Reviewed-by: Mike Leach <mike.leach at linaro.org>
>>>>>>>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>>>>>>>> ---
>>>>>>>> ?? .../devicetree/bindings/arm/qcom,coresight-ctcu.yaml??? | 17 
>>>>>>>> + + + ++++++++++++++
>>>>>>>> ?? 1 file changed, 17 insertions(+)
>>>>>>>>
>>>>>>>> diff --git a/Documentation/devicetree/bindings/arm/ 
>>>>>>>> qcom,coresight- ctcu.yaml b/Documentation/devicetree/bindings/ 
>>>>>>>> arm/qcom,coresight- ctcu.yaml
>>>>>>>> index c969c16c21ef..90f88cc6cd3e 100644
>>>>>>>> --- a/Documentation/devicetree/bindings/arm/qcom,coresight- 
>>>>>>>> ctcu.yaml
>>>>>>>> +++ b/Documentation/devicetree/bindings/arm/qcom,coresight- 
>>>>>>>> ctcu.yaml
>>>>>>>> @@ -39,6 +39,16 @@ properties:
>>>>>>>> ?????? items:
>>>>>>>> ???????? - const: apb
>>>>>>>> +? interrupts:
>>>>>>>> +??? items:
>>>>>>>> +????? - description: Byte cntr interrupt for the first etr device
>>>>>>>> +????? - description: Byte cntr interrupt for the second etr device
>>>>
>>>> This is really vague. How do you define first vs second ? Probe order ?
>>>> No way. This must be the "port" number to which the ETR is connected
>>>> to the CTCU. IIUC, there is a config area for each ETR (e.g., trace id
>>>> filter) connected to the CTCU. I was under the assumption that they
>>>> are identified as "ports" (input ports). I don't really understand how
>>>> this interrupt mapping works now. Please explain it clearly.
>>>>
>>>
>>> Sorry for the misunderstanding.
>>>
>>> Each ETR device should have its own interrupt line and an IRQ 
>>> register within the CTCU device, as defined by the specification. In 
>>> existing projects, the maximum supported number of ETR devices is 2.
>>>
>>> Each interrupt is directly mapped to a specific ETR device, for example:
>>> tmc at 1000 ? interrupt line 0
>>> tmc at 1001 ? interrupt line 1
>>>
>>> The suggestion to identify devices by ?ports? is much clearer than my 
>>> previous explanation, as it explicitly shows which device is 
>>> connected to which port.
>>
>> Thanks for confirming.
>>
>>>
>>>>>>>> +
>>>>>>>> +? interrupt-names:
>>>>>>>> +??? items:
>>>>>>>> +????? - const: etrirq0
>>>>>>>> +????? - const: etrirq1
>>>>>>>
>>>>>>> Names are kind of pointless when it is just foo<index>.
>>>>>>
>>>>>> Hi Rob,
>>>>>>
>>>>>> I was naming them as etr0/etr1. Are these names acceptable?
>>>>>
>>>>> Obviously irq is redundant, but how does etr0 solves the problem of
>>>>> calling it foo0?
>>>>>
>>>>> I don't think you really read Rob's comment.
>>>>>
>>>>>> The interrupts are assigned exclusively to a specific ETR device.
>>>>>>
>>>>>> But Suzuki is concerned that this might cause confusion because 
>>>>>> the ETR
>>>>>> device is named randomly in the driver. Suzuki suggested using 
>>>>>> ?port-0?
>>>>>> and ?port-1? and would also like to hear your feedback on these 
>>>>>> names.
>>>>>
>>>>> There is no confusion here. Writing bindings luckily clarifies this 
>>>>> what
>>>>> the indices in the array mean.
>>>>
>>>> The point is there are "n" interrupts. Question is, could there be more
>>>> devices(ETRs) connected to the CTCU than "n".
>>>>
>>>> e.g., Lets CTCU can control upto 4 ETRs and on a particular system, the
>>>>
>>>> TMC-ETR0 -> CTCU-Port0
>>>>
>>>> TMC-ETR1 -> CTCU-Port2
>>>> TMC-ETR2 -> CTCU-Port3
>>>>
>>>> Now, how many interrupts are described in the DT ? How do we map which
>>>> interrupts correspond to the CTCU-Portn. (Finding the TMC-ETRx back
>>>> from the port is possible, with the topology).
>>>>
>>>
>>> Got your point and it's much clearer.
>>>
>>>> This is what I raised in the previous version. Again, happy to hear
>>>> if there is a standard way to describe the interrupts.
>>>>
>>>> Suzuki
>>>>
>>>>
>>>>>
>>>>>>
>>>>>> Usually, the probe sequence follows the order of the addresses. In 
>>>>>> our
>>>>>> specification, ?ETR0? is always probed before ?ETR1? because its 
>>>>>> address
>>>>>> is lower.
>>>>>
>>>>> How is this even relevant? You are answering to something completely
>>>>> different, so I don't think you really tried to understand review.
>>>>>
>>>
>>> My previous explanation was definitely unclear. As Suzuki suggested, 
>>> mapping the interrupt to the port number (to identify the relevant 
>>> device based on topology) makes sense and provides a much easier way 
>>> to understand the relationship between the interrupt and the ETR device.
>>>
>>> So with the suggestion, here is the new description about the 
>>> interrupts:
>>>
>>> ?? interrupts:
>>> ???? items:
>>> ?????? - description: Interrupt for the ETR device connected to in- 
>>> port0.
>>> ?????? - description: Interrupt for the ETR device connected to in- 
>>> port1.
>>>
>>> ??interrupt-names:
>>> ???? items:
>>> ????? - const: port0
>>> ????? - const: port1
>>
>> Which brings us back to the question I posted in the previous version. 
>> Do we really need a "name" or are there other ways to define, a sparse
>> list of interrupts ?
>>
> 
> Each interrupt is dedicated to a specific ETR device. While we can 
> retrieve the list of interrupts using of_irq_get, we cannot guarantee 
> that the obtained interrupt corresponds to the correct ETR device?
> I believe it would be better to have an interrupt-name property, so we 
> can assign the name in the data structure and retrieve the interrupt by 
> its name, ensuring it maps to the correct ETR device.

I have tried to get the interrupt with of_irq_get(nd, port_number).

If we define the interrupts in the correct sequence aligned with the 
port numbers, we can then retrieve each interrupt by its corresponding 
port number.

Is that ok to drop the interrupt-name with the solution?

Thanks,
Jie

> 
> Thanks,
> Jie
> 
> 
> 



From leo.yan at arm.com  Mon Dec 22 01:22:15 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 22 Dec 2025 09:22:15 +0000
Subject: [PATCH 0/2] arm64: Support NVIDIA Olympus for Perf Arm SPE
In-Reply-To: <20251219231325.2742580-1-bwicaksono@nvidia.com>
References: <20251219231325.2742580-1-bwicaksono@nvidia.com>
Message-ID: <20251222092215.GE9788@e132581.arm.com>

On Fri, Dec 19, 2025 at 11:13:23PM +0000, Besar Wicaksono wrote:
> This series support NVIDIA Olympus CPU in Perf Arm SPE.
> The first patch syncs the kernel header to the tools header.

Yes, I saw the kernel change has been merged.  For the series:

Reviewed-by: Leo Yan <leo.yan at arm.com>

> The second patch adds NVIDIA Olympus into perf's Neoverse SPE data source list.
> 
> Besar Wicaksono (2):
>   tools headers arm64: Add NVIDIA Olympus part
>   perf arm-spe: Add NVIDIA Olympus to neoverse list
> 
>  tools/arch/arm64/include/asm/cputype.h | 2 ++
>  tools/perf/util/arm-spe.c              | 1 +
>  2 files changed, 3 insertions(+)
> 
> -- 
> 2.43.0
> 


From mikko.rapeli at linaro.org  Mon Dec 22 01:29:39 2025
From: mikko.rapeli at linaro.org (Mikko Rapeli)
Date: Mon, 22 Dec 2025 11:29:39 +0200
Subject: [PATCH 0/3] drm: zynqmp: Make the video plane primary
In-Reply-To: <24a9a9a2-ba7c-4619-96dc-4355d850561b@linux.dev>
References: <20251113203715.2768107-1-sean.anderson@linux.dev>
 <36048dd7-796f-495d-b715-d8f65a7c2f98@suse.de>
 <24a9a9a2-ba7c-4619-96dc-4355d850561b@linux.dev>
Message-ID: <aUkPg_VUxp0KrpWE@nuoska>

Hi,

On Fri, Nov 14, 2025 at 10:35:10AM -0500, Sean Anderson wrote:
> On 11/14/25 02:42, Thomas Zimmermann wrote:
> > Am 13.11.25 um 21:37 schrieb Sean Anderson:
> >> The graphics plane does not support XRGB8888, which is the default mode
> >> X uses for 24-bit color. Because of this, X must be set to use 16-bit
> >> color, which has a measurable performance penalty. Make the video plane
> >> the primary plane as it natively supports XRGB8888. An alternative
> >> approach to add XRGB8888 to the graphics plane is discussed in [1], as
> >> well as in patch 2.
> > 
> > Did you try to set drm_device.mode_config.preferred_depth = 16, like at [1]?? IIRC user space looks at this value to auto-detect the color format.
> 
> I have not tried that. But I would rather use 24-bit color for the performance boost.

I have tested preferred_depth = 16 and it works. Proposed in
https://lists.freedesktop.org/archives/dri-devel/2025-December/540189.html
but I'm also fine with 24/32 bpp, or any default which draws pixels to HDMI
on AMD KV260 and X11 without manually changing the config.

This full series also works for me on AMD KV260 running Yocto genericarm64
machine config and core-image-sato image with Xorg.

Cheers,

-Mikko


From andrew at lunn.ch  Mon Dec 22 01:30:44 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Mon, 22 Dec 2025 10:30:44 +0100
Subject: [PATCH 2/2] ARM: dts: aspeed: ventura2: Add Meta ventura2 BMC
In-Reply-To: <20251222-ventura2_initial_dts-v1-2-1f06166c78a3@gmail.com>
References: <20251222-ventura2_initial_dts-v1-0-1f06166c78a3@gmail.com>
 <20251222-ventura2_initial_dts-v1-2-1f06166c78a3@gmail.com>
Message-ID: <c069b452-df22-4afa-bf6a-c48949f40ebc@lunn.ch>

> +&mdio0 {
> +	status = "okay";
> +};
> +
> +&mac2 {
> +	status = "okay";
> +	phy-mode = "rmii";
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_rmii3_default>;
> +	fixed-link {
> +		speed = <100>;
> +		full-duplex;
> +	};
> +};

That is an odd combination. You enable the MDIO bus, but don't have
any PHYs on it, no phandles pointing to it. And you have this
fixed-link. It makes me think you have an Ethernet switch on the bus,
and this connects to it?

    Andrew


From peter.griffin at linaro.org  Mon Dec 22 01:39:44 2025
From: peter.griffin at linaro.org (Peter Griffin)
Date: Mon, 22 Dec 2025 09:39:44 +0000
Subject: [PATCH v6 1/4] dt-bindings: clock: google,gs101-clock: add
 samsung,sysreg property as required
In-Reply-To: <215eb434-683f-4cf2-9bcd-0860991ae23e@kernel.org>
References: <20251220-automatic-clocks-v6-0-36c2f276a135@linaro.org>
 <20251220-automatic-clocks-v6-1-36c2f276a135@linaro.org> <215eb434-683f-4cf2-9bcd-0860991ae23e@kernel.org>
Message-ID: <CADrjBPoWcONhJJdCeovkwQ9Oha+t+dpHY_ohKPV7BQS1tougGw@mail.gmail.com>

Hi Krzysztof,

On Sun, 21 Dec 2025 at 13:26, Krzysztof Kozlowski <krzk at kernel.org> wrote:
>
> On 20/12/2025 10:05, Peter Griffin wrote:
> > Each CMU (with the exception of cmu_top) has a corresponding sysreg bank
> > that contains the BUSCOMPONENT_DRCG_EN and optional MEMCLK registers.
> > The BUSCOMPONENT_DRCG_EN register enables dynamic root clock gating of
> > bus components and MEMCLK gates the sram clock.
> >
> > Now the clock driver supports automatic clock mode, to fully enable dynamic
> > root clock gating it is required to configure these registers. Update the
> > bindings documentation so that all CMUs (with the exception of
> > gs101-cmu-top) have samsung,sysreg as a required property.
> >
> > Note this is NOT an ABI break, as if the property isn't specified the
> > clock driver will fallback to the current behaviour of not initializing
> > the registers. The system still boots, but bus components won't benefit
> > from dynamic root clock gating and dynamic power will be higher (which has
> > been the case until now anyway).
> >
> > Additionally update the DT example to included the correct CMU size as
> > registers in that region are used for automatic clock mode.
> >
> > Signed-off-by: Peter Griffin <peter.griffin at linaro.org>
> > ---
> > Changes in v5:
> > - Invert the test for google,gs101-cmu-top (Andre)
> >
>
>
> <form letter>
> This is a friendly reminder during the review process.
>
> It looks like you received a tag and forgot to add it.
>
> If you do not know the process, here is a short explanation:
> Please add Acked-by/Reviewed-by/Tested-by tags when posting new versions
> of patchset, under or above your Signed-off-by tag, unless patch changed
> significantly (e.g. new properties added to the DT bindings). Tag is
> "received", when provided in a message replied to you on the mailing
> list. Tools like b4 can help here. However, there's no need to repost
> patches *only* to add the tags. The upstream maintainer will do that for
> tags received on the version they apply.
>
> Please read:
> https://elixir.bootlin.com/linux/v6.12-rc3/source/Documentation/process/submitting-patches.rst#L577
>
> If a tag was not added on purpose, please state why and what changed.
> </form letter>

Apologies, your tag should have been added.... got kind of sidetracked
bisecting the linux-next regression with the serial console and then
forgot to apply it.

Peter.


From mikko.rapeli at linaro.org  Mon Dec 22 01:42:10 2025
From: mikko.rapeli at linaro.org (Mikko Rapeli)
Date: Mon, 22 Dec 2025 11:42:10 +0200
Subject: [PATCH 0/3] drm: zynqmp: Make the video plane primary
In-Reply-To: <20251113203715.2768107-1-sean.anderson@linux.dev>
References: <20251113203715.2768107-1-sean.anderson@linux.dev>
Message-ID: <aUkSclVzlRCXDdug@nuoska>

Hi,

On Thu, Nov 13, 2025 at 03:37:11PM -0500, Sean Anderson wrote:
> The graphics plane does not support XRGB8888, which is the default mode
> X uses for 24-bit color. Because of this, X must be set to use 16-bit
> color, which has a measurable performance penalty. Make the video plane
> the primary plane as it natively supports XRGB8888. An alternative
> approach to add XRGB8888 to the graphics plane is discussed in [1], as
> well as in patch 2.
> 
> [1] https://lore.kernel.org/dri-devel/20250627145058.6880-1-mike.looijmans at topic.nl/

I've tested this series on AMD KV260 running Yocto genericarm64 machine config and
core-image-sato with Xorg. This series fixes HDMI output using X11, no need to
configure Xorg to 16bpp as workaround.

Tested-by: Mikko Rapeli <mikko.rapeli at linaro.org>

That said, I also tested
https://lore.kernel.org/dri-devel/20250627145058.6880-1-mike.looijmans at topic.nl/
and it works.

And I tested and submitted the patch for zynqmp framebuffer to prefer 16bpp
until different modes are actually support, which fixes Xorg startup and
the depth detection logic used there:

https://lore.kernel.org/dri-devel/20251205123751.2257694-3-mikko.rapeli at linaro.org/

This series and Mike's patches enable 24bpp mode to work, which I guess is the long
term path, but it is not clear to me what is still missing.

The patch from me fixes the current situtation where only 16bpp works but framebuffer
driver does not prefer that and thus userspace X11 uses the default 24bpp
which then fails. My patch could be merged right now until the XRGB8888 support
is finalized.

Cheers,

-Mikko


From tianruidong at linux.alibaba.com  Mon Dec 22 01:43:35 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Mon, 22 Dec 2025 17:43:35 +0800
Subject: [PATCH v4 02/17] ras: AEST: Add probe/remove for AEST driver
In-Reply-To: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
References: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
Message-ID: <20251222094351.38792-3-tianruidong@linux.alibaba.com>

Parse register information from the AEST table in the probe function,
create corresponding structures, and mappings AEST record.

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 MAINTAINERS                  |   2 +
 drivers/ras/Kconfig          |   1 +
 drivers/ras/Makefile         |   1 +
 drivers/ras/aest/Kconfig     |  17 +++
 drivers/ras/aest/Makefile    |   5 +
 drivers/ras/aest/aest-core.c | 217 +++++++++++++++++++++++++++++++++++
 drivers/ras/aest/aest.h      | 124 ++++++++++++++++++++
 include/linux/acpi_aest.h    |   9 ++
 8 files changed, 376 insertions(+)
 create mode 100644 drivers/ras/aest/Kconfig
 create mode 100644 drivers/ras/aest/Makefile
 create mode 100644 drivers/ras/aest/aest-core.c
 create mode 100644 drivers/ras/aest/aest.h

diff --git a/MAINTAINERS b/MAINTAINERS
index d14e16c3a93b..fd4c40c4607c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -346,7 +346,9 @@ M:	Ruidong Tian <tianruidond at linux.alibaba.com>
 L:	linux-acpi at vger.kernel.org
 L:	linux-arm-kernel at lists.infradead.org
 S:	Supported
+F:	arch/arm64/include/asm/ras.h
 F:	drivers/acpi/arm64/aest.c
+F:	drivers/ras/aest/
 F:	include/linux/acpi_aest.h
 
 ACPI FOR RISC-V (ACPI/riscv)
diff --git a/drivers/ras/Kconfig b/drivers/ras/Kconfig
index fc4f4bb94a4c..61a2a05d9c94 100644
--- a/drivers/ras/Kconfig
+++ b/drivers/ras/Kconfig
@@ -33,6 +33,7 @@ if RAS
 
 source "arch/x86/ras/Kconfig"
 source "drivers/ras/amd/atl/Kconfig"
+source "drivers/ras/aest/Kconfig"
 
 config RAS_FMPM
 	tristate "FRU Memory Poison Manager"
diff --git a/drivers/ras/Makefile b/drivers/ras/Makefile
index 11f95d59d397..72411ee9deaf 100644
--- a/drivers/ras/Makefile
+++ b/drivers/ras/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_RAS_CEC)	+= cec.o
 
 obj-$(CONFIG_RAS_FMPM)	+= amd/fmpm.o
 obj-y			+= amd/atl/
+obj-y 			+= aest/
diff --git a/drivers/ras/aest/Kconfig b/drivers/ras/aest/Kconfig
new file mode 100644
index 000000000000..0b09a5d5acce
--- /dev/null
+++ b/drivers/ras/aest/Kconfig
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# ARM Error Source Table Support
+#
+# Copyright (c) 2025, Alibaba Group.
+#
+
+config AEST
+	tristate "ARM AEST Driver"
+	depends on ACPI_AEST && RAS
+
+	help
+	  The Arm Error Source Table (AEST) provides details on ACPI
+	  extensions that enable kernel-first handling of errors in a
+	  system that supports the Armv8 RAS extensions.
+
+	  If set, the kernel will report and log hardware errors.
diff --git a/drivers/ras/aest/Makefile b/drivers/ras/aest/Makefile
new file mode 100644
index 000000000000..a6ba7e36fb43
--- /dev/null
+++ b/drivers/ras/aest/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_AEST) 	+= aest.o
+
+aest-y		:= aest-core.o
diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
new file mode 100644
index 000000000000..c7ef6c13fd44
--- /dev/null
+++ b/drivers/ras/aest/aest-core.c
@@ -0,0 +1,217 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ARM Error Source Table Support
+ *
+ * Copyright (c) 2025, Alibaba Group.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/xarray.h>
+#include <linux/ras.h>
+
+#include "aest.h"
+
+DEFINE_PER_CPU(struct aest_device, percpu_adev);
+
+#undef pr_fmt
+#define pr_fmt(fmt) "AEST: " fmt
+
+static int aest_init_record(struct aest_record *record, int i,
+			    struct aest_node *node)
+{
+	struct device *dev = node->adev->dev;
+
+	record->name = devm_kasprintf(dev, GFP_KERNEL, "record%d", i);
+	if (!record->name)
+		return -ENOMEM;
+
+	if (node->base)
+		record->regs_base =
+			node->base + sizeof(struct ras_ext_regs) * i;
+
+	record->addressing_mode = test_bit(i, node->info->addressing_mode);
+	record->index = i;
+	record->node = node;
+
+	aest_record_dbg(record, "base: %p, index: %d, address mode: %x\n",
+			record->regs_base, record->index,
+			record->addressing_mode);
+	return 0;
+}
+
+static void aest_device_remove(struct platform_device *pdev)
+{
+	platform_set_drvdata(pdev, NULL);
+}
+
+static char *alloc_aest_node_name(struct aest_node *node)
+{
+	char *name;
+
+	switch (node->type) {
+	case ACPI_AEST_PROCESSOR_ERROR_NODE:
+		name = devm_kasprintf(node->adev->dev, GFP_KERNEL, "%s.%d",
+				      aest_node_name[node->type],
+				      node->info->processor->processor_id);
+		break;
+	case ACPI_AEST_MEMORY_ERROR_NODE:
+	case ACPI_AEST_SMMU_ERROR_NODE:
+	case ACPI_AEST_VENDOR_ERROR_NODE:
+	case ACPI_AEST_GIC_ERROR_NODE:
+	case ACPI_AEST_PCIE_ERROR_NODE:
+	case ACPI_AEST_PROXY_ERROR_NODE:
+		name = devm_kasprintf(node->adev->dev, GFP_KERNEL, "%s.%llx",
+				      aest_node_name[node->type],
+				      node->info->interface_hdr->address);
+		break;
+	default:
+		name = devm_kasprintf(node->adev->dev, GFP_KERNEL, "Unknown");
+	}
+
+	return name;
+}
+
+static int aest_node_set_errgsr(struct aest_device *adev,
+				struct aest_node *node)
+{
+	struct acpi_aest_node *anode = node->info;
+	u64 errgsr_base = anode->common->error_group_register_base;
+
+	if (anode->interface_hdr->type != ACPI_AEST_NODE_MEMORY_MAPPED)
+		return 0;
+
+	if (!node->base)
+		return 0;
+
+	if (!(anode->interface_hdr->flags & AEST_XFACE_FLAG_ERROR_GROUP)) {
+		node->errgsr = node->base + ERXGROUP;
+		return 0;
+	}
+
+	if (!errgsr_base)
+		return -EINVAL;
+
+	node->errgsr = devm_ioremap(adev->dev, errgsr_base, PAGE_SIZE);
+	if (!node->errgsr)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int aest_init_node(struct aest_device *adev, struct aest_node *node,
+			  struct acpi_aest_node *anode)
+{
+	int i, ret;
+	u64 address;
+
+	node->adev = adev;
+	node->info = anode;
+	node->type = anode->type;
+	node->name = alloc_aest_node_name(node);
+	if (!node->name)
+		return -ENOMEM;
+	node->record_implemented = anode->record_implemented;
+	node->status_reporting = anode->status_reporting;
+
+	address = anode->interface_hdr->address;
+	if (address) {
+		node->base = devm_ioremap(adev->dev, address, PAGE_SIZE);
+		if (!node->base)
+			return -ENOMEM;
+	}
+
+	ret = aest_node_set_errgsr(adev, node);
+	if (ret)
+		return ret;
+
+	node->record_count = anode->interface_hdr->error_record_count;
+	node->records = devm_kcalloc(adev->dev, node->record_count,
+				     sizeof(struct aest_record), GFP_KERNEL);
+	if (!node->records)
+		return -ENOMEM;
+
+	for (i = 0; i < node->record_count; i++) {
+		ret = aest_init_record(&node->records[i], i, node);
+		if (ret)
+			return ret;
+	}
+	aest_node_dbg(node, "%d records, base: %llx, errgsr: %llx\n",
+		      node->record_count, (u64)node->base, (u64)node->errgsr);
+	return 0;
+}
+
+static int aest_init_nodes(struct aest_device *adev, struct aest_hnode *ahnode)
+{
+	struct acpi_aest_node *anode;
+	struct aest_node *node;
+	int ret, i = 0;
+
+	adev->node_cnt = ahnode->count;
+	adev->nodes = devm_kcalloc(adev->dev, adev->node_cnt,
+				   sizeof(struct aest_node), GFP_KERNEL);
+	if (!adev->nodes)
+		return -ENOMEM;
+
+	list_for_each_entry(anode, &ahnode->list, list) {
+		adev->type = anode->type;
+
+		node = &adev->nodes[i++];
+		ret = aest_init_node(adev, node, anode);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int aest_device_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct aest_device *adev;
+	struct aest_hnode *ahnode;
+
+	ahnode = *((struct aest_hnode **)pdev->dev.platform_data);
+	if (!ahnode)
+		return -ENODEV;
+
+	adev = devm_kzalloc(&pdev->dev, sizeof(*adev), GFP_KERNEL);
+	if (!adev)
+		return -ENOMEM;
+
+	adev->dev = &pdev->dev;
+	adev->id = pdev->id;
+	aest_set_name(adev, ahnode);
+	ret = aest_init_nodes(adev, ahnode);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, adev);
+
+	aest_dev_dbg(adev, "Node cnt: %x, id: %x\n", adev->node_cnt, adev->id);
+
+	return 0;
+}
+
+static struct platform_driver aest_driver = {
+	.driver	= {
+		.name	= "AEST",
+	},
+	.probe	= aest_device_probe,
+	.remove = aest_device_remove,
+};
+
+static int __init aest_init(void)
+{
+	return platform_driver_register(&aest_driver);
+}
+module_init(aest_init);
+
+static void __exit aest_exit(void)
+{
+	platform_driver_unregister(&aest_driver);
+}
+module_exit(aest_exit);
+
+MODULE_DESCRIPTION("ARM AEST Driver");
+MODULE_AUTHOR("Ruidong Tian <tianruidong at linux.alibaba.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ras/aest/aest.h b/drivers/ras/aest/aest.h
new file mode 100644
index 000000000000..d918240c3f57
--- /dev/null
+++ b/drivers/ras/aest/aest.h
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * ARM Error Source Table Support
+ *
+ * Copyright (c) 2025, Alibaba Group.
+ */
+
+#include <linux/acpi_aest.h>
+#include <asm/ras.h>
+
+#define MAX_GSI_PER_NODE 2
+
+#define aest_dev_err(__adev, format, ...) \
+	dev_err((__adev)->dev, format, ##__VA_ARGS__)
+#define aest_dev_info(__adev, format, ...) \
+	dev_info((__adev)->dev, format, ##__VA_ARGS__)
+#define aest_dev_dbg(__adev, format, ...) \
+	dev_dbg((__adev)->dev, format, ##__VA_ARGS__)
+
+#define aest_node_err(__node, format, ...)                          \
+	dev_err((__node)->adev->dev, "%s: " format, (__node)->name, \
+		##__VA_ARGS__)
+#define aest_node_info(__node, format, ...)                          \
+	dev_info((__node)->adev->dev, "%s: " format, (__node)->name, \
+		 ##__VA_ARGS__)
+#define aest_node_dbg(__node, format, ...)                          \
+	dev_dbg((__node)->adev->dev, "%s: " format, (__node)->name, \
+		##__VA_ARGS__)
+
+#define aest_record_err(__record, format, ...)                  \
+	dev_err((__record)->node->adev->dev, "%s: %s: " format, \
+		(__record)->node->name, (__record)->name, ##__VA_ARGS__)
+#define aest_record_info(__record, format, ...)                  \
+	dev_info((__record)->node->adev->dev, "%s: %s: " format, \
+		 (__record)->node->name, (__record)->name, ##__VA_ARGS__)
+#define aest_record_dbg(__record, format, ...)                  \
+	dev_dbg((__record)->node->adev->dev, "%s: %s: " format, \
+		(__record)->node->name, (__record)->name, ##__VA_ARGS__)
+
+#define ERXGROUP 0xE00
+
+struct aest_record {
+	char *name;
+	int index;
+	void __iomem *regs_base;
+
+	/*
+	 * This bit specifies the addressing mode  to populate the ERR_ADDR
+	 * register:
+	 *   0b: Error record reports System Physical Addresses (SPA) in
+	 *       the ERR_ADDR register.
+	 *   1b: Error record reports error node-specific Logical Addresses(LA)
+	 *       in the ERR_ADD register. OS must use other means to translate
+	 *       the reported LA into SPA
+	 */
+	int addressing_mode;
+	struct aest_node *node;
+};
+
+struct aest_node {
+	char *name;
+	u8 type;
+	void *errgsr;
+	void *base;
+
+	/*
+	 * This bitmap indicates which of the error records within this error
+	 * node must be polled for error status.
+	 * Bit[n] of this field pertains to error record corresponding to
+	 * index n in this error group.
+	 * Bit[n] = 0b: Error record at index n needs to be polled.
+	 * Bit[n] = 1b: Error record at index n do not needs to be polled.
+	 */
+	unsigned long *record_implemented;
+	/*
+	 * This bitmap indicates which of the error records within this error
+	 * node support error status reporting using ERRGSR register.
+	 * Bit[n] of this field pertains to error record corresponding to
+	 * index n in this error group.
+	 * Bit[n] = 0b: Error record at index n supports error status reporting
+	 *              through ERRGSR.S.
+	 * Bit[n] = 1b: Error record at index n does not support error reporting
+	 *              through the ERRGSR.S bit If this error record is
+	 *              implemented, then it must be polled explicitly for
+	 *              error events.
+	 */
+	unsigned long *status_reporting;
+
+	struct aest_device *adev;
+	struct acpi_aest_node *info;
+
+	int record_count;
+	struct aest_record *records;
+};
+
+struct aest_device {
+	struct device *dev;
+	u32 type;
+	int node_cnt;
+	struct aest_node *nodes;
+	u32 id;
+};
+
+static const char *const aest_node_name[] = {
+	[ACPI_AEST_PROCESSOR_ERROR_NODE] = "processor",
+	[ACPI_AEST_MEMORY_ERROR_NODE] = "memory",
+	[ACPI_AEST_SMMU_ERROR_NODE] = "smmu",
+	[ACPI_AEST_VENDOR_ERROR_NODE] = "vendor",
+	[ACPI_AEST_GIC_ERROR_NODE] = "gic",
+	[ACPI_AEST_PCIE_ERROR_NODE] = "pcie",
+	[ACPI_AEST_PROXY_ERROR_NODE] = "proxy",
+};
+
+static inline int aest_set_name(struct aest_device *adev,
+				struct aest_hnode *ahnode)
+{
+	adev->dev->init_name = devm_kasprintf(adev->dev, GFP_KERNEL, "%s%d",
+					      aest_node_name[ahnode->type],
+					      adev->id);
+	if (!adev->dev->init_name)
+		return -ENOMEM;
+
+	return 0;
+}
diff --git a/include/linux/acpi_aest.h b/include/linux/acpi_aest.h
index 53c1970e7583..77187ce43d44 100644
--- a/include/linux/acpi_aest.h
+++ b/include/linux/acpi_aest.h
@@ -15,6 +15,15 @@
 
 #define AEST_MAX_INTERRUPT_PER_NODE 2
 
+/* AEST interface */
+#define AEST_XFACE_FLAG_SHARED (1 << 0)
+#define AEST_XFACE_FLAG_CLEAR_MISC (1 << 1)
+#define AEST_XFACE_FLAG_ERROR_DEVICE (1 << 2)
+#define AEST_XFACE_FLAG_AFFINITY (1 << 3)
+#define AEST_XFACE_FLAG_ERROR_GROUP (1 << 4)
+#define AEST_XFACE_FLAG_FAULT_INJECT (1 << 5)
+#define AEST_XFACE_FLAG_INT_CONFIG (1 << 6)
+
 #define KB 1024
 #define MB (1024 * KB)
 #define GB (1024 * MB)
-- 
2.51.2.612.gdc70283dfc



From tianruidong at linux.alibaba.com  Mon Dec 22 01:43:34 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Mon, 22 Dec 2025 17:43:34 +0800
Subject: [PATCH v4 01/17] ACPI/AEST: Parse the AEST table
In-Reply-To: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
References: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
Message-ID: <20251222094351.38792-2-tianruidong@linux.alibaba.com>

This patch introduces the creation of AEST platform devices, where each
device represents a logical "error node device" grouping one or more
AEST nodes from the ACPI table.

Instead of relying on the optional 'error_node_device' field in the AEST
table[1], this commit uses the interrupt number as the sole identifier for
the parent device. This design simplifies the driver logic by providing a
single, consistent mechanism for grouping nodes.

The 'error_node_device' field can be unspecified, but an AEST node is
always physically associated with a parent component. The interrupt
number serves as a reliable proxy for this association. This approach
is based on the safe assumption that distinct hardware components (e.g.,
SMMU, CMN, GIC) are assigned unique error interrupts and do not share
them.

[1]: https://developer.arm.com/documentation/den0085/latest

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 MAINTAINERS                  |   8 +
 arch/arm64/include/asm/ras.h |  15 ++
 drivers/acpi/arm64/Kconfig   |  11 ++
 drivers/acpi/arm64/Makefile  |   1 +
 drivers/acpi/arm64/aest.c    | 311 +++++++++++++++++++++++++++++++++++
 include/linux/acpi_aest.h    |  56 +++++++
 6 files changed, 402 insertions(+)
 create mode 100644 arch/arm64/include/asm/ras.h
 create mode 100644 drivers/acpi/arm64/aest.c
 create mode 100644 include/linux/acpi_aest.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 84cda6701685..d14e16c3a93b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -341,6 +341,14 @@ S:	Maintained
 F:	drivers/acpi/arm64
 F:	include/linux/acpi_iort.h
 
+ACPI AEST
+M:	Ruidong Tian <tianruidond at linux.alibaba.com>
+L:	linux-acpi at vger.kernel.org
+L:	linux-arm-kernel at lists.infradead.org
+S:	Supported
+F:	drivers/acpi/arm64/aest.c
+F:	include/linux/acpi_aest.h
+
 ACPI FOR RISC-V (ACPI/riscv)
 M:	Sunil V L <sunilvl at ventanamicro.com>
 L:	linux-acpi at vger.kernel.org
diff --git a/arch/arm64/include/asm/ras.h b/arch/arm64/include/asm/ras.h
new file mode 100644
index 000000000000..b6640b9972bf
--- /dev/null
+++ b/arch/arm64/include/asm/ras.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_RAS_H
+#define __ASM_RAS_H
+
+#include <linux/types.h>
+
+struct ras_ext_regs {
+	u64 err_fr;
+	u64 err_ctlr;
+	u64 err_status;
+	u64 err_addr;
+	u64 err_misc[4];
+};
+
+#endif /* __ASM_RAS_H */
diff --git a/drivers/acpi/arm64/Kconfig b/drivers/acpi/arm64/Kconfig
index f2fd79f22e7d..52df190356c8 100644
--- a/drivers/acpi/arm64/Kconfig
+++ b/drivers/acpi/arm64/Kconfig
@@ -24,3 +24,14 @@ config ACPI_APMT
 
 config ACPI_MPAM
 	bool
+
+config ACPI_AEST
+	bool "ARM Error Source Table Support"
+	depends on ARM64_RAS_EXTN
+
+	help
+	  The Arm Error Source Table (AEST) provides details on ACPI
+	  extensions that enable kernel-first handling of errors in a
+	  system that supports the Armv8 RAS extensions.
+
+	  If set, the kernel will report and log hardware errors.
diff --git a/drivers/acpi/arm64/Makefile b/drivers/acpi/arm64/Makefile
index 9390b57cb564..bad77fdbf8dd 100644
--- a/drivers/acpi/arm64/Makefile
+++ b/drivers/acpi/arm64/Makefile
@@ -7,5 +7,6 @@ obj-$(CONFIG_ACPI_IORT) 	+= iort.o
 obj-$(CONFIG_ACPI_MPAM) 	+= mpam.o
 obj-$(CONFIG_ACPI_PROCESSOR_IDLE) += cpuidle.o
 obj-$(CONFIG_ARM_AMBA)		+= amba.o
+obj-$(CONFIG_ACPI_AEST) 	+= aest.o
 obj-y				+= dma.o init.o
 obj-y				+= thermal_cpufreq.o
diff --git a/drivers/acpi/arm64/aest.c b/drivers/acpi/arm64/aest.c
new file mode 100644
index 000000000000..b8359b95f40f
--- /dev/null
+++ b/drivers/acpi/arm64/aest.c
@@ -0,0 +1,311 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ARM Error Source Table Support
+ *
+ * Copyright (c) 2025, Alibaba Group.
+ */
+
+#include <linux/xarray.h>
+#include <linux/platform_device.h>
+#include <linux/acpi_aest.h>
+
+#include "init.h"
+
+#undef pr_fmt
+#define pr_fmt(fmt) "ACPI AEST: " fmt
+
+static struct xarray *aest_array;
+
+static void __init aest_init_interface(struct acpi_aest_hdr *hdr,
+				       struct acpi_aest_node *node)
+{
+	struct acpi_aest_node_interface_header *interface;
+
+	interface = ACPI_ADD_PTR(struct acpi_aest_node_interface_header, hdr,
+				 hdr->node_interface_offset);
+
+	node->type = hdr->type;
+	node->interface_hdr = interface;
+
+	switch (interface->group_format) {
+	case ACPI_AEST_NODE_GROUP_FORMAT_4K: {
+		struct acpi_aest_node_interface_4k *interface_4k =
+			(struct acpi_aest_node_interface_4k *)(interface + 1);
+
+		node->common = &interface_4k->common;
+		node->record_implemented =
+			(unsigned long *)&interface_4k->error_record_implemented;
+		node->status_reporting =
+			(unsigned long *)&interface_4k->error_status_reporting;
+		node->addressing_mode =
+			(unsigned long *)&interface_4k->addressing_mode;
+		break;
+	}
+	case ACPI_AEST_NODE_GROUP_FORMAT_16K: {
+		struct acpi_aest_node_interface_16k *interface_16k =
+			(struct acpi_aest_node_interface_16k *)(interface + 1);
+
+		node->common = &interface_16k->common;
+		node->record_implemented =
+			(unsigned long *)interface_16k->error_record_implemented;
+		node->status_reporting =
+			(unsigned long *)interface_16k->error_status_reporting;
+		node->addressing_mode =
+			(unsigned long *)interface_16k->addressing_mode;
+		break;
+	}
+	case ACPI_AEST_NODE_GROUP_FORMAT_64K: {
+		struct acpi_aest_node_interface_64k *interface_64k =
+			(struct acpi_aest_node_interface_64k *)(interface + 1);
+
+		node->common = &interface_64k->common;
+		node->record_implemented =
+			(unsigned long *)interface_64k->error_record_implemented;
+		node->status_reporting =
+			(unsigned long *)interface_64k->error_status_reporting;
+		node->addressing_mode =
+			(unsigned long *)interface_64k->addressing_mode;
+		break;
+	}
+	default:
+		pr_err("invalid group format: %d\n", interface->group_format);
+	}
+
+	node->interrupt = ACPI_ADD_PTR(struct acpi_aest_node_interrupt_v2, hdr,
+				       hdr->node_interrupt_offset);
+
+	node->interrupt_count = hdr->node_interrupt_count;
+}
+
+static struct aest_hnode *__init
+acpi_aest_alloc_ahnode(struct acpi_aest_node *node, u64 error_device_id)
+{
+	struct aest_hnode *ahnode __free(kfree) = NULL;
+
+	ahnode = kzalloc(sizeof(*ahnode), GFP_KERNEL);
+	if (!ahnode)
+		return NULL;
+
+	INIT_LIST_HEAD(&ahnode->list);
+	ahnode->id = error_device_id;
+	ahnode->count = 0;
+	ahnode->type = node->type;
+
+	return_ptr(ahnode);
+}
+static int __init acpi_aest_init_node(struct acpi_aest_hdr *aest_hdr)
+{
+	struct aest_hnode *ahnode;
+	u64 error_device_id;
+	struct acpi_aest_node *node;
+
+	node = kzalloc(sizeof(*node), GFP_KERNEL);
+	if (!node)
+		return -ENOMEM;
+
+	node->spec_pointer =
+		ACPI_ADD_PTR(void, aest_hdr, aest_hdr->node_specific_offset);
+	if (aest_hdr->type == ACPI_AEST_PROCESSOR_ERROR_NODE)
+		node->processor_spec_pointer =
+			ACPI_ADD_PTR(void, node->spec_pointer,
+				     sizeof(struct acpi_aest_processor));
+
+	aest_init_interface(aest_hdr, node);
+
+	if (node->interrupt_count <= 0)
+		return -EINVAL;
+
+	error_device_id = node->interrupt[0].gsiv;
+	ahnode = xa_load(aest_array, error_device_id);
+	if (!ahnode) {
+		ahnode = acpi_aest_alloc_ahnode(node, error_device_id);
+		if (!ahnode)
+			return -ENOMEM;
+		xa_store(aest_array, error_device_id, ahnode, GFP_KERNEL);
+	}
+
+	list_add_tail(&node->list, &ahnode->list);
+	ahnode->count++;
+
+	return 0;
+}
+
+static int __init acpi_aest_init_nodes(struct acpi_table_header *aest_table)
+{
+	struct acpi_aest_hdr *aest_node, *aest_end;
+	struct acpi_table_aest *aest;
+	int rc;
+
+	aest = (struct acpi_table_aest *)aest_table;
+	aest_node = ACPI_ADD_PTR(struct acpi_aest_hdr, aest,
+				 sizeof(struct acpi_table_header));
+	aest_end = ACPI_ADD_PTR(struct acpi_aest_hdr, aest, aest_table->length);
+
+	while (aest_node < aest_end) {
+		if (((u64)aest_node + aest_node->length) > (u64)aest_end) {
+			pr_warn(FW_WARN
+				"AEST node pointer overflow, bad table.\n");
+			return -EINVAL;
+		}
+
+		rc = acpi_aest_init_node(aest_node);
+		if (rc)
+			return rc;
+
+		aest_node = ACPI_ADD_PTR(struct acpi_aest_hdr, aest_node,
+					 aest_node->length);
+	}
+
+	return 0;
+}
+
+static int acpi_aest_parse_irqs(struct platform_device *pdev,
+				struct acpi_aest_node *anode,
+				struct resource *res, int *res_idx, int irqs[2])
+{
+	int i;
+	struct acpi_aest_node_interrupt_v2 *interrupt;
+	int trigger, irq;
+
+	for (i = 0; i < anode->interrupt_count; i++) {
+		interrupt = &anode->interrupt[i];
+		if (irqs[interrupt->type])
+			continue;
+
+		trigger = (interrupt->flags & AEST_INTERRUPT_MODE) ?
+				  ACPI_LEVEL_SENSITIVE :
+				  ACPI_EDGE_SENSITIVE;
+
+		irq = acpi_register_gsi(&pdev->dev, interrupt->gsiv, trigger,
+					ACPI_ACTIVE_HIGH);
+		if (irq <= 0) {
+			pr_err("failed to map AEST GSI %d\n", interrupt->gsiv);
+			return irq;
+		}
+
+		res[*res_idx].start = irq;
+		res[*res_idx].end = irq;
+		res[*res_idx].flags = IORESOURCE_IRQ;
+		res[*res_idx].name = interrupt->type ? AEST_ERI_NAME :
+						       AEST_FHI_NAME;
+
+		(*res_idx)++;
+
+		irqs[interrupt->type] = irq;
+	}
+
+	return 0;
+}
+
+DEFINE_FREE(res, struct resource *, if (_T) kfree(_T))
+static struct platform_device *__init
+acpi_aest_alloc_pdev(struct aest_hnode *ahnode, int index)
+{
+	struct platform_device *pdev __free(platform_device_put) =
+		platform_device_alloc("AEST", index++);
+	struct resource *res __free(res);
+	struct acpi_aest_node *anode;
+	int ret, size, j, irq[AEST_MAX_INTERRUPT_PER_NODE] = { 0 };
+
+	if (!pdev)
+		return ERR_PTR(-ENOMEM);
+
+	res = kcalloc(ahnode->count + AEST_MAX_INTERRUPT_PER_NODE, sizeof(*res),
+		      GFP_KERNEL);
+	if (!res)
+		return ERR_PTR(-ENOMEM);
+
+	j = 0;
+	list_for_each_entry(anode, &ahnode->list, list) {
+		if (anode->interface_hdr->type !=
+		    ACPI_AEST_NODE_SYSTEM_REGISTER) {
+			res[j].name = AEST_NODE_NAME;
+			res[j].start = anode->interface_hdr->address;
+			switch (anode->interface_hdr->group_format) {
+			case ACPI_AEST_NODE_GROUP_FORMAT_4K:
+				size = 4 * KB;
+				break;
+			case ACPI_AEST_NODE_GROUP_FORMAT_16K:
+				size = 16 * KB;
+				break;
+			case ACPI_AEST_NODE_GROUP_FORMAT_64K:
+				size = 64 * KB;
+				break;
+			default:
+				size = 4 * KB;
+			}
+			res[j].end = res[j].start + size - 1;
+			res[j].flags = IORESOURCE_MEM;
+		}
+
+		ret = acpi_aest_parse_irqs(pdev, anode, res, &j, irq);
+		if (ret)
+			return ERR_PTR(ret);
+	}
+
+	ret = platform_device_add_resources(pdev, res, j);
+	if (ret)
+		return ERR_PTR(ret);
+
+	ret = platform_device_add_data(pdev, &ahnode, sizeof(ahnode));
+	if (ret)
+		return ERR_PTR(ret);
+
+	ret = platform_device_add(pdev);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return_ptr(pdev);
+}
+static int __init acpi_aest_alloc_pdevs(void)
+{
+	int ret = 0, index = 0;
+	struct aest_hnode *ahnode = NULL;
+	unsigned long i;
+
+	xa_for_each(aest_array, i, ahnode) {
+		struct platform_device *pdev =
+			acpi_aest_alloc_pdev(ahnode, index++);
+
+		if (IS_ERR(pdev)) {
+			ret = PTR_ERR(pdev);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int __init acpi_aest_init(void)
+{
+	int ret;
+
+	if (acpi_disabled)
+		return 0;
+
+	struct acpi_table_header *aest_table __free(acpi_put_table) =
+		acpi_get_table_pointer(ACPI_SIG_AEST, 0);
+	if (IS_ERR(aest_table))
+		return 0;
+
+	aest_array = kzalloc(sizeof(struct xarray), GFP_KERNEL);
+	if (!aest_array)
+		return -ENOMEM;
+
+	xa_init(aest_array);
+
+	ret = acpi_aest_init_nodes(aest_table);
+	if (ret) {
+		pr_err("Failed init aest node %d\n", ret);
+		return ret;
+	}
+
+	ret = acpi_aest_alloc_pdevs();
+	if (ret) {
+		pr_err("Failed alloc pdev %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+subsys_initcall_sync(acpi_aest_init);
diff --git a/include/linux/acpi_aest.h b/include/linux/acpi_aest.h
new file mode 100644
index 000000000000..53c1970e7583
--- /dev/null
+++ b/include/linux/acpi_aest.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ACPI_AEST_H__
+#define __ACPI_AEST_H__
+
+#include <asm/ras.h>
+#include <linux/acpi.h>
+
+/* AEST resource name */
+#define AEST_NODE_NAME "AEST:NODE"
+#define AEST_FHI_NAME "AEST:FHI"
+#define AEST_ERI_NAME "AEST:ERI"
+
+/* AEST interrupt */
+#define AEST_INTERRUPT_MODE BIT(0)
+
+#define AEST_MAX_INTERRUPT_PER_NODE 2
+
+#define KB 1024
+#define MB (1024 * KB)
+#define GB (1024 * MB)
+
+struct aest_hnode {
+	struct list_head list;
+	int count;
+	u32 id;
+	int type;
+};
+
+struct acpi_aest_node {
+	struct list_head list;
+	int type;
+	struct acpi_aest_node_interface_header *interface_hdr;
+	unsigned long *record_implemented;
+	unsigned long *status_reporting;
+	unsigned long *addressing_mode;
+	struct acpi_aest_node_interface_common *common;
+	union {
+		struct acpi_aest_processor *processor;
+		struct acpi_aest_memory *memory;
+		struct acpi_aest_smmu *smmu;
+		struct acpi_aest_vendor_v2 *vendor;
+		struct acpi_aest_gic *gic;
+		struct acpi_aest_pcie *pcie;
+		struct acpi_aest_proxy *proxy;
+		void *spec_pointer;
+	};
+	union {
+		struct acpi_aest_processor_cache *cache;
+		struct acpi_aest_processor_tlb *tlb;
+		struct acpi_aest_processor_generic *generic;
+		void *processor_spec_pointer;
+	};
+	struct acpi_aest_node_interrupt_v2 *interrupt;
+	int interrupt_count;
+};
+#endif /* __ACPI_AEST_H__ */
-- 
2.51.2.612.gdc70283dfc



From tianruidong at linux.alibaba.com  Mon Dec 22 01:43:33 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Mon, 22 Dec 2025 17:43:33 +0800
Subject: [PATCH v4 00/17] ARM Error Source Table V2 Support
Message-ID: <20251222094351.38792-1-tianruidong@linux.alibaba.com>

This series introduces support for the ARM Error Source Table (AEST), aligning
with version 2.0 of ACPI for Armv8 RAS Extensions [0].

AEST provides a critical mechanism for hardware to directly notify the
operating system kernel about RAS errors via interrupts, a concept known as
Kernel-first error handling. Compared to firmware-first error handling
(e.g., GHES), AEST offers a more lightweight approach. This efficiency allows
the OS to potentially report every Corrected Error (CE), enabling upper-layer
applications to leverage CE information for error prediction[1][2].

This series is based on Tyler Baicar's preliminary patches [3], which have not
yet been sent to the mailing list as v2.

AEST Driver Architecture
========================

The AEST driver is structured into three primary components:
  - AEST device: Responsible for handling interrupts, managing the lifecycle
                 of AEST nodes, and processing error records.
  - AEST node: Corresponds directly to a RAS node in the hardware
  - AEST record: Represents a set of RAS registers associated with a specific
                 error source.

These components are organized hierarchically as follows:

 ????????????????????????????????????????????????????
 ?             AEST Driver Device Management        ?
 ????????????????    ????????????     ????????????? ?
 ?? AEST Device ??????AEST Node ???????AEST Record? ?
 ???????????????? ?  ????????????  ?  ????????????? ?
 ?                ?       .        ?  ????????????? ?
 ?                ?       .        ????AEST Record? ?
 ?                ?       .        ?  ????????????? ?
 ?                ?  ????????????  ?        .       ?
 ?                ????AEST Node ?  ?        .       ?
 ?                ?  ????????????  ?        .       ?
 ?                ?                ?  ????????????? ?
 ?                ?  ????????????  ????AEST Record? ?
 ?                ????AEST Node ?     ????????????? ?
 ?                   ????????????                   ?
 ????????????????????????????????????????????????????

AEST Interrupt Handle
=====================

Upon an AEST interrupt, the driver performs the following sequence:
1. The AEST device iterates through all registered AEST nodes to identify the
   specific node(s) and record(s) that reported an error.
2. Each node typically contains two types of records:
      - report record: Errors can be located efficiently through a bitmap
                       in the `ERRGSR` register.
      - poll record: The node must individually poll all records to determine
                     if an error has occurred.
3. process record:
      - if error is corrected, The CE threshold is reset, and the error event
        is logged.
      - if error is defered, Relevant registers are dumped, and
        `memory_failure()` is invoked.
      - if error is uncorrected, panic, While UEs typically trigger an
        exception rather than an interrupt, if detected, the system will panic.
4. decode record: The AEST driver notifies other relevant drivers, such as
   EDAC, to further decode the reported RAS register information.

Address Translation
===================

As described in section 2.2 [0], error addresses reported by AEST records
may be "node-specific Logical Addresses" rather than the "System Physical
Addresses" (SPA) used by the kernel. Therefore, the driver needs to translate
these Logical Addresses (LA) to SPA. This translation mechanism is conceptually
similar to AMD's Address Translation Logic (ATL) [4], leading patch 0014 to
introduce a common translation function for both AMD and ARM architectures.

Testing
===================
I have tested this series on THead Yitian710 SOC with customized BIOS. Someone
can also use QEMU[5] for preliminary driver testing.

1. Boot Qemu

qemu-system-aarch64 -smp 4 -m 32G \
  -cpu host --enable-kvm -machine virt,gic-version=3 \
  -kernel Image -initrd initrd.cpio.gz \
  -device virtio-net-pci,netdev=t0 -netdev user,id=t0 \
  -bios /usr/share/edk2/aarch64/QEMU_EFI.fd  \
  -append "rdinit=/sbin/init earlycon verbose debug console=ttyAMA0 aest.dyndbg='+pt'" \
  -nographic -d guest_errors -D qemu.log

2. inject error
devmem 0x90d0808 l 0xc4800390

2.1 Memory error
[   64.959849] AEST: {1}[Hardware Error]: Hardware error from AEST memory.90d0000
[   64.959852] AEST: {1}[Hardware Error]:  Error from memory at SRAT proximity domain 0x0
[   64.959855] AEST: {1}[Hardware Error]:   ERR0FR: 0x40000080044081
[   64.959858] AEST: {1}[Hardware Error]:   ERR0CTRL: 0x108
[   64.959859] AEST: {1}[Hardware Error]:   ERR0STATUS: 0xc4800390
[   64.959860] AEST: {1}[Hardware Error]:   ERR0ADDR: 0x8400000043344521
[   64.959861] AEST: {1}[Hardware Error]:   ERR0MISC0: 0x7fff00000000
[   64.959861] AEST: {1}[Hardware Error]:   ERR0MISC1: 0x0
[   64.959862] AEST: {1}[Hardware Error]:   ERR0MISC2: 0x0
[   64.959863] AEST: {1}[Hardware Error]:   ERR0MISC3: 0x0
[   64.959873] Memory failure: 0x43344: recovery action for free buddy page: Recovered

2.2 CMN error
[  132.044283] AEST: {2}[Hardware Error]: Hardware error from AEST XP
[  132.044286] AEST: {2}[Hardware Error]:  Error from vendor hid ARMHC700 uid 0x0
[  132.044288] AEST: {2}[Hardware Error]:   ERR0FR: 0x48a5
[  132.044290] AEST: {2}[Hardware Error]:   ERR0CTRL: 0x108
[  132.044292] AEST: {2}[Hardware Error]:   ERR0STATUS: 0xc4800390
[  132.044293] AEST: {2}[Hardware Error]:   ERR0ADDR: 0x8400000043344521
[  132.044295] AEST: {2}[Hardware Error]:   ERR0MISC0: 0x0
[  132.044296] AEST: {2}[Hardware Error]:   ERR0MISC1: 0x0
[  132.044298] AEST: {2}[Hardware Error]:   ERR0MISC2: 0x0
[  132.044299] AEST: {2}[Hardware Error]:   ERR0MISC3: 0x0
[  132.044302] Memory failure: 0x43344: recovery action for already poisoned page: Failed

[0]: https://developer.arm.com/documentation/den0085/0101/
[1]: Intel: Predicting Uncorrectable Memory Errors from the Correctable Error History
[2]: Alibaba. Predicting DRAM-Caused Risky VMs in Large-Scale Clouds. Published in HPCA2025
[3]: https://lore.kernel.org/all/20211124170708.3874-1-baicar at os.amperecomputing.com/
[4]: https://lore.kernel.org/all/20240123041401.79812-2-yazen.ghannam at amd.com/
[5]: https://github.com/winterddd/qemu/tree/error_record

Change from V3:
https://lore.kernel.org/all/20250115084228.107573-1-tianruidong at linux.alibaba.com/
1. Add vendor AEST node framework and support CMN700
2. Borislav Petkov
    - Split into multiple smaller patches for easier review.
    - refined the English in the cover letter for better flow.
3. Accept Tomohiro Misono's comment

Change from V2:
https://lore.kernel.org/all/20240321025317.114621-1-tianruidong at linux.alibaba.com/
1. Tomohiro Misono
    - dump register before panic
2. Baolin Wang & Shuai Xue: accept all comment.
3. Support AEST V2.

Change from V1:
https://lore.kernel.org/all/20240304111517.33001-1-tianruidong at linux.alibaba.com/
1. Marc Zyngier
  - Use readq/writeq_relaxed instead of readq/writeq for MMIO address.
  - Add sync for system register operation.
  - Use irq_is_percpu_devid() helper to identify a per-CPU interrupt.
  - Other fix.
2. Set RAS CE threshold in AEST driver.
3. Enable RAS interrupt explicitly in driver.
4. UER and UEO trigger memory_failure other than panic.

Ruidong Tian (17):
  ACPI/AEST: Parse the AEST table
  ras: AEST: Add probe/remove for AEST driver
  ras: AEST: support different group format
  ras: AEST: Unify the read/write interface for system and MMIO register
  ras: AEST: Probe RAS system architecture version
  ras: AEST: Support RAS Common Fault Injection Model Extension
  ras: AEST: Support CE threshold of error record
  ras: AEST: Enable and register IRQs
  ras: AEST: Add cpuhp callback
  ras: AEST: Introduce AEST driver sysfs interface
  ras: AEST: Add error count tracking and debugfs interface
  ras: AEST: Allow configuring CE threshold via debugfs
  ras: AEST: Introduce AEST inject interface to test AEST driver
  ras: ATL: Unify ATL interface for ARM64 and AMD
  ras: AEST: Add framework to process AEST vendor node
  ras: AEST: support vendor node CMN700
  trace, ras: add ARM RAS extension trace event

 Documentation/ABI/testing/debugfs-aest |   98 +++
 MAINTAINERS                            |   11 +
 arch/arm64/include/asm/arm-cmn.h       |   47 ++
 arch/arm64/include/asm/ras.h           |   95 +++
 drivers/acpi/arm64/Kconfig             |   11 +
 drivers/acpi/arm64/Makefile            |    1 +
 drivers/acpi/arm64/aest.c              |  311 +++++++
 drivers/edac/amd64_edac.c              |    2 +-
 drivers/perf/arm-cmn.c                 |   37 +-
 drivers/ras/Kconfig                    |    1 +
 drivers/ras/Makefile                   |    1 +
 drivers/ras/aest/Kconfig               |   17 +
 drivers/ras/aest/Makefile              |    8 +
 drivers/ras/aest/aest-cmn.c            |  332 ++++++++
 drivers/ras/aest/aest-core.c           | 1057 ++++++++++++++++++++++++
 drivers/ras/aest/aest-inject.c         |  131 +++
 drivers/ras/aest/aest-sysfs.c          |  228 +++++
 drivers/ras/aest/aest.h                |  410 +++++++++
 drivers/ras/amd/atl/core.c             |    4 +-
 drivers/ras/amd/atl/internal.h         |    2 +-
 drivers/ras/amd/atl/umc.c              |    3 +-
 drivers/ras/ras.c                      |   27 +-
 include/linux/acpi_aest.h              |   75 ++
 include/linux/cpuhotplug.h             |    1 +
 include/linux/ras.h                    |   17 +-
 include/ras/ras_event.h                |   71 ++
 26 files changed, 2939 insertions(+), 59 deletions(-)
 create mode 100644 Documentation/ABI/testing/debugfs-aest
 create mode 100644 arch/arm64/include/asm/arm-cmn.h
 create mode 100644 arch/arm64/include/asm/ras.h
 create mode 100644 drivers/acpi/arm64/aest.c
 create mode 100644 drivers/ras/aest/Kconfig
 create mode 100644 drivers/ras/aest/Makefile
 create mode 100644 drivers/ras/aest/aest-cmn.c
 create mode 100644 drivers/ras/aest/aest-core.c
 create mode 100644 drivers/ras/aest/aest-inject.c
 create mode 100644 drivers/ras/aest/aest-sysfs.c
 create mode 100644 drivers/ras/aest/aest.h
 create mode 100644 include/linux/acpi_aest.h

-- 
2.51.2.612.gdc70283dfc



From tianruidong at linux.alibaba.com  Mon Dec 22 01:43:36 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Mon, 22 Dec 2025 17:43:36 +0800
Subject: [PATCH v4 03/17] ras: AEST: support different group format
In-Reply-To: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
References: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
Message-ID: <20251222094351.38792-4-tianruidong@linux.alibaba.com>

Support for various AEST group formats allows for flexible configuration of
AEST node address space sizes and maximum record counts per group.

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 drivers/ras/aest/aest-core.c |  6 ++++--
 drivers/ras/aest/aest.h      | 39 +++++++++++++++++++++++++++++++++++-
 2 files changed, 42 insertions(+), 3 deletions(-)

diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index c7ef6c13fd44..acebb293ac75 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -84,7 +84,7 @@ static int aest_node_set_errgsr(struct aest_device *adev,
 		return 0;
 
 	if (!(anode->interface_hdr->flags & AEST_XFACE_FLAG_ERROR_GROUP)) {
-		node->errgsr = node->base + ERXGROUP;
+		node->errgsr = node->base + node->group->errgsr_offset;
 		return 0;
 	}
 
@@ -112,10 +112,12 @@ static int aest_init_node(struct aest_device *adev, struct aest_node *node,
 		return -ENOMEM;
 	node->record_implemented = anode->record_implemented;
 	node->status_reporting = anode->status_reporting;
+	node->group = &aest_group_config[anode->interface_hdr->group_format];
 
 	address = anode->interface_hdr->address;
 	if (address) {
-		node->base = devm_ioremap(adev->dev, address, PAGE_SIZE);
+		node->base =
+			devm_ioremap(adev->dev, address, node->group->size);
 		if (!node->base)
 			return -ENOMEM;
 	}
diff --git a/drivers/ras/aest/aest.h b/drivers/ras/aest/aest.h
index d918240c3f57..3250675e99b7 100644
--- a/drivers/ras/aest/aest.h
+++ b/drivers/ras/aest/aest.h
@@ -37,7 +37,15 @@
 	dev_dbg((__record)->node->adev->dev, "%s: %s: " format, \
 		(__record)->node->name, (__record)->name, ##__VA_ARGS__)
 
-#define ERXGROUP 0xE00
+#define ERXGROUP_4K_OFFSET 0xE00
+#define ERXGROUP_16K_OFFSET 0x3800
+#define ERXGROUP_64K_OFFSET 0xE000
+#define ERXGROUP_4K_SIZE (4 * KB)
+#define ERXGROUP_16K_SIZE (16 * KB)
+#define ERXGROUP_64K_SIZE (64 * KB)
+#define ERXGROUP_4K_ERRGSR_NUM 1
+#define ERXGROUP_16K_ERRGSR_NUM 4
+#define ERXGROUP_64K_ERRGSR_NUM 14
 
 struct aest_record {
 	char *name;
@@ -57,6 +65,34 @@ struct aest_record {
 	struct aest_node *node;
 };
 
+struct aest_group {
+	int type;
+	int errgsr_num;
+	size_t size;
+	u64 errgsr_offset;
+};
+
+static const struct aest_group aest_group_config[] = {
+	[ACPI_AEST_NODE_GROUP_FORMAT_4K] = {
+		.type = ACPI_AEST_NODE_GROUP_FORMAT_4K,
+		.errgsr_num = ERXGROUP_4K_ERRGSR_NUM,
+		.size = ERXGROUP_4K_SIZE,
+		.errgsr_offset = ERXGROUP_4K_OFFSET,
+	},
+	[ACPI_AEST_NODE_GROUP_FORMAT_16K] = {
+		.type = ACPI_AEST_NODE_GROUP_FORMAT_16K,
+		.errgsr_num = ERXGROUP_16K_ERRGSR_NUM,
+		.size = ERXGROUP_16K_SIZE,
+		.errgsr_offset = ERXGROUP_16K_OFFSET,
+	},
+	[ACPI_AEST_NODE_GROUP_FORMAT_64K] = {
+		.type = ACPI_AEST_NODE_GROUP_FORMAT_64K,
+		.errgsr_num = ERXGROUP_64K_ERRGSR_NUM,
+		.size = ERXGROUP_64K_SIZE,
+		.errgsr_offset = ERXGROUP_64K_OFFSET,
+	},
+};
+
 struct aest_node {
 	char *name;
 	u8 type;
@@ -86,6 +122,7 @@ struct aest_node {
 	 */
 	unsigned long *status_reporting;
 
+	const struct aest_group *group;
 	struct aest_device *adev;
 	struct acpi_aest_node *info;
 
-- 
2.51.2.612.gdc70283dfc



From tianruidong at linux.alibaba.com  Mon Dec 22 01:43:37 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Mon, 22 Dec 2025 17:43:37 +0800
Subject: [PATCH v4 04/17] ras: AEST: Unify the read/write interface for system and MMIO register
In-Reply-To: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
References: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
Message-ID: <20251222094351.38792-5-tianruidong@linux.alibaba.com>

Use record_read/write to simultaneously read and write system registers and
MMIO registers while maintaining code conciseness.

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 drivers/ras/aest/aest-core.c |  1 +
 drivers/ras/aest/aest.h      | 94 ++++++++++++++++++++++++++++++++++++
 2 files changed, 95 insertions(+)

diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index acebb293ac75..f4a5119dc513 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -29,6 +29,7 @@ static int aest_init_record(struct aest_record *record, int i,
 		record->regs_base =
 			node->base + sizeof(struct ras_ext_regs) * i;
 
+	record->access = &aest_access[node->info->interface_hdr->type];
 	record->addressing_mode = test_bit(i, node->info->addressing_mode);
 	record->index = i;
 	record->node = node;
diff --git a/drivers/ras/aest/aest.h b/drivers/ras/aest/aest.h
index 3250675e99b7..31131cce9928 100644
--- a/drivers/ras/aest/aest.h
+++ b/drivers/ras/aest/aest.h
@@ -10,6 +10,11 @@
 
 #define MAX_GSI_PER_NODE 2
 
+#define record_read(record, offset) \
+	record->access->read(record->regs_base, offset)
+#define record_write(record, offset, val) \
+	record->access->write(record->regs_base, offset, val)
+
 #define aest_dev_err(__adev, format, ...) \
 	dev_err((__adev)->dev, format, ##__VA_ARGS__)
 #define aest_dev_info(__adev, format, ...) \
@@ -47,6 +52,20 @@
 #define ERXGROUP_16K_ERRGSR_NUM 4
 #define ERXGROUP_64K_ERRGSR_NUM 14
 
+#define ERXFR 0x0
+#define ERXCTLR 0x8
+#define ERXSTATUS 0x10
+#define ERXADDR 0x18
+#define ERXMISC0 0x20
+#define ERXMISC1 0x28
+#define ERXMISC2 0x30
+#define ERXMISC3 0x38
+
+struct aest_access {
+	u64 (*read)(void *base, u32 offset);
+	void (*write)(void *base, u32 offset, u64 val);
+};
+
 struct aest_record {
 	char *name;
 	int index;
@@ -63,6 +82,7 @@ struct aest_record {
 	 */
 	int addressing_mode;
 	struct aest_node *node;
+	const struct aest_access *access;
 };
 
 struct aest_group {
@@ -159,3 +179,77 @@ static inline int aest_set_name(struct aest_device *adev,
 
 	return 0;
 }
+
+#define CASE_READ(res, x)                           \
+	case (x): {                                 \
+		res = read_sysreg_s(SYS_##x##_EL1); \
+		break;                              \
+	}
+
+#define CASE_WRITE(val, x)                            \
+	case (x): {                                   \
+		write_sysreg_s((val), SYS_##x##_EL1); \
+		break;                                \
+	}
+
+static inline u64 aest_sysreg_read(void *__unused, u32 offset)
+{
+	u64 res;
+
+	switch (offset) {
+		CASE_READ(res, ERXFR)
+		CASE_READ(res, ERXCTLR)
+		CASE_READ(res, ERXSTATUS)
+		CASE_READ(res, ERXADDR)
+		CASE_READ(res, ERXMISC0)
+		CASE_READ(res, ERXMISC1)
+		CASE_READ(res, ERXMISC2)
+		CASE_READ(res, ERXMISC3)
+	default :
+		res = 0;
+	}
+	return res;
+}
+
+static inline void aest_sysreg_write(void *base, u32 offset, u64 val)
+{
+	switch (offset) {
+		CASE_WRITE(val, ERXFR)
+		CASE_WRITE(val, ERXCTLR)
+		CASE_WRITE(val, ERXSTATUS)
+		CASE_WRITE(val, ERXADDR)
+		CASE_WRITE(val, ERXMISC0)
+		CASE_WRITE(val, ERXMISC1)
+		CASE_WRITE(val, ERXMISC2)
+		CASE_WRITE(val, ERXMISC3)
+	default :
+		return;
+	}
+}
+
+static inline u64 aest_iomem_read(void *base, u32 offset)
+{
+	return readq_relaxed(base + offset);
+}
+
+static inline void aest_iomem_write(void *base, u32 offset, u64 val)
+{
+	writeq_relaxed(val, base + offset);
+}
+
+/* access type is decided by AEST interface type. */
+static const struct aest_access aest_access[] = {
+	[ACPI_AEST_NODE_SYSTEM_REGISTER] = {
+		.read = aest_sysreg_read,
+		.write = aest_sysreg_write,
+	},
+	[ACPI_AEST_NODE_MEMORY_MAPPED] = {
+		.read = aest_iomem_read,
+		.write = aest_iomem_write,
+	},
+	[ACPI_AEST_NODE_SINGLE_RECORD_MEMORY_MAPPED] = {
+		.read = aest_iomem_read,
+		.write = aest_iomem_write,
+	},
+	{ }
+};
-- 
2.51.2.612.gdc70283dfc



From tianruidong at linux.alibaba.com  Mon Dec 22 01:43:38 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Mon, 22 Dec 2025 17:43:38 +0800
Subject: [PATCH v4 05/17] ras: AEST: Probe RAS system architecture version
In-Reply-To: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
References: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
Message-ID: <20251222094351.38792-6-tianruidong@linux.alibaba.com>

The RAS version of a component can be probed via its ERRDEVARCH register.

In cases where a component (e.g., SMMU) does not implement an ERRDEVARCH
register, the driver falls back to using the RAS version of the Processing
Element (PE).

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 arch/arm64/include/asm/ras.h |  3 +++
 drivers/ras/aest/aest-core.c | 22 ++++++++++++++++++++++
 drivers/ras/aest/aest.h      |  3 +++
 3 files changed, 28 insertions(+)

diff --git a/arch/arm64/include/asm/ras.h b/arch/arm64/include/asm/ras.h
index b6640b9972bf..da7c441252fe 100644
--- a/arch/arm64/include/asm/ras.h
+++ b/arch/arm64/include/asm/ras.h
@@ -4,6 +4,9 @@
 
 #include <linux/types.h>
 
+/* ERRDEVARCH */
+#define ERRDEVARCH_REV GENMASK(19, 16)
+
 struct ras_ext_regs {
 	u64 err_fr;
 	u64 err_ctlr;
diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index f4a5119dc513..84b2fb8127ff 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -16,6 +16,27 @@ DEFINE_PER_CPU(struct aest_device, percpu_adev);
 #undef pr_fmt
 #define pr_fmt(fmt) "AEST: " fmt
 
+static int get_aest_node_ver(struct aest_node *node)
+{
+	u64 reg;
+	void *devarch_base;
+
+	if (node->type == ACPI_AEST_GIC_ERROR_NODE) {
+		devarch_base = ioremap(node->info->interface_hdr->address +
+					       GIC_ERRDEVARCH,
+				       PAGE_SIZE);
+		if (!devarch_base)
+			return 0;
+
+		reg = readl_relaxed(devarch_base);
+		iounmap(devarch_base);
+
+		return FIELD_GET(ERRDEVARCH_REV, reg);
+	}
+
+	return FIELD_GET(ID_AA64PFR0_EL1_RAS_MASK, read_cpuid(ID_AA64PFR0_EL1));
+}
+
 static int aest_init_record(struct aest_record *record, int i,
 			    struct aest_node *node)
 {
@@ -108,6 +129,7 @@ static int aest_init_node(struct aest_device *adev, struct aest_node *node,
 	node->adev = adev;
 	node->info = anode;
 	node->type = anode->type;
+	node->version = get_aest_node_ver(node);
 	node->name = alloc_aest_node_name(node);
 	if (!node->name)
 		return -ENOMEM;
diff --git a/drivers/ras/aest/aest.h b/drivers/ras/aest/aest.h
index 31131cce9928..bf0b9a49fdaa 100644
--- a/drivers/ras/aest/aest.h
+++ b/drivers/ras/aest/aest.h
@@ -61,6 +61,8 @@
 #define ERXMISC2 0x30
 #define ERXMISC3 0x38
 
+#define GIC_ERRDEVARCH 0xFFBC
+
 struct aest_access {
 	u64 (*read)(void *base, u32 offset);
 	void (*write)(void *base, u32 offset, u64 val);
@@ -141,6 +143,7 @@ struct aest_node {
 	 *              error events.
 	 */
 	unsigned long *status_reporting;
+	int version;
 
 	const struct aest_group *group;
 	struct aest_device *adev;
-- 
2.51.2.612.gdc70283dfc



From tianruidong at linux.alibaba.com  Mon Dec 22 01:43:39 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Mon, 22 Dec 2025 17:43:39 +0800
Subject: [PATCH v4 06/17] ras: AEST: Support RAS Common Fault Injection Model Extension
In-Reply-To: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
References: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
Message-ID: <20251222094351.38792-7-tianruidong@linux.alibaba.com>

Add inject register descripted in Common Fault Injection Model
Extension.

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 drivers/ras/aest/aest-core.c | 15 ++++++++++++++-
 drivers/ras/aest/aest.h      | 10 ++++++++++
 2 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index 84b2fb8127ff..1218ae51079c 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -124,7 +124,7 @@ static int aest_init_node(struct aest_device *adev, struct aest_node *node,
 			  struct acpi_aest_node *anode)
 {
 	int i, ret;
-	u64 address;
+	u64 address, flags;
 
 	node->adev = adev;
 	node->info = anode;
@@ -145,6 +145,19 @@ static int aest_init_node(struct aest_device *adev, struct aest_node *node,
 			return -ENOMEM;
 	}
 
+	flags = anode->interface_hdr->flags;
+	address = node->info->common->fault_inject_register_base;
+	if ((flags & AEST_XFACE_FLAG_FAULT_INJECT) && address) {
+		if (address - anode->interface_hdr->address < node->group->size)
+			node->inj = node->base +
+				    (address - anode->interface_hdr->address);
+		else {
+			node->inj = devm_ioremap(adev->dev, address, PAGE_SIZE);
+			if (!node->inj)
+				return -ENOMEM;
+		}
+	}
+
 	ret = aest_node_set_errgsr(adev, node);
 	if (ret)
 		return ret;
diff --git a/drivers/ras/aest/aest.h b/drivers/ras/aest/aest.h
index bf0b9a49fdaa..505ecd9635bc 100644
--- a/drivers/ras/aest/aest.h
+++ b/drivers/ras/aest/aest.h
@@ -60,6 +60,9 @@
 #define ERXMISC1 0x28
 #define ERXMISC2 0x30
 #define ERXMISC3 0x38
+#define ERXPFGF 0x800
+#define ERXPFGCTL 0x808
+#define ERXPFGCDN 0x810
 
 #define GIC_ERRDEVARCH 0xFFBC
 
@@ -120,6 +123,7 @@ struct aest_node {
 	u8 type;
 	void *errgsr;
 	void *base;
+	void *inj;
 
 	/*
 	 * This bitmap indicates which of the error records within this error
@@ -208,6 +212,9 @@ static inline u64 aest_sysreg_read(void *__unused, u32 offset)
 		CASE_READ(res, ERXMISC1)
 		CASE_READ(res, ERXMISC2)
 		CASE_READ(res, ERXMISC3)
+		CASE_READ(res, ERXPFGF)
+		CASE_READ(res, ERXPFGCTL)
+		CASE_READ(res, ERXPFGCDN)
 	default :
 		res = 0;
 	}
@@ -225,6 +232,9 @@ static inline void aest_sysreg_write(void *base, u32 offset, u64 val)
 		CASE_WRITE(val, ERXMISC1)
 		CASE_WRITE(val, ERXMISC2)
 		CASE_WRITE(val, ERXMISC3)
+		CASE_WRITE(val, ERXPFGF)
+		CASE_WRITE(val, ERXPFGCTL)
+		CASE_WRITE(val, ERXPFGCDN)
 	default :
 		return;
 	}
-- 
2.51.2.612.gdc70283dfc



From tianruidong at linux.alibaba.com  Mon Dec 22 01:43:40 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Mon, 22 Dec 2025 17:43:40 +0800
Subject: [PATCH v4 07/17] ras: AEST: Support CE threshold of error record
In-Reply-To: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
References: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
Message-ID: <20251222094351.38792-8-tianruidong@linux.alibaba.com>

The CE threshold defines the number of Correctable Errors (CE) that
must occur in a record before triggering an interrupt. Error records
support multiple threshold configurations, including 8B, 16B, and 32B.
This patch detects the supported threshold settings for error records
and sets the default threshold to 1, ensuring an interrupt is generated
for every CE occurrence.

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 arch/arm64/include/asm/ras.h | 41 ++++++++++++++++++++
 drivers/ras/aest/aest-core.c | 74 ++++++++++++++++++++++++++++++++++++
 drivers/ras/aest/aest.h      | 17 +++++++++
 include/linux/acpi_aest.h    |  3 ++
 4 files changed, 135 insertions(+)

diff --git a/arch/arm64/include/asm/ras.h b/arch/arm64/include/asm/ras.h
index da7c441252fe..6c51d27520c0 100644
--- a/arch/arm64/include/asm/ras.h
+++ b/arch/arm64/include/asm/ras.h
@@ -4,9 +4,50 @@
 
 #include <linux/types.h>
 
+/* ERR<n>FR */
+#define ERR_FR_CE GENMASK_ULL(54, 53)
+#define ERR_FR_RP BIT(15)
+#define ERR_FR_CEC GENMASK_ULL(14, 12)
+
+#define ERR_FR_RP_SINGLE_COUNTER 0
+#define ERR_FR_RP_DOUBLE_COUNTER 1
+
+#define ERR_FR_CEC_0B_COUNTER 0
+#define ERR_FR_CEC_8B_COUNTER BIT(1)
+#define ERR_FR_CEC_16B_COUNTER BIT(2)
+
+/* ERR<n>MISC0 */
+
+/* ERR<n>FR.CEC == 0b010, ERR<n>FR.RP == 0  */
+#define ERR_MISC0_8B_OF BIT(39)
+#define ERR_MISC0_8B_CEC GENMASK_ULL(38, 32)
+
+/* ERR<n>FR.CEC == 0b100, ERR<n>FR.RP == 0  */
+#define ERR_MISC0_16B_OF BIT(47)
+#define ERR_MISC0_16B_CEC GENMASK_ULL(46, 32)
+
+#define ERR_MISC0_CEC_SHIFT 31
+
+#define ERR_8B_CEC_MAX (ERR_MISC0_8B_CEC >> ERR_MISC0_CEC_SHIFT)
+#define ERR_16B_CEC_MAX (ERR_MISC0_16B_CEC >> ERR_MISC0_CEC_SHIFT)
+
+/* ERR<n>FR.CEC == 0b100, ERR<n>FR.RP == 1  */
+#define ERR_MISC0_16B_OFO BIT(63)
+#define ERR_MISC0_16B_CECO GENMASK_ULL(62, 48)
+#define ERR_MISC0_16B_OFR BIT(47)
+#define ERR_MISC0_16B_CECR GENMASK_ULL(46, 32)
+
 /* ERRDEVARCH */
 #define ERRDEVARCH_REV GENMASK(19, 16)
 
+enum ras_ce_threshold {
+	RAS_CE_THRESHOLD_0B,
+	RAS_CE_THRESHOLD_8B,
+	RAS_CE_THRESHOLD_16B,
+	RAS_CE_THRESHOLD_32B,
+	UNKNOWN,
+};
+
 struct ras_ext_regs {
 	u64 err_fr;
 	u64 err_ctlr;
diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index 1218ae51079c..5cfe91a6d72a 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -16,6 +16,79 @@ DEFINE_PER_CPU(struct aest_device, percpu_adev);
 #undef pr_fmt
 #define pr_fmt(fmt) "AEST: " fmt
 
+static enum ras_ce_threshold aest_get_ce_threshold(struct aest_record *record)
+{
+	u64 err_fr, err_fr_cec, err_fr_rp = -1;
+
+	err_fr = record_read(record, ERXFR);
+	err_fr_cec = FIELD_GET(ERR_FR_CEC, err_fr);
+	err_fr_rp = FIELD_GET(ERR_FR_RP, err_fr);
+
+	if (err_fr_cec == ERR_FR_CEC_0B_COUNTER)
+		return RAS_CE_THRESHOLD_0B;
+	else if (err_fr_rp == ERR_FR_RP_DOUBLE_COUNTER)
+		return RAS_CE_THRESHOLD_32B;
+	else if (err_fr_cec == ERR_FR_CEC_8B_COUNTER)
+		return RAS_CE_THRESHOLD_8B;
+	else if (err_fr_cec == ERR_FR_CEC_16B_COUNTER)
+		return RAS_CE_THRESHOLD_16B;
+	else
+		return UNKNOWN;
+}
+
+static const struct ce_threshold_info ce_info[] = {
+	[RAS_CE_THRESHOLD_0B] = { 0 },
+	[RAS_CE_THRESHOLD_8B] = {
+		.max_count = ERR_8B_CEC_MAX,
+		.mask = ERR_MISC0_8B_CEC,
+		.shift = ERR_MISC0_CEC_SHIFT,
+	},
+	[RAS_CE_THRESHOLD_16B] = {
+		.max_count = ERR_16B_CEC_MAX,
+		.mask = ERR_MISC0_16B_CEC,
+		.shift = ERR_MISC0_CEC_SHIFT,
+	},
+};
+
+static void aest_set_ce_threshold(struct aest_record *record)
+{
+	u64 err_misc0;
+	struct ce_threshold *ce = &record->ce;
+	const struct ce_threshold_info *info;
+
+	record->threshold_type = aest_get_ce_threshold(record);
+
+	switch (record->threshold_type) {
+	case RAS_CE_THRESHOLD_0B:
+		aest_record_dbg(record, "do not support CE threshold!\n");
+		return;
+	case RAS_CE_THRESHOLD_8B:
+		aest_record_dbg(record, "support 8 bit CE threshold!\n");
+		break;
+	case RAS_CE_THRESHOLD_16B:
+		aest_record_dbg(record, "support 16 bit CE threshold!\n");
+		break;
+	case RAS_CE_THRESHOLD_32B:
+		aest_record_dbg(record, "not support 32 bit CE threshold!\n");
+		break;
+	default:
+		aest_record_dbg(record, "Unknown misc0 ce threshold!\n");
+	}
+
+	err_misc0 = record_read(record, ERXMISC0);
+	info = &ce_info[record->threshold_type];
+	ce->info = info;
+
+	// Default CE threshold is 1.
+	ce->count = info->max_count;
+	ce->threshold = DEFAULT_CE_THRESHOLD;
+	ce->reg_val = err_misc0 | info->mask;
+
+	record_write(record, ERXMISC0, ce->reg_val);
+	aest_record_dbg(record, "CE threshold is %llx, controlled by Kernel",
+			ce->threshold);
+}
+
 static int get_aest_node_ver(struct aest_node *node)
 {
 	u64 reg;
@@ -54,6 +127,7 @@ static int aest_init_record(struct aest_record *record, int i,
 	record->addressing_mode = test_bit(i, node->info->addressing_mode);
 	record->index = i;
 	record->node = node;
+	aest_set_ce_threshold(record);
 
 	aest_record_dbg(record, "base: %p, index: %d, address mode: %x\n",
 			record->regs_base, record->index,
diff --git a/drivers/ras/aest/aest.h b/drivers/ras/aest/aest.h
index 505ecd9635bc..85eeed79bcbe 100644
--- a/drivers/ras/aest/aest.h
+++ b/drivers/ras/aest/aest.h
@@ -9,6 +9,7 @@
 #include <asm/ras.h>
 
 #define MAX_GSI_PER_NODE 2
+#define DEFAULT_CE_THRESHOLD 1
 
 #define record_read(record, offset) \
 	record->access->read(record->regs_base, offset)
@@ -71,6 +72,19 @@ struct aest_access {
 	void (*write)(void *base, u32 offset, u64 val);
 };
 
+struct ce_threshold_info {
+	const u64 max_count;
+	const u64 mask;
+	const u64 shift;
+};
+
+struct ce_threshold {
+	const struct ce_threshold_info *info;
+	u64 count;
+	u64 threshold;
+	u64 reg_val;
+};
+
 struct aest_record {
 	char *name;
 	int index;
@@ -88,6 +102,9 @@ struct aest_record {
 	int addressing_mode;
 	struct aest_node *node;
 	const struct aest_access *access;
+
+	struct ce_threshold ce;
+	enum ras_ce_threshold threshold_type;
 };
 
 struct aest_group {
diff --git a/include/linux/acpi_aest.h b/include/linux/acpi_aest.h
index 77187ce43d44..a7898c643896 100644
--- a/include/linux/acpi_aest.h
+++ b/include/linux/acpi_aest.h
@@ -13,6 +13,9 @@
 /* AEST interrupt */
 #define AEST_INTERRUPT_MODE BIT(0)
 
+#define AEST_INTERRUPT_FHI_UE_SUPPORT		BIT(0)
+#define AEST_INTERRUPT_FHI_UE_NO_SUPPORT		BIT(1)
+
 #define AEST_MAX_INTERRUPT_PER_NODE 2
 
 /* AEST interface */
-- 
2.51.2.612.gdc70283dfc



From tianruidong at linux.alibaba.com  Mon Dec 22 01:43:41 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Mon, 22 Dec 2025 17:43:41 +0800
Subject: [PATCH v4 08/17] ras: AEST: Enable and register IRQs
In-Reply-To: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
References: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
Message-ID: <20251222094351.38792-9-tianruidong@linux.alibaba.com>

The interrupt numbers for certain error records may be explicitly
programmed into their configuration register.

And for PPIs, each core will maintains its own copy of the aest_device
structure.

Given that handling RAS errors entails complex processes such as EDAC
and memory_failure, all handling is deferred to and handled within a
bottom-half context.

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 arch/arm64/include/asm/ras.h |  36 +++
 drivers/ras/aest/aest-core.c | 531 ++++++++++++++++++++++++++++++++++-
 drivers/ras/aest/aest.h      |  56 ++++
 include/linux/acpi_aest.h    |   7 +
 include/linux/ras.h          |   8 +
 5 files changed, 637 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/ras.h b/arch/arm64/include/asm/ras.h
index 6c51d27520c0..02cf15278d9f 100644
--- a/arch/arm64/include/asm/ras.h
+++ b/arch/arm64/include/asm/ras.h
@@ -2,6 +2,7 @@
 #ifndef __ASM_RAS_H
 #define __ASM_RAS_H
 
+#include <linux/bits.h>
 #include <linux/types.h>
 
 /* ERR<n>FR */
@@ -37,6 +38,41 @@
 #define ERR_MISC0_16B_OFR BIT(47)
 #define ERR_MISC0_16B_CECR GENMASK_ULL(46, 32)
 
+/* ERR<n>STATUS */
+#define ERR_STATUS_AV BIT(31)
+#define ERR_STATUS_V BIT(30)
+#define ERR_STATUS_UE BIT(29)
+#define ERR_STATUS_ER BIT(28)
+#define ERR_STATUS_OF BIT(27)
+#define ERR_STATUS_MV BIT(26)
+#define ERR_STATUS_CE (BIT(25) | BIT(24))
+#define ERR_STATUS_DE BIT(23)
+#define ERR_STATUS_PN BIT(22)
+#define ERR_STATUS_UET (BIT(21) | BIT(20))
+#define ERR_STATUS_CI BIT(19)
+#define ERR_STATUS_IERR GENMASK_ULL(15, 8)
+#define ERR_STATUS_SERR GENMASK_ULL(7, 0)
+
+/* Theses bits are	 write-one-to-clear */
+#define ERR_STATUS_W1TC                                                  \
+	(ERR_STATUS_AV | ERR_STATUS_V | ERR_STATUS_UE | ERR_STATUS_ER |  \
+	 ERR_STATUS_OF | ERR_STATUS_MV | ERR_STATUS_CE | ERR_STATUS_DE | \
+	 ERR_STATUS_PN | ERR_STATUS_UET | ERR_STATUS_CI)
+
+#define ERR_STATUS_UET_UC 0
+#define ERR_STATUS_UET_UEU 1
+#define ERR_STATUS_UET_UEO 2
+#define ERR_STATUS_UET_UER 3
+
+/* ERR<n>ADDR */
+#define ERR_ADDR_AI BIT(61)
+#define ERR_ADDR_PADDR GENMASK_ULL(55, 0)
+
+/* ERR<n>CTLR */
+#define ERR_CTLR_CFI BIT(8)
+#define ERR_CTLR_FI BIT(3)
+#define ERR_CTLR_UI BIT(2)
+
 /* ERRDEVARCH */
 #define ERRDEVARCH_REV GENMASK(19, 16)
 
diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index 5cfe91a6d72a..5ec0ba38f51b 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -5,8 +5,11 @@
  * Copyright (c) 2025, Alibaba Group.
  */
 
+#include <linux/interrupt.h>
+#include <linux/panic.h>
 #include <linux/platform_device.h>
 #include <linux/xarray.h>
+#include <linux/genalloc.h>
 #include <linux/ras.h>
 
 #include "aest.h"
@@ -16,6 +19,439 @@ DEFINE_PER_CPU(struct aest_device, percpu_adev);
 #undef pr_fmt
 #define pr_fmt(fmt) "AEST: " fmt
 
+/*
+ * This memory pool is only to be used to save AEST node in AEST irq context.
+ * There can be 500 AEST node at most.
+ */
+#define AEST_NODE_ALLOCED_MAX 500
+
+#define AEST_LOG_PREFIX_BUFFER 64
+
+BLOCKING_NOTIFIER_HEAD(aest_decoder_chain);
+
+static void aest_print(struct aest_event *event)
+{
+	static atomic_t seqno = { 0 };
+	unsigned int curr_seqno;
+	char pfx_seq[AEST_LOG_PREFIX_BUFFER];
+	int index;
+	struct ras_ext_regs *regs;
+
+	curr_seqno = atomic_inc_return(&seqno);
+	snprintf(pfx_seq, sizeof(pfx_seq), "{%u}" HW_ERR, curr_seqno);
+	pr_info("%sHardware error from AEST %s\n", pfx_seq, event->node_name);
+
+	switch (event->type) {
+	case ACPI_AEST_PROCESSOR_ERROR_NODE:
+		pr_err("%s Error from CPU%d\n", pfx_seq, event->id0);
+		break;
+	case ACPI_AEST_MEMORY_ERROR_NODE:
+		pr_err("%s Error from memory at SRAT proximity domain %#x\n",
+		       pfx_seq, event->id0);
+		break;
+	case ACPI_AEST_SMMU_ERROR_NODE:
+		pr_err("%s Error from SMMU IORT node %#x subcomponent %#x\n",
+		       pfx_seq, event->id0, event->id1);
+		break;
+	case ACPI_AEST_VENDOR_ERROR_NODE:
+		pr_err("%s Error from vendor hid %8.8s uid %#x\n", pfx_seq,
+		       event->hid, event->id1);
+		break;
+	case ACPI_AEST_GIC_ERROR_NODE:
+		pr_err("%s Error from GIC type %#x instance %#x\n", pfx_seq,
+		       event->id0, event->id1);
+		break;
+	default:
+		pr_err("%s Unknown AEST node type\n", pfx_seq);
+		return;
+	}
+
+	index = event->index;
+	regs = &event->regs;
+
+	pr_err("%s  ERR%dFR: 0x%llx\n", pfx_seq, index, regs->err_fr);
+	pr_err("%s  ERR%dCTRL: 0x%llx\n", pfx_seq, index, regs->err_ctlr);
+	pr_err("%s  ERR%dSTATUS: 0x%llx\n", pfx_seq, index, regs->err_status);
+	if (regs->err_status & ERR_STATUS_AV)
+		pr_err("%s  ERR%dADDR: 0x%llx\n", pfx_seq, index,
+		       regs->err_addr);
+
+	if (regs->err_status & ERR_STATUS_MV) {
+		pr_err("%s  ERR%dMISC0: 0x%llx\n", pfx_seq, index,
+		       regs->err_misc[0]);
+		pr_err("%s  ERR%dMISC1: 0x%llx\n", pfx_seq, index,
+		       regs->err_misc[1]);
+		pr_err("%s  ERR%dMISC2: 0x%llx\n", pfx_seq, index,
+		       regs->err_misc[2]);
+		pr_err("%s  ERR%dMISC3: 0x%llx\n", pfx_seq, index,
+		       regs->err_misc[3]);
+	}
+}
+
+static void aest_handle_memory_failure(u64 addr)
+{
+	unsigned long pfn;
+
+	pfn = PHYS_PFN(addr);
+
+	if (!pfn_valid(pfn)) {
+		pr_warn(HW_ERR "Invalid physical address: %#llx\n", addr);
+		return;
+	}
+
+#ifdef CONFIG_MEMORY_FAILURE
+	memory_failure(pfn, 0);
+#endif
+}
+
+static void init_aest_event(struct aest_event *event,
+			    struct aest_record *record,
+			    struct ras_ext_regs *regs)
+{
+	struct aest_node *node = record->node;
+	struct acpi_aest_node *info = node->info;
+
+	event->type = node->type;
+	event->node_name = node->name;
+	switch (node->type) {
+	case ACPI_AEST_PROCESSOR_ERROR_NODE:
+		if (info->processor->flags &
+		    (ACPI_AEST_PROC_FLAG_SHARED | ACPI_AEST_PROC_FLAG_GLOBAL))
+			event->id0 = smp_processor_id();
+		else
+			event->id0 = get_cpu_for_acpi_id(
+				info->processor->processor_id);
+
+		event->id1 = info->processor->resource_type;
+		break;
+	case ACPI_AEST_MEMORY_ERROR_NODE:
+		event->id0 = info->memory->srat_proximity_domain;
+		break;
+	case ACPI_AEST_SMMU_ERROR_NODE:
+		event->id0 = info->smmu->iort_node_reference;
+		event->id1 = info->smmu->subcomponent_reference;
+		break;
+	case ACPI_AEST_VENDOR_ERROR_NODE:
+		event->id0 = 0;
+		event->id1 = info->vendor->acpi_uid;
+		event->hid = info->vendor->acpi_hid;
+		break;
+	case ACPI_AEST_GIC_ERROR_NODE:
+		event->id0 = info->gic->interface_type;
+		event->id1 = info->gic->instance_id;
+		break;
+	default:
+		event->id0 = 0;
+		event->id1 = 0;
+	}
+
+	memcpy(&event->regs, regs, sizeof(*regs));
+	event->index = record->index;
+	event->addressing_mode = record->addressing_mode;
+}
+
+static int aest_node_gen_pool_add(struct aest_device *adev,
+				  struct aest_record *record,
+				  struct ras_ext_regs *regs)
+{
+	struct aest_event *event;
+
+	if (!adev->pool)
+		return -EINVAL;
+
+	event = (void *)gen_pool_alloc(adev->pool, sizeof(*event));
+	if (!event)
+		return -ENOMEM;
+
+	init_aest_event(event, record, regs);
+	llist_add(&event->llnode, &adev->event_list);
+
+	return 0;
+}
+
+static void aest_log(struct aest_record *record, struct ras_ext_regs *regs)
+{
+	struct aest_device *adev = record->node->adev;
+
+	if (!aest_node_gen_pool_add(adev, record, regs))
+		schedule_work(&adev->aest_work);
+}
+
+void aest_register_decode_chain(struct notifier_block *nb)
+{
+	blocking_notifier_chain_register(&aest_decoder_chain, nb);
+}
+EXPORT_SYMBOL_GPL(aest_register_decode_chain);
+
+void aest_unregister_decode_chain(struct notifier_block *nb)
+{
+	blocking_notifier_chain_unregister(&aest_decoder_chain, nb);
+}
+EXPORT_SYMBOL_GPL(aest_unregister_decode_chain);
+
+static void aest_node_pool_process(struct work_struct *work)
+{
+	struct llist_node *head;
+	struct aest_event *event;
+	struct aest_device *adev =
+		container_of(work, struct aest_device, aest_work);
+	u64 status, addr;
+
+	head = llist_del_all(&adev->event_list);
+	if (!head)
+		return;
+
+	head = llist_reverse_order(head);
+	llist_for_each_entry(event, head, llnode) {
+		aest_print(event);
+
+		status = event->regs.err_status;
+		if (!(event->regs.err_addr & ERR_ADDR_AI) &&
+		    (status & (ERR_STATUS_UE | ERR_STATUS_DE))) {
+			if (event->addressing_mode == AEST_ADDREESS_SPA)
+				addr = event->regs.err_addr & PHYS_MASK;
+			aest_handle_memory_failure(addr);
+		}
+
+		blocking_notifier_call_chain(&aest_decoder_chain, 0, event);
+		gen_pool_free(adev->pool, (unsigned long)event, sizeof(*event));
+	}
+}
+
+static int aest_node_pool_init(struct aest_device *adev)
+{
+	unsigned long addr, size;
+
+	size = ilog2(sizeof(struct aest_event));
+	adev->pool =
+		devm_gen_pool_create(adev->dev, size, -1, dev_name(adev->dev));
+	if (!adev->pool)
+		return -ENOMEM;
+
+	size = PAGE_ALIGN(size * AEST_NODE_ALLOCED_MAX);
+	addr = (unsigned long)devm_kzalloc(adev->dev, size, GFP_KERNEL);
+	if (!addr)
+		return -ENOMEM;
+
+	return gen_pool_add(adev->pool, addr, size, -1);
+}
+
+static void aest_panic(struct aest_record *record, struct ras_ext_regs *regs,
+		       char *msg)
+{
+	struct aest_event event = { 0 };
+
+	init_aest_event(&event, record, regs);
+
+	aest_print(&event);
+
+	panic(msg);
+}
+
+static void aest_proc_record(struct aest_record *record, void *data)
+{
+	struct ras_ext_regs regs = { 0 };
+	int *count = data;
+	u64 ue;
+
+	regs.err_status = record_read(record, ERXSTATUS);
+	if (!(regs.err_status & ERR_STATUS_V))
+		return;
+
+	(*count)++;
+
+	if (regs.err_status & ERR_STATUS_AV)
+		regs.err_addr = record_read(record, ERXADDR);
+
+	regs.err_fr = record_read(record, ERXFR);
+	regs.err_ctlr = record_read(record, ERXCTLR);
+
+	if (regs.err_status & ERR_STATUS_MV) {
+		regs.err_misc[0] = record_read(record, ERXMISC0);
+		regs.err_misc[1] = record_read(record, ERXMISC1);
+		if (record->node->version >= ID_AA64PFR0_EL1_RAS_V1P1) {
+			regs.err_misc[2] = record_read(record, ERXMISC2);
+			regs.err_misc[3] = record_read(record, ERXMISC3);
+		}
+
+		if (record->node->info->interface_hdr->flags &
+		    AEST_XFACE_FLAG_CLEAR_MISC) {
+			record_write(record, ERXMISC0, 0);
+			record_write(record, ERXMISC1, 0);
+			if (record->node->version >= ID_AA64PFR0_EL1_RAS_V1P1) {
+				record_write(record, ERXMISC2, 0);
+				record_write(record, ERXMISC3, 0);
+			}
+			/* ce count is 0 if record do not support ce */
+		} else if (record->ce.count > 0)
+			record_write(record, ERXMISC0, record->ce.reg_val);
+	}
+
+	/* panic if unrecoverable and uncontainable error encountered */
+	ue = FIELD_GET(ERR_STATUS_UET, regs.err_status);
+	if ((regs.err_status & ERR_STATUS_UE) &&
+	    (ue == ERR_STATUS_UET_UC || ue == ERR_STATUS_UET_UEU))
+		aest_panic(record, &regs,
+			   "AEST: unrecoverable error encountered");
+
+	aest_log(record, &regs);
+
+	/* Write-one-to-clear the bits we've seen */
+	regs.err_status &= ERR_STATUS_W1TC;
+
+	/* Multi bit filed need to write all-ones to clear. */
+	if (regs.err_status & ERR_STATUS_CE)
+		regs.err_status |= ERR_STATUS_CE;
+
+	/* Multi bit filed need to write all-ones to clear. */
+	if (regs.err_status & ERR_STATUS_UET)
+		regs.err_status |= ERR_STATUS_UET;
+
+	record_write(record, ERXSTATUS, regs.err_status);
+}
+
+static void aest_node_foreach_record(void (*func)(struct aest_record *, void *),
+				     struct aest_node *node, void *data,
+				     unsigned long *bitmap)
+{
+	int i;
+
+	for_each_clear_bit(i, bitmap, node->record_count) {
+		aest_select_record(node, i);
+
+		func(&node->records[i], data);
+
+		aest_sync(node);
+	}
+}
+
+static int aest_proc(struct aest_node *node)
+{
+	int count = 0, i, j, size = node->record_count;
+	u64 err_group = 0;
+
+	aest_node_dbg(node, "Poll bitmap %*pb\n", size,
+		      node->record_implemented);
+	aest_node_foreach_record(aest_proc_record, node, &count,
+				 node->record_implemented);
+
+	if (!node->errgsr)
+		return count;
+
+	aest_node_dbg(node, "Report bitmap %*pb\n", size,
+		      node->status_reporting);
+	for (i = 0; i < BITS_TO_U64(size); i++) {
+		err_group = readq_relaxed((void *)node->errgsr + i * 8);
+		aest_node_dbg(node, "errgsr[%d]: 0x%llx\n", i, err_group);
+
+		for_each_set_bit(j, (unsigned long *)&err_group,
+				 BITS_PER_LONG) {
+			/*
+			 * Error group base is only valid in Memory Map node,
+			 * so driver do not need to write select register and
+			 * sync.
+			 */
+			if (test_bit(i * BITS_PER_LONG + j,
+				     node->status_reporting))
+				continue;
+			aest_proc_record(&node->records[j], &count);
+		}
+	}
+
+	return count;
+}
+
+static irqreturn_t aest_irq_func(int irq, void *input)
+{
+	struct aest_device *adev = input;
+	int i;
+
+	for (i = 0; i < adev->node_cnt; i++)
+		aest_proc(&adev->nodes[i]);
+
+	return IRQ_HANDLED;
+}
+
+static int aest_register_irq(struct aest_device *adev)
+{
+	int i, irq, ret;
+	char *irq_desc;
+
+	irq_desc = devm_kasprintf(adev->dev, GFP_KERNEL, "%s.%s.",
+				  dev_driver_string(adev->dev),
+				  dev_name(adev->dev));
+	if (!irq_desc)
+		return -ENOMEM;
+
+	for (i = 0; i < MAX_GSI_PER_NODE; i++) {
+		irq = adev->irq[i];
+
+		if (!irq)
+			continue;
+
+		if (irq_is_percpu_devid(irq)) {
+			ret = request_percpu_irq(irq, aest_irq_func, irq_desc,
+						 adev->adev_oncore);
+			if (ret)
+				goto free;
+		} else {
+			ret = devm_request_irq(adev->dev, irq, aest_irq_func, 0,
+					       irq_desc, adev);
+			if (ret)
+				return ret;
+		}
+	}
+	return 0;
+
+free:
+	for (; i >= 0; i--) {
+		irq = adev->irq[i];
+
+		if (irq_is_percpu_devid(irq))
+			free_percpu_irq(irq, adev->adev_oncore);
+	}
+
+	return ret;
+}
+
+static void aest_enable_irq(struct aest_record *record)
+{
+	u64 err_ctlr;
+	struct aest_device *adev = record->node->adev;
+
+	err_ctlr = record_read(record, ERXCTLR);
+
+	if (adev->irq[ACPI_AEST_NODE_FAULT_HANDLING])
+		err_ctlr |= (ERR_CTLR_FI | ERR_CTLR_CFI);
+	if (adev->irq[ACPI_AEST_NODE_ERROR_RECOVERY])
+		err_ctlr |= ERR_CTLR_UI;
+
+	record_write(record, ERXCTLR, err_ctlr);
+}
+
+static void aest_config_irq(struct aest_node *node)
+{
+	int i;
+	struct acpi_aest_node_interrupt_v2 *interrupt;
+
+	if (!node->irq_config)
+		return;
+
+	for (i = 0; i < node->info->interrupt_count; i++) {
+		interrupt = &node->info->interrupt[i];
+
+		if (interrupt->type == ACPI_AEST_NODE_FAULT_HANDLING)
+			writeq_relaxed(interrupt->gsiv, node->irq_config);
+
+		if (interrupt->type == ACPI_AEST_NODE_ERROR_RECOVERY)
+			writeq_relaxed(interrupt->gsiv, node->irq_config + 8);
+
+		aest_node_dbg(node, "config irq type %d gsiv %d at %llx",
+			      interrupt->type, interrupt->gsiv,
+			      (u64)node->irq_config);
+	}
+}
+
 static enum ras_ce_threshold aest_get_ce_threshold(struct aest_record *record)
 {
 	u64 err_fr, err_fr_cec, err_fr_rp = -1;
@@ -128,6 +564,7 @@ static int aest_init_record(struct aest_record *record, int i,
 	record->index = i;
 	record->node = node;
 	aest_set_ce_threshold(record);
+	aest_enable_irq(record);
 
 	aest_record_dbg(record, "base: %p, index: %d, address mode: %x\n",
 			record->regs_base, record->index,
@@ -232,6 +669,21 @@ static int aest_init_node(struct aest_device *adev, struct aest_node *node,
 		}
 	}
 
+	address = node->info->common->interrupt_config_register_base;
+	if ((flags & AEST_XFACE_FLAG_INT_CONFIG) && address) {
+		if (address - anode->interface_hdr->address < node->group->size)
+			node->irq_config =
+				node->base +
+				(address - anode->interface_hdr->address);
+		else {
+			node->irq_config =
+				devm_ioremap(adev->dev, address, PAGE_SIZE);
+			if (!node->irq_config)
+				return -ENOMEM;
+		}
+	}
+	aest_config_irq(node);
+
 	ret = aest_node_set_errgsr(adev, node);
 	if (ret)
 		return ret;
@@ -276,6 +728,66 @@ static int aest_init_nodes(struct aest_device *adev, struct aest_hnode *ahnode)
 	return 0;
 }
 
+static int __setup_ppi(struct aest_device *adev)
+{
+	int cpu, i;
+	struct aest_device *oncore_adev;
+	struct aest_node *oncore_node;
+	size_t size;
+
+	adev->adev_oncore = &percpu_adev;
+	for_each_possible_cpu(cpu) {
+		oncore_adev = per_cpu_ptr(&percpu_adev, cpu);
+		memcpy(oncore_adev, adev, sizeof(struct aest_device));
+
+		oncore_adev->nodes =
+			devm_kcalloc(adev->dev, oncore_adev->node_cnt,
+				     sizeof(struct aest_node), GFP_KERNEL);
+		if (!oncore_adev->nodes)
+			return -ENOMEM;
+
+		size = adev->node_cnt * sizeof(struct aest_node);
+		memcpy(oncore_adev->nodes, adev->nodes, size);
+		for (i = 0; i < oncore_adev->node_cnt; i++) {
+			oncore_node = &oncore_adev->nodes[i];
+			oncore_node->records = devm_kcalloc(
+				adev->dev, oncore_node->record_count,
+				sizeof(struct aest_record), GFP_KERNEL);
+			if (!oncore_node->records)
+				return -ENOMEM;
+
+			size = oncore_node->record_count *
+			       sizeof(struct aest_record);
+			memcpy(oncore_node->records, adev->nodes[i].records,
+			       size);
+		}
+
+		aest_dev_dbg(adev, "Init device on CPU%d.\n", cpu);
+	}
+
+	return 0;
+}
+
+static int aest_setup_irq(struct platform_device *pdev,
+			  struct aest_device *adev)
+{
+	int fhi_irq, eri_irq;
+
+	fhi_irq = platform_get_irq_byname_optional(pdev, AEST_FHI_NAME);
+	if (fhi_irq > 0)
+		adev->irq[0] = fhi_irq;
+
+	eri_irq = platform_get_irq_byname_optional(pdev, AEST_ERI_NAME);
+	if (eri_irq > 0)
+		adev->irq[1] = eri_irq;
+
+	/* Allocate and initialise the percpu device pointer for PPI */
+	if (irq_is_percpu(fhi_irq) || irq_is_percpu(eri_irq))
+		return __setup_ppi(adev);
+
+	return 0;
+}
+
 static int aest_device_probe(struct platform_device *pdev)
 {
 	int ret;
@@ -289,14 +801,31 @@ static int aest_device_probe(struct platform_device *pdev)
 	adev = devm_kzalloc(&pdev->dev, sizeof(*adev), GFP_KERNEL);
 	if (!adev)
 		return -ENOMEM;
-
 	adev->dev = &pdev->dev;
 	adev->id = pdev->id;
 	aest_set_name(adev, ahnode);
+
+	INIT_WORK(&adev->aest_work, aest_node_pool_process);
+	ret = aest_node_pool_init(adev);
+	if (ret) {
+		aest_dev_err(adev, "Failed init aest node pool.\n");
+		return ret;
+	}
+	init_llist_head(&adev->event_list);
+
 	ret = aest_init_nodes(adev, ahnode);
 	if (ret)
 		return ret;
 
+	ret = aest_setup_irq(pdev, adev);
+	if (ret)
+		return ret;
+
+	ret = aest_register_irq(adev);
+	if (ret) {
+		aest_dev_err(adev, "register irq failed\n");
+		return ret;
+	}
 	platform_set_drvdata(pdev, adev);
 
 	aest_dev_dbg(adev, "Node cnt: %x, id: %x\n", adev->node_cnt, adev->id);
diff --git a/drivers/ras/aest/aest.h b/drivers/ras/aest/aest.h
index 85eeed79bcbe..a5e43b2a2e90 100644
--- a/drivers/ras/aest/aest.h
+++ b/drivers/ras/aest/aest.h
@@ -67,6 +67,34 @@
 
 #define GIC_ERRDEVARCH 0xFFBC
 
+struct aest_event {
+	struct llist_node llnode;
+	char *node_name;
+	u32 type;
+	/*
+	 * Different nodes have different meanings:
+	 *   - Processor node	: processor number.
+	 *   - Memory node	: SRAT proximity domain.
+	 *   - SMMU node	: IORT proximity domain.
+	 *   - GIC node		: interface type.
+	 */
+	u32 id0;
+	/*
+	 * Different nodes have different meanings:
+	 *   - Processor node	: processor resource type.
+	 *   - Memory node	: Non.
+	 *   - SMMU node	: subcomponent reference.
+	 *   - Vendor node	: Unique ID.
+	 *   - GIC node		: instance identifier.
+	 */
+	u32 id1;
+	/* Vendor node	: hardware ID. */
+	char *hid;
+	u32 index;
+	int addressing_mode;
+	struct ras_ext_regs regs;
+};
+
 struct aest_access {
 	u64 (*read)(void *base, u32 offset);
 	void (*write)(void *base, u32 offset, u64 val);
@@ -141,6 +169,7 @@ struct aest_node {
 	void *errgsr;
 	void *base;
 	void *inj;
+	void *irq_config;
 
 	/*
 	 * This bitmap indicates which of the error records within this error
@@ -172,6 +201,7 @@ struct aest_node {
 
 	int record_count;
 	struct aest_record *records;
+	struct aest_node __percpu *oncore_node;
 };
 
 struct aest_device {
@@ -180,6 +210,12 @@ struct aest_device {
 	int node_cnt;
 	struct aest_node *nodes;
 	u32 id;
+	int irq[MAX_GSI_PER_NODE];
+
+	struct work_struct aest_work;
+	struct gen_pool *pool;
+	struct llist_head event_list;
+	struct aest_device __percpu *adev_oncore;
 };
 
 static const char *const aest_node_name[] = {
@@ -283,3 +319,23 @@ static const struct aest_access aest_access[] = {
 	},
 	{ }
 };
+
+/*
+ * Each PE may has multi error record, you must selects an error
+ * record to be accessed through the Error Record System
+ * registers.
+ */
+static inline void aest_select_record(struct aest_node *node, int index)
+{
+	if (node->type == ACPI_AEST_PROCESSOR_ERROR_NODE) {
+		write_sysreg_s(index, SYS_ERRSELR_EL1);
+		isb();
+	}
+}
+
+/* Ensure all writes has taken effect. */
+static inline void aest_sync(struct aest_node *node)
+{
+	if (node->type == ACPI_AEST_PROCESSOR_ERROR_NODE)
+		isb();
+}
diff --git a/include/linux/acpi_aest.h b/include/linux/acpi_aest.h
index a7898c643896..3a899f57f92f 100644
--- a/include/linux/acpi_aest.h
+++ b/include/linux/acpi_aest.h
@@ -10,6 +10,13 @@
 #define AEST_FHI_NAME "AEST:FHI"
 #define AEST_ERI_NAME "AEST:ERI"
 
+/* AEST component */
+#define ACPI_AEST_PROC_FLAG_GLOBAL	(1<<0)
+#define ACPI_AEST_PROC_FLAG_SHARED	(1<<1)
+
+#define AEST_ADDREESS_SPA	0
+#define AEST_ADDREESS_LA	1
+
 /* AEST interrupt */
 #define AEST_INTERRUPT_MODE BIT(0)
 
diff --git a/include/linux/ras.h b/include/linux/ras.h
index 468941bfe855..05096f049dac 100644
--- a/include/linux/ras.h
+++ b/include/linux/ras.h
@@ -63,4 +63,12 @@ amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err) { return -EINVAL; }
 #define GET_LOGICAL_INDEX(mpidr) -EINVAL
 #endif /* CONFIG_ARM || CONFIG_ARM64 */
 
+#if IS_ENABLED(CONFIG_AEST)
+void aest_register_decode_chain(struct notifier_block *nb);
+void aest_unregister_decode_chain(struct notifier_block *nb);
+#else
+static inline void aest_register_decode_chain(struct notifier_block *nb) {}
+static inline void aest_unregister_decode_chain(struct notifier_block *nb) {}
+#endif /* CONFIG_AEST */
+
 #endif /* __RAS_H__ */
-- 
2.51.2.612.gdc70283dfc



From tianruidong at linux.alibaba.com  Mon Dec 22 01:43:42 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Mon, 22 Dec 2025 17:43:42 +0800
Subject: [PATCH v4 09/17] ras: AEST: Add cpuhp callback
In-Reply-To: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
References: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
Message-ID: <20251222094351.38792-10-tianruidong@linux.alibaba.com>

Move the configuration of interrupts and CE thresholds
into the CPU hotplug callbacks for the per-CPU AEST node.

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 drivers/ras/aest/aest-core.c | 118 ++++++++++++++++++++++++++++++++++-
 drivers/ras/aest/aest.h      |   5 ++
 include/linux/cpuhotplug.h   |   1 +
 3 files changed, 121 insertions(+), 3 deletions(-)

diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index 5ec0ba38f51b..686dde6f2e68 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -5,6 +5,7 @@
  * Copyright (c) 2025, Alibaba Group.
  */
 
+#include <linux/cpu.h>
 #include <linux/interrupt.h>
 #include <linux/panic.h>
 #include <linux/platform_device.h>
@@ -563,8 +564,6 @@ static int aest_init_record(struct aest_record *record, int i,
 	record->addressing_mode = test_bit(i, node->info->addressing_mode);
 	record->index = i;
 	record->node = node;
-	aest_set_ce_threshold(record);
-	aest_enable_irq(record);
 
 	aest_record_dbg(record, "base: %p, index: %d, address mode: %x\n",
 			record->regs_base, record->index,
@@ -572,9 +571,113 @@ static int aest_init_record(struct aest_record *record, int i,
 	return 0;
 }
 
+static void aest_online_record(struct aest_record *record, void *data)
+{
+	if (record_read(record, ERXFR) & ERR_FR_CE)
+		aest_set_ce_threshold(record);
+
+	aest_enable_irq(record);
+}
+
+static void aest_online_oncore_node(struct aest_node *node)
+{
+	int count;
+
+	count = aest_proc(node);
+	aest_node_dbg(node, "Find %d error on CPU%d before AEST probe\n", count,
+		      smp_processor_id());
+
+	aest_node_foreach_record(aest_online_record, node, NULL,
+				 node->record_implemented);
+
+	aest_node_foreach_record(aest_online_record, node, NULL,
+				 node->status_reporting);
+}
+
+static void aest_online_oncore_dev(void *data)
+{
+	int fhi_irq, eri_irq, i;
+	struct aest_device *adev = this_cpu_ptr(data);
+
+	for (i = 0; i < adev->node_cnt; i++)
+		aest_online_oncore_node(&adev->nodes[i]);
+
+	fhi_irq = adev->irq[ACPI_AEST_NODE_FAULT_HANDLING];
+	if (fhi_irq > 0)
+		enable_percpu_irq(fhi_irq, IRQ_TYPE_NONE);
+	eri_irq = adev->irq[ACPI_AEST_NODE_ERROR_RECOVERY];
+	if (eri_irq > 0)
+		enable_percpu_irq(eri_irq, IRQ_TYPE_NONE);
+}
+
+static void aest_offline_oncore_dev(void *data)
+{
+	int fhi_irq, eri_irq;
+	struct aest_device *adev = this_cpu_ptr(data);
+
+	fhi_irq = adev->irq[ACPI_AEST_NODE_FAULT_HANDLING];
+	if (fhi_irq > 0)
+		disable_percpu_irq(fhi_irq);
+	eri_irq = adev->irq[ACPI_AEST_NODE_ERROR_RECOVERY];
+	if (eri_irq > 0)
+		disable_percpu_irq(eri_irq);
+}
+
+static void aest_online_dev(struct aest_device *adev)
+{
+	int count, i;
+	struct aest_node *node;
+
+	for (i = 0; i < adev->node_cnt; i++) {
+		node = &adev->nodes[i];
+
+		if (!node->name)
+			continue;
+
+		count = aest_proc(node);
+		aest_node_dbg(node, "Find %d error before AEST probe\n", count);
+
+		aest_config_irq(node);
+
+		aest_node_foreach_record(aest_online_record, node, NULL,
+					 node->record_implemented);
+		aest_node_foreach_record(aest_online_record, node, NULL,
+					 node->status_reporting);
+	}
+}
+
+static int aest_starting_cpu(unsigned int cpu)
+{
+	pr_debug("CPU%d starting\n", cpu);
+	aest_online_oncore_dev(&percpu_adev);
+
+	return 0;
+}
+
+static int aest_dying_cpu(unsigned int cpu)
+{
+	pr_debug("CPU%d dying\n", cpu);
+	aest_offline_oncore_dev(&percpu_adev);
+
+	return 0;
+}
+
 static void aest_device_remove(struct platform_device *pdev)
 {
+	struct aest_device *adev = platform_get_drvdata(pdev);
+	int i;
+
 	platform_set_drvdata(pdev, NULL);
+
+	if (adev->type != ACPI_AEST_PROCESSOR_ERROR_NODE)
+		return;
+
+	on_each_cpu(aest_offline_oncore_dev, adev->adev_oncore, 1);
+
+	for (i = 0; i < MAX_GSI_PER_NODE; i++) {
+		if (adev->irq[i])
+			free_percpu_irq(adev->irq[i], adev->adev_oncore);
+	}
 }
 
 static char *alloc_aest_node_name(struct aest_node *node)
@@ -682,7 +785,6 @@ static int aest_init_node(struct aest_device *adev, struct aest_node *node,
 				return -ENOMEM;
 		}
 	}
-	aest_config_irq(node);
 
 	ret = aest_node_set_errgsr(adev, node);
 	if (ret)
@@ -826,6 +928,16 @@ static int aest_device_probe(struct platform_device *pdev)
 		aest_dev_err(adev, "register irq failed\n");
 		return ret;
 	}
+
+	if (aest_dev_is_oncore(adev))
+		ret = cpuhp_setup_state(CPUHP_AP_ARM_AEST_STARTING,
+					"drivers/acpi/arm64/aest:starting",
+					aest_starting_cpu, aest_dying_cpu);
+	else
+		aest_online_dev(adev);
+	if (ret)
+		return ret;
+
 	platform_set_drvdata(pdev, adev);
 
 	aest_dev_dbg(adev, "Node cnt: %x, id: %x\n", adev->node_cnt, adev->id);
diff --git a/drivers/ras/aest/aest.h b/drivers/ras/aest/aest.h
index a5e43b2a2e90..f85e81ff35a6 100644
--- a/drivers/ras/aest/aest.h
+++ b/drivers/ras/aest/aest.h
@@ -339,3 +339,8 @@ static inline void aest_sync(struct aest_node *node)
 	if (node->type == ACPI_AEST_PROCESSOR_ERROR_NODE)
 		isb();
 }
+
+static inline bool aest_dev_is_oncore(struct aest_device *adev)
+{
+	return adev->type == ACPI_AEST_PROCESSOR_ERROR_NODE;
+}
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 62cd7b35a29c..831fe9011943 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -179,6 +179,7 @@ enum cpuhp_state {
 	CPUHP_AP_HYPERV_TIMER_STARTING,
 	/* Must be the last timer callback */
 	CPUHP_AP_DUMMY_TIMER_STARTING,
+	CPUHP_AP_ARM_AEST_STARTING,
 	CPUHP_AP_ARM_XEN_STARTING,
 	CPUHP_AP_ARM_XEN_RUNSTATE_STARTING,
 	CPUHP_AP_ARM_CORESIGHT_STARTING,
-- 
2.51.2.612.gdc70283dfc



From tianruidong at linux.alibaba.com  Mon Dec 22 01:43:43 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Mon, 22 Dec 2025 17:43:43 +0800
Subject: [PATCH v4 10/17] ras: AEST: Introduce AEST driver sysfs interface
In-Reply-To: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
References: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
Message-ID: <20251222094351.38792-11-tianruidong@linux.alibaba.com>

Exposes certain AEST driver information to userspace.

Only ROOT can access these interface because it includes
hardware-sensitive information:

  ls /sys/kernel/debug/aest/
  memory<id> smmu<id> ...

  ls /sys/kernel/debug/aest/memory<id>/
  record0 record1 ...

All details at:
        Documentation/ABI/testing/debugfs-aest

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 Documentation/ABI/testing/debugfs-aest |  31 +++++++
 MAINTAINERS                            |   1 +
 drivers/ras/aest/Makefile              |   1 +
 drivers/ras/aest/aest-core.c           |  13 +++
 drivers/ras/aest/aest-sysfs.c          | 118 +++++++++++++++++++++++++
 drivers/ras/aest/aest.h                |   8 ++
 6 files changed, 172 insertions(+)
 create mode 100644 Documentation/ABI/testing/debugfs-aest
 create mode 100644 drivers/ras/aest/aest-sysfs.c

diff --git a/Documentation/ABI/testing/debugfs-aest b/Documentation/ABI/testing/debugfs-aest
new file mode 100644
index 000000000000..1152fc83c3fc
--- /dev/null
+++ b/Documentation/ABI/testing/debugfs-aest
@@ -0,0 +1,31 @@
+What:		/sys/kernel/debug/aest/<name>.<id>/
+Date:		Dec 2025
+KernelVersion	6.19
+Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
+Description:
+		Directory represented a AEST device, <name> means device type,
+		like:
+
+			processor
+			memory
+			smmu
+			...
+		<id> is the unique ID for this device.
+
+What:		/sys/kernel/debug/aest/<name>.<id>/<node_name>/*
+Date:		Dec 2025
+KernelVersion	6.19
+Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
+Description:
+		Attibute for aest node which belong this device, the format
+		of node name is: <Node Type>-<Node Address>
+
+		See more at:
+			https://developer.arm.com/documentation/den0085/latest/
+
+What:		/sys/kernel/debug/aest/<name>.<id>/<node_name>/record<index>/err_*
+Date:		Dec 2025
+KernelVersion	6.19
+Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
+Description:
+		(RO) Read err_* register and return val.
diff --git a/MAINTAINERS b/MAINTAINERS
index fd4c40c4607c..2c148b7ab4b2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -346,6 +346,7 @@ M:	Ruidong Tian <tianruidond at linux.alibaba.com>
 L:	linux-acpi at vger.kernel.org
 L:	linux-arm-kernel at lists.infradead.org
 S:	Supported
+F:	Documentation/ABI/testing/debugfs-aest
 F:	arch/arm64/include/asm/ras.h
 F:	drivers/acpi/arm64/aest.c
 F:	drivers/ras/aest/
diff --git a/drivers/ras/aest/Makefile b/drivers/ras/aest/Makefile
index a6ba7e36fb43..75495413d2b6 100644
--- a/drivers/ras/aest/Makefile
+++ b/drivers/ras/aest/Makefile
@@ -3,3 +3,4 @@
 obj-$(CONFIG_AEST) 	+= aest.o
 
 aest-y		:= aest-core.o
+aest-y		+= aest-sysfs.o
diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index 686dde6f2e68..3bcc635cf8e4 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -20,6 +20,9 @@ DEFINE_PER_CPU(struct aest_device, percpu_adev);
 #undef pr_fmt
 #define pr_fmt(fmt) "AEST: " fmt
 
+#ifdef CONFIG_DEBUG_FS
+struct dentry *aest_debugfs;
+#endif
 /*
  * This memory pool is only to be used to save AEST node in AEST irq context.
  * There can be 500 AEST node at most.
@@ -940,6 +943,8 @@ static int aest_device_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, adev);
 
+	aest_dev_init_debugfs(adev);
+
 	aest_dev_dbg(adev, "Node cnt: %x, id: %x\n", adev->node_cnt, adev->id);
 
 	return 0;
@@ -955,12 +960,20 @@ static struct platform_driver aest_driver = {
 
 static int __init aest_init(void)
 {
+#ifdef CONFIG_DEBUG_FS
+	aest_debugfs = debugfs_create_dir("aest", NULL);
+#endif
+
 	return platform_driver_register(&aest_driver);
 }
 module_init(aest_init);
 
 static void __exit aest_exit(void)
 {
+#ifdef CONFIG_DEBUG_FS
+	debugfs_remove(aest_debugfs);
+#endif
+
 	platform_driver_unregister(&aest_driver);
 }
 module_exit(aest_exit);
diff --git a/drivers/ras/aest/aest-sysfs.c b/drivers/ras/aest/aest-sysfs.c
new file mode 100644
index 000000000000..f3b5427ff4f0
--- /dev/null
+++ b/drivers/ras/aest/aest-sysfs.c
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ARM Error Source Table Support
+ *
+ * Copyright (c) 2025, Alibaba Group.
+ */
+
+#include "aest.h"
+
+/*******************************************************************************
+ *
+ * Attribute for AEST record
+ *
+ ******************************************************************************/
+
+#define DEFINE_AEST_DEBUGFS_ATTR(name, offset) \
+static int name##_get(void *data, u64 *val) \
+{ \
+	struct aest_record *record = data; \
+	*val = record_read(record, offset); \
+	return 0; \
+} \
+static int name##_set(void *data, u64 val) \
+{ \
+	struct aest_record *record = data; \
+	record_write(record, offset, val); \
+	return 0; \
+} \
+DEFINE_DEBUGFS_ATTRIBUTE(name##_ops, name##_get, name##_set, "%#llx\n")
+
+DEFINE_AEST_DEBUGFS_ATTR(err_fr, ERXFR);
+DEFINE_AEST_DEBUGFS_ATTR(err_ctrl, ERXCTLR);
+DEFINE_AEST_DEBUGFS_ATTR(err_status, ERXSTATUS);
+DEFINE_AEST_DEBUGFS_ATTR(err_addr, ERXADDR);
+DEFINE_AEST_DEBUGFS_ATTR(err_misc0, ERXMISC0);
+DEFINE_AEST_DEBUGFS_ATTR(err_misc1, ERXMISC1);
+DEFINE_AEST_DEBUGFS_ATTR(err_misc2, ERXMISC2);
+DEFINE_AEST_DEBUGFS_ATTR(err_misc3, ERXMISC3);
+
+static void aest_record_init_debugfs(struct aest_record *record)
+{
+	debugfs_create_file("err_fr", 0600, record->debugfs, record,
+								&err_fr_ops);
+	debugfs_create_file("err_ctrl", 0600, record->debugfs, record,
+								&err_ctrl_ops);
+	debugfs_create_file("err_status", 0600, record->debugfs, record,
+								&err_status_ops);
+	debugfs_create_file("err_addr", 0600, record->debugfs, record,
+								&err_addr_ops);
+	debugfs_create_file("err_misc0", 0600, record->debugfs, record,
+								&err_misc0_ops);
+	debugfs_create_file("err_misc1", 0600, record->debugfs, record,
+								&err_misc1_ops);
+	debugfs_create_file("err_misc2", 0600, record->debugfs, record,
+								&err_misc2_ops);
+	debugfs_create_file("err_misc3", 0600, record->debugfs, record,
+								&err_misc3_ops);
+}
+
+static void
+aest_node_init_debugfs(struct aest_node *node)
+{
+	int i;
+	struct aest_record *record;
+
+	for (i = 0; i < node->record_count; i++) {
+		record = &node->records[i];
+		if (!record->name)
+			continue;
+		record->debugfs = debugfs_create_dir(record->name,
+								node->debugfs);
+		aest_record_init_debugfs(record);
+	}
+}
+
+static void
+aest_oncore_dev_init_debugfs(struct aest_device *adev)
+{
+	int cpu, i;
+	struct aest_node *node;
+	struct aest_device *percpu_dev;
+	char name[16];
+
+	for_each_possible_cpu(cpu) {
+		percpu_dev = this_cpu_ptr(adev->adev_oncore);
+
+		snprintf(name, sizeof(name), "processor%u", cpu);
+		percpu_dev->debugfs = debugfs_create_dir(name, aest_debugfs);
+
+		for (i = 0; i < adev->node_cnt; i++) {
+			node = &adev->nodes[i];
+
+			node->debugfs = debugfs_create_dir(node->name,
+							percpu_dev->debugfs);
+			aest_node_init_debugfs(node);
+		}
+	}
+}
+
+void aest_dev_init_debugfs(struct aest_device *adev)
+{
+	int i;
+	struct aest_node *node;
+
+	adev->debugfs = debugfs_create_dir(dev_name(adev->dev), aest_debugfs);
+	if (aest_dev_is_oncore(adev)) {
+		aest_oncore_dev_init_debugfs(adev);
+		return;
+	}
+
+	for (i = 0; i < adev->node_cnt; i++) {
+		node = &adev->nodes[i];
+		if (!node->name)
+			continue;
+		node->debugfs = debugfs_create_dir(node->name, adev->debugfs);
+		aest_node_init_debugfs(node);
+	}
+}
diff --git a/drivers/ras/aest/aest.h b/drivers/ras/aest/aest.h
index f85e81ff35a6..ceb9e32bcee3 100644
--- a/drivers/ras/aest/aest.h
+++ b/drivers/ras/aest/aest.h
@@ -7,6 +7,7 @@
 
 #include <linux/acpi_aest.h>
 #include <asm/ras.h>
+#include <linux/debugfs.h>
 
 #define MAX_GSI_PER_NODE 2
 #define DEFAULT_CE_THRESHOLD 1
@@ -67,6 +68,8 @@
 
 #define GIC_ERRDEVARCH 0xFFBC
 
+extern struct dentry *aest_debugfs;
+
 struct aest_event {
 	struct llist_node llnode;
 	char *node_name;
@@ -133,6 +136,7 @@ struct aest_record {
 
 	struct ce_threshold ce;
 	enum ras_ce_threshold threshold_type;
+	struct dentry *debugfs;
 };
 
 struct aest_group {
@@ -201,6 +205,7 @@ struct aest_node {
 
 	int record_count;
 	struct aest_record *records;
+	struct dentry *debugfs;
 	struct aest_node __percpu *oncore_node;
 };
 
@@ -215,6 +220,7 @@ struct aest_device {
 	struct work_struct aest_work;
 	struct gen_pool *pool;
 	struct llist_head event_list;
+	struct dentry *debugfs;
 	struct aest_device __percpu *adev_oncore;
 };
 
@@ -344,3 +350,5 @@ static inline bool aest_dev_is_oncore(struct aest_device *adev)
 {
 	return adev->type == ACPI_AEST_PROCESSOR_ERROR_NODE;
 }
+
+void aest_dev_init_debugfs(struct aest_device *adev);
-- 
2.51.2.612.gdc70283dfc



From tianruidong at linux.alibaba.com  Mon Dec 22 01:43:44 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Mon, 22 Dec 2025 17:43:44 +0800
Subject: [PATCH v4 11/17] ras: AEST: Add error count tracking and debugfs interface
In-Reply-To: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
References: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
Message-ID: <20251222094351.38792-12-tianruidong@linux.alibaba.com>

This commit introduces error counting functionality for AEST records.
Previously, error statistics were not directly available for individual
error records or AEST nodes.

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 Documentation/ABI/testing/debugfs-aest | 14 ++++++
 drivers/ras/aest/aest-core.c           | 21 +++++++++
 drivers/ras/aest/aest-sysfs.c          | 64 ++++++++++++++++++++++++++
 drivers/ras/aest/aest.h                | 10 ++++
 4 files changed, 109 insertions(+)

diff --git a/Documentation/ABI/testing/debugfs-aest b/Documentation/ABI/testing/debugfs-aest
index 1152fc83c3fc..a984fcedede2 100644
--- a/Documentation/ABI/testing/debugfs-aest
+++ b/Documentation/ABI/testing/debugfs-aest
@@ -23,9 +23,23 @@ Description:
 		See more at:
 			https://developer.arm.com/documentation/den0085/latest/
 
+What:		/sys/kernel/debug/aest/<name>.<id>/<node_name>/err_count
+Date:		Dec 2025
+KernelVersion	6.19
+Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
+Description:
+		(RO) Outputs error statistics for all error records of this node.
+
 What:		/sys/kernel/debug/aest/<name>.<id>/<node_name>/record<index>/err_*
 Date:		Dec 2025
 KernelVersion	6.19
 Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
 Description:
 		(RO) Read err_* register and return val.
+
+What:		/sys/kernel/debug/aest/<name>.<id>/<node_name>/record<index>/err_count
+Date:		Dec 2025
+KernelVersion	6.19
+Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
+Description:
+		(RO) Outputs error statistics for all this records.
diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index 3bcc635cf8e4..75cca98024ad 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -170,6 +170,27 @@ static int aest_node_gen_pool_add(struct aest_device *adev,
 	init_aest_event(event, record, regs);
 	llist_add(&event->llnode, &adev->event_list);
 
+	if (regs->err_status & ERR_STATUS_CE)
+		record->count.ce++;
+	if (regs->err_status & ERR_STATUS_DE)
+		record->count.de++;
+	if (regs->err_status & ERR_STATUS_UE) {
+		switch (regs->err_status & ERR_STATUS_UET) {
+		case ERR_STATUS_UET_UC:
+			record->count.uc++;
+			break;
+		case ERR_STATUS_UET_UEU:
+			record->count.ueu++;
+			break;
+		case ERR_STATUS_UET_UER:
+			record->count.uer++;
+			break;
+		case ERR_STATUS_UET_UEO:
+			record->count.ueo++;
+			break;
+		}
+	}
+
 	return 0;
 }
 
diff --git a/drivers/ras/aest/aest-sysfs.c b/drivers/ras/aest/aest-sysfs.c
index f3b5427ff4f0..b54e879506aa 100644
--- a/drivers/ras/aest/aest-sysfs.c
+++ b/drivers/ras/aest/aest-sysfs.c
@@ -7,6 +7,46 @@
 
 #include "aest.h"
 
+static void
+aest_error_count(struct aest_record *record, void *data)
+{
+	struct record_count *count = data;
+
+	count->ce += record->count.ce;
+	count->de += record->count.de;
+	count->uc += record->count.uc;
+	count->ueu += record->count.ueu;
+	count->uer += record->count.uer;
+	count->ueo += record->count.ueo;
+}
+
+/*******************************************************************************
+ *
+ * Debugfs for AEST node
+ *
+ ******************************************************************************/
+
+static int aest_node_err_count_show(struct seq_file *m, void *data)
+{
+	struct aest_node *node = m->private;
+	struct record_count count = { 0 };
+	int i;
+
+	for (i = 0; i < node->record_count; i++)
+		aest_error_count(&node->records[i], &count);
+
+	seq_printf(m, "CE: %llu\n"
+				"DE: %llu\n"
+				"UC: %llu\n"
+				"UEU: %llu\n"
+				"UEO: %llu\n"
+				"UER: %llu\n",
+				count.ce, count.de, count.uc, count.ueu,
+				count.uer, count.ueo);
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(aest_node_err_count);
+
 /*******************************************************************************
  *
  * Attribute for AEST record
@@ -37,6 +77,25 @@ DEFINE_AEST_DEBUGFS_ATTR(err_misc1, ERXMISC1);
 DEFINE_AEST_DEBUGFS_ATTR(err_misc2, ERXMISC2);
 DEFINE_AEST_DEBUGFS_ATTR(err_misc3, ERXMISC3);
 
+static int aest_record_err_count_show(struct seq_file *m, void *data)
+{
+	struct aest_record *record = m->private;
+	struct record_count count = { 0 };
+
+	aest_error_count(record, &count);
+
+	seq_printf(m, "CE: %llu\n"
+				"DE: %llu\n"
+				"UC: %llu\n"
+				"UEU: %llu\n"
+				"UEO: %llu\n"
+				"UER: %llu\n",
+				count.ce, count.de, count.uc, count.ueu,
+				count.uer, count.ueo);
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(aest_record_err_count);
+
 static void aest_record_init_debugfs(struct aest_record *record)
 {
 	debugfs_create_file("err_fr", 0600, record->debugfs, record,
@@ -55,6 +114,8 @@ static void aest_record_init_debugfs(struct aest_record *record)
 								&err_misc2_ops);
 	debugfs_create_file("err_misc3", 0600, record->debugfs, record,
 								&err_misc3_ops);
+	debugfs_create_file("err_count", 0400, record->debugfs, record,
+						&aest_record_err_count_fops);
 }
 
 static void
@@ -63,6 +124,9 @@ aest_node_init_debugfs(struct aest_node *node)
 	int i;
 	struct aest_record *record;
 
+	debugfs_create_file("err_count", 0400, node->debugfs, node,
+					&aest_node_err_count_fops);
+
 	for (i = 0; i < node->record_count; i++) {
 		record = &node->records[i];
 		if (!record->name)
diff --git a/drivers/ras/aest/aest.h b/drivers/ras/aest/aest.h
index ceb9e32bcee3..802430857dc4 100644
--- a/drivers/ras/aest/aest.h
+++ b/drivers/ras/aest/aest.h
@@ -116,6 +116,15 @@ struct ce_threshold {
 	u64 reg_val;
 };
 
+struct record_count {
+	u64 ce;
+	u64 de;
+	u64 uc;
+	u64 uer;
+	u64 ueo;
+	u64 ueu;
+};
+
 struct aest_record {
 	char *name;
 	int index;
@@ -136,6 +145,7 @@ struct aest_record {
 
 	struct ce_threshold ce;
 	enum ras_ce_threshold threshold_type;
+	struct record_count count;
 	struct dentry *debugfs;
 };
 
-- 
2.51.2.612.gdc70283dfc



From tianruidong at linux.alibaba.com  Mon Dec 22 01:43:46 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Mon, 22 Dec 2025 17:43:46 +0800
Subject: [PATCH v4 13/17] ras: AEST: Introduce AEST inject interface to test AEST driver
In-Reply-To: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
References: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
Message-ID: <20251222094351.38792-14-tianruidong@linux.alibaba.com>

AEST offers both soft and hard injection. Soft injection simulates errors
in software, providing flexibility to define the error register content.
Hard injection, on the other hand, utilizes error injection registers to
introduce hardware faults, strictly requiring values that adhere to their
specifications.

Read Documentation/ABI/testing/debugfs-aest to learn how to use them.

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 Documentation/ABI/testing/debugfs-aest |  37 +++++++
 drivers/ras/aest/Makefile              |   1 +
 drivers/ras/aest/aest-core.c           |  24 +++--
 drivers/ras/aest/aest-inject.c         | 131 +++++++++++++++++++++++++
 drivers/ras/aest/aest-sysfs.c          |   8 +-
 drivers/ras/aest/aest.h                |   2 +
 6 files changed, 193 insertions(+), 10 deletions(-)
 create mode 100644 drivers/ras/aest/aest-inject.c

diff --git a/Documentation/ABI/testing/debugfs-aest b/Documentation/ABI/testing/debugfs-aest
index 76ba1b77b274..bd7742a36321 100644
--- a/Documentation/ABI/testing/debugfs-aest
+++ b/Documentation/ABI/testing/debugfs-aest
@@ -59,3 +59,40 @@ KernelVersion	6.19
 Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
 Description:
 		(RO) Outputs error statistics for all this records.
+
+What:		/sys/kernel/debug/aest/<name>.<id>/<node_name>/record<index>/inject/err_*
+Date:		Dec 2025
+KernelVersion	6.19
+Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
+Description:
+		(RW) These registers are used to simulate soft injection errors
+		by holding error register values. You can write any values
+		to them. To trigger the injection, you need to write soft_inject
+		at last. The validity of the injected error depends on the
+		value written to err_status.
+
+		Accepts values -  any.
+
+What:		/sys/kernel/debug/aest/<name>.<id>/<node_name>/record<index>/inject/soft_inject
+Date:		Dec 2025
+KernelVersion	6.19
+Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
+Description:
+		(WO) Write any value to this file to trigger the error
+		injection. Make sure you have specified all necessary error
+		parameters, i.e. this write should be the last step when
+		injecting errors.
+
+		Accepts values -  any.
+
+What:		/sys/kernel/debug/aest/<name>.<id>/<node_name>/record<index>/inject/hard_inject
+Date:		Dec 2025
+KernelVersion	6.19
+Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
+Description:
+		(WO) If the AEST table provides error injection registers,
+		you can write to them via this interface. For instance,
+		values can be written to the ERXPFGCTL register. The post-injection
+		behavior is then determined by the hardware specification.
+
+		Accepts values - any.
diff --git a/drivers/ras/aest/Makefile b/drivers/ras/aest/Makefile
index 75495413d2b6..5ee10fc8b2e9 100644
--- a/drivers/ras/aest/Makefile
+++ b/drivers/ras/aest/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_AEST) 	+= aest.o
 
 aest-y		:= aest-core.o
 aest-y		+= aest-sysfs.o
+aest-y		+= aest-inject.o
diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index 75cca98024ad..a290b482bf8b 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -273,7 +273,7 @@ static void aest_panic(struct aest_record *record, struct ras_ext_regs *regs,
 	panic(msg);
 }
 
-static void aest_proc_record(struct aest_record *record, void *data)
+void aest_proc_record(struct aest_record *record, void *data, bool fake)
 {
 	struct ras_ext_regs regs = { 0 };
 	int *count = data;
@@ -315,9 +315,15 @@ static void aest_proc_record(struct aest_record *record, void *data)
 	/* panic if unrecoverable and uncontainable error encountered */
 	ue = FIELD_GET(ERR_STATUS_UET, regs.err_status);
 	if ((regs.err_status & ERR_STATUS_UE) &&
-	    (ue == ERR_STATUS_UET_UC || ue == ERR_STATUS_UET_UEU))
-		aest_panic(record, &regs,
-			   "AEST: unrecoverable error encountered");
+	    (ue == ERR_STATUS_UET_UC || ue == ERR_STATUS_UET_UEU)) {
+		if (fake)
+			aest_record_info(
+				record,
+				"Simulated error! Skip panic due to fault injection\n");
+		else
+			aest_panic(record, &regs,
+				   "AEST: unrecoverable error encountered");
+	}
 
 	aest_log(record, &regs);
 
@@ -335,7 +341,8 @@ static void aest_proc_record(struct aest_record *record, void *data)
 	record_write(record, ERXSTATUS, regs.err_status);
 }
 
-static void aest_node_foreach_record(void (*func)(struct aest_record *, void *),
+static void aest_node_foreach_record(void (*func)(struct aest_record *, void *,
+						  bool),
 				     struct aest_node *node, void *data,
 				     unsigned long *bitmap)
 {
@@ -344,7 +351,7 @@ static void aest_node_foreach_record(void (*func)(struct aest_record *, void *),
 	for_each_clear_bit(i, bitmap, node->record_count) {
 		aest_select_record(node, i);
 
-		func(&node->records[i], data);
+		func(&node->records[i], data, false);
 
 		aest_sync(node);
 	}
@@ -379,7 +386,7 @@ static int aest_proc(struct aest_node *node)
 			if (test_bit(i * BITS_PER_LONG + j,
 				     node->status_reporting))
 				continue;
-			aest_proc_record(&node->records[j], &count);
+			aest_proc_record(&node->records[j], &count, false);
 		}
 	}
 
@@ -595,7 +602,8 @@ static int aest_init_record(struct aest_record *record, int i,
 	return 0;
 }
 
-static void aest_online_record(struct aest_record *record, void *data)
+static void aest_online_record(struct aest_record *record, void *data,
+			       bool __unused)
 {
 	if (record_read(record, ERXFR) & ERR_FR_CE)
 		aest_set_ce_threshold(record);
diff --git a/drivers/ras/aest/aest-inject.c b/drivers/ras/aest/aest-inject.c
new file mode 100644
index 000000000000..fe6ccac8338e
--- /dev/null
+++ b/drivers/ras/aest/aest-inject.c
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ARM Error Source Table Support
+ *
+ * Copyright (c) 2024, Alibaba Group.
+ */
+
+#include "aest.h"
+
+static struct ras_ext_regs regs_inj;
+
+struct inj_attr {
+	struct attribute attr;
+	ssize_t (*show)(struct aest_node *n, struct inj_attr *a, char *b);
+	ssize_t (*store)(struct aest_node *n, struct inj_attr *a, const char *b,
+				size_t c);
+};
+
+struct aest_inject {
+	struct aest_node *node;
+	struct kobject kobj;
+};
+
+#define to_inj(k)	container_of(k, struct aest_inject, kobj)
+#define to_inj_attr(a)	container_of(a, struct inj_attr, attr)
+
+static u64 aest_sysreg_read_inject(void *__unused, u32 offset)
+{
+	u64 *p = (u64 *)&regs_inj;
+
+	return p[offset/8];
+}
+
+static void aest_sysreg_write_inject(void *base, u32 offset, u64 val)
+{
+	u64 *p = (u64 *)&regs_inj;
+
+	p[offset/8] = val;
+}
+
+static u64 aest_iomem_read_inject(void *base, u32 offset)
+{
+	u64 *p = (u64 *)&regs_inj;
+
+	return p[offset/8];
+}
+
+static void aest_iomem_write_inject(void *base, u32 offset, u64 val)
+{
+	u64 *p = (u64 *)&regs_inj;
+
+	p[offset/8] = val;
+}
+
+static struct aest_access aest_access_inject[] = {
+	[ACPI_AEST_NODE_SYSTEM_REGISTER] = {
+		.read = aest_sysreg_read_inject,
+		.write = aest_sysreg_write_inject,
+	},
+
+	[ACPI_AEST_NODE_MEMORY_MAPPED] = {
+		.read = aest_iomem_read_inject,
+		.write = aest_iomem_write_inject,
+	},
+	[ACPI_AEST_NODE_SINGLE_RECORD_MEMORY_MAPPED] = {
+		.read = aest_iomem_read_inject,
+		.write = aest_iomem_write_inject,
+	},
+	{ }
+};
+
+static int soft_inject_store(void *data, u64 val)
+{
+	int count = 0;
+	struct aest_record record_inj, *record = data;
+	struct aest_node node_inj, *node = record->node;
+
+	memcpy(&node_inj, node, sizeof(*node));
+	node_inj.name = "AEST-injection";
+
+	record_inj.access = &aest_access_inject[node->info->interface_hdr->type];
+	record_inj.node = &node_inj;
+	record_inj.index = record->index;
+
+	regs_inj.err_status |= ERR_STATUS_V;
+
+	aest_proc_record(&record_inj, &count, true);
+
+	if (count != 1)
+		return -EIO;
+
+	return 0;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(soft_inject_ops, NULL, soft_inject_store, "%llu\n");
+
+static int hard_inject_store(void *data, u64 val)
+{
+	struct aest_record *record = data;
+	struct aest_node *node = record->node;
+
+	if (!node->inj)
+		return -EPERM;
+
+	aest_select_record(node, record->index);
+	record_write(record, ERXPFGCTL, val);
+	record_write(record, ERXPFGCDN, 0x100);
+	aest_sync(node);
+
+	return 0;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(hard_inject_ops, NULL, hard_inject_store, "%llu\n");
+
+void aest_inject_init_debugfs(struct aest_record *record)
+{
+	struct dentry *inj;
+
+	inj = debugfs_create_dir("inject", record->debugfs);
+
+	debugfs_create_u64("err_fr", 0600, inj, &regs_inj.err_fr);
+	debugfs_create_u64("err_ctrl", 0600, inj, &regs_inj.err_ctlr);
+	debugfs_create_u64("err_status", 0600, inj, &regs_inj.err_status);
+	debugfs_create_u64("err_addr", 0600, inj, &regs_inj.err_addr);
+	debugfs_create_u64("err_misc0", 0600, inj, &regs_inj.err_misc[0]);
+	debugfs_create_u64("err_misc1", 0600, inj, &regs_inj.err_misc[1]);
+	debugfs_create_u64("err_misc2", 0600, inj, &regs_inj.err_misc[2]);
+	debugfs_create_u64("err_misc3", 0600, inj, &regs_inj.err_misc[3]);
+	debugfs_create_file("soft_inject", 0400, inj, record, &soft_inject_ops);
+
+	if (record->node->inj)
+		debugfs_create_file("hard_inject", 0400, inj, record, &hard_inject_ops);
+}
diff --git a/drivers/ras/aest/aest-sysfs.c b/drivers/ras/aest/aest-sysfs.c
index 392e7ad8328e..66e9c1103f99 100644
--- a/drivers/ras/aest/aest-sysfs.c
+++ b/drivers/ras/aest/aest-sysfs.c
@@ -158,6 +158,7 @@ static void aest_record_init_debugfs(struct aest_record *record)
 						&aest_record_err_count_fops);
 	debugfs_create_file("ce_threshold", 0600, record->debugfs, record,
 						&record_ce_threshold_ops);
+	aest_inject_init_debugfs(record);
 }
 
 static void
@@ -190,8 +191,8 @@ aest_oncore_dev_init_debugfs(struct aest_device *adev)
 	for_each_possible_cpu(cpu) {
 		percpu_dev = this_cpu_ptr(adev->adev_oncore);
 
-		snprintf(name, sizeof(name), "processor%u", cpu);
-		percpu_dev->debugfs = debugfs_create_dir(name, aest_debugfs);
+		snprintf(name, sizeof(name), "processor%u%u", cpu);
+		percpu_dev->debugfs = debugfs_create_dir(name, adev->debugfs);
 
 		for (i = 0; i < adev->node_cnt; i++) {
 			node = &adev->nodes[i];
@@ -208,6 +209,9 @@ void aest_dev_init_debugfs(struct aest_device *adev)
 	int i;
 	struct aest_node *node;
 
+	if (!aest_debugfs)
+		dev_err(adev->dev, "debugfs not enabled\n");
+
 	adev->debugfs = debugfs_create_dir(dev_name(adev->dev), aest_debugfs);
 	if (aest_dev_is_oncore(adev)) {
 		aest_oncore_dev_init_debugfs(adev);
diff --git a/drivers/ras/aest/aest.h b/drivers/ras/aest/aest.h
index 802430857dc4..2f6a7b9ca4ef 100644
--- a/drivers/ras/aest/aest.h
+++ b/drivers/ras/aest/aest.h
@@ -362,3 +362,5 @@ static inline bool aest_dev_is_oncore(struct aest_device *adev)
 }
 
 void aest_dev_init_debugfs(struct aest_device *adev);
+void aest_inject_init_debugfs(struct aest_record *record);
+void aest_proc_record(struct aest_record *record, void *data, bool fake);
-- 
2.51.2.612.gdc70283dfc



From tianruidong at linux.alibaba.com  Mon Dec 22 01:43:45 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Mon, 22 Dec 2025 17:43:45 +0800
Subject: [PATCH v4 12/17] ras: AEST: Allow configuring CE threshold via debugfs
In-Reply-To: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
References: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
Message-ID: <20251222094351.38792-13-tianruidong@linux.alibaba.com>

This commit introduces the ability to configure the Corrected Error (CE)
threshold for AEST records through debugfs. This allows administrators to
dynamically adjust the CE threshold for error reporting.

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 Documentation/ABI/testing/debugfs-aest | 16 ++++++++++
 drivers/ras/aest/aest-sysfs.c          | 42 ++++++++++++++++++++++++++
 2 files changed, 58 insertions(+)

diff --git a/Documentation/ABI/testing/debugfs-aest b/Documentation/ABI/testing/debugfs-aest
index a984fcedede2..76ba1b77b274 100644
--- a/Documentation/ABI/testing/debugfs-aest
+++ b/Documentation/ABI/testing/debugfs-aest
@@ -23,6 +23,14 @@ Description:
 		See more at:
 			https://developer.arm.com/documentation/den0085/latest/
 
+What:		/sys/kernel/debug/aest/<name>.<id>/<node_name>/ce_threshold
+Date:		Dec 2025
+KernelVersion	6.19
+Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
+Description:
+		(WO) Write the ce threshold to all records of this node. Failed
+		if input exceeded the maximum threshold
+
 What:		/sys/kernel/debug/aest/<name>.<id>/<node_name>/err_count
 Date:		Dec 2025
 KernelVersion	6.19
@@ -37,6 +45,14 @@ Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
 Description:
 		(RO) Read err_* register and return val.
 
+What:		/sys/kernel/debug/aest/<name>.<id>/<node_name>/record<index>/ce_threshold
+Date:		Dec 2025
+KernelVersion	6.19
+Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
+Description:
+		(RW) Read and write the ce threshold to this record. Failed
+		if input exceeded the maximum threshold
+
 What:		/sys/kernel/debug/aest/<name>.<id>/<node_name>/record<index>/err_count
 Date:		Dec 2025
 KernelVersion	6.19
diff --git a/drivers/ras/aest/aest-sysfs.c b/drivers/ras/aest/aest-sysfs.c
index b54e879506aa..392e7ad8328e 100644
--- a/drivers/ras/aest/aest-sysfs.c
+++ b/drivers/ras/aest/aest-sysfs.c
@@ -7,6 +7,25 @@
 
 #include "aest.h"
 
+static void
+aest_store_threshold(struct aest_record *record, void *data)
+{
+	u64 err_misc0, *threshold = data;
+	struct ce_threshold *ce = &record->ce;
+
+	if (*threshold > ce->info->max_count)
+		return;
+
+	ce->threshold = *threshold;
+	ce->count = ce->info->max_count - ce->threshold + 1;
+
+	err_misc0 = record_read(record, ERXMISC0);
+	ce->reg_val = (err_misc0 & ~ce->info->mask) |
+			(ce->count << ce->info->shift);
+
+	record_write(record, ERXMISC0, ce->reg_val);
+}
+
 static void
 aest_error_count(struct aest_record *record, void *data)
 {
@@ -77,6 +96,27 @@ DEFINE_AEST_DEBUGFS_ATTR(err_misc1, ERXMISC1);
 DEFINE_AEST_DEBUGFS_ATTR(err_misc2, ERXMISC2);
 DEFINE_AEST_DEBUGFS_ATTR(err_misc3, ERXMISC3);
 
+static int record_ce_threshold_get(void *data, u64 *val)
+{
+	struct aest_record *record = data;
+
+	*val = record->ce.threshold;
+	return 0;
+}
+
+static int record_ce_threshold_set(void *data, u64 val)
+{
+	u64 threshold = val;
+	struct aest_record *record = data;
+
+	aest_store_threshold(record, &threshold);
+
+	return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(record_ce_threshold_ops, record_ce_threshold_get,
+					record_ce_threshold_set, "%llu\n");
+
 static int aest_record_err_count_show(struct seq_file *m, void *data)
 {
 	struct aest_record *record = m->private;
@@ -116,6 +156,8 @@ static void aest_record_init_debugfs(struct aest_record *record)
 								&err_misc3_ops);
 	debugfs_create_file("err_count", 0400, record->debugfs, record,
 						&aest_record_err_count_fops);
+	debugfs_create_file("ce_threshold", 0600, record->debugfs, record,
+						&record_ce_threshold_ops);
 }
 
 static void
-- 
2.51.2.612.gdc70283dfc



From tianruidong at linux.alibaba.com  Mon Dec 22 01:43:48 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Mon, 22 Dec 2025 17:43:48 +0800
Subject: [PATCH v4 14/17] ras: ATL: Unify ATL interface for ARM64 and AMD
In-Reply-To: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
References: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
Message-ID: <20251222094351.38792-16-tianruidong@linux.alibaba.com>

Certain components report errors using their internal physical addresses.
For instance, on AMD platforms, the UMC (Unified Memory Controller) reports
normalized addresses, while on Arm systems, memory controllers may report
logical addresses. These addresses must be translated into System Physical
Addresses (SPA) before the OS can utilize them effectively.

AMD already provides the amd_atl_umc_na_to_spa interface for physical address
translation. This patch introduces a common function, atl_ras_la_to_spa,
intended for use by both AMD and Arm64 architectures. The parameters of this
function are architecture-specific data required for the address translation
process.

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 drivers/edac/amd64_edac.c      |  2 +-
 drivers/ras/aest/aest-core.c   |  3 +++
 drivers/ras/amd/atl/core.c     |  4 ++--
 drivers/ras/amd/atl/internal.h |  2 +-
 drivers/ras/amd/atl/umc.c      |  3 ++-
 drivers/ras/ras.c              | 24 +++++++++++-------------
 include/linux/ras.h            |  9 ++++-----
 7 files changed, 24 insertions(+), 23 deletions(-)

diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 2391f3469961..478cfef37892 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -2847,7 +2847,7 @@ static void decode_umc_error(int node_id, struct mce *m)
 	a_err.ipid = m->ipid;
 	a_err.cpu  = m->extcpu;
 
-	sys_addr = amd_convert_umc_mca_addr_to_sys_addr(&a_err);
+	sys_addr = convert_ras_la_to_spa(&a_err);
 	if (IS_ERR_VALUE(sys_addr)) {
 		err.err_code = ERR_NORM_ADDR;
 		goto log_error;
diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index a290b482bf8b..052211ca3e2a 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -235,6 +235,9 @@ static void aest_node_pool_process(struct work_struct *work)
 		    (status & (ERR_STATUS_UE | ERR_STATUS_DE))) {
 			if (event->addressing_mode == AEST_ADDREESS_SPA)
 				addr = event->regs.err_addr & PHYS_MASK;
+			else
+				addr = convert_ras_la_to_spa(event);
+
 			aest_handle_memory_failure(addr);
 		}
 
diff --git a/drivers/ras/amd/atl/core.c b/drivers/ras/amd/atl/core.c
index 0f7cd6dab0b0..4f44c0ce97ec 100644
--- a/drivers/ras/amd/atl/core.c
+++ b/drivers/ras/amd/atl/core.c
@@ -210,7 +210,7 @@ static int __init amd_atl_init(void)
 
 	/* Increment this module's recount so that it can't be easily unloaded. */
 	__module_get(THIS_MODULE);
-	amd_atl_register_decoder(convert_umc_mca_addr_to_sys_addr);
+	atl_register_decoder(convert_umc_mca_addr_to_sys_addr);
 
 	pr_info("AMD Address Translation Library initialized\n");
 	return 0;
@@ -222,7 +222,7 @@ static int __init amd_atl_init(void)
  */
 static void __exit amd_atl_exit(void)
 {
-	amd_atl_unregister_decoder();
+	atl_unregister_decoder();
 }
 
 module_init(amd_atl_init);
diff --git a/drivers/ras/amd/atl/internal.h b/drivers/ras/amd/atl/internal.h
index 82a56d9c2be1..423a6193fdc7 100644
--- a/drivers/ras/amd/atl/internal.h
+++ b/drivers/ras/amd/atl/internal.h
@@ -279,7 +279,7 @@ int denormalize_address(struct addr_ctx *ctx);
 int dehash_address(struct addr_ctx *ctx);
 
 unsigned long norm_to_sys_addr(u8 socket_id, u8 die_id, u8 coh_st_inst_id, unsigned long addr);
-unsigned long convert_umc_mca_addr_to_sys_addr(struct atl_err *err);
+unsigned long convert_umc_mca_addr_to_sys_addr(void *data);
 
 u64 add_base_and_hole(struct addr_ctx *ctx, u64 addr);
 u64 remove_base_and_hole(struct addr_ctx *ctx, u64 addr);
diff --git a/drivers/ras/amd/atl/umc.c b/drivers/ras/amd/atl/umc.c
index befc616d5e8a..57a78c380467 100644
--- a/drivers/ras/amd/atl/umc.c
+++ b/drivers/ras/amd/atl/umc.c
@@ -399,8 +399,9 @@ static u8 get_coh_st_inst_id(struct atl_err *err)
 	return FIELD_GET(UMC_CHANNEL_NUM, err->ipid);
 }
 
-unsigned long convert_umc_mca_addr_to_sys_addr(struct atl_err *err)
+unsigned long convert_umc_mca_addr_to_sys_addr(void *data)
 {
+	struct atl_err *err = data;
 	u8 socket_id = topology_physical_package_id(err->cpu);
 	u8 coh_st_inst_id = get_coh_st_inst_id(err);
 	unsigned long addr = get_addr(err->addr);
diff --git a/drivers/ras/ras.c b/drivers/ras/ras.c
index 2a5b5a9fdcb3..050b49466a18 100644
--- a/drivers/ras/ras.c
+++ b/drivers/ras/ras.c
@@ -10,36 +10,34 @@
 #include <linux/ras.h>
 #include <linux/uuid.h>
 
-#if IS_ENABLED(CONFIG_AMD_ATL)
 /*
  * Once set, this function pointer should never be unset.
  *
  * The library module will set this pointer if it successfully loads. The module
  * should not be unloaded except for testing and debug purposes.
  */
-static unsigned long (*amd_atl_umc_na_to_spa)(struct atl_err *err);
+static unsigned long (*atl_ras_la_to_spa)(void *err);
 
-void amd_atl_register_decoder(unsigned long (*f)(struct atl_err *))
+void atl_register_decoder(unsigned long (*f)(void *))
 {
-	amd_atl_umc_na_to_spa = f;
+	atl_ras_la_to_spa = f;
 }
-EXPORT_SYMBOL_GPL(amd_atl_register_decoder);
+EXPORT_SYMBOL_GPL(atl_register_decoder);
 
-void amd_atl_unregister_decoder(void)
+void atl_unregister_decoder(void)
 {
-	amd_atl_umc_na_to_spa = NULL;
+	atl_ras_la_to_spa = NULL;
 }
-EXPORT_SYMBOL_GPL(amd_atl_unregister_decoder);
+EXPORT_SYMBOL_GPL(atl_unregister_decoder);
 
-unsigned long amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err)
+unsigned long convert_ras_la_to_spa(void *err)
 {
-	if (!amd_atl_umc_na_to_spa)
+	if (!atl_ras_la_to_spa)
 		return -EINVAL;
 
-	return amd_atl_umc_na_to_spa(err);
+	return atl_ras_la_to_spa(err);
 }
-EXPORT_SYMBOL_GPL(amd_convert_umc_mca_addr_to_sys_addr);
-#endif /* CONFIG_AMD_ATL */
+EXPORT_SYMBOL_GPL(convert_ras_la_to_spa);
 
 #define CREATE_TRACE_POINTS
 #define TRACE_INCLUDE_PATH ../../include/ras
diff --git a/include/linux/ras.h b/include/linux/ras.h
index 05096f049dac..2270a8eb1038 100644
--- a/include/linux/ras.h
+++ b/include/linux/ras.h
@@ -42,14 +42,9 @@ struct atl_err {
 };
 
 #if IS_ENABLED(CONFIG_AMD_ATL)
-void amd_atl_register_decoder(unsigned long (*f)(struct atl_err *));
-void amd_atl_unregister_decoder(void);
 void amd_retire_dram_row(struct atl_err *err);
-unsigned long amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err);
 #else
 static inline void amd_retire_dram_row(struct atl_err *err) { }
-static inline unsigned long
-amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err) { return -EINVAL; }
 #endif /* CONFIG_AMD_ATL */
 
 #if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
@@ -63,6 +58,10 @@ amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err) { return -EINVAL; }
 #define GET_LOGICAL_INDEX(mpidr) -EINVAL
 #endif /* CONFIG_ARM || CONFIG_ARM64 */
 
+void atl_register_decoder(unsigned long (*f)(void *));
+void atl_unregister_decoder(void);
+unsigned long convert_ras_la_to_spa(void *err);
+
 #if IS_ENABLED(CONFIG_AEST)
 void aest_register_decode_chain(struct notifier_block *nb);
 void aest_unregister_decode_chain(struct notifier_block *nb);
-- 
2.51.2.612.gdc70283dfc



From tianruidong at linux.alibaba.com  Mon Dec 22 01:43:47 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Mon, 22 Dec 2025 17:43:47 +0800
Subject: [PATCH v4 14/17] ras: ATL: Unified ATL interface for ARM64 and AMD
In-Reply-To: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
References: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
Message-ID: <20251222094351.38792-15-tianruidong@linux.alibaba.com>

Translate device normalize address in AMD, also named logical address,
to system physical address is a common interface in RAS. Provides common
interface both for AMD and ARM.

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 drivers/edac/amd64_edac.c      |  2 +-
 drivers/ras/aest/aest-core.c   |  3 +++
 drivers/ras/amd/atl/core.c     |  4 ++--
 drivers/ras/amd/atl/internal.h |  2 +-
 drivers/ras/amd/atl/umc.c      |  3 ++-
 drivers/ras/ras.c              | 24 +++++++++++-------------
 include/linux/ras.h            |  9 ++++-----
 7 files changed, 24 insertions(+), 23 deletions(-)

diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 2391f3469961..478cfef37892 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -2847,7 +2847,7 @@ static void decode_umc_error(int node_id, struct mce *m)
 	a_err.ipid = m->ipid;
 	a_err.cpu  = m->extcpu;
 
-	sys_addr = amd_convert_umc_mca_addr_to_sys_addr(&a_err);
+	sys_addr = convert_ras_la_to_spa(&a_err);
 	if (IS_ERR_VALUE(sys_addr)) {
 		err.err_code = ERR_NORM_ADDR;
 		goto log_error;
diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index a290b482bf8b..052211ca3e2a 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -235,6 +235,9 @@ static void aest_node_pool_process(struct work_struct *work)
 		    (status & (ERR_STATUS_UE | ERR_STATUS_DE))) {
 			if (event->addressing_mode == AEST_ADDREESS_SPA)
 				addr = event->regs.err_addr & PHYS_MASK;
+			else
+				addr = convert_ras_la_to_spa(event);
+
 			aest_handle_memory_failure(addr);
 		}
 
diff --git a/drivers/ras/amd/atl/core.c b/drivers/ras/amd/atl/core.c
index 0f7cd6dab0b0..4f44c0ce97ec 100644
--- a/drivers/ras/amd/atl/core.c
+++ b/drivers/ras/amd/atl/core.c
@@ -210,7 +210,7 @@ static int __init amd_atl_init(void)
 
 	/* Increment this module's recount so that it can't be easily unloaded. */
 	__module_get(THIS_MODULE);
-	amd_atl_register_decoder(convert_umc_mca_addr_to_sys_addr);
+	atl_register_decoder(convert_umc_mca_addr_to_sys_addr);
 
 	pr_info("AMD Address Translation Library initialized\n");
 	return 0;
@@ -222,7 +222,7 @@ static int __init amd_atl_init(void)
  */
 static void __exit amd_atl_exit(void)
 {
-	amd_atl_unregister_decoder();
+	atl_unregister_decoder();
 }
 
 module_init(amd_atl_init);
diff --git a/drivers/ras/amd/atl/internal.h b/drivers/ras/amd/atl/internal.h
index 82a56d9c2be1..423a6193fdc7 100644
--- a/drivers/ras/amd/atl/internal.h
+++ b/drivers/ras/amd/atl/internal.h
@@ -279,7 +279,7 @@ int denormalize_address(struct addr_ctx *ctx);
 int dehash_address(struct addr_ctx *ctx);
 
 unsigned long norm_to_sys_addr(u8 socket_id, u8 die_id, u8 coh_st_inst_id, unsigned long addr);
-unsigned long convert_umc_mca_addr_to_sys_addr(struct atl_err *err);
+unsigned long convert_umc_mca_addr_to_sys_addr(void *data);
 
 u64 add_base_and_hole(struct addr_ctx *ctx, u64 addr);
 u64 remove_base_and_hole(struct addr_ctx *ctx, u64 addr);
diff --git a/drivers/ras/amd/atl/umc.c b/drivers/ras/amd/atl/umc.c
index befc616d5e8a..57a78c380467 100644
--- a/drivers/ras/amd/atl/umc.c
+++ b/drivers/ras/amd/atl/umc.c
@@ -399,8 +399,9 @@ static u8 get_coh_st_inst_id(struct atl_err *err)
 	return FIELD_GET(UMC_CHANNEL_NUM, err->ipid);
 }
 
-unsigned long convert_umc_mca_addr_to_sys_addr(struct atl_err *err)
+unsigned long convert_umc_mca_addr_to_sys_addr(void *data)
 {
+	struct atl_err *err = data;
 	u8 socket_id = topology_physical_package_id(err->cpu);
 	u8 coh_st_inst_id = get_coh_st_inst_id(err);
 	unsigned long addr = get_addr(err->addr);
diff --git a/drivers/ras/ras.c b/drivers/ras/ras.c
index 2a5b5a9fdcb3..050b49466a18 100644
--- a/drivers/ras/ras.c
+++ b/drivers/ras/ras.c
@@ -10,36 +10,34 @@
 #include <linux/ras.h>
 #include <linux/uuid.h>
 
-#if IS_ENABLED(CONFIG_AMD_ATL)
 /*
  * Once set, this function pointer should never be unset.
  *
  * The library module will set this pointer if it successfully loads. The module
  * should not be unloaded except for testing and debug purposes.
  */
-static unsigned long (*amd_atl_umc_na_to_spa)(struct atl_err *err);
+static unsigned long (*atl_ras_la_to_spa)(void *err);
 
-void amd_atl_register_decoder(unsigned long (*f)(struct atl_err *))
+void atl_register_decoder(unsigned long (*f)(void *))
 {
-	amd_atl_umc_na_to_spa = f;
+	atl_ras_la_to_spa = f;
 }
-EXPORT_SYMBOL_GPL(amd_atl_register_decoder);
+EXPORT_SYMBOL_GPL(atl_register_decoder);
 
-void amd_atl_unregister_decoder(void)
+void atl_unregister_decoder(void)
 {
-	amd_atl_umc_na_to_spa = NULL;
+	atl_ras_la_to_spa = NULL;
 }
-EXPORT_SYMBOL_GPL(amd_atl_unregister_decoder);
+EXPORT_SYMBOL_GPL(atl_unregister_decoder);
 
-unsigned long amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err)
+unsigned long convert_ras_la_to_spa(void *err)
 {
-	if (!amd_atl_umc_na_to_spa)
+	if (!atl_ras_la_to_spa)
 		return -EINVAL;
 
-	return amd_atl_umc_na_to_spa(err);
+	return atl_ras_la_to_spa(err);
 }
-EXPORT_SYMBOL_GPL(amd_convert_umc_mca_addr_to_sys_addr);
-#endif /* CONFIG_AMD_ATL */
+EXPORT_SYMBOL_GPL(convert_ras_la_to_spa);
 
 #define CREATE_TRACE_POINTS
 #define TRACE_INCLUDE_PATH ../../include/ras
diff --git a/include/linux/ras.h b/include/linux/ras.h
index 05096f049dac..2270a8eb1038 100644
--- a/include/linux/ras.h
+++ b/include/linux/ras.h
@@ -42,14 +42,9 @@ struct atl_err {
 };
 
 #if IS_ENABLED(CONFIG_AMD_ATL)
-void amd_atl_register_decoder(unsigned long (*f)(struct atl_err *));
-void amd_atl_unregister_decoder(void);
 void amd_retire_dram_row(struct atl_err *err);
-unsigned long amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err);
 #else
 static inline void amd_retire_dram_row(struct atl_err *err) { }
-static inline unsigned long
-amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err) { return -EINVAL; }
 #endif /* CONFIG_AMD_ATL */
 
 #if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
@@ -63,6 +58,10 @@ amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err) { return -EINVAL; }
 #define GET_LOGICAL_INDEX(mpidr) -EINVAL
 #endif /* CONFIG_ARM || CONFIG_ARM64 */
 
+void atl_register_decoder(unsigned long (*f)(void *));
+void atl_unregister_decoder(void);
+unsigned long convert_ras_la_to_spa(void *err);
+
 #if IS_ENABLED(CONFIG_AEST)
 void aest_register_decode_chain(struct notifier_block *nb);
 void aest_unregister_decode_chain(struct notifier_block *nb);
-- 
2.51.2.612.gdc70283dfc



From tianruidong at linux.alibaba.com  Mon Dec 22 01:43:49 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Mon, 22 Dec 2025 17:43:49 +0800
Subject: [PATCH v4 15/17] ras: AEST: Add framework to process AEST vendor node
In-Reply-To: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
References: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
Message-ID: <20251222094351.38792-17-tianruidong@linux.alibaba.com>

AEST table include vendor error node to support the component that do
not implement standard Arm RAS architecture[1]. Each vendor node may
have their own initialize and interrupt handle function. This patch
supply a framework to process vendor error nodes, the vendor process
function is binded with vendor HID.

[1]: https://developer.arm.com/documentation/ddi0587/latest/

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 drivers/ras/aest/aest-core.c | 28 +++++++++++++++++++++++++++-
 drivers/ras/aest/aest.h      |  5 +++++
 2 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index 052211ca3e2a..4d20e54832fd 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -925,6 +925,29 @@ static int aest_setup_irq(struct platform_device *pdev,
 	return 0;
 }
 
+static struct aest_vendor_match vendor_match[] = {
+	{  },
+};
+
+static int
+aest_vendor_probe(struct aest_device *adev, struct aest_hnode *ahnode)
+{
+	int i;
+	struct acpi_aest_node *anode;
+
+	anode = list_first_entry(&ahnode->list, struct acpi_aest_node, list);
+	if (!anode)
+		return -ENODEV;
+
+	aest_dev_dbg(adev, "Try to probe vendor node %s\n", anode->vendor->acpi_hid);
+	for (i = 0; i < ARRAY_SIZE(vendor_match); i++) {
+		if (!strncmp(vendor_match[i].hid, anode->vendor->acpi_hid, 8))
+			return vendor_match[i].probe(adev, ahnode);
+	}
+
+	return -ENODEV;
+}
+
 static int aest_device_probe(struct platform_device *pdev)
 {
 	int ret;
@@ -950,7 +973,10 @@ static int aest_device_probe(struct platform_device *pdev)
 	}
 	init_llist_head(&adev->event_list);
 
-	ret = aest_init_nodes(adev, ahnode);
+	if (ahnode->type == ACPI_AEST_VENDOR_ERROR_NODE)
+		ret = aest_vendor_probe(adev, ahnode);
+	else
+		ret = aest_init_nodes(adev, ahnode);
 	if (ret)
 		return ret;
 
diff --git a/drivers/ras/aest/aest.h b/drivers/ras/aest/aest.h
index 2f6a7b9ca4ef..304c03839d31 100644
--- a/drivers/ras/aest/aest.h
+++ b/drivers/ras/aest/aest.h
@@ -244,6 +244,11 @@ static const char *const aest_node_name[] = {
 	[ACPI_AEST_PROXY_ERROR_NODE] = "proxy",
 };
 
+struct aest_vendor_match {
+	char hid[ACPI_ID_LEN];
+	int (*probe)(struct aest_device *adev, struct aest_hnode *anode);
+};
+
 static inline int aest_set_name(struct aest_device *adev,
 				struct aest_hnode *ahnode)
 {
-- 
2.51.2.612.gdc70283dfc



From tianruidong at linux.alibaba.com  Mon Dec 22 01:43:51 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Mon, 22 Dec 2025 17:43:51 +0800
Subject: [PATCH v4 17/17] trace, ras: add ARM RAS extension trace event
In-Reply-To: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
References: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
Message-ID: <20251222094351.38792-19-tianruidong@linux.alibaba.com>

Add a trace event for hardware errors reported by the ARMv8
RAS extension registers. userspace app can monitor this
trace event and decode error information.

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 drivers/ras/aest/aest-core.c |  6 +++
 drivers/ras/ras.c            |  3 ++
 include/ras/ras_event.h      | 71 ++++++++++++++++++++++++++++++++++++
 3 files changed, 80 insertions(+)

diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index 33e1f32c5892..9f06ac0b7c16 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -13,6 +13,8 @@
 #include <linux/genalloc.h>
 #include <linux/ras.h>
 
+#include <ras/ras_event.h>
+
 #include "aest.h"
 
 DEFINE_PER_CPU(struct aest_device, percpu_adev);
@@ -90,6 +92,10 @@ static void aest_print(struct aest_event *event)
 		pr_err("%s  ERR%dMISC3: 0x%llx\n", pfx_seq, index,
 		       regs->err_misc[3]);
 	}
+
+	trace_arm_ras_ext_event(event->type, event->id0, event->id1,
+				event->index, event->hid, &event->regs,
+				event->vendor_data, event->vendor_data_size);
 }
 
 static void aest_handle_memory_failure(u64 addr)
diff --git a/drivers/ras/ras.c b/drivers/ras/ras.c
index 050b49466a18..3c0ba6c02d27 100644
--- a/drivers/ras/ras.c
+++ b/drivers/ras/ras.c
@@ -109,6 +109,9 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(extlog_mem_event);
 EXPORT_TRACEPOINT_SYMBOL_GPL(mc_event);
 EXPORT_TRACEPOINT_SYMBOL_GPL(non_standard_event);
 EXPORT_TRACEPOINT_SYMBOL_GPL(arm_event);
+#ifdef CONFIG_ARM64_RAS_EXTN
+EXPORT_TRACEPOINT_SYMBOL_GPL(arm_ras_ext_event);
+#endif
 
 static int __init parse_ras_param(char *str)
 {
diff --git a/include/ras/ras_event.h b/include/ras/ras_event.h
index eaecc3c5f772..3a4a0c0e4dbe 100644
--- a/include/ras/ras_event.h
+++ b/include/ras/ras_event.h
@@ -377,6 +377,77 @@ TRACE_EVENT(aer_event,
 			"Not available")
 );
 #endif /* CONFIG_PCIEAER */
+
+/*
+ * ARM RAS Extension Events Report
+ *
+ * This event is generated when an error reported by the ARM RAS extension
+ * hardware is detected.
+ */
+
+#ifdef CONFIG_ARM64_RAS_EXTN
+#include <asm/ras.h>
+TRACE_EVENT(arm_ras_ext_event,
+
+	TP_PROTO(const u8 type,
+		 const u32 id0,
+		 const u32 id1,
+		 const u32 index,
+		 char *hid,
+		 struct ras_ext_regs *regs,
+		 const u8 *data,
+		 const u32 len),
+
+	TP_ARGS(type, id0, id1, index, hid, regs, data, len),
+
+	TP_STRUCT__entry(
+		__field(u8,  type)
+		__field(u32, id0)
+		__field(u32, id1)
+		__field(u32, index)
+		__field(char *, hid)
+		__field(u64, err_fr)
+		__field(u64, err_ctlr)
+		__field(u64, err_status)
+		__field(u64, err_addr)
+		__field(u64, err_misc0)
+		__field(u64, err_misc1)
+		__field(u64, err_misc2)
+		__field(u64, err_misc3)
+		__field(u32, len)
+		__dynamic_array(u8, buf, len)
+	),
+
+	TP_fast_assign(
+		__entry->type = type;
+		__entry->id0 = id0;
+		__entry->id1 = id1;
+		__entry->index = index;
+		__entry->hid = hid;
+		__entry->err_fr = regs->err_fr;
+		__entry->err_ctlr = regs->err_ctlr;
+		__entry->err_status = regs->err_status;
+		__entry->err_addr = regs->err_addr;
+		__entry->err_misc0 = regs->err_misc[0];
+		__entry->err_misc1 = regs->err_misc[1];
+		__entry->err_misc2 = regs->err_misc[2];
+		__entry->err_misc3 = regs->err_misc[3];
+		__entry->len = len;
+		memcpy(__get_dynamic_array(buf), data, len);
+	),
+
+	TP_printk("type: %d; id0: %d; id1: %d; index: %d; hid: %s; "
+		  "ERR_FR: %llx; ERR_CTLR: %llx; ERR_STATUS: %llx; "
+		  "ERR_ADDR: %llx; ERR_MISC0: %llx; ERR_MISC1: %llx; "
+		  "ERR_MISC2: %llx; ERR_MISC3: %llx; data len:%d; raw data:%s",
+		  __entry->type, __entry->id0, __entry->id1, __entry->index,
+		  __entry->hid, __entry->err_fr, __entry->err_ctlr,
+		  __entry->err_status, __entry->err_addr, __entry->err_misc0,
+		  __entry->err_misc1, __entry->err_misc2, __entry->err_misc3,
+		  __entry->len,
+		  __print_hex(__get_dynamic_array(buf), __entry->len))
+);
+#endif /* CONFIG_ARM64_RAS_EXTN */
 #endif /* _TRACE_HW_EVENT_MC_H */
 
 /* This part must be outside protection */
-- 
2.51.2.612.gdc70283dfc



From tianruidong at linux.alibaba.com  Mon Dec 22 01:43:50 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Mon, 22 Dec 2025 17:43:50 +0800
Subject: [PATCH v4 16/17] ras: AEST: support vendor node CMN700
In-Reply-To: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
References: <20251222094351.38792-1-tianruidong@linux.alibaba.com>
Message-ID: <20251222094351.38792-18-tianruidong@linux.alibaba.com>

The CMN (Coherent Mesh Network) architecture incorporates five distinct
device types. Each device type is associated with an error group register
set. The struct aest_cmn_700 models a single CMN instance, while struct
aest_cmn_700_child represents an individual CMN device.

CMN's error records utilize a memory-mapped single error record view [1].
Critically, one error record corresponds to one AEST node, implying that
a single CMN instance can generate hundreds of AEST nodes. To manage this
scale, this driver introduces a virtual AEST node, which represents an
entire CMN device, such as an HNI or HNF. This allows an HNF AEST node,
for instance, to leverage its errgsr register to pinpoint which specific
error record has reported an error.

During the AEST probe phase, the CMN AEST driver identifies the CMN node
type using the cmn_node_info register. It then reorganizes all AEST nodes
belonging to the same CMN node type into a cohesive CMN AEST node
structure. To locate the relevant CMN register addresses, the CMN's
presence in the DSDT is required, along with the CMN node offset
specified in the AEST vendor specification data [1].

[1]: https://developer.arm.com/documentation/102308/latest/

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 arch/arm64/include/asm/arm-cmn.h |  47 +++++
 drivers/perf/arm-cmn.c           |  37 +---
 drivers/ras/aest/Makefile        |   1 +
 drivers/ras/aest/aest-cmn.c      | 332 +++++++++++++++++++++++++++++++
 drivers/ras/aest/aest-core.c     |  42 ++--
 drivers/ras/aest/aest.h          |  39 ++++
 6 files changed, 446 insertions(+), 52 deletions(-)
 create mode 100644 arch/arm64/include/asm/arm-cmn.h
 create mode 100644 drivers/ras/aest/aest-cmn.c

diff --git a/arch/arm64/include/asm/arm-cmn.h b/arch/arm64/include/asm/arm-cmn.h
new file mode 100644
index 000000000000..1b9f50679794
--- /dev/null
+++ b/arch/arm64/include/asm/arm-cmn.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2015 ARM Ltd.
+ */
+#ifndef __ASM_ARM_CMN_H
+#define __ASM_ARM_CMN_H
+
+#include <asm/sysreg.h>
+
+/* Common register stuff */
+#define CMN_NODE_INFO			0x0000
+#define CMN_NI_NODE_TYPE		GENMASK_ULL(15, 0)
+#define CMN_NI_NODE_ID			GENMASK_ULL(31, 16)
+#define CMN_NI_LOGICAL_ID		GENMASK_ULL(47, 32)
+
+enum cmn_node_type {
+	CMN_TYPE_INVALID,
+	CMN_TYPE_DVM,
+	CMN_TYPE_CFG,
+	CMN_TYPE_DTC,
+	CMN_TYPE_HNI,
+	CMN_TYPE_HNF,
+	CMN_TYPE_XP,
+	CMN_TYPE_SBSX,
+	CMN_TYPE_MPAM_S,
+	CMN_TYPE_MPAM_NS,
+	CMN_TYPE_RNI,
+	CMN_TYPE_RND = 0xd,
+	CMN_TYPE_RNSAM = 0xf,
+	CMN_TYPE_MTSX,
+	CMN_TYPE_HNP,
+	CMN_TYPE_CXRA = 0x100,
+	CMN_TYPE_CXHA,
+	CMN_TYPE_CXLA,
+	CMN_TYPE_CCRA,
+	CMN_TYPE_CCHA,
+	CMN_TYPE_CCLA,
+	CMN_TYPE_CCLA_RNI,
+	CMN_TYPE_HNS = 0x200,
+	CMN_TYPE_HNS_MPAM_S,
+	CMN_TYPE_HNS_MPAM_NS,
+	CMN_TYPE_APB = 0x1000,
+	/* Not a real node type */
+	CMN_TYPE_WP = 0x7770
+};
+
+#endif /* __ASM_ARM_CMN_H */
diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c
index 23245352a3fc..989482096dfb 100644
--- a/drivers/perf/arm-cmn.c
+++ b/drivers/perf/arm-cmn.c
@@ -2,6 +2,7 @@
 // Copyright (C) 2016-2020 Arm Limited
 // ARM CMN/CI interconnect PMU driver
 
+#include <asm/arm-cmn.h>
 #include <linux/acpi.h>
 #include <linux/bitfield.h>
 #include <linux/bitops.h>
@@ -19,11 +20,6 @@
 #include <linux/sort.h>
 
 /* Common register stuff */
-#define CMN_NODE_INFO			0x0000
-#define CMN_NI_NODE_TYPE		GENMASK_ULL(15, 0)
-#define CMN_NI_NODE_ID			GENMASK_ULL(31, 16)
-#define CMN_NI_LOGICAL_ID		GENMASK_ULL(47, 32)
-
 #define CMN_CHILD_INFO			0x0080
 #define CMN_CI_CHILD_COUNT		GENMASK_ULL(15, 0)
 #define CMN_CI_CHILD_PTR_OFFSET		GENMASK_ULL(31, 16)
@@ -241,37 +237,6 @@ enum cmn_revision {
 	REV_CI700_R2P0,
 };
 
-enum cmn_node_type {
-	CMN_TYPE_INVALID,
-	CMN_TYPE_DVM,
-	CMN_TYPE_CFG,
-	CMN_TYPE_DTC,
-	CMN_TYPE_HNI,
-	CMN_TYPE_HNF,
-	CMN_TYPE_XP,
-	CMN_TYPE_SBSX,
-	CMN_TYPE_MPAM_S,
-	CMN_TYPE_MPAM_NS,
-	CMN_TYPE_RNI,
-	CMN_TYPE_RND = 0xd,
-	CMN_TYPE_RNSAM = 0xf,
-	CMN_TYPE_MTSX,
-	CMN_TYPE_HNP,
-	CMN_TYPE_CXRA = 0x100,
-	CMN_TYPE_CXHA,
-	CMN_TYPE_CXLA,
-	CMN_TYPE_CCRA,
-	CMN_TYPE_CCHA,
-	CMN_TYPE_CCLA,
-	CMN_TYPE_CCLA_RNI,
-	CMN_TYPE_HNS = 0x200,
-	CMN_TYPE_HNS_MPAM_S,
-	CMN_TYPE_HNS_MPAM_NS,
-	CMN_TYPE_APB = 0x1000,
-	/* Not a real node type */
-	CMN_TYPE_WP = 0x7770
-};
-
 enum cmn_filter_select {
 	SEL_NONE = -1,
 	SEL_OCCUP1ID,
diff --git a/drivers/ras/aest/Makefile b/drivers/ras/aest/Makefile
index 5ee10fc8b2e9..e5a45fde6d36 100644
--- a/drivers/ras/aest/Makefile
+++ b/drivers/ras/aest/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_AEST) 	+= aest.o
 aest-y		:= aest-core.o
 aest-y		+= aest-sysfs.o
 aest-y		+= aest-inject.o
+aest-y		+= aest-cmn.o
diff --git a/drivers/ras/aest/aest-cmn.c b/drivers/ras/aest/aest-cmn.c
new file mode 100644
index 000000000000..456203377c79
--- /dev/null
+++ b/drivers/ras/aest/aest-cmn.c
@@ -0,0 +1,332 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ARM Error Source Table CMN700 Support
+ *
+ * Copyright (c) 2025, Alibaba Inc
+ */
+
+#include "linux/bitfield.h"
+#include "linux/io.h"
+#include <asm/arm-cmn.h>
+
+#include "aest.h"
+
+/*
+ * CMN include 5 device types, each device type has an error group register set
+ * which contains a set of error records. The struct aest_cmn_700 represents
+ * one CMN Instance, and the struct aest_cmn_700_child represent one CMN device.
+ * The error record of CMN use memory-mapped single error record view, so one
+ * record is correspond to one AEST node, it means there will be hundreds of
+ * AEST node of CMN. As described in chapters 2.6.3.4 of Arm ACPI Spec[1], we
+ * use vendor define data to recognize the device type of an AEST node. So AEST
+ * driver can enumerate all CMN AEST node to initialize struct aest_cmn_700 and
+ * aest_cmn_700_child with HID, UID and other CMN info described in AEST or CMN
+ * register.
+ *
+ * Each CMN Instance has their own error interrupt and the struct aest_cmn_700
+ * is passed to interrupt context. OS check error group register set to locate
+ * record which report error. All procedure is similar with chapters 3.8 in
+ * Arm CMN Spec[2].
+ *
+ * The CMN RAS architecture is showed as follow:
+ *
+ *                     +----+
+ *                  -->|XP  |     ......
+ *                  |  +----+
+ *                  |
+ *                  |  +----+     ......
+ *                  |  |HNI |     +----------------+
+ *                  |  +----+   ->|record/AEST node|
+ *                  |           | +----------------+
+ *  +------------+  |  +----+   |    .
+ *  |CMN Instance|--|  |HNF |---|    .
+ *  +------------+  |  +----+   |    .
+ *                  |           | +----------------+
+ *                  |  +----+   ->|record/AEST node|
+ *                  |  |SBSX|     +----------------+
+ *                  |  +----+     ......
+ *                  |
+ *                  |  +----+
+ *                  -->|CCG |     ......
+ *                     +----+
+ *
+ * [1]: https://developer.arm.com/documentation/den0093/latest
+ * [2]: https://developer.arm.com/documentation/102308/latest
+ */
+
+#define CMN_RAS_DEV_NUM 6
+#define CMN700_ERRGSR_NUM 8
+#define CMN_MAX_UID 8
+#define CMN_ERRDEVARCH 0x3FB8
+#define CMN_ERRDEVARCH_REV GENMASK(19, 16)
+#define CMN_ERRGSR_OFFSET 0x3000
+
+struct cmn_vendor_data {
+	int node_type;
+	int node_id;
+	int logic_id;
+};
+
+struct cmn_config {
+	int errgsr_num;
+	int dev_num;
+	int ras_ver;
+	const int *node_id_map;
+	const char *const *node_name;
+	int (*errgsr_mapping)(int errgsr_bit);
+	u64 (*errgsr_offset)(u64 hnd_ofset, int node_idx);
+};
+
+static const char *const cmn700_node_name[] = {
+	[CMN_TYPE_HNI] = "HNI",	 [CMN_TYPE_HNF] = "HNF",
+	[CMN_TYPE_XP] = "XP",	 [CMN_TYPE_SBSX] = "SBSX",
+	[CMN_TYPE_CXRA] = "RND", [CMN_TYPE_MTSX] = "MTSX",
+};
+
+static const int cmn700_node_id_map[] = {
+	[CMN_TYPE_HNI] = 1,  [CMN_TYPE_HNF] = 2,  [CMN_TYPE_XP] = 0,
+	[CMN_TYPE_SBSX] = 3, [CMN_TYPE_CXRA] = 4, [CMN_TYPE_MTSX] = 5,
+};
+
+static u64 cmn_dev_array[CMN_MAX_UID];
+static struct cmn_config *cmn_config;
+
+static u64 cmn700_errgsr_offset(u64 hnd_offset, int node_idx)
+{
+	return hnd_offset + CMN_ERRGSR_OFFSET +
+	       (node_idx * 2) * CMN700_ERRGSR_NUM * 8;
+}
+
+static struct cmn_config cmn700_config = {
+	.errgsr_num = CMN700_ERRGSR_NUM,
+	.dev_num = CMN_RAS_DEV_NUM,
+	.ras_ver = 1,
+	.node_name = cmn700_node_name,
+	.node_id_map = cmn700_node_id_map,
+	.errgsr_mapping = cmn700_errgsr_mapping,
+	.errgsr_offset = cmn700_errgsr_offset,
+};
+
+static acpi_status aest_cmn_700_resource_ioremap(struct acpi_resource *res,
+						 void *data)
+{
+	struct acpi_resource_address64 addr64;
+	u32 *uid = data;
+	acpi_status status;
+
+	status = acpi_resource_to_address64(res, &addr64);
+	if (ACPI_FAILURE(status) || (addr64.resource_type != ACPI_MEMORY_RANGE))
+		return AE_OK;
+
+	cmn_dev_array[*uid] = (u64)ioremap(addr64.address.minimum,
+					   addr64.address.address_length);
+
+	pr_debug("CMN device resource [%llx-%llx] ioremap to %llx\n",
+		 addr64.address.minimum, addr64.address.maximum,
+		 cmn_dev_array[*uid]);
+
+	return AE_CTRL_TERMINATE;
+}
+
+static acpi_status aest_cmn_get_dev_by_uid(acpi_handle handle, u32 level,
+					   void *data, void **return_value)
+{
+	u32 *match_uid = data;
+	acpi_status status;
+	unsigned long long uid;
+
+	status = acpi_evaluate_integer(handle, METHOD_NAME__UID, NULL, &uid);
+	if (ACPI_FAILURE(status)) {
+		pr_err("Do not find devive\n");
+		return_ACPI_STATUS(status);
+	}
+
+	if (uid != *match_uid)
+		return AE_OK;
+
+	pr_debug("CMN device instance %llx, walk through resource\n", uid);
+
+	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
+				     aest_cmn_700_resource_ioremap, data);
+
+	if (ACPI_FAILURE(status)) {
+		pr_err("Device do not have resource\n");
+		return_ACPI_STATUS(status);
+	}
+
+	return AE_CTRL_TERMINATE;
+}
+
+static inline int aest_cmn_node_ver(void *base)
+{
+	return FIELD_GET(CMN_ERRDEVARCH_REV,
+			 readl_relaxed(base + CMN_ERRDEVARCH));
+}
+
+static int aest_cmn_init_node(struct aest_device *adev,
+			      struct aest_node *cmn_node,
+			      struct acpi_aest_node *anode, u64 type,
+			      u64 errgsr_addr)
+{
+	cmn_node->info = anode;
+	cmn_node->name = devm_kasprintf(adev->dev, GFP_KERNEL, "%s",
+					cmn_config->node_name[type]);
+	if (!cmn_node->name)
+		return -ENOMEM;
+	cmn_node->errgsr = (void *)errgsr_addr;
+	cmn_node->type = anode->type;
+	cmn_node->adev = adev;
+	cmn_node->version = cmn_config->ras_ver;
+	cmn_node->errgsr_num = cmn_config->errgsr_num;
+	cmn_node->errgsr_mapping = cmn_config->errgsr_mapping;
+	cmn_node->record_count = cmn_node->errgsr_num * BITS_PER_LONG / 2;
+	cmn_node->record_implemented = devm_bitmap_zalloc(
+		adev->dev, cmn_node->record_count, GFP_KERNEL);
+	if (!cmn_node->record_implemented)
+		return -ENOMEM;
+	bitmap_set(cmn_node->record_implemented, 0, cmn_node->record_count);
+
+	cmn_node->status_reporting = devm_bitmap_zalloc(
+		adev->dev, cmn_node->record_count, GFP_KERNEL);
+	if (!cmn_node->status_reporting)
+		return -ENOMEM;
+	bitmap_set(cmn_node->status_reporting, 0, cmn_node->record_count);
+
+	cmn_node->records = devm_kcalloc(adev->dev, cmn_node->record_count,
+					 sizeof(struct aest_record),
+					 GFP_KERNEL);
+	if (!cmn_node->records)
+		return -ENOMEM;
+
+	aest_node_dbg(cmn_node, "Node init with errgsr %llx\n", errgsr_addr);
+
+	return 0;
+}
+
+static int aest_cmn_reorgnize_node(struct aest_device *adev,
+				   struct acpi_aest_node *anode, u64 base)
+{
+	struct aest_node *cmn_node;
+	u64 hnd_offset, cmn_node_offset, reg, logic_id, type, node_id;
+	u64 errgsr_addr, hnd_base;
+	struct aest_record *record;
+	int ret, node_index;
+	struct cmn_vendor_data *vendor_data;
+
+	if (anode->interface_hdr->type !=
+	    ACPI_AEST_NODE_SINGLE_RECORD_MEMORY_MAPPED) {
+		aest_dev_err(adev, "CMN just use single memory mapping\n");
+		return -ENODEV;
+	}
+
+	hnd_offset = *((u64 *)anode->vendor->vendor_specific_data);
+	cmn_node_offset = *((u64 *)&anode->vendor->vendor_specific_data[8]);
+
+	reg = readq_relaxed((void *)base + cmn_node_offset + CMN_NODE_INFO);
+
+	logic_id = FIELD_GET(CMN_NI_LOGICAL_ID, reg);
+	type = FIELD_GET(CMN_NI_NODE_TYPE, reg);
+	node_id = FIELD_GET(CMN_NI_NODE_ID, reg);
+
+	hnd_base = base + hnd_offset;
+	node_index = cmn_config->node_id_map[type];
+	errgsr_addr = base + cmn_config->errgsr_offset(hnd_offset, node_index);
+
+	// node not register, create it
+	cmn_node = &adev->nodes[node_index];
+	if (!cmn_node->errgsr) {
+		ret = aest_cmn_init_node(adev, cmn_node, anode, type,
+					 errgsr_addr);
+		if (ret)
+			return -ENOMEM;
+	}
+
+	aest_dev_dbg(adev, "node type %llx, id %llx, offset %llx\n", type,
+		     logic_id, cmn_node_offset);
+
+	if (!test_bit(0, anode->record_implemented))
+		clear_bit(logic_id, cmn_node->record_implemented);
+
+	if (!test_bit(0, anode->status_reporting))
+		clear_bit(logic_id, cmn_node->status_reporting);
+
+	record = &cmn_node->records[logic_id];
+	record->name =
+		devm_kasprintf(adev->dev, GFP_KERNEL, "record%lld", logic_id);
+	if (!record->name)
+		return -ENOMEM;
+	record->regs_base = devm_ioremap(
+		adev->dev, (resource_size_t)anode->interface_hdr->address,
+		sizeof(struct ras_ext_regs));
+	if (!record->regs_base)
+		return -ENOMEM;
+	record->addressing_mode = test_bit(0, anode->addressing_mode);
+	record->node = cmn_node;
+	record->index = logic_id;
+	record->access = &aest_access[anode->interface_hdr->type];
+
+	vendor_data = devm_kzalloc(adev->dev, sizeof(struct cmn_vendor_data),
+				   GFP_KERNEL);
+	vendor_data->node_type = type;
+	vendor_data->node_id = node_id;
+	vendor_data->logic_id = logic_id;
+
+	record->vendor_data = vendor_data;
+	record->vendor_data_size = sizeof(struct cmn_vendor_data);
+
+	aest_record_dbg(record, "base %llx\n", anode->interface_hdr->address);
+
+	return 0;
+}
+
+// reorgnize cmn node
+static int aest_cmn_probe(struct aest_device *adev, struct aest_hnode *ahnode)
+{
+	acpi_status status;
+	u64 base;
+	int ret = 0;
+	struct acpi_aest_node *anode;
+	char name[9];
+
+	anode = list_first_entry(&ahnode->list, struct acpi_aest_node, list);
+	if (!anode)
+		return -ENODEV;
+
+	if (!cmn_dev_array[anode->vendor->acpi_uid]) {
+		snprintf(name, 9, "%s", anode->vendor->acpi_hid);
+		status = acpi_get_devices(name, aest_cmn_get_dev_by_uid,
+					  &anode->vendor->acpi_uid, NULL);
+		if (ACPI_FAILURE(status)) {
+			aest_dev_err(adev, "Can not find base\n");
+			return_ACPI_STATUS(status);
+		}
+	}
+	base = cmn_dev_array[anode->vendor->acpi_uid];
+	if (!base) {
+		aest_dev_err(adev, "Device base invalid\n");
+		return -ENODEV;
+	}
+
+	adev->type = anode->type;
+	adev->node_cnt = cmn_config->dev_num;
+	adev->nodes = devm_kcalloc(adev->dev, adev->node_cnt,
+				   sizeof(struct aest_node), GFP_KERNEL);
+	if (!adev->nodes)
+		return -ENOMEM;
+	aest_set_name(adev, ahnode);
+
+	list_for_each_entry(anode, &ahnode->list, list) {
+		ret = aest_cmn_reorgnize_node(adev, anode, base);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int aest_cmn700_probe(struct aest_device *adev, struct aest_hnode *ahnode)
+{
+	cmn_config = &cmn700_config;
+
+	return aest_cmn_probe(adev, ahnode);
+}
diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index 4d20e54832fd..33e1f32c5892 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -152,6 +152,8 @@ static void init_aest_event(struct aest_event *event,
 	memcpy(&event->regs, regs, sizeof(*regs));
 	event->index = record->index;
 	event->addressing_mode = record->addressing_mode;
+	event->vendor_data_size = record->vendor_data_size;
+	event->vendor_data = record->vendor_data;
 }
 
 static int aest_node_gen_pool_add(struct aest_device *adev,
@@ -344,10 +346,9 @@ void aest_proc_record(struct aest_record *record, void *data, bool fake)
 	record_write(record, ERXSTATUS, regs.err_status);
 }
 
-static void aest_node_foreach_record(void (*func)(struct aest_record *, void *,
-						  bool),
-				     struct aest_node *node, void *data,
-				     unsigned long *bitmap)
+void aest_node_foreach_record(void (*func)(struct aest_record *, void *, bool),
+			      struct aest_node *node, void *data,
+			      unsigned long *bitmap)
 {
 	int i;
 
@@ -362,7 +363,7 @@ static void aest_node_foreach_record(void (*func)(struct aest_record *, void *,
 
 static int aest_proc(struct aest_node *node)
 {
-	int count = 0, i, j, size = node->record_count;
+	int count = 0, i, j, size = node->record_count, record_idx;
 	u64 err_group = 0;
 
 	aest_node_dbg(node, "Poll bitmap %*pb\n", size,
@@ -377,19 +378,21 @@ static int aest_proc(struct aest_node *node)
 		      node->status_reporting);
 	for (i = 0; i < BITS_TO_U64(size); i++) {
 		err_group = readq_relaxed((void *)node->errgsr + i * 8);
-		aest_node_dbg(node, "errgsr[%d]: 0x%llx\n", i, err_group);
-
 		for_each_set_bit(j, (unsigned long *)&err_group,
 				 BITS_PER_LONG) {
+			record_idx =
+				node->errgsr_mapping(i * BITS_PER_LONG + j);
+			aest_node_dbg(node, "errgsr[%d]: bit %d occur error\n",
+				      i, record_idx);
 			/*
 			 * Error group base is only valid in Memory Map node,
 			 * so driver do not need to write select register and
 			 * sync.
 			 */
-			if (test_bit(i * BITS_PER_LONG + j,
-				     node->status_reporting))
+			if (test_bit(record_idx, node->status_reporting))
 				continue;
-			aest_proc_record(&node->records[j], &count, false);
+			aest_proc_record(&node->records[record_idx], &count,
+					 false);
 		}
 	}
 
@@ -401,8 +404,11 @@ static irqreturn_t aest_irq_func(int irq, void *input)
 	struct aest_device *adev = input;
 	int i;
 
-	for (i = 0; i < adev->node_cnt; i++)
+	for (i = 0; i < adev->node_cnt; i++) {
+		if (!adev->nodes[i].record_count)
+			continue;
 		aest_proc(&adev->nodes[i]);
+	}
 
 	return IRQ_HANDLED;
 }
@@ -779,6 +785,7 @@ static int aest_init_node(struct aest_device *adev, struct aest_node *node,
 	node->info = anode;
 	node->type = anode->type;
 	node->version = get_aest_node_ver(node);
+	node->errgsr_mapping = default_errgsr_mapping;
 	node->name = alloc_aest_node_name(node);
 	if (!node->name)
 		return -ENOMEM;
@@ -831,6 +838,7 @@ static int aest_init_node(struct aest_device *adev, struct aest_node *node,
 	if (!node->records)
 		return -ENOMEM;
 
+	node->errgsr_num = DIV_ROUND_UP(node->record_count, BITS_PER_LONG);
 	for (i = 0; i < node->record_count; i++) {
 		ret = aest_init_record(&node->records[i], i, node);
 		if (ret)
@@ -926,11 +934,12 @@ static int aest_setup_irq(struct platform_device *pdev,
 }
 
 static struct aest_vendor_match vendor_match[] = {
-	{  },
+	{ "ARMHC700", &aest_cmn700_probe },
+	{},
 };
 
-static int
-aest_vendor_probe(struct aest_device *adev, struct aest_hnode *ahnode)
+static int aest_vendor_probe(struct aest_device *adev,
+			     struct aest_hnode *ahnode)
 {
 	int i;
 	struct acpi_aest_node *anode;
@@ -939,13 +948,14 @@ aest_vendor_probe(struct aest_device *adev, struct aest_hnode *ahnode)
 	if (!anode)
 		return -ENODEV;
 
-	aest_dev_dbg(adev, "Try to probe vendor node %s\n", anode->vendor->acpi_hid);
+	aest_dev_dbg(adev, "Try to probe vendor node %s\n",
+		     anode->vendor->acpi_hid);
 	for (i = 0; i < ARRAY_SIZE(vendor_match); i++) {
 		if (!strncmp(vendor_match[i].hid, anode->vendor->acpi_hid, 8))
 			return vendor_match[i].probe(adev, ahnode);
 	}
 
-	return -ENODEV;
+	return 0;
 }
 
 static int aest_device_probe(struct platform_device *pdev)
diff --git a/drivers/ras/aest/aest.h b/drivers/ras/aest/aest.h
index 304c03839d31..9d67d79eb4a2 100644
--- a/drivers/ras/aest/aest.h
+++ b/drivers/ras/aest/aest.h
@@ -94,8 +94,16 @@ struct aest_event {
 	/* Vendor node	: hardware ID. */
 	char *hid;
 	u32 index;
+	u64 ce_threshold;
 	int addressing_mode;
 	struct ras_ext_regs regs;
+
+	/*
+	 * This field is used to store vendor specific data for decoding error
+	 * record by EDAC driver.
+	 */
+	void *vendor_data;
+	size_t vendor_data_size;
 };
 
 struct aest_access {
@@ -147,6 +155,9 @@ struct aest_record {
 	enum ras_ce_threshold threshold_type;
 	struct record_count count;
 	struct dentry *debugfs;
+
+	void *vendor_data;
+	size_t vendor_data_size;
 };
 
 struct aest_group {
@@ -208,6 +219,19 @@ struct aest_node {
 	 */
 	unsigned long *status_reporting;
 	int version;
+	/*
+	 * Usually bit[n] in errgsr indicates [n]th error record within this
+	 * error node report error. But some compoent may have different rules.
+	 * For example, CMN700 TRM 4.3.5.12 say:
+	 *	``` Error occurs when the index is even and Fault
+	 *	    occurs when the index is odd. ```
+	 *	Bit[n]: record[n] report ERROR.
+	 *	Bit[n + 1]: record[n] report FAULT.
+	 * errgsr_mapping function is used to map errgsr bit to record index
+	 * for various components.
+	 */
+	int (*errgsr_mapping)(int errgsr_bit);
+	int errgsr_num;
 
 	const struct aest_group *group;
 	struct aest_device *adev;
@@ -366,6 +390,21 @@ static inline bool aest_dev_is_oncore(struct aest_device *adev)
 	return adev->type == ACPI_AEST_PROCESSOR_ERROR_NODE;
 }
 
+static inline int default_errgsr_mapping(int errgsr_bit)
+{
+	return errgsr_bit;
+}
+
+static inline int cmn700_errgsr_mapping(int errgsr_bit)
+{
+	return errgsr_bit / 2;
+}
+
 void aest_dev_init_debugfs(struct aest_device *adev);
 void aest_inject_init_debugfs(struct aest_record *record);
 void aest_proc_record(struct aest_record *record, void *data, bool fake);
+void aest_node_foreach_record(void (*func)(struct aest_record *, void *, bool),
+			      struct aest_node *node, void *data,
+			      unsigned long *bitmap);
+
+int aest_cmn700_probe(struct aest_device *adev, struct aest_hnode *ahnode);
-- 
2.51.2.612.gdc70283dfc



From tomi.valkeinen at ideasonboard.com  Mon Dec 22 01:48:13 2025
From: tomi.valkeinen at ideasonboard.com (Tomi Valkeinen)
Date: Mon, 22 Dec 2025 11:48:13 +0200
Subject: [PATCH 0/3] drm: zynqmp: Make the video plane primary
In-Reply-To: <20251113203715.2768107-1-sean.anderson@linux.dev>
References: <20251113203715.2768107-1-sean.anderson@linux.dev>
Message-ID: <a7aa91ad-3f16-48b7-88f6-ea03c466f76c@ideasonboard.com>

Hi,

On 13/11/2025 22:37, Sean Anderson wrote:
> The graphics plane does not support XRGB8888, which is the default mode
> X uses for 24-bit color. Because of this, X must be set to use 16-bit
> color, which has a measurable performance penalty. Make the video plane
> the primary plane as it natively supports XRGB8888. An alternative
> approach to add XRGB8888 to the graphics plane is discussed in [1], as
> well as in patch 2.
> 
> [1] https://lore.kernel.org/dri-devel/20250627145058.6880-1-mike.looijmans at topic.nl/
> 
> 
> Sean Anderson (3):
>   drm: zynqmp: Check property creation status
>   drm: zynqmp: Make the video plane primary
>   drm: zynqmp: Add blend mode property to graphics plane
> 
>  drivers/gpu/drm/xlnx/zynqmp_kms.c | 42 +++++++++++++++++++++++++------
>  1 file changed, 34 insertions(+), 8 deletions(-)
> 

I made a test with pykms and tried this series with a few different
things. Afaics with this series the driver behaves as I would expect the
driver to behave. It makes sense to have the lower z-order plane as the
primary plane, especially as it supports the standard XRGB8888.

That said, I don't think there's anything that exactly would make the
current way of having GFX as primary wrong... So I still don't see a
single obvious solution to this whole issue.

A few thoughts:

If there is no regression here (i.e. this just has never worked well
with X/Weston), might the actual fix be in X/Weston? Is there an actual
bug in the xilinx driver?

On the other hand, I think it makes sense for drivers to (try to) expose
the HW in a common way. XRGB8888 is the standard format, so it makes
sense to expose XRGB8888 on primary plane. I think this is how the
driver should have behaved from the start. But if changing that now
would cause user space regressions, it's not good either.

 Tomi



From krzk at kernel.org  Mon Dec 22 01:53:31 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 22 Dec 2025 10:53:31 +0100
Subject: [PATCH v6 1/4] dt-bindings: clock: google,gs101-clock: add
 samsung,sysreg property as required
In-Reply-To: <CADrjBPoWcONhJJdCeovkwQ9Oha+t+dpHY_ohKPV7BQS1tougGw@mail.gmail.com>
References: <20251220-automatic-clocks-v6-0-36c2f276a135@linaro.org>
 <20251220-automatic-clocks-v6-1-36c2f276a135@linaro.org>
 <215eb434-683f-4cf2-9bcd-0860991ae23e@kernel.org>
 <CADrjBPoWcONhJJdCeovkwQ9Oha+t+dpHY_ohKPV7BQS1tougGw@mail.gmail.com>
Message-ID: <d7a749e2-1d00-459f-adbb-0841190b7849@kernel.org>

On 22/12/2025 10:39, Peter Griffin wrote:
> Hi Krzysztof,
> 
> On Sun, 21 Dec 2025 at 13:26, Krzysztof Kozlowski <krzk at kernel.org> wrote:
>>
>> On 20/12/2025 10:05, Peter Griffin wrote:
>>> Each CMU (with the exception of cmu_top) has a corresponding sysreg bank
>>> that contains the BUSCOMPONENT_DRCG_EN and optional MEMCLK registers.
>>> The BUSCOMPONENT_DRCG_EN register enables dynamic root clock gating of
>>> bus components and MEMCLK gates the sram clock.
>>>
>>> Now the clock driver supports automatic clock mode, to fully enable dynamic
>>> root clock gating it is required to configure these registers. Update the
>>> bindings documentation so that all CMUs (with the exception of
>>> gs101-cmu-top) have samsung,sysreg as a required property.
>>>
>>> Note this is NOT an ABI break, as if the property isn't specified the
>>> clock driver will fallback to the current behaviour of not initializing
>>> the registers. The system still boots, but bus components won't benefit
>>> from dynamic root clock gating and dynamic power will be higher (which has
>>> been the case until now anyway).
>>>
>>> Additionally update the DT example to included the correct CMU size as
>>> registers in that region are used for automatic clock mode.
>>>
>>> Signed-off-by: Peter Griffin <peter.griffin at linaro.org>
>>> ---
>>> Changes in v5:
>>> - Invert the test for google,gs101-cmu-top (Andre)
>>>
>>
>>
>> <form letter>
>> This is a friendly reminder during the review process.
>>
>> It looks like you received a tag and forgot to add it.
>>
>> If you do not know the process, here is a short explanation:
>> Please add Acked-by/Reviewed-by/Tested-by tags when posting new versions
>> of patchset, under or above your Signed-off-by tag, unless patch changed
>> significantly (e.g. new properties added to the DT bindings). Tag is
>> "received", when provided in a message replied to you on the mailing
>> list. Tools like b4 can help here. However, there's no need to repost
>> patches *only* to add the tags. The upstream maintainer will do that for
>> tags received on the version they apply.
>>
>> Please read:
>> https://elixir.bootlin.com/linux/v6.12-rc3/source/Documentation/process/submitting-patches.rst#L577
>>
>> If a tag was not added on purpose, please state why and what changed.
>> </form letter>
> 
> Apologies, your tag should have been added.... got kind of sidetracked
> bisecting the linux-next regression with the serial console and then
> forgot to apply it.

I think it was more than one tag, so I decided not to look for them.
Please send v7 with all tags collected.

Best regards,
Krzysztof


From jim.cromie at gmail.com  Mon Dec 22 00:20:36 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:36 +1300
Subject: [PATCH v7 19/31] selftests-dyndbg: add a dynamic_debug run_tests target
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-20-jim.cromie@gmail.com>

Add a selftest script for dynamic-debug.  The config requires
CONFIG_TEST_DYNAMIC_DEBUG=m and CONFIG_TEST_DYNAMIC_DEBUG_SUBMOD=m,
which tacitly requires either CONFIG_DYNAMIC_DEBUG=y or
CONFIG_DYNAMIC_DEBUG_CORE=y

ATM this has just basic_tests(), which modify pr_debug() flags in the
builtin params module.  This means they're available to manipulate and
observe the effects in "cat control".

This is backported from another feature branch; the support-fns (thx
Lukas) have unused features at the moment, they'll get used shortly.

The script enables simple virtme-ng testing:

   [jimc at gandalf b0-ftrace]$ vrun_t
   virtme-ng 1.32+115.g07b109d
   doing: vng --name v6.14-rc4-60-gd5f48427de0c \
	  --user root -v -p 4 -a dynamic_debug.verbose=3 V=1 \
	  -- ../tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh
   virtme: waiting for virtiofsd to start
   ..

And add dynamic_debug to TARGETS, so `make run_tests` sees it properly
For the impatient, set TARGETS explicitly:

  [root at v6 selftests]# make TARGETS=dynamic_debug run_tests
  make[1]: Nothing to be done for 'all'.
  TAP version 13
  1..1
  # timeout set to 45
  # selftests: dynamic_debug: dyndbg_selftest.sh
  # # BASIC_TESTS    95.422122] dyndbg: query 0: 0"=_" mod:*
  ...

NOTES

check KCONFIG_CONFIG to avoid silly fails

Several tests are dependent upon config choices. Lets avoid failing
where that is noise.

The KCONFIG_CONFIG var exists to convey the config-file around.  If
the var names a file, read it and extract the relevant CONFIG items,
and use them to skip the dependent tests, thus avoiding the fails that
would follow, and the disruption to whatever CI is running these
selftests.

If the envar doesn't name a config-file, ".config" is assumed.

CONFIG_DYNAMIC_DEBUG=y:

basic-tests() and comma-terminator-tests() test for the presence of
the builtin pr_debugs in module/main.c, which I deemed stable and
therefore safe to count.  That said, the test fails if only
CONFIG_DYNAMIC_DEBUG_CORE=y is set.  It could be rewritten to test
against test-dynamic-debug.ko, but that just trades one config
dependence for another.

CONFIG_TEST_DYNAMIC_DEBUG=m

As written, test_percent_splitting() modprobes test_dynamic_debug,
enables several classes, and counts them.  It could be re-written to
work for the builtin module also, but builtin test modules are not a
common or desirable build/config.

Co-developed-by: ?ukasz Bartosik <ukaszb at chromium.org>
Signed-off-by: ?ukasz Bartosik <ukaszb at chromium.org>
Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 MAINTAINERS                                   |   1 +
 tools/testing/selftests/Makefile              |   1 +
 .../testing/selftests/dynamic_debug/Makefile  |   9 +
 tools/testing/selftests/dynamic_debug/config  |   7 +
 .../dynamic_debug/dyndbg_selftest.sh          | 257 ++++++++++++++++++
 5 files changed, 275 insertions(+)
 create mode 100644 tools/testing/selftests/dynamic_debug/Makefile
 create mode 100644 tools/testing/selftests/dynamic_debug/config
 create mode 100755 tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh

diff --git a/MAINTAINERS b/MAINTAINERS
index e8f06145fb54..b9d38a5b4f12 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8772,6 +8772,7 @@ S:	Maintained
 F:	include/linux/dynamic_debug.h
 F:	lib/dynamic_debug.c
 F:	lib/test_dynamic_debug.c
+F:	tools/testing/selftests/dynamic_debug/*
 
 DYNAMIC INTERRUPT MODERATION
 M:	Tal Gilboa <talgi at nvidia.com>
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index c46ebdb9b8ef..8a2542006e23 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -26,6 +26,7 @@ TARGETS += drivers/net/team
 TARGETS += drivers/net/virtio_net
 TARGETS += drivers/platform/x86/intel/ifs
 TARGETS += dt
+TARGETS += dynamic_debug
 TARGETS += efivarfs
 TARGETS += exec
 TARGETS += fchmodat2
diff --git a/tools/testing/selftests/dynamic_debug/Makefile b/tools/testing/selftests/dynamic_debug/Makefile
new file mode 100644
index 000000000000..6d06fa7f1040
--- /dev/null
+++ b/tools/testing/selftests/dynamic_debug/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# borrowed from Makefile for user memory selftests
+
+# No binaries, but make sure arg-less "make" doesn't trigger "run_tests"
+all:
+
+TEST_PROGS := dyndbg_selftest.sh
+
+include ../lib.mk
diff --git a/tools/testing/selftests/dynamic_debug/config b/tools/testing/selftests/dynamic_debug/config
new file mode 100644
index 000000000000..0f906ff53908
--- /dev/null
+++ b/tools/testing/selftests/dynamic_debug/config
@@ -0,0 +1,7 @@
+
+# basic tests ref the builtin params module
+CONFIG_DYNAMIC_DEBUG=m
+
+# more testing is possible with these
+# CONFIG_TEST_DYNAMIC_DEBUG=m
+# CONFIG_TEST_DYNAMIC_DEBUG_SUBMOD=m
diff --git a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh
new file mode 100755
index 000000000000..465fad3f392c
--- /dev/null
+++ b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh
@@ -0,0 +1,257 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0-only
+
+V=${V:=0}  # invoke as V=1 $0  for global verbose
+RED="\033[0;31m"
+GREEN="\033[0;32m"
+YELLOW="\033[0;33m"
+BLUE="\033[0;34m"
+MAGENTA="\033[0;35m"
+CYAN="\033[0;36m"
+NC="\033[0;0m"
+error_msg=""
+
+[ -e /proc/dynamic_debug/control ] || {
+    echo -e "${RED}: this test requires CONFIG_DYNAMIC_DEBUG=y ${NC}"
+    exit 0 # nothing to test here, no good reason to fail.
+}
+
+# need info to avoid failures due to untestable configs
+
+[ -f "$KCONFIG_CONFIG" ] || KCONFIG_CONFIG=".config"
+if [ -f "$KCONFIG_CONFIG" ]; then
+    echo "# consulting KCONFIG_CONFIG: $KCONFIG_CONFIG"
+    grep -q "CONFIG_DYNAMIC_DEBUG=y" $KCONFIG_CONFIG ; LACK_DD_BUILTIN=$?
+    grep -q "CONFIG_TEST_DYNAMIC_DEBUG=m" $KCONFIG_CONFIG ; LACK_TMOD=$?
+    grep -q "CONFIG_TEST_DYNAMIC_DEBUG_SUBMOD=m" $KCONFIG_CONFIG ; LACK_TMOD_SUBMOD=$?
+    if [ $V -eq 1 ]; then
+	echo LACK_DD_BUILTIN: $LACK_DD_BUILTIN
+	echo LACK_TMOD: $LACK_TMOD
+	echo LACK_TMOD_SUBMOD: $LACK_TMOD_SUBMOD
+    fi
+else
+    LACK_DD_BUILTIN=0
+    LACK_TMOD=0
+    LACK_TMOD_SUBMOD=0
+fi
+
+function vx () {
+    echo $1 > /sys/module/dynamic_debug/parameters/verbose
+}
+
+function ddgrep () {
+    grep $1 /proc/dynamic_debug/control
+}
+
+function doprints () {
+    cat /sys/module/test_dynamic_debug/parameters/do_prints
+}
+
+function ddcmd () {
+    exp_exit_code=0
+    num_args=$#
+    if [ "${@:$#}" = "pass" ]; then
+	num_args=$#-1
+    elif [ "${@:$#}" = "fail" ]; then
+        num_args=$#-1
+	exp_exit_code=1
+    fi
+    args=${@:1:$num_args}
+    output=$((echo "$args" > /proc/dynamic_debug/control) 2>&1)
+    exit_code=$?
+    error_msg=$(echo $output | cut -d ":" -f 5 | sed -e 's/^[[:space:]]*//')
+    handle_exit_code $BASH_LINENO $FUNCNAME $exit_code $exp_exit_code
+}
+
+function handle_exit_code() {
+    local exp_exit_code=0
+    [ $# == 4 ] && exp_exit_code=$4
+    if [ $3 -ne $exp_exit_code ]; then
+        echo -e "${RED}: $BASH_SOURCE:$1 $2() expected to exit with code $exp_exit_code"
+	[ $3 == 1 ] && echo "Error: '$error_msg'"
+        exit
+    fi
+}
+
+# $1 - pattern to match, pattern in $1 is enclosed by spaces for a match ""\s$1\s"
+# $2 - number of times the pattern passed in $1 is expected to match
+# $3 - optional can be set either to "-r" or "-v"
+#       "-r" means relaxed matching in this case pattern provided in $1 is passed
+#       as is without enclosing it with spaces
+#       "-v" prints matching lines
+# $4 - optional when $3 is set to "-r" then $4 can be used to pass "-v"
+function check_match_ct {
+    pattern="\s$1\s"
+    exp_cnt=0
+
+    [ "$3" == "-r" ] && pattern="$1"
+    let cnt=$(ddgrep "$pattern" | wc -l)
+    if [ $V -eq 1 ] || [ "$3" == "-v" ] || [ "$4" == "-v" ]; then
+        echo -ne "${BLUE}" && ddgrep $pattern && echo -ne "${NC}"
+    fi
+    [ $# -gt 1 ] && exp_cnt=$2
+    if [ $cnt -ne $exp_cnt ]; then
+        echo -e "${RED}: $BASH_SOURCE:$BASH_LINENO check failed expected $exp_cnt on $1, got $cnt"
+        exit
+    else
+        echo ": $cnt matches on $1"
+    fi
+}
+
+# $1 - trace instance name
+# #2 - if > 0 then directory is expected to exist, if <= 0 then otherwise
+# $3 - "-v" for verbose
+function check_trace_instance_dir {
+    if [ -e /sys/kernel/tracing/instances/$1 ]; then
+        if [ "$3" == "-v" ] ; then
+            echo "ls -l /sys/kernel/tracing/instances/$1: "
+            ls -l /sys/kernel/tracing/instances/$1
+        fi
+	if [ $2 -le 0 ]; then
+            echo -e "${RED}: $BASH_SOURCE:$BASH_LINENO error trace instance \
+		    '/sys/kernel/tracing/instances/$1' does exist"
+	    exit
+	fi
+    else
+	if [ $2 -gt 0 ]; then
+            echo -e "${RED}: $BASH_SOURCE:$BASH_LINENO error trace instance \
+		    '/sys/kernel/tracing/instances/$1' does not exist"
+	    exit
+        fi
+    fi
+}
+
+function tmark {
+    echo $* > /sys/kernel/tracing/trace_marker
+}
+
+# $1 - trace instance name
+# $2 - line number
+# $3 - if > 0 then the instance is expected to be opened, otherwise
+# the instance is expected to be closed
+function check_trace_instance {
+    output=$(tail -n9 /proc/dynamic_debug/control | grep ": Opened trace instances" \
+	    | xargs -n1 | grep $1)
+    if [ "$output" != $1 ] && [ $3 -gt 0 ]; then
+        echo -e "${RED}: $BASH_SOURCE:$2 trace instance $1 is not opened"
+        exit
+    fi
+    if [ "$output" == $1 ] && [ $3 -le 0 ]; then
+        echo -e "${RED}: $BASH_SOURCE:$2 trace instance $1 is not closed"
+        exit
+    fi
+}
+
+function is_trace_instance_opened {
+    check_trace_instance $1 $BASH_LINENO 1
+}
+
+function is_trace_instance_closed {
+    check_trace_instance $1 $BASH_LINENO 0
+}
+
+# $1 - trace instance directory to delete
+# $2 - if > 0 then directory is expected to be deleted successfully, if <= 0 then otherwise
+function del_trace_instance_dir() {
+    exp_exit_code=1
+    [ $2 -gt 0 ] && exp_exit_code=0
+    output=$((rmdir /sys/kernel/debug/tracing/instances/$1) 2>&1)
+    exit_code=$?
+    error_msg=$(echo $output | cut -d ":" -f 3 | sed -e 's/^[[:space:]]*//')
+    handle_exit_code $BASH_LINENO $FUNCNAME $exit_code $exp_exit_code
+}
+
+function error_log_ref {
+    # to show what I got
+    : echo "# error-log-ref: $1"
+    : echo cat \$2
+}
+
+function ifrmmod {
+    lsmod | grep $1 2>&1>/dev/null && rmmod $1
+}
+
+# $1 - text to search for
+function search_trace() {
+    search_trace_name 0 1 $1
+}
+
+# $1 - trace instance name, 0 for global event trace
+# $2 - line number counting from the bottom
+# $3 - text to search for
+function search_trace_name() {
+	if [ "$1" = "0" ]; then
+	    buf=$(cat /sys/kernel/debug/tracing/trace)
+	    line=$(tail -$2 /sys/kernel/debug/tracing/trace | head -1 | sed -e 's/^[[:space:]]*//')
+	else
+	    buf=$(cat /sys/kernel/debug/tracing/instances/$1/trace)
+	    line=$(tail -$2 /sys/kernel/debug/tracing/instances/$1/trace | head -1 | \
+		   sed -e 's/^[[:space:]]*//')
+	fi
+	if [ $2 = 0 ]; then
+	    # whole-buf check
+	    output=$(echo $buf | grep "$3")
+	else
+	    output=$(echo $line | grep "$3")
+	fi
+	if [ "$output" = "" ]; then
+            echo -e "${RED}: $BASH_SOURCE:$BASH_LINENO search for '$3' failed \
+		    in line '$line' or '$buf'"
+	    exit
+	fi
+	if [ $V = 1 ]; then
+	    echo -e "${MAGENTA}: search_trace_name in $1 found: \n$output \nin:${BLUE} $buf ${NC}"
+        fi
+}
+
+# $1 - error message to check
+function check_err_msg() {
+    if [ "$error_msg" != "$1" ]; then
+        echo -e "${RED}: $BASH_SOURCE:$BASH_LINENO error message '$error_msg' \
+		does not match with '$1'"
+        exit
+    fi
+}
+
+function basic_tests {
+    echo -e "${GREEN}# BASIC_TESTS ${NC}"
+    if [ $LACK_DD_BUILTIN -eq 1 ]; then
+	echo "SKIP"
+	return
+    fi
+    ddcmd =_ # zero everything
+    check_match_ct =p 0
+
+    # module params are builtin to handle boot args
+    check_match_ct '\[params\]' 4 -r
+    ddcmd module params +mpf
+    check_match_ct =pmf 4
+
+    # multi-cmd input, newline separated, with embedded comments
+    cat <<"EOF" > /proc/dynamic_debug/control
+      module params =_				# clear params
+      module params +mf				# set flags
+      module params func parse_args +sl		# other flags
+EOF
+    check_match_ct =mf 3
+    check_match_ct =mfsl 1
+    ddcmd =_
+}
+
+tests_list=(
+    basic_tests
+)
+
+# Run tests
+
+ifrmmod test_dynamic_debug_submod
+ifrmmod test_dynamic_debug
+
+for test in "${tests_list[@]}"
+do
+    $test
+    echo ""
+done
+echo -en "${GREEN}# Done on: "
+date
+echo -en "${NC}"
-- 
2.52.0



From krzk at kernel.org  Mon Dec 22 01:58:52 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 22 Dec 2025 10:58:52 +0100
Subject: [PATCH] arm64: dts: lg: Use recommended simple-bus node name
In-Reply-To: <20251216175951.2791921-2-robh@kernel.org>
References: <20251216175951.2791921-2-robh@kernel.org>
Message-ID: <176639753214.30319.18070408035908204137.b4-ty@kernel.org>


On Tue, 16 Dec 2025 11:59:52 -0600, Rob Herring (Arm) wrote:
> Update LG LG131x 'amba' bus node name to 'amba-bus' following the
> standard names for simple-bus nodes. Generally, node names and paths
> aren't considered ABI, so it is safe to change them.
> 
> 

Applied, thanks!

[1/1] arm64: dts: lg: Use recommended simple-bus node name
      https://git.kernel.org/krzk/linux-dt/c/30ae13173704585f2a3f406e94e0dbaa5cfde69a

Best regards,
-- 
Krzysztof Kozlowski <krzk at kernel.org>



From quic_nihalkum at quicinc.com  Mon Dec 22 01:59:09 2025
From: quic_nihalkum at quicinc.com (Nihal Kumar Gupta)
Date: Mon, 22 Dec 2025 15:29:09 +0530
Subject: [PATCH v8 0/5] Add CCI and imx577 sensor support for monaco evk
Message-ID: <20251222095914.1995041-1-quic_nihalkum@quicinc.com>

From: nihalkum <nihalkum at qti.qualcomm.com>

Monaco EVK is a single-board computer based on the Qualcomm QCS8300 SoC.
It lacks a camera sensor in its default configuration.
This series adds CCI support and enables the IMX577 sensor via CSIPHY1
through device tree overlay.

We have tested IMX577 Sensor on CCI1 with following commands:
- media-ctl --reset
- media-ctl -V '"imx577 3-001a":0[fmt:SRGGB10/4056x3040 field:none]'
- media-ctl -V '"msm_csiphy1":0[fmt:SRGGB10/4056x3040]'
- media-ctl -V '"msm_csid0":0[fmt:SRGGB10/4056x3040]'
- media-ctl -V '"msm_vfe0_rdi0":0[fmt:SRGGB10/4056x3040]'
- media-ctl -l '"msm_csiphy1":1->"msm_csid0":0[1]'
- media-ctl -l '"msm_csid0":1->"msm_vfe0_rdi0":0[1]'
- yavta -B capture-mplane -c -I -n 5 -f SRGGB10P -s 4056x3040 -F /dev/video1
---

This patch series depends on patch series:
https://lore.kernel.org/all/20251107162521.511536-1-quic_vikramsa at quicinc.com

Bindings for Supplies are added by below patch:
https://lore.kernel.org/all/20251107162521.511536-1-quic_vikramsa at quicinc.com

Changes in v8:
- Removed clock-lanes property from CAMSS node - Vladimir
- Changed data-lanes property to <1 2 3 4> on sensor node - Vladimir
- Sorted regulator entries with respect to the pin index - Konrad
- Link to v7:
  https://lore.kernel.org/all/20251216062223.2474216-1-quic_nihalkum at quicinc.com

Changes in v7:
- Define MCLK pinctrl definitions in monaco.dtsi - Konrad and Vladimir
- Define fixed regulators for camera AVDD rails in monaco-evk.dts - Konrad
- Link to v6:
  https://lore.kernel.org/all/20251126081057.4191122-1-quic_vikramsa at quicinc.com

Changes in v6:
- Fixed ordering of property-n and property-names in vreg_cam1_2p8 - Konrad 
- Moved vreg_cam1_2p8 defintion to monaco-evk.dts - Konrad
- Removed description of pins with MCLK and Regulators function - Konrad
- Added pin hardware description for MCLK, regulators in monaco.dtsi - Konrad
- Link to v5:
  https://lore.kernel.org/all/20251114064541.446276-1-quic_vikramsa at quicinc.com

Changes in v5:
- Rename cciX_i2cY_* to cciX_Y_* to shorten the labels - Vladimir 
- Added description of pins with MCLK function - Vladimir 
- Link to v4:
  https://lore.kernel.org/all/20251015131303.2797800-1-quic_vikramsa at quicinc.com

Changes in v4:
- Remove the AXI source clock from the CCI node - Konrad
- Updated the qcs8300-camss device tree binding.
- Link to v3:
  https://lore.kernel.org/all/20250917130647.1701883-1-quic_vikramsa at quicinc.com

Changes in v3:
- Updated and Wrapped commit messages for [PATCH v2 1/3] and [PATCH v2 2/3] - Rob
- Link to v2:
  https://lore.kernel.org/all/20250912141134.2799078-1-quic_vikramsa at quicinc.com

Changes in v2:
- Remove the patch that adds PHY supply documentation in the qcs8300 CAMSS. 
  bindings. This change should be submitted together with the qcs8300 bindings patch.
- Fix indentation and regulator node name - Krzysztof.
- Update commit message as suggested - Dmitry.
- Link to v1:
  https://lore.kernel.org/lkml/20250909114241.840842-1-quic_vikramsa at quicinc.com

Used following tools for the sanity check of these changes.
- make -j32 W=1
- checkpatch.pl
- make DT_CHECKER_FLAGS=-m W=1 DT_SCHEMA_FILES=i2c/qcom,i2c-cci.yaml dt_binding_check
- make CHECK_DTBS=y W=1 DT_SCHEMA_FILES=i2c/qcom,i2c-cci.yaml
- make DT_CHECKER_FLAGS=-m W=1 DT_SCHEMA_FILES=media/qcom,qcs8300-camss.yaml dt_binding_check
- make CHECK_DTBS=y W=1 DT_SCHEMA_FILES=media/qcom,qcs8300-camss.yaml

Signed-off-by: Nihal Kumar Gupta <quic_nihalkum at quicinc.com>
Signed-off-by: Vikram Sharma <quic_vikramsa at quicinc.com>

Nihal Kumar Gupta (5):
  dt-bindings: i2c: qcom-cci: Document qcs8300 compatible
  arm64: dts: qcom: monaco: Add CCI definitions
  arm64: dts: qcom: monaco: Add camera MCLK pinctrl
  arm64: dts: qcom: monaco-evk: Add camera AVDD regulators
  arm64: dts: qcom: monaco-evk-camera: Add DT overlay

 .../devicetree/bindings/i2c/qcom,i2c-cci.yaml |   2 +
 arch/arm64/boot/dts/qcom/Makefile             |   4 +
 .../dts/qcom/monaco-evk-camera-imx577.dtso    |  66 ++++
 arch/arm64/boot/dts/qcom/monaco-evk.dts       |  51 +++
 arch/arm64/boot/dts/qcom/monaco.dtsi          | 324 ++++++++++++++++++
 5 files changed, 447 insertions(+)
 create mode 100644 arch/arm64/boot/dts/qcom/monaco-evk-camera-imx577.dtso

-- 
2.34.1



From quic_nihalkum at quicinc.com  Mon Dec 22 01:59:10 2025
From: quic_nihalkum at quicinc.com (Nihal Kumar Gupta)
Date: Mon, 22 Dec 2025 15:29:10 +0530
Subject: [PATCH v8 1/5] dt-bindings: i2c: qcom-cci: Document qcs8300 compatible
In-Reply-To: <20251222095914.1995041-1-quic_nihalkum@quicinc.com>
References: <20251222095914.1995041-1-quic_nihalkum@quicinc.com>
Message-ID: <20251222095914.1995041-2-quic_nihalkum@quicinc.com>

The three instances of CCI found on the QCS8300 are functionally the same
as on a number of existing Qualcomm SoCs.

Introduce a new SoC-specific compatible string "qcom,qcs8300-cci" with a
common fallback.

Signed-off-by: Nihal Kumar Gupta <quic_nihalkum at quicinc.com>
Signed-off-by: Vikram Sharma <quic_vikramsa at quicinc.com>
Reviewed-by: Bryan O'Donoghue <bryan.odonoghue at linaro.org>
Acked-by: Rob Herring (Arm) <robh at kernel.org>
Reviewed-by: Vladimir Zapolskiy <vladimir.zapolskiy at linaro.org>
---
 Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml
index a3fe1eea6aec..399a09409e07 100644
--- a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml
+++ b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml
@@ -28,6 +28,7 @@ properties:
           - enum:
               - qcom,kaanapali-cci
               - qcom,qcm2290-cci
+              - qcom,qcs8300-cci
               - qcom,sa8775p-cci
               - qcom,sc7280-cci
               - qcom,sc8280xp-cci
@@ -133,6 +134,7 @@ allOf:
             enum:
               - qcom,kaanapali-cci
               - qcom,qcm2290-cci
+              - qcom,qcs8300-cci
               - qcom,sm8750-cci
     then:
       properties:
-- 
2.34.1



From quic_nihalkum at quicinc.com  Mon Dec 22 01:59:11 2025
From: quic_nihalkum at quicinc.com (Nihal Kumar Gupta)
Date: Mon, 22 Dec 2025 15:29:11 +0530
Subject: [PATCH v8 2/5] arm64: dts: qcom: monaco: Add CCI definitions
In-Reply-To: <20251222095914.1995041-1-quic_nihalkum@quicinc.com>
References: <20251222095914.1995041-1-quic_nihalkum@quicinc.com>
Message-ID: <20251222095914.1995041-3-quic_nihalkum@quicinc.com>

Qualcomm QCS8300 SoC contains three Camera Control Interface (CCI).
Compared to Lemans, the key difference is in SDA/SCL GPIO assignments
and number of CCIs.

Signed-off-by: Nihal Kumar Gupta <quic_nihalkum at quicinc.com>
Co-developed-by: Ravi Shankar <quic_rshankar at quicinc.com>
Signed-off-by: Ravi Shankar <quic_rshankar at quicinc.com>
Co-developed-by: Vishal Verma <quic_vishverm at quicinc.com>
Signed-off-by: Vishal Verma <quic_vishverm at quicinc.com>
Co-developed-by: Suresh Vankadara <quic_svankada at quicinc.com>
Signed-off-by: Suresh Vankadara <quic_svankada at quicinc.com>
Signed-off-by: Vikram Sharma <quic_vikramsa at quicinc.com>
Reviewed-by: Vladimir Zapolskiy <vladimir.zapolskiy at linaro.org>
Reviewed-by: Bryan O'Donoghue <bryan.odonoghue at linaro.org>
Reviewed-by: Konrad Dybcio <konrad.dybcio at oss.qualcomm.com>
---
 arch/arm64/boot/dts/qcom/monaco.dtsi | 303 +++++++++++++++++++++++++++
 1 file changed, 303 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/monaco.dtsi b/arch/arm64/boot/dts/qcom/monaco.dtsi
index 774255c3f6fc..4b2d8a449b00 100644
--- a/arch/arm64/boot/dts/qcom/monaco.dtsi
+++ b/arch/arm64/boot/dts/qcom/monaco.dtsi
@@ -4776,6 +4776,117 @@ videocc: clock-controller at abf0000 {
 			#power-domain-cells = <1>;
 		};
 
+		cci0: cci at ac13000 {
+			compatible = "qcom,qcs8300-cci", "qcom,msm8996-cci";
+			reg = <0x0 0x0ac13000 0x0 0x1000>;
+
+			interrupts = <GIC_SPI 460 IRQ_TYPE_EDGE_RISING>;
+
+			clocks = <&camcc CAM_CC_CPAS_AHB_CLK>,
+				 <&camcc CAM_CC_CCI_0_CLK>;
+			clock-names = "cpas_ahb",
+				      "cci";
+
+			power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>;
+
+			pinctrl-0 = <&cci0_0_default &cci0_1_default>;
+			pinctrl-1 = <&cci0_0_sleep &cci0_1_sleep>;
+			pinctrl-names = "default", "sleep";
+
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			status = "disabled";
+
+			cci0_i2c0: i2c-bus at 0 {
+				reg = <0>;
+				clock-frequency = <1000000>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+
+			cci0_i2c1: i2c-bus at 1 {
+				reg = <1>;
+				clock-frequency = <1000000>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+		};
+
+		cci1: cci at ac14000 {
+			compatible = "qcom,qcs8300-cci", "qcom,msm8996-cci";
+			reg = <0x0 0x0ac14000 0x0 0x1000>;
+
+			interrupts = <GIC_SPI 271 IRQ_TYPE_EDGE_RISING>;
+
+			clocks = <&camcc CAM_CC_CPAS_AHB_CLK>,
+				 <&camcc CAM_CC_CCI_1_CLK>;
+			clock-names = "cpas_ahb",
+				      "cci";
+
+			power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>;
+
+			pinctrl-0 = <&cci1_0_default &cci1_1_default>;
+			pinctrl-1 = <&cci1_0_sleep &cci1_1_sleep>;
+			pinctrl-names = "default", "sleep";
+
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			status = "disabled";
+
+			cci1_i2c0: i2c-bus at 0 {
+				reg = <0>;
+				clock-frequency = <1000000>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+
+			cci1_i2c1: i2c-bus at 1 {
+				reg = <1>;
+				clock-frequency = <1000000>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+		};
+
+		cci2: cci at ac15000 {
+			compatible = "qcom,qcs8300-cci", "qcom,msm8996-cci";
+			reg = <0x0 0x0ac15000 0x0 0x1000>;
+
+			interrupts = <GIC_SPI 651 IRQ_TYPE_EDGE_RISING>;
+
+			clocks = <&camcc CAM_CC_CPAS_AHB_CLK>,
+				 <&camcc CAM_CC_CCI_2_CLK>;
+			clock-names = "cpas_ahb",
+				      "cci";
+
+			power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>;
+
+			pinctrl-0 = <&cci2_0_default &cci2_1_default>;
+			pinctrl-1 = <&cci2_0_sleep &cci2_1_sleep>;
+			pinctrl-names = "default", "sleep";
+
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			status = "disabled";
+
+			cci2_i2c0: i2c-bus at 0 {
+				reg = <0>;
+				clock-frequency = <1000000>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+
+			cci2_i2c1: i2c-bus at 1 {
+				reg = <1>;
+				clock-frequency = <1000000>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+		};
+
 		camss: isp at ac78000 {
 			compatible = "qcom,qcs8300-camss";
 
@@ -5071,6 +5182,198 @@ tlmm: pinctrl at f100000 {
 			#interrupt-cells = <2>;
 			wakeup-parent = <&pdc>;
 
+			cci0_0_default: cci0-0-default-state {
+				sda-pins {
+					pins = "gpio57";
+					function = "cci_i2c_sda";
+					drive-strength = <2>;
+					bias-pull-up = <2200>;
+				};
+
+				scl-pins {
+					pins = "gpio58";
+					function = "cci_i2c_scl";
+					drive-strength = <2>;
+					bias-pull-up = <2200>;
+				};
+			};
+
+			cci0_0_sleep: cci0-0-sleep-state {
+				sda-pins {
+					pins = "gpio57";
+					function = "cci_i2c_sda";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+
+				scl-pins {
+					pins = "gpio58";
+					function = "cci_i2c_scl";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+
+			cci0_1_default: cci0-1-default-state {
+				sda-pins {
+					pins = "gpio29";
+					function = "cci_i2c_sda";
+					drive-strength = <2>;
+					bias-pull-up = <2200>;
+				};
+
+				scl-pins {
+					pins = "gpio30";
+					function = "cci_i2c_scl";
+					drive-strength = <2>;
+					bias-pull-up = <2200>;
+				};
+			};
+
+			cci0_1_sleep: cci0-1-sleep-state {
+				sda-pins {
+					pins = "gpio29";
+					function = "cci_i2c_sda";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+
+				scl-pins {
+					pins = "gpio30";
+					function = "cci_i2c_scl";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+
+			cci1_0_default: cci1-0-default-state {
+				sda-pins {
+					pins = "gpio59";
+					function = "cci_i2c_sda";
+					drive-strength = <2>;
+					bias-pull-up = <2200>;
+				};
+
+				scl-pins {
+					pins = "gpio60";
+					function = "cci_i2c_scl";
+					drive-strength = <2>;
+					bias-pull-up = <2200>;
+				};
+			};
+
+			cci1_0_sleep: cci1-0-sleep-state {
+				sda-pins {
+					pins = "gpio59";
+					function = "cci_i2c_sda";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+
+				scl-pins {
+					pins = "gpio60";
+					function = "cci_i2c_scl";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+
+			cci1_1_default: cci1-1-default-state {
+				sda-pins {
+					pins = "gpio31";
+					function = "cci_i2c_sda";
+					drive-strength = <2>;
+					bias-pull-up = <2200>;
+				};
+
+				scl-pins {
+					pins = "gpio32";
+					function = "cci_i2c_scl";
+					drive-strength = <2>;
+					bias-pull-up = <2200>;
+				};
+			};
+
+			cci1_1_sleep: cci1-1-sleep-state {
+				sda-pins {
+					pins = "gpio31";
+					function = "cci_i2c_sda";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+
+				scl-pins {
+					pins = "gpio32";
+					function = "cci_i2c_scl";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+
+			cci2_0_default: cci2-0-default-state {
+				sda-pins {
+					pins = "gpio61";
+					function = "cci_i2c_sda";
+					drive-strength = <2>;
+					bias-pull-up = <2200>;
+				};
+
+				scl-pins {
+					pins = "gpio62";
+					function = "cci_i2c_scl";
+					drive-strength = <2>;
+					bias-pull-up = <2200>;
+				};
+			};
+
+			cci2_0_sleep: cci2-0-sleep-state {
+				sda-pins {
+					pins = "gpio61";
+					function = "cci_i2c_sda";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+
+				scl-pins {
+					pins = "gpio62";
+					function = "cci_i2c_scl";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+
+			cci2_1_default: cci2-1-default-state {
+				sda-pins {
+					pins = "gpio54";
+					function = "cci_i2c_sda";
+					drive-strength = <2>;
+					bias-pull-up = <2200>;
+				};
+
+				scl-pins {
+					pins = "gpio55";
+					function = "cci_i2c_scl";
+					drive-strength = <2>;
+					bias-pull-up = <2200>;
+				};
+			};
+
+			cci2_1_sleep: cci2-1-sleep-state {
+				sda-pins {
+					pins = "gpio54";
+					function = "cci_i2c_sda";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+
+				scl-pins {
+					pins = "gpio55";
+					function = "cci_i2c_scl";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+
 			hs0_mi2s_active: hs0-mi2s-active-state {
 				pins = "gpio106", "gpio107", "gpio108", "gpio109";
 				function = "hs0_mi2s";
-- 
2.34.1



From quic_nihalkum at quicinc.com  Mon Dec 22 01:59:12 2025
From: quic_nihalkum at quicinc.com (Nihal Kumar Gupta)
Date: Mon, 22 Dec 2025 15:29:12 +0530
Subject: [PATCH v8 3/5] arm64: dts: qcom: monaco: Add camera MCLK pinctrl
In-Reply-To: <20251222095914.1995041-1-quic_nihalkum@quicinc.com>
References: <20251222095914.1995041-1-quic_nihalkum@quicinc.com>
Message-ID: <20251222095914.1995041-4-quic_nihalkum@quicinc.com>

Define pinctrl definitions to enable camera master clocks on Monaco.

Signed-off-by: Nihal Kumar Gupta <quic_nihalkum at quicinc.com>
Signed-off-by: Vikram Sharma <quic_vikramsa at quicinc.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio at oss.qualcomm.com>
Reviewed-by: Vladimir Zapolskiy <vladimir.zapolskiy at linaro.org>
---
 arch/arm64/boot/dts/qcom/monaco.dtsi | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/monaco.dtsi b/arch/arm64/boot/dts/qcom/monaco.dtsi
index 4b2d8a449b00..ace09239d167 100644
--- a/arch/arm64/boot/dts/qcom/monaco.dtsi
+++ b/arch/arm64/boot/dts/qcom/monaco.dtsi
@@ -5182,6 +5182,27 @@ tlmm: pinctrl at f100000 {
 			#interrupt-cells = <2>;
 			wakeup-parent = <&pdc>;
 
+			cam0_default: cam0-default-state {
+				pins = "gpio67";
+				function = "cam_mclk";
+				drive-strength = <2>;
+				bias-disable;
+			};
+
+			cam1_default: cam1-default-state {
+				pins = "gpio68";
+				function = "cam_mclk";
+				drive-strength = <2>;
+				bias-disable;
+			};
+
+			cam2_default: cam2-default-state {
+				pins = "gpio69";
+				function = "cam_mclk";
+				drive-strength = <2>;
+				bias-disable;
+			};
+
 			cci0_0_default: cci0-0-default-state {
 				sda-pins {
 					pins = "gpio57";
-- 
2.34.1



From quic_nihalkum at quicinc.com  Mon Dec 22 01:59:13 2025
From: quic_nihalkum at quicinc.com (Nihal Kumar Gupta)
Date: Mon, 22 Dec 2025 15:29:13 +0530
Subject: [PATCH v8 4/5] arm64: dts: qcom: monaco-evk: Add camera AVDD regulators
In-Reply-To: <20251222095914.1995041-1-quic_nihalkum@quicinc.com>
References: <20251222095914.1995041-1-quic_nihalkum@quicinc.com>
Message-ID: <20251222095914.1995041-5-quic_nihalkum@quicinc.com>

Define three fixed regulators for camera AVDD rails, each gpio-controlled
with corresponding pinctrl definitions.

Signed-off-by: Nihal Kumar Gupta <quic_nihalkum at quicinc.com>
Signed-off-by: Vikram Sharma <quic_vikramsa at quicinc.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio at oss.qualcomm.com>
---
 arch/arm64/boot/dts/qcom/monaco-evk.dts | 51 +++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/monaco-evk.dts b/arch/arm64/boot/dts/qcom/monaco-evk.dts
index bb35893da73d..003c24d08c71 100644
--- a/arch/arm64/boot/dts/qcom/monaco-evk.dts
+++ b/arch/arm64/boot/dts/qcom/monaco-evk.dts
@@ -76,6 +76,36 @@ platform {
 			};
 		};
 	};
+
+	vreg_cam0_2p8: vreg-cam0-2p8 {
+		compatible = "regulator-fixed";
+		regulator-name = "vreg_cam0_2p8";
+		startup-delay-us = <10000>;
+		enable-active-high;
+		gpio = <&tlmm 73 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&cam0_avdd_2v8_en_default>;
+		pinctrl-names = "default";
+	};
+
+	vreg_cam1_2p8: vreg-cam1-2p8 {
+		compatible = "regulator-fixed";
+		regulator-name = "vreg_cam1_2p8";
+		startup-delay-us = <10000>;
+		enable-active-high;
+		gpio = <&tlmm 74 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&cam1_avdd_2v8_en_default>;
+		pinctrl-names = "default";
+	};
+
+	vreg_cam2_2p8: vreg-cam2-2p8 {
+		compatible = "regulator-fixed";
+		regulator-name = "vreg_cam2_2p8";
+		startup-delay-us = <10000>;
+		enable-active-high;
+		gpio = <&tlmm 75 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&cam2_avdd_2v8_en_default>;
+		pinctrl-names = "default";
+	};
 };
 
 &apps_rsc {
@@ -458,6 +488,27 @@ qup_i2c1_default: qup-i2c1-state {
 		bias-pull-up;
 	};
 
+	cam0_avdd_2v8_en_default: cam0-avdd-2v8-en-state {
+		pins = "gpio73";
+		function = "gpio";
+		drive-strength = <2>;
+		bias-disable;
+	};
+
+	cam1_avdd_2v8_en_default: cam1-avdd-2v8-en-state {
+		pins = "gpio74";
+		function = "gpio";
+		drive-strength = <2>;
+		bias-disable;
+	};
+
+	cam2_avdd_2v8_en_default: cam2-avdd-2v8-en-state {
+		pins = "gpio75";
+		function = "gpio";
+		drive-strength = <2>;
+		bias-disable;
+	};
+
 	qup_i2c15_default: qup-i2c15-state {
 		pins = "gpio91", "gpio92";
 		function = "qup1_se7";
-- 
2.34.1



From quic_nihalkum at quicinc.com  Mon Dec 22 01:59:14 2025
From: quic_nihalkum at quicinc.com (Nihal Kumar Gupta)
Date: Mon, 22 Dec 2025 15:29:14 +0530
Subject: [PATCH v8 5/5] arm64: dts: qcom: monaco-evk-camera: Add DT overlay
In-Reply-To: <20251222095914.1995041-1-quic_nihalkum@quicinc.com>
References: <20251222095914.1995041-1-quic_nihalkum@quicinc.com>
Message-ID: <20251222095914.1995041-6-quic_nihalkum@quicinc.com>

Monaco EVK board does not include a camera sensor in its default hardware
configuration. Introducing a device tree overlay to support optional
integration of the IMX577 sensor via CSIPHY1.

Camera reset is handled through an I2C expander, and power is enabled
via TLMM GPIO74.

An example media-ctl pipeline for the imx577 is:

media-ctl --reset
media-ctl -V '"imx577 3-001a":0[fmt:SRGGB10/4056x3040 field:none]'
media-ctl -V '"msm_csiphy1":0[fmt:SRGGB10/4056x3040]'
media-ctl -V '"msm_csid0":0[fmt:SRGGB10/4056x3040]'
media-ctl -V '"msm_vfe0_rdi0":0[fmt:SRGGB10/4056x3040]'
media-ctl -l '"msm_csiphy1":1->"msm_csid0":0[1]'
media-ctl -l '"msm_csid0":1->"msm_vfe0_rdi0":0[1]'
yavta -B capture-mplane -c -I -n 5 -f SRGGB10P -s 4056x3040 -F /dev/video1

Signed-off-by: Nihal Kumar Gupta <quic_nihalkum at quicinc.com>
Co-developed-by: Ravi Shankar <quic_rshankar at quicinc.com>
Signed-off-by: Ravi Shankar <quic_rshankar at quicinc.com>
Co-developed-by: Vishal Verma <quic_vishverm at quicinc.com>
Signed-off-by: Vishal Verma <quic_vishverm at quicinc.com>
Signed-off-by: Vikram Sharma <quic_vikramsa at quicinc.com>
Reviewed-by: Vladimir Zapolskiy <vladimir.zapolskiy at linaro.org>
Reviewed-by: Bryan O'Donoghue <bryan.odonoghue at linaro.org>
---
 arch/arm64/boot/dts/qcom/Makefile             |  4 ++
 .../dts/qcom/monaco-evk-camera-imx577.dtso    | 66 +++++++++++++++++++
 2 files changed, 70 insertions(+)
 create mode 100644 arch/arm64/boot/dts/qcom/monaco-evk-camera-imx577.dtso

diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 76cf0115a00a..5cf72bdff0b6 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -40,6 +40,10 @@ lemans-evk-camera-dtbs	:= lemans-evk.dtb lemans-evk-camera.dtbo
 dtb-$(CONFIG_ARCH_QCOM)	+= lemans-evk-camera-csi1-imx577.dtb
 dtb-$(CONFIG_ARCH_QCOM)	+= lemans-evk-camera.dtb
 dtb-$(CONFIG_ARCH_QCOM)	+= monaco-evk.dtb
+
+monaco-evk-camera-imx577-dtbs	:= monaco-evk.dtb monaco-evk-camera-imx577.dtbo
+dtb-$(CONFIG_ARCH_QCOM)	+= monaco-evk-camera-imx577.dtb
+
 dtb-$(CONFIG_ARCH_QCOM)	+= msm8216-samsung-fortuna3g.dtb
 dtb-$(CONFIG_ARCH_QCOM)	+= msm8916-acer-a1-724.dtb
 dtb-$(CONFIG_ARCH_QCOM)	+= msm8916-alcatel-idol347.dtb
diff --git a/arch/arm64/boot/dts/qcom/monaco-evk-camera-imx577.dtso b/arch/arm64/boot/dts/qcom/monaco-evk-camera-imx577.dtso
new file mode 100644
index 000000000000..0d5ccd020e6e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/monaco-evk-camera-imx577.dtso
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,sa8775p-camcc.h>
+#include <dt-bindings/gpio/gpio.h>
+
+&camss {
+	vdda-phy-supply = <&vreg_l4a>;
+	vdda-pll-supply = <&vreg_l5a>;
+
+	status = "okay";
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 1 {
+			reg = <1>;
+
+			csiphy1_ep: endpoint {
+				data-lanes = <0 1 2 3>;
+				remote-endpoint = <&imx577_ep1>;
+			};
+		};
+	};
+};
+
+&cci1 {
+	pinctrl-0 = <&cci1_0_default>;
+	pinctrl-1 = <&cci1_0_sleep>;
+
+	status = "okay";
+};
+
+&cci1_i2c0 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	camera at 1a {
+		compatible = "sony,imx577";
+		reg = <0x1a>;
+
+		reset-gpios = <&expander2 1 GPIO_ACTIVE_LOW>;
+		pinctrl-0 = <&cam1_default>;
+		pinctrl-names = "default";
+
+		clocks = <&camcc CAM_CC_MCLK1_CLK>;
+		assigned-clocks = <&camcc CAM_CC_MCLK1_CLK>;
+		assigned-clock-rates = <24000000>;
+
+		avdd-supply = <&vreg_cam1_2p8>;
+
+		port {
+			imx577_ep1: endpoint {
+				link-frequencies = /bits/ 64 <600000000>;
+				data-lanes = <1 2 3 4>;
+				remote-endpoint = <&csiphy1_ep>;
+			};
+		};
+	};
+};
-- 
2.34.1



From krzk at kernel.org  Mon Dec 22 02:01:46 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 22 Dec 2025 11:01:46 +0100
Subject: [PATCH] arm64: dts: toshiba: Use recommended node names
In-Reply-To: <20251216180055.2793215-2-robh@kernel.org>
References: <20251216180055.2793215-2-robh@kernel.org>
Message-ID: <20251222-lean-resourceful-barnacle-95cd83@quoll>

On Tue, Dec 16, 2025 at 12:00:54PM -0600, Rob Herring (Arm) wrote:
> Update Toshiba TMPV7708 node name to the recommended standard node
> names. Generally, node names and paths aren't considered ABI, so it
> is safe to change them.
> 
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> ---
> SoC maintainers, Please take this directly.

Applied, rebased on top of my earlier fixes.

I took all your patches to my DTS cleanup branch, not to soc tree,
because that way I can combine with my other fixes. I'll send them to
soc tree soon.

Best regards,
Krzysztof



From krzk at kernel.org  Mon Dec 22 02:02:07 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 22 Dec 2025 11:02:07 +0100
Subject: [PATCH] arm64: dts: toshiba: Use recommended node names
In-Reply-To: <20251216180055.2793215-2-robh@kernel.org>
References: <20251216180055.2793215-2-robh@kernel.org>
Message-ID: <176639772702.31420.9343688718392781751.b4-ty@kernel.org>


On Tue, 16 Dec 2025 12:00:54 -0600, Rob Herring (Arm) wrote:
> Update Toshiba TMPV7708 node name to the recommended standard node
> names. Generally, node names and paths aren't considered ABI, so it
> is safe to change them.
> 
> 

Applied, thanks!

[1/1] arm64: dts: toshiba: Use recommended node names
      https://git.kernel.org/krzk/linux-dt/c/22fbe6e21450d629642e4bdc8d8d329219abeb46

Best regards,
-- 
Krzysztof Kozlowski <krzk at kernel.org>



From james.clark at linaro.org  Mon Dec 22 02:05:44 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 22 Dec 2025 10:05:44 +0000
Subject: [PATCH] arm64: perf: fix syscalltbl path base
In-Reply-To: <c8161700-ad9d-43d3-8c45-cfc110ebcd49@app.fastmail.com>
References: <b2651f20-6f3a-49f5-9cd8-3fb028b2cab5@app.fastmail.com>
 <fcefc3c0-541d-40cc-84e3-9c2460308bdb@linaro.org>
 <23c07ac4-ff13-47a5-824a-e7af1d1847a3@app.fastmail.com>
 <bda366b4-fa53-4feb-a7ce-ee47cfc404b5@linaro.org>
 <20251215112818.GB681384@e132581.arm.com>
 <c8161700-ad9d-43d3-8c45-cfc110ebcd49@app.fastmail.com>
Message-ID: <a5448524-a147-4edb-9359-bcee3d780eb6@linaro.org>



On 21/12/2025 9:48 pm, Joel May wrote:
> On Mon, Dec 15, 2025, at 03:28, Leo Yan wrote:
>> On Mon, Dec 15, 2025 at 12:52:24PM +0200, James Clark wrote:
>>> On 15/12/2025 11:33, Arnd Bergmann wrote:
>>>> On Mon, Dec 15, 2025, at 09:47, James Clark wrote:
>>>>> On 15/12/2025 00:12, Joel May wrote:
>>>>>
>>>>> Hi Joel,
>>>>>
>>>>> There is a similar fix on the list here:
>>>>>
>>>>> https://lore.kernel.org/linux-perf-users/20251204-perf_fix_syscall_header-v1-1-b8e27f74ed6a at arm.com/
>>>>>
>>>>> I'm not sure if commit 1 alone will also fix your issue, or we'd need to
>>>>> collapse both of the commits in that set.
>>
>> We need to apply both patches in the share link - we need to apply the
>> second patch to revert generating unistd_64.h in libperf.
> 
> Yes, applying both of those patches will mitigate my problem.
> 
> Neither of those patches update syscalltbl in
> arm/arm64/kernel/Makefile.syscalls though.  Based on the context in
> scripts/Makefile.asm-headers, it looks like syscalltbl is always intended
> to be relative to srctree.  So, my patch increases consistency, even if
> it's not fixing any known problem (after the other patches are applied).
> 
> Whether headers are dynamically generated or not, it seems like this is
> something that can be improved anyway.
> 
> This is my first time contributing to the Linux kernel, so please bare with
> my ignorance.  I don't know whether it's acceptable to consider patches
> that conceptually improve something without an actual problem they're
> solving.
> 

No worries, thanks for sending the fix. Yes I think it could be ok to 
apply your patch anyway. I just wanted to make sure we were all on the 
same page with both fixes fixing the same thing.

You might want to drop the fixes tag though to avoid confusion if Leo's 
one gets accepted, because then technically it doesn't fix anything any 
more. Keeping Leo's fixes: tag is a bit better because it fixes 
additional things and targets an older commit.

James

> Thanks,
> --Joel





From krzk at kernel.org  Mon Dec 22 02:05:48 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 22 Dec 2025 11:05:48 +0100
Subject: [PATCH] arm64: dts: cavium: Drop thunder2
In-Reply-To: <20251216180202.2794695-2-robh@kernel.org>
References: <20251216180202.2794695-2-robh@kernel.org>
Message-ID: <176639794821.32569.10955263518261221529.b4-ty@kernel.org>


On Tue, 16 Dec 2025 12:02:02 -0600, Rob Herring (Arm) wrote:
> The Cavium thunder2 DT support
>  is incomplete. It consists of 4 cores
> (out of 128) and only a serial port. The thunder2 specific drivers in
> the kernel don't have DT support either. The few remaining users of
> this platform likely use ACPI.
> 
> 
> [...]

Applied, thanks!

[1/1] arm64: dts: cavium: Drop thunder2
      https://git.kernel.org/krzk/linux-dt/c/f25aa20e92305c7ab7a6387b8ef7b6e83f8a49fb

Best regards,
-- 
Krzysztof Kozlowski <krzk at kernel.org>



From krzk at kernel.org  Mon Dec 22 02:05:51 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 22 Dec 2025 11:05:51 +0100
Subject: [PATCH] ARM: dts: vexpress/v2m-rs1: Use documented
 arm,vexpress,config-bus child node names
In-Reply-To: <20251216191212.2879226-2-robh@kernel.org>
References: <20251216191212.2879226-2-robh@kernel.org>
Message-ID: <176639795130.32569.11857070217126257109.b4-ty@kernel.org>


On Tue, 16 Dec 2025 13:12:12 -0600, Rob Herring (Arm) wrote:
> Update the arm,vexpress,config-bus child node names to use the
> documented ones. Most of these were updated a while back, but I missed
> these.
> 
> 

Applied, thanks!

[1/1] ARM: dts: vexpress/v2m-rs1: Use documented arm,vexpress,config-bus child node names
      https://git.kernel.org/krzk/linux-dt/c/7dd84bbec273345bd5735f6917b93eb2a7d9c0c3

Best regards,
-- 
Krzysztof Kozlowski <krzk at kernel.org>



From jim.cromie at gmail.com  Mon Dec 22 00:20:46 2025
From: jim.cromie at gmail.com (Jim Cromie)
Date: Mon, 22 Dec 2025 21:20:46 +1300
Subject: [PATCH v7 29/31] dyndbg: resolve "protection" of class'd pr_debug
In-Reply-To: <20251222082049.1782440-3-jim.cromie@gmail.com>
References: <20251222082049.1782440-3-jim.cromie@gmail.com>
Message-ID: <20251222082049.1782440-30-jim.cromie@gmail.com>

classmap-v1 code protected class'd pr_debugs from unintended
changes by unclassed/_DFLT queries:

  # - to declutter examples:
  alias ddcmd='echo $* > /proc/dynamic_debug/control'

  # IOW, this should NOT alter drm.debug settings
  ddcmd -p

  # Instead, you must name the class to change it.
  # Protective but tedious
  ddcmd class DRM_UT_CORE +p

  # Or do it the (old school) subsystem way
  # This is ABI !!
  echo 1 > /sys/module/drm/parameters/debug

Since the debug sysfs-node is ABI, if dyndbg is going to implement it,
it must also honor its settings; it must at least protect against
accidental changes to its classes from legacy queries.

The protection allows all previously conceived queries to work the way
they always have; ie select the same set of pr_debugs, despite the
inclusion of whole new classes of pr_debugs.

But that choice has 2 downsides:

1. "name the class to change it" makes a tedious long-winded
interface, needing many commands to set DRM_UT_* one at a time.

2. It makes the class keyword special in some sense; the other
keywords skip only on query mismatch, otherwise the code falls thru to
adjust the pr-debug site.

 Jason Baron	didn't like v1 on point 2.
 Louis Chauvet	didn't like recent rev on point 1 tedium.

But that said: /sys/ is ABI, so this must be reliable:

  #> echo 0x1f > /sys/module/drm/parameters/debug

It 'just works' without dyndbg underneath; we must deliver that same
stability.  Convenience is secondary.

The new resolution:

If ABI is the blocking issue, then no ABI means no blocking issue.
IOW, if the classmap has no presence under /sys/*, ie no PARAM, there
is no ABI to guard, and no reason to enforce a tedious interface.

In the future, if DRM wants to alter this protection, that is
practical, but I think default-on is the correct mode.

So atm classes without a PARAM are unprotected at >control, allowing
admins their shortcuts.  I think this could satisfy all viewpoints.

That said, theres also a possibility of wildcard classes:

   #> ddcmd class '*' +p

Currently, the query-class is exact-matched against each module's
classmaps.names.  This gives precise behavior, a good basis.

But class wildcards are possible, they just did'nt appear useful for
DRM, whose classmap names are a flat DRM_UT_* namespace.

IOW, theres no useful selectivity there:

   #> ddcmd class "DRM_*" +p		# these enable every DRM_* class
   #> ddcmd class "DRM_UT_*" +p

   #> ddcmd class "DRM_UT_V*" +p	# finally select just 1: DRM_UT_VBL
   #> ddcmd class "DRM_UT_D*" +p	# but this gets 3

   #> ddcmd class "D*V*" +p		# here be dragons

But there is debatable utility in the feature.

   #> ddcmd class __DEFAULT__ -p	# what about this ?
   #> ddcmd -p				# thats what this does. automatically

Anyway, this patch does:

1. adds link field from _ddebug_class_map to the .controlling_param

2. sets it in ddebug_match_apply_kparam(), during modprobe/init,
   when options like drm.debug=VAL are handled.

3. ddebug_class_has_param() now checks .controlling_param

4. ddebug_class_wants_protection() macro renames 3.
   this frames it as a separable policy decision

5. ddebug_match_desc() gets the most attention:

a. move classmap consideration to the bottom
   this insures all other constraints act 1st.
   allows simpler 'final' decisions.

b. split class choices cleanly on query:
   class FOO vs none, and class'd vs _DPRINTK_CLASS_DFLT site.

c. calls 4 when applying a class-less query to a class'd pr_debug
   here we need a new fn to find the classmap with this .class_id

d. calls new ddebug_find_classmap_by_class_id().
   when class-less query looks at a class'd pr_debug.
   finds classmap, which can then decide, currently by PARAM existence.

NOTES:

protection is only against class-less queries, explicit "class FOO"
adjustments are allowed (that is the mechanism).

The drm.debug sysfs-node heavily under-specifies the class'd pr_debugs
it controls; none of the +mfls prefixing flags have any effect, and
each callsite remains individually controllable. drm.debug just
toggles the +p flag for all the modules' class'd pr_debugs.

Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
 include/linux/dynamic_debug.h |  14 ++--
 lib/dynamic_debug.c           | 127 +++++++++++++++++++++++++++-------
 2 files changed, 110 insertions(+), 31 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index b1d11d946780..b22da40e2583 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -75,6 +75,7 @@ enum ddebug_class_map_type {
  * map @class_names 0..N to consecutive constants starting at @base.
  */
 struct _ddebug_class_map {
+	struct _ddebug_class_param *controlling_param;
 	const struct module *mod;	/* NULL for builtins */
 	const char *mod_name;
 	const char **class_names;
@@ -259,7 +260,12 @@ struct _ddebug_class_param {
  *
  * Creates a sysfs-param to control the classes defined by the
  * exported classmap, with bits 0..N-1 mapped to the classes named.
- * This version keeps class-state in a private long int.
+ *
+ * Since sysfs-params are ABI, this also protects the classmap'd
+ * pr_debugs from un-class'd `echo -p > /proc/dynamic_debug/control`
+ * changes.
+ *
+ * This keeps class-state in a private long int.
  */
 #define DYNAMIC_DEBUG_CLASSMAP_PARAM(_name, _var, _flags)		\
 	static unsigned long _name##_bvec;				\
@@ -272,10 +278,8 @@ struct _ddebug_class_param {
  * @_var:   name of the (exported) classmap var defining the classes/bits
  * @_flags: flags to be toggled, typically just 'p'
  *
- * Creates a sysfs-param to control the classes defined by the
- * exported clasmap, with bits 0..N-1 mapped to the classes named.
- * This version keeps class-state in user @_bits.  This lets drm check
- * __drm_debug elsewhere too.
+ * Like DYNAMIC_DEBUG_CLASSMAP_PARAM, but maintains param-state in
+ * extern @_bits.  This lets DRM check __drm_debug elsewhere too.
  */
 #define DYNAMIC_DEBUG_CLASSMAP_PARAM_REF(_name, _bits, _var, _flags)	\
 	__DYNAMIC_DEBUG_CLASSMAP_PARAM(_name, _bits, _var, _flags)
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index c50836c262b4..f60a723a441b 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -206,6 +206,50 @@ ddebug_find_valid_class(struct _ddebug_info const *di, const char *query_class,
 	return NULL;
 }
 
+static bool ddebug_class_in_range(const int class_id, const struct _ddebug_class_map *map)
+{
+	return (class_id >= map->base &&
+		class_id < map->base + map->length);
+}
+
+static struct _ddebug_class_map *
+ddebug_find_map_by_class_id(struct _ddebug_info *di, int class_id)
+{
+	struct _ddebug_class_map *map;
+	struct _ddebug_class_user *cli;
+	int i;
+
+	for_subvec(i, map, di, maps)
+		if (ddebug_class_in_range(class_id, map))
+			return map;
+
+	for_subvec(i, cli, di, users)
+		if (ddebug_class_in_range(class_id, cli->map))
+			return cli->map;
+
+	return NULL;
+}
+
+/*
+ * classmaps-V1 protected classes from changes by legacy commands
+ * (those selecting _DPRINTK_CLASS_DFLT by omission).  This had the
+ * downside that saying "class FOO" for every change can get tedious.
+ *
+ * V2 is smarter, it protects class-maps if the defining module also
+ * calls DYNAMIC_DEBUG_CLASSMAP_PARAM to create a sysfs parameter.
+ * Since the author wants the knob, we should assume they intend to
+ * use it (in preference to "class FOO +p" >control), and want to
+ * trust its settings.  This gives protection when its useful, and not
+ * when its just tedious.
+ */
+static inline bool ddebug_class_has_param(const struct _ddebug_class_map *map)
+{
+	return !!(map->controlling_param);
+}
+
+/* re-framed as a policy choice */
+#define ddebug_class_wants_protection(map) (ddebug_class_has_param(map))
+
 /*
  * Search the tables for _ddebug's which match the given `query' and
  * apply the `flags' and `mask' to them.  Returns number of matching
@@ -214,11 +258,10 @@ ddebug_find_valid_class(struct _ddebug_info const *di, const char *query_class,
  */
 static bool ddebug_match_desc(const struct ddebug_query *query,
 			      struct _ddebug *dp,
-			      int valid_class)
+			      struct _ddebug_info *di,
+			      int selected_class)
 {
-	/* match site against query-class */
-	if (dp->class_id != valid_class)
-		return false;
+	struct _ddebug_class_map *site_map;
 
 	/* match against the source filename */
 	if (query->filename &&
@@ -255,7 +298,28 @@ static bool ddebug_match_desc(const struct ddebug_query *query,
 	    dp->lineno > query->last_lineno)
 		return false;
 
-	return true;
+	/*
+	 * above are all satisfied, so we can make final decisions:
+	 * 1- class FOO or implied class __DEFAULT__
+	 * 2- site.is_classed or not
+	 */
+	if (query->class_string) {
+		/* class FOO given, exact match required */
+		return (dp->class_id == selected_class);
+	}
+	/* query class __DEFAULT__ by omission. */
+	if (dp->class_id == _DPRINTK_CLASS_DFLT) {
+		/* un-classed site */
+		return true;
+	}
+	/* site is class'd */
+	site_map = ddebug_find_map_by_class_id(di, dp->class_id);
+	if (!site_map) {
+		WARN_ONCE(1, "unknown class_id %d, check %s's CLASSMAP definitions", dp->class_id, di->mod_name);
+		return false;
+	}
+	/* module(-param) decides protection */
+	return !ddebug_class_wants_protection(site_map);
 }
 
 static int ddebug_change(const struct ddebug_query *query, struct flag_settings *modifiers)
@@ -265,33 +329,31 @@ static int ddebug_change(const struct ddebug_query *query, struct flag_settings
 	unsigned int newflags;
 	unsigned int nfound = 0;
 	struct flagsbuf fbuf, nbuf;
-	struct _ddebug_class_map *map = NULL;
-	int valid_class;
+	int selected_class;
 
 	/* search for matching ddebugs */
 	mutex_lock(&ddebug_lock);
 	list_for_each_entry(dt, &ddebug_tables, link) {
 		struct _ddebug_info *di = &dt->info;
+		struct _ddebug_class_map *mods_map;
 
 		/* match against the module name */
 		if (query->module &&
 		    !match_wildcard(query->module, di->mod_name))
 			continue;
 
+		selected_class = _DPRINTK_CLASS_DFLT;
 		if (query->class_string) {
-			map = ddebug_find_valid_class(&dt->info, query->class_string,
-						      &valid_class);
-			if (!map)
+			mods_map = ddebug_find_valid_class(di, query->class_string,
+							   &selected_class);
+			if (!mods_map)
 				continue;
-		} else {
-			/* constrain query, do not touch class'd callsites */
-			valid_class = _DPRINTK_CLASS_DFLT;
 		}
 
 		for (i = 0; i < di->descs.len; i++) {
 			struct _ddebug *dp = &di->descs.start[i];
 
-			if (!ddebug_match_desc(query, dp, valid_class))
+			if (!ddebug_match_desc(query, dp, di, selected_class))
 				continue;
 
 			nfound++;
@@ -656,6 +718,7 @@ static int ddebug_exec_queries(char *query, const char *modname)
 }
 
 /* apply a new class-param setting */
+
 static int ddebug_apply_class_bitmap(const struct _ddebug_class_param *dcp,
 				     const unsigned long *new_bits,
 				     const unsigned long old_bits,
@@ -1107,12 +1170,6 @@ static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos)
 	return dp;
 }
 
-static bool ddebug_class_in_range(const int class_id, const struct _ddebug_class_map *map)
-{
-	return (class_id >= map->base &&
-		class_id < map->base + map->length);
-}
-
 static const char *ddebug_class_name(struct _ddebug_info *di, struct _ddebug *dp)
 {
 	struct _ddebug_class_map *map;
@@ -1237,25 +1294,36 @@ static void ddebug_sync_classbits(const struct kernel_param *kp, const char *mod
 	}
 }
 
-static void ddebug_match_apply_kparam(const struct kernel_param *kp,
-				      const struct _ddebug_class_map *map,
-				      const char *mod_name)
+static struct _ddebug_class_param *
+ddebug_get_classmap_kparam(const struct kernel_param *kp,
+			   const struct _ddebug_class_map *map)
 {
 	struct _ddebug_class_param *dcp;
 
 	if (kp->ops != &param_ops_dyndbg_classes)
-		return;
+		return false;
 
 	dcp = (struct _ddebug_class_param *)kp->arg;
 
-	if (map == dcp->map) {
+	return (map == dcp->map)
+		? dcp : (struct _ddebug_class_param *)NULL;
+}
+
+static void ddebug_match_apply_kparam(const struct kernel_param *kp,
+				      struct _ddebug_class_map *map,
+				      const char *mod_name)
+{
+	struct _ddebug_class_param *dcp = ddebug_get_classmap_kparam(kp, map);
+
+	if (dcp) {
+		map->controlling_param = dcp;
 		v2pr_info(" kp:%s.%s =0x%lx", mod_name, kp->name, *dcp->bits);
 		vpr_cm_info(map, " %s maps ", mod_name);
 		ddebug_sync_classbits(kp, mod_name);
 	}
 }
 
-static void ddebug_apply_params(const struct _ddebug_class_map *cm, const char *mod_name)
+static void ddebug_apply_params(struct _ddebug_class_map *cm, const char *mod_name)
 {
 	const struct kernel_param *kp;
 #if IS_ENABLED(CONFIG_MODULES)
@@ -1275,6 +1343,13 @@ static void ddebug_apply_params(const struct _ddebug_class_map *cm, const char *
 	}
 }
 
+/*
+ * called from add_module, ie early. it can find controlling kparams,
+ * which can/does? enable protection of this classmap from class-less
+ * queries, on the grounds that the user created the kparam, means to
+ * use it, and expects it to reflect reality.  We should oblige him,
+ * and protect those classmaps from classless "-p" changes.
+ */
 static void ddebug_apply_class_maps(const struct _ddebug_info *di)
 {
 	struct _ddebug_class_map *cm;
-- 
2.52.0



From peter.griffin at linaro.org  Mon Dec 22 02:20:44 2025
From: peter.griffin at linaro.org (Peter Griffin)
Date: Mon, 22 Dec 2025 10:20:44 +0000
Subject: [PATCH v6 1/4] dt-bindings: clock: google,gs101-clock: add
 samsung,sysreg property as required
In-Reply-To: <d7a749e2-1d00-459f-adbb-0841190b7849@kernel.org>
References: <20251220-automatic-clocks-v6-0-36c2f276a135@linaro.org>
 <20251220-automatic-clocks-v6-1-36c2f276a135@linaro.org> <215eb434-683f-4cf2-9bcd-0860991ae23e@kernel.org>
 <CADrjBPoWcONhJJdCeovkwQ9Oha+t+dpHY_ohKPV7BQS1tougGw@mail.gmail.com> <d7a749e2-1d00-459f-adbb-0841190b7849@kernel.org>
Message-ID: <CADrjBPpv9OB5zjsE=+dUyZCz2xSs6XXWkpbK2qbFAdUyTaXXhQ@mail.gmail.com>

Hi Krzysztof,

On Mon, 22 Dec 2025 at 09:53, Krzysztof Kozlowski <krzk at kernel.org> wrote:
>
> On 22/12/2025 10:39, Peter Griffin wrote:
> > Hi Krzysztof,
> >
> > On Sun, 21 Dec 2025 at 13:26, Krzysztof Kozlowski <krzk at kernel.org> wrote:
> >>
> >> On 20/12/2025 10:05, Peter Griffin wrote:
> >>> Each CMU (with the exception of cmu_top) has a corresponding sysreg bank
> >>> that contains the BUSCOMPONENT_DRCG_EN and optional MEMCLK registers.
> >>> The BUSCOMPONENT_DRCG_EN register enables dynamic root clock gating of
> >>> bus components and MEMCLK gates the sram clock.
> >>>
> >>> Now the clock driver supports automatic clock mode, to fully enable dynamic
> >>> root clock gating it is required to configure these registers. Update the
> >>> bindings documentation so that all CMUs (with the exception of
> >>> gs101-cmu-top) have samsung,sysreg as a required property.
> >>>
> >>> Note this is NOT an ABI break, as if the property isn't specified the
> >>> clock driver will fallback to the current behaviour of not initializing
> >>> the registers. The system still boots, but bus components won't benefit
> >>> from dynamic root clock gating and dynamic power will be higher (which has
> >>> been the case until now anyway).
> >>>
> >>> Additionally update the DT example to included the correct CMU size as
> >>> registers in that region are used for automatic clock mode.
> >>>
> >>> Signed-off-by: Peter Griffin <peter.griffin at linaro.org>
> >>> ---
> >>> Changes in v5:
> >>> - Invert the test for google,gs101-cmu-top (Andre)
> >>>
> >>
> >>
> >> <form letter>
> >> This is a friendly reminder during the review process.
> >>
> >> It looks like you received a tag and forgot to add it.
> >>
> >> If you do not know the process, here is a short explanation:
> >> Please add Acked-by/Reviewed-by/Tested-by tags when posting new versions
> >> of patchset, under or above your Signed-off-by tag, unless patch changed
> >> significantly (e.g. new properties added to the DT bindings). Tag is
> >> "received", when provided in a message replied to you on the mailing
> >> list. Tools like b4 can help here. However, there's no need to repost
> >> patches *only* to add the tags. The upstream maintainer will do that for
> >> tags received on the version they apply.
> >>
> >> Please read:
> >> https://elixir.bootlin.com/linux/v6.12-rc3/source/Documentation/process/submitting-patches.rst#L577
> >>
> >> If a tag was not added on purpose, please state why and what changed.
> >> </form letter>
> >
> > Apologies, your tag should have been added.... got kind of sidetracked
> > bisecting the linux-next regression with the serial console and then
> > forgot to apply it.
>
> I think it was more than one tag, so I decided not to look for them.
> Please send v7 with all tags collected.

Sure, will resend shortly.

Peter


From peter.griffin at linaro.org  Mon Dec 22 02:22:11 2025
From: peter.griffin at linaro.org (Peter Griffin)
Date: Mon, 22 Dec 2025 10:22:11 +0000
Subject: [PATCH v7 0/4] Implement hardware automatic clock gating (HWACG)
 for gs101
Message-ID: <20251222-automatic-clocks-v7-0-fec86fa89874@linaro.org>

Hi folks,

This series addresses an issue with Samsung Exynos based upstream clock driver
whereby the upstream clock driver sets all the clock gates into "manual mode"
(which uses a bit that is documented as reserved in the gate registers).

Another issue with the current "manual clock gating" approach upstream is
there are many bus/interconnect clocks whose relationships to the IPs
are not well documented or defined in the specs. When adding a new CMU until
now we have tried to label these clocks appropriately with CLK_IS_CRITICAL and
CLK_IGNORE_UNUSED but doing so is both error prone and time consuming. If
your lucky disabling a critical bus clock causes an immediate hang. Other
clocks however aren't so obvious and show up through random instability
some period of time later.

Fortunately each CMU (at least on newer Exynos) provides a "hardware
automatic clock gating" HWACG feature that is used by the downstream
Samsung clock drivers. Hardware automatic clock gating uses a hardware
interface between the CMU and IP to control all clocks required by the
IP. This interface is called Q-channel, and is part of the Arm AMBA low
power interface specification [1].

The advantage of using this Qchannel hardware interface for
enabling/disabling the clocks is that it takes care of all clocks
(including bus/interconnect) ones for the IP automatically thereby reducing
the dynamic power.

Whilst each clock component (GATE, MUX, DIV, QCH etc) has a HWACG enable
bit there are also some "global enable override" bits for the entire CMU in
the CMU_CONTROLLER_OPTION register.

This series makes use of those "global enable" override bits to enable auto
clock mode for the entire CMU and every component within it. Through
experimentation we can see that setting the "manual mode" reserved gate bit
on a particular gate register overides the global enable bits. So the code
is updated accordingly not to do that.

Auto clock mode has been implemented as a "opt in" by setting a new
auto_clock_gate flag in the CMU static data. The intention is existing
platforms in manual mode should not be effected by any of these changes.

If auto_clock_mode flag is set and the option_offset field is specified
then the global enable override bits will be written for the
CMU (to avoid relying on any prior bootstage configuration). Again if auto
mode is enabled the code no longer sets MANUAL and clears HWACG bits on
each gate register.

To ensure compatibility with older DTs (that specified an incorrect CMU
size) the resource size is checked and the driver falls back to manual
clock gate mode in such cases. As the CLK_IGNORE_UNUSED and CLK_IS_CRITICAL
flags are required for manual clock gate mode, the patch removing these
flags has been dropped from v2. I tested with an old DT and we successfully
switch to manual clock gate mode and the system correctly boots.

To have dynamic root clock gating (drcg) of bus components and memclk
enabled, it is required to set the bus_component_drcg and memclk registers
in the correspondingly named sysreg controller. If auto clock mode is
enabled the clock driver will now attempt to get the sysreg syscon via the
samsung,sysreg property (as used by other Exynos drivers upstream) and set
the registers accordingly. The suspend/resume code paths are also updated
to handle saving/restoring registers using a regmap. Note cmu_top is an
exception and does not have a corresondingly named sysreg_top.

As all clock gates are currently exposed in the gs101 drivers and DT, we
continue to register all of these gates in auto clock mode, but with some new
samsung_auto_clk_gate_ops. As clk enable and clk disable are now handled by
Q-channel interface the .enable and .disable implementations are
no-ops. However by using some CMU qchannel debug registers we can report
the current clock status (enabled or disabled) of every clock gate in the
system. This has the nice effect of still being able to dump the entire
clock tree from /sys/kernel/debug/clk/clk_summary and see a live view of
every auto clock in the system.

With the infrastructure in place, all the CMUs registered in clk-gs101 are
now updated to enable auto clock mode. From dumping
/sys/kernel/debug/clk/clk_summary it is possible to see that after enabling
auto clock mode approximately 305 clocks are enabled, and 299 are now
disabled. This number goes up and down a bit by 3-5 clocks just on a idle
system sat at a console.

With auto clock mode enabled it is now also possible to boot without the
clk_ignore_unused kernel command line property for the first time!

For future CMUs in gs101 I propose we continue to expose all gates, but
register the CMU in "auto mode". For new device drivers or updates to
existing dt bindings related to clocks to support gs101 I suggest we only
use the "obviously correct" clock(s). By "obviously correct" I mean a clock
has the IP name in the clock register name, but not try to deduce other
obsucurely named bus/interconnect clocks which will now all be handled
automatically. Note it is still possible to test whether the "obviously
correct" clock is indeed correct by putting the individual gate in manual
mode and disabling the clock (e.g. by using devmem).

Note: As everything here will go via one of Krzysztof's trees I've sent it
as one series.

regards,

Peter

[1] https://documentation-service.arm.com/static/5f915e69f86e16515cdc3b3e?token=

Signed-off-by: Peter Griffin <peter.griffin at linaro.org>
---
Changes in v7:
- Add Reviewed-by tags (Krzysztof)
- Link to v6: https://lore.kernel.org/r/20251220-automatic-clocks-v6-0-36c2f276a135 at linaro.org

Changes in v6:
- Rebased onto next-20251219 (Krzysztof)
- NOTE: linux-next has a regression atm 
  24ec03cc5512 ("serial: core: Restore sysfs fwnode information") needs to be
  reverted for boot testing this series on Pixel 6.
- Link to v5: https://lore.kernel.org/r/20251114-automatic-clocks-v5-0-efb9202ffcd7 at linaro.org

Changes in v5:
- Invert the test in dt-bindings: clock: google,gs101-clock (Andre)
- Link to v4: https://lore.kernel.org/r/20251110-automatic-clocks-v4-0-8f46929f50b7 at linaro.org

Changes in v4:
- Update commit description with additional requested details (Krzysztof)
- Remove unnecessary header of_address.h (Peter)
- Link to v3: https://lore.kernel.org/r/20251102-automatic-clocks-v3-0-ff10eafe61c8 at linaro.org

Changes in v3:
- Add missing 'np' func param to kerneldoc in samsung_cmu_register_clocks
(0-DAY CI )
- Link to v2: https://lore.kernel.org/r/20251029-automatic-clocks-v2-0-f8edd3a2d82b at linaro.org

Changes in v2:
- Rebased onto next-20251024
- Fallback to manual clock gate mode for old DTs with incorrect CMU reg
  size (added samsung_is_auto_capable(). Tested with old DT and it works as
  expected. It does require keeping all the CLK_IS_CRITICAL
  CLK_IGNORE_UNUSED flags in clk-gs101 so patch removing those is
  dropped. (Krzysztof)
- Rename OPT_UNKNOWN bit to OPT_EN_LAYER2_CTRL (Andre)
- Rename OPT_EN_MEM_PM_GATING to OPT_EN_MEM_PWR_GATING (Peter)
- Reverse Option bit definitions LSB -> MSB (Krzysztof)
- Update kerneldoc init_clk_regs comment (Andre)
- Fix space on various comments (Andre)
- Fix regmap typo on samsung_clk_save/restore calls (Andre)
- Include error code in pr_err message (Andre)
- Add macros for dcrg and memclk (Andre)
- Avoid confusing !IS_ERR_OR_NULL(ctx->sysreg) test (Krzysztof)
- Update kerneldoc to mention drcg_offset & memclk_offset are in sysreg
(Andre)
- Update bindings commit description as to why the sysreg is required
(Krzysztof)
- Link to v1: https://lore.kernel.org/r/20251013-automatic-clocks-v1-0-72851ee00300 at linaro.org

---
Peter Griffin (4):
      dt-bindings: clock: google,gs101-clock: add samsung,sysreg property as required
      arm64: dts: exynos: gs101: add samsung,sysreg property to CMU nodes
      clk: samsung: Implement automatic clock gating mode for CMUs
      clk: samsung: gs101: Enable auto_clock_gate mode for each gs101 CMU

 .../bindings/clock/google,gs101-clock.yaml         |  19 +-
 arch/arm64/boot/dts/exynos/google/gs101.dtsi       |   6 +
 drivers/clk/samsung/clk-exynos-arm64.c             |  62 ++++++-
 drivers/clk/samsung/clk-exynos4.c                  |  12 +-
 drivers/clk/samsung/clk-exynos4412-isp.c           |   4 +-
 drivers/clk/samsung/clk-exynos5250.c               |   2 +-
 drivers/clk/samsung/clk-exynos5420.c               |   4 +-
 drivers/clk/samsung/clk-gs101.c                    |  55 ++++++
 drivers/clk/samsung/clk-s3c64xx.c                  |   4 +-
 drivers/clk/samsung/clk-s5pv210.c                  |   2 +-
 drivers/clk/samsung/clk.c                          | 200 +++++++++++++++++++--
 drivers/clk/samsung/clk.h                          |  55 +++++-
 12 files changed, 381 insertions(+), 44 deletions(-)
---
base-commit: cc3aa43b44bdb43dfbac0fcb51c56594a11338a8
change-id: 20251008-automatic-clocks-249ab60f62ce

Best regards,
-- 
Peter Griffin <peter.griffin at linaro.org>



From peter.griffin at linaro.org  Mon Dec 22 02:22:12 2025
From: peter.griffin at linaro.org (Peter Griffin)
Date: Mon, 22 Dec 2025 10:22:12 +0000
Subject: [PATCH v7 1/4] dt-bindings: clock: google,gs101-clock: add
 samsung,sysreg property as required
In-Reply-To: <20251222-automatic-clocks-v7-0-fec86fa89874@linaro.org>
References: <20251222-automatic-clocks-v7-0-fec86fa89874@linaro.org>
Message-ID: <20251222-automatic-clocks-v7-1-fec86fa89874@linaro.org>

Each CMU (with the exception of cmu_top) has a corresponding sysreg bank
that contains the BUSCOMPONENT_DRCG_EN and optional MEMCLK registers.
The BUSCOMPONENT_DRCG_EN register enables dynamic root clock gating of
bus components and MEMCLK gates the sram clock.

Now the clock driver supports automatic clock mode, to fully enable dynamic
root clock gating it is required to configure these registers. Update the
bindings documentation so that all CMUs (with the exception of
gs101-cmu-top) have samsung,sysreg as a required property.

Note this is NOT an ABI break, as if the property isn't specified the
clock driver will fallback to the current behaviour of not initializing
the registers. The system still boots, but bus components won't benefit
from dynamic root clock gating and dynamic power will be higher (which has
been the case until now anyway).

Additionally update the DT example to included the correct CMU size as
registers in that region are used for automatic clock mode.

Acked-by: Rob Herring (Arm) <robh at kernel.org>
Reviewed-by: Andr? Draszik <andre.draszik at linaro.org>
Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Peter Griffin <peter.griffin at linaro.org>
---
Changes in v5:
- Invert the test for google,gs101-cmu-top (Andre)

Changes in v4
- Update commit description with additional requested details (Krzysztof)

Changes in v3:
- Update commit description as to why the sysreg is required (Krzysztof)

Changes in v2:
- Update commit description regarding updated example (Andre)
---
 .../devicetree/bindings/clock/google,gs101-clock.yaml | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml b/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
index 31e106ef913dead9a038b3b6d8b43b950587f6aa..09e679c1a9def03d53b8b493929911ea902a1763 100644
--- a/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
+++ b/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
@@ -52,6 +52,11 @@ properties:
   reg:
     maxItems: 1
 
+  samsung,sysreg:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      Phandle to system registers interface.
+
 required:
   - compatible
   - "#clock-cells"
@@ -166,6 +171,18 @@ allOf:
             - const: bus
             - const: ip
 
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: google,gs101-cmu-top
+    then:
+      properties:
+        samsung,sysreg: false
+    else:
+      required:
+        - samsung,sysreg
+
 additionalProperties: false
 
 examples:
@@ -175,7 +192,7 @@ examples:
 
     cmu_top: clock-controller at 1e080000 {
         compatible = "google,gs101-cmu-top";
-        reg = <0x1e080000 0x8000>;
+        reg = <0x1e080000 0x10000>;
         #clock-cells = <1>;
         clocks = <&ext_24_5m>;
         clock-names = "oscclk";

-- 
2.52.0.351.gbe84eed79e-goog



From peter.griffin at linaro.org  Mon Dec 22 02:22:13 2025
From: peter.griffin at linaro.org (Peter Griffin)
Date: Mon, 22 Dec 2025 10:22:13 +0000
Subject: [PATCH v7 2/4] arm64: dts: exynos: gs101: add samsung,sysreg
 property to CMU nodes
In-Reply-To: <20251222-automatic-clocks-v7-0-fec86fa89874@linaro.org>
References: <20251222-automatic-clocks-v7-0-fec86fa89874@linaro.org>
Message-ID: <20251222-automatic-clocks-v7-2-fec86fa89874@linaro.org>

With the exception of cmu_top, each CMU has a corresponding sysreg bank
that contains the BUSCOMPONENT_DRCG_EN and optional MEMCLK registers.
The BUSCOMPONENT_DRCG_EN register enables dynamic root clock gating of
bus components and MEMCLK gates the sram clock.

Now the clock driver supports automatic clock mode, provide the
samsung,sysreg property so the driver can enable dynamic root clock
gating of bus components and gate sram clock.

Note without the property specified the driver simply falls back to
previous behaviour of not configuring these registers so it is not an ABI
break.

Signed-off-by: Peter Griffin <peter.griffin at linaro.org>
---
Changes in v4:
- Update commit message (Peter)
---
 arch/arm64/boot/dts/exynos/google/gs101.dtsi | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm64/boot/dts/exynos/google/gs101.dtsi b/arch/arm64/boot/dts/exynos/google/gs101.dtsi
index 9b38c2248016aa65293c0abf9ccaf20857d89693..2e25eeb0c2590b99ef98c7bdac3caa0c34161706 100644
--- a/arch/arm64/boot/dts/exynos/google/gs101.dtsi
+++ b/arch/arm64/boot/dts/exynos/google/gs101.dtsi
@@ -578,6 +578,7 @@ cmu_misc: clock-controller at 10010000 {
 			clocks = <&cmu_top CLK_DOUT_CMU_MISC_BUS>,
 				 <&cmu_top CLK_DOUT_CMU_MISC_SSS>;
 			clock-names = "bus", "sss";
+			samsung,sysreg = <&sysreg_misc>;
 		};
 
 		sysreg_misc: syscon at 10030000 {
@@ -671,6 +672,7 @@ cmu_peric0: clock-controller at 10800000 {
 				 <&cmu_top CLK_DOUT_CMU_PERIC0_BUS>,
 				 <&cmu_top CLK_DOUT_CMU_PERIC0_IP>;
 			clock-names = "oscclk", "bus", "ip";
+			samsung,sysreg = <&sysreg_peric0>;
 		};
 
 		sysreg_peric0: syscon at 10820000 {
@@ -1217,6 +1219,7 @@ cmu_peric1: clock-controller at 10c00000 {
 				 <&cmu_top CLK_DOUT_CMU_PERIC1_BUS>,
 				 <&cmu_top CLK_DOUT_CMU_PERIC1_IP>;
 			clock-names = "oscclk", "bus", "ip";
+			samsung,sysreg = <&sysreg_peric1>;
 		};
 
 		sysreg_peric1: syscon at 10c20000 {
@@ -1575,6 +1578,7 @@ cmu_hsi0: clock-controller at 11000000 {
 				 <&cmu_top CLK_DOUT_CMU_HSI0_USBDPDBG>;
 			clock-names = "oscclk", "bus", "dpgtc", "usb31drd",
 				      "usbdpdbg";
+			samsung,sysreg = <&sysreg_hsi0>;
 		};
 
 		sysreg_hsi0: syscon at 11020000 {
@@ -1646,6 +1650,7 @@ cmu_hsi2: clock-controller at 14400000 {
 				 <&cmu_top CLK_DOUT_CMU_HSI2_UFS_EMBD>,
 				 <&cmu_top CLK_DOUT_CMU_HSI2_MMC_CARD>;
 			clock-names = "oscclk", "bus", "pcie", "ufs", "mmc";
+			samsung,sysreg = <&sysreg_hsi2>;
 		};
 
 		sysreg_hsi2: syscon at 14420000 {
@@ -1706,6 +1711,7 @@ cmu_apm: clock-controller at 17400000 {
 
 			clocks = <&ext_24_5m>;
 			clock-names = "oscclk";
+			samsung,sysreg = <&sysreg_apm>;
 		};
 
 		sysreg_apm: syscon at 17420000 {

-- 
2.52.0.351.gbe84eed79e-goog



From peter.griffin at linaro.org  Mon Dec 22 02:22:14 2025
From: peter.griffin at linaro.org (Peter Griffin)
Date: Mon, 22 Dec 2025 10:22:14 +0000
Subject: [PATCH v7 3/4] clk: samsung: Implement automatic clock gating mode
 for CMUs
In-Reply-To: <20251222-automatic-clocks-v7-0-fec86fa89874@linaro.org>
References: <20251222-automatic-clocks-v7-0-fec86fa89874@linaro.org>
Message-ID: <20251222-automatic-clocks-v7-3-fec86fa89874@linaro.org>

Update exynos_arm64_init_clocks() so that it enables the automatic clock
mode bits in the CMU option register if the auto_clock_gate flag and
option_offset fields are set for the CMU. To ensure compatibility with
older DTs (that specified an incorrect CMU reg size), detect this and
fallback to manual clock gate mode as the auto clock mode feature depends
on registers in this area.

The CMU option register bits are global and effect every clock component in
the CMU, as such clearing the GATE_ENABLE_HWACG bit and setting GATE_MANUAL
bit on every gate register is only required if auto_clock_gate is false.

Additionally if auto_clock_gate is enabled the dynamic root clock gating
and memclk registers will be configured in the corresponding CMUs sysreg
bank. These registers are exposed via syscon, so the register
samsung_clk_save/restore paths are updated to also take a regmap.

As many gates for various Samsung SoCs are already exposed in the Samsung
clock drivers a new samsung_auto_clk_gate_ops is implemented. This uses
some CMU debug registers to report whether clocks are enabled or disabled
when operating in automatic mode. This allows
/sys/kernel/debug/clk/clk_summary to still dump the entire clock tree and
correctly report the status of each clock in the system.

Signed-off-by: Peter Griffin <peter.griffin at linaro.org>
---
Changes in v3:
- Add missing 'np' func param to kerneldoc in samsung_cmu_register_clocks
(0-DAY CI)

Changes in v2:
- Fallback to manual clock gate mode for old DTs with incorrect CMU size
(added samsung_is_auto_capable()) (Krzysztof)
- Rename OPT_UNKNOWN bit to OPT_EN_LAYER2_CTRL (Andre)
- Rename OPT_EN_MEM_PM_GATING to OPT_EN_MEM_PWR_GATING (Andre)
- Reverse Option bit definitions LSB -> MSB (Krzysztof)
- Update kerneldoc init_clk_regs comment (Andre)
- Fix space on various comments (Andre)
- Fix regmap typo on samsung_clk_save/restore calls (Andre)
- Include error code in pr_err message (Andre)
- Add macros for dcrg and memclk (Andre)
- Avoid confusing !IS_ERR_OR_NULL(ctx->sysreg) test (Krzysztof)
- Update kerneldoc to mention drcg_offset & memclk_offset are in sysreg (Andre)
- Fix 0-DAY CI randconfig warning (0-DAY CI)
- Update clk-s5pv210 and clk-s3c64xx.c samsung_clk_sleep_init call sites (Peter)
---
 drivers/clk/samsung/clk-exynos-arm64.c   |  62 ++++++++--
 drivers/clk/samsung/clk-exynos4.c        |  12 +-
 drivers/clk/samsung/clk-exynos4412-isp.c |   4 +-
 drivers/clk/samsung/clk-exynos5250.c     |   2 +-
 drivers/clk/samsung/clk-exynos5420.c     |   4 +-
 drivers/clk/samsung/clk-s3c64xx.c        |   4 +-
 drivers/clk/samsung/clk-s5pv210.c        |   2 +-
 drivers/clk/samsung/clk.c                | 200 ++++++++++++++++++++++++++++---
 drivers/clk/samsung/clk.h                |  55 ++++++++-
 9 files changed, 302 insertions(+), 43 deletions(-)

diff --git a/drivers/clk/samsung/clk-exynos-arm64.c b/drivers/clk/samsung/clk-exynos-arm64.c
index bf7de21f329ec89069dcf817ca578fcf9b2d9809..11e4d49f2390ba714eff5a329bb1f427cd6437b9 100644
--- a/drivers/clk/samsung/clk-exynos-arm64.c
+++ b/drivers/clk/samsung/clk-exynos-arm64.c
@@ -24,6 +24,16 @@
 #define GATE_MANUAL		BIT(20)
 #define GATE_ENABLE_HWACG	BIT(28)
 
+/* Option register bits */
+#define OPT_EN_MEM_PWR_GATING		BIT(24)
+#define OPT_EN_AUTO_GATING		BIT(28)
+#define OPT_EN_PWR_MANAGEMENT		BIT(29)
+#define OPT_EN_LAYER2_CTRL		BIT(30)
+#define OPT_EN_DBG			BIT(31)
+
+#define CMU_OPT_GLOBAL_EN_AUTO_GATING	(OPT_EN_DBG | OPT_EN_LAYER2_CTRL | \
+	OPT_EN_PWR_MANAGEMENT | OPT_EN_AUTO_GATING | OPT_EN_MEM_PWR_GATING)
+
 /* PLL_CONx_PLL register offsets range */
 #define PLL_CON_OFF_START	0x100
 #define PLL_CON_OFF_END		0x600
@@ -37,6 +47,8 @@ struct exynos_arm64_cmu_data {
 	unsigned int nr_clk_save;
 	const struct samsung_clk_reg_dump *clk_suspend;
 	unsigned int nr_clk_suspend;
+	struct samsung_clk_reg_dump *clk_sysreg_save;
+	unsigned int nr_clk_sysreg;
 
 	struct clk *clk;
 	struct clk **pclks;
@@ -76,19 +88,41 @@ static void __init exynos_arm64_init_clocks(struct device_node *np,
 	const unsigned long *reg_offs = cmu->clk_regs;
 	size_t reg_offs_len = cmu->nr_clk_regs;
 	void __iomem *reg_base;
+	bool init_auto;
 	size_t i;
 
 	reg_base = of_iomap(np, 0);
 	if (!reg_base)
 		panic("%s: failed to map registers\n", __func__);
 
+	/* ensure compatibility with older DTs */
+	if (cmu->auto_clock_gate && samsung_is_auto_capable(np))
+		init_auto = true;
+	else
+		init_auto = false;
+
+	if (cmu->option_offset && init_auto) {
+		/*
+		 * Enable the global automatic mode for the entire CMU.
+		 * This overrides the individual HWACG bits in each of the
+		 * individual gate, mux and qch registers.
+		 */
+		writel(CMU_OPT_GLOBAL_EN_AUTO_GATING,
+		       reg_base + cmu->option_offset);
+	}
+
 	for (i = 0; i < reg_offs_len; ++i) {
 		void __iomem *reg = reg_base + reg_offs[i];
 		u32 val;
 
 		if (cmu->manual_plls && is_pll_con1_reg(reg_offs[i])) {
 			writel(PLL_CON1_MANUAL, reg);
-		} else if (is_gate_reg(reg_offs[i])) {
+		} else if (is_gate_reg(reg_offs[i]) && !init_auto) {
+			/*
+			 * Setting GATE_MANUAL bit (which is described in TRM as
+			 * reserved!) overrides the global CMU automatic mode
+			 * option.
+			 */
 			val = readl(reg);
 			val |= GATE_MANUAL;
 			val &= ~GATE_ENABLE_HWACG;
@@ -210,8 +244,8 @@ void __init exynos_arm64_register_cmu(struct device *dev,
 /**
  * exynos_arm64_register_cmu_pm - Register Exynos CMU domain with PM support
  *
- * @pdev:	Platform device object
- * @set_manual:	If true, set gate clocks to manual mode
+ * @pdev:		Platform device object
+ * @init_clk_regs:	If true, initialize CMU registers
  *
  * It's a version of exynos_arm64_register_cmu() with PM support. Should be
  * called from probe function of platform driver.
@@ -219,7 +253,7 @@ void __init exynos_arm64_register_cmu(struct device *dev,
  * Return: 0 on success, or negative error code on error.
  */
 int __init exynos_arm64_register_cmu_pm(struct platform_device *pdev,
-					bool set_manual)
+					bool init_clk_regs)
 {
 	const struct samsung_cmu_info *cmu;
 	struct device *dev = &pdev->dev;
@@ -249,7 +283,7 @@ int __init exynos_arm64_register_cmu_pm(struct platform_device *pdev,
 		dev_err(dev, "%s: could not enable bus clock %s; err = %d\n",
 		       __func__, cmu->clk_name, ret);
 
-	if (set_manual)
+	if (init_clk_regs)
 		exynos_arm64_init_clocks(np, cmu);
 
 	reg_base = devm_platform_ioremap_resource(pdev, 0);
@@ -268,8 +302,10 @@ int __init exynos_arm64_register_cmu_pm(struct platform_device *pdev,
 	pm_runtime_set_active(dev);
 	pm_runtime_enable(dev);
 
-	samsung_cmu_register_clocks(data->ctx, cmu);
+	samsung_cmu_register_clocks(data->ctx, cmu, np);
 	samsung_clk_of_add_provider(dev->of_node, data->ctx);
+	/* sysreg DT nodes reference a clock in this CMU */
+	samsung_en_dyn_root_clk_gating(np, data->ctx, cmu);
 	pm_runtime_put_sync(dev);
 
 	return 0;
@@ -280,14 +316,17 @@ int exynos_arm64_cmu_suspend(struct device *dev)
 	struct exynos_arm64_cmu_data *data = dev_get_drvdata(dev);
 	int i;
 
-	samsung_clk_save(data->ctx->reg_base, data->clk_save,
+	samsung_clk_save(data->ctx->reg_base, NULL, data->clk_save,
 			 data->nr_clk_save);
 
+	samsung_clk_save(NULL, data->ctx->sysreg, data->clk_sysreg_save,
+			 data->nr_clk_sysreg);
+
 	for (i = 0; i < data->nr_pclks; i++)
 		clk_prepare_enable(data->pclks[i]);
 
 	/* For suspend some registers have to be set to certain values */
-	samsung_clk_restore(data->ctx->reg_base, data->clk_suspend,
+	samsung_clk_restore(data->ctx->reg_base, NULL, data->clk_suspend,
 			    data->nr_clk_suspend);
 
 	for (i = 0; i < data->nr_pclks; i++)
@@ -308,9 +347,14 @@ int exynos_arm64_cmu_resume(struct device *dev)
 	for (i = 0; i < data->nr_pclks; i++)
 		clk_prepare_enable(data->pclks[i]);
 
-	samsung_clk_restore(data->ctx->reg_base, data->clk_save,
+	samsung_clk_restore(data->ctx->reg_base, NULL, data->clk_save,
 			    data->nr_clk_save);
 
+	if (data->ctx->sysreg)
+		samsung_clk_restore(NULL, data->ctx->sysreg,
+				    data->clk_sysreg_save,
+				    data->nr_clk_sysreg);
+
 	for (i = 0; i < data->nr_pclks; i++)
 		clk_disable_unprepare(data->pclks[i]);
 
diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c
index cc5c1644c41c08b27bc48d809a08cd8a006cbe8f..246bd28bac2d577a58a7b9e0e93b700548370a36 100644
--- a/drivers/clk/samsung/clk-exynos4.c
+++ b/drivers/clk/samsung/clk-exynos4.c
@@ -1361,12 +1361,12 @@ static void __init exynos4_clk_init(struct device_node *np,
 					ARRAY_SIZE(exynos4x12_plls));
 	}
 
-	samsung_cmu_register_clocks(ctx, &cmu_info_exynos4);
+	samsung_cmu_register_clocks(ctx, &cmu_info_exynos4, np);
 
 	if (exynos4_soc == EXYNOS4210) {
-		samsung_cmu_register_clocks(ctx, &cmu_info_exynos4210);
+		samsung_cmu_register_clocks(ctx, &cmu_info_exynos4210, np);
 	} else {
-		samsung_cmu_register_clocks(ctx, &cmu_info_exynos4x12);
+		samsung_cmu_register_clocks(ctx, &cmu_info_exynos4x12, np);
 		if (soc == EXYNOS4412)
 			samsung_clk_register_cpu(ctx, exynos4412_cpu_clks,
 					ARRAY_SIZE(exynos4412_cpu_clks));
@@ -1378,15 +1378,15 @@ static void __init exynos4_clk_init(struct device_node *np,
 	if (soc == EXYNOS4212 || soc == EXYNOS4412)
 		exynos4x12_core_down_clock();
 
-	samsung_clk_extended_sleep_init(reg_base,
+	samsung_clk_extended_sleep_init(reg_base, NULL,
 			exynos4_clk_regs, ARRAY_SIZE(exynos4_clk_regs),
 			src_mask_suspend, ARRAY_SIZE(src_mask_suspend));
 	if (exynos4_soc == EXYNOS4210)
-		samsung_clk_extended_sleep_init(reg_base,
+		samsung_clk_extended_sleep_init(reg_base, NULL,
 		    exynos4210_clk_save, ARRAY_SIZE(exynos4210_clk_save),
 		    src_mask_suspend_e4210, ARRAY_SIZE(src_mask_suspend_e4210));
 	else
-		samsung_clk_sleep_init(reg_base, exynos4x12_clk_save,
+		samsung_clk_sleep_init(reg_base, NULL, exynos4x12_clk_save,
 				       ARRAY_SIZE(exynos4x12_clk_save));
 
 	samsung_clk_of_add_provider(np, ctx);
diff --git a/drivers/clk/samsung/clk-exynos4412-isp.c b/drivers/clk/samsung/clk-exynos4412-isp.c
index fa915057e109e0008ebe0b1b5d1652fd5804e82b..772bc18a1e686f23b11bf160b803becff6279637 100644
--- a/drivers/clk/samsung/clk-exynos4412-isp.c
+++ b/drivers/clk/samsung/clk-exynos4412-isp.c
@@ -94,7 +94,7 @@ static int __maybe_unused exynos4x12_isp_clk_suspend(struct device *dev)
 {
 	struct samsung_clk_provider *ctx = dev_get_drvdata(dev);
 
-	samsung_clk_save(ctx->reg_base, exynos4x12_save_isp,
+	samsung_clk_save(ctx->reg_base, NULL, exynos4x12_save_isp,
 			 ARRAY_SIZE(exynos4x12_clk_isp_save));
 	return 0;
 }
@@ -103,7 +103,7 @@ static int __maybe_unused exynos4x12_isp_clk_resume(struct device *dev)
 {
 	struct samsung_clk_provider *ctx = dev_get_drvdata(dev);
 
-	samsung_clk_restore(ctx->reg_base, exynos4x12_save_isp,
+	samsung_clk_restore(ctx->reg_base, NULL, exynos4x12_save_isp,
 			    ARRAY_SIZE(exynos4x12_clk_isp_save));
 	return 0;
 }
diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c
index e90d3a0848cbc24b2709c10795f6affcda404567..f97f30b29be7317db8186bac39cf52e1893eb106 100644
--- a/drivers/clk/samsung/clk-exynos5250.c
+++ b/drivers/clk/samsung/clk-exynos5250.c
@@ -854,7 +854,7 @@ static void __init exynos5250_clk_init(struct device_node *np)
 		PWR_CTRL2_CORE2_UP_RATIO | PWR_CTRL2_CORE1_UP_RATIO);
 	__raw_writel(tmp, reg_base + PWR_CTRL2);
 
-	samsung_clk_sleep_init(reg_base, exynos5250_clk_regs,
+	samsung_clk_sleep_init(reg_base, NULL, exynos5250_clk_regs,
 			       ARRAY_SIZE(exynos5250_clk_regs));
 	exynos5_subcmus_init(ctx, ARRAY_SIZE(exynos5250_subcmus),
 			     exynos5250_subcmus);
diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c
index a9df4e6db82fa7831d4e5c7210b0163d7d301ec1..1982e0751ceec7e57f9e82d96dcbadce1f691092 100644
--- a/drivers/clk/samsung/clk-exynos5420.c
+++ b/drivers/clk/samsung/clk-exynos5420.c
@@ -1649,12 +1649,12 @@ static void __init exynos5x_clk_init(struct device_node *np,
 				ARRAY_SIZE(exynos5800_cpu_clks));
 	}
 
-	samsung_clk_extended_sleep_init(reg_base,
+	samsung_clk_extended_sleep_init(reg_base, NULL,
 		exynos5x_clk_regs, ARRAY_SIZE(exynos5x_clk_regs),
 		exynos5420_set_clksrc, ARRAY_SIZE(exynos5420_set_clksrc));
 
 	if (soc == EXYNOS5800) {
-		samsung_clk_sleep_init(reg_base, exynos5800_clk_regs,
+		samsung_clk_sleep_init(reg_base, NULL, exynos5800_clk_regs,
 				       ARRAY_SIZE(exynos5800_clk_regs));
 
 		exynos5_subcmus_init(ctx, ARRAY_SIZE(exynos5800_subcmus),
diff --git a/drivers/clk/samsung/clk-s3c64xx.c b/drivers/clk/samsung/clk-s3c64xx.c
index 397a057af5d1e704e7ead7ba04b477fdc28c45bf..5a2d5a5703ffc5ed48b9a18a20c39be2de827920 100644
--- a/drivers/clk/samsung/clk-s3c64xx.c
+++ b/drivers/clk/samsung/clk-s3c64xx.c
@@ -449,10 +449,10 @@ void __init s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f,
 	samsung_clk_register_alias(ctx, s3c64xx_clock_aliases,
 					ARRAY_SIZE(s3c64xx_clock_aliases));
 
-	samsung_clk_sleep_init(reg_base, s3c64xx_clk_regs,
+	samsung_clk_sleep_init(reg_base, NULL, s3c64xx_clk_regs,
 			       ARRAY_SIZE(s3c64xx_clk_regs));
 	if (!is_s3c6400)
-		samsung_clk_sleep_init(reg_base, s3c6410_clk_regs,
+		samsung_clk_sleep_init(reg_base, NULL, s3c6410_clk_regs,
 				       ARRAY_SIZE(s3c6410_clk_regs));
 
 	samsung_clk_of_add_provider(np, ctx);
diff --git a/drivers/clk/samsung/clk-s5pv210.c b/drivers/clk/samsung/clk-s5pv210.c
index 9a4217cc1908aa60ebbe51b2b5c841138cc46ef3..4ee4f2b5efbc1d4770fefff22de21f7d4e5e9506 100644
--- a/drivers/clk/samsung/clk-s5pv210.c
+++ b/drivers/clk/samsung/clk-s5pv210.c
@@ -782,7 +782,7 @@ static void __init __s5pv210_clk_init(struct device_node *np,
 	samsung_clk_register_alias(ctx, s5pv210_aliases,
 						ARRAY_SIZE(s5pv210_aliases));
 
-	samsung_clk_sleep_init(reg_base, s5pv210_clk_regs,
+	samsung_clk_sleep_init(reg_base, NULL, s5pv210_clk_regs,
 			       ARRAY_SIZE(s5pv210_clk_regs));
 
 	samsung_clk_of_add_provider(np, ctx);
diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c
index c149ca6c221725195faeb76b0d73374c3b48261b..06ea5deef4ee2ffb87dcd14102561886ea80b7bc 100644
--- a/drivers/clk/samsung/clk.c
+++ b/drivers/clk/samsung/clk.c
@@ -12,8 +12,10 @@
 #include <linux/clkdev.h>
 #include <linux/clk-provider.h>
 #include <linux/io.h>
+#include <linux/mfd/syscon.h>
 #include <linux/mod_devicetable.h>
 #include <linux/of_address.h>
+#include <linux/regmap.h>
 #include <linux/syscore_ops.h>
 
 #include "clk.h"
@@ -21,19 +23,29 @@
 static LIST_HEAD(clock_reg_cache_list);
 
 void samsung_clk_save(void __iomem *base,
+				    struct regmap *regmap,
 				    struct samsung_clk_reg_dump *rd,
 				    unsigned int num_regs)
 {
-	for (; num_regs > 0; --num_regs, ++rd)
-		rd->value = readl(base + rd->offset);
+	for (; num_regs > 0; --num_regs, ++rd) {
+		if (base)
+			rd->value = readl(base + rd->offset);
+		else if (regmap)
+			regmap_read(regmap, rd->offset, &rd->value);
+	}
 }
 
 void samsung_clk_restore(void __iomem *base,
+				      struct regmap *regmap,
 				      const struct samsung_clk_reg_dump *rd,
 				      unsigned int num_regs)
 {
-	for (; num_regs > 0; --num_regs, ++rd)
-		writel(rd->value, base + rd->offset);
+	for (; num_regs > 0; --num_regs, ++rd) {
+		if (base)
+			writel(rd->value, base + rd->offset);
+		else if (regmap)
+			regmap_write(regmap, rd->offset, rd->value);
+	}
 }
 
 struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump(
@@ -227,6 +239,103 @@ void __init samsung_clk_register_div(struct samsung_clk_provider *ctx,
 	}
 }
 
+/*
+ * Some older DT's have an incorrect CMU resource size which is incompatible
+ * with the auto clock mode feature. In such cases we switch back to manual
+ * clock gating mode.
+ */
+bool samsung_is_auto_capable(struct device_node *np)
+{
+	struct resource res;
+	resource_size_t size;
+
+	if (of_address_to_resource(np, 0, &res))
+		return false;
+
+	size = resource_size(&res);
+	if (size != 0x10000) {
+		pr_warn("%pOF: incorrect res size for automatic clocks\n", np);
+		return false;
+	}
+	return true;
+}
+
+#define ACG_MSK GENMASK(6, 4)
+#define CLK_IDLE GENMASK(5, 4)
+static int samsung_auto_clk_gate_is_en(struct clk_hw *hw)
+{
+	u32 reg;
+	struct clk_gate *gate = to_clk_gate(hw);
+
+	reg = readl(gate->reg);
+	return ((reg & ACG_MSK) == CLK_IDLE) ? 0 : 1;
+}
+
+/* enable and disable are nops in automatic clock mode */
+static int samsung_auto_clk_gate_en(struct clk_hw *hw)
+{
+	return 0;
+}
+
+static void samsung_auto_clk_gate_dis(struct clk_hw *hw)
+{
+}
+
+static const struct clk_ops samsung_auto_clk_gate_ops = {
+	.enable = samsung_auto_clk_gate_en,
+	.disable = samsung_auto_clk_gate_dis,
+	.is_enabled = samsung_auto_clk_gate_is_en,
+};
+
+struct clk_hw *samsung_register_auto_gate(struct device *dev,
+		struct device_node *np, const char *name,
+		const char *parent_name, const struct clk_hw *parent_hw,
+		const struct clk_parent_data *parent_data,
+		unsigned long flags,
+		void __iomem *reg, u8 bit_idx,
+		u8 clk_gate_flags, spinlock_t *lock)
+{
+	struct clk_gate *gate;
+	struct clk_hw *hw;
+	struct clk_init_data init = {};
+	int ret = -EINVAL;
+
+	/* allocate the gate */
+	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+	if (!gate)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &samsung_auto_clk_gate_ops;
+	init.flags = flags;
+	init.parent_names = parent_name ? &parent_name : NULL;
+	init.parent_hws = parent_hw ? &parent_hw : NULL;
+	init.parent_data = parent_data;
+	if (parent_name || parent_hw || parent_data)
+		init.num_parents = 1;
+	else
+		init.num_parents = 0;
+
+	/* struct clk_gate assignments */
+	gate->reg = reg;
+	gate->bit_idx = bit_idx;
+	gate->flags = clk_gate_flags;
+	gate->lock = lock;
+	gate->hw.init = &init;
+
+	hw = &gate->hw;
+	if (dev || !np)
+		ret = clk_hw_register(dev, hw);
+	else if (np)
+		ret = of_clk_hw_register(np, hw);
+	if (ret) {
+		kfree(gate);
+		hw = ERR_PTR(ret);
+	}
+
+	return hw;
+}
+
 /* register a list of gate clocks */
 void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx,
 				const struct samsung_gate_clock *list,
@@ -234,14 +343,24 @@ void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx,
 {
 	struct clk_hw *clk_hw;
 	unsigned int idx;
+	void __iomem *reg_offs;
 
 	for (idx = 0; idx < nr_clk; idx++, list++) {
-		clk_hw = clk_hw_register_gate(ctx->dev, list->name, list->parent_name,
-				list->flags, ctx->reg_base + list->offset,
+		reg_offs = ctx->reg_base + list->offset;
+
+		if (ctx->auto_clock_gate && ctx->gate_dbg_offset)
+			clk_hw = samsung_register_auto_gate(ctx->dev, NULL,
+				list->name, list->parent_name, NULL, NULL,
+				list->flags, reg_offs + ctx->gate_dbg_offset,
 				list->bit_idx, list->gate_flags, &ctx->lock);
+		else
+			clk_hw = clk_hw_register_gate(ctx->dev, list->name,
+				list->parent_name, list->flags,
+				ctx->reg_base + list->offset, list->bit_idx,
+				list->gate_flags, &ctx->lock);
 		if (IS_ERR(clk_hw)) {
-			pr_err("%s: failed to register clock %s\n", __func__,
-				list->name);
+			pr_err("%s: failed to register clock %s: %ld\n", __func__,
+				list->name, PTR_ERR(clk_hw));
 			continue;
 		}
 
@@ -276,10 +395,11 @@ static int samsung_clk_suspend(void *data)
 	struct samsung_clock_reg_cache *reg_cache;
 
 	list_for_each_entry(reg_cache, &clock_reg_cache_list, node) {
-		samsung_clk_save(reg_cache->reg_base, reg_cache->rdump,
-				reg_cache->rd_num);
-		samsung_clk_restore(reg_cache->reg_base, reg_cache->rsuspend,
-				reg_cache->rsuspend_num);
+		samsung_clk_save(reg_cache->reg_base, reg_cache->sysreg,
+				 reg_cache->rdump, reg_cache->rd_num);
+		samsung_clk_restore(reg_cache->reg_base, reg_cache->sysreg,
+				    reg_cache->rsuspend,
+				    reg_cache->rsuspend_num);
 	}
 	return 0;
 }
@@ -289,8 +409,8 @@ static void samsung_clk_resume(void *data)
 	struct samsung_clock_reg_cache *reg_cache;
 
 	list_for_each_entry(reg_cache, &clock_reg_cache_list, node)
-		samsung_clk_restore(reg_cache->reg_base, reg_cache->rdump,
-				reg_cache->rd_num);
+		samsung_clk_restore(reg_cache->reg_base, reg_cache->sysreg,
+				    reg_cache->rdump, reg_cache->rd_num);
 }
 
 static const struct syscore_ops samsung_clk_syscore_ops = {
@@ -303,6 +423,7 @@ static struct syscore samsung_clk_syscore = {
 };
 
 void samsung_clk_extended_sleep_init(void __iomem *reg_base,
+			struct regmap *sysreg,
 			const unsigned long *rdump,
 			unsigned long nr_rdump,
 			const struct samsung_clk_reg_dump *rsuspend,
@@ -323,6 +444,7 @@ void samsung_clk_extended_sleep_init(void __iomem *reg_base,
 		register_syscore(&samsung_clk_syscore);
 
 	reg_cache->reg_base = reg_base;
+	reg_cache->sysreg = sysreg;
 	reg_cache->rd_num = nr_rdump;
 	reg_cache->rsuspend = rsuspend;
 	reg_cache->rsuspend_num = nr_rsuspend;
@@ -334,10 +456,20 @@ void samsung_clk_extended_sleep_init(void __iomem *reg_base,
  * samsung_cmu_register_clocks() - Register all clocks provided in CMU object
  * @ctx: Clock provider object
  * @cmu: CMU object with clocks to register
+ * @np:  CMU device tree node
  */
 void __init samsung_cmu_register_clocks(struct samsung_clk_provider *ctx,
-					const struct samsung_cmu_info *cmu)
+					const struct samsung_cmu_info *cmu,
+					struct device_node *np)
 {
+	if (samsung_is_auto_capable(np) && cmu->auto_clock_gate)
+		ctx->auto_clock_gate = cmu->auto_clock_gate;
+
+	ctx->gate_dbg_offset = cmu->gate_dbg_offset;
+	ctx->option_offset = cmu->option_offset;
+	ctx->drcg_offset = cmu->drcg_offset;
+	ctx->memclk_offset = cmu->memclk_offset;
+
 	if (cmu->pll_clks)
 		samsung_clk_register_pll(ctx, cmu->pll_clks, cmu->nr_pll_clks);
 	if (cmu->mux_clks)
@@ -357,6 +489,37 @@ void __init samsung_cmu_register_clocks(struct samsung_clk_provider *ctx,
 		samsung_clk_register_cpu(ctx, cmu->cpu_clks, cmu->nr_cpu_clks);
 }
 
+/* Each bit enable/disables DRCG of a bus component */
+#define DRCG_EN_MSK	GENMASK(31, 0)
+#define MEMCLK_EN	BIT(0)
+
+/* Enable Dynamic Root Clock Gating (DRCG) of bus components */
+void samsung_en_dyn_root_clk_gating(struct device_node *np,
+				    struct samsung_clk_provider *ctx,
+				    const struct samsung_cmu_info *cmu)
+{
+	if (!ctx->auto_clock_gate)
+		return;
+
+	ctx->sysreg = syscon_regmap_lookup_by_phandle(np, "samsung,sysreg");
+	if (IS_ERR(ctx->sysreg)) {
+		pr_warn("%pOF: Unable to get CMU sysreg\n", np);
+		ctx->sysreg = NULL;
+	} else {
+		/* Enable DRCG for all bus components */
+		regmap_write(ctx->sysreg, ctx->drcg_offset, DRCG_EN_MSK);
+		/* Enable memclk gate (not present on all sysreg) */
+		if (ctx->memclk_offset)
+			regmap_write_bits(ctx->sysreg, ctx->memclk_offset,
+					  MEMCLK_EN, 0x0);
+
+		samsung_clk_extended_sleep_init(NULL, ctx->sysreg,
+						cmu->sysreg_clk_regs,
+						cmu->nr_sysreg_clk_regs,
+						NULL, 0);
+	}
+}
+
 /*
  * Common function which registers plls, muxes, dividers and gates
  * for each CMU. It also add CMU register list to register cache.
@@ -375,14 +538,17 @@ struct samsung_clk_provider * __init samsung_cmu_register_one(
 	}
 
 	ctx = samsung_clk_init(NULL, reg_base, cmu->nr_clk_ids);
-	samsung_cmu_register_clocks(ctx, cmu);
+	samsung_cmu_register_clocks(ctx, cmu, np);
 
 	if (cmu->clk_regs)
-		samsung_clk_extended_sleep_init(reg_base,
+		samsung_clk_extended_sleep_init(reg_base, NULL,
 			cmu->clk_regs, cmu->nr_clk_regs,
 			cmu->suspend_regs, cmu->nr_suspend_regs);
 
 	samsung_clk_of_add_provider(np, ctx);
 
+	/* sysreg DT nodes reference a clock in this CMU */
+	samsung_en_dyn_root_clk_gating(np, ctx, cmu);
+
 	return ctx;
 }
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
index 18660c1ac6f0106b17b9efc9c6b3cd62d46f7b82..a56aa3be54d817cd24bf2bc29427e783a1a9a859 100644
--- a/drivers/clk/samsung/clk.h
+++ b/drivers/clk/samsung/clk.h
@@ -12,6 +12,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/mod_devicetable.h>
+#include <linux/regmap.h>
 #include "clk-pll.h"
 #include "clk-cpu.h"
 
@@ -19,13 +20,25 @@
  * struct samsung_clk_provider - information about clock provider
  * @reg_base: virtual address for the register base
  * @dev: clock provider device needed for runtime PM
+ * @sysreg: syscon regmap for clock-provider sysreg controller
  * @lock: maintains exclusion between callbacks for a given clock-provider
+ * @auto_clock_gate: enable auto clk mode for all clocks in clock-provider
+ * @gate_dbg_offset: gate debug reg offset. Used for all gates in auto clk mode
+ * @option_offset: option reg offset. Enables auto mode for clock-provider
+ * @drcg_offset: dynamic root clk gate enable register offset in sysreg
+ * @memclk_offset: memclk enable register offset in sysreg
  * @clk_data: holds clock related data like clk_hw* and number of clocks
  */
 struct samsung_clk_provider {
 	void __iomem *reg_base;
 	struct device *dev;
+	struct regmap *sysreg;
 	spinlock_t lock;
+	bool auto_clock_gate;
+	u32 gate_dbg_offset;
+	u32 option_offset;
+	u32 drcg_offset;
+	u32 memclk_offset;
 	/* clk_data must be the last entry due to variable length 'hws' array */
 	struct clk_hw_onecell_data clk_data;
 };
@@ -310,6 +323,7 @@ struct samsung_cpu_clock {
 struct samsung_clock_reg_cache {
 	struct list_head node;
 	void __iomem *reg_base;
+	struct regmap *sysreg;
 	struct samsung_clk_reg_dump *rdump;
 	unsigned int rd_num;
 	const struct samsung_clk_reg_dump *rsuspend;
@@ -338,7 +352,14 @@ struct samsung_clock_reg_cache {
  * @suspend_regs: list of clock registers to set before suspend
  * @nr_suspend_regs: count of clock registers in @suspend_regs
  * @clk_name: name of the parent clock needed for CMU register access
+ * @sysreg_clk_regs: list of sysreg clock registers
+ * @nr_sysreg_clk_regs: count of clock registers in @sysreg_clk_regs
  * @manual_plls: Enable manual control for PLL clocks
+ * @auto_clock_gate: enable auto clock mode for all components in CMU
+ * @gate_dbg_offset: gate debug reg offset. Used by all gates in auto clk mode
+ * @option_offset: option reg offset. Enables auto clk mode for entire CMU
+ * @drcg_offset: dynamic root clk gate enable register offset in sysreg
+ * @memclk_offset: memclk enable register offset in sysreg
  */
 struct samsung_cmu_info {
 	const struct samsung_pll_clock *pll_clks;
@@ -364,8 +385,16 @@ struct samsung_cmu_info {
 	unsigned int nr_suspend_regs;
 	const char *clk_name;
 
+	const unsigned long *sysreg_clk_regs;
+	unsigned int nr_sysreg_clk_regs;
+
 	/* ARM64 Exynos CMUs */
 	bool manual_plls;
+	bool auto_clock_gate;
+	u32 gate_dbg_offset;
+	u32 option_offset;
+	u32 drcg_offset;
+	u32 memclk_offset;
 };
 
 struct samsung_clk_provider *samsung_clk_init(struct device *dev,
@@ -408,35 +437,55 @@ void samsung_clk_register_cpu(struct samsung_clk_provider *ctx,
 		const struct samsung_cpu_clock *list, unsigned int nr_clk);
 
 void samsung_cmu_register_clocks(struct samsung_clk_provider *ctx,
-				 const struct samsung_cmu_info *cmu);
+				 const struct samsung_cmu_info *cmu,
+				 struct device_node *np);
 struct samsung_clk_provider *samsung_cmu_register_one(
 			struct device_node *,
 			const struct samsung_cmu_info *);
 
 #ifdef CONFIG_PM_SLEEP
 void samsung_clk_extended_sleep_init(void __iomem *reg_base,
+			struct regmap *sysreg,
 			const unsigned long *rdump,
 			unsigned long nr_rdump,
 			const struct samsung_clk_reg_dump *rsuspend,
 			unsigned long nr_rsuspend);
 #else
 static inline void samsung_clk_extended_sleep_init(void __iomem *reg_base,
+			struct regmap *sysreg,
 			const unsigned long *rdump,
 			unsigned long nr_rdump,
 			const struct samsung_clk_reg_dump *rsuspend,
 			unsigned long nr_rsuspend) {}
 #endif
-#define samsung_clk_sleep_init(reg_base, rdump, nr_rdump) \
-	samsung_clk_extended_sleep_init(reg_base, rdump, nr_rdump, NULL, 0)
+#define samsung_clk_sleep_init(reg_base, sysreg, rdump, nr_rdump)	   \
+	samsung_clk_extended_sleep_init(reg_base, sysreg, rdump, nr_rdump, \
+					NULL, 0)
 
 void samsung_clk_save(void __iomem *base,
+			struct regmap *regmap,
 			struct samsung_clk_reg_dump *rd,
 			unsigned int num_regs);
 void samsung_clk_restore(void __iomem *base,
+			struct regmap *regmap,
 			const struct samsung_clk_reg_dump *rd,
 			unsigned int num_regs);
 struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump(
 			const unsigned long *rdump,
 			unsigned long nr_rdump);
 
+void samsung_en_dyn_root_clk_gating(struct device_node *np,
+				struct samsung_clk_provider *ctx,
+				const struct samsung_cmu_info *cmu);
+
+struct clk_hw *samsung_register_auto_gate(struct device *dev,
+		struct device_node *np, const char *name,
+		const char *parent_name, const struct clk_hw *parent_hw,
+		const struct clk_parent_data *parent_data,
+		unsigned long flags,
+		void __iomem *reg, u8 bit_idx,
+		u8 clk_gate_flags, spinlock_t *lock);
+
+bool samsung_is_auto_capable(struct device_node *np);
+
 #endif /* __SAMSUNG_CLK_H */

-- 
2.52.0.351.gbe84eed79e-goog



From peter.griffin at linaro.org  Mon Dec 22 02:22:15 2025
From: peter.griffin at linaro.org (Peter Griffin)
Date: Mon, 22 Dec 2025 10:22:15 +0000
Subject: [PATCH v7 4/4] clk: samsung: gs101: Enable auto_clock_gate mode
 for each gs101 CMU
In-Reply-To: <20251222-automatic-clocks-v7-0-fec86fa89874@linaro.org>
References: <20251222-automatic-clocks-v7-0-fec86fa89874@linaro.org>
Message-ID: <20251222-automatic-clocks-v7-4-fec86fa89874@linaro.org>

Enable auto clock mode, and define the additional fields which are used
when this mode is enabled.

/sys/kernel/debug/clk/clk_summary now reports approximately 308 running
clocks and 298 disabled clocks. Prior to this commit 586 clocks were
running and 17 disabled.

Signed-off-by: Peter Griffin <peter.griffin at linaro.org>
---
Changes in v4:
- Remove unnecessary header of_address.h (Peter)
---
 drivers/clk/samsung/clk-gs101.c | 55 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/drivers/clk/samsung/clk-gs101.c b/drivers/clk/samsung/clk-gs101.c
index 70b26db9b95ad0b376d23f637c7683fbc8c8c600..8551289b46eb88ec61dd1914d0fe782ae6794000 100644
--- a/drivers/clk/samsung/clk-gs101.c
+++ b/drivers/clk/samsung/clk-gs101.c
@@ -26,6 +26,10 @@
 #define CLKS_NR_PERIC0	(CLK_GOUT_PERIC0_SYSREG_PERIC0_PCLK + 1)
 #define CLKS_NR_PERIC1	(CLK_GOUT_PERIC1_SYSREG_PERIC1_PCLK + 1)
 
+#define GS101_GATE_DBG_OFFSET 0x4000
+#define GS101_DRCG_EN_OFFSET  0x104
+#define GS101_MEMCLK_OFFSET   0x108
+
 /* ---- CMU_TOP ------------------------------------------------------------- */
 
 /* Register Offset definitions for CMU_TOP (0x1e080000) */
@@ -1433,6 +1437,9 @@ static const struct samsung_cmu_info top_cmu_info __initconst = {
 	.nr_clk_ids		= CLKS_NR_TOP,
 	.clk_regs		= cmu_top_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(cmu_top_clk_regs),
+	.auto_clock_gate	= true,
+	.gate_dbg_offset	= GS101_GATE_DBG_OFFSET,
+	.option_offset		= CMU_CMU_TOP_CONTROLLER_OPTION,
 };
 
 static void __init gs101_cmu_top_init(struct device_node *np)
@@ -1900,6 +1907,11 @@ static const struct samsung_gate_clock apm_gate_clks[] __initconst = {
 	     CLK_CON_GAT_GOUT_BLK_APM_UID_XIU_DP_APM_IPCLKPORT_ACLK, 21, CLK_IS_CRITICAL, 0),
 };
 
+static const unsigned long dcrg_memclk_sysreg[] __initconst = {
+	GS101_DRCG_EN_OFFSET,
+	GS101_MEMCLK_OFFSET,
+};
+
 static const struct samsung_cmu_info apm_cmu_info __initconst = {
 	.mux_clks		= apm_mux_clks,
 	.nr_mux_clks		= ARRAY_SIZE(apm_mux_clks),
@@ -1912,6 +1924,12 @@ static const struct samsung_cmu_info apm_cmu_info __initconst = {
 	.nr_clk_ids		= CLKS_NR_APM,
 	.clk_regs		= apm_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(apm_clk_regs),
+	.sysreg_clk_regs	= dcrg_memclk_sysreg,
+	.nr_sysreg_clk_regs	= ARRAY_SIZE(dcrg_memclk_sysreg),
+	.auto_clock_gate	= true,
+	.gate_dbg_offset	= GS101_GATE_DBG_OFFSET,
+	.drcg_offset		= GS101_DRCG_EN_OFFSET,
+	.memclk_offset		= GS101_MEMCLK_OFFSET,
 };
 
 /* ---- CMU_HSI0 ------------------------------------------------------------ */
@@ -2375,7 +2393,14 @@ static const struct samsung_cmu_info hsi0_cmu_info __initconst = {
 	.nr_clk_ids		= CLKS_NR_HSI0,
 	.clk_regs		= hsi0_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(hsi0_clk_regs),
+	.sysreg_clk_regs	= dcrg_memclk_sysreg,
+	.nr_sysreg_clk_regs	= ARRAY_SIZE(dcrg_memclk_sysreg),
 	.clk_name		= "bus",
+	.auto_clock_gate        = true,
+	.gate_dbg_offset        = GS101_GATE_DBG_OFFSET,
+	.option_offset		= HSI0_CMU_HSI0_CONTROLLER_OPTION,
+	.drcg_offset		= GS101_DRCG_EN_OFFSET,
+	.memclk_offset		= GS101_MEMCLK_OFFSET,
 };
 
 /* ---- CMU_HSI2 ------------------------------------------------------------ */
@@ -2863,7 +2888,14 @@ static const struct samsung_cmu_info hsi2_cmu_info __initconst = {
 	.nr_clk_ids		= CLKS_NR_HSI2,
 	.clk_regs		= cmu_hsi2_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(cmu_hsi2_clk_regs),
+	.sysreg_clk_regs	= dcrg_memclk_sysreg,
+	.nr_sysreg_clk_regs	= ARRAY_SIZE(dcrg_memclk_sysreg),
 	.clk_name		= "bus",
+	.auto_clock_gate        = true,
+	.gate_dbg_offset        = GS101_GATE_DBG_OFFSET,
+	.option_offset		= HSI2_CMU_HSI2_CONTROLLER_OPTION,
+	.drcg_offset		= GS101_DRCG_EN_OFFSET,
+	.memclk_offset		= GS101_MEMCLK_OFFSET,
 };
 
 /* ---- CMU_MISC ------------------------------------------------------------ */
@@ -3423,7 +3455,14 @@ static const struct samsung_cmu_info misc_cmu_info __initconst = {
 	.nr_clk_ids		= CLKS_NR_MISC,
 	.clk_regs		= misc_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(misc_clk_regs),
+	.sysreg_clk_regs	= dcrg_memclk_sysreg,
+	.nr_sysreg_clk_regs	= ARRAY_SIZE(dcrg_memclk_sysreg),
 	.clk_name		= "bus",
+	.auto_clock_gate	= true,
+	.gate_dbg_offset	= GS101_GATE_DBG_OFFSET,
+	.option_offset		= MISC_CMU_MISC_CONTROLLER_OPTION,
+	.drcg_offset		= GS101_DRCG_EN_OFFSET,
+	.memclk_offset		= GS101_MEMCLK_OFFSET,
 };
 
 static void __init gs101_cmu_misc_init(struct device_node *np)
@@ -4010,6 +4049,10 @@ static const struct samsung_gate_clock peric0_gate_clks[] __initconst = {
 	     21, 0, 0),
 };
 
+static const unsigned long dcrg_sysreg[] __initconst = {
+	GS101_DRCG_EN_OFFSET,
+};
+
 static const struct samsung_cmu_info peric0_cmu_info __initconst = {
 	.mux_clks		= peric0_mux_clks,
 	.nr_mux_clks		= ARRAY_SIZE(peric0_mux_clks),
@@ -4020,7 +4063,13 @@ static const struct samsung_cmu_info peric0_cmu_info __initconst = {
 	.nr_clk_ids		= CLKS_NR_PERIC0,
 	.clk_regs		= peric0_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(peric0_clk_regs),
+	.sysreg_clk_regs	= dcrg_sysreg,
+	.nr_sysreg_clk_regs	= ARRAY_SIZE(dcrg_sysreg),
 	.clk_name		= "bus",
+	.auto_clock_gate        = true,
+	.gate_dbg_offset        = GS101_GATE_DBG_OFFSET,
+	.option_offset		= PERIC0_CMU_PERIC0_CONTROLLER_OPTION,
+	.drcg_offset		= GS101_DRCG_EN_OFFSET,
 };
 
 /* ---- CMU_PERIC1 ---------------------------------------------------------- */
@@ -4368,7 +4417,13 @@ static const struct samsung_cmu_info peric1_cmu_info __initconst = {
 	.nr_clk_ids		= CLKS_NR_PERIC1,
 	.clk_regs		= peric1_clk_regs,
 	.nr_clk_regs		= ARRAY_SIZE(peric1_clk_regs),
+	.sysreg_clk_regs	= dcrg_sysreg,
+	.nr_sysreg_clk_regs	= ARRAY_SIZE(dcrg_sysreg),
 	.clk_name		= "bus",
+	.auto_clock_gate        = true,
+	.gate_dbg_offset        = GS101_GATE_DBG_OFFSET,
+	.option_offset		= PERIC1_CMU_PERIC1_CONTROLLER_OPTION,
+	.drcg_offset		= GS101_DRCG_EN_OFFSET,
 };
 
 /* ---- platform_driver ----------------------------------------------------- */

-- 
2.52.0.351.gbe84eed79e-goog



From lpieralisi at kernel.org  Mon Dec 22 02:22:50 2025
From: lpieralisi at kernel.org (Lorenzo Pieralisi)
Date: Mon, 22 Dec 2025 11:22:50 +0100
Subject: [PATCH] irqchip/gic-v5: Fix gicv5_its_map_event() ITTE read endianness
Message-ID: <20251222102250.435460-1-lpieralisi@kernel.org>

Kbuild bot (through sparse) reported that the ITTE read to carry out
a valid check in gicv5_its_map_event() lacks proper endianness handling.

Fix it.

Fixes: 57d72196dfc8 ("irqchip/gic-v5: Add GICv5 ITS support")
Reported-by: kernel test robot <lkp at intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202512131849.30ZRTBeR-lkp at intel.com/
Signed-off-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
Cc: Thomas Gleixner <tglx at linutronix.de>
Cc: Marc Zyngier <maz at kernel.org>
---
 drivers/irqchip/irq-gic-v5-its.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/irqchip/irq-gic-v5-its.c b/drivers/irqchip/irq-gic-v5-its.c
index 554485f0be1f..8e22134b9f48 100644
--- a/drivers/irqchip/irq-gic-v5-its.c
+++ b/drivers/irqchip/irq-gic-v5-its.c
@@ -849,7 +849,7 @@ static int gicv5_its_map_event(struct gicv5_its_dev *its_dev, u16 event_id, u32
 
 	itte = gicv5_its_device_get_itte_ref(its_dev, event_id);
 
-	if (FIELD_GET(GICV5_ITTL2E_VALID, *itte))
+	if (FIELD_GET(GICV5_ITTL2E_VALID, le64_to_cpu(*itte)))
 		return -EEXIST;
 
 	itt_entry = FIELD_PREP(GICV5_ITTL2E_LPI_ID, lpi) |
-- 
2.50.1



From martin.blumenstingl at googlemail.com  Mon Dec 22 02:38:19 2025
From: martin.blumenstingl at googlemail.com (Martin Blumenstingl)
Date: Mon, 22 Dec 2025 11:38:19 +0100
Subject: [PATCH v3 12/22] drm/meson: encoder_hdmi: get/put the next bridge
In-Reply-To: <DF4KIOREQYK3.2JEGF51OECQCE@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
 <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-12-b5165fab8058@bootlin.com>
 <CAFBinCCUVOYsiwwVmyGtxN=MdqYatAaj-piVO9_E_iZX9gwiMQ@mail.gmail.com> <DF4KIOREQYK3.2JEGF51OECQCE@bootlin.com>
Message-ID: <CAFBinCBX+DA71OA79SqrE20Nd=QUrU86SmYGXu0dAYG-R5nZ4Q@mail.gmail.com>

Hi Luca,

On Mon, Dec 22, 2025 at 8:31?AM Luca Ceresoli <luca.ceresoli at bootlin.com> wrote:
>
> Hello Martin,
>
> On Sun Dec 21, 2025 at 10:51 PM CET, Martin Blumenstingl wrote:
> > On Tue, Dec 16, 2025 at 7:00?PM Luca Ceresoli <luca.ceresoli at bootlin.com> wrote:
> >>
> >> This driver obtains a bridge pointer from of_drm_find_bridge() in the probe
> >> function and stores it until driver removal. of_drm_find_bridge() is
> >> deprecated. Move to of_drm_find_and_get_bridge() for the bridge to be
> >> refcounted and use bridge->next_bridge to put the reference on
> >> deallocation.
> >>
> >> Signed-off-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
> > Reviewed-by: Martin Blumenstingl <martin.blumenstingl at googlemail.com>
> > And additionally I runtime tested this on meson-gxl-s905x-libretech-cc
> > where I still have HDMI output, so:
> > Tested-by: Martin Blumenstingl <martin.blumenstingl at googlemail.com>
>
> Thank you for the quick testing!
Thank you for doing the hard work ;-)

> I think I can append '# meson-gxl-s905x-libretech-cc' to your 'Tested-by:'
> line when I'll apply the patch, to make it more informative.
Sure, please go ahead with that!


Best regards,
Martin


From maz at kernel.org  Mon Dec 22 02:42:51 2025
From: maz at kernel.org (Marc Zyngier)
Date: Mon, 22 Dec 2025 10:42:51 +0000
Subject: [PATCH] irqchip/gic-v5: Fix gicv5_its_map_event() ITTE read endianness
In-Reply-To: <20251222102250.435460-1-lpieralisi@kernel.org>
References: <20251222102250.435460-1-lpieralisi@kernel.org>
Message-ID: <86o6nqn6fo.wl-maz@kernel.org>

On Mon, 22 Dec 2025 10:22:50 +0000,
Lorenzo Pieralisi <lpieralisi at kernel.org> wrote:
> 
> Kbuild bot (through sparse) reported that the ITTE read to carry out
> a valid check in gicv5_its_map_event() lacks proper endianness handling.
> 
> Fix it.
> 
> Fixes: 57d72196dfc8 ("irqchip/gic-v5: Add GICv5 ITS support")
> Reported-by: kernel test robot <lkp at intel.com>
> Closes: https://lore.kernel.org/oe-kbuild-all/202512131849.30ZRTBeR-lkp at intel.com/
> Signed-off-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
> Cc: Thomas Gleixner <tglx at linutronix.de>
> Cc: Marc Zyngier <maz at kernel.org>
> ---
>  drivers/irqchip/irq-gic-v5-its.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/irqchip/irq-gic-v5-its.c b/drivers/irqchip/irq-gic-v5-its.c
> index 554485f0be1f..8e22134b9f48 100644
> --- a/drivers/irqchip/irq-gic-v5-its.c
> +++ b/drivers/irqchip/irq-gic-v5-its.c
> @@ -849,7 +849,7 @@ static int gicv5_its_map_event(struct gicv5_its_dev *its_dev, u16 event_id, u32
>  
>  	itte = gicv5_its_device_get_itte_ref(its_dev, event_id);
>  
> -	if (FIELD_GET(GICV5_ITTL2E_VALID, *itte))
> +	if (FIELD_GET(GICV5_ITTL2E_VALID, le64_to_cpu(*itte)))
>  		return -EEXIST;
>  
>  	itt_entry = FIELD_PREP(GICV5_ITTL2E_LPI_ID, lpi) |

Acked-by: Marc Zyngier <maz at kernel.org>

	M.

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


From arnd at arndb.de  Mon Dec 22 02:42:49 2025
From: arnd at arndb.de (Arnd Bergmann)
Date: Mon, 22 Dec 2025 11:42:49 +0100
Subject: [PATCH] arm64: perf: fix syscalltbl path base
In-Reply-To: <a5448524-a147-4edb-9359-bcee3d780eb6@linaro.org>
References: <b2651f20-6f3a-49f5-9cd8-3fb028b2cab5@app.fastmail.com>
 <fcefc3c0-541d-40cc-84e3-9c2460308bdb@linaro.org>
 <23c07ac4-ff13-47a5-824a-e7af1d1847a3@app.fastmail.com>
 <bda366b4-fa53-4feb-a7ce-ee47cfc404b5@linaro.org>
 <20251215112818.GB681384@e132581.arm.com>
 <c8161700-ad9d-43d3-8c45-cfc110ebcd49@app.fastmail.com>
 <a5448524-a147-4edb-9359-bcee3d780eb6@linaro.org>
Message-ID: <ce4e1210-94c2-4664-885b-e39106905e21@app.fastmail.com>

On Mon, Dec 22, 2025, at 11:05, James Clark wrote:
> On 21/12/2025 9:48 pm, Joel May wrote:
>> On Mon, Dec 15, 2025, at 03:28, Leo Yan wrote:
>> 
>> This is my first time contributing to the Linux kernel, so please bare with
>> my ignorance.  I don't know whether it's acceptable to consider patches
>> that conceptually improve something without an actual problem they're
>> solving.
>> 
>
> No worries, thanks for sending the fix. Yes I think it could be ok to 
> apply your patch anyway. I just wanted to make sure we were all on the 
> same page with both fixes fixing the same thing.

I still don't think that Leo's series is correct.

> You might want to drop the fixes tag though to avoid confusion if Leo's 
> one gets accepted, because then technically it doesn't fix anything any 
> more. Keeping Leo's fixes: tag is a bit better because it fixes 
> additional things and targets an older commit.

Before that gets applied, someone should explain why arm64 needs
any special treatment at all. A lot of work has gone into making
the syscall table handling consistent across architectures, so
whether we ship a copy of the generated header for perf, we
generate a new copy or we rely on 'make headers_install', should
should really be done the same way across every architecture.

     Arnd


From kevin.tung.openbmc at gmail.com  Mon Dec 22 03:25:29 2025
From: kevin.tung.openbmc at gmail.com (Kevin Tung)
Date: Mon, 22 Dec 2025 19:25:29 +0800
Subject: [PATCH] ARM: dts: aspeed: yosemite5: add x4 E1.S expansion board
 I2C mux
Message-ID: <20251222-yv5_add_dvt_e1s_ioexp-v1-1-25ad202d2681@gmail.com>

The new hardware design adds two additional E1.S devices behind an
I2C mux at address 0x73 on bus 10. Add support for this mux in the
DTS device tree.

Signed-off-by: Kevin Tung <kevin.tung.openbmc at gmail.com>
---
Summary:
Revise linux device tree entry related to Meta (Facebook) Yosemite5.

Changes in v1:
- Add x4 E1.S expansion board I2C mux
---
 .../dts/aspeed/aspeed-bmc-facebook-yosemite5.dts   | 23 ++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts
index 2486981f3d6bd36f3fe780b21e834b85242f8aa9..87524892322c1388c146b33ac454018a31dad168 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts
+++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite5.dts
@@ -31,6 +31,8 @@ aliases {
 		i2c33 = &i2c30mux0ch1;
 		i2c34 = &i2c30mux0ch2;
 		i2c35 = &i2c30mux0ch3;
+		i2c36 = &i2c10mux0ch0;
+		i2c37 = &i2c10mux0ch1;
 		serial0 = &uart1;
 		serial2 = &uart3;
 		serial3 = &uart4;
@@ -702,6 +704,27 @@ eeprom at 54 {
 		compatible = "atmel,24c128";
 		reg = <0x54>;
 	};
+
+	/* I2C MUX on E1S x4 board */
+	i2c-mux at 73 {
+		compatible = "nxp,pca9543";
+		reg = <0x73>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		i2c10mux0ch0: i2c at 0 {
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c10mux0ch1: i2c at 1 {
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
 };
 
 &i2c11 {

---
base-commit: 9448598b22c50c8a5bb77a9103e2d49f134c9578
change-id: 20251222-yv5_add_dvt_e1s_ioexp-14930e048043

Best regards,
-- 
Kevin Tung <kevin.tung.openbmc at gmail.com>



From steven.price at arm.com  Mon Dec 22 03:43:53 2025
From: steven.price at arm.com (Steven Price)
Date: Mon, 22 Dec 2025 11:43:53 +0000
Subject: [PATCH v2 3/4] drm/panthor: Implement reading shader_present from
 nvmem
In-Reply-To: <20251220-mt8196-shader-present-v2-3-45b1ff1dfab0@collabora.com>
References: <20251220-mt8196-shader-present-v2-0-45b1ff1dfab0@collabora.com>
 <20251220-mt8196-shader-present-v2-3-45b1ff1dfab0@collabora.com>
Message-ID: <d4d35a65-6ff8-47ea-9764-f03f7bead334@arm.com>

On 20/12/2025 18:49, Nicolas Frattaroli wrote:
> On some platforms, notably MediaTek MT8196, the shader_present bitmask
> in the Mali GPU register for it has cores enabled that may be faulty.
> The true shader_present bitmask is found in an efuse instead.
> 
> Implement reading shader_present from an nvmem cell if one is present,
> falling back to the Mali register if it's absent. The error codes are
> trickled up through to the probe function so that probe deferral works.
> 
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>

Reviewed-by: Steven Price <steven.price at arm.com>

> ---
>  drivers/gpu/drm/panthor/panthor_hw.c | 36 ++++++++++++++++++++++++++++++------
>  1 file changed, 30 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c
> index 87ebb7ae42c4..80c521784cd3 100644
> --- a/drivers/gpu/drm/panthor/panthor_hw.c
> +++ b/drivers/gpu/drm/panthor/panthor_hw.c
> @@ -1,6 +1,7 @@
>  // SPDX-License-Identifier: GPL-2.0 or MIT
>  /* Copyright 2025 ARM Limited. All rights reserved. */
>  
> +#include <linux/nvmem-consumer.h>
>  #include <drm/drm_print.h>
>  
>  #include "panthor_device.h"
> @@ -109,7 +110,25 @@ static char *get_gpu_model_name(struct panthor_device *ptdev)
>  	return "(Unknown Mali GPU)";
>  }
>  
> -static void panthor_gpu_info_init(struct panthor_device *ptdev)
> +static int overload_shader_present(struct panthor_device *ptdev)
> +{
> +	u64 contents;
> +	int ret;
> +
> +	ret = nvmem_cell_read_variable_le_u64(ptdev->base.dev, "shader-present",
> +					      &contents);
> +	if (!ret)
> +		ptdev->gpu_info.shader_present = contents;
> +	else if (ret == -ENOENT)
> +		return 0;
> +	else
> +		return dev_err_probe(ptdev->base.dev, ret,
> +				     "Failed to read shader-present nvmem cell\n");
> +
> +	return 0;
> +}
> +
> +static int panthor_gpu_info_init(struct panthor_device *ptdev)
>  {
>  	unsigned int i;
>  
> @@ -143,13 +162,18 @@ static void panthor_gpu_info_init(struct panthor_device *ptdev)
>  		ptdev->gpu_info.tiler_present = gpu_read64(ptdev, GPU_TILER_PRESENT);
>  		ptdev->gpu_info.l2_present = gpu_read64(ptdev, GPU_L2_PRESENT);
>  	}
> +
> +	return overload_shader_present(ptdev);
>  }
>  
> -static void panthor_hw_info_init(struct panthor_device *ptdev)
> +static int panthor_hw_info_init(struct panthor_device *ptdev)
>  {
>  	u32 major, minor, status;
> +	int ret;
>  
> -	panthor_gpu_info_init(ptdev);
> +	ret = panthor_gpu_info_init(ptdev);
> +	if (ret)
> +		return ret;
>  
>  	major = GPU_VER_MAJOR(ptdev->gpu_info.gpu_id);
>  	minor = GPU_VER_MINOR(ptdev->gpu_info.gpu_id);
> @@ -172,6 +196,8 @@ static void panthor_hw_info_init(struct panthor_device *ptdev)
>  		 "shader_present=0x%0llx l2_present=0x%0llx tiler_present=0x%0llx",
>  		 ptdev->gpu_info.shader_present, ptdev->gpu_info.l2_present,
>  		 ptdev->gpu_info.tiler_present);
> +
> +	return 0;
>  }
>  
>  static int panthor_hw_bind_device(struct panthor_device *ptdev)
> @@ -218,7 +244,5 @@ int panthor_hw_init(struct panthor_device *ptdev)
>  	if (ret)
>  		return ret;
>  
> -	panthor_hw_info_init(ptdev);
> -
> -	return 0;
> +	return panthor_hw_info_init(ptdev);
>  }
> 



From urezki at gmail.com  Mon Dec 22 03:47:51 2025
From: urezki at gmail.com (Uladzislau Rezki)
Date: Mon, 22 Dec 2025 12:47:51 +0100
Subject: [RESEND RFC PATCH 1/2] mm/vmalloc: Do not align size to huge size
In-Reply-To: <20251212042701.71993-2-dev.jain@arm.com>
References: <20251212042701.71993-1-dev.jain@arm.com>
 <20251212042701.71993-2-dev.jain@arm.com>
Message-ID: <aUkv51yk8lgzW9jv@milan>

On Fri, Dec 12, 2025 at 09:57:00AM +0530, Dev Jain wrote:
> vmalloc() consists of the following:
> 
> (1) find empty space in the vmalloc space -> (2) get physical pages from
> the buddy system -> (3) map the pages into the pagetable.
> 
> It turns out that the cost of (1) and (3) is pretty insignificant. Hence,
> the cost of vmalloc becomes highly sensitive to physical memory allocation
> time.
> 
> Currently, if we decide to use huge mappings, apart from aligning the start
> of the target vm_struct region to the huge-alignment, we also align the
> size. This does not seem to produce any benefit (apart from simplification
> of the code), and there is a clear disadvantage - as mentioned above, the
> main cost of vmalloc comes from its interaction with the buddy system, and
> thus requesting more memory than was requested by the caller is suboptimal
> and unnecessary.
> 
> This change is also motivated due to the next patch ("arm64/mm: Enable
> vmalloc-huge by default"). Suppose that some user of vmalloc maps 17 pages,
> uses that mapping for an extremely short time, and vfree's it. That patch,
> without this patch, on arm64 will ultimately map 16 * 2 = 32 pages in a
> contiguous way. Since the mapping is used for a very short time, it is
> likely that the extra cost of mapping 15 pages defeats any benefit from
> reduced TLB pressure, and regresses that code path. 
> 
> Signed-off-by: Dev Jain <dev.jain at arm.com>
> ---
>  mm/vmalloc.c | 38 ++++++++++++++++++++++++++++++--------
>  1 file changed, 30 insertions(+), 8 deletions(-)
> 
> diff --git a/mm/vmalloc.c b/mm/vmalloc.c
> index ecbac900c35f..389225a6f7ef 100644
> --- a/mm/vmalloc.c
> +++ b/mm/vmalloc.c
> @@ -654,7 +654,7 @@ static int vmap_small_pages_range_noflush(unsigned long addr, unsigned long end,
>  int __vmap_pages_range_noflush(unsigned long addr, unsigned long end,
>  		pgprot_t prot, struct page **pages, unsigned int page_shift)
>  {
> -	unsigned int i, nr = (end - addr) >> PAGE_SHIFT;
> +	unsigned int i, step, nr = (end - addr) >> PAGE_SHIFT;
>  
>  	WARN_ON(page_shift < PAGE_SHIFT);
>  
> @@ -662,7 +662,8 @@ int __vmap_pages_range_noflush(unsigned long addr, unsigned long end,
>  			page_shift == PAGE_SHIFT)
>  		return vmap_small_pages_range_noflush(addr, end, prot, pages);
>  
> -	for (i = 0; i < nr; i += 1U << (page_shift - PAGE_SHIFT)) {
> +	step = 1U << (page_shift - PAGE_SHIFT);
> +	for (i = 0; i < ALIGN_DOWN(nr, step); i += step) {
>  		int err;
>  
>  		err = vmap_range_noflush(addr, addr + (1UL << page_shift),
> @@ -673,8 +674,9 @@ int __vmap_pages_range_noflush(unsigned long addr, unsigned long end,
>  
>  		addr += 1UL << page_shift;
>  	}
> -
> -	return 0;
> +	if (IS_ALIGNED(nr, step))
> +		return 0;
> +	return vmap_small_pages_range_noflush(addr, end, prot, pages + i);
>  }
>  
Can we improve the readability?

<snip>
index 25a4178188ee..14ca019b57af 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -655,6 +655,8 @@ int __vmap_pages_range_noflush(unsigned long addr, unsigned long end,
                pgprot_t prot, struct page **pages, unsigned int page_shift)
 {
        unsigned int i, step, nr = (end - addr) >> PAGE_SHIFT;
+       unsigned int nr_aligned;
+       unsigned long chunk_size;

        WARN_ON(page_shift < PAGE_SHIFT);

@@ -662,20 +664,24 @@ int __vmap_pages_range_noflush(unsigned long addr, unsigned long end,
                        page_shift == PAGE_SHIFT)
                return vmap_small_pages_range_noflush(addr, end, prot, pages);

-       step = 1U << (page_shift - PAGE_SHIFT);
-       for (i = 0; i < ALIGN_DOWN(nr, step); i += step) {
-               int err;
+       step = 1U << (page_shift - PAGE_SHIFT); /* small pages per huge chunk. */
+       nr_aligned = ALIGN_DOWN(nr, step);
+       chunk_size = 1UL << page_shift;

-               err = vmap_range_noflush(addr, addr + (1UL << page_shift),
+       for (i = 0; i < nr_aligned; i += step) {
+               int err = vmap_range_noflush(addr, addr + chunk_size,
                                        page_to_phys(pages[i]), prot,
                                        page_shift);
                if (err)
                        return err;

-               addr += 1UL << page_shift;
+               addr += chunk_size;
        }
-       if (IS_ALIGNED(nr, step))
+
+       if (i == nr)
                return 0;
+
+       /* Map the tail using small pages. */
        return vmap_small_pages_range_noflush(addr, end, prot, pages + i);
 }
<snip>


>  int vmap_pages_range_noflush(unsigned long addr, unsigned long end,
> @@ -3197,7 +3199,7 @@ struct vm_struct *__get_vm_area_node(unsigned long size,
>  	unsigned long requested_size = size;
>  
>  	BUG_ON(in_interrupt());
> -	size = ALIGN(size, 1ul << shift);
> +	size = PAGE_ALIGN(size);
>  	if (unlikely(!size))
>  		return NULL;
>  
> @@ -3353,7 +3355,7 @@ static void vm_reset_perms(struct vm_struct *area)
>  	 * Find the start and end range of the direct mappings to make sure that
>  	 * the vm_unmap_aliases() flush includes the direct map.
>  	 */
> -	for (i = 0; i < area->nr_pages; i += 1U << page_order) {
> +	for (i = 0; i < ALIGN_DOWN(area->nr_pages, 1U << page_order); i += (1U << page_order)) {
>
nr_blocks?

>  		unsigned long addr = (unsigned long)page_address(area->pages[i]);
>  
>  		if (addr) {
> @@ -3365,6 +3367,18 @@ static void vm_reset_perms(struct vm_struct *area)
>  			flush_dmap = 1;
>  		}
>  	}
> +	for (; i < area->nr_pages; ++i) {
> +		unsigned long addr = (unsigned long)page_address(area->pages[i]);
> +
> +		if (addr) {
> +			unsigned long page_size;
> +
> +			page_size = PAGE_SIZE;
> +			start = min(addr, start);
> +			end = max(addr + page_size, end);
> +			flush_dmap = 1;
> +		}
> +	}
>  
>  	/*
>  	 * Set direct map to something invalid so that it won't be cached if
> @@ -3673,6 +3687,7 @@ vm_area_alloc_pages(gfp_t gfp, int nid,
>  	 * more permissive.
>  	 */
>  	if (!order) {
> +single_page:
>  		while (nr_allocated < nr_pages) {
>  			unsigned int nr, nr_pages_request;
>  
> @@ -3704,13 +3719,18 @@ vm_area_alloc_pages(gfp_t gfp, int nid,
>  			 * If zero or pages were obtained partly,
>  			 * fallback to a single page allocator.
>  			 */
> -			if (nr != nr_pages_request)
> +			if (nr != nr_pages_request) {
> +				order = 0;
>  				break;
> +			}
>  		}
>  	}
>  
>  	/* High-order pages or fallback path if "bulk" fails. */
>  	while (nr_allocated < nr_pages) {
> +		if (nr_pages - nr_allocated < (1UL << order)) {
> +			goto single_page;
> +		}
>  		if (!(gfp & __GFP_NOFAIL) && fatal_signal_pending(current))
>  			break;
>
Yes, it requires more attention. That "goto single_page" should be
eliminated, IMO. We should not jump between blocks, logically the
single_page belongs to "order-0 alloc path".

Probably it requires more refactoring to simplify it.

>  
> @@ -5179,7 +5199,9 @@ static void show_numa_info(struct seq_file *m, struct vm_struct *v,
>  
>  	memset(counters, 0, nr_node_ids * sizeof(unsigned int));
>  
> -	for (nr = 0; nr < v->nr_pages; nr += step)
> +	for (nr = 0; nr < ALIGN_DOWN(v->nr_pages, step); nr += step)
> +		counters[page_to_nid(v->pages[nr])] += step;
> +	for (; nr < v->nr_pages; ++nr)
>  		counters[page_to_nid(v->pages[nr])] += step;
>
Can we fit it into one loop? Last tail loop continuous adding step?

--
Uladzislau Rezki


From jonathan.cameron at huawei.com  Mon Dec 22 03:48:04 2025
From: jonathan.cameron at huawei.com (Jonathan Cameron)
Date: Mon, 22 Dec 2025 11:48:04 +0000
Subject: [RFC PATCH 07/38] arm_mpam: resctrl: Add boilerplate cpuhp and
 domain allocation
In-Reply-To: <4495db3f-cfb8-4571-b83a-10a24f7b73a9@arm.com>
References: <20251205215901.17772-1-james.morse@arm.com>
	<20251205215901.17772-8-james.morse@arm.com>
	<20251218113014.00002691@huawei.com>
	<4495db3f-cfb8-4571-b83a-10a24f7b73a9@arm.com>
Message-ID: <20251222114804.00005231@huawei.com>


> >> +static struct mpam_resctrl_dom *
> >> +mpam_resctrl_get_domain_from_cpu(int cpu, struct mpam_resctrl_res *res)
> >> +{
> >> +	struct mpam_resctrl_dom *dom;
> >> +	struct rdt_ctrl_domain *ctrl_d;
> >> +
> >> +	lockdep_assert_cpus_held();
> >> +
> >> +	list_for_each_entry_rcu(ctrl_d, &res->resctrl_res.ctrl_domains,
> >> +				hdr.list) {
> >> +		dom = container_of(ctrl_d, struct mpam_resctrl_dom,
> >> +				   resctrl_ctrl_dom);  
> > 
> > I'm lazy so haven't checked for more code here in later patches, but
> > if not, why not iterate the list to access the domain directly rather
> > than jumping through the rdt_ctrl_domain?
> > 
> > Something along lines of:
> > 	
> > 	list_for_each_entry_rcu(dom, &res->resctrl_res.ctrl_domains,
> > 				resctrl_ctrl_dom.hdr.list) {
> > 	}
> >  
> 
> Unless I've misunderstood I don't think this works because it's not what
> the fs/resctrl code expects.

I think I explained this one badly.

This should be functionally identical to the above so no visible side
effects outside of this code.  All this change is meant to do is wrap the
container_of() in the list iterator. When using the _entry_ variants
it is wrapping container_of() anyway so just going one level further
up the hierarchy of nested structures.

struct a {
	struct b {
		struct list_head l;
	}
}

It's actually a list of struct a as all elements on this list are
struct b instances within struct a, but you are treating it as a list
of struct b and then using a container_of() to get to struct a on
each one.

The change is treat it as a list of struct a with the list_head happening
to be wrapped in struct b.  Results in slightly simpler code and makes
the point these are always struct a instances.

Jonathan



> 
> 
> >> +
> >> +		if (cpumask_test_cpu(cpu, &dom->ctrl_comp->affinity))
> >> +			return dom;
> >> +	}
> >> +
> >> +	return NULL;
> >> +}
> >> +




From ruanjinjie at huawei.com  Mon Dec 22 03:47:22 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 22 Dec 2025 19:47:22 +0800
Subject: [PATCH v10 01/16] arm64: Remove unused _TIF_WORK_MASK
In-Reply-To: <20251222114737.1334364-1-ruanjinjie@huawei.com>
References: <20251222114737.1334364-1-ruanjinjie@huawei.com>
Message-ID: <20251222114737.1334364-2-ruanjinjie@huawei.com>

Since commit b3cf07851b6c ("arm64: entry: Switch to generic IRQ
entry"), _TIF_WORK_MASK is never used, so remove it.

Reviewed-by: Anshuman Khandual <anshuman.khandual at arm.com>
Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/include/asm/thread_info.h | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index a803b887b0b4..24fcd6adaa33 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -106,12 +106,6 @@ void arch_setup_new_exec(void);
 #define _TIF_NOTIFY_SIGNAL	(1 << TIF_NOTIFY_SIGNAL)
 #define _TIF_TSC_SIGSEGV	(1 << TIF_TSC_SIGSEGV)
 
-#define _TIF_WORK_MASK		(_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY | \
-				 _TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE | \
-				 _TIF_UPROBE | _TIF_MTE_ASYNC_FAULT | \
-				 _TIF_NOTIFY_SIGNAL | _TIF_SIGPENDING | \
-				 _TIF_PATCH_PENDING)
-
 #define _TIF_SYSCALL_WORK	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
 				 _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \
 				 _TIF_SYSCALL_EMU)
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Dec 22 03:47:25 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 22 Dec 2025 19:47:25 +0800
Subject: [PATCH v10 04/16] arm64/ptrace: Refactor syscall_trace_enter/exit()
In-Reply-To: <20251222114737.1334364-1-ruanjinjie@huawei.com>
References: <20251222114737.1334364-1-ruanjinjie@huawei.com>
Message-ID: <20251222114737.1334364-5-ruanjinjie@huawei.com>

The generic syscall entry code has the following form, which use
the input syscall work flag and syscall number:

| syscall_trace_enter(struct pt_regs *regs, long syscall,
|		      unsigned long work)
|
| syscall_exit_work(struct pt_regs *regs, unsigned long work)

In preparation for moving arm64 over to the generic entry code,
refactor syscall_trace_enter/exit() to also pass thread flags, and
get syscall number by syscall_get_nr() helper.

No functional changes.

Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/include/asm/syscall.h |  4 ++--
 arch/arm64/kernel/ptrace.c       | 25 ++++++++++++++++---------
 arch/arm64/kernel/syscall.c      |  5 +++--
 3 files changed, 21 insertions(+), 13 deletions(-)

diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
index 5e4c7fc44f73..cef1d9ce6e1b 100644
--- a/arch/arm64/include/asm/syscall.h
+++ b/arch/arm64/include/asm/syscall.h
@@ -120,7 +120,7 @@ static inline int syscall_get_arch(struct task_struct *task)
 	return AUDIT_ARCH_AARCH64;
 }
 
-int syscall_trace_enter(struct pt_regs *regs);
-void syscall_trace_exit(struct pt_regs *regs);
+int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags);
+void syscall_trace_exit(struct pt_regs *regs, unsigned long flags);
 
 #endif	/* __ASM_SYSCALL_H */
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index f333791ffba6..79762ff33945 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -2407,9 +2407,8 @@ static void report_syscall_exit(struct pt_regs *regs)
 	}
 }
 
-int syscall_trace_enter(struct pt_regs *regs)
+int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags)
 {
-	unsigned long flags = read_thread_flags();
 	int ret;
 
 	if (flags & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE)) {
@@ -2422,19 +2421,27 @@ int syscall_trace_enter(struct pt_regs *regs)
 	if (secure_computing() == -1)
 		return NO_SYSCALL;
 
-	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
-		trace_sys_enter(regs, regs->syscallno);
+	/* Either of the above might have changed the syscall number */
+	syscall = syscall_get_nr(current, regs);
 
-	audit_syscall_entry(regs->syscallno, regs->orig_x0, regs->regs[1],
+	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) {
+		trace_sys_enter(regs, syscall);
+
+		/*
+		 * Probes or BPF hooks in the tracepoint may have changed the
+		 * system call number as well.
+		 */
+		 syscall = syscall_get_nr(current, regs);
+	}
+
+	audit_syscall_entry(syscall, regs->orig_x0, regs->regs[1],
 			    regs->regs[2], regs->regs[3]);
 
-	return regs->syscallno;
+	return syscall;
 }
 
-void syscall_trace_exit(struct pt_regs *regs)
+void syscall_trace_exit(struct pt_regs *regs, unsigned long flags)
 {
-	unsigned long flags = read_thread_flags();
-
 	audit_syscall_exit(regs);
 
 	if (flags & _TIF_SYSCALL_TRACEPOINT)
diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index c062badd1a56..5a103873de12 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -124,7 +124,7 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 		 */
 		if (scno == NO_SYSCALL)
 			syscall_set_return_value(current, regs, -ENOSYS, 0);
-		scno = syscall_trace_enter(regs);
+		scno = syscall_trace_enter(regs, scno, flags);
 		if (scno == NO_SYSCALL)
 			goto trace_exit;
 	}
@@ -143,7 +143,8 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 	}
 
 trace_exit:
-	syscall_trace_exit(regs);
+	flags = read_thread_flags();
+	syscall_trace_exit(regs, flags);
 }
 
 void do_el0_svc(struct pt_regs *regs)
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Dec 22 03:47:26 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 22 Dec 2025 19:47:26 +0800
Subject: [PATCH v10 05/16] arm64: ptrace: Move rseq_syscall() before audit_syscall_exit()
In-Reply-To: <20251222114737.1334364-1-ruanjinjie@huawei.com>
References: <20251222114737.1334364-1-ruanjinjie@huawei.com>
Message-ID: <20251222114737.1334364-6-ruanjinjie@huawei.com>

commit a9f3a74a29af ("entry: Provide generic syscall exit function")
introduce generic syscall exit function and call rseq_syscall()
before audit_syscall_exit() and arch_syscall_exit_tracehook().

And commit b74406f37737 ("arm: Add syscall detection for restartable
sequences") add rseq support for arm32, which also call rseq_syscall()
before audit_syscall_exit() and tracehook_report_syscall().

However, commit 409d5db49867c ("arm64: rseq: Implement backend rseq
calls and select HAVE_RSEQ") implement arm64 rseq and call
rseq_syscall() after audit_syscall_exit() and tracehook_report_syscall().

So compared to the generic entry and arm32 code, arm64 terminates
the process a bit later if the syscall is issued within
a restartable sequence.

But as commit b74406f37737 ("arm: Add syscall detection for restartable
sequences") said, syscalls are not allowed inside restartable sequences,
so should call rseq_syscall() at the very beginning of system call
exiting path for CONFIG_DEBUG_RSEQ=y kernel. This could help us to detect
whether there is a syscall issued inside restartable sequences.

It makes sense to raise SIGSEGV via rseq_syscall() before auditing
and ptrace syscall exit, because this guarantees that the process is
already in an error state with SIGSEGV pending when those later steps
run. Although it makes no practical difference to signal delivery (signals
are processed at the very end in arm64_exit_to_user_mode()), the ordering
is more logical: detect and flag the error first, then proceed with
the remaining work.

To make it more reasonable and in preparation for moving arm64 over to
the generic entry code, move rseq_syscall() ahead before
audit_syscall_exit().

Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/kernel/ptrace.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 79762ff33945..983d8d1104df 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -2442,6 +2442,8 @@ int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags)
 
 void syscall_trace_exit(struct pt_regs *regs, unsigned long flags)
 {
+	rseq_syscall(regs);
+
 	audit_syscall_exit(regs);
 
 	if (flags & _TIF_SYSCALL_TRACEPOINT)
@@ -2449,8 +2451,6 @@ void syscall_trace_exit(struct pt_regs *regs, unsigned long flags)
 
 	if (flags & (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP))
 		report_syscall_exit(regs);
-
-	rseq_syscall(regs);
 }
 
 /*
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Dec 22 03:47:21 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 22 Dec 2025 19:47:21 +0800
Subject: [PATCH v10 00/16] arm64: entry: Convert to Generic Entry
Message-ID: <20251222114737.1334364-1-ruanjinjie@huawei.com>

Currently, x86, Riscv, Loongarch use the Generic Entry which makes
maintainers' work easier and codes more elegant. arm64 has already
successfully switched to the Generic IRQ Entry in commit
b3cf07851b6c ("arm64: entry: Switch to generic IRQ entry"), it is
time to completely convert arm64 to Generic Entry.

The goal is to bring arm64 in line with other architectures that already
use the generic entry infrastructure, reducing duplicated code and
making it easier to share future changes in entry/exit paths, such as
"Syscall User Dispatch".

This patch set is rebased on v6.19-rc1. And the performance was measured
on Kunpeng 920 using "perf bench basic syscall" with "arm64.nopauth
selinux=0 audit=1".

After switch to Generic Entry, the performance are below:

| Metric     | W/O Generic Framework | With Generic Framework | Change |
| ---------- | --------------------- | ---------------------- | ------ |
| Total time | 2.487 [sec]           |  2.393[sec]            | ?3.8% |
| usecs/op   | 0.248780              |  0.239361              | ?3.8% |
| ops/sec    | 4,019,620             |  4,177,789             | ?3.9% |

Compared to earlier with arch specific handling, the performance improved
by approximately 3.9%.

On the basis of optimizing syscall_get_arguments()[1], el0_svc_common()
and syscall_exit_work(), the performance are below:

| Metric     | W/O Generic Entry | With Generic Entry opt| Change |
| ---------- | ----------------- | ------------------    | ------ |
| Total time | 2.487 [sec]       | 2.264 [sec]           | ?9.0% |
| usecs/op   | 0.248780          | 0.226481              | ?9.0% |
| ops/sec    | 4,019,620         | 4,415,383             | ?9.8% |

Therefore, after the optimization, ARM64 System Call performance improved
by approximately 9%.

It was tested ok with following test cases on kunpeng920 and QEMU
virt platform:
 - Perf tests.
 - Different `dynamic preempt` mode switch.
 - Pseudo NMI tests.
 - Stress-ng CPU stress test.
 - Hackbench stress test.
 - MTE test case in Documentation/arch/arm64/memory-tagging-extension.rst
   and all test cases in tools/testing/selftests/arm64/mte/*.
 - "sud" selftest testcase.
 - get_set_sud, get_syscall_info, set_syscall_info, peeksiginfo
   in tools/testing/selftests/ptrace.
 - breakpoint_test_arm64 in selftests/breakpoints.
 - syscall-abi and ptrace in tools/testing/selftests/arm64/abi
 - fp-ptrace, sve-ptrace, za-ptrace in selftests/arm64/fp.
 - vdso_test_getrandom in tools/testing/selftests/vDSO
 - Strace tests.

The test QEMU configuration is as follows:

	qemu-system-aarch64 \
		-M virt,gic-version=3,virtualization=on,mte=on \
		-cpu max,pauth-impdef=on \
		-kernel Image \
		-smp 8,sockets=1,cores=4,threads=2 \
		-m 512m \
		-nographic \
		-no-reboot \
		-device virtio-rng-pci \
		-append "root=/dev/vda rw console=ttyAMA0 kgdboc=ttyAMA0,115200 \
			earlycon preempt=voluntary irqchip.gicv3_pseudo_nmi=1" \
		-drive if=none,file=images/rootfs.ext4,format=raw,id=hd0 \
		-device virtio-blk-device,drive=hd0 \

[1]: https://kernel.googlesource.com/pub/scm/linux/kernel/git/akpm/mm/+/89bf683c9507c280e20c3e17b4ea15e19696ed63%5E%21/#F0

Changes in v10:
- Rebased on v6.19-rc1, rename syscall_exit_to_user_mode_prepare() to
  syscall_exit_to_user_mode_work_prepare() to avoid conflict.
- Also inline syscall_trace_enter().
- Support aarch64 for sud_benchmark.
- Update and correct the commit message.
- Add Reviewed-by.
- Link to v9: https://lore.kernel.org/all/20251204082123.2792067-1-ruanjinjie at huawei.com/

Changes in v9:
- Move "Return early for ptrace_report_syscall_entry() error" patch ahead
  to make it not introduce a regression.
- Not check _TIF_SECCOMP/SYSCALL_EMU for syscall_exit_work() in
  a separate patch.
- Do not report_syscall_exit() for PTRACE_SYSEMU_SINGLESTEP in a separate
  patch.
- Add two performance patch to improve the arm64 performance.
- Add Reviewed-by.
- Link to v8: https://lore.kernel.org/all/20251126071446.3234218-1-ruanjinjie at huawei.com/

Changes in v8:
- Rename "report_syscall_enter()" to "report_syscall_entry()".
- Add ptrace_save_reg() to avoid duplication.
- Remove unused _TIF_WORK_MASK in a standalone patch.
- Align syscall_trace_enter() return value with the generic version.
- Use "scno" instead of regs->syscallno in el0_svc_common().
- Move rseq_syscall() ahead in a standalone patch to clarify it clearly.
- Rename "syscall_trace_exit()" to "syscall_exit_work()".
- Keep the goto in el0_svc_common().
- No argument was passed to __secure_computing() and check -1 not -1L.
- Remove "Add has_syscall_work() helper" patch.
- Move "Add syscall_exit_to_user_mode_prepare() helper" patch later.
- Add miss header for asm/entry-common.h.
- Update the implementation of arch_syscall_is_vdso_sigreturn().
- Add "ARCH_SYSCALL_WORK_EXIT" to be defined as "SECCOMP | SYSCALL_EMU"
  to keep the behaviour unchanged.
- Add more testcases test.
- Add Reviewed-by.
- Update the commit message.
- Link to v7: https://lore.kernel.org/all/20251117133048.53182-1-ruanjinjie at huawei.com/

Chanegs in v7:
- Support "Syscall User Dispatch" by implementing
  arch_syscall_is_vdso_sigreturn() as kemal suggested.
- Add aarch64 support for "sud" selftest testcase, which tested ok with
  the patch series.
- Fix the kernel test robot warning for arch_ptrace_report_syscall_entry()
  and arch_ptrace_report_syscall_exit() in asm/entry-common.h.
- Add perf syscall performance test.
- Link to v6: https://lore.kernel.org/all/20250916082611.2972008-1-ruanjinjie at huawei.com/

Changes in v6:
- Rebased on v6.17-rc5-next as arm64 generic irq entry has merged.
- Update the commit message.
- Link to v5: https://lore.kernel.org/all/20241206101744.4161990-1-ruanjinjie at huawei.com/

Changes in v5:
- Not change arm32 and keep inerrupts_enabled() macro for gicv3 driver.
- Move irqentry_state definition into arch/arm64/kernel/entry-common.c.
- Avoid removing the __enter_from_*() and __exit_to_*() wrappers.
- Update "irqentry_state_t ret/irq_state" to "state"
  to keep it consistently.
- Use generic irq entry header for PREEMPT_DYNAMIC after split
  the generic entry.
- Also refactor the ARM64 syscall code.
- Introduce arch_ptrace_report_syscall_entry/exit(), instead of
  arch_pre/post_report_syscall_entry/exit() to simplify code.
- Make the syscall patches clear separation.
- Update the commit message.
- Link to v4: https://lore.kernel.org/all/20241025100700.3714552-1-ruanjinjie at huawei.com/

Changes in v4:
- Rework/cleanup split into a few patches as Mark suggested.
- Replace interrupts_enabled() macro with regs_irqs_disabled(), instead
  of left it here.
- Remove rcu and lockdep state in pt_regs by using temporary
  irqentry_state_t as Mark suggested.
- Remove some unnecessary intermediate functions to make it clear.
- Rework preempt irq and PREEMPT_DYNAMIC code
  to make the switch more clear.
- arch_prepare_*_entry/exit() -> arch_pre_*_entry/exit().
- Expand the arch functions comment.
- Make arch functions closer to its caller.
- Declare saved_reg in for block.
- Remove arch_exit_to_kernel_mode_prepare(), arch_enter_from_kernel_mode().
- Adjust "Add few arch functions to use generic entry" patch to be
  the penultimate.
- Update the commit message.
- Add suggested-by.
- Link to v3: https://lore.kernel.org/all/20240629085601.470241-1-ruanjinjie at huawei.com/

Changes in v3:
- Test the MTE test cases.
- Handle forget_syscall() in arch_post_report_syscall_entry()
- Make the arch funcs not use __weak as Thomas suggested, so move
  the arch funcs to entry-common.h, and make arch_forget_syscall() folded
  in arch_post_report_syscall_entry() as suggested.
- Move report_single_step() to thread_info.h for arm64
- Change __always_inline() to inline, add inline for the other arch funcs.
- Remove unused signal.h for entry-common.h.
- Add Suggested-by.
- Update the commit message.

Changes in v2:
- Add tested-by.
- Fix a bug that not call arch_post_report_syscall_entry() in
  syscall_trace_enter() if ptrace_report_syscall_entry() return not zero.
- Refactor report_syscall().
- Add comment for arch_prepare_report_syscall_exit().
- Adjust entry-common.h header file inclusion to alphabetical order.
- Update the commit message.

Jinjie Ruan (15):
  arm64: Remove unused _TIF_WORK_MASK
  arm64/ptrace: Split report_syscall()
  arm64/ptrace: Return early for ptrace_report_syscall_entry() error
  arm64/ptrace: Refactor syscall_trace_enter/exit()
  arm64: ptrace: Move rseq_syscall() before audit_syscall_exit()
  arm64: syscall: Rework el0_svc_common()
  arm64/ptrace: Not check _TIF_SECCOMP/SYSCALL_EMU for
    syscall_exit_work()
  arm64/ptrace: Do not report_syscall_exit() for
    PTRACE_SYSEMU_SINGLESTEP
  arm64/ptrace: Expand secure_computing() in place
  arm64/ptrace: Use syscall_get_arguments() helper
  entry: Split syscall_exit_to_user_mode_work() for arch reuse
  entry: Add arch_ptrace_report_syscall_entry/exit()
  arm64: entry: Convert to generic entry
  arm64: Inline el0_svc_common()
  entry: Inline syscall_exit_work() and syscall_trace_enter()

kemal (1):
  selftests: sud_test: Support aarch64

 arch/arm64/Kconfig                            |   2 +-
 arch/arm64/include/asm/entry-common.h         |  76 ++++++++
 arch/arm64/include/asm/syscall.h              |  19 +-
 arch/arm64/include/asm/thread_info.h          |  22 +--
 arch/arm64/kernel/debug-monitors.c            |   7 +
 arch/arm64/kernel/ptrace.c                    |  94 ----------
 arch/arm64/kernel/signal.c                    |   2 +-
 arch/arm64/kernel/syscall.c                   |  29 +--
 include/linux/entry-common.h                  | 176 ++++++++++++++++--
 kernel/entry/common.h                         |   7 -
 kernel/entry/syscall-common.c                 |  96 +---------
 kernel/entry/syscall_user_dispatch.c          |   4 +-
 .../syscall_user_dispatch/sud_benchmark.c     |   2 +-
 .../syscall_user_dispatch/sud_test.c          |   4 +
 14 files changed, 282 insertions(+), 258 deletions(-)
 delete mode 100644 kernel/entry/common.h

-- 
2.34.1



From ruanjinjie at huawei.com  Mon Dec 22 03:47:23 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 22 Dec 2025 19:47:23 +0800
Subject: [PATCH v10 02/16] arm64/ptrace: Split report_syscall()
In-Reply-To: <20251222114737.1334364-1-ruanjinjie@huawei.com>
References: <20251222114737.1334364-1-ruanjinjie@huawei.com>
Message-ID: <20251222114737.1334364-3-ruanjinjie@huawei.com>

The generic syscall entry code has the form:

| syscall_trace_enter()
| {
|	ptrace_report_syscall_entry()
| }
|
| syscall_exit_work()
| {
|	ptrace_report_syscall_exit()
| }

In preparation for moving arm64 over to the generic entry code, split
report_syscall() to two separate enter and exit functions to align
the structure of the arm64 code with syscall_trace_enter() and
syscall_exit_work() from the generic entry code.

No functional changes.

Reviewed-by: Anshuman Khandual <anshuman.khandual at arm.com>
Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
Suggested-by: Mark Rutland <mark.rutland at arm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
v8:
- report_syscall_enter() -> report_syscall_entry().
- Add ptrace_save_reg() helper.
---
 arch/arm64/kernel/ptrace.c | 41 +++++++++++++++++++++++++++-----------
 1 file changed, 29 insertions(+), 12 deletions(-)

diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index b9bdd83fbbca..03fe2f8a4d54 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -2343,9 +2343,10 @@ enum ptrace_syscall_dir {
 	PTRACE_SYSCALL_EXIT,
 };
 
-static void report_syscall(struct pt_regs *regs, enum ptrace_syscall_dir dir)
+static __always_inline unsigned long ptrace_save_reg(struct pt_regs *regs,
+						     enum ptrace_syscall_dir dir,
+						     int *regno)
 {
-	int regno;
 	unsigned long saved_reg;
 
 	/*
@@ -2364,15 +2365,31 @@ static void report_syscall(struct pt_regs *regs, enum ptrace_syscall_dir dir)
 	 * - Syscall stops behave differently to seccomp and pseudo-step traps
 	 *   (the latter do not nobble any registers).
 	 */
-	regno = (is_compat_task() ? 12 : 7);
-	saved_reg = regs->regs[regno];
-	regs->regs[regno] = dir;
+	*regno = (is_compat_task() ? 12 : 7);
+	saved_reg = regs->regs[*regno];
+	regs->regs[*regno] = dir;
 
-	if (dir == PTRACE_SYSCALL_ENTER) {
-		if (ptrace_report_syscall_entry(regs))
-			forget_syscall(regs);
-		regs->regs[regno] = saved_reg;
-	} else if (!test_thread_flag(TIF_SINGLESTEP)) {
+	return saved_reg;
+}
+
+static void report_syscall_entry(struct pt_regs *regs)
+{
+	unsigned long saved_reg;
+	int regno;
+
+	saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_ENTER, &regno);
+	if (ptrace_report_syscall_entry(regs))
+		forget_syscall(regs);
+	regs->regs[regno] = saved_reg;
+}
+
+static void report_syscall_exit(struct pt_regs *regs)
+{
+	unsigned long saved_reg;
+	int regno;
+
+	saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_EXIT, &regno);
+	if (!test_thread_flag(TIF_SINGLESTEP)) {
 		ptrace_report_syscall_exit(regs, 0);
 		regs->regs[regno] = saved_reg;
 	} else {
@@ -2392,7 +2409,7 @@ int syscall_trace_enter(struct pt_regs *regs)
 	unsigned long flags = read_thread_flags();
 
 	if (flags & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE)) {
-		report_syscall(regs, PTRACE_SYSCALL_ENTER);
+		report_syscall_entry(regs);
 		if (flags & _TIF_SYSCALL_EMU)
 			return NO_SYSCALL;
 	}
@@ -2420,7 +2437,7 @@ void syscall_trace_exit(struct pt_regs *regs)
 		trace_sys_exit(regs, syscall_get_return_value(current, regs));
 
 	if (flags & (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP))
-		report_syscall(regs, PTRACE_SYSCALL_EXIT);
+		report_syscall_exit(regs);
 
 	rseq_syscall(regs);
 }
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Dec 22 03:47:24 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 22 Dec 2025 19:47:24 +0800
Subject: [PATCH v10 03/16] arm64/ptrace: Return early for ptrace_report_syscall_entry() error
In-Reply-To: <20251222114737.1334364-1-ruanjinjie@huawei.com>
References: <20251222114737.1334364-1-ruanjinjie@huawei.com>
Message-ID: <20251222114737.1334364-4-ruanjinjie@huawei.com>

The generic entry abort the syscall_trace_enter() sequence if
ptrace_report_syscall_entry() errors out, but arm64 not.

When ptrace requests interception, it should prevent all subsequent
system-call processing, including audit and seccomp. In preparation for
moving arm64 over to the generic entry code, return early if
ptrace_report_syscall_entry() encounters an error.

Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/kernel/ptrace.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 03fe2f8a4d54..f333791ffba6 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -2372,15 +2372,18 @@ static __always_inline unsigned long ptrace_save_reg(struct pt_regs *regs,
 	return saved_reg;
 }
 
-static void report_syscall_entry(struct pt_regs *regs)
+static int report_syscall_entry(struct pt_regs *regs)
 {
 	unsigned long saved_reg;
-	int regno;
+	int regno, ret;
 
 	saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_ENTER, &regno);
-	if (ptrace_report_syscall_entry(regs))
+	ret = ptrace_report_syscall_entry(regs);
+	if (ret)
 		forget_syscall(regs);
 	regs->regs[regno] = saved_reg;
+
+	return ret;
 }
 
 static void report_syscall_exit(struct pt_regs *regs)
@@ -2407,10 +2410,11 @@ static void report_syscall_exit(struct pt_regs *regs)
 int syscall_trace_enter(struct pt_regs *regs)
 {
 	unsigned long flags = read_thread_flags();
+	int ret;
 
 	if (flags & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE)) {
-		report_syscall_entry(regs);
-		if (flags & _TIF_SYSCALL_EMU)
+		ret = report_syscall_entry(regs);
+		if (ret || (flags & _TIF_SYSCALL_EMU))
 			return NO_SYSCALL;
 	}
 
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Dec 22 03:47:27 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 22 Dec 2025 19:47:27 +0800
Subject: [PATCH v10 06/16] arm64: syscall: Rework el0_svc_common()
In-Reply-To: <20251222114737.1334364-1-ruanjinjie@huawei.com>
References: <20251222114737.1334364-1-ruanjinjie@huawei.com>
Message-ID: <20251222114737.1334364-7-ruanjinjie@huawei.com>

The generic syscall syscall_exit_work() has the following content:

| audit_syscall_exit(regs)
| trace_sys_exit(regs, ...)
| ptrace_report_syscall_exit(regs, step)

The generic syscall syscall_exit_to_user_mode_work() has
the following form:

| unsigned long work = READ_ONCE(current_thread_info()->syscall_work)
| rseq_syscall()
| if (unlikely(work & SYSCALL_WORK_EXIT))
|	syscall_exit_work(regs, work)

In preparation for moving arm64 over to the generic entry code,
rework el0_svc_common() as below:

- Rename syscall_trace_exit() to syscall_exit_work().

- Add syscall_exit_to_user_mode_work_prepare() function to replace
  the combination of read_thread_flags() and syscall_exit_work(),
  also move the syscall exit check logic into it. Move has_syscall_work()
  helper into asm/syscall.h for reuse.

- As currently rseq_syscall() is always called and itself is controlled
  by the CONFIG_DEBUG_RSEQ macro, so the CONFIG_DEBUG_RSEQ check
  is removed.

Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/include/asm/syscall.h |  7 ++++++-
 arch/arm64/kernel/ptrace.c       | 14 +++++++++++---
 arch/arm64/kernel/syscall.c      | 20 +-------------------
 3 files changed, 18 insertions(+), 23 deletions(-)

diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
index cef1d9ce6e1b..b86b2ffa16ef 100644
--- a/arch/arm64/include/asm/syscall.h
+++ b/arch/arm64/include/asm/syscall.h
@@ -120,7 +120,12 @@ static inline int syscall_get_arch(struct task_struct *task)
 	return AUDIT_ARCH_AARCH64;
 }
 
+static inline bool has_syscall_work(unsigned long flags)
+{
+	return unlikely(flags & _TIF_SYSCALL_WORK);
+}
+
 int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags);
-void syscall_trace_exit(struct pt_regs *regs, unsigned long flags);
+void syscall_exit_to_user_mode_work_prepare(struct pt_regs *regs);
 
 #endif	/* __ASM_SYSCALL_H */
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 983d8d1104df..95f8ea21680a 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -2440,10 +2440,8 @@ int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags)
 	return syscall;
 }
 
-void syscall_trace_exit(struct pt_regs *regs, unsigned long flags)
+static void syscall_exit_work(struct pt_regs *regs, unsigned long flags)
 {
-	rseq_syscall(regs);
-
 	audit_syscall_exit(regs);
 
 	if (flags & _TIF_SYSCALL_TRACEPOINT)
@@ -2453,6 +2451,16 @@ void syscall_trace_exit(struct pt_regs *regs, unsigned long flags)
 		report_syscall_exit(regs);
 }
 
+void syscall_exit_to_user_mode_work_prepare(struct pt_regs *regs)
+{
+	unsigned long flags = read_thread_flags();
+
+	rseq_syscall(regs);
+
+	if (has_syscall_work(flags) || flags & _TIF_SINGLESTEP)
+		syscall_exit_work(regs, flags);
+}
+
 /*
  * SPSR_ELx bits which are always architecturally RES0 per ARM DDI 0487D.a.
  * We permit userspace to set SSBS (AArch64 bit 12, AArch32 bit 23) which is
diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index 5a103873de12..76c9c6fc1b30 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -65,11 +65,6 @@ static void invoke_syscall(struct pt_regs *regs, unsigned int scno,
 	choose_random_kstack_offset(get_random_u16());
 }
 
-static inline bool has_syscall_work(unsigned long flags)
-{
-	return unlikely(flags & _TIF_SYSCALL_WORK);
-}
-
 static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 			   const syscall_fn_t syscall_table[])
 {
@@ -130,21 +125,8 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 	}
 
 	invoke_syscall(regs, scno, sc_nr, syscall_table);
-
-	/*
-	 * The tracing status may have changed under our feet, so we have to
-	 * check again. However, if we were tracing entry, then we always trace
-	 * exit regardless, as the old entry assembly did.
-	 */
-	if (!has_syscall_work(flags) && !IS_ENABLED(CONFIG_DEBUG_RSEQ)) {
-		flags = read_thread_flags();
-		if (!has_syscall_work(flags) && !(flags & _TIF_SINGLESTEP))
-			return;
-	}
-
 trace_exit:
-	flags = read_thread_flags();
-	syscall_trace_exit(regs, flags);
+	syscall_exit_to_user_mode_work_prepare(regs);
 }
 
 void do_el0_svc(struct pt_regs *regs)
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Dec 22 03:47:28 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 22 Dec 2025 19:47:28 +0800
Subject: [PATCH v10 07/16] arm64/ptrace: Not check _TIF_SECCOMP/SYSCALL_EMU for syscall_exit_work()
In-Reply-To: <20251222114737.1334364-1-ruanjinjie@huawei.com>
References: <20251222114737.1334364-1-ruanjinjie@huawei.com>
Message-ID: <20251222114737.1334364-8-ruanjinjie@huawei.com>

As syscall_exit_work() do not handle seccomp, so not check _TIF_SECCOMP
for syscall_exit_work().

And as the man manual of PTRACE_SYSEMU and PTRACE_SYSEMU_SINGLESTEP
said, "For PTRACE_SYSEMU, continue and stop on entry to the next system
call, which will not be executed. For PTRACE_SYSEMU_SINGLESTEP, do the same
but also singlestep if not a system call.". So only the syscall entry need
to be reported for SYSCALL_EMU, so not check _TIF_SYSCALL_EMU for
syscall_exit_work().

After this, audit_syscall_exit() and report_syscall_exit() will
no longer be called if only SECCOMP and/or SYSCALL_EMU is set.

And remove has_syscall_work() by the way as currently it is only used in
el0_svc_common().

This is another preparation for moving arm64 over to the generic
entry code.

Link?https://man7.org/linux/man-pages/man2/ptrace.2.html
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/include/asm/syscall.h     | 5 -----
 arch/arm64/include/asm/thread_info.h | 3 +++
 arch/arm64/kernel/ptrace.c           | 2 +-
 arch/arm64/kernel/syscall.c          | 2 +-
 4 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
index b86b2ffa16ef..7746c8f0e045 100644
--- a/arch/arm64/include/asm/syscall.h
+++ b/arch/arm64/include/asm/syscall.h
@@ -120,11 +120,6 @@ static inline int syscall_get_arch(struct task_struct *task)
 	return AUDIT_ARCH_AARCH64;
 }
 
-static inline bool has_syscall_work(unsigned long flags)
-{
-	return unlikely(flags & _TIF_SYSCALL_WORK);
-}
-
 int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags);
 void syscall_exit_to_user_mode_work_prepare(struct pt_regs *regs);
 
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index 24fcd6adaa33..ef1462b9b00b 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -110,6 +110,9 @@ void arch_setup_new_exec(void);
 				 _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \
 				 _TIF_SYSCALL_EMU)
 
+#define _TIF_SYSCALL_EXIT_WORK	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
+				 _TIF_SYSCALL_TRACEPOINT)
+
 #ifdef CONFIG_SHADOW_CALL_STACK
 #define INIT_SCS							\
 	.scs_base	= init_shadow_call_stack,			\
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 95f8ea21680a..ec818940114e 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -2457,7 +2457,7 @@ void syscall_exit_to_user_mode_work_prepare(struct pt_regs *regs)
 
 	rseq_syscall(regs);
 
-	if (has_syscall_work(flags) || flags & _TIF_SINGLESTEP)
+	if (unlikely(flags & _TIF_SYSCALL_EXIT_WORK) || flags & _TIF_SINGLESTEP)
 		syscall_exit_work(regs, flags);
 }
 
diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index 76c9c6fc1b30..80b7fd67492e 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -101,7 +101,7 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 		return;
 	}
 
-	if (has_syscall_work(flags)) {
+	if (unlikely(flags & _TIF_SYSCALL_WORK)) {
 		/*
 		 * The de-facto standard way to skip a system call using ptrace
 		 * is to set the system call to -1 (NO_SYSCALL) and set x0 to a
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Dec 22 03:47:29 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 22 Dec 2025 19:47:29 +0800
Subject: [PATCH v10 08/16] arm64/ptrace: Do not report_syscall_exit() for PTRACE_SYSEMU_SINGLESTEP
In-Reply-To: <20251222114737.1334364-1-ruanjinjie@huawei.com>
References: <20251222114737.1334364-1-ruanjinjie@huawei.com>
Message-ID: <20251222114737.1334364-9-ruanjinjie@huawei.com>

The generic report_single_step() always returns false if SYSCALL_EMU
is set, but arm64 only checks _TIF_SINGLESTEP and does not check
_TIF_SYSCALL_EMU, which means that if both _TIF_SINGLESTEP and
_TIF_SYSCALL_EMU are set, the generic entry will not report
a single-step, whereas arm64 will do it.

As the man manual of PTRACE_SYSEMU and PTRACE_SYSEMU_SINGLESTEP said,
"For PTRACE_SYSEMU, continue and stop on entry to the next system
call, which will not be executed. For PTRACE_SYSEMU_SINGLESTEP, do the
same but also singlestep if not a system call.". And as the generic entry
report_single_step() comment said, If SYSCALL_EMU is set, then the only
reason to report is when SINGLESTEP is set (i.e. PTRACE_SYSEMU_SINGLESTEP).
Because this syscall instruction has been already reported
in syscall_trace_enter(), there is no need to report the syscall
again in syscall_exit_work().

In preparation for moving arm64 over to the generic entry code,

- Add report_single_step() helper for arm64 to make it clear.

- Do not report_syscall_exit() if both _TIF_SYSCALL_EMU and
  _TIF_SINGLESTEP set.

Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/kernel/ptrace.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index ec818940114e..558d5553fd6b 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -2440,14 +2440,25 @@ int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags)
 	return syscall;
 }
 
+static inline bool report_single_step(unsigned long flags)
+{
+	if (flags & _TIF_SYSCALL_EMU)
+		return false;
+
+	return flags & _TIF_SINGLESTEP;
+}
+
 static void syscall_exit_work(struct pt_regs *regs, unsigned long flags)
 {
+	bool step;
+
 	audit_syscall_exit(regs);
 
 	if (flags & _TIF_SYSCALL_TRACEPOINT)
 		trace_sys_exit(regs, syscall_get_return_value(current, regs));
 
-	if (flags & (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP))
+	step = report_single_step(flags);
+	if (step || flags & _TIF_SYSCALL_TRACE)
 		report_syscall_exit(regs);
 }
 
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Dec 22 03:47:30 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 22 Dec 2025 19:47:30 +0800
Subject: [PATCH v10 09/16] arm64/ptrace: Expand secure_computing() in place
In-Reply-To: <20251222114737.1334364-1-ruanjinjie@huawei.com>
References: <20251222114737.1334364-1-ruanjinjie@huawei.com>
Message-ID: <20251222114737.1334364-10-ruanjinjie@huawei.com>

The generic entry expand secure_computing() in place and call
__secure_computing() directly.

In order to switch to the generic entry for arm64, refactor
secure_computing() for syscall_trace_enter().

No functional changes.

Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/kernel/ptrace.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 558d5553fd6b..a1922e4a6437 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -2418,8 +2418,11 @@ int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags)
 	}
 
 	/* Do the secure computing after ptrace; failures should be fast. */
-	if (secure_computing() == -1)
-		return NO_SYSCALL;
+	if (flags & _TIF_SECCOMP) {
+		ret = __secure_computing();
+		if (ret == -1)
+			return NO_SYSCALL;
+	}
 
 	/* Either of the above might have changed the syscall number */
 	syscall = syscall_get_nr(current, regs);
@@ -2437,7 +2440,7 @@ int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags)
 	audit_syscall_entry(syscall, regs->orig_x0, regs->regs[1],
 			    regs->regs[2], regs->regs[3]);
 
-	return syscall;
+	return ret ? : syscall;
 }
 
 static inline bool report_single_step(unsigned long flags)
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Dec 22 03:47:32 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 22 Dec 2025 19:47:32 +0800
Subject: [PATCH v10 11/16] entry: Split syscall_exit_to_user_mode_work() for arch reuse
In-Reply-To: <20251222114737.1334364-1-ruanjinjie@huawei.com>
References: <20251222114737.1334364-1-ruanjinjie@huawei.com>
Message-ID: <20251222114737.1334364-12-ruanjinjie@huawei.com>

In the generic entry code, the beginning of
syscall_exit_to_user_mode_work() can be reused on arm64 so it makes
sense to split it.

In preparation for moving arm64 over to the generic entry
code, split out syscall_exit_to_user_mode_work_prepare() helper from
syscall_exit_to_user_mode_work().

No functional changes.

Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
Reviewed-by: Thomas Gleixner <tglx at linutronix.de>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 include/linux/entry-common.h | 35 ++++++++++++++++++++++-------------
 1 file changed, 22 insertions(+), 13 deletions(-)

diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h
index 87efb38b7081..0de0e60630e1 100644
--- a/include/linux/entry-common.h
+++ b/include/linux/entry-common.h
@@ -121,20 +121,11 @@ static __always_inline long syscall_enter_from_user_mode(struct pt_regs *regs, l
  */
 void syscall_exit_work(struct pt_regs *regs, unsigned long work);
 
-/**
- * syscall_exit_to_user_mode_work - Handle work before returning to user mode
- * @regs:	Pointer to currents pt_regs
- *
- * Same as step 1 and 2 of syscall_exit_to_user_mode() but without calling
- * exit_to_user_mode() to perform the final transition to user mode.
- *
- * Calling convention is the same as for syscall_exit_to_user_mode() and it
- * returns with all work handled and interrupts disabled. The caller must
- * invoke exit_to_user_mode() before actually switching to user mode to
- * make the final state transitions. Interrupts must stay disabled between
- * return from this function and the invocation of exit_to_user_mode().
+/*
+ * Syscall specific exit to user mode preparation. Runs with interrupts
+ * enabled.
  */
-static __always_inline void syscall_exit_to_user_mode_work(struct pt_regs *regs)
+static __always_inline void syscall_exit_to_user_mode_work_prepare(struct pt_regs *regs)
 {
 	unsigned long work = READ_ONCE(current_thread_info()->syscall_work);
 	unsigned long nr = syscall_get_nr(current, regs);
@@ -155,6 +146,24 @@ static __always_inline void syscall_exit_to_user_mode_work(struct pt_regs *regs)
 	 */
 	if (unlikely(work & SYSCALL_WORK_EXIT))
 		syscall_exit_work(regs, work);
+}
+
+/**
+ * syscall_exit_to_user_mode_work - Handle work before returning to user mode
+ * @regs:	Pointer to currents pt_regs
+ *
+ * Same as step 1 and 2 of syscall_exit_to_user_mode() but without calling
+ * exit_to_user_mode() to perform the final transition to user mode.
+ *
+ * Calling convention is the same as for syscall_exit_to_user_mode() and it
+ * returns with all work handled and interrupts disabled. The caller must
+ * invoke exit_to_user_mode() before actually switching to user mode to
+ * make the final state transitions. Interrupts must stay disabled between
+ * return from this function and the invocation of exit_to_user_mode().
+ */
+static __always_inline void syscall_exit_to_user_mode_work(struct pt_regs *regs)
+{
+	syscall_exit_to_user_mode_work_prepare(regs);
 	local_irq_disable_exit_to_user();
 	syscall_exit_to_user_mode_prepare(regs);
 }
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Dec 22 03:47:33 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 22 Dec 2025 19:47:33 +0800
Subject: [PATCH v10 12/16] entry: Add arch_ptrace_report_syscall_entry/exit()
In-Reply-To: <20251222114737.1334364-1-ruanjinjie@huawei.com>
References: <20251222114737.1334364-1-ruanjinjie@huawei.com>
Message-ID: <20251222114737.1334364-13-ruanjinjie@huawei.com>

Differ from generic entry, due to historical reasons, ARM64 need to
save/restore during syscall entry/exit because ARM64 use a scratch
register (ip(r12) on AArch32, x7 on AArch64) to denote syscall entry/exit.

In preparation for moving arm64 over to the generic entry code,
add arch_ptrace_report_syscall_entry/exit() as the default
ptrace_report_syscall_entry/exit() implementation. This allows
arm64 to implement the architecture specific version.

This allows arm64 to implement the architecture specific version.

Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
Suggested-by: Mark Rutland <mark.rutland at arm.com>
Suggested-by: Thomas Gleixner <tglx at linutronix.de>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 include/linux/entry-common.h  | 39 +++++++++++++++++++++++++++++++++++
 kernel/entry/syscall-common.c |  4 ++--
 2 files changed, 41 insertions(+), 2 deletions(-)

diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h
index 0de0e60630e1..17171e8873fc 100644
--- a/include/linux/entry-common.h
+++ b/include/linux/entry-common.h
@@ -45,6 +45,25 @@
 				 SYSCALL_WORK_SYSCALL_EXIT_TRAP	|	\
 				 ARCH_SYSCALL_WORK_EXIT)
 
+/**
+ * arch_ptrace_report_syscall_entry - Architecture specific
+ *				      ptrace_report_syscall_entry().
+ *
+ * Invoked from syscall_trace_enter() to wrap ptrace_report_syscall_entry().
+ * Defaults to ptrace_report_syscall_entry.
+ *
+ * The main purpose is to support arch-specific ptrace_report_syscall_entry()
+ * implementation.
+ */
+static __always_inline int arch_ptrace_report_syscall_entry(struct pt_regs *regs);
+
+#ifndef arch_ptrace_report_syscall_entry
+static __always_inline int arch_ptrace_report_syscall_entry(struct pt_regs *regs)
+{
+	return ptrace_report_syscall_entry(regs);
+}
+#endif
+
 long syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long work);
 
 /**
@@ -112,6 +131,26 @@ static __always_inline long syscall_enter_from_user_mode(struct pt_regs *regs, l
 	return ret;
 }
 
+/**
+ * arch_ptrace_report_syscall_exit - Architecture specific
+ *				     ptrace_report_syscall_exit.
+ *
+ * Invoked from syscall_exit_work() to wrap ptrace_report_syscall_exit().
+ *
+ * The main purpose is to support arch-specific ptrace_report_syscall_exit
+ * implementation.
+ */
+static __always_inline void arch_ptrace_report_syscall_exit(struct pt_regs *regs,
+							    int step);
+
+#ifndef arch_ptrace_report_syscall_exit
+static __always_inline void arch_ptrace_report_syscall_exit(struct pt_regs *regs,
+							    int step)
+{
+	ptrace_report_syscall_exit(regs, step);
+}
+#endif
+
 /**
  * syscall_exit_work - Handle work before returning to user mode
  * @regs:	Pointer to current pt_regs
diff --git a/kernel/entry/syscall-common.c b/kernel/entry/syscall-common.c
index 940a597ded40..fe38f84dfff3 100644
--- a/kernel/entry/syscall-common.c
+++ b/kernel/entry/syscall-common.c
@@ -34,7 +34,7 @@ long syscall_trace_enter(struct pt_regs *regs, long syscall,
 
 	/* Handle ptrace */
 	if (work & (SYSCALL_WORK_SYSCALL_TRACE | SYSCALL_WORK_SYSCALL_EMU)) {
-		ret = ptrace_report_syscall_entry(regs);
+		ret = arch_ptrace_report_syscall_entry(regs);
 		if (ret || (work & SYSCALL_WORK_SYSCALL_EMU))
 			return -1L;
 	}
@@ -100,5 +100,5 @@ void syscall_exit_work(struct pt_regs *regs, unsigned long work)
 
 	step = report_single_step(work);
 	if (step || work & SYSCALL_WORK_SYSCALL_TRACE)
-		ptrace_report_syscall_exit(regs, step);
+		arch_ptrace_report_syscall_exit(regs, step);
 }
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Dec 22 03:47:31 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 22 Dec 2025 19:47:31 +0800
Subject: [PATCH v10 10/16] arm64/ptrace: Use syscall_get_arguments() helper
In-Reply-To: <20251222114737.1334364-1-ruanjinjie@huawei.com>
References: <20251222114737.1334364-1-ruanjinjie@huawei.com>
Message-ID: <20251222114737.1334364-11-ruanjinjie@huawei.com>

The generic entry check audit context first and use
syscall_get_arguments() helper.

In order to switch to the generic entry for arm64,

- Also use syscall_get_arguments() to get audit_syscall_entry()'s
  last four parameters.

- Extract the syscall_enter_audit() helper to make it clear.

- Check audit context first, which saves an unnecessary memcpy when
  current process's audit_context is NULL.

Overall these changes make syscall_enter_audit() exactly equivalent
to the generic one.

No functional changes.

Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/kernel/ptrace.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index a1922e4a6437..2645ddf77369 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -2407,6 +2407,16 @@ static void report_syscall_exit(struct pt_regs *regs)
 	}
 }
 
+static inline void syscall_enter_audit(struct pt_regs *regs, long syscall)
+{
+	if (unlikely(audit_context())) {
+		unsigned long args[6];
+
+		syscall_get_arguments(current, regs, args);
+		audit_syscall_entry(syscall, args[0], args[1], args[2], args[3]);
+	}
+}
+
 int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags)
 {
 	int ret;
@@ -2437,8 +2447,7 @@ int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags)
 		 syscall = syscall_get_nr(current, regs);
 	}
 
-	audit_syscall_entry(syscall, regs->orig_x0, regs->regs[1],
-			    regs->regs[2], regs->regs[3]);
+	syscall_enter_audit(regs, syscall);
 
 	return ret ? : syscall;
 }
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Dec 22 03:47:34 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 22 Dec 2025 19:47:34 +0800
Subject: [PATCH v10 13/16] arm64: entry: Convert to generic entry
In-Reply-To: <20251222114737.1334364-1-ruanjinjie@huawei.com>
References: <20251222114737.1334364-1-ruanjinjie@huawei.com>
Message-ID: <20251222114737.1334364-14-ruanjinjie@huawei.com>

Currently, x86, Riscv, Loongarch use the generic entry which makes
maintainers' work easier and codes more elegant. arm64 has already
switched to the generic IRQ entry, so completely convert arm64 to use
the generic entry infrastructure from kernel/entry/*.

The changes are below:
 - Remove TIF_SYSCALL_* flag.

 - Remove _TIF_SYSCALL_WORK/EXIT_WORK as they are equal with
   SYSCALL_WORK_ENTER/EXIT.

 - Implement arch_ptrace_report_syscall_entry/exit() with
   report_syscall_entry/exit() to do arm64-specific save/restore
   during syscall entry/exit.

 - Remove arm64 syscall_trace_enter() and related sub-functions
   including syscall_enter_audit(), by calling generic entry's
   functions with similar functionality.

 - Set/clear SYSCALL_EXIT_TRAP flag when enable/disable single_step,
   So _TIF_SINGLESTEP can be replaced with generic SYSCALL_EXIT_TRAP,
   _TIF_SYSCALL_EXIT_WORK and _TIF_SINGLESTEP can be replaced
   with generic SYSCALL_WORK_EXIT, arm64's report_single_step() can be
   replaced with generic version.

 - Remove arm64's syscall_exit_to_user_mode_work_prepare() and
   syscall_exit_work() etc. by using generic entry's similar same name
   functions.

 - Implement arch_syscall_is_vdso_sigreturn() to support "Syscall User
   Dispatch".

Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
Suggested-by: Kevin Brodsky <kevin.brodsky at arm.com>
Suggested-by: Mark Rutland <mark.rutland at arm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/Kconfig                    |   2 +-
 arch/arm64/include/asm/entry-common.h |  76 +++++++++++++
 arch/arm64/include/asm/syscall.h      |  19 +++-
 arch/arm64/include/asm/thread_info.h  |  19 +---
 arch/arm64/kernel/debug-monitors.c    |   7 ++
 arch/arm64/kernel/ptrace.c            | 153 --------------------------
 arch/arm64/kernel/signal.c            |   2 +-
 arch/arm64/kernel/syscall.c           |   6 +-
 8 files changed, 107 insertions(+), 177 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 93173f0a09c7..f50b49ce8b65 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -153,9 +153,9 @@ config ARM64
 	select GENERIC_CPU_DEVICES
 	select GENERIC_CPU_VULNERABILITIES
 	select GENERIC_EARLY_IOREMAP
+	select GENERIC_ENTRY
 	select GENERIC_IDLE_POLL_SETUP
 	select GENERIC_IOREMAP
-	select GENERIC_IRQ_ENTRY
 	select GENERIC_IRQ_IPI
 	select GENERIC_IRQ_KEXEC_CLEAR_VM_FORWARD
 	select GENERIC_IRQ_PROBE
diff --git a/arch/arm64/include/asm/entry-common.h b/arch/arm64/include/asm/entry-common.h
index cab8cd78f693..d8bf4bf342e8 100644
--- a/arch/arm64/include/asm/entry-common.h
+++ b/arch/arm64/include/asm/entry-common.h
@@ -3,14 +3,21 @@
 #ifndef _ASM_ARM64_ENTRY_COMMON_H
 #define _ASM_ARM64_ENTRY_COMMON_H
 
+#include <linux/ptrace.h>
 #include <linux/thread_info.h>
 
+#include <asm/compat.h>
 #include <asm/cpufeature.h>
 #include <asm/daifflags.h>
 #include <asm/fpsimd.h>
 #include <asm/mte.h>
 #include <asm/stacktrace.h>
 
+enum ptrace_syscall_dir {
+	PTRACE_SYSCALL_ENTER = 0,
+	PTRACE_SYSCALL_EXIT,
+};
+
 #define ARCH_EXIT_TO_USER_MODE_WORK (_TIF_MTE_ASYNC_FAULT | _TIF_FOREIGN_FPSTATE)
 
 static __always_inline void arch_exit_to_user_mode_work(struct pt_regs *regs,
@@ -54,4 +61,73 @@ static inline bool arch_irqentry_exit_need_resched(void)
 
 #define arch_irqentry_exit_need_resched arch_irqentry_exit_need_resched
 
+static __always_inline unsigned long ptrace_save_reg(struct pt_regs *regs,
+						     enum ptrace_syscall_dir dir,
+						     int *regno)
+{
+	unsigned long saved_reg;
+
+	/*
+	 * We have some ABI weirdness here in the way that we handle syscall
+	 * exit stops because we indicate whether or not the stop has been
+	 * signalled from syscall entry or syscall exit by clobbering a general
+	 * purpose register (ip/r12 for AArch32, x7 for AArch64) in the tracee
+	 * and restoring its old value after the stop. This means that:
+	 *
+	 * - Any writes by the tracer to this register during the stop are
+	 *   ignored/discarded.
+	 *
+	 * - The actual value of the register is not available during the stop,
+	 *   so the tracer cannot save it and restore it later.
+	 *
+	 * - Syscall stops behave differently to seccomp and pseudo-step traps
+	 *   (the latter do not nobble any registers).
+	 */
+	*regno = (is_compat_task() ? 12 : 7);
+	saved_reg = regs->regs[*regno];
+	regs->regs[*regno] = dir;
+
+	return saved_reg;
+}
+
+static __always_inline int arch_ptrace_report_syscall_entry(struct pt_regs *regs)
+{
+	unsigned long saved_reg;
+	int regno, ret;
+
+	saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_ENTER, &regno);
+	ret = ptrace_report_syscall_entry(regs);
+	if (ret)
+		forget_syscall(regs);
+	regs->regs[regno] = saved_reg;
+
+	return ret;
+}
+
+#define arch_ptrace_report_syscall_entry arch_ptrace_report_syscall_entry
+
+static __always_inline void arch_ptrace_report_syscall_exit(struct pt_regs *regs,
+							    int step)
+{
+	unsigned long saved_reg;
+	int regno;
+
+	saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_EXIT, &regno);
+	if (!step) {
+		ptrace_report_syscall_exit(regs, 0);
+		regs->regs[regno] = saved_reg;
+	} else {
+		regs->regs[regno] = saved_reg;
+
+		/*
+		 * Signal a pseudo-step exception since we are stepping but
+		 * tracer modifications to the registers may have rewound the
+		 * state machine.
+		 */
+		ptrace_report_syscall_exit(regs, 1);
+	}
+}
+
+#define arch_ptrace_report_syscall_exit arch_ptrace_report_syscall_exit
+
 #endif /* _ASM_ARM64_ENTRY_COMMON_H */
diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
index 7746c8f0e045..240d45735cc5 100644
--- a/arch/arm64/include/asm/syscall.h
+++ b/arch/arm64/include/asm/syscall.h
@@ -9,6 +9,9 @@
 #include <linux/compat.h>
 #include <linux/err.h>
 
+#include <asm/compat.h>
+#include <asm/vdso.h>
+
 typedef long (*syscall_fn_t)(const struct pt_regs *regs);
 
 extern const syscall_fn_t sys_call_table[];
@@ -120,7 +123,19 @@ static inline int syscall_get_arch(struct task_struct *task)
 	return AUDIT_ARCH_AARCH64;
 }
 
-int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags);
-void syscall_exit_to_user_mode_work_prepare(struct pt_regs *regs);
+static inline bool arch_syscall_is_vdso_sigreturn(struct pt_regs *regs)
+{
+	unsigned long sigtramp;
+
+#ifdef CONFIG_COMPAT
+	if (is_compat_task()) {
+		unsigned long sigpage = (unsigned long)current->mm->context.sigpage;
+
+		return regs->pc >= sigpage && regs->pc < (sigpage + PAGE_SIZE);
+	}
+#endif
+	sigtramp = (unsigned long)VDSO_SYMBOL(current->mm->context.vdso, sigtramp);
+	return regs->pc == (sigtramp + 8);
+}
 
 #endif	/* __ASM_SYSCALL_H */
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index ef1462b9b00b..90be0c590b86 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -43,6 +43,7 @@ struct thread_info {
 	void			*scs_sp;
 #endif
 	u32			cpu;
+	unsigned long		syscall_work;   /* SYSCALL_WORK_ flags */
 };
 
 #define thread_saved_pc(tsk)	\
@@ -65,11 +66,6 @@ void arch_setup_new_exec(void);
 #define TIF_UPROBE		5	/* uprobe breakpoint or singlestep */
 #define TIF_MTE_ASYNC_FAULT	6	/* MTE Asynchronous Tag Check Fault */
 #define TIF_NOTIFY_SIGNAL	7	/* signal notifications exist */
-#define TIF_SYSCALL_TRACE	8	/* syscall trace active */
-#define TIF_SYSCALL_AUDIT	9	/* syscall auditing */
-#define TIF_SYSCALL_TRACEPOINT	10	/* syscall tracepoint for ftrace */
-#define TIF_SECCOMP		11	/* syscall secure computing */
-#define TIF_SYSCALL_EMU		12	/* syscall emulation active */
 #define TIF_PATCH_PENDING	13	/* pending live patching update */
 #define TIF_MEMDIE		18	/* is terminating due to OOM killer */
 #define TIF_FREEZE		19
@@ -92,27 +88,14 @@ void arch_setup_new_exec(void);
 #define _TIF_NEED_RESCHED_LAZY	(1 << TIF_NEED_RESCHED_LAZY)
 #define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
 #define _TIF_FOREIGN_FPSTATE	(1 << TIF_FOREIGN_FPSTATE)
-#define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
-#define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
-#define _TIF_SYSCALL_TRACEPOINT	(1 << TIF_SYSCALL_TRACEPOINT)
-#define _TIF_SECCOMP		(1 << TIF_SECCOMP)
-#define _TIF_SYSCALL_EMU	(1 << TIF_SYSCALL_EMU)
 #define _TIF_PATCH_PENDING	(1 << TIF_PATCH_PENDING)
 #define _TIF_UPROBE		(1 << TIF_UPROBE)
-#define _TIF_SINGLESTEP		(1 << TIF_SINGLESTEP)
 #define _TIF_32BIT		(1 << TIF_32BIT)
 #define _TIF_SVE		(1 << TIF_SVE)
 #define _TIF_MTE_ASYNC_FAULT	(1 << TIF_MTE_ASYNC_FAULT)
 #define _TIF_NOTIFY_SIGNAL	(1 << TIF_NOTIFY_SIGNAL)
 #define _TIF_TSC_SIGSEGV	(1 << TIF_TSC_SIGSEGV)
 
-#define _TIF_SYSCALL_WORK	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
-				 _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \
-				 _TIF_SYSCALL_EMU)
-
-#define _TIF_SYSCALL_EXIT_WORK	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
-				 _TIF_SYSCALL_TRACEPOINT)
-
 #ifdef CONFIG_SHADOW_CALL_STACK
 #define INIT_SCS							\
 	.scs_base	= init_shadow_call_stack,			\
diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c
index 29307642f4c9..e67643a70405 100644
--- a/arch/arm64/kernel/debug-monitors.c
+++ b/arch/arm64/kernel/debug-monitors.c
@@ -385,11 +385,18 @@ void user_enable_single_step(struct task_struct *task)
 
 	if (!test_and_set_ti_thread_flag(ti, TIF_SINGLESTEP))
 		set_regs_spsr_ss(task_pt_regs(task));
+
+	/*
+	 * Ensure that a trap is triggered once stepping out of a system
+	 * call prior to executing any user instruction.
+	 */
+	set_task_syscall_work(task, SYSCALL_EXIT_TRAP);
 }
 NOKPROBE_SYMBOL(user_enable_single_step);
 
 void user_disable_single_step(struct task_struct *task)
 {
 	clear_ti_thread_flag(task_thread_info(task), TIF_SINGLESTEP);
+	clear_task_syscall_work(task, SYSCALL_EXIT_TRAP);
 }
 NOKPROBE_SYMBOL(user_disable_single_step);
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 2645ddf77369..f575b30b2dc4 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -8,7 +8,6 @@
  * Copyright (C) 2012 ARM Ltd.
  */
 
-#include <linux/audit.h>
 #include <linux/compat.h>
 #include <linux/kernel.h>
 #include <linux/sched/signal.h>
@@ -18,7 +17,6 @@
 #include <linux/smp.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
-#include <linux/seccomp.h>
 #include <linux/security.h>
 #include <linux/init.h>
 #include <linux/signal.h>
@@ -28,7 +26,6 @@
 #include <linux/hw_breakpoint.h>
 #include <linux/regset.h>
 #include <linux/elf.h>
-#include <linux/rseq.h>
 
 #include <asm/compat.h>
 #include <asm/cpufeature.h>
@@ -38,13 +35,9 @@
 #include <asm/mte.h>
 #include <asm/pointer_auth.h>
 #include <asm/stacktrace.h>
-#include <asm/syscall.h>
 #include <asm/traps.h>
 #include <asm/system_misc.h>
 
-#define CREATE_TRACE_POINTS
-#include <trace/events/syscalls.h>
-
 struct pt_regs_offset {
 	const char *name;
 	int offset;
@@ -2338,152 +2331,6 @@ long arch_ptrace(struct task_struct *child, long request,
 	return ptrace_request(child, request, addr, data);
 }
 
-enum ptrace_syscall_dir {
-	PTRACE_SYSCALL_ENTER = 0,
-	PTRACE_SYSCALL_EXIT,
-};
-
-static __always_inline unsigned long ptrace_save_reg(struct pt_regs *regs,
-						     enum ptrace_syscall_dir dir,
-						     int *regno)
-{
-	unsigned long saved_reg;
-
-	/*
-	 * We have some ABI weirdness here in the way that we handle syscall
-	 * exit stops because we indicate whether or not the stop has been
-	 * signalled from syscall entry or syscall exit by clobbering a general
-	 * purpose register (ip/r12 for AArch32, x7 for AArch64) in the tracee
-	 * and restoring its old value after the stop. This means that:
-	 *
-	 * - Any writes by the tracer to this register during the stop are
-	 *   ignored/discarded.
-	 *
-	 * - The actual value of the register is not available during the stop,
-	 *   so the tracer cannot save it and restore it later.
-	 *
-	 * - Syscall stops behave differently to seccomp and pseudo-step traps
-	 *   (the latter do not nobble any registers).
-	 */
-	*regno = (is_compat_task() ? 12 : 7);
-	saved_reg = regs->regs[*regno];
-	regs->regs[*regno] = dir;
-
-	return saved_reg;
-}
-
-static int report_syscall_entry(struct pt_regs *regs)
-{
-	unsigned long saved_reg;
-	int regno, ret;
-
-	saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_ENTER, &regno);
-	ret = ptrace_report_syscall_entry(regs);
-	if (ret)
-		forget_syscall(regs);
-	regs->regs[regno] = saved_reg;
-
-	return ret;
-}
-
-static void report_syscall_exit(struct pt_regs *regs)
-{
-	unsigned long saved_reg;
-	int regno;
-
-	saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_EXIT, &regno);
-	if (!test_thread_flag(TIF_SINGLESTEP)) {
-		ptrace_report_syscall_exit(regs, 0);
-		regs->regs[regno] = saved_reg;
-	} else {
-		regs->regs[regno] = saved_reg;
-
-		/*
-		 * Signal a pseudo-step exception since we are stepping but
-		 * tracer modifications to the registers may have rewound the
-		 * state machine.
-		 */
-		ptrace_report_syscall_exit(regs, 1);
-	}
-}
-
-static inline void syscall_enter_audit(struct pt_regs *regs, long syscall)
-{
-	if (unlikely(audit_context())) {
-		unsigned long args[6];
-
-		syscall_get_arguments(current, regs, args);
-		audit_syscall_entry(syscall, args[0], args[1], args[2], args[3]);
-	}
-}
-
-int syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long flags)
-{
-	int ret;
-
-	if (flags & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE)) {
-		ret = report_syscall_entry(regs);
-		if (ret || (flags & _TIF_SYSCALL_EMU))
-			return NO_SYSCALL;
-	}
-
-	/* Do the secure computing after ptrace; failures should be fast. */
-	if (flags & _TIF_SECCOMP) {
-		ret = __secure_computing();
-		if (ret == -1)
-			return NO_SYSCALL;
-	}
-
-	/* Either of the above might have changed the syscall number */
-	syscall = syscall_get_nr(current, regs);
-
-	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) {
-		trace_sys_enter(regs, syscall);
-
-		/*
-		 * Probes or BPF hooks in the tracepoint may have changed the
-		 * system call number as well.
-		 */
-		 syscall = syscall_get_nr(current, regs);
-	}
-
-	syscall_enter_audit(regs, syscall);
-
-	return ret ? : syscall;
-}
-
-static inline bool report_single_step(unsigned long flags)
-{
-	if (flags & _TIF_SYSCALL_EMU)
-		return false;
-
-	return flags & _TIF_SINGLESTEP;
-}
-
-static void syscall_exit_work(struct pt_regs *regs, unsigned long flags)
-{
-	bool step;
-
-	audit_syscall_exit(regs);
-
-	if (flags & _TIF_SYSCALL_TRACEPOINT)
-		trace_sys_exit(regs, syscall_get_return_value(current, regs));
-
-	step = report_single_step(flags);
-	if (step || flags & _TIF_SYSCALL_TRACE)
-		report_syscall_exit(regs);
-}
-
-void syscall_exit_to_user_mode_work_prepare(struct pt_regs *regs)
-{
-	unsigned long flags = read_thread_flags();
-
-	rseq_syscall(regs);
-
-	if (unlikely(flags & _TIF_SYSCALL_EXIT_WORK) || flags & _TIF_SINGLESTEP)
-		syscall_exit_work(regs, flags);
-}
-
 /*
  * SPSR_ELx bits which are always architecturally RES0 per ARM DDI 0487D.a.
  * We permit userspace to set SSBS (AArch64 bit 12, AArch32 bit 23) which is
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 1110eeb21f57..d3ec1892b3c7 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -8,8 +8,8 @@
 
 #include <linux/cache.h>
 #include <linux/compat.h>
+#include <linux/entry-common.h>
 #include <linux/errno.h>
-#include <linux/irq-entry-common.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/freezer.h>
diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index 80b7fd67492e..c440ccb2af62 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -2,6 +2,7 @@
 
 #include <linux/compiler.h>
 #include <linux/context_tracking.h>
+#include <linux/entry-common.h>
 #include <linux/errno.h>
 #include <linux/nospec.h>
 #include <linux/ptrace.h>
@@ -68,6 +69,7 @@ static void invoke_syscall(struct pt_regs *regs, unsigned int scno,
 static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 			   const syscall_fn_t syscall_table[])
 {
+	unsigned long work = READ_ONCE(current_thread_info()->syscall_work);
 	unsigned long flags = read_thread_flags();
 
 	regs->orig_x0 = regs->regs[0];
@@ -101,7 +103,7 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 		return;
 	}
 
-	if (unlikely(flags & _TIF_SYSCALL_WORK)) {
+	if (unlikely(work & SYSCALL_WORK_ENTER)) {
 		/*
 		 * The de-facto standard way to skip a system call using ptrace
 		 * is to set the system call to -1 (NO_SYSCALL) and set x0 to a
@@ -119,7 +121,7 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 		 */
 		if (scno == NO_SYSCALL)
 			syscall_set_return_value(current, regs, -ENOSYS, 0);
-		scno = syscall_trace_enter(regs, scno, flags);
+		scno = syscall_trace_enter(regs, scno, work);
 		if (scno == NO_SYSCALL)
 			goto trace_exit;
 	}
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Dec 22 03:47:35 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 22 Dec 2025 19:47:35 +0800
Subject: [PATCH v10 14/16] arm64: Inline el0_svc_common()
In-Reply-To: <20251222114737.1334364-1-ruanjinjie@huawei.com>
References: <20251222114737.1334364-1-ruanjinjie@huawei.com>
Message-ID: <20251222114737.1334364-15-ruanjinjie@huawei.com>

After switch arm64 to Generic Entry, the compiler no longer inlines
el0_svc_common() into do_el0_svc(). So inline el0_svc_common() and it
has 1% performance uplift on perf bench basic syscall on kunpeng920
as below.

| Metric     | W/O this patch | With this patch | Change    |
| ---------- | -------------- | --------------- | --------- |
| Total time | 2.195 [sec]    | 2.171 [sec]     |  ?1.1%   |
| usecs/op   | 0.219575       | 0.217192        |  ?1.1%   |
| ops/sec    | 4,554,260      | 4,604,225       |  ?1.1%    |

Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/kernel/syscall.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index c440ccb2af62..45ceb8c4316a 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -66,8 +66,8 @@ static void invoke_syscall(struct pt_regs *regs, unsigned int scno,
 	choose_random_kstack_offset(get_random_u16());
 }
 
-static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
-			   const syscall_fn_t syscall_table[])
+static __always_inline void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
+					   const syscall_fn_t syscall_table[])
 {
 	unsigned long work = READ_ONCE(current_thread_info()->syscall_work);
 	unsigned long flags = read_thread_flags();
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Dec 22 03:47:36 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 22 Dec 2025 19:47:36 +0800
Subject: [PATCH v10 15/16] entry: Inline syscall_exit_work() and syscall_trace_enter()
In-Reply-To: <20251222114737.1334364-1-ruanjinjie@huawei.com>
References: <20251222114737.1334364-1-ruanjinjie@huawei.com>
Message-ID: <20251222114737.1334364-16-ruanjinjie@huawei.com>

After switch arm64 to Generic Entry, a new hotspot syscall_exit_work()
appeared because syscall_exit_work() is not inlined, so inline
syscall_exit_work(). Also inline syscall_trace_enter() to align with
syscall_exit_work().

On v6.19-rc1 with audit on, inline both syscall_trace_enter() and
syscall_exit_work() has 4% performance uplift on perf bench basic
syscall on kunpeng920 as below:

    | Metric     | W/O this patch | With this patch | Change  |
    | ---------- | -------------- | --------------- | ------  |
    | Total time | 2.353 [sec]    | 2.264 [sec]     |  ?3.8%  |
    | usecs/op   | 0.235374       | 0.226472        |  ?3.8%  |
    | ops/sec    | 4,248,588      | 4,415,554       |  ?3.9%  |

Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 include/linux/entry-common.h         | 102 ++++++++++++++++++++++++++-
 kernel/entry/common.h                |   7 --
 kernel/entry/syscall-common.c        |  96 ++-----------------------
 kernel/entry/syscall_user_dispatch.c |   4 +-
 4 files changed, 106 insertions(+), 103 deletions(-)
 delete mode 100644 kernel/entry/common.h

diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h
index 17171e8873fc..ad61a13bf24f 100644
--- a/include/linux/entry-common.h
+++ b/include/linux/entry-common.h
@@ -2,6 +2,7 @@
 #ifndef __LINUX_ENTRYCOMMON_H
 #define __LINUX_ENTRYCOMMON_H
 
+#include <linux/audit.h>
 #include <linux/irq-entry-common.h>
 #include <linux/livepatch.h>
 #include <linux/ptrace.h>
@@ -64,7 +65,64 @@ static __always_inline int arch_ptrace_report_syscall_entry(struct pt_regs *regs
 }
 #endif
 
-long syscall_trace_enter(struct pt_regs *regs, long syscall, unsigned long work);
+static inline void syscall_enter_audit(struct pt_regs *regs, long syscall)
+{
+	if (unlikely(audit_context())) {
+		unsigned long args[6];
+
+		syscall_get_arguments(current, regs, args);
+		audit_syscall_entry(syscall, args[0], args[1], args[2], args[3]);
+	}
+}
+
+void __trace_sys_enter(struct pt_regs *regs, long syscall);
+bool syscall_user_dispatch(struct pt_regs *regs);
+
+static __always_inline long syscall_trace_enter(struct pt_regs *regs, long syscall,
+						unsigned long work)
+{
+	long ret = 0;
+
+	/*
+	 * Handle Syscall User Dispatch.  This must comes first, since
+	 * the ABI here can be something that doesn't make sense for
+	 * other syscall_work features.
+	 */
+	if (work & SYSCALL_WORK_SYSCALL_USER_DISPATCH) {
+		if (syscall_user_dispatch(regs))
+			return -1L;
+	}
+
+	/* Handle ptrace */
+	if (work & (SYSCALL_WORK_SYSCALL_TRACE | SYSCALL_WORK_SYSCALL_EMU)) {
+		ret = arch_ptrace_report_syscall_entry(regs);
+		if (ret || (work & SYSCALL_WORK_SYSCALL_EMU))
+			return -1L;
+	}
+
+	/* Do seccomp after ptrace, to catch any tracer changes. */
+	if (work & SYSCALL_WORK_SECCOMP) {
+		ret = __secure_computing();
+		if (ret == -1L)
+			return ret;
+	}
+
+	/* Either of the above might have changed the syscall number */
+	syscall = syscall_get_nr(current, regs);
+
+	if (unlikely(work & SYSCALL_WORK_SYSCALL_TRACEPOINT)) {
+		__trace_sys_enter(regs, syscall);
+		/*
+		 * Probes or BPF hooks in the tracepoint may have changed the
+		 * system call number as well.
+		 */
+		syscall = syscall_get_nr(current, regs);
+	}
+
+	syscall_enter_audit(regs, syscall);
+
+	return ret ? : syscall;
+}
 
 /**
  * syscall_enter_from_user_mode_work - Check and handle work before invoking
@@ -131,6 +189,19 @@ static __always_inline long syscall_enter_from_user_mode(struct pt_regs *regs, l
 	return ret;
 }
 
+/*
+ * If SYSCALL_EMU is set, then the only reason to report is when
+ * SINGLESTEP is set (i.e. PTRACE_SYSEMU_SINGLESTEP).  This syscall
+ * instruction has been already reported in syscall_enter_from_user_mode().
+ */
+static __always_inline bool report_single_step(unsigned long work)
+{
+	if (work & SYSCALL_WORK_SYSCALL_EMU)
+		return false;
+
+	return work & SYSCALL_WORK_SYSCALL_EXIT_TRAP;
+}
+
 /**
  * arch_ptrace_report_syscall_exit - Architecture specific
  *				     ptrace_report_syscall_exit.
@@ -151,6 +222,8 @@ static __always_inline void arch_ptrace_report_syscall_exit(struct pt_regs *regs
 }
 #endif
 
+void __trace_sys_exit(struct pt_regs *regs, long ret);
+
 /**
  * syscall_exit_work - Handle work before returning to user mode
  * @regs:	Pointer to current pt_regs
@@ -158,7 +231,32 @@ static __always_inline void arch_ptrace_report_syscall_exit(struct pt_regs *regs
  *
  * Do one-time syscall specific work.
  */
-void syscall_exit_work(struct pt_regs *regs, unsigned long work);
+static __always_inline void syscall_exit_work(struct pt_regs *regs, unsigned long work)
+{
+	bool step;
+
+	/*
+	 * If the syscall was rolled back due to syscall user dispatching,
+	 * then the tracers below are not invoked for the same reason as
+	 * the entry side was not invoked in syscall_trace_enter(): The ABI
+	 * of these syscalls is unknown.
+	 */
+	if (work & SYSCALL_WORK_SYSCALL_USER_DISPATCH) {
+		if (unlikely(current->syscall_dispatch.on_dispatch)) {
+			current->syscall_dispatch.on_dispatch = false;
+			return;
+		}
+	}
+
+	audit_syscall_exit(regs);
+
+	if (work & SYSCALL_WORK_SYSCALL_TRACEPOINT)
+		__trace_sys_exit(regs, syscall_get_return_value(current, regs));
+
+	step = report_single_step(work);
+	if (step || work & SYSCALL_WORK_SYSCALL_TRACE)
+		arch_ptrace_report_syscall_exit(regs, step);
+}
 
 /*
  * Syscall specific exit to user mode preparation. Runs with interrupts
diff --git a/kernel/entry/common.h b/kernel/entry/common.h
deleted file mode 100644
index f6e6d02f07fe..000000000000
--- a/kernel/entry/common.h
+++ /dev/null
@@ -1,7 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _COMMON_H
-#define _COMMON_H
-
-bool syscall_user_dispatch(struct pt_regs *regs);
-
-#endif
diff --git a/kernel/entry/syscall-common.c b/kernel/entry/syscall-common.c
index fe38f84dfff3..10231d30405e 100644
--- a/kernel/entry/syscall-common.c
+++ b/kernel/entry/syscall-common.c
@@ -1,104 +1,16 @@
 // SPDX-License-Identifier: GPL-2.0
 
-#include <linux/audit.h>
 #include <linux/entry-common.h>
-#include "common.h"
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/syscalls.h>
 
-static inline void syscall_enter_audit(struct pt_regs *regs, long syscall)
+void __trace_sys_enter(struct pt_regs *regs, long syscall)
 {
-	if (unlikely(audit_context())) {
-		unsigned long args[6];
-
-		syscall_get_arguments(current, regs, args);
-		audit_syscall_entry(syscall, args[0], args[1], args[2], args[3]);
-	}
+	trace_sys_enter(regs, syscall);
 }
 
-long syscall_trace_enter(struct pt_regs *regs, long syscall,
-				unsigned long work)
+void __trace_sys_exit(struct pt_regs *regs, long ret)
 {
-	long ret = 0;
-
-	/*
-	 * Handle Syscall User Dispatch.  This must comes first, since
-	 * the ABI here can be something that doesn't make sense for
-	 * other syscall_work features.
-	 */
-	if (work & SYSCALL_WORK_SYSCALL_USER_DISPATCH) {
-		if (syscall_user_dispatch(regs))
-			return -1L;
-	}
-
-	/* Handle ptrace */
-	if (work & (SYSCALL_WORK_SYSCALL_TRACE | SYSCALL_WORK_SYSCALL_EMU)) {
-		ret = arch_ptrace_report_syscall_entry(regs);
-		if (ret || (work & SYSCALL_WORK_SYSCALL_EMU))
-			return -1L;
-	}
-
-	/* Do seccomp after ptrace, to catch any tracer changes. */
-	if (work & SYSCALL_WORK_SECCOMP) {
-		ret = __secure_computing();
-		if (ret == -1L)
-			return ret;
-	}
-
-	/* Either of the above might have changed the syscall number */
-	syscall = syscall_get_nr(current, regs);
-
-	if (unlikely(work & SYSCALL_WORK_SYSCALL_TRACEPOINT)) {
-		trace_sys_enter(regs, syscall);
-		/*
-		 * Probes or BPF hooks in the tracepoint may have changed the
-		 * system call number as well.
-		 */
-		syscall = syscall_get_nr(current, regs);
-	}
-
-	syscall_enter_audit(regs, syscall);
-
-	return ret ? : syscall;
-}
-
-/*
- * If SYSCALL_EMU is set, then the only reason to report is when
- * SINGLESTEP is set (i.e. PTRACE_SYSEMU_SINGLESTEP).  This syscall
- * instruction has been already reported in syscall_enter_from_user_mode().
- */
-static inline bool report_single_step(unsigned long work)
-{
-	if (work & SYSCALL_WORK_SYSCALL_EMU)
-		return false;
-
-	return work & SYSCALL_WORK_SYSCALL_EXIT_TRAP;
-}
-
-void syscall_exit_work(struct pt_regs *regs, unsigned long work)
-{
-	bool step;
-
-	/*
-	 * If the syscall was rolled back due to syscall user dispatching,
-	 * then the tracers below are not invoked for the same reason as
-	 * the entry side was not invoked in syscall_trace_enter(): The ABI
-	 * of these syscalls is unknown.
-	 */
-	if (work & SYSCALL_WORK_SYSCALL_USER_DISPATCH) {
-		if (unlikely(current->syscall_dispatch.on_dispatch)) {
-			current->syscall_dispatch.on_dispatch = false;
-			return;
-		}
-	}
-
-	audit_syscall_exit(regs);
-
-	if (work & SYSCALL_WORK_SYSCALL_TRACEPOINT)
-		trace_sys_exit(regs, syscall_get_return_value(current, regs));
-
-	step = report_single_step(work);
-	if (step || work & SYSCALL_WORK_SYSCALL_TRACE)
-		arch_ptrace_report_syscall_exit(regs, step);
+	trace_sys_exit(regs, ret);
 }
diff --git a/kernel/entry/syscall_user_dispatch.c b/kernel/entry/syscall_user_dispatch.c
index a9055eccb27e..d89dffcc2d64 100644
--- a/kernel/entry/syscall_user_dispatch.c
+++ b/kernel/entry/syscall_user_dispatch.c
@@ -2,6 +2,8 @@
 /*
  * Copyright (C) 2020 Collabora Ltd.
  */
+
+#include <linux/entry-common.h>
 #include <linux/sched.h>
 #include <linux/prctl.h>
 #include <linux/ptrace.h>
@@ -15,8 +17,6 @@
 
 #include <asm/syscall.h>
 
-#include "common.h"
-
 static void trigger_sigsys(struct pt_regs *regs)
 {
 	struct kernel_siginfo info;
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Dec 22 03:47:37 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 22 Dec 2025 19:47:37 +0800
Subject: [PATCH v10 16/16] selftests: sud_test: Support aarch64
In-Reply-To: <20251222114737.1334364-1-ruanjinjie@huawei.com>
References: <20251222114737.1334364-1-ruanjinjie@huawei.com>
Message-ID: <20251222114737.1334364-17-ruanjinjie@huawei.com>

From: kemal <kmal at cock.li>

Support aarch64 to test "Syscall User Dispatch" with sud_test
selftest testcase.

Signed-off-by: kemal <kmal at cock.li>
---
 tools/testing/selftests/syscall_user_dispatch/sud_benchmark.c | 2 +-
 tools/testing/selftests/syscall_user_dispatch/sud_test.c      | 4 ++++
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/syscall_user_dispatch/sud_benchmark.c b/tools/testing/selftests/syscall_user_dispatch/sud_benchmark.c
index 073a03702ff5..6059abe75cb3 100644
--- a/tools/testing/selftests/syscall_user_dispatch/sud_benchmark.c
+++ b/tools/testing/selftests/syscall_user_dispatch/sud_benchmark.c
@@ -41,7 +41,7 @@
  * out of the box, but don't enable them until they support syscall user
  * dispatch.
  */
-#if defined(__x86_64__) || defined(__i386__)
+#if defined(__x86_64__) || defined(__i386__) || defined(__aarch64__)
 #define TEST_BLOCKED_RETURN
 #endif
 
diff --git a/tools/testing/selftests/syscall_user_dispatch/sud_test.c b/tools/testing/selftests/syscall_user_dispatch/sud_test.c
index b855c6000287..3ffea2f4a66d 100644
--- a/tools/testing/selftests/syscall_user_dispatch/sud_test.c
+++ b/tools/testing/selftests/syscall_user_dispatch/sud_test.c
@@ -192,6 +192,10 @@ static void handle_sigsys(int sig, siginfo_t *info, void *ucontext)
 	((ucontext_t *)ucontext)->uc_mcontext.__gregs[REG_A0] =
 			((ucontext_t *)ucontext)->uc_mcontext.__gregs[REG_A7];
 #endif
+#ifdef __aarch64__
+	((ucontext_t *)ucontext)->uc_mcontext.regs[0] = (unsigned int)
+			((ucontext_t *)ucontext)->uc_mcontext.regs[8];
+#endif
 }
 
 int setup_sigsys_handler(void)
-- 
2.34.1



From krzk at kernel.org  Mon Dec 22 03:50:10 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 22 Dec 2025 12:50:10 +0100
Subject: [PATCH v7 0/4] Implement hardware automatic clock gating (HWACG)
 for gs101
In-Reply-To: <20251222-automatic-clocks-v7-0-fec86fa89874@linaro.org>
References: <20251222-automatic-clocks-v7-0-fec86fa89874@linaro.org>
Message-ID: <c0eeae31-6951-47ca-8651-868db18d349e@kernel.org>

On 22/12/2025 11:22, Peter Griffin wrote:
> Hi folks,
> 
> This series addresses an issue with Samsung Exynos based upstream clock driver
> whereby the upstream clock driver sets all the clock gates into "manual mode"
> (which uses a bit that is documented as reserved in the gate registers).
> 

Applied. There were several checkpatch notices/less important warnings
of which most were result of existing code but few were introduced.
Please be sure you do not introduce new warnings NEXT TIME.

Also, DTS cannot be in the middle of the patchset. It's almost always
wrong, like in this case as well. This was raised, also by me, multiple
times on the lists and it is explicitly documented in submitting
patches. Putting it in the middle suggests you try to fix up broken
unbisectable things by reordering patches, but you cannot. Things will
be broken anyway, because DTS ALWAYS goes separate (also documented in
maintainers profile).

Best regards,
Krzysztof


From krzk at kernel.org  Mon Dec 22 03:50:33 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 22 Dec 2025 12:50:33 +0100
Subject: (subset) [PATCH v7 0/4] Implement hardware automatic clock
 gating (HWACG) for gs101
In-Reply-To: <20251222-automatic-clocks-v7-0-fec86fa89874@linaro.org>
References: <20251222-automatic-clocks-v7-0-fec86fa89874@linaro.org>
Message-ID: <176640423317.47079.9046133168071940495.b4-ty@kernel.org>


On Mon, 22 Dec 2025 10:22:11 +0000, Peter Griffin wrote:
> This series addresses an issue with Samsung Exynos based upstream clock driver
> whereby the upstream clock driver sets all the clock gates into "manual mode"
> (which uses a bit that is documented as reserved in the gate registers).
> 
> Another issue with the current "manual clock gating" approach upstream is
> there are many bus/interconnect clocks whose relationships to the IPs
> are not well documented or defined in the specs. When adding a new CMU until
> now we have tried to label these clocks appropriately with CLK_IS_CRITICAL and
> CLK_IGNORE_UNUSED but doing so is both error prone and time consuming. If
> your lucky disabling a critical bus clock causes an immediate hang. Other
> clocks however aren't so obvious and show up through random instability
> some period of time later.
> 
> [...]

Applied, thanks!

[2/4] arm64: dts: exynos: gs101: add samsung,sysreg property to CMU nodes
      https://git.kernel.org/krzk/linux/c/01272f05aae5f6aca4337eb52e6b9290ce12e9f7

Best regards,
-- 
Krzysztof Kozlowski <krzk at kernel.org>



From heiko at sntech.de  Mon Dec 22 03:50:07 2025
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 22 Dec 2025 12:50:07 +0100
Subject: [PATCH 3/3] iio: adc: rockchip: Simplify probe() with local 'dev'
In-Reply-To: <20251221142602.47368-6-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251221142602.47368-4-krzysztof.kozlowski@oss.qualcomm.com>
 <20251221142602.47368-6-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <5782401.ejJDZkT8p0@phil>

Am Sonntag, 21. Dezember 2025, 15:26:05 Mitteleurop?ische Normalzeit schrieb Krzysztof Kozlowski:
> Simplify the probe function by using a local 'dev' variable instead of
> full pointer dereference.  This makes several lines shorter, which
> allows to avoid wrapping making code more readable.
> 
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Yep, makes the code definitly nicer to read

Reviewed-by: Heiko Stuebner <heiko at sntech.de>




From krzk at kernel.org  Mon Dec 22 03:51:03 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 22 Dec 2025 12:51:03 +0100
Subject: (subset) [PATCH v7 0/4] Implement hardware automatic clock gating
 (HWACG) for gs101
In-Reply-To: <176640423317.47079.9046133168071940495.b4-ty@kernel.org>
References: <20251222-automatic-clocks-v7-0-fec86fa89874@linaro.org>
 <176640423317.47079.9046133168071940495.b4-ty@kernel.org>
Message-ID: <4fff2e56-600e-49a8-b993-aa7fa50f7fdf@kernel.org>

On 22/12/2025 12:50, Krzysztof Kozlowski wrote:
> 
> On Mon, 22 Dec 2025 10:22:11 +0000, Peter Griffin wrote:
>> This series addresses an issue with Samsung Exynos based upstream clock driver
>> whereby the upstream clock driver sets all the clock gates into "manual mode"
>> (which uses a bit that is documented as reserved in the gate registers).
>>
>> Another issue with the current "manual clock gating" approach upstream is
>> there are many bus/interconnect clocks whose relationships to the IPs
>> are not well documented or defined in the specs. When adding a new CMU until
>> now we have tried to label these clocks appropriately with CLK_IS_CRITICAL and
>> CLK_IGNORE_UNUSED but doing so is both error prone and time consuming. If
>> your lucky disabling a critical bus clock causes an immediate hang. Other
>> clocks however aren't so obvious and show up through random instability
>> some period of time later.
>>
>> [...]
> 
> Applied, thanks!
> 
> [2/4] arm64: dts: exynos: gs101: add samsung,sysreg property to CMU nodes
>       https://git.kernel.org/krzk/linux/c/01272f05aae5f6aca4337eb52e6b9290ce12e9f7
> 

Above is incomplete, all applied.

Best regards,
Krzysztof


From billy_tsai at aspeedtech.com  Mon Dec 22 04:04:25 2025
From: billy_tsai at aspeedtech.com (Billy Tsai)
Date: Mon, 22 Dec 2025 20:04:25 +0800
Subject: [PATCH 0/3] pinctrl: single: bit-per-mux DT flexibility, probe
 robustness, and consistent pinconf offsets
Message-ID: <20251222-upstream_pinctrl_single-v1-0-e4aaa4eeb936@aspeedtech.com>

This series updates pinctrl-single to behave more predictably on
bit-per-mux platforms by making its DT interface more flexible, its probe
path more tolerant of pre-reserved resources, and its pin configuration
register addressing consistent with pinmux.
It extends the driver to accept a per-pin <pin_index func_sel> style
description for bit-per-mux users while keeping the existing
pinctrl-single,bits binding as the preferred input when available. It also
relaxes probe failure when the I/O memory region cannot be reserved
exclusively, allowing initialization to proceed with a warning on systems
where that region is already reserved. Finally, it aligns pinconf register
offset computation with the pinmux logic so that both muxing and pin
configuration access the same register offsets, avoiding incorrect pinconf
operations on bit-per-mux configurations.

Signed-off-by: Billy Tsai <billy_tsai at aspeedtech.com>
---
Billy Tsai (3):
      pinctrl: single: add per-pin binding support for bit-per-mux
      pinctrl: single: Allow probe to continue if mem region busy
      pinctrl: single: unify pinconf offset mapping with pinmux

 drivers/pinctrl/pinctrl-single.c | 150 ++++++++++++++++++++++++++++-----------
 1 file changed, 110 insertions(+), 40 deletions(-)
---
base-commit: dd9b004b7ff3289fb7bae35130c0a5c0537266af
change-id: 20251222-upstream_pinctrl_single-99e8df1fe2b9

Best regards,
-- 
Billy Tsai <billy_tsai at aspeedtech.com>



From billy_tsai at aspeedtech.com  Mon Dec 22 04:04:26 2025
From: billy_tsai at aspeedtech.com (Billy Tsai)
Date: Mon, 22 Dec 2025 20:04:26 +0800
Subject: [PATCH 1/3] pinctrl: single: add per-pin binding support for
 bit-per-mux
In-Reply-To: <20251222-upstream_pinctrl_single-v1-0-e4aaa4eeb936@aspeedtech.com>
References: <20251222-upstream_pinctrl_single-v1-0-e4aaa4eeb936@aspeedtech.com>
Message-ID: <20251222-upstream_pinctrl_single-v1-1-e4aaa4eeb936@aspeedtech.com>

Add support for binding where bit-per-mux users specify pins as
<pin_index func_sel> pairs. Prefer explicit bits binding when present,
but fall back to the new per-pin binding for improved flexibility.
This approach is intended to adapt to hardware with a regular register
layout, where pin functions are arranged with a fixed stride. For example,
the function of pin 0 is controlled by bits [3:0] at offset 0, the
function of pin 1 by bits [7:4] at the same offset, and so on.

Signed-off-by: Billy Tsai <billy_tsai at aspeedtech.com>
---
 drivers/pinctrl/pinctrl-single.c | 132 +++++++++++++++++++++++++++++----------
 1 file changed, 100 insertions(+), 32 deletions(-)

diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 998f23d6c317..757c22cc09f3 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -1041,29 +1041,81 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
 			break;
 		}
 
-		offset = pinctrl_spec.args[0];
-		vals[found].reg = pcs->base + offset;
+		/*
+		 * For legacy (non bit-per-mux) users the first cell is the
+		 * register offset and the second (and optional third) cell is
+		 * the value to be written.
+		 *
+		 * For bit-per-mux users we want a simpler binding where the
+		 * first cell is the pin index and the second cell is the
+		 * function selector. Translate that into register offset,
+		 * value and mask here so the rest of the driver can stay
+		 * Register based.
+		 */
+		if (!pcs->bits_per_mux) {
+			offset = pinctrl_spec.args[0];
+			vals[found].reg = pcs->base + offset;
 
-		switch (pinctrl_spec.args_count) {
-		case 2:
-			vals[found].val = pinctrl_spec.args[1];
-			break;
-		case 3:
-			vals[found].val = (pinctrl_spec.args[1] | pinctrl_spec.args[2]);
-			break;
-		}
+			switch (pinctrl_spec.args_count) {
+			case 2:
+				vals[found].val = pinctrl_spec.args[1];
+				break;
+			case 3:
+				vals[found].val = (pinctrl_spec.args[1] |
+						   pinctrl_spec.args[2]);
+				break;
+			}
 
-		dev_dbg(pcs->dev, "%pOFn index: 0x%x value: 0x%x\n",
-			pinctrl_spec.np, offset, vals[found].val);
+			dev_dbg(pcs->dev, "%pOFn offset: 0x%x value: 0x%x\n",
+				 pinctrl_spec.np, offset, vals[found].val);
 
-		pin = pcs_get_pin_by_offset(pcs, offset);
-		if (pin < 0) {
-			dev_err(pcs->dev,
-				"could not add functions for %pOFn %ux\n",
-				np, offset);
-			break;
+			pin = pcs_get_pin_by_offset(pcs, offset);
+			if (pin < 0) {
+				dev_err(pcs->dev,
+					"could not add functions for %pOFn %ux\n",
+					np, offset);
+				break;
+			}
+			pins[found++] = pin;
+		} else {
+			unsigned int pin_index, func_sel;
+			unsigned int shift, mask, val;
+
+			/* Expect <pin_index func_sel> for bit-per-mux users. */
+			if (pinctrl_spec.args_count < 2) {
+				dev_err(pcs->dev,
+					"invalid args_count for bit-per-mux spec: %i\n",
+					pinctrl_spec.args_count);
+				break;
+			}
+
+			pin_index = pinctrl_spec.args[0];
+			func_sel = pinctrl_spec.args[1];
+
+			if (pin_index >= pcs->desc.npins) {
+				dev_err(pcs->dev,
+					"pin index out of range for %pOFn: %u (npins %u)\n",
+					np, pin_index, pcs->desc.npins);
+				break;
+			}
+
+			offset = pcs_pin_reg_offset_get(pcs, pin_index);
+			shift = pcs_pin_shift_reg_get(pcs, pin_index);
+
+			mask = pcs->fmask << shift;
+			val = (func_sel << shift) & mask;
+
+			vals[found].reg = pcs->base + offset;
+			vals[found].val = val;
+			vals[found].mask = mask;
+
+			dev_dbg(pcs->dev,
+				 "%pOFn pin: %u offset: 0x%x func: 0x%x val: 0x%x mask: 0x%x\n",
+				 pinctrl_spec.np, pin_index, offset,
+				 func_sel, val, mask);
+
+			pins[found++] = pin_index;
 		}
-		pins[found++] = pin;
 	}
 
 	pgnames[0] = np->name;
@@ -1280,21 +1332,37 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev,
 	}
 
 	if (pcs->bits_per_mux) {
-		ret = pcs_parse_bits_in_pinctrl_entry(pcs, np_config, map,
-				num_maps, pgnames);
-		if (ret < 0) {
-			dev_err(pcs->dev, "no pins entries for %pOFn\n",
-				np_config);
-			goto free_pgnames;
+		/*
+		 * For bit-per-mux users there are two possible bindings:
+		 * - pinctrl-single,bits: offset/value/mask triples
+		 * - pinctrl-single,pins: <pin_index func_sel> pairs
+		 *
+		 * Prefer the explicit bits binding when present so existing
+		 * users keep their current behaviour, otherwise fall back
+		 * to the per-pin binding.
+		 */
+		if (of_find_property(np_config, "pinctrl-single,bits", NULL)) {
+			ret = pcs_parse_bits_in_pinctrl_entry(pcs, np_config,
+							      map, num_maps,
+							      pgnames);
+		} else if (of_find_property(np_config,
+					    "pinctrl-single,pins", NULL)) {
+			ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map,
+							  num_maps, pgnames);
+		} else {
+			ret = -EINVAL;
 		}
 	} else {
-		ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map,
-				num_maps, pgnames);
-		if (ret < 0) {
-			dev_err(pcs->dev, "no pins entries for %pOFn\n",
-				np_config);
-			goto free_pgnames;
-		}
+		if (of_find_property(np_config, "pinctrl-single,pins", NULL))
+			ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map,
+							  num_maps, pgnames);
+		else
+			ret = -EINVAL;
+	}
+
+	if (ret < 0) {
+		dev_err(pcs->dev, "no pins entries for %pOFn\n", np_config);
+		goto free_pgnames;
 	}
 
 	return 0;

-- 
2.34.1



From billy_tsai at aspeedtech.com  Mon Dec 22 04:04:27 2025
From: billy_tsai at aspeedtech.com (Billy Tsai)
Date: Mon, 22 Dec 2025 20:04:27 +0800
Subject: [PATCH 2/3] pinctrl: single: Allow probe to continue if mem region
 busy
In-Reply-To: <20251222-upstream_pinctrl_single-v1-0-e4aaa4eeb936@aspeedtech.com>
References: <20251222-upstream_pinctrl_single-v1-0-e4aaa4eeb936@aspeedtech.com>
Message-ID: <20251222-upstream_pinctrl_single-v1-2-e4aaa4eeb936@aspeedtech.com>

Skip exclusive memory region reservation failure during probe and
continue initialization with a warning. This enables support for
systems where the memory region may already be reserved, improving
probe robustness.

Signed-off-by: Billy Tsai <billy_tsai at aspeedtech.com>
---
 drivers/pinctrl/pinctrl-single.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 757c22cc09f3..e65ae737b4c5 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -1910,13 +1910,13 @@ static int pcs_probe(struct platform_device *pdev)
 
 	pcs->res = devm_request_mem_region(pcs->dev, res->start,
 			resource_size(res), DRIVER_NAME);
-	if (!pcs->res) {
-		dev_err(pcs->dev, "could not get mem_region\n");
-		return -EBUSY;
-	}
+	if (!pcs->res)
+		dev_warn(pcs->dev, "mem_region busy, continuing without reservation\n");
+	else
+		res = pcs->res;
 
-	pcs->size = resource_size(pcs->res);
-	pcs->base = devm_ioremap(pcs->dev, pcs->res->start, pcs->size);
+	pcs->size = resource_size(res);
+	pcs->base = devm_ioremap(pcs->dev, res->start, pcs->size);
 	if (!pcs->base) {
 		dev_err(pcs->dev, "could not ioremap\n");
 		return -ENODEV;

-- 
2.34.1



From billy_tsai at aspeedtech.com  Mon Dec 22 04:04:28 2025
From: billy_tsai at aspeedtech.com (Billy Tsai)
Date: Mon, 22 Dec 2025 20:04:28 +0800
Subject: [PATCH 3/3] pinctrl: single: unify pinconf offset mapping with
 pinmux
In-Reply-To: <20251222-upstream_pinctrl_single-v1-0-e4aaa4eeb936@aspeedtech.com>
References: <20251222-upstream_pinctrl_single-v1-0-e4aaa4eeb936@aspeedtech.com>
Message-ID: <20251222-upstream_pinctrl_single-v1-3-e4aaa4eeb936@aspeedtech.com>

Use the same register offset calculation for pinconf as pinmux to
properly handle bit-per-mux configurations. Ensures consistent and
correct offset mapping for pin configuration operations.

Signed-off-by: Billy Tsai <billy_tsai at aspeedtech.com>
---
 drivers/pinctrl/pinctrl-single.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index e65ae737b4c5..aaf830315c5d 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -505,7 +505,8 @@ static int pcs_pinconf_get(struct pinctrl_dev *pctldev,
 			continue;
 		}
 
-		offset = pin * (pcs->width / BITS_PER_BYTE);
+		/* Use the same offset mapping as pinmux (handles bit-per-mux) */
+		offset = pcs_pin_reg_offset_get(pcs, pin);
 		data = pcs->read(pcs->base + offset) & func->conf[i].mask;
 		switch (func->conf[i].param) {
 		/* 4 parameters */
@@ -573,7 +574,8 @@ static int pcs_pinconf_set(struct pinctrl_dev *pctldev,
 			if (param != func->conf[i].param)
 				continue;
 
-			offset = pin * (pcs->width / BITS_PER_BYTE);
+			/* Use the same offset mapping as pinmux (handles bit-per-mux) */
+			offset = pcs_pin_reg_offset_get(pcs, pin);
 			data = pcs->read(pcs->base + offset);
 			arg = pinconf_to_config_argument(configs[j]);
 			switch (param) {

-- 
2.34.1



From lkp at intel.com  Mon Dec 22 04:11:06 2025
From: lkp at intel.com (kernel test robot)
Date: Mon, 22 Dec 2025 20:11:06 +0800
Subject: [PATCH v23 3/7] firmware: imx: add driver for NXP EdgeLock
 Enclave
In-Reply-To: <20251219-imx-se-if-v23-3-5c6773d00318@nxp.com>
References: <20251219-imx-se-if-v23-3-5c6773d00318@nxp.com>
Message-ID: <202512222045.Ldg7WTWR-lkp@intel.com>

Hi Pankaj,

kernel test robot noticed the following build errors:

[auto build test ERROR on 4a26e7032d7d57c998598c08a034872d6f0d3945]

url:    https://github.com/intel-lab-lkp/linux/commits/Pankaj-Gupta/Documentation-firmware-add-imx-se-to-other_interfaces/20251219-132830
base:   4a26e7032d7d57c998598c08a034872d6f0d3945
patch link:    https://lore.kernel.org/r/20251219-imx-se-if-v23-3-5c6773d00318%40nxp.com
patch subject: [PATCH v23 3/7] firmware: imx: add driver for NXP EdgeLock Enclave
config: arm-randconfig-r054-20251222 (https://download.01.org/0day-ci/archive/20251222/202512222045.Ldg7WTWR-lkp at intel.com/config)
compiler: clang version 19.1.7 (https://github.com/llvm/llvm-project cd708029e0b2869e80abe31ddb175f7c35361f90)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251222/202512222045.Ldg7WTWR-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512222045.Ldg7WTWR-lkp at intel.com/

All errors (new ones prefixed by >>):

>> drivers/firmware/imx/se_ctrl.c:343:9: error: incompatible pointer types passing 'phys_addr_t *' (aka 'unsigned int *') to parameter of type 'dma_addr_t *' (aka 'unsigned long long *') [-Werror,-Wincompatible-pointer-types]
     343 |                                                                 &load_fw->imem.phyaddr,
         |                                                                 ^~~~~~~~~~~~~~~~~~~~~~
   include/linux/dma-mapping.h:707:15: note: passing argument to parameter 'dma_handle' here
     707 |                 dma_addr_t *dma_handle, gfp_t gfp)
         |                             ^
   1 error generated.


vim +343 drivers/firmware/imx/se_ctrl.c

   266	
   267	static int se_if_probe(struct platform_device *pdev)
   268	{
   269		const struct se_soc_info *se_info;
   270		const struct se_if_node *if_node;
   271		struct se_fw_load_info *load_fw;
   272		struct device *dev = &pdev->dev;
   273		struct se_if_priv *priv;
   274		int ret;
   275	
   276		if_node = device_get_match_data(dev);
   277		if (!if_node)
   278			return -EINVAL;
   279	
   280		se_info = if_node->se_info;
   281	
   282		priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
   283		if (!priv)
   284			return -ENOMEM;
   285	
   286		priv->dev = dev;
   287		priv->if_defs = &if_node->if_defs;
   288		dev_set_drvdata(dev, priv);
   289	
   290		ret = devm_add_action_or_reset(dev, se_if_probe_cleanup, pdev);
   291		if (ret)
   292			return ret;
   293	
   294		/* Mailbox client configuration */
   295		priv->se_mb_cl.dev		= dev;
   296		priv->se_mb_cl.tx_block		= false;
   297		priv->se_mb_cl.knows_txdone	= true;
   298		priv->se_mb_cl.rx_callback	= se_if_rx_callback;
   299	
   300		ret = se_if_request_channel(dev, &priv->tx_chan, &priv->se_mb_cl, MBOX_TX_NAME);
   301		if (ret)
   302			return ret;
   303	
   304		ret = se_if_request_channel(dev, &priv->rx_chan, &priv->se_mb_cl, MBOX_RX_NAME);
   305		if (ret)
   306			return ret;
   307	
   308		mutex_init(&priv->se_if_cmd_lock);
   309	
   310		init_completion(&priv->waiting_rsp_clbk_hdl.done);
   311		init_completion(&priv->cmd_receiver_clbk_hdl.done);
   312	
   313		if (if_node->pool_name) {
   314			priv->mem_pool = of_gen_pool_get(dev->of_node, if_node->pool_name, 0);
   315			if (!priv->mem_pool)
   316				return dev_err_probe(dev, -ENOMEM,
   317						     "Unable to get sram pool = %s.",
   318						     if_node->pool_name);
   319		}
   320	
   321		if (if_node->reserved_dma_ranges) {
   322			ret = of_reserved_mem_device_init(dev);
   323			if (ret)
   324				return dev_err_probe(dev, ret,
   325						    "Failed to init reserved memory region.");
   326		}
   327	
   328		if (if_node->if_defs.se_if_type == SE_TYPE_ID_HSM) {
   329			ret = get_se_soc_info(priv, se_info);
   330			if (ret)
   331				return dev_err_probe(dev, ret, "Failed to fetch SoC Info.");
   332		}
   333	
   334		/* By default, there is no pending FW to be loaded.*/
   335		if (se_info->se_fw_img_nm.seco_fw_nm_in_rfs) {
   336			load_fw = get_load_fw_instance(priv);
   337			load_fw->se_fw_img_nm = &se_info->se_fw_img_nm;
   338			load_fw->is_fw_tobe_loaded = true;
   339	
   340			if (load_fw->se_fw_img_nm->prim_fw_nm_in_rfs) {
   341				/* allocate buffer where SE store encrypted IMEM */
   342				load_fw->imem.buf = dmam_alloc_coherent(priv->dev, ELE_IMEM_SIZE,
 > 343									&load_fw->imem.phyaddr,
   344									GFP_KERNEL);
   345				if (!load_fw->imem.buf)
   346					return dev_err_probe(dev, -ENOMEM,
   347							     "dmam-alloc-failed: To store encr-IMEM.");
   348				load_fw->imem_mgmt = true;
   349			}
   350		}
   351		dev_info(dev, "i.MX secure-enclave: %s0 interface to firmware, configured.",
   352			 get_se_if_name(priv->if_defs->se_if_type));
   353	
   354		return ret;
   355	}
   356	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From heiko at sntech.de  Mon Dec 22 04:18:15 2025
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 22 Dec 2025 13:18:15 +0100
Subject: [PATCH v2] arm64: dts: rockchip: enable both 2.5GbE ports on Rock 5T
In-Reply-To: <3903009.mvXUDI8C0e@workhorse>
References: <96516D1F-9787-47FE-A67E-4745D11D9207@probably.group>
 <034BDB37-34FB-441F-B79E-1631CA501576@probably.group>
 <3903009.mvXUDI8C0e@workhorse>
Message-ID: <5037086.R56niFO833@phil>

Am Freitag, 19. Dezember 2025, 14:06:12 Mitteleurop?ische Normalzeit schrieb Nicolas Frattaroli:
> On Thursday, 18 December 2025 07:27:06 Central European Standard Time Martin Holovsk? (Probably Nothing s.r.o.) wrote:
> > The Radxa Rock 5T board features two RTL8125B 2.5GbE Ethernet controllers
> > connected via PCIe lanes pcie2x1l0 (fe170000) and pcie2x1l2 (fe190000).
> > Currently only one interface is functional because the PCIe controller
> > nodes lack the necessary reset GPIO configuration.
> > 
> > Without the reset-gpios property, the RTL8125B PHYs remain in reset state
> > and are not enumerated by the PCIe bus. This results in only one Ethernet
> > interface being detected, or none at all depending on U-Boot initialization.
> > 
> > This patch adds the missing configuration for both PCIe controllers:
> > - Enables both pcie2x1l0 and pcie2x1l2 nodes (status = "okay")
> > - Configures reset GPIOs (GPIO4_PA5 and GPIO3_PB0 respectively)
> > - Adds corresponding pinctrl definitions
> > 
> > With this change, both 2.5GbE interfaces are properly detected and
> > functional on the Rock 5T.
> > 
> > Tested on Radxa Rock 5T v1.2 running Linux 6.12.
> > 
> > Signed-off-by: Martin Holovsky <mh at probably.group>
> > ---
> > Changes in v2:
> > - Sorted pcie nodes alphanumerically
> > - Sorted pinctrl nodes alphanumerically
> > - Added Signed-off-by line
> > 
> >  .../boot/dts/rockchip/rk3588-rock-5t.dts      | 28 +++++++++++++++++++
> >  1 file changed, 28 insertions(+)
> > 
> > diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts
> > index 0dd90c744380..aeb8e0d42f09 100644
> > --- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts
> > +++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts
> > @@ -68,10 +68,24 @@ &pcie2x1l1 {
> >  	reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>;
> >  	status = "okay";
> >  };
> >  
> > +&pcie2x1l0 {
> > +	pinctrl-names = "default";
> > +	pinctrl-0 = <&pcie2_0_rst>;
> > +	reset-gpios = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>;
> > +	status = "okay";
> > +};
> > +
> > +&pcie2x1l2 {
> > +	pinctrl-names = "default";
> > +	pinctrl-0 = <&pcie2_2_rst>;
> > +	reset-gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_HIGH>;
> > +	status = "okay";
> > +};
> > +
> >  &pcie30phy {
> >  	data-lanes = <1 1 2 2>;
> >  };
> > @@ -101,6 +115,14 @@ pcie2 {
> > +		pcie2_0_rst: pcie2-0-rst {
> > +			rockchip,pins = <4 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
> > +		};
> > +
> >  		pcie2_1_rst: pcie2-1-rst {
> >  			rockchip,pins = <4 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
> >  		};
> > +
> > +		pcie2_2_rst: pcie2-2-rst {
> > +			rockchip,pins = <3 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
> > +		};
> > +
> >  		pcie2_0_vcc3v3_en: pcie2-0-vcc-en {
> >  			rockchip,pins = <2 RK_PC0 RK_FUNC_GPIO &pcfg_pull_none>;
> >  		};
> > 
> 
> This stuff is already in rk3588-rock-5b-5bp-5t.dtsi. Ergo, this patch
> does nothing at all. What are you actually trying to solve?
> 
> Heiko, please don't apply this.

Thanks for the heads-up, both to you and Naoki :-)

Heiko




From heiko at sntech.de  Mon Dec 22 04:41:43 2025
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 22 Dec 2025 13:41:43 +0100
Subject: [PATCH v2] arm64: dts: rockchip: enable UFS controller on FriendlyElec
 NanoPi M5
In-Reply-To: <CABjd4Ywc-L0jvXwk253MDZwgN3srY6WQ5EhoKZ6wb+Hae376_A@mail.gmail.com>
References: <20251201-nanopi-m5-ufs-v2-1-ece9c0ee17c4@gmail.com>
 <CABjd4Ywc-L0jvXwk253MDZwgN3srY6WQ5EhoKZ6wb+Hae376_A@mail.gmail.com>
Message-ID: <119070978.nniJfEyVGO@phil>

Hi Alexey,

Am Donnerstag, 18. Dezember 2025, 15:05:39 Mitteleurop?ische Normalzeit schrieb Alexey Charkov:
> Hi Heiko,
> 
> On Mon, Dec 1, 2025 at 3:35?PM Alexey Charkov <alchark at gmail.com> wrote:
> >
> > The NanoPi M5 board supports pluggable UFS modules using the UFSHC
> > inside its Rockchip RK3576 SoC.
> >
> > Enable the respective devicetree node and add its supply regulators.
> >
> > Link: https://wiki.friendlyelec.com/wiki/images/9/97/NanoPi_M5_LP5_2411_SCH.pdf
> > Signed-off-by: Alexey Charkov <alchark at gmail.com>
> > ---
> > Changes in v2:
> > - Describe UFS supply regulators
> > - Add link to schematic
> > - Link to v1: https://lore.kernel.org/r/20251127-nanopi-m5-ufs-v1-1-0d28d157712c at gmail.com
> > ---
> >  arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts | 27 +++++++++++++++++++++++
> >  1 file changed, 27 insertions(+)
> 
> Would you mind pulling this one, or do you have any reservations?
> There hasn't been any discussion, but it looks like a pretty simple
> change, runtime tested and schema-tested.

Your patch fell directly into the dead-zone between -rc7 and -rc1 ;-)

> +	vcc1v2_ufs_vccq: regulator-vcc1v2-ufs-vccq {
> +		compatible = "regulator-fixed";
> +		regulator-min-microvolt = <1200000>;
> +		regulator-max-microvolt = <1200000>;
> +		regulator-name = "vcc1v2_ufs_vccq";
> +		vin-supply = <&vcc5v0_sys_s5>;
> +		en-supply = <&vcc_3v3_s3>;
> +	};
> +
> +	vcc1v8_ufs_vccq2: regulator-vcc1v8-ufs-vccq2 {
> +		compatible = "regulator-fixed";
> +		regulator-min-microvolt = <1800000>;
> +		regulator-max-microvolt = <1800000>;
> +		regulator-name = "vcc1v8_ufs_vccq2";
> +		vin-supply = <&vcc_1v8_s3>;
> +		en-supply = <&vdda_1v2_s0>;
> +	};


But where does the "en-supply" come from? For the life of me, I can't find
any reference to it in either the bindings in the kernel, nor the dt-schema.

Can you please point me to the part of the documentation where that is
described?

Thanks
Heiko






From lkp at intel.com  Mon Dec 22 04:43:24 2025
From: lkp at intel.com (kernel test robot)
Date: Mon, 22 Dec 2025 20:43:24 +0800
Subject: [PATCH 5/6] dma-mapping: Allow batched DMA sync operations if
 supported by the arch
In-Reply-To: <20251219053658.84978-6-21cnbao@gmail.com>
References: <20251219053658.84978-6-21cnbao@gmail.com>
Message-ID: <202512222029.Dd6Vs1Eg-lkp@intel.com>

Hi Barry,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on v6.19-rc2 next-20251219]
[cannot apply to arm64/for-next/core]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Barry-Song/arm64-Provide-dcache_by_myline_op_nosync-helper/20251219-195810
base:   linus/master
patch link:    https://lore.kernel.org/r/20251219053658.84978-6-21cnbao%40gmail.com
patch subject: [PATCH 5/6] dma-mapping: Allow batched DMA sync operations if supported by the arch
config: i386-buildonly-randconfig-006-20251222 (https://download.01.org/0day-ci/archive/20251222/202512222029.Dd6Vs1Eg-lkp at intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251222/202512222029.Dd6Vs1Eg-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512222029.Dd6Vs1Eg-lkp at intel.com/

All errors (new ones prefixed by >>):

>> kernel/dma/direct.c:456:4: error: call to undeclared function 'dma_direct_unmap_phys_batch_add'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     456 |                         dma_direct_unmap_phys_batch_add(dev, sg->dma_address,
         |                         ^
   kernel/dma/direct.c:456:4: note: did you mean 'dma_direct_unmap_phys'?
   kernel/dma/direct.h:188:20: note: 'dma_direct_unmap_phys' declared here
     188 | static inline void dma_direct_unmap_phys(struct device *dev, dma_addr_t addr,
         |                    ^
>> kernel/dma/direct.c:484:22: error: call to undeclared function 'dma_direct_map_phys_batch_add'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     484 |                         sg->dma_address = dma_direct_map_phys_batch_add(dev, sg_phys(sg),
         |                                           ^
   2 errors generated.


vim +/dma_direct_unmap_phys_batch_add +456 kernel/dma/direct.c

   439	
   440	/*
   441	 * Unmaps segments, except for ones marked as pci_p2pdma which do not
   442	 * require any further action as they contain a bus address.
   443	 */
   444	void dma_direct_unmap_sg(struct device *dev, struct scatterlist *sgl,
   445			int nents, enum dma_data_direction dir, unsigned long attrs)
   446	{
   447		struct scatterlist *sg;
   448		int i;
   449		bool need_sync = false;
   450	
   451		for_each_sg(sgl,  sg, nents, i) {
   452			if (sg_dma_is_bus_address(sg)) {
   453				sg_dma_unmark_bus_address(sg);
   454			} else {
   455				need_sync = true;
 > 456				dma_direct_unmap_phys_batch_add(dev, sg->dma_address,
   457						      sg_dma_len(sg), dir, attrs);
   458			}
   459		}
   460		if (need_sync && !dev_is_dma_coherent(dev))
   461			arch_sync_dma_batch_flush();
   462	}
   463	#endif
   464	
   465	int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
   466			enum dma_data_direction dir, unsigned long attrs)
   467	{
   468		struct pci_p2pdma_map_state p2pdma_state = {};
   469		struct scatterlist *sg;
   470		int i, ret;
   471		bool need_sync = false;
   472	
   473		for_each_sg(sgl, sg, nents, i) {
   474			switch (pci_p2pdma_state(&p2pdma_state, dev, sg_page(sg))) {
   475			case PCI_P2PDMA_MAP_THRU_HOST_BRIDGE:
   476				/*
   477				 * Any P2P mapping that traverses the PCI host bridge
   478				 * must be mapped with CPU physical address and not PCI
   479				 * bus addresses.
   480				 */
   481				break;
   482			case PCI_P2PDMA_MAP_NONE:
   483				need_sync = true;
 > 484				sg->dma_address = dma_direct_map_phys_batch_add(dev, sg_phys(sg),
   485						sg->length, dir, attrs);
   486				if (sg->dma_address == DMA_MAPPING_ERROR) {
   487					ret = -EIO;
   488					goto out_unmap;
   489				}
   490				break;
   491			case PCI_P2PDMA_MAP_BUS_ADDR:
   492				sg->dma_address = pci_p2pdma_bus_addr_map(
   493					p2pdma_state.mem, sg_phys(sg));
   494				sg_dma_len(sg) = sg->length;
   495				sg_dma_mark_bus_address(sg);
   496				continue;
   497			default:
   498				ret = -EREMOTEIO;
   499				goto out_unmap;
   500			}
   501			sg_dma_len(sg) = sg->length;
   502		}
   503	
   504		if (need_sync && !dev_is_dma_coherent(dev))
   505			arch_sync_dma_batch_flush();
   506		return nents;
   507	
   508	out_unmap:
   509		dma_direct_unmap_sg(dev, sgl, i, dir, attrs | DMA_ATTR_SKIP_CPU_SYNC);
   510		return ret;
   511	}
   512	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From suzuki.poulose at arm.com  Mon Dec 22 05:10:06 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Mon, 22 Dec 2025 13:10:06 +0000
Subject: [PATCH v6 3/4] coresight: tpda: add logic to configure TPDA_SYNCR
 register
In-Reply-To: <20251222-add_sysfs_nodes_to_configure_tpda-v6-3-b27143d45c86@oss.qualcomm.com>
References: <20251222-add_sysfs_nodes_to_configure_tpda-v6-0-b27143d45c86@oss.qualcomm.com>
 <20251222-add_sysfs_nodes_to_configure_tpda-v6-3-b27143d45c86@oss.qualcomm.com>
Message-ID: <684e06d2-1d90-4b89-96d8-7458f79e3cc9@arm.com>

On 22/12/2025 06:02, Jie Gan wrote:
> From: Tao Zhang <tao.zhang at oss.qualcomm.com>
> 
> The TPDA_SYNC counter tracks the number of bytes transferred from the
> aggregator. When this count reaches the value programmed in the
> TPDA_SYNCR register, an ASYNC request is triggered, allowing userspace
> tools to accurately parse each valid packet.
> 
> Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
> Reviewed-by: James Clark <james.clark at linaro.org>
> Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
> ---
>   .../ABI/testing/sysfs-bus-coresight-devices-tpda   | 10 +++++
>   drivers/hwtracing/coresight/coresight-tpda.c       | 46 ++++++++++++++++++++++
>   drivers/hwtracing/coresight/coresight-tpda.h       |  8 ++++
>   3 files changed, 64 insertions(+)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
> index c8bc7b19ab25..d359d90dca72 100644
> --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
> +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
> @@ -41,3 +41,13 @@ Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qu
>   Description:
>   		(RW) Set global (all ports) flush request bit. The bit remains set until a
>   		global flush request sequence completes.
> +
> +What:		/sys/bus/coresight/devices/<tpda-name>/syncr_mode
> +Date:		December 2025
> +KernelVersion:	6.19
> +Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
> +Description:
> +		(RW) Set mode the of the syncr counter.
> +		mode 0 - COUNT[11:0] value represents the approximate number of bytes moved between two ASYNC packet requests
> +		mode 1 - the bits COUNT[11:7] are used as a power of 2. for example, we could insert an async packet every 8K
> +		         data by writing a value 13 to the COUNT[11:7] field.

What is COUNT here ? and more importantly how is this usefule without
the support for setting the COUNT ? Do we plan to expose setting this ?
If yes, why not now ? I don't see the point of merging "this" patch
without the support for setting the counter.

Suzuki



> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
> index d24a9098f1b1..7baa8a0965d3 100644
> --- a/drivers/hwtracing/coresight/coresight-tpda.c
> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
> @@ -163,6 +163,15 @@ static void tpda_enable_pre_port(struct tpda_drvdata *drvdata)
>   	 */
>   	if (drvdata->trig_flag_ts)
>   		writel_relaxed(0x0, drvdata->base + TPDA_FPID_CR);
> +
> +	/* Initialize with a value of 0 */
> +	val = 0;
> +	if (drvdata->syncr_mode)
> +		val |= TPDA_SYNCR_MODE_CTRL_MASK;
> +
> +	/* Program the counter to its MAX value by default */
> +	val |= TPDA_SYNCR_COUNTER_MASK;
> +	writel_relaxed(val, drvdata->base + TPDA_SYNCR);
>   }
>   
>   static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
> @@ -385,8 +394,45 @@ static ssize_t global_flush_req_store(struct device *dev,
>   }
>   static DEVICE_ATTR_RW(global_flush_req);
>   
> +static ssize_t syncr_mode_show(struct device *dev,
> +			       struct device_attribute *attr,
> +			       char *buf)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	unsigned long val, syncr_val;
> +
> +	if (!drvdata->csdev->refcnt)
> +		return -EINVAL;
> +
> +	guard(spinlock)(&drvdata->spinlock);
> +	syncr_val = readl_relaxed(drvdata->base + TPDA_SYNCR);
> +	val = FIELD_GET(TPDA_SYNCR_MODE_CTRL_MASK, syncr_val);
> +
> +	return sysfs_emit(buf, "%lu\n", val);
> +}
> +
> +static ssize_t syncr_mode_store(struct device *dev,
> +				struct device_attribute *attr,
> +				const char *buf,
> +				size_t size)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	unsigned long val;
> +
> +	if (kstrtoul(buf, 0, &val))
> +		return -EINVAL;
> +
> +	guard(spinlock)(&drvdata->spinlock);
> +	/* set the mode when first enabling the device */
> +	drvdata->syncr_mode = !!val;
> +
> +	return size;
> +}
> +static DEVICE_ATTR_RW(syncr_mode);
> +
>   static struct attribute *tpda_attrs[] = {
>   	&dev_attr_global_flush_req.attr,
> +	&dev_attr_syncr_mode.attr,
>   	tpda_trig_sysfs_rw(freq_ts_enable, FREQTS),
>   	tpda_trig_sysfs_rw(trig_freq_enable, FRIE),
>   	tpda_trig_sysfs_rw(trig_flag_ts_enable, FLRIE),
> diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h
> index 1cc9253293ec..1d2de50bb9f9 100644
> --- a/drivers/hwtracing/coresight/coresight-tpda.h
> +++ b/drivers/hwtracing/coresight/coresight-tpda.h
> @@ -9,6 +9,7 @@
>   #define TPDA_CR			(0x000)
>   #define TPDA_Pn_CR(n)		(0x004 + (n * 4))
>   #define TPDA_FPID_CR		(0x084)
> +#define TPDA_SYNCR		(0x08C)
>   
>   /* Cross trigger global (all ports) flush request bit */
>   #define TPDA_CR_FLREQ		BIT(0)
> @@ -36,6 +37,11 @@
>   /* Aggregator port DSB data set element size bit */
>   #define TPDA_Pn_CR_DSBSIZE		BIT(8)
>   
> +/* TPDA_SYNCR counter mask */
> +#define TPDA_SYNCR_COUNTER_MASK		GENMASK(11, 0)
> +/* TPDA_SYNCR mode control bit */
> +#define TPDA_SYNCR_MODE_CTRL_MASK	GENMASK(12, 12)
> +
>   #define TPDA_MAX_INPORTS	32
>   
>   /**
> @@ -52,6 +58,7 @@
>    * @trig_freq:	Enable/disable cross trigger FREQ packet request interface.
>    * @freq_ts:	Enable/disable the timestamp for all FREQ packets.
>    * @cmbchan_mode: Configure the CMB/MCMB channel mode.
> + * @syncr_mode:	Configure the mode for counting packets.
>    */
>   struct tpda_drvdata {
>   	void __iomem		*base;
> @@ -66,6 +73,7 @@ struct tpda_drvdata {
>   	bool			trig_freq;
>   	bool			freq_ts;
>   	bool			cmbchan_mode;
> +	bool			syncr_mode;
>   };
>   
>   /* Enumerate members of global control register(cr) */
> 



From suzuki.poulose at arm.com  Mon Dec 22 05:12:45 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Mon, 22 Dec 2025 13:12:45 +0000
Subject: [PATCH v6 4/4] coresight: tpda: add sysfs node to flush specific
 port
In-Reply-To: <20251222-add_sysfs_nodes_to_configure_tpda-v6-4-b27143d45c86@oss.qualcomm.com>
References: <20251222-add_sysfs_nodes_to_configure_tpda-v6-0-b27143d45c86@oss.qualcomm.com>
 <20251222-add_sysfs_nodes_to_configure_tpda-v6-4-b27143d45c86@oss.qualcomm.com>
Message-ID: <9899b6c2-2bdf-41b8-9156-dcf1b611da39@arm.com>

On 22/12/2025 06:02, Jie Gan wrote:
> From: Tao Zhang <tao.zhang at oss.qualcomm.com>
> 
> Setting bit i in the TPDA_FLUSH_CR register initiates a flush request
> for port i, forcing the data to synchronize and be transmitted to the
> sink device.
> 
> Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
> Reviewed-by: James Clark <james.clark at linaro.org>
> Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
> ---
>   .../ABI/testing/sysfs-bus-coresight-devices-tpda   |  7 ++++
>   drivers/hwtracing/coresight/coresight-tpda.c       | 40 ++++++++++++++++++++++
>   drivers/hwtracing/coresight/coresight-tpda.h       |  1 +
>   3 files changed, 48 insertions(+)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
> index d359d90dca72..df8f03d4b573 100644
> --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
> +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
> @@ -51,3 +51,10 @@ Description:
>   		mode 0 - COUNT[11:0] value represents the approximate number of bytes moved between two ASYNC packet requests
>   		mode 1 - the bits COUNT[11:7] are used as a power of 2. for example, we could insert an async packet every 8K
>   		         data by writing a value 13 to the COUNT[11:7] field.
> +
> +What:		/sys/bus/coresight/devices/<tpda-name>/port_flush_req
> +Date:		December 2025
> +KernelVersion:	6.19
> +Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
> +Description:
> +		(RW) Configure the bit i to requests a flush operation of port i on the TPDA.

Does this have similar semantics as the "global_flush_req"  for "Read" ? 
i.e., the bit stays set until the request completes ? Otherwise, why 
isn't this Write only ?

I don't see the point of "Reading" this value back.

Suzuki

> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
> index 7baa8a0965d3..f79fea4fbb2c 100644
> --- a/drivers/hwtracing/coresight/coresight-tpda.c
> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
> @@ -430,9 +430,49 @@ static ssize_t syncr_mode_store(struct device *dev,
>   }
>   static DEVICE_ATTR_RW(syncr_mode);
>   
> +static ssize_t port_flush_req_show(struct device *dev,
> +				   struct device_attribute *attr,
> +				   char *buf)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	unsigned long val;
> +
> +	if (!drvdata->csdev->refcnt)
> +		return -EINVAL;
> +
> +	guard(spinlock)(&drvdata->spinlock);
> +	val = readl_relaxed(drvdata->base + TPDA_FLUSH_CR);
> +
> +	return sysfs_emit(buf, "0x%lx\n", val);
> +}
> +
> +static ssize_t port_flush_req_store(struct device *dev,
> +				    struct device_attribute *attr,
> +				    const char *buf,
> +				    size_t size)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	u32 val;
> +
> +	if (kstrtou32(buf, 0, &val))
> +		return -EINVAL;
> +
> +	if (!drvdata->csdev->refcnt || !val)
> +		return -EINVAL;
> +
> +	guard(spinlock)(&drvdata->spinlock);
> +	CS_UNLOCK(drvdata->base);
> +	writel_relaxed(val, drvdata->base + TPDA_FLUSH_CR);
> +	CS_LOCK(drvdata->base);
> +
> +	return size;
> +}
> +static DEVICE_ATTR_RW(port_flush_req);
> +
>   static struct attribute *tpda_attrs[] = {
>   	&dev_attr_global_flush_req.attr,
>   	&dev_attr_syncr_mode.attr,
> +	&dev_attr_port_flush_req.attr,
>   	tpda_trig_sysfs_rw(freq_ts_enable, FREQTS),
>   	tpda_trig_sysfs_rw(trig_freq_enable, FRIE),
>   	tpda_trig_sysfs_rw(trig_flag_ts_enable, FLRIE),
> diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h
> index 1d2de50bb9f9..ef1ce2ce36a9 100644
> --- a/drivers/hwtracing/coresight/coresight-tpda.h
> +++ b/drivers/hwtracing/coresight/coresight-tpda.h
> @@ -10,6 +10,7 @@
>   #define TPDA_Pn_CR(n)		(0x004 + (n * 4))
>   #define TPDA_FPID_CR		(0x084)
>   #define TPDA_SYNCR		(0x08C)
> +#define TPDA_FLUSH_CR		(0x090)
>   
>   /* Cross trigger global (all ports) flush request bit */
>   #define TPDA_CR_FLREQ		BIT(0)
> 



From nicolas.dufresne at collabora.com  Mon Dec 22 05:19:16 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Mon, 22 Dec 2025 08:19:16 -0500
Subject: [PATCH v7 14/17] media: rkvdec: Add H264 support for the
 VDPU381 variant
In-Reply-To: <20251220164604.10052-1-liujianfeng1994@gmail.com>
References: <20251218232829.337811-15-detlev.casanova@collabora.com>
	 <20251220164604.10052-1-liujianfeng1994@gmail.com>
Message-ID: <bf4a8049f49b8d6d8a39faecee025dce51d59db3.camel@collabora.com>

Hi,

Le dimanche 21 d?cembre 2025 ? 00:46 +0800, Jianfeng Liu a ?crit?:
> Hi,
> 
> On Thu, 18 Dec 2025 18:28:24 -0500, Detlev Casanova wrote:
> > +static int rkvdec_h264_start(struct rkvdec_ctx *ctx)
> > +{
> > +	struct rkvdec_dev *rkvdec = ctx->dev;
> > +	struct rkvdec_h264_priv_tbl *priv_tbl;
> > +	struct rkvdec_h264_ctx *h264_ctx;
> > +	struct v4l2_ctrl *ctrl;
> > +	int ret;
> > +
> > +	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> > +			????? V4L2_CID_STATELESS_H264_SPS);
> > +	if (!ctrl)
> > +		return -EINVAL;
> > +
> > +	h264_ctx = kzalloc(sizeof(*h264_ctx), GFP_KERNEL);
> > +	if (!h264_ctx)
> > +		return -ENOMEM;
> 
> I can see the sps validation is removed:
> 
> 	ret = rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps);
> 	if (ret)
> 		return ret;
> 
> This should fix decoding issue with chromium when minimum size of h264
> decoder is lower than 32. While I find this issue is caused by chromium
> not following v4l2 stateless spec, and I think checking sps at start
> should be still necessary.

One of the missing part of rkvdec is that once you set the OUTPUT format we only
reset the capture format, but we should also reset the SPS control to a matching
default, matching the resolution and resetting the depth. In fact, I don't even
see code that verify the bit depth against already allocated memory, and the is
not capable of converting.

I tend to agree with Jianfeng, that we should leave that un-modified until we
have time to fully address and test this situation.

Nicolas

> 
> I have sent a fix to chromium[1] and it should get merged later.
> 
> [1] https://chromium-review.googlesource.com/c/chromium/src/+/7274555
> 
> Best regards,
> Jianfeng
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251222/542004c3/attachment.sig>

From sebastian.reichel at collabora.com  Mon Dec 22 05:24:57 2025
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Mon, 22 Dec 2025 14:24:57 +0100
Subject: [PATCH 1/3] arm64: dts: rockchip: remove rtc regulator for
 ArmSoM Sige5
In-Reply-To: <20251220100010.26643-1-amadeus@jmu.edu.cn>
References: <20251220100010.26643-1-amadeus@jmu.edu.cn>
Message-ID: <aUlGPGFYYf8Ndn5D@venus>

Hi,

On Sat, Dec 20, 2025 at 06:00:08PM +0800, Chukun Pan wrote:
> According to the schematic, RTC is powered by vcc_3v3_s3.
> The vcc_3v3_rtc_s5 regulator does not exist, remove it.
> 
> Signed-off-by: Chukun Pan <amadeus at jmu.edu.cn>
> ---

That's true for all board revisions that have a public schematic
(1.1, 1.2 and 1.3), so:

Reviewed-by: Sebastian Reichel <sebastian.reichel at collabora.com>

-- Sebastian

>  arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts | 10 ----------
>  1 file changed, 10 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts b/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts
> index 3386084f6318..392ba83ab05a 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts
> +++ b/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts
> @@ -156,16 +156,6 @@ vcc_3v3_pcie: regulator-vcc-3v3-pcie {
>  		vin-supply = <&vcc_5v0_sys>;
>  	};
>  
> -	vcc_3v3_rtc_s5: regulator-vcc-3v3-rtc-s5 {
> -		compatible = "regulator-fixed";
> -		regulator-name = "vcc_3v3_rtc_s5";
> -		regulator-boot-on;
> -		regulator-always-on;
> -		regulator-min-microvolt = <3300000>;
> -		regulator-max-microvolt = <3300000>;
> -		vin-supply = <&vcc_5v0_sys>;
> -	};
> -
>  	vcc_3v3_s0: regulator-vcc-3v3-s0 {
>  		compatible = "regulator-fixed";
>  		regulator-name = "vcc_3v3_s0";
> -- 
> 2.25.1
> 
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251222/cbca05eb/attachment.sig>

From sebastian.reichel at collabora.com  Mon Dec 22 05:28:07 2025
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Mon, 22 Dec 2025 14:28:07 +0100
Subject: [PATCH 2/3] arm64: dts: rockchip: fix hp-det pin for ArmSoM Sige5
In-Reply-To: <20251220100010.26643-2-amadeus@jmu.edu.cn>
References: <20251220100010.26643-1-amadeus@jmu.edu.cn>
 <20251220100010.26643-2-amadeus@jmu.edu.cn>
Message-ID: <aUlGrcNAwp9AK8Mc@venus>

Hi,

On Sat, Dec 20, 2025 at 06:00:09PM +0800, Chukun Pan wrote:
> Although the hp_det pin is not used, according to the schematic,
> the headphone detection pin is GPIO4_B0. Fix the incorrect pin.
> 
> Signed-off-by: Chukun Pan <amadeus at jmu.edu.cn>
> ---

Apparently all of the public schematics (board rev 1.1 - 1.3) have
HP_DET_L connected to GPIO4_B0. It's also easy to see how the wrong
pin ended up in the DT: the schematics also added HP_DET_L as a
comment to GPIO0_D3 (which is actually connected to TP_RST_L)!

Reviewed-by: Sebastian Reichel <sebastian.reichel at collabora.com>

-- Sebastian

>  arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts b/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts
> index 392ba83ab05a..a0d8f52a706f 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts
> +++ b/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts
> @@ -812,8 +812,8 @@ gmac1_rst: gmac1-rst {
>  	};
>  
>  	headphone {
> -		hp_det: hp-det {
> -			rockchip,pins = <0 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up>;
> +		hp_det_l: hp-det-l {
> +			rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
>  		};
>  	};
>  
> -- 
> 2.25.1
> 
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251222/e0779c10/attachment.sig>

From alchark at gmail.com  Mon Dec 22 05:28:07 2025
From: alchark at gmail.com (Alexey Charkov)
Date: Mon, 22 Dec 2025 17:28:07 +0400
Subject: [PATCH v2] arm64: dts: rockchip: enable UFS controller on
 FriendlyElec NanoPi M5
In-Reply-To: <119070978.nniJfEyVGO@phil>
References: <20251201-nanopi-m5-ufs-v2-1-ece9c0ee17c4@gmail.com>
 <CABjd4Ywc-L0jvXwk253MDZwgN3srY6WQ5EhoKZ6wb+Hae376_A@mail.gmail.com> <119070978.nniJfEyVGO@phil>
Message-ID: <CABjd4YyCgVBFP4GG5FK5xO3SY=at5fpYicTO+ghaSCJaP_+XJQ@mail.gmail.com>

Hi Heiko,

On Mon, Dec 22, 2025 at 4:41?PM Heiko Stuebner <heiko at sntech.de> wrote:
>
> Hi Alexey,
>
> Am Donnerstag, 18. Dezember 2025, 15:05:39 Mitteleurop?ische Normalzeit schrieb Alexey Charkov:
> > Hi Heiko,
> >
> > On Mon, Dec 1, 2025 at 3:35?PM Alexey Charkov <alchark at gmail.com> wrote:
> > >
> > > The NanoPi M5 board supports pluggable UFS modules using the UFSHC
> > > inside its Rockchip RK3576 SoC.
> > >
> > > Enable the respective devicetree node and add its supply regulators.
> > >
> > > Link: https://wiki.friendlyelec.com/wiki/images/9/97/NanoPi_M5_LP5_2411_SCH.pdf
> > > Signed-off-by: Alexey Charkov <alchark at gmail.com>
> > > ---
> > > Changes in v2:
> > > - Describe UFS supply regulators
> > > - Add link to schematic
> > > - Link to v1: https://lore.kernel.org/r/20251127-nanopi-m5-ufs-v1-1-0d28d157712c at gmail.com
> > > ---
> > >  arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts | 27 +++++++++++++++++++++++
> > >  1 file changed, 27 insertions(+)
> >
> > Would you mind pulling this one, or do you have any reservations?
> > There hasn't been any discussion, but it looks like a pretty simple
> > change, runtime tested and schema-tested.
>
> Your patch fell directly into the dead-zone between -rc7 and -rc1 ;-)

Understood :)

> > +     vcc1v2_ufs_vccq: regulator-vcc1v2-ufs-vccq {
> > +             compatible = "regulator-fixed";
> > +             regulator-min-microvolt = <1200000>;
> > +             regulator-max-microvolt = <1200000>;
> > +             regulator-name = "vcc1v2_ufs_vccq";
> > +             vin-supply = <&vcc5v0_sys_s5>;
> > +             en-supply = <&vcc_3v3_s3>;
> > +     };
> > +
> > +     vcc1v8_ufs_vccq2: regulator-vcc1v8-ufs-vccq2 {
> > +             compatible = "regulator-fixed";
> > +             regulator-min-microvolt = <1800000>;
> > +             regulator-max-microvolt = <1800000>;
> > +             regulator-name = "vcc1v8_ufs_vccq2";
> > +             vin-supply = <&vcc_1v8_s3>;
> > +             en-supply = <&vdda_1v2_s0>;
> > +     };
>
>
> But where does the "en-supply" come from? For the life of me, I can't find
> any reference to it in either the bindings in the kernel, nor the dt-schema.
>
> Can you please point me to the part of the documentation where that is
> described?

The bindings [1] describe supplies by a wildcard pattern '.*-supply$',
and the device in question is a DC-DC regulator (see page 17 of the
schematic [2]), which produces the 1.2V power for the chip, its VIN
pin directly wired to VCC5V0_SYS_S5 and its EN pin directly wired to
VCC_3V3_S3, both of which need to be active for the 1.2V feed to
appear - thus both are 'supplies' of sorts. VCCQ2 is similar, but
implemented using a simple gate circuit. This is done to ensure
correct power sequencing, from what I understood.

I've just checked the fixed regulator driver though, and it only
handles 'vin-supply', not any other '.*-supply$' - thus, technically,
it doesn't currently implement the full schema :) Not sure if there is
another existing facility to model multi-parent regulators that I
missed, or if it's a good idea to extend the fixed.c driver to handle
an arbitrary number of supplies?

Any guidance would be appreciated.

Thanks a lot,
Alexey

[1] https://github.com/torvalds/linux/blob/master/Documentation/devicetree/bindings/regulator/regulator.yaml#L246-L248
[2] https://wiki.friendlyelec.com/wiki/images/9/97/NanoPi_M5_LP5_2411_SCH.pdf


From sebastian.reichel at collabora.com  Mon Dec 22 05:32:53 2025
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Mon, 22 Dec 2025 14:32:53 +0100
Subject: [PATCH 3/3] arm64: dts: rockchip: enable saradc for ArmSoM Sige5
In-Reply-To: <20251220100010.26643-3-amadeus@jmu.edu.cn>
References: <20251220100010.26643-1-amadeus@jmu.edu.cn>
 <20251220100010.26643-3-amadeus@jmu.edu.cn>
Message-ID: <aUlHa-QhCLOk8AGa@venus>

Hi,

On Sat, Dec 20, 2025 at 06:00:10PM +0800, Chukun Pan wrote:
> Add ADC support to ArmSoM Sige5 board.
> 
> Signed-off-by: Chukun Pan <amadeus at jmu.edu.cn>
> ---

The reference voltage is different between the different board
revisions. Older boards (1.1 and 1.2) have SARADC_AVDD1V8 connected
to &vcca_1v8_s0, but newer boards (1.3) use VCCA1V8_PLDO2_S0
instead. I guess considering &vcca1v8_pldo2_s0 is marked as always
on, we can ignore this difference, but I think it's worth a comment
in the DT and the commit description. Otherwise:

Reviewed-by: Sebastian Reichel <sebastian.reichel at collabora.com>

-- Sebastian

>  arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts b/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts
> index a0d8f52a706f..d372ba252af8 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts
> +++ b/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts
> @@ -897,6 +897,11 @@ &sai6 {
>  	status = "okay";
>  };
>  
> +&saradc {
> +	vref-supply = <&vcca_1v8_s0>;
> +	status = "okay";
> +};
> +
>  &sdhci {
>  	bus-width = <8>;
>  	full-pwr-cycle-in-suspend;
> -- 
> 2.25.1
> 
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251222/bc8d77b6/attachment.sig>

From heiko at sntech.de  Mon Dec 22 05:38:25 2025
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 22 Dec 2025 14:38:25 +0100
Subject: [PATCH RESEND] arm64: dts: rockchip: Fix wifi interrupts flag on Sakura Pi RK3308B
In-Reply-To: <20251217091808.38253-2-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251217091808.38253-2-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <176641067335.1648325.10724252333112097745.b4-ty@sntech.de>


On Wed, 17 Dec 2025 10:18:08 +0100, Krzysztof Kozlowski wrote:
> GPIO_ACTIVE_x flags are not correct in the context of interrupt flags.
> These are simple defines so they could be used in DTS but they will not
> have the same meaning: GPIO_ACTIVE_HIGH = 0 = IRQ_TYPE_NONE.
> 
> Correct the interrupt flags, assuming the author of the code wanted same
> logical behavior behind the name "ACTIVE_xxx", this is:
>   ACTIVE_HIGH  => IRQ_TYPE_LEVEL_HIGH
> 
> [...]

Applied, thanks!

[1/1] arm64: dts: rockchip: Fix wifi interrupts flag on Sakura Pi RK3308B
      commit: 7c6bbcb010b1b8e4e6452de109f0506bb05d6efb

Best regards,
-- 
Heiko Stuebner <heiko at sntech.de>


From heiko at sntech.de  Mon Dec 22 05:38:23 2025
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 22 Dec 2025 14:38:23 +0100
Subject: [PATCH] arm64: dts: rockchip: fix unit-address for RK3588 NPU's core1 and core2's IOMMU
In-Reply-To: <20251215-npu-dt-node-address-v1-1-840093e8a2bf@cherry.de>
References: <20251215-npu-dt-node-address-v1-1-840093e8a2bf@cherry.de>
Message-ID: <176641067338.1648325.5634476513505380555.b4-ty@sntech.de>


On Mon, 15 Dec 2025 17:45:56 +0100, Quentin Schulz wrote:
> The Device Tree specification specifies[1] that
> 
> """
> Each node in the devicetree is named according to the following
> convention:
> 	node-name at unit-address
> [...]
> The unit-address must match the first address specified in the reg
> property of the node.
> """
> 
> [...]

Applied, thanks!

[1/1] arm64: dts: rockchip: fix unit-address for RK3588 NPU's core1 and core2's IOMMU
      commit: cd8967ea3105d30adb878a9fea0e34a9378df610

Best regards,
-- 
Heiko Stuebner <heiko at sntech.de>


From heiko at sntech.de  Mon Dec 22 05:38:24 2025
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 22 Dec 2025 14:38:24 +0100
Subject: (subset) [PATCH v2 0/4] PCI: rockchip: 5.0 GT/s speed may be dangerous
In-Reply-To: <cover.1763415705.git.geraldogabriel@gmail.com>
References: <cover.1763415705.git.geraldogabriel@gmail.com>
Message-ID: <176641067349.1648325.7613113925741792154.b4-ty@sntech.de>


On Mon, 17 Nov 2025 18:46:43 -0300, Geraldo Nascimento wrote:
> Dragan Simic already had warned me of potential issues with 5.0 GT/s
> speed operation in Rockchip PCIe. However, in recent interactions
> with Shawn Lin from Rockchip it came to my attention there's grave
> danger in the unknown errata regarding 5.0 GT/s operational speed
> of their PCIe core. Even if the odds are low, to contain any damage,
> let's cover the remaining corner-cases where the default would lead
> to 5.0 GT/s operation as well as add a comment to Root Complex driver
> core, documenting this danger. Furthermore, remove redundant
> declaration of max-link-speed from rk3399-nanopi-r4s.dtsi
> 
> [...]

Applied, thanks!

[3/4] arm64: dts: rockchip: remove dangerous max-link-speed from helios64
      commit: 0368e4afcf20f377c81fa77b1c7d0dee4a625a44
[4/4] arm64: dts: rockchip: remove redundant max-link-speed from nanopi-r4s
      commit: ce652c98a7bfa0b7c675ef5cd85c44c186db96af

Best regards,
-- 
Heiko Stuebner <heiko at sntech.de>


From heiko at sntech.de  Mon Dec 22 05:38:22 2025
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 22 Dec 2025 14:38:22 +0100
Subject: [PATCH 1/3] arm64: dts: rockchip: remove rtc regulator for ArmSoM Sige5
In-Reply-To: <20251220100010.26643-1-amadeus@jmu.edu.cn>
References: <20251220100010.26643-1-amadeus@jmu.edu.cn>
Message-ID: <176641067333.1648325.14071250323791790543.b4-ty@sntech.de>


On Sat, 20 Dec 2025 18:00:08 +0800, Chukun Pan wrote:
> According to the schematic, RTC is powered by vcc_3v3_s3.
> The vcc_3v3_rtc_s5 regulator does not exist, remove it.
> 
> 

Applied, thanks!

[1/3] arm64: dts: rockchip: remove rtc regulator for ArmSoM Sige5
      commit: 3fc7029d3009682b27be2fa2cd2269bc6f104c2e
[2/3] arm64: dts: rockchip: fix hp-det pin for ArmSoM Sige5
      commit: 341735d92ff868eb4c46beafb313d66f015809be
[3/3] arm64: dts: rockchip: enable saradc for ArmSoM Sige5
      commit: 3025d360f03515d3f6396a5cec339e776d62b2da

Best regards,
-- 
Heiko Stuebner <heiko at sntech.de>


From heiko at sntech.de  Mon Dec 22 05:39:49 2025
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 22 Dec 2025 14:39:49 +0100
Subject: [PATCH 3/3] arm64: dts: rockchip: enable saradc for ArmSoM Sige5
In-Reply-To: <aUlHa-QhCLOk8AGa@venus>
References: <20251220100010.26643-1-amadeus@jmu.edu.cn>
 <20251220100010.26643-3-amadeus@jmu.edu.cn> <aUlHa-QhCLOk8AGa@venus>
Message-ID: <3767252.NG923GbCHz@phil>

Am Montag, 22. Dezember 2025, 14:32:53 Mitteleurop?ische Normalzeit schrieb Sebastian Reichel:
> Hi,
> 
> On Sat, Dec 20, 2025 at 06:00:10PM +0800, Chukun Pan wrote:
> > Add ADC support to ArmSoM Sige5 board.
> > 
> > Signed-off-by: Chukun Pan <amadeus at jmu.edu.cn>
> > ---
> 
> The reference voltage is different between the different board
> revisions. Older boards (1.1 and 1.2) have SARADC_AVDD1V8 connected
> to &vcca_1v8_s0, but newer boards (1.3) use VCCA1V8_PLDO2_S0
> instead. I guess considering &vcca1v8_pldo2_s0 is marked as always
> on, we can ignore this difference, but I think it's worth a comment
> in the DT and the commit description. Otherwise:
> 
> Reviewed-by: Sebastian Reichel <sebastian.reichel at collabora.com>

darn, too late for this one - should've waited longer for
this possible Rb :-) ... I did add the others before pushing
though.


Heiko




From liviu.dudau at arm.com  Mon Dec 22 05:41:52 2025
From: liviu.dudau at arm.com (Liviu Dudau)
Date: Mon, 22 Dec 2025 13:41:52 +0000
Subject: [PATCH v2 3/4] drm/panthor: Implement reading shader_present
 from nvmem
In-Reply-To: <20251220-mt8196-shader-present-v2-3-45b1ff1dfab0@collabora.com>
References: <20251220-mt8196-shader-present-v2-0-45b1ff1dfab0@collabora.com>
 <20251220-mt8196-shader-present-v2-3-45b1ff1dfab0@collabora.com>
Message-ID: <aUlKoHKb084vm_p-@e142607>

On Sat, Dec 20, 2025 at 07:49:54PM +0100, Nicolas Frattaroli wrote:
> On some platforms, notably MediaTek MT8196, the shader_present bitmask
> in the Mali GPU register for it has cores enabled that may be faulty.
> The true shader_present bitmask is found in an efuse instead.
> 
> Implement reading shader_present from an nvmem cell if one is present,
> falling back to the Mali register if it's absent. The error codes are
> trickled up through to the probe function so that probe deferral works.
> 
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>

Reviewed-by: Liviu Dudau <liviu.dudau at arm.com>

Best regards,
Liviu

> ---
>  drivers/gpu/drm/panthor/panthor_hw.c | 36 ++++++++++++++++++++++++++++++------
>  1 file changed, 30 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c
> index 87ebb7ae42c4..80c521784cd3 100644
> --- a/drivers/gpu/drm/panthor/panthor_hw.c
> +++ b/drivers/gpu/drm/panthor/panthor_hw.c
> @@ -1,6 +1,7 @@
>  // SPDX-License-Identifier: GPL-2.0 or MIT
>  /* Copyright 2025 ARM Limited. All rights reserved. */
>  
> +#include <linux/nvmem-consumer.h>
>  #include <drm/drm_print.h>
>  
>  #include "panthor_device.h"
> @@ -109,7 +110,25 @@ static char *get_gpu_model_name(struct panthor_device *ptdev)
>  	return "(Unknown Mali GPU)";
>  }
>  
> -static void panthor_gpu_info_init(struct panthor_device *ptdev)
> +static int overload_shader_present(struct panthor_device *ptdev)
> +{
> +	u64 contents;
> +	int ret;
> +
> +	ret = nvmem_cell_read_variable_le_u64(ptdev->base.dev, "shader-present",
> +					      &contents);
> +	if (!ret)
> +		ptdev->gpu_info.shader_present = contents;
> +	else if (ret == -ENOENT)
> +		return 0;
> +	else
> +		return dev_err_probe(ptdev->base.dev, ret,
> +				     "Failed to read shader-present nvmem cell\n");
> +
> +	return 0;
> +}
> +
> +static int panthor_gpu_info_init(struct panthor_device *ptdev)
>  {
>  	unsigned int i;
>  
> @@ -143,13 +162,18 @@ static void panthor_gpu_info_init(struct panthor_device *ptdev)
>  		ptdev->gpu_info.tiler_present = gpu_read64(ptdev, GPU_TILER_PRESENT);
>  		ptdev->gpu_info.l2_present = gpu_read64(ptdev, GPU_L2_PRESENT);
>  	}
> +
> +	return overload_shader_present(ptdev);
>  }
>  
> -static void panthor_hw_info_init(struct panthor_device *ptdev)
> +static int panthor_hw_info_init(struct panthor_device *ptdev)
>  {
>  	u32 major, minor, status;
> +	int ret;
>  
> -	panthor_gpu_info_init(ptdev);
> +	ret = panthor_gpu_info_init(ptdev);
> +	if (ret)
> +		return ret;
>  
>  	major = GPU_VER_MAJOR(ptdev->gpu_info.gpu_id);
>  	minor = GPU_VER_MINOR(ptdev->gpu_info.gpu_id);
> @@ -172,6 +196,8 @@ static void panthor_hw_info_init(struct panthor_device *ptdev)
>  		 "shader_present=0x%0llx l2_present=0x%0llx tiler_present=0x%0llx",
>  		 ptdev->gpu_info.shader_present, ptdev->gpu_info.l2_present,
>  		 ptdev->gpu_info.tiler_present);
> +
> +	return 0;
>  }
>  
>  static int panthor_hw_bind_device(struct panthor_device *ptdev)
> @@ -218,7 +244,5 @@ int panthor_hw_init(struct panthor_device *ptdev)
>  	if (ret)
>  		return ret;
>  
> -	panthor_hw_info_init(ptdev);
> -
> -	return 0;
> +	return panthor_hw_info_init(ptdev);
>  }
> 
> -- 
> 2.52.0
> 


From towinchenmi at gmail.com  Mon Dec 22 05:50:33 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Mon, 22 Dec 2025 21:50:33 +0800
Subject: [PATCH v5 08/11] input: macsmc-input: New driver to handle the
 Apple Mac SMC buttons/lid
In-Reply-To: <20251112-macsmc-subdevs-v5-8-728e4b91fe81@gmail.com>
References: <20251112-macsmc-subdevs-v5-0-728e4b91fe81@gmail.com>
 <20251112-macsmc-subdevs-v5-8-728e4b91fe81@gmail.com>
Message-ID: <aa4242f9-7d26-4df5-9e14-1b3bb7334652@gmail.com>



Hi,
On 12/11/2025 19:16, James Calligeros wrote:

> From: Hector Martin <marcan at marcan.st>
> 
> This driver implements power button and lid switch support for Apple Mac
> devices using SMC controllers driven by the macsmc driver.
> 
> In addition to basic input support, this also responds to the final
> shutdown warning (when the power button is held down long enough) by
> doing an emergency kernel poweroff. This allows the NVMe controller to
> be cleanly shut down, which prevents data loss for in-cache data.
> 
> Reviewed-by: Neal Gompa <neal at gompa.dev>
> Signed-off-by: Hector Martin <marcan at marcan.st>
> Co-developed-by: Sven Peter <sven at kernel.org>
> Signed-off-by: Sven Peter <sven at kernel.org>
> Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
> ---
>  MAINTAINERS                       |   1 +
>  drivers/input/misc/Kconfig        |  11 ++
>  drivers/input/misc/Makefile       |   1 +
>  drivers/input/misc/macsmc-input.c | 207 +++++++++++++++++++++++++
>  4 files changed, 220 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index fb55a167699e..48bdca6943f3 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2455,6 +2455,7 @@ F:	drivers/hwmon/macsmc-hwmon.c
>  F:	drivers/pmdomain/apple/
>  F:	drivers/i2c/busses/i2c-pasemi-core.c
>  F:	drivers/i2c/busses/i2c-pasemi-platform.c
> +F:	drivers/input/misc/macsmc-input.c
>  F:	drivers/input/touchscreen/apple_z2.c
>  F:	drivers/iommu/apple-dart.c
>  F:	drivers/iommu/io-pgtable-dart.c
> diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
> index cc2558630797..1144ba151dbf 100644
> --- a/drivers/input/misc/Kconfig
> +++ b/drivers/input/misc/Kconfig
> @@ -992,4 +992,15 @@ config INPUT_STPMIC1_ONKEY
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called stpmic1_onkey.
>  
> +config INPUT_MACSMC
> +	tristate "Apple Mac SMC lid/buttons"
> +	depends on MFD_MACSMC
> +	help
> +	  Say Y here if you want to use the input events delivered via the
> +	  SMC controller on Apple Mac machines using the macsmc driver.
> +	  This includes lid open/close and the power button.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called macsmc-input.
> +
>  endif
> diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
> index f5ebfa9d9983..c6394105252f 100644
> --- a/drivers/input/misc/Makefile
> +++ b/drivers/input/misc/Makefile
> @@ -52,6 +52,7 @@ obj-$(CONFIG_INPUT_IQS7222)		+= iqs7222.o
>  obj-$(CONFIG_INPUT_KEYSPAN_REMOTE)	+= keyspan_remote.o
>  obj-$(CONFIG_INPUT_KXTJ9)		+= kxtj9.o
>  obj-$(CONFIG_INPUT_M68K_BEEP)		+= m68kspkr.o
> +obj-$(CONFIG_INPUT_MACSMC_INPUT)	+= macsmc-input.o
should be CONFIG_INPUT_MACSMC (alternatively change Kconfig instead)

>  obj-$(CONFIG_INPUT_MAX7360_ROTARY)	+= max7360-rotary.o
>  obj-$(CONFIG_INPUT_MAX77650_ONKEY)	+= max77650-onkey.o
>  obj-$(CONFIG_INPUT_MAX77693_HAPTIC)	+= max77693-haptic.o
> diff --git a/drivers/input/misc/macsmc-input.c b/drivers/input/misc/macsmc-input.c
> new file mode 100644
> index 000000000000..f4598e65fc80
> --- /dev/null
> +++ b/drivers/input/misc/macsmc-input.c
> @@ -0,0 +1,207 @@
> +// SPDX-License-Identifier: GPL-2.0-only OR MIT
> +/*
> + * Apple SMC input event driver
> + * Copyright The Asahi Linux Contributors
> + *
> + * This driver exposes certain events from the SMC as an input device.
> + * This includes the lid open/close and power button notifications.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/input.h>
> +#include <linux/mfd/macsmc.h>
Missing #include <linux/mfd/core.h>

> +#include <linux/module.h>
> +#include <linux/reboot.h>
> +
> +/**
> + * struct macsmc_input
> + * @dev: Underlying struct device for the input sub-device
> + * @smc: Pointer to apple_smc struct of the mfd parent
> + * @input: Allocated input_dev; devres managed
> + * @nb: Notifier block used for incoming events from SMC (e.g. button pressed down)
> + * @wakeup_mode: Set to true when system is suspended and power button events should wake it
> + */
> +struct macsmc_input {
> +	struct device *dev;
> +	struct apple_smc *smc;
> +	struct input_dev *input;
> +	struct notifier_block nb;
> +	bool wakeup_mode;
> +};
> +
> +#define SMC_EV_BTN 0x7201
> +#define SMC_EV_LID 0x7203
> +
> +#define BTN_POWER		0x01 /* power button on e.g. Mac Mini chasis pressed */
> +#define BTN_TOUCHID		0x06 /* combined TouchID / power button on MacBooks pressed */
> +#define BTN_POWER_HELD_SHORT	0xfe /* power button briefly held down */
> +#define BTN_POWER_HELD_LONG	0x00 /* power button held down; sent just before forced poweroff */
> +
> +static void macsmc_input_event_button(struct macsmc_input *smcin, unsigned long event)
> +{
> +	u8 button = (event >> 8) & 0xff;
> +	u8 state = !!(event & 0xff);
> +
> +	switch (button) {
> +	case BTN_POWER:
> +	case BTN_TOUCHID:
> +		pm_wakeup_dev_event(smcin->dev, 0, (smcin->wakeup_mode && state));
> +
> +		/* Suppress KEY_POWER event to prevent immediate shutdown on wake */
> +		if (smcin->wakeup_mode)
> +			return;
> +
> +		input_report_key(smcin->input, KEY_POWER, state);
> +		input_sync(smcin->input);
> +		break;
> +	case BTN_POWER_HELD_SHORT: /* power button held down; ignore */
> +		break;
> +	case BTN_POWER_HELD_LONG:
> +		/*
> +		 * If we get here the power button has been held down for a while and
> +		 * we have about 4 seconds before forced power-off is triggered by SMC.
> +		 * Try to do an emergency shutdown to make sure the NVMe cache is
> +		 * flushed. macOS actually does this by panicing (!)...
> +		 */
> +		if (state) {
> +			dev_crit(smcin->dev, "Triggering forced shutdown!\n");
> +			if (kernel_can_power_off())
> +				kernel_power_off();
> +			else /* Missing macsmc-reboot driver? */
> +				kernel_restart("SMC power button triggered restart");
> +		}
> +		break;
> +	default:
> +		dev_warn(smcin->dev, "Unknown SMC button event: %04lx\n", event & 0xffff);
> +	}
> +}
> +
> +static void macsmc_input_event_lid(struct macsmc_input *smcin, unsigned long event)
> +{
> +	u8 lid_state = !!((event >> 8) & 0xff);
> +
> +	pm_wakeup_dev_event(smcin->dev, 0, (smcin->wakeup_mode && !lid_state));
> +	input_report_switch(smcin->input, SW_LID, lid_state);
> +	input_sync(smcin->input);
> +}
> +
> +static int macsmc_input_event(struct notifier_block *nb, unsigned long event, void *data)
> +{
> +	struct macsmc_input *smcin = container_of(nb, struct macsmc_input, nb);
> +	u16 type = event >> 16;
> +
> +	switch (type) {
> +	case SMC_EV_BTN:
> +		macsmc_input_event_button(smcin, event);
> +		return NOTIFY_OK;
> +	case SMC_EV_LID:
> +		macsmc_input_event_lid(smcin, event);
> +		return NOTIFY_OK;
> +	default:
> +		/* SMC event meant for another driver */
> +		return NOTIFY_DONE;
> +	}
> +}
> +
> +static int macsmc_input_probe(struct platform_device *pdev)
> +{
> +	struct apple_smc *smc = dev_get_drvdata(pdev->dev.parent);
> +	struct macsmc_input *smcin;
> +	bool have_lid, have_power;
> +	int error;
> +
> +	/* Bail early if this SMC neither supports power button nor lid events */
> +	have_lid = apple_smc_key_exists(smc, SMC_KEY(MSLD));
> +	have_power = apple_smc_key_exists(smc, SMC_KEY(bHLD));
> +	if (!have_lid && !have_power)
> +		return -ENODEV;
> +
> +	smcin = devm_kzalloc(&pdev->dev, sizeof(*smcin), GFP_KERNEL);
> +	if (!smcin)
> +		return -ENOMEM;
> +
> +	smcin->dev = &pdev->dev;
> +	smcin->smc = smc;
> +	platform_set_drvdata(pdev, smcin);
> +
> +	smcin->input = devm_input_allocate_device(&pdev->dev);
> +	if (!smcin->input)
> +		return -ENOMEM;
> +
> +	smcin->input->phys = "macsmc-input (0)";
> +	smcin->input->name = "Apple SMC power/lid events";
> +
> +	if (have_lid)
> +		input_set_capability(smcin->input, EV_SW, SW_LID);
> +	if (have_power)
> +		input_set_capability(smcin->input, EV_KEY, KEY_POWER);
> +
> +	if (have_lid) {
> +		u8 val;
> +
> +		error = apple_smc_read_u8(smc, SMC_KEY(MSLD), &val);
> +		if (error < 0)
> +			dev_warn(&pdev->dev, "Failed to read initial lid state\n");
> +		else
> +			input_report_switch(smcin->input, SW_LID, val);
> +	}
> +
> +	if (have_power) {
> +		u32 val;
> +
> +		error = apple_smc_read_u32(smc, SMC_KEY(bHLD), &val);
> +		if (error < 0)
> +			dev_warn(&pdev->dev, "Failed to read initial power button state\n");
> +		else
> +			input_report_key(smcin->input, KEY_POWER, val & 1);
> +	}
> +
> +	error = input_register_device(smcin->input);
> +	if (error) {
> +		dev_err(&pdev->dev, "Failed to register input device: %d\n", error);
> +		return error;
> +	}
> +
> +	input_sync(smcin->input);
> +
> +	smcin->nb.notifier_call = macsmc_input_event;
> +	blocking_notifier_chain_register(&smc->event_handlers, &smcin->nb);
> +
> +	device_init_wakeup(&pdev->dev, true);
> +
> +	return 0;
> +}
> +
> +static int macsmc_input_pm_prepare(struct device *dev)
> +{
> +	struct macsmc_input *smcin = dev_get_drvdata(dev);
> +
> +	smcin->wakeup_mode = true;
> +	return 0;
> +}
> +
> +static void macsmc_input_pm_complete(struct device *dev)
> +{
> +	struct macsmc_input *smcin = dev_get_drvdata(dev);
> +
> +	smcin->wakeup_mode = false;
> +}
> +
> +static const struct dev_pm_ops macsmc_input_pm_ops = {
> +	.prepare = macsmc_input_pm_prepare,
> +	.complete = macsmc_input_pm_complete,
> +};
> +
> +static struct platform_driver macsmc_input_driver = {
> +	.driver = {
> +		.name = "macsmc-input",
> +		.pm = &macsmc_input_pm_ops,
> +	},
> +	.probe = macsmc_input_probe,
> +};
> +module_platform_driver(macsmc_input_driver);
> +
> +MODULE_AUTHOR("Hector Martin <marcan at marcan.st>");
> +MODULE_LICENSE("Dual MIT/GPL");
> +MODULE_DESCRIPTION("Apple SMC input driver");
> +MODULE_ALIAS("platform:macsmc-input");
> 

Best regards,
Nick Chan


From heiko at sntech.de  Mon Dec 22 05:56:28 2025
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 22 Dec 2025 14:56:28 +0100
Subject: [PATCH 0/3] Move RK3368 Lion ethernet phy to a mdio subnode
In-Reply-To: <20251020100757.3669681-1-heiko@sntech.de>
References: <20251020100757.3669681-1-heiko@sntech.de>
Message-ID: <176641178736.1651325.8963970192002690160.b4-ty@sntech.de>


On Mon, 20 Oct 2025 12:07:54 +0200, Heiko Stuebner wrote:
> Don't use deprecated snps properties to describe the phy reset,
> but instead add the mdio bus subnode to the gmac and correctly
> describe the phy there.
> 
> This will also help us later to handle a lion-specific oddity where
> the phy needs to enable its clock output for the needed mac clock.
> 
> [...]

Applied, thanks!

[1/3] arm64: dts: rockchip: add gmac reset property to rk3368
      commit: 396870f53c4e736366b4ed2e127874c30ce2f965
[2/3] arm64: dts: rockchip: add mdio subnode to gmac on rk3368
      commit: bce933a74b8e785a8090da74bee8ec3f38be40b7
[3/3] arm64: dts: rockchip: Correctly describe the ethernet phy on rk3368-lion
      commit: 1cb0958a26aeffe315a60b3cbbc56b94246cc25a

Best regards,
-- 
Heiko Stuebner <heiko at sntech.de>


From heiko at sntech.de  Mon Dec 22 05:56:30 2025
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 22 Dec 2025 14:56:30 +0100
Subject: [PATCH] arm64: dts: rockchip: Fix Bluetooth on the RockPro64 board
In-Reply-To: <20251130161259.9828-1-raphael.kernel@jakse.fr>
References: <20251130161259.9828-1-raphael.kernel@jakse.fr>
Message-ID: <176641178738.1651325.3752551269386396461.b4-ty@sntech.de>


On Sun, 30 Nov 2025 17:12:59 +0100, Rapha?l Jakse wrote:
> The RockPro64 board has an optional BCM4345C5 Bluetooth device on UART0.
> 
> This patch fixes audio stutters by setting its correct max-speed and
> compatible properties.
> 
> 

Applied, thanks!

[1/1] arm64: dts: rockchip: Fix Bluetooth on the RockPro64 board
      commit: 9c68a9483e31a9ad25c5399bb5f066b2e4980ad5

Best regards,
-- 
Heiko Stuebner <heiko at sntech.de>


From lkp at intel.com  Mon Dec 22 06:00:46 2025
From: lkp at intel.com (kernel test robot)
Date: Mon, 22 Dec 2025 22:00:46 +0800
Subject: [PATCH 5/6] dma-mapping: Allow batched DMA sync operations if
 supported by the arch
In-Reply-To: <20251219053658.84978-6-21cnbao@gmail.com>
References: <20251219053658.84978-6-21cnbao@gmail.com>
Message-ID: <202512222137.rpXOEE5p-lkp@intel.com>

Hi Barry,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on v6.19-rc2 next-20251219]
[cannot apply to arm64/for-next/core]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Barry-Song/arm64-Provide-dcache_by_myline_op_nosync-helper/20251219-195810
base:   linus/master
patch link:    https://lore.kernel.org/r/20251219053658.84978-6-21cnbao%40gmail.com
patch subject: [PATCH 5/6] dma-mapping: Allow batched DMA sync operations if supported by the arch
config: x86_64-randconfig-161-20251222 (https://download.01.org/0day-ci/archive/20251222/202512222137.rpXOEE5p-lkp at intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251222/202512222137.rpXOEE5p-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512222137.rpXOEE5p-lkp at intel.com/

All errors (new ones prefixed by >>):

   kernel/dma/direct.c: In function 'dma_direct_unmap_sg':
>> kernel/dma/direct.c:456:25: error: implicit declaration of function 'dma_direct_unmap_phys_batch_add'; did you mean 'dma_direct_unmap_phys'? [-Wimplicit-function-declaration]
     456 |                         dma_direct_unmap_phys_batch_add(dev, sg->dma_address,
         |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         |                         dma_direct_unmap_phys
   kernel/dma/direct.c: In function 'dma_direct_map_sg':
>> kernel/dma/direct.c:484:43: error: implicit declaration of function 'dma_direct_map_phys_batch_add'; did you mean 'dma_direct_map_phys'? [-Wimplicit-function-declaration]
     484 |                         sg->dma_address = dma_direct_map_phys_batch_add(dev, sg_phys(sg),
         |                                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         |                                           dma_direct_map_phys


vim +456 kernel/dma/direct.c

   439	
   440	/*
   441	 * Unmaps segments, except for ones marked as pci_p2pdma which do not
   442	 * require any further action as they contain a bus address.
   443	 */
   444	void dma_direct_unmap_sg(struct device *dev, struct scatterlist *sgl,
   445			int nents, enum dma_data_direction dir, unsigned long attrs)
   446	{
   447		struct scatterlist *sg;
   448		int i;
   449		bool need_sync = false;
   450	
   451		for_each_sg(sgl,  sg, nents, i) {
   452			if (sg_dma_is_bus_address(sg)) {
   453				sg_dma_unmark_bus_address(sg);
   454			} else {
   455				need_sync = true;
 > 456				dma_direct_unmap_phys_batch_add(dev, sg->dma_address,
   457						      sg_dma_len(sg), dir, attrs);
   458			}
   459		}
   460		if (need_sync && !dev_is_dma_coherent(dev))
   461			arch_sync_dma_batch_flush();
   462	}
   463	#endif
   464	
   465	int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
   466			enum dma_data_direction dir, unsigned long attrs)
   467	{
   468		struct pci_p2pdma_map_state p2pdma_state = {};
   469		struct scatterlist *sg;
   470		int i, ret;
   471		bool need_sync = false;
   472	
   473		for_each_sg(sgl, sg, nents, i) {
   474			switch (pci_p2pdma_state(&p2pdma_state, dev, sg_page(sg))) {
   475			case PCI_P2PDMA_MAP_THRU_HOST_BRIDGE:
   476				/*
   477				 * Any P2P mapping that traverses the PCI host bridge
   478				 * must be mapped with CPU physical address and not PCI
   479				 * bus addresses.
   480				 */
   481				break;
   482			case PCI_P2PDMA_MAP_NONE:
   483				need_sync = true;
 > 484				sg->dma_address = dma_direct_map_phys_batch_add(dev, sg_phys(sg),
   485						sg->length, dir, attrs);
   486				if (sg->dma_address == DMA_MAPPING_ERROR) {
   487					ret = -EIO;
   488					goto out_unmap;
   489				}
   490				break;
   491			case PCI_P2PDMA_MAP_BUS_ADDR:
   492				sg->dma_address = pci_p2pdma_bus_addr_map(
   493					p2pdma_state.mem, sg_phys(sg));
   494				sg_dma_len(sg) = sg->length;
   495				sg_dma_mark_bus_address(sg);
   496				continue;
   497			default:
   498				ret = -EREMOTEIO;
   499				goto out_unmap;
   500			}
   501			sg_dma_len(sg) = sg->length;
   502		}
   503	
   504		if (need_sync && !dev_is_dma_coherent(dev))
   505			arch_sync_dma_batch_flush();
   506		return nents;
   507	
   508	out_unmap:
   509		dma_direct_unmap_sg(dev, sgl, i, dir, attrs | DMA_ATTR_SKIP_CPU_SYNC);
   510		return ret;
   511	}
   512	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From pbonzini at redhat.com  Mon Dec 22 06:09:13 2025
From: pbonzini at redhat.com (Paolo Bonzini)
Date: Mon, 22 Dec 2025 15:09:13 +0100
Subject: possible deadlock due to irq_set_thread_affinity() calling into the
 scheduler (was Re: [PATCH v3 38/62] KVM: SVM: Take and hold ir_list_lock
 across IRTE updates in IOMMU)
In-Reply-To: <njhjud3e6wbdftzr3ziyuh5bhyvc5ndt5qvmg7rlvh5isoop2l@f2uxctws2c7d>
References: <20250611224604.313496-2-seanjc@google.com>
 <20250611224604.313496-40-seanjc@google.com>
 <njhjud3e6wbdftzr3ziyuh5bhyvc5ndt5qvmg7rlvh5isoop2l@f2uxctws2c7d>
Message-ID: <42513cb3-3c2e-4aa8-b748-23b6656a5096@redhat.com>

On 12/22/25 10:16, Ankit Soni wrote:
>    ======================================================
>    WARNING: possible circular locking dependency detected
>    6.19.0-rc2 #20 Tainted: G            E
>    ------------------------------------------------------
>    CPU 58/KVM/28597 is trying to acquire lock:
>      ff12c47d4b1f34c0 (&irq_desc_lock_class){-.-.}-{2:2}, at: __irq_get_desc_lock+0x58/0xa0
> 
>      but task is already holding lock:
>      ff12c49b28552110 (&svm->ir_list_lock){....}-{2:2}, at: avic_pi_update_irte+0x147/0x270 [kvm_amd]
> 
>      which lock already depends on the new lock.
> 
>    Chain exists of:
>      &irq_desc_lock_class --> &rq->__lock --> &svm->ir_list_lock
> 
>    Possible unsafe locking scenario:
> 
>          CPU0                            CPU1
>          ----                            ----
>     lock(&svm->ir_list_lock);
>                                        lock(&rq->__lock);
>                                        lock(&svm->ir_list_lock);
>     lock(&irq_desc_lock_class);
> 
>          *** DEADLOCK ***
> 
> So lockdep sees:
> 
>    &irq_desc_lock_class -> &rq->__lock -> &svm->ir_list_lock
> 
> while avic_pi_update_irte() currently holds svm->ir_list_lock and then
> takes irq_desc_lock via irq_set_vcpu_affinity(), which creates the
> potential inversion.
> 
>    - Is this lockdep warning expected/benign in this code path, or does it
>      indicate a real potential deadlock between svm->ir_list_lock and
>      irq_desc_lock with AVIC + irq_bypass + VFIO?

I'd treat it as a potential (if unlikely) deadlock:

(a) irq_set_thread_affinity triggers the scheduler via wake_up_process,
while irq_desc->lock is taken

(b) the scheduler calls into KVM with rq_lock taken, and KVM uses
ir_list_lock within __avic_vcpu_load/__avic_vcpu_put

(c) KVM wants to block scheduling for a while and uses ir_list_lock for
that purpose, but then takes irq_set_vcpu_affinity takes irq_desc->lock.

I don't think there's an alternative choice of lock for (c); and there's
no easy way to pull the irq_desc->lock out of the IRQ subsystem--in fact
the stickiness of the situation comes from rq->rq_lock and
irq_desc->lock being both internal and not leaf.

Of the three, the most sketchy is (a); notably, __setup_irq() calls
wake_up_process outside desc->lock.  Therefore I'd like so much to treat
it as a kernel/irq/ bug; and the simplest (perhaps too simple...) fix is
to drop the wake_up_process().  The only cost is extra latency on the
next interrupt after an affinity change.

diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 8b1b4c8a4f54..fc135bd079a4 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -189,14 +189,10 @@ static void irq_set_thread_affinity(struct irq_desc *desc)
  	struct irqaction *action;
  
  	for_each_action_of_desc(desc, action) {
-		if (action->thread) {
+		if (action->thread)
  			set_bit(IRQTF_AFFINITY, &action->thread_flags);
-			wake_up_process(action->thread);
-		}
-		if (action->secondary && action->secondary->thread) {
+		if (action->secondary && action->secondary->thread)
  			set_bit(IRQTF_AFFINITY, &action->secondary->thread_flags);
-			wake_up_process(action->secondary->thread);
-		}
  	}
  }
  
Marc, what do you think?

Paolo



From tudor.ambarus at linaro.org  Mon Dec 22 06:12:35 2025
From: tudor.ambarus at linaro.org (Tudor Ambarus)
Date: Mon, 22 Dec 2025 16:12:35 +0200
Subject: [PATCH v3 5/6] soc: samsung: exynos-chipid: add google,gs101-otp
 support
In-Reply-To: <653202f78f060b7e001b78604dd26d0f18ab76f9.camel@linaro.org>
References: <20251120-gs101-chipid-v3-0-1aeaa8b7fe35@linaro.org>
 <20251120-gs101-chipid-v3-5-1aeaa8b7fe35@linaro.org>
 <653202f78f060b7e001b78604dd26d0f18ab76f9.camel@linaro.org>
Message-ID: <e9a39590-39ce-43ae-8f44-1edd137d4ade@linaro.org>

Hi!

On 12/19/25 5:10 PM, Andr? Draszik wrote:

cut

>> ?static const char *exynos_product_id_to_name(unsigned int product_id)
>> @@ -93,19 +99,53 @@ static int exynos_chipid_get_chipid_info(struct device *dev,
>> ?		return dev_err_probe(dev, ret, "failed to read Product ID\n");
>> ?	soc_info->product_id = val & EXYNOS_MASK;
>> ?
>> -	if (data->rev_reg != EXYNOS_CHIPID_REG_PRO_ID) {
>> -		ret = regmap_read(regmap, data->rev_reg, &val);
>> +	if (data->sub_rev_reg == EXYNOS_CHIPID_REG_PRO_ID) {
>> +		/* exynos4210 case */
>> +		main_rev = (val >> data->main_rev_shift) & EXYNOS_REV_PART_MASK;
>> +		sub_rev = (val >> data->sub_rev_shift) & EXYNOS_REV_PART_MASK;
>> +	} else {
>> +		unsigned int val2;
>> +
>> +		ret = regmap_read(regmap, data->sub_rev_reg, &val2);
>> ?		if (ret < 0)
>> ?			return dev_err_probe(dev, ret,
>> ?					???? "failed to read revision\n");
>> +
>> +		if (data->main_rev_reg == EXYNOS_CHIPID_REG_PRO_ID)
>> +			/* gs101 case */
>> +			main_rev = (val >> data->main_rev_shift) & EXYNOS_REV_PART_MASK;
>> +		else
>> +			/* exynos850 case */
>> +			main_rev = (val2 >> data->main_rev_shift) & EXYNOS_REV_PART_MASK;
>> +
>> +		sub_rev = (val2 >> data->sub_rev_shift) & EXYNOS_REV_PART_MASK;
> 
> The above looks a little fragile, comparing register offsets between different
> hardware platforms and macros, but I guess it works for now and isn't really
> much different to before.

Right, I thought we'll get this in faster if I keep the old style.

I can introduce a drv_data->get_chipid_info() method and add methods for exynos4210
and exynos850 before adding the g101 support. It duplicated a bit the code when I
tried it, and I chose to keep it as it is now. Happy to switch to a drv data method
if you prefer, just say.

cut

>> @@ -127,10 +167,24 @@ static int exynos_chipid_probe(struct platform_device *pdev)
>> ?		return dev_err_probe(dev, -EINVAL,
>> ?				???? "failed to get match data\n");
>> ?
>> -	regmap = device_node_to_regmap(dev->of_node);
>> -	if (IS_ERR(regmap))
>> -		return dev_err_probe(dev, PTR_ERR(regmap),
>> -				???? "failed to get regmap\n");
>> +	if (drv_data->efuse) {
>> +		struct clk *clk;
>> +
>> +		regmap = exynos_chipid_get_efuse_regmap(pdev);
>> +		if (IS_ERR(regmap))
>> +			return dev_err_probe(dev, PTR_ERR(regmap),
>> +					???? "failed to get efuse regmap\n");
>> +
>> +		clk = devm_clk_get_enabled(dev, NULL);
>> +		if (IS_ERR(clk))
>> +			return dev_err_probe(dev, PTR_ERR(clk),
>> +					???? "failed to get clock\n");
> 
> Could you use devm_regmap_init_mmio_clk() instead?

Will do, thanks! I'll need to introduce a clock-names property in the bindings.

Cheers,
ta


From lkp at intel.com  Mon Dec 22 06:21:32 2025
From: lkp at intel.com (kernel test robot)
Date: Mon, 22 Dec 2025 15:21:32 +0100
Subject: [PATCH] dt-bindings: arm: Drop obsolete brcm,vulcan-soc binding
In-Reply-To: <20251215213022.3325133-1-robh@kernel.org>
References: <20251215213022.3325133-1-robh@kernel.org>
Message-ID: <202512221537.xL09XWuA-lkp@intel.com>

Hi Rob,

kernel test robot noticed the following build warnings:

[auto build test WARNING on robh/for-next]
[also build test WARNING on krzk/for-next krzk-mem-ctrl/for-next krzk-dt/for-next linus/master v6.19-rc2 next-20251219]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Rob-Herring-Arm/dt-bindings-arm-Drop-obsolete-brcm-vulcan-soc-binding/20251216-053906
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
patch link:    https://lore.kernel.org/r/20251215213022.3325133-1-robh%40kernel.org
patch subject: [PATCH] dt-bindings: arm: Drop obsolete brcm,vulcan-soc binding
reproduce: (https://download.01.org/0day-ci/archive/20251222/202512221537.xL09XWuA-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512221537.xL09XWuA-lkp at intel.com/

All warnings (new ones prefixed by >>):

   Warning: Documentation/translations/zh_CN/dev-tools/gdb-kernel-debugging.rst references a file that doesn't exist: Documentation/dev-tools/gdb-kernel-debugging.rst
   Warning: Documentation/translations/zh_CN/doc-guide/parse-headers.rst references a file that doesn't exist: Documentation/userspace-api/media/Makefile
   Warning: Documentation/translations/zh_CN/how-to.rst references a file that doesn't exist: Documentation/xxx/xxx.rst
   Warning: Documentation/translations/zh_TW/admin-guide/README.rst references a file that doesn't exist: Documentation/dev-tools/kgdb.rst
   Warning: Documentation/translations/zh_TW/dev-tools/gdb-kernel-debugging.rst references a file that doesn't exist: Documentation/dev-tools/gdb-kernel-debugging.rst
>> Warning: MAINTAINERS references a file that doesn't exist: Documentation/devicetree/bindings/arm/bcm/brcm,vulcan-soc.yaml
   Warning: MAINTAINERS references a file that doesn't exist: Documentation/sphinx/parse-headers.pl
   Warning: MAINTAINERS references a file that doesn't exist: Documentation/devicetree/bindings/media/mediatek-mdp.txt
   Warning: MAINTAINERS references a file that doesn't exist: Documentation/devicetree/bindings/display/bridge/megachips-stdpxxxx-ge-b850v3-fw.txt
   Warning: arch/powerpc/sysdev/mpic.c references a file that doesn't exist: Documentation/devicetree/bindings/powerpc/fsl/mpic.txt
   Warning: arch/riscv/kernel/kexec_image.c references a file that doesn't exist: Documentation/riscv/boot-image-header.rst

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From andre.draszik at linaro.org  Mon Dec 22 06:39:20 2025
From: andre.draszik at linaro.org (=?ISO-8859-1?Q?Andr=E9?= Draszik)
Date: Mon, 22 Dec 2025 14:39:20 +0000
Subject: [PATCH v3 5/6] soc: samsung: exynos-chipid: add
 google,gs101-otp support
In-Reply-To: <e9a39590-39ce-43ae-8f44-1edd137d4ade@linaro.org>
References: <20251120-gs101-chipid-v3-0-1aeaa8b7fe35@linaro.org>
	 <20251120-gs101-chipid-v3-5-1aeaa8b7fe35@linaro.org>
	 <653202f78f060b7e001b78604dd26d0f18ab76f9.camel@linaro.org>
	 <e9a39590-39ce-43ae-8f44-1edd137d4ade@linaro.org>
Message-ID: <a7af16e25ad6403e867a32d9d0f26931ac40199d.camel@linaro.org>

Hi Tudor,

On Mon, 2025-12-22 at 16:12 +0200, Tudor Ambarus wrote:
> Hi!
> 
> On 12/19/25 5:10 PM, Andr? Draszik wrote:
> 
> cut
> 
> > > ?static const char *exynos_product_id_to_name(unsigned int product_id)
> > > @@ -93,19 +99,53 @@ static int exynos_chipid_get_chipid_info(struct device *dev,
> > > ?		return dev_err_probe(dev, ret, "failed to read Product ID\n");
> > > ?	soc_info->product_id = val & EXYNOS_MASK;
> > > ?
> > > -	if (data->rev_reg != EXYNOS_CHIPID_REG_PRO_ID) {
> > > -		ret = regmap_read(regmap, data->rev_reg, &val);
> > > +	if (data->sub_rev_reg == EXYNOS_CHIPID_REG_PRO_ID) {
> > > +		/* exynos4210 case */
> > > +		main_rev = (val >> data->main_rev_shift) & EXYNOS_REV_PART_MASK;
> > > +		sub_rev = (val >> data->sub_rev_shift) & EXYNOS_REV_PART_MASK;
> > > +	} else {
> > > +		unsigned int val2;
> > > +
> > > +		ret = regmap_read(regmap, data->sub_rev_reg, &val2);
> > > ?		if (ret < 0)
> > > ?			return dev_err_probe(dev, ret,
> > > ?					???? "failed to read revision\n");
> > > +
> > > +		if (data->main_rev_reg == EXYNOS_CHIPID_REG_PRO_ID)
> > > +			/* gs101 case */
> > > +			main_rev = (val >> data->main_rev_shift) & EXYNOS_REV_PART_MASK;
> > > +		else
> > > +			/* exynos850 case */
> > > +			main_rev = (val2 >> data->main_rev_shift) & EXYNOS_REV_PART_MASK;
> > > +
> > > +		sub_rev = (val2 >> data->sub_rev_shift) & EXYNOS_REV_PART_MASK;
> > 
> > The above looks a little fragile, comparing register offsets between different
> > hardware platforms and macros, but I guess it works for now and isn't really
> > much different to before.
> 
> Right, I thought we'll get this in faster if I keep the old style.
> 
> I can introduce a drv_data->get_chipid_info() method and add methods for exynos4210
> and exynos850 before adding the g101 support. It duplicated a bit the code when I
> tried it, and I chose to keep it as it is now. Happy to switch to a drv data method
> if you prefer, just say.

The above was simply an observation, and as mentioned it's not really worse than
before, therefore OK to leave from my pov.


Cheers,
A.


From bartosz.golaszewski at oss.qualcomm.com  Mon Dec 22 07:02:35 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Mon, 22 Dec 2025 16:02:35 +0100
Subject: [PATCH] clk: mediatek: don't select clk-mt8192 for all ARM64 builds
Message-ID: <20251222150235.34919-1-bartosz.golaszewski@oss.qualcomm.com>

This option defaults to y for ARCH64 meaning it's built even if we don't
want anything related to mediatek. Make the default condition stricter
and only build it if ARCH_MEDIATEK is selected.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/clk/mediatek/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
index 0e8dd82aa84e..2c09fd729bab 100644
--- a/drivers/clk/mediatek/Kconfig
+++ b/drivers/clk/mediatek/Kconfig
@@ -820,7 +820,7 @@ config COMMON_CLK_MT8192
 	depends on ARM64 || COMPILE_TEST
 	select COMMON_CLK_MEDIATEK
 	select COMMON_CLK_MEDIATEK_FHCTL
-	default ARM64
+	default ARM64 && ARCH_MEDIATEK
 	help
 	  This driver supports MediaTek MT8192 basic clocks.
 
-- 
2.47.3



From james.clark at linaro.org  Mon Dec 22 07:14:25 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 22 Dec 2025 15:14:25 +0000
Subject: [PATCH v4 00/14] perf cs-etm/arm-spe: Remove hard coded config
 fields
Message-ID: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>

The specific config field that an event format attribute is in is
consistently hard coded, even though the API is supposed to be that the
driver publishes the config field name. To stop this pattern from being
copy pasted and causing problems in the future, replace them all with
calls to a new helper that returns the value that a user set.

This reveals some issues in evsel__set_config_if_unset(). It doesn't
work with sparse bitfields, which are an unused but documented feature.
And it also only writes to the attr.config field. To fix it we need to
start tracking user changes for all config fields and then use existing
helper functions that support sparse bitfields. Some other refactoring
was also required and a test was added.

---
Changes in v4:
- Constify some function args (Ian)
- Move some evsel__* functions to evsel.c and make some pmu.c functions
  public to support this (Ian)
- Drop pmu arg where it can be fetched from evsel->pmu (Ian)
- Link to v3: https://lore.kernel.org/r/20251212-james-perf-config-bits-v3-0-aa36a4846776 at linaro.org

Changes in v3:
- Fix uninitialized variable warning on GCC
- Fix leak of evlist in test
- Confirm no type punning issues with ubsan (Ian)
- Link to v2: https://lore.kernel.org/r/20251208-james-perf-config-bits-v2-0-4ac0281993b0 at linaro.org

Changes in v2:
- Remove macros in get_config_chgs() and some other refactoring.
- Support sparse bitfields in evsel__set_config_if_unset().
- Always track user changes instead of only when
  'pmu->perf_event_attr_init_default' is set.
- Add a test.
- Don't bail out in cs-etm.c if any format fields are missing (Leo).
- Rename 'guess' to 'synth' (Mike).
- Link to v1: https://lore.kernel.org/r/20251201-james-perf-config-bits-v1-0-22ecbbf8007c at linaro.org

---
James Clark (14):
      perf parse-events: Refactor get_config_terms() to remove macros
      perf evsel: Refactor evsel__set_config_if_unset() arguments
      perf evsel: Move evsel__* functions to evsel.c
      perf evsel: Support sparse fields in evsel__set_config_if_unset()
      perf parse-events: Track all user changed config bits
      perf evsel: apply evsel__set_config_if_unset() to all config fields
      perf evsel: Add a helper to get the value of a config field
      perf parse-events: Always track user config changes
      perf tests: Test evsel__set_config_if_unset() and config change tracking
      perf cs-etm: Make a helper to find the Coresight evsel
      perf cs-etm: Don't use hard coded config bits when setting up ETMCR
      perf cs-etm: Don't use hard coded config bits when setting up TRCCONFIGR
      perf cs-etm: Don't hard code config attribute when configuring the event
      perf arm-spe: Don't hard code config attribute

 tools/perf/arch/arm/util/cs-etm.c    | 201 +++++++++++++++-------------
 tools/perf/arch/arm64/util/arm-spe.c |  17 +--
 tools/perf/arch/x86/util/intel-pt.c  |   3 +-
 tools/perf/tests/pmu.c               |  91 +++++++++++++
 tools/perf/util/evsel.c              | 112 +++++++++++++++-
 tools/perf/util/evsel.h              |   6 +-
 tools/perf/util/evsel_config.h       |   7 +-
 tools/perf/util/parse-events.c       | 248 ++++++++++++++++++++---------------
 tools/perf/util/pmu.c                |  95 ++++----------
 tools/perf/util/pmu.h                |  34 ++++-
 10 files changed, 529 insertions(+), 285 deletions(-)
---
base-commit: cbd41c6d4c26c161a2b0e70ad411d3885ff13507
change-id: 20251112-james-perf-config-bits-bee7106f0f00

Best regards,
-- 
James Clark <james.clark at linaro.org>



From james.clark at linaro.org  Mon Dec 22 07:14:26 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 22 Dec 2025 15:14:26 +0000
Subject: [PATCH v4 01/14] perf parse-events: Refactor get_config_terms() to
 remove macros
In-Reply-To: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
References: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
Message-ID: <20251222-james-perf-config-bits-v4-1-0608438186fc@linaro.org>

The ADD_CONFIG_TERM() macros build the __type argument out of a partial
EVSEL__CONFIG_TERM_x enum name. This means that they can't be called
from a function where __type is a variable and it's also impossible to
grep the codebase to find usages of these enums as they're never typed
in full.

Fix this by removing the macros and replacing them with an
add_config_term() function. It seems the main reason these existed in
the first place was to avoid type punning and to write to a specific
field in the union, but the same thing can be achieved with a single
write to a u64 'val' field.

Running the Perf tests with "-fsanitize=undefined -fno-sanitize-recover"
results in no new issues as a result of this change.

Reviewed-by: Ian Rogers <irogers at google.com>
Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/util/evsel_config.h |   1 +
 tools/perf/util/parse-events.c | 146 ++++++++++++++++++++++++-----------------
 2 files changed, 86 insertions(+), 61 deletions(-)

diff --git a/tools/perf/util/evsel_config.h b/tools/perf/util/evsel_config.h
index bcd3a978f0c4..685fd8d5c4a8 100644
--- a/tools/perf/util/evsel_config.h
+++ b/tools/perf/util/evsel_config.h
@@ -50,6 +50,7 @@ struct evsel_config_term {
 		u64	      cfg_chg;
 		char	      *str;
 		int	      cpu;
+		u64	      val;
 	} val;
 	bool weak;
 };
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 17c1c36a7bf9..46422286380f 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1116,105 +1116,107 @@ static int config_attr(struct perf_event_attr *attr,
 	return 0;
 }
 
-static int get_config_terms(const struct parse_events_terms *head_config,
-			    struct list_head *head_terms)
+static struct evsel_config_term *add_config_term(enum evsel_term_type type,
+						 struct list_head *head_terms,
+						 bool weak)
 {
-#define ADD_CONFIG_TERM(__type, __weak)				\
-	struct evsel_config_term *__t;			\
-								\
-	__t = zalloc(sizeof(*__t));				\
-	if (!__t)						\
-		return -ENOMEM;					\
-								\
-	INIT_LIST_HEAD(&__t->list);				\
-	__t->type       = EVSEL__CONFIG_TERM_ ## __type;	\
-	__t->weak	= __weak;				\
-	list_add_tail(&__t->list, head_terms)
-
-#define ADD_CONFIG_TERM_VAL(__type, __name, __val, __weak)	\
-do {								\
-	ADD_CONFIG_TERM(__type, __weak);			\
-	__t->val.__name = __val;				\
-} while (0)
+	struct evsel_config_term *t;
 
-#define ADD_CONFIG_TERM_STR(__type, __val, __weak)		\
-do {								\
-	ADD_CONFIG_TERM(__type, __weak);			\
-	__t->val.str = strdup(__val);				\
-	if (!__t->val.str) {					\
-		zfree(&__t);					\
-		return -ENOMEM;					\
-	}							\
-	__t->free_str = true;					\
-} while (0)
+	t = zalloc(sizeof(*t));
+	if (!t)
+		return NULL;
+
+	INIT_LIST_HEAD(&t->list);
+	t->type = type;
+	t->weak	= weak;
+	list_add_tail(&t->list, head_terms);
 
+	return t;
+}
+
+static int get_config_terms(const struct parse_events_terms *head_config,
+			    struct list_head *head_terms)
+{
 	struct parse_events_term *term;
 
 	list_for_each_entry(term, &head_config->terms, list) {
+		struct evsel_config_term *new_term;
+		enum evsel_term_type new_type;
+		bool str_type = false;
+		u64 val;
+
 		switch (term->type_term) {
 		case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
-			ADD_CONFIG_TERM_VAL(PERIOD, period, term->val.num, term->weak);
+			new_type = EVSEL__CONFIG_TERM_PERIOD;
+			val = term->val.num;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ:
-			ADD_CONFIG_TERM_VAL(FREQ, freq, term->val.num, term->weak);
+			new_type = EVSEL__CONFIG_TERM_FREQ;
+			val = term->val.num;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_TIME:
-			ADD_CONFIG_TERM_VAL(TIME, time, term->val.num, term->weak);
+			new_type = EVSEL__CONFIG_TERM_TIME;
+			val = term->val.num;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_CALLGRAPH:
-			ADD_CONFIG_TERM_STR(CALLGRAPH, term->val.str, term->weak);
+			new_type = EVSEL__CONFIG_TERM_CALLGRAPH;
+			str_type = true;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
-			ADD_CONFIG_TERM_STR(BRANCH, term->val.str, term->weak);
+			new_type = EVSEL__CONFIG_TERM_BRANCH;
+			str_type = true;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
-			ADD_CONFIG_TERM_VAL(STACK_USER, stack_user,
-					    term->val.num, term->weak);
+			new_type = EVSEL__CONFIG_TERM_STACK_USER;
+			val = term->val.num;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_INHERIT:
-			ADD_CONFIG_TERM_VAL(INHERIT, inherit,
-					    term->val.num ? 1 : 0, term->weak);
+			new_type = EVSEL__CONFIG_TERM_INHERIT;
+			val = term->val.num ? 1 : 0;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_NOINHERIT:
-			ADD_CONFIG_TERM_VAL(INHERIT, inherit,
-					    term->val.num ? 0 : 1, term->weak);
+			new_type = EVSEL__CONFIG_TERM_INHERIT;
+			val = term->val.num ? 0 : 1;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_MAX_STACK:
-			ADD_CONFIG_TERM_VAL(MAX_STACK, max_stack,
-					    term->val.num, term->weak);
+			new_type = EVSEL__CONFIG_TERM_MAX_STACK;
+			val = term->val.num;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS:
-			ADD_CONFIG_TERM_VAL(MAX_EVENTS, max_events,
-					    term->val.num, term->weak);
+			new_type = EVSEL__CONFIG_TERM_MAX_EVENTS;
+			val = term->val.num;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_OVERWRITE:
-			ADD_CONFIG_TERM_VAL(OVERWRITE, overwrite,
-					    term->val.num ? 1 : 0, term->weak);
+			new_type = EVSEL__CONFIG_TERM_OVERWRITE;
+			val = term->val.num ? 1 : 0;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE:
-			ADD_CONFIG_TERM_VAL(OVERWRITE, overwrite,
-					    term->val.num ? 0 : 1, term->weak);
+			new_type = EVSEL__CONFIG_TERM_OVERWRITE;
+			val = term->val.num ? 0 : 1;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_DRV_CFG:
-			ADD_CONFIG_TERM_STR(DRV_CFG, term->val.str, term->weak);
+			new_type = EVSEL__CONFIG_TERM_DRV_CFG;
+			str_type = true;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_PERCORE:
-			ADD_CONFIG_TERM_VAL(PERCORE, percore,
-					    term->val.num ? true : false, term->weak);
+			new_type = EVSEL__CONFIG_TERM_PERCORE;
+			val = term->val.num ? true : false;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT:
-			ADD_CONFIG_TERM_VAL(AUX_OUTPUT, aux_output,
-					    term->val.num ? 1 : 0, term->weak);
+			new_type = EVSEL__CONFIG_TERM_AUX_OUTPUT;
+			val = term->val.num ? 1 : 0;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_AUX_ACTION:
-			ADD_CONFIG_TERM_STR(AUX_ACTION, term->val.str, term->weak);
+			new_type = EVSEL__CONFIG_TERM_AUX_ACTION;
+			str_type = true;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE:
-			ADD_CONFIG_TERM_VAL(AUX_SAMPLE_SIZE, aux_sample_size,
-					    term->val.num, term->weak);
+			new_type = EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE;
+			val = term->val.num;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV:
-			ADD_CONFIG_TERM_STR(RATIO_TO_PREV, term->val.str, term->weak);
+			new_type = EVSEL__CONFIG_TERM_RATIO_TO_PREV;
+			str_type = true;
 			break;
 		case PARSE_EVENTS__TERM_TYPE_USER:
 		case PARSE_EVENTS__TERM_TYPE_CONFIG:
@@ -1229,7 +1231,23 @@ do {								\
 		case PARSE_EVENTS__TERM_TYPE_RAW:
 		case PARSE_EVENTS__TERM_TYPE_CPU:
 		default:
-			break;
+			/* Don't add a new term for these ones */
+			continue;
+		}
+
+		new_term = add_config_term(new_type, head_terms, term->weak);
+		if (!new_term)
+			return -ENOMEM;
+
+		if (str_type) {
+			new_term->val.str = strdup(term->val.str);
+			if (!new_term->val.str) {
+				zfree(&new_term);
+				return -ENOMEM;
+			}
+			new_term->free_str = true;
+		} else {
+			new_term->val.val = val;
 		}
 	}
 	return 0;
@@ -1290,10 +1308,16 @@ static int get_config_chgs(struct perf_pmu *pmu, struct parse_events_terms *head
 		}
 	}
 
-	if (bits)
-		ADD_CONFIG_TERM_VAL(CFG_CHG, cfg_chg, bits, false);
+	if (bits) {
+		struct evsel_config_term *new_term;
+
+		new_term = add_config_term(EVSEL__CONFIG_TERM_CFG_CHG,
+					   head_terms, false);
+		if (!new_term)
+			return -ENOMEM;
+		new_term->val.cfg_chg = bits;
+	}
 
-#undef ADD_CONFIG_TERM
 	return 0;
 }
 

-- 
2.34.1



From james.clark at linaro.org  Mon Dec 22 07:14:27 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 22 Dec 2025 15:14:27 +0000
Subject: [PATCH v4 02/14] perf evsel: Refactor evsel__set_config_if_unset()
 arguments
In-Reply-To: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
References: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
Message-ID: <20251222-james-perf-config-bits-v4-2-0608438186fc@linaro.org>

Make the evsel argument first to match the other evsel__* functions
and remove the redundant pmu argument, which can be accessed via evsel.

Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/arch/arm/util/cs-etm.c    | 9 +++------
 tools/perf/arch/arm64/util/arm-spe.c | 2 +-
 tools/perf/arch/x86/util/intel-pt.c  | 3 +--
 tools/perf/util/evsel.h              | 4 ++--
 tools/perf/util/pmu.c                | 6 +++---
 5 files changed, 10 insertions(+), 14 deletions(-)

diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
index ea891d12f8f4..c28208361d91 100644
--- a/tools/perf/arch/arm/util/cs-etm.c
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -441,10 +441,8 @@ static int cs_etm_recording_options(struct auxtrace_record *itr,
 	 * when a context switch happened.
 	 */
 	if (!perf_cpu_map__is_any_cpu_or_is_empty(cpus)) {
-		evsel__set_config_if_unset(cs_etm_pmu, cs_etm_evsel,
-					   "timestamp", 1);
-		evsel__set_config_if_unset(cs_etm_pmu, cs_etm_evsel,
-					   "contextid", 1);
+		evsel__set_config_if_unset(cs_etm_evsel, "timestamp", 1);
+		evsel__set_config_if_unset(cs_etm_evsel, "contextid", 1);
 	}
 
 	/*
@@ -453,8 +451,7 @@ static int cs_etm_recording_options(struct auxtrace_record *itr,
 	 * timestamp tracing.
 	 */
 	if (opts->sample_time_set)
-		evsel__set_config_if_unset(cs_etm_pmu, cs_etm_evsel,
-					   "timestamp", 1);
+		evsel__set_config_if_unset(cs_etm_evsel, "timestamp", 1);
 
 	/* Add dummy event to keep tracking */
 	err = parse_event(evlist, "dummy:u");
diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c
index d5ec1408d0ae..51014f8bff97 100644
--- a/tools/perf/arch/arm64/util/arm-spe.c
+++ b/tools/perf/arch/arm64/util/arm-spe.c
@@ -274,7 +274,7 @@ static void arm_spe_setup_evsel(struct evsel *evsel, struct perf_cpu_map *cpus)
 	 */
 	if (!perf_cpu_map__is_any_cpu_or_is_empty(cpus)) {
 		evsel__set_sample_bit(evsel, CPU);
-		evsel__set_config_if_unset(evsel->pmu, evsel, "ts_enable", 1);
+		evsel__set_config_if_unset(evsel, "ts_enable", 1);
 	}
 
 	/*
diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c
index b394ad9cc635..c131a727774f 100644
--- a/tools/perf/arch/x86/util/intel-pt.c
+++ b/tools/perf/arch/x86/util/intel-pt.c
@@ -664,8 +664,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr,
 		return 0;
 
 	if (opts->auxtrace_sample_mode)
-		evsel__set_config_if_unset(intel_pt_pmu, intel_pt_evsel,
-					   "psb_period", 0);
+		evsel__set_config_if_unset(intel_pt_evsel, "psb_period", 0);
 
 	err = intel_pt_validate_config(intel_pt_pmu, intel_pt_evsel);
 	if (err)
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index a08130ff2e47..2cf87bc67df7 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -575,8 +575,8 @@ void evsel__uniquify_counter(struct evsel *counter);
 	((((src) >> (pos)) & ((1ull << (size)) - 1)) << (63 - ((pos) + (size) - 1)))
 
 u64 evsel__bitfield_swap_branch_flags(u64 value);
-void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
-				const char *config_name, u64 val);
+void evsel__set_config_if_unset(struct evsel *evsel, const char *config_name,
+				u64 val);
 
 bool evsel__is_offcpu_event(struct evsel *evsel);
 
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 956ea273c2c7..e87c12946d71 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -1382,8 +1382,8 @@ bool evsel__is_aux_event(const struct evsel *evsel)
  * something to true, pass 1 for val rather than a pre shifted value.
  */
 #define field_prep(_mask, _val) (((_val) << (ffsll(_mask) - 1)) & (_mask))
-void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
-				const char *config_name, u64 val)
+void evsel__set_config_if_unset(struct evsel *evsel, const char *config_name,
+				u64 val)
 {
 	u64 user_bits = 0, bits;
 	struct evsel_config_term *term = evsel__get_config_term(evsel, CFG_CHG);
@@ -1391,7 +1391,7 @@ void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
 	if (term)
 		user_bits = term->val.cfg_chg;
 
-	bits = perf_pmu__format_bits(pmu, config_name);
+	bits = perf_pmu__format_bits(evsel->pmu, config_name);
 
 	/* Do nothing if the user changed the value */
 	if (bits & user_bits)

-- 
2.34.1



From james.clark at linaro.org  Mon Dec 22 07:14:28 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 22 Dec 2025 15:14:28 +0000
Subject: [PATCH v4 03/14] perf evsel: Move evsel__* functions to evsel.c
In-Reply-To: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
References: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
Message-ID: <20251222-james-perf-config-bits-v4-3-0608438186fc@linaro.org>

At least one of these were put here to avoid a Python binding linking
issue which is no longer present. Put them back in their correct
location to avoid confusion about which file to add a new evsel__*
function to later.

Link: https://lore.kernel.org/all/ZEbAS2yx2fguW60w at kernel.org/
Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/util/evsel.c | 40 ++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/pmu.c   | 40 ----------------------------------------
 2 files changed, 40 insertions(+), 40 deletions(-)

diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index ec6552a6f667..21878e9bd029 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1314,6 +1314,35 @@ struct evsel_config_term *__evsel__get_config_term(struct evsel *evsel, enum evs
 	return found_term;
 }
 
+/*
+ * Set @config_name to @val as long as the user hasn't already set or cleared it
+ * by passing a config term on the command line.
+ *
+ * @val is the value to put into the bits specified by @config_name rather than
+ * the bit pattern. It is shifted into position by this function, so to set
+ * something to true, pass 1 for val rather than a pre shifted value.
+ */
+#define field_prep(_mask, _val) (((_val) << (ffsll(_mask) - 1)) & (_mask))
+void evsel__set_config_if_unset(struct evsel *evsel, const char *config_name,
+				u64 val)
+{
+	u64 user_bits = 0, bits;
+	struct evsel_config_term *term = evsel__get_config_term(evsel, CFG_CHG);
+
+	if (term)
+		user_bits = term->val.cfg_chg;
+
+	bits = perf_pmu__format_bits(evsel->pmu, config_name);
+
+	/* Do nothing if the user changed the value */
+	if (bits & user_bits)
+		return;
+
+	/* Otherwise replace it */
+	evsel->core.attr.config &= ~bits;
+	evsel->core.attr.config |= field_prep(bits, val);
+}
+
 void __weak arch_evsel__set_sample_weight(struct evsel *evsel)
 {
 	evsel__set_sample_bit(evsel, WEIGHT);
@@ -4098,6 +4127,17 @@ void evsel__set_leader(struct evsel *evsel, struct evsel *leader)
 	evsel->core.leader = &leader->core;
 }
 
+bool evsel__is_aux_event(const struct evsel *evsel)
+{
+	struct perf_pmu *pmu;
+
+	if (evsel->needs_auxtrace_mmap)
+		return true;
+
+	pmu = evsel__find_pmu(evsel);
+	return pmu && pmu->auxtrace;
+}
+
 int evsel__source_count(const struct evsel *evsel)
 {
 	struct evsel *pos;
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index e87c12946d71..e3a1f26213ec 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -1362,46 +1362,6 @@ void perf_pmu__warn_invalid_formats(struct perf_pmu *pmu)
 	}
 }
 
-bool evsel__is_aux_event(const struct evsel *evsel)
-{
-	struct perf_pmu *pmu;
-
-	if (evsel->needs_auxtrace_mmap)
-		return true;
-
-	pmu = evsel__find_pmu(evsel);
-	return pmu && pmu->auxtrace;
-}
-
-/*
- * Set @config_name to @val as long as the user hasn't already set or cleared it
- * by passing a config term on the command line.
- *
- * @val is the value to put into the bits specified by @config_name rather than
- * the bit pattern. It is shifted into position by this function, so to set
- * something to true, pass 1 for val rather than a pre shifted value.
- */
-#define field_prep(_mask, _val) (((_val) << (ffsll(_mask) - 1)) & (_mask))
-void evsel__set_config_if_unset(struct evsel *evsel, const char *config_name,
-				u64 val)
-{
-	u64 user_bits = 0, bits;
-	struct evsel_config_term *term = evsel__get_config_term(evsel, CFG_CHG);
-
-	if (term)
-		user_bits = term->val.cfg_chg;
-
-	bits = perf_pmu__format_bits(evsel->pmu, config_name);
-
-	/* Do nothing if the user changed the value */
-	if (bits & user_bits)
-		return;
-
-	/* Otherwise replace it */
-	evsel->core.attr.config &= ~bits;
-	evsel->core.attr.config |= field_prep(bits, val);
-}
-
 static struct perf_pmu_format *
 pmu_find_format(const struct list_head *formats, const char *name)
 {

-- 
2.34.1



From james.clark at linaro.org  Mon Dec 22 07:14:29 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 22 Dec 2025 15:14:29 +0000
Subject: [PATCH v4 04/14] perf evsel: Support sparse fields in
 evsel__set_config_if_unset()
In-Reply-To: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
References: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
Message-ID: <20251222-james-perf-config-bits-v4-4-0608438186fc@linaro.org>

Sparse config fields are technically supported although currently
unused. field_prep() only works for contiguous bitfields so replace it
with pmu_format_value().

Reviewed-by: Ian Rogers <irogers at google.com>
Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/util/evsel.c | 4 +---
 tools/perf/util/pmu.c   | 3 +--
 tools/perf/util/pmu.h   | 1 +
 3 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 21878e9bd029..45ab97beeb34 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1322,7 +1322,6 @@ struct evsel_config_term *__evsel__get_config_term(struct evsel *evsel, enum evs
  * the bit pattern. It is shifted into position by this function, so to set
  * something to true, pass 1 for val rather than a pre shifted value.
  */
-#define field_prep(_mask, _val) (((_val) << (ffsll(_mask) - 1)) & (_mask))
 void evsel__set_config_if_unset(struct evsel *evsel, const char *config_name,
 				u64 val)
 {
@@ -1339,8 +1338,7 @@ void evsel__set_config_if_unset(struct evsel *evsel, const char *config_name,
 		return;
 
 	/* Otherwise replace it */
-	evsel->core.attr.config &= ~bits;
-	evsel->core.attr.config |= field_prep(bits, val);
+	pmu_format_value(&bits, val, &evsel->core.attr.config, /*zero=*/true);
 }
 
 void __weak arch_evsel__set_sample_weight(struct evsel *evsel)
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index e3a1f26213ec..599fdf5e28ba 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -1404,8 +1404,7 @@ int perf_pmu__format_type(struct perf_pmu *pmu, const char *name)
  * Sets value based on the format definition (format parameter)
  * and unformatted value (value parameter).
  */
-static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
-			     bool zero)
+void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, bool zero)
 {
 	unsigned long fbit, vbit;
 
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 8f11bfe8ed6d..e34db47ae5ef 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -254,6 +254,7 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_
 			  u64 *alternate_hw_config, struct parse_events_error *err);
 int perf_pmu__find_event(struct perf_pmu *pmu, const char *event, void *state, pmu_event_callback cb);
 
+void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, bool zero);
 void perf_pmu_format__set_value(void *format, int config, unsigned long *bits);
 bool perf_pmu__has_format(const struct perf_pmu *pmu, const char *name);
 int perf_pmu__for_each_format(struct perf_pmu *pmu, void *state, pmu_format_callback cb);

-- 
2.34.1



From james.clark at linaro.org  Mon Dec 22 07:14:30 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 22 Dec 2025 15:14:30 +0000
Subject: [PATCH v4 05/14] perf parse-events: Track all user changed config
 bits
In-Reply-To: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
References: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
Message-ID: <20251222-james-perf-config-bits-v4-5-0608438186fc@linaro.org>

Currently we only track which bits were set by the user in attr->config.
But all configN fields should be treated equally as they can all have
default and user overridden values.

Track them all by making get_config_chgs() generic and calling it once
for each config value.

Reviewed-by: Ian Rogers <irogers at google.com>
Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/util/evsel.c        |  9 +++-
 tools/perf/util/evsel_config.h |  6 ++-
 tools/perf/util/parse-events.c | 98 +++++++++++++++++++++++-------------------
 tools/perf/util/pmu.c          |  4 +-
 tools/perf/util/pmu.h          |  4 +-
 5 files changed, 70 insertions(+), 51 deletions(-)

diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 45ab97beeb34..354e28e94523 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1242,7 +1242,11 @@ static void evsel__apply_config_terms(struct evsel *evsel,
 		case EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE:
 			/* Already applied by auxtrace */
 			break;
-		case EVSEL__CONFIG_TERM_CFG_CHG:
+		case EVSEL__CONFIG_TERM_USR_CHG_CONFIG:
+		case EVSEL__CONFIG_TERM_USR_CHG_CONFIG1:
+		case EVSEL__CONFIG_TERM_USR_CHG_CONFIG2:
+		case EVSEL__CONFIG_TERM_USR_CHG_CONFIG3:
+		case EVSEL__CONFIG_TERM_USR_CHG_CONFIG4:
 			break;
 		case EVSEL__CONFIG_TERM_RATIO_TO_PREV:
 			rtp_buf = term->val.str;
@@ -1326,7 +1330,8 @@ void evsel__set_config_if_unset(struct evsel *evsel, const char *config_name,
 				u64 val)
 {
 	u64 user_bits = 0, bits;
-	struct evsel_config_term *term = evsel__get_config_term(evsel, CFG_CHG);
+	struct evsel_config_term *term = evsel__get_config_term(evsel,
+								USR_CHG_CONFIG);
 
 	if (term)
 		user_bits = term->val.cfg_chg;
diff --git a/tools/perf/util/evsel_config.h b/tools/perf/util/evsel_config.h
index 685fd8d5c4a8..7b565d76c0bc 100644
--- a/tools/perf/util/evsel_config.h
+++ b/tools/perf/util/evsel_config.h
@@ -27,7 +27,11 @@ enum evsel_term_type {
 	EVSEL__CONFIG_TERM_AUX_OUTPUT,
 	EVSEL__CONFIG_TERM_AUX_ACTION,
 	EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE,
-	EVSEL__CONFIG_TERM_CFG_CHG,
+	EVSEL__CONFIG_TERM_USR_CHG_CONFIG,
+	EVSEL__CONFIG_TERM_USR_CHG_CONFIG1,
+	EVSEL__CONFIG_TERM_USR_CHG_CONFIG2,
+	EVSEL__CONFIG_TERM_USR_CHG_CONFIG3,
+	EVSEL__CONFIG_TERM_USR_CHG_CONFIG4,
 	EVSEL__CONFIG_TERM_RATIO_TO_PREV,
 };
 
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 46422286380f..1f6e2213326d 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1253,66 +1253,32 @@ static int get_config_terms(const struct parse_events_terms *head_config,
 	return 0;
 }
 
-/*
- * Add EVSEL__CONFIG_TERM_CFG_CHG where cfg_chg will have a bit set for
- * each bit of attr->config that the user has changed.
- */
-static int get_config_chgs(struct perf_pmu *pmu, struct parse_events_terms *head_config,
-			   struct list_head *head_terms)
+static int add_cfg_chg(const struct perf_pmu *pmu,
+		       const struct parse_events_terms *head_config,
+		       struct list_head *head_terms,
+		       int format_type,
+		       enum parse_events__term_type term_type,
+		       enum evsel_term_type new_term_type)
 {
 	struct parse_events_term *term;
 	u64 bits = 0;
 	int type;
 
 	list_for_each_entry(term, &head_config->terms, list) {
-		switch (term->type_term) {
-		case PARSE_EVENTS__TERM_TYPE_USER:
+		if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER) {
 			type = perf_pmu__format_type(pmu, term->config);
-			if (type != PERF_PMU_FORMAT_VALUE_CONFIG)
+			if (type != format_type)
 				continue;
 			bits |= perf_pmu__format_bits(pmu, term->config);
-			break;
-		case PARSE_EVENTS__TERM_TYPE_CONFIG:
+		} else if (term->type_term == term_type) {
 			bits = ~(u64)0;
-			break;
-		case PARSE_EVENTS__TERM_TYPE_CONFIG1:
-		case PARSE_EVENTS__TERM_TYPE_CONFIG2:
-		case PARSE_EVENTS__TERM_TYPE_CONFIG3:
-		case PARSE_EVENTS__TERM_TYPE_CONFIG4:
-		case PARSE_EVENTS__TERM_TYPE_LEGACY_HARDWARE_CONFIG:
-		case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE_CONFIG:
-		case PARSE_EVENTS__TERM_TYPE_NAME:
-		case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
-		case PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ:
-		case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
-		case PARSE_EVENTS__TERM_TYPE_TIME:
-		case PARSE_EVENTS__TERM_TYPE_CALLGRAPH:
-		case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
-		case PARSE_EVENTS__TERM_TYPE_NOINHERIT:
-		case PARSE_EVENTS__TERM_TYPE_INHERIT:
-		case PARSE_EVENTS__TERM_TYPE_MAX_STACK:
-		case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS:
-		case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE:
-		case PARSE_EVENTS__TERM_TYPE_OVERWRITE:
-		case PARSE_EVENTS__TERM_TYPE_DRV_CFG:
-		case PARSE_EVENTS__TERM_TYPE_PERCORE:
-		case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT:
-		case PARSE_EVENTS__TERM_TYPE_AUX_ACTION:
-		case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE:
-		case PARSE_EVENTS__TERM_TYPE_METRIC_ID:
-		case PARSE_EVENTS__TERM_TYPE_RAW:
-		case PARSE_EVENTS__TERM_TYPE_CPU:
-		case PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV:
-		default:
-			break;
 		}
 	}
 
 	if (bits) {
 		struct evsel_config_term *new_term;
 
-		new_term = add_config_term(EVSEL__CONFIG_TERM_CFG_CHG,
-					   head_terms, false);
+		new_term = add_config_term(new_term_type, head_terms, false);
 		if (!new_term)
 			return -ENOMEM;
 		new_term->val.cfg_chg = bits;
@@ -1321,6 +1287,50 @@ static int get_config_chgs(struct perf_pmu *pmu, struct parse_events_terms *head
 	return 0;
 }
 
+/*
+ * Add EVSEL__CONFIG_TERM_USR_CFG_CONFIGn where cfg_chg will have a bit set for
+ * each bit of attr->configN that the user has changed.
+ */
+static int get_config_chgs(const struct perf_pmu *pmu,
+			   const struct parse_events_terms *head_config,
+			   struct list_head *head_terms)
+{
+	int ret;
+
+	ret = add_cfg_chg(pmu, head_config, head_terms,
+			  PERF_PMU_FORMAT_VALUE_CONFIG,
+			  PARSE_EVENTS__TERM_TYPE_CONFIG,
+			  EVSEL__CONFIG_TERM_USR_CHG_CONFIG);
+	if (ret)
+		return ret;
+
+	ret = add_cfg_chg(pmu, head_config, head_terms,
+			  PERF_PMU_FORMAT_VALUE_CONFIG1,
+			  PARSE_EVENTS__TERM_TYPE_CONFIG1,
+			  EVSEL__CONFIG_TERM_USR_CHG_CONFIG1);
+	if (ret)
+		return ret;
+
+	ret = add_cfg_chg(pmu, head_config, head_terms,
+			  PERF_PMU_FORMAT_VALUE_CONFIG2,
+			  PARSE_EVENTS__TERM_TYPE_CONFIG2,
+			  EVSEL__CONFIG_TERM_USR_CHG_CONFIG2);
+	if (ret)
+		return ret;
+
+	ret = add_cfg_chg(pmu, head_config, head_terms,
+			  PERF_PMU_FORMAT_VALUE_CONFIG3,
+			  PARSE_EVENTS__TERM_TYPE_CONFIG3,
+			  EVSEL__CONFIG_TERM_USR_CHG_CONFIG3);
+	if (ret)
+		return ret;
+
+	return add_cfg_chg(pmu, head_config, head_terms,
+			   PERF_PMU_FORMAT_VALUE_CONFIG4,
+			   PARSE_EVENTS__TERM_TYPE_CONFIG4,
+			   EVSEL__CONFIG_TERM_USR_CHG_CONFIG4);
+}
+
 int parse_events_add_tracepoint(struct parse_events_state *parse_state,
 				struct list_head *list,
 				const char *sys, const char *event,
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 599fdf5e28ba..2fe92b4b6e02 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -1374,7 +1374,7 @@ pmu_find_format(const struct list_head *formats, const char *name)
 	return NULL;
 }
 
-__u64 perf_pmu__format_bits(struct perf_pmu *pmu, const char *name)
+__u64 perf_pmu__format_bits(const struct perf_pmu *pmu, const char *name)
 {
 	struct perf_pmu_format *format = pmu_find_format(&pmu->format, name);
 	__u64 bits = 0;
@@ -1389,7 +1389,7 @@ __u64 perf_pmu__format_bits(struct perf_pmu *pmu, const char *name)
 	return bits;
 }
 
-int perf_pmu__format_type(struct perf_pmu *pmu, const char *name)
+int perf_pmu__format_type(const struct perf_pmu *pmu, const char *name)
 {
 	struct perf_pmu_format *format = pmu_find_format(&pmu->format, name);
 
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index e34db47ae5ef..7bf5b23d0ea1 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -247,8 +247,8 @@ int perf_pmu__config_terms(const struct perf_pmu *pmu,
 			   struct parse_events_terms *terms,
 			   bool zero, bool apply_hardcoded,
 			   struct parse_events_error *error);
-__u64 perf_pmu__format_bits(struct perf_pmu *pmu, const char *name);
-int perf_pmu__format_type(struct perf_pmu *pmu, const char *name);
+__u64 perf_pmu__format_bits(const struct perf_pmu *pmu, const char *name);
+int perf_pmu__format_type(const struct perf_pmu *pmu, const char *name);
 int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_terms,
 			  struct perf_pmu_info *info, bool *rewrote_terms,
 			  u64 *alternate_hw_config, struct parse_events_error *err);

-- 
2.34.1



From james.clark at linaro.org  Mon Dec 22 07:14:31 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 22 Dec 2025 15:14:31 +0000
Subject: [PATCH v4 06/14] perf evsel: apply evsel__set_config_if_unset() to
 all config fields
In-Reply-To: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
References: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
Message-ID: <20251222-james-perf-config-bits-v4-6-0608438186fc@linaro.org>

Misleadingly, evsel__set_config_if_unset() only works with the config
field and not config1, config2, etc. This is fine at the moment because
all users of it happen to operate on bits that are in that config field.
Fix it before there are any new users of the function which operate on
bits in different config fields.

In theory it's also possible for a driver to move an existing bit to
another config field and this fixes that scenario too, although this
hasn't happened yet either.

Reviewed-by: Ian Rogers <irogers at google.com>
Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/util/evsel.c | 37 ++++++++++++++++++++++++++++++++++---
 tools/perf/util/pmu.c   | 29 ++---------------------------
 tools/perf/util/pmu.h   | 27 +++++++++++++++++++++++++++
 3 files changed, 63 insertions(+), 30 deletions(-)

diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 354e28e94523..b863096ed568 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1330,8 +1330,39 @@ void evsel__set_config_if_unset(struct evsel *evsel, const char *config_name,
 				u64 val)
 {
 	u64 user_bits = 0, bits;
-	struct evsel_config_term *term = evsel__get_config_term(evsel,
-								USR_CHG_CONFIG);
+	struct evsel_config_term *term;
+	struct perf_pmu_format *format = pmu_find_format(&evsel->pmu->format,
+							 config_name);
+	__u64 *vp;
+
+	if (!format)
+		return;
+
+	switch (format->value) {
+	case PERF_PMU_FORMAT_VALUE_CONFIG:
+		term = evsel__get_config_term(evsel, USR_CHG_CONFIG);
+		vp = &evsel->core.attr.config;
+		break;
+	case PERF_PMU_FORMAT_VALUE_CONFIG1:
+		term = evsel__get_config_term(evsel, USR_CHG_CONFIG1);
+		vp = &evsel->core.attr.config1;
+		break;
+	case PERF_PMU_FORMAT_VALUE_CONFIG2:
+		term = evsel__get_config_term(evsel, USR_CHG_CONFIG2);
+		vp = &evsel->core.attr.config2;
+		break;
+	case PERF_PMU_FORMAT_VALUE_CONFIG3:
+		term = evsel__get_config_term(evsel, USR_CHG_CONFIG3);
+		vp = &evsel->core.attr.config3;
+		break;
+	case PERF_PMU_FORMAT_VALUE_CONFIG4:
+		term = evsel__get_config_term(evsel, USR_CHG_CONFIG4);
+		vp = &evsel->core.attr.config4;
+		break;
+	default:
+		pr_err("Unknown format value: %d\n", format->value);
+		return;
+	}
 
 	if (term)
 		user_bits = term->val.cfg_chg;
@@ -1343,7 +1374,7 @@ void evsel__set_config_if_unset(struct evsel *evsel, const char *config_name,
 		return;
 
 	/* Otherwise replace it */
-	pmu_format_value(&bits, val, &evsel->core.attr.config, /*zero=*/true);
+	pmu_format_value(&bits, val, vp, /*zero=*/true);
 }
 
 void __weak arch_evsel__set_sample_weight(struct evsel *evsel)
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 2fe92b4b6e02..dc5dab69151f 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -118,31 +118,6 @@ struct perf_pmu_alias {
 	bool info_loaded;
 };
 
-/**
- * struct perf_pmu_format - Values from a format file read from
- * <sysfs>/devices/cpu/format/ held in struct perf_pmu.
- *
- * For example, the contents of <sysfs>/devices/cpu/format/event may be
- * "config:0-7" and will be represented here as name="event",
- * value=PERF_PMU_FORMAT_VALUE_CONFIG and bits 0 to 7 will be set.
- */
-struct perf_pmu_format {
-	/** @list: Element on list within struct perf_pmu. */
-	struct list_head list;
-	/** @bits: Which config bits are set by this format value. */
-	DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
-	/** @name: The modifier/file name. */
-	char *name;
-	/**
-	 * @value : Which config value the format relates to. Supported values
-	 * are from PERF_PMU_FORMAT_VALUE_CONFIG to
-	 * PERF_PMU_FORMAT_VALUE_CONFIG_END.
-	 */
-	u16 value;
-	/** @loaded: Has the contents been loaded/parsed. */
-	bool loaded;
-};
-
 static int pmu_aliases_parse(struct perf_pmu *pmu);
 
 static struct perf_pmu_format *perf_pmu__new_format(struct list_head *list, char *name)
@@ -1362,8 +1337,8 @@ void perf_pmu__warn_invalid_formats(struct perf_pmu *pmu)
 	}
 }
 
-static struct perf_pmu_format *
-pmu_find_format(const struct list_head *formats, const char *name)
+struct perf_pmu_format *pmu_find_format(const struct list_head *formats,
+					const char *name)
 {
 	struct perf_pmu_format *format;
 
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 7bf5b23d0ea1..7655d996090a 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -233,6 +233,31 @@ struct pmu_event_info {
 	bool deprecated;
 };
 
+/**
+ * struct perf_pmu_format - Values from a format file read from
+ * <sysfs>/devices/cpu/format/ held in struct perf_pmu.
+ *
+ * For example, the contents of <sysfs>/devices/cpu/format/event may be
+ * "config:0-7" and will be represented here as name="event",
+ * value=PERF_PMU_FORMAT_VALUE_CONFIG and bits 0 to 7 will be set.
+ */
+struct perf_pmu_format {
+	/** @list: Element on list within struct perf_pmu. */
+	struct list_head list;
+	/** @bits: Which config bits are set by this format value. */
+	DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
+	/** @name: The modifier/file name. */
+	char *name;
+	/**
+	 * @value : Which config value the format relates to. Supported values
+	 * are from PERF_PMU_FORMAT_VALUE_CONFIG to
+	 * PERF_PMU_FORMAT_VALUE_CONFIG_END.
+	 */
+	u16 value;
+	/** @loaded: Has the contents been loaded/parsed. */
+	bool loaded;
+};
+
 typedef int (*pmu_event_callback)(void *state, struct pmu_event_info *info);
 typedef int (*pmu_format_callback)(void *state, const char *name, int config,
 				   const unsigned long *bits);
@@ -255,6 +280,8 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_
 int perf_pmu__find_event(struct perf_pmu *pmu, const char *event, void *state, pmu_event_callback cb);
 
 void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, bool zero);
+struct perf_pmu_format *pmu_find_format(const struct list_head *formats,
+					const char *name);
 void perf_pmu_format__set_value(void *format, int config, unsigned long *bits);
 bool perf_pmu__has_format(const struct perf_pmu *pmu, const char *name);
 int perf_pmu__for_each_format(struct perf_pmu *pmu, void *state, pmu_format_callback cb);

-- 
2.34.1



From james.clark at linaro.org  Mon Dec 22 07:14:32 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 22 Dec 2025 15:14:32 +0000
Subject: [PATCH v4 07/14] perf evsel: Add a helper to get the value of a
 config field
In-Reply-To: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
References: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
Message-ID: <20251222-james-perf-config-bits-v4-7-0608438186fc@linaro.org>

This will be used by aux PMUs to read an already written value for
configuring their events and for also testing.

Its helper perf_pmu__format_unpack() does the opposite of the existing
pmu_format_value() so rename that one to perf_pmu__format_pack() so it's
clear how they are related.

Reviewed-by: Ian Rogers <irogers at google.com>
Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/util/evsel.c | 38 +++++++++++++++++++++++++++++++++++++-
 tools/perf/util/evsel.h |  2 ++
 tools/perf/util/pmu.c   | 35 ++++++++++++++++++++++++++++-------
 tools/perf/util/pmu.h   |  4 +++-
 4 files changed, 70 insertions(+), 9 deletions(-)

diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index b863096ed568..703a6f73d468 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1374,7 +1374,43 @@ void evsel__set_config_if_unset(struct evsel *evsel, const char *config_name,
 		return;
 
 	/* Otherwise replace it */
-	pmu_format_value(&bits, val, vp, /*zero=*/true);
+	perf_pmu__format_pack(&bits, val, vp, /*zero=*/true);
+}
+
+
+int evsel__get_config_val(const struct evsel *evsel, const char *config_name,
+			  u64 *val)
+{
+	struct perf_pmu_format *format = pmu_find_format(&evsel->pmu->format, config_name);
+	u64 bits = perf_pmu__format_bits(evsel->pmu, config_name);
+
+	if (!format || !bits) {
+		pr_err("Unknown/empty format name: %s\n", config_name);
+		*val = 0;
+		return -EINVAL;
+	}
+
+	switch (format->value) {
+	case PERF_PMU_FORMAT_VALUE_CONFIG:
+		*val = perf_pmu__format_unpack(bits, evsel->core.attr.config);
+		return 0;
+	case PERF_PMU_FORMAT_VALUE_CONFIG1:
+		*val = perf_pmu__format_unpack(bits, evsel->core.attr.config1);
+		return 0;
+	case PERF_PMU_FORMAT_VALUE_CONFIG2:
+		*val = perf_pmu__format_unpack(bits, evsel->core.attr.config2);
+		return 0;
+	case PERF_PMU_FORMAT_VALUE_CONFIG3:
+		*val = perf_pmu__format_unpack(bits, evsel->core.attr.config3);
+		return 0;
+	case PERF_PMU_FORMAT_VALUE_CONFIG4:
+		*val = perf_pmu__format_unpack(bits, evsel->core.attr.config4);
+		return 0;
+	default:
+		pr_err("Unknown format value: %d\n", format->value);
+		*val = 0;
+		return -EINVAL;
+	}
 }
 
 void __weak arch_evsel__set_sample_weight(struct evsel *evsel)
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 2cf87bc67df7..95c4bd0f0f2e 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -575,6 +575,8 @@ void evsel__uniquify_counter(struct evsel *counter);
 	((((src) >> (pos)) & ((1ull << (size)) - 1)) << (63 - ((pos) + (size) - 1)))
 
 u64 evsel__bitfield_swap_branch_flags(u64 value);
+int evsel__get_config_val(const struct evsel *evsel, const char *config_name,
+			  u64 *val);
 void evsel__set_config_if_unset(struct evsel *evsel, const char *config_name,
 				u64 val);
 
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index dc5dab69151f..626c7307c8a3 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -1337,6 +1337,26 @@ void perf_pmu__warn_invalid_formats(struct perf_pmu *pmu)
 	}
 }
 
+/*
+ * Unpacks a raw config[n] value using the sparse bitfield that defines a
+ * format attr. For example "config1:1,6-7,44" defines a 4 bit value across non
+ * contiguous bits and this function returns those 4 bits as a value.
+ */
+u64 perf_pmu__format_unpack(u64 format, u64 config_val)
+{
+	int val_bit = 0;
+	u64 res = 0;
+	int fmt_bit;
+
+	for_each_set_bit(fmt_bit, &format, PERF_PMU_FORMAT_BITS) {
+		if (test_bit(fmt_bit, &config_val))
+			res |= BIT_ULL(val_bit);
+
+		val_bit++;
+	}
+	return res;
+}
+
 struct perf_pmu_format *pmu_find_format(const struct list_head *formats,
 					const char *name)
 {
@@ -1379,7 +1399,8 @@ int perf_pmu__format_type(const struct perf_pmu *pmu, const char *name)
  * Sets value based on the format definition (format parameter)
  * and unformatted value (value parameter).
  */
-void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, bool zero)
+void perf_pmu__format_pack(unsigned long *format, __u64 value, __u64 *v,
+			   bool zero)
 {
 	unsigned long fbit, vbit;
 
@@ -1496,23 +1517,23 @@ static int pmu_config_term(const struct perf_pmu *pmu,
 		switch (term->type_term) {
 		case PARSE_EVENTS__TERM_TYPE_CONFIG:
 			assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
-			pmu_format_value(bits, term->val.num, &attr->config, zero);
+			perf_pmu__format_pack(bits, term->val.num, &attr->config, zero);
 			break;
 		case PARSE_EVENTS__TERM_TYPE_CONFIG1:
 			assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
-			pmu_format_value(bits, term->val.num, &attr->config1, zero);
+			perf_pmu__format_pack(bits, term->val.num, &attr->config1, zero);
 			break;
 		case PARSE_EVENTS__TERM_TYPE_CONFIG2:
 			assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
-			pmu_format_value(bits, term->val.num, &attr->config2, zero);
+			perf_pmu__format_pack(bits, term->val.num, &attr->config2, zero);
 			break;
 		case PARSE_EVENTS__TERM_TYPE_CONFIG3:
 			assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
-			pmu_format_value(bits, term->val.num, &attr->config3, zero);
+			perf_pmu__format_pack(bits, term->val.num, &attr->config3, zero);
 			break;
 		case PARSE_EVENTS__TERM_TYPE_CONFIG4:
 			assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
-			pmu_format_value(bits, term->val.num, &attr->config4, zero);
+			perf_pmu__format_pack(bits, term->val.num, &attr->config4, zero);
 			break;
 		case PARSE_EVENTS__TERM_TYPE_LEGACY_HARDWARE_CONFIG:
 			assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
@@ -1650,7 +1671,7 @@ static int pmu_config_term(const struct perf_pmu *pmu,
 		 */
 	}
 
-	pmu_format_value(format->bits, val, vp, zero);
+	perf_pmu__format_pack(format->bits, val, vp, zero);
 	return 0;
 }
 
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 7655d996090a..a1255b3a8f91 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -279,12 +279,14 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_
 			  u64 *alternate_hw_config, struct parse_events_error *err);
 int perf_pmu__find_event(struct perf_pmu *pmu, const char *event, void *state, pmu_event_callback cb);
 
-void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, bool zero);
+void perf_pmu__format_pack(unsigned long *format, __u64 value, __u64 *v,
+			   bool zero);
 struct perf_pmu_format *pmu_find_format(const struct list_head *formats,
 					const char *name);
 void perf_pmu_format__set_value(void *format, int config, unsigned long *bits);
 bool perf_pmu__has_format(const struct perf_pmu *pmu, const char *name);
 int perf_pmu__for_each_format(struct perf_pmu *pmu, void *state, pmu_format_callback cb);
+u64 perf_pmu__format_unpack(u64 format, u64 config_val);
 
 bool is_pmu_core(const char *name);
 bool perf_pmu__supports_legacy_cache(const struct perf_pmu *pmu);

-- 
2.34.1



From james.clark at linaro.org  Mon Dec 22 07:14:33 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 22 Dec 2025 15:14:33 +0000
Subject: [PATCH v4 08/14] perf parse-events: Always track user config
 changes
In-Reply-To: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
References: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
Message-ID: <20251222-james-perf-config-bits-v4-8-0608438186fc@linaro.org>

Requiring the 'pmu->perf_event_attr_init_default' callback to be set to
track user changes is a bit of a trap to fall in. It's hard to see that
this is required when depending on the user change tracking.

It's possible to want all 0 defaults so not set it, but at the same time
still do some programmatic setting of configs with
evsel__set_config_if_unset(). Also if a PMU reverts to 0 defaults and
deletes its existing callback, it will silently break existing uses of
evsel__set_config_if_unset().

One way to fix this would be to assert in evsel__set_config_if_unset()
if the changes weren't tracked, but that would be a possibly untested
runtime failure. Instead, always track it as it's harmless and
simplifies testing too.

Reviewed-by: Ian Rogers <irogers at google.com>
Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/util/parse-events.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 1f6e2213326d..c8f2962a06c7 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1528,12 +1528,8 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state,
 		return -ENOMEM;
 	}
 
-	/*
-	 * When using default config, record which bits of attr->config were
-	 * changed by the user.
-	 */
-	if (pmu->perf_event_attr_init_default &&
-	    get_config_chgs(pmu, &parsed_terms, &config_terms)) {
+	/* Record which bits of attr->config were changed by the user. */
+	if (get_config_chgs(pmu, &parsed_terms, &config_terms)) {
 		parse_events_terms__exit(&parsed_terms);
 		return -ENOMEM;
 	}

-- 
2.34.1



From james.clark at linaro.org  Mon Dec 22 07:14:34 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 22 Dec 2025 15:14:34 +0000
Subject: [PATCH v4 09/14] perf tests: Test evsel__set_config_if_unset() and
 config change tracking
In-Reply-To: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
References: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
Message-ID: <20251222-james-perf-config-bits-v4-9-0608438186fc@linaro.org>

Test that evsel__set_config_if_unset() behaves as expected. This also
tests the user config change tracking mechanism as it depends on it.

Reviewed-by: Ian Rogers <irogers at google.com>
Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/tests/pmu.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 91 insertions(+)

diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c
index cbded2c6faa4..0ebf2d7b2cb4 100644
--- a/tools/perf/tests/pmu.c
+++ b/tools/perf/tests/pmu.c
@@ -192,12 +192,102 @@ static int test__pmu_format(struct test_suite *test __maybe_unused, int subtest
 	}
 	if (attr.config2 != 0x0400000020041d07) {
 		pr_err("Unexpected config2 value %llx\n", attr.config2);
+	}
+
+	ret = TEST_OK;
+err_out:
+	parse_events_terms__exit(&terms);
+	test_pmu_put(dir, pmu);
+	return ret;
+}
+
+static int test__pmu_usr_chgs(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
+{
+	const char *event = "perf-pmu-test/config=15,config1=4,krava02=170,"
+			    "krava03=1,krava11=27,krava12=1/";
+	struct parse_events_terms terms;
+	struct parse_events_error err;
+	LIST_HEAD(config_terms);
+	struct evlist *evlist;
+	struct perf_pmu *pmu;
+	struct evsel *evsel;
+	int ret = TEST_FAIL;
+	char dir[PATH_MAX];
+	u64 val;
+
+	pmu = test_pmu_get(dir, sizeof(dir));
+	if (!pmu)
+		return TEST_FAIL;
+
+	evlist = evlist__new();
+	if (evlist == NULL) {
+		pr_err("Failed allocation");
+		goto err_out;
+	}
+
+	parse_events_terms__init(&terms);
+	ret = parse_events(evlist, event, &err);
+	if (ret) {
+		pr_debug("failed to parse event '%s', err %d\n", event, ret);
+		parse_events_error__print(&err, event);
+		if (parse_events_error__contains(&err, "can't access trace events"))
+			ret = TEST_SKIP;
 		goto err_out;
 	}
+	evsel = evlist__first(evlist);
+
+	/*
+	 * Set via config=15, krava01 bits 0-1
+	 * Set via config1=4, krava11 bit 1
+	 * Set values: krava02=170, krava03=1, krava11=27, krava12=1
+	 *
+	 * Test that already set values aren't overwritten.
+	 */
+	evsel__set_config_if_unset(evsel, "krava01", 16);
+	evsel__get_config_val(evsel, "krava01", &val);
+	TEST_ASSERT_EQUAL("krava01 overwritten", (int) val, (15 & 0b11));
+
+	evsel__set_config_if_unset(evsel, "krava11", 45);
+	evsel__get_config_val(evsel, "krava11", &val);
+	TEST_ASSERT_EQUAL("krava11 overwritten", (int) val, (27 | (4 << 1)));
+
+	evsel__set_config_if_unset(evsel, "krava02", 32);
+	evsel__get_config_val(evsel, "krava02", &val);
+	TEST_ASSERT_EQUAL("krava02 overwritten", (int) val, 170);
+
+	evsel__set_config_if_unset(evsel, "krava03", 0);
+	evsel__get_config_val(evsel, "krava03", &val);
+	TEST_ASSERT_EQUAL("krava03 overwritten", (int) val, 1);
+
+	/*
+	 * krava13 doesn't have any bits set by either krava13= or config1=
+	 * but setting _any_ raw value for config1 implies that krava13
+	 * shouldn't be overwritten. So it's value should remain as 0.
+	 */
+	evsel__set_config_if_unset(evsel, "krava13", 5);
+	evsel__get_config_val(evsel, "krava13", &val);
+	TEST_ASSERT_EQUAL("krava13 overwritten", (int) val, 0);
+
+	/*
+	 * Unset values: krava21, krava22, krava23
+	 *
+	 * Test that unset values are overwritten.
+	 */
+	evsel__set_config_if_unset(evsel, "krava21", 13905);
+	evsel__get_config_val(evsel, "krava21", &val);
+	TEST_ASSERT_EQUAL("krava21 not overwritten", (int) val, 13905);
+
+	evsel__set_config_if_unset(evsel, "krava22", 11);
+	evsel__get_config_val(evsel, "krava22", &val);
+	TEST_ASSERT_EQUAL("krava22 not overwritten", (int) val, 11);
 
+	evsel__set_config_if_unset(evsel, "krava23", 0);
+	evsel__get_config_val(evsel, "krava23", &val);
+	TEST_ASSERT_EQUAL("krava23 not overwritten", (int) val, 0);
 	ret = TEST_OK;
 err_out:
 	parse_events_terms__exit(&terms);
+	evlist__delete(evlist);
 	test_pmu_put(dir, pmu);
 	return ret;
 }
@@ -539,6 +629,7 @@ static struct test_case tests__pmu[] = {
 	TEST_CASE("PMU name combining", name_len),
 	TEST_CASE("PMU name comparison", name_cmp),
 	TEST_CASE("PMU cmdline match", pmu_match),
+	TEST_CASE("PMU user config changes", pmu_usr_chgs),
 	{	.name = NULL, }
 };
 

-- 
2.34.1



From james.clark at linaro.org  Mon Dec 22 07:14:35 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 22 Dec 2025 15:14:35 +0000
Subject: [PATCH v4 10/14] perf cs-etm: Make a helper to find the Coresight
 evsel
In-Reply-To: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
References: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
Message-ID: <20251222-james-perf-config-bits-v4-10-0608438186fc@linaro.org>

This pattern occurs a few times and we'll add another one later, so add
a helper function for it.

Reviewed-by: Leo Yan <leo.yan at arm.com>
Reviewed-by: Ian Rogers <irogers at google.com>
Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/arch/arm/util/cs-etm.c | 50 +++++++++++++++++++++------------------
 1 file changed, 27 insertions(+), 23 deletions(-)

diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
index c28208361d91..a49753f0d20f 100644
--- a/tools/perf/arch/arm/util/cs-etm.c
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -302,6 +302,19 @@ static int cs_etm_set_sink_attr(struct perf_pmu *pmu,
 	return 0;
 }
 
+static struct evsel *cs_etm_get_evsel(struct evlist *evlist,
+				      struct perf_pmu *cs_etm_pmu)
+{
+	struct evsel *evsel;
+
+	evlist__for_each_entry(evlist, evsel) {
+		if (evsel->core.attr.type == cs_etm_pmu->type)
+			return evsel;
+	}
+
+	return NULL;
+}
+
 static int cs_etm_recording_options(struct auxtrace_record *itr,
 				    struct evlist *evlist,
 				    struct record_opts *opts)
@@ -473,29 +486,21 @@ static int cs_etm_recording_options(struct auxtrace_record *itr,
 
 static u64 cs_etm_get_config(struct auxtrace_record *itr)
 {
-	u64 config = 0;
 	struct cs_etm_recording *ptr =
 			container_of(itr, struct cs_etm_recording, itr);
 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
 	struct evlist *evlist = ptr->evlist;
-	struct evsel *evsel;
+	struct evsel *evsel = cs_etm_get_evsel(evlist, cs_etm_pmu);
 
-	evlist__for_each_entry(evlist, evsel) {
-		if (evsel->core.attr.type == cs_etm_pmu->type) {
-			/*
-			 * Variable perf_event_attr::config is assigned to
-			 * ETMv3/PTM.  The bit fields have been made to match
-			 * the ETMv3.5 ETRMCR register specification.  See the
-			 * PMU_FORMAT_ATTR() declarations in
-			 * drivers/hwtracing/coresight/coresight-perf.c for
-			 * details.
-			 */
-			config = evsel->core.attr.config;
-			break;
-		}
-	}
-
-	return config;
+	/*
+	 * Variable perf_event_attr::config is assigned to
+	 * ETMv3/PTM.  The bit fields have been made to match
+	 * the ETMv3.5 ETRMCR register specification.  See the
+	 * PMU_FORMAT_ATTR() declarations in
+	 * drivers/hwtracing/coresight/coresight-perf.c for
+	 * details.
+	 */
+	return evsel ? evsel->core.attr.config : 0;
 }
 
 #ifndef BIT
@@ -829,12 +834,11 @@ static int cs_etm_snapshot_start(struct auxtrace_record *itr)
 {
 	struct cs_etm_recording *ptr =
 			container_of(itr, struct cs_etm_recording, itr);
-	struct evsel *evsel;
+	struct evsel *evsel = cs_etm_get_evsel(ptr->evlist, ptr->cs_etm_pmu);
+
+	if (evsel)
+		return evsel__disable(evsel);
 
-	evlist__for_each_entry(ptr->evlist, evsel) {
-		if (evsel->core.attr.type == ptr->cs_etm_pmu->type)
-			return evsel__disable(evsel);
-	}
 	return -EINVAL;
 }
 

-- 
2.34.1



From james.clark at linaro.org  Mon Dec 22 07:14:37 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 22 Dec 2025 15:14:37 +0000
Subject: [PATCH v4 12/14] perf cs-etm: Don't use hard coded config bits
 when setting up TRCCONFIGR
In-Reply-To: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
References: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
Message-ID: <20251222-james-perf-config-bits-v4-12-0608438186fc@linaro.org>

Perf only looks at attr.config when determining what was programmed into
TRCCONFIGR. These bits could theoretically be in any of the config
fields. Use the evsel__get_config_val() helper so it's agnostic to
which config field they are in.

The kernel will also stop publishing the TRCCONFIGR register bits in a
header [1] so preempt that by defining them here.

[1]: https://lore.kernel.org/linux-arm-kernel/20251128-james-cs-syncfreq-v8-10-4d319764cc58 at linaro.org/

Reviewed-by: Leo Yan <leo.yan at arm.com>
Reviewed-by: Ian Rogers <irogers at google.com>
Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/arch/arm/util/cs-etm.c | 79 +++++++++++++++++----------------------
 1 file changed, 34 insertions(+), 45 deletions(-)

diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
index f535027ce862..12b28562c2f3 100644
--- a/tools/perf/arch/arm/util/cs-etm.c
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -68,6 +68,14 @@ static const char * const metadata_ete_ro[] = {
 
 enum cs_etm_version { CS_NOT_PRESENT, CS_ETMV3, CS_ETMV4, CS_ETE };
 
+/* ETMv4 CONFIGR register bits */
+#define TRCCONFIGR_BB		BIT(3)
+#define TRCCONFIGR_CCI		BIT(4)
+#define TRCCONFIGR_CID		BIT(6)
+#define TRCCONFIGR_VMID		BIT(7)
+#define TRCCONFIGR_TS		BIT(11)
+#define TRCCONFIGR_RS		BIT(12)
+#define TRCCONFIGR_VMIDOPT	BIT(15)
 
 /* ETMv3 ETMCR register bits */
 #define ETMCR_CYC_ACC		BIT(12)
@@ -517,56 +525,37 @@ static u64 cs_etm_synth_etmcr(struct auxtrace_record *itr)
 	return etmcr;
 }
 
-static u64 cs_etm_get_config(struct auxtrace_record *itr)
+static u64 cs_etmv4_synth_trcconfigr(struct auxtrace_record *itr)
 {
+	u64 trcconfigr = 0;
 	struct cs_etm_recording *ptr =
-			container_of(itr, struct cs_etm_recording, itr);
+		container_of(itr, struct cs_etm_recording, itr);
 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
-	struct evlist *evlist = ptr->evlist;
-	struct evsel *evsel = cs_etm_get_evsel(evlist, cs_etm_pmu);
-
-	/*
-	 * Variable perf_event_attr::config is assigned to
-	 * ETMv3/PTM.  The bit fields have been made to match
-	 * the ETMv3.5 ETRMCR register specification.  See the
-	 * PMU_FORMAT_ATTR() declarations in
-	 * drivers/hwtracing/coresight/coresight-perf.c for
-	 * details.
-	 */
-	return evsel ? evsel->core.attr.config : 0;
-}
-
-#ifndef BIT
-#define BIT(N) (1UL << (N))
-#endif
+	struct evsel *evsel = cs_etm_get_evsel(ptr->evlist, cs_etm_pmu);
+	u64 val;
 
-static u64 cs_etmv4_get_config(struct auxtrace_record *itr)
-{
-	u64 config = 0;
-	u64 config_opts = 0;
+	if (!evsel)
+		return 0;
 
 	/*
-	 * The perf event variable config bits represent both
-	 * the command line options and register programming
-	 * bits in ETMv3/PTM. For ETMv4 we must remap options
-	 * to real bits
+	 * Synthesize what the kernel programmed into TRCCONFIGR based on
+	 * what options the event was opened with. This doesn't have to be
+	 * complete or 100% accurate, not all bits used by OpenCSD anyway.
 	 */
-	config_opts = cs_etm_get_config(itr);
-	if (config_opts & BIT(ETM_OPT_CYCACC))
-		config |= BIT(ETM4_CFG_BIT_CYCACC);
-	if (config_opts & BIT(ETM_OPT_CTXTID))
-		config |= BIT(ETM4_CFG_BIT_CTXTID);
-	if (config_opts & BIT(ETM_OPT_TS))
-		config |= BIT(ETM4_CFG_BIT_TS);
-	if (config_opts & BIT(ETM_OPT_RETSTK))
-		config |= BIT(ETM4_CFG_BIT_RETSTK);
-	if (config_opts & BIT(ETM_OPT_CTXTID2))
-		config |= BIT(ETM4_CFG_BIT_VMID) |
-			  BIT(ETM4_CFG_BIT_VMID_OPT);
-	if (config_opts & BIT(ETM_OPT_BRANCH_BROADCAST))
-		config |= BIT(ETM4_CFG_BIT_BB);
-
-	return config;
+	if (!evsel__get_config_val(evsel, "cycacc", &val) && val)
+		trcconfigr |= TRCCONFIGR_CCI;
+	if (!evsel__get_config_val(evsel, "contextid1", &val) && val)
+		trcconfigr |= TRCCONFIGR_CID;
+	if (!evsel__get_config_val(evsel, "timestamp", &val) && val)
+		trcconfigr |= TRCCONFIGR_TS;
+	if (!evsel__get_config_val(evsel, "retstack", &val) && val)
+		trcconfigr |= TRCCONFIGR_RS;
+	if (!evsel__get_config_val(evsel, "contextid2", &val) && val)
+		trcconfigr |= TRCCONFIGR_VMID | TRCCONFIGR_VMIDOPT;
+	if (!evsel__get_config_val(evsel, "branch_broadcast", &val) && val)
+		trcconfigr |= TRCCONFIGR_BB;
+
+	return trcconfigr;
 }
 
 static size_t
@@ -688,7 +677,7 @@ static void cs_etm_save_etmv4_header(__u64 data[], struct auxtrace_record *itr,
 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
 
 	/* Get trace configuration register */
-	data[CS_ETMV4_TRCCONFIGR] = cs_etmv4_get_config(itr);
+	data[CS_ETMV4_TRCCONFIGR] = cs_etmv4_synth_trcconfigr(itr);
 	/* traceID set to legacy version, in case new perf running on older system */
 	data[CS_ETMV4_TRCTRACEIDR] = cs_etm_get_legacy_trace_id(cpu);
 
@@ -720,7 +709,7 @@ static void cs_etm_save_ete_header(__u64 data[], struct auxtrace_record *itr, st
 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
 
 	/* Get trace configuration register */
-	data[CS_ETE_TRCCONFIGR] = cs_etmv4_get_config(itr);
+	data[CS_ETE_TRCCONFIGR] = cs_etmv4_synth_trcconfigr(itr);
 	/* traceID set to legacy version, in case new perf running on older system */
 	data[CS_ETE_TRCTRACEIDR] = cs_etm_get_legacy_trace_id(cpu);
 

-- 
2.34.1



From james.clark at linaro.org  Mon Dec 22 07:14:38 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 22 Dec 2025 15:14:38 +0000
Subject: [PATCH v4 13/14] perf cs-etm: Don't hard code config attribute
 when configuring the event
In-Reply-To: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
References: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
Message-ID: <20251222-james-perf-config-bits-v4-13-0608438186fc@linaro.org>

These instances of hard coded config attributes are used for configuring
and validating the event options. Use the config attribute that's
published by the driver by replacing the open coded operations with
evsel__get_config_val() and evsel__set_config_if_unset().

Reviewed-by: Ian Rogers <irogers at google.com>
Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/arch/arm/util/cs-etm.c | 56 +++++++++++++++++++--------------------
 1 file changed, 27 insertions(+), 29 deletions(-)

diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
index 12b28562c2f3..dc3f4e86b075 100644
--- a/tools/perf/arch/arm/util/cs-etm.c
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -103,13 +103,14 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
 				      struct perf_cpu cpu)
 {
 	int err;
-	__u64 val;
-	u64 contextid = evsel->core.attr.config &
-		(perf_pmu__format_bits(cs_etm_pmu, "contextid") |
-		 perf_pmu__format_bits(cs_etm_pmu, "contextid1") |
-		 perf_pmu__format_bits(cs_etm_pmu, "contextid2"));
+	u64 ctxt, ctxt1, ctxt2;
+	__u64 trcidr2;
 
-	if (!contextid)
+	evsel__get_config_val(evsel, "contextid", &ctxt);
+	evsel__get_config_val(evsel, "contextid1", &ctxt1);
+	evsel__get_config_val(evsel, "contextid2", &ctxt2);
+
+	if (!ctxt && !ctxt1 && !ctxt2)
 		return 0;
 
 	/* Not supported in etmv3 */
@@ -120,12 +121,11 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
 	}
 
 	/* Get a handle on TRCIDR2 */
-	err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2], &val);
+	err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2], &trcidr2);
 	if (err)
 		return err;
 
-	if (contextid &
-	    perf_pmu__format_bits(cs_etm_pmu, "contextid1")) {
+	if (ctxt1) {
 		/*
 		 * TRCIDR2.CIDSIZE, bit [9-5], indicates whether contextID
 		 * tracing is supported:
@@ -133,15 +133,14 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
 		 *  0b00100 Maximum of 32-bit Context ID size.
 		 *  All other values are reserved.
 		 */
-		if (BMVAL(val, 5, 9) != 0x4) {
+		if (BMVAL(trcidr2, 5, 9) != 0x4) {
 			pr_err("%s: CONTEXTIDR_EL1 isn't supported, disable with %s/contextid1=0/\n",
 			       CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME);
 			return -EINVAL;
 		}
 	}
 
-	if (contextid &
-	    perf_pmu__format_bits(cs_etm_pmu, "contextid2")) {
+	if (ctxt2) {
 		/*
 		 * TRCIDR2.VMIDOPT[30:29] != 0 and
 		 * TRCIDR2.VMIDSIZE[14:10] == 0b00100 (32bit virtual contextid)
@@ -149,7 +148,7 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
 		 * virtual context id is < 32bit.
 		 * Any value of VMIDSIZE >= 4 (i.e, > 32bit) is fine for us.
 		 */
-		if (!BMVAL(val, 29, 30) || BMVAL(val, 10, 14) < 4) {
+		if (!BMVAL(trcidr2, 29, 30) || BMVAL(trcidr2, 10, 14) < 4) {
 			pr_err("%s: CONTEXTIDR_EL2 isn't supported, disable with %s/contextid2=0/\n",
 			       CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME);
 			return -EINVAL;
@@ -163,10 +162,11 @@ static int cs_etm_validate_timestamp(struct perf_pmu *cs_etm_pmu, struct evsel *
 				     struct perf_cpu cpu)
 {
 	int err;
-	__u64 val;
+	u64 val;
+	__u64 trcidr0;
 
-	if (!(evsel->core.attr.config &
-	      perf_pmu__format_bits(cs_etm_pmu, "timestamp")))
+	evsel__get_config_val(evsel, "timestamp", &val);
+	if (!val)
 		return 0;
 
 	if (cs_etm_get_version(cs_etm_pmu, cpu) == CS_ETMV3) {
@@ -176,7 +176,7 @@ static int cs_etm_validate_timestamp(struct perf_pmu *cs_etm_pmu, struct evsel *
 	}
 
 	/* Get a handle on TRCIRD0 */
-	err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0], &val);
+	err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0], &trcidr0);
 	if (err)
 		return err;
 
@@ -187,10 +187,9 @@ static int cs_etm_validate_timestamp(struct perf_pmu *cs_etm_pmu, struct evsel *
 	 *  0b00110 Implementation supports a maximum timestamp of 48bits.
 	 *  0b01000 Implementation supports a maximum timestamp of 64bits.
 	 */
-	val &= GENMASK(28, 24);
-	if (!val) {
+	trcidr0 &= GENMASK(28, 24);
+	if (!trcidr0)
 		return -EINVAL;
-	}
 
 	return 0;
 }
@@ -273,16 +272,19 @@ static int cs_etm_parse_snapshot_options(struct auxtrace_record *itr,
 	return 0;
 }
 
+/*
+ * If the sink name format "@sink_name" is used, lookup the sink by name to convert to
+ * "sinkid=sink_hash" format. If the user has already manually provided a hash then
+ * "sinkid" isn't overwritten. If neither are provided then the driver will pick the best
+ * sink.
+ */
 static int cs_etm_set_sink_attr(struct perf_pmu *pmu,
 				struct evsel *evsel)
 {
 	char msg[BUFSIZ], path[PATH_MAX], *sink;
 	struct evsel_config_term *term;
-	int ret = -EINVAL;
 	u32 hash;
-
-	if (evsel->core.attr.config2 & GENMASK(31, 0))
-		return 0;
+	int ret;
 
 	list_for_each_entry(term, &evsel->config_terms, list) {
 		if (term->type != EVSEL__CONFIG_TERM_DRV_CFG)
@@ -305,14 +307,10 @@ static int cs_etm_set_sink_attr(struct perf_pmu *pmu,
 			return ret;
 		}
 
-		evsel->core.attr.config2 |= hash;
+		evsel__set_config_if_unset(evsel, "sinkid", hash);
 		return 0;
 	}
 
-	/*
-	 * No sink was provided on the command line - allow the CoreSight
-	 * system to look for a default
-	 */
 	return 0;
 }
 

-- 
2.34.1



From james.clark at linaro.org  Mon Dec 22 07:14:36 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 22 Dec 2025 15:14:36 +0000
Subject: [PATCH v4 11/14] perf cs-etm: Don't use hard coded config bits
 when setting up ETMCR
In-Reply-To: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
References: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
Message-ID: <20251222-james-perf-config-bits-v4-11-0608438186fc@linaro.org>

Perf only looks at attr.config when determining what was programmed into
ETMCR. These bits could theoretically be in any of the config fields.
Add a generic helper to find the value of any named format field in any
config field and then use it to get the attributes relevant to ETMCR.

The kernel will also stop publishing the ETMCR register bits in a header
[1] so preempt that by defining them here.

Move field_prep() to util.h so we can define it along side field_get().
Unfortunately FIELD_PREP() and FIELD_GET() from the kernel can't be used
as they require the mask to be a compile time constant.

[1]: https://lore.kernel.org/linux-arm-kernel/20251128-james-cs-syncfreq-v8-10-4d319764cc58 at linaro.org/

Reviewed-by: Ian Rogers <irogers at google.com>
Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/arch/arm/util/cs-etm.c | 35 ++++++++++++++++++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)

diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
index a49753f0d20f..f535027ce862 100644
--- a/tools/perf/arch/arm/util/cs-etm.c
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -68,6 +68,12 @@ static const char * const metadata_ete_ro[] = {
 
 enum cs_etm_version { CS_NOT_PRESENT, CS_ETMV3, CS_ETMV4, CS_ETE };
 
+
+/* ETMv3 ETMCR register bits */
+#define ETMCR_CYC_ACC		BIT(12)
+#define ETMCR_TIMESTAMP_EN	BIT(28)
+#define ETMCR_RETURN_STACK	BIT(29)
+
 static bool cs_etm_is_ete(struct perf_pmu *cs_etm_pmu, struct perf_cpu cpu);
 static int cs_etm_get_ro(struct perf_pmu *pmu, struct perf_cpu cpu, const char *path, __u64 *val);
 static bool cs_etm_pmu_path_exists(struct perf_pmu *pmu, struct perf_cpu cpu, const char *path);
@@ -484,6 +490,33 @@ static int cs_etm_recording_options(struct auxtrace_record *itr,
 	return err;
 }
 
+static u64 cs_etm_synth_etmcr(struct auxtrace_record *itr)
+{
+	struct cs_etm_recording *ptr =
+		container_of(itr, struct cs_etm_recording, itr);
+	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
+	struct evsel *evsel = cs_etm_get_evsel(ptr->evlist, cs_etm_pmu);
+	u64 etmcr = 0;
+	u64 val;
+
+	if (!evsel)
+		return 0;
+
+	/*
+	 * Synthesize what the kernel programmed into ETMCR based on
+	 * what options the event was opened with. This doesn't have to be
+	 * complete or 100% accurate, not all bits used by OpenCSD anyway.
+	 */
+	if (!evsel__get_config_val(evsel, "cycacc", &val) && val)
+		etmcr |= ETMCR_CYC_ACC;
+	if (!evsel__get_config_val(evsel, "timestamp", &val) && val)
+		etmcr |= ETMCR_TIMESTAMP_EN;
+	if (!evsel__get_config_val(evsel, "retstack", &val) && val)
+		etmcr |= ETMCR_RETURN_STACK;
+
+	return etmcr;
+}
+
 static u64 cs_etm_get_config(struct auxtrace_record *itr)
 {
 	struct cs_etm_recording *ptr =
@@ -743,7 +776,7 @@ static void cs_etm_get_metadata(struct perf_cpu cpu, u32 *offset,
 	case CS_ETMV3:
 		magic = __perf_cs_etmv3_magic;
 		/* Get configuration register */
-		info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr);
+		info->priv[*offset + CS_ETM_ETMCR] = cs_etm_synth_etmcr(itr);
 		/* traceID set to legacy value in case new perf running on old system */
 		info->priv[*offset + CS_ETM_ETMTRACEIDR] = cs_etm_get_legacy_trace_id(cpu);
 		/* Get read-only information from sysFS */

-- 
2.34.1



From james.clark at linaro.org  Mon Dec 22 07:14:39 2025
From: james.clark at linaro.org (James Clark)
Date: Mon, 22 Dec 2025 15:14:39 +0000
Subject: [PATCH v4 14/14] perf arm-spe: Don't hard code config attribute
In-Reply-To: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
References: <20251222-james-perf-config-bits-v4-0-0608438186fc@linaro.org>
Message-ID: <20251222-james-perf-config-bits-v4-14-0608438186fc@linaro.org>

Use the config attribute that's published by the driver instead of
hard coding "attr.config".

Reviewed-by: Ian Rogers <irogers at google.com>
Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/arch/arm64/util/arm-spe.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c
index 51014f8bff97..17ced7bbbdda 100644
--- a/tools/perf/arch/arm64/util/arm-spe.c
+++ b/tools/perf/arch/arm64/util/arm-spe.c
@@ -256,7 +256,7 @@ static __u64 arm_spe_pmu__sample_period(const struct perf_pmu *arm_spe_pmu)
 
 static void arm_spe_setup_evsel(struct evsel *evsel, struct perf_cpu_map *cpus)
 {
-	u64 bit;
+	u64 pa_enable_bit;
 
 	evsel->core.attr.freq = 0;
 	evsel->core.attr.sample_period = arm_spe_pmu__sample_period(evsel->pmu);
@@ -288,9 +288,10 @@ static void arm_spe_setup_evsel(struct evsel *evsel, struct perf_cpu_map *cpus)
 	 * inform that the resulting output's SPE samples contain physical addresses
 	 * where applicable.
 	 */
-	bit = perf_pmu__format_bits(evsel->pmu, "pa_enable");
-	if (evsel->core.attr.config & bit)
-		evsel__set_sample_bit(evsel, PHYS_ADDR);
+
+	if (!evsel__get_config_val(evsel, "pa_enable", &pa_enable_bit))
+		if (pa_enable_bit)
+			evsel__set_sample_bit(evsel, PHYS_ADDR);
 }
 
 static int arm_spe_setup_aux_buffer(struct record_opts *opts)
@@ -397,6 +398,7 @@ static int arm_spe_recording_options(struct auxtrace_record *itr,
 	struct perf_cpu_map *cpus = evlist->core.user_requested_cpus;
 	bool discard = false;
 	int err;
+	u64 discard_bit;
 
 	sper->evlist = evlist;
 
@@ -425,9 +427,8 @@ static int arm_spe_recording_options(struct auxtrace_record *itr,
 	evlist__for_each_entry_safe(evlist, tmp, evsel) {
 		if (evsel__is_aux_event(evsel)) {
 			arm_spe_setup_evsel(evsel, cpus);
-			if (evsel->core.attr.config &
-			    perf_pmu__format_bits(evsel->pmu, "discard"))
-				discard = true;
+			if (!evsel__get_config_val(evsel, "discard", &discard_bit))
+				discard = !!discard_bit;
 		}
 	}
 

-- 
2.34.1



From leitao at debian.org  Mon Dec 22 07:28:55 2025
From: leitao at debian.org (Breno Leitao)
Date: Mon, 22 Dec 2025 07:28:55 -0800
Subject: [PATCH] arm64: mm: warn once for ioremap attempts on RAM mappings
Message-ID: <20251222-arm64_ioremap-v1-1-30ff5f718b61@debian.org>

Replace WARN_ON with WARN_ONCE when detecting attempts to ioremap
RAM. This prevents log spam when a misbehaving driver repeatedly tries
to map RAM via ioremap.

A single warning is more than enough to show the broken code path, and
extra reports don't add extra information.

Warning floods have been seen in production environments where broken
external drivers hit this code path thousand of times, causing
unnecessary messages to be printed and pressure on the serial console.

Signed-off-by: Breno Leitao <leitao at debian.org>
---
PS: This is crashing a host due to a lockup on nbcon that is likely
fixed by commit d5d399efff65773("printk/nbcon: Release nbcon consoles ownership
in atomic flush after each emitted record")
---
 arch/arm64/mm/ioremap.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/mm/ioremap.c b/arch/arm64/mm/ioremap.c
index 10e246f11271..b12cbed9b5ad 100644
--- a/arch/arm64/mm/ioremap.c
+++ b/arch/arm64/mm/ioremap.c
@@ -24,7 +24,8 @@ void __iomem *ioremap_prot(phys_addr_t phys_addr, size_t size,
 		return NULL;
 
 	/* Don't allow RAM to be mapped. */
-	if (WARN_ON(pfn_is_map_memory(__phys_to_pfn(phys_addr))))
+	if (WARN_ONCE(pfn_is_map_memory(__phys_to_pfn(phys_addr)),
+		      "ioremap attempted on RAM pfn\n"))
 		return NULL;
 
 	/*

---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20251222-arm64_ioremap-d20703b85358

Best regards,
--  
Breno Leitao <leitao at debian.org>



From lkp at intel.com  Mon Dec 22 07:32:53 2025
From: lkp at intel.com (kernel test robot)
Date: Mon, 22 Dec 2025 16:32:53 +0100
Subject: [PATCH v10 5/7] media: verisilicon: AV1: Restore IOMMU context
 before decoding a frame
In-Reply-To: <20251215085349.10155-6-benjamin.gaignard@collabora.com>
References: <20251215085349.10155-6-benjamin.gaignard@collabora.com>
Message-ID: <202512221600.vlUX9PF6-lkp@intel.com>

Hi Benjamin,

kernel test robot noticed the following build warnings:

[auto build test WARNING on linus/master]
[also build test WARNING on v6.19-rc2 next-20251219]
[cannot apply to robh/for-next rockchip/for-next arm64/for-next/core]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Benjamin-Gaignard/dt-bindings-vendor-prefixes-Add-Verisilicon/20251215-165740
base:   linus/master
patch link:    https://lore.kernel.org/r/20251215085349.10155-6-benjamin.gaignard%40collabora.com
patch subject: [PATCH v10 5/7] media: verisilicon: AV1: Restore IOMMU context before decoding a frame
config: openrisc-kismet-CONFIG_VSI_IOMMU-CONFIG_VIDEO_HANTRO_ROCKCHIP-0-0 (https://download.01.org/0day-ci/archive/20251222/202512221600.vlUX9PF6-lkp at intel.com/config)
reproduce: (https://download.01.org/0day-ci/archive/20251222/202512221600.vlUX9PF6-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512221600.vlUX9PF6-lkp at intel.com/

kismet warnings: (new ones prefixed by >>)
>> kismet: WARNING: unmet direct dependencies detected for VSI_IOMMU when selected by VIDEO_HANTRO_ROCKCHIP
   WARNING: unmet direct dependencies detected for VSI_IOMMU
     Depends on [n]: IOMMU_SUPPORT [=n] && (ARCH_ROCKCHIP && ARM64 || COMPILE_TEST [=y])
     Selected by [y]:
     - VIDEO_HANTRO_ROCKCHIP [=y] && MEDIA_SUPPORT [=y] && MEDIA_PLATFORM_SUPPORT [=y] && MEDIA_PLATFORM_DRIVERS [=y] && VIDEO_HANTRO [=y] && (ARCH_ROCKCHIP || COMPILE_TEST [=y])

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From leitao at debian.org  Mon Dec 22 08:08:40 2025
From: leitao at debian.org (Breno Leitao)
Date: Mon, 22 Dec 2025 08:08:40 -0800
Subject: [PATCH net-next] net: stmmac: convert to use .get_rx_ring_count
Message-ID: <20251222-gxring_stmicro-v1-1-d018a14644a5@debian.org>

Convert the stmmac driver to use the new .get_rx_ring_count
ethtool operation instead of implementing .get_rxnfc for handling
ETHTOOL_GRXRINGS command.

Since stmmac_get_rxnfc() only handled ETHTOOL_GRXRINGS (returning
-EOPNOTSUPP for all other commands), remove it entirely and replace
it with the simpler stmmac_get_rx_ring_count() callback.

Signed-off-by: Breno Leitao <leitao at debian.org>
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 15 +++------------
 1 file changed, 3 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index b155e71aac51..c1e26965d9b5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -914,20 +914,11 @@ static int stmmac_set_per_queue_coalesce(struct net_device *dev, u32 queue,
 	return __stmmac_set_coalesce(dev, ec, queue);
 }
 
-static int stmmac_get_rxnfc(struct net_device *dev,
-			    struct ethtool_rxnfc *rxnfc, u32 *rule_locs)
+static u32 stmmac_get_rx_ring_count(struct net_device *dev)
 {
 	struct stmmac_priv *priv = netdev_priv(dev);
 
-	switch (rxnfc->cmd) {
-	case ETHTOOL_GRXRINGS:
-		rxnfc->data = priv->plat->rx_queues_to_use;
-		break;
-	default:
-		return -EOPNOTSUPP;
-	}
-
-	return 0;
+	return priv->plat->rx_queues_to_use;
 }
 
 static u32 stmmac_get_rxfh_key_size(struct net_device *dev)
@@ -1121,7 +1112,7 @@ static const struct ethtool_ops stmmac_ethtool_ops = {
 	.get_eee = stmmac_ethtool_op_get_eee,
 	.set_eee = stmmac_ethtool_op_set_eee,
 	.get_sset_count	= stmmac_get_sset_count,
-	.get_rxnfc = stmmac_get_rxnfc,
+	.get_rx_ring_count = stmmac_get_rx_ring_count,
 	.get_rxfh_key_size = stmmac_get_rxfh_key_size,
 	.get_rxfh_indir_size = stmmac_get_rxfh_indir_size,
 	.get_rxfh = stmmac_get_rxfh,

---
base-commit: 7b8e9264f55a9c320f398e337d215e68cca50131
change-id: 20251222-gxring_stmicro-40bac6fcad86

Best regards,
--  
Breno Leitao <leitao at debian.org>



From mike.looijmans at topic.nl  Mon Dec 22 08:13:22 2025
From: mike.looijmans at topic.nl (Mike Looijmans)
Date: Mon, 22 Dec 2025 17:13:22 +0100
Subject: [PATCH 0/3] drm: zynqmp: Make the video plane primary
In-Reply-To: <a7aa91ad-3f16-48b7-88f6-ea03c466f76c@ideasonboard.com>
References: <20251113203715.2768107-1-sean.anderson@linux.dev>
 <a7aa91ad-3f16-48b7-88f6-ea03c466f76c@ideasonboard.com>
Message-ID: <5834a595-6474-4c50-8dea-2072e7b3554d@topic.nl>

On 22-12-2025 10:48, Tomi Valkeinen wrote:
> Hi,
>
> On 13/11/2025 22:37, Sean Anderson wrote:
>> The graphics plane does not support XRGB8888, which is the default mode
>> X uses for 24-bit color. Because of this, X must be set to use 16-bit
>> color, which has a measurable performance penalty. Make the video plane
>> the primary plane as it natively supports XRGB8888. An alternative
>> approach to add XRGB8888 to the graphics plane is discussed in [1], as
>> well as in patch 2.
>>
>> [1] https://lore.kernel.org/dri-devel/20250627145058.6880-1-mike.looijmans at topic.nl/
>>
>>
>> Sean Anderson (3):
>>    drm: zynqmp: Check property creation status
>>    drm: zynqmp: Make the video plane primary
>>    drm: zynqmp: Add blend mode property to graphics plane
>>
>>   drivers/gpu/drm/xlnx/zynqmp_kms.c | 42 +++++++++++++++++++++++++------
>>   1 file changed, 34 insertions(+), 8 deletions(-)
>>
> I made a test with pykms and tried this series with a few different
> things. Afaics with this series the driver behaves as I would expect the
> driver to behave. It makes sense to have the lower z-order plane as the
> primary plane, especially as it supports the standard XRGB8888.
>
> That said, I don't think there's anything that exactly would make the
> current way of having GFX as primary wrong... So I still don't see a
> single obvious solution to this whole issue.
>
> A few thoughts:
>
> If there is no regression here (i.e. this just has never worked well
> with X/Weston), might the actual fix be in X/Weston? Is there an actual
> bug in the xilinx driver?
>
> On the other hand, I think it makes sense for drivers to (try to) expose
> the HW in a common way. XRGB8888 is the standard format, so it makes
> sense to expose XRGB8888 on primary plane. I think this is how the
> driver should have behaved from the start. But if changing that now
> would cause user space regressions, it's not good either.

I tried to get e.g. gstreamer to use the overlay as output (in YUV 
format), but never got that to work. Having read the comments on these 
series, it's probably the lack of positioning and scaling capabilities 
that made gstreamer discard it.

I expect no regression here - everyone who got the DP output to work 
must have been using some workaround already. The driver as it is now 
never worked with X11 (or wayland) anyway, unless you forced it into 
16-bit mode.

And given the capabilities, I seriously doubt that any user ever used 
the overlay plane.

For what it's worth, I'd say the best solution is to swap the planes and 
support XRGB8888 mode properly. Then at least, X11 and wayland work 
without further configuration or patches, the output quality is as it 
should be, and as an added bonus, the performance (with or without the 
MALI GPU) is much better too.


-- 
Mike Looijmans
System Expert

TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijmans at topic.nl
W: www.topic.nl





From tudor.ambarus at linaro.org  Mon Dec 22 08:30:04 2025
From: tudor.ambarus at linaro.org (Tudor Ambarus)
Date: Mon, 22 Dec 2025 16:30:04 +0000
Subject: [PATCH v4 0/5] soc: samsung: exynos-chipid: add gs101 support
Message-ID: <20251222-gs101-chipid-v4-0-aa8e20ce7bb3@linaro.org>

Dependency
==========
Typical dependency of the DT patch depending on the bindings patch,
thus the bindings patch could go via the Samsung SoC tree with
Srinivas's ack.

Description
===========
GS101 is different (but also e850 and autov9 I assume) from the SoCs
that are currently handled by the exynos-chipid driver because the
chip ID info is part of the OTP registers. GS101 OTP has a clock, an
interrupt line, a register space (that contains product and chip ID,
TMU data, ASV, etc) and a 32Kbit memory space that can be
read/program/locked with specific commands. On GS101 the "ChipID block"
is just an abstraction, it's not a physical device. When the power-on
sequence progresses, the OTP chipid values are loaded to the OTP
registers.

Add the GS101 chip ID support. The support is intentionally added in the
exynos-chipid driver, and not in a dedicated Exynos OTP driver, because
we estimate that there will not be any OTP consumers in the kernel other
than the chip ID/SoC interface. The downstream GS101 drivers confirm
this supposition.

Testing
=======
root at google-gs:~# cat /sys/devices/soc0/family
Samsung Exynos
root at google-gs:~# cat /sys/devices/soc0/machine
Oriole
root at google-gs:~# cat /sys/devices/soc0/revision
11
root at google-gs:~# cat /sys/devices/soc0/soc_id
GS101

Signed-off-by: Tudor Ambarus <tudor.ambarus at linaro.org>
---
Changes in v4:
- bindings were not sent in v3, human error. Add them back. Compared to
  v2, add clock-names property as it's needed for
  devm_regmap_init_mmio_clk()
- driver: use devm_regmap_init_mmio_clk() to deal with clock aquisition
  and enable/disable as needed.
- dt: add clock-names prop
- Rebase and collect R-b tags
- Link to v3: https://lore.kernel.org/r/20251120-gs101-chipid-v3-0-1aeaa8b7fe35 at linaro.org

Changes in v3:
- rebase so that cleanups come before the gs101 support. The inclusion
  of linux/device/devres.h is now done in the devm action patch, as it's
  first needed there.
- update error message: s/failed to read sub revision/failed to read revision
- Link to v2: https://lore.kernel.org/r/20251118-gs101-chipid-v2-0-e9f1e7460e35 at linaro.org

Changes in v2:
- complete rework, treat it as a new patch set please.
- bindings were reviewed at:
  - Link: https://lore.kernel.org/linux-samsung-soc/27a5521cd7ddbed0e870ac416dc829722f1b36a5.camel at linaro.org/T/#me139353334db535806ca6462ae1e86b01ff032a7
  - addressed Andre's s/if of/is of
- part of the cleaning patches are from this trivial series:
  - Link: https://lore.kernel.org/linux-samsung-soc/20251112-chipid-trivial-v1-0-ec2dea03bd83 at linaro.org/
- Link to v1: https://lore.kernel.org/r/20251031-gs101-chipid-v1-0-d78d1076b210 at linaro.org

---
Tudor Ambarus (5):
      dt-bindings: nvmem: add google,gs101-otp
      soc: samsung: exynos-chipid: rename method
      soc: samsung: exynos-chipid: downgrade dev_info to dev_dbg for soc info
      soc: samsung: exynos-chipid: add google,gs101-otp support
      arm64: dts: exynos: gs101: add OTP node

 .../bindings/nvmem/google,gs101-otp.yaml           | 61 +++++++++++++++++
 arch/arm64/boot/dts/exynos/google/gs101.dtsi       |  8 +++
 drivers/soc/samsung/exynos-chipid.c                | 79 ++++++++++++++++++----
 3 files changed, 135 insertions(+), 13 deletions(-)
---
base-commit: 0825f376d02e58e8ee4179569e0a386e1cd0eb76
change-id: 20251031-gs101-chipid-fd84da8afa2f

Best regards,
-- 
Tudor Ambarus <tudor.ambarus at linaro.org>



From tudor.ambarus at linaro.org  Mon Dec 22 08:30:05 2025
From: tudor.ambarus at linaro.org (Tudor Ambarus)
Date: Mon, 22 Dec 2025 16:30:05 +0000
Subject: [PATCH v4 1/5] dt-bindings: nvmem: add google,gs101-otp
In-Reply-To: <20251222-gs101-chipid-v4-0-aa8e20ce7bb3@linaro.org>
References: <20251222-gs101-chipid-v4-0-aa8e20ce7bb3@linaro.org>
Message-ID: <20251222-gs101-chipid-v4-1-aa8e20ce7bb3@linaro.org>

Add binding for the OTP controller found on Google GS101.

Reviewed-by: Andr? Draszik <andre.draszik at linaro.org>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
Signed-off-by: Tudor Ambarus <tudor.ambarus at linaro.org>
---
 .../bindings/nvmem/google,gs101-otp.yaml           | 61 ++++++++++++++++++++++
 1 file changed, 61 insertions(+)

diff --git a/Documentation/devicetree/bindings/nvmem/google,gs101-otp.yaml b/Documentation/devicetree/bindings/nvmem/google,gs101-otp.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..99e322c72f9ee1766f3393e604991364c41456fe
--- /dev/null
+++ b/Documentation/devicetree/bindings/nvmem/google,gs101-otp.yaml
@@ -0,0 +1,61 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/nvmem/google,gs101-otp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Google GS101 OTP Controller
+
+maintainers:
+  - Tudor Ambarus <tudor.ambarus at linaro.org>
+
+description: |
+  OTP controller drives a NVMEM memory where system or user specific data
+  can be stored. The OTP controller register space is of interest as well
+  because it contains dedicated registers where it stores the Product ID
+  and the Chip ID (apart other things like TMU or ASV info).
+
+allOf:
+  - $ref: nvmem.yaml#
+
+properties:
+  compatible:
+    items:
+      - const: google,gs101-otp
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    const: pclk
+
+  interrupts:
+    maxItems: 1
+
+  reg:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - interrupts
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/google,gs101.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    efuse at 10000000 {
+        compatible = "google,gs101-otp";
+        reg = <0x10000000 0xf084>;
+        clocks = <&cmu_misc CLK_GOUT_MISC_OTP_CON_TOP_PCLK>;
+        clock-names = "pclk";
+        interrupts = <GIC_SPI 752 IRQ_TYPE_LEVEL_HIGH>;
+    };

-- 
2.52.0.322.g1dd061c0dc-goog



From tudor.ambarus at linaro.org  Mon Dec 22 08:30:06 2025
From: tudor.ambarus at linaro.org (Tudor Ambarus)
Date: Mon, 22 Dec 2025 16:30:06 +0000
Subject: [PATCH v4 2/5] soc: samsung: exynos-chipid: rename method
In-Reply-To: <20251222-gs101-chipid-v4-0-aa8e20ce7bb3@linaro.org>
References: <20251222-gs101-chipid-v4-0-aa8e20ce7bb3@linaro.org>
Message-ID: <20251222-gs101-chipid-v4-2-aa8e20ce7bb3@linaro.org>

s/product_id_to_soc_id/exynos_product_id_to_name.
Prepend exynos_ to avoid name space pollution. The method translates the
product id to a name, rename the method to make that clear. While
touching the code where it is called, add a blank line for readability
purposes.

Signed-off-by: Tudor Ambarus <tudor.ambarus at linaro.org>
---
 drivers/soc/samsung/exynos-chipid.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c
index b9a30452ad21c326af35c06a341b28491cee6979..88d264ef1b8835e15f774ff5a31f5b3de20f74ea 100644
--- a/drivers/soc/samsung/exynos-chipid.c
+++ b/drivers/soc/samsung/exynos-chipid.c
@@ -71,7 +71,7 @@ static const struct exynos_soc_id {
 	{ "EXYNOSAUTOV920", 0x0A920000 },
 };
 
-static const char *product_id_to_soc_id(unsigned int product_id)
+static const char *exynos_product_id_to_name(unsigned int product_id)
 {
 	int i;
 
@@ -150,7 +150,8 @@ static int exynos_chipid_probe(struct platform_device *pdev)
 						soc_info.revision);
 	if (!soc_dev_attr->revision)
 		return -ENOMEM;
-	soc_dev_attr->soc_id = product_id_to_soc_id(soc_info.product_id);
+
+	soc_dev_attr->soc_id = exynos_product_id_to_name(soc_info.product_id);
 	if (!soc_dev_attr->soc_id)
 		return dev_err_probe(dev, -ENODEV, "Unknown SoC\n");
 

-- 
2.52.0.322.g1dd061c0dc-goog



From tudor.ambarus at linaro.org  Mon Dec 22 08:30:07 2025
From: tudor.ambarus at linaro.org (Tudor Ambarus)
Date: Mon, 22 Dec 2025 16:30:07 +0000
Subject: [PATCH v4 3/5] soc: samsung: exynos-chipid: downgrade dev_info to
 dev_dbg for soc info
In-Reply-To: <20251222-gs101-chipid-v4-0-aa8e20ce7bb3@linaro.org>
References: <20251222-gs101-chipid-v4-0-aa8e20ce7bb3@linaro.org>
Message-ID: <20251222-gs101-chipid-v4-3-aa8e20ce7bb3@linaro.org>

The SoC information is exposed to userspace using the standard soc
interface. Downgrade to dev_dbg to stop polluting the console log.

Signed-off-by: Tudor Ambarus <tudor.ambarus at linaro.org>
Reviewed-by: Andr? Draszik <andre.draszik at linaro.org>
---
 drivers/soc/samsung/exynos-chipid.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c
index 88d264ef1b8835e15f774ff5a31f5b3de20f74ea..5c8660374269c87ec38ebca242918bd7b1d362e5 100644
--- a/drivers/soc/samsung/exynos-chipid.c
+++ b/drivers/soc/samsung/exynos-chipid.c
@@ -170,8 +170,8 @@ static int exynos_chipid_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	dev_info(dev, "Exynos: CPU[%s] PRO_ID[0x%x] REV[0x%x] Detected\n",
-		 soc_dev_attr->soc_id, soc_info.product_id, soc_info.revision);
+	dev_dbg(dev, "Exynos: CPU[%s] PRO_ID[0x%x] REV[0x%x] Detected\n",
+		soc_dev_attr->soc_id, soc_info.product_id, soc_info.revision);
 
 	return 0;
 }

-- 
2.52.0.322.g1dd061c0dc-goog



From tudor.ambarus at linaro.org  Mon Dec 22 08:30:08 2025
From: tudor.ambarus at linaro.org (Tudor Ambarus)
Date: Mon, 22 Dec 2025 16:30:08 +0000
Subject: [PATCH v4 4/5] soc: samsung: exynos-chipid: add google,gs101-otp
 support
In-Reply-To: <20251222-gs101-chipid-v4-0-aa8e20ce7bb3@linaro.org>
References: <20251222-gs101-chipid-v4-0-aa8e20ce7bb3@linaro.org>
Message-ID: <20251222-gs101-chipid-v4-4-aa8e20ce7bb3@linaro.org>

GS101 is different (but also e850 and autov9 I assume) from the SoCs
that are currently handled by the exynos-chipid driver because the
chip ID info is part of the OTP registers. GS101 OTP has a clock, an
interrupt line, a register space (that contains product and chip ID,
TMU data, ASV, etc) and a 32Kbit memory space that can be
read/program/locked with specific commands. On GS101 the "ChipID block"
is just an abstraction, it's not a physical device. When the power-on
sequence progresses, the OTP chipid values are loaded to the OTP
registers.

Add the GS101 chip ID support. The support is intentionally added in the
exynos-chipid driver, and not in a dedicated Exynos OTP driver, because
we estimate that there will not be any OTP consumers in the kernel other
than the chip ID/SoC interface. The downstream GS101 drivers confirm
this supposition.

Signed-off-by: Tudor Ambarus <tudor.ambarus at linaro.org>
---
 drivers/soc/samsung/exynos-chipid.c | 70 ++++++++++++++++++++++++++++++++-----
 1 file changed, 61 insertions(+), 9 deletions(-)

diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c
index 5c8660374269c87ec38ebca242918bd7b1d362e5..6ef9751e2509c94bd9625072d0b81ddb93048d4a 100644
--- a/drivers/soc/samsung/exynos-chipid.c
+++ b/drivers/soc/samsung/exynos-chipid.c
@@ -15,7 +15,8 @@
 #include <linux/array_size.h>
 #include <linux/device.h>
 #include <linux/device/devres.h>
-#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/ioport.h>
 #include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of.h>
@@ -28,9 +29,11 @@
 #include "exynos-asv.h"
 
 struct exynos_chipid_variant {
-	unsigned int rev_reg;		/* revision register offset */
+	unsigned int main_rev_reg;	/* main revision register offset */
+	unsigned int sub_rev_reg;	/* sub revision register offset */
 	unsigned int main_rev_shift;	/* main revision offset in rev_reg */
 	unsigned int sub_rev_shift;	/* sub revision offset in rev_reg */
+	bool efuse;
 };
 
 struct exynos_chipid_info {
@@ -69,6 +72,8 @@ static const struct exynos_soc_id {
 	{ "EXYNOS990", 0xE9830000 },
 	{ "EXYNOSAUTOV9", 0xAAA80000 },
 	{ "EXYNOSAUTOV920", 0x0A920000 },
+	/* Compatible with: google,gs101-otp */
+	{ "GS101", 0x9845000 },
 };
 
 static const char *exynos_product_id_to_name(unsigned int product_id)
@@ -93,19 +98,53 @@ static int exynos_chipid_get_chipid_info(struct device *dev,
 		return dev_err_probe(dev, ret, "failed to read Product ID\n");
 	soc_info->product_id = val & EXYNOS_MASK;
 
-	if (data->rev_reg != EXYNOS_CHIPID_REG_PRO_ID) {
-		ret = regmap_read(regmap, data->rev_reg, &val);
+	if (data->sub_rev_reg == EXYNOS_CHIPID_REG_PRO_ID) {
+		/* exynos4210 case */
+		main_rev = (val >> data->main_rev_shift) & EXYNOS_REV_PART_MASK;
+		sub_rev = (val >> data->sub_rev_shift) & EXYNOS_REV_PART_MASK;
+	} else {
+		unsigned int val2;
+
+		ret = regmap_read(regmap, data->sub_rev_reg, &val2);
 		if (ret < 0)
 			return dev_err_probe(dev, ret,
 					     "failed to read revision\n");
+
+		if (data->main_rev_reg == EXYNOS_CHIPID_REG_PRO_ID)
+			/* gs101 case */
+			main_rev = (val >> data->main_rev_shift) & EXYNOS_REV_PART_MASK;
+		else
+			/* exynos850 case */
+			main_rev = (val2 >> data->main_rev_shift) & EXYNOS_REV_PART_MASK;
+
+		sub_rev = (val2 >> data->sub_rev_shift) & EXYNOS_REV_PART_MASK;
 	}
-	main_rev = (val >> data->main_rev_shift) & EXYNOS_REV_PART_MASK;
-	sub_rev = (val >> data->sub_rev_shift) & EXYNOS_REV_PART_MASK;
+
 	soc_info->revision = (main_rev << EXYNOS_REV_PART_SHIFT) | sub_rev;
 
 	return 0;
 }
 
+static struct regmap *exynos_chipid_get_efuse_regmap(struct platform_device *pdev)
+{
+	struct resource *res;
+	void __iomem *base;
+
+	base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+	if (IS_ERR(base))
+		return ERR_CAST(base);
+
+	const struct regmap_config reg_config = {
+		.reg_bits = 32,
+		.reg_stride = 4,
+		.val_bits = 32,
+		.use_relaxed_mmio = true,
+		.max_register = (resource_size(res) - reg_config.reg_stride),
+	};
+
+	return devm_regmap_init_mmio_clk(&pdev->dev, "pclk", base, &reg_config);
+}
+
 static void exynos_chipid_unregister_soc(void *data)
 {
 	soc_device_unregister(data);
@@ -127,7 +166,11 @@ static int exynos_chipid_probe(struct platform_device *pdev)
 		return dev_err_probe(dev, -EINVAL,
 				     "failed to get match data\n");
 
-	regmap = device_node_to_regmap(dev->of_node);
+	if (drv_data->efuse)
+		regmap = exynos_chipid_get_efuse_regmap(pdev);
+	else
+		regmap = device_node_to_regmap(dev->of_node);
+
 	if (IS_ERR(regmap))
 		return dev_err_probe(dev, PTR_ERR(regmap),
 				     "failed to get regmap\n");
@@ -177,19 +220,28 @@ static int exynos_chipid_probe(struct platform_device *pdev)
 }
 
 static const struct exynos_chipid_variant exynos4210_chipid_drv_data = {
-	.rev_reg	= 0x0,
 	.main_rev_shift	= 4,
 	.sub_rev_shift	= 0,
 };
 
 static const struct exynos_chipid_variant exynos850_chipid_drv_data = {
-	.rev_reg	= 0x10,
+	.main_rev_reg	= 0x10,
+	.sub_rev_reg	= 0x10,
 	.main_rev_shift	= 20,
 	.sub_rev_shift	= 16,
 };
 
+static const struct exynos_chipid_variant gs101_chipid_drv_data = {
+	.sub_rev_reg	= 0x10,
+	.sub_rev_shift	= 16,
+	.efuse = true,
+};
+
 static const struct of_device_id exynos_chipid_of_device_ids[] = {
 	{
+		.compatible	= "google,gs101-otp",
+		.data		= &gs101_chipid_drv_data,
+	}, {
 		.compatible	= "samsung,exynos4210-chipid",
 		.data		= &exynos4210_chipid_drv_data,
 	}, {

-- 
2.52.0.322.g1dd061c0dc-goog



From tudor.ambarus at linaro.org  Mon Dec 22 08:30:09 2025
From: tudor.ambarus at linaro.org (Tudor Ambarus)
Date: Mon, 22 Dec 2025 16:30:09 +0000
Subject: [PATCH v4 5/5] arm64: dts: exynos: gs101: add OTP node
In-Reply-To: <20251222-gs101-chipid-v4-0-aa8e20ce7bb3@linaro.org>
References: <20251222-gs101-chipid-v4-0-aa8e20ce7bb3@linaro.org>
Message-ID: <20251222-gs101-chipid-v4-5-aa8e20ce7bb3@linaro.org>

Add the OTP controller node.

Signed-off-by: Tudor Ambarus <tudor.ambarus at linaro.org>
---
 arch/arm64/boot/dts/exynos/google/gs101.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/boot/dts/exynos/google/gs101.dtsi b/arch/arm64/boot/dts/exynos/google/gs101.dtsi
index 9b38c2248016aa65293c0abf9ccaf20857d89693..e078344c9e3e558aa5d58845d0fa2849832b857b 100644
--- a/arch/arm64/boot/dts/exynos/google/gs101.dtsi
+++ b/arch/arm64/boot/dts/exynos/google/gs101.dtsi
@@ -571,6 +571,14 @@ soc: soc at 0 {
 		#size-cells = <1>;
 		ranges = <0x0 0x0 0x0 0x40000000>;
 
+		efuse at 10000000 {
+			compatible = "google,gs101-otp";
+			reg = <0x10000000 0xf084>;
+			clocks = <&cmu_misc CLK_GOUT_MISC_OTP_CON_TOP_PCLK>;
+			clock-names = "pclk";
+			interrupts = <GIC_SPI 752 IRQ_TYPE_LEVEL_HIGH 0>;
+		};
+
 		cmu_misc: clock-controller at 10010000 {
 			compatible = "google,gs101-cmu-misc";
 			reg = <0x10010000 0x10000>;

-- 
2.52.0.322.g1dd061c0dc-goog



From lkp at intel.com  Mon Dec 22 08:50:04 2025
From: lkp at intel.com (kernel test robot)
Date: Tue, 23 Dec 2025 00:50:04 +0800
Subject: [arm-platforms:kvm-arm64/gicv5-full 48/82]
 arch/arm64/kvm/vgic/vgic-v5.c:737:26: warning: variable 'd' set but not used
Message-ID: <202512230041.45OmXxwl-lkp@intel.com>

tree:   https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git kvm-arm64/gicv5-full
head:   1426b88096b597395df4c82f089b87c62bab45da
commit: 784f082a09f253879e4c4f57182b3a7e0bb92539 [48/82] KVM: arm64: gic-v5: Init/tear down VMTEs
config: arm64-randconfig-003-20251222 (https://download.01.org/0day-ci/archive/20251223/202512230041.45OmXxwl-lkp at intel.com/config)
compiler: aarch64-linux-gcc (GCC) 11.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251223/202512230041.45OmXxwl-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512230041.45OmXxwl-lkp at intel.com/

All warnings (new ones prefixed by >>):

   arch/arm64/kvm/vgic/vgic-v5.c: In function 'vgic_v5_init':
>> arch/arm64/kvm/vgic/vgic-v5.c:737:26: warning: variable 'd' set but not used [-Wunused-but-set-variable]
     737 |         struct irq_data *d;
         |                          ^
   At top level:
   arch/arm64/kvm/vgic/vgic-v5.c:174:12: warning: 'vgic_v5_irs_assign_vmt' defined but not used [-Wunused-function]
     174 | static int vgic_v5_irs_assign_vmt(bool two_level, u8 vm_id_bits, phys_addr_t vmt_base)
         |            ^~~~~~~~~~~~~~~~~~~~~~


vim +/d +737 arch/arm64/kvm/vgic/vgic-v5.c

   722	
   723	/*
   724	 * Claim and populate a VMTE (optionally making a new L2 VMT valid), create VPE
   725	 * doorbells, allocate VPET and populate for each VPE. Finally, we also init the
   726	 * vIRS, which means allocating and making the virtual SPI IST valid.
   727	 *
   728	 * Note: We do need to put the cart before the horse here. The VPE doorbells are
   729	 * our conduit for communication with the IRS, which means we need to have those
   730	 * before making the VMTE valid.
   731	 */
   732	int vgic_v5_init(struct kvm *kvm)
   733	{
   734		int nr_vcpus, ret = 0;
   735		struct kvm_vcpu *vcpu, *vcpu0;
   736		unsigned long i;
 > 737		struct irq_data *d;
   738		unsigned int db_virq;
   739	
   740		if (!vgic_v5_vmt_allocated()) {
   741			pr_err("No VM tables allocated; something is horribly wrong\n");
   742			return -ENODEV;
   743		}
   744	
   745		kvm_for_each_vcpu(i, vcpu, kvm) {
   746			if (vcpu_has_nv(vcpu)) {
   747				kvm_err("Nested GICv5 VMs are currently unsupported\n");
   748				return -EINVAL;
   749			}
   750		}
   751		nr_vcpus = atomic_read(&kvm->online_vcpus);
   752		if (WARN_ON(nr_vcpus == 0)) {
   753			ret = -ENODEV;
   754			goto fail;
   755	
   756		}
   757		kvm->arch.vgic.gicv5_vm.nr_vpes = nr_vcpus;
   758	
   759		/*
   760		 * We only allow userspace to drive the SW_PPI, if it is
   761		 * implemented.
   762		 */
   763		kvm->arch.vgic.gicv5_vm.userspace_ppis[0] = GICV5_SW_PPI & GICV5_HWIRQ_ID;
   764		kvm->arch.vgic.gicv5_vm.userspace_ppis[0] &= ppi_caps->impl_ppi_mask[0];
   765		kvm->arch.vgic.gicv5_vm.userspace_ppis[1] = 0;
   766	
   767		ret = vgic_v5_allocate_vm_id(kvm);
   768		if (ret)
   769			goto fail;
   770	
   771		if (vgic_v5_create_per_vm_domain(&kvm->arch.vgic.gicv5_vm))
   772			goto fail_cleanup_id;
   773	
   774		/*
   775		 * Allocate VPE doorbells first - these are our conduit for
   776		 * communicating with the host irqchip driver. Can't do any earlier as
   777		 * we wouldn't know the VM ID.
   778		 */
   779		db_virq = irq_domain_alloc_irqs(kvm->arch.vgic.gicv5_vm.domain,
   780						nr_vcpus, NUMA_NO_NODE,
   781						&kvm->arch.vgic.gicv5_vm);
   782		if (db_virq < 0) {
   783			ret = db_virq;
   784			goto fail_cleanup_domain;
   785		}
   786		kvm->arch.vgic.gicv5_vm.vpe_db_base = db_virq;
   787	
   788		kvm_for_each_vcpu(i, vcpu, kvm) {
   789			d = irq_domain_get_irq_data(kvm->arch.vgic.gicv5_vm.domain,
   790						    db_virq + i);
   791			irq_set_status_flags(db_virq + i, IRQ_NOAUTOEN);
   792	
   793			ret = request_irq(db_virq + i, db_handler, 0, "vcpu", vcpu);
   794			if (ret)
   795				goto fail_cleanup_partial_dbs;
   796	
   797			/* Stash it with the VCPU for easy retrieval */
   798			vcpu->arch.vgic_cpu.vgic_v5.gicv5_vpe.db = db_virq + i;
   799		}
   800	
   801		/* Populate VMTE (with VPET and VM descriptor) */
   802		ret = vgic_v5_vmte_init(kvm);
   803		if (ret)
   804			goto fail_cleanup_dbs;
   805	
   806		/* We pick the first vcpu to make the VMTE valid - any would do */
   807		vcpu0 = kvm_get_vcpu(kvm, 0);
   808		ret = vgic_v5_send_command(vcpu0, VMTE_MAKE_VALID);
   809		if (ret)
   810			goto fail_cleanup_vmte;
   811	
   812		/* Loop over all VPEs, allocate/populate their data structures */
   813		kvm_for_each_vcpu(i, vcpu, kvm) {
   814			ret = vgic_v5_vmte_alloc_vpe(vcpu);
   815			if (ret)
   816				goto fail_cleanup_vpes;
   817		}
   818	
   819		return ret;
   820	
   821	fail_cleanup_vpes:
   822		/* i contains the first vCPU that failed */
   823		if (i == 0)
   824			goto fail_cleanup_vmte;
   825	
   826		do {
   827			vcpu = kvm_get_vcpu(kvm, --i);
   828			vgic_v5_vmte_free_vpe(vcpu);
   829		} while (i != 0);
   830	
   831	fail_cleanup_vmte:
   832		vgic_v5_vmte_release(kvm);
   833	
   834	fail_cleanup_dbs:
   835		i = nr_vcpus;
   836	fail_cleanup_partial_dbs:
   837		/* i contains the first vCPU that failed */
   838		if (i == 0)
   839			goto fail_cleanup_domain;
   840	
   841		do {
   842			vcpu = kvm_get_vcpu(kvm, --i);
   843			vgic_v5_disable_vcpu(vcpu);
   844		} while (i != 0);
   845	
   846	fail_cleanup_domain:
   847		vgic_v5_teardown_per_vm_domain(&kvm->arch.vgic.gicv5_vm);
   848	
   849	fail_cleanup_id:
   850		vgic_v5_release_vm_id(kvm);
   851	
   852	fail:
   853		return ret;
   854	}
   855	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From lkp at intel.com  Mon Dec 22 08:52:47 2025
From: lkp at intel.com (kernel test robot)
Date: Mon, 22 Dec 2025 17:52:47 +0100
Subject: [PATCH 14/32] KVM: arm64: gic-v5: Implement GICv5 load/put and
 save/restore
In-Reply-To: <20251212152215.675767-15-sascha.bischoff@arm.com>
References: <20251212152215.675767-15-sascha.bischoff@arm.com>
Message-ID: <202512221751.nHKObHNq-lkp@intel.com>

Hi Sascha,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on v6.19-rc2 next-20251219]
[cannot apply to kvmarm/next arm64/for-next/core kvm/queue kvm/next kvm/linux-next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Sascha-Bischoff/KVM-arm64-Account-for-RES1-bits-in-DECLARE_FEAT_MAP-and-co/20251212-233140
base:   linus/master
patch link:    https://lore.kernel.org/r/20251212152215.675767-15-sascha.bischoff%40arm.com
patch subject: [PATCH 14/32] KVM: arm64: gic-v5: Implement GICv5 load/put and save/restore
config: arm64-allnoconfig-bpf (https://download.01.org/0day-ci/archive/20251222/202512221751.nHKObHNq-lkp at intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project ecaf673850beb241957352bd61e95ed34256635f)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251222/202512221751.nHKObHNq-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512221751.nHKObHNq-lkp at intel.com/

All errors (new ones prefixed by >>):

   In file included from arch/arm64/kernel/asm-offsets.c:16:
   In file included from ./include/linux/kvm_host.h:45:
   In file included from ./arch/arm64/include/asm/kvm_host.h:36:
>> ./include/kvm/arm_vgic.h:392:19: error: field has incomplete type 'struct gicv5_vpe'
     392 |         struct gicv5_vpe gicv5_vpe;
         |                          ^
   ./include/kvm/arm_vgic.h:392:9: note: forward declaration of 'struct gicv5_vpe'
     392 |         struct gicv5_vpe gicv5_vpe;
         |                ^
   1 error generated.


vim +392 ./include/kvm/arm_vgic.h

   360	
   361	struct vgic_v5_cpu_if {
   362		u64	vgic_apr;
   363		u64	vgic_vmcr;
   364	
   365		/* PPI register state */
   366		u64	vgic_ppi_hmr[2];
   367		u64	vgic_ppi_dvir[2];
   368		u64	vgic_ppi_priorityr[16];
   369	
   370		/* The pending state of the guest. This is merged with the exit state */
   371		u64	vgic_ppi_pendr[2];
   372	
   373		/* The state flushed to the regs when entering the guest */
   374		u64	vgic_ppi_activer_entry[2];
   375		u64	vgic_ich_ppi_enabler_entry[2];
   376		u64	vgic_ppi_pendr_entry[2];
   377	
   378		/* The saved state of the regs when leaving the guest */
   379		u64	vgic_ppi_activer_exit[2];
   380		u64	vgic_ich_ppi_enabler_exit[2];
   381		u64	vgic_ppi_pendr_exit[2];
   382	
   383		/*
   384		 * The ICSR is re-used across host and guest, and hence it needs to be
   385		 * saved/restored. Only one copy is required as the host should block
   386		 * preemption between executing GIC CDRCFG and acccessing the
   387		 * ICC_ICSR_EL1. A guest, of course, can never guarantee this, and hence
   388		 * it is the hyp's responsibility to keep the state constistent.
   389		 */
   390		u64	vgic_icsr;
   391	
 > 392		struct gicv5_vpe gicv5_vpe;
   393	};
   394	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From bartosz.golaszewski at oss.qualcomm.com  Mon Dec 22 08:57:44 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Mon, 22 Dec 2025 17:57:44 +0100
Subject: [PATCH v3 0/3] gpio: Simplify with device_get_match_data()
In-Reply-To: <20251219-gpio-of-match-v3-0-6b84194a02a8@oss.qualcomm.com>
References: <20251219-gpio-of-match-v3-0-6b84194a02a8@oss.qualcomm.com>
Message-ID: <176642266266.42223.9755579914845515277.b4-ty@oss.qualcomm.com>


On Fri, 19 Dec 2025 13:13:11 +0100, Krzysztof Kozlowski wrote:
> Changes in v3:
> - Fix subjects and commit msg -> device_get_match_data
> - Patch #3: Use dev_err_probe
> - Link to v2: https://patch.msgid.link/20251219-gpio-of-match-v2-0-5c65cbb513ac at oss.qualcomm.com
> 
> Changes in v2:
> - Drop applied patch
> - Use device_get_match_data() as suggested by Bartosz
> - Link to v1: https://patch.msgid.link/20251106-gpio-of-match-v1-0-50c7115a045e at linaro.org
> 
> [...]

Applied, thanks!

[1/3] gpio: aspeed: Simplify with device_get_match_data()
      commit: cecf10b700e06a2f2e2b638b1f680e1ae7f343ac
[2/3] gpio: creg-snps: Simplify with device_get_match_data()
      commit: da7c18a457c7a32c4ed1e1e326837d9d7cb4483c
[3/3] gpio: zynq: Simplify with device_get_match_data()
      commit: 48befae0d6eee275c3e30d1cd45f39d6ba011e19

Best regards,
-- 
Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>


From bmasney at redhat.com  Mon Dec 22 08:59:56 2025
From: bmasney at redhat.com (Brian Masney)
Date: Mon, 22 Dec 2025 11:59:56 -0500
Subject: [PATCH v15 3/3] clk: aspeed: add AST2700 clock driver
In-Reply-To: <TY2PPF5CB9A1BE64DCD487138F3BAC4FD34F2FCA@TY2PPF5CB9A1BE6.apcprd06.prod.outlook.com>
References: <20251010072540.666673-1-ryan_chen@aspeedtech.com>
 <20251010072540.666673-4-ryan_chen@aspeedtech.com>
 <TY2PPF5CB9A1BE64DCD487138F3BAC4FD34F2FCA@TY2PPF5CB9A1BE6.apcprd06.prod.outlook.com>
Message-ID: <aUl5DPMq8jC1xjRu@redhat.com>

Hi Ryan,

On Mon, Oct 27, 2025 at 06:24:59AM +0000, Ryan Chen wrote:
> Hello Stephen,
> 	Will this be accepted in clk-next?

Given that aspeed is a SoC vendor, and you already have multiple clk
drivers, I think at this point your best bet is to do what the other SoC
vendors currently do. I think you should:

- Create a new subdirectory drivers/clk/aspeed/
- Move the existing aspeed clk drivers into this subdirectory, and
  update the Makefiles / Kconfigs as appropriate.
- Add a new entry to the MAINTAINERS file for the aspeed clk drivers.
  You probably also want to have that entry cover the reset driver,
  and any other aspeed-specific drivers as well.
- Post that patch set. Include this new clk driver as a separate patch
  in that series. Feel free to CC me to the series and I'll review it
  for you.
- After it's reviewed, wait a week or two, and send Stephen a 
  'GIT PULL' using git request-pull. I can help you with the workflow
  if needed.
  
  One important detail is that you want to base your branch for the GIT
  PULL on the lowest common denominator, which is usually the latest rc1
  from Linus. So even if Linus is at rc5, try to base yours on rc1, unless
  there's some issue, and you need to document why. Stephen should get the
  merge to newer rcX branches from Linus, and not you.

When you send a PULL to Stephen, you can use 'b4 am' to assemble the
contents of your branch. When I sent him a PULL a few months ago, I
included the b4 commands that I used.

https://lore.kernel.org/all/aL8MXYrR5uoBa4cB at x1/

If he accepts the pull, you'll still need to post your patches to the
clk mailinglist, and have them reviewed on list. Folks from aspeed
should do that review publicly on the list.

Brian



From manivannan.sadhasivam at oss.qualcomm.com  Mon Dec 22 09:02:26 2025
From: manivannan.sadhasivam at oss.qualcomm.com (Manivannan Sadhasivam)
Date: Mon, 22 Dec 2025 22:32:26 +0530
Subject: [PATCH v2 0/6] PCI: dwc: Revert Link Up IRQ support
In-Reply-To: <20251222064207.3246632-8-cassel@kernel.org>
References: <20251222064207.3246632-8-cassel@kernel.org>
Message-ID: <176642294649.11053.7692165747212741983.b4-ty@kernel.org>


On Mon, 22 Dec 2025 07:42:07 +0100, Niklas Cassel wrote:
> Revert all patches related to pcie-designware Root Complex Link Up IRQ
> support.
> 
> While this fake hotplugging was a nice idea, it has shown that this feature
> does not handle PCIe switches correctly:
> pci_bus 0004:43: busn_res: can not insert [bus 43-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci_bus 0004:43: busn_res: [bus 43-41] end is updated to 43
> pci_bus 0004:43: busn_res: can not insert [bus 43] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci 0004:42:00.0: devices behind bridge are unusable because [bus 43] cannot be assigned for them
> pci_bus 0004:44: busn_res: can not insert [bus 44-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci_bus 0004:44: busn_res: [bus 44-41] end is updated to 44
> pci_bus 0004:44: busn_res: can not insert [bus 44] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci 0004:42:02.0: devices behind bridge are unusable because [bus 44] cannot be assigned for them
> pci_bus 0004:45: busn_res: can not insert [bus 45-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci_bus 0004:45: busn_res: [bus 45-41] end is updated to 45
> pci_bus 0004:45: busn_res: can not insert [bus 45] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci 0004:42:06.0: devices behind bridge are unusable because [bus 45] cannot be assigned for them
> pci_bus 0004:46: busn_res: can not insert [bus 46-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci_bus 0004:46: busn_res: [bus 46-41] end is updated to 46
> pci_bus 0004:46: busn_res: can not insert [bus 46] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci 0004:42:0e.0: devices behind bridge are unusable because [bus 46] cannot be assigned for them
> pci_bus 0004:42: busn_res: [bus 42-41] end is updated to 46
> pci_bus 0004:42: busn_res: can not insert [bus 42-46] under [bus 41] (conflicts with (null) [bus 41])
> pci 0004:41:00.0: devices behind bridge are unusable because [bus 42-46] cannot be assigned for them
> pcieport 0004:40:00.0: bridge has subordinate 41 but max busn 46
> 
> [...]

Applied, thanks!

[1/6] Revert "PCI: dw-rockchip: Don't wait for link since we can detect Link Up"
      commit: fc6298086bfacaa7003b0bd1da4e4f42b29f7d77
[2/6] Revert "PCI: dw-rockchip: Enumerate endpoints based on dll_link_up IRQ"
      commit: 180c3cfe36786d261a55da52a161f9e279b19a6f
[3/6] Revert "PCI: qcom: Don't wait for link if we can detect Link Up"
      commit: e9ce5b3804436301ab343bc14203a4c14b336d1b
[4/6] Revert "PCI: qcom: Enable MSI interrupts together with Link up if 'Global IRQ' is supported"
      commit: 7ebdefb87942073679e56cfbc5a72e8fc5441bfc
[5/6] Revert "PCI: qcom: Enumerate endpoints based on Link up event in 'global_irq' interrupt"
      commit: 9a9793b55854422652ea92625e48277c4651c0fd
[6/6] Revert "PCI: dwc: Don't wait for link up if driver can detect Link Up event"
      commit: 142d5869f6eec3110adda0ad2d931f5b3c22371d

Best regards,
-- 
Manivannan Sadhasivam <mani at kernel.org>



From broonie at kernel.org  Mon Dec 22 09:17:52 2025
From: broonie at kernel.org (Mark Brown)
Date: Mon, 22 Dec 2025 17:17:52 +0000
Subject: (subset) [PATCH 0/4] arm64: allwinner: a523: Support SPI
 controllers
In-Reply-To: <20251221110513.1850535-1-wens@kernel.org>
References: <20251221110513.1850535-1-wens@kernel.org>
Message-ID: <176642387228.913099.2681822678465821683.b4-ty@kernel.org>

On Sun, 21 Dec 2025 19:05:07 +0800, Chen-Yu Tsai wrote:
> This series adds support for the SPI controllers found in the Allwinner
> A523 SoC family. The SPI controller is almost the same as the ones in
> previous generations, except that it moved the "RX buffer count"
> register field to a separate register, and that register now reports
> the total count for RX buffer and FIFO.
> 
> In practice the driver has never cared about the buffer count, but if
> any implementation were to use it, this counts as a non-backward
> compatible change.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next

Thanks!

[1/4] spi: dt-bindings: sun6i: Add compatibles for A523's SPI controllers
      commit: e0c8755d44eb85afd40100586076c3dc4b62ee3b
[2/4] spi: sun6i: Support A523's SPI controllers
      commit: c81f30bde5b0449d9d82d31a66f0ffd608e610b5

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark



From leo.yan at arm.com  Mon Dec 22 09:36:53 2025
From: leo.yan at arm.com (Leo Yan)
Date: Mon, 22 Dec 2025 17:36:53 +0000
Subject: [PATCH] arm64: perf: fix syscalltbl path base
In-Reply-To: <ce4e1210-94c2-4664-885b-e39106905e21@app.fastmail.com>
References: <b2651f20-6f3a-49f5-9cd8-3fb028b2cab5@app.fastmail.com>
 <fcefc3c0-541d-40cc-84e3-9c2460308bdb@linaro.org>
 <23c07ac4-ff13-47a5-824a-e7af1d1847a3@app.fastmail.com>
 <bda366b4-fa53-4feb-a7ce-ee47cfc404b5@linaro.org>
 <20251215112818.GB681384@e132581.arm.com>
 <c8161700-ad9d-43d3-8c45-cfc110ebcd49@app.fastmail.com>
 <a5448524-a147-4edb-9359-bcee3d780eb6@linaro.org>
 <ce4e1210-94c2-4664-885b-e39106905e21@app.fastmail.com>
Message-ID: <20251222173653.GF9788@e132581.arm.com>

On Mon, Dec 22, 2025 at 11:42:49AM +0100, Arnd Bergmann wrote:
> On Mon, Dec 22, 2025, at 11:05, James Clark wrote:
> > On 21/12/2025 9:48 pm, Joel May wrote:
> >> On Mon, Dec 15, 2025, at 03:28, Leo Yan wrote:
> >> 
> >> This is my first time contributing to the Linux kernel, so please bare with
> >> my ignorance.  I don't know whether it's acceptable to consider patches
> >> that conceptually improve something without an actual problem they're
> >> solving.
> >> 
> >
> > No worries, thanks for sending the fix. Yes I think it could be ok to 
> > apply your patch anyway. I just wanted to make sure we were all on the 
> > same page with both fixes fixing the same thing.
> 
> I still don't think that Leo's series is correct.

As discussed, I will respin the series to use asm-generic/unistd.h for
arm64, this is consistent with other arches.

> > You might want to drop the fixes tag though to avoid confusion if Leo's 
> > one gets accepted, because then technically it doesn't fix anything any 
> > more. Keeping Leo's fixes: tag is a bit better because it fixes 
> > additional things and targets an older commit.
> 
> Before that gets applied, someone should explain why arm64 needs
> any special treatment at all. A lot of work has gone into making
> the syscall table handling consistent across architectures, so
> whether we ship a copy of the generated header for perf, we
> generate a new copy or we rely on 'make headers_install', should
> should really be done the same way across every architecture.

I agree arm64 is not a special case.

For the long term, I think "make headers_install" is worth trying.  The
main concern is that it introduces a dependency between tool builds
and the kernel.  However, if tools/selftests need the latest kernel
features, it's natural to depend on the latest headers.

Thanks,
Leo


From bmasney at redhat.com  Mon Dec 22 10:00:36 2025
From: bmasney at redhat.com (Brian Masney)
Date: Mon, 22 Dec 2025 13:00:36 -0500
Subject: [PATCH v4 04/21] clk: mediatek: Add MT8189 apmixedsys clock
 support
In-Reply-To: <20251215034944.2973003-5-irving-ch.lin@mediatek.com>
References: <20251215034944.2973003-1-irving-ch.lin@mediatek.com>
 <20251215034944.2973003-5-irving-ch.lin@mediatek.com>
Message-ID: <aUmHRCXNy45PrVLG@redhat.com>

On Mon, Dec 15, 2025 at 11:49:13AM +0800, irving.ch.lin wrote:
> From: Irving-CH Lin <irving-ch.lin at mediatek.com>
> 
> Add support for the MT8189 apmixedsys clock controller, which provides
> PLLs generated from SoC 26m.
> 
> Signed-off-by: Irving-CH Lin <irving-ch.lin at mediatek.com>
> ---
>  drivers/clk/mediatek/Kconfig                 |  13 ++
>  drivers/clk/mediatek/Makefile                |   1 +
>  drivers/clk/mediatek/clk-mt8189-apmixedsys.c | 192 +++++++++++++++++++
                        ^^^^^^^^^^^^^^^^^^^^^^^

This file, along with others in this series, is not listed in
MAINTAINERS. This is the current entry:

MEDIATEK MT6735 CLOCK & RESET DRIVERS
M:      Yassine Oudjana <y.oudjana at protonmail.com>
L:      linux-clk at vger.kernel.org
L:      linux-mediatek at lists.infradead.org (moderated for non-subscribers)
S:      Maintained
F:      drivers/clk/mediatek/clk-mt6735-apmixedsys.c
F:      drivers/clk/mediatek/clk-mt6735-imgsys.c
F:      drivers/clk/mediatek/clk-mt6735-infracfg.c
F:      drivers/clk/mediatek/clk-mt6735-mfgcfg.c
F:      drivers/clk/mediatek/clk-mt6735-pericfg.c
F:      drivers/clk/mediatek/clk-mt6735-topckgen.c
F:      drivers/clk/mediatek/clk-mt6735-vdecsys.c
F:      drivers/clk/mediatek/clk-mt6735-vencsys.c
F:      include/dt-bindings/clock/mediatek,mt6735-apmixedsys.h
F:      include/dt-bindings/clock/mediatek,mt6735-imgsys.h
F:      include/dt-bindings/clock/mediatek,mt6735-infracfg.h
F:      include/dt-bindings/clock/mediatek,mt6735-mfgcfg.h
F:      include/dt-bindings/clock/mediatek,mt6735-pericfg.h
F:      include/dt-bindings/clock/mediatek,mt6735-topckgen.h
F:      include/dt-bindings/clock/mediatek,mt6735-vdecsys.h
F:      include/dt-bindings/clock/mediatek,mt6735-vencsys.h
F:      include/dt-bindings/reset/mediatek,mt6735-infracfg.h
F:      include/dt-bindings/reset/mediatek,mt6735-mfgcfg.h
F:      include/dt-bindings/reset/mediatek,mt6735-pericfg.h
F:      include/dt-bindings/reset/mediatek,mt6735-vdecsys.h

Should the entries to MAINTAINERS be simplified to the following?

F:      drivers/clk/mediatek/
F:      include/dt-bindings/clock/mediatek,*

Brian



From hpausten at protonmail.com  Mon Dec 22 10:05:33 2025
From: hpausten at protonmail.com (Harry Austen)
Date: Mon, 22 Dec 2025 18:05:33 +0000
Subject: [PATCH] wifi: mt76: fix buffer overflow bug
Message-ID: <20251222180437.1938-1-hpausten@protonmail.com>

Prevents attempting to read an extra byte from the origin string.
Example stacktrace:

------------[ cut here ]------------
strnlen: detected buffer overflow: 17 byte read of buffer size 16
WARNING: lib/string_helpers.c:1036 at __fortify_report+0x2d/0x50, CPU#0: kworker/0:0/9
Modules linked in:
CPU: 0 UID: 0 PID: 9 Comm: kworker/0:0 Not tainted 6.19.0-rc2+ #13 PREEMPT(full)
Hardware name: Micro-Star International Co., Ltd. MS-7E24/B650M GAMING PLUS WIFI (MS-7E24), BIOS 1.C2 08/06/2025
Workqueue: events mt7921_init_work
RIP: 0010:__fortify_report+0x3f/0x50
Code: b6 c1 48 c7 c1 93 60 c0 95 48 8b 34 c5 50 9c 2a 95 48 8d 05 03 1f ee 01 40 f6 c7 01 48 c7 c7 3c 66 c4 95 48 0f 44 cf 48 89 c7 <67> 48 0f b9 3a c3 cc cc cc cc cc cc cc cc cc cc cc ba 2f 00 00 00
RSP: 0018:ffff9f370019fcd0 EFLAGS: 00010246
RAX: ffffffff9636a210 RBX: ffff9420525b1ea0 RCX: ffffffff95c4663c
RDX: 0000000000000011 RSI: ffffffff95cf5242 RDI: ffffffff9636a210
RBP: ffff9f370019fd70 R08: 0000000000000010 R09: ffff9f370019fbf1
R10: 0000000000000004 R11: 0000000000000000 R12: ffffffff95bb3ca3
R13: ffff9420525bb101 R14: 0000000000000000 R15: 00000000ffffffea
FS:  0000000000000000(0000) GS:ffff9427c79ae000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: ffff942526a01000 CR3: 00000005e5a2c000 CR4: 0000000000750ef0
PKRU: 55555554
Call Trace:
 <TASK>
 __fortify_panic+0x5/0x10
 mt76_connac2_load_patch+0x34f/0x360
 ? update_load_avg+0x1f1/0x840
 mt792x_load_firmware+0x35/0x150
 mt7921_run_firmware+0x28/0x4c0
 ? _raw_spin_unlock+0x12/0x30
 ? ____mt76_poll_msec+0x53/0xa0
 mt7921e_mcu_init+0xba/0x100
 mt7921_init_work+0x70/0x1c0
 process_scheduled_works+0x1f0/0x420
 worker_thread+0x296/0x370
 ? pr_cont_work+0x1c0/0x1c0
 kthread+0x213/0x240
 ? kthread_blkcg+0x40/0x40
 ret_from_fork+0xfa/0x1c0
 ? kthread_blkcg+0x40/0x40
 ret_from_fork_asm+0x11/0x20
 </TASK>
---[ end trace 0000000000000000 ]---
------------[ cut here ]------------
kernel BUG at lib/string_helpers.c:1043!
Oops: invalid opcode: 0000 [#1] SMP NOPTI
CPU: 0 UID: 0 PID: 9 Comm: kworker/0:0 Tainted: G        W           6.19.0-rc2+ #13 PREEMPT(full)
Tainted: [W]=WARN
Hardware name: Micro-Star International Co., Ltd. MS-7E24/B650M GAMING PLUS WIFI (MS-7E24), BIOS 1.C2 08/06/2025
Workqueue: events mt7921_init_work
RIP: 0010:__fortify_panic+0x5/0x10
Code: 1d 00 00 00 48 89 df 48 c7 c6 72 68 c8 95 5b 41 5e 41 5f e9 dd c2 4a 00 cc cc cc cc cc cc cc cc cc cc cc cc cc e8 bb b3 87 00 <0f> 0b cc cc cc cc cc cc cc cc cc 0f 1f 44 00 00 55 48 89 e5 41 56
RSP: 0018:ffff9f370019fcd8 EFLAGS: 00010246
RAX: ffffffff9636a210 RBX: ffff9420525b1ea0 RCX: ffffffff95c4663c
RDX: 0000000000000011 RSI: ffffffff95cf5242 RDI: ffffffff9636a210
RBP: ffff9f370019fd70 R08: 0000000000000010 R09: ffff9f370019fbf1
R10: 0000000000000004 R11: 0000000000000000 R12: ffffffff95bb3ca3
R13: ffff9420525bb101 R14: 0000000000000000 R15: 00000000ffffffea
FS:  0000000000000000(0000) GS:ffff9427c79ae000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: ffff942526a01000 CR3: 00000005e5a2c000 CR4: 0000000000750ef0
PKRU: 55555554
Call Trace:
 <TASK>
 mt76_connac2_load_patch+0x34f/0x360
 ? update_load_avg+0x1f1/0x840
 mt792x_load_firmware+0x35/0x150
 mt7921_run_firmware+0x28/0x4c0
 ? _raw_spin_unlock+0x12/0x30
 ? ____mt76_poll_msec+0x53/0xa0
 mt7921e_mcu_init+0xba/0x100
 mt7921_init_work+0x70/0x1c0
 process_scheduled_works+0x1f0/0x420
 worker_thread+0x296/0x370
 ? pr_cont_work+0x1c0/0x1c0
 kthread+0x213/0x240
 ? kthread_blkcg+0x40/0x40
 ret_from_fork+0xfa/0x1c0
 ? kthread_blkcg+0x40/0x40
 ret_from_fork_asm+0x11/0x20
 </TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:__fortify_panic+0x5/0x10
Code: 1d 00 00 00 48 89 df 48 c7 c6 72 68 c8 95 5b 41 5e 41 5f e9 dd c2 4a 00 cc cc cc cc cc cc cc cc cc cc cc cc cc e8 bb b3 87 00 <0f> 0b cc cc cc cc cc cc cc cc cc 0f 1f 44 00 00 55 48 89 e5 41 56
RSP: 0018:ffff9f370019fcd8 EFLAGS: 00010246
RAX: ffffffff9636a210 RBX: ffff9420525b1ea0 RCX: ffffffff95c4663c
RDX: 0000000000000011 RSI: ffffffff95cf5242 RDI: ffffffff9636a210
RBP: ffff9f370019fd70 R08: 0000000000000010 R09: ffff9f370019fbf1
R10: 0000000000000004 R11: 0000000000000000 R12: ffffffff95bb3ca3
R13: ffff9420525bb101 R14: 0000000000000000 R15: 00000000ffffffea
FS:  0000000000000000(0000) GS:ffff9427c79ae000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: ffff942526a01000 CR3: 00000005e5a2c000 CR4: 0000000000750ef0
PKRU: 55555554

Fixes: f804a5895eba ("wifi: mt76: Strip whitespace from build ddate")
Signed-off-by: Harry Austen <hpausten at protonmail.com>
---
 drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
index ea99167765b0c..b735b3671fab5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
@@ -3101,7 +3101,7 @@ int mt76_connac2_load_patch(struct mt76_dev *dev, const char *fw_name)
 	int i, ret, sem, max_len = mt76_is_sdio(dev) ? 2048 : 4096;
 	const struct mt76_connac2_patch_hdr *hdr;
 	const struct firmware *fw = NULL;
-	char build_date[17];
+	char build_date[sizeof(hdr->build_date) + 1];
 
 	sem = mt76_connac_mcu_patch_sem_ctrl(dev, true);
 	switch (sem) {
@@ -3125,8 +3125,8 @@ int mt76_connac2_load_patch(struct mt76_dev *dev, const char *fw_name)
 	}
 
 	hdr = (const void *)fw->data;
-	strscpy(build_date, hdr->build_date, sizeof(build_date));
-	build_date[16] = '\0';
+	strscpy(build_date, hdr->build_date, sizeof(hdr->build_date));
+	build_date[sizeof(hdr->build_date)] = '\0';
 	strim(build_date);
 	dev_info(dev->dev, "HW/SW Version: 0x%x, Build Time: %.16s\n",
 		 be32_to_cpu(hdr->hw_sw_ver), build_date);
-- 
2.52.0




From andrew.jones at linux.dev  Mon Dec 22 10:06:08 2025
From: andrew.jones at linux.dev (Andrew Jones)
Date: Mon, 22 Dec 2025 12:06:08 -0600
Subject: [PATCH v2 2/5] KVM: arm64: selftests: Fix incorrect rounding in
 page_align()
In-Reply-To: <20251215165155.3451819-3-tabba@google.com>
References: <20251215165155.3451819-1-tabba@google.com>
 <20251215165155.3451819-3-tabba@google.com>
Message-ID: <20251222-f8d98d81659c01f79e16da2f@orel>

On Mon, Dec 15, 2025 at 04:51:52PM +0000, Fuad Tabba wrote:
> The implementation of `page_align()` in `processor.c` calculates
> alignment incorrectly for values that are already aligned. Specifically,
> `(v + vm->page_size) & ~(vm->page_size - 1)` aligns to the *next* page
> boundary even if `v` is already page-aligned, potentially wasting a page
> of memory.
> 
> Fix the calculation to use standard alignment logic: `(v + vm->page_size
> - 1) & ~(vm->page_size - 1)`.
> 
> Fixes: 7a6629ef746d ("kvm: selftests: add virt mem support for aarch64")
> Signed-off-by: Fuad Tabba <tabba at google.com>
> ---
>  tools/testing/selftests/kvm/lib/arm64/processor.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/testing/selftests/kvm/lib/arm64/processor.c
> index 5b379da8cb90..607a4e462984 100644
> --- a/tools/testing/selftests/kvm/lib/arm64/processor.c
> +++ b/tools/testing/selftests/kvm/lib/arm64/processor.c
> @@ -23,7 +23,7 @@ static vm_vaddr_t exception_handlers;
>  
>  static uint64_t page_align(struct kvm_vm *vm, uint64_t v)
>  {
> -	return (v + vm->page_size) & ~(vm->page_size - 1);
> +	return (v + vm->page_size - 1) & ~(vm->page_size - 1);
>  }
>  
>  static uint64_t pgd_index(struct kvm_vm *vm, vm_vaddr_t gva)
> -- 
> 2.52.0.239.gd5f0c6e74e-goog
> 
>

Thanks for finding and fixing this. I'll get my paper bag out later.

Reviewed-by: Andrew Jones <andrew.jones at linux.dev>


From andrew.jones at linux.dev  Mon Dec 22 10:06:47 2025
From: andrew.jones at linux.dev (Andrew Jones)
Date: Mon, 22 Dec 2025 12:06:47 -0600
Subject: [PATCH v2 3/5] KVM: riscv: selftests: Fix incorrect rounding in
 page_align()
In-Reply-To: <20251215165155.3451819-4-tabba@google.com>
References: <20251215165155.3451819-1-tabba@google.com>
 <20251215165155.3451819-4-tabba@google.com>
Message-ID: <20251222-67bdefbbd6f1687ffbcabf81@orel>

On Mon, Dec 15, 2025 at 04:51:53PM +0000, Fuad Tabba wrote:
> The implementation of `page_align()` in `processor.c` calculates
> alignment incorrectly for values that are already aligned. Specifically,
> `(v + vm->page_size) & ~(vm->page_size - 1)` aligns to the *next* page
> boundary even if `v` is already page-aligned, potentially wasting a page
> of memory.
> 
> Fix the calculation to use standard alignment logic: `(v + vm->page_size
> - 1) & ~(vm->page_size - 1)`.
> 
> Fixes: 3e06cdf10520 ("KVM: selftests: Add initial support for RISC-V 64-bit")
> Signed-off-by: Fuad Tabba <tabba at google.com>
> ---
>  tools/testing/selftests/kvm/lib/riscv/processor.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c
> index 2eac7d4b59e9..d5e8747b5e69 100644
> --- a/tools/testing/selftests/kvm/lib/riscv/processor.c
> +++ b/tools/testing/selftests/kvm/lib/riscv/processor.c
> @@ -28,7 +28,7 @@ bool __vcpu_has_ext(struct kvm_vcpu *vcpu, uint64_t ext)
>  
>  static uint64_t page_align(struct kvm_vm *vm, uint64_t v)
>  {
> -	return (v + vm->page_size) & ~(vm->page_size - 1);
> +	return (v + vm->page_size - 1) & ~(vm->page_size - 1);
>  }
>  
>  static uint64_t pte_addr(struct kvm_vm *vm, uint64_t entry)
> -- 
> 2.52.0.239.gd5f0c6e74e-goog

Reviewed-by: Andrew Jones <andrew.jones at linux.dev>


From bmasney at redhat.com  Mon Dec 22 10:09:43 2025
From: bmasney at redhat.com (Brian Masney)
Date: Mon, 22 Dec 2025 13:09:43 -0500
Subject: [PATCH] clk: mediatek: don't select clk-mt8192 for all ARM64
 builds
In-Reply-To: <20251222150235.34919-1-bartosz.golaszewski@oss.qualcomm.com>
References: <20251222150235.34919-1-bartosz.golaszewski@oss.qualcomm.com>
Message-ID: <aUmJZ7o6PpWeXFZP@redhat.com>

On Mon, Dec 22, 2025 at 04:02:35PM +0100, Bartosz Golaszewski wrote:
> This option defaults to y for ARCH64 meaning it's built even if we don't
> want anything related to mediatek. Make the default condition stricter
> and only build it if ARCH_MEDIATEK is selected.
> 
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>

Reviewed-by: Brian Masney <bmasney at redhat.com>



From andrew.jones at linux.dev  Mon Dec 22 10:11:18 2025
From: andrew.jones at linux.dev (Andrew Jones)
Date: Mon, 22 Dec 2025 12:11:18 -0600
Subject: [PATCH v2 4/5] KVM: selftests: Move page_align() to shared header
In-Reply-To: <20251215165155.3451819-5-tabba@google.com>
References: <20251215165155.3451819-1-tabba@google.com>
 <20251215165155.3451819-5-tabba@google.com>
Message-ID: <20251222-ed460d0e29ab66fb4987e365@orel>

On Mon, Dec 15, 2025 at 04:51:54PM +0000, Fuad Tabba wrote:
> To avoid code duplication, move page_align() to the shared `kvm_util.h`
> header file.
> 
> No functional change intended.
> 
> Signed-off-by: Fuad Tabba <tabba at google.com>
> ---
>  tools/testing/selftests/kvm/include/kvm_util.h    | 5 +++++
>  tools/testing/selftests/kvm/lib/arm64/processor.c | 5 -----
>  tools/testing/selftests/kvm/lib/riscv/processor.c | 5 -----
>  3 files changed, 5 insertions(+), 10 deletions(-)
> 
> diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
> index 81f4355ff28a..dabbe4c3b93f 100644
> --- a/tools/testing/selftests/kvm/include/kvm_util.h
> +++ b/tools/testing/selftests/kvm/include/kvm_util.h
> @@ -1258,6 +1258,11 @@ static inline int __vm_disable_nx_huge_pages(struct kvm_vm *vm)
>  	return __vm_enable_cap(vm, KVM_CAP_VM_DISABLE_NX_HUGE_PAGES, 0);
>  }
>  
> +static inline uint64_t page_align(struct kvm_vm *vm, uint64_t v)
> +{
> +	return (v + vm->page_size - 1) & ~(vm->page_size - 1);
> +}
> +
>  /*
>   * Arch hook that is invoked via a constructor, i.e. before exeucting main(),
>   * to allow for arch-specific setup that is common to all tests, e.g. computing
> diff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/testing/selftests/kvm/lib/arm64/processor.c
> index 607a4e462984..143632917766 100644
> --- a/tools/testing/selftests/kvm/lib/arm64/processor.c
> +++ b/tools/testing/selftests/kvm/lib/arm64/processor.c
> @@ -21,11 +21,6 @@
>  
>  static vm_vaddr_t exception_handlers;
>  
> -static uint64_t page_align(struct kvm_vm *vm, uint64_t v)
> -{
> -	return (v + vm->page_size - 1) & ~(vm->page_size - 1);
> -}
> -
>  static uint64_t pgd_index(struct kvm_vm *vm, vm_vaddr_t gva)
>  {
>  	unsigned int shift = (vm->pgtable_levels - 1) * (vm->page_shift - 3) + vm->page_shift;
> diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c
> index d5e8747b5e69..f8ff4bf938d9 100644
> --- a/tools/testing/selftests/kvm/lib/riscv/processor.c
> +++ b/tools/testing/selftests/kvm/lib/riscv/processor.c
> @@ -26,11 +26,6 @@ bool __vcpu_has_ext(struct kvm_vcpu *vcpu, uint64_t ext)
>  	return !ret && !!value;
>  }
>  
> -static uint64_t page_align(struct kvm_vm *vm, uint64_t v)
> -{
> -	return (v + vm->page_size - 1) & ~(vm->page_size - 1);
> -}
> -
>  static uint64_t pte_addr(struct kvm_vm *vm, uint64_t entry)
>  {
>  	return ((entry & PGTBL_PTE_ADDR_MASK) >> PGTBL_PTE_ADDR_SHIFT) <<
> -- 
> 2.52.0.239.gd5f0c6e74e-goog
> 
>

kvm_util.h is collecting a bit too much random stuff and it'd be nice to
split stuff out rather than add more, but, for now, this is an overall
improvement since we kill some duplication.

Reviewed-by: Andrew Jones <andrew.jones at linux.dev>

Thanks,
drew


From andrew.jones at linux.dev  Mon Dec 22 10:13:58 2025
From: andrew.jones at linux.dev (Andrew Jones)
Date: Mon, 22 Dec 2025 12:13:58 -0600
Subject: [PATCH v2 5/5] KVM: selftests: Fix typos and stale comments in
 kvm_util
In-Reply-To: <20251215165155.3451819-6-tabba@google.com>
References: <20251215165155.3451819-1-tabba@google.com>
 <20251215165155.3451819-6-tabba@google.com>
Message-ID: <20251222-5d40dd87b6e6d0308ff1e900@orel>

On Mon, Dec 15, 2025 at 04:51:55PM +0000, Fuad Tabba wrote:
> Fix minor documentation errors in `kvm_util.h` and `kvm_util.c`.
> 
> - Correct the argument description for `vcpu_args_set` in `kvm_util.h`,
>   which incorrectly listed `vm` instead of `vcpu`.
> - Fix a typo in the comment for `kvm_selftest_arch_init` ("exeucting" ->
>   "executing").
> - Correct the return value description for `vm_vaddr_unused_gap` in
>   `kvm_util.c` to match the implementation, which returns an address "at
>   or above" `vaddr_min`, not "at or below".
> 
> No functional change intended.
> 
> Signed-off-by: Fuad Tabba <tabba at google.com>
> ---
>  tools/testing/selftests/kvm/include/kvm_util.h | 4 ++--
>  tools/testing/selftests/kvm/lib/kvm_util.c     | 2 +-
>  2 files changed, 3 insertions(+), 3 deletions(-)
>

Reviewed-by: Andrew Jones <andrew.jones at linux.dev>


From lkp at intel.com  Mon Dec 22 10:29:18 2025
From: lkp at intel.com (kernel test robot)
Date: Tue, 23 Dec 2025 02:29:18 +0800
Subject: [arm-platforms:kvm-arm64/gicv5-full 78/82]
 arch/arm64/kvm/vgic/vgic-v5-tables.c:1186:44: warning: variable 'host_l2sz'
 set but not used
Message-ID: <202512230249.PtF5RcJh-lkp@intel.com>

tree:   https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git kvm-arm64/gicv5-full
head:   1426b88096b597395df4c82f089b87c62bab45da
commit: ba5d2e0b287e57a009751d6a993a4b31206fd97b [78/82] KVM: arm64: gic-v5: Implement Save/Restore for ISTs
config: arm64-randconfig-003-20251222 (https://download.01.org/0day-ci/archive/20251223/202512230249.PtF5RcJh-lkp at intel.com/config)
compiler: aarch64-linux-gcc (GCC) 11.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251223/202512230249.PtF5RcJh-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512230249.PtF5RcJh-lkp at intel.com/

All warnings (new ones prefixed by >>):

   arch/arm64/kvm/vgic/vgic-v5-tables.c: In function 'vgic_v5_save_spi_ist':
>> arch/arm64/kvm/vgic/vgic-v5-tables.c:1186:44: warning: variable 'host_l2sz' set but not used [-Wunused-but-set-variable]
    1186 |         unsigned host_id_bits, host_istsz, host_l2sz;
         |                                            ^~~~~~~~~
   arch/arm64/kvm/vgic/vgic-v5-tables.c: In function 'vgic_v5_restore_spi_ist':
   arch/arm64/kvm/vgic/vgic-v5-tables.c:1380:44: warning: variable 'host_l2sz' set but not used [-Wunused-but-set-variable]
    1380 |         unsigned host_id_bits, host_istsz, host_l2sz;
         |                                            ^~~~~~~~~


vim +/host_l2sz +1186 arch/arm64/kvm/vgic/vgic-v5-tables.c

  1179	
  1180	int vgic_v5_save_spi_ist(struct kvm *kvm, struct kvm_device_attr *attr)
  1181	{
  1182		u16 vm_id = vgic_v5_vm_id(kvm);
  1183		u32 __user *uaddr = (u32 __user *)(unsigned long)attr->addr;
  1184		int ret = 0;
  1185		__le32 h_iste;
> 1186		unsigned host_id_bits, host_istsz, host_l2sz;
  1187		volatile void *host_ist_base;
  1188		struct vmtl2_entry *vmte;
  1189		gicv5_vm_info *vmi;
  1190	
  1191		ret = vgic_v5_check_vm_id(vm_id);
  1192		if (ret)
  1193			return ret;
  1194	
  1195		vmi = xa_load(&vm_info, vm_id);
  1196		if (WARN_ON_ONCE(!vmi))
  1197			return -EINVAL;
  1198	
  1199		ret = vgic_v5_get_l2_vmte(vm_id, &vmte);
  1200		if (ret)
  1201			return ret;
  1202	
  1203		host_ist_base = vmi->h_spi_ist;
  1204		if (!host_ist_base && attr)
  1205			return -ENOENT;
  1206		else if (host_ist_base && !attr)
  1207			return -EINVAL;
  1208	
  1209		host_id_bits = FIELD_GET(GICV5_VMTEL2E_IST_ID_BITS, vmte->val[3]);
  1210		host_istsz = FIELD_GET(GICV5_VMTEL2E_IST_ISTSZ, vmte->val[3]);
  1211		host_l2sz = FIELD_GET(GICV5_VMTEL2E_IST_L2SZ, vmte->val[3]);
  1212	
  1213		for (int i = 0; i < BIT(host_id_bits); ++i) {
  1214			volatile void *h_iste_addr = host_ist_base + i * BIT(host_istsz + 2);
  1215			h_iste = *((__le32*)h_iste_addr);
  1216	
  1217			ret = put_user(h_iste, uaddr);
  1218			if (ret)
  1219				return ret;
  1220	
  1221			uaddr++;
  1222		}
  1223	
  1224		return ret;
  1225	}
  1226	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From seanjc at google.com  Mon Dec 22 11:34:33 2025
From: seanjc at google.com (Sean Christopherson)
Date: Mon, 22 Dec 2025 11:34:33 -0800
Subject: possible deadlock due to irq_set_thread_affinity() calling into
 the scheduler (was Re: [PATCH v3 38/62] KVM: SVM: Take and hold ir_list_lock
 across IRTE updates in IOMMU)
In-Reply-To: <42513cb3-3c2e-4aa8-b748-23b6656a5096@redhat.com>
References: <20250611224604.313496-2-seanjc@google.com> <20250611224604.313496-40-seanjc@google.com>
 <njhjud3e6wbdftzr3ziyuh5bhyvc5ndt5qvmg7rlvh5isoop2l@f2uxctws2c7d> <42513cb3-3c2e-4aa8-b748-23b6656a5096@redhat.com>
Message-ID: <aUmdSb3d7Z5REMLk@google.com>

On Mon, Dec 22, 2025, Paolo Bonzini wrote:
> On 12/22/25 10:16, Ankit Soni wrote:
> >    ======================================================
> >    WARNING: possible circular locking dependency detected
> >    6.19.0-rc2 #20 Tainted: G            E
> >    ------------------------------------------------------
> >    CPU 58/KVM/28597 is trying to acquire lock:
> >      ff12c47d4b1f34c0 (&irq_desc_lock_class){-.-.}-{2:2}, at: __irq_get_desc_lock+0x58/0xa0
> > 
> >      but task is already holding lock:
> >      ff12c49b28552110 (&svm->ir_list_lock){....}-{2:2}, at: avic_pi_update_irte+0x147/0x270 [kvm_amd]
> > 
> >      which lock already depends on the new lock.
> > 
> >    Chain exists of:
> >      &irq_desc_lock_class --> &rq->__lock --> &svm->ir_list_lock
> > 
> >    Possible unsafe locking scenario:
> > 
> >          CPU0                            CPU1
> >          ----                            ----
> >     lock(&svm->ir_list_lock);
> >                                        lock(&rq->__lock);
> >                                        lock(&svm->ir_list_lock);
> >     lock(&irq_desc_lock_class);
> > 
> >          *** DEADLOCK ***
> > 
> > So lockdep sees:
> > 
> >    &irq_desc_lock_class -> &rq->__lock -> &svm->ir_list_lock
> > 
> > while avic_pi_update_irte() currently holds svm->ir_list_lock and then
> > takes irq_desc_lock via irq_set_vcpu_affinity(), which creates the
> > potential inversion.
> > 
> >    - Is this lockdep warning expected/benign in this code path, or does it
> >      indicate a real potential deadlock between svm->ir_list_lock and
> >      irq_desc_lock with AVIC + irq_bypass + VFIO?
> 
> I'd treat it as a potential (if unlikely) deadlock:
> 
> (a) irq_set_thread_affinity triggers the scheduler via wake_up_process,
> while irq_desc->lock is taken
> 
> (b) the scheduler calls into KVM with rq_lock taken, and KVM uses
> ir_list_lock within __avic_vcpu_load/__avic_vcpu_put
> 
> (c) KVM wants to block scheduling for a while and uses ir_list_lock for
> that purpose, but then takes irq_set_vcpu_affinity takes irq_desc->lock.
> 
> I don't think there's an alternative choice of lock for (c); and there's
> no easy way to pull the irq_desc->lock out of the IRQ subsystem--in fact
> the stickiness of the situation comes from rq->rq_lock and
> irq_desc->lock being both internal and not leaf.
> 
> Of the three, the most sketchy is (a);

Maybe the most unnecessary, but I think there's a pretty strong argument that
(d) is the most sketchy:

  (d) KVM takes svm->ir_list_lock around the call to irq_set_vcpu_affinity()

> notably, __setup_irq() calls wake_up_process outside desc->lock.  Therefore
> I'd like so much to treat it as a kernel/irq/ bug; and the simplest (perhaps
> too simple...) fix is to drop the wake_up_process().  The only cost is extra
> latency on the next interrupt after an affinity change.

Alternatively, what if we rework the KVM<=>IOMMU exchange to decouple updating
the IRTE from binding the metadata to the vCPU?  KVM already has the necessary
exports to do "out-of-band" updates due to the AVIC architecture requiring IRTE
updates on scheduling changes.

It's a bit wonky (and not yet tested), but I like the idea of making
svm->ir_list_lock a leaf lock so that we don't end up with a game of whack-a-mole,
e.g. if something in the IRQ subsystem changes in the future.

---
 arch/x86/include/asm/irq_remapping.h |  3 --
 arch/x86/kvm/svm/avic.c              | 78 ++++++++++++++++++----------
 drivers/iommu/amd/iommu.c            | 24 +++------
 3 files changed, 57 insertions(+), 48 deletions(-)

diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h
index 4e55d1755846..1426ecd09943 100644
--- a/arch/x86/include/asm/irq_remapping.h
+++ b/arch/x86/include/asm/irq_remapping.h
@@ -35,9 +35,6 @@ struct amd_iommu_pi_data {
 	u64 vapic_addr;		/* Physical address of the vCPU's vAPIC. */
 	u32 ga_tag;
 	u32 vector;		/* Guest vector of the interrupt */
-	int cpu;
-	bool ga_log_intr;
-	bool is_guest_mode;
 	void *ir_data;
 };
 
diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c
index 6b77b2033208..0f4f353c7db6 100644
--- a/arch/x86/kvm/svm/avic.c
+++ b/arch/x86/kvm/svm/avic.c
@@ -868,6 +868,51 @@ static void svm_ir_list_del(struct kvm_kernel_irqfd *irqfd)
 	raw_spin_unlock_irqrestore(&to_svm(vcpu)->ir_list_lock, flags);
 }
 
+static int avic_pi_add_irte(struct kvm_kernel_irqfd *irqfd, void *ir_data,
+			    struct kvm_vcpu *vcpu)
+{
+	struct vcpu_svm *svm = to_svm(vcpu);
+	int r;
+
+	/*
+	 * Prevent the vCPU from being scheduled out or migrated until the IRTE
+	 * is updated and its metadata has been added to the list of IRQs being
+	 * posted to the vCPU, to ensure the IRTE isn't programmed with stale
+	 * pCPU/IsRunning information.
+	 */
+	guard(raw_spinlock_irqsave)(&svm->ir_list_lock);
+
+	if (kvm_vcpu_apicv_active(vcpu)) {
+		u64 entry = svm->avic_physical_id_entry;
+		bool ga_log_intr;
+		int cpu;
+
+		/*
+		 * Update the target pCPU for IOMMU doorbells if the vCPU is
+		 * running.  If the vCPU is NOT running, i.e. is blocking or
+		 * scheduled out, KVM will update the pCPU info when the vCPU
+		 * is awakened and/or scheduled in.  See also avic_vcpu_load().
+		 */
+		if (entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK) {
+			cpu = entry & AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK;
+			ga_log_intr = false;
+		} else {
+			cpu = -1;
+			ga_log_intr = entry & AVIC_PHYSICAL_ID_ENTRY_GA_LOG_INTR;
+		}
+		r = amd_iommu_activate_guest_mode(ir_data, cpu, ga_log_intr);
+	} else {
+		r = amd_iommu_deactivate_guest_mode(ir_data);
+	}
+
+	if (r)
+		return r;
+
+	irqfd->irq_bypass_data = ir_data;
+	list_add(&irqfd->vcpu_list, &svm->ir_list);
+	return 0;
+}
+
 int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
 			unsigned int host_irq, uint32_t guest_irq,
 			struct kvm_vcpu *vcpu, u32 vector)
@@ -888,36 +933,11 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
 		struct amd_iommu_pi_data pi_data = {
 			.ga_tag = AVIC_GATAG(to_kvm_svm(kvm)->avic_vm_id,
 					     vcpu->vcpu_idx),
-			.is_guest_mode = kvm_vcpu_apicv_active(vcpu),
 			.vapic_addr = avic_get_backing_page_address(to_svm(vcpu)),
 			.vector = vector,
 		};
-		struct vcpu_svm *svm = to_svm(vcpu);
-		u64 entry;
 		int ret;
 
-		/*
-		 * Prevent the vCPU from being scheduled out or migrated until
-		 * the IRTE is updated and its metadata has been added to the
-		 * list of IRQs being posted to the vCPU, to ensure the IRTE
-		 * isn't programmed with stale pCPU/IsRunning information.
-		 */
-		guard(raw_spinlock_irqsave)(&svm->ir_list_lock);
-
-		/*
-		 * Update the target pCPU for IOMMU doorbells if the vCPU is
-		 * running.  If the vCPU is NOT running, i.e. is blocking or
-		 * scheduled out, KVM will update the pCPU info when the vCPU
-		 * is awakened and/or scheduled in.  See also avic_vcpu_load().
-		 */
-		entry = svm->avic_physical_id_entry;
-		if (entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK) {
-			pi_data.cpu = entry & AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK;
-		} else {
-			pi_data.cpu = -1;
-			pi_data.ga_log_intr = entry & AVIC_PHYSICAL_ID_ENTRY_GA_LOG_INTR;
-		}
-
 		ret = irq_set_vcpu_affinity(host_irq, &pi_data);
 		if (ret)
 			return ret;
@@ -932,9 +952,11 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
 			return -EIO;
 		}
 
-		irqfd->irq_bypass_data = pi_data.ir_data;
-		list_add(&irqfd->vcpu_list, &svm->ir_list);
-		return 0;
+		ret = avic_pi_add_irte(irqfd, pi_data.ir_data, vcpu);
+		if (WARN_ON_ONCE(ret))
+			irq_set_vcpu_affinity(host_irq, NULL);
+
+		return ret;
 	}
 	return irq_set_vcpu_affinity(host_irq, NULL);
 }
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 5d45795c367a..855c6309900c 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -3970,7 +3970,6 @@ EXPORT_SYMBOL(amd_iommu_deactivate_guest_mode);
 
 static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *info)
 {
-	int ret;
 	struct amd_iommu_pi_data *pi_data = info;
 	struct amd_ir_data *ir_data = data->chip_data;
 	struct irq_2_irte *irte_info = &ir_data->irq_2_irte;
@@ -3993,25 +3992,16 @@ static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *info)
 
 	ir_data->cfg = irqd_cfg(data);
 
-	if (pi_data) {
-		pi_data->ir_data = ir_data;
+	if (!pi_data)
+		return amd_iommu_deactivate_guest_mode(ir_data);
 
-		ir_data->ga_root_ptr = (pi_data->vapic_addr >> 12);
-		ir_data->ga_vector = pi_data->vector;
-		ir_data->ga_tag = pi_data->ga_tag;
-		if (pi_data->is_guest_mode)
-			ret = amd_iommu_activate_guest_mode(ir_data, pi_data->cpu,
-							    pi_data->ga_log_intr);
-		else
-			ret = amd_iommu_deactivate_guest_mode(ir_data);
-	} else {
-		ret = amd_iommu_deactivate_guest_mode(ir_data);
-	}
-
-	return ret;
+	pi_data->ir_data = ir_data;
+	ir_data->ga_root_ptr = (pi_data->vapic_addr >> 12);
+	ir_data->ga_vector = pi_data->vector;
+	ir_data->ga_tag = pi_data->ga_tag;
+	return 0;
 }
 
-
 static void amd_ir_update_irte(struct irq_data *irqd, struct amd_iommu *iommu,
 			       struct amd_ir_data *ir_data,
 			       struct irq_2_irte *irte_info,

base-commit: 9448598b22c50c8a5bb77a9103e2d49f134c9578
--


From lkp at intel.com  Mon Dec 22 11:55:06 2025
From: lkp at intel.com (kernel test robot)
Date: Tue, 23 Dec 2025 03:55:06 +0800
Subject: [arm-platforms:kvm-arm64/gicv5-full 79/82]
 arch/arm64/kvm/vgic/vgic-kvm-device.c:814:15: warning: variable 'addr' set
 but not used
Message-ID: <202512230356.D7sdAEag-lkp@intel.com>

tree:   https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git kvm-arm64/gicv5-full
head:   1426b88096b597395df4c82f089b87c62bab45da
commit: 68c9d49d6ae8b462ac80a902806969a43ac20de0 [79/82] KVM: arm64: gic-v5: Plumb in has/set/get for sysregs & IRS
config: arm64-randconfig-003-20251222 (https://download.01.org/0day-ci/archive/20251223/202512230356.D7sdAEag-lkp at intel.com/config)
compiler: aarch64-linux-gcc (GCC) 11.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251223/202512230356.D7sdAEag-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512230356.D7sdAEag-lkp at intel.com/

All warnings (new ones prefixed by >>):

   arch/arm64/kvm/vgic/vgic-kvm-device.c: In function 'vgic_v5_attr_regs_access':
>> arch/arm64/kvm/vgic/vgic-kvm-device.c:814:15: warning: variable 'addr' set but not used [-Wunused-but-set-variable]
     814 |         gpa_t addr;
         |               ^~~~
--
   arch/arm64/kvm/vgic/vgic-irs-v5.c: In function 'vgic_v5_has_attr_regs':
>> arch/arm64/kvm/vgic/vgic-irs-v5.c:988:15: warning: variable 'addr' set but not used [-Wunused-but-set-variable]
     988 |         gpa_t addr, offset;
         |               ^~~~


vim +/addr +814 arch/arm64/kvm/vgic/vgic-kvm-device.c

   801	
   802	/*
   803	 * vgic_v5_attr_regs_access - allows user space to access VGIC v5 state
   804	 *
   805	 * @dev:      kvm device handle
   806	 * @attr:     kvm device attribute
   807	 * @is_write: true if userspace is writing a register
   808	 */
   809	static int vgic_v5_attr_regs_access(struct kvm_device *dev,
   810					    struct kvm_device_attr *attr,
   811					    bool is_write)
   812	{
   813		struct vgic_reg_attr reg_attr;
 > 814		gpa_t addr;
   815		struct kvm_vcpu *vcpu;
   816		bool uaccess;
   817		u64 val;
   818		int ret;
   819	
   820		ret = vgic_v5_parse_attr(dev, attr, &reg_attr);
   821		if (ret)
   822			return ret;
   823	
   824		vcpu = reg_attr.vcpu;
   825		addr = reg_attr.addr;
   826	
   827		switch (attr->group) {
   828		case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS:
   829			/* Sysregs uaccess is performed by the sysreg handling code */
   830			uaccess = false;
   831			break;
   832		case KVM_DEV_ARM_VGIC_GRP_IRS_REGS: fallthrough;
   833		default:
   834			uaccess = true;
   835		}
   836	
   837		if (uaccess && is_write) {
   838			u64 __user *uaddr = (u64 __user *)(unsigned long)attr->addr;
   839			if (get_user(val, uaddr))
   840				return -EFAULT;
   841		}
   842	
   843		mutex_lock(&dev->kvm->lock);
   844	
   845		if (kvm_trylock_all_vcpus(dev->kvm)) {
   846			mutex_unlock(&dev->kvm->lock);
   847			return -EBUSY;
   848		}
   849	
   850		mutex_lock(&dev->kvm->arch.config_lock);
   851	
   852		if (!(vgic_initialized(dev->kvm) || v5_reg_allowed_pre_init(attr))) {
   853			ret = -EBUSY;
   854			goto out;
   855		}
   856	
   857		switch (attr->group) {
   858		case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS:
   859			ret = vgic_v5_cpu_sysregs_uaccess(vcpu, attr, is_write);
   860			break;
   861		case KVM_DEV_ARM_VGIC_GRP_IRS_REGS:
   862			ret = vgic_v5_irs_attr_regs_access(dev, attr, &val, is_write);
   863			break;
   864		default:
   865			ret = -EINVAL;
   866			break;
   867		}
   868	
   869	out:
   870		mutex_unlock(&dev->kvm->arch.config_lock);
   871		kvm_unlock_all_vcpus(dev->kvm);
   872		mutex_unlock(&dev->kvm->lock);
   873	
   874		if (!ret && uaccess && !is_write) {
   875			u64 __user *uaddr = (u64 __user *)(unsigned long)attr->addr;
   876			ret = put_user(val, uaddr);
   877		}
   878	
   879		return ret;
   880	}
   881	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From hpausten at protonmail.com  Mon Dec 22 12:47:44 2025
From: hpausten at protonmail.com (Harry Austen)
Date: Mon, 22 Dec 2025 20:47:44 +0000
Subject: [PATCH] wifi: mt76: fix buffer overflow bug
In-Reply-To: <20251222180437.1938-1-hpausten@protonmail.com>
References: <20251222180437.1938-1-hpausten@protonmail.com>
Message-ID: <DF51GPM5N848.3L90OHP3XRWTV@protonmail.com>

On Mon Dec 22, 2025 at 6:05 PM GMT, Harry Austen wrote:
> Prevents attempting to read an extra byte from the origin string.
...

Ah, my apologies. There appear to be a bunch of emails about this bug already.
And an existing patch [1], which has already been reviewed. Please ignore my
patch.

Apologies for the noise,
Harry

[1]: https://lore.kernel.org/all/20251205161202.48409-1-mikhail.v.gavrilov at gmail.com/



From pbonzini at redhat.com  Mon Dec 22 13:15:24 2025
From: pbonzini at redhat.com (Paolo Bonzini)
Date: Mon, 22 Dec 2025 22:15:24 +0100
Subject: possible deadlock due to irq_set_thread_affinity() calling into
 the scheduler (was Re: [PATCH v3 38/62] KVM: SVM: Take and hold ir_list_lock
 across IRTE updates in IOMMU)
In-Reply-To: <aUmdSb3d7Z5REMLk@google.com>
References: <20250611224604.313496-2-seanjc@google.com>
 <20250611224604.313496-40-seanjc@google.com>
 <njhjud3e6wbdftzr3ziyuh5bhyvc5ndt5qvmg7rlvh5isoop2l@f2uxctws2c7d>
 <42513cb3-3c2e-4aa8-b748-23b6656a5096@redhat.com>
 <aUmdSb3d7Z5REMLk@google.com>
Message-ID: <9218dafc-c6ad-4ef3-b869-2d6d4a308181@redhat.com>

On 12/22/25 20:34, Sean Christopherson wrote:
> On Mon, Dec 22, 2025, Paolo Bonzini wrote:
>> On 12/22/25 10:16, Ankit Soni wrote:
>>>     - Is this lockdep warning expected/benign in this code path, or does it
>>>       indicate a real potential deadlock between svm->ir_list_lock and
>>>       irq_desc_lock with AVIC + irq_bypass + VFIO?
>>
>> I'd treat it as a potential (if unlikely) deadlock:
>>
>> (a) irq_set_thread_affinity triggers the scheduler via wake_up_process,
>> while irq_desc->lock is taken
>>
>> (b) the scheduler calls into KVM with rq_lock taken, and KVM uses
>> ir_list_lock within __avic_vcpu_load/__avic_vcpu_put
>>
>> (c) KVM wants to block scheduling for a while and uses ir_list_lock for
>> that purpose, but then irq_set_vcpu_affinity takes irq_desc->lock.
>>
>> I don't think there's an alternative choice of lock for (c); and there's
>> no easy way to pull the irq_desc->lock out of the IRQ subsystem--in fact
>> the stickiness of the situation comes from rq->rq_lock and
>> irq_desc->lock being both internal and not leaf.
>>
>> Of the three, the most sketchy is (a);
> 
> Maybe the most unnecessary, but I think there's a pretty strong argument that
> (d) is the most sketchy:
> 
>    (d) KVM takes svm->ir_list_lock around the call to irq_set_vcpu_affinity()

That's (c). :)

I called irq_set_thread_affinity() sketchy, because it's a core kernel 
subsystem that takes a pretty common lock, and directly calls a function 
that takes another very common lock.  KVM's deadlock scenario seems like 
a relatively natural occurrence, though in this case it can be fixed 
outside kernel/irq as well.

>> notably, __setup_irq() calls wake_up_process outside desc->lock.  Therefore
>> I'd like so much to treat it as a kernel/irq/ bug; and the simplest (perhaps
>> too simple...) fix is to drop the wake_up_process().  The only cost is extra
>> latency on the next interrupt after an affinity change.
> 
> Alternatively, what if we rework the KVM<=>IOMMU exchange to decouple updating
> the IRTE from binding the metadata to the vCPU?  KVM already has the necessary
> exports to do "out-of-band" updates due to the AVIC architecture requiring IRTE
> updates on scheduling changes.

In fact this was actually my first idea, exactly because it makes
svm->ir_list_lock a leaf lock!

I threw it away because it makes amd_ir_set_vcpu_affinity() weird, 
passing back the ir_data but not really doing anything else.  Basically 
its role becomes little more than violate abstractions, which seemed 
wrong.  On the other hand, drivers/iommu is already very much tied to 
the KVM vendor modules (in particular avic.c already calls 
amd_iommu_{,de}activate_guest_mode), so who am I to judge what the IOMMU 
driver does.

Paolo

> It's a bit wonky (and not yet tested), but I like the idea of making
> svm->ir_list_lock a leaf lock so that we don't end up with a game of whack-a-mole,
> e.g. if something in the IRQ subsystem changes in the future.
> 
> ---
>   arch/x86/include/asm/irq_remapping.h |  3 --
>   arch/x86/kvm/svm/avic.c              | 78 ++++++++++++++++++----------
>   drivers/iommu/amd/iommu.c            | 24 +++------
>   3 files changed, 57 insertions(+), 48 deletions(-)
> 
> diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h
> index 4e55d1755846..1426ecd09943 100644
> --- a/arch/x86/include/asm/irq_remapping.h
> +++ b/arch/x86/include/asm/irq_remapping.h
> @@ -35,9 +35,6 @@ struct amd_iommu_pi_data {
>   	u64 vapic_addr;		/* Physical address of the vCPU's vAPIC. */
>   	u32 ga_tag;
>   	u32 vector;		/* Guest vector of the interrupt */
> -	int cpu;
> -	bool ga_log_intr;
> -	bool is_guest_mode;
>   	void *ir_data;
>   };
>   
> diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c
> index 6b77b2033208..0f4f353c7db6 100644
> --- a/arch/x86/kvm/svm/avic.c
> +++ b/arch/x86/kvm/svm/avic.c
> @@ -868,6 +868,51 @@ static void svm_ir_list_del(struct kvm_kernel_irqfd *irqfd)
>   	raw_spin_unlock_irqrestore(&to_svm(vcpu)->ir_list_lock, flags);
>   }
>   
> +static int avic_pi_add_irte(struct kvm_kernel_irqfd *irqfd, void *ir_data,
> +			    struct kvm_vcpu *vcpu)
> +{
> +	struct vcpu_svm *svm = to_svm(vcpu);
> +	int r;
> +
> +	/*
> +	 * Prevent the vCPU from being scheduled out or migrated until the IRTE
> +	 * is updated and its metadata has been added to the list of IRQs being
> +	 * posted to the vCPU, to ensure the IRTE isn't programmed with stale
> +	 * pCPU/IsRunning information.
> +	 */
> +	guard(raw_spinlock_irqsave)(&svm->ir_list_lock);
> +
> +	if (kvm_vcpu_apicv_active(vcpu)) {
> +		u64 entry = svm->avic_physical_id_entry;
> +		bool ga_log_intr;
> +		int cpu;
> +
> +		/*
> +		 * Update the target pCPU for IOMMU doorbells if the vCPU is
> +		 * running.  If the vCPU is NOT running, i.e. is blocking or
> +		 * scheduled out, KVM will update the pCPU info when the vCPU
> +		 * is awakened and/or scheduled in.  See also avic_vcpu_load().
> +		 */
> +		if (entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK) {
> +			cpu = entry & AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK;
> +			ga_log_intr = false;
> +		} else {
> +			cpu = -1;
> +			ga_log_intr = entry & AVIC_PHYSICAL_ID_ENTRY_GA_LOG_INTR;
> +		}
> +		r = amd_iommu_activate_guest_mode(ir_data, cpu, ga_log_intr);
> +	} else {
> +		r = amd_iommu_deactivate_guest_mode(ir_data);
> +	}
> +
> +	if (r)
> +		return r;
> +
> +	irqfd->irq_bypass_data = ir_data;
> +	list_add(&irqfd->vcpu_list, &svm->ir_list);
> +	return 0;
> +}
> +
>   int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
>   			unsigned int host_irq, uint32_t guest_irq,
>   			struct kvm_vcpu *vcpu, u32 vector)
> @@ -888,36 +933,11 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
>   		struct amd_iommu_pi_data pi_data = {
>   			.ga_tag = AVIC_GATAG(to_kvm_svm(kvm)->avic_vm_id,
>   					     vcpu->vcpu_idx),
> -			.is_guest_mode = kvm_vcpu_apicv_active(vcpu),
>   			.vapic_addr = avic_get_backing_page_address(to_svm(vcpu)),
>   			.vector = vector,
>   		};
> -		struct vcpu_svm *svm = to_svm(vcpu);
> -		u64 entry;
>   		int ret;
>   
> -		/*
> -		 * Prevent the vCPU from being scheduled out or migrated until
> -		 * the IRTE is updated and its metadata has been added to the
> -		 * list of IRQs being posted to the vCPU, to ensure the IRTE
> -		 * isn't programmed with stale pCPU/IsRunning information.
> -		 */
> -		guard(raw_spinlock_irqsave)(&svm->ir_list_lock);
> -
> -		/*
> -		 * Update the target pCPU for IOMMU doorbells if the vCPU is
> -		 * running.  If the vCPU is NOT running, i.e. is blocking or
> -		 * scheduled out, KVM will update the pCPU info when the vCPU
> -		 * is awakened and/or scheduled in.  See also avic_vcpu_load().
> -		 */
> -		entry = svm->avic_physical_id_entry;
> -		if (entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK) {
> -			pi_data.cpu = entry & AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK;
> -		} else {
> -			pi_data.cpu = -1;
> -			pi_data.ga_log_intr = entry & AVIC_PHYSICAL_ID_ENTRY_GA_LOG_INTR;
> -		}
> -
>   		ret = irq_set_vcpu_affinity(host_irq, &pi_data);
>   		if (ret)
>   			return ret;
> @@ -932,9 +952,11 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
>   			return -EIO;
>   		}
>   
> -		irqfd->irq_bypass_data = pi_data.ir_data;
> -		list_add(&irqfd->vcpu_list, &svm->ir_list);
> -		return 0;
> +		ret = avic_pi_add_irte(irqfd, pi_data.ir_data, vcpu);
> +		if (WARN_ON_ONCE(ret))
> +			irq_set_vcpu_affinity(host_irq, NULL);
> +
> +		return ret;
>   	}
>   	return irq_set_vcpu_affinity(host_irq, NULL);
>   }
> diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
> index 5d45795c367a..855c6309900c 100644
> --- a/drivers/iommu/amd/iommu.c
> +++ b/drivers/iommu/amd/iommu.c
> @@ -3970,7 +3970,6 @@ EXPORT_SYMBOL(amd_iommu_deactivate_guest_mode);
>   
>   static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *info)
>   {
> -	int ret;
>   	struct amd_iommu_pi_data *pi_data = info;
>   	struct amd_ir_data *ir_data = data->chip_data;
>   	struct irq_2_irte *irte_info = &ir_data->irq_2_irte;
> @@ -3993,25 +3992,16 @@ static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *info)
>   
>   	ir_data->cfg = irqd_cfg(data);
>   
> -	if (pi_data) {
> -		pi_data->ir_data = ir_data;
> +	if (!pi_data)
> +		return amd_iommu_deactivate_guest_mode(ir_data);
>   
> -		ir_data->ga_root_ptr = (pi_data->vapic_addr >> 12);
> -		ir_data->ga_vector = pi_data->vector;
> -		ir_data->ga_tag = pi_data->ga_tag;
> -		if (pi_data->is_guest_mode)
> -			ret = amd_iommu_activate_guest_mode(ir_data, pi_data->cpu,
> -							    pi_data->ga_log_intr);
> -		else
> -			ret = amd_iommu_deactivate_guest_mode(ir_data);
> -	} else {
> -		ret = amd_iommu_deactivate_guest_mode(ir_data);
> -	}
> -
> -	return ret;
> +	pi_data->ir_data = ir_data;
> +	ir_data->ga_root_ptr = (pi_data->vapic_addr >> 12);
> +	ir_data->ga_vector = pi_data->vector;
> +	ir_data->ga_tag = pi_data->ga_tag;
> +	return 0;
>   }
>   
> -
>   static void amd_ir_update_irte(struct irq_data *irqd, struct amd_iommu *iommu,
>   			       struct amd_ir_data *ir_data,
>   			       struct irq_2_irte *irte_info,
> 
> base-commit: 9448598b22c50c8a5bb77a9103e2d49f134c9578
> --
> 



From royluo at google.com  Mon Dec 22 13:31:25 2025
From: royluo at google.com (Roy Luo)
Date: Mon, 22 Dec 2025 21:31:25 +0000
Subject: [PATCH v9 0/2] Add Google Tensor SoC USB PHY support
Message-ID: <20251222-phyb4-v9-0-82c0b671b070@google.com>

This series introduces USB PHY support for the Google Tensor G5
SoC (codename: Laguna), a new generation of Google silicon first
launched with Pixel 10 devices.

The Tensor G5 represents a significant architectural overhaul compared
to previous Tensor generations (e.g., gs101), which were based on Samsung
Exynos IP. Although the G5 still utilizes Synopsys IP for the USB
components, the custom top-level integration introduces a completely new
design for clock, reset scheme, register interfaces and programming
sequence, necessitating new drivers and device tree bindings.

The USB subsystem on Tensor G5 integrates a Synopsys DWC3 USB 3.1
DRD-Single Port controller with hibernation support, and a custom PHY
block comprising Synopsys eUSB2 and USB 3.2/DP combo PHYs. The controller
support is sent as a separate patch series.

Co-developed-by: Joy Chakraborty <joychakr at google.com>
Signed-off-by: Joy Chakraborty <joychakr at google.com>
Co-developed-by: Naveen Kumar <mnkumar at google.com>
Signed-off-by: Naveen Kumar <mnkumar at google.com>
Signed-off-by: Roy Luo <royluo at google.com>
---
Changes in v9:
- Per Greg's feedback, remove Kconfig dependency on ARCH_GOOGLE || COMPILE_TEST.
  Remove ARCH_GOOGLE as it's not yet in the kernel, and COMPILE_TEST is no longer needed without it.
Link to v8: https://lore.kernel.org/r/20251205-phyb4-v8-0-c59ea80a4458 at google.com

Changes in v8:
- Update the Kconfig dependency to depends on ARCH_GOOGLE || COMPILE_TEST
  Note that ARCH_GOOGLE does not exist yet but will eventually
  be there when the following patch lands
  https://lore.kernel.org/r/20251111112158.3.I35b9e835ac49ab408e5ca3e0983930a1f1395814 at changeid/
- Mention SoC codename Laguna in Kconfig description.
- Sort the header alphabetically and sort the variables using the
  reverse christmas tree ordering.
- Add driver and binding files to the Tensor SoC MAINTAINER entry.
- Add detailed comment for phy_mutex
Link to v7: https://lore.kernel.org/r/20251121-phyb4-v7-0-df644fa62180 at google.com

Changes in v7:
- Change the device tree binding example node name to usb-phy to follow
 the hyphen-separated naming convention and remove label.
Link to v6: https://lore.kernel.org/r/20251120-phyb4-v6-0-b6694e1f0caf at google.com

Changes in v6:
- Use "lga" as SoC name instead of "gs5" to align with Tensor G5 device
  tree https://lore.kernel.org/lkml/20251111192422.4180216-1-dianders at chromium.org 
- Add "usb2_core" to the reg property to define the MMIO space for
  the eUSB 2.0 PHY IP.
- Rename "usb3_top" reg as "usbdp_top" and update the description to
  reflect its nature as a top-level wrapper and align with internal
  documentation.
- Use syscon to access the "usb2_cfg" MMIO space.
- Remove minItems for clocks and resets, making all listed clocks and
  resets (including USB3) mandatory.
Link to v5: https://lore.kernel.org/linux-phy/20251029214032.3175261-1-royluo at google.com

Changes in v5:
- Add usb3 registers/clks/resets to binding as suggested by Krzysztof
  Kozlowski. This ensures completeness of the binding, though the
  driver has not yet ultilized the resources. The usb3 clks and resets
  are optional if usb2-only operation is desired, this is denoted by
  minItems and descriptions in the clocks and resets properties.
  Additionally, rename existing binding entries for consistency and to
  better differntiate between usb2 and usb3.
- Move the description of the phy select to phy-cells in binding as
  suggested by Krzysztof Kozlowski.
Link to v4: https://lore.kernel.org/linux-phy/20251017235159.2417576-1-royluo at google.com

Changes in v4:
- Separate controller and phy changes into two distinct patch series.
- Remove usb2only mode configuration and the corresponding usb_top_cfg
  reg (moved to controller)
- Add more descriptions to dp_top reg to indicate it's not DP specific.
- Add u2phy_apb clk/reset
Link to v3: https://lore.kernel.org/linux-usb/20251010201607.1190967-1-royluo at google.com

Changes in v3:
- Align binding file name with the compatible string
- Simplify the compatible property in binding to a single const value.
- Add descriptive comments and use item list in binding.
- Rename binding entries for clarity and brevity.
Link to v2: https://lore.kernel.org/linux-usb/20251008060000.3136021-1-royluo at google.com

Changes in v2:
- Reorder patches to present bindings first.
- Update dt binding compatible strings to be SoC-specific (google,gs5-*).
- Better describe the hardware in dt binding commit messages and
  descriptions.
- Adjust PHY driver commit subjects to use correct prefixes ("phy:").
- Move PHY driver from a subdirectory to drivers/phy/.
Link to v1: https://lore.kernel.org/linux-usb/20251006232125.1833979-1-royluo at google.com/

---
Roy Luo (2):
      dt-bindings: phy: google: Add Google Tensor G5 USB PHY
      phy: Add Google Tensor SoC USB PHY driver

 .../bindings/phy/google,lga-usb-phy.yaml           | 133 ++++++++++
 MAINTAINERS                                        |   2 +
 drivers/phy/Kconfig                                |  10 +
 drivers/phy/Makefile                               |   1 +
 drivers/phy/phy-google-usb.c                       | 295 +++++++++++++++++++++
 5 files changed, 441 insertions(+)
---
base-commit: ea1013c1539270e372fc99854bc6e4d94eaeff66
change-id: 20251119-phyb4-2e03a7c449c4

Best regards,
-- 
Roy Luo <royluo at google.com>



From royluo at google.com  Mon Dec 22 13:31:26 2025
From: royluo at google.com (Roy Luo)
Date: Mon, 22 Dec 2025 21:31:26 +0000
Subject: [PATCH v9 1/2] dt-bindings: phy: google: Add Google Tensor G5 USB PHY
In-Reply-To: <20251222-phyb4-v9-0-82c0b671b070@google.com>
References: <20251222-phyb4-v9-0-82c0b671b070@google.com>
Message-ID: <20251222-phyb4-v9-1-82c0b671b070@google.com>

Document the device tree bindings for the USB PHY interfaces integrated
with the DWC3 controller on Google Tensor SoCs, starting with G5
generation (Laguna). The USB PHY on Tensor G5 includes two integrated
Synopsys PHY IPs: the eUSB 2.0 PHY IP and the USB 3.2/DisplayPort combo
PHY IP.

Due to a complete architectural overhaul in the Google Tensor G5, the
existing Samsung/Exynos USB PHY binding for older generations of Google
silicons such as gs101 are no longer compatible, necessitating this new
device tree binding.

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
Signed-off-by: Roy Luo <royluo at google.com>
---
 .../bindings/phy/google,lga-usb-phy.yaml           | 133 +++++++++++++++++++++
 MAINTAINERS                                        |   1 +
 2 files changed, 134 insertions(+)

diff --git a/Documentation/devicetree/bindings/phy/google,lga-usb-phy.yaml b/Documentation/devicetree/bindings/phy/google,lga-usb-phy.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..427e2e3425f645f40c0813e29d6efe4f62b20609
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/google,lga-usb-phy.yaml
@@ -0,0 +1,133 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2025, Google LLC
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/google,lga-usb-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Google Tensor Series G5 (Laguna) USB PHY
+
+maintainers:
+  - Roy Luo <royluo at google.com>
+
+description:
+  Describes the USB PHY interfaces integrated with the DWC3 USB controller on
+  Google Tensor SoCs, starting with the G5 generation (laguna).
+  Two specific PHY IPs from Synopsys are integrated, including eUSB 2.0 PHY IP
+  and USB3.2/DisplayPort combo PHY IP.
+
+properties:
+  compatible:
+    const: google,lga-usb-phy
+
+  reg:
+    items:
+      - description: USB3.2/DisplayPort combo PHY core registers.
+      - description: USB3.2/DisplayPort combo PHY Type-C Assist registers.
+      - description: eUSB 2.0 PHY core registers.
+      - description: Top-level wrapper registers for the integrated PHYs.
+
+  reg-names:
+    items:
+      - const: usb3_core
+      - const: usb3_tca
+      - const: usb2_core
+      - const: usbdp_top
+
+  "#phy-cells":
+    description: |
+      The phandle's argument in the PHY specifier selects one of the three
+      following PHY interfaces.
+      - 0 for USB high-speed.
+      - 1 for USB super-speed.
+      - 2 for DisplayPort.
+    const: 1
+
+  clocks:
+    items:
+      - description: USB2 PHY clock.
+      - description: USB2 PHY APB clock.
+      - description: USB3.2/DisplayPort combo PHY clock.
+      - description: USB3.2/DisplayPort combo PHY firmware clock.
+
+  clock-names:
+    items:
+      - const: usb2
+      - const: usb2_apb
+      - const: usb3
+      - const: usb3_fw
+
+  resets:
+    items:
+      - description: USB2 PHY reset.
+      - description: USB2 PHY APB reset.
+      - description: USB3.2/DisplayPort combo PHY reset.
+
+  reset-names:
+    items:
+      - const: usb2
+      - const: usb2_apb
+      - const: usb3
+
+  power-domains:
+    maxItems: 1
+
+  orientation-switch:
+    type: boolean
+    description:
+      Indicates the PHY as a handler of USB Type-C orientation changes
+
+  google,usb-cfg-csr:
+    description:
+      A phandle to a syscon node used to access the USB configuration
+      registers. These registers are the top-level wrapper of the USB
+      subsystem and provide control and status for the integrated USB
+      controller and USB PHY.
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    items:
+      - items:
+          - description: phandle to the syscon node.
+          - description: USB2 PHY configuration register offset.
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - "#phy-cells"
+  - clocks
+  - clock-names
+  - resets
+  - reset-names
+  - power-domains
+  - orientation-switch
+  - google,usb-cfg-csr
+
+additionalProperties: false
+
+examples:
+  - |
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        usb-phy at c410000 {
+            compatible = "google,lga-usb-phy";
+            reg = <0 0x0c410000 0 0x20000>,
+                  <0 0x0c430000 0 0x1000>,
+                  <0 0x0c440000 0 0x10000>,
+                  <0 0x0c637000 0 0xa0>;
+            reg-names = "usb3_core", "usb3_tca", "usb2_core", "usbdp_top";
+            #phy-cells = <1>;
+            clocks = <&hsion_usb2_phy_clk>, <&hsion_u2phy_apb_clk>,
+                     <&hsion_usb3_phy_clk>, <&hsion_usb3_phy_fw_clk>;
+            clock-names = "usb2", "usb2_apb", "usb3", "usb3_fw";
+            resets = <&hsion_resets_usb2_phy>,
+                     <&hsion_resets_u2phy_apb>,
+                     <&hsion_resets_usb3_phy>;
+            reset-names = "usb2", "usb2_apb", "usb3";
+            power-domains = <&hsio_n_usb_pd>;
+            orientation-switch;
+            google,usb-cfg-csr = <&usb_cfg_csr 0x14>;
+        };
+    };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 5b11839cba9de1e9e43f63787578edd8c429ca39..8a2e94be2f5c5e6e7315bb7bec385798dbd52493 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10721,6 +10721,7 @@ S:	Maintained
 P:	Documentation/process/maintainer-soc-clean-dts.rst
 C:	irc://irc.oftc.net/pixel6-kernel-dev
 F:	Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
+F:	Documentation/devicetree/bindings/phy/google,lga-usb-phy.yaml
 F:	Documentation/devicetree/bindings/soc/google/google,gs101-pmu-intr-gen.yaml
 F:	arch/arm64/boot/dts/exynos/google/
 F:	drivers/clk/samsung/clk-gs101.c

-- 
2.52.0.358.g0dd7633a29-goog



From royluo at google.com  Mon Dec 22 13:31:27 2025
From: royluo at google.com (Roy Luo)
Date: Mon, 22 Dec 2025 21:31:27 +0000
Subject: [PATCH v9 2/2] phy: Add Google Tensor SoC USB PHY driver
In-Reply-To: <20251222-phyb4-v9-0-82c0b671b070@google.com>
References: <20251222-phyb4-v9-0-82c0b671b070@google.com>
Message-ID: <20251222-phyb4-v9-2-82c0b671b070@google.com>

Support the USB PHY found on Google Tensor G5 (Laguna). This
particular USB PHY supports both high-speed and super-speed
operations, and is integrated with the SNPS DWC3 controller that's
also on the SoC. This initial patch specifically adds functionality
for high-speed.

Co-developed-by: Joy Chakraborty <joychakr at google.com>
Signed-off-by: Joy Chakraborty <joychakr at google.com>
Co-developed-by: Naveen Kumar <mnkumar at google.com>
Signed-off-by: Naveen Kumar <mnkumar at google.com>
Signed-off-by: Roy Luo <royluo at google.com>
---
 MAINTAINERS                  |   1 +
 drivers/phy/Kconfig          |  10 ++
 drivers/phy/Makefile         |   1 +
 drivers/phy/phy-google-usb.c | 295 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 307 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 8a2e94be2f5c5e6e7315bb7bec385798dbd52493..afd0d7484ffe5fa652798c9b3c86ae6d83302382 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10725,6 +10725,7 @@ F:	Documentation/devicetree/bindings/phy/google,lga-usb-phy.yaml
 F:	Documentation/devicetree/bindings/soc/google/google,gs101-pmu-intr-gen.yaml
 F:	arch/arm64/boot/dts/exynos/google/
 F:	drivers/clk/samsung/clk-gs101.c
+F:	drivers/phy/phy-google-usb.c
 F:	drivers/soc/samsung/gs101-pmu.c
 F:	drivers/phy/samsung/phy-gs101-ufs.c
 F:	include/dt-bindings/clock/google,gs101*
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 678dd0452f0aa0597773433f04d2a9ba77474d2a..5a642e04caeeea9d40ac583767622cff2ef5e80c 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -101,6 +101,16 @@ config PHY_NXP_PTN3222
 	  schemes. It supports all three USB 2.0 data rates: Low Speed, Full
 	  Speed and High Speed.
 
+config PHY_GOOGLE_USB
+	tristate "Google Tensor SoC USB PHY driver"
+	select GENERIC_PHY
+	help
+	  Enable support for the USB PHY on Google Tensor SoCs, starting with
+	  the G5 generation (Laguna). This driver provides the PHY interfaces
+	  to interact with the SNPS eUSB2 and USB 3.2/DisplayPort Combo PHY,
+	  both of which are integrated with the DWC3 USB DRD controller.
+	  This driver currently supports USB high-speed.
+
 source "drivers/phy/allwinner/Kconfig"
 source "drivers/phy/amlogic/Kconfig"
 source "drivers/phy/broadcom/Kconfig"
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index bfb27fb5a494283d7fd05dd670ebd1b12df8b1a1..aeaaaf988554a24bb572d8b34b54638a6a3aed73 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_PHY_SNPS_EUSB2)		+= phy-snps-eusb2.o
 obj-$(CONFIG_USB_LGM_PHY)		+= phy-lgm-usb.o
 obj-$(CONFIG_PHY_AIROHA_PCIE)		+= phy-airoha-pcie.o
 obj-$(CONFIG_PHY_NXP_PTN3222)		+= phy-nxp-ptn3222.o
+obj-$(CONFIG_PHY_GOOGLE_USB)		+= phy-google-usb.o
 obj-y					+= allwinner/	\
 					   amlogic/	\
 					   broadcom/	\
diff --git a/drivers/phy/phy-google-usb.c b/drivers/phy/phy-google-usb.c
new file mode 100644
index 0000000000000000000000000000000000000000..97e345fdab9b3679e7a76f6957ae3814ef3420e8
--- /dev/null
+++ b/drivers/phy/phy-google-usb.c
@@ -0,0 +1,295 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * phy-google-usb.c - Google USB PHY driver
+ *
+ * Copyright (C) 2025, Google LLC
+ */
+
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/usb/typec_mux.h>
+
+#define USBCS_USB2PHY_CFG19_OFFSET 0x0
+#define USBCS_USB2PHY_CFG19_PHY_CFG_PLL_FB_DIV GENMASK(19, 8)
+
+#define USBCS_USB2PHY_CFG21_OFFSET 0x8
+#define USBCS_USB2PHY_CFG21_PHY_ENABLE BIT(12)
+#define USBCS_USB2PHY_CFG21_REF_FREQ_SEL GENMASK(15, 13)
+#define USBCS_USB2PHY_CFG21_PHY_TX_DIG_BYPASS_SEL BIT(19)
+
+#define USBCS_PHY_CFG1_OFFSET 0x28
+#define USBCS_PHY_CFG1_SYS_VBUSVALID BIT(17)
+
+enum google_usb_phy_id {
+	GOOGLE_USB2_PHY,
+	GOOGLE_USB_PHY_NUM,
+};
+
+struct google_usb_phy_instance {
+	int index;
+	struct phy *phy;
+	int num_clks;
+	struct clk_bulk_data *clks;
+	int num_rsts;
+	struct reset_control_bulk_data *rsts;
+};
+
+struct google_usb_phy {
+	struct device *dev;
+	struct regmap *usb_cfg_regmap;
+	unsigned int usb2_cfg_offset;
+	void __iomem *usbdp_top_base;
+	struct google_usb_phy_instance insts[GOOGLE_USB_PHY_NUM];
+	/*
+	 * Protect phy registers from concurrent access, specifically via
+	 * google_usb_set_orientation callback.
+	 */
+	struct mutex phy_mutex;
+	struct typec_switch_dev *sw;
+	enum typec_orientation orientation;
+};
+
+static inline struct google_usb_phy *to_google_usb_phy(struct google_usb_phy_instance *inst)
+{
+	return container_of(inst, struct google_usb_phy, insts[inst->index]);
+}
+
+static void set_vbus_valid(struct google_usb_phy *gphy)
+{
+	u32 reg;
+
+	if (gphy->orientation == TYPEC_ORIENTATION_NONE) {
+		reg = readl(gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+		reg &= ~USBCS_PHY_CFG1_SYS_VBUSVALID;
+		writel(reg, gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+	} else {
+		reg = readl(gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+		reg |= USBCS_PHY_CFG1_SYS_VBUSVALID;
+		writel(reg, gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+	}
+}
+
+static int google_usb_set_orientation(struct typec_switch_dev *sw,
+				      enum typec_orientation orientation)
+{
+	struct google_usb_phy *gphy = typec_switch_get_drvdata(sw);
+
+	dev_dbg(gphy->dev, "set orientation %d\n", orientation);
+
+	gphy->orientation = orientation;
+
+	if (pm_runtime_suspended(gphy->dev))
+		return 0;
+
+	guard(mutex)(&gphy->phy_mutex);
+
+	set_vbus_valid(gphy);
+
+	return 0;
+}
+
+static int google_usb2_phy_init(struct phy *_phy)
+{
+	struct google_usb_phy_instance *inst = phy_get_drvdata(_phy);
+	struct google_usb_phy *gphy = to_google_usb_phy(inst);
+	u32 reg;
+	int ret = 0;
+
+	dev_dbg(gphy->dev, "initializing usb2 phy\n");
+
+	guard(mutex)(&gphy->phy_mutex);
+
+	regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, &reg);
+	reg &= ~USBCS_USB2PHY_CFG21_PHY_TX_DIG_BYPASS_SEL;
+	reg &= ~USBCS_USB2PHY_CFG21_REF_FREQ_SEL;
+	reg |= FIELD_PREP(USBCS_USB2PHY_CFG21_REF_FREQ_SEL, 0);
+	regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, reg);
+
+	regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG19_OFFSET, &reg);
+	reg &= ~USBCS_USB2PHY_CFG19_PHY_CFG_PLL_FB_DIV;
+	reg |= FIELD_PREP(USBCS_USB2PHY_CFG19_PHY_CFG_PLL_FB_DIV, 368);
+	regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG19_OFFSET, reg);
+
+	set_vbus_valid(gphy);
+
+	ret = clk_bulk_prepare_enable(inst->num_clks, inst->clks);
+	if (ret)
+		return ret;
+
+	ret = reset_control_bulk_deassert(inst->num_rsts, inst->rsts);
+	if (ret) {
+		clk_bulk_disable_unprepare(inst->num_clks, inst->clks);
+		return ret;
+	}
+
+	regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, &reg);
+	reg |= USBCS_USB2PHY_CFG21_PHY_ENABLE;
+	regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, reg);
+
+	return ret;
+}
+
+static int google_usb2_phy_exit(struct phy *_phy)
+{
+	struct google_usb_phy_instance *inst = phy_get_drvdata(_phy);
+	struct google_usb_phy *gphy = to_google_usb_phy(inst);
+	u32 reg;
+
+	dev_dbg(gphy->dev, "exiting usb2 phy\n");
+
+	guard(mutex)(&gphy->phy_mutex);
+
+	regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, &reg);
+	reg &= ~USBCS_USB2PHY_CFG21_PHY_ENABLE;
+	regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, reg);
+
+	reset_control_bulk_assert(inst->num_rsts, inst->rsts);
+	clk_bulk_disable_unprepare(inst->num_clks, inst->clks);
+
+	return 0;
+}
+
+static const struct phy_ops google_usb2_phy_ops = {
+	.init		= google_usb2_phy_init,
+	.exit		= google_usb2_phy_exit,
+};
+
+static struct phy *google_usb_phy_xlate(struct device *dev,
+					const struct of_phandle_args *args)
+{
+	struct google_usb_phy *gphy = dev_get_drvdata(dev);
+
+	if (args->args[0] >= GOOGLE_USB_PHY_NUM) {
+		dev_err(dev, "invalid PHY index requested from DT\n");
+		return ERR_PTR(-ENODEV);
+	}
+	return gphy->insts[args->args[0]].phy;
+}
+
+static int google_usb_phy_probe(struct platform_device *pdev)
+{
+	struct typec_switch_desc sw_desc = { };
+	struct google_usb_phy_instance *inst;
+	struct phy_provider *phy_provider;
+	struct device *dev = &pdev->dev;
+	struct google_usb_phy *gphy;
+	struct phy *phy;
+	u32 args[1];
+	int ret;
+
+	gphy = devm_kzalloc(dev, sizeof(*gphy), GFP_KERNEL);
+	if (!gphy)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, gphy);
+	gphy->dev = dev;
+
+	ret = devm_mutex_init(dev, &gphy->phy_mutex);
+	if (ret)
+		return ret;
+
+	gphy->usb_cfg_regmap =
+		syscon_regmap_lookup_by_phandle_args(dev->of_node,
+						     "google,usb-cfg-csr",
+						     ARRAY_SIZE(args), args);
+	if (IS_ERR(gphy->usb_cfg_regmap)) {
+		return dev_err_probe(dev, PTR_ERR(gphy->usb_cfg_regmap),
+				     "invalid usb cfg csr\n");
+	}
+
+	gphy->usb2_cfg_offset = args[0];
+
+	gphy->usbdp_top_base = devm_platform_ioremap_resource_byname(pdev,
+								     "usbdp_top");
+	if (IS_ERR(gphy->usbdp_top_base))
+		return dev_err_probe(dev, PTR_ERR(gphy->usbdp_top_base),
+				    "invalid usbdp top\n");
+
+	inst = &gphy->insts[GOOGLE_USB2_PHY];
+	inst->index = GOOGLE_USB2_PHY;
+	phy = devm_phy_create(dev, NULL, &google_usb2_phy_ops);
+	if (IS_ERR(phy))
+		return dev_err_probe(dev, PTR_ERR(phy),
+				     "failed to create usb2 phy instance\n");
+	inst->phy = phy;
+	phy_set_drvdata(phy, inst);
+
+	inst->num_clks = 2;
+	inst->clks = devm_kcalloc(dev, inst->num_clks, sizeof(*inst->clks), GFP_KERNEL);
+	if (!inst->clks)
+		return -ENOMEM;
+	inst->clks[0].id = "usb2";
+	inst->clks[1].id = "usb2_apb";
+	ret = devm_clk_bulk_get(dev, inst->num_clks, inst->clks);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to get u2 phy clks\n");
+
+	inst->num_rsts = 2;
+	inst->rsts = devm_kcalloc(dev, inst->num_rsts, sizeof(*inst->rsts), GFP_KERNEL);
+	if (!inst->rsts)
+		return -ENOMEM;
+	inst->rsts[0].id = "usb2";
+	inst->rsts[1].id = "usb2_apb";
+	ret = devm_reset_control_bulk_get_exclusive(dev, inst->num_rsts, inst->rsts);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to get u2 phy resets\n");
+
+	phy_provider = devm_of_phy_provider_register(dev, google_usb_phy_xlate);
+	if (IS_ERR(phy_provider))
+		return dev_err_probe(dev, PTR_ERR(phy_provider),
+				     "failed to register phy provider\n");
+
+	pm_runtime_enable(dev);
+
+	sw_desc.fwnode = dev_fwnode(dev);
+	sw_desc.drvdata = gphy;
+	sw_desc.name = fwnode_get_name(dev_fwnode(dev));
+	sw_desc.set = google_usb_set_orientation;
+
+	gphy->sw = typec_switch_register(dev, &sw_desc);
+	if (IS_ERR(gphy->sw))
+		return dev_err_probe(dev, PTR_ERR(gphy->sw),
+				     "failed to register typec switch\n");
+
+	return 0;
+}
+
+static void google_usb_phy_remove(struct platform_device *pdev)
+{
+	struct google_usb_phy *gphy = dev_get_drvdata(&pdev->dev);
+
+	typec_switch_unregister(gphy->sw);
+	pm_runtime_disable(&pdev->dev);
+}
+
+static const struct of_device_id google_usb_phy_of_match[] = {
+	{
+		.compatible = "google,lga-usb-phy",
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, google_usb_phy_of_match);
+
+static struct platform_driver google_usb_phy = {
+	.probe	= google_usb_phy_probe,
+	.remove = google_usb_phy_remove,
+	.driver = {
+		.name		= "google-usb-phy",
+		.of_match_table	= google_usb_phy_of_match,
+	}
+};
+
+module_platform_driver(google_usb_phy);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Google USB phy driver");

-- 
2.52.0.358.g0dd7633a29-goog



From arnd at arndb.de  Mon Dec 22 14:04:09 2025
From: arnd at arndb.de (Arnd Bergmann)
Date: Mon, 22 Dec 2025 23:04:09 +0100
Subject: [PATCH] ARM: dts: intel: Drop pxa2xx
In-Reply-To: <700e5050-aebe-4ca4-b02d-8ffacccf7045@zonque.org>
References: <20251212203226.458694-4-robh@kernel.org> <m2345fmkg7.fsf@free.fr>
 <35405ed3-1319-4d3a-84a5-ad67f4c823ad@app.fastmail.com>
 <700e5050-aebe-4ca4-b02d-8ffacccf7045@zonque.org>
Message-ID: <de82700c-2e63-4598-a6ba-be27903e807c@app.fastmail.com>

On Thu, Dec 18, 2025, at 09:21, Daniel wrote:
> On 12/17/25 17:04, Arnd Bergmann wrote:
>> On Fri, Dec 12, 2025, at 22:58, Robert Jarzmik wrote:
>>> "Rob Herring (Arm)" <robh at kernel.org> writes:
>>>
>>>> These .dtsi files are not included anywhere in the tree and 
>>>> can't be tested. They have not been touched since 2018 other than 
>>>> clean-ups.
>>>>
>>> And yet, there are used by people using pxa2xx board with an DT 
>>> support (like the mioa701 for which a board file was never merged).
>>>
>>> If you remove pxa25x.dtsi and pxa27x.dtsi, you might as well 
>>> remove all support for this architecture from the kernel, as
>>> these are the building blocks needed to make it work.
>>>
>>> That might be what should be done, I'll let Arnd and Daniel 
>>> comment on the future of PXA in the kernel.
>> 
>> I agree with Rob that at the very minimum, any dtsi files in the
>> kernel should be build-tested along with the rest, so either
>> we add some dts files using them soon, or we can remove pxa2xx
>> (and maybe pxa3xx) completely.
>
> PXA3xx is in use by the Raumfeld boards, and I would really like to keep
> them around.

Ok, no problem. If there are upstream users, we can always keep that.

> For PXA2xx I'm torn. I don't have the capacity and hardware to work on
> those, but I don't know how many users are out there with out-of-tree
> dts files.

It's clear that nobody has done anything upstream for a while on pxa2xx,
you both initially put a lot of work into it but it has been incomplete
for almost a decade at this point.

I wouldn't even expect you to do any runtime testing, but if we want
to keep it in mainline, it seems the minimum state we should get to
is to complete the upstreaming to the degree that one machine can
plausibly boot with a mainline that gets built by default, and not
introduce new warnings in the process.

At the moment, an empty dts file that includes pxa25x.dtsi doesn't
even build because there is no pwri2c node:

arch/arm/boot/dts/intel/pxa/pxa2xx.dtsi:36.10-43.4: ERROR (path_references): /aliases: Reference to non-existent node or label "pwri2c"

The pxa27x.dtsi file does build but produces a couple of
'dtbs_check' W=1 and W=2 warnings:

arch/arm/boot/dts/intel/pxa/pxa27x.dtsi:134.30-138.5: Warning (node_name_chars_strict): /clocks/pxa2xx_clks at 41300004: Character '_' not recommended in node name
arch/arm/boot/dts/intel/pxa/pxa27x.dtsi:149.31-187.4: Warning (node_name_chars_strict): /opp_table0: Character '_' not recommended in node name
arch/arm/boot/dts/intel/pxa/pxa27x.dtsi:134.30-138.5: Warning (unit_address_vs_reg): /clocks/pxa2xx_clks at 41300004: node has a unit name, but no reg or ranges property
arch/arm/boot/dts/intel/pxa/pxa2xx.dtsi:154.33-160.5: Warning (simple_bus_reg): /pxabus/lcd-controller at 40500000: simple-bus unit address format error, expected "44000000"
arch/arm/boot/dts/intel/pxa/pxa27x.dtsi:29.29-33.5: Warning (simple_bus_reg): /pxabus/pinctrl at 40e00000: simple-bus unit address format error, expected "40e00054"
arch/arm/boot/dts/intel/pxa/pxa2xx.dtsi:67.23-94.5: Warning (unique_unit_address): /pxabus/gpio at 40e00000: duplicate unit-address (also used in node /pxabus/pinctrl at 40e00000)
pxa270-minimal.dtb: /: failed to match any schema with compatible: ['marvell,pxa27x']
pxa270-minimal.dtb: cpus: '#address-cells' is a required property 
        from schema $id: http://devicetree.org/schemas/cpus.yaml#
pxa270-minimal.dtb: cpus: '#size-cells' is a required property
        from schema $id: http://devicetree.org/schemas/cpus.yaml#
pxa270-minimal.dtb: /cpus/cpu: failed to match any schema with compatible: ['marvell,xscale']
pxa270-minimal.dtb: pxabus (simple-bus): $nodename:0: 'pxabus' does not match '^([a-z][a-z0-9\\-]+-bus|bus|localbus|soc|axi|ahb|apb)(@.+)?$'
        from schema $id: http://devicetree.org/schemas/simple-bus.yaml#
pxa270-minimal.dtb: /pxabus/interrupt-controller at 40d00000: failed to match any schema with compatible: ['marvell,pxa-intc']
pxa270-minimal.dtb: interrupt-controller at 40d00000 (marvell,pxa-intc): interrupt-parent: True is not of type 'array'
        from schema $id: http://devicetree.org/schemas/interrupts.yaml#
pxa270-minimal.dtb: /pxabus/mmc at 41100000: failed to match any schema with compatible: ['marvell,pxa-mmc']
pxa270-minimal.dtb: rtc at 40900000 (marvell,pxa-rtc): Unevaluated properties are not allowed ('clocks' was unexpected)
        from schema $id: http://devicetree.org/schemas/rtc/marvell,pxa-rtc.yaml#
pxa270-minimal.dtb: /pxabus/lcd-controller at 44000000: failed to match any schema with compatible: ['marvell,pxa2xx-lcdc']
pxa270-minimal.dtb: /pxabus/pinctrl at 40e00000: failed to match any schema with compatible: ['marvell,pxa27x-pinctrl']
pxa270-minimal.dtb: /pxabus/usb at 4c000000: failed to match any schema with compatible: ['marvell,pxa-ohci']
pxa270-minimal.dtb: pwm at 40b00000 (marvell,pxa270-pwm): compatible: 'oneOf' conditional failed, one must be fixed:
        ['marvell,pxa270-pwm', 'marvell,pxa250-pwm'] is too long
        'spacemit,k1-pwm' was expected
        'marvell,pxa910-pwm' was expected
        from schema $id: http://devicetree.org/schemas/pwm/marvell,pxa-pwm.yaml#
pxa270-minimal.dtb: pwm at 40b00010 (marvell,pxa270-pwm): compatible: 'oneOf' conditional failed, one must be fixed:
        ['marvell,pxa270-pwm', 'marvell,pxa250-pwm'] is too long
        'spacemit,k1-pwm' was expected
        'marvell,pxa910-pwm' was expected
        from schema $id: http://devicetree.org/schemas/pwm/marvell,pxa-pwm.yaml#
pxa270-minimal.dtb: pwm at 40c00000 (marvell,pxa270-pwm): compatible: 'oneOf' conditional failed, one must be fixed:
        ['marvell,pxa270-pwm', 'marvell,pxa250-pwm'] is too long
        'spacemit,k1-pwm' was expected
        'marvell,pxa910-pwm' was expected
        from schema $id: http://devicetree.org/schemas/pwm/marvell,pxa-pwm.yaml#
pxa270-minimal.dtb: pwm at 40c00010 (marvell,pxa270-pwm): compatible: 'oneOf' conditional failed, one must be fixed:
        ['marvell,pxa270-pwm', 'marvell,pxa250-pwm'] is too long
        'spacemit,k1-pwm' was expected
        'marvell,pxa910-pwm' was expected 
        from schema $id: http://devicetree.org/schemas/pwm/marvell,pxa-pwm.yaml#
pxa270-minimal.dtb: /pxabus/udc at 40600000: failed to match any schema with compatible: ['marvell,pxa270-udc']
pxa270-minimal.dtb: /pxabus/keypad at 41500000: failed to match any schema with compatible: ['marvell,pxa27x-keypad']
pxa270-minimal.dtb: /pxabus/imaging at 50000000: failed to match any schema with compatible: ['marvell,pxa270-qci']
pxa270-minimal.dtb: imaging at 50000000 (marvell,pxa270-qci): '#clock-cells' is a dependency of 'clock-output-names'
        from schema $id: http://devicetree.org/schemas/clock/clock.yaml#
pxa270-minimal.dtb: /clocks/pxa2xx_clks at 41300004: failed to match any schema with compatible: ['marvell,pxa270-clocks']
pxa270-minimal.dtb: /timer at 40a00000: failed to match any schema with compatible: ['marvell,pxa-timer'] 
pxa270-minimal.dtb: opp_table0 (operating-points-v2): $nodename:0: 'opp_table0' does not match '^opp-table(-[a-z0-9]+)?$'
        from schema $id: http://devicetree.org/schemas/opp/opp-v2.yaml#
pxa270-minimal.dtb: opp_table0 (operating-points-v2): Unevaluated properties are not allowed ('opp-104000000', 'opp-156000000', 'opp-208000000', 'opp-312000000', 'opp-416000000', 'opp-520000000', 'opp-624000000' were unexpected)
        from schema $id: http://devicetree.org/schemas/opp/opp-v2.yaml#

Most of these have an obvious fix and just need someone to care
a little bit. The Raumfeld files have a similar set of warnings:

arch/arm/boot/dts/intel/pxa/pxa300-raumfeld-common.dtsi:17.9-20.4: Warning (unit_address_vs_reg): /memory: node has a reg or ranges property, but no unit name
arch/arm/boot/dts/intel/pxa/pxa300-raumfeld-controller.dts:242.29-248.4: Warning (node_name_chars_strict): /pxabus/pinctrl at 40e10000/charger_pins: Character '_' not recommended in node name
arch/arm/boot/dts/intel/pxa/pxa300-raumfeld-controller.dts:250.37-256.4: Warning (node_name_chars_strict): /pxabus/pinctrl at 40e10000/dock_detect_pins: Character '_' not recommended in node name
arch/arm/boot/dts/intel/pxa/pxa300-raumfeld-speaker-one.dts:122.3-25: Warning (property_name_chars_strict): /pxabus/i2c at 40301680/codec at 1a:st,needs_esd_watchdog: Character '_' not recommended in property name
pxa300-raumfeld-speaker-l.dtb: /: failed to match any schema with compatible: ['raumfeld,raumfeld-speaker-l-pxa303', 'marvell,pxa300']
pxa300-raumfeld-speaker-l.dtb: /: failed to match any schema with compatible: ['raumfeld,raumfeld-speaker-l-pxa303', 'marvell,pxa300']
pxa300-raumfeld-speaker-l.dtb: / (raumfeld,raumfeld-speaker-l-pxa303): memory: False schema does not allow {'device_type': ['memory'], 'reg': [[2684354560, 134217728]]}
        from schema $id: http://devicetree.org/schemas/root-node.yaml#
pxa300-raumfeld-speaker-l.dtb: cpus: '#address-cells' is a required property
        from schema $id: http://devicetree.org/schemas/cpus.yaml#
pxa300-raumfeld-speaker-l.dtb: cpus: '#size-cells' is a required property
        from schema $id: http://devicetree.org/schemas/cpus.yaml#
pxa300-raumfeld-speaker-l.dtb: /cpus/cpu: failed to match any schema with compatible: ['marvell,xscale']
pxa300-raumfeld-speaker-l.dtb: pxabus (simple-bus): $nodename:0: 'pxabus' does not match '^([a-z][a-z0-9\\-]+-bus|bus|localbus|soc|axi|ahb|apb)(@.+)?$'
        from schema $id: http://devicetree.org/schemas/simple-bus.yaml#
pxa300-raumfeld-speaker-l.dtb: /pxabus/interrupt-controller at 40d00000: failed to match any schema with compatible: ['marvell,pxa-intc']
pxa300-raumfeld-speaker-l.dtb: interrupt-controller at 40d00000 (marvell,pxa-intc): interrupt-parent: True is not of type 'array'
        from schema $id: http://devicetree.org/schemas/interrupts.yaml#
pxa300-raumfeld-speaker-l.dtb: /pxabus/mmc at 41100000: failed to match any schema with compatible: ['marvell,pxa-mmc']
pxa300-raumfeld-speaker-l.dtb: /pxabus/lcd-controller at 44000000: failed to match any schema with compatible: ['marvell,pxa2xx-lcdc']
pxa300-raumfeld-speaker-l.dtb: /pxabus/i2c at 40f500c0: failed to match any schema with compatible: ['mrvl,pwri2c']
pxa300-raumfeld-speaker-l.dtb: regulator at 34 (maxim,max8660): $nodename:0: 'regulator at 34' does not match 'pmic@[0-9a-f]{1,2}'
        from schema $id: http://devicetree.org/schemas/regulator/max8660.yaml#
pxa300-raumfeld-speaker-l.dtb: regulator at 34 (maxim,max8660): regulators:regulator-v3: Unevaluated properties are not allowed ('regulator-compatible' was unexpected)
        from schema $id: http://devicetree.org/schemas/regulator/max8660.yaml#
pxa300-raumfeld-speaker-l.dtb: regulator at 34 (maxim,max8660): regulators:regulator-v4: Unevaluated properties are not allowed ('regulator-compatible' was unexpected)
        from schema $id: http://devicetree.org/schemas/regulator/max8660.yaml#
pxa300-raumfeld-speaker-l.dtb: regulator at 34 (maxim,max8660): regulators:regulator-v5: Unevaluated properties are not allowed ('regulator-compatible' was unexpected)
        from schema $id: http://devicetree.org/schemas/regulator/max8660.yaml#
pxa300-raumfeld-speaker-l.dtb: regulator at 34 (maxim,max8660): regulators:regulator-v6: Unevaluated properties are not allowed ('regulator-compatible' was unexpected)
        from schema $id: http://devicetree.org/schemas/regulator/max8660.yaml#
pxa300-raumfeld-speaker-l.dtb: regulator at 34 (maxim,max8660): regulators:regulator-v7: Unevaluated properties are not allowed ('regulator-compatible' was unexpected)
        from schema $id: http://devicetree.org/schemas/regulator/max8660.yaml#
pxa300-raumfeld-speaker-l.dtb: pinctrl at 40e10000 (pinconf-single): 'led-pins-a', 'led-pins-b' do not match any of the regexes: '-pins(-[0-9]+)?$|-pin$', '^pinctrl-[0-9]+$'
        from schema $id: http://devicetree.org/schemas/pinctrl/pinctrl-single.yaml#
pxa300-raumfeld-speaker-l.dtb: /pxabus/mmc at 42000000: failed to match any schema with compatible: ['marvell,pxa-mmc']
pxa300-raumfeld-speaker-l.dtb: /pxabus/mmc at 42500000: failed to match any schema with compatible: ['marvell,pxa-mmc']
pxa300-raumfeld-speaker-l.dtb: /pxabus/usb at 4c000000: failed to match any schema with compatible: ['marvell,pxa-ohci']
pxa300-raumfeld-speaker-l.dtb: ssp at 41000000 (mrvl,pxa3xx-ssp): $nodename:0: 'ssp at 41000000' does not match '^spi(@.*|-([0-9]|[1-9][0-9]+))?$'
        from schema $id: http://devicetree.org/schemas/spi/marvell,mmp2-ssp.yaml#
pxa300-raumfeld-speaker-l.dtb: ssp at 41700000 (mrvl,pxa3xx-ssp): $nodename:0: 'ssp at 41700000' does not match '^spi(@.*|-([0-9]|[1-9][0-9]+))?$'
        from schema $id: http://devicetree.org/schemas/spi/marvell,mmp2-ssp.yaml#
pxa300-raumfeld-speaker-l.dtb: ssp at 41900000 (mrvl,pxa3xx-ssp): $nodename:0: 'ssp at 41900000' does not match '^spi(@.*|-([0-9]|[1-9][0-9]+))?$'
        from schema $id: http://devicetree.org/schemas/spi/marvell,mmp2-ssp.yaml#
pxa300-raumfeld-speaker-l.dtb: ssp at 41a00000 (mrvl,pxa3xx-ssp): $nodename:0: 'ssp at 41a00000' does not match '^spi(@.*|-([0-9]|[1-9][0-9]+))?$'
        from schema $id: http://devicetree.org/schemas/spi/marvell,mmp2-ssp.yaml#
pxa300-raumfeld-speaker-l.dtb: /pxabus/timer at 40a00000: failed to match any schema with compatible: ['marvell,pxa-timer']
pxa300-raumfeld-speaker-l.dtb: /pxabus/display-controller at 54000000: failed to match any schema with compatible: ['marvell,pxa300-gcu']
pxa300-raumfeld-speaker-l.dtb: /clocks/clocks: failed to match any schema with compatible: ['marvell,pxa300-clocks']
pxa300-raumfeld-speaker-l.dtb: /ssp-dai0: failed to match any schema with compatible: ['mrvl,pxa-ssp-dai']
pxa300-raumfeld-speaker-l.dtb: /ssp-dai1: failed to match any schema with compatible: ['mrvl,pxa-ssp-dai']
pxa300-raumfeld-speaker-l.dtb: spi (spi-gpio): gpio-miso: False schema does not allow [8, 98, 0]
        from schema $id: http://devicetree.org/schemas/spi/spi-gpio.yaml#
pxa300-raumfeld-speaker-l.dtb: spi (spi-gpio): gpio-mosi: False schema does not allow [8, 97, 0]
        from schema $id: http://devicetree.org/schemas/spi/spi-gpio.yaml#
pxa300-raumfeld-speaker-l.dtb: spi (spi-gpio): gpio-sck: False schema does not allow [8, 95, 0]
        from schema $id: http://devicetree.org/schemas/spi/spi-gpio.yaml#
pxa300-raumfeld-speaker-l.dtb: spi (spi-gpio): 'sck-gpios' is a required property
        from schema $id: http://devicetree.org/schemas/spi/spi-gpio.yaml#
pxa300-raumfeld-speaker-l.dtb: spi (spi-gpio): Unevaluated properties are not allowed ('gpio-miso', 'gpio-mosi', 'gpio-sck' were unexpected)
        from schema $id: http://devicetree.org/schemas/spi/spi-gpio.yaml#
pxa300-raumfeld-speaker-l.dtb: dac at 2 (ti,dac7512): 'vcc-supply' does not match any of the regexes: '^pinctrl-[0-9]+$'
        from schema $id: http://devicetree.org/schemas/iio/dac/ti,dac7512.yaml#
pxa300-raumfeld-speaker-l.dtb: gpio-keys (gpio-keys): 'on-off', 'rescue-boot', 'setup' do not match any of the regexes: '^(button|event|key|switch|(button|event|key|switch)-[a-z0-9-]+|[a-z0-9-]+-(button|event|key|switch))$', '^pinctrl-[0-9]+$'
        from schema $id: http://devicetree.org/schemas/input/gpio-keys.yaml#
pxa300-raumfeld-speaker-l.dtb: leds (gpio-leds): 'left', 'right' do not match any of the regexes: '(^led-[0-9a-f]$|led)', '^pinctrl-[0-9]+$'
        from schema $id: http://devicetree.org/schemas/leds/leds-gpio.yaml#:%!

It would be good to at least address the warnings for nodes that
have an existing yaml binding. Converting the remaining others or
writing new ones takes more time and I wouldn't stress out about
those (yet).

    Arnd


From seanjc at google.com  Mon Dec 22 14:10:37 2025
From: seanjc at google.com (Sean Christopherson)
Date: Mon, 22 Dec 2025 14:10:37 -0800
Subject: possible deadlock due to irq_set_thread_affinity() calling into
 the scheduler (was Re: [PATCH v3 38/62] KVM: SVM: Take and hold ir_list_lock
 across IRTE updates in IOMMU)
In-Reply-To: <9218dafc-c6ad-4ef3-b869-2d6d4a308181@redhat.com>
References: <20250611224604.313496-2-seanjc@google.com> <20250611224604.313496-40-seanjc@google.com>
 <njhjud3e6wbdftzr3ziyuh5bhyvc5ndt5qvmg7rlvh5isoop2l@f2uxctws2c7d>
 <42513cb3-3c2e-4aa8-b748-23b6656a5096@redhat.com> <aUmdSb3d7Z5REMLk@google.com>
 <9218dafc-c6ad-4ef3-b869-2d6d4a308181@redhat.com>
Message-ID: <aUnB3WNLYape2Nap@google.com>

On Mon, Dec 22, 2025, Paolo Bonzini wrote:
> On 12/22/25 20:34, Sean Christopherson wrote:
> > On Mon, Dec 22, 2025, Paolo Bonzini wrote:
> > > notably, __setup_irq() calls wake_up_process outside desc->lock.  Therefore
> > > I'd like so much to treat it as a kernel/irq/ bug; and the simplest (perhaps
> > > too simple...) fix is to drop the wake_up_process().  The only cost is extra
> > > latency on the next interrupt after an affinity change.
> > 
> > Alternatively, what if we rework the KVM<=>IOMMU exchange to decouple updating
> > the IRTE from binding the metadata to the vCPU?  KVM already has the necessary
> > exports to do "out-of-band" updates due to the AVIC architecture requiring IRTE
> > updates on scheduling changes.
> 
> In fact this was actually my first idea, exactly because it makes
> svm->ir_list_lock a leaf lock!
> 
> I threw it away because it makes amd_ir_set_vcpu_affinity() weird, passing
> back the ir_data but not really doing anything else.  Basically its role
> becomes little more than violate abstractions, which seemed wrong.  On the
> other hand, drivers/iommu is already very much tied to the KVM vendor
> modules (in particular avic.c already calls
> amd_iommu_{,de}activate_guest_mode), so who am I to judge what the IOMMU
> driver does.

Yeah, I 100% agree the whole thing is a bit gross, but practically speaking it's
just not feasible to properly abstract the interaction, because in reality the
IOMMU implementation is tightly coupled to the CPU implementation.  E.g. passing
in the address of a PID isn't going to work well with an AMD IOMMU, and passing
in the address of a vCPI isn't going to work well with an Intel IOMMU.

And FWIW, the lack of true abstraction isn't limited to x86.  ARM's GIGv4 passes
around "struct its_cmd_info" and PPC uses "struct kvmppc_xive_irq_state".

I mean, we could do what GICv4 does and use irq_set_vcpu_affinity() to pass
different commands to the IOMMU, e.g. by formalizing "enum avic_vcpu_action"
between KVM and IOMMU so that avic_update_iommu_vcpu_affinity() wouldn't need to
_directly_ call AMD IOMMU code.  But IMO that would be a net negative because in
practice all it would do is make it harder to understand what's going on.  And
it would more directly create this potential deadlock.

Huh.  Which begs the question of whether or not ARM is also affected by this
deadlock, without the extra hop through svm->ir_list_lock:

  (a) irq_set_thread_affinity() triggers the scheduler via wake_up_process(),
      while irq_desc->lock is taken

  (b) the scheduler calls into KVM with rq_lock taken, and KVM uses
      irq_set_vcpu_affinity() via vgic_v4_{load,put}()

If ARM is affected, then maybe fixing this in irq_set_thread_affinity() is indeed
better than fudging around the deadlock in avic.c.


From nicolas at ndufresne.ca  Mon Dec 22 14:35:40 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Mon, 22 Dec 2025 17:35:40 -0500
Subject: [PATCH] media: amphion: Use kmalloc instead of vmalloc
In-Reply-To: <20251222084912.747-1-ming.qian@oss.nxp.com>
References: <20251222084912.747-1-ming.qian@oss.nxp.com>
Message-ID: <de871401c693088783de5ad8068533ac532a9f03.camel@ndufresne.ca>

Hi,

Le lundi 22 d?cembre 2025 ? 16:49 +0800, ming.qian at oss.nxp.com a ?crit?:
> From: Ming Qian <ming.qian at oss.nxp.com>
> 
> Replace vmalloc/vfree with kmalloc/kfree for allocating small
> driver structures (vpu_inst, vdec_t, venc_t, vpu_cmd_t, and
> frame objects).
> 
> vmalloc() is designed for large memory allocations and incurs
> unnecessary overhead for small objects due to virtual memory
> mapping. kmalloc() is more appropriate as it allocates physically
> contiguous memory with lower overhead.
> 
> ftrace measurements of vpu_alloc_cmd() show significant improvement:
> 
> ? Before (vmalloc):? 35-72 us?? (avg ~45.7 us)
> ? After (kmalloc):?? 11-26 us?? (avg ~16.8 us)
> 
> This reduces allocation time by approximately 63%.
> 
> No functional changes are intended.
> 
> Signed-off-by: Ming Qian <ming.qian at oss.nxp.com>

I don't see this patch on patchwork yet, I don't know why. Did you get a
notification or anything ? The patch looks good to me.

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?drivers/media/platform/amphion/vdec.c???? | 16 +++++++---------
> ?drivers/media/platform/amphion/venc.c???? | 20 +++++++++-----------
> ?drivers/media/platform/amphion/vpu_cmds.c | 15 +++++++--------
> ?drivers/media/platform/amphion/vpu_core.c | 11 ++++-------
> ?4 files changed, 27 insertions(+), 35 deletions(-)
> 
> diff --git a/drivers/media/platform/amphion/vdec.c b/drivers/media/platform/amphion/vdec.c
> index c0d2aabb9e0e..7a1c58cac02d 100644
> --- a/drivers/media/platform/amphion/vdec.c
> +++ b/drivers/media/platform/amphion/vdec.c
> @@ -9,7 +9,6 @@
> ?#include <linux/list.h>
> ?#include <linux/kernel.h>
> ?#include <linux/module.h>
> -#include <linux/vmalloc.h>
> ?#include <linux/videodev2.h>
> ?#include <media/v4l2-device.h>
> ?#include <media/v4l2-event.h>
> @@ -17,7 +16,6 @@
> ?#include <media/v4l2-ioctl.h>
> ?#include <media/videobuf2-v4l2.h>
> ?#include <media/videobuf2-dma-contig.h>
> -#include <media/videobuf2-vmalloc.h>
> ?#include "vpu.h"
> ?#include "vpu_defs.h"
> ?#include "vpu_core.h"
> @@ -1642,9 +1640,9 @@ static void vdec_cleanup(struct vpu_inst *inst)
> ?		vdec->slots = NULL;
> ?		vdec->slot_count = 0;
> ?	}
> -	vfree(vdec);
> +	kfree(vdec);
> ?	inst->priv = NULL;
> -	vfree(inst);
> +	kfree(inst);
> ?}
> ?
> ?static void vdec_init_params(struct vdec_t *vdec)
> @@ -1909,13 +1907,13 @@ static int vdec_open(struct file *file)
> ?	struct vdec_t *vdec;
> ?	int ret;
> ?
> -	inst = vzalloc(sizeof(*inst));
> +	inst = kzalloc(sizeof(*inst), GFP_KERNEL);
> ?	if (!inst)
> ?		return -ENOMEM;
> ?
> -	vdec = vzalloc(sizeof(*vdec));
> +	vdec = kzalloc(sizeof(*vdec), GFP_KERNEL);
> ?	if (!vdec) {
> -		vfree(inst);
> +		kfree(inst);
> ?		return -ENOMEM;
> ?	}
> ?
> @@ -1923,8 +1921,8 @@ static int vdec_open(struct file *file)
> ?				??? sizeof(*vdec->slots),
> ?				??? GFP_KERNEL | __GFP_ZERO);
> ?	if (!vdec->slots) {
> -		vfree(vdec);
> -		vfree(inst);
> +		kfree(vdec);
> +		kfree(inst);
> ?		return -ENOMEM;
> ?	}
> ?	vdec->slot_count = VDEC_SLOT_CNT_DFT;
> diff --git a/drivers/media/platform/amphion/venc.c b/drivers/media/platform/amphion/venc.c
> index aced76401b69..9e5cbc2b0d3f 100644
> --- a/drivers/media/platform/amphion/venc.c
> +++ b/drivers/media/platform/amphion/venc.c
> @@ -13,14 +13,12 @@
> ?#include <linux/videodev2.h>
> ?#include <linux/ktime.h>
> ?#include <linux/rational.h>
> -#include <linux/vmalloc.h>
> ?#include <media/v4l2-device.h>
> ?#include <media/v4l2-event.h>
> ?#include <media/v4l2-mem2mem.h>
> ?#include <media/v4l2-ioctl.h>
> ?#include <media/videobuf2-v4l2.h>
> ?#include <media/videobuf2-dma-contig.h>
> -#include <media/videobuf2-vmalloc.h>
> ?#include "vpu.h"
> ?#include "vpu_defs.h"
> ?#include "vpu_core.h"
> @@ -844,7 +842,7 @@ static int venc_get_encoded_frames(struct vpu_inst *inst)
> ?					?????? v4l2_m2m_dst_buf_remove(inst->fh.m2m_ctx)))
> ?			break;
> ?		list_del_init(&frame->list);
> -		vfree(frame);
> +		kfree(frame);
> ?	}
> ?
> ?	return 0;
> @@ -860,7 +858,7 @@ static int venc_frame_encoded(struct vpu_inst *inst, void *arg)
> ?	if (!info)
> ?		return -EINVAL;
> ?	venc = inst->priv;
> -	frame = vzalloc(sizeof(*frame));
> +	frame = kzalloc(sizeof(*frame), GFP_KERNEL);
> ?	if (!frame)
> ?		return -ENOMEM;
> ?
> @@ -912,9 +910,9 @@ static void venc_cleanup(struct vpu_inst *inst)
> ?		return;
> ?
> ?	venc = inst->priv;
> -	vfree(venc);
> +	kfree(venc);
> ?	inst->priv = NULL;
> -	vfree(inst);
> +	kfree(inst);
> ?}
> ?
> ?static int venc_start_session(struct vpu_inst *inst, u32 type)
> @@ -1067,7 +1065,7 @@ static void venc_cleanup_frames(struct venc_t *venc)
> ?
> ?	list_for_each_entry_safe(frame, tmp, &venc->frames, list) {
> ?		list_del_init(&frame->list);
> -		vfree(frame);
> +		kfree(frame);
> ?	}
> ?}
> ?
> @@ -1151,7 +1149,7 @@ static int venc_process_capture(struct vpu_inst *inst, struct vb2_buffer *vb)
> ?		return ret;
> ?
> ?	list_del_init(&frame->list);
> -	vfree(frame);
> +	kfree(frame);
> ?	return 0;
> ?}
> ?
> @@ -1309,13 +1307,13 @@ static int venc_open(struct file *file)
> ?	struct venc_t *venc;
> ?	int ret;
> ?
> -	inst = vzalloc(sizeof(*inst));
> +	inst = kzalloc(sizeof(*inst), GFP_KERNEL);
> ?	if (!inst)
> ?		return -ENOMEM;
> ?
> -	venc = vzalloc(sizeof(*venc));
> +	venc = kzalloc(sizeof(*venc), GFP_KERNEL);
> ?	if (!venc) {
> -		vfree(inst);
> +		kfree(inst);
> ?		return -ENOMEM;
> ?	}
> ?
> diff --git a/drivers/media/platform/amphion/vpu_cmds.c b/drivers/media/platform/amphion/vpu_cmds.c
> index 5695f5c1cb3e..ab69412e0aa7 100644
> --- a/drivers/media/platform/amphion/vpu_cmds.c
> +++ b/drivers/media/platform/amphion/vpu_cmds.c
> @@ -13,7 +13,6 @@
> ?#include <linux/slab.h>
> ?#include <linux/types.h>
> ?#include <linux/delay.h>
> -#include <linux/vmalloc.h>
> ?#include "vpu.h"
> ?#include "vpu_defs.h"
> ?#include "vpu_cmds.h"
> @@ -84,13 +83,13 @@ static struct vpu_cmd_t *vpu_alloc_cmd(struct vpu_inst *inst, u32 id, void *data
> ?	int i;
> ?	int ret;
> ?
> -	cmd = vzalloc(sizeof(*cmd));
> +	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
> ?	if (!cmd)
> ?		return NULL;
> ?
> -	cmd->pkt = vzalloc(sizeof(*cmd->pkt));
> +	cmd->pkt = kzalloc(sizeof(*cmd->pkt), GFP_KERNEL);
> ?	if (!cmd->pkt) {
> -		vfree(cmd);
> +		kfree(cmd);
> ?		return NULL;
> ?	}
> ?
> @@ -98,8 +97,8 @@ static struct vpu_cmd_t *vpu_alloc_cmd(struct vpu_inst *inst, u32 id, void *data
> ?	ret = vpu_iface_pack_cmd(inst->core, cmd->pkt, inst->id, id, data);
> ?	if (ret) {
> ?		dev_err(inst->dev, "iface pack cmd %s fail\n", vpu_id_name(id));
> -		vfree(cmd->pkt);
> -		vfree(cmd);
> +		kfree(cmd->pkt);
> +		kfree(cmd);
> ?		return NULL;
> ?	}
> ?	for (i = 0; i < ARRAY_SIZE(vpu_cmd_requests); i++) {
> @@ -118,8 +117,8 @@ static void vpu_free_cmd(struct vpu_cmd_t *cmd)
> ?		return;
> ?	if (cmd->last_response_cmd)
> ?		atomic_long_set(cmd->last_response_cmd, cmd->key);
> -	vfree(cmd->pkt);
> -	vfree(cmd);
> +	kfree(cmd->pkt);
> +	kfree(cmd);
> ?}
> ?
> ?static int vpu_session_process_cmd(struct vpu_inst *inst, struct vpu_cmd_t *cmd)
> diff --git a/drivers/media/platform/amphion/vpu_core.c b/drivers/media/platform/amphion/vpu_core.c
> index 168f0514851e..85cc4a14f8ed 100644
> --- a/drivers/media/platform/amphion/vpu_core.c
> +++ b/drivers/media/platform/amphion/vpu_core.c
> @@ -17,7 +17,6 @@
> ?#include <linux/pm_runtime.h>
> ?#include <linux/pm_domain.h>
> ?#include <linux/firmware.h>
> -#include <linux/vmalloc.h>
> ?#include "vpu.h"
> ?#include "vpu_defs.h"
> ?#include "vpu_core.h"
> @@ -265,7 +264,7 @@ static int vpu_core_register(struct device *dev, struct vpu_core *core)
> ?	INIT_WORK(&core->msg_work, vpu_msg_run_work);
> ?	INIT_DELAYED_WORK(&core->msg_delayed_work, vpu_msg_delayed_work);
> ?	buffer_size = roundup_pow_of_two(VPU_MSG_BUFFER_SIZE);
> -	core->msg_buffer = vzalloc(buffer_size);
> +	core->msg_buffer = kzalloc(buffer_size, GFP_KERNEL);
> ?	if (!core->msg_buffer) {
> ?		dev_err(core->dev, "failed allocate buffer for fifo\n");
> ?		ret = -ENOMEM;
> @@ -282,10 +281,8 @@ static int vpu_core_register(struct device *dev, struct vpu_core *core)
> ?
> ?	return 0;
> ?error:
> -	if (core->msg_buffer) {
> -		vfree(core->msg_buffer);
> -		core->msg_buffer = NULL;
> -	}
> +	kfree(core->msg_buffer);
> +	core->msg_buffer = NULL;
> ?	if (core->workqueue) {
> ?		destroy_workqueue(core->workqueue);
> ?		core->workqueue = NULL;
> @@ -308,7 +305,7 @@ static int vpu_core_unregister(struct device *dev, struct vpu_core *core)
> ?
> ?	vpu_core_put_vpu(core);
> ?	core->vpu = NULL;
> -	vfree(core->msg_buffer);
> +	kfree(core->msg_buffer);
> ?	core->msg_buffer = NULL;
> ?
> ?	if (core->workqueue) {
> 
> base-commit: b70886ff5833cf499e77af77d2324ce8f68b60ce
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251222/b5d5a8c8/attachment.sig>

From namhyung at kernel.org  Mon Dec 22 14:57:13 2025
From: namhyung at kernel.org (Namhyung Kim)
Date: Mon, 22 Dec 2025 14:57:13 -0800
Subject: [PATCH 08/11] tools headers: Sync arm64 headers with kernel sources
In-Reply-To: <20251222225716.3565649-1-namhyung@kernel.org>
References: <20251222225716.3565649-1-namhyung@kernel.org>
Message-ID: <20251222225716.3565649-8-namhyung@kernel.org>

To pick up changes from:

  b0a3f0e894f34e01 ("arm64/sysreg: Replace TCR_EL1 field macros")
  3bbf004c4808e2c3 ("arm64: cputype: Add Neoverse-V3AE definitions")
  e185c8a0d84236d1 ("arm64: cputype: Add NVIDIA Olympus definitions")
  52b49bd6de29a89a ("arm64: cputype: Remove duplicate Cortex-X1C definitions")

This should address these tools/perf build warnings:

  Warning: Kernel ABI header differences:
    diff -u tools/arch/arm64/include/asm/cputype.h arch/arm64/include/asm/cputype.h

Please see tools/include/README.kernel-copies.

Note that this is still out of sync due to is_midr_in_range_list().

Cc: linux-arm-kernel at lists.infradead.org
Signed-off-by: Namhyung Kim <namhyung at kernel.org>
---
 tools/arch/arm64/include/asm/cputype.h | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/tools/arch/arm64/include/asm/cputype.h b/tools/arch/arm64/include/asm/cputype.h
index f898c47e551f655c..9b73c1aa3ad747ec 100644
--- a/tools/arch/arm64/include/asm/cputype.h
+++ b/tools/arch/arm64/include/asm/cputype.h
@@ -81,7 +81,6 @@
 #define ARM_CPU_PART_CORTEX_A78AE	0xD42
 #define ARM_CPU_PART_CORTEX_X1		0xD44
 #define ARM_CPU_PART_CORTEX_A510	0xD46
-#define ARM_CPU_PART_CORTEX_X1C		0xD4C
 #define ARM_CPU_PART_CORTEX_A520	0xD80
 #define ARM_CPU_PART_CORTEX_A710	0xD47
 #define ARM_CPU_PART_CORTEX_A715	0xD4D
@@ -93,6 +92,7 @@
 #define ARM_CPU_PART_NEOVERSE_V2	0xD4F
 #define ARM_CPU_PART_CORTEX_A720	0xD81
 #define ARM_CPU_PART_CORTEX_X4		0xD82
+#define ARM_CPU_PART_NEOVERSE_V3AE	0xD83
 #define ARM_CPU_PART_NEOVERSE_V3	0xD84
 #define ARM_CPU_PART_CORTEX_X925	0xD85
 #define ARM_CPU_PART_CORTEX_A725	0xD87
@@ -130,6 +130,7 @@
 
 #define NVIDIA_CPU_PART_DENVER		0x003
 #define NVIDIA_CPU_PART_CARMEL		0x004
+#define NVIDIA_CPU_PART_OLYMPUS		0x010
 
 #define FUJITSU_CPU_PART_A64FX		0x001
 
@@ -171,7 +172,6 @@
 #define MIDR_CORTEX_A78AE	MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78AE)
 #define MIDR_CORTEX_X1	MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X1)
 #define MIDR_CORTEX_A510 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A510)
-#define MIDR_CORTEX_X1C MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X1C)
 #define MIDR_CORTEX_A520 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A520)
 #define MIDR_CORTEX_A710 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A710)
 #define MIDR_CORTEX_A715 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A715)
@@ -183,6 +183,7 @@
 #define MIDR_NEOVERSE_V2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V2)
 #define MIDR_CORTEX_A720 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A720)
 #define MIDR_CORTEX_X4 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X4)
+#define MIDR_NEOVERSE_V3AE	MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V3AE)
 #define MIDR_NEOVERSE_V3 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V3)
 #define MIDR_CORTEX_X925 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X925)
 #define MIDR_CORTEX_A725 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A725)
@@ -222,6 +223,7 @@
 
 #define MIDR_NVIDIA_DENVER MIDR_CPU_MODEL(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_DENVER)
 #define MIDR_NVIDIA_CARMEL MIDR_CPU_MODEL(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_CARMEL)
+#define MIDR_NVIDIA_OLYMPUS MIDR_CPU_MODEL(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_OLYMPUS)
 #define MIDR_FUJITSU_A64FX MIDR_CPU_MODEL(ARM_CPU_IMP_FUJITSU, FUJITSU_CPU_PART_A64FX)
 #define MIDR_HISI_TSV110 MIDR_CPU_MODEL(ARM_CPU_IMP_HISI, HISI_CPU_PART_TSV110)
 #define MIDR_HISI_HIP09 MIDR_CPU_MODEL(ARM_CPU_IMP_HISI, HISI_CPU_PART_HIP09)
@@ -245,7 +247,7 @@
 /* Fujitsu Erratum 010001 affects A64FX 1.0 and 1.1, (v0r0 and v1r0) */
 #define MIDR_FUJITSU_ERRATUM_010001		MIDR_FUJITSU_A64FX
 #define MIDR_FUJITSU_ERRATUM_010001_MASK	(~MIDR_CPU_VAR_REV(1, 0))
-#define TCR_CLEAR_FUJITSU_ERRATUM_010001	(TCR_NFD1 | TCR_NFD0)
+#define TCR_CLEAR_FUJITSU_ERRATUM_010001	(TCR_EL1_NFD1 | TCR_EL1_NFD0)
 
 #ifndef __ASSEMBLER__
 
-- 
2.52.0.351.gbe84eed79e-goog



From linusw at kernel.org  Mon Dec 22 15:18:39 2025
From: linusw at kernel.org (Linus Walleij)
Date: Tue, 23 Dec 2025 00:18:39 +0100
Subject: [PATCH 0/4] drm: Revert and fix enable/disable sequence
In-Reply-To: <817b2358-0920-4b7a-abb1-133103d0f9fe@ideasonboard.com>
References: <20251205-drm-seq-fix-v1-0-fda68fa1b3de@ideasonboard.com>
 <3b13c7a2-f7e6-49fd-b3bb-3e0a1fe9acf3@ideasonboard.com> <CAD++jLk8-0Rkh16T+R1dh6=e_f9U1i=AKOk1Y8dLGV4bxzRtFg@mail.gmail.com>
 <817b2358-0920-4b7a-abb1-133103d0f9fe@ideasonboard.com>
Message-ID: <CAD++jLm_0xweD4tRJ8ZfwmcOe2BBGCsUuL1UWUiNM+Gpbq3Zuw@mail.gmail.com>

On Sun, Dec 14, 2025 at 1:42?PM Tomi Valkeinen
<tomi.valkeinen at ideasonboard.com> wrote:

> >> Should we merge this series as a fix for 6.18 rcs?
> >
> > Too late now, so let's merge it as a fix for v6.19 rcs!
>
> Ah, right. Indeed, I meant v6.19 rcs.

Are you applying it or should I?
Not sure if you want some special timing, like outside of
holidays.

Yours,
Linus Walleij


From lkp at intel.com  Mon Dec 22 15:34:06 2025
From: lkp at intel.com (kernel test robot)
Date: Tue, 23 Dec 2025 00:34:06 +0100
Subject: [PATCH v4 14/17] ras: ATL: Unify ATL interface for ARM64 and AMD
In-Reply-To: <20251222094351.38792-16-tianruidong@linux.alibaba.com>
References: <20251222094351.38792-16-tianruidong@linux.alibaba.com>
Message-ID: <202512230007.Vs6IvFVD-lkp@intel.com>

Hi Ruidong,

kernel test robot noticed the following build errors:

[auto build test ERROR on rafael-pm/linux-next]
[also build test ERROR on rafael-pm/bleeding-edge ras/edac-for-next linus/master v6.19-rc2 next-20251219]
[cannot apply to arm64/for-next/core tip/smp/core]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Ruidong-Tian/ACPI-AEST-Parse-the-AEST-table/20251222-175211
base:   https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git linux-next
patch link:    https://lore.kernel.org/r/20251222094351.38792-16-tianruidong%40linux.alibaba.com
patch subject: [PATCH v4 14/17] ras: ATL: Unify ATL interface for ARM64 and AMD
config: x86_64-rhel-9.4 (https://download.01.org/0day-ci/archive/20251223/202512230007.Vs6IvFVD-lkp at intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251223/202512230007.Vs6IvFVD-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512230007.Vs6IvFVD-lkp at intel.com/

All errors (new ones prefixed by >>):

   drivers/ras/amd/fmpm.c: In function 'save_spa':
>> drivers/ras/amd/fmpm.c:336:15: error: implicit declaration of function 'amd_convert_umc_mca_addr_to_sys_addr'; did you mean 'convert_umc_mca_addr_to_sys_addr'? [-Wimplicit-function-declaration]
     336 |         spa = amd_convert_umc_mca_addr_to_sys_addr(&a_err);
         |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         |               convert_umc_mca_addr_to_sys_addr
--
   drivers/ras/amd/atl/umc.c: In function '_retire_row_mi300':
>> drivers/ras/amd/atl/umc.c:321:24: error: implicit declaration of function 'amd_convert_umc_mca_addr_to_sys_addr'; did you mean 'convert_umc_mca_addr_to_sys_addr'? [-Wimplicit-function-declaration]
     321 |                 addr = amd_convert_umc_mca_addr_to_sys_addr(a_err);
         |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         |                        convert_umc_mca_addr_to_sys_addr


vim +336 drivers/ras/amd/fmpm.c

6f15e617cc9932 Yazen Ghannam 2024-02-13  298  
838850c50884cd Yazen Ghannam 2024-03-01  299  static void save_spa(struct fru_rec *rec, unsigned int entry,
838850c50884cd Yazen Ghannam 2024-03-01  300  		     u64 addr, u64 id, unsigned int cpu)
838850c50884cd Yazen Ghannam 2024-03-01  301  {
838850c50884cd Yazen Ghannam 2024-03-01  302  	unsigned int i, fru_idx, spa_entry;
838850c50884cd Yazen Ghannam 2024-03-01  303  	struct atl_err a_err;
838850c50884cd Yazen Ghannam 2024-03-01  304  	unsigned long spa;
838850c50884cd Yazen Ghannam 2024-03-01  305  
838850c50884cd Yazen Ghannam 2024-03-01  306  	if (entry >= max_nr_entries) {
838850c50884cd Yazen Ghannam 2024-03-01  307  		pr_warn_once("FRU descriptor entry %d out-of-bounds (max: %d)\n",
838850c50884cd Yazen Ghannam 2024-03-01  308  			     entry, max_nr_entries);
838850c50884cd Yazen Ghannam 2024-03-01  309  		return;
838850c50884cd Yazen Ghannam 2024-03-01  310  	}
838850c50884cd Yazen Ghannam 2024-03-01  311  
838850c50884cd Yazen Ghannam 2024-03-01  312  	/* spa_nr_entries is always multiple of max_nr_entries */
838850c50884cd Yazen Ghannam 2024-03-01  313  	for (i = 0; i < spa_nr_entries; i += max_nr_entries) {
838850c50884cd Yazen Ghannam 2024-03-01  314  		fru_idx = i / max_nr_entries;
838850c50884cd Yazen Ghannam 2024-03-01  315  		if (fru_records[fru_idx] == rec)
838850c50884cd Yazen Ghannam 2024-03-01  316  			break;
838850c50884cd Yazen Ghannam 2024-03-01  317  	}
838850c50884cd Yazen Ghannam 2024-03-01  318  
838850c50884cd Yazen Ghannam 2024-03-01  319  	if (i >= spa_nr_entries) {
838850c50884cd Yazen Ghannam 2024-03-01  320  		pr_warn_once("FRU record %d not found\n", i);
838850c50884cd Yazen Ghannam 2024-03-01  321  		return;
838850c50884cd Yazen Ghannam 2024-03-01  322  	}
838850c50884cd Yazen Ghannam 2024-03-01  323  
838850c50884cd Yazen Ghannam 2024-03-01  324  	spa_entry = i + entry;
838850c50884cd Yazen Ghannam 2024-03-01  325  	if (spa_entry >= spa_nr_entries) {
838850c50884cd Yazen Ghannam 2024-03-01  326  		pr_warn_once("spa_entries[] index out-of-bounds\n");
838850c50884cd Yazen Ghannam 2024-03-01  327  		return;
838850c50884cd Yazen Ghannam 2024-03-01  328  	}
838850c50884cd Yazen Ghannam 2024-03-01  329  
838850c50884cd Yazen Ghannam 2024-03-01  330  	memset(&a_err, 0, sizeof(struct atl_err));
838850c50884cd Yazen Ghannam 2024-03-01  331  
838850c50884cd Yazen Ghannam 2024-03-01  332  	a_err.addr = addr;
838850c50884cd Yazen Ghannam 2024-03-01  333  	a_err.ipid = id;
838850c50884cd Yazen Ghannam 2024-03-01  334  	a_err.cpu  = cpu;
838850c50884cd Yazen Ghannam 2024-03-01  335  
838850c50884cd Yazen Ghannam 2024-03-01 @336  	spa = amd_convert_umc_mca_addr_to_sys_addr(&a_err);
838850c50884cd Yazen Ghannam 2024-03-01  337  	if (IS_ERR_VALUE(spa)) {
838850c50884cd Yazen Ghannam 2024-03-01  338  		pr_debug("Failed to get system address\n");
838850c50884cd Yazen Ghannam 2024-03-01  339  		return;
838850c50884cd Yazen Ghannam 2024-03-01  340  	}
838850c50884cd Yazen Ghannam 2024-03-01  341  
838850c50884cd Yazen Ghannam 2024-03-01  342  	spa_entries[spa_entry] = spa;
838850c50884cd Yazen Ghannam 2024-03-01  343  	pr_debug("fru_idx: %u, entry: %u, spa_entry: %u, spa: 0x%016llx\n",
838850c50884cd Yazen Ghannam 2024-03-01  344  		 fru_idx, entry, spa_entry, spa_entries[spa_entry]);
838850c50884cd Yazen Ghannam 2024-03-01  345  }
838850c50884cd Yazen Ghannam 2024-03-01  346  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From lkp at intel.com  Mon Dec 22 15:58:22 2025
From: lkp at intel.com (kernel test robot)
Date: Tue, 23 Dec 2025 07:58:22 +0800
Subject: [arm-platforms:kvm-arm64/gicv5-full 42/82]
 arch/arm64/kvm/vgic/vgic-v5-tables.c:385:6: warning: variable 'vmi' is used
 uninitialized whenever 'if' condition is true
Message-ID: <202512230706.u4lubWCl-lkp@intel.com>

tree:   https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git kvm-arm64/gicv5-full
head:   1426b88096b597395df4c82f089b87c62bab45da
commit: a994bc0447523a526e17ae0a62024bf8ef371ce6 [42/82] KVM: arm64: gic-v5: Create, manage, and teardown VMT & VPETs
config: arm64-allmodconfig (https://download.01.org/0day-ci/archive/20251223/202512230706.u4lubWCl-lkp at intel.com/config)
compiler: clang version 19.1.7 (https://github.com/llvm/llvm-project cd708029e0b2869e80abe31ddb175f7c35361f90)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251223/202512230706.u4lubWCl-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512230706.u4lubWCl-lkp at intel.com/

All warnings (new ones prefixed by >>):

>> arch/arm64/kvm/vgic/vgic-v5-tables.c:385:6: warning: variable 'vmi' is used uninitialized whenever 'if' condition is true [-Wsometimes-uninitialized]
     385 |         if (!vgic_v5_vmt_allocated()) {
         |             ^~~~~~~~~~~~~~~~~~~~~~~~
   arch/arm64/kvm/vgic/vgic-v5-tables.c:507:6: note: uninitialized use occurs here
     507 |         if (vmi)
         |             ^~~
   arch/arm64/kvm/vgic/vgic-v5-tables.c:385:2: note: remove the 'if' if its condition is always false
     385 |         if (!vgic_v5_vmt_allocated()) {
         |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     386 |                 kvm_err("VMT is not allocated; cannot populate\n");
         |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     387 |                 ret = -EINVAL;
         |                 ~~~~~~~~~~~~~~
     388 |                 goto out_fail;
         |                 ~~~~~~~~~~~~~~
     389 |         }
         |         ~
   arch/arm64/kvm/vgic/vgic-v5-tables.c:377:20: note: initialize the variable 'vmi' to silence this warning
     377 |         gicv5_vm_info *vmi;
         |                           ^
         |                            = NULL
   1 warning generated.


vim +385 arch/arm64/kvm/vgic/vgic-v5-tables.c

   357	
   358	/*
   359	 * Initialise an entry in the VMT based on the index of the VM. We
   360	 * make the assumption that our VM ID is zero based, and that we can
   361	 * use it to index into the VMT. We check that the index is in the
   362	 * allowed range, just in case.
   363	 *
   364	 * We allocate:
   365	 *     * The VM Descriptor
   366	 *     * The VPE Table
   367	 *
   368	 * We set:
   369	 *     * The VPE ID Bits
   370	 *
   371	 * Note: We don't mark the VMTE as valid as this needs to be done by
   372	 * the hardware..
   373	 */
   374	int vgic_v5_vmte_init(struct kvm *kvm)
   375	{
   376		struct vmtl2_entry *vmte;
   377		gicv5_vm_info *vmi;
   378		void *vmd = NULL, *vpet = NULL;
   379		void **vped_ptrs = NULL;
   380		size_t vpet_alloc_size;
   381		int ret;
   382		u64 tmp;
   383		u16 vm_id = vgic_v5_vm_id(kvm);
   384	
 > 385		if (!vgic_v5_vmt_allocated()) {
   386			kvm_err("VMT is not allocated; cannot populate\n");
   387			ret = -EINVAL;
   388			goto out_fail;
   389		}
   390	
   391		if (vm_id < 0) {
   392			kvm_err("Failed to find free vm_id\n");
   393			return vm_id;
   394		}
   395	
   396		if (vgic_v5_alloc_l2_vmt(kvm)) {
   397			kvm_err("Failed to make the L2 VMTE valid!\n");
   398			return -EIO;
   399		}
   400	
   401		ret = vgic_v5_get_l2_vmte(vm_id, &vmte);
   402		if (ret) {
   403			kvm_err("Failed to look up VMTE\n");
   404			return ret;
   405		}
   406	
   407		if (FIELD_GET(GICV5_VMTEL2E_VALID, vmte->val[0])) {
   408			kvm_err("Attempt to initialize a valid VMTE (0x%x)!\n", vm_id);
   409			return -EINVAL;
   410		}
   411	
   412		ret = vgic_v5_reset_vmte(vm_id);
   413		if (ret) {
   414			kvm_err("Failed to reset VMTE\n");
   415			return ret;
   416		}
   417	
   418		vmi = kzalloc(sizeof(gicv5_vm_info), GFP_KERNEL);
   419		if (vmi == NULL) {
   420			ret = -ENOMEM;
   421			goto out_fail;
   422		}
   423	
   424		/* Allocate and assign the VM Descriptor, if requested. */
   425		if (vmt_info->vmd_size != 0) {
   426			vmd = kzalloc(vmt_info->vmd_size, GFP_KERNEL);
   427			if (vmd == NULL) {
   428				kvm_err("Failed to allocate memory for VM Descriptor\n");
   429				ret = -ENOMEM;
   430				goto out_fail;
   431			}
   432	
   433			if (!IS_ALIGNED((u64)vmd, vmt_info->vmd_size)) {
   434				kvm_err("VMD is incorrectly aligned\n");
   435				ret = -EFAULT;
   436				goto out_fail;
   437			}
   438	
   439			/* Stash the VA so we can free it later */
   440			vmi->vmd_base = vmd;
   441	
   442			tmp = FIELD_PREP(GICV5_VMTEL2E_VMD_ADDR,
   443					virt_to_phys(vmd) >>
   444					GICV5_VMTEL2E_VMD_ADDR_SHIFT);
   445			WRITE_ONCE(vmte->val[0], cpu_to_le64(tmp));
   446		}
   447	
   448		/*
   449		 * Allocate and assign the VPE Table.
   450		 */
   451		vpet_alloc_size = sizeof(vpe_entry) * vmt_info->max_vpes;
   452		vpet = kzalloc(vpet_alloc_size, GFP_KERNEL);
   453		if (vpet == NULL) {
   454			kvm_err("Failed to allocate memory for VPE Table\n");
   455			ret = -ENOMEM;
   456			goto out_fail;
   457		}
   458	
   459		if (!IS_ALIGNED((u64)vpet, vpet_alloc_size)) {
   460			kvm_err("VPET is incorrectly aligned\n");
   461			ret = -EFAULT;
   462			goto out_fail;
   463		}
   464	
   465		/* Stash the VA so we can free it later */
   466		vmi->vpet_base = vpet;
   467	
   468		tmp = FIELD_PREP(GICV5_VMTEL2E_VPET_ADDR,
   469				virt_to_phys(vpet) >> GICV5_VMTEL2E_VPET_ADDR_SHIFT);
   470		tmp |= FIELD_PREP(GICV5_VMTEL2E_VPE_ID_BITS, fls(vmt_info->max_vpes) - 1);
   471		WRITE_ONCE(vmte->val[1], cpu_to_le64(tmp));
   472	
   473		vped_ptrs = kzalloc(vmt_info->max_vpes * sizeof(vped_ptrs), GFP_KERNEL);
   474		if (vped_ptrs == NULL) {
   475			kvm_err("Failed to allocate memory for VPED tracking\n");
   476			ret = -ENOMEM;
   477			goto out_fail;
   478		}
   479		vmi->vped_ptrs = vped_ptrs;
   480	
   481		if (gicv5_host_ist_caps.irs_non_coherent) {
   482			if (vmd)
   483				dcache_clean_inval_poc((unsigned long)vmd,
   484						       (unsigned long)vmd + vmt_info->vmd_size);
   485			if (vpet)
   486				dcache_clean_inval_poc((unsigned long)vpet,
   487						       (unsigned long)vpet + vpet_alloc_size);
   488			dcache_clean_poc((unsigned long)vmte,
   489					 (unsigned long)vmte + sizeof(*vmte));
   490		} else {
   491			dsb(ishst);
   492		}
   493	
   494		ret = xa_insert(&vm_info, vm_id, vmi, GFP_KERNEL);
   495		if (ret)
   496			goto out_fail;
   497	
   498		return 0;
   499	
   500	out_fail:
   501		if (vmd)
   502			kfree(vmd);
   503		if (vpet)
   504			kfree(vpet);
   505		if (vped_ptrs)
   506			kfree(vped_ptrs);
   507		if (vmi)
   508			kfree(vmi);
   509	
   510		vgic_v5_reset_vmte(vm_id);
   511	
   512		return ret;
   513	}
   514	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From 21cnbao at gmail.com  Mon Dec 22 16:02:55 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Tue, 23 Dec 2025 13:02:55 +1300
Subject: [PATCH 5/6] dma-mapping: Allow batched DMA sync operations if
 supported by the arch
In-Reply-To: <20251222084921.GA13529@unreal>
References: <20251221115523.GI13030@unreal> <20251221192458.1320-1-21cnbao@gmail.com>
 <20251222084921.GA13529@unreal>
Message-ID: <CAGsJ_4yuvHNqHDi8eN-8UoY2McoXUeCMmbjFAr=jSdv8GpGKeg@mail.gmail.com>

On Mon, Dec 22, 2025 at 9:49?PM Leon Romanovsky <leon at kernel.org> wrote:
>
> On Mon, Dec 22, 2025 at 03:24:58AM +0800, Barry Song wrote:
> > On Sun, Dec 21, 2025 at 7:55?PM Leon Romanovsky <leon at kernel.org> wrote:
> > [...]
> > > > +
> > >
> > > I'm wondering why you don't implement this batch?sync support inside the
> > > arch_sync_dma_*() functions. Doing so would minimize changes to the generic
> > > kernel/dma/* code and reduce the amount of #ifdef?based spaghetti.
> > >
> >
> > There are two cases: mapping an sg list and mapping a single
> > buffer. The former can be batched with
> > arch_sync_dma_*_batch_add() and flushed via
> > arch_sync_dma_batch_flush(), while the latter requires all work to
> > be done inside arch_sync_dma_*(). Therefore,
> > arch_sync_dma_*() cannot always batch and flush.
>
> Probably in all cases you can call the _batch_ variant, followed by _flush_,
> even when handling a single page. This keeps the code consistent across all
> paths. On platforms that do not support _batch_, the _flush_ operation will be
> a NOP anyway.

We have a lot of code outside kernel/dma that also calls
arch_sync_dma_for_* such as arch/arm, arch/mips, drivers/xen,
I guess we don?t want to modify so many things?

for kernel/dma, we have two "single" callers only:
kernel/dma/direct.h, kernel/dma/swiotlb.c.  and they looks quite
straightforward:

static inline void dma_direct_sync_single_for_device(struct device *dev,
                dma_addr_t addr, size_t size, enum dma_data_direction dir)
{
        phys_addr_t paddr = dma_to_phys(dev, addr);

        swiotlb_sync_single_for_device(dev, paddr, size, dir);

        if (!dev_is_dma_coherent(dev))
                arch_sync_dma_for_device(paddr, size, dir);
}

I guess moving to arch_sync_dma_for_device_batch + flush
doesn?t really look much better, does it?

>
> I would also rename arch_sync_dma_batch_flush() to arch_sync_dma_flush().

Sure.

>
> You can also minimize changes in dma_direct_map_phys() too, by extending
> it's signature to provide if flush is needed or not.

Yes. I have

static inline dma_addr_t __dma_direct_map_phys(struct device *dev,
                phys_addr_t phys, size_t size, enum dma_data_direction dir,
                unsigned long attrs, bool flush)

and two wrappers:
static inline dma_addr_t dma_direct_map_phys(struct device *dev,
                phys_addr_t phys, size_t size, enum dma_data_direction dir,
                unsigned long attrs)
{
        return __dma_direct_map_phys(dev, phys, size, dir, attrs, true);
}

static inline dma_addr_t dma_direct_map_phys_batch_add(struct device *dev,
                phys_addr_t phys, size_t size, enum dma_data_direction dir,
                unsigned long attrs)
{
        return __dma_direct_map_phys(dev, phys, size, dir, attrs, false);
}

If you prefer exposing "flush" directly in dma_direct_map_phys()
and updating its callers with flush=true, I think that?s fine.

It could be also true for dma_direct_sync_single_for_device().

>
> dma_direct_map_phys(....) -> dma_direct_map_phys(...., bool flush):
>
> static inline dma_addr_t dma_direct_map_phys(...., bool flush)
> {
>         ....
>
>         if (dma_addr != DMA_MAPPING_ERROR && !dev_is_dma_coherent(dev) &&
>             !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO)))
>         {
>                 arch_sync_dma_for_device(phys, size, dir);
>                 if (flush)
>                         arch_sync_dma_flush();
>         }
> }
>

Thanks
Barry


From lkp at intel.com  Mon Dec 22 16:57:16 2025
From: lkp at intel.com (kernel test robot)
Date: Tue, 23 Dec 2025 01:57:16 +0100
Subject: [PATCH v4 10/17] ras: AEST: Introduce AEST driver sysfs interface
In-Reply-To: <20251222094351.38792-11-tianruidong@linux.alibaba.com>
References: <20251222094351.38792-11-tianruidong@linux.alibaba.com>
Message-ID: <202512230122.CfXZcF76-lkp@intel.com>

Hi Ruidong,

kernel test robot noticed the following build warnings:

[auto build test WARNING on rafael-pm/linux-next]
[also build test WARNING on rafael-pm/bleeding-edge ras/edac-for-next next-20251219]
[cannot apply to arm64/for-next/core linus/master tip/smp/core v6.16-rc1]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Ruidong-Tian/ACPI-AEST-Parse-the-AEST-table/20251222-175211
base:   https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git linux-next
patch link:    https://lore.kernel.org/r/20251222094351.38792-11-tianruidong%40linux.alibaba.com
patch subject: [PATCH v4 10/17] ras: AEST: Introduce AEST driver sysfs interface
reproduce: (https://download.01.org/0day-ci/archive/20251223/202512230122.CfXZcF76-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512230122.CfXZcF76-lkp at intel.com/

All warnings (new ones prefixed by >>):

   Using alabaster theme
   ERROR: Cannot find file ./include/linux/pci.h
   WARNING: No kernel-doc for file ./include/linux/pci.h
   ERROR: Cannot find file ./include/linux/mod_devicetable.h
   WARNING: No kernel-doc for file ./include/linux/mod_devicetable.h
>> Documentation/ABI/testing/debugfs-aest:1: WARNING: Block quote ends without a blank line; unexpected unindent. [docutils]
   ERROR: Cannot find file ./include/linux/bootconfig.h
   WARNING: No kernel-doc for file ./include/linux/bootconfig.h
   ERROR: Cannot find file ./include/linux/pstore_zone.h
   ERROR: Cannot find file ./include/linux/pstore_zone.h
   WARNING: No kernel-doc for file ./include/linux/pstore_zone.h


vim +1 Documentation/ABI/testing/debugfs-aest

   > 1	What:		/sys/kernel/debug/aest/<name>.<id>/
     2	Date:		Dec 2025
     3	KernelVersion	6.19
     4	Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
     5	Description:
     6			Directory represented a AEST device, <name> means device type,
     7			like:
     8	
     9				processor
    10				memory
    11				smmu
    12				...
    13			<id> is the unique ID for this device.
    14	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From ming.qian at oss.nxp.com  Mon Dec 22 17:18:47 2025
From: ming.qian at oss.nxp.com (Ming Qian(OSS))
Date: Tue, 23 Dec 2025 09:18:47 +0800
Subject: [PATCH] media: amphion: Use kmalloc instead of vmalloc
In-Reply-To: <de871401c693088783de5ad8068533ac532a9f03.camel@ndufresne.ca>
References: <20251222084912.747-1-ming.qian@oss.nxp.com>
 <de871401c693088783de5ad8068533ac532a9f03.camel@ndufresne.ca>
Message-ID: <1261af9b-339a-4081-ab95-ad8a4d05636d@oss.nxp.com>

Hi Nicolas,

On 12/23/2025 6:35 AM, Nicolas Dufresne wrote:
> Hi,
> 
> Le lundi 22 d?cembre 2025 ? 16:49 +0800, ming.qian at oss.nxp.com a ?crit :
>> From: Ming Qian <ming.qian at oss.nxp.com>
>>
>> Replace vmalloc/vfree with kmalloc/kfree for allocating small
>> driver structures (vpu_inst, vdec_t, venc_t, vpu_cmd_t, and
>> frame objects).
>>
>> vmalloc() is designed for large memory allocations and incurs
>> unnecessary overhead for small objects due to virtual memory
>> mapping. kmalloc() is more appropriate as it allocates physically
>> contiguous memory with lower overhead.
>>
>> ftrace measurements of vpu_alloc_cmd() show significant improvement:
>>
>>    Before (vmalloc):  35-72 us   (avg ~45.7 us)
>>    After (kmalloc):   11-26 us   (avg ~16.8 us)
>>
>> This reduces allocation time by approximately 63%.
>>
>> No functional changes are intended.
>>
>> Signed-off-by: Ming Qian <ming.qian at oss.nxp.com>
> 
> I don't see this patch on patchwork yet, I don't know why. Did you get a
> notification or anything ? The patch looks good to me.
> 
> Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
> 

I did not receive any system notification or reply.
It's currently in patchwork, and I'm not sure why there's been such a 
long delay.

Thanks for your review.

Regards,
Ming

>> ---
>>   drivers/media/platform/amphion/vdec.c     | 16 +++++++---------
>>   drivers/media/platform/amphion/venc.c     | 20 +++++++++-----------
>>   drivers/media/platform/amphion/vpu_cmds.c | 15 +++++++--------
>>   drivers/media/platform/amphion/vpu_core.c | 11 ++++-------
>>   4 files changed, 27 insertions(+), 35 deletions(-)
>>
>> diff --git a/drivers/media/platform/amphion/vdec.c b/drivers/media/platform/amphion/vdec.c
>> index c0d2aabb9e0e..7a1c58cac02d 100644
>> --- a/drivers/media/platform/amphion/vdec.c
>> +++ b/drivers/media/platform/amphion/vdec.c
>> @@ -9,7 +9,6 @@
>>   #include <linux/list.h>
>>   #include <linux/kernel.h>
>>   #include <linux/module.h>
>> -#include <linux/vmalloc.h>
>>   #include <linux/videodev2.h>
>>   #include <media/v4l2-device.h>
>>   #include <media/v4l2-event.h>
>> @@ -17,7 +16,6 @@
>>   #include <media/v4l2-ioctl.h>
>>   #include <media/videobuf2-v4l2.h>
>>   #include <media/videobuf2-dma-contig.h>
>> -#include <media/videobuf2-vmalloc.h>
>>   #include "vpu.h"
>>   #include "vpu_defs.h"
>>   #include "vpu_core.h"
>> @@ -1642,9 +1640,9 @@ static void vdec_cleanup(struct vpu_inst *inst)
>>   		vdec->slots = NULL;
>>   		vdec->slot_count = 0;
>>   	}
>> -	vfree(vdec);
>> +	kfree(vdec);
>>   	inst->priv = NULL;
>> -	vfree(inst);
>> +	kfree(inst);
>>   }
>>   
>>   static void vdec_init_params(struct vdec_t *vdec)
>> @@ -1909,13 +1907,13 @@ static int vdec_open(struct file *file)
>>   	struct vdec_t *vdec;
>>   	int ret;
>>   
>> -	inst = vzalloc(sizeof(*inst));
>> +	inst = kzalloc(sizeof(*inst), GFP_KERNEL);
>>   	if (!inst)
>>   		return -ENOMEM;
>>   
>> -	vdec = vzalloc(sizeof(*vdec));
>> +	vdec = kzalloc(sizeof(*vdec), GFP_KERNEL);
>>   	if (!vdec) {
>> -		vfree(inst);
>> +		kfree(inst);
>>   		return -ENOMEM;
>>   	}
>>   
>> @@ -1923,8 +1921,8 @@ static int vdec_open(struct file *file)
>>   				    sizeof(*vdec->slots),
>>   				    GFP_KERNEL | __GFP_ZERO);
>>   	if (!vdec->slots) {
>> -		vfree(vdec);
>> -		vfree(inst);
>> +		kfree(vdec);
>> +		kfree(inst);
>>   		return -ENOMEM;
>>   	}
>>   	vdec->slot_count = VDEC_SLOT_CNT_DFT;
>> diff --git a/drivers/media/platform/amphion/venc.c b/drivers/media/platform/amphion/venc.c
>> index aced76401b69..9e5cbc2b0d3f 100644
>> --- a/drivers/media/platform/amphion/venc.c
>> +++ b/drivers/media/platform/amphion/venc.c
>> @@ -13,14 +13,12 @@
>>   #include <linux/videodev2.h>
>>   #include <linux/ktime.h>
>>   #include <linux/rational.h>
>> -#include <linux/vmalloc.h>
>>   #include <media/v4l2-device.h>
>>   #include <media/v4l2-event.h>
>>   #include <media/v4l2-mem2mem.h>
>>   #include <media/v4l2-ioctl.h>
>>   #include <media/videobuf2-v4l2.h>
>>   #include <media/videobuf2-dma-contig.h>
>> -#include <media/videobuf2-vmalloc.h>
>>   #include "vpu.h"
>>   #include "vpu_defs.h"
>>   #include "vpu_core.h"
>> @@ -844,7 +842,7 @@ static int venc_get_encoded_frames(struct vpu_inst *inst)
>>   					       v4l2_m2m_dst_buf_remove(inst->fh.m2m_ctx)))
>>   			break;
>>   		list_del_init(&frame->list);
>> -		vfree(frame);
>> +		kfree(frame);
>>   	}
>>   
>>   	return 0;
>> @@ -860,7 +858,7 @@ static int venc_frame_encoded(struct vpu_inst *inst, void *arg)
>>   	if (!info)
>>   		return -EINVAL;
>>   	venc = inst->priv;
>> -	frame = vzalloc(sizeof(*frame));
>> +	frame = kzalloc(sizeof(*frame), GFP_KERNEL);
>>   	if (!frame)
>>   		return -ENOMEM;
>>   
>> @@ -912,9 +910,9 @@ static void venc_cleanup(struct vpu_inst *inst)
>>   		return;
>>   
>>   	venc = inst->priv;
>> -	vfree(venc);
>> +	kfree(venc);
>>   	inst->priv = NULL;
>> -	vfree(inst);
>> +	kfree(inst);
>>   }
>>   
>>   static int venc_start_session(struct vpu_inst *inst, u32 type)
>> @@ -1067,7 +1065,7 @@ static void venc_cleanup_frames(struct venc_t *venc)
>>   
>>   	list_for_each_entry_safe(frame, tmp, &venc->frames, list) {
>>   		list_del_init(&frame->list);
>> -		vfree(frame);
>> +		kfree(frame);
>>   	}
>>   }
>>   
>> @@ -1151,7 +1149,7 @@ static int venc_process_capture(struct vpu_inst *inst, struct vb2_buffer *vb)
>>   		return ret;
>>   
>>   	list_del_init(&frame->list);
>> -	vfree(frame);
>> +	kfree(frame);
>>   	return 0;
>>   }
>>   
>> @@ -1309,13 +1307,13 @@ static int venc_open(struct file *file)
>>   	struct venc_t *venc;
>>   	int ret;
>>   
>> -	inst = vzalloc(sizeof(*inst));
>> +	inst = kzalloc(sizeof(*inst), GFP_KERNEL);
>>   	if (!inst)
>>   		return -ENOMEM;
>>   
>> -	venc = vzalloc(sizeof(*venc));
>> +	venc = kzalloc(sizeof(*venc), GFP_KERNEL);
>>   	if (!venc) {
>> -		vfree(inst);
>> +		kfree(inst);
>>   		return -ENOMEM;
>>   	}
>>   
>> diff --git a/drivers/media/platform/amphion/vpu_cmds.c b/drivers/media/platform/amphion/vpu_cmds.c
>> index 5695f5c1cb3e..ab69412e0aa7 100644
>> --- a/drivers/media/platform/amphion/vpu_cmds.c
>> +++ b/drivers/media/platform/amphion/vpu_cmds.c
>> @@ -13,7 +13,6 @@
>>   #include <linux/slab.h>
>>   #include <linux/types.h>
>>   #include <linux/delay.h>
>> -#include <linux/vmalloc.h>
>>   #include "vpu.h"
>>   #include "vpu_defs.h"
>>   #include "vpu_cmds.h"
>> @@ -84,13 +83,13 @@ static struct vpu_cmd_t *vpu_alloc_cmd(struct vpu_inst *inst, u32 id, void *data
>>   	int i;
>>   	int ret;
>>   
>> -	cmd = vzalloc(sizeof(*cmd));
>> +	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
>>   	if (!cmd)
>>   		return NULL;
>>   
>> -	cmd->pkt = vzalloc(sizeof(*cmd->pkt));
>> +	cmd->pkt = kzalloc(sizeof(*cmd->pkt), GFP_KERNEL);
>>   	if (!cmd->pkt) {
>> -		vfree(cmd);
>> +		kfree(cmd);
>>   		return NULL;
>>   	}
>>   
>> @@ -98,8 +97,8 @@ static struct vpu_cmd_t *vpu_alloc_cmd(struct vpu_inst *inst, u32 id, void *data
>>   	ret = vpu_iface_pack_cmd(inst->core, cmd->pkt, inst->id, id, data);
>>   	if (ret) {
>>   		dev_err(inst->dev, "iface pack cmd %s fail\n", vpu_id_name(id));
>> -		vfree(cmd->pkt);
>> -		vfree(cmd);
>> +		kfree(cmd->pkt);
>> +		kfree(cmd);
>>   		return NULL;
>>   	}
>>   	for (i = 0; i < ARRAY_SIZE(vpu_cmd_requests); i++) {
>> @@ -118,8 +117,8 @@ static void vpu_free_cmd(struct vpu_cmd_t *cmd)
>>   		return;
>>   	if (cmd->last_response_cmd)
>>   		atomic_long_set(cmd->last_response_cmd, cmd->key);
>> -	vfree(cmd->pkt);
>> -	vfree(cmd);
>> +	kfree(cmd->pkt);
>> +	kfree(cmd);
>>   }
>>   
>>   static int vpu_session_process_cmd(struct vpu_inst *inst, struct vpu_cmd_t *cmd)
>> diff --git a/drivers/media/platform/amphion/vpu_core.c b/drivers/media/platform/amphion/vpu_core.c
>> index 168f0514851e..85cc4a14f8ed 100644
>> --- a/drivers/media/platform/amphion/vpu_core.c
>> +++ b/drivers/media/platform/amphion/vpu_core.c
>> @@ -17,7 +17,6 @@
>>   #include <linux/pm_runtime.h>
>>   #include <linux/pm_domain.h>
>>   #include <linux/firmware.h>
>> -#include <linux/vmalloc.h>
>>   #include "vpu.h"
>>   #include "vpu_defs.h"
>>   #include "vpu_core.h"
>> @@ -265,7 +264,7 @@ static int vpu_core_register(struct device *dev, struct vpu_core *core)
>>   	INIT_WORK(&core->msg_work, vpu_msg_run_work);
>>   	INIT_DELAYED_WORK(&core->msg_delayed_work, vpu_msg_delayed_work);
>>   	buffer_size = roundup_pow_of_two(VPU_MSG_BUFFER_SIZE);
>> -	core->msg_buffer = vzalloc(buffer_size);
>> +	core->msg_buffer = kzalloc(buffer_size, GFP_KERNEL);
>>   	if (!core->msg_buffer) {
>>   		dev_err(core->dev, "failed allocate buffer for fifo\n");
>>   		ret = -ENOMEM;
>> @@ -282,10 +281,8 @@ static int vpu_core_register(struct device *dev, struct vpu_core *core)
>>   
>>   	return 0;
>>   error:
>> -	if (core->msg_buffer) {
>> -		vfree(core->msg_buffer);
>> -		core->msg_buffer = NULL;
>> -	}
>> +	kfree(core->msg_buffer);
>> +	core->msg_buffer = NULL;
>>   	if (core->workqueue) {
>>   		destroy_workqueue(core->workqueue);
>>   		core->workqueue = NULL;
>> @@ -308,7 +305,7 @@ static int vpu_core_unregister(struct device *dev, struct vpu_core *core)
>>   
>>   	vpu_core_put_vpu(core);
>>   	core->vpu = NULL;
>> -	vfree(core->msg_buffer);
>> +	kfree(core->msg_buffer);
>>   	core->msg_buffer = NULL;
>>   
>>   	if (core->workqueue) {
>>
>> base-commit: b70886ff5833cf499e77af77d2324ce8f68b60ce


From broonie at kernel.org  Mon Dec 22 17:20:54 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:20:54 +0000
Subject: [PATCH v9 00/30] KVM: arm64: Implement support for SME
Message-ID: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>

I've removed the RFC tag from this version of the series, but the items
that I'm looking for feedback on remains the same:

 - The userspace ABI, in particular:
  - The vector length used for the SVE registers, access to the SVE
    registers and access to ZA and (if available) ZT0 depending on
    the current state of PSTATE.{SM,ZA}.
  - The use of a single finalisation for both SVE and SME.

 - The addition of control for enabling fine grained traps in a similar
   manner to FGU but without the UNDEF, I'm not clear if this is desired
   at all and at present this requires symmetric read and write traps like
   FGU. That seemed like it might be desired from an implementation
   point of view but we already have one case where we enable an
   asymmetric trap (for ARM64_WORKAROUND_AMPERE_AC03_CPU_38) and it
   seems generally useful to enable asymmetrically.

This series implements support for SME use in non-protected KVM guests.
Much of this is very similar to SVE, the main additional challenge that
SME presents is that it introduces a new vector length similar to the
SVE vector length and two new controls which change the registers seen
by guests:

 - PSTATE.ZA enables the ZA matrix register and, if SME2 is supported,
   the ZT0 LUT register.
 - PSTATE.SM enables streaming mode, a new floating point mode which
   uses the SVE register set with the separately configured SME vector
   length.  In streaming mode implementation of the FFR register is
   optional.

It is also permitted to build systems which support SME without SVE, in
this case when not in streaming mode no SVE registers or instructions
are available.  Further, there is no requirement that there be any
overlap in the set of vector lengths supported by SVE and SME in a
system, this is expected to be a common situation in practical systems.

Since there is a new vector length to configure we introduce a new
feature parallel to the existing SVE one with a new pseudo register for
the streaming mode vector length.  Due to the overlap with SVE caused by
streaming mode rather than finalising SME as a separate feature we use
the existing SVE finalisation to also finalise SME, a new define
KVM_ARM_VCPU_VEC is provided to help make user code clearer.  Finalising
SVE and SME separately would introduce complication with register access
since finalising SVE makes the SVE registers writeable by userspace and
doing multiple finalisations results in an error being reported.
Dealing with a state where the SVE registers are writeable due to one of
SVE or SME being finalised but may have their VL changed by the other
being finalised seems like needless complexity with minimal practical
utility, it seems clearer to just express directly that only one
finalisation can be done in the ABI.

Access to the floating point registers follows the architecture:

 - When both SVE and SME are present:
   - If PSTATE.SM == 0 the vector length used for the Z and P registers
     is the SVE vector length.
   - If PSTATE.SM == 1 the vector length used for the Z and P registers
     is the SME vector length.
 - If only SME is present:
   - If PSTATE.SM == 0 the Z and P registers are inaccessible and the
     floating point state accessed via the encodings for the V registers.
   - If PSTATE.SM == 1 the vector length used for the Z and P registers
 - The SME specific ZA and ZT0 registers are only accessible if SVCR.ZA is 1.

The VMM must understand this, in particular when loading state SVCR
should be configured before other state.  It should be noted that while
the architecture refers to PSTATE.SM and PSTATE.ZA these PSTATE bits are
not preserved in SPSR_ELx, they are only accessible via SVCR.

There are a large number of subfeatures for SME, most of which only
offer additional instructions but some of which (SME2 and FA64) add
architectural state. These are configured via the ID registers as per
usual.

Protected KVM supported, with the implementation maintaining the
existing restriction that the hypervisor will refuse to run if streaming
mode or ZA is enabled.  This both simplfies the code and avoids the need
to allocate storage for host ZA and ZT0 state, there seems to be little
practical use case for supporting this and the memory usage would be
non-trivial.

The new KVM_ARM_VCPU_VEC feature and ZA and ZT0 registers have not been
added to the get-reg-list selftest, the idea of supporting additional
features there without restructuring the program to generate all
possible feature combinations has been rejected.  I will post a separate
series which does that restructuring.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
Changes in v9:
- Rebase onto v6.19-rc1.
- ABI document clarifications.
- Add changes dropping asserts on single bit wide bitfields in set_id_regs.
- Link to v8: https://lore.kernel.org/r/20250902-kvm-arm64-sme-v8-0-2cb2199c656c at kernel.org

Changes in v8:
- Small fixes in ABI documentation.
- Link to v7: https://lore.kernel.org/r/20250822-kvm-arm64-sme-v7-0-7a65d82b8b10 at kernel.org

Changes in v7:
- Rebase onto v6.17-rc1.
- Handle SMIDR_EL1 as a VM wide ID register and use this in feat_sme_smps().
- Expose affinity fields in SMIDR_EL1.
- Remove SMPRI_EL1 from vcpu_sysreg, the value is always 0 currently.
- Prevent userspace writes to SMPRIMAP_EL2.
- Link to v6: https://lore.kernel.org/r/20250625-kvm-arm64-sme-v6-0-114cff4ffe04 at kernel.org

Changes in v6:
- Rebase onto v6.16-rc3.
- Link to v5: https://lore.kernel.org/r/20250417-kvm-arm64-sme-v5-0-f469a2d5f574 at kernel.org

Changes in v5:
- Rebase onto v6.15-rc2.
- Add pKVM guest support.
- Always restore SVCR.
- Link to v4: https://lore.kernel.org/r/20250214-kvm-arm64-sme-v4-0-d64a681adcc2 at kernel.org

Changes in v4:
- Rebase onto v6.14-rc2 and Mark Rutland's fixes.
- Expose SME to nested guests.
- Additional cleanups and test fixes following on from the rebase.
- Flush register state on VMM PSTATE.{SM,ZA}.
- Link to v3: https://lore.kernel.org/r/20241220-kvm-arm64-sme-v3-0-05b018c1ffeb at kernel.org

Changes in v3:
- Rebase onto v6.12-rc2.
- Link to v2: https://lore.kernel.org/r/20231222-kvm-arm64-sme-v2-0-da226cb180bb at kernel.org

Changes in v2:
- Rebase onto v6.7-rc3.
- Configure subfeatures based on host system only.
- Complete nVHE support.
- There was some snafu with sending v1 out, it didn't make it to the
  lists but in case it hit people's inboxes I'm sending as v2.

---
Mark Brown (30):
      arm64/sysreg: Update SMIDR_EL1 to DDI0601 2025-06
      arm64/fpsimd: Update FA64 and ZT0 enables when loading SME state
      arm64/fpsimd: Decide to save ZT0 and streaming mode FFR at bind time
      arm64/fpsimd: Check enable bit for FA64 when saving EFI state
      arm64/fpsimd: Determine maximum virtualisable SME vector length
      KVM: arm64: Pay attention to FFR parameter in SVE save and load
      KVM: arm64: Pull ctxt_has_ helpers to start of sysreg-sr.h
      KVM: arm64: Move SVE state access macros after feature test macros
      KVM: arm64: Rename SVE finalization constants to be more general
      KVM: arm64: Document the KVM ABI for SME
      KVM: arm64: Define internal features for SME
      KVM: arm64: Rename sve_state_reg_region
      KVM: arm64: Store vector lengths in an array
      KVM: arm64: Implement SME vector length configuration
      KVM: arm64: Support SME control registers
      KVM: arm64: Support TPIDR2_EL0
      KVM: arm64: Support SME identification registers for guests
      KVM: arm64: Support SME priority registers
      KVM: arm64: Provide assembly for SME register access
      KVM: arm64: Support userspace access to streaming mode Z and P registers
      KVM: arm64: Flush register state on writes to SVCR.SM and SVCR.ZA
      KVM: arm64: Expose SME specific state to userspace
      KVM: arm64: Context switch SME state for guests
      KVM: arm64: Handle SME exceptions
      KVM: arm64: Expose SME to nested guests
      KVM: arm64: Provide interface for configuring and enabling SME for guests
      KVM: arm64: selftests: Remove spurious check for single bit safe values
      KVM: arm64: selftests: Skip impossible invalid value tests
      KVM: arm64: selftests: Add SME system registers to get-reg-list
      KVM: arm64: selftests: Add SME to set_id_regs test

 Documentation/virt/kvm/api.rst                   | 120 ++++++++---
 arch/arm64/include/asm/fpsimd.h                  |  26 +++
 arch/arm64/include/asm/kvm_emulate.h             |   6 +
 arch/arm64/include/asm/kvm_host.h                | 163 ++++++++++++---
 arch/arm64/include/asm/kvm_hyp.h                 |   5 +-
 arch/arm64/include/asm/kvm_pkvm.h                |   2 +-
 arch/arm64/include/asm/vncr_mapping.h            |   2 +
 arch/arm64/include/uapi/asm/kvm.h                |  33 +++
 arch/arm64/kernel/cpufeature.c                   |   2 -
 arch/arm64/kernel/fpsimd.c                       |  89 ++++----
 arch/arm64/kvm/arm.c                             |  10 +
 arch/arm64/kvm/config.c                          |  11 +-
 arch/arm64/kvm/fpsimd.c                          |  28 ++-
 arch/arm64/kvm/guest.c                           | 252 ++++++++++++++++++++---
 arch/arm64/kvm/handle_exit.c                     |  14 ++
 arch/arm64/kvm/hyp/fpsimd.S                      |  28 ++-
 arch/arm64/kvm/hyp/include/hyp/switch.h          | 168 +++++++++++++--
 arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h       | 110 ++++++----
 arch/arm64/kvm/hyp/nvhe/hyp-main.c               |  86 ++++++--
 arch/arm64/kvm/hyp/nvhe/pkvm.c                   |  85 ++++++--
 arch/arm64/kvm/hyp/nvhe/switch.c                 |   4 +-
 arch/arm64/kvm/hyp/nvhe/sys_regs.c               |   6 +
 arch/arm64/kvm/hyp/vhe/switch.c                  |  17 +-
 arch/arm64/kvm/hyp/vhe/sysreg-sr.c               |   7 +
 arch/arm64/kvm/nested.c                          |   3 +-
 arch/arm64/kvm/reset.c                           | 156 ++++++++++----
 arch/arm64/kvm/sys_regs.c                        | 140 ++++++++++++-
 arch/arm64/tools/sysreg                          |   8 +-
 include/uapi/linux/kvm.h                         |   1 +
 tools/testing/selftests/kvm/arm64/get-reg-list.c |  15 +-
 tools/testing/selftests/kvm/arm64/set_id_regs.c  |  84 ++++++--
 31 files changed, 1367 insertions(+), 314 deletions(-)
---
base-commit: 3e7f562e20ee87a25e104ef4fce557d39d62fa85
change-id: 20230301-kvm-arm64-sme-06a1246d3636

Best regards,
--  
Mark Brown <broonie at kernel.org>



From broonie at kernel.org  Mon Dec 22 17:20:55 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:20:55 +0000
Subject: [PATCH v9 01/30] arm64/sysreg: Update SMIDR_EL1 to DDI0601 2025-06
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-1-8be3867cb883@kernel.org>

Update the definiton of SMIDR_EL1 in the sysreg definition to reflect the
information in DD0601 2025-06. This includes somewhat more generic ways of
describing the sharing of SMCUs, more information on supported priorities
and provides additional resolution for describing affinity groups.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 arch/arm64/tools/sysreg | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
index 8921b51866d6..6bf143bfe57c 100644
--- a/arch/arm64/tools/sysreg
+++ b/arch/arm64/tools/sysreg
@@ -3660,11 +3660,15 @@ Field	3:0	BS
 EndSysreg
 
 Sysreg	SMIDR_EL1	3	1	0	0	6
-Res0	63:32
+Res0	63:60
+Field	59:56	NSMC
+Field	55:52	HIP
+Field	51:32	AFFINITY2
 Field	31:24	IMPLEMENTER
 Field	23:16	REVISION
 Field	15	SMPS
-Res0	14:12
+Field	14:13	SH
+Res0	12
 Field	11:0	AFFINITY
 EndSysreg
 

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:20:56 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:20:56 +0000
Subject: [PATCH v9 02/30] arm64/fpsimd: Update FA64 and ZT0 enables when
 loading SME state
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-2-8be3867cb883@kernel.org>

Currently we enable EL0 and EL1 access to FA64 and ZT0 at boot and leave
them enabled throughout the runtime of the system. When we add KVM support
we will need to make this configuration dynamic, these features may be
disabled for some KVM guests. Since the host kernel saves the floating
point state for non-protected guests and we wish to avoid KVM having to
reload the floating point state needlessly on guest reentry let's move the
configuration of these enables to the floating point state reload.

We provide a helper which does the configuration as part of a
read/modify/write operation along with the configuration of the task VL,
then update the floating point state load and SME access trap to use it.
We also remove the setting of the enable bits from the CPU feature
identification and resume paths.  There will be a small overhead from
setting the enables one at a time but this should be negligable in the
context of the state load or access trap.  In order to avoid compiler
warnings due to unused variables in !CONFIG_ARM64_SME cases we avoid
storing the vector length in temporary variables.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 arch/arm64/include/asm/fpsimd.h | 14 ++++++++++++
 arch/arm64/kernel/cpufeature.c  |  2 --
 arch/arm64/kernel/fpsimd.c      | 47 +++++++++++------------------------------
 3 files changed, 26 insertions(+), 37 deletions(-)

diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index 1d2e33559bd5..ece65061dea0 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -428,6 +428,18 @@ static inline size_t sme_state_size(struct task_struct const *task)
 	return __sme_state_size(task_get_sme_vl(task));
 }
 
+#define sme_cond_update_smcr(vl, fa64, zt0, reg)		\
+	do {							\
+		u64 __old = read_sysreg_s((reg));		\
+		u64 __new = vl;					\
+		if (fa64)			\
+			__new |= SMCR_ELx_FA64;			\
+		if (zt0)					\
+			__new |= SMCR_ELx_EZT0;			\
+		if (__old != __new)				\
+			write_sysreg_s(__new, (reg));		\
+	} while (0)
+
 #else
 
 static inline void sme_user_disable(void) { BUILD_BUG(); }
@@ -456,6 +468,8 @@ static inline size_t sme_state_size(struct task_struct const *task)
 	return 0;
 }
 
+#define sme_cond_update_smcr(val, fa64, zt0, reg) do { } while (0)
+
 #endif /* ! CONFIG_ARM64_SME */
 
 /* For use by EFI runtime services calls only */
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index c840a93b9ef9..ca9e66cc62d8 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -2965,7 +2965,6 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
 		.type = ARM64_CPUCAP_SYSTEM_FEATURE,
 		.capability = ARM64_SME_FA64,
 		.matches = has_cpuid_feature,
-		.cpu_enable = cpu_enable_fa64,
 		ARM64_CPUID_FIELDS(ID_AA64SMFR0_EL1, FA64, IMP)
 	},
 	{
@@ -2973,7 +2972,6 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
 		.type = ARM64_CPUCAP_SYSTEM_FEATURE,
 		.capability = ARM64_SME2,
 		.matches = has_cpuid_feature,
-		.cpu_enable = cpu_enable_sme2,
 		ARM64_CPUID_FIELDS(ID_AA64PFR1_EL1, SME, SME2)
 	},
 #endif /* CONFIG_ARM64_SME */
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index c154f72634e0..be4499ff6498 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -405,11 +405,15 @@ static void task_fpsimd_load(void)
 
 	/* Restore SME, override SVE register configuration if needed */
 	if (system_supports_sme()) {
-		unsigned long sme_vl = task_get_sme_vl(current);
-
-		/* Ensure VL is set up for restoring data */
+		/*
+		 * Ensure VL is set up for restoring data.  KVM might
+		 * disable subfeatures so we reset them each time.
+		 */
 		if (test_thread_flag(TIF_SME))
-			sme_set_vq(sve_vq_from_vl(sme_vl) - 1);
+			sme_cond_update_smcr(sve_vq_from_vl(task_get_sme_vl(current)) - 1,
+					     system_supports_fa64(),
+					     system_supports_sme2(),
+					     SYS_SMCR_EL1);
 
 		write_sysreg_s(current->thread.svcr, SYS_SVCR);
 
@@ -1250,26 +1254,6 @@ void cpu_enable_sme(const struct arm64_cpu_capabilities *__always_unused p)
 	isb();
 }
 
-void cpu_enable_sme2(const struct arm64_cpu_capabilities *__always_unused p)
-{
-	/* This must be enabled after SME */
-	BUILD_BUG_ON(ARM64_SME2 <= ARM64_SME);
-
-	/* Allow use of ZT0 */
-	write_sysreg_s(read_sysreg_s(SYS_SMCR_EL1) | SMCR_ELx_EZT0_MASK,
-		       SYS_SMCR_EL1);
-}
-
-void cpu_enable_fa64(const struct arm64_cpu_capabilities *__always_unused p)
-{
-	/* This must be enabled after SME */
-	BUILD_BUG_ON(ARM64_SME_FA64 <= ARM64_SME);
-
-	/* Allow use of FA64 */
-	write_sysreg_s(read_sysreg_s(SYS_SMCR_EL1) | SMCR_ELx_FA64_MASK,
-		       SYS_SMCR_EL1);
-}
-
 void __init sme_setup(void)
 {
 	struct vl_info *info = &vl_info[ARM64_VEC_SME];
@@ -1314,17 +1298,9 @@ void __init sme_setup(void)
 
 void sme_suspend_exit(void)
 {
-	u64 smcr = 0;
-
 	if (!system_supports_sme())
 		return;
 
-	if (system_supports_fa64())
-		smcr |= SMCR_ELx_FA64;
-	if (system_supports_sme2())
-		smcr |= SMCR_ELx_EZT0;
-
-	write_sysreg_s(smcr, SYS_SMCR_EL1);
 	write_sysreg_s(0, SYS_SMPRI_EL1);
 }
 
@@ -1439,9 +1415,10 @@ void do_sme_acc(unsigned long esr, struct pt_regs *regs)
 		WARN_ON(1);
 
 	if (!test_thread_flag(TIF_FOREIGN_FPSTATE)) {
-		unsigned long vq_minus_one =
-			sve_vq_from_vl(task_get_sme_vl(current)) - 1;
-		sme_set_vq(vq_minus_one);
+		sme_cond_update_smcr(sve_vq_from_vl(task_get_sme_vl(current)) - 1,
+				     system_supports_fa64(),
+				     system_supports_sme2(),
+				     SYS_SMCR_EL1);
 
 		fpsimd_bind_task_to_cpu();
 	} else {

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:20:57 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:20:57 +0000
Subject: [PATCH v9 03/30] arm64/fpsimd: Decide to save ZT0 and streaming
 mode FFR at bind time
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-3-8be3867cb883@kernel.org>

Some parts of the SME state are optional, enabled by additional features
on top of the base FEAT_SME and controlled with enable bits in SMCR_ELx. We
unconditionally enable these for the host but for KVM we will allow the
feature set exposed to guests to be restricted by the VMM. These are the
FFR register (FEAT_SME_FA64) and ZT0 (FEAT_SME2).

We defer saving of guest floating point state for non-protected guests to
the host kernel. We also want to avoid having to reconfigure the guest
floating point state if nothing used the floating point state while running
the host. If the guest was running with the optional features disabled then
traps will be enabled for them so the host kernel will need to skip
accessing that state when saving state for the guest.

Support this by moving the decision about saving this state to the point
where we bind floating point state to the CPU, adding a new variable to
the cpu_fp_state which uses the enable bits in SMCR_ELx to flag which
features are enabled.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 arch/arm64/include/asm/fpsimd.h |  1 +
 arch/arm64/kernel/fpsimd.c      | 10 ++++++++--
 arch/arm64/kvm/fpsimd.c         |  1 +
 3 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index ece65061dea0..146c1af55e22 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -87,6 +87,7 @@ struct cpu_fp_state {
 	void *sme_state;
 	u64 *svcr;
 	u64 *fpmr;
+	u64 sme_features;
 	unsigned int sve_vl;
 	unsigned int sme_vl;
 	enum fp_type *fp_type;
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index be4499ff6498..887fce177c92 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -490,12 +490,12 @@ static void fpsimd_save_user_state(void)
 
 		if (*svcr & SVCR_ZA_MASK)
 			sme_save_state(last->sme_state,
-				       system_supports_sme2());
+				       last->sme_features & SMCR_ELx_EZT0);
 
 		/* If we are in streaming mode override regular SVE. */
 		if (*svcr & SVCR_SM_MASK) {
 			save_sve_regs = true;
-			save_ffr = system_supports_fa64();
+			save_ffr = last->sme_features & SMCR_ELx_FA64;
 			vl = last->sme_vl;
 		}
 	}
@@ -1671,6 +1671,12 @@ static void fpsimd_bind_task_to_cpu(void)
 	last->to_save = FP_STATE_CURRENT;
 	current->thread.fpsimd_cpu = smp_processor_id();
 
+	last->sme_features = 0;
+	if (system_supports_fa64())
+		last->sme_features |= SMCR_ELx_FA64;
+	if (system_supports_sme2())
+		last->sme_features |= SMCR_ELx_EZT0;
+
 	/*
 	 * Toggle SVE and SME trapping for userspace if needed, these
 	 * are serialsied by ret_to_user().
diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c
index 15e17aca1dec..9158353d8be3 100644
--- a/arch/arm64/kvm/fpsimd.c
+++ b/arch/arm64/kvm/fpsimd.c
@@ -80,6 +80,7 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
 		fp_state.svcr = __ctxt_sys_reg(&vcpu->arch.ctxt, SVCR);
 		fp_state.fpmr = __ctxt_sys_reg(&vcpu->arch.ctxt, FPMR);
 		fp_state.fp_type = &vcpu->arch.fp_type;
+		fp_state.sme_features = 0;
 
 		if (vcpu_has_sve(vcpu))
 			fp_state.to_save = FP_STATE_SVE;

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:20:58 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:20:58 +0000
Subject: [PATCH v9 04/30] arm64/fpsimd: Check enable bit for FA64 when
 saving EFI state
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-4-8be3867cb883@kernel.org>

Currently when deciding if we need to save FFR when in streaming mode prior
to EFI calls we check if FA64 is supported by the system. Since KVM guest
support will mean that FA64 might be enabled and disabled at runtime switch
to checking if traps for FA64 are enabled in SMCR_EL1 instead.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 arch/arm64/kernel/fpsimd.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 887fce177c92..f4e8cee00198 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -1948,6 +1948,11 @@ static bool efi_sm_state;
  * either doing something wrong or you need to propose some refactoring.
  */
 
+static bool fa64_enabled(void)
+{
+	return read_sysreg_s(SYS_SMCR_EL1) & SMCR_ELx_FA64;
+}
+
 /*
  * __efi_fpsimd_begin(): prepare FPSIMD for making an EFI runtime services call
  */
@@ -1980,7 +1985,7 @@ void __efi_fpsimd_begin(void)
 				 * Unless we have FA64 FFR does not
 				 * exist in streaming mode.
 				 */
-				if (!system_supports_fa64())
+				if (!fa64_enabled())
 					ffr = !(svcr & SVCR_SM_MASK);
 			}
 
@@ -2028,7 +2033,7 @@ void __efi_fpsimd_end(void)
 					 * Unless we have FA64 FFR does not
 					 * exist in streaming mode.
 					 */
-					if (!system_supports_fa64())
+					if (!fa64_enabled())
 						ffr = false;
 				}
 			}

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:20:59 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:20:59 +0000
Subject: [PATCH v9 05/30] arm64/fpsimd: Determine maximum virtualisable SME
 vector length
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-5-8be3867cb883@kernel.org>

As with SVE we can only virtualise SME vector lengths that are supported by
all CPUs in the system, implement similar checks to those for SVE. Since
unlike SVE there are no specific vector lengths that are architecturally
required the handling is subtly different, we report a system where this
happens with a maximum vector length of -1.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 arch/arm64/kernel/fpsimd.c | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index f4e8cee00198..22f8397c67f0 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -1257,7 +1257,8 @@ void cpu_enable_sme(const struct arm64_cpu_capabilities *__always_unused p)
 void __init sme_setup(void)
 {
 	struct vl_info *info = &vl_info[ARM64_VEC_SME];
-	int min_bit, max_bit;
+	DECLARE_BITMAP(tmp_map, SVE_VQ_MAX);
+	int min_bit, max_bit, b;
 
 	if (!system_supports_sme())
 		return;
@@ -1288,12 +1289,32 @@ void __init sme_setup(void)
 	 */
 	set_sme_default_vl(find_supported_vector_length(ARM64_VEC_SME, 32));
 
+	bitmap_andnot(tmp_map, info->vq_partial_map, info->vq_map,
+		      SVE_VQ_MAX);
+
+	b = find_last_bit(tmp_map, SVE_VQ_MAX);
+	if (b >= SVE_VQ_MAX)
+		/* All VLs virtualisable */
+		info->max_virtualisable_vl = SVE_VQ_MAX;
+	else if (b == SVE_VQ_MAX - 1)
+		/* No virtualisable VLs */
+		info->max_virtualisable_vl = -1;
+	else
+		info->max_virtualisable_vl = sve_vl_from_vq(__bit_to_vq(b +  1));
+
+	if (info->max_virtualisable_vl > info->max_vl)
+		info->max_virtualisable_vl = info->max_vl;
+
 	pr_info("SME: minimum available vector length %u bytes per vector\n",
 		info->min_vl);
 	pr_info("SME: maximum available vector length %u bytes per vector\n",
 		info->max_vl);
 	pr_info("SME: default vector length %u bytes per vector\n",
 		get_sme_default_vl());
+
+	/* KVM decides whether to support mismatched systems. Just warn here: */
+	if (info->max_virtualisable_vl < info->max_vl)
+		pr_warn("SME: unvirtualisable vector lengths present\n");
 }
 
 void sme_suspend_exit(void)

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:21:00 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:21:00 +0000
Subject: [PATCH v9 06/30] KVM: arm64: Pay attention to FFR parameter in SVE
 save and load
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-6-8be3867cb883@kernel.org>

The hypervisor copies of the SVE save and load functions are prototyped
with third arguments specifying FFR should be accessed but the assembly
functions overwrite whatever is supplied to unconditionally access FFR.
Remove this and use the supplied parameter.

This has no effect currently since FFR is always present for SVE but will
be important for SME.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 arch/arm64/kvm/hyp/fpsimd.S | 2 --
 1 file changed, 2 deletions(-)

diff --git a/arch/arm64/kvm/hyp/fpsimd.S b/arch/arm64/kvm/hyp/fpsimd.S
index e950875e31ce..6e16cbfc5df2 100644
--- a/arch/arm64/kvm/hyp/fpsimd.S
+++ b/arch/arm64/kvm/hyp/fpsimd.S
@@ -21,13 +21,11 @@ SYM_FUNC_START(__fpsimd_restore_state)
 SYM_FUNC_END(__fpsimd_restore_state)
 
 SYM_FUNC_START(__sve_restore_state)
-	mov	x2, #1
 	sve_load 0, x1, x2, 3
 	ret
 SYM_FUNC_END(__sve_restore_state)
 
 SYM_FUNC_START(__sve_save_state)
-	mov	x2, #1
 	sve_save 0, x1, x2, 3
 	ret
 SYM_FUNC_END(__sve_save_state)

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:21:01 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:21:01 +0000
Subject: [PATCH v9 07/30] KVM: arm64: Pull ctxt_has_ helpers to start of
 sysreg-sr.h
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-7-8be3867cb883@kernel.org>

Rather than add earlier prototypes of specific ctxt_has_ helpers let's just
pull all their definitions to the top of sysreg-sr.h so they're all
available to all the individual save/restore functions.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h | 84 +++++++++++++++---------------
 1 file changed, 41 insertions(+), 43 deletions(-)

diff --git a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
index a17cbe7582de..5624fd705ae3 100644
--- a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
+++ b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
@@ -16,8 +16,6 @@
 #include <asm/kvm_hyp.h>
 #include <asm/kvm_mmu.h>
 
-static inline bool ctxt_has_s1poe(struct kvm_cpu_context *ctxt);
-
 static inline struct kvm_vcpu *ctxt_to_vcpu(struct kvm_cpu_context *ctxt)
 {
 	struct kvm_vcpu *vcpu = ctxt->__hyp_running_vcpu;
@@ -28,47 +26,6 @@ static inline struct kvm_vcpu *ctxt_to_vcpu(struct kvm_cpu_context *ctxt)
 	return vcpu;
 }
 
-static inline bool ctxt_is_guest(struct kvm_cpu_context *ctxt)
-{
-	return host_data_ptr(host_ctxt) != ctxt;
-}
-
-static inline u64 *ctxt_mdscr_el1(struct kvm_cpu_context *ctxt)
-{
-	struct kvm_vcpu *vcpu = ctxt_to_vcpu(ctxt);
-
-	if (ctxt_is_guest(ctxt) && kvm_host_owns_debug_regs(vcpu))
-		return &vcpu->arch.external_mdscr_el1;
-
-	return &ctxt_sys_reg(ctxt, MDSCR_EL1);
-}
-
-static inline u64 ctxt_midr_el1(struct kvm_cpu_context *ctxt)
-{
-	struct kvm *kvm = kern_hyp_va(ctxt_to_vcpu(ctxt)->kvm);
-
-	if (!(ctxt_is_guest(ctxt) &&
-	      test_bit(KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS, &kvm->arch.flags)))
-		return read_cpuid_id();
-
-	return kvm_read_vm_id_reg(kvm, SYS_MIDR_EL1);
-}
-
-static inline void __sysreg_save_common_state(struct kvm_cpu_context *ctxt)
-{
-	*ctxt_mdscr_el1(ctxt)	= read_sysreg(mdscr_el1);
-
-	// POR_EL0 can affect uaccess, so must be saved/restored early.
-	if (ctxt_has_s1poe(ctxt))
-		ctxt_sys_reg(ctxt, POR_EL0)	= read_sysreg_s(SYS_POR_EL0);
-}
-
-static inline void __sysreg_save_user_state(struct kvm_cpu_context *ctxt)
-{
-	ctxt_sys_reg(ctxt, TPIDR_EL0)	= read_sysreg(tpidr_el0);
-	ctxt_sys_reg(ctxt, TPIDRRO_EL0)	= read_sysreg(tpidrro_el0);
-}
-
 static inline bool ctxt_has_mte(struct kvm_cpu_context *ctxt)
 {
 	struct kvm_vcpu *vcpu = ctxt_to_vcpu(ctxt);
@@ -131,6 +88,47 @@ static inline bool ctxt_has_sctlr2(struct kvm_cpu_context *ctxt)
 	return kvm_has_sctlr2(kern_hyp_va(vcpu->kvm));
 }
 
+static inline bool ctxt_is_guest(struct kvm_cpu_context *ctxt)
+{
+	return host_data_ptr(host_ctxt) != ctxt;
+}
+
+static inline u64 *ctxt_mdscr_el1(struct kvm_cpu_context *ctxt)
+{
+	struct kvm_vcpu *vcpu = ctxt_to_vcpu(ctxt);
+
+	if (ctxt_is_guest(ctxt) && kvm_host_owns_debug_regs(vcpu))
+		return &vcpu->arch.external_mdscr_el1;
+
+	return &ctxt_sys_reg(ctxt, MDSCR_EL1);
+}
+
+static inline u64 ctxt_midr_el1(struct kvm_cpu_context *ctxt)
+{
+	struct kvm *kvm = kern_hyp_va(ctxt_to_vcpu(ctxt)->kvm);
+
+	if (!(ctxt_is_guest(ctxt) &&
+	      test_bit(KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS, &kvm->arch.flags)))
+		return read_cpuid_id();
+
+	return kvm_read_vm_id_reg(kvm, SYS_MIDR_EL1);
+}
+
+static inline void __sysreg_save_common_state(struct kvm_cpu_context *ctxt)
+{
+	*ctxt_mdscr_el1(ctxt)	= read_sysreg(mdscr_el1);
+
+	// POR_EL0 can affect uaccess, so must be saved/restored early.
+	if (ctxt_has_s1poe(ctxt))
+		ctxt_sys_reg(ctxt, POR_EL0)	= read_sysreg_s(SYS_POR_EL0);
+}
+
+static inline void __sysreg_save_user_state(struct kvm_cpu_context *ctxt)
+{
+	ctxt_sys_reg(ctxt, TPIDR_EL0)	= read_sysreg(tpidr_el0);
+	ctxt_sys_reg(ctxt, TPIDRRO_EL0)	= read_sysreg(tpidrro_el0);
+}
+
 static inline void __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
 {
 	ctxt_sys_reg(ctxt, SCTLR_EL1)	= read_sysreg_el1(SYS_SCTLR);

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:21:02 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:21:02 +0000
Subject: [PATCH v9 08/30] KVM: arm64: Move SVE state access macros after
 feature test macros
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-8-8be3867cb883@kernel.org>

In preparation for SME support move the macros used to access SVE state
after the feature test macros, we will need to test for SME subfeatures to
determine the size of the SME state.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 arch/arm64/include/asm/kvm_host.h | 50 +++++++++++++++++++--------------------
 1 file changed, 25 insertions(+), 25 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index ac7f970c7883..e6d25db10a6b 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -1048,31 +1048,6 @@ struct kvm_vcpu_arch {
 #define NESTED_SERROR_PENDING	__vcpu_single_flag(sflags, BIT(8))
 
 
-/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
-#define vcpu_sve_pffr(vcpu) (kern_hyp_va((vcpu)->arch.sve_state) +	\
-			     sve_ffr_offset((vcpu)->arch.sve_max_vl))
-
-#define vcpu_sve_max_vq(vcpu)	sve_vq_from_vl((vcpu)->arch.sve_max_vl)
-
-#define vcpu_sve_zcr_elx(vcpu)						\
-	(unlikely(is_hyp_ctxt(vcpu)) ? ZCR_EL2 : ZCR_EL1)
-
-#define sve_state_size_from_vl(sve_max_vl) ({				\
-	size_t __size_ret;						\
-	unsigned int __vq;						\
-									\
-	if (WARN_ON(!sve_vl_valid(sve_max_vl))) {			\
-		__size_ret = 0;						\
-	} else {							\
-		__vq = sve_vq_from_vl(sve_max_vl);			\
-		__size_ret = SVE_SIG_REGS_SIZE(__vq);			\
-	}								\
-									\
-	__size_ret;							\
-})
-
-#define vcpu_sve_state_size(vcpu) sve_state_size_from_vl((vcpu)->arch.sve_max_vl)
-
 #define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | \
 				 KVM_GUESTDBG_USE_SW_BP | \
 				 KVM_GUESTDBG_USE_HW | \
@@ -1108,6 +1083,31 @@ struct kvm_vcpu_arch {
 
 #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.regs)
 
+/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
+#define vcpu_sve_pffr(vcpu) (kern_hyp_va((vcpu)->arch.sve_state) +	\
+			     sve_ffr_offset((vcpu)->arch.sve_max_vl))
+
+#define vcpu_sve_max_vq(vcpu)	sve_vq_from_vl((vcpu)->arch.sve_max_vl)
+
+#define vcpu_sve_zcr_elx(vcpu)						\
+	(unlikely(is_hyp_ctxt(vcpu)) ? ZCR_EL2 : ZCR_EL1)
+
+#define sve_state_size_from_vl(sve_max_vl) ({				\
+	size_t __size_ret;						\
+	unsigned int __vq;						\
+									\
+	if (WARN_ON(!sve_vl_valid(sve_max_vl))) {			\
+		__size_ret = 0;						\
+	} else {							\
+		__vq = sve_vq_from_vl(sve_max_vl);			\
+		__size_ret = SVE_SIG_REGS_SIZE(__vq);			\
+	}								\
+									\
+	__size_ret;							\
+})
+
+#define vcpu_sve_state_size(vcpu) sve_state_size_from_vl((vcpu)->arch.sve_max_vl)
+
 /*
  * Only use __vcpu_sys_reg/ctxt_sys_reg if you know you want the
  * memory backed version of a register, and not the one most recently

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:21:03 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:21:03 +0000
Subject: [PATCH v9 09/30] KVM: arm64: Rename SVE finalization constants to
 be more general
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-9-8be3867cb883@kernel.org>

Due to the overlap between SVE and SME vector length configuration
created by streaming mode SVE we will finalize both at once.  Rename the
existing finalization to use _VEC (vector) for the naming to avoid
confusion.

Since this includes the userspace API we create an alias
KVM_ARM_VCPU_VEC for the existing KVM_ARM_VCPU_SVE capability, existing
code which does not enable SME will be unaffected and any SME only code
will not need to use SVE constants.

No functional change.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 arch/arm64/include/asm/kvm_host.h |  8 +++++---
 arch/arm64/include/uapi/asm/kvm.h |  6 ++++++
 arch/arm64/kvm/guest.c            | 10 +++++-----
 arch/arm64/kvm/hyp/nvhe/pkvm.c    |  2 +-
 arch/arm64/kvm/reset.c            | 20 ++++++++++----------
 5 files changed, 27 insertions(+), 19 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index e6d25db10a6b..0f3d26467bf0 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -988,8 +988,8 @@ struct kvm_vcpu_arch {
 
 /* KVM_ARM_VCPU_INIT completed */
 #define VCPU_INITIALIZED	__vcpu_single_flag(cflags, BIT(0))
-/* SVE config completed */
-#define VCPU_SVE_FINALIZED	__vcpu_single_flag(cflags, BIT(1))
+/* Vector config completed */
+#define VCPU_VEC_FINALIZED	__vcpu_single_flag(cflags, BIT(1))
 /* pKVM VCPU setup completed */
 #define VCPU_PKVM_FINALIZED	__vcpu_single_flag(cflags, BIT(2))
 
@@ -1062,6 +1062,8 @@ struct kvm_vcpu_arch {
 #define vcpu_has_sve(vcpu)	kvm_has_sve((vcpu)->kvm)
 #endif
 
+#define vcpu_has_vec(vcpu) vcpu_has_sve(vcpu)
+
 #ifdef CONFIG_ARM64_PTR_AUTH
 #define vcpu_has_ptrauth(vcpu)						\
 	((cpus_have_final_cap(ARM64_HAS_ADDRESS_AUTH) ||		\
@@ -1458,7 +1460,7 @@ struct kvm *kvm_arch_alloc_vm(void);
 int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int feature);
 bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu);
 
-#define kvm_arm_vcpu_sve_finalized(vcpu) vcpu_get_flag(vcpu, VCPU_SVE_FINALIZED)
+#define kvm_arm_vcpu_vec_finalized(vcpu) vcpu_get_flag(vcpu, VCPU_VEC_FINALIZED)
 
 #define kvm_has_mte(kvm)					\
 	(system_supports_mte() &&				\
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index a792a599b9d6..c67564f02981 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -107,6 +107,12 @@ struct kvm_regs {
 #define KVM_ARM_VCPU_HAS_EL2		7 /* Support nested virtualization */
 #define KVM_ARM_VCPU_HAS_EL2_E2H0	8 /* Limit NV support to E2H RES0 */
 
+/*
+ * An alias for _SVE since we finalize VL configuration for both SVE and SME
+ * simultaneously.
+ */
+#define KVM_ARM_VCPU_VEC		KVM_ARM_VCPU_SVE
+
 struct kvm_vcpu_init {
 	__u32 target;
 	__u32 features[7];
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 1c87699fd886..d15aa2da1891 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -342,7 +342,7 @@ static int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	if (!vcpu_has_sve(vcpu))
 		return -ENOENT;
 
-	if (kvm_arm_vcpu_sve_finalized(vcpu))
+	if (kvm_arm_vcpu_vec_finalized(vcpu))
 		return -EPERM; /* too late! */
 
 	if (WARN_ON(vcpu->arch.sve_state))
@@ -497,7 +497,7 @@ static int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	if (ret)
 		return ret;
 
-	if (!kvm_arm_vcpu_sve_finalized(vcpu))
+	if (!kvm_arm_vcpu_vec_finalized(vcpu))
 		return -EPERM;
 
 	if (copy_to_user(uptr, vcpu->arch.sve_state + region.koffset,
@@ -523,7 +523,7 @@ static int set_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	if (ret)
 		return ret;
 
-	if (!kvm_arm_vcpu_sve_finalized(vcpu))
+	if (!kvm_arm_vcpu_vec_finalized(vcpu))
 		return -EPERM;
 
 	if (copy_from_user(vcpu->arch.sve_state + region.koffset, uptr,
@@ -599,7 +599,7 @@ static unsigned long num_sve_regs(const struct kvm_vcpu *vcpu)
 		return 0;
 
 	/* Policed by KVM_GET_REG_LIST: */
-	WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu));
+	WARN_ON(!kvm_arm_vcpu_vec_finalized(vcpu));
 
 	return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */)
 		+ 1; /* KVM_REG_ARM64_SVE_VLS */
@@ -617,7 +617,7 @@ static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
 		return 0;
 
 	/* Policed by KVM_GET_REG_LIST: */
-	WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu));
+	WARN_ON(!kvm_arm_vcpu_vec_finalized(vcpu));
 
 	/*
 	 * Enumerate this first, so that userspace can save/restore in
diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index 8911338961c5..b402dcb7691e 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -445,7 +445,7 @@ static int pkvm_vcpu_init_sve(struct pkvm_hyp_vcpu *hyp_vcpu, struct kvm_vcpu *h
 	int ret = 0;
 
 	if (!vcpu_has_feature(vcpu, KVM_ARM_VCPU_SVE)) {
-		vcpu_clear_flag(vcpu, VCPU_SVE_FINALIZED);
+		vcpu_clear_flag(vcpu, VCPU_VEC_FINALIZED);
 		return 0;
 	}
 
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index 959532422d3a..f7c63e145d54 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -92,7 +92,7 @@ static void kvm_vcpu_enable_sve(struct kvm_vcpu *vcpu)
  * Finalize vcpu's maximum SVE vector length, allocating
  * vcpu->arch.sve_state as necessary.
  */
-static int kvm_vcpu_finalize_sve(struct kvm_vcpu *vcpu)
+static int kvm_vcpu_finalize_vec(struct kvm_vcpu *vcpu)
 {
 	void *buf;
 	unsigned int vl;
@@ -122,21 +122,21 @@ static int kvm_vcpu_finalize_sve(struct kvm_vcpu *vcpu)
 	}
 	
 	vcpu->arch.sve_state = buf;
-	vcpu_set_flag(vcpu, VCPU_SVE_FINALIZED);
+	vcpu_set_flag(vcpu, VCPU_VEC_FINALIZED);
 	return 0;
 }
 
 int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int feature)
 {
 	switch (feature) {
-	case KVM_ARM_VCPU_SVE:
-		if (!vcpu_has_sve(vcpu))
+	case KVM_ARM_VCPU_VEC:
+		if (!vcpu_has_vec(vcpu))
 			return -EINVAL;
 
-		if (kvm_arm_vcpu_sve_finalized(vcpu))
+		if (kvm_arm_vcpu_vec_finalized(vcpu))
 			return -EPERM;
 
-		return kvm_vcpu_finalize_sve(vcpu);
+		return kvm_vcpu_finalize_vec(vcpu);
 	}
 
 	return -EINVAL;
@@ -144,7 +144,7 @@ int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int feature)
 
 bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu)
 {
-	if (vcpu_has_sve(vcpu) && !kvm_arm_vcpu_sve_finalized(vcpu))
+	if (vcpu_has_vec(vcpu) && !kvm_arm_vcpu_vec_finalized(vcpu))
 		return false;
 
 	return true;
@@ -163,7 +163,7 @@ void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu)
 	kfree(vcpu->arch.ccsidr);
 }
 
-static void kvm_vcpu_reset_sve(struct kvm_vcpu *vcpu)
+static void kvm_vcpu_reset_vec(struct kvm_vcpu *vcpu)
 {
 	if (vcpu_has_sve(vcpu))
 		memset(vcpu->arch.sve_state, 0, vcpu_sve_state_size(vcpu));
@@ -203,11 +203,11 @@ void kvm_reset_vcpu(struct kvm_vcpu *vcpu)
 	if (loaded)
 		kvm_arch_vcpu_put(vcpu);
 
-	if (!kvm_arm_vcpu_sve_finalized(vcpu)) {
+	if (!kvm_arm_vcpu_vec_finalized(vcpu)) {
 		if (vcpu_has_feature(vcpu, KVM_ARM_VCPU_SVE))
 			kvm_vcpu_enable_sve(vcpu);
 	} else {
-		kvm_vcpu_reset_sve(vcpu);
+		kvm_vcpu_reset_vec(vcpu);
 	}
 
 	if (vcpu_el1_is_32bit(vcpu))

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:21:04 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:21:04 +0000
Subject: [PATCH v9 10/30] KVM: arm64: Document the KVM ABI for SME
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-10-8be3867cb883@kernel.org>

SME, the Scalable Matrix Extension, is an arm64 extension which adds
support for matrix operations, with core concepts patterned after SVE.

SVE introduced some complication in the ABI since it adds new vector
floating point registers with runtime configurable size, the size being
controlled by a parameter called the vector length (VL). To provide control
of this to VMMs we offer two phase configuration of SVE, SVE must first be
enabled for the vCPU with KVM_ARM_VCPU_INIT(KVM_ARM_VCPU_SVE), after which
vector length may then be configured but the configurably sized floating
point registers are inaccessible until finalized with a call to
KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE) after which the configurably sized
registers can be accessed.

SME introduces an additional independent configurable vector length
which as well as controlling the size of the new ZA register also
provides an alternative view of the configurably sized SVE registers
(known as streaming mode) with the guest able to switch between the two
modes as it pleases.  There is also a fixed sized register ZT0
introduced in SME2. As well as streaming mode the guest may enable and
disable ZA and (where SME2 is available) ZT0 dynamically independently
of streaming mode. These modes are controlled via the system register
SVCR.

We handle the configuration of the vector length for SME in a similar
manner to SVE, requiring initialization and finalization of the feature
with a pseudo register controlling the available SME vector lengths as for
SVE. Further, if the guest has both SVE and SME then finalizing one
prevents further configuration of the vector length for the other.

Where both SVE and SME are configured for the guest we always present
the SVE registers to userspace as having the larger of the configured
maximum SVE and SME vector lengths, discarding extra data at load time
and zero padding on read as required if the active vector length is
lower. Note that this means that enabling or disabling streaming mode
while the guest is stopped will not zero Zn or Pn as it will when the
guest is running, but it does allow SVCR, Zn and Pn to be read and
written in any order.

Userspace access to ZA and (if configured) ZT0 is always available, they
will be zeroed when the guest runs if disabled in SVCR and the value
read will be zero if the guest stops with them disabled. This mirrors
the behaviour of the architecture, enabling access causes ZA and ZT0 to
be zeroed, while allowing access to SVCR, ZA and ZT0 to be performed in
any order.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 Documentation/virt/kvm/api.rst | 120 +++++++++++++++++++++++++++++------------
 1 file changed, 86 insertions(+), 34 deletions(-)

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 01a3abef8abb..e024b9783932 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -406,7 +406,7 @@ Errors:
              instructions from device memory (arm64)
   ENOSYS     data abort outside memslots with no syndrome info and
              KVM_CAP_ARM_NISV_TO_USER not enabled (arm64)
-  EPERM      SVE feature set but not finalized (arm64)
+  EPERM      SVE or SME feature set but not finalized (arm64)
   =======    ==============================================================
 
 This ioctl is used to run a guest virtual cpu.  While there are no
@@ -2606,11 +2606,11 @@ Specifically:
 ======================= ========= ===== =======================================
 
 .. [1] These encodings are not accepted for SVE-enabled vcpus.  See
-       :ref:`KVM_ARM_VCPU_INIT`.
+       :ref:`KVM_ARM_VCPU_INIT`.  They are also not accepted when SME is
+       enabled without SVE and the vcpu is in streaming mode.
 
        The equivalent register content can be accessed via bits [127:0] of
-       the corresponding SVE Zn registers instead for vcpus that have SVE
-       enabled (see below).
+       the corresponding SVE Zn registers in these cases (see below).
 
 arm64 CCSIDR registers are demultiplexed by CSSELR value::
 
@@ -2641,24 +2641,39 @@ arm64 SVE registers have the following bit patterns::
   0x6050 0000 0015 060 <slice:5>        FFR bits[256*slice + 255 : 256*slice]
   0x6060 0000 0015 ffff                 KVM_REG_ARM64_SVE_VLS pseudo-register
 
-Access to register IDs where 2048 * slice >= 128 * max_vq will fail with
-ENOENT.  max_vq is the vcpu's maximum supported vector length in 128-bit
-quadwords: see [2]_ below.
+arm64 SME registers have the following bit patterns:
+
+  0x6080 0000 0017 00 <n:5> <slice:5>   ZA.H[n] bits[2048*slice + 2047 : 2048*slice]
+  0x6060 0000 0017 0100                 ZT0
+  0x6060 0000 0017 fffe                 KVM_REG_ARM64_SME_VLS pseudo-register
+
+Access to Z, P, FFR or ZA register IDs where 2048 * slice >= 128 *
+max_vq will fail with ENOENT.  max_vq is the vcpu's current maximum
+supported vector length in 128-bit quadwords: see [2]_ below.
+
+Changing the value of SVCR.SM will result in the contents of
+the Z, P and FFR registers being reset to 0.  When restoring the
+values of these registers for a VM with SME support it is
+important that SVCR.SM be configured first.
+
+Access to the ZA and ZT0 registers is only available if SVCR.ZA is set
+to 1.
 
 These registers are only accessible on vcpus for which SVE is enabled.
 See KVM_ARM_VCPU_INIT for details.
 
-In addition, except for KVM_REG_ARM64_SVE_VLS, these registers are not
-accessible until the vcpu's SVE configuration has been finalized
-using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).  See KVM_ARM_VCPU_INIT
-and KVM_ARM_VCPU_FINALIZE for more information about this procedure.
+In addition, except for KVM_REG_ARM64_SVE_VLS and
+KVM_REG_ARM64_SME_VLS, these registers are not accessible until the
+vcpu's SVE and SME configuration has been finalized using
+KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_VEC).  See KVM_ARM_VCPU_INIT and
+KVM_ARM_VCPU_FINALIZE for more information about this procedure.
 
-KVM_REG_ARM64_SVE_VLS is a pseudo-register that allows the set of vector
-lengths supported by the vcpu to be discovered and configured by
-userspace.  When transferred to or from user memory via KVM_GET_ONE_REG
-or KVM_SET_ONE_REG, the value of this register is of type
-__u64[KVM_ARM64_SVE_VLS_WORDS], and encodes the set of vector lengths as
-follows::
+KVM_REG_ARM64_SVE_VLS and KVM_ARM64_VCPU_SME_VLS are pseudo-registers
+that allows the set of vector lengths supported by the vcpu to be
+discovered and configured by userspace.  When transferred to or from
+user memory via KVM_GET_ONE_REG or KVM_SET_ONE_REG, the value of this
+register is of type __u64[KVM_ARM64_SVE_VLS_WORDS], and encodes the
+set of vector lengths as follows::
 
   __u64 vector_lengths[KVM_ARM64_SVE_VLS_WORDS];
 
@@ -2670,19 +2685,25 @@ follows::
 	/* Vector length vq * 16 bytes not supported */
 
 .. [2] The maximum value vq for which the above condition is true is
-       max_vq.  This is the maximum vector length available to the guest on
-       this vcpu, and determines which register slices are visible through
-       this ioctl interface.
+       max_vq.  This is the maximum vector length currently available to
+       the guest on this vcpu, and determines which register slices are
+       visible through this ioctl interface.
+
+       If SME is supported then the max_vq used for the Z and P registers
+       while SVCR.SM is 1 this vector length will be the maximum SME
+       vector length max_vq_sme available for the guest, otherwise it
+       will be the maximum SVE vector length max_vq_sve available.
 
 (See Documentation/arch/arm64/sve.rst for an explanation of the "vq"
 nomenclature.)
 
-KVM_REG_ARM64_SVE_VLS is only accessible after KVM_ARM_VCPU_INIT.
-KVM_ARM_VCPU_INIT initialises it to the best set of vector lengths that
-the host supports.
+KVM_REG_ARM64_SVE_VLS and KVM_REG_ARM_SME_VLS are only accessible
+after KVM_ARM_VCPU_INIT.  KVM_ARM_VCPU_INIT initialises them to the
+best set of vector lengths that the host supports.
 
-Userspace may subsequently modify it if desired until the vcpu's SVE
-configuration is finalized using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).
+Userspace may subsequently modify these registers if desired until the
+vcpu's SVE and SME configuration is finalized using
+KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_VEC).
 
 Apart from simply removing all vector lengths from the host set that
 exceed some value, support for arbitrarily chosen sets of vector lengths
@@ -2690,8 +2711,8 @@ is hardware-dependent and may not be available.  Attempting to configure
 an invalid set of vector lengths via KVM_SET_ONE_REG will fail with
 EINVAL.
 
-After the vcpu's SVE configuration is finalized, further attempts to
-write this register will fail with EPERM.
+After the vcpu's SVE or SME configuration is finalized, further
+attempts to write these registers will fail with EPERM.
 
 arm64 bitmap feature firmware pseudo-registers have the following bit pattern::
 
@@ -3490,6 +3511,7 @@ The initial values are defined as:
 	- General Purpose registers, including PC and SP: set to 0
 	- FPSIMD/NEON registers: set to 0
 	- SVE registers: set to 0
+	- SME registers: set to 0
 	- System registers: Reset to their architecturally defined
 	  values as for a warm reset to EL1 (resp. SVC) or EL2 (in the
 	  case of EL2 being enabled).
@@ -3533,7 +3555,7 @@ Possible features:
 
 	- KVM_ARM_VCPU_SVE: Enables SVE for the CPU (arm64 only).
 	  Depends on KVM_CAP_ARM_SVE.
-	  Requires KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
+	  Requires KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_VEC):
 
 	   * After KVM_ARM_VCPU_INIT:
 
@@ -3541,7 +3563,7 @@ Possible features:
 	        initial value of this pseudo-register indicates the best set of
 	        vector lengths possible for a vcpu on this host.
 
-	   * Before KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
+	   * Before KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_VEC):
 
 	      - KVM_RUN and KVM_GET_REG_LIST are not available;
 
@@ -3554,11 +3576,40 @@ Possible features:
 	        KVM_SET_ONE_REG, to modify the set of vector lengths available
 	        for the vcpu.
 
-	   * After KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
+	   * After KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_VEC):
 
 	      - the KVM_REG_ARM64_SVE_VLS pseudo-register is immutable, and can
 	        no longer be written using KVM_SET_ONE_REG.
 
+	- KVM_ARM_VCPU_SME: Enables SME for the CPU (arm64 only).
+	  Depends on KVM_CAP_ARM_SME.
+	  Requires KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_VEC):
+
+	   * After KVM_ARM_VCPU_INIT:
+
+	      - KVM_REG_ARM64_SME_VLS may be read using KVM_GET_ONE_REG: the
+	        initial value of this pseudo-register indicates the best set of
+	        vector lengths possible for a vcpu on this host.
+
+	   * Before KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_VEC):
+
+	      - KVM_RUN and KVM_GET_REG_LIST are not available;
+
+	      - KVM_GET_ONE_REG and KVM_SET_ONE_REG cannot be used to access
+	        the scalable architectural SVE registers
+	        KVM_REG_ARM64_SVE_ZREG(), KVM_REG_ARM64_SVE_PREG() or
+	        KVM_REG_ARM64_SVE_FFR, the matrix register
+		KVM_REG_ARM64_SME_ZA() or the LUT register KVM_REG_ARM64_ZT();
+
+	      - KVM_REG_ARM64_SME_VLS may optionally be written using
+	        KVM_SET_ONE_REG, to modify the set of vector lengths available
+	        for the vcpu.
+
+	   * After KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_VEC):
+
+	      - the KVM_REG_ARM64_SME_VLS pseudo-register is immutable, and can
+	        no longer be written using KVM_SET_ONE_REG.
+
 	- KVM_ARM_VCPU_HAS_EL2: Enable Nested Virtualisation support,
 	  booting the guest from EL2 instead of EL1.
 	  Depends on KVM_CAP_ARM_EL2.
@@ -5143,11 +5194,12 @@ Errors:
 
 Recognised values for feature:
 
-  =====      ===========================================
-  arm64      KVM_ARM_VCPU_SVE (requires KVM_CAP_ARM_SVE)
-  =====      ===========================================
+  =====      ==============================================================
+  arm64      KVM_ARM_VCPU_VEC (requires KVM_CAP_ARM_SVE or KVM_CAP_ARM_SME)
+  arm64      KVM_ARM_VCPU_SVE (alias for KVM_ARM_VCPU_VEC)
+  =====      ==============================================================
 
-Finalizes the configuration of the specified vcpu feature.
+Finalizes the configuration of the specified vcpu features.
 
 The vcpu must already have been initialised, enabling the affected feature, by
 means of a successful :ref:`KVM_ARM_VCPU_INIT <KVM_ARM_VCPU_INIT>` call with the

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:21:05 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:21:05 +0000
Subject: [PATCH v9 11/30] KVM: arm64: Define internal features for SME
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-11-8be3867cb883@kernel.org>

In order to simplify interdependencies in the rest of the series define
the feature detection for SME and it's subfeatures.  Due to the need for
vector length configuration we define a flag for SME like for SVE.  We
also have two subfeatures which add architectural state, FA64 and SME2,
which are configured via the normal ID register scheme.

Also provide helpers which check if the vCPU is in streaming mode or has
ZA enabled.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 arch/arm64/include/asm/kvm_host.h | 35 ++++++++++++++++++++++++++++++++++-
 arch/arm64/kvm/sys_regs.c         |  2 +-
 2 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 0f3d26467bf0..0816180dc551 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -353,6 +353,8 @@ struct kvm_arch {
 #define KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS		10
 	/* Unhandled SEAs are taken to userspace */
 #define KVM_ARCH_FLAG_EXIT_SEA				11
+	/* SME exposed to guest */
+#define KVM_ARCH_FLAG_GUEST_HAS_SME			12
 	unsigned long flags;
 
 	/* VM-wide vCPU feature set */
@@ -1062,7 +1064,16 @@ struct kvm_vcpu_arch {
 #define vcpu_has_sve(vcpu)	kvm_has_sve((vcpu)->kvm)
 #endif
 
-#define vcpu_has_vec(vcpu) vcpu_has_sve(vcpu)
+#define kvm_has_sme(kvm)	(system_supports_sme() &&		\
+				 test_bit(KVM_ARCH_FLAG_GUEST_HAS_SME, &(kvm)->arch.flags))
+
+#ifdef __KVM_NVHE_HYPERVISOR__
+#define vcpu_has_sme(vcpu)	kvm_has_sme(kern_hyp_va((vcpu)->kvm))
+#else
+#define vcpu_has_sme(vcpu)	kvm_has_sme((vcpu)->kvm)
+#endif
+
+#define vcpu_has_vec(vcpu) (vcpu_has_sve(vcpu) || vcpu_has_sme(vcpu))
 
 #ifdef CONFIG_ARM64_PTR_AUTH
 #define vcpu_has_ptrauth(vcpu)						\
@@ -1602,6 +1613,28 @@ void kvm_set_vm_id_reg(struct kvm *kvm, u32 reg, u64 val);
 #define kvm_has_sctlr2(k)				\
 	(kvm_has_feat((k), ID_AA64MMFR3_EL1, SCTLRX, IMP))
 
+#define kvm_has_fa64(k)					\
+	(system_supports_fa64() &&			\
+	 kvm_has_feat((k), ID_AA64SMFR0_EL1, FA64, IMP))
+
+#define kvm_has_sme2(k)					\
+	(system_supports_sme2() &&			\
+	 kvm_has_feat((k), ID_AA64PFR1_EL1, SME, SME2))
+
+#ifdef __KVM_NVHE_HYPERVISOR__
+#define vcpu_has_sme2(vcpu)	kvm_has_sme2(kern_hyp_va((vcpu)->kvm))
+#define vcpu_has_fa64(vcpu)	kvm_has_fa64(kern_hyp_va((vcpu)->kvm))
+#else
+#define vcpu_has_sme2(vcpu)	kvm_has_sme2((vcpu)->kvm)
+#define vcpu_has_fa64(vcpu)	kvm_has_fa64((vcpu)->kvm)
+#endif
+
+#define vcpu_in_streaming_mode(vcpu) \
+	(__vcpu_sys_reg(vcpu, SVCR) & SVCR_SM_MASK)
+
+#define vcpu_za_enabled(vcpu) \
+	(__vcpu_sys_reg(vcpu, SVCR) & SVCR_ZA_MASK)
+
 static inline bool kvm_arch_has_irq_bypass(void)
 {
 	return true;
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index c8fd7c6a12a1..3576e69468db 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1945,7 +1945,7 @@ static unsigned int sve_visibility(const struct kvm_vcpu *vcpu,
 static unsigned int sme_visibility(const struct kvm_vcpu *vcpu,
 				   const struct sys_reg_desc *rd)
 {
-	if (kvm_has_feat(vcpu->kvm, ID_AA64PFR1_EL1, SME, IMP))
+	if (vcpu_has_sme(vcpu))
 		return 0;
 
 	return REG_HIDDEN;

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:21:06 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:21:06 +0000
Subject: [PATCH v9 12/30] KVM: arm64: Rename sve_state_reg_region
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-12-8be3867cb883@kernel.org>

As for SVE we will need to pull parts of dynamically sized registers out of
a block of memory for SME so we will use a similar code pattern for this.
Rename the current struct sve_state_reg_region in preparation for this.

No functional change.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 arch/arm64/kvm/guest.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index d15aa2da1891..8c3405b5d7b1 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -404,9 +404,9 @@ static int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
  */
 #define vcpu_sve_slices(vcpu) 1
 
-/* Bounds of a single SVE register slice within vcpu->arch.sve_state */
-struct sve_state_reg_region {
-	unsigned int koffset;	/* offset into sve_state in kernel memory */
+/* Bounds of a single register slice within vcpu->arch.s[mv]e_state */
+struct vec_state_reg_region {
+	unsigned int koffset;	/* offset into s[mv]e_state in kernel memory */
 	unsigned int klen;	/* length in kernel memory */
 	unsigned int upad;	/* extra trailing padding in user memory */
 };
@@ -415,7 +415,7 @@ struct sve_state_reg_region {
  * Validate SVE register ID and get sanitised bounds for user/kernel SVE
  * register copy
  */
-static int sve_reg_to_region(struct sve_state_reg_region *region,
+static int sve_reg_to_region(struct vec_state_reg_region *region,
 			     struct kvm_vcpu *vcpu,
 			     const struct kvm_one_reg *reg)
 {
@@ -485,7 +485,7 @@ static int sve_reg_to_region(struct sve_state_reg_region *region,
 static int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 {
 	int ret;
-	struct sve_state_reg_region region;
+	struct vec_state_reg_region region;
 	char __user *uptr = (char __user *)reg->addr;
 
 	/* Handle the KVM_REG_ARM64_SVE_VLS pseudo-reg as a special case: */
@@ -511,7 +511,7 @@ static int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 static int set_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 {
 	int ret;
-	struct sve_state_reg_region region;
+	struct vec_state_reg_region region;
 	const char __user *uptr = (const char __user *)reg->addr;
 
 	/* Handle the KVM_REG_ARM64_SVE_VLS pseudo-reg as a special case: */

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:21:07 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:21:07 +0000
Subject: [PATCH v9 13/30] KVM: arm64: Store vector lengths in an array
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-13-8be3867cb883@kernel.org>

SME adds a second vector length configured in a very similar way to the
SVE vector length, in order to facilitate future code sharing for SME
refactor our storage of vector lengths to use an array like the host does.
We do not yet take much advantage of this so the intermediate code is not
as clean as might be.

No functional change.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 arch/arm64/include/asm/kvm_host.h       | 17 +++++++++++------
 arch/arm64/include/asm/kvm_hyp.h        |  2 +-
 arch/arm64/include/asm/kvm_pkvm.h       |  2 +-
 arch/arm64/kvm/fpsimd.c                 |  2 +-
 arch/arm64/kvm/guest.c                  |  6 +++---
 arch/arm64/kvm/hyp/include/hyp/switch.h |  6 +++---
 arch/arm64/kvm/hyp/nvhe/hyp-main.c      |  6 +++---
 arch/arm64/kvm/hyp/nvhe/pkvm.c          |  7 ++++---
 arch/arm64/kvm/reset.c                  | 22 +++++++++++-----------
 9 files changed, 38 insertions(+), 32 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 0816180dc551..3a3330b2a6a9 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -77,8 +77,10 @@ enum kvm_mode kvm_get_mode(void);
 static inline enum kvm_mode kvm_get_mode(void) { return KVM_MODE_NONE; };
 #endif
 
-extern unsigned int __ro_after_init kvm_sve_max_vl;
-extern unsigned int __ro_after_init kvm_host_sve_max_vl;
+extern unsigned int __ro_after_init kvm_max_vl[ARM64_VEC_MAX];
+extern unsigned int __ro_after_init kvm_host_max_vl[ARM64_VEC_MAX];
+DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
+
 int __init kvm_arm_init_sve(void);
 
 u32 __attribute_const__ kvm_target_cpu(void);
@@ -811,7 +813,7 @@ struct kvm_vcpu_arch {
 	 */
 	void *sve_state;
 	enum fp_type fp_type;
-	unsigned int sve_max_vl;
+	unsigned int max_vl[ARM64_VEC_MAX];
 
 	/* Stage 2 paging state used by the hardware on next switch */
 	struct kvm_s2_mmu *hw_mmu;
@@ -1098,9 +1100,12 @@ struct kvm_vcpu_arch {
 
 /* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
 #define vcpu_sve_pffr(vcpu) (kern_hyp_va((vcpu)->arch.sve_state) +	\
-			     sve_ffr_offset((vcpu)->arch.sve_max_vl))
+			     sve_ffr_offset((vcpu)->arch.max_vl[ARM64_VEC_SVE]))
+
+#define vcpu_vec_max_vq(vcpu, type) sve_vq_from_vl((vcpu)->arch.max_vl[type])
+
+#define vcpu_sve_max_vq(vcpu)	vcpu_vec_max_vq(vcpu, ARM64_VEC_SVE)
 
-#define vcpu_sve_max_vq(vcpu)	sve_vq_from_vl((vcpu)->arch.sve_max_vl)
 
 #define vcpu_sve_zcr_elx(vcpu)						\
 	(unlikely(is_hyp_ctxt(vcpu)) ? ZCR_EL2 : ZCR_EL1)
@@ -1119,7 +1124,7 @@ struct kvm_vcpu_arch {
 	__size_ret;							\
 })
 
-#define vcpu_sve_state_size(vcpu) sve_state_size_from_vl((vcpu)->arch.sve_max_vl)
+#define vcpu_sve_state_size(vcpu) sve_state_size_from_vl((vcpu)->arch.max_vl[ARM64_VEC_SVE])
 
 /*
  * Only use __vcpu_sys_reg/ctxt_sys_reg if you know you want the
diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index 76ce2b94bd97..0317790dd3b7 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -146,6 +146,6 @@ extern u64 kvm_nvhe_sym(id_aa64smfr0_el1_sys_val);
 
 extern unsigned long kvm_nvhe_sym(__icache_flags);
 extern unsigned int kvm_nvhe_sym(kvm_arm_vmid_bits);
-extern unsigned int kvm_nvhe_sym(kvm_host_sve_max_vl);
+extern unsigned int kvm_nvhe_sym(kvm_host_max_vl[ARM64_VEC_MAX]);
 
 #endif /* __ARM64_KVM_HYP_H__ */
diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm_pkvm.h
index 0aecd4ac5f45..0697c88f2210 100644
--- a/arch/arm64/include/asm/kvm_pkvm.h
+++ b/arch/arm64/include/asm/kvm_pkvm.h
@@ -167,7 +167,7 @@ static inline size_t pkvm_host_sve_state_size(void)
 		return 0;
 
 	return size_add(sizeof(struct cpu_sve_state),
-			SVE_SIG_REGS_SIZE(sve_vq_from_vl(kvm_host_sve_max_vl)));
+			SVE_SIG_REGS_SIZE(sve_vq_from_vl(kvm_host_max_vl[ARM64_VEC_SVE])));
 }
 
 struct pkvm_mapping {
diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c
index 9158353d8be3..1f4fcc8b5554 100644
--- a/arch/arm64/kvm/fpsimd.c
+++ b/arch/arm64/kvm/fpsimd.c
@@ -75,7 +75,7 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
 		 */
 		fp_state.st = &vcpu->arch.ctxt.fp_regs;
 		fp_state.sve_state = vcpu->arch.sve_state;
-		fp_state.sve_vl = vcpu->arch.sve_max_vl;
+		fp_state.sve_vl = vcpu->arch.max_vl[ARM64_VEC_SVE];
 		fp_state.sme_state = NULL;
 		fp_state.svcr = __ctxt_sys_reg(&vcpu->arch.ctxt, SVCR);
 		fp_state.fpmr = __ctxt_sys_reg(&vcpu->arch.ctxt, FPMR);
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 8c3405b5d7b1..456ef61b6ed5 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -318,7 +318,7 @@ static int get_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	if (!vcpu_has_sve(vcpu))
 		return -ENOENT;
 
-	if (WARN_ON(!sve_vl_valid(vcpu->arch.sve_max_vl)))
+	if (WARN_ON(!sve_vl_valid(vcpu->arch.max_vl[ARM64_VEC_SVE])))
 		return -EINVAL;
 
 	memset(vqs, 0, sizeof(vqs));
@@ -356,7 +356,7 @@ static int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 		if (vq_present(vqs, vq))
 			max_vq = vq;
 
-	if (max_vq > sve_vq_from_vl(kvm_sve_max_vl))
+	if (max_vq > sve_vq_from_vl(kvm_max_vl[ARM64_VEC_SVE]))
 		return -EINVAL;
 
 	/*
@@ -375,7 +375,7 @@ static int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 		return -EINVAL;
 
 	/* vcpu->arch.sve_state will be alloc'd by kvm_vcpu_finalize_sve() */
-	vcpu->arch.sve_max_vl = sve_vl_from_vq(max_vq);
+	vcpu->arch.max_vl[ARM64_VEC_SVE] = sve_vl_from_vq(max_vq);
 
 	return 0;
 }
diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index c5d5e5b86eaf..9ce53524d664 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -458,8 +458,8 @@ static inline void __hyp_sve_save_host(void)
 	struct cpu_sve_state *sve_state = *host_data_ptr(sve_state);
 
 	sve_state->zcr_el1 = read_sysreg_el1(SYS_ZCR);
-	write_sysreg_s(sve_vq_from_vl(kvm_host_sve_max_vl) - 1, SYS_ZCR_EL2);
-	__sve_save_state(sve_state->sve_regs + sve_ffr_offset(kvm_host_sve_max_vl),
+	write_sysreg_s(sve_vq_from_vl(kvm_host_max_vl[ARM64_VEC_SVE]) - 1, SYS_ZCR_EL2);
+	__sve_save_state(sve_state->sve_regs + sve_ffr_offset(kvm_host_max_vl[ARM64_VEC_SVE]),
 			 &sve_state->fpsr,
 			 true);
 }
@@ -514,7 +514,7 @@ static inline void fpsimd_lazy_switch_to_host(struct kvm_vcpu *vcpu)
 			zcr_el2 = vcpu_sve_max_vq(vcpu) - 1;
 			write_sysreg_el2(zcr_el2, SYS_ZCR);
 		} else {
-			zcr_el2 = sve_vq_from_vl(kvm_host_sve_max_vl) - 1;
+			zcr_el2 = sve_vq_from_vl(kvm_host_max_vl[ARM64_VEC_SVE]) - 1;
 			write_sysreg_el2(zcr_el2, SYS_ZCR);
 
 			zcr_el1 = vcpu_sve_max_vq(vcpu) - 1;
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index a7c689152f68..208e9042aca4 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -34,7 +34,7 @@ static void __hyp_sve_save_guest(struct kvm_vcpu *vcpu)
 	 */
 	sve_cond_update_zcr_vq(vcpu_sve_max_vq(vcpu) - 1, SYS_ZCR_EL2);
 	__sve_save_state(vcpu_sve_pffr(vcpu), &vcpu->arch.ctxt.fp_regs.fpsr, true);
-	write_sysreg_s(sve_vq_from_vl(kvm_host_sve_max_vl) - 1, SYS_ZCR_EL2);
+	write_sysreg_s(sve_vq_from_vl(kvm_host_max_vl[ARM64_VEC_SVE]) - 1, SYS_ZCR_EL2);
 }
 
 static void __hyp_sve_restore_host(void)
@@ -50,8 +50,8 @@ static void __hyp_sve_restore_host(void)
 	 * that was discovered, if we wish to use larger VLs this will
 	 * need to be revisited.
 	 */
-	write_sysreg_s(sve_vq_from_vl(kvm_host_sve_max_vl) - 1, SYS_ZCR_EL2);
-	__sve_restore_state(sve_state->sve_regs + sve_ffr_offset(kvm_host_sve_max_vl),
+	write_sysreg_s(sve_vq_from_vl(kvm_host_max_vl[ARM64_VEC_SVE]) - 1, SYS_ZCR_EL2);
+	__sve_restore_state(sve_state->sve_regs + sve_ffr_offset(kvm_host_max_vl[ARM64_VEC_SVE]),
 			    &sve_state->fpsr,
 			    true);
 	write_sysreg_el1(sve_state->zcr_el1, SYS_ZCR);
diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index b402dcb7691e..f4ec6695a6a5 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -20,7 +20,7 @@ unsigned long __icache_flags;
 /* Used by kvm_get_vttbr(). */
 unsigned int kvm_arm_vmid_bits;
 
-unsigned int kvm_host_sve_max_vl;
+unsigned int kvm_host_max_vl[ARM64_VEC_MAX];
 
 /*
  * The currently loaded hyp vCPU for each physical CPU. Used in protected mode
@@ -450,7 +450,8 @@ static int pkvm_vcpu_init_sve(struct pkvm_hyp_vcpu *hyp_vcpu, struct kvm_vcpu *h
 	}
 
 	/* Limit guest vector length to the maximum supported by the host. */
-	sve_max_vl = min(READ_ONCE(host_vcpu->arch.sve_max_vl), kvm_host_sve_max_vl);
+	sve_max_vl = min(READ_ONCE(host_vcpu->arch.max_vl[ARM64_VEC_SVE]),
+			 kvm_host_max_vl[ARM64_VEC_SVE]);
 	sve_state_size = sve_state_size_from_vl(sve_max_vl);
 	sve_state = kern_hyp_va(READ_ONCE(host_vcpu->arch.sve_state));
 
@@ -464,7 +465,7 @@ static int pkvm_vcpu_init_sve(struct pkvm_hyp_vcpu *hyp_vcpu, struct kvm_vcpu *h
 		goto err;
 
 	vcpu->arch.sve_state = sve_state;
-	vcpu->arch.sve_max_vl = sve_max_vl;
+	vcpu->arch.max_vl[ARM64_VEC_SVE] = sve_max_vl;
 
 	return 0;
 err:
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index f7c63e145d54..a8684a1346ec 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -32,7 +32,7 @@
 
 /* Maximum phys_shift supported for any VM on this host */
 static u32 __ro_after_init kvm_ipa_limit;
-unsigned int __ro_after_init kvm_host_sve_max_vl;
+unsigned int __ro_after_init kvm_host_max_vl[ARM64_VEC_MAX];
 
 /*
  * ARMv8 Reset Values
@@ -46,14 +46,14 @@ unsigned int __ro_after_init kvm_host_sve_max_vl;
 #define VCPU_RESET_PSTATE_SVC	(PSR_AA32_MODE_SVC | PSR_AA32_A_BIT | \
 				 PSR_AA32_I_BIT | PSR_AA32_F_BIT)
 
-unsigned int __ro_after_init kvm_sve_max_vl;
+unsigned int __ro_after_init kvm_max_vl[ARM64_VEC_MAX];
 
 int __init kvm_arm_init_sve(void)
 {
 	if (system_supports_sve()) {
-		kvm_sve_max_vl = sve_max_virtualisable_vl();
-		kvm_host_sve_max_vl = sve_max_vl();
-		kvm_nvhe_sym(kvm_host_sve_max_vl) = kvm_host_sve_max_vl;
+		kvm_max_vl[ARM64_VEC_SVE] = sve_max_virtualisable_vl();
+		kvm_host_max_vl[ARM64_VEC_SVE] = sve_max_vl();
+		kvm_nvhe_sym(kvm_host_max_vl[ARM64_VEC_SVE]) = kvm_host_max_vl[ARM64_VEC_SVE];
 
 		/*
 		 * The get_sve_reg()/set_sve_reg() ioctl interface will need
@@ -61,16 +61,16 @@ int __init kvm_arm_init_sve(void)
 		 * order to support vector lengths greater than
 		 * VL_ARCH_MAX:
 		 */
-		if (WARN_ON(kvm_sve_max_vl > VL_ARCH_MAX))
-			kvm_sve_max_vl = VL_ARCH_MAX;
+		if (WARN_ON(kvm_max_vl[ARM64_VEC_SVE] > VL_ARCH_MAX))
+			kvm_max_vl[ARM64_VEC_SVE] = VL_ARCH_MAX;
 
 		/*
 		 * Don't even try to make use of vector lengths that
 		 * aren't available on all CPUs, for now:
 		 */
-		if (kvm_sve_max_vl < sve_max_vl())
+		if (kvm_max_vl[ARM64_VEC_SVE] < sve_max_vl())
 			pr_warn("KVM: SVE vector length for guests limited to %u bytes\n",
-				kvm_sve_max_vl);
+				kvm_max_vl[ARM64_VEC_SVE]);
 	}
 
 	return 0;
@@ -78,7 +78,7 @@ int __init kvm_arm_init_sve(void)
 
 static void kvm_vcpu_enable_sve(struct kvm_vcpu *vcpu)
 {
-	vcpu->arch.sve_max_vl = kvm_sve_max_vl;
+	vcpu->arch.max_vl[ARM64_VEC_SVE] = kvm_max_vl[ARM64_VEC_SVE];
 
 	/*
 	 * Userspace can still customize the vector lengths by writing
@@ -99,7 +99,7 @@ static int kvm_vcpu_finalize_vec(struct kvm_vcpu *vcpu)
 	size_t reg_sz;
 	int ret;
 
-	vl = vcpu->arch.sve_max_vl;
+	vl = vcpu->arch.max_vl[ARM64_VEC_SVE];
 
 	/*
 	 * Responsibility for these properties is shared between

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:21:08 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:21:08 +0000
Subject: [PATCH v9 14/30] KVM: arm64: Implement SME vector length
 configuration
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-14-8be3867cb883@kernel.org>

SME implements a vector length which architecturally looks very similar
to that for SVE, configured in a very similar manner.  This controls the
vector length used for the ZA matrix register, and for the SVE vector
and predicate registers when in streaming mode.  The only substantial
difference is that unlike SVE the architecture does not guarantee that
any particular vector length will be implemented.

Configuration for SME vector lengths is done using a virtual register as
for SVE, hook up the implementation for the virtual register.  Since we
do not yet have support for any of the new SME registers stub register
access functions are provided that only allow VL configuration.  These
will be extended as the SME specific registers, as for SVE.

Since vq_available() is currently only defined for CONFIG_SVE add a stub
for builds where that is disabled.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 arch/arm64/include/asm/fpsimd.h   |  1 +
 arch/arm64/include/asm/kvm_host.h | 24 ++++++++++--
 arch/arm64/include/uapi/asm/kvm.h |  9 +++++
 arch/arm64/kvm/guest.c            | 82 +++++++++++++++++++++++++++++++--------
 4 files changed, 96 insertions(+), 20 deletions(-)

diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index 146c1af55e22..8b0840bd7e14 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -340,6 +340,7 @@ static inline int sve_max_vl(void)
 	return -EINVAL;
 }
 
+static inline bool vq_available(enum vec_type type, unsigned int vq) { return false; }
 static inline bool sve_vq_available(unsigned int vq) { return false; }
 
 static inline void sve_user_disable(void) { BUILD_BUG(); }
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 3a3330b2a6a9..b41700df3ce9 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -810,8 +810,15 @@ struct kvm_vcpu_arch {
 	 * low 128 bits of the SVE Z registers.  When the core
 	 * floating point code saves the register state of a task it
 	 * records which view it saved in fp_type.
+	 *
+	 * If SME support is also present then it provides an
+	 * alternative view of the SVE registers accessed as for the Z
+	 * registers when PSTATE.SM is 1, plus an additional set of
+	 * SME specific state in the matrix register ZA and LUT
+	 * register ZT0.
 	 */
 	void *sve_state;
+	void *sme_state;
 	enum fp_type fp_type;
 	unsigned int max_vl[ARM64_VEC_MAX];
 
@@ -1098,14 +1105,23 @@ struct kvm_vcpu_arch {
 
 #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.regs)
 
-/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
-#define vcpu_sve_pffr(vcpu) (kern_hyp_va((vcpu)->arch.sve_state) +	\
-			     sve_ffr_offset((vcpu)->arch.max_vl[ARM64_VEC_SVE]))
-
 #define vcpu_vec_max_vq(vcpu, type) sve_vq_from_vl((vcpu)->arch.max_vl[type])
 
 #define vcpu_sve_max_vq(vcpu)	vcpu_vec_max_vq(vcpu, ARM64_VEC_SVE)
+#define vcpu_sme_max_vq(vcpu)	vcpu_vec_max_vq(vcpu, ARM64_VEC_SME)
+
+#define vcpu_sve_max_vl(vcpu)	((vcpu)->arch.max_vl[ARM64_VEC_SVE])
+#define vcpu_sme_max_vl(vcpu)	((vcpu)->arch.max_vl[ARM64_VEC_SME])
 
+#define vcpu_max_vl(vcpu) max(vcpu_sve_max_vl(vcpu), vcpu_sme_max_vl(vcpu))
+#define vcpu_max_vq(vcpu) sve_vq_from_vl(vcpu_max_vl(vcpu))
+
+#define vcpu_cur_sve_vl(vcpu) (vcpu_in_streaming_mode(vcpu) ? \
+			       vcpu_sme_max_vl(vcpu) : vcpu_sve_max_vl(vcpu))
+
+/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
+#define vcpu_sve_pffr(vcpu) (kern_hyp_va((vcpu)->arch.sve_state) +	\
+			     sve_ffr_offset(vcpu_cur_sve_vl(vcpu)))
 
 #define vcpu_sve_zcr_elx(vcpu)						\
 	(unlikely(is_hyp_ctxt(vcpu)) ? ZCR_EL2 : ZCR_EL1)
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index c67564f02981..498a49a61487 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -354,6 +354,15 @@ struct kvm_arm_counter_offset {
 #define KVM_ARM64_SVE_VLS_WORDS	\
 	((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
 
+/* SME registers */
+#define KVM_REG_ARM64_SME		(0x17 << KVM_REG_ARM_COPROC_SHIFT)
+
+/* Vector lengths pseudo-register: */
+#define KVM_REG_ARM64_SME_VLS		(KVM_REG_ARM64 | KVM_REG_ARM64_SME | \
+					 KVM_REG_SIZE_U512 | 0xfffe)
+#define KVM_ARM64_SME_VLS_WORDS	\
+	((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
+
 /* Bitmap feature firmware registers */
 #define KVM_REG_ARM_FW_FEAT_BMAP		(0x0016 << KVM_REG_ARM_COPROC_SHIFT)
 #define KVM_REG_ARM_FW_FEAT_BMAP_REG(r)		(KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 456ef61b6ed5..2a1fdcb0ec49 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -310,22 +310,20 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 #define vq_mask(vq) ((u64)1 << ((vq) - SVE_VQ_MIN) % 64)
 #define vq_present(vqs, vq) (!!((vqs)[vq_word(vq)] & vq_mask(vq)))
 
-static int get_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+static int get_vec_vls(enum vec_type vec_type, struct kvm_vcpu *vcpu,
+		      const struct kvm_one_reg *reg)
 {
 	unsigned int max_vq, vq;
 	u64 vqs[KVM_ARM64_SVE_VLS_WORDS];
 
-	if (!vcpu_has_sve(vcpu))
-		return -ENOENT;
-
-	if (WARN_ON(!sve_vl_valid(vcpu->arch.max_vl[ARM64_VEC_SVE])))
+	if (WARN_ON(!sve_vl_valid(vcpu->arch.max_vl[vec_type])))
 		return -EINVAL;
 
 	memset(vqs, 0, sizeof(vqs));
 
-	max_vq = vcpu_sve_max_vq(vcpu);
+	max_vq = vcpu_vec_max_vq(vcpu, vec_type);
 	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
-		if (sve_vq_available(vq))
+		if (vq_available(vec_type, vq))
 			vqs[vq_word(vq)] |= vq_mask(vq);
 
 	if (copy_to_user((void __user *)reg->addr, vqs, sizeof(vqs)))
@@ -334,40 +332,41 @@ static int get_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	return 0;
 }
 
-static int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+static int set_vec_vls(enum vec_type vec_type, struct kvm_vcpu *vcpu,
+		       const struct kvm_one_reg *reg)
 {
 	unsigned int max_vq, vq;
 	u64 vqs[KVM_ARM64_SVE_VLS_WORDS];
 
-	if (!vcpu_has_sve(vcpu))
-		return -ENOENT;
-
 	if (kvm_arm_vcpu_vec_finalized(vcpu))
 		return -EPERM; /* too late! */
 
-	if (WARN_ON(vcpu->arch.sve_state))
+	if (WARN_ON(!sve_vl_valid(vcpu->arch.max_vl[vec_type])))
 		return -EINVAL;
 
 	if (copy_from_user(vqs, (const void __user *)reg->addr, sizeof(vqs)))
 		return -EFAULT;
 
+	if (WARN_ON(vcpu->arch.sve_state || vcpu->arch.sme_state))
+		return -EINVAL;
+
 	max_vq = 0;
 	for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; ++vq)
 		if (vq_present(vqs, vq))
 			max_vq = vq;
 
-	if (max_vq > sve_vq_from_vl(kvm_max_vl[ARM64_VEC_SVE]))
+	if (max_vq > sve_vq_from_vl(kvm_max_vl[vec_type]))
 		return -EINVAL;
 
 	/*
 	 * Vector lengths supported by the host can't currently be
 	 * hidden from the guest individually: instead we can only set a
-	 * maximum via ZCR_EL2.LEN.  So, make sure the available vector
+	 * maximum via xCR_EL2.LEN.  So, make sure the available vector
 	 * lengths match the set requested exactly up to the requested
 	 * maximum:
 	 */
 	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
-		if (vq_present(vqs, vq) != sve_vq_available(vq))
+		if (vq_present(vqs, vq) != vq_available(vec_type, vq))
 			return -EINVAL;
 
 	/* Can't run with no vector lengths at all: */
@@ -375,11 +374,27 @@ static int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 		return -EINVAL;
 
 	/* vcpu->arch.sve_state will be alloc'd by kvm_vcpu_finalize_sve() */
-	vcpu->arch.max_vl[ARM64_VEC_SVE] = sve_vl_from_vq(max_vq);
+	vcpu->arch.max_vl[vec_type] = sve_vl_from_vq(max_vq);
 
 	return 0;
 }
 
+static int get_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+	if (!vcpu_has_sve(vcpu))
+		return -ENOENT;
+
+	return get_vec_vls(ARM64_VEC_SVE, vcpu, reg);
+}
+
+static int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+	if (!vcpu_has_sve(vcpu))
+		return -ENOENT;
+
+	return set_vec_vls(ARM64_VEC_SVE, vcpu, reg);
+}
+
 #define SVE_REG_SLICE_SHIFT	0
 #define SVE_REG_SLICE_BITS	5
 #define SVE_REG_ID_SHIFT	(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS)
@@ -533,6 +548,39 @@ static int set_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	return 0;
 }
 
+static int get_sme_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+	if (!vcpu_has_sme(vcpu))
+		return -ENOENT;
+
+	return get_vec_vls(ARM64_VEC_SME, vcpu, reg);
+}
+
+static int set_sme_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+	if (!vcpu_has_sme(vcpu))
+		return -ENOENT;
+
+	return set_vec_vls(ARM64_VEC_SME, vcpu, reg);
+}
+
+static int get_sme_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+	/* Handle the KVM_REG_ARM64_SME_VLS pseudo-reg as a special case: */
+	if (reg->id == KVM_REG_ARM64_SME_VLS)
+		return get_sme_vls(vcpu, reg);
+
+	return -EINVAL;
+}
+
+static int set_sme_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+	/* Handle the KVM_REG_ARM64_SME_VLS pseudo-reg as a special case: */
+	if (reg->id == KVM_REG_ARM64_SME_VLS)
+		return set_sme_vls(vcpu, reg);
+
+	return -EINVAL;
+}
 int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
 	return -EINVAL;
@@ -711,6 +759,7 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	case KVM_REG_ARM_FW_FEAT_BMAP:
 		return kvm_arm_get_fw_reg(vcpu, reg);
 	case KVM_REG_ARM64_SVE:	return get_sve_reg(vcpu, reg);
+	case KVM_REG_ARM64_SME:	return get_sme_reg(vcpu, reg);
 	}
 
 	return kvm_arm_sys_reg_get_reg(vcpu, reg);
@@ -728,6 +777,7 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	case KVM_REG_ARM_FW_FEAT_BMAP:
 		return kvm_arm_set_fw_reg(vcpu, reg);
 	case KVM_REG_ARM64_SVE:	return set_sve_reg(vcpu, reg);
+	case KVM_REG_ARM64_SME:	return set_sme_reg(vcpu, reg);
 	}
 
 	return kvm_arm_sys_reg_set_reg(vcpu, reg);

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:21:09 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:21:09 +0000
Subject: [PATCH v9 15/30] KVM: arm64: Support SME control registers
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-15-8be3867cb883@kernel.org>

SME is configured by the system registers SMCR_EL1 and SMCR_EL2, add
definitions and userspace access for them.  These control the SME vector
length in a manner similar to that for SVE and also have feature enable
bits for SME2 and FA64.  A subsequent patch will add management of them
for guests as part of the general floating point context switch, as is
done for the equivalent SVE registers.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 arch/arm64/include/asm/kvm_host.h     |  2 ++
 arch/arm64/include/asm/vncr_mapping.h |  1 +
 arch/arm64/kvm/sys_regs.c             | 36 ++++++++++++++++++++++++++++++++++-
 3 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index b41700df3ce9..f24441244a68 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -504,6 +504,7 @@ enum vcpu_sysreg {
 	CPTR_EL2,	/* Architectural Feature Trap Register (EL2) */
 	HACR_EL2,	/* Hypervisor Auxiliary Control Register */
 	ZCR_EL2,	/* SVE Control Register (EL2) */
+	SMCR_EL2,	/* SME Control Register (EL2) */
 	TTBR0_EL2,	/* Translation Table Base Register 0 (EL2) */
 	TTBR1_EL2,	/* Translation Table Base Register 1 (EL2) */
 	TCR_EL2,	/* Translation Control Register (EL2) */
@@ -542,6 +543,7 @@ enum vcpu_sysreg {
 	VNCR(ACTLR_EL1),/* Auxiliary Control Register */
 	VNCR(CPACR_EL1),/* Coprocessor Access Control */
 	VNCR(ZCR_EL1),	/* SVE Control */
+	VNCR(SMCR_EL1),	/* SME Control */
 	VNCR(TTBR0_EL1),/* Translation Table Base Register 0 */
 	VNCR(TTBR1_EL1),/* Translation Table Base Register 1 */
 	VNCR(TCR_EL1),	/* Translation Control Register */
diff --git a/arch/arm64/include/asm/vncr_mapping.h b/arch/arm64/include/asm/vncr_mapping.h
index c2485a862e69..44b12565321b 100644
--- a/arch/arm64/include/asm/vncr_mapping.h
+++ b/arch/arm64/include/asm/vncr_mapping.h
@@ -44,6 +44,7 @@
 #define VNCR_HDFGWTR_EL2	0x1D8
 #define VNCR_ZCR_EL1            0x1E0
 #define VNCR_HAFGRTR_EL2	0x1E8
+#define VNCR_SMCR_EL1		0x1F0
 #define VNCR_TTBR0_EL1          0x200
 #define VNCR_TTBR1_EL1          0x210
 #define VNCR_FAR_EL1            0x220
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 3576e69468db..5c912139d264 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -2827,6 +2827,37 @@ static bool access_gic_elrsr(struct kvm_vcpu *vcpu,
 	return true;
 }
 
+static unsigned int sme_el2_visibility(const struct kvm_vcpu *vcpu,
+				       const struct sys_reg_desc *rd)
+{
+	return __el2_visibility(vcpu, rd, sme_visibility);
+}
+
+static bool access_smcr_el2(struct kvm_vcpu *vcpu,
+			    struct sys_reg_params *p,
+			    const struct sys_reg_desc *r)
+{
+	unsigned int vq;
+	u64 smcr;
+
+	if (guest_hyp_sve_traps_enabled(vcpu)) {
+		kvm_inject_nested_sve_trap(vcpu);
+		return false;
+	}
+
+	if (!p->is_write) {
+		p->regval = __vcpu_sys_reg(vcpu, SMCR_EL2);
+		return true;
+	}
+
+	smcr = p->regval;
+	vq = SYS_FIELD_GET(SMCR_ELx, LEN, smcr) + 1;
+	vq = min(vq, vcpu_sme_max_vq(vcpu));
+	__vcpu_assign_sys_reg(vcpu, SMCR_EL2, SYS_FIELD_PREP(SMCR_ELx, LEN,
+							     vq - 1));
+	return true;
+}
+
 static unsigned int s1poe_visibility(const struct kvm_vcpu *vcpu,
 				     const struct sys_reg_desc *rd)
 {
@@ -3291,7 +3322,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	{ SYS_DESC(SYS_ZCR_EL1), NULL, reset_val, ZCR_EL1, 0, .visibility = sve_visibility },
 	{ SYS_DESC(SYS_TRFCR_EL1), undef_access },
 	{ SYS_DESC(SYS_SMPRI_EL1), undef_access },
-	{ SYS_DESC(SYS_SMCR_EL1), undef_access },
+	{ SYS_DESC(SYS_SMCR_EL1), NULL, reset_val, SMCR_EL1, 0, .visibility = sme_visibility },
 	{ SYS_DESC(SYS_TTBR0_EL1), access_vm_reg, reset_unknown, TTBR0_EL1 },
 	{ SYS_DESC(SYS_TTBR1_EL1), access_vm_reg, reset_unknown, TTBR1_EL1 },
 	{ SYS_DESC(SYS_TCR_EL1), access_vm_reg, reset_val, TCR_EL1, 0 },
@@ -3655,6 +3686,9 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 
 	EL2_REG_VNCR(HCRX_EL2, reset_val, 0),
 
+	EL2_REG_FILTERED(SMCR_EL2, access_smcr_el2, reset_val, 0,
+			 sme_el2_visibility),
+
 	EL2_REG(TTBR0_EL2, access_rw, reset_val, 0),
 	EL2_REG(TTBR1_EL2, access_rw, reset_val, 0),
 	EL2_REG(TCR_EL2, access_rw, reset_val, TCR_EL2_RES1),

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:21:10 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:21:10 +0000
Subject: [PATCH v9 16/30] KVM: arm64: Support TPIDR2_EL0
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-16-8be3867cb883@kernel.org>

SME adds a new thread ID register, TPIDR2_EL0. This is used in userspace
for delayed saving of the ZA state but in terms of the architecture is
not really connected to SME other than being part of FEAT_SME. It has an
independent fine grained trap and the runtime connection with the rest
of SME is purely software defined.

Expose the register as a system register if the guest supports SME,
context switching it along with the other EL0 TPIDRs.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 arch/arm64/include/asm/kvm_host.h          |  1 +
 arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h | 15 +++++++++++++++
 arch/arm64/kvm/sys_regs.c                  |  3 ++-
 3 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index f24441244a68..825b74f752d6 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -448,6 +448,7 @@ enum vcpu_sysreg {
 	CSSELR_EL1,	/* Cache Size Selection Register */
 	TPIDR_EL0,	/* Thread ID, User R/W */
 	TPIDRRO_EL0,	/* Thread ID, User R/O */
+	TPIDR2_EL0,	/* Thread ID, Register 2 */
 	TPIDR_EL1,	/* Thread ID, Privileged */
 	CNTKCTL_EL1,	/* Timer Control Register (EL1) */
 	PAR_EL1,	/* Physical Address Register */
diff --git a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
index 5624fd705ae3..8c3b3d6df99f 100644
--- a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
+++ b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
@@ -88,6 +88,17 @@ static inline bool ctxt_has_sctlr2(struct kvm_cpu_context *ctxt)
 	return kvm_has_sctlr2(kern_hyp_va(vcpu->kvm));
 }
 
+static inline bool ctxt_has_sme(struct kvm_cpu_context *ctxt)
+{
+	struct kvm_vcpu *vcpu;
+
+	if (!system_supports_sme())
+		return false;
+
+	vcpu = ctxt_to_vcpu(ctxt);
+	return kvm_has_sme(kern_hyp_va(vcpu->kvm));
+}
+
 static inline bool ctxt_is_guest(struct kvm_cpu_context *ctxt)
 {
 	return host_data_ptr(host_ctxt) != ctxt;
@@ -127,6 +138,8 @@ static inline void __sysreg_save_user_state(struct kvm_cpu_context *ctxt)
 {
 	ctxt_sys_reg(ctxt, TPIDR_EL0)	= read_sysreg(tpidr_el0);
 	ctxt_sys_reg(ctxt, TPIDRRO_EL0)	= read_sysreg(tpidrro_el0);
+	if (ctxt_has_sme(ctxt))
+		ctxt_sys_reg(ctxt, TPIDR2_EL0)	= read_sysreg_s(SYS_TPIDR2_EL0);
 }
 
 static inline void __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
@@ -204,6 +217,8 @@ static inline void __sysreg_restore_user_state(struct kvm_cpu_context *ctxt)
 {
 	write_sysreg(ctxt_sys_reg(ctxt, TPIDR_EL0),	tpidr_el0);
 	write_sysreg(ctxt_sys_reg(ctxt, TPIDRRO_EL0),	tpidrro_el0);
+	if (ctxt_has_sme(ctxt))
+		write_sysreg_s(ctxt_sys_reg(ctxt, TPIDR2_EL0), SYS_TPIDR2_EL0);
 }
 
 static inline void __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt,
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 5c912139d264..7e550f045f4d 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -3504,7 +3504,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	  .visibility = s1poe_visibility },
 	{ SYS_DESC(SYS_TPIDR_EL0), NULL, reset_unknown, TPIDR_EL0 },
 	{ SYS_DESC(SYS_TPIDRRO_EL0), NULL, reset_unknown, TPIDRRO_EL0 },
-	{ SYS_DESC(SYS_TPIDR2_EL0), undef_access },
+	{ SYS_DESC(SYS_TPIDR2_EL0), NULL, reset_unknown, TPIDR2_EL0,
+	  .visibility = sme_visibility},
 
 	{ SYS_DESC(SYS_SCXTNUM_EL0), undef_access },
 

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:21:13 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:21:13 +0000
Subject: [PATCH v9 19/30] KVM: arm64: Provide assembly for SME register
 access
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-19-8be3867cb883@kernel.org>

Provide versions of the SME state save and restore functions for the
hypervisor to allow it to restore ZA and ZT for guests.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 arch/arm64/include/asm/kvm_hyp.h |  3 +++
 arch/arm64/kvm/hyp/fpsimd.S      | 26 ++++++++++++++++++++++++++
 2 files changed, 29 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index 0317790dd3b7..1cef9991d238 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -116,6 +116,9 @@ void __fpsimd_save_state(struct user_fpsimd_state *fp_regs);
 void __fpsimd_restore_state(struct user_fpsimd_state *fp_regs);
 void __sve_save_state(void *sve_pffr, u32 *fpsr, int save_ffr);
 void __sve_restore_state(void *sve_pffr, u32 *fpsr, int restore_ffr);
+int __sve_get_vl(void);
+void __sme_save_state(void const *state, bool restore_zt);
+void __sme_restore_state(void const *state, bool restore_zt);
 
 u64 __guest_enter(struct kvm_vcpu *vcpu);
 
diff --git a/arch/arm64/kvm/hyp/fpsimd.S b/arch/arm64/kvm/hyp/fpsimd.S
index 6e16cbfc5df2..44a1b0a483da 100644
--- a/arch/arm64/kvm/hyp/fpsimd.S
+++ b/arch/arm64/kvm/hyp/fpsimd.S
@@ -29,3 +29,29 @@ SYM_FUNC_START(__sve_save_state)
 	sve_save 0, x1, x2, 3
 	ret
 SYM_FUNC_END(__sve_save_state)
+
+SYM_FUNC_START(__sve_get_vl)
+	_sve_rdvl	0, 1
+	ret
+SYM_FUNC_END(__sve_get_vl)
+
+SYM_FUNC_START(__sme_save_state)
+	_sme_rdsvl	2, 1		// x2 = VL/8
+	sme_save_za 0, x2, 12		// Leaves x0 pointing to the end of ZA
+
+	cbz	x1, 1f
+	_str_zt 0
+1:
+	ret
+SYM_FUNC_END(__sme_save_state)
+
+SYM_FUNC_START(__sme_restore_state)
+	_sme_rdsvl	2, 1		// x2 = VL/8
+	sme_load_za	0, x2, 12	// Leaves x0 pointing to end of ZA
+
+	cbz	x1, 1f
+	_ldr_zt 0
+
+1:
+	ret
+SYM_FUNC_END(__sme_restore_state)

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:21:11 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:21:11 +0000
Subject: [PATCH v9 17/30] KVM: arm64: Support SME identification registers
 for guests
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-17-8be3867cb883@kernel.org>

The primary register for identifying SME is ID_AA64PFR1_EL1.SME.  This
is hidden from guests unless SME is enabled by the VMM.
When it is visible it is writable and can be used to control the
availability of SME2.

There is also a new register ID_AA64SMFR0_EL1 which we make writable,
forcing it to all bits 0 if SME is disabled.  This includes the field
SMEver giving the SME version, userspace is responsible for ensuring
the value is consistent with ID_AA64PFR1_EL1.SME.  It also includes
FA64, a separately enableable extension which provides the full FPSIMD
and SVE instruction set including FFR in streaming mode.  Userspace can
control the availability of FA64 by writing to this field.  The other
features enumerated there only add new instructions, there are no
architectural controls for these.

There is a further identification register SMIDR_EL1 which provides a
basic description of the SME microarchitecture, in a manner similar to
MIDR_EL1 for the PE.  It also describes support for priority management
and a basic affinity description for shared SME units, plus some RES0
space.  We do not support priority management for guests so this is
hidden from guests, along with any new fields.

As for MIDR_EL1 and REVIDR_EL1 we expose the implementer and revision
information to guests with the raw value from the CPU we are running on,
this may present issues for asymmetric systems or for migration as it
does for the existing registers.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 arch/arm64/include/asm/kvm_host.h          |  3 +++
 arch/arm64/kvm/config.c                    |  8 +-----
 arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h | 11 ++++++++
 arch/arm64/kvm/hyp/nvhe/pkvm.c             |  4 ++-
 arch/arm64/kvm/sys_regs.c                  | 40 +++++++++++++++++++++++++++---
 5 files changed, 54 insertions(+), 12 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 825b74f752d6..fead6988f47c 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -400,6 +400,7 @@ struct kvm_arch {
 	u64 revidr_el1;
 	u64 aidr_el1;
 	u64 ctr_el0;
+	u64 smidr_el1;
 
 	/* Masks for VNCR-backed and general EL2 sysregs */
 	struct kvm_sysreg_masks	*sysreg_masks;
@@ -1543,6 +1544,8 @@ static inline u64 *__vm_id_reg(struct kvm_arch *ka, u32 reg)
 		return &ka->revidr_el1;
 	case SYS_AIDR_EL1:
 		return &ka->aidr_el1;
+	case SYS_SMIDR_EL1:
+		return &ka->smidr_el1;
 	default:
 		WARN_ON_ONCE(1);
 		return NULL;
diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index 24bb3f36e9d5..7e26991b2df1 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -274,14 +274,8 @@ static bool feat_anerr(struct kvm *kvm)
 
 static bool feat_sme_smps(struct kvm *kvm)
 {
-	/*
-	 * Revists this if KVM ever supports SME -- this really should
-	 * look at the guest's view of SMIDR_EL1. Funnily enough, this
-	 * is not captured in the JSON file, but only as a note in the
-	 * ARM ARM.
-	 */
 	return (kvm_has_feat(kvm, FEAT_SME) &&
-		(read_sysreg_s(SYS_SMIDR_EL1) & SMIDR_EL1_SMPS));
+		(kvm_read_vm_id_reg(kvm, SYS_SMIDR_EL1) & SMIDR_EL1_SMPS));
 }
 
 static bool feat_spe_fds(struct kvm *kvm)
diff --git a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
index 8c3b3d6df99f..d921db152119 100644
--- a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
+++ b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
@@ -125,6 +125,17 @@ static inline u64 ctxt_midr_el1(struct kvm_cpu_context *ctxt)
 	return kvm_read_vm_id_reg(kvm, SYS_MIDR_EL1);
 }
 
+static inline u64 ctxt_smidr_el1(struct kvm_cpu_context *ctxt)
+{
+	struct kvm *kvm = kern_hyp_va(ctxt_to_vcpu(ctxt)->kvm);
+
+	if (!(ctxt_is_guest(ctxt) &&
+	      test_bit(KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS, &kvm->arch.flags)))
+		return read_sysreg_s(SYS_SMIDR_EL1);
+
+	return kvm_read_vm_id_reg(kvm, SYS_SMIDR_EL1);
+}
+
 static inline void __sysreg_save_common_state(struct kvm_cpu_context *ctxt)
 {
 	*ctxt_mdscr_el1(ctxt)	= read_sysreg(mdscr_el1);
diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index f4ec6695a6a5..b656449dff69 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -351,8 +351,10 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
 			    host_kvm->arch.vcpu_features,
 			    KVM_VCPU_MAX_FEATURES);
 
-		if (test_bit(KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS, &host_arch_flags))
+		if (test_bit(KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS, &host_arch_flags)) {
 			hyp_vm->kvm.arch.midr_el1 = host_kvm->arch.midr_el1;
+			hyp_vm->kvm.arch.smidr_el1 = host_kvm->arch.smidr_el1;
+		}
 
 		return;
 	}
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 7e550f045f4d..a7ab02822023 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1893,6 +1893,10 @@ static unsigned int id_visibility(const struct kvm_vcpu *vcpu,
 		if (!vcpu_has_sve(vcpu))
 			return REG_RAZ;
 		break;
+	case SYS_ID_AA64SMFR0_EL1:
+		if (!vcpu_has_sme(vcpu))
+			return REG_RAZ;
+		break;
 	}
 
 	return 0;
@@ -1920,10 +1924,25 @@ static unsigned int raz_visibility(const struct kvm_vcpu *vcpu,
 
 /* cpufeature ID register access trap handlers */
 
+static bool hidden_id_reg(struct kvm_vcpu *vcpu,
+			  struct sys_reg_params *p,
+			  const struct sys_reg_desc *r)
+{
+	switch (reg_to_encoding(r)) {
+	case SYS_SMIDR_EL1:
+		return !vcpu_has_sme(vcpu);
+	default:
+		return false;
+	}
+}
+
 static bool access_id_reg(struct kvm_vcpu *vcpu,
 			  struct sys_reg_params *p,
 			  const struct sys_reg_desc *r)
 {
+	if (hidden_id_reg(vcpu, p, r))
+		return bad_trap(vcpu, p, r, "write to hidden ID register");
+
 	if (p->is_write)
 		return write_to_read_only(vcpu, p, r);
 
@@ -2012,7 +2031,9 @@ static u64 sanitise_id_aa64pfr1_el1(const struct kvm_vcpu *vcpu, u64 val)
 	      SYS_FIELD_GET(ID_AA64PFR0_EL1, RAS, pfr0) == ID_AA64PFR0_EL1_RAS_IMP))
 		val &= ~ID_AA64PFR1_EL1_RAS_frac;
 
-	val &= ~ID_AA64PFR1_EL1_SME;
+	if (!kvm_has_sme(vcpu->kvm))
+		val &= ~ID_AA64PFR1_EL1_SME;
+
 	val &= ~ID_AA64PFR1_EL1_RNDR_trap;
 	val &= ~ID_AA64PFR1_EL1_NMI;
 	val &= ~ID_AA64PFR1_EL1_GCS;
@@ -3038,6 +3059,9 @@ static bool access_imp_id_reg(struct kvm_vcpu *vcpu,
 	case SYS_AIDR_EL1:
 		p->regval = read_sysreg(aidr_el1);
 		break;
+	case SYS_SMIDR_EL1:
+		p->regval = read_sysreg_s(SYS_SMIDR_EL1);
+		break;
 	default:
 		WARN_ON_ONCE(1);
 	}
@@ -3048,12 +3072,15 @@ static bool access_imp_id_reg(struct kvm_vcpu *vcpu,
 static u64 __ro_after_init boot_cpu_midr_val;
 static u64 __ro_after_init boot_cpu_revidr_val;
 static u64 __ro_after_init boot_cpu_aidr_val;
+static u64 __ro_after_init boot_cpu_smidr_val;
 
 static void init_imp_id_regs(void)
 {
 	boot_cpu_midr_val = read_sysreg(midr_el1);
 	boot_cpu_revidr_val = read_sysreg(revidr_el1);
 	boot_cpu_aidr_val = read_sysreg(aidr_el1);
+	if (system_supports_sme())
+		boot_cpu_smidr_val = read_sysreg_s(SYS_SMIDR_EL1);
 }
 
 static u64 reset_imp_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
@@ -3065,6 +3092,8 @@ static u64 reset_imp_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 		return boot_cpu_revidr_val;
 	case SYS_AIDR_EL1:
 		return boot_cpu_aidr_val;
+	case SYS_SMIDR_EL1:
+		return boot_cpu_smidr_val;
 	default:
 		KVM_BUG_ON(1, vcpu->kvm);
 		return 0;
@@ -3229,7 +3258,6 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 				       ID_AA64PFR1_EL1_MTE_frac |
 				       ID_AA64PFR1_EL1_NMI |
 				       ID_AA64PFR1_EL1_RNDR_trap |
-				       ID_AA64PFR1_EL1_SME |
 				       ID_AA64PFR1_EL1_RES0 |
 				       ID_AA64PFR1_EL1_MPAM_frac |
 				       ID_AA64PFR1_EL1_MTE)),
@@ -3239,7 +3267,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 		    ID_AA64PFR2_EL1_MTESTOREONLY),
 	ID_UNALLOCATED(4,3),
 	ID_WRITABLE(ID_AA64ZFR0_EL1, ~ID_AA64ZFR0_EL1_RES0),
-	ID_HIDDEN(ID_AA64SMFR0_EL1),
+	ID_WRITABLE(ID_AA64SMFR0_EL1, ~ID_AA64SMFR0_EL1_RES0),
 	ID_UNALLOCATED(4,6),
 	ID_WRITABLE(ID_AA64FPFR0_EL1, ~ID_AA64FPFR0_EL1_RES0),
 
@@ -3446,7 +3474,11 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	{ SYS_DESC(SYS_CLIDR_EL1), access_clidr, reset_clidr, CLIDR_EL1,
 	  .set_user = set_clidr, .val = ~CLIDR_EL1_RES0 },
 	{ SYS_DESC(SYS_CCSIDR2_EL1), undef_access },
-	{ SYS_DESC(SYS_SMIDR_EL1), undef_access },
+	IMPLEMENTATION_ID(SMIDR_EL1, (SMIDR_EL1_NSMC | SMIDR_EL1_HIP |
+				      SMIDR_EL1_AFFINITY2 |
+				      SMIDR_EL1_IMPLEMENTER |
+				      SMIDR_EL1_REVISION | SMIDR_EL1_SH |
+				      SMIDR_EL1_AFFINITY)),
 	IMPLEMENTATION_ID(AIDR_EL1, GENMASK_ULL(63, 0)),
 	{ SYS_DESC(SYS_CSSELR_EL1), access_csselr, reset_unknown, CSSELR_EL1 },
 	ID_FILTERED(CTR_EL0, ctr_el0,

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:21:12 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:21:12 +0000
Subject: [PATCH v9 18/30] KVM: arm64: Support SME priority registers
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-18-8be3867cb883@kernel.org>

SME has optional support for configuring the relative priorities of PEs
in systems where they share a single SME hardware block, known as a
SMCU. Currently we do not have any support for this in Linux and will
also hide it from KVM guests, pending experience with practical
implementations. The interface for configuring priority support is via
two new system registers, these registers are always defined when SME is
available.

The register SMPRI_EL1 allows control of SME execution priorities. Since
we disable SME priority support for guests this register is RES0, define
it as such and enable fine grained traps for SMPRI_EL1 to ensure that
guests can't write to it even if the hardware supports priorites.  Since
the register should be readable with fixed contents we only trap writes,
not reads. Since there is no host support for using priorities the
register currently left with a value of 0 by the host so we do not need
to update the value for guests.

There is also an EL2 register SMPRIMAP_EL2 for virtualisation of
priorities, this is RES0 when priority configuration is not supported
but has no specific traps available.  When saving state from a nested
guest we overwite any value the guest stored.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 arch/arm64/include/asm/kvm_host.h     |  1 +
 arch/arm64/include/asm/vncr_mapping.h |  1 +
 arch/arm64/kvm/config.c               |  3 +++
 arch/arm64/kvm/hyp/vhe/sysreg-sr.c    |  7 +++++++
 arch/arm64/kvm/sys_regs.c             | 30 +++++++++++++++++++++++++++++-
 5 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index fead6988f47c..44595a789a97 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -546,6 +546,7 @@ enum vcpu_sysreg {
 	VNCR(CPACR_EL1),/* Coprocessor Access Control */
 	VNCR(ZCR_EL1),	/* SVE Control */
 	VNCR(SMCR_EL1),	/* SME Control */
+	VNCR(SMPRIMAP_EL2),	/* Streaming Mode Priority Mapping Register */
 	VNCR(TTBR0_EL1),/* Translation Table Base Register 0 */
 	VNCR(TTBR1_EL1),/* Translation Table Base Register 1 */
 	VNCR(TCR_EL1),	/* Translation Control Register */
diff --git a/arch/arm64/include/asm/vncr_mapping.h b/arch/arm64/include/asm/vncr_mapping.h
index 44b12565321b..a2a84af6585b 100644
--- a/arch/arm64/include/asm/vncr_mapping.h
+++ b/arch/arm64/include/asm/vncr_mapping.h
@@ -45,6 +45,7 @@
 #define VNCR_ZCR_EL1            0x1E0
 #define VNCR_HAFGRTR_EL2	0x1E8
 #define VNCR_SMCR_EL1		0x1F0
+#define VNCR_SMPRIMAP_EL2	0x1F0
 #define VNCR_TTBR0_EL1          0x200
 #define VNCR_TTBR1_EL1          0x210
 #define VNCR_FAR_EL1            0x220
diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index 7e26991b2df1..0088635a95bd 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -1481,6 +1481,9 @@ static void __compute_hfgwtr(struct kvm_vcpu *vcpu)
 
 	if (cpus_have_final_cap(ARM64_WORKAROUND_AMPERE_AC03_CPU_38))
 		*vcpu_fgt(vcpu, HFGWTR_EL2) |= HFGWTR_EL2_TCR_EL1;
+
+	if (kvm_has_feat(vcpu->kvm, ID_AA64PFR1_EL1, SME, IMP))
+		*vcpu_fgt(vcpu, HFGWTR_EL2) |= HFGWTR_EL2_nSMPRI_EL1;
 }
 
 static void __compute_hdfgwtr(struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/kvm/hyp/vhe/sysreg-sr.c b/arch/arm64/kvm/hyp/vhe/sysreg-sr.c
index f28c6cf4fe1b..07aa4378c58a 100644
--- a/arch/arm64/kvm/hyp/vhe/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/vhe/sysreg-sr.c
@@ -80,6 +80,13 @@ static void __sysreg_save_vel2_state(struct kvm_vcpu *vcpu)
 
 	if (ctxt_has_sctlr2(&vcpu->arch.ctxt))
 		__vcpu_assign_sys_reg(vcpu, SCTLR2_EL2, read_sysreg_el1(SYS_SCTLR2));
+
+	/*
+	 * We block SME priorities so SMPRIMAP_EL2 is RES0, however we
+	 * do not have traps to block access so the guest might have
+	 * updated the state, overwrite anything there.
+	 */
+	__vcpu_assign_sys_reg(vcpu, SMPRIMAP_EL2, 0);
 }
 
 static void __sysreg_restore_vel2_state(struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index a7ab02822023..51f175bbe8d1 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -691,6 +691,15 @@ static bool trap_raz_wi(struct kvm_vcpu *vcpu,
 		return read_zero(vcpu, p);
 }
 
+static int set_res0(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
+		    u64 val)
+{
+	if (val)
+		return -EINVAL;
+
+	return 0;
+}
+
 /*
  * ARMv8.1 mandates at least a trivial LORegion implementation, where all the
  * RW registers are RES0 (which we can implement as RAZ/WI). On an ARMv8.0
@@ -1979,6 +1988,15 @@ static unsigned int fp8_visibility(const struct kvm_vcpu *vcpu,
 	return REG_HIDDEN;
 }
 
+static unsigned int sme_raz_visibility(const struct kvm_vcpu *vcpu,
+				       const struct sys_reg_desc *rd)
+{
+	if (vcpu_has_sme(vcpu))
+		return REG_RAZ;
+
+	return REG_HIDDEN;
+}
+
 static u64 sanitise_id_aa64pfr0_el1(const struct kvm_vcpu *vcpu, u64 val)
 {
 	if (!vcpu_has_sve(vcpu))
@@ -3349,7 +3367,14 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 
 	{ SYS_DESC(SYS_ZCR_EL1), NULL, reset_val, ZCR_EL1, 0, .visibility = sve_visibility },
 	{ SYS_DESC(SYS_TRFCR_EL1), undef_access },
-	{ SYS_DESC(SYS_SMPRI_EL1), undef_access },
+
+	/*
+	 * SMPRI_EL1 is UNDEF when SME is disabled, the UNDEF is
+	 * handled via FGU which is handled without consulting this
+	 * table.
+	 */
+	{ SYS_DESC(SYS_SMPRI_EL1), trap_raz_wi, .visibility = sme_raz_visibility },
+
 	{ SYS_DESC(SYS_SMCR_EL1), NULL, reset_val, SMCR_EL1, 0, .visibility = sme_visibility },
 	{ SYS_DESC(SYS_TTBR0_EL1), access_vm_reg, reset_unknown, TTBR0_EL1 },
 	{ SYS_DESC(SYS_TTBR1_EL1), access_vm_reg, reset_unknown, TTBR1_EL1 },
@@ -3719,6 +3744,9 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 
 	EL2_REG_VNCR(HCRX_EL2, reset_val, 0),
 
+	{ SYS_DESC(SYS_SMPRIMAP_EL2), .reg = SMPRIMAP_EL2,
+	  .access = trap_raz_wi, .set_user = set_res0, .reset = reset_val,
+	  .val = 0, .visibility = sme_el2_visibility },
 	EL2_REG_FILTERED(SMCR_EL2, access_smcr_el2, reset_val, 0,
 			 sme_el2_visibility),
 

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:21:15 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:21:15 +0000
Subject: [PATCH v9 21/30] KVM: arm64: Flush register state on writes to
 SVCR.SM and SVCR.ZA
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-21-8be3867cb883@kernel.org>

Writes to the physical SVCR.SM and SVCR.ZA change the state of PSTATE.SM
and PSTATE.ZA, causing other floating point state to reset. Emulate this
behaviour for writes done via the KVM userspace ABI.

Setting PSTATE.ZA to 1 causes ZA and ZT0 to be reset to 0, these are stored
in sme_state. Setting PSTATE.ZA to 0 causes ZA and ZT0 to become inaccesible
so no reset is needed.

Any change in PSTATE.SM causes the V, Z, P, FFR and FPMR registers to be
reset to 0 and FPSR to be reset to 0x800009f.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 arch/arm64/include/asm/kvm_host.h | 24 ++++++++++++++++++++++++
 arch/arm64/kvm/sys_regs.c         | 29 ++++++++++++++++++++++++++++-
 2 files changed, 52 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 44595a789a97..bd7a9a4efbc3 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -1147,6 +1147,30 @@ struct kvm_vcpu_arch {
 
 #define vcpu_sve_state_size(vcpu) sve_state_size_from_vl((vcpu)->arch.max_vl[ARM64_VEC_SVE])
 
+#define vcpu_sme_state(vcpu) (kern_hyp_va((vcpu)->arch.sme_state))
+
+#define sme_state_size_from_vl(vl, sme2) ({				\
+	size_t __size_ret;						\
+	unsigned int __vq;						\
+									\
+	if (WARN_ON(!sve_vl_valid(vl))) {				\
+		__size_ret = 0;						\
+	} else {							\
+		__vq = sve_vq_from_vl(vl);				\
+		__size_ret = ZA_SIG_REGS_SIZE(__vq);			\
+		if (sme2)						\
+			__size_ret += ZT_SIG_REG_SIZE;			\
+	}								\
+									\
+	__size_ret;							\
+})
+
+#define vcpu_sme_state_size(vcpu) ({					\
+	unsigned long __vl;						\
+	__vl = (vcpu)->arch.max_vl[ARM64_VEC_SME];			\
+	sme_state_size_from_vl(__vl, vcpu_has_sme2(vcpu));		\
+})
+
 /*
  * Only use __vcpu_sys_reg/ctxt_sys_reg if you know you want the
  * memory backed version of a register, and not the one most recently
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 51f175bbe8d1..4ecfcb0af24c 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -927,6 +927,33 @@ static unsigned int hidden_visibility(const struct kvm_vcpu *vcpu,
 	return REG_HIDDEN;
 }
 
+static int set_svcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
+		    u64 val)
+{
+	u64 old = __vcpu_sys_reg(vcpu, rd->reg);
+
+	if (val & SVCR_RES0)
+		return -EINVAL;
+
+	if ((val & SVCR_ZA) && !(old & SVCR_ZA) && vcpu->arch.sme_state)
+		memset(vcpu->arch.sme_state, 0, vcpu_sme_state_size(vcpu));
+
+	if ((val & SVCR_SM) != (old & SVCR_SM)) {
+		memset(vcpu->arch.ctxt.fp_regs.vregs, 0,
+		       sizeof(vcpu->arch.ctxt.fp_regs.vregs));
+
+		if (vcpu->arch.sve_state)
+			memset(vcpu->arch.sve_state, 0,
+			       vcpu_sve_state_size(vcpu));
+
+		__vcpu_assign_sys_reg(vcpu, FPMR, 0);
+		vcpu->arch.ctxt.fp_regs.fpsr = 0x800009f;
+	}
+
+	__vcpu_assign_sys_reg(vcpu, rd->reg, val);
+	return 0;
+}
+
 static unsigned int pmu_visibility(const struct kvm_vcpu *vcpu,
 				   const struct sys_reg_desc *r)
 {
@@ -3512,7 +3539,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 		    CTR_EL0_DminLine_MASK |
 		    CTR_EL0_L1Ip_MASK |
 		    CTR_EL0_IminLine_MASK),
-	{ SYS_DESC(SYS_SVCR), undef_access, reset_val, SVCR, 0, .visibility = sme_visibility  },
+	{ SYS_DESC(SYS_SVCR), undef_access, reset_val, SVCR, 0, .visibility = sme_visibility, .set_user = set_svcr },
 	{ SYS_DESC(SYS_FPMR), undef_access, reset_val, FPMR, 0, .visibility = fp8_visibility },
 
 	{ PMU_SYS_REG(PMCR_EL0), .access = access_pmcr, .reset = reset_pmcr,

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:21:14 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:21:14 +0000
Subject: [PATCH v9 20/30] KVM: arm64: Support userspace access to streaming
 mode Z and P registers
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-20-8be3867cb883@kernel.org>

SME introduces a mode called streaming mode where the Z, P and optionally
FFR registers can be accessed using the SVE instructions but with the SME
vector length. Reflect this in the ABI for accessing the guest registers by
making the vector length for the vcpu reflect the vector length that would
be seen by the guest were it running, using the SME vector length when the
guest is configured for streaming mode.

Since SME may be present without SVE we also update the existing checks for
access to the Z, P and V registers to check for either SVE or streaming
mode. When not in streaming mode the guest floating point state may be
accessed via the V registers.

Any VMM that supports SME must be aware of the need to configure streaming
mode prior to writing the floating point registers that this creates.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 arch/arm64/kvm/guest.c | 38 ++++++++++++++++++++++++++++++++++----
 1 file changed, 34 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 2a1fdcb0ec49..90dcacb35f01 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -73,6 +73,11 @@ static u64 core_reg_offset_from_id(u64 id)
 	return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE);
 }
 
+static bool vcpu_has_sve_regs(const struct kvm_vcpu *vcpu)
+{
+	return vcpu_has_sve(vcpu) || vcpu_in_streaming_mode(vcpu);
+}
+
 static int core_reg_size_from_offset(const struct kvm_vcpu *vcpu, u64 off)
 {
 	int size;
@@ -110,9 +115,10 @@ static int core_reg_size_from_offset(const struct kvm_vcpu *vcpu, u64 off)
 	/*
 	 * The KVM_REG_ARM64_SVE regs must be used instead of
 	 * KVM_REG_ARM_CORE for accessing the FPSIMD V-registers on
-	 * SVE-enabled vcpus:
+	 * SVE-enabled vcpus or when a SME enabled vcpu is in
+	 * streaming mode:
 	 */
-	if (vcpu_has_sve(vcpu) && core_reg_offset_is_vreg(off))
+	if (vcpu_has_sve_regs(vcpu) && core_reg_offset_is_vreg(off))
 		return -EINVAL;
 
 	return size;
@@ -426,6 +432,24 @@ struct vec_state_reg_region {
 	unsigned int upad;	/* extra trailing padding in user memory */
 };
 
+/*
+ * We represent the Z and P registers to userspace using either the
+ * SVE or SME vector length, depending on which features the guest has
+ * and if the guest is in streaming mode.
+ */
+static unsigned int vcpu_sve_cur_vq(struct kvm_vcpu *vcpu)
+{
+	unsigned int vq = 0;
+
+	if (vcpu_has_sve(vcpu))
+		vq = vcpu_sve_max_vq(vcpu);
+
+	if (vcpu_in_streaming_mode(vcpu))
+		vq = vcpu_sme_max_vq(vcpu);
+
+	return vq;
+}
+
 /*
  * Validate SVE register ID and get sanitised bounds for user/kernel SVE
  * register copy
@@ -466,7 +490,7 @@ static int sve_reg_to_region(struct vec_state_reg_region *region,
 		if (!vcpu_has_sve(vcpu) || (reg->id & SVE_REG_SLICE_MASK) > 0)
 			return -ENOENT;
 
-		vq = vcpu_sve_max_vq(vcpu);
+		vq = vcpu_sve_cur_vq(vcpu);
 
 		reqoffset = SVE_SIG_ZREG_OFFSET(vq, reg_num) -
 				SVE_SIG_REGS_OFFSET;
@@ -476,7 +500,7 @@ static int sve_reg_to_region(struct vec_state_reg_region *region,
 		if (!vcpu_has_sve(vcpu) || (reg->id & SVE_REG_SLICE_MASK) > 0)
 			return -ENOENT;
 
-		vq = vcpu_sve_max_vq(vcpu);
+		vq = vcpu_sve_cur_vq(vcpu);
 
 		reqoffset = SVE_SIG_PREG_OFFSET(vq, reg_num) -
 				SVE_SIG_REGS_OFFSET;
@@ -515,6 +539,9 @@ static int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	if (!kvm_arm_vcpu_vec_finalized(vcpu))
 		return -EPERM;
 
+	if (!vcpu_has_sve_regs(vcpu))
+		return -EBUSY;
+
 	if (copy_to_user(uptr, vcpu->arch.sve_state + region.koffset,
 			 region.klen) ||
 	    clear_user(uptr + region.klen, region.upad))
@@ -541,6 +568,9 @@ static int set_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	if (!kvm_arm_vcpu_vec_finalized(vcpu))
 		return -EPERM;
 
+	if (!vcpu_has_sve_regs(vcpu))
+		return -EBUSY;
+
 	if (copy_from_user(vcpu->arch.sve_state + region.koffset, uptr,
 			   region.klen))
 		return -EFAULT;

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:21:16 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:21:16 +0000
Subject: [PATCH v9 22/30] KVM: arm64: Expose SME specific state to
 userspace
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-22-8be3867cb883@kernel.org>

SME introduces two new registers, the ZA matrix register and the ZT0 LUT
register.  Both of these registers are only accessible when PSTATE.ZA is
set and ZT0 is only present if SME2 is enabled for the guest. Provide
support for configuring these from VMMs.

The ZA matrix is a single SVL*SVL register which is available when
PSTATE.ZA is set. We follow the pattern established by the architecture
itself and expose this to userspace as a series of horizontal SVE vectors
with the streaming mode vector length, using the format already established
for the SVE vectors themselves.

ZT0 is a single register with a refreshingly fixed size 512 bit register
which is like ZA accessible only when PSTATE.ZA is set. Add support for it
to the userspace API, as with ZA we allow the register to be read or written
regardless of the state of PSTATE.ZA in order to simplify userspace usage.
The value will be reset to 0 whenever PSTATE.ZA changes from 0 to 1,
userspace can read stale values but these are not observable by the guest
without manipulation of PSTATE.ZA by userspace.

While there is currently only one ZT register the naming as ZT0 and the
instruction encoding clearly leave room for future extensions adding more
ZT registers. This encoding can readily support such an extension if one is
introduced.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 arch/arm64/include/uapi/asm/kvm.h |  17 ++++++
 arch/arm64/kvm/guest.c            | 114 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 129 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 498a49a61487..9a19cc58d227 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -357,6 +357,23 @@ struct kvm_arm_counter_offset {
 /* SME registers */
 #define KVM_REG_ARM64_SME		(0x17 << KVM_REG_ARM_COPROC_SHIFT)
 
+#define KVM_ARM64_SME_VQ_MIN __SVE_VQ_MIN
+#define KVM_ARM64_SME_VQ_MAX __SVE_VQ_MAX
+
+/* ZA and ZTn occupy blocks at the following offsets within this range: */
+#define KVM_REG_ARM64_SME_ZA_BASE	0
+#define KVM_REG_ARM64_SME_ZT_BASE	0x600
+
+#define KVM_ARM64_SME_MAX_ZAHREG	(__SVE_VQ_BYTES * KVM_ARM64_SME_VQ_MAX)
+
+#define KVM_REG_ARM64_SME_ZAHREG(n, i)					\
+	(KVM_REG_ARM64 | KVM_REG_ARM64_SME | KVM_REG_ARM64_SME_ZA_BASE | \
+	 KVM_REG_SIZE_U2048 |						\
+	 (((n) & (KVM_ARM64_SME_MAX_ZAHREG - 1)) << 5) |		\
+	 ((i) & (KVM_ARM64_SVE_MAX_SLICES - 1)))
+
+#define KVM_REG_ARM64_SME_ZTREG_SIZE	(512 / 8)
+
 /* Vector lengths pseudo-register: */
 #define KVM_REG_ARM64_SME_VLS		(KVM_REG_ARM64 | KVM_REG_ARM64_SME | \
 					 KVM_REG_SIZE_U512 | 0xfffe)
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 90dcacb35f01..d4e30eb57a9c 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -594,23 +594,133 @@ static int set_sme_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	return set_vec_vls(ARM64_VEC_SME, vcpu, reg);
 }
 
+/*
+ * Validate SVE register ID and get sanitised bounds for user/kernel SVE
+ * register copy
+ */
+static int sme_reg_to_region(struct vec_state_reg_region *region,
+			     struct kvm_vcpu *vcpu,
+			     const struct kvm_one_reg *reg)
+{
+	/* reg ID ranges for ZA.H[n] registers */
+	unsigned int vq = vcpu_sme_max_vq(vcpu) - 1;
+	const u64 za_h_max = vq * __SVE_VQ_BYTES;
+	const u64 zah_id_min = KVM_REG_ARM64_SME_ZAHREG(0, 0);
+	const u64 zah_id_max = KVM_REG_ARM64_SME_ZAHREG(za_h_max - 1,
+						       SVE_NUM_SLICES - 1);
+	unsigned int reg_num;
+
+	unsigned int reqoffset, reqlen; /* User-requested offset and length */
+	unsigned int maxlen; /* Maximum permitted length */
+
+	size_t sme_state_size;
+
+	reg_num = (reg->id & SVE_REG_ID_MASK) >> SVE_REG_ID_SHIFT;
+
+	if (reg->id >= zah_id_min && reg->id <= zah_id_max) {
+		if (!vcpu_has_sme(vcpu) || (reg->id & SVE_REG_SLICE_MASK) > 0)
+			return -ENOENT;
+
+		/* ZA is exposed as SVE vectors ZA.H[n] */
+		reqoffset = ZA_SIG_ZAV_OFFSET(vq, reg_num) -
+			ZA_SIG_REGS_OFFSET;
+		reqlen = KVM_SVE_ZREG_SIZE;
+		maxlen = SVE_SIG_ZREG_SIZE(vq);
+	} else if (reg->id == KVM_REG_ARM64_SME_ZT_BASE) {
+		/* ZA is exposed as SVE vectors ZA.H[n] */
+		if (!kvm_has_feat(vcpu->kvm, ID_AA64PFR1_EL1, SME, SME2) ||
+		    (reg->id & SVE_REG_SLICE_MASK) > 0 ||
+		    reg_num > 0)
+			return -ENOENT;
+
+		/* ZT0 is stored after ZA */
+		reqlen = KVM_REG_ARM64_SME_ZTREG_SIZE;
+		maxlen = KVM_REG_ARM64_SME_ZTREG_SIZE;
+	} else {
+		return -EINVAL;
+	}
+
+	sme_state_size = vcpu_sme_state_size(vcpu);
+	if (WARN_ON(!sme_state_size))
+		return -EINVAL;
+
+	region->koffset = array_index_nospec(reqoffset, sme_state_size);
+	region->klen = min(maxlen, reqlen);
+	region->upad = reqlen - region->klen;
+
+	return 0;
+}
+
+/*
+ * ZA is exposed as an array of horizontal vectors with the same
+ * format as SVE, mirroring the architecture's LDR ZA[Wv, offs], [Xn]
+ * instruction.
+ */
+
 static int get_sme_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 {
+	int ret;
+	struct vec_state_reg_region region;
+	char __user *uptr = (char __user *)reg->addr;
+
 	/* Handle the KVM_REG_ARM64_SME_VLS pseudo-reg as a special case: */
 	if (reg->id == KVM_REG_ARM64_SME_VLS)
 		return get_sme_vls(vcpu, reg);
 
-	return -EINVAL;
+	/* Try to interpret reg ID as an architectural SME register... */
+	ret = sme_reg_to_region(&region, vcpu, reg);
+	if (ret)
+		return ret;
+
+	if (!kvm_arm_vcpu_vec_finalized(vcpu))
+		return -EPERM;
+
+	/*
+	 * None of the SME specific registers are accessible unless
+	 * PSTATE.ZA is set.
+	 */
+	if (!vcpu_za_enabled(vcpu))
+		return -EINVAL;
+
+	if (copy_from_user(vcpu->arch.sme_state + region.koffset, uptr,
+			   region.klen))
+		return -EFAULT;
+
+	return 0;
 }
 
 static int set_sme_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 {
+	int ret;
+	struct vec_state_reg_region region;
+	char __user *uptr = (char __user *)reg->addr;
+
 	/* Handle the KVM_REG_ARM64_SME_VLS pseudo-reg as a special case: */
 	if (reg->id == KVM_REG_ARM64_SME_VLS)
 		return set_sme_vls(vcpu, reg);
 
-	return -EINVAL;
+	/* Try to interpret reg ID as an architectural SME register... */
+	ret = sme_reg_to_region(&region, vcpu, reg);
+	if (ret)
+		return ret;
+
+	if (!kvm_arm_vcpu_vec_finalized(vcpu))
+		return -EPERM;
+
+	/*
+	 * None of the SME specific registers are accessible unless
+	 * PSTATE.ZA is set.
+	 */
+	if (!vcpu_za_enabled(vcpu))
+		return -EINVAL;
+
+	if (copy_from_user(vcpu->arch.sme_state + region.koffset, uptr,
+			   region.klen))
+		return -EFAULT;
+
+	return 0;
 }
+
 int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
 	return -EINVAL;

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:21:17 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:21:17 +0000
Subject: [PATCH v9 23/30] KVM: arm64: Context switch SME state for guests
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-23-8be3867cb883@kernel.org>

If the guest has SME state we need to context switch that state, provide
support for that for normal guests.

SME has three sets of registers, ZA, ZT (only present for SME2) and also
streaming SVE which replaces the standard floating point registers when
active. The first two are fairly straightforward, they are accessible only
when PSTATE.ZA is set and we can reuse the assembly from the host to save
and load them from a single contiguous buffer. When PSTATE.ZA is not set
then these registers are inaccessible, when the guest enables PSTATE.ZA
all bits will be set to 0 by that and nothing is required on restore.

Streaming mode is slightly more complicated, when enabled via PSTATE.SM it
provides a version of the SVE registers using the SME vector length and may
optionally omit the FFR register. SME may also be present without SVE. The
register state is stored in sve_state as for non-streaming SVE mode, we
make an initial selection of registers to update based on the guest SVE
support and then override this when loading SVCR if streaming mode is
enabled.

A further complication is that when the hardware is in streaming mode
guest operations that are invalid in in streaming mode will generate SME
exceptions. There are also subfeature exceptions for SME2 controlled via
SMCR which generate distinct exception codes. In many situations these
exceptions are routed directly to the lower ELs with no opportunity for
the hypervisor to intercept. So that guests do not see unexpected
exception types due to the actual hardware configuration not being what
the guest configured we update the SMCRs and SVCR even if the guest does
not own the registers.

Since in order to avoid duplication with SME we now restore the register
state outside of the SVE specific restore function we need to move the
restore of the effective VL for nested guests to a separate restore
function run after loading the floating point register state, along with
the similar handling required for SME.

The selection of which vector length to use is handled by vcpu_sve_pffr().

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 arch/arm64/include/asm/fpsimd.h         |  10 +++
 arch/arm64/include/asm/kvm_emulate.h    |   6 ++
 arch/arm64/include/asm/kvm_host.h       |   4 +
 arch/arm64/kvm/fpsimd.c                 |  25 ++++--
 arch/arm64/kvm/hyp/include/hyp/switch.h | 151 ++++++++++++++++++++++++++++++--
 arch/arm64/kvm/hyp/nvhe/hyp-main.c      |  80 +++++++++++++++--
 6 files changed, 255 insertions(+), 21 deletions(-)

diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index 8b0840bd7e14..8642efbdcb2b 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -442,6 +442,15 @@ static inline size_t sme_state_size(struct task_struct const *task)
 			write_sysreg_s(__new, (reg));		\
 	} while (0)
 
+#define sme_cond_update_smcr_vq(val, reg)			\
+	do {							\
+		u64 __smcr = read_sysreg_s((reg));		\
+		u64 __new = __smcr & ~SMCR_ELx_LEN_MASK;	\
+		__new |= (val) & SMCR_ELx_LEN_MASK;		\
+		if (__smcr != __new)				\
+			write_sysreg_s(__new, (reg));		\
+	} while (0)
+
 #else
 
 static inline void sme_user_disable(void) { BUILD_BUG(); }
@@ -471,6 +480,7 @@ static inline size_t sme_state_size(struct task_struct const *task)
 }
 
 #define sme_cond_update_smcr(val, fa64, zt0, reg) do { } while (0)
+#define sme_cond_update_smcr_vq(val, reg) do { } while (0)
 
 #endif /* ! CONFIG_ARM64_SME */
 
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index c9eab316398e..1b0ebe480e19 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -696,4 +696,10 @@ static inline void vcpu_set_hcrx(struct kvm_vcpu *vcpu)
 			vcpu->arch.hcrx_el2 |= HCRX_EL2_SCTLR2En;
 	}
 }
+
+static inline bool guest_hyp_sme_traps_enabled(const struct kvm_vcpu *vcpu)
+{
+	return __guest_hyp_cptr_xen_trap_enabled(vcpu, SMEN);
+}
+
 #endif /* __ARM64_KVM_EMULATE_H__ */
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index bd7a9a4efbc3..bceaf0608d75 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -736,6 +736,7 @@ struct kvm_host_data {
 
 	/* Used by pKVM only. */
 	u64	fpmr;
+	u64	smcr_el1;
 
 	/* Ownership of the FP regs */
 	enum {
@@ -1131,6 +1132,9 @@ struct kvm_vcpu_arch {
 #define vcpu_sve_zcr_elx(vcpu)						\
 	(unlikely(is_hyp_ctxt(vcpu)) ? ZCR_EL2 : ZCR_EL1)
 
+#define vcpu_sme_smcr_elx(vcpu)						\
+	(unlikely(is_hyp_ctxt(vcpu)) ? SMCR_EL2 : SMCR_EL1)
+
 #define sve_state_size_from_vl(sve_max_vl) ({				\
 	size_t __size_ret;						\
 	unsigned int __vq;						\
diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c
index 1f4fcc8b5554..8fb8c55e50b3 100644
--- a/arch/arm64/kvm/fpsimd.c
+++ b/arch/arm64/kvm/fpsimd.c
@@ -69,19 +69,25 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
 	WARN_ON_ONCE(!irqs_disabled());
 
 	if (guest_owns_fp_regs()) {
-		/*
-		 * Currently we do not support SME guests so SVCR is
-		 * always 0 and we just need a variable to point to.
-		 */
 		fp_state.st = &vcpu->arch.ctxt.fp_regs;
 		fp_state.sve_state = vcpu->arch.sve_state;
 		fp_state.sve_vl = vcpu->arch.max_vl[ARM64_VEC_SVE];
-		fp_state.sme_state = NULL;
+		fp_state.sme_state = vcpu->arch.sme_state;
+		fp_state.sme_vl = vcpu->arch.max_vl[ARM64_VEC_SME];
 		fp_state.svcr = __ctxt_sys_reg(&vcpu->arch.ctxt, SVCR);
 		fp_state.fpmr = __ctxt_sys_reg(&vcpu->arch.ctxt, FPMR);
 		fp_state.fp_type = &vcpu->arch.fp_type;
+
 		fp_state.sme_features = 0;
+		if (kvm_has_fa64(vcpu->kvm))
+			fp_state.sme_features |= SMCR_ELx_FA64;
+		if (kvm_has_sme2(vcpu->kvm))
+			fp_state.sme_features |= SMCR_ELx_EZT0;
 
+		/*
+		 * For SME only hosts fpsimd_save() will override the
+		 * state selection if we are in streaming mode.
+		 */
 		if (vcpu_has_sve(vcpu))
 			fp_state.to_save = FP_STATE_SVE;
 		else
@@ -90,6 +96,15 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
 		fpsimd_bind_state_to_cpu(&fp_state);
 
 		clear_thread_flag(TIF_FOREIGN_FPSTATE);
+	} else {
+		/*
+		 * We might have enabled SME to configure traps but
+		 * insist the host doesn't run the hypervisor with SME
+		 * enabled, ensure it's disabled again.
+		 */
+		if (system_supports_sme()) {
+			sme_smstop();
+		}
 	}
 }
 
diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index 9ce53524d664..5bcc72ae48ff 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -431,6 +431,22 @@ static inline bool kvm_hyp_handle_mops(struct kvm_vcpu *vcpu, u64 *exit_code)
 	return true;
 }
 
+static inline void __hyp_sme_restore_guest(struct kvm_vcpu *vcpu,
+					   bool *restore_sve,
+					   bool *restore_ffr)
+{
+	bool has_fa64 = vcpu_has_fa64(vcpu);
+	bool has_sme2 = vcpu_has_sme2(vcpu);
+
+	if (vcpu_in_streaming_mode(vcpu)) {
+		*restore_sve = true;
+		*restore_ffr = has_fa64;
+	}
+
+	if (vcpu_za_enabled(vcpu))
+		__sme_restore_state(vcpu_sme_state(vcpu), has_sme2);
+}
+
 static inline void __hyp_sve_restore_guest(struct kvm_vcpu *vcpu)
 {
 	/*
@@ -438,19 +454,25 @@ static inline void __hyp_sve_restore_guest(struct kvm_vcpu *vcpu)
 	 * vCPU. Start off with the max VL so we can load the SVE state.
 	 */
 	sve_cond_update_zcr_vq(vcpu_sve_max_vq(vcpu) - 1, SYS_ZCR_EL2);
-	__sve_restore_state(vcpu_sve_pffr(vcpu),
-			    &vcpu->arch.ctxt.fp_regs.fpsr,
-			    true);
 
+	write_sysreg_el1(__vcpu_sys_reg(vcpu, vcpu_sve_zcr_elx(vcpu)), SYS_ZCR);
+}
+
+static inline void __hyp_nv_restore_guest_vls(struct kvm_vcpu *vcpu)
+{
 	/*
 	 * The effective VL for a VM could differ from the max VL when running a
 	 * nested guest, as the guest hypervisor could select a smaller VL. Slap
 	 * that into hardware before wrapping up.
 	 */
-	if (is_nested_ctxt(vcpu))
+	if (!is_nested_ctxt(vcpu))
+		return;
+
+	if (vcpu_has_sve(vcpu))
 		sve_cond_update_zcr_vq(__vcpu_sys_reg(vcpu, ZCR_EL2), SYS_ZCR_EL2);
 
-	write_sysreg_el1(__vcpu_sys_reg(vcpu, vcpu_sve_zcr_elx(vcpu)), SYS_ZCR);
+	if (vcpu_has_sme(vcpu))
+		sme_cond_update_smcr_vq(__vcpu_sys_reg(vcpu, SMCR_EL2), SYS_SMCR_EL2);
 }
 
 static inline void __hyp_sve_save_host(void)
@@ -464,10 +486,46 @@ static inline void __hyp_sve_save_host(void)
 			 true);
 }
 
+static inline void kvm_sme_configure_traps(struct kvm_vcpu *vcpu)
+{
+	u64 smcr_el1, smcr_el2;
+	u64 svcr;
+
+	if (!vcpu_has_sme(vcpu))
+		return;
+
+	/* A guest hypervisor may restrict the effective max VL. */
+	if (is_nested_ctxt(vcpu))
+		smcr_el2 = __vcpu_sys_reg(vcpu, SMCR_EL2);
+	else
+		smcr_el2 = vcpu_sme_max_vq(vcpu) - 1;
+
+	if (vcpu_has_fa64(vcpu))
+		smcr_el2 |= SMCR_ELx_FA64;
+	if (vcpu_has_sme2(vcpu))
+		smcr_el2 |= SMCR_ELx_EZT0;
+
+	write_sysreg_el2(smcr_el2, SYS_SMCR);
+
+	smcr_el1 = __vcpu_sys_reg(vcpu, vcpu_sme_smcr_elx(vcpu));
+	write_sysreg_el1(smcr_el1, SYS_SMCR);
+
+	svcr = __vcpu_sys_reg(vcpu, SVCR);
+	write_sysreg_s(svcr, SYS_SVCR);
+}
+
 static inline void fpsimd_lazy_switch_to_guest(struct kvm_vcpu *vcpu)
 {
 	u64 zcr_el1, zcr_el2;
 
+	/*
+	 * We always load the SME control registers that affect traps
+	 * since if they are not configured as expected by the guest
+	 * then it may have exceptions that it does not expect
+	 * directly delivered.
+	 */
+	kvm_sme_configure_traps(vcpu);
+
 	if (!guest_owns_fp_regs())
 		return;
 
@@ -487,8 +545,51 @@ static inline void fpsimd_lazy_switch_to_guest(struct kvm_vcpu *vcpu)
 
 static inline void fpsimd_lazy_switch_to_host(struct kvm_vcpu *vcpu)
 {
+	u64 smcr_el1, smcr_el2;
 	u64 zcr_el1, zcr_el2;
 
+	/*
+	 * We always load the control registers for the guest so we
+	 * always restore state for the host.
+	 */
+	if (vcpu_has_sme(vcpu)) {
+		/*
+		 * __deactivate_cptr_traps() disabled traps, but there
+		 * hasn't necessarily been a context synchronization
+		 * event yet.
+		 */
+		isb();
+
+		smcr_el1 = read_sysreg_el1(SYS_SMCR);
+		__vcpu_assign_sys_reg(vcpu, vcpu_sme_smcr_elx(vcpu), smcr_el1);
+
+		smcr_el2 = 0;
+		if (system_supports_fa64())
+			smcr_el2 |= SMCR_ELx_FA64;
+		if (system_supports_sme2())
+			smcr_el2 |= SMCR_ELx_EZT0;
+
+		/*
+		 * The guest's state is always saved using the guest's max VL.
+		 * Ensure that the host has the guest's max VL active such that
+		 * the host can save the guest's state lazily, but don't
+		 * artificially restrict the host to the guest's max VL.
+		 */
+		if (has_vhe()) {
+			smcr_el2 |= vcpu_sme_max_vq(vcpu) - 1;
+			write_sysreg_el2(smcr_el2, SYS_SMCR);
+		} else {
+			smcr_el1 = smcr_el2;
+			smcr_el2 |= sve_vq_from_vl(kvm_host_max_vl[ARM64_VEC_SME]) - 1;
+			write_sysreg_el2(smcr_el2, SYS_SMCR);
+
+			smcr_el1 |= vcpu_sve_max_vq(vcpu) - 1;
+			write_sysreg_el1(smcr_el1, SYS_SMCR);
+		}
+
+		__vcpu_assign_sys_reg(vcpu, SVCR, read_sysreg_s(SYS_SVCR));
+	}
+
 	if (!guest_owns_fp_regs())
 		return;
 
@@ -525,6 +626,16 @@ static inline void fpsimd_lazy_switch_to_host(struct kvm_vcpu *vcpu)
 
 static void kvm_hyp_save_fpsimd_host(struct kvm_vcpu *vcpu)
 {
+	/*
+	 * The hypervisor refuses to run if streaming mode or ZA is
+	 * enabled, we only need to save SMCR_EL1 for SME.  For pKVM
+	 * we will restore this, reset SMCR_EL2 to a fixed value and
+	 * disable streaming mode and ZA to avoid any state being
+	 * leaked.
+	 */
+	if (system_supports_sme())
+		*host_data_ptr(smcr_el1) = read_sysreg_el1(SYS_SMCR);
+
 	/*
 	 * Non-protected kvm relies on the host restoring its sve state.
 	 * Protected kvm restores the host's sve state as not to reveal that
@@ -549,14 +660,17 @@ static void kvm_hyp_save_fpsimd_host(struct kvm_vcpu *vcpu)
  */
 static inline bool kvm_hyp_handle_fpsimd(struct kvm_vcpu *vcpu, u64 *exit_code)
 {
-	bool sve_guest;
-	u8 esr_ec;
+	bool restore_sve, restore_ffr;
+	bool sve_guest, sme_guest;
+	u8 esr_ec, esr_iss_smtc;
 
 	if (!system_supports_fpsimd())
 		return false;
 
 	sve_guest = vcpu_has_sve(vcpu);
+	sme_guest = vcpu_has_sme(vcpu);
 	esr_ec = kvm_vcpu_trap_get_class(vcpu);
+	esr_iss_smtc = ESR_ELx_SME_ISS_SMTC((kvm_vcpu_get_esr(vcpu)));
 
 	/* Only handle traps the vCPU can support here: */
 	switch (esr_ec) {
@@ -575,6 +689,15 @@ static inline bool kvm_hyp_handle_fpsimd(struct kvm_vcpu *vcpu, u64 *exit_code)
 		if (guest_hyp_sve_traps_enabled(vcpu))
 			return false;
 		break;
+	case ESR_ELx_EC_SME:
+		if (!sme_guest)
+			return false;
+		if (guest_hyp_sme_traps_enabled(vcpu))
+			return false;
+		if (!kvm_has_sme2(vcpu->kvm) &&
+		    (esr_iss_smtc == ESR_ELx_SME_ISS_SMTC_ZT_DISABLED))
+			return false;
+		break;
 	default:
 		return false;
 	}
@@ -590,8 +713,20 @@ static inline bool kvm_hyp_handle_fpsimd(struct kvm_vcpu *vcpu, u64 *exit_code)
 		kvm_hyp_save_fpsimd_host(vcpu);
 
 	/* Restore the guest state */
+
+	/* These may be overridden for a SME guest */
+	restore_sve = sve_guest;
+	restore_ffr = sve_guest;
+
 	if (sve_guest)
 		__hyp_sve_restore_guest(vcpu);
+	if (sme_guest)
+		__hyp_sme_restore_guest(vcpu, &restore_sve, &restore_ffr);
+
+	if (restore_sve)
+		__sve_restore_state(vcpu_sve_pffr(vcpu),
+				    &vcpu->arch.ctxt.fp_regs.fpsr,
+				    restore_ffr);
 	else
 		__fpsimd_restore_state(&vcpu->arch.ctxt.fp_regs);
 
@@ -602,6 +737,8 @@ static inline bool kvm_hyp_handle_fpsimd(struct kvm_vcpu *vcpu, u64 *exit_code)
 	if (!(read_sysreg(hcr_el2) & HCR_RW))
 		write_sysreg(__vcpu_sys_reg(vcpu, FPEXC32_EL2), fpexc32_el2);
 
+	__hyp_nv_restore_guest_vls(vcpu);
+
 	*host_data_ptr(fp_owner) = FP_STATE_GUEST_OWNED;
 
 	/*
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 208e9042aca4..bd48e149764c 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -26,14 +26,17 @@ void __kvm_hyp_host_forward_smc(struct kvm_cpu_context *host_ctxt);
 
 static void __hyp_sve_save_guest(struct kvm_vcpu *vcpu)
 {
+	bool save_ffr = !vcpu_in_streaming_mode(vcpu) || vcpu_has_fa64(vcpu);
+
 	__vcpu_assign_sys_reg(vcpu, ZCR_EL1, read_sysreg_el1(SYS_ZCR));
+
 	/*
 	 * On saving/restoring guest sve state, always use the maximum VL for
 	 * the guest. The layout of the data when saving the sve state depends
 	 * on the VL, so use a consistent (i.e., the maximum) guest VL.
 	 */
 	sve_cond_update_zcr_vq(vcpu_sve_max_vq(vcpu) - 1, SYS_ZCR_EL2);
-	__sve_save_state(vcpu_sve_pffr(vcpu), &vcpu->arch.ctxt.fp_regs.fpsr, true);
+	__sve_save_state(vcpu_sve_pffr(vcpu), &vcpu->arch.ctxt.fp_regs.fpsr, save_ffr);
 	write_sysreg_s(sve_vq_from_vl(kvm_host_max_vl[ARM64_VEC_SVE]) - 1, SYS_ZCR_EL2);
 }
 
@@ -57,9 +60,63 @@ static void __hyp_sve_restore_host(void)
 	write_sysreg_el1(sve_state->zcr_el1, SYS_ZCR);
 }
 
-static void fpsimd_sve_flush(void)
+static void __hyp_sme_save_guest(struct kvm_vcpu *vcpu)
 {
-	*host_data_ptr(fp_owner) = FP_STATE_HOST_OWNED;
+	__vcpu_assign_sys_reg(vcpu, SMCR_EL1, read_sysreg_el1(SYS_SMCR));
+	__vcpu_assign_sys_reg(vcpu, SVCR, read_sysreg_s(SYS_SVCR));
+
+	/*
+	 * On saving/restoring guest sve state, always use the maximum VL for
+	 * the guest. The layout of the data when saving the sve state depends
+	 * on the VL, so use a consistent (i.e., the maximum) guest VL.
+	 *
+	 * We restore the FA64 and SME2 enables for the host since we
+	 * will always restore the host configuration so if host and
+	 * guest VLs are the same we might suppress an update.
+	 */
+	sme_cond_update_smcr(vcpu_sme_max_vq(vcpu) - 1, system_supports_fa64(),
+			     system_supports_sme2(), SYS_SMCR_EL2);
+
+	if (vcpu_za_enabled(vcpu))
+		__sme_save_state(vcpu_sme_state(vcpu), vcpu_has_sme2(vcpu));
+}
+
+static void __hyp_sme_restore_host(void)
+{
+	/*
+	 * The hypervisor refuses to run if we are in streaming mode
+	 * or have ZA enabled so there is no SME specific state to
+	 * restore other than the system registers.
+	 *
+	 * Note that this constrains the PE to the maximum shared VL
+	 * that was discovered, if we wish to use larger VLs this will
+	 * need to be revisited.
+	 */
+	sme_cond_update_smcr(sve_vq_from_vl(kvm_host_max_vl[ARM64_VEC_SME]) - 1,
+			     cpus_have_final_cap(ARM64_SME_FA64),
+			     cpus_have_final_cap(ARM64_SME2), SYS_SMCR_EL2);
+
+	write_sysreg_el1(*host_data_ptr(smcr_el1), SYS_SMCR);
+
+	sme_smstop();
+}
+
+static void fpsimd_sve_flush(struct kvm_vcpu *vcpu)
+{
+	/*
+	 * If the guest has SME then we need to restore the trap
+	 * controls in SMCR and mode in SVCR in order to ensure that
+	 * traps generated directly to EL1 have the correct types,
+	 * otherwise we can defer until we load the guest state.
+	 */
+	if (vcpu_has_sme(vcpu)) {
+		kvm_hyp_save_fpsimd_host(vcpu);
+		kvm_sme_configure_traps(vcpu);
+
+		*host_data_ptr(fp_owner) = FP_STATE_FREE;
+	} else {
+		*host_data_ptr(fp_owner) = FP_STATE_HOST_OWNED;
+	}
 }
 
 static void fpsimd_sve_sync(struct kvm_vcpu *vcpu)
@@ -75,7 +132,10 @@ static void fpsimd_sve_sync(struct kvm_vcpu *vcpu)
 	 */
 	isb();
 
-	if (vcpu_has_sve(vcpu))
+	if (vcpu_has_sme(vcpu))
+		__hyp_sme_save_guest(vcpu);
+
+	if (vcpu_has_sve(vcpu) || vcpu_in_streaming_mode(vcpu))
 		__hyp_sve_save_guest(vcpu);
 	else
 		__fpsimd_save_state(&vcpu->arch.ctxt.fp_regs);
@@ -84,6 +144,9 @@ static void fpsimd_sve_sync(struct kvm_vcpu *vcpu)
 	if (has_fpmr)
 		__vcpu_assign_sys_reg(vcpu, FPMR, read_sysreg_s(SYS_FPMR));
 
+	if (system_supports_sme())
+		__hyp_sme_restore_host();
+
 	if (system_supports_sve())
 		__hyp_sve_restore_host();
 	else
@@ -121,7 +184,7 @@ static void flush_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu)
 {
 	struct kvm_vcpu *host_vcpu = hyp_vcpu->host_vcpu;
 
-	fpsimd_sve_flush();
+	fpsimd_sve_flush(host_vcpu);
 	flush_debug_state(hyp_vcpu);
 
 	hyp_vcpu->vcpu.arch.ctxt	= host_vcpu->arch.ctxt;
@@ -204,10 +267,9 @@ static void handle___kvm_vcpu_run(struct kvm_cpu_context *host_ctxt)
 		struct pkvm_hyp_vcpu *hyp_vcpu = pkvm_get_loaded_hyp_vcpu();
 
 		/*
-		 * KVM (and pKVM) doesn't support SME guests for now, and
-		 * ensures that SME features aren't enabled in pstate when
-		 * loading a vcpu. Therefore, if SME features enabled the host
-		 * is misbehaving.
+		 * KVM (and pKVM) refuses to run if PSTATE.{SM,ZA} are
+		 * enabled. Therefore, if SME features enabled the
+		 * host is misbehaving.
 		 */
 		if (unlikely(system_supports_sme() && read_sysreg_s(SYS_SVCR))) {
 			ret = -EINVAL;

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:21:18 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:21:18 +0000
Subject: [PATCH v9 24/30] KVM: arm64: Handle SME exceptions
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-24-8be3867cb883@kernel.org>

The access control for SME follows the same structure as for the base FP
and SVE extensions, with control being via CPACR_ELx.SMEN and CPTR_EL2.TSM
mirroring the equivalent FPSIMD and SVE controls in those registers. Add
handling for these controls and exceptions mirroring the existing handling
for FPSIMD and SVE.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 arch/arm64/kvm/handle_exit.c            | 14 ++++++++++++++
 arch/arm64/kvm/hyp/include/hyp/switch.h | 11 ++++++-----
 arch/arm64/kvm/hyp/nvhe/switch.c        |  4 +++-
 arch/arm64/kvm/hyp/vhe/switch.c         | 17 ++++++++++++-----
 4 files changed, 35 insertions(+), 11 deletions(-)

diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index cc7d5d1709cb..1e54d5d722e4 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -237,6 +237,19 @@ static int handle_sve(struct kvm_vcpu *vcpu)
 	return 1;
 }
 
+/*
+ * Guest access to SME registers should be routed to this handler only
+ * when the system doesn't support SME.
+ */
+static int handle_sme(struct kvm_vcpu *vcpu)
+{
+	if (guest_hyp_sme_traps_enabled(vcpu))
+		return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_esr(vcpu));
+
+	kvm_inject_undefined(vcpu);
+	return 1;
+}
+
 /*
  * Two possibilities to handle a trapping ptrauth instruction:
  *
@@ -390,6 +403,7 @@ static exit_handle_fn arm_exit_handlers[] = {
 	[ESR_ELx_EC_SVC64]	= handle_svc,
 	[ESR_ELx_EC_SYS64]	= kvm_handle_sys_reg,
 	[ESR_ELx_EC_SVE]	= handle_sve,
+	[ESR_ELx_EC_SME]	= handle_sme,
 	[ESR_ELx_EC_ERET]	= kvm_handle_eret,
 	[ESR_ELx_EC_IABT_LOW]	= kvm_handle_guest_abort,
 	[ESR_ELx_EC_DABT_LOW]	= kvm_handle_guest_abort,
diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index 5bcc72ae48ff..ad88cc7bd5d3 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -69,11 +69,8 @@ static inline void __activate_cptr_traps_nvhe(struct kvm_vcpu *vcpu)
 {
 	u64 val = CPTR_NVHE_EL2_RES1 | CPTR_EL2_TAM | CPTR_EL2_TTA;
 
-	/*
-	 * Always trap SME since it's not supported in KVM.
-	 * TSM is RES1 if SME isn't implemented.
-	 */
-	val |= CPTR_EL2_TSM;
+	if (!vcpu_has_sme(vcpu) || !guest_owns_fp_regs())
+		val |= CPTR_EL2_TSM;
 
 	if (!vcpu_has_sve(vcpu) || !guest_owns_fp_regs())
 		val |= CPTR_EL2_TZ;
@@ -101,6 +98,8 @@ static inline void __activate_cptr_traps_vhe(struct kvm_vcpu *vcpu)
 		val |= CPACR_EL1_FPEN;
 		if (vcpu_has_sve(vcpu))
 			val |= CPACR_EL1_ZEN;
+		if (vcpu_has_sme(vcpu))
+			val |= CPACR_EL1_SMEN;
 	}
 
 	if (!vcpu_has_nv(vcpu))
@@ -142,6 +141,8 @@ static inline void __activate_cptr_traps_vhe(struct kvm_vcpu *vcpu)
 		val &= ~CPACR_EL1_FPEN;
 	if (!(SYS_FIELD_GET(CPACR_EL1, ZEN, cptr) & BIT(0)))
 		val &= ~CPACR_EL1_ZEN;
+	if (!(SYS_FIELD_GET(CPACR_EL1, SMEN, cptr) & BIT(0)))
+		val &= ~CPACR_EL1_SMEN;
 
 	if (kvm_has_feat(vcpu->kvm, ID_AA64MMFR3_EL1, S2POE, IMP))
 		val |= cptr & CPACR_EL1_E0POE;
diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c
index d3b9ec8a7c28..b2cba7c92b0f 100644
--- a/arch/arm64/kvm/hyp/nvhe/switch.c
+++ b/arch/arm64/kvm/hyp/nvhe/switch.c
@@ -181,6 +181,7 @@ static const exit_handler_fn hyp_exit_handlers[] = {
 	[ESR_ELx_EC_CP15_32]		= kvm_hyp_handle_cp15_32,
 	[ESR_ELx_EC_SYS64]		= kvm_hyp_handle_sysreg,
 	[ESR_ELx_EC_SVE]		= kvm_hyp_handle_fpsimd,
+	[ESR_ELx_EC_SME]		= kvm_hyp_handle_fpsimd,
 	[ESR_ELx_EC_FP_ASIMD]		= kvm_hyp_handle_fpsimd,
 	[ESR_ELx_EC_IABT_LOW]		= kvm_hyp_handle_iabt_low,
 	[ESR_ELx_EC_DABT_LOW]		= kvm_hyp_handle_dabt_low,
@@ -192,7 +193,8 @@ static const exit_handler_fn pvm_exit_handlers[] = {
 	[0 ... ESR_ELx_EC_MAX]		= NULL,
 	[ESR_ELx_EC_SYS64]		= kvm_handle_pvm_sys64,
 	[ESR_ELx_EC_SVE]		= kvm_handle_pvm_restricted,
-	[ESR_ELx_EC_FP_ASIMD]		= kvm_hyp_handle_fpsimd,
+	[ESR_ELx_EC_SME]		= kvm_handle_pvm_restricted,
+	[ESR_ELx_EC_FP_ASIMD]		= kvm_handle_pvm_restricted,
 	[ESR_ELx_EC_IABT_LOW]		= kvm_hyp_handle_iabt_low,
 	[ESR_ELx_EC_DABT_LOW]		= kvm_hyp_handle_dabt_low,
 	[ESR_ELx_EC_WATCHPT_LOW]	= kvm_hyp_handle_watchpt_low,
diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c
index 9984c492305a..8449004bc24e 100644
--- a/arch/arm64/kvm/hyp/vhe/switch.c
+++ b/arch/arm64/kvm/hyp/vhe/switch.c
@@ -458,22 +458,28 @@ static bool kvm_hyp_handle_cpacr_el1(struct kvm_vcpu *vcpu, u64 *exit_code)
 	return true;
 }
 
-static bool kvm_hyp_handle_zcr_el2(struct kvm_vcpu *vcpu, u64 *exit_code)
+static bool kvm_hyp_handle_vec_cr_el2(struct kvm_vcpu *vcpu, u64 *exit_code)
 {
 	u32 sysreg = esr_sys64_to_sysreg(kvm_vcpu_get_esr(vcpu));
 
 	if (!vcpu_has_nv(vcpu))
 		return false;
 
-	if (sysreg != SYS_ZCR_EL2)
+	switch (sysreg) {
+	case SYS_ZCR_EL2:
+	case SYS_SMCR_EL2:
+		break;
+	default:
 		return false;
+	}
 
 	if (guest_owns_fp_regs())
 		return false;
 
 	/*
-	 * ZCR_EL2 traps are handled in the slow path, with the expectation
-	 * that the guest's FP context has already been loaded onto the CPU.
+	 * ZCR_EL2 and SMCR_EL2 traps are handled in the slow path,
+	 * with the expectation that the guest's FP context has
+	 * already been loaded onto the CPU.
 	 *
 	 * Load the guest's FP context and unconditionally forward to the
 	 * slow path for handling (i.e. return false).
@@ -493,7 +499,7 @@ static bool kvm_hyp_handle_sysreg_vhe(struct kvm_vcpu *vcpu, u64 *exit_code)
 	if (kvm_hyp_handle_cpacr_el1(vcpu, exit_code))
 		return true;
 
-	if (kvm_hyp_handle_zcr_el2(vcpu, exit_code))
+	if (kvm_hyp_handle_vec_cr_el2(vcpu, exit_code))
 		return true;
 
 	return kvm_hyp_handle_sysreg(vcpu, exit_code);
@@ -522,6 +528,7 @@ static const exit_handler_fn hyp_exit_handlers[] = {
 	[0 ... ESR_ELx_EC_MAX]		= NULL,
 	[ESR_ELx_EC_CP15_32]		= kvm_hyp_handle_cp15_32,
 	[ESR_ELx_EC_SYS64]		= kvm_hyp_handle_sysreg_vhe,
+	[ESR_ELx_EC_SME]		= kvm_hyp_handle_fpsimd,
 	[ESR_ELx_EC_SVE]		= kvm_hyp_handle_fpsimd,
 	[ESR_ELx_EC_FP_ASIMD]		= kvm_hyp_handle_fpsimd,
 	[ESR_ELx_EC_IABT_LOW]		= kvm_hyp_handle_iabt_low,

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:21:20 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:21:20 +0000
Subject: [PATCH v9 26/30] KVM: arm64: Provide interface for configuring and
 enabling SME for guests
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-26-8be3867cb883@kernel.org>

Since SME requires configuration of a vector length in order to know the
size of both the streaming mode SVE state and ZA array we implement a
capability for it and require that it be enabled and finalized before
the SME specific state can be accessed, similarly to SVE.

Due to the overlap with sizing the SVE state we finalise both SVE and
SME with a single finalization, preventing any further changes to the
SVE and SME configuration once KVM_ARM_VCPU_VEC (an alias for _VCPU_SVE)
has been finalised. This is not a thing of great elegance but it ensures
that we never have a state where one of SVE or SME is finalised and the
other not, avoiding complexity.

SME is supported for normal and protected guests.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 arch/arm64/include/asm/kvm_host.h  |  12 +++-
 arch/arm64/include/uapi/asm/kvm.h  |   1 +
 arch/arm64/kvm/arm.c               |  10 ++++
 arch/arm64/kvm/hyp/nvhe/pkvm.c     |  76 +++++++++++++++++++-----
 arch/arm64/kvm/hyp/nvhe/sys_regs.c |   6 ++
 arch/arm64/kvm/reset.c             | 116 +++++++++++++++++++++++++++++++------
 include/uapi/linux/kvm.h           |   1 +
 7 files changed, 189 insertions(+), 33 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index bceaf0608d75..011debfc1afd 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -39,7 +39,7 @@
 
 #define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
 
-#define KVM_VCPU_MAX_FEATURES 9
+#define KVM_VCPU_MAX_FEATURES 10
 #define KVM_VCPU_VALID_FEATURES	(BIT(KVM_VCPU_MAX_FEATURES) - 1)
 
 #define KVM_REQ_SLEEP \
@@ -82,6 +82,7 @@ extern unsigned int __ro_after_init kvm_host_max_vl[ARM64_VEC_MAX];
 DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
 
 int __init kvm_arm_init_sve(void);
+int __init kvm_arm_init_sme(void);
 
 u32 __attribute_const__ kvm_target_cpu(void);
 void kvm_reset_vcpu(struct kvm_vcpu *vcpu);
@@ -1149,7 +1150,14 @@ struct kvm_vcpu_arch {
 	__size_ret;							\
 })
 
-#define vcpu_sve_state_size(vcpu) sve_state_size_from_vl((vcpu)->arch.max_vl[ARM64_VEC_SVE])
+#define vcpu_sve_state_size(vcpu) ({					\
+	unsigned int __max_vl;						\
+									\
+	__max_vl = max((vcpu)->arch.max_vl[ARM64_VEC_SVE],		\
+		       (vcpu)->arch.max_vl[ARM64_VEC_SME]);		\
+									\
+	sve_state_size_from_vl(__max_vl);				\
+})
 
 #define vcpu_sme_state(vcpu) (kern_hyp_va((vcpu)->arch.sme_state))
 
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 9a19cc58d227..b4be424e4230 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -106,6 +106,7 @@ struct kvm_regs {
 #define KVM_ARM_VCPU_PTRAUTH_GENERIC	6 /* VCPU uses generic authentication */
 #define KVM_ARM_VCPU_HAS_EL2		7 /* Support nested virtualization */
 #define KVM_ARM_VCPU_HAS_EL2_E2H0	8 /* Limit NV support to E2H RES0 */
+#define KVM_ARM_VCPU_SME		9 /* enable SME for this CPU */
 
 /*
  * An alias for _SVE since we finalize VL configuration for both SVE and SME
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 4f80da0c0d1d..7de7b497f74f 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -402,6 +402,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 	case KVM_CAP_ARM_SVE:
 		r = system_supports_sve();
 		break;
+	case KVM_CAP_ARM_SME:
+		r = system_supports_sme();
+		break;
 	case KVM_CAP_ARM_PTRAUTH_ADDRESS:
 	case KVM_CAP_ARM_PTRAUTH_GENERIC:
 		r = kvm_has_full_ptr_auth();
@@ -1456,6 +1459,9 @@ static unsigned long system_supported_vcpu_features(void)
 	if (!system_supports_sve())
 		clear_bit(KVM_ARM_VCPU_SVE, &features);
 
+	if (!system_supports_sme())
+		clear_bit(KVM_ARM_VCPU_SME, &features);
+
 	if (!kvm_has_full_ptr_auth()) {
 		clear_bit(KVM_ARM_VCPU_PTRAUTH_ADDRESS, &features);
 		clear_bit(KVM_ARM_VCPU_PTRAUTH_GENERIC, &features);
@@ -2878,6 +2884,10 @@ static __init int kvm_arm_init(void)
 	if (err)
 		return err;
 
+	err = kvm_arm_init_sme();
+	if (err)
+		return err;
+
 	err = kvm_arm_vmid_alloc_init();
 	if (err) {
 		kvm_err("Failed to initialize VMID allocator.\n");
diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index b656449dff69..30ee9f371b0d 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -148,10 +148,6 @@ static int pkvm_check_pvm_cpu_features(struct kvm_vcpu *vcpu)
 	    !kvm_has_feat(kvm, ID_AA64PFR0_EL1, AdvSIMD, IMP))
 		return -EINVAL;
 
-	/* No SME support in KVM right now. Check to catch if it changes. */
-	if (kvm_has_feat(kvm, ID_AA64PFR1_EL1, SME, IMP))
-		return -EINVAL;
-
 	return 0;
 }
 
@@ -377,6 +373,11 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
 		kvm->arch.flags |= host_arch_flags & BIT(KVM_ARCH_FLAG_GUEST_HAS_SVE);
 	}
 
+	if (kvm_pvm_ext_allowed(KVM_CAP_ARM_SME)) {
+		set_bit(KVM_ARM_VCPU_SME, allowed_features);
+		kvm->arch.flags |= host_arch_flags & BIT(KVM_ARCH_FLAG_GUEST_HAS_SME);
+	}
+
 	bitmap_and(kvm->arch.vcpu_features, host_kvm->arch.vcpu_features,
 		   allowed_features, KVM_VCPU_MAX_FEATURES);
 }
@@ -399,6 +400,18 @@ static void unpin_host_sve_state(struct pkvm_hyp_vcpu *hyp_vcpu)
 			     sve_state + vcpu_sve_state_size(&hyp_vcpu->vcpu));
 }
 
+static void unpin_host_sme_state(struct pkvm_hyp_vcpu *hyp_vcpu)
+{
+	void *sme_state;
+
+	if (!vcpu_has_feature(&hyp_vcpu->vcpu, KVM_ARM_VCPU_SME))
+		return;
+
+	sme_state = kern_hyp_va(hyp_vcpu->vcpu.arch.sme_state);
+	hyp_unpin_shared_mem(sme_state,
+			     sme_state + vcpu_sme_state_size(&hyp_vcpu->vcpu));
+}
+
 static void unpin_host_vcpus(struct pkvm_hyp_vcpu *hyp_vcpus[],
 			     unsigned int nr_vcpus)
 {
@@ -412,6 +425,7 @@ static void unpin_host_vcpus(struct pkvm_hyp_vcpu *hyp_vcpus[],
 
 		unpin_host_vcpu(hyp_vcpu->host_vcpu);
 		unpin_host_sve_state(hyp_vcpu);
+		unpin_host_sme_state(hyp_vcpu);
 	}
 }
 
@@ -438,23 +452,35 @@ static void init_pkvm_hyp_vm(struct kvm *host_kvm, struct pkvm_hyp_vm *hyp_vm,
 	mmu->pgt = &hyp_vm->pgt;
 }
 
-static int pkvm_vcpu_init_sve(struct pkvm_hyp_vcpu *hyp_vcpu, struct kvm_vcpu *host_vcpu)
+static int pkvm_vcpu_init_vec(struct pkvm_hyp_vcpu *hyp_vcpu, struct kvm_vcpu *host_vcpu)
 {
 	struct kvm_vcpu *vcpu = &hyp_vcpu->vcpu;
-	unsigned int sve_max_vl;
-	size_t sve_state_size;
-	void *sve_state;
+	unsigned int sve_max_vl, sme_max_vl;
+	size_t sve_state_size, sme_state_size;
+	void *sve_state, *sme_state;
 	int ret = 0;
 
-	if (!vcpu_has_feature(vcpu, KVM_ARM_VCPU_SVE)) {
+	if (!vcpu_has_feature(vcpu, KVM_ARM_VCPU_SVE) &&
+	    !vcpu_has_feature(vcpu, KVM_ARM_VCPU_SME)) {
 		vcpu_clear_flag(vcpu, VCPU_VEC_FINALIZED);
 		return 0;
 	}
 
 	/* Limit guest vector length to the maximum supported by the host. */
-	sve_max_vl = min(READ_ONCE(host_vcpu->arch.max_vl[ARM64_VEC_SVE]),
-			 kvm_host_max_vl[ARM64_VEC_SVE]);
-	sve_state_size = sve_state_size_from_vl(sve_max_vl);
+	if (vcpu_has_feature(vcpu, KVM_ARM_VCPU_SVE))
+		sve_max_vl = min(READ_ONCE(host_vcpu->arch.max_vl[ARM64_VEC_SVE]),
+				 kvm_host_max_vl[ARM64_VEC_SVE]);
+	else
+		sve_max_vl = 0;
+
+	if (vcpu_has_feature(vcpu, KVM_ARM_VCPU_SME))
+		sme_max_vl = min(READ_ONCE(host_vcpu->arch.max_vl[ARM64_VEC_SME]),
+				 kvm_host_max_vl[ARM64_VEC_SME]);
+	else
+		sme_max_vl = 0;
+
+	/* We need SVE storage for the larger of normal or streaming mode */
+	sve_state_size = sve_state_size_from_vl(max(sve_max_vl, sme_max_vl));
 	sve_state = kern_hyp_va(READ_ONCE(host_vcpu->arch.sve_state));
 
 	if (!sve_state || !sve_state_size) {
@@ -466,12 +492,36 @@ static int pkvm_vcpu_init_sve(struct pkvm_hyp_vcpu *hyp_vcpu, struct kvm_vcpu *h
 	if (ret)
 		goto err;
 
+	if (vcpu_has_feature(vcpu, KVM_ARM_VCPU_SME)) {
+		sme_state_size = sme_state_size_from_vl(sme_max_vl,
+							vcpu_has_sme2(vcpu));
+		sme_state = kern_hyp_va(READ_ONCE(host_vcpu->arch.sme_state));
+
+		if (!sme_state || !sme_state_size) {
+			ret = -EINVAL;
+			goto err_sve_mapped;
+		}
+
+		ret = hyp_pin_shared_mem(sme_state, sme_state + sme_state_size);
+		if (ret)
+			goto err_sve_mapped;
+	} else {
+		sme_state = 0;
+	}
+
 	vcpu->arch.sve_state = sve_state;
 	vcpu->arch.max_vl[ARM64_VEC_SVE] = sve_max_vl;
 
+	vcpu->arch.sme_state = sme_state;
+	vcpu->arch.max_vl[ARM64_VEC_SME] = sme_max_vl;
+
 	return 0;
+
+err_sve_mapped:
+	hyp_unpin_shared_mem(sve_state, sve_state + sve_state_size);
 err:
 	clear_bit(KVM_ARM_VCPU_SVE, vcpu->kvm->arch.vcpu_features);
+	clear_bit(KVM_ARM_VCPU_SME, vcpu->kvm->arch.vcpu_features);
 	return ret;
 }
 
@@ -501,7 +551,7 @@ static int init_pkvm_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu,
 	if (ret)
 		goto done;
 
-	ret = pkvm_vcpu_init_sve(hyp_vcpu, host_vcpu);
+	ret = pkvm_vcpu_init_vec(hyp_vcpu, host_vcpu);
 done:
 	if (ret)
 		unpin_host_vcpu(host_vcpu);
diff --git a/arch/arm64/kvm/hyp/nvhe/sys_regs.c b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
index 3108b5185c20..40127ba86335 100644
--- a/arch/arm64/kvm/hyp/nvhe/sys_regs.c
+++ b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
@@ -66,6 +66,11 @@ static bool vm_has_ptrauth(const struct kvm *kvm)
 		kvm_vcpu_has_feature(kvm, KVM_ARM_VCPU_PTRAUTH_GENERIC);
 }
 
+static bool vm_has_sme(const struct kvm *kvm)
+{
+	return system_supports_sme() && kvm_vcpu_has_feature(kvm, KVM_ARM_VCPU_SME);
+}
+
 static bool vm_has_sve(const struct kvm *kvm)
 {
 	return system_supports_sve() && kvm_vcpu_has_feature(kvm, KVM_ARM_VCPU_SVE);
@@ -102,6 +107,7 @@ static const struct pvm_ftr_bits pvmid_aa64pfr0[] = {
 };
 
 static const struct pvm_ftr_bits pvmid_aa64pfr1[] = {
+	MAX_FEAT_FUNC(ID_AA64PFR1_EL1, SME, SME2, vm_has_sme),
 	MAX_FEAT(ID_AA64PFR1_EL1, BT, IMP),
 	MAX_FEAT(ID_AA64PFR1_EL1, SSBS, SSBS2),
 	MAX_FEAT_ENUM(ID_AA64PFR1_EL1, MTE_frac, NI),
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index a8684a1346ec..e6dc04267cbb 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -76,6 +76,34 @@ int __init kvm_arm_init_sve(void)
 	return 0;
 }
 
+int __init kvm_arm_init_sme(void)
+{
+	if (system_supports_sme()) {
+		kvm_max_vl[ARM64_VEC_SME] = sme_max_virtualisable_vl();
+		kvm_host_max_vl[ARM64_VEC_SME] = sme_max_vl();
+		kvm_nvhe_sym(kvm_host_max_vl[ARM64_VEC_SME]) = kvm_host_max_vl[ARM64_VEC_SME];
+
+		/*
+		 * The get_sve_reg()/set_sve_reg() ioctl interface will need
+		 * to be extended with multiple register slice support in
+		 * order to support vector lengths greater than
+		 * VL_ARCH_MAX:
+		 */
+		if (WARN_ON(kvm_max_vl[ARM64_VEC_SME] > VL_ARCH_MAX))
+			kvm_max_vl[ARM64_VEC_SME] = VL_ARCH_MAX;
+
+		/*
+		 * Don't even try to make use of vector lengths that
+		 * aren't available on all CPUs, for now:
+		 */
+		if (kvm_max_vl[ARM64_VEC_SME] < sme_max_vl())
+			pr_warn("KVM: SME vector length for guests limited to %u bytes\n",
+				kvm_max_vl[ARM64_VEC_SME]);
+	}
+
+	return 0;
+}
+
 static void kvm_vcpu_enable_sve(struct kvm_vcpu *vcpu)
 {
 	vcpu->arch.max_vl[ARM64_VEC_SVE] = kvm_max_vl[ARM64_VEC_SVE];
@@ -88,42 +116,86 @@ static void kvm_vcpu_enable_sve(struct kvm_vcpu *vcpu)
 	set_bit(KVM_ARCH_FLAG_GUEST_HAS_SVE, &vcpu->kvm->arch.flags);
 }
 
+static void kvm_vcpu_enable_sme(struct kvm_vcpu *vcpu)
+{
+	vcpu->arch.max_vl[ARM64_VEC_SME] = kvm_max_vl[ARM64_VEC_SME];
+
+	/*
+	 * Userspace can still customize the vector lengths by writing
+	 * KVM_REG_ARM64_SME_VLS.  Allocation is deferred until
+	 * kvm_arm_vcpu_finalize(), which freezes the configuration.
+	 */
+	set_bit(KVM_ARCH_FLAG_GUEST_HAS_SME, &vcpu->kvm->arch.flags);
+}
+
 /*
- * Finalize vcpu's maximum SVE vector length, allocating
- * vcpu->arch.sve_state as necessary.
+ * Finalize vcpu's maximum vector lengths, allocating
+ * vcpu->arch.sve_state and vcpu->arch.sme_state as necessary.
  */
 static int kvm_vcpu_finalize_vec(struct kvm_vcpu *vcpu)
 {
-	void *buf;
+	void *sve_state, *sme_state;
 	unsigned int vl;
-	size_t reg_sz;
 	int ret;
 
-	vl = vcpu->arch.max_vl[ARM64_VEC_SVE];
-
 	/*
 	 * Responsibility for these properties is shared between
 	 * kvm_arm_init_sve(), kvm_vcpu_enable_sve() and
 	 * set_sve_vls().  Double-check here just to be sure:
 	 */
-	if (WARN_ON(!sve_vl_valid(vl) || vl > sve_max_virtualisable_vl() ||
-		    vl > VL_ARCH_MAX))
-		return -EIO;
+	if (vcpu_has_sve(vcpu)) {
+		vl = vcpu->arch.max_vl[ARM64_VEC_SVE];
+		if (WARN_ON(!sve_vl_valid(vl) ||
+			    vl > sve_max_virtualisable_vl() ||
+			    vl > VL_ARCH_MAX))
+			return -EIO;
+	}
 
-	reg_sz = vcpu_sve_state_size(vcpu);
-	buf = kzalloc(reg_sz, GFP_KERNEL_ACCOUNT);
-	if (!buf)
+	/* Similarly for SME */
+	if (vcpu_has_sme(vcpu)) {
+		vl = vcpu->arch.max_vl[ARM64_VEC_SME];
+		if (WARN_ON(!sve_vl_valid(vl) ||
+			    vl > sme_max_virtualisable_vl() ||
+			    vl > VL_ARCH_MAX))
+			return -EIO;
+	}
+
+	sve_state = kzalloc(vcpu_sve_state_size(vcpu), GFP_KERNEL_ACCOUNT);
+	if (!sve_state)
 		return -ENOMEM;
 
-	ret = kvm_share_hyp(buf, buf + reg_sz);
-	if (ret) {
-		kfree(buf);
-		return ret;
+	ret = kvm_share_hyp(sve_state, sve_state + vcpu_sve_state_size(vcpu));
+	if (ret)
+		goto err_sve_alloc;
+
+	if (vcpu_has_sme(vcpu)) {
+		sme_state = kzalloc(vcpu_sme_state_size(vcpu),
+				    GFP_KERNEL_ACCOUNT);
+		if (!sme_state) {
+			ret = -ENOMEM;
+			goto err_sve_map;
+		}
+
+		ret = kvm_share_hyp(sme_state,
+				    sme_state + vcpu_sme_state_size(vcpu));
+		if (ret)
+			goto err_sme_alloc;
+	} else {
+		sme_state = NULL;
 	}
-	
-	vcpu->arch.sve_state = buf;
+
+	vcpu->arch.sve_state = sve_state;
+	vcpu->arch.sme_state = sme_state;
 	vcpu_set_flag(vcpu, VCPU_VEC_FINALIZED);
 	return 0;
+
+err_sme_alloc:
+	kfree(sme_state);
+err_sve_map:
+	kvm_unshare_hyp(sve_state, sve_state + vcpu_sve_state_size(vcpu));
+err_sve_alloc:
+	kfree(sve_state);
+	return ret;
 }
 
 int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int feature)
@@ -153,12 +225,16 @@ bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu)
 void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu)
 {
 	void *sve_state = vcpu->arch.sve_state;
+	void *sme_state = vcpu->arch.sme_state;
 
 	kvm_unshare_hyp(vcpu, vcpu + 1);
 	if (sve_state)
 		kvm_unshare_hyp(sve_state, sve_state + vcpu_sve_state_size(vcpu));
 	kfree(sve_state);
 	free_page((unsigned long)vcpu->arch.ctxt.vncr_array);
+	if (sme_state)
+		kvm_unshare_hyp(sme_state, sme_state + vcpu_sme_state_size(vcpu));
+	kfree(sme_state);
 	kfree(vcpu->arch.vncr_tlb);
 	kfree(vcpu->arch.ccsidr);
 }
@@ -167,6 +243,8 @@ static void kvm_vcpu_reset_vec(struct kvm_vcpu *vcpu)
 {
 	if (vcpu_has_sve(vcpu))
 		memset(vcpu->arch.sve_state, 0, vcpu_sve_state_size(vcpu));
+	if (vcpu_has_sme(vcpu))
+		memset(vcpu->arch.sme_state, 0, vcpu_sme_state_size(vcpu));
 }
 
 /**
@@ -206,6 +284,8 @@ void kvm_reset_vcpu(struct kvm_vcpu *vcpu)
 	if (!kvm_arm_vcpu_vec_finalized(vcpu)) {
 		if (vcpu_has_feature(vcpu, KVM_ARM_VCPU_SVE))
 			kvm_vcpu_enable_sve(vcpu);
+		if (vcpu_has_feature(vcpu, KVM_ARM_VCPU_SME))
+			kvm_vcpu_enable_sme(vcpu);
 	} else {
 		kvm_vcpu_reset_vec(vcpu);
 	}
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index dddb781b0507..d9e068db3b73 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -974,6 +974,7 @@ struct kvm_enable_cap {
 #define KVM_CAP_GUEST_MEMFD_FLAGS 244
 #define KVM_CAP_ARM_SEA_TO_USER 245
 #define KVM_CAP_S390_USER_OPEREXEC 246
+#define KVM_CAP_ARM_SME 247
 
 struct kvm_irq_routing_irqchip {
 	__u32 irqchip;

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:21:21 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:21:21 +0000
Subject: [PATCH v9 27/30] KVM: arm64: selftests: Remove spurious check for
 single bit safe values
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-27-8be3867cb883@kernel.org>

get_safe_value() currently asserts that bitfields it is generating a safe
value for must be more than one bit wide but in actual fact it should
always be possible to generate a safe value to write to a bitfield even if
it is just the current value and the function correctly handles that.
Remove the assert.

Fixes: bf09ee918053e ("KVM: arm64: selftests: Remove ARM64_FEATURE_FIELD_BITS and its last user")
Signed-off-by: Mark Brown <broonie at kernel.org>
---
 tools/testing/selftests/kvm/arm64/set_id_regs.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/tools/testing/selftests/kvm/arm64/set_id_regs.c b/tools/testing/selftests/kvm/arm64/set_id_regs.c
index c4815d365816..322cd13b9352 100644
--- a/tools/testing/selftests/kvm/arm64/set_id_regs.c
+++ b/tools/testing/selftests/kvm/arm64/set_id_regs.c
@@ -270,8 +270,6 @@ uint64_t get_safe_value(const struct reg_ftr_bits *ftr_bits, uint64_t ftr)
 {
 	uint64_t ftr_max = ftr_bits->mask >> ftr_bits->shift;
 
-	TEST_ASSERT(ftr_max > 1, "This test doesn't support single bit features");
-
 	if (ftr_bits->sign == FTR_UNSIGNED) {
 		switch (ftr_bits->type) {
 		case FTR_EXACT:

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:21:19 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:21:19 +0000
Subject: [PATCH v9 25/30] KVM: arm64: Expose SME to nested guests
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-25-8be3867cb883@kernel.org>

With support for context switching SME state in place allow access to SME
in nested guests.

The SME floating point state is handled along with all the other floating
point state, SME specific floating point exceptions are directed into the
same handlers as other floating point exceptions with NV specific handling
for the vector lengths already in place.

TPIDR2_EL0 is context switched along with the other TPIDRs as part of the
main guest register context switch.

SME priority support is currently masked from all guests including nested
ones.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 arch/arm64/kvm/nested.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
index cdeeb8f09e72..a0967ca8c61e 100644
--- a/arch/arm64/kvm/nested.c
+++ b/arch/arm64/kvm/nested.c
@@ -1534,14 +1534,13 @@ u64 limit_nv_id_reg(struct kvm *kvm, u32 reg, u64 val)
 		break;
 
 	case SYS_ID_AA64PFR1_EL1:
-		/* Only support BTI, SSBS, CSV2_frac */
+		/* Only support BTI, SME, SSBS, CSV2_frac */
 		val &= ~(ID_AA64PFR1_EL1_PFAR		|
 			 ID_AA64PFR1_EL1_MTEX		|
 			 ID_AA64PFR1_EL1_THE		|
 			 ID_AA64PFR1_EL1_GCS		|
 			 ID_AA64PFR1_EL1_MTE_frac	|
 			 ID_AA64PFR1_EL1_NMI		|
-			 ID_AA64PFR1_EL1_SME		|
 			 ID_AA64PFR1_EL1_RES0		|
 			 ID_AA64PFR1_EL1_MPAM_frac	|
 			 ID_AA64PFR1_EL1_MTE);

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:21:22 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:21:22 +0000
Subject: [PATCH v9 28/30] KVM: arm64: selftests: Skip impossible invalid
 value tests
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-28-8be3867cb883@kernel.org>

The set_id_regs test currently assumes that there will always be invalid
values available in bitfields for it to generate but this may not be the
case if the architecture has defined meanings for every possible value for
the bitfield. An assert added in commit bf09ee918053e ("KVM: arm64:
selftests: Remove ARM64_FEATURE_FIELD_BITS and its last user") refuses to
run for single bit fields which will show the issue most readily but there
is no reason wider ones can't show the same issue.

Rework the tests for invalid value to check if an invalid value can be
generated and skip the test if not, removing the assert.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 tools/testing/selftests/kvm/arm64/set_id_regs.c | 58 ++++++++++++++++++++-----
 1 file changed, 46 insertions(+), 12 deletions(-)

diff --git a/tools/testing/selftests/kvm/arm64/set_id_regs.c b/tools/testing/selftests/kvm/arm64/set_id_regs.c
index 322cd13b9352..641194c5005a 100644
--- a/tools/testing/selftests/kvm/arm64/set_id_regs.c
+++ b/tools/testing/selftests/kvm/arm64/set_id_regs.c
@@ -318,11 +318,12 @@ uint64_t get_safe_value(const struct reg_ftr_bits *ftr_bits, uint64_t ftr)
 }
 
 /* Return an invalid value to a given ftr_bits an ftr value */
-uint64_t get_invalid_value(const struct reg_ftr_bits *ftr_bits, uint64_t ftr)
+uint64_t get_invalid_value(const struct reg_ftr_bits *ftr_bits, uint64_t ftr,
+			   bool *skip)
 {
 	uint64_t ftr_max = ftr_bits->mask >> ftr_bits->shift;
 
-	TEST_ASSERT(ftr_max > 1, "This test doesn't support single bit features");
+	*skip = false;
 
 	if (ftr_bits->sign == FTR_UNSIGNED) {
 		switch (ftr_bits->type) {
@@ -330,42 +331,72 @@ uint64_t get_invalid_value(const struct reg_ftr_bits *ftr_bits, uint64_t ftr)
 			ftr = max((uint64_t)ftr_bits->safe_val + 1, ftr + 1);
 			break;
 		case FTR_LOWER_SAFE:
+			if (ftr == ftr_max)
+				*skip = true;
 			ftr++;
 			break;
 		case FTR_HIGHER_SAFE:
+			if (ftr == 0)
+				*skip = true;
 			ftr--;
 			break;
 		case FTR_HIGHER_OR_ZERO_SAFE:
-			if (ftr == 0)
+			switch (ftr) {
+			case 0:
 				ftr = ftr_max;
-			else
+				break;
+			case 1:
+				*skip = true;
+				break;
+			default:
 				ftr--;
-			break;
+				break;
+			}
 		default:
+			*skip = true;
 			break;
 		}
 	} else if (ftr != ftr_max) {
 		switch (ftr_bits->type) {
 		case FTR_EXACT:
 			ftr = max((uint64_t)ftr_bits->safe_val + 1, ftr + 1);
+			if (ftr > ftr_max)
+				*skip = true;
 			break;
 		case FTR_LOWER_SAFE:
-			ftr++;
+			if (ftr == ftr_max)
+				*skip = true;
+			else
+				ftr++;
 			break;
 		case FTR_HIGHER_SAFE:
-			ftr--;
-			break;
-		case FTR_HIGHER_OR_ZERO_SAFE:
 			if (ftr == 0)
-				ftr = ftr_max - 1;
+				*skip = true;
 			else
 				ftr--;
 			break;
+		case FTR_HIGHER_OR_ZERO_SAFE:
+			switch (ftr) {
+			case 0:
+				if (ftr_max > 1)
+					ftr = ftr_max - 1;
+				else
+					*skip = true;
+				break;
+			case 1:
+				*skip = true;
+				break;
+			default:
+				ftr--;
+				break;
+			break;
+			}
 		default:
+			*skip = true;
 			break;
 		}
 	} else {
-		ftr = 0;
+		*skip = true;
 	}
 
 	return ftr;
@@ -400,12 +431,15 @@ static void test_reg_set_fail(struct kvm_vcpu *vcpu, uint64_t reg,
 	uint8_t shift = ftr_bits->shift;
 	uint64_t mask = ftr_bits->mask;
 	uint64_t val, old_val, ftr;
+	bool skip;
 	int r;
 
 	val = vcpu_get_reg(vcpu, reg);
 	ftr = (val & mask) >> shift;
 
-	ftr = get_invalid_value(ftr_bits, ftr);
+	ftr = get_invalid_value(ftr_bits, ftr, &skip);
+	if (skip)
+		return;
 
 	old_val = val;
 	ftr <<= shift;

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:21:23 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:21:23 +0000
Subject: [PATCH v9 29/30] KVM: arm64: selftests: Add SME system registers
 to get-reg-list
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-29-8be3867cb883@kernel.org>

SME adds a number of new system registers, update get-reg-list to check for
them based on the visibility of SME.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 tools/testing/selftests/kvm/arm64/get-reg-list.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/kvm/arm64/get-reg-list.c b/tools/testing/selftests/kvm/arm64/get-reg-list.c
index 0a3a94c4cca1..876c4719e2e2 100644
--- a/tools/testing/selftests/kvm/arm64/get-reg-list.c
+++ b/tools/testing/selftests/kvm/arm64/get-reg-list.c
@@ -61,7 +61,13 @@ static struct feature_id_reg feat_id_regs[] = {
 	REG_FEAT(HFGITR2_EL2,	ID_AA64MMFR0_EL1, FGT, FGT2),
 	REG_FEAT(HDFGRTR2_EL2,	ID_AA64MMFR0_EL1, FGT, FGT2),
 	REG_FEAT(HDFGWTR2_EL2,	ID_AA64MMFR0_EL1, FGT, FGT2),
-	REG_FEAT(ZCR_EL2,	ID_AA64PFR0_EL1, SVE, IMP),
+	REG_FEAT(SMCR_EL1,	ID_AA64PFR1_EL1, SME, IMP),
+	REG_FEAT(SMCR_EL2,	ID_AA64PFR1_EL1, SME, IMP),
+	REG_FEAT(SMIDR_EL1,	ID_AA64PFR1_EL1, SME, IMP),
+	REG_FEAT(SMPRI_EL1,	ID_AA64PFR1_EL1, SME, IMP),
+	REG_FEAT(SMPRIMAP_EL2,	ID_AA64PFR1_EL1, SME, IMP),
+	REG_FEAT(TPIDR2_EL0,	ID_AA64PFR1_EL1, SME, IMP),
+	REG_FEAT(SVCR,		ID_AA64PFR1_EL1, SME, IMP),
 	REG_FEAT(SCTLR2_EL1,	ID_AA64MMFR3_EL1, SCTLRX, IMP),
 	REG_FEAT(SCTLR2_EL2,	ID_AA64MMFR3_EL1, SCTLRX, IMP),
 	REG_FEAT(VDISR_EL2,	ID_AA64PFR0_EL1, RAS, IMP),
@@ -367,6 +373,7 @@ static __u64 base_regs[] = {
 	ARM64_SYS_REG(3, 0, 0, 0, 0),	/* MIDR_EL1 */
 	ARM64_SYS_REG(3, 0, 0, 0, 6),	/* REVIDR_EL1 */
 	ARM64_SYS_REG(3, 1, 0, 0, 1),	/* CLIDR_EL1 */
+	ARM64_SYS_REG(3, 1, 0, 0, 6),	/* SMIDR_EL1 */
 	ARM64_SYS_REG(3, 1, 0, 0, 7),	/* AIDR_EL1 */
 	ARM64_SYS_REG(3, 3, 0, 0, 1),	/* CTR_EL0 */
 	ARM64_SYS_REG(2, 0, 0, 0, 4),
@@ -498,6 +505,8 @@ static __u64 base_regs[] = {
 	ARM64_SYS_REG(3, 0, 1, 0, 1),	/* ACTLR_EL1 */
 	ARM64_SYS_REG(3, 0, 1, 0, 2),	/* CPACR_EL1 */
 	KVM_ARM64_SYS_REG(SYS_SCTLR2_EL1),
+	ARM64_SYS_REG(3, 0, 1, 2, 4),	/* SMPRI_EL1 */
+	ARM64_SYS_REG(3, 0, 1, 2, 6),	/* SMCR_EL1 */
 	ARM64_SYS_REG(3, 0, 2, 0, 0),	/* TTBR0_EL1 */
 	ARM64_SYS_REG(3, 0, 2, 0, 1),	/* TTBR1_EL1 */
 	ARM64_SYS_REG(3, 0, 2, 0, 2),	/* TCR_EL1 */
@@ -518,9 +527,11 @@ static __u64 base_regs[] = {
 	ARM64_SYS_REG(3, 0, 13, 0, 4),	/* TPIDR_EL1 */
 	ARM64_SYS_REG(3, 0, 14, 1, 0),	/* CNTKCTL_EL1 */
 	ARM64_SYS_REG(3, 2, 0, 0, 0),	/* CSSELR_EL1 */
+	ARM64_SYS_REG(3, 3, 4, 2, 2),	/* SVCR */
 	ARM64_SYS_REG(3, 3, 10, 2, 4),	/* POR_EL0 */
 	ARM64_SYS_REG(3, 3, 13, 0, 2),	/* TPIDR_EL0 */
 	ARM64_SYS_REG(3, 3, 13, 0, 3),	/* TPIDRRO_EL0 */
+	ARM64_SYS_REG(3, 3, 13, 0, 5),	/* TPIDR2_EL0 */
 	ARM64_SYS_REG(3, 3, 14, 0, 1),	/* CNTPCT_EL0 */
 	ARM64_SYS_REG(3, 3, 14, 2, 1),	/* CNTP_CTL_EL0 */
 	ARM64_SYS_REG(3, 3, 14, 2, 2),	/* CNTP_CVAL_EL0 */
@@ -730,6 +741,8 @@ static __u64 el2_regs[] = {
 	SYS_REG(HFGITR_EL2),
 	SYS_REG(HACR_EL2),
 	SYS_REG(ZCR_EL2),
+	SYS_REG(SMPRIMAP_EL2),
+	SYS_REG(SMCR_EL2),
 	SYS_REG(HCRX_EL2),
 	SYS_REG(TTBR0_EL2),
 	SYS_REG(TTBR1_EL2),

-- 
2.47.3



From broonie at kernel.org  Mon Dec 22 17:21:24 2025
From: broonie at kernel.org (Mark Brown)
Date: Tue, 23 Dec 2025 01:21:24 +0000
Subject: [PATCH v9 30/30] KVM: arm64: selftests: Add SME to set_id_regs
 test
In-Reply-To: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
References: <20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org>
Message-ID: <20251223-kvm-arm64-sme-v9-30-8be3867cb883@kernel.org>

Add coverage of the SME ID registers to set_id_regs, ID_AA64PFR1_EL1.SME
becomes writable and we add ID_AA64SMFR_EL1 and it's subfields.

Signed-off-by: Mark Brown <broonie at kernel.org>
---
 tools/testing/selftests/kvm/arm64/set_id_regs.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/tools/testing/selftests/kvm/arm64/set_id_regs.c b/tools/testing/selftests/kvm/arm64/set_id_regs.c
index 641194c5005a..73489c48d550 100644
--- a/tools/testing/selftests/kvm/arm64/set_id_regs.c
+++ b/tools/testing/selftests/kvm/arm64/set_id_regs.c
@@ -203,6 +203,28 @@ static const struct reg_ftr_bits ftr_id_aa64mmfr3_el1[] = {
 	REG_FTR_END,
 };
 
+static const struct reg_ftr_bits ftr_id_aa64smfr0_el1[] = {
+	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64SMFR0_EL1, FA64, 0),
+	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64SMFR0_EL1, LUTv2, 0),
+	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64SMFR0_EL1, SMEver, 0),
+	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64SMFR0_EL1, I16I64, 0),
+	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64SMFR0_EL1, F64F64, 0),
+	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64SMFR0_EL1, I16I32, 0),
+	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64SMFR0_EL1, B16B16, 0),
+	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64SMFR0_EL1, F16F16, 0),
+	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64SMFR0_EL1, F8F16, 0),
+	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64SMFR0_EL1, F8F32, 0),
+	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64SMFR0_EL1, I8I32, 0),
+	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64SMFR0_EL1, F16F32, 0),
+	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64SMFR0_EL1, B16F32, 0),
+	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64SMFR0_EL1, BI32I32, 0),
+	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64SMFR0_EL1, F32F32, 0),
+	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64SMFR0_EL1, SF8FMA, 0),
+	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64SMFR0_EL1, SF8DP4, 0),
+	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64SMFR0_EL1, SF8DP2, 0),
+	REG_FTR_END,
+};
+
 static const struct reg_ftr_bits ftr_id_aa64zfr0_el1[] = {
 	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ZFR0_EL1, F64MM, 0),
 	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ZFR0_EL1, F32MM, 0),
@@ -235,6 +257,7 @@ static struct test_feature_reg test_regs[] = {
 	TEST_REG(SYS_ID_AA64MMFR1_EL1, ftr_id_aa64mmfr1_el1),
 	TEST_REG(SYS_ID_AA64MMFR2_EL1, ftr_id_aa64mmfr2_el1),
 	TEST_REG(SYS_ID_AA64MMFR3_EL1, ftr_id_aa64mmfr3_el1),
+	TEST_REG(SYS_ID_AA64SMFR0_EL1, ftr_id_aa64smfr0_el1),
 	TEST_REG(SYS_ID_AA64ZFR0_EL1, ftr_id_aa64zfr0_el1),
 };
 
@@ -254,6 +277,7 @@ static void guest_code(void)
 	GUEST_REG_SYNC(SYS_ID_AA64MMFR1_EL1);
 	GUEST_REG_SYNC(SYS_ID_AA64MMFR2_EL1);
 	GUEST_REG_SYNC(SYS_ID_AA64MMFR3_EL1);
+	GUEST_REG_SYNC(SYS_ID_AA64SMFR0_EL1);
 	GUEST_REG_SYNC(SYS_ID_AA64ZFR0_EL1);
 	GUEST_REG_SYNC(SYS_MPIDR_EL1);
 	GUEST_REG_SYNC(SYS_CLIDR_EL1);

-- 
2.47.3



From kylehsieh1995 at gmail.com  Mon Dec 22 17:49:02 2025
From: kylehsieh1995 at gmail.com (=?UTF-8?B?6Kyd5pS/5ZCJ?=)
Date: Tue, 23 Dec 2025 09:49:02 +0800
Subject: [PATCH 2/2] ARM: dts: aspeed: ventura2: Add Meta ventura2 BMC
In-Reply-To: <c069b452-df22-4afa-bf6a-c48949f40ebc@lunn.ch>
References: <20251222-ventura2_initial_dts-v1-0-1f06166c78a3@gmail.com>
 <20251222-ventura2_initial_dts-v1-2-1f06166c78a3@gmail.com> <c069b452-df22-4afa-bf6a-c48949f40ebc@lunn.ch>
Message-ID: <CAF7HswN_jEXOU_9K4LpLnbhvd+RD0qqELAHxMBbp=hGtMjS4kQ@mail.gmail.com>

On Mon, Dec 22, 2025 at 5:30?PM Andrew Lunn <andrew at lunn.ch> wrote:
>
> > +&mdio0 {
> > +     status = "okay";
> > +};
> > +
> > +&mac2 {
> > +     status = "okay";
> > +     phy-mode = "rmii";
> > +     pinctrl-names = "default";
> > +     pinctrl-0 = <&pinctrl_rmii3_default>;
> > +     fixed-link {
> > +             speed = <100>;
> > +             full-duplex;
> > +     };
> > +};
>
> That is an odd combination. You enable the MDIO bus, but don't have
> any PHYs on it, no phandles pointing to it. And you have this
> fixed-link. It makes me think you have an Ethernet switch on the bus,
> and this connects to it?
Thanks for the clarification.
Yes, there is an Ethernet switch in the design.
The MAC is connected to the switch via RMII using a fixed-link
configuration.
However, the MDIO bus is not connected to the switch and is not
used on this board. Enabling the MDIO controller in the DTS was
a mistake on my side.
I will fix this in the next revision by disabling the unused MDIO
node, while keeping the fixed-link RMII connection to the switch.
>
>     Andrew


From jie.gan at oss.qualcomm.com  Mon Dec 22 18:12:26 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Tue, 23 Dec 2025 10:12:26 +0800
Subject: [PATCH v6 3/4] coresight: tpda: add logic to configure TPDA_SYNCR
 register
In-Reply-To: <684e06d2-1d90-4b89-96d8-7458f79e3cc9@arm.com>
References: <20251222-add_sysfs_nodes_to_configure_tpda-v6-0-b27143d45c86@oss.qualcomm.com>
 <20251222-add_sysfs_nodes_to_configure_tpda-v6-3-b27143d45c86@oss.qualcomm.com>
 <684e06d2-1d90-4b89-96d8-7458f79e3cc9@arm.com>
Message-ID: <9249de66-89de-4365-a821-3ca8718b38e4@oss.qualcomm.com>



On 12/22/2025 9:10 PM, Suzuki K Poulose wrote:
> On 22/12/2025 06:02, Jie Gan wrote:
>> From: Tao Zhang <tao.zhang at oss.qualcomm.com>
>>
>> The TPDA_SYNC counter tracks the number of bytes transferred from the
>> aggregator. When this count reaches the value programmed in the
>> TPDA_SYNCR register, an ASYNC request is triggered, allowing userspace
>> tools to accurately parse each valid packet.
>>
>> Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
>> Reviewed-by: James Clark <james.clark at linaro.org>
>> Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> ---
>> ? .../ABI/testing/sysfs-bus-coresight-devices-tpda?? | 10 +++++
>> ? drivers/hwtracing/coresight/coresight-tpda.c?????? | 46 ++++++++++++ 
>> ++++++++++
>> ? drivers/hwtracing/coresight/coresight-tpda.h?????? |? 8 ++++
>> ? 3 files changed, 64 insertions(+)
>>
>> diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices- 
>> tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
>> index c8bc7b19ab25..d359d90dca72 100644
>> --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
>> +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
>> @@ -41,3 +41,13 @@ Contact:??? Jinlong Mao 
>> <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qu
>> ? Description:
>> ????????? (RW) Set global (all ports) flush request bit. The bit 
>> remains set until a
>> ????????? global flush request sequence completes.
>> +
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/syncr_mode
>> +Date:??????? December 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Set mode the of the syncr counter.
>> +??????? mode 0 - COUNT[11:0] value represents the approximate number 
>> of bytes moved between two ASYNC packet requests
>> +??????? mode 1 - the bits COUNT[11:7] are used as a power of 2. for 
>> example, we could insert an async packet every 8K
>> +???????????????? data by writing a value 13 to the COUNT[11:7] field.
> 
> What is COUNT here ? and more importantly how is this usefule without
> the support for setting the COUNT ? Do we plan to expose setting this ?
> If yes, why not now ? I don't see the point of merging "this" patch
> without the support for setting the counter.

During enable_pre_port, COUNT is configured to its maximum value. This 
counter tracks packets received by TPDA and inserts an async packet once 
the specified value is reached.

I will add the sysfs node for COUNT. I didnt add it because we typically 
didnt modify the value of the COUNT, but it's better to have a node for 
setting the value when needed.

Thanks,
Jie

> 
> Suzuki
> 
> 
> 
>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/ 
>> hwtracing/coresight/coresight-tpda.c
>> index d24a9098f1b1..7baa8a0965d3 100644
>> --- a/drivers/hwtracing/coresight/coresight-tpda.c
>> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
>> @@ -163,6 +163,15 @@ static void tpda_enable_pre_port(struct 
>> tpda_drvdata *drvdata)
>> ?????? */
>> ????? if (drvdata->trig_flag_ts)
>> ????????? writel_relaxed(0x0, drvdata->base + TPDA_FPID_CR);
>> +
>> +??? /* Initialize with a value of 0 */
>> +??? val = 0;
>> +??? if (drvdata->syncr_mode)
>> +??????? val |= TPDA_SYNCR_MODE_CTRL_MASK;
>> +
>> +??? /* Program the counter to its MAX value by default */
>> +??? val |= TPDA_SYNCR_COUNTER_MASK;
>> +??? writel_relaxed(val, drvdata->base + TPDA_SYNCR);
>> ? }
>> ? static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
>> @@ -385,8 +394,45 @@ static ssize_t global_flush_req_store(struct 
>> device *dev,
>> ? }
>> ? static DEVICE_ATTR_RW(global_flush_req);
>> +static ssize_t syncr_mode_show(struct device *dev,
>> +?????????????????? struct device_attribute *attr,
>> +?????????????????? char *buf)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +??? unsigned long val, syncr_val;
>> +
>> +??? if (!drvdata->csdev->refcnt)
>> +??????? return -EINVAL;
>> +
>> +??? guard(spinlock)(&drvdata->spinlock);
>> +??? syncr_val = readl_relaxed(drvdata->base + TPDA_SYNCR);
>> +??? val = FIELD_GET(TPDA_SYNCR_MODE_CTRL_MASK, syncr_val);
>> +
>> +??? return sysfs_emit(buf, "%lu\n", val);
>> +}
>> +
>> +static ssize_t syncr_mode_store(struct device *dev,
>> +??????????????? struct device_attribute *attr,
>> +??????????????? const char *buf,
>> +??????????????? size_t size)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +??? unsigned long val;
>> +
>> +??? if (kstrtoul(buf, 0, &val))
>> +??????? return -EINVAL;
>> +
>> +??? guard(spinlock)(&drvdata->spinlock);
>> +??? /* set the mode when first enabling the device */
>> +??? drvdata->syncr_mode = !!val;
>> +
>> +??? return size;
>> +}
>> +static DEVICE_ATTR_RW(syncr_mode);
>> +
>> ? static struct attribute *tpda_attrs[] = {
>> ????? &dev_attr_global_flush_req.attr,
>> +??? &dev_attr_syncr_mode.attr,
>> ????? tpda_trig_sysfs_rw(freq_ts_enable, FREQTS),
>> ????? tpda_trig_sysfs_rw(trig_freq_enable, FRIE),
>> ????? tpda_trig_sysfs_rw(trig_flag_ts_enable, FLRIE),
>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/ 
>> hwtracing/coresight/coresight-tpda.h
>> index 1cc9253293ec..1d2de50bb9f9 100644
>> --- a/drivers/hwtracing/coresight/coresight-tpda.h
>> +++ b/drivers/hwtracing/coresight/coresight-tpda.h
>> @@ -9,6 +9,7 @@
>> ? #define TPDA_CR??????????? (0x000)
>> ? #define TPDA_Pn_CR(n)??????? (0x004 + (n * 4))
>> ? #define TPDA_FPID_CR??????? (0x084)
>> +#define TPDA_SYNCR??????? (0x08C)
>> ? /* Cross trigger global (all ports) flush request bit */
>> ? #define TPDA_CR_FLREQ??????? BIT(0)
>> @@ -36,6 +37,11 @@
>> ? /* Aggregator port DSB data set element size bit */
>> ? #define TPDA_Pn_CR_DSBSIZE??????? BIT(8)
>> +/* TPDA_SYNCR counter mask */
>> +#define TPDA_SYNCR_COUNTER_MASK??????? GENMASK(11, 0)
>> +/* TPDA_SYNCR mode control bit */
>> +#define TPDA_SYNCR_MODE_CTRL_MASK??? GENMASK(12, 12)
>> +
>> ? #define TPDA_MAX_INPORTS??? 32
>> ? /**
>> @@ -52,6 +58,7 @@
>> ?? * @trig_freq:??? Enable/disable cross trigger FREQ packet request 
>> interface.
>> ?? * @freq_ts:??? Enable/disable the timestamp for all FREQ packets.
>> ?? * @cmbchan_mode: Configure the CMB/MCMB channel mode.
>> + * @syncr_mode:??? Configure the mode for counting packets.
>> ?? */
>> ? struct tpda_drvdata {
>> ????? void __iomem??????? *base;
>> @@ -66,6 +73,7 @@ struct tpda_drvdata {
>> ????? bool??????????? trig_freq;
>> ????? bool??????????? freq_ts;
>> ????? bool??????????? cmbchan_mode;
>> +??? bool??????????? syncr_mode;
>> ? };
>> ? /* Enumerate members of global control register(cr) */
>>
> 



From jie.gan at oss.qualcomm.com  Mon Dec 22 18:16:36 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Tue, 23 Dec 2025 10:16:36 +0800
Subject: [PATCH v6 4/4] coresight: tpda: add sysfs node to flush specific
 port
In-Reply-To: <9899b6c2-2bdf-41b8-9156-dcf1b611da39@arm.com>
References: <20251222-add_sysfs_nodes_to_configure_tpda-v6-0-b27143d45c86@oss.qualcomm.com>
 <20251222-add_sysfs_nodes_to_configure_tpda-v6-4-b27143d45c86@oss.qualcomm.com>
 <9899b6c2-2bdf-41b8-9156-dcf1b611da39@arm.com>
Message-ID: <b3b1e130-4592-4863-825f-e00cb9d996b8@oss.qualcomm.com>



On 12/22/2025 9:12 PM, Suzuki K Poulose wrote:
> On 22/12/2025 06:02, Jie Gan wrote:
>> From: Tao Zhang <tao.zhang at oss.qualcomm.com>
>>
>> Setting bit i in the TPDA_FLUSH_CR register initiates a flush request
>> for port i, forcing the data to synchronize and be transmitted to the
>> sink device.
>>
>> Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
>> Reviewed-by: James Clark <james.clark at linaro.org>
>> Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> ---
>> ? .../ABI/testing/sysfs-bus-coresight-devices-tpda?? |? 7 ++++
>> ? drivers/hwtracing/coresight/coresight-tpda.c?????? | 40 ++++++++++++ 
>> ++++++++++
>> ? drivers/hwtracing/coresight/coresight-tpda.h?????? |? 1 +
>> ? 3 files changed, 48 insertions(+)
>>
>> diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices- 
>> tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
>> index d359d90dca72..df8f03d4b573 100644
>> --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
>> +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
>> @@ -51,3 +51,10 @@ Description:
>> ????????? mode 0 - COUNT[11:0] value represents the approximate number 
>> of bytes moved between two ASYNC packet requests
>> ????????? mode 1 - the bits COUNT[11:7] are used as a power of 2. for 
>> example, we could insert an async packet every 8K
>> ?????????????????? data by writing a value 13 to the COUNT[11:7] field.
>> +
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/port_flush_req
>> +Date:??????? December 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Configure the bit i to requests a flush operation of 
>> port i on the TPDA.
> 
> Does this have similar semantics as the "global_flush_req"? for "Read" ? 

Yes, global_flush_req triggers all ports at once, whereas this node 
initiates a flush request for specific port(s).

For reading, we can check whether the flush request has completed.

Thanks,
Jie

> i.e., the bit stays set until the request completes ? Otherwise, why 
> isn't this Write only ?
> 
> I don't see the point of "Reading" this value back.
> 
> Suzuki
> 
>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/ 
>> hwtracing/coresight/coresight-tpda.c
>> index 7baa8a0965d3..f79fea4fbb2c 100644
>> --- a/drivers/hwtracing/coresight/coresight-tpda.c
>> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
>> @@ -430,9 +430,49 @@ static ssize_t syncr_mode_store(struct device *dev,
>> ? }
>> ? static DEVICE_ATTR_RW(syncr_mode);
>> +static ssize_t port_flush_req_show(struct device *dev,
>> +?????????????????? struct device_attribute *attr,
>> +?????????????????? char *buf)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +??? unsigned long val;
>> +
>> +??? if (!drvdata->csdev->refcnt)
>> +??????? return -EINVAL;
>> +
>> +??? guard(spinlock)(&drvdata->spinlock);
>> +??? val = readl_relaxed(drvdata->base + TPDA_FLUSH_CR);
>> +
>> +??? return sysfs_emit(buf, "0x%lx\n", val);
>> +}
>> +
>> +static ssize_t port_flush_req_store(struct device *dev,
>> +??????????????????? struct device_attribute *attr,
>> +??????????????????? const char *buf,
>> +??????????????????? size_t size)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +??? u32 val;
>> +
>> +??? if (kstrtou32(buf, 0, &val))
>> +??????? return -EINVAL;
>> +
>> +??? if (!drvdata->csdev->refcnt || !val)
>> +??????? return -EINVAL;
>> +
>> +??? guard(spinlock)(&drvdata->spinlock);
>> +??? CS_UNLOCK(drvdata->base);
>> +??? writel_relaxed(val, drvdata->base + TPDA_FLUSH_CR);
>> +??? CS_LOCK(drvdata->base);
>> +
>> +??? return size;
>> +}
>> +static DEVICE_ATTR_RW(port_flush_req);
>> +
>> ? static struct attribute *tpda_attrs[] = {
>> ????? &dev_attr_global_flush_req.attr,
>> ????? &dev_attr_syncr_mode.attr,
>> +??? &dev_attr_port_flush_req.attr,
>> ????? tpda_trig_sysfs_rw(freq_ts_enable, FREQTS),
>> ????? tpda_trig_sysfs_rw(trig_freq_enable, FRIE),
>> ????? tpda_trig_sysfs_rw(trig_flag_ts_enable, FLRIE),
>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/ 
>> hwtracing/coresight/coresight-tpda.h
>> index 1d2de50bb9f9..ef1ce2ce36a9 100644
>> --- a/drivers/hwtracing/coresight/coresight-tpda.h
>> +++ b/drivers/hwtracing/coresight/coresight-tpda.h
>> @@ -10,6 +10,7 @@
>> ? #define TPDA_Pn_CR(n)??????? (0x004 + (n * 4))
>> ? #define TPDA_FPID_CR??????? (0x084)
>> ? #define TPDA_SYNCR??????? (0x08C)
>> +#define TPDA_FLUSH_CR??????? (0x090)
>> ? /* Cross trigger global (all ports) flush request bit */
>> ? #define TPDA_CR_FLREQ??????? BIT(0)
>>
> 



From 21cnbao at gmail.com  Mon Dec 22 18:36:46 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Tue, 23 Dec 2025 15:36:46 +1300
Subject: [PATCH 5/6] dma-mapping: Allow batched DMA sync operations if supported by the arch
In-Reply-To: <CAGsJ_4yuvHNqHDi8eN-8UoY2McoXUeCMmbjFAr=jSdv8GpGKeg@mail.gmail.com>
References: <CAGsJ_4yuvHNqHDi8eN-8UoY2McoXUeCMmbjFAr=jSdv8GpGKeg@mail.gmail.com>
Message-ID: <20251223023648.31614-1-21cnbao@gmail.com>

>
> >
> > I would also rename arch_sync_dma_batch_flush() to arch_sync_dma_flush().
>
> Sure.
>
> >
> > You can also minimize changes in dma_direct_map_phys() too, by extending
> > it's signature to provide if flush is needed or not.
>
> Yes. I have
>
> static inline dma_addr_t __dma_direct_map_phys(struct device *dev,
> ? ? ? ? ? ? ? ? phys_addr_t phys, size_t size, enum dma_data_direction dir,
> ? ? ? ? ? ? ? ? unsigned long attrs, bool flush)
>
> and two wrappers:
> static inline dma_addr_t dma_direct_map_phys(struct device *dev,
> ? ? ? ? ? ? ? ? phys_addr_t phys, size_t size, enum dma_data_direction dir,
> ? ? ? ? ? ? ? ? unsigned long attrs)
> {
> ? ? ? ? return __dma_direct_map_phys(dev, phys, size, dir, attrs, true);
> }
>
> static inline dma_addr_t dma_direct_map_phys_batch_add(struct device *dev,
> ? ? ? ? ? ? ? ? phys_addr_t phys, size_t size, enum dma_data_direction dir,
> ? ? ? ? ? ? ? ? unsigned long attrs)
> {
> ? ? ? ? return __dma_direct_map_phys(dev, phys, size, dir, attrs, false);
> }
>
> If you prefer exposing "flush" directly in dma_direct_map_phys()
> and updating its callers with flush=true, I think that?s fine.
>
> It could be also true for dma_direct_sync_single_for_device().

sorry for typo. I meant dma_direct_sync_single_for_cpu().
With flush passed as an argument, the patch becomes the following.
Please feel free to comment before I send v2.


diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index 50c3fe2a1d55..5c65d213eb37 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -403,9 +403,11 @@ void dma_direct_sync_sg_for_device(struct device *dev,
 		swiotlb_sync_single_for_device(dev, paddr, sg->length, dir);
 
 		if (!dev_is_dma_coherent(dev))
-			arch_sync_dma_for_device(paddr, sg->length,
+			arch_sync_dma_for_device_batch_add(paddr, sg->length,
 					dir);
 	}
+	if (!dev_is_dma_coherent(dev))
+		arch_sync_dma_flush();
 }
 #endif
 
@@ -422,7 +424,7 @@ void dma_direct_sync_sg_for_cpu(struct device *dev,
 		phys_addr_t paddr = dma_to_phys(dev, sg_dma_address(sg));
 
 		if (!dev_is_dma_coherent(dev))
-			arch_sync_dma_for_cpu(paddr, sg->length, dir);
+			arch_sync_dma_for_cpu_batch_add(paddr, sg->length, dir);
 
 		swiotlb_sync_single_for_cpu(dev, paddr, sg->length, dir);
 
@@ -430,8 +432,10 @@ void dma_direct_sync_sg_for_cpu(struct device *dev,
 			arch_dma_mark_clean(paddr, sg->length);
 	}
 
-	if (!dev_is_dma_coherent(dev))
+	if (!dev_is_dma_coherent(dev)) {
 		arch_sync_dma_for_cpu_all();
+		arch_sync_dma_flush();
+	}
 }
 
 /*
@@ -443,14 +447,19 @@ void dma_direct_unmap_sg(struct device *dev, struct scatterlist *sgl,
 {
 	struct scatterlist *sg;
 	int i;
+	bool need_sync = false;
 
 	for_each_sg(sgl,  sg, nents, i) {
-		if (sg_dma_is_bus_address(sg))
+		if (sg_dma_is_bus_address(sg)) {
 			sg_dma_unmark_bus_address(sg);
-		else
+		} else {
+			need_sync = true;
 			dma_direct_unmap_phys(dev, sg->dma_address,
-					      sg_dma_len(sg), dir, attrs);
+					      sg_dma_len(sg), dir, attrs, false);
+		}
 	}
+	if (need_sync && !dev_is_dma_coherent(dev))
+		arch_sync_dma_flush();
 }
 #endif
 
@@ -460,6 +469,7 @@ int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
 	struct pci_p2pdma_map_state p2pdma_state = {};
 	struct scatterlist *sg;
 	int i, ret;
+	bool need_sync = false;
 
 	for_each_sg(sgl, sg, nents, i) {
 		switch (pci_p2pdma_state(&p2pdma_state, dev, sg_page(sg))) {
@@ -471,8 +481,9 @@ int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
 			 */
 			break;
 		case PCI_P2PDMA_MAP_NONE:
+			need_sync = true;
 			sg->dma_address = dma_direct_map_phys(dev, sg_phys(sg),
-					sg->length, dir, attrs);
+					sg->length, dir, attrs, false);
 			if (sg->dma_address == DMA_MAPPING_ERROR) {
 				ret = -EIO;
 				goto out_unmap;
@@ -491,6 +502,8 @@ int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
 		sg_dma_len(sg) = sg->length;
 	}
 
+	if (need_sync && !dev_is_dma_coherent(dev))
+		arch_sync_dma_flush();
 	return nents;
 
 out_unmap:
diff --git a/kernel/dma/direct.h b/kernel/dma/direct.h
index da2fadf45bcd..b13eb5bfd051 100644
--- a/kernel/dma/direct.h
+++ b/kernel/dma/direct.h
@@ -65,12 +65,15 @@ static inline void dma_direct_sync_single_for_device(struct device *dev,
 }
 
 static inline void dma_direct_sync_single_for_cpu(struct device *dev,
-		dma_addr_t addr, size_t size, enum dma_data_direction dir)
+		dma_addr_t addr, size_t size, enum dma_data_direction dir,
+		bool flush)
 {
 	phys_addr_t paddr = dma_to_phys(dev, addr);
 
 	if (!dev_is_dma_coherent(dev)) {
-		arch_sync_dma_for_cpu(paddr, size, dir);
+		arch_sync_dma_for_cpu_batch_add(paddr, size, dir);
+		if (flush)
+			arch_sync_dma_flush();
 		arch_sync_dma_for_cpu_all();
 	}
 
@@ -82,7 +85,7 @@ static inline void dma_direct_sync_single_for_cpu(struct device *dev,
 
 static inline dma_addr_t dma_direct_map_phys(struct device *dev,
 		phys_addr_t phys, size_t size, enum dma_data_direction dir,
-		unsigned long attrs)
+		unsigned long attrs, bool flush)
 {
 	dma_addr_t dma_addr;
 
@@ -109,8 +112,11 @@ static inline dma_addr_t dma_direct_map_phys(struct device *dev,
 	}
 
 	if (!dev_is_dma_coherent(dev) &&
-	    !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO)))
-		arch_sync_dma_for_device(phys, size, dir);
+	    !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO))) {
+		arch_sync_dma_for_device_batch_add(phys, size, dir);
+		if (flush)
+			arch_sync_dma_flush();
+	}
 	return dma_addr;
 
 err_overflow:
@@ -122,7 +128,8 @@ static inline dma_addr_t dma_direct_map_phys(struct device *dev,
 }
 
 static inline void dma_direct_unmap_phys(struct device *dev, dma_addr_t addr,
-		size_t size, enum dma_data_direction dir, unsigned long attrs)
+		size_t size, enum dma_data_direction dir, unsigned long attrs,
+		bool flush)
 {
 	phys_addr_t phys;
 
@@ -132,9 +139,10 @@ static inline void dma_direct_unmap_phys(struct device *dev, dma_addr_t addr,
 
 	phys = dma_to_phys(dev, addr);
 	if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
-		dma_direct_sync_single_for_cpu(dev, addr, size, dir);
+		dma_direct_sync_single_for_cpu(dev, addr, size, dir, flush);
 
 	swiotlb_tbl_unmap_single(dev, phys, size, dir,
 					 attrs | DMA_ATTR_SKIP_CPU_SYNC);
 }
+
 #endif /* _KERNEL_DMA_DIRECT_H */
diff --git a/kernel/dma/mapping.c b/kernel/dma/mapping.c
index 37163eb49f9f..d8cfa56a3cbb 100644
--- a/kernel/dma/mapping.c
+++ b/kernel/dma/mapping.c
@@ -166,7 +166,7 @@ dma_addr_t dma_map_phys(struct device *dev, phys_addr_t phys, size_t size,
 
 	if (dma_map_direct(dev, ops) ||
 	    (!is_mmio && arch_dma_map_phys_direct(dev, phys + size)))
-		addr = dma_direct_map_phys(dev, phys, size, dir, attrs);
+		addr = dma_direct_map_phys(dev, phys, size, dir, attrs, true);
 	else if (use_dma_iommu(dev))
 		addr = iommu_dma_map_phys(dev, phys, size, dir, attrs);
 	else if (ops->map_phys)
@@ -207,7 +207,7 @@ void dma_unmap_phys(struct device *dev, dma_addr_t addr, size_t size,
 	BUG_ON(!valid_dma_direction(dir));
 	if (dma_map_direct(dev, ops) ||
 	    (!is_mmio && arch_dma_unmap_phys_direct(dev, addr + size)))
-		dma_direct_unmap_phys(dev, addr, size, dir, attrs);
+		dma_direct_unmap_phys(dev, addr, size, dir, attrs, true);
 	else if (use_dma_iommu(dev))
 		iommu_dma_unmap_phys(dev, addr, size, dir, attrs);
 	else if (ops->unmap_phys)
@@ -373,7 +373,7 @@ void __dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr, size_t size,
 
 	BUG_ON(!valid_dma_direction(dir));
 	if (dma_map_direct(dev, ops))
-		dma_direct_sync_single_for_cpu(dev, addr, size, dir);
+		dma_direct_sync_single_for_cpu(dev, addr, size, dir, true);
 	else if (use_dma_iommu(dev))
 		iommu_dma_sync_single_for_cpu(dev, addr, size, dir);
 	else if (ops->sync_single_for_cpu)
-- 
2.43.0


From wenst at chromium.org  Mon Dec 22 19:19:16 2025
From: wenst at chromium.org (Chen-Yu Tsai)
Date: Tue, 23 Dec 2025 11:19:16 +0800
Subject: [PATCH] clk: mediatek: don't select clk-mt8192 for all ARM64 builds
In-Reply-To: <20251222150235.34919-1-bartosz.golaszewski@oss.qualcomm.com>
References: <20251222150235.34919-1-bartosz.golaszewski@oss.qualcomm.com>
Message-ID: <CAGXv+5Gpf+U8ih_QvZmEwSQgkb2c0wesLNePCG=eDqy0G7F-vA@mail.gmail.com>

On Mon, Dec 22, 2025 at 11:02?PM Bartosz Golaszewski
<bartosz.golaszewski at oss.qualcomm.com> wrote:
>
> This option defaults to y for ARCH64 meaning it's built even if we don't
> want anything related to mediatek. Make the default condition stricter
> and only build it if ARCH_MEDIATEK is selected.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>

Reviewed-by: Chen-Yu Tsai <wenst at chromium.org>


From lkp at intel.com  Mon Dec 22 20:23:33 2025
From: lkp at intel.com (kernel test robot)
Date: Tue, 23 Dec 2025 12:23:33 +0800
Subject: [soc:ti/fixes] BUILD SUCCESS
 cf5e8adebe77917a4cc95e43e461cdbd857591ce
Message-ID: <202512231228.39XCot5A-lkp@intel.com>

tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git ti/fixes
branch HEAD: cf5e8adebe77917a4cc95e43e461cdbd857591ce  arm64: dts: ti: k3-am62-lp-sk-nand: Rename pinctrls to fix schema warnings

elapsed time: 1091m

configs tested: 145
configs skipped: 25

The following configs have been built successfully.
More configs may be tested in the coming days.

tested configs:
alpha                             allnoconfig    gcc-15.1.0
alpha                            allyesconfig    gcc-15.1.0
alpha                               defconfig    gcc-15.1.0
arc                              allmodconfig    clang-16
arc                               allnoconfig    gcc-15.1.0
arc                              allyesconfig    clang-22
arc                              allyesconfig    gcc-15.1.0
arc                                 defconfig    gcc-15.1.0
arc                   randconfig-001-20251223    gcc-8.5.0
arc                   randconfig-002-20251223    gcc-8.5.0
arm                               allnoconfig    clang-22
arm                               allnoconfig    gcc-15.1.0
arm                              allyesconfig    clang-16
arm                                 defconfig    gcc-15.1.0
arm                   randconfig-001-20251223    gcc-8.5.0
arm                   randconfig-002-20251223    gcc-8.5.0
arm                   randconfig-003-20251223    gcc-8.5.0
arm                   randconfig-004-20251223    gcc-8.5.0
arm64                            allmodconfig    clang-19
arm64                            allmodconfig    clang-22
arm64                             allnoconfig    gcc-15.1.0
arm64                               defconfig    gcc-15.1.0
arm64                 randconfig-001-20251223    gcc-15.1.0
arm64                 randconfig-002-20251223    gcc-15.1.0
arm64                 randconfig-003-20251223    gcc-15.1.0
arm64                 randconfig-004-20251223    gcc-15.1.0
csky                             allmodconfig    gcc-15.1.0
csky                              allnoconfig    gcc-15.1.0
csky                                defconfig    gcc-15.1.0
csky                  randconfig-001-20251223    gcc-15.1.0
csky                  randconfig-002-20251223    gcc-15.1.0
hexagon                          allmodconfig    gcc-15.1.0
hexagon                           allnoconfig    clang-22
hexagon                           allnoconfig    gcc-15.1.0
hexagon                             defconfig    gcc-15.1.0
hexagon               randconfig-001-20251223    gcc-15.1.0
hexagon               randconfig-002-20251223    gcc-15.1.0
i386                             allmodconfig    clang-20
i386                              allnoconfig    gcc-14
i386                              allnoconfig    gcc-15.1.0
i386                             allyesconfig    clang-20
i386        buildonly-randconfig-001-20251223    gcc-14
i386        buildonly-randconfig-002-20251223    gcc-14
i386        buildonly-randconfig-003-20251223    gcc-14
i386        buildonly-randconfig-004-20251223    gcc-14
i386        buildonly-randconfig-005-20251223    gcc-14
i386        buildonly-randconfig-006-20251223    gcc-14
i386                                defconfig    gcc-15.1.0
loongarch                        allmodconfig    clang-19
loongarch                        allmodconfig    clang-22
loongarch                         allnoconfig    clang-22
loongarch                         allnoconfig    gcc-15.1.0
loongarch                           defconfig    clang-19
loongarch             randconfig-001-20251223    gcc-15.1.0
loongarch             randconfig-002-20251223    gcc-15.1.0
m68k                             allmodconfig    gcc-15.1.0
m68k                              allnoconfig    gcc-15.1.0
m68k                             allyesconfig    clang-16
m68k                                defconfig    clang-19
microblaze                        allnoconfig    gcc-15.1.0
microblaze                       allyesconfig    gcc-15.1.0
microblaze                          defconfig    clang-19
mips                             allmodconfig    gcc-15.1.0
mips                              allnoconfig    gcc-15.1.0
mips                             allyesconfig    gcc-15.1.0
nios2                         10m50_defconfig    clang-22
nios2                            allmodconfig    clang-22
nios2                               defconfig    clang-19
nios2                 randconfig-001-20251223    gcc-15.1.0
nios2                 randconfig-002-20251223    gcc-15.1.0
openrisc                         allmodconfig    clang-22
openrisc                            defconfig    gcc-15.1.0
parisc                           allmodconfig    gcc-15.1.0
parisc                           allyesconfig    clang-19
parisc                              defconfig    gcc-15.1.0
parisc                randconfig-001-20251223    clang-22
parisc                randconfig-002-20251223    clang-22
parisc64                            defconfig    clang-19
powerpc                          allmodconfig    gcc-15.1.0
powerpc                    amigaone_defconfig    clang-22
powerpc                     mpc512x_defconfig    clang-22
powerpc                  mpc866_ads_defconfig    clang-22
powerpc               randconfig-001-20251223    clang-22
powerpc               randconfig-002-20251223    clang-22
powerpc                     tqm8548_defconfig    clang-22
powerpc64             randconfig-001-20251223    clang-22
powerpc64             randconfig-002-20251223    clang-22
riscv                            allmodconfig    clang-22
riscv                            allyesconfig    clang-16
riscv                               defconfig    gcc-15.1.0
riscv                 randconfig-001-20251223    gcc-14.3.0
riscv                 randconfig-002-20251223    gcc-14.3.0
s390                             allmodconfig    clang-19
s390                             allyesconfig    gcc-15.1.0
s390                                defconfig    gcc-15.1.0
s390                  randconfig-001-20251223    gcc-14.3.0
s390                  randconfig-002-20251223    gcc-14.3.0
sh                               allmodconfig    gcc-15.1.0
sh                               allyesconfig    clang-19
sh                                  defconfig    gcc-14
sh                    randconfig-001-20251223    gcc-14.3.0
sh                    randconfig-002-20251223    gcc-14.3.0
sh                   secureedge5410_defconfig    clang-22
sh                             sh03_defconfig    clang-22
sparc                               defconfig    gcc-15.1.0
sparc                 randconfig-001-20251223    clang-22
sparc                 randconfig-002-20251223    clang-22
sparc64                          allmodconfig    clang-22
sparc64                             defconfig    gcc-14
sparc64               randconfig-001-20251223    clang-22
sparc64               randconfig-002-20251223    clang-22
um                               allmodconfig    clang-19
um                               allyesconfig    gcc-15.1.0
um                                  defconfig    gcc-14
um                             i386_defconfig    clang-22
um                             i386_defconfig    gcc-14
um                    randconfig-001-20251223    clang-22
um                    randconfig-002-20251223    clang-22
um                           x86_64_defconfig    gcc-14
x86_64                           allmodconfig    clang-20
x86_64                           allyesconfig    clang-20
x86_64      buildonly-randconfig-001-20251223    clang-20
x86_64      buildonly-randconfig-002-20251223    clang-20
x86_64      buildonly-randconfig-003-20251223    clang-20
x86_64      buildonly-randconfig-004-20251223    clang-20
x86_64      buildonly-randconfig-005-20251223    clang-20
x86_64      buildonly-randconfig-006-20251223    clang-20
x86_64                              defconfig    gcc-14
x86_64                                  kexec    clang-20
x86_64                randconfig-071-20251223    gcc-14
x86_64                randconfig-072-20251223    gcc-14
x86_64                randconfig-073-20251223    gcc-14
x86_64                randconfig-074-20251223    gcc-14
x86_64                randconfig-075-20251223    gcc-14
x86_64                randconfig-076-20251223    gcc-14
x86_64                               rhel-9.4    clang-20
x86_64                           rhel-9.4-bpf    gcc-14
x86_64                          rhel-9.4-func    clang-20
x86_64                    rhel-9.4-kselftests    clang-20
x86_64                         rhel-9.4-kunit    gcc-14
x86_64                           rhel-9.4-ltp    gcc-14
x86_64                          rhel-9.4-rust    clang-20
xtensa                           allyesconfig    clang-22
xtensa                randconfig-001-20251223    clang-22
xtensa                randconfig-002-20251223    clang-22

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From lkp at intel.com  Mon Dec 22 20:25:12 2025
From: lkp at intel.com (kernel test robot)
Date: Tue, 23 Dec 2025 12:25:12 +0800
Subject: [soc:arm/fixes] BUILD SUCCESS
 c4c6db7ac54649c0cfe7d86b4a5358296dc8d08b
Message-ID: <202512231207.yLZmN61U-lkp@intel.com>

tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git arm/fixes
branch HEAD: c4c6db7ac54649c0cfe7d86b4a5358296dc8d08b  MAINTAINERS: Fix a linusw mail address

elapsed time: 1092m

configs tested: 157
configs skipped: 2

The following configs have been built successfully.
More configs may be tested in the coming days.

tested configs:
alpha                             allnoconfig    gcc-15.1.0
alpha                            allyesconfig    gcc-15.1.0
alpha                               defconfig    gcc-15.1.0
arc                              allmodconfig    gcc-15.1.0
arc                               allnoconfig    gcc-15.1.0
arc                              allyesconfig    gcc-15.1.0
arc                   randconfig-001-20251223    gcc-8.5.0
arc                   randconfig-002-20251223    gcc-8.5.0
arm                               allnoconfig    clang-22
arm                              allyesconfig    gcc-15.1.0
arm                       aspeed_g5_defconfig    gcc-15.1.0
arm                       omap2plus_defconfig    gcc-15.1.0
arm                   randconfig-001-20251223    clang-22
arm                   randconfig-002-20251223    gcc-10.5.0
arm                   randconfig-003-20251223    clang-20
arm                   randconfig-004-20251223    gcc-8.5.0
arm64                            allmodconfig    clang-19
arm64                             allnoconfig    gcc-15.1.0
arm64                 randconfig-001-20251223    clang-17
arm64                 randconfig-002-20251223    clang-22
arm64                 randconfig-003-20251223    clang-18
arm64                 randconfig-004-20251223    gcc-9.5.0
csky                             allmodconfig    gcc-15.1.0
csky                              allnoconfig    gcc-15.1.0
csky                  randconfig-001-20251223    gcc-11.5.0
csky                  randconfig-002-20251223    gcc-15.1.0
hexagon                          allmodconfig    clang-17
hexagon                           allnoconfig    clang-22
hexagon               randconfig-001-20251223    clang-22
hexagon               randconfig-002-20251223    clang-22
i386                             allmodconfig    gcc-14
i386                              allnoconfig    gcc-14
i386                             allyesconfig    gcc-14
i386        buildonly-randconfig-001-20251223    clang-20
i386        buildonly-randconfig-002-20251223    gcc-14
i386        buildonly-randconfig-003-20251223    clang-20
i386        buildonly-randconfig-004-20251223    clang-20
i386        buildonly-randconfig-005-20251223    gcc-14
i386        buildonly-randconfig-006-20251223    clang-20
i386                  randconfig-001-20251223    clang-20
i386                  randconfig-002-20251223    gcc-14
i386                  randconfig-003-20251223    clang-20
i386                  randconfig-004-20251223    gcc-14
i386                  randconfig-005-20251223    gcc-13
i386                  randconfig-006-20251223    gcc-14
i386                  randconfig-007-20251223    gcc-14
i386                  randconfig-011-20251223    gcc-12
i386                  randconfig-012-20251223    gcc-14
i386                  randconfig-013-20251223    gcc-12
i386                  randconfig-014-20251223    gcc-14
i386                  randconfig-015-20251223    gcc-14
loongarch                        allmodconfig    clang-19
loongarch                         allnoconfig    clang-22
loongarch                           defconfig    clang-19
loongarch             randconfig-001-20251223    gcc-15.1.0
loongarch             randconfig-002-20251223    clang-22
m68k                             allmodconfig    gcc-15.1.0
m68k                              allnoconfig    gcc-15.1.0
m68k                             allyesconfig    gcc-15.1.0
m68k                                defconfig    gcc-15.1.0
m68k                        m5272c3_defconfig    gcc-15.1.0
microblaze                        allnoconfig    gcc-15.1.0
microblaze                       allyesconfig    gcc-15.1.0
microblaze                          defconfig    gcc-15.1.0
mips                             allmodconfig    gcc-15.1.0
mips                              allnoconfig    gcc-15.1.0
mips                             allyesconfig    gcc-15.1.0
mips                          eyeq6_defconfig    clang-22
nios2                            allmodconfig    gcc-11.5.0
nios2                             allnoconfig    gcc-11.5.0
nios2                               defconfig    gcc-11.5.0
nios2                 randconfig-001-20251223    gcc-11.5.0
nios2                 randconfig-002-20251223    gcc-11.5.0
openrisc                         allmodconfig    gcc-15.1.0
openrisc                          allnoconfig    gcc-15.1.0
openrisc                            defconfig    gcc-15.1.0
parisc                           allmodconfig    gcc-15.1.0
parisc                            allnoconfig    gcc-15.1.0
parisc                           allyesconfig    gcc-15.1.0
parisc                              defconfig    gcc-15.1.0
parisc                randconfig-001-20251223    gcc-8.5.0
parisc                randconfig-002-20251223    gcc-8.5.0
parisc64                            defconfig    gcc-15.1.0
powerpc                          allmodconfig    gcc-15.1.0
powerpc                           allnoconfig    gcc-15.1.0
powerpc                         ps3_defconfig    gcc-15.1.0
powerpc               randconfig-001-20251223    clang-22
powerpc               randconfig-002-20251223    clang-22
powerpc64             randconfig-001-20251223    clang-17
powerpc64             randconfig-002-20251223    clang-22
riscv                            allmodconfig    clang-22
riscv                             allnoconfig    gcc-15.1.0
riscv                            allyesconfig    clang-16
riscv                               defconfig    clang-22
riscv                 randconfig-001-20251223    gcc-8.5.0
riscv                 randconfig-002-20251223    clang-22
s390                             allmodconfig    clang-18
s390                              allnoconfig    clang-22
s390                             allyesconfig    gcc-15.1.0
s390                                defconfig    clang-22
s390                  randconfig-001-20251223    gcc-14.3.0
s390                  randconfig-002-20251223    gcc-14.3.0
sh                               allmodconfig    gcc-15.1.0
sh                                allnoconfig    gcc-15.1.0
sh                               allyesconfig    gcc-15.1.0
sh                                  defconfig    gcc-15.1.0
sh                    randconfig-001-20251223    gcc-10.5.0
sh                    randconfig-002-20251223    gcc-15.1.0
sparc                             allnoconfig    gcc-15.1.0
sparc                               defconfig    gcc-15.1.0
sparc                 randconfig-001-20251223    gcc-15.1.0
sparc                 randconfig-002-20251223    gcc-12.5.0
sparc64                          allmodconfig    clang-22
sparc64                             defconfig    clang-20
sparc64               randconfig-001-20251223    gcc-8.5.0
sparc64               randconfig-002-20251223    gcc-8.5.0
um                               allmodconfig    clang-19
um                                allnoconfig    clang-22
um                               allyesconfig    gcc-14
um                                  defconfig    clang-22
um                             i386_defconfig    gcc-14
um                    randconfig-001-20251223    clang-22
um                    randconfig-002-20251223    gcc-14
um                           x86_64_defconfig    clang-22
x86_64                           allmodconfig    clang-20
x86_64                            allnoconfig    clang-20
x86_64                           allyesconfig    clang-20
x86_64      buildonly-randconfig-001-20251223    clang-20
x86_64      buildonly-randconfig-002-20251223    clang-20
x86_64      buildonly-randconfig-003-20251223    gcc-14
x86_64      buildonly-randconfig-004-20251223    gcc-14
x86_64      buildonly-randconfig-005-20251223    clang-20
x86_64      buildonly-randconfig-006-20251223    clang-20
x86_64                              defconfig    gcc-14
x86_64                randconfig-001-20251223    gcc-14
x86_64                randconfig-002-20251223    clang-20
x86_64                randconfig-003-20251223    gcc-14
x86_64                randconfig-004-20251223    clang-20
x86_64                randconfig-005-20251223    gcc-14
x86_64                randconfig-006-20251223    clang-20
x86_64                randconfig-011-20251223    gcc-14
x86_64                randconfig-012-20251223    clang-20
x86_64                randconfig-013-20251223    clang-20
x86_64                randconfig-014-20251223    clang-20
x86_64                randconfig-015-20251223    gcc-14
x86_64                randconfig-016-20251223    gcc-14
x86_64                randconfig-071-20251223    gcc-14
x86_64                randconfig-072-20251223    clang-20
x86_64                randconfig-073-20251223    clang-20
x86_64                randconfig-074-20251223    gcc-14
x86_64                randconfig-075-20251223    gcc-14
x86_64                randconfig-076-20251223    clang-20
x86_64                          rhel-9.4-rust    clang-20
xtensa                            allnoconfig    gcc-15.1.0
xtensa                           allyesconfig    gcc-15.1.0
xtensa                randconfig-001-20251223    gcc-8.5.0
xtensa                randconfig-002-20251223    gcc-15.1.0

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From devnull+xianwei.zhao.amlogic.com at kernel.org  Mon Dec 22 21:37:09 2025
From: devnull+xianwei.zhao.amlogic.com at kernel.org (Xianwei Zhao via B4 Relay)
Date: Tue, 23 Dec 2025 05:37:09 +0000
Subject: [PATCH v2 1/4] dt-bindings: reset: Add compatible for Amlogic
 S6/S7/S7D
In-Reply-To: <20251223-reset-s6-s7-s7d-v2-0-958f341449f1@amlogic.com>
References: <20251223-reset-s6-s7-s7d-v2-0-958f341449f1@amlogic.com>
Message-ID: <20251223-reset-s6-s7-s7d-v2-1-958f341449f1@amlogic.com>

From: Xianwei Zhao <xianwei.zhao at amlogic.com>

Add compatibles for Amlogic S6/S7/S7D reset controllers,
which fall back to 'amlogic,meson-s4-reset'.

Acked-by: Conor Dooley <conor.dooley at microchip.com>
Signed-off-by: Xianwei Zhao <xianwei.zhao at amlogic.com>
---
 Documentation/devicetree/bindings/reset/amlogic,meson-reset.yaml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/reset/amlogic,meson-reset.yaml b/Documentation/devicetree/bindings/reset/amlogic,meson-reset.yaml
index 150e95c0d9be..ab0239cf16e5 100644
--- a/Documentation/devicetree/bindings/reset/amlogic,meson-reset.yaml
+++ b/Documentation/devicetree/bindings/reset/amlogic,meson-reset.yaml
@@ -25,6 +25,9 @@ properties:
           - enum:
               - amlogic,a4-reset
               - amlogic,a5-reset
+              - amlogic,s6-reset
+              - amlogic,s7-reset
+              - amlogic,s7d-reset
           - const: amlogic,meson-s4-reset
 
   reg:

-- 
2.52.0




From devnull+xianwei.zhao.amlogic.com at kernel.org  Mon Dec 22 21:37:12 2025
From: devnull+xianwei.zhao.amlogic.com at kernel.org (Xianwei Zhao via B4 Relay)
Date: Tue, 23 Dec 2025 05:37:12 +0000
Subject: [PATCH v2 4/4] arm64: dts: amlogic: Add S7D Reset Controller
In-Reply-To: <20251223-reset-s6-s7-s7d-v2-0-958f341449f1@amlogic.com>
References: <20251223-reset-s6-s7-s7d-v2-0-958f341449f1@amlogic.com>
Message-ID: <20251223-reset-s6-s7-s7d-v2-4-958f341449f1@amlogic.com>

From: Xianwei Zhao <xianwei.zhao at amlogic.com>

Add the device node and related header file for Amlogic
S7D reset controller.

Signed-off-by: Xianwei Zhao <xianwei.zhao at amlogic.com>
---
 arch/arm64/boot/dts/amlogic/amlogic-s7d-reset.h | 134 ++++++++++++++++++++++++
 arch/arm64/boot/dts/amlogic/amlogic-s7d.dtsi    |   8 ++
 2 files changed, 142 insertions(+)

diff --git a/arch/arm64/boot/dts/amlogic/amlogic-s7d-reset.h b/arch/arm64/boot/dts/amlogic/amlogic-s7d-reset.h
new file mode 100644
index 000000000000..fb15a93d901e
--- /dev/null
+++ b/arch/arm64/boot/dts/amlogic/amlogic-s7d-reset.h
@@ -0,0 +1,134 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2025 Amlogic, Inc. All rights reserved.
+ */
+
+#ifndef _DT_BINDINGS_AMLOGIC_S7D_RESET_H
+#define _DT_BINDINGS_AMLOGIC_S7D_RESET_H
+
+/* RESET0 */
+#define RESET_USB_DDR0			0
+#define RESET_USB_DDR1			1
+#define RESET_USB_DDR2			2
+#define RESET_USB_DDR3			3
+#define RESET_USB1			4
+#define RESET_USB0			5
+#define RESET_USB1_COMB			6
+#define RESET_USB0_COMB			7
+#define RESET_USBPHY20			8
+#define RESET_USBPHY21			9
+#define RESET_USBCC			10
+#define RESET_BC			11
+#define RESET_AMFC_APB			12
+/*					13-14	*/
+#define RESET_HDMI20_AES		15
+#define RESET_HDMITX_CAPB3		16
+#define RESET_BRG_VCBUS_DEC		17
+#define RESET_VCBUS			18
+#define RESET_VID_PLL_DIV		19
+#define RESET_VIDEO6			20
+#define RESET_GE2D			21
+#define RESET_HDMITXPHY			22
+#define RESET_VID_LOCK			23
+#define RESET_VENCL			24
+#define RESET_VDAC			25
+#define RESET_VENCP			26
+#define RESET_VENCI			27
+#define RESET_RDMA			28
+#define RESET_HDMI_TX			29
+#define RESET_VIU			30
+#define RESET_VENC			31
+
+/* RESET1 */
+#define RESET_AUDIO			32
+#define RESET_MALI_CAPB3		33
+#define RESET_MALI			34
+#define RESET_DDR_APB			35
+#define RESET_DDR			36
+#define RESET_DOS_CAPB3			37
+#define RESET_DOS			38
+#define RESET_GPU_TS			39
+#define RESET_PLCK_DBG			40
+/*					41-47	*/
+#define RESET_ETH			48
+/*					49-63	*/
+
+/* RESET2 */
+#define RESET_AM2AXI			64
+#define RESET_IR_CTRL			65
+/*					66	*/
+#define RESET_TEMPSENSOR_PLL		67
+/*					68-71	*/
+#define RESET_SMART_CARD		72
+#define RESET_SPICC0			73
+/*					74-79	*/
+#define RESET_MSR_CLK			80
+/*					81	*/
+#define RESET_SAR_DIG			82
+#define RESET_SAR_ANA			83
+/*					84-85	*/
+#define RESET_AMFC			86
+/*					87	*/
+#define RESET_ACODEC			88
+#define RESET_CEC			89
+/*					90	*/
+#define RESET_WATCHDOG			91
+/*					92-95	*/
+
+/* RESET3 */
+/* 96 ~ 127 */
+
+/* RESET4 */
+/*					128-131	*/
+#define RESET_PWM_A			128
+#define RESET_PWM_B			129
+#define RESET_PWM_C			130
+#define RESET_PWM_D			131
+#define RESET_PWM_E			132
+#define RESET_PWM_F			133
+#define RESET_PWM_G			134
+#define RESET_PWM_H			135
+#define RESET_PWM_I			136
+#define RESET_PWM_J			137
+#define RESET_UART_A			138
+#define RESET_UART_B			139
+#define RESET_UART_C			140
+#define RESET_UART_D			141
+#define RESET_UART_E			142
+/*					140-143	*/
+#define RESET_I2C_S_A			144
+#define RESET_I2C_M_A			145
+#define RESET_I2C_M_B			146
+#define RESET_I2C_M_C			147
+#define RESET_I2C_M_D			148
+#define RESET_I2C_M_E			149
+/*					150-151	*/
+#define RESET_SD_EMMC_A			152
+#define RESET_SD_EMMC_B			153
+#define RESET_SD_EMMC_C			154
+/*					155-159	*/
+
+/* RESET5 */
+#define RESET_BRG_VDEC_PIPE0		160
+/*					161-163	*/
+#define RESET_BRG_GE2D_PIPE0		164
+#define RESET_BRG_DMC_PIPE0		165
+#define RESET_BRG_A55_PIPE0		166
+#define RESET_BRG_MALI_PIPE0		167
+/*					168	*/
+#define RESET_BRG_MALI_PIPE1		169
+/*					170-171	*/
+#define RESET_BRG_HEVCF_PIPE1		172
+#define RESET_BRG_HEVCB_PIPE1		173
+/*					174-182	*/
+#define RESET_BRG_NIC_EMMC		183
+/*					164	*/
+#define RESET_BRG_NIC_SDIOB		185
+#define RESET_BRG_NIC_SDIOA		186
+#define RESET_BRG_NIC_VAPB		187
+#define RESET_BRG_NIC_DSU		188
+#define RESET_BRG_NIC_CLK81		189
+#define RESET_BRG_NIC_MAIN		190
+#define RESET_BRG_NIC_ALL		191
+
+#endif
diff --git a/arch/arm64/boot/dts/amlogic/amlogic-s7d.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-s7d.dtsi
index 0c4417bcd682..bae89ca6c448 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-s7d.dtsi
+++ b/arch/arm64/boot/dts/amlogic/amlogic-s7d.dtsi
@@ -8,6 +8,7 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/pinctrl/amlogic,pinctrl.h>
 #include <dt-bindings/power/amlogic,s7d-pwrc.h>
+#include "amlogic-s7d-reset.h"
 
 / {
 	cpus {
@@ -106,6 +107,13 @@ uart_b: serial at 7a000 {
 				status = "disabled";
 			};
 
+			reset: reset-controller at 2000 {
+				compatible = "amlogic,s7d-reset",
+					     "amlogic,meson-s4-reset";
+				reg = <0x0 0x2000 0x0 0x98>;
+				#reset-cells = <1>;
+			};
+
 			periphs_pinctrl: pinctrl at 4000 {
 				compatible = "amlogic,pinctrl-s7d",
 					     "amlogic,pinctrl-s7";

-- 
2.52.0




From devnull+xianwei.zhao.amlogic.com at kernel.org  Mon Dec 22 21:37:10 2025
From: devnull+xianwei.zhao.amlogic.com at kernel.org (Xianwei Zhao via B4 Relay)
Date: Tue, 23 Dec 2025 05:37:10 +0000
Subject: [PATCH v2 2/4] arm64: dts: amlogic: Add S6 Reset Controller
In-Reply-To: <20251223-reset-s6-s7-s7d-v2-0-958f341449f1@amlogic.com>
References: <20251223-reset-s6-s7-s7d-v2-0-958f341449f1@amlogic.com>
Message-ID: <20251223-reset-s6-s7-s7d-v2-2-958f341449f1@amlogic.com>

From: Xianwei Zhao <xianwei.zhao at amlogic.com>

Add the device node and related header file for Amlogic
S6 reset controller.

Signed-off-by: Xianwei Zhao <xianwei.zhao at amlogic.com>
---
 arch/arm64/boot/dts/amlogic/amlogic-s6-reset.h | 171 +++++++++++++++++++++++++
 arch/arm64/boot/dts/amlogic/amlogic-s6.dtsi    |   8 ++
 2 files changed, 179 insertions(+)

diff --git a/arch/arm64/boot/dts/amlogic/amlogic-s6-reset.h b/arch/arm64/boot/dts/amlogic/amlogic-s6-reset.h
new file mode 100644
index 000000000000..90bf5a182046
--- /dev/null
+++ b/arch/arm64/boot/dts/amlogic/amlogic-s6-reset.h
@@ -0,0 +1,171 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2025 Amlogic, Inc. All rights reserved.
+ */
+
+#ifndef _DT_BINDINGS_AMLOGIC_S6_RESET_H
+#define _DT_BINDINGS_AMLOGIC_S6_RESET_H
+
+/* RESET0 */
+/*					0-1	*/
+#define RESET_U3DRD_USB3PHY_APB		2
+#define RESET_U3DRD_USB3PHY		3
+#define RESET_U3DRD_USB2PHY		4
+#define RESET_U3DRD			5
+#define RESET_U3DRD_COMB		6
+#define RESET_U2DRD			7
+#define RESET_U2DRD_COMB		8
+#define RESET_U2DRD_USB2PHY		9
+#define RESET_USB_CC			10
+#define RESET_BC			11
+#define RESET_VC9000E_APB		12
+#define RESET_VC9000E			13
+#define RESET_VC9000E_CORE		14
+#define RESET_HDMI20_AES		15
+#define RESET_HDMITX_CAPB3		16
+#define RESET_BRQ_VCBUS_DEC		17
+#define RESET_VCBUS			18
+#define RESET_VID_PLL_DIV		19
+#define RESET_VDI6			20
+/*					21	*/
+#define RESET_HDMITXPHY			22
+#define RESET_VID_LOCK			23
+#define RESET_VENCL			24
+#define RESET_VDAC			25
+#define RESET_VENCP			26
+#define RESET_VENCI			27
+#define RESET_RDMA			28
+#define RESET_HDMITX			29
+#define RESET_VIU			30
+#define RESET_VENC			31
+
+/* RESET1 */
+#define RESET_AUDIO			32
+#define RESET_MALI_CAPB3		33
+#define RESET_MALI			34
+#define RESET_DDR_APB			35
+#define RESET_DDR			36
+#define RESET_DOS_CAPB3			37
+#define RESET_DOS			38
+#define RESET_MALI_SYS			39
+#define RESET_I_DSPA			40
+#define RESET_I_DEBUGA			41
+#define RESET_U3P2_PHY_APB		42
+#define RESET_PCIE_PIPE			43
+#define RESET_PCIE_A			44
+#define RESET_PCIE_PHY			45
+#define RESET_PCIE_APB			46
+#define RESET_AMFC_APB			47
+#define RESET_ETHERNET			48
+/*					49-50	*/
+#define RESET_BRG_ETH_APB_SYNC		51
+#define RESET_VICP			52
+#define RESET_DEWARP			53
+#define RESET_GE2D			54
+#define RESET_VGE			55
+#define RESET_PCIE0			56
+#define RESET_PCIE1			57
+#define RESET_PCIE2			58
+#define RESET_PCIE3			59
+#define RESET_PCIE4			60
+#define RESET_PCIE5			61
+#define RESET_PCIE6			62
+#define RESET_PCIE7			63
+
+/* RESET2 */
+#define RESET_AM2AXI			64
+#define RESET_IR_CTRL			65
+#define RESET_MIPI_DSI_PHY		66
+#define RESET_TS_PLL			67
+#define RESET_MIPI_CSI2_PHY0		68
+#define RESET_ETH_AXI			69
+/*					70-71	*/
+#define RESET_SMART_CARD		72
+#define RESET_SPICC_0			73
+#define RESET_BRG_VGE_PIPE1		74
+#define RESET_BRG_VC9000E_PIPE1		75
+#define RESET_BRG_AMFC_PIPE1		76
+/*					77	*/
+#define RESET_NNA_APB			78
+#define RESET_NNA			79
+#define RESET_MSR_CLK			80
+/*					81	*/
+#define RESET_SAR_DIG			82
+#define RESET_SAR_ANA			83
+/*					84-85	*/
+#define RESET_AMFC			86
+/*					87-88	*/
+#define RESET_CEC			89
+/*					90	*/
+#define RESET_WATCHDOG			91
+/*					92	*/
+#define RESET_MIP_DSI_HOST		93
+/*					94-95	*/
+
+/* RESET3 */
+/* 96 ~ 127 */
+
+/* RESET4 */
+#define RESET_PWM_A			128
+#define RESET_PWM_B			129
+#define RESET_PWM_C			130
+#define RESET_PWM_D			131
+#define RESET_PWM_E			132
+#define RESET_PWM_F			133
+#define RESET_PWM_G			134
+#define RESET_PWM_H			135
+#define RESET_PWM_I			136
+#define RESET_PWM_J			137
+#define RESET_UART_A			138
+#define RESET_UART_B			139
+#define RESET_UART_C			140
+#define RESET_UART_D			141
+#define RESET_UART_E			142
+/*					143	*/
+#define RESET_I2C_S_A			144
+#define RESET_I2C_M_A			145
+#define RESET_I2C_M_B			146
+#define RESET_I2C_M_C			147
+#define RESET_I2C_M_D			148
+#define RESET_I2C_M_E			149
+/*					150-151	*/
+#define RESET_SDEMMC_A			152
+#define RESET_SDEMMC_B			153
+#define RESET_SDEMMC_C			154
+/*					155-159	*/
+
+/* RESET5 */
+#define RESET_BRG_VDEC_PIPE		160
+#define RESET_BRG_SDIOA_PIPE		161
+#define RESET_BRG_SDIOB_PIPE		162
+#define RESET_BRG_EMMC_PIPE		163
+#define RESET_BRG_GE2D_DMC_PIPE		164
+#define RESET_BRG_DMC_VPU_PIPE1		165
+#define RESET_BRG_A53_DMC_PIPE1		166
+#define RESET_BRG_MALI_DMC_PIPE		167
+/*					168	*/
+#define RESET_BRG_MALI_DMC_PIPE1	169
+#define RESET_BRG_U2DRD_PIPE		170
+#define RESET_BRG_U2H_PIPE		171
+#define RESET_BRG_HEVCF_PIPE1		172
+#define RESET_BRG_AMBUS_ETH_PIPE1	173
+#define RESET_BRG_SRAM_NIC_NNA		174
+#define RESET_BRG_SRAM_NIC_MAIN		175
+#define RESET_BRG_SRAM_NIC_DEV		176
+#define RESET_BRG_SRAM_NIC_CPU		177
+#define RESET_BRG_SRAM_NIC_ALL		178
+#define RESET_BRG_CPU_NIC_RAMA		179
+#define RESET_BRG_CPU_NIC_VAPB		180
+#define RESET_BRG_CPU_NIC_DSU		181
+#define RESET_BRG_CPU_NIC_CLK81		182
+#define RESET_BRG_CPU_NIC_ALL		183
+#define RESET_BRG_NIC_CAPU		184
+#define RESET_BRG_AO_NIC_EMMC		185
+#define RESET_BRG_AO_NIC_DSPA		186
+#define RESET_BRG_AO_NIC_SDIOB		187
+#define RESET_BRG_AO_NIC_SDIOA		188
+#define RESET_BRG_AO_NIC_CLK81		189
+#define RESET_BRG_AO_NIC_MAIN		190
+#define RESET_BRG_AO_NIC_ALL		191
+
+#endif
diff --git a/arch/arm64/boot/dts/amlogic/amlogic-s6.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-s6.dtsi
index 8ef631939033..386244b3a1f5 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-s6.dtsi
+++ b/arch/arm64/boot/dts/amlogic/amlogic-s6.dtsi
@@ -8,6 +8,7 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/pinctrl/amlogic,pinctrl.h>
 #include <dt-bindings/power/amlogic,s6-pwrc.h>
+#include "amlogic-s6-reset.h"
 / {
 	cpus {
 		#address-cells = <2>;
@@ -104,6 +105,13 @@ uart_b: serial at 7a000 {
 				status = "disabled";
 			};
 
+			reset: reset-controller at 2000 {
+				compatible = "amlogic,s6-reset",
+					     "amlogic,meson-s4-reset";
+				reg = <0x0 0x2000 0x0 0x98>;
+				#reset-cells = <1>;
+			};
+
 			periphs_pinctrl: pinctrl at 4000 {
 				compatible = "amlogic,pinctrl-s6";
 				#address-cells = <2>;

-- 
2.52.0




From devnull+xianwei.zhao.amlogic.com at kernel.org  Mon Dec 22 21:37:08 2025
From: devnull+xianwei.zhao.amlogic.com at kernel.org (Xianwei Zhao via B4 Relay)
Date: Tue, 23 Dec 2025 05:37:08 +0000
Subject: [PATCH v2 0/4] Add support for Amlogic S6/S7/S7D Reset
Message-ID: <20251223-reset-s6-s7-s7d-v2-0-958f341449f1@amlogic.com>

Add dt-binding compatibles and device nodes for Amlogic S6/S7/S7D reset.

Signed-off-by: Xianwei Zhao <xianwei.zhao at amlogic.com>
---
Changes in v2:
- Fix some macro definition names, MAIL to MALI, PIPEL to PIPE, PIPL to PIPE.
- Link to v1: https://lore.kernel.org/r/20251127-reset-s6-s7-s7d-v1-0-879099ad90d3 at amlogic.com

---
Xianwei Zhao (4):
      dt-bindings: reset: Add compatible for Amlogic S6/S7/S7D
      arm64: dts: amlogic: Add S6 Reset Controller
      arm64: dts: amlogic: Add S7 Reset Controller
      arm64: dts: amlogic: Add S7D Reset Controller

 .../bindings/reset/amlogic,meson-reset.yaml        |   3 +
 arch/arm64/boot/dts/amlogic/amlogic-s6-reset.h     | 171 +++++++++++++++++++++
 arch/arm64/boot/dts/amlogic/amlogic-s6.dtsi        |   8 +
 arch/arm64/boot/dts/amlogic/amlogic-s7-reset.h     | 124 +++++++++++++++
 arch/arm64/boot/dts/amlogic/amlogic-s7.dtsi        |   8 +
 arch/arm64/boot/dts/amlogic/amlogic-s7d-reset.h    | 134 ++++++++++++++++
 arch/arm64/boot/dts/amlogic/amlogic-s7d.dtsi       |   8 +
 7 files changed, 456 insertions(+)
---
base-commit: 79482f3791c4760b9b0d8d9bfde9f1053ea3dd5e
change-id: 20251125-reset-s6-s7-s7d-211f9782dfab

Best regards,
-- 
Xianwei Zhao <xianwei.zhao at amlogic.com>




From devnull+xianwei.zhao.amlogic.com at kernel.org  Mon Dec 22 21:37:11 2025
From: devnull+xianwei.zhao.amlogic.com at kernel.org (Xianwei Zhao via B4 Relay)
Date: Tue, 23 Dec 2025 05:37:11 +0000
Subject: [PATCH v2 3/4] arm64: dts: amlogic: Add S7 Reset Controller
In-Reply-To: <20251223-reset-s6-s7-s7d-v2-0-958f341449f1@amlogic.com>
References: <20251223-reset-s6-s7-s7d-v2-0-958f341449f1@amlogic.com>
Message-ID: <20251223-reset-s6-s7-s7d-v2-3-958f341449f1@amlogic.com>

From: Xianwei Zhao <xianwei.zhao at amlogic.com>

Add the device node and related header file for Amlogic
S7 reset controller.

Signed-off-by: Xianwei Zhao <xianwei.zhao at amlogic.com>
---
 arch/arm64/boot/dts/amlogic/amlogic-s7-reset.h | 124 +++++++++++++++++++++++++
 arch/arm64/boot/dts/amlogic/amlogic-s7.dtsi    |   8 ++
 2 files changed, 132 insertions(+)

diff --git a/arch/arm64/boot/dts/amlogic/amlogic-s7-reset.h b/arch/arm64/boot/dts/amlogic/amlogic-s7-reset.h
new file mode 100644
index 000000000000..243136aaf8ec
--- /dev/null
+++ b/arch/arm64/boot/dts/amlogic/amlogic-s7-reset.h
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2025 Amlogic, Inc. All rights reserved.
+ */
+
+#ifndef _DT_BINDINGS_AMLOGIC_S7_RESET_H
+#define _DT_BINDINGS_AMLOGIC_S7_RESET_H
+
+/* RESET0 */
+#define RESET_USB_DDR0			0
+#define RESET_USB_DDR1			1
+#define RESET_USB_DDR2			2
+#define RESET_USB_DDR3			3
+#define RESET_USB1			4
+#define RESET_USB0			5
+#define RESET_USB1_COMB			6
+#define RESET_USB0_COMB			7
+#define RESET_USBPHY20			8
+#define RESET_USBPHY21			9
+/*					10-14	*/
+#define RESET_HDMI20_AES		15
+#define RESET_HDMITX_CAPB3		16
+#define RESET_BRG_VCBUS_DEC		17
+#define RESET_VCBUS			18
+#define RESET_VID_PLL_DIV		19
+#define RESET_VIDEO6			20
+#define RESET_GE2D			21
+#define RESET_HDMITXPHY			22
+#define RESET_VID_LOCK			23
+#define RESET_VENCL			24
+#define RESET_VDAC			25
+#define RESET_VENCP			26
+#define RESET_VENCI			27
+#define RESET_RDMA			28
+#define RESET_HDMI_TX			29
+#define RESET_VIU			30
+#define RESET_VENC			31
+
+/* RESET1 */
+#define RESET_AUDIO			32
+#define RESET_MALI_CAPB3		33
+#define RESET_MALI			34
+#define RESET_DDR_APB			35
+#define RESET_DDR			36
+#define RESET_DOS_CAPB3			37
+#define RESET_DOS			38
+/*					39-47	*/
+#define RESET_ETH			48
+/*					49-63	*/
+
+/* RESET2 */
+#define RESET_AM2AXI			64
+#define RESET_IR_CTRL			65
+/*					66	*/
+#define RESET_TEMPSENSOR_PLL		67
+/*					68-71	*/
+#define RESET_SMART_CARD		72
+#define RESET_SPICC0			73
+/*					74-79	*/
+#define RESET_MSR_CLK			80
+/*					81	*/
+#define RESET_SARADC			82
+/*					83-87	*/
+#define RESET_ACODEC			88
+#define RESET_CEC			89
+/*					90	*/
+#define RESET_WATCHDOG			91
+/*					92-95	*/
+
+/* RESET3 */
+/* 96 ~ 127 */
+
+/* RESET4 */
+/*					128-131	*/
+#define RESET_PWM_A			128
+#define RESET_PWM_B			129
+#define RESET_PWM_C			130
+#define RESET_PWM_D			131
+#define RESET_PWM_E			132
+#define RESET_PWM_F			133
+#define RESET_PWM_G			134
+#define RESET_PWM_H			135
+#define RESET_PWM_I			136
+#define RESET_PWM_J			137
+#define RESET_UART_A			138
+#define RESET_UART_B			139
+/*					140-143	*/
+#define RESET_I2C_S_A			144
+#define RESET_I2C_M_A			145
+#define RESET_I2C_M_B			146
+#define RESET_I2C_M_C			147
+#define RESET_I2C_M_D			148
+#define RESET_I2C_M_E			149
+/*					150-151	*/
+#define RESET_SD_EMMC_A			152
+#define RESET_SD_EMMC_B			153
+#define RESET_SD_EMMC_C			154
+/*					155-159	*/
+
+/* RESET5 */
+#define RESET_BRG_VDEC_PIPE0		160
+#define RESET_BRG_HEVCF_PIPE0		161
+/*					162-163	*/
+#define RESET_BRG_GE2D_PIPE0		164
+#define RESET_BRG_DMC_PIPE0		165
+#define RESET_BRG_A53_PIPE0		166
+#define RESET_BRG_MALI_PIPE0		167
+/*					168	*/
+#define RESET_BRG_MALI_PIPE1		169
+/*					170-171	*/
+#define RESET_BRG_HEVCF_PIPE1		172
+#define RESET_BRG_HEVCB_PIPE1		173
+/*					174-182	*/
+#define RESET_BRG_NIC_EMMC		183
+#define RESET_BRG_NIC_RAMA		184
+#define RESET_BRG_NIC_SDIOB		185
+#define RESET_BRG_NIC_SDIOA		186
+#define RESET_BRG_NIC_VAPB		187
+#define RESET_BRG_NIC_DSU		188
+#define RESET_BRG_NIC_CLK81		189
+#define RESET_BRG_NIC_MAIN		190
+#define RESET_BRG_NIC_ALL		191
+
+#endif
diff --git a/arch/arm64/boot/dts/amlogic/amlogic-s7.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-s7.dtsi
index a3faf4d188e1..0b2ac24e8dbc 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-s7.dtsi
+++ b/arch/arm64/boot/dts/amlogic/amlogic-s7.dtsi
@@ -8,6 +8,7 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/pinctrl/amlogic,pinctrl.h>
 #include <dt-bindings/power/amlogic,s7-pwrc.h>
+#include "amlogic-s7-reset.h"
 
 / {
 	cpus {
@@ -142,6 +143,13 @@ uart_b: serial at 7a000 {
 				status = "disabled";
 			};
 
+			reset: reset-controller at 2000 {
+				compatible = "amlogic,s7-reset",
+					     "amlogic,meson-s4-reset";
+				reg = <0x0 0x2000 0x0 0x98>;
+				#reset-cells = <1>;
+			};
+
 			periphs_pinctrl: pinctrl at 4000 {
 				compatible = "amlogic,pinctrl-s7";
 				#address-cells = <2>;

-- 
2.52.0




From baolin.wang at linux.alibaba.com  Mon Dec 22 21:48:38 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Tue, 23 Dec 2025 13:48:38 +0800
Subject: [PATCH v4 4/5] arm64: mm: implement the architecture-specific clear_flush_young_ptes()
In-Reply-To: <cover.1766455377.git.baolin.wang@linux.alibaba.com>
References: <cover.1766455377.git.baolin.wang@linux.alibaba.com>
Message-ID: <e1e57d89fed939e3f7ff877e4f406d807a7eebd4.1766455378.git.baolin.wang@linux.alibaba.com>

Implement the Arm64 architecture-specific clear_flush_young_ptes() to enable
batched checking of young flags and TLB flushing, improving performance during
large folio reclamation.

Performance testing:
Allocate 10G clean file-backed folios by mmap() in a memory cgroup, and try to
reclaim 8G file-backed folios via the memory.reclaim interface. I can observe
33% performance improvement on my Arm64 32-core server (and 10%+ improvement
on my X86 machine). Meanwhile, the hotspot folio_check_references() dropped
from approximately 35% to around 5%.

W/o patchset:
real	0m1.518s
user	0m0.000s
sys	0m1.518s

W/ patchset:
real	0m1.018s
user	0m0.000s
sys	0m1.018s

Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
---
 arch/arm64/include/asm/pgtable.h | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index d5fbe72e820a..84a6bdabb1f9 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -1838,6 +1838,17 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
 	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
 }
 
+#define clear_flush_young_ptes clear_flush_young_ptes
+static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
+					unsigned long addr, pte_t *ptep,
+					unsigned int nr)
+{
+	if (likely(nr == 1 && !pte_cont(__ptep_get(ptep))))
+		return __ptep_clear_flush_young(vma, addr, ptep);
+
+	return contpte_clear_flush_young_ptes(vma, addr, ptep, nr);
+}
+
 #define wrprotect_ptes wrprotect_ptes
 static __always_inline void wrprotect_ptes(struct mm_struct *mm,
 				unsigned long addr, pte_t *ptep, unsigned int nr)
-- 
2.47.3



From baolin.wang at linux.alibaba.com  Mon Dec 22 21:48:39 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Tue, 23 Dec 2025 13:48:39 +0800
Subject: [PATCH v4 5/5] mm: rmap: support batched unmapping for file large folios
In-Reply-To: <cover.1766455377.git.baolin.wang@linux.alibaba.com>
References: <cover.1766455377.git.baolin.wang@linux.alibaba.com>
Message-ID: <d869ae45a7be322f342ace62ffcdd4b47f4154fc.1766455378.git.baolin.wang@linux.alibaba.com>

Similar to folio_referenced_one(), we can apply batched unmapping for file
large folios to optimize the performance of file folios reclamation.

Barry previously implemented batched unmapping for lazyfree anonymous large
folios[1] and did not further optimize anonymous large folios or file-backed
large folios at that stage. As for file-backed large folios, the batched
unmapping support is relatively straightforward, as we only need to clear
the consecutive (present) PTE entries for file-backed large folios.

Performance testing:
Allocate 10G clean file-backed folios by mmap() in a memory cgroup, and try to
reclaim 8G file-backed folios via the memory.reclaim interface. I can observe
75% performance improvement on my Arm64 32-core server (and 50%+ improvement
on my X86 machine) with this patch.

W/o patch:
real    0m1.018s
user    0m0.000s
sys     0m1.018s

W/ patch:
real	0m0.249s
user	0m0.000s
sys	0m0.249s

[1] https://lore.kernel.org/all/20250214093015.51024-4-21cnbao at gmail.com/T/#u
Acked-by: Barry Song <baohua at kernel.org>
Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
---
 mm/rmap.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/mm/rmap.c b/mm/rmap.c
index a0fc05f5966f..7482121d4e92 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1862,9 +1862,10 @@ static inline unsigned int folio_unmap_pte_batch(struct folio *folio,
 	end_addr = pmd_addr_end(addr, vma->vm_end);
 	max_nr = (end_addr - addr) >> PAGE_SHIFT;
 
-	/* We only support lazyfree batching for now ... */
-	if (!folio_test_anon(folio) || folio_test_swapbacked(folio))
+	/* We only support lazyfree or file folios batching for now ... */
+	if (folio_test_anon(folio) && folio_test_swapbacked(folio))
 		return 1;
+
 	if (pte_unused(pte))
 		return 1;
 
@@ -2230,7 +2231,7 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
 			 *
 			 * See Documentation/mm/mmu_notifier.rst
 			 */
-			dec_mm_counter(mm, mm_counter_file(folio));
+			add_mm_counter(mm, mm_counter_file(folio), -nr_pages);
 		}
 discard:
 		if (unlikely(folio_test_hugetlb(folio))) {
-- 
2.47.3



From baolin.wang at linux.alibaba.com  Mon Dec 22 21:48:37 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Tue, 23 Dec 2025 13:48:37 +0800
Subject: [PATCH v4 3/5] arm64: mm: support batch clearing of the young flag for large folios
In-Reply-To: <cover.1766455377.git.baolin.wang@linux.alibaba.com>
References: <cover.1766455377.git.baolin.wang@linux.alibaba.com>
Message-ID: <3b427d9010a6d52f2b91342760f12be097d21cf6.1766455378.git.baolin.wang@linux.alibaba.com>

Currently, contpte_ptep_test_and_clear_young() and contpte_ptep_clear_flush_young()
only clear the young flag and flush TLBs for PTEs within the contiguous range.
To support batch PTE operations for other sized large folios in the following
patches, adding a new parameter to specify the number of PTEs that map consecutive
pages of the same large folio in a single VMA and a single page table.

While we are at it, rename the functions to maintain consistency with other
contpte_*() functions.

Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
---
 arch/arm64/include/asm/pgtable.h | 12 ++++++------
 arch/arm64/mm/contpte.c          | 33 ++++++++++++++++++--------------
 2 files changed, 25 insertions(+), 20 deletions(-)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 445e18e92221..d5fbe72e820a 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -1648,10 +1648,10 @@ extern void contpte_clear_full_ptes(struct mm_struct *mm, unsigned long addr,
 extern pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
 				unsigned long addr, pte_t *ptep,
 				unsigned int nr, int full);
-extern int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
-				unsigned long addr, pte_t *ptep);
-extern int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
-				unsigned long addr, pte_t *ptep);
+int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
+				unsigned long addr, pte_t *ptep, unsigned int nr);
+int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
+				unsigned long addr, pte_t *ptep, unsigned int nr);
 extern void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
 				pte_t *ptep, unsigned int nr);
 extern int contpte_ptep_set_access_flags(struct vm_area_struct *vma,
@@ -1823,7 +1823,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
 	if (likely(!pte_valid_cont(orig_pte)))
 		return __ptep_test_and_clear_young(vma, addr, ptep);
 
-	return contpte_ptep_test_and_clear_young(vma, addr, ptep);
+	return contpte_test_and_clear_young_ptes(vma, addr, ptep, CONT_PTES);
 }
 
 #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
@@ -1835,7 +1835,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
 	if (likely(!pte_valid_cont(orig_pte)))
 		return __ptep_clear_flush_young(vma, addr, ptep);
 
-	return contpte_ptep_clear_flush_young(vma, addr, ptep);
+	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
 }
 
 #define wrprotect_ptes wrprotect_ptes
diff --git a/arch/arm64/mm/contpte.c b/arch/arm64/mm/contpte.c
index e4ddeb46f25d..b929a455103f 100644
--- a/arch/arm64/mm/contpte.c
+++ b/arch/arm64/mm/contpte.c
@@ -508,8 +508,9 @@ pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
 }
 EXPORT_SYMBOL_GPL(contpte_get_and_clear_full_ptes);
 
-int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
-					unsigned long addr, pte_t *ptep)
+int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
+					unsigned long addr, pte_t *ptep,
+					unsigned int nr)
 {
 	/*
 	 * ptep_clear_flush_young() technically requires us to clear the access
@@ -518,41 +519,45 @@ int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
 	 * contig range when the range is covered by a single folio, we can get
 	 * away with clearing young for the whole contig range here, so we avoid
 	 * having to unfold.
+	 *
+	 * The 'nr' means consecutive (present) PTEs that map consecutive pages
+	 * of the same large folio in a single VMA and a single page table.
 	 */
 
+	unsigned long end = addr + nr * PAGE_SIZE;
 	int young = 0;
-	int i;
 
-	ptep = contpte_align_down(ptep);
-	addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
-
-	for (i = 0; i < CONT_PTES; i++, ptep++, addr += PAGE_SIZE)
+	ptep = contpte_align_addr_ptep(&addr, &end, ptep, nr);
+	for (; addr != end; ptep++, addr += PAGE_SIZE)
 		young |= __ptep_test_and_clear_young(vma, addr, ptep);
 
 	return young;
 }
-EXPORT_SYMBOL_GPL(contpte_ptep_test_and_clear_young);
+EXPORT_SYMBOL_GPL(contpte_test_and_clear_young_ptes);
 
-int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
-					unsigned long addr, pte_t *ptep)
+int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
+				unsigned long addr, pte_t *ptep,
+				unsigned int nr)
 {
 	int young;
 
-	young = contpte_ptep_test_and_clear_young(vma, addr, ptep);
+	young = contpte_test_and_clear_young_ptes(vma, addr, ptep, nr);
 
 	if (young) {
+		unsigned long end = addr + nr * PAGE_SIZE;
+
+		contpte_align_addr_ptep(&addr, &end, ptep, nr);
 		/*
 		 * See comment in __ptep_clear_flush_young(); same rationale for
 		 * eliding the trailing DSB applies here.
 		 */
-		addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
-		__flush_tlb_range_nosync(vma->vm_mm, addr, addr + CONT_PTE_SIZE,
+		__flush_tlb_range_nosync(vma->vm_mm, addr, end,
 					 PAGE_SIZE, true, 3);
 	}
 
 	return young;
 }
-EXPORT_SYMBOL_GPL(contpte_ptep_clear_flush_young);
+EXPORT_SYMBOL_GPL(contpte_clear_flush_young_ptes);
 
 void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
 					pte_t *ptep, unsigned int nr)
-- 
2.47.3



From baolin.wang at linux.alibaba.com  Mon Dec 22 21:48:36 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Tue, 23 Dec 2025 13:48:36 +0800
Subject: [PATCH v4 2/5] arm64: mm: factor out the address and ptep alignment into a new helper
In-Reply-To: <cover.1766455377.git.baolin.wang@linux.alibaba.com>
References: <cover.1766455377.git.baolin.wang@linux.alibaba.com>
Message-ID: <47e29030347c23ffce238ff5ed752da01a8cc7cb.1766455378.git.baolin.wang@linux.alibaba.com>

Factor out the contpte block's address and ptep alignment into a new helper,
and will be reused in the following patch.

No functional changes.

Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
---
 arch/arm64/mm/contpte.c | 29 +++++++++++++++++++++--------
 1 file changed, 21 insertions(+), 8 deletions(-)

diff --git a/arch/arm64/mm/contpte.c b/arch/arm64/mm/contpte.c
index 589bcf878938..e4ddeb46f25d 100644
--- a/arch/arm64/mm/contpte.c
+++ b/arch/arm64/mm/contpte.c
@@ -26,6 +26,26 @@ static inline pte_t *contpte_align_down(pte_t *ptep)
 	return PTR_ALIGN_DOWN(ptep, sizeof(*ptep) * CONT_PTES);
 }
 
+static inline pte_t *contpte_align_addr_ptep(unsigned long *start,
+					     unsigned long *end, pte_t *ptep,
+					     unsigned int nr)
+{
+	/*
+	 * Note: caller must ensure these nr PTEs are consecutive (present)
+	 * PTEs that map consecutive pages of the same large folio within a
+	 * single VMA and a single page table.
+	 */
+	if (pte_cont(__ptep_get(ptep + nr - 1)))
+		*end = ALIGN(*end, CONT_PTE_SIZE);
+
+	if (pte_cont(__ptep_get(ptep))) {
+		*start = ALIGN_DOWN(*start, CONT_PTE_SIZE);
+		ptep = contpte_align_down(ptep);
+	}
+
+	return ptep;
+}
+
 static void contpte_try_unfold_partial(struct mm_struct *mm, unsigned long addr,
 					pte_t *ptep, unsigned int nr)
 {
@@ -569,14 +589,7 @@ void contpte_clear_young_dirty_ptes(struct vm_area_struct *vma,
 	unsigned long start = addr;
 	unsigned long end = start + nr * PAGE_SIZE;
 
-	if (pte_cont(__ptep_get(ptep + nr - 1)))
-		end = ALIGN(end, CONT_PTE_SIZE);
-
-	if (pte_cont(__ptep_get(ptep))) {
-		start = ALIGN_DOWN(start, CONT_PTE_SIZE);
-		ptep = contpte_align_down(ptep);
-	}
-
+	ptep = contpte_align_addr_ptep(&start, &end, ptep, nr);
 	__clear_young_dirty_ptes(vma, start, ptep, (end - start) / PAGE_SIZE, flags);
 }
 EXPORT_SYMBOL_GPL(contpte_clear_young_dirty_ptes);
-- 
2.47.3



From baolin.wang at linux.alibaba.com  Mon Dec 22 21:48:35 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Tue, 23 Dec 2025 13:48:35 +0800
Subject: [PATCH v4 1/5] mm: rmap: support batched checks of the references for large folios
In-Reply-To: <cover.1766455377.git.baolin.wang@linux.alibaba.com>
References: <cover.1766455377.git.baolin.wang@linux.alibaba.com>
Message-ID: <e9ff5fa689740f3b6f3ed1c1ec0e3244f20c1f06.1766455378.git.baolin.wang@linux.alibaba.com>

Currently, folio_referenced_one() always checks the young flag for each PTE
sequentially, which is inefficient for large folios. This inefficiency is
especially noticeable when reclaiming clean file-backed large folios, where
folio_referenced() is observed as a significant performance hotspot.

Moreover, on Arm64 architecture, which supports contiguous PTEs, there is already
an optimization to clear the young flags for PTEs within a contiguous range.
However, this is not sufficient. We can extend this to perform batched operations
for the entire large folio (which might exceed the contiguous range: CONT_PTE_SIZE).

Introduce a new API: clear_flush_young_ptes() to facilitate batched checking
of the young flags and flushing TLB entries, thereby improving performance
during large folio reclamation. And it will be overridden by the architecture
that implements a more efficient batch operation in the following patches.

Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
---
 include/linux/mmu_notifier.h |  9 +++++----
 include/linux/pgtable.h      | 35 +++++++++++++++++++++++++++++++++++
 mm/rmap.c                    | 29 +++++++++++++++++++++++++++--
 3 files changed, 67 insertions(+), 6 deletions(-)

diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h
index d1094c2d5fb6..dbbdcef4abf1 100644
--- a/include/linux/mmu_notifier.h
+++ b/include/linux/mmu_notifier.h
@@ -515,16 +515,17 @@ static inline void mmu_notifier_range_init_owner(
 	range->owner = owner;
 }
 
-#define ptep_clear_flush_young_notify(__vma, __address, __ptep)		\
+#define ptep_clear_flush_young_notify(__vma, __address, __ptep, __nr)	\
 ({									\
 	int __young;							\
 	struct vm_area_struct *___vma = __vma;				\
 	unsigned long ___address = __address;				\
-	__young = ptep_clear_flush_young(___vma, ___address, __ptep);	\
+	unsigned int ___nr = __nr;					\
+	__young = clear_flush_young_ptes(___vma, ___address, __ptep, ___nr);	\
 	__young |= mmu_notifier_clear_flush_young(___vma->vm_mm,	\
 						  ___address,		\
 						  ___address +		\
-							PAGE_SIZE);	\
+						  ___nr * PAGE_SIZE);	\
 	__young;							\
 })
 
@@ -650,7 +651,7 @@ static inline void mmu_notifier_subscriptions_destroy(struct mm_struct *mm)
 
 #define mmu_notifier_range_update_to_read_only(r) false
 
-#define ptep_clear_flush_young_notify ptep_clear_flush_young
+#define ptep_clear_flush_young_notify clear_flush_young_ptes
 #define pmdp_clear_flush_young_notify pmdp_clear_flush_young
 #define ptep_clear_young_notify ptep_test_and_clear_young
 #define pmdp_clear_young_notify pmdp_test_and_clear_young
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index 2f0dd3a4ace1..fcf7a7820061 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -1087,6 +1087,41 @@ static inline void wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
 }
 #endif
 
+#ifndef clear_flush_young_ptes
+/**
+ * clear_flush_young_ptes - Clear the access bit and perform a TLB flush for PTEs
+ *			    that map consecutive pages of the same folio.
+ * @vma: The virtual memory area the pages are mapped into.
+ * @addr: Address the first page is mapped at.
+ * @ptep: Page table pointer for the first entry.
+ * @nr: Number of entries to clear access bit.
+ *
+ * May be overridden by the architecture; otherwise, implemented as a simple
+ * loop over ptep_clear_flush_young().
+ *
+ * Note that PTE bits in the PTE range besides the PFN can differ. For example,
+ * some PTEs might be write-protected.
+ *
+ * Context: The caller holds the page table lock.  The PTEs map consecutive
+ * pages that belong to the same folio.  The PTEs are all in the same PMD.
+ */
+static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
+					 unsigned long addr, pte_t *ptep,
+					 unsigned int nr)
+{
+	int young;
+
+	young = ptep_clear_flush_young(vma, addr, ptep);
+	while (--nr) {
+		ptep++;
+		addr += PAGE_SIZE;
+		young |= ptep_clear_flush_young(vma, addr, ptep);
+	}
+
+	return young;
+}
+#endif
+
 /*
  * On some architectures hardware does not set page access bit when accessing
  * memory page, it is responsibility of software setting this bit. It brings
diff --git a/mm/rmap.c b/mm/rmap.c
index d6799afe1114..a0fc05f5966f 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -827,9 +827,11 @@ static bool folio_referenced_one(struct folio *folio,
 	struct folio_referenced_arg *pra = arg;
 	DEFINE_FOLIO_VMA_WALK(pvmw, folio, vma, address, 0);
 	int ptes = 0, referenced = 0;
+	unsigned int nr;
 
 	while (page_vma_mapped_walk(&pvmw)) {
 		address = pvmw.address;
+		nr = 1;
 
 		if (vma->vm_flags & VM_LOCKED) {
 			ptes++;
@@ -874,9 +876,24 @@ static bool folio_referenced_one(struct folio *folio,
 			if (lru_gen_look_around(&pvmw))
 				referenced++;
 		} else if (pvmw.pte) {
+			if (folio_test_large(folio)) {
+				unsigned long end_addr =
+					pmd_addr_end(address, vma->vm_end);
+				unsigned int max_nr =
+					(end_addr - address) >> PAGE_SHIFT;
+				pte_t pteval = ptep_get(pvmw.pte);
+
+				nr = folio_pte_batch(folio, pvmw.pte,
+						     pteval, max_nr);
+			}
+
+			ptes += nr;
 			if (ptep_clear_flush_young_notify(vma, address,
-						pvmw.pte))
+						pvmw.pte, nr))
 				referenced++;
+			/* Skip the batched PTEs */
+			pvmw.pte += nr - 1;
+			pvmw.address += (nr - 1) * PAGE_SIZE;
 		} else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) {
 			if (pmdp_clear_flush_young_notify(vma, address,
 						pvmw.pmd))
@@ -886,7 +903,15 @@ static bool folio_referenced_one(struct folio *folio,
 			WARN_ON_ONCE(1);
 		}
 
-		pra->mapcount--;
+		pra->mapcount -= nr;
+		/*
+		 * If we are sure that we batched the entire folio,
+		 * we can just optimize and stop right here.
+		 */
+		if (ptes == pvmw.nr_pages) {
+			page_vma_mapped_walk_done(&pvmw);
+			break;
+		}
 	}
 
 	if (referenced)
-- 
2.47.3



From baolin.wang at linux.alibaba.com  Mon Dec 22 21:48:34 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Tue, 23 Dec 2025 13:48:34 +0800
Subject: [PATCH v4 0/5] support batch checking of references and unmapping for large folios
Message-ID: <cover.1766455377.git.baolin.wang@linux.alibaba.com>

Currently, folio_referenced_one() always checks the young flag for each PTE
sequentially, which is inefficient for large folios. This inefficiency is
especially noticeable when reclaiming clean file-backed large folios, where
folio_referenced() is observed as a significant performance hotspot.

Moreover, on Arm architecture, which supports contiguous PTEs, there is already
an optimization to clear the young flags for PTEs within a contiguous range.
However, this is not sufficient. We can extend this to perform batched operations
for the entire large folio (which might exceed the contiguous range: CONT_PTE_SIZE).

Similar to folio_referenced_one(), we can also apply batched unmapping for large
file folios to optimize the performance of file folio reclamation. By supporting
batched checking of the young flags, flushing TLB entries, and unmapping, I can
observed a significant performance improvements in my performance tests for file
folios reclamation. Please check the performance data in the commit message of
each patch.

Run stress-ng and mm selftests, no issues were found.

Patch 1: Add a new generic batched PTE helper that supports batched checks of
the references for large folios.
Patch 2 - 3: Preparation patches.
patch 4: Implement the Arm64 arch-specific clear_flush_young_ptes().
Patch 5: Support batched unmapping for file large folios.

Changes from v3:
 - Fix using an incorrect parameter in ptep_clear_flush_young_notify()
   (per Liam).

Changes from v2:
 - Rearrange the patch set (per Ryan).
 - Add pte_cont() check in clear_flush_young_ptes() (per Ryan).
 - Add a helper to do contpte block alignment (per Ryan).
 - Fix some coding style issues (per Lorenzo and Ryan).
 - Add more comments and update the commit message (per Lorenzo and Ryan).
 - Add acked tag from Barry. Thanks. 

Changes from v1:
 - Add a new patch to support batched unmapping for file large folios.
 - Update the cover letter

Baolin Wang (5):
  mm: rmap: support batched checks of the references for large folios
  arm64: mm: factor out the address and ptep alignment into a new helper
  arm64: mm: support batch clearing of the young flag for large folios
  arm64: mm: implement the architecture-specific
    clear_flush_young_ptes()
  mm: rmap: support batched unmapping for file large folios

 arch/arm64/include/asm/pgtable.h | 23 ++++++++----
 arch/arm64/mm/contpte.c          | 62 ++++++++++++++++++++------------
 include/linux/mmu_notifier.h     |  9 ++---
 include/linux/pgtable.h          | 35 ++++++++++++++++++
 mm/rmap.c                        | 36 ++++++++++++++++---
 5 files changed, 128 insertions(+), 37 deletions(-)

-- 
2.47.3



From ming.qian at oss.nxp.com  Mon Dec 22 22:27:52 2025
From: ming.qian at oss.nxp.com (ming.qian at oss.nxp.com)
Date: Tue, 23 Dec 2025 14:27:52 +0800
Subject: [PATCH] media: amphion: Drop min_queued_buffers assignment
Message-ID: <20251223062754.836-1-ming.qian@oss.nxp.com>

From: Ming Qian <ming.qian at oss.nxp.com>

The min_queued_buffers field controls when start_streaming() is called
by the vb2 core (it delays the callback until at least N buffers are
queued). Setting it to 1 affects the timing of start_streaming(), which
breaks the seek flow in decoder scenarios and causes test failures.

The current driver implementation does not rely on this minimum buffer
requirement and handles streaming start correctly with the default
value of 0, so remove these assignments.

Fixes: 3cd084519c6f ("media: amphion: add vpu v4l2 m2m support")
Signed-off-by: Ming Qian <ming.qian at oss.nxp.com>
---
 drivers/media/platform/amphion/vpu_v4l2.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c
index 47dff9a35bb4..1fb887b9098c 100644
--- a/drivers/media/platform/amphion/vpu_v4l2.c
+++ b/drivers/media/platform/amphion/vpu_v4l2.c
@@ -670,7 +670,6 @@ static int vpu_m2m_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_q
 		src_vq->mem_ops = &vb2_vmalloc_memops;
 	src_vq->drv_priv = inst;
 	src_vq->buf_struct_size = sizeof(struct vpu_vb2_buffer);
-	src_vq->min_queued_buffers = 1;
 	src_vq->dev = inst->vpu->dev;
 	src_vq->lock = &inst->lock;
 	ret = vb2_queue_init(src_vq);
@@ -687,7 +686,6 @@ static int vpu_m2m_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_q
 		dst_vq->mem_ops = &vb2_vmalloc_memops;
 	dst_vq->drv_priv = inst;
 	dst_vq->buf_struct_size = sizeof(struct vpu_vb2_buffer);
-	dst_vq->min_queued_buffers = 1;
 	dst_vq->dev = inst->vpu->dev;
 	dst_vq->lock = &inst->lock;
 	ret = vb2_queue_init(dst_vq);
-- 
2.52.0



From Liankun.Yang at mediatek.com  Mon Dec 22 22:34:33 2025
From: Liankun.Yang at mediatek.com (=?utf-8?B?TElBTktVTiBZQU5HICjmnajov57lnaQp?=)
Date: Tue, 23 Dec 2025 06:34:33 +0000
Subject: [PATCH v7 2/2] drm/mediatek: Add isolation to edp
In-Reply-To: <e9f167c88c29fa30ef3a22995c2955cde478b41d.camel@mediatek.com>
References: <20251104085957.1175-1-liankun.yang@mediatek.com>
	 <20251104085957.1175-3-liankun.yang@mediatek.com>
	 <e9f167c88c29fa30ef3a22995c2955cde478b41d.camel@mediatek.com>
Message-ID: <d26f894c12ae21a64dcf5926ebf0fc1cffbb39d5.camel@mediatek.com>

On Wed, 2025-12-17 at 10:08 +0000, CK Hu (???) wrote:
> On Tue, 2025-11-04 at 16:55 +0800, Liankun Yang wrote:
> > Because edp doesn't expect any (un)plug events during runtime and
> > its process differs from DP. Therefore, it is necessary to isolate
> > the parsing capability, panel power, training state and enable
> > state.
> > 
> > And DP related behaviors are adjusted to execute in the second half
> > of the interrupt.
> > For DP details, see drm/mediatek: Adjust bandwidth limit for DP
> > 
> > Signed-off-by: Liankun Yang <liankun.yang at mediatek.com>
> > ---
> >  drivers/gpu/drm/mediatek/mtk_dp.c | 37 +++++++++++++++----------
> > ------
> >  1 file changed, 18 insertions(+), 19 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c
> > b/drivers/gpu/drm/mediatek/mtk_dp.c
> > index 0ba2c208811c..efd4c45985ca 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_dp.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
> > @@ -2187,7 +2187,8 @@ static const struct drm_edid
> > *mtk_dp_edid_read(struct drm_bridge *bridge,
> >  	 * Parse capability here to let atomic_get_input_bus_fmts and
> >  	 * mode_valid use the capability to calculate sink bitrates.
> >  	 */
> > -	if (mtk_dp_parse_capabilities(mtk_dp)) {
> > +	if (mtk_dp->bridge.type == DRM_MODE_CONNECTOR_eDP &&
> > +	    mtk_dp_parse_capabilities(mtk_dp)) {
> 
> This is not related to dp training.
> If dp does not need to parse edid, describe WHY and do not mix edid
> modification with dp training modification.
> 

`mtk_dp_parse_capabilities` is related to DP training, it is
used in `mtk_dp_hpd_event_thread` before DP training, and then only
used by eDP when read edid.

Read edid continued according to its original logic and was unaffected.
	...
	drm_edid = drm_edid_read_ddc(connector, &mtk_dp->aux.ddc);

	/*
	 * Parse capability here to let atomic_get_input_bus_fmts and
	 * mode_valid use the capability to calculate sink bitrates.
	 */
	if (mtk_dp_parse_capabilities(mtk_dp)) {
		drm_err(mtk_dp->drm_dev, "Can't parse capabilities\n");
		drm_edid_free(drm_edid);
		drm_edid = NULL;
	}

	if (drm_edid) {
	...

> >  		drm_err(mtk_dp->drm_dev, "Can't parse capabilities\n");
> >  		drm_edid_free(drm_edid);
> >  		drm_edid = NULL;
> > @@ -2385,13 +2386,15 @@ static void
> > mtk_dp_bridge_atomic_enable(struct drm_bridge *bridge,
> >  		return;
> >  	}
> >  
> > -	mtk_dp_aux_panel_poweron(mtk_dp, true);
> > +	if (mtk_dp->data->bridge_type == DRM_MODE_CONNECTOR_eDP) {
> > +		mtk_dp_aux_panel_poweron(mtk_dp, true);
> >  
> > -	/* Training */
> > -	ret = mtk_dp_training(mtk_dp);
> > -	if (ret) {
> > -		drm_err(mtk_dp->drm_dev, "Training failed, %d\n", ret);
> > -		goto power_off_aux;
> > +		/* Training */
> > +		ret = mtk_dp_training(mtk_dp);
> > +		if (ret) {
> > +			drm_err(mtk_dp->drm_dev, "Training failed,
> > %d\n", ret);
> > +			goto power_off_aux;
> > +		}
> 
> Merge this to previous patch.
> 
> >  	}
> >  
> >  	ret = mtk_dp_video_config(mtk_dp);
> > @@ -2411,7 +2414,9 @@ static void
> > mtk_dp_bridge_atomic_enable(struct drm_bridge *bridge,
> >  		       sizeof(mtk_dp->info.audio_cur_cfg));
> >  	}
> >  
> > -	mtk_dp->enabled = true;
> > +	if (mtk_dp->data->bridge_type == DRM_MODE_CONNECTOR_eDP)
> > +		mtk_dp->enabled = true;
> 
> Merge this to previous patch.
> 
> > +
> >  	mtk_dp_update_plugged_status(mtk_dp);
> >  
> >  	return;
> > @@ -2426,21 +2431,15 @@ static void
> > mtk_dp_bridge_atomic_disable(struct drm_bridge *bridge,
> >  {
> >  	struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
> >  
> > -	mtk_dp->enabled = false;
> > +	if (mtk_dp->data->bridge_type == DRM_MODE_CONNECTOR_eDP) {
> > +		mtk_dp->enabled = false;
> 
> Merge this to previous patch.
> 
> > +		mtk_dp_aux_panel_poweron(mtk_dp, false);
> 
> You change the code flow of DRM_MODE_CONNECTOR_eDP.
> I think you should not change this.
> 
> > +	}
> > +
> >  	mtk_dp_update_plugged_status(mtk_dp);
> >  	mtk_dp_video_enable(mtk_dp, false);
> >  	mtk_dp_audio_mute(mtk_dp, true);
> >  
> > -	if (mtk_dp->train_info.cable_plugged_in) {
> > -		drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER,
> > DP_SET_POWER_D3);
> > -		usleep_range(2000, 3000);
> 
> For DRM_MODE_CONNECTOR_DP, you remove this usleep. This may cause
> side effect.
> Doesn't it?
> 

The modification to `mtk_dp_bridge_atomic_disable` here is base on
the same logic as `mtk_dp_aux_panel_poweron(mtk_dp, false);`.

Modify part of in `mtk_dp_bridge_atomic_disable`
  if (mtk_dp->train_info.cable_plugged_in) {
    drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D3);
    usleep_range(2000, 3000);
  }

  /* power off aux */
  mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
		DP_PWR_STATE_BANDGAP_TPLL,
		DP_PWR_STATE_MASK);

Modify part of in `mtk_dp_aux_panel_poweron(mtk_dp, false);`
  if (pwron) {
    ....
  } else {
    /* power off panel */
    drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D3);
    usleep_range(2000, 3000);

    /* power off aux */
    mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
			DP_PWR_STATE_BANDGAP_TPLL,
			DP_PWR_STATE_MASK);
  }

The `mtk_dp_aux_panel_poweron` function fails to align.
Within the `mtk_dp_hpd_event_thread`, if DP is disconnected,
the `mtk_dp_aux_panel_poweron` function will write from `aux`
to `DPRX`, causing a failure and thus preventing symmetry.

> > -	}
> > -
> > -	/* power off aux */
> > -	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
> > -			   DP_PWR_STATE_BANDGAP_TPLL,
> > -			   DP_PWR_STATE_MASK);
> 
> if (mtk_dp->data->bridge_type == DRM_MODE_CONNECTOR_eDP) {
> 	/* power off aux */
> 	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
> 			   DP_PWR_STATE_BANDGAP_TPLL,
> 			   DP_PWR_STATE_MASK);
> }
> 
> Regards,
> CK
> 
> > -
> >  	/* SDP path reset sw*/
> >  	mtk_dp_sdp_path_reset(mtk_dp);
> >  
> 
> 

From liankun.yang at mediatek.com  Mon Dec 22 22:16:52 2025
From: liankun.yang at mediatek.com (Liankun Yang)
Date: Tue, 23 Dec 2025 14:16:52 +0800
Subject: [PATCH v8 1/1] drm/mediatek: Move DP training to hotplug thread
Message-ID: <20251223061755.7717-1-liankun.yang@mediatek.com>

By adjusting the order of link training and relocating it to HPD,
link training can identify the usability of each lane in the current link.

It also supports handling signal instability and weakness due to
environmental issues, enabling the acquisition of a stable bandwidth
for the current link. Subsequently, DP work can proceed based on
the actual maximum bandwidth.

It should training in the hpd event thread.
Check the mode with lane count and link rate of training.

If we're eDP and capabilities were already parsed we can skip
reading again because eDP panels aren't hotpluggable hence the
caps and training information won't ever change in a boot life

Therefore, bridge typec judgment is required for edp training in
atomic_enable function.

`mtk_dp_parse_capabilities` is related to DP training, it is
used in `mtk_dp_hpd_event_thread` before DP training, and then only
used by eDP when read edid.

-Modify part of in `mtk_dp_bridge_atomic_disable`
    if (mtk_dp->train_info.cable_plugged_in) {
       drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D3);
       usleep_range(2000, 3000);
    }

    /* power off aux */
    mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
		DP_PWR_STATE_BANDGAP_TPLL,
		DP_PWR_STATE_MASK);

-Modify part of in `mtk_dp_aux_panel_poweron(mtk_dp, false);`
    if (pwron) {
       ....
    } else {
       /* power off panel */
       drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D3);
       usleep_range(2000, 3000);

       /* power off aux */
       mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
			DP_PWR_STATE_BANDGAP_TPLL,
			DP_PWR_STATE_MASK);
    }

The `mtk_dp_aux_panel_poweron` function fails to align.
Within the `mtk_dp_hpd_event_thread`, if DP is disconnected,
the `mtk_dp_aux_panel_poweron` function will write from `aux`
to `DPRX`, causing a failure and thus preventing symmetry.

This shows the current timings after the DP cable is plugged in,
as well as the modified timings.

current timings:		Fix timings:

mtk_dp_hpd_event_thread()	mtk_dp_hpd_event_thread()
				(including DP link training)
	|				|
       ...			       ...
mtk_dp_bridge_mode_valid()	mtk_dp_bridge_mode_valid()
	|
       ...			       ...
mtk_dp_bridge_atomic_check()	mtk_dp_bridge_atomic_check()
	|
       ...			       ...
mtk_dp_bridge_atomic_enable()	mtk_dp_bridge_atomic_enable()
(including DP link training)

PS:
1. "..." represents ommited steps;

2. `mtk_dp_bridge_mode_valid()` calculates the bandwidth using the
current lane count and link rate, and then filters each mode to
determine if it supports returning a status.

3. In the `drm_display_mode_to_videomode(&crtc_state->adjusted_mode,
&mtk_dp->info.vm);` function, within the `mtk_dp_bridge_atomic_check()`
function, `adjusted_mode` sets the currently selected display mode for
the DRM.

4. DP link training tests the signal conditions of the link between
DPTX and DPRX, and selects the lane count and link rate that meet
the signal conditions.

5. For example, the platform support DP 4lane 5.4G,
but panel A support DP 2lane 5.4G.

   This is a time sequence:

   a).Plug in panel A. According to the platform, it can output 4K60Hz.
   b).Timing mode set 4K 60Hz(Including in mtk_dp_bridge_atomic_check
   function).
   c).Atomic enable(Based on panel A ability, training pass 2lane
   5.4G).
   d).Finally, due to 2lane 5.4G bandwidth limitation, the platform
   cannot output 4K 60Hz, resulting in a black sreen.

   If apply this patch.

   a).Plug in panel A.
   b).Training pass 2lane 5.4G
   c).Timing mode set 2K 60Hz(Based on the 2lane 5.4G bandwidth limit
   and including in mtk_dp_bridge_atomic_che

Signed-off-by: Liankun Yang <liankun.yang at mediatek.com>
---
Change in V8:
- Update the commit message.
- Update the commit title.
Per suggestion from the previous thread:
https://patchwork.kernel.org/project/linux-mediatek/patch/20251104085957.1175-2-liankun.yang at mediatek.com/

Change in V7:
- Separate the edp part.
Per suggestion from the previous thread:
https://patchwork.kernel.org/project/linux-mediatek/patch/20250822120506.15486-1-liankun.yang at mediatek.com/

Change in V6:
- Fixed power on in atomic enable.
Per suggestion from the previous thread:
https://patchwork.kernel.org/project/linux-mediatek/patch/20250630080824.7107-1-liankun.yang at mediatek.com/

Change in V5:
- Fixed the issue that the 4th version of the patch caused DP to have no screen.
Per suggestion from the previous thread:
https://patchwork.kernel.org/project/linux-mediatek/patch/20250625095446.31726-1-liankun.yang at mediatek.com/

Change in V4:
- Tested the internal eDP display on MT8195 Tomato and it is fine.
Per suggestion from the previous thread:
https://patchwork.kernel.org/project/linux-mediatek/patch/20250318140236.13650-2-liankun.yang at mediatek.com/

Change in V3:
- Remove 'mtk_dp->enabled = false" in atomic disable.
- Remove 'mtk_dp->enabled = true" in atomic enable.
Per suggestion from the previous thread:
https://patchwork.kernel.org/project/linux-mediatek/patch/20241025083036.8829-4-liankun.yang at mediatek.com/

Change in V2:
- Adjust DP training timing.
- Adjust parse capabilities timing.
- Add power on/off for connect/disconnect.
Per suggestion from the previous thread:
https://patchwork.kernel.org/project/linux-mediatek/patch/20240315015233.2023-1-liankun.yang at mediatek.com/
---
 drivers/gpu/drm/mediatek/mtk_dp.c | 57 ++++++++++++++++++++-----------
 1 file changed, 38 insertions(+), 19 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index b0b1e158600f..5e67dab6e2e9 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -1976,6 +1976,7 @@ static irqreturn_t mtk_dp_hpd_event_thread(int hpd, void *dev)
 	struct mtk_dp *mtk_dp = dev;
 	unsigned long flags;
 	u32 status;
+	int ret;
 
 	if (mtk_dp->need_debounce && mtk_dp->train_info.cable_plugged_in)
 		msleep(100);
@@ -1994,9 +1995,28 @@ static irqreturn_t mtk_dp_hpd_event_thread(int hpd, void *dev)
 			memset(&mtk_dp->info.audio_cur_cfg, 0,
 			       sizeof(mtk_dp->info.audio_cur_cfg));
 
+			mtk_dp->enabled = false;
+			/* power off aux */
+			mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
+					   DP_PWR_STATE_BANDGAP_TPLL,
+					   DP_PWR_STATE_MASK);
+
 			mtk_dp->need_debounce = false;
 			mod_timer(&mtk_dp->debounce_timer,
 				  jiffies + msecs_to_jiffies(100) - 1);
+		} else {
+			mtk_dp_aux_panel_poweron(mtk_dp, true);
+
+			ret = mtk_dp_parse_capabilities(mtk_dp);
+			if (ret)
+				drm_err(mtk_dp->drm_dev, "Can't parse capabilities\n");
+
+			/* Training */
+			ret = mtk_dp_training(mtk_dp);
+			if (ret)
+				drm_err(mtk_dp->drm_dev, "Training failed, %d\n", ret);
+
+			mtk_dp->enabled = true;
 		}
 	}
 
@@ -2168,7 +2188,8 @@ static const struct drm_edid *mtk_dp_edid_read(struct drm_bridge *bridge,
 	 * Parse capability here to let atomic_get_input_bus_fmts and
 	 * mode_valid use the capability to calculate sink bitrates.
 	 */
-	if (mtk_dp_parse_capabilities(mtk_dp)) {
+	if (mtk_dp->bridge.type == DRM_MODE_CONNECTOR_eDP &&
+	    mtk_dp_parse_capabilities(mtk_dp)) {
 		drm_err(mtk_dp->drm_dev, "Can't parse capabilities\n");
 		drm_edid_free(drm_edid);
 		drm_edid = NULL;
@@ -2366,13 +2387,15 @@ static void mtk_dp_bridge_atomic_enable(struct drm_bridge *bridge,
 		return;
 	}
 
-	mtk_dp_aux_panel_poweron(mtk_dp, true);
+	if (mtk_dp->data->bridge_type == DRM_MODE_CONNECTOR_eDP) {
+		mtk_dp_aux_panel_poweron(mtk_dp, true);
 
-	/* Training */
-	ret = mtk_dp_training(mtk_dp);
-	if (ret) {
-		drm_err(mtk_dp->drm_dev, "Training failed, %d\n", ret);
-		goto power_off_aux;
+		/* Training */
+		ret = mtk_dp_training(mtk_dp);
+		if (ret) {
+			drm_err(mtk_dp->drm_dev, "Training failed, %d\n", ret);
+			goto power_off_aux;
+		}
 	}
 
 	ret = mtk_dp_video_config(mtk_dp);
@@ -2392,7 +2415,9 @@ static void mtk_dp_bridge_atomic_enable(struct drm_bridge *bridge,
 		       sizeof(mtk_dp->info.audio_cur_cfg));
 	}
 
-	mtk_dp->enabled = true;
+	if (mtk_dp->data->bridge_type == DRM_MODE_CONNECTOR_eDP)
+		mtk_dp->enabled = true;
+
 	mtk_dp_update_plugged_status(mtk_dp);
 
 	return;
@@ -2407,21 +2432,15 @@ static void mtk_dp_bridge_atomic_disable(struct drm_bridge *bridge,
 {
 	struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
 
-	mtk_dp->enabled = false;
+	if (mtk_dp->data->bridge_type == DRM_MODE_CONNECTOR_eDP) {
+		mtk_dp->enabled = false;
+		mtk_dp_aux_panel_poweron(mtk_dp, false);
+	}
+
 	mtk_dp_update_plugged_status(mtk_dp);
 	mtk_dp_video_enable(mtk_dp, false);
 	mtk_dp_audio_mute(mtk_dp, true);
 
-	if (mtk_dp->train_info.cable_plugged_in) {
-		drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D3);
-		usleep_range(2000, 3000);
-	}
-
-	/* power off aux */
-	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
-			   DP_PWR_STATE_BANDGAP_TPLL,
-			   DP_PWR_STATE_MASK);
-
 	/* SDP path reset sw*/
 	mtk_dp_sdp_path_reset(mtk_dp);
 
-- 
2.45.2



From thomas.weissschuh at linutronix.de  Mon Dec 22 22:59:12 2025
From: thomas.weissschuh at linutronix.de (=?utf-8?q?Thomas_Wei=C3=9Fschuh?=)
Date: Tue, 23 Dec 2025 07:59:12 +0100
Subject: [PATCH 1/9] vdso: Add prototype for __vdso_clock_getres_time64()
In-Reply-To: <20251223-vdso-compat-time32-v1-0-97ea7a06a543@linutronix.de>
References: <20251223-vdso-compat-time32-v1-0-97ea7a06a543@linutronix.de>
Message-ID: <20251223-vdso-compat-time32-v1-1-97ea7a06a543@linutronix.de>

For consistency with __vdso_clock_gettime64() there should also be a
64-bit variant of clock_getres(). This will allow the extension of
CONFIG_COMPAT_32BIT_TIME to the vDSO and finally the removal of 32-bit
time types from the kernel and UAPI. The generic vDSO library already
provides nearly all necessary building blocks for architectures to
provide this function. Only a prototype is missing.

Add the prototype to the generic header so architectures can start
providing this function.

Suggested-by: Arnd Bergmann <arnd at arndb.de>
Signed-off-by: Thomas Wei?schuh <thomas.weissschuh at linutronix.de>
---
 include/vdso/gettime.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/vdso/gettime.h b/include/vdso/gettime.h
index 9ac161866653..16a0a0556b86 100644
--- a/include/vdso/gettime.h
+++ b/include/vdso/gettime.h
@@ -20,5 +20,6 @@ int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts);
 __kernel_old_time_t __vdso_time(__kernel_old_time_t *t);
 int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz);
 int __vdso_clock_gettime64(clockid_t clock, struct __kernel_timespec *ts);
+int __vdso_clock_getres_time64(clockid_t clock, struct __kernel_timespec *ts);
 
 #endif

-- 
2.52.0



From thomas.weissschuh at linutronix.de  Mon Dec 22 22:59:11 2025
From: thomas.weissschuh at linutronix.de (=?utf-8?q?Thomas_Wei=C3=9Fschuh?=)
Date: Tue, 23 Dec 2025 07:59:11 +0100
Subject: [PATCH 0/9] vDSO: Provide clock_getres_time64() where applicable
Message-ID: <20251223-vdso-compat-time32-v1-0-97ea7a06a543@linutronix.de>

For consistency with __vdso_clock_gettime64() there should also be a
64-bit variant of clock_getres(). This will allow the extension of
CONFIG_COMPAT_32BIT_TIME to the vDSO and finally the removal of 32-bit
time types from the kernel and UAPI.
    

Signed-off-by: Thomas Wei?schuh <thomas.weissschuh at linutronix.de>
---
Thomas Wei?schuh (9):
      vdso: Add prototype for __vdso_clock_getres_time64()
      selftests: vDSO: vdso_config: Add configurations for clock_getres_time64()
      selftests: vDSO: vdso_test_abi: Use UAPI system call numbers
      selftests: vDSO: vdso_test_abi: Add test for clock_getres_time64()
      x86/vdso: Provide clock_getres_time64() for x86-32
      ARM: VDSO: also patch out __vdso_clock_getres() if unavailable
      ARM: VDSO: provide clock_getres_time64()
      arm64: vdso32: Provide clock_getres_time64()
      MIPS: vdso: Provide getres_time64() for 32-bit ABIs

 arch/arm/kernel/vdso.c                       |  2 +
 arch/arm/vdso/vdso.lds.S                     |  1 +
 arch/arm/vdso/vgettimeofday.c                |  6 +++
 arch/arm64/kernel/vdso32/vdso.lds.S          |  1 +
 arch/arm64/kernel/vdso32/vgettimeofday.c     |  6 +++
 arch/mips/vdso/vdso.lds.S                    |  1 +
 arch/mips/vdso/vgettimeofday.c               |  6 +++
 arch/x86/entry/vdso/vclock_gettime.c         |  8 ++++
 arch/x86/entry/vdso/vdso32/vdso32.lds.S      |  1 +
 include/vdso/gettime.h                       |  1 +
 tools/testing/selftests/vDSO/vdso_config.h   |  4 +-
 tools/testing/selftests/vDSO/vdso_test_abi.c | 55 +++++++++++++++++++++++++++-
 12 files changed, 89 insertions(+), 3 deletions(-)
---
base-commit: 15a11f3ffb629cbbf6efd272239c04a9eb3180e2
change-id: 20251120-vdso-compat-time32-f4684ff250ba

Best regards,
-- 
Thomas Wei?schuh <thomas.weissschuh at linutronix.de>



From thomas.weissschuh at linutronix.de  Mon Dec 22 22:59:13 2025
From: thomas.weissschuh at linutronix.de (=?utf-8?q?Thomas_Wei=C3=9Fschuh?=)
Date: Tue, 23 Dec 2025 07:59:13 +0100
Subject: [PATCH 2/9] selftests: vDSO: vdso_config: Add configurations for
 clock_getres_time64()
In-Reply-To: <20251223-vdso-compat-time32-v1-0-97ea7a06a543@linutronix.de>
References: <20251223-vdso-compat-time32-v1-0-97ea7a06a543@linutronix.de>
Message-ID: <20251223-vdso-compat-time32-v1-2-97ea7a06a543@linutronix.de>

Some architectures will start to implement this function.
Make sure that tests can be written for it.

Signed-off-by: Thomas Wei?schuh <thomas.weissschuh at linutronix.de>
---
 tools/testing/selftests/vDSO/vdso_config.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/vDSO/vdso_config.h b/tools/testing/selftests/vDSO/vdso_config.h
index 50c261005111..5da223731b81 100644
--- a/tools/testing/selftests/vDSO/vdso_config.h
+++ b/tools/testing/selftests/vDSO/vdso_config.h
@@ -66,7 +66,7 @@ static const char *versions[7] = {
 };
 
 __attribute__((unused))
-static const char *names[2][7] = {
+static const char *names[2][8] = {
 	{
 		"__kernel_gettimeofday",
 		"__kernel_clock_gettime",
@@ -75,6 +75,7 @@ static const char *names[2][7] = {
 		"__kernel_getcpu",
 		"__kernel_clock_gettime64",
 		"__kernel_getrandom",
+		"__kernel_clock_getres_time64",
 	},
 	{
 		"__vdso_gettimeofday",
@@ -84,6 +85,7 @@ static const char *names[2][7] = {
 		"__vdso_getcpu",
 		"__vdso_clock_gettime64",
 		"__vdso_getrandom",
+		"__vdso_clock_getres_time64",
 	},
 };
 

-- 
2.52.0



From thomas.weissschuh at linutronix.de  Mon Dec 22 22:59:14 2025
From: thomas.weissschuh at linutronix.de (=?utf-8?q?Thomas_Wei=C3=9Fschuh?=)
Date: Tue, 23 Dec 2025 07:59:14 +0100
Subject: [PATCH 3/9] selftests: vDSO: vdso_test_abi: Use UAPI system call
 numbers
In-Reply-To: <20251223-vdso-compat-time32-v1-0-97ea7a06a543@linutronix.de>
References: <20251223-vdso-compat-time32-v1-0-97ea7a06a543@linutronix.de>
Message-ID: <20251223-vdso-compat-time32-v1-3-97ea7a06a543@linutronix.de>

SYS_clock_getres might have been redirected by libc to some other system
call than the actual clock_getres. In the test we want to make sure to
use exactly this system call.

Use the system call number exported by the UAPI headers which is always
correct.

Signed-off-by: Thomas Wei?schuh <thomas.weissschuh at linutronix.de>
---
 tools/testing/selftests/vDSO/vdso_test_abi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/testing/selftests/vDSO/vdso_test_abi.c b/tools/testing/selftests/vDSO/vdso_test_abi.c
index c620317eaeea..a75c12dcb0f1 100644
--- a/tools/testing/selftests/vDSO/vdso_test_abi.c
+++ b/tools/testing/selftests/vDSO/vdso_test_abi.c
@@ -179,7 +179,7 @@ static void vdso_test_clock_getres(clockid_t clk_id)
 		clock_getres_fail++;
 	}
 
-	ret = syscall(SYS_clock_getres, clk_id, &sys_ts);
+	ret = syscall(__NR_clock_getres, clk_id, &sys_ts);
 
 	ksft_print_msg("The syscall resolution is %lld %lld\n",
 			(long long)sys_ts.tv_sec, (long long)sys_ts.tv_nsec);

-- 
2.52.0



From thomas.weissschuh at linutronix.de  Mon Dec 22 22:59:15 2025
From: thomas.weissschuh at linutronix.de (=?utf-8?q?Thomas_Wei=C3=9Fschuh?=)
Date: Tue, 23 Dec 2025 07:59:15 +0100
Subject: [PATCH 4/9] selftests: vDSO: vdso_test_abi: Add test for
 clock_getres_time64()
In-Reply-To: <20251223-vdso-compat-time32-v1-0-97ea7a06a543@linutronix.de>
References: <20251223-vdso-compat-time32-v1-0-97ea7a06a543@linutronix.de>
Message-ID: <20251223-vdso-compat-time32-v1-4-97ea7a06a543@linutronix.de>

Some architectures will start to implement this function.
Make sure it works correctly.

Signed-off-by: Thomas Wei?schuh <thomas.weissschuh at linutronix.de>
---
 tools/testing/selftests/vDSO/vdso_test_abi.c | 53 +++++++++++++++++++++++++++-
 1 file changed, 52 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/vDSO/vdso_test_abi.c b/tools/testing/selftests/vDSO/vdso_test_abi.c
index a75c12dcb0f1..b162a4ba9c4f 100644
--- a/tools/testing/selftests/vDSO/vdso_test_abi.c
+++ b/tools/testing/selftests/vDSO/vdso_test_abi.c
@@ -36,6 +36,7 @@ typedef long (*vdso_gettimeofday_t)(struct timeval *tv, struct timezone *tz);
 typedef long (*vdso_clock_gettime_t)(clockid_t clk_id, struct timespec *ts);
 typedef long (*vdso_clock_gettime64_t)(clockid_t clk_id, struct vdso_timespec64 *ts);
 typedef long (*vdso_clock_getres_t)(clockid_t clk_id, struct timespec *ts);
+typedef long (*vdso_clock_getres_time64_t)(clockid_t clk_id, struct vdso_timespec64 *ts);
 typedef time_t (*vdso_time_t)(time_t *t);
 
 static const char * const vdso_clock_name[] = {
@@ -196,6 +197,55 @@ static void vdso_test_clock_getres(clockid_t clk_id)
 	}
 }
 
+#ifdef __NR_clock_getres_time64
+static void vdso_test_clock_getres_time64(clockid_t clk_id)
+{
+	int clock_getres_fail = 0;
+
+	/* Find clock_getres. */
+	vdso_clock_getres_time64_t vdso_clock_getres_time64 =
+		(vdso_clock_getres_time64_t)vdso_sym(version, name[7]);
+
+	if (!vdso_clock_getres_time64) {
+		ksft_print_msg("Couldn't find %s\n", name[7]);
+		ksft_test_result_skip("%s %s\n", name[7],
+				      vdso_clock_name[clk_id]);
+		return;
+	}
+
+	struct vdso_timespec64 ts, sys_ts;
+	long ret = VDSO_CALL(vdso_clock_getres_time64, 2, clk_id, &ts);
+
+	if (ret == 0) {
+		ksft_print_msg("The vdso resolution is %lld %lld\n",
+			       (long long)ts.tv_sec, (long long)ts.tv_nsec);
+	} else {
+		clock_getres_fail++;
+	}
+
+	ret = syscall(__NR_clock_getres_time64, clk_id, &sys_ts);
+
+	ksft_print_msg("The syscall resolution is %lld %lld\n",
+			(long long)sys_ts.tv_sec, (long long)sys_ts.tv_nsec);
+
+	if ((sys_ts.tv_sec != ts.tv_sec) || (sys_ts.tv_nsec != ts.tv_nsec))
+		clock_getres_fail++;
+
+	if (clock_getres_fail > 0) {
+		ksft_test_result_fail("%s %s\n", name[7],
+				      vdso_clock_name[clk_id]);
+	} else {
+		ksft_test_result_pass("%s %s\n", name[7],
+				      vdso_clock_name[clk_id]);
+	}
+}
+#else /* !__NR_clock_getres_time64 */
+static void vdso_test_clock_getres_time64(clockid_t clk_id)
+{
+	ksft_test_result_skip("%s %s\n", name[7], vdso_clock_name[clk_id]);
+}
+#endif /* __NR_clock_getres_time64 */
+
 /*
  * This function calls vdso_test_clock_gettime and vdso_test_clock_getres
  * with different values for clock_id.
@@ -208,9 +258,10 @@ static inline void vdso_test_clock(clockid_t clock_id)
 	vdso_test_clock_gettime64(clock_id);
 
 	vdso_test_clock_getres(clock_id);
+	vdso_test_clock_getres_time64(clock_id);
 }
 
-#define VDSO_TEST_PLAN	29
+#define VDSO_TEST_PLAN	38
 
 int main(int argc, char **argv)
 {

-- 
2.52.0



From thomas.weissschuh at linutronix.de  Mon Dec 22 22:59:16 2025
From: thomas.weissschuh at linutronix.de (=?utf-8?q?Thomas_Wei=C3=9Fschuh?=)
Date: Tue, 23 Dec 2025 07:59:16 +0100
Subject: [PATCH 5/9] x86/vdso: Provide clock_getres_time64() for x86-32
In-Reply-To: <20251223-vdso-compat-time32-v1-0-97ea7a06a543@linutronix.de>
References: <20251223-vdso-compat-time32-v1-0-97ea7a06a543@linutronix.de>
Message-ID: <20251223-vdso-compat-time32-v1-5-97ea7a06a543@linutronix.de>

For consistency with __vdso_clock_gettime64() there should also be a
64-bit variant of clock_getres(). This will allow the extension of
CONFIG_COMPAT_32BIT_TIME to the vDSO and finally the removal of 32-bit
time types from the kernel and UAPI.

Signed-off-by: Thomas Wei?schuh <thomas.weissschuh at linutronix.de>
---
 arch/x86/entry/vdso/vclock_gettime.c    | 8 ++++++++
 arch/x86/entry/vdso/vdso32/vdso32.lds.S | 1 +
 2 files changed, 9 insertions(+)

diff --git a/arch/x86/entry/vdso/vclock_gettime.c b/arch/x86/entry/vdso/vclock_gettime.c
index 0debc194bd78..027b7e88d753 100644
--- a/arch/x86/entry/vdso/vclock_gettime.c
+++ b/arch/x86/entry/vdso/vclock_gettime.c
@@ -74,4 +74,12 @@ int __vdso_clock_getres(clockid_t clock, struct old_timespec32 *res)
 
 int clock_getres(clockid_t, struct old_timespec32 *)
 	__attribute__((weak, alias("__vdso_clock_getres")));
+
+int __vdso_clock_getres_time64(clockid_t clock, struct __kernel_timespec *ts)
+{
+	return __cvdso_clock_getres(clock, ts);
+}
+
+int clock_getres_time64(clockid_t, struct __kernel_timespec *)
+	__attribute__((weak, alias("__vdso_clock_getres_time64")));
 #endif
diff --git a/arch/x86/entry/vdso/vdso32/vdso32.lds.S b/arch/x86/entry/vdso/vdso32/vdso32.lds.S
index 8a3be07006bb..6f977c103584 100644
--- a/arch/x86/entry/vdso/vdso32/vdso32.lds.S
+++ b/arch/x86/entry/vdso/vdso32/vdso32.lds.S
@@ -28,6 +28,7 @@ VERSION
 		__vdso_time;
 		__vdso_clock_getres;
 		__vdso_clock_gettime64;
+		__vdso_clock_getres_time64;
 		__vdso_getcpu;
 	};
 

-- 
2.52.0



From thomas.weissschuh at linutronix.de  Mon Dec 22 22:59:18 2025
From: thomas.weissschuh at linutronix.de (=?utf-8?q?Thomas_Wei=C3=9Fschuh?=)
Date: Tue, 23 Dec 2025 07:59:18 +0100
Subject: [PATCH 7/9] ARM: VDSO: provide clock_getres_time64()
In-Reply-To: <20251223-vdso-compat-time32-v1-0-97ea7a06a543@linutronix.de>
References: <20251223-vdso-compat-time32-v1-0-97ea7a06a543@linutronix.de>
Message-ID: <20251223-vdso-compat-time32-v1-7-97ea7a06a543@linutronix.de>

For consistency with __vdso_clock_gettime64() there should also be a
64-bit variant of clock_getres(). This will allow the extension of
CONFIG_COMPAT_32BIT_TIME to the vDSO and finally the removal of 32-bit
time types from the kernel and UAPI.

Signed-off-by: Thomas Wei?schuh <thomas.weissschuh at linutronix.de>
---
 arch/arm/kernel/vdso.c        | 1 +
 arch/arm/vdso/vdso.lds.S      | 1 +
 arch/arm/vdso/vgettimeofday.c | 6 ++++++
 3 files changed, 8 insertions(+)

diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c
index 566c40f0f7c7..0108f33d6bed 100644
--- a/arch/arm/kernel/vdso.c
+++ b/arch/arm/kernel/vdso.c
@@ -162,6 +162,7 @@ static void __init patch_vdso(void *ehdr)
 		vdso_nullpatch_one(&einfo, "__vdso_clock_gettime");
 		vdso_nullpatch_one(&einfo, "__vdso_clock_gettime64");
 		vdso_nullpatch_one(&einfo, "__vdso_clock_getres");
+		vdso_nullpatch_one(&einfo, "__vdso_clock_getres_time64");
 	}
 }
 
diff --git a/arch/arm/vdso/vdso.lds.S b/arch/arm/vdso/vdso.lds.S
index 7c08371f4400..74d8d8bc8a40 100644
--- a/arch/arm/vdso/vdso.lds.S
+++ b/arch/arm/vdso/vdso.lds.S
@@ -74,6 +74,7 @@ VERSION
 		__vdso_gettimeofday;
 		__vdso_clock_getres;
 		__vdso_clock_gettime64;
+		__vdso_clock_getres_time64;
 	local: *;
 	};
 }
diff --git a/arch/arm/vdso/vgettimeofday.c b/arch/arm/vdso/vgettimeofday.c
index 3554aa35f1ba..2874dde7e6cf 100644
--- a/arch/arm/vdso/vgettimeofday.c
+++ b/arch/arm/vdso/vgettimeofday.c
@@ -34,6 +34,12 @@ int __vdso_clock_getres(clockid_t clock_id,
 	return __cvdso_clock_getres_time32(clock_id, res);
 }
 
+int __vdso_clock_getres_time64(clockid_t clock_id,
+			       struct __kernel_timespec *res)
+{
+	return __cvdso_clock_getres(clock_id, res);
+}
+
 /* Avoid unresolved references emitted by GCC */
 
 void __aeabi_unwind_cpp_pr0(void)

-- 
2.52.0



From thomas.weissschuh at linutronix.de  Mon Dec 22 22:59:17 2025
From: thomas.weissschuh at linutronix.de (=?utf-8?q?Thomas_Wei=C3=9Fschuh?=)
Date: Tue, 23 Dec 2025 07:59:17 +0100
Subject: [PATCH 6/9] ARM: VDSO: also patch out __vdso_clock_getres() if
 unavailable
In-Reply-To: <20251223-vdso-compat-time32-v1-0-97ea7a06a543@linutronix.de>
References: <20251223-vdso-compat-time32-v1-0-97ea7a06a543@linutronix.de>
Message-ID: <20251223-vdso-compat-time32-v1-6-97ea7a06a543@linutronix.de>

The vDSO code hides symbols which are non-functional.
__vdso_clock_getres() was not added to this list when it got introduced.

Fixes: 052e76a31b4a ("ARM: 8931/1: Add clock_getres entry point")
Signed-off-by: Thomas Wei?schuh <thomas.weissschuh at linutronix.de>
---
 arch/arm/kernel/vdso.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c
index e38a30477f3d..566c40f0f7c7 100644
--- a/arch/arm/kernel/vdso.c
+++ b/arch/arm/kernel/vdso.c
@@ -161,6 +161,7 @@ static void __init patch_vdso(void *ehdr)
 		vdso_nullpatch_one(&einfo, "__vdso_gettimeofday");
 		vdso_nullpatch_one(&einfo, "__vdso_clock_gettime");
 		vdso_nullpatch_one(&einfo, "__vdso_clock_gettime64");
+		vdso_nullpatch_one(&einfo, "__vdso_clock_getres");
 	}
 }
 

-- 
2.52.0



From thomas.weissschuh at linutronix.de  Mon Dec 22 22:59:19 2025
From: thomas.weissschuh at linutronix.de (=?utf-8?q?Thomas_Wei=C3=9Fschuh?=)
Date: Tue, 23 Dec 2025 07:59:19 +0100
Subject: [PATCH 8/9] arm64: vdso32: Provide clock_getres_time64()
In-Reply-To: <20251223-vdso-compat-time32-v1-0-97ea7a06a543@linutronix.de>
References: <20251223-vdso-compat-time32-v1-0-97ea7a06a543@linutronix.de>
Message-ID: <20251223-vdso-compat-time32-v1-8-97ea7a06a543@linutronix.de>

For consistency with __vdso_clock_gettime64() there should also be a
64-bit variant of clock_getres(). This will allow the extension of
CONFIG_COMPAT_32BIT_TIME to the vDSO and finally the removal of 32-bit
time types from the kernel and UAPI.

Signed-off-by: Thomas Wei?schuh <thomas.weissschuh at linutronix.de>
---
 arch/arm64/kernel/vdso32/vdso.lds.S      | 1 +
 arch/arm64/kernel/vdso32/vgettimeofday.c | 6 ++++++
 2 files changed, 7 insertions(+)

diff --git a/arch/arm64/kernel/vdso32/vdso.lds.S b/arch/arm64/kernel/vdso32/vdso.lds.S
index e02b27487ce8..c374fb0146f3 100644
--- a/arch/arm64/kernel/vdso32/vdso.lds.S
+++ b/arch/arm64/kernel/vdso32/vdso.lds.S
@@ -86,6 +86,7 @@ VERSION
 		__vdso_gettimeofday;
 		__vdso_clock_getres;
 		__vdso_clock_gettime64;
+		__vdso_clock_getres_time64;
 	local: *;
 	};
 }
diff --git a/arch/arm64/kernel/vdso32/vgettimeofday.c b/arch/arm64/kernel/vdso32/vgettimeofday.c
index 29b4d8f61e39..d7b39b0a9668 100644
--- a/arch/arm64/kernel/vdso32/vgettimeofday.c
+++ b/arch/arm64/kernel/vdso32/vgettimeofday.c
@@ -32,6 +32,12 @@ int __vdso_clock_getres(clockid_t clock_id,
 	return __cvdso_clock_getres_time32(clock_id, res);
 }
 
+int __vdso_clock_getres_time64(clockid_t clock_id,
+			       struct __kernel_timespec *res)
+{
+	return __cvdso_clock_getres(clock_id, res);
+}
+
 /* Avoid unresolved references emitted by GCC */
 
 void __aeabi_unwind_cpp_pr0(void)

-- 
2.52.0



From thomas.weissschuh at linutronix.de  Mon Dec 22 22:59:20 2025
From: thomas.weissschuh at linutronix.de (=?utf-8?q?Thomas_Wei=C3=9Fschuh?=)
Date: Tue, 23 Dec 2025 07:59:20 +0100
Subject: [PATCH 9/9] MIPS: vdso: Provide getres_time64() for 32-bit ABIs
In-Reply-To: <20251223-vdso-compat-time32-v1-0-97ea7a06a543@linutronix.de>
References: <20251223-vdso-compat-time32-v1-0-97ea7a06a543@linutronix.de>
Message-ID: <20251223-vdso-compat-time32-v1-9-97ea7a06a543@linutronix.de>

For consistency with __vdso_clock_gettime64() there should also be a
64-bit variant of clock_getres(). This will allow the extension of
CONFIG_COMPAT_32BIT_TIME to the vDSO and finally the removal of 32-bit
time types from the kernel and UAPI.

Signed-off-by: Thomas Wei?schuh <thomas.weissschuh at linutronix.de>
---
 arch/mips/vdso/vdso.lds.S      | 1 +
 arch/mips/vdso/vgettimeofday.c | 6 ++++++
 2 files changed, 7 insertions(+)

diff --git a/arch/mips/vdso/vdso.lds.S b/arch/mips/vdso/vdso.lds.S
index c8bbe56d89cb..5d08be3a6b85 100644
--- a/arch/mips/vdso/vdso.lds.S
+++ b/arch/mips/vdso/vdso.lds.S
@@ -103,6 +103,7 @@ VERSION
 		__vdso_clock_getres;
 #if _MIPS_SIM != _MIPS_SIM_ABI64
 		__vdso_clock_gettime64;
+		__vdso_clock_getres_time64;
 #endif
 #endif
 	local: *;
diff --git a/arch/mips/vdso/vgettimeofday.c b/arch/mips/vdso/vgettimeofday.c
index 604afea3f336..59627f2f51b7 100644
--- a/arch/mips/vdso/vgettimeofday.c
+++ b/arch/mips/vdso/vgettimeofday.c
@@ -46,6 +46,12 @@ int __vdso_clock_gettime64(clockid_t clock,
 	return __cvdso_clock_gettime(clock, ts);
 }
 
+int __vdso_clock_getres_time64(clockid_t clock,
+			       struct __kernel_timespec *ts)
+{
+	return __cvdso_clock_getres(clock, ts);
+}
+
 #else
 
 int __vdso_clock_gettime(clockid_t clock,

-- 
2.52.0



From lkp at intel.com  Mon Dec 22 23:02:49 2025
From: lkp at intel.com (kernel test robot)
Date: Tue, 23 Dec 2025 15:02:49 +0800
Subject: [arm-platforms:kvm-arm64/gicv5-full 42/82]
 arch/arm64/kvm/vgic/vgic-v5-tables.c:502:2-7: WARNING: NULL check before some
 freeing functions is not needed.
Message-ID: <202512231452.XlBbTBAN-lkp@intel.com>

tree:   https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git kvm-arm64/gicv5-full
head:   1426b88096b597395df4c82f089b87c62bab45da
commit: a994bc0447523a526e17ae0a62024bf8ef371ce6 [42/82] KVM: arm64: gic-v5: Create, manage, and teardown VMT & VPETs
config: arm64-randconfig-r064-20251223 (https://download.01.org/0day-ci/archive/20251223/202512231452.XlBbTBAN-lkp at intel.com/config)
compiler: aarch64-linux-gcc (GCC) 15.1.0

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512231452.XlBbTBAN-lkp at intel.com/

cocci warnings: (new ones prefixed by >>)
>> arch/arm64/kvm/vgic/vgic-v5-tables.c:502:2-7: WARNING: NULL check before some freeing functions is not needed.
   arch/arm64/kvm/vgic/vgic-v5-tables.c:504:2-7: WARNING: NULL check before some freeing functions is not needed.
   arch/arm64/kvm/vgic/vgic-v5-tables.c:506:2-7: WARNING: NULL check before some freeing functions is not needed.
   arch/arm64/kvm/vgic/vgic-v5-tables.c:508:2-7: WARNING: NULL check before some freeing functions is not needed.
--
>> arch/arm64/kvm/vgic/vgic-v5-tables.c:473:42-48: ERROR: application of sizeof to pointer
--
>> arch/arm64/kvm/vgic/vgic-v5-tables.c:391:5-10: WARNING: Unsigned expression compared with zero: vm_id < 0

vim +502 arch/arm64/kvm/vgic/vgic-v5-tables.c

   357	
   358	/*
   359	 * Initialise an entry in the VMT based on the index of the VM. We
   360	 * make the assumption that our VM ID is zero based, and that we can
   361	 * use it to index into the VMT. We check that the index is in the
   362	 * allowed range, just in case.
   363	 *
   364	 * We allocate:
   365	 *     * The VM Descriptor
   366	 *     * The VPE Table
   367	 *
   368	 * We set:
   369	 *     * The VPE ID Bits
   370	 *
   371	 * Note: We don't mark the VMTE as valid as this needs to be done by
   372	 * the hardware..
   373	 */
   374	int vgic_v5_vmte_init(struct kvm *kvm)
   375	{
   376		struct vmtl2_entry *vmte;
   377		gicv5_vm_info *vmi;
   378		void *vmd = NULL, *vpet = NULL;
   379		void **vped_ptrs = NULL;
   380		size_t vpet_alloc_size;
   381		int ret;
   382		u64 tmp;
   383		u16 vm_id = vgic_v5_vm_id(kvm);
   384	
   385		if (!vgic_v5_vmt_allocated()) {
   386			kvm_err("VMT is not allocated; cannot populate\n");
   387			ret = -EINVAL;
   388			goto out_fail;
   389		}
   390	
 > 391		if (vm_id < 0) {
   392			kvm_err("Failed to find free vm_id\n");
   393			return vm_id;
   394		}
   395	
   396		if (vgic_v5_alloc_l2_vmt(kvm)) {
   397			kvm_err("Failed to make the L2 VMTE valid!\n");
   398			return -EIO;
   399		}
   400	
   401		ret = vgic_v5_get_l2_vmte(vm_id, &vmte);
   402		if (ret) {
   403			kvm_err("Failed to look up VMTE\n");
   404			return ret;
   405		}
   406	
   407		if (FIELD_GET(GICV5_VMTEL2E_VALID, vmte->val[0])) {
   408			kvm_err("Attempt to initialize a valid VMTE (0x%x)!\n", vm_id);
   409			return -EINVAL;
   410		}
   411	
   412		ret = vgic_v5_reset_vmte(vm_id);
   413		if (ret) {
   414			kvm_err("Failed to reset VMTE\n");
   415			return ret;
   416		}
   417	
   418		vmi = kzalloc(sizeof(gicv5_vm_info), GFP_KERNEL);
   419		if (vmi == NULL) {
   420			ret = -ENOMEM;
   421			goto out_fail;
   422		}
   423	
   424		/* Allocate and assign the VM Descriptor, if requested. */
   425		if (vmt_info->vmd_size != 0) {
   426			vmd = kzalloc(vmt_info->vmd_size, GFP_KERNEL);
   427			if (vmd == NULL) {
   428				kvm_err("Failed to allocate memory for VM Descriptor\n");
   429				ret = -ENOMEM;
   430				goto out_fail;
   431			}
   432	
   433			if (!IS_ALIGNED((u64)vmd, vmt_info->vmd_size)) {
   434				kvm_err("VMD is incorrectly aligned\n");
   435				ret = -EFAULT;
   436				goto out_fail;
   437			}
   438	
   439			/* Stash the VA so we can free it later */
   440			vmi->vmd_base = vmd;
   441	
   442			tmp = FIELD_PREP(GICV5_VMTEL2E_VMD_ADDR,
   443					virt_to_phys(vmd) >>
   444					GICV5_VMTEL2E_VMD_ADDR_SHIFT);
   445			WRITE_ONCE(vmte->val[0], cpu_to_le64(tmp));
   446		}
   447	
   448		/*
   449		 * Allocate and assign the VPE Table.
   450		 */
   451		vpet_alloc_size = sizeof(vpe_entry) * vmt_info->max_vpes;
   452		vpet = kzalloc(vpet_alloc_size, GFP_KERNEL);
   453		if (vpet == NULL) {
   454			kvm_err("Failed to allocate memory for VPE Table\n");
   455			ret = -ENOMEM;
   456			goto out_fail;
   457		}
   458	
   459		if (!IS_ALIGNED((u64)vpet, vpet_alloc_size)) {
   460			kvm_err("VPET is incorrectly aligned\n");
   461			ret = -EFAULT;
   462			goto out_fail;
   463		}
   464	
   465		/* Stash the VA so we can free it later */
   466		vmi->vpet_base = vpet;
   467	
   468		tmp = FIELD_PREP(GICV5_VMTEL2E_VPET_ADDR,
   469				virt_to_phys(vpet) >> GICV5_VMTEL2E_VPET_ADDR_SHIFT);
   470		tmp |= FIELD_PREP(GICV5_VMTEL2E_VPE_ID_BITS, fls(vmt_info->max_vpes) - 1);
   471		WRITE_ONCE(vmte->val[1], cpu_to_le64(tmp));
   472	
 > 473		vped_ptrs = kzalloc(vmt_info->max_vpes * sizeof(vped_ptrs), GFP_KERNEL);
   474		if (vped_ptrs == NULL) {
   475			kvm_err("Failed to allocate memory for VPED tracking\n");
   476			ret = -ENOMEM;
   477			goto out_fail;
   478		}
   479		vmi->vped_ptrs = vped_ptrs;
   480	
   481		if (gicv5_host_ist_caps.irs_non_coherent) {
   482			if (vmd)
   483				dcache_clean_inval_poc((unsigned long)vmd,
   484						       (unsigned long)vmd + vmt_info->vmd_size);
   485			if (vpet)
   486				dcache_clean_inval_poc((unsigned long)vpet,
   487						       (unsigned long)vpet + vpet_alloc_size);
   488			dcache_clean_poc((unsigned long)vmte,
   489					 (unsigned long)vmte + sizeof(*vmte));
   490		} else {
   491			dsb(ishst);
   492		}
   493	
   494		ret = xa_insert(&vm_info, vm_id, vmi, GFP_KERNEL);
   495		if (ret)
   496			goto out_fail;
   497	
   498		return 0;
   499	
   500	out_fail:
   501		if (vmd)
 > 502			kfree(vmd);
   503		if (vpet)
   504			kfree(vpet);
   505		if (vped_ptrs)
   506			kfree(vped_ptrs);
   507		if (vmi)
   508			kfree(vmi);
   509	
   510		vgic_v5_reset_vmte(vm_id);
   511	
   512		return ret;
   513	}
   514	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From zhanjie9 at hisilicon.com  Mon Dec 22 23:21:19 2025
From: zhanjie9 at hisilicon.com (Jie Zhan)
Date: Tue, 23 Dec 2025 15:21:19 +0800
Subject: [PATCH v5 3/3] cpufreq: CPPC: Update FIE arch_freq_scale in ticks for non-PCC regs
In-Reply-To: <20251223072119.3372582-1-zhanjie9@hisilicon.com>
References: <20251223072119.3372582-1-zhanjie9@hisilicon.com>
Message-ID: <20251223072119.3372582-4-zhanjie9@hisilicon.com>

Currently, the CPPC Frequency Invariance Engine (FIE) is invoked from the
scheduler tick but defers the update of arch_freq_scale to a separate
thread because cppc_get_perf_ctrs() would sleep if the CPC regs are in PCC.

However, this deferred update mechanism is unnecessary and introduces extra
overhead for non-PCC register spaces (e.g. System Memory or FFH), where
accessing the regs won't sleep and can be safely performed from the tick
context.

Furthermore, with the CPPC FIE registered, it throws repeated warnings of
"cppc_scale_freq_workfn: failed to read perf counters" on our platform with
the CPC regs in System Memory and a power-down idle state enabled.  That's
because the remote CPU can be in a power-down idle state, and reading its
perf counters returns 0.  Moving the FIE handling back to the scheduler
tick process makes the CPU handle its own perf counters, so it won't be
idle and the issue would be inherently solved.

To address the above issues, update arch_freq_scale directly in ticks for
non-PCC regs and keep the deferred update mechanism for PCC regs.

Reviewed-by: Lifeng Zheng <zhenglifeng1 at huawei.com>
Reviewed-by: Pierre Gondois <pierre.gondois at arm.com>
Signed-off-by: Jie Zhan <zhanjie9 at hisilicon.com>
---
 drivers/cpufreq/cppc_cpufreq.c | 77 +++++++++++++++++++++++-----------
 1 file changed, 52 insertions(+), 25 deletions(-)

diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index 947b4e2e1d4e..36e8a75a37f1 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -54,31 +54,24 @@ static int cppc_perf_from_fbctrs(struct cppc_perf_fb_ctrs *fb_ctrs_t0,
 				 struct cppc_perf_fb_ctrs *fb_ctrs_t1);
 
 /**
- * cppc_scale_freq_workfn - CPPC arch_freq_scale updater for frequency invariance
- * @work: The work item.
+ * __cppc_scale_freq_tick - CPPC arch_freq_scale updater for frequency invariance
+ * @cppc_fi: per-cpu CPPC FIE data.
  *
- * The CPPC driver register itself with the topology core to provide its own
+ * The CPPC driver registers itself with the topology core to provide its own
  * implementation (cppc_scale_freq_tick()) of topology_scale_freq_tick() which
  * gets called by the scheduler on every tick.
  *
  * Note that the arch specific counters have higher priority than CPPC counters,
  * if available, though the CPPC driver doesn't need to have any special
  * handling for that.
- *
- * On an invocation of cppc_scale_freq_tick(), we schedule an irq work (since we
- * reach here from hard-irq context), which then schedules a normal work item
- * and cppc_scale_freq_workfn() updates the per_cpu arch_freq_scale variable
- * based on the counter updates since the last tick.
  */
-static void cppc_scale_freq_workfn(struct kthread_work *work)
+static void __cppc_scale_freq_tick(struct cppc_freq_invariance *cppc_fi)
 {
-	struct cppc_freq_invariance *cppc_fi;
 	struct cppc_perf_fb_ctrs fb_ctrs = {0};
 	struct cppc_cpudata *cpu_data;
 	unsigned long local_freq_scale;
 	u64 perf;
 
-	cppc_fi = container_of(work, struct cppc_freq_invariance, work);
 	cpu_data = cppc_fi->cpu_data;
 
 	if (cppc_get_perf_ctrs(cppc_fi->cpu, &fb_ctrs)) {
@@ -102,6 +95,24 @@ static void cppc_scale_freq_workfn(struct kthread_work *work)
 	per_cpu(arch_freq_scale, cppc_fi->cpu) = local_freq_scale;
 }
 
+static void cppc_scale_freq_tick(void)
+{
+	__cppc_scale_freq_tick(&per_cpu(cppc_freq_inv, smp_processor_id()));
+}
+
+static struct scale_freq_data cppc_sftd = {
+	.source = SCALE_FREQ_SOURCE_CPPC,
+	.set_freq_scale = cppc_scale_freq_tick,
+};
+
+static void cppc_scale_freq_workfn(struct kthread_work *work)
+{
+	struct cppc_freq_invariance *cppc_fi;
+
+	cppc_fi = container_of(work, struct cppc_freq_invariance, work);
+	__cppc_scale_freq_tick(cppc_fi);
+}
+
 static void cppc_irq_work(struct irq_work *irq_work)
 {
 	struct cppc_freq_invariance *cppc_fi;
@@ -110,7 +121,14 @@ static void cppc_irq_work(struct irq_work *irq_work)
 	kthread_queue_work(kworker_fie, &cppc_fi->work);
 }
 
-static void cppc_scale_freq_tick(void)
+/*
+ * Reading perf counters may sleep if the CPC regs are in PCC.  Thus, we
+ * schedule an irq work in scale_freq_tick (since we reach here from hard-irq
+ * context), which then schedules a normal work item cppc_scale_freq_workfn()
+ * that updates the per_cpu arch_freq_scale variable based on the counter
+ * updates since the last tick.
+ */
+static void cppc_scale_freq_tick_pcc(void)
 {
 	struct cppc_freq_invariance *cppc_fi = &per_cpu(cppc_freq_inv, smp_processor_id());
 
@@ -121,13 +139,14 @@ static void cppc_scale_freq_tick(void)
 	irq_work_queue(&cppc_fi->irq_work);
 }
 
-static struct scale_freq_data cppc_sftd = {
+static struct scale_freq_data cppc_sftd_pcc = {
 	.source = SCALE_FREQ_SOURCE_CPPC,
-	.set_freq_scale = cppc_scale_freq_tick,
+	.set_freq_scale = cppc_scale_freq_tick_pcc,
 };
 
 static void cppc_cpufreq_cpu_fie_init(struct cpufreq_policy *policy)
 {
+	struct scale_freq_data *sftd = &cppc_sftd;
 	struct cppc_freq_invariance *cppc_fi;
 	int cpu, ret;
 
@@ -138,8 +157,11 @@ static void cppc_cpufreq_cpu_fie_init(struct cpufreq_policy *policy)
 		cppc_fi = &per_cpu(cppc_freq_inv, cpu);
 		cppc_fi->cpu = cpu;
 		cppc_fi->cpu_data = policy->driver_data;
-		kthread_init_work(&cppc_fi->work, cppc_scale_freq_workfn);
-		init_irq_work(&cppc_fi->irq_work, cppc_irq_work);
+		if (cppc_perf_ctrs_in_pcc_cpu(cpu)) {
+			kthread_init_work(&cppc_fi->work, cppc_scale_freq_workfn);
+			init_irq_work(&cppc_fi->irq_work, cppc_irq_work);
+			sftd = &cppc_sftd_pcc;
+		}
 
 		ret = cppc_get_perf_ctrs(cpu, &cppc_fi->prev_perf_fb_ctrs);
 
@@ -155,7 +177,7 @@ static void cppc_cpufreq_cpu_fie_init(struct cpufreq_policy *policy)
 	}
 
 	/* Register for freq-invariance */
-	topology_set_scale_freq_source(&cppc_sftd, policy->cpus);
+	topology_set_scale_freq_source(sftd, policy->cpus);
 }
 
 /*
@@ -178,6 +200,8 @@ static void cppc_cpufreq_cpu_fie_exit(struct cpufreq_policy *policy)
 	topology_clear_scale_freq_source(SCALE_FREQ_SOURCE_CPPC, policy->related_cpus);
 
 	for_each_cpu(cpu, policy->related_cpus) {
+		if (!cppc_perf_ctrs_in_pcc_cpu(cpu))
+			continue;
 		cppc_fi = &per_cpu(cppc_freq_inv, cpu);
 		irq_work_sync(&cppc_fi->irq_work);
 		kthread_cancel_work_sync(&cppc_fi->work);
@@ -206,6 +230,7 @@ static void cppc_fie_kworker_init(void)
 		pr_warn("%s: failed to create kworker_fie: %ld\n", __func__,
 			PTR_ERR(kworker_fie));
 		fie_disabled = FIE_DISABLED;
+		kworker_fie = NULL;
 		return;
 	}
 
@@ -215,20 +240,24 @@ static void cppc_fie_kworker_init(void)
 			ret);
 		kthread_destroy_worker(kworker_fie);
 		fie_disabled = FIE_DISABLED;
+		kworker_fie = NULL;
 	}
 }
 
 static void __init cppc_freq_invariance_init(void)
 {
-	if (fie_disabled != FIE_ENABLED && fie_disabled != FIE_DISABLED) {
-		fie_disabled = FIE_ENABLED;
-		if (cppc_perf_ctrs_in_pcc()) {
+	bool perf_ctrs_in_pcc = cppc_perf_ctrs_in_pcc();
+
+	if (fie_disabled == FIE_UNSET) {
+		if (perf_ctrs_in_pcc) {
 			pr_info("FIE not enabled on systems with registers in PCC\n");
 			fie_disabled = FIE_DISABLED;
+		} else {
+			fie_disabled = FIE_ENABLED;
 		}
 	}
 
-	if (fie_disabled)
+	if (fie_disabled || !perf_ctrs_in_pcc)
 		return;
 
 	cppc_fie_kworker_init();
@@ -236,10 +265,8 @@ static void __init cppc_freq_invariance_init(void)
 
 static void cppc_freq_invariance_exit(void)
 {
-	if (fie_disabled)
-		return;
-
-	kthread_destroy_worker(kworker_fie);
+	if (kworker_fie)
+		kthread_destroy_worker(kworker_fie);
 }
 
 #else
-- 
2.33.0



From zhanjie9 at hisilicon.com  Mon Dec 22 23:21:18 2025
From: zhanjie9 at hisilicon.com (Jie Zhan)
Date: Tue, 23 Dec 2025 15:21:18 +0800
Subject: [PATCH v5 2/3] cpufreq: CPPC: Factor out cppc_fie_kworker_init()
In-Reply-To: <20251223072119.3372582-1-zhanjie9@hisilicon.com>
References: <20251223072119.3372582-1-zhanjie9@hisilicon.com>
Message-ID: <20251223072119.3372582-3-zhanjie9@hisilicon.com>

Factor out the CPPC FIE kworker init in cppc_freq_invariance_init() because
it's a standalone procedure for use when the CPC regs are in PCC channels.

Reviewed-by: Lifeng Zheng <zhenglifeng1 at huawei.com>
Reviewed-by: Pierre Gondois <pierre.gondois at arm.com>
Signed-off-by: Jie Zhan <zhanjie9 at hisilicon.com>
---
 drivers/cpufreq/cppc_cpufreq.c | 29 +++++++++++++++++------------
 1 file changed, 17 insertions(+), 12 deletions(-)

diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index 9eac77c4f294..947b4e2e1d4e 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -184,7 +184,7 @@ static void cppc_cpufreq_cpu_fie_exit(struct cpufreq_policy *policy)
 	}
 }
 
-static void __init cppc_freq_invariance_init(void)
+static void cppc_fie_kworker_init(void)
 {
 	struct sched_attr attr = {
 		.size		= sizeof(struct sched_attr),
@@ -201,17 +201,6 @@ static void __init cppc_freq_invariance_init(void)
 	};
 	int ret;
 
-	if (fie_disabled != FIE_ENABLED && fie_disabled != FIE_DISABLED) {
-		fie_disabled = FIE_ENABLED;
-		if (cppc_perf_ctrs_in_pcc()) {
-			pr_info("FIE not enabled on systems with registers in PCC\n");
-			fie_disabled = FIE_DISABLED;
-		}
-	}
-
-	if (fie_disabled)
-		return;
-
 	kworker_fie = kthread_run_worker(0, "cppc_fie");
 	if (IS_ERR(kworker_fie)) {
 		pr_warn("%s: failed to create kworker_fie: %ld\n", __func__,
@@ -229,6 +218,22 @@ static void __init cppc_freq_invariance_init(void)
 	}
 }
 
+static void __init cppc_freq_invariance_init(void)
+{
+	if (fie_disabled != FIE_ENABLED && fie_disabled != FIE_DISABLED) {
+		fie_disabled = FIE_ENABLED;
+		if (cppc_perf_ctrs_in_pcc()) {
+			pr_info("FIE not enabled on systems with registers in PCC\n");
+			fie_disabled = FIE_DISABLED;
+		}
+	}
+
+	if (fie_disabled)
+		return;
+
+	cppc_fie_kworker_init();
+}
+
 static void cppc_freq_invariance_exit(void)
 {
 	if (fie_disabled)
-- 
2.33.0



From zhanjie9 at hisilicon.com  Mon Dec 22 23:21:17 2025
From: zhanjie9 at hisilicon.com (Jie Zhan)
Date: Tue, 23 Dec 2025 15:21:17 +0800
Subject: [PATCH v5 1/3] ACPI: CPPC: Factor out and export per-cpu cppc_perf_ctrs_in_pcc_cpu()
In-Reply-To: <20251223072119.3372582-1-zhanjie9@hisilicon.com>
References: <20251223072119.3372582-1-zhanjie9@hisilicon.com>
Message-ID: <20251223072119.3372582-2-zhanjie9@hisilicon.com>

Factor out cppc_perf_ctrs_in_pcc_cpu() for checking whether per-cpu CPC
regs are defined in PCC channels, and export it out for further use.

Reviewed-by: Lifeng Zheng <zhenglifeng1 at huawei.com>
Reviewed-by: Pierre Gondois <pierre.gondois at arm.com>
Signed-off-by: Jie Zhan <zhanjie9 at hisilicon.com>
---
 drivers/acpi/cppc_acpi.c | 48 ++++++++++++++++++++++------------------
 include/acpi/cppc_acpi.h |  5 +++++
 2 files changed, 32 insertions(+), 21 deletions(-)

diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index e66e20d1f31b..22d7fd669a6c 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1423,6 +1423,32 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
 }
 EXPORT_SYMBOL_GPL(cppc_get_perf_caps);
 
+/**
+ * cppc_perf_ctrs_in_pcc_cpu - Check if any perf counters of a CPU are in PCC.
+ * @cpu: CPU on which to check perf counters.
+ *
+ * Return: true if any of the counters are in PCC regions, false otherwise
+ */
+bool cppc_perf_ctrs_in_pcc_cpu(unsigned int cpu)
+{
+	struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu);
+	struct cpc_register_resource *ref_perf_reg;
+
+	/*
+	 * If reference perf register is not supported then we should use the
+	 * nominal perf value
+	 */
+	ref_perf_reg = &cpc_desc->cpc_regs[REFERENCE_PERF];
+	if (!CPC_SUPPORTED(ref_perf_reg))
+		ref_perf_reg = &cpc_desc->cpc_regs[NOMINAL_PERF];
+
+	return CPC_IN_PCC(&cpc_desc->cpc_regs[DELIVERED_CTR]) ||
+		CPC_IN_PCC(&cpc_desc->cpc_regs[REFERENCE_CTR]) ||
+		CPC_IN_PCC(&cpc_desc->cpc_regs[CTR_WRAP_TIME]) ||
+		CPC_IN_PCC(ref_perf_reg);
+}
+EXPORT_SYMBOL_GPL(cppc_perf_ctrs_in_pcc_cpu);
+
 /**
  * cppc_perf_ctrs_in_pcc - Check if any perf counters are in a PCC region.
  *
@@ -1437,27 +1463,7 @@ bool cppc_perf_ctrs_in_pcc(void)
 	int cpu;
 
 	for_each_online_cpu(cpu) {
-		struct cpc_register_resource *ref_perf_reg;
-		struct cpc_desc *cpc_desc;
-
-		cpc_desc = per_cpu(cpc_desc_ptr, cpu);
-
-		if (CPC_IN_PCC(&cpc_desc->cpc_regs[DELIVERED_CTR]) ||
-		    CPC_IN_PCC(&cpc_desc->cpc_regs[REFERENCE_CTR]) ||
-		    CPC_IN_PCC(&cpc_desc->cpc_regs[CTR_WRAP_TIME]))
-			return true;
-
-
-		ref_perf_reg = &cpc_desc->cpc_regs[REFERENCE_PERF];
-
-		/*
-		 * If reference perf register is not supported then we should
-		 * use the nominal perf value
-		 */
-		if (!CPC_SUPPORTED(ref_perf_reg))
-			ref_perf_reg = &cpc_desc->cpc_regs[NOMINAL_PERF];
-
-		if (CPC_IN_PCC(ref_perf_reg))
+		if (cppc_perf_ctrs_in_pcc_cpu(cpu))
 			return true;
 	}
 
diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h
index 13fa81504844..4bcdcaf8bf2c 100644
--- a/include/acpi/cppc_acpi.h
+++ b/include/acpi/cppc_acpi.h
@@ -154,6 +154,7 @@ extern int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_ctrs);
 extern int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls);
 extern int cppc_set_enable(int cpu, bool enable);
 extern int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps);
+extern bool cppc_perf_ctrs_in_pcc_cpu(unsigned int cpu);
 extern bool cppc_perf_ctrs_in_pcc(void);
 extern unsigned int cppc_perf_to_khz(struct cppc_perf_caps *caps, unsigned int perf);
 extern unsigned int cppc_khz_to_perf(struct cppc_perf_caps *caps, unsigned int freq);
@@ -204,6 +205,10 @@ static inline int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps)
 {
 	return -EOPNOTSUPP;
 }
+static inline bool cppc_perf_ctrs_in_pcc_cpu(unsigned int cpu)
+{
+	return false;
+}
 static inline bool cppc_perf_ctrs_in_pcc(void)
 {
 	return false;
-- 
2.33.0



From zhanjie9 at hisilicon.com  Mon Dec 22 23:21:16 2025
From: zhanjie9 at hisilicon.com (Jie Zhan)
Date: Tue, 23 Dec 2025 15:21:16 +0800
Subject: [PATCH v5 0/3] cpufreq: CPPC: Update FIE arch_freq_scale in ticks for non-PCC regs
Message-ID: <20251223072119.3372582-1-zhanjie9@hisilicon.com>

Currently, the CPPC Frequency Invariance Engine (FIE) is invoked from the
scheduler tick but defers the update of arch_freq_scale to a separate
thread because cppc_get_perf_ctrs() would sleep if the CPC regs are in PCC.

However, this deferred update mechanism is unnecessary and introduces extra
overhead for non-PCC register spaces (e.g. System Memory or FFH), where
accessing the regs won't sleep and can be safely performed from the tick
context.

Furthermore, with the CPPC FIE registered, it throws repeated warnings of
"cppc_scale_freq_workfn: failed to read perf counters" on our platform with
the CPC regs in System Memory and a power-down idle state enabled.  That's
because the remote CPU can be in a power-down idle state, and reading its
perf counters returns 0.  Moving the FIE handling back to the scheduler
tick process makes the CPU handle its own perf counters, so it won't be
idle and the issue would be inherently solved.

To address the above issues, update arch_freq_scale directly in ticks for
non-PCC regs and keep the deferred update mechanism for PCC regs.

We have tested this on Kunpeng SoCs with the CPC regs both in System Memory
and FFH.  More tests on other platforms are welcome (typically with the
regs in PCC).

Changelog:
v5:
- Minor cleanup of cppc_perf_ctrs_in_pcc_cpu() (Thanks to Rafael).
- Add a function description for cppc_perf_ctrs_in_pcc_cpu().
- Pick up tags from Lifeng and Pierre, Thanks!

v4:
https://lore.kernel.org/all/20251203032422.3232957-1-zhanjie9 at hisilicon.com/
- Allow either non-PCC or PCC scale_freq_tick callbacks to be registered
  for each cpufreq policy.
- Factor out cppc_perf_ctrs_in_pcc_cpu() and cppc_fie_kworker_init() for
  the above change.

v3:
https://lore.kernel.org/linux-pm/20251104065039.1675549-1-zhanjie9 at hisilicon.com/
- Stash the state of 'cppc_perf_ctrs_in_pcc' so it won't have to check the
  CPC regs of all CPUs everywhere (Thanks to the suggestion from Beata
  Michalska).
- Update the commit log, explaining more on the warning issue caused by
  accessing perf counters on remote CPUs.
- Drop Patch 1 that has been accepted, and rebase Patch 2 on that.

v2:
https://lore.kernel.org/linux-pm/20250828110212.2108653-1-zhanjie9 at hisilicon.com/
- Update the cover letter and the commit log based on v1 discussion
- Update FIE arch_freq_scale in ticks for non-PCC regs

v1:
https://lore.kernel.org/linux-pm/20250730032312.167062-1-yubowen8 at huawei.com/

Jie Zhan (3):
  ACPI: CPPC: Factor out and export per-cpu cppc_perf_ctrs_in_pcc_cpu()
  cpufreq: CPPC: Factor out cppc_fie_kworker_init()
  cpufreq: CPPC: Update FIE arch_freq_scale in ticks for non-PCC regs

 drivers/acpi/cppc_acpi.c       | 48 +++++++++--------
 drivers/cpufreq/cppc_cpufreq.c | 96 ++++++++++++++++++++++------------
 include/acpi/cppc_acpi.h       |  5 ++
 3 files changed, 96 insertions(+), 53 deletions(-)

-- 
2.33.0



From richard.genoud at bootlin.com  Mon Dec 22 23:25:49 2025
From: richard.genoud at bootlin.com (Richard Genoud)
Date: Tue, 23 Dec 2025 08:25:49 +0100
Subject: [PATCH] soc: fsl: qbman: fix race condition in qman_destroy_fq
Message-ID: <20251223072549.397625-1-richard.genoud@bootlin.com>

When QMAN_FQ_FLAG_DYNAMIC_FQID is set, there's a race condition between
fq_table[fq->idx] state and freeing/allocating from the pool and
WARN_ON(fq_table[fq->idx]) in qman_create_fq() gets triggered.

Indeed, we can have:
         Thread A                             Thread B
    qman_destroy_fq()                    qman_create_fq()
      qman_release_fqid()
        qman_shutdown_fq()
        gen_pool_free()
           -- At this point, the fqid is available again --
                                           qman_alloc_fqid()
           -- so, we can get the just-freed fqid in thread B --
                                           fq->fqid = fqid;
                                           fq->idx = fqid * 2;
                                           WARN_ON(fq_table[fq->idx]);
                                           fq_table[fq->idx] = fq;
     fq_table[fq->idx] = NULL;

And adding some logs between qman_release_fqid() and
fq_table[fq->idx] = NULL makes the WARN_ON() trigger a lot more.

To prevent that, ensure that fq_table[fq->idx] is set to NULL before
gen_pool_free() is called by using smp_wmb().

Fixes: c535e923bb97 ("soc/fsl: Introduce DPAA 1.x QMan device driver")
Signed-off-by: Richard Genoud <richard.genoud at bootlin.com>
---
 drivers/soc/fsl/qbman/qman.c | 24 ++++++++++++++++++++++--
 1 file changed, 22 insertions(+), 2 deletions(-)

NB: I'm not 100% sure of the need of a barrier here, since even without
it, the WARN_ON() wasn't triggered any more.

diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c
index 6b392b3ad4b1..39a3e7aab6ff 100644
--- a/drivers/soc/fsl/qbman/qman.c
+++ b/drivers/soc/fsl/qbman/qman.c
@@ -1827,6 +1827,8 @@ EXPORT_SYMBOL(qman_create_fq);
 
 void qman_destroy_fq(struct qman_fq *fq)
 {
+	int leaked;
+
 	/*
 	 * We don't need to lock the FQ as it is a pre-condition that the FQ be
 	 * quiesced. Instead, run some checks.
@@ -1834,11 +1836,29 @@ void qman_destroy_fq(struct qman_fq *fq)
 	switch (fq->state) {
 	case qman_fq_state_parked:
 	case qman_fq_state_oos:
-		if (fq_isset(fq, QMAN_FQ_FLAG_DYNAMIC_FQID))
-			qman_release_fqid(fq->fqid);
+		/*
+		 * There's a race condition here on releasing the fqid,
+		 * setting the fq_table to NULL, and freeing the fqid.
+		 * To prevent it, this order should be respected:
+		 */
+		if (fq_isset(fq, QMAN_FQ_FLAG_DYNAMIC_FQID)) {
+			leaked = qman_shutdown_fq(fq->fqid);
+			if (leaked)
+				pr_debug("FQID %d leaked\n", fq->fqid);
+		}
 
 		DPAA_ASSERT(fq_table[fq->idx]);
 		fq_table[fq->idx] = NULL;
+
+		if (fq_isset(fq, QMAN_FQ_FLAG_DYNAMIC_FQID) && !leaked) {
+			/*
+			 * fq_table[fq->idx] should be set to null before
+			 * freeing fq->fqid otherwise it could by allocated by
+			 * qman_alloc_fqid() while still being !NULL
+			 */
+			smp_wmb();
+			gen_pool_free(qm_fqalloc, fq->fqid | DPAA_GENALLOC_OFF, 1);
+		}
 		return;
 	default:
 		break;

base-commit: 9448598b22c50c8a5bb77a9103e2d49f134c9578
-- 
2.47.3



From francesco at dolcini.it  Tue Dec 23 00:37:26 2025
From: francesco at dolcini.it (Francesco Dolcini)
Date: Tue, 23 Dec 2025 09:37:26 +0100
Subject: [PATCH v2] phy: fsl-imx8mq-usb: fix typec orientation switch
 when built as module
In-Reply-To: <20251126140136.1202241-1-fra.schnyder@gmail.com>
References: <20251126140136.1202241-1-fra.schnyder@gmail.com>
Message-ID: <20251223083726.GA24283@francesco-nb>

Hello Vinod,

On Wed, Nov 26, 2025 at 03:01:33PM +0100, Franz Schnyder wrote:
> From: Franz Schnyder <franz.schnyder at toradex.com>
> 
> Currently, the PHY only registers the typec orientation switch when it
> is built in. If the typec driver is built as a module, the switch
> registration is skipped due to the preprocessor condition, causing
> orientation detection to fail.
> 
> With commit
> 45fe729be9a6 ("usb: typec: Stub out typec_switch APIs when CONFIG_TYPEC=n")
> the preprocessor condition is not needed anymore and the orientation
> switch is correctly registered for both built-in and module builds.
> 
> Fixes: b58f0f86fd61 ("phy: fsl-imx8mq-usb: add tca function driver for imx95")
> Cc: stable at vger.kernel.org
> Suggested-by: Xu Yang <xu.yang_2 at nxp.com>
> Signed-off-by: Franz Schnyder <franz.schnyder at toradex.com>

Just a gentle ping on this.

Thanks,
Francesco



From jie.gan at oss.qualcomm.com  Tue Dec 23 00:41:44 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Tue, 23 Dec 2025 16:41:44 +0800
Subject: [PATCH v7 0/4] add sysfs nodes to configure TPDA's registers
Message-ID: <20251223-add_sysfs_nodes_to_configure_tpda-v7-0-db4e6810047c@oss.qualcomm.com>

Patchset 1 introduces configuration of the global control register with
appropriate values to enable proper generation of cross-trigger packets.

Patchset 2 introduces a sysfs node for triggering global flush for all
ports.

Patchset 3 introduces a logic to configure the TPDA_SYNCR register,
which determines the frequency of ASYNC packet generation. These packets
assist userspace tools in accurately identifying each valid packet.

Patchset 4 introduces a sysfs node to initiate a flush request for the
specific port, forcing the data to synchronize and be transmitted to the
sink device.

Changes in v7:
1. add syncr_count sysfs node.
2. add more detail to describe port_flush_req node.
Link to v6: https://lore.kernel.org/r/20251222-add_sysfs_nodes_to_configure_tpda-v6-0-b27143d45c86 at oss.qualcomm.com

Changes in v6:
1. Create a new patch for introducing gloabl_flush_req sysfs node.
2. Add a syncr_mode sysfs node for TPDA_SYNCR.
3. Remove the redundant attr_grp and consolidate all attributes under tpda_attr_grp.
Link to v5: https://lore.kernel.org/r/20251219-add_sysfs_nodes_to_configure_tpda-v5-0-ca93ddfe9d30 at oss.qualcomm.com

Chnages in V5:
1. Optimizing the solution to creat sysfs nodes.
2. Optimizing the logic for configuring bits of the global control
   register.
Link to V4 - https://lore.kernel.org/all/20251028-configure_tpda_reg-v4-0-23000805d21d at oss.qualcomm.com/

Changes in V4:
1. Document sysfs nodes with correct kernel version and date.
Link to V3 - https://lore.kernel.org/linux-arm-kernel/20250827105545.7140-1-jie.gan at oss.qualcomm.com/

Changes in V3:
1. Optimizing codes according to James's comment.
Link to V2 - https://lore.kernel.org/all/20250827042042.6786-1-jie.gan at oss.qualcomm.com/

Changes in V2:
1. Refactoring the code based on James's comment for optimization.
Link to V1 - https://lore.kernel.org/all/20250826070150.5603-1-jie.gan at oss.qualcomm.com/

Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
Jie Gan (1):
      coresight: tpda: add global_flush_req sysfs node

Tao Zhang (3):
      coresight: tpda: add sysfs nodes for tpda cross-trigger configuration
      coresight: tpda: add logic to configure TPDA_SYNCR register
      coresight: tpda: add sysfs node to flush specific port

 .../ABI/testing/sysfs-bus-coresight-devices-tpda   |  69 +++++
 drivers/hwtracing/coresight/coresight-tpda.c       | 284 ++++++++++++++++++++-
 drivers/hwtracing/coresight/coresight-tpda.h       |  76 +++++-
 3 files changed, 422 insertions(+), 7 deletions(-)
---
base-commit: 12b95d29eb979e5c4f4f31bb05817bc935c52050
change-id: 20251219-add_sysfs_nodes_to_configure_tpda-f54636512817

Best regards,
-- 
Jie Gan <jie.gan at oss.qualcomm.com>



From jie.gan at oss.qualcomm.com  Tue Dec 23 00:41:45 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Tue, 23 Dec 2025 16:41:45 +0800
Subject: [PATCH v7 1/4] coresight: tpda: add sysfs nodes for tpda
 cross-trigger configuration
In-Reply-To: <20251223-add_sysfs_nodes_to_configure_tpda-v7-0-db4e6810047c@oss.qualcomm.com>
References: <20251223-add_sysfs_nodes_to_configure_tpda-v7-0-db4e6810047c@oss.qualcomm.com>
Message-ID: <20251223-add_sysfs_nodes_to_configure_tpda-v7-1-db4e6810047c@oss.qualcomm.com>

From: Tao Zhang <tao.zhang at oss.qualcomm.com>

Introduce sysfs nodes to configure cross-trigger parameters for TPDA.
These registers define the characteristics of cross-trigger packets,
including generation frequency and flag values.

Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
Reviewed-by: James Clark <james.clark at linaro.org>
Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 .../ABI/testing/sysfs-bus-coresight-devices-tpda   |  35 +++++++
 drivers/hwtracing/coresight/coresight-tpda.c       | 109 ++++++++++++++++++++-
 drivers/hwtracing/coresight/coresight-tpda.h       |  63 +++++++++++-
 3 files changed, 200 insertions(+), 7 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
new file mode 100644
index 000000000000..735ce0e494da
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
@@ -0,0 +1,35 @@
+What:		/sys/bus/coresight/devices/<tpda-name>/trig_async_enable
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Enable/disable cross trigger synchronization sequence interface.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/trig_flag_ts_enable
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Enable/disable cross trigger FLAG packet request interface.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/trig_freq_enable
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Enable/disable cross trigger FREQ packet request interface.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/freq_ts_enable
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Enable/disable the timestamp for all FREQ packets.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/cmbchan_mode
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Configure the CMB/MCMB channel mode for all enabled ports.
+		Value 0 means raw channel mapping mode. Value 1 means channel pair marking mode.
diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
index 3a3825d27f86..2186223ad33e 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.c
+++ b/drivers/hwtracing/coresight/coresight-tpda.c
@@ -137,12 +137,32 @@ static int tpda_get_element_size(struct tpda_drvdata *drvdata,
 /* Settings pre enabling port control register */
 static void tpda_enable_pre_port(struct tpda_drvdata *drvdata)
 {
-	u32 val;
+	u32 val = 0;
 
-	val = readl_relaxed(drvdata->base + TPDA_CR);
-	val &= ~TPDA_CR_ATID;
 	val |= FIELD_PREP(TPDA_CR_ATID, drvdata->atid);
+	if (drvdata->trig_async)
+		val |= TPDA_CR_SRIE;
+
+	if (drvdata->trig_flag_ts)
+		val |= TPDA_CR_FLRIE;
+
+	if (drvdata->trig_freq)
+		val |= TPDA_CR_FRIE;
+
+	if (drvdata->freq_ts)
+		val |= TPDA_CR_FREQTS;
+
+	if (drvdata->cmbchan_mode)
+		val |= TPDA_CR_CMBCHANMODE;
+
 	writel_relaxed(val, drvdata->base + TPDA_CR);
+
+	/*
+	 * If FLRIE bit is set, set the master and channel
+	 * id as zero
+	 */
+	if (drvdata->trig_flag_ts)
+		writel_relaxed(0x0, drvdata->base + TPDA_FPID_CR);
 }
 
 static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
@@ -258,6 +278,87 @@ static const struct coresight_ops tpda_cs_ops = {
 	.link_ops	= &tpda_link_ops,
 };
 
+/* Read cross-trigger register member */
+static ssize_t tpda_trig_sysfs_show(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	struct tpda_trig_sysfs_attribute *tpda_attr =
+		container_of(attr, struct tpda_trig_sysfs_attribute, attr);
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	guard(spinlock)(&drvdata->spinlock);
+	switch (tpda_attr->mem) {
+	case FREQTS:
+		return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->freq_ts);
+	case FRIE:
+		return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_freq);
+	case FLRIE:
+		return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_flag_ts);
+	case SRIE:
+		return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_async);
+	case CMBCHANMODE:
+		return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->cmbchan_mode);
+
+	}
+	return -EINVAL;
+}
+
+static ssize_t tpda_trig_sysfs_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf,
+				     size_t size)
+{
+	struct tpda_trig_sysfs_attribute *tpda_attr =
+		container_of(attr, struct tpda_trig_sysfs_attribute, attr);
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (kstrtoul(buf, 0, &val))
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	switch (tpda_attr->mem) {
+	case FREQTS:
+		drvdata->freq_ts = !!val;
+		break;
+	case FRIE:
+		drvdata->trig_freq = !!val;
+		break;
+	case FLRIE:
+		drvdata->trig_flag_ts = !!val;
+		break;
+	case SRIE:
+		drvdata->trig_async = !!val;
+		break;
+	case CMBCHANMODE:
+		drvdata->cmbchan_mode = !!val;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return size;
+}
+
+static struct attribute *tpda_attrs[] = {
+	tpda_trig_sysfs_rw(freq_ts_enable, FREQTS),
+	tpda_trig_sysfs_rw(trig_freq_enable, FRIE),
+	tpda_trig_sysfs_rw(trig_flag_ts_enable, FLRIE),
+	tpda_trig_sysfs_rw(trig_async_enable, SRIE),
+	tpda_trig_sysfs_rw(cmbchan_mode, CMBCHANMODE),
+	NULL,
+};
+
+static struct attribute_group tpda_attr_grp = {
+	.attrs	= tpda_attrs,
+};
+
+static const struct attribute_group *tpda_attr_grps[] = {
+	&tpda_attr_grp,
+	NULL,
+};
+
 static int tpda_init_default_data(struct tpda_drvdata *drvdata)
 {
 	int atid;
@@ -273,6 +374,7 @@ static int tpda_init_default_data(struct tpda_drvdata *drvdata)
 		return atid;
 
 	drvdata->atid = atid;
+	drvdata->freq_ts = true;
 	return 0;
 }
 
@@ -316,6 +418,7 @@ static int tpda_probe(struct amba_device *adev, const struct amba_id *id)
 	desc.ops = &tpda_cs_ops;
 	desc.pdata = adev->dev.platform_data;
 	desc.dev = &adev->dev;
+	desc.groups = tpda_attr_grps;
 	desc.access = CSDEV_ACCESS_IOMEM(base);
 	drvdata->csdev = coresight_register(&desc);
 	if (IS_ERR(drvdata->csdev))
diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h
index c6af3d2da3ef..c93732e04af2 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.h
+++ b/drivers/hwtracing/coresight/coresight-tpda.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 /*
- * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2023,2025 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CORESIGHT_CORESIGHT_TPDA_H
@@ -8,6 +8,25 @@
 
 #define TPDA_CR			(0x000)
 #define TPDA_Pn_CR(n)		(0x004 + (n * 4))
+#define TPDA_FPID_CR		(0x084)
+
+/* Cross trigger FREQ packets timestamp bit */
+#define TPDA_CR_FREQTS		BIT(2)
+/* Cross trigger FREQ packet request bit */
+#define TPDA_CR_FRIE		BIT(3)
+/* Cross trigger FLAG packet request interface bit */
+#define TPDA_CR_FLRIE		BIT(4)
+/* Cross trigger synchronization bit */
+#define TPDA_CR_SRIE		BIT(5)
+/* Bits 6 ~ 12 is for atid value */
+#define TPDA_CR_ATID		GENMASK(12, 6)
+/*
+ * Channel mode bit of the packetization of CMB/MCB traffic
+ * 0 - raw channel mapping mode
+ * 1 - channel pair marking mode
+ */
+#define TPDA_CR_CMBCHANMODE	BIT(20)
+
 /* Aggregator port enable bit */
 #define TPDA_Pn_CR_ENA		BIT(0)
 /* Aggregator port CMB data set element size bit */
@@ -17,9 +36,6 @@
 
 #define TPDA_MAX_INPORTS	32
 
-/* Bits 6 ~ 12 is for atid value */
-#define TPDA_CR_ATID		GENMASK(12, 6)
-
 /**
  * struct tpda_drvdata - specifics associated to an TPDA component
  * @base:       memory mapped base address for this component.
@@ -29,6 +45,11 @@
  * @enable:     enable status of the component.
  * @dsb_esize   Record the DSB element size.
  * @cmb_esize   Record the CMB element size.
+ * @trig_async:	Enable/disable cross trigger synchronization sequence interface.
+ * @trig_flag_ts: Enable/disable cross trigger FLAG packet request interface.
+ * @trig_freq:	Enable/disable cross trigger FREQ packet request interface.
+ * @freq_ts:	Enable/disable the timestamp for all FREQ packets.
+ * @cmbchan_mode: Configure the CMB/MCMB channel mode.
  */
 struct tpda_drvdata {
 	void __iomem		*base;
@@ -38,6 +59,40 @@ struct tpda_drvdata {
 	u8			atid;
 	u32			dsb_esize;
 	u32			cmb_esize;
+	bool			trig_async;
+	bool			trig_flag_ts;
+	bool			trig_freq;
+	bool			freq_ts;
+	bool			cmbchan_mode;
+};
+
+/* Enumerate members of global control register(cr) */
+enum tpda_cr_mem {
+	FREQTS,
+	FRIE,
+	FLRIE,
+	SRIE,
+	CMBCHANMODE
+};
+
+/**
+ * struct tpda_trig_sysfs_attribute - Record the member variables of cross
+ * trigger register that need to be operated by sysfs file
+ * @attr:	The device attribute
+ * @mem:	The member in the control register data structure
+ */
+struct tpda_trig_sysfs_attribute {
+	struct device_attribute attr;
+	enum tpda_cr_mem mem;
 };
 
+#define tpda_trig_sysfs_rw(name, mem)				\
+	(&((struct tpda_trig_sysfs_attribute[]) {		\
+	   {							\
+		__ATTR(name, 0644, tpda_trig_sysfs_show,	\
+		tpda_trig_sysfs_store),				\
+		mem,						\
+	   }							\
+	   })[0].attr.attr)
+
 #endif  /* _CORESIGHT_CORESIGHT_TPDA_H */

-- 
2.34.1



From jie.gan at oss.qualcomm.com  Tue Dec 23 00:41:46 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Tue, 23 Dec 2025 16:41:46 +0800
Subject: [PATCH v7 2/4] coresight: tpda: add global_flush_req sysfs node
In-Reply-To: <20251223-add_sysfs_nodes_to_configure_tpda-v7-0-db4e6810047c@oss.qualcomm.com>
References: <20251223-add_sysfs_nodes_to_configure_tpda-v7-0-db4e6810047c@oss.qualcomm.com>
Message-ID: <20251223-add_sysfs_nodes_to_configure_tpda-v7-2-db4e6810047c@oss.qualcomm.com>

Setting the global_flush_req register to 1 initiates a flush request for
all enabled TPDA input ports. The register remains set until the flush
operation is complete.

Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 .../ABI/testing/sysfs-bus-coresight-devices-tpda   |  8 ++++
 drivers/hwtracing/coresight/coresight-tpda.c       | 45 ++++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-tpda.h       |  2 +
 3 files changed, 55 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
index 735ce0e494da..c8bc7b19ab25 100644
--- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
@@ -33,3 +33,11 @@ Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qu
 Description:
 		(RW) Configure the CMB/MCMB channel mode for all enabled ports.
 		Value 0 means raw channel mapping mode. Value 1 means channel pair marking mode.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/global_flush_req
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Set global (all ports) flush request bit. The bit remains set until a
+		global flush request sequence completes.
diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
index 2186223ad33e..d24a9098f1b1 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.c
+++ b/drivers/hwtracing/coresight/coresight-tpda.c
@@ -341,7 +341,52 @@ static ssize_t tpda_trig_sysfs_store(struct device *dev,
 	return size;
 }
 
+static ssize_t global_flush_req_show(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (!drvdata->csdev->refcnt)
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	val = readl_relaxed(drvdata->base + TPDA_CR);
+	/* read global_flush_req bit */
+	val &= TPDA_CR_FLREQ;
+
+	return sysfs_emit(buf, "%lu\n", val);
+}
+
+static ssize_t global_flush_req_store(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf,
+				      size_t size)
+{
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (kstrtoul(buf, 0, &val))
+		return -EINVAL;
+
+	if (!drvdata->csdev->refcnt || !val)
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	val = readl_relaxed(drvdata->base + TPDA_CR);
+	/* set global_flush_req bit */
+	val |= TPDA_CR_FLREQ;
+	CS_UNLOCK(drvdata->base);
+	writel_relaxed(val, drvdata->base + TPDA_CR);
+	CS_LOCK(drvdata->base);
+
+	return size;
+}
+static DEVICE_ATTR_RW(global_flush_req);
+
 static struct attribute *tpda_attrs[] = {
+	&dev_attr_global_flush_req.attr,
 	tpda_trig_sysfs_rw(freq_ts_enable, FREQTS),
 	tpda_trig_sysfs_rw(trig_freq_enable, FRIE),
 	tpda_trig_sysfs_rw(trig_flag_ts_enable, FLRIE),
diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h
index c93732e04af2..1cc9253293ec 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.h
+++ b/drivers/hwtracing/coresight/coresight-tpda.h
@@ -10,6 +10,8 @@
 #define TPDA_Pn_CR(n)		(0x004 + (n * 4))
 #define TPDA_FPID_CR		(0x084)
 
+/* Cross trigger global (all ports) flush request bit */
+#define TPDA_CR_FLREQ		BIT(0)
 /* Cross trigger FREQ packets timestamp bit */
 #define TPDA_CR_FREQTS		BIT(2)
 /* Cross trigger FREQ packet request bit */

-- 
2.34.1



From jie.gan at oss.qualcomm.com  Tue Dec 23 00:41:47 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Tue, 23 Dec 2025 16:41:47 +0800
Subject: [PATCH v7 3/4] coresight: tpda: add logic to configure TPDA_SYNCR
 register
In-Reply-To: <20251223-add_sysfs_nodes_to_configure_tpda-v7-0-db4e6810047c@oss.qualcomm.com>
References: <20251223-add_sysfs_nodes_to_configure_tpda-v7-0-db4e6810047c@oss.qualcomm.com>
Message-ID: <20251223-add_sysfs_nodes_to_configure_tpda-v7-3-db4e6810047c@oss.qualcomm.com>

From: Tao Zhang <tao.zhang at oss.qualcomm.com>

The TPDA_SYNC counter tracks the number of bytes transferred from the
aggregator. When this count reaches the value programmed in the
TPDA_SYNCR register, an ASYNC request is triggered, allowing userspace
tools to accurately parse each valid packet.

Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
Reviewed-by: James Clark <james.clark at linaro.org>
Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 .../ABI/testing/sysfs-bus-coresight-devices-tpda   | 18 +++++
 drivers/hwtracing/coresight/coresight-tpda.c       | 90 ++++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-tpda.h       | 10 +++
 3 files changed, 118 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
index c8bc7b19ab25..c989eea1ef59 100644
--- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
@@ -41,3 +41,21 @@ Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qu
 Description:
 		(RW) Set global (all ports) flush request bit. The bit remains set until a
 		global flush request sequence completes.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/syncr_mode
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Set mode the of the syncr counter.
+		mode 0 - COUNT[11:0] value represents the approximate number of bytes moved between two ASYNC packet requests
+		mode 1 - the bits COUNT[11:7] are used as a power of 2. for example, we could insert an async packet every 8K
+		         data by writing a value 13 to the COUNT[11:7] field.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/syncr_count
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Set value the of the syncr counter.
+		Range: 0-4095
diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
index d24a9098f1b1..8283e16ec400 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.c
+++ b/drivers/hwtracing/coresight/coresight-tpda.c
@@ -163,6 +163,20 @@ static void tpda_enable_pre_port(struct tpda_drvdata *drvdata)
 	 */
 	if (drvdata->trig_flag_ts)
 		writel_relaxed(0x0, drvdata->base + TPDA_FPID_CR);
+
+	/* Initialize with a value of 0 */
+	val = 0;
+	if (drvdata->syncr_mode)
+		val |= TPDA_SYNCR_MODE_CTRL_MASK;
+
+	if (drvdata->syncr_count > 0 &&
+	    drvdata->syncr_count < TPDA_SYNCR_COUNT_MASK)
+		val |= drvdata->syncr_count;
+	else
+		/* Program the count to its MAX value by default */
+		val |= TPDA_SYNCR_COUNT_MASK;
+
+	writel_relaxed(val, drvdata->base + TPDA_SYNCR);
 }
 
 static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
@@ -385,8 +399,84 @@ static ssize_t global_flush_req_store(struct device *dev,
 }
 static DEVICE_ATTR_RW(global_flush_req);
 
+static ssize_t syncr_mode_show(struct device *dev,
+			       struct device_attribute *attr,
+			       char *buf)
+{
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val, syncr_val;
+
+	if (!drvdata->csdev->refcnt)
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	syncr_val = readl_relaxed(drvdata->base + TPDA_SYNCR);
+	val = FIELD_GET(TPDA_SYNCR_MODE_CTRL_MASK, syncr_val);
+
+	return sysfs_emit(buf, "%lu\n", val);
+}
+
+static ssize_t syncr_mode_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf,
+				size_t size)
+{
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (kstrtoul(buf, 0, &val))
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	/* set the mode when first enabling the device */
+	drvdata->syncr_mode = !!val;
+
+	return size;
+}
+static DEVICE_ATTR_RW(syncr_mode);
+
+static ssize_t syncr_count_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (!drvdata->csdev->refcnt)
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	val = readl_relaxed(drvdata->base + TPDA_SYNCR);
+	val &= TPDA_SYNCR_COUNT_MASK;
+
+	return sysfs_emit(buf, "%lu\n", val);
+}
+
+static ssize_t syncr_count_store(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf,
+				 size_t size)
+{
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (kstrtoul(buf, 0, &val))
+		return -EINVAL;
+
+	if (val < 0 || val > TPDA_SYNCR_COUNT_MASK)
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	drvdata->syncr_count = val;
+
+	return size;
+}
+static DEVICE_ATTR_RW(syncr_count);
+
 static struct attribute *tpda_attrs[] = {
 	&dev_attr_global_flush_req.attr,
+	&dev_attr_syncr_mode.attr,
+	&dev_attr_syncr_count.attr,
 	tpda_trig_sysfs_rw(freq_ts_enable, FREQTS),
 	tpda_trig_sysfs_rw(trig_freq_enable, FRIE),
 	tpda_trig_sysfs_rw(trig_flag_ts_enable, FLRIE),
diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h
index 1cc9253293ec..56d35697303a 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.h
+++ b/drivers/hwtracing/coresight/coresight-tpda.h
@@ -9,6 +9,7 @@
 #define TPDA_CR			(0x000)
 #define TPDA_Pn_CR(n)		(0x004 + (n * 4))
 #define TPDA_FPID_CR		(0x084)
+#define TPDA_SYNCR		(0x08C)
 
 /* Cross trigger global (all ports) flush request bit */
 #define TPDA_CR_FLREQ		BIT(0)
@@ -36,6 +37,11 @@
 /* Aggregator port DSB data set element size bit */
 #define TPDA_Pn_CR_DSBSIZE		BIT(8)
 
+/* TPDA_SYNCR count mask */
+#define TPDA_SYNCR_COUNT_MASK		GENMASK(11, 0)
+/* TPDA_SYNCR mode control bit */
+#define TPDA_SYNCR_MODE_CTRL_MASK	GENMASK(12, 12)
+
 #define TPDA_MAX_INPORTS	32
 
 /**
@@ -52,6 +58,8 @@
  * @trig_freq:	Enable/disable cross trigger FREQ packet request interface.
  * @freq_ts:	Enable/disable the timestamp for all FREQ packets.
  * @cmbchan_mode: Configure the CMB/MCMB channel mode.
+ * @syncr_mode:	Setting the mode for counting packets.
+ * @syncr_count: Setting the value of the count.
  */
 struct tpda_drvdata {
 	void __iomem		*base;
@@ -66,6 +74,8 @@ struct tpda_drvdata {
 	bool			trig_freq;
 	bool			freq_ts;
 	bool			cmbchan_mode;
+	bool			syncr_mode;
+	u32			syncr_count;
 };
 
 /* Enumerate members of global control register(cr) */

-- 
2.34.1



From jie.gan at oss.qualcomm.com  Tue Dec 23 00:41:48 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Tue, 23 Dec 2025 16:41:48 +0800
Subject: [PATCH v7 4/4] coresight: tpda: add sysfs node to flush specific
 port
In-Reply-To: <20251223-add_sysfs_nodes_to_configure_tpda-v7-0-db4e6810047c@oss.qualcomm.com>
References: <20251223-add_sysfs_nodes_to_configure_tpda-v7-0-db4e6810047c@oss.qualcomm.com>
Message-ID: <20251223-add_sysfs_nodes_to_configure_tpda-v7-4-db4e6810047c@oss.qualcomm.com>

From: Tao Zhang <tao.zhang at oss.qualcomm.com>

Setting bit i in the TPDA_FLUSH_CR register initiates a flush request
for port i, forcing the data to synchronize and be transmitted to the
sink device.

Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
Reviewed-by: James Clark <james.clark at linaro.org>
Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 .../ABI/testing/sysfs-bus-coresight-devices-tpda   |  8 +++++
 drivers/hwtracing/coresight/coresight-tpda.c       | 40 ++++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-tpda.h       |  1 +
 3 files changed, 49 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
index c989eea1ef59..48b8fda1b796 100644
--- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
@@ -59,3 +59,11 @@ Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qu
 Description:
 		(RW) Set value the of the syncr counter.
 		Range: 0-4095
+
+What:		/sys/bus/coresight/devices/<tpda-name>/port_flush_req
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Configure the bit i to requests a flush operation of port i on the TPDA.
+		The requested bit(s) remain set until the flush request completes.
diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
index 8283e16ec400..412c35decc8e 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.c
+++ b/drivers/hwtracing/coresight/coresight-tpda.c
@@ -473,10 +473,50 @@ static ssize_t syncr_count_store(struct device *dev,
 }
 static DEVICE_ATTR_RW(syncr_count);
 
+static ssize_t port_flush_req_show(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (!drvdata->csdev->refcnt)
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	val = readl_relaxed(drvdata->base + TPDA_FLUSH_CR);
+
+	return sysfs_emit(buf, "0x%lx\n", val);
+}
+
+static ssize_t port_flush_req_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf,
+				    size_t size)
+{
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	u32 val;
+
+	if (kstrtou32(buf, 0, &val))
+		return -EINVAL;
+
+	if (!drvdata->csdev->refcnt || !val)
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	CS_UNLOCK(drvdata->base);
+	writel_relaxed(val, drvdata->base + TPDA_FLUSH_CR);
+	CS_LOCK(drvdata->base);
+
+	return size;
+}
+static DEVICE_ATTR_RW(port_flush_req);
+
 static struct attribute *tpda_attrs[] = {
 	&dev_attr_global_flush_req.attr,
 	&dev_attr_syncr_mode.attr,
 	&dev_attr_syncr_count.attr,
+	&dev_attr_port_flush_req.attr,
 	tpda_trig_sysfs_rw(freq_ts_enable, FREQTS),
 	tpda_trig_sysfs_rw(trig_freq_enable, FRIE),
 	tpda_trig_sysfs_rw(trig_flag_ts_enable, FLRIE),
diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h
index 56d35697303a..a090352009bb 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.h
+++ b/drivers/hwtracing/coresight/coresight-tpda.h
@@ -10,6 +10,7 @@
 #define TPDA_Pn_CR(n)		(0x004 + (n * 4))
 #define TPDA_FPID_CR		(0x084)
 #define TPDA_SYNCR		(0x08C)
+#define TPDA_FLUSH_CR		(0x090)
 
 /* Cross trigger global (all ports) flush request bit */
 #define TPDA_CR_FLREQ		BIT(0)

-- 
2.34.1



From anshuld at ti.com  Tue Dec 23 00:44:16 2025
From: anshuld at ti.com (Anshul Dalal)
Date: Tue, 23 Dec 2025 14:14:16 +0530
Subject: [PATCH v6] dt-bindings: arm: keystone: add boot_* mboxes to
 ti,sci
In-Reply-To: <1844147d-543d-4739-a1ec-a59f8a4564fb@kernel.org>
References: <20251222-k3_syscon_add_boot_mailboxes-v6-1-b93ada9f1d47@ti.com>
 <1844147d-543d-4739-a1ec-a59f8a4564fb@kernel.org>
Message-ID: <DF5GPF5U7NPA.2ODE22YOF8E1R@ti.com>

On Mon Dec 22, 2025 at 2:23 PM IST, Krzysztof Kozlowski wrote:
> On 22/12/2025 09:43, Anshul Dalal wrote:
>> The bootloader on K3 devices makes use of mailboxes as per the ROM spec
>> which might be different than one's available to the kernel (firmware
>> spec).
>> 
>> Therefore, this patch adds the missing mailbox entries to the DT binding
>> if the matching compatible is ti,am654-sci to represent the mailboxes
>> exposed by the hardware during boot for the purpose of loading the
>> firmware.
>> 
>> The new ti,am642-sci compatible is also added to represent SoCs which do
>> not expose a "notify" channel as part of their TI-SCI spec such as AM64x
>> or the AM62 family. The newly added mboxes are made optional by keeping
>> minItems as 2 to remain compliant with existing device-trees.
>> 
>> Signed-off-by: Anshul Dalal <anshuld at ti.com>
>> ---
>> Changes in v6:
>> - Added ti,am642-sci compatible to represent SoCs without a "notify" channel
>> - Added new examples instead of editing existing ones
>
> Why? Rob asked not to.

I had followed what Nishanth had said[1], I'll wait for him and Rob to
align first before posting the next revision.

[1]: https://lore.kernel.org/linux-devicetree/20251218190449.cnp46cf6hikt6cqa at freebie/

>
>> - Link to v5: https://lore.kernel.org/r/20251215-k3_syscon_add_boot_mailboxes-v5-1-5a8fe567fd31 at ti.com
>> 
>> Changes in v5:
>> - Added commit description for the optional mailboxes
>> - Link to v4: https://lore.kernel.org/r/20251205-k3_syscon_add_boot_mailboxes-v4-1-8e216fb88941 at ti.com
>> 
>> Changes in v4:
>> - Make new boot_* mboxes conditional on ti,am654-sci compatible
>> - Link to v3: https://lore.kernel.org/r/20251112-k3_syscon_add_boot_mailboxes-v3-1-66155a4236dc at ti.com
>> 
>> Changes in v3:
>> - Drop [1/2] of the last patch series
>> - Update existing example with boot_* mailboxes instead of adding a new one
>> - Link to v2: https://lore.kernel.org/r/20251112-k3_syscon_add_boot_mailboxes-v2-0-aebc1e47b391 at ti.com
>> 
>> Changes in v2:
>> - Remove maxItems entry
>> - Remove RFC tag from patch (added by mistake in v1)
>> - Document the new mailboxes in mboxes instead of mbox-names
>> - Provide example with all the mailboxes set
>> - Update commit title to have "ti,sci"
>> - Split into two patches
>> - Link to v1: https://lore.kernel.org/r/20251111-k3_syscon_add_boot_mailboxes-v1-1-529a27f21076 at ti.com
>> ---
>>  .../devicetree/bindings/arm/keystone/ti,sci.yaml   | 94 +++++++++++++++++++++-
>>  1 file changed, 91 insertions(+), 3 deletions(-)
>> 
>> diff --git a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
>> index 25a2b42105e5..0f2c764eae5a 100644
>> --- a/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
>> +++ b/Documentation/devicetree/bindings/arm/keystone/ti,sci.yaml
>> @@ -40,6 +40,9 @@ properties:
>>        - description: System controller on TI AM654 SoC
>>          items:
>>            - const: ti,am654-sci
>> +      - description: System controller on TI AM642 SoC
>> +        items:
>> +          - const: ti,am642-sci
>
> Why this is not part of enum with previous entries like that?

Yes, I missed adding it. Will fixed in the next revision if the
compatible is still required.

>
>>  
>>    reg-names:
>>      description: |
>> @@ -51,15 +54,15 @@ properties:
>>      minItems: 1
>>  
>>    mbox-names:
>> +    minItems: 2
>> +    maxItems: 6
>>      description: |
>>        Specifies the mailboxes used to communicate with TI-SCI Controller
>>        made available from TI-SCI controller.
>> -    items:
>> -      - const: rx
>> -      - const: tx
>>  
>>    mboxes:
>>      minItems: 2
>> +    maxItems: 6
>>  
>>    ti,host-id:
>>      $ref: /schemas/types.yaml#/definitions/uint32
>> @@ -79,6 +82,66 @@ properties:
>>      type: object
>>      $ref: /schemas/reset/ti,sci-reset.yaml#
>>  
>> +if:
>> +  properties:
>> +    compatible:
>> +      contains:
>> +        const: ti,am654-sci
>> +then:
>> +  properties:
>> +    mbox-names:
>> +      minItems: 2
>> +      items:
>> +        - const: rx
>> +        - const: tx
>> +        - const: notify
>
> Move the notify to the end, so you have only one common list defined at
> the top and you only change number of items per variant.
>
>> +        - const: boot_rx
>> +        - const: boot_tx
>> +        - const: boot_notify
>> +    mboxes:
>> +      minItems: 2
>> +      items:
>> +        - description: RX thread
>> +        - description: TX thread
>> +        - description: Notify thread
>> +        - description: boot stage RX thread
>> +        - description: boot stage TX thread
>> +        - description: boot stage Notify thread
>> +else:
>> +  if:
>
> No, that's not readable. Don't nest these.
>

I agree, perhaps we should drop the new ti,am642-sci compatible and just
reorder the list for ti,am654-sci to: rx, tx, boot_rx, boot_tx,
notify, boot_notify with a minItems of 2 as Nishanth had suggested?

>> +    properties:
>> +      compatible:
>> +        contains:
>> +          const: ti,am642-sci
>> +  then:
>> +    properties:
>> +      mbox-names:
>> +        minItems: 2
>> +        items:
>> +          - const: rx
>> +          - const: tx
>> +          - const: boot_rx
>> +          - const: boot_tx
>> +          - const: boot_notify
>> +      mboxes:
>> +        minItems: 2
>> +        items:
>> +          - description: RX thread
>> +          - description: TX thread
>> +          - description: boot stage RX thread
>> +          - description: boot stage TX thread
>> +          - description: boot stage Notify thread
>> +  else:
>> +    properties:
>> +      mbox-names:
>> +        items:
>> +          - const: rx
>> +          - const: tx
>> +      mboxes:
>> +        items:
>> +          - description: RX thread
>> +          - description: TX thread
>> +
>>  required:
>>    - compatible
>>    - mbox-names
>> @@ -122,3 +185,28 @@ examples:
>>          #reset-cells = <2>;
>>        };
>>      };
>> +
>> +  - |
>> +    system-controller at 44083000 {
>> +      compatible = "ti,am654-sci";
>> +      ti,host-id = <4>;
>> +      mbox-names = "rx", "tx", "notify", "boot_rx", "boot_tx";
>> +      mboxes = <&secure_proxy_mcu 6>, <&secure_proxy_mcu 8>,
>> +        <&secure_proxy_mcu 5>, <&secure_proxy_mcu 5>, <&secure_proxy_mcu 4>;
>> +
>> +      reg-names = "debug_messages";
>> +      reg = <0x44083000 0x1000>;
>> +    };
>
> You already have there two examples. You do not need three and for sure
> you do not need four of which two are exactly the same. Rob already
> commented on this.

I can edit the existing example instead if Rob and Nishanth are aligned.

Regards,
Anshul


From lkp at intel.com  Tue Dec 23 00:49:19 2025
From: lkp at intel.com (kernel test robot)
Date: Tue, 23 Dec 2025 16:49:19 +0800
Subject: [arm-platforms:kvm-arm64/gicv5-full 59/82]
 arch/arm64/kvm/vgic/vgic-irs-v5.c:784:24: warning: variable 'ist_l2sz' is
 uninitialized when used here
Message-ID: <202512231615.mYXXEOUa-lkp@intel.com>

tree:   https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git kvm-arm64/gicv5-full
head:   1426b88096b597395df4c82f089b87c62bab45da
commit: e19948af6683f38c4f8634a3ee7e30347e481aa9 [59/82] KVM: arm64: gic-v5: Add GICv5 IRS IODEV
config: arm64-allmodconfig (https://download.01.org/0day-ci/archive/20251223/202512231615.mYXXEOUa-lkp at intel.com/config)
compiler: clang version 19.1.7 (https://github.com/llvm/llvm-project cd708029e0b2869e80abe31ddb175f7c35361f90)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251223/202512231615.mYXXEOUa-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512231615.mYXXEOUa-lkp at intel.com/

All warnings (new ones prefixed by >>):

   arch/arm64/kvm/vgic/vgic-irs-v5.c:675:5: warning: no previous prototype for function 'vgic_v5_register_irs_iodev' [-Wmissing-prototypes]
     675 | int vgic_v5_register_irs_iodev(struct kvm *kvm, gpa_t irs_base_address)
         |     ^
   arch/arm64/kvm/vgic/vgic-irs-v5.c:675:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
     675 | int vgic_v5_register_irs_iodev(struct kvm *kvm, gpa_t irs_base_address)
         | ^
         | static 
>> arch/arm64/kvm/vgic/vgic-irs-v5.c:784:24: warning: variable 'ist_l2sz' is uninitialized when used here [-Wuninitialized]
     784 |                                              nr_spi_bits, ist_l2sz, istsz,
         |                                                           ^~~~~~~~
   arch/arm64/kvm/vgic/vgic-irs-v5.c:712:47: note: initialize the variable 'ist_l2sz' to silence this warning
     712 |         size_t istsz, nr_spi_bits, istmd_sz, ist_l2sz;
         |                                                      ^
         |                                                       = 0
   2 warnings generated.


vim +/ist_l2sz +784 arch/arm64/kvm/vgic/vgic-irs-v5.c

   699	
   700	/**
   701	 * kvm_vgic_v5_irs_init: initialize the IRS data structures
   702	 * @kvm: kvm struct pointer
   703	 * @nr_spis: number of spis, frozen by caller
   704	 */
   705	int kvm_vgic_v5_irs_init(struct kvm *kvm, unsigned int nr_spis)
   706	{
   707		struct vgic_dist *dist = &kvm->arch.vgic;
   708		struct vgic_v5_irs *irs = dist->vgic_v5_irs_data;
   709		struct kvm_vcpu *vcpu0 = kvm_get_vcpu(kvm, 0);
   710		int i;
   711		phys_addr_t spi_ist_phys_base;
   712		size_t istsz, nr_spi_bits, istmd_sz, ist_l2sz;
   713		u64 mmfr0;
   714		int ret = 0;
   715	
   716		INIT_LIST_HEAD(&dist->vgic_v5_spi_ap_list_head);
   717		raw_spin_lock_init(&dist->vgic_v5_spi_ap_list_lock);
   718	
   719		/*
   720		 * We (KVM) allocate an Interrupt State Table (IST) for SPIs. The
   721		 * hardware mandates that lower 6 bits of the address are 0. Each ISTE
   722		 * is 4 bytes in size (or larger if metadata storage is required). In
   723		 * order to simplify the allocation logic, we round up the minimum
   724		 * number of SPIs to 16 (2^6 = 64, 64/4 = 16).
   725		 */
   726		if (nr_spis && nr_spis < 16)
   727			nr_spis = 16;
   728	
   729		if (nr_spis) {
   730			dist->spis = kcalloc(nr_spis, sizeof(struct vgic_irq),
   731					     GFP_KERNEL_ACCOUNT);
   732			if (!dist->spis)
   733				return -ENOMEM;
   734	
   735			/*
   736			 * In the following code we do not take the irq struct lock since
   737			 * no other action on irq structs can happen while the VGIC is
   738			 * not initialized yet:
   739			 * If someone wants to inject an interrupt or does a MMIO access,
   740			 * we require prior initialization in case of a virtual GICv3.
   741			 */
   742			for (i = 0; i < nr_spis; i++) {
   743				struct vgic_irq *irq = &dist->spis[i];
   744	
   745				/*
   746				 * We use the full GICv5-style IntID here, rather than
   747				 * just the index of the SPI. This helps to correctly
   748				 * identify the interrupt when injecting it.
   749				 */
   750				irq->intid = i | FIELD_PREP(GICV5_HWIRQ_TYPE,
   751							    GICV5_HWIRQ_TYPE_SPI);
   752				INIT_LIST_HEAD(&irq->ap_list);
   753				raw_spin_lock_init(&irq->irq_lock);
   754				irq->vcpu = NULL;
   755				irq->target_vcpu = vcpu0;
   756				refcount_set(&irq->refcount, 0);
   757				/*
   758				 * The guest controls the enable state, and again it is
   759				 * directly handled by the hardware. From our point of
   760				 * view it is always enabled.
   761				 */
   762				irq->enabled = 1;
   763				vgic_v5_set_spi_ops(irq);
   764			}
   765	
   766			nr_spi_bits = fls(roundup_pow_of_two(nr_spis)) - 1;
   767	
   768			istsz = GICV5_IRS_IST_CFGR_ISTSZ_4;
   769			if (vgic_v5_host_caps()->istmd) {
   770				istmd_sz = vgic_v5_host_caps()->istmd_sz;
   771	
   772				if (nr_spi_bits < istmd_sz)
   773					istsz = GICV5_IRS_IST_CFGR_ISTSZ_8;
   774				else
   775					istsz = GICV5_IRS_IST_CFGR_ISTSZ_16;
   776			}
   777	
   778			ret = vgic_v5_spi_ist_allocate(kvm, &spi_ist_phys_base,
   779						      nr_spi_bits, istsz);
   780			if (ret)
   781				return ret;
   782	
   783			ret = vgic_v5_vmte_assign_ist(kvm, spi_ist_phys_base, false,
 > 784						     nr_spi_bits, ist_l2sz, istsz,

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From jbrunet at baylibre.com  Tue Dec 23 00:59:05 2025
From: jbrunet at baylibre.com (Jerome Brunet)
Date: Tue, 23 Dec 2025 09:59:05 +0100
Subject: [PATCH v4 1/8] dt-bindings: clock: Add Amlogic A5 SCMI clock
 controller support
In-Reply-To: <20251028-a5-clk-v4-1-e62ca0aae243@amlogic.com> (Chuan Liu via's
	message of "Tue, 28 Oct 2025 17:52:27 +0800")
References: <20251028-a5-clk-v4-0-e62ca0aae243@amlogic.com>
	<20251028-a5-clk-v4-1-e62ca0aae243@amlogic.com>
Message-ID: <1jv7hx7ew6.fsf@starbuckisacylon.baylibre.com>

On Tue 28 Oct 2025 at 17:52, Chuan Liu via B4 Relay <devnull+chuan.liu.amlogic.com at kernel.org> wrote:

> From: Chuan Liu <chuan.liu at amlogic.com>
>
> Add the SCMI clock controller dt-bindings for the Amlogic A5 SoC
> family.
>
> Signed-off-by: Chuan Liu <chuan.liu at amlogic.com>
> Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
> Signed-off-by: Xianwei Zhao <xianwei.zhao at amlogic.com>

Please read:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/submitting-patches.rst?h=v6.19-rc1#n503

and adjust your patches accordingly

> ---
>  include/dt-bindings/clock/amlogic,a5-scmi-clkc.h | 44 ++++++++++++++++++++++++
>  1 file changed, 44 insertions(+)
>
> diff --git a/include/dt-bindings/clock/amlogic,a5-scmi-clkc.h b/include/dt-bindings/clock/amlogic,a5-scmi-clkc.h
> new file mode 100644
> index 000000000000..1bf027d0110a
> --- /dev/null
> +++ b/include/dt-bindings/clock/amlogic,a5-scmi-clkc.h
> @@ -0,0 +1,44 @@
> +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
> +/*
> + * Copyright (c) 2024 Amlogic, Inc. All rights reserved.
> + * Author: Chuan Liu <chuan.liu at amlogic.com>
> + */
> +
> +#ifndef __AMLOGIC_A5_SCMI_CLKC_H
> +#define __AMLOGIC_A5_SCMI_CLKC_H
> +
> +#define CLKID_OSC				0
> +#define CLKID_SYS_CLK				1
> +#define CLKID_AXI_CLK				2
> +#define CLKID_CPU_CLK				3
> +#define CLKID_DSU_CLK				4
> +#define CLKID_GP1_PLL				5
> +#define CLKID_FIXED_PLL_DCO			6
> +#define CLKID_FIXED_PLL				7
> +#define CLKID_ACLKM				8
> +#define CLKID_SYS_PLL_DIV16			9
> +#define CLKID_CPU_CLK_DIV16			10
> +#define CLKID_FCLK_50M_PREDIV			11
> +#define CLKID_FCLK_50M_DIV			12
> +#define CLKID_FCLK_50M				13
> +#define CLKID_FCLK_DIV2_DIV			14
> +#define CLKID_FCLK_DIV2				15
> +#define CLKID_FCLK_DIV2P5_DIV			16
> +#define CLKID_FCLK_DIV2P5			17
> +#define CLKID_FCLK_DIV3_DIV			18
> +#define CLKID_FCLK_DIV3				19
> +#define CLKID_FCLK_DIV4_DIV			20
> +#define CLKID_FCLK_DIV4				21
> +#define CLKID_FCLK_DIV5_DIV			22
> +#define CLKID_FCLK_DIV5				23
> +#define CLKID_FCLK_DIV7_DIV			24
> +#define CLKID_FCLK_DIV7				25
> +#define CLKID_SYS_MMC_PCLK			26
> +#define CLKID_SYS_CPU_CTRL			27
> +#define CLKID_SYS_IRQ_CTRL			28
> +#define CLKID_SYS_GIC				29
> +#define CLKID_SYS_BIG_NIC			30
> +#define CLKID_AXI_SYS_NIC			31
> +#define CLKID_AXI_CPU_DMC			32
> +
> +#endif /* __AMLOGIC_A5_SCMI_CLKC_H */

-- 
Jerome


From Ankit.Soni at amd.com  Tue Dec 23 00:59:15 2025
From: Ankit.Soni at amd.com (Ankit Soni)
Date: Tue, 23 Dec 2025 08:59:15 +0000
Subject: possible deadlock due to irq_set_thread_affinity() calling into
 the scheduler (was Re: [PATCH v3 38/62] KVM: SVM: Take and hold ir_list_lock
 across IRTE updates in IOMMU)
In-Reply-To: <42513cb3-3c2e-4aa8-b748-23b6656a5096@redhat.com>
References: <20250611224604.313496-2-seanjc@google.com>
 <20250611224604.313496-40-seanjc@google.com>
 <njhjud3e6wbdftzr3ziyuh5bhyvc5ndt5qvmg7rlvh5isoop2l@f2uxctws2c7d>
 <42513cb3-3c2e-4aa8-b748-23b6656a5096@redhat.com>
Message-ID: <flitmw3b2imbpbyhygaushwt4h6k3fa5l2ebdfkl7knw5ghvod@ioqe2bsvq6vz>

On Mon, Dec 22, 2025 at 03:09:13PM +0100, Paolo Bonzini wrote:
> On 12/22/25 10:16, Ankit Soni wrote:
> >    ======================================================
> >    WARNING: possible circular locking dependency detected
> >    6.19.0-rc2 #20 Tainted: G            E
> >    ------------------------------------------------------
> >    CPU 58/KVM/28597 is trying to acquire lock:
> >      ff12c47d4b1f34c0 (&irq_desc_lock_class){-.-.}-{2:2}, at: __irq_get_desc_lock+0x58/0xa0
> > 
> >      but task is already holding lock:
> >      ff12c49b28552110 (&svm->ir_list_lock){....}-{2:2}, at: avic_pi_update_irte+0x147/0x270 [kvm_amd]
> > 
> >      which lock already depends on the new lock.
> > 
> >    Chain exists of:
> >      &irq_desc_lock_class --> &rq->__lock --> &svm->ir_list_lock
> > 
> >    Possible unsafe locking scenario:
> > 
> >          CPU0                            CPU1
> >          ----                            ----
> >     lock(&svm->ir_list_lock);
> >                                        lock(&rq->__lock);
> >                                        lock(&svm->ir_list_lock);
> >     lock(&irq_desc_lock_class);
> > 
> >          *** DEADLOCK ***
> > 
> > So lockdep sees:
> > 
> >    &irq_desc_lock_class -> &rq->__lock -> &svm->ir_list_lock
> > 
> > while avic_pi_update_irte() currently holds svm->ir_list_lock and then
> > takes irq_desc_lock via irq_set_vcpu_affinity(), which creates the
> > potential inversion.
> > 
> >    - Is this lockdep warning expected/benign in this code path, or does it
> >      indicate a real potential deadlock between svm->ir_list_lock and
> >      irq_desc_lock with AVIC + irq_bypass + VFIO?
> 
> I'd treat it as a potential (if unlikely) deadlock:
> 
> (a) irq_set_thread_affinity triggers the scheduler via wake_up_process,
> while irq_desc->lock is taken
> 
> (b) the scheduler calls into KVM with rq_lock taken, and KVM uses
> ir_list_lock within __avic_vcpu_load/__avic_vcpu_put
> 
> (c) KVM wants to block scheduling for a while and uses ir_list_lock for
> that purpose, but then takes irq_set_vcpu_affinity takes irq_desc->lock.
> 
> I don't think there's an alternative choice of lock for (c); and there's
> no easy way to pull the irq_desc->lock out of the IRQ subsystem--in fact
> the stickiness of the situation comes from rq->rq_lock and
> irq_desc->lock being both internal and not leaf.
> 
> Of the three, the most sketchy is (a); notably, __setup_irq() calls
> wake_up_process outside desc->lock.  Therefore I'd like so much to treat
> it as a kernel/irq/ bug; and the simplest (perhaps too simple...) fix is
> to drop the wake_up_process().  The only cost is extra latency on the
> next interrupt after an affinity change.
> 
> diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
> index 8b1b4c8a4f54..fc135bd079a4 100644
> --- a/kernel/irq/manage.c
> +++ b/kernel/irq/manage.c
> @@ -189,14 +189,10 @@ static void irq_set_thread_affinity(struct irq_desc *desc)
>  	struct irqaction *action;
>  	for_each_action_of_desc(desc, action) {
> -		if (action->thread) {
> +		if (action->thread)
>  			set_bit(IRQTF_AFFINITY, &action->thread_flags);
> -			wake_up_process(action->thread);
> -		}
> -		if (action->secondary && action->secondary->thread) {
> +		if (action->secondary && action->secondary->thread)
>  			set_bit(IRQTF_AFFINITY, &action->secondary->thread_flags);
> -			wake_up_process(action->secondary->thread);
> -		}
>  	}
>  }
> Marc, what do you think?
> 
> Paolo
> 

Hi Paolo,
With the above patch I?m still seeing the same circular dependency warning.
However, and with Sean?s patch I?m not seeing any warnings.

[  335.128640] ======================================================
[  335.128650] WARNING: possible circular locking dependency detected
[  335.128660] 6.19.0-rc2-dirty #21 Tainted: G            E
[  335.128668] ------------------------------------------------------
[  335.128675] CPU 96/KVM/28699 is trying to acquire lock:
[  335.128682] ff453c6b59bb18c0 (&irq_desc_lock_class){-.-.}-{2:2}, at: __irq_get_desc_lock+0x58/0xa0
[  335.128704]
               but task is already holding lock:
[  335.128712] ff453c8b0946e600 (&svm->ir_list_lock){....}-{2:2}, at: avic_pi_update_irte+0x147/0x270 [kvm_amd]
[  335.128732]
               which lock already depends on the new lock.

[  335.128742]
               the existing dependency chain (in reverse order) is:
[  335.128751]
               -> #4 (&svm->ir_list_lock){....}-{2:2}:
[  335.128760]        _raw_spin_lock_irqsave+0x4e/0xb0
[  335.128772]        __avic_vcpu_put+0x7a/0x150 [kvm_amd]
[  335.128783]        avic_vcpu_put+0x50/0x70 [kvm_amd]
[  335.128791]        svm_vcpu_put+0x38/0x70 [kvm_amd]
[  335.128800]        kvm_arch_vcpu_put+0x21b/0x330 [kvm]
[  335.128854]        kvm_sched_out+0x62/0x90 [kvm]
[  335.128893]        __schedule+0x8d3/0x1d10
[  335.128901]        __cond_resched+0x5c/0x80
[  335.128909]        __kmalloc_cache_noprof+0x3d7/0x730
[  335.128920]        kvm_hv_vcpu_init+0x48/0x260 [kvm]
[  335.128957]        kvm_hv_set_msr_common+0x5b/0x12a0 [kvm]
[  335.128988]        kvm_set_msr_common+0x468/0x1310 [kvm]
[  335.129019]        svm_set_msr+0x645/0x730 [kvm_amd]
[  335.129028]        __kvm_set_msr+0xa3/0x2f0 [kvm]
[  335.129066]        kvm_set_msr_ignored_check+0x23/0x1b0 [kvm]
[  335.129096]        do_set_msr+0x76/0xd0 [kvm]
[  335.129126]        msr_io+0xbe/0x1c0 [kvm]
[  335.129152]        kvm_arch_vcpu_ioctl+0x700/0x2090 [kvm]
[  335.129181]        kvm_vcpu_ioctl+0x632/0xc60 [kvm]
[  335.129215]        __x64_sys_ioctl+0xa5/0x100
[  335.129224]        x64_sys_call+0x1243/0x26b0
[  335.129234]        do_syscall_64+0x93/0x1470
[  335.129242]        entry_SYSCALL_64_after_hwframe+0x76/0x7e
[  335.129251]
               -> #3 (&rq->__lock){-.-.}-{2:2}:
[  335.129259]        _raw_spin_lock_nested+0x32/0x80
[  335.129267]        raw_spin_rq_lock_nested+0x22/0xa0
[  335.129276]        task_rq_lock+0x5f/0x150
[  335.129392]        cgroup_move_task+0x46/0x110
[  335.129494]        css_set_move_task+0xe1/0x240
[  335.129614]        cgroup_post_fork+0x98/0x2d0
[  335.129704]        copy_process+0x1ea8/0x2330
[  335.129795]        kernel_clone+0xa7/0x440
[  335.129883]        user_mode_thread+0x63/0x90
[  335.129970]        rest_init+0x28/0x200
[  335.130056]        start_kernel+0xae0/0xcd0
[  335.130144]        x86_64_start_reservations+0x18/0x30
[  335.130230]        x86_64_start_kernel+0xfd/0x150
[  335.130312]        common_startup_64+0x13e/0x141
[  335.130396]
               -> #2 (&p->pi_lock){-.-.}-{2:2}:
[  335.130554]        _raw_spin_lock_irqsave+0x4e/0xb0
[  335.130631]        try_to_wake_up+0x59/0xaa0
[  335.130709]        wake_up_process+0x15/0x30
[  335.130785]        create_worker+0x154/0x250
[  335.130862]        workqueue_init+0x414/0x760
[  335.130938]        kernel_init_freeable+0x24f/0x630
[  335.131013]        kernel_init+0x1b/0x200
[  335.131086]        ret_from_fork+0x344/0x3a0
[  335.131161]        ret_from_fork_asm+0x1a/0x30
[  335.131235]
               -> #1 (&pool->lock){-.-.}-{2:2}:
[  335.131375]        _raw_spin_lock+0x34/0x80
[  335.131448]        __queue_work+0xf4/0x740
[  335.131523]        queue_work_on+0x70/0xd0
[  335.131595]        irq_set_affinity_locked+0x13b/0x250
[  335.131669]        __irq_apply_affinity_hint+0xf8/0x120
[  335.131742]        mlx5_irq_alloc+0x28e/0x4e0 [mlx5_core]
[  335.131884]        mlx5_irq_request+0x125/0x140 [mlx5_core]
[  335.131997]        mlx5_irq_request_vector+0xb4/0x110 [mlx5_core]
[  335.132107]        comp_irq_request_pci+0x68/0xf0 [mlx5_core]
[  335.132219]        mlx5_comp_eqn_get+0x127/0x850 [mlx5_core]
[  335.132327]        mlx5e_create_cq+0x58/0x260 [mlx5_core]
[  335.132452]        mlx5e_open_drop_rq+0x11c/0x220 [mlx5_core]
[  335.132573]        mlx5e_init_nic_rx+0x2c/0x270 [mlx5_core]
[  335.132687]        mlx5e_attach_netdev+0xed/0x340 [mlx5_core]
[  335.132794]        _mlx5e_resume+0x6a/0xd0 [mlx5_core]
[  335.132900]        mlx5e_probe+0x5e3/0xa50 [mlx5_core]
[  335.133010]        auxiliary_bus_probe+0x45/0x90
[  335.133086]        really_probe+0xf1/0x410
[  335.133160]        __driver_probe_device+0x8c/0x190
[  335.133233]        driver_probe_device+0x24/0xd0
[  335.133305]        __device_attach_driver+0xcd/0x170
[  335.133377]        bus_for_each_drv+0x99/0x100
[  335.133450]        __device_attach+0xba/0x1f0
[  335.133523]        device_initial_probe+0x4e/0x50
[  335.133595]        bus_probe_device+0x3c/0xa0
[  335.133668]        device_add+0x6af/0x8a0
[  335.133740]        __auxiliary_device_add+0x43/0xc0
[  335.133813]        add_adev+0xd3/0x160 [mlx5_core]
[  335.133931]        mlx5_rescan_drivers_locked+0x1ee/0x340 [mlx5_core]
[  335.134045]        mlx5_register_device+0x37/0xb0 [mlx5_core]
[  335.134156]        mlx5_init_one_devl_locked+0x43e/0x710 [mlx5_core]
[  335.134267]        probe_one+0x35b/0x530 [mlx5_core]
[  335.134382]        local_pci_probe+0x47/0xb0
[  335.134460]        work_for_cpu_fn+0x1a/0x30
[  335.134538]        process_one_work+0x22b/0x6f0
[  335.134613]        worker_thread+0x1c6/0x3b0
[  335.134687]        kthread+0x110/0x230
[  335.134764]        ret_from_fork+0x344/0x3a0
[  335.134838]        ret_from_fork_asm+0x1a/0x30
[  335.134913]
               -> #0 (&irq_desc_lock_class){-.-.}-{2:2}:
[  335.135059]        __lock_acquire+0x1595/0x2640
[  335.135135]        lock_acquire+0xc4/0x2c0
[  335.135210]        _raw_spin_lock_irqsave+0x4e/0xb0
[  335.135286]        __irq_get_desc_lock+0x58/0xa0
[  335.135362]        irq_set_vcpu_affinity+0x4a/0x100
[  335.135438]        avic_pi_update_irte+0x170/0x270 [kvm_amd]
[  335.135521]        kvm_pi_update_irte+0xea/0x220 [kvm]
[  335.135633]        kvm_arch_irq_bypass_add_producer+0x9b/0xb0 [kvm]
[  335.135737]        __connect+0x5f/0x100 [irqbypass]
[  335.135815]        irq_bypass_register_producer+0xe4/0xb90 [irqbypass]
[  335.135895]        vfio_msi_set_vector_signal+0x1b0/0x330 [vfio_pci_core]
[  335.135979]        vfio_msi_set_block+0x5a/0xd0 [vfio_pci_core]
[  335.136060]        vfio_pci_set_msi_trigger+0x19e/0x260 [vfio_pci_core]
[  335.136142]        vfio_pci_set_irqs_ioctl+0x46/0x140 [vfio_pci_core]
[  335.136224]        vfio_pci_core_ioctl+0x6ea/0xc20 [vfio_pci_core]
[  335.136306]        vfio_device_fops_unl_ioctl+0xb1/0x9d0 [vfio]
[  335.136390]        __x64_sys_ioctl+0xa5/0x100
[  335.136470]        x64_sys_call+0x1243/0x26b0
[  335.136553]        do_syscall_64+0x93/0x1470
[  335.136632]        entry_SYSCALL_64_after_hwframe+0x76/0x7e
[  335.136712]
               other info that might help us debug this:

[  335.136942] Chain exists of:
                 &irq_desc_lock_class --> &rq->__lock --> &svm->ir_list_lock

[  335.137178]  Possible unsafe locking scenario:

[  335.137340]        CPU0                    CPU1
[  335.137420]        ----                    ----
[  335.137502]   lock(&svm->ir_list_lock);
[  335.137582]                                lock(&rq->__lock);
[  335.137664]                                lock(&svm->ir_list_lock);
[  335.137746]   lock(&irq_desc_lock_class);
[  335.137826]
                *** DEADLOCK ***

[  335.138057] 4 locks held by CPU 96/KVM/28699:
[  335.138136]  #0: ff453c6c28bae800 (&vdev->igate){+.+.}-{4:4}, at: vfio_pci_core_ioctl+0x6d2/0xc20 [vfio_pci_core]
[  335.138223]  #1: ffffffffc0faf110 (lock#10){+.+.}-{4:4}, at: irq_bypass_register_producer+0x31/0xb90 [irqbypass]
[  335.138310]  #2: ff453c8b11179478 (&kvm->irqfds.lock){....}-{3:3}, at: kvm_arch_irq_bypass_add_producer+0x2d/0xb0 [kvm]
[  335.138423]  #3: ff453c8b0946e600 (&svm->ir_list_lock){....}-{2:2}, at: avic_pi_update_irte+0x147/0x270 [kvm_amd]

-Ankit


From haibo.chen at nxp.com  Tue Dec 23 01:05:55 2025
From: haibo.chen at nxp.com (Haibo Chen)
Date: Tue, 23 Dec 2025 17:05:55 +0800
Subject: [PATCH 0/2] Add xspi device node and mt35xu512aba spi nor device
 support on imx943-evk board
Message-ID: <20251223-imx943-xspi-dts-v1-0-7c18e5b4f97a@nxp.com>

xspi is a new flexible SPI host controller in imx94. The driver
already merged into linux-next, refer to the following link:

https://lore.kernel.org/r/20251216-xspi-v7-0-282525220979 at nxp.com

The first patch add the xspi device node in imx94.dtsi.
Second patch add mt35xu512aba spi support on imx943-evk board.

Signed-off-by: Haibo Chen <haibo.chen at nxp.com>
---
Haibo Chen (2):
      arm64: dts: imx94: add xspi device node
      arm64: dts: imx94: add mt35xu512aba spi nor support

 arch/arm64/boot/dts/freescale/imx94.dtsi     | 34 +++++++++++++++++++++++++++-
 arch/arm64/boot/dts/freescale/imx943-evk.dts | 34 ++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+), 1 deletion(-)
---
base-commit: cc3aa43b44bdb43dfbac0fcb51c56594a11338a8
change-id: 20251223-imx943-xspi-dts-68da1c32534e

Best regards,
-- 
Haibo Chen <haibo.chen at nxp.com>



From haibo.chen at nxp.com  Tue Dec 23 01:05:56 2025
From: haibo.chen at nxp.com (Haibo Chen)
Date: Tue, 23 Dec 2025 17:05:56 +0800
Subject: [PATCH 1/2] arm64: dts: imx94: add xspi device node
In-Reply-To: <20251223-imx943-xspi-dts-v1-0-7c18e5b4f97a@nxp.com>
References: <20251223-imx943-xspi-dts-v1-0-7c18e5b4f97a@nxp.com>
Message-ID: <20251223-imx943-xspi-dts-v1-1-7c18e5b4f97a@nxp.com>

imx94 has two xspi, add these device nodes.

Signed-off-by: Haibo Chen <haibo.chen at nxp.com>
---
 arch/arm64/boot/dts/freescale/imx94.dtsi | 34 +++++++++++++++++++++++++++++++-
 1 file changed, 33 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/freescale/imx94.dtsi b/arch/arm64/boot/dts/freescale/imx94.dtsi
index 73184f03f8a3e134abc03dbd22ea24eff17be79b..96dd87800c8b500f2a885c1c1726e314b839fa8a 100644
--- a/arch/arm64/boot/dts/freescale/imx94.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx94.dtsi
@@ -629,7 +629,7 @@ aips3: bus at 42800000 {
 			compatible = "fsl,aips-bus", "simple-bus";
 			reg = <0 0x42800000 0 0x800000>;
 			ranges = <0x42800000 0x0 0x42800000 0x800000>,
-				 <0x28000000 0x0 0x28000000 0x1000000>;
+				 <0x24000000 0x0 0x24000000 0xc000000>;
 			#address-cells = <1>;
 			#size-cells = <1>;
 
@@ -785,6 +785,38 @@ mu17: mailbox at 42b60000 {
 				#mbox-cells = <2>;
 				status = "disabled";
 			};
+
+			xspi1: spi at 42b90000 {
+				compatible = "nxp,imx94-xspi";
+				reg = <0x42b90000 0x50000>, <0x28000000 0x08000000>;
+				reg-names = "base", "mmap";
+				interrupts = <GIC_SPI 390 IRQ_TYPE_LEVEL_HIGH>,		// EENV0
+					     <GIC_SPI 391 IRQ_TYPE_LEVEL_HIGH>,		// EENV1
+					     <GIC_SPI 392 IRQ_TYPE_LEVEL_HIGH>,		// EENV2
+					     <GIC_SPI 393 IRQ_TYPE_LEVEL_HIGH>,		// EENV3
+					     <GIC_SPI 394 IRQ_TYPE_LEVEL_HIGH>;		// EENV4
+				#address-cells = <1>;
+				#size-cells = <0>;
+				clocks = <&scmi_clk IMX94_CLK_XSPI1>;
+				clock-names = "per";
+				status = "disabled";
+			};
+
+			xspi2: spi at 42be0000 {
+				compatible = "nxp,imx94-xspi";
+				reg = <0x42be0000 0x50000>, <0x24000000 0x04000000>;
+				reg-names = "base", "mmap";
+				interrupts = <GIC_SPI 395 IRQ_TYPE_LEVEL_HIGH>,		// EENV0
+					     <GIC_SPI 396 IRQ_TYPE_LEVEL_HIGH>,		// EENV1
+					     <GIC_SPI 397 IRQ_TYPE_LEVEL_HIGH>,		// EENV2
+					     <GIC_SPI 398 IRQ_TYPE_LEVEL_HIGH>,		// EENV3
+					     <GIC_SPI 399 IRQ_TYPE_LEVEL_HIGH>;		// EENV4
+				#address-cells = <1>;
+				#size-cells = <0>;
+				clocks = <&scmi_clk IMX94_CLK_XSPI2>;
+				clock-names = "per";
+				status = "disabled";
+			};
 		};
 
 		gpio2: gpio at 43810000 {

-- 
2.34.1



From haibo.chen at nxp.com  Tue Dec 23 01:05:57 2025
From: haibo.chen at nxp.com (Haibo Chen)
Date: Tue, 23 Dec 2025 17:05:57 +0800
Subject: [PATCH 2/2] arm64: dts: imx94: add mt35xu512aba spi nor support
In-Reply-To: <20251223-imx943-xspi-dts-v1-0-7c18e5b4f97a@nxp.com>
References: <20251223-imx943-xspi-dts-v1-0-7c18e5b4f97a@nxp.com>
Message-ID: <20251223-imx943-xspi-dts-v1-2-7c18e5b4f97a@nxp.com>

Add mt35xu512aba spi nor support on imx943-evk board.
This nor chip support OCT DTR mode.

For the reset pin, since the nor chip side need 1.8v IO
voltage for reset pin, but the IO expander side use 3.3v
IO voltage, so to make circuit safe, need to config the
pad as OPEN DRAIN.

Signed-off-by: Haibo Chen <haibo.chen at nxp.com>
---
 arch/arm64/boot/dts/freescale/imx943-evk.dts | 34 ++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx943-evk.dts b/arch/arm64/boot/dts/freescale/imx943-evk.dts
index c8c3eff9df1a23c52e74bf2bc5d4ba543bb5a65b..19c02bd49cf5b0410b5d9f513ee279446ff79616 100644
--- a/arch/arm64/boot/dts/freescale/imx943-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx943-evk.dts
@@ -594,6 +594,22 @@ pinctrl_reg_usdhc2_vmmc: usdhc2regvmmcgrp {
 			IMX94_PAD_SD2_RESET_B__GPIO4_IO27	0x31e
 		>;
 	};
+
+	pinctrl_xspi1: xspi1grp {
+		fsl,pins = <
+			IMX94_PAD_XSPI1_SCLK__XSPI1_A_SCLK	0x3fe
+			IMX94_PAD_XSPI1_SS0_B__XSPI1_A_SS0_B	0x3fe
+			IMX94_PAD_XSPI1_DATA0__XSPI1_A_DATA0	0x3fe
+			IMX94_PAD_XSPI1_DATA1__XSPI1_A_DATA1	0x3fe
+			IMX94_PAD_XSPI1_DATA2__XSPI1_A_DATA2	0x3fe
+			IMX94_PAD_XSPI1_DATA3__XSPI1_A_DATA3	0x3fe
+			IMX94_PAD_XSPI1_DATA4__XSPI1_A_DATA4	0x3fe
+			IMX94_PAD_XSPI1_DATA5__XSPI1_A_DATA5	0x3fe
+			IMX94_PAD_XSPI1_DATA6__XSPI1_A_DATA6	0x3fe
+			IMX94_PAD_XSPI1_DATA7__XSPI1_A_DATA7	0x3fe
+			IMX94_PAD_XSPI1_DQS__XSPI1_A_DQS	0x3fe
+		>;
+	};
 };
 
 &usdhc1 {
@@ -625,3 +641,21 @@ &wdog3 {
 	fsl,ext-reset-output;
 	status = "okay";
 };
+
+&xspi1 {
+	pinctrl-0 = <&pinctrl_xspi1>;
+	pinctrl-1 = <&pinctrl_xspi1>;
+	pinctrl-names = "default", "sleep";
+	status = "okay";
+
+	mt35xu512aba: flash at 0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reset-gpios = <&pcal6416_i2c6_u50 15 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>;
+		spi-max-frequency = <200000000>;
+		spi-rx-bus-width = <8>;
+		spi-tx-bus-width = <8>;
+	};
+};

-- 
2.34.1



From andrew at lunn.ch  Tue Dec 23 01:13:38 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Tue, 23 Dec 2025 10:13:38 +0100
Subject: [PATCH 2/2] ARM: dts: aspeed: ventura2: Add Meta ventura2 BMC
In-Reply-To: <CAF7HswN_jEXOU_9K4LpLnbhvd+RD0qqELAHxMBbp=hGtMjS4kQ@mail.gmail.com>
References: <20251222-ventura2_initial_dts-v1-0-1f06166c78a3@gmail.com>
 <20251222-ventura2_initial_dts-v1-2-1f06166c78a3@gmail.com>
 <c069b452-df22-4afa-bf6a-c48949f40ebc@lunn.ch>
 <CAF7HswN_jEXOU_9K4LpLnbhvd+RD0qqELAHxMBbp=hGtMjS4kQ@mail.gmail.com>
Message-ID: <35f3eba9-5ec4-4cba-8a64-fb521dc65b79@lunn.ch>

On Tue, Dec 23, 2025 at 09:49:02AM +0800, ??? wrote:
> On Mon, Dec 22, 2025 at 5:30?PM Andrew Lunn <andrew at lunn.ch> wrote:
> >
> > > +&mdio0 {
> > > +     status = "okay";
> > > +};
> > > +
> > > +&mac2 {
> > > +     status = "okay";
> > > +     phy-mode = "rmii";
> > > +     pinctrl-names = "default";
> > > +     pinctrl-0 = <&pinctrl_rmii3_default>;
> > > +     fixed-link {
> > > +             speed = <100>;
> > > +             full-duplex;
> > > +     };
> > > +};
> >
> > That is an odd combination. You enable the MDIO bus, but don't have
> > any PHYs on it, no phandles pointing to it. And you have this
> > fixed-link. It makes me think you have an Ethernet switch on the bus,
> > and this connects to it?
> Thanks for the clarification.
> Yes, there is an Ethernet switch in the design.
> The MAC is connected to the switch via RMII using a fixed-link
> configuration.

What make/model of switch is it? Is it unmanaged, or does it use SPI
or I2C for management?

	Andrew


From jie.gan at oss.qualcomm.com  Tue Dec 23 01:14:11 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Tue, 23 Dec 2025 17:14:11 +0800
Subject: [PATCH v2 1/2] dt-binding: arm: add CTCU device for hamoa
In-Reply-To: <20251106-enable-etr-and-ctcu-for-hamoa-v2-1-cdb3a18753aa@oss.qualcomm.com>
References: <20251106-enable-etr-and-ctcu-for-hamoa-v2-0-cdb3a18753aa@oss.qualcomm.com>
 <20251106-enable-etr-and-ctcu-for-hamoa-v2-1-cdb3a18753aa@oss.qualcomm.com>
Message-ID: <076f6aff-4f9a-4630-8e5d-c11f0272de70@oss.qualcomm.com>



On 11/6/2025 9:57 AM, Jie Gan wrote:
> Document the CTCU compatible for Hamoa, enabling support for the
> CTCU device on the Hamoa platform.
> 

Gentle reminder.

The dependency[1] has applied and I have tested this series on 
next-20251219, no conflict and work well.

[1]https://lore.kernel.org/all/176615287813.688536.723538049922655005.b4-ty at arm.com/

Thanks,
Jie

> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
> ---
>   Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml | 1 +
>   1 file changed, 1 insertion(+)
> 
> diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
> index 460f38ddbd73..57dede7a90e9 100644
> --- a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
> +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
> @@ -29,6 +29,7 @@ properties:
>       oneOf:
>         - items:
>             - enum:
> +              - qcom,hamoa-ctcu
>                 - qcom,qcs8300-ctcu
>             - const: qcom,sa8775p-ctcu
>         - enum:
> 



From jbrunet at baylibre.com  Tue Dec 23 01:16:39 2025
From: jbrunet at baylibre.com (Jerome Brunet)
Date: Tue, 23 Dec 2025 10:16:39 +0100
Subject: [PATCH v4 5/8] clk: amlogic: Add A5 clock peripherals
 controller driver
In-Reply-To: <20251028-a5-clk-v4-5-e62ca0aae243@amlogic.com> (Chuan Liu via's
	message of "Tue, 28 Oct 2025 17:52:31 +0800")
References: <20251028-a5-clk-v4-0-e62ca0aae243@amlogic.com>
	<20251028-a5-clk-v4-5-e62ca0aae243@amlogic.com>
Message-ID: <1jpl857e2w.fsf@starbuckisacylon.baylibre.com>

On Tue 28 Oct 2025 at 17:52, Chuan Liu via B4 Relay <devnull+chuan.liu.amlogic.com at kernel.org> wrote:

> From: Chuan Liu <chuan.liu at amlogic.com>
>
> Add the peripherals clock controller driver for the Amlogic A5 SoC
> family.
>
> Signed-off-by: Chuan Liu <chuan.liu at amlogic.com>
> Signed-off-by: Xianwei Zhao <xianwei.zhao at amlogic.com>
> ---
>  drivers/clk/meson/Kconfig          |  13 +
>  drivers/clk/meson/Makefile         |   1 +
>  drivers/clk/meson/a5-peripherals.c | 883 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 897 insertions(+)
>
> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
> index b627821da081..5576f351ef8c 100644
> --- a/drivers/clk/meson/Kconfig
> +++ b/drivers/clk/meson/Kconfig
> @@ -146,6 +146,19 @@ config COMMON_CLK_A5_PLL
>  	  Say Y if you want the board to work, because PLLs are the parent
>  	  of most peripherals.
>  
> +config COMMON_CLK_A5_PERIPHERALS
> +	tristate "Amlogic A5 peripherals clock controller"
> +	depends on ARM64
> +	default ARCH_MESON
> +	select COMMON_CLK_MESON_REGMAP
> +	select COMMON_CLK_MESON_DUALDIV
> +	select COMMON_CLK_MESON_CLKC_UTILS
> +	imply COMMON_CLK_SCMI
> +	imply COMMON_CLK_A5_PLL
> +	help
> +	  Support for the Peripherals clock controller on Amlogic A113X2 device,
> +	  AKA A5. Say Y if you want the peripherals clock to work.
> +
>  config COMMON_CLK_C3_PLL
>  	tristate "Amlogic C3 PLL clock controller"
>  	depends on ARM64
> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
> index a074aa7e187f..0432027d7e2e 100644
> --- a/drivers/clk/meson/Makefile
> +++ b/drivers/clk/meson/Makefile
> @@ -20,6 +20,7 @@ obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
>  obj-$(CONFIG_COMMON_CLK_A1_PLL) += a1-pll.o
>  obj-$(CONFIG_COMMON_CLK_A1_PERIPHERALS) += a1-peripherals.o
>  obj-$(CONFIG_COMMON_CLK_A5_PLL) += a5-pll.o
> +obj-$(CONFIG_COMMON_CLK_A5_PERIPHERALS) += a5-peripherals.o
>  obj-$(CONFIG_COMMON_CLK_C3_PLL) += c3-pll.o
>  obj-$(CONFIG_COMMON_CLK_C3_PERIPHERALS) += c3-peripherals.o
>  obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
> diff --git a/drivers/clk/meson/a5-peripherals.c b/drivers/clk/meson/a5-peripherals.c
> new file mode 100644
> index 000000000000..eca9f3dcc256
> --- /dev/null
> +++ b/drivers/clk/meson/a5-peripherals.c
> @@ -0,0 +1,883 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Amlogic A5 Peripherals Clock Controller Driver
> + *
> + * Copyright (c) 2024-2025 Amlogic, inc.
> + * Author: Chuan Liu <chuan.liu at amlogic.com>
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/platform_device.h>
> +#include "clk-regmap.h"
> +#include "clk-dualdiv.h"
> +#include "meson-clkc-utils.h"
> +#include <dt-bindings/clock/amlogic,a5-peripherals-clkc.h>
> +
> +#define RTC_BY_OSCIN_CTRL0		0x8
> +#define RTC_BY_OSCIN_CTRL1		0xc
> +#define RTC_CTRL			0x10
> +#define SYS_CLK_EN0_REG0		0x44
> +#define SYS_CLK_EN0_REG1		0x48
> +#define DSPA_CLK_CTRL0			0x9c
> +#define CLK12_24_CTRL			0xa8
> +#define AXI_CLK_EN0			0xac
> +#define TS_CLK_CTRL			0x158
> +#define ETH_CLK_CTRL			0x164
> +#define NAND_CLK_CTRL			0x168
> +#define SD_EMMC_CLK_CTRL		0x16c
> +#define SPICC_CLK_CTRL			0x174
> +#define GEN_CLK_CTRL			0x178
> +#define SAR_CLK_CTRL0			0x17c
> +#define PWM_CLK_AB_CTRL			0x180
> +#define PWM_CLK_CD_CTRL			0x184
> +#define PWM_CLK_EF_CTRL			0x188
> +#define PWM_CLK_GH_CTRL			0x18c
> +#define NNA_CLK_CNTL			0x220
> +
> +static struct clk_regmap a5_rtc_dualdiv_clkin = {
> +	.data = &(struct clk_regmap_gate_data) {
> +		.offset = RTC_BY_OSCIN_CTRL0,
> +		.bit_idx = 31,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "rtc_dualdiv_clkin",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_data = &(const struct clk_parent_data) {
> +			.fw_name = "oscin",
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static const struct meson_clk_dualdiv_param a5_rtc_dualdiv_table[] = {
> +	{ 733, 732, 8, 11, 1 },
> +	{ /* sentinel */ }
> +};
> +
> +static struct clk_regmap a5_rtc_dualdiv = {
> +	.data = &(struct meson_clk_dualdiv_data) {
> +		.n1 = {
> +			.reg_off = RTC_BY_OSCIN_CTRL0,
> +			.shift   = 0,
> +			.width   = 12,
> +		},
> +		.n2 = {
> +			.reg_off = RTC_BY_OSCIN_CTRL0,
> +			.shift   = 12,
> +			.width   = 12,
> +		},
> +		.m1 = {
> +			.reg_off = RTC_BY_OSCIN_CTRL1,
> +			.shift   = 0,
> +			.width   = 12,
> +		},
> +		.m2 = {
> +			.reg_off = RTC_BY_OSCIN_CTRL1,
> +			.shift   = 12,
> +			.width   = 12,
> +		},
> +		.dual = {
> +			.reg_off = RTC_BY_OSCIN_CTRL0,
> +			.shift   = 28,
> +			.width   = 1,
> +		},
> +		.table = a5_rtc_dualdiv_table,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "rtc_dualdiv",
> +		.ops = &meson_clk_dualdiv_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a5_rtc_dualdiv_clkin.hw
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static const struct clk_parent_data a5_rtc_dualdiv_parent_data[] = {
> +	{ .hw = &a5_rtc_dualdiv.hw },
> +	{ .hw = &a5_rtc_dualdiv_clkin.hw }
> +};
> +
> +static struct clk_regmap a5_rtc_dualdiv_sel = {
> +	.data = &(struct clk_regmap_mux_data) {
> +		.offset = RTC_BY_OSCIN_CTRL1,
> +		.mask = 0x1,
> +		.shift = 24,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "rtc_dualdiv_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = a5_rtc_dualdiv_parent_data,
> +		.num_parents = ARRAY_SIZE(a5_rtc_dualdiv_parent_data),
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a5_rtc_dualdiv_clkout = {
> +	.data = &(struct clk_regmap_gate_data) {
> +		.offset = RTC_BY_OSCIN_CTRL0,
> +		.bit_idx = 30,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "rtc_dualdiv_clkout",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a5_rtc_dualdiv_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static const struct clk_parent_data a5_rtc_clk_parent_data[] = {
> +	{ .fw_name = "oscin" },
> +	{ .hw = &a5_rtc_dualdiv_clkout.hw },
> +	{ .fw_name = "pad_osc" }
> +};
> +
> +static struct clk_regmap a5_rtc_clk = {
> +	.data = &(struct clk_regmap_mux_data) {
> +		.offset = RTC_CTRL,
> +		.mask = 0x3,
> +		.shift = 0,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "rtc_clk",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = a5_rtc_clk_parent_data,
> +		.num_parents = ARRAY_SIZE(a5_rtc_clk_parent_data),
> +		.flags = CLK_SET_RATE_PARENT,

NO_REPARENT maybe ?

> +	},
> +};
> +
> +#define A5_PCLK(_name, _reg, _bit, _pdata, _flags)			\
> +struct clk_regmap a5_##_name = {					\
> +	.data = &(struct clk_regmap_gate_data) {			\
> +		.offset = (_reg),					\
> +		.bit_idx = (_bit),					\
> +	},								\
> +	.hw.init = &(struct clk_init_data) {				\
> +		.name = #_name,						\
> +		.ops = &clk_regmap_gate_ops,				\
> +		.parent_data = (_pdata),				\
> +		.num_parents = 1,					\
> +		.flags = (_flags),					\
> +	},								\
> +}

You've complained about the time it took to do the clean-up of amlogic
clocks, and yet, look what we have here ...

> +
> +static const struct clk_parent_data a5_sys_pclk_parents = { .fw_name = "sysclk" };
> +
> +#define A5_SYS_PCLK(_name, _reg, _bit, _flags) \
> +	A5_PCLK(_name, _reg, _bit, &a5_sys_pclk_parents, _flags)
> +
> +static A5_SYS_PCLK(sys_reset_ctrl,	SYS_CLK_EN0_REG0, 1, 0);
> +static A5_SYS_PCLK(sys_pwr_ctrl,	SYS_CLK_EN0_REG0, 3, 0);
> +static A5_SYS_PCLK(sys_pad_ctrl,	SYS_CLK_EN0_REG0, 4, 0);
> +static A5_SYS_PCLK(sys_ctrl,		SYS_CLK_EN0_REG0, 5, 0);
> +static A5_SYS_PCLK(sys_ts_pll,		SYS_CLK_EN0_REG0, 6, 0);
> +
> +/*
> + * NOTE: sys_dev_arb provides the clock to the ETH and SPICC arbiters that
> + * access the AXI bus.
> + */
> +static A5_SYS_PCLK(sys_dev_arb,		SYS_CLK_EN0_REG0, 7, 0);
> +static A5_SYS_PCLK(sys_mailbox,		SYS_CLK_EN0_REG0, 10, 0);
> +static A5_SYS_PCLK(sys_jtag_ctrl,	SYS_CLK_EN0_REG0, 12, 0);
> +static A5_SYS_PCLK(sys_ir_ctrl,		SYS_CLK_EN0_REG0, 13, 0);
> +static A5_SYS_PCLK(sys_msr_clk,		SYS_CLK_EN0_REG0, 15, 0);
> +static A5_SYS_PCLK(sys_rom,		SYS_CLK_EN0_REG0, 16, 0);
> +static A5_SYS_PCLK(sys_cpu_apb,		SYS_CLK_EN0_REG0, 18, 0);
> +static A5_SYS_PCLK(sys_rsa,		SYS_CLK_EN0_REG0, 19, 0);
> +static A5_SYS_PCLK(sys_saradc,		SYS_CLK_EN0_REG0, 20, 0);
> +static A5_SYS_PCLK(sys_startup,		SYS_CLK_EN0_REG0, 21, 0);
> +static A5_SYS_PCLK(sys_secure,		SYS_CLK_EN0_REG0, 22, 0);
> +static A5_SYS_PCLK(sys_spifc,		SYS_CLK_EN0_REG0, 23, 0);
> +static A5_SYS_PCLK(sys_dspa,		SYS_CLK_EN0_REG0, 24, 0);
> +static A5_SYS_PCLK(sys_nna,		SYS_CLK_EN0_REG0, 25, 0);
> +static A5_SYS_PCLK(sys_eth_mac,		SYS_CLK_EN0_REG0, 26, 0);
> +static A5_SYS_PCLK(sys_rama,		SYS_CLK_EN0_REG0, 28, 0);
> +static A5_SYS_PCLK(sys_ramb,		SYS_CLK_EN0_REG0, 30, 0);
> +static A5_SYS_PCLK(sys_audio_top,	SYS_CLK_EN0_REG1, 0, 0);
> +static A5_SYS_PCLK(sys_audio_vad,	SYS_CLK_EN0_REG1, 1, 0);
> +static A5_SYS_PCLK(sys_usb,		SYS_CLK_EN0_REG1, 2, 0);
> +static A5_SYS_PCLK(sys_sd_emmc_a,	SYS_CLK_EN0_REG1, 3, 0);
> +static A5_SYS_PCLK(sys_sd_emmc_c,	SYS_CLK_EN0_REG1, 4, 0);
> +static A5_SYS_PCLK(sys_pwm_ab,		SYS_CLK_EN0_REG1, 5, 0);
> +static A5_SYS_PCLK(sys_pwm_cd,		SYS_CLK_EN0_REG1, 6, 0);
> +static A5_SYS_PCLK(sys_pwm_ef,		SYS_CLK_EN0_REG1, 7, 0);
> +static A5_SYS_PCLK(sys_pwm_gh,		SYS_CLK_EN0_REG1, 8, 0);
> +static A5_SYS_PCLK(sys_spicc_1,		SYS_CLK_EN0_REG1, 9, 0);
> +static A5_SYS_PCLK(sys_spicc_0,		SYS_CLK_EN0_REG1, 10, 0);
> +static A5_SYS_PCLK(sys_uart_a,		SYS_CLK_EN0_REG1, 11, 0);
> +static A5_SYS_PCLK(sys_uart_b,		SYS_CLK_EN0_REG1, 12, 0);
> +static A5_SYS_PCLK(sys_uart_c,		SYS_CLK_EN0_REG1, 13, 0);
> +static A5_SYS_PCLK(sys_uart_d,		SYS_CLK_EN0_REG1, 14, 0);
> +static A5_SYS_PCLK(sys_uart_e,		SYS_CLK_EN0_REG1, 15, 0);
> +static A5_SYS_PCLK(sys_i2c_m_a,		SYS_CLK_EN0_REG1, 16, 0);
> +static A5_SYS_PCLK(sys_i2c_m_b,		SYS_CLK_EN0_REG1, 17, 0);
> +static A5_SYS_PCLK(sys_i2c_m_c,		SYS_CLK_EN0_REG1, 18, 0);
> +static A5_SYS_PCLK(sys_i2c_m_d,		SYS_CLK_EN0_REG1, 19, 0);
> +static A5_SYS_PCLK(sys_rtc,		SYS_CLK_EN0_REG1, 21, 0);
> +
> +static const struct clk_parent_data a5_axi_clk_parents = { .fw_name = "axiclk" };
> +
> +#define A5_AXI_CLK(_name, _reg, _bit, _flags) \
> +	A5_PCLK(_name, _reg, _bit, &a5_axi_clk_parents, _flags)
> +
> +static A5_AXI_CLK(axi_audio_vad,	AXI_CLK_EN0, 0, 0);
> +static A5_AXI_CLK(axi_audio_top,	AXI_CLK_EN0, 1, 0);
> +static A5_AXI_CLK(axi_ramb,		AXI_CLK_EN0, 5, 0);
> +static A5_AXI_CLK(axi_rama,		AXI_CLK_EN0, 6, 0);
> +static A5_AXI_CLK(axi_nna,		AXI_CLK_EN0, 12, 0);
> +
> +/*
> + * NOTE: axi_dev1_dmc provides the clock for the peripherals(EMMC, SDIO,
> + * sec_top, USB, Audio) to access the AXI bus of the DDR.
> + */
> +static A5_AXI_CLK(axi_dev1_dmc,	AXI_CLK_EN0, 13, 0);
> +
> +/*
> + * NOTE: axi_dev0_dmc provides the clock for the peripherals(ETH and SPICC)
> + * to access the AXI bus of the DDR.
> + */
> +static A5_AXI_CLK(axi_dev0_dmc,	AXI_CLK_EN0, 14, 0);
> +static A5_AXI_CLK(axi_dsp_dmc,		AXI_CLK_EN0, 15, 0);
> +
> +static struct clk_regmap a5_clk_12_24m_in = {
> +	.data = &(struct clk_regmap_gate_data) {
> +		.offset = CLK12_24_CTRL,
> +		.bit_idx = 11,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "clk_12_24m_in",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_data = &(const struct clk_parent_data) {
> +			.fw_name = "xtal",
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_regmap a5_clk_12_24m = {
> +	.data = &(struct clk_regmap_div_data) {
> +		.offset = CLK12_24_CTRL,
> +		.shift = 10,
> +		.width = 1,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "clk_12_24m",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a5_clk_12_24m_in.hw
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_regmap a5_fclk_25m_div = {
> +	.data = &(struct clk_regmap_div_data) {
> +		.offset = CLK12_24_CTRL,
> +		.shift = 0,
> +		.width = 8,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "fclk_25m_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_data = &(const struct clk_parent_data) {
> +			.fw_name = "fix",
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_regmap a5_fclk_25m = {
> +	.data = &(struct clk_regmap_gate_data) {
> +		.offset = CLK12_24_CTRL,
> +		.bit_idx = 12,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "fclk_25m",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a5_fclk_25m_div.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +/*
> + * Channel 4 5 8 9 10 11 13 14 15 16 18 are not connected.
> + *
> + * gp1 is designed for DSU (DynamIQ Shared Unit) alone. It cannot be changed
> + * arbitrarily. gp1 is read-only in the kernel and is only open for debug
> + * purposes.
> + */
> +static u32 a5_gen_parent_table[] = { 0, 1, 2, 3, 6, 7, 12, 17, 19, 20, 21, 22,
> +				    23, 24, 25, 26, 27, 28};
> +
> +static const struct clk_parent_data a5_gen_parent_data[] = {
> +	{ .fw_name = "oscin" },
> +	{ .hw = &a5_rtc_clk.hw },
> +	{ .fw_name = "sysplldiv16" },
> +	{ .fw_name = "ddr" },
> +	{ .fw_name = "gp1" },
> +	{ .fw_name = "hifi" },
> +	{ .fw_name = "clkmsr" },
> +	{ .fw_name = "cpudiv16" },
> +	{ .fw_name = "fdiv2" },
> +	{ .fw_name = "fdiv2p5" },
> +	{ .fw_name = "fdiv3" },
> +	{ .fw_name = "fdiv4" },
> +	{ .fw_name = "fdiv5" },
> +	{ .fw_name = "fdiv7" },
> +	{ .fw_name = "mpll0" },
> +	{ .fw_name = "mpll1" },
> +	{ .fw_name = "mpll2" },
> +	{ .fw_name = "mpll3" }
> +};
> +
> +static struct clk_regmap a5_gen_sel = {
> +	.data = &(struct clk_regmap_mux_data) {
> +		.offset = GEN_CLK_CTRL,
> +		.mask = 0x1f,
> +		.shift = 12,
> +		.table = a5_gen_parent_table,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "gen_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = a5_gen_parent_data,
> +		.num_parents = ARRAY_SIZE(a5_gen_parent_data),
> +	},
> +};
> +
> +static struct clk_regmap a5_gen_div = {
> +	.data = &(struct clk_regmap_div_data) {
> +		.offset = GEN_CLK_CTRL,
> +		.shift = 0,
> +		.width = 11,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "gen_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a5_gen_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a5_gen = {
> +	.data = &(struct clk_regmap_gate_data) {
> +		.offset = GEN_CLK_CTRL,
> +		.bit_idx = 11,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "gen",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a5_gen_div.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +#define A5_COMP_SEL(_name, _reg, _shift, _mask, _pdata) \
> +	MESON_COMP_SEL(a5_, _name, _reg, _shift, _mask, _pdata, NULL, 0, 0)
> +
> +#define A5_COMP_DIV(_name, _reg, _shift, _width) \
> +	MESON_COMP_DIV(a5_, _name, _reg, _shift, _width, 0, CLK_SET_RATE_PARENT)
> +
> +#define A5_COMP_GATE(_name, _reg, _bit) \
> +	MESON_COMP_GATE(a5_, _name, _reg, _bit, CLK_SET_RATE_PARENT)
> +
> +static const struct clk_parent_data a5_saradc_parent_data[] = {
> +	{ .fw_name = "oscin" },
> +	{ .fw_name = "sysclk" }
> +};
> +
> +static A5_COMP_SEL(saradc, SAR_CLK_CTRL0, 9, 0x3, a5_saradc_parent_data);
> +static A5_COMP_DIV(saradc, SAR_CLK_CTRL0, 0, 8);
> +static A5_COMP_GATE(saradc, SAR_CLK_CTRL0, 8);
> +
> +static const struct clk_parent_data a5_pwm_parent_data[] = {
> +	{ .fw_name = "oscin" },
> +	{ .hw = &a5_rtc_clk.hw },
> +	{ .fw_name = "fdiv4" },
> +	{ .fw_name = "fdiv3" }
> +};
> +
> +static A5_COMP_SEL(pwm_a, PWM_CLK_AB_CTRL, 9, 0x3, a5_pwm_parent_data);
> +static A5_COMP_DIV(pwm_a, PWM_CLK_AB_CTRL, 0, 8);
> +static A5_COMP_GATE(pwm_a, PWM_CLK_AB_CTRL, 8);
> +
> +static A5_COMP_SEL(pwm_b, PWM_CLK_AB_CTRL, 25, 0x3, a5_pwm_parent_data);
> +static A5_COMP_DIV(pwm_b, PWM_CLK_AB_CTRL, 16, 8);
> +static A5_COMP_GATE(pwm_b, PWM_CLK_AB_CTRL, 24);
> +
> +static A5_COMP_SEL(pwm_c, PWM_CLK_CD_CTRL, 9, 0x3, a5_pwm_parent_data);
> +static A5_COMP_DIV(pwm_c, PWM_CLK_CD_CTRL, 0, 8);
> +static A5_COMP_GATE(pwm_c, PWM_CLK_CD_CTRL, 8);
> +
> +static A5_COMP_SEL(pwm_d, PWM_CLK_CD_CTRL, 25, 0x3, a5_pwm_parent_data);
> +static A5_COMP_DIV(pwm_d, PWM_CLK_CD_CTRL, 16, 8);
> +static A5_COMP_GATE(pwm_d, PWM_CLK_CD_CTRL, 24);
> +
> +static A5_COMP_SEL(pwm_e, PWM_CLK_EF_CTRL, 9, 0x3, a5_pwm_parent_data);
> +static A5_COMP_DIV(pwm_e, PWM_CLK_EF_CTRL, 0, 8);
> +static A5_COMP_GATE(pwm_e, PWM_CLK_EF_CTRL, 8);
> +
> +static A5_COMP_SEL(pwm_f, PWM_CLK_EF_CTRL, 25, 0x3, a5_pwm_parent_data);
> +static A5_COMP_DIV(pwm_f, PWM_CLK_EF_CTRL, 16, 8);
> +static A5_COMP_GATE(pwm_f, PWM_CLK_EF_CTRL, 24);
> +
> +static A5_COMP_SEL(pwm_g, PWM_CLK_GH_CTRL, 9, 0x3, a5_pwm_parent_data);
> +static A5_COMP_DIV(pwm_g, PWM_CLK_GH_CTRL, 0, 8);
> +static A5_COMP_GATE(pwm_g, PWM_CLK_GH_CTRL, 8);
> +
> +static A5_COMP_SEL(pwm_h, PWM_CLK_GH_CTRL, 25, 0x3, a5_pwm_parent_data);
> +static A5_COMP_DIV(pwm_h, PWM_CLK_GH_CTRL, 16, 8);
> +static A5_COMP_GATE(pwm_h, PWM_CLK_GH_CTRL, 24);
> +
> +/*
> + * NOTE: Channel 7 is gp1, because gp1 is designed for DSU, so spicc does not
> + * support this source in the driver.
> + */
> +static const struct clk_parent_data a5_spicc_parent_data[] = {
> +	{ .fw_name = "oscin" },
> +	{ .fw_name = "sysclk" },
> +	{ .fw_name = "fdiv4" },
> +	{ .fw_name = "fdiv3" },
> +	{ .fw_name = "fdiv2" },
> +	{ .fw_name = "fdiv5" },
> +	{ .fw_name = "fdiv7" }
> +};
> +
> +static A5_COMP_SEL(spicc_0, SPICC_CLK_CTRL, 7, 0x7, a5_spicc_parent_data);
> +static A5_COMP_DIV(spicc_0, SPICC_CLK_CTRL, 0, 6);
> +static A5_COMP_GATE(spicc_0, SPICC_CLK_CTRL, 6);
> +
> +static A5_COMP_SEL(spicc_1, SPICC_CLK_CTRL, 23, 0x7, a5_spicc_parent_data);
> +static A5_COMP_DIV(spicc_1, SPICC_CLK_CTRL, 16, 6);
> +static A5_COMP_GATE(spicc_1, SPICC_CLK_CTRL, 22);
> +
> +static const struct clk_parent_data a5_sd_emmc_parent_data[] = {
> +	{ .fw_name = "oscin" },
> +	{ .fw_name = "fdiv2" },
> +	{ .fw_name = "fdiv3" },
> +	{ .fw_name = "hifi" },
> +	{ .fw_name = "fdiv2p5" },
> +	{ .fw_name = "mpll2" },
> +	{ .fw_name = "mpll3" },
> +	{ .fw_name = "gp0" }
> +};
> +
> +static A5_COMP_SEL(sd_emmc_a, SD_EMMC_CLK_CTRL, 9, 0x7, a5_sd_emmc_parent_data);
> +static A5_COMP_DIV(sd_emmc_a, SD_EMMC_CLK_CTRL, 0, 7);
> +static A5_COMP_GATE(sd_emmc_a, SD_EMMC_CLK_CTRL, 7);
> +
> +static A5_COMP_SEL(sd_emmc_c, NAND_CLK_CTRL, 9, 0x7, a5_sd_emmc_parent_data);
> +static A5_COMP_DIV(sd_emmc_c, NAND_CLK_CTRL, 0, 7);
> +static A5_COMP_GATE(sd_emmc_c, NAND_CLK_CTRL, 7);
> +
> +static struct clk_regmap a5_ts_div = {
> +	.data = &(struct clk_regmap_div_data) {
> +		.offset = TS_CLK_CTRL,
> +		.shift = 0,
> +		.width = 8,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "ts_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_data = &(const struct clk_parent_data) {
> +			.fw_name = "oscin",
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_regmap a5_ts = {
> +	.data = &(struct clk_regmap_gate_data) {
> +		.offset = TS_CLK_CTRL,
> +		.bit_idx = 8,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "ts",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a5_ts_div.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_fixed_factor a5_eth_125m_div = {
> +	.mult = 1,
> +	.div = 8,
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "eth_125m_div",
> +		.ops = &clk_fixed_factor_ops,
> +		.parent_data = &(const struct clk_parent_data) {
> +			.fw_name = "fdiv2",
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_regmap a5_eth_125m = {
> +	.data = &(struct clk_regmap_gate_data) {
> +		.offset = ETH_CLK_CTRL,
> +		.bit_idx = 7,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "eth_125m",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a5_eth_125m_div.hw
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_regmap a5_eth_rmii_div = {
> +	.data = &(struct clk_regmap_div_data) {
> +		.offset = ETH_CLK_CTRL,
> +		.shift = 0,
> +		.width = 7,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "eth_rmii_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_data = &(const struct clk_parent_data) {
> +			.fw_name = "fdiv2",
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_regmap a5_eth_rmii = {
> +	.data = &(struct clk_regmap_gate_data) {
> +		.offset = ETH_CLK_CTRL,
> +		.bit_idx = 8,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "eth_rmii",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a5_eth_rmii_div.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +/* Channel 6 is gp1. */
> +static u32 a5_dspa_parent_table[] = { 0, 1, 2, 3, 4, 5, 7};

Considering there is no rate propagation from mux below, is it really a
problem to have gp1 in here ? 

> +
> +static const struct clk_parent_data a5_dspa_parent_data[] = {
> +	{ .fw_name = "oscin" },
> +	{ .fw_name = "fdiv2p5" },
> +	{ .fw_name = "fdiv3" },
> +	{ .fw_name = "rtc" },  /* rtc_pll */
> +	{ .fw_name = "hifi" },
> +	{ .fw_name = "fdiv4" },
> +	{ .hw = &a5_rtc_clk.hw }
> +};
> +
> +static struct clk_regmap a5_dspa_0_sel = {
> +	.data = &(struct clk_regmap_mux_data) {
> +		.offset = DSPA_CLK_CTRL0,
> +		.mask = 0x7,
> +		.shift = 10,
> +		.table = a5_dspa_parent_table,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "dspa_0_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = a5_dspa_parent_data,
> +		.num_parents = ARRAY_SIZE(a5_dspa_parent_data),
> +	},
> +};
> +
> +static struct clk_regmap a5_dspa_0_div = {
> +	.data = &(struct clk_regmap_div_data) {
> +		.offset = DSPA_CLK_CTRL0,
> +		.shift = 0,
> +		.width = 10,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "dspa_0_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a5_dspa_0_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};

Same comment as the t7 regarding naming and macro usage for the glitch
free composite clocks. Please adjust accordingly.

> +
> +static struct clk_regmap a5_dspa_0 = {
> +	.data = &(struct clk_regmap_gate_data) {
> +		.offset = DSPA_CLK_CTRL0,
> +		.bit_idx = 13,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "dspa_0",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a5_dspa_0_div.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a5_dspa_1_sel = {
> +	.data = &(struct clk_regmap_mux_data) {
> +		.offset = DSPA_CLK_CTRL0,
> +		.mask = 0x7,
> +		.shift = 26,
> +		.table = a5_dspa_parent_table,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "dspa_1_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = a5_dspa_parent_data,
> +		.num_parents = ARRAY_SIZE(a5_dspa_parent_data),
> +	},
> +};
> +
> +static struct clk_regmap a5_dspa_1_div = {
> +	.data = &(struct clk_regmap_div_data) {
> +		.offset = DSPA_CLK_CTRL0,
> +		.shift = 16,
> +		.width = 10,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "dspa_1_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a5_dspa_1_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a5_dspa_1 = {
> +	.data = &(struct clk_regmap_gate_data) {
> +		.offset = DSPA_CLK_CTRL0,
> +		.bit_idx = 29,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "dspa_1",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a5_dspa_1_div.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a5_dspa = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = DSPA_CLK_CTRL0,
> +		.mask = 0x1,
> +		.shift = 15,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "dspa",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a5_dspa_0.hw,
> +			&a5_dspa_1.hw
> +		},
> +		.num_parents = 2,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +#define A5_COMP_SEL_WITH_TAB(_name, _reg, _shift, _mask, _pdata, _table) \

No, adjust your main macro.

> +	MESON_COMP_SEL(a5_, _name, _reg, _shift, _mask, _pdata, _table, 0, 0)
> +
> +/* Channel 6 is gp1. */
> +static u32 a5_nna_parent_table[] = { 0, 1, 2, 3, 4, 5, 7};
> +
> +static const struct clk_parent_data a5_nna_parent_data[] = {
> +	{ .fw_name = "oscin" },
> +	{ .fw_name = "fdiv2p5" },
> +	{ .fw_name = "fdiv4" },
> +	{ .fw_name = "fdiv3" },
> +	{ .fw_name = "fdiv5" },
> +	{ .fw_name = "fdiv2" },
> +	{ .fw_name = "hifi" }
> +};
> +
> +static A5_COMP_SEL_WITH_TAB(nna_core, NNA_CLK_CNTL, 9, 0x7,
> +			    a5_nna_parent_data, a5_nna_parent_table);
> +static A5_COMP_DIV(nna_core, NNA_CLK_CNTL, 0, 7);
> +static A5_COMP_GATE(nna_core, NNA_CLK_CNTL, 8);
> +
> +static A5_COMP_SEL_WITH_TAB(nna_axi, NNA_CLK_CNTL, 25, 0x7,
> +			    a5_nna_parent_data, a5_nna_parent_table);
> +static A5_COMP_DIV(nna_axi, NNA_CLK_CNTL, 16, 7);
> +static A5_COMP_GATE(nna_axi, NNA_CLK_CNTL, 24);
> +
> +static struct clk_hw *a5_peripherals_hw_clks[] = {
> +	[CLKID_RTC_DUALDIV_CLKIN]	= &a5_rtc_dualdiv_clkin.hw,
> +	[CLKID_RTC_DUALDIV]		= &a5_rtc_dualdiv.hw,
> +	[CLKID_RTC_DUALDIV_SEL]		= &a5_rtc_dualdiv_sel.hw,
> +	[CLKID_RTC_DUALDIV_CLKOUT]	= &a5_rtc_dualdiv_clkout.hw,
> +	[CLKID_RTC_CLK]			= &a5_rtc_clk.hw,
> +	[CLKID_SYS_RESET_CTRL]		= &a5_sys_reset_ctrl.hw,
> +	[CLKID_SYS_PWR_CTRL]		= &a5_sys_pwr_ctrl.hw,
> +	[CLKID_SYS_PAD_CTRL]		= &a5_sys_pad_ctrl.hw,
> +	[CLKID_SYS_CTRL]		= &a5_sys_ctrl.hw,
> +	[CLKID_SYS_TS_PLL]		= &a5_sys_ts_pll.hw,
> +	[CLKID_SYS_DEV_ARB]		= &a5_sys_dev_arb.hw,
> +	[CLKID_SYS_MAILBOX]		= &a5_sys_mailbox.hw,
> +	[CLKID_SYS_JTAG_CTRL]		= &a5_sys_jtag_ctrl.hw,
> +	[CLKID_SYS_IR_CTRL]		= &a5_sys_ir_ctrl.hw,
> +	[CLKID_SYS_MSR_CLK]		= &a5_sys_msr_clk.hw,
> +	[CLKID_SYS_ROM]			= &a5_sys_rom.hw,
> +	[CLKID_SYS_CPU_ARB]		= &a5_sys_cpu_apb.hw,
> +	[CLKID_SYS_RSA]			= &a5_sys_rsa.hw,
> +	[CLKID_SYS_SARADC]		= &a5_sys_saradc.hw,
> +	[CLKID_SYS_STARTUP]		= &a5_sys_startup.hw,
> +	[CLKID_SYS_SECURE]		= &a5_sys_secure.hw,
> +	[CLKID_SYS_SPIFC]		= &a5_sys_spifc.hw,
> +	[CLKID_SYS_DSPA]		= &a5_sys_dspa.hw,
> +	[CLKID_SYS_NNA]			= &a5_sys_nna.hw,
> +	[CLKID_SYS_ETH_MAC]		= &a5_sys_eth_mac.hw,
> +	[CLKID_SYS_RAMA]		= &a5_sys_rama.hw,
> +	[CLKID_SYS_RAMB]		= &a5_sys_ramb.hw,
> +	[CLKID_SYS_AUDIO_TOP]		= &a5_sys_audio_top.hw,
> +	[CLKID_SYS_AUDIO_VAD]		= &a5_sys_audio_vad.hw,
> +	[CLKID_SYS_USB]			= &a5_sys_usb.hw,
> +	[CLKID_SYS_SD_EMMC_A]		= &a5_sys_sd_emmc_a.hw,
> +	[CLKID_SYS_SD_EMMC_C]		= &a5_sys_sd_emmc_c.hw,
> +	[CLKID_SYS_PWM_AB]		= &a5_sys_pwm_ab.hw,
> +	[CLKID_SYS_PWM_CD]		= &a5_sys_pwm_cd.hw,
> +	[CLKID_SYS_PWM_EF]		= &a5_sys_pwm_ef.hw,
> +	[CLKID_SYS_PWM_GH]		= &a5_sys_pwm_gh.hw,
> +	[CLKID_SYS_SPICC_1]		= &a5_sys_spicc_1.hw,
> +	[CLKID_SYS_SPICC_0]		= &a5_sys_spicc_0.hw,
> +	[CLKID_SYS_UART_A]		= &a5_sys_uart_a.hw,
> +	[CLKID_SYS_UART_B]		= &a5_sys_uart_b.hw,
> +	[CLKID_SYS_UART_C]		= &a5_sys_uart_c.hw,
> +	[CLKID_SYS_UART_D]		= &a5_sys_uart_d.hw,
> +	[CLKID_SYS_UART_E]		= &a5_sys_uart_e.hw,
> +	[CLKID_SYS_I2C_M_A]		= &a5_sys_i2c_m_a.hw,
> +	[CLKID_SYS_I2C_M_B]		= &a5_sys_i2c_m_b.hw,
> +	[CLKID_SYS_I2C_M_C]		= &a5_sys_i2c_m_c.hw,
> +	[CLKID_SYS_I2C_M_D]		= &a5_sys_i2c_m_d.hw,
> +	[CLKID_SYS_RTC]			= &a5_sys_rtc.hw,
> +	[CLKID_AXI_AUDIO_VAD]		= &a5_axi_audio_vad.hw,
> +	[CLKID_AXI_AUDIO_TOP]		= &a5_axi_audio_top.hw,
> +	[CLKID_AXI_RAMB]		= &a5_axi_ramb.hw,
> +	[CLKID_AXI_RAMA]		= &a5_axi_rama.hw,
> +	[CLKID_AXI_NNA]			= &a5_axi_nna.hw,
> +	[CLKID_AXI_DEV1_DMC]		= &a5_axi_dev1_dmc.hw,
> +	[CLKID_AXI_DEV0_DMC]		= &a5_axi_dev0_dmc.hw,
> +	[CLKID_AXI_DSP_DMC]		= &a5_axi_dsp_dmc.hw,
> +	[CLKID_12_24M_IN]		= &a5_clk_12_24m_in.hw,
> +	[CLKID_12M_24M]			= &a5_clk_12_24m.hw,
> +	[CLKID_FCLK_25M_DIV]		= &a5_fclk_25m_div.hw,
> +	[CLKID_FCLK_25M]		= &a5_fclk_25m.hw,
> +	[CLKID_GEN_SEL]			= &a5_gen_sel.hw,
> +	[CLKID_GEN_DIV]			= &a5_gen_div.hw,
> +	[CLKID_GEN]			= &a5_gen.hw,
> +	[CLKID_SARADC_SEL]		= &a5_saradc_sel.hw,
> +	[CLKID_SARADC_DIV]		= &a5_saradc_div.hw,
> +	[CLKID_SARADC]			= &a5_saradc.hw,
> +	[CLKID_PWM_A_SEL]		= &a5_pwm_a_sel.hw,
> +	[CLKID_PWM_A_DIV]		= &a5_pwm_a_div.hw,
> +	[CLKID_PWM_A]			= &a5_pwm_a.hw,
> +	[CLKID_PWM_B_SEL]		= &a5_pwm_b_sel.hw,
> +	[CLKID_PWM_B_DIV]		= &a5_pwm_b_div.hw,
> +	[CLKID_PWM_B]			= &a5_pwm_b.hw,
> +	[CLKID_PWM_C_SEL]		= &a5_pwm_c_sel.hw,
> +	[CLKID_PWM_C_DIV]		= &a5_pwm_c_div.hw,
> +	[CLKID_PWM_C]			= &a5_pwm_c.hw,
> +	[CLKID_PWM_D_SEL]		= &a5_pwm_d_sel.hw,
> +	[CLKID_PWM_D_DIV]		= &a5_pwm_d_div.hw,
> +	[CLKID_PWM_D]			= &a5_pwm_d.hw,
> +	[CLKID_PWM_E_SEL]		= &a5_pwm_e_sel.hw,
> +	[CLKID_PWM_E_DIV]		= &a5_pwm_e_div.hw,
> +	[CLKID_PWM_E]			= &a5_pwm_e.hw,
> +	[CLKID_PWM_F_SEL]		= &a5_pwm_f_sel.hw,
> +	[CLKID_PWM_F_DIV]		= &a5_pwm_f_div.hw,
> +	[CLKID_PWM_F]			= &a5_pwm_f.hw,
> +	[CLKID_PWM_G_SEL]		= &a5_pwm_g_sel.hw,
> +	[CLKID_PWM_G_DIV]		= &a5_pwm_g_div.hw,
> +	[CLKID_PWM_G]			= &a5_pwm_g.hw,
> +	[CLKID_PWM_H_SEL]		= &a5_pwm_h_sel.hw,
> +	[CLKID_PWM_H_DIV]		= &a5_pwm_h_div.hw,
> +	[CLKID_PWM_H]			= &a5_pwm_h.hw,
> +	[CLKID_SPICC_0_SEL]		= &a5_spicc_0_sel.hw,
> +	[CLKID_SPICC_0_DIV]		= &a5_spicc_0_div.hw,
> +	[CLKID_SPICC_0]			= &a5_spicc_0.hw,
> +	[CLKID_SPICC_1_SEL]		= &a5_spicc_1_sel.hw,
> +	[CLKID_SPICC_1_DIV]		= &a5_spicc_1_div.hw,
> +	[CLKID_SPICC_1]			= &a5_spicc_1.hw,
> +	[CLKID_SD_EMMC_A_SEL]		= &a5_sd_emmc_a_sel.hw,
> +	[CLKID_SD_EMMC_A_DIV]		= &a5_sd_emmc_a_div.hw,
> +	[CLKID_SD_EMMC_A]		= &a5_sd_emmc_a.hw,
> +	[CLKID_SD_EMMC_C_SEL]		= &a5_sd_emmc_c_sel.hw,
> +	[CLKID_SD_EMMC_C_DIV]		= &a5_sd_emmc_c_div.hw,
> +	[CLKID_SD_EMMC_C]		= &a5_sd_emmc_c.hw,
> +	[CLKID_TS_DIV]			= &a5_ts_div.hw,
> +	[CLKID_TS]			= &a5_ts.hw,
> +	[CLKID_ETH_125M_DIV]		= &a5_eth_125m_div.hw,
> +	[CLKID_ETH_125M]		= &a5_eth_125m.hw,
> +	[CLKID_ETH_RMII_DIV]		= &a5_eth_rmii_div.hw,
> +	[CLKID_ETH_RMII]		= &a5_eth_rmii.hw,
> +	[CLKID_DSPA_0_SEL]		= &a5_dspa_0_sel.hw,
> +	[CLKID_DSPA_0_DIV]		= &a5_dspa_0_div.hw,
> +	[CLKID_DSPA_0]			= &a5_dspa_0.hw,
> +	[CLKID_DSPA_1_SEL]		= &a5_dspa_1_sel.hw,
> +	[CLKID_DSPA_1_DIV]		= &a5_dspa_1_div.hw,
> +	[CLKID_DSPA_1]			= &a5_dspa_1.hw,
> +	[CLKID_DSPA]			= &a5_dspa.hw,
> +	[CLKID_NNA_CORE_SEL]		= &a5_nna_core_sel.hw,
> +	[CLKID_NNA_CORE_DIV]		= &a5_nna_core_div.hw,
> +	[CLKID_NNA_CORE]		= &a5_nna_core.hw,
> +	[CLKID_NNA_AXI_SEL]		= &a5_nna_axi_sel.hw,
> +	[CLKID_NNA_AXI_DIV]		= &a5_nna_axi_div.hw,
> +	[CLKID_NNA_AXI]			= &a5_nna_axi.hw,
> +};
> +
> +static const struct meson_clkc_data a5_peripherals_clkc_data = {
> +	.hw_clks = {
> +		.hws = a5_peripherals_hw_clks,
> +		.num = ARRAY_SIZE(a5_peripherals_hw_clks),
> +	},
> +};
> +
> +static const struct of_device_id a5_peripherals_clkc_match_table[] = {
> +	{
> +		.compatible = "amlogic,a5-peripherals-clkc",
> +		.data = &a5_peripherals_clkc_data,
> +	},
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, a5_peripherals_clkc_match_table);
> +
> +static struct platform_driver a5_peripherals_clkc_driver = {
> +	.probe = meson_clkc_mmio_probe,
> +	.driver = {
> +		.name = "a5-peripherals-clkc",
> +		.of_match_table = a5_peripherals_clkc_match_table,
> +	},
> +};
> +module_platform_driver(a5_peripherals_clkc_driver);
> +
> +MODULE_DESCRIPTION("Amlogic A5 Peripherals Clock Controller driver");
> +MODULE_AUTHOR("Chuan Liu <chuan.liu at amlogic.com>");
> +MODULE_LICENSE("GPL");
> +MODULE_IMPORT_NS("CLK_MESON");

-- 
Jerome


From lakshmicar.2023 at gmail.com  Tue Dec 23 01:18:07 2025
From: lakshmicar.2023 at gmail.com (Lakshmi S)
Date: Tue, 23 Dec 2025 14:48:07 +0530
Subject: [PATCH] mailbox: arm_mhuv3: fix typo in comment 
Message-ID: <20251223091807.3070-1-lakshmicar.2023@gmail.com>

Fix typo "channnels"-> "channels" in struct documentation.

Signed-off-by: Lakshmi S <lakshmicar.2023 at gmail.com>
---
 drivers/mailbox/arm_mhuv3.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mailbox/arm_mhuv3.c b/drivers/mailbox/arm_mhuv3.c
index 0910da67f8a1..a1c528be47f3 100644
--- a/drivers/mailbox/arm_mhuv3.c
+++ b/drivers/mailbox/arm_mhuv3.c
@@ -333,7 +333,7 @@ struct mhuv3_extension {
  * @rev: MHUv3 controller IIDR revision.
  * @var: MHUv3 controller IIDR variant.
  * @prod_id: MHUv3 controller IIDR product_id.
- * @num_chans: The total number of channnels discovered across all extensions.
+ * @num_chans: The total number of channels discovered across all extensions.
  * @cmb_irq: Combined IRQ number if any found defined.
  * @ctrl: A reference to the MHUv3 control page for this block.
  * @pbx: Base address of the PBX register mapping region.
-- 
2.25.1



From kylehsieh1995 at gmail.com  Tue Dec 23 01:26:02 2025
From: kylehsieh1995 at gmail.com (Kyle Hsieh)
Date: Tue, 23 Dec 2025 17:26:02 +0800
Subject: [PATCH 2/2] ARM: dts: aspeed: ventura2: Add Meta ventura2 BMC
In-Reply-To: <35f3eba9-5ec4-4cba-8a64-fb521dc65b79@lunn.ch>
References: <20251222-ventura2_initial_dts-v1-0-1f06166c78a3@gmail.com>
 <20251222-ventura2_initial_dts-v1-2-1f06166c78a3@gmail.com>
 <c069b452-df22-4afa-bf6a-c48949f40ebc@lunn.ch> <CAF7HswN_jEXOU_9K4LpLnbhvd+RD0qqELAHxMBbp=hGtMjS4kQ@mail.gmail.com>
 <35f3eba9-5ec4-4cba-8a64-fb521dc65b79@lunn.ch>
Message-ID: <CAF7HswN0hhJQ-gmE59cKTuPyzrs1A3rM8Xw+Z8i3_AsHRiNcug@mail.gmail.com>

On Tue, Dec 23, 2025 at 5:13?PM Andrew Lunn <andrew at lunn.ch> wrote:
>
> On Tue, Dec 23, 2025 at 09:49:02AM +0800, ??? wrote:
> > On Mon, Dec 22, 2025 at 5:30?PM Andrew Lunn <andrew at lunn.ch> wrote:
> > >
> > > > +&mdio0 {
> > > > +     status = "okay";
> > > > +};
> > > > +
> > > > +&mac2 {
> > > > +     status = "okay";
> > > > +     phy-mode = "rmii";
> > > > +     pinctrl-names = "default";
> > > > +     pinctrl-0 = <&pinctrl_rmii3_default>;
> > > > +     fixed-link {
> > > > +             speed = <100>;
> > > > +             full-duplex;
> > > > +     };
> > > > +};
> > >
> > > That is an odd combination. You enable the MDIO bus, but don't have
> > > any PHYs on it, no phandles pointing to it. And you have this
> > > fixed-link. It makes me think you have an Ethernet switch on the bus,
> > > and this connects to it?
> > Thanks for the clarification.
> > Yes, there is an Ethernet switch in the design.
> > The MAC is connected to the switch via RMII using a fixed-link
> > configuration.
>
> What make/model of switch is it? Is it unmanaged, or does it use SPI
> or I2C for management?
The switch is connected via RMII to the MAC and is managed over MDIO.
On our board, MDIO is not wired directly to the processor; instead, we
use a USB-to-MPSSE bridge (FT2232) to toggle the MDIO signals for
switch management.
So the MDIO bus in the DTS is not used, and enabling it there was a mistake.
>
>         Andrew
Best Regard,
Kyle Hsieh


From wangzhou1 at hisilicon.com  Tue Dec 23 01:33:41 2025
From: wangzhou1 at hisilicon.com (Zhou Wang)
Date: Tue, 23 Dec 2025 17:33:41 +0800
Subject: [PATCH v8 5/7] KVM: arm64: Enable FEAT_{LS64, LS64_V} in the supported guest
In-Reply-To: <20251223093343.3822498-1-wangzhou1@hisilicon.com>
References: <20251223093343.3822498-1-wangzhou1@hisilicon.com>
Message-ID: <20251223093343.3822498-6-wangzhou1@hisilicon.com>

From: Yicong Yang <yangyicong at hisilicon.com>

Using FEAT_{LS64, LS64_V} instructions in a guest is also controlled
by HCRX_EL2.{EnALS, EnASR}. Enable it if guest has related feature.

Acked-by: Arnd Bergmann <arnd at arndb.de>
Acked-by: Oliver Upton <oupton at kernel.org>
Signed-off-by: Yicong Yang <yangyicong at hisilicon.com>
Signed-off-by: Zhou Wang <wangzhou1 at hisilicon.com>
---
 arch/arm64/include/asm/kvm_emulate.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index bab967d65715..29291e25ecfd 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -695,6 +695,12 @@ static inline void vcpu_set_hcrx(struct kvm_vcpu *vcpu)
 
 		if (kvm_has_sctlr2(kvm))
 			vcpu->arch.hcrx_el2 |= HCRX_EL2_SCTLR2En;
+
+		if (kvm_has_feat(kvm, ID_AA64ISAR1_EL1, LS64, LS64))
+			vcpu->arch.hcrx_el2 |= HCRX_EL2_EnALS;
+
+		if (kvm_has_feat(kvm, ID_AA64ISAR1_EL1, LS64, LS64_V))
+			vcpu->arch.hcrx_el2 |= HCRX_EL2_EnASR;
 	}
 }
 #endif /* __ARM64_KVM_EMULATE_H__ */
-- 
2.33.0



From wangzhou1 at hisilicon.com  Tue Dec 23 01:33:40 2025
From: wangzhou1 at hisilicon.com (Zhou Wang)
Date: Tue, 23 Dec 2025 17:33:40 +0800
Subject: [PATCH v8 4/7] arm64: Provide basic EL2 setup for FEAT_{LS64, LS64_V} usage at EL0/1
In-Reply-To: <20251223093343.3822498-1-wangzhou1@hisilicon.com>
References: <20251223093343.3822498-1-wangzhou1@hisilicon.com>
Message-ID: <20251223093343.3822498-5-wangzhou1@hisilicon.com>

From: Yicong Yang <yangyicong at hisilicon.com>

Instructions introduced by FEAT_{LS64, LS64_V} is controlled by
HCRX_EL2.{EnALS, EnASR}. Configure all of these to allow usage
at EL0/1.

This doesn't mean these instructions are always available in
EL0/1 if provided. The hypervisor still have the control at
runtime.

Acked-by: Will Deacon <will at kernel.org>
Acked-by: Arnd Bergmann <arnd at arndb.de>
Acked-by: Oliver Upton <oupton at kernel.org>
Signed-off-by: Yicong Yang <yangyicong at hisilicon.com>
Signed-off-by: Zhou Wang <wangzhou1 at hisilicon.com>
---
 arch/arm64/include/asm/el2_setup.h | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h
index cacd20df1786..9393220de069 100644
--- a/arch/arm64/include/asm/el2_setup.h
+++ b/arch/arm64/include/asm/el2_setup.h
@@ -83,9 +83,19 @@
         /* Enable GCS if supported */
 	mrs_s	x1, SYS_ID_AA64PFR1_EL1
 	ubfx	x1, x1, #ID_AA64PFR1_EL1_GCS_SHIFT, #4
-	cbz	x1, .Lset_hcrx_\@
+	cbz	x1, .Lskip_gcs_hcrx_\@
 	orr	x0, x0, #HCRX_EL2_GCSEn
 
+.Lskip_gcs_hcrx_\@:
+	/* Enable LS64, LS64_V if supported */
+	mrs_s	x1, SYS_ID_AA64ISAR1_EL1
+	ubfx	x1, x1, #ID_AA64ISAR1_EL1_LS64_SHIFT, #4
+	cbz	x1, .Lset_hcrx_\@
+	orr	x0, x0, #HCRX_EL2_EnALS
+	cmp	x1, #ID_AA64ISAR1_EL1_LS64_LS64_V
+	b.lt	.Lset_hcrx_\@
+	orr	x0, x0, #HCRX_EL2_EnASR
+
 .Lset_hcrx_\@:
 	msr_s	SYS_HCRX_EL2, x0
 .Lskip_hcrx_\@:
-- 
2.33.0



From wangzhou1 at hisilicon.com  Tue Dec 23 01:33:38 2025
From: wangzhou1 at hisilicon.com (Zhou Wang)
Date: Tue, 23 Dec 2025 17:33:38 +0800
Subject: [PATCH v8 2/7] KVM: arm64: Add documentation for KVM_EXIT_ARM_LDST64B
In-Reply-To: <20251223093343.3822498-1-wangzhou1@hisilicon.com>
References: <20251223093343.3822498-1-wangzhou1@hisilicon.com>
Message-ID: <20251223093343.3822498-3-wangzhou1@hisilicon.com>

From: Marc Zyngier <maz at kernel.org>

Add a bit of documentation for KVM_EXIT_ARM_LDST64B so that userspace
knows what to expect.

Acked-by: Arnd Bergmann <arnd at arndb.de>
Acked-by: Oliver Upton <oupton at kernel.org>
Signed-off-by: Marc Zyngier <maz at kernel.org>
Signed-off-by: Yicong Yang <yangyicong at hisilicon.com>
Signed-off-by: Zhou Wang <wangzhou1 at hisilicon.com>
---
 Documentation/virt/kvm/api.rst | 43 ++++++++++++++++++++++++++++------
 1 file changed, 36 insertions(+), 7 deletions(-)

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 01a3abef8abb..bfa0ab343081 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -1303,12 +1303,13 @@ userspace, for example because of missing instruction syndrome decode
 information or because there is no device mapped at the accessed IPA, then
 userspace can ask the kernel to inject an external abort using the address
 from the exiting fault on the VCPU. It is a programming error to set
-ext_dabt_pending after an exit which was not either KVM_EXIT_MMIO or
-KVM_EXIT_ARM_NISV. This feature is only available if the system supports
-KVM_CAP_ARM_INJECT_EXT_DABT. This is a helper which provides commonality in
-how userspace reports accesses for the above cases to guests, across different
-userspace implementations. Nevertheless, userspace can still emulate all Arm
-exceptions by manipulating individual registers using the KVM_SET_ONE_REG API.
+ext_dabt_pending after an exit which was not either KVM_EXIT_MMIO,
+KVM_EXIT_ARM_NISV, or KVM_EXIT_ARM_LDST64B. This feature is only available if
+the system supports KVM_CAP_ARM_INJECT_EXT_DABT. This is a helper which
+provides commonality in how userspace reports accesses for the above cases to
+guests, across different userspace implementations. Nevertheless, userspace
+can still emulate all Arm exceptions by manipulating individual registers
+using the KVM_SET_ONE_REG API.
 
 See KVM_GET_VCPU_EVENTS for the data structure.
 
@@ -7050,12 +7051,14 @@ in send_page or recv a buffer to recv_page).
 
 ::
 
-		/* KVM_EXIT_ARM_NISV */
+		/* KVM_EXIT_ARM_NISV / KVM_EXIT_ARM_LDST64B */
 		struct {
 			__u64 esr_iss;
 			__u64 fault_ipa;
 		} arm_nisv;
 
+- KVM_EXIT_ARM_NISV:
+
 Used on arm64 systems. If a guest accesses memory not in a memslot,
 KVM will typically return to userspace and ask it to do MMIO emulation on its
 behalf. However, for certain classes of instructions, no instruction decode
@@ -7089,6 +7092,32 @@ Note that although KVM_CAP_ARM_NISV_TO_USER will be reported if
 queried outside of a protected VM context, the feature will not be
 exposed if queried on a protected VM file descriptor.
 
+- KVM_EXIT_ARM_LDST64B:
+
+Used on arm64 systems. When a guest using a LD64B, ST64B, ST64BV, ST64BV0,
+outside of a memslot, KVM will return to userspace with KVM_EXIT_ARM_LDST64B,
+exposing the relevant ESR_EL2 information and faulting IPA, similarly to
+KVM_EXIT_ARM_NISV.
+
+Userspace is supposed to fully emulate the instructions, which includes:
+
+	- fetch of the operands for a store, including ACCDATA_EL1 in the case
+	  of a ST64BV0 instruction
+	- deal with the endianness if the guest is big-endian
+	- emulate the access, including the delivery of an exception if the
+	  access didn't succeed
+	- provide a return value in the case of ST64BV/ST64BV0
+	- return the data in the case of a load
+	- increment PC if the instruction was successfully executed
+
+Note that there is no expectation of performance for this emulation, as it
+involves a large number of interaction with the guest state. It is, however,
+expected that the instruction's semantics are preserved, specially the
+single-copy atomicity property of the 64 byte access.
+
+This exit reason must be handled if userspace sets ID_AA64ISAR1_EL1.LS64 to a
+non-zero value, indicating that FEAT_LS64* is enabled.
+
 ::
 
 		/* KVM_EXIT_X86_RDMSR / KVM_EXIT_X86_WRMSR */
-- 
2.33.0



From wangzhou1 at hisilicon.com  Tue Dec 23 01:33:42 2025
From: wangzhou1 at hisilicon.com (Zhou Wang)
Date: Tue, 23 Dec 2025 17:33:42 +0800
Subject: [PATCH v8 6/7] arm64: Add support for FEAT_{LS64, LS64_V}
In-Reply-To: <20251223093343.3822498-1-wangzhou1@hisilicon.com>
References: <20251223093343.3822498-1-wangzhou1@hisilicon.com>
Message-ID: <20251223093343.3822498-7-wangzhou1@hisilicon.com>

From: Yicong Yang <yangyicong at hisilicon.com>

Armv8.7 introduces single-copy atomic 64-byte loads and stores
instructions and its variants named under FEAT_{LS64, LS64_V}.
These features are identified by ID_AA64ISAR1_EL1.LS64 and the
use of such instructions in userspace (EL0) can be trapped.

As st64bv (FEAT_LS64_V) and st64bv0 (FEAT_LS64_ACCDATA) can not be tell
apart, FEAT_LS64 and FEAT_LS64_ACCDATA which will be supported in later
patch will be exported to userspace, FEAT_LS64_V will be enabled only
in kernel.

In order to support the use of corresponding instructions in userspace:
- Make ID_AA64ISAR1_EL1.LS64 visbile to userspace
- Add identifying and enabling in the cpufeature list
- Expose these support of these features to userspace through HWCAP3
  and cpuinfo

ld64b/st64b (FEAT_LS64) and st64bv (FEAT_LS64_V) is intended for
special memory (device memory) so requires support by the CPU, system
and target memory location (device that support these instructions).
The HWCAP3_LS64, implies the support of CPU and system (since no
identification method from system, so SoC vendors should advertise
support in the CPU if system also support them).

Otherwise for ld64b/st64b the atomicity may not be guaranteed or a
DABT will be generated, so users (probably userspace driver developer)
should make sure the target memory (device) also have the support.
For st64bv 0xffffffffffffffff will be returned as status result for
unsupported memory so user should check it.

Document the restrictions along with HWCAP3_LS64.

Acked-by: Arnd Bergmann <arnd at arndb.de>
Acked-by: Oliver Upton <oupton at kernel.org>
Signed-off-by: Yicong Yang <yangyicong at hisilicon.com>
Signed-off-by: Zhou Wang <wangzhou1 at hisilicon.com>
---
 Documentation/arch/arm64/booting.rst    | 12 +++++++++++
 Documentation/arch/arm64/elf_hwcaps.rst |  7 +++++++
 arch/arm64/include/asm/hwcap.h          |  1 +
 arch/arm64/include/uapi/asm/hwcap.h     |  1 +
 arch/arm64/kernel/cpufeature.c          | 28 +++++++++++++++++++++++++
 arch/arm64/kernel/cpuinfo.c             |  1 +
 arch/arm64/tools/cpucaps                |  2 ++
 7 files changed, 52 insertions(+)

diff --git a/Documentation/arch/arm64/booting.rst b/Documentation/arch/arm64/booting.rst
index 26efca09aef3..13ef311dace8 100644
--- a/Documentation/arch/arm64/booting.rst
+++ b/Documentation/arch/arm64/booting.rst
@@ -556,6 +556,18 @@ Before jumping into the kernel, the following conditions must be met:
 
    - MDCR_EL3.TPM (bit 6) must be initialized to 0b0
 
+  For CPUs with support for 64-byte loads and stores without status (FEAT_LS64):
+
+  - If the kernel is entered at EL1 and EL2 is present:
+
+    - HCRX_EL2.EnALS (bit 1) must be initialised to 0b1.
+
+  For CPUs with support for 64-byte stores with status (FEAT_LS64_V):
+
+  - If the kernel is entered at EL1 and EL2 is present:
+
+    - HCRX_EL2.EnASR (bit 2) must be initialised to 0b1.
+
 The requirements described above for CPU mode, caches, MMUs, architected
 timers, coherency and system registers apply to all CPUs.  All CPUs must
 enter the kernel in the same exception level.  Where the values documented
diff --git a/Documentation/arch/arm64/elf_hwcaps.rst b/Documentation/arch/arm64/elf_hwcaps.rst
index a15df4956849..97315ae6c0da 100644
--- a/Documentation/arch/arm64/elf_hwcaps.rst
+++ b/Documentation/arch/arm64/elf_hwcaps.rst
@@ -444,6 +444,13 @@ HWCAP3_MTE_STORE_ONLY
 HWCAP3_LSFE
     Functionality implied by ID_AA64ISAR3_EL1.LSFE == 0b0001
 
+HWCAP3_LS64
+    Functionality implied by ID_AA64ISAR1_EL1.LS64 == 0b0001. Note that
+    the function of instruction ld64b/st64b requires support by CPU, system
+    and target (device) memory location and HWCAP3_LS64 implies the support
+    of CPU. User should only use ld64b/st64b on supported target (device)
+    memory location, otherwise fallback to the non-atomic alternatives.
+
 
 4. Unused AT_HWCAP bits
 -----------------------
diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h
index 1f63814ae6c4..72ea4bda79f3 100644
--- a/arch/arm64/include/asm/hwcap.h
+++ b/arch/arm64/include/asm/hwcap.h
@@ -179,6 +179,7 @@
 #define KERNEL_HWCAP_MTE_FAR		__khwcap3_feature(MTE_FAR)
 #define KERNEL_HWCAP_MTE_STORE_ONLY	__khwcap3_feature(MTE_STORE_ONLY)
 #define KERNEL_HWCAP_LSFE		__khwcap3_feature(LSFE)
+#define KERNEL_HWCAP_LS64		__khwcap3_feature(LS64)
 
 /*
  * This yields a mask that user programs can use to figure out what
diff --git a/arch/arm64/include/uapi/asm/hwcap.h b/arch/arm64/include/uapi/asm/hwcap.h
index 575564ecdb0b..06f83ca8de56 100644
--- a/arch/arm64/include/uapi/asm/hwcap.h
+++ b/arch/arm64/include/uapi/asm/hwcap.h
@@ -146,5 +146,6 @@
 #define HWCAP3_MTE_FAR		(1UL << 0)
 #define HWCAP3_MTE_STORE_ONLY		(1UL << 1)
 #define HWCAP3_LSFE		(1UL << 2)
+#define HWCAP3_LS64		(1UL << 3)
 
 #endif /* _UAPI__ASM_HWCAP_H */
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index c840a93b9ef9..6cab77e2ffa9 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -240,6 +240,7 @@ static const struct arm64_ftr_bits ftr_id_aa64isar0[] = {
 };
 
 static const struct arm64_ftr_bits ftr_id_aa64isar1[] = {
+	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_EL1_LS64_SHIFT, 4, 0),
 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_EL1_XS_SHIFT, 4, 0),
 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_EL1_I8MM_SHIFT, 4, 0),
 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_EL1_DGH_SHIFT, 4, 0),
@@ -2260,6 +2261,16 @@ static void cpu_enable_e0pd(struct arm64_cpu_capabilities const *cap)
 }
 #endif /* CONFIG_ARM64_E0PD */
 
+static void cpu_enable_ls64(struct arm64_cpu_capabilities const *cap)
+{
+	sysreg_clear_set(sctlr_el1, SCTLR_EL1_EnALS, SCTLR_EL1_EnALS);
+}
+
+static void cpu_enable_ls64_v(struct arm64_cpu_capabilities const *cap)
+{
+	sysreg_clear_set(sctlr_el1, SCTLR_EL1_EnASR, 0);
+}
+
 #ifdef CONFIG_ARM64_PSEUDO_NMI
 static bool can_use_gic_priorities(const struct arm64_cpu_capabilities *entry,
 				   int scope)
@@ -3148,6 +3159,22 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
 		.matches = has_cpuid_feature,
 		ARM64_CPUID_FIELDS(ID_AA64MMFR1_EL1, XNX, IMP)
 	},
+	{
+		.desc = "LS64",
+		.capability = ARM64_HAS_LS64,
+		.type = ARM64_CPUCAP_SYSTEM_FEATURE,
+		.matches = has_cpuid_feature,
+		.cpu_enable = cpu_enable_ls64,
+		ARM64_CPUID_FIELDS(ID_AA64ISAR1_EL1, LS64, LS64)
+	},
+	{
+		.desc = "LS64_V",
+		.capability = ARM64_HAS_LS64_V,
+		.type = ARM64_CPUCAP_SYSTEM_FEATURE,
+		.matches = has_cpuid_feature,
+		.cpu_enable = cpu_enable_ls64_v,
+		ARM64_CPUID_FIELDS(ID_AA64ISAR1_EL1, LS64, LS64_V)
+	},
 	{},
 };
 
@@ -3267,6 +3294,7 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = {
 	HWCAP_CAP(ID_AA64ISAR1_EL1, BF16, EBF16, CAP_HWCAP, KERNEL_HWCAP_EBF16),
 	HWCAP_CAP(ID_AA64ISAR1_EL1, DGH, IMP, CAP_HWCAP, KERNEL_HWCAP_DGH),
 	HWCAP_CAP(ID_AA64ISAR1_EL1, I8MM, IMP, CAP_HWCAP, KERNEL_HWCAP_I8MM),
+	HWCAP_CAP(ID_AA64ISAR1_EL1, LS64, LS64, CAP_HWCAP, KERNEL_HWCAP_LS64),
 	HWCAP_CAP(ID_AA64ISAR2_EL1, LUT, IMP, CAP_HWCAP, KERNEL_HWCAP_LUT),
 	HWCAP_CAP(ID_AA64ISAR3_EL1, FAMINMAX, IMP, CAP_HWCAP, KERNEL_HWCAP_FAMINMAX),
 	HWCAP_CAP(ID_AA64ISAR3_EL1, LSFE, IMP, CAP_HWCAP, KERNEL_HWCAP_LSFE),
diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c
index c44e6d94f5de..6149bc91251d 100644
--- a/arch/arm64/kernel/cpuinfo.c
+++ b/arch/arm64/kernel/cpuinfo.c
@@ -81,6 +81,7 @@ static const char *const hwcap_str[] = {
 	[KERNEL_HWCAP_PACA]		= "paca",
 	[KERNEL_HWCAP_PACG]		= "pacg",
 	[KERNEL_HWCAP_GCS]		= "gcs",
+	[KERNEL_HWCAP_LS64]		= "ls64",
 	[KERNEL_HWCAP_DCPODP]		= "dcpodp",
 	[KERNEL_HWCAP_SVE2]		= "sve2",
 	[KERNEL_HWCAP_SVEAES]		= "sveaes",
diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps
index 0fac75f01534..50a0c695f340 100644
--- a/arch/arm64/tools/cpucaps
+++ b/arch/arm64/tools/cpucaps
@@ -46,6 +46,8 @@ HAS_HCX
 HAS_LDAPR
 HAS_LPA2
 HAS_LSE_ATOMICS
+HAS_LS64
+HAS_LS64_V
 HAS_MOPS
 HAS_NESTED_VIRT
 HAS_BBML2_NOABORT
-- 
2.33.0



From wangzhou1 at hisilicon.com  Tue Dec 23 01:33:37 2025
From: wangzhou1 at hisilicon.com (Zhou Wang)
Date: Tue, 23 Dec 2025 17:33:37 +0800
Subject: [PATCH v8 1/7] KVM: arm64: Add exit to userspace on {LD,ST}64B* outside of memslots
In-Reply-To: <20251223093343.3822498-1-wangzhou1@hisilicon.com>
References: <20251223093343.3822498-1-wangzhou1@hisilicon.com>
Message-ID: <20251223093343.3822498-2-wangzhou1@hisilicon.com>

From: Marc Zyngier <maz at kernel.org>

The main use of {LD,ST}64B* is to talk to a device, which is hopefully
directly assigned to the guest and requires no additional handling.

However, this does not preclude a VMM from exposing a virtual device
to the guest, and to allow 64 byte accesses as part of the programming
interface. A direct consequence of this is that we need to be able
to forward such access to userspace.

Given that such a contraption is very unlikely to ever exist, we choose
to offer a limited service: userspace gets (as part of a new exit reason)
the ESR, the IPA, and that's it. It is fully expected to handle the full
semantics of the instructions, deal with ACCDATA, the return values and
increment PC. Much fun.

A canonical implementation can also simply inject an abort and be done
with it. Frankly, don't try to do anything else unless you have time
to waste.

Acked-by: Arnd Bergmann <arnd at arndb.de>
Acked-by: Oliver Upton <oupton at kernel.org>
Signed-off-by: Marc Zyngier <maz at kernel.org>
Signed-off-by: Yicong Yang <yangyicong at hisilicon.com>
Signed-off-by: Zhou Wang <wangzhou1 at hisilicon.com>
---
 arch/arm64/kvm/mmio.c    | 27 ++++++++++++++++++++++++++-
 include/uapi/linux/kvm.h |  3 ++-
 2 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/mmio.c b/arch/arm64/kvm/mmio.c
index 54f9358c9e0e..e2285ed8c91d 100644
--- a/arch/arm64/kvm/mmio.c
+++ b/arch/arm64/kvm/mmio.c
@@ -159,6 +159,9 @@ int io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
 	bool is_write;
 	int len;
 	u8 data_buf[8];
+	u64 esr;
+
+	esr = kvm_vcpu_get_esr(vcpu);
 
 	/*
 	 * No valid syndrome? Ask userspace for help if it has
@@ -168,7 +171,7 @@ int io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
 	 * though, so directly deliver an exception to the guest.
 	 */
 	if (!kvm_vcpu_dabt_isvalid(vcpu)) {
-		trace_kvm_mmio_nisv(*vcpu_pc(vcpu), kvm_vcpu_get_esr(vcpu),
+		trace_kvm_mmio_nisv(*vcpu_pc(vcpu), esr,
 				    kvm_vcpu_get_hfar(vcpu), fault_ipa);
 
 		if (vcpu_is_protected(vcpu))
@@ -185,6 +188,28 @@ int io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
 		return -ENOSYS;
 	}
 
+	/*
+	 * When (DFSC == 0b00xxxx || DFSC == 0b10101x) && DFSC != 0b0000xx
+	 * ESR_EL2[12:11] describe the Load/Store Type. This allows us to
+	 * punt the LD64B/ST64B/ST64BV/ST64BV0 instructions to userspace,
+	 * which will have to provide a full emulation of these 4
+	 * instructions.  No, we don't expect this do be fast.
+	 *
+	 * We rely on traps being set if the corresponding features are not
+	 * enabled, so if we get here, userspace has promised us to handle
+	 * it already.
+	 */
+	switch (kvm_vcpu_trap_get_fault(vcpu)) {
+	case 0b000100 ... 0b001111:
+	case 0b101010 ... 0b101011:
+		if (FIELD_GET(GENMASK(12, 11), esr)) {
+			run->exit_reason = KVM_EXIT_ARM_LDST64B;
+			run->arm_nisv.esr_iss = esr & ~(u64)ESR_ELx_FSC;
+			run->arm_nisv.fault_ipa = fault_ipa;
+			return 0;
+		}
+	}
+
 	/*
 	 * Prepare MMIO operation. First decode the syndrome data we get
 	 * from the CPU. Then try if some in-kernel emulation feels
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index dddb781b0507..88cca0e22ece 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -180,6 +180,7 @@ struct kvm_xen_exit {
 #define KVM_EXIT_MEMORY_FAULT     39
 #define KVM_EXIT_TDX              40
 #define KVM_EXIT_ARM_SEA          41
+#define KVM_EXIT_ARM_LDST64B      42
 
 /* For KVM_EXIT_INTERNAL_ERROR */
 /* Emulate instruction failed. */
@@ -402,7 +403,7 @@ struct kvm_run {
 		} eoi;
 		/* KVM_EXIT_HYPERV */
 		struct kvm_hyperv_exit hyperv;
-		/* KVM_EXIT_ARM_NISV */
+		/* KVM_EXIT_ARM_NISV / KVM_EXIT_ARM_LDST64B */
 		struct {
 			__u64 esr_iss;
 			__u64 fault_ipa;
-- 
2.33.0



From wangzhou1 at hisilicon.com  Tue Dec 23 01:33:39 2025
From: wangzhou1 at hisilicon.com (Zhou Wang)
Date: Tue, 23 Dec 2025 17:33:39 +0800
Subject: [PATCH v8 3/7] KVM: arm64: Handle DABT caused by LS64* instructions on unsupported memory
In-Reply-To: <20251223093343.3822498-1-wangzhou1@hisilicon.com>
References: <20251223093343.3822498-1-wangzhou1@hisilicon.com>
Message-ID: <20251223093343.3822498-4-wangzhou1@hisilicon.com>

From: Yicong Yang <yangyicong at hisilicon.com>

If FEAT_LS64WB not supported, FEAT_LS64* instructions only support
to access Device/Uncacheable memory, otherwise a data abort for
unsupported Exclusive or atomic access (0x35, UAoEF) is generated
per spec. It's implementation defined whether the target exception
level is routed and is possible to implemented as route to EL2 on a
VHE VM according to DDI0487L.b Section C3.2.6 Single-copy atomic
64-byte load/store.

If it's implemented as generate the DABT to the final enabled stage
(stage-2), inject the UAoEF back to the guest after checking the
memslot is valid.

Acked-by: Arnd Bergmann <arnd at arndb.de>
Acked-by: Oliver Upton <oupton at kernel.org>
Signed-off-by: Yicong Yang <yangyicong at hisilicon.com>
Signed-off-by: Zhou Wang <wangzhou1 at hisilicon.com>
---
 arch/arm64/include/asm/esr.h         |  8 +++++++
 arch/arm64/include/asm/kvm_emulate.h |  1 +
 arch/arm64/kvm/inject_fault.c        | 34 ++++++++++++++++++++++++++++
 arch/arm64/kvm/mmu.c                 | 14 +++++++++++-
 4 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h
index 4975a92cbd17..7e86d400864e 100644
--- a/arch/arm64/include/asm/esr.h
+++ b/arch/arm64/include/asm/esr.h
@@ -124,6 +124,7 @@
 #define ESR_ELx_FSC_SEA_TTW(n)	(0x14 + (n))
 #define ESR_ELx_FSC_SECC	(0x18)
 #define ESR_ELx_FSC_SECC_TTW(n)	(0x1c + (n))
+#define ESR_ELx_FSC_EXCL_ATOMIC	(0x35)
 #define ESR_ELx_FSC_ADDRSZ	(0x00)
 
 /*
@@ -488,6 +489,13 @@ static inline bool esr_fsc_is_access_flag_fault(unsigned long esr)
 	       (esr == ESR_ELx_FSC_ACCESS_L(0));
 }
 
+static inline bool esr_fsc_is_excl_atomic_fault(unsigned long esr)
+{
+	esr = esr & ESR_ELx_FSC;
+
+	return esr == ESR_ELx_FSC_EXCL_ATOMIC;
+}
+
 static inline bool esr_fsc_is_addr_sz_fault(unsigned long esr)
 {
 	esr &= ESR_ELx_FSC;
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index c9eab316398e..bab967d65715 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -47,6 +47,7 @@ void kvm_skip_instr32(struct kvm_vcpu *vcpu);
 void kvm_inject_undefined(struct kvm_vcpu *vcpu);
 int kvm_inject_serror_esr(struct kvm_vcpu *vcpu, u64 esr);
 int kvm_inject_sea(struct kvm_vcpu *vcpu, bool iabt, u64 addr);
+int kvm_inject_dabt_excl_atomic(struct kvm_vcpu *vcpu, u64 addr);
 void kvm_inject_size_fault(struct kvm_vcpu *vcpu);
 
 static inline int kvm_inject_sea_dabt(struct kvm_vcpu *vcpu, u64 addr)
diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
index dfcd66c65517..6cc7ad84d7d8 100644
--- a/arch/arm64/kvm/inject_fault.c
+++ b/arch/arm64/kvm/inject_fault.c
@@ -253,6 +253,40 @@ int kvm_inject_sea(struct kvm_vcpu *vcpu, bool iabt, u64 addr)
 	return 1;
 }
 
+static int kvm_inject_nested_excl_atomic(struct kvm_vcpu *vcpu, u64 addr)
+{
+	u64 esr = FIELD_PREP(ESR_ELx_EC_MASK, ESR_ELx_EC_DABT_LOW) |
+		  FIELD_PREP(ESR_ELx_FSC, ESR_ELx_FSC_EXCL_ATOMIC) |
+		  ESR_ELx_IL;
+
+	vcpu_write_sys_reg(vcpu, addr, FAR_EL2);
+	return kvm_inject_nested_sync(vcpu, esr);
+}
+
+/**
+ * kvm_inject_dabt_excl_atomic - inject a data abort for unsupported exclusive
+ *				 or atomic access
+ * @vcpu: The VCPU to receive the data abort
+ * @addr: The address to report in the DFAR
+ *
+ * It is assumed that this code is called from the VCPU thread and that the
+ * VCPU therefore is not currently executing guest code.
+ */
+int kvm_inject_dabt_excl_atomic(struct kvm_vcpu *vcpu, u64 addr)
+{
+	u64 esr;
+
+	if (is_nested_ctxt(vcpu) && (vcpu_read_sys_reg(vcpu, HCR_EL2) & HCR_VM))
+		return kvm_inject_nested_excl_atomic(vcpu, addr);
+
+	__kvm_inject_sea(vcpu, false, addr);
+	esr = vcpu_read_sys_reg(vcpu, exception_esr_elx(vcpu));
+	esr &= ~ESR_ELx_FSC;
+	esr |= ESR_ELx_FSC_EXCL_ATOMIC;
+	vcpu_write_sys_reg(vcpu, esr, exception_esr_elx(vcpu));
+	return 1;
+}
+
 void kvm_inject_size_fault(struct kvm_vcpu *vcpu)
 {
 	unsigned long addr, esr;
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index 48d7c372a4cd..edc348431d71 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -1845,6 +1845,17 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 		return ret;
 	}
 
+	/*
+	 * Guest performs atomic/exclusive operations on memory with unsupported
+	 * attributes (e.g. ld64b/st64b on normal memory when no FEAT_LS64WB)
+	 * and trigger the exception here. Since the memslot is valid, inject
+	 * the fault back to the guest.
+	 */
+	if (esr_fsc_is_excl_atomic_fault(kvm_vcpu_get_esr(vcpu))) {
+		kvm_inject_dabt_excl_atomic(vcpu, kvm_vcpu_get_hfar(vcpu));
+		return 1;
+	}
+
 	if (nested)
 		adjust_nested_fault_perms(nested, &prot, &writable);
 
@@ -2082,7 +2093,8 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
 	/* Check the stage-2 fault is trans. fault or write fault */
 	if (!esr_fsc_is_translation_fault(esr) &&
 	    !esr_fsc_is_permission_fault(esr) &&
-	    !esr_fsc_is_access_flag_fault(esr)) {
+	    !esr_fsc_is_access_flag_fault(esr) &&
+	    !esr_fsc_is_excl_atomic_fault(esr)) {
 		kvm_err("Unsupported FSC: EC=%#x xFSC=%#lx ESR_EL2=%#lx\n",
 			kvm_vcpu_trap_get_class(vcpu),
 			(unsigned long)kvm_vcpu_trap_get_fault(vcpu),
-- 
2.33.0



From wangzhou1 at hisilicon.com  Tue Dec 23 01:33:36 2025
From: wangzhou1 at hisilicon.com (Zhou Wang)
Date: Tue, 23 Dec 2025 17:33:36 +0800
Subject: [PATCH v8 0/7] Add support for FEAT_{LS64, LS64_V} and related tests
Message-ID: <20251223093343.3822498-1-wangzhou1@hisilicon.com>

Armv8.7 introduces single-copy atomic 64-byte loads and stores
instructions and its variants named under FEAT_{LS64, LS64_V}.
Add support for Armv8.7 FEAT_{LS64, LS64_V}:
- Add identifying and enabling in the cpufeature list
- Expose the support of FEAT_LS64 to userspace through HWCAP3 and cpuinfo
- Add related hwcap test
- Handle the trap of unsupported memory (normal/uncacheable) access in a VM

A real scenario for this feature is that the userspace driver can make use of
this to implement direct WQE (workqueue entry) - a mechanism to fill WQE
directly into the hardware.

Picked Marc's 2 patches form [1] for handling the LS64 trap in a VM on emulated
MMIO and the introduce of KVM_EXIT_ARM_LDST64B.

[1] https://lore.kernel.org/linux-arm-kernel/20240815125959.2097734-1-maz at kernel.org/

Tested with updated hwcap test(host in VHE):
[root at localhost tmp]# ./hwcap
[...]
# LS64 present
ok 226 cpuinfo_match_LS64
ok 227 sigill_LS64
ok 228 # SKIP sigbus_LS64
# 120 skipped test(s) detected. Consider enabling relevant config options to improve coverage.
# Totals: pass:108 fail:0 xfail:0 xpass:0 skip:120 error:0

Tested with updated hwcap test(guest in VHE):
root at localhost:/mnt# ./hwcap
[...]
# LS64 present
ok 226 cpuinfo_match_LS64
ok 227 sigill_LS64
ok 228 # SKIP sigbus_LS64
# 120 skipped test(s) detected. Consider enabling relevant config options to improve coverage.
# Totals: pass:108 fail:0 xfail:0 xpass:0 skip:120 error:0

Tested nVHE case as well, same log as above.

Change since v7:
- Tiny spelling fix in 1/7
- Change the order between 5/7 and 6/7
- Remove has_ls64, use has_cpuid_feature directly in 6/7
- Add Acked-by from Arnd and Oliver
- Trap st64bv from EL0 to EL1/EL2
- Rebase on v6.19-rc1
Link: https://lore.kernel.org/all/20251107072127.448953-1-wangzhou1 at hisilicon.com/

Change since v6:
- Add exception inject about nested VM in 3/7
- Remove __maybe_unused related codes in 7/7, replace to use asm clobber
- Add my signoff in each patch
- Rebase on v6.18-rc4
Link: https://lore.kernel.org/all/20251024090819.4097819-1-wangzhou1 at hisilicon.com/

Change since v5:
- Rebase on v6.18-rc2 and fix the conflicts
- Add more description in elf_hwcaps.rst as suggested by Catalin Marinas
Link: https://lore.kernel.org/all/20250818064806.25417-1-yangyicong at huawei.com/

Change since v4:
- Rebase on v6.17-rc2 and fix the conflicts
Link: https://lore.kernel.org/linux-arm-kernel/20250715081356.12442-1-yangyicong at huawei.com/

Change since v3:
- Inject DABT fault for LS64 fault on unsupported memory but with valid memslot
Link: https://lore.kernel.org/linux-arm-kernel/20250626080906.64230-1-yangyicong at huawei.com/

Change since v2:
- Handle the LS64 fault to userspace and allow userspace to inject LS64 fault
- Reorder the patches to make KVM handling prior to feature support
Link: https://lore.kernel.org/linux-arm-kernel/20250331094320.35226-1-yangyicong at huawei.com/

Change since v1:
- Drop the support for LS64_ACCDATA
- handle the DABT of unsupported memory type after checking the memory attributes
Link: https://lore.kernel.org/linux-arm-kernel/20241202135504.14252-1-yangyicong at huawei.com/

Marc Zyngier (2):
  KVM: arm64: Add exit to userspace on {LD,ST}64B* outside of memslots
  KVM: arm64: Add documentation for KVM_EXIT_ARM_LDST64B

Yicong Yang (5):
  KVM: arm64: Handle DABT caused by LS64* instructions on unsupported
    memory
  arm64: Provide basic EL2 setup for FEAT_{LS64, LS64_V} usage at EL0/1
  KVM: arm64: Enable FEAT_{LS64, LS64_V} in the supported guest
  arm64: Add support for FEAT_{LS64, LS64_V}
  kselftest/arm64: Add HWCAP test for FEAT_LS64

 Documentation/arch/arm64/booting.rst      | 12 ++++++
 Documentation/arch/arm64/elf_hwcaps.rst   |  7 ++++
 Documentation/virt/kvm/api.rst            | 43 ++++++++++++++++----
 arch/arm64/include/asm/el2_setup.h        | 12 +++++-
 arch/arm64/include/asm/esr.h              |  8 ++++
 arch/arm64/include/asm/hwcap.h            |  1 +
 arch/arm64/include/asm/kvm_emulate.h      |  7 ++++
 arch/arm64/include/uapi/asm/hwcap.h       |  1 +
 arch/arm64/kernel/cpufeature.c            | 28 +++++++++++++
 arch/arm64/kernel/cpuinfo.c               |  1 +
 arch/arm64/kvm/inject_fault.c             | 34 ++++++++++++++++
 arch/arm64/kvm/mmio.c                     | 27 ++++++++++++-
 arch/arm64/kvm/mmu.c                      | 14 ++++++-
 arch/arm64/tools/cpucaps                  |  2 +
 include/uapi/linux/kvm.h                  |  3 +-
 tools/testing/selftests/arm64/abi/hwcap.c | 49 +++++++++++++++++++++++
 16 files changed, 238 insertions(+), 11 deletions(-)

-- 
2.33.0



From wangzhou1 at hisilicon.com  Tue Dec 23 01:33:43 2025
From: wangzhou1 at hisilicon.com (Zhou Wang)
Date: Tue, 23 Dec 2025 17:33:43 +0800
Subject: [PATCH v8 7/7] kselftest/arm64: Add HWCAP test for FEAT_LS64
In-Reply-To: <20251223093343.3822498-1-wangzhou1@hisilicon.com>
References: <20251223093343.3822498-1-wangzhou1@hisilicon.com>
Message-ID: <20251223093343.3822498-8-wangzhou1@hisilicon.com>

From: Yicong Yang <yangyicong at hisilicon.com>

Add tests for FEAT_LS64. Issue related instructions if feature
presents, no SIGILL should be received. When such instructions
operate on Device memory or non-cacheable memory, we may received
a SIGBUS during the test (w/o FEAT_LS64WB). Just ignore it since
we only tested whether the instruction itself can be issued as
expected on platforms declaring the support of such features.

Acked-by: Arnd Bergmann <arnd at arndb.de>
Acked-by: Oliver Upton <oupton at kernel.org>
Signed-off-by: Yicong Yang <yangyicong at hisilicon.com>
Signed-off-by: Zhou Wang <wangzhou1 at hisilicon.com>
---
 tools/testing/selftests/arm64/abi/hwcap.c | 49 +++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/tools/testing/selftests/arm64/abi/hwcap.c b/tools/testing/selftests/arm64/abi/hwcap.c
index c41640f18e4e..9d2df1f3e6bb 100644
--- a/tools/testing/selftests/arm64/abi/hwcap.c
+++ b/tools/testing/selftests/arm64/abi/hwcap.c
@@ -11,6 +11,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <linux/auxvec.h>
+#include <linux/compiler.h>
 #include <sys/auxv.h>
 #include <sys/prctl.h>
 #include <asm/hwcap.h>
@@ -595,6 +597,45 @@ static void lrcpc3_sigill(void)
 	              : "=r" (data0), "=r" (data1) : "r" (src) :);
 }
 
+static void ignore_signal(int sig, siginfo_t *info, void *context)
+{
+	ucontext_t *uc = context;
+
+	uc->uc_mcontext.pc += 4;
+}
+
+static void ls64_sigill(void)
+{
+	struct sigaction ign, old;
+	char src[64] __aligned(64) = { 1 };
+
+	/*
+	 * LS64 requires target memory to be Device/Non-cacheable (if
+	 * FEAT_LS64WB not supported) and the completer supports these
+	 * instructions, otherwise we'll receive a SIGBUS. Since we are only
+	 * testing the ABI here, so just ignore the SIGBUS and see if we can
+	 * execute the instructions without receiving a SIGILL. Restore the
+	 * handler of SIGBUS after this test.
+	 */
+	ign.sa_sigaction = ignore_signal;
+	ign.sa_flags = SA_SIGINFO | SA_RESTART;
+	sigemptyset(&ign.sa_mask);
+	sigaction(SIGBUS, &ign, &old);
+
+	register void *xn asm ("x8") = src;
+	register u64 xt_1 asm ("x0");
+
+	/* LD64B x0, [x8] */
+	asm volatile(".inst 0xf83fd100" : "=r" (xt_1) : "r" (xn)
+		     : "x1", "x2", "x3", "x4", "x5", "x6", "x7");
+
+	/* ST64B x0, [x8] */
+	asm volatile(".inst 0xf83f9100" : : "r" (xt_1), "r" (xn)
+		     : "x1", "x2", "x3", "x4", "x5", "x6", "x7");
+
+	sigaction(SIGBUS, &old, NULL);
+}
+
 static const struct hwcap_data {
 	const char *name;
 	unsigned long at_hwcap;
@@ -1134,6 +1175,14 @@ static const struct hwcap_data {
 		.hwcap_bit = HWCAP3_MTE_STORE_ONLY,
 		.cpuinfo = "mtestoreonly",
 	},
+	{
+		.name = "LS64",
+		.at_hwcap = AT_HWCAP3,
+		.hwcap_bit = HWCAP3_LS64,
+		.cpuinfo = "ls64",
+		.sigill_fn = ls64_sigill,
+		.sigill_reliable = true,
+	},
 };
 
 typedef void (*sighandler_fn)(int, siginfo_t *, void *);
-- 
2.33.0



From peter.wang at mediatek.com  Tue Dec 23 01:35:39 2025
From: peter.wang at mediatek.com (=?utf-8?B?UGV0ZXIgV2FuZyAo546L5L+h5Y+LKQ==?=)
Date: Tue, 23 Dec 2025 09:35:39 +0000
Subject: [PATCH v4 07/25] scsi: ufs: mediatek: Rework 0.9V regulator
In-Reply-To: <20251218-mt8196-ufs-v4-7-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
	 <20251218-mt8196-ufs-v4-7-ddec7a369dd2@collabora.com>
Message-ID: <8206d9e715f7ef987b5369d0bda68cce13528112.camel@mediatek.com>

On Thu, 2025-12-18 at 13:54 +0100, Nicolas Frattaroli wrote:
> 
> +static int ufs_mtk_get_supplies(struct ufs_mtk_host *host)
> +{
> +?????? struct device *dev = host->hba->dev;
> +?????? const struct ufs_mtk_soc_data *data =
> of_device_get_match_data(dev);
> +
> +?????? if (!data || !data->has_avdd09)
> +?????????????? return 0;
> 


Hi Nicolas,

It seems that has_avdd09 is not necessary, because if the 
platform does not support avdd09, it will return an error
(-ENODEV) and bypass the avdd09 flow, right?

Thanks
Peter




From suzuki.poulose at arm.com  Tue Dec 23 01:37:27 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Tue, 23 Dec 2025 09:37:27 +0000
Subject: [PATCH v6 4/4] coresight: tpda: add sysfs node to flush specific
 port
In-Reply-To: <b3b1e130-4592-4863-825f-e00cb9d996b8@oss.qualcomm.com>
References: <20251222-add_sysfs_nodes_to_configure_tpda-v6-0-b27143d45c86@oss.qualcomm.com>
 <20251222-add_sysfs_nodes_to_configure_tpda-v6-4-b27143d45c86@oss.qualcomm.com>
 <9899b6c2-2bdf-41b8-9156-dcf1b611da39@arm.com>
 <b3b1e130-4592-4863-825f-e00cb9d996b8@oss.qualcomm.com>
Message-ID: <dcc1adba-9e7a-4820-8fab-eed14f3d8770@arm.com>

On 23/12/2025 02:16, Jie Gan wrote:
> 
> 
> On 12/22/2025 9:12 PM, Suzuki K Poulose wrote:
>> On 22/12/2025 06:02, Jie Gan wrote:
>>> From: Tao Zhang <tao.zhang at oss.qualcomm.com>
>>>
>>> Setting bit i in the TPDA_FLUSH_CR register initiates a flush request
>>> for port i, forcing the data to synchronize and be transmitted to the
>>> sink device.
>>>
>>> Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
>>> Reviewed-by: James Clark <james.clark at linaro.org>
>>> Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
>>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>>> ---
>>> ? .../ABI/testing/sysfs-bus-coresight-devices-tpda?? |? 7 ++++
>>> ? drivers/hwtracing/coresight/coresight-tpda.c?????? | 40 +++++++++++ 
>>> + ++++++++++
>>> ? drivers/hwtracing/coresight/coresight-tpda.h?????? |? 1 +
>>> ? 3 files changed, 48 insertions(+)
>>>
>>> diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices- 
>>> tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
>>> index d359d90dca72..df8f03d4b573 100644
>>> --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
>>> +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
>>> @@ -51,3 +51,10 @@ Description:
>>> ????????? mode 0 - COUNT[11:0] value represents the approximate 
>>> number of bytes moved between two ASYNC packet requests
>>> ????????? mode 1 - the bits COUNT[11:7] are used as a power of 2. for 
>>> example, we could insert an async packet every 8K
>>> ?????????????????? data by writing a value 13 to the COUNT[11:7] field.
>>> +
>>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/port_flush_req
>>> +Date:??????? December 2025
>>> +KernelVersion:??? 6.19
>>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>>> +Description:
>>> +??????? (RW) Configure the bit i to requests a flush operation of 
>>> port i on the TPDA.
>>
>> Does this have similar semantics as the "global_flush_req"? for "Read" ? 
> 
> Yes, global_flush_req triggers all ports at once, whereas this node 
> initiates a flush request for specific port(s).
> 
> For reading, we can check whether the flush request has completed.

Please document it as such.

Suzuki


> 
> Thanks,
> Jie
> 
>> i.e., the bit stays set until the request completes ? Otherwise, why 
>> isn't this Write only ?
>>
>> I don't see the point of "Reading" this value back.
>>
>> Suzuki
>>
>>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/ 
>>> hwtracing/coresight/coresight-tpda.c
>>> index 7baa8a0965d3..f79fea4fbb2c 100644
>>> --- a/drivers/hwtracing/coresight/coresight-tpda.c
>>> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
>>> @@ -430,9 +430,49 @@ static ssize_t syncr_mode_store(struct device *dev,
>>> ? }
>>> ? static DEVICE_ATTR_RW(syncr_mode);
>>> +static ssize_t port_flush_req_show(struct device *dev,
>>> +?????????????????? struct device_attribute *attr,
>>> +?????????????????? char *buf)
>>> +{
>>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>>> +??? unsigned long val;
>>> +
>>> +??? if (!drvdata->csdev->refcnt)
>>> +??????? return -EINVAL;
>>> +
>>> +??? guard(spinlock)(&drvdata->spinlock);
>>> +??? val = readl_relaxed(drvdata->base + TPDA_FLUSH_CR);
>>> +
>>> +??? return sysfs_emit(buf, "0x%lx\n", val);
>>> +}
>>> +
>>> +static ssize_t port_flush_req_store(struct device *dev,
>>> +??????????????????? struct device_attribute *attr,
>>> +??????????????????? const char *buf,
>>> +??????????????????? size_t size)
>>> +{
>>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>>> +??? u32 val;
>>> +
>>> +??? if (kstrtou32(buf, 0, &val))
>>> +??????? return -EINVAL;
>>> +
>>> +??? if (!drvdata->csdev->refcnt || !val)
>>> +??????? return -EINVAL;
>>> +
>>> +??? guard(spinlock)(&drvdata->spinlock);
>>> +??? CS_UNLOCK(drvdata->base);
>>> +??? writel_relaxed(val, drvdata->base + TPDA_FLUSH_CR);
>>> +??? CS_LOCK(drvdata->base);
>>> +
>>> +??? return size;
>>> +}
>>> +static DEVICE_ATTR_RW(port_flush_req);
>>> +
>>> ? static struct attribute *tpda_attrs[] = {
>>> ????? &dev_attr_global_flush_req.attr,
>>> ????? &dev_attr_syncr_mode.attr,
>>> +??? &dev_attr_port_flush_req.attr,
>>> ????? tpda_trig_sysfs_rw(freq_ts_enable, FREQTS),
>>> ????? tpda_trig_sysfs_rw(trig_freq_enable, FRIE),
>>> ????? tpda_trig_sysfs_rw(trig_flag_ts_enable, FLRIE),
>>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/ 
>>> hwtracing/coresight/coresight-tpda.h
>>> index 1d2de50bb9f9..ef1ce2ce36a9 100644
>>> --- a/drivers/hwtracing/coresight/coresight-tpda.h
>>> +++ b/drivers/hwtracing/coresight/coresight-tpda.h
>>> @@ -10,6 +10,7 @@
>>> ? #define TPDA_Pn_CR(n)??????? (0x004 + (n * 4))
>>> ? #define TPDA_FPID_CR??????? (0x084)
>>> ? #define TPDA_SYNCR??????? (0x08C)
>>> +#define TPDA_FLUSH_CR??????? (0x090)
>>> ? /* Cross trigger global (all ports) flush request bit */
>>> ? #define TPDA_CR_FLREQ??????? BIT(0)
>>>
>>
> 



From suzuki.poulose at arm.com  Tue Dec 23 01:49:07 2025
From: suzuki.poulose at arm.com (Suzuki K Poulose)
Date: Tue, 23 Dec 2025 09:49:07 +0000
Subject: [PATCH v7 3/4] coresight: tpda: add logic to configure TPDA_SYNCR
 register
In-Reply-To: <20251223-add_sysfs_nodes_to_configure_tpda-v7-3-db4e6810047c@oss.qualcomm.com>
References: <20251223-add_sysfs_nodes_to_configure_tpda-v7-0-db4e6810047c@oss.qualcomm.com>
 <20251223-add_sysfs_nodes_to_configure_tpda-v7-3-db4e6810047c@oss.qualcomm.com>
Message-ID: <ab53c4e1-e0a2-4a6b-840b-a84e9b236e8f@arm.com>

On 23/12/2025 08:41, Jie Gan wrote:
> From: Tao Zhang <tao.zhang at oss.qualcomm.com>
> 
> The TPDA_SYNC counter tracks the number of bytes transferred from the
> aggregator. When this count reaches the value programmed in the
> TPDA_SYNCR register, an ASYNC request is triggered, allowing userspace
> tools to accurately parse each valid packet.
> 
> Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
> Reviewed-by: James Clark <james.clark at linaro.org>
> Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
> ---
>   .../ABI/testing/sysfs-bus-coresight-devices-tpda   | 18 +++++
>   drivers/hwtracing/coresight/coresight-tpda.c       | 90 ++++++++++++++++++++++
>   drivers/hwtracing/coresight/coresight-tpda.h       | 10 +++
>   3 files changed, 118 insertions(+)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
> index c8bc7b19ab25..c989eea1ef59 100644
> --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
> +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
> @@ -41,3 +41,21 @@ Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qu
>   Description:
>   		(RW) Set global (all ports) flush request bit. The bit remains set until a
>   		global flush request sequence completes.
> +
> +What:		/sys/bus/coresight/devices/<tpda-name>/syncr_mode
> +Date:		December 2025
> +KernelVersion:	6.19
> +Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
> +Description:
> +		(RW) Set mode the of the syncr counter.
> +		mode 0 - COUNT[11:0] value represents the approximate number of bytes moved between two ASYNC packet requests
> +		mode 1 - the bits COUNT[11:7] are used as a power of 2. for example, we could insert an async packet every 8K
> +		         data by writing a value 13 to the COUNT[11:7] field.
> +
> +What:		/sys/bus/coresight/devices/<tpda-name>/syncr_count
> +Date:		December 2025
> +KernelVersion:	6.19
> +Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
> +Description:
> +		(RW) Set value the of the syncr counter.
> +		Range: 0-4095
> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
> index d24a9098f1b1..8283e16ec400 100644
> --- a/drivers/hwtracing/coresight/coresight-tpda.c
> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
> @@ -163,6 +163,20 @@ static void tpda_enable_pre_port(struct tpda_drvdata *drvdata)
>   	 */
>   	if (drvdata->trig_flag_ts)
>   		writel_relaxed(0x0, drvdata->base + TPDA_FPID_CR);
> +
> +	/* Initialize with a value of 0 */
> +	val = 0;
> +	if (drvdata->syncr_mode)
> +		val |= TPDA_SYNCR_MODE_CTRL_MASK;
> +
> +	if (drvdata->syncr_count > 0 &&
> +	    drvdata->syncr_count < TPDA_SYNCR_COUNT_MASK)
> +		val |= drvdata->syncr_count;
> +	else
> +		/* Program the count to its MAX value by default */
> +		val |= TPDA_SYNCR_COUNT_MASK;
> +
> +	writel_relaxed(val, drvdata->base + TPDA_SYNCR);
>   }
>   
>   static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
> @@ -385,8 +399,84 @@ static ssize_t global_flush_req_store(struct device *dev,
>   }
>   static DEVICE_ATTR_RW(global_flush_req);
>   
> +static ssize_t syncr_mode_show(struct device *dev,
> +			       struct device_attribute *attr,
> +			       char *buf)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	unsigned long val, syncr_val;
> +
> +	if (!drvdata->csdev->refcnt)
> +		return -EINVAL;
> +
> +	guard(spinlock)(&drvdata->spinlock);
> +	syncr_val = readl_relaxed(drvdata->base + TPDA_SYNCR);
> +	val = FIELD_GET(TPDA_SYNCR_MODE_CTRL_MASK, syncr_val);
> +
> +	return sysfs_emit(buf, "%lu\n", val);
> +}
> +
> +static ssize_t syncr_mode_store(struct device *dev,
> +				struct device_attribute *attr,
> +				const char *buf,
> +				size_t size)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	unsigned long val;
> +
> +	if (kstrtoul(buf, 0, &val))
> +		return -EINVAL;
> +
> +	guard(spinlock)(&drvdata->spinlock);
> +	/* set the mode when first enabling the device */
> +	drvdata->syncr_mode = !!val;
> +
> +	return size;
> +}
> +static DEVICE_ATTR_RW(syncr_mode);
> +
> +static ssize_t syncr_count_show(struct device *dev,
> +				struct device_attribute *attr,
> +				char *buf)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	unsigned long val;
> +
> +	if (!drvdata->csdev->refcnt)
> +		return -EINVAL;
> +
> +	guard(spinlock)(&drvdata->spinlock);
> +	val = readl_relaxed(drvdata->base + TPDA_SYNCR);
> +	val &= TPDA_SYNCR_COUNT_MASK;
> +
> +	return sysfs_emit(buf, "%lu\n", val);
> +}
> +
> +static ssize_t syncr_count_store(struct device *dev,
> +				 struct device_attribute *attr,
> +				 const char *buf,
> +				 size_t size)
> +{
> +	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	unsigned long val;
> +
> +	if (kstrtoul(buf, 0, &val))
> +		return -EINVAL;
> +
> +	if (val < 0 || val > TPDA_SYNCR_COUNT_MASK)

Checking "val < 0" for an unsigned type is invalid. Simply keep the 
second part.

Suzuki


> +		return -EINVAL;
> +
> +	guard(spinlock)(&drvdata->spinlock);
> +	drvdata->syncr_count = val;
> +
> +	return size;
> +}
> +static DEVICE_ATTR_RW(syncr_count);
> +
>   static struct attribute *tpda_attrs[] = {
>   	&dev_attr_global_flush_req.attr,
> +	&dev_attr_syncr_mode.attr,
> +	&dev_attr_syncr_count.attr,
>   	tpda_trig_sysfs_rw(freq_ts_enable, FREQTS),
>   	tpda_trig_sysfs_rw(trig_freq_enable, FRIE),
>   	tpda_trig_sysfs_rw(trig_flag_ts_enable, FLRIE),
> diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h
> index 1cc9253293ec..56d35697303a 100644
> --- a/drivers/hwtracing/coresight/coresight-tpda.h
> +++ b/drivers/hwtracing/coresight/coresight-tpda.h
> @@ -9,6 +9,7 @@
>   #define TPDA_CR			(0x000)
>   #define TPDA_Pn_CR(n)		(0x004 + (n * 4))
>   #define TPDA_FPID_CR		(0x084)
> +#define TPDA_SYNCR		(0x08C)
>   
>   /* Cross trigger global (all ports) flush request bit */
>   #define TPDA_CR_FLREQ		BIT(0)
> @@ -36,6 +37,11 @@
>   /* Aggregator port DSB data set element size bit */
>   #define TPDA_Pn_CR_DSBSIZE		BIT(8)
>   
> +/* TPDA_SYNCR count mask */
> +#define TPDA_SYNCR_COUNT_MASK		GENMASK(11, 0)
> +/* TPDA_SYNCR mode control bit */
> +#define TPDA_SYNCR_MODE_CTRL_MASK	GENMASK(12, 12)
> +
>   #define TPDA_MAX_INPORTS	32
>   
>   /**
> @@ -52,6 +58,8 @@
>    * @trig_freq:	Enable/disable cross trigger FREQ packet request interface.
>    * @freq_ts:	Enable/disable the timestamp for all FREQ packets.
>    * @cmbchan_mode: Configure the CMB/MCMB channel mode.
> + * @syncr_mode:	Setting the mode for counting packets.
> + * @syncr_count: Setting the value of the count.
>    */
>   struct tpda_drvdata {
>   	void __iomem		*base;
> @@ -66,6 +74,8 @@ struct tpda_drvdata {
>   	bool			trig_freq;
>   	bool			freq_ts;
>   	bool			cmbchan_mode;
> +	bool			syncr_mode;
> +	u32			syncr_count;
>   };
>   
>   /* Enumerate members of global control register(cr) */
> 



From jie.gan at oss.qualcomm.com  Tue Dec 23 01:53:12 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Tue, 23 Dec 2025 17:53:12 +0800
Subject: [PATCH v7 3/4] coresight: tpda: add logic to configure TPDA_SYNCR
 register
In-Reply-To: <ab53c4e1-e0a2-4a6b-840b-a84e9b236e8f@arm.com>
References: <20251223-add_sysfs_nodes_to_configure_tpda-v7-0-db4e6810047c@oss.qualcomm.com>
 <20251223-add_sysfs_nodes_to_configure_tpda-v7-3-db4e6810047c@oss.qualcomm.com>
 <ab53c4e1-e0a2-4a6b-840b-a84e9b236e8f@arm.com>
Message-ID: <23737351-e254-4b2c-a3e3-bc7eebb1c025@oss.qualcomm.com>



On 12/23/2025 5:49 PM, Suzuki K Poulose wrote:
> On 23/12/2025 08:41, Jie Gan wrote:
>> From: Tao Zhang <tao.zhang at oss.qualcomm.com>
>>
>> The TPDA_SYNC counter tracks the number of bytes transferred from the
>> aggregator. When this count reaches the value programmed in the
>> TPDA_SYNCR register, an ASYNC request is triggered, allowing userspace
>> tools to accurately parse each valid packet.
>>
>> Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
>> Reviewed-by: James Clark <james.clark at linaro.org>
>> Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
>> ---
>> ? .../ABI/testing/sysfs-bus-coresight-devices-tpda?? | 18 +++++
>> ? drivers/hwtracing/coresight/coresight-tpda.c?????? | 90 ++++++++++++ 
>> ++++++++++
>> ? drivers/hwtracing/coresight/coresight-tpda.h?????? | 10 +++
>> ? 3 files changed, 118 insertions(+)
>>
>> diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices- 
>> tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
>> index c8bc7b19ab25..c989eea1ef59 100644
>> --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
>> +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
>> @@ -41,3 +41,21 @@ Contact:??? Jinlong Mao 
>> <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qu
>> ? Description:
>> ????????? (RW) Set global (all ports) flush request bit. The bit 
>> remains set until a
>> ????????? global flush request sequence completes.
>> +
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/syncr_mode
>> +Date:??????? December 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Set mode the of the syncr counter.
>> +??????? mode 0 - COUNT[11:0] value represents the approximate number 
>> of bytes moved between two ASYNC packet requests
>> +??????? mode 1 - the bits COUNT[11:7] are used as a power of 2. for 
>> example, we could insert an async packet every 8K
>> +???????????????? data by writing a value 13 to the COUNT[11:7] field.
>> +
>> +What:??????? /sys/bus/coresight/devices/<tpda-name>/syncr_count
>> +Date:??????? December 2025
>> +KernelVersion:??? 6.19
>> +Contact:??? Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang 
>> <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
>> +Description:
>> +??????? (RW) Set value the of the syncr counter.
>> +??????? Range: 0-4095
>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/ 
>> hwtracing/coresight/coresight-tpda.c
>> index d24a9098f1b1..8283e16ec400 100644
>> --- a/drivers/hwtracing/coresight/coresight-tpda.c
>> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
>> @@ -163,6 +163,20 @@ static void tpda_enable_pre_port(struct 
>> tpda_drvdata *drvdata)
>> ?????? */
>> ????? if (drvdata->trig_flag_ts)
>> ????????? writel_relaxed(0x0, drvdata->base + TPDA_FPID_CR);
>> +
>> +??? /* Initialize with a value of 0 */
>> +??? val = 0;
>> +??? if (drvdata->syncr_mode)
>> +??????? val |= TPDA_SYNCR_MODE_CTRL_MASK;
>> +
>> +??? if (drvdata->syncr_count > 0 &&
>> +??????? drvdata->syncr_count < TPDA_SYNCR_COUNT_MASK)
>> +??????? val |= drvdata->syncr_count;
>> +??? else
>> +??????? /* Program the count to its MAX value by default */
>> +??????? val |= TPDA_SYNCR_COUNT_MASK;
>> +
>> +??? writel_relaxed(val, drvdata->base + TPDA_SYNCR);
>> ? }
>> ? static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
>> @@ -385,8 +399,84 @@ static ssize_t global_flush_req_store(struct 
>> device *dev,
>> ? }
>> ? static DEVICE_ATTR_RW(global_flush_req);
>> +static ssize_t syncr_mode_show(struct device *dev,
>> +?????????????????? struct device_attribute *attr,
>> +?????????????????? char *buf)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +??? unsigned long val, syncr_val;
>> +
>> +??? if (!drvdata->csdev->refcnt)
>> +??????? return -EINVAL;
>> +
>> +??? guard(spinlock)(&drvdata->spinlock);
>> +??? syncr_val = readl_relaxed(drvdata->base + TPDA_SYNCR);
>> +??? val = FIELD_GET(TPDA_SYNCR_MODE_CTRL_MASK, syncr_val);
>> +
>> +??? return sysfs_emit(buf, "%lu\n", val);
>> +}
>> +
>> +static ssize_t syncr_mode_store(struct device *dev,
>> +??????????????? struct device_attribute *attr,
>> +??????????????? const char *buf,
>> +??????????????? size_t size)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +??? unsigned long val;
>> +
>> +??? if (kstrtoul(buf, 0, &val))
>> +??????? return -EINVAL;
>> +
>> +??? guard(spinlock)(&drvdata->spinlock);
>> +??? /* set the mode when first enabling the device */
>> +??? drvdata->syncr_mode = !!val;
>> +
>> +??? return size;
>> +}
>> +static DEVICE_ATTR_RW(syncr_mode);
>> +
>> +static ssize_t syncr_count_show(struct device *dev,
>> +??????????????? struct device_attribute *attr,
>> +??????????????? char *buf)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +??? unsigned long val;
>> +
>> +??? if (!drvdata->csdev->refcnt)
>> +??????? return -EINVAL;
>> +
>> +??? guard(spinlock)(&drvdata->spinlock);
>> +??? val = readl_relaxed(drvdata->base + TPDA_SYNCR);
>> +??? val &= TPDA_SYNCR_COUNT_MASK;
>> +
>> +??? return sysfs_emit(buf, "%lu\n", val);
>> +}
>> +
>> +static ssize_t syncr_count_store(struct device *dev,
>> +???????????????? struct device_attribute *attr,
>> +???????????????? const char *buf,
>> +???????????????? size_t size)
>> +{
>> +??? struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> +??? unsigned long val;
>> +
>> +??? if (kstrtoul(buf, 0, &val))
>> +??????? return -EINVAL;
>> +
>> +??? if (val < 0 || val > TPDA_SYNCR_COUNT_MASK)
> 
> Checking "val < 0" for an unsigned type is invalid. Simply keep the 
> second part.
> 

Sure, sorry for the mistake. I forgot it?s an unsigned value here.

Will send a new version to fix it.

Thanks,
Jie

> Suzuki
> 
> 
>> +??????? return -EINVAL;
>> +
>> +??? guard(spinlock)(&drvdata->spinlock);
>> +??? drvdata->syncr_count = val;
>> +
>> +??? return size;
>> +}
>> +static DEVICE_ATTR_RW(syncr_count);
>> +
>> ? static struct attribute *tpda_attrs[] = {
>> ????? &dev_attr_global_flush_req.attr,
>> +??? &dev_attr_syncr_mode.attr,
>> +??? &dev_attr_syncr_count.attr,
>> ????? tpda_trig_sysfs_rw(freq_ts_enable, FREQTS),
>> ????? tpda_trig_sysfs_rw(trig_freq_enable, FRIE),
>> ????? tpda_trig_sysfs_rw(trig_flag_ts_enable, FLRIE),
>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/ 
>> hwtracing/coresight/coresight-tpda.h
>> index 1cc9253293ec..56d35697303a 100644
>> --- a/drivers/hwtracing/coresight/coresight-tpda.h
>> +++ b/drivers/hwtracing/coresight/coresight-tpda.h
>> @@ -9,6 +9,7 @@
>> ? #define TPDA_CR??????????? (0x000)
>> ? #define TPDA_Pn_CR(n)??????? (0x004 + (n * 4))
>> ? #define TPDA_FPID_CR??????? (0x084)
>> +#define TPDA_SYNCR??????? (0x08C)
>> ? /* Cross trigger global (all ports) flush request bit */
>> ? #define TPDA_CR_FLREQ??????? BIT(0)
>> @@ -36,6 +37,11 @@
>> ? /* Aggregator port DSB data set element size bit */
>> ? #define TPDA_Pn_CR_DSBSIZE??????? BIT(8)
>> +/* TPDA_SYNCR count mask */
>> +#define TPDA_SYNCR_COUNT_MASK??????? GENMASK(11, 0)
>> +/* TPDA_SYNCR mode control bit */
>> +#define TPDA_SYNCR_MODE_CTRL_MASK??? GENMASK(12, 12)
>> +
>> ? #define TPDA_MAX_INPORTS??? 32
>> ? /**
>> @@ -52,6 +58,8 @@
>> ?? * @trig_freq:??? Enable/disable cross trigger FREQ packet request 
>> interface.
>> ?? * @freq_ts:??? Enable/disable the timestamp for all FREQ packets.
>> ?? * @cmbchan_mode: Configure the CMB/MCMB channel mode.
>> + * @syncr_mode:??? Setting the mode for counting packets.
>> + * @syncr_count: Setting the value of the count.
>> ?? */
>> ? struct tpda_drvdata {
>> ????? void __iomem??????? *base;
>> @@ -66,6 +74,8 @@ struct tpda_drvdata {
>> ????? bool??????????? trig_freq;
>> ????? bool??????????? freq_ts;
>> ????? bool??????????? cmbchan_mode;
>> +??? bool??????????? syncr_mode;
>> +??? u32??????????? syncr_count;
>> ? };
>> ? /* Enumerate members of global control register(cr) */
>>
> 



From abhiraj21put at gmail.com  Tue Dec 23 01:54:34 2025
From: abhiraj21put at gmail.com (Abhishek Rajput)
Date: Tue, 23 Dec 2025 15:24:34 +0530
Subject: [PATCH v2] drm/mediatek: Convert legacy DRM logging to drm_* helpers in mtk_crtc.c
Message-ID: <20251223095434.492041-1-abhiraj21put@gmail.com>

Replace DRM_ERROR() and DRM_DEBUG_DRIVER() calls in
drivers/gpu/drm/mediatek/mtk_crtc.c with the corresponding drm__err()
and drm_dbg_driver() helpers.

The drm_*() logging helpers take a struct drm_device * argument,
allowing the DRM core to prefix log messages with the correct device
name and instance. This is required to correctly distinguish log
messages on systems with multiple GPUs.

This change aligns the Mediatek DRM driver with the DRM TODO item:
"Convert logging to drm_* functions with drm_device parameter".

Reported-by: kernel test robot <lkp at intel.com>
Closes:
https://lore.kernel.org/oe-kbuild-all/202512220515.z3QybJ8I-lkp at intel.com/
Signed-off-by: Abhishek Rajput <abhiraj21put at gmail.com>
---
v2:
- Fix unused variable warning when CONFIG_MTK_CMDQ is disabled
- Added Reported-by and Closes tags
Link to v1:
https://lore.kernel.org/all/20251217070303.689913-1-abhiraj21put at gmail.com/
 drivers/gpu/drm/mediatek/mtk_crtc.c | 22 ++++++++++++++--------
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c b/drivers/gpu/drm/mediatek/mtk_crtc.c
index 991cdb3d7d5f..bca2e40bca54 100644
--- a/drivers/gpu/drm/mediatek/mtk_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_crtc.c
@@ -227,11 +227,12 @@ static int mtk_crtc_ddp_clk_enable(struct mtk_crtc *mtk_crtc)
 {
 	int ret;
 	int i;
+	struct drm_device *dev = mtk_crtc->base.dev;
 
 	for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
 		ret = mtk_ddp_comp_clk_enable(mtk_crtc->ddp_comp[i]);
 		if (ret) {
-			DRM_ERROR("Failed to enable clock %d: %d\n", i, ret);
+			drm_err(dev, "Failed to enable clock %d: %d\n", i, ret);
 			goto err;
 		}
 	}
@@ -343,6 +344,7 @@ static int mtk_crtc_ddp_hw_init(struct mtk_crtc *mtk_crtc)
 	struct drm_connector *connector;
 	struct drm_encoder *encoder;
 	struct drm_connector_list_iter conn_iter;
+	struct drm_device *dev = mtk_crtc->base.dev;
 	unsigned int width, height, vrefresh, bpc = MTK_MAX_BPC;
 	int ret;
 	int i;
@@ -371,19 +373,19 @@ static int mtk_crtc_ddp_hw_init(struct mtk_crtc *mtk_crtc)
 
 	ret = pm_runtime_resume_and_get(crtc->dev->dev);
 	if (ret < 0) {
-		DRM_ERROR("Failed to enable power domain: %d\n", ret);
+		drm_err(dev, "Failed to enable power domain: %d\n", ret);
 		return ret;
 	}
 
 	ret = mtk_mutex_prepare(mtk_crtc->mutex);
 	if (ret < 0) {
-		DRM_ERROR("Failed to enable mutex clock: %d\n", ret);
+		drm_err(dev, "Failed to enable mutex clock: %d\n", ret);
 		goto err_pm_runtime_put;
 	}
 
 	ret = mtk_crtc_ddp_clk_enable(mtk_crtc);
 	if (ret < 0) {
-		DRM_ERROR("Failed to enable component clocks: %d\n", ret);
+		drm_err(dev, "Failed to enable component clocks: %d\n", ret);
 		goto err_mutex_unprepare;
 	}
 
@@ -648,10 +650,11 @@ static void mtk_crtc_ddp_irq(void *data)
 	struct mtk_drm_private *priv = crtc->dev->dev_private;
 
 #if IS_REACHABLE(CONFIG_MTK_CMDQ)
+	struct drm_device *dev = mtk_crtc->base.dev;
 	if (!priv->data->shadow_register && !mtk_crtc->cmdq_client.chan)
 		mtk_crtc_ddp_config(crtc, NULL);
 	else if (mtk_crtc->cmdq_vblank_cnt > 0 && --mtk_crtc->cmdq_vblank_cnt == 0)
-		DRM_ERROR("mtk_crtc %d CMDQ execute command timeout!\n",
+		drm_err(dev, "mtk_crtc %d CMDQ execute command timeout!\n",
 			  drm_crtc_index(&mtk_crtc->base));
 #else
 	if (!priv->data->shadow_register)
@@ -776,9 +779,10 @@ static void mtk_crtc_atomic_enable(struct drm_crtc *crtc,
 {
 	struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
 	struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0];
+	struct drm_device *dev = mtk_crtc->base.dev;
 	int ret;
 
-	DRM_DEBUG_DRIVER("%s %d\n", __func__, crtc->base.id);
+	drm_dbg_driver(dev, "%s %d\n", __func__, crtc->base.id);
 
 	ret = mtk_ddp_comp_power_on(comp);
 	if (ret < 0) {
@@ -803,9 +807,10 @@ static void mtk_crtc_atomic_disable(struct drm_crtc *crtc,
 {
 	struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
 	struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0];
+	struct drm_device *dev = mtk_crtc->base.dev;
 	int i;
 
-	DRM_DEBUG_DRIVER("%s %d\n", __func__, crtc->base.id);
+	drm_dbg_driver(dev, "%s %d\n", __func__, crtc->base.id);
 	if (!mtk_crtc->enabled)
 		return;
 
@@ -845,10 +850,11 @@ static void mtk_crtc_atomic_begin(struct drm_crtc *crtc,
 									  crtc);
 	struct mtk_crtc_state *mtk_crtc_state = to_mtk_crtc_state(crtc_state);
 	struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
+	struct drm_device *dev = mtk_crtc->base.dev;
 	unsigned long flags;
 
 	if (mtk_crtc->event && mtk_crtc_state->base.event)
-		DRM_ERROR("new event while there is still a pending event\n");
+		drm_err(dev, "new event while there is still a pending event\n");
 
 	if (mtk_crtc_state->base.event) {
 		mtk_crtc_state->base.event->pipe = drm_crtc_index(crtc);
-- 
2.34.1



From andre.draszik at linaro.org  Tue Dec 23 01:55:15 2025
From: andre.draszik at linaro.org (=?ISO-8859-1?Q?Andr=E9?= Draszik)
Date: Tue, 23 Dec 2025 09:55:15 +0000
Subject: [PATCH v4 2/5] soc: samsung: exynos-chipid: rename method
In-Reply-To: <20251222-gs101-chipid-v4-2-aa8e20ce7bb3@linaro.org>
References: <20251222-gs101-chipid-v4-0-aa8e20ce7bb3@linaro.org>
	 <20251222-gs101-chipid-v4-2-aa8e20ce7bb3@linaro.org>
Message-ID: <bf1bca0af63f161afe351cb0e449896cec11cdcc.camel@linaro.org>

On Mon, 2025-12-22 at 16:30 +0000, Tudor Ambarus wrote:
> s/product_id_to_soc_id/exynos_product_id_to_name.
> Prepend exynos_ to avoid name space pollution. The method translates the
> product id to a name, rename the method to make that clear. While
> touching the code where it is called, add a blank line for readability
> purposes.
> 
> Signed-off-by: Tudor Ambarus <tudor.ambarus at linaro.org>
> ---
> ?drivers/soc/samsung/exynos-chipid.c | 5 +++--
> ?1 file changed, 3 insertions(+), 2 deletions(-)

I'm not sure this change helps with anything, in particular as the
return value is used to assign to soc_id, but in case it gets applied:

Reviewed-by: Andr? Draszik <andre.draszik at linaro.org>

> 
> diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c
> index b9a30452ad21c326af35c06a341b28491cee6979..88d264ef1b8835e15f774ff5a31f5b3de20f74ea 100644
> --- a/drivers/soc/samsung/exynos-chipid.c
> +++ b/drivers/soc/samsung/exynos-chipid.c
> @@ -71,7 +71,7 @@ static const struct exynos_soc_id {
> ?	{ "EXYNOSAUTOV920", 0x0A920000 },
> ?};
> ?
> -static const char *product_id_to_soc_id(unsigned int product_id)
> +static const char *exynos_product_id_to_name(unsigned int product_id)
> ?{
> ?	int i;
> ?
> @@ -150,7 +150,8 @@ static int exynos_chipid_probe(struct platform_device *pdev)
> ?						soc_info.revision);
> ?	if (!soc_dev_attr->revision)
> ?		return -ENOMEM;
> -	soc_dev_attr->soc_id = product_id_to_soc_id(soc_info.product_id);
> +
> +	soc_dev_attr->soc_id = exynos_product_id_to_name(soc_info.product_id);
> ?	if (!soc_dev_attr->soc_id)
> ?		return dev_err_probe(dev, -ENODEV, "Unknown SoC\n");
> ?


From andre.draszik at linaro.org  Tue Dec 23 01:56:45 2025
From: andre.draszik at linaro.org (=?ISO-8859-1?Q?Andr=E9?= Draszik)
Date: Tue, 23 Dec 2025 09:56:45 +0000
Subject: [PATCH v4 4/5] soc: samsung: exynos-chipid: add
 google,gs101-otp support
In-Reply-To: <20251222-gs101-chipid-v4-4-aa8e20ce7bb3@linaro.org>
References: <20251222-gs101-chipid-v4-0-aa8e20ce7bb3@linaro.org>
	 <20251222-gs101-chipid-v4-4-aa8e20ce7bb3@linaro.org>
Message-ID: <2150539a352c802372ffb9dbb3a47cf8b4e8a816.camel@linaro.org>

On Mon, 2025-12-22 at 16:30 +0000, Tudor Ambarus wrote:
> GS101 is different (but also e850 and autov9 I assume) from the SoCs
> that are currently handled by the exynos-chipid driver because the
> chip ID info is part of the OTP registers. GS101 OTP has a clock, an
> interrupt line, a register space (that contains product and chip ID,
> TMU data, ASV, etc) and a 32Kbit memory space that can be
> read/program/locked with specific commands. On GS101 the "ChipID block"
> is just an abstraction, it's not a physical device. When the power-on
> sequence progresses, the OTP chipid values are loaded to the OTP
> registers.
> 
> Add the GS101 chip ID support. The support is intentionally added in the
> exynos-chipid driver, and not in a dedicated Exynos OTP driver, because
> we estimate that there will not be any OTP consumers in the kernel other
> than the chip ID/SoC interface. The downstream GS101 drivers confirm
> this supposition.
> 
> Signed-off-by: Tudor Ambarus <tudor.ambarus at linaro.org>
> ---
> ?drivers/soc/samsung/exynos-chipid.c | 70 ++++++++++++++++++++++++++++++++-----
> ?1 file changed, 61 insertions(+), 9 deletions(-)

Reviewed-by: Andr? Draszik <andre.draszik at linaro.org>


From andre.draszik at linaro.org  Tue Dec 23 02:01:34 2025
From: andre.draszik at linaro.org (=?ISO-8859-1?Q?Andr=E9?= Draszik)
Date: Tue, 23 Dec 2025 10:01:34 +0000
Subject: [PATCH v4 5/5] arm64: dts: exynos: gs101: add OTP node
In-Reply-To: <20251222-gs101-chipid-v4-5-aa8e20ce7bb3@linaro.org>
References: <20251222-gs101-chipid-v4-0-aa8e20ce7bb3@linaro.org>
	 <20251222-gs101-chipid-v4-5-aa8e20ce7bb3@linaro.org>
Message-ID: <28ead866eb9a11fb3f20ad49839aadd3993f3886.camel@linaro.org>

On Mon, 2025-12-22 at 16:30 +0000, Tudor Ambarus wrote:
> Add the OTP controller node.
> 
> Signed-off-by: Tudor Ambarus <tudor.ambarus at linaro.org>
> ---
> ?arch/arm64/boot/dts/exynos/google/gs101.dtsi | 8 ++++++++
> ?1 file changed, 8 insertions(+)

Reviewed-by: Andr? Draszik <andre.draszik at linaro.org>


From bartosz.golaszewski at oss.qualcomm.com  Tue Dec 23 02:02:22 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 11:02:22 +0100
Subject: [PATCH 00/12] i2c: add and start using i2c_adapter-specific printk
 helpers
Message-ID: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>

It's been another year of discussing the object life-time problems at
conferences. I2C is one of the offenders and its problems are more
complex than those of some other subsystems. It seems the revocable[1]
API may make its way into the kernel this year but even with it in
place, I2C won't be able to use it as there's currently nothing to
*revoke*. The struct device is embedded within the i2c_adapter struct
whose lifetime is tied to the provider device being bound to its driver.

Fixing this won't be fast and easy but nothing's going to happen if we
don't start chipping away at it. The ultimate goal in order to be able
to use an SRCU-based solution (revocable or otherwise) is to convert the
embedded struct device in struct i2c_adapter into an __rcu pointer that
can be *revoked*. To that end we need to hide all dereferences of
adap->dev in drivers.

This series addresses the usage of adap->dev in device printk() helpers
(dev_err() et al). It introduces a set of i2c-specific helpers and
starts using them across bus drivers. For now just 12 patches but I'll
keep on doing it if these get accepted. Once these get upstream for
v6.20/7.0, we'll be able to also start converting i2c drivers outside of
drivers/i2c/.

[1] https://lore.kernel.org/all/20251106152330.11733-1-tzungbi at kernel.org/

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
Bartosz Golaszewski (12):
      i2c: add i2c_adapter-specific printk helpers
      i2c: sun6i-p2wi: use i2c_adapter-specific printk helpers
      i2c: mlxbf: use i2c_adapter-specific printk helpers
      i2c: isch: use i2c_adapter-specific printk helpers
      i2c: ali1535: use i2c_adapter-specific printk helpers
      i2c: scmi: use i2c_adapter-specific printk helpers
      i2c: ali15x3: use i2c_adapter-specific printk helpers
      i2c: powermac: use i2c_adapter-specific printk helpers
      i2c: owl: use i2c_adapter-specific printk helpers
      i2c: nforce2: use i2c_adapter-specific printk helpers
      i2c: amd756: use i2c_adapter-specific printk helpers
      i2c: piix4: use i2c_adapter-specific printk helpers

 drivers/i2c/busses/i2c-ali1535.c    | 20 ++++++++++----------
 drivers/i2c/busses/i2c-ali15x3.c    | 20 ++++++++++----------
 drivers/i2c/busses/i2c-amd756.c     | 24 ++++++++++++------------
 drivers/i2c/busses/i2c-isch.c       | 32 ++++++++++++++++----------------
 drivers/i2c/busses/i2c-mlxbf.c      | 19 +++++++++----------
 drivers/i2c/busses/i2c-nforce2.c    | 14 +++++++-------
 drivers/i2c/busses/i2c-owl.c        |  4 ++--
 drivers/i2c/busses/i2c-piix4.c      |  8 ++++----
 drivers/i2c/busses/i2c-powermac.c   | 26 +++++++++++++-------------
 drivers/i2c/busses/i2c-scmi.c       |  6 +++---
 drivers/i2c/busses/i2c-sun6i-p2wi.c |  8 ++++----
 include/linux/i2c.h                 |  6 ++++++
 12 files changed, 96 insertions(+), 91 deletions(-)
---
base-commit: cc3aa43b44bdb43dfbac0fcb51c56594a11338a8
change-id: 20251222-i2c-printk-helpers-a69f4403ca70

Best regards,
-- 
Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>



From bartosz.golaszewski at oss.qualcomm.com  Tue Dec 23 02:02:23 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 11:02:23 +0100
Subject: [PATCH 01/12] i2c: add i2c_adapter-specific printk helpers
In-Reply-To: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>
References: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>
Message-ID: <20251223-i2c-printk-helpers-v1-1-46a08306afdb@oss.qualcomm.com>

Add a set of i2c-specific printk helpers that wrap their device-level
counterparts and hide the dereferencing of struct device embedded in
struct i2c_adapter. This is done in order to allow moving this struct
device out of struct i2c_adapter into memory managed by i2c core.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 include/linux/i2c.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 20fd41b51d5c85ee1665395c07345faafd8e2fca..2225696c859f617479be4d5c9d304bb32cbf5e9d 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -768,6 +768,12 @@ struct i2c_adapter {
 };
 #define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
 
+#define i2c_err(adap, fmt, ...) dev_err(&(adap)->dev, fmt, ##__VA_ARGS__)
+#define i2c_warn(adap, fmt, ...) dev_warn(&(adap)->dev, fmt, ##__VA_ARGS__)
+#define i2c_notice(adap, fmt, ...) dev_notice(&(adap)->dev, fmt, ##__VA_ARGS__)
+#define i2c_info(adap, fmt, ...) dev_info(&(adap)->dev, fmt, ##__VA_ARGS__)
+#define i2c_dbg(adap, fmt, ...) dev_dbg(&(adap)->dev, fmt, ##__VA_ARGS__)
+
 static inline void *i2c_get_adapdata(const struct i2c_adapter *adap)
 {
 	return dev_get_drvdata(&adap->dev);

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Tue Dec 23 02:02:24 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 11:02:24 +0100
Subject: [PATCH 02/12] i2c: sun6i-p2wi: use i2c_adapter-specific printk
 helpers
In-Reply-To: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>
References: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>
Message-ID: <20251223-i2c-printk-helpers-v1-2-46a08306afdb@oss.qualcomm.com>

Convert all instances of using device printk helpers with struct device
embedded in struct i2c_adapter to the new i2c-specific macros that hide
that dereference.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/i2c/busses/i2c-sun6i-p2wi.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/i2c/busses/i2c-sun6i-p2wi.c b/drivers/i2c/busses/i2c-sun6i-p2wi.c
index fb5280b8cf7fc0e3cba8ea6a318172ea2b011a02..845ca56cdae2d056c122eb648c082f319d955b5e 100644
--- a/drivers/i2c/busses/i2c-sun6i-p2wi.c
+++ b/drivers/i2c/busses/i2c-sun6i-p2wi.c
@@ -122,7 +122,7 @@ static int p2wi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
 	unsigned long dlen = P2WI_DLEN_DATA_LENGTH(1);
 
 	if (p2wi->target_addr >= 0 && addr != p2wi->target_addr) {
-		dev_err(&adap->dev, "invalid P2WI address\n");
+		i2c_err(adap, "invalid P2WI address\n");
 		return -EINVAL;
 	}
 
@@ -139,7 +139,7 @@ static int p2wi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
 	writel(dlen, p2wi->regs + P2WI_DLEN);
 
 	if (readl(p2wi->regs + P2WI_CTRL) & P2WI_CTRL_START_TRANS) {
-		dev_err(&adap->dev, "P2WI bus busy\n");
+		i2c_err(adap, "P2WI bus busy\n");
 		return -EBUSY;
 	}
 
@@ -154,12 +154,12 @@ static int p2wi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
 	wait_for_completion(&p2wi->complete);
 
 	if (p2wi->status & P2WI_INTS_LOAD_BSY) {
-		dev_err(&adap->dev, "P2WI bus busy\n");
+		i2c_err(adap, "P2WI bus busy\n");
 		return -EBUSY;
 	}
 
 	if (p2wi->status & P2WI_INTS_TRANS_ERR) {
-		dev_err(&adap->dev, "P2WI bus xfer error\n");
+		i2c_err(adap, "P2WI bus xfer error\n");
 		return -ENXIO;
 	}
 

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Tue Dec 23 02:02:25 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 11:02:25 +0100
Subject: [PATCH 03/12] i2c: mlxbf: use i2c_adapter-specific printk helpers
In-Reply-To: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>
References: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>
Message-ID: <20251223-i2c-printk-helpers-v1-3-46a08306afdb@oss.qualcomm.com>

Convert all instances of using device printk helpers with struct device
embedded in struct i2c_adapter to the new i2c-specific macros that hide
that dereference.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/i2c/busses/i2c-mlxbf.c | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/drivers/i2c/busses/i2c-mlxbf.c b/drivers/i2c/busses/i2c-mlxbf.c
index 8345f7e6385df64bcd3a82021df3f1e04524c6c5..78a7e893b572a682133b3cea200f571f1977ca1e 100644
--- a/drivers/i2c/busses/i2c-mlxbf.c
+++ b/drivers/i2c/busses/i2c-mlxbf.c
@@ -2045,28 +2045,28 @@ static s32 mlxbf_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr,
 	switch (size) {
 	case I2C_SMBUS_QUICK:
 		mlxbf_i2c_smbus_quick_command(&request, read);
-		dev_dbg(&adap->dev, "smbus quick, slave 0x%02x\n", addr);
+		i2c_dbg(adap, "smbus quick, slave 0x%02x\n", addr);
 		break;
 
 	case I2C_SMBUS_BYTE:
 		mlxbf_i2c_smbus_byte_func(&request,
 					  read ? &data->byte : &command, read,
 					  pec);
-		dev_dbg(&adap->dev, "smbus %s byte, slave 0x%02x.\n",
+		i2c_dbg(adap, "smbus %s byte, slave 0x%02x.\n",
 			str_read_write(read), addr);
 		break;
 
 	case I2C_SMBUS_BYTE_DATA:
 		mlxbf_i2c_smbus_data_byte_func(&request, &command, &data->byte,
 					       read, pec);
-		dev_dbg(&adap->dev, "smbus %s byte data at 0x%02x, slave 0x%02x.\n",
+		i2c_dbg(adap, "smbus %s byte data at 0x%02x, slave 0x%02x.\n",
 			str_read_write(read), command, addr);
 		break;
 
 	case I2C_SMBUS_WORD_DATA:
 		mlxbf_i2c_smbus_data_word_func(&request, &command,
 					       (u8 *)&data->word, read, pec);
-		dev_dbg(&adap->dev, "smbus %s word data at 0x%02x, slave 0x%02x.\n",
+		i2c_dbg(adap, "smbus %s word data at 0x%02x, slave 0x%02x.\n",
 			str_read_write(read), command, addr);
 		break;
 
@@ -2074,7 +2074,7 @@ static s32 mlxbf_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr,
 		byte_cnt = data->block[0];
 		mlxbf_i2c_smbus_i2c_block_func(&request, &command, data->block,
 					       &byte_cnt, read, pec);
-		dev_dbg(&adap->dev, "i2c %s block data, %d bytes at 0x%02x, slave 0x%02x.\n",
+		i2c_dbg(adap, "i2c %s block data, %d bytes at 0x%02x, slave 0x%02x.\n",
 			str_read_write(read), byte_cnt, command, addr);
 		break;
 
@@ -2082,14 +2082,14 @@ static s32 mlxbf_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr,
 		byte_cnt = read ? I2C_SMBUS_BLOCK_MAX : data->block[0];
 		mlxbf_i2c_smbus_block_func(&request, &command, data->block,
 					   &byte_cnt, read, pec);
-		dev_dbg(&adap->dev, "smbus %s block data, %d bytes at 0x%02x, slave 0x%02x.\n",
+		i2c_dbg(adap, "smbus %s block data, %d bytes at 0x%02x, slave 0x%02x.\n",
 			str_read_write(read), byte_cnt, command, addr);
 		break;
 
 	case I2C_FUNC_SMBUS_PROC_CALL:
 		mlxbf_i2c_smbus_process_call_func(&request, &command,
 						  (u8 *)&data->word, pec);
-		dev_dbg(&adap->dev, "process call, wr/rd at 0x%02x, slave 0x%02x.\n",
+		i2c_dbg(adap, "process call, wr/rd at 0x%02x, slave 0x%02x.\n",
 			command, addr);
 		break;
 
@@ -2098,13 +2098,12 @@ static s32 mlxbf_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr,
 		mlxbf_i2c_smbus_blk_process_call_func(&request, &command,
 						      data->block, &byte_cnt,
 						      pec);
-		dev_dbg(&adap->dev, "block process call, wr/rd %d bytes, slave 0x%02x.\n",
+		i2c_dbg(adap, "block process call, wr/rd %d bytes, slave 0x%02x.\n",
 			byte_cnt, addr);
 		break;
 
 	default:
-		dev_dbg(&adap->dev, "Unsupported I2C/SMBus command %d\n",
-			size);
+		i2c_dbg(adap, "Unsupported I2C/SMBus command %d\n", size);
 		return -EOPNOTSUPP;
 	}
 

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Tue Dec 23 02:02:26 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 11:02:26 +0100
Subject: [PATCH 04/12] i2c: isch: use i2c_adapter-specific printk helpers
In-Reply-To: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>
References: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>
Message-ID: <20251223-i2c-printk-helpers-v1-4-46a08306afdb@oss.qualcomm.com>

Convert all instances of using device printk helpers with struct device
embedded in struct i2c_adapter to the new i2c-specific macros that hide
that dereference.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/i2c/busses/i2c-isch.c | 32 ++++++++++++++++----------------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/drivers/i2c/busses/i2c-isch.c b/drivers/i2c/busses/i2c-isch.c
index a2ac992f9cb0d2accfaa979b802b98c3b7fbe3af..6ff07ab12e30db6821cadea4de3a588b9023ea20 100644
--- a/drivers/i2c/busses/i2c-isch.c
+++ b/drivers/i2c/busses/i2c-isch.c
@@ -86,7 +86,7 @@ static int sch_transaction(struct i2c_adapter *adap)
 	int temp;
 	int rc;
 
-	dev_dbg(&adap->dev,
+	i2c_dbg(adap,
 		"Transaction (pre): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
 		sch_io_rd8(priv, SMBHSTCNT), sch_io_rd8(priv, SMBHSTCMD),
 		sch_io_rd8(priv, SMBHSTADD),
@@ -97,13 +97,13 @@ static int sch_transaction(struct i2c_adapter *adap)
 	if (temp) {
 		/* Can not be busy since we checked it in sch_access */
 		if (temp & 0x01)
-			dev_dbg(&adap->dev, "Completion (%02x). Clear...\n", temp);
+			i2c_dbg(adap, "Completion (%02x). Clear...\n", temp);
 		if (temp & 0x06)
-			dev_dbg(&adap->dev, "SMBus error (%02x). Resetting...\n", temp);
+			i2c_dbg(adap, "SMBus error (%02x). Resetting...\n", temp);
 		sch_io_wr8(priv, SMBHSTSTS, temp);
 		temp = sch_io_rd8(priv, SMBHSTSTS) & 0x0f;
 		if (temp) {
-			dev_err(&adap->dev, "SMBus is not ready: (%02x)\n", temp);
+			i2c_err(adap, "SMBus is not ready: (%02x)\n", temp);
 			return -EAGAIN;
 		}
 	}
@@ -116,28 +116,28 @@ static int sch_transaction(struct i2c_adapter *adap)
 	rc = read_poll_timeout(sch_io_rd8, temp, !(temp & 0x08), 200, 500000, true, priv, SMBHSTSTS);
 	/* If the SMBus is still busy, we give up */
 	if (rc) {
-		dev_err(&adap->dev, "SMBus Timeout!\n");
+		i2c_err(adap, "SMBus Timeout!\n");
 	} else if (temp & 0x04) {
 		rc = -EIO;
-		dev_dbg(&adap->dev, "Bus collision! SMBus may be locked until next hard reset. (sorry!)\n");
+		i2c_dbg(adap, "Bus collision! SMBus may be locked until next hard reset. (sorry!)\n");
 		/* Clock stops and target is stuck in mid-transmission */
 	} else if (temp & 0x02) {
 		rc = -EIO;
-		dev_err(&adap->dev, "Error: no response!\n");
+		i2c_err(adap, "Error: no response!\n");
 	} else if (temp & 0x01) {
-		dev_dbg(&adap->dev, "Post complete!\n");
+		i2c_dbg(adap, "Post complete!\n");
 		sch_io_wr8(priv, SMBHSTSTS, temp & 0x0f);
 		temp = sch_io_rd8(priv, SMBHSTSTS) & 0x07;
 		if (temp & 0x06) {
 			/* Completion clear failed */
-			dev_dbg(&adap->dev,
+			i2c_dbg(adap,
 				"Failed reset at end of transaction (%02x), Bus error!\n", temp);
 		}
 	} else {
 		rc = -ENXIO;
-		dev_dbg(&adap->dev, "No such address.\n");
+		i2c_dbg(adap, "No such address.\n");
 	}
-	dev_dbg(&adap->dev, "Transaction (post): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
+	i2c_dbg(adap, "Transaction (post): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
 		sch_io_rd8(priv, SMBHSTCNT), sch_io_rd8(priv, SMBHSTCMD),
 		sch_io_rd8(priv, SMBHSTADD),
 		sch_io_rd8(priv, SMBHSTDAT0), sch_io_rd8(priv, SMBHSTDAT1));
@@ -166,7 +166,7 @@ static s32 sch_access(struct i2c_adapter *adap, u16 addr,
 	/* Make sure the SMBus host is not busy */
 	temp = sch_io_rd8(priv, SMBHSTSTS) & 0x0f;
 	if (temp & 0x08) {
-		dev_dbg(&adap->dev, "SMBus busy (%02x)\n", temp);
+		i2c_dbg(adap, "SMBus busy (%02x)\n", temp);
 		return -EAGAIN;
 	}
 	temp = sch_io_rd16(priv, SMBHSTCLK);
@@ -177,11 +177,11 @@ static s32 sch_access(struct i2c_adapter *adap, u16 addr,
 		 * 100 kHz. If we actually run at 25 MHz the bus will be
 		 * run ~75 kHz instead which should do no harm.
 		 */
-		dev_notice(&adap->dev, "Clock divider uninitialized. Setting defaults\n");
+		i2c_notice(adap, "Clock divider uninitialized. Setting defaults\n");
 		sch_io_wr16(priv, SMBHSTCLK, backbone_speed / (4 * 100));
 	}
 
-	dev_dbg(&adap->dev, "access size: %d %s\n", size, str_read_write(read_write));
+	i2c_dbg(adap, "access size: %d %s\n", size, str_read_write(read_write));
 	switch (size) {
 	case I2C_SMBUS_QUICK:
 		sch_io_wr8(priv, SMBHSTADD, (addr << 1) | read_write);
@@ -223,10 +223,10 @@ static s32 sch_access(struct i2c_adapter *adap, u16 addr,
 		size = SCH_BLOCK_DATA;
 		break;
 	default:
-		dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+		i2c_warn(adap, "Unsupported transaction %d\n", size);
 		return -EOPNOTSUPP;
 	}
-	dev_dbg(&adap->dev, "write size %d to 0x%04x\n", size, SMBHSTCNT);
+	i2c_dbg(adap, "write size %d to 0x%04x\n", size, SMBHSTCNT);
 
 	temp = sch_io_rd8(priv, SMBHSTCNT);
 	temp = (temp & 0xb0) | (size & 0x7);

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Tue Dec 23 02:02:27 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 11:02:27 +0100
Subject: [PATCH 05/12] i2c: ali1535: use i2c_adapter-specific printk
 helpers
In-Reply-To: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>
References: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>
Message-ID: <20251223-i2c-printk-helpers-v1-5-46a08306afdb@oss.qualcomm.com>

Convert all instances of using device printk helpers with struct device
embedded in struct i2c_adapter to the new i2c-specific macros that hide
that dereference.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/i2c/busses/i2c-ali1535.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c
index 1eac358380405838d15551e353605cab0a7e5e65..bf0f36450c5930f86b122618d17eecf1782dd776 100644
--- a/drivers/i2c/busses/i2c-ali1535.c
+++ b/drivers/i2c/busses/i2c-ali1535.c
@@ -215,7 +215,7 @@ static int ali1535_transaction(struct i2c_adapter *adap)
 	int result = 0;
 	int timeout = 0;
 
-	dev_dbg(&adap->dev, "Transaction (pre): STS=%02x, TYP=%02x, "
+	i2c_dbg(adap, "Transaction (pre): STS=%02x, TYP=%02x, "
 		"CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
 		inb_p(SMBHSTSTS), inb_p(SMBHSTTYP), inb_p(SMBHSTCMD),
 		inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
@@ -245,7 +245,7 @@ static int ali1535_transaction(struct i2c_adapter *adap)
 		 * BUSY bit may come back on when you try and use the chip
 		 * again.  If that's the case you are stuck.
 		 */
-		dev_info(&adap->dev,
+		i2c_info(adap,
 			"Resetting entire SMB Bus to clear busy condition (%02x)\n",
 			temp);
 		outb_p(ALI1535_T_OUT, SMBHSTTYP);
@@ -262,7 +262,7 @@ static int ali1535_transaction(struct i2c_adapter *adap)
 			 * power reset as one of the bits now appears to be
 			 * stuck */
 			/* This may be a bus or device with electrical problems. */
-			dev_err(&adap->dev,
+			i2c_err(adap,
 				"SMBus reset failed! (0x%02x) - controller or "
 				"device on bus is probably hung\n", temp);
 			return -EBUSY;
@@ -290,7 +290,7 @@ static int ali1535_transaction(struct i2c_adapter *adap)
 
 	if (temp & ALI1535_STS_FAIL) {
 		result = -EIO;
-		dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
+		i2c_dbg(adap, "Error: Failed bus transaction\n");
 	}
 
 	/* Unfortunately the ALI SMB controller maps "no response" and "bus
@@ -299,7 +299,7 @@ static int ali1535_transaction(struct i2c_adapter *adap)
 	 */
 	if (temp & ALI1535_STS_BUSERR) {
 		result = -ENXIO;
-		dev_dbg(&adap->dev,
+		i2c_dbg(adap,
 			"Error: no response or bus collision ADD=%02x\n",
 			inb_p(SMBHSTADD));
 	}
@@ -307,14 +307,14 @@ static int ali1535_transaction(struct i2c_adapter *adap)
 	/* haven't ever seen this */
 	if (temp & ALI1535_STS_DEV) {
 		result = -EIO;
-		dev_err(&adap->dev, "Error: device error\n");
+		i2c_err(adap, "Error: device error\n");
 	}
 
 	/* check to see if the "command complete" indication is set */
 	if (!(temp & ALI1535_STS_DONE))
 		result = -ETIMEDOUT;
 
-	dev_dbg(&adap->dev, "Transaction (post): STS=%02x, TYP=%02x, "
+	i2c_dbg(adap, "Transaction (post): STS=%02x, TYP=%02x, "
 		"CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
 		inb_p(SMBHSTSTS), inb_p(SMBHSTTYP), inb_p(SMBHSTCMD),
 		inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
@@ -352,7 +352,7 @@ static s32 ali1535_access(struct i2c_adapter *adap, u16 addr,
 		temp = inb_p(SMBHSTSTS);
 	}
 	if (timeout >= MAX_TIMEOUT)
-		dev_warn(&adap->dev, "Idle wait Timeout! STS=0x%02x\n", temp);
+		i2c_warn(adap, "Idle wait Timeout! STS=0x%02x\n", temp);
 
 	/* clear status register (clear-on-write) */
 	outb_p(0xFF, SMBHSTSTS);
@@ -416,7 +416,7 @@ static s32 ali1535_access(struct i2c_adapter *adap, u16 addr,
 		}
 		break;
 	default:
-		dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+		i2c_warn(adap, "Unsupported transaction %d\n", size);
 		result = -EOPNOTSUPP;
 		goto EXIT;
 	}
@@ -449,7 +449,7 @@ static s32 ali1535_access(struct i2c_adapter *adap, u16 addr,
 		outb_p(inb_p(SMBHSTTYP) | ALI1535_BLOCK_CLR, SMBHSTTYP);
 		for (i = 1; i <= data->block[0]; i++) {
 			data->block[i] = inb_p(SMBBLKDAT);
-			dev_dbg(&adap->dev, "Blk: len=%d, i=%d, data=%02x\n",
+			i2c_dbg(adap, "Blk: len=%d, i=%d, data=%02x\n",
 				len, i, data->block[i]);
 		}
 		break;

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Tue Dec 23 02:02:28 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 11:02:28 +0100
Subject: [PATCH 06/12] i2c: scmi: use i2c_adapter-specific printk helpers
In-Reply-To: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>
References: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>
Message-ID: <20251223-i2c-printk-helpers-v1-6-46a08306afdb@oss.qualcomm.com>

Convert all instances of using device printk helpers with struct device
embedded in struct i2c_adapter to the new i2c-specific macros that hide
that dereference.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/i2c/busses/i2c-scmi.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/i2c/busses/i2c-scmi.c b/drivers/i2c/busses/i2c-scmi.c
index 10a5146b3aa5fc6edb4c2f3e1cc57750041b7087..96a2cd70d367f485d5f230be4eaf124398b0f239 100644
--- a/drivers/i2c/busses/i2c-scmi.c
+++ b/drivers/i2c/busses/i2c-scmi.c
@@ -87,7 +87,7 @@ acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
 	char *method;
 	int len = 0;
 
-	dev_dbg(&adap->dev, "access size: %d %s\n", size,
+	i2c_dbg(adap, "access size: %d %s\n", size,
 		(read_write) ? "READ" : "WRITE");
 	switch (size) {
 	case I2C_SMBUS_QUICK:
@@ -148,7 +148,7 @@ acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
 		break;
 
 	default:
-		dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+		i2c_warn(adap, "Unsupported transaction %d\n", size);
 		return -EOPNOTSUPP;
 	}
 
@@ -257,7 +257,7 @@ acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
 
 out:
 	kfree(buffer.pointer);
-	dev_dbg(&adap->dev, "Transaction status: %i\n", result);
+	i2c_dbg(adap, "Transaction status: %i\n", result);
 	return result;
 }
 

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Tue Dec 23 02:02:29 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 11:02:29 +0100
Subject: [PATCH 07/12] i2c: ali15x3: use i2c_adapter-specific printk
 helpers
In-Reply-To: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>
References: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>
Message-ID: <20251223-i2c-printk-helpers-v1-7-46a08306afdb@oss.qualcomm.com>

Convert all instances of using device printk helpers with struct device
embedded in struct i2c_adapter to the new i2c-specific macros that hide
that dereference.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/i2c/busses/i2c-ali15x3.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c
index 418d11266671e314aa2fb882ece025dc0ae998da..bd62aa8d645004bef121fa46efc1d7afc473332a 100644
--- a/drivers/i2c/busses/i2c-ali15x3.c
+++ b/drivers/i2c/busses/i2c-ali15x3.c
@@ -223,7 +223,7 @@ static int ali15x3_transaction(struct i2c_adapter *adap)
 	int result = 0;
 	int timeout = 0;
 
-	dev_dbg(&adap->dev, "Transaction (pre): STS=%02x, CNT=%02x, CMD=%02x, "
+	i2c_dbg(adap, "Transaction (pre): STS=%02x, CNT=%02x, CMD=%02x, "
 		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS),
 		inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
 		inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
@@ -255,7 +255,7 @@ static int ali15x3_transaction(struct i2c_adapter *adap)
 	   then the BUSY bit may come back on when you try and use the chip again.
 	   If that's the case you are stuck.
 	*/
-		dev_info(&adap->dev, "Resetting entire SMB Bus to "
+		i2c_info(adap, "Resetting entire SMB Bus to "
 			"clear busy condition (%02x)\n", temp);
 		outb_p(ALI15X3_T_OUT, SMBHSTCNT);
 		temp = inb_p(SMBHSTSTS);
@@ -270,7 +270,7 @@ static int ali15x3_transaction(struct i2c_adapter *adap)
 			/* this is probably going to be correctable only by a power reset
 			   as one of the bits now appears to be stuck */
 			/* This may be a bus or device with electrical problems. */
-			dev_err(&adap->dev, "SMBus reset failed! (0x%02x) - "
+			i2c_err(adap, "SMBus reset failed! (0x%02x) - "
 				"controller or device on bus is probably hung\n",
 				temp);
 			return -EBUSY;
@@ -299,7 +299,7 @@ static int ali15x3_transaction(struct i2c_adapter *adap)
 
 	if (temp & ALI15X3_STS_TERM) {
 		result = -EIO;
-		dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
+		i2c_dbg(adap, "Error: Failed bus transaction\n");
 	}
 
 	/*
@@ -310,7 +310,7 @@ static int ali15x3_transaction(struct i2c_adapter *adap)
 	*/
 	if (temp & ALI15X3_STS_COLL) {
 		result = -ENXIO;
-		dev_dbg(&adap->dev,
+		i2c_dbg(adap,
 			"Error: no response or bus collision ADD=%02x\n",
 			inb_p(SMBHSTADD));
 	}
@@ -318,9 +318,9 @@ static int ali15x3_transaction(struct i2c_adapter *adap)
 	/* haven't ever seen this */
 	if (temp & ALI15X3_STS_DEV) {
 		result = -EIO;
-		dev_err(&adap->dev, "Error: device error\n");
+		i2c_err(adap, "Error: device error\n");
 	}
-	dev_dbg(&adap->dev, "Transaction (post): STS=%02x, CNT=%02x, CMD=%02x, "
+	i2c_dbg(adap, "Transaction (post): STS=%02x, CNT=%02x, CMD=%02x, "
 		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS),
 		inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
 		inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
@@ -347,7 +347,7 @@ static s32 ali15x3_access(struct i2c_adapter * adap, u16 addr,
 		temp = inb_p(SMBHSTSTS);
 	}
 	if (timeout >= MAX_TIMEOUT) {
-		dev_err(&adap->dev, "Idle wait Timeout! STS=0x%02x\n", temp);
+		i2c_err(adap, "Idle wait Timeout! STS=0x%02x\n", temp);
 	}
 
 	switch (size) {
@@ -404,7 +404,7 @@ static s32 ali15x3_access(struct i2c_adapter * adap, u16 addr,
 		size = ALI15X3_BLOCK_DATA;
 		break;
 	default:
-		dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+		i2c_warn(adap, "Unsupported transaction %d\n", size);
 		return -EOPNOTSUPP;
 	}
 
@@ -437,7 +437,7 @@ static s32 ali15x3_access(struct i2c_adapter * adap, u16 addr,
 		outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT);
 		for (i = 1; i <= data->block[0]; i++) {
 			data->block[i] = inb_p(SMBBLKDAT);
-			dev_dbg(&adap->dev, "Blk: len=%d, i=%d, data=%02x\n",
+			i2c_dbg(adap, "Blk: len=%d, i=%d, data=%02x\n",
 				len, i, data->block[i]);
 		}
 		break;

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Tue Dec 23 02:02:30 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 11:02:30 +0100
Subject: [PATCH 08/12] i2c: powermac: use i2c_adapter-specific printk
 helpers
In-Reply-To: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>
References: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>
Message-ID: <20251223-i2c-printk-helpers-v1-8-46a08306afdb@oss.qualcomm.com>

Convert all instances of using device printk helpers with struct device
embedded in struct i2c_adapter to the new i2c-specific macros that hide
that dereference.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/i2c/busses/i2c-powermac.c | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
index f99a2cc721a81dc328bc03ea88ff959cafe0f05a..fb5482655d6c5c617392e9ccd745433d5d828335 100644
--- a/drivers/i2c/busses/i2c-powermac.c
+++ b/drivers/i2c/busses/i2c-powermac.c
@@ -92,13 +92,13 @@ static s32 i2c_powermac_smbus_xfer(	struct i2c_adapter*	adap,
 
 	rc = pmac_i2c_open(bus, 0);
 	if (rc) {
-		dev_err(&adap->dev, "Failed to open I2C, err %d\n", rc);
+		i2c_err(adap, "Failed to open I2C, err %d\n", rc);
 		return rc;
 	}
 
 	rc = pmac_i2c_setmode(bus, mode);
 	if (rc) {
-		dev_err(&adap->dev, "Failed to set I2C mode %d, err %d\n",
+		i2c_err(adap, "Failed to set I2C mode %d, err %d\n",
 			mode, rc);
 		goto bail;
 	}
@@ -106,11 +106,11 @@ static s32 i2c_powermac_smbus_xfer(	struct i2c_adapter*	adap,
 	rc = pmac_i2c_xfer(bus, addrdir, subsize, subaddr, buf, len);
 	if (rc) {
 		if (rc == -ENXIO)
-			dev_dbg(&adap->dev,
+			i2c_dbg(adap,
 				"I2C transfer at 0x%02x failed, size %d, "
 				"err %d\n", addrdir >> 1, size, rc);
 		else
-			dev_err(&adap->dev,
+			i2c_err(adap,
 				"I2C transfer at 0x%02x failed, size %d, "
 				"err %d\n", addrdir >> 1, size, rc);
 		goto bail;
@@ -145,23 +145,23 @@ static int i2c_powermac_xfer(struct i2c_adapter *adap,
 
 	rc = pmac_i2c_open(bus, 0);
 	if (rc) {
-		dev_err(&adap->dev, "Failed to open I2C, err %d\n", rc);
+		i2c_err(adap, "Failed to open I2C, err %d\n", rc);
 		return rc;
 	}
 	rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
 	if (rc) {
-		dev_err(&adap->dev, "Failed to set I2C mode %d, err %d\n",
+		i2c_err(adap, "Failed to set I2C mode %d, err %d\n",
 			pmac_i2c_mode_std, rc);
 		goto bail;
 	}
 	rc = pmac_i2c_xfer(bus, addrdir, 0, 0, msgs->buf, msgs->len);
 	if (rc < 0) {
 		if (rc == -ENXIO)
-			dev_dbg(&adap->dev, "I2C %s 0x%02x failed, err %d\n",
+			i2c_dbg(adap, "I2C %s 0x%02x failed, err %d\n",
 				addrdir & 1 ? "read from" : "write to",
 				addrdir >> 1, rc);
 		else
-			dev_err(&adap->dev, "I2C %s 0x%02x failed, err %d\n",
+			i2c_err(adap, "I2C %s 0x%02x failed, err %d\n",
 				addrdir & 1 ? "read from" : "write to",
 				addrdir >> 1, rc);
 	}
@@ -219,7 +219,7 @@ static u32 i2c_powermac_get_addr(struct i2c_adapter *adap,
 	else if (of_node_name_eq(node, "deq"))
 		return 0x34;
 
-	dev_warn(&adap->dev, "No i2c address for %pOF\n", node);
+	i2c_warn(adap, "No i2c address for %pOF\n", node);
 
 	return 0xffffffff;
 }
@@ -235,7 +235,7 @@ static void i2c_powermac_create_one(struct i2c_adapter *adap,
 	info.addr = addr;
 	newdev = i2c_new_client_device(adap, &info);
 	if (IS_ERR(newdev))
-		dev_err(&adap->dev,
+		i2c_err(adap,
 			"i2c-powermac: Failure to register missing %s\n",
 			type);
 }
@@ -299,7 +299,7 @@ static bool i2c_powermac_get_type(struct i2c_adapter *adap,
 		}
 	}
 
-	dev_err(&adap->dev, "i2c-powermac: modalias failure on %pOF\n", node);
+	i2c_err(adap, "i2c-powermac: modalias failure on %pOF\n", node);
 	return false;
 }
 
@@ -331,7 +331,7 @@ static void i2c_powermac_register_devices(struct i2c_adapter *adap,
 		if (!pmac_i2c_match_adapter(node, adap))
 			continue;
 
-		dev_dbg(&adap->dev, "i2c-powermac: register %pOF\n", node);
+		i2c_dbg(adap, "i2c-powermac: register %pOF\n", node);
 
 		/*
 		 * Keep track of some device existence to handle
@@ -353,7 +353,7 @@ static void i2c_powermac_register_devices(struct i2c_adapter *adap,
 
 		newdev = i2c_new_client_device(adap, &info);
 		if (IS_ERR(newdev)) {
-			dev_err(&adap->dev, "i2c-powermac: Failure to register"
+			i2c_err(adap, "i2c-powermac: Failure to register"
 				" %pOF\n", node);
 			of_node_put(node);
 			/* We do not dispose of the interrupt mapping on

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Tue Dec 23 02:02:31 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 11:02:31 +0100
Subject: [PATCH 09/12] i2c: owl: use i2c_adapter-specific printk helpers
In-Reply-To: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>
References: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>
Message-ID: <20251223-i2c-printk-helpers-v1-9-46a08306afdb@oss.qualcomm.com>

Convert all instances of using device printk helpers with struct device
embedded in struct i2c_adapter to the new i2c-specific macros that hide
that dereference.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/i2c/busses/i2c-owl.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-owl.c b/drivers/i2c/busses/i2c-owl.c
index 84a195e358866d693fb6d435a5beaaee640fd2e2..17718f15a0f1fd238bb4a6f23dbb4f9696969ed5 100644
--- a/drivers/i2c/busses/i2c-owl.c
+++ b/drivers/i2c/busses/i2c-owl.c
@@ -241,7 +241,7 @@ static int owl_i2c_check_bus_busy(struct i2c_adapter *adap)
 	timeout = jiffies + OWL_I2C_TIMEOUT;
 	while (readl(i2c_dev->base + OWL_I2C_REG_STAT) & OWL_I2C_STAT_BBB) {
 		if (time_after(jiffies, timeout)) {
-			dev_err(&adap->dev, "Bus busy timeout\n");
+			i2c_err(adap, "Bus busy timeout\n");
 			return -ETIMEDOUT;
 		}
 	}
@@ -383,7 +383,7 @@ static int owl_i2c_xfer_common(struct i2c_adapter *adap, struct i2c_msg *msgs,
 	spin_lock_irqsave(&i2c_dev->lock, flags);
 
 	if (ret) {
-		dev_err(&adap->dev, "Transaction timed out\n");
+		i2c_err(adap, "Transaction timed out\n");
 		/* Send stop condition and release the bus */
 		owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL,
 				   OWL_I2C_CTL_GBCC_STOP | OWL_I2C_CTL_RB,

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Tue Dec 23 02:02:32 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 11:02:32 +0100
Subject: [PATCH 10/12] i2c: nforce2: use i2c_adapter-specific printk
 helpers
In-Reply-To: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>
References: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>
Message-ID: <20251223-i2c-printk-helpers-v1-10-46a08306afdb@oss.qualcomm.com>

Convert all instances of using device printk helpers with struct device
embedded in struct i2c_adapter to the new i2c-specific macros that hide
that dereference.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/i2c/busses/i2c-nforce2.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index d58a308582e47650238312537d2d721261d3bca4..2fa6f1dbd27a92c2d67915775e588e4bab675d76 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -123,7 +123,7 @@ static void nforce2_abort(struct i2c_adapter *adap)
 	int timeout = 0;
 	unsigned char temp;
 
-	dev_dbg(&adap->dev, "Aborting current transaction\n");
+	i2c_dbg(adap, "Aborting current transaction\n");
 
 	outb_p(NVIDIA_SMB_CTRL_ABORT, NVIDIA_SMB_CTRL);
 	do {
@@ -132,7 +132,7 @@ static void nforce2_abort(struct i2c_adapter *adap)
 	} while (!(temp & NVIDIA_SMB_STATUS_ABRT_STS) &&
 			(timeout++ < MAX_TIMEOUT));
 	if (!(temp & NVIDIA_SMB_STATUS_ABRT_STS))
-		dev_err(&adap->dev, "Can't reset the smbus\n");
+		i2c_err(adap, "Can't reset the smbus\n");
 	outb_p(NVIDIA_SMB_STATUS_ABRT_STS, NVIDIA_SMB_STATUS_ABRT);
 }
 
@@ -148,13 +148,13 @@ static int nforce2_check_status(struct i2c_adapter *adap)
 	} while ((!temp) && (timeout++ < MAX_TIMEOUT));
 
 	if (timeout > MAX_TIMEOUT) {
-		dev_dbg(&adap->dev, "SMBus Timeout!\n");
+		i2c_dbg(adap, "SMBus Timeout!\n");
 		if (smbus->can_abort)
 			nforce2_abort(adap);
 		return -ETIMEDOUT;
 	}
 	if (!(temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) {
-		dev_dbg(&adap->dev, "Transaction failed (0x%02x)!\n", temp);
+		i2c_dbg(adap, "Transaction failed (0x%02x)!\n", temp);
 		return -EIO;
 	}
 	return 0;
@@ -207,7 +207,7 @@ static s32 nforce2_access(struct i2c_adapter *adap, u16 addr,
 		if (read_write == I2C_SMBUS_WRITE) {
 			len = data->block[0];
 			if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX)) {
-				dev_err(&adap->dev,
+				i2c_err(adap,
 					"Transaction failed (requested block size: %d)\n",
 					len);
 				return -EINVAL;
@@ -221,7 +221,7 @@ static s32 nforce2_access(struct i2c_adapter *adap, u16 addr,
 		break;
 
 	default:
-		dev_err(&adap->dev, "Unsupported transaction %d\n", size);
+		i2c_err(adap, "Unsupported transaction %d\n", size);
 		return -EOPNOTSUPP;
 	}
 
@@ -249,7 +249,7 @@ static s32 nforce2_access(struct i2c_adapter *adap, u16 addr,
 	case I2C_SMBUS_BLOCK_DATA:
 		len = inb_p(NVIDIA_SMB_BCNT);
 		if ((len <= 0) || (len > I2C_SMBUS_BLOCK_MAX)) {
-			dev_err(&adap->dev,
+			i2c_err(adap,
 				"Transaction failed (received block size: 0x%02x)\n",
 				len);
 			return -EPROTO;

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Tue Dec 23 02:02:33 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 11:02:33 +0100
Subject: [PATCH 11/12] i2c: amd756: use i2c_adapter-specific printk helpers
In-Reply-To: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>
References: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>
Message-ID: <20251223-i2c-printk-helpers-v1-11-46a08306afdb@oss.qualcomm.com>

Convert all instances of using device printk helpers with struct device
embedded in struct i2c_adapter to the new i2c-specific macros that hide
that dereference.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/i2c/busses/i2c-amd756.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c
index 3621c02f1cbabd8c5e9d8a4ae1494ada78726b15..629da0b8024b88cc4d51ea5e785147b462a1281c 100644
--- a/drivers/i2c/busses/i2c-amd756.c
+++ b/drivers/i2c/busses/i2c-amd756.c
@@ -99,14 +99,14 @@ static int amd756_transaction(struct i2c_adapter *adap)
 	int result = 0;
 	int timeout = 0;
 
-	dev_dbg(&adap->dev, "Transaction (pre): GS=%04x, GE=%04x, ADD=%04x, "
+	i2c_dbg(adap, "Transaction (pre): GS=%04x, GE=%04x, ADD=%04x, "
 		"DAT=%04x\n", inw_p(SMB_GLOBAL_STATUS),
 		inw_p(SMB_GLOBAL_ENABLE), inw_p(SMB_HOST_ADDRESS),
 		inb_p(SMB_HOST_DATA));
 
 	/* Make sure the SMBus host is ready to start transmitting */
 	if ((temp = inw_p(SMB_GLOBAL_STATUS)) & (GS_HST_STS | GS_SMB_STS)) {
-		dev_dbg(&adap->dev, "SMBus busy (%04x). Waiting...\n", temp);
+		i2c_dbg(adap, "SMBus busy (%04x). Waiting...\n", temp);
 		do {
 			msleep(1);
 			temp = inw_p(SMB_GLOBAL_STATUS);
@@ -114,7 +114,7 @@ static int amd756_transaction(struct i2c_adapter *adap)
 		         (timeout++ < MAX_TIMEOUT));
 		/* If the SMBus is still busy, we give up */
 		if (timeout > MAX_TIMEOUT) {
-			dev_dbg(&adap->dev, "Busy wait timeout (%04x)\n", temp);
+			i2c_dbg(adap, "Busy wait timeout (%04x)\n", temp);
 			goto abort;
 		}
 		timeout = 0;
@@ -131,38 +131,38 @@ static int amd756_transaction(struct i2c_adapter *adap)
 
 	/* If the SMBus is still busy, we give up */
 	if (timeout > MAX_TIMEOUT) {
-		dev_dbg(&adap->dev, "Completion timeout!\n");
+		i2c_dbg(adap, "Completion timeout!\n");
 		goto abort;
 	}
 
 	if (temp & GS_PRERR_STS) {
 		result = -ENXIO;
-		dev_dbg(&adap->dev, "SMBus Protocol error (no response)!\n");
+		i2c_dbg(adap, "SMBus Protocol error (no response)!\n");
 	}
 
 	if (temp & GS_COL_STS) {
 		result = -EIO;
-		dev_warn(&adap->dev, "SMBus collision!\n");
+		i2c_warn(adap, "SMBus collision!\n");
 	}
 
 	if (temp & GS_TO_STS) {
 		result = -ETIMEDOUT;
-		dev_dbg(&adap->dev, "SMBus protocol timeout!\n");
+		i2c_dbg(adap, "SMBus protocol timeout!\n");
 	}
 
 	if (temp & GS_HCYC_STS)
-		dev_dbg(&adap->dev, "SMBus protocol success!\n");
+		i2c_dbg(adap, "SMBus protocol success!\n");
 
 	outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
 
 #ifdef DEBUG
 	if (((temp = inw_p(SMB_GLOBAL_STATUS)) & GS_CLEAR_STS) != 0x00) {
-		dev_dbg(&adap->dev,
+		i2c_dbg(adap,
 			"Failed reset at end of transaction (%04x)\n", temp);
 	}
 #endif
 
-	dev_dbg(&adap->dev,
+	i2c_dbg(adap,
 		"Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n",
 		inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE),
 		inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA));
@@ -170,7 +170,7 @@ static int amd756_transaction(struct i2c_adapter *adap)
 	return result;
 
  abort:
-	dev_warn(&adap->dev, "Sending abort\n");
+	i2c_warn(adap, "Sending abort\n");
 	outw_p(inw(SMB_GLOBAL_ENABLE) | GE_ABORT, SMB_GLOBAL_ENABLE);
 	msleep(100);
 	outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
@@ -233,7 +233,7 @@ static s32 amd756_access(struct i2c_adapter * adap, u16 addr,
 		size = AMD756_BLOCK_DATA;
 		break;
 	default:
-		dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+		i2c_warn(adap, "Unsupported transaction %d\n", size);
 		return -EOPNOTSUPP;
 	}
 

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Tue Dec 23 02:02:34 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 11:02:34 +0100
Subject: [PATCH 12/12] i2c: piix4: use i2c_adapter-specific printk helpers
In-Reply-To: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>
References: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>
Message-ID: <20251223-i2c-printk-helpers-v1-12-46a08306afdb@oss.qualcomm.com>

Convert all instances of using device printk helpers with struct device
embedded in struct i2c_adapter to the new i2c-specific macros that hide
that dereference.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/i2c/busses/i2c-piix4.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index ac3bb550303fe5893822af50c385004c9292e695..bf6ce6b4bed3f4ae8aa392c68189a67636c01bf9 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -650,7 +650,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
 		size = PIIX4_BLOCK_DATA;
 		break;
 	default:
-		dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+		i2c_warn(adap, "Unsupported transaction %d\n", size);
 		return -EOPNOTSUPP;
 	}
 
@@ -825,12 +825,12 @@ static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr,
 		ret = piix4_imc_sleep();
 		switch (ret) {
 		case -EBUSY:
-			dev_warn(&adap->dev,
+			i2c_warn(adap,
 				 "IMC base address index region 0x%x already in use.\n",
 				 KERNCZ_IMC_IDX);
 			break;
 		case -ETIMEDOUT:
-			dev_warn(&adap->dev,
+			i2c_warn(adap,
 				 "Failed to communicate with the IMC.\n");
 			break;
 		default:
@@ -839,7 +839,7 @@ static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr,
 
 		/* If IMC communication fails do not retry */
 		if (ret) {
-			dev_warn(&adap->dev,
+			i2c_warn(adap,
 				 "Continuing without IMC notification.\n");
 			adapdata->notify_imc = false;
 		}

-- 
2.47.3



From lkp at intel.com  Tue Dec 23 02:03:30 2025
From: lkp at intel.com (kernel test robot)
Date: Tue, 23 Dec 2025 18:03:30 +0800
Subject: [arm-platforms:kvm-arm64/gicv5-full 62/82]
 arch/arm64/kvm/vgic/vgic-v5.c:896:2-7: WARNING: NULL check before some
 freeing functions is not needed.
Message-ID: <202512231705.sZJLmMXm-lkp@intel.com>

tree:   https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git kvm-arm64/gicv5-full
head:   1426b88096b597395df4c82f089b87c62bab45da
commit: 9c3aa62ac1b11cec38e958d7f7bf033bf308902d [62/82] KVM: arm64: gic-v5: Add IRS init/teardown to vgic_v5 init/teardown
config: arm64-randconfig-r064-20251223 (https://download.01.org/0day-ci/archive/20251223/202512231705.sZJLmMXm-lkp at intel.com/config)
compiler: aarch64-linux-gcc (GCC) 15.1.0

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512231705.sZJLmMXm-lkp at intel.com/

cocci warnings: (new ones prefixed by >>)
>> arch/arm64/kvm/vgic/vgic-v5.c:896:2-7: WARNING: NULL check before some freeing functions is not needed.

vim +896 arch/arm64/kvm/vgic/vgic-v5.c

   858	
   859	void vgic_v5_teardown(struct kvm *kvm)
   860	{
   861		struct kvm_vcpu *vcpu, *vcpu0;
   862		struct vgic_dist *dist = &kvm->arch.vgic;
   863		unsigned long i;
   864		int rc;
   865	
   866		/*
   867		 * There's a chance we don't have CPUs yet, in which case we've also not
   868		 * initialised the tables.
   869		 */
   870		if (!atomic_read(&kvm->online_vcpus))
   871			goto out_no_vcpus;
   872	
   873		/* Make the VM invalid  */
   874		vcpu0 = kvm_get_vcpu(kvm, 0);
   875		rc = vgic_v5_send_command(vcpu0, VMTE_MAKE_INVALID);
   876		if (rc)
   877			kvm_err("could not make VMTE invalid\n");
   878	
   879		kvm_for_each_vcpu(i, vcpu, kvm) {
   880			/* Goodbye doorbell */
   881			vgic_v5_disable_vcpu(vcpu);
   882	
   883			if (vgic_v5_vmte_free_vpe(vcpu))
   884				kvm_err("Failed to free VPE\n");
   885		}
   886	
   887		vgic_v5_teardown_per_vm_domain(&kvm->arch.vgic.gicv5_vm);
   888	
   889		if (vgic_v5_vmte_release(kvm))
   890			kvm_err("Failed to release VM 0x%x\n", dist->gicv5_vm.vm_id);
   891	
   892		vgic_v5_release_vm_id(kvm);
   893	
   894	out_no_vcpus:
   895		if (dist->vgic_v5_irs_data)
 > 896			kfree(dist->vgic_v5_irs_data);
   897		dist->vgic_v5_irs_data = NULL;
   898	}
   899	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From bartosz.golaszewski at oss.qualcomm.com  Tue Dec 23 02:04:38 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 11:04:38 +0100
Subject: [PATCH 00/12] i2c: configure parent device and OF node through the
 adapter struct
Message-ID: <20251223-i2c-adap-dev-config-v1-0-4829b1cf0834@oss.qualcomm.com>

It's been another year of discussing the object life-time problems at
conferences. I2C is one of the offenders and its problems are more
complex than those of some other subsystems. It seems the revocable[1]
API may make its way into the kernel this year but even with it in
place, I2C won't be able to use it as there's currently nothing to
*revoke*. The struct device is embedded within the i2c_adapter struct
whose lifetime is tied to the provider device being bound to its driver.

Fixing this won't be fast and easy but nothing's going to happen if we
don't start chipping away at it. The ultimate goal in order to be able
to use an SRCU-based solution (revocable or otherwise) is to convert the
embedded struct device in struct i2c_adapter into an __rcu pointer that
can be *revoked*. To that end we need to hide all dereferences of
adap->dev in drivers.

This series addresses the usage of adap->dev in probe() callbacks where
drivers assign the parent device address and the associated OF-node
directly to the struct device embedded in i2c_adapter. We extend the
latter struct to accept the parent struct device and of_node directly
and make it assign it to its internal struct device inside
i2c_register_adapter(). For now just 12 patches but I'll keep on doing it
if these get accepted. Once these get upstream for v6.20/7.0, we'll be
able to also start converting i2c drivers outside of drivers/i2c/.

[1] https://lore.kernel.org/all/20251106152330.11733-1-tzungbi at kernel.org/

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
Bartosz Golaszewski (12):
      i2c: allow setting the parent device and OF node through the adapter struct
      i2c: qcom-geni: set device parent and of_node through the adapter struct
      i2c: bcm-kona: set device parent and of_node through the adapter struct
      i2c: keba: set device parent and of_node through the adapter struct
      i2c: omap: set device parent and of_node through the adapter struct
      i2c: rcar: set device parent and of_node through the adapter struct
      i2c: st: set device parent and of_node through the adapter struct
      i2c: mxs: set device parent and of_node through the adapter struct
      i2c: highlander: set device parent and of_node through the adapter struct
      i2c: gpio: set device parent and of_node through the adapter struct
      i2c: nomadik: set device parent and of_node through the adapter struct
      i2c: bcm2835: set device parent and of_node through the adapter struct

 drivers/i2c/busses/i2c-bcm-kona.c   | 4 ++--
 drivers/i2c/busses/i2c-bcm2835.c    | 4 ++--
 drivers/i2c/busses/i2c-gpio.c       | 2 +-
 drivers/i2c/busses/i2c-highlander.c | 2 +-
 drivers/i2c/busses/i2c-keba.c       | 2 +-
 drivers/i2c/busses/i2c-mxs.c        | 4 ++--
 drivers/i2c/busses/i2c-nomadik.c    | 4 ++--
 drivers/i2c/busses/i2c-omap.c       | 4 ++--
 drivers/i2c/busses/i2c-qcom-geni.c  | 4 ++--
 drivers/i2c/busses/i2c-rcar.c       | 4 ++--
 drivers/i2c/busses/i2c-st.c         | 4 ++--
 drivers/i2c/i2c-core-base.c         | 5 +++++
 include/linux/i2c.h                 | 4 ++++
 13 files changed, 28 insertions(+), 19 deletions(-)
---
base-commit: 9448598b22c50c8a5bb77a9103e2d49f134c9578
change-id: 20251223-i2c-adap-dev-config-9403ab811795

Best regards,
-- 
Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>



From bartosz.golaszewski at oss.qualcomm.com  Tue Dec 23 02:04:39 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 11:04:39 +0100
Subject: [PATCH 01/12] i2c: allow setting the parent device and OF node
 through the adapter struct
In-Reply-To: <20251223-i2c-adap-dev-config-v1-0-4829b1cf0834@oss.qualcomm.com>
References: <20251223-i2c-adap-dev-config-v1-0-4829b1cf0834@oss.qualcomm.com>
Message-ID: <20251223-i2c-adap-dev-config-v1-1-4829b1cf0834@oss.qualcomm.com>

In order to stop i2c bus drivers from dereferencing the struct device
embedded in struct i2c_adapter, let's allow configuring the parent
device and OF-node of the adapter directly through dedicated fields.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/i2c/i2c-core-base.c | 5 +++++
 include/linux/i2c.h         | 4 ++++
 2 files changed, 9 insertions(+)

diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index ae7e9c8b65a65c415f5a42f0eb0e7a4ff3e86dce..732828e63730bb773b77ab59362bad8697a1ebde 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -1561,6 +1561,11 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
 	adap->dev.type = &i2c_adapter_type;
 	device_initialize(&adap->dev);
 
+	if (!adap->dev.parent)
+		adap->dev.parent = adap->parent;
+	if (!adap->dev.of_node)
+		adap->dev.of_node = adap->of_node;
+
 	/*
 	 * This adapter can be used as a parent immediately after device_add(),
 	 * setup runtime-pm (especially ignore-children) before hand.
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 20fd41b51d5c85ee1665395c07345faafd8e2fca..72677f29aff161530bc3c497d1e07144a44eb9e4 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -761,6 +761,10 @@ struct i2c_adapter {
 	struct irq_domain *host_notify_domain;
 	struct regulator *bus_regulator;
 
+	/* Device configuration. */
+	struct device *parent;
+	struct device_node *of_node;
+
 	struct dentry *debugfs;
 
 	/* 7bit address space */

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Tue Dec 23 02:04:40 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 11:04:40 +0100
Subject: [PATCH 02/12] i2c: qcom-geni: set device parent and of_node
 through the adapter struct
In-Reply-To: <20251223-i2c-adap-dev-config-v1-0-4829b1cf0834@oss.qualcomm.com>
References: <20251223-i2c-adap-dev-config-v1-0-4829b1cf0834@oss.qualcomm.com>
Message-ID: <20251223-i2c-adap-dev-config-v1-2-4829b1cf0834@oss.qualcomm.com>

Configure the parent device and the OF-node using dedicated fields in
struct i2c_adapter and avoid dereferencing the internal struct device.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/i2c/busses/i2c-qcom-geni.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index 3a04016db2c3222cc6c91386f8904921014a3f90..389fa49f0ba7e657d97a94d9e27f5d916d1ffcf1 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -1038,8 +1038,8 @@ static int geni_i2c_probe(struct platform_device *pdev)
 				     "Request_irq failed: %d\n", gi2c->irq);
 
 	i2c_set_adapdata(&gi2c->adap, gi2c);
-	gi2c->adap.dev.parent = dev;
-	gi2c->adap.dev.of_node = dev->of_node;
+	gi2c->adap.parent = dev;
+	gi2c->adap.of_node = dev->of_node;
 	strscpy(gi2c->adap.name, "Geni-I2C", sizeof(gi2c->adap.name));
 
 	ret = geni_icc_get(&gi2c->se, desc ? desc->icc_ddr : "qup-memory");

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Tue Dec 23 02:04:41 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 11:04:41 +0100
Subject: [PATCH 03/12] i2c: bcm-kona: set device parent and of_node through
 the adapter struct
In-Reply-To: <20251223-i2c-adap-dev-config-v1-0-4829b1cf0834@oss.qualcomm.com>
References: <20251223-i2c-adap-dev-config-v1-0-4829b1cf0834@oss.qualcomm.com>
Message-ID: <20251223-i2c-adap-dev-config-v1-3-4829b1cf0834@oss.qualcomm.com>

Configure the parent device and the OF-node using dedicated fields in
struct i2c_adapter and avoid dereferencing the internal struct device.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/i2c/busses/i2c-bcm-kona.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-bcm-kona.c b/drivers/i2c/busses/i2c-bcm-kona.c
index 9d8838bbd938bf6c43d9553d9f54acac1282f7e8..edd79689f40f451fc216455c9da5704bdc73c62f 100644
--- a/drivers/i2c/busses/i2c-bcm-kona.c
+++ b/drivers/i2c/busses/i2c-bcm-kona.c
@@ -840,8 +840,8 @@ static int bcm_kona_i2c_probe(struct platform_device *pdev)
 	adap->owner = THIS_MODULE;
 	strscpy(adap->name, "Broadcom I2C adapter", sizeof(adap->name));
 	adap->algo = &bcm_algo;
-	adap->dev.parent = &pdev->dev;
-	adap->dev.of_node = pdev->dev.of_node;
+	adap->parent = &pdev->dev;
+	adap->of_node = pdev->dev.of_node;
 
 	rc = i2c_add_adapter(adap);
 	if (rc)

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Tue Dec 23 02:04:42 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 11:04:42 +0100
Subject: [PATCH 04/12] i2c: keba: set device parent and of_node through the
 adapter struct
In-Reply-To: <20251223-i2c-adap-dev-config-v1-0-4829b1cf0834@oss.qualcomm.com>
References: <20251223-i2c-adap-dev-config-v1-0-4829b1cf0834@oss.qualcomm.com>
Message-ID: <20251223-i2c-adap-dev-config-v1-4-4829b1cf0834@oss.qualcomm.com>

Configure the parent device using the dedicated field in struct
i2c_adapter and avoid dereferencing the internal struct device.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/i2c/busses/i2c-keba.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-keba.c b/drivers/i2c/busses/i2c-keba.c
index 9420c8b342b573da435eeef5a05efde35d61434d..01aa5dd9638dac38dd92500cc8890feb8020754c 100644
--- a/drivers/i2c/busses/i2c-keba.c
+++ b/drivers/i2c/busses/i2c-keba.c
@@ -532,7 +532,7 @@ static int ki2c_probe(struct auxiliary_device *auxdev,
 	adap->owner = THIS_MODULE;
 	adap->class = I2C_CLASS_HWMON;
 	adap->algo = &ki2c_algo;
-	adap->dev.parent = dev;
+	adap->parent = dev;
 
 	i2c_set_adapdata(adap, ki2c);
 

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Tue Dec 23 02:04:43 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 11:04:43 +0100
Subject: [PATCH 05/12] i2c: omap: set device parent and of_node through the
 adapter struct
In-Reply-To: <20251223-i2c-adap-dev-config-v1-0-4829b1cf0834@oss.qualcomm.com>
References: <20251223-i2c-adap-dev-config-v1-0-4829b1cf0834@oss.qualcomm.com>
Message-ID: <20251223-i2c-adap-dev-config-v1-5-4829b1cf0834@oss.qualcomm.com>

Configure the parent device and the OF-node using dedicated fields in
struct i2c_adapter and avoid dereferencing the internal struct device.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/i2c/busses/i2c-omap.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index d9f590f0c384340dd31308bdf9ed0cb1a1a2ba8b..f95f31c521314e1d67f3d5b34bb44fcef557624f 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -1496,8 +1496,8 @@ omap_i2c_probe(struct platform_device *pdev)
 	strscpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
 	adap->algo = &omap_i2c_algo;
 	adap->quirks = &omap_i2c_quirks;
-	adap->dev.parent = &pdev->dev;
-	adap->dev.of_node = pdev->dev.of_node;
+	adap->parent = &pdev->dev;
+	adap->of_node = pdev->dev.of_node;
 	adap->bus_recovery_info = &omap_i2c_bus_recovery_info;
 
 	/* i2c device drivers may be active on return from add_adapter() */

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Tue Dec 23 02:04:44 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 11:04:44 +0100
Subject: [PATCH 06/12] i2c: rcar: set device parent and of_node through the
 adapter struct
In-Reply-To: <20251223-i2c-adap-dev-config-v1-0-4829b1cf0834@oss.qualcomm.com>
References: <20251223-i2c-adap-dev-config-v1-0-4829b1cf0834@oss.qualcomm.com>
Message-ID: <20251223-i2c-adap-dev-config-v1-6-4829b1cf0834@oss.qualcomm.com>

Configure the parent device and the OF-node using dedicated fields in
struct i2c_adapter and avoid dereferencing the internal struct device.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/i2c/busses/i2c-rcar.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
index 5ce8f8e4856fb2bb21c9cd731ddbbd8f3622ca26..86826502533bf866ca81cb86ddd10b2a2be3c798 100644
--- a/drivers/i2c/busses/i2c-rcar.c
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -1149,8 +1149,8 @@ static int rcar_i2c_probe(struct platform_device *pdev)
 	adap->algo = &rcar_i2c_algo;
 	adap->class = I2C_CLASS_DEPRECATED;
 	adap->retries = 3;
-	adap->dev.parent = dev;
-	adap->dev.of_node = dev->of_node;
+	adap->parent = dev;
+	adap->of_node = dev->of_node;
 	adap->bus_recovery_info = &rcar_i2c_bri;
 	adap->quirks = &rcar_i2c_quirks;
 	i2c_set_adapdata(adap, priv);

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Tue Dec 23 02:04:45 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 11:04:45 +0100
Subject: [PATCH 07/12] i2c: st: set device parent and of_node through the
 adapter struct
In-Reply-To: <20251223-i2c-adap-dev-config-v1-0-4829b1cf0834@oss.qualcomm.com>
References: <20251223-i2c-adap-dev-config-v1-0-4829b1cf0834@oss.qualcomm.com>
Message-ID: <20251223-i2c-adap-dev-config-v1-7-4829b1cf0834@oss.qualcomm.com>

Configure the parent device and the OF-node using dedicated fields in
struct i2c_adapter and avoid dereferencing the internal struct device.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/i2c/busses/i2c-st.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c
index 97d70e66722706f242cd97153387c3a865abc12d..b50be2c39eaa4b9b95a71b038a4d63f3c5fd7c4b 100644
--- a/drivers/i2c/busses/i2c-st.c
+++ b/drivers/i2c/busses/i2c-st.c
@@ -849,8 +849,8 @@ static int st_i2c_probe(struct platform_device *pdev)
 	adap->retries = 0;
 	adap->algo = &st_i2c_algo;
 	adap->bus_recovery_info = &st_i2c_recovery_info;
-	adap->dev.parent = &pdev->dev;
-	adap->dev.of_node = pdev->dev.of_node;
+	adap->parent = &pdev->dev;
+	adap->of_node = pdev->dev.of_node;
 
 	init_completion(&i2c_dev->complete);
 

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Tue Dec 23 02:04:46 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 11:04:46 +0100
Subject: [PATCH 08/12] i2c: mxs: set device parent and of_node through the
 adapter struct
In-Reply-To: <20251223-i2c-adap-dev-config-v1-0-4829b1cf0834@oss.qualcomm.com>
References: <20251223-i2c-adap-dev-config-v1-0-4829b1cf0834@oss.qualcomm.com>
Message-ID: <20251223-i2c-adap-dev-config-v1-8-4829b1cf0834@oss.qualcomm.com>

Configure the parent device and the OF-node using dedicated fields in
struct i2c_adapter and avoid dereferencing the internal struct device.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/i2c/busses/i2c-mxs.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index 08c9091a1e35151bac8d4adb80abdbd29a62b95a..bfbd96ee2f483cd1dd872c3448eaa6a17940d70f 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -849,9 +849,9 @@ static int mxs_i2c_probe(struct platform_device *pdev)
 	adap->owner = THIS_MODULE;
 	adap->algo = &mxs_i2c_algo;
 	adap->quirks = &mxs_i2c_quirks;
-	adap->dev.parent = dev;
+	adap->parent = dev;
 	adap->nr = pdev->id;
-	adap->dev.of_node = pdev->dev.of_node;
+	adap->of_node = pdev->dev.of_node;
 	i2c_set_adapdata(adap, i2c);
 	err = i2c_add_numbered_adapter(adap);
 	if (err) {

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Tue Dec 23 02:04:47 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 11:04:47 +0100
Subject: [PATCH 09/12] i2c: highlander: set device parent and of_node
 through the adapter struct
In-Reply-To: <20251223-i2c-adap-dev-config-v1-0-4829b1cf0834@oss.qualcomm.com>
References: <20251223-i2c-adap-dev-config-v1-0-4829b1cf0834@oss.qualcomm.com>
Message-ID: <20251223-i2c-adap-dev-config-v1-9-4829b1cf0834@oss.qualcomm.com>

Configure the parent device using the dedicated field in struct
i2c_adapter and avoid dereferencing the internal struct device.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/i2c/busses/i2c-highlander.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-highlander.c b/drivers/i2c/busses/i2c-highlander.c
index 78c5845e0877ae3e2ad1dcef052cdef021372e12..8aa2baf96c266edeb67d1da123e314e57831e0f8 100644
--- a/drivers/i2c/busses/i2c-highlander.c
+++ b/drivers/i2c/busses/i2c-highlander.c
@@ -404,7 +404,7 @@ static int highlander_i2c_probe(struct platform_device *pdev)
 	adap->class = I2C_CLASS_HWMON;
 	strscpy(adap->name, "HL FPGA I2C adapter", sizeof(adap->name));
 	adap->algo = &highlander_i2c_algo;
-	adap->dev.parent = &pdev->dev;
+	adap->parent = &pdev->dev;
 	adap->nr = pdev->id;
 
 	/*

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Tue Dec 23 02:04:48 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 11:04:48 +0100
Subject: [PATCH 10/12] i2c: gpio: set device parent and of_node through the
 adapter struct
In-Reply-To: <20251223-i2c-adap-dev-config-v1-0-4829b1cf0834@oss.qualcomm.com>
References: <20251223-i2c-adap-dev-config-v1-0-4829b1cf0834@oss.qualcomm.com>
Message-ID: <20251223-i2c-adap-dev-config-v1-10-4829b1cf0834@oss.qualcomm.com>

Configure the parent device using the dedicated field in struct
i2c_adapter and avoid dereferencing the internal struct device.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/i2c/busses/i2c-gpio.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
index f4355b17bfbf15c402e71096ccbb99f5a35bb479..78f8bc2525be6d1fd9a7907df4c253f33bbec9f0 100644
--- a/drivers/i2c/busses/i2c-gpio.c
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -425,7 +425,7 @@ static int i2c_gpio_probe(struct platform_device *pdev)
 
 	adap->algo_data = bit_data;
 	adap->class = I2C_CLASS_HWMON;
-	adap->dev.parent = dev;
+	adap->parent = dev;
 	device_set_node(&adap->dev, fwnode);
 
 	adap->nr = pdev->id;

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Tue Dec 23 02:04:50 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 11:04:50 +0100
Subject: [PATCH 12/12] i2c: bcm2835: set device parent and of_node through
 the adapter struct
In-Reply-To: <20251223-i2c-adap-dev-config-v1-0-4829b1cf0834@oss.qualcomm.com>
References: <20251223-i2c-adap-dev-config-v1-0-4829b1cf0834@oss.qualcomm.com>
Message-ID: <20251223-i2c-adap-dev-config-v1-12-4829b1cf0834@oss.qualcomm.com>

Configure the parent device and the OF-node using dedicated fields in
struct i2c_adapter and avoid dereferencing the internal struct device.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/i2c/busses/i2c-bcm2835.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
index 0d7e2654a534e92a529f27fdc049812359678522..4f7e4a178b33fdd172657cc625a34018b18f88ca 100644
--- a/drivers/i2c/busses/i2c-bcm2835.c
+++ b/drivers/i2c/busses/i2c-bcm2835.c
@@ -474,8 +474,8 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
 	snprintf(adap->name, sizeof(adap->name), "bcm2835 (%s)",
 		 of_node_full_name(pdev->dev.of_node));
 	adap->algo = &bcm2835_i2c_algo;
-	adap->dev.parent = &pdev->dev;
-	adap->dev.of_node = pdev->dev.of_node;
+	adap->parent = &pdev->dev;
+	adap->of_node = pdev->dev.of_node;
 	adap->quirks = of_device_get_match_data(&pdev->dev);
 
 	/*

-- 
2.47.3



From bartosz.golaszewski at oss.qualcomm.com  Tue Dec 23 02:04:49 2025
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 11:04:49 +0100
Subject: [PATCH 11/12] i2c: nomadik: set device parent and of_node through
 the adapter struct
In-Reply-To: <20251223-i2c-adap-dev-config-v1-0-4829b1cf0834@oss.qualcomm.com>
References: <20251223-i2c-adap-dev-config-v1-0-4829b1cf0834@oss.qualcomm.com>
Message-ID: <20251223-i2c-adap-dev-config-v1-11-4829b1cf0834@oss.qualcomm.com>

Configure the parent device and the OF-node using dedicated fields in
struct i2c_adapter and avoid dereferencing the internal struct device.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/i2c/busses/i2c-nomadik.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
index 19b648fc094d9748a0cce4e35f350da35ee25505..133ce90941ed596ba2e6dc2d9b368cebe7ace3a3 100644
--- a/drivers/i2c/busses/i2c-nomadik.c
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -1147,8 +1147,8 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
 	init_hw(priv);
 
 	adap = &priv->adap;
-	adap->dev.of_node = np;
-	adap->dev.parent = dev;
+	adap->of_node = np;
+	adap->parent = dev;
 	adap->owner = THIS_MODULE;
 	adap->class = I2C_CLASS_DEPRECATED;
 	adap->algo = &nmk_i2c_algo;

-- 
2.47.3



From sashal at kernel.org  Tue Dec 23 02:05:07 2025
From: sashal at kernel.org (Sasha Levin)
Date: Tue, 23 Dec 2025 05:05:07 -0500
Subject: [PATCH AUTOSEL 6.18-6.12] spi: mt65xx: Use IRQF_ONESHOT with threaded IRQ
In-Reply-To: <20251223100518.2383364-1-sashal@kernel.org>
References: <20251223100518.2383364-1-sashal@kernel.org>
Message-ID: <20251223100518.2383364-3-sashal@kernel.org>

From: Fei Shao <fshao at chromium.org>

[ Upstream commit 8c04b77f87e6e321ae6acd28ce1de5553916153f ]

This driver is migrated to use threaded IRQ since commit 5972eb05ca32
("spi: spi-mt65xx: Use threaded interrupt for non-SPIMEM transfer"), and
we almost always want to disable the interrupt line to avoid excess
interrupts while the threaded handler is processing SPI transfer.
Use IRQF_ONESHOT for that purpose.

In practice, we see MediaTek devices show SPI transfer timeout errors
when communicating with ChromeOS EC in certain scenarios, and with
IRQF_ONESHOT, the issue goes away.

Signed-off-by: Fei Shao <fshao at chromium.org>
Link: https://patch.msgid.link/20251217101131.1975131-1-fshao at chromium.org
Signed-off-by: Mark Brown <broonie at kernel.org>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---

LLM Generated explanations, may be completely bogus:

### 4. SCOPE AND RISK ASSESSMENT

- **Lines changed:** 1 line
- **Files touched:** 1 file
- **Complexity:** Trivially low - just a flag change
- **Risk:** Very low

The fix is:
- **Obviously correct**: IRQF_ONESHOT is the documented standard for
  threaded interrupts
- **Small and contained**: One flag change
- **Fixes a real bug**: Transfer timeout errors on real hardware

Looking at the interrupt handler code:
- `mtk_spi_interrupt` returns `IRQ_WAKE_THREAD` for non-SPIMEM transfers
- Without IRQF_ONESHOT, the IRQ line stays enabled, allowing repeated
  interrupts while the thread processes
- This causes race conditions on `mdata->state` and transfer handling,
  leading to timeouts

### 5. USER IMPACT

- **Who is affected:** Users of MediaTek SPI devices, particularly
  ChromeOS users with embedded controllers
- **Severity:** Medium-High - SPI transfer timeouts can cause
  significant functionality issues
- **Real-world impact:** Confirmed on MediaTek devices communicating
  with ChromeOS EC

### 6. DEPENDENCY CHECK

The prerequisite commit `5972eb05ca32` ("spi: spi-mt65xx: Use threaded
interrupt for non-SPIMEM transfer") was first included in **v6.12-rc1**.
This means:
- This fix is only applicable to 6.12.y stable trees and newer
- Older stable trees (6.6.y, 6.1.y, 5.15.y) don't have the threaded IRQ
  code, so this fix doesn't apply

### 7. SUMMARY

| Criterion | Assessment |
|-----------|------------|
| Fixes real bug | ? Yes - SPI transfer timeouts |
| Obviously correct | ? Yes - standard pattern |
| Small and contained | ? Yes - 1 line change |
| Tested | ? Yes - real hardware testing |
| Risk | ? Very low |
| Dependencies | ? Clear - requires 5972eb05ca32 (v6.12+) |

### Conclusion

This commit is an excellent candidate for stable backporting:

1. **Fixes a real, user-visible bug**: SPI transfer timeouts on MediaTek
   hardware
2. **Minimal change**: Single flag addition, no logic changes
3. **Obviously correct**: IRQF_ONESHOT is the proper pattern for
   threaded IRQs with hardirq handlers that return IRQ_WAKE_THREAD
4. **Low risk**: Well-understood kernel mechanism with no side effects
5. **Tested**: Confirmed to resolve the issue on real ChromeOS EC
   hardware

The only consideration is that this fix only applies to stable trees
with kernel 6.12 or later (which contain the prerequisite threaded IRQ
commit). For those trees, this is a straightforward, low-risk fix that
resolves real hardware issues.

**YES**

 drivers/spi/spi-mt65xx.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c
index 4b40985af1ea..90e5813cfdc3 100644
--- a/drivers/spi/spi-mt65xx.c
+++ b/drivers/spi/spi-mt65xx.c
@@ -1320,7 +1320,7 @@ static int mtk_spi_probe(struct platform_device *pdev)
 
 	ret = devm_request_threaded_irq(dev, irq, mtk_spi_interrupt,
 					mtk_spi_interrupt_thread,
-					IRQF_TRIGGER_NONE, dev_name(dev), host);
+					IRQF_ONESHOT, dev_name(dev), host);
 	if (ret)
 		return dev_err_probe(dev, ret, "failed to register irq\n");
 
-- 
2.51.0



From jie.gan at oss.qualcomm.com  Tue Dec 23 02:09:49 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Tue, 23 Dec 2025 18:09:49 +0800
Subject: [PATCH v8 0/4] add sysfs nodes to configure TPDA's registers
Message-ID: <20251223-add_sysfs_nodes_to_configure_tpda-v8-0-4c95db608b62@oss.qualcomm.com>

Patchset 1 introduces configuration of the global control register with
appropriate values to enable proper generation of cross-trigger packets.

Patchset 2 introduces a sysfs node for triggering global flush for all
ports.

Patchset 3 introduces a logic to configure the TPDA_SYNCR register,
which determines the frequency of ASYNC packet generation. These packets
assist userspace tools in accurately identifying each valid packet.

Patchset 4 introduces a sysfs node to initiate a flush request for the
specific port, forcing the data to synchronize and be transmitted to the
sink device.

Changes in v8:
1. remove redundant check in pachset 3.
Link to v7: https://lore.kernel.org/r/20251223-add_sysfs_nodes_to_configure_tpda-v7-0-db4e6810047c at oss.qualcomm.com

Changes in v7:
1. add syncr_count sysfs node.
2. add more detail to describe port_flush_req node.
Link to v6: https://lore.kernel.org/r/20251222-add_sysfs_nodes_to_configure_tpda-v6-0-b27143d45c86 at oss.qualcomm.com

Changes in v6:
1. Create a new patch for introducing gloabl_flush_req sysfs node.
2. Add a syncr_mode sysfs node for TPDA_SYNCR.
3. Remove the redundant attr_grp and consolidate all attributes under tpda_attr_grp.
Link to v5: https://lore.kernel.org/r/20251219-add_sysfs_nodes_to_configure_tpda-v5-0-ca93ddfe9d30 at oss.qualcomm.com

Chnages in V5:
1. Optimizing the solution to creat sysfs nodes.
2. Optimizing the logic for configuring bits of the global control
   register.
Link to V4 - https://lore.kernel.org/all/20251028-configure_tpda_reg-v4-0-23000805d21d at oss.qualcomm.com/

Changes in V4:
1. Document sysfs nodes with correct kernel version and date.
Link to V3 - https://lore.kernel.org/linux-arm-kernel/20250827105545.7140-1-jie.gan at oss.qualcomm.com/

Changes in V3:
1. Optimizing codes according to James's comment.
Link to V2 - https://lore.kernel.org/all/20250827042042.6786-1-jie.gan at oss.qualcomm.com/

Changes in V2:
1. Refactoring the code based on James's comment for optimization.
Link to V1 - https://lore.kernel.org/all/20250826070150.5603-1-jie.gan at oss.qualcomm.com/

Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
Jie Gan (1):
      coresight: tpda: add global_flush_req sysfs node

Tao Zhang (3):
      coresight: tpda: add sysfs nodes for tpda cross-trigger configuration
      coresight: tpda: add logic to configure TPDA_SYNCR register
      coresight: tpda: add sysfs node to flush specific port

 .../ABI/testing/sysfs-bus-coresight-devices-tpda   |  69 +++++
 drivers/hwtracing/coresight/coresight-tpda.c       | 284 ++++++++++++++++++++-
 drivers/hwtracing/coresight/coresight-tpda.h       |  76 +++++-
 3 files changed, 422 insertions(+), 7 deletions(-)
---
base-commit: 12b95d29eb979e5c4f4f31bb05817bc935c52050
change-id: 20251219-add_sysfs_nodes_to_configure_tpda-f54636512817

Best regards,
-- 
Jie Gan <jie.gan at oss.qualcomm.com>



From jie.gan at oss.qualcomm.com  Tue Dec 23 02:09:50 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Tue, 23 Dec 2025 18:09:50 +0800
Subject: [PATCH v8 1/4] coresight: tpda: add sysfs nodes for tpda
 cross-trigger configuration
In-Reply-To: <20251223-add_sysfs_nodes_to_configure_tpda-v8-0-4c95db608b62@oss.qualcomm.com>
References: <20251223-add_sysfs_nodes_to_configure_tpda-v8-0-4c95db608b62@oss.qualcomm.com>
Message-ID: <20251223-add_sysfs_nodes_to_configure_tpda-v8-1-4c95db608b62@oss.qualcomm.com>

From: Tao Zhang <tao.zhang at oss.qualcomm.com>

Introduce sysfs nodes to configure cross-trigger parameters for TPDA.
These registers define the characteristics of cross-trigger packets,
including generation frequency and flag values.

Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
Reviewed-by: James Clark <james.clark at linaro.org>
Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 .../ABI/testing/sysfs-bus-coresight-devices-tpda   |  35 +++++++
 drivers/hwtracing/coresight/coresight-tpda.c       | 109 ++++++++++++++++++++-
 drivers/hwtracing/coresight/coresight-tpda.h       |  63 +++++++++++-
 3 files changed, 200 insertions(+), 7 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
new file mode 100644
index 000000000000..735ce0e494da
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
@@ -0,0 +1,35 @@
+What:		/sys/bus/coresight/devices/<tpda-name>/trig_async_enable
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Enable/disable cross trigger synchronization sequence interface.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/trig_flag_ts_enable
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Enable/disable cross trigger FLAG packet request interface.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/trig_freq_enable
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Enable/disable cross trigger FREQ packet request interface.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/freq_ts_enable
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Enable/disable the timestamp for all FREQ packets.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/cmbchan_mode
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Configure the CMB/MCMB channel mode for all enabled ports.
+		Value 0 means raw channel mapping mode. Value 1 means channel pair marking mode.
diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
index 3a3825d27f86..2186223ad33e 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.c
+++ b/drivers/hwtracing/coresight/coresight-tpda.c
@@ -137,12 +137,32 @@ static int tpda_get_element_size(struct tpda_drvdata *drvdata,
 /* Settings pre enabling port control register */
 static void tpda_enable_pre_port(struct tpda_drvdata *drvdata)
 {
-	u32 val;
+	u32 val = 0;
 
-	val = readl_relaxed(drvdata->base + TPDA_CR);
-	val &= ~TPDA_CR_ATID;
 	val |= FIELD_PREP(TPDA_CR_ATID, drvdata->atid);
+	if (drvdata->trig_async)
+		val |= TPDA_CR_SRIE;
+
+	if (drvdata->trig_flag_ts)
+		val |= TPDA_CR_FLRIE;
+
+	if (drvdata->trig_freq)
+		val |= TPDA_CR_FRIE;
+
+	if (drvdata->freq_ts)
+		val |= TPDA_CR_FREQTS;
+
+	if (drvdata->cmbchan_mode)
+		val |= TPDA_CR_CMBCHANMODE;
+
 	writel_relaxed(val, drvdata->base + TPDA_CR);
+
+	/*
+	 * If FLRIE bit is set, set the master and channel
+	 * id as zero
+	 */
+	if (drvdata->trig_flag_ts)
+		writel_relaxed(0x0, drvdata->base + TPDA_FPID_CR);
 }
 
 static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
@@ -258,6 +278,87 @@ static const struct coresight_ops tpda_cs_ops = {
 	.link_ops	= &tpda_link_ops,
 };
 
+/* Read cross-trigger register member */
+static ssize_t tpda_trig_sysfs_show(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	struct tpda_trig_sysfs_attribute *tpda_attr =
+		container_of(attr, struct tpda_trig_sysfs_attribute, attr);
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	guard(spinlock)(&drvdata->spinlock);
+	switch (tpda_attr->mem) {
+	case FREQTS:
+		return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->freq_ts);
+	case FRIE:
+		return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_freq);
+	case FLRIE:
+		return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_flag_ts);
+	case SRIE:
+		return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_async);
+	case CMBCHANMODE:
+		return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->cmbchan_mode);
+
+	}
+	return -EINVAL;
+}
+
+static ssize_t tpda_trig_sysfs_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf,
+				     size_t size)
+{
+	struct tpda_trig_sysfs_attribute *tpda_attr =
+		container_of(attr, struct tpda_trig_sysfs_attribute, attr);
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (kstrtoul(buf, 0, &val))
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	switch (tpda_attr->mem) {
+	case FREQTS:
+		drvdata->freq_ts = !!val;
+		break;
+	case FRIE:
+		drvdata->trig_freq = !!val;
+		break;
+	case FLRIE:
+		drvdata->trig_flag_ts = !!val;
+		break;
+	case SRIE:
+		drvdata->trig_async = !!val;
+		break;
+	case CMBCHANMODE:
+		drvdata->cmbchan_mode = !!val;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return size;
+}
+
+static struct attribute *tpda_attrs[] = {
+	tpda_trig_sysfs_rw(freq_ts_enable, FREQTS),
+	tpda_trig_sysfs_rw(trig_freq_enable, FRIE),
+	tpda_trig_sysfs_rw(trig_flag_ts_enable, FLRIE),
+	tpda_trig_sysfs_rw(trig_async_enable, SRIE),
+	tpda_trig_sysfs_rw(cmbchan_mode, CMBCHANMODE),
+	NULL,
+};
+
+static struct attribute_group tpda_attr_grp = {
+	.attrs	= tpda_attrs,
+};
+
+static const struct attribute_group *tpda_attr_grps[] = {
+	&tpda_attr_grp,
+	NULL,
+};
+
 static int tpda_init_default_data(struct tpda_drvdata *drvdata)
 {
 	int atid;
@@ -273,6 +374,7 @@ static int tpda_init_default_data(struct tpda_drvdata *drvdata)
 		return atid;
 
 	drvdata->atid = atid;
+	drvdata->freq_ts = true;
 	return 0;
 }
 
@@ -316,6 +418,7 @@ static int tpda_probe(struct amba_device *adev, const struct amba_id *id)
 	desc.ops = &tpda_cs_ops;
 	desc.pdata = adev->dev.platform_data;
 	desc.dev = &adev->dev;
+	desc.groups = tpda_attr_grps;
 	desc.access = CSDEV_ACCESS_IOMEM(base);
 	drvdata->csdev = coresight_register(&desc);
 	if (IS_ERR(drvdata->csdev))
diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h
index c6af3d2da3ef..c93732e04af2 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.h
+++ b/drivers/hwtracing/coresight/coresight-tpda.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 /*
- * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2023,2025 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CORESIGHT_CORESIGHT_TPDA_H
@@ -8,6 +8,25 @@
 
 #define TPDA_CR			(0x000)
 #define TPDA_Pn_CR(n)		(0x004 + (n * 4))
+#define TPDA_FPID_CR		(0x084)
+
+/* Cross trigger FREQ packets timestamp bit */
+#define TPDA_CR_FREQTS		BIT(2)
+/* Cross trigger FREQ packet request bit */
+#define TPDA_CR_FRIE		BIT(3)
+/* Cross trigger FLAG packet request interface bit */
+#define TPDA_CR_FLRIE		BIT(4)
+/* Cross trigger synchronization bit */
+#define TPDA_CR_SRIE		BIT(5)
+/* Bits 6 ~ 12 is for atid value */
+#define TPDA_CR_ATID		GENMASK(12, 6)
+/*
+ * Channel mode bit of the packetization of CMB/MCB traffic
+ * 0 - raw channel mapping mode
+ * 1 - channel pair marking mode
+ */
+#define TPDA_CR_CMBCHANMODE	BIT(20)
+
 /* Aggregator port enable bit */
 #define TPDA_Pn_CR_ENA		BIT(0)
 /* Aggregator port CMB data set element size bit */
@@ -17,9 +36,6 @@
 
 #define TPDA_MAX_INPORTS	32
 
-/* Bits 6 ~ 12 is for atid value */
-#define TPDA_CR_ATID		GENMASK(12, 6)
-
 /**
  * struct tpda_drvdata - specifics associated to an TPDA component
  * @base:       memory mapped base address for this component.
@@ -29,6 +45,11 @@
  * @enable:     enable status of the component.
  * @dsb_esize   Record the DSB element size.
  * @cmb_esize   Record the CMB element size.
+ * @trig_async:	Enable/disable cross trigger synchronization sequence interface.
+ * @trig_flag_ts: Enable/disable cross trigger FLAG packet request interface.
+ * @trig_freq:	Enable/disable cross trigger FREQ packet request interface.
+ * @freq_ts:	Enable/disable the timestamp for all FREQ packets.
+ * @cmbchan_mode: Configure the CMB/MCMB channel mode.
  */
 struct tpda_drvdata {
 	void __iomem		*base;
@@ -38,6 +59,40 @@ struct tpda_drvdata {
 	u8			atid;
 	u32			dsb_esize;
 	u32			cmb_esize;
+	bool			trig_async;
+	bool			trig_flag_ts;
+	bool			trig_freq;
+	bool			freq_ts;
+	bool			cmbchan_mode;
+};
+
+/* Enumerate members of global control register(cr) */
+enum tpda_cr_mem {
+	FREQTS,
+	FRIE,
+	FLRIE,
+	SRIE,
+	CMBCHANMODE
+};
+
+/**
+ * struct tpda_trig_sysfs_attribute - Record the member variables of cross
+ * trigger register that need to be operated by sysfs file
+ * @attr:	The device attribute
+ * @mem:	The member in the control register data structure
+ */
+struct tpda_trig_sysfs_attribute {
+	struct device_attribute attr;
+	enum tpda_cr_mem mem;
 };
 
+#define tpda_trig_sysfs_rw(name, mem)				\
+	(&((struct tpda_trig_sysfs_attribute[]) {		\
+	   {							\
+		__ATTR(name, 0644, tpda_trig_sysfs_show,	\
+		tpda_trig_sysfs_store),				\
+		mem,						\
+	   }							\
+	   })[0].attr.attr)
+
 #endif  /* _CORESIGHT_CORESIGHT_TPDA_H */

-- 
2.34.1



From jie.gan at oss.qualcomm.com  Tue Dec 23 02:09:51 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Tue, 23 Dec 2025 18:09:51 +0800
Subject: [PATCH v8 2/4] coresight: tpda: add global_flush_req sysfs node
In-Reply-To: <20251223-add_sysfs_nodes_to_configure_tpda-v8-0-4c95db608b62@oss.qualcomm.com>
References: <20251223-add_sysfs_nodes_to_configure_tpda-v8-0-4c95db608b62@oss.qualcomm.com>
Message-ID: <20251223-add_sysfs_nodes_to_configure_tpda-v8-2-4c95db608b62@oss.qualcomm.com>

Setting the global_flush_req register to 1 initiates a flush request for
all enabled TPDA input ports. The register remains set until the flush
operation is complete.

Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 .../ABI/testing/sysfs-bus-coresight-devices-tpda   |  8 ++++
 drivers/hwtracing/coresight/coresight-tpda.c       | 45 ++++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-tpda.h       |  2 +
 3 files changed, 55 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
index 735ce0e494da..c8bc7b19ab25 100644
--- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
@@ -33,3 +33,11 @@ Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qu
 Description:
 		(RW) Configure the CMB/MCMB channel mode for all enabled ports.
 		Value 0 means raw channel mapping mode. Value 1 means channel pair marking mode.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/global_flush_req
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Set global (all ports) flush request bit. The bit remains set until a
+		global flush request sequence completes.
diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
index 2186223ad33e..d24a9098f1b1 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.c
+++ b/drivers/hwtracing/coresight/coresight-tpda.c
@@ -341,7 +341,52 @@ static ssize_t tpda_trig_sysfs_store(struct device *dev,
 	return size;
 }
 
+static ssize_t global_flush_req_show(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (!drvdata->csdev->refcnt)
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	val = readl_relaxed(drvdata->base + TPDA_CR);
+	/* read global_flush_req bit */
+	val &= TPDA_CR_FLREQ;
+
+	return sysfs_emit(buf, "%lu\n", val);
+}
+
+static ssize_t global_flush_req_store(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf,
+				      size_t size)
+{
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (kstrtoul(buf, 0, &val))
+		return -EINVAL;
+
+	if (!drvdata->csdev->refcnt || !val)
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	val = readl_relaxed(drvdata->base + TPDA_CR);
+	/* set global_flush_req bit */
+	val |= TPDA_CR_FLREQ;
+	CS_UNLOCK(drvdata->base);
+	writel_relaxed(val, drvdata->base + TPDA_CR);
+	CS_LOCK(drvdata->base);
+
+	return size;
+}
+static DEVICE_ATTR_RW(global_flush_req);
+
 static struct attribute *tpda_attrs[] = {
+	&dev_attr_global_flush_req.attr,
 	tpda_trig_sysfs_rw(freq_ts_enable, FREQTS),
 	tpda_trig_sysfs_rw(trig_freq_enable, FRIE),
 	tpda_trig_sysfs_rw(trig_flag_ts_enable, FLRIE),
diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h
index c93732e04af2..1cc9253293ec 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.h
+++ b/drivers/hwtracing/coresight/coresight-tpda.h
@@ -10,6 +10,8 @@
 #define TPDA_Pn_CR(n)		(0x004 + (n * 4))
 #define TPDA_FPID_CR		(0x084)
 
+/* Cross trigger global (all ports) flush request bit */
+#define TPDA_CR_FLREQ		BIT(0)
 /* Cross trigger FREQ packets timestamp bit */
 #define TPDA_CR_FREQTS		BIT(2)
 /* Cross trigger FREQ packet request bit */

-- 
2.34.1



From jie.gan at oss.qualcomm.com  Tue Dec 23 02:09:52 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Tue, 23 Dec 2025 18:09:52 +0800
Subject: [PATCH v8 3/4] coresight: tpda: add logic to configure TPDA_SYNCR
 register
In-Reply-To: <20251223-add_sysfs_nodes_to_configure_tpda-v8-0-4c95db608b62@oss.qualcomm.com>
References: <20251223-add_sysfs_nodes_to_configure_tpda-v8-0-4c95db608b62@oss.qualcomm.com>
Message-ID: <20251223-add_sysfs_nodes_to_configure_tpda-v8-3-4c95db608b62@oss.qualcomm.com>

From: Tao Zhang <tao.zhang at oss.qualcomm.com>

The TPDA_SYNC counter tracks the number of bytes transferred from the
aggregator. When this count reaches the value programmed in the
TPDA_SYNCR register, an ASYNC request is triggered, allowing userspace
tools to accurately parse each valid packet.

Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
Reviewed-by: James Clark <james.clark at linaro.org>
Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 .../ABI/testing/sysfs-bus-coresight-devices-tpda   | 18 +++++
 drivers/hwtracing/coresight/coresight-tpda.c       | 90 ++++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-tpda.h       | 10 +++
 3 files changed, 118 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
index c8bc7b19ab25..c989eea1ef59 100644
--- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
@@ -41,3 +41,21 @@ Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qu
 Description:
 		(RW) Set global (all ports) flush request bit. The bit remains set until a
 		global flush request sequence completes.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/syncr_mode
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Set mode the of the syncr counter.
+		mode 0 - COUNT[11:0] value represents the approximate number of bytes moved between two ASYNC packet requests
+		mode 1 - the bits COUNT[11:7] are used as a power of 2. for example, we could insert an async packet every 8K
+		         data by writing a value 13 to the COUNT[11:7] field.
+
+What:		/sys/bus/coresight/devices/<tpda-name>/syncr_count
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Set value the of the syncr counter.
+		Range: 0-4095
diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
index d24a9098f1b1..deb5a646a04c 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.c
+++ b/drivers/hwtracing/coresight/coresight-tpda.c
@@ -163,6 +163,20 @@ static void tpda_enable_pre_port(struct tpda_drvdata *drvdata)
 	 */
 	if (drvdata->trig_flag_ts)
 		writel_relaxed(0x0, drvdata->base + TPDA_FPID_CR);
+
+	/* Initialize with a value of 0 */
+	val = 0;
+	if (drvdata->syncr_mode)
+		val |= TPDA_SYNCR_MODE_CTRL_MASK;
+
+	if (drvdata->syncr_count > 0 &&
+	    drvdata->syncr_count < TPDA_SYNCR_COUNT_MASK)
+		val |= drvdata->syncr_count;
+	else
+		/* Program the count to its MAX value by default */
+		val |= TPDA_SYNCR_COUNT_MASK;
+
+	writel_relaxed(val, drvdata->base + TPDA_SYNCR);
 }
 
 static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
@@ -385,8 +399,84 @@ static ssize_t global_flush_req_store(struct device *dev,
 }
 static DEVICE_ATTR_RW(global_flush_req);
 
+static ssize_t syncr_mode_show(struct device *dev,
+			       struct device_attribute *attr,
+			       char *buf)
+{
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val, syncr_val;
+
+	if (!drvdata->csdev->refcnt)
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	syncr_val = readl_relaxed(drvdata->base + TPDA_SYNCR);
+	val = FIELD_GET(TPDA_SYNCR_MODE_CTRL_MASK, syncr_val);
+
+	return sysfs_emit(buf, "%lu\n", val);
+}
+
+static ssize_t syncr_mode_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf,
+				size_t size)
+{
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (kstrtoul(buf, 0, &val))
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	/* set the mode when first enabling the device */
+	drvdata->syncr_mode = !!val;
+
+	return size;
+}
+static DEVICE_ATTR_RW(syncr_mode);
+
+static ssize_t syncr_count_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (!drvdata->csdev->refcnt)
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	val = readl_relaxed(drvdata->base + TPDA_SYNCR);
+	val &= TPDA_SYNCR_COUNT_MASK;
+
+	return sysfs_emit(buf, "%lu\n", val);
+}
+
+static ssize_t syncr_count_store(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf,
+				 size_t size)
+{
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (kstrtoul(buf, 0, &val))
+		return -EINVAL;
+
+	if (val > TPDA_SYNCR_COUNT_MASK)
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	drvdata->syncr_count = val;
+
+	return size;
+}
+static DEVICE_ATTR_RW(syncr_count);
+
 static struct attribute *tpda_attrs[] = {
 	&dev_attr_global_flush_req.attr,
+	&dev_attr_syncr_mode.attr,
+	&dev_attr_syncr_count.attr,
 	tpda_trig_sysfs_rw(freq_ts_enable, FREQTS),
 	tpda_trig_sysfs_rw(trig_freq_enable, FRIE),
 	tpda_trig_sysfs_rw(trig_flag_ts_enable, FLRIE),
diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h
index 1cc9253293ec..56d35697303a 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.h
+++ b/drivers/hwtracing/coresight/coresight-tpda.h
@@ -9,6 +9,7 @@
 #define TPDA_CR			(0x000)
 #define TPDA_Pn_CR(n)		(0x004 + (n * 4))
 #define TPDA_FPID_CR		(0x084)
+#define TPDA_SYNCR		(0x08C)
 
 /* Cross trigger global (all ports) flush request bit */
 #define TPDA_CR_FLREQ		BIT(0)
@@ -36,6 +37,11 @@
 /* Aggregator port DSB data set element size bit */
 #define TPDA_Pn_CR_DSBSIZE		BIT(8)
 
+/* TPDA_SYNCR count mask */
+#define TPDA_SYNCR_COUNT_MASK		GENMASK(11, 0)
+/* TPDA_SYNCR mode control bit */
+#define TPDA_SYNCR_MODE_CTRL_MASK	GENMASK(12, 12)
+
 #define TPDA_MAX_INPORTS	32
 
 /**
@@ -52,6 +58,8 @@
  * @trig_freq:	Enable/disable cross trigger FREQ packet request interface.
  * @freq_ts:	Enable/disable the timestamp for all FREQ packets.
  * @cmbchan_mode: Configure the CMB/MCMB channel mode.
+ * @syncr_mode:	Setting the mode for counting packets.
+ * @syncr_count: Setting the value of the count.
  */
 struct tpda_drvdata {
 	void __iomem		*base;
@@ -66,6 +74,8 @@ struct tpda_drvdata {
 	bool			trig_freq;
 	bool			freq_ts;
 	bool			cmbchan_mode;
+	bool			syncr_mode;
+	u32			syncr_count;
 };
 
 /* Enumerate members of global control register(cr) */

-- 
2.34.1



From jie.gan at oss.qualcomm.com  Tue Dec 23 02:09:53 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Tue, 23 Dec 2025 18:09:53 +0800
Subject: [PATCH v8 4/4] coresight: tpda: add sysfs node to flush specific
 port
In-Reply-To: <20251223-add_sysfs_nodes_to_configure_tpda-v8-0-4c95db608b62@oss.qualcomm.com>
References: <20251223-add_sysfs_nodes_to_configure_tpda-v8-0-4c95db608b62@oss.qualcomm.com>
Message-ID: <20251223-add_sysfs_nodes_to_configure_tpda-v8-4-4c95db608b62@oss.qualcomm.com>

From: Tao Zhang <tao.zhang at oss.qualcomm.com>

Setting bit i in the TPDA_FLUSH_CR register initiates a flush request
for port i, forcing the data to synchronize and be transmitted to the
sink device.

Signed-off-by: Tao Zhang <tao.zhang at oss.qualcomm.com>
Reviewed-by: James Clark <james.clark at linaro.org>
Co-developed-by: Jie Gan <jie.gan at oss.qualcomm.com>
Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 .../ABI/testing/sysfs-bus-coresight-devices-tpda   |  8 +++++
 drivers/hwtracing/coresight/coresight-tpda.c       | 40 ++++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-tpda.h       |  1 +
 3 files changed, 49 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
index c989eea1ef59..48b8fda1b796 100644
--- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpda
@@ -59,3 +59,11 @@ Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qu
 Description:
 		(RW) Set value the of the syncr counter.
 		Range: 0-4095
+
+What:		/sys/bus/coresight/devices/<tpda-name>/port_flush_req
+Date:		December 2025
+KernelVersion:	6.19
+Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Tao Zhang <tao.zhang at oss.qualcomm.com>, Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Configure the bit i to requests a flush operation of port i on the TPDA.
+		The requested bit(s) remain set until the flush request completes.
diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
index deb5a646a04c..7055f8f13427 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.c
+++ b/drivers/hwtracing/coresight/coresight-tpda.c
@@ -473,10 +473,50 @@ static ssize_t syncr_count_store(struct device *dev,
 }
 static DEVICE_ATTR_RW(syncr_count);
 
+static ssize_t port_flush_req_show(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (!drvdata->csdev->refcnt)
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	val = readl_relaxed(drvdata->base + TPDA_FLUSH_CR);
+
+	return sysfs_emit(buf, "0x%lx\n", val);
+}
+
+static ssize_t port_flush_req_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf,
+				    size_t size)
+{
+	struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	u32 val;
+
+	if (kstrtou32(buf, 0, &val))
+		return -EINVAL;
+
+	if (!drvdata->csdev->refcnt || !val)
+		return -EINVAL;
+
+	guard(spinlock)(&drvdata->spinlock);
+	CS_UNLOCK(drvdata->base);
+	writel_relaxed(val, drvdata->base + TPDA_FLUSH_CR);
+	CS_LOCK(drvdata->base);
+
+	return size;
+}
+static DEVICE_ATTR_RW(port_flush_req);
+
 static struct attribute *tpda_attrs[] = {
 	&dev_attr_global_flush_req.attr,
 	&dev_attr_syncr_mode.attr,
 	&dev_attr_syncr_count.attr,
+	&dev_attr_port_flush_req.attr,
 	tpda_trig_sysfs_rw(freq_ts_enable, FREQTS),
 	tpda_trig_sysfs_rw(trig_freq_enable, FRIE),
 	tpda_trig_sysfs_rw(trig_flag_ts_enable, FLRIE),
diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h
index 56d35697303a..a090352009bb 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.h
+++ b/drivers/hwtracing/coresight/coresight-tpda.h
@@ -10,6 +10,7 @@
 #define TPDA_Pn_CR(n)		(0x004 + (n * 4))
 #define TPDA_FPID_CR		(0x084)
 #define TPDA_SYNCR		(0x08C)
+#define TPDA_FLUSH_CR		(0x090)
 
 /* Cross trigger global (all ports) flush request bit */
 #define TPDA_CR_FLREQ		BIT(0)

-- 
2.34.1



From eichest at gmail.com  Tue Dec 23 02:10:59 2025
From: eichest at gmail.com (Stefan Eichenberger)
Date: Tue, 23 Dec 2025 11:10:59 +0100
Subject: [PATCH net-next v2] net: stmmac: dwmac: Add a fixup for the Micrel KSZ9131 PHY
Message-ID: <20251223101240.10634-1-eichest@gmail.com>

From: Stefan Eichenberger <stefan.eichenberger at toradex.com>

Add a fixup to the stmmac driver to keep the preamble before the SFD
(Start Frame Delimiter) on the Micrel KSZ9131 PHY when the driver is
used on an NXP i.MX8MP SoC.

This allows to workaround errata ERR050694 of the NXP i.MX8MP that
states:
ENET_QOS: MAC incorrectly discards the received packets when Preamble
Byte does not precede SFD or SMD.

The bit which disables this feature is not documented in the datasheet
from Micrel, but has been found by NXP and Micrel following this
discussion:
https://community.nxp.com/t5/i-MX-Processors/iMX8MP-eqos-not-working-for-10base-t/m-p/2151032

It has been tested on Verdin iMX8MP from Toradex by forcing the PHY to
10MBit. Without bit 2 being set in the remote loopback register, no
packets are received. With the bit set, reception works fine.

Signed-off-by: Stefan Eichenberger <stefan.eichenberger at toradex.com>
---
Changes in v2:
- Use phy_register_fixup_for_uid() instead of adding a new device tree
  property
- I will send the conversion of the micrel.txt binding as a separate
  patch series
- Link to v1: https://lore.kernel.org/all/20251212084657.29239-1-eichest at gmail.com/

 .../net/ethernet/stmicro/stmmac/dwmac-imx.c   | 56 ++++++++++++++++++-
 1 file changed, 55 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c
index db288fbd5a4df..23bc917d3f0bd 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c
@@ -19,6 +19,7 @@
 #include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/stmmac.h>
+#include <linux/micrel_phy.h>
 
 #include "stmmac_platform.h"
 
@@ -39,6 +40,12 @@
 #define RMII_RESET_SPEED		(0x3 << 14)
 #define CTRL_SPEED_MASK			GENMASK(15, 14)
 
+/* Undocumented bit of the KSZ9131RNX in the remote loopback register to keep
+ * the preamble before sfd. It was reported by NXP in cooperation with Micrel.
+ */
+#define KSZ9x31_REMOTE_LOOPBACK			0x11
+#define KSZ9x31_REMOTE_LOOPBACK_KEEP_PREAMBLE	BIT(2)
+
 struct imx_priv_data;
 
 struct imx_dwmac_ops {
@@ -282,6 +289,30 @@ imx_dwmac_parse_dt(struct imx_priv_data *dwmac, struct device *dev)
 	return err;
 }
 
+static int imx8mp_dwmac_phy_micrel_fixup(struct phy_device *phydev)
+{
+	struct device *mdio_bus_dev = phydev->mdio.dev.parent;
+	struct device_node *mac_node;
+
+	if (!mdio_bus_dev || !mdio_bus_dev->parent)
+		return 0;
+
+	mac_node = mdio_bus_dev->parent->of_node;
+	if (!mac_node)
+		return 0;
+
+	if (!of_device_is_compatible(mac_node, "nxp,imx8mp-dwmac-eqos"))
+		return 0;
+
+	/* Keep the preamble before the SFD (Start Frame Delimiter) for the
+	 * Micrel KSZ9131. This is required on the i.MX8MP because of errata
+	 * ERR050694.
+	 */
+	return phy_modify_changed(phydev, KSZ9x31_REMOTE_LOOPBACK,
+				  KSZ9x31_REMOTE_LOOPBACK_KEEP_PREAMBLE,
+				  KSZ9x31_REMOTE_LOOPBACK_KEEP_PREAMBLE);
+}
+
 static int imx_dwmac_probe(struct platform_device *pdev)
 {
 	struct plat_stmmacenet_data *plat_dat;
@@ -389,7 +420,30 @@ static struct platform_driver imx_dwmac_driver = {
 		.of_match_table = imx_dwmac_match,
 	},
 };
-module_platform_driver(imx_dwmac_driver);
+
+static int __init imx_dwmac_init(void)
+{
+	int ret;
+
+	if (of_machine_is_compatible("fsl,imx8mp")) {
+		ret = phy_register_fixup_for_uid(PHY_ID_KSZ9131, MICREL_PHY_ID_MASK,
+						 imx8mp_dwmac_phy_micrel_fixup);
+		if (ret)
+			return ret;
+	}
+
+	return platform_driver_register(&imx_dwmac_driver);
+}
+module_init(imx_dwmac_init);
+
+static void __exit imx_dwmac_exit(void)
+{
+	if (of_machine_is_compatible("fsl,imx8mp"))
+		phy_unregister_fixup_for_uid(PHY_ID_KSZ9131, MICREL_PHY_ID_MASK);
+
+	platform_driver_unregister(&imx_dwmac_driver);
+}
+module_exit(imx_dwmac_exit);
 
 MODULE_AUTHOR("NXP");
 MODULE_DESCRIPTION("NXP imx8 DWMAC Specific Glue layer");
-- 
2.51.0



From tudor.ambarus at linaro.org  Tue Dec 23 02:14:49 2025
From: tudor.ambarus at linaro.org (Tudor Ambarus)
Date: Tue, 23 Dec 2025 12:14:49 +0200
Subject: [PATCH v4 2/5] soc: samsung: exynos-chipid: rename method
In-Reply-To: <bf1bca0af63f161afe351cb0e449896cec11cdcc.camel@linaro.org>
References: <20251222-gs101-chipid-v4-0-aa8e20ce7bb3@linaro.org>
 <20251222-gs101-chipid-v4-2-aa8e20ce7bb3@linaro.org>
 <bf1bca0af63f161afe351cb0e449896cec11cdcc.camel@linaro.org>
Message-ID: <51565d98-ac0a-44f4-af30-6d42b68661da@linaro.org>



On 12/23/25 11:55 AM, Andr? Draszik wrote:
> On Mon, 2025-12-22 at 16:30 +0000, Tudor Ambarus wrote:
>> s/product_id_to_soc_id/exynos_product_id_to_name.
>> Prepend exynos_ to avoid name space pollution. The method translates the
>> product id to a name, rename the method to make that clear. While
>> touching the code where it is called, add a blank line for readability
>> purposes.
>>
>> Signed-off-by: Tudor Ambarus <tudor.ambarus at linaro.org>
>> ---
>> ?drivers/soc/samsung/exynos-chipid.c | 5 +++--
>> ?1 file changed, 3 insertions(+), 2 deletions(-)
> 
> I'm not sure this change helps with anything, in particular as the
> return value is used to assign to soc_id, but in case it gets applied:

what drove me to do the rename, and prepend exynos_ to the method name,
was that IP specific drivers should not use generic names for methods ->
those shall be left for the core.

Now about the s/soc_id/name, you're right, I could kept soc_id to align
with the soc interface. Happy to resend for this if you think it is worth
it, or drop altogether.
> 
> Reviewed-by: Andr? Draszik <andre.draszik at linaro.org>

Cheers,
ta


From andre.draszik at linaro.org  Tue Dec 23 02:18:56 2025
From: andre.draszik at linaro.org (=?ISO-8859-1?Q?Andr=E9?= Draszik)
Date: Tue, 23 Dec 2025 10:18:56 +0000
Subject: [PATCH v4 4/5] soc: samsung: exynos-chipid: add
 google,gs101-otp support
In-Reply-To: <20251222-gs101-chipid-v4-4-aa8e20ce7bb3@linaro.org>
References: <20251222-gs101-chipid-v4-0-aa8e20ce7bb3@linaro.org>
	 <20251222-gs101-chipid-v4-4-aa8e20ce7bb3@linaro.org>
Message-ID: <aa55c3865d151697120a2855e711d59468bdcd0a.camel@linaro.org>

On Mon, 2025-12-22 at 16:30 +0000, Tudor Ambarus wrote:
> GS101 is different (but also e850 and autov9 I assume) from the SoCs
> that are currently handled by the exynos-chipid driver because the
> chip ID info is part of the OTP registers. GS101 OTP has a clock, an
> interrupt line, a register space (that contains product and chip ID,
> TMU data, ASV, etc) and a 32Kbit memory space that can be
> read/program/locked with specific commands. On GS101 the "ChipID block"
> is just an abstraction, it's not a physical device. When the power-on
> sequence progresses, the OTP chipid values are loaded to the OTP
> registers.
> 
> Add the GS101 chip ID support. The support is intentionally added in the
> exynos-chipid driver, and not in a dedicated Exynos OTP driver, because
> we estimate that there will not be any OTP consumers in the kernel other
> than the chip ID/SoC interface. The downstream GS101 drivers confirm
> this supposition.
> 
> Signed-off-by: Tudor Ambarus <tudor.ambarus at linaro.org>
> ---
> ?drivers/soc/samsung/exynos-chipid.c | 70 ++++++++++++++++++++++++++++++++-----
> ?1 file changed, 61 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c
> index 5c8660374269c87ec38ebca242918bd7b1d362e5..6ef9751e2509c94bd9625072d0b81ddb93048d4a 100644
> --- a/drivers/soc/samsung/exynos-chipid.c
> +++ b/drivers/soc/samsung/exynos-chipid.c
> @@ -15,7 +15,8 @@
> ?#include <linux/array_size.h>
> ?#include <linux/device.h>
> ?#include <linux/device/devres.h>
> -#include <linux/errno.h>
> +#include <linux/err.h>
> +#include <linux/ioport.h>
> ?#include <linux/mfd/syscon.h>
> ?#include <linux/module.h>
> ?#include <linux/of.h>
> @@ -28,9 +29,11 @@
> ?#include "exynos-asv.h"
> ?
> ?struct exynos_chipid_variant {
> -	unsigned int rev_reg;		/* revision register offset */
> +	unsigned int main_rev_reg;	/* main revision register offset */
> +	unsigned int sub_rev_reg;	/* sub revision register offset */
> ?	unsigned int main_rev_shift;	/* main revision offset in rev_reg */
> ?	unsigned int sub_rev_shift;	/* sub revision offset in rev_reg */
> +	bool efuse;
> ?};
> ?
> ?struct exynos_chipid_info {
> @@ -69,6 +72,8 @@ static const struct exynos_soc_id {
> ?	{ "EXYNOS990", 0xE9830000 },
> ?	{ "EXYNOSAUTOV9", 0xAAA80000 },
> ?	{ "EXYNOSAUTOV920", 0x0A920000 },
> +	/* Compatible with: google,gs101-otp */
> +	{ "GS101", 0x9845000 },
> ?};
> ?
> ?static const char *exynos_product_id_to_name(unsigned int product_id)
> @@ -93,19 +98,53 @@ static int exynos_chipid_get_chipid_info(struct device *dev,
> ?		return dev_err_probe(dev, ret, "failed to read Product ID\n");
> ?	soc_info->product_id = val & EXYNOS_MASK;
> ?
> -	if (data->rev_reg != EXYNOS_CHIPID_REG_PRO_ID) {
> -		ret = regmap_read(regmap, data->rev_reg, &val);
> +	if (data->sub_rev_reg == EXYNOS_CHIPID_REG_PRO_ID) {
> +		/* exynos4210 case */
> +		main_rev = (val >> data->main_rev_shift) & EXYNOS_REV_PART_MASK;
> +		sub_rev = (val >> data->sub_rev_shift) & EXYNOS_REV_PART_MASK;
> +	} else {
> +		unsigned int val2;
> +
> +		ret = regmap_read(regmap, data->sub_rev_reg, &val2);
> ?		if (ret < 0)
> ?			return dev_err_probe(dev, ret,
> ?					???? "failed to read revision\n");
> +
> +		if (data->main_rev_reg == EXYNOS_CHIPID_REG_PRO_ID)
> +			/* gs101 case */
> +			main_rev = (val >> data->main_rev_shift) & EXYNOS_REV_PART_MASK;
> +		else
> +			/* exynos850 case */
> +			main_rev = (val2 >> data->main_rev_shift) & EXYNOS_REV_PART_MASK;

Looking closer, why is this not val? Now you're shifting the sub_rev
register value by the main rev shift, assigning the sub_rev register
value to the main rev variable.

And then, all assignments to main_rev become identical and don't need to
be duplicated.

> +
> +		sub_rev = (val2 >> data->sub_rev_shift) & EXYNOS_REV_PART_MASK;
> ?	}
> -	main_rev = (val >> data->main_rev_shift) & EXYNOS_REV_PART_MASK;
> -	sub_rev = (val >> data->sub_rev_shift) & EXYNOS_REV_PART_MASK;
> +
> ?	soc_info->revision = (main_rev << EXYNOS_REV_PART_SHIFT) | sub_rev;
> ?
> ?	return 0;
> ?}


Cheers,
Andre'


From andrew at lunn.ch  Tue Dec 23 02:35:40 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Tue, 23 Dec 2025 11:35:40 +0100
Subject: [PATCH 2/2] ARM: dts: aspeed: ventura2: Add Meta ventura2 BMC
In-Reply-To: <CAF7HswN0hhJQ-gmE59cKTuPyzrs1A3rM8Xw+Z8i3_AsHRiNcug@mail.gmail.com>
References: <20251222-ventura2_initial_dts-v1-0-1f06166c78a3@gmail.com>
 <20251222-ventura2_initial_dts-v1-2-1f06166c78a3@gmail.com>
 <c069b452-df22-4afa-bf6a-c48949f40ebc@lunn.ch>
 <CAF7HswN_jEXOU_9K4LpLnbhvd+RD0qqELAHxMBbp=hGtMjS4kQ@mail.gmail.com>
 <35f3eba9-5ec4-4cba-8a64-fb521dc65b79@lunn.ch>
 <CAF7HswN0hhJQ-gmE59cKTuPyzrs1A3rM8Xw+Z8i3_AsHRiNcug@mail.gmail.com>
Message-ID: <1e21f828-1b06-492d-bfcd-ab5721621e8a@lunn.ch>

> > What make/model of switch is it? Is it unmanaged, or does it use SPI
> > or I2C for management?

> The switch is connected via RMII to the MAC and is managed over MDIO.

O.K. What make/model?

> On our board, MDIO is not wired directly to the processor; instead, we
> use a USB-to-MPSSE bridge (FT2232) to toggle the MDIO signals for
> switch management.

I have to push back on you using a closed source user space driver,
given that i help maintain the Ethernet switch drivers...

I know there have been attempts to get GPIO support added for FT2232,
but i don't think any got as far as mainline. That is probably the
only part you are missing. You can describe USB devices in DT. So you
should be able to describe such a GPIO controller. You can then
instantiate an virtual,mdio-gpio driver to give you an MDIO bus. And
then add nodes for the switch using DSA.

     Andrew


From lkp at intel.com  Tue Dec 23 02:35:12 2025
From: lkp at intel.com (kernel test robot)
Date: Tue, 23 Dec 2025 18:35:12 +0800
Subject: [arm-platforms:kvm-arm64/gicv5-full 68/82]
 arch/arm64/kvm/vgic/vgic-its-v5.c:311:13: warning: variable
 'device_id_l1_shift' is used uninitialized whenever 'if' condition is false
Message-ID: <202512231832.ACrEYhoS-lkp@intel.com>

tree:   https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git kvm-arm64/gicv5-full
head:   1426b88096b597395df4c82f089b87c62bab45da
commit: 9d01097b8baaed8cf8de6d6eece4953aa6ed71c5 [68/82] KVM: arm64: gic-v5: Add the ITS device
config: arm64-allmodconfig (https://download.01.org/0day-ci/archive/20251223/202512231832.ACrEYhoS-lkp at intel.com/config)
compiler: clang version 19.1.7 (https://github.com/llvm/llvm-project cd708029e0b2869e80abe31ddb175f7c35361f90)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251223/202512231832.ACrEYhoS-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512231832.ACrEYhoS-lkp at intel.com/

All warnings (new ones prefixed by >>):

>> arch/arm64/kvm/vgic/vgic-its-v5.c:311:13: warning: variable 'device_id_l1_shift' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]
     311 |         } else if (dt_l2sz == 2) {
         |                    ^~~~~~~~~~~~
   arch/arm64/kvm/vgic/vgic-its-v5.c:317:22: note: uninitialized use occurs here
     317 |                      (device_id >> device_id_l1_shift) * sizeof(__le64);
         |                                    ^~~~~~~~~~~~~~~~~~
   arch/arm64/kvm/vgic/vgic-its-v5.c:311:9: note: remove the 'if' if its condition is always true
     311 |         } else if (dt_l2sz == 2) {
         |                ^~~~~~~~~~~~~~~~~
   arch/arm64/kvm/vgic/vgic-its-v5.c:301:29: note: initialize the variable 'device_id_l1_shift' to silence this warning
     301 |         unsigned device_id_l1_shift, l2_device_id;
         |                                    ^
         |                                     = 0
>> arch/arm64/kvm/vgic/vgic-its-v5.c:421:13: warning: variable 'itt_split_bits' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]
     421 |         } else if (itt_l2sz == 2) {
         |                    ^~~~~~~~~~~~~
   arch/arm64/kvm/vgic/vgic-its-v5.c:427:28: note: uninitialized use occurs here
     427 |         l1_event_id = event_id >> itt_split_bits;
         |                                   ^~~~~~~~~~~~~~
   arch/arm64/kvm/vgic/vgic-its-v5.c:421:9: note: remove the 'if' if its condition is always true
     421 |         } else if (itt_l2sz == 2) {
         |                ^~~~~~~~~~~~~~~~~~
   arch/arm64/kvm/vgic/vgic-its-v5.c:411:25: note: initialize the variable 'itt_split_bits' to silence this warning
     411 |         unsigned itt_split_bits, l2_event_id_bits;
         |                                ^
         |                                 = 0
   arch/arm64/kvm/vgic/vgic-its-v5.c:515:5: warning: no previous prototype for function 'vgic_v5_its_look_up_lpi' [-Wmissing-prototypes]
     515 | int vgic_v5_its_look_up_lpi(struct kvm *kvm, struct vgic_v5_its *its,
         |     ^
   arch/arm64/kvm/vgic/vgic-its-v5.c:515:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
     515 | int vgic_v5_its_look_up_lpi(struct kvm *kvm, struct vgic_v5_its *its,
         | ^
         | static 
   3 warnings generated.


vim +311 arch/arm64/kvm/vgic/vgic-its-v5.c

   293	
   294	static int parse_two_level_dt(struct kvm *kvm, gpa_t dt_base, unsigned dt_l2sz,
   295				      u32 device_id, gpa_t *itt_base,
   296				      bool *two_level_itt, unsigned *event_id_bits,
   297				      unsigned *itt_l2sz)
   298	{
   299		int ret;
   300		__le64 dt_l1_entry;
   301		unsigned device_id_l1_shift, l2_device_id;
   302		gpa_t dt_l2_base;
   303		gpa_t entry_addr;
   304	
   305		if (dt_l2sz == 0) {
   306			// 9 bits for L2 table (4kB)
   307			device_id_l1_shift = 9;
   308		} else if (dt_l2sz == 1) {
   309			// 11 bits for L2 table (16kB)
   310			device_id_l1_shift = 11;
 > 311		} else if (dt_l2sz == 2) {
   312			// 13 bits for L2 table (64kB)
   313			device_id_l1_shift = 13;
   314		}
   315	
   316		entry_addr = dt_base +
   317			     (device_id >> device_id_l1_shift) * sizeof(__le64);
   318	
   319		ret = kvm_read_guest_lock(kvm, entry_addr, &dt_l1_entry,
   320					  sizeof(__le64));
   321		if (ret) {
   322			kvm_err("Failed to read guest memory for L1 DT!");
   323			return ret;
   324		}
   325	
   326		if (!FIELD_GET(GICV5_DTL1E_VALID, dt_l1_entry)) {
   327			kvm_err("Guest DT L1 entry is invalid!\n");
   328			return -EINVAL;
   329		}
   330	
   331		dt_l2_base = FIELD_GET(GICV5_DTL1E_L2_ADDR_MASK, dt_l1_entry) << 3;
   332		l2_device_id = device_id % (1UL << device_id_l1_shift);
   333		if (l2_device_id >= (1UL << FIELD_GET(GICV5_DTL1E_SPAN, dt_l1_entry))) {
   334			kvm_err("DeviceID 0x%x out of range of guest DT\n", device_id);
   335			return -ENXIO;
   336		}
   337	
   338		return parse_linear_dt(kvm, dt_l2_base, l2_device_id, itt_base,
   339				       two_level_itt, event_id_bits, itt_l2sz);
   340	}
   341	
   342	/*
   343	 * Get the GPA for the ITT corresponding to device_id in the guest.
   344	 */
   345	static int get_itt(struct kvm *kvm, struct vgic_v5_its *its, u32 device_id,
   346			   gpa_t *itt_base, bool *two_level_itt,
   347			   unsigned *event_id_bits, unsigned *itt_l2sz)
   348	{
   349		gpa_t dt_base;
   350		bool two_level_dt;
   351		unsigned dt_l2sz, device_id_bits;
   352		int ret;
   353	
   354		/*
   355		 * First of all, let's make sure that we have a valid ITS_DT_BASER. This
   356		 * MMIO register doesn't have a valid bit, so we assume that it is valid
   357		 * if the guest enabled the virtual ITS. This matches the expected
   358		 * behaviour of a HW device.
   359		 */
   360		if (its->enabled == 0) {
   361			kvm_err("Cannot look up LPI; vITS is disabled!\n");
   362			return -ENXIO;
   363		}
   364	
   365		/* The physical address of the DT in the guest */
   366		dt_base = its->dt_baser.addr;
   367	
   368		two_level_dt = its->dt_cfgr.structure;
   369		dt_l2sz = its->dt_cfgr.l2sz;
   370		device_id_bits = its->dt_cfgr.device_id_bits;
   371	
   372		if (device_id >= 1UL << device_id_bits) {
   373			kvm_err("Device ID out of range!\n");
   374			return -E2BIG;
   375		}
   376	
   377		if (!two_level_dt) {
   378			ret = parse_linear_dt(kvm, dt_base, device_id, itt_base,
   379					      two_level_itt, event_id_bits, itt_l2sz);
   380		} else {
   381			ret = parse_two_level_dt(kvm, dt_base, dt_l2sz, device_id,
   382						 itt_base, two_level_itt, event_id_bits,
   383						 itt_l2sz);
   384		}
   385	
   386		return ret;
   387	}
   388	
   389	static int parse_linear_itt(struct kvm *kvm, u32 event_id, gpa_t itt_base,
   390				    __le64 *itt_l2_entry)
   391	{
   392		int ret = 0;
   393		gpa_t entry_addr = itt_base + event_id * sizeof(*itt_l2_entry);
   394	
   395		ret = kvm_read_guest_lock(kvm, entry_addr, itt_l2_entry,
   396					  sizeof(*itt_l2_entry));
   397		if (ret) {
   398			kvm_err("Failed to read guest memory for L2 ITT!");
   399			return ret;
   400		}
   401	
   402		return ret;
   403	}
   404	
   405	static int parse_two_level_itt(struct kvm *kvm, u32 event_id, gpa_t itt_base,
   406				       unsigned itt_l2sz, __le64 *itt_l2_entry)
   407	{
   408		int ret = 0;
   409		__le64 itt_l1_entry;
   410		gpa_t itt_l2_base;
   411		unsigned itt_split_bits, l2_event_id_bits;
   412		u32 l1_event_id, l2_event_id;
   413		gpa_t entry_addr;
   414	
   415		if (itt_l2sz == 0) {
   416			// 9 bits for L2 table (4kB)
   417			itt_split_bits = 9;
   418		} else if (itt_l2sz == 1) {
   419			// 11 bits for L2 table (16kB)
   420			itt_split_bits = 11;
 > 421		} else if (itt_l2sz == 2) {
   422			// 13 bits for L2 table (64kB)
   423			itt_split_bits = 13;
   424		}
   425	
   426		/* Get the bits of the EventID used for L1 indexing */
   427		l1_event_id = event_id >> itt_split_bits;
   428	
   429		entry_addr = itt_base + l1_event_id * sizeof(itt_l1_entry);
   430		ret = kvm_read_guest_lock(kvm, entry_addr, &itt_l1_entry,
   431					  sizeof(itt_l1_entry));
   432		if (ret) {
   433			kvm_err("Failed to read guest memory for L1 ITT!");
   434			return ret;
   435		}
   436	
   437		if (!FIELD_GET(GICV5_ITTL1E_VALID, itt_l1_entry)) {
   438			kvm_err("Guest ITT L1 entry is invalid!\n");
   439			return -EINVAL;
   440		}
   441	
   442		itt_l2_base = FIELD_GET(GICV5_ITTL1E_L2_ADDR_MASK, itt_l1_entry) << 3;
   443	
   444		/*
   445		 * L2 event is limited by the min value of itt_split_bits and the span
   446		 * from the L1 entry.
   447		 */
   448		l2_event_id_bits =
   449			min(FIELD_GET(GICV5_ITTL1E_SPAN, itt_l1_entry), itt_split_bits);
   450		l2_event_id = event_id % (1UL << l2_event_id_bits);
   451	
   452		/*
   453		 * If the event is unreachable because it doesn't exist at L2 (span
   454		 * smaller than the number of L2 bits), we can't continue!
   455		 */
   456		if ((itt_split_bits != l2_event_id_bits) &&
   457		    (event_id % itt_split_bits) != l2_event_id) {
   458			kvm_err("EventID is out of range of L2 ITT!");
   459			return -ENXIO;
   460		}
   461	
   462		return parse_linear_itt(kvm, l2_event_id, itt_l2_base, itt_l2_entry);
   463	
   464		return ret;
   465	}
   466	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From vkoul at kernel.org  Tue Dec 23 02:41:43 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 23 Dec 2025 16:11:43 +0530
Subject: [PATCH v2 1/8] dmaengine: Add API to combine configuration and
 preparation (sg and single)
In-Reply-To: <20251218-dma_prep_config-v2-1-c07079836128@nxp.com>
References: <20251218-dma_prep_config-v2-0-c07079836128@nxp.com>
 <20251218-dma_prep_config-v2-1-c07079836128@nxp.com>
Message-ID: <aUpx59CeT4XfL5i1@vaman>

On 18-12-25, 10:56, Frank Li wrote:
> Previously, configuration and preparation required two separate calls. This
> works well when configuration is done only once during initialization.
> 
> However, in cases where the burst length or source/destination address must
> be adjusted for each transfer, calling two functions is verbose and
> requires additional locking to ensure both steps complete atomically.
> 
> Add a new API dmaengine_prep_config_single() and dmaengine_prep_config_sg()
> and callback device_prep_config_sg() that combines configuration and
> preparation into a single operation. If the configuration argument is
> passed as NULL, fall back to the existing implementation.
> 
> Add a new API dmaengine_prep_config_single_safe() and
> dmaengine_prep_config_sg_safe() for re-entrancy, which require driver
> implement callback device_prep_config_sg().
> 
> Tested-by: Niklas Cassel <cassel at kernel.org>
> Signed-off-by: Frank Li <Frank.Li at nxp.com>
> ---
> change in v2
> - add () for function
> - use short name device_prep_sg(), remove "slave" and "config". the 'slave'
> is reduntant. after remove slave, the function name is difference existed
> one, so remove _config suffix.
> ---
>  Documentation/driver-api/dmaengine/client.rst |   9 +++
>  include/linux/dmaengine.h                     | 103 ++++++++++++++++++++++++--
>  2 files changed, 105 insertions(+), 7 deletions(-)
> 
> diff --git a/Documentation/driver-api/dmaengine/client.rst b/Documentation/driver-api/dmaengine/client.rst
> index d491e385d61a98b8a804cd823caf254a2dc62cf4..02c45b7d7a779421411eb9c68325cdedafcfe3b1 100644
> --- a/Documentation/driver-api/dmaengine/client.rst
> +++ b/Documentation/driver-api/dmaengine/client.rst
> @@ -80,6 +80,10 @@ The details of these operations are:
>  
>    - slave_sg: DMA a list of scatter gather buffers from/to a peripheral
>  
> +  - config_sg: Similar with slave_sg, just pass down dma_slave_config
> +    struct to avoid call dmaengine_slave_config() every time if need
> +    adjust burst length or FIFO address.
> +
>    - peripheral_dma_vec: DMA an array of scatter gather buffers from/to a
>      peripheral. Similar to slave_sg, but uses an array of dma_vec
>      structures instead of a scatterlist.
> @@ -106,6 +110,11 @@ The details of these operations are:
>  		unsigned int sg_len, enum dma_data_direction direction,
>  		unsigned long flags);
>  
> +     struct dma_async_tx_descriptor *dmaengine_prep_config_sg(
> +		struct dma_chan *chan, struct scatterlist *sgl,
> +		unsigned int sg_len, enum dma_transfer_direction dir,
> +		unsigned long flags, struct dma_slave_config *config);
> +
>       struct dma_async_tx_descriptor *dmaengine_prep_peripheral_dma_vec(
>  		struct dma_chan *chan, const struct dma_vec *vecs,
>  		size_t nents, enum dma_data_direction direction,
> diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
> index 99efe2b9b4ea9844ca6161208362ef18ef111d96..276dca760f95e1131f5ff5bf69752c4c9cb1bcad 100644
> --- a/include/linux/dmaengine.h
> +++ b/include/linux/dmaengine.h
> @@ -835,6 +835,8 @@ struct dma_filter {
>   *	where the address and size of each segment is located in one entry of
>   *	the dma_vec array.
>   * @device_prep_slave_sg: prepares a slave dma operation
> + *	(Deprecated, use @device_prep_config_sg)

Sorry that is _not_ deprecated, we are adding another way to do this in
a single shot

> + * @device_prep_config_sg: prepares a slave DMA operation with dma_slave_config
>   * @device_prep_dma_cyclic: prepare a cyclic dma operation suitable for audio.
>   *	The function takes a buffer of size buf_len. The callback function will
>   *	be called after period_len bytes have been transferred.
> @@ -934,6 +936,11 @@ struct dma_device {
>  		struct dma_chan *chan, struct scatterlist *sgl,
>  		unsigned int sg_len, enum dma_transfer_direction direction,
>  		unsigned long flags, void *context);
> +	struct dma_async_tx_descriptor *(*device_prep_config_sg)(
> +		struct dma_chan *chan, struct scatterlist *sgl,
> +		unsigned int sg_len, enum dma_transfer_direction direction,
> +		unsigned long flags, struct dma_slave_config *config,
> +		void *context);
>  	struct dma_async_tx_descriptor *(*device_prep_dma_cyclic)(
>  		struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
>  		size_t period_len, enum dma_transfer_direction direction,
> @@ -974,22 +981,85 @@ static inline bool is_slave_direction(enum dma_transfer_direction direction)
>  	       (direction == DMA_DEV_TO_DEV);
>  }
>  
> -static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_single(
> -	struct dma_chan *chan, dma_addr_t buf, size_t len,
> -	enum dma_transfer_direction dir, unsigned long flags)
> +/*
> + * Re-entrancy and locking considerations for callers:
> + *
> + * dmaengine_prep_config_single(sg)_safe() is re-entrant and requires the
> + * DMA engine driver to implement device_prep_config_sg(). It returns NULL
> + * if device_prep_config_sg() is not implemented.
> + *
> + * The unsafe variant (without the _safe suffix) falls back to calling
> + * dmaengine_slave_config() and dmaengine_prep_slave_sg() separately.
> + * In this case, additional locking may be required, depending on the
> + * DMA consumer's usage.
> + */
> +static inline struct dma_async_tx_descriptor *
> +dmaengine_prep_config_sg_safe(struct dma_chan *chan, struct scatterlist *sgl,
> +	unsigned int sg_len, enum dma_transfer_direction dir,
> +	unsigned long flags, struct dma_slave_config *config)
> +{
> +	if (!chan || !chan->device || !chan->device->device_prep_config_sg)
> +		return NULL;
> +
> +	return chan->device->device_prep_config_sg(chan, sgl, sg_len,
> +						   dir, flags, config, NULL);
> +}
> +
> +static inline struct dma_async_tx_descriptor *
> +dmaengine_prep_config_single_safe(struct dma_chan *chan, dma_addr_t buf,
> +	size_t len, enum dma_transfer_direction dir, unsigned long flags,
> +	struct dma_slave_config *config)

Agree with Damien, this could look better!

-- 
~Vinod


From Harini.T at amd.com  Tue Dec 23 02:48:50 2025
From: Harini.T at amd.com (T, Harini)
Date: Tue, 23 Dec 2025 10:48:50 +0000
Subject: [PATCH] dt-bindings: mailbox: xlnx,zynqmp-ipi-mailbox: Document
 msg region requirement
In-Reply-To: <20251222-funny-aspiring-seal-05c4ae@quoll>
References: <20251222044653.1757886-1-harini.t@amd.com>
 <20251222-funny-aspiring-seal-05c4ae@quoll>
Message-ID: <LV5PR12MB980465BAF86F179E5638016A92B5A@LV5PR12MB9804.namprd12.prod.outlook.com>

[Public]

Hi,

> -----Original Message-----
> From: Krzysztof Kozlowski <krzk at kernel.org>
> Sent: Monday, December 22, 2025 2:39 PM
> To: T, Harini <Harini.T at amd.com>
> Cc: jassisinghbrar at gmail.com; robh at kernel.org; krzk+dt at kernel.org;
> conor+dt at kernel.org; Simek, Michal <michal.simek at amd.com>; Datta,
> Shubhrajyoti <shubhrajyoti.datta at amd.com>; linux-kernel at vger.kernel.org;
> devicetree at vger.kernel.org; linux-arm-kernel at lists.infradead.org; git (AMD-
> Xilinx) <git at amd.com>
> Subject: Re: [PATCH] dt-bindings: mailbox: xlnx,zynqmp-ipi-mailbox:
> Document msg region requirement
>
> Caution: This message originated from an External Source. Use proper caution
> when opening attachments, clicking links, or responding.
>
>
> On Mon, Dec 22, 2025 at 10:16:53AM +0530, Harini T wrote:
> > Add description clarifying that for Versal IPI mailboxes, both host
> > and remote agents must have the "msg" register region defined for
> > successful message passing. Without both, only notification-based
> > communication works.
> >
> > Signed-off-by: Harini T <harini.t at amd.com>
> > ---
> >  .../bindings/mailbox/xlnx,zynqmp-ipi-mailbox.yaml           | 6 ++++++
> >  1 file changed, 6 insertions(+)
> >
> > diff --git
> > a/Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-mailbox.ya
> > ml
> > b/Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-mailbox.ya
> > ml index 04d6473d666f..8fdf77c7935c 100644
> > ---
> > a/Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-mailbox.ya
> > ml
> > +++ b/Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-mailbo
> > +++ x.yaml
> > @@ -165,6 +165,12 @@ allOf:
> >          reg-names: false
> >
> >      else:
> > +      description:
>
> Else block cannot have description.

Can I remove the description from else block and move the clarifying text to the top-level description field?

>
> > +        For Versal IPI mailboxes, the "msg" register region is optional.
>
> So it is optional...

The schema marks "msg" as optional to support both notification-only and message-passing use-cases. In hardware, some mailbox channels may be designed for notification only (no buffer), while others support full message passing (with buffer). The schema allows both, but for message passing, "msg" is required on both ends

>
> > +        However, for successful message passing via mailbox, both the
> > + host IPI
>
> And it is not optional. If nothing works, then it is not optional.
>
> And why would it be optional in the first place? You generate your same IP
> with different settings?

There are 2 types of IPI channels (Buffered and Buffer-less)
Some IPI channels are used only for notification (no message buffer, so "msg" is omitted).
Others are used for message passing (buffer present, so "msg" is required).
Reference: https://docs.amd.com/r/en-US/am026-versal-ai-edge-prime-gen2-trm/Features?tocId=K2dUHSdNOkFPpbvkR5v6bQ

>
> Best regards,
> Krzysztof

Thanks,
Harini T


From taniya.das at oss.qualcomm.com  Tue Dec 23 02:49:20 2025
From: taniya.das at oss.qualcomm.com (Taniya Das)
Date: Tue, 23 Dec 2025 16:19:20 +0530
Subject: [PATCH v2 07/11] dt-bindings: clock: qcom: document the Kaanapali
 GPU Clock Controller
In-Reply-To: <65e5459b-7509-47db-9089-6efecead3f44@kernel.org>
References: <20251125-kaanapali-mmcc-v2-v2-0-fb44e78f300b@oss.qualcomm.com>
 <20251125-kaanapali-mmcc-v2-v2-7-fb44e78f300b@oss.qualcomm.com>
 <20251126-elated-stoic-scorpion-25b630@kuoka>
 <de44560d-4ed8-41fe-be7b-56412b933a8c@oss.qualcomm.com>
 <fbe39eac-7c92-4a08-bafb-31e5c51a0613@kernel.org>
 <503f445e-0d12-407d-bc77-f48ad335639b@oss.qualcomm.com>
 <e8bdb176-b6fb-4dd2-8b5b-9da8073fa915@kernel.org>
 <ca118faf-3451-4b83-9074-82bc5e1f731e@oss.qualcomm.com>
 <3e8128f4-3cba-4c13-a846-e5f1638a1e0f@kernel.org>
 <701a7b2f-848a-4cc0-8924-ec72155d93a7@oss.qualcomm.com>
 <65e5459b-7509-47db-9089-6efecead3f44@kernel.org>
Message-ID: <a63f2bc7-11af-46d1-a950-60a25ef79bb0@oss.qualcomm.com>



On 12/19/2025 8:15 PM, Krzysztof Kozlowski wrote:
> On 19/12/2025 14:02, Konrad Dybcio wrote:
>> On 12/17/25 2:54 PM, Krzysztof Kozlowski wrote:
>>> On 17/12/2025 14:21, Konrad Dybcio wrote:
>>>> On 12/17/25 11:09 AM, Krzysztof Kozlowski wrote:
>>>>> On 17/12/2025 10:32, Taniya Das wrote:
>>>>>>>>
>>>>>>>> We would like to leverage the existing common clock driver(GDSC) code to
>>>>>>>
>>>>>>> Fix the driver code if it cannot handle other cells. Your drivers do not
>>>>>>> matter for choices made in bindings.
>>>>>>>
>>>>>>
>>>>>> As it is still a clock controller from hardware design and in SW I will
>>>>>> be map the entire hardware region and this way this clock controller
>>>>>> will also be aligned to the existing clock controllers and keep the
>>>>>> #power-domain-cells = <1> as other CCs.
>>>>>
>>>>> I don't see how this resolves my comment.
>>>>
>>>> Spanning the entire 0x6000-long block will remove your worry about this
>>>> description only being 2-register-wide
>>>
>>> But that was not the comment here. Taniya replied under comment about
>>> cells. We are not discussing here some other things...
>>
>> Right, you omitted the part where I answered your comment from the
>> context, so I'll re-add it:
>>
>> """
>> This block provides more than one GDSC - although again, not all of them
>> need/should be accessed by Linux. I suppose just enumerating the "extra"
>> ones in bindings will be a good enough compromise?
>> """
>>
>> TLDR: cells=1 makes sense as per usual
> 
> Either list them in headers or at least explain that in the binding.

I will take care to list them and explain them as well.


-- 
Thanks,
Taniya Das



From leitao at debian.org  Tue Dec 23 02:55:42 2025
From: leitao at debian.org (Breno Leitao)
Date: Tue, 23 Dec 2025 02:55:42 -0800
Subject: [PATCH 0/2] arm64: efi: Fix NULL pointer crash in 6.19-rc2
Message-ID: <20251223-efi_fix_619-v1-0-e0146b8b9d73@debian.org>

I am seeing the following crash on arm64 with 6.19-rc2 (commit 9448598b22c5
("Linux 6.19-rc2"))

	Unable to handle kernel NULL pointer dereference at virtual address 00000000000000c8

	Call trace:
	cap_capable (security/commoncap.c:82 security/commoncap.c:128) (P)
	security_capable (security/security.c:?)
	ns_capable_noaudit (kernel/capability.c:342 kernel/capability.c:381)
	__ptrace_may_access (./include/linux/rcupdate.h:895 kernel/ptrace.c:326)
	ptrace_may_access (kernel/ptrace.c:353)
	do_task_stat (fs/proc/array.c:467)
	proc_tgid_stat (fs/proc/array.c:673)
	proc_single_show (fs/proc/base.c:803)
	seq_read_iter (fs/seq_file.c:209)
	seq_read (./include/linux/ioprio.h:59 ./include/linux/ioprio.h:84 ./include/linux/fs.h:2177 fs/seq_file.c:158)
	vfs_read (./arch/arm64/include/asm/uaccess.h:46 fs/read_write.c:560)
	ksys_read (fs/read_write.c:705)
	__arm64_sys_read (fs/read_write.c:722)
	invoke_syscall (arch/arm64/kernel/syscall.c:46)
	el0_svc_common+0x90/0xe0
	do_el0_svc (arch/arm64/kernel/syscall.c:150)
	el0_svc (arch/arm64/kernel/entry-common.c:724)
	el0t_64_sync_handler (arch/arm64/kernel/entry-common.c:743)
	el0t_64_sync (arch/arm64/kernel/entry.S:596)

This was bissected to commit a5baf582f4 ("arm64/efi: Call EFI runtime services without
disabling preemption").

After the commit above, it crashes arm64 with a NULL pointer dereference in
cap_capable() when running below (ocassionally). Unfortunately I still don't
have a simple reproducer, and it takes about 10 minutes to crash on my systems.
it always crash with below[1] application.

>From my investigation, the root cause is that efi_mm lacks user_ns
initialization. When kthread_use_mm(&efi_mm) temporarily adopts efi_mm
for EFI calls, LSM hooks expect mm->user_ns to be valid for credential
checks. With it being NULL, capability checks crash.

This series contains two patches:

1. efi: Initialize efi_mm.user_ns to &init_user_ns (the actual fix)
2. kthread: Add WARN_ON_ONCE() to catch similar bugs early (RFC)

The second patch is mostly an RFC that adds a warning in
kthread_use_mm() to detect any mm_struct missing user_ns initialization,
helping prevent similar NULL pointer crashes in the future.

Link: https://github.com/facebookincubator/below [1]

Signed-off-by: Breno Leitao <leitao at debian.org>
---
Breno Leitao (2):
      arm64: efi: Fix NULL pointer dereference by initializing user_ns
      kthread: Warn if mm_struct lacks user_ns in kthread_use_mm()

 drivers/firmware/efi/efi.c | 1 +
 kernel/kthread.c           | 1 +
 2 files changed, 2 insertions(+)
---
base-commit: 9448598b22c50c8a5bb77a9103e2d49f134c9578
change-id: 20251223-efi_fix_619-3891ca7d2914

Best regards,
--  
Breno Leitao <leitao at debian.org>



From leitao at debian.org  Tue Dec 23 02:55:43 2025
From: leitao at debian.org (Breno Leitao)
Date: Tue, 23 Dec 2025 02:55:43 -0800
Subject: [PATCH 1/2] arm64: efi: Fix NULL pointer dereference by
 initializing user_ns
In-Reply-To: <20251223-efi_fix_619-v1-0-e0146b8b9d73@debian.org>
References: <20251223-efi_fix_619-v1-0-e0146b8b9d73@debian.org>
Message-ID: <20251223-efi_fix_619-v1-1-e0146b8b9d73@debian.org>

Linux 6.19-rc2 (9448598b22c5 ("Linux 6.19-rc2")) is crashing with a NULL
pointer dereference on arm64 hosts:

  Unable to handle kernel NULL pointer dereference at virtual address 00000000000000c8
   pc : cap_capable (security/commoncap.c:82 security/commoncap.c:128)
   Call trace:
    cap_capable (security/commoncap.c:82 security/commoncap.c:128) (P)
    security_capable (security/security.c:?)
    ns_capable_noaudit (kernel/capability.c:342 kernel/capability.c:381)
    __ptrace_may_access (./include/linux/rcupdate.h:895 kernel/ptrace.c:326)
    ptrace_may_access (kernel/ptrace.c:353)
    do_task_stat (fs/proc/array.c:467)
    proc_tgid_stat (fs/proc/array.c:673)
    proc_single_show (fs/proc/base.c:803)

I've bissected the problem to commit a5baf582f4c0 ("arm64/efi: Call EFI
runtime services without disabling preemption").

>From my analyzes, the crash occurs because efi_mm lacks a user_ns field
initialization. This was previously harmless, but commit a5baf582f4c0
("arm64/efi: Call EFI runtime services without disabling preemption")
changed the EFI runtime call path to use kthread_use_mm(&efi_mm), which
temporarily adopts efi_mm as the current mm for the calling kthread.

When a thread has an active mm, LSM hooks like cap_capable() expect
mm->user_ns to be valid for credential checks. With efi_mm.user_ns being
NULL, capability checks during possible /proc access dereference the
NULL pointer and crash.

Fix by initializing efi_mm.user_ns to &init_user_ns.

Fixes: a5baf582f4c0 ("arm64/efi: Call EFI runtime services without disabling preemption")
Signed-off-by: Breno Leitao <leitao at debian.org>
---
 drivers/firmware/efi/efi.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index a9070d00b833..55452e61af31 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -73,6 +73,7 @@ struct mm_struct efi_mm = {
 	MMAP_LOCK_INITIALIZER(efi_mm)
 	.page_table_lock	= __SPIN_LOCK_UNLOCKED(efi_mm.page_table_lock),
 	.mmlist			= LIST_HEAD_INIT(efi_mm.mmlist),
+	.user_ns		= &init_user_ns,
 	.cpu_bitmap		= { [BITS_TO_LONGS(NR_CPUS)] = 0},
 #ifdef CONFIG_SCHED_MM_CID
 	.mm_cid.lock		= __RAW_SPIN_LOCK_UNLOCKED(efi_mm.mm_cid.lock),

-- 
2.47.3



From leitao at debian.org  Tue Dec 23 02:55:44 2025
From: leitao at debian.org (Breno Leitao)
Date: Tue, 23 Dec 2025 02:55:44 -0800
Subject: [PATCH 2/2] kthread: Warn if mm_struct lacks user_ns in
 kthread_use_mm()
In-Reply-To: <20251223-efi_fix_619-v1-0-e0146b8b9d73@debian.org>
References: <20251223-efi_fix_619-v1-0-e0146b8b9d73@debian.org>
Message-ID: <20251223-efi_fix_619-v1-2-e0146b8b9d73@debian.org>

Add a WARN_ON_ONCE() check to detect mm_struct instances that are
missing user_ns initialization when passed to kthread_use_mm().

When a kthread adopts an mm via kthread_use_mm(), LSM hooks and
capability checks may access current->mm->user_ns for credential
validation. If user_ns is NULL, this leads to a NULL pointer
dereference crash.

This was observed with efi_mm on arm64, where commit a5baf582f4c0
("arm64/efi: Call EFI runtime services without disabling preemption")
introduced kthread_use_mm(&efi_mm), but efi_mm lacked user_ns
initialization, causing crashes during /proc access.

Adding this warning helps catch similar bugs early during development
rather than waiting for hard-to-debug NULL pointer crashes in
production.

Signed-off-by: Breno Leitao <leitao at debian.org>
---
 kernel/kthread.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/kernel/kthread.c b/kernel/kthread.c
index 99a3808d086f..39511dd2abc9 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -1599,6 +1599,7 @@ void kthread_use_mm(struct mm_struct *mm)
 
 	WARN_ON_ONCE(!(tsk->flags & PF_KTHREAD));
 	WARN_ON_ONCE(tsk->mm);
+	WARN_ON_ONCE(!mm->user_ns);
 
 	/*
 	 * It is possible for mm to be the same as tsk->active_mm, but

-- 
2.47.3



From wens at kernel.org  Tue Dec 23 03:04:11 2025
From: wens at kernel.org (Chen-Yu Tsai)
Date: Tue, 23 Dec 2025 19:04:11 +0800
Subject: [PATCH 02/12] i2c: sun6i-p2wi: use i2c_adapter-specific printk helpers
In-Reply-To: <20251223-i2c-printk-helpers-v1-2-46a08306afdb@oss.qualcomm.com>
References: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com> <20251223-i2c-printk-helpers-v1-2-46a08306afdb@oss.qualcomm.com>
Message-ID: <CAGb2v65_bC23uVNdXXy0OW3Zx4wxO+CAuae5zPR4m2zt29kYXA@mail.gmail.com>

On Tue, Dec 23, 2025 at 6:02?PM Bartosz Golaszewski
<bartosz.golaszewski at oss.qualcomm.com> wrote:
>
> Convert all instances of using device printk helpers with struct device
> embedded in struct i2c_adapter to the new i2c-specific macros that hide
> that dereference.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>

Acked-by: Chen-Yu Tsai <wens at kernel.org>

> ---
>  drivers/i2c/busses/i2c-sun6i-p2wi.c | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-sun6i-p2wi.c b/drivers/i2c/busses/i2c-sun6i-p2wi.c
> index fb5280b8cf7fc0e3cba8ea6a318172ea2b011a02..845ca56cdae2d056c122eb648c082f319d955b5e 100644
> --- a/drivers/i2c/busses/i2c-sun6i-p2wi.c
> +++ b/drivers/i2c/busses/i2c-sun6i-p2wi.c
> @@ -122,7 +122,7 @@ static int p2wi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
>         unsigned long dlen = P2WI_DLEN_DATA_LENGTH(1);
>
>         if (p2wi->target_addr >= 0 && addr != p2wi->target_addr) {
> -               dev_err(&adap->dev, "invalid P2WI address\n");
> +               i2c_err(adap, "invalid P2WI address\n");
>                 return -EINVAL;
>         }
>
> @@ -139,7 +139,7 @@ static int p2wi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
>         writel(dlen, p2wi->regs + P2WI_DLEN);
>
>         if (readl(p2wi->regs + P2WI_CTRL) & P2WI_CTRL_START_TRANS) {
> -               dev_err(&adap->dev, "P2WI bus busy\n");
> +               i2c_err(adap, "P2WI bus busy\n");
>                 return -EBUSY;
>         }
>
> @@ -154,12 +154,12 @@ static int p2wi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
>         wait_for_completion(&p2wi->complete);
>
>         if (p2wi->status & P2WI_INTS_LOAD_BSY) {
> -               dev_err(&adap->dev, "P2WI bus busy\n");
> +               i2c_err(adap, "P2WI bus busy\n");
>                 return -EBUSY;
>         }
>
>         if (p2wi->status & P2WI_INTS_TRANS_ERR) {
> -               dev_err(&adap->dev, "P2WI bus xfer error\n");
> +               i2c_err(adap, "P2WI bus xfer error\n");
>                 return -ENXIO;
>         }
>
>
> --
> 2.47.3
>


From sjoerd at collabora.com  Tue Dec 23 03:05:17 2025
From: sjoerd at collabora.com (Sjoerd Simons)
Date: Tue, 23 Dec 2025 12:05:17 +0100
Subject: [PATCH] clk: mediatek: Drop __initconst from gates
Message-ID: <20251223-mtk-gate-v1-1-e4a489ab33de@collabora.com>

Since commit 8ceff24a754a ("clk: mediatek: clk-gate: Refactor
mtk_clk_register_gate to use mtk_gate struct") the mtk_gate structs
are no longer just used for initialization/registration, but also at
runtime. So drop __initconst annotations.

Fixes: 8ceff24a754a ("clk: mediatek: clk-gate: Refactor mtk_clk_register_gate to use mtk_gate struct")
Signed-off-by: Sjoerd Simons <sjoerd at collabora.com>
---
 drivers/clk/mediatek/clk-mt7981-eth.c | 6 +++---
 drivers/clk/mediatek/clk-mt8516.c     | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/clk/mediatek/clk-mt7981-eth.c b/drivers/clk/mediatek/clk-mt7981-eth.c
index 906aec9ddff5..0655ebb6c561 100644
--- a/drivers/clk/mediatek/clk-mt7981-eth.c
+++ b/drivers/clk/mediatek/clk-mt7981-eth.c
@@ -31,7 +31,7 @@ static const struct mtk_gate_regs sgmii0_cg_regs = {
 		.ops = &mtk_clk_gate_ops_no_setclr_inv,	\
 	}
 
-static const struct mtk_gate sgmii0_clks[] __initconst = {
+static const struct mtk_gate sgmii0_clks[] = {
 	GATE_SGMII0(CLK_SGM0_TX_EN, "sgm0_tx_en", "usb_tx250m", 2),
 	GATE_SGMII0(CLK_SGM0_RX_EN, "sgm0_rx_en", "usb_eq_rx250m", 3),
 	GATE_SGMII0(CLK_SGM0_CK0_EN, "sgm0_ck0_en", "usb_ln0", 4),
@@ -53,7 +53,7 @@ static const struct mtk_gate_regs sgmii1_cg_regs = {
 		.ops = &mtk_clk_gate_ops_no_setclr_inv,	\
 	}
 
-static const struct mtk_gate sgmii1_clks[] __initconst = {
+static const struct mtk_gate sgmii1_clks[] = {
 	GATE_SGMII1(CLK_SGM1_TX_EN, "sgm1_tx_en", "usb_tx250m", 2),
 	GATE_SGMII1(CLK_SGM1_RX_EN, "sgm1_rx_en", "usb_eq_rx250m", 3),
 	GATE_SGMII1(CLK_SGM1_CK1_EN, "sgm1_ck1_en", "usb_ln0", 4),
@@ -75,7 +75,7 @@ static const struct mtk_gate_regs eth_cg_regs = {
 		.ops = &mtk_clk_gate_ops_no_setclr_inv,	\
 	}
 
-static const struct mtk_gate eth_clks[] __initconst = {
+static const struct mtk_gate eth_clks[] = {
 	GATE_ETH(CLK_ETH_FE_EN, "eth_fe_en", "netsys_2x", 6),
 	GATE_ETH(CLK_ETH_GP2_EN, "eth_gp2_en", "sgm_325m", 7),
 	GATE_ETH(CLK_ETH_GP1_EN, "eth_gp1_en", "sgm_325m", 8),
diff --git a/drivers/clk/mediatek/clk-mt8516.c b/drivers/clk/mediatek/clk-mt8516.c
index 21eb052b0a53..342a59019fea 100644
--- a/drivers/clk/mediatek/clk-mt8516.c
+++ b/drivers/clk/mediatek/clk-mt8516.c
@@ -544,7 +544,7 @@ static const struct mtk_gate_regs top5_cg_regs = {
 #define GATE_TOP5(_id, _name, _parent, _shift)				\
 	GATE_MTK(_id, _name, _parent, &top5_cg_regs, _shift, &mtk_clk_gate_ops_setclr)
 
-static const struct mtk_gate top_clks[] __initconst = {
+static const struct mtk_gate top_clks[] = {
 	/* TOP1 */
 	GATE_TOP1(CLK_TOP_THEM, "them", "ahb_infra_sel", 1),
 	GATE_TOP1(CLK_TOP_APDMA, "apdma", "ahb_infra_sel", 2),

---
base-commit: b927546677c876e26eba308550207c2ddf812a43
change-id: 20251223-mtk-gate-a98133ab80c9

Best regards,
-- 
Sjoerd Simons <sjoerd at collabora.com>



From lbulwahn at redhat.com  Tue Dec 23 03:07:30 2025
From: lbulwahn at redhat.com (Lukas Bulwahn)
Date: Tue, 23 Dec 2025 12:07:30 +0100
Subject: [PATCH] arm64: Kconfig: deprecate redundant ARM64_USE_LSE_ATOMICS
Message-ID: <20251223110730.121239-1-lukas.bulwahn@redhat.com>

From: Lukas Bulwahn <lukas.bulwahn at redhat.com>

Currently, the config options ARM64_USE_LSE_ATOMICS and ARM64_LSE_ATOMICS
are equivalent, i.e., ARM64_LSE_ATOMICS is true if and only if
ARM64_USE_LSE_ATOMICS is true.

Prior to commit 395af861377d ("arm64: Move the LSE gas support detection to
Kconfig")---included in v5.6-rc1---only the config option ARM64_LSE_ATOMICS
was defined, and the check for gas support was done in the Makefile. This
mentioned commit then introduces the config option ARM64_USE_LSE_ATOMICS to
be the promptable option, and changes the semantics of ARM64_LSE_ATOMICS to
check for the gas support.

Note that there is then some minor refactoring in commit 2decad92f473
("arm64: mte: Ensure TIF_MTE_ASYNC_FAULT is set atomically"), putting this
gas support check into its own config option AS_HAS_LSE_ATOMICS, but the
logic remains the same. Since every binutils version defined suitable for
kernel compilation then eventually included the required support, the
config option AS_HAS_LSE_ATOMICS and the dependency was dropped with
commit 2555d4c68720 ("arm64: drop binutils version checks"). This then
makes ARM64_USE_LSE_ATOMICS and ARM64_LSE_ATOMICS equivalent. Hence, one
of the two config options can be dropped now.

Considerations for the decision which config option to drop:

  - ARM64_USE_LSE_ATOMICS is promptable by the user since its introduction
    in 2020. So there might be some Kconfig fragments that define this
    config option and expect that this then implies ARM64_LSE_ATOMICS to be
    set. However, within the kernel tree, there is no existing config file
    referring to that option. So, it is unlikely to be widely used.
  - ARM64_LSE_ATOMICS is used in nine places within the arm64 directory in
    the current kernel tree.
  - ARM64_USE_LSE_ATOMICS is the only config option that contains the infix
    string _USE_ to enable support and use of an arm64 architectural
    feature. However, there is not a very stringent and consistent naming
    convention for Kconfig options throughout the kernel tree anyway.
  - The use of the transitional attribute allows to simplify transitioning
    to a different Kconfig symbol name, but also adds some intermediate
    definition to be removed later eventually.

After thoughtful consideration, keep ARM_LSE_ATOMICS and remove
ARM64_USE_LSE_ATOMICS in a two-step approach, first deprecate
ARM64_USE_LSE_ATOMICS with the transitional attribute here and then plan
to completely remove it in two or three years with a further dedicated
commit then.

Signed-off-by: Lukas Bulwahn <lukas.bulwahn at redhat.com>
---
CC-ing Vegard and Kees to check that the use of the transitional attribute
is done as it is intended.
 
Note I have set myself a reminder in my personal calendar for three years
in the future from now to remove the transitional Kconfig definition,
assuming by then all users that maintain their Kconfig fragments with
ARM64_USE_LSE_ATOMICS included have transitioned (if such users exist at
all).

 arch/arm64/Kconfig | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 3fb4603c0e16..e113555ef6cd 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1875,11 +1875,8 @@ config ARM64_PAN
 	  instruction if the cpu does not implement the feature.
 
 config ARM64_LSE_ATOMICS
-	bool
-	default ARM64_USE_LSE_ATOMICS
-
-config ARM64_USE_LSE_ATOMICS
 	bool "Atomic instructions"
+	default ARM64_USE_LSE_ATOMICS
 	default y
 	help
 	  As part of the Large System Extensions, ARMv8.1 introduces new
@@ -1890,6 +1887,13 @@ config ARM64_USE_LSE_ATOMICS
 	  atomic routines. This incurs a small overhead on CPUs that do
 	  not support these instructions.
 
+config ARM64_USE_LSE_ATOMICS
+	bool
+	transitional
+	help
+	  Transitional config for ARM64_USE_LSE_ATOMICS to ARM64_LSE_ATOMICS
+	  migration.
+
 endmenu # "ARMv8.1 architectural features"
 
 menu "ARMv8.2 architectural features"
-- 
2.52.0



From andre.draszik at linaro.org  Tue Dec 23 03:23:56 2025
From: andre.draszik at linaro.org (=?ISO-8859-1?Q?Andr=E9?= Draszik)
Date: Tue, 23 Dec 2025 11:23:56 +0000
Subject: [PATCH v4 4/5] soc: samsung: exynos-chipid: add
 google,gs101-otp support
In-Reply-To: <aa55c3865d151697120a2855e711d59468bdcd0a.camel@linaro.org>
References: <20251222-gs101-chipid-v4-0-aa8e20ce7bb3@linaro.org>
		 <20251222-gs101-chipid-v4-4-aa8e20ce7bb3@linaro.org>
	 <aa55c3865d151697120a2855e711d59468bdcd0a.camel@linaro.org>
Message-ID: <a3b89ce1a88e9efb2ff6af27bd1bd48dbc06c2fc.camel@linaro.org>

On Tue, 2025-12-23 at 10:18 +0000, Andr? Draszik wrote:
> Looking closer, why is this not val? Now you're shifting the sub_rev
> register value by the main rev shift, assigning the sub_rev register
> value to the main rev variable.
> 
> And then, all assignments to main_rev become identical and don't need to
> be duplicated.

Anyway, it does work for the SoCs supported, my RB still applies. Code can be
updated in the future if the need arises.

Cheers,
Andre'


From vkoul at kernel.org  Tue Dec 23 03:28:18 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 23 Dec 2025 16:58:18 +0530
Subject: [PATCH] dmaengine: sun6i: Choose appropriate burst length
 under maxburst
In-Reply-To: <20251221080450.1813479-1-wens@kernel.org>
References: <20251221080450.1813479-1-wens@kernel.org>
Message-ID: <176648929819.697163.12733277039569161505.b4-ty@kernel.org>


On Sun, 21 Dec 2025 16:04:48 +0800, Chen-Yu Tsai wrote:
> maxburst, as provided by the client, specifies the largest amount of
> data that is allowed to be transferred in one burst. This limit is
> normally provided to avoid a data burst overflowing the target FIFO.
> It does not mean that the DMA engine can only do bursts in that size.
> 
> Let the driver pick the largest supported burst length within the
> given limit. This lets the driver work correctly with some clients that
> give a large maxburst value. In particular, the 8250_dw driver will give
> a quarter of the UART's FIFO size as maxburst. On some systems the FIFO
> size is 256 bytes, giving a maxburst of 64 bytes, while the hardware
> only supports bursts of up to 16 bytes.
> 
> [...]

Applied, thanks!

[1/1] dmaengine: sun6i: Choose appropriate burst length under maxburst
      commit: 7178c3586ab42693b28bb81014320a7783e5c435

Best regards,
-- 
~Vinod




From vkoul at kernel.org  Tue Dec 23 03:28:20 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 23 Dec 2025 16:58:20 +0530
Subject: [PATCH RESEND] dmaengine: sun6i: Add debug messages for cyclic
 DMA prepare
In-Reply-To: <20251221064754.1783369-1-wens@kernel.org>
References: <20251221064754.1783369-1-wens@kernel.org>
Message-ID: <176648930092.697163.4869399888360483655.b4-ty@kernel.org>


On Sun, 21 Dec 2025 14:47:52 +0800, Chen-Yu Tsai wrote:
> The driver already has debug messages for memcpy and linear transfers,
> but is missing them for cyclic transfers.
> 
> Cyclic transfers are one of the main uses of the DMA controller, used
> for audio data transfers. And since these are likely the first DMA
> peripherals to be enabled, it helps to have these debug messages.
> 
> [...]

Applied, thanks!

[1/1] dmaengine: sun6i: Add debug messages for cyclic DMA prepare
      commit: 7105e968d1f6f6753f8fc3c47b8a705b6dad36d4

Best regards,
-- 
~Vinod




From vkoul at kernel.org  Tue Dec 23 03:28:23 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 23 Dec 2025 16:58:23 +0530
Subject: [PATCH] dmaengine: xilinx_dma: Add support for residue on
 direct AXIDMA S2MM
In-Reply-To: <20251218-xilinx-dma-residue-fix-v1-1-7cd221d69d6b@ideasonboard.com>
References: <20251218-xilinx-dma-residue-fix-v1-1-7cd221d69d6b@ideasonboard.com>
Message-ID: <176648930316.697163.15880064963614554229.b4-ty@kernel.org>


On Thu, 18 Dec 2025 10:39:37 +0200, Tomi Valkeinen wrote:
> AXIDMA IP supports reporting the amount of bytes transferred on the S2MM
> channel in direct mode (i.e. non-SG), but the driver does not. Thus the
> driver always reports that all of the buffer was filled.
> 
> Add xilinx_dma_get_residue_axidma_direct_s2mm() which gets the residue
> amount for direct AXIDMA for S2MM direction.
> 
> [...]

Applied, thanks!

[1/1] dmaengine: xilinx_dma: Add support for residue on direct AXIDMA S2MM
      commit: 5c9142a8063f71233b25d94ae0d73e7dcf9d2a1d

Best regards,
-- 
~Vinod




From vkoul at kernel.org  Tue Dec 23 03:28:25 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 23 Dec 2025 16:58:25 +0530
Subject: [PATCH v2] dmaengine: stm32-mdma: initialize m2m_hw_period and
 ccr to fix warnings
In-Reply-To: <20251217-mdma_warnings_fix-v2-1-340200e0bb55@foss.st.com>
References: <20251217-mdma_warnings_fix-v2-1-340200e0bb55@foss.st.com>
Message-ID: <176648930565.697163.2533356435881488772.b4-ty@kernel.org>


On Wed, 17 Dec 2025 09:15:03 +0100, Amelie Delaunay wrote:
> m2m_hw_period is initialized only when chan_config->m2m_hw is true. This
> triggers a warning:
> ?m2m_hw_period? may be used uninitialized [-Wmaybe-uninitialized]
> Although m2m_hw_period is only used when chan_config->m2m_hw is true and
> ignored otherwise, initialize it unconditionally to 0.
> 
> ccr is initialized by stm32_mdma_set_xfer_param() when the sg list is not
> empty. This triggers a warning:
> ?ccr? may be used uninitialized [-Wmaybe-uninitialized]
> Indeed, it could be used uninitialized if the sg list is empty. Initialize
> it to 0.
> 
> [...]

Applied, thanks!

[1/1] dmaengine: stm32-mdma: initialize m2m_hw_period and ccr to fix warnings
      commit: aaf3bc0265744adbc2d364964ef409cf118d193d

Best regards,
-- 
~Vinod




From vkoul at kernel.org  Tue Dec 23 03:28:28 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 23 Dec 2025 16:58:28 +0530
Subject: [PATCH 0/8] MediaTek UART DMA: Fixes, improvements and new
 SoCs
In-Reply-To: <20251113122229.23998-1-angelogioacchino.delregno@collabora.com>
References: <20251113122229.23998-1-angelogioacchino.delregno@collabora.com>
Message-ID: <176648930864.697163.15382813689450810341.b4-ty@kernel.org>


On Thu, 13 Nov 2025 13:22:21 +0100, AngeloGioacchino Del Regno wrote:
> This series performs fixes the MediaTek UART DMA driver to be able
> to correctly program AP_DMA controllers that support extended
> addressing, performs some cleanups to improve code readability
> and adds support for *all* of the SoCs generations that are upstream.
> 
> This includes MT6795, MT7988, MT8173, MT8183, MT8186, MT8188, MT8195,
> other than all of their Genio variants (where applicable), all of
> their Smartphone variants (where applicable), and also some newer
> generation SoCs that are in the process of being upstreamed, like
> MT8196 and MT8189.
> 
> [...]

Applied, thanks!

[1/8] dt-bindings: dma: mediatek,uart-dma: Allow MT6795 single compatible
      commit: 4b9ce35ca5924c195df1a6bbccdc9aae4f5cb422
[2/8] dt-bindings: dma: mediatek,uart-dma: Deprecate mediatek,dma-33bits
      commit: ebc5e9176e0f9b7effc259b58a7387019ac8811d
[3/8] dt-bindings: dma: mediatek,uart-dma: Support all SoC generations
      commit: fd7843f0da58b37072c1dafa779d128bb36912bf
[4/8] dmaengine: mediatek: uart-apdma: Get addressing bits from match data
      commit: ff81a68a87b1dbf5c1b819f240f83715c701ef0d
[5/8] dmaengine: mediatek: uart-apdma: Fix above 4G addressing TX/RX
      commit: 58ab9d7b6651d21e1cff1777529f2d3dd0b4e851
[6/8] dmaengine: mediatek: mtk-uart-apdma: Rename support_33bits to support_ext_addr
      commit: 7cb173936858f2278d9cf8b2f5d7d52fd000e54e
[7/8] dmaengine: mediatek: mtk-uart-apdma: Add support for Dimensity 6300
      commit: 391e20f21cfdee2f55f2274e83b37c03199062ea
[8/8] dmaengine: mediatek: mtk-uart-apdma: Add support for Dimensity 9200
      commit: 3587b2b6bf7681835c7c366c6083e2cd9e4b519d

Best regards,
-- 
~Vinod




From vkoul at kernel.org  Tue Dec 23 03:28:36 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 23 Dec 2025 16:58:36 +0530
Subject: [PATCH dmaengine 0/2] dmaengine: st_fdma: support COMPILE_TEST
In-Reply-To: <20251106022015.84970-1-rosenp@gmail.com>
References: <20251106022015.84970-1-rosenp@gmail.com>
Message-ID: <176648931679.697163.16396174417183020187.b4-ty@kernel.org>


On Wed, 05 Nov 2025 18:20:13 -0800, Rosen Penev wrote:
> First commit fixes compilation under 64-bit and second actually enables
> it.
> 
> Rosen Penev (2):
>   dmaengine: st_fdma: change dreg_line to long
>   dmaengine: st_fdma: add COMPILE_TEST support
> 
> [...]

Applied, thanks!

[1/2] dmaengine: st_fdma: change dreg_line to long
      commit: 19fed6ca15c4c41c28059c25f9cc85c0058cc4fd
[2/2] dmaengine: st_fdma: add COMPILE_TEST support
      commit: c3af05623e079c2a9a9363386796fdea20defa18

Best regards,
-- 
~Vinod




From vkoul at kernel.org  Tue Dec 23 03:28:41 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 23 Dec 2025 16:58:41 +0530
Subject: (subset) [PATCH V2 0/4] Add tegra264 audio device tree support
In-Reply-To: <20250929105930.1767294-1-sheetal@nvidia.com>
References: <20250929105930.1767294-1-sheetal@nvidia.com>
Message-ID: <176648932106.697163.11384203027531307860.b4-ty@kernel.org>


On Mon, 29 Sep 2025 16:29:26 +0530, Sheetal . wrote:
> Add device tree support for tegra264 audio subsystem including:
> - Binding update for
>   - 64-channel ADMA controller
>   - 32 RX/TX ADMAIF channels
>   - tegra264-agic binding for arm,gic
> - Add device tree nodes for
>   - APE subsystem (ACONNECT, AGIC, ADMA, AHUB and children (ADMAIF, I2S,
>     DMIC, DSPK, MVC, SFC, ASRC, AMX, ADX, OPE and Mixer) nodes
>   - HDA controller
>   - sound
> 
> [...]

Applied, thanks!

[1/4] dt-bindings: dma: Update ADMA bindings for tegra264
      commit: 0b4f3aeee766fd3cc3bf254a26b9761d9b53818b

Best regards,
-- 
~Vinod




From tomi.valkeinen at ideasonboard.com  Tue Dec 23 03:48:48 2025
From: tomi.valkeinen at ideasonboard.com (Tomi Valkeinen)
Date: Tue, 23 Dec 2025 13:48:48 +0200
Subject: [PATCH 0/4] drm: Revert and fix enable/disable sequence
In-Reply-To: <CAD++jLm_0xweD4tRJ8ZfwmcOe2BBGCsUuL1UWUiNM+Gpbq3Zuw@mail.gmail.com>
References: <20251205-drm-seq-fix-v1-0-fda68fa1b3de@ideasonboard.com>
 <3b13c7a2-f7e6-49fd-b3bb-3e0a1fe9acf3@ideasonboard.com>
 <CAD++jLk8-0Rkh16T+R1dh6=e_f9U1i=AKOk1Y8dLGV4bxzRtFg@mail.gmail.com>
 <817b2358-0920-4b7a-abb1-133103d0f9fe@ideasonboard.com>
 <CAD++jLm_0xweD4tRJ8ZfwmcOe2BBGCsUuL1UWUiNM+Gpbq3Zuw@mail.gmail.com>
Message-ID: <6be8aaf6-b01d-4444-9850-967f8e316896@ideasonboard.com>

Hi,

On 23/12/2025 01:18, Linus Walleij wrote:
> On Sun, Dec 14, 2025 at 1:42?PM Tomi Valkeinen
> <tomi.valkeinen at ideasonboard.com> wrote:
> 
>>>> Should we merge this series as a fix for 6.18 rcs?
>>>
>>> Too late now, so let's merge it as a fix for v6.19 rcs!
>>
>> Ah, right. Indeed, I meant v6.19 rcs.
> 
> Are you applying it or should I?
> Not sure if you want some special timing, like outside of
> holidays.
Oh. No, I'm not a DRM maintainer, so I was waiting for someone to merge
this. From my point of view it's ready for merging.

 Tomi



From chuan.liu at amlogic.com  Tue Dec 23 03:56:02 2025
From: chuan.liu at amlogic.com (Chuan Liu)
Date: Tue, 23 Dec 2025 19:56:02 +0800
Subject: [PATCH v4 1/8] dt-bindings: clock: Add Amlogic A5 SCMI clock
 controller support
In-Reply-To: <1jv7hx7ew6.fsf@starbuckisacylon.baylibre.com>
References: <20251028-a5-clk-v4-0-e62ca0aae243@amlogic.com>
 <20251028-a5-clk-v4-1-e62ca0aae243@amlogic.com>
 <1jv7hx7ew6.fsf@starbuckisacylon.baylibre.com>
Message-ID: <a4d1c7a1-f7b5-4717-b356-0562efdb9815@amlogic.com>

Hi Jerome,
Thanks for coming back to review. Y

On 12/23/2025 4:59 PM, Jerome Brunet wrote:
> [ EXTERNAL EMAIL ]
> 
> On Tue 28 Oct 2025 at 17:52, Chuan Liu via B4 Relay <devnull+chuan.liu.amlogic.com at kernel.org> wrote:
> 
>> From: Chuan Liu <chuan.liu at amlogic.com>
>>
>> Add the SCMI clock controller dt-bindings for the Amlogic A5 SoC
>> family.
>>
>> Signed-off-by: Chuan Liu <chuan.liu at amlogic.com>
>> Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
>> Signed-off-by: Xianwei Zhao <xianwei.zhao at amlogic.com>
> 
> Please read:
> 
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/submitting-patches.rst?h=v6.19-rc1#n503
> 
> and adjust your patches accordingly
> 

Thanks for pointing that out. I'll address it.

>> ---
>>   include/dt-bindings/clock/amlogic,a5-scmi-clkc.h | 44 ++++++++++++++++++++++++
>>   1 file changed, 44 insertions(+)
>>
>> diff --git a/include/dt-bindings/clock/amlogic,a5-scmi-clkc.h b/include/dt-bindings/clock/amlogic,a5-scmi-clkc.h
>> new file mode 100644
>> index 000000000000..1bf027d0110a
>> --- /dev/null
>> +++ b/include/dt-bindings/clock/amlogic,a5-scmi-clkc.h
>> @@ -0,0 +1,44 @@
>> +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
>> +/*
>> + * Copyright (c) 2024 Amlogic, Inc. All rights reserved.
>> + * Author: Chuan Liu <chuan.liu at amlogic.com>
>> + */
>> +
>> +#ifndef __AMLOGIC_A5_SCMI_CLKC_H
>> +#define __AMLOGIC_A5_SCMI_CLKC_H
>> +
>> +#define CLKID_OSC                            0
>> +#define CLKID_SYS_CLK                                1
>> +#define CLKID_AXI_CLK                                2
>> +#define CLKID_CPU_CLK                                3
>> +#define CLKID_DSU_CLK                                4
>> +#define CLKID_GP1_PLL                                5
>> +#define CLKID_FIXED_PLL_DCO                  6
>> +#define CLKID_FIXED_PLL                              7
>> +#define CLKID_ACLKM                          8
>> +#define CLKID_SYS_PLL_DIV16                  9
>> +#define CLKID_CPU_CLK_DIV16                  10
>> +#define CLKID_FCLK_50M_PREDIV                        11
>> +#define CLKID_FCLK_50M_DIV                   12
>> +#define CLKID_FCLK_50M                               13
>> +#define CLKID_FCLK_DIV2_DIV                  14
>> +#define CLKID_FCLK_DIV2                              15
>> +#define CLKID_FCLK_DIV2P5_DIV                        16
>> +#define CLKID_FCLK_DIV2P5                    17
>> +#define CLKID_FCLK_DIV3_DIV                  18
>> +#define CLKID_FCLK_DIV3                              19
>> +#define CLKID_FCLK_DIV4_DIV                  20
>> +#define CLKID_FCLK_DIV4                              21
>> +#define CLKID_FCLK_DIV5_DIV                  22
>> +#define CLKID_FCLK_DIV5                              23
>> +#define CLKID_FCLK_DIV7_DIV                  24
>> +#define CLKID_FCLK_DIV7                              25
>> +#define CLKID_SYS_MMC_PCLK                   26
>> +#define CLKID_SYS_CPU_CTRL                   27
>> +#define CLKID_SYS_IRQ_CTRL                   28
>> +#define CLKID_SYS_GIC                                29
>> +#define CLKID_SYS_BIG_NIC                    30
>> +#define CLKID_AXI_SYS_NIC                    31
>> +#define CLKID_AXI_CPU_DMC                    32
>> +
>> +#endif /* __AMLOGIC_A5_SCMI_CLKC_H */
> 
> --
> Jerome



From julia.lawall at inria.fr  Tue Dec 23 03:57:43 2025
From: julia.lawall at inria.fr (Julia Lawall)
Date: Tue, 23 Dec 2025 12:57:43 +0100 (CET)
Subject: [arm-platforms:kvm-arm64/gicv5-full 63/82] arch/arm64/kvm/vgic/vgic-kvm-device.c:187:3-9:
 preceding lock on line 111 (fwd)
Message-ID: <db3b9674-4fb1-3c5a-ad3-944949960b2@inria.fr>

Please check whether an unlock is needed on line 187.

julia

---------- Forwarded message ----------
Date: Tue, 23 Dec 2025 19:37:11 +0800
From: kernel test robot <lkp at intel.com>
To: oe-kbuild at lists.linux.dev
Cc: lkp at intel.com, Julia Lawall <julia.lawall at inria.fr>
Subject: [arm-platforms:kvm-arm64/gicv5-full 63/82]
    arch/arm64/kvm/vgic/vgic-kvm-device.c:187:3-9: preceding lock on line 111

BCC: lkp at intel.com
CC: oe-kbuild-all at lists.linux.dev
CC: linux-arm-kernel at lists.infradead.org
TO: Sascha Bischoff <sascha.bischoff at arm.com>

tree:   https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git kvm-arm64/gicv5-full
head:   1426b88096b597395df4c82f089b87c62bab45da
commit: 77646e062bb3fbc3f7a614ab5d1bc7f273748c61 [63/82] KVM: arm64: gic-v5: Register the IRS IODEV
:::::: branch date: 4 days ago
:::::: commit date: 4 days ago
config: arm64-randconfig-r064-20251223 (https://download.01.org/0day-ci/archive/20251223/202512231907.IGXeZ6an-lkp at intel.com/config)
compiler: aarch64-linux-gcc (GCC) 15.1.0

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Reported-by: Julia Lawall <julia.lawall at inria.fr>
| Closes: https://lore.kernel.org/r/202512231907.IGXeZ6an-lkp at intel.com/

cocci warnings: (new ones prefixed by >>)
>> arch/arm64/kvm/vgic/vgic-kvm-device.c:187:3-9: preceding lock on line 111

vim +187 arch/arm64/kvm/vgic/vgic-kvm-device.c

9f968c9266aa30 arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05   77
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21   78  /**
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21   79   * kvm_vgic_addr - set or get vgic VM base addresses
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21   80   * @kvm:   pointer to the vm struct
4b85080f4e378f arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05   81   * @attr:  pointer to the attribute being retrieved/updated
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21   82   * @write: if true set the address in the VM address space, if false read the
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21   83   *          address
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21   84   *
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21   85   * Set or get the vgic base addresses for the distributor and the virtual CPU
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21   86   * interface in the VM physical address space.  These addresses are properties
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21   87   * of the emulated core/SoC and therefore user space initially knows this
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21   88   * information.
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21   89   * Check them for sanity (alignment, double assignment). We can't check for
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21   90   * overlapping regions in case of a virtual GICv3 here, since we don't know
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21   91   * the number of VCPUs yet, so we defer this check to map_resources().
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21   92   */
4b85080f4e378f arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05   93  static int kvm_vgic_addr(struct kvm *kvm, struct kvm_device_attr *attr, bool write)
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21   94  {
4b85080f4e378f arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05   95  	u64 __user *uaddr = (u64 __user *)attr->addr;
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21   96  	struct vgic_dist *vgic = &kvm->arch.vgic;
c56a87da0a7fa1 arch/arm64/kvm/vgic/vgic-kvm-device.c Ricardo Koller        2021-10-04   97  	phys_addr_t *addr_ptr, alignment, size;
dbd9733ab6742d virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22   98  	u64 undef_value = VGIC_ADDR_UNDEF;
4b85080f4e378f arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05   99  	u64 addr;
4b85080f4e378f arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05  100  	int r;
4b85080f4e378f arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05  101
4b85080f4e378f arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05  102  	/* Reading a redistributor region addr implies getting the index */
4b85080f4e378f arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05  103  	if (write || attr->attr == KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION)
4b85080f4e378f arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05  104  		if (get_user(addr, uaddr))
4b85080f4e378f arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05  105  			return -EFAULT;
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  106
59112e9c390be5 arch/arm64/kvm/vgic/vgic-kvm-device.c Jean-Philippe Brucker 2023-05-18  107  	/*
59112e9c390be5 arch/arm64/kvm/vgic/vgic-kvm-device.c Jean-Philippe Brucker 2023-05-18  108  	 * Since we can't hold config_lock while registering the redistributor
59112e9c390be5 arch/arm64/kvm/vgic/vgic-kvm-device.c Jean-Philippe Brucker 2023-05-18  109  	 * iodevs, take the slots_lock immediately.
59112e9c390be5 arch/arm64/kvm/vgic/vgic-kvm-device.c Jean-Philippe Brucker 2023-05-18  110  	 */
59112e9c390be5 arch/arm64/kvm/vgic/vgic-kvm-device.c Jean-Philippe Brucker 2023-05-18 @111  	mutex_lock(&kvm->slots_lock);
4b85080f4e378f arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05  112  	switch (attr->attr) {
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  113  	case KVM_VGIC_V2_ADDR_TYPE_DIST:
72030536ebf5e5 virt/kvm/arm/vgic/vgic-kvm-device.c   Christoffer Dall      2017-05-08  114  		r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V2);
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  115  		addr_ptr = &vgic->vgic_dist_base;
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  116  		alignment = SZ_4K;
c56a87da0a7fa1 arch/arm64/kvm/vgic/vgic-kvm-device.c Ricardo Koller        2021-10-04  117  		size = KVM_VGIC_V2_DIST_SIZE;
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  118  		break;
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  119  	case KVM_VGIC_V2_ADDR_TYPE_CPU:
72030536ebf5e5 virt/kvm/arm/vgic/vgic-kvm-device.c   Christoffer Dall      2017-05-08  120  		r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V2);
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  121  		addr_ptr = &vgic->vgic_cpu_base;
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  122  		alignment = SZ_4K;
c56a87da0a7fa1 arch/arm64/kvm/vgic/vgic-kvm-device.c Ricardo Koller        2021-10-04  123  		size = KVM_VGIC_V2_CPU_SIZE;
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  124  		break;
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  125  	case KVM_VGIC_V3_ADDR_TYPE_DIST:
72030536ebf5e5 virt/kvm/arm/vgic/vgic-kvm-device.c   Christoffer Dall      2017-05-08  126  		r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V3);
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  127  		addr_ptr = &vgic->vgic_dist_base;
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  128  		alignment = SZ_64K;
c56a87da0a7fa1 arch/arm64/kvm/vgic/vgic-kvm-device.c Ricardo Koller        2021-10-04  129  		size = KVM_VGIC_V3_DIST_SIZE;
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  130  		break;
dbd9733ab6742d virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  131  	case KVM_VGIC_V3_ADDR_TYPE_REDIST: {
dbd9733ab6742d virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  132  		struct vgic_redist_region *rdreg;
dbd9733ab6742d virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  133
72030536ebf5e5 virt/kvm/arm/vgic/vgic-kvm-device.c   Christoffer Dall      2017-05-08  134  		r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V3);
1aab6f468c10a1 virt/kvm/arm/vgic/vgic-kvm-device.c   Christoffer Dall      2017-05-08  135  		if (r)
1aab6f468c10a1 virt/kvm/arm/vgic/vgic-kvm-device.c   Christoffer Dall      2017-05-08  136  			break;
1aab6f468c10a1 virt/kvm/arm/vgic/vgic-kvm-device.c   Christoffer Dall      2017-05-08  137  		if (write) {
4b85080f4e378f arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05  138  			r = vgic_v3_set_redist_base(kvm, 0, addr, 0);
1aab6f468c10a1 virt/kvm/arm/vgic/vgic-kvm-device.c   Christoffer Dall      2017-05-08  139  			goto out;
1aab6f468c10a1 virt/kvm/arm/vgic/vgic-kvm-device.c   Christoffer Dall      2017-05-08  140  		}
94ac0835391efc arch/arm64/kvm/vgic/vgic-kvm-device.c Eric Auger            2021-04-12  141  		rdreg = list_first_entry_or_null(&vgic->rd_regions,
dbd9733ab6742d virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  142  						 struct vgic_redist_region, list);
dbd9733ab6742d virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  143  		if (!rdreg)
dbd9733ab6742d virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  144  			addr_ptr = &undef_value;
dbd9733ab6742d virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  145  		else
dbd9733ab6742d virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  146  			addr_ptr = &rdreg->base;
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  147  		break;
dbd9733ab6742d virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  148  	}
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  149  	case KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION:
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  150  	{
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  151  		struct vgic_redist_region *rdreg;
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  152  		u8 index;
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  153
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  154  		r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V3);
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  155  		if (r)
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  156  			break;
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  157
4b85080f4e378f arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05  158  		index = addr & KVM_VGIC_V3_RDIST_INDEX_MASK;
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  159
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  160  		if (write) {
4b85080f4e378f arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05  161  			gpa_t base = addr & KVM_VGIC_V3_RDIST_BASE_MASK;
4b85080f4e378f arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05  162  			u32 count = FIELD_GET(KVM_VGIC_V3_RDIST_COUNT_MASK, addr);
4b85080f4e378f arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05  163  			u8 flags = FIELD_GET(KVM_VGIC_V3_RDIST_FLAGS_MASK, addr);
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  164
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  165  			if (!count || flags)
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  166  				r = -EINVAL;
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  167  			else
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  168  				r = vgic_v3_set_redist_base(kvm, index,
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  169  							    base, count);
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  170  			goto out;
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  171  		}
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  172
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  173  		rdreg = vgic_v3_rdist_region_from_index(kvm, index);
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  174  		if (!rdreg) {
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  175  			r = -ENOENT;
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  176  			goto out;
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  177  		}
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  178
4b85080f4e378f arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05  179  		addr = index;
4b85080f4e378f arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05  180  		addr |= rdreg->base;
4b85080f4e378f arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05  181  		addr |= (u64)rdreg->count << KVM_VGIC_V3_RDIST_COUNT_SHIFT;
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  182  		goto out;
04c11093222579 virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2018-05-22  183  	}
77646e062bb3fb arch/arm64/kvm/vgic/vgic-kvm-device.c Sascha Bischoff       2025-12-11  184  	case KVM_VGIC_V5_ADDR_TYPE_IRS:
77646e062bb3fb arch/arm64/kvm/vgic/vgic-kvm-device.c Sascha Bischoff       2025-12-11  185  		r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V5);
77646e062bb3fb arch/arm64/kvm/vgic/vgic-kvm-device.c Sascha Bischoff       2025-12-11  186  		if (r)
77646e062bb3fb arch/arm64/kvm/vgic/vgic-kvm-device.c Sascha Bischoff       2025-12-11 @187  			return r;
77646e062bb3fb arch/arm64/kvm/vgic/vgic-kvm-device.c Sascha Bischoff       2025-12-11  188  		addr_ptr = &vgic->vgic_v5_irs_data->vgic_v5_irs_base;
77646e062bb3fb arch/arm64/kvm/vgic/vgic-kvm-device.c Sascha Bischoff       2025-12-11  189  		alignment = SZ_64K;
77646e062bb3fb arch/arm64/kvm/vgic/vgic-kvm-device.c Sascha Bischoff       2025-12-11  190  		size = KVM_VGIC_V5_IRS_SIZE;
77646e062bb3fb arch/arm64/kvm/vgic/vgic-kvm-device.c Sascha Bischoff       2025-12-11  191  		get_user(addr, uaddr);
77646e062bb3fb arch/arm64/kvm/vgic/vgic-kvm-device.c Sascha Bischoff       2025-12-11  192  		break;
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  193  	default:
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  194  		r = -ENODEV;
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  195  	}
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  196
72030536ebf5e5 virt/kvm/arm/vgic/vgic-kvm-device.c   Christoffer Dall      2017-05-08  197  	if (r)
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  198  		goto out;
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  199
59112e9c390be5 arch/arm64/kvm/vgic/vgic-kvm-device.c Jean-Philippe Brucker 2023-05-18  200  	mutex_lock(&kvm->arch.config_lock);
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  201  	if (write) {
4b85080f4e378f arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05  202  		r = vgic_check_iorange(kvm, *addr_ptr, addr, alignment, size);
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  203  		if (!r)
4b85080f4e378f arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05  204  			*addr_ptr = addr;
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  205  	} else {
4b85080f4e378f arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05  206  		addr = *addr_ptr;
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  207  	}
59112e9c390be5 arch/arm64/kvm/vgic/vgic-kvm-device.c Jean-Philippe Brucker 2023-05-18  208  	mutex_unlock(&kvm->arch.config_lock);
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  209
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  210  out:
59112e9c390be5 arch/arm64/kvm/vgic/vgic-kvm-device.c Jean-Philippe Brucker 2023-05-18  211  	mutex_unlock(&kvm->slots_lock);
4b85080f4e378f arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05  212
4b85080f4e378f arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05  213  	if (!r && !write)
4b85080f4e378f arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05  214  		r =  put_user(addr, uaddr);
4b85080f4e378f arch/arm64/kvm/vgic/vgic-kvm-device.c Marc Zyngier          2022-07-05  215
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  216  	return r;
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  217  }
e2c1f9abff83ee virt/kvm/arm/vgic/vgic-kvm-device.c   Eric Auger            2015-12-21  218

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From jonathan.cameron at huawei.com  Tue Dec 23 03:58:01 2025
From: jonathan.cameron at huawei.com (Jonathan Cameron)
Date: Tue, 23 Dec 2025 11:58:01 +0000
Subject: [PATCH v2 01/45] arm_mpam: Stop using uninitialized variables
 in __ris_msmon_read()
In-Reply-To: <20251219181147.3404071-2-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
	<20251219181147.3404071-2-ben.horgan@arm.com>
Message-ID: <20251223115801.000033cb@huawei.com>

On Fri, 19 Dec 2025 18:11:03 +0000
Ben Horgan <ben.horgan at arm.com> wrote:

> Dan has reported two uses of uninitialized variables in __ris_msmon_read().
> If an unknown monitor type is encountered then the local variable, now, is
> used uninitialized. Fix this by returning early on error. If a non-mbwu
> monitor is being read then the local variable, overflow, is not initialized
> but still read. Initialize it to false as overflow is not relevant for csu
> monitors.
> 
> Reported-by: kernel test robot <lkp at intel.com>
> Reported-by: Dan Carpenter <dan.carpenter at linaro.org>
> Closes: https://lore.kernel.org/r/202512091519.RBwiJcSq-lkp at intel.com/
> Closes: https://lore.kernel.org/r/202512100547.N7QPYgfb-lkp at intel.com/
> Signed-off-by: Ben Horgan <ben.horgan at arm.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron at huawei.com>


From sebin.francis at ti.com  Tue Dec 23 04:02:46 2025
From: sebin.francis at ti.com (Sebin Francis)
Date: Tue, 23 Dec 2025 17:32:46 +0530
Subject: [PATCH v6 0/6] clk: Support spread spectrum and use it in
 clk-scmi
In-Reply-To: <20251128-clk-ssc-v6-2-v6-0-cfafdb5d6811@nxp.com>
References: <20251128-clk-ssc-v6-2-v6-0-cfafdb5d6811@nxp.com>
Message-ID: <e547db61-1ce3-4b55-948d-28d3257d68ba@ti.com>

Hi Peng,

On 28/11/25 08:44, Peng Fan (OSS) wrote:
> Since the assigned-clock-sscs property [1] has been accepted into the device
> tree schema, we can now support it in the Linux clock driver. Therefore,
> I've picked up the previously submitted work [2] titled "clk: Support
> spread spectrum and use it in clk-pll144x and clk-scmi."
> As more than six months have passed since [2] was posted, I?m treating this
> patchset as a new submission rather than a v3.
> 
> - Introduce clk_set_spread_spectrum to set the parameters for enabling
>    spread spectrum of a clock.
> - Parse 'assigned-clock-sscs' and configure it by default before using the
>    clock. This property is parsed before parsing clock rate.
> - Enable this feature for clk-scmi on i.MX95.
> 
> Because SCMI spec will not include spread spectrum as a standard
> extension, we still need to use NXP i.MX OEM extension.
> 
> [1] https://github.com/devicetree-org/dt-schema/pull/154
> [2] https://lore.kernel.org/all/20250205-clk-ssc-v2-0-fa73083caa92 at nxp.com/
> 
> Signed-off-by: Peng Fan <peng.fan at nxp.com>
> ---

Thanks for incorporating the changes, The changes looks good to me!

Reviewed-by: Sebin Francis <sebin.francis at ti.com>

---

Thanks
Sebin


From angelogioacchino.delregno at collabora.com  Tue Dec 23 04:04:53 2025
From: angelogioacchino.delregno at collabora.com (AngeloGioacchino Del Regno)
Date: Tue, 23 Dec 2025 13:04:53 +0100
Subject: [PATCH v4 00/25] MediaTek UFS Cleanup and MT8196 Enablement
In-Reply-To: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
Message-ID: <ddff4617-884d-4ac2-bc24-28f669104b2e@collabora.com>

Il 18/12/25 13:54, Nicolas Frattaroli ha scritto:
> In this series, the existing MediaTek UFS binding is expanded and
> completed to correctly describe not just the existing compatibles, but
> also to introduce a new compatible in the from of the MT8196 SoC.
> 
> The resets, which until now were completely absent from both the UFS
> host controller binding and the UFS PHY binding, are introduced to both.
> This also means the driver's undocumented and, in mainline, unused reset
> logic is reworked. In particular, the PHY reset is no longer a reset of
> the host controller node, but of the PHY node.
> 
> This means the host controller can reset the PHY through the common PHY
> framework.
> 
> The resets remain optional.
> 
> Additionally, a massive number of driver cleanups are introduced. These
> were prompted by me inspecting the driver more closely as I was
> adjusting it to correspond to the binding.
> 
> The driver still implements vendor properties that are undocumented in
> the binding. I did not touch most of those, as I neither want to
> convince the bindings maintainers that they are needed without knowing
> precisely what they're for, nor do I want to argue with the driver
> authors when removing them.
> 
> Due to the "Marie Kondo with a chainsaw" nature of the driver cleanup
> patches, I humbly request that reviewers do not comment on displeasing
> code they see in the context portion of a patch before they've read the
> whole patch series, as that displeasing code may in fact be reworked in
> a subsequent patch of this series. Please keep comments focused on the
> changed lines of the diff; I know there's more that can be done, but it
> doesn't necessarily need to be part of this series.
> 
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
> ---
> Changes in v4:
> - bindings: Redo the supply situation, as the avdd pins don't describe
>    the vcc(q2) card supplies.
> - bindings: format clock in mt8196 example more tersely.
> - phy: use devm_reset_control_get_optional_exclusive directly
> - driver: get and enable/disable the aforementioned avdd supplies.
> - Link to v3: https://lore.kernel.org/r/20251023-mt8196-ufs-v3-0-0f04b4a795ff at collabora.com
> 
> Changes in v3:
> - Split mediatek,ufs bindings change into two patches, one for
>    completing the existing binding, one for the MT8196
> - Add over a dozen driver cleanup patches
> - Add explicit support for the MT8196 compatible to the driver
> - Note: next-20251023, on which I based this, currently has a broken
>    build due to an unrelated OPP core change that was merged with no
>    build testing. I can't use next-20251022 either, as that lacks the
>    recent mediatek UFS changes. It is what it is.
> - Link to v2: https://lore.kernel.org/r/20251016-mt8196-ufs-v2-0-c373834c4e7a at collabora.com
> 
> Changes in v2:
> - Reorder define in mtk_sip_svc.h
> - Use bulk reset APIs in UFS host driver
> - Link to v1: https://lore.kernel.org/r/20251014-mt8196-ufs-v1-0-195dceb83bc8 at collabora.com
> 

Whole series is

Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>




From lakshmicar.2023 at gmail.com  Tue Dec 23 04:06:22 2025
From: lakshmicar.2023 at gmail.com (Lakshmi S)
Date: Tue, 23 Dec 2025 17:36:22 +0530
Subject: [PATCH] mailbox: cix: fix typo in error message
Message-ID: <20251223120622.4316-1-lakshmicar.2023@gmail.com>

Fix typo "overlow" -> "overflow" in FIFO overflow error message.

Signed-off-by: Lakshmi S <lakshmicar.2023 at gmail.com>
---
 drivers/mailbox/cix-mailbox.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mailbox/cix-mailbox.c b/drivers/mailbox/cix-mailbox.c
index 5bb1416c26a5..443620e8ae37 100644
--- a/drivers/mailbox/cix-mailbox.c
+++ b/drivers/mailbox/cix-mailbox.c
@@ -346,7 +346,7 @@ static void cix_mbox_isr_fifo(struct mbox_chan *chan)
 		/* FIFO overflow is generated */
 		if (int_status & CIX_FIFO_OFLOW_INT) {
 			status = cix_mbox_read(priv, CIX_FIFO_STAS);
-			dev_err(priv->dev, "fifo overlow: int_stats %d\n", status);
+			dev_err(priv->dev, "fifo overflow: int_stats %d\n", status);
 			cix_mbox_write(priv, CIX_FIFO_OFLOW_INT, CIX_INT_CLEAR);
 		}
 	}
-- 
2.25.1



From jonathan.cameron at huawei.com  Tue Dec 23 04:10:23 2025
From: jonathan.cameron at huawei.com (Jonathan Cameron)
Date: Tue, 23 Dec 2025 12:10:23 +0000
Subject: [PATCH v2 02/45] arm_mpam: Remove duplicate linux/srcu.h header
In-Reply-To: <20251219181147.3404071-3-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
	<20251219181147.3404071-3-ben.horgan@arm.com>
Message-ID: <20251223121023.0000200e@huawei.com>

On Fri, 19 Dec 2025 18:11:04 +0000
Ben Horgan <ben.horgan at arm.com> wrote:

> From: Jiapeng Chong <jiapeng.chong at linux.alibaba.com>
> 
> ./drivers/resctrl/mpam_internal.h: linux/srcu.h is included more than once.
> 
> Reported-by: Abaci Robot <abaci at linux.alibaba.com>
> Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=27328
> Signed-off-by: Jiapeng Chong <jiapeng.chong at linux.alibaba.com>
> Acked-by: James Morse <james.morse at arm.com>
> [BH: Keep alphabetical order]
> Signed-off-by: Ben Horgan <ben.horgan at arm.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron at huawei.com>


From chuan.liu at amlogic.com  Tue Dec 23 04:27:39 2025
From: chuan.liu at amlogic.com (Chuan Liu)
Date: Tue, 23 Dec 2025 20:27:39 +0800
Subject: [PATCH v4 5/8] clk: amlogic: Add A5 clock peripherals controller
 driver
In-Reply-To: <1jpl857e2w.fsf@starbuckisacylon.baylibre.com>
References: <20251028-a5-clk-v4-0-e62ca0aae243@amlogic.com>
 <20251028-a5-clk-v4-5-e62ca0aae243@amlogic.com>
 <1jpl857e2w.fsf@starbuckisacylon.baylibre.com>
Message-ID: <425ebeb4-8001-4493-882b-dfee87ed82c8@amlogic.com>

Hi Jerome,

On 12/23/2025 5:16 PM, Jerome Brunet wrote:
> [ EXTERNAL EMAIL ]
> 
> On Tue 28 Oct 2025 at 17:52, Chuan Liu via B4 Relay <devnull+chuan.liu.amlogic.com at kernel.org> wrote:
> 
>> From: Chuan Liu <chuan.liu at amlogic.com>
>>
>> Add the peripherals clock controller driver for the Amlogic A5 SoC
>> family.
>>
>> Signed-off-by: Chuan Liu <chuan.liu at amlogic.com>
>> Signed-off-by: Xianwei Zhao <xianwei.zhao at amlogic.com>
>> ---
>>   drivers/clk/meson/Kconfig          |  13 +
>>   drivers/clk/meson/Makefile         |   1 +
>>   drivers/clk/meson/a5-peripherals.c | 883 +++++++++++++++++++++++++++++++++++++
>>   3 files changed, 897 insertions(+)
>>
>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
>> index b627821da081..5576f351ef8c 100644
>> --- a/drivers/clk/meson/Kconfig
>> +++ b/drivers/clk/meson/Kconfig
>> @@ -146,6 +146,19 @@ config COMMON_CLK_A5_PLL
>>          Say Y if you want the board to work, because PLLs are the parent
>>          of most peripherals.
>>
>> +config COMMON_CLK_A5_PERIPHERALS
>> +     tristate "Amlogic A5 peripherals clock controller"
>> +     depends on ARM64
>> +     default ARCH_MESON
>> +     select COMMON_CLK_MESON_REGMAP
>> +     select COMMON_CLK_MESON_DUALDIV
>> +     select COMMON_CLK_MESON_CLKC_UTILS
>> +     imply COMMON_CLK_SCMI
>> +     imply COMMON_CLK_A5_PLL
>> +     help
>> +       Support for the Peripherals clock controller on Amlogic A113X2 device,
>> +       AKA A5. Say Y if you want the peripherals clock to work.
>> +
>>   config COMMON_CLK_C3_PLL
>>        tristate "Amlogic C3 PLL clock controller"
>>        depends on ARM64
>> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
>> index a074aa7e187f..0432027d7e2e 100644
>> --- a/drivers/clk/meson/Makefile
>> +++ b/drivers/clk/meson/Makefile
>> @@ -20,6 +20,7 @@ obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
>>   obj-$(CONFIG_COMMON_CLK_A1_PLL) += a1-pll.o
>>   obj-$(CONFIG_COMMON_CLK_A1_PERIPHERALS) += a1-peripherals.o
>>   obj-$(CONFIG_COMMON_CLK_A5_PLL) += a5-pll.o
>> +obj-$(CONFIG_COMMON_CLK_A5_PERIPHERALS) += a5-peripherals.o
>>   obj-$(CONFIG_COMMON_CLK_C3_PLL) += c3-pll.o
>>   obj-$(CONFIG_COMMON_CLK_C3_PERIPHERALS) += c3-peripherals.o
>>   obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
>> diff --git a/drivers/clk/meson/a5-peripherals.c b/drivers/clk/meson/a5-peripherals.c
>> new file mode 100644
>> index 000000000000..eca9f3dcc256
>> --- /dev/null
>> +++ b/drivers/clk/meson/a5-peripherals.c
>> @@ -0,0 +1,883 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Amlogic A5 Peripherals Clock Controller Driver
>> + *
>> + * Copyright (c) 2024-2025 Amlogic, inc.
>> + * Author: Chuan Liu <chuan.liu at amlogic.com>
>> + */
>> +
>> +#include <linux/clk-provider.h>
>> +#include <linux/platform_device.h>
>> +#include "clk-regmap.h"
>> +#include "clk-dualdiv.h"
>> +#include "meson-clkc-utils.h"
>> +#include <dt-bindings/clock/amlogic,a5-peripherals-clkc.h>
>> +
>> +#define RTC_BY_OSCIN_CTRL0           0x8
>> +#define RTC_BY_OSCIN_CTRL1           0xc
>> +#define RTC_CTRL                     0x10
>> +#define SYS_CLK_EN0_REG0             0x44
>> +#define SYS_CLK_EN0_REG1             0x48
>> +#define DSPA_CLK_CTRL0                       0x9c
>> +#define CLK12_24_CTRL                        0xa8
>> +#define AXI_CLK_EN0                  0xac
>> +#define TS_CLK_CTRL                  0x158
>> +#define ETH_CLK_CTRL                 0x164
>> +#define NAND_CLK_CTRL                        0x168
>> +#define SD_EMMC_CLK_CTRL             0x16c
>> +#define SPICC_CLK_CTRL                       0x174
>> +#define GEN_CLK_CTRL                 0x178
>> +#define SAR_CLK_CTRL0                        0x17c
>> +#define PWM_CLK_AB_CTRL                      0x180
>> +#define PWM_CLK_CD_CTRL                      0x184
>> +#define PWM_CLK_EF_CTRL                      0x188
>> +#define PWM_CLK_GH_CTRL                      0x18c
>> +#define NNA_CLK_CNTL                 0x220
>> +
>> +static struct clk_regmap a5_rtc_dualdiv_clkin = {
>> +     .data = &(struct clk_regmap_gate_data) {
>> +             .offset = RTC_BY_OSCIN_CTRL0,
>> +             .bit_idx = 31,
>> +     },
>> +     .hw.init = &(struct clk_init_data) {
>> +             .name = "rtc_dualdiv_clkin",
>> +             .ops = &clk_regmap_gate_ops,
>> +             .parent_data = &(const struct clk_parent_data) {
>> +                     .fw_name = "oscin",
>> +             },
>> +             .num_parents = 1,
>> +     },
>> +};
>> +
>> +static const struct meson_clk_dualdiv_param a5_rtc_dualdiv_table[] = {
>> +     { 733, 732, 8, 11, 1 },
>> +     { /* sentinel */ }
>> +};
>> +
>> +static struct clk_regmap a5_rtc_dualdiv = {
>> +     .data = &(struct meson_clk_dualdiv_data) {
>> +             .n1 = {
>> +                     .reg_off = RTC_BY_OSCIN_CTRL0,
>> +                     .shift   = 0,
>> +                     .width   = 12,
>> +             },
>> +             .n2 = {
>> +                     .reg_off = RTC_BY_OSCIN_CTRL0,
>> +                     .shift   = 12,
>> +                     .width   = 12,
>> +             },
>> +             .m1 = {
>> +                     .reg_off = RTC_BY_OSCIN_CTRL1,
>> +                     .shift   = 0,
>> +                     .width   = 12,
>> +             },
>> +             .m2 = {
>> +                     .reg_off = RTC_BY_OSCIN_CTRL1,
>> +                     .shift   = 12,
>> +                     .width   = 12,
>> +             },
>> +             .dual = {
>> +                     .reg_off = RTC_BY_OSCIN_CTRL0,
>> +                     .shift   = 28,
>> +                     .width   = 1,
>> +             },
>> +             .table = a5_rtc_dualdiv_table,
>> +     },
>> +     .hw.init = &(struct clk_init_data) {
>> +             .name = "rtc_dualdiv",
>> +             .ops = &meson_clk_dualdiv_ops,
>> +             .parent_hws = (const struct clk_hw *[]) {
>> +                     &a5_rtc_dualdiv_clkin.hw
>> +             },
>> +             .num_parents = 1,
>> +     },
>> +};
>> +
>> +static const struct clk_parent_data a5_rtc_dualdiv_parent_data[] = {
>> +     { .hw = &a5_rtc_dualdiv.hw },
>> +     { .hw = &a5_rtc_dualdiv_clkin.hw }
>> +};
>> +
>> +static struct clk_regmap a5_rtc_dualdiv_sel = {
>> +     .data = &(struct clk_regmap_mux_data) {
>> +             .offset = RTC_BY_OSCIN_CTRL1,
>> +             .mask = 0x1,
>> +             .shift = 24,
>> +     },
>> +     .hw.init = &(struct clk_init_data) {
>> +             .name = "rtc_dualdiv_sel",
>> +             .ops = &clk_regmap_mux_ops,
>> +             .parent_data = a5_rtc_dualdiv_parent_data,
>> +             .num_parents = ARRAY_SIZE(a5_rtc_dualdiv_parent_data),
>> +             .flags = CLK_SET_RATE_PARENT,
>> +     },
>> +};
>> +
>> +static struct clk_regmap a5_rtc_dualdiv_clkout = {
>> +     .data = &(struct clk_regmap_gate_data) {
>> +             .offset = RTC_BY_OSCIN_CTRL0,
>> +             .bit_idx = 30,
>> +     },
>> +     .hw.init = &(struct clk_init_data) {
>> +             .name = "rtc_dualdiv_clkout",
>> +             .ops = &clk_regmap_gate_ops,
>> +             .parent_hws = (const struct clk_hw *[]) {
>> +                     &a5_rtc_dualdiv_sel.hw
>> +             },
>> +             .num_parents = 1,
>> +             .flags = CLK_SET_RATE_PARENT,
>> +     },
>> +};
>> +
>> +static const struct clk_parent_data a5_rtc_clk_parent_data[] = {
>> +     { .fw_name = "oscin" },
>> +     { .hw = &a5_rtc_dualdiv_clkout.hw },
>> +     { .fw_name = "pad_osc" }
>> +};
>> +
>> +static struct clk_regmap a5_rtc_clk = {
>> +     .data = &(struct clk_regmap_mux_data) {
>> +             .offset = RTC_CTRL,
>> +             .mask = 0x3,
>> +             .shift = 0,
>> +     },
>> +     .hw.init = &(struct clk_init_data) {
>> +             .name = "rtc_clk",
>> +             .ops = &clk_regmap_mux_ops,
>> +             .parent_data = a5_rtc_clk_parent_data,
>> +             .num_parents = ARRAY_SIZE(a5_rtc_clk_parent_data),
>> +             .flags = CLK_SET_RATE_PARENT,
> 
> NO_REPARENT maybe ?
> 

OK, I noticed your comment on T7, and it is reasonable. I will add it.

>> +     },
>> +};
>> +
>> +#define A5_PCLK(_name, _reg, _bit, _pdata, _flags)                   \
>> +struct clk_regmap a5_##_name = {                                     \
>> +     .data = &(struct clk_regmap_gate_data) {                        \
>> +             .offset = (_reg),                                       \
>> +             .bit_idx = (_bit),                                      \
>> +     },                                                              \
>> +     .hw.init = &(struct clk_init_data) {                            \
>> +             .name = #_name,                                         \
>> +             .ops = &clk_regmap_gate_ops,                            \
>> +             .parent_data = (_pdata),                                \
>> +             .num_parents = 1,                                       \
>> +             .flags = (_flags),                                      \
>> +     },                                                              \
>> +}
> 
> You've complained about the time it took to do the clean-up of amlogic
> clocks, and yet, look what we have here ...
> 

Yes, the previous clean-up was meaningful, as it helped simplify a large 
amount of duplicated code.

Here, I redefined a macro to avoid adding a SoC prefix to the "clock 
name", which does not seem necessary.

>> +
>> +static const struct clk_parent_data a5_sys_pclk_parents = { .fw_name = "sysclk" };
>> +
>> +#define A5_SYS_PCLK(_name, _reg, _bit, _flags) \
>> +     A5_PCLK(_name, _reg, _bit, &a5_sys_pclk_parents, _flags)
>> +
>> +static A5_SYS_PCLK(sys_reset_ctrl,   SYS_CLK_EN0_REG0, 1, 0);
>> +static A5_SYS_PCLK(sys_pwr_ctrl,     SYS_CLK_EN0_REG0, 3, 0);
>> +static A5_SYS_PCLK(sys_pad_ctrl,     SYS_CLK_EN0_REG0, 4, 0);
>> +static A5_SYS_PCLK(sys_ctrl,         SYS_CLK_EN0_REG0, 5, 0);
>> +static A5_SYS_PCLK(sys_ts_pll,               SYS_CLK_EN0_REG0, 6, 0);
>> +
>> +/*
>> + * NOTE: sys_dev_arb provides the clock to the ETH and SPICC arbiters that
>> + * access the AXI bus.
>> + */
>> +static A5_SYS_PCLK(sys_dev_arb,              SYS_CLK_EN0_REG0, 7, 0);
>> +static A5_SYS_PCLK(sys_mailbox,              SYS_CLK_EN0_REG0, 10, 0);
>> +static A5_SYS_PCLK(sys_jtag_ctrl,    SYS_CLK_EN0_REG0, 12, 0);
>> +static A5_SYS_PCLK(sys_ir_ctrl,              SYS_CLK_EN0_REG0, 13, 0);
>> +static A5_SYS_PCLK(sys_msr_clk,              SYS_CLK_EN0_REG0, 15, 0);
>> +static A5_SYS_PCLK(sys_rom,          SYS_CLK_EN0_REG0, 16, 0);
>> +static A5_SYS_PCLK(sys_cpu_apb,              SYS_CLK_EN0_REG0, 18, 0);
>> +static A5_SYS_PCLK(sys_rsa,          SYS_CLK_EN0_REG0, 19, 0);
>> +static A5_SYS_PCLK(sys_saradc,               SYS_CLK_EN0_REG0, 20, 0);
>> +static A5_SYS_PCLK(sys_startup,              SYS_CLK_EN0_REG0, 21, 0);
>> +static A5_SYS_PCLK(sys_secure,               SYS_CLK_EN0_REG0, 22, 0);
>> +static A5_SYS_PCLK(sys_spifc,                SYS_CLK_EN0_REG0, 23, 0);
>> +static A5_SYS_PCLK(sys_dspa,         SYS_CLK_EN0_REG0, 24, 0);
>> +static A5_SYS_PCLK(sys_nna,          SYS_CLK_EN0_REG0, 25, 0);
>> +static A5_SYS_PCLK(sys_eth_mac,              SYS_CLK_EN0_REG0, 26, 0);
>> +static A5_SYS_PCLK(sys_rama,         SYS_CLK_EN0_REG0, 28, 0);
>> +static A5_SYS_PCLK(sys_ramb,         SYS_CLK_EN0_REG0, 30, 0);
>> +static A5_SYS_PCLK(sys_audio_top,    SYS_CLK_EN0_REG1, 0, 0);
>> +static A5_SYS_PCLK(sys_audio_vad,    SYS_CLK_EN0_REG1, 1, 0);
>> +static A5_SYS_PCLK(sys_usb,          SYS_CLK_EN0_REG1, 2, 0);
>> +static A5_SYS_PCLK(sys_sd_emmc_a,    SYS_CLK_EN0_REG1, 3, 0);
>> +static A5_SYS_PCLK(sys_sd_emmc_c,    SYS_CLK_EN0_REG1, 4, 0);
>> +static A5_SYS_PCLK(sys_pwm_ab,               SYS_CLK_EN0_REG1, 5, 0);
>> +static A5_SYS_PCLK(sys_pwm_cd,               SYS_CLK_EN0_REG1, 6, 0);
>> +static A5_SYS_PCLK(sys_pwm_ef,               SYS_CLK_EN0_REG1, 7, 0);
>> +static A5_SYS_PCLK(sys_pwm_gh,               SYS_CLK_EN0_REG1, 8, 0);
>> +static A5_SYS_PCLK(sys_spicc_1,              SYS_CLK_EN0_REG1, 9, 0);
>> +static A5_SYS_PCLK(sys_spicc_0,              SYS_CLK_EN0_REG1, 10, 0);
>> +static A5_SYS_PCLK(sys_uart_a,               SYS_CLK_EN0_REG1, 11, 0);
>> +static A5_SYS_PCLK(sys_uart_b,               SYS_CLK_EN0_REG1, 12, 0);
>> +static A5_SYS_PCLK(sys_uart_c,               SYS_CLK_EN0_REG1, 13, 0);
>> +static A5_SYS_PCLK(sys_uart_d,               SYS_CLK_EN0_REG1, 14, 0);
>> +static A5_SYS_PCLK(sys_uart_e,               SYS_CLK_EN0_REG1, 15, 0);
>> +static A5_SYS_PCLK(sys_i2c_m_a,              SYS_CLK_EN0_REG1, 16, 0);
>> +static A5_SYS_PCLK(sys_i2c_m_b,              SYS_CLK_EN0_REG1, 17, 0);
>> +static A5_SYS_PCLK(sys_i2c_m_c,              SYS_CLK_EN0_REG1, 18, 0);
>> +static A5_SYS_PCLK(sys_i2c_m_d,              SYS_CLK_EN0_REG1, 19, 0);
>> +static A5_SYS_PCLK(sys_rtc,          SYS_CLK_EN0_REG1, 21, 0);
>> +
>> +static const struct clk_parent_data a5_axi_clk_parents = { .fw_name = "axiclk" };
>> +
>> +#define A5_AXI_CLK(_name, _reg, _bit, _flags) \
>> +     A5_PCLK(_name, _reg, _bit, &a5_axi_clk_parents, _flags)
>> +
>> +static A5_AXI_CLK(axi_audio_vad,     AXI_CLK_EN0, 0, 0);
>> +static A5_AXI_CLK(axi_audio_top,     AXI_CLK_EN0, 1, 0);
>> +static A5_AXI_CLK(axi_ramb,          AXI_CLK_EN0, 5, 0);
>> +static A5_AXI_CLK(axi_rama,          AXI_CLK_EN0, 6, 0);
>> +static A5_AXI_CLK(axi_nna,           AXI_CLK_EN0, 12, 0);
>> +
>> +/*
>> + * NOTE: axi_dev1_dmc provides the clock for the peripherals(EMMC, SDIO,
>> + * sec_top, USB, Audio) to access the AXI bus of the DDR.
>> + */
>> +static A5_AXI_CLK(axi_dev1_dmc,      AXI_CLK_EN0, 13, 0);
>> +
>> +/*
>> + * NOTE: axi_dev0_dmc provides the clock for the peripherals(ETH and SPICC)
>> + * to access the AXI bus of the DDR.
>> + */
>> +static A5_AXI_CLK(axi_dev0_dmc,      AXI_CLK_EN0, 14, 0);
>> +static A5_AXI_CLK(axi_dsp_dmc,               AXI_CLK_EN0, 15, 0);
>> +
>> +static struct clk_regmap a5_clk_12_24m_in = {
>> +     .data = &(struct clk_regmap_gate_data) {
>> +             .offset = CLK12_24_CTRL,
>> +             .bit_idx = 11,
>> +     },
>> +     .hw.init = &(struct clk_init_data) {
>> +             .name = "clk_12_24m_in",
>> +             .ops = &clk_regmap_gate_ops,
>> +             .parent_data = &(const struct clk_parent_data) {
>> +                     .fw_name = "xtal",
>> +             },
>> +             .num_parents = 1,
>> +     },
>> +};
>> +
>> +static struct clk_regmap a5_clk_12_24m = {
>> +     .data = &(struct clk_regmap_div_data) {
>> +             .offset = CLK12_24_CTRL,
>> +             .shift = 10,
>> +             .width = 1,
>> +     },
>> +     .hw.init = &(struct clk_init_data) {
>> +             .name = "clk_12_24m",
>> +             .ops = &clk_regmap_divider_ops,
>> +             .parent_hws = (const struct clk_hw *[]) {
>> +                     &a5_clk_12_24m_in.hw
>> +             },
>> +             .num_parents = 1,
>> +     },
>> +};
>> +
>> +static struct clk_regmap a5_fclk_25m_div = {
>> +     .data = &(struct clk_regmap_div_data) {
>> +             .offset = CLK12_24_CTRL,
>> +             .shift = 0,
>> +             .width = 8,
>> +     },
>> +     .hw.init = &(struct clk_init_data) {
>> +             .name = "fclk_25m_div",
>> +             .ops = &clk_regmap_divider_ops,
>> +             .parent_data = &(const struct clk_parent_data) {
>> +                     .fw_name = "fix",
>> +             },
>> +             .num_parents = 1,
>> +     },
>> +};
>> +
>> +static struct clk_regmap a5_fclk_25m = {
>> +     .data = &(struct clk_regmap_gate_data) {
>> +             .offset = CLK12_24_CTRL,
>> +             .bit_idx = 12,
>> +     },
>> +     .hw.init = &(struct clk_init_data) {
>> +             .name = "fclk_25m",
>> +             .ops = &clk_regmap_gate_ops,
>> +             .parent_hws = (const struct clk_hw *[]) {
>> +                     &a5_fclk_25m_div.hw
>> +             },
>> +             .num_parents = 1,
>> +             .flags = CLK_SET_RATE_PARENT,
>> +     },
>> +};
>> +
>> +/*
>> + * Channel 4 5 8 9 10 11 13 14 15 16 18 are not connected.
>> + *
>> + * gp1 is designed for DSU (DynamIQ Shared Unit) alone. It cannot be changed
>> + * arbitrarily. gp1 is read-only in the kernel and is only open for debug
>> + * purposes.
>> + */
>> +static u32 a5_gen_parent_table[] = { 0, 1, 2, 3, 6, 7, 12, 17, 19, 20, 21, 22,
>> +                                 23, 24, 25, 26, 27, 28};
>> +
>> +static const struct clk_parent_data a5_gen_parent_data[] = {
>> +     { .fw_name = "oscin" },
>> +     { .hw = &a5_rtc_clk.hw },
>> +     { .fw_name = "sysplldiv16" },
>> +     { .fw_name = "ddr" },
>> +     { .fw_name = "gp1" },
>> +     { .fw_name = "hifi" },
>> +     { .fw_name = "clkmsr" },
>> +     { .fw_name = "cpudiv16" },
>> +     { .fw_name = "fdiv2" },
>> +     { .fw_name = "fdiv2p5" },
>> +     { .fw_name = "fdiv3" },
>> +     { .fw_name = "fdiv4" },
>> +     { .fw_name = "fdiv5" },
>> +     { .fw_name = "fdiv7" },
>> +     { .fw_name = "mpll0" },
>> +     { .fw_name = "mpll1" },
>> +     { .fw_name = "mpll2" },
>> +     { .fw_name = "mpll3" }
>> +};
>> +
>> +static struct clk_regmap a5_gen_sel = {
>> +     .data = &(struct clk_regmap_mux_data) {
>> +             .offset = GEN_CLK_CTRL,
>> +             .mask = 0x1f,
>> +             .shift = 12,
>> +             .table = a5_gen_parent_table,
>> +     },
>> +     .hw.init = &(struct clk_init_data) {
>> +             .name = "gen_sel",
>> +             .ops = &clk_regmap_mux_ops,
>> +             .parent_data = a5_gen_parent_data,
>> +             .num_parents = ARRAY_SIZE(a5_gen_parent_data),
>> +     },
>> +};
>> +
>> +static struct clk_regmap a5_gen_div = {
>> +     .data = &(struct clk_regmap_div_data) {
>> +             .offset = GEN_CLK_CTRL,
>> +             .shift = 0,
>> +             .width = 11,
>> +     },
>> +     .hw.init = &(struct clk_init_data) {
>> +             .name = "gen_div",
>> +             .ops = &clk_regmap_divider_ops,
>> +             .parent_hws = (const struct clk_hw *[]) {
>> +                     &a5_gen_sel.hw
>> +             },
>> +             .num_parents = 1,
>> +             .flags = CLK_SET_RATE_PARENT,
>> +     },
>> +};
>> +
>> +static struct clk_regmap a5_gen = {
>> +     .data = &(struct clk_regmap_gate_data) {
>> +             .offset = GEN_CLK_CTRL,
>> +             .bit_idx = 11,
>> +     },
>> +     .hw.init = &(struct clk_init_data) {
>> +             .name = "gen",
>> +             .ops = &clk_regmap_gate_ops,
>> +             .parent_hws = (const struct clk_hw *[]) {
>> +                     &a5_gen_div.hw
>> +             },
>> +             .num_parents = 1,
>> +             .flags = CLK_SET_RATE_PARENT,
>> +     },
>> +};
>> +
>> +#define A5_COMP_SEL(_name, _reg, _shift, _mask, _pdata) \
>> +     MESON_COMP_SEL(a5_, _name, _reg, _shift, _mask, _pdata, NULL, 0, 0)
>> +
>> +#define A5_COMP_DIV(_name, _reg, _shift, _width) \
>> +     MESON_COMP_DIV(a5_, _name, _reg, _shift, _width, 0, CLK_SET_RATE_PARENT)
>> +
>> +#define A5_COMP_GATE(_name, _reg, _bit) \
>> +     MESON_COMP_GATE(a5_, _name, _reg, _bit, CLK_SET_RATE_PARENT)
>> +
>> +static const struct clk_parent_data a5_saradc_parent_data[] = {
>> +     { .fw_name = "oscin" },
>> +     { .fw_name = "sysclk" }
>> +};
>> +
>> +static A5_COMP_SEL(saradc, SAR_CLK_CTRL0, 9, 0x3, a5_saradc_parent_data);
>> +static A5_COMP_DIV(saradc, SAR_CLK_CTRL0, 0, 8);
>> +static A5_COMP_GATE(saradc, SAR_CLK_CTRL0, 8);
>> +
>> +static const struct clk_parent_data a5_pwm_parent_data[] = {
>> +     { .fw_name = "oscin" },
>> +     { .hw = &a5_rtc_clk.hw },
>> +     { .fw_name = "fdiv4" },
>> +     { .fw_name = "fdiv3" }
>> +};
>> +
>> +static A5_COMP_SEL(pwm_a, PWM_CLK_AB_CTRL, 9, 0x3, a5_pwm_parent_data);
>> +static A5_COMP_DIV(pwm_a, PWM_CLK_AB_CTRL, 0, 8);
>> +static A5_COMP_GATE(pwm_a, PWM_CLK_AB_CTRL, 8);
>> +
>> +static A5_COMP_SEL(pwm_b, PWM_CLK_AB_CTRL, 25, 0x3, a5_pwm_parent_data);
>> +static A5_COMP_DIV(pwm_b, PWM_CLK_AB_CTRL, 16, 8);
>> +static A5_COMP_GATE(pwm_b, PWM_CLK_AB_CTRL, 24);
>> +
>> +static A5_COMP_SEL(pwm_c, PWM_CLK_CD_CTRL, 9, 0x3, a5_pwm_parent_data);
>> +static A5_COMP_DIV(pwm_c, PWM_CLK_CD_CTRL, 0, 8);
>> +static A5_COMP_GATE(pwm_c, PWM_CLK_CD_CTRL, 8);
>> +
>> +static A5_COMP_SEL(pwm_d, PWM_CLK_CD_CTRL, 25, 0x3, a5_pwm_parent_data);
>> +static A5_COMP_DIV(pwm_d, PWM_CLK_CD_CTRL, 16, 8);
>> +static A5_COMP_GATE(pwm_d, PWM_CLK_CD_CTRL, 24);
>> +
>> +static A5_COMP_SEL(pwm_e, PWM_CLK_EF_CTRL, 9, 0x3, a5_pwm_parent_data);
>> +static A5_COMP_DIV(pwm_e, PWM_CLK_EF_CTRL, 0, 8);
>> +static A5_COMP_GATE(pwm_e, PWM_CLK_EF_CTRL, 8);
>> +
>> +static A5_COMP_SEL(pwm_f, PWM_CLK_EF_CTRL, 25, 0x3, a5_pwm_parent_data);
>> +static A5_COMP_DIV(pwm_f, PWM_CLK_EF_CTRL, 16, 8);
>> +static A5_COMP_GATE(pwm_f, PWM_CLK_EF_CTRL, 24);
>> +
>> +static A5_COMP_SEL(pwm_g, PWM_CLK_GH_CTRL, 9, 0x3, a5_pwm_parent_data);
>> +static A5_COMP_DIV(pwm_g, PWM_CLK_GH_CTRL, 0, 8);
>> +static A5_COMP_GATE(pwm_g, PWM_CLK_GH_CTRL, 8);
>> +
>> +static A5_COMP_SEL(pwm_h, PWM_CLK_GH_CTRL, 25, 0x3, a5_pwm_parent_data);
>> +static A5_COMP_DIV(pwm_h, PWM_CLK_GH_CTRL, 16, 8);
>> +static A5_COMP_GATE(pwm_h, PWM_CLK_GH_CTRL, 24);
>> +
>> +/*
>> + * NOTE: Channel 7 is gp1, because gp1 is designed for DSU, so spicc does not
>> + * support this source in the driver.
>> + */
>> +static const struct clk_parent_data a5_spicc_parent_data[] = {
>> +     { .fw_name = "oscin" },
>> +     { .fw_name = "sysclk" },
>> +     { .fw_name = "fdiv4" },
>> +     { .fw_name = "fdiv3" },
>> +     { .fw_name = "fdiv2" },
>> +     { .fw_name = "fdiv5" },
>> +     { .fw_name = "fdiv7" }
>> +};
>> +
>> +static A5_COMP_SEL(spicc_0, SPICC_CLK_CTRL, 7, 0x7, a5_spicc_parent_data);
>> +static A5_COMP_DIV(spicc_0, SPICC_CLK_CTRL, 0, 6);
>> +static A5_COMP_GATE(spicc_0, SPICC_CLK_CTRL, 6);
>> +
>> +static A5_COMP_SEL(spicc_1, SPICC_CLK_CTRL, 23, 0x7, a5_spicc_parent_data);
>> +static A5_COMP_DIV(spicc_1, SPICC_CLK_CTRL, 16, 6);
>> +static A5_COMP_GATE(spicc_1, SPICC_CLK_CTRL, 22);
>> +
>> +static const struct clk_parent_data a5_sd_emmc_parent_data[] = {
>> +     { .fw_name = "oscin" },
>> +     { .fw_name = "fdiv2" },
>> +     { .fw_name = "fdiv3" },
>> +     { .fw_name = "hifi" },
>> +     { .fw_name = "fdiv2p5" },
>> +     { .fw_name = "mpll2" },
>> +     { .fw_name = "mpll3" },
>> +     { .fw_name = "gp0" }
>> +};
>> +
>> +static A5_COMP_SEL(sd_emmc_a, SD_EMMC_CLK_CTRL, 9, 0x7, a5_sd_emmc_parent_data);
>> +static A5_COMP_DIV(sd_emmc_a, SD_EMMC_CLK_CTRL, 0, 7);
>> +static A5_COMP_GATE(sd_emmc_a, SD_EMMC_CLK_CTRL, 7);
>> +
>> +static A5_COMP_SEL(sd_emmc_c, NAND_CLK_CTRL, 9, 0x7, a5_sd_emmc_parent_data);
>> +static A5_COMP_DIV(sd_emmc_c, NAND_CLK_CTRL, 0, 7);
>> +static A5_COMP_GATE(sd_emmc_c, NAND_CLK_CTRL, 7);
>> +
>> +static struct clk_regmap a5_ts_div = {
>> +     .data = &(struct clk_regmap_div_data) {
>> +             .offset = TS_CLK_CTRL,
>> +             .shift = 0,
>> +             .width = 8,
>> +     },
>> +     .hw.init = &(struct clk_init_data) {
>> +             .name = "ts_div",
>> +             .ops = &clk_regmap_divider_ops,
>> +             .parent_data = &(const struct clk_parent_data) {
>> +                     .fw_name = "oscin",
>> +             },
>> +             .num_parents = 1,
>> +     },
>> +};
>> +
>> +static struct clk_regmap a5_ts = {
>> +     .data = &(struct clk_regmap_gate_data) {
>> +             .offset = TS_CLK_CTRL,
>> +             .bit_idx = 8,
>> +     },
>> +     .hw.init = &(struct clk_init_data) {
>> +             .name = "ts",
>> +             .ops = &clk_regmap_gate_ops,
>> +             .parent_hws = (const struct clk_hw *[]) {
>> +                     &a5_ts_div.hw
>> +             },
>> +             .num_parents = 1,
>> +             .flags = CLK_SET_RATE_PARENT,
>> +     },
>> +};
>> +
>> +static struct clk_fixed_factor a5_eth_125m_div = {
>> +     .mult = 1,
>> +     .div = 8,
>> +     .hw.init = &(struct clk_init_data) {
>> +             .name = "eth_125m_div",
>> +             .ops = &clk_fixed_factor_ops,
>> +             .parent_data = &(const struct clk_parent_data) {
>> +                     .fw_name = "fdiv2",
>> +             },
>> +             .num_parents = 1,
>> +     },
>> +};
>> +
>> +static struct clk_regmap a5_eth_125m = {
>> +     .data = &(struct clk_regmap_gate_data) {
>> +             .offset = ETH_CLK_CTRL,
>> +             .bit_idx = 7,
>> +     },
>> +     .hw.init = &(struct clk_init_data) {
>> +             .name = "eth_125m",
>> +             .ops = &clk_regmap_gate_ops,
>> +             .parent_hws = (const struct clk_hw *[]) {
>> +                     &a5_eth_125m_div.hw
>> +             },
>> +             .num_parents = 1,
>> +     },
>> +};
>> +
>> +static struct clk_regmap a5_eth_rmii_div = {
>> +     .data = &(struct clk_regmap_div_data) {
>> +             .offset = ETH_CLK_CTRL,
>> +             .shift = 0,
>> +             .width = 7,
>> +     },
>> +     .hw.init = &(struct clk_init_data) {
>> +             .name = "eth_rmii_div",
>> +             .ops = &clk_regmap_divider_ops,
>> +             .parent_data = &(const struct clk_parent_data) {
>> +                     .fw_name = "fdiv2",
>> +             },
>> +             .num_parents = 1,
>> +     },
>> +};
>> +
>> +static struct clk_regmap a5_eth_rmii = {
>> +     .data = &(struct clk_regmap_gate_data) {
>> +             .offset = ETH_CLK_CTRL,
>> +             .bit_idx = 8,
>> +     },
>> +     .hw.init = &(struct clk_init_data) {
>> +             .name = "eth_rmii",
>> +             .ops = &clk_regmap_gate_ops,
>> +             .parent_hws = (const struct clk_hw *[]) {
>> +                     &a5_eth_rmii_div.hw
>> +             },
>> +             .num_parents = 1,
>> +             .flags = CLK_SET_RATE_PARENT,
>> +     },
>> +};
>> +
>> +/* Channel 6 is gp1. */
>> +static u32 a5_dspa_parent_table[] = { 0, 1, 2, 3, 4, 5, 7};
> 
> Considering there is no rate propagation from mux below, is it really a
> problem to have gp1 in here ?
> 

gp1 is used to provide the clock for the DSU, and the dsu_clk changes 
dynamically along with cpu_clk (cpufreq support is required). Although 
we do not have good cpufreq support upstream at the moment, it is very 
likely (and almost inevitable) that it will be supported in the future.

If the clocks of other modules are switched to gp1, and cpufreq later 
adjusts the gp1 frequency again, those modules that depend on gp1 may 
behave abnormally. Therefore, gp1 may not be suitable to be exposed to 
the clock tree for general peripherals.

>> +
>> +static const struct clk_parent_data a5_dspa_parent_data[] = {
>> +     { .fw_name = "oscin" },
>> +     { .fw_name = "fdiv2p5" },
>> +     { .fw_name = "fdiv3" },
>> +     { .fw_name = "rtc" },  /* rtc_pll */
>> +     { .fw_name = "hifi" },
>> +     { .fw_name = "fdiv4" },
>> +     { .hw = &a5_rtc_clk.hw }
>> +};
>> +
>> +static struct clk_regmap a5_dspa_0_sel = {
>> +     .data = &(struct clk_regmap_mux_data) {
>> +             .offset = DSPA_CLK_CTRL0,
>> +             .mask = 0x7,
>> +             .shift = 10,
>> +             .table = a5_dspa_parent_table,
>> +     },
>> +     .hw.init = &(struct clk_init_data) {
>> +             .name = "dspa_0_sel",
>> +             .ops = &clk_regmap_mux_ops,
>> +             .parent_data = a5_dspa_parent_data,
>> +             .num_parents = ARRAY_SIZE(a5_dspa_parent_data),
>> +     },
>> +};
>> +
>> +static struct clk_regmap a5_dspa_0_div = {
>> +     .data = &(struct clk_regmap_div_data) {
>> +             .offset = DSPA_CLK_CTRL0,
>> +             .shift = 0,
>> +             .width = 10,
>> +     },
>> +     .hw.init = &(struct clk_init_data) {
>> +             .name = "dspa_0_div",
>> +             .ops = &clk_regmap_divider_ops,
>> +             .parent_hws = (const struct clk_hw *[]) {
>> +                     &a5_dspa_0_sel.hw
>> +             },
>> +             .num_parents = 1,
>> +             .flags = CLK_SET_RATE_PARENT,
>> +     },
>> +};
> 
> Same comment as the t7 regarding naming and macro usage for the glitch
> free composite clocks. Please adjust accordingly.
> 

Ok, got it.

>> +
>> +static struct clk_regmap a5_dspa_0 = {
>> +     .data = &(struct clk_regmap_gate_data) {
>> +             .offset = DSPA_CLK_CTRL0,
>> +             .bit_idx = 13,
>> +     },
>> +     .hw.init = &(struct clk_init_data) {
>> +             .name = "dspa_0",
>> +             .ops = &clk_regmap_gate_ops,
>> +             .parent_hws = (const struct clk_hw *[]) {
>> +                     &a5_dspa_0_div.hw
>> +             },
>> +             .num_parents = 1,
>> +             .flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT,
>> +     },
>> +};
>> +
>> +static struct clk_regmap a5_dspa_1_sel = {
>> +     .data = &(struct clk_regmap_mux_data) {
>> +             .offset = DSPA_CLK_CTRL0,
>> +             .mask = 0x7,
>> +             .shift = 26,
>> +             .table = a5_dspa_parent_table,
>> +     },
>> +     .hw.init = &(struct clk_init_data) {
>> +             .name = "dspa_1_sel",
>> +             .ops = &clk_regmap_mux_ops,
>> +             .parent_data = a5_dspa_parent_data,
>> +             .num_parents = ARRAY_SIZE(a5_dspa_parent_data),
>> +     },
>> +};
>> +
>> +static struct clk_regmap a5_dspa_1_div = {
>> +     .data = &(struct clk_regmap_div_data) {
>> +             .offset = DSPA_CLK_CTRL0,
>> +             .shift = 16,
>> +             .width = 10,
>> +     },
>> +     .hw.init = &(struct clk_init_data) {
>> +             .name = "dspa_1_div",
>> +             .ops = &clk_regmap_divider_ops,
>> +             .parent_hws = (const struct clk_hw *[]) {
>> +                     &a5_dspa_1_sel.hw
>> +             },
>> +             .num_parents = 1,
>> +             .flags = CLK_SET_RATE_PARENT,
>> +     },
>> +};
>> +
>> +static struct clk_regmap a5_dspa_1 = {
>> +     .data = &(struct clk_regmap_gate_data) {
>> +             .offset = DSPA_CLK_CTRL0,
>> +             .bit_idx = 29,
>> +     },
>> +     .hw.init = &(struct clk_init_data) {
>> +             .name = "dspa_1",
>> +             .ops = &clk_regmap_gate_ops,
>> +             .parent_hws = (const struct clk_hw *[]) {
>> +                     &a5_dspa_1_div.hw
>> +             },
>> +             .num_parents = 1,
>> +             .flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT,
>> +     },
>> +};
>> +
>> +static struct clk_regmap a5_dspa = {
>> +     .data = &(struct clk_regmap_mux_data){
>> +             .offset = DSPA_CLK_CTRL0,
>> +             .mask = 0x1,
>> +             .shift = 15,
>> +     },
>> +     .hw.init = &(struct clk_init_data) {
>> +             .name = "dspa",
>> +             .ops = &clk_regmap_mux_ops,
>> +             .parent_hws = (const struct clk_hw *[]) {
>> +                     &a5_dspa_0.hw,
>> +                     &a5_dspa_1.hw
>> +             },
>> +             .num_parents = 2,
>> +             .flags = CLK_SET_RATE_PARENT,
>> +     },
>> +};
>> +
>> +#define A5_COMP_SEL_WITH_TAB(_name, _reg, _shift, _mask, _pdata, _table) \
> 
> No, adjust your main macro.
> 

Do you mean to unify this into a single macro here? Like this:

#define A5_COMP_SEL(_name, _reg, _shift, _mask, _pdata, _table) \
    MESON_COMP_SEL(a5_, _name, _reg, _shift, _mask, _pdata, _table, 0, 0)

>> +     MESON_COMP_SEL(a5_, _name, _reg, _shift, _mask, _pdata, _table, 0, 0)
>> +
>> +/* Channel 6 is gp1. */
>> +static u32 a5_nna_parent_table[] = { 0, 1, 2, 3, 4, 5, 7};
>> +
>> +static const struct clk_parent_data a5_nna_parent_data[] = {
>> +     { .fw_name = "oscin" },
>> +     { .fw_name = "fdiv2p5" },
>> +     { .fw_name = "fdiv4" },
>> +     { .fw_name = "fdiv3" },
>> +     { .fw_name = "fdiv5" },
>> +     { .fw_name = "fdiv2" },
>> +     { .fw_name = "hifi" }
>> +};
>> +
>> +static A5_COMP_SEL_WITH_TAB(nna_core, NNA_CLK_CNTL, 9, 0x7,
>> +                         a5_nna_parent_data, a5_nna_parent_table);
>> +static A5_COMP_DIV(nna_core, NNA_CLK_CNTL, 0, 7);
>> +static A5_COMP_GATE(nna_core, NNA_CLK_CNTL, 8);
>> +
>> +static A5_COMP_SEL_WITH_TAB(nna_axi, NNA_CLK_CNTL, 25, 0x7,
>> +                         a5_nna_parent_data, a5_nna_parent_table);
>> +static A5_COMP_DIV(nna_axi, NNA_CLK_CNTL, 16, 7);
>> +static A5_COMP_GATE(nna_axi, NNA_CLK_CNTL, 24);
>> +
>> +static struct clk_hw *a5_peripherals_hw_clks[] = {
>> +     [CLKID_RTC_DUALDIV_CLKIN]       = &a5_rtc_dualdiv_clkin.hw,
>> +     [CLKID_RTC_DUALDIV]             = &a5_rtc_dualdiv.hw,
>> +     [CLKID_RTC_DUALDIV_SEL]         = &a5_rtc_dualdiv_sel.hw,
>> +     [CLKID_RTC_DUALDIV_CLKOUT]      = &a5_rtc_dualdiv_clkout.hw,
>> +     [CLKID_RTC_CLK]                 = &a5_rtc_clk.hw,
>> +     [CLKID_SYS_RESET_CTRL]          = &a5_sys_reset_ctrl.hw,
>> +     [CLKID_SYS_PWR_CTRL]            = &a5_sys_pwr_ctrl.hw,
>> +     [CLKID_SYS_PAD_CTRL]            = &a5_sys_pad_ctrl.hw,
>> +     [CLKID_SYS_CTRL]                = &a5_sys_ctrl.hw,
>> +     [CLKID_SYS_TS_PLL]              = &a5_sys_ts_pll.hw,
>> +     [CLKID_SYS_DEV_ARB]             = &a5_sys_dev_arb.hw,
>> +     [CLKID_SYS_MAILBOX]             = &a5_sys_mailbox.hw,
>> +     [CLKID_SYS_JTAG_CTRL]           = &a5_sys_jtag_ctrl.hw,
>> +     [CLKID_SYS_IR_CTRL]             = &a5_sys_ir_ctrl.hw,
>> +     [CLKID_SYS_MSR_CLK]             = &a5_sys_msr_clk.hw,
>> +     [CLKID_SYS_ROM]                 = &a5_sys_rom.hw,
>> +     [CLKID_SYS_CPU_ARB]             = &a5_sys_cpu_apb.hw,
>> +     [CLKID_SYS_RSA]                 = &a5_sys_rsa.hw,
>> +     [CLKID_SYS_SARADC]              = &a5_sys_saradc.hw,
>> +     [CLKID_SYS_STARTUP]             = &a5_sys_startup.hw,
>> +     [CLKID_SYS_SECURE]              = &a5_sys_secure.hw,
>> +     [CLKID_SYS_SPIFC]               = &a5_sys_spifc.hw,
>> +     [CLKID_SYS_DSPA]                = &a5_sys_dspa.hw,
>> +     [CLKID_SYS_NNA]                 = &a5_sys_nna.hw,
>> +     [CLKID_SYS_ETH_MAC]             = &a5_sys_eth_mac.hw,
>> +     [CLKID_SYS_RAMA]                = &a5_sys_rama.hw,
>> +     [CLKID_SYS_RAMB]                = &a5_sys_ramb.hw,
>> +     [CLKID_SYS_AUDIO_TOP]           = &a5_sys_audio_top.hw,
>> +     [CLKID_SYS_AUDIO_VAD]           = &a5_sys_audio_vad.hw,
>> +     [CLKID_SYS_USB]                 = &a5_sys_usb.hw,
>> +     [CLKID_SYS_SD_EMMC_A]           = &a5_sys_sd_emmc_a.hw,
>> +     [CLKID_SYS_SD_EMMC_C]           = &a5_sys_sd_emmc_c.hw,
>> +     [CLKID_SYS_PWM_AB]              = &a5_sys_pwm_ab.hw,
>> +     [CLKID_SYS_PWM_CD]              = &a5_sys_pwm_cd.hw,
>> +     [CLKID_SYS_PWM_EF]              = &a5_sys_pwm_ef.hw,
>> +     [CLKID_SYS_PWM_GH]              = &a5_sys_pwm_gh.hw,
>> +     [CLKID_SYS_SPICC_1]             = &a5_sys_spicc_1.hw,
>> +     [CLKID_SYS_SPICC_0]             = &a5_sys_spicc_0.hw,
>> +     [CLKID_SYS_UART_A]              = &a5_sys_uart_a.hw,
>> +     [CLKID_SYS_UART_B]              = &a5_sys_uart_b.hw,
>> +     [CLKID_SYS_UART_C]              = &a5_sys_uart_c.hw,
>> +     [CLKID_SYS_UART_D]              = &a5_sys_uart_d.hw,
>> +     [CLKID_SYS_UART_E]              = &a5_sys_uart_e.hw,
>> +     [CLKID_SYS_I2C_M_A]             = &a5_sys_i2c_m_a.hw,
>> +     [CLKID_SYS_I2C_M_B]             = &a5_sys_i2c_m_b.hw,
>> +     [CLKID_SYS_I2C_M_C]             = &a5_sys_i2c_m_c.hw,
>> +     [CLKID_SYS_I2C_M_D]             = &a5_sys_i2c_m_d.hw,
>> +     [CLKID_SYS_RTC]                 = &a5_sys_rtc.hw,
>> +     [CLKID_AXI_AUDIO_VAD]           = &a5_axi_audio_vad.hw,
>> +     [CLKID_AXI_AUDIO_TOP]           = &a5_axi_audio_top.hw,
>> +     [CLKID_AXI_RAMB]                = &a5_axi_ramb.hw,
>> +     [CLKID_AXI_RAMA]                = &a5_axi_rama.hw,
>> +     [CLKID_AXI_NNA]                 = &a5_axi_nna.hw,
>> +     [CLKID_AXI_DEV1_DMC]            = &a5_axi_dev1_dmc.hw,
>> +     [CLKID_AXI_DEV0_DMC]            = &a5_axi_dev0_dmc.hw,
>> +     [CLKID_AXI_DSP_DMC]             = &a5_axi_dsp_dmc.hw,
>> +     [CLKID_12_24M_IN]               = &a5_clk_12_24m_in.hw,
>> +     [CLKID_12M_24M]                 = &a5_clk_12_24m.hw,
>> +     [CLKID_FCLK_25M_DIV]            = &a5_fclk_25m_div.hw,
>> +     [CLKID_FCLK_25M]                = &a5_fclk_25m.hw,
>> +     [CLKID_GEN_SEL]                 = &a5_gen_sel.hw,
>> +     [CLKID_GEN_DIV]                 = &a5_gen_div.hw,
>> +     [CLKID_GEN]                     = &a5_gen.hw,
>> +     [CLKID_SARADC_SEL]              = &a5_saradc_sel.hw,
>> +     [CLKID_SARADC_DIV]              = &a5_saradc_div.hw,
>> +     [CLKID_SARADC]                  = &a5_saradc.hw,
>> +     [CLKID_PWM_A_SEL]               = &a5_pwm_a_sel.hw,
>> +     [CLKID_PWM_A_DIV]               = &a5_pwm_a_div.hw,
>> +     [CLKID_PWM_A]                   = &a5_pwm_a.hw,
>> +     [CLKID_PWM_B_SEL]               = &a5_pwm_b_sel.hw,
>> +     [CLKID_PWM_B_DIV]               = &a5_pwm_b_div.hw,
>> +     [CLKID_PWM_B]                   = &a5_pwm_b.hw,
>> +     [CLKID_PWM_C_SEL]               = &a5_pwm_c_sel.hw,
>> +     [CLKID_PWM_C_DIV]               = &a5_pwm_c_div.hw,
>> +     [CLKID_PWM_C]                   = &a5_pwm_c.hw,
>> +     [CLKID_PWM_D_SEL]               = &a5_pwm_d_sel.hw,
>> +     [CLKID_PWM_D_DIV]               = &a5_pwm_d_div.hw,
>> +     [CLKID_PWM_D]                   = &a5_pwm_d.hw,
>> +     [CLKID_PWM_E_SEL]               = &a5_pwm_e_sel.hw,
>> +     [CLKID_PWM_E_DIV]               = &a5_pwm_e_div.hw,
>> +     [CLKID_PWM_E]                   = &a5_pwm_e.hw,
>> +     [CLKID_PWM_F_SEL]               = &a5_pwm_f_sel.hw,
>> +     [CLKID_PWM_F_DIV]               = &a5_pwm_f_div.hw,
>> +     [CLKID_PWM_F]                   = &a5_pwm_f.hw,
>> +     [CLKID_PWM_G_SEL]               = &a5_pwm_g_sel.hw,
>> +     [CLKID_PWM_G_DIV]               = &a5_pwm_g_div.hw,
>> +     [CLKID_PWM_G]                   = &a5_pwm_g.hw,
>> +     [CLKID_PWM_H_SEL]               = &a5_pwm_h_sel.hw,
>> +     [CLKID_PWM_H_DIV]               = &a5_pwm_h_div.hw,
>> +     [CLKID_PWM_H]                   = &a5_pwm_h.hw,
>> +     [CLKID_SPICC_0_SEL]             = &a5_spicc_0_sel.hw,
>> +     [CLKID_SPICC_0_DIV]             = &a5_spicc_0_div.hw,
>> +     [CLKID_SPICC_0]                 = &a5_spicc_0.hw,
>> +     [CLKID_SPICC_1_SEL]             = &a5_spicc_1_sel.hw,
>> +     [CLKID_SPICC_1_DIV]             = &a5_spicc_1_div.hw,
>> +     [CLKID_SPICC_1]                 = &a5_spicc_1.hw,
>> +     [CLKID_SD_EMMC_A_SEL]           = &a5_sd_emmc_a_sel.hw,
>> +     [CLKID_SD_EMMC_A_DIV]           = &a5_sd_emmc_a_div.hw,
>> +     [CLKID_SD_EMMC_A]               = &a5_sd_emmc_a.hw,
>> +     [CLKID_SD_EMMC_C_SEL]           = &a5_sd_emmc_c_sel.hw,
>> +     [CLKID_SD_EMMC_C_DIV]           = &a5_sd_emmc_c_div.hw,
>> +     [CLKID_SD_EMMC_C]               = &a5_sd_emmc_c.hw,
>> +     [CLKID_TS_DIV]                  = &a5_ts_div.hw,
>> +     [CLKID_TS]                      = &a5_ts.hw,
>> +     [CLKID_ETH_125M_DIV]            = &a5_eth_125m_div.hw,
>> +     [CLKID_ETH_125M]                = &a5_eth_125m.hw,
>> +     [CLKID_ETH_RMII_DIV]            = &a5_eth_rmii_div.hw,
>> +     [CLKID_ETH_RMII]                = &a5_eth_rmii.hw,
>> +     [CLKID_DSPA_0_SEL]              = &a5_dspa_0_sel.hw,
>> +     [CLKID_DSPA_0_DIV]              = &a5_dspa_0_div.hw,
>> +     [CLKID_DSPA_0]                  = &a5_dspa_0.hw,
>> +     [CLKID_DSPA_1_SEL]              = &a5_dspa_1_sel.hw,
>> +     [CLKID_DSPA_1_DIV]              = &a5_dspa_1_div.hw,
>> +     [CLKID_DSPA_1]                  = &a5_dspa_1.hw,
>> +     [CLKID_DSPA]                    = &a5_dspa.hw,
>> +     [CLKID_NNA_CORE_SEL]            = &a5_nna_core_sel.hw,
>> +     [CLKID_NNA_CORE_DIV]            = &a5_nna_core_div.hw,
>> +     [CLKID_NNA_CORE]                = &a5_nna_core.hw,
>> +     [CLKID_NNA_AXI_SEL]             = &a5_nna_axi_sel.hw,
>> +     [CLKID_NNA_AXI_DIV]             = &a5_nna_axi_div.hw,
>> +     [CLKID_NNA_AXI]                 = &a5_nna_axi.hw,
>> +};
>> +
>> +static const struct meson_clkc_data a5_peripherals_clkc_data = {
>> +     .hw_clks = {
>> +             .hws = a5_peripherals_hw_clks,
>> +             .num = ARRAY_SIZE(a5_peripherals_hw_clks),
>> +     },
>> +};
>> +
>> +static const struct of_device_id a5_peripherals_clkc_match_table[] = {
>> +     {
>> +             .compatible = "amlogic,a5-peripherals-clkc",
>> +             .data = &a5_peripherals_clkc_data,
>> +     },
>> +     {}
>> +};
>> +MODULE_DEVICE_TABLE(of, a5_peripherals_clkc_match_table);
>> +
>> +static struct platform_driver a5_peripherals_clkc_driver = {
>> +     .probe = meson_clkc_mmio_probe,
>> +     .driver = {
>> +             .name = "a5-peripherals-clkc",
>> +             .of_match_table = a5_peripherals_clkc_match_table,
>> +     },
>> +};
>> +module_platform_driver(a5_peripherals_clkc_driver);
>> +
>> +MODULE_DESCRIPTION("Amlogic A5 Peripherals Clock Controller driver");
>> +MODULE_AUTHOR("Chuan Liu <chuan.liu at amlogic.com>");
>> +MODULE_LICENSE("GPL");
>> +MODULE_IMPORT_NS("CLK_MESON");
> 
> --
> Jerome



From manivannan.sadhasivam at oss.qualcomm.com  Tue Dec 23 04:29:54 2025
From: manivannan.sadhasivam at oss.qualcomm.com (Manivannan Sadhasivam)
Date: Tue, 23 Dec 2025 17:59:54 +0530
Subject: [PATCH v3] PCI: xilinx: Fix INTx IRQ domain leak in error
 paths
In-Reply-To: <20251219021615.965-1-vulab@iscas.ac.cn>
References: <20251119033301.518-1-vulab@iscas.ac.cn>
 <20251219021615.965-1-vulab@iscas.ac.cn>
Message-ID: <176649299472.522673.6050154108234112363.b4-ty@kernel.org>


On Fri, 19 Dec 2025 10:16:15 +0800, Haotian Zhang wrote:
> In xilinx_pcie_init_irq_domain(), if xilinx_allocate_msi_domains()
> fails after pcie->leg_domain has been successfully created via
> irq_domain_create_linear(), the function returns directly without
> cleaning up the allocated IRQ domain, resulting in a resource leak.
> In xilinx_free_msi_domains(), pcie->leg_domain is also neglected.
> 
> Add irq_domain_remove() call in the error path to properly release the
> IRQ domain before returning the error. Rename xilinx_free_msi_domains()
> to xilinx_free_irq_domains() and add the release of pcie->leg_domain
> in the function.
> 
> [...]

Applied, thanks!

[1/1] PCI: xilinx: Fix INTx IRQ domain leak in error paths
      commit: f42b3c053b1554d66af6fe45bb1ef357464c0456

Best regards,
-- 
Manivannan Sadhasivam <mani at kernel.org>



From manivannan.sadhasivam at oss.qualcomm.com  Tue Dec 23 04:35:10 2025
From: manivannan.sadhasivam at oss.qualcomm.com (Manivannan Sadhasivam)
Date: Tue, 23 Dec 2025 18:05:10 +0530
Subject: (subset) [PATCH v10 0/4] PCI: imx6: Add external reference
 clock mode support
In-Reply-To: <20251211064821.2707001-1-hongxing.zhu@nxp.com>
References: <20251211064821.2707001-1-hongxing.zhu@nxp.com>
Message-ID: <176649331066.523506.9443864112044699350.b4-ty@kernel.org>


On Thu, 11 Dec 2025 14:48:17 +0800, Richard Zhu wrote:
> I'm really sorry to send this version patch-set late, because that I was
> engaged in other emergent tasks in the past weeks. And didn't have time
> to continue this topic. Now, I have chance to continue doing this again.
> Sorry to bring the inconvenience to the patch review.
> 
> i.MX95 PCIes have two reference clock inputs: one from internal PLL.
> It's wired inside chip and present as "ref" clock. It's not an optional
> clock. The other from off chip crystal oscillator. The "extref" clock
> refers to a reference clock from an external crystal oscillator through
> the CLKIN_N/P pair PADs. It is an optional clock, relied on the board
> design.
> 
> [...]

Applied, thanks!

[1/4] dt-bindings: PCI: dwc: Add external reference clock input
      commit: 418970983059aa06302ddd5ca76d441973b537c1
[2/4] dt-bindings: PCI: pci-imx6: Add external reference clock input
      commit: 1352f58d7c8dfb6ba0fbd2041bfc8b4b3966ec67
[3/4] PCI: imx6: Add external reference clock input mode support
      commit: d8574ce57d760a958623c8f6bc3c55b5187a7bd7

Best regards,
-- 
Manivannan Sadhasivam <mani at kernel.org>



From sjoerd at collabora.com  Tue Dec 23 04:37:51 2025
From: sjoerd at collabora.com (Sjoerd Simons)
Date: Tue, 23 Dec 2025 13:37:51 +0100
Subject: [PATCH v5 1/8] dt-bindings: PCI: mediatek-gen3: Add MT7981 PCIe
 compatible
In-Reply-To: <20251223-openwrt-one-network-v5-0-7d1864ea3ad5@collabora.com>
References: <20251223-openwrt-one-network-v5-0-7d1864ea3ad5@collabora.com>
Message-ID: <20251223-openwrt-one-network-v5-1-7d1864ea3ad5@collabora.com>

Add compatible string for MediaTek MT7981 PCIe Gen3 controller.
The MT7981 PCIe controller is compatible with the MT8192 PCIe
controller.

Acked-by: Conor Dooley <conor.dooley at microchip.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
Signed-off-by: Sjoerd Simons <sjoerd at collabora.com>
---
V1 -> V2: Improve commit subject
---
 Documentation/devicetree/bindings/pci/mediatek-pcie-gen3.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/pci/mediatek-pcie-gen3.yaml b/Documentation/devicetree/bindings/pci/mediatek-pcie-gen3.yaml
index 0278845701ce..4db700fc36ba 100644
--- a/Documentation/devicetree/bindings/pci/mediatek-pcie-gen3.yaml
+++ b/Documentation/devicetree/bindings/pci/mediatek-pcie-gen3.yaml
@@ -48,6 +48,7 @@ properties:
     oneOf:
       - items:
           - enum:
+              - mediatek,mt7981-pcie
               - mediatek,mt7986-pcie
               - mediatek,mt8188-pcie
               - mediatek,mt8195-pcie

-- 
2.51.0



From sjoerd at collabora.com  Tue Dec 23 04:37:53 2025
From: sjoerd at collabora.com (Sjoerd Simons)
Date: Tue, 23 Dec 2025 13:37:53 +0100
Subject: [PATCH v5 3/8] arm64: dts: mediatek: mt7981b-openwrt-one: Enable
 PCIe and USB
In-Reply-To: <20251223-openwrt-one-network-v5-0-7d1864ea3ad5@collabora.com>
References: <20251223-openwrt-one-network-v5-0-7d1864ea3ad5@collabora.com>
Message-ID: <20251223-openwrt-one-network-v5-3-7d1864ea3ad5@collabora.com>

Enable the PCIe controller and USB3 XHCI host on the OpenWrt One
board. The USB controller is configured for USB 2.0 only mode, as the
shared USB3/PCIe PHY is dedicated to PCIe functionality on this board.

Signed-off-by: Sjoerd Simons <sjoerd at collabora.com>
---
 .../boot/dts/mediatek/mt7981b-openwrt-one.dts      | 43 ++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts b/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts
index 2e39e7287730..7382599cfea2 100644
--- a/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts
+++ b/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts
@@ -67,9 +67,40 @@ led-2 {
 			linux,default-trigger = "netdev";
 		};
 	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+
+	reg_5v: regulator-5v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-5V";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
+&pcie {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie_pins>;
+	status = "okay";
 };
 
 &pio {
+	pcie_pins: pcie-pins {
+		mux {
+			function = "pcie";
+			groups = "pcie_pereset";
+		};
+	};
+
 	pwm_pins: pwm-pins {
 		mux {
 			function = "pwm";
@@ -163,3 +194,15 @@ partition at 180000 {
 &uart0 {
 	status = "okay";
 };
+
+&usb_phy {
+	status = "okay";
+};
+
+&xhci {
+	phys = <&u2port0 PHY_TYPE_USB2>;
+	vusb33-supply = <&reg_3p3v>;
+	vbus-supply = <&reg_5v>;
+	mediatek,u3p-dis-msk = <0x01>;
+	status = "okay";
+};

-- 
2.51.0



From sjoerd at collabora.com  Tue Dec 23 04:37:56 2025
From: sjoerd at collabora.com (Sjoerd Simons)
Date: Tue, 23 Dec 2025 13:37:56 +0100
Subject: [PATCH v5 6/8] arm64: dts: mediatek: mt7981b: Disable wifi by
 default
In-Reply-To: <20251223-openwrt-one-network-v5-0-7d1864ea3ad5@collabora.com>
References: <20251223-openwrt-one-network-v5-0-7d1864ea3ad5@collabora.com>
Message-ID: <20251223-openwrt-one-network-v5-6-7d1864ea3ad5@collabora.com>

Disable the wifi block by default as it won't function properly without
at least pin muxing.

This doesn't enable wifi on any of the existing mt7981b devices as a
required memory-region property is missing, causing the driver to fail
probing anyway.

Signed-off-by: Sjoerd Simons <sjoerd at collabora.com>
---
V2: Newly introduced patch
---
 arch/arm64/boot/dts/mediatek/mt7981b.dtsi | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi
index 6be588be3761..1f4c11435466 100644
--- a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi
@@ -499,6 +499,7 @@ wifi at 18000000 {
 			clock-names = "mcu", "ap2conn";
 			resets = <&watchdog MT7986_TOPRGU_CONSYS_SW_RST>;
 			reset-names = "consys";
+			status = "disabled";
 		};
 	};
 

-- 
2.51.0



From sjoerd at collabora.com  Tue Dec 23 04:37:50 2025
From: sjoerd at collabora.com (Sjoerd Simons)
Date: Tue, 23 Dec 2025 13:37:50 +0100
Subject: [PATCH v5 0/8] arm64: dts: mediatek: Add Openwrt One AP
 functionality
Message-ID: <20251223-openwrt-one-network-v5-0-7d1864ea3ad5@collabora.com>

Significant changes in V5:
  * Rebase against linux v6.19-rc2, dropping merged patches
  * Drop note about disable pci_aspm in cover letter, not required anymore
Significant changes in V4:
  * Drop patches that were picked up
  * Improve mediatek,net dt bindings:
    - Move back to V2 version (widening global constraint, constraining
      per compatible)
    - Ensure all compatibles are constraint in the amount of WEDs (2 for
      everything apart from mt7981). Specifically adding constraints for
      mediatek,mt7622-eth and ralink,rt5350-eth
Significant changes in V3:
  * Drop patches that were picked up
  * Re-order patches so changes that don't require dt binding changes
    come first (Requested by Angelo)
  * Specify drive power directly rather then using MTK_DRIVE_...
  * Simply mediatek,net binding changes to avoid accidental changes to
    other compatibles then mediatek,mt7981-eth
Significant changes in V2:
  * https://lore.kernel.org/lkml/20251016-openwrt-one-network-v1-0-de259719b6f2 at collabora.com/
  * Only introduce labels in mt7981b.dtsi when required
  * Switch Airoha EN8811H phy irq to level rather then edge triggered
  * Move uart0 pinctrl from board dts to soc dtsi
  * Only overwrite constraints with non-default values in MT7981 bindings
  * Make SPI NOR nvmem cell labels more meaningfull
  * Seperate fixing and disable-by-default for the mt7981 in seperate
    patches

This series add various peripherals to the Openwrt One, to make it
actually useful an access point:

* Pcie express (tested with nvme storage)
* Wired network interfaces
* Wireless network interfaces (2.4g, 5ghz wifi)
* Status leds
* SPI NOR for factory data

Unsurprisingly the series is a mix of dt binding updates, extensions of
the mt7981b and the openwrt one dtb. All driver support required is
already available.

Sadly during testing i've found various quirks requiring kernel
arguments. Documenting those here both as note to self and making it
easier for others to test :)

* fw_devlink=permissive: the nvmem fixed-layout doesn't create a layout
  device, so doesn't trigger fw_devlink
* clk_ignore_unused: Needed when building CONFIG_NET_MEDIATEK_SOC as a
  module. If the ethernet related clocks (gp1/gp2) get disabled the
  mac ends up in a weird state causing it not to function correctly.

Patches are against linux v6.19-rc2

Signed-off-by: Sjoerd Simons <sjoerd at collabora.com>
---
Sjoerd Simons (8):
      dt-bindings: PCI: mediatek-gen3: Add MT7981 PCIe compatible
      arm64: dts: mediatek: mt7981b: Add PCIe and USB support
      arm64: dts: mediatek: mt7981b-openwrt-one: Enable PCIe and USB
      arm64: dts: mediatek: mt7981b: Add Ethernet and WiFi offload support
      arm64: dts: mediatek: mt7981b-openwrt-one: Enable Ethernet
      arm64: dts: mediatek: mt7981b: Disable wifi by default
      arm64: dts: mediatek: mt7981b: Add wifi memory region
      arm64: dts: mediatek: mt7981b-openwrt-one: Enable wifi

 .../bindings/pci/mediatek-pcie-gen3.yaml           |   1 +
 .../boot/dts/mediatek/mt7981b-openwrt-one.dts      | 125 ++++++++++++
 arch/arm64/boot/dts/mediatek/mt7981b.dtsi          | 222 ++++++++++++++++++++-
 3 files changed, 346 insertions(+), 2 deletions(-)
---
base-commit: b927546677c876e26eba308550207c2ddf812a43
change-id: 20251016-openwrt-one-network-40bc9ac1b25c

Best regards,
-- 
Sjoerd Simons <sjoerd at collabora.com>



From sjoerd at collabora.com  Tue Dec 23 04:37:52 2025
From: sjoerd at collabora.com (Sjoerd Simons)
Date: Tue, 23 Dec 2025 13:37:52 +0100
Subject: [PATCH v5 2/8] arm64: dts: mediatek: mt7981b: Add PCIe and USB
 support
In-Reply-To: <20251223-openwrt-one-network-v5-0-7d1864ea3ad5@collabora.com>
References: <20251223-openwrt-one-network-v5-0-7d1864ea3ad5@collabora.com>
Message-ID: <20251223-openwrt-one-network-v5-2-7d1864ea3ad5@collabora.com>

Add device tree nodes for PCIe controller and USB3 XHCI host
controller on MT7981B SoC. Both controllers share the USB3 PHY
which can be configured for either USB3 or PCIe operation.

The USB3 XHCI controller supports USB 2.0 and USB 3.0 SuperSpeed
operation. The PCIe controller is compatible with PCIe Gen2
specifications.

Also add the topmisc syscon node required for USB/PCIe PHY
multiplexing.

Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
Signed-off-by: Sjoerd Simons <sjoerd at collabora.com>
---
V1 -> V2: Keep xhci reg and phys properties in single lines
---
 arch/arm64/boot/dts/mediatek/mt7981b.dtsi | 80 +++++++++++++++++++++++++++++++
 1 file changed, 80 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi
index 416096b80770..d3f37413413e 100644
--- a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi
@@ -2,6 +2,7 @@
 
 #include <dt-bindings/clock/mediatek,mt7981-clk.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/phy/phy.h>
 #include <dt-bindings/reset/mt7986-resets.h>
 
 / {
@@ -223,6 +224,55 @@ auxadc: adc at 1100d000 {
 			status = "disabled";
 		};
 
+		xhci: usb at 11200000 {
+			compatible = "mediatek,mt7986-xhci", "mediatek,mtk-xhci";
+			reg = <0 0x11200000 0 0x2e00>, <0 0x11203e00 0 0x0100>;
+			reg-names = "mac", "ippc";
+			clocks = <&infracfg CLK_INFRA_IUSB_SYS_CK>,
+				 <&infracfg CLK_INFRA_IUSB_CK>,
+				 <&infracfg CLK_INFRA_IUSB_133_CK>,
+				 <&infracfg CLK_INFRA_IUSB_66M_CK>,
+				 <&topckgen CLK_TOP_U2U3_XHCI_SEL>;
+			clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck", "xhci_ck";
+			interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
+			phys = <&u2port0 PHY_TYPE_USB2>, <&u3port0 PHY_TYPE_USB3>;
+			status = "disabled";
+		};
+
+		pcie: pcie at 11280000 {
+			compatible = "mediatek,mt7981-pcie",
+				     "mediatek,mt8192-pcie";
+			reg = <0 0x11280000 0 0x4000>;
+			reg-names = "pcie-mac";
+			ranges = <0x82000000 0 0x20000000
+				  0x0 0x20000000 0 0x10000000>;
+			bus-range = <0x00 0xff>;
+			clocks = <&infracfg CLK_INFRA_IPCIE_CK>,
+				 <&infracfg CLK_INFRA_IPCIE_PIPE_CK>,
+				 <&infracfg CLK_INFRA_IPCIER_CK>,
+				 <&infracfg CLK_INFRA_IPCIEB_CK>;
+			clock-names = "pl_250m", "tl_26m", "peri_26m", "top_133m";
+			device_type = "pci";
+			phys = <&u3port0 PHY_TYPE_PCIE>;
+			phy-names = "pcie-phy";
+			interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-map-mask = <0 0 0 7>;
+			interrupt-map = <0 0 0 1 &pcie_intc 0>,
+					<0 0 0 2 &pcie_intc 1>,
+					<0 0 0 3 &pcie_intc 2>,
+					<0 0 0 4 &pcie_intc 3>;
+			#address-cells = <3>;
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			status = "disabled";
+
+			pcie_intc: interrupt-controller {
+				interrupt-controller;
+				#address-cells = <0>;
+				#interrupt-cells = <1>;
+			};
+		};
+
 		pio: pinctrl at 11d00000 {
 			compatible = "mediatek,mt7981-pinctrl";
 			reg = <0 0x11d00000 0 0x1000>,
@@ -252,6 +302,36 @@ mux {
 			};
 		};
 
+		topmisc: topmisc at 11d10000 {
+			compatible = "mediatek,mt7981-topmisc", "syscon";
+			reg = <0 0x11d10000 0 0x10000>;
+			#clock-cells = <1>;
+		};
+
+		usb_phy: t-phy at 11e10000 {
+			compatible = "mediatek,mt7981-tphy",
+				     "mediatek,generic-tphy-v2";
+			ranges = <0 0 0x11e10000 0x1700>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			status = "disabled";
+
+			u2port0: usb-phy at 0 {
+				reg = <0x0 0x700>;
+				clocks = <&topckgen CLK_TOP_USB_FRMCNT_SEL>;
+				clock-names = "ref";
+				#phy-cells = <1>;
+			};
+
+			u3port0: usb-phy at 700 {
+				reg = <0x700 0x900>;
+				clocks = <&topckgen CLK_TOP_USB3_PHY_SEL>;
+				clock-names = "ref";
+				#phy-cells = <1>;
+				mediatek,syscon-type = <&topmisc 0x218 0>;
+			};
+		};
+
 		efuse at 11f20000 {
 			compatible = "mediatek,mt7981-efuse", "mediatek,efuse";
 			reg = <0 0x11f20000 0 0x1000>;

-- 
2.51.0



From sjoerd at collabora.com  Tue Dec 23 04:37:58 2025
From: sjoerd at collabora.com (Sjoerd Simons)
Date: Tue, 23 Dec 2025 13:37:58 +0100
Subject: [PATCH v5 8/8] arm64: dts: mediatek: mt7981b-openwrt-one: Enable
 wifi
In-Reply-To: <20251223-openwrt-one-network-v5-0-7d1864ea3ad5@collabora.com>
References: <20251223-openwrt-one-network-v5-0-7d1864ea3ad5@collabora.com>
Message-ID: <20251223-openwrt-one-network-v5-8-7d1864ea3ad5@collabora.com>

Enable Dual-band WiFI 6 functionality on the Openwrt One

Signed-off-by: Sjoerd Simons <sjoerd at collabora.com>
---
V2 -> V3: replace MTK_DRIVE_4mA with direct value
V1 -> V2: Update eeprom node label
---
 .../boot/dts/mediatek/mt7981b-openwrt-one.dts      | 24 ++++++++++++++++++++++
 arch/arm64/boot/dts/mediatek/mt7981b.dtsi          |  2 +-
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts b/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts
index 2aea89900645..3de368c73bc8 100644
--- a/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts
+++ b/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts
@@ -180,6 +180,22 @@ conf-pd {
 			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
 		};
 	};
+
+	wifi_dbdc_pins: wifi-dbdc-pins {
+		mux {
+			function = "eth";
+			groups = "wf0_mode1";
+		};
+
+		conf {
+			pins = "WF_HB1", "WF_HB2", "WF_HB3", "WF_HB4",
+			       "WF_HB0", "WF_HB0_B", "WF_HB5", "WF_HB6",
+			       "WF_HB7", "WF_HB8", "WF_HB9", "WF_HB10",
+			       "WF_TOP_CLK", "WF_TOP_DATA", "WF_XO_REQ",
+			       "WF_CBA_RESETB", "WF_DIG_RESETB";
+			drive-strength = <4>;
+		};
+	};
 };
 
 &pwm {
@@ -257,6 +273,14 @@ &usb_phy {
 	status = "okay";
 };
 
+&wifi {
+	nvmem-cells = <&wifi_factory_calibration>;
+	nvmem-cell-names = "eeprom";
+	pinctrl-names = "dbdc";
+	pinctrl-0 = <&wifi_dbdc_pins>;
+	status = "okay";
+};
+
 &xhci {
 	phys = <&u2port0 PHY_TYPE_USB2>;
 	vusb33-supply = <&reg_3p3v>;
diff --git a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi
index a7be3670e005..66d89495bac5 100644
--- a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi
@@ -490,7 +490,7 @@ wo_ccif0: syscon at 151a5000 {
 			interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>;
 		};
 
-		wifi at 18000000 {
+		wifi: wifi at 18000000 {
 			compatible = "mediatek,mt7981-wmac";
 			reg = <0 0x18000000 0 0x1000000>,
 			      <0 0x10003000 0 0x1000>,

-- 
2.51.0



From sjoerd at collabora.com  Tue Dec 23 04:37:54 2025
From: sjoerd at collabora.com (Sjoerd Simons)
Date: Tue, 23 Dec 2025 13:37:54 +0100
Subject: [PATCH v5 4/8] arm64: dts: mediatek: mt7981b: Add Ethernet and
 WiFi offload support
In-Reply-To: <20251223-openwrt-one-network-v5-0-7d1864ea3ad5@collabora.com>
References: <20251223-openwrt-one-network-v5-0-7d1864ea3ad5@collabora.com>
Message-ID: <20251223-openwrt-one-network-v5-4-7d1864ea3ad5@collabora.com>

Add device tree nodes for the Ethernet subsystem on MT7981B SoC,
including:
- Ethernet MAC controller with dual GMAC support
- Wireless Ethernet Dispatch (WED)
- SGMII PHY controllers for high-speed Ethernet interfaces
- Reserved memory regions for WiFi offload processor

Signed-off-by: Sjoerd Simons <sjoerd at collabora.com>
---
V1 -> V2: Don't add unneeded interrupt-parent
---
 arch/arm64/boot/dts/mediatek/mt7981b.dtsi | 133 +++++++++++++++++++++++++++++-
 1 file changed, 132 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi
index d3f37413413e..6be588be3761 100644
--- a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi
@@ -2,6 +2,7 @@
 
 #include <dt-bindings/clock/mediatek,mt7981-clk.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/leds/common.h>
 #include <dt-bindings/phy/phy.h>
 #include <dt-bindings/reset/mt7986-resets.h>
 
@@ -47,11 +48,36 @@ reserved-memory {
 		#size-cells = <2>;
 		ranges;
 
+		wo_boot: wo-boot at 15194000 {
+			reg = <0 0x15194000 0 0x1000>;
+			no-map;
+		};
+
+		wo_ilm0: wo-ilm at 151e0000 {
+			reg = <0 0x151e0000 0 0x8000>;
+			no-map;
+		};
+
+		wo_dlm0: wo-dlm at 151e8000 {
+			reg = <0 0x151e8000 0 0x2000>;
+			no-map;
+		};
+
 		/* 192 KiB reserved for ARM Trusted Firmware (BL31) */
 		secmon_reserved: secmon at 43000000 {
 			reg = <0 0x43000000 0 0x30000>;
 			no-map;
 		};
+
+		wo_emi0: wo-emi at 47d80000 {
+			reg = <0 0x47d80000 0 0x40000>;
+			no-map;
+		};
+
+		wo_data: wo-data at 47dc0000 {
+			reg = <0 0x47dc0000 0 0x240000>;
+			no-map;
+		};
 	};
 
 	soc {
@@ -107,6 +133,18 @@ pwm: pwm at 10048000 {
 			#pwm-cells = <2>;
 		};
 
+		sgmiisys0: syscon at 10060000 {
+			compatible = "mediatek,mt7981-sgmiisys_0", "syscon";
+			reg = <0 0x10060000 0 0x1000>;
+			#clock-cells = <1>;
+		};
+
+		sgmiisys1: syscon at 10070000 {
+			compatible = "mediatek,mt7981-sgmiisys_1", "syscon";
+			reg = <0 0x10070000 0 0x1000>;
+			#clock-cells = <1>;
+		};
+
 		uart0: serial at 11002000 {
 			compatible = "mediatek,mt7981-uart", "mediatek,mt6577-uart";
 			reg = <0 0x11002000 0 0x100>;
@@ -345,15 +383,108 @@ soc-uuid at 140 {
 			thermal_calibration: thermal-calib at 274 {
 				reg = <0x274 0xc>;
 			};
+
+			phy_calibration: phy-calib at 8dc {
+				reg = <0x8dc 0x10>;
+			};
 		};
 
-		clock-controller at 15000000 {
+		ethsys: clock-controller at 15000000 {
 			compatible = "mediatek,mt7981-ethsys", "syscon";
 			reg = <0 0x15000000 0 0x1000>;
 			#clock-cells = <1>;
 			#reset-cells = <1>;
 		};
 
+		wed: wed at 15010000 {
+			compatible = "mediatek,mt7981-wed",
+				     "syscon";
+			reg = <0 0x15010000 0 0x1000>;
+			interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
+			memory-region = <&wo_emi0>, <&wo_ilm0>, <&wo_dlm0>,
+					<&wo_data>, <&wo_boot>;
+			memory-region-names = "wo-emi", "wo-ilm", "wo-dlm",
+					      "wo-data", "wo-boot";
+			mediatek,wo-ccif = <&wo_ccif0>;
+		};
+
+		eth: ethernet at 15100000 {
+			compatible = "mediatek,mt7981-eth";
+			reg = <0 0x15100000 0 0x40000>;
+			assigned-clocks = <&topckgen CLK_TOP_NETSYS_2X_SEL>,
+					  <&topckgen CLK_TOP_SGM_325M_SEL>;
+			assigned-clock-parents = <&topckgen CLK_TOP_CB_NET2_800M>,
+						 <&topckgen CLK_TOP_CB_SGM_325M>;
+			clocks = <&ethsys CLK_ETH_FE_EN>,
+				 <&ethsys CLK_ETH_GP2_EN>,
+				 <&ethsys CLK_ETH_GP1_EN>,
+				 <&ethsys CLK_ETH_WOCPU0_EN>,
+				 <&topckgen CLK_TOP_SGM_REG>,
+				 <&sgmiisys0 CLK_SGM0_TX_EN>,
+				 <&sgmiisys0 CLK_SGM0_RX_EN>,
+				 <&sgmiisys0 CLK_SGM0_CK0_EN>,
+				 <&sgmiisys0 CLK_SGM0_CDR_CK0_EN>,
+				 <&sgmiisys1 CLK_SGM1_TX_EN>,
+				 <&sgmiisys1 CLK_SGM1_RX_EN>,
+				 <&sgmiisys1 CLK_SGM1_CK1_EN>,
+				 <&sgmiisys1 CLK_SGM1_CDR_CK1_EN>,
+				 <&topckgen CLK_TOP_NETSYS_SEL>,
+				 <&topckgen CLK_TOP_NETSYS_500M_SEL>;
+			clock-names = "fe", "gp2", "gp1", "wocpu0",
+				      "sgmii_ck",
+				      "sgmii_tx250m", "sgmii_rx250m",
+				      "sgmii_cdr_ref", "sgmii_cdr_fb",
+				      "sgmii2_tx250m", "sgmii2_rx250m",
+				      "sgmii2_cdr_ref", "sgmii2_cdr_fb",
+				      "netsys0", "netsys1";
+			interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "fe0", "fe1", "fe2", "fe3", "pdma0",
+					  "pdma1", "pdma2", "pdma3";
+			sram = <&eth_sram>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			mediatek,ethsys = <&ethsys>;
+			mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
+			mediatek,infracfg = <&topmisc>;
+			mediatek,wed = <&wed>;
+			status = "disabled";
+
+			mdio_bus: mdio-bus {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				int_gbe_phy: ethernet-phy at 0 {
+					compatible = "ethernet-phy-ieee802.3-c22";
+					reg = <0>;
+					phy-mode = "gmii";
+					phy-is-integrated;
+					nvmem-cells = <&phy_calibration>;
+					nvmem-cell-names = "phy-cal-data";
+				};
+			};
+		};
+
+		eth_sram: sram at 15140000 {
+			compatible = "mmio-sram";
+			reg = <0 0x15140000 0 0x40000>;
+			ranges = <0 0x15140000 0 0x40000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+		};
+
+		wo_ccif0: syscon at 151a5000 {
+			compatible = "mediatek,mt7986-wo-ccif", "syscon";
+			reg = <0 0x151a5000 0 0x1000>;
+			interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
 		wifi at 18000000 {
 			compatible = "mediatek,mt7981-wmac";
 			reg = <0 0x18000000 0 0x1000000>,

-- 
2.51.0



From sjoerd at collabora.com  Tue Dec 23 04:37:55 2025
From: sjoerd at collabora.com (Sjoerd Simons)
Date: Tue, 23 Dec 2025 13:37:55 +0100
Subject: [PATCH v5 5/8] arm64: dts: mediatek: mt7981b-openwrt-one: Enable
 Ethernet
In-Reply-To: <20251223-openwrt-one-network-v5-0-7d1864ea3ad5@collabora.com>
References: <20251223-openwrt-one-network-v5-0-7d1864ea3ad5@collabora.com>
Message-ID: <20251223-openwrt-one-network-v5-5-7d1864ea3ad5@collabora.com>

Enable the Ethernet subsystem on OpenWrt One board with dual-MAC
configuration:
- GMAC0: Connected to external Airoha EN8811H 2.5GbE PHY via SGMII
  (2500base-x mode) for WAN connectivity with LED indicators
- GMAC1: Connected to internal MT7981 1GbE PHY (GMII mode) for LAN

Ethernet aliases are defined to provide consistent network interface
naming (ethernet0 = LAN, ethernet1 = WAN).

Signed-off-by: Sjoerd Simons <sjoerd at collabora.com>
---
V1 -> V2:
  - Switch gmac0 phy irq to Level
  - Update mac nvmem label name
---
 .../boot/dts/mediatek/mt7981b-openwrt-one.dts      | 58 ++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts b/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts
index 7382599cfea2..2aea89900645 100644
--- a/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts
+++ b/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts
@@ -12,6 +12,8 @@ / {
 	model = "OpenWrt One";
 
 	aliases {
+		ethernet0 = &gmac1;
+		ethernet1 = &gmac0;
 		serial0 = &uart0;
 	};
 
@@ -87,6 +89,58 @@ reg_5v: regulator-5v {
 	};
 };
 
+&eth {
+	status = "okay";
+
+	/* WAN interface */
+	gmac0: mac at 0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		nvmem-cells = <&wan_factory_mac 0>;
+		nvmem-cell-names = "mac-address";
+		phy-mode = "2500base-x";
+		phy-handle = <&phy15>;
+	};
+
+	/* LAN interface */
+	gmac1: mac at 1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "gmii";
+		phy-handle = <&int_gbe_phy>;
+	};
+};
+
+&mdio_bus {
+	phy15: ethernet-phy at f {
+		compatible = "ethernet-phy-id03a2.a411";
+		reg = <0xf>;
+		interrupt-parent = <&pio>;
+		interrupts = <38 IRQ_TYPE_LEVEL_LOW>;
+		reset-gpios = <&pio 39 GPIO_ACTIVE_LOW>;
+		reset-assert-us = <10000>;
+		reset-deassert-us = <20000>;
+		airoha,pnswap-rx;
+
+		leds {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			led at 0 {
+				reg = <0>;
+				function = LED_FUNCTION_WAN;
+				color = <LED_COLOR_ID_AMBER>;
+			};
+
+			led at 1 {
+				reg = <1>;
+				function = LED_FUNCTION_WAN;
+				color = <LED_COLOR_ID_GREEN>;
+			};
+		};
+	};
+};
+
 &pcie {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pcie_pins>;
@@ -191,6 +245,10 @@ partition at 180000 {
 	};
 };
 
+&sgmiisys0 {
+	mediatek,pnswap;
+};
+
 &uart0 {
 	status = "okay";
 };

-- 
2.51.0



From sjoerd at collabora.com  Tue Dec 23 04:37:57 2025
From: sjoerd at collabora.com (Sjoerd Simons)
Date: Tue, 23 Dec 2025 13:37:57 +0100
Subject: [PATCH v5 7/8] arm64: dts: mediatek: mt7981b: Add wifi memory
 region
In-Reply-To: <20251223-openwrt-one-network-v5-0-7d1864ea3ad5@collabora.com>
References: <20251223-openwrt-one-network-v5-0-7d1864ea3ad5@collabora.com>
Message-ID: <20251223-openwrt-one-network-v5-7-7d1864ea3ad5@collabora.com>

Add required memory region for the builtin wifi block.

Signed-off-by: Sjoerd Simons <sjoerd at collabora.com>
---
V1 -> V2: Don't set status to in this patch
---
 arch/arm64/boot/dts/mediatek/mt7981b.dtsi | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi
index 1f4c11435466..a7be3670e005 100644
--- a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi
@@ -69,6 +69,11 @@ secmon_reserved: secmon at 43000000 {
 			no-map;
 		};
 
+		wmcpu_emi: wmcpu-reserved at 47c80000 {
+			reg = <0 0x47c80000 0 0x100000>;
+			no-map;
+		};
+
 		wo_emi0: wo-emi at 47d80000 {
 			reg = <0 0x47d80000 0 0x40000>;
 			no-map;
@@ -497,6 +502,7 @@ wifi at 18000000 {
 			clocks = <&topckgen CLK_TOP_NETSYS_MCU_SEL>,
 				 <&topckgen CLK_TOP_AP2CNN_HOST_SEL>;
 			clock-names = "mcu", "ap2conn";
+			memory-region = <&wmcpu_emi>;
 			resets = <&watchdog MT7986_TOPRGU_CONSYS_SW_RST>;
 			reset-names = "consys";
 			status = "disabled";

-- 
2.51.0



From mwalle at kernel.org  Tue Dec 23 04:47:12 2025
From: mwalle at kernel.org (Michael Walle)
Date: Tue, 23 Dec 2025 13:47:12 +0100
Subject: [PATCH v2 0/4] drm/imagination: add AM62P/AM67A/J722S support
Message-ID: <20251223124729.2482877-1-mwalle@kernel.org>

The AM62P and AM67A/J722S feature the same BXS-4 GPU as the J721S2.
In theory, one have to just add the DT node. But it turns out, that
the clock handling is not working. If I understood Nishan Menon
correct, it is working on the J721S2 because there, the clock is
shared, while on the AM62P the GPU has its own PLL.
In the latter case, the driver will fail with a WARN() because the
queried clock rate is zero due to a wrong cached value.

This was tested on the sa67 board which is based on the AM67A SoC.

v2:
 - collect ACKs
 - rebase onto latest -next
 - new patch which enables 800MHz operation for the sa67 board

v1:
 - https://lore.kernel.org/r/20250915143440.2362812-1-mwalle at kernel.org/
 - Don't set the clock to 800MHz in the soc dtsi. 800MHz is only
   possible if the core voltage is 0.85V. Just use the hardware
   default of 720MHz. A board device tree can set the 800MHz if
   applicable. Thanks Nishan.
 - Also add the new compatible to a conditional in the DT schema.
   Thanks Andrew.
 - Dropped the wrong of_clk_set_defaults() and instead disable
   caching of the clock rate.

RFC:
 - https://lore.kernel.org/r/20250716134717.4085567-1-mwalle at kernel.org/

Michael Walle (4):
  dt-bindings: gpu: img: Add AM62P SoC specific compatible
  clk: keystone: don't cache clock rate
  arm64: dts: ti: add GPU node
  arm64: dts: ti: sa67: set the GPU clock to 800MHz

 .../devicetree/bindings/gpu/img,powervr-rogue.yaml    |  2 ++
 .../arm64/boot/dts/ti/k3-am62p-j722s-common-main.dtsi | 11 +++++++++++
 arch/arm64/boot/dts/ti/k3-am67a-kontron-sa67-base.dts |  6 ++++++
 drivers/clk/keystone/sci-clk.c                        |  8 ++++++++
 4 files changed, 27 insertions(+)

-- 
2.47.3



From mwalle at kernel.org  Tue Dec 23 04:47:13 2025
From: mwalle at kernel.org (Michael Walle)
Date: Tue, 23 Dec 2025 13:47:13 +0100
Subject: [PATCH v2 1/4] dt-bindings: gpu: img: Add AM62P SoC specific compatible
In-Reply-To: <20251223124729.2482877-1-mwalle@kernel.org>
References: <20251223124729.2482877-1-mwalle@kernel.org>
Message-ID: <20251223124729.2482877-2-mwalle@kernel.org>

The AM62P and the J722S features the same BXS-4 GPU as the J721S2. Add a
new SoC specific compatible.

Signed-off-by: Michael Walle <mwalle at kernel.org>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
 Documentation/devicetree/bindings/gpu/img,powervr-rogue.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/gpu/img,powervr-rogue.yaml b/Documentation/devicetree/bindings/gpu/img,powervr-rogue.yaml
index 86ef68985317..a1f54dbae3f3 100644
--- a/Documentation/devicetree/bindings/gpu/img,powervr-rogue.yaml
+++ b/Documentation/devicetree/bindings/gpu/img,powervr-rogue.yaml
@@ -40,6 +40,7 @@ properties:
           - const: img,img-rogue
       - items:
           - enum:
+              - ti,am62p-gpu
               - ti,j721s2-gpu
           - const: img,img-bxs-4-64
           - const: img,img-rogue
@@ -100,6 +101,7 @@ allOf:
           contains:
             enum:
               - ti,am62-gpu
+              - ti,am62p-gpu
               - ti,j721s2-gpu
     then:
       properties:
-- 
2.47.3



From mwalle at kernel.org  Tue Dec 23 04:47:14 2025
From: mwalle at kernel.org (Michael Walle)
Date: Tue, 23 Dec 2025 13:47:14 +0100
Subject: [PATCH v2 2/4] clk: keystone: don't cache clock rate
In-Reply-To: <20251223124729.2482877-1-mwalle@kernel.org>
References: <20251223124729.2482877-1-mwalle@kernel.org>
Message-ID: <20251223124729.2482877-3-mwalle@kernel.org>

The TISCI firmware will return 0 if the clock or consumer is not
enabled although there is a stored value in the firmware. IOW a call to
set rate will work but at get rate will always return 0 if the clock is
disabled.
The clk framework will try to cache the clock rate when it's requested
by a consumer. If the clock or consumer is not enabled at that point,
the cached value is 0, which is wrong. Thus, disable the cache
altogether.

Signed-off-by: Michael Walle <mwalle at kernel.org>
Reviewed-by: Kevin Hilman <khilman at baylibre.com>
Reviewed-by: Randolph Sapp <rs at ti.com>
---
 drivers/clk/keystone/sci-clk.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/clk/keystone/sci-clk.c b/drivers/clk/keystone/sci-clk.c
index 9d5071223f4c..0a1565fdbb3b 100644
--- a/drivers/clk/keystone/sci-clk.c
+++ b/drivers/clk/keystone/sci-clk.c
@@ -333,6 +333,14 @@ static int _sci_clk_build(struct sci_clk_provider *provider,
 
 	init.ops = &sci_clk_ops;
 	init.num_parents = sci_clk->num_parents;
+
+	/*
+	 * A clock rate query to the SCI firmware will return 0 if either the
+	 * clock itself is disabled or the attached device/consumer is disabled.
+	 * This makes it inherently unsuitable for the caching of the clk
+	 * framework.
+	 */
+	init.flags = CLK_GET_RATE_NOCACHE;
 	sci_clk->hw.init = &init;
 
 	ret = devm_clk_hw_register(provider->dev, &sci_clk->hw);
-- 
2.47.3



From mwalle at kernel.org  Tue Dec 23 04:47:15 2025
From: mwalle at kernel.org (Michael Walle)
Date: Tue, 23 Dec 2025 13:47:15 +0100
Subject: [PATCH v2 3/4] arm64: dts: ti: add GPU node
In-Reply-To: <20251223124729.2482877-1-mwalle@kernel.org>
References: <20251223124729.2482877-1-mwalle@kernel.org>
Message-ID: <20251223124729.2482877-4-mwalle@kernel.org>

The J722S features a BXS-4 GPU. Add the node for it.

Signed-off-by: Michael Walle <mwalle at kernel.org>
---
 .../arm64/boot/dts/ti/k3-am62p-j722s-common-main.dtsi | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm64/boot/dts/ti/k3-am62p-j722s-common-main.dtsi b/arch/arm64/boot/dts/ti/k3-am62p-j722s-common-main.dtsi
index 3cf7c2b3ce2d..a55e5108e7b6 100644
--- a/arch/arm64/boot/dts/ti/k3-am62p-j722s-common-main.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am62p-j722s-common-main.dtsi
@@ -1110,6 +1110,17 @@ dphy0: phy at 30110000 {
 		status = "disabled";
 	};
 
+	gpu: gpu at fd80000 {
+		compatible = "ti,am62p-gpu", "img,img-bxs-4-64", "img,img-rogue";
+		reg = <0x00 0x0fd80000 0x00 0x80000>;
+		clocks = <&k3_clks 237 3>;
+		clock-names = "core";
+		interrupts = <GIC_SPI 241 IRQ_TYPE_LEVEL_HIGH>;
+		power-domains = <&k3_pds 237 TI_SCI_PD_EXCLUSIVE>,
+				<&k3_pds 242 TI_SCI_PD_EXCLUSIVE>;
+		power-domain-names = "a", "b";
+	};
+
 	vpu: video-codec at 30210000 {
 		compatible = "ti,j721s2-wave521c", "cnm,wave521c";
 		reg = <0x00 0x30210000 0x00 0x10000>;
-- 
2.47.3



From mwalle at kernel.org  Tue Dec 23 04:47:16 2025
From: mwalle at kernel.org (Michael Walle)
Date: Tue, 23 Dec 2025 13:47:16 +0100
Subject: [PATCH v2 4/4] arm64: dts: ti: sa67: set the GPU clock to 800MHz
In-Reply-To: <20251223124729.2482877-1-mwalle@kernel.org>
References: <20251223124729.2482877-1-mwalle@kernel.org>
Message-ID: <20251223124729.2482877-5-mwalle@kernel.org>

The board is running with a core voltage of 0.85V and therefore we can
clock the GPU at 800MHz.

Signed-off-by: Michael Walle <mwalle at kernel.org>
---
 arch/arm64/boot/dts/ti/k3-am67a-kontron-sa67-base.dts | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm64/boot/dts/ti/k3-am67a-kontron-sa67-base.dts b/arch/arm64/boot/dts/ti/k3-am67a-kontron-sa67-base.dts
index 7169d934adac..0c7f3e10a150 100644
--- a/arch/arm64/boot/dts/ti/k3-am67a-kontron-sa67-base.dts
+++ b/arch/arm64/boot/dts/ti/k3-am67a-kontron-sa67-base.dts
@@ -292,6 +292,12 @@ &cpsw_port1 {
 	status = "okay";
 };
 
+&gpu {
+	/* The VCORE is 0.85V, thus we can use a faster GPU clock. */
+	assigned-clocks = <&k3_clks 237 3>;
+	assigned-clock-rates = <800000000>;
+};
+
 &main_gpio0 {
 	gpio-line-names =
 		"", "", "", "", "", "", "", "SOC_SDIO_PWR_EN", "VSD_SEL",
-- 
2.47.3



From julia.lawall at inria.fr  Tue Dec 23 05:05:47 2025
From: julia.lawall at inria.fr (Julia Lawall)
Date: Tue, 23 Dec 2025 14:05:47 +0100 (CET)
Subject: [arm-platforms:kvm-arm64/gicv5-full 80/82] arch/arm64/kvm/vgic/vgic-its-v5.c:1213:2-8:
 preceding lock on line 1181 (fwd)
Message-ID: <15556f41-78ab-7418-f686-4d796a3ecf38@inria.fr>

Pleas check whether unlocks are needed at line 1213.

julia

---------- Forwarded message ----------
Date: Tue, 23 Dec 2025 20:39:59 +0800
From: kernel test robot <lkp at intel.com>
To: oe-kbuild at lists.linux.dev
Cc: lkp at intel.com, Julia Lawall <julia.lawall at inria.fr>
Subject: [arm-platforms:kvm-arm64/gicv5-full 80/82]
    arch/arm64/kvm/vgic/vgic-its-v5.c:1213:2-8: preceding lock on line 1181

BCC: lkp at intel.com
CC: oe-kbuild-all at lists.linux.dev
CC: linux-arm-kernel at lists.infradead.org
TO: Sascha Bischoff <sascha.bischoff at arm.com>

tree:   https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git kvm-arm64/gicv5-full
head:   1426b88096b597395df4c82f089b87c62bab45da
commit: e01f1868ec7bf5d212cd8daf67da77fc8c1cd320 [80/82] KVM: arm64: gic-v5: Implement has/set/get attr for ITS MMIO regions
:::::: branch date: 4 days ago
:::::: commit date: 4 days ago
config: arm64-randconfig-r064-20251223 (https://download.01.org/0day-ci/archive/20251223/202512232029.FJOH3tvX-lkp at intel.com/config)
compiler: aarch64-linux-gcc (GCC) 15.1.0

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Reported-by: Julia Lawall <julia.lawall at inria.fr>
| Closes: https://lore.kernel.org/r/202512232029.FJOH3tvX-lkp at intel.com/

cocci warnings: (new ones prefixed by >>)
>> arch/arm64/kvm/vgic/vgic-its-v5.c:1213:2-8: preceding lock on line 1181
   arch/arm64/kvm/vgic/vgic-its-v5.c:1213:2-8: preceding lock on line 1188

vim +1213 arch/arm64/kvm/vgic/vgic-its-v5.c

e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1167
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1168  static int vgic_v5_its_attr_regs_access(struct kvm_device *dev,
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1169  				 struct kvm_device_attr *attr,
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1170  				 u64 *reg, bool is_write)
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1171  {
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1172  	const struct vgic_register_region *region;
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1173  	struct vgic_v5_its *its;
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1174  	gpa_t addr, offset;
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1175  	unsigned int len;
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1176  	int align, ret = 0;
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1177
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1178  	its = dev->private;
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1179  	offset = attr->attr;
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1180
e01f1868ec7bf5 Sascha Bischoff 2025-09-05 @1181  	mutex_lock(&dev->kvm->lock);
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1182
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1183  	if (kvm_trylock_all_vcpus(dev->kvm)) {
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1184  		mutex_unlock(&dev->kvm->lock);
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1185  		return -EBUSY;
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1186  	}
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1187
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1188  	mutex_lock(&dev->kvm->arch.config_lock);
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1189
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1190  	if (IS_VGIC_ADDR_UNDEF(its->vgic_v5_its_base)) {
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1191  		ret = -ENXIO;
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1192  		goto out;
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1193  	}
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1194
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1195  	region = vgic_find_mmio_region(vgic_v5_its_registers,
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1196  				       ARRAY_SIZE(vgic_v5_its_registers),
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1197  				       offset);
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1198  	if (!region) {
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1199  		ret = -ENXIO;
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1200  		goto out;
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1201  	}
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1202
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1203  	/*
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1204  	 * Although the spec supports upper/lower 32-bit accesses to
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1205  	 * 64-bit ITS registers, the userspace ABI requires 64-bit
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1206  	 * accesses to all 64-bit wide registers. We therefore only
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1207  	 * support 32-bit accesses to 32-bit-wide registers.
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1208  	 */
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1209  	align = region->access_flags & VGIC_ACCESS_64bit ? 0x7 : 0x3;
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1210  	len = region->access_flags & VGIC_ACCESS_64bit ? 8 : 4;
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1211
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1212  	if (offset & align)
e01f1868ec7bf5 Sascha Bischoff 2025-09-05 @1213  		return -EINVAL;
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1214
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1215  	addr = its->vgic_v5_its_base + offset;
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1216
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1217  	if (is_write) {
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1218  		region->its_write(dev->kvm, its, addr, len, *reg);
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1219  	} else {
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1220  		*reg = region->its_read(dev->kvm, its, addr, len);
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1221  	}
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1222  out:
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1223  	mutex_unlock(&dev->kvm->arch.config_lock);
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1224  	kvm_unlock_all_vcpus(dev->kvm);
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1225  	mutex_unlock(&dev->kvm->lock);
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1226
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1227  	return ret;
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1228  }
e01f1868ec7bf5 Sascha Bischoff 2025-09-05  1229

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From krzk at kernel.org  Tue Dec 23 05:32:24 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 14:32:24 +0100
Subject: [PATCH v2 1/5] dt-bindings: mfd: maxim,max77759: add charger
 child node
In-Reply-To: <411802b6-517d-497e-bf7b-183e6e6d7a64@kernel.org>
References: <20251218-max77759-charger-v2-0-2b259980a686@google.com>
 <20251218-max77759-charger-v2-1-2b259980a686@google.com>
 <411802b6-517d-497e-bf7b-183e6e6d7a64@kernel.org>
Message-ID: <3d156c45-b55d-4ca4-95d6-0d06e067bbdb@kernel.org>

On 19/12/2025 09:17, Krzysztof Kozlowski wrote:
> On 18/12/2025 23:49, Amit Sunil Dhamne via B4 Relay wrote:
>> From: Amit Sunil Dhamne <amitsd at google.com>
>>
>> The Maxim MAX77759 MFD includes a charger function. Extend the max77759
>> binding to include the charger. Also, update the example to include
>> charger.
>>
>> Signed-off-by: Amit Sunil Dhamne <amitsd at google.com>
>> ---
>>  .../devicetree/bindings/mfd/maxim,max77759.yaml    | 33 ++++++++++++++++++++++
>>  1 file changed, 33 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml b/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml
>> index 525de9ab3c2b..1cffdf2e5776 100644
>> --- a/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml
>> +++ b/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml
>> @@ -37,6 +37,30 @@ properties:
>>    nvmem-0:
>>      $ref: /schemas/nvmem/maxim,max77759-nvmem.yaml
>>  
>> +  charger:
>> +    type: object
>> +    description: This is a dual input switch mode battery charger for portable
>> +      applications. It supports wired and wireless charging and can operate in
>> +      buck and boost mode.
>> +
> 
> 
> I do not see any improvements, so same comment: this should be folded
> into the parent.
> 
> Please read DTS 101 slides or writing bindings or any other talks...
> 

No responses to my emails for a few days, so I assume discussion is done
and I mark it as changes requested in patchwork.

Best regards,
Krzysztof


From krzk at kernel.org  Tue Dec 23 05:40:31 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 14:40:31 +0100
Subject: [PATCH v6] dt-bindings: arm: keystone: add boot_* mboxes to
 ti,sci
In-Reply-To: <DF5GPF5U7NPA.2ODE22YOF8E1R@ti.com>
References: <20251222-k3_syscon_add_boot_mailboxes-v6-1-b93ada9f1d47@ti.com>
 <1844147d-543d-4739-a1ec-a59f8a4564fb@kernel.org>
 <DF5GPF5U7NPA.2ODE22YOF8E1R@ti.com>
Message-ID: <e516b73b-2dc3-4ae4-966b-278a946491c8@kernel.org>

On 23/12/2025 09:44, Anshul Dalal wrote:
> On Mon Dec 22, 2025 at 2:23 PM IST, Krzysztof Kozlowski wrote:
>> On 22/12/2025 09:43, Anshul Dalal wrote:
>>> The bootloader on K3 devices makes use of mailboxes as per the ROM spec
>>> which might be different than one's available to the kernel (firmware
>>> spec).
>>>
>>> Therefore, this patch adds the missing mailbox entries to the DT binding
>>> if the matching compatible is ti,am654-sci to represent the mailboxes
>>> exposed by the hardware during boot for the purpose of loading the
>>> firmware.
>>>
>>> The new ti,am642-sci compatible is also added to represent SoCs which do
>>> not expose a "notify" channel as part of their TI-SCI spec such as AM64x
>>> or the AM62 family. The newly added mboxes are made optional by keeping
>>> minItems as 2 to remain compliant with existing device-trees.
>>>
>>> Signed-off-by: Anshul Dalal <anshuld at ti.com>
>>> ---
>>> Changes in v6:
>>> - Added ti,am642-sci compatible to represent SoCs without a "notify" channel
>>> - Added new examples instead of editing existing ones
>>
>> Why? Rob asked not to.
> 
> I had followed what Nishanth had said[1], I'll wait for him and Rob to
> align first before posting the next revision.


Existing examples are fine. There is no rule saying you need to keep
updating examples or keep adding new device to examples. If someone told
you about such rule, tell them to stop inventing rules...

Best regards,
Krzysztof


From mikko.rapeli at linaro.org  Tue Dec 23 05:48:07 2025
From: mikko.rapeli at linaro.org (Mikko Rapeli)
Date: Tue, 23 Dec 2025 15:48:07 +0200
Subject: [PATCH] arm64: defconfig: remove SLIM_QCOM_CTRL
Message-ID: <20251223134807.3543642-1-mikko.rapeli@linaro.org>

It has been removed by:

Fixes: 7cbba32a2d62 ("slimbus: qcom: remove unused qcom controller driver")

Signed-off-by: Mikko Rapeli <mikko.rapeli at linaro.org>
---
 arch/arm64/configs/defconfig | 1 -
 1 file changed, 1 deletion(-)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 997fa7cd9de5..4dc0caa36263 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -1709,7 +1709,6 @@ CONFIG_OPTEE=y
 CONFIG_MUX_GPIO=m
 CONFIG_MUX_MMIO=y
 CONFIG_SLIMBUS=m
-CONFIG_SLIM_QCOM_CTRL=m
 CONFIG_SLIM_QCOM_NGD_CTRL=m
 CONFIG_INTERCONNECT=y
 CONFIG_INTERCONNECT_IMX=y
-- 
2.34.1



From krzk at kernel.org  Tue Dec 23 05:51:45 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 14:51:45 +0100
Subject: [PATCH] arm64: defconfig: remove SLIM_QCOM_CTRL
In-Reply-To: <20251223134807.3543642-1-mikko.rapeli@linaro.org>
References: <20251223134807.3543642-1-mikko.rapeli@linaro.org>
Message-ID: <c06878f7-bb93-4de2-b54a-e97fbc1a333e@kernel.org>

On 23/12/2025 14:48, Mikko Rapeli wrote:
> It has been removed by:

by commit foo bar (see also checkpatch and submitting patches).

> 
> Fixes: 7cbba32a2d62 ("slimbus: qcom: remove unused qcom controller driver")
> 

Drop blank line

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

You anyway need to send to proper mailing list for this soc (Qcom), not
random folks.

Best regards,
Krzysztof


From krzk at kernel.org  Tue Dec 23 05:54:13 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 14:54:13 +0100
Subject: [PATCH 1/2] dt-bindings: arm: aspeed: add Meta ventura2 board
In-Reply-To: <20251222-ventura2_initial_dts-v1-1-1f06166c78a3@gmail.com>
References: <20251222-ventura2_initial_dts-v1-0-1f06166c78a3@gmail.com>
 <20251222-ventura2_initial_dts-v1-1-1f06166c78a3@gmail.com>
Message-ID: <20251223-ginger-worm-of-swiftness-a8fa05@quoll>

On Mon, Dec 22, 2025 at 03:45:43PM +0800, Kyle Hsieh wrote:
> Document the new compatibles used on Facebook ventura2.
> 
> Signed-off-by: Kyle Hsieh <kylehsieh1995 at gmail.com>
> ---
>  Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml | 1 +
>  1 file changed, 1 insertion(+)

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof



From mikko.rapeli at linaro.org  Tue Dec 23 05:58:44 2025
From: mikko.rapeli at linaro.org (Mikko Rapeli)
Date: Tue, 23 Dec 2025 15:58:44 +0200
Subject: [PATCH] arm64: defconfig: remove SLIM_QCOM_CTRL
In-Reply-To: <c06878f7-bb93-4de2-b54a-e97fbc1a333e@kernel.org>
References: <20251223134807.3543642-1-mikko.rapeli@linaro.org>
 <c06878f7-bb93-4de2-b54a-e97fbc1a333e@kernel.org>
Message-ID: <aUqgFCgmBy7H9yW0@nuoska>

Hi,

On Tue, Dec 23, 2025 at 02:51:45PM +0100, Krzysztof Kozlowski wrote:
> On 23/12/2025 14:48, Mikko Rapeli wrote:
> > It has been removed by:
> 
> by commit foo bar (see also checkpatch and submitting patches).

Ok will duplicate the info then.

> > 
> > Fixes: 7cbba32a2d62 ("slimbus: qcom: remove unused qcom controller driver")
> > 
> 
> Drop blank line

Ok
 
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
> 
> You anyway need to send to proper mailing list for this soc (Qcom), not
> random folks.

Which proper list?

I sent to addresses reported by get_maintainers.pl.

Cheers,

-Mikko


From amadeus at jmu.edu.cn  Tue Dec 23 06:00:16 2025
From: amadeus at jmu.edu.cn (Chukun Pan)
Date: Tue, 23 Dec 2025 22:00:16 +0800
Subject: [PATCH 1/1] wifi: mt76: mt7996: fix mixed FEM check of mt7996 chipset
In-Reply-To: <87fr96tp7w.fsf@miraculix.mork.no>
References: <87fr96tp7w.fsf@miraculix.mork.no>
Message-ID: <20251223140016.235771-1-amadeus@jmu.edu.cn>

Hi,

> The problem is that the patch breaks the other device variant, which
> used to work before.  If we assume the eeprom data from Zyxel is
> correct, then this variant is iFEM.

Do you have the specific model name and what the RF chips are?
The eeprom seems to be fine.

Thanks,
Chukun


From claudiu.beznea at tuxon.dev  Tue Dec 23 06:00:49 2025
From: claudiu.beznea at tuxon.dev (claudiu beznea)
Date: Tue, 23 Dec 2025 16:00:49 +0200
Subject: [PATCH v4 11/31] clk: at91: clk-usb: add support for
 clk_parent_data
In-Reply-To: <14ea374c-2889-4bc5-b0c9-fb5b5498593e@microchip.com>
References: <cover.1758226719.git.Ryan.Wanner@microchip.com>
 <6979b3734462c97381159f3968a3f22b6193e04d.1758226719.git.Ryan.Wanner@microchip.com>
 <27aab227-01e3-4074-8aab-38623b4d9808@tuxon.dev>
 <14ea374c-2889-4bc5-b0c9-fb5b5498593e@microchip.com>
Message-ID: <cb19cd94-7f81-4f75-a7db-bf25192986ed@tuxon.dev>



On 12/18/25 18:23, Ryan.Wanner at microchip.com wrote:
> On 10/20/25 12:17, Claudiu Beznea wrote:
>> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
>>
>> Hi, Ryan,
>>
>> On 9/19/25 00:15, Ryan.Wanner at microchip.com wrote:
>>> From: Claudiu Beznea <claudiu.beznea at tuxon.dev>
>>>
>>> Add support for clk_parent_data in usb clock driver.
>>>
>>> All the SoC based drivers that rely on clk-usb were adapted
>>> to the new API change. The switch itself for SoCs will be done
>>> in subsequent patches.
>>>
>>> Remove the use of __clk_get_hw() for the slow clocks.
>>>
>>> Signed-off-by: Claudiu Beznea <claudiu.beznea at tuxon.dev>
>>> [ryan.wanner at microchip: Add SAMA7D65 and SAM9X75 SoCs to the changes.
>>> Change how the main_xtal and slcks are initialized so they match the
>>> parent_data API]
>>> Signed-off-by: Ryan Wanner <Ryan.Wanner at microchip.com>
>>> ---
>>>   drivers/clk/at91/at91rm9200.c  |  2 +-
>>>   drivers/clk/at91/at91sam9260.c |  2 +-
>>>   drivers/clk/at91/at91sam9g45.c |  2 +-
>>>   drivers/clk/at91/at91sam9n12.c |  2 +-
>>>   drivers/clk/at91/at91sam9x5.c  |  2 +-
>>>   drivers/clk/at91/clk-usb.c     | 41 ++++++++++++++++++++++------------
>>>   drivers/clk/at91/dt-compat.c   |  6 ++---
>>>   drivers/clk/at91/pmc.h         | 11 +++++----
>>>   drivers/clk/at91/sam9x60.c     |  2 +-
>>>   drivers/clk/at91/sam9x7.c      | 21 +++++++++--------
>>>   drivers/clk/at91/sama5d2.c     |  2 +-
>>>   drivers/clk/at91/sama5d3.c     |  2 +-
>>>   drivers/clk/at91/sama5d4.c     |  2 +-
>>>   drivers/clk/at91/sama7d65.c    | 24 +++++++++++---------
>>>   14 files changed, 72 insertions(+), 49 deletions(-)
>>>
>>
>> [ ... ]
>>
>>> @@ -882,10 +885,10 @@ static void __init sam9x7_pmc_setup(struct device_node *np)
>>>
>>>        sam9x7_pmc->chws[PMC_MCK] = hw;
>>>
>>> -     parent_names[0] = "plla_divpmcck";
>>> -     parent_names[1] = "upll_divpmcck";
>>> -     parent_names[2] = "main_osc";
>>> -     usbck_hw = sam9x60_clk_register_usb(regmap, "usbck", parent_names, 3);
>>> +     parent_data[0] = AT91_CLK_PD_HW(sam9x7_plls[PLL_ID_PLLA][PLL_COMPID_DIV0].hw);
>>> +     parent_data[1] = AT91_CLK_PD_HW(sam9x7_plls[PLL_ID_UPLL][PLL_COMPID_DIV0].hw);
>>> +     parent_data[2] = AT91_CLK_PD_HW(main_osc_hw);
>>> +     usbck_hw = sam9x60_clk_register_usb(regmap, "usbck", NULL, parent_data, 3);
>>
>> sam9x60_clk_register_usb() could be converted to use parent_hws member of
>> struct clk_init_data instead of parent_data.
> 
> So this would mean that I would pass in an array of the plls as
> parent_hws, and use that to load the clk_init_data struct instead of
> filling the array of parent_data as it is changed to in this patch set?
> 
> And this would be functionally the same since parent_data points to
> clk_hw?>
> 

It should be something like:

  	usb = kzalloc(sizeof(*usb), GFP_KERNEL);
@@ -235,7 +235,10 @@ _at91sam9x5_clk_register_usb(struct regmap *regmap, const 
char *name, const clk_hw **parent_hws)

  	init.name = name;
  	init.ops = &at91sam9x5_usb_ops;
-	init.parent_names = parent_names;
+	if (parent_hws)
+		init.parent_hws = parent_hws;
+	else
+		init.parent_names = parent_names;

Thank you,
Claudiu


From vkoul at kernel.org  Tue Dec 23 06:04:29 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 23 Dec 2025 19:34:29 +0530
Subject: [PATCH v9 2/2] phy: Add Google Tensor SoC USB PHY driver
In-Reply-To: <20251222-phyb4-v9-2-82c0b671b070@google.com>
References: <20251222-phyb4-v9-0-82c0b671b070@google.com>
 <20251222-phyb4-v9-2-82c0b671b070@google.com>
Message-ID: <aUqhbVFHczpL9qnL@vaman>

On 22-12-25, 21:31, Roy Luo wrote:
> Support the USB PHY found on Google Tensor G5 (Laguna). This
> particular USB PHY supports both high-speed and super-speed
> operations, and is integrated with the SNPS DWC3 controller that's
> also on the SoC. This initial patch specifically adds functionality
> for high-speed.
> 
> Co-developed-by: Joy Chakraborty <joychakr at google.com>
> Signed-off-by: Joy Chakraborty <joychakr at google.com>
> Co-developed-by: Naveen Kumar <mnkumar at google.com>
> Signed-off-by: Naveen Kumar <mnkumar at google.com>
> Signed-off-by: Roy Luo <royluo at google.com>
> ---
>  MAINTAINERS                  |   1 +
>  drivers/phy/Kconfig          |  10 ++
>  drivers/phy/Makefile         |   1 +
>  drivers/phy/phy-google-usb.c | 295 +++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 307 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 8a2e94be2f5c5e6e7315bb7bec385798dbd52493..afd0d7484ffe5fa652798c9b3c86ae6d83302382 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -10725,6 +10725,7 @@ F:	Documentation/devicetree/bindings/phy/google,lga-usb-phy.yaml
>  F:	Documentation/devicetree/bindings/soc/google/google,gs101-pmu-intr-gen.yaml
>  F:	arch/arm64/boot/dts/exynos/google/
>  F:	drivers/clk/samsung/clk-gs101.c
> +F:	drivers/phy/phy-google-usb.c
>  F:	drivers/soc/samsung/gs101-pmu.c
>  F:	drivers/phy/samsung/phy-gs101-ufs.c
>  F:	include/dt-bindings/clock/google,gs101*
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index 678dd0452f0aa0597773433f04d2a9ba77474d2a..5a642e04caeeea9d40ac583767622cff2ef5e80c 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -101,6 +101,16 @@ config PHY_NXP_PTN3222
>  	  schemes. It supports all three USB 2.0 data rates: Low Speed, Full
>  	  Speed and High Speed.
>  
> +config PHY_GOOGLE_USB

This does not seem sorted!

> +	tristate "Google Tensor SoC USB PHY driver"
> +	select GENERIC_PHY
> +	help
> +	  Enable support for the USB PHY on Google Tensor SoCs, starting with
> +	  the G5 generation (Laguna). This driver provides the PHY interfaces
> +	  to interact with the SNPS eUSB2 and USB 3.2/DisplayPort Combo PHY,
> +	  both of which are integrated with the DWC3 USB DRD controller.
> +	  This driver currently supports USB high-speed.
> +
>  source "drivers/phy/allwinner/Kconfig"
>  source "drivers/phy/amlogic/Kconfig"
>  source "drivers/phy/broadcom/Kconfig"
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index bfb27fb5a494283d7fd05dd670ebd1b12df8b1a1..aeaaaf988554a24bb572d8b34b54638a6a3aed73 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -13,6 +13,7 @@ obj-$(CONFIG_PHY_SNPS_EUSB2)		+= phy-snps-eusb2.o
>  obj-$(CONFIG_USB_LGM_PHY)		+= phy-lgm-usb.o
>  obj-$(CONFIG_PHY_AIROHA_PCIE)		+= phy-airoha-pcie.o
>  obj-$(CONFIG_PHY_NXP_PTN3222)		+= phy-nxp-ptn3222.o
> +obj-$(CONFIG_PHY_GOOGLE_USB)		+= phy-google-usb.o

and here!

>  obj-y					+= allwinner/	\
>  					   amlogic/	\
>  					   broadcom/	\
> diff --git a/drivers/phy/phy-google-usb.c b/drivers/phy/phy-google-usb.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..97e345fdab9b3679e7a76f6957ae3814ef3420e8
> --- /dev/null
> +++ b/drivers/phy/phy-google-usb.c
> @@ -0,0 +1,295 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * phy-google-usb.c - Google USB PHY driver
> + *
> + * Copyright (C) 2025, Google LLC
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/cleanup.h>
> +#include <linux/clk.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/reset.h>
> +#include <linux/usb/typec_mux.h>
> +
> +#define USBCS_USB2PHY_CFG19_OFFSET 0x0
> +#define USBCS_USB2PHY_CFG19_PHY_CFG_PLL_FB_DIV GENMASK(19, 8)
> +
> +#define USBCS_USB2PHY_CFG21_OFFSET 0x8
> +#define USBCS_USB2PHY_CFG21_PHY_ENABLE BIT(12)
> +#define USBCS_USB2PHY_CFG21_REF_FREQ_SEL GENMASK(15, 13)
> +#define USBCS_USB2PHY_CFG21_PHY_TX_DIG_BYPASS_SEL BIT(19)
> +
> +#define USBCS_PHY_CFG1_OFFSET 0x28
> +#define USBCS_PHY_CFG1_SYS_VBUSVALID BIT(17)
> +
> +enum google_usb_phy_id {
> +	GOOGLE_USB2_PHY,
> +	GOOGLE_USB_PHY_NUM,
> +};
> +
> +struct google_usb_phy_instance {
> +	int index;

maybe use unsigned?

> +	struct phy *phy;
> +	int num_clks;

here too?

> +	struct clk_bulk_data *clks;
 +	int num_rsts;

and here?

> +	struct reset_control_bulk_data *rsts;
> +};
> +
> +struct google_usb_phy {
> +	struct device *dev;
> +	struct regmap *usb_cfg_regmap;
> +	unsigned int usb2_cfg_offset;
> +	void __iomem *usbdp_top_base;
> +	struct google_usb_phy_instance insts[GOOGLE_USB_PHY_NUM];

so you have an array for one phy?

> +	/*
> +	 * Protect phy registers from concurrent access, specifically via
> +	 * google_usb_set_orientation callback.
> +	 */
> +	struct mutex phy_mutex;
> +	struct typec_switch_dev *sw;
> +	enum typec_orientation orientation;
> +};
> +
> +static inline struct google_usb_phy *to_google_usb_phy(struct google_usb_phy_instance *inst)
> +{
> +	return container_of(inst, struct google_usb_phy, insts[inst->index]);
> +}
> +
> +static void set_vbus_valid(struct google_usb_phy *gphy)
> +{
> +	u32 reg;
> +
> +	if (gphy->orientation == TYPEC_ORIENTATION_NONE) {
> +		reg = readl(gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
> +		reg &= ~USBCS_PHY_CFG1_SYS_VBUSVALID;
> +		writel(reg, gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
> +	} else {
> +		reg = readl(gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
> +		reg |= USBCS_PHY_CFG1_SYS_VBUSVALID;
> +		writel(reg, gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
> +	}
> +}
> +
> +static int google_usb_set_orientation(struct typec_switch_dev *sw,
> +				      enum typec_orientation orientation)
> +{
> +	struct google_usb_phy *gphy = typec_switch_get_drvdata(sw);
> +
> +	dev_dbg(gphy->dev, "set orientation %d\n", orientation);
> +
> +	gphy->orientation = orientation;
> +
> +	if (pm_runtime_suspended(gphy->dev))
> +		return 0;
> +
> +	guard(mutex)(&gphy->phy_mutex);
> +
> +	set_vbus_valid(gphy);
> +
> +	return 0;
> +}
> +
> +static int google_usb2_phy_init(struct phy *_phy)
> +{
> +	struct google_usb_phy_instance *inst = phy_get_drvdata(_phy);
> +	struct google_usb_phy *gphy = to_google_usb_phy(inst);
> +	u32 reg;
> +	int ret = 0;

superfluous init

> +
> +	dev_dbg(gphy->dev, "initializing usb2 phy\n");
> +
> +	guard(mutex)(&gphy->phy_mutex);
> +
> +	regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, &reg);
> +	reg &= ~USBCS_USB2PHY_CFG21_PHY_TX_DIG_BYPASS_SEL;
> +	reg &= ~USBCS_USB2PHY_CFG21_REF_FREQ_SEL;
> +	reg |= FIELD_PREP(USBCS_USB2PHY_CFG21_REF_FREQ_SEL, 0);
> +	regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, reg);
> +
> +	regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG19_OFFSET, &reg);
> +	reg &= ~USBCS_USB2PHY_CFG19_PHY_CFG_PLL_FB_DIV;
> +	reg |= FIELD_PREP(USBCS_USB2PHY_CFG19_PHY_CFG_PLL_FB_DIV, 368);
> +	regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG19_OFFSET, reg);
> +
> +	set_vbus_valid(gphy);
> +
> +	ret = clk_bulk_prepare_enable(inst->num_clks, inst->clks);
> +	if (ret)
> +		return ret;
> +
> +	ret = reset_control_bulk_deassert(inst->num_rsts, inst->rsts);
> +	if (ret) {
> +		clk_bulk_disable_unprepare(inst->num_clks, inst->clks);
> +		return ret;
> +	}
> +
> +	regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, &reg);
> +	reg |= USBCS_USB2PHY_CFG21_PHY_ENABLE;
> +	regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, reg);
> +
> +	return ret;

would it not be return 0 here? can it be any other value

> +}
> +
> +static int google_usb2_phy_exit(struct phy *_phy)
> +{
> +	struct google_usb_phy_instance *inst = phy_get_drvdata(_phy);
> +	struct google_usb_phy *gphy = to_google_usb_phy(inst);
> +	u32 reg;
> +
> +	dev_dbg(gphy->dev, "exiting usb2 phy\n");
> +
> +	guard(mutex)(&gphy->phy_mutex);
> +
> +	regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, &reg);
> +	reg &= ~USBCS_USB2PHY_CFG21_PHY_ENABLE;
> +	regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, reg);
> +
> +	reset_control_bulk_assert(inst->num_rsts, inst->rsts);
> +	clk_bulk_disable_unprepare(inst->num_clks, inst->clks);
> +
> +	return 0;
> +}
> +
> +static const struct phy_ops google_usb2_phy_ops = {
> +	.init		= google_usb2_phy_init,
> +	.exit		= google_usb2_phy_exit,
> +};

Only two ops? I would expect more... No power_on/off or set_mode?

-- 
~Vinod


From krzk at kernel.org  Tue Dec 23 06:10:56 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 15:10:56 +0100
Subject: [PATCH] arm64: defconfig: remove SLIM_QCOM_CTRL
In-Reply-To: <aUqgFCgmBy7H9yW0@nuoska>
References: <20251223134807.3543642-1-mikko.rapeli@linaro.org>
 <c06878f7-bb93-4de2-b54a-e97fbc1a333e@kernel.org> <aUqgFCgmBy7H9yW0@nuoska>
Message-ID: <4f99f3ba-ef5b-4163-ad1a-99527dd96f8a@kernel.org>

On 23/12/2025 14:58, Mikko Rapeli wrote:
> Hi,
> 
> On Tue, Dec 23, 2025 at 02:51:45PM +0100, Krzysztof Kozlowski wrote:
>> On 23/12/2025 14:48, Mikko Rapeli wrote:
>>> It has been removed by:
>>
>> by commit foo bar (see also checkpatch and submitting patches).
> 
> Ok will duplicate the info then.
> 
>>>
>>> Fixes: 7cbba32a2d62 ("slimbus: qcom: remove unused qcom controller driver")
>>>
>>
>> Drop blank line
> 
> Ok
>  
>> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
>>
>> You anyway need to send to proper mailing list for this soc (Qcom), not
>> random folks.
> 
> Which proper list?

The list for this soc. get_maintainers will tell you that - run it on
any soc driver for that soc.

> 
> I sent to addresses reported by get_maintainers.pl.

There is no output of get_maintainers.pl for this file. It's one of
cases where script does not work (I think already documented in
maintainer soc profile).


> 
> Cheers,
> 
> -Mikko


Best regards,
Krzysztof


From pabeni at redhat.com  Tue Dec 23 06:12:58 2025
From: pabeni at redhat.com (Paolo Abeni)
Date: Tue, 23 Dec 2025 15:12:58 +0100
Subject: [PATCH] net: fix segmentation of forwarding fraglist GRO
In-Reply-To: <20251217035548.8104-1-jibin.zhang@mediatek.com>
References: <20251217035548.8104-1-jibin.zhang@mediatek.com>
Message-ID: <aab6c515-12e4-48ca-8220-c0797dae781f@redhat.com>

On 12/17/25 4:55 AM, Jibin Zhang wrote:
> This patch enhances GSO segment checks by verifying the presence
> of frag_list and protocol consistency, addressing low throughput
> issues on IPv4 servers when used as hotspots
> 
> Specifically, it fixes a bug in GSO segmentation when forwarding
> GRO packets with frag_list. The function skb_segment_list cannot
> correctly process GRO skbs converted by XLAT, because XLAT only
> converts the header of the head skb. As a result, skbs in the
> frag_list may remain unconverted, leading to protocol
> inconsistencies and reduced throughput.
> 
> To resolve this, the patch uses skb_segment to handle forwarded
> packets converted by XLAT, ensuring that all fragments are
> properly converted and segmented.
> 
> Signed-off-by: Jibin Zhang <jibin.zhang at mediatek.com>

This looks like a fix, it should target the 'net' tree and include a
suitable Fixes tag.

> ---
>  net/ipv4/tcp_offload.c | 3 ++-
>  net/ipv4/udp_offload.c | 3 ++-
>  2 files changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c
> index fdda18b1abda..162a384a15bb 100644
> --- a/net/ipv4/tcp_offload.c
> +++ b/net/ipv4/tcp_offload.c
> @@ -104,7 +104,8 @@ static struct sk_buff *tcp4_gso_segment(struct sk_buff *skb,
>  	if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
>  		return ERR_PTR(-EINVAL);
>  
> -	if (skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST) {
> +	if ((skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST) && skb_has_frag_list(skb) &&
> +	    (skb->protocol == skb_shinfo(skb)->frag_list->protocol)) {
>  		struct tcphdr *th = tcp_hdr(skb);
>  
>  		if (skb_pagelen(skb) - th->doff * 4 == skb_shinfo(skb)->gso_size)
> diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
> index 19d0b5b09ffa..704fb32d10d7 100644
> --- a/net/ipv4/udp_offload.c
> +++ b/net/ipv4/udp_offload.c
> @@ -512,7 +512,8 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
>  		return NULL;
>  	}
>  
> -	if (skb_shinfo(gso_skb)->gso_type & SKB_GSO_FRAGLIST) {
> +	if ((skb_shinfo(gso_skb)->gso_type & SKB_GSO_FRAGLIST) && skb_has_frag_list(gso_skb) &&
> +	    (gso_skb->protocol == skb_shinfo(gso_skb)->frag_list->protocol)) {
>  		 /* Detect modified geometry and pass those to skb_segment. */
>  		if (skb_pagelen(gso_skb) - sizeof(*uh) == skb_shinfo(gso_skb)->gso_size)
>  			return __udp_gso_segment_list(gso_skb, features, is_ipv6);

I guess checks should be needed for ipv6.

Also it looks like this skips the CSUM_PARTIAL preparation, and possibly
break csum offload.

Additionally I don't like the ever increasing stack of hacks needed to
let GSO_FRAGLIST operate in the most diverse setups, the simpler fix
would be disabling such aggregation.

/P



From towinchenmi at gmail.com  Tue Dec 23 06:13:41 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Tue, 23 Dec 2025 22:13:41 +0800
Subject: [PATCH 0/3] RTKit protocol version 10 support
Message-ID: <20251223-rtkit-v10-v1-0-12b4783d6403@gmail.com>

Add support for version 10 of the RTKit protocol which is used from iOS 11
to iOS 13. In version 10 epmap is always completed within 1 message, and
app endpoints start at 0x6 instead of 0x20.

A new interface apple_rtkit_app_ep_to_ep() is added to accommodate the
difference in app endpoints. Consumer drivers that uses RTKit app endpoints
need to be modified to use the new interface to work with protocol
version 10.

Add support in macsmc to get the SMC endpoint with the new interface.
nvme-apple does not use any RTKit app endpoints.

Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
Nick Chan (3):
      soc: apple: rtkit: Support verison-specific app endpoint start
      soc: apple: rtkit: Add protocol version 10 support
      mfd: macsmc: Support variable app endpoint start

 drivers/mfd/macsmc.c               | 18 +++++++-----
 drivers/soc/apple/rtkit-internal.h |  4 ++-
 drivers/soc/apple/rtkit.c          | 59 ++++++++++++++++++++++++++------------
 include/linux/mfd/macsmc.h         |  2 ++
 include/linux/soc/apple/rtkit.h    | 10 +++++++
 5 files changed, 67 insertions(+), 26 deletions(-)
---
base-commit: 9448598b22c50c8a5bb77a9103e2d49f134c9578
change-id: 20251222-rtkit-v10-cdcf41bdaaef

Best regards,
-- 
Nick Chan <towinchenmi at gmail.com>



From towinchenmi at gmail.com  Tue Dec 23 06:13:42 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Tue, 23 Dec 2025 22:13:42 +0800
Subject: [PATCH 1/3] soc: apple: rtkit: Support verison-specific app
 endpoint start
In-Reply-To: <20251223-rtkit-v10-v1-0-12b4783d6403@gmail.com>
References: <20251223-rtkit-v10-v1-0-12b4783d6403@gmail.com>
Message-ID: <20251223-rtkit-v10-v1-1-12b4783d6403@gmail.com>

Support for protocol versions where app endpoints starts at a
different endpoint number will be added. Consumer drivers will also
need to be modified to have them to work with such protocol
versions.

Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
 drivers/soc/apple/rtkit-internal.h |  3 ++-
 drivers/soc/apple/rtkit.c          | 42 +++++++++++++++++++++++++++-----------
 include/linux/soc/apple/rtkit.h    | 10 +++++++++
 3 files changed, 42 insertions(+), 13 deletions(-)

diff --git a/drivers/soc/apple/rtkit-internal.h b/drivers/soc/apple/rtkit-internal.h
index b8d5244678f0100b72173fa9aca80bf9db1b4e5e..52ef7a202120eb8a56c149179389741ec0f5e358 100644
--- a/drivers/soc/apple/rtkit-internal.h
+++ b/drivers/soc/apple/rtkit-internal.h
@@ -19,7 +19,7 @@
 #include <linux/workqueue.h>
 #include "mailbox.h"
 
-#define APPLE_RTKIT_APP_ENDPOINT_START 0x20
+#define APPLE_RTKIT_APP_ENDPOINT_START_V11 0x20
 #define APPLE_RTKIT_MAX_ENDPOINTS 0x100
 
 struct apple_rtkit {
@@ -35,6 +35,7 @@ struct apple_rtkit {
 
 	int boot_result;
 	int version;
+	u8 app_ep_start;
 
 	unsigned int iop_power_state;
 	unsigned int ap_power_state;
diff --git a/drivers/soc/apple/rtkit.c b/drivers/soc/apple/rtkit.c
index b8d4da147d23f7e99e76eea314e4d976cddbd1c6..716d6a3e6eefd82d919467e39d68245c5c0d137c 100644
--- a/drivers/soc/apple/rtkit.c
+++ b/drivers/soc/apple/rtkit.c
@@ -140,6 +140,8 @@ static void apple_rtkit_management_rx_hello(struct apple_rtkit *rtk, u64 msg)
 		 want_ver);
 	rtk->version = want_ver;
 
+	rtk->app_ep_start = APPLE_RTKIT_APP_ENDPOINT_START_V11;
+
 	reply = FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MINVER, want_ver);
 	reply |= FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MAXVER, want_ver);
 	apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_HELLO_REPLY, reply);
@@ -179,7 +181,7 @@ static void apple_rtkit_management_rx_epmap(struct apple_rtkit *rtk, u64 msg)
 	if (!(msg & APPLE_RTKIT_MGMT_EPMAP_LAST))
 		return;
 
-	for_each_set_bit(ep, rtk->endpoints, APPLE_RTKIT_APP_ENDPOINT_START) {
+	for_each_set_bit(ep, rtk->endpoints, rtk->app_ep_start) {
 		switch (ep) {
 		/* the management endpoint is started by default */
 		case APPLE_RTKIT_EP_MGMT:
@@ -547,20 +549,21 @@ static void apple_rtkit_rx_work(struct work_struct *work)
 	case APPLE_RTKIT_EP_OSLOG:
 		apple_rtkit_oslog_rx(rtk, rtk_work->msg);
 		break;
-	case APPLE_RTKIT_APP_ENDPOINT_START ... 0xff:
-		if (rtk->ops->recv_message)
+	default:
+		if (rtk_work->ep >= rtk->app_ep_start && rtk->ops->recv_message)
 			rtk->ops->recv_message(rtk->cookie, rtk_work->ep,
 					       rtk_work->msg);
-		else
+		else if (rtk_work->ep >= rtk->app_ep_start)
 			dev_warn(
 				rtk->dev,
 				"Received unexpected message to EP%02d: %llx\n",
 				rtk_work->ep, rtk_work->msg);
+		else
+			dev_warn(
+				rtk->dev,
+				"RTKit: message to unknown endpoint %02x: %llx\n",
+				rtk_work->ep, rtk_work->msg);
 		break;
-	default:
-		dev_warn(rtk->dev,
-			 "RTKit: message to unknown endpoint %02x: %llx\n",
-			 rtk_work->ep, rtk_work->msg);
 	}
 
 	kfree(rtk_work);
@@ -585,7 +588,7 @@ static void apple_rtkit_rx(struct apple_mbox *mbox, struct apple_mbox_msg msg,
 			 "RTKit: Message to undiscovered endpoint 0x%02x\n",
 			 ep);
 
-	if (ep >= APPLE_RTKIT_APP_ENDPOINT_START &&
+	if (ep >= rtk->app_ep_start &&
 	    rtk->ops->recv_message_early &&
 	    rtk->ops->recv_message_early(rtk->cookie, ep, msg.msg0))
 		return;
@@ -615,8 +618,7 @@ int apple_rtkit_send_message(struct apple_rtkit *rtk, u8 ep, u64 message,
 		return -EINVAL;
 	}
 
-	if (ep >= APPLE_RTKIT_APP_ENDPOINT_START &&
-	    !apple_rtkit_is_running(rtk)) {
+	if (ep >= rtk->app_ep_start && !apple_rtkit_is_running(rtk)) {
 		dev_warn(rtk->dev,
 			 "RTKit: Endpoint 0x%02x is not running, cannot send message\n", ep);
 		return -EINVAL;
@@ -645,7 +647,7 @@ int apple_rtkit_start_ep(struct apple_rtkit *rtk, u8 endpoint)
 
 	if (!test_bit(endpoint, rtk->endpoints))
 		return -EINVAL;
-	if (endpoint >= APPLE_RTKIT_APP_ENDPOINT_START &&
+	if (endpoint >= rtk->app_ep_start &&
 	    !apple_rtkit_is_running(rtk))
 		return -EINVAL;
 
@@ -675,6 +677,13 @@ struct apple_rtkit *apple_rtkit_init(struct device *dev, void *cookie,
 	rtk->cookie = cookie;
 	rtk->ops = ops;
 
+	/*
+	 * The management endpoint is required to receive the HELLO message
+	 * and infer the start of app endpoints so assume it is a system
+	 * endpoint here and update this value when HELLO is received.
+	 */
+	rtk->app_ep_start = APPLE_RTKIT_EP_CRASHLOG;
+
 	init_completion(&rtk->epmap_completion);
 	init_completion(&rtk->iop_pwr_ack_completion);
 	init_completion(&rtk->ap_pwr_ack_completion);
@@ -851,6 +860,15 @@ int apple_rtkit_shutdown(struct apple_rtkit *rtk)
 }
 EXPORT_SYMBOL_GPL(apple_rtkit_shutdown);
 
+u8 apple_rtkit_app_ep_to_ep(struct apple_rtkit *rtk, u8 app_ep)
+{
+	if (!apple_rtkit_is_running(rtk))
+		return 0;
+
+	return rtk->app_ep_start + app_ep;
+}
+EXPORT_SYMBOL_GPL(apple_rtkit_app_ep_to_ep);
+
 int apple_rtkit_idle(struct apple_rtkit *rtk)
 {
 	int ret;
diff --git a/include/linux/soc/apple/rtkit.h b/include/linux/soc/apple/rtkit.h
index 736f530180179bd144cf85eb0f0bd93844d7188a..423cf1022372b124c9b2728445f85a9b3067c707 100644
--- a/include/linux/soc/apple/rtkit.h
+++ b/include/linux/soc/apple/rtkit.h
@@ -172,4 +172,14 @@ int apple_rtkit_send_message(struct apple_rtkit *rtk, u8 ep, u64 message,
  */
 int apple_rtkit_poll(struct apple_rtkit *rtk);
 
+/*
+ * Convert an endpoint number relative to start of app endpoint to an absolute
+ * endpoint number.
+ *
+ * Returns the endpoint number on success, 0 on failure.
+ *
+ * @rtk:            RTKit reference
+ */
+u8 apple_rtkit_app_ep_to_ep(struct apple_rtkit *rtk, u8 app_ep);
+
 #endif /* _LINUX_APPLE_RTKIT_H_ */

-- 
2.52.0



From towinchenmi at gmail.com  Tue Dec 23 06:13:43 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Tue, 23 Dec 2025 22:13:43 +0800
Subject: [PATCH 2/3] soc: apple: rtkit: Add protocol version 10 support
In-Reply-To: <20251223-rtkit-v10-v1-0-12b4783d6403@gmail.com>
References: <20251223-rtkit-v10-v1-0-12b4783d6403@gmail.com>
Message-ID: <20251223-rtkit-v10-v1-2-12b4783d6403@gmail.com>

Add support for protocol version 10 used from iOS 11-13. In
protocol version 10, epmap is always completed within a single
message, and app endpoints start at 0x6 instead of 0x20.

Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
 drivers/soc/apple/rtkit-internal.h |  1 +
 drivers/soc/apple/rtkit.c          | 19 ++++++++++++-------
 2 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/drivers/soc/apple/rtkit-internal.h b/drivers/soc/apple/rtkit-internal.h
index 52ef7a202120eb8a56c149179389741ec0f5e358..5f91dea8b7a178b368783d74f8c5786ea2965fa7 100644
--- a/drivers/soc/apple/rtkit-internal.h
+++ b/drivers/soc/apple/rtkit-internal.h
@@ -19,6 +19,7 @@
 #include <linux/workqueue.h>
 #include "mailbox.h"
 
+#define APPLE_RTKIT_APP_ENDPOINT_START_V10 0x6
 #define APPLE_RTKIT_APP_ENDPOINT_START_V11 0x20
 #define APPLE_RTKIT_MAX_ENDPOINTS 0x100
 
diff --git a/drivers/soc/apple/rtkit.c b/drivers/soc/apple/rtkit.c
index 716d6a3e6eefd82d919467e39d68245c5c0d137c..376d1d30fd1e2176357c1daa24c76300c7c70f85 100644
--- a/drivers/soc/apple/rtkit.c
+++ b/drivers/soc/apple/rtkit.c
@@ -71,7 +71,7 @@ enum {
 #define APPLE_RTKIT_OSLOG_SIZE GENMASK_ULL(55, 36)
 #define APPLE_RTKIT_OSLOG_IOVA GENMASK_ULL(35, 0)
 
-#define APPLE_RTKIT_MIN_SUPPORTED_VERSION 11
+#define APPLE_RTKIT_MIN_SUPPORTED_VERSION 10
 #define APPLE_RTKIT_MAX_SUPPORTED_VERSION 12
 
 struct apple_rtkit_rx_work {
@@ -140,7 +140,10 @@ static void apple_rtkit_management_rx_hello(struct apple_rtkit *rtk, u64 msg)
 		 want_ver);
 	rtk->version = want_ver;
 
-	rtk->app_ep_start = APPLE_RTKIT_APP_ENDPOINT_START_V11;
+	if (rtk->version < 11)
+		rtk->app_ep_start = APPLE_RTKIT_APP_ENDPOINT_START_V10;
+	else
+		rtk->app_ep_start = APPLE_RTKIT_APP_ENDPOINT_START_V11;
 
 	reply = FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MINVER, want_ver);
 	reply |= FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MAXVER, want_ver);
@@ -171,14 +174,16 @@ static void apple_rtkit_management_rx_epmap(struct apple_rtkit *rtk, u64 msg)
 	}
 
 	reply = FIELD_PREP(APPLE_RTKIT_MGMT_EPMAP_BASE, base);
-	if (msg & APPLE_RTKIT_MGMT_EPMAP_LAST)
-		reply |= APPLE_RTKIT_MGMT_EPMAP_LAST;
-	else
-		reply |= APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE;
+	if (rtk->version > 10) {
+		if (msg & APPLE_RTKIT_MGMT_EPMAP_LAST)
+			reply |= APPLE_RTKIT_MGMT_EPMAP_LAST;
+		else
+			reply |= APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE;
+	}
 
 	apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_EPMAP_REPLY, reply);
 
-	if (!(msg & APPLE_RTKIT_MGMT_EPMAP_LAST))
+	if (rtk->version > 10 && !(msg & APPLE_RTKIT_MGMT_EPMAP_LAST))
 		return;
 
 	for_each_set_bit(ep, rtk->endpoints, rtk->app_ep_start) {

-- 
2.52.0



From towinchenmi at gmail.com  Tue Dec 23 06:13:44 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Tue, 23 Dec 2025 22:13:44 +0800
Subject: [PATCH 3/3] mfd: macsmc: Support variable app endpoint start
In-Reply-To: <20251223-rtkit-v10-v1-0-12b4783d6403@gmail.com>
References: <20251223-rtkit-v10-v1-0-12b4783d6403@gmail.com>
Message-ID: <20251223-rtkit-v10-v1-3-12b4783d6403@gmail.com>

Instead of hardcoding the SMC endpoint number, use
apple_rtkit_app_ep_to_ep() to convert a relative endpoint number to
an absolute endpoint number in order to support protocol versions
with a different start of app endpoint number.

Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
 drivers/mfd/macsmc.c       | 18 +++++++++++-------
 include/linux/mfd/macsmc.h |  2 ++
 2 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/drivers/mfd/macsmc.c b/drivers/mfd/macsmc.c
index e3893e255ce5e4bb4832d80ad1fc002d413a291a..4e0fc5ddf9293ee7281680e964fc5f9b80260b3d 100644
--- a/drivers/mfd/macsmc.c
+++ b/drivers/mfd/macsmc.c
@@ -21,7 +21,7 @@
 #include <linux/soc/apple/rtkit.h>
 #include <linux/unaligned.h>
 
-#define SMC_ENDPOINT			0x20
+#define SMC_APP_ENDPOINT		0
 
 /* We don't actually know the true size here but this seem reasonable */
 #define SMC_SHMEM_SIZE			0x1000
@@ -72,7 +72,7 @@ static int apple_smc_cmd_locked(struct apple_smc *smc, u64 cmd, u64 arg,
 	       FIELD_PREP(SMC_ID, smc->msg_id) |
 	       FIELD_PREP(SMC_DATA, arg));
 
-	ret = apple_rtkit_send_message(smc->rtk, SMC_ENDPOINT, msg, NULL, false);
+	ret = apple_rtkit_send_message(smc->rtk, smc->ep, msg, NULL, false);
 	if (ret) {
 		dev_err(smc->dev, "Failed to send command\n");
 		return ret;
@@ -262,7 +262,7 @@ int apple_smc_write_atomic(struct apple_smc *smc, smc_key key, const void *buf,
 	       FIELD_PREP(SMC_DATA, key));
 	smc->atomic_pending = true;
 
-	ret = apple_rtkit_send_message(smc->rtk, SMC_ENDPOINT, msg, NULL, true);
+	ret = apple_rtkit_send_message(smc->rtk, smc->ep, msg, NULL, true);
 	if (ret < 0) {
 		dev_err(smc->dev, "Failed to send command (%d)\n", ret);
 		return ret;
@@ -330,7 +330,7 @@ static bool apple_smc_rtkit_recv_early(void *cookie, u8 endpoint, u64 message)
 {
 	struct apple_smc *smc = cookie;
 
-	if (endpoint != SMC_ENDPOINT) {
+	if (endpoint != smc->ep) {
 		dev_warn(smc->dev, "Received message for unknown endpoint 0x%x\n", endpoint);
 		return false;
 	}
@@ -366,7 +366,7 @@ static void apple_smc_rtkit_recv(void *cookie, u8 endpoint, u64 message)
 {
 	struct apple_smc *smc = cookie;
 
-	if (endpoint != SMC_ENDPOINT) {
+	if (endpoint != smc->ep) {
 		dev_warn(smc->dev, "Received message for unknown endpoint 0x%x\n", endpoint);
 		return;
 	}
@@ -427,18 +427,22 @@ static int apple_smc_probe(struct platform_device *pdev)
 	if (ret)
 		return dev_err_probe(dev, ret, "Failed to wake up SMC");
 
+	smc->ep = apple_rtkit_app_ep_to_ep(smc->rtk, SMC_APP_ENDPOINT);
+	if (!smc->ep)
+		return dev_err_probe(dev, ret, "Failed to get SMC endpoint");
+
 	ret = devm_add_action_or_reset(dev, apple_smc_rtkit_shutdown, smc);
 	if (ret)
 		return ret;
 
-	ret = apple_rtkit_start_ep(smc->rtk, SMC_ENDPOINT);
+	ret = apple_rtkit_start_ep(smc->rtk, smc->ep);
 	if (ret)
 		return dev_err_probe(dev, ret, "Failed to start SMC endpoint");
 
 	init_completion(&smc->init_done);
 	init_completion(&smc->cmd_done);
 
-	ret = apple_rtkit_send_message(smc->rtk, SMC_ENDPOINT,
+	ret = apple_rtkit_send_message(smc->rtk, smc->ep,
 				       FIELD_PREP(SMC_MSG, SMC_MSG_INITIALIZE), NULL, false);
 	if (ret)
 		return dev_err_probe(dev, ret, "Failed to send init message");
diff --git a/include/linux/mfd/macsmc.h b/include/linux/mfd/macsmc.h
index cc09ecce0df7424b288d4248d869f4c9bed3e188..1a462baae0e38ac099f90988afda0f3f5ad968b9 100644
--- a/include/linux/mfd/macsmc.h
+++ b/include/linux/mfd/macsmc.h
@@ -93,6 +93,7 @@ enum apple_smc_boot_stage {
  * @sram: Pointer to SRAM resource
  * @sram_base: SRAM base address
  * @shmem: RTKit shared memory structure for SRAM
+ * @ep: SMC endpoint number
  * @msg_id: Current message id for commands, will be incremented for each command
  * @atomic_mode: Flag set when atomic mode is entered
  * @atomic_pending: Flag indicating pending atomic command
@@ -118,6 +119,7 @@ struct apple_smc {
 	struct resource *sram;
 	void __iomem *sram_base;
 	struct apple_rtkit_shmem shmem;
+	u8 ep;
 
 	unsigned int msg_id;
 

-- 
2.52.0



From leon at kernel.org  Tue Dec 23 06:14:24 2025
From: leon at kernel.org (Leon Romanovsky)
Date: Tue, 23 Dec 2025 16:14:24 +0200
Subject: [PATCH 5/6] dma-mapping: Allow batched DMA sync operations if
 supported by the arch
In-Reply-To: <CAGsJ_4yuvHNqHDi8eN-8UoY2McoXUeCMmbjFAr=jSdv8GpGKeg@mail.gmail.com>
References: <20251221115523.GI13030@unreal>
 <20251221192458.1320-1-21cnbao@gmail.com>
 <20251222084921.GA13529@unreal>
 <CAGsJ_4yuvHNqHDi8eN-8UoY2McoXUeCMmbjFAr=jSdv8GpGKeg@mail.gmail.com>
Message-ID: <20251223141424.GB11869@unreal>

On Tue, Dec 23, 2025 at 01:02:55PM +1300, Barry Song wrote:
> On Mon, Dec 22, 2025 at 9:49?PM Leon Romanovsky <leon at kernel.org> wrote:
> >
> > On Mon, Dec 22, 2025 at 03:24:58AM +0800, Barry Song wrote:
> > > On Sun, Dec 21, 2025 at 7:55?PM Leon Romanovsky <leon at kernel.org> wrote:
> > > [...]
> > > > > +
> > > >
> > > > I'm wondering why you don't implement this batch?sync support inside the
> > > > arch_sync_dma_*() functions. Doing so would minimize changes to the generic
> > > > kernel/dma/* code and reduce the amount of #ifdef?based spaghetti.
> > > >
> > >
> > > There are two cases: mapping an sg list and mapping a single
> > > buffer. The former can be batched with
> > > arch_sync_dma_*_batch_add() and flushed via
> > > arch_sync_dma_batch_flush(), while the latter requires all work to
> > > be done inside arch_sync_dma_*(). Therefore,
> > > arch_sync_dma_*() cannot always batch and flush.
> >
> > Probably in all cases you can call the _batch_ variant, followed by _flush_,
> > even when handling a single page. This keeps the code consistent across all
> > paths. On platforms that do not support _batch_, the _flush_ operation will be
> > a NOP anyway.
> 
> We have a lot of code outside kernel/dma that also calls
> arch_sync_dma_for_* such as arch/arm, arch/mips, drivers/xen,
> I guess we don?t want to modify so many things?

Aren't they using internal, arch specific, arch_sync_dma_for_* implementations?

> 
> for kernel/dma, we have two "single" callers only:
> kernel/dma/direct.h, kernel/dma/swiotlb.c.  and they looks quite
> straightforward:
> 
> static inline void dma_direct_sync_single_for_device(struct device *dev,
>                 dma_addr_t addr, size_t size, enum dma_data_direction dir)
> {
>         phys_addr_t paddr = dma_to_phys(dev, addr);
> 
>         swiotlb_sync_single_for_device(dev, paddr, size, dir);
> 
>         if (!dev_is_dma_coherent(dev))
>                 arch_sync_dma_for_device(paddr, size, dir);
> }
> 
> I guess moving to arch_sync_dma_for_device_batch + flush
> doesn?t really look much better, does it?
> 
> >
> > I would also rename arch_sync_dma_batch_flush() to arch_sync_dma_flush().
> 
> Sure.
> 
> >
> > You can also minimize changes in dma_direct_map_phys() too, by extending
> > it's signature to provide if flush is needed or not.
> 
> Yes. I have
> 
> static inline dma_addr_t __dma_direct_map_phys(struct device *dev,
>                 phys_addr_t phys, size_t size, enum dma_data_direction dir,
>                 unsigned long attrs, bool flush)

My suggestion is to use it directly, without wrappers.

> 
> and two wrappers:
> static inline dma_addr_t dma_direct_map_phys(struct device *dev,
>                 phys_addr_t phys, size_t size, enum dma_data_direction dir,
>                 unsigned long attrs)
> {
>         return __dma_direct_map_phys(dev, phys, size, dir, attrs, true);
> }
> 
> static inline dma_addr_t dma_direct_map_phys_batch_add(struct device *dev,
>                 phys_addr_t phys, size_t size, enum dma_data_direction dir,
>                 unsigned long attrs)
> {
>         return __dma_direct_map_phys(dev, phys, size, dir, attrs, false);
> }
> 
> If you prefer exposing "flush" directly in dma_direct_map_phys()
> and updating its callers with flush=true, I think that?s fine.

Yes

> 
> It could be also true for dma_direct_sync_single_for_device().
> 
> >
> > dma_direct_map_phys(....) -> dma_direct_map_phys(...., bool flush):
> >
> > static inline dma_addr_t dma_direct_map_phys(...., bool flush)
> > {
> >         ....
> >
> >         if (dma_addr != DMA_MAPPING_ERROR && !dev_is_dma_coherent(dev) &&
> >             !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO)))
> >         {
> >                 arch_sync_dma_for_device(phys, size, dir);
> >                 if (flush)
> >                         arch_sync_dma_flush();
> >         }
> > }
> >
> 
> Thanks
> Barry
> 


From vkoul at kernel.org  Tue Dec 23 06:19:11 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 23 Dec 2025 19:49:11 +0530
Subject: [PATCH] phy: fsl-imx8mq-usb: add debugfs to access control
 register
In-Reply-To: <20251219075447.3672833-1-xu.yang_2@nxp.com>
References: <20251219075447.3672833-1-xu.yang_2@nxp.com>
Message-ID: <aUqk3z8CSVldoO5V@vaman>

On 19-12-25, 15:54, Xu Yang wrote:
> The CR port is a simple 16-bit data/address parallel port that is
> provided for on-chip access to the control registers inside the
> USB 3.0 femtoPHY. While access to these registers is not required
> for normal PHY operation, this interface enables you to access
> some of the PHY?s diagnostic features during normal operation or
> to override some basic PHY control signals.
> 
> 3 debugfs files are created to read and write control registers,
> all use hexadecimal format:
> ctrl_reg_base: the register offset to write, or the start offset
>                to read.
> ctrl_reg_count: how many continuous registers to be read.
> ctrl_reg_value: read to show the continuous registers value from
>                 the offset in ctrl_reg_base, to ctrl_reg_base
>                 + ctrl_reg_count - 1, one line for one register.
>                 when write, override the register at ctrl_reg_base,
>                 one time can only change one 16bits register.
> 
> Signed-off-by: Li Jun <jun.li at nxp.com>
> Signed-off-by: Xu Yang <xu.yang_2 at nxp.com>
> ---
>  drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 221 ++++++++++++++++++++-
>  1 file changed, 220 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> index ad8a55012e42..cb2392008ad2 100644
> --- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> +++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> @@ -1,8 +1,9 @@
>  // SPDX-License-Identifier: GPL-2.0+
> -/* Copyright (c) 2017 NXP. */
> +/* Copyright (c) 2017-2025 NXP. */
>  
>  #include <linux/bitfield.h>
>  #include <linux/clk.h>
> +#include <linux/debugfs.h>
>  #include <linux/delay.h>
>  #include <linux/io.h>
>  #include <linux/module.h>
> @@ -52,6 +53,21 @@
>  
>  #define PHY_TUNE_DEFAULT		0xffffffff
>  
> +/* PHY control register access */
> +#define PHY_CTRL_REG_COUNT_MAX		0x42
> +#define PHY_CTRL_REG_OFFSET_MAX		0x201f
> +
> +#define PHY_CRCTL			0x30
> +#define PHY_CRCTL_DATA_IN_MASK		GENMASK(15, 0)
> +#define PHY_CRCTL_CAP_ADDR		BIT(16)
> +#define PHY_CRCTL_CAP_DATA		BIT(17)
> +#define PHY_CRCTL_CR_WRITE		BIT(18)
> +#define PHY_CRCTL_CR_READ		BIT(19)
> +
> +#define PHY_CRSR			0x34
> +#define PHY_CRSR_DATA_OUT_MASK		GENMASK(15, 0)
> +#define PHY_CRSR_CR_ACK			BIT(16)
> +
>  #define TCA_CLK_RST			0x00
>  #define TCA_CLK_RST_SW			BIT(9)
>  #define TCA_CLK_RST_REF_CLK_EN		BIT(1)
> @@ -113,6 +129,9 @@ struct imx8mq_usb_phy {
>  	void __iomem *base;
>  	struct regulator *vbus;
>  	struct tca_blk *tca;
> +	struct dentry *debugfs;
> +	u16 cr_access_base;
> +	u16 cr_read_count;
>  	u32 pcs_tx_swing_full;
>  	u32 pcs_tx_deemph_3p5db;
>  	u32 tx_vref_tune;
> @@ -420,6 +439,204 @@ static u32 phy_pcs_tx_swing_full_from_property(u32 percent)
>  	percent = min(percent, 100U);
>  
>  	return (percent * 127) / 100;
> +};
> +
> +#define IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT 500000

empty line here, possibly move this to top of file

> +static int imx8mq_phy_ctrl_reg_addr(struct imx8mq_usb_phy *imx_phy, u16 offset)
> +{
> +	void __iomem	*cr_ctrl = imx_phy->base + PHY_CRCTL;
> +	void __iomem	*cr_sr = imx_phy->base + PHY_CRSR;
> +	struct device	*dev = &imx_phy->phy->dev;
> +	int i;
> +
> +	/* Address Phrase */
> +	writel(offset, cr_ctrl);
> +	writel(readl(cr_ctrl) | PHY_CRCTL_CAP_ADDR, cr_ctrl);
> +
> +	/* Wait CRSR[16] == 1 */
> +	i = IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT;
> +	while (!(readl(cr_sr) & PHY_CRSR_CR_ACK) && i > 0)
> +		i--;
> +	if (i == 0)
> +		goto cr_addr_err;
> +
> +	writel(readl(cr_ctrl) & (~PHY_CRCTL_CAP_ADDR), cr_ctrl);
> +
> +	/* Wait CRSR[16] == 0 */
> +	i = IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT;
> +	while ((readl(cr_sr) & PHY_CRSR_CR_ACK) && i > 0)
> +		i--;
> +	if (i == 0)
> +		goto cr_addr_err;
> +
> +	return 0;
> +
> +cr_addr_err:
> +	dev_err(dev, "Failed to address reg 0x%x.\n", offset);
> +	return -EIO;
> +}
> +
> +static int imx8mq_phy_ctrl_reg_read(struct imx8mq_usb_phy *imx_phy, u16 offset)
> +{
> +	void __iomem	*cr_ctrl = imx_phy->base + PHY_CRCTL;
> +	void __iomem	*cr_sr = imx_phy->base + PHY_CRSR;
> +	struct device	*dev = &imx_phy->phy->dev;
> +	int val, i;
> +
> +	/* Address Phrase */
> +	val = imx8mq_phy_ctrl_reg_addr(imx_phy, offset);
> +	if (val)
> +		return val;
> +
> +	/* Read Phrase */
> +	writel(readl(cr_ctrl) | PHY_CRCTL_CR_READ, cr_ctrl);
> +
> +	/* Wait CRSR[16] == 1 */
> +	i = IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT;
> +	while (!(readl(cr_sr) & PHY_CRSR_CR_ACK) && i > 0)
> +		i--;
> +	if (i == 0)
> +		goto cr_read_err;
> +
> +	val = readl(cr_sr);
> +	writel(val & ~PHY_CRCTL_CR_READ, cr_ctrl);
> +
> +	/* Wait CRSR[16] == 0 */
> +	i = IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT;
> +	while (!(readl(cr_sr) & PHY_CRSR_CR_ACK) && i > 0)
> +		i--;
> +	if (i == 0)
> +		goto cr_read_err;
> +
> +	return val;
> +
> +cr_read_err:
> +	dev_err(dev, "Failed to read reg 0x%x.\n", offset);
> +	return -EIO;
> +}
> +
> +static int imx8mq_phy_ctrl_reg_write(struct imx8mq_usb_phy *imx_phy,
> +				     u16 offset, u16 val)
> +{
> +	void __iomem	*cr_ctrl = imx_phy->base + PHY_CRCTL;
> +	void __iomem	*cr_sr = imx_phy->base + PHY_CRSR;
> +	struct device	*dev = &imx_phy->phy->dev;
> +	int i, ret;
> +
> +	/* Address Phrase */
> +	ret = imx8mq_phy_ctrl_reg_addr(imx_phy, offset);
> +	if (ret)
> +		return ret;
> +
> +	writel(val, cr_ctrl);
> +
> +	/* Set cr_cap_data to be 1'b1 */
> +	writel(readl(cr_ctrl) | PHY_CRCTL_CAP_DATA, cr_ctrl);
> +	/* Wait CRSR[16] == 1 */
> +	i = IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT;
> +	while (!(readl(cr_sr) & PHY_CRSR_CR_ACK) && i > 0)
> +		i--;
> +	if (i == 0)
> +		goto cr_write_err;

seems like a repeated pattern, maybe move to a helper. (if driver used
regmap, it could have used helpers from regmap for this polling)

> +
> +	/* Clear cr_cap_data to be 1'br0 */
> +	writel(readl(cr_ctrl) & ~PHY_CRCTL_CAP_DATA, cr_ctrl);
> +	/* Wait CRSR[16] == 0 */
> +	i = IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT;
> +	while ((readl(cr_sr) & PHY_CRSR_CR_ACK) && i > 0)
> +		i--;
> +	if (i == 0)
> +		goto cr_write_err;
> +
> +	/* Set cr_write to be 1'b1 */
> +	writel(readl(cr_ctrl) | PHY_CRCTL_CR_WRITE, cr_ctrl);
> +	/* Wait CRSR[16] == 1 */
> +	i = IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT;
> +	while (!(readl(cr_sr) & PHY_CRSR_CR_ACK) && i > 0)
> +		i--;
> +	if (i == 0)
> +		goto cr_write_err;
> +
> +	/* Clear cr_write to be 1'br0 */
> +	writel(readl(cr_ctrl) & ~PHY_CRCTL_CR_WRITE, cr_ctrl);
> +	/* Wait CRSR[16] == 0 */
> +	i = IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT;
> +	while ((readl(cr_sr) & PHY_CRSR_CR_ACK) && i > 0)
> +		i--;
> +	if (i == 0)
> +		goto cr_write_err;
> +
> +	return 0;
> +
> +cr_write_err:
> +	dev_err(dev, "Failed to write reg 0x%x.\n", offset);
> +	return -EIO;
> +}
> +
> +static int ctrl_reg_value_show(struct seq_file *s, void *unused)
> +{
> +	struct imx8mq_usb_phy *imx_phy = s->private;
> +	u16 i, val, base = imx_phy->cr_access_base;
> +
> +	for (i = 0; i < imx_phy->cr_read_count; i++) {
> +		val = imx8mq_phy_ctrl_reg_read(imx_phy, base + i);
> +		seq_printf(s, "Control Register 0x%x value is 0x%4x\n",
> +			   base + i, val);
> +	}
> +
> +	return 0;
> +}
> +
> +static int ctrl_reg_value_open(struct inode *inode, struct file *file)
> +{
> +	return single_open(file, ctrl_reg_value_show, inode->i_private);
> +}
> +
> +static ssize_t ctrl_reg_value_write(struct file *file, const char __user *ubuf,
> +				    size_t count, loff_t *ppos)
> +{
> +	struct seq_file		*s = file->private_data;
> +	struct imx8mq_usb_phy	*imx_phy = s->private;
> +	u16			cr_value;
> +	int			ret;
> +
> +	ret = kstrtou16_from_user(ubuf, count, 16, &cr_value);
> +	if (ret)
> +		return ret;
> +
> +	imx8mq_phy_ctrl_reg_write(imx_phy, imx_phy->cr_access_base, cr_value);
> +
> +	return count;
> +}
> +
> +static const struct file_operations ctrl_reg_value_fops = {
> +	.open		= ctrl_reg_value_open,
> +	.write		= ctrl_reg_value_write,
> +	.read		= seq_read,
> +	.llseek		= seq_lseek,
> +	.release	= single_release,
> +};

please use DEFINE_DEBUGFS_ATTRIBUTE for this

> +
> +static void debug_create_files(struct imx8mq_usb_phy *imx_phy)
> +{
> +	struct device *dev = &imx_phy->phy->dev;
> +
> +	imx_phy->debugfs = debugfs_create_dir(dev_name(dev), imx_phy->phy->debugfs);
> +
> +	debugfs_create_x16("ctrl_reg_base", 0600, imx_phy->debugfs,
> +			   &imx_phy->cr_access_base);
> +	debugfs_create_x16("ctrl_reg_count", 0600, imx_phy->debugfs,
> +			   &imx_phy->cr_read_count);
> +	debugfs_create_file("ctrl_reg_value", 0600, imx_phy->debugfs,
> +			    imx_phy, &ctrl_reg_value_fops);
> +
> +	imx_phy->cr_access_base = 0;
> +	imx_phy->cr_read_count = 1;
> +}
> +
> +static void debug_remove_files(struct imx8mq_usb_phy *imx_phy)
> +{
> +	debugfs_remove_recursive(imx_phy->debugfs);
>  }
>  
>  static void imx8m_get_phy_tuning_data(struct imx8mq_usb_phy *imx_phy)
> @@ -724,6 +941,7 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
>  					"failed to get tca\n");
>  
>  	imx8m_get_phy_tuning_data(imx_phy);
> +	debug_create_files(imx_phy);

please use phy->debugfs as root node

-- 
~Vinod


From krzk at kernel.org  Tue Dec 23 06:23:18 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 15:23:18 +0100
Subject: [PATCH 1/8] dt-bindings: phy: axiado,ax3000-emmc-phy: add Axiado
 eMMC PHY document
In-Reply-To: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-1-5457d0ebcdb4@axiado.com>
References: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-0-5457d0ebcdb4@axiado.com>
 <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-1-5457d0ebcdb4@axiado.com>
Message-ID: <20251223-nondescript-horned-mouflon-36ba75@quoll>

On Mon, Dec 22, 2025 at 04:45:00PM +0800, Tzu-Hao Wei wrote:
> From: SriNavmani A <srinavmani at axiado.com>
> 
> Add device tree bindings for the Axiado AX3000 eMMC PHY. The bindings
> define the required properties for configuring the external Arasan
> eMMC PHY, including register base addresses and clock references
> needed for HS200 mode operation.

Do not say what the bindings are supposed to do. We can read the diff.
Explain the hardware.

> 
> Signed-off-by: SriNavmani A <srinavmani at axiado.com>
> Signed-off-by: Tzu-Hao Wei <twei at axiado.com>
> ---
>  .../bindings/phy/axiado,ax3000-emmc-phy.yaml       | 46 ++++++++++++++++++++++
>  1 file changed, 46 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/phy/axiado,ax3000-emmc-phy.yaml b/Documentation/devicetree/bindings/phy/axiado,ax3000-emmc-phy.yaml
> new file mode 100644
> index 0000000000000000000000000000000000000000..f88941ce60cbd99a73e8c504e0bf36c626bbf674
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/axiado,ax3000-emmc-phy.yaml
> @@ -0,0 +1,46 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/phy/axiado,ax3000-emmc-phy.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Axiado AX3000 Arasan eMMC PHY
> +
> +maintainers:
> +  - SriNavmani A <srinavmani at axiado.com>
> +  - Tzu-Hao Wei <twei at axiado.com>
> +  - Prasad Bolisetty <pbolisetty at axiado.com>
> +
> +description: |+
> +  Bindings for eMMC PHY on Axiado AX3000 SoC.

Irrelevant

> +
> +  - compatible:         Should be one of the following:
> +                        "axiado,ax3000-emmc-phy"
> +  - reg:
> +      maxItems: 1

Entire description is not correct. Do you see any file written like
this/

> +
> +properties:
> +  compatible:
> +    enum:
> +      - axiado,ax3000-emmc-phy
> +
> +  "#phy-cells":
> +    const: 0
> +
> +  reg:
> +    maxItems: 1
> +
> +required:
> +  - "#phy-cells"
> +  - compatible
> +  - reg

Wrong order, use the same as in properties.

> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    emmc_phy: emmc-phy at 80801C00 {

Drop label and node is just phy@

Also, use lowercase hex everywhere.

Read DTS coding style - Axiado already received this feedback, so you
should follow it in all your submissions.

Best regards,
Krzysztof



From krzk at kernel.org  Tue Dec 23 06:23:46 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 15:23:46 +0100
Subject: [PATCH 1/8] dt-bindings: phy: axiado,ax3000-emmc-phy: add Axiado
 eMMC PHY document
In-Reply-To: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-1-5457d0ebcdb4@axiado.com>
References: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-0-5457d0ebcdb4@axiado.com>
 <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-1-5457d0ebcdb4@axiado.com>
Message-ID: <20251223-adder-of-imminent-recreation-ea90c0@quoll>

On Mon, Dec 22, 2025 at 04:45:00PM +0800, Tzu-Hao Wei wrote:
> From: SriNavmani A <srinavmani at axiado.com>
> 
> Add device tree bindings for the Axiado AX3000 eMMC PHY. The bindings
> define the required properties for configuring the external Arasan

Ah, and also:

A nit, subject: drop second/last, redundant "document". The
"dt-bindings" prefix is already stating that these are documents.
See also:
https://elixir.bootlin.com/linux/v6.17-rc3/source/Documentation/devicetree/bindings/submitting-patches.rst#L18

Best regards,
Krzysztof



From johan at kernel.org  Tue Dec 23 06:23:58 2025
From: johan at kernel.org (Johan Hovold)
Date: Tue, 23 Dec 2025 15:23:58 +0100
Subject: [PATCH 00/12] i2c: add and start using i2c_adapter-specific
 printk helpers
In-Reply-To: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>
References: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com>
Message-ID: <aUql_tZisfH8E1bq@hovoldconsulting.com>

On Tue, Dec 23, 2025 at 11:02:22AM +0100, Bartosz Golaszewski wrote:
> It's been another year of discussing the object life-time problems at
> conferences. I2C is one of the offenders and its problems are more
> complex than those of some other subsystems. It seems the revocable[1]
> API may make its way into the kernel this year but even with it in
> place, I2C won't be able to use it as there's currently nothing to
> *revoke*. The struct device is embedded within the i2c_adapter struct
> whose lifetime is tied to the provider device being bound to its driver.
> 
> Fixing this won't be fast and easy but nothing's going to happen if we
> don't start chipping away at it. The ultimate goal in order to be able
> to use an SRCU-based solution (revocable or otherwise) is to convert the
> embedded struct device in struct i2c_adapter into an __rcu pointer that
> can be *revoked*. To that end we need to hide all dereferences of
> adap->dev in drivers.

No, this is not the way to do it. You start with designing and showing
what the end result will look like *before* you start rewriting world
like you are doing here.

We should not be making driver code less readable just to address some
really niche corner cases like hot pluggable i2c controllers.

But in any case, don't get ahead of things by posting changes that we
most likely don't want in the end anyway.

> This series addresses the usage of adap->dev in device printk() helpers
> (dev_err() et al). It introduces a set of i2c-specific helpers and
> starts using them across bus drivers. For now just 12 patches but I'll
> keep on doing it if these get accepted. Once these get upstream for
> v6.20/7.0, we'll be able to also start converting i2c drivers outside of
> drivers/i2c/.

Same comment applies to the other two series you posted today.

Johan


From krzysztof.kozlowski at oss.qualcomm.com  Tue Dec 23 06:27:27 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 15:27:27 +0100
Subject: [PATCH 1/2] Documentation/process: maintainer-soc: Be more explicit about defconfig
Message-ID: <20251223142726.73417-3-krzysztof.kozlowski@oss.qualcomm.com>

It is already documented but people still send noticeable amount of
patches ignoring the rule - get_maintainers.pl does not work on
arm64/configs/defconfig or any other shared ARM defconfig.

Be more explicit, that one must not rely on typical/simple approach
here for getting To/Cc list.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

---

Incorrectly addressed patches for arm64/defconfig are around ~2 per month...
---
 Documentation/process/maintainer-soc.rst | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/Documentation/process/maintainer-soc.rst b/Documentation/process/maintainer-soc.rst
index 3ba886f52a51..014c639022b2 100644
--- a/Documentation/process/maintainer-soc.rst
+++ b/Documentation/process/maintainer-soc.rst
@@ -57,8 +57,10 @@ Submitting Patches for Given SoC
 
 All typical platform related patches should be sent via SoC submaintainers
 (platform-specific maintainers).  This includes also changes to per-platform or
-shared defconfigs (scripts/get_maintainer.pl might not provide correct
-addresses in such case).
+shared defconfigs. Note that scripts/get_maintainer.pl might not provide
+correct addresses for the shared defconfig, so ignore its output and manually
+create CC-list based on MAINTAINERS file or use something like
+``scripts/get_maintainer.pl -f drivers/soc/FOO/``).
 
 Submitting Patches to the Main SoC Maintainers
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Tue Dec 23 06:27:28 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 15:27:28 +0100
Subject: [PATCH 2/2] Documentation/process: maintainer-soc: Mark 'make' as commands
In-Reply-To: <20251223142726.73417-3-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251223142726.73417-3-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <20251223142726.73417-4-krzysztof.kozlowski@oss.qualcomm.com>

Improve readability of the docs by marking 'make dtbs/dtbs_check' as
shell commands.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 Documentation/process/maintainer-soc.rst | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Documentation/process/maintainer-soc.rst b/Documentation/process/maintainer-soc.rst
index 014c639022b2..7d6bad989ad8 100644
--- a/Documentation/process/maintainer-soc.rst
+++ b/Documentation/process/maintainer-soc.rst
@@ -116,9 +116,9 @@ coordinating how the changes get merged through different maintainer trees.
 Usually the branch that includes a driver change will also include the
 corresponding change to the devicetree binding description, to ensure they are
 in fact compatible.  This means that the devicetree branch can end up causing
-warnings in the "make dtbs_check" step.  If a devicetree change depends on
+warnings in the ``make dtbs_check`` step.  If a devicetree change depends on
 missing additions to a header file in include/dt-bindings/, it will fail the
-"make dtbs" step and not get merged.
+``make dtbs`` step and not get merged.
 
 There are multiple ways to deal with this:
 
-- 
2.51.0



From krzk at kernel.org  Tue Dec 23 06:32:06 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 15:32:06 +0100
Subject: [PATCH 2/8] phy: axiado: add Arasan eMMC-PHY for Axiado
In-Reply-To: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-2-5457d0ebcdb4@axiado.com>
References: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-0-5457d0ebcdb4@axiado.com>
 <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-2-5457d0ebcdb4@axiado.com>
Message-ID: <20251223-grumpy-daft-loon-6a6186@quoll>

On Mon, Dec 22, 2025 at 04:45:01PM +0800, Tzu-Hao Wei wrote:
> @@ -15,6 +15,7 @@ obj-$(CONFIG_PHY_AIROHA_PCIE)		+= phy-airoha-pcie.o
>  obj-$(CONFIG_PHY_NXP_PTN3222)		+= phy-nxp-ptn3222.o


Where is maintainers file update in this patch? Why shall we take
unmaintained code?

>  obj-y					+= allwinner/	\
>  					   amlogic/	\
> +					   axiado/	\
>  					   broadcom/	\
>  					   cadence/	\
>  					   freescale/	\
> diff --git a/drivers/phy/axiado/Kconfig b/drivers/phy/axiado/Kconfig
> new file mode 100644
> index 0000000000000000000000000000000000000000..824114e6068da327308321b9884552ad33db9efc
> --- /dev/null
> +++ b/drivers/phy/axiado/Kconfig
> @@ -0,0 +1,15 @@
> +#
> +# PHY drivers for Axiado platforms
> +#
> +

Missing menuconfig or other if-block for groupping this with your ARCH
and COMPILE_TEST dependency.

Look how other NEW and MAINTAINED platforms did it.

> +config PHY_AX3000_EMMC
> +	tristate "Axiado eMMC PHY driver"
> +	select GENERIC_PHY
> +	help
> +	  This enables support for the eMMC PHY block found on the
> +	  Axiado AX3000 SoCs. The PHY provides the physical layer
> +	  interface used by the Arasan SDHCI host controller for emmc
> +	  signaling and timing adjustment.
> +
> +	  If you are building a kernel for AX3000 platform with
> +	  eMMC storage, say Y or N.

...


> +static void arasan_emmc_phy_write(struct axiado_emmc_phy *ax_phy, u32 offset, u32 data)
> +{
> +	writel(data, ax_phy->reg_base + offset);
> +}
> +
> +static int arasan_emmc_phy_read(struct axiado_emmc_phy *ax_phy, u32 offset)

Useless wrappers. Just use readl/writel directly. You are not making
code more readable.

> +{
> +	u32 val = readl(ax_phy->reg_base + offset);
> +
> +	return val;
> +}
> +
> +static int axiado_emmc_phy_init(struct phy *phy)
> +{
> +	u32 val;
> +	ktime_t timeout;
> +
> +	struct axiado_emmc_phy *ax_phy = phy_get_drvdata(phy);
> +
> +	val = arasan_emmc_phy_read(ax_phy, PHY_CTRL_1);
> +	arasan_emmc_phy_write(ax_phy, PHY_CTRL_1, val | RETB_ENBL | RTRIM_EN);
> +
> +	val = arasan_emmc_phy_read(ax_phy, PHY_CTRL_3);
> +	arasan_emmc_phy_write(ax_phy, PHY_CTRL_3, val | PDB_ENBL);
> +
> +	/* Wait max 3000 ms */
> +	timeout = ktime_add_ms(ktime_get(), LOOP_TIMEOUT);
> +
> +	while (1) {
> +		bool timedout = ktime_after(ktime_get(), timeout);
> +
> +		if (arasan_emmc_phy_read(ax_phy, STATUS) & CALDONE_MASK)
> +			break;
> +
> +		if (timedout) {
> +			dev_err(&phy->dev, "CALDONE_MASK bit is not cleared.");
> +			return -ETIMEDOUT;
> +		}
> +		udelay(TIMEOUT_DELAY);
> +	}
> +
> +	val = arasan_emmc_phy_read(ax_phy, PHY_CTRL_1);
> +
> +	arasan_emmc_phy_write(ax_phy, PHY_CTRL_1, val | REN_CMD_EN | PU_CMD_EN);
> +
> +	val = arasan_emmc_phy_read(ax_phy, PHY_CTRL_2);
> +	arasan_emmc_phy_write(ax_phy, PHY_CTRL_2, val | REN_STRB);
> +
> +	val = arasan_emmc_phy_read(ax_phy, PHY_CTRL_3);
> +	arasan_emmc_phy_write(ax_phy, PHY_CTRL_3, val | MAX_CLK_BUF0 |
> +			MAX_CLK_BUF1 | MAX_CLK_BUF2);
> +
> +	val = arasan_emmc_phy_read(ax_phy, CAP_REG_IN_S1_MSB);
> +	arasan_emmc_phy_write(ax_phy, CAP_REG_IN_S1_MSB, CLK_MULTIPLIER);
> +
> +	val = arasan_emmc_phy_read(ax_phy, PHY_CTRL_3);
> +	arasan_emmc_phy_write(ax_phy, PHY_CTRL_3, val | SEL_DLY_RXCLK |
> +			SEL_DLY_TXCLK);
> +
> +	return 0;
> +}
> +
> +static int axiado_emmc_phy_power_on(struct phy *phy)
> +{
> +	struct axiado_emmc_phy *ax_phy = phy_get_drvdata(phy);
> +
> +	u32 val;
> +	ktime_t timeout;
> +
> +	val = arasan_emmc_phy_read(ax_phy, PHY_CTRL_1);
> +	arasan_emmc_phy_write(ax_phy, PHY_CTRL_1, val | RETB_ENBL);
> +
> +	val = arasan_emmc_phy_read(ax_phy, PHY_CTRL_3);
> +	arasan_emmc_phy_write(ax_phy, PHY_CTRL_3, val | PDB_ENBL);
> +
> +	val = arasan_emmc_phy_read(ax_phy, PHY_CTRL_2);
> +	arasan_emmc_phy_write(ax_phy, PHY_CTRL_2, val | OTAP_SEL(OTAP_DLY));
> +
> +	arasan_emmc_phy_read(ax_phy, PHY_CTRL_2);
> +
> +	val = arasan_emmc_phy_read(ax_phy, PHY_CTRL_1);
> +	arasan_emmc_phy_write(ax_phy, PHY_CTRL_1, val | DLL_TRM(DLL_TRM_ICP));
> +
> +	arasan_emmc_phy_write(ax_phy, STATUS, 0x00);
> +
> +	val = arasan_emmc_phy_read(ax_phy, PHY_CTRL_3);
> +	arasan_emmc_phy_write(ax_phy, PHY_CTRL_3, val | DLL_FRQSEL(FRQ_SEL));
> +
> +	/* Wait max 3000 ms */
> +	timeout = ktime_add_ms(ktime_get(), LOOP_TIMEOUT);
> +
> +	while (1) {

You proper read_poll loop.

> +		bool timedout = ktime_after(ktime_get(), timeout);
> +
> +		if (arasan_emmc_phy_read(ax_phy, STATUS) & DLL_RDY_MASK)
> +			break;
> +
> +		if (timedout) {
> +			dev_err(&phy->dev, "DLL_RDY_MASK bit is not cleared.");
> +			return -ETIMEDOUT;
> +		}
> +		udelay(TIMEOUT_DELAY);

...

> +static int axiado_emmc_phy_probe(struct platform_device *pdev)
> +{
> +	struct axiado_emmc_phy *ax_phy;
> +	struct phy_provider *phy_provider;
> +	struct device *dev = &pdev->dev;
> +	const struct of_device_id *id;
> +	struct phy *generic_phy;
> +	struct resource *res;
> +
> +	if (!dev->of_node)
> +		return -ENODEV;
> +
> +	ax_phy = devm_kzalloc(dev, sizeof(*ax_phy), GFP_KERNEL);
> +	if (!ax_phy)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +

Use proper wrapper to combine get resource and ioremap.

> +	ax_phy->reg_base = devm_ioremap_resource(&pdev->dev, res);
> +

Drop blank line, there's never such.

> +	if (IS_ERR(ax_phy->reg_base))
> +		return PTR_ERR(ax_phy->reg_base);
> +
> +	id = of_match_node(axiado_emmc_phy_of_match, pdev->dev.of_node);
> +	if (!id) {
> +		dev_err(dev, "failed to get match_node\n");

What is the point of this? You do not use this match at all, no other
devices. How can your device bind and still fail the match?

Drop

> +		return -EINVAL;
> +	}
> +
> +	generic_phy = devm_phy_create(dev, dev->of_node, &axiado_emmc_phy_ops);
> +	if (IS_ERR(generic_phy)) {
> +		dev_err(dev, "failed to create PHY\n");
> +		return PTR_ERR(generic_phy);

Syntax is - return dev_err_probe.

Didn't Axiado receive this feedback before? Are you sure that you have
procedures set inside to avoid repeating same mistakes?

Best regards,
Krzysztof



From krzk at kernel.org  Tue Dec 23 06:33:14 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 15:33:14 +0100
Subject: [PATCH 0/8] Add Axiado AX3000 eMMC Host Controller Support
In-Reply-To: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-0-5457d0ebcdb4@axiado.com>
References: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-0-5457d0ebcdb4@axiado.com>
Message-ID: <20251223-black-auk-of-priority-8b48ae@quoll>

On Mon, Dec 22, 2025 at 04:44:59PM +0800, Tzu-Hao Wei wrote:
> This patch series adds support for the eMMC host controller found on
> the Axiado AX3000 SoC. The implementation includes support for an
> external Arasan eMMC PHY that enables HS200 mode operation at 200 MHz,
> significantly improving performance over the default 25 MHz operation.
> 
> Hardware Details:
> 
> Arasan eMMC host controller on AX3000 SoC
> External Arasan eMMC PHY (different from internal PHY supported
> by the standard sdhci-of-arasan driver)
> Support for HS200 mode (200 MHz) operation
> Integration with existing SDHCI framework
> Implementation Overview:
> The series adds support for the external eMMC PHY required for HS200
> mode. The existing sdhci-of-arasan.c driver supports internal PHY
> configurations, but the AX3000 uses an external PHY that requires
> different configuration. The PHY driver was implemented based on the
> reference code in sdhci-pci-arasan.c as recommended by the Arasan team.
> 
> This series includes:
> 1. Device tree bindings for the eMMC PHY
> 2. PHY driver implementation for the external Arasan eMMC PHY
> 3. Integration of PHY support into the sdhci-of-arasan host driver
> 4. Device tree bindings for the eMMC host controller variant
> 5. Device tree source files for the SoC and EVK board
> 6. MAINTAINERS file update

You completely disorganized the patch.. dts is mixed all over driver
code, you combined two or three completely independent subsystems into
one.

Read submitting patches in DT dir to understand how DTS must be sent.


Best regards,
Krzysztof



From krzk at kernel.org  Tue Dec 23 06:34:05 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 15:34:05 +0100
Subject: [PATCH 6/8] mmc: host: axiado: add AX3000 eMMC PHY support to
 sdhci-of-arasan
In-Reply-To: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-6-5457d0ebcdb4@axiado.com>
References: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-0-5457d0ebcdb4@axiado.com>
 <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-6-5457d0ebcdb4@axiado.com>
Message-ID: <20251223-optimal-ochre-kestrel-a8cb1c@quoll>

On Mon, Dec 22, 2025 at 04:45:05PM +0800, Tzu-Hao Wei wrote:
> From: SriNavmani A <srinavmani at axiado.com>
> 
> Add support for the external eMMC PHY used on the AX3000 SoC in the
> sdhci-of-arasan driver. The default Arasan host driver operates at
> 25 MHz, but with the external PHY support, the controller can achieve
> HS200 mode operation at 200 MHz.
> 
> This change integrates the AX3000 eMMC PHY driver with the existing
> sdhci-of-arasan host controller driver to enable high-speed eMMC
> operations.
> 
> Signed-off-by: Tzu-Hao Wei <twei at axiado.com>
> ---
>  drivers/mmc/host/sdhci-of-arasan.c | 20 +++++++++++++-------

Why do you mix mmc, phy and soc into one patchset?

>  1 file changed, 13 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
> index ab7f0ffe7b4f007a58eb0a26868b08b0b02b40f3..2d4f64e9014ae168957113478edc11209cd76b64 100644
> --- a/drivers/mmc/host/sdhci-of-arasan.c
> +++ b/drivers/mmc/host/sdhci-of-arasan.c
> @@ -1547,6 +1547,10 @@ static const struct of_device_id sdhci_arasan_of_match[] = {
>  		.compatible = "arasan,sdhci-5.1",
>  		.data = &sdhci_arasan_generic_data,
>  	},
> +	{
> +		.compatible = "axiado,ax3000-sdhci-5.1-emmc",
> +		.data = &sdhci_arasan_generic_data,
> +	},
>  	{
>  		.compatible = "arasan,sdhci-4.9a",
>  		.data = &sdhci_arasan_generic_data,
> @@ -2019,15 +2023,17 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
>  			goto unreg_clk;
>  		}
>  
> -		host->mmc_host_ops.hs400_enhanced_strobe =
> +		if (!of_device_is_compatible(np, "axiado,ax3000-sdhci-5.1-emmc")) {

No, don't sprinkle compatibles all around. You should use driver match
data for this.

Best regards,
Krzysztof



From krzk at kernel.org  Tue Dec 23 06:34:52 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 15:34:52 +0100
Subject: [PATCH 8/8] arm64: dts: axiado: enable sdhci host
In-Reply-To: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-8-5457d0ebcdb4@axiado.com>
References: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-0-5457d0ebcdb4@axiado.com>
 <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-8-5457d0ebcdb4@axiado.com>
Message-ID: <20251223-fat-nickel-copperhead-9adeed@quoll>

On Mon, Dec 22, 2025 at 04:45:07PM +0800, Tzu-Hao Wei wrote:
> From: SriNavmani A <srinavmani at axiado.com>
> 
> Enable the SDHCI host controller for eMMC support on the AX3000 EVK
> evaluation board by referencing the SDHCI node defined in the SoC
> device tree include file. This enables eMMC functionality on the
> evaluation board.
> 
> Signed-off-by: Tzu-Hao Wei <twei at axiado.com>

Why DTS is both BEFORE and AFTER drivers? This is a total mess.


> ---
>  arch/arm64/boot/dts/axiado/ax3000-evk.dts | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/axiado/ax3000-evk.dts b/arch/arm64/boot/dts/axiado/ax3000-evk.dts
> index b86e969625573bf92bdd5e4435ea571dd7500de2..a5cc75dfbe554749201b0910ec268c899bc5246c 100644
> --- a/arch/arm64/boot/dts/axiado/ax3000-evk.dts
> +++ b/arch/arm64/boot/dts/axiado/ax3000-evk.dts
> @@ -80,3 +80,11 @@ &uart2 {
>  &uart3 {
>  	status = "okay";
>  };
> +
> +&emmc_phy {

Axiado already received comment to read DTS coding style. Did you read
it?

Best regards,
Krzysztof



From mikko.rapeli at linaro.org  Tue Dec 23 06:36:36 2025
From: mikko.rapeli at linaro.org (Mikko Rapeli)
Date: Tue, 23 Dec 2025 16:36:36 +0200
Subject: [PATCH] arm64: defconfig: remove SLIM_QCOM_CTRL
In-Reply-To: <4f99f3ba-ef5b-4163-ad1a-99527dd96f8a@kernel.org>
References: <20251223134807.3543642-1-mikko.rapeli@linaro.org>
 <c06878f7-bb93-4de2-b54a-e97fbc1a333e@kernel.org>
 <aUqgFCgmBy7H9yW0@nuoska>
 <4f99f3ba-ef5b-4163-ad1a-99527dd96f8a@kernel.org>
Message-ID: <aUqo9AV2zSJqr_oE@nuoska>

Hi,

On Tue, Dec 23, 2025 at 03:10:56PM +0100, Krzysztof Kozlowski wrote:
> On 23/12/2025 14:58, Mikko Rapeli wrote:
> > On Tue, Dec 23, 2025 at 02:51:45PM +0100, Krzysztof Kozlowski wrote:
> >> On 23/12/2025 14:48, Mikko Rapeli wrote:
> >>> It has been removed by:
> >>
> >> by commit foo bar (see also checkpatch and submitting patches).
> > 
> > Ok will duplicate the info then.
> > 
> >>>
> >>> Fixes: 7cbba32a2d62 ("slimbus: qcom: remove unused qcom controller driver")
> >>>
> >>
> >> Drop blank line
> > 
> > Ok
> >  
> >> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
> >>
> >> You anyway need to send to proper mailing list for this soc (Qcom), not
> >> random folks.
> > 
> > Which proper list?
> 
> The list for this soc. get_maintainers will tell you that - run it on
> any soc driver for that soc.
> 
> > 
> > I sent to addresses reported by get_maintainers.pl.
> 
> There is no output of get_maintainers.pl for this file. It's one of
> cases where script does not work (I think already documented in
> maintainer soc profile).

Sorry, I don't get it. This issue is a generic one since now arm64 defconfig
has one unknown option. Tools which check kernel config for unknown options
trigger warnings when arm64 defconfig is used.

If get_maintainers.pl is broken for this file, then please fix it. I don't
know how to fix it.

Cheers,

-Mikko


From krzk at kernel.org  Tue Dec 23 06:43:01 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 15:43:01 +0100
Subject: [PATCH 5/8] dt-bindings: mmc: axiado: Add axiado eMMC variant
In-Reply-To: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-5-5457d0ebcdb4@axiado.com>
References: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-0-5457d0ebcdb4@axiado.com>
 <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-5-5457d0ebcdb4@axiado.com>
Message-ID: <20251223-ludicrous-carmine-mushroom-983c69@quoll>

On Mon, Dec 22, 2025 at 04:45:04PM +0800, Tzu-Hao Wei wrote:
> From: SriNavmani A <srinavmani at axiado.com>
> 
> Add device tree binding variant for the Axiado AX3000 Arasan eMMC
> controller. This variant identifies the specific eMMC controller
> implementation used on the AX3000 SoC and enables the appropriate
> driver configuration.
> 
> Signed-off-by: Tzu-Hao Wei <twei at axiado.com>
> ---
>  .../devicetree/bindings/mmc/arasan,sdhci.yaml          | 18 ++++++++++++++++++
>  1 file changed, 18 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml b/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml
> index 8e79de97b242a698a2c555b0b94e2975b1761710..47d0e35efea00bf7b1927bd0cfa39c86f0137d44 100644
> --- a/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml
> +++ b/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml
> @@ -106,6 +106,12 @@ properties:
>          description:
>            For this device it is strongly suggested to include
>            arasan,soc-ctl-syscon.
> +      - items:
> +          - const: axiado,ax3000-sdhci-5.1-emmc
> +          - const: arasan,sdhci-5.1
> +        description:
> +          For this device it is strongly suggested to include
> +          clock-output-names and '#clock-cells'.
>  
>    reg:
>      maxItems: 1
> @@ -334,3 +340,15 @@ examples:
>                     <&scmi_clk KEEM_BAY_PSS_SD0>;
>            arasan,soc-ctl-syscon = <&sd0_phy_syscon>;
>      };
> +
> +  - |
> +    mmc at 86000000 {

No need for a new example. Please writing bindings and writing schema
docs first.

Best regards,
Krzysztof



From laurent.pinchart at ideasonboard.com  Tue Dec 23 07:02:56 2025
From: laurent.pinchart at ideasonboard.com (Laurent Pinchart)
Date: Tue, 23 Dec 2025 17:02:56 +0200
Subject: [PATCH 1/2] Documentation/process: maintainer-soc: Be more
 explicit about defconfig
In-Reply-To: <20251223142726.73417-3-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251223142726.73417-3-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <20251223150256.GI9817@pendragon.ideasonboard.com>

Hi Krzysztof,

On Tue, Dec 23, 2025 at 03:27:27PM +0100, Krzysztof Kozlowski wrote:
> It is already documented but people still send noticeable amount of
> patches ignoring the rule - get_maintainers.pl does not work on
> arm64/configs/defconfig or any other shared ARM defconfig.
> 
> Be more explicit, that one must not rely on typical/simple approach
> here for getting To/Cc list.
> 
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
> 
> ---
> 
> Incorrectly addressed patches for arm64/defconfig are around ~2 per month...
> ---
>  Documentation/process/maintainer-soc.rst | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/process/maintainer-soc.rst b/Documentation/process/maintainer-soc.rst
> index 3ba886f52a51..014c639022b2 100644
> --- a/Documentation/process/maintainer-soc.rst
> +++ b/Documentation/process/maintainer-soc.rst
> @@ -57,8 +57,10 @@ Submitting Patches for Given SoC
>  
>  All typical platform related patches should be sent via SoC submaintainers
>  (platform-specific maintainers).  This includes also changes to per-platform or
> -shared defconfigs (scripts/get_maintainer.pl might not provide correct
> -addresses in such case).
> +shared defconfigs. Note that scripts/get_maintainer.pl might not provide
> +correct addresses for the shared defconfig, so ignore its output and manually
> +create CC-list based on MAINTAINERS file or use something like
> +``scripts/get_maintainer.pl -f drivers/soc/FOO/``).

I fear this will be another piece of documentation that people won't
read. It would be more effective to implement custom logic in
get_maintainer.pl (or at least output an informative message).

>  
>  Submitting Patches to the Main SoC Maintainers
>  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

-- 
Regards,

Laurent Pinchart


From rafael at beims.me  Tue Dec 23 07:02:54 2025
From: rafael at beims.me (Rafael Beims)
Date: Tue, 23 Dec 2025 12:02:54 -0300
Subject: [PATCH] phy: freescale: imx8m-pcie: assert phy reset during power on
Message-ID: <20251223150254.1075221-1-rafael@beims.me>

From: Rafael Beims <rafael.beims at toradex.com>

After U-Boot initializes PCIe with "pcie enum", Linux fails to detect
an NVMe disk on some boot cycles with:

  phy phy-32f00000.pcie-phy.0: phy poweron failed --> -110

Discussion with NXP identified that the iMX8MP PCIe PHY PLL may fail to
lock when re-initialized without a reset cycle [1].

The issue reproduces on 7% of tested hardware platforms, with a 30-40%
failure rate per affected device across boot cycles.

Insert a reset cycle in the power-on routine to ensure the PHY is
initialized from a known state.

[1] https://community.nxp.com/t5/i-MX-Processors/iMX8MP-PCIe-initialization-in-U-Boot/m-p/2248437#M242401

Signed-off-by: Rafael Beims <rafael.beims at toradex.com>
Cc: stable at vger.kernel.org
---
 drivers/phy/freescale/phy-fsl-imx8m-pcie.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/phy/freescale/phy-fsl-imx8m-pcie.c b/drivers/phy/freescale/phy-fsl-imx8m-pcie.c
index 68fcc8114d75..7f5600103a00 100644
--- a/drivers/phy/freescale/phy-fsl-imx8m-pcie.c
+++ b/drivers/phy/freescale/phy-fsl-imx8m-pcie.c
@@ -89,7 +89,8 @@ static int imx8_pcie_phy_power_on(struct phy *phy)
 			writel(imx8_phy->tx_deemph_gen2,
 			       imx8_phy->base + PCIE_PHY_TRSV_REG6);
 		break;
-	case IMX8MP: /* Do nothing. */
+	case IMX8MP:
+		reset_control_assert(imx8_phy->reset);
 		break;
 	}
 
-- 
2.51.0



From brgl at kernel.org  Tue Dec 23 07:11:08 2025
From: brgl at kernel.org (Bartosz Golaszewski)
Date: Tue, 23 Dec 2025 16:11:08 +0100
Subject: [PATCH 00/12] i2c: add and start using i2c_adapter-specific
 printk helpers
In-Reply-To: <aUql_tZisfH8E1bq@hovoldconsulting.com>
References: <20251223-i2c-printk-helpers-v1-0-46a08306afdb@oss.qualcomm.com> <aUql_tZisfH8E1bq@hovoldconsulting.com>
Message-ID: <CAMRc=MeHL5=s=ciUjHGw_poKpeVMWVi_2LBDFY_ugvXBaaE0vA@mail.gmail.com>

On Tue, Dec 23, 2025 at 3:24?PM Johan Hovold <johan at kernel.org> wrote:
>
> On Tue, Dec 23, 2025 at 11:02:22AM +0100, Bartosz Golaszewski wrote:
> > It's been another year of discussing the object life-time problems at
> > conferences. I2C is one of the offenders and its problems are more
> > complex than those of some other subsystems. It seems the revocable[1]
> > API may make its way into the kernel this year but even with it in
> > place, I2C won't be able to use it as there's currently nothing to
> > *revoke*. The struct device is embedded within the i2c_adapter struct
> > whose lifetime is tied to the provider device being bound to its driver.
> >
> > Fixing this won't be fast and easy but nothing's going to happen if we
> > don't start chipping away at it. The ultimate goal in order to be able
> > to use an SRCU-based solution (revocable or otherwise) is to convert the
> > embedded struct device in struct i2c_adapter into an __rcu pointer that
> > can be *revoked*. To that end we need to hide all dereferences of
> > adap->dev in drivers.
>
> No, this is not the way to do it. You start with designing and showing
> what the end result will look like *before* you start rewriting world
> like you are doing here.
>

The paragraph you're commenting under explains exactly what I propose
to do: move struct device out of struct i2c_adapter and protect the
pointer storing its address with SRCU. This is a well-known design
that's being generalized to a common "revocable" API which will
possibly be available upstream by the time we're ready to use it.

You know I can't possibly *show* the end result in a single series
because - as the paragraph before explains - we need to first hide all
direct dereferences of struct device in struct i2c_adapter behind
dedicated interfaces so that we when do the conversion, it'll affect
only a limited number of places. It can't realistically be done at
once.

> We should not be making driver code less readable just to address some
> really niche corner cases like hot pluggable i2c controllers.
>
> But in any case, don't get ahead of things by posting changes that we
> most likely don't want in the end anyway.
>

The changes I sent are the result of another discussion with Wolfram
at LPC so I'll definitely wait for his take on it before dropping
anything.

Bartosz


From frederic at kernel.org  Tue Dec 23 07:16:29 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Tue, 23 Dec 2025 16:16:29 +0100
Subject: [PATCH 13/31] cpuset: Update HK_TYPE_DOMAIN cpumask from cpuset
In-Reply-To: <e0c0f8b7-112f-40d7-b211-89065e9003b2@huaweicloud.com>
References: <20251105210348.35256-1-frederic@kernel.org>
 <20251105210348.35256-14-frederic@kernel.org>
 <e0c0f8b7-112f-40d7-b211-89065e9003b2@huaweicloud.com>
Message-ID: <aUqyTUm2NipItcVu@localhost.localdomain>

Le Sat, Nov 08, 2025 at 05:05:10PM +0800, Chen Ridong a ?crit :
> > +int housekeeping_update(struct cpumask *mask, enum hk_type type)
> > +{
> > +	struct cpumask *trial, *old = NULL;
> > +
> > +	if (type != HK_TYPE_DOMAIN)
> > +		return -ENOTSUPP;
> > +
> > +	trial = kmalloc(cpumask_size(), GFP_KERNEL);
> > +	if (!trial)
> > +		return -ENOMEM;
> > +
> > +	cpumask_andnot(trial, housekeeping_cpumask(HK_TYPE_DOMAIN_BOOT), mask);
> 
> Since there's no comment for the 'mask' parameter, would it be better to name it 'isol_mask'? This
> would make it clearer that this is the isolation mask input and what is doing
> here.

Good point! I made the change.

Thanks.

-- 
Frederic Weisbecker
SUSE Labs


From frederic at kernel.org  Tue Dec 23 07:17:55 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Tue, 23 Dec 2025 16:17:55 +0100
Subject: [PATCH 17/31] cpuset: Propagate cpuset isolation update to
 workqueue through housekeeping
In-Reply-To: <e0b3f050-ef2e-478e-9e22-5f800b86ee42@huaweicloud.com>
References: <20251105210348.35256-1-frederic@kernel.org>
 <20251105210348.35256-18-frederic@kernel.org>
 <e0b3f050-ef2e-478e-9e22-5f800b86ee42@huaweicloud.com>
Message-ID: <aUqyo58-CDReEm10@localhost.localdomain>

Le Thu, Nov 06, 2025 at 08:55:42AM +0800, Chen Ridong a ?crit :
> 
> 
> On 2025/11/6 5:03, Frederic Weisbecker wrote:
> > Until now, cpuset would propagate isolated partition changes to
> > workqueues so that unbound workers get properly reaffined.
> > 
> > Since housekeeping now centralizes, synchronize and propagates isolation
> > cpumask changes, perform the work from that subsystem for consolidation
> > and consistency purposes.
> > 
> > For simplification purpose, the target function is adapted to take the
> > new housekeeping mask instead of the isolated mask.
> > 
> > Suggested-by: Tejun Heo <tj at kernel.org>
> > Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
> > ---
> >  include/linux/workqueue.h |  2 +-
> >  init/Kconfig              |  1 +
> >  kernel/cgroup/cpuset.c    | 14 ++++++--------
> >  kernel/sched/isolation.c  |  4 +++-
> >  kernel/workqueue.c        | 17 ++++++++++-------
> >  5 files changed, 21 insertions(+), 17 deletions(-)
> > 
> > diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
> > index dabc351cc127..a4749f56398f 100644
> > --- a/include/linux/workqueue.h
> > +++ b/include/linux/workqueue.h
> > @@ -588,7 +588,7 @@ struct workqueue_attrs *alloc_workqueue_attrs_noprof(void);
> >  void free_workqueue_attrs(struct workqueue_attrs *attrs);
> >  int apply_workqueue_attrs(struct workqueue_struct *wq,
> >  			  const struct workqueue_attrs *attrs);
> > -extern int workqueue_unbound_exclude_cpumask(cpumask_var_t cpumask);
> > +extern int workqueue_unbound_housekeeping_update(const struct cpumask *hk);
> >  
> >  extern bool queue_work_on(int cpu, struct workqueue_struct *wq,
> >  			struct work_struct *work);
> > diff --git a/init/Kconfig b/init/Kconfig
> > index cab3ad28ca49..a1b3a3b66bfc 100644
> > --- a/init/Kconfig
> > +++ b/init/Kconfig
> > @@ -1247,6 +1247,7 @@ config CPUSETS
> >  	bool "Cpuset controller"
> >  	depends on SMP
> >  	select UNION_FIND
> > +	select CPU_ISOLATION
> >  	help
> >  	  This option will let you create and manage CPUSETs which
> >  	  allow dynamically partitioning a system into sets of CPUs and
> > diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> > index b04a4242f2fa..ea102e4695a5 100644
> > --- a/kernel/cgroup/cpuset.c
> > +++ b/kernel/cgroup/cpuset.c
> > @@ -1392,7 +1392,7 @@ static bool partition_xcpus_del(int old_prs, struct cpuset *parent,
> >  	return isolcpus_updated;
> >  }
> >  
> > -static void update_unbound_workqueue_cpumask(bool isolcpus_updated)
> > +static void update_housekeeping_cpumask(bool isolcpus_updated)
> >  {
> >  	int ret;
> >  
> > @@ -1401,8 +1401,6 @@ static void update_unbound_workqueue_cpumask(bool isolcpus_updated)
> >  	if (!isolcpus_updated)
> >  		return;
> >  
> > -	ret = workqueue_unbound_exclude_cpumask(isolated_cpus);
> > -	WARN_ON_ONCE(ret < 0);
> >  	ret = housekeeping_update(isolated_cpus, HK_TYPE_DOMAIN);
> >  	WARN_ON_ONCE(ret < 0);
> >  }
> > @@ -1558,7 +1556,7 @@ static int remote_partition_enable(struct cpuset *cs, int new_prs,
> >  	list_add(&cs->remote_sibling, &remote_children);
> >  	cpumask_copy(cs->effective_xcpus, tmp->new_cpus);
> >  	spin_unlock_irq(&callback_lock);
> > -	update_unbound_workqueue_cpumask(isolcpus_updated);
> > +	update_housekeeping_cpumask(isolcpus_updated);
> >  	cpuset_force_rebuild();
> >  	cs->prs_err = 0;
> >  
> > @@ -1599,7 +1597,7 @@ static void remote_partition_disable(struct cpuset *cs, struct tmpmasks *tmp)
> >  	compute_excpus(cs, cs->effective_xcpus);
> >  	reset_partition_data(cs);
> >  	spin_unlock_irq(&callback_lock);
> > -	update_unbound_workqueue_cpumask(isolcpus_updated);
> > +	update_housekeeping_cpumask(isolcpus_updated);
> >  	cpuset_force_rebuild();
> >  
> >  	/*
> > @@ -1668,7 +1666,7 @@ static void remote_cpus_update(struct cpuset *cs, struct cpumask *xcpus,
> >  	if (xcpus)
> >  		cpumask_copy(cs->exclusive_cpus, xcpus);
> >  	spin_unlock_irq(&callback_lock);
> > -	update_unbound_workqueue_cpumask(isolcpus_updated);
> > +	update_housekeeping_cpumask(isolcpus_updated);
> >  	if (adding || deleting)
> >  		cpuset_force_rebuild();
> >  
> > @@ -2027,7 +2025,7 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
> >  		WARN_ON_ONCE(parent->nr_subparts < 0);
> >  	}
> >  	spin_unlock_irq(&callback_lock);
> > -	update_unbound_workqueue_cpumask(isolcpus_updated);
> > +	update_housekeeping_cpumask(isolcpus_updated);
> >  
> >  	if ((old_prs != new_prs) && (cmd == partcmd_update))
> >  		update_partition_exclusive_flag(cs, new_prs);
> > @@ -3047,7 +3045,7 @@ static int update_prstate(struct cpuset *cs, int new_prs)
> >  	else if (isolcpus_updated)
> >  		isolated_cpus_update(old_prs, new_prs, cs->effective_xcpus);
> >  	spin_unlock_irq(&callback_lock);
> > -	update_unbound_workqueue_cpumask(isolcpus_updated);
> > +	update_housekeeping_cpumask(isolcpus_updated);
> >  
> 
> The patch [1] has been applied to cgroup/for-next, you may have to adapt it.
> 
> [1]:
> https://lore.kernel.org/cgroups/20251105043848.382703-6-longman at redhat.com/T/#u

Right, I just waited for -rc1 to pop-up before doing that.
v5 will follow shortly.

Thanks.

> 
> -- 
> Best regards,
> Ridong
> 

-- 
Frederic Weisbecker
SUSE Labs


From corbet at lwn.net  Tue Dec 23 07:23:43 2025
From: corbet at lwn.net (Jonathan Corbet)
Date: Tue, 23 Dec 2025 08:23:43 -0700
Subject: [PATCH 1/2] Documentation/process: maintainer-soc: Be more
 explicit about defconfig
In-Reply-To: <20251223142726.73417-3-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251223142726.73417-3-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <87ecolxlvk.fsf@trenco.lwn.net>

Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com> writes:

> It is already documented but people still send noticeable amount of
> patches ignoring the rule - get_maintainers.pl does not work on
> arm64/configs/defconfig or any other shared ARM defconfig.
>
> Be more explicit, that one must not rely on typical/simple approach
> here for getting To/Cc list.
>
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
>
> ---
>
> Incorrectly addressed patches for arm64/defconfig are around ~2 per month...
> ---
>  Documentation/process/maintainer-soc.rst | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/process/maintainer-soc.rst b/Documentation/process/maintainer-soc.rst
> index 3ba886f52a51..014c639022b2 100644
> --- a/Documentation/process/maintainer-soc.rst
> +++ b/Documentation/process/maintainer-soc.rst
> @@ -57,8 +57,10 @@ Submitting Patches for Given SoC
>  
>  All typical platform related patches should be sent via SoC submaintainers
>  (platform-specific maintainers).  This includes also changes to per-platform or
> -shared defconfigs (scripts/get_maintainer.pl might not provide correct
> -addresses in such case).
> +shared defconfigs. Note that scripts/get_maintainer.pl might not provide
> +correct addresses for the shared defconfig, so ignore its output and manually
> +create CC-list based on MAINTAINERS file or use something like
> +``scripts/get_maintainer.pl -f drivers/soc/FOO/``).
>  

Like Laurent, I don't see this as being effective.  Why is it that
get_maintainer.pl fails here?  It seems far better to fix that, if at
all possible, rather than expect random contributors to notice this text
and work around the problem...?

Thanks,

jon


From krzysztof.kozlowski at oss.qualcomm.com  Tue Dec 23 07:24:25 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 16:24:25 +0100
Subject: [PATCH] arm64: dts: cix: Use lowercase hex
Message-ID: <20251223152424.155253-2-krzysztof.kozlowski@oss.qualcomm.com>

The DTS code coding style expects lowercase hex for values and unit
addresses.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

---

Patches done with sed, verified with comparing unflattened DTB and
dtx_diff.
---
 arch/arm64/boot/dts/cix/sky1.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/cix/sky1.dtsi b/arch/arm64/boot/dts/cix/sky1.dtsi
index 64b76905cbff..fb8c826bbc97 100644
--- a/arch/arm64/boot/dts/cix/sky1.dtsi
+++ b/arch/arm64/boot/dts/cix/sky1.dtsi
@@ -523,7 +523,7 @@ pcie_x1_1_rc: pcie at a0e0000 {
 			reg-names = "reg", "cfg", "rcsu_strap", "rcsu_status", "msg";
 			ranges = <0x01000000 0x0 0x38100000 0x0 0x38100000 0x0 0x00100000>,
 				 <0x02000000 0x0 0x38200000 0x0 0x38200000 0x0 0x07e00000>,
-				 <0x43000000 0x0C 0x00000000 0x0C 0x00000000 0x04 0x00000000>;
+				 <0x43000000 0x0c 0x00000000 0x0c 0x00000000 0x04 0x00000000>;
 			#address-cells = <3>;
 			#size-cells = <2>;
 			bus-range = <0x30 0x5f>;
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Tue Dec 23 07:24:33 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 16:24:33 +0100
Subject: [PATCH] arm64: dts: axiado: Use lowercase hex
Message-ID: <20251223152432.155299-2-krzysztof.kozlowski@oss.qualcomm.com>

The DTS code coding style expects lowercase hex for values and unit
addresses.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

---

Patches done with sed, verified with comparing unflattened DTB and
dtx_diff.
---
 arch/arm64/boot/dts/axiado/ax3000.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/axiado/ax3000.dtsi b/arch/arm64/boot/dts/axiado/ax3000.dtsi
index 792f52e0c7dd..d515f3141529 100644
--- a/arch/arm64/boot/dts/axiado/ax3000.dtsi
+++ b/arch/arm64/boot/dts/axiado/ax3000.dtsi
@@ -480,7 +480,7 @@ uart0: serial at 80520000 {
 
 		uart1: serial at 805a0000 {
 			compatible = "axiado,ax3000-uart", "cdns,uart-r1p12";
-			reg = <0x00 0x805A0000 0x00 0x100>;
+			reg = <0x00 0x805a0000 0x00 0x100>;
 			interrupt-parent = <&gic500>;
 			interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
 			clock-names = "uart_clk", "pclk";
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Tue Dec 23 07:24:58 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 16:24:58 +0100
Subject: [PATCH 1/2] arm64: dts: arm: Use hyphen in node names
Message-ID: <20251223152457.155392-3-krzysztof.kozlowski@oss.qualcomm.com>

DTS coding style prefers hyphens instead of underscores in the node
names.  Change should be safe, because node names are not considered an
ABI.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

---

Patches done with sed, verified with comparing unflattened DTB and
dtx_diff.
---
 arch/arm64/boot/dts/arm/morello-fvp.dts | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/boot/dts/arm/morello-fvp.dts b/arch/arm64/boot/dts/arm/morello-fvp.dts
index 2072c0b72325..4a3f217555f7 100644
--- a/arch/arm64/boot/dts/arm/morello-fvp.dts
+++ b/arch/arm64/boot/dts/arm/morello-fvp.dts
@@ -25,25 +25,25 @@ bp_refclock24mhz: clock-24000000 {
 		clock-output-names = "bp:clock24mhz";
 	};
 
-	block_0: virtio_block at 1c170000 {
+	block_0: virtio-block at 1c170000 {
 		compatible = "virtio,mmio";
 		reg = <0x0 0x1c170000 0x0 0x200>;
 		interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
 	};
 
-	net_0: virtio_net at 1c180000 {
+	net_0: virtio-net at 1c180000 {
 		compatible = "virtio,mmio";
 		reg = <0x0 0x1c180000 0x0 0x200>;
 		interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
 	};
 
-	rng_0: virtio_rng at 1c190000 {
+	rng_0: virtio-rng at 1c190000 {
 		compatible = "virtio,mmio";
 		reg = <0x0 0x1c190000 0x0 0x200>;
 		interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
 	};
 
-	p9_0: virtio_p9 at 1c1a0000 {
+	p9_0: virtio-p9 at 1c1a0000 {
 		compatible = "virtio,mmio";
 		reg = <0x0 0x1c1a0000 0x0 0x200>;
 		interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Tue Dec 23 07:24:59 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 16:24:59 +0100
Subject: [PATCH 2/2] arm64: dts: arm: Use lowercase hex
In-Reply-To: <20251223152457.155392-3-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251223152457.155392-3-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <20251223152457.155392-4-krzysztof.kozlowski@oss.qualcomm.com>

The DTS code coding style expects lowercase hex for values and unit
addresses.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 arch/arm/boot/dts/arm/arm-realview-eb.dtsi    | 2 +-
 arch/arm/boot/dts/arm/arm-realview-pb1176.dts | 2 +-
 arch/arm/boot/dts/arm/arm-realview-pb11mp.dts | 2 +-
 arch/arm/boot/dts/arm/arm-realview-pbx.dtsi   | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boot/dts/arm/arm-realview-eb.dtsi b/arch/arm/boot/dts/arm/arm-realview-eb.dtsi
index 16f784da5a55..ae370d4eb9d8 100644
--- a/arch/arm/boot/dts/arm/arm-realview-eb.dtsi
+++ b/arch/arm/boot/dts/arm/arm-realview-eb.dtsi
@@ -234,7 +234,7 @@ oscclk0: clock-controller at c {
 				reg = <0x0c 0x04>;
 				#clock-cells = <0>;
 				lock-offset = <0x20>;
-				vco-offset = <0x0C>;
+				vco-offset = <0x0c>;
 				clocks = <&xtal24mhz>;
 			};
 			oscclk1: clock-controller at 10 {
diff --git a/arch/arm/boot/dts/arm/arm-realview-pb1176.dts b/arch/arm/boot/dts/arm/arm-realview-pb1176.dts
index b9b10cbd65aa..a75d8b107fe1 100644
--- a/arch/arm/boot/dts/arm/arm-realview-pb1176.dts
+++ b/arch/arm/boot/dts/arm/arm-realview-pb1176.dts
@@ -260,7 +260,7 @@ oscclk0: clock-controller at c {
 				reg = <0x0c 0x04>;
 				#clock-cells = <0>;
 				lock-offset = <0x20>;
-				vco-offset = <0x0C>;
+				vco-offset = <0x0c>;
 				clocks = <&xtal24mhz>;
 			};
 			oscclk1: clock-controller at 10 {
diff --git a/arch/arm/boot/dts/arm/arm-realview-pb11mp.dts b/arch/arm/boot/dts/arm/arm-realview-pb11mp.dts
index db1b6793cd2c..59c78def83f2 100644
--- a/arch/arm/boot/dts/arm/arm-realview-pb11mp.dts
+++ b/arch/arm/boot/dts/arm/arm-realview-pb11mp.dts
@@ -343,7 +343,7 @@ oscclk0: clock-controller at c {
 				reg = <0x0c 0x04>;
 				#clock-cells = <0>;
 				lock-offset = <0x20>;
-				vco-offset = <0x0C>;
+				vco-offset = <0x0c>;
 				clocks = <&xtal24mhz>;
 			};
 			oscclk1: clock-controller at 10 {
diff --git a/arch/arm/boot/dts/arm/arm-realview-pbx.dtsi b/arch/arm/boot/dts/arm/arm-realview-pbx.dtsi
index e625403a9456..0d3d96ffa6e6 100644
--- a/arch/arm/boot/dts/arm/arm-realview-pbx.dtsi
+++ b/arch/arm/boot/dts/arm/arm-realview-pbx.dtsi
@@ -256,7 +256,7 @@ oscclk0: clock-controller at c {
 				reg = <0x0c 0x04>;
 				#clock-cells = <0>;
 				lock-offset = <0x20>;
-				vco-offset = <0x0C>;
+				vco-offset = <0x0c>;
 				clocks = <&xtal24mhz>;
 			};
 			oscclk1: clock-controller at 10 {
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Tue Dec 23 07:25:11 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 16:25:11 +0100
Subject: [PATCH 1/2] arm64: dts: amlogic: Use hyphen in node names
Message-ID: <20251223152510.155463-3-krzysztof.kozlowski@oss.qualcomm.com>

DTS coding style prefers hyphens instead of underscores in the node
names.  Change should be safe, because node names are not considered an
ABI.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

---

Patches done with sed, verified with comparing unflattened DTB and
dtx_diff.
---
 arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi
index 13b7ac03f9b2..c9d9f3ddf73c 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi
+++ b/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi
@@ -780,7 +780,7 @@ int_mdio: mdio at 1 {
 					#address-cells = <1>;
 					#size-cells = <0>;
 
-					internal_ephy: ethernet_phy at 8 {
+					internal_ephy: ethernet-phy at 8 {
 						compatible = "ethernet-phy-id0180.3301",
 							     "ethernet-phy-ieee802.3-c22";
 						interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Tue Dec 23 07:25:12 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 16:25:12 +0100
Subject: [PATCH 2/2] arm64: dts: amlogic: Use lowercase hex
In-Reply-To: <20251223152510.155463-3-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251223152510.155463-3-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <20251223152510.155463-4-krzysztof.kozlowski@oss.qualcomm.com>

The DTS code coding style expects lowercase hex for values and unit
addresses.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi               | 4 ++--
 arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-an400.dts   | 2 +-
 arch/arm64/boot/dts/amlogic/meson-gxm-mecool-kiii-pro.dts | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi
index c9d9f3ddf73c..11e5323f95b7 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi
+++ b/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi
@@ -108,7 +108,7 @@ scmi_shmem: sram at 0 {
 	firmware {
 		scmi: scmi {
 			compatible = "arm,scmi-smc";
-			arm,smc-id = <0x820000C1>;
+			arm,smc-id = <0x820000c1>;
 			shmem = <&scmi_shmem>;
 			#address-cells = <1>;
 			#size-cells = <0>;
@@ -989,7 +989,7 @@ sd: mmc at 8a000 {
 			nand: nand-controller at 8d000 {
 				compatible = "amlogic,meson-axg-nfc";
 				reg = <0x0 0x8d000 0x0 0x200>,
-					<0x0 0x8C000 0x0 0x4>;
+					<0x0 0x8c000 0x0 0x4>;
 				reg-names = "nfc", "emmc";
 				interrupts = <GIC_SPI 87 IRQ_TYPE_EDGE_RISING>;
 				clocks = <&clkc_periphs CLKID_SYS_SD_EMMC_C>,
diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-an400.dts b/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-an400.dts
index c05edebb90b5..cab2ee9ea0d3 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-an400.dts
+++ b/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-an400.dts
@@ -20,7 +20,7 @@ aliases {
 
 	memory at 0 {
 		device_type = "memory";
-		reg = <0x00000000 0x00000000 0x00000000 0xE0000000
+		reg = <0x00000000 0x00000000 0x00000000 0xe0000000
 			0x00000001 0x00000000 0x00000000 0x20000000>;
 	};
 
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-mecool-kiii-pro.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-mecool-kiii-pro.dts
index f5b3424c0f61..dddbbe6dca7c 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxm-mecool-kiii-pro.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-mecool-kiii-pro.dts
@@ -17,7 +17,7 @@ / {
 
 	memory at 0 {
 		device_type = "memory";
-		reg = <0x0 0x0 0x0 0xC0000000>;
+		reg = <0x0 0x0 0x0 0xc0000000>;
 	};
 
 	adc-keys {
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Tue Dec 23 07:25:24 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 16:25:24 +0100
Subject: [PATCH] arm64: dts: airoha: Use hyphen in node names
Message-ID: <20251223152523.155523-2-krzysztof.kozlowski@oss.qualcomm.com>

DTS coding style prefers hyphens instead of underscores in the node
names.  Change should be safe, because node names are not considered an
ABI.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

---

Patches done with sed, verified with comparing unflattened DTB and
dtx_diff.
---
 arch/arm64/boot/dts/airoha/en7581-evb.dts | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/boot/dts/airoha/en7581-evb.dts b/arch/arm64/boot/dts/airoha/en7581-evb.dts
index dae9968a4ff6..886e2e4b5f64 100644
--- a/arch/arm64/boot/dts/airoha/en7581-evb.dts
+++ b/arch/arm64/boot/dts/airoha/en7581-evb.dts
@@ -47,17 +47,17 @@ tclinux at 600000 {
 			reg = <0x00600000 0x03200000>;
 		};
 
-		tclinux_slave at 3800000 {
+		tclinux-slave at 3800000 {
 			label = "tclinux_alt";
 			reg = <0x03800000 0x03200000>;
 		};
 
-		rootfs_data at 6a00000 {
+		rootfs-data at 6a00000 {
 			label = "rootfs_data";
 			reg = <0x06a00000 0x01400000>;
 		};
 
-		reserved_bmt at 7e00000 {
+		reserved-bmt at 7e00000 {
 			label = "reserved_bmt";
 			reg = <0x07e00000 0x00200000>;
 			read-only;
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Tue Dec 23 07:25:36 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 16:25:36 +0100
Subject: [PATCH 1/2] arm64: dts: ti: Minor whitespace cleanup
Message-ID: <20251223152535.155571-3-krzysztof.kozlowski@oss.qualcomm.com>

The DTS code coding style expects exactly one space around '=' and
before '{' characters.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

---

Patches done with sed, verified with comparing unflattened DTB and
dtx_diff.
---
 arch/arm64/boot/dts/ti/k3-am62d2-evm.dts              | 2 +-
 arch/arm64/boot/dts/ti/k3-am62p5-var-som-symphony.dts | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/boot/dts/ti/k3-am62d2-evm.dts b/arch/arm64/boot/dts/ti/k3-am62d2-evm.dts
index 2b233bc0323d..a5d5dc0a7bec 100644
--- a/arch/arm64/boot/dts/ti/k3-am62d2-evm.dts
+++ b/arch/arm64/boot/dts/ti/k3-am62d2-evm.dts
@@ -669,7 +669,7 @@ &ospi0 {
 	pinctrl-0 = <&ospi0_pins_default>;
 	status = "okay";
 
-	flash at 0{
+	flash at 0 {
 		compatible = "jedec,spi-nor";
 		reg = <0x0>;
 		spi-tx-bus-width = <8>;
diff --git a/arch/arm64/boot/dts/ti/k3-am62p5-var-som-symphony.dts b/arch/arm64/boot/dts/ti/k3-am62p5-var-som-symphony.dts
index 4bb92fde6ab8..5ba4ed56755b 100644
--- a/arch/arm64/boot/dts/ti/k3-am62p5-var-som-symphony.dts
+++ b/arch/arm64/boot/dts/ti/k3-am62p5-var-som-symphony.dts
@@ -224,7 +224,7 @@ &dphy0 {
 	status = "okay";
 };
 
-&main_i2c0{
+&main_i2c0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_i2c0>;
 	clock-frequency = <400000>;
@@ -466,7 +466,7 @@ &sdhci1 {
 	pinctrl-0 = <&pinctrl_mmc1>;
 	disable-wp;
 	bootph-all;
-	status="okay";
+	status = "okay";
 };
 
 &ti_csi2rx0 {
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Tue Dec 23 07:25:37 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 16:25:37 +0100
Subject: [PATCH 2/2] arm64: dts: ti: Use lowercase hex
In-Reply-To: <20251223152535.155571-3-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251223152535.155571-3-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <20251223152535.155571-4-krzysztof.kozlowski@oss.qualcomm.com>

The DTS code coding style expects lowercase hex for values and unit
addresses.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 arch/arm64/boot/dts/ti/k3-am62p-verdin.dtsi   |  2 +-
 arch/arm64/boot/dts/ti/k3-am62p5-sk.dts       |  2 +-
 arch/arm64/boot/dts/ti/k3-am64-main.dtsi      | 18 +++---
 .../dts/ti/k3-am642-phyboard-electra-rdk.dts  |  6 +-
 ...phyboard-electra-x27-gpio1-spi1-uart3.dtso |  4 +-
 .../ti/k3-am65-iot2050-arduino-connector.dtsi | 58 +++++++++----------
 .../boot/dts/ti/k3-am65-iot2050-common.dtsi   |  2 +-
 arch/arm64/boot/dts/ti/k3-am65-main.dtsi      |  4 +-
 .../arm64/boot/dts/ti/k3-am654-base-board.dts |  2 +-
 .../boot/dts/ti/k3-am68-sk-base-board.dts     | 14 ++---
 arch/arm64/boot/dts/ti/k3-am69-sk.dts         | 26 ++++-----
 .../boot/dts/ti/k3-j7200-mcu-wakeup.dtsi      |  4 +-
 arch/arm64/boot/dts/ti/k3-j721e-sk.dts        | 24 ++++----
 arch/arm64/boot/dts/ti/k3-j721e.dtsi          |  4 +-
 .../boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi     |  2 +-
 arch/arm64/boot/dts/ti/k3-j722s-evm.dts       |  2 +-
 arch/arm64/boot/dts/ti/k3-j722s.dtsi          |  2 +-
 .../dts/ti/k3-j784s4-j742s2-evm-common.dtsi   |  4 +-
 18 files changed, 90 insertions(+), 90 deletions(-)

diff --git a/arch/arm64/boot/dts/ti/k3-am62p-verdin.dtsi b/arch/arm64/boot/dts/ti/k3-am62p-verdin.dtsi
index ec9dd931fe92..34954df692a3 100644
--- a/arch/arm64/boot/dts/ti/k3-am62p-verdin.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am62p-verdin.dtsi
@@ -514,7 +514,7 @@ pinctrl_sdhci2: main-mmc2-default-pins {
 		pinctrl-single,pins = <
 			AM62PX_IOPAD(0x0120, PIN_INPUT,  0) /* (K24) MMC2_CMD  */ /* SODIMM 160, WiFi_SDIO_CMD   */
 			AM62PX_IOPAD(0x0118, PIN_OUTPUT, 0) /* (K21) MMC2_CLK  */ /* SODIMM 156, WiFi_SDIO_CLK   */
-			AM62PX_IOPAD(0x011C, PIN_INPUT,  0) /* () MMC2_CLKLB   */
+			AM62PX_IOPAD(0x011c, PIN_INPUT,  0) /* () MMC2_CLKLB   */
 			AM62PX_IOPAD(0x0114, PIN_INPUT,  0) /* (K23) MMC2_DAT0 */ /* SODIMM 162, WiFi_SDIO_DATA0 */
 			AM62PX_IOPAD(0x0110, PIN_INPUT,  0) /* (K22) MMC2_DAT1 */ /* SODIMM 164, WiFi_SDIO_DATA1 */
 			AM62PX_IOPAD(0x010c, PIN_INPUT,  0) /* (L20) MMC2_DAT2 */ /* SODIMM 166, WiFi_SDIO_DATA2 */
diff --git a/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts b/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts
index ef719c6334fc..4f7f6f95b02e 100644
--- a/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts
+++ b/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts
@@ -283,7 +283,7 @@ main_mmc2_pins_default: main-mmc2-default-pins {
 		pinctrl-single,pins = <
 			AM62PX_IOPAD(0x0120, PIN_INPUT, 0) /* (K24) MMC2_CMD */
 			AM62PX_IOPAD(0x0118, PIN_OUTPUT, 0) /* (K21) MMC2_CLK */
-			AM62PX_IOPAD(0x011C, PIN_INPUT, 0) /* () MMC2_CLKLB */
+			AM62PX_IOPAD(0x011c, PIN_INPUT, 0) /* () MMC2_CLKLB */
 			AM62PX_IOPAD(0x0114, PIN_INPUT, 0) /* (K23) MMC2_DAT0 */
 			AM62PX_IOPAD(0x0110, PIN_INPUT_PULLUP, 0) /* (K22) MMC2_DAT1 */
 			AM62PX_IOPAD(0x010c, PIN_INPUT_PULLUP, 0) /* (L20) MMC2_DAT2 */
diff --git a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi
index d872cc671094..1b1d3970888b 100644
--- a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi
@@ -84,7 +84,7 @@ gic500: interrupt-controller at 1800000 {
 		#interrupt-cells = <3>;
 		interrupt-controller;
 		reg = <0x00 0x01800000 0x00 0x10000>,	/* GICD */
-		      <0x00 0x01840000 0x00 0xC0000>,	/* GICR */
+		      <0x00 0x01840000 0x00 0xc0000>,	/* GICR */
 		      <0x01 0x00000000 0x00 0x2000>,	/* GICC */
 		      <0x01 0x00010000 0x00 0x1000>,	/* GICH */
 		      <0x01 0x00020000 0x00 0x2000>;	/* GICV */
@@ -685,14 +685,14 @@ cpsw3g: ethernet at 8000000 {
 		power-domains = <&k3_pds 13 TI_SCI_PD_EXCLUSIVE>;
 		status = "disabled";
 
-		dmas = <&main_pktdma 0xC500 15>,
-		       <&main_pktdma 0xC501 15>,
-		       <&main_pktdma 0xC502 15>,
-		       <&main_pktdma 0xC503 15>,
-		       <&main_pktdma 0xC504 15>,
-		       <&main_pktdma 0xC505 15>,
-		       <&main_pktdma 0xC506 15>,
-		       <&main_pktdma 0xC507 15>,
+		dmas = <&main_pktdma 0xc500 15>,
+		       <&main_pktdma 0xc501 15>,
+		       <&main_pktdma 0xc502 15>,
+		       <&main_pktdma 0xc503 15>,
+		       <&main_pktdma 0xc504 15>,
+		       <&main_pktdma 0xc505 15>,
+		       <&main_pktdma 0xc506 15>,
+		       <&main_pktdma 0xc507 15>,
 		       <&main_pktdma 0x4500 15>;
 		dma-names = "tx0", "tx1", "tx2", "tx3", "tx4", "tx5", "tx6",
 			    "tx7", "rx";
diff --git a/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts b/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts
index e4afa8c0a8ca..793538f94942 100644
--- a/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts
+++ b/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts
@@ -206,8 +206,8 @@ icssg0_mdio_pins_default: icssg0-mdio-default-pins {
 		pinctrl-single,pins = <
 			AM64X_IOPAD(0x0200, PIN_INPUT, 0)	/* (P2) PRG0_MDIO0_MDIO */
 			AM64X_IOPAD(0x0204, PIN_OUTPUT, 0)	/* (P3) PRG0_MDIO0_MDC */
-			AM64X_IOPAD(0x01A8, PIN_OUTPUT, 7)	/* (V1) PRG0_PRU0_GPO18.GPIO1_18 */
-			AM64X_IOPAD(0x01AC, PIN_OUTPUT, 7)	/* (W1) PRG0_PRU0_GPO19.GPIO1_19 */
+			AM64X_IOPAD(0x01a8, PIN_OUTPUT, 7)	/* (V1) PRG0_PRU0_GPO18.GPIO1_18 */
+			AM64X_IOPAD(0x01ac, PIN_OUTPUT, 7)	/* (W1) PRG0_PRU0_GPO19.GPIO1_19 */
 		>;
 	};
 
@@ -300,7 +300,7 @@ AM64X_IOPAD(0x0234, PIN_OUTPUT, 0)	/* (C16) UART0_TXD */
 	main_uart1_pins_default: main-uart1-default-pins {
 		pinctrl-single,pins = <
 			AM64X_IOPAD(0x0248, PIN_INPUT, 0)	/* (D16) UART1_CTSn */
-			AM64X_IOPAD(0x024C, PIN_OUTPUT, 0)	/* (E16) UART1_RTSn */
+			AM64X_IOPAD(0x024c, PIN_OUTPUT, 0)	/* (E16) UART1_RTSn */
 			AM64X_IOPAD(0x0240, PIN_INPUT, 0)	/* (E15) UART1_RXD */
 			AM64X_IOPAD(0x0244, PIN_OUTPUT, 0)	/* (E14) UART1_TXD */
 		>;
diff --git a/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-x27-gpio1-spi1-uart3.dtso b/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-x27-gpio1-spi1-uart3.dtso
index bea8efa3e909..39306bf8eec1 100644
--- a/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-x27-gpio1-spi1-uart3.dtso
+++ b/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-x27-gpio1-spi1-uart3.dtso
@@ -29,9 +29,9 @@ AM64X_IOPAD(0x0220, PIN_INPUT, 7)	/* (D14) SPI1_CS1.GPIO1_48 */
 	main_spi1_pins_default: main-spi1-default-pins {
 		pinctrl-single,pins = <
 			AM64X_IOPAD(0x0224, PIN_INPUT, 0)	/* (C14) SPI1_CLK */
-			AM64X_IOPAD(0x021C, PIN_OUTPUT, 0)	/* (B14) SPI1_CS0 */
+			AM64X_IOPAD(0x021c, PIN_OUTPUT, 0)	/* (B14) SPI1_CS0 */
 			AM64X_IOPAD(0x0228, PIN_OUTPUT, 0)	/* (B15) SPI1_D0 */
-			AM64X_IOPAD(0x022C, PIN_INPUT, 0)	/* (A15) SPI1_D1 */
+			AM64X_IOPAD(0x022c, PIN_INPUT, 0)	/* (A15) SPI1_D1 */
 		>;
 	};
 
diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-arduino-connector.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-arduino-connector.dtsi
index 7ff0abd7c62e..6c7fdaf1f2c4 100644
--- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-arduino-connector.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-arduino-connector.dtsi
@@ -138,28 +138,28 @@ AM65X_WKUP_IOPAD(0x0048, PIN_INPUT_PULLDOWN, 7)
 	d2_uart0_ctsn: d2-uart0-ctsn-pins {
 		pinctrl-single,pins = <
 			/* (P1) MCU_UART0_CTSn */
-			AM65X_WKUP_IOPAD(0x004C, PIN_INPUT, 4)
+			AM65X_WKUP_IOPAD(0x004c, PIN_INPUT, 4)
 		>;
 	};
 
 	d2_gpio: d2-gpio-pins {
 		pinctrl-single,pins = <
 			/* (P5) WKUP_GPIO0_31 */
-			AM65X_WKUP_IOPAD(0x004C, PIN_INPUT, 7)
+			AM65X_WKUP_IOPAD(0x004c, PIN_INPUT, 7)
 		>;
 	};
 
 	d2_gpio_pullup: d2-gpio-pullup-pins {
 		pinctrl-single,pins = <
 			/* (P5) WKUP_GPIO0_31 */
-			AM65X_WKUP_IOPAD(0x004C, PIN_INPUT, 7)
+			AM65X_WKUP_IOPAD(0x004c, PIN_INPUT, 7)
 		>;
 	};
 
 	d2_gpio_pulldown: d2-gpio-pulldown-pins {
 		pinctrl-single,pins = <
 			/* (P5) WKUP_GPIO0_31 */
-			AM65X_WKUP_IOPAD(0x004C, PIN_INPUT_PULLDOWN, 7)
+			AM65X_WKUP_IOPAD(0x004c, PIN_INPUT_PULLDOWN, 7)
 		>;
 	};
 
@@ -348,42 +348,42 @@ AM65X_WKUP_IOPAD(0x0080, PIN_INPUT_PULLDOWN, 7)
 	a2_gpio: a2-gpio-pins {
 		pinctrl-single,pins = <
 			/* (L5) WKUP_GPIO0_43 */
-			AM65X_WKUP_IOPAD(0x007C, PIN_INPUT, 7)
+			AM65X_WKUP_IOPAD(0x007c, PIN_INPUT, 7)
 		>;
 	};
 
 	a2_gpio_pullup: a2-gpio-pullup-pins {
 		pinctrl-single,pins = <
 			/* (L5) WKUP_GPIO0_43 */
-			AM65X_WKUP_IOPAD(0x007C, PIN_INPUT, 7)
+			AM65X_WKUP_IOPAD(0x007c, PIN_INPUT, 7)
 		>;
 	};
 
 	a2_gpio_pulldown: a2-gpio-pulldown-pins {
 		pinctrl-single,pins = <
 			/* (L5) WKUP_GPIO0_43 */
-			AM65X_WKUP_IOPAD(0x007C, PIN_INPUT_PULLDOWN, 7)
+			AM65X_WKUP_IOPAD(0x007c, PIN_INPUT_PULLDOWN, 7)
 		>;
 	};
 
 	a3_gpio: a3-gpio-pins {
 		pinctrl-single,pins = <
 			/* (M5) WKUP_GPIO0_39 */
-			AM65X_WKUP_IOPAD(0x006C, PIN_INPUT, 7)
+			AM65X_WKUP_IOPAD(0x006c, PIN_INPUT, 7)
 		>;
 	};
 
 	a3_gpio_pullup: a3-gpio-pullup-pins {
 		pinctrl-single,pins = <
 			/* (M5) WKUP_GPIO0_39 */
-			AM65X_WKUP_IOPAD(0x006C, PIN_INPUT, 7)
+			AM65X_WKUP_IOPAD(0x006c, PIN_INPUT, 7)
 		>;
 	};
 
 	a3_gpio_pulldown: a3-gpio-pulldown-pins {
 		pinctrl-single,pins = <
 			/* (M5) WKUP_GPIO0_39 */
-			AM65X_WKUP_IOPAD(0x006C, PIN_INPUT_PULLDOWN, 7)
+			AM65X_WKUP_IOPAD(0x006c, PIN_INPUT_PULLDOWN, 7)
 		>;
 	};
 
@@ -411,21 +411,21 @@ AM65X_WKUP_IOPAD(0x0078, PIN_INPUT_PULLDOWN, 7)
 	a5_gpio: a5-gpio-pins {
 		pinctrl-single,pins = <
 			/* (N5) WKUP_GPIO0_35 */
-			AM65X_WKUP_IOPAD(0x005C, PIN_INPUT, 7)
+			AM65X_WKUP_IOPAD(0x005c, PIN_INPUT, 7)
 		>;
 	};
 
 	a5_gpio_pullup: a5-gpio-pullup-pins {
 		pinctrl-single,pins = <
 			/* (N5) WKUP_GPIO0_35 */
-			AM65X_WKUP_IOPAD(0x005C, PIN_INPUT_PULLUP, 7)
+			AM65X_WKUP_IOPAD(0x005c, PIN_INPUT_PULLUP, 7)
 		>;
 	};
 
 	a5_gpio_pulldown: a5-gpio-pulldown-pins {
 		pinctrl-single,pins = <
 			/* (N5) WKUP_GPIO0_35 */
-			AM65X_WKUP_IOPAD(0x005C, PIN_INPUT_PULLDOWN, 7)
+			AM65X_WKUP_IOPAD(0x005c, PIN_INPUT_PULLDOWN, 7)
 		>;
 	};
 
@@ -533,28 +533,28 @@ AM65X_IOPAD(0x0084, PIN_INPUT_PULLDOWN, 7)
 	d5_ehrpwm1_a: d5-ehrpwm1-a-pins {
 		pinctrl-single,pins = <
 			/* (AF17) EHRPWM1_A */
-			AM65X_IOPAD(0x008C, PIN_OUTPUT, 5)
+			AM65X_IOPAD(0x008c, PIN_OUTPUT, 5)
 		>;
 	};
 
 	d5_gpio: d5-gpio-pins {
 		pinctrl-single,pins = <
 			/* (AF17) GPIO0_35 */
-			AM65X_IOPAD(0x008C, PIN_INPUT, 7)
+			AM65X_IOPAD(0x008c, PIN_INPUT, 7)
 		>;
 	};
 
 	d5_gpio_pullup: d5-gpio-pullup-pins {
 		pinctrl-single,pins = <
 			/* (AF17) GPIO0_35 */
-			AM65X_IOPAD(0x008C, PIN_INPUT_PULLUP, 7)
+			AM65X_IOPAD(0x008c, PIN_INPUT_PULLUP, 7)
 		>;
 	};
 
 	d5_gpio_pulldown: d5-gpio-pulldown-pins {
 		pinctrl-single,pins = <
 			/* (AF17) GPIO0_35 */
-			AM65X_IOPAD(0x008C, PIN_INPUT_PULLDOWN, 7)
+			AM65X_IOPAD(0x008c, PIN_INPUT_PULLDOWN, 7)
 		>;
 	};
 
@@ -589,84 +589,84 @@ AM65X_IOPAD(0x0098, PIN_INPUT_PULLDOWN, 7)
 	d7_ehrpwm3_a: d7-ehrpwm3-a-pins {
 		pinctrl-single,pins = <
 			/* (AH15) EHRPWM3_A */
-			AM65X_IOPAD(0x00AC, PIN_OUTPUT, 5)
+			AM65X_IOPAD(0x00ac, PIN_OUTPUT, 5)
 		>;
 	};
 
 	d7_gpio: d7-gpio-pins {
 		pinctrl-single,pins = <
 			/* (AH15) GPIO0_43 */
-			AM65X_IOPAD(0x00AC, PIN_INPUT, 7)
+			AM65X_IOPAD(0x00ac, PIN_INPUT, 7)
 		>;
 	};
 
 	d7_gpio_pullup: d7-gpio-pullup-pins {
 		pinctrl-single,pins = <
 			/* (AH15) GPIO0_43 */
-			AM65X_IOPAD(0x00AC, PIN_INPUT_PULLUP, 7)
+			AM65X_IOPAD(0x00ac, PIN_INPUT_PULLUP, 7)
 		>;
 	};
 
 	d7_gpio_pulldown: d7-gpio-pulldown-pins {
 		pinctrl-single,pins = <
 			/* (AH15) GPIO0_43 */
-			AM65X_IOPAD(0x00AC, PIN_INPUT_PULLDOWN, 7)
+			AM65X_IOPAD(0x00ac, PIN_INPUT_PULLDOWN, 7)
 		>;
 	};
 
 	d8_ehrpwm4_a: d8-ehrpwm4-a-pins {
 		pinctrl-single,pins = <
 			/* (AG15) EHRPWM4_A */
-			AM65X_IOPAD(0x00C0, PIN_OUTPUT, 5)
+			AM65X_IOPAD(0x00c0, PIN_OUTPUT, 5)
 		>;
 	};
 
 	d8_gpio: d8-gpio-pins {
 		pinctrl-single,pins = <
 			/* (AG15) GPIO0_48 */
-			AM65X_IOPAD(0x00C0, PIN_INPUT, 7)
+			AM65X_IOPAD(0x00c0, PIN_INPUT, 7)
 		>;
 	};
 
 	d8_gpio_pullup: d8-gpio-pullup-pins {
 		pinctrl-single,pins = <
 			/* (AG15) GPIO0_48 */
-			AM65X_IOPAD(0x00C0, PIN_INPUT_PULLUP, 7)
+			AM65X_IOPAD(0x00c0, PIN_INPUT_PULLUP, 7)
 		>;
 	};
 
 	d8_gpio_pulldown: d8-gpio-pulldown-pins {
 		pinctrl-single,pins = <
 			/* (AG15) GPIO0_48 */
-			AM65X_IOPAD(0x00C0, PIN_INPUT_PULLDOWN, 7)
+			AM65X_IOPAD(0x00c0, PIN_INPUT_PULLDOWN, 7)
 		>;
 	};
 
 	d9_ehrpwm5_a: d9-ehrpwm5-a-pins {
 		pinctrl-single,pins = <
 			/* (AD15) EHRPWM5_A */
-			AM65X_IOPAD(0x00CC, PIN_OUTPUT, 5)
+			AM65X_IOPAD(0x00cc, PIN_OUTPUT, 5)
 		>;
 	};
 
 	d9_gpio: d9-gpio-pins {
 		pinctrl-single,pins = <
 			/* (AD15) GPIO0_51 */
-			AM65X_IOPAD(0x00CC, PIN_INPUT, 7)
+			AM65X_IOPAD(0x00cc, PIN_INPUT, 7)
 		>;
 	};
 
 	d9_gpio_pullup: d9-gpio-pullup-pins {
 		pinctrl-single,pins = <
 			/* (AD15) GPIO0_51 */
-			AM65X_IOPAD(0x00CC, PIN_INPUT_PULLUP, 7)
+			AM65X_IOPAD(0x00cc, PIN_INPUT_PULLUP, 7)
 		>;
 	};
 
 	d9_gpio_pulldown: d9-gpio-pulldown-pins {
 		pinctrl-single,pins = <
 			/* (AD15) GPIO0_51 */
-			AM65X_IOPAD(0x00CC, PIN_INPUT_PULLDOWN, 7)
+			AM65X_IOPAD(0x00cc, PIN_INPUT_PULLDOWN, 7)
 		>;
 	};
 };
diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi
index a9a4e7401a49..f3ee73e64d69 100644
--- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi
@@ -266,7 +266,7 @@ AM65X_WKUP_IOPAD(0x009c, PIN_OUTPUT, 0)
 	minipcie_pins_default: minipcie-default-pins {
 		pinctrl-single,pins = <
 			/* (P2) MCU_OSPI1_DQS.WKUP_GPIO0_27 */
-			AM65X_WKUP_IOPAD(0x003C, PIN_OUTPUT, 7)
+			AM65X_WKUP_IOPAD(0x003c, PIN_OUTPUT, 7)
 		>;
 	};
 };
diff --git a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi
index 61c11dc92d9c..d6ee7b9a6b68 100644
--- a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi
@@ -884,7 +884,7 @@ pcie0_rc: pcie at 5500000 {
 		#address-cells = <3>;
 		#size-cells = <2>;
 		ranges = <0x81000000 0 0          0x0 0x10020000 0 0x00010000>,
-			 <0x82000000 0 0x10030000 0x0 0x10030000 0 0x07FD0000>;
+			 <0x82000000 0 0x10030000 0x0 0x10030000 0 0x07fd0000>;
 		ti,syscon-pcie-id = <&scm_conf 0x210>;
 		ti,syscon-pcie-mode = <&scm_conf 0x4060>;
 		bus-range = <0x0 0xff>;
@@ -905,7 +905,7 @@ pcie1_rc: pcie at 5600000 {
 		#address-cells = <3>;
 		#size-cells = <2>;
 		ranges = <0x81000000 0 0          0x0   0x18020000 0 0x00010000>,
-			 <0x82000000 0 0x18030000 0x0   0x18030000 0 0x07FD0000>;
+			 <0x82000000 0 0x18030000 0x0   0x18030000 0 0x07fd0000>;
 		ti,syscon-pcie-id = <&scm_conf 0x210>;
 		ti,syscon-pcie-mode = <&scm_conf 0x4070>;
 		bus-range = <0x0 0xff>;
diff --git a/arch/arm64/boot/dts/ti/k3-am654-base-board.dts b/arch/arm64/boot/dts/ti/k3-am654-base-board.dts
index 46c58162eca0..e0262c2743eb 100644
--- a/arch/arm64/boot/dts/ti/k3-am654-base-board.dts
+++ b/arch/arm64/boot/dts/ti/k3-am654-base-board.dts
@@ -190,7 +190,7 @@ mcu_uart0_pins_default: mcu-uart0-default-pins {
 		pinctrl-single,pins = <
 			AM65X_WKUP_IOPAD(0x0044, PIN_INPUT, 4)	/* (P4) MCU_OSPI1_D1.MCU_UART0_RXD */
 			AM65X_WKUP_IOPAD(0x0048, PIN_OUTPUT, 4)	/* (P5) MCU_OSPI1_D2.MCU_UART0_TXD */
-			AM65X_WKUP_IOPAD(0x004C, PIN_INPUT, 4)	/* (P1) MCU_OSPI1_D3.MCU_UART0_CTSn */
+			AM65X_WKUP_IOPAD(0x004c, PIN_INPUT, 4)	/* (P1) MCU_OSPI1_D3.MCU_UART0_CTSn */
 			AM65X_WKUP_IOPAD(0x0054, PIN_OUTPUT, 4)	/* (N3) MCU_OSPI1_CSn1.MCU_UART0_RTSn */
 		>;
 		bootph-all;
diff --git a/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts b/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts
index 88f202f266c6..8178333fb2b4 100644
--- a/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts
+++ b/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts
@@ -359,15 +359,15 @@ J721S2_WKUP_IOPAD(0x04c, PIN_OUTPUT, 0) /* (D27) WKUP_UART0_TXD */
 
 	mcu_cpsw_pins_default: mcu-cpsw-default-pins {
 		pinctrl-single,pins = <
-			J721S2_WKUP_IOPAD(0x02C, PIN_INPUT, 0) /* (B22) MCU_RGMII1_RD0 */
+			J721S2_WKUP_IOPAD(0x02c, PIN_INPUT, 0) /* (B22) MCU_RGMII1_RD0 */
 			J721S2_WKUP_IOPAD(0x028, PIN_INPUT, 0) /* (B21) MCU_RGMII1_RD1 */
 			J721S2_WKUP_IOPAD(0x024, PIN_INPUT, 0) /* (C22) MCU_RGMII1_RD2 */
 			J721S2_WKUP_IOPAD(0x020, PIN_INPUT, 0) /* (D23) MCU_RGMII1_RD3 */
-			J721S2_WKUP_IOPAD(0x01C, PIN_INPUT, 0) /* (D22) MCU_RGMII1_RXC */
+			J721S2_WKUP_IOPAD(0x01c, PIN_INPUT, 0) /* (D22) MCU_RGMII1_RXC */
 			J721S2_WKUP_IOPAD(0x004, PIN_INPUT, 0) /* (E23) MCU_RGMII1_RX_CTL */
 			J721S2_WKUP_IOPAD(0x014, PIN_OUTPUT, 0) /* (F23) MCU_RGMII1_TD0 */
 			J721S2_WKUP_IOPAD(0x010, PIN_OUTPUT, 0) /* (G22) MCU_RGMII1_TD1 */
-			J721S2_WKUP_IOPAD(0x00C, PIN_OUTPUT, 0) /* (E21) MCU_RGMII1_TD2 */
+			J721S2_WKUP_IOPAD(0x00c, PIN_OUTPUT, 0) /* (E21) MCU_RGMII1_TD2 */
 			J721S2_WKUP_IOPAD(0x008, PIN_OUTPUT, 0) /* (E22) MCU_RGMII1_TD3 */
 			J721S2_WKUP_IOPAD(0x018, PIN_OUTPUT, 0) /* (F21) MCU_RGMII1_TXC */
 			J721S2_WKUP_IOPAD(0x000, PIN_OUTPUT, 0) /* (F22) MCU_RGMII1_TX_CTL */
@@ -392,7 +392,7 @@ J721S2_WKUP_IOPAD(0x050, PIN_OUTPUT, 0) /* (E27) MCU_MCAN0_TX */
 
 	mcu_mcan1_pins_default: mcu-mcan1-default-pins {
 		pinctrl-single,pins = <
-			J721S2_WKUP_IOPAD(0x06C, PIN_INPUT, 0) /* (F26) WKUP_GPIO0_5.MCU_MCAN1_RX */
+			J721S2_WKUP_IOPAD(0x06c, PIN_INPUT, 0) /* (F26) WKUP_GPIO0_5.MCU_MCAN1_RX */
 			J721S2_WKUP_IOPAD(0x068, PIN_OUTPUT, 0) /* (C23) WKUP_GPIO0_4.MCU_MCAN1_TX*/
 		>;
 	};
@@ -422,13 +422,13 @@ J721S2_WKUP_IOPAD(0x088, PIN_OUTPUT, 0) /* (C25) WKUP_GPIO0_12.MCU_UART0_TXD */
 	mcu_rpi_header_gpio0_pins0_default: mcu-rpi-header-gpio0-default-pins-0 {
 		pinctrl-single,pins = <
 			J721S2_WKUP_IOPAD(0x118, PIN_INPUT, 7) /* (G25) WKUP_GPIO0_66 */
-			J721S2_WKUP_IOPAD(0x05C, PIN_INPUT, 7) /* (E24) MCU_SPI1_D0.WKUP_GPIO0_1 */
+			J721S2_WKUP_IOPAD(0x05c, PIN_INPUT, 7) /* (E24) MCU_SPI1_D0.WKUP_GPIO0_1 */
 			J721S2_WKUP_IOPAD(0x060, PIN_INPUT, 7) /* (C28) MCU_SPI1_D1.WKUP_GPIO0_2 */
 			J721S2_WKUP_IOPAD(0x058, PIN_INPUT, 7) /* (D26) MCU_SPI1_CLK.WKUP_GPIO0_0 */
 			J721S2_WKUP_IOPAD(0x094, PIN_INPUT, 7) /* (D25) MCU_SPI1_CS2.WKUP_GPIO0_15*/
-			J721S2_WKUP_IOPAD(0x0B8, PIN_INPUT, 7) /* (G27) WKUP_GPIO0_56 */
+			J721S2_WKUP_IOPAD(0x0b8, PIN_INPUT, 7) /* (G27) WKUP_GPIO0_56 */
 			J721S2_WKUP_IOPAD(0x114, PIN_INPUT, 7) /* (J26) WKUP_GPIO0_57 */
-			J721S2_WKUP_IOPAD(0x11C, PIN_INPUT, 7) /* (J27) WKUP_GPIO0_67 */
+			J721S2_WKUP_IOPAD(0x11c, PIN_INPUT, 7) /* (J27) WKUP_GPIO0_67 */
 			J721S2_WKUP_IOPAD(0x064, PIN_INPUT, 7) /* (C27) MCU_SPI1_CS0.WKUP_GPIO0_3 */
 		>;
 	};
diff --git a/arch/arm64/boot/dts/ti/k3-am69-sk.dts b/arch/arm64/boot/dts/ti/k3-am69-sk.dts
index abe2f21e0e1d..e56772a334c5 100644
--- a/arch/arm64/boot/dts/ti/k3-am69-sk.dts
+++ b/arch/arm64/boot/dts/ti/k3-am69-sk.dts
@@ -264,24 +264,24 @@ J784S4_IOPAD(0x0e8, PIN_INPUT, 8) /* (AR38) TIMER_IO0.MMC1_SDCD */
 
 	vdd_sd_dv_pins_default: vdd-sd-dv-default-pins {
 		pinctrl-single,pins = <
-			J784S4_IOPAD(0x0C4, PIN_INPUT, 7) /* (AD36) ECAP0_IN_APWM_OUT.GPIO0_49 */
+			J784S4_IOPAD(0x0c4, PIN_INPUT, 7) /* (AD36) ECAP0_IN_APWM_OUT.GPIO0_49 */
 		>;
 	};
 
 	rpi_header_gpio0_pins_default: rpi-header-gpio0-default-pins {
 		pinctrl-single,pins = <
-			J784S4_IOPAD(0x0BC, PIN_INPUT, 7) /* (AD33) MCASP1_AFSX.GPIO0_47 */
-			J784S4_IOPAD(0x06C, PIN_INPUT, 7) /* (AJ37) MCASP4_AFSX.GPIO0_27 */
-			J784S4_IOPAD(0x0B4, PIN_INPUT, 7) /* (AL34) MCASP1_AXR4.GPIO0_45 */
-			J784S4_IOPAD(0x0C0, PIN_INPUT, 7) /* (AD38) MCASP1_AXR0.GPIO0_48 */
-			J784S4_IOPAD(0x00C, PIN_INPUT, 7) /* (AF33) MCAN13_TX.GPIO0_3 */
-			J784S4_IOPAD(0x0B8, PIN_INPUT, 7) /* (AC34) MCASP1_ACLKX.GPIO0_46 */
+			J784S4_IOPAD(0x0bc, PIN_INPUT, 7) /* (AD33) MCASP1_AFSX.GPIO0_47 */
+			J784S4_IOPAD(0x06c, PIN_INPUT, 7) /* (AJ37) MCASP4_AFSX.GPIO0_27 */
+			J784S4_IOPAD(0x0b4, PIN_INPUT, 7) /* (AL34) MCASP1_AXR4.GPIO0_45 */
+			J784S4_IOPAD(0x0c0, PIN_INPUT, 7) /* (AD38) MCASP1_AXR0.GPIO0_48 */
+			J784S4_IOPAD(0x00c, PIN_INPUT, 7) /* (AF33) MCAN13_TX.GPIO0_3 */
+			J784S4_IOPAD(0x0b8, PIN_INPUT, 7) /* (AC34) MCASP1_ACLKX.GPIO0_46 */
 			J784S4_IOPAD(0x090, PIN_INPUT, 7) /* (AC35) MCASP0_AXR8.GPIO0_36 */
-			J784S4_IOPAD(0x0A8, PIN_INPUT, 7) /* (AF34) MCASP0_AXR14.GPIO0_42 */
-			J784S4_IOPAD(0x0A4, PIN_INPUT, 7) /* (AJ36) MCASP0_AXR13.GPIO0_41 */
+			J784S4_IOPAD(0x0a8, PIN_INPUT, 7) /* (AF34) MCASP0_AXR14.GPIO0_42 */
+			J784S4_IOPAD(0x0a4, PIN_INPUT, 7) /* (AJ36) MCASP0_AXR13.GPIO0_41 */
 			J784S4_IOPAD(0x034, PIN_INPUT, 7) /* (AJ34) PMIC_WAKE0n.GPIO0_13 */
-			J784S4_IOPAD(0x0CC, PIN_INPUT, 7) /* (AM37) SPI0_CS0.GPIO0_51 */
-			J784S4_IOPAD(0x08C, PIN_INPUT, 7) /* (AE35) MCASP0_AXR7.GPIO0_35 */
+			J784S4_IOPAD(0x0cc, PIN_INPUT, 7) /* (AM37) SPI0_CS0.GPIO0_51 */
+			J784S4_IOPAD(0x08c, PIN_INPUT, 7) /* (AE35) MCASP0_AXR7.GPIO0_35 */
 			J784S4_IOPAD(0x008, PIN_INPUT, 7) /* (AJ33) MCAN12_RX.GPIO0_2 */
 			J784S4_IOPAD(0x004, PIN_INPUT, 7) /* (AG36) MCAN12_TX.GPIO0_1 */
 		>;
@@ -347,8 +347,8 @@ J784S4_IOPAD(0x094, PIN_OUTPUT, 0) /* (AG35) MCAN6_TX */
 
 	main_mcan7_pins_default: main-mcan7-default-pins {
 		pinctrl-single,pins = <
-			J784S4_IOPAD(0x0A0, PIN_INPUT, 0) /* (AD34) MCAN7_RX */
-			J784S4_IOPAD(0x09C, PIN_OUTPUT, 0) /* (AF35) MCAN7_TX */
+			J784S4_IOPAD(0x0a0, PIN_INPUT, 0) /* (AD34) MCAN7_RX */
+			J784S4_IOPAD(0x09c, PIN_OUTPUT, 0) /* (AF35) MCAN7_TX */
 		>;
 	};
 
diff --git a/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi
index fec1db8b133d..dc5c02a025f8 100644
--- a/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi
@@ -212,7 +212,7 @@ mcu_timerio_input: pinctrl at 40f04200 {
 		reg = <0x0 0x40f04200 0x0 0x28>;
 		#pinctrl-cells = <1>;
 		pinctrl-single,register-width = <32>;
-		pinctrl-single,function-mask = <0x0000000F>;
+		pinctrl-single,function-mask = <0x0000000f>;
 		status = "reserved";
 	};
 
@@ -222,7 +222,7 @@ mcu_timerio_output: pinctrl at 40f04280 {
 		reg = <0x0 0x40f04280 0x0 0x28>;
 		#pinctrl-cells = <1>;
 		pinctrl-single,register-width = <32>;
-		pinctrl-single,function-mask = <0x0000000F>;
+		pinctrl-single,function-mask = <0x0000000f>;
 		status = "reserved";
 	};
 
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-sk.dts b/arch/arm64/boot/dts/ti/k3-j721e-sk.dts
index 050776cb4df8..689ba2ff81f7 100644
--- a/arch/arm64/boot/dts/ti/k3-j721e-sk.dts
+++ b/arch/arm64/boot/dts/ti/k3-j721e-sk.dts
@@ -443,29 +443,29 @@ J721E_IOPAD(0x154, PIN_INPUT_PULLUP, 2) /* (AA27) PRG0_MDIO0_MDC.I2C5_SDA */
 
 	rpi_header_gpio0_pins_default: rpi-header-gpio0-default-pins {
 		pinctrl-single,pins = <
-			J721E_IOPAD(0x01C, PIN_INPUT, 7) /* (AD22) PRG1_PRU0_GPO6.GPIO0_7 */
+			J721E_IOPAD(0x01c, PIN_INPUT, 7) /* (AD22) PRG1_PRU0_GPO6.GPIO0_7 */
 			J721E_IOPAD(0x120, PIN_INPUT, 7) /* (AA28) PRG0_PRU1_GPO8.GPIO0_71 */
-			J721E_IOPAD(0x14C, PIN_INPUT, 7) /* (AA29) PRG0_PRU1_GPO19.GPIO0_82 */
-			J721E_IOPAD(0x02C, PIN_INPUT, 7) /* (AD21) PRG1_PRU0_GPO10.GPIO0_11 */
+			J721E_IOPAD(0x14c, PIN_INPUT, 7) /* (AA29) PRG0_PRU1_GPO19.GPIO0_82 */
+			J721E_IOPAD(0x02c, PIN_INPUT, 7) /* (AD21) PRG1_PRU0_GPO10.GPIO0_11 */
 			J721E_IOPAD(0x198, PIN_INPUT, 7) /* (V25) RGMII6_TD1.GPIO0_101 */
-			J721E_IOPAD(0x1B0, PIN_INPUT, 7) /* (W24) RGMII6_RD1.GPIO0_107 */
-			J721E_IOPAD(0x1A0, PIN_INPUT, 7) /* (W29) RGMII6_TXC.GPIO0_103 */
+			J721E_IOPAD(0x1b0, PIN_INPUT, 7) /* (W24) RGMII6_RD1.GPIO0_107 */
+			J721E_IOPAD(0x1a0, PIN_INPUT, 7) /* (W29) RGMII6_TXC.GPIO0_103 */
 			J721E_IOPAD(0x008, PIN_INPUT, 7) /* (AG22) PRG1_PRU0_GPO1.GPIO0_2 */
-			J721E_IOPAD(0x1D0, PIN_INPUT, 7) /* (AA3) SPI0_D1.GPIO0_115 */
-			J721E_IOPAD(0x11C, PIN_INPUT, 7) /* (AA24) PRG0_PRU1_GPO7.GPIO0_70 */
+			J721E_IOPAD(0x1d0, PIN_INPUT, 7) /* (AA3) SPI0_D1.GPIO0_115 */
+			J721E_IOPAD(0x11c, PIN_INPUT, 7) /* (AA24) PRG0_PRU1_GPO7.GPIO0_70 */
 			J721E_IOPAD(0x148, PIN_INPUT, 7) /* (AA26) PRG0_PRU1_GPO18.GPIO0_81 */
 			J721E_IOPAD(0x004, PIN_INPUT, 7) /* (AC23) PRG1_PRU0_GPO0.GPIO0_1 */
 			J721E_IOPAD(0x014, PIN_INPUT, 7) /* (AH23) PRG1_PRU0_GPO4.GPIO0_5 */
 			J721E_IOPAD(0x020, PIN_INPUT, 7) /* (AE20) PRG1_PRU0_GPO7.GPIO0_8 */
-			J721E_IOPAD(0x19C, PIN_INPUT, 7) /* (W27) RGMII6_TD0.GPIO0_102 */
-			J721E_IOPAD(0x1B4, PIN_INPUT, 7) /* (W25) RGMII6_RD0.GPIO0_108 */
+			J721E_IOPAD(0x19c, PIN_INPUT, 7) /* (W27) RGMII6_TD0.GPIO0_102 */
+			J721E_IOPAD(0x1b4, PIN_INPUT, 7) /* (W25) RGMII6_RD0.GPIO0_108 */
 			J721E_IOPAD(0x188, PIN_INPUT, 7) /* (Y28) RGMII6_TX_CTL.GPIO0_97 */
-			J721E_IOPAD(0x00C, PIN_INPUT, 7) /* (AF22) PRG1_PRU0_GPO2.GPIO0_3 */
+			J721E_IOPAD(0x00c, PIN_INPUT, 7) /* (AF22) PRG1_PRU0_GPO2.GPIO0_3 */
 			J721E_IOPAD(0x010, PIN_INPUT, 7) /* (AJ23) PRG1_PRU0_GPO3.GPIO0_4 */
 			J721E_IOPAD(0x178, PIN_INPUT, 7) /* (U27) RGMII5_RD3.GPIO0_93 */
-			J721E_IOPAD(0x17C, PIN_INPUT, 7) /* (U24) RGMII5_RD2.GPIO0_94 */
+			J721E_IOPAD(0x17c, PIN_INPUT, 7) /* (U24) RGMII5_RD2.GPIO0_94 */
 			J721E_IOPAD(0x190, PIN_INPUT, 7) /* (W23) RGMII6_TD3.GPIO0_99 */
-			J721E_IOPAD(0x18C, PIN_INPUT, 7) /* (V23) RGMII6_RX_CTL.GPIO0_98 */
+			J721E_IOPAD(0x18c, PIN_INPUT, 7) /* (V23) RGMII6_RX_CTL.GPIO0_98 */
 		>;
 	};
 
diff --git a/arch/arm64/boot/dts/ti/k3-j721e.dtsi b/arch/arm64/boot/dts/ti/k3-j721e.dtsi
index b6e22c242951..ba109cc5b2bc 100644
--- a/arch/arm64/boot/dts/ti/k3-j721e.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-j721e.dtsi
@@ -41,7 +41,7 @@ cpu0: cpu at 0 {
 			reg = <0x000>;
 			device_type = "cpu";
 			enable-method = "psci";
-			i-cache-size = <0xC000>;
+			i-cache-size = <0xc000>;
 			i-cache-line-size = <64>;
 			i-cache-sets = <256>;
 			d-cache-size = <0x8000>;
@@ -55,7 +55,7 @@ cpu1: cpu at 1 {
 			reg = <0x001>;
 			device_type = "cpu";
 			enable-method = "psci";
-			i-cache-size = <0xC000>;
+			i-cache-size = <0xc000>;
 			i-cache-line-size = <64>;
 			i-cache-sets = <256>;
 			d-cache-size = <0x8000>;
diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi
index 2a7f9c519735..fd01437726ab 100644
--- a/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi
@@ -87,7 +87,7 @@ wkup_pmx0: pinctrl at 4301c000 {
 	wkup_pmx1: pinctrl at 4301c038 {
 		compatible = "pinctrl-single";
 		/* Proxy 0 addressing */
-		reg = <0x00 0x4301c038 0x00 0x02C>;
+		reg = <0x00 0x4301c038 0x00 0x02c>;
 		#pinctrl-cells = <1>;
 		pinctrl-single,register-width = <32>;
 		pinctrl-single,function-mask = <0xffffffff>;
diff --git a/arch/arm64/boot/dts/ti/k3-j722s-evm.dts b/arch/arm64/boot/dts/ti/k3-j722s-evm.dts
index 7baf5764862b..e66330c71593 100644
--- a/arch/arm64/boot/dts/ti/k3-j722s-evm.dts
+++ b/arch/arm64/boot/dts/ti/k3-j722s-evm.dts
@@ -436,7 +436,7 @@ J722S_MCU_IOPAD(0x034, PIN_OUTPUT, 0) /* (B2) MCU_MCAN0_TX */
 	mcu_mcan1_pins_default: mcu-mcan1-default-pins {
 		pinctrl-single,pins = <
 			J722S_MCU_IOPAD(0x040, PIN_INPUT, 0) /* (B1) MCU_MCAN1_RX */
-			J722S_MCU_IOPAD(0x03C, PIN_OUTPUT, 0) /*(C1) MCU_MCAN1_TX */
+			J722S_MCU_IOPAD(0x03c, PIN_OUTPUT, 0) /*(C1) MCU_MCAN1_TX */
 		>;
 	};
 
diff --git a/arch/arm64/boot/dts/ti/k3-j722s.dtsi b/arch/arm64/boot/dts/ti/k3-j722s.dtsi
index cdc8570e54b2..c8b634c34677 100644
--- a/arch/arm64/boot/dts/ti/k3-j722s.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-j722s.dtsi
@@ -162,7 +162,7 @@ cbass_main: bus at f0000 {
 			 <0x00 0x0fd20200 0x00 0x0fd20200 0x00 0x00000200>, /* JPEGENC0_CORE_MMU */
 			 <0x00 0x20000000 0x00 0x20000000 0x00 0x0a008000>, /* Third peripheral window */
 			 <0x00 0x30040000 0x00 0x30040000 0x00 0x00080000>, /* PRUSS-M */
-			 <0x00 0x301C0000 0x00 0x301C0000 0x00 0x00001000>, /* DPHY-TX */
+			 <0x00 0x301c0000 0x00 0x301c0000 0x00 0x00001000>, /* DPHY-TX */
 			 <0x00 0x30101000 0x00 0x30101000 0x00 0x00080100>, /* CSI window */
 			 <0x00 0x30200000 0x00 0x30200000 0x00 0x00010000>, /* DSS */
 			 <0x00 0x30210000 0x00 0x30210000 0x00 0x00010000>, /* VPU */
diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-evm-common.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-evm-common.dtsi
index e50735577737..ff3a85cbc524 100644
--- a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-evm-common.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-evm-common.dtsi
@@ -509,10 +509,10 @@ J784S4_WKUP_IOPAD(0x008, PIN_OUTPUT, 0) /* (F32) MCU_OSPI1_CLK */
 			J784S4_WKUP_IOPAD(0x024, PIN_OUTPUT, 0) /* (G32) MCU_OSPI1_CSn0 */
 			J784S4_WKUP_IOPAD(0x014, PIN_INPUT, 0) /* (E35) MCU_OSPI1_D0 */
 			J784S4_WKUP_IOPAD(0x018, PIN_INPUT, 0) /* (D31) MCU_OSPI1_D1 */
-			J784S4_WKUP_IOPAD(0x01C, PIN_INPUT, 0) /* (G31) MCU_OSPI1_D2 */
+			J784S4_WKUP_IOPAD(0x01c, PIN_INPUT, 0) /* (G31) MCU_OSPI1_D2 */
 			J784S4_WKUP_IOPAD(0x020, PIN_INPUT, 0) /* (F33) MCU_OSPI1_D3 */
 			J784S4_WKUP_IOPAD(0x010, PIN_INPUT, 0) /* (F31) MCU_OSPI1_DQS */
-			J784S4_WKUP_IOPAD(0x00C, PIN_INPUT, 0) /* (C31) MCU_OSPI1_LBCLKO */
+			J784S4_WKUP_IOPAD(0x00c, PIN_INPUT, 0) /* (C31) MCU_OSPI1_LBCLKO */
 		>;
 	};
 };
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Tue Dec 23 07:25:45 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 16:25:45 +0100
Subject: [PATCH 1/2] arm64: dts: st: Use hyphen in node names
Message-ID: <20251223152544.155637-3-krzysztof.kozlowski@oss.qualcomm.com>

DTS coding style prefers hyphens instead of underscores in the node
names.  Change should be safe, because node names are not considered an
ABI.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

---

Patches done with sed, verified with comparing unflattened DTB and
dtx_diff.
---
 arch/arm64/boot/dts/st/stm32mp231.dtsi | 4 ++--
 arch/arm64/boot/dts/st/stm32mp251.dtsi | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/boot/dts/st/stm32mp231.dtsi b/arch/arm64/boot/dts/st/stm32mp231.dtsi
index 88e214d395ab..a6658d836122 100644
--- a/arch/arm64/boot/dts/st/stm32mp231.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp231.dtsi
@@ -761,11 +761,11 @@ bsec: efuse at 44000000 {
 			#address-cells = <1>;
 			#size-cells = <1>;
 
-			part_number_otp at 24 {
+			part-number-otp at 24 {
 				reg = <0x24 0x4>;
 			};
 
-			package_otp at 1e8 {
+			package-otp at 1e8 {
 				reg = <0x1e8 0x1>;
 				bits = <0 3>;
 			};
diff --git a/arch/arm64/boot/dts/st/stm32mp251.dtsi b/arch/arm64/boot/dts/st/stm32mp251.dtsi
index a8e6e0f77b83..ec5db00b9d72 100644
--- a/arch/arm64/boot/dts/st/stm32mp251.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp251.dtsi
@@ -1739,11 +1739,11 @@ bsec: efuse at 44000000 {
 			#address-cells = <1>;
 			#size-cells = <1>;
 
-			part_number_otp at 24 {
+			part-number-otp at 24 {
 				reg = <0x24 0x4>;
 			};
 
-			package_otp at 1e8 {
+			package-otp at 1e8 {
 				reg = <0x1e8 0x1>;
 				bits = <0 3>;
 			};
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Tue Dec 23 07:25:46 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 16:25:46 +0100
Subject: [PATCH 2/2] arm64: dts: st: Minor whitespace cleanup
In-Reply-To: <20251223152544.155637-3-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251223152544.155637-3-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <20251223152544.155637-4-krzysztof.kozlowski@oss.qualcomm.com>

The DTS code coding style expects exactly one space around '=' and
before '{' characters.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 arch/arm64/boot/dts/st/stm32mp235f-dk.dts  | 2 +-
 arch/arm64/boot/dts/st/stm32mp257f-dk.dts  | 2 +-
 arch/arm64/boot/dts/st/stm32mp257f-ev1.dts | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/boot/dts/st/stm32mp235f-dk.dts b/arch/arm64/boot/dts/st/stm32mp235f-dk.dts
index c3e688068223..9a2b2f50df76 100644
--- a/arch/arm64/boot/dts/st/stm32mp235f-dk.dts
+++ b/arch/arm64/boot/dts/st/stm32mp235f-dk.dts
@@ -93,7 +93,7 @@ mdio {
 		phy1_eth1: ethernet-phy at 1 {
 			compatible = "ethernet-phy-id001c.c916";
 			reg = <1>;
-			reset-gpios =  <&gpioa 2 GPIO_ACTIVE_LOW>;
+			reset-gpios = <&gpioa 2 GPIO_ACTIVE_LOW>;
 			reset-assert-us = <10000>;
 			reset-deassert-us = <80000>;
 		};
diff --git a/arch/arm64/boot/dts/st/stm32mp257f-dk.dts b/arch/arm64/boot/dts/st/stm32mp257f-dk.dts
index e718d888ce21..4a489a8d9aca 100644
--- a/arch/arm64/boot/dts/st/stm32mp257f-dk.dts
+++ b/arch/arm64/boot/dts/st/stm32mp257f-dk.dts
@@ -93,7 +93,7 @@ mdio {
 		phy1_eth1: ethernet-phy at 1 {
 			compatible = "ethernet-phy-id001c.c916";
 			reg = <1>;
-			reset-gpios =  <&gpioa 2 GPIO_ACTIVE_LOW>;
+			reset-gpios = <&gpioa 2 GPIO_ACTIVE_LOW>;
 			reset-assert-us = <10000>;
 			reset-deassert-us = <80000>;
 		};
diff --git a/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts b/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
index bb6d6393d2e4..0c5fc7a7be8d 100644
--- a/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
+++ b/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
@@ -186,7 +186,7 @@ mdio {
 		phy1_eth1: ethernet-phy at 4 {
 			compatible = "ethernet-phy-id001c.c916";
 			reg = <4>;
-			reset-gpios =  <&gpioj 9 GPIO_ACTIVE_LOW>;
+			reset-gpios = <&gpioj 9 GPIO_ACTIVE_LOW>;
 			reset-assert-us = <10000>;
 			reset-deassert-us = <80000>;
 		};
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Tue Dec 23 07:26:25 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 16:26:25 +0100
Subject: [PATCH 1/3] arm64: dts: freescale: Use hyphen in node names
Message-ID: <20251223152624.155845-4-krzysztof.kozlowski@oss.qualcomm.com>

DTS coding style prefers hyphens instead of underscores in the node
names.  Change should be safe, because node names are not considered an
ABI.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

---

Patches done with sed, verified with comparing unflattened DTB and
dtx_diff.
---
 arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi          | 2 +-
 arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi          | 6 +++---
 arch/arm64/boot/dts/freescale/imx8mm-phycore-rpmsg.dtso | 2 +-
 arch/arm64/boot/dts/freescale/imx95-15x15-evk.dts       | 2 +-
 arch/arm64/boot/dts/freescale/imx95-tqma9596sa.dtsi     | 2 +-
 5 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
index ef80bf6a604f..b07022e3b6d5 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
@@ -278,7 +278,7 @@ sfp: efuse at 1e80000 {
 			clock-names = "sfp";
 		};
 
-		sec_mon: sec_mon at 1e90000 {
+		sec_mon: sec-mon at 1e90000 {
 			compatible = "fsl,sec-v5.4-mon", "fsl,sec-v5.0-mon",
 				     "fsl,sec-v4.0-mon";
 			reg = <0x0 0x1e90000 0x0 0x10000>;
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
index 22173d69713d..6fefe837f434 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
@@ -851,7 +851,7 @@ pcie1: pcie at 3400000 {
 			status = "disabled";
 		};
 
-		pcie_ep1: pcie_ep at 3400000 {
+		pcie_ep1: pcie-ep at 3400000 {
 			compatible = "fsl,ls1046a-pcie-ep";
 			reg = <0x00 0x03400000 0x0 0x00100000>,
 			      <0x40 0x00000000 0x8 0x00000000>;
@@ -890,7 +890,7 @@ pcie2: pcie at 3500000 {
 			status = "disabled";
 		};
 
-		pcie_ep2: pcie_ep at 3500000 {
+		pcie_ep2: pcie-ep at 3500000 {
 			compatible = "fsl,ls1046a-pcie-ep";
 			reg = <0x00 0x03500000 0x0 0x00100000>,
 			      <0x48 0x00000000 0x8 0x00000000>;
@@ -929,7 +929,7 @@ pcie3: pcie at 3600000 {
 			status = "disabled";
 		};
 
-		pcie_ep3: pcie_ep at 3600000 {
+		pcie_ep3: pcie-ep at 3600000 {
 			compatible = "fsl,ls1046a-pcie-ep";
 			reg = <0x00 0x03600000 0x0 0x00100000>,
 			      <0x50 0x00000000 0x8 0x00000000>;
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-phycore-rpmsg.dtso b/arch/arm64/boot/dts/freescale/imx8mm-phycore-rpmsg.dtso
index 43d5905f3d72..414f44b85564 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-phycore-rpmsg.dtso
+++ b/arch/arm64/boot/dts/freescale/imx8mm-phycore-rpmsg.dtso
@@ -33,7 +33,7 @@ vdev0vring1: vdev0vring1 at b8008000 {
 			no-map;
 		};
 
-		rsc_table: rsc_table at b80ff000 {
+		rsc_table: rsc-table at b80ff000 {
 			reg = <0 0xb80ff000 0 0x1000>;
 			no-map;
 		};
diff --git a/arch/arm64/boot/dts/freescale/imx95-15x15-evk.dts b/arch/arm64/boot/dts/freescale/imx95-15x15-evk.dts
index c1e245ecea9c..ff720c139a7e 100644
--- a/arch/arm64/boot/dts/freescale/imx95-15x15-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx95-15x15-evk.dts
@@ -216,7 +216,7 @@ rsc_table: rsc-table at 88220000 {
 			no-map;
 		};
 
-		vpu_boot: vpu_boot at a0000000 {
+		vpu_boot: vpu-boot at a0000000 {
 			reg = <0 0xa0000000 0 0x100000>;
 			no-map;
 		};
diff --git a/arch/arm64/boot/dts/freescale/imx95-tqma9596sa.dtsi b/arch/arm64/boot/dts/freescale/imx95-tqma9596sa.dtsi
index 43418844701b..456129f4a682 100644
--- a/arch/arm64/boot/dts/freescale/imx95-tqma9596sa.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx95-tqma9596sa.dtsi
@@ -40,7 +40,7 @@ linux_cma: linux,cma {
 			linux,cma-default;
 		};
 
-		vpu_boot: vpu_boot at a0000000 {
+		vpu_boot: vpu-boot at a0000000 {
 			reg = <0 0xa0000000 0 0x100000>;
 			no-map;
 		};
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Tue Dec 23 07:26:26 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 16:26:26 +0100
Subject: [PATCH 2/3] arm64: dts: freescale: Minor whitespace cleanup
In-Reply-To: <20251223152624.155845-4-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251223152624.155845-4-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <20251223152624.155845-5-krzysztof.kozlowski@oss.qualcomm.com>

The DTS code coding style expects exactly one space around '=' and
before '{' characters.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 arch/arm64/boot/dts/freescale/imx8mp-edm-g-wb.dts           | 2 +-
 .../dts/freescale/imx8mp-hummingboard-pulse-common.dtsi     | 2 +-
 arch/arm64/boot/dts/freescale/imx8mp-sr-som.dtsi            | 6 +++---
 arch/arm64/boot/dts/freescale/imx93-var-som.dtsi            | 4 ++--
 4 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-edm-g-wb.dts b/arch/arm64/boot/dts/freescale/imx8mp-edm-g-wb.dts
index 138f21e257aa..242fa930bd2f 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-edm-g-wb.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-edm-g-wb.dts
@@ -117,7 +117,7 @@ &aud2htx {
 };
 
 &easrc {
-	fsl,asrc-rate  = <48000>;
+	fsl,asrc-rate = <48000>;
 	status = "okay";
 };
 
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-common.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-common.dtsi
index 825ad6a2ba14..fa7cb9759d01 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-common.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-common.dtsi
@@ -141,7 +141,7 @@ mpcie-reset-hog {
 };
 
 &i2c3 {
-	carrier_eeprom: eeprom at 57{
+	carrier_eeprom: eeprom at 57 {
 		compatible = "st,24c02", "atmel,24c02";
 		reg = <0x57>;
 		pagesize = <16>;
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-sr-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-sr-som.dtsi
index 4e6629f940bf..3cdb0bc0ab72 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-sr-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-sr-som.dtsi
@@ -198,7 +198,7 @@ buck2: BUCK2 {
 				nxp,dvs-standby-voltage = <850000>;
 			};
 
-			buck4: BUCK4{
+			buck4: BUCK4 {
 				regulator-name = "BUCK4";
 				regulator-min-microvolt = <600000>;
 				regulator-max-microvolt = <3400000>;
@@ -206,7 +206,7 @@ buck4: BUCK4{
 				regulator-always-on;
 			};
 
-			buck5: BUCK5{
+			buck5: BUCK5 {
 				regulator-name = "BUCK5";
 				regulator-min-microvolt = <600000>;
 				regulator-max-microvolt = <3400000>;
@@ -264,7 +264,7 @@ ldo5: LDO5 {
 		};
 	};
 
-	som_eeprom: eeprom at 50{
+	som_eeprom: eeprom at 50 {
 		compatible = "st,24c01", "atmel,24c01";
 		reg = <0x50>;
 		pagesize = <16>;
diff --git a/arch/arm64/boot/dts/freescale/imx93-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx93-var-som.dtsi
index 2dc8b18ae91e..24063bf8183d 100644
--- a/arch/arm64/boot/dts/freescale/imx93-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx93-var-som.dtsi
@@ -131,7 +131,7 @@ buck2: BUCK2 {
 				regulator-ramp-delay = <3125>;
 			};
 
-			buck4: BUCK4{
+			buck4: BUCK4 {
 				regulator-name = "BUCK4";
 				regulator-min-microvolt = <600000>;
 				regulator-max-microvolt = <3400000>;
@@ -139,7 +139,7 @@ buck4: BUCK4{
 				regulator-always-on;
 			};
 
-			buck5: BUCK5{
+			buck5: BUCK5 {
 				regulator-name = "BUCK5";
 				regulator-min-microvolt = <600000>;
 				regulator-max-microvolt = <3400000>;
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Tue Dec 23 07:26:27 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 16:26:27 +0100
Subject: [PATCH 3/3] arm64: dts: freescale: Use lowercase hex
In-Reply-To: <20251223152624.155845-4-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251223152624.155845-4-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <20251223152624.155845-6-krzysztof.kozlowski@oss.qualcomm.com>

The DTS code coding style expects lowercase hex for values and unit
addresses.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 .../boot/dts/freescale/fsl-ls1088a-ten64.dts  |  4 +--
 .../arm64/boot/dts/freescale/fsl-ls1088a.dtsi |  2 +-
 .../arm64/boot/dts/freescale/fsl-ls208xa.dtsi |  2 +-
 .../arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 32 +++++++++----------
 .../dts/freescale/imx8mn-tqma8mqnl-mba8mx.dts | 16 +++++-----
 .../dts/freescale/imx8mp-libra-rdk-fpsc.dts   |  2 +-
 .../freescale/imx8mp-phyboard-pollux-rdk.dts  |  2 +-
 .../dts/freescale/imx8mp-toradex-smarc.dtsi   |  6 ++--
 .../imx8mp-tqma8mpql-mba8mp-ras314.dts        |  2 +-
 .../freescale/imx8mp-tqma8mpql-mba8mpxl.dts   |  2 +-
 .../dts/freescale/imx8mq-librem5-devkit.dts   |  2 +-
 .../boot/dts/freescale/imx8mq-librem5.dtsi    |  6 ++--
 arch/arm64/boot/dts/freescale/imx8qm-mek.dts  | 12 +++----
 arch/arm64/boot/dts/freescale/imx8qm.dtsi     |  4 +--
 arch/arm64/boot/dts/freescale/imx8qxp-mek.dts |  6 ++--
 .../boot/dts/freescale/imx8x-colibri.dtsi     |  2 +-
 .../boot/dts/freescale/imx95-15x15-evk.dts    |  2 +-
 .../dts/freescale/imx95-toradex-smarc.dtsi    |  2 +-
 arch/arm64/boot/dts/freescale/s32g3.dtsi      |  4 +--
 .../boot/dts/freescale/s32gxxxa-evb.dtsi      | 20 ++++++------
 .../boot/dts/freescale/s32gxxxa-rdb.dtsi      | 20 ++++++------
 21 files changed, 75 insertions(+), 75 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a-ten64.dts b/arch/arm64/boot/dts/freescale/fsl-ls1088a-ten64.dts
index 71765ec91745..f51508952d51 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1088a-ten64.dts
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a-ten64.dts
@@ -392,13 +392,13 @@ partition at 800000 {
 			/* ubia (first OpenWrt) - a/b names to prevent confusion with ubi0/1/etc. */
 			partition at 2800000 {
 				label = "ubia";
-				reg = <0x2800000 0x6C00000>;
+				reg = <0x2800000 0x6c00000>;
 			};
 
 			/* ubib (second OpenWrt) */
 			partition at 9400000 {
 				label = "ubib";
-				reg = <0x9400000 0x6C00000>;
+				reg = <0x9400000 0x6c00000>;
 			};
 		};
 	};
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
index b2f6cd237be0..99016768b73f 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
@@ -684,7 +684,7 @@ smmu: iommu at 5000000 {
 			compatible = "arm,mmu-500";
 			reg = <0 0x5000000 0 0x800000>;
 			#iommu-cells = <1>;
-			stream-match-mask = <0x7C00>;
+			stream-match-mask = <0x7c00>;
 			dma-coherent;
 			#global-interrupts = <12>;
 				     // global secure fault
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
index 9421fdd7e30e..6073e426774a 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
@@ -881,7 +881,7 @@ smmu: iommu at 5000000 {
 			reg = <0 0x5000000 0 0x800000>;
 			#global-interrupts = <12>;
 			#iommu-cells = <1>;
-			stream-match-mask = <0x7C00>;
+			stream-match-mask = <0x7c00>;
 			dma-coherent;
 			interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>, /* global secure fault */
 				     <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>, /* combined secure interrupt */
diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
index d899c0355e51..853b01452813 100644
--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
@@ -35,7 +35,7 @@ cpu0: cpu at 0 {
 			d-cache-size = <0x8000>;
 			d-cache-line-size = <64>;
 			d-cache-sets = <128>;
-			i-cache-size = <0xC000>;
+			i-cache-size = <0xc000>;
 			i-cache-line-size = <64>;
 			i-cache-sets = <192>;
 			next-level-cache = <&cluster0_l2>;
@@ -52,7 +52,7 @@ cpu1: cpu at 1 {
 			d-cache-size = <0x8000>;
 			d-cache-line-size = <64>;
 			d-cache-sets = <128>;
-			i-cache-size = <0xC000>;
+			i-cache-size = <0xc000>;
 			i-cache-line-size = <64>;
 			i-cache-sets = <192>;
 			next-level-cache = <&cluster0_l2>;
@@ -69,7 +69,7 @@ cpu100: cpu at 100 {
 			d-cache-size = <0x8000>;
 			d-cache-line-size = <64>;
 			d-cache-sets = <128>;
-			i-cache-size = <0xC000>;
+			i-cache-size = <0xc000>;
 			i-cache-line-size = <64>;
 			i-cache-sets = <192>;
 			next-level-cache = <&cluster1_l2>;
@@ -86,7 +86,7 @@ cpu101: cpu at 101 {
 			d-cache-size = <0x8000>;
 			d-cache-line-size = <64>;
 			d-cache-sets = <128>;
-			i-cache-size = <0xC000>;
+			i-cache-size = <0xc000>;
 			i-cache-line-size = <64>;
 			i-cache-sets = <192>;
 			next-level-cache = <&cluster1_l2>;
@@ -103,7 +103,7 @@ cpu200: cpu at 200 {
 			d-cache-size = <0x8000>;
 			d-cache-line-size = <64>;
 			d-cache-sets = <128>;
-			i-cache-size = <0xC000>;
+			i-cache-size = <0xc000>;
 			i-cache-line-size = <64>;
 			i-cache-sets = <192>;
 			next-level-cache = <&cluster2_l2>;
@@ -120,7 +120,7 @@ cpu201: cpu at 201 {
 			d-cache-size = <0x8000>;
 			d-cache-line-size = <64>;
 			d-cache-sets = <128>;
-			i-cache-size = <0xC000>;
+			i-cache-size = <0xc000>;
 			i-cache-line-size = <64>;
 			i-cache-sets = <192>;
 			next-level-cache = <&cluster2_l2>;
@@ -137,7 +137,7 @@ cpu300: cpu at 300 {
 			d-cache-size = <0x8000>;
 			d-cache-line-size = <64>;
 			d-cache-sets = <128>;
-			i-cache-size = <0xC000>;
+			i-cache-size = <0xc000>;
 			i-cache-line-size = <64>;
 			i-cache-sets = <192>;
 			next-level-cache = <&cluster3_l2>;
@@ -154,7 +154,7 @@ cpu301: cpu at 301 {
 			d-cache-size = <0x8000>;
 			d-cache-line-size = <64>;
 			d-cache-sets = <128>;
-			i-cache-size = <0xC000>;
+			i-cache-size = <0xc000>;
 			i-cache-line-size = <64>;
 			i-cache-sets = <192>;
 			next-level-cache = <&cluster3_l2>;
@@ -171,7 +171,7 @@ cpu400: cpu at 400 {
 			d-cache-size = <0x8000>;
 			d-cache-line-size = <64>;
 			d-cache-sets = <128>;
-			i-cache-size = <0xC000>;
+			i-cache-size = <0xc000>;
 			i-cache-line-size = <64>;
 			i-cache-sets = <192>;
 			next-level-cache = <&cluster4_l2>;
@@ -188,7 +188,7 @@ cpu401: cpu at 401 {
 			d-cache-size = <0x8000>;
 			d-cache-line-size = <64>;
 			d-cache-sets = <128>;
-			i-cache-size = <0xC000>;
+			i-cache-size = <0xc000>;
 			i-cache-line-size = <64>;
 			i-cache-sets = <192>;
 			next-level-cache = <&cluster4_l2>;
@@ -205,7 +205,7 @@ cpu500: cpu at 500 {
 			d-cache-size = <0x8000>;
 			d-cache-line-size = <64>;
 			d-cache-sets = <128>;
-			i-cache-size = <0xC000>;
+			i-cache-size = <0xc000>;
 			i-cache-line-size = <64>;
 			i-cache-sets = <192>;
 			next-level-cache = <&cluster5_l2>;
@@ -222,7 +222,7 @@ cpu501: cpu at 501 {
 			d-cache-size = <0x8000>;
 			d-cache-line-size = <64>;
 			d-cache-sets = <128>;
-			i-cache-size = <0xC000>;
+			i-cache-size = <0xc000>;
 			i-cache-line-size = <64>;
 			i-cache-sets = <192>;
 			next-level-cache = <&cluster5_l2>;
@@ -239,7 +239,7 @@ cpu600: cpu at 600 {
 			d-cache-size = <0x8000>;
 			d-cache-line-size = <64>;
 			d-cache-sets = <128>;
-			i-cache-size = <0xC000>;
+			i-cache-size = <0xc000>;
 			i-cache-line-size = <64>;
 			i-cache-sets = <192>;
 			next-level-cache = <&cluster6_l2>;
@@ -256,7 +256,7 @@ cpu601: cpu at 601 {
 			d-cache-size = <0x8000>;
 			d-cache-line-size = <64>;
 			d-cache-sets = <128>;
-			i-cache-size = <0xC000>;
+			i-cache-size = <0xc000>;
 			i-cache-line-size = <64>;
 			i-cache-sets = <192>;
 			next-level-cache = <&cluster6_l2>;
@@ -273,7 +273,7 @@ cpu700: cpu at 700 {
 			d-cache-size = <0x8000>;
 			d-cache-line-size = <64>;
 			d-cache-sets = <128>;
-			i-cache-size = <0xC000>;
+			i-cache-size = <0xc000>;
 			i-cache-line-size = <64>;
 			i-cache-sets = <192>;
 			next-level-cache = <&cluster7_l2>;
@@ -290,7 +290,7 @@ cpu701: cpu at 701 {
 			d-cache-size = <0x8000>;
 			d-cache-line-size = <64>;
 			d-cache-sets = <128>;
-			i-cache-size = <0xC000>;
+			i-cache-size = <0xc000>;
 			i-cache-line-size = <64>;
 			i-cache-sets = <192>;
 			next-level-cache = <&cluster7_l2>;
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl-mba8mx.dts b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl-mba8mx.dts
index d7f7f9aafb7d..54b6f04645f4 100644
--- a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl-mba8mx.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl-mba8mx.dts
@@ -143,23 +143,23 @@ pinctrl_gpioled: gpioledgrp {
 	};
 
 	pinctrl_i2c2: i2c2grp {
-		fsl,pins = <MX8MN_IOMUXC_I2C2_SCL_I2C2_SCL		0x400001C4>,
-			   <MX8MN_IOMUXC_I2C2_SDA_I2C2_SDA		0x400001C4>;
+		fsl,pins = <MX8MN_IOMUXC_I2C2_SCL_I2C2_SCL		0x400001c4>,
+			   <MX8MN_IOMUXC_I2C2_SDA_I2C2_SDA		0x400001c4>;
 	};
 
 	pinctrl_i2c2_gpio: i2c2gpiogrp {
-		fsl,pins = <MX8MN_IOMUXC_I2C2_SCL_GPIO5_IO16		0x400001C4>,
-			   <MX8MN_IOMUXC_I2C2_SDA_GPIO5_IO17		0x400001C4>;
+		fsl,pins = <MX8MN_IOMUXC_I2C2_SCL_GPIO5_IO16		0x400001c4>,
+			   <MX8MN_IOMUXC_I2C2_SDA_GPIO5_IO17		0x400001c4>;
 	};
 
 	pinctrl_i2c3: i2c3grp {
-		fsl,pins = <MX8MN_IOMUXC_I2C3_SCL_I2C3_SCL		0x400001C4>,
-			   <MX8MN_IOMUXC_I2C3_SDA_I2C3_SDA		0x400001C4>;
+		fsl,pins = <MX8MN_IOMUXC_I2C3_SCL_I2C3_SCL		0x400001c4>,
+			   <MX8MN_IOMUXC_I2C3_SDA_I2C3_SDA		0x400001c4>;
 	};
 
 	pinctrl_i2c3_gpio: i2c3gpiogrp {
-		fsl,pins = <MX8MN_IOMUXC_I2C3_SCL_GPIO5_IO18		0x400001C4>,
-			   <MX8MN_IOMUXC_I2C3_SDA_GPIO5_IO19		0x400001C4>;
+		fsl,pins = <MX8MN_IOMUXC_I2C3_SCL_GPIO5_IO18		0x400001c4>,
+			   <MX8MN_IOMUXC_I2C3_SDA_GPIO5_IO19		0x400001c4>;
 	};
 
 	pinctrl_pwm3: pwm3grp {
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-libra-rdk-fpsc.dts b/arch/arm64/boot/dts/freescale/imx8mp-libra-rdk-fpsc.dts
index 6f3a7b863dca..3f5734abf6f1 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-libra-rdk-fpsc.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-libra-rdk-fpsc.dts
@@ -226,7 +226,7 @@ MX8MP_IOMUXC_UART1_TXD__GPIO5_IO23	0x12
 	};
 	pinctrl_rtc: rtcgrp {
 		fsl,pins = <
-			MX8MP_IOMUXC_UART2_TXD__GPIO5_IO25	0x1C0
+			MX8MP_IOMUXC_UART2_TXD__GPIO5_IO25	0x1c0
 		>;
 	};
 };
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts b/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts
index 9687b4ded8f4..ed29e3b88415 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts
@@ -470,7 +470,7 @@ MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19	0x40
 
 	pinctrl_rtc: rtcgrp {
 		fsl,pins = <
-			MX8MP_IOMUXC_SAI1_TXD7__GPIO4_IO19	0x1C0
+			MX8MP_IOMUXC_SAI1_TXD7__GPIO4_IO19	0x1c0
 		>;
 	};
 
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-toradex-smarc.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-toradex-smarc.dtsi
index bebe19eb360f..0348da385f23 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-toradex-smarc.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-toradex-smarc.dtsi
@@ -1044,7 +1044,7 @@ pinctrl_lvds_dsi_sel: lvdsdsiselgrp {
 	};
 
 	pinctrl_mcu_int: mcuintgrp {
-		fsl,pins = <MX8MP_IOMUXC_NAND_DATA02__GPIO3_IO08	0x1C0>; /* MCU_INT# */
+		fsl,pins = <MX8MP_IOMUXC_NAND_DATA02__GPIO3_IO08	0x1c0>; /* MCU_INT# */
 	};
 
 	/* SMARC LCD1_BKLT_PWM */
@@ -1096,12 +1096,12 @@ pinctrl_sai3: sai3grp {
 
 	/* SMARC SLEEP# */
 	pinctrl_sleep: sleepgrp {
-		fsl,pins = <MX8MP_IOMUXC_NAND_CE0_B__GPIO3_IO01	0x1C0>; /* SMARC S149 - SLEEP# */
+		fsl,pins = <MX8MP_IOMUXC_NAND_CE0_B__GPIO3_IO01	0x1c0>; /* SMARC S149 - SLEEP# */
 	};
 
 	/* SMARC SMB_ALERT# */
 	pinctrl_smb_alert: smbalertgrp {
-		fsl,pins = <MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16	0x1C0>; /* SMARC P1 - SMB_ALERT# */
+		fsl,pins = <MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16	0x1c0>; /* SMARC P1 - SMB_ALERT# */
 	};
 
 	/* TPM_CS# */
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts
index f7346b3d35fe..d5881ee0fe78 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts
@@ -134,7 +134,7 @@ linux,cma {
 			compatible = "shared-dma-pool";
 			reusable;
 			size = <0 0x38000000>;
-			alloc-ranges = <0 0x40000000 0 0xB0000000>;
+			alloc-ranges = <0 0x40000000 0 0xb0000000>;
 			linux,cma-default;
 		};
 	};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
index 59642a8a2c44..ae1f1ec77c14 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
@@ -227,7 +227,7 @@ linux,cma {
 			compatible = "shared-dma-pool";
 			reusable;
 			size = <0 0x38000000>;
-			alloc-ranges = <0 0x40000000 0 0xB0000000>;
+			alloc-ranges = <0 0x40000000 0 0xb0000000>;
 			linux,cma-default;
 		};
 	};
diff --git a/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts b/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts
index d9f203c79519..aadaeef928bd 100644
--- a/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts
@@ -633,7 +633,7 @@ MX8MQ_IOMUXC_SPDIF_RX_GPIO5_IO4		0xc6   /* nHAPTIC */
 
 	pinctrl_hpdet: hpdetgrp {
 		fsl,pins = <
-			MX8MQ_IOMUXC_SAI5_RXC_GPIO3_IO20	0xC0   /* HP_DET */
+			MX8MQ_IOMUXC_SAI5_RXC_GPIO3_IO20	0xc0   /* HP_DET */
 		>;
 	};
 
diff --git a/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi b/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi
index 9e0e2d7271ef..2975e9451661 100644
--- a/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi
@@ -536,9 +536,9 @@ MX8MQ_IOMUXC_I2C4_SDA_I2C4_SDA		0x40000026
 	pinctrl_keys: keysgrp {
 		fsl,pins = <
 			/* VOL- */
-			MX8MQ_IOMUXC_ENET_MDIO_GPIO1_IO17	0x01C0
+			MX8MQ_IOMUXC_ENET_MDIO_GPIO1_IO17	0x01c0
 			/* VOL+ */
-			MX8MQ_IOMUXC_ENET_MDC_GPIO1_IO16	0x01C0
+			MX8MQ_IOMUXC_ENET_MDC_GPIO1_IO16	0x01c0
 		>;
 	};
 
@@ -620,7 +620,7 @@ MX8MQ_IOMUXC_SAI1_TXD5_SAI6_TX_DATA0	0xd6
 	pinctrl_tcpc: tcpcgrp {
 		fsl,pins = <
 			/* TCPC_INT */
-			MX8MQ_IOMUXC_GPIO1_IO10_GPIO1_IO10	0x01C0
+			MX8MQ_IOMUXC_GPIO1_IO10_GPIO1_IO10	0x01c0
 		>;
 	};
 
diff --git a/arch/arm64/boot/dts/freescale/imx8qm-mek.dts b/arch/arm64/boot/dts/freescale/imx8qm-mek.dts
index 779d9f78fb81..7d4574c6de1d 100644
--- a/arch/arm64/boot/dts/freescale/imx8qm-mek.dts
+++ b/arch/arm64/boot/dts/freescale/imx8qm-mek.dts
@@ -1214,17 +1214,17 @@ IMX8QM_LVDS1_I2C1_SDA_LVDS1_I2C1_SDA	0xc600004c
 
 	pinctrl_mipi_csi0: mipi-csi0grp {
 		fsl,pins = <
-			IMX8QM_MIPI_CSI0_GPIO0_00_LSIO_GPIO1_IO27		0xC0000041
-			IMX8QM_MIPI_CSI0_GPIO0_01_LSIO_GPIO1_IO28		0xC0000041
-			IMX8QM_MIPI_CSI0_MCLK_OUT_MIPI_CSI0_ACM_MCLK_OUT	0xC0000041
+			IMX8QM_MIPI_CSI0_GPIO0_00_LSIO_GPIO1_IO27		0xc0000041
+			IMX8QM_MIPI_CSI0_GPIO0_01_LSIO_GPIO1_IO28		0xc0000041
+			IMX8QM_MIPI_CSI0_MCLK_OUT_MIPI_CSI0_ACM_MCLK_OUT	0xc0000041
 		>;
 	};
 
 	pinctrl_mipi_csi1: mipi-csi1grp {
 		fsl,pins = <
-			IMX8QM_MIPI_CSI1_GPIO0_00_LSIO_GPIO1_IO30		0xC0000041
-			IMX8QM_MIPI_CSI1_GPIO0_01_LSIO_GPIO1_IO31		0xC0000041
-			IMX8QM_MIPI_CSI1_MCLK_OUT_MIPI_CSI1_ACM_MCLK_OUT	0xC0000041
+			IMX8QM_MIPI_CSI1_GPIO0_00_LSIO_GPIO1_IO30		0xc0000041
+			IMX8QM_MIPI_CSI1_GPIO0_01_LSIO_GPIO1_IO31		0xc0000041
+			IMX8QM_MIPI_CSI1_MCLK_OUT_MIPI_CSI1_ACM_MCLK_OUT	0xc0000041
 		>;
 	};
 
diff --git a/arch/arm64/boot/dts/freescale/imx8qm.dtsi b/arch/arm64/boot/dts/freescale/imx8qm.dtsi
index cb66853b1cd3..c0a869c88098 100644
--- a/arch/arm64/boot/dts/freescale/imx8qm.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8qm.dtsi
@@ -137,7 +137,7 @@ A72_0: cpu at 100 {
 			reg = <0x0 0x100>;
 			clocks = <&clk IMX_SC_R_A72 IMX_SC_PM_CLK_CPU>;
 			enable-method = "psci";
-			i-cache-size = <0xC000>;
+			i-cache-size = <0xc000>;
 			i-cache-line-size = <64>;
 			i-cache-sets = <256>;
 			d-cache-size = <0x8000>;
@@ -241,7 +241,7 @@ opp-1596000000 {
 	gic: interrupt-controller at 51a00000 {
 		compatible = "arm,gic-v3";
 		reg = <0x0 0x51a00000 0 0x10000>, /* GIC Dist */
-		      <0x0 0x51b00000 0 0xC0000>, /* GICR */
+		      <0x0 0x51b00000 0 0xc0000>, /* GICR */
 		      <0x0 0x52000000 0 0x2000>,  /* GICC */
 		      <0x0 0x52010000 0 0x1000>,  /* GICH */
 		      <0x0 0x52020000 0 0x20000>; /* GICV */
diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts
index 523f48896b6b..90b02fa3c949 100644
--- a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts
+++ b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts
@@ -1030,9 +1030,9 @@ IMX8QXP_FLEXCAN2_RX_ADMA_UART3_RX			0x06000020
 
 	pinctrl_mipi_csi0: mipi-csi0grp {
 		fsl,pins = <
-			IMX8QXP_MIPI_CSI0_GPIO0_01_LSIO_GPIO3_IO07		0xC0000041
-			IMX8QXP_MIPI_CSI0_GPIO0_00_LSIO_GPIO3_IO08		0xC0000041
-			IMX8QXP_MIPI_CSI0_MCLK_OUT_MIPI_CSI0_ACM_MCLK_OUT	0xC0000041
+			IMX8QXP_MIPI_CSI0_GPIO0_01_LSIO_GPIO3_IO07		0xc0000041
+			IMX8QXP_MIPI_CSI0_GPIO0_00_LSIO_GPIO3_IO08		0xc0000041
+			IMX8QXP_MIPI_CSI0_MCLK_OUT_MIPI_CSI0_ACM_MCLK_OUT	0xc0000041
 		>;
 	};
 
diff --git a/arch/arm64/boot/dts/freescale/imx8x-colibri.dtsi b/arch/arm64/boot/dts/freescale/imx8x-colibri.dtsi
index 8e9e841cc828..014808774b0e 100644
--- a/arch/arm64/boot/dts/freescale/imx8x-colibri.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8x-colibri.dtsi
@@ -623,7 +623,7 @@ pinctrl_csi_ctl: csictlgrp {
 	};
 
 	pinctrl_csi_mclk: csimclkgrp {
-		fsl,pins = <IMX8QXP_CSI_MCLK_CI_PI_MCLK				0xC0000041>;	/* SODIMM  75 / X3-12 */
+		fsl,pins = <IMX8QXP_CSI_MCLK_CI_PI_MCLK				0xc0000041>;	/* SODIMM  75 / X3-12 */
 	};
 
 	pinctrl_ext_io0: extio0grp {
diff --git a/arch/arm64/boot/dts/freescale/imx95-15x15-evk.dts b/arch/arm64/boot/dts/freescale/imx95-15x15-evk.dts
index ff720c139a7e..b12687d87920 100644
--- a/arch/arm64/boot/dts/freescale/imx95-15x15-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx95-15x15-evk.dts
@@ -179,7 +179,7 @@ reserved-memory {
 
 		linux_cma: linux,cma {
 			compatible = "shared-dma-pool";
-			alloc-ranges = <0 0x80000000 0 0x7F000000>;
+			alloc-ranges = <0 0x80000000 0 0x7f000000>;
 			reusable;
 			size = <0 0x3c000000>;
 			linux,cma-default;
diff --git a/arch/arm64/boot/dts/freescale/imx95-toradex-smarc.dtsi b/arch/arm64/boot/dts/freescale/imx95-toradex-smarc.dtsi
index afbdadcb3686..a0752f21edf9 100644
--- a/arch/arm64/boot/dts/freescale/imx95-toradex-smarc.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx95-toradex-smarc.dtsi
@@ -153,7 +153,7 @@ linux_cma: linux,cma {
 			compatible = "shared-dma-pool";
 			reusable;
 			size = <0 0x3c000000>;
-			alloc-ranges = <0 0x80000000 0 0x7F000000>;
+			alloc-ranges = <0 0x80000000 0 0x7f000000>;
 			linux,cma-default;
 		};
 	};
diff --git a/arch/arm64/boot/dts/freescale/s32g3.dtsi b/arch/arm64/boot/dts/freescale/s32g3.dtsi
index eff7673e7f34..e314f3c7d61d 100644
--- a/arch/arm64/boot/dts/freescale/s32g3.dtsi
+++ b/arch/arm64/boot/dts/freescale/s32g3.dtsi
@@ -641,9 +641,9 @@ swt6: watchdog at 40208000 {
 			status = "disabled";
 		};
 
-		swt7: watchdog at 4020C000 {
+		swt7: watchdog at 4020c000 {
 			compatible = "nxp,s32g3-swt", "nxp,s32g2-swt";
-			reg = <0x4020C000 0x1000>;
+			reg = <0x4020c000 0x1000>;
 			clocks = <&clks 0x3a>, <&clks 0x3b>, <&clks 0x3b>;
 			clock-names = "counter", "module", "register";
 			status = "disabled";
diff --git a/arch/arm64/boot/dts/freescale/s32gxxxa-evb.dtsi b/arch/arm64/boot/dts/freescale/s32gxxxa-evb.dtsi
index f1969cdcef19..803ff4531077 100644
--- a/arch/arm64/boot/dts/freescale/s32gxxxa-evb.dtsi
+++ b/arch/arm64/boot/dts/freescale/s32gxxxa-evb.dtsi
@@ -197,16 +197,16 @@ dspi1-grp2 {
 		};
 
 		dspi1-grp3 {
-			pinmux = <0x5F0>;
+			pinmux = <0x5f0>;
 			input-enable;
 			slew-rate = <150>;
 			bias-pull-up;
 		};
 
 		dspi1-grp4 {
-			pinmux = <0x3D92>,
-				 <0x3DA2>,
-				 <0x3DB2>;
+			pinmux = <0x3d92>,
+				 <0x3da2>,
+				 <0x3db2>;
 		};
 	};
 
@@ -219,26 +219,26 @@ dspi5-grp0 {
 		};
 
 		dspi5-grp1 {
-			pinmux = <0xA0>;
+			pinmux = <0xa0>;
 			input-enable;
 			slew-rate = <150>;
 			bias-pull-up;
 		};
 
 		dspi5-grp2 {
-			pinmux = <0x3ED2>,
-				 <0x3EE2>,
-				 <0x3EF2>;
+			pinmux = <0x3ed2>,
+				 <0x3ee2>,
+				 <0x3ef2>;
 		};
 
 		dspi5-grp3 {
-			pinmux = <0xB3>;
+			pinmux = <0xb3>;
 			output-enable;
 			slew-rate = <150>;
 		};
 
 		dspi5-grp4 {
-			pinmux = <0xC3>;
+			pinmux = <0xc3>;
 			output-enable;
 			input-enable;
 			slew-rate = <150>;
diff --git a/arch/arm64/boot/dts/freescale/s32gxxxa-rdb.dtsi b/arch/arm64/boot/dts/freescale/s32gxxxa-rdb.dtsi
index 3bc3335c9248..979868f6d2c5 100644
--- a/arch/arm64/boot/dts/freescale/s32gxxxa-rdb.dtsi
+++ b/arch/arm64/boot/dts/freescale/s32gxxxa-rdb.dtsi
@@ -151,16 +151,16 @@ dspi1-grp2 {
 		};
 
 		dspi1-grp3 {
-			pinmux = <0x5F0>;
+			pinmux = <0x5f0>;
 			input-enable;
 			slew-rate = <150>;
 			bias-pull-up;
 		};
 
 		dspi1-grp4 {
-			pinmux = <0x3D92>,
-				 <0x3DA2>,
-				 <0x3DB2>;
+			pinmux = <0x3d92>,
+				 <0x3da2>,
+				 <0x3db2>;
 		};
 	};
 
@@ -173,26 +173,26 @@ dspi5-grp0 {
 		};
 
 		dspi5-grp1 {
-			pinmux = <0xA0>;
+			pinmux = <0xa0>;
 			input-enable;
 			slew-rate = <150>;
 			bias-pull-up;
 		};
 
 		dspi5-grp2 {
-			pinmux = <0x3ED2>,
-				 <0x3EE2>,
-				 <0x3EF2>;
+			pinmux = <0x3ed2>,
+				 <0x3ee2>,
+				 <0x3ef2>;
 		};
 
 		dspi5-grp3 {
-			pinmux = <0xB3>;
+			pinmux = <0xb3>;
 			output-enable;
 			slew-rate = <150>;
 		};
 
 		dspi5-grp4 {
-			pinmux = <0xC3>;
+			pinmux = <0xc3>;
 			output-enable;
 			input-enable;
 			slew-rate = <150>;
-- 
2.51.0



From krzk at kernel.org  Tue Dec 23 07:27:59 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 16:27:59 +0100
Subject: [PATCH] arm64: defconfig: remove SLIM_QCOM_CTRL
In-Reply-To: <aUqo9AV2zSJqr_oE@nuoska>
References: <20251223134807.3543642-1-mikko.rapeli@linaro.org>
 <c06878f7-bb93-4de2-b54a-e97fbc1a333e@kernel.org> <aUqgFCgmBy7H9yW0@nuoska>
 <4f99f3ba-ef5b-4163-ad1a-99527dd96f8a@kernel.org> <aUqo9AV2zSJqr_oE@nuoska>
Message-ID: <6f425362-ad11-43d3-b74f-4576a7dc9954@kernel.org>

On 23/12/2025 15:36, Mikko Rapeli wrote:
>>
>>>
>>> I sent to addresses reported by get_maintainers.pl.
>>
>> There is no output of get_maintainers.pl for this file. It's one of
>> cases where script does not work (I think already documented in
>> maintainer soc profile).
> 
> Sorry, I don't get it. This issue is a generic one since now arm64 defconfig
> has one unknown option. Tools which check kernel config for unknown options
> trigger warnings when arm64 defconfig is used.
> 
> If get_maintainers.pl is broken for this file, then please fix it. I don't
> know how to fix it.

No one knows, partially because it is very, very difficult task, that's
the problem.

Best regards,
Krzysztof


From krzk at kernel.org  Tue Dec 23 07:30:04 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 16:30:04 +0100
Subject: [PATCH] arm64: defconfig: remove SLIM_QCOM_CTRL
In-Reply-To: <6f425362-ad11-43d3-b74f-4576a7dc9954@kernel.org>
References: <20251223134807.3543642-1-mikko.rapeli@linaro.org>
 <c06878f7-bb93-4de2-b54a-e97fbc1a333e@kernel.org> <aUqgFCgmBy7H9yW0@nuoska>
 <4f99f3ba-ef5b-4163-ad1a-99527dd96f8a@kernel.org> <aUqo9AV2zSJqr_oE@nuoska>
 <6f425362-ad11-43d3-b74f-4576a7dc9954@kernel.org>
Message-ID: <b8efa1f8-1e6d-4069-a57a-ab58d5dbc2ce@kernel.org>

On 23/12/2025 16:27, Krzysztof Kozlowski wrote:
> On 23/12/2025 15:36, Mikko Rapeli wrote:
>>>
>>>>
>>>> I sent to addresses reported by get_maintainers.pl.
>>>
>>> There is no output of get_maintainers.pl for this file. It's one of
>>> cases where script does not work (I think already documented in
>>> maintainer soc profile).
>>
>> Sorry, I don't get it. This issue is a generic one since now arm64 defconfig
>> has one unknown option. Tools which check kernel config for unknown options
>> trigger warnings when arm64 defconfig is used.
>>
>> If get_maintainers.pl is broken for this file, then please fix it. I don't
>> know how to fix it.
> 
> No one knows, partially because it is very, very difficult task, that's
> the problem.

Ah, wait, it was fixed already! You just run get_maintainers incorrectly
- You cannot use git fallback here, it's pointless. You could have read
the get_maintainers.pl output.

Best regards,
Krzysztof


From krzysztof.kozlowski at oss.qualcomm.com  Tue Dec 23 07:32:02 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 16:32:02 +0100
Subject: [PATCH 1/2] Documentation/process: maintainer-soc: Be more
 explicit about defconfig
In-Reply-To: <20251223150256.GI9817@pendragon.ideasonboard.com>
References: <20251223142726.73417-3-krzysztof.kozlowski@oss.qualcomm.com>
 <20251223150256.GI9817@pendragon.ideasonboard.com>
Message-ID: <f858ea0e-24d5-4cdd-ab57-dfeebe67ae7b@oss.qualcomm.com>

On 23/12/2025 16:02, Laurent Pinchart wrote:
> Hi Krzysztof,
> 
> On Tue, Dec 23, 2025 at 03:27:27PM +0100, Krzysztof Kozlowski wrote:
>> It is already documented but people still send noticeable amount of
>> patches ignoring the rule - get_maintainers.pl does not work on
>> arm64/configs/defconfig or any other shared ARM defconfig.
>>
>> Be more explicit, that one must not rely on typical/simple approach
>> here for getting To/Cc list.
>>
>> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
>>
>> ---
>>
>> Incorrectly addressed patches for arm64/defconfig are around ~2 per month...
>> ---
>>  Documentation/process/maintainer-soc.rst | 6 ++++--
>>  1 file changed, 4 insertions(+), 2 deletions(-)
>>
>> diff --git a/Documentation/process/maintainer-soc.rst b/Documentation/process/maintainer-soc.rst
>> index 3ba886f52a51..014c639022b2 100644
>> --- a/Documentation/process/maintainer-soc.rst
>> +++ b/Documentation/process/maintainer-soc.rst
>> @@ -57,8 +57,10 @@ Submitting Patches for Given SoC
>>  
>>  All typical platform related patches should be sent via SoC submaintainers
>>  (platform-specific maintainers).  This includes also changes to per-platform or
>> -shared defconfigs (scripts/get_maintainer.pl might not provide correct
>> -addresses in such case).
>> +shared defconfigs. Note that scripts/get_maintainer.pl might not provide
>> +correct addresses for the shared defconfig, so ignore its output and manually
>> +create CC-list based on MAINTAINERS file or use something like
>> +``scripts/get_maintainer.pl -f drivers/soc/FOO/``).
> 
> I fear this will be another piece of documentation that people won't
> read. It would be more effective to implement custom logic in
> get_maintainer.pl (or at least output an informative message).

Part of the logic is already there, but I will not grow that - I don't
want to touch Perl code. It's pretty obvious the tool should be do it,
so feel free to fix it. No point however to stop proper documentation.

Best regards,
Krzysztof


From krzysztof.kozlowski at oss.qualcomm.com  Tue Dec 23 07:36:20 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Tue, 23 Dec 2025 16:36:20 +0100
Subject: [PATCH 1/2] Documentation/process: maintainer-soc: Be more
 explicit about defconfig
In-Reply-To: <87ecolxlvk.fsf@trenco.lwn.net>
References: <20251223142726.73417-3-krzysztof.kozlowski@oss.qualcomm.com>
 <87ecolxlvk.fsf@trenco.lwn.net>
Message-ID: <cd06d5bc-ee77-4e04-ade6-6d650527378a@oss.qualcomm.com>

On 23/12/2025 16:23, Jonathan Corbet wrote:
> Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com> writes:
> 
>> It is already documented but people still send noticeable amount of
>> patches ignoring the rule - get_maintainers.pl does not work on
>> arm64/configs/defconfig or any other shared ARM defconfig.
>>
>> Be more explicit, that one must not rely on typical/simple approach
>> here for getting To/Cc list.
>>
>> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
>>
>> ---
>>
>> Incorrectly addressed patches for arm64/defconfig are around ~2 per month...
>> ---
>>  Documentation/process/maintainer-soc.rst | 6 ++++--
>>  1 file changed, 4 insertions(+), 2 deletions(-)
>>
>> diff --git a/Documentation/process/maintainer-soc.rst b/Documentation/process/maintainer-soc.rst
>> index 3ba886f52a51..014c639022b2 100644
>> --- a/Documentation/process/maintainer-soc.rst
>> +++ b/Documentation/process/maintainer-soc.rst
>> @@ -57,8 +57,10 @@ Submitting Patches for Given SoC
>>  
>>  All typical platform related patches should be sent via SoC submaintainers
>>  (platform-specific maintainers).  This includes also changes to per-platform or
>> -shared defconfigs (scripts/get_maintainer.pl might not provide correct
>> -addresses in such case).
>> +shared defconfigs. Note that scripts/get_maintainer.pl might not provide
>> +correct addresses for the shared defconfig, so ignore its output and manually
>> +create CC-list based on MAINTAINERS file or use something like
>> +``scripts/get_maintainer.pl -f drivers/soc/FOO/``).
>>  
> 
> Like Laurent, I don't see this as being effective.  Why is it that
> get_maintainer.pl fails here?  It seems far better to fix that, if at

Because there is no single maintainer for that file but around 60-80,
depending on the context (who owns the CONFIG symbol). We cannot print
all of them and finding actual owner is not a trivial.

> all possible, rather than expect random contributors to notice this text
> and work around the problem...?

Of course better to fix the tool. Problem is known for years (10? 15?).
Was it fixed? No, although in August finally Sebastian Reichel improved
it a bit (See 750b54513f69f1046895346ea97cc3d96584355e) but did not
solve it, because people do not run get_maintainers.pl correctly.

My template reply, so often pasted on mailing lists, always suggest to
use --no-git-fallback, but it's not the default. We could try to make it
default, but it won't solve the problem - output will be empty:

get_maintainer.pl -f --no-git-fallback arch/arm64/configs/defconfig





Best regards,
Krzysztof


From leo.yan at arm.com  Tue Dec 23 07:36:48 2025
From: leo.yan at arm.com (Leo Yan)
Date: Tue, 23 Dec 2025 15:36:48 +0000
Subject: [PATCH 08/11] tools headers: Sync arm64 headers with kernel
 sources
In-Reply-To: <20251222225716.3565649-8-namhyung@kernel.org>
References: <20251222225716.3565649-1-namhyung@kernel.org>
 <20251222225716.3565649-8-namhyung@kernel.org>
Message-ID: <20251223153648.GG9788@e132581.arm.com>

Hi Namhyung,

On Mon, Dec 22, 2025 at 02:57:13PM -0800, Namhyung Kim wrote:

[...]

>  #define NVIDIA_CPU_PART_DENVER		0x003
>  #define NVIDIA_CPU_PART_CARMEL		0x004
> +#define NVIDIA_CPU_PART_OLYMPUS		0x010

Just remind, this is duplicated with patch [1], so you may decide
which one to pick for merging.

Otherwise, LGTM:

Reviewed-by: Leo Yan <leo.yan at arm.com>

[1] https://lore.kernel.org/linux-perf-users/20251219231325.2742580-2-bwicaksono at nvidia.com/T/#u


From vkoul at kernel.org  Tue Dec 23 07:38:44 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 23 Dec 2025 21:08:44 +0530
Subject: [PATCH v7 4/7] PHY: aspeed: Add ASPEED PCIe PHY driver
In-Reply-To: <20251216-upstream_pcie_rc-v7-4-4aeb0f53c4ce@aspeedtech.com>
References: <20251216-upstream_pcie_rc-v7-0-4aeb0f53c4ce@aspeedtech.com>
 <20251216-upstream_pcie_rc-v7-4-4aeb0f53c4ce@aspeedtech.com>
Message-ID: <aUq3hF7Xfk-f35Nh@vaman>

On 16-12-25, 09:50, Jacky Chou wrote:
> Introduce support for Aspeed PCIe PHY controller available in
> AST2600/2700.

What is with the uppercase "PHY" in patch title instead of lowercase
'phy' as is the convention

> 
> Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
> ---
>  drivers/phy/Kconfig                  |   1 +
>  drivers/phy/Makefile                 |   1 +
>  drivers/phy/aspeed/Kconfig           |  15 +++
>  drivers/phy/aspeed/Makefile          |   2 +
>  drivers/phy/aspeed/phy-aspeed-pcie.c | 209 +++++++++++++++++++++++++++++++++++
>  5 files changed, 228 insertions(+)
> 
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index 678dd0452f0a..f6a8f06fd244 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -103,6 +103,7 @@ config PHY_NXP_PTN3222
>  
>  source "drivers/phy/allwinner/Kconfig"
>  source "drivers/phy/amlogic/Kconfig"
> +source "drivers/phy/aspeed/Kconfig"
>  source "drivers/phy/broadcom/Kconfig"
>  source "drivers/phy/cadence/Kconfig"
>  source "drivers/phy/freescale/Kconfig"
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index bfb27fb5a494..18990c87dfb0 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -15,6 +15,7 @@ obj-$(CONFIG_PHY_AIROHA_PCIE)		+= phy-airoha-pcie.o
>  obj-$(CONFIG_PHY_NXP_PTN3222)		+= phy-nxp-ptn3222.o
>  obj-y					+= allwinner/	\
>  					   amlogic/	\
> +					   aspeed/	\
>  					   broadcom/	\
>  					   cadence/	\
>  					   freescale/	\
> diff --git a/drivers/phy/aspeed/Kconfig b/drivers/phy/aspeed/Kconfig
> new file mode 100644
> index 000000000000..6aeeca84091f
> --- /dev/null
> +++ b/drivers/phy/aspeed/Kconfig
> @@ -0,0 +1,15 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +#
> +# Phy drivers for Aspeed platforms
> +#
> +config PHY_ASPEED_PCIE
> +	tristate "ASPEED PCIe PHY driver"
> +	select GENERIC_PHY
> +	depends on ARCH_ASPEED
> +	default y

NO! why should this driver be default!

> +	help
> +	  This option enables support for the ASPEED PCIe PHY driver.
> +	  The driver provides the necessary interface to control and
> +	  configure the PCIe PHY hardware found on ASPEED SoCs.
> +	  It is required for proper operation of PCIe devices on
> +	  platforms using ASPEED chips.
> \ No newline at end of file

??

> diff --git a/drivers/phy/aspeed/Makefile b/drivers/phy/aspeed/Makefile
> new file mode 100644
> index 000000000000..7203152f44bf
> --- /dev/null
> +++ b/drivers/phy/aspeed/Makefile
> @@ -0,0 +1,2 @@
> +# SPDX-License-Identifier: GPL-2.0
> +obj-$(CONFIG_PHY_ASPEED_PCIE)		+= phy-aspeed-pcie.o
> \ No newline at end of file

Are we expecting more drivers for aspeed, if not move it to drivers/phy/
once we have couple of them we can add a directory

> diff --git a/drivers/phy/aspeed/phy-aspeed-pcie.c b/drivers/phy/aspeed/phy-aspeed-pcie.c
> new file mode 100644
> index 000000000000..3de43a86ac17
> --- /dev/null
> +++ b/drivers/phy/aspeed/phy-aspeed-pcie.c
> @@ -0,0 +1,209 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright 2025 Aspeed Technology Inc.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/iopoll.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>

why do you need this

> +#include <linux/phy/pcie.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/reset.h>
> +#include <linux/slab.h>


Do you need all headers here?

-- 
~Vinod


From wens at kernel.org  Tue Dec 23 07:47:57 2025
From: wens at kernel.org (Chen-Yu Tsai)
Date: Tue, 23 Dec 2025 23:47:57 +0800
Subject: (subset) [PATCH 0/4] arm64: allwinner: a523: Support SPI
 controllers
In-Reply-To: <20251221110513.1850535-1-wens@kernel.org>
References: <20251221110513.1850535-1-wens@kernel.org>
Message-ID: <176650487726.2524343.9774305641530243477.b4-ty@kernel.org>

On Sun, 21 Dec 2025 19:05:07 +0800, Chen-Yu Tsai wrote:
> This series adds support for the SPI controllers found in the Allwinner
> A523 SoC family. The SPI controller is almost the same as the ones in
> previous generations, except that it moved the "RX buffer count"
> register field to a separate register, and that register now reports
> the total count for RX buffer and FIFO.
> 
> In practice the driver has never cared about the buffer count, but if
> any implementation were to use it, this counts as a non-backward
> compatible change.
> 
> [...]

Applied to sunxi/dt-for-6.20 in local tree, thanks!

[3/4] arm64: dts: allwinner: sun55i: Add SPI controllers
      commit: 1bec3bd1f839f269dfdec3c635dd2afe15e30995
[4/4] arm64: dts: allwinner: t527: orangepi-4a: Enable SPI-NOR flash
      commit: bd14ba160bbe863e7b7bc489fd947ae1cdc03047

Best regards,
-- 
Chen-Yu Tsai <wens at kernel.org>



From manivannan.sadhasivam at oss.qualcomm.com  Tue Dec 23 07:58:27 2025
From: manivannan.sadhasivam at oss.qualcomm.com (Manivannan Sadhasivam)
Date: Tue, 23 Dec 2025 21:28:27 +0530
Subject: (subset) [PATCH v7 0/7] Add ASPEED PCIe Root Complex support
In-Reply-To: <20251216-upstream_pcie_rc-v7-0-4aeb0f53c4ce@aspeedtech.com>
References: <20251216-upstream_pcie_rc-v7-0-4aeb0f53c4ce@aspeedtech.com>
Message-ID: <176650550798.2188958.10356654881464455126.b4-ty@kernel.org>


On Tue, 16 Dec 2025 09:49:59 +0800, Jacky Chou wrote:
> This patch series adds support for the ASPEED PCIe Root Complex,
> including device tree bindings, pinctrl support, and the PCIe host controller
> driver. The patches introduce the necessary device tree nodes, pinmux groups,
> and driver implementation to enable PCIe functionality on ASPEED platforms.
> Currently, the ASPEED PCIe Root Complex only supports a single port.
> 
> Summary of changes:
> - Add device tree binding documents for ASPEED PCIe PHY and PCIe RC
> - Update MAINTAINERS for new bindings and driver
> - Implement ASPEED PCIe PHY driver
> - Implement ASPEED PCIe Root Complex host controller driver
> 
> [...]

Applied, thanks!

[2/7] dt-bindings: PCI: Add ASPEED PCIe RC support
      commit: a20df1a7683d6c1416c0f56fb737554b9abe9959
[5/7] PCI: Add FMT, TYPE and CPL status definition for TLP header
      commit: 73ce5ba701a53ad89c623a641401288844f526ac
[6/7] PCI: aspeed: Add ASPEED PCIe RC driver
      commit: 9aa0cb68fcc16280c8c8bdd22dc770af8dd7349f
[7/7] MAINTAINERS: Add ASPEED PCIe RC driver
      commit: e5c2061442dda716fb08cc4eff485220c94e6475

Best regards,
-- 
Manivannan Sadhasivam <mani at kernel.org>



From mani at kernel.org  Tue Dec 23 07:59:12 2025
From: mani at kernel.org (Manivannan Sadhasivam)
Date: Tue, 23 Dec 2025 21:29:12 +0530
Subject: [PATCH v7 7/7] MAINTAINERS: Add ASPEED PCIe RC driver
In-Reply-To: <20251216-upstream_pcie_rc-v7-7-4aeb0f53c4ce@aspeedtech.com>
References: <20251216-upstream_pcie_rc-v7-0-4aeb0f53c4ce@aspeedtech.com>
 <20251216-upstream_pcie_rc-v7-7-4aeb0f53c4ce@aspeedtech.com>
Message-ID: <kbads4vnfjf2ce6sks7bvjmhpt73fmvdmrikxwp7y6wjw3flse@5yer3aegbfo6>

On Tue, Dec 16, 2025 at 09:50:06AM +0800, Jacky Chou wrote:
> Add maintainer for ASPEED PCIe RC driver.
> 
> Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
> ---
>  MAINTAINERS | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index aff3e162180d..c327ea375746 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -3900,6 +3900,18 @@ S:	Maintained
>  F:	Documentation/devicetree/bindings/media/aspeed,video-engine.yaml
>  F:	drivers/media/platform/aspeed/
>  
> +ASPEED PCIE CONTROLLER DRIVER
> +M:	Jacky Chou <jacky_chou at aspeedtech.com>
> +L:	linux-aspeed at lists.ozlabs.org (moderated for non-subscribers)
> +L:	linux-pci at vger.kernel.org
> +L:	linux-phy at lists.infradead.org
> +S:	Maintained
> +F:	Documentation/devicetree/bindings/pci/aspeed,ast2600-pcie.yaml
> +F:	Documentation/devicetree/bindings/phy/aspeed,ast2600-pcie-phy.yaml
> +F:	drivers/pci/controller/pcie-aspeed.c
> +F:	drivers/phy/aspeed/Kconfig
> +F:	drivers/phy/aspeed/pcie-phy-aspeed.c

PHY drivers and binding belong to a separate entry. So I've removed these while
applying.

- Mani

-- 
????????? ????????


From nicolas.frattaroli at collabora.com  Tue Dec 23 08:13:39 2025
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 23 Dec 2025 17:13:39 +0100
Subject: [PATCH v4 07/25] scsi: ufs: mediatek: Rework 0.9V regulator
In-Reply-To: <8206d9e715f7ef987b5369d0bda68cce13528112.camel@mediatek.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
 <20251218-mt8196-ufs-v4-7-ddec7a369dd2@collabora.com>
 <8206d9e715f7ef987b5369d0bda68cce13528112.camel@mediatek.com>
Message-ID: <14003986.uLZWGnKmhe@workhorse>

On Tuesday, 23 December 2025 10:35:39 Central European Standard Time Peter Wang (???) wrote:
> On Thu, 2025-12-18 at 13:54 +0100, Nicolas Frattaroli wrote:
> > 
> > +static int ufs_mtk_get_supplies(struct ufs_mtk_host *host)
> > +{
> > +       struct device *dev = host->hba->dev;
> > +       const struct ufs_mtk_soc_data *data =
> > of_device_get_match_data(dev);
> > +
> > +       if (!data || !data->has_avdd09)
> > +               return 0;
> > 
> 
> 
> Hi Nicolas,
> 
> It seems that has_avdd09 is not necessary, because if the 
> platform does not support avdd09, it will return an error
> (-ENODEV) and bypass the avdd09 flow, right?
> 
> Thanks
> Peter
> 
> 
> 
> 

Hi,

that would allow compatibles that are not allowed to have an avdd09
regulator by the binding (because the SoC doesn't have that pin) to
have one specified in the device tree get picked up. This would then
cause those devices with such a device tree to enter
ufs_mtk_va09_pwr_ctrl(), which is not what we want. While we could
blame this on the DT being wrong in that case, I think it's better
if we avoid such a situation entirely.

Kind regards,
Nicolas Frattaroli




From laurent.pinchart at ideasonboard.com  Tue Dec 23 08:27:56 2025
From: laurent.pinchart at ideasonboard.com (Laurent Pinchart)
Date: Tue, 23 Dec 2025 18:27:56 +0200
Subject: [PATCH 1/2] Documentation/process: maintainer-soc: Be more
 explicit about defconfig
In-Reply-To: <f858ea0e-24d5-4cdd-ab57-dfeebe67ae7b@oss.qualcomm.com>
References: <20251223142726.73417-3-krzysztof.kozlowski@oss.qualcomm.com>
 <20251223150256.GI9817@pendragon.ideasonboard.com>
 <f858ea0e-24d5-4cdd-ab57-dfeebe67ae7b@oss.qualcomm.com>
Message-ID: <20251223162756.GA25011@pendragon.ideasonboard.com>

On Tue, Dec 23, 2025 at 04:32:02PM +0100, Krzysztof Kozlowski wrote:
> On 23/12/2025 16:02, Laurent Pinchart wrote:
> > On Tue, Dec 23, 2025 at 03:27:27PM +0100, Krzysztof Kozlowski wrote:
> >> It is already documented but people still send noticeable amount of
> >> patches ignoring the rule - get_maintainers.pl does not work on
> >> arm64/configs/defconfig or any other shared ARM defconfig.
> >>
> >> Be more explicit, that one must not rely on typical/simple approach
> >> here for getting To/Cc list.
> >>
> >> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
> >>
> >> ---
> >>
> >> Incorrectly addressed patches for arm64/defconfig are around ~2 per month...
> >> ---
> >>  Documentation/process/maintainer-soc.rst | 6 ++++--
> >>  1 file changed, 4 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/Documentation/process/maintainer-soc.rst b/Documentation/process/maintainer-soc.rst
> >> index 3ba886f52a51..014c639022b2 100644
> >> --- a/Documentation/process/maintainer-soc.rst
> >> +++ b/Documentation/process/maintainer-soc.rst
> >> @@ -57,8 +57,10 @@ Submitting Patches for Given SoC
> >>  
> >>  All typical platform related patches should be sent via SoC submaintainers
> >>  (platform-specific maintainers).  This includes also changes to per-platform or
> >> -shared defconfigs (scripts/get_maintainer.pl might not provide correct
> >> -addresses in such case).
> >> +shared defconfigs. Note that scripts/get_maintainer.pl might not provide
> >> +correct addresses for the shared defconfig, so ignore its output and manually
> >> +create CC-list based on MAINTAINERS file or use something like
> >> +``scripts/get_maintainer.pl -f drivers/soc/FOO/``).
> > 
> > I fear this will be another piece of documentation that people won't
> > read. It would be more effective to implement custom logic in
> > get_maintainer.pl (or at least output an informative message).
> 
> Part of the logic is already there, but I will not grow that - I don't
> want to touch Perl code. It's pretty obvious the tool should be do it,
> so feel free to fix it.

Even if I knew perl, I'd have no time :-)

> No point however to stop proper documentation.

-- 
Regards,

Laurent Pinchart


From francesco at dolcini.it  Tue Dec 23 08:28:26 2025
From: francesco at dolcini.it (Francesco Dolcini)
Date: Tue, 23 Dec 2025 17:28:26 +0100
Subject: [PATCH v1 0/4] arm64: dts: freescale: Add Apalis iMX8QP
Message-ID: <20251223162833.138286-1-francesco@dolcini.it>

From: Francesco Dolcini <francesco.dolcini at toradex.com>

Add support for the NXP i.MX8QP SoC and for Apalis iMX8QP SoM mated with
Apalis Ixora and Apalis Evaluation board.

Apalis iMX8QP is a variant of the Apalis iMX8QM, using an NXP i.MX8QP
SoC instead of the i.MX8QM. The two SoCs are pin to pin compatible, with
the i.MX8QP being a lower end variant, with a slower GPU and one Cortex
A72 core instead of two.

The two Apalis SoMs variants share the same schematics and PCB, and the
iMX8QP variant exists only on revision V1.1 of board.

Link: https://www.nxp.com/products/i.MX8
Link: https://www.toradex.com/computer-on-modules/apalis-arm-family/nxp-imx-8

Francesco Dolcini (4):
  dt-bindings: arm: fsl: Add Apalis iMX8QP
  arm64: dts: imx8qm: Add CPU cluster labels
  arm64: dts: freescale: Add NXP i.MX8QP SoC dtsi
  arm64: dts: freescale: Add Apalis iMX8QP

 .../devicetree/bindings/arm/fsl.yaml          |  6 +++--
 arch/arm64/boot/dts/freescale/Makefile        |  5 ++++
 arch/arm64/boot/dts/freescale/imx8qm.dtsi     |  4 +--
 .../imx8qp-apalis-v1.1-eval-v1.2.dts          | 26 +++++++++++++++++++
 .../dts/freescale/imx8qp-apalis-v1.1-eval.dts | 16 ++++++++++++
 .../imx8qp-apalis-v1.1-ixora-v1.1.dts         | 16 ++++++++++++
 .../imx8qp-apalis-v1.1-ixora-v1.2.dts         | 16 ++++++++++++
 .../dts/freescale/imx8qp-apalis-v1.1.dtsi     | 16 ++++++++++++
 arch/arm64/boot/dts/freescale/imx8qp.dtsi     | 24 +++++++++++++++++
 9 files changed, 125 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm64/boot/dts/freescale/imx8qp-apalis-v1.1-eval-v1.2.dts
 create mode 100644 arch/arm64/boot/dts/freescale/imx8qp-apalis-v1.1-eval.dts
 create mode 100644 arch/arm64/boot/dts/freescale/imx8qp-apalis-v1.1-ixora-v1.1.dts
 create mode 100644 arch/arm64/boot/dts/freescale/imx8qp-apalis-v1.1-ixora-v1.2.dts
 create mode 100644 arch/arm64/boot/dts/freescale/imx8qp-apalis-v1.1.dtsi
 create mode 100644 arch/arm64/boot/dts/freescale/imx8qp.dtsi

-- 
2.47.3



From francesco at dolcini.it  Tue Dec 23 08:28:28 2025
From: francesco at dolcini.it (Francesco Dolcini)
Date: Tue, 23 Dec 2025 17:28:28 +0100
Subject: [PATCH v1 2/4] arm64: dts: imx8qm: Add CPU cluster labels
In-Reply-To: <20251223162833.138286-1-francesco@dolcini.it>
References: <20251223162833.138286-1-francesco@dolcini.it>
Message-ID: <20251223162833.138286-3-francesco@dolcini.it>

From: Francesco Dolcini <francesco.dolcini at toradex.com>

Add labels to the cpu cluster nodes to prepare for the addition of the
i.MX8QP SoC in which these nodes would need to be adjusted from another
DT file.

Signed-off-by: Francesco Dolcini <francesco.dolcini at toradex.com>
---
 arch/arm64/boot/dts/freescale/imx8qm.dtsi | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8qm.dtsi b/arch/arm64/boot/dts/freescale/imx8qm.dtsi
index cb66853b1cd3..e0046f798eca 100644
--- a/arch/arm64/boot/dts/freescale/imx8qm.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8qm.dtsi
@@ -38,7 +38,7 @@ cpus {
 		#size-cells = <0>;
 
 		cpu-map {
-			cluster0 {
+			cluster0: cluster0 {
 				core0 {
 					cpu = <&A53_0>;
 				};
@@ -53,7 +53,7 @@ core3 {
 				};
 			};
 
-			cluster1 {
+			cluster1: cluster1 {
 				core0 {
 					cpu = <&A72_0>;
 				};
-- 
2.47.3



From francesco at dolcini.it  Tue Dec 23 08:28:29 2025
From: francesco at dolcini.it (Francesco Dolcini)
Date: Tue, 23 Dec 2025 17:28:29 +0100
Subject: [PATCH v1 3/4] arm64: dts: freescale: Add NXP i.MX8QP SoC dtsi
In-Reply-To: <20251223162833.138286-1-francesco@dolcini.it>
References: <20251223162833.138286-1-francesco@dolcini.it>
Message-ID: <20251223162833.138286-4-francesco@dolcini.it>

From: Francesco Dolcini <francesco.dolcini at toradex.com>

Add support for NXP i.MX8QP SoC, this is pin to pin compatible variant
of the i.MX8QM, with a slower GPU and one Cortex A72 core instead of
two.

Link: https://www.nxp.com/products/i.MX8
Signed-off-by: Francesco Dolcini <francesco.dolcini at toradex.com>
---
 arch/arm64/boot/dts/freescale/imx8qp.dtsi | 24 +++++++++++++++++++++++
 1 file changed, 24 insertions(+)
 create mode 100644 arch/arm64/boot/dts/freescale/imx8qp.dtsi

diff --git a/arch/arm64/boot/dts/freescale/imx8qp.dtsi b/arch/arm64/boot/dts/freescale/imx8qp.dtsi
new file mode 100644
index 000000000000..26af9c5a51c5
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8qp.dtsi
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
+
+#include "imx8qm.dtsi"
+
+/delete-node/ &A72_1;
+
+&cluster1 {
+	/delete-node/ core1;
+};
+
+&gpu_3d0 {
+	assigned-clock-rates = <625000000>, <625000000>;
+};
+
+&thermal_zones {
+	cpu1-thermal {
+		cooling-maps {
+			map0 {
+				cooling-device =
+					<&A72_0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+			};
+		};
+	};
+};
-- 
2.47.3



From francesco at dolcini.it  Tue Dec 23 08:28:27 2025
From: francesco at dolcini.it (Francesco Dolcini)
Date: Tue, 23 Dec 2025 17:28:27 +0100
Subject: [PATCH v1 1/4] dt-bindings: arm: fsl: Add Apalis iMX8QP
In-Reply-To: <20251223162833.138286-1-francesco@dolcini.it>
References: <20251223162833.138286-1-francesco@dolcini.it>
Message-ID: <20251223162833.138286-2-francesco@dolcini.it>

From: Francesco Dolcini <francesco.dolcini at toradex.com>

Add binding documentation for the Apalis iMX8QP SoM mated with Apalis
Ixora and Apalis Evaluation board.

Apalis iMX8QP is a variant of the Apalis iMX8QM, using an NXP i.MX8QP
SoC instead of the i.MX8QM. The two SoCs are pin to pin compatible, with
the i.MX8QP being a lower end variant, with a slower GPU and one Cortex
A72 core instead of two.

The two Apalis SoMs variants share the same schematics and PCB, and the
iMX8QP variant exists only on revision V1.1 of board.

Link: https://www.nxp.com/products/i.MX8
Link: https://www.toradex.com/computer-on-modules/apalis-arm-family/nxp-imx-8
Signed-off-by: Francesco Dolcini <francesco.dolcini at toradex.com>
---
 Documentation/devicetree/bindings/arm/fsl.yaml | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
index 68a2d5fecc43..611fe36c2884 100644
--- a/Documentation/devicetree/bindings/arm/fsl.yaml
+++ b/Documentation/devicetree/bindings/arm/fsl.yaml
@@ -1333,7 +1333,7 @@ properties:
           - const: toradex,apalis-imx8
           - const: fsl,imx8qm
 
-      - description: i.MX8QM Boards with Toradex Apalis iMX8 V1.1 Modules
+      - description: i.MX8QM/i.MX8QP Boards with Toradex Apalis iMX8 V1.1 Modules
         items:
           - enum:
               - toradex,apalis-imx8-v1.1-eval       # Apalis iMX8 V1.1 Module on Apalis Eval. V1.0/V1.1 Board
@@ -1341,7 +1341,9 @@ properties:
               - toradex,apalis-imx8-v1.1-ixora-v1.1 # Apalis iMX8 V1.1 Module on Ixora V1.1 C. Board
               - toradex,apalis-imx8-v1.1-ixora-v1.2 # Apalis iMX8 V1.1 Module on Ixora V1.2 C. Board
           - const: toradex,apalis-imx8-v1.1
-          - const: fsl,imx8qm
+          - enum:
+              - fsl,imx8qm
+              - fsl,imx8qp
 
       - description: i.MX8QXP based Boards
         items:
-- 
2.47.3



From francesco at dolcini.it  Tue Dec 23 08:28:30 2025
From: francesco at dolcini.it (Francesco Dolcini)
Date: Tue, 23 Dec 2025 17:28:30 +0100
Subject: [PATCH v1 4/4] arm64: dts: freescale: Add Apalis iMX8QP
In-Reply-To: <20251223162833.138286-1-francesco@dolcini.it>
References: <20251223162833.138286-1-francesco@dolcini.it>
Message-ID: <20251223162833.138286-5-francesco@dolcini.it>

From: Francesco Dolcini <francesco.dolcini at toradex.com>

Add support for the Apalis iMX8QP SoM mated with Apalis Ixora and Apalis
Evaluation board.

Apalis iMX8QP is a variant of the Apalis iMX8QM, using an NXP i.MX8QP
SoC instead of the i.MX8QM. The two SoCs are pin to pin compatible, with
the i.MX8QP being a lower end variant, with a slower GPU and one Cortex
A72 core instead of two.

The two Apalis SoMs variants share the same schematics and PCB, and the
iMX8QP variant exists only on revision V1.1 of board.

Link: https://www.nxp.com/products/i.MX8
Link: https://www.toradex.com/computer-on-modules/apalis-arm-family/nxp-imx-8
Signed-off-by: Francesco Dolcini <francesco.dolcini at toradex.com>
---
 arch/arm64/boot/dts/freescale/Makefile        |  5 ++++
 .../imx8qp-apalis-v1.1-eval-v1.2.dts          | 26 +++++++++++++++++++
 .../dts/freescale/imx8qp-apalis-v1.1-eval.dts | 16 ++++++++++++
 .../imx8qp-apalis-v1.1-ixora-v1.1.dts         | 16 ++++++++++++
 .../imx8qp-apalis-v1.1-ixora-v1.2.dts         | 16 ++++++++++++
 .../dts/freescale/imx8qp-apalis-v1.1.dtsi     | 16 ++++++++++++
 6 files changed, 95 insertions(+)
 create mode 100644 arch/arm64/boot/dts/freescale/imx8qp-apalis-v1.1-eval-v1.2.dts
 create mode 100644 arch/arm64/boot/dts/freescale/imx8qp-apalis-v1.1-eval.dts
 create mode 100644 arch/arm64/boot/dts/freescale/imx8qp-apalis-v1.1-ixora-v1.1.dts
 create mode 100644 arch/arm64/boot/dts/freescale/imx8qp-apalis-v1.1-ixora-v1.2.dts
 create mode 100644 arch/arm64/boot/dts/freescale/imx8qp-apalis-v1.1.dtsi

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index f30d3fd724d0..61c7f0383f91 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -350,6 +350,11 @@ dtb-${CONFIG_ARCH_MXC} += imx8qm-mek-ov5640-csi1.dtb
 imx8qm-mek-ov5640-dual-dtbs := imx8qm-mek.dtb imx8qm-mek-ov5640-csi0.dtbo imx8qm-mek-ov5640-csi1.dtbo
 dtb-${CONFIG_ARCH_MXC} += imx8qm-mek-ov5640-dual.dtb
 
+dtb-$(CONFIG_ARCH_MXC) += imx8qp-apalis-v1.1-eval.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8qp-apalis-v1.1-eval-v1.2.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8qp-apalis-v1.1-ixora-v1.1.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8qp-apalis-v1.1-ixora-v1.2.dtb
+
 dtb-$(CONFIG_ARCH_MXC) += imx8qxp-ai_ml.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8qxp-colibri-aster.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8qxp-colibri-eval-v3.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx8qp-apalis-v1.1-eval-v1.2.dts b/arch/arm64/boot/dts/freescale/imx8qp-apalis-v1.1-eval-v1.2.dts
new file mode 100644
index 000000000000..b5318de67cb0
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8qp-apalis-v1.1-eval-v1.2.dts
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright 2024 Toradex
+ */
+
+/dts-v1/;
+
+#include "imx8qp-apalis-v1.1.dtsi"
+#include "imx8-apalis-eval-v1.2.dtsi"
+
+/ {
+	model = "Toradex Apalis iMX8QP V1.1 on Apalis Evaluation Board V1.2";
+	compatible = "toradex,apalis-imx8-v1.1-eval-v1.2",
+		     "toradex,apalis-imx8-v1.1",
+		     "fsl,imx8qp";
+};
+
+/* Apalis MMC1 */
+&usdhc2 {
+	/delete-property/ no-1-8-v;
+};
+
+/* Apalis SD1 */
+&usdhc3 {
+	/delete-property/ no-1-8-v;
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8qp-apalis-v1.1-eval.dts b/arch/arm64/boot/dts/freescale/imx8qp-apalis-v1.1-eval.dts
new file mode 100644
index 000000000000..d558cff2582f
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8qp-apalis-v1.1-eval.dts
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright 2022 Toradex
+ */
+
+/dts-v1/;
+
+#include "imx8qp-apalis-v1.1.dtsi"
+#include "imx8-apalis-eval-v1.1.dtsi"
+
+/ {
+	model = "Toradex Apalis iMX8QP V1.1 on Apalis Evaluation Board";
+	compatible = "toradex,apalis-imx8-v1.1-eval",
+		     "toradex,apalis-imx8-v1.1",
+		     "fsl,imx8qp";
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8qp-apalis-v1.1-ixora-v1.1.dts b/arch/arm64/boot/dts/freescale/imx8qp-apalis-v1.1-ixora-v1.1.dts
new file mode 100644
index 000000000000..a73a6324f552
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8qp-apalis-v1.1-ixora-v1.1.dts
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright 2022 Toradex
+ */
+
+/dts-v1/;
+
+#include "imx8qp-apalis-v1.1.dtsi"
+#include "imx8-apalis-ixora-v1.1.dtsi"
+
+/ {
+	model = "Toradex Apalis iMX8QP V1.1 on Apalis Ixora V1.1 Carrier Board";
+	compatible = "toradex,apalis-imx8-v1.1-ixora-v1.1",
+		     "toradex,apalis-imx8-v1.1",
+		     "fsl,imx8qp";
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8qp-apalis-v1.1-ixora-v1.2.dts b/arch/arm64/boot/dts/freescale/imx8qp-apalis-v1.1-ixora-v1.2.dts
new file mode 100644
index 000000000000..71568d7ec8e5
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8qp-apalis-v1.1-ixora-v1.2.dts
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright 2022 Toradex
+ */
+
+/dts-v1/;
+
+#include "imx8qp-apalis-v1.1.dtsi"
+#include "imx8-apalis-ixora-v1.2.dtsi"
+
+/ {
+	model = "Toradex Apalis iMX8QP V1.1 on Apalis Ixora V1.2 Carrier Board";
+	compatible = "toradex,apalis-imx8-v1.1-ixora-v1.2",
+		     "toradex,apalis-imx8-v1.1",
+		     "fsl,imx8qp";
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8qp-apalis-v1.1.dtsi b/arch/arm64/boot/dts/freescale/imx8qp-apalis-v1.1.dtsi
new file mode 100644
index 000000000000..1e5311512344
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8qp-apalis-v1.1.dtsi
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright 2022 Toradex
+ */
+
+#include "imx8qp.dtsi"
+#include "imx8-apalis-v1.1.dtsi"
+
+&cooling_maps_map0 {
+	cooling-device =
+		<&A53_0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+		<&A53_1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+		<&A53_2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+		<&A53_3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+		<&A72_0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+};
-- 
2.47.3



From shivendra.pratap at oss.qualcomm.com  Tue Dec 23 09:07:31 2025
From: shivendra.pratap at oss.qualcomm.com (Shivendra Pratap)
Date: Tue, 23 Dec 2025 22:37:31 +0530
Subject: [PATCH v18 00/10] Implement PSCI reboot mode driver for PSCI
 resets
Message-ID: <20251223-arm-psci-system_reset2-vendor-reboots-v18-0-32fa9e76efc3@oss.qualcomm.com>

Userspace should be able to initiate device reboots using the various
PSCI SYSTEM_RESET and SYSTEM_RESET2 types defined by PSCI spec. This
patch series introduces psci-reboot-mode driver that registers with
reboot-mode framework to provide this functionality.

The PSCI system reset calls takes two arguments: reset_type and cookie.
It defines predefined reset types, such as warm and cold reset, and
vendor-specific reset types which are SoC vendor specific. To support
these requirements, the reboot-mode framework is enhanced in two key
ways:
1. 64-bit magic support: Extend reboot-mode to handle two 32-bit
arguments (reset_type and cookie) by encoding them into a single 64-bit
magic value.
2. Predefined modes: Add support for predefined reboot modes in the
framework.

With these enhancements, the patch series enables:
 - Warm reset and cold reset as predefined reboot modes.
 - Vendor-specific resets exposed as tunables, configurable via the
   SoC-specific device tree.

Together, these changes allow userspace to trigger all above PSCI resets
from userspace.

Currently three drivers register with reboot-mode framework -
syscon-reboot-mode, nvmem-reboot-mode and qcom-pon. Consolidated
list of commands currently added across various vendor DTs:
 mode-loader
 mode-normal
 mode-bootloader
 mode-charge
 mode-fastboot
 mode-reboot-ab-update
 mode-recovery
 mode-rescue
 mode-shutdown-thermal
 mode-shutdown-thermal-battery

On gs101 we also pass kernel-generated modes from kernel_restart()
or panic(), specifically DM verity's 'dm-verity device corrupted':
	mode-dm-verity-device-corrupted = <0x50>;

- thanks Andre' for providing this.

Detailed list of commands being used by syscon-reboot-mode:
    arm64/boot/dts/exynos/exynosautov9.dtsi:
	mode-bootloader = <EXYNOSAUTOV9_BOOT_BOOTLOADER>;
	mode-fastboot = <EXYNOSAUTOV9_BOOT_FASTBOOT>;
	mode-recovery = <EXYNOSAUTOV9_BOOT_RECOVERY>;

    arm64/boot/dts/exynos/google/gs101.dtsi:
    	mode-bootloader = <0xfc>;
    	mode-charge = <0x0a>;
    	mode-fastboot = <0xfa>;
    	mode-reboot-ab-update = <0x52>;
    	mode-recovery = <0xff>;
    	mode-rescue = <0xf9>;
    	mode-shutdown-thermal = <0x51>;
    	mode-shutdown-thermal-battery = <0x51>;

    arm64/boot/dts/hisilicon/hi3660-hikey960.dts:
    	mode-normal = <0x77665501>;
    	mode-bootloader = <0x77665500>;
    	mode-recovery = <0x77665502>;

    arm64/boot/dts/hisilicon/hi6220-hikey.dts:
    	mode-normal = <0x77665501>;
    	mode-bootloader = <0x77665500>;
    	mode-recovery = <0x77665502>;

    arm64/boot/dts/rockchip/px30.dtsi:
    	mode-bootloader = <BOOT_BL_DOWNLOAD>;
    	mode-fastboot = <BOOT_FASTBOOT>;
    	mode-loader = <BOOT_BL_DOWNLOAD>;
    	mode-normal = <BOOT_NORMAL>;
    	mode-recovery = <BOOT_RECOVERY>;

    arm64/boot/dts/rockchip/rk3308.dtsi:
    	mode-bootloader = <BOOT_BL_DOWNLOAD>;
    	mode-loader = <BOOT_BL_DOWNLOAD>;
    	mode-normal = <BOOT_NORMAL>;
    	mode-recovery = <BOOT_RECOVERY>;
    	mode-fastboot = <BOOT_FASTBOOT>;

    arm64/boot/dts/rockchip/rk3566-lckfb-tspi.dts:
    	mode-normal = <BOOT_NORMAL>;
    	mode-loader = <BOOT_BL_DOWNLOAD>;
			mode-recovery = <BOOT_RECOVERY>;
			mode-bootloader = <BOOT_FASTBOOT>;

Detailed list of commands being used by nvmem-reboot-mode:
    arm64/boot/dts/qcom/pmXXXX.dtsi:(multiple qcom DTs)
			mode-recovery = <0x01>;
			mode-bootloader = <0x02>;

The patch is tested on rb3Gen2, lemans-ride, lemans-evk, monaco-ride,
qcs615-ride.

@Florian/@Kathiravan, Please note that reset_type in DT needs to be
full in itself with 31st bit set. (eg: 0x80000000).

Previous discussions around SYSTEM_RESET2:
- https://lore.kernel.org/lkml/20230724223057.1208122-2-quic_eberman at quicinc.com/T/
- https://lore.kernel.org/all/4a679542-b48d-7e11-f33a-63535a5c68cb at quicinc.com/

Signed-off-by: Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>

Changes in v18:
 power: reset: reboot-mode: Remove devres based allocations
 - Update commit text for alignment. ? Bart
 - Read magic before assigning kzalloc(info) in reboot_mode_register. - Mukesh
 - Update error handling path. - Mukesh
By Bjorn
 - Expose sysfs for reboot-mode bisected to different series-
   Link: https://lore.kernel.org/all/20251222-next-15nov_expose_sysfs-v21-0-244614135fd8 at oss.qualcomm.com/
By Bjorn/Lorenzo/Mukesh
  power: reset: reboot-mode: Add support for 64 bit magic
  - Use FIELD_GET/FIELD_PREP for u64 magic wherever required.
  - Update commit text and add documentation for structure of 64 bit magic.
By Lorenzo
 - Remove direct reboot-mode registration by psci driver.
 - Add support for predefined reboot modes in reboot-mode framework.
 - Add psci-reboot-mode driver and implement a psci-resets to accommodate
   all psci-resets including warm, cold and customizable vendor-resets.
By Bjorn
 - Update DT patches for qcm6490, lemans, monaco and tolos.
  - Update commit text to include more details ? By Bjorn
For Alignment
 - dt-bindings: arm: Document reboot mode magic
   - Update reboot mode documentation to clarify that argument1 should provide
     full value of reset_type along with the 31st bit wherever required.
 - DT patches for qcm6490, lemans, monaco and tolos.
   - Provide full value of reset_type including 31st bit.(eg:0x80000001).
- Link to v17: https://lore.kernel.org/r/20251109-arm-psci-system_reset2-vendor-reboots-v17-0-46e085bca4cc at oss.qualcomm.com

Changes in v17:
 Remove the patch to synchronize list traversal - Bjorn
 power: reset: reboot-mode: Remove devres based allocations
   - Remove devres based allocations as a fix   - Bartosz
 power: reset: reboot-mode: Expose sysfs for registered reboot_modes
   - remove devres based allocations in create_reboot_mode_device
     and manually free resources on failure.    - Bartosz
   - Add driver data while creating reboot device and
     retrive the same in reboot_mode_show.      - Bartosz
   - Remove the mutex lock.
 firmware: psci: Implement vendor-specific resets as reboot-mode
   - Call put_device(np) once processing is complete - Pavan Kondeti
 Move reboot-mode to SOC DT wherever applicable - Mukesh Ojha
- Link to v16: https://lore.kernel.org/r/20251015-arm-psci-system_reset2-vendor-reboots-v16-0-b98aedaa23ee at oss.qualcomm.com

Changes in v16:
 firmware: psci: Implement vendor-specific resets as reboot-mode
  - Use GENMASK(31, 0) instead of 0xffffffff - by Kathiravan
- Link to v15: https://lore.kernel.org/r/20250922-arm-psci-system_reset2-vendor-reboots-v15-0-7ce3a08878f1 at oss.qualcomm.com

Changes in v15:
By Sebastian:
  power: reset: reboot-mode: Synchronize list traversal
   - Change mutex locking to scoped_guard() and a Fixes: tag
  power: reset: reboot-mode: Add device tree node-based registration
   - Change reboot_mode_register external call to use fwnode
  power: reset: reboot-mode: Expose sysfs for registered reboot_modes
   - Use sysfs_emit_at for printing sysfs entries
   - Add driver_name to struct reboot_mode_driver instead of passing
     as argument
   - Update reboot_mode_register, devm_reboot_mode_register and
     create_reboot_mode_device for same.
  firmware: psci: Implement vendor-specific resets as reboot-mode
   - Update psci to use updated reboot_mode_register and store driver_name
     to struct reboot_mode_driver
- Add DT nodes for PSCI SYSTEM_RESET2 types for lemans-evk, qcs8300-ride,
  monaco-evk and qcs615-ride boards.
- Link to v14: https://lore.kernel.org/r/20250815-arm-psci-system_reset2-vendor-reboots-v14-0-37d29f59ac9a at oss.qualcomm.com

Changes in v14:
- mode-dm-verity-device-corrupted documented in cover letter -by Andr?
 ABI Documentation:
- Updated KernelVersion in ABI documentation to reflect base commit
  version. ? by Andr?
- Revised ABI documentation to clarify space-separated format for
  supported reboot-mode commands. ? by Andr?
 power: reset: reboot-mode: Expose sysfs patch
- Modified `show_modes` to output a space-separated list of supported
  reboot modes ? by Andr?
- Added error handling in `create_reboot_mode_device()` to ensure
  proper cleanup on failure.
 firmware: psci:
- Locate psci/reboot-mode node using psci compatible. - by Krzysztof,
  Dmitry, Sudeep.
- Added error handling for additional code for compatible.
- Converted hex values to lowercase for consistency. ? by Andr?
- Introduced panic notifier to disable valid vendor-reset flag in
  panic path. ? by Andr?
- Added check for `psci_system_reset2` before registering vendor reset
  commands.
- Updated Commit text.
 dts: sa8775p:
- DT file name changed from sa8775p to lemans and commit text updated
  accordingly. ? for dt renaming in base commit (sa8775p to lemans).
- Link to v13: https://lore.kernel.org/r/20250727-arm-psci-system_reset2-vendor-reboots-v13-0-6b8d23315898 at oss.qualcomm.com

Changes in v13:
- Split patch1 into two (Synchronize list traversal and DT node-based
  registration) - by Dmitry.
- Move mutex lock inside get_reboot_mode_magic - by Dmitry.
- Reorder the patches ? pull patch8 for exposing reboot-mode sysfs before
  psci patch - to align the change in reboot-mode sysfs patch.
- Update patch- reboot-mode: Expose sysfs for registered reboot_modes
     - Introduce a driver_name in reboot_mode_register. This will be used
       in sysfs creation  -  by Arnd.
     - Update documentation and commit text for above.
     - Fix release function to properly call delete attr file.
     - Fix sparse warning for devres_find.
     - Add error handling for devres_find.
- Split ABI documentation as a separate patch and update ABI documentation
  for usage of driver-name in sysfs - by Arnd
- Update patch - psci: Implement vendor-specific resets as reboot-mode
     - Fix Kconfig for CONFIG related warning.
     - Add driver_name as "psci" in register call to reboot-mode - by Arnd
- Link to v12: https://lore.kernel.org/r/20250721-arm-psci-system_reset2-vendor-reboots-v12-0-87bac3ec422e at oss.qualcomm.com

Changes in v12:
- Added lock for list traversals in reboot-mode - by Dmitry.
- Added proper handling for BE and LE cases in reboot-mode - by Dmitry.
- Removed type casting for u64 to u32 conversions. Added limit checks
  and used bitwise operations for same - by Andrew.
- Link to v11: https://lore.kernel.org/r/20250717-arm-psci-system_reset2-vendor-reboots-v11-0-df3e2b2183c3 at oss.qualcomm.com

Changes in v11:
- Remove reference of cookie in reboot-mode ? Arnd/Rob
- Introduce 64-bit magic in reboot-mode to accommodate two 32-bit
  arguments ? Arnd
- Change reset-type to reboot-mode in psci device tree binding ? Arnd
	- binding no more mandates two arguments as in v10.
	- dt changes done to support this binding.
- Remove obvious comments in psci reset path ? Konrad
- Merge sysfs and ABI doc into single patch.
- Fix compilation issue on X86 configs.
- Fix warnings for pr_fmt.
- Link to v10: https://lore.kernel.org/all/569f154d-c714-1714-b898-83a42a38771c at oss.qualcomm.com/

Changes in V10:
- Change in reset-type binding to make cookie as a mandatory
  argument.
- Change reboot-mode binding to support additional argument
  "cookie".
 From Lorenzo:
- Use reboot-mode framework for implementing vendor-resets.
- Modify reboot-mode framework to support two arguments
  (magic and cookie).
- Expose sysfs for supported reboot-modes commands.
- List out all existing reboot-mode commands and their users.
   - Added this to cover letter.
 From Dmitry:
- Modify reboot-mode to support non-device based registration.
- Modify reboot-mode to create a class and device to expose
  sysfs interface.
- Link to v9: https://lore.kernel.org/all/20250303-arm-psci-system_reset2-vendor-reboots-v9-0-b2cf4a20feda at oss.qualcomm.com/

Changes in v9:
- Don't fallback to architecturally defined resets from Lorenzo.
- Link to v8: https://lore.kernel.org/r/20241107-arm-psci-system_reset2-vendor-reboots-v8-0-e8715fa65cb5 at quicinc.com

Changes in v8:
- Code style nits from Stephen
- Add rb3gen2
- Link to v7: https://lore.kernel.org/r/20241028-arm-psci-system_reset2-vendor-reboots-v7-0-a4c40b0ebc54 at quicinc.com

Changes in v7:
- Code style nits from Stephen
- Dropped unnecessary hunk from the sa8775p-ride patch
- Link to v6: https://lore.kernel.org/r/20241018-arm-psci-system_reset2-vendor-reboots-v6-0-50cbe88b0a24 at quicinc.com

Changes in v6:
- Rebase to v6.11 and fix trivial conflicts in qcm6490-idp
- Add sa8775p-ride support (same as qcm6490-idp)
- Link to v5: https://lore.kernel.org/r/20240617-arm-psci-system_reset2-vendor-reboots-v5-0-086950f650c8 at quicinc.com

Changes in v5:
- Drop the nested "items" in prep for future dtschema tools
- Link to v4: https://lore.kernel.org/r/20240611-arm-psci-system_reset2-vendor-reboots-v4-0-98f55aa74ae8 at quicinc.com

Changes in v4:
- Change mode- properties from uint32-matrix to uint32-array
- Restructure the reset-types node so only the restriction is in the
  if/then schemas and not the entire definition
- Link to v3: https://lore.kernel.org/r/20240515-arm-psci-system_reset2-vendor-reboots-v3-0-16dd4f9c0ab4 at quicinc.com

Changes in v3:
- Limit outer number of items to 1 for mode-* properties
- Move the reboot-mode for psci under a subnode "reset-types"
- Fix the DT node in qcm6490-idp so it doesn't overwrite the one from
  sc7820.dtsi
- Link to v2: https://lore.kernel.org/r/20240414-arm-psci-system_reset2-vendor-reboots-v2-0-da9a055a648f at quicinc.com

Changes in v2:
- Fixes to schema as suggested by Rob and Krzysztof
- Add qcm6490 idp as first Qualcomm device to support
- Link to v1: https://lore.kernel.org/r/20231117-arm-psci-system_reset2-vendor-reboots-v1-0-03c4612153e2 at quicinc.com

Changes in v1:
- Reference reboot-mode bindings as suggeted by Rob.
- Link to RFC: https://lore.kernel.org/r/20231030-arm-psci-system_reset2-vendor-reboots-v1-0-dcdd63352ad1 at quicinc.com

---
Shivendra Pratap (10):
      power: reset: reboot-mode: Remove devres based allocations
      power: reset: reboot-mode: Add support for 64 bit magic
      power: reset: reboot-mode: Add support for predefined reboot modes
      firmware: psci: Introduce command-based reset in psci_sys_reset
      dt-bindings: arm: Document reboot mode magic
      power: reset: Add psci-reboot-mode driver
      arm64: dts: qcom: qcm6490: Add psci reboot-modes
      arm64: dts: qcom: lemans: Add psci reboot-modes
      arm64: dts: qcom: monaco: Add psci reboot-modes
      arm64: dts: qcom: talos: Add psci reboot-modes

 Documentation/devicetree/bindings/arm/psci.yaml |  42 +++++++++
 arch/arm64/boot/dts/qcom/kodiak.dtsi            |   2 +-
 arch/arm64/boot/dts/qcom/lemans.dtsi            |   5 ++
 arch/arm64/boot/dts/qcom/monaco.dtsi            |   5 ++
 arch/arm64/boot/dts/qcom/qcm6490-idp.dts        |   7 ++
 arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts    |   7 ++
 arch/arm64/boot/dts/qcom/talos.dtsi             |   5 ++
 drivers/firmware/psci/psci.c                    |  46 +++++++++-
 drivers/power/reset/Kconfig                     |  10 +++
 drivers/power/reset/Makefile                    |   1 +
 drivers/power/reset/nvmem-reboot-mode.c         |  11 ++-
 drivers/power/reset/psci-reboot-mode.c          | 111 ++++++++++++++++++++++++
 drivers/power/reset/qcom-pon.c                  |   9 +-
 drivers/power/reset/reboot-mode.c               |  79 ++++++++++++-----
 drivers/power/reset/syscon-reboot-mode.c        |   9 +-
 include/linux/psci.h                            |   2 +
 include/linux/reboot-mode.h                     |  15 +++-
 17 files changed, 331 insertions(+), 35 deletions(-)
---
base-commit: cc3aa43b44bdb43dfbac0fcb51c56594a11338a8
change-id: 20250709-arm-psci-system_reset2-vendor-reboots-46c80044afcf

Best regards,
-- 
Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>



From shivendra.pratap at oss.qualcomm.com  Tue Dec 23 09:07:32 2025
From: shivendra.pratap at oss.qualcomm.com (Shivendra Pratap)
Date: Tue, 23 Dec 2025 22:37:32 +0530
Subject: [PATCH v18 01/10] power: reset: reboot-mode: Remove devres based
 allocations
In-Reply-To: <20251223-arm-psci-system_reset2-vendor-reboots-v18-0-32fa9e76efc3@oss.qualcomm.com>
References: <20251223-arm-psci-system_reset2-vendor-reboots-v18-0-32fa9e76efc3@oss.qualcomm.com>
Message-ID: <20251223-arm-psci-system_reset2-vendor-reboots-v18-1-32fa9e76efc3@oss.qualcomm.com>

Devres APIs are intended for use in drivers, where the managed lifetime
of resources is tied directly to the driver attach/detach cycle. In
shared subsystem code, there is no guarantee that the subsystem
functions will only be called after a driver has been attached, nor that
they will not be referenced after the managed resources have been
released during driver detach.

To ensure correct lifetime handling, avoid using devres-based
allocations in the reboot-mode and explicitly handle allocation and
cleanup of resources.

Fixes: 4fcd504edbf7 ("power: reset: add reboot mode driver")
Signed-off-by: Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>
---
 drivers/power/reset/reboot-mode.c | 33 +++++++++++++++++++++------------
 1 file changed, 21 insertions(+), 12 deletions(-)

diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c
index fba53f638da04655e756b5f8b7d2d666d1379535..4b6ae4007c4f6fb7d51520b4be2bf3cb1dff518e 100644
--- a/drivers/power/reset/reboot-mode.c
+++ b/drivers/power/reset/reboot-mode.c
@@ -3,6 +3,8 @@
  * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd
  */
 
+#define pr_fmt(fmt)	"reboot-mode: " fmt
+
 #include <linux/device.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -71,9 +73,11 @@ static int reboot_mode_notify(struct notifier_block *this,
 int reboot_mode_register(struct reboot_mode_driver *reboot)
 {
 	struct mode_info *info;
+	struct mode_info *next;
 	struct property *prop;
 	struct device_node *np = reboot->dev->of_node;
 	size_t len = strlen(PREFIX);
+	u32 magic;
 	int ret;
 
 	INIT_LIST_HEAD(&reboot->head);
@@ -82,19 +86,17 @@ int reboot_mode_register(struct reboot_mode_driver *reboot)
 		if (strncmp(prop->name, PREFIX, len))
 			continue;
 
-		info = devm_kzalloc(reboot->dev, sizeof(*info), GFP_KERNEL);
+		if (of_property_read_u32(np, prop->name, &magic)) {
+			pr_err("reboot mode %s without magic number\n", prop->name);
+			continue;
+		}
+
+		info = kzalloc(sizeof(*info), GFP_KERNEL);
 		if (!info) {
 			ret = -ENOMEM;
 			goto error;
 		}
 
-		if (of_property_read_u32(np, prop->name, &info->magic)) {
-			dev_err(reboot->dev, "reboot mode %s without magic number\n",
-				info->mode);
-			devm_kfree(reboot->dev, info);
-			continue;
-		}
-
 		info->mode = kstrdup_const(prop->name + len, GFP_KERNEL);
 		if (!info->mode) {
 			ret =  -ENOMEM;
@@ -102,8 +104,7 @@ int reboot_mode_register(struct reboot_mode_driver *reboot)
 		} else if (info->mode[0] == '\0') {
 			kfree_const(info->mode);
 			ret = -EINVAL;
-			dev_err(reboot->dev, "invalid mode name(%s): too short!\n",
-				prop->name);
+			pr_err("invalid mode name(%s): too short!\n", prop->name);
 			goto error;
 		}
 
@@ -116,8 +117,12 @@ int reboot_mode_register(struct reboot_mode_driver *reboot)
 	return 0;
 
 error:
-	list_for_each_entry(info, &reboot->head, list)
+	kfree(info);
+	list_for_each_entry_safe(info, next, &reboot->head, list) {
+		list_del(&info->list);
 		kfree_const(info->mode);
+		kfree(info);
+	}
 
 	return ret;
 }
@@ -130,11 +135,15 @@ EXPORT_SYMBOL_GPL(reboot_mode_register);
 int reboot_mode_unregister(struct reboot_mode_driver *reboot)
 {
 	struct mode_info *info;
+	struct mode_info *next;
 
 	unregister_reboot_notifier(&reboot->reboot_notifier);
 
-	list_for_each_entry(info, &reboot->head, list)
+	list_for_each_entry_safe(info, next, &reboot->head, list) {
+		list_del(&info->list);
 		kfree_const(info->mode);
+		kfree(info);
+	}
 
 	return 0;
 }

-- 
2.34.1



From shivendra.pratap at oss.qualcomm.com  Tue Dec 23 09:07:33 2025
From: shivendra.pratap at oss.qualcomm.com (Shivendra Pratap)
Date: Tue, 23 Dec 2025 22:37:33 +0530
Subject: [PATCH v18 02/10] power: reset: reboot-mode: Add support for 64
 bit magic
In-Reply-To: <20251223-arm-psci-system_reset2-vendor-reboots-v18-0-32fa9e76efc3@oss.qualcomm.com>
References: <20251223-arm-psci-system_reset2-vendor-reboots-v18-0-32fa9e76efc3@oss.qualcomm.com>
Message-ID: <20251223-arm-psci-system_reset2-vendor-reboots-v18-2-32fa9e76efc3@oss.qualcomm.com>

Current reboot-mode supports a single 32-bit argument for any
supported mode. Some reboot-mode based drivers may require
passing two independent 32-bit arguments during a reboot
sequence, for uses-cases, where a mode requires an additional
argument. Such drivers may not be able to use the reboot-mode
driver. For example, ARM PSCI vendor-specific resets, need two
arguments for its operation ? reset_type and cookie, to complete
the reset operation. If a driver wants to implement this
firmware-based reset, it cannot use reboot-mode framework.

Introduce 64-bit magic values in reboot-mode driver to
accommodate up-to two 32-bit arguments.
u64 magic
--------------------------------------------
|    Higher 32 bit  |   Lower 32 bit       |
|	 arg2	    | 	    arg1	   |
--------------------------------------------

Update current reboot-mode drivers for 64-bit magic.

Reviewed-by: Umang Chheda <umang.chheda at oss.qualcomm.com>
Reviewed-by: Nirmesh Kumar Singh <nirmesh.singh at oss.qualcomm.com>
Signed-off-by: Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>
---
 drivers/power/reset/nvmem-reboot-mode.c  | 10 ++++++----
 drivers/power/reset/qcom-pon.c           |  8 +++++---
 drivers/power/reset/reboot-mode.c        | 24 ++++++++++++++++++------
 drivers/power/reset/syscon-reboot-mode.c |  8 +++++---
 include/linux/reboot-mode.h              |  6 +++++-
 5 files changed, 39 insertions(+), 17 deletions(-)

diff --git a/drivers/power/reset/nvmem-reboot-mode.c b/drivers/power/reset/nvmem-reboot-mode.c
index 41530b70cfc48c2a83fbbd96f523d5816960a0d1..b3d21d39b0f732254c40103db1b51fb7045ce344 100644
--- a/drivers/power/reset/nvmem-reboot-mode.c
+++ b/drivers/power/reset/nvmem-reboot-mode.c
@@ -16,15 +16,17 @@ struct nvmem_reboot_mode {
 	struct nvmem_cell *cell;
 };
 
-static int nvmem_reboot_mode_write(struct reboot_mode_driver *reboot,
-				    unsigned int magic)
+static int nvmem_reboot_mode_write(struct reboot_mode_driver *reboot, u64 magic)
 {
-	int ret;
 	struct nvmem_reboot_mode *nvmem_rbm;
+	u32 magic_arg1;
+	int ret;
 
+	/* Use low 32 bits of magic for argument_1 */
+	magic_arg1 = FIELD_GET(GENMASK_ULL(31, 0), magic);
 	nvmem_rbm = container_of(reboot, struct nvmem_reboot_mode, reboot);
 
-	ret = nvmem_cell_write(nvmem_rbm->cell, &magic, sizeof(magic));
+	ret = nvmem_cell_write(nvmem_rbm->cell, &magic_arg1, sizeof(magic_arg1));
 	if (ret < 0)
 		dev_err(reboot->dev, "update reboot mode bits failed\n");
 
diff --git a/drivers/power/reset/qcom-pon.c b/drivers/power/reset/qcom-pon.c
index 7e108982a582e8243c5c806bd4a793646b87189f..ccce1673b2ec47d02524edd44811d4f528c243e8 100644
--- a/drivers/power/reset/qcom-pon.c
+++ b/drivers/power/reset/qcom-pon.c
@@ -27,17 +27,19 @@ struct qcom_pon {
 	long reason_shift;
 };
 
-static int qcom_pon_reboot_mode_write(struct reboot_mode_driver *reboot,
-				    unsigned int magic)
+static int qcom_pon_reboot_mode_write(struct reboot_mode_driver *reboot, u64 magic)
 {
 	struct qcom_pon *pon = container_of
 			(reboot, struct qcom_pon, reboot_mode);
+	u32 magic_arg1;
 	int ret;
 
+	/* Use low 32 bits of magic for argument_1 */
+	magic_arg1 = FIELD_GET(GENMASK_ULL(31, 0), magic);
 	ret = regmap_update_bits(pon->regmap,
 				 pon->baseaddr + PON_SOFT_RB_SPARE,
 				 GENMASK(7, pon->reason_shift),
-				 magic << pon->reason_shift);
+				 magic_arg1 << pon->reason_shift);
 	if (ret < 0)
 		dev_err(pon->dev, "update reboot mode bits failed\n");
 
diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c
index 4b6ae4007c4f6fb7d51520b4be2bf3cb1dff518e..54adcda57e44edf2fd2cda0f752226f747aa72d7 100644
--- a/drivers/power/reset/reboot-mode.c
+++ b/drivers/power/reset/reboot-mode.c
@@ -17,12 +17,11 @@
 
 struct mode_info {
 	const char *mode;
-	u32 magic;
+	u64 magic;
 	struct list_head list;
 };
 
-static unsigned int get_reboot_mode_magic(struct reboot_mode_driver *reboot,
-					  const char *cmd)
+static u64 get_reboot_mode_magic(struct reboot_mode_driver *reboot, const char *cmd)
 {
 	const char *normal = "normal";
 	struct mode_info *info;
@@ -54,7 +53,7 @@ static int reboot_mode_notify(struct notifier_block *this,
 			      unsigned long mode, void *cmd)
 {
 	struct reboot_mode_driver *reboot;
-	unsigned int magic;
+	u64 magic;
 
 	reboot = container_of(this, struct reboot_mode_driver, reboot_notifier);
 	magic = get_reboot_mode_magic(reboot, cmd);
@@ -77,7 +76,8 @@ int reboot_mode_register(struct reboot_mode_driver *reboot)
 	struct property *prop;
 	struct device_node *np = reboot->dev->of_node;
 	size_t len = strlen(PREFIX);
-	u32 magic;
+	u32 magic_arg1;
+	u32 magic_arg2;
 	int ret;
 
 	INIT_LIST_HEAD(&reboot->head);
@@ -86,10 +86,13 @@ int reboot_mode_register(struct reboot_mode_driver *reboot)
 		if (strncmp(prop->name, PREFIX, len))
 			continue;
 
-		if (of_property_read_u32(np, prop->name, &magic)) {
+		if (of_property_read_u32(np, prop->name, &magic_arg1)) {
 			pr_err("reboot mode %s without magic number\n", prop->name);
 			continue;
 		}
+		/* Default magic_arg2 to zero */
+		if (of_property_read_u32_index(np, prop->name, 1, &magic_arg2))
+			magic_arg2 = 0;
 
 		info = kzalloc(sizeof(*info), GFP_KERNEL);
 		if (!info) {
@@ -97,6 +100,15 @@ int reboot_mode_register(struct reboot_mode_driver *reboot)
 			goto error;
 		}
 
+		/**
+		 * Format of u64 magic
+		 *-------------------------------------------
+		 *|    Higher 32 bit  |   Lower 32 bit      |
+		 *|        arg2       |       arg1          |
+		 *-------------------------------------------
+		 */
+		info->magic = FIELD_PREP(GENMASK_ULL(63, 32), magic_arg2) |
+			      FIELD_PREP(GENMASK_ULL(31, 0), magic_arg1);
 		info->mode = kstrdup_const(prop->name + len, GFP_KERNEL);
 		if (!info->mode) {
 			ret =  -ENOMEM;
diff --git a/drivers/power/reset/syscon-reboot-mode.c b/drivers/power/reset/syscon-reboot-mode.c
index e0772c9f70f7a19cd8ec8a0b7fdbbaa7ba44afd0..eb7fc5b7d6a7ed8a833d4920991c4c40b5b13ca7 100644
--- a/drivers/power/reset/syscon-reboot-mode.c
+++ b/drivers/power/reset/syscon-reboot-mode.c
@@ -20,16 +20,18 @@ struct syscon_reboot_mode {
 	u32 mask;
 };
 
-static int syscon_reboot_mode_write(struct reboot_mode_driver *reboot,
-				    unsigned int magic)
+static int syscon_reboot_mode_write(struct reboot_mode_driver *reboot, u64 magic)
 {
 	struct syscon_reboot_mode *syscon_rbm;
+	u32 magic_arg1;
 	int ret;
 
+	/* Use low 32 bits of magic for argument_1 */
+	magic_arg1 = FIELD_GET(GENMASK_ULL(31, 0), magic);
 	syscon_rbm = container_of(reboot, struct syscon_reboot_mode, reboot);
 
 	ret = regmap_update_bits(syscon_rbm->map, syscon_rbm->offset,
-				 syscon_rbm->mask, magic);
+				 syscon_rbm->mask, magic_arg1);
 	if (ret < 0)
 		dev_err(reboot->dev, "update reboot mode bits failed\n");
 
diff --git a/include/linux/reboot-mode.h b/include/linux/reboot-mode.h
index 4a2abb38d1d612ec0fdf05eb18c98b210f631b7f..a359dc0c6dede0ac5ce67190a00d46a7e7856707 100644
--- a/include/linux/reboot-mode.h
+++ b/include/linux/reboot-mode.h
@@ -2,10 +2,14 @@
 #ifndef __REBOOT_MODE_H__
 #define __REBOOT_MODE_H__
 
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/types.h>
+
 struct reboot_mode_driver {
 	struct device *dev;
 	struct list_head head;
-	int (*write)(struct reboot_mode_driver *reboot, unsigned int magic);
+	int (*write)(struct reboot_mode_driver *reboot, u64 magic);
 	struct notifier_block reboot_notifier;
 };
 

-- 
2.34.1



From shivendra.pratap at oss.qualcomm.com  Tue Dec 23 09:07:34 2025
From: shivendra.pratap at oss.qualcomm.com (Shivendra Pratap)
Date: Tue, 23 Dec 2025 22:37:34 +0530
Subject: [PATCH v18 03/10] power: reset: reboot-mode: Add support for
 predefined reboot modes
In-Reply-To: <20251223-arm-psci-system_reset2-vendor-reboots-v18-0-32fa9e76efc3@oss.qualcomm.com>
References: <20251223-arm-psci-system_reset2-vendor-reboots-v18-0-32fa9e76efc3@oss.qualcomm.com>
Message-ID: <20251223-arm-psci-system_reset2-vendor-reboots-v18-3-32fa9e76efc3@oss.qualcomm.com>

reboot-mode based drivers can define a reboot-mode by adding it under
the reboot-mode node in device tree. This limits such drivers, to define
any predefined reboot-modes statically within the driver and creates a
dependency on device-tree.

Introduce a list for predefined modes in the reboot-mode framework and
process the predefined reboot-modes along with the device-tree defined
reboot-modes. Modify existing reboot-mode based drivers to initialize
the predefined list-head as empty.

This patch enables a reboot mode driver to define reboot-modes through a
predefined static list, in addition to the device-tree based reboot-modes.

Signed-off-by: Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>
---
 drivers/power/reset/nvmem-reboot-mode.c  |  1 +
 drivers/power/reset/qcom-pon.c           |  1 +
 drivers/power/reset/reboot-mode.c        | 28 ++++++++++++++++++++++------
 drivers/power/reset/syscon-reboot-mode.c |  1 +
 include/linux/reboot-mode.h              |  9 +++++++++
 5 files changed, 34 insertions(+), 6 deletions(-)

diff --git a/drivers/power/reset/nvmem-reboot-mode.c b/drivers/power/reset/nvmem-reboot-mode.c
index b3d21d39b0f732254c40103db1b51fb7045ce344..b02a2af31aac52cb0ab19cf5d4d315d17c208f6e 100644
--- a/drivers/power/reset/nvmem-reboot-mode.c
+++ b/drivers/power/reset/nvmem-reboot-mode.c
@@ -44,6 +44,7 @@ static int nvmem_reboot_mode_probe(struct platform_device *pdev)
 
 	nvmem_rbm->reboot.dev = &pdev->dev;
 	nvmem_rbm->reboot.write = nvmem_reboot_mode_write;
+	INIT_LIST_HEAD(&nvmem_rbm->reboot.predefined_modes);
 
 	nvmem_rbm->cell = devm_nvmem_cell_get(&pdev->dev, "reboot-mode");
 	if (IS_ERR(nvmem_rbm->cell)) {
diff --git a/drivers/power/reset/qcom-pon.c b/drivers/power/reset/qcom-pon.c
index ccce1673b2ec47d02524edd44811d4f528c243e8..bf7b9f0bcdcc4c168aa7ff8d6494122d898814b5 100644
--- a/drivers/power/reset/qcom-pon.c
+++ b/drivers/power/reset/qcom-pon.c
@@ -75,6 +75,7 @@ static int qcom_pon_probe(struct platform_device *pdev)
 		pon->reboot_mode.dev = &pdev->dev;
 		pon->reason_shift = reason_shift;
 		pon->reboot_mode.write = qcom_pon_reboot_mode_write;
+		INIT_LIST_HEAD(&pon->reboot_mode.predefined_modes);
 		error = devm_reboot_mode_register(&pdev->dev, &pon->reboot_mode);
 		if (error) {
 			dev_err(&pdev->dev, "can't register reboot mode\n");
diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c
index 54adcda57e44edf2fd2cda0f752226f747aa72d7..c17c61f47f069b96a9b38699de71dc1f30a807c5 100644
--- a/drivers/power/reset/reboot-mode.c
+++ b/drivers/power/reset/reboot-mode.c
@@ -15,12 +15,6 @@
 
 #define PREFIX "mode-"
 
-struct mode_info {
-	const char *mode;
-	u64 magic;
-	struct list_head list;
-};
-
 static u64 get_reboot_mode_magic(struct reboot_mode_driver *reboot, const char *cmd)
 {
 	const char *normal = "normal";
@@ -71,6 +65,7 @@ static int reboot_mode_notify(struct notifier_block *this,
  */
 int reboot_mode_register(struct reboot_mode_driver *reboot)
 {
+	struct mode_info *info_predef;
 	struct mode_info *info;
 	struct mode_info *next;
 	struct property *prop;
@@ -82,6 +77,9 @@ int reboot_mode_register(struct reboot_mode_driver *reboot)
 
 	INIT_LIST_HEAD(&reboot->head);
 
+	if (!np)
+		goto predefined_modes;
+
 	for_each_property_of_node(np, prop) {
 		if (strncmp(prop->name, PREFIX, len))
 			continue;
@@ -123,6 +121,24 @@ int reboot_mode_register(struct reboot_mode_driver *reboot)
 		list_add_tail(&info->list, &reboot->head);
 	}
 
+predefined_modes:
+	list_for_each_entry(info_predef, &reboot->predefined_modes, list) {
+		info = kzalloc(sizeof(*info), GFP_KERNEL);
+		if (!info) {
+			ret = -ENOMEM;
+			goto error;
+		}
+
+		info->mode = kstrdup_const(info_predef->mode, GFP_KERNEL);
+		if (!info->mode) {
+			ret = -ENOMEM;
+			goto error;
+		}
+
+		info->magic = info_predef->magic;
+		list_add_tail(&info->list, &reboot->head);
+	}
+
 	reboot->reboot_notifier.notifier_call = reboot_mode_notify;
 	register_reboot_notifier(&reboot->reboot_notifier);
 
diff --git a/drivers/power/reset/syscon-reboot-mode.c b/drivers/power/reset/syscon-reboot-mode.c
index eb7fc5b7d6a7ed8a833d4920991c4c40b5b13ca7..74e2e14c5d87c54ac24ef63c7905b3266d736439 100644
--- a/drivers/power/reset/syscon-reboot-mode.c
+++ b/drivers/power/reset/syscon-reboot-mode.c
@@ -50,6 +50,7 @@ static int syscon_reboot_mode_probe(struct platform_device *pdev)
 	syscon_rbm->reboot.dev = &pdev->dev;
 	syscon_rbm->reboot.write = syscon_reboot_mode_write;
 	syscon_rbm->mask = 0xffffffff;
+	INIT_LIST_HEAD(&syscon_rbm->reboot.predefined_modes);
 
 	syscon_rbm->map = syscon_node_to_regmap(pdev->dev.parent->of_node);
 	if (IS_ERR(syscon_rbm->map))
diff --git a/include/linux/reboot-mode.h b/include/linux/reboot-mode.h
index a359dc0c6dede0ac5ce67190a00d46a7e7856707..bddec9b7f94187dcb056540df79eea34c25b1d0d 100644
--- a/include/linux/reboot-mode.h
+++ b/include/linux/reboot-mode.h
@@ -4,11 +4,20 @@
 
 #include <linux/bitfield.h>
 #include <linux/bits.h>
+#include <linux/reboot.h>
 #include <linux/types.h>
 
+struct mode_info {
+	const char *mode;
+	u64 magic;
+	struct list_head list;
+};
+
 struct reboot_mode_driver {
 	struct device *dev;
 	struct list_head head;
+	/* List of predefined reboot-modes, a reboot-mode-driver may populate. */
+	struct list_head predefined_modes;
 	int (*write)(struct reboot_mode_driver *reboot, u64 magic);
 	struct notifier_block reboot_notifier;
 };

-- 
2.34.1



From shivendra.pratap at oss.qualcomm.com  Tue Dec 23 09:07:35 2025
From: shivendra.pratap at oss.qualcomm.com (Shivendra Pratap)
Date: Tue, 23 Dec 2025 22:37:35 +0530
Subject: [PATCH v18 04/10] firmware: psci: Introduce command-based reset in
 psci_sys_reset
In-Reply-To: <20251223-arm-psci-system_reset2-vendor-reboots-v18-0-32fa9e76efc3@oss.qualcomm.com>
References: <20251223-arm-psci-system_reset2-vendor-reboots-v18-0-32fa9e76efc3@oss.qualcomm.com>
Message-ID: <20251223-arm-psci-system_reset2-vendor-reboots-v18-4-32fa9e76efc3@oss.qualcomm.com>

PSCI currently supports only COLD reset and ARCH WARM reset based on the
Linux reboot_mode variable. The PSCI specification now includes
SYSTEM_RESET2 for vendor-specific resets, but there's no mechanism to
issue these through psci_sys_reset.

Add a command-based reset mechanism that allows external drivers to set
the psci reset command via a new psci_set_reset_cmd() function.

The psci command-based reset is disabled by default and the
psci_sys_reset follows its original flow until a psci_reset command is
set or a kernel panic is in progress.

Signed-off-by: Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>
---
 drivers/firmware/psci/psci.c | 46 ++++++++++++++++++++++++++++++++++++++++++--
 include/linux/psci.h         |  2 ++
 2 files changed, 46 insertions(+), 2 deletions(-)

diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c
index 38ca190d4a22d6e7e0f06420e8478a2b0ec2fe6f..ad7a3267276f9e26740aea99c11f171ac715f9ba 100644
--- a/drivers/firmware/psci/psci.c
+++ b/drivers/firmware/psci/psci.c
@@ -51,6 +51,15 @@ static int resident_cpu = -1;
 struct psci_operations psci_ops;
 static enum arm_smccc_conduit psci_conduit = SMCCC_CONDUIT_NONE;
 
+struct psci_sys_reset_params {
+	u32 system_reset;
+	u32 reset_type;
+	u32 cookie;
+	bool cmd;
+};
+
+static struct psci_sys_reset_params psci_reset;
+
 bool psci_tos_resident_on(int cpu)
 {
 	return cpu == resident_cpu;
@@ -80,6 +89,29 @@ static u32 psci_cpu_suspend_feature;
 static bool psci_system_reset2_supported;
 static bool psci_system_off2_hibernate_supported;
 
+/**
+ * psci_set_reset_cmd - Sets the psci_reset_cmd for command-based
+ * reset which will be used in psci_sys_reset call.
+ *
+ * @cmd_sys_rst2: Set to true for SYSTEM_RESET2 based resets.
+ * @cmd_reset_type: Set the reset_type argument for psci_sys_reset.
+ * @cmd_cookie: Set the cookie argument for psci_sys_reset.
+ */
+void psci_set_reset_cmd(bool cmd_sys_rst2, u32 cmd_reset_type, u32 cmd_cookie)
+{
+	if (cmd_sys_rst2 && psci_system_reset2_supported) {
+		psci_reset.system_reset = PSCI_FN_NATIVE(1_1, SYSTEM_RESET2);
+		psci_reset.reset_type = cmd_reset_type;
+		psci_reset.cookie = cmd_cookie;
+	} else {
+		psci_reset.system_reset = PSCI_0_2_FN_SYSTEM_RESET;
+		psci_reset.reset_type = 0;
+		psci_reset.cookie = 0;
+	}
+	psci_reset.cmd = true;
+}
+EXPORT_SYMBOL_GPL(psci_set_reset_cmd);
+
 static inline bool psci_has_ext_power_state(void)
 {
 	return psci_cpu_suspend_feature &
@@ -309,14 +341,24 @@ static int get_set_conduit_method(const struct device_node *np)
 static int psci_sys_reset(struct notifier_block *nb, unsigned long action,
 			  void *data)
 {
-	if ((reboot_mode == REBOOT_WARM || reboot_mode == REBOOT_SOFT) &&
-	    psci_system_reset2_supported) {
+	if (((reboot_mode == REBOOT_WARM || reboot_mode == REBOOT_SOFT) &&
+	     psci_system_reset2_supported) && (panic_in_progress() || !psci_reset.cmd)) {
 		/*
 		 * reset_type[31] = 0 (architectural)
 		 * reset_type[30:0] = 0 (SYSTEM_WARM_RESET)
 		 * cookie = 0 (ignored by the implementation)
 		 */
 		invoke_psci_fn(PSCI_FN_NATIVE(1_1, SYSTEM_RESET2), 0, 0, 0);
+	} else if (!panic_in_progress() && psci_reset.cmd) {
+		/*
+		 * Commands are being set in psci_set_reset_cmd
+		 * This issues, SYSTEM_RESET2 arch warm reset or
+		 * SYSTEM_RESET2 vendor-specific reset or
+		 * a SYSTEM_RESET cold reset in accordance with
+		 * the reboot-mode command.
+		 */
+		invoke_psci_fn(psci_reset.system_reset, psci_reset.reset_type,
+			       psci_reset.cookie, 0);
 	} else {
 		invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0);
 	}
diff --git a/include/linux/psci.h b/include/linux/psci.h
index 4ca0060a3fc42ba1ca751c7862fb4ad8dda35a4c..d13ceca88eab8932894051e7c86e806c2ad8a73a 100644
--- a/include/linux/psci.h
+++ b/include/linux/psci.h
@@ -45,8 +45,10 @@ struct psci_0_1_function_ids get_psci_0_1_function_ids(void);
 
 #if defined(CONFIG_ARM_PSCI_FW)
 int __init psci_dt_init(void);
+void psci_set_reset_cmd(bool cmd_sys_rst2, u32 cmd_reset_type, u32 cmd_cookie);
 #else
 static inline int psci_dt_init(void) { return 0; }
+static inline void psci_set_reset_cmd(bool cmd_sys_rst2, u32 cmd_reset_type, u32 cmd_cookie) { }
 #endif
 
 #if defined(CONFIG_ARM_PSCI_FW) && defined(CONFIG_ACPI)

-- 
2.34.1



From shivendra.pratap at oss.qualcomm.com  Tue Dec 23 09:07:36 2025
From: shivendra.pratap at oss.qualcomm.com (Shivendra Pratap)
Date: Tue, 23 Dec 2025 22:37:36 +0530
Subject: [PATCH v18 05/10] dt-bindings: arm: Document reboot mode magic
In-Reply-To: <20251223-arm-psci-system_reset2-vendor-reboots-v18-0-32fa9e76efc3@oss.qualcomm.com>
References: <20251223-arm-psci-system_reset2-vendor-reboots-v18-0-32fa9e76efc3@oss.qualcomm.com>
Message-ID: <20251223-arm-psci-system_reset2-vendor-reboots-v18-5-32fa9e76efc3@oss.qualcomm.com>

Add bindings to describe vendor-specific reboot modes. Values here
correspond to valid parameters to vendor-specific reset types in PSCI
SYSTEM_RESET2 call.

Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>
---
 Documentation/devicetree/bindings/arm/psci.yaml | 42 +++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/psci.yaml b/Documentation/devicetree/bindings/arm/psci.yaml
index 6e2e0c551841111fbb0aa8c0951dca411b94035c..5fdcbf331ea5620363638feb6f8105427a87c00f 100644
--- a/Documentation/devicetree/bindings/arm/psci.yaml
+++ b/Documentation/devicetree/bindings/arm/psci.yaml
@@ -98,6 +98,26 @@ properties:
       [1] Kernel documentation - ARM idle states bindings
         Documentation/devicetree/bindings/cpu/idle-states.yaml
 
+  reboot-mode:
+    type: object
+    $ref: /schemas/power/reset/reboot-mode.yaml#
+    unevaluatedProperties: false
+    properties:
+      # "mode-normal" is just SYSTEM_RESET
+      mode-normal: false
+    patternProperties:
+      "^mode-.*$":
+        minItems: 1
+        maxItems: 2
+        description: |
+          Describes a vendor-specific reset type. The string after "mode-"
+          maps a reboot mode to the parameters in the PSCI SYSTEM_RESET2 call.
+
+          Parameters are named mode-xxx = <type[, cookie]>, where xxx is the
+          name of the magic reboot mode, type corresponds to the reset_type
+          and the values should be provided as per the PSCI SYSTEM_RESET2
+          specs. The cookie value is optional and defaulted to zero.
+
 patternProperties:
   "^power-domain-":
     $ref: /schemas/power/power-domain.yaml#
@@ -137,6 +157,15 @@ allOf:
       required:
         - cpu_off
         - cpu_on
+  - if:
+      not:
+        properties:
+          compatible:
+            contains:
+              const: arm,psci-1.0
+    then:
+      properties:
+        reboot-mode: false
 
 additionalProperties: false
 
@@ -260,4 +289,17 @@ examples:
         domain-idle-states = <&cluster_ret>, <&cluster_pwrdn>;
       };
     };
+
+  - |+
+
+    // Case 5: SYSTEM_RESET2 vendor resets
+    psci {
+      compatible = "arm,psci-1.0";
+      method = "smc";
+
+      reboot-mode {
+        mode-edl = <0x80000000 1>;
+        mode-bootloader = <0x80010001 2>;
+      };
+    };
 ...

-- 
2.34.1



From shivendra.pratap at oss.qualcomm.com  Tue Dec 23 09:07:37 2025
From: shivendra.pratap at oss.qualcomm.com (Shivendra Pratap)
Date: Tue, 23 Dec 2025 22:37:37 +0530
Subject: [PATCH v18 06/10] power: reset: Add psci-reboot-mode driver
In-Reply-To: <20251223-arm-psci-system_reset2-vendor-reboots-v18-0-32fa9e76efc3@oss.qualcomm.com>
References: <20251223-arm-psci-system_reset2-vendor-reboots-v18-0-32fa9e76efc3@oss.qualcomm.com>
Message-ID: <20251223-arm-psci-system_reset2-vendor-reboots-v18-6-32fa9e76efc3@oss.qualcomm.com>

PSCI supports different types of resets like COLD reset, ARCH WARM
reset, vendor-specific resets. Currently there is no common driver that
handles all supported psci resets at one place. Additionally, there is
no common mechanism to issue the supported psci resets from userspace.

Add a PSCI reboot mode driver and define two types of PSCI resets in the
driver as reboot-modes: predefined resets controlled by Linux
reboot_mode and customizable resets defined by SoC vendors in their
device tree under the psci:reboot-mode node.

Register the driver with the reboot-mode framework to interface these
resets to userspace. When userspace initiates a supported command, pass
the reset arguments to the PSCI driver to enable command-based reset.

This change allows userspace to issue supported PSCI reset commands
using the standard reboot system calls while enabling SoC vendors to
define their specific resets for PSCI.

Signed-off-by: Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>
---
 drivers/power/reset/Kconfig            |  10 +++
 drivers/power/reset/Makefile           |   1 +
 drivers/power/reset/psci-reboot-mode.c | 111 +++++++++++++++++++++++++++++++++
 3 files changed, 122 insertions(+)

diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index f6c1bcbb57deff3568d6b1b326454add3b3bbf06..529d6c7d3555601f7b7e6199acd29838030fcef2 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -348,6 +348,16 @@ config NVMEM_REBOOT_MODE
 	  then the bootloader can read it and take different
 	  action according to the mode.
 
+config PSCI_REBOOT_MODE
+	bool "PSCI reboot mode driver"
+	depends on OF && ARM_PSCI_FW
+	select REBOOT_MODE
+	help
+	  Say y here will enable PSCI reboot mode driver. This gets
+          the PSCI reboot mode arguments and passes them to psci
+	  driver. psci driver uses these arguments for issuing
+	  device reset into different boot states.
+
 config POWER_MLXBF
 	tristate "Mellanox BlueField power handling driver"
 	depends on (GPIO_MLXBF2 || GPIO_MLXBF3) && ACPI
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index 0e4ae6f6b5c55729cf60846d47e6fe0fec24f3cc..49774b42cdf61fd57a5b70f286c65c9d66bbc0cb 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -40,4 +40,5 @@ obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o
 obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o
 obj-$(CONFIG_POWER_RESET_SC27XX) += sc27xx-poweroff.o
 obj-$(CONFIG_NVMEM_REBOOT_MODE) += nvmem-reboot-mode.o
+obj-$(CONFIG_PSCI_REBOOT_MODE) += psci-reboot-mode.o
 obj-$(CONFIG_POWER_MLXBF) += pwr-mlxbf.o
diff --git a/drivers/power/reset/psci-reboot-mode.c b/drivers/power/reset/psci-reboot-mode.c
new file mode 100644
index 0000000000000000000000000000000000000000..499cf504071e88022fa5b5b32e26b7a674da8691
--- /dev/null
+++ b/drivers/power/reset/psci-reboot-mode.c
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/device/faux.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/psci.h>
+#include <linux/reboot.h>
+#include <linux/reboot-mode.h>
+#include <linux/types.h>
+
+/*
+ * Predefined reboot-modes:
+ * reset_type(arg1) is zero; cookie(arg2) is stored in magic.
+ * psci_reboot_mode_set_predefined_modes to move values to higher 32 bit of magic.
+ */
+static struct mode_info psci_resets[] = {
+	{ .mode = "warm", .magic = REBOOT_WARM},
+	{ .mode = "soft", .magic = REBOOT_SOFT},
+	{ .mode = "cold", .magic = REBOOT_COLD},
+};
+
+static void psci_reboot_mode_set_predefined_modes(struct reboot_mode_driver *reboot)
+{
+	INIT_LIST_HEAD(&reboot->predefined_modes);
+	for (u32 i = 0; i < ARRAY_SIZE(psci_resets); i++) {
+		/* Move values to higher 32 bit of magic */
+		psci_resets[i].magic = FIELD_PREP(GENMASK_ULL(63, 32), psci_resets[i].magic);
+		INIT_LIST_HEAD(&psci_resets[i].list);
+		list_add_tail(&psci_resets[i].list, &reboot->predefined_modes);
+	}
+}
+
+/*
+ * magic is 64 bit.
+ * arg1 - reset_type(Low 32 bit of magic).
+ * arg2 - cookie(High 32 bit of magic).
+ * arg2(cookie) decides the mode, If arg1(reset_type) is 0;
+ */
+static int psci_reboot_mode_write(struct reboot_mode_driver *reboot, u64 magic)
+{
+	u32 reset_type = FIELD_GET(GENMASK_ULL(31, 0), magic);
+	u32 cookie = FIELD_GET(GENMASK_ULL(63, 32), magic);
+
+	if (reset_type == 0) {
+		if (cookie == REBOOT_WARM || cookie == REBOOT_SOFT)
+			psci_set_reset_cmd(true, 0, 0);
+		else
+			psci_set_reset_cmd(false, 0, 0);
+	} else {
+		psci_set_reset_cmd(true, reset_type, cookie);
+	}
+
+	return NOTIFY_DONE;
+}
+
+static int psci_reboot_mode_probe(struct faux_device *fdev)
+{
+	struct reboot_mode_driver *reboot;
+	struct device_node *psci_np;
+	struct device_node *np;
+	int ret;
+
+	psci_np = of_find_compatible_node(NULL, NULL, "arm,psci-1.0");
+	if (!psci_np)
+		return -ENODEV;
+
+	/*
+	 * Find the psci:reboot-mode node.
+	 * If NULL, continue to register predefined modes.
+	 * np refcount to be handled by dev;
+	 * psci_np refcount is decremented by of_find_node_by_name;
+	 */
+	np = of_find_node_by_name(psci_np, "reboot-mode");
+	fdev->dev.of_node = np;
+
+	reboot = devm_kzalloc(&fdev->dev, sizeof(*reboot), GFP_KERNEL);
+	if (!reboot)
+		return -ENOMEM;
+
+	psci_reboot_mode_set_predefined_modes(reboot);
+	reboot->write = psci_reboot_mode_write;
+	reboot->dev = &fdev->dev;
+
+	ret = devm_reboot_mode_register(&fdev->dev, reboot);
+	if (ret) {
+		dev_err(&fdev->dev, "devm_reboot_mode_register failed %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct faux_device_ops psci_reboot_mode_ops = {
+	.probe = psci_reboot_mode_probe,
+};
+
+static int __init psci_reboot_mode_init(void)
+{
+	struct faux_device *fdev;
+
+	fdev = faux_device_create("psci-reboot-mode", NULL, &psci_reboot_mode_ops);
+	if (!fdev)
+		return -ENODEV;
+
+	return 0;
+}
+device_initcall(psci_reboot_mode_init);

-- 
2.34.1



From shivendra.pratap at oss.qualcomm.com  Tue Dec 23 09:07:38 2025
From: shivendra.pratap at oss.qualcomm.com (Shivendra Pratap)
Date: Tue, 23 Dec 2025 22:37:38 +0530
Subject: [PATCH v18 07/10] arm64: dts: qcom: qcm6490: Add psci reboot-modes
In-Reply-To: <20251223-arm-psci-system_reset2-vendor-reboots-v18-0-32fa9e76efc3@oss.qualcomm.com>
References: <20251223-arm-psci-system_reset2-vendor-reboots-v18-0-32fa9e76efc3@oss.qualcomm.com>
Message-ID: <20251223-arm-psci-system_reset2-vendor-reboots-v18-7-32fa9e76efc3@oss.qualcomm.com>

Add PSCI SYSTEM_RESET2 reboot-modes for qcm6490-idp and qcs6490-rb3gen2
for use by the psci_reboot_mode driver.
The following modes are defined:
- bootloader: reboot into fastboot mode for fastboot flashing.
- edl: reboot into emergency download mode for image loading via
  the Firehose protocol.

Support for these modes is firmware dependent and not available across
all sc7280 based boards.

Signed-off-by: Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>
---
 arch/arm64/boot/dts/qcom/kodiak.dtsi         | 2 +-
 arch/arm64/boot/dts/qcom/qcm6490-idp.dts     | 7 +++++++
 arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts | 7 +++++++
 3 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/qcom/kodiak.dtsi b/arch/arm64/boot/dts/qcom/kodiak.dtsi
index c2ccbb67f800cb9927627f991e3d97174cc73c64..e319a1894901cc9c56a89cb8b8ad0acb7a18dc99 100644
--- a/arch/arm64/boot/dts/qcom/kodiak.dtsi
+++ b/arch/arm64/boot/dts/qcom/kodiak.dtsi
@@ -858,7 +858,7 @@ pmu-a78 {
 		interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_LOW>;
 	};
 
-	psci {
+	psci: psci {
 		compatible = "arm,psci-1.0";
 		method = "smc";
 
diff --git a/arch/arm64/boot/dts/qcom/qcm6490-idp.dts b/arch/arm64/boot/dts/qcom/qcm6490-idp.dts
index 089a027c57d5caed103f41f20c01fe1294b4c950..5816cc1c033c396f49fddbbcd4b09e5a633bc804 100644
--- a/arch/arm64/boot/dts/qcom/qcm6490-idp.dts
+++ b/arch/arm64/boot/dts/qcom/qcm6490-idp.dts
@@ -695,6 +695,13 @@ &pon_resin {
 	status = "okay";
 };
 
+&psci {
+	reboot-mode {
+		mode-bootloader = <0x80010001 0x2>;
+		mode-edl = <0x80000000 0x1>;
+	};
+};
+
 &qupv3_id_0 {
 	status = "okay";
 };
diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
index f29a352b0288e9ef554ecfff59820ba39bf2cdb1..6e836e476d595b7e1b69a0859cf2f697c529cbfa 100644
--- a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
+++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
@@ -935,6 +935,13 @@ &pon_resin {
 	status = "okay";
 };
 
+&psci {
+	reboot-mode {
+		mode-bootloader = <0x80010001 0x2>;
+		mode-edl = <0x80000000 0x1>;
+	};
+};
+
 &qup_uart7_cts {
 	/*
 	 * Configure a bias-bus-hold on CTS to lower power

-- 
2.34.1



From shivendra.pratap at oss.qualcomm.com  Tue Dec 23 09:07:39 2025
From: shivendra.pratap at oss.qualcomm.com (Shivendra Pratap)
Date: Tue, 23 Dec 2025 22:37:39 +0530
Subject: [PATCH v18 08/10] arm64: dts: qcom: lemans: Add psci reboot-modes
In-Reply-To: <20251223-arm-psci-system_reset2-vendor-reboots-v18-0-32fa9e76efc3@oss.qualcomm.com>
References: <20251223-arm-psci-system_reset2-vendor-reboots-v18-0-32fa9e76efc3@oss.qualcomm.com>
Message-ID: <20251223-arm-psci-system_reset2-vendor-reboots-v18-8-32fa9e76efc3@oss.qualcomm.com>

Add PSCI SYSTEM_RESET2 reboot-modes for lemans based boards, for use by
the psci_reboot_mode driver.

The following modes are defined:
- bootloader: reboot into fastboot mode for fastboot flashing.
- edl: reboot into emergency download mode for image loading via
  the Firehose protocol.

Support for these modes is firmware dependent.

Signed-off-by: Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>
---
 arch/arm64/boot/dts/qcom/lemans.dtsi | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi
index 0b154d57ba24e69a9d900f06bbb22baa2781cc3f..cc70316d6949c8a36280b85931c4adec9cd60f62 100644
--- a/arch/arm64/boot/dts/qcom/lemans.dtsi
+++ b/arch/arm64/boot/dts/qcom/lemans.dtsi
@@ -698,6 +698,11 @@ system_pd: power-domain-system {
 			#power-domain-cells = <0>;
 			domain-idle-states = <&cluster_sleep_apss_rsc_pc>;
 		};
+
+		reboot-mode {
+			mode-bootloader = <0x80010001 0x2>;
+			mode-edl = <0x80000000 0x1>;
+		};
 	};
 
 	reserved-memory {

-- 
2.34.1



From shivendra.pratap at oss.qualcomm.com  Tue Dec 23 09:07:40 2025
From: shivendra.pratap at oss.qualcomm.com (Shivendra Pratap)
Date: Tue, 23 Dec 2025 22:37:40 +0530
Subject: [PATCH v18 09/10] arm64: dts: qcom: monaco: Add psci reboot-modes
In-Reply-To: <20251223-arm-psci-system_reset2-vendor-reboots-v18-0-32fa9e76efc3@oss.qualcomm.com>
References: <20251223-arm-psci-system_reset2-vendor-reboots-v18-0-32fa9e76efc3@oss.qualcomm.com>
Message-ID: <20251223-arm-psci-system_reset2-vendor-reboots-v18-9-32fa9e76efc3@oss.qualcomm.com>

Add PSCI SYSTEM_RESET2 reboot-modes for monaco based boards, for use by
the psci_reboot_mode driver.

The following modes are defined:
- bootloader: reboot into fastboot mode for fastboot flashing.
- edl: reboot into emergency download mode for image loading via
  the Firehose protocol.

Support for these modes is firmware dependent.

Signed-off-by: Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>
---
 arch/arm64/boot/dts/qcom/monaco.dtsi | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/monaco.dtsi b/arch/arm64/boot/dts/qcom/monaco.dtsi
index 816fa2af8a9a663b8ad176f93d2f18284a08c3d1..9c8087f870fc8889edffda63c62f4d5167729cbc 100644
--- a/arch/arm64/boot/dts/qcom/monaco.dtsi
+++ b/arch/arm64/boot/dts/qcom/monaco.dtsi
@@ -732,6 +732,11 @@ system_pd: power-domain-system {
 			#power-domain-cells = <0>;
 			domain-idle-states = <&system_sleep>;
 		};
+
+		reboot-mode {
+			mode-bootloader = <0x80010001 0x2>;
+			mode-edl = <0x80000000 0x1>;
+		};
 	};
 
 	reserved-memory {

-- 
2.34.1



From shivendra.pratap at oss.qualcomm.com  Tue Dec 23 09:07:41 2025
From: shivendra.pratap at oss.qualcomm.com (Shivendra Pratap)
Date: Tue, 23 Dec 2025 22:37:41 +0530
Subject: [PATCH v18 10/10] arm64: dts: qcom: talos: Add psci reboot-modes
In-Reply-To: <20251223-arm-psci-system_reset2-vendor-reboots-v18-0-32fa9e76efc3@oss.qualcomm.com>
References: <20251223-arm-psci-system_reset2-vendor-reboots-v18-0-32fa9e76efc3@oss.qualcomm.com>
Message-ID: <20251223-arm-psci-system_reset2-vendor-reboots-v18-10-32fa9e76efc3@oss.qualcomm.com>

Add PSCI SYSTEM_RESET2 reboot-modes for talos based boards, for use by
the psci_reboot_mode driver.

The following modes are defined:
- bootloader: reboot into fastboot mode for fastboot flashing.
- edl: reboot into emergency download mode for image loading via
  the Firehose protocol.

Support for these modes is firmware dependent.

Signed-off-by: Song Xue <quic_songxue at quicinc.com>
Signed-off-by: Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>
---
 arch/arm64/boot/dts/qcom/talos.dtsi | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi
index 95d26e3136229f9015d49e2be22f6b28f1e842f4..11a2cfa209065776a8ae61c6e661c09bb871c400 100644
--- a/arch/arm64/boot/dts/qcom/talos.dtsi
+++ b/arch/arm64/boot/dts/qcom/talos.dtsi
@@ -613,6 +613,11 @@ cluster_pd: power-domain-cluster {
 					      &cluster_sleep_1
 					      &cluster_sleep_2>;
 		};
+
+		reboot-mode {
+			mode-bootloader = <0x80010001 0x2>;
+			mode-edl = <0x80000000 0x1>;
+		};
 	};
 
 	reserved-memory {

-- 
2.34.1



From bmork at telenor.net  Tue Dec 23 09:16:18 2025
From: bmork at telenor.net (=?utf-8?Q?Bj=C3=B8rn_Mork?=)
Date: Tue, 23 Dec 2025 18:16:18 +0100
Subject: [PATCH 1/1] wifi: mt76: mt7996: fix mixed FEM check of mt7996
 chipset
In-Reply-To: <20251223140016.235771-1-amadeus@jmu.edu.cn> (Chukun Pan's
	message of "Tue, 23 Dec 2025 22:00:16 +0800")
References: <87fr96tp7w.fsf@miraculix.mork.no>
	<20251223140016.235771-1-amadeus@jmu.edu.cn>
Message-ID: <87a4z9f7a5.fsf@miraculix.mork.no>

Chukun Pan <amadeus at jmu.edu.cn> writes:

>> The problem is that the patch breaks the other device variant, which
>> used to work before.  If we assume the eeprom data from Zyxel is
>> correct, then this variant is iFEM.
>
> Do you have the specific model name and what the RF chips are?
> The eeprom seems to be fine.

Device with iFEM+eFEM+eFEM, working with your patch:
Zyxel EE4600-00

Readouts from the ADIE_ID registers:

root at ee4600:~# echo 0x0f00002c >/sys/kernel/debug/ieee80211/phy0/mt76/regidx
root at ee4600:~# grep . /sys/kernel/debug/ieee80211/phy0/mt76/rf_regval 
0x79758a02
root at ee4600:~# echo 0x1f00002c >/sys/kernel/debug/ieee80211/phy0/mt76/regidx
root at ee4600:~# grep . /sys/kernel/debug/ieee80211/phy0/mt76/rf_regval 
0x79778a10
root at ee4600:~# echo 0x2f00002c >/sys/kernel/debug/ieee80211/phy0/mt76/regidx
root at ee4600:~# grep . /sys/kernel/debug/ieee80211/phy0/mt76/rf_regval 
0x79778a10

Device with iFEM+iFEM+iFEM, working before and breaking with your patch:
Zyxel WE4600-01

Readouts from the ADIE_ID registers:

root at we4600:~# echo 0x0f00002c >/sys/kernel/debug/ieee80211/phy0/mt76/regidx
root at we4600:~# grep . /sys/kernel/debug/ieee80211/phy0/mt76/rf_regval
0x79758a02
root at we4600:~# echo 0x1f00002c >/sys/kernel/debug/ieee80211/phy0/mt76/regidx
root at we4600:~# grep . /sys/kernel/debug/ieee80211/phy0/mt76/rf_regval
0x79778a11
root at we4600:~# echo 0x2f00002c >/sys/kernel/debug/ieee80211/phy0/mt76/regidx
root at we4600:~# grep . /sys/kernel/debug/ieee80211/phy0/mt76/rf_regval
0x79778a11


I don't know exactly what chips these are.  I have no specs or
datasheets and I haven't removed the heatsink and shielding




Bj?rn


From vkoul at kernel.org  Tue Dec 23 09:33:37 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 23 Dec 2025 23:03:37 +0530
Subject: [PATCH v2] phy: fsl-imx8mq-usb: fix typec orientation switch
 when built as module
In-Reply-To: <20251126140136.1202241-1-fra.schnyder@gmail.com>
References: <20251126140136.1202241-1-fra.schnyder@gmail.com>
Message-ID: <176651121758.749296.4271020306636125527.b4-ty@kernel.org>


On Wed, 26 Nov 2025 15:01:33 +0100, Franz Schnyder wrote:
> Currently, the PHY only registers the typec orientation switch when it
> is built in. If the typec driver is built as a module, the switch
> registration is skipped due to the preprocessor condition, causing
> orientation detection to fail.
> 
> With commit
> 45fe729be9a6 ("usb: typec: Stub out typec_switch APIs when CONFIG_TYPEC=n")
> the preprocessor condition is not needed anymore and the orientation
> switch is correctly registered for both built-in and module builds.
> 
> [...]

Applied, thanks!

[1/1] phy: fsl-imx8mq-usb: fix typec orientation switch when built as module
      commit: 49ccab4bedd4779899246107dc19fb01c5b6fea3

Best regards,
-- 
~Vinod




From vkoul at kernel.org  Tue Dec 23 09:33:55 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 23 Dec 2025 23:03:55 +0530
Subject: [PATCH] phy: stm32-usphyc: Fix off by one in probe()
In-Reply-To: <aTfHcMJK1wFVnvEe@stanley.mountain>
References: <aTfHcMJK1wFVnvEe@stanley.mountain>
Message-ID: <176651123567.749296.7003388912771665169.b4-ty@kernel.org>


On Tue, 09 Dec 2025 09:53:36 +0300, Dan Carpenter wrote:
> The "index" variable is used as an index into the usbphyc->phys[] array
> which has usbphyc->nphys elements.  So if it is equal to usbphyc->nphys
> then it is one element out of bounds.  The "index" comes from the
> device tree so it's data that we trust and it's unlikely to be wrong,
> however it's obviously still worth fixing the bug.  Change the > to >=.
> 
> 
> [...]

Applied, thanks!

[1/1] phy: stm32-usphyc: Fix off by one in probe()
      commit: cabd25b57216ddc132efbcc31f972baa03aad15a

Best regards,
-- 
~Vinod




From vkoul at kernel.org  Tue Dec 23 09:34:06 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 23 Dec 2025 23:04:06 +0530
Subject: [PATCH v2 0/2] phy: rockchip: inno-usb2: fix gadget mode
 disconnection after 6 seconds
In-Reply-To: <20251127-rk3308-fix-usb-gadget-phy-disconnect-v2-0-dac8a02cd2ca@bootlin.com>
References: <20251127-rk3308-fix-usb-gadget-phy-disconnect-v2-0-dac8a02cd2ca@bootlin.com>
Message-ID: <176651124639.749296.13619922936818344494.b4-ty@kernel.org>


On Thu, 27 Nov 2025 11:26:15 +0100, Luca Ceresoli wrote:
> The USB OTG port of the RK3308 exibits a bug when:
> 
>  - configured as peripheral, and
>  - used in gadget mode, and
>  - the USB cable is connected since before booting
> 
> The symptom is: about 6 seconds after configuring gadget mode the device is
> disconnected and then re-enumerated. This happens only once per boot.
> 
> [...]

Applied, thanks!

[1/2] phy: rockchip: inno-usb2: fix disconnection in gadget mode
      commit: 028e8ca7b20fb7324f3e5db34ba8bd366d9d3acc
[2/2] phy: rockchip: inno-usb2: fix communication disruption in gadget mode
      commit: 7d8f725b79e35fa47e42c88716aad8711e1168d8

Best regards,
-- 
~Vinod




From vkoul at kernel.org  Tue Dec 23 09:39:08 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 23 Dec 2025 23:09:08 +0530
Subject: [PATCH v4 01/25] dt-bindings: phy: Add mediatek,mt8196-ufsphy
 variant
In-Reply-To: <20251218-mt8196-ufs-v4-1-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
 <20251218-mt8196-ufs-v4-1-ddec7a369dd2@collabora.com>
Message-ID: <aUrTvAPcHNkyuTol@vaman>

On 18-12-25, 13:54, Nicolas Frattaroli wrote:
> The MediaTek MT8196 SoC includes an M-PHY compatible with the already
> existing mt8183 binding.
> 
> However, one omission from the original binding was that all of these
> variants may have an optional reset.
> 
> Add the new compatible, and also the resets property, with an example.

Acked-by: Vinod Koul <vkoul at kernel.org>


-- 
~Vinod


From vkoul at kernel.org  Tue Dec 23 09:39:27 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 23 Dec 2025 23:09:27 +0530
Subject: [PATCH v4 02/25] dt-bindings: ufs: mediatek,ufs: Complete the
 binding
In-Reply-To: <20251218-mt8196-ufs-v4-2-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
 <20251218-mt8196-ufs-v4-2-ddec7a369dd2@collabora.com>
Message-ID: <aUrTz1xf0t3uxoJD@vaman>

On 18-12-25, 13:54, Nicolas Frattaroli wrote:
> As it stands, the mediatek,ufs.yaml binding is startlingly incomplete.
> Its one example, which is the only real "user" of this binding in
> mainline, uses the deprecated freq-table-hz property.
> 
> The resets, of which there are three optional ones, are completely
> absent.
> 
> The clock description for MT8195 is incomplete, as is the one for
> MT8192. It's not known if the one clock binding for MT8183 is even
> correct, but I do not have access to the necessary code and
> documentation to find this out myself.
> 
> The power supply situation is not much better; the binding describes one
> required power supply, but it's the UFS card supply, not any of the
> supplies feeding the controller silicon.
> 
> No second example is present in the binding, making verification
> difficult.
> 
> Disallow freq-table-hz and move to operating-points-v2. It's fine to
> break compatibility here, as the binding is currently unused and would
> be impossible to correctly use in its current state.
> 
> Add the three resets and the corresponding reset-names property. These
> resets appear to be optional, i.e. not required for the functioning of
> the device.
> 
> Move the list of clock names out of the if condition, and expand it for
> the confirmed clocks I could find by cross-referencing several clock
> drivers. For MT8195, increase the minimum number of clocks to include
> the crypt and rx_symbol ones, as they're internal to the SoC and should
> always be present, and should therefore not be omitted.
> 
> MT8192 gets to have at least 3 clocks, as these were the ones I could
> quickly confirm from a glance at various trees. I can't say this was an
> exhaustive search though, but it's better than the current situation.
> 
> Properly document all supplies, with which pin name on the SoCs they
> supply. Complete the example with them.
> 
> Also add a MT8195 example to the binding, using supply labels that I am
> pretty sure would be the right ones for e.g. the Radxa NIO 12L.

Acked-by: Vinod Koul <vkoul at kernel.org>


-- 
~Vinod


From vkoul at kernel.org  Tue Dec 23 09:39:42 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 23 Dec 2025 23:09:42 +0530
Subject: [PATCH v4 03/25] dt-bindings: ufs: mediatek,ufs: Add mt8196
 variant
In-Reply-To: <20251218-mt8196-ufs-v4-3-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
 <20251218-mt8196-ufs-v4-3-ddec7a369dd2@collabora.com>
Message-ID: <aUrT3pd_rCp_7CQI@vaman>

On 18-12-25, 13:54, Nicolas Frattaroli wrote:
> The MediaTek MT8196 SoC's UFS controller uses three additional clocks
> compared to the MT8195, and a different set of supplies. It is therefore
> not compatible with the MT8195.
> 
> While it does have a AVDD09_UFS_1 pin in addition to the AVDD09_UFS pin,
> it appears that these two pins are commoned together, as the board
> schematic I have access to uses the same supply for both, and the
> downstream driver does not distinguish between the two supplies either.
> 
> Add a compatible for it, and modify the binding correspondingly.

Acked-by: Vinod Koul <vkoul at kernel.org>


-- 
~Vinod


From vkoul at kernel.org  Tue Dec 23 09:39:57 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 23 Dec 2025 23:09:57 +0530
Subject: [PATCH v4 05/25] phy: mediatek: ufs: Add support for resets
In-Reply-To: <20251218-mt8196-ufs-v4-5-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
 <20251218-mt8196-ufs-v4-5-ddec7a369dd2@collabora.com>
Message-ID: <aUrT7R41XJk07Esf@vaman>

On 18-12-25, 13:54, Nicolas Frattaroli wrote:
> The MediaTek UFS PHY supports PHY resets. Until now, they've been
> implemented in the UFS host driver. Since they were never documented in
> the UFS HCI node's DT bindings, and no mainline DT uses it, it's fine if
> it's moved to the correct location, which is the PHY driver.
> 
> Implement the MPHY reset logic in this driver and expose it through the
> phy subsystem's reset op. The reset itself is optional, as judging by
> other mainline devices that use this hardware, it's not required for the
> device to function.
> 
> If no reset is present, the reset op returns -EOPNOTSUPP, which means
> that the ufshci driver can detect it's present and not double sleep in
> its own reset function, where it will call the phy reset.

Acked-by: Vinod Koul <vkoul at kernel.org>


-- 
~Vinod


From vkoul at kernel.org  Tue Dec 23 09:44:29 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 23 Dec 2025 23:14:29 +0530
Subject: [PATCH] phy: fsl-imx8mq-usb: change ssc_range value for
 i.MX8MQ
In-Reply-To: <20251219081354.3806806-1-xu.yang_2@nxp.com>
References: <20251219081354.3806806-1-xu.yang_2@nxp.com>
Message-ID: <176651186992.759340.3813003594906863484.b4-ty@kernel.org>


On Fri, 19 Dec 2025 16:13:54 +0800, Xu Yang wrote:
> According to IC engineer suggestion, set ssc_range as -4003 ppm
> will have more tolerance for EMI, and suitable for more boards.
> Besides, it's confirmed that with this setting the TX SSC test
> will pass on one customer board.
> 
> 

Applied, thanks!

[1/1] phy: fsl-imx8mq-usb: change ssc_range value for i.MX8MQ
      commit: c9d03933ea161a5543e15857ee519c60ec04fe9b

Best regards,
-- 
~Vinod




From vkoul at kernel.org  Tue Dec 23 09:44:33 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 23 Dec 2025 23:14:33 +0530
Subject: [PATCH v2 0/2] Fixup HDMI PLL for phy-rockchip-samsung-hdptx
In-Reply-To: <20251221-phy-hdptx-pll-fix-v2-0-ae4abf7f75a1@collabora.com>
References: <20251221-phy-hdptx-pll-fix-v2-0-ae4abf7f75a1@collabora.com>
Message-ID: <176651187342.759340.7650219710991415977.b4-ty@kernel.org>


On Sun, 21 Dec 2025 12:36:22 +0200, Cristian Ciocaltea wrote:
> The Samsung HDMI/eDP TX PHY is currently not able to provide an accurate
> enough PLL output frequency to match the TMDS rate of a 1080p at 120Hz
> display mode, when used with 10 bpc RGB.
> 
> This patch set adds a new entry to the TMDS configuration table,
> providing the necessary frequency division coefficients for the PHY PLL
> to generate the expected 461.101250 MHz output.
> 
> [...]

Applied, thanks!

[1/2] phy: rockchip: samsung-hdptx: Pre-compute HDMI PLL config for 461.10125 MHz output
      commit: f2daf0c67a1767ff6536aa3e96599afb42ca42e7
[2/2] phy: rockchip: samsung-hdptx: Cleanup TMDS PLL config table
      commit: 3be8131ee936abb6ff56ca9ec9d38c911251410b

Best regards,
-- 
~Vinod




From vkoul at kernel.org  Tue Dec 23 09:44:36 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 23 Dec 2025 23:14:36 +0530
Subject: (subset) [PATCH v2 00/12] Add HDMI support for Mediatek Genio
 510/700/1200-EVK and Radxa NIO-12L boards
In-Reply-To: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
References: <20251217-mtk-genio-evk-hdmi-support-v2-0-a994976bb39a@collabora.com>
Message-ID: <176651187669.759340.13955241073309104035.b4-ty@kernel.org>


On Wed, 17 Dec 2025 11:18:59 +0100, Louis-Alexis Eyraud wrote:
> This patch series adds and enables the HDMI output support for the
> following boards:
> - Mediatek Genio 510-EVK (MT8370)
> - Mediatek Genio 700-EVK (MT8390)
> - Mediatek Genio 1200-EVK (MT8395)
> - Radxa NIO-12L (MT8395)
> 
> [...]

Applied, thanks!

[01/12] dt-bindings: phy: mediatek,hdmi-phy: Fix clock output names for MT8195
        commit: 65790df6dcd2f41fab2288ed3d2c3bca00d8dfd4
[02/12] dt-bindings: phy: mediatek,hdmi-phy: Add support for MT8188 SoC
        commit: 6226f616c8e9ac30c294b86ff59e3a9566e2a8d0
[03/12] dt-bindings: phy: mediatek,hdmi-phy: Document extra clocks for MT8195
        commit: ff89cea2385b6236790f3be2727d9ae527daf4a0

Best regards,
-- 
~Vinod




From vkoul at kernel.org  Tue Dec 23 09:45:11 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 23 Dec 2025 23:15:11 +0530
Subject: [PATCH v3 0/3] Apple Silicon Type-C PHY
In-Reply-To: <20251214-b4-atcphy-v3-0-ba82b20e9459@kernel.org>
References: <20251214-b4-atcphy-v3-0-ba82b20e9459@kernel.org>
Message-ID: <176651191159.759340.7918107926279417342.b4-ty@kernel.org>


On Sun, 14 Dec 2025 11:51:33 +0000, Sven Peter wrote:
> This series adds support for the combined Type-C PHY found in Apple
> Silicon machines and required for USB3, DP-AltMode, and Thunderbolt/USB4
> support. As in the previous versions, this is limited to USB3 support so
> far since the other modes need further work in different subsystems.
> With the dwc3 glue driver being upstream this is however the last part
> required for upstream USB3 support.
> 
> [...]

Applied, thanks!

[1/3] soc: apple: Add hardware tunable support
      commit: a722de305eacb382a5d306f9f8e502f81bab682d
[2/3] dt-bindings: phy: Add Apple Type-C PHY
      commit: c1538b87caef6b2783502c820457be092a7266be
[3/3] phy: apple: Add Apple Type-C PHY
      commit: 8e98ca1e74db2ae051c9b545d42b879efa5a2f6c

Best regards,
-- 
~Vinod




From vkoul at kernel.org  Tue Dec 23 09:45:16 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 23 Dec 2025 23:15:16 +0530
Subject: [PATCH v10 0/6] initial usbdrd phy support for Exynosautov920
 soc
In-Reply-To: <20251124110453.2887437-1-pritam.sutar@samsung.com>
References: <CGME20251124105651epcas5p20d9987d882d5d3850b599b4b46cf70d5@epcas5p2.samsung.com>
 <20251124110453.2887437-1-pritam.sutar@samsung.com>
Message-ID: <176651191635.759340.5010016532880564804.b4-ty@kernel.org>


On Mon, 24 Nov 2025 16:34:47 +0530, Pritam Manohar Sutar wrote:
> This SoC has a single USB 3.1 DRD combo phy and three USB2.0 only
> DRD phy controllers as mentined below
> 
>   * Combo phy supports USB3.1 SSP+(10Gbps) protocol and is backwards
>     compatible to the USB3.0 SS(5Gbps). 'Add-on USB2.0' phy is added
>     to support USB2.0 HS(480Mbps), FS(12Mbps) and LS(1.5Mbps) data rates.
>     These two phys are combined to form a combo phy as mentioned below.
> 
> [...]

Applied, thanks!

[1/6] dt-bindings: phy: samsung,usb3-drd-phy: add ExynosAutov920 HS phy compatible
      commit: 28810c0dfe8aa82e6514858bdcd7a83f0848e90a
[2/6] phy: exynos5-usbdrd: support HS phy for ExynosAutov920
      commit: 031314bd37cb6ce352b1300ffd4e07a7bebce1ef
[3/6] dt-bindings: phy: samsung,usb3-drd-phy: add ExynosAutov920 combo hsphy
      commit: fc58d4628396e4ae2791ff2396793d04940348e1
[4/6] phy: exynos5-usbdrd: support HS combo phy for ExynosAutov920
      commit: 22a401c9a2e1e27a136088e4291bec49869cecf5
[5/6] dt-bindings: phy: samsung,usb3-drd-phy: add ExynosAutov920 combo ssphy
      commit: 05681c9c7e59c164d7e1fc34696f3130d088bc64
[6/6] phy: exynos5-usbdrd: support SS combo phy for ExynosAutov920
      commit: 2fdfc1bb752e393561cf532f5d54607d70e464bc

Best regards,
-- 
~Vinod




From vkoul at kernel.org  Tue Dec 23 09:45:29 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Tue, 23 Dec 2025 23:15:29 +0530
Subject: [PATCH 1/1] phy: rockchip: naneng-combphy: use existing DT
 property check for rk3528
In-Reply-To: <20250910122000.951100-1-amadeus@jmu.edu.cn>
References: <20250910122000.951100-1-amadeus@jmu.edu.cn>
Message-ID: <176651192952.759340.11206011301842508188.b4-ty@kernel.org>


On Wed, 10 Sep 2025 20:20:00 +0800, Chukun Pan wrote:
> The naneng-combphy driver already has DT property checks for
> "rockchip,enable-ssc" and "rockchip,ext-refclk", use it for
> the rk3528_combphy_cfg. Also aligned the indentation of the
> rk3528_combphy_grfcfgs parameters (using tabs).
> 
> 

Applied, thanks!

[1/1] phy: rockchip: naneng-combphy: use existing DT property check for rk3528
      commit: 23c3373af05a3ec268acb02ffe962ac6882c673a

Best regards,
-- 
~Vinod




From royluo at google.com  Tue Dec 23 09:53:34 2025
From: royluo at google.com (Roy Luo)
Date: Tue, 23 Dec 2025 09:53:34 -0800
Subject: [PATCH v9 2/2] phy: Add Google Tensor SoC USB PHY driver
In-Reply-To: <aUqhbVFHczpL9qnL@vaman>
References: <20251222-phyb4-v9-0-82c0b671b070@google.com> <20251222-phyb4-v9-2-82c0b671b070@google.com>
 <aUqhbVFHczpL9qnL@vaman>
Message-ID: <CA+zupgxP+_2iRYABhPM1OOJtRdkrcOvrsKH=Sxk45XwsiamzTw@mail.gmail.com>

On Tue, Dec 23, 2025 at 6:04?AM Vinod Koul <vkoul at kernel.org> wrote:
>
> On 22-12-25, 21:31, Roy Luo wrote:
> > Support the USB PHY found on Google Tensor G5 (Laguna). This
> > particular USB PHY supports both high-speed and super-speed
> > operations, and is integrated with the SNPS DWC3 controller that's
> > also on the SoC. This initial patch specifically adds functionality
> > for high-speed.
> >
> > Co-developed-by: Joy Chakraborty <joychakr at google.com>
> > Signed-off-by: Joy Chakraborty <joychakr at google.com>
> > Co-developed-by: Naveen Kumar <mnkumar at google.com>
> > Signed-off-by: Naveen Kumar <mnkumar at google.com>
> > Signed-off-by: Roy Luo <royluo at google.com>
> > ---
> >  MAINTAINERS                  |   1 +
> >  drivers/phy/Kconfig          |  10 ++
> >  drivers/phy/Makefile         |   1 +
> >  drivers/phy/phy-google-usb.c | 295 +++++++++++++++++++++++++++++++++++++++++++
> >  4 files changed, 307 insertions(+)
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 8a2e94be2f5c5e6e7315bb7bec385798dbd52493..afd0d7484ffe5fa652798c9b3c86ae6d83302382 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -10725,6 +10725,7 @@ F:    Documentation/devicetree/bindings/phy/google,lga-usb-phy.yaml
> >  F:   Documentation/devicetree/bindings/soc/google/google,gs101-pmu-intr-gen.yaml
> >  F:   arch/arm64/boot/dts/exynos/google/
> >  F:   drivers/clk/samsung/clk-gs101.c
> > +F:   drivers/phy/phy-google-usb.c
> >  F:   drivers/soc/samsung/gs101-pmu.c
> >  F:   drivers/phy/samsung/phy-gs101-ufs.c
> >  F:   include/dt-bindings/clock/google,gs101*
> > diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> > index 678dd0452f0aa0597773433f04d2a9ba77474d2a..5a642e04caeeea9d40ac583767622cff2ef5e80c 100644
> > --- a/drivers/phy/Kconfig
> > +++ b/drivers/phy/Kconfig
> > @@ -101,6 +101,16 @@ config PHY_NXP_PTN3222
> >         schemes. It supports all three USB 2.0 data rates: Low Speed, Full
> >         Speed and High Speed.
> >
> > +config PHY_GOOGLE_USB
>
> This does not seem sorted!
>
> > +     tristate "Google Tensor SoC USB PHY driver"
> > +     select GENERIC_PHY
> > +     help
> > +       Enable support for the USB PHY on Google Tensor SoCs, starting with
> > +       the G5 generation (Laguna). This driver provides the PHY interfaces
> > +       to interact with the SNPS eUSB2 and USB 3.2/DisplayPort Combo PHY,
> > +       both of which are integrated with the DWC3 USB DRD controller.
> > +       This driver currently supports USB high-speed.
> > +
> >  source "drivers/phy/allwinner/Kconfig"
> >  source "drivers/phy/amlogic/Kconfig"
> >  source "drivers/phy/broadcom/Kconfig"
> > diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> > index bfb27fb5a494283d7fd05dd670ebd1b12df8b1a1..aeaaaf988554a24bb572d8b34b54638a6a3aed73 100644
> > --- a/drivers/phy/Makefile
> > +++ b/drivers/phy/Makefile
> > @@ -13,6 +13,7 @@ obj-$(CONFIG_PHY_SNPS_EUSB2)                += phy-snps-eusb2.o
> >  obj-$(CONFIG_USB_LGM_PHY)            += phy-lgm-usb.o
> >  obj-$(CONFIG_PHY_AIROHA_PCIE)                += phy-airoha-pcie.o
> >  obj-$(CONFIG_PHY_NXP_PTN3222)                += phy-nxp-ptn3222.o
> > +obj-$(CONFIG_PHY_GOOGLE_USB)         += phy-google-usb.o
>
> and here!
>
> >  obj-y                                        += allwinner/   \
> >                                          amlogic/     \
> >                                          broadcom/    \
> > diff --git a/drivers/phy/phy-google-usb.c b/drivers/phy/phy-google-usb.c
> > new file mode 100644
> > index 0000000000000000000000000000000000000000..97e345fdab9b3679e7a76f6957ae3814ef3420e8
> > --- /dev/null
> > +++ b/drivers/phy/phy-google-usb.c
> > @@ -0,0 +1,295 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * phy-google-usb.c - Google USB PHY driver
> > + *
> > + * Copyright (C) 2025, Google LLC
> > + */
> > +
> > +#include <linux/bitfield.h>
> > +#include <linux/cleanup.h>
> > +#include <linux/clk.h>
> > +#include <linux/io.h>
> > +#include <linux/kernel.h>
> > +#include <linux/mfd/syscon.h>
> > +#include <linux/module.h>
> > +#include <linux/mutex.h>
> > +#include <linux/of.h>
> > +#include <linux/phy/phy.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/regmap.h>
> > +#include <linux/reset.h>
> > +#include <linux/usb/typec_mux.h>
> > +
> > +#define USBCS_USB2PHY_CFG19_OFFSET 0x0
> > +#define USBCS_USB2PHY_CFG19_PHY_CFG_PLL_FB_DIV GENMASK(19, 8)
> > +
> > +#define USBCS_USB2PHY_CFG21_OFFSET 0x8
> > +#define USBCS_USB2PHY_CFG21_PHY_ENABLE BIT(12)
> > +#define USBCS_USB2PHY_CFG21_REF_FREQ_SEL GENMASK(15, 13)
> > +#define USBCS_USB2PHY_CFG21_PHY_TX_DIG_BYPASS_SEL BIT(19)
> > +
> > +#define USBCS_PHY_CFG1_OFFSET 0x28
> > +#define USBCS_PHY_CFG1_SYS_VBUSVALID BIT(17)
> > +
> > +enum google_usb_phy_id {
> > +     GOOGLE_USB2_PHY,
> > +     GOOGLE_USB_PHY_NUM,
> > +};
> > +
> > +struct google_usb_phy_instance {
> > +     int index;
>
> maybe use unsigned?
>
> > +     struct phy *phy;
> > +     int num_clks;
>
> here too?
>
> > +     struct clk_bulk_data *clks;
>  +      int num_rsts;
>
> and here?

Ack to all the comments above, will fix them in the next version.

>
> > +     struct reset_control_bulk_data *rsts;
> > +};
> > +
> > +struct google_usb_phy {
> > +     struct device *dev;
> > +     struct regmap *usb_cfg_regmap;
> > +     unsigned int usb2_cfg_offset;
> > +     void __iomem *usbdp_top_base;
> > +     struct google_usb_phy_instance insts[GOOGLE_USB_PHY_NUM];
>
> so you have an array for one phy?

While the current patch only supports usb2, I used an array
to simplify future support for usb3 and DP. I understand this
might seem like over-engineering for now, and we could
certainly wait to implement the array until the second phy
support is added. I?m happy to move away from array if
you?d prefer a simpler approach for this iteration.

>
> > +     /*
> > +      * Protect phy registers from concurrent access, specifically via
> > +      * google_usb_set_orientation callback.
> > +      */
> > +     struct mutex phy_mutex;
> > +     struct typec_switch_dev *sw;
> > +     enum typec_orientation orientation;
> > +};
> > +
> > +static inline struct google_usb_phy *to_google_usb_phy(struct google_usb_phy_instance *inst)
> > +{
> > +     return container_of(inst, struct google_usb_phy, insts[inst->index]);
> > +}
> > +
> > +static void set_vbus_valid(struct google_usb_phy *gphy)
> > +{
> > +     u32 reg;
> > +
> > +     if (gphy->orientation == TYPEC_ORIENTATION_NONE) {
> > +             reg = readl(gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
> > +             reg &= ~USBCS_PHY_CFG1_SYS_VBUSVALID;
> > +             writel(reg, gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
> > +     } else {
> > +             reg = readl(gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
> > +             reg |= USBCS_PHY_CFG1_SYS_VBUSVALID;
> > +             writel(reg, gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
> > +     }
> > +}
> > +
> > +static int google_usb_set_orientation(struct typec_switch_dev *sw,
> > +                                   enum typec_orientation orientation)
> > +{
> > +     struct google_usb_phy *gphy = typec_switch_get_drvdata(sw);
> > +
> > +     dev_dbg(gphy->dev, "set orientation %d\n", orientation);
> > +
> > +     gphy->orientation = orientation;
> > +
> > +     if (pm_runtime_suspended(gphy->dev))
> > +             return 0;
> > +
> > +     guard(mutex)(&gphy->phy_mutex);
> > +
> > +     set_vbus_valid(gphy);
> > +
> > +     return 0;
> > +}
> > +
> > +static int google_usb2_phy_init(struct phy *_phy)
> > +{
> > +     struct google_usb_phy_instance *inst = phy_get_drvdata(_phy);
> > +     struct google_usb_phy *gphy = to_google_usb_phy(inst);
> > +     u32 reg;
> > +     int ret = 0;
>
> superfluous init

Ack, will fix it in the next version.

>
> > +
> > +     dev_dbg(gphy->dev, "initializing usb2 phy\n");
> > +
> > +     guard(mutex)(&gphy->phy_mutex);
> > +
> > +     regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, &reg);
> > +     reg &= ~USBCS_USB2PHY_CFG21_PHY_TX_DIG_BYPASS_SEL;
> > +     reg &= ~USBCS_USB2PHY_CFG21_REF_FREQ_SEL;
> > +     reg |= FIELD_PREP(USBCS_USB2PHY_CFG21_REF_FREQ_SEL, 0);
> > +     regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, reg);
> > +
> > +     regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG19_OFFSET, &reg);
> > +     reg &= ~USBCS_USB2PHY_CFG19_PHY_CFG_PLL_FB_DIV;
> > +     reg |= FIELD_PREP(USBCS_USB2PHY_CFG19_PHY_CFG_PLL_FB_DIV, 368);
> > +     regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG19_OFFSET, reg);
> > +
> > +     set_vbus_valid(gphy);
> > +
> > +     ret = clk_bulk_prepare_enable(inst->num_clks, inst->clks);
> > +     if (ret)
> > +             return ret;
> > +
> > +     ret = reset_control_bulk_deassert(inst->num_rsts, inst->rsts);
> > +     if (ret) {
> > +             clk_bulk_disable_unprepare(inst->num_clks, inst->clks);
> > +             return ret;
> > +     }
> > +
> > +     regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, &reg);
> > +     reg |= USBCS_USB2PHY_CFG21_PHY_ENABLE;
> > +     regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, reg);
> > +
> > +     return ret;
>
> would it not be return 0 here? can it be any other value

No it cannot be any other value, will change it to "return 0".

>
> > +}
> > +
> > +static int google_usb2_phy_exit(struct phy *_phy)
> > +{
> > +     struct google_usb_phy_instance *inst = phy_get_drvdata(_phy);
> > +     struct google_usb_phy *gphy = to_google_usb_phy(inst);
> > +     u32 reg;
> > +
> > +     dev_dbg(gphy->dev, "exiting usb2 phy\n");
> > +
> > +     guard(mutex)(&gphy->phy_mutex);
> > +
> > +     regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, &reg);
> > +     reg &= ~USBCS_USB2PHY_CFG21_PHY_ENABLE;
> > +     regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, reg);
> > +
> > +     reset_control_bulk_assert(inst->num_rsts, inst->rsts);
> > +     clk_bulk_disable_unprepare(inst->num_clks, inst->clks);
> > +
> > +     return 0;
> > +}
> > +
> > +static const struct phy_ops google_usb2_phy_ops = {
> > +     .init           = google_usb2_phy_init,
> > +     .exit           = google_usb2_phy_exit,
> > +};
>
> Only two ops? I would expect more... No power_on/off or set_mode?
>
> --
> ~Vinod

No, configuring usb2 phy is pretty straightforward. The hardware
does not distinguish between "initialized" and "powered on" states,
it also does not distinguish phy mode.

Thanks,
Roy


From linux at fw-web.de  Tue Dec 23 09:56:25 2025
From: linux at fw-web.de (Frank Wunderlich)
Date: Tue, 23 Dec 2025 18:56:25 +0100
Subject: [PATCH v2 0/2] Add MT7987 Thermal support
Message-ID: <20251223175710.25850-1-linux@fw-web.de>

From: Frank Wunderlich <frank-w at public-files.de>

This series adds Thermal support for MT7987.

v2:
- dropped non-irq patches
- dropped patch for golden_temp
- moved mt7987 COEFF above mt7988

Frank Wunderlich (2):
  dt-bindings: thermal: mediatek: Add LVTS thermal controller definition
    for MT7987
  thermal/drivers/mediatek/lvts_thermal: Add mt7987 support

 .../thermal/mediatek,lvts-thermal.yaml        |  1 +
 drivers/thermal/mediatek/lvts_thermal.c       | 36 +++++++++++++++++++
 .../thermal/mediatek,lvts-thermal.h           |  3 ++
 3 files changed, 40 insertions(+)

-- 
2.43.0



From linux at fw-web.de  Tue Dec 23 09:56:26 2025
From: linux at fw-web.de (Frank Wunderlich)
Date: Tue, 23 Dec 2025 18:56:26 +0100
Subject: [PATCH v2 1/2] dt-bindings: thermal: mediatek: Add LVTS thermal controller definition for MT7987
In-Reply-To: <20251223175710.25850-1-linux@fw-web.de>
References: <20251223175710.25850-1-linux@fw-web.de>
Message-ID: <20251223175710.25850-2-linux@fw-web.de>

From: Frank Wunderlich <frank-w at public-files.de>

Add thermal controller definition for MT7987.

Signed-off-by: Frank Wunderlich <frank-w at public-files.de>
Acked-by: Rob Herring (Arm) <robh at kernel.org>
---
 .../devicetree/bindings/thermal/mediatek,lvts-thermal.yaml     | 1 +
 include/dt-bindings/thermal/mediatek,lvts-thermal.h            | 3 +++
 2 files changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml b/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml
index 0259cd3ce9c5..a9befb523fd4 100644
--- a/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml
+++ b/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml
@@ -18,6 +18,7 @@ description: |
 properties:
   compatible:
     enum:
+      - mediatek,mt7987-lvts-ap
       - mediatek,mt7988-lvts-ap
       - mediatek,mt8186-lvts
       - mediatek,mt8188-lvts-ap
diff --git a/include/dt-bindings/thermal/mediatek,lvts-thermal.h b/include/dt-bindings/thermal/mediatek,lvts-thermal.h
index ddc7302a510a..e9780edcd26c 100644
--- a/include/dt-bindings/thermal/mediatek,lvts-thermal.h
+++ b/include/dt-bindings/thermal/mediatek,lvts-thermal.h
@@ -7,6 +7,9 @@
 #ifndef __MEDIATEK_LVTS_DT_H
 #define __MEDIATEK_LVTS_DT_H
 
+#define MT7987_CPU		0
+#define MT7987_ETH2P5G		1
+
 #define MT7988_CPU_0		0
 #define MT7988_CPU_1		1
 #define MT7988_ETH2P5G_0	2
-- 
2.43.0



From linux at fw-web.de  Tue Dec 23 09:56:27 2025
From: linux at fw-web.de (Frank Wunderlich)
Date: Tue, 23 Dec 2025 18:56:27 +0100
Subject: [PATCH v2 2/2] thermal/drivers/mediatek/lvts_thermal: Add mt7987 support
In-Reply-To: <20251223175710.25850-1-linux@fw-web.de>
References: <20251223175710.25850-1-linux@fw-web.de>
Message-ID: <20251223175710.25850-3-linux@fw-web.de>

From: Frank Wunderlich <frank-w at public-files.de>

Add support for MT7987.

Signed-off-by: Frank Wunderlich <frank-w at public-files.de>
---
v2:
- drop irq-enable member
- move mt7987 above mt7988
---
 drivers/thermal/mediatek/lvts_thermal.c | 36 +++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c
index ab55b20cda47..c345a6191715 100644
--- a/drivers/thermal/mediatek/lvts_thermal.c
+++ b/drivers/thermal/mediatek/lvts_thermal.c
@@ -85,6 +85,8 @@
 #define LVTS_GOLDEN_TEMP_DEFAULT	50
 #define LVTS_COEFF_A_MT8195			-250460
 #define LVTS_COEFF_B_MT8195			250460
+#define LVTS_COEFF_A_MT7987			-204650
+#define LVTS_COEFF_B_MT7987			204650
 #define LVTS_COEFF_A_MT7988			-204650
 #define LVTS_COEFF_B_MT7988			204650
 
@@ -1373,6 +1375,20 @@ static void lvts_remove(struct platform_device *pdev)
 		lvts_ctrl_set_enable(&lvts_td->lvts_ctrl[i], false);
 }
 
+static const struct lvts_ctrl_data mt7987_lvts_ap_data_ctrl[] = {
+	{
+		.lvts_sensor = {
+			{ .dt_id = MT7987_CPU,
+			  .cal_offsets = { 0x04, 0x05, 0x06 } },
+			{ .dt_id = MT7987_ETH2P5G,
+			  .cal_offsets = { 0x08, 0x09, 0x0a } },
+		},
+		VALID_SENSOR_MAP(1, 1, 0, 0),
+		.offset = 0x0,
+		.mode = LVTS_MSR_FILTERED_MODE,
+	},
+};
+
 static const struct lvts_ctrl_data mt7988_lvts_ap_data_ctrl[] = {
 	{
 		.lvts_sensor = {
@@ -1455,6 +1471,12 @@ static const u32 default_init_cmds[] = {
 	0xC10300FC, 0xC103009D, 0xC10300F1, 0xC10300E1
 };
 
+static const u32 mt7987_init_cmds[] = {
+	0xC1030300, 0xC1030420, 0xC1030500, 0xC10307A6, 0xC10308C7,
+	0xC103098D, 0xC1030C7C, 0xC1030AA8, 0xC10308CE, 0xC10308C7,
+	0xC1030B04, 0xC1030E01, 0xC10306B8
+};
+
 static const u32 mt7988_init_cmds[] = {
 	0xC1030300, 0xC1030420, 0xC1030500, 0xC10307A6, 0xC1030CFC,
 	0xC1030A8C, 0xC103098D, 0xC10308F1, 0xC1030B04, 0xC1030E01,
@@ -1753,6 +1775,19 @@ static const struct lvts_ctrl_data mt8195_lvts_ap_data_ctrl[] = {
 	}
 };
 
+static const struct lvts_data mt7987_lvts_ap_data = {
+	.lvts_ctrl	= mt7987_lvts_ap_data_ctrl,
+	.num_lvts_ctrl	= ARRAY_SIZE(mt7987_lvts_ap_data_ctrl),
+	.conn_cmd	= mt7988_conn_cmds,
+	.init_cmd	= mt7987_init_cmds,
+	.num_conn_cmd	= ARRAY_SIZE(mt7988_conn_cmds),
+	.num_init_cmd	= ARRAY_SIZE(mt7987_init_cmds),
+	.temp_factor	= LVTS_COEFF_A_MT7987,
+	.temp_offset	= LVTS_COEFF_B_MT7987,
+	.gt_calib_bit_offset = 32,
+	.def_calibration = 19380,
+};
+
 static const struct lvts_data mt7988_lvts_ap_data = {
 	.lvts_ctrl	= mt7988_lvts_ap_data_ctrl,
 	.conn_cmd	= mt7988_conn_cmds,
@@ -1857,6 +1892,7 @@ static const struct lvts_data mt8195_lvts_ap_data = {
 };
 
 static const struct of_device_id lvts_of_match[] = {
+	{ .compatible = "mediatek,mt7987-lvts-ap", .data = &mt7987_lvts_ap_data },
 	{ .compatible = "mediatek,mt7988-lvts-ap", .data = &mt7988_lvts_ap_data },
 	{ .compatible = "mediatek,mt8186-lvts", .data = &mt8186_lvts_data },
 	{ .compatible = "mediatek,mt8188-lvts-mcu", .data = &mt8188_lvts_mcu_data },
-- 
2.43.0



From ariel.dalessandro at collabora.com  Tue Dec 23 10:01:20 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Tue, 23 Dec 2025 15:01:20 -0300
Subject: [PATCH v3 00/21] Introduce support for CRTC (post-blend) color
 pipeline
Message-ID: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>

This series is based on "Color Pipeline API w/ VKMS" [1]. It reuses the
same concept of a color pipeline API but for the post-blend stage
instead of pre-blend, by attaching the COLOR_PIPELINE property to the
CRTC rather than a plane.

The patches in the series first implement the necessary changes in the
DRM core to allow for CRTC (post-blend) color pipelines and expose it 
through the uAPI, and then implement support in both the MediaTek KMS
driver and in VKMS.

This series has been tested with IGT, with the latest revision of patch
series "Support post-blend color pipeline API" [2] applied, on top of
VKMS, as well as with Weston, with a WIP branch [3], on a MT8195-Tomato
Chromebook and a MT8188 Genio 700 EVK, where both gamma LUT and CTM
color transformations have been simultaneously configured in hardware
through the API and validated (test commits for weston at [4]).

[1] https://lore.kernel.org/all/20251115000237.3561250-1-alex.hung at amd.com/
[2] https://lore.kernel.org/igt-dev/20250912-post-blend-colorops-v1-0-83fc62420cba at collabora.com/T/#t
[3] https://gitlab.collabora.com/nfraprado/weston/-/tree/post-blend-colorops?ref_type=heads
[4] https://gitlab.collabora.com/nfraprado/weston/-/tree/post-blend-color-pipeline-lut-ctm-test?ref_type=tags

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
Co-developed-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Signed-off-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
---
Changes in v3:
- Aligned terminology between plane (pre-blend) and crtc (post-blend)
  color pipeline (Harry Wentland). Replaced all naming s/post-blend/crtc
- Reworked cleanup in vkms_initialize_post_blend_color_pipeline (Louis
  Chauvet).
- Added check on CLIENT_CAP while setting COLOR_PIPELINE property (Louis
  Chauvet).
- Moved common color_pipeline property initialization code to
  drivers/gpu/drm/drm_property.c
- Added missing support for CRTC (post-blend) color pipeline
  configuration in VKMS.
- Added missing return value checks in mtk_crtc_create()
- Added drm_color_lut_to_lut32() and made use of it in mtk_disp_gamma.c
- Added drm_color_ctm_to_ctm_3x4() and made use of it in mtk_disp_ccorr.c
- Split plane and crtc fields descriptions in struct drm_colorop
- Link to v2: https://lore.kernel.org/r/20250917-mtk-post-blend-color-pipeline-v2-0-ac4471b44758 at collabora.com

Changes in v2:
- Split core DRM changes for post-blend color pipelines from single
  commit into smaller changes
- Added post-blend color pipeline support in VKMS
- Introduced driver cap, and made client cap depend on it (daniels)
- Made deprecated color props (GAMMA_LUT, DEGAMMA_LUT, CTM) available as
  read-only when post-blend color pipelines are enabled (daniels)
- Created colorop_modeset_lock/unlock to commonize locking pattern for
  colorops (louis.chauvet)
- Added helper for post-blend 1D curve colorop creation
- Link to v1: https://lore.kernel.org/r/20250822-mtk-post-blend-color-pipeline-v1-0-a9446d4aca82 at collabora.com

---
Ariel D'Alessandro (2):
      drm: Add helper to extract a 3x4 matrix from any CTM matrix dimensions
      drm: Add helper to extract a LUT entry from either 16-bit or 32-bit LUT

N?colas F. R. A. Prado (19):
      drm/crtc: Add color pipeline to CRTC state
      drm/colorop: Allow parenting colorop to CRTC
      drm: Factor out common color_pipeline property initialization code
      drm/crtc: Add COLOR_PIPELINE property
      drm: Introduce DRM_CAP_CRTC_COLOR_PIPELINE
      drm: Introduce DRM_CLIENT_CAP_CRTC_COLOR_PIPELINE
      drm/atomic: Pass crtc_color_pipeline client cap to atomic check
      drm/atomic: Print the color pipeline as part of the CRTC state print
      drm/colorop: Factor out common paths from colorops helpers
      drm/colorop: Introduce colorop helpers for crtc
      drm/crtc: Track crtc color pipeline client cap in drm_crtc_state
      drm/mediatek: Support CRTC colorops for gamma and ctm
      drm/mediatek: ccorr: Support CRTC color pipeline API
      drm/mediatek: gamma: Support CRTC color pipeline API
      drm/mediatek: Set CRTC color pipeline driver cap
      drm/vkms: Rename existing color pipeline helpers to contain "plane"
      drm/vkms: Prepare pre_blend_color_transform() for CRTC color pipelines
      drm/vkms: Introduce support for post-blend color pipeline
      drm/vkms: Set CRTC color pipeline driver cap

 drivers/gpu/drm/drm_atomic.c                  |   9 +-
 drivers/gpu/drm/drm_atomic_uapi.c             |  71 +++++++-
 drivers/gpu/drm/drm_colorop.c                 | 242 +++++++++++++++++++++-----
 drivers/gpu/drm/drm_connector.c               |   1 +
 drivers/gpu/drm/drm_crtc.c                    |  31 ++++
 drivers/gpu/drm/drm_crtc_internal.h           |   1 +
 drivers/gpu/drm/drm_ioctl.c                   |  12 ++
 drivers/gpu/drm/drm_mode_object.c             |   9 +
 drivers/gpu/drm/drm_plane.c                   |  35 +---
 drivers/gpu/drm/drm_property.c                |  44 +++++
 drivers/gpu/drm/mediatek/mtk_crtc.c           | 222 ++++++++++++++++++++++-
 drivers/gpu/drm/mediatek/mtk_ddp_comp.c       |   6 +-
 drivers/gpu/drm/mediatek/mtk_ddp_comp.h       |   2 +
 drivers/gpu/drm/mediatek/mtk_disp_ccorr.c     |  88 ++++++++--
 drivers/gpu/drm/mediatek/mtk_disp_drv.h       |   6 +-
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c     |  68 ++++++--
 drivers/gpu/drm/mediatek/mtk_drm_drv.c        |   3 +-
 drivers/gpu/drm/vkms/tests/vkms_config_test.c |  70 +++++---
 drivers/gpu/drm/vkms/vkms_colorop.c           | 110 +++++++++++-
 drivers/gpu/drm/vkms/vkms_composer.c          |  13 +-
 drivers/gpu/drm/vkms/vkms_config.c            |   5 +-
 drivers/gpu/drm/vkms/vkms_config.h            |  29 ++-
 drivers/gpu/drm/vkms/vkms_crtc.c              |   6 +-
 drivers/gpu/drm/vkms/vkms_drv.c               |  10 +-
 drivers/gpu/drm/vkms/vkms_drv.h               |   8 +-
 drivers/gpu/drm/vkms/vkms_output.c            |   3 +-
 drivers/gpu/drm/vkms/vkms_plane.c             |   2 +-
 include/drm/drm_atomic.h                      |  20 +++
 include/drm/drm_atomic_uapi.h                 |   2 +
 include/drm/drm_color_mgmt.h                  |  61 +++++++
 include/drm/drm_colorop.h                     |  25 ++-
 include/drm/drm_crtc.h                        |  27 +++
 include/drm/drm_drv.h                         |   6 +
 include/drm/drm_file.h                        |   7 +
 include/drm/drm_property.h                    |   5 +
 include/uapi/drm/drm.h                        |  25 +++
 36 files changed, 1109 insertions(+), 175 deletions(-)
---
base-commit: b96bcfba104c65db41378a04f5ccac186f79578f
change-id: 20250730-mtk-post-blend-color-pipeline-498e1a9cc53e

Best regards,
-- 
Ariel D'Alessandro <ariel.dalessandro at collabora.com>



From ariel.dalessandro at collabora.com  Tue Dec 23 10:01:21 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Tue, 23 Dec 2025 15:01:21 -0300
Subject: [PATCH v3 01/21] drm/crtc: Add color pipeline to CRTC state
In-Reply-To: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
References: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
Message-ID: <20251223-mtk-post-blend-color-pipeline-v3-1-7d969f9a37a0@collabora.com>

From: "N?colas F. R. A. Prado" <nfraprado at collabora.com>

Add a color pipeline to the CRTC state to allow post-blend color
pipelines.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
Reviewed-by: Harry Wentland <harry.wentland at amd.com>
Reviewed-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
---
 include/drm/drm_crtc.h | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 66278ffeebd68..8490f4bc31260 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -274,6 +274,14 @@ struct drm_crtc_state {
 	 */
 	struct drm_property_blob *gamma_lut;
 
+	/**
+	 * @color_pipeline:
+	 *
+	 * The first colorop of the active color pipeline, or NULL, if no
+	 * color pipeline is active.
+	 */
+	struct drm_colorop *color_pipeline;
+
 	/**
 	 * @target_vblank:
 	 *

-- 
2.51.0



From ariel.dalessandro at collabora.com  Tue Dec 23 10:01:22 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Tue, 23 Dec 2025 15:01:22 -0300
Subject: [PATCH v3 02/21] drm/colorop: Allow parenting colorop to CRTC
In-Reply-To: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
References: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
Message-ID: <20251223-mtk-post-blend-color-pipeline-v3-2-7d969f9a37a0@collabora.com>

From: "N?colas F. R. A. Prado" <nfraprado at collabora.com>

In order to allow for post-blend color pipelines, colorops need to be
assigned to a crtc rather than a plane. Add a crtc to the colorop
struct to enable this. Either the plane or the crtc will be set for any
given colorop depending on whether it is part of a pre- or post-blend
color pipeline.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
Co-developed-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Signed-off-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
Reviewed-by: Harry Wentland <harry.wentland at amd.com>
---
 drivers/gpu/drm/drm_atomic.c  |  6 +++---
 drivers/gpu/drm/drm_colorop.c | 25 +++++++++++++++++++++++++
 include/drm/drm_colorop.h     | 17 +++++++++++++++--
 3 files changed, 43 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 6d3ea8056b603..e9022d7ad04b0 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -620,7 +620,7 @@ drm_atomic_get_colorop_state(struct drm_atomic_state *state,
 	if (colorop_state)
 		return colorop_state;
 
-	ret = drm_modeset_lock(&colorop->plane->mutex, state->acquire_ctx);
+	ret = drm_colorop_modeset_lock(colorop, state->acquire_ctx);
 	if (ret)
 		return ERR_PTR(ret);
 
@@ -2012,10 +2012,10 @@ static void __drm_state_dump(struct drm_device *dev, struct drm_printer *p,
 
 	list_for_each_entry(colorop, &config->colorop_list, head) {
 		if (take_locks)
-			drm_modeset_lock(&colorop->plane->mutex, NULL);
+			drm_colorop_modeset_lock(colorop, NULL);
 		drm_atomic_colorop_print_state(p, colorop->state);
 		if (take_locks)
-			drm_modeset_unlock(&colorop->plane->mutex);
+			drm_colorop_modeset_unlock(colorop);
 	}
 
 	list_for_each_entry(plane, &config->plane_list, head) {
diff --git a/drivers/gpu/drm/drm_colorop.c b/drivers/gpu/drm/drm_colorop.c
index 44eb823585d2e..bf3b8ff51571b 100644
--- a/drivers/gpu/drm/drm_colorop.c
+++ b/drivers/gpu/drm/drm_colorop.c
@@ -24,6 +24,7 @@
  *
  */
 
+#include <drm/drm_crtc.h>
 #include <drm/drm_colorop.h>
 #include <drm/drm_print.h>
 #include <drm/drm_drv.h>
@@ -597,3 +598,27 @@ void drm_colorop_set_next_property(struct drm_colorop *colorop, struct drm_color
 	colorop->next = next;
 }
 EXPORT_SYMBOL(drm_colorop_set_next_property);
+
+int drm_colorop_modeset_lock(struct drm_colorop *colorop, struct drm_modeset_acquire_ctx *ctx)
+{
+	if (colorop->plane)
+		return drm_modeset_lock(&colorop->plane->mutex, ctx);
+
+	if (colorop->crtc)
+		return drm_modeset_lock(&colorop->crtc->mutex, ctx);
+
+	drm_err(colorop->dev, "Dangling colorop, it must be attached to a plane or a CRTC\n");
+	return -EINVAL;
+}
+EXPORT_SYMBOL(drm_colorop_modeset_lock);
+
+void drm_colorop_modeset_unlock(struct drm_colorop *colorop)
+{
+	if (colorop->plane)
+		drm_modeset_unlock(&colorop->plane->mutex);
+	else if (colorop->crtc)
+		drm_modeset_unlock(&colorop->crtc->mutex);
+	else
+		drm_err(colorop->dev, "Dangling colorop, it must be attached to a plane or a CRTC\n");
+}
+EXPORT_SYMBOL(drm_colorop_modeset_unlock);
diff --git a/include/drm/drm_colorop.h b/include/drm/drm_colorop.h
index a3a32f9f918c7..49d342b7f8b0b 100644
--- a/include/drm/drm_colorop.h
+++ b/include/drm/drm_colorop.h
@@ -29,6 +29,7 @@
 
 #include <drm/drm_mode_object.h>
 #include <drm/drm_mode.h>
+#include <drm/drm_modeset_lock.h>
 #include <drm/drm_property.h>
 
 /* DRM colorop flags */
@@ -223,11 +224,21 @@ struct drm_colorop {
 	/**
 	 * @plane:
 	 *
-	 * The plane on which the colorop sits. A drm_colorop is always unique
-	 * to a plane.
+	 * The plane on which the colorop sits if it is a pre-blend colorop.
+	 * In this case it is unique to the plane.
+	 * NOTE: plane and crtc are mutually exclusive.
 	 */
 	struct drm_plane *plane;
 
+	/**
+	 * @crtc:
+	 *
+	 * The CRTC on which the colorop sits if it is a post-blend colorop.
+	 * In this case it is unique to the CRTC.
+	 * NOTE: plane and crtc are mutually exclusive.
+	 */
+	struct drm_crtc *crtc;
+
 	/**
 	 * @state:
 	 *
@@ -460,5 +471,7 @@ const char *
 drm_get_colorop_lut3d_interpolation_name(enum drm_colorop_lut3d_interpolation_type type);
 
 void drm_colorop_set_next_property(struct drm_colorop *colorop, struct drm_colorop *next);
+int drm_colorop_modeset_lock(struct drm_colorop *colorop, struct drm_modeset_acquire_ctx *ctx);
+void drm_colorop_modeset_unlock(struct drm_colorop *colorop);
 
 #endif /* __DRM_COLOROP_H__ */

-- 
2.51.0



From ariel.dalessandro at collabora.com  Tue Dec 23 10:01:23 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Tue, 23 Dec 2025 15:01:23 -0300
Subject: [PATCH v3 03/21] drm: Factor out common color_pipeline property
 initialization code
In-Reply-To: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
References: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
Message-ID: <20251223-mtk-post-blend-color-pipeline-v3-3-7d969f9a37a0@collabora.com>

From: "N?colas F. R. A. Prado" <nfraprado at collabora.com>

In preparation for sharing the initialization code for the color
pipeline property between pre-blend (plane) and post-blend (crtc) color
pipelines, factor out the common initialization to a separate function.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
Co-developed-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Signed-off-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
---
 drivers/gpu/drm/drm_plane.c    | 35 ++++-----------------------------
 drivers/gpu/drm/drm_property.c | 44 ++++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_property.h     |  5 +++++
 3 files changed, 53 insertions(+), 31 deletions(-)

diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c
index bed2562bf911b..3d7324757d7b2 100644
--- a/drivers/gpu/drm/drm_plane.c
+++ b/drivers/gpu/drm/drm_plane.c
@@ -1839,43 +1839,16 @@ int drm_plane_create_color_pipeline_property(struct drm_plane *plane,
 					     const struct drm_prop_enum_list *pipelines,
 					     int num_pipelines)
 {
-	struct drm_prop_enum_list *all_pipelines;
 	struct drm_property *prop;
-	int len = 0;
-	int i;
-
-	all_pipelines = kcalloc(num_pipelines + 1,
-				sizeof(*all_pipelines),
-				GFP_KERNEL);
-
-	if (!all_pipelines) {
-		drm_err(plane->dev, "failed to allocate color pipeline\n");
-		return -ENOMEM;
-	}
-
-	/* Create default Bypass color pipeline */
-	all_pipelines[len].type = 0;
-	all_pipelines[len].name = "Bypass";
-	len++;
 
-	/* Add all other color pipelines */
-	for (i = 0; i < num_pipelines; i++, len++) {
-		all_pipelines[len].type = pipelines[i].type;
-		all_pipelines[len].name = pipelines[i].name;
-	}
+	prop = drm_property_create_color_pipeline(plane->dev, &plane->base,
+						  pipelines, num_pipelines);
+	if (IS_ERR(prop))
+		return PTR_ERR(prop);
 
-	prop = drm_property_create_enum(plane->dev, DRM_MODE_PROP_ATOMIC,
-					"COLOR_PIPELINE",
-					all_pipelines, len);
-	if (!prop) {
-		kfree(all_pipelines);
-		return -ENOMEM;
-	}
 
-	drm_object_attach_property(&plane->base, prop, 0);
 	plane->color_pipeline_property = prop;
 
-	kfree(all_pipelines);
 	return 0;
 }
 EXPORT_SYMBOL(drm_plane_create_color_pipeline_property);
diff --git a/drivers/gpu/drm/drm_property.c b/drivers/gpu/drm/drm_property.c
index 596272149a359..cc2a1422599ac 100644
--- a/drivers/gpu/drm/drm_property.c
+++ b/drivers/gpu/drm/drm_property.c
@@ -997,3 +997,47 @@ void drm_property_change_valid_put(struct drm_property *property,
 	} else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB))
 		drm_property_blob_put(obj_to_blob(ref));
 }
+
+struct drm_property *
+drm_property_create_color_pipeline(struct drm_device *dev, struct drm_mode_object *obj,
+				   const struct drm_prop_enum_list *pipelines,
+				   int num_pipelines)
+{
+	struct drm_prop_enum_list *all_pipelines;
+	struct drm_property *prop;
+	int len = 0;
+	int i;
+
+	all_pipelines = kcalloc(num_pipelines + 1,
+				sizeof(*all_pipelines),
+				GFP_KERNEL);
+
+	if (!all_pipelines) {
+		drm_err(dev, "failed to allocate color pipeline\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	/* Create default Bypass color pipeline */
+	all_pipelines[len].type = 0;
+	all_pipelines[len].name = "Bypass";
+	len++;
+
+	/* Add all other color pipelines */
+	for (i = 0; i < num_pipelines; i++, len++) {
+		all_pipelines[len].type = pipelines[i].type;
+		all_pipelines[len].name = pipelines[i].name;
+	}
+
+	prop = drm_property_create_enum(dev, DRM_MODE_PROP_ATOMIC,
+					"COLOR_PIPELINE",
+					all_pipelines, len);
+	if (!prop) {
+		kfree(all_pipelines);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	drm_object_attach_property(obj, prop, 0);
+
+	kfree(all_pipelines);
+	return prop;
+}
diff --git a/include/drm/drm_property.h b/include/drm/drm_property.h
index 082f29156b3e3..3acf340635226 100644
--- a/include/drm/drm_property.h
+++ b/include/drm/drm_property.h
@@ -296,6 +296,11 @@ bool drm_property_replace_blob(struct drm_property_blob **blob,
 struct drm_property_blob *drm_property_blob_get(struct drm_property_blob *blob);
 void drm_property_blob_put(struct drm_property_blob *blob);
 
+struct drm_property *
+drm_property_create_color_pipeline(struct drm_device *dev, struct drm_mode_object *obj,
+				   const struct drm_prop_enum_list *pipelines,
+				   int num_pipelines);
+
 /**
  * drm_property_find - find property object
  * @dev: DRM device

-- 
2.51.0



From ariel.dalessandro at collabora.com  Tue Dec 23 10:01:24 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Tue, 23 Dec 2025 15:01:24 -0300
Subject: [PATCH v3 04/21] drm/crtc: Add COLOR_PIPELINE property
In-Reply-To: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
References: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
Message-ID: <20251223-mtk-post-blend-color-pipeline-v3-4-7d969f9a37a0@collabora.com>

From: "N?colas F. R. A. Prado" <nfraprado at collabora.com>

Add a COLOR_PIPELINE property to the CRTC to allow userspace to set a
post-blend color pipeline analogously to how pre-blend color pipelines
are set on planes.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
Co-developed-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Signed-off-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
---
 drivers/gpu/drm/drm_atomic_uapi.c | 50 +++++++++++++++++++++++++++++++++++----
 drivers/gpu/drm/drm_crtc.c        | 31 ++++++++++++++++++++++++
 include/drm/drm_atomic_uapi.h     |  2 ++
 include/drm/drm_crtc.h            | 11 +++++++++
 4 files changed, 90 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
index 7320db4b8489f..07d0d224fe58c 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -286,6 +286,34 @@ drm_atomic_set_colorop_for_plane(struct drm_plane_state *plane_state,
 }
 EXPORT_SYMBOL(drm_atomic_set_colorop_for_plane);
 
+/**
+ * drm_atomic_set_colorop_for_crtc - set colorop for crtc
+ * @crtc_state: atomic state object for the crtc
+ * @colorop: colorop to use for the crtc
+ *
+ * Helper function to select the color pipeline on a crtc by setting
+ * it to the first drm_colorop element of the pipeline.
+ */
+void
+drm_atomic_set_colorop_for_crtc(struct drm_crtc_state *crtc_state,
+				 struct drm_colorop *colorop)
+{
+	struct drm_crtc *crtc = crtc_state->crtc;
+
+	if (colorop)
+		drm_dbg_atomic(crtc->dev,
+			       "Set [COLOROP:%d] for [CRTC:%d:%s] state %p\n",
+			       colorop->base.id, crtc->base.id, crtc->name,
+			       crtc_state);
+	else
+		drm_dbg_atomic(crtc->dev,
+			       "Set [NOCOLOROP] for [CRTC:%d:%s] state %p\n",
+			       crtc->base.id, crtc->name, crtc_state);
+
+	crtc_state->color_pipeline = colorop;
+}
+EXPORT_SYMBOL(drm_atomic_set_colorop_for_crtc);
+
 /**
  * drm_atomic_set_crtc_for_connector - set CRTC for connector
  * @conn_state: atomic state object for the connector
@@ -394,8 +422,8 @@ static s32 __user *get_out_fence_for_connector(struct drm_atomic_state *state,
 }
 
 static int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
-		struct drm_crtc_state *state, struct drm_property *property,
-		uint64_t val)
+		struct drm_crtc_state *state, struct drm_file *file_priv,
+		struct drm_property *property, uint64_t val)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_mode_config *config = &dev->mode_config;
@@ -404,7 +432,17 @@ static int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
 
 	if (property == config->prop_active)
 		state->active = val;
-	else if (property == config->prop_mode_id) {
+	else if (property == crtc->color_pipeline_property) {
+		/* find DRM colorop object */
+		struct drm_colorop *colorop = NULL;
+
+		colorop = drm_colorop_find(dev, file_priv, val);
+
+		if (val && !colorop)
+			return -EACCES;
+
+		drm_atomic_set_colorop_for_crtc(state, colorop);
+	} else if (property == config->prop_mode_id) {
 		struct drm_property_blob *mode =
 			drm_property_lookup_blob(dev, val);
 		ret = drm_atomic_set_mode_prop_for_crtc(state, mode);
@@ -489,6 +527,8 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc,
 		*val = state->scaling_filter;
 	else if (property == crtc->sharpness_strength_property)
 		*val = state->sharpness_strength;
+	else if (property == crtc->color_pipeline_property)
+		*val = (state->color_pipeline) ? state->color_pipeline->base.id : 0;
 	else if (crtc->funcs->atomic_get_property)
 		return crtc->funcs->atomic_get_property(crtc, state, property, val);
 	else {
@@ -1050,6 +1090,8 @@ int drm_atomic_get_property(struct drm_mode_object *obj,
 
 		if (colorop->plane)
 			WARN_ON(!drm_modeset_is_locked(&colorop->plane->mutex));
+		else if (colorop->crtc)
+			WARN_ON(!drm_modeset_is_locked(&colorop->crtc->mutex));
 
 		ret = drm_atomic_colorop_get_property(colorop, colorop->state, property, val);
 		break;
@@ -1206,7 +1248,7 @@ int drm_atomic_set_property(struct drm_atomic_state *state,
 		}
 
 		ret = drm_atomic_crtc_set_property(crtc,
-				crtc_state, prop, prop_value);
+				crtc_state, file_priv, prop, prop_value);
 		break;
 	}
 	case DRM_MODE_OBJECT_PLANE: {
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index a7797d260f1e2..133ff9212fbc4 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -994,3 +994,34 @@ bool drm_crtc_in_clone_mode(struct drm_crtc_state *crtc_state)
 	return hweight32(crtc_state->encoder_mask) > 1;
 }
 EXPORT_SYMBOL(drm_crtc_in_clone_mode);
+
+/**
+ * drm_crtc_create_color_pipeline_property - create a new color pipeline
+ * property
+ *
+ * @crtc: drm CRTC
+ * @pipelines: list of pipelines
+ * @num_pipelines: number of pipelines
+ *
+ * Create the COLOR_PIPELINE CRTC property to specify color pipelines on
+ * the CRTC.
+ *
+ * RETURNS:
+ * Zero for success or -errno
+ */
+int drm_crtc_create_color_pipeline_property(struct drm_crtc *crtc,
+					    const struct drm_prop_enum_list *pipelines,
+					    int num_pipelines)
+{
+	struct drm_property *prop;
+
+	prop = drm_property_create_color_pipeline(crtc->dev, &crtc->base,
+						  pipelines, num_pipelines);
+	if (IS_ERR(prop))
+		return PTR_ERR(prop);
+
+	crtc->color_pipeline_property = prop;
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_crtc_create_color_pipeline_property);
diff --git a/include/drm/drm_atomic_uapi.h b/include/drm/drm_atomic_uapi.h
index 4363155233267..4dc191f6f929d 100644
--- a/include/drm/drm_atomic_uapi.h
+++ b/include/drm/drm_atomic_uapi.h
@@ -52,6 +52,8 @@ void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
 				 struct drm_framebuffer *fb);
 void drm_atomic_set_colorop_for_plane(struct drm_plane_state *plane_state,
 				      struct drm_colorop *colorop);
+void drm_atomic_set_colorop_for_crtc(struct drm_crtc_state *crtc_state,
+				     struct drm_colorop *colorop);
 int __must_check
 drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
 				  struct drm_crtc *crtc);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 8490f4bc31260..b3c9818715851 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -1113,6 +1113,14 @@ struct drm_crtc {
 	 */
 	struct drm_property *sharpness_strength_property;
 
+	/**
+	 * @color_pipeline_property:
+	 *
+	 * Optional "COLOR_PIPELINE" enum property for specifying
+	 * a color pipeline to use on the CRTC.
+	 */
+	struct drm_property *color_pipeline_property;
+
 	/**
 	 * @state:
 	 *
@@ -1348,6 +1356,9 @@ static inline struct drm_crtc *drm_crtc_find(struct drm_device *dev,
 
 int drm_crtc_create_scaling_filter_property(struct drm_crtc *crtc,
 					    unsigned int supported_filters);
+int drm_crtc_create_color_pipeline_property(struct drm_crtc *crtc,
+					     const struct drm_prop_enum_list *pipelines,
+					     int num_pipelines);
 bool drm_crtc_in_clone_mode(struct drm_crtc_state *crtc_state);
 int drm_crtc_create_sharpness_strength_property(struct drm_crtc *crtc);
 #endif /* __DRM_CRTC_H__ */

-- 
2.51.0



From ariel.dalessandro at collabora.com  Tue Dec 23 10:01:25 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Tue, 23 Dec 2025 15:01:25 -0300
Subject: [PATCH v3 05/21] drm: Introduce DRM_CAP_CRTC_COLOR_PIPELINE
In-Reply-To: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
References: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
Message-ID: <20251223-mtk-post-blend-color-pipeline-v3-5-7d969f9a37a0@collabora.com>

From: "N?colas F. R. A. Prado" <nfraprado at collabora.com>

Add a new cap that drivers can set to signal they support CRTC (a.k.a.
post-blend) color pipelines.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
Co-developed-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Signed-off-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
---
 drivers/gpu/drm/drm_ioctl.c | 3 +++
 include/drm/drm_drv.h       | 6 ++++++
 include/uapi/drm/drm.h      | 6 ++++++
 3 files changed, 15 insertions(+)

diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index ff193155129e7..2884075660ddd 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -304,6 +304,9 @@ static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_
 		req->value = drm_core_check_feature(dev, DRIVER_ATOMIC) &&
 			     dev->mode_config.async_page_flip;
 		break;
+	case DRM_CAP_CRTC_COLOR_PIPELINE:
+		req->value = drm_core_check_feature(dev, DRIVER_CRTC_COLOR_PIPELINE);
+		break;
 	default:
 		return -EINVAL;
 	}
diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h
index 42fc085f986de..2a57c50b4223e 100644
--- a/include/drm/drm_drv.h
+++ b/include/drm/drm_drv.h
@@ -122,6 +122,12 @@ enum drm_driver_feature {
 	 * the cursor planes to work correctly).
 	 */
 	DRIVER_CURSOR_HOTSPOT           = BIT(9),
+	/**
+	 * @DRIVER_CRTC_COLOR_PIPELINE:
+	 *
+	 * Driver supports CRTC (post-blend) color pipeline.
+	 */
+	DRIVER_CRTC_COLOR_PIPELINE	= BIT(10),
 
 	/* IMPORTANT: Below are all the legacy flags, add new ones above. */
 
diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
index 27cc159c1d275..d726828bdf408 100644
--- a/include/uapi/drm/drm.h
+++ b/include/uapi/drm/drm.h
@@ -812,6 +812,12 @@ struct drm_gem_change_handle {
  * commits.
  */
 #define DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP	0x15
+/**
+ * DRM_CAP_CRTC_COLOR_PIPELINE
+ *
+ * If set to 1, the driver supports CRTC (post-blend) color pipelines.
+ */
+#define DRM_CAP_CRTC_COLOR_PIPELINE	0x16
 
 /* DRM_IOCTL_GET_CAP ioctl argument type */
 struct drm_get_cap {

-- 
2.51.0



From ariel.dalessandro at collabora.com  Tue Dec 23 10:01:26 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Tue, 23 Dec 2025 15:01:26 -0300
Subject: [PATCH v3 06/21] drm: Introduce DRM_CLIENT_CAP_CRTC_COLOR_PIPELINE
In-Reply-To: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
References: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
Message-ID: <20251223-mtk-post-blend-color-pipeline-v3-6-7d969f9a37a0@collabora.com>

From: "N?colas F. R. A. Prado" <nfraprado at collabora.com>

Introduce DRM_CLIENT_CAP_CRTC_COLOR_PIPELINE which a DRM client can set
to enable the usage of CRTC (post-blend) color pipelines instead of the
now deprecated CRTC color management properties: "GAMMA_LUT",
"DEGAMMA_LUT" and "CTM".

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
Co-developed-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Signed-off-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
---
 drivers/gpu/drm/drm_atomic_uapi.c   | 20 ++++++++++++++++++++
 drivers/gpu/drm/drm_connector.c     |  1 +
 drivers/gpu/drm/drm_crtc_internal.h |  1 +
 drivers/gpu/drm/drm_ioctl.c         |  9 +++++++++
 drivers/gpu/drm/drm_mode_object.c   |  9 +++++++++
 include/drm/drm_file.h              |  7 +++++++
 include/uapi/drm/drm.h              | 19 +++++++++++++++++++
 7 files changed, 66 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
index 07d0d224fe58c..d1bc78b2567a9 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -433,6 +433,11 @@ static int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
 	if (property == config->prop_active)
 		state->active = val;
 	else if (property == crtc->color_pipeline_property) {
+		if (!file_priv->crtc_color_pipeline) {
+			drm_dbg_atomic(dev,
+				"Setting COLOR_PIPELINE CRTC property not permitted without DRM_CLIENT_CAP_CRTC_COLOR_PIPELINE client cap\n");
+			return -EINVAL;
+		}
 		/* find DRM colorop object */
 		struct drm_colorop *colorop = NULL;
 
@@ -451,6 +456,11 @@ static int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
 	} else if (property == config->prop_vrr_enabled) {
 		state->vrr_enabled = val;
 	} else if (property == config->degamma_lut_property) {
+		if (file_priv->crtc_color_pipeline) {
+			drm_dbg_atomic(dev,
+				"Setting DEGAMMA_LUT CRTC property not permitted with DRM_CLIENT_CAP_CRTC_COLOR_PIPELINE client cap\n");
+			return -EINVAL;
+		}
 		ret = drm_property_replace_blob_from_id(dev,
 					&state->degamma_lut,
 					val,
@@ -459,6 +469,11 @@ static int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
 		state->color_mgmt_changed |= replaced;
 		return ret;
 	} else if (property == config->ctm_property) {
+		if (file_priv->crtc_color_pipeline) {
+			drm_dbg_atomic(dev,
+				"Setting CTM CRTC property not permitted with DRM_CLIENT_CAP_CRTC_COLOR_PIPELINE client cap\n");
+			return -EINVAL;
+		}
 		ret = drm_property_replace_blob_from_id(dev,
 					&state->ctm,
 					val,
@@ -467,6 +482,11 @@ static int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
 		state->color_mgmt_changed |= replaced;
 		return ret;
 	} else if (property == config->gamma_lut_property) {
+		if (file_priv->crtc_color_pipeline) {
+			drm_dbg_atomic(dev,
+				"Setting GAMMA_LUT CRTC property not permitted with DRM_CLIENT_CAP_CRTC_COLOR_PIPELINE client cap\n");
+			return -EINVAL;
+		}
 		ret = drm_property_replace_blob_from_id(dev,
 					&state->gamma_lut,
 					val,
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 4d6dc9ebfdb5b..aec8a5c0d593a 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -3440,6 +3440,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
 	 */
 	ret = drm_mode_object_get_properties(&connector->base, file_priv->atomic,
 			file_priv->plane_color_pipeline,
+			file_priv->crtc_color_pipeline,
 			(uint32_t __user *)(unsigned long)(out_resp->props_ptr),
 			(uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr),
 			&out_resp->count_props);
diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h
index c094092296448..ab02e6295271d 100644
--- a/drivers/gpu/drm/drm_crtc_internal.h
+++ b/drivers/gpu/drm/drm_crtc_internal.h
@@ -164,6 +164,7 @@ void drm_mode_object_unregister(struct drm_device *dev,
 				struct drm_mode_object *object);
 int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic,
 				   bool plane_color_pipeline,
+				   bool crtc_color_pipeline,
 				   uint32_t __user *prop_ptr,
 				   uint64_t __user *prop_values,
 				   uint32_t *arg_count_props);
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index 2884075660ddd..14746afd82783 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -383,6 +383,15 @@ drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
 			return -EINVAL;
 		file_priv->plane_color_pipeline = req->value;
 		break;
+	case DRM_CLIENT_CAP_CRTC_COLOR_PIPELINE:
+		if (!file_priv->atomic)
+			return -EINVAL;
+		if (req->value > 1)
+			return -EINVAL;
+		if (!drm_core_check_feature(dev, DRIVER_CRTC_COLOR_PIPELINE))
+			return -EINVAL;
+		file_priv->crtc_color_pipeline = req->value;
+		break;
 	default:
 		return -EINVAL;
 	}
diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c
index b45d501b10c86..ea4508f6a09a6 100644
--- a/drivers/gpu/drm/drm_mode_object.c
+++ b/drivers/gpu/drm/drm_mode_object.c
@@ -388,6 +388,7 @@ EXPORT_SYMBOL(drm_object_property_get_default_value);
 /* helper for getconnector and getproperties ioctls */
 int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic,
 				   bool plane_color_pipeline,
+				   bool crtc_color_pipeline,
 				   uint32_t __user *prop_ptr,
 				   uint64_t __user *prop_values,
 				   uint32_t *arg_count_props)
@@ -416,6 +417,13 @@ int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic,
 				continue;
 		}
 
+		if (!crtc_color_pipeline && obj->type == DRM_MODE_OBJECT_CRTC) {
+			struct drm_crtc *crtc = obj_to_crtc(obj);
+
+			if (prop == crtc->color_pipeline_property)
+				continue;
+		}
+
 		if (*arg_count_props > count) {
 			ret = __drm_object_property_get_value(obj, prop, &val);
 			if (ret)
@@ -475,6 +483,7 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
 
 	ret = drm_mode_object_get_properties(obj, file_priv->atomic,
 			file_priv->plane_color_pipeline,
+			file_priv->crtc_color_pipeline,
 			(uint32_t __user *)(unsigned long)(arg->props_ptr),
 			(uint64_t __user *)(unsigned long)(arg->prop_values_ptr),
 			&arg->count_props);
diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h
index 6ee70ad65e1fd..d0c323378ae46 100644
--- a/include/drm/drm_file.h
+++ b/include/drm/drm_file.h
@@ -214,6 +214,13 @@ struct drm_file {
 	 */
 	bool plane_color_pipeline;
 
+	/**
+	 * @crtc_color_pipeline:
+	 *
+	 * True if client understands CRTC (post-blend) color pipelines
+	 */
+	bool crtc_color_pipeline;
+
 	/**
 	 * @was_master:
 	 *
diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
index d726828bdf408..991ef14c5377c 100644
--- a/include/uapi/drm/drm.h
+++ b/include/uapi/drm/drm.h
@@ -927,6 +927,25 @@ struct drm_get_cap {
  */
 #define DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE	7
 
+/**
+ * DRM_CLIENT_CAP_CRTC_COLOR_PIPELINE
+ *
+ * If set to 1 the DRM core will allow setting the COLOR_PIPELINE
+ * property on a &drm_crtc, as well as drm_colorop properties.
+ *
+ * Setting of these crtc properties will be rejected when this client
+ * cap is set:
+ * - GAMMA_LUT
+ * - DEGAMMA_LUT
+ * - CTM
+ *
+ * The client must enable &DRM_CLIENT_CAP_ATOMIC first.
+ *
+ * This client cap can only be set if the driver sets the corresponding driver
+ * cap &DRM_CAP_CRTC_COLOR_PIPELINE.
+ */
+#define DRM_CLIENT_CAP_CRTC_COLOR_PIPELINE	8
+
 /* DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */
 struct drm_set_client_cap {
 	__u64 capability;

-- 
2.51.0



From ariel.dalessandro at collabora.com  Tue Dec 23 10:01:27 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Tue, 23 Dec 2025 15:01:27 -0300
Subject: [PATCH v3 07/21] drm/atomic: Pass crtc_color_pipeline client cap
 to atomic check
In-Reply-To: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
References: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
Message-ID: <20251223-mtk-post-blend-color-pipeline-v3-7-7d969f9a37a0@collabora.com>

From: "N?colas F. R. A. Prado" <nfraprado at collabora.com>

Pass the state of the CRTC (post-blend) color pipeline client cap to the
atomic state so that drivers can rely on it to enable color pipeline
functionality and ignore the deprecated color management CRTC
properties.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
Co-developed-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Signed-off-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
---
 drivers/gpu/drm/drm_atomic_uapi.c |  1 +
 include/drm/drm_atomic.h          | 20 ++++++++++++++++++++
 2 files changed, 21 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
index d1bc78b2567a9..03f5a80448d10 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -1668,6 +1668,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
 	state->acquire_ctx = &ctx;
 	state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET);
 	state->plane_color_pipeline = file_priv->plane_color_pipeline;
+	state->crtc_color_pipeline = file_priv->crtc_color_pipeline;
 
 retry:
 	copied_objs = 0;
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 74ce26fa8838b..7eb21c0426105 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -560,6 +560,26 @@ struct drm_atomic_state {
 	 */
 	bool plane_color_pipeline : 1;
 
+	/**
+	 * @crtc_color_pipeline:
+	 *
+	 * Indicates whether this atomic state originated with a client that
+	 * set the DRM_CLIENT_CAP_CRTC_COLOR_PIPELINE.
+	 *
+	 * Drivers and helper functions should use this to ignore legacy
+	 * properties that are incompatible with the drm_crtc COLOR_PIPELINE
+	 * behavior, such as:
+	 *
+	 *  - GAMMA_LUT
+	 *  - DEGAMMA_LUT
+	 *  - GAMMA_LUT_SIZE
+	 *  - CTM
+	 *
+	 * or any other driver-specific properties that might affect pixel
+	 * values.
+	 */
+	bool crtc_color_pipeline : 1;
+
 	/**
 	 * @colorops:
 	 *

-- 
2.51.0



From ariel.dalessandro at collabora.com  Tue Dec 23 10:01:28 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Tue, 23 Dec 2025 15:01:28 -0300
Subject: [PATCH v3 08/21] drm/atomic: Print the color pipeline as part of
 the CRTC state print
In-Reply-To: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
References: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
Message-ID: <20251223-mtk-post-blend-color-pipeline-v3-8-7d969f9a37a0@collabora.com>

From: "N?colas F. R. A. Prado" <nfraprado at collabora.com>

Print the value of the color pipeline in the CRTC state as part of the
CRTC state print.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
Co-developed-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Signed-off-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
Reviewed-by: Harry Wentland <harry.wentland at amd.com>
---
 drivers/gpu/drm/drm_atomic.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index e9022d7ad04b0..aa4aa2f589b3d 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -475,6 +475,8 @@ static void drm_atomic_crtc_print_state(struct drm_printer *p,
 	drm_printf(p, "\tplane_mask=%x\n", state->plane_mask);
 	drm_printf(p, "\tconnector_mask=%x\n", state->connector_mask);
 	drm_printf(p, "\tencoder_mask=%x\n", state->encoder_mask);
+	drm_printf(p, "\tcolor-pipeline=%d\n",
+		   state->color_pipeline ? state->color_pipeline->base.id : 0);
 	drm_printf(p, "\tmode: " DRM_MODE_FMT "\n", DRM_MODE_ARG(&state->mode));
 
 	if (crtc->funcs->atomic_print_state)

-- 
2.51.0



From ariel.dalessandro at collabora.com  Tue Dec 23 10:01:29 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Tue, 23 Dec 2025 15:01:29 -0300
Subject: [PATCH v3 09/21] drm/colorop: Factor out common paths from
 colorops helpers
In-Reply-To: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
References: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
Message-ID: <20251223-mtk-post-blend-color-pipeline-v3-9-7d969f9a37a0@collabora.com>

From: "N?colas F. R. A. Prado" <nfraprado at collabora.com>

Factor out the common code paths from the colorop helpers so they can be
reused by the post-blend colorop helpers.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
Co-developed-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Signed-off-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
Reviewed-by: Harry Wentland <harry.wentland at amd.com>
---
 drivers/gpu/drm/drm_colorop.c | 146 ++++++++++++++++++++++++++++--------------
 1 file changed, 99 insertions(+), 47 deletions(-)

diff --git a/drivers/gpu/drm/drm_colorop.c b/drivers/gpu/drm/drm_colorop.c
index bf3b8ff51571b..6a285cdb0a354 100644
--- a/drivers/gpu/drm/drm_colorop.c
+++ b/drivers/gpu/drm/drm_colorop.c
@@ -93,9 +93,9 @@ static const struct drm_prop_enum_list drm_colorop_lut3d_interpolation_list[] =
 
 /* Init Helpers */
 
-static int drm_plane_colorop_init(struct drm_device *dev, struct drm_colorop *colorop,
-				  struct drm_plane *plane, enum drm_colorop_type type,
-				  uint32_t flags)
+static int drm_common_colorop_init(struct drm_device *dev,
+				   struct drm_colorop *colorop,
+				   enum drm_colorop_type type, uint32_t flags)
 {
 	struct drm_mode_config *config = &dev->mode_config;
 	struct drm_property *prop;
@@ -108,7 +108,6 @@ static int drm_plane_colorop_init(struct drm_device *dev, struct drm_colorop *co
 	colorop->base.properties = &colorop->properties;
 	colorop->dev = dev;
 	colorop->type = type;
-	colorop->plane = plane;
 	colorop->next = NULL;
 
 	list_add_tail(&colorop->head, &config->colorop_list);
@@ -157,6 +156,20 @@ static int drm_plane_colorop_init(struct drm_device *dev, struct drm_colorop *co
 	return ret;
 }
 
+static int drm_plane_colorop_init(struct drm_device *dev,
+				  struct drm_colorop *colorop,
+				  struct drm_plane *plane,
+				  enum drm_colorop_type type, uint32_t flags)
+{
+	int ret;
+
+	ret = drm_common_colorop_init(dev, colorop, type, flags);
+
+	colorop->plane = plane;
+
+	return ret;
+}
+
 /**
  * drm_colorop_cleanup - Cleanup a drm_colorop object in color_pipeline
  *
@@ -210,31 +223,13 @@ EXPORT_SYMBOL(drm_colorop_pipeline_destroy);
  * @flags: bitmask of misc, see DRM_COLOROP_FLAG_* defines.
  * @return zero on success, -E value on failure
  */
-int drm_plane_colorop_curve_1d_init(struct drm_device *dev, struct drm_colorop *colorop,
-				    struct drm_plane *plane, u64 supported_tfs, uint32_t flags)
+static int drm_common_colorop_curve_1d_init(struct drm_device *dev, struct drm_colorop *colorop,
+					    u64 supported_tfs, uint32_t flags)
 {
 	struct drm_prop_enum_list enum_list[DRM_COLOROP_1D_CURVE_COUNT];
 	int i, len;
 
 	struct drm_property *prop;
-	int ret;
-
-	if (!supported_tfs) {
-		drm_err(dev,
-			"No supported TFs for new 1D curve colorop on [PLANE:%d:%s]\n",
-			plane->base.id, plane->name);
-		return -EINVAL;
-	}
-
-	if ((supported_tfs & -BIT(DRM_COLOROP_1D_CURVE_COUNT)) != 0) {
-		drm_err(dev, "Unknown TF provided on [PLANE:%d:%s]\n",
-			plane->base.id, plane->name);
-		return -EINVAL;
-	}
-
-	ret = drm_plane_colorop_init(dev, colorop, plane, DRM_COLOROP_1D_CURVE, flags);
-	if (ret)
-		return ret;
 
 	len = 0;
 	for (i = 0; i < DRM_COLOROP_1D_CURVE_COUNT; i++) {
@@ -263,6 +258,41 @@ int drm_plane_colorop_curve_1d_init(struct drm_device *dev, struct drm_colorop *
 
 	return 0;
 }
+
+static int drm_colorop_has_supported_tf(struct drm_device *dev, struct drm_mode_object *obj,
+					const char *name, u64 supported_tfs)
+{
+	if (!supported_tfs) {
+		drm_err(dev,
+			"No supported TFs for new 1D curve colorop on [PLANE:%d:%s]\n",
+			obj->id, name);
+		return -EINVAL;
+	}
+
+	if ((supported_tfs & -BIT(DRM_COLOROP_1D_CURVE_COUNT)) != 0) {
+		drm_err(dev, "Unknown TF provided on [PLANE:%d:%s]\n",
+			obj->id, name);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int drm_plane_colorop_curve_1d_init(struct drm_device *dev, struct drm_colorop *colorop,
+				    struct drm_plane *plane, u64 supported_tfs, uint32_t flags)
+{
+	int ret;
+
+	ret = drm_colorop_has_supported_tf(dev, &plane->base, plane->name, supported_tfs);
+	if (ret)
+		return ret;
+
+	ret = drm_plane_colorop_init(dev, colorop, plane, DRM_COLOROP_1D_CURVE, flags);
+	if (ret)
+		return ret;
+
+	return drm_common_colorop_curve_1d_init(dev, colorop, supported_tfs, flags);
+}
 EXPORT_SYMBOL(drm_plane_colorop_curve_1d_init);
 
 static int drm_colorop_create_data_prop(struct drm_device *dev, struct drm_colorop *colorop)
@@ -283,29 +313,16 @@ static int drm_colorop_create_data_prop(struct drm_device *dev, struct drm_color
 	return 0;
 }
 
-/**
- * drm_plane_colorop_curve_1d_lut_init - Initialize a DRM_COLOROP_1D_LUT
- *
- * @dev: DRM device
- * @colorop: The drm_colorop object to initialize
- * @plane: The associated drm_plane
- * @lut_size: LUT size supported by driver
- * @interpolation: 1D LUT interpolation type
- * @flags: bitmask of misc, see DRM_COLOROP_FLAG_* defines.
- * @return zero on success, -E value on failure
- */
-int drm_plane_colorop_curve_1d_lut_init(struct drm_device *dev, struct drm_colorop *colorop,
-					struct drm_plane *plane, uint32_t lut_size,
-					enum drm_colorop_lut1d_interpolation_type interpolation,
-					uint32_t flags)
+static int
+drm_common_colorop_curve_1d_lut_init(struct drm_device *dev,
+				     struct drm_colorop *colorop,
+				     uint32_t lut_size,
+				     enum drm_colorop_lut1d_interpolation_type interpolation,
+				     uint32_t flags)
 {
 	struct drm_property *prop;
 	int ret;
 
-	ret = drm_plane_colorop_init(dev, colorop, plane, DRM_COLOROP_1D_LUT, flags);
-	if (ret)
-		return ret;
-
 	/* initialize 1D LUT only attribute */
 	/* LUT size */
 	prop = drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE | DRM_MODE_PROP_ATOMIC,
@@ -337,17 +354,40 @@ int drm_plane_colorop_curve_1d_lut_init(struct drm_device *dev, struct drm_color
 
 	return 0;
 }
-EXPORT_SYMBOL(drm_plane_colorop_curve_1d_lut_init);
 
-int drm_plane_colorop_ctm_3x4_init(struct drm_device *dev, struct drm_colorop *colorop,
-				   struct drm_plane *plane, uint32_t flags)
+/**
+ * drm_plane_colorop_curve_1d_lut_init - Initialize a DRM_COLOROP_1D_LUT
+ *
+ * @dev: DRM device
+ * @colorop: The drm_colorop object to initialize
+ * @plane: The associated drm_plane
+ * @lut_size: LUT size supported by driver
+ * @lut1d_interpolation: 1D LUT interpolation type
+ * @flags: bitmask of misc, see DRM_COLOROP_FLAG_* defines.
+ * @return zero on success, -E value on failure
+ */
+int
+drm_plane_colorop_curve_1d_lut_init(struct drm_device *dev, struct drm_colorop *colorop,
+				    struct drm_plane *plane, uint32_t lut_size,
+				    enum drm_colorop_lut1d_interpolation_type lut1d_interpolation,
+				    uint32_t flags)
 {
 	int ret;
 
-	ret = drm_plane_colorop_init(dev, colorop, plane, DRM_COLOROP_CTM_3X4, flags);
+	ret = drm_plane_colorop_init(dev, colorop, plane, DRM_COLOROP_1D_LUT, flags);
 	if (ret)
 		return ret;
 
+	return drm_common_colorop_curve_1d_lut_init(dev, colorop, lut_size,
+						    lut1d_interpolation, flags);
+}
+EXPORT_SYMBOL(drm_plane_colorop_curve_1d_lut_init);
+
+static int drm_common_colorop_ctm_3x4_init(struct drm_device *dev, struct drm_colorop *colorop,
+					   uint32_t flags)
+{
+	int ret;
+
 	ret = drm_colorop_create_data_prop(dev, colorop);
 	if (ret)
 		return ret;
@@ -356,6 +396,18 @@ int drm_plane_colorop_ctm_3x4_init(struct drm_device *dev, struct drm_colorop *c
 
 	return 0;
 }
+
+int drm_plane_colorop_ctm_3x4_init(struct drm_device *dev, struct drm_colorop *colorop,
+				   struct drm_plane *plane, uint32_t flags)
+{
+	int ret;
+
+	ret = drm_plane_colorop_init(dev, colorop, plane, DRM_COLOROP_CTM_3X4, flags);
+	if (ret)
+		return ret;
+
+	return drm_common_colorop_ctm_3x4_init(dev, colorop, flags);
+}
 EXPORT_SYMBOL(drm_plane_colorop_ctm_3x4_init);
 
 /**

-- 
2.51.0



From ariel.dalessandro at collabora.com  Tue Dec 23 10:01:30 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Tue, 23 Dec 2025 15:01:30 -0300
Subject: [PATCH v3 10/21] drm/colorop: Introduce colorop helpers for crtc
In-Reply-To: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
References: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
Message-ID: <20251223-mtk-post-blend-color-pipeline-v3-10-7d969f9a37a0@collabora.com>

From: "N?colas F. R. A. Prado" <nfraprado at collabora.com>

Introduce colorop helper counterparts for post-blend color pipelines
that take a CRTC instead of a plane.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
Co-developed-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Signed-off-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
Reviewed-by: Harry Wentland <harry.wentland at amd.com>
---
 drivers/gpu/drm/drm_colorop.c | 73 +++++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_colorop.h     |  8 +++++
 2 files changed, 81 insertions(+)

diff --git a/drivers/gpu/drm/drm_colorop.c b/drivers/gpu/drm/drm_colorop.c
index 6a285cdb0a354..4ce93807ea565 100644
--- a/drivers/gpu/drm/drm_colorop.c
+++ b/drivers/gpu/drm/drm_colorop.c
@@ -170,6 +170,20 @@ static int drm_plane_colorop_init(struct drm_device *dev,
 	return ret;
 }
 
+static int drm_crtc_colorop_init(struct drm_device *dev,
+				 struct drm_colorop *colorop,
+				 struct drm_crtc *crtc,
+				 enum drm_colorop_type type, uint32_t flags)
+{
+	int ret;
+
+	ret = drm_common_colorop_init(dev, colorop, type, flags);
+
+	colorop->crtc = crtc;
+
+	return ret;
+}
+
 /**
  * drm_colorop_cleanup - Cleanup a drm_colorop object in color_pipeline
  *
@@ -295,6 +309,23 @@ int drm_plane_colorop_curve_1d_init(struct drm_device *dev, struct drm_colorop *
 }
 EXPORT_SYMBOL(drm_plane_colorop_curve_1d_init);
 
+int drm_crtc_colorop_curve_1d_init(struct drm_device *dev, struct drm_colorop *colorop,
+				   struct drm_crtc *crtc, u64 supported_tfs, uint32_t flags)
+{
+	int ret;
+
+	ret = drm_colorop_has_supported_tf(dev, &crtc->base, crtc->name, supported_tfs);
+	if (ret)
+		return ret;
+
+	ret = drm_crtc_colorop_init(dev, colorop, crtc, DRM_COLOROP_1D_CURVE, flags);
+	if (ret)
+		return ret;
+
+	return drm_common_colorop_curve_1d_init(dev, colorop, supported_tfs, flags);
+}
+EXPORT_SYMBOL(drm_crtc_colorop_curve_1d_init);
+
 static int drm_colorop_create_data_prop(struct drm_device *dev, struct drm_colorop *colorop)
 {
 	struct drm_property *prop;
@@ -383,6 +414,35 @@ drm_plane_colorop_curve_1d_lut_init(struct drm_device *dev, struct drm_colorop *
 }
 EXPORT_SYMBOL(drm_plane_colorop_curve_1d_lut_init);
 
+/**
+ * drm_crtc_colorop_curve_1d_lut_init - Initialize a DRM_COLOROP_1D_LUT
+ *
+ * @dev: DRM device
+ * @colorop: The drm_colorop object to initialize
+ * @crtc: The associated drm_crtc
+ * @lut_size: LUT size supported by driver
+ * @interpolation: 1D LUT interpolation type
+ * @flags: bitmask of misc, see DRM_COLOROP_FLAG_* defines.
+ * @return zero on success, -E value on failure
+ */
+int
+drm_crtc_colorop_curve_1d_lut_init(struct drm_device *dev,
+				   struct drm_colorop *colorop,
+				   struct drm_crtc *crtc, uint32_t lut_size,
+				   enum drm_colorop_lut1d_interpolation_type interpolation,
+				   uint32_t flags)
+{
+	int ret;
+
+	ret = drm_crtc_colorop_init(dev, colorop, crtc, DRM_COLOROP_1D_LUT, flags);
+	if (ret)
+		return ret;
+
+	return drm_common_colorop_curve_1d_lut_init(dev, colorop, lut_size,
+						    interpolation, flags);
+}
+EXPORT_SYMBOL(drm_crtc_colorop_curve_1d_lut_init);
+
 static int drm_common_colorop_ctm_3x4_init(struct drm_device *dev, struct drm_colorop *colorop,
 					   uint32_t flags)
 {
@@ -410,6 +470,19 @@ int drm_plane_colorop_ctm_3x4_init(struct drm_device *dev, struct drm_colorop *c
 }
 EXPORT_SYMBOL(drm_plane_colorop_ctm_3x4_init);
 
+int drm_crtc_colorop_ctm_3x4_init(struct drm_device *dev, struct drm_colorop *colorop,
+				   struct drm_crtc *crtc, uint32_t flags)
+{
+	int ret;
+
+	ret = drm_crtc_colorop_init(dev, colorop, crtc, DRM_COLOROP_CTM_3X4, flags);
+	if (ret)
+		return ret;
+
+	return drm_common_colorop_ctm_3x4_init(dev, colorop, flags);
+}
+EXPORT_SYMBOL(drm_crtc_colorop_ctm_3x4_init);
+
 /**
  * drm_plane_colorop_mult_init - Initialize a DRM_COLOROP_MULTIPLIER
  *
diff --git a/include/drm/drm_colorop.h b/include/drm/drm_colorop.h
index 49d342b7f8b0b..a1f81fa96f66b 100644
--- a/include/drm/drm_colorop.h
+++ b/include/drm/drm_colorop.h
@@ -400,14 +400,22 @@ static inline struct drm_colorop *drm_colorop_find(struct drm_device *dev,
 void drm_colorop_pipeline_destroy(struct drm_device *dev);
 void drm_colorop_cleanup(struct drm_colorop *colorop);
 
+int drm_crtc_colorop_curve_1d_lut_init(struct drm_device *dev, struct drm_colorop *colorop,
+				       struct drm_crtc *crtc, uint32_t lut_size,
+				       enum drm_colorop_lut1d_interpolation_type interpolation,
+				       uint32_t flags);
 int drm_plane_colorop_curve_1d_init(struct drm_device *dev, struct drm_colorop *colorop,
 				    struct drm_plane *plane, u64 supported_tfs, uint32_t flags);
+int drm_crtc_colorop_curve_1d_init(struct drm_device *dev, struct drm_colorop *colorop,
+				   struct drm_crtc *crtc, u64 supported_tfs, uint32_t flags);
 int drm_plane_colorop_curve_1d_lut_init(struct drm_device *dev, struct drm_colorop *colorop,
 					struct drm_plane *plane, uint32_t lut_size,
 					enum drm_colorop_lut1d_interpolation_type interpolation,
 					uint32_t flags);
 int drm_plane_colorop_ctm_3x4_init(struct drm_device *dev, struct drm_colorop *colorop,
 				   struct drm_plane *plane, uint32_t flags);
+int drm_crtc_colorop_ctm_3x4_init(struct drm_device *dev, struct drm_colorop *colorop,
+				   struct drm_crtc *crtc, uint32_t flags);
 int drm_plane_colorop_mult_init(struct drm_device *dev, struct drm_colorop *colorop,
 				struct drm_plane *plane, uint32_t flags);
 int drm_plane_colorop_3dlut_init(struct drm_device *dev, struct drm_colorop *colorop,

-- 
2.51.0



From ariel.dalessandro at collabora.com  Tue Dec 23 10:01:31 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Tue, 23 Dec 2025 15:01:31 -0300
Subject: [PATCH v3 11/21] drm/crtc: Track crtc color pipeline client cap in
 drm_crtc_state
In-Reply-To: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
References: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
Message-ID: <20251223-mtk-post-blend-color-pipeline-v3-11-7d969f9a37a0@collabora.com>

From: "N?colas F. R. A. Prado" <nfraprado at collabora.com>

Some drivers, like VKMS, only have access to the drm_crtc_state but not
the drm_atomic_state during composition of the output framebuffer. Store
the state of the CRTC (post-blend) color pipeline client cap in the
drm_crtc_state so those drivers can decide whether to look at the color
pipeline or the legacy properties for the color management settings to
apply.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
Co-developed-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Signed-off-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
Reviewed-by: Harry Wentland <harry.wentland at amd.com>
---
 drivers/gpu/drm/drm_atomic.c | 1 +
 include/drm/drm_crtc.h       | 8 ++++++++
 2 files changed, 9 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index aa4aa2f589b3d..f2028e6cdd62f 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -389,6 +389,7 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state,
 	state->crtcs[index].new_state = crtc_state;
 	state->crtcs[index].ptr = crtc;
 	crtc_state->state = state;
+	crtc_state->color_pipeline_enabled = state->crtc_color_pipeline;
 
 	drm_dbg_atomic(state->dev, "Added [CRTC:%d:%s] %p state to %p\n",
 		       crtc->base.id, crtc->name, crtc_state, state);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index b3c9818715851..888a3a5aa3a27 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -282,6 +282,14 @@ struct drm_crtc_state {
 	 */
 	struct drm_colorop *color_pipeline;
 
+	/**
+	 * @color_pipeline_enabled:
+	 *
+	 * Whether color management should be done based on the &color_pipeline
+	 * or the legacy color properties (&ctm, &gamma_lut and &degamma_lut).
+	 */
+	bool color_pipeline_enabled;
+
 	/**
 	 * @target_vblank:
 	 *

-- 
2.51.0



From ariel.dalessandro at collabora.com  Tue Dec 23 10:01:32 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Tue, 23 Dec 2025 15:01:32 -0300
Subject: [PATCH v3 12/21] drm/mediatek: Support CRTC colorops for gamma and
 ctm
In-Reply-To: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
References: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
Message-ID: <20251223-mtk-post-blend-color-pipeline-v3-12-7d969f9a37a0@collabora.com>

From: "N?colas F. R. A. Prado" <nfraprado at collabora.com>

Allow configuring the gamma and ccorr blocks through the CRTC color
pipeline API instead of the GAMMA_LUT and CTM properties.

In order to achieve this, initialize the color pipeline property and
colorops on the CRTC based on the DDP components available in the CRTC
path. Then introduce a struct mtk_drm_colorop that extends drm_colorop
and tracks the mtk_ddp_comp that implements it in hardware, and include
new ddp_comp helper functions for setting gamma and ctm through the new
API. These helpers will then be called during commit flush for every
updated colorop if the DRM client supports the CRTC (post-blend) color
pipeline API.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
Co-developed-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Signed-off-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_crtc.c     | 222 +++++++++++++++++++++++++++++++-
 drivers/gpu/drm/mediatek/mtk_ddp_comp.h |   2 +
 2 files changed, 219 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c b/drivers/gpu/drm/mediatek/mtk_crtc.c
index 991cdb3d7d5fd..1ed3157fa91f0 100644
--- a/drivers/gpu/drm/mediatek/mtk_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_crtc.c
@@ -83,6 +83,12 @@ struct mtk_crtc_state {
 	unsigned int			pending_vrefresh;
 };
 
+struct mtk_drm_colorop {
+	struct drm_colorop colorop;
+	struct mtk_ddp_comp *comp;
+	uint32_t data_id;
+};
+
 static inline struct mtk_crtc *to_mtk_crtc(struct drm_crtc *c)
 {
 	return container_of(c, struct mtk_crtc, base);
@@ -93,6 +99,11 @@ static inline struct mtk_crtc_state *to_mtk_crtc_state(struct drm_crtc_state *s)
 	return container_of(s, struct mtk_crtc_state, base);
 }
 
+static inline struct mtk_drm_colorop *to_mtk_colorop(struct drm_colorop *colorop)
+{
+	return container_of(colorop, struct mtk_drm_colorop, colorop);
+}
+
 static void mtk_crtc_finish_page_flip(struct mtk_crtc *mtk_crtc)
 {
 	struct drm_crtc *crtc = &mtk_crtc->base;
@@ -126,6 +137,19 @@ static void mtk_drm_finish_page_flip(struct mtk_crtc *mtk_crtc)
 	spin_unlock_irqrestore(&mtk_crtc->config_lock, flags);
 }
 
+static void mtk_drm_colorop_pipeline_destroy(struct drm_device *dev)
+{
+	struct drm_mode_config *config = &dev->mode_config;
+	struct drm_colorop *colorop, *next;
+	struct mtk_drm_colorop *mtk_colorop;
+
+	list_for_each_entry_safe(colorop, next, &config->colorop_list, head) {
+		drm_colorop_cleanup(colorop);
+		mtk_colorop = to_mtk_colorop(colorop);
+		kfree(mtk_colorop);
+	}
+}
+
 static void mtk_crtc_destroy(struct drm_crtc *crtc)
 {
 	struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
@@ -147,6 +171,8 @@ static void mtk_crtc_destroy(struct drm_crtc *crtc)
 		mtk_ddp_comp_unregister_vblank_cb(comp);
 	}
 
+	mtk_drm_colorop_pipeline_destroy(crtc->dev);
+
 	drm_crtc_cleanup(crtc);
 }
 
@@ -862,20 +888,103 @@ static void mtk_crtc_atomic_begin(struct drm_crtc *crtc,
 	}
 }
 
+static bool colorop_data_update_flush_status(struct drm_colorop_state *colorop_state)
+{
+	struct drm_colorop *colorop = colorop_state->colorop;
+	struct mtk_drm_colorop *mtk_colorop = to_mtk_colorop(colorop);
+	struct drm_property_blob *data_blob = colorop_state->data;
+	uint32_t data_id = colorop_state->bypass ? 0 : data_blob->base.id;
+	bool needs_flush = mtk_colorop->data_id != data_id;
+
+	mtk_colorop->data_id = data_id;
+
+	return needs_flush;
+}
+
+static void mtk_crtc_ddp_comp_apply_colorop(struct drm_colorop_state *colorop_state)
+{
+	struct drm_colorop *colorop = colorop_state->colorop;
+	struct mtk_drm_colorop *mtk_colorop = to_mtk_colorop(colorop);
+	struct drm_property_blob *data_blob = colorop_state->data;
+	struct mtk_ddp_comp *ddp_comp = mtk_colorop->comp;
+	struct drm_color_ctm_3x4 *ctm = NULL;
+	struct drm_color_lut32 *lut = NULL;
+
+	switch (colorop->type) {
+	case DRM_COLOROP_1D_LUT:
+		if (!colorop_data_update_flush_status(colorop_state))
+			return;
+
+		if (!colorop_state->bypass)
+			lut = (struct drm_color_lut32 *)data_blob->data;
+
+		ddp_comp->funcs->gamma_set_color_pipeline(ddp_comp->dev, lut);
+		break;
+	case DRM_COLOROP_CTM_3X4:
+		if (!colorop_data_update_flush_status(colorop_state))
+			return;
+
+		if (!colorop_state->bypass)
+			ctm = (struct drm_color_ctm_3x4 *)data_blob->data;
+
+		ddp_comp->funcs->ctm_set_color_pipeline(ddp_comp->dev, ctm);
+		break;
+	default:
+		/* If this happens the driver is broken */
+		drm_WARN(colorop->dev, 1,
+			 "Trying to atomic flush COLOROP of type unsupported by driver: %d\n",
+			 colorop->type);
+		break;
+	}
+}
+
 static void mtk_crtc_atomic_flush(struct drm_crtc *crtc,
 				  struct drm_atomic_state *state)
 {
 	struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
+	struct drm_colorop_state *new_colorop_state;
+	struct drm_colorop *colorop;
 	int i;
 
-	if (crtc->state->color_mgmt_changed)
-		for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
-			mtk_ddp_gamma_set(mtk_crtc->ddp_comp[i], crtc->state);
-			mtk_ddp_ctm_set(mtk_crtc->ddp_comp[i], crtc->state);
-		}
+	if (state->crtc_color_pipeline) {
+		for_each_new_colorop_in_state(state, colorop, new_colorop_state, i)
+			mtk_crtc_ddp_comp_apply_colorop(new_colorop_state);
+	} else {
+		if (crtc->state->color_mgmt_changed)
+			for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
+				mtk_ddp_gamma_set(mtk_crtc->ddp_comp[i], crtc->state);
+				mtk_ddp_ctm_set(mtk_crtc->ddp_comp[i], crtc->state);
+			}
+	}
 	mtk_crtc_update_config(mtk_crtc, !!mtk_crtc->event);
 }
 
+static int mtk_crtc_atomic_check(struct drm_crtc *crtc,
+				 struct drm_atomic_state *state)
+{
+	struct drm_colorop_state *new_colorop_state;
+	struct drm_colorop *colorop;
+	int i;
+
+	for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) {
+		switch (colorop->type) {
+		case DRM_COLOROP_1D_LUT:
+		case DRM_COLOROP_CTM_3X4:
+			if (!new_colorop_state->bypass && !new_colorop_state->data) {
+				drm_dbg_atomic(crtc->dev,
+					       "Missing required DATA property for COLOROP:%d\n",
+					       colorop->base.id);
+				return -EINVAL;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	return 0;
+}
+
 static const struct drm_crtc_funcs mtk_crtc_funcs = {
 	.set_config		= drm_atomic_helper_set_config,
 	.page_flip		= drm_atomic_helper_page_flip,
@@ -893,6 +1002,7 @@ static const struct drm_crtc_helper_funcs mtk_crtc_helper_funcs = {
 	.mode_valid	= mtk_crtc_mode_valid,
 	.atomic_begin	= mtk_crtc_atomic_begin,
 	.atomic_flush	= mtk_crtc_atomic_flush,
+	.atomic_check   = mtk_crtc_atomic_check,
 	.atomic_enable	= mtk_crtc_atomic_enable,
 	.atomic_disable	= mtk_crtc_atomic_disable,
 };
@@ -995,6 +1105,100 @@ struct device *mtk_crtc_dma_dev_get(struct drm_crtc *crtc)
 	return mtk_crtc->dma_dev;
 }
 
+#define MAX_COLOR_PIPELINE_OPS 2
+#define MAX_COLOR_PIPELINES 1
+
+static int mtk_colorop_init(struct mtk_crtc *mtk_crtc,
+			    struct mtk_drm_colorop *mtk_colorop,
+			    struct mtk_ddp_comp *ddp_comp)
+{
+	struct drm_colorop *colorop = &mtk_colorop->colorop;
+	int ret = 0;
+
+	if (ddp_comp->funcs->gamma_set_color_pipeline) {
+		unsigned int lut_sz = mtk_ddp_gamma_get_lut_size(ddp_comp);
+
+		ret = drm_crtc_colorop_curve_1d_lut_init(mtk_crtc->base.dev, colorop,
+							 &mtk_crtc->base,
+							 lut_sz,
+							 DRM_COLOROP_LUT1D_INTERPOLATION_LINEAR,
+							 DRM_COLOROP_FLAG_ALLOW_BYPASS);
+	} else if (ddp_comp->funcs->ctm_set_color_pipeline) {
+		ret = drm_crtc_colorop_ctm_3x4_init(mtk_crtc->base.dev,
+						    colorop,
+						    &mtk_crtc->base,
+						    DRM_COLOROP_FLAG_ALLOW_BYPASS);
+	}
+
+	mtk_colorop->comp = ddp_comp;
+
+	return ret;
+}
+
+static int mtk_crtc_init_crtc_color_pipeline(struct mtk_crtc *mtk_crtc,
+					     unsigned int gamma_lut_size)
+{
+	struct drm_prop_enum_list pipelines[MAX_COLOR_PIPELINES];
+	struct drm_colorop *ops[MAX_COLOR_PIPELINE_OPS];
+	struct mtk_drm_colorop *mtk_colorop;
+	unsigned int num_pipelines = 0;
+	unsigned int op_idx = 0;
+	int ret;
+	int j;
+
+	memset(ops, 0, sizeof(ops));
+
+	for (unsigned int i = 0;
+	     i < mtk_crtc->ddp_comp_nr && op_idx < MAX_COLOR_PIPELINE_OPS;
+	     i++) {
+		struct mtk_ddp_comp *ddp_comp = mtk_crtc->ddp_comp[i];
+
+		if (!(ddp_comp->funcs->gamma_set_color_pipeline ||
+		      ddp_comp->funcs->ctm_set_color_pipeline))
+			continue;
+
+		mtk_colorop = kzalloc(sizeof(struct mtk_drm_colorop), GFP_KERNEL);
+		if (!mtk_colorop) {
+			ret = -ENOMEM;
+			goto cleanup;
+		}
+
+		ops[op_idx] = &mtk_colorop->colorop;
+
+		ret = mtk_colorop_init(mtk_crtc, mtk_colorop, ddp_comp);
+		if (ret)
+			goto cleanup;
+
+		if (op_idx > 0)
+			drm_colorop_set_next_property(ops[op_idx-1], ops[op_idx]);
+
+		op_idx++;
+	}
+
+	if (op_idx > 0) {
+		pipelines[0].type = ops[0]->base.id;
+		pipelines[0].name = kasprintf(GFP_KERNEL, "Color Pipeline %d", ops[0]->base.id);
+		num_pipelines = 1;
+	}
+
+	/* Create COLOR_PIPELINE property and attach */
+	drm_crtc_create_color_pipeline_property(&mtk_crtc->base, pipelines, num_pipelines);
+
+	return 0;
+
+cleanup:
+	for (j = 0; j < op_idx; j++) {
+		if (ops[j]) {
+			drm_colorop_cleanup(ops[j]);
+			mtk_colorop = to_mtk_colorop(ops[j]);
+			kfree(mtk_colorop);
+			kfree(ops[j]);
+		}
+	}
+
+	return ret;
+}
+
 int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
 		    unsigned int path_len, int priv_data_index,
 		    const struct mtk_drm_route *conn_routes,
@@ -1111,6 +1315,10 @@ int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
 	if (ret < 0)
 		return ret;
 
+	ret = mtk_crtc_init_crtc_color_pipeline(mtk_crtc, gamma_lut_size);
+	if (ret < 0)
+		goto err_cleanup_crtc;
+
 	if (gamma_lut_size)
 		drm_mode_crtc_set_gamma_size(&mtk_crtc->base, gamma_lut_size);
 	drm_crtc_enable_color_mgmt(&mtk_crtc->base, 0, has_ctm, gamma_lut_size);
@@ -1183,4 +1391,8 @@ int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
 	}
 
 	return 0;
+
+err_cleanup_crtc:
+	drm_crtc_cleanup(&mtk_crtc->base);
+	return ret;
 }
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
index 3f3d43f4330da..93665b5d5358c 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
@@ -75,10 +75,12 @@ struct mtk_ddp_comp_funcs {
 	unsigned int (*gamma_get_lut_size)(struct device *dev);
 	void (*gamma_set)(struct device *dev,
 			  struct drm_crtc_state *state);
+	void (*gamma_set_color_pipeline)(struct device *dev, struct drm_color_lut32 *lut);
 	void (*bgclr_in_on)(struct device *dev);
 	void (*bgclr_in_off)(struct device *dev);
 	void (*ctm_set)(struct device *dev,
 			struct drm_crtc_state *state);
+	void (*ctm_set_color_pipeline)(struct device *dev, struct drm_color_ctm_3x4 *ctm);
 	struct device * (*dma_dev_get)(struct device *dev);
 	u32 (*get_blend_modes)(struct device *dev);
 	const u32 *(*get_formats)(struct device *dev);

-- 
2.51.0



From ariel.dalessandro at collabora.com  Tue Dec 23 10:01:33 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Tue, 23 Dec 2025 15:01:33 -0300
Subject: [PATCH v3 13/21] drm: Add helper to extract a 3x4 matrix from any
 CTM matrix dimensions
In-Reply-To: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
References: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
Message-ID: <20251223-mtk-post-blend-color-pipeline-v3-13-7d969f9a37a0@collabora.com>

Add a common helper to ease the conversion from both 3x3 or 3x4 matrices
to a CTM 3x4 matrix. This is handy for code that needs to handle both
dimensions.

Signed-off-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
---
 include/drm/drm_color_mgmt.h | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/include/drm/drm_color_mgmt.h b/include/drm/drm_color_mgmt.h
index 5140691f476a9..51279267ed3fd 100644
--- a/include/drm/drm_color_mgmt.h
+++ b/include/drm/drm_color_mgmt.h
@@ -66,6 +66,40 @@ static inline u32 drm_color_lut32_extract(u32 user_input, int bit_precision)
 				     (1ULL << 32) - 1);
 }
 
+/**
+ * drm_color_ctm_to_ctm_3x4 - Copy CTM matrix contents to 3x4 dimensions matrix
+ *
+ * @dest: The destination CTM 3x4 dimensions matrix
+ * @src: The source CTM matrix (3x3 or 3x4 dimensions depending on @ctm_3x4)
+ * @ctm_3x4: Boolean indicating the source CTM matrix dimensions
+ *
+ * Copy the contents of a CTM matrix from @src, to a CTM 3x4 dimensions matrix.
+ * The source matrix can be 3x3 or 3x4 dimensions depending on the @ctm_3x4
+ * boolean argument.
+ */
+static inline void drm_color_ctm_to_ctm_3x4(struct drm_color_ctm_3x4 *dest,
+					    void *src, bool ctm_3x4)
+{
+	if (ctm_3x4) {
+		*dest = *(struct drm_color_ctm_3x4 *)src;
+	} else {
+		struct drm_color_ctm *ctm = (struct drm_color_ctm *)src;
+
+		dest->matrix[0] = ctm->matrix[0];
+		dest->matrix[1] = ctm->matrix[1];
+		dest->matrix[2] = ctm->matrix[2];
+		dest->matrix[3] = 0;
+		dest->matrix[4] = ctm->matrix[3];
+		dest->matrix[5] = ctm->matrix[4];
+		dest->matrix[6] = ctm->matrix[5];
+		dest->matrix[7] = 0;
+		dest->matrix[8] = ctm->matrix[6];
+		dest->matrix[9] = ctm->matrix[7];
+		dest->matrix[10] = ctm->matrix[8];
+		dest->matrix[11] = 0;
+	}
+}
+
 u64 drm_color_ctm_s31_32_to_qm_n(u64 user_input, u32 m, u32 n);
 
 void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc,

-- 
2.51.0



From ariel.dalessandro at collabora.com  Tue Dec 23 10:01:34 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Tue, 23 Dec 2025 15:01:34 -0300
Subject: [PATCH v3 14/21] drm/mediatek: ccorr: Support CRTC color pipeline
 API
In-Reply-To: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
References: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
Message-ID: <20251223-mtk-post-blend-color-pipeline-v3-14-7d969f9a37a0@collabora.com>

From: "N?colas F. R. A. Prado" <nfraprado at collabora.com>

Implement the ctm_set_color_pipeline DDP component function to allow
configuring the CTM through the color pipeline API.

The color pipeline API only defines a 3x4 matrix, while the driver
currently only supports setting the coefficients for a 3x3 matrix.
However the underlying hardware does support setting the offset
coefficients that make up a 3x4 matrix, so implement support for setting
them so the 3x4 matrix structure for the API can be used as is.

Also make sure to enable or disable the CTM function depending on
whether the block should be bypassed or not.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
Co-developed-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Signed-off-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_ddp_comp.c   |  3 +-
 drivers/gpu/drm/mediatek/mtk_disp_ccorr.c | 88 ++++++++++++++++++++++++-------
 drivers/gpu/drm/mediatek/mtk_disp_drv.h   |  3 +-
 3 files changed, 73 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index 9672ea1f91a2b..69eeb36609584 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -284,7 +284,8 @@ static const struct mtk_ddp_comp_funcs ddp_ccorr = {
 	.config = mtk_ccorr_config,
 	.start = mtk_ccorr_start,
 	.stop = mtk_ccorr_stop,
-	.ctm_set = mtk_ccorr_ctm_set,
+	.ctm_set = mtk_ccorr_ctm_set_legacy,
+	.ctm_set_color_pipeline = mtk_ccorr_ctm_set_color_pipeline,
 };
 
 static const struct mtk_ddp_comp_funcs ddp_color = {
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c b/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c
index 6d7bf4afa78d3..e2bd8010d22e5 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c
@@ -28,6 +28,11 @@
 #define DISP_CCORR_COEF_2			0x0088
 #define DISP_CCORR_COEF_3			0x008C
 #define DISP_CCORR_COEF_4			0x0090
+#define DISP_CCORR_OFFSET_0			0x0100
+#define CCORR_OFFSET_EN					BIT(31)
+#define DISP_CCORR_OFFSET_1			0x0104
+#define DISP_CCORR_OFFSET_2			0x0108
+#define DISP_CCORR_OFFSET_MASK				GENMASK(26, 14)
 
 struct mtk_disp_ccorr_data {
 	u32 matrix_bits;
@@ -80,36 +85,81 @@ void mtk_ccorr_stop(struct device *dev)
 	writel_relaxed(0x0, ccorr->regs + DISP_CCORR_EN);
 }
 
-void mtk_ccorr_ctm_set(struct device *dev, struct drm_crtc_state *state)
+static void mtk_ccorr_ctm_set(struct device *dev, struct cmdq_pkt *cmdq_pkt,
+			      void *ctm, bool ctm_3x4)
 {
 	struct mtk_disp_ccorr *ccorr = dev_get_drvdata(dev);
-	struct drm_property_blob *blob = state->ctm;
-	struct drm_color_ctm *ctm;
-	const u64 *input;
-	uint16_t coeffs[9] = { 0 };
-	int i;
-	struct cmdq_pkt *cmdq_pkt = NULL;
 	u32 matrix_bits = ccorr->data->matrix_bits;
+	struct drm_color_ctm_3x4 coeffs;
+	u32 val;
+	int i;
 
-	if (!blob)
-		return;
+	drm_color_ctm_to_ctm_3x4(&coeffs, ctm, ctm_3x4);
 
-	ctm = (struct drm_color_ctm *)blob->data;
-	input = ctm->matrix;
+	for (i = 0; i < ARRAY_SIZE(coeffs.matrix); i++)
+		coeffs.matrix[i] =
+			drm_color_ctm_s31_32_to_qm_n(coeffs.matrix[i], 2, matrix_bits);
 
-	for (i = 0; i < ARRAY_SIZE(coeffs); i++)
-		coeffs[i] = drm_color_ctm_s31_32_to_qm_n(input[i], 2, matrix_bits);
-
-	mtk_ddp_write(cmdq_pkt, coeffs[0] << 16 | coeffs[1],
+	mtk_ddp_write(cmdq_pkt, coeffs.matrix[0] << 16 | coeffs.matrix[1],
 		      &ccorr->cmdq_reg, ccorr->regs, DISP_CCORR_COEF_0);
-	mtk_ddp_write(cmdq_pkt, coeffs[2] << 16 | coeffs[3],
+	mtk_ddp_write(cmdq_pkt, coeffs.matrix[2] << 16 | coeffs.matrix[4],
 		      &ccorr->cmdq_reg, ccorr->regs, DISP_CCORR_COEF_1);
-	mtk_ddp_write(cmdq_pkt, coeffs[4] << 16 | coeffs[5],
+	mtk_ddp_write(cmdq_pkt, coeffs.matrix[5] << 16 | coeffs.matrix[6],
 		      &ccorr->cmdq_reg, ccorr->regs, DISP_CCORR_COEF_2);
-	mtk_ddp_write(cmdq_pkt, coeffs[6] << 16 | coeffs[7],
+	mtk_ddp_write(cmdq_pkt, coeffs.matrix[8] << 16 | coeffs.matrix[9],
 		      &ccorr->cmdq_reg, ccorr->regs, DISP_CCORR_COEF_3);
-	mtk_ddp_write(cmdq_pkt, coeffs[8] << 16,
+	mtk_ddp_write(cmdq_pkt, coeffs.matrix[10] << 16,
 		      &ccorr->cmdq_reg, ccorr->regs, DISP_CCORR_COEF_4);
+
+	if (ctm_3x4) {
+		val = CCORR_OFFSET_EN;
+		val |= FIELD_PREP(DISP_CCORR_OFFSET_MASK, coeffs.matrix[3]);
+		mtk_ddp_write(cmdq_pkt, val, &ccorr->cmdq_reg,
+			      ccorr->regs, DISP_CCORR_OFFSET_0);
+		val = FIELD_PREP(DISP_CCORR_OFFSET_MASK, coeffs.matrix[7]);
+		mtk_ddp_write(cmdq_pkt, val, &ccorr->cmdq_reg,
+			      ccorr->regs, DISP_CCORR_OFFSET_1);
+		val = FIELD_PREP(DISP_CCORR_OFFSET_MASK, coeffs.matrix[11]);
+		mtk_ddp_write(cmdq_pkt, val, &ccorr->cmdq_reg,
+			      ccorr->regs, DISP_CCORR_OFFSET_2);
+	} else {
+		mtk_ddp_write_mask(cmdq_pkt, 0, &ccorr->cmdq_reg,
+				   ccorr->regs, DISP_CCORR_OFFSET_0,
+				   CCORR_OFFSET_EN);
+	}
+
+	mtk_ddp_write(cmdq_pkt, CCORR_ENGINE_EN, &ccorr->cmdq_reg,
+		      ccorr->regs, DISP_CCORR_CFG);
+}
+
+void mtk_ccorr_ctm_set_legacy(struct device *dev, struct drm_crtc_state *state)
+{
+	struct drm_property_blob *blob = state->ctm;
+	struct cmdq_pkt *cmdq_pkt = NULL;
+	struct drm_color_ctm *ctm;
+
+	if (!blob)
+		return;
+
+	ctm = (struct drm_color_ctm *)blob->data;
+
+	mtk_ccorr_ctm_set(dev, cmdq_pkt, ctm, false);
+}
+
+void mtk_ccorr_ctm_set_color_pipeline(struct device *dev, struct drm_color_ctm_3x4 *ctm)
+{
+	struct mtk_disp_ccorr *ccorr = dev_get_drvdata(dev);
+	struct cmdq_pkt *cmdq_pkt = NULL;
+
+	/* Configure block to be bypassed */
+	if (!ctm) {
+		mtk_ddp_write_mask(cmdq_pkt, CCORR_RELAY_MODE, &ccorr->cmdq_reg,
+				   ccorr->regs, DISP_CCORR_CFG,
+				   CCORR_RELAY_MODE | CCORR_ENGINE_EN);
+		return;
+	}
+
+	mtk_ccorr_ctm_set(dev, cmdq_pkt, ctm, true);
 }
 
 static int mtk_disp_ccorr_bind(struct device *dev, struct device *master,
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index 679d413bf10be..ac84cf579150f 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -22,7 +22,8 @@ void mtk_aal_gamma_set(struct device *dev, struct drm_crtc_state *state);
 void mtk_aal_start(struct device *dev);
 void mtk_aal_stop(struct device *dev);
 
-void mtk_ccorr_ctm_set(struct device *dev, struct drm_crtc_state *state);
+void mtk_ccorr_ctm_set_legacy(struct device *dev, struct drm_crtc_state *state);
+void mtk_ccorr_ctm_set_color_pipeline(struct device *dev, struct drm_color_ctm_3x4 *ctm);
 int mtk_ccorr_clk_enable(struct device *dev);
 void mtk_ccorr_clk_disable(struct device *dev);
 void mtk_ccorr_config(struct device *dev, unsigned int w,

-- 
2.51.0



From ariel.dalessandro at collabora.com  Tue Dec 23 10:01:35 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Tue, 23 Dec 2025 15:01:35 -0300
Subject: [PATCH v3 15/21] drm: Add helper to extract a LUT entry from
 either 16-bit or 32-bit LUT
In-Reply-To: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
References: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
Message-ID: <20251223-mtk-post-blend-color-pipeline-v3-15-7d969f9a37a0@collabora.com>

Add a common helper to ease extracting a 32-bit LUT entry from either
16-bit or 32-bit LUT entry. This is handy for code that needs to handle
both bit widths.

Signed-off-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Co-developed-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
---
 include/drm/drm_color_mgmt.h | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/include/drm/drm_color_mgmt.h b/include/drm/drm_color_mgmt.h
index 51279267ed3fd..3d0117aae342d 100644
--- a/include/drm/drm_color_mgmt.h
+++ b/include/drm/drm_color_mgmt.h
@@ -66,6 +66,33 @@ static inline u32 drm_color_lut32_extract(u32 user_input, int bit_precision)
 				     (1ULL << 32) - 1);
 }
 
+/**
+ * drm_color_lut_to_lut32 - Copy LUT entry contents to 32-bit channel color LUT
+ *
+ * @dest: The destination 32-bit per channel color LUT entry
+ * @src: The source array of LUT entries (16-bit or 32-bit depending on @bits32)
+ * @index: LUT entry array index
+ * @bits32: Boolean indicating the source LUT entry bit-witdh
+ *
+ * Copy the contents of a LUT entry from the source array, to a 32-bit channel
+ * color LUT. The source array of LUT entries can be 16-bit or 32-bit width
+ * depending on the @bits32 boolean argument.
+ */
+static inline void drm_color_lut_to_lut32(struct drm_color_lut32 *dest,
+					  void *src, int index, bool bits32)
+{
+	if (bits32) {
+		*dest = ((struct drm_color_lut32 *)src)[index];
+	} else {
+		struct drm_color_lut *lut =
+			&((struct drm_color_lut *)src)[index];
+		dest->red = lut->red;
+		dest->green = lut->green;
+		dest->blue = lut->blue;
+		dest->reserved = lut->reserved;
+	}
+}
+
 /**
  * drm_color_ctm_to_ctm_3x4 - Copy CTM matrix contents to 3x4 dimensions matrix
  *

-- 
2.51.0



From ariel.dalessandro at collabora.com  Tue Dec 23 10:01:36 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Tue, 23 Dec 2025 15:01:36 -0300
Subject: [PATCH v3 16/21] drm/mediatek: gamma: Support CRTC color pipeline
 API
In-Reply-To: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
References: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
Message-ID: <20251223-mtk-post-blend-color-pipeline-v3-16-7d969f9a37a0@collabora.com>

From: "N?colas F. R. A. Prado" <nfraprado at collabora.com>

Implement the gamma_set_color_pipeline DDP component function to allow
configuring the gamma LUT through the CRTC color pipeline API.

The color pipeline API uses a 32-bit long, rather than 16-bit long, LUT,
so also update the functions to handle both cases.

Also make sure to enable or disable the LUT function depending on
whether the block should be bypassed or not.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
Co-developed-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Signed-off-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_ddp_comp.c   |  3 +-
 drivers/gpu/drm/mediatek/mtk_disp_drv.h   |  3 +-
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 68 +++++++++++++++++++++++--------
 3 files changed, 54 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index 69eeb36609584..cf456ab3cf70f 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -327,7 +327,8 @@ static const struct mtk_ddp_comp_funcs ddp_gamma = {
 	.clk_enable = mtk_gamma_clk_enable,
 	.clk_disable = mtk_gamma_clk_disable,
 	.gamma_get_lut_size = mtk_gamma_get_lut_size,
-	.gamma_set = mtk_gamma_set,
+	.gamma_set = mtk_gamma_set_legacy,
+	.gamma_set_color_pipeline = mtk_gamma_set_color_pipeline,
 	.config = mtk_gamma_config,
 	.start = mtk_gamma_start,
 	.stop = mtk_gamma_stop,
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index ac84cf579150f..7795aa5bc057f 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -58,7 +58,8 @@ void mtk_gamma_config(struct device *dev, unsigned int w,
 		      unsigned int h, unsigned int vrefresh,
 		      unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
 unsigned int mtk_gamma_get_lut_size(struct device *dev);
-void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state);
+void mtk_gamma_set_legacy(struct device *dev, struct drm_crtc_state *state);
+void mtk_gamma_set_color_pipeline(struct device *dev, struct drm_color_lut32 *lut);
 void mtk_gamma_start(struct device *dev);
 void mtk_gamma_stop(struct device *dev);
 
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index 8afd15006df2a..efda0bbb0b09d 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -87,13 +87,17 @@ unsigned int mtk_gamma_get_lut_size(struct device *dev)
 	return 0;
 }
 
-static bool mtk_gamma_lut_is_descending(struct drm_color_lut *lut, u32 lut_size)
+static bool mtk_gamma_lut_is_descending(void *lut, bool bits32, u32 lut_size)
 {
 	u64 first, last;
 	int last_entry = lut_size - 1;
+	struct drm_color_lut32 lut_first, lut_last;
 
-	first = lut[0].red + lut[0].green + lut[0].blue;
-	last = lut[last_entry].red + lut[last_entry].green + lut[last_entry].blue;
+	drm_color_lut_to_lut32(&lut_first, lut, 0, bits32);
+	drm_color_lut_to_lut32(&lut_last, lut, last_entry, bits32);
+
+	first = lut_first.red + lut_first.green + lut_first.blue;
+	last = lut_last.red + lut_last.green + lut_last.blue;
 
 	return !!(first > last);
 }
@@ -113,7 +117,7 @@ static bool mtk_gamma_lut_is_descending(struct drm_color_lut *lut, u32 lut_size)
  *     - 12-bits LUT supported
  *     - 10-its LUT not supported
  */
-void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state)
+static void mtk_gamma_set(struct device *dev, void *lut, bool bits32)
 {
 	struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
 	void __iomem *lut0_base = gamma->regs + DISP_GAMMA_LUT;
@@ -121,15 +125,9 @@ void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state)
 	u32 cfg_val, data_mode, lbank_val, word[2];
 	u8 lut_bits = gamma->data->lut_bits;
 	int cur_bank, num_lut_banks;
-	struct drm_color_lut *lut;
 	unsigned int i;
 
-	/* If there's no gamma lut there's nothing to do here. */
-	if (!state->gamma_lut)
-		return;
-
 	num_lut_banks = gamma->data->lut_size / gamma->data->lut_bank_size;
-	lut = (struct drm_color_lut *)state->gamma_lut->data;
 
 	/* Switch to 12 bits data mode if supported */
 	data_mode = FIELD_PREP(DISP_GAMMA_BANK_DATA_MODE, !!(lut_bits == 12));
@@ -145,11 +143,13 @@ void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state)
 
 		for (i = 0; i < gamma->data->lut_bank_size; i++) {
 			int n = cur_bank * gamma->data->lut_bank_size + i;
-			struct drm_color_lut diff, hwlut;
+			struct drm_color_lut32 diff, hwlut, lut32;
+
+			drm_color_lut_to_lut32(&lut32, lut, n, bits32);
 
-			hwlut.red = drm_color_lut_extract(lut[n].red, lut_bits);
-			hwlut.green = drm_color_lut_extract(lut[n].green, lut_bits);
-			hwlut.blue = drm_color_lut_extract(lut[n].blue, lut_bits);
+			hwlut.red = drm_color_lut_extract(lut32.red, lut_bits);
+			hwlut.green = drm_color_lut_extract(lut32.green, lut_bits);
+			hwlut.blue = drm_color_lut_extract(lut32.blue, lut_bits);
 
 			if (!gamma->data->lut_diff || (i % 2 == 0)) {
 				if (lut_bits == 12) {
@@ -162,13 +162,17 @@ void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state)
 					word[0] |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, hwlut.blue);
 				}
 			} else {
-				diff.red = lut[n].red - lut[n - 1].red;
+				struct drm_color_lut32 lut_prev;
+
+				drm_color_lut_to_lut32(&lut_prev, lut, n-1, bits32);
+
+				diff.red = lut32.red - lut_prev.red;
 				diff.red = drm_color_lut_extract(diff.red, lut_bits);
 
-				diff.green = lut[n].green - lut[n - 1].green;
+				diff.green = lut32.green - lut_prev.green;
 				diff.green = drm_color_lut_extract(diff.green, lut_bits);
 
-				diff.blue = lut[n].blue - lut[n - 1].blue;
+				diff.blue = lut32.blue - lut_prev.blue;
 				diff.blue = drm_color_lut_extract(diff.blue, lut_bits);
 
 				if (lut_bits == 12) {
@@ -191,7 +195,7 @@ void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state)
 
 	if (!gamma->data->has_dither) {
 		/* Descending or Rising LUT */
-		if (mtk_gamma_lut_is_descending(lut, gamma->data->lut_size - 1))
+		if (mtk_gamma_lut_is_descending(lut, bits32, gamma->data->lut_size - 1))
 			cfg_val |= FIELD_PREP(GAMMA_LUT_TYPE, 1);
 		else
 			cfg_val &= ~GAMMA_LUT_TYPE;
@@ -206,6 +210,34 @@ void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state)
 	writel(cfg_val, gamma->regs + DISP_GAMMA_CFG);
 }
 
+void mtk_gamma_set_legacy(struct device *dev, struct drm_crtc_state *state)
+{
+	struct drm_color_lut *lut = (struct drm_color_lut *)state->gamma_lut->data;
+
+	/* If there's no gamma lut there's nothing to do here. */
+	if (!state->gamma_lut)
+		return;
+
+	mtk_gamma_set(dev, lut, false);
+}
+
+void mtk_gamma_set_color_pipeline(struct device *dev, struct drm_color_lut32 *lut)
+{
+	struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
+	u32 cfg_val;
+
+	/* Configure block to be bypassed */
+	if (!lut) {
+		cfg_val = readl(gamma->regs + DISP_GAMMA_CFG);
+		cfg_val &= ~GAMMA_LUT_EN;
+		cfg_val |= GAMMA_RELAY_MODE;
+		writel(cfg_val, gamma->regs + DISP_GAMMA_CFG);
+		return;
+	}
+
+	mtk_gamma_set(dev, lut, true);
+}
+
 void mtk_gamma_config(struct device *dev, unsigned int w,
 		      unsigned int h, unsigned int vrefresh,
 		      unsigned int bpc, struct cmdq_pkt *cmdq_pkt)

-- 
2.51.0



From ariel.dalessandro at collabora.com  Tue Dec 23 10:01:37 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Tue, 23 Dec 2025 15:01:37 -0300
Subject: [PATCH v3 17/21] drm/mediatek: Set CRTC color pipeline driver cap
In-Reply-To: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
References: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
Message-ID: <20251223-mtk-post-blend-color-pipeline-v3-17-7d969f9a37a0@collabora.com>

From: "N?colas F. R. A. Prado" <nfraprado at collabora.com>

Now that the driver implements CRTC (post-blend) color pipelines, set
the driver cap so they can be used from userspace.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
Co-developed-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Signed-off-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
---
 drivers/gpu/drm/mediatek/mtk_drm_drv.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index a94c51a832616..554b310ca11a5 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -613,7 +613,8 @@ static struct drm_gem_object *mtk_gem_prime_import(struct drm_device *dev,
 }
 
 static const struct drm_driver mtk_drm_driver = {
-	.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
+	.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC |
+			   DRIVER_CRTC_COLOR_PIPELINE,
 
 	.dumb_create = mtk_gem_dumb_create,
 	DRM_FBDEV_DMA_DRIVER_OPS,

-- 
2.51.0



From ariel.dalessandro at collabora.com  Tue Dec 23 10:01:38 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Tue, 23 Dec 2025 15:01:38 -0300
Subject: [PATCH v3 18/21] drm/vkms: Rename existing color pipeline helpers
 to contain "plane"
In-Reply-To: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
References: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
Message-ID: <20251223-mtk-post-blend-color-pipeline-v3-18-7d969f9a37a0@collabora.com>

From: "N?colas F. R. A. Prado" <nfraprado at collabora.com>

Rename the existing color pipeline helpers so they contain "plane" in
the name to make them clearly distinguishable from the crtc helpers when
they're introduced.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
Co-developed-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Signed-off-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
---
 drivers/gpu/drm/vkms/vkms_colorop.c | 7 ++++---
 drivers/gpu/drm/vkms/vkms_drv.h     | 2 +-
 drivers/gpu/drm/vkms/vkms_plane.c   | 2 +-
 3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_colorop.c b/drivers/gpu/drm/vkms/vkms_colorop.c
index 5c3ffc78aea06..dd6120434690e 100644
--- a/drivers/gpu/drm/vkms/vkms_colorop.c
+++ b/drivers/gpu/drm/vkms/vkms_colorop.c
@@ -14,7 +14,8 @@ static const u64 supported_tfs =
 
 #define MAX_COLOR_PIPELINE_OPS 4
 
-static int vkms_initialize_color_pipeline(struct drm_plane *plane, struct drm_prop_enum_list *list)
+static int vkms_initialize_plane_color_pipeline(struct drm_plane *plane,
+						struct drm_prop_enum_list *list)
 {
 	struct drm_colorop *ops[MAX_COLOR_PIPELINE_OPS];
 	struct drm_device *dev = plane->dev;
@@ -101,13 +102,13 @@ static int vkms_initialize_color_pipeline(struct drm_plane *plane, struct drm_pr
 	return ret;
 }
 
-int vkms_initialize_colorops(struct drm_plane *plane)
+int vkms_initialize_plane_colorops(struct drm_plane *plane)
 {
 	struct drm_prop_enum_list pipeline;
 	int ret;
 
 	/* Add color pipeline */
-	ret = vkms_initialize_color_pipeline(plane, &pipeline);
+	ret = vkms_initialize_plane_color_pipeline(plane, &pipeline);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
index 0933e4ce0ff03..bdeb52623f4d6 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.h
+++ b/drivers/gpu/drm/vkms/vkms_drv.h
@@ -324,6 +324,6 @@ void vkms_writeback_row(struct vkms_writeback_job *wb, const struct line_buffer
 int vkms_enable_writeback_connector(struct vkms_device *vkmsdev, struct vkms_output *vkms_out);
 
 /* Colorops */
-int vkms_initialize_colorops(struct drm_plane *plane);
+int vkms_initialize_plane_colorops(struct drm_plane *plane);
 
 #endif /* _VKMS_DRV_H_ */
diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c
index 19fe6acad306e..82be1b862c1da 100644
--- a/drivers/gpu/drm/vkms/vkms_plane.c
+++ b/drivers/gpu/drm/vkms/vkms_plane.c
@@ -247,7 +247,7 @@ struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
 					  DRM_COLOR_YCBCR_FULL_RANGE);
 
 	if (vkms_config_plane_get_default_pipeline(plane_cfg))
-		vkms_initialize_colorops(&plane->base);
+		vkms_initialize_plane_colorops(&plane->base);
 
 	return plane;
 }

-- 
2.51.0



From ariel.dalessandro at collabora.com  Tue Dec 23 10:01:39 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Tue, 23 Dec 2025 15:01:39 -0300
Subject: [PATCH v3 19/21] drm/vkms: Prepare pre_blend_color_transform() for
 CRTC color pipelines
In-Reply-To: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
References: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
Message-ID: <20251223-mtk-post-blend-color-pipeline-v3-19-7d969f9a37a0@collabora.com>

From: "N?colas F. R. A. Prado" <nfraprado at collabora.com>

As a preparatory step for supporting CRTC (post-blend) color pipelines
in VKMS, rename pre_blend_color_transform() to color_transform() and
make it take the first colorop instead of a plane state, so it can be
shared by both plane (pre-blend) and CRTC (post-blend) color pipeline
code paths.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
Reviewed-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
---
 drivers/gpu/drm/vkms/vkms_composer.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c
index 3cf3f26e0d8ea..d4f87a2aa3359 100644
--- a/drivers/gpu/drm/vkms/vkms_composer.c
+++ b/drivers/gpu/drm/vkms/vkms_composer.c
@@ -189,13 +189,13 @@ static void apply_colorop(struct pixel_argb_s32 *pixel, struct drm_colorop *colo
 	}
 }
 
-static void pre_blend_color_transform(const struct vkms_plane_state *plane_state,
-				      struct line_buffer *output_buffer)
+static void color_transform(struct drm_colorop *first_colorop,
+			    struct line_buffer *output_buffer)
 {
 	struct pixel_argb_s32 pixel;
 
 	for (size_t x = 0; x < output_buffer->n_pixels; x++) {
-		struct drm_colorop *colorop = plane_state->base.base.color_pipeline;
+		struct drm_colorop *colorop = first_colorop;
 
 		/*
 		 * Some operations, such as applying a BT709 encoding matrix,
@@ -449,7 +449,7 @@ static void blend_line(struct vkms_plane_state *current_plane, int y,
 	 */
 	current_plane->pixel_read_line(current_plane, src_x_start, src_y_start, direction,
 				       pixel_count, &stage_buffer->pixels[dst_x_start]);
-	pre_blend_color_transform(current_plane, stage_buffer);
+	color_transform(current_plane->base.base.color_pipeline, stage_buffer);
 	pre_mul_alpha_blend(stage_buffer, output_buffer,
 			    dst_x_start, pixel_count);
 }

-- 
2.51.0



From ariel.dalessandro at collabora.com  Tue Dec 23 10:01:40 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Tue, 23 Dec 2025 15:01:40 -0300
Subject: [PATCH v3 20/21] drm/vkms: Introduce support for post-blend color
 pipeline
In-Reply-To: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
References: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
Message-ID: <20251223-mtk-post-blend-color-pipeline-v3-20-7d969f9a37a0@collabora.com>

From: "N?colas F. R. A. Prado" <nfraprado at collabora.com>

Introduce a post-blend color pipeline with the same colorop blocks as
the pre-blend color pipeline.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
Co-developed-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Signed-off-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
---
 drivers/gpu/drm/vkms/tests/vkms_config_test.c |  70 ++++++++++-------
 drivers/gpu/drm/vkms/vkms_colorop.c           | 103 ++++++++++++++++++++++++++
 drivers/gpu/drm/vkms/vkms_composer.c          |   5 +-
 drivers/gpu/drm/vkms/vkms_config.c            |   5 +-
 drivers/gpu/drm/vkms/vkms_config.h            |  29 +++++++-
 drivers/gpu/drm/vkms/vkms_crtc.c              |   6 +-
 drivers/gpu/drm/vkms/vkms_drv.c               |   7 +-
 drivers/gpu/drm/vkms/vkms_drv.h               |   6 +-
 drivers/gpu/drm/vkms/vkms_output.c            |   3 +-
 9 files changed, 202 insertions(+), 32 deletions(-)

diff --git a/drivers/gpu/drm/vkms/tests/vkms_config_test.c b/drivers/gpu/drm/vkms/tests/vkms_config_test.c
index 1e4ea1863420f..ec1d84ae508ad 100644
--- a/drivers/gpu/drm/vkms/tests/vkms_config_test.c
+++ b/drivers/gpu/drm/vkms/tests/vkms_config_test.c
@@ -84,6 +84,7 @@ struct default_config_case {
 	bool enable_writeback;
 	bool enable_overlay;
 	bool enable_plane_pipeline;
+	bool enable_crtc_pipeline;
 };
 
 static void vkms_config_test_empty_config(struct kunit *test)
@@ -109,22 +110,38 @@ static void vkms_config_test_empty_config(struct kunit *test)
 }
 
 static struct default_config_case default_config_cases[] = {
-	{ false, false, false, false },
-	{ true, false, false, false },
-	{ true, true, false, false },
-	{ true, false, true, false },
-	{ false, true, false, false },
-	{ false, true, true, false },
-	{ false, false, true, false },
-	{ true, true, true, false },
-	{ false, false, false, true },
-	{ true, false, false, true },
-	{ true, true, false, true },
-	{ true, false, true, true },
-	{ false, true, false, true },
-	{ false, true, true, true },
-	{ false, false, true, true },
-	{ true, true, true, true },
+	{ false, false, false, false, false },
+	{ true, false, false, false, false },
+	{ true, true, false, false, false },
+	{ true, false, true, false, false },
+	{ false, true, false, false, false },
+	{ false, true, true, false, false },
+	{ false, false, true, false, false },
+	{ true, true, true, false, false },
+	{ false, false, false, true, false },
+	{ true, false, false, true, false },
+	{ true, true, false, true, false },
+	{ true, false, true, true, false },
+	{ false, true, false, true, false },
+	{ false, true, true, true, false },
+	{ false, false, true, true, false },
+	{ true, true, true, true, false },
+	{ false, false, false, false, true },
+	{ true, false, false, false, true },
+	{ true, true, false, false, true },
+	{ true, false, true, false, true },
+	{ false, true, false, false, true },
+	{ false, true, true, false, true },
+	{ false, false, true, false, true },
+	{ true, true, true, false, true },
+	{ false, false, false, true, true },
+	{ true, false, false, true, true },
+	{ true, true, false, true, true },
+	{ true, false, true, true, true },
+	{ false, true, false, true, true },
+	{ false, true, true, true, true },
+	{ false, false, true, true, true },
+	{ true, true, true, true, true },
 };
 
 KUNIT_ARRAY_PARAM(default_config, default_config_cases, NULL);
@@ -142,7 +159,8 @@ static void vkms_config_test_default_config(struct kunit *test)
 	config = vkms_config_default_create(params->enable_cursor,
 					    params->enable_writeback,
 					    params->enable_overlay,
-					    params->enable_plane_pipeline);
+					    params->enable_plane_pipeline,
+					    params->enable_crtc_pipeline);
 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
 
 	/* Planes */
@@ -174,6 +192,8 @@ static void vkms_config_test_default_config(struct kunit *test)
 	crtc_cfg = get_first_crtc(config);
 	KUNIT_EXPECT_EQ(test, vkms_config_crtc_get_writeback(crtc_cfg),
 			params->enable_writeback);
+	KUNIT_EXPECT_EQ(test, vkms_config_crtc_get_default_pipeline(crtc_cfg),
+			params->enable_crtc_pipeline);
 
 	vkms_config_for_each_plane(config, plane_cfg) {
 		struct vkms_config_crtc *possible_crtc;
@@ -381,7 +401,7 @@ static void vkms_config_test_invalid_plane_number(struct kunit *test)
 	struct vkms_config_plane *plane_cfg;
 	int n;
 
-	config = vkms_config_default_create(false, false, false, false);
+	config = vkms_config_default_create(false, false, false, false, false);
 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
 
 	/* Invalid: No planes */
@@ -406,7 +426,7 @@ static void vkms_config_test_valid_plane_type(struct kunit *test)
 	struct vkms_config_encoder *encoder_cfg;
 	int err;
 
-	config = vkms_config_default_create(false, false, false, false);
+	config = vkms_config_default_create(false, false, false, false, false);
 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
 
 	plane_cfg = get_first_plane(config);
@@ -487,7 +507,7 @@ static void vkms_config_test_valid_plane_possible_crtcs(struct kunit *test)
 	struct vkms_config_plane *plane_cfg;
 	struct vkms_config_crtc *crtc_cfg;
 
-	config = vkms_config_default_create(false, false, false, false);
+	config = vkms_config_default_create(false, false, false, false, false);
 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
 
 	plane_cfg = get_first_plane(config);
@@ -506,7 +526,7 @@ static void vkms_config_test_invalid_crtc_number(struct kunit *test)
 	struct vkms_config_crtc *crtc_cfg;
 	int n;
 
-	config = vkms_config_default_create(false, false, false, false);
+	config = vkms_config_default_create(false, false, false, false, false);
 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
 
 	/* Invalid: No CRTCs */
@@ -529,7 +549,7 @@ static void vkms_config_test_invalid_encoder_number(struct kunit *test)
 	struct vkms_config_encoder *encoder_cfg;
 	int n;
 
-	config = vkms_config_default_create(false, false, false, false);
+	config = vkms_config_default_create(false, false, false, false, false);
 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
 
 	/* Invalid: No encoders */
@@ -554,7 +574,7 @@ static void vkms_config_test_valid_encoder_possible_crtcs(struct kunit *test)
 	struct vkms_config_encoder *encoder_cfg;
 	int err;
 
-	config = vkms_config_default_create(false, false, false, false);
+	config = vkms_config_default_create(false, false, false, false, false);
 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
 
 	crtc_cfg1 = get_first_crtc(config);
@@ -600,7 +620,7 @@ static void vkms_config_test_invalid_connector_number(struct kunit *test)
 	struct vkms_config_connector *connector_cfg;
 	int n;
 
-	config = vkms_config_default_create(false, false, false, false);
+	config = vkms_config_default_create(false, false, false, false, false);
 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
 
 	/* Invalid: No connectors */
@@ -623,7 +643,7 @@ static void vkms_config_test_valid_connector_possible_encoders(struct kunit *tes
 	struct vkms_config_encoder *encoder_cfg;
 	struct vkms_config_connector *connector_cfg;
 
-	config = vkms_config_default_create(false, false, false, false);
+	config = vkms_config_default_create(false, false, false, false, false);
 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
 
 	encoder_cfg = get_first_encoder(config);
diff --git a/drivers/gpu/drm/vkms/vkms_colorop.c b/drivers/gpu/drm/vkms/vkms_colorop.c
index dd6120434690e..6c4a6cb186564 100644
--- a/drivers/gpu/drm/vkms/vkms_colorop.c
+++ b/drivers/gpu/drm/vkms/vkms_colorop.c
@@ -102,6 +102,91 @@ static int vkms_initialize_plane_color_pipeline(struct drm_plane *plane,
 	return ret;
 }
 
+static int vkms_initialize_crtc_color_pipeline(struct drm_crtc *crtc,
+					       struct drm_prop_enum_list *list)
+{
+	struct drm_colorop *ops[MAX_COLOR_PIPELINE_OPS];
+	struct drm_device *dev = crtc->dev;
+	int ret;
+	int i = 0, j = 0;
+
+	memset(ops, 0, sizeof(ops));
+
+	/* 1st op: 1d curve */
+	ops[i] = kzalloc(sizeof(*ops[i]), GFP_KERNEL);
+	if (!ops[i]) {
+		ret = -ENOMEM;
+		goto cleanup;
+	}
+
+	ret = drm_crtc_colorop_curve_1d_init(dev, ops[i], crtc, supported_tfs,
+					     DRM_COLOROP_FLAG_ALLOW_BYPASS);
+	if (ret)
+		goto err_colorop_init;
+
+	list->type = ops[i]->base.id;
+	list->name = kasprintf(GFP_KERNEL, "Color Pipeline %d", ops[i]->base.id);
+
+	i++;
+
+	/* 2nd op: 3x4 matrix */
+	ops[i] = kzalloc(sizeof(*ops[i]), GFP_KERNEL);
+	if (!ops[i]) {
+		ret = -ENOMEM;
+		goto cleanup;
+	}
+
+	ret = drm_crtc_colorop_ctm_3x4_init(dev, ops[i], crtc, DRM_COLOROP_FLAG_ALLOW_BYPASS);
+	if (ret)
+		goto err_colorop_init;
+
+	drm_colorop_set_next_property(ops[i - 1], ops[i]);
+
+	i++;
+
+	/* 3rd op: 3x4 matrix */
+	ops[i] = kzalloc(sizeof(*ops[i]), GFP_KERNEL);
+	if (!ops[i]) {
+		ret = -ENOMEM;
+		goto cleanup;
+	}
+
+	ret = drm_crtc_colorop_ctm_3x4_init(dev, ops[i], crtc, DRM_COLOROP_FLAG_ALLOW_BYPASS);
+	if (ret)
+		goto err_colorop_init;
+
+	drm_colorop_set_next_property(ops[i - 1], ops[i]);
+
+	i++;
+
+	/* 4th op: 1d curve */
+	ops[i] = kzalloc(sizeof(*ops[i]), GFP_KERNEL);
+	if (!ops[i]) {
+		ret = -ENOMEM;
+		goto cleanup;
+	}
+
+	ret = drm_crtc_colorop_curve_1d_init(dev, ops[i], crtc, supported_tfs,
+					     DRM_COLOROP_FLAG_ALLOW_BYPASS);
+	if (ret)
+		goto err_colorop_init;
+
+	drm_colorop_set_next_property(ops[i - 1], ops[i]);
+
+	return 0;
+
+err_colorop_init:
+	kfree(ops[i]);
+
+cleanup:
+	for (j = 0; j < i; j++) {
+		drm_colorop_cleanup(ops[j]);
+		kfree(ops[j]);
+	}
+
+	return ret;
+}
+
 int vkms_initialize_plane_colorops(struct drm_plane *plane)
 {
 	struct drm_prop_enum_list pipeline;
@@ -119,3 +204,21 @@ int vkms_initialize_plane_colorops(struct drm_plane *plane)
 
 	return 0;
 }
+
+int vkms_initialize_crtc_colorops(struct drm_crtc *crtc)
+{
+	struct drm_prop_enum_list pipeline;
+	int ret;
+
+	/* Add color pipeline */
+	ret = vkms_initialize_crtc_color_pipeline(crtc, &pipeline);
+	if (ret)
+		return ret;
+
+	/* Create COLOR_PIPELINE property and attach */
+	ret = drm_crtc_create_color_pipeline_property(crtc, &pipeline, 1);
+	if (ret)
+		return ret;
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c
index d4f87a2aa3359..621f008b165a6 100644
--- a/drivers/gpu/drm/vkms/vkms_composer.c
+++ b/drivers/gpu/drm/vkms/vkms_composer.c
@@ -495,7 +495,10 @@ static void blend(struct vkms_writeback_job *wb,
 			blend_line(plane[i], y, crtc_x_limit, stage_buffer, output_buffer);
 		}
 
-		apply_lut(crtc_state, output_buffer);
+		if (crtc_state->base.color_pipeline_enabled)
+			color_transform(crtc_state->base.color_pipeline, output_buffer);
+		else
+			apply_lut(crtc_state, output_buffer);
 
 		*crc32 = crc32_le(*crc32, (void *)output_buffer->pixels, row_size);
 
diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 8788df9edb7ca..a65c3638eff4d 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -34,7 +34,8 @@ EXPORT_SYMBOL_IF_KUNIT(vkms_config_create);
 struct vkms_config *vkms_config_default_create(bool enable_cursor,
 					       bool enable_writeback,
 					       bool enable_overlay,
-					       bool enable_plane_pipeline)
+					       bool enable_plane_pipeline,
+					       bool enable_crtc_pipeline)
 {
 	struct vkms_config *config;
 	struct vkms_config_plane *plane_cfg;
@@ -56,6 +57,7 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor,
 	if (IS_ERR(crtc_cfg))
 		goto err_alloc;
 	vkms_config_crtc_set_writeback(crtc_cfg, enable_writeback);
+	vkms_config_crtc_set_default_pipeline(crtc_cfg, enable_crtc_pipeline);
 
 	if (vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg))
 		goto err_alloc;
@@ -454,6 +456,7 @@ struct vkms_config_crtc *vkms_config_create_crtc(struct vkms_config *config)
 
 	crtc_cfg->config = config;
 	vkms_config_crtc_set_writeback(crtc_cfg, false);
+	vkms_config_crtc_set_default_pipeline(crtc_cfg, false);
 
 	list_add_tail(&crtc_cfg->link, &config->crtcs);
 
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index 8f7f286a4bdd7..e12e4065f01f0 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -61,6 +61,7 @@ struct vkms_config_plane {
  * @link: Link to the others CRTCs in vkms_config
  * @config: The vkms_config this CRTC belongs to
  * @writeback: If true, a writeback buffer can be attached to the CRTC
+ * @default_pipeline: If true, CRTC will be created with the default pipeline.
  * @crtc: Internal usage. This pointer should never be considered as valid.
  *        It can be used to store a temporary reference to a VKMS CRTC during
  *        device creation. This pointer is not managed by the configuration and
@@ -71,6 +72,7 @@ struct vkms_config_crtc {
 	struct vkms_config *config;
 
 	bool writeback;
+	bool default_pipeline;
 
 	/* Internal usage */
 	struct vkms_output *crtc;
@@ -205,7 +207,8 @@ struct vkms_config *vkms_config_create(const char *dev_name);
 struct vkms_config *vkms_config_default_create(bool enable_cursor,
 					       bool enable_writeback,
 					       bool enable_overlay,
-					       bool enable_plane_pipeline);
+					       bool enable_plane_pipeline,
+					       bool enable_crtc_pipeline);
 
 /**
  * vkms_config_destroy() - Free a VKMS configuration
@@ -314,6 +317,30 @@ vkms_config_plane_set_default_pipeline(struct vkms_config_plane *plane_cfg,
 	plane_cfg->default_pipeline = default_pipeline;
 }
 
+/**
+ * vkms_config_crtc_get_default_pipeline() - Return if the CRTC will
+ * be created with the default pipeline
+ * @crtc_cfg: CRTC to get the information from
+ */
+static inline bool
+vkms_config_crtc_get_default_pipeline(struct vkms_config_crtc *crtc_cfg)
+{
+	return crtc_cfg->default_pipeline;
+}
+
+/**
+ * vkms_config_crtc_set_default_pipeline() - Set if the CRTC will
+ * be created with the default pipeline
+ * @crtc_cfg: CRTC to configure the pipeline
+ * @default_pipeline: New default pipeline value
+ */
+static inline void
+vkms_config_crtc_set_default_pipeline(struct vkms_config_crtc *crtc_cfg,
+				      bool default_pipeline)
+{
+	crtc_cfg->default_pipeline = default_pipeline;
+}
+
 /**
  * vkms_config_plane_attach_crtc - Attach a plane to a CRTC
  * @plane_cfg: Plane to attach
diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c
index 9a7db1d510222..60c372c0ce2d8 100644
--- a/drivers/gpu/drm/vkms/vkms_crtc.c
+++ b/drivers/gpu/drm/vkms/vkms_crtc.c
@@ -10,6 +10,7 @@
 #include <drm/drm_vblank.h>
 #include <drm/drm_vblank_helper.h>
 
+#include "vkms_config.h"
 #include "vkms_drv.h"
 
 static bool vkms_crtc_handle_vblank_timeout(struct drm_crtc *crtc)
@@ -202,7 +203,7 @@ static const struct drm_crtc_helper_funcs vkms_crtc_helper_funcs = {
 };
 
 struct vkms_output *vkms_crtc_init(struct drm_device *dev, struct drm_plane *primary,
-				   struct drm_plane *cursor)
+				   struct drm_plane *cursor, struct vkms_config_crtc *crtc_cfg)
 {
 	struct vkms_output *vkms_out;
 	struct drm_crtc *crtc;
@@ -228,6 +229,9 @@ struct vkms_output *vkms_crtc_init(struct drm_device *dev, struct drm_plane *pri
 
 	drm_crtc_enable_color_mgmt(crtc, 0, false, VKMS_LUT_SIZE);
 
+	if (vkms_config_crtc_get_default_pipeline(crtc_cfg))
+		vkms_initialize_crtc_colorops(crtc);
+
 	spin_lock_init(&vkms_out->lock);
 	spin_lock_init(&vkms_out->composer_lock);
 
diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
index dd1402f437736..39195540fe2b1 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.c
+++ b/drivers/gpu/drm/vkms/vkms_drv.c
@@ -55,6 +55,10 @@ static bool enable_plane_pipeline;
 module_param_named(enable_plane_pipeline, enable_plane_pipeline, bool, 0444);
 MODULE_PARM_DESC(enable_plane_pipeline, "Enable/Disable plane pipeline support");
 
+static bool enable_crtc_pipeline;
+module_param_named(enable_crtc_pipeline, enable_crtc_pipeline, bool, 0444);
+MODULE_PARM_DESC(enable_crtc_pipeline, "Enable/Disable CRTC pipeline support");
+
 static bool create_default_dev = true;
 module_param_named(create_default_dev, create_default_dev, bool, 0444);
 MODULE_PARM_DESC(create_default_dev, "Create or not the default VKMS device");
@@ -232,7 +236,8 @@ static int __init vkms_init(void)
 		return 0;
 
 	config = vkms_config_default_create(enable_cursor, enable_writeback,
-					    enable_overlay, enable_plane_pipeline);
+					    enable_overlay, enable_plane_pipeline,
+					    enable_crtc_pipeline);
 	if (IS_ERR(config))
 		return PTR_ERR(config);
 
diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
index bdeb52623f4d6..1688c885f2285 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.h
+++ b/drivers/gpu/drm/vkms/vkms_drv.h
@@ -229,6 +229,7 @@ struct vkms_output {
 };
 
 struct vkms_config;
+struct vkms_config_crtc;
 struct vkms_config_plane;
 
 /**
@@ -287,10 +288,12 @@ void vkms_destroy(struct vkms_config *config);
  * @crtc: uninitialized CRTC device
  * @primary: primary plane to attach to the CRTC
  * @cursor: plane to attach to the CRTC
+ * @crtc_cfg: CRTC configuration
  */
 struct vkms_output *vkms_crtc_init(struct drm_device *dev,
 				   struct drm_plane *primary,
-				   struct drm_plane *cursor);
+				   struct drm_plane *cursor,
+				   struct vkms_config_crtc *crtc_cfg);
 
 /**
  * vkms_output_init() - Initialize all sub-components needed for a VKMS device.
@@ -325,5 +328,6 @@ int vkms_enable_writeback_connector(struct vkms_device *vkmsdev, struct vkms_out
 
 /* Colorops */
 int vkms_initialize_plane_colorops(struct drm_plane *plane);
+int vkms_initialize_crtc_colorops(struct drm_crtc *crtc);
 
 #endif /* _VKMS_DRV_H_ */
diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
index 86ce07a617f52..a0856ba90ac24 100644
--- a/drivers/gpu/drm/vkms/vkms_output.c
+++ b/drivers/gpu/drm/vkms/vkms_output.c
@@ -34,7 +34,8 @@ int vkms_output_init(struct vkms_device *vkmsdev)
 		cursor = vkms_config_crtc_cursor_plane(vkmsdev->config, crtc_cfg);
 
 		crtc_cfg->crtc = vkms_crtc_init(dev, &primary->plane->base,
-						cursor ? &cursor->plane->base : NULL);
+						cursor ? &cursor->plane->base : NULL,
+						crtc_cfg);
 		if (IS_ERR(crtc_cfg->crtc)) {
 			DRM_ERROR("Failed to allocate CRTC\n");
 			return PTR_ERR(crtc_cfg->crtc);

-- 
2.51.0



From ariel.dalessandro at collabora.com  Tue Dec 23 10:01:41 2025
From: ariel.dalessandro at collabora.com (Ariel D'Alessandro)
Date: Tue, 23 Dec 2025 15:01:41 -0300
Subject: [PATCH v3 21/21] drm/vkms: Set CRTC color pipeline driver cap
In-Reply-To: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
References: <20251223-mtk-post-blend-color-pipeline-v3-0-7d969f9a37a0@collabora.com>
Message-ID: <20251223-mtk-post-blend-color-pipeline-v3-21-7d969f9a37a0@collabora.com>

From: "N?colas F. R. A. Prado" <nfraprado at collabora.com>

Now that the driver implements CRTC (post-blend) color pipelines, set
the driver cap so they can be used from userspace.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
Co-developed-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Signed-off-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Reviewed-by: Louis Chauvet <louis.chauvet at bootlin.com>
---
 drivers/gpu/drm/vkms/vkms_drv.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
index 39195540fe2b1..62cd36c805e45 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.c
+++ b/drivers/gpu/drm/vkms/vkms_drv.c
@@ -94,7 +94,8 @@ static void vkms_atomic_commit_tail(struct drm_atomic_state *old_state)
 }
 
 static const struct drm_driver vkms_driver = {
-	.driver_features	= DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM,
+	.driver_features	= DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM |
+				  DRIVER_CRTC_COLOR_PIPELINE,
 	.fops			= &vkms_driver_fops,
 	DRM_GEM_SHMEM_DRIVER_OPS,
 	DRM_FBDEV_SHMEM_DRIVER_OPS,

-- 
2.51.0



From namhyung at kernel.org  Tue Dec 23 10:11:06 2025
From: namhyung at kernel.org (Namhyung Kim)
Date: Tue, 23 Dec 2025 10:11:06 -0800
Subject: [PATCH 08/11] tools headers: Sync arm64 headers with kernel
 sources
In-Reply-To: <20251223153648.GG9788@e132581.arm.com>
References: <20251222225716.3565649-1-namhyung@kernel.org>
 <20251222225716.3565649-8-namhyung@kernel.org>
 <20251223153648.GG9788@e132581.arm.com>
Message-ID: <aUrbOlBwdLFTMjH1@google.com>

Hi Leo,

On Tue, Dec 23, 2025 at 03:36:48PM +0000, Leo Yan wrote:
> Hi Namhyung,
> 
> On Mon, Dec 22, 2025 at 02:57:13PM -0800, Namhyung Kim wrote:
> 
> [...]
> 
> >  #define NVIDIA_CPU_PART_DENVER		0x003
> >  #define NVIDIA_CPU_PART_CARMEL		0x004
> > +#define NVIDIA_CPU_PART_OLYMPUS		0x010
> 
> Just remind, this is duplicated with patch [1], so you may decide
> which one to pick for merging.

Oh, thanks for the reminder.  I've missed it.  I think it's small enough
to merge to perf-tools tree.  I'll drop this part.

> 
> Otherwise, LGTM:
> 
> Reviewed-by: Leo Yan <leo.yan at arm.com>

Thanks,
Namhyung



From willemdebruijn.kernel at gmail.com  Tue Dec 23 11:01:11 2025
From: willemdebruijn.kernel at gmail.com (Willem de Bruijn)
Date: Tue, 23 Dec 2025 14:01:11 -0500
Subject: [PATCH] net: fix segmentation of forwarding fraglist GRO
In-Reply-To: <aab6c515-12e4-48ca-8220-c0797dae781f@redhat.com>
References: <20251217035548.8104-1-jibin.zhang@mediatek.com>
 <aab6c515-12e4-48ca-8220-c0797dae781f@redhat.com>
Message-ID: <willemdebruijn.kernel.2633c480125d5@gmail.com>

Paolo Abeni wrote:
> On 12/17/25 4:55 AM, Jibin Zhang wrote:
> > This patch enhances GSO segment checks by verifying the presence
> > of frag_list and protocol consistency, addressing low throughput
> > issues on IPv4 servers when used as hotspots
> > 
> > Specifically, it fixes a bug in GSO segmentation when forwarding
> > GRO packets with frag_list. The function skb_segment_list cannot
> > correctly process GRO skbs converted by XLAT, because XLAT only
> > converts the header of the head skb. As a result, skbs in the
> > frag_list may remain unconverted, leading to protocol
> > inconsistencies and reduced throughput.
> > 
> > To resolve this, the patch uses skb_segment to handle forwarded
> > packets converted by XLAT, ensuring that all fragments are
> > properly converted and segmented.
> > 
> > Signed-off-by: Jibin Zhang <jibin.zhang at mediatek.com>
> 
> This looks like a fix, it should target the 'net' tree and include a
> suitable Fixes tag.
> 
> > ---
> >  net/ipv4/tcp_offload.c | 3 ++-
> >  net/ipv4/udp_offload.c | 3 ++-
> >  2 files changed, 4 insertions(+), 2 deletions(-)
> > 
> > diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c
> > index fdda18b1abda..162a384a15bb 100644
> > --- a/net/ipv4/tcp_offload.c
> > +++ b/net/ipv4/tcp_offload.c
> > @@ -104,7 +104,8 @@ static struct sk_buff *tcp4_gso_segment(struct sk_buff *skb,
> >  	if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
> >  		return ERR_PTR(-EINVAL);
> >  
> > -	if (skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST) {
> > +	if ((skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST) && skb_has_frag_list(skb) &&
> > +	    (skb->protocol == skb_shinfo(skb)->frag_list->protocol)) {
> >  		struct tcphdr *th = tcp_hdr(skb);

Using fraglist gso on a system that modifies packet headers is a known
bad idea. I guess this was not anticipated when the feature was added.
But we've seen plenty of examples with BPF already before.

This skb->protocol change is only one of a variety of ways that the
headers may end up mismatching.

It's not bad to bandaid it and fall back onto regular GSO.

But it seems like we'll continue to have to play whack-a-mole unless
we find a more fundamental solution. E.g., disabling fraglist GRO when
such a path is detected, or downgrade an skb to non-fraglist in paths
like this XLAT.


> >  
> >  		if (skb_pagelen(skb) - th->doff * 4 == skb_shinfo(skb)->gso_size)
> > diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
> > index 19d0b5b09ffa..704fb32d10d7 100644
> > --- a/net/ipv4/udp_offload.c
> > +++ b/net/ipv4/udp_offload.c
> > @@ -512,7 +512,8 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
> >  		return NULL;
> >  	}
> >  
> > -	if (skb_shinfo(gso_skb)->gso_type & SKB_GSO_FRAGLIST) {
> > +	if ((skb_shinfo(gso_skb)->gso_type & SKB_GSO_FRAGLIST) && skb_has_frag_list(gso_skb) &&
> > +	    (gso_skb->protocol == skb_shinfo(gso_skb)->frag_list->protocol)) {
> >  		 /* Detect modified geometry and pass those to skb_segment. */
> >  		if (skb_pagelen(gso_skb) - sizeof(*uh) == skb_shinfo(gso_skb)->gso_size)
> >  			return __udp_gso_segment_list(gso_skb, features, is_ipv6);
> 
> I guess checks should be needed for ipv6.
> 
> Also it looks like this skips the CSUM_PARTIAL preparation, and possibly
> break csum offload.
> 
> Additionally I don't like the ever increasing stack of hacks needed to
> let GSO_FRAGLIST operate in the most diverse setups, the simpler fix
> would be disabling such aggregation.
> 
> /P
> 




From riel at surriel.com  Tue Dec 23 11:24:33 2025
From: riel at surriel.com (Rik van Riel)
Date: Tue, 23 Dec 2025 14:24:33 -0500
Subject: [PATCH 1/2] arm64: efi: Fix NULL pointer dereference by
 initializing user_ns
In-Reply-To: <20251223-efi_fix_619-v1-1-e0146b8b9d73@debian.org>
References: <20251223-efi_fix_619-v1-0-e0146b8b9d73@debian.org>
	 <20251223-efi_fix_619-v1-1-e0146b8b9d73@debian.org>
Message-ID: <a060d8ec023cb7b8dbec0cb4105d03fb24c57a3d.camel@surriel.com>

On Tue, 2025-12-23 at 02:55 -0800, Breno Leitao wrote:
> 
> diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
> index a9070d00b833..55452e61af31 100644
> --- a/drivers/firmware/efi/efi.c
> +++ b/drivers/firmware/efi/efi.c
> @@ -73,6 +73,7 @@ struct mm_struct efi_mm = {
> ?	MMAP_LOCK_INITIALIZER(efi_mm)
> ?	.page_table_lock	=
> __SPIN_LOCK_UNLOCKED(efi_mm.page_table_lock),
> ?	.mmlist			=
> LIST_HEAD_INIT(efi_mm.mmlist),
> +	.user_ns		= &init_user_ns,
> ?	.cpu_bitmap		= { [BITS_TO_LONGS(NR_CPUS)] = 0},
> ?#ifdef CONFIG_SCHED_MM_CID
> ?	.mm_cid.lock		=
> __RAW_SPIN_LOCK_UNLOCKED(efi_mm.mm_cid.lock),

Seems legit?

Acked-by: Rik van Riel <riel at surriel.com>

-- 
All Rights Reversed.


From riel at surriel.com  Tue Dec 23 11:31:32 2025
From: riel at surriel.com (Rik van Riel)
Date: Tue, 23 Dec 2025 14:31:32 -0500
Subject: [PATCH 2/2] kthread: Warn if mm_struct lacks user_ns in
 kthread_use_mm()
In-Reply-To: <20251223-efi_fix_619-v1-2-e0146b8b9d73@debian.org>
References: <20251223-efi_fix_619-v1-0-e0146b8b9d73@debian.org>
	 <20251223-efi_fix_619-v1-2-e0146b8b9d73@debian.org>
Message-ID: <4d867df02dcc3cc8f519903282f6e63b2974a461.camel@surriel.com>

On Tue, 2025-12-23 at 02:55 -0800, Breno Leitao wrote:
> Add a WARN_ON_ONCE() check to detect mm_struct instances that are
> missing user_ns initialization when passed to kthread_use_mm().
> 
> When a kthread adopts an mm via kthread_use_mm(), LSM hooks and
> capability checks may access current->mm->user_ns for credential
> validation. If user_ns is NULL, this leads to a NULL pointer
> dereference crash.
> 
> This was observed with efi_mm on arm64, where commit a5baf582f4c0
> ("arm64/efi: Call EFI runtime services without disabling preemption")
> introduced kthread_use_mm(&efi_mm), but efi_mm lacked user_ns
> initialization, causing crashes during /proc access.
> 
> Adding this warning helps catch similar bugs early during development
> rather than waiting for hard-to-debug NULL pointer crashes in
> production.
> 
> Signed-off-by: Breno Leitao <leitao at debian.org>

Acked-by: Rik van Riel <riel at surriel.com>

-- 
All Rights Reversed.


From pekangas at google.com  Tue Dec 23 11:34:39 2025
From: pekangas at google.com (Petteri Kangaslampi)
Date: Tue, 23 Dec 2025 19:34:39 +0000
Subject: [PATCH 0/1] KVM: arm64: Fix hyp VA size between layout and MMU
Message-ID: <20251223193440.1441657-1-pekangas@google.com>

All,

In the KVM initialization code, kvm_mmu_init() and
kvm_compute_layout() use different logic when determining the
hypervisor's virtual address space size. Specifically, the MMU code
uses the larger of vabits_actual (the kernel's VA size) and
IDMAP_VA_BITS (48 bits), while the VA layout code just uses the
kernel's VA size.

This means that if the kernel is configured with a VA size of less
than 48 bits (like happens in our environment), the assumptions used
to calculate hyp_physvirt_offset and the code that determines VA
ranges to use for mappings in hyp/nvhe/mm.c get out of sync, which can
results in mapping failures.

The immediate fix is pretty obvious and attached here. This is against
6.12 but I don't think this code has changed recently. I think longer
term refactoring knowledge of the hypervisor's address space into one
place might be helpful; currently it is a bit spread out.

Petteri Kangaslampi (1):
  KVM: arm64: Fix hyp VA size between layout and MMU

 arch/arm64/kvm/va_layout.c | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

-- 
2.52.0.351.gbe84eed79e-goog



From pekangas at google.com  Tue Dec 23 11:34:40 2025
From: pekangas at google.com (Petteri Kangaslampi)
Date: Tue, 23 Dec 2025 19:34:40 +0000
Subject: [PATCH 1/1] KVM: arm64: Fix hyp VA size between layout and MMU
In-Reply-To: <20251223193440.1441657-1-pekangas@google.com>
References: <20251223193440.1441657-1-pekangas@google.com>
Message-ID: <20251223193440.1441657-2-pekangas@google.com>

Use a consistent hypervisor VA size between memory layout and MMU
initialization logic when the kernel is configured for less than
IDMAP_VA_BITS of VA space.

Signed-off-by: Petteri Kangaslampi <pekangas at google.com>
---
 arch/arm64/kvm/va_layout.c | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/kvm/va_layout.c b/arch/arm64/kvm/va_layout.c
index f6ca0193a96f..76cdd62550e1 100644
--- a/arch/arm64/kvm/va_layout.c
+++ b/arch/arm64/kvm/va_layout.c
@@ -49,7 +49,7 @@ static void init_hyp_physvirt_offset(void)
 
 /*
  * We want to generate a hyp VA with the following format (with V ==
- * vabits_actual):
+ * hypervisor VA bits):
  *
  *  63 ... V |     V-1    | V-2 .. tag_lsb | tag_lsb - 1 .. 0
  *  ---------------------------------------------------------
@@ -62,10 +62,17 @@ __init void kvm_compute_layout(void)
 {
 	phys_addr_t idmap_addr = __pa_symbol(__hyp_idmap_text_start);
 	u64 hyp_va_msb;
+	u32 hyp_va_bits;
+
+	/*
+	 * We use the bigger of IDMAP_VA_BITS and kernel VA size as the
+	 * hypervisor VA address space size. See mmu.c.
+	 */
+	hyp_va_bits = max(IDMAP_VA_BITS, vabits_actual);
 
 	/* Where is my RAM region? */
-	hyp_va_msb  = idmap_addr & BIT(vabits_actual - 1);
-	hyp_va_msb ^= BIT(vabits_actual - 1);
+	hyp_va_msb  = idmap_addr & BIT(hyp_va_bits - 1);
+	hyp_va_msb ^= BIT(hyp_va_bits - 1);
 
 	tag_lsb = fls64((u64)phys_to_virt(memblock_start_of_DRAM()) ^
 			(u64)(high_memory - 1));
@@ -73,9 +80,9 @@ __init void kvm_compute_layout(void)
 	va_mask = GENMASK_ULL(tag_lsb - 1, 0);
 	tag_val = hyp_va_msb;
 
-	if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && tag_lsb != (vabits_actual - 1)) {
+	if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && tag_lsb != (hyp_va_bits - 1)) {
 		/* We have some free bits to insert a random tag. */
-		tag_val |= get_random_long() & GENMASK_ULL(vabits_actual - 2, tag_lsb);
+		tag_val |= get_random_long() & GENMASK_ULL(hyp_va_bits - 2, tag_lsb);
 	}
 	tag_val >>= tag_lsb;
 
-- 
2.52.0.351.gbe84eed79e-goog



From nfraprado at collabora.com  Tue Dec 23 11:44:41 2025
From: nfraprado at collabora.com (=?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?=)
Date: Tue, 23 Dec 2025 16:44:41 -0300
Subject: [PATCH 00/11] Plane Color Pipeline support for MediaTek
Message-ID: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>

This series implements a plane color pipeline for MediaTek platforms,
specifically for MT8195-compatible SoCs.

The pipeline is composed of the following blocks:

Inverse Gamma -> RGB to RGB Color Space Conversion (R2R CSC) -> Gamma
(1D Curve)       (3x3 Matrix)                                   (1D Curve) 

The curves supported by Inverse Gamma are:
* scRGB
* BT.709

The curves supported by Gamma are:
* scRGB
* BT.709
* BT.2020
* HLG

Given the lack of support for writeback connectors on the MediaTek KMS
driver, combined with limited hardware documentation, I haven't been
able to verify the correctness of each curve, only that they were
visually sane (gamma curves made the image on the display brighter,
while inverse gamma made it darker).

This series depends on "drm: Color pipeline teardown and follow-up
fixes/improvements" [1].

This series was tested on the MT8195-Tomato Chromebook.

Regarding the support of color operations in OVL for different SoCs:
* it's not supported by MT8183, and presumably also not by older
  generations
* On MT8192 it's supported by ovl0 and ovl_2l0, but not ovl_2l2 (despite
  the same compatible as ovl_2l0).

For this series I'm only enabling it on MT8195 since that's the one
where I can readily test.

[1] https://lore.kernel.org/all/20251219065614.190834-1-chaitanya.kumar.borah at intel.com/#t

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
---
N?colas F. R. A. Prado (11):
      drm/mediatek: Introduce DDP plane_colorops_init() hook
      drm/mediatek: Initialize colorops when creating plane
      drm/mediatek: ovl: Add supports_plane_colorops flag
      drm/mediatek: ovl: Enable per-plane color operations on MT8195
      drm/mediatek: ovl: Implement support for Inverse Gamma
      drm/mediatek: Add plane_colorops_init() DDP hook for OVL
      drm/colorop: Introduce HLG EOTF
      drm/mediatek: ovl: Implement support for Gamma
      drm/colorop: Introduce 3x3 Matrix
      drm/mediatek: ovl: Enable support for R2R Color Space Conversion
      drm/mediatek: Check 3x3 Matrix colorop has DATA set

 drivers/gpu/drm/drm_atomic.c            |   1 +
 drivers/gpu/drm/drm_atomic_uapi.c       |   3 +
 drivers/gpu/drm/drm_colorop.c           |  22 +++
 drivers/gpu/drm/mediatek/mtk_crtc.c     |  36 +++-
 drivers/gpu/drm/mediatek/mtk_ddp_comp.c |   1 +
 drivers/gpu/drm/mediatek/mtk_ddp_comp.h |   2 +
 drivers/gpu/drm/mediatek/mtk_disp_drv.h |   1 +
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 287 ++++++++++++++++++++++++++++++++
 include/drm/drm_colorop.h               |  13 ++
 include/uapi/drm/drm_mode.h             |  16 ++
 10 files changed, 381 insertions(+), 1 deletion(-)
---
base-commit: 1783cdadb70e74a30dfee250f8c2dc13b4e61128
change-id: 20251219-mtk-ovl-pre-blend-colorops-95b7b2883d95

Best regards,
-- 
N?colas F. R. A. Prado <nfraprado at collabora.com>



From nfraprado at collabora.com  Tue Dec 23 11:44:42 2025
From: nfraprado at collabora.com (=?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?=)
Date: Tue, 23 Dec 2025 16:44:42 -0300
Subject: [PATCH 01/11] drm/mediatek: Introduce DDP plane_colorops_init()
 hook
In-Reply-To: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
References: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
Message-ID: <20251223-mtk-ovl-pre-blend-colorops-v1-1-0cb99bd0ab33@collabora.com>

Introduce a plane_colorops_init() hook to allow DDP components to define
how to initialize the color pipeline on their planes.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_ddp_comp.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
index 99bf1e1015da..3a7393b7f4c9 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
@@ -13,6 +13,7 @@
 #include <linux/soc/mediatek/mtk-mutex.h>
 
 #include <drm/drm_modes.h>
+#include <drm/drm_plane.h>
 
 struct device;
 struct device_node;
@@ -86,6 +87,7 @@ struct mtk_ddp_comp_funcs {
 	const u32 *(*get_formats)(struct device *dev);
 	size_t (*get_num_formats)(struct device *dev);
 	bool (*is_afbc_supported)(struct device *dev);
+	int (*plane_colorops_init)(struct device *dev, struct drm_plane *plane);
 	void (*connect)(struct device *dev, struct device *mmsys_dev, unsigned int next);
 	void (*disconnect)(struct device *dev, struct device *mmsys_dev, unsigned int next);
 	void (*add)(struct device *dev, struct mtk_mutex *mutex);

-- 
2.51.0



From nfraprado at collabora.com  Tue Dec 23 11:44:43 2025
From: nfraprado at collabora.com (=?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?=)
Date: Tue, 23 Dec 2025 16:44:43 -0300
Subject: [PATCH 02/11] drm/mediatek: Initialize colorops when creating
 plane
In-Reply-To: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
References: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
Message-ID: <20251223-mtk-ovl-pre-blend-colorops-v1-2-0cb99bd0ab33@collabora.com>

During initialization of a plane, if the DDP component supplying it
defines a plane_colorops_init() hook, call it to initialize the color
pipeline on the plane.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_crtc.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c b/drivers/gpu/drm/mediatek/mtk_crtc.c
index 22f255c3ddd3..f7db235d986f 100644
--- a/drivers/gpu/drm/mediatek/mtk_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_crtc.c
@@ -985,8 +985,10 @@ static int mtk_crtc_init_comp_planes(struct drm_device *drm_dev,
 	int i, ret;
 
 	for (i = 0; i < num_planes; i++) {
+		struct drm_plane *plane = &mtk_crtc->planes[mtk_crtc->layer_nr];
+
 		ret = mtk_plane_init(drm_dev,
-				&mtk_crtc->planes[mtk_crtc->layer_nr],
+				plane,
 				BIT(pipe),
 				mtk_crtc_plane_type(mtk_crtc->layer_nr, num_planes),
 				mtk_ddp_comp_supported_rotations(comp),
@@ -997,6 +999,12 @@ static int mtk_crtc_init_comp_planes(struct drm_device *drm_dev,
 		if (ret)
 			return ret;
 
+		if (comp->funcs && comp->funcs->plane_colorops_init) {
+			ret = comp->funcs->plane_colorops_init(comp->dev, plane);
+			if (ret)
+				return ret;
+		}
+
 		mtk_crtc->layer_nr++;
 	}
 	return 0;

-- 
2.51.0



From nfraprado at collabora.com  Tue Dec 23 11:44:44 2025
From: nfraprado at collabora.com (=?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?=)
Date: Tue, 23 Dec 2025 16:44:44 -0300
Subject: [PATCH 03/11] drm/mediatek: ovl: Add supports_plane_colorops flag
In-Reply-To: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
References: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
Message-ID: <20251223-mtk-ovl-pre-blend-colorops-v1-3-0cb99bd0ab33@collabora.com>

Add a supports_plane_colorops flag to the driver data to allow SoCs that
support per-plane color operations to enable support for it in the
driver.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index 8e20b45411fc..46238c21b0ac 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -150,6 +150,7 @@ struct mtk_disp_ovl_data {
 	const u32 *formats;
 	size_t num_formats;
 	bool supports_clrfmt_ext;
+	bool supports_plane_colorops;
 };
 
 /*

-- 
2.51.0



From nfraprado at collabora.com  Tue Dec 23 11:44:45 2025
From: nfraprado at collabora.com (=?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?=)
Date: Tue, 23 Dec 2025 16:44:45 -0300
Subject: [PATCH 04/11] drm/mediatek: ovl: Enable per-plane color operations
 on MT8195
In-Reply-To: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
References: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
Message-ID: <20251223-mtk-ovl-pre-blend-colorops-v1-4-0cb99bd0ab33@collabora.com>

MT8195's OVL hardware supports per-plane color operations. Enable
support for it in the driver.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index 46238c21b0ac..cfc6a3154f73 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -738,6 +738,7 @@ static const struct mtk_disp_ovl_data mt8195_ovl_driver_data = {
 	.fmt_rgb565_is_0 = true,
 	.smi_id_en = true,
 	.supports_afbc = true,
+	.supports_plane_colorops = true,
 	.blend_modes = BIT(DRM_MODE_BLEND_PREMULTI) |
 		       BIT(DRM_MODE_BLEND_COVERAGE) |
 		       BIT(DRM_MODE_BLEND_PIXEL_NONE),

-- 
2.51.0



From nfraprado at collabora.com  Tue Dec 23 11:44:46 2025
From: nfraprado at collabora.com (=?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?=)
Date: Tue, 23 Dec 2025 16:44:46 -0300
Subject: [PATCH 05/11] drm/mediatek: ovl: Implement support for Inverse
 Gamma
In-Reply-To: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
References: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
Message-ID: <20251223-mtk-ovl-pre-blend-colorops-v1-5-0cb99bd0ab33@collabora.com>

The OVL hardware allows selecting between different fixed transfer
functions for each layer through the Inverse Gamma setting. Available
functions are scRGB and BT.709. Implement support for it and expose it
as a colorop through the DRM plane color pipeline uAPI.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_disp_drv.h |   1 +
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 169 ++++++++++++++++++++++++++++++++
 2 files changed, 170 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index e0c30c6c7cc8..fde31e3fcc4a 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -115,6 +115,7 @@ void mtk_ovl_disable_vblank(struct device *dev);
 u32 mtk_ovl_get_blend_modes(struct device *dev);
 const u32 *mtk_ovl_get_formats(struct device *dev);
 size_t mtk_ovl_get_num_formats(struct device *dev);
+int mtk_ovl_plane_colorops_init(struct device *dev, struct drm_plane *plane);
 bool mtk_ovl_is_afbc_supported(struct device *dev);
 
 void mtk_ovl_adaptor_add_comp(struct device *dev, struct mtk_mutex *mutex);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index cfc6a3154f73..4eaa31541ccc 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -4,8 +4,11 @@
  */
 
 #include <drm/drm_blend.h>
+#include <drm/drm_colorop.h>
 #include <drm/drm_fourcc.h>
 #include <drm/drm_framebuffer.h>
+#include <drm/drm_mode.h>
+#include <drm/drm_print.h>
 
 #include <linux/clk.h>
 #include <linux/component.h>
@@ -47,6 +50,12 @@
 #define OVL_CON_CLRFMT_BIT_DEPTH(depth, n)		((depth) << (4 * (n)))
 #define OVL_CON_CLRFMT_8_BIT				(0)
 #define OVL_CON_CLRFMT_10_BIT				(1)
+#define DISP_REG_OVL_WCG_CFG1			0x2d8
+#define IGAMMA_EN(layer)				BIT(0 + 4 * (layer))
+#define DISP_REG_OVL_WCG_CFG2			0x2dc
+#define IGAMMA_MASK(layer)				GENMASK((layer) * 4 + 1, (layer) * 4)
+#define IGAMMA_SCRGB					0
+#define IGAMMA_BT709					1
 #define DISP_REG_OVL_ADDR_MT8173		0x0f40
 #define DISP_REG_OVL_ADDR(ovl, n)		((ovl)->data->addr + 0x20 * (n))
 #define DISP_REG_OVL_HDR_ADDR(ovl, n)		((ovl)->data->addr + 0x20 * (n) + 0x04)
@@ -492,6 +501,91 @@ static void mtk_ovl_afbc_layer_config(struct mtk_disp_ovl *ovl,
 	}
 }
 
+static int mtk_ovl_colorop_curve_to_reg_val(enum drm_colorop_curve_1d_type curve)
+{
+	switch (curve) {
+	case DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF:
+		return IGAMMA_SCRGB;
+	case DRM_COLOROP_1D_CURVE_BT2020_OETF:
+		return IGAMMA_BT709;
+	default:
+		return -EINVAL;
+	}
+}
+
+static void mtk_ovl_apply_igamma(struct mtk_disp_ovl *ovl, unsigned int idx,
+				 struct drm_colorop *colorop,
+				 struct cmdq_pkt *cmdq_pkt)
+{
+	int curve_reg_val;
+
+	if (colorop->state->bypass) {
+		/* igamma curve needs to be set to default when igamma is disabled */
+		curve_reg_val = IGAMMA_SCRGB;
+	} else {
+		curve_reg_val = mtk_ovl_colorop_curve_to_reg_val(colorop->state->curve_1d_type);
+		if (curve_reg_val < 0) {
+			drm_WARN(ovl->crtc->dev, 1,
+				 "Invalid curve 1d type %u\n",
+				 colorop->state->curve_1d_type);
+			return;
+		}
+	}
+
+	mtk_ddp_write_mask(cmdq_pkt,
+			   field_prep(IGAMMA_MASK(idx), curve_reg_val),
+			   &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_WCG_CFG2,
+			   IGAMMA_MASK(idx));
+
+	mtk_ddp_write_mask(cmdq_pkt,
+			   colorop->state->bypass ? 0 : IGAMMA_EN(idx),
+			   &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_WCG_CFG1,
+			   IGAMMA_EN(idx));
+}
+
+static void mtk_ovl_apply_colorop(struct mtk_disp_ovl *ovl, unsigned int idx,
+				  struct drm_colorop *colorop,
+				  struct cmdq_pkt *cmdq_pkt)
+{
+	switch (colorop->type) {
+	case DRM_COLOROP_1D_CURVE:
+		mtk_ovl_apply_igamma(ovl, idx, colorop, cmdq_pkt);
+		break;
+	default:
+		drm_WARN(ovl->crtc->dev, 1, "Invalid colorop type %u\n", colorop->type);
+		break;
+	}
+}
+
+static void mtk_ovl_disable_colorops(struct mtk_disp_ovl *ovl, unsigned int idx,
+				     struct cmdq_pkt *cmdq_pkt)
+{
+	mtk_ddp_write_mask(cmdq_pkt, 0, &ovl->cmdq_reg, ovl->regs,
+			   DISP_REG_OVL_WCG_CFG1,
+			   IGAMMA_EN(idx));
+
+	/* igamma curve needs to be set to default when igamma is disabled */
+	mtk_ddp_write_mask(cmdq_pkt, IGAMMA_SCRGB, &ovl->cmdq_reg, ovl->regs,
+			   DISP_REG_OVL_WCG_CFG2, IGAMMA_MASK(idx));
+}
+
+static void mtk_ovl_apply_colorops(struct mtk_disp_ovl *ovl, unsigned int idx,
+				   struct mtk_plane_state *state,
+				   struct cmdq_pkt *cmdq_pkt)
+{
+	if (!ovl->data->supports_plane_colorops)
+		return;
+
+	if (!state->base.color_pipeline) {
+		mtk_ovl_disable_colorops(ovl, idx, cmdq_pkt);
+		return;
+	}
+
+	for (struct drm_colorop *colorop = state->base.color_pipeline; colorop;
+	     colorop = colorop->next)
+		mtk_ovl_apply_colorop(ovl, idx, colorop, cmdq_pkt);
+}
+
 void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
 			  struct mtk_plane_state *state,
 			  struct cmdq_pkt *cmdq_pkt)
@@ -513,6 +607,8 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
 		return;
 	}
 
+	mtk_ovl_apply_colorops(ovl, idx, state, cmdq_pkt);
+
 	con = mtk_ovl_fmt_convert(ovl, state);
 	if (state->base.fb) {
 		con |= state->base.alpha & OVL_CON_ALPHA;
@@ -593,6 +689,79 @@ void mtk_ovl_bgclr_in_off(struct device *dev)
 	writel(reg, ovl->regs + DISP_REG_OVL_DATAPATH_CON);
 }
 
+static const struct drm_colorop_funcs mtk_ovl_colorop_funcs = {
+	.destroy = drm_colorop_destroy,
+};
+
+static const u64 igamma_supported_tfs =
+	BIT(DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF) |
+	BIT(DRM_COLOROP_1D_CURVE_BT2020_OETF);
+
+#define MAX_COLOR_PIPELINE_OPS 3
+
+static int
+mtk_ovl_initialize_plane_color_pipeline(struct drm_plane *plane,
+					struct drm_prop_enum_list *pipeline)
+{
+	struct drm_colorop *ops[MAX_COLOR_PIPELINE_OPS];
+	struct drm_device *dev = plane->dev;
+	int i = 0;
+	int ret;
+
+	memset(ops, 0, sizeof(ops));
+
+	/* 1st op: OVL's Inverse Gamma */
+	ops[i] = kzalloc(sizeof(*ops[i]), GFP_KERNEL);
+	if (!ops[i]) {
+		ret = -ENOMEM;
+		goto err_alloc;
+	}
+
+	ret = drm_plane_colorop_curve_1d_init(dev, ops[i], plane,
+					      &mtk_ovl_colorop_funcs,
+					      igamma_supported_tfs,
+					      DRM_COLOROP_FLAG_ALLOW_BYPASS);
+	if (ret)
+		goto err_colorop_init;
+
+	pipeline->type = ops[0]->base.id;
+	pipeline->name = kasprintf(GFP_KERNEL, "Color Pipeline %d", ops[0]->base.id);
+
+	return 0;
+
+err_colorop_init:
+	kfree(ops[i]);
+
+err_alloc:
+	i--;
+	for (; i >= 0; i--) {
+		drm_colorop_cleanup(ops[i]);
+		kfree(ops[i]);
+	}
+
+	return ret;
+}
+
+int mtk_ovl_plane_colorops_init(struct device *dev, struct drm_plane *plane)
+{
+	struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
+	struct drm_prop_enum_list pipeline = {};
+	int ret;
+
+	if (!ovl->data->supports_plane_colorops)
+		return 0;
+
+	ret = mtk_ovl_initialize_plane_color_pipeline(plane, &pipeline);
+	if (ret)
+		return ret;
+
+	ret = drm_plane_create_color_pipeline_property(plane, &pipeline, 1);
+
+	kfree(pipeline.name);
+
+	return ret;
+}
+
 static int mtk_disp_ovl_bind(struct device *dev, struct device *master,
 			     void *data)
 {

-- 
2.51.0



From nfraprado at collabora.com  Tue Dec 23 11:44:47 2025
From: nfraprado at collabora.com (=?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?=)
Date: Tue, 23 Dec 2025 16:44:47 -0300
Subject: [PATCH 06/11] drm/mediatek: Add plane_colorops_init() DDP hook for
 OVL
In-Reply-To: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
References: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
Message-ID: <20251223-mtk-ovl-pre-blend-colorops-v1-6-0cb99bd0ab33@collabora.com>

Hook OVL's plane colorops initialization function in DDP to allow its
usage by the MediaTek KMS driver.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index 94b356da6de7..ef906b2aff74 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -331,6 +331,7 @@ static const struct mtk_ddp_comp_funcs ddp_ovl = {
 	.get_formats = mtk_ovl_get_formats,
 	.get_num_formats = mtk_ovl_get_num_formats,
 	.is_afbc_supported = mtk_ovl_is_afbc_supported,
+	.plane_colorops_init = mtk_ovl_plane_colorops_init,
 };
 
 static const struct mtk_ddp_comp_funcs ddp_postmask = {

-- 
2.51.0



From nfraprado at collabora.com  Tue Dec 23 11:44:48 2025
From: nfraprado at collabora.com (=?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?=)
Date: Tue, 23 Dec 2025 16:44:48 -0300
Subject: [PATCH 07/11] drm/colorop: Introduce HLG EOTF
In-Reply-To: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
References: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
Message-ID: <20251223-mtk-ovl-pre-blend-colorops-v1-7-0cb99bd0ab33@collabora.com>

Introduce definition of a hybrid log-gamma electro-optical transfer
function for 1D Curve colorops.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
---
 drivers/gpu/drm/drm_colorop.c |  1 +
 include/drm/drm_colorop.h     | 10 ++++++++++
 2 files changed, 11 insertions(+)

diff --git a/drivers/gpu/drm/drm_colorop.c b/drivers/gpu/drm/drm_colorop.c
index fafe45b93ff8..a19e03fb9c7c 100644
--- a/drivers/gpu/drm/drm_colorop.c
+++ b/drivers/gpu/drm/drm_colorop.c
@@ -79,6 +79,7 @@ static const char * const colorop_curve_1d_type_names[] = {
 	[DRM_COLOROP_1D_CURVE_BT2020_OETF] = "BT.2020 OETF",
 	[DRM_COLOROP_1D_CURVE_GAMMA22] = "Gamma 2.2",
 	[DRM_COLOROP_1D_CURVE_GAMMA22_INV] = "Gamma 2.2 Inverse",
+	[DRM_COLOROP_1D_CURVE_HLG_EOTF] = "HLG",
 };
 
 static const struct drm_prop_enum_list drm_colorop_lut1d_interpolation_list[] = {
diff --git a/include/drm/drm_colorop.h b/include/drm/drm_colorop.h
index ee6454b08b2d..8ec98521607d 100644
--- a/include/drm/drm_colorop.h
+++ b/include/drm/drm_colorop.h
@@ -126,6 +126,16 @@ enum drm_colorop_curve_1d_type {
 	 * The inverse of &DRM_COLOROP_1D_CURVE_GAMMA22
 	 */
 	DRM_COLOROP_1D_CURVE_GAMMA22_INV,
+
+	/**
+	 * @DRM_COLOROP_1D_CURVE_HLG_EOTF:
+	 *
+	 * enum string "HLG"
+	 *
+	 * Hybrid log-gamma transfer function.
+	 */
+	DRM_COLOROP_1D_CURVE_HLG_EOTF,
+
 	/**
 	 * @DRM_COLOROP_1D_CURVE_COUNT:
 	 *

-- 
2.51.0



From nfraprado at collabora.com  Tue Dec 23 11:44:49 2025
From: nfraprado at collabora.com (=?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?=)
Date: Tue, 23 Dec 2025 16:44:49 -0300
Subject: [PATCH 08/11] drm/mediatek: ovl: Implement support for Gamma
In-Reply-To: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
References: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
Message-ID: <20251223-mtk-ovl-pre-blend-colorops-v1-8-0cb99bd0ab33@collabora.com>

The OVL hardware allows selecting between different fixed transfer
functions for each layer through the Gamma setting. Available
functions are scRGB, BT.709, BT.2020 and HLG. Implement support for it
and expose it as a colorop through the DRM plane color pipeline uAPI.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 67 ++++++++++++++++++++++++++++++++-
 1 file changed, 65 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index 4eaa31541ccc..a70092c792a9 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -52,10 +52,16 @@
 #define OVL_CON_CLRFMT_10_BIT				(1)
 #define DISP_REG_OVL_WCG_CFG1			0x2d8
 #define IGAMMA_EN(layer)				BIT(0 + 4 * (layer))
+#define GAMMA_EN(layer)					BIT(2 + 4 * (layer))
 #define DISP_REG_OVL_WCG_CFG2			0x2dc
 #define IGAMMA_MASK(layer)				GENMASK((layer) * 4 + 1, (layer) * 4)
 #define IGAMMA_SCRGB					0
 #define IGAMMA_BT709					1
+#define GAMMA_MASK(layer)				GENMASK((layer) * 4 + 3, (layer) * 4 + 2)
+#define GAMMA_SCRGB					0
+#define GAMMA_BT709					1
+#define GAMMA_BT2020					2
+#define GAMMA_HLG					3
 #define DISP_REG_OVL_ADDR_MT8173		0x0f40
 #define DISP_REG_OVL_ADDR(ovl, n)		((ovl)->data->addr + 0x20 * (n))
 #define DISP_REG_OVL_HDR_ADDR(ovl, n)		((ovl)->data->addr + 0x20 * (n) + 0x04)
@@ -508,11 +514,41 @@ static int mtk_ovl_colorop_curve_to_reg_val(enum drm_colorop_curve_1d_type curve
 		return IGAMMA_SCRGB;
 	case DRM_COLOROP_1D_CURVE_BT2020_OETF:
 		return IGAMMA_BT709;
+	case DRM_COLOROP_1D_CURVE_SRGB_EOTF:
+		return GAMMA_SCRGB;
+	case DRM_COLOROP_1D_CURVE_BT2020_INV_OETF:
+		return GAMMA_BT2020;
+	case DRM_COLOROP_1D_CURVE_HLG_EOTF:
+		return GAMMA_HLG;
 	default:
 		return -EINVAL;
 	}
 }
 
+static void mtk_ovl_apply_gamma(struct mtk_disp_ovl *ovl, unsigned int idx,
+				struct drm_colorop *colorop,
+				struct cmdq_pkt *cmdq_pkt)
+{
+	int curve_reg_val;
+
+	curve_reg_val = mtk_ovl_colorop_curve_to_reg_val(colorop->state->curve_1d_type);
+	if (curve_reg_val < 0) {
+		drm_WARN(ovl->crtc->dev, 1, "Invalid curve 1d type %u\n",
+			 colorop->state->curve_1d_type);
+		return;
+	}
+
+	mtk_ddp_write_mask(cmdq_pkt,
+			   field_prep(GAMMA_MASK(idx), curve_reg_val),
+			   &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_WCG_CFG2,
+			   GAMMA_MASK(idx));
+
+	mtk_ddp_write_mask(cmdq_pkt,
+			   colorop->state->bypass ? 0 : GAMMA_EN(idx),
+			   &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_WCG_CFG1,
+			   GAMMA_EN(idx));
+}
+
 static void mtk_ovl_apply_igamma(struct mtk_disp_ovl *ovl, unsigned int idx,
 				 struct drm_colorop *colorop,
 				 struct cmdq_pkt *cmdq_pkt)
@@ -549,7 +585,11 @@ static void mtk_ovl_apply_colorop(struct mtk_disp_ovl *ovl, unsigned int idx,
 {
 	switch (colorop->type) {
 	case DRM_COLOROP_1D_CURVE:
-		mtk_ovl_apply_igamma(ovl, idx, colorop, cmdq_pkt);
+		/* gamma is the last colorop in pipeline */
+		if (!colorop->next)
+			mtk_ovl_apply_gamma(ovl, idx, colorop, cmdq_pkt);
+		else
+			mtk_ovl_apply_igamma(ovl, idx, colorop, cmdq_pkt);
 		break;
 	default:
 		drm_WARN(ovl->crtc->dev, 1, "Invalid colorop type %u\n", colorop->type);
@@ -562,7 +602,7 @@ static void mtk_ovl_disable_colorops(struct mtk_disp_ovl *ovl, unsigned int idx,
 {
 	mtk_ddp_write_mask(cmdq_pkt, 0, &ovl->cmdq_reg, ovl->regs,
 			   DISP_REG_OVL_WCG_CFG1,
-			   IGAMMA_EN(idx));
+			   IGAMMA_EN(idx) | GAMMA_EN(idx));
 
 	/* igamma curve needs to be set to default when igamma is disabled */
 	mtk_ddp_write_mask(cmdq_pkt, IGAMMA_SCRGB, &ovl->cmdq_reg, ovl->regs,
@@ -697,6 +737,11 @@ static const u64 igamma_supported_tfs =
 	BIT(DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF) |
 	BIT(DRM_COLOROP_1D_CURVE_BT2020_OETF);
 
+static const u64 gamma_supported_tfs =
+	BIT(DRM_COLOROP_1D_CURVE_SRGB_EOTF) |
+	BIT(DRM_COLOROP_1D_CURVE_BT2020_INV_OETF) |
+	BIT(DRM_COLOROP_1D_CURVE_HLG_EOTF);
+
 #define MAX_COLOR_PIPELINE_OPS 3
 
 static int
@@ -724,6 +769,24 @@ mtk_ovl_initialize_plane_color_pipeline(struct drm_plane *plane,
 	if (ret)
 		goto err_colorop_init;
 
+	i++;
+
+	/* 3rd op: OVL's Gamma */
+	ops[i] = kzalloc(sizeof(*ops[i]), GFP_KERNEL);
+	if (!ops[i]) {
+		ret = -ENOMEM;
+		goto err_alloc;
+	}
+
+	ret = drm_plane_colorop_curve_1d_init(dev, ops[i], plane,
+					      &mtk_ovl_colorop_funcs,
+					      gamma_supported_tfs,
+					      DRM_COLOROP_FLAG_ALLOW_BYPASS);
+	if (ret)
+		goto err_colorop_init;
+
+	drm_colorop_set_next_property(ops[i - 1], ops[i]);
+
 	pipeline->type = ops[0]->base.id;
 	pipeline->name = kasprintf(GFP_KERNEL, "Color Pipeline %d", ops[0]->base.id);
 

-- 
2.51.0



From nfraprado at collabora.com  Tue Dec 23 11:44:50 2025
From: nfraprado at collabora.com (=?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?=)
Date: Tue, 23 Dec 2025 16:44:50 -0300
Subject: [PATCH 09/11] drm/colorop: Introduce 3x3 Matrix
In-Reply-To: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
References: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
Message-ID: <20251223-mtk-ovl-pre-blend-colorops-v1-9-0cb99bd0ab33@collabora.com>

Introduce a 3x3 Matrix colorop analogous to the 3x4 Matrix colorop, with
the difference of not supporting offset coefficients.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
---
 drivers/gpu/drm/drm_atomic.c      |  1 +
 drivers/gpu/drm/drm_atomic_uapi.c |  3 +++
 drivers/gpu/drm/drm_colorop.c     | 21 +++++++++++++++++++++
 include/drm/drm_colorop.h         |  3 +++
 include/uapi/drm/drm_mode.h       | 16 ++++++++++++++++
 5 files changed, 44 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 6d3ea8056b60..bf4a31c02b70 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -802,6 +802,7 @@ static void drm_atomic_colorop_print_state(struct drm_printer *p,
 		drm_printf(p, "\tdata blob id=%d\n", state->data ? state->data->base.id : 0);
 		break;
 	case DRM_COLOROP_CTM_3X4:
+	case DRM_COLOROP_CTM_3X3:
 		drm_printf(p, "\tdata blob id=%d\n", state->data ? state->data->base.id : 0);
 		break;
 	case DRM_COLOROP_MULTIPLIER:
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
index 7320db4b8489..7a70e894a2ef 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -709,6 +709,9 @@ static int drm_atomic_color_set_data_property(struct drm_colorop *colorop,
 		size = colorop->size * colorop->size * colorop->size *
 		       sizeof(struct drm_color_lut32);
 		break;
+	case DRM_COLOROP_CTM_3X3:
+		size = sizeof(struct drm_color_ctm);
+		break;
 	default:
 		/* should never get here */
 		return -EINVAL;
diff --git a/drivers/gpu/drm/drm_colorop.c b/drivers/gpu/drm/drm_colorop.c
index a19e03fb9c7c..51c1a0726dfa 100644
--- a/drivers/gpu/drm/drm_colorop.c
+++ b/drivers/gpu/drm/drm_colorop.c
@@ -68,6 +68,7 @@ static const struct drm_prop_enum_list drm_colorop_type_enum_list[] = {
 	{ DRM_COLOROP_CTM_3X4, "3x4 Matrix"},
 	{ DRM_COLOROP_MULTIPLIER, "Multiplier"},
 	{ DRM_COLOROP_3D_LUT, "3D LUT"},
+	{ DRM_COLOROP_CTM_3X3, "3x3 Matrix"},
 };
 
 static const char * const colorop_curve_1d_type_names[] = {
@@ -377,6 +378,26 @@ int drm_plane_colorop_ctm_3x4_init(struct drm_device *dev, struct drm_colorop *c
 }
 EXPORT_SYMBOL(drm_plane_colorop_ctm_3x4_init);
 
+int drm_plane_colorop_ctm_3x3_init(struct drm_device *dev, struct drm_colorop *colorop,
+				   struct drm_plane *plane, const struct drm_colorop_funcs *funcs,
+				   uint32_t flags)
+{
+	int ret;
+
+	ret = drm_plane_colorop_init(dev, colorop, plane, funcs, DRM_COLOROP_CTM_3X3, flags);
+	if (ret)
+		return ret;
+
+	ret = drm_colorop_create_data_prop(dev, colorop);
+	if (ret)
+		return ret;
+
+	drm_colorop_reset(colorop);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_plane_colorop_ctm_3x3_init);
+
 /**
  * drm_plane_colorop_mult_init - Initialize a DRM_COLOROP_MULTIPLIER
  *
diff --git a/include/drm/drm_colorop.h b/include/drm/drm_colorop.h
index 8ec98521607d..ee7fa0eb5dbf 100644
--- a/include/drm/drm_colorop.h
+++ b/include/drm/drm_colorop.h
@@ -426,6 +426,9 @@ int drm_plane_colorop_curve_1d_lut_init(struct drm_device *dev, struct drm_color
 int drm_plane_colorop_ctm_3x4_init(struct drm_device *dev, struct drm_colorop *colorop,
 				   struct drm_plane *plane, const struct drm_colorop_funcs *funcs,
 				   uint32_t flags);
+int drm_plane_colorop_ctm_3x3_init(struct drm_device *dev, struct drm_colorop *colorop,
+				   struct drm_plane *plane, const struct drm_colorop_funcs *funcs,
+				   uint32_t flags);
 int drm_plane_colorop_mult_init(struct drm_device *dev, struct drm_colorop *colorop,
 				struct drm_plane *plane, const struct drm_colorop_funcs *funcs,
 				uint32_t flags);
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index cbbbfc1dfe2b..b894b19eb9f8 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -964,6 +964,22 @@ enum drm_colorop_type {
 	 *         color = lut3d[index]
 	 */
 	DRM_COLOROP_3D_LUT,
+
+	/**
+	 * @DRM_COLOROP_CTM_3X3:
+	 *
+	 * enum string "3x3 Matrix"
+	 *
+	 * A 3x3 matrix. Its values are specified via the
+	 * &drm_color_ctm struct provided via the DATA property.
+	 *
+	 * The DATA blob is a float[9]:
+	 * out   matrix          in
+	 * | R |   | 0  1  2 |   | R |
+	 * | G | = | 3  4  5 | x | G |
+	 * | B |   | 6  7  8 |   | B |
+	 */
+	DRM_COLOROP_CTM_3X3,
 };
 
 /**

-- 
2.51.0



From nfraprado at collabora.com  Tue Dec 23 11:44:51 2025
From: nfraprado at collabora.com (=?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?=)
Date: Tue, 23 Dec 2025 16:44:51 -0300
Subject: [PATCH 10/11] drm/mediatek: ovl: Enable support for R2R Color
 Space Conversion
In-Reply-To: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
References: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
Message-ID: <20251223-mtk-ovl-pre-blend-colorops-v1-10-0cb99bd0ab33@collabora.com>

The OVL hardware allows applying a 3x3 matrix transformation for each
layer through the 'RGB to RGB Color Space Conversion' (R2R CSC) setting.
Implement support for it and expose it as a colorop through the DRM
plane color pipeline uAPI.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 55 ++++++++++++++++++++++++++++++++-
 1 file changed, 54 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index a70092c792a9..c8a2b1b13035 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -4,6 +4,7 @@
  */
 
 #include <drm/drm_blend.h>
+#include <drm/drm_color_mgmt.h>
 #include <drm/drm_colorop.h>
 #include <drm/drm_fourcc.h>
 #include <drm/drm_framebuffer.h>
@@ -52,6 +53,7 @@
 #define OVL_CON_CLRFMT_10_BIT				(1)
 #define DISP_REG_OVL_WCG_CFG1			0x2d8
 #define IGAMMA_EN(layer)				BIT(0 + 4 * (layer))
+#define CSC_EN(layer)					BIT(1 + 4 * (layer))
 #define GAMMA_EN(layer)					BIT(2 + 4 * (layer))
 #define DISP_REG_OVL_WCG_CFG2			0x2dc
 #define IGAMMA_MASK(layer)				GENMASK((layer) * 4 + 1, (layer) * 4)
@@ -62,6 +64,7 @@
 #define GAMMA_BT709					1
 #define GAMMA_BT2020					2
 #define GAMMA_HLG					3
+#define DISP_REG_OVL_R2R_PARA(layer)		(0x500 + (layer) * 0x40)
 #define DISP_REG_OVL_ADDR_MT8173		0x0f40
 #define DISP_REG_OVL_ADDR(ovl, n)		((ovl)->data->addr + 0x20 * (n))
 #define DISP_REG_OVL_HDR_ADDR(ovl, n)		((ovl)->data->addr + 0x20 * (n) + 0x04)
@@ -579,11 +582,44 @@ static void mtk_ovl_apply_igamma(struct mtk_disp_ovl *ovl, unsigned int idx,
 			   IGAMMA_EN(idx));
 }
 
+static void mtk_ovl_write_r2r_para(struct mtk_disp_ovl *ovl, unsigned int idx,
+				   struct drm_color_ctm *ctm,
+				   struct cmdq_pkt *cmdq_pkt)
+{
+	unsigned int i;
+	u64 val;
+
+	for (i = 0; i < ARRAY_SIZE(ctm->matrix); i++) {
+		val = drm_color_ctm_s31_32_to_qm_n(ctm->matrix[i], 5, 18);
+		mtk_ddp_write(cmdq_pkt, val, &ovl->cmdq_reg, ovl->regs,
+			      DISP_REG_OVL_R2R_PARA(idx) + i * 4);
+	}
+}
+
+static void mtk_ovl_apply_r2r_csc(struct mtk_disp_ovl *ovl, unsigned int idx,
+				  struct drm_colorop *colorop,
+				  struct cmdq_pkt *cmdq_pkt)
+{
+	struct drm_color_ctm *ctm;
+
+	if (colorop->state->data && colorop->state->data->data) {
+		ctm = (struct drm_color_ctm *)colorop->state->data->data;
+		mtk_ovl_write_r2r_para(ovl, idx, ctm, cmdq_pkt);
+	}
+
+	mtk_ddp_write_mask(cmdq_pkt, colorop->state->bypass ? 0 : CSC_EN(idx),
+			   &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_WCG_CFG1,
+			   CSC_EN(idx));
+}
+
 static void mtk_ovl_apply_colorop(struct mtk_disp_ovl *ovl, unsigned int idx,
 				  struct drm_colorop *colorop,
 				  struct cmdq_pkt *cmdq_pkt)
 {
 	switch (colorop->type) {
+	case DRM_COLOROP_CTM_3X3:
+		mtk_ovl_apply_r2r_csc(ovl, idx, colorop, cmdq_pkt);
+		break;
 	case DRM_COLOROP_1D_CURVE:
 		/* gamma is the last colorop in pipeline */
 		if (!colorop->next)
@@ -602,7 +638,7 @@ static void mtk_ovl_disable_colorops(struct mtk_disp_ovl *ovl, unsigned int idx,
 {
 	mtk_ddp_write_mask(cmdq_pkt, 0, &ovl->cmdq_reg, ovl->regs,
 			   DISP_REG_OVL_WCG_CFG1,
-			   IGAMMA_EN(idx) | GAMMA_EN(idx));
+			   IGAMMA_EN(idx) | CSC_EN(idx) | GAMMA_EN(idx));
 
 	/* igamma curve needs to be set to default when igamma is disabled */
 	mtk_ddp_write_mask(cmdq_pkt, IGAMMA_SCRGB, &ovl->cmdq_reg, ovl->regs,
@@ -771,6 +807,23 @@ mtk_ovl_initialize_plane_color_pipeline(struct drm_plane *plane,
 
 	i++;
 
+	/* 2nd op: OVL's R2R Color Space Conversion */
+	ops[i] = kzalloc(sizeof(*ops[i]), GFP_KERNEL);
+	if (!ops[i]) {
+		ret = -ENOMEM;
+		goto err_alloc;
+	}
+
+	ret = drm_plane_colorop_ctm_3x3_init(dev, ops[i], plane,
+					     &mtk_ovl_colorop_funcs,
+					     DRM_COLOROP_FLAG_ALLOW_BYPASS);
+	if (ret)
+		goto err_colorop_init;
+
+	drm_colorop_set_next_property(ops[i - 1], ops[i]);
+
+	i++;
+
 	/* 3rd op: OVL's Gamma */
 	ops[i] = kzalloc(sizeof(*ops[i]), GFP_KERNEL);
 	if (!ops[i]) {

-- 
2.51.0



From nfraprado at collabora.com  Tue Dec 23 11:44:52 2025
From: nfraprado at collabora.com (=?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?=)
Date: Tue, 23 Dec 2025 16:44:52 -0300
Subject: [PATCH 11/11] drm/mediatek: Check 3x3 Matrix colorop has DATA set
In-Reply-To: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
References: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
Message-ID: <20251223-mtk-ovl-pre-blend-colorops-v1-11-0cb99bd0ab33@collabora.com>

Add an atomic check hook for the CRTC and use it to verify that any 3x3
Matrix colorop, which requires the DATA property to be set, does in fact
have it set.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_crtc.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c b/drivers/gpu/drm/mediatek/mtk_crtc.c
index f7db235d986f..1a55d5df6dbe 100644
--- a/drivers/gpu/drm/mediatek/mtk_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_crtc.c
@@ -897,6 +897,31 @@ static void mtk_crtc_atomic_flush(struct drm_crtc *crtc,
 	mtk_crtc_update_config(mtk_crtc, !!mtk_crtc->event);
 }
 
+static int mtk_crtc_atomic_check(struct drm_crtc *crtc,
+				 struct drm_atomic_state *state)
+{
+	struct drm_colorop_state *new_colorop_state;
+	struct drm_colorop *colorop;
+	int i;
+
+	for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) {
+		switch (colorop->type) {
+		case DRM_COLOROP_CTM_3X3:
+			if (!new_colorop_state->bypass && !new_colorop_state->data) {
+				drm_dbg_atomic(crtc->dev,
+					       "Missing required DATA property for COLOROP:%d\n",
+					       colorop->base.id);
+				return -EINVAL;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	return 0;
+}
+
 static const struct drm_crtc_funcs mtk_crtc_funcs = {
 	.set_config		= drm_atomic_helper_set_config,
 	.page_flip		= drm_atomic_helper_page_flip,
@@ -914,6 +939,7 @@ static const struct drm_crtc_helper_funcs mtk_crtc_helper_funcs = {
 	.mode_valid	= mtk_crtc_mode_valid,
 	.atomic_begin	= mtk_crtc_atomic_begin,
 	.atomic_flush	= mtk_crtc_atomic_flush,
+	.atomic_check	= mtk_crtc_atomic_check,
 	.atomic_enable	= mtk_crtc_atomic_enable,
 	.atomic_disable	= mtk_crtc_atomic_disable,
 };

-- 
2.51.0



From shenwei.wang at nxp.com  Tue Dec 23 11:47:31 2025
From: shenwei.wang at nxp.com (Shenwei Wang)
Date: Tue, 23 Dec 2025 19:47:31 +0000
Subject: [PATCH v6 2/5] remoteproc: imx_rproc: Populate devices under
 "rpmsg" subnode
In-Reply-To: <3bbemd2vbsfss3sqpjpokytvvzweoqrtiqygffj5vqazqk3jyq@eobv6ruriiwb>
References: <20251212194341.966387-1-shenwei.wang@nxp.com>
 <20251212194341.966387-3-shenwei.wang@nxp.com>
 <3bbemd2vbsfss3sqpjpokytvvzweoqrtiqygffj5vqazqk3jyq@eobv6ruriiwb>
Message-ID: <PAXPR04MB9185AF0B5225CB8DD06F774289B5A@PAXPR04MB9185.eurprd04.prod.outlook.com>



> -----Original Message-----
> From: Bjorn Andersson <andersson at kernel.org>
> Sent: Thursday, December 18, 2025 8:24 PM
> To: Shenwei Wang <shenwei.wang at nxp.com>
> Cc: Linus Walleij <linusw at kernel.org>; Bartosz Golaszewski <brgl at kernel.org>;
> Rob Herring <robh at kernel.org>; Krzysztof Kozlowski <krzk+dt at kernel.org>;
> Conor Dooley <conor+dt at kernel.org>; Mathieu Poirier
> <mathieu.poirier at linaro.org>; Shawn Guo <shawnguo at kernel.org>; Sascha
> Hauer <s.hauer at pengutronix.de>; Jonathan Corbet <corbet at lwn.net>;
> Pengutronix Kernel Team <kernel at pengutronix.de>; Fabio Estevam
> <festevam at gmail.com>; Peng Fan <peng.fan at nxp.com>; linux-
> gpio at vger.kernel.org; devicetree at vger.kernel.org; linux-
> kernel at vger.kernel.org; linux-remoteproc at vger.kernel.org; imx at lists.linux.dev;
> linux-arm-kernel at lists.infradead.org; linux-doc at vger.kernel.org; dl-linux-imx
> <linux-imx at nxp.com>
> Subject: [EXT] Re: [PATCH v6 2/5] remoteproc: imx_rproc: Populate devices
> under "rpmsg" subnode
> 
> Caution: This is an external email. Please take care when clicking links or opening
> attachments. When in doubt, report the message using the 'Report this email'
> button
> 
> 
> On Fri, Dec 12, 2025 at 01:43:38PM -0600, Shenwei Wang wrote:
> > Register the RPMsg channel driver and populate remote devices defined
> > under the "rpmsg" subnode upon receiving their notification messages.
> 
> Please provide a proper description of what "problem" this patch solves.
> 
> >
> > The following illustrates the expected DTS layout structure:
> >
> >       cm33: remoteproc-cm33 {
> >               compatible = "fsl,imx8ulp-cm33";
> >
> >               rpmsg {
> >                       rpmsg-io-channel {
> >                               gpio at 0 {
> >                                       compatible = "fsl,imx-rpmsg-gpio";
> >                                       reg = <0>;
> 
> Surely there needs to be some "gpio-controller" and "#gpio-cells" here?
> Would be useful if the example is somewhat complete, to give a picture of what's
> actually going on.
> 

Okay. Will add those in next version.

> >                               };
> >
> >                               gpio at 1 {
> >                                       compatible = "fsl,imx-rpmsg-gpio";
> >                                       reg = <1>;
> >                               };
> >
> >                               ...
> >                       };
> >
> >                       ...
> >               };
> >       };
> >
> > +     drvdata->rpdev = rpdev;
> > +     auxdata[0].compatible = devm_kstrdup(dev, imx_rpdrv->compat,
> GFP_KERNEL);
> > +     auxdata[0].platform_data = drvdata;
> > +     dev_set_drvdata(dev, drvdata);
> > +
> > +     of_platform_populate(drvdata->channel_node, NULL, auxdata, dev);
> 
> auxiliary_bus would be a better choice, but I don't understand why you probe a
> rpmsg_device for each "gpio channel" and then from that create a
> platform_device.
> 
> Why don't you just make the rpmsg_device register the gpio controller directly?
> 

The "GPIO channel" is just one example-there are also "PWM channel", "I2C channel", and other channels. 
The goal is to manage all these channels under a common logic, which helps avoid redundant code and keeps 
the implementation consistent.

> > +
> > +     return 0;
> > +}
> > +
> > +     rp_driver->rpdrv.drv.name = name;
> > +     rp_driver->rpdrv.id_table = rpdev_id;
> > +     rp_driver->rpdrv.probe = imx_rpmsg_endpoint_probe;
> > +     rp_driver->rpdrv.remove = imx_rpmsg_endpoint_remove;
> > +     rp_driver->rpdrv.callback = imx_rpmsg_endpoint_cb;
> > +     rp_driver->driver_data = driver_data;
> > +     rp_driver->compat = compat;
> > +
> > +     register_rpmsg_driver(&rp_driver->rpdrv);
> 
> This would then also imply that it's the gpio driver that registers the
> rpmsg_driver.
> 
> > +
> > +     return 0;
> > +}
> > +
> > +static int rproc_of_rpmsg_node_init(struct platform_device *pdev) {
> > +     struct device *dev = &pdev->dev;
> > +     const char *compat;
> > +     int ret;
> > +
> > +     struct device_node *np __free(device_node) = of_get_child_by_name(dev-
> >of_node, "rpmsg");
> > +     if (!np)
> > +             return 0;
> > +
> > +     for_each_child_of_node_scoped(np, child) {
> > +             compat = imx_of_rpmsg_is_in_map(child->name);
> > +             if (!compat)
> > +                     ret = of_platform_default_populate(child, NULL,
> > + dev);
> 
> So if you don't recognize the child device node name you just register
> platform_devices for each of the children?
> 

Yes. That would register platform_devices without the platform_data.

> > +             else
> > +                     ret = imx_of_rpmsg_register_rpdriver(child, dev,
> > + child->name, compat);
> > +
> > +             if (ret < 0)
> > +                     return ret;
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> >  static int imx_rproc_probe(struct platform_device *pdev)  {
> >       struct device *dev = &pdev->dev; @@ -1114,6 +1253,10 @@ static
> > int imx_rproc_probe(struct platform_device *pdev)
> >               goto err_put_pm;
> >       }
> >
> > +     ret = rproc_of_rpmsg_node_init(pdev);
> > +     if (ret < 0)
> > +             dev_info(dev, "populating 'rpmsg' node failed\n");
> > +
> >       return 0;
> >
> >  err_put_pm:
> > diff --git a/include/linux/rpmsg/rpdev_info.h
> > b/include/linux/rpmsg/rpdev_info.h
> > new file mode 100644
> > index 000000000000..13e020cd028b
> > --- /dev/null
> > +++ b/include/linux/rpmsg/rpdev_info.h
> > @@ -0,0 +1,33 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/* Copyright 2025 NXP */
> > +
> > +/*
> > + * @file linux/rpdev_info.h
> > + *
> > + * @brief Global header file for RPDEV Info
> > + *
> > + * @ingroup RPMSG
> > + */
> > +#ifndef __LINUX_RPDEV_INFO_H__
> > +#define __LINUX_RPDEV_INFO_H__
> > +
> > +#define MAX_DEV_PER_CHANNEL    10
> > +
> > +/**
> > + * rpdev_platform_info - store the platform information of rpdev
> > + * @rproc_name: the name of the remote proc.
> > + * @rpdev: rpmsg channel device
> > + * @device_node: pointer to the device node of the rpdev.
> > + * @rx_callback: rx callback handler of the rpdev.
> > + * @channel_devices: an array of the devices related to the rpdev.
> > + */
> > +struct rpdev_platform_info {
> 
> I don't understand what this structure represents. Why is this glue between the
> rpmsg_device and a made up platform_device needed?
> 

The purpose is to have a shared array that can be accessed by all devices within 
the same channel.

> > +     const char *rproc_name;
> 
> You don't need this, because you can rproc_get_by_child(&self) and then get the
> remoteproc name from that.
> 

Good to know. Will try it in the next version.

> > +     struct rpmsg_device *rpdev;
> > +     struct device_node *channel_node;
> > +     int (*rx_callback)(struct rpmsg_device *rpdev, void *data,
> > +                        int len, void *priv, u32 src);
> > +     void *channel_devices[MAX_DEV_PER_CHANNEL];
> 
> Why 10? What does it mean?
> 

This is based on practical experience. For example, on the i.MX platform, we typically don't have 
more than eight same devices on the remote system.

> I think this becomes the list of the 10 grandchildren of the remoteproc (per child
> node). So what happens if those matches against two different drivers, what will
> rx_callback point to?
> 

This is the limitation. That's why I used the map to populate the known child device for one specific channel.

Thanks,
Shenwei

> > +};
> 
> Regards,
> Bjorn
> 
> > +
> > +#endif /* __LINUX_RPDEV_INFO_H__ */
> > --
> > 2.43.0
> >


From robert.marko at sartura.hr  Tue Dec 23 12:16:11 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Tue, 23 Dec 2025 21:16:11 +0100
Subject: [PATCH v3 00/15] Add support for Microchip LAN969x
Message-ID: <20251223201921.1332786-1-robert.marko@sartura.hr>

This series adds support for the Microchip LAN969x switch SoC family.

Series is a bit long since after discussions in previous versions, it was
recommended[1][2] to add SoC specific compatibles for device nodes so it
includes the required bindings updates.

[1] https://lore.kernel.org/all/20251203-splendor-cubbyhole-eda2d6982b46 at spud/
[2] https://lore.kernel.org/all/173412c8-c2fb-4c38-8de7-5b1c2eebdbf9 at microchip.com/
[3] https://lore.kernel.org/all/20251203-duly-leotard-86b83bd840c6 at spud/

Signed-off-by: Robert Marko <robert.marko at sartura.hr>

Changes in v3:
* Pick Acked-by from Conor
* Drop HWMON binding as it was picked into hwmon already
* Document EV23X71A into AT91 binding
* Drop SparX-5 and AT91 bindings merge
* Apply remark from Conor on DMA binding regarding merging cases

Changes in v2:
* Change LAN969x wildcards to LAN9691 in patches
* Split SoC DTSI and evaluation board patches
* Add the suggested binding changes required for SoC specific compatibles
* Merge SparX-5 and AT91 bindings as suggested[3]

Robert Marko (15):
  include: dt-bindings: add LAN969x clock bindings
  dt-bindings: usb: Add Microchip LAN969x support
  dt-bindings: mfd: atmel,sama5d2-flexcom: add microchip,lan9691-flexcom
  dt-bindings: serial: atmel,at91-usart: add microchip,lan9691-usart
  dt-bindings: spi: at91: add microchip,lan9691-spi
  dt-bindings: i2c: atmel,at91sam: add microchip,lan9691-i2c
  dt-bindings: rng: atmel,at91-trng: add microchip,lan9691-trng
  dt-bindings: crypto: atmel,at91sam9g46-aes: add microchip,lan9691-aes
  dt-bindings: crypto: atmel,at91sam9g46-sha: add microchip,lan9691-sha
  dt-bindings: dma: atmel: add microchip,lan9691-dma
  dt-bindings: net: mscc-miim: add microchip,lan9691-miim
  dt-bindings: pinctrl: pinctrl-microchip-sgpio: add LAN969x
  arm64: dts: microchip: add LAN969x support
  dt-bindings: arm: AT91: document EV23X71A board
  arm64: dts: microchip: add EV23X71A board

 .../devicetree/bindings/arm/atmel-at91.yaml   |   6 +
 .../crypto/atmel,at91sam9g46-aes.yaml         |   1 +
 .../crypto/atmel,at91sam9g46-sha.yaml         |   1 +
 .../bindings/dma/atmel,sama5d4-dma.yaml       |   4 +-
 .../bindings/i2c/atmel,at91sam-i2c.yaml       |   1 +
 .../bindings/mfd/atmel,sama5d2-flexcom.yaml   |   1 +
 .../devicetree/bindings/net/mscc,miim.yaml    |  11 +-
 .../pinctrl/microchip,sparx5-sgpio.yaml       |  20 +-
 .../bindings/rng/atmel,at91-trng.yaml         |   1 +
 .../bindings/serial/atmel,at91-usart.yaml     |   1 +
 .../bindings/spi/atmel,at91rm9200-spi.yaml    |   1 +
 .../bindings/usb/microchip,lan9691-dwc3.yaml  |  68 ++
 arch/arm64/boot/dts/microchip/Makefile        |   1 +
 arch/arm64/boot/dts/microchip/lan9691.dtsi    | 487 +++++++++++
 .../boot/dts/microchip/lan9696-ev23x71a.dts   | 757 ++++++++++++++++++
 include/dt-bindings/clock/microchip,lan9691.h |  24 +
 16 files changed, 1376 insertions(+), 9 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/usb/microchip,lan9691-dwc3.yaml
 create mode 100644 arch/arm64/boot/dts/microchip/lan9691.dtsi
 create mode 100644 arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts
 create mode 100644 include/dt-bindings/clock/microchip,lan9691.h

-- 
2.52.0



From robert.marko at sartura.hr  Tue Dec 23 12:16:12 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Tue, 23 Dec 2025 21:16:12 +0100
Subject: [PATCH v3 01/15] include: dt-bindings: add LAN969x clock bindings
In-Reply-To: <20251223201921.1332786-1-robert.marko@sartura.hr>
References: <20251223201921.1332786-1-robert.marko@sartura.hr>
Message-ID: <20251223201921.1332786-2-robert.marko@sartura.hr>

Add the required LAN969x clock bindings.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
---
Changes in v2:
* Rename file to microchip,lan9691.h

 include/dt-bindings/clock/microchip,lan9691.h | 24 +++++++++++++++++++
 1 file changed, 24 insertions(+)
 create mode 100644 include/dt-bindings/clock/microchip,lan9691.h

diff --git a/include/dt-bindings/clock/microchip,lan9691.h b/include/dt-bindings/clock/microchip,lan9691.h
new file mode 100644
index 000000000000..260370c2b238
--- /dev/null
+++ b/include/dt-bindings/clock/microchip,lan9691.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+
+#ifndef _DT_BINDINGS_CLK_LAN9691_H
+#define _DT_BINDINGS_CLK_LAN9691_H
+
+#define GCK_ID_QSPI0		0
+#define GCK_ID_QSPI2		1
+#define GCK_ID_SDMMC0		2
+#define GCK_ID_SDMMC1		3
+#define GCK_ID_MCAN0		4
+#define GCK_ID_MCAN1		5
+#define GCK_ID_FLEXCOM0		6
+#define GCK_ID_FLEXCOM1		7
+#define GCK_ID_FLEXCOM2		8
+#define GCK_ID_FLEXCOM3		9
+#define GCK_ID_TIMER		10
+#define GCK_ID_USB_REFCLK	11
+
+/* Gate clocks */
+#define GCK_GATE_USB_DRD	12
+#define GCK_GATE_MCRAMC		13
+#define GCK_GATE_HMATRIX	14
+
+#endif
-- 
2.52.0



From robert.marko at sartura.hr  Tue Dec 23 12:16:13 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Tue, 23 Dec 2025 21:16:13 +0100
Subject: [PATCH v3 02/15] dt-bindings: usb: Add Microchip LAN969x support
In-Reply-To: <20251223201921.1332786-1-robert.marko@sartura.hr>
References: <20251223201921.1332786-1-robert.marko@sartura.hr>
Message-ID: <20251223201921.1332786-3-robert.marko@sartura.hr>

Microchip LAN969x has DWC3 compatible controller, though limited to 2.0(HS)
speed, so document it.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
---
Changes in v2:
* Fix example indentation

 .../bindings/usb/microchip,lan9691-dwc3.yaml  | 68 +++++++++++++++++++
 1 file changed, 68 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/usb/microchip,lan9691-dwc3.yaml

diff --git a/Documentation/devicetree/bindings/usb/microchip,lan9691-dwc3.yaml b/Documentation/devicetree/bindings/usb/microchip,lan9691-dwc3.yaml
new file mode 100644
index 000000000000..6b49ef0a6bdd
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/microchip,lan9691-dwc3.yaml
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/microchip,lan9691-dwc3.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Microchip LAN969x SuperSpeed DWC3 USB SoC controller
+
+maintainers:
+  - Robert Marko <robert.marko at sartura.hr>
+
+select:
+  properties:
+    compatible:
+      contains:
+        enum:
+          - microchip,lan9691-dwc3
+  required:
+    - compatible
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - microchip,lan9691-dwc3
+      - const: snps,dwc3
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: Gated USB DRD clock
+      - description: Controller reference clock
+
+  clock-names:
+    items:
+      - const: bus_early
+      - const: ref
+
+unevaluatedProperties: false
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+
+allOf:
+  - $ref: snps,dwc3.yaml#
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/microchip,lan9691.h>
+
+    usb at 300000 {
+        compatible = "microchip,lan9691-dwc3", "snps,dwc3";
+        reg = <0x300000 0x80000>;
+        interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&clks GCK_GATE_USB_DRD>,
+                 <&clks GCK_ID_USB_REFCLK>;
+        clock-names = "bus_early", "ref";
+    };
-- 
2.52.0



From robert.marko at sartura.hr  Tue Dec 23 12:16:14 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Tue, 23 Dec 2025 21:16:14 +0100
Subject: [PATCH v3 03/15] dt-bindings: mfd: atmel,sama5d2-flexcom: add microchip,lan9691-flexcom
In-Reply-To: <20251223201921.1332786-1-robert.marko@sartura.hr>
References: <20251223201921.1332786-1-robert.marko@sartura.hr>
Message-ID: <20251223201921.1332786-4-robert.marko@sartura.hr>

Add binding documentation for Microchip LAN969x.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
Changes in v3:
* Pick Acked-by from Conor

 Documentation/devicetree/bindings/mfd/atmel,sama5d2-flexcom.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/mfd/atmel,sama5d2-flexcom.yaml b/Documentation/devicetree/bindings/mfd/atmel,sama5d2-flexcom.yaml
index c7d6cf96796c..5e5dec2f6564 100644
--- a/Documentation/devicetree/bindings/mfd/atmel,sama5d2-flexcom.yaml
+++ b/Documentation/devicetree/bindings/mfd/atmel,sama5d2-flexcom.yaml
@@ -20,6 +20,7 @@ properties:
       - const: atmel,sama5d2-flexcom
       - items:
           - enum:
+              - microchip,lan9691-flexcom
               - microchip,sam9x7-flexcom
               - microchip,sama7d65-flexcom
               - microchip,sama7g5-flexcom
-- 
2.52.0



From robert.marko at sartura.hr  Tue Dec 23 12:16:15 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Tue, 23 Dec 2025 21:16:15 +0100
Subject: [PATCH v3 04/15] dt-bindings: serial: atmel,at91-usart: add microchip,lan9691-usart
In-Reply-To: <20251223201921.1332786-1-robert.marko@sartura.hr>
References: <20251223201921.1332786-1-robert.marko@sartura.hr>
Message-ID: <20251223201921.1332786-5-robert.marko@sartura.hr>

Document Microchip LAN969x USART compatible.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
Changes in v3:
* Pick Acked-by from Conor

 Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml b/Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml
index 087a8926f8b4..375cd50bc5cc 100644
--- a/Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml
+++ b/Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml
@@ -24,6 +24,7 @@ properties:
           - const: atmel,at91sam9260-usart
       - items:
           - enum:
+              - microchip,lan9691-usart
               - microchip,sam9x60-usart
               - microchip,sam9x7-usart
               - microchip,sama7d65-usart
-- 
2.52.0



From robert.marko at sartura.hr  Tue Dec 23 12:16:16 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Tue, 23 Dec 2025 21:16:16 +0100
Subject: [PATCH v3 05/15] dt-bindings: spi: at91: add microchip,lan9691-spi
In-Reply-To: <20251223201921.1332786-1-robert.marko@sartura.hr>
References: <20251223201921.1332786-1-robert.marko@sartura.hr>
Message-ID: <20251223201921.1332786-6-robert.marko@sartura.hr>

Document Microchip LAN969x SPI compatible.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
Changes in v3:
* Pick Acked-by from Conor

 Documentation/devicetree/bindings/spi/atmel,at91rm9200-spi.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/spi/atmel,at91rm9200-spi.yaml b/Documentation/devicetree/bindings/spi/atmel,at91rm9200-spi.yaml
index 11885d0cc209..a8539b68a2f3 100644
--- a/Documentation/devicetree/bindings/spi/atmel,at91rm9200-spi.yaml
+++ b/Documentation/devicetree/bindings/spi/atmel,at91rm9200-spi.yaml
@@ -19,6 +19,7 @@ properties:
       - const: atmel,at91rm9200-spi
       - items:
           - enum:
+              - microchip,lan9691-spi
               - microchip,sam9x60-spi
               - microchip,sam9x7-spi
               - microchip,sama7d65-spi
-- 
2.52.0



From robert.marko at sartura.hr  Tue Dec 23 12:16:17 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Tue, 23 Dec 2025 21:16:17 +0100
Subject: [PATCH v3 06/15] dt-bindings: i2c: atmel,at91sam: add microchip,lan9691-i2c
In-Reply-To: <20251223201921.1332786-1-robert.marko@sartura.hr>
References: <20251223201921.1332786-1-robert.marko@sartura.hr>
Message-ID: <20251223201921.1332786-7-robert.marko@sartura.hr>

Document Microchip LAN969x I2C compatible.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
Changes in v3:
* Pick Acked-by from Conor

 Documentation/devicetree/bindings/i2c/atmel,at91sam-i2c.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/i2c/atmel,at91sam-i2c.yaml b/Documentation/devicetree/bindings/i2c/atmel,at91sam-i2c.yaml
index e61cdb5b16ef..c83674c3183b 100644
--- a/Documentation/devicetree/bindings/i2c/atmel,at91sam-i2c.yaml
+++ b/Documentation/devicetree/bindings/i2c/atmel,at91sam-i2c.yaml
@@ -26,6 +26,7 @@ properties:
               - microchip,sam9x60-i2c
       - items:
           - enum:
+              - microchip,lan9691-i2c
               - microchip,sama7d65-i2c
               - microchip,sama7g5-i2c
               - microchip,sam9x7-i2c
-- 
2.52.0



From robert.marko at sartura.hr  Tue Dec 23 12:16:18 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Tue, 23 Dec 2025 21:16:18 +0100
Subject: [PATCH v3 07/15] dt-bindings: rng: atmel,at91-trng: add microchip,lan9691-trng
In-Reply-To: <20251223201921.1332786-1-robert.marko@sartura.hr>
References: <20251223201921.1332786-1-robert.marko@sartura.hr>
Message-ID: <20251223201921.1332786-8-robert.marko@sartura.hr>

Document Microchip LAN9696X TRNG compatible.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
Changes in v3:
* Pick Acked-by from Conor

 Documentation/devicetree/bindings/rng/atmel,at91-trng.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/rng/atmel,at91-trng.yaml b/Documentation/devicetree/bindings/rng/atmel,at91-trng.yaml
index f78614100ea8..3628251b8c51 100644
--- a/Documentation/devicetree/bindings/rng/atmel,at91-trng.yaml
+++ b/Documentation/devicetree/bindings/rng/atmel,at91-trng.yaml
@@ -19,6 +19,7 @@ properties:
           - microchip,sam9x60-trng
       - items:
           - enum:
+              - microchip,lan9691-trng
               - microchip,sama7g5-trng
           - const: atmel,at91sam9g45-trng
       - items:
-- 
2.52.0



From robert.marko at sartura.hr  Tue Dec 23 12:16:19 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Tue, 23 Dec 2025 21:16:19 +0100
Subject: [PATCH v3 08/15] dt-bindings: crypto: atmel,at91sam9g46-aes: add microchip,lan9691-aes
In-Reply-To: <20251223201921.1332786-1-robert.marko@sartura.hr>
References: <20251223201921.1332786-1-robert.marko@sartura.hr>
Message-ID: <20251223201921.1332786-9-robert.marko@sartura.hr>

Document Microchip LAN969x AES compatible.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
Changes in v3:
* Pick Acked-by from Conor

 .../devicetree/bindings/crypto/atmel,at91sam9g46-aes.yaml        | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-aes.yaml b/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-aes.yaml
index 19010f90198a..f3b6af6baf15 100644
--- a/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-aes.yaml
+++ b/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-aes.yaml
@@ -16,6 +16,7 @@ properties:
       - const: atmel,at91sam9g46-aes
       - items:
           - enum:
+              - microchip,lan9691-aes
               - microchip,sam9x7-aes
               - microchip,sama7d65-aes
           - const: atmel,at91sam9g46-aes
-- 
2.52.0



From shenwei.wang at nxp.com  Tue Dec 23 12:20:49 2025
From: shenwei.wang at nxp.com (Shenwei Wang)
Date: Tue, 23 Dec 2025 20:20:49 +0000
Subject: [PATCH v6 4/5] gpio: rpmsg: add generic rpmsg GPIO driver
In-Reply-To: <mnpg4xanzl45lal72c6kgog7qmqgk2zcp734eqdpk3gsonq63f@vlewh6jgdjy4>
References: <20251212194341.966387-1-shenwei.wang@nxp.com>
 <20251212194341.966387-5-shenwei.wang@nxp.com>
 <mnpg4xanzl45lal72c6kgog7qmqgk2zcp734eqdpk3gsonq63f@vlewh6jgdjy4>
Message-ID: <PAXPR04MB9185B16A2B08E739B2FB64C889B5A@PAXPR04MB9185.eurprd04.prod.outlook.com>



> -----Original Message-----
> From: Bjorn Andersson <andersson at kernel.org>
> Sent: Thursday, December 18, 2025 9:58 AM
> To: Shenwei Wang <shenwei.wang at nxp.com>
> Cc: Linus Walleij <linusw at kernel.org>; Bartosz Golaszewski <brgl at kernel.org>;
> Rob Herring <robh at kernel.org>; Krzysztof Kozlowski <krzk+dt at kernel.org>;
> Conor Dooley <conor+dt at kernel.org>; Mathieu Poirier
> <mathieu.poirier at linaro.org>; Shawn Guo <shawnguo at kernel.org>; Sascha
> Hauer <s.hauer at pengutronix.de>; Jonathan Corbet <corbet at lwn.net>;
> Pengutronix Kernel Team <kernel at pengutronix.de>; Fabio Estevam
> On Fri, Dec 12, 2025 at 01:43:40PM -0600, Shenwei Wang wrote:
> > On an AMP platform, the system may include two processors:
> 
> We have many examples where there's N systems and it's certainly not
> unreasonable to have multiple remote processors expose GPIOs in this fashion.
> 

Agreed. There's no restriction on that.

> >       - An MCU running an RTOS
> >       - An MPU running Linux
> >
> > These processors communicate via the RPMSG protocol.
> > The driver implements the standard GPIO interface, allowing the Linux
> > side to control GPIO controllers which reside in the remote processor
> > +
> > +#define GPIOS_PER_PORT               32
> > +#define RPMSG_TIMEOUT                1000
> > +
> > +enum gpio_input_trigger_type {
> > +     GPIO_RPMSG_TRI_IGNORE,
> 
> These aren't enumerations, they are well defined constants of the protocol. I
> think #define is better.
> 
> > +     GPIO_RPMSG_TRI_RISING,
> > +     GPIO_RPMSG_TRI_FALLING,
> > +     GPIO_RPMSG_TRI_BOTH_EDGE,
> > +     GPIO_RPMSG_TRI_LOW_LEVEL,
> > +     GPIO_RPMSG_TRI_HIGH_LEVEL,
> > +};
> > +
> > +enum gpio_rpmsg_header_type {
> > +     GPIO_RPMSG_SETUP,
> > +     GPIO_RPMSG_REPLY,
> > +     GPIO_RPMSG_NOTIFY,
> > +};
> > +
> > +enum gpio_rpmsg_header_cmd {
> > +     GPIO_RPMSG_INPUT_INIT,
> > +     GPIO_RPMSG_OUTPUT_INIT,
> > +     GPIO_RPMSG_INPUT_GET,
> > +     GPIO_RPMSG_DIRECTION_GET,
> > +};
> > +
> > +struct gpio_rpmsg_head {
> > +     u8 id;          /* Message ID Code */
> > +     u8 vendor;      /* Vendor ID number */
> > +     u8 version;     /* Vendor-specific version number */
> > +     u8 type;        /* Message type */
> > +     u8 cmd;         /* Command code */
> > +     u8 reserved[5];
> > +} __packed;
> > +
> > +struct gpio_rpmsg_packet {
> > +     struct gpio_rpmsg_head header;
> > +     u8 pin_idx;
> > +     u8 port_idx;
> > +     union {
> > +             u8 event;
> > +             u8 retcode;
> > +             u8 value;
> > +     } out;
> > +     union {
> > +             u8 wakeup;
> > +             u8 value;
> > +     } in;
> > +} __packed __aligned(8);
> > +
> > +struct gpio_rpmsg_pin {
> > +     u8 irq_shutdown;
> > +     u8 irq_unmask;
> > +     u8 irq_mask;
> > +     u32 irq_wake_enable;
> > +     u32 irq_type;
> > +     struct gpio_rpmsg_packet msg;
> > +};
> > +
> > +struct gpio_rpmsg_info {
> > +     struct rpmsg_device *rpdev;
> > +     struct gpio_rpmsg_packet *notify_msg;
> > +     struct gpio_rpmsg_packet *reply_msg;
> > +     struct completion cmd_complete;
> > +     struct mutex lock;
> > +     void **port_store;
> > +};
> > +
> > +struct rpmsg_gpio_port {
> > +     struct gpio_chip gc;
> > +     struct gpio_rpmsg_pin gpio_pins[GPIOS_PER_PORT];
> > +     struct gpio_rpmsg_info info;
> > +     int idx;
> > +};
> > +
> > +static int gpio_send_message(struct rpmsg_gpio_port *port,
> > +                          struct gpio_rpmsg_packet *msg,
> > +                          bool sync)
> > +{
> > +     struct gpio_rpmsg_info *info = &port->info;
> > +     int err;
> > +
> > +     if (!info->rpdev) {
> > +             pr_err("rpmsg channel doesn't exist, is remote core
> > + ready?\n");
> 
> How is this possible? You're creating and destroying the platform_device based
> on the presence of the rpmsg channel/endpoint, in what case would you end up
> here without a valid rpdev?
> 
> And if this is to deal with the race during removal, I guess the error message is
> wrong and rpdev might go away before you access it below?
> 

Yes, the error message should be improved.

> > +             return -EINVAL;
> > +     }
> > +
> > +     reinit_completion(&info->cmd_complete);
> > +     err = rpmsg_send(info->rpdev->ept, (void *)msg,
> > +                      sizeof(struct gpio_rpmsg_packet));
> > +     if (err) {
> > +             dev_err(&info->rpdev->dev, "rpmsg_send failed: %d\n", err);
> > +             return err;
> > +     }
> > +
> > +     if (sync) {
> > +             err = wait_for_completion_timeout(&info->cmd_complete,
> > +                                               msecs_to_jiffies(RPMSG_TIMEOUT));
> > +             if (!err) {
> > +                     dev_err(&info->rpdev->dev, "rpmsg_send timeout!\n");
> > +                     return -ETIMEDOUT;
> > +             }
> > +
> > +             if (info->reply_msg->out.retcode != 0) {
> > +                     dev_err(&info->rpdev->dev, "remote core replies an error: %d!\n",
> > +                             info->reply_msg->out.retcode);
> > +                     return -EINVAL;
> > +             }
> > +
> > +             /* copy the reply message */
> > +             memcpy(&port->gpio_pins[info->reply_msg->pin_idx].msg,
> > +                    info->reply_msg, sizeof(*info->reply_msg));
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +static struct gpio_rpmsg_packet *gpio_setup_msg_header(struct
> rpmsg_gpio_port *port,
> > +                                                    unsigned int offset,
> > +                                                    u8 cmd) {
> > +     struct gpio_rpmsg_packet *msg = &port->gpio_pins[offset].msg;
> > +
> > +     memset(msg, 0, sizeof(struct gpio_rpmsg_packet));
> > +     msg->header.id = RPMSG_GPIO_ID;
> > +     msg->header.vendor = RPMSG_VENDOR;
> > +     msg->header.version = RPMSG_VERSION;
> > +     msg->header.type = GPIO_RPMSG_SETUP;
> > +     msg->header.cmd = cmd;
> > +     msg->pin_idx = offset;
> > +     msg->port_idx = port->idx;
> > +
> > +     return msg;
> > +};
> > +
> > +static int rpmsg_gpio_get(struct gpio_chip *gc, unsigned int gpio) {
> > +     struct rpmsg_gpio_port *port = gpiochip_get_data(gc);
> > +     struct gpio_rpmsg_packet *msg = NULL;
> 
> There's no reason to initialize msg here, the first reference is an assignment.
> 
> > +     int ret;
> > +
> > +     guard(mutex)(&port->info.lock);
> > +
> > +     msg = gpio_setup_msg_header(port, gpio, GPIO_RPMSG_INPUT_GET);
> > +
> > +     ret = gpio_send_message(port, msg, true);
> > +     if (!ret)
> > +             ret = !!port->gpio_pins[gpio].msg.in.value;
> > +
> > +     return ret;
> > +}
> > +
> > +static int rpmsg_gpio_get_direction(struct gpio_chip *gc, unsigned
> > +int gpio) {
> > +     struct rpmsg_gpio_port *port = gpiochip_get_data(gc);
> > +     struct gpio_rpmsg_packet *msg = NULL;
> > +     int ret;
> > +
> > +     guard(mutex)(&port->info.lock);
> > +
> > +     msg = gpio_setup_msg_header(port, gpio,
> > + GPIO_RPMSG_DIRECTION_GET);
> > +
> > +     ret = gpio_send_message(port, msg, true);
> > +     if (!ret)
> > +             ret = !!port->gpio_pins[gpio].msg.in.value;
> > +
> > +     return ret;
> > +}
> > +
> > +static int rpmsg_gpio_direction_input(struct gpio_chip *gc, unsigned
> > +int gpio) {
> > +     struct rpmsg_gpio_port *port = gpiochip_get_data(gc);
> > +     struct gpio_rpmsg_packet *msg = NULL;
> > +
> > +     guard(mutex)(&port->info.lock);
> > +
> > +     msg = gpio_setup_msg_header(port, gpio, GPIO_RPMSG_INPUT_INIT);
> > +
> > +     return gpio_send_message(port, msg, true); }
> > +
> > +static int rpmsg_gpio_set(struct gpio_chip *gc, unsigned int gpio,
> > +int val) {
> > +     struct rpmsg_gpio_port *port = gpiochip_get_data(gc);
> > +     struct gpio_rpmsg_packet *msg = NULL;
> > +
> > +     guard(mutex)(&port->info.lock);
> > +
> > +     msg = gpio_setup_msg_header(port, gpio, GPIO_RPMSG_OUTPUT_INIT);
> > +     msg->out.value = val;
> > +
> > +     return gpio_send_message(port, msg, true); }
> > +
> > +static int rpmsg_gpio_direction_output(struct gpio_chip *gc,
> > +                                    unsigned int gpio,
> > +                                    int val) {
> > +
> > +     return rpmsg_gpio_set(gc, gpio, val); }
> > +
> > +static int gpio_rpmsg_irq_set_type(struct irq_data *d, u32 type) {
> > +     struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
> > +     u32 gpio_idx = d->hwirq;
> > +     int edge = 0;
> > +     int ret = 0;
> > +
> > +     switch (type) {
> > +     case IRQ_TYPE_EDGE_RISING:
> > +             edge = GPIO_RPMSG_TRI_RISING;
> > +             irq_set_handler_locked(d, handle_simple_irq);
> > +             break;
> > +     case IRQ_TYPE_EDGE_FALLING:
> > +             edge = GPIO_RPMSG_TRI_FALLING;
> > +             irq_set_handler_locked(d, handle_simple_irq);
> > +             break;
> > +     case IRQ_TYPE_EDGE_BOTH:
> > +             edge = GPIO_RPMSG_TRI_BOTH_EDGE;
> > +             irq_set_handler_locked(d, handle_simple_irq);
> > +             break;
> > +     case IRQ_TYPE_LEVEL_LOW:
> > +             edge = GPIO_RPMSG_TRI_LOW_LEVEL;
> > +             irq_set_handler_locked(d, handle_level_irq);
> > +             break;
> > +     case IRQ_TYPE_LEVEL_HIGH:
> > +             edge = GPIO_RPMSG_TRI_HIGH_LEVEL;
> > +             irq_set_handler_locked(d, handle_level_irq);
> > +             break;
> > +     default:
> > +             ret = -EINVAL;
> > +             irq_set_handler_locked(d, handle_bad_irq);
> > +             break;
> > +     }
> > +
> > +     port->gpio_pins[gpio_idx].irq_type = edge;
> > +
> > +     return ret;
> > +}
> > +
> > +static int gpio_rpmsg_irq_set_wake(struct irq_data *d, u32 enable) {
> > +     struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
> > +     u32 gpio_idx = d->hwirq;
> > +
> > +     port->gpio_pins[gpio_idx].irq_wake_enable = enable;
> > +
> > +     return 0;
> > +}
> > +
> > +/*
> > + * This function will be called at:
> > + *  - one interrupt setup.
> > + *  - the end of one interrupt happened
> > + * The gpio over rpmsg driver will not write the real register, so
> > +save
> > + * all infos before this function and then send all infos to M core
> > +in this
> > + * step.
> > + */
> > +static void gpio_rpmsg_unmask_irq(struct irq_data *d) {
> > +     struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
> > +     u32 gpio_idx = d->hwirq;
> > +
> > +     port->gpio_pins[gpio_idx].irq_unmask = 1; }
> > +
> > +static void gpio_rpmsg_mask_irq(struct irq_data *d) {
> > +     struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
> > +     u32 gpio_idx = d->hwirq;
> > +     /*
> > +      * No need to implement the callback at A core side.
> > +      * M core will mask interrupt after a interrupt occurred, and then
> > +      * sends a notify to A core.
> > +      * After A core dealt with the notify, A core will send a rpmsg to
> > +      * M core to unmask this interrupt again.
> 
> There's nothing in this scheme that dictates that we have A cores and M cores, or
> that we have a single core system on both sides, or that they are Arm cores,
> please describe things in terms of Linux system and "remote system".
> 

Good point. I will reframe the description in next version.

> > +      */
> > +     port->gpio_pins[gpio_idx].irq_mask = 1; }
> > +
> > +static void gpio_rpmsg_irq_shutdown(struct irq_data *d) {
> > +     struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
> > +     u32 gpio_idx = d->hwirq;
> > +
> > +     port->gpio_pins[gpio_idx].irq_shutdown = 1; }
> > +
> > +static void gpio_rpmsg_irq_bus_lock(struct irq_data *d) {
> > +     struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
> > +
> > +     mutex_lock(&port->info.lock);
> > +}
> > +
> > +static void gpio_rpmsg_irq_bus_sync_unlock(struct irq_data *d) {
> > +     struct rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
> > +     struct gpio_rpmsg_packet *msg = NULL;
> > +     u32 gpio_idx = d->hwirq;
> > +
> > +     if (!port)
> > +             return;
> > +
> > +     /*
> > +      * For mask irq, do nothing here.
> > +      * M core will mask interrupt after a interrupt occurred, and then
> > +      * sends a notify to A core.
> > +      * After A core dealt with the notify, A core will send a rpmsg to
> > +      * M core to unmask this interrupt again.
> > +      */
> > +
> > +     if (port->gpio_pins[gpio_idx].irq_mask && !port-
> >gpio_pins[gpio_idx].irq_unmask) {
> > +             port->gpio_pins[gpio_idx].irq_mask = 0;
> > +             mutex_unlock(&port->info.lock);
> > +             return;
> > +     }
> > +
> > +     msg = gpio_setup_msg_header(port, gpio_idx,
> > + GPIO_RPMSG_INPUT_INIT);
> > +
> > +     if (port->gpio_pins[gpio_idx].irq_shutdown) {
> > +             msg->out.event = GPIO_RPMSG_TRI_IGNORE;
> > +             msg->in.wakeup = 0;
> > +             port->gpio_pins[gpio_idx].irq_shutdown = 0;
> > +     } else {
> > +              /* if not set irq type, then use low level as trigger type */
> > +             msg->out.event = port->gpio_pins[gpio_idx].irq_type;
> > +             if (!msg->out.event)
> > +                     msg->out.event = GPIO_RPMSG_TRI_LOW_LEVEL;
> > +             if (port->gpio_pins[gpio_idx].irq_unmask) {
> > +                     msg->in.wakeup = 0;
> > +                     port->gpio_pins[gpio_idx].irq_unmask = 0;
> > +             } else /* irq set wake */
> > +                     msg->in.wakeup = port->gpio_pins[gpio_idx].irq_wake_enable;
> > +     }
> > +
> > +     gpio_send_message(port, msg, false);
> > +     mutex_unlock(&port->info.lock);
> > +}
> > +
> > +static const struct irq_chip gpio_rpmsg_irq_chip = {
> > +     .irq_mask = gpio_rpmsg_mask_irq,
> > +     .irq_unmask = gpio_rpmsg_unmask_irq,
> > +     .irq_set_wake = gpio_rpmsg_irq_set_wake,
> > +     .irq_set_type = gpio_rpmsg_irq_set_type,
> > +     .irq_shutdown = gpio_rpmsg_irq_shutdown,
> > +     .irq_bus_lock = gpio_rpmsg_irq_bus_lock,
> > +     .irq_bus_sync_unlock = gpio_rpmsg_irq_bus_sync_unlock,
> > +     .flags = IRQCHIP_IMMUTABLE,
> > +};
> > +
> > +static int rpmsg_gpio_callback(struct rpmsg_device *rpdev,
> > +                            void *data, int len, void *priv, u32 src)
> > +{
> > +     struct gpio_rpmsg_packet *msg = (struct gpio_rpmsg_packet *)data;
> > +     struct rpmsg_gpio_port *port = NULL;
> > +     struct rpdev_platform_info *drvdata;
> > +
> > +     drvdata = dev_get_drvdata(&rpdev->dev);
> > +     if (msg)
> > +             port = drvdata->channel_devices[msg->port_idx];
> > +
> > +     if (!port)
> > +             return -ENODEV;
> > +
> > +     if (msg->header.type == GPIO_RPMSG_REPLY) {
> > +             port->info.reply_msg = msg;
> 
> As soon as you return from this function, the msg buffer is put back into the
> virtqueue, so you can't just stash a reference to it here and hope that it's still
> available when gpio_send_message() tries to read it.
> 

Will resove it in the next version.

> > +             complete(&port->info.cmd_complete);
> > +     } else if (msg->header.type == GPIO_RPMSG_NOTIFY) {
> > +             port->info.notify_msg = msg;
> 
> Ditto.
> 
> Although notify_msg is assigned, but I never see any further access to it.
> 
> > +             generic_handle_domain_irq_safe(port->gc.irq.domain, msg->pin_idx);
> > +     } else
> > +             dev_err(&rpdev->dev, "wrong command type!\n");
> > +
> > +     return 0;
> > +}
> > +
> > +static void rpmsg_gpio_remove_action(void *data) {
> > +     struct rpmsg_gpio_port *port = data;
> > +
> > +     port->info.port_store[port->idx] = NULL; }
> > +
> > +static int rpmsg_gpio_probe(struct platform_device *pdev) {
> > +     struct rpdev_platform_info *pltdata = pdev->dev.platform_data;
> > +     struct rpmsg_gpio_port *port;
> > +     struct gpio_irq_chip *girq;
> > +     struct gpio_chip *gc;
> > +     int ret;
> > +
> > +     if (!pltdata)
> > +             return -EPROBE_DEFER;
> 
> EPROBE_DEFER would imply that if we try again a bit later, platform_data is
> suddenly non-NULL, that seems unlikely.
> 
> > +
> > +     port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
> > +     if (!port)
> > +             return -ENOMEM;
> > +
> > +     ret = device_property_read_u32(&pdev->dev, "reg", &port->idx);
> > +     if (ret)
> > +             return ret;
> > +
> > +     if (port->idx > MAX_DEV_PER_CHANNEL)
> > +             return -EINVAL;
> > +
> > +     ret = devm_mutex_init(&pdev->dev, &port->info.lock);
> > +     if (ret)
> > +             return ret;
> > +
> > +     init_completion(&port->info.cmd_complete);
> > +     port->info.rpdev = pltdata->rpdev;
> > +     port->info.port_store = pltdata->channel_devices;
> > +     port->info.port_store[port->idx] = port;
> > +     if (!pltdata->rx_callback)
> > +             pltdata->rx_callback = rpmsg_gpio_callback;
> 
> What happens if you rmmod your rpmsg gpio driver and then trigger an interrupt?
> 

The driver has a rpmsg_gpio_remove_action which will clear the devices in the pltdata->channel_devices[].
In the rpmsg callback function, it will just return -NODEV error.

     if (msg)
             port = drvdata->channel_devices[msg->port_idx];

     if (!port)
             return -ENODEV;

> > +
> > +     gc = &port->gc;
> > +     gc->owner = THIS_MODULE;
> > +     gc->parent = &pdev->dev;
> > +     gc->label = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s-gpio%d",
> > +                                pltdata->rproc_name, port->idx);
> > +     gc->ngpio = GPIOS_PER_PORT;
> > +     gc->base = -1;
> > +
> > +     gc->direction_input = rpmsg_gpio_direction_input;
> > +     gc->direction_output = rpmsg_gpio_direction_output;
> > +     gc->get_direction = rpmsg_gpio_get_direction;
> > +     gc->get = rpmsg_gpio_get;
> > +     gc->set = rpmsg_gpio_set;
> > +
> > +     platform_set_drvdata(pdev, port);
> > +     girq = &gc->irq;
> > +     gpio_irq_chip_set_chip(girq, &gpio_rpmsg_irq_chip);
> > +     girq->parent_handler = NULL;
> > +     girq->num_parents = 0;
> > +     girq->parents = NULL;
> > +     girq->chip->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s-
> gpio%d",
> > +                                       pltdata->rproc_name,
> > + port->idx);
> > +
> > +     ret = devm_add_action_or_reset(&pdev->dev, rpmsg_gpio_remove_action,
> port);
> > +     if (ret)
> > +             return ret;
> > +
> > +     return devm_gpiochip_add_data(&pdev->dev, gc, port); }
> > +
> > +static const struct of_device_id rpmsg_gpio_dt_ids[] = {
> > +     { .compatible = "rpmsg-gpio" },
> > +     { /* sentinel */ }
> > +};
> > +
> > +static struct platform_driver rpmsg_gpio_driver = {
> 
> It's an "rpmsg gpio driver", but it's a platform_driver...
> 
> I don't think this is the correct design, but if it is then this needs to be well
> documented.
> 
> Same thing as platform_data forms a strong ABI between some other driver and
> this platform_driver, this needs to be well documented (but should be avoided).
> 

Are you suggesting to use "rpmsg_driver" framework here?

Thank you very much for the review.
Shenwei

> Regards,
> Bjorn
> 
> > +     .driver = {
> > +             .name = "gpio-rpmsg",
> > +             .of_match_table = rpmsg_gpio_dt_ids,
> > +     },
> > +     .probe = rpmsg_gpio_probe,
> > +};
> > +
> > +module_platform_driver(rpmsg_gpio_driver);
> > +
> > +MODULE_AUTHOR("Shenwei Wang <shenwei.wang at nxp.com>");
> > +MODULE_DESCRIPTION("generic rpmsg gpio driver");
> > +MODULE_LICENSE("GPL");
> > --
> > 2.43.0
> >


From robert.marko at sartura.hr  Tue Dec 23 12:16:20 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Tue, 23 Dec 2025 21:16:20 +0100
Subject: [PATCH v3 09/15] dt-bindings: crypto: atmel,at91sam9g46-sha: add microchip,lan9691-sha
In-Reply-To: <20251223201921.1332786-1-robert.marko@sartura.hr>
References: <20251223201921.1332786-1-robert.marko@sartura.hr>
Message-ID: <20251223201921.1332786-10-robert.marko@sartura.hr>

Document Microchip LAN969x SHA compatible.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
Changes in v3:
* Pick Acked-by from Conor

 .../devicetree/bindings/crypto/atmel,at91sam9g46-sha.yaml        | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-sha.yaml b/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-sha.yaml
index 39e076b275b3..16704ff0dd7f 100644
--- a/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-sha.yaml
+++ b/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-sha.yaml
@@ -16,6 +16,7 @@ properties:
       - const: atmel,at91sam9g46-sha
       - items:
           - enum:
+              - microchip,lan9691-sha
               - microchip,sam9x7-sha
               - microchip,sama7d65-sha
           - const: atmel,at91sam9g46-sha
-- 
2.52.0



From robert.marko at sartura.hr  Tue Dec 23 12:16:21 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Tue, 23 Dec 2025 21:16:21 +0100
Subject: [PATCH v3 10/15] dt-bindings: dma: atmel: add microchip,lan9691-dma
In-Reply-To: <20251223201921.1332786-1-robert.marko@sartura.hr>
References: <20251223201921.1332786-1-robert.marko@sartura.hr>
Message-ID: <20251223201921.1332786-11-robert.marko@sartura.hr>

Document Microchip LAN969x DMA compatible which is compatible to SAMA7G5.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
---
Changes in v3:
* Merged with microchip,sama7d65-dma since that also falls back to
microchip,sama7g5-dma

 Documentation/devicetree/bindings/dma/atmel,sama5d4-dma.yaml | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/dma/atmel,sama5d4-dma.yaml b/Documentation/devicetree/bindings/dma/atmel,sama5d4-dma.yaml
index 73fc13b902b3..197efb19b07a 100644
--- a/Documentation/devicetree/bindings/dma/atmel,sama5d4-dma.yaml
+++ b/Documentation/devicetree/bindings/dma/atmel,sama5d4-dma.yaml
@@ -33,7 +33,9 @@ properties:
               - microchip,sam9x7-dma
           - const: atmel,sama5d4-dma
       - items:
-          - const: microchip,sama7d65-dma
+          - enum:
+              - microchip,lan9691-dma
+              - microchip,sama7d65-dma
           - const: microchip,sama7g5-dma
 
   "#dma-cells":
-- 
2.52.0



From robert.marko at sartura.hr  Tue Dec 23 12:16:22 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Tue, 23 Dec 2025 21:16:22 +0100
Subject: [PATCH v3 11/15] dt-bindings: net: mscc-miim: add microchip,lan9691-miim
In-Reply-To: <20251223201921.1332786-1-robert.marko@sartura.hr>
References: <20251223201921.1332786-1-robert.marko@sartura.hr>
Message-ID: <20251223201921.1332786-12-robert.marko@sartura.hr>

Document Microchip LAN969x MIIM compatible.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
Changes in v3:
* Pick Acked-by from Conor

 Documentation/devicetree/bindings/net/mscc,miim.yaml | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/mscc,miim.yaml b/Documentation/devicetree/bindings/net/mscc,miim.yaml
index 792f26b06b06..2207b33aee76 100644
--- a/Documentation/devicetree/bindings/net/mscc,miim.yaml
+++ b/Documentation/devicetree/bindings/net/mscc,miim.yaml
@@ -14,9 +14,14 @@ allOf:
 
 properties:
   compatible:
-    enum:
-      - mscc,ocelot-miim
-      - microchip,lan966x-miim
+    oneOf:
+      - enum:
+          - mscc,ocelot-miim
+          - microchip,lan966x-miim
+      - items:
+          - enum:
+              - microchip,lan9691-miim
+          - const: mscc,ocelot-miim
 
   "#address-cells":
     const: 1
-- 
2.52.0



From robert.marko at sartura.hr  Tue Dec 23 12:16:23 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Tue, 23 Dec 2025 21:16:23 +0100
Subject: [PATCH v3 12/15] dt-bindings: pinctrl: pinctrl-microchip-sgpio: add LAN969x
In-Reply-To: <20251223201921.1332786-1-robert.marko@sartura.hr>
References: <20251223201921.1332786-1-robert.marko@sartura.hr>
Message-ID: <20251223201921.1332786-13-robert.marko@sartura.hr>

Document LAN969x compatibles for SGPIO.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
Changes in v3:
* Pick Acked-by from Conor

 .../pinctrl/microchip,sparx5-sgpio.yaml       | 20 ++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/Documentation/devicetree/bindings/pinctrl/microchip,sparx5-sgpio.yaml b/Documentation/devicetree/bindings/pinctrl/microchip,sparx5-sgpio.yaml
index fa47732d7cef..9fbbafcdc063 100644
--- a/Documentation/devicetree/bindings/pinctrl/microchip,sparx5-sgpio.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/microchip,sparx5-sgpio.yaml
@@ -21,10 +21,15 @@ properties:
     pattern: '^gpio@[0-9a-f]+$'
 
   compatible:
-    enum:
-      - microchip,sparx5-sgpio
-      - mscc,ocelot-sgpio
-      - mscc,luton-sgpio
+    oneOf:
+      - enum:
+          - microchip,sparx5-sgpio
+          - mscc,ocelot-sgpio
+          - mscc,luton-sgpio
+      - items:
+          - enum:
+              - microchip,lan9691-sgpio
+          - const: microchip,sparx5-sgpio
 
   '#address-cells':
     const: 1
@@ -80,7 +85,12 @@ patternProperties:
     type: object
     properties:
       compatible:
-        const: microchip,sparx5-sgpio-bank
+        oneOf:
+          - items:
+              - enum:
+                  - microchip,lan9691-sgpio-bank
+              - const: microchip,sparx5-sgpio-bank
+          - const: microchip,sparx5-sgpio-bank
 
       reg:
         description: |
-- 
2.52.0



From robert.marko at sartura.hr  Tue Dec 23 12:16:24 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Tue, 23 Dec 2025 21:16:24 +0100
Subject: [PATCH v3 13/15] arm64: dts: microchip: add LAN969x support
In-Reply-To: <20251223201921.1332786-1-robert.marko@sartura.hr>
References: <20251223201921.1332786-1-robert.marko@sartura.hr>
Message-ID: <20251223201921.1332786-14-robert.marko@sartura.hr>

Add support for Microchip LAN969x switch SoC series by adding the SoC DTSI.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
---
Changes in v2:
* Rename to lan9691
* Split SoC DTSI and evaluation board commits
* Use SoC specific compatibles for devices
* Alphanumerically sort remaining nodes
* Apply DTS coding style

 arch/arm64/boot/dts/microchip/lan9691.dtsi | 487 +++++++++++++++++++++
 1 file changed, 487 insertions(+)
 create mode 100644 arch/arm64/boot/dts/microchip/lan9691.dtsi

diff --git a/arch/arm64/boot/dts/microchip/lan9691.dtsi b/arch/arm64/boot/dts/microchip/lan9691.dtsi
new file mode 100644
index 000000000000..afe8c59ee79d
--- /dev/null
+++ b/arch/arm64/boot/dts/microchip/lan9691.dtsi
@@ -0,0 +1,487 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT)
+/*
+ * Copyright (c) 2025 Microchip Technology Inc. and its subsidiaries.
+ */
+
+#include <dt-bindings/clock/microchip,lan9691.h>
+#include <dt-bindings/dma/at91.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/mfd/at91-usart.h>
+#include <dt-bindings/mfd/atmel-flexcom.h>
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	model = "Microchip LAN969x";
+	compatible = "microchip,lan9691";
+	interrupt-parent = <&gic>;
+
+	clocks {
+		fx100_clk: fx100-clk {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <320000000>;
+		};
+
+		cpu_clk: cpu-clk {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <1000000000>;
+		};
+
+		ddr_clk: ddr-clk {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <600000000>;
+		};
+
+		fabric_clk: fabric-clk {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <250000000>;
+		};
+	};
+
+	cpus {
+		#address-cells = <2>;
+		#size-cells = <0>;
+
+		cpu0: cpu at 0 {
+			compatible = "arm,cortex-a53";
+			device_type = "cpu";
+			reg = <0x0 0x0>;
+			next-level-cache = <&l2_0>;
+		};
+
+		l2_0: l2-cache {
+			compatible = "cache";
+			cache-level = <2>;
+			cache-unified;
+		};
+	};
+
+	psci {
+		compatible = "arm,psci-1.0";
+		method = "smc";
+	};
+
+	pmu {
+		compatible = "arm,cortex-a53-pmu";
+		interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>, /* Secure Phys IRQ */
+			     <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>, /* Non-secure Phys IRQ */
+			     <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>, /* Virt IRQ */
+			     <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>; /* Hyp IRQ */
+	};
+
+	axi: axi {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		usb: usb at 300000 {
+			compatible = "microchip,lan9691-dwc3", "snps,dwc3";
+			reg = <0x300000 0x80000>;
+			interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clks GCK_GATE_USB_DRD>,
+				 <&clks GCK_ID_USB_REFCLK>;
+			clock-names = "bus_early", "ref";
+			assigned-clocks = <&clks GCK_ID_USB_REFCLK>;
+			assigned-clock-rates = <60000000>;
+			maximum-speed = "high-speed";
+			dr_mode = "host";
+			status = "disabled";
+		};
+
+		flx0: flexcom at e0040000 {
+			compatible = "microchip,lan9691-flexcom", "atmel,sama5d2-flexcom";
+			reg = <0xe0040000 0x100>;
+			ranges = <0x0 0xe0040000 0x800>;
+			clocks = <&clks GCK_ID_FLEXCOM0>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			status = "disabled";
+
+			usart0: serial at 200 {
+				compatible = "microchip,lan9691-usart", "atmel,at91sam9260-usart";
+				reg = <0x200 0x200>;
+				interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
+				       <&dma AT91_XDMAC_DT_PERID(2)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				clock-names = "usart";
+				atmel,fifo-size = <32>;
+				atmel,usart-mode = <AT91_USART_MODE_SERIAL>;
+				status = "disabled";
+			};
+
+			spi0: spi at 400 {
+				compatible = "microchip,lan9691-spi", "atmel,at91rm9200-spi";
+				reg = <0x400 0x200>;
+				interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
+				       <&dma AT91_XDMAC_DT_PERID(2)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				clock-names = "spi_clk";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				atmel,fifo-size = <32>;
+				status = "disabled";
+			};
+
+			i2c0: i2c at 600 {
+				compatible = "microchip,lan9691-i2c", "microchip,sam9x60-i2c";
+				reg = <0x600 0x200>;
+				interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
+				       <&dma AT91_XDMAC_DT_PERID(2)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+		};
+
+		flx1: flexcom at e0044000 {
+			compatible = "microchip,lan9691-flexcom", "atmel,sama5d2-flexcom";
+			reg = <0xe0044000 0x100>;
+			ranges = <0x0 0xe0044000 0x800>;
+			clocks = <&clks GCK_ID_FLEXCOM1>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			status = "disabled";
+
+			usart1: serial at 200 {
+				compatible = "microchip,lan9691-usart", "atmel,at91sam9260-usart";
+				reg = <0x200 0x200>;
+				interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
+				       <&dma AT91_XDMAC_DT_PERID(2)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				clock-names = "usart";
+				atmel,fifo-size = <32>;
+				atmel,usart-mode = <AT91_USART_MODE_SERIAL>;
+				status = "disabled";
+			};
+
+			spi1: spi at 400 {
+				compatible = "microchip,lan9691-spi", "atmel,at91rm9200-spi";
+				reg = <0x400 0x200>;
+				interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
+				       <&dma AT91_XDMAC_DT_PERID(2)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				clock-names = "spi_clk";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				atmel,fifo-size = <32>;
+				status = "disabled";
+			};
+
+			i2c1: i2c at 600 {
+				compatible = "microchip,lan9691-i2c", "microchip,sam9x60-i2c";
+				reg = <0x600 0x200>;
+				interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
+				       <&dma AT91_XDMAC_DT_PERID(2)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+		};
+
+		trng: rng at e0048000 {
+			compatible = "microchip,lan9691-trng", "atmel,at91sam9g45-trng";
+			reg = <0xe0048000 0x100>;
+			clocks = <&fabric_clk>;
+			status = "disabled";
+		};
+
+		aes: crypto at e004c000 {
+			compatible = "microchip,lan9691-aes", "atmel,at91sam9g46-aes";
+			reg = <0xe004c000 0x100>;
+			interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&dma AT91_XDMAC_DT_PERID(12)>,
+			       <&dma AT91_XDMAC_DT_PERID(13)>;
+			dma-names = "tx", "rx";
+			clocks = <&fabric_clk>;
+			clock-names = "aes_clk";
+			status = "disabled";
+		};
+
+		flx2: flexcom at e0060000 {
+			compatible = "microchip,lan9691-flexcom", "atmel,sama5d2-flexcom";
+			reg = <0xe0060000 0x100>;
+			ranges = <0x0 0xe0060000 0x800>;
+			clocks = <&clks GCK_ID_FLEXCOM2>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			status = "disabled";
+
+			usart2: serial at 200 {
+				compatible = "microchip,lan9691-usart", "atmel,at91sam9260-usart";
+				reg = <0x200 0x200>;
+				interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(7)>,
+				       <&dma AT91_XDMAC_DT_PERID(6)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				clock-names = "usart";
+				atmel,fifo-size = <32>;
+				atmel,usart-mode = <AT91_USART_MODE_SERIAL>;
+				status = "disabled";
+			};
+
+			spi2: spi at 400 {
+				compatible = "microchip,lan9691-spi", "atmel,at91rm9200-spi";
+				reg = <0x400 0x200>;
+				interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(7)>,
+				       <&dma AT91_XDMAC_DT_PERID(6)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				clock-names = "spi_clk";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				atmel,fifo-size = <32>;
+				status = "disabled";
+			};
+
+			i2c2: i2c at 600 {
+				compatible = "microchip,lan9691-i2c", "microchip,sam9x60-i2c";
+				reg = <0x600 0x200>;
+				interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(7)>,
+				       <&dma AT91_XDMAC_DT_PERID(6)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+		};
+
+		flx3: flexcom at e0064000 {
+			compatible = "microchip,lan9691-flexcom", "atmel,sama5d2-flexcom";
+			reg = <0xe0064000 0x100>;
+			ranges = <0x0 0xe0064000 0x800>;
+			clocks = <&clks GCK_ID_FLEXCOM3>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			status = "disabled";
+
+			usart3: serial at 200 {
+				compatible = "microchip,lan9691-usart", "atmel,at91sam9260-usart";
+				reg = <0x200 0x200>;
+				interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(9)>,
+				       <&dma AT91_XDMAC_DT_PERID(8)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				clock-names = "usart";
+				atmel,fifo-size = <32>;
+				atmel,usart-mode = <AT91_USART_MODE_SERIAL>;
+				status = "disabled";
+			};
+
+			spi3: spi at 400 {
+				compatible = "microchip,lan9691-spi", "atmel,at91rm9200-spi";
+				reg = <0x400 0x200>;
+				interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(9)>,
+				       <&dma AT91_XDMAC_DT_PERID(8)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				clock-names = "spi_clk";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				atmel,fifo-size = <32>;
+				status = "disabled";
+			};
+
+			i2c3: i2c at 600 {
+				compatible = "microchip,lan9691-i2c", "microchip,sam9x60-i2c";
+				reg = <0x600 0x200>;
+				interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(9)>,
+				       <&dma AT91_XDMAC_DT_PERID(8)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+		};
+
+		dma: dma-controller at e0068000 {
+			compatible = "microchip,lan9691-dma", "microchip,sama7g5-dma";
+			reg = <0xe0068000 0x1000>;
+			interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+			dma-channels = <16>;
+			#dma-cells = <1>;
+			clocks = <&fabric_clk>;
+			clock-names = "dma_clk";
+		};
+
+		sha: crypto at e006c000 {
+			compatible = "microchip,lan9691-sha", "atmel,at91sam9g46-sha";
+			reg = <0xe006c000 0xec>;
+			interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&dma AT91_XDMAC_DT_PERID(14)>;
+			dma-names = "tx";
+			clocks = <&fabric_clk>;
+			clock-names = "sha_clk";
+			status = "disabled";
+		};
+
+		timer: timer at e008c000 {
+			compatible = "snps,dw-apb-timer";
+			reg = <0xe008c000 0x400>;
+			clocks = <&fabric_clk>;
+			clock-names = "timer";
+			interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
+		};
+
+		watchdog: watchdog at e0090000 {
+			compatible = "snps,dw-wdt";
+			reg = <0xe0090000 0x1000>;
+			interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&fabric_clk>;
+		};
+
+		cpu_ctrl: syscon at e00c0000 {
+			compatible = "microchip,lan966x-cpu-syscon", "syscon";
+			reg = <0xe00c0000 0x350>;
+		};
+
+		switch: switch at e00c0000 {
+			compatible = "microchip,lan9691-switch";
+			reg = <0xe00c0000 0x0010000>,
+			      <0xe2010000 0x1410000>;
+			reg-names = "cpu", "devices";
+			interrupt-names = "xtr", "fdma", "ptp";
+			interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI  9 IRQ_TYPE_LEVEL_HIGH>;
+			resets = <&reset 0>;
+			reset-names = "switch";
+			status = "disabled";
+		};
+
+		clks: clock-controller at e00c00b4 {
+			compatible = "microchip,lan9691-gck";
+			reg = <0xe00c00b4 0x30>, <0xe00c0308 0x4>;
+			#clock-cells = <1>;
+			clocks = <&cpu_clk>, <&ddr_clk>, <&fx100_clk>;
+			clock-names = "cpu", "ddr", "sys";
+		};
+
+		reset: reset-controller at e201000c {
+			compatible = "microchip,lan9691-switch-reset",
+				     "microchip,lan966x-switch-reset";
+			reg = <0xe201000c 0x4>;
+			reg-names = "gcb";
+			#reset-cells = <1>;
+			cpu-syscon = <&cpu_ctrl>;
+		};
+
+		gpio: pinctrl at e20100d4 {
+			compatible = "microchip,lan9691-pinctrl";
+			reg = <0xe20100d4 0xd4>,
+			      <0xe2010370 0xa8>;
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&gpio 0 0 66>;
+			interrupt-controller;
+			interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+			#interrupt-cells = <2>;
+		};
+
+		mdio0: mdio at e20101a8 {
+			compatible = "microchip,lan9691-miim", "mscc,ocelot-miim";
+			reg = <0xe20101a8 0x24>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clocks = <&fx100_clk>;
+			status = "disabled";
+		};
+
+		mdio1: mdio at e20101cc {
+			compatible = "microchip,lan9691-miim", "mscc,ocelot-miim";
+			reg = <0xe20101cc 0x24>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clocks = <&fx100_clk>;
+			status = "disabled";
+		};
+
+		sgpio: gpio at e2010230 {
+			compatible = "microchip,lan9691-sgpio", "microchip,sparx5-sgpio";
+			reg = <0xe2010230 0x118>;
+			clocks = <&fx100_clk>;
+			resets = <&reset 0>;
+			reset-names = "switch";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+
+			sgpio_in: gpio at 0 {
+				compatible = "microchip,lan9691-sgpio-bank",
+					     "microchip,sparx5-sgpio-bank";
+				reg = <0>;
+				gpio-controller;
+				#gpio-cells = <3>;
+				interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-controller;
+				#interrupt-cells = <3>;
+			};
+
+			sgpio_out: gpio at 1 {
+				compatible = "microchip,lan9691-sgpio-bank",
+					     "microchip,sparx5-sgpio-bank";
+				reg = <1>;
+				gpio-controller;
+				#gpio-cells = <3>;
+			};
+		};
+
+		tmon: hwmon at e2020100 {
+			compatible = "microchip,lan9691-temp", "microchip,sparx5-temp";
+			reg = <0xe2020100 0xc>;
+			clocks = <&fx100_clk>;
+			#thermal-sensor-cells = <0>;
+		};
+
+		serdes: serdes at e3410000 {
+			compatible = "microchip,lan9691-serdes";
+			reg = <0xe3410000 0x150000>;
+			#phy-cells = <1>;
+			clocks = <&fabric_clk>;
+		};
+
+		gic: interrupt-controller at e8c11000 {
+			compatible = "arm,gic-400";
+			reg = <0xe8c11000 0x1000>, /* Distributor GICD_ */
+			      <0xe8c12000 0x2000>, /* CPU interface GICC_ */
+			      <0xe8c14000 0x2000>, /* Virt interface control */
+			      <0xe8c16000 0x2000>; /* Virt CPU interface */
+			#interrupt-cells = <3>;
+			interrupt-controller;
+			interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+		};
+	};
+};
-- 
2.52.0



From robert.marko at sartura.hr  Tue Dec 23 12:16:25 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Tue, 23 Dec 2025 21:16:25 +0100
Subject: [PATCH v3 14/15] dt-bindings: arm: AT91: document EV23X71A board
In-Reply-To: <20251223201921.1332786-1-robert.marko@sartura.hr>
References: <20251223201921.1332786-1-robert.marko@sartura.hr>
Message-ID: <20251223201921.1332786-15-robert.marko@sartura.hr>

Microchip EV23X71A board is an LAN9696 based evaluation board.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
---
 Documentation/devicetree/bindings/arm/atmel-at91.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.yaml b/Documentation/devicetree/bindings/arm/atmel-at91.yaml
index 3a34b7a2e8d4..b0065e2f3713 100644
--- a/Documentation/devicetree/bindings/arm/atmel-at91.yaml
+++ b/Documentation/devicetree/bindings/arm/atmel-at91.yaml
@@ -241,6 +241,12 @@ properties:
           - const: microchip,lan9668
           - const: microchip,lan966
 
+      - description: Microchip LAN9696 EV23X71A Evaluation Board
+        items:
+          - const: microchip,ev23x71a
+          - const: microchip,lan9696
+          - const: microchip,lan9691
+
       - description: Kontron KSwitch D10 MMT series
         items:
           - enum:
-- 
2.52.0



From robert.marko at sartura.hr  Tue Dec 23 12:16:26 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Tue, 23 Dec 2025 21:16:26 +0100
Subject: [PATCH v3 15/15] arm64: dts: microchip: add EV23X71A board
In-Reply-To: <20251223201921.1332786-1-robert.marko@sartura.hr>
References: <20251223201921.1332786-1-robert.marko@sartura.hr>
Message-ID: <20251223201921.1332786-16-robert.marko@sartura.hr>

Microchip EV23X71A is an LAN9696 based evaluation board.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
---
Changes in v2:
* Split from SoC DTSI commit
* Apply DTS coding style
* Enclose array in i2c-mux
* Alphanumericaly sort nodes
* Change management port mode to RGMII-ID 

 arch/arm64/boot/dts/microchip/Makefile        |   1 +
 .../boot/dts/microchip/lan9696-ev23x71a.dts   | 757 ++++++++++++++++++
 2 files changed, 758 insertions(+)
 create mode 100644 arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts

diff --git a/arch/arm64/boot/dts/microchip/Makefile b/arch/arm64/boot/dts/microchip/Makefile
index c6e0313eea0f..09d16fc1ce9a 100644
--- a/arch/arm64/boot/dts/microchip/Makefile
+++ b/arch/arm64/boot/dts/microchip/Makefile
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
+dtb-$(CONFIG_ARCH_LAN969X) += lan9696-ev23x71a.dtb
 dtb-$(CONFIG_ARCH_SPARX5) += sparx5_pcb125.dtb
 dtb-$(CONFIG_ARCH_SPARX5) += sparx5_pcb134.dtb sparx5_pcb134_emmc.dtb
 dtb-$(CONFIG_ARCH_SPARX5) += sparx5_pcb135.dtb sparx5_pcb135_emmc.dtb
diff --git a/arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts b/arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts
new file mode 100644
index 000000000000..435df455b078
--- /dev/null
+++ b/arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts
@@ -0,0 +1,757 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT)
+/*
+ * Copyright (c) 2025 Microchip Technology Inc. and its subsidiaries.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
+#include "lan9691.dtsi"
+
+/ {
+	model = "Microchip EV23X71A";
+	compatible = "microchip,ev23x71a", "microchip,lan9696", "microchip,lan9691";
+
+	aliases {
+		serial0 = &usart0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	gpio-restart {
+		compatible = "gpio-restart";
+		gpios = <&gpio 60 GPIO_ACTIVE_LOW>;
+		open-source;
+		priority = <200>;
+	};
+
+	i2c-mux {
+		compatible = "i2c-mux-gpio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-parent = <&i2c3>;
+		idle-state = <0x8>;
+		mux-gpios = <&sgpio_out 0 1 GPIO_ACTIVE_HIGH>,
+			    <&sgpio_out 0 2 GPIO_ACTIVE_HIGH>,
+			    <&sgpio_out 0 3 GPIO_ACTIVE_HIGH>;
+		settle-time-us = <100>;
+
+		i2c_sfp0: i2c at 0 {
+			reg = <0x0>;
+		};
+
+		i2c_sfp1: i2c at 1 {
+			reg = <0x1>;
+		};
+
+		i2c_sfp2: i2c at 2 {
+			reg = <0x2>;
+		};
+
+		i2c_sfp3: i2c at 3 {
+			reg = <0x3>;
+		};
+
+		i2c_poe: i2c at 7 {
+			reg = <0x7>;
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		led-status {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_STATUS;
+			gpios = <&gpio 61 GPIO_ACTIVE_LOW>;
+		};
+
+		led-sfp1-green {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_LAN;
+			function-enumerator = <0>;
+			gpios = <&sgpio_out 6 0 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-sfp1-yellow {
+			color = <LED_COLOR_ID_YELLOW>;
+			function = LED_FUNCTION_LAN;
+			function-enumerator = <0>;
+			gpios = <&sgpio_out 6 1 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-sfp2-green {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_LAN;
+			function-enumerator = <1>;
+			gpios = <&sgpio_out 7 0 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-sfp2-yellow {
+			color = <LED_COLOR_ID_YELLOW>;
+			function = LED_FUNCTION_LAN;
+			function-enumerator = <1>;
+			gpios = <&sgpio_out 7 1 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-sfp3-green {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_LAN;
+			function-enumerator = <2>;
+			gpios = <&sgpio_out 8 0 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-sfp3-yellow {
+			color = <LED_COLOR_ID_YELLOW>;
+			function = LED_FUNCTION_LAN;
+			function-enumerator = <2>;
+			gpios = <&sgpio_out 8 1 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-sfp4-green {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_LAN;
+			function-enumerator = <3>;
+			gpios = <&sgpio_out 9 0 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-sfp4-yellow {
+			color = <LED_COLOR_ID_YELLOW>;
+			function = LED_FUNCTION_LAN;
+			function-enumerator = <3>;
+			gpios = <&sgpio_out 9 1 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+	};
+
+	mux-controller {
+		compatible = "gpio-mux";
+		#mux-control-cells = <0>;
+		mux-gpios = <&sgpio_out 1 2 GPIO_ACTIVE_LOW>,
+			    <&sgpio_out 1 3 GPIO_ACTIVE_LOW>;
+	};
+
+	sfp0: sfp0 {
+		compatible = "sff,sfp";
+		i2c-bus = <&i2c_sfp0>;
+		tx-disable-gpios = <&sgpio_out 6 2 GPIO_ACTIVE_HIGH>;
+		los-gpios = <&sgpio_in 6 0 GPIO_ACTIVE_HIGH>;
+		mod-def0-gpios = <&sgpio_in 6 1 GPIO_ACTIVE_LOW>;
+		tx-fault-gpios = <&sgpio_in 6 2 GPIO_ACTIVE_HIGH>;
+	};
+
+	sfp1: sfp1 {
+		compatible = "sff,sfp";
+		i2c-bus = <&i2c_sfp1>;
+		tx-disable-gpios = <&sgpio_out 7 2 GPIO_ACTIVE_HIGH>;
+		los-gpios = <&sgpio_in 7 0 GPIO_ACTIVE_HIGH>;
+		mod-def0-gpios = <&sgpio_in 7 1 GPIO_ACTIVE_LOW>;
+		tx-fault-gpios = <&sgpio_in 7 2 GPIO_ACTIVE_HIGH>;
+	};
+
+	sfp2: sfp2 {
+		compatible = "sff,sfp";
+		i2c-bus = <&i2c_sfp2>;
+		tx-disable-gpios = <&sgpio_out 8 2 GPIO_ACTIVE_HIGH>;
+		los-gpios = <&sgpio_in 8 0 GPIO_ACTIVE_HIGH>;
+		mod-def0-gpios = <&sgpio_in 8 1 GPIO_ACTIVE_LOW>;
+		tx-fault-gpios = <&sgpio_in 8 2 GPIO_ACTIVE_HIGH>;
+	};
+
+	sfp3: sfp3 {
+		compatible = "sff,sfp";
+		i2c-bus = <&i2c_sfp3>;
+		tx-disable-gpios = <&sgpio_out 9 2 GPIO_ACTIVE_HIGH>;
+		los-gpios = <&sgpio_in 9 0 GPIO_ACTIVE_HIGH>;
+		mod-def0-gpios = <&sgpio_in 9 1 GPIO_ACTIVE_LOW>;
+		tx-fault-gpios = <&sgpio_in 9 2 GPIO_ACTIVE_HIGH>;
+	};
+};
+
+&gpio {
+	emmc_sd_pins: emmc-sd-pins {
+		/* eMMC_SD - CMD, CLK, D0, D1, D2, D3, D4, D5, D6, D7, RSTN */
+		pins = "GPIO_14", "GPIO_15", "GPIO_16", "GPIO_17",
+		       "GPIO_18", "GPIO_19", "GPIO_20", "GPIO_21",
+		       "GPIO_22", "GPIO_23", "GPIO_24";
+		function = "emmc_sd";
+	};
+
+	fan_pins: fan-pins {
+		pins = "GPIO_25", "GPIO_26";
+		function = "fan";
+	};
+
+	fc0_pins: fc0-pins {
+		pins = "GPIO_3", "GPIO_4";
+		function = "fc";
+	};
+
+	fc2_pins: fc2-pins {
+		pins = "GPIO_64", "GPIO_65", "GPIO_66";
+		function = "fc";
+	};
+
+	fc3_pins: fc3-pins {
+		pins = "GPIO_55", "GPIO_56";
+		function = "fc";
+	};
+
+	mdio_pins: mdio-pins {
+		pins = "GPIO_9", "GPIO_10";
+		function = "miim";
+	};
+
+	mdio_irq_pins: mdio-irq-pins {
+		pins = "GPIO_11";
+		function = "miim_irq";
+	};
+
+	sgpio_pins: sgpio-pins {
+		/* SCK, D0, D1, LD */
+		pins = "GPIO_5", "GPIO_6", "GPIO_7", "GPIO_8";
+		function = "sgpio_a";
+	};
+
+	usb_ulpi_pins: usb-ulpi-pins {
+		pins = "GPIO_30", "GPIO_31", "GPIO_32", "GPIO_33",
+		       "GPIO_34", "GPIO_35", "GPIO_36", "GPIO_37",
+		       "GPIO_38", "GPIO_39", "GPIO_40", "GPIO_41";
+		function = "usb_ulpi";
+	};
+
+	usb_rst_pins: usb-rst-pins {
+		pins = "GPIO_12";
+		function = "usb2phy_rst";
+	};
+
+	usb_over_pins: usb-over-pins {
+		pins = "GPIO_13";
+		function = "usb_over_detect";
+	};
+
+	usb_power_pins: usb-power-pins {
+		pins = "GPIO_1";
+		function = "usb_power";
+	};
+
+	ptp_out_pins: ptp-out-pins {
+		pins = "GPIO_58";
+		function = "ptpsync_4";
+	};
+
+	ptp_ext_pins: ptp-ext-pins {
+		pins = "GPIO_59";
+		function = "ptpsync_5";
+	};
+};
+
+&flx0 {
+	atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_USART>;
+	status = "okay";
+};
+
+&flx2 {
+	atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_SPI>;
+	status = "okay";
+};
+
+&flx3 {
+	atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_TWI>;
+	status = "okay";
+};
+
+&i2c3 {
+	pinctrl-0 = <&fc3_pins>;
+	pinctrl-names = "default";
+	i2c-analog-filter;
+	i2c-digital-filter;
+	i2c-digital-filter-width-ns = <35>;
+	i2c-sda-hold-time-ns = <1500>;
+	status = "okay";
+};
+
+&mdio0 {
+	pinctrl-0 = <&mdio_pins>, <&mdio_irq_pins>;
+	pinctrl-names = "default";
+	reset-gpios = <&gpio 62 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	phy3: phy at 3 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <3>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy4: phy at 4 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <4>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy5: phy at 5 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <5>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy6: phy at 6 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <6>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy7: phy at 7 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <7>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy8: phy at 8 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <8>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy9: phy at 9 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <9>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy10: phy at 10 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <10>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy11: phy at 11 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <11>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy12: phy at 12 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <12>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy13: phy at 13 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <13>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy14: phy at 14 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <14>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy15: phy at 15 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <15>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy16: phy at 16 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <16>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy17: phy at 17 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <17>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy18: phy at 18 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <18>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy19: phy at 19 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <19>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy20: phy at 20 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <20>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy21: phy at 21 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <21>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy22: phy at 22 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <22>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy23: phy at 23 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <23>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy24: phy at 24 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <24>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy25: phy at 25 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <25>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy26: phy at 26 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <26>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy27: phy at 27 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <27>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+};
+
+&serdes {
+	status = "okay";
+};
+
+&sgpio {
+	pinctrl-0 = <&sgpio_pins>;
+	pinctrl-names = "default";
+	microchip,sgpio-port-ranges = <0 1>, <6 9>;
+	status = "okay";
+
+	gpio at 0 {
+		ngpios = <128>;
+	};
+	gpio at 1 {
+		ngpios = <128>;
+	};
+};
+
+&spi2 {
+	pinctrl-0 = <&fc2_pins>;
+	pinctrl-names = "default";
+	cs-gpios = <&gpio 63 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&switch {
+	pinctrl-0 = <&ptp_out_pins>, <&ptp_ext_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	ethernet-ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port0: port at 0 {
+			reg = <0>;
+			phy-handle = <&phy4>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 0>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port1: port at 1 {
+			reg = <1>;
+			phy-handle = <&phy5>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 0>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port2: port at 2 {
+			reg = <2>;
+			phy-handle = <&phy6>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 0>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port3: port at 3 {
+			reg = <3>;
+			phy-handle = <&phy7>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 0>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port4: port at 4 {
+			reg = <4>;
+			phy-handle = <&phy8>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 1>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port5: port at 5 {
+			reg = <5>;
+			phy-handle = <&phy9>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 1>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port6: port at 6 {
+			reg = <6>;
+			phy-handle = <&phy10>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 1>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port7: port at 7 {
+			reg = <7>;
+			phy-handle = <&phy11>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 1>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port8: port at 8 {
+			reg = <8>;
+			phy-handle = <&phy12>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 2>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port9: port at 9 {
+			reg = <9>;
+			phy-handle = <&phy13>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 2>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port10: port at 10 {
+			reg = <10>;
+			phy-handle = <&phy14>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 2>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port11: port at 11 {
+			reg = <11>;
+			phy-handle = <&phy15>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 2>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port12: port at 12 {
+			reg = <12>;
+			phy-handle = <&phy16>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 3>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port13: port at 13 {
+			reg = <13>;
+			phy-handle = <&phy17>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 3>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port14: port at 14 {
+			reg = <14>;
+			phy-handle = <&phy18>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 3>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port15: port at 15 {
+			reg = <15>;
+			phy-handle = <&phy19>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 3>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port16: port at 16 {
+			reg = <16>;
+			phy-handle = <&phy20>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 4>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port17: port at 17 {
+			reg = <17>;
+			phy-handle = <&phy21>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 4>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port18: port at 18 {
+			reg = <18>;
+			phy-handle = <&phy22>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 4>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port19: port at 19 {
+			reg = <19>;
+			phy-handle = <&phy23>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 4>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port20: port at 20 {
+			reg = <20>;
+			phy-handle = <&phy24>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 5>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port21: port at 21 {
+			reg = <21>;
+			phy-handle = <&phy25>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 5>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port22: port at 22 {
+			reg = <22>;
+			phy-handle = <&phy26>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 5>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port23: port at 23 {
+			reg = <23>;
+			phy-handle = <&phy27>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 5>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port24: port at 24 {
+			reg = <24>;
+			phys = <&serdes 6>;
+			phy-mode = "10gbase-r";
+			sfp = <&sfp0>;
+			managed = "in-band-status";
+			microchip,bandwidth = <10000>;
+			microchip,sd-sgpio = <24>;
+		};
+
+		port25: port at 25 {
+			reg = <25>;
+			phys = <&serdes 7>;
+			phy-mode = "10gbase-r";
+			sfp = <&sfp1>;
+			managed = "in-band-status";
+			microchip,bandwidth = <10000>;
+			microchip,sd-sgpio = <28>;
+		};
+
+		port26: port at 26 {
+			reg = <26>;
+			phys = <&serdes 8>;
+			phy-mode = "10gbase-r";
+			sfp = <&sfp2>;
+			managed = "in-band-status";
+			microchip,bandwidth = <10000>;
+			microchip,sd-sgpio = <32>;
+		};
+
+		port27: port at 27 {
+			reg = <27>;
+			phys = <&serdes 9>;
+			phy-mode = "10gbase-r";
+			sfp = <&sfp3>;
+			managed = "in-band-status";
+			microchip,bandwidth = <10000>;
+			microchip,sd-sgpio = <36>;
+		};
+
+		port29: port at 29 {
+			reg = <29>;
+			phys = <&serdes 11>;
+			phy-handle = <&phy3>;
+			phy-mode = "rgmii-id";
+			microchip,bandwidth = <1000>;
+		};
+	};
+};
+
+&tmon {
+	pinctrl-0 = <&fan_pins>;
+	pinctrl-names = "default";
+};
+
+&usart0 {
+	pinctrl-0 = <&fc0_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&usb {
+	pinctrl-0 = <&usb_ulpi_pins>, <&usb_rst_pins>, <&usb_over_pins>, <&usb_power_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
-- 
2.52.0



From andreas at kemnade.info  Tue Dec 23 12:43:02 2025
From: andreas at kemnade.info (Andreas Kemnade)
Date: Tue, 23 Dec 2025 21:43:02 +0100
Subject: [PATCH] ARM: dts: imx: imx6sll: fix lcdif compatible
Message-ID: <20251223204302.519468-1-andreas@kemnade.info>

Fix lcdif compatible according to bindings doc.

dtbs_check tested only, a glance at the datasheet shows that it should be
the correct fallback compatible.

Signed-off-by: Andreas Kemnade <andreas at kemnade.info>
---
 arch/arm/boot/dts/nxp/imx/imx6sll.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/nxp/imx/imx6sll.dtsi b/arch/arm/boot/dts/nxp/imx/imx6sll.dtsi
index 704870e8c10c..c96669605d1d 100644
--- a/arch/arm/boot/dts/nxp/imx/imx6sll.dtsi
+++ b/arch/arm/boot/dts/nxp/imx/imx6sll.dtsi
@@ -657,7 +657,7 @@ pxp: pxp at 20f0000 {
 			};
 
 			lcdif: lcd-controller at 20f8000 {
-				compatible = "fsl,imx6sll-lcdif", "fsl,imx28-lcdif";
+				compatible = "fsl,imx6sll-lcdif", "fsl,imx6sx-lcdif";
 				reg = <0x020f8000 0x4000>;
 				interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clks IMX6SLL_CLK_LCDIF_PIX>,
-- 
2.47.3



From andreas at kemnade.info  Tue Dec 23 13:34:03 2025
From: andreas at kemnade.info (Andreas Kemnade)
Date: Tue, 23 Dec 2025 22:34:03 +0100
Subject: [PATCH 2/2] ARM: imx_v6_v7_defconfig: enable EPD regulator needed
 for Kobo Clara 2e
In-Reply-To: <20251223-fp9931-clara2e-v1-0-e5b1cb79330a@kemnade.info>
References: <20251223-fp9931-clara2e-v1-0-e5b1cb79330a@kemnade.info>
Message-ID: <20251223-fp9931-clara2e-v1-2-e5b1cb79330a@kemnade.info>

Kobo Clara 2e revision b requires the JD9930/FP9931 regulator driver
for the EPD, so enable it.

Signed-off-by: Andreas Kemnade <andreas at kemnade.info>
---
 arch/arm/configs/imx_v6_v7_defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 0d55056c6f82..94ef23b272fc 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -251,6 +251,7 @@ CONFIG_REGULATOR_DA9052=y
 CONFIG_REGULATOR_DA9062=y
 CONFIG_REGULATOR_DA9063=y
 CONFIG_REGULATOR_GPIO=y
+CONFIG_REGULATOR_FP9931=m
 CONFIG_REGULATOR_LTC3676=y
 CONFIG_REGULATOR_MC13783=y
 CONFIG_REGULATOR_MC13892=y

-- 
2.47.3



From andreas at kemnade.info  Tue Dec 23 13:34:02 2025
From: andreas at kemnade.info (Andreas Kemnade)
Date: Tue, 23 Dec 2025 22:34:02 +0100
Subject: [PATCH 1/2] ARM: dts: imx: imx6sll-kobo-clara2e: add regulator for
 EPD.
In-Reply-To: <20251223-fp9931-clara2e-v1-0-e5b1cb79330a@kemnade.info>
References: <20251223-fp9931-clara2e-v1-0-e5b1cb79330a@kemnade.info>
Message-ID: <20251223-fp9931-clara2e-v1-1-e5b1cb79330a@kemnade.info>

Now there is a driver and binding for the JD9930, so add the information
to the devicetree for revision b.

Signed-off-by: Andreas Kemnade <andreas at kemnade.info>
---
 .../boot/dts/nxp/imx/imx6sll-kobo-clara2e-b.dts    | 61 +++++++++++++++++++++-
 1 file changed, 60 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/nxp/imx/imx6sll-kobo-clara2e-b.dts b/arch/arm/boot/dts/nxp/imx/imx6sll-kobo-clara2e-b.dts
index f81aeacf5142..f5e88764a08c 100644
--- a/arch/arm/boot/dts/nxp/imx/imx6sll-kobo-clara2e-b.dts
+++ b/arch/arm/boot/dts/nxp/imx/imx6sll-kobo-clara2e-b.dts
@@ -16,8 +16,67 @@
 / {
 	model = "Kobo Clara 2E";
 	compatible = "kobo,clara2e-b", "kobo,clara2e", "fsl,imx6sll";
+
+	epd_pmic_supply: regulator-epd-pmic-in {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_epd_pmic_supply>;
+		regulator-name = "epd_pmic_supply";
+		gpio = <&gpio2 14 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		startup-delay-us = <20000>;
+	};
 };
 
 &i2c2 {
-	/* EPD PMIC JD9930 at 0x18 */
+	jd9930: pmic at 18 {
+		compatible = "fitipower,jd9930", "fitipower,fp9931";
+		reg = <0x18>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_jd9930_gpio>;
+		vin-supply = <&epd_pmic_supply>;
+		pg-gpios = <&gpio2 7 GPIO_ACTIVE_HIGH>;
+		en-ts-gpios = <&gpio2 9 GPIO_ACTIVE_HIGH>;
+		enable-gpios = <&gpio2 8 GPIO_ACTIVE_HIGH>;
+		fitipower,tdly-ms = <2 2 2 2>;
+
+		regulators {
+			vcom_reg: vcom {
+				regulator-name = "vcom";
+				/*
+				 * For optimal performance these should be
+				 * tuned on a per batch basis e.g. using
+				 * overlays.
+				 */
+				regulator-min-microvolt = <2352840>;
+				regulator-max-microvolt = <2352840>;
+			};
+
+			vposneg_reg: vposneg {
+				regulator-name = "vposneg";
+				regulator-min-microvolt = <15060000>;
+				regulator-max-microvolt = <15060000>;
+			};
+
+			v3p3_reg: v3p3 {
+				regulator-name = "v3p3";
+			};
+		};
+	};
+};
+
+&iomuxc {
+	pinctrl_jd9930_gpio: jd9930-gpiogrp {
+		fsl,pins = <
+			MX6SLL_PAD_EPDC_PWR_CTRL0__GPIO2_IO07	0x17059 /* PG */
+			MX6SLL_PAD_EPDC_PWR_CTRL1__GPIO2_IO08	0x40010059 /* EN */
+			MX6SLL_PAD_EPDC_PWR_CTRL2__GPIO2_IO09	0x40010059 /* EN_TS */
+		>;
+	};
+
+	pinctrl_epd_pmic_supply: epd-pmic-supplygrp {
+		fsl,pins = <
+			MX6SLL_PAD_EPDC_PWR_WAKE__GPIO2_IO14	0x40010059
+		>;
+	};
 };

-- 
2.47.3



From andreas at kemnade.info  Tue Dec 23 13:34:01 2025
From: andreas at kemnade.info (Andreas Kemnade)
Date: Tue, 23 Dec 2025 22:34:01 +0100
Subject: [PATCH 0/2] ARM: dts: imx: imx6sll-kobo-clara2e add JD9930
 regulator
Message-ID: <20251223-fp9931-clara2e-v1-0-e5b1cb79330a@kemnade.info>

Add the JD9930 regulator to the devicetree and enable the
corresponding driver in the defconfig.

Signed-off-by: Andreas Kemnade <andreas at kemnade.info>
---
Andreas Kemnade (2):
      ARM: dts: imx: imx6sll-kobo-clara2e: add regulator for EPD.
      ARM: imx_v6_v7_defconfig: enable EPD regulator needed for Kobo Clara 2e

 .../boot/dts/nxp/imx/imx6sll-kobo-clara2e-b.dts    | 61 +++++++++++++++++++++-
 arch/arm/configs/imx_v6_v7_defconfig               |  1 +
 2 files changed, 61 insertions(+), 1 deletion(-)
---
base-commit: 9448598b22c50c8a5bb77a9103e2d49f134c9578
change-id: 20251223-fp9931-clara2e-59d1d51d32b0

Best regards,
--  
Andreas Kemnade <andreas at kemnade.info>



From lorenzo at kernel.org  Tue Dec 23 13:56:44 2025
From: lorenzo at kernel.org (Lorenzo Bianconi)
Date: Tue, 23 Dec 2025 22:56:44 +0100
Subject: [PATCH net] net: airoha: Fix schedule while atomic in
 airoha_ppe_deinit()
Message-ID: <20251223-airoha-fw-ethtool-v1-1-1dbd1568c585@kernel.org>

Rely on rcu_replace_pointer in airoha_ppe_deinit routine in order to fix
schedule while atomic issue.

Fixes: 00a7678310fe3 ("net: airoha: Introduce flowtable offload support")
Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
---
 drivers/net/ethernet/airoha/airoha_ppe.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c
index 0caabb0c3aa06948e46ad087c50eba5babc81994..2221bafaf7c9fed73dcf8d30ff3b1c5eecc463d4 100644
--- a/drivers/net/ethernet/airoha/airoha_ppe.c
+++ b/drivers/net/ethernet/airoha/airoha_ppe.c
@@ -1547,13 +1547,16 @@ void airoha_ppe_deinit(struct airoha_eth *eth)
 {
 	struct airoha_npu *npu;
 
-	rcu_read_lock();
-	npu = rcu_dereference(eth->npu);
+	mutex_lock(&flow_offload_mutex);
+
+	npu = rcu_replace_pointer(eth->npu, NULL,
+				  lockdep_is_held(&flow_offload_mutex));
 	if (npu) {
 		npu->ops.ppe_deinit(npu);
 		airoha_npu_put(npu);
 	}
-	rcu_read_unlock();
+
+	mutex_unlock(&flow_offload_mutex);
 
 	rhashtable_destroy(&eth->ppe->l2_flows);
 	rhashtable_destroy(&eth->flow_table);

---
base-commit: 7b8e9264f55a9c320f398e337d215e68cca50131
change-id: 20251223-airoha-fw-ethtool-21f54b02c98b

Best regards,
-- 
Lorenzo Bianconi <lorenzo at kernel.org>



From andreas at kemnade.info  Tue Dec 23 14:24:35 2025
From: andreas at kemnade.info (Andreas Kemnade)
Date: Tue, 23 Dec 2025 23:24:35 +0100
Subject: [PATCH] ARM: dts: imx: imx6sl: fix lcdif compatible
Message-ID: <20251223222435.538096-1-andreas@kemnade.info>

Fix lcdif compatible according to bindings doc.

dtbs_check tested only, a glance at the datasheet shows that it should be
the correct fallback compatible.

Signed-off-by: Andreas Kemnade <andreas at kemnade.info>
---
 arch/arm/boot/dts/nxp/imx/imx6sl.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/nxp/imx/imx6sl.dtsi b/arch/arm/boot/dts/nxp/imx/imx6sl.dtsi
index 7381fb7f8912..13b0474aa42c 100644
--- a/arch/arm/boot/dts/nxp/imx/imx6sl.dtsi
+++ b/arch/arm/boot/dts/nxp/imx/imx6sl.dtsi
@@ -776,7 +776,7 @@ epdc: epdc at 20f4000 {
 			};
 
 			lcdif: lcdif at 20f8000 {
-				compatible = "fsl,imx6sl-lcdif", "fsl,imx28-lcdif";
+				compatible = "fsl,imx6sl-lcdif", "fsl,imx6sx-lcdif";
 				reg = <0x020f8000 0x4000>;
 				interrupts = <0 39 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clks IMX6SL_CLK_LCDIF_PIX>,
-- 
2.47.3



From yang at os.amperecomputing.com  Tue Dec 23 14:59:11 2025
From: yang at os.amperecomputing.com (Yang Shi)
Date: Tue, 23 Dec 2025 14:59:11 -0800
Subject: [PATCH 0/2] introduce pagetable_alloc_nolock()
In-Reply-To: <d96ac977-222e-4e8d-9487-da1306198419@arm.com>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com>
 <916c17ba-22b1-456e-a184-cb3f60249af7@arm.com>
 <aUGOPd7gNRf1xHEc@e129823.arm.com>
 <100cc8da-b826-4fc2-a624-746bf6fb049d@arm.com>
 <aUKKZR0u22KOPfd7@e129823.arm.com>
 <d96ac977-222e-4e8d-9487-da1306198419@arm.com>
Message-ID: <93327680-7d7d-415e-958b-0d2a667dbb52@os.amperecomputing.com>



On 12/17/25 9:04 PM, Ryan Roberts wrote:
> On 17/12/2025 10:48, Yeoreum Yun wrote:
>> Hi Ryan,
>>
>>> On 16/12/2025 16:52, Yeoreum Yun wrote:
>>>> Hi Ryan,
>>>>
>>>>> On 12/12/2025 16:18, Yeoreum Yun wrote:
>>>>>> Some architectures invoke pagetable_alloc() or __get_free_pages()
>>>>>> with preemption disabled.
>>>>>> For example, in arm64, linear_map_split_to_ptes() calls pagetable_alloc()
>>>>>> while spliting block entry to ptes and __kpti_install_ng_mappings()
>>>>>> calls __get_free_pages() to create kpti pagetable.
>>>>>>
>>>>>> Under PREEMPT_RT, calling pagetable_alloc() with
>>>>>> preemption disabled is not allowed, because it may acquire
>>>>>> a spin lock that becomes sleepable on RT, potentially
>>>>>> causing a sleep during page allocation.
>>>>>>
>>>>>> Since above two functions is called as callback of stop_machine()
>>>>>> where its callback is called in preemption disabled,
>>>>>> They could make a potential problem. (sleeping in preemption disabled).
>>>>>>
>>>>>> To address this, introduce pagetable_alloc_nolock() API.
>>>>> I don't really understand what the problem is that you're trying to fix. As I
>>>>> see it, there are 2 call sites in arm64 arch code that are calling into the page
>>>>> allocator from stop_machine() - one via via pagetable_alloc() and another via
>>>>> __get_free_pages(). But both of those calls are passing in GFP_ATOMIC. It was my
>>>>> understanding that the page allocator would ensure it never sleeps when
>>>>> GFP_ATOMIC is passed in, (even for PREEMPT_RT)?
>>>> Although GFP_ATOMIC is specify, it only affects of "water mark" of the
>>>> page with __GFP_HIGH. and to get a page, it must grab the lock --
>>>> zone->lock or pcp_lock in the rmqueue().
>>>>
>>>> This zone->lock and pcp_lock is spin_lock and it's a sleepable in
>>>> PREEMPT_RT that's why the memory allocation/free using general API
>>>> except nolock() version couldn't be called since
>>>> if "contention" happens they'll sleep while waiting to get the lock.
>>>>
>>>> The reason why "nolock()" can use, it always uses "trylock" with
>>>> ALLOC_TRYLOCK flags. otherwise GFP_ATOMIC also can be sleepable in
>>>> PREEMPT_RT.
>>>>
>>>>> What is the actual symptom you are seeing?
>>>> Since the place where called while smp_cpus_done() and there seems no
>>>> contention, there seems no problem. However as I mention in another
>>>> thread
>>>> (https://lore.kernel.org/all/aT%2FdrjN1BkvyAGoi at e129823.arm.com/),
>>>> This gives a the false impression --
>>>> GFP_ATOMIC are ?safe to use in preemption disabled?
>>>> even though they are not in PREEMPT_RT case, I've changed it.
>>>>
>>>>> If the page allocator is somehow ignoring the GFP_ATOMIC request for PREEMPT_RT,
>>>>> then isn't that a bug in the page allocator? I'm not sure why you would change
>>>>> the callsites? Can't you just change the page allocator based on GFP_ATOMIC?
>>>> It doesn't ignore the GFP_ATOMIC feature:
>>>>    - __GFP_HIGH: use water mark till min reserved
>>>>    - __GFP_KSWAPD_RECLAIM: wake up kswapd if reclaim required.
>>>>
>>>> But, it's a restriction -- "page allocation / free" API cannot be called
>>>> in preempt-disabled context at PREEMPT_RT.
>>>>
>>>> That's why I think it's wrong usage not a page allocator bug.
>>> I've taken a look at this and I agree with your analysis. Thanks for explaining.
>>>
>>> Looking at other stop_machine() callbacks, there are some that call printk() and
>>> I would assume that spinlocks could be taken there which may present the same
>>> kind of issue or PREEMPT_RT? (I'm guessing). I don't see any others that attempt
>>> to allocate memory though.
>> IIRC, there was a problem related for printk while try to grab
>> pl011_console related lock (spin_lock) while holding
>> console_lock(raw_spin_lock) in v6.10.0-rc7 at rpi5:
>>
>>      [  230.381263] CPU: 2 PID: 5574 Comm: syz.4.1695 Not tainted 6.10.0-rc7-01903-g52828ea60dfd #3
>>      [  230.381479] Hardware name: linux,dummy-virt (DT)
>>      [  230.381565] Call trace:
>>      [  230.381607]  dump_backtrace+0x318/0x348
>>      [  230.381727]  show_stack+0x4c/0x80
>>      [  230.381875]  dump_stack_lvl+0x214/0x328
>>      [  230.382159]  dump_stack+0x3c/0x58
>>      [  230.382456]  __lock_acquire+0x4398/0x4720
>>      [  230.382683]  lock_acquire+0x648/0xb70
>>      [  230.382928]  _raw_spin_lock_irqsave+0x138/0x240
>>      [  230.383121]  pl011_console_write+0x240/0x8a0
>>      [  230.383356]  console_flush_all+0x708/0x1368
>>      [  230.383571]  console_unlock+0x180/0x440
>>      [  230.383742]  vprintk_emit+0x1f8/0x9d0
>>      [  230.383832]  vprintk_default+0x64/0x90
>>      [  230.383914]  vprintk+0x2d0/0x400
>>      [  230.383971]  _printk+0xdc/0x128
>>      [  230.384229]  hrtimer_interrupt+0x8f0/0x920
>>      [  230.384414]  arch_timer_handler_virt+0xc0/0x100
>>      [  230.384812]  handle_percpu_devid_irq+0x20c/0x4e0
>>      [  230.385053]  generic_handle_domain_irq+0xc0/0x120
>>      [  230.385367]  gic_handle_irq+0x88/0x360
>>      [  230.385559]  call_on_irq_stack+0x24/0x70
>>      [  230.385801]  do_interrupt_handler+0xf8/0x200
>>      [  230.386092]  el1_interrupt+0x68/0xc0
>>      [  230.386434]  el1h_64_irq_handler+0x18/0x28
>>      [  230.386716]  el1h_64_irq+0x64/0x68
>>      [  230.386853]  __sanitizer_cov_trace_const_cmp2+0x30/0x68
>>      [  230.387026]  alloc_pages_mpol_noprof+0x170/0x698
>>      [  230.387309]  vma_alloc_folio_noprof+0x128/0x2a8
>>      [  230.387610]  vma_alloc_zeroed_movable_folio+0xa0/0xe0
>>      [  230.387822]  folio_prealloc+0x5c/0x280
>>      [  230.388008]  do_wp_page+0xc30/0x3bc0
>>      [  230.388206]  __handle_mm_fault+0xdb8/0x2ba0
>>      [  230.388448]  handle_mm_fault+0x194/0x8a8
>>      [  230.388676]  do_page_fault+0x6bc/0x1030
>>      [  230.388924]  do_mem_abort+0x8c/0x240
>>      [  230.389056]  el0_da+0xf0/0x3f8
>>      [  230.389178]  el0t_64_sync_handler+0xb4/0x130
>>      [  230.389452]  el0t_64_sync+0x190/0x198
>>
>> But this problem is gone when I try with some of patches in rt-tree
>> related for printk which are merged in current tree
>> (https://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git/log/?h=linux-6.10.y-rt-rebase).
>>
>> So I think printk() wouldn't be a problem.
>>
>>> Anyway, to fix the 2 arm64 callsites, I see 2 possible approaches:
>>>
>>> - Call the nolock variant (as you are doing). But that would just convert a
>>> deadlock to a panic; if the lock is held when stop_machine() runs, without your
>>> change, we now have a deadlock due to waiting on the lock inside stop_machine().
>>> With your change, we notice the lock is already taken and panic. I guess it is
>>> marginally better, but not by much. Certainly I would just _always_ call the
>>> nolock variant regardless of PREEMPT_RT if we take this route; For !PREEMPT_RT,
>>> the lock is guarranteed to be free so nolock will always succeed.
>>>
>>> - Preallocate the memory before entering stop_machine(). I think this would be
>>> much more robust. For kpti_install_ng_mappings() I think you could hoist the
>>> allocation/free out of stop_machine() and pass the pointer in pretty easily. For
>>> linear_map_split_to_ptes() its a bit more complex; Perhaps, we need to walk the
>>> pgtable to figure out how much to preallocate, allocate it, then set it up as a
>>> special allocator, wrapped by an allocation function and modify the callchain to
>>> take a callback function instead of gfp flags.
>>>
>>> What do you think?
>> Definitely, second suggestoin is much better.
>> My question is whether *memory contention* really happen in the point
>> both functions are called.
> My guess would be that it's unlikely, but not impossible. The secondary CPUs are
> up, and presumably running their idle thread. I think various power management
> things can be plugged into the idle thread; if so, then I guess it's possible
> that the CPU could be running some hook as part of a power state transition, and
> that could be dynamically allocating memory? That's all just a guess though; I
> don't know the details of that part of the system.

Sorry for chiming in late. I was just done my travel, but still suffered 
from jet lag. I may be out of my mind...

I agree the sleeping lock is a problem for -rt kernel. But it is hard 
for me to understand how come the lock contention could happen. When the 
boot CPU is repainting the linear map, the secondary CPUs are running in 
a busy loop to wait for idmap_kpti_bbml2_flag is cleared by the boot CPU 
instead of idle thread. And the secondary CPUs running with idmap active 
and init_mm inactive. So the nolock variant seems good enough to me if I 
don't miss anything.

Thanks,
Yang

>
>> Above two functions are called as last step of "smp_init()" -- smp_cpus_done().
>> If we can be sure, I think we don't need to go to complex way and
>> I believe the reason why we couldn't find out this problem,
>> even using GFP_ATOMIC in PREEMPT_RT since there was *no contection*
>> in this time of both functions are called.
>>> That's why I first try with the "simple way".
>> What do you think?
> As far as linear_map_split_to_ptes() is concerned, it was implemented under the
> impression that doing allocation with GFP_ATOMIC was safe, even in
> stop_machine(). Given that's an incorrect assumption, I think we should fix it
> to pre-allocate outside of stop_machine() regardless of the likelihood of
> actually hitting the race.
>
> Thanks,
> Ryan
>
>> --
>> Sincerely,
>> Yeoreum Yun



From vvidwans at nvidia.com  Tue Dec 23 15:01:29 2025
From: vvidwans at nvidia.com (Vedashree Vidwans)
Date: Tue, 23 Dec 2025 23:01:29 +0000
Subject: [RFC PATCH v2 0/1] firmware: smccc: Add support for Live Firmware Activation (LFA)
In-Reply-To: <20250926123145.268728-1-salman.nabi@arm.com>
References: <20250926123145.268728-1-salman.nabi@arm.com>
Message-ID: <20251223230134.462535-1-vvidwans@nvidia.com>

Hello Salman,

Thank you for the patch. As you might know, I am implementing the
interrupt interface for LFA driver. The LFA usecase I am working
with will validate both interrupt and sysfs interfaces of the LFA
driver. Hence, I would like to extend the driver posted here with
required changes. Please find the extended driver patches posted
at [1].
While working on this code, I realized that LFA driver should
use SMCCC 1.2+ version as per the LFA specification. And I have
included a patch to upgrade SMCCC version in the code.
As the initial LFA driver in this thread isn't merged yet, I would
like to request modification to this original patch based on
a review comment on my patch series.

Could we please come up with a strategy to incorporate the changes?
We are aiming to merge LFA patches to Linux kernel as soon as
possible. Since I am actively working on this driver, I will be
happy to revise the initial patch(with authors intact) and post
a fresh series for review.

Regards,
Veda

[1] https://lore.kernel.org/linux-arm-kernel/20251208221319.1524888-1-vvidwans at nvidia.com/


From martin.blumenstingl at googlemail.com  Tue Dec 23 15:08:54 2025
From: martin.blumenstingl at googlemail.com (Martin Blumenstingl)
Date: Wed, 24 Dec 2025 00:08:54 +0100
Subject: [PATCH 1/2] arm64: dts: amlogic: Use hyphen in node names
In-Reply-To: <20251223152510.155463-3-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251223152510.155463-3-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <CAFBinCBt-Ra__iNTPP2wqbo00VThDQrs-sUWvBR_FisgNwc2kg@mail.gmail.com>

On Tue, Dec 23, 2025 at 4:25?PM Krzysztof Kozlowski
<krzysztof.kozlowski at oss.qualcomm.com> wrote:
>
> DTS coding style prefers hyphens instead of underscores in the node
> names.  Change should be safe, because node names are not considered an
> ABI.
>
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
Reviewed-by: Martin Blumenstingl <martin.blumenstingl at googlemail.com>


From martin.blumenstingl at googlemail.com  Tue Dec 23 15:09:26 2025
From: martin.blumenstingl at googlemail.com (Martin Blumenstingl)
Date: Wed, 24 Dec 2025 00:09:26 +0100
Subject: [PATCH 2/2] arm64: dts: amlogic: Use lowercase hex
In-Reply-To: <20251223152510.155463-4-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251223152510.155463-3-krzysztof.kozlowski@oss.qualcomm.com> <20251223152510.155463-4-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <CAFBinCDRUEKeE1ufjiqX=jr3nrJX6crg-rBVU5DW66WkFA5NAA@mail.gmail.com>

On Tue, Dec 23, 2025 at 4:25?PM Krzysztof Kozlowski
<krzysztof.kozlowski at oss.qualcomm.com> wrote:
>
> The DTS code coding style expects lowercase hex for values and unit
> addresses.
>
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
Reviewed-by: Martin Blumenstingl <martin.blumenstingl at googlemail.com>


From andersson at kernel.org  Tue Dec 23 16:09:44 2025
From: andersson at kernel.org (Bjorn Andersson)
Date: Tue, 23 Dec 2025 18:09:44 -0600
Subject: [PATCH v6 4/5] gpio: rpmsg: add generic rpmsg GPIO driver
In-Reply-To: <PAXPR04MB9185B16A2B08E739B2FB64C889B5A@PAXPR04MB9185.eurprd04.prod.outlook.com>
References: <20251212194341.966387-1-shenwei.wang@nxp.com>
 <20251212194341.966387-5-shenwei.wang@nxp.com>
 <mnpg4xanzl45lal72c6kgog7qmqgk2zcp734eqdpk3gsonq63f@vlewh6jgdjy4>
 <PAXPR04MB9185B16A2B08E739B2FB64C889B5A@PAXPR04MB9185.eurprd04.prod.outlook.com>
Message-ID: <xiqftcgga24bypbux276u56t2lxjy4oxzggixrhy5h7woc4aon@2zbcfxxrzqig>

On Tue, Dec 23, 2025 at 08:20:49PM +0000, Shenwei Wang wrote:
> 
> 
> > -----Original Message-----
> > From: Bjorn Andersson <andersson at kernel.org>
> > Sent: Thursday, December 18, 2025 9:58 AM
> > To: Shenwei Wang <shenwei.wang at nxp.com>
> > Cc: Linus Walleij <linusw at kernel.org>; Bartosz Golaszewski <brgl at kernel.org>;
> > Rob Herring <robh at kernel.org>; Krzysztof Kozlowski <krzk+dt at kernel.org>;
> > Conor Dooley <conor+dt at kernel.org>; Mathieu Poirier
> > <mathieu.poirier at linaro.org>; Shawn Guo <shawnguo at kernel.org>; Sascha
> > Hauer <s.hauer at pengutronix.de>; Jonathan Corbet <corbet at lwn.net>;
> > Pengutronix Kernel Team <kernel at pengutronix.de>; Fabio Estevam
> > On Fri, Dec 12, 2025 at 01:43:40PM -0600, Shenwei Wang wrote:
> > > On an AMP platform, the system may include two processors:
[..]
> > > +static int rpmsg_gpio_callback(struct rpmsg_device *rpdev,
> > > +                            void *data, int len, void *priv, u32 src)
> > > +{
[..]
> > > +     init_completion(&port->info.cmd_complete);
> > > +     port->info.rpdev = pltdata->rpdev;
> > > +     port->info.port_store = pltdata->channel_devices;
> > > +     port->info.port_store[port->idx] = port;
> > > +     if (!pltdata->rx_callback)
> > > +             pltdata->rx_callback = rpmsg_gpio_callback;
> > 
> > What happens if you rmmod your rpmsg gpio driver and then trigger an interrupt?
> > 
> 
> The driver has a rpmsg_gpio_remove_action which will clear the devices in the pltdata->channel_devices[].
> In the rpmsg callback function, it will just return -NODEV error.

When you rmmod the rpmsg_gpio driver, the code will go away, so at the
address of rpmsg_gpio_callback there's going to be some undefined data.

> 
>      if (msg)
>              port = drvdata->channel_devices[msg->port_idx];

So this code is no longer going to be there, or maybe there's some
remnants of it? But jumping to the address of rpmsg_gpio_callback (not
the actual rpmsg_gpio_callback) is best case going to result in a crash.

> 
>      if (!port)
>              return -ENODEV;
> 
> > > +
[..]
> > > +static const struct of_device_id rpmsg_gpio_dt_ids[] = {
> > > +     { .compatible = "rpmsg-gpio" },
> > > +     { /* sentinel */ }
> > > +};
> > > +
> > > +static struct platform_driver rpmsg_gpio_driver = {
> > 
> > It's an "rpmsg gpio driver", but it's a platform_driver...
> > 
> > I don't think this is the correct design, but if it is then this needs to be well
> > documented.
> > 
> > Same thing as platform_data forms a strong ABI between some other driver and
> > this platform_driver, this needs to be well documented (but should be avoided).
> > 
> 
> Are you suggesting to use "rpmsg_driver" framework here?
> 

Yes, making the functional driver bind to the particular rpmsg channel
is exactly what I would expect from a "rpmsg gpio driver".

Regards,
Bjorn

> Thank you very much for the review.
> Shenwei
> 
> > Regards,
> > Bjorn
> > 
> > > +     .driver = {
> > > +             .name = "gpio-rpmsg",
> > > +             .of_match_table = rpmsg_gpio_dt_ids,
> > > +     },
> > > +     .probe = rpmsg_gpio_probe,
> > > +};
> > > +
> > > +module_platform_driver(rpmsg_gpio_driver);
> > > +
> > > +MODULE_AUTHOR("Shenwei Wang <shenwei.wang at nxp.com>");
> > > +MODULE_DESCRIPTION("generic rpmsg gpio driver");
> > > +MODULE_LICENSE("GPL");
> > > --
> > > 2.43.0
> > >


From andersson at kernel.org  Tue Dec 23 16:15:27 2025
From: andersson at kernel.org (Bjorn Andersson)
Date: Tue, 23 Dec 2025 18:15:27 -0600
Subject: [PATCH v6 2/5] remoteproc: imx_rproc: Populate devices under
 "rpmsg" subnode
In-Reply-To: <PAXPR04MB9185AF0B5225CB8DD06F774289B5A@PAXPR04MB9185.eurprd04.prod.outlook.com>
References: <20251212194341.966387-1-shenwei.wang@nxp.com>
 <20251212194341.966387-3-shenwei.wang@nxp.com>
 <3bbemd2vbsfss3sqpjpokytvvzweoqrtiqygffj5vqazqk3jyq@eobv6ruriiwb>
 <PAXPR04MB9185AF0B5225CB8DD06F774289B5A@PAXPR04MB9185.eurprd04.prod.outlook.com>
Message-ID: <ctrcrgvevo2liu7v4us4aa37pmt5bytkky2mcvacp5bhmkjl22@sfwzfkgemtyf>

On Tue, Dec 23, 2025 at 07:47:31PM +0000, Shenwei Wang wrote:
> 
> 
> > -----Original Message-----
> > From: Bjorn Andersson <andersson at kernel.org>
> > Sent: Thursday, December 18, 2025 8:24 PM
> > To: Shenwei Wang <shenwei.wang at nxp.com>
> > Cc: Linus Walleij <linusw at kernel.org>; Bartosz Golaszewski <brgl at kernel.org>;
> > Rob Herring <robh at kernel.org>; Krzysztof Kozlowski <krzk+dt at kernel.org>;
> > Conor Dooley <conor+dt at kernel.org>; Mathieu Poirier
> > <mathieu.poirier at linaro.org>; Shawn Guo <shawnguo at kernel.org>; Sascha
> > Hauer <s.hauer at pengutronix.de>; Jonathan Corbet <corbet at lwn.net>;
> > Pengutronix Kernel Team <kernel at pengutronix.de>; Fabio Estevam
> > <festevam at gmail.com>; Peng Fan <peng.fan at nxp.com>; linux-
> > gpio at vger.kernel.org; devicetree at vger.kernel.org; linux-
> > kernel at vger.kernel.org; linux-remoteproc at vger.kernel.org; imx at lists.linux.dev;
> > linux-arm-kernel at lists.infradead.org; linux-doc at vger.kernel.org; dl-linux-imx
> > <linux-imx at nxp.com>
> > Subject: [EXT] Re: [PATCH v6 2/5] remoteproc: imx_rproc: Populate devices
> > under "rpmsg" subnode
> > 
> > Caution: This is an external email. Please take care when clicking links or opening
> > attachments. When in doubt, report the message using the 'Report this email'
> > button
> > 
> > 
> > On Fri, Dec 12, 2025 at 01:43:38PM -0600, Shenwei Wang wrote:
> > > Register the RPMsg channel driver and populate remote devices defined
> > > under the "rpmsg" subnode upon receiving their notification messages.
> > 
> > Please provide a proper description of what "problem" this patch solves.
> > 
> > >
> > > The following illustrates the expected DTS layout structure:
> > >
> > >       cm33: remoteproc-cm33 {
> > >               compatible = "fsl,imx8ulp-cm33";
> > >
> > >               rpmsg {
> > >                       rpmsg-io-channel {
> > >                               gpio at 0 {
> > >                                       compatible = "fsl,imx-rpmsg-gpio";
> > >                                       reg = <0>;
> > 
> > Surely there needs to be some "gpio-controller" and "#gpio-cells" here?
> > Would be useful if the example is somewhat complete, to give a picture of what's
> > actually going on.
> > 
> 
> Okay. Will add those in next version.
> 
> > >                               };
> > >
> > >                               gpio at 1 {
> > >                                       compatible = "fsl,imx-rpmsg-gpio";
> > >                                       reg = <1>;
> > >                               };
> > >
> > >                               ...
> > >                       };
> > >
> > >                       ...
> > >               };
> > >       };
> > >
> > > +     drvdata->rpdev = rpdev;
> > > +     auxdata[0].compatible = devm_kstrdup(dev, imx_rpdrv->compat,
> > GFP_KERNEL);
> > > +     auxdata[0].platform_data = drvdata;
> > > +     dev_set_drvdata(dev, drvdata);
> > > +
> > > +     of_platform_populate(drvdata->channel_node, NULL, auxdata, dev);
> > 
> > auxiliary_bus would be a better choice, but I don't understand why you probe a
> > rpmsg_device for each "gpio channel" and then from that create a
> > platform_device.
> > 
> > Why don't you just make the rpmsg_device register the gpio controller directly?
> > 
> 
> The "GPIO channel" is just one example-there are also "PWM channel", "I2C channel", and other channels. 
> The goal is to manage all these channels under a common logic, which helps avoid redundant code and keeps 
> the implementation consistent.
> 

If you make rpmsg_drivers for each of these channels/functions, then all
the common code should already be in the rpmsg framework.

What are you missing there?

> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +     rp_driver->rpdrv.drv.name = name;
> > > +     rp_driver->rpdrv.id_table = rpdev_id;
> > > +     rp_driver->rpdrv.probe = imx_rpmsg_endpoint_probe;
> > > +     rp_driver->rpdrv.remove = imx_rpmsg_endpoint_remove;
> > > +     rp_driver->rpdrv.callback = imx_rpmsg_endpoint_cb;
> > > +     rp_driver->driver_data = driver_data;
> > > +     rp_driver->compat = compat;
> > > +
> > > +     register_rpmsg_driver(&rp_driver->rpdrv);
> > 
> > This would then also imply that it's the gpio driver that registers the
> > rpmsg_driver.
> > 
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +static int rproc_of_rpmsg_node_init(struct platform_device *pdev) {
> > > +     struct device *dev = &pdev->dev;
> > > +     const char *compat;
> > > +     int ret;
> > > +
> > > +     struct device_node *np __free(device_node) = of_get_child_by_name(dev-
> > >of_node, "rpmsg");
> > > +     if (!np)
> > > +             return 0;
> > > +
> > > +     for_each_child_of_node_scoped(np, child) {
> > > +             compat = imx_of_rpmsg_is_in_map(child->name);
> > > +             if (!compat)
> > > +                     ret = of_platform_default_populate(child, NULL,
> > > + dev);
> > 
> > So if you don't recognize the child device node name you just register
> > platform_devices for each of the children?
> > 
> 
> Yes. That would register platform_devices without the platform_data.
> 
> > > +             else
> > > +                     ret = imx_of_rpmsg_register_rpdriver(child, dev,
> > > + child->name, compat);
> > > +
> > > +             if (ret < 0)
> > > +                     return ret;
> > > +     }
> > > +
> > > +     return 0;
> > > +}
> > > +
> > >  static int imx_rproc_probe(struct platform_device *pdev)  {
> > >       struct device *dev = &pdev->dev; @@ -1114,6 +1253,10 @@ static
> > > int imx_rproc_probe(struct platform_device *pdev)
> > >               goto err_put_pm;
> > >       }
> > >
> > > +     ret = rproc_of_rpmsg_node_init(pdev);
> > > +     if (ret < 0)
> > > +             dev_info(dev, "populating 'rpmsg' node failed\n");
> > > +
> > >       return 0;
> > >
> > >  err_put_pm:
> > > diff --git a/include/linux/rpmsg/rpdev_info.h
> > > b/include/linux/rpmsg/rpdev_info.h
> > > new file mode 100644
> > > index 000000000000..13e020cd028b
> > > --- /dev/null
> > > +++ b/include/linux/rpmsg/rpdev_info.h
> > > @@ -0,0 +1,33 @@
> > > +/* SPDX-License-Identifier: GPL-2.0 */
> > > +/* Copyright 2025 NXP */
> > > +
> > > +/*
> > > + * @file linux/rpdev_info.h
> > > + *
> > > + * @brief Global header file for RPDEV Info
> > > + *
> > > + * @ingroup RPMSG
> > > + */
> > > +#ifndef __LINUX_RPDEV_INFO_H__
> > > +#define __LINUX_RPDEV_INFO_H__
> > > +
> > > +#define MAX_DEV_PER_CHANNEL    10
> > > +
> > > +/**
> > > + * rpdev_platform_info - store the platform information of rpdev
> > > + * @rproc_name: the name of the remote proc.
> > > + * @rpdev: rpmsg channel device
> > > + * @device_node: pointer to the device node of the rpdev.
> > > + * @rx_callback: rx callback handler of the rpdev.
> > > + * @channel_devices: an array of the devices related to the rpdev.
> > > + */
> > > +struct rpdev_platform_info {
> > 
> > I don't understand what this structure represents. Why is this glue between the
> > rpmsg_device and a made up platform_device needed?
> > 
> 
> The purpose is to have a shared array that can be accessed by all devices within 
> the same channel.
> 

What does this mean? How are multiple functions multiplexed over a
single rpmsg channel/endpoint?

Please provide a concrete description of how a device with some gpios
and PWMs would actually look in this model.

> > > +     const char *rproc_name;
> > 
> > You don't need this, because you can rproc_get_by_child(&self) and then get the
> > remoteproc name from that.
> > 
> 
> Good to know. Will try it in the next version.
> 
> > > +     struct rpmsg_device *rpdev;
> > > +     struct device_node *channel_node;
> > > +     int (*rx_callback)(struct rpmsg_device *rpdev, void *data,
> > > +                        int len, void *priv, u32 src);
> > > +     void *channel_devices[MAX_DEV_PER_CHANNEL];
> > 
> > Why 10? What does it mean?
> > 
> 
> This is based on practical experience. For example, on the i.MX platform, we typically don't have 
> more than eight same devices on the remote system.
> 
> > I think this becomes the list of the 10 grandchildren of the remoteproc (per child
> > node). So what happens if those matches against two different drivers, what will
> > rx_callback point to?
> > 
> 
> This is the limitation. That's why I used the map to populate the known child device for one specific channel.
> 

So for each rpdev_platform_info there can only be one type of client
driver. Where is this limitation defined? What happens if I put a PWM
and a GPIO controller under my rpmsg-io-channel?

Regards,
Bjorn

> Thanks,
> Shenwei
> 
> > > +};
> > 
> > Regards,
> > Bjorn
> > 
> > > +
> > > +#endif /* __LINUX_RPDEV_INFO_H__ */
> > > --
> > > 2.43.0
> > >


From dmitry.baryshkov at oss.qualcomm.com  Tue Dec 23 17:02:49 2025
From: dmitry.baryshkov at oss.qualcomm.com (Dmitry Baryshkov)
Date: Wed, 24 Dec 2025 03:02:49 +0200
Subject: [PATCH v3 00/10] drm/connector: hdmi: limit infoframes per driver
 capabilities, second approach
Message-ID: <20251224-limit-infoframes-2-v3-0-7fd3cacfefed@oss.qualcomm.com>

It's not uncommon for the particular device to support only a subset of
HDMI InfoFrames. Currently it's mostly ignored by the framework: it
calls write_infoframe() / clear_infoframe() callbacks for all frames and
expects them to return success even if the InfoFrame is not supported.

Sort that out, making sure that all interfaces are consistent:
- split function interfaces, having a pair of callbacks per each
  InfoFrame type.
- write_infoframe() / clear_infoframe() functions return -EOPNOTSUPP
  for unsupported InfoFrames.
- don't create and enable unsupported InfoFrames.
- limit debugfs to provide supported InfoFrames only.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
---
Changes in v3:
- Added DRM KUnit tests verifying InfoFrames behaviour (Maxime)
- Reworked the patchset, having per-infoframe callbacks rather than
  extra flags (Maxime)
- Link to v2: https://lore.kernel.org/r/20250928-limit-infoframes-2-v2-0-6f8f5fd04214 at oss.qualcomm.com

Changes in v2:
- Fixed build issue in common code
- Fixed comments regarding HDR / audio frames (Diedrik)
- In adv7511 actually check for the HDR frame (the comment was correct)
  rather than the audio infoframe (c&p error).
- Link to v1: https://lore.kernel.org/r/20250927-limit-infoframes-2-v1-0-697511bd050b at oss.qualcomm.com

---
Dmitry Baryshkov (10):
      drm/tests: hdmi: check the infoframes behaviour
      drm/vc4: hdmi: implement clear_infoframe
      drm/sun4i: hdmi_enc: implement clear_infoframe stub
      drm/connector: make clear_infoframe callback mandatory for HDMI connectors
      drm/bridge: refactor HDMI InfoFrame callbacks
      drm/display: hdmi_state_helper: split InfoFrame functions per type
      drm/display: hdmi_state_helper: reject Audio IF updates if it's not supported
      drm/display: hdmi_state_helper: don't generate unsupported InfoFrames
      drm/display: bridge_connector: dynamically generate HDMI callbacks
      drm/debug: don't register files for unsupported HDMI InfoFrames

 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c       | 180 ++++---
 drivers/gpu/drm/bridge/ite-it6263.c                |  95 ++--
 drivers/gpu/drm/bridge/lontium-lt9611.c            | 143 +++---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c       | 110 +++--
 drivers/gpu/drm/display/drm_bridge_connector.c     | 190 +++++++-
 drivers/gpu/drm/display/drm_hdmi_state_helper.c    |  94 ++--
 drivers/gpu/drm/drm_connector.c                    |   6 +
 drivers/gpu/drm/drm_debugfs.c                      |   7 +
 drivers/gpu/drm/mediatek/mtk_hdmi_common.c         |   8 +-
 drivers/gpu/drm/mediatek/mtk_hdmi_v2.c             | 110 +++--
 drivers/gpu/drm/msm/hdmi/hdmi_bridge.c             | 195 ++++----
 drivers/gpu/drm/rockchip/inno_hdmi.c               |  47 +-
 drivers/gpu/drm/rockchip/rk3066_hdmi.c             |  47 +-
 drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c             |  42 +-
 drivers/gpu/drm/tests/drm_client_modeset_test.c    |   3 +
 drivers/gpu/drm/tests/drm_connector_test.c         |  19 +
 drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 525 +++++++++++++++++++++
 drivers/gpu/drm/tests/drm_kunit_edid.h             | 119 +++++
 drivers/gpu/drm/vc4/vc4_hdmi.c                     | 105 ++++-
 include/drm/drm_bridge.h                           | 127 ++++-
 include/drm/drm_connector.h                        | 105 +++--
 21 files changed, 1762 insertions(+), 515 deletions(-)
---
base-commit: e05b08d7d0162cf77fff119367fb1a2d5ab3e669
change-id: 20250927-limit-infoframes-2-6b93e599e79a

Best regards,
-- 
With best wishes
Dmitry



From dmitry.baryshkov at oss.qualcomm.com  Tue Dec 23 17:02:50 2025
From: dmitry.baryshkov at oss.qualcomm.com (Dmitry Baryshkov)
Date: Wed, 24 Dec 2025 03:02:50 +0200
Subject: [PATCH v3 01/10] drm/tests: hdmi: check the infoframes behaviour
In-Reply-To: <20251224-limit-infoframes-2-v3-0-7fd3cacfefed@oss.qualcomm.com>
References: <20251224-limit-infoframes-2-v3-0-7fd3cacfefed@oss.qualcomm.com>
Message-ID: <20251224-limit-infoframes-2-v3-1-7fd3cacfefed@oss.qualcomm.com>

Verify the InfoFrames behaviour. Check that reporting InfoFrame as
unsupported doesn't result in a commit error. Also check that HDR and
Audio InfoFrames are not triggered if corresponding features are not
enabled.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
---
 drivers/gpu/drm/tests/drm_client_modeset_test.c    |   3 +
 drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 485 +++++++++++++++++++++
 drivers/gpu/drm/tests/drm_kunit_edid.h             | 119 +++++
 3 files changed, 607 insertions(+)

diff --git a/drivers/gpu/drm/tests/drm_client_modeset_test.c b/drivers/gpu/drm/tests/drm_client_modeset_test.c
index 3f44fe5e92e4..ec58fe064d86 100644
--- a/drivers/gpu/drm/tests/drm_client_modeset_test.c
+++ b/drivers/gpu/drm/tests/drm_client_modeset_test.c
@@ -5,6 +5,7 @@
 
 #include <kunit/test.h>
 
+#include <drm/drm_atomic_state_helper.h>
 #include <drm/drm_connector.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_drv.h>
@@ -48,6 +49,8 @@ static const struct drm_connector_helper_funcs drm_client_modeset_connector_help
 };
 
 static const struct drm_connector_funcs drm_client_modeset_connector_funcs = {
+	.atomic_destroy_state   = drm_atomic_helper_connector_destroy_state,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state
 };
 
 static int drm_client_modeset_test_init(struct kunit *test)
diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
index 8bd412735000..bdf14a0623b2 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -40,6 +40,9 @@ struct drm_atomic_helper_connector_hdmi_priv {
 #define connector_to_priv(c) \
 	container_of_const(c, struct drm_atomic_helper_connector_hdmi_priv, connector)
 
+#define encoder_to_priv(e) \
+	container_of_const(e, struct drm_atomic_helper_connector_hdmi_priv, encoder)
+
 static struct drm_display_mode *find_preferred_mode(struct drm_connector *connector)
 {
 	struct drm_device *drm = connector->dev;
@@ -138,6 +141,24 @@ static const struct drm_connector_funcs dummy_connector_funcs = {
 	.reset			= dummy_hdmi_connector_reset,
 };
 
+static int hdmi_update_failures;
+
+static void test_encoder_atomic_enable(struct drm_encoder *encoder,
+			      struct drm_atomic_state *state)
+{
+	struct drm_atomic_helper_connector_hdmi_priv *priv =
+		encoder_to_priv(encoder);
+	int ret;
+
+	ret = drm_atomic_helper_connector_hdmi_update_infoframes(&priv->connector, state);
+	if (ret)
+		hdmi_update_failures++;
+}
+
+static const struct drm_encoder_helper_funcs test_encoder_helper_funcs = {
+	.atomic_enable = test_encoder_atomic_enable,
+};
+
 static
 struct drm_atomic_helper_connector_hdmi_priv *
 __connector_hdmi_init(struct kunit *test,
@@ -2323,10 +2344,474 @@ static struct kunit_suite drm_atomic_helper_connector_hdmi_mode_valid_test_suite
 	.test_cases	= drm_atomic_helper_connector_hdmi_mode_valid_tests,
 };
 
+/*
+ * Test that the default behaviour works without errors.
+ */
+static void drm_test_check_infoframes(struct kunit *test)
+{
+	struct drm_atomic_helper_connector_hdmi_priv *priv;
+	struct drm_modeset_acquire_ctx ctx;
+	struct drm_connector_state *new_conn_state;
+	struct drm_crtc_state *crtc_state;
+	struct drm_atomic_state *state;
+	struct drm_display_mode *preferred;
+	struct drm_connector *conn;
+	struct drm_device *drm;
+	struct drm_crtc *crtc;
+	int old_hdmi_update_failures;
+	int ret;
+
+	priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+				BIT(HDMI_COLORSPACE_RGB),
+				8,
+				&dummy_connector_hdmi_funcs,
+				test_edid_hdmi_1080p_rgb_max_200mhz);
+	KUNIT_ASSERT_NOT_NULL(test, priv);
+
+	drm = &priv->drm;
+	crtc = priv->crtc;
+	conn = &priv->connector;
+
+	preferred = find_preferred_mode(conn);
+	KUNIT_ASSERT_NOT_NULL(test, preferred);
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+	ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+						     crtc, conn,
+						     preferred,
+						     &ctx);
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+	new_conn_state = drm_atomic_get_connector_state(state, conn);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
+
+	crtc_state = drm_atomic_get_crtc_state(state, crtc);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+	crtc_state->mode_changed = true;
+
+	old_hdmi_update_failures = hdmi_update_failures;
+
+	ret = drm_atomic_check_only(state);
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	ret = drm_atomic_commit(state);
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	KUNIT_ASSERT_EQ(test, old_hdmi_update_failures, hdmi_update_failures);
+
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+}
+
+static int reject_avi_infoframe_write_infoframe(struct drm_connector *connector,
+						enum hdmi_infoframe_type type,
+						const u8 *buffer, size_t len)
+{
+	if (type == HDMI_INFOFRAME_TYPE_AVI)
+		return -EOPNOTSUPP;
+
+	return 0;
+}
+
+static const struct drm_connector_hdmi_funcs reject_avi_infoframe_hdmi_funcs = {
+	.write_infoframe = reject_avi_infoframe_write_infoframe,
+};
+
+/*
+ * Test that the rejection of AVI InfoFrame results in the failure of
+ * drm_atomic_helper_connector_hdmi_update_infoframes().
+ */
+static void drm_test_check_reject_avi_infoframe(struct kunit *test)
+{
+	struct drm_atomic_helper_connector_hdmi_priv *priv;
+	struct drm_modeset_acquire_ctx ctx;
+	struct drm_atomic_state *state;
+	struct drm_connector_state *new_conn_state;
+	struct drm_crtc_state *crtc_state;
+	struct drm_display_mode *preferred;
+	struct drm_connector *conn;
+	struct drm_device *drm;
+	struct drm_crtc *crtc;
+	int old_hdmi_update_failures;
+	int ret;
+
+	priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+				BIT(HDMI_COLORSPACE_RGB),
+				8,
+				&reject_avi_infoframe_hdmi_funcs,
+				test_edid_hdmi_1080p_rgb_max_200mhz);
+	KUNIT_ASSERT_NOT_NULL(test, priv);
+
+	drm = &priv->drm;
+	crtc = priv->crtc;
+	conn = &priv->connector;
+
+	preferred = find_preferred_mode(conn);
+	KUNIT_ASSERT_NOT_NULL(test, preferred);
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+	ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+						     crtc, conn,
+						     preferred,
+						     &ctx);
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	drm_encoder_helper_add(&priv->encoder, &test_encoder_helper_funcs);
+
+	state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+	new_conn_state = drm_atomic_get_connector_state(state, conn);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
+
+	crtc_state = drm_atomic_get_crtc_state(state, crtc);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+	crtc_state->mode_changed = true;
+
+	old_hdmi_update_failures = hdmi_update_failures;
+
+	ret = drm_atomic_check_only(state);
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	ret = drm_atomic_commit(state);
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	KUNIT_ASSERT_NE(test, old_hdmi_update_failures, hdmi_update_failures);
+
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+}
+
+static int reject_hdr_infoframe_write_infoframe(struct drm_connector *connector,
+						enum hdmi_infoframe_type type,
+						const u8 *buffer, size_t len)
+{
+	if (type == HDMI_INFOFRAME_TYPE_DRM)
+		return -EOPNOTSUPP;
+
+	return 0;
+}
+
+static const struct drm_connector_hdmi_funcs reject_hdr_infoframe_hdmi_funcs = {
+	.write_infoframe = reject_hdr_infoframe_write_infoframe,
+};
+
+/*
+ * Test that the HDR InfoFrame isn't programmed in
+ * drm_atomic_helper_connector_hdmi_update_infoframes() if the max_bpc is 8.
+ */
+static void drm_test_check_reject_hdr_infoframe_bpc_8(struct kunit *test)
+{
+	struct drm_atomic_helper_connector_hdmi_priv *priv;
+	struct drm_modeset_acquire_ctx ctx;
+	struct drm_atomic_state *state;
+	struct drm_connector_state *new_conn_state;
+	struct drm_crtc_state *crtc_state;
+	struct drm_display_mode *preferred;
+	struct drm_connector *conn;
+	struct drm_device *drm;
+	struct drm_crtc *crtc;
+	int old_hdmi_update_failures;
+	int ret;
+
+	priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+				BIT(HDMI_COLORSPACE_RGB),
+				8,
+				&reject_hdr_infoframe_hdmi_funcs,
+				test_edid_hdmi_1080p_rgb_max_200mhz_hdr);
+	KUNIT_ASSERT_NOT_NULL(test, priv);
+
+	drm = &priv->drm;
+	crtc = priv->crtc;
+	conn = &priv->connector;
+
+	preferred = find_preferred_mode(conn);
+	KUNIT_ASSERT_NOT_NULL(test, preferred);
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+	ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+						     crtc, conn,
+						     preferred,
+						     &ctx);
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	drm_encoder_helper_add(&priv->encoder, &test_encoder_helper_funcs);
+
+	state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+	new_conn_state = drm_atomic_get_connector_state(state, conn);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
+
+	crtc_state = drm_atomic_get_crtc_state(state, crtc);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+	/* Verify that there is no HDR property, so "userspace" can't set it. */
+	for (int i = 0; i < conn->base.properties->count; i++)
+		KUNIT_ASSERT_PTR_NE(test,
+				    drm->mode_config.hdr_output_metadata_property,
+				    conn->base.properties->properties[i]);
+
+	crtc_state->mode_changed = true;
+
+	old_hdmi_update_failures = hdmi_update_failures;
+
+	ret = drm_atomic_check_only(state);
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	ret = drm_atomic_commit(state);
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	KUNIT_ASSERT_EQ(test, old_hdmi_update_failures, hdmi_update_failures);
+
+	new_conn_state = conn->state;
+	KUNIT_ASSERT_NOT_NULL(test, new_conn_state);
+
+	KUNIT_ASSERT_EQ(test, new_conn_state->hdmi.output_bpc, 8);
+	KUNIT_ASSERT_EQ(test, new_conn_state->hdmi.infoframes.hdr_drm.set, false);
+
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+}
+
+/*
+ * Test that the rejection of HDR InfoFrame results in the failure of
+ * drm_atomic_helper_connector_hdmi_update_infoframes() in the high bpc is
+ * supported.
+ */
+static void drm_test_check_reject_hdr_infoframe_bpc_10(struct kunit *test)
+{
+	struct drm_atomic_helper_connector_hdmi_priv *priv;
+	struct drm_modeset_acquire_ctx ctx;
+	struct drm_atomic_state *state;
+	struct drm_connector_state *new_conn_state;
+	struct drm_crtc_state *crtc_state;
+	struct drm_display_mode *preferred;
+	struct drm_connector *conn;
+	struct drm_device *drm;
+	struct drm_crtc *crtc;
+	int old_hdmi_update_failures;
+	struct hdr_output_metadata hdr_data;
+	struct drm_property_blob *hdr_blob;
+	bool replaced;
+	int ret;
+
+	priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+				BIT(HDMI_COLORSPACE_RGB),
+				10,
+				&reject_hdr_infoframe_hdmi_funcs,
+				test_edid_hdmi_1080p_rgb_max_200mhz_hdr);
+	KUNIT_ASSERT_NOT_NULL(test, priv);
+
+	drm = &priv->drm;
+	crtc = priv->crtc;
+	conn = &priv->connector;
+
+	preferred = find_preferred_mode(conn);
+	KUNIT_ASSERT_NOT_NULL(test, preferred);
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+	ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+						     crtc, conn,
+						     preferred,
+						     &ctx);
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	drm_encoder_helper_add(&priv->encoder, &test_encoder_helper_funcs);
+
+	state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+	new_conn_state = drm_atomic_get_connector_state(state, conn);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
+
+	crtc_state = drm_atomic_get_crtc_state(state, crtc);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+	hdr_data.metadata_type = HDMI_STATIC_METADATA_TYPE1;
+	hdr_data.hdmi_metadata_type1.eotf = HDMI_EOTF_TRADITIONAL_GAMMA_SDR;
+	hdr_data.hdmi_metadata_type1.metadata_type = HDMI_STATIC_METADATA_TYPE1;
+
+	hdr_blob = drm_property_create_blob(drm, sizeof(hdr_data), &hdr_data);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hdr_blob);
+
+	ret = drm_property_replace_blob_from_id(drm,
+						&new_conn_state->hdr_output_metadata,
+						hdr_blob->base.id,
+						sizeof(struct hdr_output_metadata), -1,
+						&replaced);
+	KUNIT_ASSERT_EQ(test, ret, 0);
+	KUNIT_ASSERT_EQ(test, replaced, true);
+
+	crtc_state->mode_changed = true;
+
+	old_hdmi_update_failures = hdmi_update_failures;
+
+	ret = drm_atomic_check_only(state);
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	ret = drm_atomic_commit(state);
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	KUNIT_ASSERT_NE(test, old_hdmi_update_failures, hdmi_update_failures);
+
+	new_conn_state = conn->state;
+	KUNIT_ASSERT_NOT_NULL(test, new_conn_state);
+
+	KUNIT_ASSERT_EQ(test, new_conn_state->hdmi.output_bpc, 10);
+	KUNIT_ASSERT_EQ(test, new_conn_state->hdmi.infoframes.hdr_drm.set, true);
+
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+}
+
+static int reject_audio_infoframe_write_infoframe(struct drm_connector *connector,
+						  enum hdmi_infoframe_type type,
+						  const u8 *buffer, size_t len)
+{
+	if (type == HDMI_INFOFRAME_TYPE_AUDIO)
+		return -EOPNOTSUPP;
+
+	return 0;
+}
+
+static const struct drm_connector_hdmi_funcs reject_audio_infoframe_hdmi_funcs = {
+	.write_infoframe = reject_audio_infoframe_write_infoframe,
+};
+
+/*
+ * Test that Audio InfoFrame is only programmed if we call a corresponding API,
+ * thus the drivers can safely assume that they won't get Audio InfoFrames if
+ * they don't call it.
+ */
+static void drm_test_check_reject_audio_infoframe(struct kunit *test)
+{
+	struct drm_atomic_helper_connector_hdmi_priv *priv;
+	struct drm_modeset_acquire_ctx ctx;
+	struct drm_atomic_state *state;
+	struct drm_connector_state *new_conn_state;
+	struct drm_crtc_state *crtc_state;
+	struct drm_display_mode *preferred;
+	struct drm_connector *conn;
+	struct drm_device *drm;
+	struct drm_crtc *crtc;
+	int old_hdmi_update_failures;
+	struct hdmi_audio_infoframe cea;
+	int ret;
+
+	priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+				BIT(HDMI_COLORSPACE_RGB),
+				8,
+				&reject_audio_infoframe_hdmi_funcs,
+				test_edid_hdmi_1080p_rgb_max_200mhz);
+	KUNIT_ASSERT_NOT_NULL(test, priv);
+
+	drm = &priv->drm;
+	crtc = priv->crtc;
+	conn = &priv->connector;
+
+	preferred = find_preferred_mode(conn);
+	KUNIT_ASSERT_NOT_NULL(test, preferred);
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+	ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+						     crtc, conn,
+						     preferred,
+						     &ctx);
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	drm_encoder_helper_add(&priv->encoder, &test_encoder_helper_funcs);
+
+	state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+	new_conn_state = drm_atomic_get_connector_state(state, conn);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
+
+	crtc_state = drm_atomic_get_crtc_state(state, crtc);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+	crtc_state->mode_changed = true;
+
+	old_hdmi_update_failures = hdmi_update_failures;
+
+	ret = drm_atomic_check_only(state);
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	ret = drm_atomic_commit(state);
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	KUNIT_ASSERT_EQ(test, old_hdmi_update_failures, hdmi_update_failures);
+
+	/*
+	 * So, it works without Audio InfoFrame, let's fail with it in place,
+	 * checking that writing the infofraem actually gets triggered.
+	 */
+
+	hdmi_audio_infoframe_init(&cea);
+	cea.channels = 2;
+	cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM;
+	cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM;
+	cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM;
+
+	ret = drm_atomic_helper_connector_hdmi_update_audio_infoframe(conn, &cea);
+	KUNIT_ASSERT_EQ(test, ret, -EOPNOTSUPP);
+
+	state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+	new_conn_state = drm_atomic_get_connector_state(state, conn);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
+
+	crtc_state = drm_atomic_get_crtc_state(state, crtc);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+	crtc_state->mode_changed = true;
+
+	old_hdmi_update_failures = hdmi_update_failures;
+
+	ret = drm_atomic_check_only(state);
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	ret = drm_atomic_commit(state);
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	KUNIT_ASSERT_NE(test, old_hdmi_update_failures, hdmi_update_failures);
+
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+}
+
+
+static struct kunit_case drm_atomic_helper_connector_hdmi_infoframes_tests[] = {
+	KUNIT_CASE(drm_test_check_infoframes),
+	KUNIT_CASE(drm_test_check_reject_avi_infoframe),
+	KUNIT_CASE(drm_test_check_reject_hdr_infoframe_bpc_8),
+	KUNIT_CASE(drm_test_check_reject_hdr_infoframe_bpc_10),
+	KUNIT_CASE(drm_test_check_reject_audio_infoframe),
+	{ }
+};
+
+static struct kunit_suite drm_atomic_helper_connector_hdmi_infoframes_test_suite = {
+	.name		= "drm_atomic_helper_connector_hdmi_infoframes",
+	.test_cases	= drm_atomic_helper_connector_hdmi_infoframes_tests,
+};
+
 kunit_test_suites(
 	&drm_atomic_helper_connector_hdmi_check_test_suite,
 	&drm_atomic_helper_connector_hdmi_reset_test_suite,
 	&drm_atomic_helper_connector_hdmi_mode_valid_test_suite,
+	&drm_atomic_helper_connector_hdmi_infoframes_test_suite,
 );
 
 MODULE_AUTHOR("Maxime Ripard <mripard at kernel.org>");
diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.h b/drivers/gpu/drm/tests/drm_kunit_edid.h
index c59c8528a3f7..f4923157f5bf 100644
--- a/drivers/gpu/drm/tests/drm_kunit_edid.h
+++ b/drivers/gpu/drm/tests/drm_kunit_edid.h
@@ -293,6 +293,125 @@ static const unsigned char test_edid_hdmi_1080p_rgb_max_200mhz[] = {
 	0x00, 0x00, 0x00, 0xfc
 };
 
+/*
+ * edid-decode (hex):
+ *
+ * 00 ff ff ff ff ff ff 00 31 d8 2a 00 00 00 00 00
+ * 00 21 01 03 81 a0 5a 78 02 00 00 00 00 00 00 00
+ * 00 00 00 20 00 00 01 01 01 01 01 01 01 01 01 01
+ * 01 01 01 01 01 01 02 3a 80 18 71 38 2d 40 58 2c
+ * 45 00 40 84 63 00 00 1e 00 00 00 fc 00 54 65 73
+ * 74 20 45 44 49 44 0a 20 20 20 00 00 00 fd 00 32
+ * 46 1e 46 0f 00 0a 20 20 20 20 20 20 00 00 00 10
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 92
+ *
+ * 02 03 1c 81 e3 05 c0 20 41 10 e2 00 4a 67 03 0c
+ * 00 12 34 00 28 e6 06 05 01 52 52 51 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4e
+ *
+ * ----------------
+ *
+ * Block 0, Base EDID:
+ *   EDID Structure Version & Revision: 1.3
+ *   Vendor & Product Identification:
+ *     Manufacturer: LNX
+ *     Model: 42
+ *     Made in: 2023
+ *   Basic Display Parameters & Features:
+ *     Digital display
+ *     DFP 1.x compatible TMDS
+ *     Maximum image size: 160 cm x 90 cm
+ *     Gamma: 2.20
+ *     Monochrome or grayscale display
+ *     First detailed timing is the preferred timing
+ *   Color Characteristics:
+ *     Red  : 0.0000, 0.0000
+ *     Green: 0.0000, 0.0000
+ *     Blue : 0.0000, 0.0000
+ *     White: 0.0000, 0.0000
+ *   Established Timings I & II:
+ *     DMT 0x04:   640x480    59.940476 Hz   4:3     31.469 kHz     25.175000 MHz
+ *   Standard Timings: none
+ *   Detailed Timing Descriptors:
+ *     DTD 1:  1920x1080   60.000000 Hz  16:9     67.500 kHz    148.500000 MHz (1600 mm x 900 mm)
+ *                  Hfront   88 Hsync  44 Hback  148 Hpol P
+ *                  Vfront    4 Vsync   5 Vback   36 Vpol P
+ *     Display Product Name: 'Test EDID'
+ *     Display Range Limits:
+ *       Monitor ranges (GTF): 50-70 Hz V, 30-70 kHz H, max dotclock 150 MHz
+ *     Dummy Descriptor:
+ *   Extension blocks: 1
+ * Checksum: 0x92
+ *
+ * ----------------
+ *
+ * Block 1, CTA-861 Extension Block:
+ *   Revision: 3
+ *   Underscans IT Video Formats by default
+ *   Native detailed modes: 1
+ *   Colorimetry Data Block:
+ *     BT2020YCC
+ *     BT2020RGB
+ *     sRGB
+ *   Video Data Block:
+ *     VIC  16:  1920x1080   60.000000 Hz  16:9     67.500 kHz    148.500000 MHz
+ *   Video Capability Data Block:
+ *     YCbCr quantization: No Data
+ *     RGB quantization: Selectable (via AVI Q)
+ *     PT scan behavior: No Data
+ *     IT scan behavior: Always Underscanned
+ *     CE scan behavior: Always Underscanned
+ *   Vendor-Specific Data Block (HDMI), OUI 00-0C-03:
+ *     Source physical address: 1.2.3.4
+ *     Maximum TMDS clock: 200 MHz
+ *   HDR Static Metadata Data Block:
+ *     Electro optical transfer functions:
+ *       Traditional gamma - SDR luminance range
+ *       SMPTE ST2084
+ *     Supported static metadata descriptors:
+ *       Static metadata type 1
+ *     Desired content max luminance: 82 (295.365 cd/m^2)
+ *     Desired content max frame-average luminance: 82 (295.365 cd/m^2)
+ *     Desired content min luminance: 81 (0.298 cd/m^2)
+ * Checksum: 0x4e  Unused space in Extension Block: 99 bytes
+ *
+ * ----------------
+ *
+ * edid-decode 1.31.0-5387
+ * edid-decode SHA: 5508bc4301ac 2025-08-25 08:14:22
+ *
+ * EDID conformity: PASS
+ */
+static const unsigned char test_edid_hdmi_1080p_rgb_max_200mhz_hdr[] = {
+	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x31, 0xd8, 0x2a, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x01, 0x03, 0x81, 0xa0, 0x5a, 0x78,
+	0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
+	0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38,
+	0x2d, 0x40, 0x58, 0x2c, 0x45, 0x00, 0x40, 0x84, 0x63, 0x00, 0x00, 0x1e,
+	0x00, 0x00, 0x00, 0xfc, 0x00, 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x44,
+	0x49, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x32,
+	0x46, 0x1e, 0x46, 0x0f, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+	0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x92, 0x02, 0x03, 0x1c, 0x81,
+	0xe3, 0x05, 0xc0, 0x20, 0x41, 0x10, 0xe2, 0x00, 0x4a, 0x67, 0x03, 0x0c,
+	0x00, 0x12, 0x34, 0x78, 0x28, 0xe6, 0x06, 0x05, 0x01, 0x52, 0x52, 0x51,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0xd6,
+};
+
 /*
  * edid-decode (hex):
  *

-- 
2.47.3



From dmitry.baryshkov at oss.qualcomm.com  Tue Dec 23 17:02:51 2025
From: dmitry.baryshkov at oss.qualcomm.com (Dmitry Baryshkov)
Date: Wed, 24 Dec 2025 03:02:51 +0200
Subject: [PATCH v3 02/10] drm/vc4: hdmi: implement clear_infoframe
In-Reply-To: <20251224-limit-infoframes-2-v3-0-7fd3cacfefed@oss.qualcomm.com>
References: <20251224-limit-infoframes-2-v3-0-7fd3cacfefed@oss.qualcomm.com>
Message-ID: <20251224-limit-infoframes-2-v3-2-7fd3cacfefed@oss.qualcomm.com>

Implement the clear_infoframe callback, disabling corresponding
InfoFrame type.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
---
 drivers/gpu/drm/vc4/vc4_hdmi.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 1798d1156d10..4cfb7ebc0c81 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -624,6 +624,30 @@ static int vc4_hdmi_stop_packet(struct vc4_hdmi *vc4_hdmi,
 	return ret;
 }
 
+static int vc4_hdmi_clear_infoframe(struct drm_connector *connector,
+				    enum hdmi_infoframe_type type)
+{
+	struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
+	struct drm_device *drm = connector->dev;
+	int ret;
+	int idx;
+
+	if (!drm_dev_enter(drm, &idx))
+		return 0;
+
+	WARN_ONCE(!(HDMI_READ(HDMI_RAM_PACKET_CONFIG) &
+		    VC4_HDMI_RAM_PACKET_ENABLE),
+		  "Packet RAM has to be on to store the packet.");
+
+	ret = vc4_hdmi_stop_packet(vc4_hdmi, type, true);
+	if (ret)
+		drm_err(drm, "Failed to wait for infoframe to go idle: %d\n", ret);
+
+	drm_dev_exit(idx);
+
+	return ret;
+}
+
 static int vc4_hdmi_write_infoframe(struct drm_connector *connector,
 				    enum hdmi_infoframe_type type,
 				    const u8 *infoframe, size_t len)
@@ -1660,6 +1684,7 @@ vc4_hdmi_connector_clock_valid(const struct drm_connector *connector,
 
 static const struct drm_connector_hdmi_funcs vc4_hdmi_hdmi_connector_funcs = {
 	.tmds_char_rate_valid	= vc4_hdmi_connector_clock_valid,
+	.clear_infoframe	= vc4_hdmi_clear_infoframe,
 	.write_infoframe	= vc4_hdmi_write_infoframe,
 };
 

-- 
2.47.3



From dmitry.baryshkov at oss.qualcomm.com  Tue Dec 23 17:02:52 2025
From: dmitry.baryshkov at oss.qualcomm.com (Dmitry Baryshkov)
Date: Wed, 24 Dec 2025 03:02:52 +0200
Subject: [PATCH v3 03/10] drm/sun4i: hdmi_enc: implement clear_infoframe
 stub
In-Reply-To: <20251224-limit-infoframes-2-v3-0-7fd3cacfefed@oss.qualcomm.com>
References: <20251224-limit-infoframes-2-v3-0-7fd3cacfefed@oss.qualcomm.com>
Message-ID: <20251224-limit-infoframes-2-v3-3-7fd3cacfefed@oss.qualcomm.com>

In preparation to making clear_infoframes callbacks required, add a stub
to the sun4i driver.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
---
 drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
index ab0938ba61f7..6263ee15880a 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
@@ -40,6 +40,14 @@
 #define drm_connector_to_sun4i_hdmi(c)		\
 	container_of_const(c, struct sun4i_hdmi, connector)
 
+static int sun4i_hdmi_clear_infoframe(struct drm_connector *connector,
+				      enum hdmi_infoframe_type type)
+{
+	drm_warn_once(connector->dev, "clearing of AVI infoframe is not implemented\n");
+
+	return 0;
+}
+
 static int sun4i_hdmi_write_infoframe(struct drm_connector *connector,
 				      enum hdmi_infoframe_type type,
 				      const u8 *buffer, size_t len)
@@ -236,6 +244,7 @@ static struct i2c_adapter *sun4i_hdmi_get_ddc(struct device *dev)
 
 static const struct drm_connector_hdmi_funcs sun4i_hdmi_hdmi_connector_funcs = {
 	.tmds_char_rate_valid	= sun4i_hdmi_connector_clock_valid,
+	.clear_infoframe	= sun4i_hdmi_clear_infoframe,
 	.write_infoframe	= sun4i_hdmi_write_infoframe,
 };
 

-- 
2.47.3



From dmitry.baryshkov at oss.qualcomm.com  Tue Dec 23 17:02:53 2025
From: dmitry.baryshkov at oss.qualcomm.com (Dmitry Baryshkov)
Date: Wed, 24 Dec 2025 03:02:53 +0200
Subject: [PATCH v3 04/10] drm/connector: make clear_infoframe callback
 mandatory for HDMI connectors
In-Reply-To: <20251224-limit-infoframes-2-v3-0-7fd3cacfefed@oss.qualcomm.com>
References: <20251224-limit-infoframes-2-v3-0-7fd3cacfefed@oss.qualcomm.com>
Message-ID: <20251224-limit-infoframes-2-v3-4-7fd3cacfefed@oss.qualcomm.com>

We already require both hdmi_write_infoframe and hdmi_clear_infoframe
for bridges implementing DRM_BRIDGE_OP_HDMI. It makes sense to require
the clear_infoframes callback for HDMI connectors utilizing
drmm_connector_hdmi_init().

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
---
 drivers/gpu/drm/drm_connector.c                    |  4 ++++
 drivers/gpu/drm/tests/drm_connector_test.c         | 15 +++++++++++++++
 drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 22 ++++++++++++++++++++++
 include/drm/drm_connector.h                        |  2 +-
 4 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 4d6dc9ebfdb5..40e025712c9b 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -600,6 +600,10 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
 	if (!(max_bpc == 8 || max_bpc == 10 || max_bpc == 12))
 		return -EINVAL;
 
+	if (!hdmi_funcs->clear_infoframe ||
+	    !hdmi_funcs->write_infoframe)
+		return -EINVAL;
+
 	ret = drmm_connector_init(dev, connector, funcs, connector_type, ddc);
 	if (ret)
 		return ret;
diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c
index 22e2d959eb31..f356ea695ae7 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -25,7 +25,22 @@ struct drm_connector_init_priv {
 	struct i2c_adapter ddc;
 };
 
+static int accept_infoframe_clear_infoframe(struct drm_connector *connector,
+					    enum hdmi_infoframe_type type)
+{
+	return 0;
+}
+
+static int accept_infoframe_write_infoframe(struct drm_connector *connector,
+					    enum hdmi_infoframe_type type,
+					    const u8 *buffer, size_t len)
+{
+	return 0;
+}
+
 static const struct drm_connector_hdmi_funcs dummy_hdmi_funcs = {
+	.clear_infoframe = accept_infoframe_clear_infoframe,
+	.write_infoframe = accept_infoframe_write_infoframe,
 };
 
 static const struct drm_connector_funcs dummy_funcs = {
diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
index bdf14a0623b2..915dcd106703 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -76,7 +76,22 @@ static int set_connector_edid(struct kunit *test, struct drm_connector *connecto
 	return ret;
 }
 
+static int accept_infoframe_clear_infoframe(struct drm_connector *connector,
+					    enum hdmi_infoframe_type type)
+{
+	return 0;
+}
+
+static int accept_infoframe_write_infoframe(struct drm_connector *connector,
+					    enum hdmi_infoframe_type type,
+					    const u8 *buffer, size_t len)
+{
+	return 0;
+}
+
 static const struct drm_connector_hdmi_funcs dummy_connector_hdmi_funcs = {
+	.clear_infoframe = accept_infoframe_clear_infoframe,
+	.write_infoframe = accept_infoframe_write_infoframe,
 };
 
 static enum drm_mode_status
@@ -89,6 +104,8 @@ reject_connector_tmds_char_rate_valid(const struct drm_connector *connector,
 
 static const struct drm_connector_hdmi_funcs reject_connector_hdmi_funcs = {
 	.tmds_char_rate_valid	= reject_connector_tmds_char_rate_valid,
+	.clear_infoframe = accept_infoframe_clear_infoframe,
+	.write_infoframe = accept_infoframe_write_infoframe,
 };
 
 static enum drm_mode_status
@@ -101,6 +118,8 @@ reject_100mhz_connector_tmds_char_rate_valid(const struct drm_connector *connect
 
 static const struct drm_connector_hdmi_funcs reject_100mhz_connector_hdmi_funcs = {
 	.tmds_char_rate_valid	= reject_100mhz_connector_tmds_char_rate_valid,
+	.clear_infoframe = accept_infoframe_clear_infoframe,
+	.write_infoframe = accept_infoframe_write_infoframe,
 };
 
 static int dummy_connector_get_modes(struct drm_connector *connector)
@@ -2419,6 +2438,7 @@ static int reject_avi_infoframe_write_infoframe(struct drm_connector *connector,
 }
 
 static const struct drm_connector_hdmi_funcs reject_avi_infoframe_hdmi_funcs = {
+	.clear_infoframe = accept_infoframe_clear_infoframe,
 	.write_infoframe = reject_avi_infoframe_write_infoframe,
 };
 
@@ -2500,6 +2520,7 @@ static int reject_hdr_infoframe_write_infoframe(struct drm_connector *connector,
 }
 
 static const struct drm_connector_hdmi_funcs reject_hdr_infoframe_hdmi_funcs = {
+	.clear_infoframe = accept_infoframe_clear_infoframe,
 	.write_infoframe = reject_hdr_infoframe_write_infoframe,
 };
 
@@ -2685,6 +2706,7 @@ static int reject_audio_infoframe_write_infoframe(struct drm_connector *connecto
 }
 
 static const struct drm_connector_hdmi_funcs reject_audio_infoframe_hdmi_funcs = {
+	.clear_infoframe = accept_infoframe_clear_infoframe,
 	.write_infoframe = reject_audio_infoframe_write_infoframe,
 };
 
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 8f34f4b8183d..4543833acdec 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1253,7 +1253,7 @@ struct drm_connector_hdmi_funcs {
 	 * called multiple times, once for every disabled infoframe
 	 * type.
 	 *
-	 * The @clear_infoframe callback is optional.
+	 * The @clear_infoframe callback is mandatory.
 	 *
 	 * Returns:
 	 * 0 on success, a negative error code otherwise

-- 
2.47.3



From dmitry.baryshkov at oss.qualcomm.com  Tue Dec 23 17:02:54 2025
From: dmitry.baryshkov at oss.qualcomm.com (Dmitry Baryshkov)
Date: Wed, 24 Dec 2025 03:02:54 +0200
Subject: [PATCH v3 05/10] drm/bridge: refactor HDMI InfoFrame callbacks
In-Reply-To: <20251224-limit-infoframes-2-v3-0-7fd3cacfefed@oss.qualcomm.com>
References: <20251224-limit-infoframes-2-v3-0-7fd3cacfefed@oss.qualcomm.com>
Message-ID: <20251224-limit-infoframes-2-v3-5-7fd3cacfefed@oss.qualcomm.com>

Having only a single set of callbacks, hdmi_clear_infoframe and
hdmi_write_infoframe, bridge drivers don't have an easy way to signal to
the DRM framework, which InfoFrames are actually supported by the
hardware and by the driver and which are not. Also, it makes it
extremely easy for HDMI bridge drivers to skip implementing the
seemingly required InfoFrames (e.g. HDMI VSI). Last, but not least,
those callbacks take a single 'type' parameter, which makes it
impossible to implement support for multiple VSIs (which will be
required once we start working on HDMI Forum VSI).

Split the callbacks into a per-InfoFrame-kind pairs, letting the bridge
drivers actually signal supported features. The implementation follows
the overall drm_bridge design, where the bridge has a single
drm_bridge_funcs implementation and signals, which functions are to be
called using the drm_bridge->ops flags.

The AVI and HDMI VSI are assumed to be required for a normal HDMI
operation (with the drivers getting a drm_warn_once() stub
implementation if one is missing). The Audio InfoFrame is handled by the
existing DRM_BRIDGE_OP_HDMI_AUDIO, while the SPD and HDR DRM InfoFrames
got new drm_bridge_ops values.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
---
 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c   | 180 +++++++++++++----------
 drivers/gpu/drm/bridge/ite-it6263.c            |  95 ++++++------
 drivers/gpu/drm/bridge/lontium-lt9611.c        | 143 ++++++++++--------
 drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c   | 110 +++++++++-----
 drivers/gpu/drm/display/drm_bridge_connector.c |  70 ++++++++-
 drivers/gpu/drm/mediatek/mtk_hdmi_common.c     |   8 +-
 drivers/gpu/drm/mediatek/mtk_hdmi_v2.c         | 110 +++++++-------
 drivers/gpu/drm/msm/hdmi/hdmi_bridge.c         | 195 +++++++++++++------------
 drivers/gpu/drm/rockchip/rk3066_hdmi.c         |  47 +++---
 include/drm/drm_bridge.h                       | 127 ++++++++++++++--
 10 files changed, 682 insertions(+), 403 deletions(-)

diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index b9be86541307..1050bb62280b 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -887,88 +887,111 @@ static const struct drm_edid *adv7511_bridge_edid_read(struct drm_bridge *bridge
 	return adv7511_edid_read(adv, connector);
 }
 
-static int adv7511_bridge_hdmi_clear_infoframe(struct drm_bridge *bridge,
-					       enum hdmi_infoframe_type type)
+static int adv7511_bridge_hdmi_clear_audio_infoframe(struct drm_bridge *bridge)
 {
 	struct adv7511 *adv7511 = bridge_to_adv7511(bridge);
 
-	switch (type) {
-	case HDMI_INFOFRAME_TYPE_AUDIO:
-		adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_AUDIO_INFOFRAME);
-		break;
-	case HDMI_INFOFRAME_TYPE_AVI:
-		adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME);
-		break;
-	case HDMI_INFOFRAME_TYPE_SPD:
-		adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_SPD);
-		break;
-	case HDMI_INFOFRAME_TYPE_VENDOR:
-		adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_SPARE1);
-		break;
-	default:
-		drm_dbg_driver(adv7511->bridge.dev, "Unsupported HDMI InfoFrame %x\n", type);
-		break;
-	}
+	adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_AUDIO_INFOFRAME);
 
 	return 0;
 }
 
-static int adv7511_bridge_hdmi_write_infoframe(struct drm_bridge *bridge,
-					       enum hdmi_infoframe_type type,
-					       const u8 *buffer, size_t len)
+static int adv7511_bridge_hdmi_clear_avi_infoframe(struct drm_bridge *bridge)
 {
 	struct adv7511 *adv7511 = bridge_to_adv7511(bridge);
 
-	switch (type) {
-	case HDMI_INFOFRAME_TYPE_AUDIO:
-		/* send current Audio infoframe values while updating */
-		regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,
-				   BIT(5), BIT(5));
-
-		/* The Audio infoframe id is not configurable */
-		regmap_bulk_write(adv7511->regmap, ADV7511_REG_AUDIO_INFOFRAME_VERSION,
-				  buffer + 1, len - 1);
-
-		/* use Audio infoframe updated info */
-		regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,
-				   BIT(5), 0);
-
-		adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_AUDIO_INFOFRAME);
-		break;
-	case HDMI_INFOFRAME_TYPE_AVI:
-		/* send current AVI infoframe values while updating */
-		regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,
-				   BIT(6), BIT(6));
-
-		/* The AVI infoframe id is not configurable */
-		regmap_bulk_write(adv7511->regmap, ADV7511_REG_AVI_INFOFRAME_VERSION,
-				  buffer + 1, len - 1);
-
-		regmap_write(adv7511->regmap, ADV7511_REG_AUDIO_INFOFRAME_LENGTH, 0x2);
-		regmap_write(adv7511->regmap, ADV7511_REG_AUDIO_INFOFRAME(1), 0x1);
-
-		/* use AVI infoframe updated info */
-		regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,
-				   BIT(6), 0);
-
-		adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME);
-		break;
-	case HDMI_INFOFRAME_TYPE_SPD:
-		adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_SPD);
-		regmap_bulk_write(adv7511->regmap_packet, ADV7511_PACKET_SPD(0),
-				  buffer, len);
-		adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_SPD);
-		break;
-	case HDMI_INFOFRAME_TYPE_VENDOR:
-		adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_SPARE1);
-		regmap_bulk_write(adv7511->regmap_packet, ADV7511_PACKET_SPARE1(0),
-				  buffer, len);
-		adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_SPARE1);
-		break;
-	default:
-		drm_dbg_driver(adv7511->bridge.dev, "Unsupported HDMI InfoFrame %x\n", type);
-		break;
-	}
+	adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME);
+
+	return 0;
+}
+
+static int adv7511_bridge_hdmi_clear_spd_infoframe(struct drm_bridge *bridge)
+{
+	struct adv7511 *adv7511 = bridge_to_adv7511(bridge);
+
+	adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_SPD);
+
+	return 0;
+}
+
+static int adv7511_bridge_hdmi_clear_hdmi_infoframe(struct drm_bridge *bridge)
+{
+	struct adv7511 *adv7511 = bridge_to_adv7511(bridge);
+
+	adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_SPARE1);
+
+	return 0;
+}
+
+static int adv7511_bridge_hdmi_write_audio_infoframe(struct drm_bridge *bridge,
+						     const u8 *buffer, size_t len)
+{
+	struct adv7511 *adv7511 = bridge_to_adv7511(bridge);
+
+	/* send current Audio infoframe values while updating */
+	regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,
+			   BIT(5), BIT(5));
+
+	/* The Audio infoframe id is not configurable */
+	regmap_bulk_write(adv7511->regmap, ADV7511_REG_AUDIO_INFOFRAME_VERSION,
+			  buffer + 1, len - 1);
+
+	/* use Audio infoframe updated info */
+	regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,
+			   BIT(5), 0);
+
+	adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_AUDIO_INFOFRAME);
+
+	return 0;
+}
+
+static int adv7511_bridge_hdmi_write_avi_infoframe(struct drm_bridge *bridge,
+						   const u8 *buffer, size_t len)
+{
+	struct adv7511 *adv7511 = bridge_to_adv7511(bridge);
+
+	/* send current AVI infoframe values while updating */
+	regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,
+			   BIT(6), BIT(6));
+
+	/* The AVI infoframe id is not configurable */
+	regmap_bulk_write(adv7511->regmap, ADV7511_REG_AVI_INFOFRAME_VERSION,
+			  buffer + 1, len - 1);
+
+	regmap_write(adv7511->regmap, ADV7511_REG_AUDIO_INFOFRAME_LENGTH, 0x2);
+	regmap_write(adv7511->regmap, ADV7511_REG_AUDIO_INFOFRAME(1), 0x1);
+
+	/* use AVI infoframe updated info */
+	regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,
+			   BIT(6), 0);
+
+	adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME);
+
+	return 0;
+}
+
+static int adv7511_bridge_hdmi_write_spd_infoframe(struct drm_bridge *bridge,
+						   const u8 *buffer, size_t len)
+{
+	struct adv7511 *adv7511 = bridge_to_adv7511(bridge);
+
+	adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_SPD);
+	regmap_bulk_write(adv7511->regmap_packet, ADV7511_PACKET_SPD(0),
+			  buffer, len);
+	adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_SPD);
+
+	return 0;
+}
+
+static int adv7511_bridge_hdmi_write_hdmi_infoframe(struct drm_bridge *bridge,
+						    const u8 *buffer, size_t len)
+{
+	struct adv7511 *adv7511 = bridge_to_adv7511(bridge);
+
+	adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_SPARE1);
+	regmap_bulk_write(adv7511->regmap_packet, ADV7511_PACKET_SPARE1(0),
+			  buffer, len);
+	adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_SPARE1);
 
 	return 0;
 }
@@ -986,8 +1009,14 @@ static const struct drm_bridge_funcs adv7511_bridge_funcs = {
 	.atomic_reset = drm_atomic_helper_bridge_reset,
 
 	.hdmi_tmds_char_rate_valid = adv7511_bridge_hdmi_tmds_char_rate_valid,
-	.hdmi_clear_infoframe = adv7511_bridge_hdmi_clear_infoframe,
-	.hdmi_write_infoframe = adv7511_bridge_hdmi_write_infoframe,
+	.hdmi_clear_audio_infoframe = adv7511_bridge_hdmi_clear_audio_infoframe,
+	.hdmi_write_audio_infoframe = adv7511_bridge_hdmi_write_audio_infoframe,
+	.hdmi_clear_avi_infoframe = adv7511_bridge_hdmi_clear_avi_infoframe,
+	.hdmi_write_avi_infoframe = adv7511_bridge_hdmi_write_avi_infoframe,
+	.hdmi_clear_spd_infoframe = adv7511_bridge_hdmi_clear_spd_infoframe,
+	.hdmi_write_spd_infoframe = adv7511_bridge_hdmi_write_spd_infoframe,
+	.hdmi_clear_hdmi_infoframe = adv7511_bridge_hdmi_clear_hdmi_infoframe,
+	.hdmi_write_hdmi_infoframe = adv7511_bridge_hdmi_write_hdmi_infoframe,
 
 	.hdmi_audio_startup = adv7511_hdmi_audio_startup,
 	.hdmi_audio_prepare = adv7511_hdmi_audio_prepare,
@@ -1322,7 +1351,8 @@ static int adv7511_probe(struct i2c_client *i2c)
 
 	adv7511->bridge.ops = DRM_BRIDGE_OP_DETECT |
 		DRM_BRIDGE_OP_EDID |
-		DRM_BRIDGE_OP_HDMI;
+		DRM_BRIDGE_OP_HDMI |
+		DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME;
 	if (adv7511->i2c_main->irq)
 		adv7511->bridge.ops |= DRM_BRIDGE_OP_HPD;
 
diff --git a/drivers/gpu/drm/bridge/ite-it6263.c b/drivers/gpu/drm/bridge/ite-it6263.c
index 2eb8fba7016c..3991fb76143c 100644
--- a/drivers/gpu/drm/bridge/ite-it6263.c
+++ b/drivers/gpu/drm/bridge/ite-it6263.c
@@ -759,61 +759,62 @@ it6263_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge,
 	return MODE_OK;
 }
 
-static int it6263_hdmi_clear_infoframe(struct drm_bridge *bridge,
-				       enum hdmi_infoframe_type type)
+static int it6263_hdmi_clear_avi_infoframe(struct drm_bridge *bridge)
 {
 	struct it6263 *it = bridge_to_it6263(bridge);
 
-	switch (type) {
-	case HDMI_INFOFRAME_TYPE_AVI:
-		regmap_write(it->hdmi_regmap, HDMI_REG_AVI_INFOFRM_CTRL, 0);
-		break;
-	case HDMI_INFOFRAME_TYPE_VENDOR:
-		regmap_write(it->hdmi_regmap, HDMI_REG_PKT_NULL_CTRL, 0);
-		break;
-	default:
-		dev_dbg(it->dev, "unsupported HDMI infoframe 0x%x\n", type);
-	}
+	regmap_write(it->hdmi_regmap, HDMI_REG_AVI_INFOFRM_CTRL, 0);
+
+	return 0;
+}
+
+static int it6263_hdmi_clear_hdmi_infoframe(struct drm_bridge *bridge)
+{
+	struct it6263 *it = bridge_to_it6263(bridge);
+
+	regmap_write(it->hdmi_regmap, HDMI_REG_PKT_NULL_CTRL, 0);
 
 	return 0;
 }
 
-static int it6263_hdmi_write_infoframe(struct drm_bridge *bridge,
-				       enum hdmi_infoframe_type type,
-				       const u8 *buffer, size_t len)
+static int it6263_hdmi_write_avi_infoframe(struct drm_bridge *bridge,
+					   const u8 *buffer, size_t len)
 {
 	struct it6263 *it = bridge_to_it6263(bridge);
 	struct regmap *regmap = it->hdmi_regmap;
 
-	switch (type) {
-	case HDMI_INFOFRAME_TYPE_AVI:
-		/* write the first AVI infoframe data byte chunk(DB1-DB5) */
-		regmap_bulk_write(regmap, HDMI_REG_AVI_DB1,
-				  &buffer[HDMI_INFOFRAME_HEADER_SIZE],
-				  HDMI_AVI_DB_CHUNK1_SIZE);
-
-		/* write the second AVI infoframe data byte chunk(DB6-DB13) */
-		regmap_bulk_write(regmap, HDMI_REG_AVI_DB6,
-				  &buffer[HDMI_INFOFRAME_HEADER_SIZE +
-					  HDMI_AVI_DB_CHUNK1_SIZE],
-				  HDMI_AVI_DB_CHUNK2_SIZE);
-
-		/* write checksum */
-		regmap_write(regmap, HDMI_REG_AVI_CSUM, buffer[3]);
-
-		regmap_write(regmap, HDMI_REG_AVI_INFOFRM_CTRL,
-			     ENABLE_PKT | REPEAT_PKT);
-		break;
-	case HDMI_INFOFRAME_TYPE_VENDOR:
-		/* write header and payload */
-		regmap_bulk_write(regmap, HDMI_REG_PKT_HB(0), buffer, len);
-
-		regmap_write(regmap, HDMI_REG_PKT_NULL_CTRL,
-			     ENABLE_PKT | REPEAT_PKT);
-		break;
-	default:
-		dev_dbg(it->dev, "unsupported HDMI infoframe 0x%x\n", type);
-	}
+	/* write the first AVI infoframe data byte chunk(DB1-DB5) */
+	regmap_bulk_write(regmap, HDMI_REG_AVI_DB1,
+			  &buffer[HDMI_INFOFRAME_HEADER_SIZE],
+			  HDMI_AVI_DB_CHUNK1_SIZE);
+
+	/* write the second AVI infoframe data byte chunk(DB6-DB13) */
+	regmap_bulk_write(regmap, HDMI_REG_AVI_DB6,
+			  &buffer[HDMI_INFOFRAME_HEADER_SIZE +
+				  HDMI_AVI_DB_CHUNK1_SIZE],
+			  HDMI_AVI_DB_CHUNK2_SIZE);
+
+	/* write checksum */
+	regmap_write(regmap, HDMI_REG_AVI_CSUM, buffer[3]);
+
+	regmap_write(regmap, HDMI_REG_AVI_INFOFRM_CTRL,
+		     ENABLE_PKT | REPEAT_PKT);
+
+	return 0;
+}
+
+static int it6263_hdmi_write_hdmi_infoframe(struct drm_bridge *bridge,
+					    const u8 *buffer, size_t len)
+{
+	struct it6263 *it = bridge_to_it6263(bridge);
+	struct regmap *regmap = it->hdmi_regmap;
+
+	/* write header and payload */
+	regmap_bulk_write(regmap, HDMI_REG_PKT_HB(0), buffer, len);
+
+	regmap_write(regmap, HDMI_REG_PKT_NULL_CTRL,
+		     ENABLE_PKT | REPEAT_PKT);
+
 
 	return 0;
 }
@@ -830,8 +831,10 @@ static const struct drm_bridge_funcs it6263_bridge_funcs = {
 	.edid_read = it6263_bridge_edid_read,
 	.atomic_get_input_bus_fmts = it6263_bridge_atomic_get_input_bus_fmts,
 	.hdmi_tmds_char_rate_valid = it6263_hdmi_tmds_char_rate_valid,
-	.hdmi_clear_infoframe = it6263_hdmi_clear_infoframe,
-	.hdmi_write_infoframe = it6263_hdmi_write_infoframe,
+	.hdmi_clear_avi_infoframe = it6263_hdmi_clear_avi_infoframe,
+	.hdmi_write_avi_infoframe = it6263_hdmi_write_avi_infoframe,
+	.hdmi_clear_hdmi_infoframe = it6263_hdmi_clear_hdmi_infoframe,
+	.hdmi_write_hdmi_infoframe = it6263_hdmi_write_hdmi_infoframe,
 };
 
 static int it6263_probe(struct i2c_client *client)
diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c
index a2d032ee4744..0628d8e737ab 100644
--- a/drivers/gpu/drm/bridge/lontium-lt9611.c
+++ b/drivers/gpu/drm/bridge/lontium-lt9611.c
@@ -843,84 +843,96 @@ lt9611_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
 #define LT9611_INFOFRAME_AUDIO	0x02
 #define LT9611_INFOFRAME_AVI	0x08
 #define LT9611_INFOFRAME_SPD	0x10
-#define LT9611_INFOFRAME_VENDOR	0x20
+#define LT9611_INFOFRAME_HDMI	0x20
 
-static int lt9611_hdmi_clear_infoframe(struct drm_bridge *bridge,
-				       enum hdmi_infoframe_type type)
+static int lt9611_hdmi_clear_audio_infoframe(struct drm_bridge *bridge)
 {
 	struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
-	unsigned int mask;
 
-	switch (type) {
-	case HDMI_INFOFRAME_TYPE_AUDIO:
-		mask = LT9611_INFOFRAME_AUDIO;
-		break;
+	regmap_update_bits(lt9611->regmap, 0x843d, LT9611_INFOFRAME_AUDIO, 0);
 
-	case HDMI_INFOFRAME_TYPE_AVI:
-		mask = LT9611_INFOFRAME_AVI;
-		break;
+	return 0;
+}
 
-	case HDMI_INFOFRAME_TYPE_SPD:
-		mask = LT9611_INFOFRAME_SPD;
-		break;
+static int lt9611_hdmi_clear_avi_infoframe(struct drm_bridge *bridge)
+{
+	struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
 
-	case HDMI_INFOFRAME_TYPE_VENDOR:
-		mask = LT9611_INFOFRAME_VENDOR;
-		break;
+	regmap_update_bits(lt9611->regmap, 0x843d, LT9611_INFOFRAME_AVI, 0);
 
-	default:
-		drm_dbg_driver(lt9611->bridge.dev, "Unsupported HDMI InfoFrame %x\n", type);
-		mask = 0;
-		break;
-	}
+	return 0;
+}
+
+static int lt9611_hdmi_clear_spd_infoframe(struct drm_bridge *bridge)
+{
+	struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
 
-	if (mask)
-		regmap_update_bits(lt9611->regmap, 0x843d, mask, 0);
+	regmap_update_bits(lt9611->regmap, 0x843d, LT9611_INFOFRAME_SPD, 0);
 
 	return 0;
 }
 
-static int lt9611_hdmi_write_infoframe(struct drm_bridge *bridge,
-				       enum hdmi_infoframe_type type,
-				       const u8 *buffer, size_t len)
+static int lt9611_hdmi_clear_hdmi_infoframe(struct drm_bridge *bridge)
+{
+	struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
+
+	regmap_update_bits(lt9611->regmap, 0x843d, LT9611_INFOFRAME_HDMI, 0);
+
+	return 0;
+}
+
+static int lt9611_hdmi_write_audio_infoframe(struct drm_bridge *bridge,
+					     const u8 *buffer, size_t len)
 {
 	struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
-	unsigned int mask, addr;
 	int i;
 
-	switch (type) {
-	case HDMI_INFOFRAME_TYPE_AUDIO:
-		mask = LT9611_INFOFRAME_AUDIO;
-		addr = 0x84b2;
-		break;
-
-	case HDMI_INFOFRAME_TYPE_AVI:
-		mask = LT9611_INFOFRAME_AVI;
-		addr = 0x8440;
-		break;
-
-	case HDMI_INFOFRAME_TYPE_SPD:
-		mask = LT9611_INFOFRAME_SPD;
-		addr = 0x8493;
-		break;
-
-	case HDMI_INFOFRAME_TYPE_VENDOR:
-		mask = LT9611_INFOFRAME_VENDOR;
-		addr = 0x8474;
-		break;
-
-	default:
-		drm_dbg_driver(lt9611->bridge.dev, "Unsupported HDMI InfoFrame %x\n", type);
-		mask = 0;
-		break;
-	}
+	for (i = 0; i < len; i++)
+		regmap_write(lt9611->regmap, 0x84b2 + i, buffer[i]);
 
-	if (mask) {
-		for (i = 0; i < len; i++)
-			regmap_write(lt9611->regmap, addr + i, buffer[i]);
+	regmap_update_bits(lt9611->regmap, 0x843d, LT9611_INFOFRAME_AUDIO, LT9611_INFOFRAME_AUDIO);
 
-		regmap_update_bits(lt9611->regmap, 0x843d, mask, mask);
-	}
+	return 0;
+}
+
+static int lt9611_hdmi_write_avi_infoframe(struct drm_bridge *bridge,
+					   const u8 *buffer, size_t len)
+{
+	struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
+	int i;
+
+	for (i = 0; i < len; i++)
+		regmap_write(lt9611->regmap, 0x8440 + i, buffer[i]);
+
+	regmap_update_bits(lt9611->regmap, 0x843d, LT9611_INFOFRAME_AVI, LT9611_INFOFRAME_AVI);
+
+	return 0;
+}
+
+static int lt9611_hdmi_write_spd_infoframe(struct drm_bridge *bridge,
+					   const u8 *buffer, size_t len)
+{
+	struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
+	int i;
+
+	for (i = 0; i < len; i++)
+		regmap_write(lt9611->regmap, 0x8493 + i, buffer[i]);
+
+	regmap_update_bits(lt9611->regmap, 0x843d, LT9611_INFOFRAME_SPD, LT9611_INFOFRAME_SPD);
+
+	return 0;
+}
+
+static int lt9611_hdmi_write_hdmi_infoframe(struct drm_bridge *bridge,
+					    const u8 *buffer, size_t len)
+{
+	struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
+	int i;
+
+	for (i = 0; i < len; i++)
+		regmap_write(lt9611->regmap, 0x8474 + i, buffer[i]);
+
+	regmap_update_bits(lt9611->regmap, 0x843d, LT9611_INFOFRAME_HDMI, LT9611_INFOFRAME_HDMI);
 
 	return 0;
 }
@@ -1003,8 +1015,14 @@ static const struct drm_bridge_funcs lt9611_bridge_funcs = {
 	.atomic_get_input_bus_fmts = lt9611_atomic_get_input_bus_fmts,
 
 	.hdmi_tmds_char_rate_valid = lt9611_hdmi_tmds_char_rate_valid,
-	.hdmi_write_infoframe = lt9611_hdmi_write_infoframe,
-	.hdmi_clear_infoframe = lt9611_hdmi_clear_infoframe,
+	.hdmi_write_audio_infoframe = lt9611_hdmi_write_audio_infoframe,
+	.hdmi_clear_audio_infoframe = lt9611_hdmi_clear_audio_infoframe,
+	.hdmi_write_avi_infoframe = lt9611_hdmi_write_avi_infoframe,
+	.hdmi_clear_avi_infoframe = lt9611_hdmi_clear_avi_infoframe,
+	.hdmi_write_spd_infoframe = lt9611_hdmi_write_spd_infoframe,
+	.hdmi_clear_spd_infoframe = lt9611_hdmi_clear_spd_infoframe,
+	.hdmi_write_hdmi_infoframe = lt9611_hdmi_write_hdmi_infoframe,
+	.hdmi_clear_hdmi_infoframe = lt9611_hdmi_clear_hdmi_infoframe,
 
 	.hdmi_audio_startup = lt9611_hdmi_audio_startup,
 	.hdmi_audio_prepare = lt9611_hdmi_audio_prepare,
@@ -1132,7 +1150,8 @@ static int lt9611_probe(struct i2c_client *client)
 	lt9611->bridge.of_node = client->dev.of_node;
 	lt9611->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID |
 			     DRM_BRIDGE_OP_HPD | DRM_BRIDGE_OP_MODES |
-			     DRM_BRIDGE_OP_HDMI | DRM_BRIDGE_OP_HDMI_AUDIO;
+			     DRM_BRIDGE_OP_HDMI | DRM_BRIDGE_OP_HDMI_AUDIO |
+			     DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME;
 	lt9611->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
 	lt9611->bridge.vendor = "Lontium";
 	lt9611->bridge.product = "LT9611";
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index fe4c026280f0..f57307dd61c8 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -26,6 +26,7 @@
 #include <drm/drm_connector.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_modes.h>
+#include <drm/drm_print.h>
 
 #include <media/cec.h>
 
@@ -933,57 +934,85 @@ dw_hdmi_qp_bridge_tmds_char_rate_valid(const struct drm_bridge *bridge,
 	return MODE_OK;
 }
 
-static int dw_hdmi_qp_bridge_clear_infoframe(struct drm_bridge *bridge,
-					     enum hdmi_infoframe_type type)
+static int dw_hdmi_qp_bridge_clear_avi_infoframe(struct drm_bridge *bridge)
 {
 	struct dw_hdmi_qp *hdmi = bridge->driver_private;
 
-	switch (type) {
-	case HDMI_INFOFRAME_TYPE_AVI:
-		dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_AVI_TX_EN | PKTSCHED_GCP_TX_EN,
-			       PKTSCHED_PKT_EN);
-		break;
+	dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_AVI_TX_EN | PKTSCHED_GCP_TX_EN,
+		       PKTSCHED_PKT_EN);
 
-	case HDMI_INFOFRAME_TYPE_DRM:
-		dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_DRMI_TX_EN, PKTSCHED_PKT_EN);
-		break;
+	return 0;
+}
 
-	case HDMI_INFOFRAME_TYPE_AUDIO:
-		dw_hdmi_qp_mod(hdmi, 0,
-			       PKTSCHED_ACR_TX_EN |
-			       PKTSCHED_AUDS_TX_EN |
-			       PKTSCHED_AUDI_TX_EN,
-			       PKTSCHED_PKT_EN);
-		break;
-	default:
-		dev_dbg(hdmi->dev, "Unsupported infoframe type %x\n", type);
-	}
+static int dw_hdmi_qp_bridge_clear_hdmi_infoframe(struct drm_bridge *bridge)
+{
+	/* FIXME: add support for this InfoFrame */
+
+	drm_warn_once(bridge->encoder->dev, "HDMI VSI not supported\n");
 
 	return 0;
 }
 
-static int dw_hdmi_qp_bridge_write_infoframe(struct drm_bridge *bridge,
-					     enum hdmi_infoframe_type type,
-					     const u8 *buffer, size_t len)
+static int dw_hdmi_qp_bridge_clear_hdr_drm_infoframe(struct drm_bridge *bridge)
 {
 	struct dw_hdmi_qp *hdmi = bridge->driver_private;
 
-	dw_hdmi_qp_bridge_clear_infoframe(bridge, type);
+	dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_DRMI_TX_EN, PKTSCHED_PKT_EN);
 
-	switch (type) {
-	case HDMI_INFOFRAME_TYPE_AVI:
-		return dw_hdmi_qp_config_avi_infoframe(hdmi, buffer, len);
+	return 0;
+}
 
-	case HDMI_INFOFRAME_TYPE_DRM:
-		return dw_hdmi_qp_config_drm_infoframe(hdmi, buffer, len);
+static int dw_hdmi_qp_bridge_clear_audio_infoframe(struct drm_bridge *bridge)
+{
+	struct dw_hdmi_qp *hdmi = bridge->driver_private;
 
-	case HDMI_INFOFRAME_TYPE_AUDIO:
-		return dw_hdmi_qp_config_audio_infoframe(hdmi, buffer, len);
+	dw_hdmi_qp_mod(hdmi, 0,
+		       PKTSCHED_ACR_TX_EN |
+		       PKTSCHED_AUDS_TX_EN |
+		       PKTSCHED_AUDI_TX_EN,
+		       PKTSCHED_PKT_EN);
 
-	default:
-		dev_dbg(hdmi->dev, "Unsupported infoframe type %x\n", type);
-		return 0;
-	}
+	return 0;
+}
+
+static int dw_hdmi_qp_bridge_write_avi_infoframe(struct drm_bridge *bridge,
+						 const u8 *buffer, size_t len)
+{
+	struct dw_hdmi_qp *hdmi = bridge->driver_private;
+
+	dw_hdmi_qp_bridge_clear_avi_infoframe(bridge);
+
+	return dw_hdmi_qp_config_avi_infoframe(hdmi, buffer, len);
+}
+
+static int dw_hdmi_qp_bridge_write_hdmi_infoframe(struct drm_bridge *bridge,
+						  const u8 *buffer, size_t len)
+{
+	dw_hdmi_qp_bridge_clear_hdmi_infoframe(bridge);
+
+	/* FIXME: add support for the HDMI VSI */
+
+	return 0;
+}
+
+static int dw_hdmi_qp_bridge_write_hdr_drm_infoframe(struct drm_bridge *bridge,
+						     const u8 *buffer, size_t len)
+{
+	struct dw_hdmi_qp *hdmi = bridge->driver_private;
+
+	dw_hdmi_qp_bridge_clear_hdr_drm_infoframe(bridge);
+
+	return dw_hdmi_qp_config_drm_infoframe(hdmi, buffer, len);
+}
+
+static int dw_hdmi_qp_bridge_write_audio_infoframe(struct drm_bridge *bridge,
+						   const u8 *buffer, size_t len)
+{
+	struct dw_hdmi_qp *hdmi = bridge->driver_private;
+
+	dw_hdmi_qp_bridge_clear_audio_infoframe(bridge);
+
+	return dw_hdmi_qp_config_audio_infoframe(hdmi, buffer, len);
 }
 
 #ifdef CONFIG_DRM_DW_HDMI_QP_CEC
@@ -1168,8 +1197,14 @@ static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {
 	.detect = dw_hdmi_qp_bridge_detect,
 	.edid_read = dw_hdmi_qp_bridge_edid_read,
 	.hdmi_tmds_char_rate_valid = dw_hdmi_qp_bridge_tmds_char_rate_valid,
-	.hdmi_clear_infoframe = dw_hdmi_qp_bridge_clear_infoframe,
-	.hdmi_write_infoframe = dw_hdmi_qp_bridge_write_infoframe,
+	.hdmi_clear_avi_infoframe = dw_hdmi_qp_bridge_clear_avi_infoframe,
+	.hdmi_write_avi_infoframe = dw_hdmi_qp_bridge_write_avi_infoframe,
+	.hdmi_clear_hdmi_infoframe = dw_hdmi_qp_bridge_clear_hdmi_infoframe,
+	.hdmi_write_hdmi_infoframe = dw_hdmi_qp_bridge_write_hdmi_infoframe,
+	.hdmi_clear_hdr_drm_infoframe = dw_hdmi_qp_bridge_clear_hdr_drm_infoframe,
+	.hdmi_write_hdr_drm_infoframe = dw_hdmi_qp_bridge_write_hdr_drm_infoframe,
+	.hdmi_clear_audio_infoframe = dw_hdmi_qp_bridge_clear_audio_infoframe,
+	.hdmi_write_audio_infoframe = dw_hdmi_qp_bridge_write_audio_infoframe,
 	.hdmi_audio_startup = dw_hdmi_qp_audio_enable,
 	.hdmi_audio_shutdown = dw_hdmi_qp_audio_disable,
 	.hdmi_audio_prepare = dw_hdmi_qp_audio_prepare,
@@ -1282,6 +1317,7 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
 			   DRM_BRIDGE_OP_EDID |
 			   DRM_BRIDGE_OP_HDMI |
 			   DRM_BRIDGE_OP_HDMI_AUDIO |
+			   DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME |
 			   DRM_BRIDGE_OP_HPD;
 	hdmi->bridge.of_node = pdev->dev.of_node;
 	hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index a2d30cf9e06d..8fd7722fe9a3 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -412,7 +412,30 @@ static int drm_bridge_connector_clear_infoframe(struct drm_connector *connector,
 	if (!bridge)
 		return -EINVAL;
 
-	return bridge->funcs->hdmi_clear_infoframe(bridge, type);
+	switch (type) {
+	case HDMI_INFOFRAME_TYPE_AVI:
+		/* required */
+		return bridge->funcs->hdmi_clear_avi_infoframe(bridge);
+	case HDMI_INFOFRAME_TYPE_VENDOR:
+		/* required */
+		return bridge->funcs->hdmi_clear_hdmi_infoframe(bridge);
+	case HDMI_INFOFRAME_TYPE_AUDIO:
+		if (bridge->ops & DRM_BRIDGE_OP_HDMI_AUDIO)
+			return bridge->funcs->hdmi_clear_audio_infoframe(bridge);
+		break;
+	case HDMI_INFOFRAME_TYPE_DRM:
+		if (bridge->ops & DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME)
+			return bridge->funcs->hdmi_clear_hdr_drm_infoframe(bridge);
+		break;
+	case HDMI_INFOFRAME_TYPE_SPD:
+		if (bridge->ops & DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME)
+			return bridge->funcs->hdmi_clear_spd_infoframe(bridge);
+		break;
+	}
+
+	drm_dbg_driver(connector->dev, "Unsupported HDMI InfoFrame %x\n", type);
+
+	return 0;
 }
 
 static int drm_bridge_connector_write_infoframe(struct drm_connector *connector,
@@ -427,7 +450,30 @@ static int drm_bridge_connector_write_infoframe(struct drm_connector *connector,
 	if (!bridge)
 		return -EINVAL;
 
-	return bridge->funcs->hdmi_write_infoframe(bridge, type, buffer, len);
+	switch (type) {
+	case HDMI_INFOFRAME_TYPE_AVI:
+		/* required */
+		return bridge->funcs->hdmi_write_avi_infoframe(bridge, buffer, len);
+	case HDMI_INFOFRAME_TYPE_VENDOR:
+		/* required */
+		return bridge->funcs->hdmi_write_hdmi_infoframe(bridge, buffer, len);
+	case HDMI_INFOFRAME_TYPE_AUDIO:
+		if (bridge->ops & DRM_BRIDGE_OP_HDMI_AUDIO)
+			return bridge->funcs->hdmi_write_audio_infoframe(bridge, buffer, len);
+		break;
+	case HDMI_INFOFRAME_TYPE_DRM:
+		if (bridge->ops & DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME)
+			return bridge->funcs->hdmi_write_hdr_drm_infoframe(bridge, buffer, len);
+		break;
+	case HDMI_INFOFRAME_TYPE_SPD:
+		if (bridge->ops & DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME)
+			return bridge->funcs->hdmi_write_spd_infoframe(bridge, buffer, len);
+		break;
+	}
+
+	drm_dbg_driver(connector->dev, "Unsupported HDMI InfoFrame %x\n", type);
+
+	return 0;
 }
 
 static const struct drm_edid *
@@ -709,8 +755,20 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
 		if (bridge->ops & DRM_BRIDGE_OP_HDMI) {
 			if (bridge_connector->bridge_hdmi)
 				return ERR_PTR(-EBUSY);
-			if (!bridge->funcs->hdmi_write_infoframe ||
-			    !bridge->funcs->hdmi_clear_infoframe)
+			if (!bridge->funcs->hdmi_write_avi_infoframe ||
+			    !bridge->funcs->hdmi_clear_avi_infoframe ||
+			    !bridge->funcs->hdmi_write_hdmi_infoframe ||
+			    !bridge->funcs->hdmi_clear_hdmi_infoframe)
+				return ERR_PTR(-EINVAL);
+
+			if (bridge->ops & DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME &&
+			    (!bridge->funcs->hdmi_write_hdr_drm_infoframe ||
+			     !bridge->funcs->hdmi_clear_hdr_drm_infoframe))
+				return ERR_PTR(-EINVAL);
+
+			if (bridge->ops & DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME &&
+			    (!bridge->funcs->hdmi_write_spd_infoframe ||
+			     !bridge->funcs->hdmi_clear_spd_infoframe))
 				return ERR_PTR(-EINVAL);
 
 			bridge_connector->bridge_hdmi = drm_bridge_get(bridge);
@@ -732,7 +790,9 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
 			    !bridge->hdmi_audio_spdif_playback)
 				return ERR_PTR(-EINVAL);
 
-			if (!bridge->funcs->hdmi_audio_prepare ||
+			if (!bridge->funcs->hdmi_write_audio_infoframe ||
+			    !bridge->funcs->hdmi_clear_audio_infoframe ||
+			    !bridge->funcs->hdmi_audio_prepare ||
 			    !bridge->funcs->hdmi_audio_shutdown)
 				return ERR_PTR(-EINVAL);
 
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_common.c b/drivers/gpu/drm/mediatek/mtk_hdmi_common.c
index e78eb0876f16..c599ba767093 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi_common.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi_common.c
@@ -433,9 +433,11 @@ struct mtk_hdmi *mtk_hdmi_common_probe(struct platform_device *pdev)
 	hdmi->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID
 			 | DRM_BRIDGE_OP_HPD;
 
-	if (ver_conf->bridge_funcs->hdmi_write_infoframe &&
-	    ver_conf->bridge_funcs->hdmi_clear_infoframe)
-		hdmi->bridge.ops |= DRM_BRIDGE_OP_HDMI;
+	/* Only v2 support OP_HDMI now and it we know that it also support SPD */
+	if (ver_conf->bridge_funcs->hdmi_write_avi_infoframe &&
+	    ver_conf->bridge_funcs->hdmi_clear_avi_infoframe)
+		hdmi->bridge.ops |= DRM_BRIDGE_OP_HDMI |
+				    DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME;
 
 	hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
 	hdmi->bridge.ddc = hdmi->ddc_adpt;
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c b/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c
index c272e1e74b7d..d0e4440b7491 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c
@@ -145,8 +145,11 @@ static inline u32 mtk_hdmi_v2_format_hw_packet(const u8 *buffer, u8 len)
 	return val;
 }
 
-static void mtk_hdmi_v2_hw_write_audio_infoframe(struct mtk_hdmi *hdmi, const u8 *buffer)
+static int mtk_hdmi_v2_hdmi_write_audio_infoframe(struct drm_bridge *bridge,
+						  const u8 *buffer, size_t len)
 {
+	struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
+
 	regmap_clear_bits(hdmi->regs, TOP_INFO_EN, AUD_EN | AUD_EN_WR);
 	regmap_clear_bits(hdmi->regs, TOP_INFO_RPT, AUD_RPT_EN);
 
@@ -158,10 +161,15 @@ static void mtk_hdmi_v2_hw_write_audio_infoframe(struct mtk_hdmi *hdmi, const u8
 
 	regmap_set_bits(hdmi->regs, TOP_INFO_RPT, AUD_RPT_EN);
 	regmap_set_bits(hdmi->regs, TOP_INFO_EN, AUD_EN | AUD_EN_WR);
+
+	return 0;
 }
 
-static void mtk_hdmi_v2_hw_write_avi_infoframe(struct mtk_hdmi *hdmi, const u8 *buffer)
+static int mtk_hdmi_v2_hdmi_write_avi_infoframe(struct drm_bridge *bridge,
+						const u8 *buffer, size_t len)
 {
+	struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
+
 	regmap_clear_bits(hdmi->regs, TOP_INFO_EN, AVI_EN_WR | AVI_EN);
 	regmap_clear_bits(hdmi->regs, TOP_INFO_RPT, AVI_RPT_EN);
 
@@ -175,10 +183,15 @@ static void mtk_hdmi_v2_hw_write_avi_infoframe(struct mtk_hdmi *hdmi, const u8 *
 
 	regmap_set_bits(hdmi->regs, TOP_INFO_RPT, AVI_RPT_EN);
 	regmap_set_bits(hdmi->regs, TOP_INFO_EN, AVI_EN_WR | AVI_EN);
+
+	return 0;
 }
 
-static void mtk_hdmi_v2_hw_write_spd_infoframe(struct mtk_hdmi *hdmi, const u8 *buffer)
+static int mtk_hdmi_v2_hdmi_write_spd_infoframe(struct drm_bridge *bridge,
+						const u8 *buffer, size_t len)
 {
+	struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
+
 	regmap_clear_bits(hdmi->regs, TOP_INFO_EN, SPD_EN_WR | SPD_EN);
 	regmap_clear_bits(hdmi->regs, TOP_INFO_RPT, SPD_RPT_EN);
 
@@ -194,10 +207,15 @@ static void mtk_hdmi_v2_hw_write_spd_infoframe(struct mtk_hdmi *hdmi, const u8 *
 
 	regmap_set_bits(hdmi->regs, TOP_INFO_EN, SPD_EN_WR | SPD_EN);
 	regmap_set_bits(hdmi->regs, TOP_INFO_RPT, SPD_RPT_EN);
+
+	return 0;
 }
 
-static void mtk_hdmi_v2_hw_write_vendor_infoframe(struct mtk_hdmi *hdmi, const u8 *buffer)
+static int mtk_hdmi_v2_hdmi_write_hdmi_infoframe(struct drm_bridge *bridge,
+						 const u8 *buffer, size_t len)
 {
+	struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
+
 	regmap_clear_bits(hdmi->regs, TOP_INFO_EN, VSIF_EN_WR | VSIF_EN);
 	regmap_clear_bits(hdmi->regs, TOP_INFO_RPT, VSIF_RPT_EN);
 
@@ -213,6 +231,8 @@ static void mtk_hdmi_v2_hw_write_vendor_infoframe(struct mtk_hdmi *hdmi, const u
 
 	regmap_set_bits(hdmi->regs, TOP_INFO_EN, VSIF_EN_WR | VSIF_EN);
 	regmap_set_bits(hdmi->regs, TOP_INFO_RPT, VSIF_RPT_EN);
+
+	return 0;
 }
 
 static void mtk_hdmi_yuv420_downsampling(struct mtk_hdmi *hdmi, bool enable)
@@ -255,7 +275,7 @@ static int mtk_hdmi_v2_setup_audio_infoframe(struct mtk_hdmi *hdmi)
 	if (ret < 0)
 		return ret;
 
-	mtk_hdmi_v2_hw_write_audio_infoframe(hdmi, buffer);
+	mtk_hdmi_v2_hdmi_write_audio_infoframe(&hdmi->bridge, buffer, sizeof(buffer));
 
 	return 0;
 }
@@ -1132,60 +1152,42 @@ static int mtk_hdmi_v2_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge
 		return MODE_OK;
 }
 
-static int mtk_hdmi_v2_hdmi_clear_infoframe(struct drm_bridge *bridge,
-					    enum hdmi_infoframe_type type)
+static int mtk_hdmi_v2_hdmi_clear_audio_infoframe(struct drm_bridge *bridge)
 {
 	struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
 
-	switch (type) {
-	case HDMI_INFOFRAME_TYPE_AUDIO:
-		regmap_clear_bits(hdmi->regs, TOP_INFO_EN, AUD_EN_WR | AUD_EN);
-		regmap_clear_bits(hdmi->regs, TOP_INFO_RPT, AUD_RPT_EN);
-		break;
-	case HDMI_INFOFRAME_TYPE_AVI:
-		regmap_clear_bits(hdmi->regs, TOP_INFO_EN, AVI_EN_WR | AVI_EN);
-		regmap_clear_bits(hdmi->regs, TOP_INFO_RPT, AVI_RPT_EN);
-		break;
-	case HDMI_INFOFRAME_TYPE_SPD:
-		regmap_clear_bits(hdmi->regs, TOP_INFO_EN, SPD_EN_WR | SPD_EN);
-		regmap_clear_bits(hdmi->regs, TOP_INFO_RPT, SPD_RPT_EN);
-		break;
-	case HDMI_INFOFRAME_TYPE_VENDOR:
-		regmap_clear_bits(hdmi->regs, TOP_INFO_EN, VSIF_EN_WR | VSIF_EN);
-		regmap_clear_bits(hdmi->regs, TOP_INFO_RPT, VSIF_RPT_EN);
-		break;
-	case HDMI_INFOFRAME_TYPE_DRM:
-	default:
-		break;
-	};
+	regmap_clear_bits(hdmi->regs, TOP_INFO_EN, AUD_EN_WR | AUD_EN);
+	regmap_clear_bits(hdmi->regs, TOP_INFO_RPT, AUD_RPT_EN);
 
 	return 0;
 }
 
-static int mtk_hdmi_v2_hdmi_write_infoframe(struct drm_bridge *bridge,
-					    enum hdmi_infoframe_type type,
-					    const u8 *buffer, size_t len)
+static int mtk_hdmi_v2_hdmi_clear_avi_infoframe(struct drm_bridge *bridge)
 {
 	struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
 
-	switch (type) {
-	case HDMI_INFOFRAME_TYPE_AUDIO:
-		mtk_hdmi_v2_hw_write_audio_infoframe(hdmi, buffer);
-		break;
-	case HDMI_INFOFRAME_TYPE_AVI:
-		mtk_hdmi_v2_hw_write_avi_infoframe(hdmi, buffer);
-		break;
-	case HDMI_INFOFRAME_TYPE_SPD:
-		mtk_hdmi_v2_hw_write_spd_infoframe(hdmi, buffer);
-		break;
-	case HDMI_INFOFRAME_TYPE_VENDOR:
-		mtk_hdmi_v2_hw_write_vendor_infoframe(hdmi, buffer);
-		break;
-	case HDMI_INFOFRAME_TYPE_DRM:
-	default:
-		dev_err(hdmi->dev, "Unsupported HDMI infoframe type %u\n", type);
-		break;
-	};
+	regmap_clear_bits(hdmi->regs, TOP_INFO_EN, AVI_EN_WR | AVI_EN);
+	regmap_clear_bits(hdmi->regs, TOP_INFO_RPT, AVI_RPT_EN);
+
+	return 0;
+}
+
+static int mtk_hdmi_v2_hdmi_clear_spd_infoframe(struct drm_bridge *bridge)
+{
+	struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
+
+	regmap_clear_bits(hdmi->regs, TOP_INFO_EN, SPD_EN_WR | SPD_EN);
+	regmap_clear_bits(hdmi->regs, TOP_INFO_RPT, SPD_RPT_EN);
+
+	return 0;
+}
+
+static int mtk_hdmi_v2_hdmi_clear_hdmi_infoframe(struct drm_bridge *bridge)
+{
+	struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
+
+	regmap_clear_bits(hdmi->regs, TOP_INFO_EN, VSIF_EN_WR | VSIF_EN);
+	regmap_clear_bits(hdmi->regs, TOP_INFO_RPT, VSIF_RPT_EN);
 
 	return 0;
 }
@@ -1329,8 +1331,14 @@ static const struct drm_bridge_funcs mtk_v2_hdmi_bridge_funcs = {
 	.hpd_enable = mtk_hdmi_v2_hpd_enable,
 	.hpd_disable = mtk_hdmi_v2_hpd_disable,
 	.hdmi_tmds_char_rate_valid = mtk_hdmi_v2_hdmi_tmds_char_rate_valid,
-	.hdmi_clear_infoframe = mtk_hdmi_v2_hdmi_clear_infoframe,
-	.hdmi_write_infoframe = mtk_hdmi_v2_hdmi_write_infoframe,
+	.hdmi_clear_audio_infoframe = mtk_hdmi_v2_hdmi_clear_audio_infoframe,
+	.hdmi_write_audio_infoframe = mtk_hdmi_v2_hdmi_write_audio_infoframe,
+	.hdmi_clear_avi_infoframe = mtk_hdmi_v2_hdmi_clear_avi_infoframe,
+	.hdmi_write_avi_infoframe = mtk_hdmi_v2_hdmi_write_avi_infoframe,
+	.hdmi_clear_spd_infoframe = mtk_hdmi_v2_hdmi_clear_spd_infoframe,
+	.hdmi_write_spd_infoframe = mtk_hdmi_v2_hdmi_write_spd_infoframe,
+	.hdmi_clear_hdmi_infoframe = mtk_hdmi_v2_hdmi_clear_hdmi_infoframe,
+	.hdmi_write_hdmi_infoframe = mtk_hdmi_v2_hdmi_write_hdmi_infoframe,
 	.debugfs_init = mtk_hdmi_v2_debugfs_init,
 };
 
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index 46fd58646d32..98cd490e7ab0 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -54,9 +54,80 @@ static void power_off(struct drm_bridge *bridge)
 #define SPD_IFRAME_LINE_NUMBER 1
 #define VENSPEC_IFRAME_LINE_NUMBER 3
 
-static int msm_hdmi_config_avi_infoframe(struct hdmi *hdmi,
-					 const u8 *buffer, size_t len)
+static int msm_hdmi_bridge_clear_avi_infoframe(struct drm_bridge *bridge)
 {
+	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
+	struct hdmi *hdmi = hdmi_bridge->hdmi;
+	u32 val;
+
+	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
+	val &= ~(HDMI_INFOFRAME_CTRL0_AVI_SEND |
+		 HDMI_INFOFRAME_CTRL0_AVI_CONT);
+	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
+
+	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
+	val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
+	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
+
+	return 0;
+}
+
+static int msm_hdmi_bridge_clear_audio_infoframe(struct drm_bridge *bridge)
+{
+	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
+	struct hdmi *hdmi = hdmi_bridge->hdmi;
+	u32 val;
+
+	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
+	val &= ~(HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND |
+		 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT |
+		 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE |
+		 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE);
+	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
+
+	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
+	val &= ~HDMI_INFOFRAME_CTRL1_AUDIO_INFO_LINE__MASK;
+	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
+
+	return 0;
+}
+
+static int msm_hdmi_bridge_clear_spd_infoframe(struct drm_bridge *bridge)
+{
+	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
+	struct hdmi *hdmi = hdmi_bridge->hdmi;
+	u32 val;
+
+	val = hdmi_read(hdmi, REG_HDMI_GEN_PKT_CTRL);
+	val &= ~(HDMI_GEN_PKT_CTRL_GENERIC1_SEND |
+		 HDMI_GEN_PKT_CTRL_GENERIC1_CONT |
+		 HDMI_GEN_PKT_CTRL_GENERIC1_LINE__MASK);
+	hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, val);
+
+	return 0;
+}
+
+static int msm_hdmi_bridge_clear_hdmi_infoframe(struct drm_bridge *bridge)
+{
+	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
+	struct hdmi *hdmi = hdmi_bridge->hdmi;
+	u32 val;
+
+	val = hdmi_read(hdmi, REG_HDMI_GEN_PKT_CTRL);
+	val &= ~(HDMI_GEN_PKT_CTRL_GENERIC0_SEND |
+		 HDMI_GEN_PKT_CTRL_GENERIC0_CONT |
+		 HDMI_GEN_PKT_CTRL_GENERIC0_UPDATE |
+		 HDMI_GEN_PKT_CTRL_GENERIC0_LINE__MASK);
+	hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, val);
+
+	return 0;
+}
+
+static int msm_hdmi_bridge_write_avi_infoframe(struct drm_bridge *bridge,
+					       const u8 *buffer, size_t len)
+{
+	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
+	struct hdmi *hdmi = hdmi_bridge->hdmi;
 	u32 buf[4] = {};
 	u32 val;
 	int i;
@@ -67,6 +138,8 @@ static int msm_hdmi_config_avi_infoframe(struct hdmi *hdmi,
 		return -EINVAL;
 	}
 
+	msm_hdmi_bridge_clear_avi_infoframe(bridge);
+
 	/*
 	 * the AVI_INFOx registers don't map exactly to how the AVI infoframes
 	 * are packed according to the spec. The checksum from the header is
@@ -93,9 +166,11 @@ static int msm_hdmi_config_avi_infoframe(struct hdmi *hdmi,
 	return 0;
 }
 
-static int msm_hdmi_config_audio_infoframe(struct hdmi *hdmi,
-					   const u8 *buffer, size_t len)
+static int msm_hdmi_bridge_write_audio_infoframe(struct drm_bridge *bridge,
+						 const u8 *buffer, size_t len)
 {
+	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
+	struct hdmi *hdmi = hdmi_bridge->hdmi;
 	u32 val;
 
 	if (len != HDMI_INFOFRAME_SIZE(AUDIO)) {
@@ -104,6 +179,8 @@ static int msm_hdmi_config_audio_infoframe(struct hdmi *hdmi,
 		return -EINVAL;
 	}
 
+	msm_hdmi_bridge_clear_audio_infoframe(bridge);
+
 	hdmi_write(hdmi, REG_HDMI_AUDIO_INFO0,
 		   buffer[3] |
 		   buffer[4] << 8 |
@@ -126,9 +203,11 @@ static int msm_hdmi_config_audio_infoframe(struct hdmi *hdmi,
 	return 0;
 }
 
-static int msm_hdmi_config_spd_infoframe(struct hdmi *hdmi,
-					 const u8 *buffer, size_t len)
+static int msm_hdmi_bridge_write_spd_infoframe(struct drm_bridge *bridge,
+					       const u8 *buffer, size_t len)
 {
+	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
+	struct hdmi *hdmi = hdmi_bridge->hdmi;
 	u32 buf[7] = {};
 	u32 val;
 	int i;
@@ -139,6 +218,8 @@ static int msm_hdmi_config_spd_infoframe(struct hdmi *hdmi,
 		return -EINVAL;
 	}
 
+	msm_hdmi_bridge_clear_spd_infoframe(bridge);
+
 	/* checksum gets written together with the body of the frame */
 	hdmi_write(hdmi, REG_HDMI_GENERIC1_HDR,
 		   buffer[0] |
@@ -159,9 +240,11 @@ static int msm_hdmi_config_spd_infoframe(struct hdmi *hdmi,
 	return 0;
 }
 
-static int msm_hdmi_config_hdmi_infoframe(struct hdmi *hdmi,
-					  const u8 *buffer, size_t len)
+static int msm_hdmi_bridge_write_hdmi_infoframe(struct drm_bridge *bridge,
+						const u8 *buffer, size_t len)
 {
+	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
+	struct hdmi *hdmi = hdmi_bridge->hdmi;
 	u32 buf[7] = {};
 	u32 val;
 	int i;
@@ -173,6 +256,8 @@ static int msm_hdmi_config_hdmi_infoframe(struct hdmi *hdmi,
 		return -EINVAL;
 	}
 
+	msm_hdmi_bridge_clear_hdmi_infoframe(bridge);
+
 	/* checksum gets written together with the body of the frame */
 	hdmi_write(hdmi, REG_HDMI_GENERIC0_HDR,
 		   buffer[0] |
@@ -194,90 +279,6 @@ static int msm_hdmi_config_hdmi_infoframe(struct hdmi *hdmi,
 	return 0;
 }
 
-static int msm_hdmi_bridge_clear_infoframe(struct drm_bridge *bridge,
-					   enum hdmi_infoframe_type type)
-{
-	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
-	struct hdmi *hdmi = hdmi_bridge->hdmi;
-	u32 val;
-
-	switch (type) {
-	case HDMI_INFOFRAME_TYPE_AVI:
-		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
-		val &= ~(HDMI_INFOFRAME_CTRL0_AVI_SEND |
-			 HDMI_INFOFRAME_CTRL0_AVI_CONT);
-		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
-
-		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
-		val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
-		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
-
-		break;
-
-	case HDMI_INFOFRAME_TYPE_AUDIO:
-		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
-		val &= ~(HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND |
-			 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT |
-			 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE |
-			 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE);
-		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
-
-		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
-		val &= ~HDMI_INFOFRAME_CTRL1_AUDIO_INFO_LINE__MASK;
-		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
-
-		break;
-
-	case HDMI_INFOFRAME_TYPE_SPD:
-		val = hdmi_read(hdmi, REG_HDMI_GEN_PKT_CTRL);
-		val &= ~(HDMI_GEN_PKT_CTRL_GENERIC1_SEND |
-			 HDMI_GEN_PKT_CTRL_GENERIC1_CONT |
-			 HDMI_GEN_PKT_CTRL_GENERIC1_LINE__MASK);
-		hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, val);
-
-		break;
-
-	case HDMI_INFOFRAME_TYPE_VENDOR:
-		val = hdmi_read(hdmi, REG_HDMI_GEN_PKT_CTRL);
-		val &= ~(HDMI_GEN_PKT_CTRL_GENERIC0_SEND |
-			 HDMI_GEN_PKT_CTRL_GENERIC0_CONT |
-			 HDMI_GEN_PKT_CTRL_GENERIC0_UPDATE |
-			 HDMI_GEN_PKT_CTRL_GENERIC0_LINE__MASK);
-		hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, val);
-
-		break;
-
-	default:
-		drm_dbg_driver(hdmi_bridge->base.dev, "Unsupported infoframe type %x\n", type);
-	}
-
-	return 0;
-}
-
-static int msm_hdmi_bridge_write_infoframe(struct drm_bridge *bridge,
-					   enum hdmi_infoframe_type type,
-					   const u8 *buffer, size_t len)
-{
-	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
-	struct hdmi *hdmi = hdmi_bridge->hdmi;
-
-	msm_hdmi_bridge_clear_infoframe(bridge, type);
-
-	switch (type) {
-	case HDMI_INFOFRAME_TYPE_AVI:
-		return msm_hdmi_config_avi_infoframe(hdmi, buffer, len);
-	case HDMI_INFOFRAME_TYPE_AUDIO:
-		return msm_hdmi_config_audio_infoframe(hdmi, buffer, len);
-	case HDMI_INFOFRAME_TYPE_SPD:
-		return msm_hdmi_config_spd_infoframe(hdmi, buffer, len);
-	case HDMI_INFOFRAME_TYPE_VENDOR:
-		return msm_hdmi_config_hdmi_infoframe(hdmi, buffer, len);
-	default:
-		drm_dbg_driver(hdmi_bridge->base.dev, "Unsupported infoframe type %x\n", type);
-		return 0;
-	}
-}
-
 static void msm_hdmi_set_timings(struct hdmi *hdmi,
 				 const struct drm_display_mode *mode);
 
@@ -462,8 +463,14 @@ static const struct drm_bridge_funcs msm_hdmi_bridge_funcs = {
 	.hpd_enable = msm_hdmi_hpd_enable,
 	.hpd_disable = msm_hdmi_hpd_disable,
 	.hdmi_tmds_char_rate_valid = msm_hdmi_bridge_tmds_char_rate_valid,
-	.hdmi_clear_infoframe = msm_hdmi_bridge_clear_infoframe,
-	.hdmi_write_infoframe = msm_hdmi_bridge_write_infoframe,
+	.hdmi_clear_audio_infoframe = msm_hdmi_bridge_clear_audio_infoframe,
+	.hdmi_write_audio_infoframe = msm_hdmi_bridge_write_audio_infoframe,
+	.hdmi_clear_avi_infoframe = msm_hdmi_bridge_clear_avi_infoframe,
+	.hdmi_write_avi_infoframe = msm_hdmi_bridge_write_avi_infoframe,
+	.hdmi_clear_spd_infoframe = msm_hdmi_bridge_clear_spd_infoframe,
+	.hdmi_write_spd_infoframe = msm_hdmi_bridge_write_spd_infoframe,
+	.hdmi_clear_hdmi_infoframe = msm_hdmi_bridge_clear_hdmi_infoframe,
+	.hdmi_write_hdmi_infoframe = msm_hdmi_bridge_write_hdmi_infoframe,
 	.hdmi_audio_prepare = msm_hdmi_bridge_audio_prepare,
 	.hdmi_audio_shutdown = msm_hdmi_bridge_audio_shutdown,
 };
diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
index 997429115068..9066ee2d1dff 100644
--- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c
+++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
@@ -158,35 +158,33 @@ static void rk3066_hdmi_set_power_mode(struct rk3066_hdmi *hdmi, int mode)
 		hdmi->tmdsclk = DEFAULT_PLLA_RATE;
 }
 
-static int rk3066_hdmi_bridge_clear_infoframe(struct drm_bridge *bridge,
-					      enum hdmi_infoframe_type type)
+static int rk3066_hdmi_bridge_clear_avi_infoframe(struct drm_bridge *bridge)
 {
 	struct rk3066_hdmi *hdmi = bridge_to_rk3066_hdmi(bridge);
 
-	if (type != HDMI_INFOFRAME_TYPE_AVI) {
-		drm_err(bridge->dev, "Unsupported infoframe type: %u\n", type);
-		return 0;
-	}
-
 	hdmi_writeb(hdmi, HDMI_CP_BUF_INDEX, HDMI_INFOFRAME_AVI);
 
 	return 0;
 }
 
 static int
-rk3066_hdmi_bridge_write_infoframe(struct drm_bridge *bridge,
-				   enum hdmi_infoframe_type type,
-				   const u8 *buffer, size_t len)
+rk3066_hdmi_bridge_clear_hdmi_infoframe(struct drm_bridge *bridge)
+{
+	/* FIXME: add support for this InfoFrame */
+
+	drm_warn_once(bridge->encoder->dev, "HDMI VSI not supported\n");
+
+	return 0;
+}
+
+static int
+rk3066_hdmi_bridge_write_avi_infoframe(struct drm_bridge *bridge,
+				       const u8 *buffer, size_t len)
 {
 	struct rk3066_hdmi *hdmi = bridge_to_rk3066_hdmi(bridge);
 	ssize_t i;
 
-	if (type != HDMI_INFOFRAME_TYPE_AVI) {
-		drm_err(bridge->dev, "Unsupported infoframe type: %u\n", type);
-		return 0;
-	}
-
-	rk3066_hdmi_bridge_clear_infoframe(bridge, type);
+	rk3066_hdmi_bridge_clear_avi_infoframe(bridge);
 
 	for (i = 0; i < len; i++)
 		hdmi_writeb(hdmi, HDMI_CP_BUF_ACC_HB0 + i * 4, buffer[i]);
@@ -194,6 +192,17 @@ rk3066_hdmi_bridge_write_infoframe(struct drm_bridge *bridge,
 	return 0;
 }
 
+static int
+rk3066_hdmi_bridge_write_hdmi_infoframe(struct drm_bridge *bridge,
+					const u8 *buffer, size_t len)
+{
+	rk3066_hdmi_bridge_clear_hdmi_infoframe(bridge);
+
+	/* FIXME: add support for this InfoFrame */
+
+	return 0;
+}
+
 static int rk3066_hdmi_config_video_timing(struct rk3066_hdmi *hdmi,
 					   struct drm_display_mode *mode)
 {
@@ -493,8 +502,10 @@ static const struct drm_bridge_funcs rk3066_hdmi_bridge_funcs = {
 	.atomic_disable = rk3066_hdmi_bridge_atomic_disable,
 	.detect = rk3066_hdmi_bridge_detect,
 	.edid_read = rk3066_hdmi_bridge_edid_read,
-	.hdmi_clear_infoframe = rk3066_hdmi_bridge_clear_infoframe,
-	.hdmi_write_infoframe = rk3066_hdmi_bridge_write_infoframe,
+	.hdmi_clear_avi_infoframe = rk3066_hdmi_bridge_clear_avi_infoframe,
+	.hdmi_write_avi_infoframe = rk3066_hdmi_bridge_write_avi_infoframe,
+	.hdmi_clear_hdmi_infoframe = rk3066_hdmi_bridge_clear_hdmi_infoframe,
+	.hdmi_write_hdmi_infoframe = rk3066_hdmi_bridge_write_hdmi_infoframe,
 	.mode_valid = rk3066_hdmi_bridge_mode_valid,
 };
 
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index d2683846cc61..071e2f72fd0f 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -784,29 +784,113 @@ struct drm_bridge_funcs {
 				     unsigned long long tmds_rate);
 
 	/**
-	 * @hdmi_clear_infoframe:
+	 * @hdmi_clear_avi_infoframe:
 	 *
 	 * This callback clears the infoframes in the hardware during commit.
-	 * It will be called multiple times, once for every disabled infoframe
-	 * type.
 	 *
 	 * This callback is optional but it must be implemented by bridges that
 	 * set the DRM_BRIDGE_OP_HDMI flag in their &drm_bridge->ops.
 	 */
-	int (*hdmi_clear_infoframe)(struct drm_bridge *bridge,
-				    enum hdmi_infoframe_type type);
+	int (*hdmi_clear_avi_infoframe)(struct drm_bridge *bridge);
+
+	/**
+	 * @hdmi_write_avi_infoframe:
+	 *
+	 * Program the infoframe into the hardware.
+	 *
+	 * This callback is optional but it must be implemented by bridges that
+	 * set the DRM_BRIDGE_OP_HDMI flag in their &drm_bridge->ops.
+	 */
+	int (*hdmi_write_avi_infoframe)(struct drm_bridge *bridge,
+					const u8 *buffer, size_t len);
+
+	/**
+	 * @hdmi_clear_hdmi_infoframe:
+	 *
+	 * This callback clears the infoframes in the hardware during commit.
+	 *
+	 * This callback is optional but it must be implemented by bridges that
+	 * set the DRM_BRIDGE_OP_HDMI flag in their &drm_bridge->ops.
+	 */
+	int (*hdmi_clear_hdmi_infoframe)(struct drm_bridge *bridge);
+
 	/**
-	 * @hdmi_write_infoframe:
+	 * @hdmi_write_hdmi_infoframe:
 	 *
-	 * Program the infoframe into the hardware. It will be called multiple
-	 * times, once for every updated infoframe type.
+	 * Program the infoframe into the hardware.
 	 *
 	 * This callback is optional but it must be implemented by bridges that
 	 * set the DRM_BRIDGE_OP_HDMI flag in their &drm_bridge->ops.
 	 */
-	int (*hdmi_write_infoframe)(struct drm_bridge *bridge,
-				    enum hdmi_infoframe_type type,
-				    const u8 *buffer, size_t len);
+	int (*hdmi_write_hdmi_infoframe)(struct drm_bridge *bridge,
+					    const u8 *buffer, size_t len);
+
+	/**
+	 * @hdmi_clear_hdr_drm_infoframe:
+	 *
+	 * This callback clears the infoframes in the hardware during commit.
+	 *
+	 * This callback is optional but it must be implemented by bridges that
+	 * set the DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME flag in their
+	 * &drm_bridge->ops.
+	 */
+	int (*hdmi_clear_hdr_drm_infoframe)(struct drm_bridge *bridge);
+
+	/**
+	 * @hdmi_write_hdr_drm_infoframe:
+	 *
+	 * Program the infoframe into the hardware.
+	 *
+	 * This callback is optional but it must be implemented by bridges that
+	 * set the DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME flag in their
+	 * &drm_bridge->ops.
+	 */
+	int (*hdmi_write_hdr_drm_infoframe)(struct drm_bridge *bridge,
+					const u8 *buffer, size_t len);
+
+	/**
+	 * @hdmi_clear_spd_infoframe:
+	 *
+	 * This callback clears the infoframes in the hardware during commit.
+	 *
+	 * This callback is optional but it must be implemented by bridges that
+	 * set the DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME flag in their
+	 * &drm_bridge->ops.
+	 */
+	int (*hdmi_clear_spd_infoframe)(struct drm_bridge *bridge);
+
+	/**
+	 * @hdmi_write_spd_infoframe:
+	 *
+	 * Program the infoframe into the hardware.
+	 *
+	 * This callback is optional but it must be implemented by bridges that
+	 * set the DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME flag in their
+	 * &drm_bridge->ops.
+	 */
+	int (*hdmi_write_spd_infoframe)(struct drm_bridge *bridge,
+					const u8 *buffer, size_t len);
+
+	/**
+	 * @hdmi_clear_audio_infoframe:
+	 *
+	 * This callback clears the infoframes in the hardware during commit.
+	 *
+	 * This callback is optional but it must be implemented by bridges that
+	 * set the DRM_BRIDGE_OP_HDMI_AUDIO flag in their &drm_bridge->ops.
+	 */
+	int (*hdmi_clear_audio_infoframe)(struct drm_bridge *bridge);
+
+	/**
+	 * @hdmi_write_audio_infoframe:
+	 *
+	 * Program the infoframe into the hardware.
+	 *
+	 * This callback is optional but it must be implemented by bridges that
+	 * set the DRM_BRIDGE_OP_HDMI_AUDIO flag in their &drm_bridge->ops.
+	 */
+	int (*hdmi_write_audio_infoframe)(struct drm_bridge *bridge,
+					  const u8 *buffer, size_t len);
 
 	/**
 	 * @hdmi_audio_startup:
@@ -1062,7 +1146,11 @@ enum drm_bridge_ops {
 	/**
 	 * @DRM_BRIDGE_OP_HDMI: The bridge provides HDMI connector operations,
 	 * including infoframes support. Bridges that set this flag must
-	 * implement the &drm_bridge_funcs->write_infoframe callback.
+	 * provide HDMI-related information and implement the
+	 * &drm_bridge_funcs->clear_avi_infoframe,
+	 * &drm_bridge_funcs->write_avi_infoframe,
+	 * &drm_bridge_funcs->clear_hdmi_infoframe and
+	 * &drm_bridge_funcs->write_hdmi_infoframe callbacks.
 	 *
 	 * Note: currently there can be at most one bridge in a chain that sets
 	 * this bit. This is to simplify corresponding glue code in connector
@@ -1074,6 +1162,9 @@ enum drm_bridge_ops {
 	 * Bridges that set this flag must implement the
 	 * &drm_bridge_funcs->hdmi_audio_prepare and
 	 * &drm_bridge_funcs->hdmi_audio_shutdown callbacks.
+	 * If the bridge implements @DRM_BRIDGE_OP_HDMI, it also must implement
+	 * &drm_bridge_funcs->hdmi_write_audio_infoframe and
+	 * &drm_bridge_funcs->hdmi_cleaer_audio_infoframe callbacks.
 	 *
 	 * Note: currently there can be at most one bridge in a chain that sets
 	 * this bit. This is to simplify corresponding glue code in connector
@@ -1105,6 +1196,18 @@ enum drm_bridge_ops {
 	 * to be present.
 	 */
 	DRM_BRIDGE_OP_HDMI_CEC_ADAPTER = BIT(8),
+	/**
+	 * @DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME: The bridge supports
+	 * &drm_bridge_funcs->hdmi_write_hdr_drm_infoframe and
+	 * &drm_bridge_funcs->hdmi_clear_hdr_drm_infoframe callbacks.
+	 */
+	DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME = BIT(9),
+	/**
+	 * @DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME: The bridge supports
+	 * &drm_bridge_funcs->hdmi_write_spd_infoframe and
+	 * &drm_bridge_funcs->hdmi_clear_spd_infoframe callbacks.
+	 */
+	DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME = BIT(10),
 };
 
 /**

-- 
2.47.3



From dmitry.baryshkov at oss.qualcomm.com  Tue Dec 23 17:02:55 2025
From: dmitry.baryshkov at oss.qualcomm.com (Dmitry Baryshkov)
Date: Wed, 24 Dec 2025 03:02:55 +0200
Subject: [PATCH v3 06/10] drm/display: hdmi_state_helper: split InfoFrame
 functions per type
In-Reply-To: <20251224-limit-infoframes-2-v3-0-7fd3cacfefed@oss.qualcomm.com>
References: <20251224-limit-infoframes-2-v3-0-7fd3cacfefed@oss.qualcomm.com>
Message-ID: <20251224-limit-infoframes-2-v3-6-7fd3cacfefed@oss.qualcomm.com>

Havign a single set of InfoFrame callbacks doesn't provide enough
information to the DRM framework about the InfoFrame types that are
actually supported. Also it's not really future-proof: it provides a way
to program only a single Vendor-Specific frame, however we might need to
support multiple VSIs at the same time (e.g. HDMI vs HDMI Forum
VSIs).

Provide separate sets of callbacks, one per the InfoFrame type.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
---
 drivers/gpu/drm/display/drm_bridge_connector.c     | 206 ++++++++++++++++-----
 drivers/gpu/drm/display/drm_hdmi_state_helper.c    |  86 ++++-----
 drivers/gpu/drm/drm_connector.c                    |   6 +-
 drivers/gpu/drm/rockchip/inno_hdmi.c               |  47 +++--
 drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c             |  39 ++--
 drivers/gpu/drm/tests/drm_connector_test.c         |  14 +-
 drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 102 +++++-----
 drivers/gpu/drm/vc4/vc4_hdmi.c                     |  82 +++++++-
 include/drm/drm_connector.h                        | 105 ++++++++---
 9 files changed, 482 insertions(+), 205 deletions(-)

diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 8fd7722fe9a3..c8858d48199c 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -401,8 +401,7 @@ drm_bridge_connector_tmds_char_rate_valid(const struct drm_connector *connector,
 		return MODE_OK;
 }
 
-static int drm_bridge_connector_clear_infoframe(struct drm_connector *connector,
-						enum hdmi_infoframe_type type)
+static int drm_bridge_connector_clear_avi_infoframe(struct drm_connector *connector)
 {
 	struct drm_bridge_connector *bridge_connector =
 		to_drm_bridge_connector(connector);
@@ -412,35 +411,70 @@ static int drm_bridge_connector_clear_infoframe(struct drm_connector *connector,
 	if (!bridge)
 		return -EINVAL;
 
-	switch (type) {
-	case HDMI_INFOFRAME_TYPE_AVI:
-		/* required */
-		return bridge->funcs->hdmi_clear_avi_infoframe(bridge);
-	case HDMI_INFOFRAME_TYPE_VENDOR:
-		/* required */
-		return bridge->funcs->hdmi_clear_hdmi_infoframe(bridge);
-	case HDMI_INFOFRAME_TYPE_AUDIO:
-		if (bridge->ops & DRM_BRIDGE_OP_HDMI_AUDIO)
-			return bridge->funcs->hdmi_clear_audio_infoframe(bridge);
-		break;
-	case HDMI_INFOFRAME_TYPE_DRM:
-		if (bridge->ops & DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME)
-			return bridge->funcs->hdmi_clear_hdr_drm_infoframe(bridge);
-		break;
-	case HDMI_INFOFRAME_TYPE_SPD:
-		if (bridge->ops & DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME)
-			return bridge->funcs->hdmi_clear_spd_infoframe(bridge);
-		break;
-	}
+	return bridge->funcs->hdmi_clear_avi_infoframe(bridge);
+}
+
+static int drm_bridge_connector_write_avi_infoframe(struct drm_connector *connector,
+						    const u8 *buffer, size_t len)
+{
+	struct drm_bridge_connector *bridge_connector =
+		to_drm_bridge_connector(connector);
+	struct drm_bridge *bridge;
+
+	bridge = bridge_connector->bridge_hdmi;
+	if (!bridge)
+		return -EINVAL;
+
+	return bridge->funcs->hdmi_write_avi_infoframe(bridge, buffer, len);
+}
 
-	drm_dbg_driver(connector->dev, "Unsupported HDMI InfoFrame %x\n", type);
+static int drm_bridge_connector_clear_hdmi_infoframe(struct drm_connector *connector)
+{
+	struct drm_bridge_connector *bridge_connector =
+		to_drm_bridge_connector(connector);
+	struct drm_bridge *bridge;
+
+	bridge = bridge_connector->bridge_hdmi;
+	if (!bridge)
+		return -EINVAL;
+
+	return bridge->funcs->hdmi_clear_hdmi_infoframe(bridge);
+}
+
+static int drm_bridge_connector_write_hdmi_infoframe(struct drm_connector *connector,
+						     const u8 *buffer, size_t len)
+{
+	struct drm_bridge_connector *bridge_connector =
+		to_drm_bridge_connector(connector);
+	struct drm_bridge *bridge;
+
+	bridge = bridge_connector->bridge_hdmi;
+	if (!bridge)
+		return -EINVAL;
+
+	return bridge->funcs->hdmi_write_hdmi_infoframe(bridge, buffer, len);
+}
+
+static int drm_bridge_connector_clear_audio_infoframe(struct drm_connector *connector)
+{
+	struct drm_bridge_connector *bridge_connector =
+		to_drm_bridge_connector(connector);
+	struct drm_bridge *bridge;
+
+	bridge = bridge_connector->bridge_hdmi;
+	if (!bridge)
+		return -EINVAL;
+
+	if (bridge->ops & DRM_BRIDGE_OP_HDMI_AUDIO)
+		return bridge->funcs->hdmi_clear_audio_infoframe(bridge);
+
+	drm_dbg_driver(connector->dev, "Unsupported HDMI Audio InfoFrame\n");
 
 	return 0;
 }
 
-static int drm_bridge_connector_write_infoframe(struct drm_connector *connector,
-						enum hdmi_infoframe_type type,
-						const u8 *buffer, size_t len)
+static int drm_bridge_connector_write_audio_infoframe(struct drm_connector *connector,
+						      const u8 *buffer, size_t len)
 {
 	struct drm_bridge_connector *bridge_connector =
 		to_drm_bridge_connector(connector);
@@ -450,28 +484,84 @@ static int drm_bridge_connector_write_infoframe(struct drm_connector *connector,
 	if (!bridge)
 		return -EINVAL;
 
-	switch (type) {
-	case HDMI_INFOFRAME_TYPE_AVI:
-		/* required */
-		return bridge->funcs->hdmi_write_avi_infoframe(bridge, buffer, len);
-	case HDMI_INFOFRAME_TYPE_VENDOR:
-		/* required */
-		return bridge->funcs->hdmi_write_hdmi_infoframe(bridge, buffer, len);
-	case HDMI_INFOFRAME_TYPE_AUDIO:
-		if (bridge->ops & DRM_BRIDGE_OP_HDMI_AUDIO)
-			return bridge->funcs->hdmi_write_audio_infoframe(bridge, buffer, len);
-		break;
-	case HDMI_INFOFRAME_TYPE_DRM:
-		if (bridge->ops & DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME)
-			return bridge->funcs->hdmi_write_hdr_drm_infoframe(bridge, buffer, len);
-		break;
-	case HDMI_INFOFRAME_TYPE_SPD:
-		if (bridge->ops & DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME)
-			return bridge->funcs->hdmi_write_spd_infoframe(bridge, buffer, len);
-		break;
-	}
+	if (bridge->ops & DRM_BRIDGE_OP_HDMI_AUDIO)
+		return bridge->funcs->hdmi_write_audio_infoframe(bridge, buffer, len);
+
+	drm_dbg_driver(connector->dev, "Unsupported HDMI Audio InfoFrame\n");
+
+	return 0;
+}
+
+static int drm_bridge_connector_clear_hdr_drm_infoframe(struct drm_connector *connector)
+{
+	struct drm_bridge_connector *bridge_connector =
+		to_drm_bridge_connector(connector);
+	struct drm_bridge *bridge;
+
+	bridge = bridge_connector->bridge_hdmi;
+	if (!bridge)
+		return -EINVAL;
+
+	if (bridge->ops & DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME)
+		return bridge->funcs->hdmi_clear_hdr_drm_infoframe(bridge);
+
+	drm_dbg_driver(connector->dev, "Unsupported HDMI HDR DRM InfoFrame\n");
+
+	return 0;
+}
+
+static int drm_bridge_connector_write_hdr_drm_infoframe(struct drm_connector *connector,
+							const u8 *buffer, size_t len)
+{
+	struct drm_bridge_connector *bridge_connector =
+		to_drm_bridge_connector(connector);
+	struct drm_bridge *bridge;
+
+	bridge = bridge_connector->bridge_hdmi;
+	if (!bridge)
+		return -EINVAL;
+
+	if (bridge->ops & DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME)
+		return bridge->funcs->hdmi_write_hdr_drm_infoframe(bridge, buffer, len);
+
+	drm_dbg_driver(connector->dev, "Unsupported HDMI HDR DRM InfoFrame\n");
+
+	return 0;
+}
+
+static int drm_bridge_connector_clear_spd_infoframe(struct drm_connector *connector)
+{
+	struct drm_bridge_connector *bridge_connector =
+		to_drm_bridge_connector(connector);
+	struct drm_bridge *bridge;
+
+	bridge = bridge_connector->bridge_hdmi;
+	if (!bridge)
+		return -EINVAL;
+
+	if (bridge->ops & DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME)
+		return bridge->funcs->hdmi_clear_spd_infoframe(bridge);
+
+	drm_dbg_driver(connector->dev, "Unsupported HDMI SPD InfoFrame\n");
+
+	return 0;
+}
+
+static int drm_bridge_connector_write_spd_infoframe(struct drm_connector *connector,
+						    const u8 *buffer, size_t len)
+{
+	struct drm_bridge_connector *bridge_connector =
+		to_drm_bridge_connector(connector);
+	struct drm_bridge *bridge;
+
+	bridge = bridge_connector->bridge_hdmi;
+	if (!bridge)
+		return -EINVAL;
+
+	if (bridge->ops & DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME)
+		return bridge->funcs->hdmi_write_spd_infoframe(bridge, buffer, len);
 
-	drm_dbg_driver(connector->dev, "Unsupported HDMI InfoFrame %x\n", type);
+	drm_dbg_driver(connector->dev, "Unsupported HDMI SPD InfoFrame\n");
 
 	return 0;
 }
@@ -492,9 +582,27 @@ drm_bridge_connector_read_edid(struct drm_connector *connector)
 
 static const struct drm_connector_hdmi_funcs drm_bridge_connector_hdmi_funcs = {
 	.tmds_char_rate_valid = drm_bridge_connector_tmds_char_rate_valid,
-	.clear_infoframe = drm_bridge_connector_clear_infoframe,
-	.write_infoframe = drm_bridge_connector_write_infoframe,
 	.read_edid = drm_bridge_connector_read_edid,
+	.avi = {
+		.clear_infoframe = drm_bridge_connector_clear_avi_infoframe,
+		.write_infoframe = drm_bridge_connector_write_avi_infoframe,
+	},
+	.hdmi = {
+		.clear_infoframe = drm_bridge_connector_clear_hdmi_infoframe,
+		.write_infoframe = drm_bridge_connector_write_hdmi_infoframe,
+	},
+	.audio = {
+		.clear_infoframe = drm_bridge_connector_clear_audio_infoframe,
+		.write_infoframe = drm_bridge_connector_write_audio_infoframe,
+	},
+	.hdr_drm = {
+		.clear_infoframe = drm_bridge_connector_clear_hdr_drm_infoframe,
+		.write_infoframe = drm_bridge_connector_write_hdr_drm_infoframe,
+	},
+	.spd = {
+		.clear_infoframe = drm_bridge_connector_clear_spd_infoframe,
+		.write_infoframe = drm_bridge_connector_write_spd_infoframe,
+	},
 };
 
 static int drm_bridge_connector_audio_startup(struct drm_connector *connector)
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index a561f124be99..5a3817271d91 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -891,21 +891,21 @@ drm_hdmi_connector_mode_valid(struct drm_connector *connector,
 }
 EXPORT_SYMBOL(drm_hdmi_connector_mode_valid);
 
-static int clear_device_infoframe(struct drm_connector *connector,
-				  enum hdmi_infoframe_type type)
+static int clear_infoframe(struct drm_connector *connector,
+			   const struct drm_connector_infoframe_funcs *funcs,
+			   const char *type)
 {
-	const struct drm_connector_hdmi_funcs *funcs = connector->hdmi.funcs;
 	struct drm_device *dev = connector->dev;
 	int ret;
 
-	drm_dbg_kms(dev, "Clearing infoframe type 0x%x\n", type);
+	drm_dbg_kms(dev, "Clearing %s InfoFrame\n", type);
 
-	if (!funcs || !funcs->clear_infoframe) {
+	if (!funcs->clear_infoframe) {
 		drm_dbg_kms(dev, "Function not implemented, bailing.\n");
 		return 0;
 	}
 
-	ret = funcs->clear_infoframe(connector, type);
+	ret = funcs->clear_infoframe(connector);
 	if (ret) {
 		drm_dbg_kms(dev, "Call failed: %d\n", ret);
 		return ret;
@@ -914,39 +914,28 @@ static int clear_device_infoframe(struct drm_connector *connector,
 	return 0;
 }
 
-static int clear_infoframe(struct drm_connector *connector,
-			   struct drm_connector_hdmi_infoframe *old_frame)
-{
-	int ret;
-
-	ret = clear_device_infoframe(connector, old_frame->data.any.type);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static int write_device_infoframe(struct drm_connector *connector,
-				  union hdmi_infoframe *frame)
+static int write_infoframe(struct drm_connector *connector,
+			   const struct drm_connector_infoframe_funcs *funcs,
+			   const char *type,
+			   struct drm_connector_hdmi_infoframe *new_frame)
 {
-	const struct drm_connector_hdmi_funcs *funcs = connector->hdmi.funcs;
 	struct drm_device *dev = connector->dev;
 	u8 buffer[HDMI_INFOFRAME_SIZE(MAX)];
 	int ret;
 	int len;
 
-	drm_dbg_kms(dev, "Writing infoframe type %x\n", frame->any.type);
+	drm_dbg_kms(dev, "Writing %s InfoFrame\n", type);
 
-	if (!funcs || !funcs->write_infoframe) {
+	if (!funcs->write_infoframe) {
 		drm_dbg_kms(dev, "Function not implemented, bailing.\n");
-		return -EINVAL;
+		return 0; /* XXX: temporal until we stop generating unsupported frames */
 	}
 
-	len = hdmi_infoframe_pack(frame, buffer, sizeof(buffer));
+	len = hdmi_infoframe_pack(&new_frame->data, buffer, sizeof(buffer));
 	if (len < 0)
 		return len;
 
-	ret = funcs->write_infoframe(connector, frame->any.type, buffer, len);
+	ret = funcs->write_infoframe(connector, buffer, len);
 	if (ret) {
 		drm_dbg_kms(dev, "Call failed: %d\n", ret);
 		return ret;
@@ -955,27 +944,17 @@ static int write_device_infoframe(struct drm_connector *connector,
 	return 0;
 }
 
-static int write_infoframe(struct drm_connector *connector,
-			   struct drm_connector_hdmi_infoframe *new_frame)
-{
-	int ret;
-
-	ret = write_device_infoframe(connector, &new_frame->data);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
 static int write_or_clear_infoframe(struct drm_connector *connector,
+				    const struct drm_connector_infoframe_funcs *funcs,
+				    const char *type,
 				    struct drm_connector_hdmi_infoframe *old_frame,
 				    struct drm_connector_hdmi_infoframe *new_frame)
 {
 	if (new_frame->set)
-		return write_infoframe(connector, new_frame);
+		return write_infoframe(connector, funcs, type, new_frame);
 
 	if (old_frame->set && !new_frame->set)
-		return clear_infoframe(connector, old_frame);
+		return clear_infoframe(connector, funcs, type);
 
 	return 0;
 }
@@ -995,6 +974,7 @@ static int write_or_clear_infoframe(struct drm_connector *connector,
 int drm_atomic_helper_connector_hdmi_update_infoframes(struct drm_connector *connector,
 						       struct drm_atomic_state *state)
 {
+	const struct drm_connector_hdmi_funcs *funcs = connector->hdmi.funcs;
 	struct drm_connector_state *old_conn_state =
 		drm_atomic_get_old_connector_state(state, connector);
 	struct drm_connector_state *new_conn_state =
@@ -1005,9 +985,15 @@ int drm_atomic_helper_connector_hdmi_update_infoframes(struct drm_connector *con
 	if (!info->is_hdmi)
 		return 0;
 
+	if (!funcs) {
+		drm_dbg_kms(connector->dev, "Function not implemented, bailing.\n");
+		return -EINVAL;
+	}
+
 	mutex_lock(&connector->hdmi.infoframes.lock);
 
 	ret = write_or_clear_infoframe(connector,
+				       &funcs->avi, "AVI",
 				       &old_conn_state->hdmi.infoframes.avi,
 				       &new_conn_state->hdmi.infoframes.avi);
 	if (ret)
@@ -1015,18 +1001,21 @@ int drm_atomic_helper_connector_hdmi_update_infoframes(struct drm_connector *con
 
 	if (connector->hdmi.infoframes.audio.set) {
 		ret = write_infoframe(connector,
+				      &funcs->audio, "Audio",
 				      &connector->hdmi.infoframes.audio);
 		if (ret)
 			goto out;
 	}
 
 	ret = write_or_clear_infoframe(connector,
+				       &funcs->hdr_drm, "HDR DRM",
 				       &old_conn_state->hdmi.infoframes.hdr_drm,
 				       &new_conn_state->hdmi.infoframes.hdr_drm);
 	if (ret)
 		goto out;
 
 	ret = write_or_clear_infoframe(connector,
+				       &funcs->spd, "SPD",
 				       &old_conn_state->hdmi.infoframes.spd,
 				       &new_conn_state->hdmi.infoframes.spd);
 	if (ret)
@@ -1034,6 +1023,7 @@ int drm_atomic_helper_connector_hdmi_update_infoframes(struct drm_connector *con
 
 	if (info->has_hdmi_infoframe) {
 		ret = write_or_clear_infoframe(connector,
+					       &funcs->hdmi, "HDMI-VS",
 					       &old_conn_state->hdmi.infoframes.hdmi,
 					       &new_conn_state->hdmi.infoframes.hdmi);
 		if (ret)
@@ -1062,6 +1052,7 @@ int
 drm_atomic_helper_connector_hdmi_update_audio_infoframe(struct drm_connector *connector,
 							struct hdmi_audio_infoframe *frame)
 {
+	const struct drm_connector_hdmi_funcs *funcs = connector->hdmi.funcs;
 	struct drm_connector_hdmi_infoframe *infoframe =
 		&connector->hdmi.infoframes.audio;
 	struct drm_display_info *info = &connector->display_info;
@@ -1070,12 +1061,17 @@ drm_atomic_helper_connector_hdmi_update_audio_infoframe(struct drm_connector *co
 	if (!info->is_hdmi)
 		return 0;
 
+	if (!funcs) {
+		drm_dbg_kms(connector->dev, "Function not implemented, bailing.\n");
+		return -EINVAL;
+	}
+
 	mutex_lock(&connector->hdmi.infoframes.lock);
 
 	memcpy(&infoframe->data, frame, sizeof(infoframe->data));
 	infoframe->set = true;
 
-	ret = write_infoframe(connector, infoframe);
+	ret = write_infoframe(connector, &funcs->audio, "Audio", infoframe);
 
 	mutex_unlock(&connector->hdmi.infoframes.lock);
 
@@ -1097,6 +1093,7 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_update_audio_infoframe);
 int
 drm_atomic_helper_connector_hdmi_clear_audio_infoframe(struct drm_connector *connector)
 {
+	const struct drm_connector_hdmi_funcs *funcs = connector->hdmi.funcs;
 	struct drm_connector_hdmi_infoframe *infoframe =
 		&connector->hdmi.infoframes.audio;
 	struct drm_display_info *info = &connector->display_info;
@@ -1105,11 +1102,16 @@ drm_atomic_helper_connector_hdmi_clear_audio_infoframe(struct drm_connector *con
 	if (!info->is_hdmi)
 		return 0;
 
+	if (!funcs) {
+		drm_dbg_kms(connector->dev, "Function not implemented, bailing.\n");
+		return -EINVAL;
+	}
+
 	mutex_lock(&connector->hdmi.infoframes.lock);
 
 	infoframe->set = false;
 
-	ret = clear_infoframe(connector, infoframe);
+	ret = clear_infoframe(connector, &funcs->audio, "Audio");
 
 	memset(&infoframe->data, 0, sizeof(infoframe->data));
 
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 40e025712c9b..4f5b27fab475 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -600,8 +600,10 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
 	if (!(max_bpc == 8 || max_bpc == 10 || max_bpc == 12))
 		return -EINVAL;
 
-	if (!hdmi_funcs->clear_infoframe ||
-	    !hdmi_funcs->write_infoframe)
+	if (!hdmi_funcs->avi.clear_infoframe ||
+	    !hdmi_funcs->avi.write_infoframe ||
+	    !hdmi_funcs->hdmi.clear_infoframe ||
+	    !hdmi_funcs->hdmi.write_infoframe)
 		return -EINVAL;
 
 	ret = drmm_connector_init(dev, connector, funcs, connector_type, ddc);
diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c
index 9f7a8cf0ab44..1575f05bb4af 100644
--- a/drivers/gpu/drm/rockchip/inno_hdmi.c
+++ b/drivers/gpu/drm/rockchip/inno_hdmi.c
@@ -637,36 +637,22 @@ static void inno_hdmi_init_hw(struct inno_hdmi *hdmi)
 	hdmi_modb(hdmi, HDMI_STATUS, m_MASK_INT_HOTPLUG, v_MASK_INT_HOTPLUG(1));
 }
 
-static int inno_hdmi_disable_frame(struct drm_connector *connector,
-				   enum hdmi_infoframe_type type)
+static int inno_hdmi_clear_avi_infoframe(struct drm_connector *connector)
 {
 	struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector);
 
-	if (type != HDMI_INFOFRAME_TYPE_AVI) {
-		drm_err(connector->dev,
-			"Unsupported infoframe type: %u\n", type);
-		return 0;
-	}
-
 	hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_BUF_INDEX, INFOFRAME_AVI);
 
 	return 0;
 }
 
-static int inno_hdmi_upload_frame(struct drm_connector *connector,
-				  enum hdmi_infoframe_type type,
-				  const u8 *buffer, size_t len)
+static int inno_hdmi_write_avi_infoframe(struct drm_connector *connector,
+					 const u8 *buffer, size_t len)
 {
 	struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector);
 	ssize_t i;
 
-	if (type != HDMI_INFOFRAME_TYPE_AVI) {
-		drm_err(connector->dev,
-			"Unsupported infoframe type: %u\n", type);
-		return 0;
-	}
-
-	inno_hdmi_disable_frame(connector, type);
+	inno_hdmi_clear_avi_infoframe(connector);
 
 	for (i = 0; i < len; i++)
 		hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_ADDR + i, buffer[i]);
@@ -674,9 +660,30 @@ static int inno_hdmi_upload_frame(struct drm_connector *connector,
 	return 0;
 }
 
+static int inno_hdmi_clear_hdmi_infoframe(struct drm_connector *connector)
+{
+	drm_warn_once(connector->dev, "HDMI VSI not implemented\n");
+
+	return 0;
+}
+
+static int inno_hdmi_write_hdmi_infoframe(struct drm_connector *connector,
+					  const u8 *buffer, size_t len)
+{
+	drm_warn_once(connector->dev, "HDMI VSI not implemented\n");
+
+	return 0;
+}
+
 static const struct drm_connector_hdmi_funcs inno_hdmi_hdmi_connector_funcs = {
-	.clear_infoframe	= inno_hdmi_disable_frame,
-	.write_infoframe	= inno_hdmi_upload_frame,
+	.avi = {
+		.clear_infoframe	= inno_hdmi_clear_avi_infoframe,
+		.write_infoframe	= inno_hdmi_write_avi_infoframe,
+	},
+	.hdmi = {
+		.clear_infoframe	= inno_hdmi_clear_hdmi_infoframe,
+		.write_infoframe	= inno_hdmi_write_hdmi_infoframe,
+	},
 };
 
 static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi)
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
index 6263ee15880a..a50f260c73e4 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
@@ -40,27 +40,19 @@
 #define drm_connector_to_sun4i_hdmi(c)		\
 	container_of_const(c, struct sun4i_hdmi, connector)
 
-static int sun4i_hdmi_clear_infoframe(struct drm_connector *connector,
-				      enum hdmi_infoframe_type type)
+static int sun4i_hdmi_clear_avi_infoframe(struct drm_connector *connector)
 {
 	drm_warn_once(connector->dev, "clearing of AVI infoframe is not implemented\n");
 
 	return 0;
 }
 
-static int sun4i_hdmi_write_infoframe(struct drm_connector *connector,
-				      enum hdmi_infoframe_type type,
-				      const u8 *buffer, size_t len)
+static int sun4i_hdmi_write_avi_infoframe(struct drm_connector *connector,
+					  const u8 *buffer, size_t len)
 {
 	struct sun4i_hdmi *hdmi = drm_connector_to_sun4i_hdmi(connector);
 	int i;
 
-	if (type != HDMI_INFOFRAME_TYPE_AVI) {
-		drm_err(connector->dev,
-			"Unsupported infoframe type: %u\n", type);
-		return 0;
-	}
-
 	for (i = 0; i < len; i++)
 		writeb(buffer[i], hdmi->base + SUN4I_HDMI_AVI_INFOFRAME_REG(i));
 
@@ -68,6 +60,21 @@ static int sun4i_hdmi_write_infoframe(struct drm_connector *connector,
 
 }
 
+static int sun4i_hdmi_clear_hdmi_infoframe(struct drm_connector *connector)
+{
+	drm_warn_once(connector->dev, "HDMI VSI not implemented\n");
+
+	return 0;
+}
+
+static int sun4i_hdmi_write_hdmi_infoframe(struct drm_connector *connector,
+					   const u8 *buffer, size_t len)
+{
+	drm_warn_once(connector->dev, "HDMI VSI not implemented\n");
+
+	return 0;
+}
+
 static void sun4i_hdmi_disable(struct drm_encoder *encoder,
 			       struct drm_atomic_state *state)
 {
@@ -244,8 +251,14 @@ static struct i2c_adapter *sun4i_hdmi_get_ddc(struct device *dev)
 
 static const struct drm_connector_hdmi_funcs sun4i_hdmi_hdmi_connector_funcs = {
 	.tmds_char_rate_valid	= sun4i_hdmi_connector_clock_valid,
-	.clear_infoframe	= sun4i_hdmi_clear_infoframe,
-	.write_infoframe	= sun4i_hdmi_write_infoframe,
+	.avi = {
+		.clear_infoframe	= sun4i_hdmi_clear_avi_infoframe,
+		.write_infoframe	= sun4i_hdmi_write_avi_infoframe,
+	},
+	.hdmi = {
+		.clear_infoframe	= sun4i_hdmi_clear_hdmi_infoframe,
+		.write_infoframe	= sun4i_hdmi_write_hdmi_infoframe,
+	},
 };
 
 static const struct drm_connector_helper_funcs sun4i_hdmi_connector_helper_funcs = {
diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c
index f356ea695ae7..86860ad0861c 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -25,22 +25,26 @@ struct drm_connector_init_priv {
 	struct i2c_adapter ddc;
 };
 
-static int accept_infoframe_clear_infoframe(struct drm_connector *connector,
-					    enum hdmi_infoframe_type type)
+static int accept_infoframe_clear_infoframe(struct drm_connector *connector)
 {
 	return 0;
 }
 
 static int accept_infoframe_write_infoframe(struct drm_connector *connector,
-					    enum hdmi_infoframe_type type,
 					    const u8 *buffer, size_t len)
 {
 	return 0;
 }
 
 static const struct drm_connector_hdmi_funcs dummy_hdmi_funcs = {
-	.clear_infoframe = accept_infoframe_clear_infoframe,
-	.write_infoframe = accept_infoframe_write_infoframe,
+	.avi = {
+		.clear_infoframe = accept_infoframe_clear_infoframe,
+		.write_infoframe = accept_infoframe_write_infoframe,
+	},
+	.hdmi = {
+		.clear_infoframe = accept_infoframe_clear_infoframe,
+		.write_infoframe = accept_infoframe_write_infoframe,
+	},
 };
 
 static const struct drm_connector_funcs dummy_funcs = {
diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
index 915dcd106703..7e4e986bdfd6 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -76,22 +76,26 @@ static int set_connector_edid(struct kunit *test, struct drm_connector *connecto
 	return ret;
 }
 
-static int accept_infoframe_clear_infoframe(struct drm_connector *connector,
-					    enum hdmi_infoframe_type type)
+static int accept_infoframe_clear_infoframe(struct drm_connector *connector)
 {
 	return 0;
 }
 
 static int accept_infoframe_write_infoframe(struct drm_connector *connector,
-					    enum hdmi_infoframe_type type,
 					    const u8 *buffer, size_t len)
 {
 	return 0;
 }
 
 static const struct drm_connector_hdmi_funcs dummy_connector_hdmi_funcs = {
-	.clear_infoframe = accept_infoframe_clear_infoframe,
-	.write_infoframe = accept_infoframe_write_infoframe,
+	.avi = {
+		.clear_infoframe = accept_infoframe_clear_infoframe,
+		.write_infoframe = accept_infoframe_write_infoframe,
+	},
+	.hdmi = {
+		.clear_infoframe = accept_infoframe_clear_infoframe,
+		.write_infoframe = accept_infoframe_write_infoframe,
+	},
 };
 
 static enum drm_mode_status
@@ -104,8 +108,14 @@ reject_connector_tmds_char_rate_valid(const struct drm_connector *connector,
 
 static const struct drm_connector_hdmi_funcs reject_connector_hdmi_funcs = {
 	.tmds_char_rate_valid	= reject_connector_tmds_char_rate_valid,
-	.clear_infoframe = accept_infoframe_clear_infoframe,
-	.write_infoframe = accept_infoframe_write_infoframe,
+	.avi = {
+		.clear_infoframe = accept_infoframe_clear_infoframe,
+		.write_infoframe = accept_infoframe_write_infoframe,
+	},
+	.hdmi = {
+		.clear_infoframe = accept_infoframe_clear_infoframe,
+		.write_infoframe = accept_infoframe_write_infoframe,
+	},
 };
 
 static enum drm_mode_status
@@ -118,8 +128,14 @@ reject_100mhz_connector_tmds_char_rate_valid(const struct drm_connector *connect
 
 static const struct drm_connector_hdmi_funcs reject_100mhz_connector_hdmi_funcs = {
 	.tmds_char_rate_valid	= reject_100mhz_connector_tmds_char_rate_valid,
-	.clear_infoframe = accept_infoframe_clear_infoframe,
-	.write_infoframe = accept_infoframe_write_infoframe,
+	.avi = {
+		.clear_infoframe = accept_infoframe_clear_infoframe,
+		.write_infoframe = accept_infoframe_write_infoframe,
+	},
+	.hdmi = {
+		.clear_infoframe = accept_infoframe_clear_infoframe,
+		.write_infoframe = accept_infoframe_write_infoframe,
+	},
 };
 
 static int dummy_connector_get_modes(struct drm_connector *connector)
@@ -2427,19 +2443,21 @@ static void drm_test_check_infoframes(struct kunit *test)
 	drm_modeset_acquire_fini(&ctx);
 }
 
-static int reject_avi_infoframe_write_infoframe(struct drm_connector *connector,
-						enum hdmi_infoframe_type type,
-						const u8 *buffer, size_t len)
+static int reject_infoframe_write_infoframe(struct drm_connector *connector,
+					    const u8 *buffer, size_t len)
 {
-	if (type == HDMI_INFOFRAME_TYPE_AVI)
-		return -EOPNOTSUPP;
-
-	return 0;
+	return -EOPNOTSUPP;
 }
 
 static const struct drm_connector_hdmi_funcs reject_avi_infoframe_hdmi_funcs = {
-	.clear_infoframe = accept_infoframe_clear_infoframe,
-	.write_infoframe = reject_avi_infoframe_write_infoframe,
+	.avi = {
+		.clear_infoframe = accept_infoframe_clear_infoframe,
+		.write_infoframe = reject_infoframe_write_infoframe,
+	},
+	.hdmi = {
+		.clear_infoframe = accept_infoframe_clear_infoframe,
+		.write_infoframe = accept_infoframe_write_infoframe,
+	},
 };
 
 /*
@@ -2509,19 +2527,19 @@ static void drm_test_check_reject_avi_infoframe(struct kunit *test)
 	drm_modeset_acquire_fini(&ctx);
 }
 
-static int reject_hdr_infoframe_write_infoframe(struct drm_connector *connector,
-						enum hdmi_infoframe_type type,
-						const u8 *buffer, size_t len)
-{
-	if (type == HDMI_INFOFRAME_TYPE_DRM)
-		return -EOPNOTSUPP;
-
-	return 0;
-}
-
 static const struct drm_connector_hdmi_funcs reject_hdr_infoframe_hdmi_funcs = {
-	.clear_infoframe = accept_infoframe_clear_infoframe,
-	.write_infoframe = reject_hdr_infoframe_write_infoframe,
+	.avi = {
+		.clear_infoframe = accept_infoframe_clear_infoframe,
+		.write_infoframe = accept_infoframe_write_infoframe,
+	},
+	.hdmi = {
+		.clear_infoframe = accept_infoframe_clear_infoframe,
+		.write_infoframe = accept_infoframe_write_infoframe,
+	},
+	.hdr_drm = {
+		.clear_infoframe = accept_infoframe_clear_infoframe,
+		.write_infoframe = reject_infoframe_write_infoframe,
+	},
 };
 
 /*
@@ -2695,19 +2713,19 @@ static void drm_test_check_reject_hdr_infoframe_bpc_10(struct kunit *test)
 	drm_modeset_acquire_fini(&ctx);
 }
 
-static int reject_audio_infoframe_write_infoframe(struct drm_connector *connector,
-						  enum hdmi_infoframe_type type,
-						  const u8 *buffer, size_t len)
-{
-	if (type == HDMI_INFOFRAME_TYPE_AUDIO)
-		return -EOPNOTSUPP;
-
-	return 0;
-}
-
 static const struct drm_connector_hdmi_funcs reject_audio_infoframe_hdmi_funcs = {
-	.clear_infoframe = accept_infoframe_clear_infoframe,
-	.write_infoframe = reject_audio_infoframe_write_infoframe,
+	.avi = {
+		.clear_infoframe = accept_infoframe_clear_infoframe,
+		.write_infoframe = accept_infoframe_write_infoframe,
+	},
+	.hdmi = {
+		.clear_infoframe = accept_infoframe_clear_infoframe,
+		.write_infoframe = accept_infoframe_write_infoframe,
+	},
+	.audio = {
+		.clear_infoframe = accept_infoframe_clear_infoframe,
+		.write_infoframe = reject_infoframe_write_infoframe,
+	},
 };
 
 /*
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 4cfb7ebc0c81..9fe605a42df7 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -727,6 +727,66 @@ static int vc4_hdmi_write_infoframe(struct drm_connector *connector,
 	return ret;
 }
 
+static int vc4_hdmi_clear_avi_infoframe(struct drm_connector *connector)
+{
+	return vc4_hdmi_clear_infoframe(connector, HDMI_INFOFRAME_TYPE_AVI);
+}
+
+static int vc4_hdmi_clear_hdmi_infoframe(struct drm_connector *connector)
+{
+	return vc4_hdmi_clear_infoframe(connector, HDMI_INFOFRAME_TYPE_VENDOR);
+}
+
+static int vc4_hdmi_clear_audio_infoframe(struct drm_connector *connector)
+{
+	return vc4_hdmi_clear_infoframe(connector, HDMI_INFOFRAME_TYPE_AUDIO);
+}
+
+static int vc4_hdmi_clear_hdr_drm_infoframe(struct drm_connector *connector)
+{
+	return vc4_hdmi_clear_infoframe(connector, HDMI_INFOFRAME_TYPE_DRM);
+}
+
+static int vc4_hdmi_clear_spd_infoframe(struct drm_connector *connector)
+{
+	return vc4_hdmi_clear_infoframe(connector, HDMI_INFOFRAME_TYPE_SPD);
+}
+
+static int vc4_hdmi_write_avi_infoframe(struct drm_connector *connector,
+					const u8 *buffer, size_t len)
+{
+	return vc4_hdmi_write_infoframe(connector, HDMI_INFOFRAME_TYPE_AVI,
+					buffer, len);
+}
+
+static int vc4_hdmi_write_hdmi_infoframe(struct drm_connector *connector,
+					 const u8 *buffer, size_t len)
+{
+	return vc4_hdmi_write_infoframe(connector, HDMI_INFOFRAME_TYPE_VENDOR,
+					buffer, len);
+}
+
+static int vc4_hdmi_write_audio_infoframe(struct drm_connector *connector,
+					  const u8 *buffer, size_t len)
+{
+	return vc4_hdmi_write_infoframe(connector, HDMI_INFOFRAME_TYPE_AUDIO,
+					buffer, len);
+}
+
+static int vc4_hdmi_write_hdr_drm_infoframe(struct drm_connector *connector,
+					    const u8 *buffer, size_t len)
+{
+	return vc4_hdmi_write_infoframe(connector, HDMI_INFOFRAME_TYPE_DRM,
+					buffer, len);
+}
+
+static int vc4_hdmi_write_spd_infoframe(struct drm_connector *connector,
+					const u8 *buffer, size_t len)
+{
+	return vc4_hdmi_write_infoframe(connector, HDMI_INFOFRAME_TYPE_SPD,
+					buffer, len);
+}
+
 #define SCRAMBLING_POLLING_DELAY_MS	1000
 
 static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
@@ -1684,8 +1744,26 @@ vc4_hdmi_connector_clock_valid(const struct drm_connector *connector,
 
 static const struct drm_connector_hdmi_funcs vc4_hdmi_hdmi_connector_funcs = {
 	.tmds_char_rate_valid	= vc4_hdmi_connector_clock_valid,
-	.clear_infoframe	= vc4_hdmi_clear_infoframe,
-	.write_infoframe	= vc4_hdmi_write_infoframe,
+	.avi = {
+		.clear_infoframe = vc4_hdmi_clear_avi_infoframe,
+		.write_infoframe = vc4_hdmi_write_avi_infoframe,
+	},
+	.hdmi = {
+		.clear_infoframe = vc4_hdmi_clear_hdmi_infoframe,
+		.write_infoframe = vc4_hdmi_write_hdmi_infoframe,
+	},
+	.audio = {
+		.clear_infoframe = vc4_hdmi_clear_audio_infoframe,
+		.write_infoframe = vc4_hdmi_write_audio_infoframe,
+	},
+	.hdr_drm = {
+		.clear_infoframe = vc4_hdmi_clear_hdr_drm_infoframe,
+		.write_infoframe = vc4_hdmi_write_hdr_drm_infoframe,
+	},
+	.spd = {
+		.clear_infoframe = vc4_hdmi_clear_spd_infoframe,
+		.write_infoframe = vc4_hdmi_write_spd_infoframe,
+	},
 };
 
 #define WIFI_2_4GHz_CH1_MIN_FREQ	2400000000ULL
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 4543833acdec..7eaec37ae1c7 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1222,44 +1222,24 @@ struct drm_connector_cec_funcs {
 };
 
 /**
- * struct drm_connector_hdmi_funcs - drm_hdmi_connector control functions
+ * struct drm_connector_infoframe_funcs - InfoFrame-related functions
  */
-struct drm_connector_hdmi_funcs {
-	/**
-	 * @tmds_char_rate_valid:
-	 *
-	 * This callback is invoked at atomic_check time to figure out
-	 * whether a particular TMDS character rate is supported by the
-	 * driver.
-	 *
-	 * The @tmds_char_rate_valid callback is optional.
-	 *
-	 * Returns:
-	 *
-	 * Either &drm_mode_status.MODE_OK or one of the failure reasons
-	 * in &enum drm_mode_status.
-	 */
-	enum drm_mode_status
-	(*tmds_char_rate_valid)(const struct drm_connector *connector,
-				const struct drm_display_mode *mode,
-				unsigned long long tmds_rate);
-
+struct drm_connector_infoframe_funcs {
 	/**
 	 * @clear_infoframe:
 	 *
 	 * This callback is invoked through
 	 * @drm_atomic_helper_connector_hdmi_update_infoframes during a
 	 * commit to clear the infoframes into the hardware. It will be
-	 * called multiple times, once for every disabled infoframe
-	 * type.
+	 * called once for each frame type to be disabled.
 	 *
-	 * The @clear_infoframe callback is mandatory.
+	 * The @clear_infoframe callback is mandatory for AVI and HDMI-VS
+	 * InfoFrame types.
 	 *
 	 * Returns:
 	 * 0 on success, a negative error code otherwise
 	 */
-	int (*clear_infoframe)(struct drm_connector *connector,
-			       enum hdmi_infoframe_type type);
+	int (*clear_infoframe)(struct drm_connector *connector);
 
 	/**
 	 * @write_infoframe:
@@ -1267,18 +1247,42 @@ struct drm_connector_hdmi_funcs {
 	 * This callback is invoked through
 	 * @drm_atomic_helper_connector_hdmi_update_infoframes during a
 	 * commit to program the infoframes into the hardware. It will
-	 * be called multiple times, once for every updated infoframe
-	 * type.
+	 * be called for every updated infoframe type.
 	 *
-	 * The @write_infoframe callback is mandatory.
+	 * The @write_infoframe callback is mandatory for AVI and HDMI-VS
+	 * InfoFrame types.
 	 *
 	 * Returns:
 	 * 0 on success, a negative error code otherwise
 	 */
 	int (*write_infoframe)(struct drm_connector *connector,
-			       enum hdmi_infoframe_type type,
 			       const u8 *buffer, size_t len);
 
+};
+
+/**
+ * struct drm_connector_hdmi_funcs - drm_hdmi_connector control functions
+ */
+struct drm_connector_hdmi_funcs {
+	/**
+	 * @tmds_char_rate_valid:
+	 *
+	 * This callback is invoked at atomic_check time to figure out
+	 * whether a particular TMDS character rate is supported by the
+	 * driver.
+	 *
+	 * The @tmds_char_rate_valid callback is optional.
+	 *
+	 * Returns:
+	 *
+	 * Either &drm_mode_status.MODE_OK or one of the failure reasons
+	 * in &enum drm_mode_status.
+	 */
+	enum drm_mode_status
+	(*tmds_char_rate_valid)(const struct drm_connector *connector,
+				const struct drm_display_mode *mode,
+				unsigned long long tmds_rate);
+
 	/**
 	 * @read_edid:
 	 *
@@ -1293,6 +1297,47 @@ struct drm_connector_hdmi_funcs {
 	 * Valid EDID on success, NULL in case of failure.
 	 */
 	const struct drm_edid *(*read_edid)(struct drm_connector *connector);
+
+	/**
+	 * @avi:
+	 *
+	 * Set of callbacks for handling the AVI InfoFrame. These callbacks are
+	 * mandatory.
+	 */
+	struct drm_connector_infoframe_funcs avi;
+
+	/**
+	 * @hdmi:
+	 *
+	 * Set of callbacks for handling the HDMI Vendor-Specific InfoFrame.
+	 * These callbacks are mandatory.
+	 */
+	struct drm_connector_infoframe_funcs hdmi;
+
+	/**
+	 * @audio:
+	 *
+	 * Set of callbacks for handling the Audio InfoFrame. These callbacks
+	 * are optional, but they are required for drivers which use
+	 * drm_atomic_helper_connector_hdmi_update_audio_infoframe().
+	 */
+	struct drm_connector_infoframe_funcs audio;
+
+	/**
+	 * @hdr_drm:
+	 *
+	 * Set of callbacks for handling the HDR DRM InfoFrame. These callbacks
+	 * are mandatory if HDR output is to be supported.
+	 */
+	struct drm_connector_infoframe_funcs hdr_drm;
+
+	/**
+	 * @spd:
+	 *
+	 * Set of callbacks for handling the SPD InfoFrame. These callbacks are
+	 * optional.
+	 */
+	struct drm_connector_infoframe_funcs spd;
 };
 
 /**

-- 
2.47.3



From dmitry.baryshkov at oss.qualcomm.com  Tue Dec 23 17:02:56 2025
From: dmitry.baryshkov at oss.qualcomm.com (Dmitry Baryshkov)
Date: Wed, 24 Dec 2025 03:02:56 +0200
Subject: [PATCH v3 07/10] drm/display: hdmi_state_helper: reject Audio IF
 updates if it's not supported
In-Reply-To: <20251224-limit-infoframes-2-v3-0-7fd3cacfefed@oss.qualcomm.com>
References: <20251224-limit-infoframes-2-v3-0-7fd3cacfefed@oss.qualcomm.com>
Message-ID: <20251224-limit-infoframes-2-v3-7-7fd3cacfefed@oss.qualcomm.com>

Updating the InfoFrame if it can not be sent over the wire makes no
sense. Change drm_atomic_helper_connector_hdmi_update_audio_infoframe()
and drm_atomic_helper_connector_hdmi_clear_audio_infoframe() to return
an error if Audio InfoFrame callbacks are not implemented.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
---
 drivers/gpu/drm/display/drm_hdmi_state_helper.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index 5a3817271d91..e8556bf9e1da 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -1061,7 +1061,7 @@ drm_atomic_helper_connector_hdmi_update_audio_infoframe(struct drm_connector *co
 	if (!info->is_hdmi)
 		return 0;
 
-	if (!funcs) {
+	if (!funcs || !funcs->audio.write_infoframe) {
 		drm_dbg_kms(connector->dev, "Function not implemented, bailing.\n");
 		return -EINVAL;
 	}
@@ -1102,7 +1102,7 @@ drm_atomic_helper_connector_hdmi_clear_audio_infoframe(struct drm_connector *con
 	if (!info->is_hdmi)
 		return 0;
 
-	if (!funcs) {
+	if (!funcs || !funcs->audio.write_infoframe) {
 		drm_dbg_kms(connector->dev, "Function not implemented, bailing.\n");
 		return -EINVAL;
 	}

-- 
2.47.3



From dmitry.baryshkov at oss.qualcomm.com  Tue Dec 23 17:02:58 2025
From: dmitry.baryshkov at oss.qualcomm.com (Dmitry Baryshkov)
Date: Wed, 24 Dec 2025 03:02:58 +0200
Subject: [PATCH v3 09/10] drm/display: bridge_connector: dynamically
 generate HDMI callbacks
In-Reply-To: <20251224-limit-infoframes-2-v3-0-7fd3cacfefed@oss.qualcomm.com>
References: <20251224-limit-infoframes-2-v3-0-7fd3cacfefed@oss.qualcomm.com>
Message-ID: <20251224-limit-infoframes-2-v3-9-7fd3cacfefed@oss.qualcomm.com>

The rest of the DRM framework uses presence of the callbacks to check if
the particular infoframe is supported. Register HDMI callbacks
dynamically, basing on the corresponding drm_bridge ops.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
---
 drivers/gpu/drm/display/drm_bridge_connector.c | 94 ++++++++++++--------------
 1 file changed, 45 insertions(+), 49 deletions(-)

diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index c8858d48199c..2a8f586c6d13 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -123,6 +123,14 @@ struct drm_bridge_connector {
 	 * DRM_BRIDGE_OP_HDMI_CEC_NOTIFIER).
 	 */
 	struct drm_bridge *bridge_hdmi_cec;
+
+	/**
+	 * @hdmi_funcs:
+	 *
+	 * The particular &drm_connector_hdmi_funcs implementation for this
+	 * bridge connector.
+	 */
+	struct drm_connector_hdmi_funcs hdmi_funcs;
 };
 
 #define to_drm_bridge_connector(x) \
@@ -465,12 +473,7 @@ static int drm_bridge_connector_clear_audio_infoframe(struct drm_connector *conn
 	if (!bridge)
 		return -EINVAL;
 
-	if (bridge->ops & DRM_BRIDGE_OP_HDMI_AUDIO)
-		return bridge->funcs->hdmi_clear_audio_infoframe(bridge);
-
-	drm_dbg_driver(connector->dev, "Unsupported HDMI Audio InfoFrame\n");
-
-	return 0;
+	return bridge->funcs->hdmi_clear_audio_infoframe(bridge);
 }
 
 static int drm_bridge_connector_write_audio_infoframe(struct drm_connector *connector,
@@ -484,12 +487,7 @@ static int drm_bridge_connector_write_audio_infoframe(struct drm_connector *conn
 	if (!bridge)
 		return -EINVAL;
 
-	if (bridge->ops & DRM_BRIDGE_OP_HDMI_AUDIO)
-		return bridge->funcs->hdmi_write_audio_infoframe(bridge, buffer, len);
-
-	drm_dbg_driver(connector->dev, "Unsupported HDMI Audio InfoFrame\n");
-
-	return 0;
+	return bridge->funcs->hdmi_write_audio_infoframe(bridge, buffer, len);
 }
 
 static int drm_bridge_connector_clear_hdr_drm_infoframe(struct drm_connector *connector)
@@ -502,12 +500,7 @@ static int drm_bridge_connector_clear_hdr_drm_infoframe(struct drm_connector *co
 	if (!bridge)
 		return -EINVAL;
 
-	if (bridge->ops & DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME)
-		return bridge->funcs->hdmi_clear_hdr_drm_infoframe(bridge);
-
-	drm_dbg_driver(connector->dev, "Unsupported HDMI HDR DRM InfoFrame\n");
-
-	return 0;
+	return bridge->funcs->hdmi_clear_hdr_drm_infoframe(bridge);
 }
 
 static int drm_bridge_connector_write_hdr_drm_infoframe(struct drm_connector *connector,
@@ -521,12 +514,7 @@ static int drm_bridge_connector_write_hdr_drm_infoframe(struct drm_connector *co
 	if (!bridge)
 		return -EINVAL;
 
-	if (bridge->ops & DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME)
-		return bridge->funcs->hdmi_write_hdr_drm_infoframe(bridge, buffer, len);
-
-	drm_dbg_driver(connector->dev, "Unsupported HDMI HDR DRM InfoFrame\n");
-
-	return 0;
+	return bridge->funcs->hdmi_write_hdr_drm_infoframe(bridge, buffer, len);
 }
 
 static int drm_bridge_connector_clear_spd_infoframe(struct drm_connector *connector)
@@ -539,12 +527,7 @@ static int drm_bridge_connector_clear_spd_infoframe(struct drm_connector *connec
 	if (!bridge)
 		return -EINVAL;
 
-	if (bridge->ops & DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME)
-		return bridge->funcs->hdmi_clear_spd_infoframe(bridge);
-
-	drm_dbg_driver(connector->dev, "Unsupported HDMI SPD InfoFrame\n");
-
-	return 0;
+	return bridge->funcs->hdmi_clear_spd_infoframe(bridge);
 }
 
 static int drm_bridge_connector_write_spd_infoframe(struct drm_connector *connector,
@@ -558,12 +541,7 @@ static int drm_bridge_connector_write_spd_infoframe(struct drm_connector *connec
 	if (!bridge)
 		return -EINVAL;
 
-	if (bridge->ops & DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME)
-		return bridge->funcs->hdmi_write_spd_infoframe(bridge, buffer, len);
-
-	drm_dbg_driver(connector->dev, "Unsupported HDMI SPD InfoFrame\n");
-
-	return 0;
+	return bridge->funcs->hdmi_write_spd_infoframe(bridge, buffer, len);
 }
 
 static const struct drm_edid *
@@ -591,18 +569,22 @@ static const struct drm_connector_hdmi_funcs drm_bridge_connector_hdmi_funcs = {
 		.clear_infoframe = drm_bridge_connector_clear_hdmi_infoframe,
 		.write_infoframe = drm_bridge_connector_write_hdmi_infoframe,
 	},
-	.audio = {
-		.clear_infoframe = drm_bridge_connector_clear_audio_infoframe,
-		.write_infoframe = drm_bridge_connector_write_audio_infoframe,
-	},
-	.hdr_drm = {
-		.clear_infoframe = drm_bridge_connector_clear_hdr_drm_infoframe,
-		.write_infoframe = drm_bridge_connector_write_hdr_drm_infoframe,
-	},
-	.spd = {
-		.clear_infoframe = drm_bridge_connector_clear_spd_infoframe,
-		.write_infoframe = drm_bridge_connector_write_spd_infoframe,
-	},
+	/* audio, hdr_drm and spd are set dynamically during init */
+};
+
+static const struct drm_connector_infoframe_funcs drm_bridge_connector_hdmi_audio_infoframe = {
+	.clear_infoframe = drm_bridge_connector_clear_audio_infoframe,
+	.write_infoframe = drm_bridge_connector_write_audio_infoframe,
+};
+
+static const struct drm_connector_infoframe_funcs drm_bridge_connector_hdmi_hdr_drm_infoframe = {
+	.clear_infoframe = drm_bridge_connector_clear_hdr_drm_infoframe,
+	.write_infoframe = drm_bridge_connector_write_hdr_drm_infoframe,
+};
+
+static const struct drm_connector_infoframe_funcs drm_bridge_connector_hdmi_spd_infoframe = {
+	.clear_infoframe = drm_bridge_connector_clear_spd_infoframe,
+	.write_infoframe = drm_bridge_connector_write_spd_infoframe,
 };
 
 static int drm_bridge_connector_audio_startup(struct drm_connector *connector)
@@ -971,11 +953,25 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
 		if (!connector->ycbcr_420_allowed)
 			supported_formats &= ~BIT(HDMI_COLORSPACE_YUV420);
 
+		bridge_connector->hdmi_funcs = drm_bridge_connector_hdmi_funcs;
+
+		if (bridge_connector->bridge_hdmi->ops & DRM_BRIDGE_OP_HDMI_AUDIO)
+			bridge_connector->hdmi_funcs.audio =
+				drm_bridge_connector_hdmi_audio_infoframe;
+
+		if (bridge_connector->bridge_hdmi->ops & DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME)
+			bridge_connector->hdmi_funcs.hdr_drm =
+				drm_bridge_connector_hdmi_hdr_drm_infoframe;
+
+		if (bridge_connector->bridge_hdmi->ops & DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME)
+			bridge_connector->hdmi_funcs.spd =
+				drm_bridge_connector_hdmi_spd_infoframe;
+
 		ret = drmm_connector_hdmi_init(drm, connector,
 					       bridge_connector->bridge_hdmi->vendor,
 					       bridge_connector->bridge_hdmi->product,
 					       &drm_bridge_connector_funcs,
-					       &drm_bridge_connector_hdmi_funcs,
+					       &bridge_connector->hdmi_funcs,
 					       connector_type, ddc,
 					       supported_formats,
 					       max_bpc);

-- 
2.47.3



From dmitry.baryshkov at oss.qualcomm.com  Tue Dec 23 17:02:57 2025
From: dmitry.baryshkov at oss.qualcomm.com (Dmitry Baryshkov)
Date: Wed, 24 Dec 2025 03:02:57 +0200
Subject: [PATCH v3 08/10] drm/display: hdmi_state_helper: don't generate
 unsupported InfoFrames
In-Reply-To: <20251224-limit-infoframes-2-v3-0-7fd3cacfefed@oss.qualcomm.com>
References: <20251224-limit-infoframes-2-v3-0-7fd3cacfefed@oss.qualcomm.com>
Message-ID: <20251224-limit-infoframes-2-v3-8-7fd3cacfefed@oss.qualcomm.com>

There is little point in generating InfoFrames which are not supported
by the driver. Skip generating the unsupported InfoFrames, making sure
that the kernel never tries to write the unsupported frame. As there are
no remaining usecases, change write_infoframe / clear_infoframe helpers
return an error if the corresponding callback is NULL.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
---
 drivers/gpu/drm/display/drm_hdmi_state_helper.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index e8556bf9e1da..a1d16762ac7a 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -718,6 +718,9 @@ static int hdmi_generate_spd_infoframe(const struct drm_connector *connector,
 
 	infoframe->set = false;
 
+	if (!connector->hdmi.funcs->spd.write_infoframe)
+		return 0;
+
 	ret = hdmi_spd_infoframe_init(frame,
 				      connector->hdmi.vendor,
 				      connector->hdmi.product);
@@ -742,6 +745,9 @@ static int hdmi_generate_hdr_infoframe(const struct drm_connector *connector,
 
 	infoframe->set = false;
 
+	if (!connector->hdmi.funcs->hdr_drm.write_infoframe)
+		return 0;
+
 	if (connector->max_bpc < 10)
 		return 0;
 
@@ -902,7 +908,7 @@ static int clear_infoframe(struct drm_connector *connector,
 
 	if (!funcs->clear_infoframe) {
 		drm_dbg_kms(dev, "Function not implemented, bailing.\n");
-		return 0;
+		return -EOPNOTSUPP;
 	}
 
 	ret = funcs->clear_infoframe(connector);
@@ -928,7 +934,7 @@ static int write_infoframe(struct drm_connector *connector,
 
 	if (!funcs->write_infoframe) {
 		drm_dbg_kms(dev, "Function not implemented, bailing.\n");
-		return 0; /* XXX: temporal until we stop generating unsupported frames */
+		return -EOPNOTSUPP;
 	}
 
 	len = hdmi_infoframe_pack(&new_frame->data, buffer, sizeof(buffer));

-- 
2.47.3



From dmitry.baryshkov at oss.qualcomm.com  Tue Dec 23 17:02:59 2025
From: dmitry.baryshkov at oss.qualcomm.com (Dmitry Baryshkov)
Date: Wed, 24 Dec 2025 03:02:59 +0200
Subject: [PATCH v3 10/10] drm/debug: don't register files for unsupported
 HDMI InfoFrames
In-Reply-To: <20251224-limit-infoframes-2-v3-0-7fd3cacfefed@oss.qualcomm.com>
References: <20251224-limit-infoframes-2-v3-0-7fd3cacfefed@oss.qualcomm.com>
Message-ID: <20251224-limit-infoframes-2-v3-10-7fd3cacfefed@oss.qualcomm.com>

Having debugfs files for the InfoFrames that are not supported by the
driver is confusing, stop registering those in the debugfs.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
---
 drivers/gpu/drm/drm_debugfs.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c
index 365cf337529f..ae1c6126c2c5 100644
--- a/drivers/gpu/drm/drm_debugfs.c
+++ b/drivers/gpu/drm/drm_debugfs.c
@@ -672,6 +672,10 @@ static int create_hdmi_audio_infoframe_file(struct drm_connector *connector,
 {
 	struct dentry *file;
 
+	if (!connector->hdmi.funcs ||
+	    !connector->hdmi.funcs->audio.write_infoframe)
+		return 0;
+
 	file = debugfs_create_file("audio", 0400, parent, connector, &audio_infoframe_fops);
 	if (IS_ERR(file))
 		return PTR_ERR(file);
@@ -726,6 +730,9 @@ static int create_hdmi_## _f ## _infoframe_file(struct drm_connector *connector,
 { \
 	struct dentry *file; \
 	\
+	if (!connector->hdmi.funcs || \
+	    !connector->hdmi.funcs->_f.write_infoframe) \
+		return 0; \
 	file = debugfs_create_file(#_f, 0400, parent, connector, &_f ## _infoframe_fops); \
 	if (IS_ERR(file)) \
 		return PTR_ERR(file); \

-- 
2.47.3



From 21cnbao at gmail.com  Tue Dec 23 17:29:13 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Wed, 24 Dec 2025 14:29:13 +1300
Subject: [PATCH 5/6] dma-mapping: Allow batched DMA sync operations if
 supported by the arch
In-Reply-To: <20251223141424.GB11869@unreal>
References: <20251221115523.GI13030@unreal> <20251221192458.1320-1-21cnbao@gmail.com>
 <20251222084921.GA13529@unreal> <CAGsJ_4yuvHNqHDi8eN-8UoY2McoXUeCMmbjFAr=jSdv8GpGKeg@mail.gmail.com>
 <20251223141424.GB11869@unreal>
Message-ID: <CAGsJ_4x9YOT2kG0iWz_5NzRVt2iDN9YeUTknZ2MKg7SwmOGOqg@mail.gmail.com>

On Wed, Dec 24, 2025 at 3:14?AM Leon Romanovsky <leon at kernel.org> wrote:
>
> On Tue, Dec 23, 2025 at 01:02:55PM +1300, Barry Song wrote:
> > On Mon, Dec 22, 2025 at 9:49?PM Leon Romanovsky <leon at kernel.org> wrote:
> > >
> > > On Mon, Dec 22, 2025 at 03:24:58AM +0800, Barry Song wrote:
> > > > On Sun, Dec 21, 2025 at 7:55?PM Leon Romanovsky <leon at kernel.org> wrote:
> > > > [...]
> > > > > > +
> > > > >
> > > > > I'm wondering why you don't implement this batch?sync support inside the
> > > > > arch_sync_dma_*() functions. Doing so would minimize changes to the generic
> > > > > kernel/dma/* code and reduce the amount of #ifdef?based spaghetti.
> > > > >
> > > >
> > > > There are two cases: mapping an sg list and mapping a single
> > > > buffer. The former can be batched with
> > > > arch_sync_dma_*_batch_add() and flushed via
> > > > arch_sync_dma_batch_flush(), while the latter requires all work to
> > > > be done inside arch_sync_dma_*(). Therefore,
> > > > arch_sync_dma_*() cannot always batch and flush.
> > >
> > > Probably in all cases you can call the _batch_ variant, followed by _flush_,
> > > even when handling a single page. This keeps the code consistent across all
> > > paths. On platforms that do not support _batch_, the _flush_ operation will be
> > > a NOP anyway.
> >
> > We have a lot of code outside kernel/dma that also calls
> > arch_sync_dma_for_* such as arch/arm, arch/mips, drivers/xen,
> > I guess we don?t want to modify so many things?
>
> Aren't they using internal, arch specific, arch_sync_dma_for_* implementations?

for arch/arm, arch/mips, they are arch-specific implementations.
xen is an exception:

static void xen_swiotlb_unmap_phys(struct device *hwdev, dma_addr_t dev_addr,
                size_t size, enum dma_data_direction dir, unsigned long attrs)
{
        phys_addr_t paddr = xen_dma_to_phys(hwdev, dev_addr);
        struct io_tlb_pool *pool;

        BUG_ON(dir == DMA_NONE);

        if (!dev_is_dma_coherent(hwdev) && !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) {
                if (pfn_valid(PFN_DOWN(dma_to_phys(hwdev, dev_addr))))
                        arch_sync_dma_for_cpu(paddr, size, dir);
                else
                        xen_dma_sync_for_cpu(hwdev, dev_addr, size, dir);
        }

        /* NOTE: We use dev_addr here, not paddr! */
        pool = xen_swiotlb_find_pool(hwdev, dev_addr);
        if (pool)
                __swiotlb_tbl_unmap_single(hwdev, paddr, size, dir,
                                           attrs, pool);
}

>
> >
> > for kernel/dma, we have two "single" callers only:
> > kernel/dma/direct.h, kernel/dma/swiotlb.c.  and they looks quite
> > straightforward:
> >
> > static inline void dma_direct_sync_single_for_device(struct device *dev,
> >                 dma_addr_t addr, size_t size, enum dma_data_direction dir)
> > {
> >         phys_addr_t paddr = dma_to_phys(dev, addr);
> >
> >         swiotlb_sync_single_for_device(dev, paddr, size, dir);
> >
> >         if (!dev_is_dma_coherent(dev))
> >                 arch_sync_dma_for_device(paddr, size, dir);
> > }
> >
> > I guess moving to arch_sync_dma_for_device_batch + flush
> > doesn?t really look much better, does it?
> >
> > >
> > > I would also rename arch_sync_dma_batch_flush() to arch_sync_dma_flush().
> >
> > Sure.
> >
> > >
> > > You can also minimize changes in dma_direct_map_phys() too, by extending
> > > it's signature to provide if flush is needed or not.
> >
> > Yes. I have
> >
> > static inline dma_addr_t __dma_direct_map_phys(struct device *dev,
> >                 phys_addr_t phys, size_t size, enum dma_data_direction dir,
> >                 unsigned long attrs, bool flush)
>
> My suggestion is to use it directly, without wrappers.
>
> >
> > and two wrappers:
> > static inline dma_addr_t dma_direct_map_phys(struct device *dev,
> >                 phys_addr_t phys, size_t size, enum dma_data_direction dir,
> >                 unsigned long attrs)
> > {
> >         return __dma_direct_map_phys(dev, phys, size, dir, attrs, true);
> > }
> >
> > static inline dma_addr_t dma_direct_map_phys_batch_add(struct device *dev,
> >                 phys_addr_t phys, size_t size, enum dma_data_direction dir,
> >                 unsigned long attrs)
> > {
> >         return __dma_direct_map_phys(dev, phys, size, dir, attrs, false);
> > }
> >
> > If you prefer exposing "flush" directly in dma_direct_map_phys()
> > and updating its callers with flush=true, I think that?s fine.
>
> Yes
>

OK. Could you take a look at [1] and see if any further
improvements are needed before I send v2?

[1] https://lore.kernel.org/lkml/20251223023648.31614-1-21cnbao at gmail.com/

Thanks
Barry


From Macpaul.Lin at mediatek.com  Tue Dec 23 18:17:48 2025
From: Macpaul.Lin at mediatek.com (=?utf-8?B?TWFjcGF1bCBMaW4gKOael+aZuuaWjCk=?=)
Date: Wed, 24 Dec 2025 02:17:48 +0000
Subject: [PATCH 03/11] drm/mediatek: ovl: Add supports_plane_colorops flag
In-Reply-To: <20251223-mtk-ovl-pre-blend-colorops-v1-3-0cb99bd0ab33@collabora.com>
References: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
	 <20251223-mtk-ovl-pre-blend-colorops-v1-3-0cb99bd0ab33@collabora.com>
Message-ID: <4d639355fb6071d568e079778eee50b89ffbb0da.camel@mediatek.com>

On Tue, 2025-12-23 at 16:44 -0300, N?colas F. R. A. Prado wrote:
> Add a supports_plane_colorops flag to the driver data to allow SoCs
> that
> support per-plane color operations to enable support for it in the
> driver.
> 
> Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
> ---
> ?drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 1 +
> ?1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> index 8e20b45411fc..46238c21b0ac 100644
> --- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> +++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> @@ -150,6 +150,7 @@ struct mtk_disp_ovl_data {
> ??????? const u32 *formats;
> ??????? size_t num_formats;
> ??????? bool supports_clrfmt_ext;
> +?????? bool supports_plane_colorops;
> ?};
> 
> ?/*
> 
> --
> 2.51.0
> 
> 

Reviewed-by: Macpaul Lin <macpaul.lin at mediatek.com>

BR,
Macpaul Lin

From Macpaul.Lin at mediatek.com  Tue Dec 23 18:19:17 2025
From: Macpaul.Lin at mediatek.com (=?utf-8?B?TWFjcGF1bCBMaW4gKOael+aZuuaWjCk=?=)
Date: Wed, 24 Dec 2025 02:19:17 +0000
Subject: [PATCH 04/11] drm/mediatek: ovl: Enable per-plane color
 operations on MT8195
In-Reply-To: <20251223-mtk-ovl-pre-blend-colorops-v1-4-0cb99bd0ab33@collabora.com>
References: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
	 <20251223-mtk-ovl-pre-blend-colorops-v1-4-0cb99bd0ab33@collabora.com>
Message-ID: <515f2adf162b33785790acdebe5b345571ade668.camel@mediatek.com>

On Tue, 2025-12-23 at 16:44 -0300, N?colas F. R. A. Prado wrote:
> MT8195's OVL hardware supports per-plane color operations. Enable
> support for it in the driver.
> 
> Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
> ---
> ?drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 1 +
> ?1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> index 46238c21b0ac..cfc6a3154f73 100644
> --- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> +++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> @@ -738,6 +738,7 @@ static const struct mtk_disp_ovl_data
> mt8195_ovl_driver_data = {
> ??????? .fmt_rgb565_is_0 = true,
> ??????? .smi_id_en = true,
> ??????? .supports_afbc = true,
> +?????? .supports_plane_colorops = true,
> ??????? .blend_modes = BIT(DRM_MODE_BLEND_PREMULTI) |
> ?????????????????????? BIT(DRM_MODE_BLEND_COVERAGE) |
> ?????????????????????? BIT(DRM_MODE_BLEND_PIXEL_NONE),
> 
> --
> 2.51.0
> 
> 

Reviewed-by: Macpaul Lin <macpaul.lin at mediatek.com>

Best regards,
Macpaul Lin

From devnull+shimin.guo.skydio.com at kernel.org  Tue Dec 23 18:19:20 2025
From: devnull+shimin.guo.skydio.com at kernel.org (Shimin Guo via B4 Relay)
Date: Tue, 23 Dec 2025 18:19:20 -0800
Subject: [PATCH] perf unwind-libdw: fix a cross-arch unwinding bug
Message-ID: <20251223-cross-arch-unwind-v1-1-4d71ee7db512@skydio.com>

From: Shimin Guo <shimin.guo at skydio.com>

The set_initial_registers field of Dwfl_Thread_Callbacks needs to be set
according to the arch of the stack samples being analyzed, not the arch
that perf itself is built for. Currently perf fails to unwind stack samples
collected from archs different from that of the host perf is running on.
This patch moves the arch-specific implementations of set_initial_registers
from tools/perf/arch to tools/perf/utli/unwind-libdw-arch, similar to the
way the perf-regs-arch folder contains arch-specific functions related to
registers, and chooses the implementation based on the arch of the data
being processed.

Signed-off-by: Shimin Guo <shimin.guo at skydio.com>
---
checkpatch flagged three issues:
> tools/perf/util/unwind-libdw-arch/Build:232: WARNING: added, moved
or deleted file(s), does MAINTAINERS need updating?

Not sure what to do about that.

> checkpatch.pl: tools/perf/util/unwind-libdw.c:228: WARNING:
Non-declarative macros with multiple statements should be enclosed in
a do - while loop
> checkpatch.pl: tools/perf/util/unwind-libdw.c:228: WARNING: macros
should not use a trailing semicolon

Are these two false positives? I'm defining static global variables
with the macro.
---
 tools/perf/arch/arm/util/Build                     |  1 -
 tools/perf/arch/arm64/util/Build                   |  1 -
 tools/perf/arch/csky/util/Build                    |  2 -
 tools/perf/arch/powerpc/util/Build                 |  1 -
 tools/perf/arch/riscv/util/Build                   |  1 -
 tools/perf/arch/s390/util/Build                    |  2 -
 tools/perf/arch/x86/util/Build                     |  1 -
 tools/perf/util/Build                              |  1 +
 tools/perf/util/unwind-libdw-arch/Build            |  8 ++++
 .../unwind-libdw-arch/unwind-libdw-arm.c}          |  4 +-
 .../unwind-libdw-arch/unwind-libdw-arm64.c}        |  4 +-
 .../unwind-libdw-arch/unwind-libdw-csky.c}         |  6 +--
 .../unwind-libdw-arch/unwind-libdw-loongarch.c}    |  4 +-
 .../unwind-libdw-arch/unwind-libdw-powerpc.c}      |  4 +-
 .../unwind-libdw-arch/unwind-libdw-riscv.c}        |  4 +-
 .../unwind-libdw-arch/unwind-libdw-s390.c}         |  6 +--
 .../unwind-libdw-arch/unwind-libdw-x86.c}          |  2 +-
 tools/perf/util/unwind-libdw.c                     | 49 +++++++++++++++++++---
 tools/perf/util/unwind-libdw.h                     | 10 ++++-
 19 files changed, 79 insertions(+), 32 deletions(-)

diff --git a/tools/perf/arch/arm/util/Build b/tools/perf/arch/arm/util/Build
index fd695e1fdaee2ccc300a206131b8b38a763b00ce..3291f893b943df0722dff583523fff4ae79919bc 100644
--- a/tools/perf/arch/arm/util/Build
+++ b/tools/perf/arch/arm/util/Build
@@ -1,6 +1,5 @@
 perf-util-y += perf_regs.o
 
 perf-util-$(CONFIG_LOCAL_LIBUNWIND)    += unwind-libunwind.o
-perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
 
 perf-util-y += pmu.o auxtrace.o cs-etm.o
diff --git a/tools/perf/arch/arm64/util/Build b/tools/perf/arch/arm64/util/Build
index d63881081d2eb1e9a83eabf82104d75308f7fc79..0177af19cc00038d6a6005592ddc530bf7eb1557 100644
--- a/tools/perf/arch/arm64/util/Build
+++ b/tools/perf/arch/arm64/util/Build
@@ -1,4 +1,3 @@
-perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
 perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
 perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
 perf-util-y += ../../arm/util/auxtrace.o
diff --git a/tools/perf/arch/csky/util/Build b/tools/perf/arch/csky/util/Build
index 5e6ea82c42021d3d5651ca4c4a3a6e5138574e4e..6b2d0e021b11464e46d6b53974260d32ea969732 100644
--- a/tools/perf/arch/csky/util/Build
+++ b/tools/perf/arch/csky/util/Build
@@ -1,3 +1 @@
 perf-util-y += perf_regs.o
-
-perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build
index 3d0d5427aef7f26a8c05c883cc7ad763f08cbb30..5fd28ec713a4db74ecd1d26866a65ddb20e94bd3 100644
--- a/tools/perf/arch/powerpc/util/Build
+++ b/tools/perf/arch/powerpc/util/Build
@@ -9,5 +9,4 @@ perf-util-y += evsel.o
 perf-util-$(CONFIG_LIBDW) += skip-callchain-idx.o
 
 perf-util-$(CONFIG_LIBUNWIND) += unwind-libunwind.o
-perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
 perf-util-y += auxtrace.o
diff --git a/tools/perf/arch/riscv/util/Build b/tools/perf/arch/riscv/util/Build
index 58a672246024dd0f72e767d11e9958bd9913ec3c..628b9ebd418bde8cdf1ab1332bf79f7c9d50760e 100644
--- a/tools/perf/arch/riscv/util/Build
+++ b/tools/perf/arch/riscv/util/Build
@@ -2,4 +2,3 @@ perf-util-y += perf_regs.o
 perf-util-y += header.o
 
 perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
-perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
diff --git a/tools/perf/arch/s390/util/Build b/tools/perf/arch/s390/util/Build
index c64eb18dbdae93adafabf8542e4c9a763ecfe057..5391d26fedd46b7d30a1bef0bff2ec2d58ec30ed 100644
--- a/tools/perf/arch/s390/util/Build
+++ b/tools/perf/arch/s390/util/Build
@@ -2,8 +2,6 @@ perf-util-y += header.o
 perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
 perf-util-y += perf_regs.o
 
-perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
-
 perf-util-y += machine.o
 perf-util-y += pmu.o
 
diff --git a/tools/perf/arch/x86/util/Build b/tools/perf/arch/x86/util/Build
index c0dc5965f3624a6f02525a04d287dff755356d20..fad256252bb95a8f8350b6bb1a54e8074eaebbec 100644
--- a/tools/perf/arch/x86/util/Build
+++ b/tools/perf/arch/x86/util/Build
@@ -12,7 +12,6 @@ perf-util-y += evsel.o
 perf-util-y += iostat.o
 
 perf-util-$(CONFIG_LOCAL_LIBUNWIND)    += unwind-libunwind.o
-perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
 
 perf-util-y += auxtrace.o
 perf-util-y += archinsn.o
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 1c2a43e1dc68e7f751ec6082352b10de9ffeea62..15f8a4f4b24a46b6300e824f672dd9c0d5b7865f 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -226,6 +226,7 @@ perf-util-$(CONFIG_LIBDW) += debuginfo.o
 perf-util-$(CONFIG_LIBDW) += annotate-data.o
 
 perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
+perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-arch/
 perf-util-$(CONFIG_LOCAL_LIBUNWIND)    += unwind-libunwind-local.o
 perf-util-$(CONFIG_LIBUNWIND)          += unwind-libunwind.o
 perf-util-$(CONFIG_LIBUNWIND_X86)      += libunwind/x86_32.o
diff --git a/tools/perf/util/unwind-libdw-arch/Build b/tools/perf/util/unwind-libdw-arch/Build
new file mode 100644
index 0000000000000000000000000000000000000000..e016d54ae2a40ecba47156c8f09cb72156105727
--- /dev/null
+++ b/tools/perf/util/unwind-libdw-arch/Build
@@ -0,0 +1,8 @@
+perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-x86.o
+perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-arm.o
+perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-arm64.o
+perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-csky.o
+perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-loongarch.o
+perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-powerpc.o
+perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-riscv.o
+perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-s390.o
\ No newline at end of file
diff --git a/tools/perf/arch/arm/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-arm.c
similarity index 88%
rename from tools/perf/arch/arm/util/unwind-libdw.c
rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-arm.c
index fbb643f224ec4b27ce9d67051fe0bc4ad555b05e..c2718d6b6cff131cd67883e24bb0d3d963c8095a 100644
--- a/tools/perf/arch/arm/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-arm.c
@@ -1,11 +1,11 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <elfutils/libdwfl.h>
-#include "perf_regs.h"
+#include "../../../arch/arm/include/uapi/asm/perf_regs.h"
 #include "../../../util/unwind-libdw.h"
 #include "../../../util/perf_regs.h"
 #include "../../../util/sample.h"
 
-bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
+bool libdw_set_initial_registers_arm(Dwfl_Thread *thread, void *arg)
 {
 	struct unwind_info *ui = arg;
 	struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
diff --git a/tools/perf/arch/arm64/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-arm64.c
similarity index 92%
rename from tools/perf/arch/arm64/util/unwind-libdw.c
rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-arm64.c
index b89b0a7e5ad919fed23643d219fbdc3d84deff1e..87602503e057badc6efd37169cc60c96cf3949ab 100644
--- a/tools/perf/arch/arm64/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-arm64.c
@@ -1,11 +1,11 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <elfutils/libdwfl.h>
-#include "perf_regs.h"
+#include "../../../arch/arm64/include/uapi/asm/perf_regs.h"
 #include "../../../util/unwind-libdw.h"
 #include "../../../util/perf_regs.h"
 #include "../../../util/sample.h"
 
-bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
+bool libdw_set_initial_registers_arm64(Dwfl_Thread *thread, void *arg)
 {
 	struct unwind_info *ui = arg;
 	struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
diff --git a/tools/perf/arch/csky/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-csky.c
similarity index 92%
rename from tools/perf/arch/csky/util/unwind-libdw.c
rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-csky.c
index b20b1569783d7e982e91b1b40120d29ccf2f01d1..889d3b788931f3af55b03ef8b91d5def364972e5 100644
--- a/tools/perf/arch/csky/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-csky.c
@@ -2,12 +2,12 @@
 // Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd.
 
 #include <elfutils/libdwfl.h>
-#include "perf_regs.h"
+#include "../../../arch/csky/include/uapi/asm/perf_regs.h"
 #include "../../util/unwind-libdw.h"
 #include "../../util/perf_regs.h"
-#include "../../util/event.h"
+#include "../../util/sample.h"
 
-bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
+bool libdw_set_initial_registers_csky(Dwfl_Thread *thread, void *arg)
 {
 	struct unwind_info *ui = arg;
 	struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
diff --git a/tools/perf/arch/loongarch/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-loongarch.c
similarity index 91%
rename from tools/perf/arch/loongarch/util/unwind-libdw.c
rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-loongarch.c
index 60b1144bedd5f325e1512eeab05c29a1e8de2b03..1c5753ace6f63be771aa92365d3174ad8ed3a6fd 100644
--- a/tools/perf/arch/loongarch/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-loongarch.c
@@ -2,12 +2,12 @@
 /* Copyright (C) 2020-2023 Loongson Technology Corporation Limited */
 
 #include <elfutils/libdwfl.h>
-#include "perf_regs.h"
+#include "../../../arch/loongarch/include/uapi/asm/perf_regs.h"
 #include "../../util/unwind-libdw.h"
 #include "../../util/perf_regs.h"
 #include "../../util/sample.h"
 
-bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
+bool libdw_set_initial_registers_loongarch(Dwfl_Thread *thread, void *arg)
 {
 	struct unwind_info *ui = arg;
 	struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
diff --git a/tools/perf/arch/powerpc/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-powerpc.c
similarity index 93%
rename from tools/perf/arch/powerpc/util/unwind-libdw.c
rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-powerpc.c
index 82d0c28ae3459ecdb0039cac1f534420d142739b..28635af3c4aa420faa4de7e53428d82917f78021 100644
--- a/tools/perf/arch/powerpc/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-powerpc.c
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <elfutils/libdwfl.h>
 #include <linux/kernel.h>
-#include "perf_regs.h"
+#include "../../../arch/powerpc/include/uapi/asm/perf_regs.h"
 #include "../../../util/unwind-libdw.h"
 #include "../../../util/perf_regs.h"
 #include "../../../util/sample.h"
@@ -13,7 +13,7 @@ static const int special_regs[3][2] = {
 	{ 109, PERF_REG_POWERPC_CTR },
 };
 
-bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
+bool libdw_set_initial_registers_powerpc(Dwfl_Thread *thread, void *arg)
 {
 	struct unwind_info *ui = arg;
 	struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
diff --git a/tools/perf/arch/riscv/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-riscv.c
similarity index 92%
rename from tools/perf/arch/riscv/util/unwind-libdw.c
rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-riscv.c
index dc1476e16321736de897ad53a00fbc813bd706db..2a5442b3b5bdc27252378de0073deb8a620f8779 100644
--- a/tools/perf/arch/riscv/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-riscv.c
@@ -2,12 +2,12 @@
 /* Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd. */
 
 #include <elfutils/libdwfl.h>
-#include "perf_regs.h"
+#include "../../../arch/riscv/include/uapi/asm/perf_regs.h"
 #include "../../util/unwind-libdw.h"
 #include "../../util/perf_regs.h"
 #include "../../util/sample.h"
 
-bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
+bool libdw_set_initial_registers_riscv(Dwfl_Thread *thread, void *arg)
 {
 	struct unwind_info *ui = arg;
 	struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
diff --git a/tools/perf/arch/s390/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-s390.c
similarity index 89%
rename from tools/perf/arch/s390/util/unwind-libdw.c
rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-s390.c
index c27c7a0d1076c890c35ba19543932c4ed5ac9c2a..18d44074a55bc1c7fa2d7150afc1f1a93d4eadf8 100644
--- a/tools/perf/arch/s390/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-s390.c
@@ -4,11 +4,11 @@
 #include "../../util/perf_regs.h"
 #include "../../util/event.h"
 #include "../../util/sample.h"
-#include "dwarf-regs-table.h"
-#include "perf_regs.h"
+#include "../../arch/s390/include/dwarf-regs-table.h"
+#include "../../../arch/s390/include/uapi/asm/perf_regs.h"
 
 
-bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
+bool libdw_set_initial_registers_s390(Dwfl_Thread *thread, void *arg)
 {
 	struct unwind_info *ui = arg;
 	struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
diff --git a/tools/perf/arch/x86/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-x86.c
similarity index 94%
rename from tools/perf/arch/x86/util/unwind-libdw.c
rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-x86.c
index 798493e887d7308cb293e29e4ba11054d0fda722..822e799fe1543d82dab27a8efeada3f5cde08a44 100644
--- a/tools/perf/arch/x86/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-x86.c
@@ -5,7 +5,7 @@
 #include "../../../util/perf_regs.h"
 #include "util/sample.h"
 
-bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
+bool libdw_set_initial_registers_x86(Dwfl_Thread *thread, void *arg)
 {
 	struct unwind_info *ui = arg;
 	struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index ae70fb56a05729b9f06a411d162eabebbf29ac52..4a0f13bc5af99de446d440c551c718ef0187e195 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -225,12 +225,46 @@ static bool memory_read(Dwfl *dwfl __maybe_unused, Dwarf_Addr addr, Dwarf_Word *
 	return true;
 }
 
-static const Dwfl_Thread_Callbacks callbacks = {
-	.next_thread		= next_thread,
-	.memory_read		= memory_read,
-	.set_initial_registers	= libdw__arch_set_initial_registers,
+#define DEFINE_DWFL_THREAD_CALLBACKS(arch)                           \
+static const Dwfl_Thread_Callbacks callbacks_##arch = {              \
+	.next_thread           = next_thread,                        \
+	.memory_read           = memory_read,                        \
+	.set_initial_registers = libdw_set_initial_registers_##arch, \
 };
 
+DEFINE_DWFL_THREAD_CALLBACKS(x86)
+DEFINE_DWFL_THREAD_CALLBACKS(arm)
+DEFINE_DWFL_THREAD_CALLBACKS(arm64)
+DEFINE_DWFL_THREAD_CALLBACKS(csky)
+DEFINE_DWFL_THREAD_CALLBACKS(loongarch)
+DEFINE_DWFL_THREAD_CALLBACKS(powerpc)
+DEFINE_DWFL_THREAD_CALLBACKS(riscv)
+DEFINE_DWFL_THREAD_CALLBACKS(s390)
+
+static const Dwfl_Thread_Callbacks *get_thread_callbacks(const char *arch)
+{
+	if (!strcmp(arch, "arm"))
+		return &callbacks_arm;
+	else if (!strcmp(arch, "arm64"))
+		return &callbacks_arm64;
+	else if (!strcmp(arch, "csky"))
+		return &callbacks_csky;
+	else if (!strcmp(arch, "loongarch"))
+		return &callbacks_loongarch;
+	else if (!strcmp(arch, "powerpc"))
+		return &callbacks_powerpc;
+	else if (!strcmp(arch, "riscv"))
+		return &callbacks_riscv;
+	else if (!strcmp(arch, "s390"))
+		return &callbacks_s390;
+	else if (!strcmp(arch, "x86"))
+		return &callbacks_x86;
+
+	pr_err("Fail to get thread callbacks for arch %s, returns NULL\n",
+	       arch);
+	return NULL;
+}
+
 static int
 frame_callback(Dwfl_Frame *state, void *arg)
 {
@@ -278,6 +312,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
 	const char *arch = perf_env__arch(ui_buf.machine->env);
 	Dwarf_Word ip;
 	int err = -EINVAL, i;
+	const Dwfl_Thread_Callbacks *callbacks;
 
 	if (!data->user_regs || !data->user_regs->regs)
 		return -EINVAL;
@@ -300,7 +335,11 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
 	if (err)
 		goto out;
 
-	err = !dwfl_attach_state(ui->dwfl, EM_NONE, thread__tid(thread), &callbacks, ui);
+	callbacks = get_thread_callbacks(arch);
+	if (!callbacks)
+		goto out;
+
+	err = !dwfl_attach_state(ui->dwfl, EM_NONE, thread__tid(thread), callbacks, ui);
 	if (err)
 		goto out;
 
diff --git a/tools/perf/util/unwind-libdw.h b/tools/perf/util/unwind-libdw.h
index 8c88bc4f2304b59561ffd482469ca63ce0f531f0..574b29848cce31e6bfd93021f752b518cebf73b7 100644
--- a/tools/perf/util/unwind-libdw.h
+++ b/tools/perf/util/unwind-libdw.h
@@ -9,7 +9,15 @@ struct machine;
 struct perf_sample;
 struct thread;
 
-bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg);
+bool libdw_set_initial_registers_x86(Dwfl_Thread *thread, void *arg);
+bool libdw_set_initial_registers_arm(Dwfl_Thread *thread, void *arg);
+bool libdw_set_initial_registers_arm64(Dwfl_Thread *thread, void *arg);
+bool libdw_set_initial_registers_csky(Dwfl_Thread *thread, void *arg);
+bool libdw_set_initial_registers_loongarch(Dwfl_Thread *thread, void *arg);
+bool libdw_set_initial_registers_mips(Dwfl_Thread *thread, void *arg);
+bool libdw_set_initial_registers_powerpc(Dwfl_Thread *thread, void *arg);
+bool libdw_set_initial_registers_riscv(Dwfl_Thread *thread, void *arg);
+bool libdw_set_initial_registers_s390(Dwfl_Thread *thread, void *arg);
 
 struct unwind_info {
 	Dwfl			*dwfl;

---
base-commit: cbd41c6d4c26c161a2b0e70ad411d3885ff13507
change-id: 20251223-cross-arch-unwind-d890d6a5ff0a

Best regards,
-- 
Shimin Guo <shimin.guo at skydio.com>




From Macpaul.Lin at mediatek.com  Tue Dec 23 18:20:19 2025
From: Macpaul.Lin at mediatek.com (=?utf-8?B?TWFjcGF1bCBMaW4gKOael+aZuuaWjCk=?=)
Date: Wed, 24 Dec 2025 02:20:19 +0000
Subject: [PATCH 06/11] drm/mediatek: Add plane_colorops_init() DDP hook
 for OVL
In-Reply-To: <20251223-mtk-ovl-pre-blend-colorops-v1-6-0cb99bd0ab33@collabora.com>
References: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
	 <20251223-mtk-ovl-pre-blend-colorops-v1-6-0cb99bd0ab33@collabora.com>
Message-ID: <5bc77576fc6e77f9f87cef27b42b67e2c2c2c9ac.camel@mediatek.com>

On Tue, 2025-12-23 at 16:44 -0300, N?colas F. R. A. Prado wrote:
> Hook OVL's plane colorops initialization function in DDP to allow its
> usage by the MediaTek KMS driver.
> 
> Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
> ---
> ?drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 1 +
> ?1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
> b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
> index 94b356da6de7..ef906b2aff74 100644
> --- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
> @@ -331,6 +331,7 @@ static const struct mtk_ddp_comp_funcs ddp_ovl =
> {
> ??????? .get_formats = mtk_ovl_get_formats,
> ??????? .get_num_formats = mtk_ovl_get_num_formats,
> ??????? .is_afbc_supported = mtk_ovl_is_afbc_supported,
> +?????? .plane_colorops_init = mtk_ovl_plane_colorops_init,
> ?};
> 
> ?static const struct mtk_ddp_comp_funcs ddp_postmask = {
> 
> --
> 2.51.0
> 
> 

Reviewed-by: Macpaul Lin <macpaul.lin at mediatek.com>

Best regards,
Macpaul Lin

From Macpaul.Lin at mediatek.com  Tue Dec 23 18:21:42 2025
From: Macpaul.Lin at mediatek.com (=?utf-8?B?TWFjcGF1bCBMaW4gKOael+aZuuaWjCk=?=)
Date: Wed, 24 Dec 2025 02:21:42 +0000
Subject: [PATCH 07/11] drm/colorop: Introduce HLG EOTF
In-Reply-To: <20251223-mtk-ovl-pre-blend-colorops-v1-7-0cb99bd0ab33@collabora.com>
References: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
	 <20251223-mtk-ovl-pre-blend-colorops-v1-7-0cb99bd0ab33@collabora.com>
Message-ID: <04894f0988cd81c7effb6fcbc2997108ba84b064.camel@mediatek.com>

On Tue, 2025-12-23 at 16:44 -0300, N?colas F. R. A. Prado wrote:
> Introduce definition of a hybrid log-gamma electro-optical transfer
> function for 1D Curve colorops.
> 
> Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
> ---
> ?drivers/gpu/drm/drm_colorop.c |? 1 +
> ?include/drm/drm_colorop.h???? | 10 ++++++++++
> ?2 files changed, 11 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_colorop.c
> b/drivers/gpu/drm/drm_colorop.c
> index fafe45b93ff8..a19e03fb9c7c 100644
> --- a/drivers/gpu/drm/drm_colorop.c
> +++ b/drivers/gpu/drm/drm_colorop.c
> @@ -79,6 +79,7 @@ static const char * const
> colorop_curve_1d_type_names[] = {
> ??????? [DRM_COLOROP_1D_CURVE_BT2020_OETF] = "BT.2020 OETF",
> ??????? [DRM_COLOROP_1D_CURVE_GAMMA22] = "Gamma 2.2",
> ??????? [DRM_COLOROP_1D_CURVE_GAMMA22_INV] = "Gamma 2.2 Inverse",
> +?????? [DRM_COLOROP_1D_CURVE_HLG_EOTF] = "HLG",
> ?};
> 
> ?static const struct drm_prop_enum_list
> drm_colorop_lut1d_interpolation_list[] = {
> diff --git a/include/drm/drm_colorop.h b/include/drm/drm_colorop.h
> index ee6454b08b2d..8ec98521607d 100644
> --- a/include/drm/drm_colorop.h
> +++ b/include/drm/drm_colorop.h
> @@ -126,6 +126,16 @@ enum drm_colorop_curve_1d_type {
> ???????? * The inverse of &DRM_COLOROP_1D_CURVE_GAMMA22
> ???????? */
> ??????? DRM_COLOROP_1D_CURVE_GAMMA22_INV,
> +
> +?????? /**
> +??????? * @DRM_COLOROP_1D_CURVE_HLG_EOTF:
> +??????? *
> +??????? * enum string "HLG"
> +??????? *
> +??????? * Hybrid log-gamma transfer function.
> +??????? */
> +?????? DRM_COLOROP_1D_CURVE_HLG_EOTF,
> +
> ??????? /**
> ???????? * @DRM_COLOROP_1D_CURVE_COUNT:
> ???????? *
> 
> --
> 2.51.0
> 
> 

Reviewed-by: Macpaul Lin <macpaul.lin at mediatek.com>

Best regards,
Macpaul Lin

From geraldogabriel at gmail.com  Tue Dec 23 18:24:12 2025
From: geraldogabriel at gmail.com (Geraldo Nascimento)
Date: Tue, 23 Dec 2025 23:24:12 -0300
Subject: [PATCH v2 1/4] PCI: rockchip: limit RK3399 to 2.5 GT/s to prevent damage
In-Reply-To: <656e9b4e-c350-f808-701e-e49e8dad7062@manjaro.org>
References: <cover.1763415705.git.geraldogabriel@gmail.com>
 <eaa9c75ca02a53f8bcc293b8bc73d013e26ec253.1763415706.git.geraldogabriel@gmail.com>
 <qncj72c3owrw7rvnj6jit2sbn4ojyr3kztcjailfxtdboan6sy@ddh5g7v4fcvt>
 <3ea8ac20-6332-0c0c-645b-36ca4231c109@manjaro.org> <DF197NIRHLIJ.3LIG9GJGJQLQX@cknow-tech.com>
 <656e9b4e-c350-f808-701e-e49e8dad7062@manjaro.org>
Message-ID: <CAEsQvcv_8HnWNHAQGKs3pzBqrO_9+HsMr9w-F=pZJ1oEXeC=Bw@mail.gmail.com>

Hello Mani, Dragan, Diederik, and all,

I'm currently facing banking issues in Brazil which means I'm
refraining from fetching my email through POP3 with mutt to do proper
kernel development.
I usually fetch my mail through POP3 and have the server delete it, to
save space on my free tier.
But I found out I have a 20-year old bank account open that I had
forgot about, and with this bureaucracy hell I can't have the server
delete the messages for now.
I'll send v3 with more proper and illustrative wording once I get this done.

Thanks,
Geraldo Nascimento

On Thu, Dec 18, 2025 at 7:13?AM Dragan Simic <dsimic at manjaro.org> wrote:
>
> Hello Diederik,
>
> On Thursday, December 18, 2025 11:01 CET, "Diederik de Haas" <diederik at cknow-tech.com> wrote:
> > On Thu Dec 18, 2025 at 10:47 AM CET, Dragan Simic wrote:
> > > On Thursday, December 18, 2025 09:05 CET, Manivannan Sadhasivam <mani at kernel.org> wrote:
> > >> On Mon, Nov 17, 2025 at 06:47:05PM -0300, Geraldo Nascimento wrote:
> > >> > Shawn Lin from Rockchip has reiterated that there may be danger in using
> > >> > their PCIe with 5.0 GT/s speeds. Warn the user if they make a DT change
> > >> > from the default and drive at 2.5 GT/s only, even if the DT
> > >> > max-link-speed property is invalid or inexistent.
> > >> >
> > >> > This change is corroborated by RK3399 official datasheet [1], which
> > >> > says maximum link speed for this platform is 2.5 GT/s.
> > >> >
> > >> > [1] https://opensource.rock-chips.com/images/d/d7/Rockchip_RK3399_Datasheet_V2.1-20200323.pdf
> > >> >
> > >> > Fixes: 956cd99b35a8 ("PCI: rockchip: Separate common code from RC driver")
> > >> > Link: https://lore.kernel.org/all/ffd05070-9879-4468-94e3-b88968b4c21b at rock-chips.com/
> > >> > Cc: stable at vger.kernel.org
> > >> > Reported-by: Dragan Simic <dsimic at manjaro.org>
> > >> > Reported-by: Shawn Lin <shawn.lin at rock-chips.com>
> > >> > Reviewed-by: Dragan Simic <dsimic at manjaro.org>
> > >> > Signed-off-by: Geraldo Nascimento <geraldogabriel at gmail.com>
> > >> > ---
> > >> >  drivers/pci/controller/pcie-rockchip.c | 10 ++++++++--
> > >> >  1 file changed, 8 insertions(+), 2 deletions(-)
> > >> >
> > >> > diff --git a/drivers/pci/controller/pcie-rockchip.c b/drivers/pci/controller/pcie-rockchip.c
> > >> > index 0f88da378805..992ccf4b139e 100644
> > >> > --- a/drivers/pci/controller/pcie-rockchip.c
> > >> > +++ b/drivers/pci/controller/pcie-rockchip.c
> > >> > @@ -66,8 +66,14 @@ int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip)
> > >> >          }
> > >> >
> > >> >          rockchip->link_gen = of_pci_get_max_link_speed(node);
> > >> > -        if (rockchip->link_gen < 0 || rockchip->link_gen > 2)
> > >> > -                rockchip->link_gen = 2;
> > >> > +        if (rockchip->link_gen < 0 || rockchip->link_gen > 2) {
> > >> > +                rockchip->link_gen = 1;
> > >> > +                dev_warn(dev, "invalid max-link-speed, set to 2.5 GT/s\n");
> > >> > +        }
> > >> > +        else if (rockchip->link_gen == 2) {
> > >> > +                rockchip->link_gen = 1;
> > >> > +                dev_warn(dev, "5.0 GT/s is dangerous, set to 2.5 GT/s\n");
> > >>
> > >> What does 'danger' really mean here? Link instability or something else?
> > >> Error messages should be precise and not fearmongering.
> > >
> > > I agree that the original wording is a bit suboptimal, and I'd suggest
> > > to Geraldo that the produced warning message is changed to
> > >
> > >   "5.0 GT/s may cause data corruption, limited to to 2.5 GT/s\n"
> > >
> > > or something similar, to better reflect the actual underlying issue.
> >
> > s/limited to to/therefore limit speed to/ ?
>
> That would work well in a book or an article, while slightly terse
> wording is usually preferred in the messages produced by the kernel,
> or in log messages in general.  Such an approach compacts as much
> information as possible in as few words as possible, while still
> remaining (mostly) grammatically correct.
>


From jgg at nvidia.com  Tue Dec 23 18:26:12 2025
From: jgg at nvidia.com (Jason Gunthorpe)
Date: Tue, 23 Dec 2025 22:26:12 -0400
Subject: [PATCH 3/4] ARM: remove support for highmem on VIVT
In-Reply-To: <513078d3-976a-4e6d-b311-dcfcfea99238@app.fastmail.com>
References: <20251219161559.556737-1-arnd@kernel.org>
 <20251219161559.556737-4-arnd@kernel.org>
 <20251219171412.GG254720@nvidia.com>
 <513078d3-976a-4e6d-b311-dcfcfea99238@app.fastmail.com>
Message-ID: <aUtPRFdbpSQ20eOx@nvidia.com>

On Fri, Dec 19, 2025 at 09:34:33PM +0100, Arnd Bergmann wrote:
> On Fri, Dec 19, 2025, at 18:14, Jason Gunthorpe wrote:
> > On Fri, Dec 19, 2025 at 05:15:58PM +0100, Arnd Bergmann wrote:
> >>  arch/arm/Kconfig                    |  1 +
> >>  arch/arm/configs/gemini_defconfig   |  1 -
> >>  arch/arm/configs/multi_v5_defconfig |  1 -
> >>  arch/arm/configs/mvebu_v5_defconfig |  1 -
> >>  arch/arm/include/asm/highmem.h      | 56 ++---------------------------
> >>  arch/arm/mm/cache-feroceon-l2.c     | 31 ++--------------
> >>  arch/arm/mm/cache-xsc3l2.c          | 47 +++---------------------
> >>  arch/arm/mm/dma-mapping.c           | 12 ++-----
> >>  arch/arm/mm/flush.c                 | 19 +++-------
> >>  9 files changed, 16 insertions(+), 153 deletions(-)
> >
> > This looks great, but do you think there should be a boot time crash
> > if a VIVT and HIGHMEM are enabled, just incase?
> 
> Do you mean in the common code or just for Arm?
> 
> We could use the Arm specific cache_is_vivt() macro, but it feels like
> the 'dpends on !CPU_CACHE_VIVT' Kconfig check I added is both
> safer and simpler.

Okay, so maybe I'm asking if !CPU_CACHE_VIVT then the kernel fails to
boot on vivt systems, maybe it already does?

It would be ARM specific, all this stuff is only for ARM32..

Jason


From jianhua.lin at mediatek.com  Tue Dec 23 19:17:17 2025
From: jianhua.lin at mediatek.com (Jianhua Lin)
Date: Wed, 24 Dec 2025 11:17:17 +0800
Subject: [PATCH v2 0/4] Mediatek MT8189 JPEG support
Message-ID: <20251224031721.9942-1-jianhua.lin@mediatek.com>

This series is based on tag: next-20251219, linux-next/master

Changes compared with v1:
- Patches 1/4:
  - Updating commit message
- Patches 2/4, 3/4: 
  - Updating commit message
  - Adjusted property descriptions acorrding to hardware requirements
  - Improved formatting for better readability and consistency
- Patches 4/4:
  - Updating commit message

Jianhua Lin (4):
  arm64: dts: mt8188: update JPEG encoder/decoder compatible
  dt-bindings: media: mediatek-jpeg-decoder: add MT8189 compatible
    string
  dt-bindings: media: mediatek-jpeg-encoder: add MT8189 compatible
    string
  media: mediatek: jpeg: add compatible for MT8189 SoC

 .../bindings/media/mediatek-jpeg-decoder.yaml | 50 ++++++++++++++++---
 .../bindings/media/mediatek-jpeg-encoder.yaml | 29 ++++++++---
 arch/arm64/boot/dts/mediatek/mt8188.dtsi      |  9 ++--
 .../platform/mediatek/jpeg/mtk_jpeg_core.c    | 44 ++++++++++++++++
 4 files changed, 114 insertions(+), 18 deletions(-)

-- 
2.45.2



From jianhua.lin at mediatek.com  Tue Dec 23 19:17:20 2025
From: jianhua.lin at mediatek.com (Jianhua Lin)
Date: Wed, 24 Dec 2025 11:17:20 +0800
Subject: [PATCH v2 3/4] dt-bindings: media: mediatek-jpeg-encoder: add MT8189 compatible string
In-Reply-To: <20251224031721.9942-1-jianhua.lin@mediatek.com>
References: <20251224031721.9942-1-jianhua.lin@mediatek.com>
Message-ID: <20251224031721.9942-4-jianhua.lin@mediatek.com>

Compared to the previous generation IC, the MT8189 uses 34-bit iova
address-space (16GB)  and requires a single clock configuration.
Therefore, add "mediatek,mt8189-jpgenc" compatible to the binding document.
Additionally, it corrects the inheritance for MT8188, aligning it
with MT8189 due to their shared architecture and 34-bit iova address
space (16GB) requirements.
Previously, MT8188 was incorrectly defined alongside SoCs with 32-bit
iova address-space (4GB), such as "mediatek,mtk-jpgenc". This mismatch
results in an ABI break, as MT8188 cannot function correctly under
the 32-bit iova address-space (4GB) configuration.

Key changes include:
- Introducing "mediatek,mt8189-jpgenc" as a new compatible string to
  represent the correct architecture.
- Updating MT8188 to inherit from MT8189, ensuring proper support for
  34-bit iova address-space (16GB).
- Add property "mediatek,larb" for MT8189 requirements.
- Improved formatting for better readability and consistency.

These changes ensure that both MT8188 and MT8189 are correctly supported
with the necessary 34-bit iova address-space (16GB), while maintaining
compatibility with their shared architecture.

Extensive internal review and testing have been conducted to validate
these changes and ensure compliance with DT binding standards.

Signed-off-by: Jianhua Lin <jianhua.lin at mediatek.com>
---
 .../bindings/media/mediatek-jpeg-encoder.yaml | 29 ++++++++++++++-----
 1 file changed, 22 insertions(+), 7 deletions(-)

diff --git a/Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml b/Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml
index 5b15f8977f67..3205ecbaa6c5 100644
--- a/Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml
+++ b/Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml
@@ -14,13 +14,24 @@ description: |-
 
 properties:
   compatible:
-    items:
-      - enum:
-          - mediatek,mt2701-jpgenc
-          - mediatek,mt8183-jpgenc
-          - mediatek,mt8186-jpgenc
-          - mediatek,mt8188-jpgenc
-      - const: mediatek,mtk-jpgenc
+    oneOf:
+      - items:
+          - enum:
+              - mediatek,mtk-jpgenc
+      - items:
+          - enum:
+              - mediatek,mt8189-jpgenc
+      - items:
+          - enum:
+              - mediatek,mt2701-jpgenc
+              - mediatek,mt8183-jpgenc
+              - mediatek,mt8186-jpgenc
+          - const: mediatek,mtk-jpgenc
+      - items:
+          - enum:
+              - mediatek,mt8188-jpgenc
+          - const: mediatek,mt8189-jpgenc
+
   reg:
     maxItems: 1
 
@@ -34,6 +45,10 @@ properties:
     items:
       - const: jpgenc
 
+  mediatek,larb:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: a phandle to the smi_larb node.
+
   power-domains:
     maxItems: 1
 
-- 
2.45.2



From jianhua.lin at mediatek.com  Tue Dec 23 19:17:18 2025
From: jianhua.lin at mediatek.com (Jianhua Lin)
Date: Wed, 24 Dec 2025 11:17:18 +0800
Subject: [PATCH v2 1/4] arm64: dts: mt8188: update JPEG encoder/decoder compatible
In-Reply-To: <20251224031721.9942-1-jianhua.lin@mediatek.com>
References: <20251224031721.9942-1-jianhua.lin@mediatek.com>
Message-ID: <20251224031721.9942-2-jianhua.lin@mediatek.com>

The JPEG encoder and decoder of MT8188 share the same architecture
and features as those of MT8189, both use a 34-bit iova
address-space (16GB) and a single clock configuration.

Previously, MT8188 was incorrectly defined alongside SoCs with 32-bit
iova address-space (4GB), such as "mediatek,mt2701-jpgdec" and
"mediatek,mtk-jpgenc". This mismatch results in an ABI break,
as MT8188 cannot function correctly under the 32-bit iova
address-space (4GB) configuration.

Therefore, MT8188 needs to inherit from MT8189.
Update "mediatek,mtk-jpgenc" to "mediatek,mt8189-jpgenc",
update "mediatek,mt2701-jpgdec" to "mediatek,mt8189-jpgdec".

Signed-off-by: Jianhua Lin <jianhua.lin at mediatek.com>
---
 arch/arm64/boot/dts/mediatek/mt8188.dtsi | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/boot/dts/mediatek/mt8188.dtsi b/arch/arm64/boot/dts/mediatek/mt8188.dtsi
index 90c388f1890f..ff9a774f5911 100644
--- a/arch/arm64/boot/dts/mediatek/mt8188.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8188.dtsi
@@ -2846,7 +2846,7 @@ video_encoder: video-encoder at 1a020000 {
 		};
 
 		jpeg_encoder: jpeg-encoder at 1a030000 {
-			compatible = "mediatek,mt8188-jpgenc", "mediatek,mtk-jpgenc";
+			compatible = "mediatek,mt8188-jpgenc", "mediatek,mt8189-jpgenc";
 			reg = <0 0x1a030000 0 0x10000>;
 			clocks = <&vencsys CLK_VENC1_JPGENC>;
 			clock-names = "jpgenc";
@@ -2859,11 +2859,10 @@ jpeg_encoder: jpeg-encoder at 1a030000 {
 		};
 
 		jpeg_decoder: jpeg-decoder at 1a040000 {
-			compatible = "mediatek,mt8188-jpgdec", "mediatek,mt2701-jpgdec";
+			compatible = "mediatek,mt8188-jpgdec", "mediatek,mt8189-jpgdec";
 			reg = <0 0x1a040000 0 0x10000>;
-			clocks = <&vencsys CLK_VENC1_LARB>,
-				 <&vencsys CLK_VENC1_JPGDEC>;
-			clock-names = "jpgdec-smi", "jpgdec";
+			clocks = <&vencsys CLK_VENC1_JPGDEC>;
+			clock-names = "jpgdec";
 			interrupts = <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH 0>;
 			iommus = <&vdo_iommu M4U_PORT_L19_JPGDEC_WDMA_0>,
 				 <&vdo_iommu M4U_PORT_L19_JPGDEC_BSDMA_0>,
-- 
2.45.2



From jianhua.lin at mediatek.com  Tue Dec 23 19:17:19 2025
From: jianhua.lin at mediatek.com (Jianhua Lin)
Date: Wed, 24 Dec 2025 11:17:19 +0800
Subject: [PATCH v2 2/4] dt-bindings: media: mediatek-jpeg-decoder: add MT8189 compatible string
In-Reply-To: <20251224031721.9942-1-jianhua.lin@mediatek.com>
References: <20251224031721.9942-1-jianhua.lin@mediatek.com>
Message-ID: <20251224031721.9942-3-jianhua.lin@mediatek.com>

Compared to the previous generation IC, the MT8189 uses 34-bit iova
address-space (16GB) and requires a single clock configuration.
Therefore, add "mediatek,mt8189-jpgdec" compatible to the binding document.
Additionally, it corrects the inheritance for MT8188, aligning it
with MT8189 due to their shared architecture and 34-bit iova address
space (16GB) and singlesingle clock requirement.
Previously, MT8188 was incorrectly defined alongside SoCs with 32-bit
iova address-space (4GB), such as "mediatek,mt2701-jpgdec". This mismatch
results in an ABI break, as MT8188 cannot function correctly under
the 32-bit iova address-space (4GB) configuration.

Key changes include:
- Introducing "mediatek,mt8189-jpgdec" as a new compatible string to
  represent the correct architecture.
- Updating MT8188 to inherit from MT8189, ensuring proper support for
  34-bit iova address-space (16GB) and simplifying clock configuration.
- Add property "mediatek,larb" for MT8189 requirements.
- Improved formatting for better readability and consistency.

These changes ensure that both MT8188 and MT8189 are correctly supported
with the necessary 34-bit iova address-space (16GB), while maintaining
compatibility with their shared architecture.

Extensive internal review and testing have been conducted to validate
these changes and ensure compliance with DT binding standards.

Signed-off-by: Jianhua Lin <jianhua.lin at mediatek.com>
---
 .../bindings/media/mediatek-jpeg-decoder.yaml | 50 ++++++++++++++++---
 1 file changed, 44 insertions(+), 6 deletions(-)

diff --git a/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml b/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml
index a4aacd3eb189..814b53ef46e7 100644
--- a/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml
+++ b/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml
@@ -17,13 +17,19 @@ properties:
     oneOf:
       - items:
           - enum:
-              - mediatek,mt8173-jpgdec
               - mediatek,mt2701-jpgdec
+              - mediatek,mt8173-jpgdec
+      - items:
+          - enum:
+              - mediatek,mt8189-jpgdec
       - items:
           - enum:
               - mediatek,mt7623-jpgdec
-              - mediatek,mt8188-jpgdec
           - const: mediatek,mt2701-jpgdec
+      - items:
+          - enum:
+              - mediatek,mt8188-jpgdec
+          - const: mediatek,mt8189-jpgdec
 
   reg:
     maxItems: 1
@@ -32,13 +38,16 @@ properties:
     maxItems: 1
 
   clocks:
+    minItems: 1
     maxItems: 2
-    minItems: 2
 
   clock-names:
-    items:
-      - const: jpgdec-smi
-      - const: jpgdec
+    minItems: 1
+    maxItems: 2
+
+  mediatek,larb:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: a phandle to the smi_larb node.
 
   power-domains:
     maxItems: 1
@@ -51,6 +60,35 @@ properties:
       Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml for details.
       Ports are according to the HW.
 
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - mediatek,mt2701-jpgdec
+              - mediatek,mt8173-jpgdec
+
+    then:
+      properties:
+        clock-names:
+          items:
+            - const: jpgdec-smi
+            - const: jpgdec
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - mediatek,mt8189-jpgdec
+
+    then:
+      properties:
+        clock-names:
+          items:
+            - const: jpgdec
+
 required:
   - compatible
   - reg
-- 
2.45.2



From jianhua.lin at mediatek.com  Tue Dec 23 19:17:21 2025
From: jianhua.lin at mediatek.com (Jianhua Lin)
Date: Wed, 24 Dec 2025 11:17:21 +0800
Subject: [PATCH v2 4/4] media: mediatek: jpeg: add compatible for MT8189 SoC
In-Reply-To: <20251224031721.9942-1-jianhua.lin@mediatek.com>
References: <20251224031721.9942-1-jianhua.lin@mediatek.com>
Message-ID: <20251224031721.9942-5-jianhua.lin@mediatek.com>

Compared to the previous generation IC, the MT8189 uses 34-bit iova
address-space (16GB) and requires a single clock configuration.
Therefore, add new compatible to support the JPEG encoder and decoder
of MT8189 SoC.

Signed-off-by: Jianhua Lin <jianhua.lin at mediatek.com>
---
 .../platform/mediatek/jpeg/mtk_jpeg_core.c    | 44 +++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
index d08fe365cbb2..9ea8d8f56e9b 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
@@ -1866,6 +1866,10 @@ static struct clk_bulk_data mt8173_jpeg_dec_clocks[] = {
 	{ .id = "jpgdec" },
 };
 
+static struct clk_bulk_data mtk_jpeg_dec_clocks[] = {
+	{ .id = "jpgdec" },
+};
+
 static const struct mtk_jpeg_variant mt8173_jpeg_drvdata = {
 	.clks = mt8173_jpeg_dec_clocks,
 	.num_clks = ARRAY_SIZE(mt8173_jpeg_dec_clocks),
@@ -1897,6 +1901,38 @@ static const struct mtk_jpeg_variant mtk_jpeg_drvdata = {
 	.multi_core = false,
 };
 
+static const struct mtk_jpeg_variant mtk8189_jpegenc_drvdata = {
+	.clks = mtk_jpeg_clocks,
+	.num_clks = ARRAY_SIZE(mtk_jpeg_clocks),
+	.formats = mtk_jpeg_enc_formats,
+	.num_formats = MTK_JPEG_ENC_NUM_FORMATS,
+	.qops = &mtk_jpeg_enc_qops,
+	.irq_handler = mtk_jpeg_enc_irq,
+	.hw_reset = mtk_jpeg_enc_reset,
+	.m2m_ops = &mtk_jpeg_enc_m2m_ops,
+	.dev_name = "mtk-jpeg-enc",
+	.ioctl_ops = &mtk_jpeg_enc_ioctl_ops,
+	.out_q_default_fourcc = V4L2_PIX_FMT_YUYV,
+	.cap_q_default_fourcc = V4L2_PIX_FMT_JPEG,
+	.support_34bit = true,
+};
+
+static const struct mtk_jpeg_variant mtk8189_jpegdec_drvdata = {
+	.clks = mtk_jpeg_dec_clocks,
+	.num_clks = ARRAY_SIZE(mtk_jpeg_dec_clocks),
+	.formats = mtk_jpeg_dec_formats,
+	.num_formats = MTK_JPEG_DEC_NUM_FORMATS,
+	.qops = &mtk_jpeg_dec_qops,
+	.irq_handler = mtk_jpeg_dec_irq,
+	.hw_reset = mtk_jpeg_dec_reset,
+	.m2m_ops = &mtk_jpeg_dec_m2m_ops,
+	.dev_name = "mtk-jpeg-dec",
+	.ioctl_ops = &mtk_jpeg_dec_ioctl_ops,
+	.out_q_default_fourcc = V4L2_PIX_FMT_JPEG,
+	.cap_q_default_fourcc = V4L2_PIX_FMT_YUV420M,
+	.support_34bit = true,
+};
+
 static struct mtk_jpeg_variant mtk8195_jpegenc_drvdata = {
 	.formats = mtk_jpeg_enc_formats,
 	.num_formats = MTK_JPEG_ENC_NUM_FORMATS,
@@ -1936,6 +1972,14 @@ static const struct of_device_id mtk_jpeg_match[] = {
 		.compatible = "mediatek,mtk-jpgenc",
 		.data = &mtk_jpeg_drvdata,
 	},
+	{
+		.compatible = "mediatek,mt8189-jpgenc",
+		.data = &mtk8189_jpegenc_drvdata,
+	},
+	{
+		.compatible = "mediatek,mt8189-jpgdec",
+		.data = &mtk8189_jpegdec_drvdata,
+	},
 	{
 		.compatible = "mediatek,mt8195-jpgenc",
 		.data = &mtk8195_jpegenc_drvdata,
-- 
2.45.2



From vz at mleia.com  Tue Dec 23 20:52:05 2025
From: vz at mleia.com (Vladimir Zapolskiy)
Date: Wed, 24 Dec 2025 06:52:05 +0200
Subject: [PATCH] ARM: dts: lpc32xx: Update spi clock properties
Message-ID: <20251224045205.1204414-1-vz@mleia.com>

From: Kuldeep Singh <singh.kuldeep87k at gmail.com>

PL022 binding require two clocks to be defined but NXP LPC32xx platform
doesn't comply with the bindings and define only one clock i.e apb_pclk.

Update SPI clocks and clocks-names property by adding appropriate clock
reference to make it compliant with the bindings.

Noteworthy, strictly speaking the change tackles DT ABI by changing
the order in the list of clock-names property values, however this level
of impact is considered as acceptable.

Cc: Vladimir Zapolskiy <vz at mleia.com>
Signed-off-by: Kuldeep Singh <singh.kuldeep87k at gmail.com>
[vzapolskiy: rebased and minor update to the commit message]
Signed-off-by: Vladimir Zapolskiy <vz at mleia.com>
---
I do resend the unapplied change from the past, which raised a discussion:
* https://lore.kernel.org/all/20220311093800.18778-4-singh.kuldeep87k at gmail.com/

A functionally identical change has been sent recently:
* https://lore.kernel.org/all/20251029202801.3963952-2-Frank.Li at nxp.com/
---
 arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
index e780451fd335..206c66bdfe41 100644
--- a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
+++ b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
@@ -172,8 +172,8 @@ ssp0: spi at 20084000 {
 				compatible = "arm,pl022", "arm,primecell";
 				reg = <0x20084000 0x1000>;
 				interrupts = <20 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk LPC32XX_CLK_SSP0>;
-				clock-names = "apb_pclk";
+				clocks = <&clk LPC32XX_CLK_SSP0>, <&clk LPC32XX_CLK_SSP0>;
+				clock-names = "sspclk", "apb_pclk";
 				#address-cells = <1>;
 				#size-cells = <0>;
 				status = "disabled";
@@ -196,8 +196,8 @@ ssp1: spi at 2008c000 {
 				compatible = "arm,pl022", "arm,primecell";
 				reg = <0x2008c000 0x1000>;
 				interrupts = <21 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk LPC32XX_CLK_SSP1>;
-				clock-names = "apb_pclk";
+				clocks = <&clk LPC32XX_CLK_SSP1>, <&clk LPC32XX_CLK_SSP1>;
+				clock-names = "sspclk", "apb_pclk";
 				#address-cells = <1>;
 				#size-cells = <0>;
 				status = "disabled";
-- 
2.43.0



From dev.jain at arm.com  Tue Dec 23 21:05:04 2025
From: dev.jain at arm.com (Dev Jain)
Date: Wed, 24 Dec 2025 10:35:04 +0530
Subject: [RESEND RFC PATCH 1/2] mm/vmalloc: Do not align size to huge size
In-Reply-To: <aUkv51yk8lgzW9jv@milan>
References: <20251212042701.71993-1-dev.jain@arm.com>
 <20251212042701.71993-2-dev.jain@arm.com> <aUkv51yk8lgzW9jv@milan>
Message-ID: <19e28edb-87b1-4e4d-accc-2219f717aa51@arm.com>


On 22/12/25 5:17 pm, Uladzislau Rezki wrote:
> On Fri, Dec 12, 2025 at 09:57:00AM +0530, Dev Jain wrote:
>> vmalloc() consists of the following:
>>
>> (1) find empty space in the vmalloc space -> (2) get physical pages from
>> the buddy system -> (3) map the pages into the pagetable.
>>
>> It turns out that the cost of (1) and (3) is pretty insignificant. Hence,
>> the cost of vmalloc becomes highly sensitive to physical memory allocation
>> time.
>>
>> Currently, if we decide to use huge mappings, apart from aligning the start
>> of the target vm_struct region to the huge-alignment, we also align the
>> size. This does not seem to produce any benefit (apart from simplification
>> of the code), and there is a clear disadvantage - as mentioned above, the
>> main cost of vmalloc comes from its interaction with the buddy system, and
>> thus requesting more memory than was requested by the caller is suboptimal
>> and unnecessary.
>>
>> This change is also motivated due to the next patch ("arm64/mm: Enable
>> vmalloc-huge by default"). Suppose that some user of vmalloc maps 17 pages,
>> uses that mapping for an extremely short time, and vfree's it. That patch,
>> without this patch, on arm64 will ultimately map 16 * 2 = 32 pages in a
>> contiguous way. Since the mapping is used for a very short time, it is
>> likely that the extra cost of mapping 15 pages defeats any benefit from
>> reduced TLB pressure, and regresses that code path. 
>>
>> Signed-off-by: Dev Jain <dev.jain at arm.com>
>> ---
>>  mm/vmalloc.c | 38 ++++++++++++++++++++++++++++++--------
>>  1 file changed, 30 insertions(+), 8 deletions(-)
>>
>> diff --git a/mm/vmalloc.c b/mm/vmalloc.c
>> index ecbac900c35f..389225a6f7ef 100644
>> --- a/mm/vmalloc.c
>> +++ b/mm/vmalloc.c
>> @@ -654,7 +654,7 @@ static int vmap_small_pages_range_noflush(unsigned long addr, unsigned long end,
>>  int __vmap_pages_range_noflush(unsigned long addr, unsigned long end,
>>  		pgprot_t prot, struct page **pages, unsigned int page_shift)
>>  {
>> -	unsigned int i, nr = (end - addr) >> PAGE_SHIFT;
>> +	unsigned int i, step, nr = (end - addr) >> PAGE_SHIFT;
>>  
>>  	WARN_ON(page_shift < PAGE_SHIFT);
>>  
>> @@ -662,7 +662,8 @@ int __vmap_pages_range_noflush(unsigned long addr, unsigned long end,
>>  			page_shift == PAGE_SHIFT)
>>  		return vmap_small_pages_range_noflush(addr, end, prot, pages);
>>  
>> -	for (i = 0; i < nr; i += 1U << (page_shift - PAGE_SHIFT)) {
>> +	step = 1U << (page_shift - PAGE_SHIFT);
>> +	for (i = 0; i < ALIGN_DOWN(nr, step); i += step) {
>>  		int err;
>>  
>>  		err = vmap_range_noflush(addr, addr + (1UL << page_shift),
>> @@ -673,8 +674,9 @@ int __vmap_pages_range_noflush(unsigned long addr, unsigned long end,
>>  
>>  		addr += 1UL << page_shift;
>>  	}
>> -
>> -	return 0;
>> +	if (IS_ALIGNED(nr, step))
>> +		return 0;
>> +	return vmap_small_pages_range_noflush(addr, end, prot, pages + i);
>>  }
>>  
> Can we improve the readability?
>
> <snip>
> index 25a4178188ee..14ca019b57af 100644
> --- a/mm/vmalloc.c
> +++ b/mm/vmalloc.c
> @@ -655,6 +655,8 @@ int __vmap_pages_range_noflush(unsigned long addr, unsigned long end,
>                 pgprot_t prot, struct page **pages, unsigned int page_shift)
>  {
>         unsigned int i, step, nr = (end - addr) >> PAGE_SHIFT;
> +       unsigned int nr_aligned;
> +       unsigned long chunk_size;
>
>         WARN_ON(page_shift < PAGE_SHIFT);
>
> @@ -662,20 +664,24 @@ int __vmap_pages_range_noflush(unsigned long addr, unsigned long end,
>                         page_shift == PAGE_SHIFT)
>                 return vmap_small_pages_range_noflush(addr, end, prot, pages);
>
> -       step = 1U << (page_shift - PAGE_SHIFT);
> -       for (i = 0; i < ALIGN_DOWN(nr, step); i += step) {
> -               int err;
> +       step = 1U << (page_shift - PAGE_SHIFT); /* small pages per huge chunk. */
> +       nr_aligned = ALIGN_DOWN(nr, step);
> +       chunk_size = 1UL << page_shift;
>
> -               err = vmap_range_noflush(addr, addr + (1UL << page_shift),
> +       for (i = 0; i < nr_aligned; i += step) {
> +               int err = vmap_range_noflush(addr, addr + chunk_size,
>                                         page_to_phys(pages[i]), prot,
>                                         page_shift);
>                 if (err)
>                         return err;
>
> -               addr += 1UL << page_shift;
> +               addr += chunk_size;
>         }
> -       if (IS_ALIGNED(nr, step))
> +
> +       if (i == nr)
>                 return 0;
> +
> +       /* Map the tail using small pages. */
>         return vmap_small_pages_range_noflush(addr, end, prot, pages + i);
>  }
> <snip>

Indeed I can do this.

>
>>  int vmap_pages_range_noflush(unsigned long addr, unsigned long end,
>> @@ -3197,7 +3199,7 @@ struct vm_struct *__get_vm_area_node(unsigned long size,
>>  	unsigned long requested_size = size;
>>  
>>  	BUG_ON(in_interrupt());
>> -	size = ALIGN(size, 1ul << shift);
>> +	size = PAGE_ALIGN(size);
>>  	if (unlikely(!size))
>>  		return NULL;
>>  
>> @@ -3353,7 +3355,7 @@ static void vm_reset_perms(struct vm_struct *area)
>>  	 * Find the start and end range of the direct mappings to make sure that
>>  	 * the vm_unmap_aliases() flush includes the direct map.
>>  	 */
>> -	for (i = 0; i < area->nr_pages; i += 1U << page_order) {
>> +	for (i = 0; i < ALIGN_DOWN(area->nr_pages, 1U << page_order); i += (1U << page_order)) {
>>
> nr_blocks?
>
>>  		unsigned long addr = (unsigned long)page_address(area->pages[i]);
>>  
>>  		if (addr) {
>> @@ -3365,6 +3367,18 @@ static void vm_reset_perms(struct vm_struct *area)
>>  			flush_dmap = 1;
>>  		}
>>  	}
>> +	for (; i < area->nr_pages; ++i) {
>> +		unsigned long addr = (unsigned long)page_address(area->pages[i]);
>> +
>> +		if (addr) {
>> +			unsigned long page_size;
>> +
>> +			page_size = PAGE_SIZE;
>> +			start = min(addr, start);
>> +			end = max(addr + page_size, end);
>> +			flush_dmap = 1;
>> +		}
>> +	}
>>  
>>  	/*
>>  	 * Set direct map to something invalid so that it won't be cached if
>> @@ -3673,6 +3687,7 @@ vm_area_alloc_pages(gfp_t gfp, int nid,
>>  	 * more permissive.
>>  	 */
>>  	if (!order) {
>> +single_page:
>>  		while (nr_allocated < nr_pages) {
>>  			unsigned int nr, nr_pages_request;
>>  
>> @@ -3704,13 +3719,18 @@ vm_area_alloc_pages(gfp_t gfp, int nid,
>>  			 * If zero or pages were obtained partly,
>>  			 * fallback to a single page allocator.
>>  			 */
>> -			if (nr != nr_pages_request)
>> +			if (nr != nr_pages_request) {
>> +				order = 0;
>>  				break;
>> +			}
>>  		}
>>  	}
>>  
>>  	/* High-order pages or fallback path if "bulk" fails. */
>>  	while (nr_allocated < nr_pages) {
>> +		if (nr_pages - nr_allocated < (1UL << order)) {
>> +			goto single_page;
>> +		}
>>  		if (!(gfp & __GFP_NOFAIL) && fatal_signal_pending(current))
>>  			break;
>>
> Yes, it requires more attention. That "goto single_page" should be
> eliminated, IMO. We should not jump between blocks, logically the
> single_page belongs to "order-0 alloc path".
>
> Probably it requires more refactoring to simplify it.

I can think about refactoring this.

>
>>  
>> @@ -5179,7 +5199,9 @@ static void show_numa_info(struct seq_file *m, struct vm_struct *v,
>>  
>>  	memset(counters, 0, nr_node_ids * sizeof(unsigned int));
>>  
>> -	for (nr = 0; nr < v->nr_pages; nr += step)
>> +	for (nr = 0; nr < ALIGN_DOWN(v->nr_pages, step); nr += step)
>> +		counters[page_to_nid(v->pages[nr])] += step;
>> +	for (; nr < v->nr_pages; ++nr)
>>  		counters[page_to_nid(v->pages[nr])] += step;
>>
> Can we fit it into one loop? Last tail loop continuous adding step?

I don't see any other way.

>
> --
> Uladzislau Rezki


From linux.amoon at gmail.com  Tue Dec 23 21:18:20 2025
From: linux.amoon at gmail.com (Anand Moon)
Date: Wed, 24 Dec 2025 10:48:20 +0530
Subject: [PATCH v2 1/4] PCI: rockchip: limit RK3399 to 2.5 GT/s to prevent damage
In-Reply-To: <eaa9c75ca02a53f8bcc293b8bc73d013e26ec253.1763415706.git.geraldogabriel@gmail.com>
References: <cover.1763415705.git.geraldogabriel@gmail.com> <eaa9c75ca02a53f8bcc293b8bc73d013e26ec253.1763415706.git.geraldogabriel@gmail.com>
Message-ID: <CANAwSgQ726J_vnDKEKd94Kq62kx8ToZzUGysz4r3tNAXvfAbGA@mail.gmail.com>

Hi Geraldo,

On Tue, 18 Nov 2025 at 03:17, Geraldo Nascimento
<geraldogabriel at gmail.com> wrote:
>
> Shawn Lin from Rockchip has reiterated that there may be danger in using
> their PCIe with 5.0 GT/s speeds. Warn the user if they make a DT change
> from the default and drive at 2.5 GT/s only, even if the DT
> max-link-speed property is invalid or inexistent.
>
> This change is corroborated by RK3399 official datasheet [1], which
> says maximum link speed for this platform is 2.5 GT/s.
>
> [1] https://opensource.rock-chips.com/images/d/d7/Rockchip_RK3399_Datasheet_V2.1-20200323.pdf
>
To accurately determine the operating speed, we can leverage the
PCIE_CLIENT_BASIC_STATUS0/1 fields.
This provides a dynamic mechanism to resolve the issue.

[1] https://github.com/torvalds/linux/blob/master/drivers/pci/controller/pcie-rockchip-ep.c#L533-L595

Thanks
-Anand

> Fixes: 956cd99b35a8 ("PCI: rockchip: Separate common code from RC driver")
> Link: https://lore.kernel.org/all/ffd05070-9879-4468-94e3-b88968b4c21b at rock-chips.com/
> Cc: stable at vger.kernel.org
> Reported-by: Dragan Simic <dsimic at manjaro.org>
> Reported-by: Shawn Lin <shawn.lin at rock-chips.com>
> Reviewed-by: Dragan Simic <dsimic at manjaro.org>
> Signed-off-by: Geraldo Nascimento <geraldogabriel at gmail.com>
> ---
>  drivers/pci/controller/pcie-rockchip.c | 10 ++++++++--
>  1 file changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/pci/controller/pcie-rockchip.c b/drivers/pci/controller/pcie-rockchip.c
> index 0f88da378805..992ccf4b139e 100644
> --- a/drivers/pci/controller/pcie-rockchip.c
> +++ b/drivers/pci/controller/pcie-rockchip.c
> @@ -66,8 +66,14 @@ int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip)
>         }
>
>         rockchip->link_gen = of_pci_get_max_link_speed(node);
> -       if (rockchip->link_gen < 0 || rockchip->link_gen > 2)
> -               rockchip->link_gen = 2;
> +       if (rockchip->link_gen < 0 || rockchip->link_gen > 2) {
> +               rockchip->link_gen = 1;
> +               dev_warn(dev, "invalid max-link-speed, set to 2.5 GT/s\n");
> +       }
> +       else if (rockchip->link_gen == 2) {
> +               rockchip->link_gen = 1;
> +               dev_warn(dev, "5.0 GT/s is dangerous, set to 2.5 GT/s\n");
> +       }
>
>         for (i = 0; i < ROCKCHIP_NUM_PM_RSTS; i++)
>                 rockchip->pm_rsts[i].id = rockchip_pci_pm_rsts[i];
> --
> 2.49.0
>
>


From vkoul at kernel.org  Tue Dec 23 21:30:46 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Wed, 24 Dec 2025 11:00:46 +0530
Subject: [PATCH v9 2/2] phy: Add Google Tensor SoC USB PHY driver
In-Reply-To: <CA+zupgxP+_2iRYABhPM1OOJtRdkrcOvrsKH=Sxk45XwsiamzTw@mail.gmail.com>
References: <20251222-phyb4-v9-0-82c0b671b070@google.com>
 <20251222-phyb4-v9-2-82c0b671b070@google.com>
 <aUqhbVFHczpL9qnL@vaman>
 <CA+zupgxP+_2iRYABhPM1OOJtRdkrcOvrsKH=Sxk45XwsiamzTw@mail.gmail.com>
Message-ID: <aUt6hobN9DPUGbpz@vaman>

On 23-12-25, 09:53, Roy Luo wrote:
> On Tue, Dec 23, 2025 at 6:04?AM Vinod Koul <vkoul at kernel.org> wrote:
> >
> > On 22-12-25, 21:31, Roy Luo wrote:

> > > +struct google_usb_phy {
> > > +     struct device *dev;
> > > +     struct regmap *usb_cfg_regmap;
> > > +     unsigned int usb2_cfg_offset;
> > > +     void __iomem *usbdp_top_base;
> > > +     struct google_usb_phy_instance insts[GOOGLE_USB_PHY_NUM];
> >
> > so you have an array for one phy?
> 
> While the current patch only supports usb2, I used an array
> to simplify future support for usb3 and DP. I understand this
> might seem like over-engineering for now, and we could
> certainly wait to implement the array until the second phy
> support is added. I?m happy to move away from array if
> you?d prefer a simpler approach for this iteration.

Rather than do array, allocate mem as probe based on how many phys will
be there and use that. That would be a better approach than static
allocation here

> > > +static int google_usb2_phy_exit(struct phy *_phy)
> > > +{
> > > +     struct google_usb_phy_instance *inst = phy_get_drvdata(_phy);
> > > +     struct google_usb_phy *gphy = to_google_usb_phy(inst);
> > > +     u32 reg;
> > > +
> > > +     dev_dbg(gphy->dev, "exiting usb2 phy\n");
> > > +
> > > +     guard(mutex)(&gphy->phy_mutex);
> > > +
> > > +     regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, &reg);
> > > +     reg &= ~USBCS_USB2PHY_CFG21_PHY_ENABLE;
> > > +     regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, reg);
> > > +
> > > +     reset_control_bulk_assert(inst->num_rsts, inst->rsts);
> > > +     clk_bulk_disable_unprepare(inst->num_clks, inst->clks);
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +static const struct phy_ops google_usb2_phy_ops = {
> > > +     .init           = google_usb2_phy_init,
> > > +     .exit           = google_usb2_phy_exit,
> > > +};
> >
> > Only two ops? I would expect more... No power_on/off or set_mode?
> >
> > --
> > ~Vinod
> 
> No, configuring usb2 phy is pretty straightforward. The hardware
> does not distinguish between "initialized" and "powered on" states,
> it also does not distinguish phy mode.

ok

-- 
~Vinod


From jacky_chou at aspeedtech.com  Tue Dec 23 21:32:00 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Wed, 24 Dec 2025 05:32:00 +0000
Subject: [PATCH v7 4/7] PHY: aspeed: Add ASPEED PCIe PHY driver
In-Reply-To: <aUq3hF7Xfk-f35Nh@vaman>
References: <20251216-upstream_pcie_rc-v7-0-4aeb0f53c4ce@aspeedtech.com>
 <20251216-upstream_pcie_rc-v7-4-4aeb0f53c4ce@aspeedtech.com>
 <aUq3hF7Xfk-f35Nh@vaman>
Message-ID: <SEYPR06MB51340F64E40B19975A2FD9D79DB2A@SEYPR06MB5134.apcprd06.prod.outlook.com>

Hi Vinod,

Thank you for your reply.

> > Introduce support for Aspeed PCIe PHY controller available in
> > AST2600/2700.
> 
> What is with the uppercase "PHY" in patch title instead of lowercase 'phy' as is
> the convention
> 

Got it. I will change the title to lowercase 'phy' in next version.

> > +++ b/drivers/phy/aspeed/Kconfig
> > @@ -0,0 +1,15 @@
> > +# SPDX-License-Identifier: GPL-2.0-only # # Phy drivers for Aspeed
> > +platforms # config PHY_ASPEED_PCIE
> > +	tristate "ASPEED PCIe PHY driver"
> > +	select GENERIC_PHY
> > +	depends on ARCH_ASPEED
> > +	default y
> 
> NO! why should this driver be default!
> 

Agreed - this should not be default.
I'll remove `default y` in the next revision.

> > +	help
> > +	  This option enables support for the ASPEED PCIe PHY driver.
> > +	  The driver provides the necessary interface to control and
> > +	  configure the PCIe PHY hardware found on ASPEED SoCs.
> > +	  It is required for proper operation of PCIe devices on
> > +	  platforms using ASPEED chips.
> > \ No newline at end of file
> 
> ??
> 

I'll add the missing newline at end of file in the next revision.

> > diff --git a/drivers/phy/aspeed/Makefile b/drivers/phy/aspeed/Makefile
> > new file mode 100644 index 000000000000..7203152f44bf
> > --- /dev/null
> > +++ b/drivers/phy/aspeed/Makefile
> > @@ -0,0 +1,2 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +obj-$(CONFIG_PHY_ASPEED_PCIE)		+= phy-aspeed-pcie.o
> > \ No newline at end of file
> 
> Are we expecting more drivers for aspeed, if not move it to drivers/phy/ once
> we have couple of them we can add a directory
> 

Yes, we are expecting more PHY drivers for ASPEED.

This is the first ASPEED PHY driver, and additional ASPEED-specific
PHY drivers will be submitted later, so having a dedicated
drivers/phy/aspeed/ directory is intentional.

> > diff --git a/drivers/phy/aspeed/phy-aspeed-pcie.c
> > b/drivers/phy/aspeed/phy-aspeed-pcie.c
> > new file mode 100644
> > index 000000000000..3de43a86ac17
> > --- /dev/null
> > +++ b/drivers/phy/aspeed/phy-aspeed-pcie.c
> > @@ -0,0 +1,209 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright 2025 Aspeed Technology Inc.
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/clk-provider.h>
> > +#include <linux/delay.h>
> > +#include <linux/err.h>
> > +#include <linux/io.h>
> > +#include <linux/iopoll.h>
> > +#include <linux/kernel.h>
> > +#include <linux/mfd/syscon.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> 
> why do you need this
> 
> > +#include <linux/phy/pcie.h>
> > +#include <linux/phy/phy.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/regmap.h>
> > +#include <linux/regulator/consumer.h> #include <linux/reset.h>
> > +#include <linux/slab.h>
> 
> 
> Do you need all headers here?
> 

Thanks for pointing this out.

I'll confirm which headers are actually required and clean up
the unused includes in the next revision.

Thanks,
Jacky



From Chaotian.Jing at mediatek.com  Tue Dec 23 21:33:42 2025
From: Chaotian.Jing at mediatek.com (=?utf-8?B?Q2hhb3RpYW4gSmluZyAo5LqV5pyd5aSpKQ==?=)
Date: Wed, 24 Dec 2025 05:33:42 +0000
Subject: [PATCH v4 02/25] dt-bindings: ufs: mediatek,ufs: Complete the
 binding
In-Reply-To: <20251218-mt8196-ufs-v4-2-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
	 <20251218-mt8196-ufs-v4-2-ddec7a369dd2@collabora.com>
Message-ID: <e30abc4cbda3d655d9e0ef2beeac1456b93febb5.camel@mediatek.com>

On Thu, 2025-12-18 at 13:54 +0100, Nicolas Frattaroli wrote:
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
> 
> 
> As it stands, the mediatek,ufs.yaml binding is startlingly
> incomplete.
> Its one example, which is the only real "user" of this binding in
> mainline, uses the deprecated freq-table-hz property.
> 
> The resets, of which there are three optional ones, are completely
> absent.
> 
> The clock description for MT8195 is incomplete, as is the one for
> MT8192. It's not known if the one clock binding for MT8183 is even
> correct, but I do not have access to the necessary code and
> documentation to find this out myself.
> 
> The power supply situation is not much better; the binding describes
> one
> required power supply, but it's the UFS card supply, not any of the
> supplies feeding the controller silicon.
> 
> No second example is present in the binding, making verification
> difficult.
> 
> Disallow freq-table-hz and move to operating-points-v2. It's fine to
> break compatibility here, as the binding is currently unused and
> would
> be impossible to correctly use in its current state.
> 
> Add the three resets and the corresponding reset-names property.
> These
> resets appear to be optional, i.e. not required for the functioning
> of
> the device.
> 
> Move the list of clock names out of the if condition, and expand it
> for
> the confirmed clocks I could find by cross-referencing several clock
> drivers. For MT8195, increase the minimum number of clocks to include
> the crypt and rx_symbol ones, as they're internal to the SoC and
> should
> always be present, and should therefore not be omitted.
> 
> MT8192 gets to have at least 3 clocks, as these were the ones I could
> quickly confirm from a glance at various trees. I can't say this was
> an
> exhaustive search though, but it's better than the current situation.
> 
> Properly document all supplies, with which pin name on the SoCs they
> supply. Complete the example with them.
> 
> Also add a MT8195 example to the binding, using supply labels that I
> am
> pretty sure would be the right ones for e.g. the Radxa NIO 12L.
> 
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
> ---
>  .../devicetree/bindings/ufs/mediatek,ufs.yaml      | 117
> ++++++++++++++++++---
>  1 file changed, 100 insertions(+), 17 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/ufs/mediatek,ufs.yaml
> b/Documentation/devicetree/bindings/ufs/mediatek,ufs.yaml
> index 15c347f5e660..e0aef3e5f56b 100644
> --- a/Documentation/devicetree/bindings/ufs/mediatek,ufs.yaml
> +++ b/Documentation/devicetree/bindings/ufs/mediatek,ufs.yaml
> @@ -19,11 +19,28 @@ properties:
> 
>    clocks:
>      minItems: 1
> -    maxItems: 8
> +    maxItems: 13
> 
>    clock-names:
>      minItems: 1
> -    maxItems: 8
> +    items:
> +      - const: ufs
> +      - const: ufs_aes
> +      - const: ufs_tick
> +      - const: unipro_sysclk
> +      - const: unipro_tick
> +      - const: unipro_mp_bclk
> +      - const: ufs_tx_symbol
> +      - const: ufs_mem_sub
> +      - const: crypt_mux
> +      - const: crypt_lp
> +      - const: crypt_perf
> +      - const: ufs_rx_symbol0
> +      - const: ufs_rx_symbol1
> +
> +  operating-points-v2: true
> +
> +  freq-table-hz: false
> 
>    phys:
>      maxItems: 1
> @@ -31,8 +48,36 @@ properties:
>    reg:
>      maxItems: 1
> 
> +  resets:
> +    items:
> +      - description: reset for the UniPro layer
> +      - description: reset for the cryptography engine
> +      - description: reset for the host controller
> +
> +  reset-names:
> +    items:
> +      - const: unipro
> +      - const: crypto
> +      - const: hci
> +
> +  avdd09-supply:
> +    description: Phandle to the 0.9V supply powering the AVDD09_UFS
> pin
> +
> +  avdd12-supply:
> +    description: Phandle to the 1.2V supply powering the AVDD12_UFS
> pin
> +
> +  avdd12-ckbuf-supply:
> +    description: Phandle to the 1.2V supply powering the
> AVDD12_CKBUF_UFS pin
> +
> +  avdd18-supply:
> +    description: Phandle to the 1.8V supply powering the AVDD18_UFS
> pin
> +
>    vcc-supply: true
> 
> +  vccq-supply: true
> +
> +  vccq2-supply: true
> +
>    mediatek,ufs-disable-mcq:
>      $ref: /schemas/types.yaml#/definitions/flag
>      description: The mask to disable MCQ (Multi-Circular Queue) for
> UFS host.
> @@ -54,29 +99,41 @@ allOf:
>        properties:
>          compatible:
>            contains:
> -            enum:
> -              - mediatek,mt8195-ufshci
> +            const: mediatek,mt8183-ufshci
>      then:
>        properties:
>          clocks:
> -          minItems: 8
> +          maxItems: 1
>          clock-names:
>            items:
>              - const: ufs
> -            - const: ufs_aes
> -            - const: ufs_tick
> -            - const: unipro_sysclk
> -            - const: unipro_tick
> -            - const: unipro_mp_bclk
> -            - const: ufs_tx_symbol
> -            - const: ufs_mem_sub
> -    else:
> +        avdd12-ckbuf-supply: false
> +  - if:
> +      properties:
> +        compatible:
> +          contains:
> +            const: mediatek,mt8192-ufshci
> +    then:
>        properties:
>          clocks:
> -          maxItems: 1
> +          minItems: 3
> +          maxItems: 3
> +        clocks-names:
> +          minItems: 3
> +          maxItems: 3
> +        avdd09-supply: false
> +  - if:
> +      properties:
> +        compatible:
> +          contains:
> +            const: mediatek,mt8195-ufshci
> +    then:
> +      properties:
> +        clocks:
> +          minItems: 13
>          clock-names:
> -          items:
> -            - const: ufs
> +          minItems: 13
> +        avdd09-supply: false
> 
>  examples:
>    - |
> @@ -95,8 +152,34 @@ examples:
> 
>              clocks = <&infracfg_ao CLK_INFRA_UFS>;
>              clock-names = "ufs";
> -            freq-table-hz = <0 0>;
> 
>              vcc-supply = <&mt_pmic_vemc_ldo_reg>;
>          };
>      };
> +  - |
> +    ufshci at 11270000 {
> +        compatible = "mediatek,mt8195-ufshci";
> +        reg = <0x11270000 0x2300>;
> +        interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
> +        phys = <&ufsphy>;
> +        clocks = <&infracfg_ao 63>, <&infracfg_ao 64>, <&infracfg_ao
> 65>,
> +                 <&infracfg_ao 54>, <&infracfg_ao 55>,
> +                 <&infracfg_ao 56>, <&infracfg_ao 90>,
> +                 <&infracfg_ao 93>, <&topckgen 60>, <&topckgen 152>,
> +                 <&topckgen 125>, <&topckgen 212>, <&topckgen 215>;
> +        clock-names = "ufs", "ufs_aes", "ufs_tick",
> +                      "unipro_sysclk", "unipro_tick",
> +                      "unipro_mp_bclk", "ufs_tx_symbol",
> +                      "ufs_mem_sub", "crypt_mux", "crypt_lp",
> +                      "crypt_perf", "ufs_rx_symbol0",
> "ufs_rx_symbol1";
> +
> +        operating-points-v2 = <&ufs_opp_table>;
> +
> +        avdd12-supply = <&mt6359_vrf12_ldo_reg>;
> +        avdd12-ckbuf-supply = <&mt6359_vbbck_ldo_reg>;
> +        avdd18-supply = <&mt6359_vio18_ldo_reg>;
Do not add the avdd12/avdd12-clkbuf/avdd18! these analog power cannot
be power off. even that the system is in suspend state!
> +        vcc-supply = <&mt6359_vemc_1_ldo_reg>;
> +        vccq2-supply = <&mt6359_vufs_ldo_reg>;
> +
> +        mediatek,ufs-disable-mcq;
> +    };
> 
> --
> 2.52.0
> 

From Chaotian.Jing at mediatek.com  Tue Dec 23 21:34:58 2025
From: Chaotian.Jing at mediatek.com (=?utf-8?B?Q2hhb3RpYW4gSmluZyAo5LqV5pyd5aSpKQ==?=)
Date: Wed, 24 Dec 2025 05:34:58 +0000
Subject: [PATCH v4 10/25] scsi: ufs: mediatek: Handle misc host voltage
 regulators
In-Reply-To: <20251218-mt8196-ufs-v4-10-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
	 <20251218-mt8196-ufs-v4-10-ddec7a369dd2@collabora.com>
Message-ID: <1671b55e55a61af655bbab7c1de264eb70383fc4.camel@mediatek.com>

On Thu, 2025-12-18 at 13:55 +0100, Nicolas Frattaroli wrote:
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
> 
> 
> MediaTek SoCs handled by this driver contain a per-SoC specific set
> of
> miscellaneous supplies. These feed parts of the UFS controller
> silicon
> inside the SoC, as opposed to the UFS card.
> 
> Add the necessary driver code to acquire these supplies using the
> regulator bulk API, and disable/enable them during suspend/resume.
> 
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
> ---
>  drivers/ufs/host/ufs-mediatek.c | 61
> ++++++++++++++++++++++++++++++++++++++---
>  drivers/ufs/host/ufs-mediatek.h |  2 ++
>  2 files changed, 59 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-
> mediatek.c
> index 9c0ac72d6e43..10d6b69e91a5 100644
> --- a/drivers/ufs/host/ufs-mediatek.c
> +++ b/drivers/ufs/host/ufs-mediatek.c
> @@ -40,6 +40,8 @@ static void _ufs_mtk_clk_scale(struct ufs_hba *hba,
> bool scale_up);
> 
>  struct ufs_mtk_soc_data {
>         bool has_avdd09;
> +       u8 num_reg_names;
> +       const char *const *reg_names;
>  };
> 
>  static const struct ufs_dev_quirk ufs_mtk_dev_fixups[] = {
> @@ -1190,8 +1192,37 @@ static int ufs_mtk_get_supplies(struct
> ufs_mtk_host *host)
>  {
>         struct device *dev = host->hba->dev;
>         const struct ufs_mtk_soc_data *data =
> of_device_get_match_data(dev);
> +       int ret;
> 
> -       if (!data || !data->has_avdd09)
> +       if (!data)
> +               return 0;
> +
> +       if (data->num_reg_names) {
> +               host->reg_misc = devm_kcalloc(dev, data-
> >num_reg_names,
> +                                             sizeof(*host-
> >reg_misc), GFP_KERNEL);
> +               if (!host->reg_misc)
> +                       return -ENOMEM;
> +
> +               regulator_bulk_set_supply_names(host->reg_misc, data-
> >reg_names,
> +                                               data->num_reg_names);
> +
> +               ret = devm_regulator_bulk_get(dev, data-
> >num_reg_names, host->reg_misc);
> +               if (ret) {
> +                       dev_err(dev, "Failed to get misc regulators:
> %pe\n", ERR_PTR(ret));
> +                       return ret;
> +               }
> +
> +               host->num_reg_misc = data->num_reg_names;
> +
> +               ret = regulator_bulk_enable(host->num_reg_misc, host-
> >reg_misc);
> +               if (ret) {
> +                       dev_err(dev, "Failed to turn on misc
> regulators: %pe\n",
> +                               ERR_PTR(ret));
> +                       return ret;
> +               }
> +       }
> +
> +       if (!data->has_avdd09)
>                 return 0;
> 
>         host->reg_avdd09 = devm_regulator_get_optional(dev,
> "avdd09");
> @@ -1833,7 +1864,9 @@ static int ufs_mtk_suspend(struct ufs_hba *hba,
> enum ufs_pm_op pm_op,
>                 _ufs_mtk_clk_scale(hba, false);
>         }
> 
> -       return 0;
> +       err = regulator_bulk_disable(host->num_reg_misc, host-
> >reg_misc);
> +
> +       return err;
>  fail:
>         /*
>          * Set link as off state enforcedly to trigger
> @@ -1850,6 +1883,10 @@ static int ufs_mtk_resume(struct ufs_hba *hba,
> enum ufs_pm_op pm_op)
>         struct arm_smccc_res res;
>         struct ufs_mtk_host *host = ufshcd_get_variant(hba);
> 
> +       err = regulator_bulk_enable(host->num_reg_misc, host-
> >reg_misc);
> +       if (err)
> +               return err;
> +
>         if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL)
>                 ufs_mtk_dev_vreg_set_lpm(hba, false);
> 
> @@ -2333,14 +2370,30 @@ static const struct ufs_hba_variant_ops
> ufs_hba_mtk_vops = {
>         .config_scsi_dev     = ufs_mtk_config_scsi_dev,
>  };
> 
> +static const char *const ufs_mtk_regs_avdd12_avdd18[] = {
> +       "avdd12", "avdd18"
> +};
> +
> +static const char *const ufs_mtk_regs_avdd12_ckbuf_avdd18[] = {
> +       "avdd12", "avdd12-ckbuf", "avdd18"
> +};
> +
>  static const struct ufs_mtk_soc_data mt8183_data = {
>         .has_avdd09 = true,
> +       .reg_names = ufs_mtk_regs_avdd12_avdd18,
> +       .num_reg_names = ARRAY_SIZE(ufs_mtk_regs_avdd12_avdd18),
> +};
> +
> +static const struct ufs_mtk_soc_data mt8192_8195_data = {
> +       .has_avdd09 = false,
> +       .reg_names = ufs_mtk_regs_avdd12_ckbuf_avdd18,
> +       .num_reg_names =
> ARRAY_SIZE(ufs_mtk_regs_avdd12_ckbuf_avdd18),
>  };
These analog power cannot be powered off, even in suspend stage!
> 
>  static const struct of_device_id ufs_mtk_of_match[] = {
>         { .compatible = "mediatek,mt8183-ufshci", .data =
> &mt8183_data },
> -       { .compatible = "mediatek,mt8192-ufshci" },
> -       { .compatible = "mediatek,mt8195-ufshci" },
> +       { .compatible = "mediatek,mt8192-ufshci", .data =
> &mt8192_8195_data },
> +       { .compatible = "mediatek,mt8195-ufshci", .data =
> &mt8192_8195_data },
>         {},
>  };
>  MODULE_DEVICE_TABLE(of, ufs_mtk_of_match);
> diff --git a/drivers/ufs/host/ufs-mediatek.h b/drivers/ufs/host/ufs-
> mediatek.h
> index 24c8941f6b86..cb32fc987864 100644
> --- a/drivers/ufs/host/ufs-mediatek.h
> +++ b/drivers/ufs/host/ufs-mediatek.h
> @@ -176,6 +176,8 @@ struct ufs_mtk_mcq_intr_info {
>  struct ufs_mtk_host {
>         struct phy *mphy;
>         struct regulator *reg_avdd09;
> +       struct regulator_bulk_data *reg_misc;
> +       u8 num_reg_misc;
>         struct reset_control_bulk_data resets[MTK_UFS_NUM_RESETS];
>         struct ufs_hba *hba;
>         struct ufs_mtk_crypt_cfg *crypt;
> 
> --
> 2.52.0
> 

From ryan_chen at aspeedtech.com  Tue Dec 23 21:37:21 2025
From: ryan_chen at aspeedtech.com (Ryan Chen)
Date: Wed, 24 Dec 2025 13:37:21 +0800
Subject: [PATCH v16 0/3] Add support for AST2700 clk driver
Message-ID: <20251224-upstream_clk-v16-0-8c1318f56c3c@aspeedtech.com>

This patch series is add clk driver for AST2700.

AST2700 is the 8th generation of Integrated Remote Management Processor
introduced by ASPEED Technology Inc. Which is Board Management controller
(BMC) SoC family. AST2700 have two SoC connected, one is SoC0, another
is SoC1, it has it's own scu, this driver inlcude SCU0 and SCU1 driver.

Signed-off-by: Ryan Chen <ryan_chen at aspeedtech.com>
---
Changes in v16
- clk/aspeed: move existing ASPEED clk drivers to drivers/clk/aspeed subdirectory
- MAINTAINERS: Add ASPEED clock drivers entry
- Link to v15: https://lore.kernel.org/all/20251010072540.666673-1-ryan_chen at aspeedtech.com/

Changes in v15:
- clk-ast2700.c
- remove #include <linux/of_platform.h>.
- use inline 12MHZ, 24MHZ, 25MHZ, 192MHZ define.
- use clk_hw pointers, index member instead of .fw_name and .name members.
- use module_platform_driver().
- Link to v14: https://lore.kernel.org/all/20250917020539.3690324-1-ryan_chen at aspeedtech.com/

Changes in v14:
- patch (3/3) : remove duplcate Signed-off-by.
-Link to v13: https://lore.kernel.org/all/20250912052231.1944937-1-ryan_chen at aspeedtech.com/

Changes in v13:
- clk-ast2700.c
 - remove unnecessary ().
 - refine ast2700_soc1_configure_i3c_clk to be easy readable.
-Link to v12: https://lore.kernel.org/all/20250708052909.4145983-1-ryan_chen at aspeedtech.com/

Changes in v12:
-fix mistakes commit message Acked-by:Krzysztof Kozlowski
<krzysztof.kozloski at linaro.org> to Acked-by: Krzysztof Kozlowski
<krzysztof.kozlowski at linaro.org>
-Link to v11: https://lore.kernel.org/all/20250707011826.3719229-1-ryan_chen at aspeedtech.com/

Changes in v11:
-update patch(1/3) commit message subject prefix dt-binding: to dt-bindings:
-Link to v10: https://lore.kernel.org/all/20250611073139.636724-1-ryan_chen at aspeedtech.com/

Changes in v10:
-aspeed,ast2700-scu.h:
-add SOC0_CLK_AHBMUX, SOC0_CLK_MPHYSRC, SOC0_CLK_U2PHY_REFCLKSRC,
 SOC1_CLK_I3C.
-clk-ast2700.c
-add #include <linux/auxiliary_bus.h>
-remove #include <soc/aspeed/reset-aspeed.h>
-use devm_auxiliary_device_create replace aspeed_reset_controller_register
-reset-aspeed.c:
-remove aspeed_reset_unregister_adev, aspeed_reset_adev_release,
 aspeed_reset_controller_register.
-compatible name change reset_aspeed.reset0/1 -> clk_ast2700.reset0/1
-remove reset-aspeed.h
-Link to v9: https://lore.kernel.org/all/20250224095506.2047064-1-ryan_chen at aspeedtech.com/

Changes in v9:
-aspeed,ast2700-scu.h: no change.
add more clear commit description.
-clk-ast2700.c:
add inlcude bitfield.h
remove redundant clk_parent_data soc0_mpll_div8/soc0_ahb/uart13clk/
uart14clk/uart15clk/uart16clk/soc1_ahb/d_clk_sels
-Link to v8: https://lore.kernel.org/all/20250210085004.1898895-1-ryan_chen at aspeedtech.com/

Changes in v8:
-aspeed,ast2700-scu.h: remove no use soc0 clock, add new clock
-clk-ast2700.c: remove include <linux/auxiliary_bus.h>,
include <linux/clk-provider.h>, include <linux/of_address.h>
-clk-ast2700.c: add include <linux/mod_devicetable.h>
-clk-ast2700.c: modify include <soc/aspeed/reset-aspeed.h> order before
dt-bindings
-clk-ast2700.c: modify define to be tabbed out space
-clk-ast2700.c: add union struct for each clk type
        union {
                struct ast2700_clk_fixed_factor_data factor;
                struct ast2700_clk_fixed_rate_data rate;
                struct ast2700_clk_gate_data gate;
                struct ast2700_clk_div_data div;
                struct ast2700_clk_pll_data pll;
                struct ast2700_clk_mux_data mux;
        } data;
-clk-ast2700.c: modify clk_data = device_get_match_data(dev);
-clk-ast2700.c: modify builtin_platform_driver_probe to
arch_initcall(clk_ast2700_init)
-clk-ast2700.c: ast2700_clk_hw_register_hpll explain: scu010[4:2],
scu010[4:2] = 010, hpll force 1.8Ghz
scu010[4:2] = 011, hpll force 1.7Ghz
scu010[4:2] = 110, hpll force 1.2Ghz
scu010[4:2] = 111, hpll force 800Mhz
others depend on hpll parameter register setting.
-Link to v7: https://lore.kernel.org/all/20241028053018.2579200-1-ryan_chen at aspeedtech.com/

Changes in v7:
-reset-aspeed.h: fix declare static inline aspeed_reset_controller_register
if the function is not used.
-Link to v6: https://lore.kernel.org/all/20241023090153.1395220-1-ryan_chen at aspeedtech.com/

Changes in v6:
-patch-2: add reset-aspeed.h
-reset-aspeed: add include cleanup.h for guard()
-reset-aspeed: change ids name clk_aspeed to reset_aspeed
-reset-aspeed: move aspeed_reset_controller_register,
aspeed_reset_adev_release, aspeed_reset_unregister_adev from clk-ast2700.c
-reset-aspeed: drop base check, since it check in clk-ast2700.c
-clk-ast2700: sync each gate name from *clk to *clk-gate name.
-clk-ast2700: add CLK_GATE_ASPEED to diff clk_hw_register_gate and
ast2700_clk_hw_register_gate.
-Link to v5: https://lore.kernel.org/all/20241009060521.2971168-1-ryan_chen at aspeedtech.com/

Changes in v5:
-patch-2 Kconfig: add select AUXILIARY_BUS
-reset-aspeed: #define to_aspeed_reset(p) turn into static inline function.
-reset-aspeed: modify spin_lock_irqsave to guard(spinlock_irqsave)
-reset-aspeed: remove unnecessary parentheses.
-clk-ast2700: use <linux/units.h> and refrain from define clk
-Link to v4: https://lore.kernel.org/all/20240923075012.2264573-1-ryan_chen at aspeedtech.com/

Changes in v4:
-yaml: keep size-cells=<1>.
-merge clk,reset dt binding header with yaml the same patch.
-rename clk,reset dt binding header to aspeed,ast2700-scu.h
-reset-aspeed: update tables tabs sapces to consistent spaces.
-reset-aspeed: remove no use dev_set_drvdata.
-clk-ast2700: modify reset_name to const int scu in struct clk_data.
-clk-ast2700: use scu number in clk_data generate reset_name for reset
 driver register.
-clk-ast2700: fix pll number mix up scu0,scu1.
-clk-ast2700: update dt-binding clock include file.
-Link to v3: https://lore.kernel.org/all/20240916091039.3584505-1-ryan_chen at aspeedtech.com/

Changes in v3:
-yaml: v2 missing send yaml patch, v3 add.
-yaml: drop 64bits address example.
-yaml: add discription about soc0 and soc1
-dt-bindings: remove (), *_NUMS, reserved.
-dt-bindings: remove dulipated define number.
-dt-bindings: merge clk and reset to be one patch.
-reset-aspeed: add auxiliary device for reset driver.
-clk-ast2700: modify reset to be auxiliary add.
-clk-ast2700: modify to be platform driver.
-clk-ast2700: modify each clk to const clk array.
-Link to v2: https://lore.kernel.org/all/20240828062740.1614744-1-ryan_chen at aspeedtech.com/

Changes in v2:
-yaml: drop 64bits address example.
-yaml: add discription about soc0 and soc1
-dt-bindings: remove (), *_NUMS, reserved.
-dt-bindings: remove dulipated define number
-clk-ast2700: drop WARN_ON, weird comment.
-Link to v1: https://lore.kernel.org/all/20240808075937.2756733-1-ryan_chen at aspeedtech.com/

---
Ryan Chen (3):
      clk: aspeed: Move the existing ASPEED clk drivers into aspeed subdirectory.
      MAINTAINERS: Add entry for ASPEED clock drivers.
      clk: aspeed: add AST2700 clock driver

 MAINTAINERS                            |    9 +
 drivers/clk/Kconfig                    |   13 +-
 drivers/clk/Makefile                   |    3 +-
 drivers/clk/aspeed/Kconfig             |   21 +
 drivers/clk/aspeed/Makefile            |    4 +
 drivers/clk/{ => aspeed}/clk-aspeed.c  |    0
 drivers/clk/{ => aspeed}/clk-aspeed.h  |    0
 drivers/clk/{ => aspeed}/clk-ast2600.c |    0
 drivers/clk/aspeed/clk-ast2700.c       | 1055 ++++++++++++++++++++++++++++++++
 9 files changed, 1091 insertions(+), 14 deletions(-)
---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20251223-upstream_clk-87649aab18da

Best regards,
-- 
Ryan Chen <ryan_chen at aspeedtech.com>



From ryan_chen at aspeedtech.com  Tue Dec 23 21:37:22 2025
From: ryan_chen at aspeedtech.com (Ryan Chen)
Date: Wed, 24 Dec 2025 13:37:22 +0800
Subject: [PATCH v16 1/3] clk: aspeed: Move the existing ASPEED clk drivers
 into aspeed subdirectory.
In-Reply-To: <20251224-upstream_clk-v16-0-8c1318f56c3c@aspeedtech.com>
References: <20251224-upstream_clk-v16-0-8c1318f56c3c@aspeedtech.com>
Message-ID: <20251224-upstream_clk-v16-1-8c1318f56c3c@aspeedtech.com>

Prepare for long-term maintenance and future additions by introducing a
dedicated drivers/clk/aspeed/ subdirectory for ASPEED clock drivers.

Move the existing ASPEED clock drivers into the new
drivers/clk/aspeed/ subdirectory.

No functional change, file move only.

Signed-off-by: Ryan Chen <ryan_chen at aspeedtech.com>
---
 drivers/clk/Kconfig                    | 13 +------------
 drivers/clk/Makefile                   |  3 +--
 drivers/clk/aspeed/Kconfig             | 13 +++++++++++++
 drivers/clk/aspeed/Makefile            |  3 +++
 drivers/clk/{ => aspeed}/clk-aspeed.c  |  0
 drivers/clk/{ => aspeed}/clk-aspeed.h  |  0
 drivers/clk/{ => aspeed}/clk-ast2600.c |  0
 7 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 3a1611008e48..c46920649c97 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -284,18 +284,6 @@ config COMMON_CLK_LAN966X
 	  LAN966X SoC. GCK generates and supplies clock to various peripherals
 	  within the SoC.
 
-config COMMON_CLK_ASPEED
-	bool "Clock driver for Aspeed BMC SoCs"
-	depends on ARCH_ASPEED || COMPILE_TEST
-	default ARCH_ASPEED
-	select MFD_SYSCON
-	select RESET_CONTROLLER
-	help
-	  This driver supports the SoC clocks on the Aspeed BMC platforms.
-
-	  The G4 and G5 series, including the ast2400 and ast2500, are supported
-	  by this driver.
-
 config COMMON_CLK_S2MPS11
 	tristate "Clock driver for S2MPS1X/S5M8767 MFD"
 	depends on MFD_SEC_CORE || COMPILE_TEST
@@ -513,6 +501,7 @@ config COMMON_CLK_RPMI
 
 source "drivers/clk/actions/Kconfig"
 source "drivers/clk/analogbits/Kconfig"
+source "drivers/clk/aspeed/Kconfig"
 source "drivers/clk/baikal-t1/Kconfig"
 source "drivers/clk/bcm/Kconfig"
 source "drivers/clk/hisilicon/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 61ec08404442..f7bce3951a30 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -62,8 +62,6 @@ obj-$(CONFIG_COMMON_CLK_FIXED_MMIO)	+= clk-fixed-mmio.o
 obj-$(CONFIG_COMMON_CLK_FSL_FLEXSPI)	+= clk-fsl-flexspi.o
 obj-$(CONFIG_COMMON_CLK_FSL_SAI)	+= clk-fsl-sai.o
 obj-$(CONFIG_COMMON_CLK_GEMINI)		+= clk-gemini.o
-obj-$(CONFIG_COMMON_CLK_ASPEED)		+= clk-aspeed.o
-obj-$(CONFIG_MACH_ASPEED_G6)		+= clk-ast2600.o
 obj-$(CONFIG_ARCH_HIGHBANK)		+= clk-highbank.o
 obj-$(CONFIG_CLK_HSDK)			+= clk-hsdk-pll.o
 obj-$(CONFIG_COMMON_CLK_K210)		+= clk-k210.o
@@ -114,6 +112,7 @@ obj-$(CONFIG_COMMON_CLK_XGENE)		+= clk-xgene.o
 # please keep this section sorted lexicographically by directory path name
 obj-y					+= actions/
 obj-y					+= analogbits/
+obj-y					+= aspeed/
 obj-$(CONFIG_COMMON_CLK_AT91)		+= at91/
 obj-$(CONFIG_ARCH_ARTPEC)		+= axis/
 obj-$(CONFIG_ARC_PLAT_AXS10X)		+= axs10x/
diff --git a/drivers/clk/aspeed/Kconfig b/drivers/clk/aspeed/Kconfig
new file mode 100644
index 000000000000..c59b0a1f581c
--- /dev/null
+++ b/drivers/clk/aspeed/Kconfig
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config COMMON_CLK_ASPEED
+        bool "Clock driver for Aspeed BMC SoCs"
+        depends on ARCH_ASPEED || COMPILE_TEST
+        default ARCH_ASPEED
+        select MFD_SYSCON
+        select RESET_CONTROLLER
+        help
+          This driver supports the SoC clocks on the Aspeed BMC platforms.
+
+          The G4 and G5 series, including the ast2400 and ast2500, are supported
+          by this driver.
diff --git a/drivers/clk/aspeed/Makefile b/drivers/clk/aspeed/Makefile
new file mode 100644
index 000000000000..7db136b89b1e
--- /dev/null
+++ b/drivers/clk/aspeed/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_COMMON_CLK_ASPEED)		+= clk-aspeed.o
+obj-$(CONFIG_MACH_ASPEED_G6)		+= clk-ast2600.o
diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/aspeed/clk-aspeed.c
similarity index 100%
rename from drivers/clk/clk-aspeed.c
rename to drivers/clk/aspeed/clk-aspeed.c
diff --git a/drivers/clk/clk-aspeed.h b/drivers/clk/aspeed/clk-aspeed.h
similarity index 100%
rename from drivers/clk/clk-aspeed.h
rename to drivers/clk/aspeed/clk-aspeed.h
diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/aspeed/clk-ast2600.c
similarity index 100%
rename from drivers/clk/clk-ast2600.c
rename to drivers/clk/aspeed/clk-ast2600.c

-- 
2.34.1



From ryan_chen at aspeedtech.com  Tue Dec 23 21:37:23 2025
From: ryan_chen at aspeedtech.com (Ryan Chen)
Date: Wed, 24 Dec 2025 13:37:23 +0800
Subject: [PATCH v16 2/3] MAINTAINERS: Add entry for ASPEED clock drivers.
In-Reply-To: <20251224-upstream_clk-v16-0-8c1318f56c3c@aspeedtech.com>
References: <20251224-upstream_clk-v16-0-8c1318f56c3c@aspeedtech.com>
Message-ID: <20251224-upstream_clk-v16-2-8c1318f56c3c@aspeedtech.com>

Add support entry for ASPEED clock drivers.

Signed-off-by: Ryan Chen <ryan_chen at aspeedtech.com>
---
 MAINTAINERS | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 5b11839cba9d..201ff5d5c31c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3836,6 +3836,15 @@ L:	rust-for-linux at vger.kernel.org
 S:	Maintained
 F:	drivers/net/phy/ax88796b_rust.rs
 
+ARM/ASPEED CLOCK SUPPORT
+M:	Ryan Chen <ryan_chen at aspeedtech.com>
+R:	Joel Stanley <joel at jms.id.au>
+L:	linux-clk at vger.kernel.org
+L:	linux-aspeed at lists.ozlabs.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/mfd/aspeed,ast2x00-scu.yaml
+F:	drivers/clk/aspeed/
+
 ASPEED CRYPTO DRIVER
 M:	Neal Liu <neal_liu at aspeedtech.com>
 L:	linux-aspeed at lists.ozlabs.org (moderated for non-subscribers)

-- 
2.34.1



From ryan_chen at aspeedtech.com  Tue Dec 23 21:37:24 2025
From: ryan_chen at aspeedtech.com (Ryan Chen)
Date: Wed, 24 Dec 2025 13:37:24 +0800
Subject: [PATCH v16 3/3] clk: aspeed: add AST2700 clock driver
In-Reply-To: <20251224-upstream_clk-v16-0-8c1318f56c3c@aspeedtech.com>
References: <20251224-upstream_clk-v16-0-8c1318f56c3c@aspeedtech.com>
Message-ID: <20251224-upstream_clk-v16-3-8c1318f56c3c@aspeedtech.com>

Add AST2700 clock controller driver and also use axiliary
device framework register the reset controller driver.
Due to clock and reset using the same register region.

Signed-off-by: Ryan Chen <ryan_chen at aspeedtech.com>
Reviewed-by: Brian Masney <bmasney at redhat.com>
---
 drivers/clk/aspeed/Kconfig       |    8 +
 drivers/clk/aspeed/Makefile      |    1 +
 drivers/clk/aspeed/clk-ast2700.c | 1055 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 1064 insertions(+)

diff --git a/drivers/clk/aspeed/Kconfig b/drivers/clk/aspeed/Kconfig
index c59b0a1f581c..ef50481c31ff 100644
--- a/drivers/clk/aspeed/Kconfig
+++ b/drivers/clk/aspeed/Kconfig
@@ -11,3 +11,11 @@ config COMMON_CLK_ASPEED
 
           The G4 and G5 series, including the ast2400 and ast2500, are supported
           by this driver.
+
+config COMMON_CLK_AST2700
+        bool "Clock driver for AST2700 SoC"
+        depends on ARCH_ASPEED || COMPILE_TEST
+        help
+          This driver provides support for clock on AST2700 SoC.
+          The driver is responsible for managing the various clocks required
+          by the peripherals and cores within the AST2700.
diff --git a/drivers/clk/aspeed/Makefile b/drivers/clk/aspeed/Makefile
index 7db136b89b1e..eb5d219f738d 100644
--- a/drivers/clk/aspeed/Makefile
+++ b/drivers/clk/aspeed/Makefile
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_COMMON_CLK_ASPEED)		+= clk-aspeed.o
 obj-$(CONFIG_MACH_ASPEED_G6)		+= clk-ast2600.o
+obj-$(CONFIG_COMMON_CLK_AST2700)	+= clk-ast2700.o
diff --git a/drivers/clk/aspeed/clk-ast2700.c b/drivers/clk/aspeed/clk-ast2700.c
new file mode 100644
index 000000000000..bbb2b571eb72
--- /dev/null
+++ b/drivers/clk/aspeed/clk-ast2700.c
@@ -0,0 +1,1055 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2024 ASPEED Technology Inc.
+ * Author: Ryan Chen <ryan_chen at aspeedtech.com>
+ */
+#include <linux/auxiliary_bus.h>
+#include <linux/bitfield.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/units.h>
+
+#include <dt-bindings/clock/aspeed,ast2700-scu.h>
+
+/* SOC0 */
+#define SCU0_HWSTRAP1		0x010
+#define SCU0_CLK_STOP		0x240
+#define SCU0_CLK_SEL1		0x280
+#define SCU0_CLK_SEL2		0x284
+#define GET_USB_REFCLK_DIV(x)	((GENMASK(23, 20) & (x)) >> 20)
+#define UART_DIV13_EN		BIT(30)
+#define SCU0_HPLL_PARAM		0x300
+#define SCU0_DPLL_PARAM		0x308
+#define SCU0_MPLL_PARAM		0x310
+#define SCU0_D0CLK_PARAM	0x320
+#define SCU0_D1CLK_PARAM	0x330
+#define SCU0_CRT0CLK_PARAM	0x340
+#define SCU0_CRT1CLK_PARAM	0x350
+#define SCU0_MPHYCLK_PARAM	0x360
+
+/* SOC1 */
+#define SCU1_REVISION_ID	0x0
+#define REVISION_ID		GENMASK(23, 16)
+#define SCU1_CLK_STOP		0x240
+#define SCU1_CLK_STOP2		0x260
+#define SCU1_CLK_SEL1		0x280
+#define SCU1_CLK_SEL2		0x284
+#define SCU1_CLK_I3C_DIV_MASK	GENMASK(25, 23)
+#define SCU1_CLK_I3C_DIV(n)	((n) - 1)
+#define UXCLK_MASK		GENMASK(1, 0)
+#define HUXCLK_MASK		GENMASK(4, 3)
+#define SCU1_HPLL_PARAM		0x300
+#define SCU1_APLL_PARAM		0x310
+#define SCU1_DPLL_PARAM		0x320
+#define SCU1_UXCLK_CTRL		0x330
+#define SCU1_HUXCLK_CTRL	0x334
+#define SCU1_MAC12_CLK_DLY	0x390
+#define SCU1_MAC12_CLK_DLY_100M	0x394
+#define SCU1_MAC12_CLK_DLY_10M	0x398
+
+enum ast2700_clk_type {
+	CLK_MUX,
+	CLK_PLL,
+	CLK_HPLL,
+	CLK_GATE,
+	CLK_MISC,
+	CLK_FIXED,
+	CLK_DIVIDER,
+	CLK_UART_PLL,
+	CLK_GATE_ASPEED,
+	CLK_FIXED_FACTOR,
+	CLK_FIXED_DISPLAY,
+};
+
+struct ast2700_clk_fixed_factor_data {
+	unsigned int mult;
+	unsigned int div;
+	int parent_id;
+};
+
+struct ast2700_clk_gate_data {
+	int parent_id;
+	u32 flags;
+	u32 reg;
+	u8 bit;
+};
+
+struct ast2700_clk_mux_data {
+	const struct clk_hw **parent_hws;
+	const unsigned int *parent_ids;
+	unsigned int num_parents;
+	u8 bit_shift;
+	u8 bit_width;
+	u32 reg;
+};
+
+struct ast2700_clk_div_data {
+	const struct clk_div_table *div_table;
+	unsigned int parent_id;
+	u8 bit_shift;
+	u8 bit_width;
+	u32 reg;
+};
+
+struct ast2700_clk_pll_data {
+	unsigned int parent_id;
+	u32 reg;
+};
+
+struct ast2700_clk_fixed_rate_data {
+	unsigned long fixed_rate;
+};
+
+struct ast2700_clk_display_fixed_data {
+	u32 reg;
+};
+
+struct ast2700_clk_info {
+	const char *name;
+	u32 id;
+	u32 reg;
+	u32 type;
+	union {
+		struct ast2700_clk_fixed_factor_data factor;
+		struct ast2700_clk_fixed_rate_data rate;
+		struct ast2700_clk_display_fixed_data display_rate;
+		struct ast2700_clk_gate_data gate;
+		struct ast2700_clk_div_data div;
+		struct ast2700_clk_pll_data pll;
+		struct ast2700_clk_mux_data mux;
+	} data;
+};
+
+struct ast2700_clk_data {
+	const struct ast2700_clk_info *clk_info;
+	unsigned int nr_clks;
+	const int scu;
+};
+
+struct ast2700_clk_ctrl {
+	const struct ast2700_clk_data *clk_data;
+	struct device *dev;
+	void __iomem *base;
+	spinlock_t lock; /* clk lock */
+};
+
+static const struct clk_div_table ast2700_rgmii_div_table[] = {
+	{ 0x0, 4 },
+	{ 0x1, 4 },
+	{ 0x2, 6 },
+	{ 0x3, 8 },
+	{ 0x4, 10 },
+	{ 0x5, 12 },
+	{ 0x6, 14 },
+	{ 0x7, 16 },
+	{ 0 }
+};
+
+static const struct clk_div_table ast2700_rmii_div_table[] = {
+	{ 0x0, 8 },
+	{ 0x1, 8 },
+	{ 0x2, 12 },
+	{ 0x3, 16 },
+	{ 0x4, 20 },
+	{ 0x5, 24 },
+	{ 0x6, 28 },
+	{ 0x7, 32 },
+	{ 0 }
+};
+
+static const struct clk_div_table ast2700_clk_div_table[] = {
+	{ 0x0, 2 },
+	{ 0x1, 2 },
+	{ 0x2, 3 },
+	{ 0x3, 4 },
+	{ 0x4, 5 },
+	{ 0x5, 6 },
+	{ 0x6, 7 },
+	{ 0x7, 8 },
+	{ 0 }
+};
+
+static const struct clk_div_table ast2700_clk_div_table2[] = {
+	{ 0x0, 2 },
+	{ 0x1, 4 },
+	{ 0x2, 6 },
+	{ 0x3, 8 },
+	{ 0x4, 10 },
+	{ 0x5, 12 },
+	{ 0x6, 14 },
+	{ 0x7, 16 },
+	{ 0 }
+};
+
+static const struct clk_div_table ast2700_hclk_div_table[] = {
+	{ 0x0, 6 },
+	{ 0x1, 5 },
+	{ 0x2, 4 },
+	{ 0x3, 7 },
+	{ 0 }
+};
+
+static const struct clk_div_table ast2700_clk_uart_div_table[] = {
+	{ 0x0, 1 },
+	{ 0x1, 13 },
+	{ 0 }
+};
+
+/* soc 0 */
+static const unsigned int psp_parent_ids[] = {
+	SCU0_CLK_MPLL,
+	SCU0_CLK_HPLL,
+	SCU0_CLK_HPLL,
+	SCU0_CLK_HPLL,
+	SCU0_CLK_MPLL_DIV2,
+	SCU0_CLK_HPLL_DIV2,
+	SCU0_CLK_HPLL,
+	SCU0_CLK_HPLL
+};
+
+static const struct clk_hw *psp_parent_hws[ARRAY_SIZE(psp_parent_ids)];
+
+static const unsigned int hclk_parent_ids[] = {
+	SCU0_CLK_HPLL,
+	SCU0_CLK_MPLL
+};
+
+static const struct clk_hw *hclk_parent_hws[ARRAY_SIZE(hclk_parent_ids)];
+
+static const unsigned int emmc_parent_ids[] = {
+	SCU0_CLK_MPLL_DIV4,
+	SCU0_CLK_HPLL_DIV4
+};
+
+static const struct clk_hw *emmc_parent_hws[ARRAY_SIZE(emmc_parent_ids)];
+
+static const unsigned int mphy_parent_ids[] = {
+	SCU0_CLK_MPLL,
+	SCU0_CLK_HPLL,
+	SCU0_CLK_DPLL,
+	SCU0_CLK_192M
+};
+
+static const struct clk_hw *mphy_parent_hws[ARRAY_SIZE(mphy_parent_ids)];
+
+static const unsigned int u2phy_parent_ids[] = {
+	SCU0_CLK_MPLL,
+	SCU0_CLK_HPLL
+};
+
+static const struct clk_hw *u2phy_parent_hws[ARRAY_SIZE(u2phy_parent_ids)];
+
+static const unsigned int uart_parent_ids[] = {
+	SCU0_CLK_24M,
+	SCU0_CLK_192M
+};
+
+static const struct clk_hw *uart_parent_hws[ARRAY_SIZE(uart_parent_ids)];
+
+/* soc 1 */
+static const unsigned int uartx_parent_ids[] = {
+	SCU1_CLK_UARTX,
+	SCU1_CLK_HUARTX
+};
+
+static const struct clk_hw *uartx_parent_hws[ARRAY_SIZE(uartx_parent_ids)];
+
+static const unsigned int uxclk_parent_ids[] = {
+	SCU1_CLK_APLL_DIV4,
+	SCU1_CLK_APLL_DIV2,
+	SCU1_CLK_APLL,
+	SCU1_CLK_HPLL
+};
+
+static const struct clk_hw *uxclk_parent_hws[ARRAY_SIZE(uxclk_parent_ids)];
+
+static const unsigned int sdclk_parent_ids[] = {
+	SCU1_CLK_HPLL,
+	SCU1_CLK_APLL
+};
+
+static const struct clk_hw *sdclk_parent_hws[ARRAY_SIZE(sdclk_parent_ids)];
+
+#define FIXED_CLK(_id, _name, _rate) \
+	{ \
+		.id = _id,	\
+		.type = CLK_FIXED, \
+		.name = _name, \
+		.data = { .rate = { .fixed_rate = _rate, } }, \
+	}
+
+#define FIXED_DISPLAY_CLK(_id, _name, _reg) \
+		{ \
+			.id = _id, \
+			.type = CLK_FIXED_DISPLAY, \
+			.name = _name, \
+			.data = { .display_rate = { .reg = _reg } }, \
+		}
+
+#define PLL_CLK(_id, _type, _name, _parent_id, _reg) \
+	{ \
+		.id = _id, \
+		.type = _type, \
+		.name = _name, \
+		.data = { .pll = { \
+			.parent_id = _parent_id, \
+			.reg		= _reg, \
+		} }, \
+	}
+
+#define MUX_CLK(_id, _name, _parent_ids, _num_parents, _parent_hws, _reg, _shift, _width) \
+		{ \
+			.id = _id, \
+			.type = CLK_MUX, \
+			.name = _name, \
+			.data = { \
+				.mux = { \
+					.parent_ids  = _parent_ids, \
+					.parent_hws  = _parent_hws, \
+					.num_parents = _num_parents, \
+					.reg = (_reg), \
+					.bit_shift = _shift, \
+					.bit_width = _width, \
+				}, \
+			}, \
+		}
+
+#define DIVIDER_CLK(_id, _name, _parent_id, _reg, _shift, _width, _div_table) \
+	{ \
+		.id = _id,	\
+		.type = CLK_DIVIDER, \
+		.name = _name, \
+		.data = { \
+			.div = { \
+				.parent_id = _parent_id, \
+				.reg = _reg, \
+				.bit_shift = _shift, \
+				.bit_width = _width, \
+				.div_table = _div_table, \
+			}, \
+		}, \
+	}
+
+#define FIXED_FACTOR_CLK(_id, _name, _parent_id, _mult, _div) \
+	{ \
+		.id = _id,	\
+		.type = CLK_FIXED_FACTOR, \
+		.name = _name, \
+		.data = { .factor = { .parent_id = _parent_id, .mult = _mult, .div = _div, } }, \
+	}
+
+#define GATE_CLK(_id, _type, _name, _parent_id, _reg, _bit, _flags) \
+	{ \
+		.id = _id,	\
+		.type = _type, \
+		.name = _name, \
+		.data = { \
+			.gate = { \
+				.parent_id = _parent_id, \
+				.reg = _reg, \
+				.bit = _bit, \
+				.flags = _flags, \
+			}, \
+		}, \
+	}
+
+static const struct ast2700_clk_info ast2700_scu0_clk_info[] __initconst = {
+	FIXED_CLK(SCU0_CLKIN, "soc0-clkin", 25 * HZ_PER_MHZ),
+	FIXED_CLK(SCU0_CLK_24M, "soc0-clk24Mhz", 24 * HZ_PER_MHZ),
+	FIXED_CLK(SCU0_CLK_192M, "soc0-clk192Mhz", 192 * HZ_PER_MHZ),
+	FIXED_CLK(SCU0_CLK_U2PHY_CLK12M, "u2phy_clk12m", 12 * HZ_PER_MHZ),
+	FIXED_DISPLAY_CLK(SCU0_CLK_D0, "d0clk", SCU0_D0CLK_PARAM),
+	FIXED_DISPLAY_CLK(SCU0_CLK_D1, "d1clk", SCU0_D1CLK_PARAM),
+	FIXED_DISPLAY_CLK(SCU0_CLK_CRT0, "crt0clk", SCU0_CRT0CLK_PARAM),
+	FIXED_DISPLAY_CLK(SCU0_CLK_CRT1, "crt1clk", SCU0_CRT1CLK_PARAM),
+	PLL_CLK(SCU0_CLK_HPLL, CLK_HPLL, "soc0-hpll", SCU0_CLKIN, SCU0_HPLL_PARAM),
+	PLL_CLK(SCU0_CLK_DPLL, CLK_PLL, "soc0-dpll", SCU0_CLKIN, SCU0_DPLL_PARAM),
+	PLL_CLK(SCU0_CLK_MPLL, CLK_PLL, "soc0-mpll", SCU0_CLKIN, SCU0_MPLL_PARAM),
+	FIXED_FACTOR_CLK(SCU0_CLK_HPLL_DIV2, "soc0-hpll_div2", SCU0_CLK_HPLL, 1, 2),
+	FIXED_FACTOR_CLK(SCU0_CLK_HPLL_DIV4, "soc0-hpll_div4", SCU0_CLK_HPLL, 1, 4),
+	FIXED_FACTOR_CLK(SCU0_CLK_MPLL_DIV2, "soc0-mpll_div2", SCU0_CLK_MPLL, 1, 2),
+	FIXED_FACTOR_CLK(SCU0_CLK_MPLL_DIV4, "soc0-mpll_div4", SCU0_CLK_MPLL, 1, 4),
+	FIXED_FACTOR_CLK(SCU0_CLK_MPLL_DIV8, "soc0-mpll_div8", SCU0_CLK_MPLL, 1, 8),
+	FIXED_FACTOR_CLK(SCU0_CLK_AXI1, "axi1clk", SCU0_CLK_MPLL, 1, 4),
+	MUX_CLK(SCU0_CLK_PSP, "pspclk", psp_parent_ids, ARRAY_SIZE(psp_parent_ids),
+		psp_parent_hws, SCU0_HWSTRAP1, 2, 3),
+	FIXED_FACTOR_CLK(SCU0_CLK_AXI0, "axi0clk", SCU0_CLK_PSP, 1, 2),
+	MUX_CLK(SCU0_CLK_AHBMUX, "soc0-ahbmux", hclk_parent_ids, ARRAY_SIZE(hclk_parent_ids),
+		hclk_parent_hws, SCU0_HWSTRAP1, 7, 1),
+	MUX_CLK(SCU0_CLK_EMMCMUX, "emmcsrc-mux", emmc_parent_ids, ARRAY_SIZE(emmc_parent_ids),
+		emmc_parent_hws, SCU0_CLK_SEL1, 11, 1),
+	MUX_CLK(SCU0_CLK_MPHYSRC, "mphysrc", mphy_parent_ids, ARRAY_SIZE(mphy_parent_ids),
+		mphy_parent_hws, SCU0_CLK_SEL2, 18, 2),
+	MUX_CLK(SCU0_CLK_U2PHY_REFCLKSRC, "u2phy_refclksrc", u2phy_parent_ids,
+		ARRAY_SIZE(u2phy_parent_ids), u2phy_parent_hws, SCU0_CLK_SEL2, 23, 1),
+	MUX_CLK(SCU0_CLK_UART, "soc0-uartclk", uart_parent_ids, ARRAY_SIZE(uart_parent_ids),
+		uart_parent_hws, SCU0_CLK_SEL2, 14, 1),
+	PLL_CLK(SCU0_CLK_MPHY, CLK_MISC, "mphyclk", SCU0_CLK_MPHYSRC, SCU0_MPHYCLK_PARAM),
+	PLL_CLK(SCU0_CLK_U2PHY_REFCLK, CLK_MISC, "u2phy_refclk", SCU0_CLK_U2PHY_REFCLKSRC,
+		SCU0_CLK_SEL2),
+	DIVIDER_CLK(SCU0_CLK_AHB, "soc0-ahb", SCU0_CLK_AHBMUX,
+		    SCU0_HWSTRAP1, 5, 2, ast2700_hclk_div_table),
+	DIVIDER_CLK(SCU0_CLK_EMMC, "emmcclk", SCU0_CLK_EMMCMUX,
+		    SCU0_CLK_SEL1, 12, 3, ast2700_clk_div_table2),
+	DIVIDER_CLK(SCU0_CLK_APB, "soc0-apb", SCU0_CLK_AXI0,
+		    SCU0_CLK_SEL1, 23, 3, ast2700_clk_div_table2),
+	DIVIDER_CLK(SCU0_CLK_HPLL_DIV_AHB, "soc0-hpll-ahb", SCU0_CLK_HPLL,
+		    SCU0_HWSTRAP1, 5, 2, ast2700_hclk_div_table),
+	DIVIDER_CLK(SCU0_CLK_MPLL_DIV_AHB, "soc0-mpll-ahb", SCU0_CLK_MPLL,
+		    SCU0_HWSTRAP1, 5, 2, ast2700_hclk_div_table),
+	DIVIDER_CLK(SCU0_CLK_UART4, "uart4clk", SCU0_CLK_UART,
+		    SCU0_CLK_SEL2, 30, 1, ast2700_clk_uart_div_table),
+	GATE_CLK(SCU0_CLK_GATE_MCLK, CLK_GATE_ASPEED, "mclk-gate", SCU0_CLK_MPLL,
+		 SCU0_CLK_STOP, 0, CLK_IS_CRITICAL),
+	GATE_CLK(SCU0_CLK_GATE_ECLK, CLK_GATE_ASPEED, "eclk-gate", -1, SCU0_CLK_STOP, 1, 0),
+	GATE_CLK(SCU0_CLK_GATE_2DCLK, CLK_GATE_ASPEED, "gclk-gate", -1, SCU0_CLK_STOP, 2, 0),
+	GATE_CLK(SCU0_CLK_GATE_VCLK, CLK_GATE_ASPEED, "vclk-gate", -1, SCU0_CLK_STOP, 3, 0),
+	GATE_CLK(SCU0_CLK_GATE_BCLK, CLK_GATE_ASPEED, "bclk-gate", -1,
+		 SCU0_CLK_STOP, 4, CLK_IS_CRITICAL),
+	GATE_CLK(SCU0_CLK_GATE_VGA0CLK,  CLK_GATE_ASPEED, "vga0clk-gate", -1,
+		 SCU0_CLK_STOP, 5, CLK_IS_CRITICAL),
+	GATE_CLK(SCU0_CLK_GATE_REFCLK,  CLK_GATE_ASPEED, "soc0-refclk-gate", SCU0_CLKIN,
+		 SCU0_CLK_STOP, 6, CLK_IS_CRITICAL),
+	GATE_CLK(SCU0_CLK_GATE_PORTBUSB2CLK, CLK_GATE_ASPEED, "portb-usb2clk-gate", -1,
+		 SCU0_CLK_STOP, 7, 0),
+	GATE_CLK(SCU0_CLK_GATE_UHCICLK, CLK_GATE_ASPEED, "uhciclk-gate", -1, SCU0_CLK_STOP, 9, 0),
+	GATE_CLK(SCU0_CLK_GATE_VGA1CLK, CLK_GATE_ASPEED, "vga1clk-gate", -1,
+		 SCU0_CLK_STOP, 10, CLK_IS_CRITICAL),
+	GATE_CLK(SCU0_CLK_GATE_DDRPHYCLK, CLK_GATE_ASPEED, "ddrphy-gate", -1,
+		 SCU0_CLK_STOP, 11, CLK_IS_CRITICAL),
+	GATE_CLK(SCU0_CLK_GATE_E2M0CLK, CLK_GATE_ASPEED, "e2m0clk-gate", -1,
+		 SCU0_CLK_STOP, 12, CLK_IS_CRITICAL),
+	GATE_CLK(SCU0_CLK_GATE_HACCLK, CLK_GATE_ASPEED, "hacclk-gate", -1, SCU0_CLK_STOP, 13, 0),
+	GATE_CLK(SCU0_CLK_GATE_PORTAUSB2CLK, CLK_GATE_ASPEED, "porta-usb2clk-gate", -1,
+		 SCU0_CLK_STOP, 14, 0),
+	GATE_CLK(SCU0_CLK_GATE_UART4CLK, CLK_GATE_ASPEED, "uart4clk-gate", SCU0_CLK_UART4,
+		 SCU0_CLK_STOP, 15, CLK_IS_CRITICAL),
+	GATE_CLK(SCU0_CLK_GATE_SLICLK, CLK_GATE_ASPEED, "soc0-sliclk-gate", -1,
+		 SCU0_CLK_STOP, 16, CLK_IS_CRITICAL),
+	GATE_CLK(SCU0_CLK_GATE_DACCLK, CLK_GATE_ASPEED, "dacclk-gate", -1,
+		 SCU0_CLK_STOP, 17, CLK_IS_CRITICAL),
+	GATE_CLK(SCU0_CLK_GATE_DP, CLK_GATE_ASPEED, "dpclk-gate", -1,
+		 SCU0_CLK_STOP, 18, CLK_IS_CRITICAL),
+	GATE_CLK(SCU0_CLK_GATE_E2M1CLK, CLK_GATE_ASPEED, "e2m1clk-gate", -1,
+		 SCU0_CLK_STOP, 19, CLK_IS_CRITICAL),
+	GATE_CLK(SCU0_CLK_GATE_CRT0CLK, CLK_GATE_ASPEED, "crt0clk-gate", -1,
+		 SCU0_CLK_STOP, 20, 0),
+	GATE_CLK(SCU0_CLK_GATE_CRT1CLK, CLK_GATE_ASPEED, "crt1clk-gate", -1,
+		 SCU0_CLK_STOP, 21, 0),
+	GATE_CLK(SCU0_CLK_GATE_ECDSACLK, CLK_GATE_ASPEED, "eccclk-gate", -1,
+		 SCU0_CLK_STOP, 23, 0),
+	GATE_CLK(SCU0_CLK_GATE_RSACLK, CLK_GATE_ASPEED, "rsaclk-gate", -1,
+		 SCU0_CLK_STOP, 24, 0),
+	GATE_CLK(SCU0_CLK_GATE_RVAS0CLK, CLK_GATE_ASPEED, "rvas0clk-gate", -1,
+		 SCU0_CLK_STOP, 25, 0),
+	GATE_CLK(SCU0_CLK_GATE_UFSCLK, CLK_GATE_ASPEED, "ufsclk-gate", -1,
+		 SCU0_CLK_STOP, 26, 0),
+	GATE_CLK(SCU0_CLK_GATE_EMMCCLK, CLK_GATE_ASPEED, "emmcclk-gate", SCU0_CLK_EMMC,
+		 SCU0_CLK_STOP, 27, 0),
+	GATE_CLK(SCU0_CLK_GATE_RVAS1CLK, CLK_GATE_ASPEED, "rvas1clk-gate", -1,
+		 SCU0_CLK_STOP, 28, 0),
+};
+
+static const struct ast2700_clk_info ast2700_scu1_clk_info[] __initconst = {
+	FIXED_CLK(SCU1_CLKIN, "soc1-clkin", 25 * HZ_PER_MHZ),
+	PLL_CLK(SCU1_CLK_HPLL, CLK_PLL, "soc1-hpll", SCU1_CLKIN, SCU1_HPLL_PARAM),
+	PLL_CLK(SCU1_CLK_APLL, CLK_PLL, "soc1-apll", SCU1_CLKIN, SCU1_APLL_PARAM),
+	PLL_CLK(SCU1_CLK_DPLL, CLK_PLL, "soc1-dpll", SCU1_CLKIN, SCU1_DPLL_PARAM),
+	FIXED_FACTOR_CLK(SCU1_CLK_APLL_DIV2, "soc1-apll_div2", SCU1_CLK_APLL, 1, 2),
+	FIXED_FACTOR_CLK(SCU1_CLK_APLL_DIV4, "soc1-apll_div4", SCU1_CLK_APLL, 1, 4),
+	FIXED_FACTOR_CLK(SCU1_CLK_CAN, "canclk", SCU1_CLK_APLL, 1, 10),
+	DIVIDER_CLK(SCU1_CLK_APB, "soc1-apb", SCU1_CLK_HPLL,
+		    SCU1_CLK_SEL1, 18, 3, ast2700_clk_div_table2),
+	DIVIDER_CLK(SCU1_CLK_RMII, "rmii", SCU1_CLK_HPLL,
+		    SCU1_CLK_SEL1, 21, 3, ast2700_rmii_div_table),
+	DIVIDER_CLK(SCU1_CLK_RGMII, "rgmii", SCU1_CLK_HPLL,
+		    SCU1_CLK_SEL1, 25, 3, ast2700_rgmii_div_table),
+	DIVIDER_CLK(SCU1_CLK_MACHCLK, "machclk", SCU1_CLK_HPLL,
+		    SCU1_CLK_SEL1, 29, 3, ast2700_clk_div_table),
+	DIVIDER_CLK(SCU1_CLK_APLL_DIVN, "soc1-apll_divn",
+		    SCU1_CLK_APLL, SCU1_CLK_SEL2, 8, 3, ast2700_clk_div_table),
+	DIVIDER_CLK(SCU1_CLK_AHB, "soc1-ahb", SCU1_CLK_HPLL,
+		    SCU1_CLK_SEL2, 20, 3, ast2700_clk_div_table),
+	DIVIDER_CLK(SCU1_CLK_I3C, "soc1-i3c", SCU1_CLK_HPLL,
+		    SCU1_CLK_SEL2, 23, 3, ast2700_clk_div_table),
+	MUX_CLK(SCU1_CLK_SDMUX, "sdclk-mux", sdclk_parent_ids, ARRAY_SIZE(sdclk_parent_ids),
+		sdclk_parent_hws, SCU1_CLK_SEL1, 13, 1),
+	MUX_CLK(SCU1_CLK_UXCLK, "uxclk", uxclk_parent_ids, ARRAY_SIZE(uxclk_parent_ids),
+		uxclk_parent_hws, SCU1_CLK_SEL2, 0, 2),
+	MUX_CLK(SCU1_CLK_HUXCLK, "huxclk", uxclk_parent_ids, ARRAY_SIZE(uxclk_parent_ids),
+		uxclk_parent_hws, SCU1_CLK_SEL2, 3, 2),
+	DIVIDER_CLK(SCU1_CLK_SDCLK, "sdclk", SCU1_CLK_SDMUX,
+		    SCU1_CLK_SEL1, 14, 3, ast2700_clk_div_table),
+	PLL_CLK(SCU1_CLK_UARTX, CLK_UART_PLL, "uartxclk", SCU1_CLK_UXCLK, SCU1_UXCLK_CTRL),
+	PLL_CLK(SCU1_CLK_HUARTX, CLK_UART_PLL, "huartxclk", SCU1_CLK_HUXCLK, SCU1_HUXCLK_CTRL),
+	MUX_CLK(SCU1_CLK_UART0, "uart0clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids),
+		uartx_parent_hws, SCU1_CLK_SEL1, 0, 1),
+	MUX_CLK(SCU1_CLK_UART1, "uart1clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids),
+		uartx_parent_hws, SCU1_CLK_SEL1, 1, 1),
+	MUX_CLK(SCU1_CLK_UART2, "uart2clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids),
+		uartx_parent_hws, SCU1_CLK_SEL1, 2, 1),
+	MUX_CLK(SCU1_CLK_UART3, "uart3clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids),
+		uartx_parent_hws, SCU1_CLK_SEL1, 3, 1),
+	MUX_CLK(SCU1_CLK_UART5, "uart5clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids),
+		uartx_parent_hws, SCU1_CLK_SEL1, 5, 1),
+	MUX_CLK(SCU1_CLK_UART6, "uart6clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids),
+		uartx_parent_hws, SCU1_CLK_SEL1, 6, 1),
+	MUX_CLK(SCU1_CLK_UART7, "uart7clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids),
+		uartx_parent_hws, SCU1_CLK_SEL1, 7, 1),
+	MUX_CLK(SCU1_CLK_UART8, "uart8clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids),
+		uartx_parent_hws, SCU1_CLK_SEL1, 8, 1),
+	MUX_CLK(SCU1_CLK_UART9, "uart9clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids),
+		uartx_parent_hws, SCU1_CLK_SEL1, 9, 1),
+	MUX_CLK(SCU1_CLK_UART10, "uart10clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids),
+		uartx_parent_hws, SCU1_CLK_SEL1, 10, 1),
+	MUX_CLK(SCU1_CLK_UART11, "uart11clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids),
+		uartx_parent_hws, SCU1_CLK_SEL1, 11, 1),
+	MUX_CLK(SCU1_CLK_UART12, "uart12clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids),
+		uartx_parent_hws, SCU1_CLK_SEL1, 12, 1),
+	FIXED_FACTOR_CLK(SCU1_CLK_UART13, "uart13clk", SCU1_CLK_HUARTX, 1, 1),
+	FIXED_FACTOR_CLK(SCU1_CLK_UART14, "uart14clk", SCU1_CLK_HUARTX, 1, 1),
+	GATE_CLK(SCU1_CLK_MAC0RCLK, CLK_GATE, "mac0rclk-gate", SCU1_CLK_RMII,
+		 SCU1_MAC12_CLK_DLY, 29, 0),
+	GATE_CLK(SCU1_CLK_MAC1RCLK, CLK_GATE, "mac1rclk-gate", SCU1_CLK_RMII,
+		 SCU1_MAC12_CLK_DLY, 30, 0),
+	GATE_CLK(SCU1_CLK_GATE_LCLK0, CLK_GATE_ASPEED, "lclk0-gate", -1,
+		 SCU1_CLK_STOP, 0, CLK_IS_CRITICAL),
+	GATE_CLK(SCU1_CLK_GATE_LCLK1, CLK_GATE_ASPEED, "lclk1-gate", -1,
+		 SCU1_CLK_STOP, 1, CLK_IS_CRITICAL),
+	GATE_CLK(SCU1_CLK_GATE_ESPI0CLK, CLK_GATE_ASPEED, "espi0clk-gate", -1,
+		 SCU1_CLK_STOP, 2, CLK_IS_CRITICAL),
+	GATE_CLK(SCU1_CLK_GATE_ESPI1CLK, CLK_GATE_ASPEED, "espi1clk-gate", -1,
+		 SCU1_CLK_STOP, 3, CLK_IS_CRITICAL),
+	GATE_CLK(SCU1_CLK_GATE_SDCLK, CLK_GATE_ASPEED, "sdclk-gate", SCU1_CLK_SDCLK,
+		 SCU1_CLK_STOP, 4, CLK_IS_CRITICAL),
+	GATE_CLK(SCU1_CLK_GATE_IPEREFCLK, CLK_GATE_ASPEED, "soc1-iperefclk-gate", -1,
+		 SCU1_CLK_STOP, 5, CLK_IS_CRITICAL),
+	GATE_CLK(SCU1_CLK_GATE_REFCLK, CLK_GATE_ASPEED, "soc1-refclk-gate", -1,
+		 SCU1_CLK_STOP, 6, CLK_IS_CRITICAL),
+	GATE_CLK(SCU1_CLK_GATE_LPCHCLK, CLK_GATE_ASPEED, "lpchclk-gate", -1,
+		 SCU1_CLK_STOP, 7, CLK_IS_CRITICAL),
+	GATE_CLK(SCU1_CLK_GATE_MAC0CLK, CLK_GATE_ASPEED, "mac0clk-gate", -1,
+		 SCU1_CLK_STOP, 8, 0),
+	GATE_CLK(SCU1_CLK_GATE_MAC1CLK, CLK_GATE_ASPEED, "mac1clk-gate", -1,
+		 SCU1_CLK_STOP, 9, 0),
+	GATE_CLK(SCU1_CLK_GATE_MAC2CLK, CLK_GATE_ASPEED, "mac2clk-gate", -1,
+		 SCU1_CLK_STOP, 10, 0),
+	GATE_CLK(SCU1_CLK_GATE_UART0CLK, CLK_GATE_ASPEED, "uart0clk-gate", SCU1_CLK_UART0,
+		 SCU1_CLK_STOP, 11, CLK_IS_CRITICAL),
+	GATE_CLK(SCU1_CLK_GATE_UART1CLK, CLK_GATE_ASPEED, "uart1clk-gate", SCU1_CLK_UART1,
+		 SCU1_CLK_STOP, 12, CLK_IS_CRITICAL),
+	GATE_CLK(SCU1_CLK_GATE_UART2CLK, CLK_GATE_ASPEED, "uart2clk-gate", SCU1_CLK_UART2,
+		 SCU1_CLK_STOP, 13, CLK_IS_CRITICAL),
+	GATE_CLK(SCU1_CLK_GATE_UART3CLK, CLK_GATE_ASPEED, "uart3clk-gate", SCU1_CLK_UART3,
+		 SCU1_CLK_STOP, 14, CLK_IS_CRITICAL),
+	GATE_CLK(SCU1_CLK_GATE_I2CCLK, CLK_GATE_ASPEED, "i2cclk-gate", -1, SCU1_CLK_STOP, 15, 0),
+	GATE_CLK(SCU1_CLK_GATE_I3C0CLK, CLK_GATE_ASPEED, "i3c0clk-gate", SCU1_CLK_I3C,
+		 SCU1_CLK_STOP, 16, 0),
+	GATE_CLK(SCU1_CLK_GATE_I3C1CLK, CLK_GATE_ASPEED, "i3c1clk-gate", SCU1_CLK_I3C,
+		 SCU1_CLK_STOP, 17, 0),
+	GATE_CLK(SCU1_CLK_GATE_I3C2CLK, CLK_GATE_ASPEED, "i3c2clk-gate", SCU1_CLK_I3C,
+		 SCU1_CLK_STOP, 18, 0),
+	GATE_CLK(SCU1_CLK_GATE_I3C3CLK, CLK_GATE_ASPEED, "i3c3clk-gate", SCU1_CLK_I3C,
+		 SCU1_CLK_STOP, 19, 0),
+	GATE_CLK(SCU1_CLK_GATE_I3C4CLK, CLK_GATE_ASPEED, "i3c4clk-gate", SCU1_CLK_I3C,
+		 SCU1_CLK_STOP, 20, 0),
+	GATE_CLK(SCU1_CLK_GATE_I3C5CLK, CLK_GATE_ASPEED, "i3c5clk-gate", SCU1_CLK_I3C,
+		 SCU1_CLK_STOP, 21, 0),
+	GATE_CLK(SCU1_CLK_GATE_I3C6CLK, CLK_GATE_ASPEED, "i3c6clk-gate", SCU1_CLK_I3C,
+		 SCU1_CLK_STOP, 22, 0),
+	GATE_CLK(SCU1_CLK_GATE_I3C7CLK, CLK_GATE_ASPEED, "i3c7clk-gate", SCU1_CLK_I3C,
+		 SCU1_CLK_STOP, 23, 0),
+	GATE_CLK(SCU1_CLK_GATE_I3C8CLK, CLK_GATE_ASPEED, "i3c8clk-gate", SCU1_CLK_I3C,
+		 SCU1_CLK_STOP, 24, 0),
+	GATE_CLK(SCU1_CLK_GATE_I3C9CLK, CLK_GATE_ASPEED, "i3c9clk-gate", SCU1_CLK_I3C,
+		 SCU1_CLK_STOP, 25, 0),
+	GATE_CLK(SCU1_CLK_GATE_I3C10CLK, CLK_GATE_ASPEED, "i3c10clk-gate", SCU1_CLK_I3C,
+		 SCU1_CLK_STOP, 26, 0),
+	GATE_CLK(SCU1_CLK_GATE_I3C11CLK, CLK_GATE_ASPEED, "i3c11clk-gate", SCU1_CLK_I3C,
+		 SCU1_CLK_STOP, 27, 0),
+	GATE_CLK(SCU1_CLK_GATE_I3C12CLK, CLK_GATE_ASPEED, "i3c12clk-gate", SCU1_CLK_I3C,
+		 SCU1_CLK_STOP, 28, 0),
+	GATE_CLK(SCU1_CLK_GATE_I3C13CLK, CLK_GATE_ASPEED, "i3c13clk-gate", SCU1_CLK_I3C,
+		 SCU1_CLK_STOP, 29, 0),
+	GATE_CLK(SCU1_CLK_GATE_I3C14CLK, CLK_GATE_ASPEED, "i3c14clk-gate", SCU1_CLK_I3C,
+		 SCU1_CLK_STOP, 30, 0),
+	GATE_CLK(SCU1_CLK_GATE_I3C15CLK, CLK_GATE_ASPEED, "i3c15clk-gate", SCU1_CLK_I3C,
+		 SCU1_CLK_STOP, 31, 0),
+	GATE_CLK(SCU1_CLK_GATE_UART5CLK, CLK_GATE_ASPEED, "uart5clk-gate", SCU1_CLK_UART5,
+		 SCU1_CLK_STOP2, 0, CLK_IS_CRITICAL),
+	GATE_CLK(SCU1_CLK_GATE_UART6CLK, CLK_GATE_ASPEED, "uart6clk-gate", SCU1_CLK_UART6,
+		 SCU1_CLK_STOP2, 1, CLK_IS_CRITICAL),
+	GATE_CLK(SCU1_CLK_GATE_UART7CLK, CLK_GATE_ASPEED, "uart7clk-gate", SCU1_CLK_UART7,
+		 SCU1_CLK_STOP2, 2, CLK_IS_CRITICAL),
+	GATE_CLK(SCU1_CLK_GATE_UART8CLK, CLK_GATE_ASPEED, "uart8clk-gate", SCU1_CLK_UART8,
+		 SCU1_CLK_STOP2, 3, CLK_IS_CRITICAL),
+	GATE_CLK(SCU1_CLK_GATE_UART9CLK, CLK_GATE_ASPEED, "uart9clk-gate", SCU1_CLK_UART9,
+		 SCU1_CLK_STOP2, 4, 0),
+	GATE_CLK(SCU1_CLK_GATE_UART10CLK, CLK_GATE_ASPEED, "uart10clk-gate", SCU1_CLK_UART10,
+		 SCU1_CLK_STOP2, 5, 0),
+	GATE_CLK(SCU1_CLK_GATE_UART11CLK, CLK_GATE_ASPEED, "uart11clk-gate", SCU1_CLK_UART11,
+		 SCU1_CLK_STOP2, 6, 0),
+	GATE_CLK(SCU1_CLK_GATE_UART12CLK, CLK_GATE_ASPEED, "uart12clk-gate", SCU1_CLK_UART12,
+		 SCU1_CLK_STOP2, 7, 0),
+	GATE_CLK(SCU1_CLK_GATE_FSICLK, CLK_GATE_ASPEED, "fsiclk-gate", -1, SCU1_CLK_STOP2, 8, 0),
+	GATE_CLK(SCU1_CLK_GATE_LTPIPHYCLK, CLK_GATE_ASPEED, "ltpiphyclk-gate", -1,
+		 SCU1_CLK_STOP2, 9, 0),
+	GATE_CLK(SCU1_CLK_GATE_LTPICLK, CLK_GATE_ASPEED, "ltpiclk-gate", -1,
+		 SCU1_CLK_STOP2, 10, 0),
+	GATE_CLK(SCU1_CLK_GATE_VGALCLK, CLK_GATE_ASPEED, "vgalclk-gate", -1,
+		 SCU1_CLK_STOP2, 11, CLK_IS_CRITICAL),
+	GATE_CLK(SCU1_CLK_GATE_UHCICLK, CLK_GATE_ASPEED, "usbuartclk-gate", -1,
+		 SCU1_CLK_STOP2, 12, 0),
+	GATE_CLK(SCU1_CLK_GATE_CANCLK, CLK_GATE_ASPEED, "canclk-gate", SCU1_CLK_CAN,
+		 SCU1_CLK_STOP2, 13, 0),
+	GATE_CLK(SCU1_CLK_GATE_PCICLK, CLK_GATE_ASPEED, "pciclk-gate", -1,
+		 SCU1_CLK_STOP2, 14, 0),
+	GATE_CLK(SCU1_CLK_GATE_SLICLK, CLK_GATE_ASPEED, "soc1-sliclk-gate", -1,
+		 SCU1_CLK_STOP2, 15, CLK_IS_CRITICAL),
+	GATE_CLK(SCU1_CLK_GATE_E2MCLK, CLK_GATE_ASPEED, "soc1-e2m-gate", -1,
+		 SCU1_CLK_STOP2, 16, CLK_IS_CRITICAL),
+	GATE_CLK(SCU1_CLK_GATE_PORTCUSB2CLK, CLK_GATE_ASPEED, "portcusb2-gate", -1,
+		 SCU1_CLK_STOP2, 17, 0),
+	GATE_CLK(SCU1_CLK_GATE_PORTDUSB2CLK, CLK_GATE_ASPEED, "portdusb2-gate", -1,
+		 SCU1_CLK_STOP2, 18, 0),
+	GATE_CLK(SCU1_CLK_GATE_LTPI1TXCLK, CLK_GATE_ASPEED, "ltp1tx-gate", -1,
+		 SCU1_CLK_STOP2, 19, 0),
+};
+
+static struct clk_hw *ast2700_clk_hw_register_fixed_display(void __iomem *reg, const char *name,
+							    struct ast2700_clk_ctrl *clk_ctrl)
+{
+	unsigned int mult, div, r, n;
+	u32 xdclk;
+	u32 val;
+
+	val = readl(clk_ctrl->base + SCU0_CLK_SEL2);
+	if (val & BIT(29))
+		xdclk = 800 * HZ_PER_MHZ;
+	else
+		xdclk = 1000 * HZ_PER_MHZ;
+
+	val = readl(reg);
+	r = val & GENMASK(15, 0);
+	n = (val >> 16) & GENMASK(15, 0);
+	mult = r;
+	div = 2 * n;
+
+	return devm_clk_hw_register_fixed_rate(clk_ctrl->dev, name, NULL, 0, (xdclk * mult) / div);
+}
+
+static struct clk_hw *ast2700_clk_hw_register_hpll(void __iomem *reg,
+						   const char *name, const struct clk_hw *parent_hw,
+						   struct ast2700_clk_ctrl *clk_ctrl)
+{
+	unsigned int mult, div;
+	u32 val;
+
+	val = readl(clk_ctrl->base + SCU0_HWSTRAP1);
+	if ((readl(clk_ctrl->base) & REVISION_ID) && (val & BIT(3))) {
+		switch ((val & GENMASK(4, 2)) >> 2) {
+		case 2:
+			return devm_clk_hw_register_fixed_rate(clk_ctrl->dev, name, NULL,
+							       0, 1800 * HZ_PER_MHZ);
+		case 3:
+			return devm_clk_hw_register_fixed_rate(clk_ctrl->dev, name, NULL,
+							       0, 1700 * HZ_PER_MHZ);
+		case 6:
+			return devm_clk_hw_register_fixed_rate(clk_ctrl->dev, name, NULL,
+							       0, 1200 * HZ_PER_MHZ);
+		case 7:
+			return devm_clk_hw_register_fixed_rate(clk_ctrl->dev, name, NULL,
+							       0, 800 * HZ_PER_MHZ);
+		default:
+			return ERR_PTR(-EINVAL);
+		}
+	} else if ((val & GENMASK(3, 2)) != 0) {
+		switch ((val & GENMASK(3, 2)) >> 2) {
+		case 1:
+			return devm_clk_hw_register_fixed_rate(clk_ctrl->dev, name, NULL,
+							       0, 1900 * HZ_PER_MHZ);
+		case 2:
+			return devm_clk_hw_register_fixed_rate(clk_ctrl->dev, name, NULL,
+							       0, 1800 * HZ_PER_MHZ);
+		case 3:
+			return devm_clk_hw_register_fixed_rate(clk_ctrl->dev, name, NULL,
+							       0, 1700 * HZ_PER_MHZ);
+		default:
+			return ERR_PTR(-EINVAL);
+		}
+	} else {
+		val = readl(reg);
+
+		if (val & BIT(24)) {
+			/* Pass through mode */
+			mult = 1;
+			div = 1;
+		} else {
+			u32 m = val & 0x1fff;
+			u32 n = (val >> 13) & 0x3f;
+			u32 p = (val >> 19) & 0xf;
+
+			mult = (m + 1) / (2 * (n + 1));
+			div = p + 1;
+		}
+	}
+
+	return devm_clk_hw_register_fixed_factor_parent_hw(clk_ctrl->dev, name,
+							   parent_hw, 0, mult, div);
+}
+
+static struct clk_hw *ast2700_clk_hw_register_pll(int clk_idx, void __iomem *reg,
+						  const char *name, const struct clk_hw *parent_hw,
+						  struct ast2700_clk_ctrl *clk_ctrl)
+{
+	int scu = clk_ctrl->clk_data->scu;
+	unsigned int mult, div;
+	u32 val = readl(reg);
+
+	if (val & BIT(24)) {
+		/* Pass through mode */
+		mult = 1;
+		div = 1;
+	} else {
+		u32 m = val & 0x1fff;
+		u32 n = (val >> 13) & 0x3f;
+		u32 p = (val >> 19) & 0xf;
+
+		if (scu) {
+			mult = (m + 1) / (n + 1);
+			div = p + 1;
+		} else {
+			if (clk_idx == SCU0_CLK_MPLL) {
+				mult = m / (n + 1);
+				div = p + 1;
+			} else {
+				mult = (m + 1) / (2 * (n + 1));
+				div = p + 1;
+			}
+		}
+	}
+
+	return devm_clk_hw_register_fixed_factor_parent_hw(clk_ctrl->dev, name,
+							   parent_hw, 0, mult, div);
+}
+
+static struct clk_hw *ast2700_clk_hw_register_uartpll(void __iomem *reg, const char *name,
+						      const struct clk_hw *parent_hw,
+						      struct ast2700_clk_ctrl *clk_ctrl)
+{
+	unsigned int mult, div;
+	u32 val = readl(reg);
+	u32 r = val & 0xff;
+	u32 n = (val >> 8) & 0x3ff;
+
+	mult = r;
+	div = n * 2;
+
+	return devm_clk_hw_register_fixed_factor_parent_hw(clk_ctrl->dev, name,
+							   parent_hw, 0, mult, div);
+}
+
+static struct clk_hw *ast2700_clk_hw_register_misc(int clk_idx, void __iomem *reg,
+						   const char *name, const struct clk_hw *parent_hw,
+						   struct ast2700_clk_ctrl *clk_ctrl)
+{
+	u32 div = 0;
+
+	if (clk_idx == SCU0_CLK_MPHY) {
+		div = readl(reg) + 1;
+	} else if (clk_idx == SCU0_CLK_U2PHY_REFCLK) {
+		if (readl(clk_ctrl->base) & REVISION_ID)
+			div = (GET_USB_REFCLK_DIV(readl(reg)) + 1) << 4;
+		else
+			div = (GET_USB_REFCLK_DIV(readl(reg)) + 1) << 1;
+	} else {
+		return ERR_PTR(-EINVAL);
+	}
+
+	return devm_clk_hw_register_fixed_factor_parent_hw(clk_ctrl->dev, name,
+							   parent_hw, 0, 1, div);
+}
+
+static int ast2700_clk_is_enabled(struct clk_hw *hw)
+{
+	struct clk_gate *gate = to_clk_gate(hw);
+	u32 clk = BIT(gate->bit_idx);
+	u32 reg;
+
+	reg = readl(gate->reg);
+
+	return !(reg & clk);
+}
+
+static int ast2700_clk_enable(struct clk_hw *hw)
+{
+	struct clk_gate *gate = to_clk_gate(hw);
+	u32 clk = BIT(gate->bit_idx);
+
+	if (readl(gate->reg) & clk)
+		writel(clk, gate->reg + 0x04);
+
+	return 0;
+}
+
+static void ast2700_clk_disable(struct clk_hw *hw)
+{
+	struct clk_gate *gate = to_clk_gate(hw);
+	u32 clk = BIT(gate->bit_idx);
+
+	/* Clock is set to enable, so use write to set register */
+	writel(clk, gate->reg);
+}
+
+static const struct clk_ops ast2700_clk_gate_ops = {
+	.enable = ast2700_clk_enable,
+	.disable = ast2700_clk_disable,
+	.is_enabled = ast2700_clk_is_enabled,
+};
+
+static struct clk_hw *ast2700_clk_hw_register_gate(struct device *dev, const char *name,
+						   const struct clk_hw *parent_hw,
+						   void __iomem *reg, u8 clock_idx,
+						   unsigned long flags, spinlock_t *lock)
+{
+	struct clk_init_data init;
+	struct clk_gate *gate;
+	struct clk_hw *hw;
+	int ret = -EINVAL;
+
+	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+	if (!gate)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &ast2700_clk_gate_ops;
+	init.flags = flags;
+	init.parent_names = NULL;
+	init.parent_hws = parent_hw ? &parent_hw : NULL;
+	init.parent_data = NULL;
+	init.num_parents = parent_hw ? 1 : 0;
+
+	gate->reg = reg;
+	gate->bit_idx = clock_idx;
+	gate->flags = 0;
+	gate->lock = lock;
+	gate->hw.init = &init;
+
+	hw = &gate->hw;
+	ret = clk_hw_register(dev, hw);
+	if (ret) {
+		kfree(gate);
+		hw = ERR_PTR(ret);
+	}
+
+	return hw;
+}
+
+static void ast2700_soc1_configure_i3c_clk(struct ast2700_clk_ctrl *clk_ctrl)
+{
+	if (readl(clk_ctrl->base) & REVISION_ID) {
+		u32 val;
+
+		/* I3C 250MHz = HPLL/4 */
+		val = readl(clk_ctrl->base + SCU1_CLK_SEL2) & ~SCU1_CLK_I3C_DIV_MASK;
+		val |= FIELD_PREP(SCU1_CLK_I3C_DIV_MASK, SCU1_CLK_I3C_DIV(4));
+		writel(val, clk_ctrl->base + SCU1_CLK_SEL2);
+	}
+}
+
+static inline const struct clk_hw *get_parent_hw_or_null(struct clk_hw **hws, int idx)
+{
+	if (idx < 0)
+		return NULL;
+	else
+		return hws[idx];
+}
+
+static int ast2700_soc_clk_probe(struct platform_device *pdev)
+{
+	const struct ast2700_clk_data *clk_data;
+	struct clk_hw_onecell_data *clk_hw_data;
+	struct ast2700_clk_ctrl *clk_ctrl;
+	struct device *dev = &pdev->dev;
+	struct auxiliary_device *adev;
+	void __iomem *clk_base;
+	struct clk_hw **hws;
+	char *reset_name;
+	int ret;
+	int i;
+
+	clk_ctrl = devm_kzalloc(dev, sizeof(*clk_ctrl), GFP_KERNEL);
+	if (!clk_ctrl)
+		return -ENOMEM;
+	clk_ctrl->dev = dev;
+	dev_set_drvdata(&pdev->dev, clk_ctrl);
+
+	spin_lock_init(&clk_ctrl->lock);
+
+	clk_base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(clk_base))
+		return PTR_ERR(clk_base);
+
+	clk_ctrl->base = clk_base;
+
+	clk_data = device_get_match_data(dev);
+	if (!clk_data)
+		return -ENODEV;
+
+	clk_ctrl->clk_data = clk_data;
+	reset_name = devm_kasprintf(dev, GFP_KERNEL, "reset%d", clk_data->scu);
+
+	clk_hw_data = devm_kzalloc(dev, struct_size(clk_hw_data, hws, clk_data->nr_clks),
+				   GFP_KERNEL);
+	if (!clk_hw_data)
+		return -ENOMEM;
+
+	clk_hw_data->num = clk_data->nr_clks;
+	hws = clk_hw_data->hws;
+
+	if (clk_data->scu)
+		ast2700_soc1_configure_i3c_clk(clk_ctrl);
+
+	for (i = 0; i < clk_data->nr_clks; i++) {
+		const struct ast2700_clk_info *clk = &clk_data->clk_info[i];
+		const struct clk_hw *phw = NULL;
+		unsigned int id = clk->id;
+		void __iomem *reg = NULL;
+
+		if (id >= clk_hw_data->num || hws[id]) {
+			dev_err(dev, "clk id %u invalid for %s\n", id, clk->name);
+			return -EINVAL;
+		}
+
+		if (clk->type == CLK_FIXED) {
+			const struct ast2700_clk_fixed_rate_data *fixed_rate = &clk->data.rate;
+
+			hws[id] = devm_clk_hw_register_fixed_rate(dev, clk->name, NULL, 0,
+								  fixed_rate->fixed_rate);
+		} else if (clk->type == CLK_FIXED_FACTOR) {
+			const struct ast2700_clk_fixed_factor_data *factor = &clk->data.factor;
+
+			phw = hws[factor->parent_id];
+			hws[id] = devm_clk_hw_register_fixed_factor_parent_hw(dev, clk->name,
+									      phw, 0, factor->mult,
+									      factor->div);
+		} else if (clk->type == CLK_FIXED_DISPLAY) {
+			reg = clk_ctrl->base + clk->data.display_rate.reg;
+
+			hws[id] = ast2700_clk_hw_register_fixed_display(reg, clk->name, clk_ctrl);
+		} else if (clk->type == CLK_HPLL) {
+			const struct ast2700_clk_pll_data *pll = &clk->data.pll;
+
+			reg = clk_ctrl->base + pll->reg;
+			phw = hws[pll->parent_id];
+			hws[id] = ast2700_clk_hw_register_hpll(reg, clk->name, phw, clk_ctrl);
+		} else if (clk->type == CLK_PLL) {
+			const struct ast2700_clk_pll_data *pll = &clk->data.pll;
+
+			reg = clk_ctrl->base + pll->reg;
+			phw = hws[pll->parent_id];
+			hws[id] = ast2700_clk_hw_register_pll(id, reg, clk->name, phw, clk_ctrl);
+		} else if (clk->type == CLK_UART_PLL) {
+			const struct ast2700_clk_pll_data *pll = &clk->data.pll;
+
+			reg = clk_ctrl->base + pll->reg;
+			phw = hws[pll->parent_id];
+			hws[id] = ast2700_clk_hw_register_uartpll(reg, clk->name, phw, clk_ctrl);
+		} else if (clk->type == CLK_MUX) {
+			const struct ast2700_clk_mux_data *mux = &clk->data.mux;
+
+			reg = clk_ctrl->base + mux->reg;
+			for (int j = 0; j < mux->num_parents; j++) {
+				unsigned int pid = mux->parent_ids[j];
+
+				mux->parent_hws[j] = hws[pid];
+			}
+
+			hws[id] = devm_clk_hw_register_mux_parent_hws(dev, clk->name,
+								      mux->parent_hws,
+								      mux->num_parents, 0,
+								      reg, mux->bit_shift,
+								      mux->bit_width, 0,
+								      &clk_ctrl->lock);
+		} else if (clk->type == CLK_MISC) {
+			const struct ast2700_clk_pll_data *pll = &clk->data.pll;
+
+			reg = clk_ctrl->base + pll->reg;
+			phw = hws[pll->parent_id];
+			hws[id] = ast2700_clk_hw_register_misc(id, reg, clk->name, phw, clk_ctrl);
+		} else if (clk->type == CLK_DIVIDER) {
+			const struct ast2700_clk_div_data *divider = &clk->data.div;
+
+			reg = clk_ctrl->base + divider->reg;
+			phw = hws[divider->parent_id];
+			hws[id] = clk_hw_register_divider_table_parent_hw(dev, clk->name,
+									  phw,
+									  0, reg,
+									  divider->bit_shift,
+									  divider->bit_width, 0,
+									  divider->div_table,
+									  &clk_ctrl->lock);
+		} else if (clk->type == CLK_GATE_ASPEED) {
+			const struct ast2700_clk_gate_data *gate = &clk->data.gate;
+
+			phw = get_parent_hw_or_null(hws, gate->parent_id);
+			reg = clk_ctrl->base + gate->reg;
+			hws[id] = ast2700_clk_hw_register_gate(dev, clk->name, phw, reg, gate->bit,
+							       gate->flags, &clk_ctrl->lock);
+		} else {
+			const struct ast2700_clk_gate_data *gate = &clk->data.gate;
+
+			phw = get_parent_hw_or_null(hws, gate->parent_id);
+			reg = clk_ctrl->base + gate->reg;
+			hws[id] = devm_clk_hw_register_gate_parent_hw(dev, clk->name, phw,
+								      gate->flags, reg, gate->bit,
+								      0, &clk_ctrl->lock);
+		}
+
+		if (IS_ERR(hws[id]))
+			return PTR_ERR(hws[id]);
+	}
+
+	ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_hw_data);
+	if (ret)
+		return ret;
+
+	adev = devm_auxiliary_device_create(dev, reset_name, (__force void *)clk_base);
+	if (!adev)
+		return -ENODEV;
+
+	return 0;
+}
+
+static const struct ast2700_clk_data ast2700_clk0_data = {
+	.scu = 0,
+	.nr_clks = ARRAY_SIZE(ast2700_scu0_clk_info),
+	.clk_info = ast2700_scu0_clk_info,
+};
+
+static const struct ast2700_clk_data ast2700_clk1_data = {
+	.scu = 1,
+	.nr_clks = ARRAY_SIZE(ast2700_scu1_clk_info),
+	.clk_info = ast2700_scu1_clk_info,
+};
+
+static const struct of_device_id ast2700_scu_match[] = {
+	{ .compatible = "aspeed,ast2700-scu0", .data = &ast2700_clk0_data },
+	{ .compatible = "aspeed,ast2700-scu1", .data = &ast2700_clk1_data },
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, ast2700_scu_match);
+
+static struct platform_driver ast2700_scu_driver = {
+	.probe = ast2700_soc_clk_probe,
+	.driver = {
+		.name = "clk-ast2700",
+		.of_match_table = ast2700_scu_match,
+	},
+};
+
+module_platform_driver(ast2700_scu_driver);

-- 
2.34.1



From geraldogabriel at gmail.com  Tue Dec 23 21:38:40 2025
From: geraldogabriel at gmail.com (Geraldo Nascimento)
Date: Wed, 24 Dec 2025 02:38:40 -0300
Subject: [PATCH v2 1/4] PCI: rockchip: limit RK3399 to 2.5 GT/s to prevent damage
In-Reply-To: <CANAwSgQ726J_vnDKEKd94Kq62kx8ToZzUGysz4r3tNAXvfAbGA@mail.gmail.com>
References: <cover.1763415705.git.geraldogabriel@gmail.com>
 <eaa9c75ca02a53f8bcc293b8bc73d013e26ec253.1763415706.git.geraldogabriel@gmail.com>
 <CANAwSgQ726J_vnDKEKd94Kq62kx8ToZzUGysz4r3tNAXvfAbGA@mail.gmail.com>
Message-ID: <CAEsQvctSY7-RQEQF2TmJU2qKPZOe9TC5g-7Jat0LQKRHYz_6dQ@mail.gmail.com>

On Wed, Dec 24, 2025 at 2:18?AM Anand Moon <linux.amoon at gmail.com> wrote:
>
> Hi Geraldo,
>
> On Tue, 18 Nov 2025 at 03:17, Geraldo Nascimento
> <geraldogabriel at gmail.com> wrote:
> >
> > Shawn Lin from Rockchip has reiterated that there may be danger in using
> > their PCIe with 5.0 GT/s speeds. Warn the user if they make a DT change
> > from the default and drive at 2.5 GT/s only, even if the DT
> > max-link-speed property is invalid or inexistent.
> >
> > This change is corroborated by RK3399 official datasheet [1], which
> > says maximum link speed for this platform is 2.5 GT/s.
> >
> > [1] https://opensource.rock-chips.com/images/d/d7/Rockchip_RK3399_Datasheet_V2.1-20200323.pdf
> >
> To accurately determine the operating speed, we can leverage the
> PCIE_CLIENT_BASIC_STATUS0/1 fields.
> This provides a dynamic mechanism to resolve the issue.
>
> [1] https://github.com/torvalds/linux/blob/master/drivers/pci/controller/pcie-rockchip-ep.c#L533-L595
>
> Thanks
> -Anand

Hi Anand,

not to put you down but I think your approach adds unnecessary complexity.

All I care really is that the Kernel Project isn't blamed in the
future if someone happens to lose their data.

Thanks,
Geraldo Nascimento


From ryan_chen at aspeedtech.com  Tue Dec 23 21:39:31 2025
From: ryan_chen at aspeedtech.com (Ryan Chen)
Date: Wed, 24 Dec 2025 05:39:31 +0000
Subject: [PATCH v15 3/3] clk: aspeed: add AST2700 clock driver
In-Reply-To: <aUl5DPMq8jC1xjRu@redhat.com>
References: <20251010072540.666673-1-ryan_chen@aspeedtech.com>
 <20251010072540.666673-4-ryan_chen@aspeedtech.com>
 <TY2PPF5CB9A1BE64DCD487138F3BAC4FD34F2FCA@TY2PPF5CB9A1BE6.apcprd06.prod.outlook.com>
 <aUl5DPMq8jC1xjRu@redhat.com>
Message-ID: <TY2PPF5CB9A1BE61BCB26BC17BE7824D429F2B2A@TY2PPF5CB9A1BE6.apcprd06.prod.outlook.com>

> Subject: Re: [PATCH v15 3/3] clk: aspeed: add AST2700 clock driver
> 
> Hi Ryan,
> 
> On Mon, Oct 27, 2025 at 06:24:59AM +0000, Ryan Chen wrote:
> > Hello Stephen,
> > 	Will this be accepted in clk-next?
> 
> Given that aspeed is a SoC vendor, and you already have multiple clk drivers, I
> think at this point your best bet is to do what the other SoC vendors currently
> do. I think you should:
> 
> - Create a new subdirectory drivers/clk/aspeed/
> - Move the existing aspeed clk drivers into this subdirectory, and
>   update the Makefiles / Kconfigs as appropriate.
> - Add a new entry to the MAINTAINERS file for the aspeed clk drivers.
>   You probably also want to have that entry cover the reset driver,
>   and any other aspeed-specific drivers as well.
> - Post that patch set. Include this new clk driver as a separate patch
>   in that series. Feel free to CC me to the series and I'll review it
>   for you.
> - After it's reviewed, wait a week or two, and send Stephen a
>   'GIT PULL' using git request-pull. I can help you with the workflow
>   if needed.
> 
>   One important detail is that you want to base your branch for the GIT
>   PULL on the lowest common denominator, which is usually the latest rc1
>   from Linus. So even if Linus is at rc5, try to base yours on rc1, unless
>   there's some issue, and you need to document why. Stephen should get the
>   merge to newer rcX branches from Linus, and not you.
> 
> When you send a PULL to Stephen, you can use 'b4 am' to assemble the
> contents of your branch. When I sent him a PULL a few months ago, I included
> the b4 commands that I used.
> 
> https://lore.kernel.org/all/aL8MXYrR5uoBa4cB at x1/
> 
> If he accepts the pull, you'll still need to post your patches to the clk mailinglist,
> and have them reviewed on list. Folks from aspeed should do that review
> publicly on the list.
> 
Hello Brian,
	Thanks a lot for your guidance. I send out v16 next.
Ryan



From s-vadapalli at ti.com  Tue Dec 23 21:48:57 2025
From: s-vadapalli at ti.com (Siddharth Vadapalli)
Date: Wed, 24 Dec 2025 11:18:57 +0530
Subject: [PATCH 0/2] Cadence: Torrent: Enable PCIe + XAUI multilink configuration
Message-ID: <20251224054905.763399-1-s-vadapalli@ti.com>

Hello,

This patch series adds the dt-binding for PHY_TYPE_XAUI and adds the
driver support for enabling PCIe + XAUI multilink configuration.

Patch series is based on linux-next tagged next-20251219.

Regards,
Siddharth.

Swapnil Jakhade (2):
  dt-bindings: phy: Add PHY_TYPE_XAUI definition
  phy: cadence-torrent: Add PCIe + XAUI multilink configuration for
    100MHz refclk

 drivers/phy/cadence/phy-cadence-torrent.c | 143 ++++++++++++++++++++--
 include/dt-bindings/phy/phy.h             |   1 +
 2 files changed, 137 insertions(+), 7 deletions(-)

-- 
2.51.1



From s-vadapalli at ti.com  Tue Dec 23 21:48:58 2025
From: s-vadapalli at ti.com (Siddharth Vadapalli)
Date: Wed, 24 Dec 2025 11:18:58 +0530
Subject: [PATCH 1/2] dt-bindings: phy: Add PHY_TYPE_XAUI definition
In-Reply-To: <20251224054905.763399-1-s-vadapalli@ti.com>
References: <20251224054905.763399-1-s-vadapalli@ti.com>
Message-ID: <20251224054905.763399-2-s-vadapalli@ti.com>

From: Swapnil Jakhade <sjakhade at cadence.com>

Add definition for XAUI phy type.

Signed-off-by: Swapnil Jakhade <sjakhade at cadence.com>
Signed-off-by: Siddharth Vadapalli <s-vadapalli at ti.com>
---
 include/dt-bindings/phy/phy.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/dt-bindings/phy/phy.h b/include/dt-bindings/phy/phy.h
index 6b901b342348..d77b372d302f 100644
--- a/include/dt-bindings/phy/phy.h
+++ b/include/dt-bindings/phy/phy.h
@@ -23,5 +23,6 @@
 #define PHY_TYPE_DPHY		10
 #define PHY_TYPE_CPHY		11
 #define PHY_TYPE_USXGMII	12
+#define PHY_TYPE_XAUI		13
 
 #endif /* _DT_BINDINGS_PHY */
-- 
2.51.1



From s-vadapalli at ti.com  Tue Dec 23 21:48:59 2025
From: s-vadapalli at ti.com (Siddharth Vadapalli)
Date: Wed, 24 Dec 2025 11:18:59 +0530
Subject: [PATCH 2/2] phy: cadence-torrent: Add PCIe + XAUI multilink configuration for 100MHz refclk
In-Reply-To: <20251224054905.763399-1-s-vadapalli@ti.com>
References: <20251224054905.763399-1-s-vadapalli@ti.com>
Message-ID: <20251224054905.763399-3-s-vadapalli@ti.com>

From: Swapnil Jakhade <sjakhade at cadence.com>

Add register sequences for PCIe + XAUI multilink configuration for
100MHz reference clock.

Signed-off-by: Swapnil Jakhade <sjakhade at cadence.com>
Signed-off-by: Siddharth Vadapalli <s-vadapalli at ti.com>
---
 drivers/phy/cadence/phy-cadence-torrent.c | 143 ++++++++++++++++++++--
 1 file changed, 136 insertions(+), 7 deletions(-)

diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c
index 37fa4bad6bd7..f0d870886cca 100644
--- a/drivers/phy/cadence/phy-cadence-torrent.c
+++ b/drivers/phy/cadence/phy-cadence-torrent.c
@@ -300,6 +300,7 @@ enum cdns_torrent_phy_type {
 	TYPE_USB,
 	TYPE_USXGMII,
 	TYPE_PCIE_ML,
+	TYPE_XAUI,
 };
 
 enum cdns_torrent_ref_clk {
@@ -320,14 +321,14 @@ enum cdns_torrent_ssc_mode {
 /* Unique key id for vals table entry
  * REFCLK0_RATE | REFCLK1_RATE | LINK0_TYPE | LINK1_TYPE | SSC_TYPE
  */
-#define REFCLK0_SHIFT	12
-#define REFCLK0_MASK	GENMASK(14, 12)
-#define REFCLK1_SHIFT	9
-#define REFCLK1_MASK	GENMASK(11, 9)
-#define LINK0_SHIFT	6
-#define LINK0_MASK	GENMASK(8, 6)
+#define REFCLK0_SHIFT	15
+#define REFCLK0_MASK	GENMASK(18, 15)
+#define REFCLK1_SHIFT	11
+#define REFCLK1_MASK	GENMASK(14, 11)
+#define LINK0_SHIFT	7
+#define LINK0_MASK	GENMASK(10, 7)
 #define LINK1_SHIFT	3
-#define LINK1_MASK	GENMASK(5, 3)
+#define LINK1_MASK	GENMASK(6, 3)
 #define SSC_SHIFT	0
 #define SSC_MASK	GENMASK(2, 0)
 
@@ -708,6 +709,8 @@ static const char *cdns_torrent_get_phy_type(enum cdns_torrent_phy_type phy_type
 		return "USB";
 	case TYPE_USXGMII:
 		return "USXGMII";
+	case TYPE_XAUI:
+		return "XAUI";
 	default:
 		return "None";
 	}
@@ -3020,6 +3023,9 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev)
 		case PHY_TYPE_USXGMII:
 			cdns_phy->phys[node].phy_type = TYPE_USXGMII;
 			break;
+		case PHY_TYPE_XAUI:
+			cdns_phy->phys[node].phy_type = TYPE_XAUI;
+			break;
 		default:
 			dev_err(dev, "Unsupported protocol\n");
 			ret = -EINVAL;
@@ -3382,6 +3388,95 @@ static DEFINE_NOIRQ_DEV_PM_OPS(cdns_torrent_phy_pm_ops,
 			       cdns_torrent_phy_suspend_noirq,
 			       cdns_torrent_phy_resume_noirq);
 
+/* PCIe and XAUI link configuration */
+static const struct cdns_reg_pairs pcie_xaui_link_cmn_regs[] = {
+	{0x0003, PHY_PLL_CFG},
+	{0x0600, CMN_PDIAG_PLL1_CLK_SEL_M0}
+};
+
+static const struct cdns_reg_pairs xaui_pcie_xcvr_diag_ln_regs[] = {
+	{0x0011, XCVR_DIAG_HSCLK_SEL},
+	{0x0089, XCVR_DIAG_PLLDRC_CTRL}
+};
+
+static const struct cdns_torrent_vals pcie_xaui_link_cmn_vals = {
+	.reg_pairs = pcie_xaui_link_cmn_regs,
+	.num_regs = ARRAY_SIZE(pcie_xaui_link_cmn_regs),
+};
+
+static const struct cdns_torrent_vals xaui_pcie_xcvr_diag_ln_vals = {
+	.reg_pairs = xaui_pcie_xcvr_diag_ln_regs,
+	.num_regs = ARRAY_SIZE(xaui_pcie_xcvr_diag_ln_regs),
+};
+
+/* XAUI 100 MHz Ref clk, no SSC */
+static const struct cdns_reg_pairs xaui_100_no_ssc_cmn_regs[] = {
+	{0x0004, CMN_PLL1_DSM_DIAG_M0},
+	{0x0B17, CMN_PDIAG_PLL1_CP_PADJ_M0},
+	{0x0E01, CMN_PDIAG_PLL1_CP_IADJ_M0},
+	{0x0D05, CMN_PDIAG_PLL1_FILT_PADJ_M0},
+	{0x003E, CMN_PLL1_INTDIV_M0},
+	{0x8000, CMN_PLL1_FRACDIVL_M0},
+	{0x0002, CMN_PLL1_FRACDIVH_M0},
+	{0x002A, CMN_PLL1_HIGH_THR_M0},
+	{0x3102, CMN_PDIAG_PLL1_CTRL_M0},
+	{0x007F, CMN_TXPUCAL_TUNE},
+	{0x007F, CMN_TXPDCAL_TUNE}
+};
+
+static const struct cdns_reg_pairs xaui_100_no_ssc_tx_ln_regs[] = {
+	{0x00F3, TX_PSC_A0},
+	{0x04A2, TX_PSC_A2},
+	{0x04A2, TX_PSC_A3 },
+	{0x0000, TX_TXCC_CPOST_MULT_00}
+};
+
+static const struct cdns_reg_pairs ti_xaui_100_no_ssc_tx_ln_regs[] = {
+	{0x00F3, TX_PSC_A0},
+	{0x04A2, TX_PSC_A2},
+	{0x04A2, TX_PSC_A3 },
+	{0x0000, TX_TXCC_CPOST_MULT_00},
+	{0x4000, XCVR_DIAG_RXCLK_CTRL}
+};
+
+static const struct cdns_reg_pairs xaui_100_no_ssc_rx_ln_regs[] = {
+	{0x091D, RX_PSC_A0},
+	{0x0900, RX_PSC_A2},
+	{0x0100, RX_PSC_A3},
+	{0x03C7, RX_REE_GCSM1_EQENM_PH1},
+	{0x01C7, RX_REE_GCSM1_EQENM_PH2},
+	{0x0000, RX_DIAG_DFE_CTRL},
+	{0x0019, RX_REE_TAP1_CLIP},
+	{0x0019, RX_REE_TAP2TON_CLIP},
+	{0x0098, RX_DIAG_NQST_CTRL},
+	{0x0C01, RX_DIAG_DFE_AMP_TUNE_2},
+	{0x0000, RX_DIAG_DFE_AMP_TUNE_3},
+	{0x0000, RX_DIAG_PI_CAP},
+	{0x0031, RX_DIAG_PI_RATE},
+	{0x0001, RX_DIAG_ACYA},
+	{0x018C, RX_CDRLF_CNFG},
+};
+
+static const struct cdns_torrent_vals xaui_100_no_ssc_cmn_vals = {
+	.reg_pairs = xaui_100_no_ssc_cmn_regs,
+	.num_regs = ARRAY_SIZE(xaui_100_no_ssc_cmn_regs),
+};
+
+static const struct cdns_torrent_vals xaui_100_no_ssc_tx_ln_vals = {
+	.reg_pairs = xaui_100_no_ssc_tx_ln_regs,
+	.num_regs = ARRAY_SIZE(xaui_100_no_ssc_tx_ln_regs),
+};
+
+static const struct cdns_torrent_vals ti_xaui_100_no_ssc_tx_ln_vals = {
+	.reg_pairs = ti_xaui_100_no_ssc_tx_ln_regs,
+	.num_regs = ARRAY_SIZE(ti_xaui_100_no_ssc_tx_ln_regs),
+};
+
+static const struct cdns_torrent_vals xaui_100_no_ssc_rx_ln_vals = {
+	.reg_pairs = xaui_100_no_ssc_rx_ln_regs,
+	.num_regs = ARRAY_SIZE(xaui_100_no_ssc_rx_ln_regs),
+};
+
 /* USB and DP link configuration */
 static const struct cdns_reg_pairs usb_dp_link_cmn_regs[] = {
 	{0x0002, PHY_PLL_CFG},
@@ -4853,6 +4948,7 @@ static const struct cdns_torrent_vals_entry link_cmn_vals_entries[] = {
 	{CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_USB), &pcie_usb_link_cmn_vals},
 	{CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_DP), &pcie_dp_link_cmn_vals},
 	{CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_USXGMII), &pcie_usxgmii_link_cmn_vals},
+	{CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_XAUI), &pcie_xaui_link_cmn_vals},
 
 	{CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE_ML, TYPE_USB), &ml_pcie_usb_link_cmn_vals},
 
@@ -4879,6 +4975,8 @@ static const struct cdns_torrent_vals_entry link_cmn_vals_entries[] = {
 	{CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_PCIE), &pcie_usxgmii_link_cmn_vals},
 	{CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_SGMII), &usxgmii_sgmii_link_cmn_vals},
 	{CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_QSGMII), &usxgmii_sgmii_link_cmn_vals},
+
+	{CDNS_TORRENT_KEY_ANYCLK(TYPE_XAUI, TYPE_PCIE), &pcie_xaui_link_cmn_vals},
 };
 
 static const struct cdns_torrent_vals_entry xcvr_diag_vals_entries[] = {
@@ -4893,6 +4991,7 @@ static const struct cdns_torrent_vals_entry xcvr_diag_vals_entries[] = {
 	{CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_USB), &pcie_usb_xcvr_diag_ln_vals},
 	{CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_DP), &pcie_dp_xcvr_diag_ln_vals},
 	{CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_USXGMII), &pcie_usxgmii_xcvr_diag_ln_vals},
+	{CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_XAUI), NULL},
 
 	{CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE_ML, TYPE_USB), &ml_pcie_usb_xcvr_diag_ln_vals},
 
@@ -4919,6 +5018,8 @@ static const struct cdns_torrent_vals_entry xcvr_diag_vals_entries[] = {
 	{CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_PCIE), &usxgmii_pcie_xcvr_diag_ln_vals},
 	{CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_SGMII), &usxgmii_sgmii_xcvr_diag_ln_vals},
 	{CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_QSGMII), &usxgmii_sgmii_xcvr_diag_ln_vals},
+
+	{CDNS_TORRENT_KEY_ANYCLK(TYPE_XAUI, TYPE_PCIE), &xaui_pcie_xcvr_diag_ln_vals},
 };
 
 static const struct cdns_torrent_vals_entry pcs_cmn_vals_entries[] = {
@@ -4960,6 +5061,8 @@ static const struct cdns_torrent_vals_entry cmn_vals_entries[] = {
 
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), NULL},
 
+	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_XAUI, NO_SSC), NULL},
+
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, NO_SSC), &ml_pcie_100_no_ssc_cmn_vals},
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, EXTERNAL_SSC), &ml_pcie_100_no_ssc_cmn_vals},
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, INTERNAL_SSC), &ml_pcie_100_int_ssc_cmn_vals},
@@ -5010,6 +5113,8 @@ static const struct cdns_torrent_vals_entry cmn_vals_entries[] = {
 
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_cmn_vals},
 
+	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_XAUI, TYPE_PCIE, NO_SSC), &xaui_100_no_ssc_cmn_vals},
+
 	{CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &sl_usxgmii_156_25_no_ssc_cmn_vals},
 
 	/* Dual refclk */
@@ -5054,6 +5159,8 @@ static const struct cdns_torrent_vals_entry cdns_tx_ln_vals_entries[] = {
 
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), NULL},
 
+	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_XAUI, NO_SSC), NULL},
+
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, NO_SSC), NULL},
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, EXTERNAL_SSC), NULL},
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, INTERNAL_SSC), NULL},
@@ -5104,6 +5211,8 @@ static const struct cdns_torrent_vals_entry cdns_tx_ln_vals_entries[] = {
 
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_tx_ln_vals},
 
+	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_XAUI, TYPE_PCIE, NO_SSC), &xaui_100_no_ssc_tx_ln_vals},
+
 	{CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &usxgmii_156_25_no_ssc_tx_ln_vals},
 
 	/* Dual refclk */
@@ -5148,6 +5257,8 @@ static const struct cdns_torrent_vals_entry cdns_rx_ln_vals_entries[] = {
 
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), &pcie_100_no_ssc_rx_ln_vals},
 
+	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_XAUI, NO_SSC), &ml_pcie_100_no_ssc_rx_ln_vals},
+
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, NO_SSC), &ml_pcie_100_no_ssc_rx_ln_vals},
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, EXTERNAL_SSC), &ml_pcie_100_no_ssc_rx_ln_vals},
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, INTERNAL_SSC), &ml_pcie_100_no_ssc_rx_ln_vals},
@@ -5198,6 +5309,8 @@ static const struct cdns_torrent_vals_entry cdns_rx_ln_vals_entries[] = {
 
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_rx_ln_vals},
 
+	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_XAUI, TYPE_PCIE, NO_SSC), &xaui_100_no_ssc_rx_ln_vals},
+
 	{CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &usxgmii_156_25_no_ssc_rx_ln_vals},
 
 	/* Dual refclk */
@@ -5278,6 +5391,8 @@ static const struct cdns_torrent_vals_entry ti_tx_ln_vals_entries[] = {
 
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), NULL},
 
+	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_XAUI, NO_SSC), NULL},
+
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, NO_SSC), NULL},
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, EXTERNAL_SSC), NULL},
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, INTERNAL_SSC), NULL},
@@ -5328,6 +5443,8 @@ static const struct cdns_torrent_vals_entry ti_tx_ln_vals_entries[] = {
 
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_tx_ln_vals},
 
+	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_XAUI, TYPE_PCIE, NO_SSC), &ti_xaui_100_no_ssc_tx_ln_vals},
+
 	{CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &usxgmii_156_25_no_ssc_tx_ln_vals},
 
 	/* Dual refclk */
@@ -5406,6 +5523,8 @@ static const struct cdns_torrent_vals_entry ti_j7200_cmn_vals_entries[] = {
 
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), NULL},
 
+	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_XAUI, NO_SSC), NULL},
+
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, NO_SSC), &ml_pcie_100_no_ssc_cmn_vals},
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, EXTERNAL_SSC), &ml_pcie_100_no_ssc_cmn_vals},
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, INTERNAL_SSC), &ml_pcie_100_int_ssc_cmn_vals},
@@ -5456,6 +5575,8 @@ static const struct cdns_torrent_vals_entry ti_j7200_cmn_vals_entries[] = {
 
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_cmn_vals},
 
+	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_XAUI, TYPE_PCIE, NO_SSC), &xaui_100_no_ssc_cmn_vals},
+
 	{CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &sl_usxgmii_156_25_no_ssc_cmn_vals},
 
 	/* Dual refclk */
@@ -5500,6 +5621,8 @@ static const struct cdns_torrent_vals_entry ti_j7200_tx_ln_vals_entries[] = {
 
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), NULL},
 
+	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_XAUI, NO_SSC), NULL},
+
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, NO_SSC), NULL},
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, EXTERNAL_SSC), NULL},
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, INTERNAL_SSC), NULL},
@@ -5550,6 +5673,8 @@ static const struct cdns_torrent_vals_entry ti_j7200_tx_ln_vals_entries[] = {
 
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_tx_ln_vals},
 
+	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_XAUI, TYPE_PCIE, NO_SSC), &ti_xaui_100_no_ssc_tx_ln_vals},
+
 	{CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &usxgmii_156_25_no_ssc_tx_ln_vals},
 
 	/* Dual refclk */
@@ -5594,6 +5719,8 @@ static const struct cdns_torrent_vals_entry ti_j7200_rx_ln_vals_entries[] = {
 
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), &pcie_100_no_ssc_rx_ln_vals},
 
+	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_XAUI, NO_SSC), &pcie_100_no_ssc_rx_ln_vals},
+
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, NO_SSC), &pcie_100_no_ssc_rx_ln_vals},
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, EXTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals},
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, INTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals},
@@ -5644,6 +5771,8 @@ static const struct cdns_torrent_vals_entry ti_j7200_rx_ln_vals_entries[] = {
 
 	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_rx_ln_vals},
 
+	{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_XAUI, TYPE_PCIE, NO_SSC), &xaui_100_no_ssc_rx_ln_vals},
+
 	{CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &usxgmii_156_25_no_ssc_rx_ln_vals},
 
 	/* Dual refclk */
-- 
2.51.1



From a-kumar2 at ti.com  Tue Dec 23 21:54:10 2025
From: a-kumar2 at ti.com (Abhash Kumar Jha)
Date: Wed, 24 Dec 2025 11:24:10 +0530
Subject: [PATCH] arm64: dts: ti: Remove 4 watchdogs from common file and move them to J784S4
Message-ID: <20251224055410.208516-1-a-kumar2@ti.com>

As the J742S2 SOC has only 4 cores, remove the extra watchdogs and add
them only for J784S4 SOC.

Signed-off-by: Abhash Kumar Jha <a-kumar2 at ti.com>
---
 .../dts/ti/k3-j784s4-j742s2-main-common.dtsi  | 36 -------------------
 arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi    | 36 +++++++++++++++++++
 2 files changed, 36 insertions(+), 36 deletions(-)

diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi
index 9cc0901d58fb..c2636e624f18 100644
--- a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi
@@ -2378,42 +2378,6 @@ watchdog3: watchdog at 2230000 {
 		assigned-clock-parents = <&k3_clks 351 4>;
 	};
 
-	watchdog4: watchdog at 2240000 {
-		compatible = "ti,j7-rti-wdt";
-		reg = <0x00 0x2240000 0x00 0x100>;
-		clocks = <&k3_clks 352 0>;
-		power-domains = <&k3_pds 352 TI_SCI_PD_EXCLUSIVE>;
-		assigned-clocks = <&k3_clks 352 0>;
-		assigned-clock-parents = <&k3_clks 352 4>;
-	};
-
-	watchdog5: watchdog at 2250000 {
-		compatible = "ti,j7-rti-wdt";
-		reg = <0x00 0x2250000 0x00 0x100>;
-		clocks = <&k3_clks 353 0>;
-		power-domains = <&k3_pds 353 TI_SCI_PD_EXCLUSIVE>;
-		assigned-clocks = <&k3_clks 353 0>;
-		assigned-clock-parents = <&k3_clks 353 4>;
-	};
-
-	watchdog6: watchdog at 2260000 {
-		compatible = "ti,j7-rti-wdt";
-		reg = <0x00 0x2260000 0x00 0x100>;
-		clocks = <&k3_clks 354 0>;
-		power-domains = <&k3_pds 354 TI_SCI_PD_EXCLUSIVE>;
-		assigned-clocks = <&k3_clks 354 0>;
-		assigned-clock-parents = <&k3_clks 354 4>;
-	};
-
-	watchdog7: watchdog at 2270000 {
-		compatible = "ti,j7-rti-wdt";
-		reg = <0x00 0x2270000 0x00 0x100>;
-		clocks = <&k3_clks 355 0>;
-		power-domains = <&k3_pds 355 TI_SCI_PD_EXCLUSIVE>;
-		assigned-clocks = <&k3_clks 355 0>;
-		assigned-clock-parents = <&k3_clks 355 4>;
-	};
-
 	/*
 	 * The following RTI instances are coupled with MCU R5Fs, c7x and
 	 * GPU so keeping them reserved as these will be used by their
diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi
index 0160fe0da983..ffc61ec77635 100644
--- a/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi
@@ -113,6 +113,42 @@ serdes2: serdes at 5020000 {
 			status = "disabled";
 		};
 	};
+
+	watchdog4: watchdog at 2240000 {
+		compatible = "ti,j7-rti-wdt";
+		reg = <0x00 0x2240000 0x00 0x100>;
+		clocks = <&k3_clks 352 0>;
+		power-domains = <&k3_pds 352 TI_SCI_PD_EXCLUSIVE>;
+		assigned-clocks = <&k3_clks 352 0>;
+		assigned-clock-parents = <&k3_clks 352 4>;
+	};
+
+	watchdog5: watchdog at 2250000 {
+		compatible = "ti,j7-rti-wdt";
+		reg = <0x00 0x2250000 0x00 0x100>;
+		clocks = <&k3_clks 353 0>;
+		power-domains = <&k3_pds 353 TI_SCI_PD_EXCLUSIVE>;
+		assigned-clocks = <&k3_clks 353 0>;
+		assigned-clock-parents = <&k3_clks 353 4>;
+	};
+
+	watchdog6: watchdog at 2260000 {
+		compatible = "ti,j7-rti-wdt";
+		reg = <0x00 0x2260000 0x00 0x100>;
+		clocks = <&k3_clks 354 0>;
+		power-domains = <&k3_pds 354 TI_SCI_PD_EXCLUSIVE>;
+		assigned-clocks = <&k3_clks 354 0>;
+		assigned-clock-parents = <&k3_clks 354 4>;
+	};
+
+	watchdog7: watchdog at 2270000 {
+		compatible = "ti,j7-rti-wdt";
+		reg = <0x00 0x2270000 0x00 0x100>;
+		clocks = <&k3_clks 355 0>;
+		power-domains = <&k3_pds 355 TI_SCI_PD_EXCLUSIVE>;
+		assigned-clocks = <&k3_clks 355 0>;
+		assigned-clock-parents = <&k3_clks 355 4>;
+	};
 };
 
 &scm_conf {
-- 
2.34.1



From peter.wang at mediatek.com  Tue Dec 23 22:13:05 2025
From: peter.wang at mediatek.com (=?utf-8?B?UGV0ZXIgV2FuZyAo546L5L+h5Y+LKQ==?=)
Date: Wed, 24 Dec 2025 06:13:05 +0000
Subject: [PATCH v4 07/25] scsi: ufs: mediatek: Rework 0.9V regulator
In-Reply-To: <14003986.uLZWGnKmhe@workhorse>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
	 <20251218-mt8196-ufs-v4-7-ddec7a369dd2@collabora.com>
	 <8206d9e715f7ef987b5369d0bda68cce13528112.camel@mediatek.com>
	 <14003986.uLZWGnKmhe@workhorse>
Message-ID: <2eec4b3c0fff4869c599558a7e851d052eb60e0e.camel@mediatek.com>

On Tue, 2025-12-23 at 17:13 +0100, Nicolas Frattaroli wrote:
> 
> 
> Hi,
> 
> that would allow compatibles that are not allowed to have an avdd09
> regulator by the binding (because the SoC doesn't have that pin) to
> have one specified in the device tree get picked up. This would then
> cause those devices with such a device tree to enter
> ufs_mtk_va09_pwr_ctrl(), which is not what we want. While we could
> blame this on the DT being wrong in that case, I think it's better
> if we avoid such a situation entirely.
> 
> Kind regards,
> Nicolas Frattaroli
> 
> 

Hi Nicolas,

Okay, this does help avoid issues caused by incorrect DTS 
settings. Although it increases the complexity of the code, 
it provides a mistake proofing.
Thanks.

Reviewed-by: Peter Wang <peter.wang at mediatek.com>

From peter.wang at mediatek.com  Tue Dec 23 22:14:19 2025
From: peter.wang at mediatek.com (=?utf-8?B?UGV0ZXIgV2FuZyAo546L5L+h5Y+LKQ==?=)
Date: Wed, 24 Dec 2025 06:14:19 +0000
Subject: [PATCH v4 08/25] scsi: ufs: mediatek: Rework init function
In-Reply-To: <20251218-mt8196-ufs-v4-8-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
	 <20251218-mt8196-ufs-v4-8-ddec7a369dd2@collabora.com>
Message-ID: <cb912a89b651bd64a0f2f088bd4f802b68825d80.camel@mediatek.com>

On Thu, 2025-12-18 at 13:54 +0100, Nicolas Frattaroli wrote:
> Printing an error message on ENOMEM is pointless. The print will not
> work because there is no memory.
> 
> Adding an of_match_device to the init function is pointless. Why
> would a
> different device with a different probe function ever use the same
> init
> function? Get rid of it.
> 
> zero-initialising an error variable just so you can then goto a bare
> return statement with that error variable to signal success is also
> pointless, just return directly, there's no unwind being done.
> 
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>

Reviewed-by: Peter Wang <peter.wang at mediatek.com>


From zhengtian10 at huawei.com  Tue Dec 23 22:15:16 2025
From: zhengtian10 at huawei.com (Tian Zheng)
Date: Wed, 24 Dec 2025 14:15:16 +0800
Subject: [PATCH v2 4/5] KVM: arm64: Enable HDBSS support and handle HDBSSF
 events
In-Reply-To: <87df4cba-b191-49cf-9486-fc379470a6eb@gmail.com>
References: <20251121092342.3393318-1-zhengtian10@huawei.com>
 <20251121092342.3393318-5-zhengtian10@huawei.com>
 <87df4cba-b191-49cf-9486-fc379470a6eb@gmail.com>
Message-ID: <f8e59e80-33b2-47cd-a042-11f28cc61645@huawei.com>



On 12/17/2025 9:39 PM, Robert Hoo wrote:
> On 11/21/2025 5:23 PM, Tian Zheng wrote:
>> From: eillon <yezhenyu2 at huawei.com>
>>
>> Implement the HDBSS enable/disable functionality using the
>> KVM_CAP_ARM_HW_DIRTY_STATE_TRACK ioctl.
>>
>> Userspace (e.g., QEMU) can enable HDBSS by invoking the ioctl
>> at the start of live migration, configuring the buffer size.
>> The feature is disabled by invoking the ioctl again with size
>> set to 0 once migration completes.
>>
>> Add support for updating the dirty bitmap based on the HDBSS
>> buffer. Similar to the x86 PML implementation, KVM flushes the
>> buffer on all VM-Exits, so running vCPUs only need to be kicked
>> to force a VM-Exit.
>>
>> Signed-off-by: eillon <yezhenyu2 at huawei.com>
>> Signed-off-by: Tian Zheng <zhengtian10 at huawei.com>
>> ---
>> ? arch/arm64/include/asm/kvm_host.h |? 10 +++
>> ? arch/arm64/include/asm/kvm_mmu.h? |? 17 +++++
>> ? arch/arm64/kvm/arm.c????????????? | 107 ++++++++++++++++++++++++++++++
>> ? arch/arm64/kvm/handle_exit.c????? |? 45 +++++++++++++
>> ? arch/arm64/kvm/hyp/vhe/switch.c?? |?? 1 +
>> ? arch/arm64/kvm/mmu.c????????????? |? 10 +++
>> ? arch/arm64/kvm/reset.c??????????? |?? 3 +
>> ? include/linux/kvm_host.h????????? |?? 1 +
>> ? 8 files changed, 194 insertions(+)
>>
>> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/ 
>> asm/kvm_host.h
>> index d962932f0e5f..408e4c2b3d1a 100644
>> --- a/arch/arm64/include/asm/kvm_host.h
>> +++ b/arch/arm64/include/asm/kvm_host.h
>> @@ -87,6 +87,7 @@ int __init kvm_arm_init_sve(void);
>> ? u32 __attribute_const__ kvm_target_cpu(void);
>> ? void kvm_reset_vcpu(struct kvm_vcpu *vcpu);
>> ? void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu);
>> +void kvm_arm_vcpu_free_hdbss(struct kvm_vcpu *vcpu);
>>
>> ? struct kvm_hyp_memcache {
>> ????? phys_addr_t head;
>> @@ -793,6 +794,12 @@ struct vcpu_reset_state {
>> ????? bool??????? reset;
>> ? };
>>
>> +struct vcpu_hdbss_state {
>> +??? phys_addr_t base_phys;
>> +??? u32 size;
>> +??? u32 next_index;
>> +};
>> +
>> ? struct vncr_tlb;
>>
>> ? struct kvm_vcpu_arch {
>> @@ -897,6 +904,9 @@ struct kvm_vcpu_arch {
>>
>> ????? /* Per-vcpu TLB for VNCR_EL2 -- NULL when !NV */
>> ????? struct vncr_tlb??? *vncr_tlb;
>> +
>> +??? /* HDBSS registers info */
>> +??? struct vcpu_hdbss_state hdbss;
>> ? };
>>
>> ? /*
>> diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/ 
>> asm/kvm_mmu.h
>> index e4069f2ce642..6ace1080aed5 100644
>> --- a/arch/arm64/include/asm/kvm_mmu.h
>> +++ b/arch/arm64/include/asm/kvm_mmu.h
>> @@ -331,6 +331,23 @@ static __always_inline void __load_stage2(struct 
>> kvm_s2_mmu *mmu,
>> ????? asm(ALTERNATIVE("nop", "isb", ARM64_WORKAROUND_SPECULATIVE_AT));
>> ? }
>>
>> +static __always_inline void __load_hdbss(struct kvm_vcpu *vcpu)
>> +{
>> +??? struct kvm *kvm = vcpu->kvm;
>> +??? u64 br_el2, prod_el2;
>> +
>> +??? if (!kvm->enable_hdbss)
>> +??????? return;
>> +
>> +??? br_el2 = HDBSSBR_EL2(vcpu->arch.hdbss.base_phys, vcpu- 
>> >arch.hdbss.size);
>> +??? prod_el2 = vcpu->arch.hdbss.next_index;
>> +
>> +??? write_sysreg_s(br_el2, SYS_HDBSSBR_EL2);
>> +??? write_sysreg_s(prod_el2, SYS_HDBSSPROD_EL2);
>> +
>> +??? isb();
>> +}
>> +
>> ? static inline struct kvm *kvm_s2_mmu_to_kvm(struct kvm_s2_mmu *mmu)
>> ? {
>> ????? return container_of(mmu->arch, struct kvm, arch);
>> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
>> index 870953b4a8a7..64f65e3c2a89 100644
>> --- a/arch/arm64/kvm/arm.c
>> +++ b/arch/arm64/kvm/arm.c
>> @@ -79,6 +79,92 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
>> ????? return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE;
>> ? }
>>
>> +void kvm_arm_vcpu_free_hdbss(struct kvm_vcpu *vcpu)
>> +{
>> +??? struct page *hdbss_pg = NULL;
>> +
>> +??? hdbss_pg = phys_to_page(vcpu->arch.hdbss.base_phys);
>> +??? if (hdbss_pg)
>> +??????? __free_pages(hdbss_pg, vcpu->arch.hdbss.size);
>> +
>> +??? vcpu->arch.hdbss = (struct vcpu_hdbss_state) {
>> +??????? .base_phys = 0,
>> +??????? .size = 0,
>> +??????? .next_index = 0,
>> +??? };
>> +}
>> +
>> +static int kvm_cap_arm_enable_hdbss(struct kvm *kvm,
>> +??????????????????? struct kvm_enable_cap *cap)
>> +{
>> +??? unsigned long i;
>> +??? struct kvm_vcpu *vcpu;
>> +??? struct page *hdbss_pg = NULL;
>> +??? int size = cap->args[0];
>> +??? int ret = 0;
>> +
>> +??? if (!system_supports_hdbss()) {
>> +??????? kvm_err("This system does not support HDBSS!\n");
>> +??????? return -EINVAL;
>> +??? }
>> +
>> +??? if (size < 0 || size > HDBSS_MAX_SIZE) {
>> +??????? kvm_err("Invalid HDBSS buffer size: %d!\n", size);
>> +??????? return -EINVAL;
>> +??? }
>> +
> 
> I think you should check if it's already enabled here. What if user 
> space calls this twice?

Ok, I review the implement of qemu, when disable the hdbss feature in
ram_save_cleanup, size=0 will be set, so here can add a check, if (size
&& kvm->arch.enable_hdbss), we will do nothing.

> 
>> +??? /* Enable the HDBSS feature if size > 0, otherwise disable it. */
>> +??? if (size) {
>> +??????? kvm_for_each_vcpu(i, vcpu, kvm) {
>> +??????????? hdbss_pg = alloc_pages(GFP_KERNEL_ACCOUNT, size);
>> +??????????? if (!hdbss_pg) {
>> +??????????????? kvm_err("Alloc HDBSS buffer failed!\n");
>> +??????????????? ret = -ENOMEM;
>> +??????????????? goto error_alloc;
>> +??????????? }
>> +
>> +??????????? vcpu->arch.hdbss = (struct vcpu_hdbss_state) {
>> +??????????????? .base_phys = page_to_phys(hdbss_pg),
>> +??????????????? .size = size,
>> +??????????????? .next_index = 0,
>> +??????????? };
>> +??????? }
>> +
>> +??????? kvm->enable_hdbss = true;
>> +??????? kvm->arch.mmu.vtcr |= VTCR_EL2_HD | VTCR_EL2_HDBSS;
> 
> VTCR_EL2_HA is also a necessity for VTCR_EL2_HDBSS to take effect.

I see, thanks! I checked the architecture spec, and it indeed states
that HA needs to be enabled for AF hardware management to function
properly.

> 
>> +
>> +??????? /*
>> +???????? * We should kick vcpus out of guest mode here to load new
>> +???????? * vtcr value to vtcr_el2 register when re-enter guest mode.
>> +???????? */
>> +??????? kvm_for_each_vcpu(i, vcpu, kvm)
>> +??????????? kvm_vcpu_kick(vcpu);
>> +??? } else if (kvm->enable_hdbss) {
>> +??????? kvm->arch.mmu.vtcr &= ~(VTCR_EL2_HD | VTCR_EL2_HDBSS);
>> +
>> +??????? kvm_for_each_vcpu(i, vcpu, kvm) {
>> +??????????? /* Kick vcpus to flush hdbss buffer. */
>> +??????????? kvm_vcpu_kick(vcpu);
>> +
>> +??????????? kvm_arm_vcpu_free_hdbss(vcpu);
>> +??????? }
>> +
>> +??????? kvm->enable_hdbss = false;
>> +??? }
>> +
>> +??? return ret;
>> +
>> +error_alloc:
>> +??? kvm_for_each_vcpu(i, vcpu, kvm) {
>> +??????? if (!vcpu->arch.hdbss.base_phys && !vcpu->arch.hdbss.size)
>> +??????????? continue;
>> +
>> +??????? kvm_arm_vcpu_free_hdbss(vcpu);
>> +??? }
>> +
>> +??? return ret;
>> +}
>> +
>> ? int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
>> ????????????????? struct kvm_enable_cap *cap)
>> ? {
>> @@ -132,6 +218,11 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
>> ????????? }
>> ????????? mutex_unlock(&kvm->lock);
>> ????????? break;
>> +??? case KVM_CAP_ARM_HW_DIRTY_STATE_TRACK:
>> +??????? mutex_lock(&kvm->lock);
>> +??????? r = kvm_cap_arm_enable_hdbss(kvm, cap);
>> +??????? mutex_unlock(&kvm->lock);
>> +??????? break;
>> ????? default:
>> ????????? break;
>> ????? }
>> @@ -420,6 +511,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, 
>> long ext)
>> ????????????? r = kvm_supports_cacheable_pfnmap();
>> ????????? break;
>>
>> +??? case KVM_CAP_ARM_HW_DIRTY_STATE_TRACK:
>> +??????? r = system_supports_hdbss();
>> +??????? break;
>> ????? default:
>> ????????? r = 0;
>> ????? }
>> @@ -1837,7 +1931,20 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
>>
>> ? void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot 
>> *memslot)
>> ? {
>> +??? /*
>> +???? * Flush all CPUs' dirty log buffers to the dirty_bitmap.? Called
>> +???? * before reporting dirty_bitmap to userspace.? KVM flushes the 
>> buffers
>> +???? * on all VM-Exits, thus we only need to kick running vCPUs to 
>> force a
>> +???? * VM-Exit.
>> +???? */
>> +??? struct kvm_vcpu *vcpu;
>> +??? unsigned long i;
>>
>> +??? if (!kvm->enable_hdbss)
>> +??????? return;
>> +
>> +??? kvm_for_each_vcpu(i, vcpu, kvm)
>> +??????? kvm_vcpu_kick(vcpu);
>> ? }
>>
>> ? static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm,
>> diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
>> index cc7d5d1709cb..9ba0ea6305ef 100644
>> --- a/arch/arm64/kvm/handle_exit.c
>> +++ b/arch/arm64/kvm/handle_exit.c
>> @@ -412,6 +412,49 @@ static exit_handle_fn kvm_get_exit_handler(struct 
>> kvm_vcpu *vcpu)
>> ????? return arm_exit_handlers[esr_ec];
>> ? }
>>
>> +static void kvm_flush_hdbss_buffer(struct kvm_vcpu *vcpu)
>> +{
>> +??? int idx, curr_idx;
>> +??? u64 *hdbss_buf;
>> +??? struct kvm *kvm = vcpu->kvm;
>> +??? u64 br_el2;
>> +
>> +??? if (!kvm->enable_hdbss)
>> +??????? return;
>> +
>> +??? dsb(sy);
>> +??? isb();
>> +??? curr_idx = HDBSSPROD_IDX(read_sysreg_s(SYS_HDBSSPROD_EL2));
>> +??? br_el2 = HDBSSBR_EL2(vcpu->arch.hdbss.base_phys, vcpu- 
>> >arch.hdbss.size);
>> +
>> +??? /* Do nothing if HDBSS buffer is empty or br_el2 is NULL */
>> +??? if (curr_idx == 0 || br_el2 == 0)
>> +??????? return;
>> +
>> +??? hdbss_buf = page_address(phys_to_page(vcpu->arch.hdbss.base_phys));
>> +??? if (!hdbss_buf) {
>> +??????? kvm_err("Enter flush hdbss buffer with buffer == NULL!");
>> +??????? return;
>> +??? }
>> +
>> +??? guard(write_lock_irqsave)(&vcpu->kvm->mmu_lock);
>> +??? for (idx = 0; idx < curr_idx; idx++) {
>> +??????? u64 gpa;
>> +
>> +??????? gpa = hdbss_buf[idx];
>> +??????? if (!(gpa & HDBSS_ENTRY_VALID))
>> +??????????? continue;
>> +
>> +??????? gpa &= HDBSS_ENTRY_IPA;
>> +??????? kvm_vcpu_mark_page_dirty(vcpu, gpa >> PAGE_SHIFT);
>> +??? }
>> +
>> +??? /* reset HDBSS index */
>> +??? write_sysreg_s(0, SYS_HDBSSPROD_EL2);
>> +??? vcpu->arch.hdbss.next_index = 0;
>> +??? isb();
>> +}
>> +
>> ? /*
>> ?? * We may be single-stepping an emulated instruction. If the emulation
>> ?? * has been completed in the kernel, we can return to userspace with a
>> @@ -447,6 +490,8 @@ int handle_exit(struct kvm_vcpu *vcpu, int 
>> exception_index)
>> ? {
>> ????? struct kvm_run *run = vcpu->run;
>>
>> +??? kvm_flush_hdbss_buffer(vcpu);
>> +
>> ????? if (ARM_SERROR_PENDING(exception_index)) {
>> ????????? /*
>> ?????????? * The SError is handled by handle_exit_early(). If the guest
>> diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/ 
>> switch.c
>> index 9984c492305a..3787c9c5810d 100644
>> --- a/arch/arm64/kvm/hyp/vhe/switch.c
>> +++ b/arch/arm64/kvm/hyp/vhe/switch.c
>> @@ -220,6 +220,7 @@ void kvm_vcpu_load_vhe(struct kvm_vcpu *vcpu)
>> ????? __vcpu_load_switch_sysregs(vcpu);
>> ????? __vcpu_load_activate_traps(vcpu);
>> ????? __load_stage2(vcpu->arch.hw_mmu, vcpu->arch.hw_mmu->arch);
>> +??? __load_hdbss(vcpu);
>> ? }
>>
>> ? void kvm_vcpu_put_vhe(struct kvm_vcpu *vcpu)
>> diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
>> index 7cc964af8d30..91a2f9dbb406 100644
>> --- a/arch/arm64/kvm/mmu.c
>> +++ b/arch/arm64/kvm/mmu.c
>> @@ -1843,6 +1843,9 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, 
>> phys_addr_t fault_ipa,
>> ????? if (writable)
>> ????????? prot |= KVM_PGTABLE_PROT_W;
>>
>> +??? if (writable && kvm->enable_hdbss && logging_active)
>> +??????? prot |= KVM_PGTABLE_PROT_DBM;
>> +
>> ????? if (exec_fault)
>> ????????? prot |= KVM_PGTABLE_PROT_X;
>>
>> @@ -1950,6 +1953,13 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
>>
>> ????? is_iabt = kvm_vcpu_trap_is_iabt(vcpu);
>>
>> +??? /*
>> +???? * HDBSS buffer already flushed when enter handle_trap_exceptions().
>> +???? * Nothing to do here.
>> +???? */
>> +??? if (ESR_ELx_ISS2(esr) & ESR_ELx_HDBSSF)
>> +??????? return 1;
>> +
>> ????? if (esr_fsc_is_translation_fault(esr)) {
>> ????????? /* Beyond sanitised PARange (which is the IPA limit) */
>> ????????? if (fault_ipa >= BIT_ULL(get_kvm_ipa_limit())) {
>> diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
>> index 959532422d3a..65e8f890f863 100644
>> --- a/arch/arm64/kvm/reset.c
>> +++ b/arch/arm64/kvm/reset.c
>> @@ -161,6 +161,9 @@ void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu)
>> ????? free_page((unsigned long)vcpu->arch.ctxt.vncr_array);
>> ????? kfree(vcpu->arch.vncr_tlb);
>> ????? kfree(vcpu->arch.ccsidr);
>> +
>> +??? if (vcpu->arch.hdbss.base_phys || vcpu->arch.hdbss.size)
>> +??????? kvm_arm_vcpu_free_hdbss(vcpu);
>> ? }
>>
>> ? static void kvm_vcpu_reset_sve(struct kvm_vcpu *vcpu)
>> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
>> index 5bd76cf394fa..aa8138604b1e 100644
>> --- a/include/linux/kvm_host.h
>> +++ b/include/linux/kvm_host.h
>> @@ -876,6 +876,7 @@ struct kvm {
>> ????? struct xarray mem_attr_array;
>> ? #endif
>> ????? char stats_id[KVM_STATS_NAME_SIZE];
>> +??? bool enable_hdbss;
>> ? };
>>
>> ? #define kvm_err(fmt, ...) \
>> -- 
>> 2.33.0
>>
>>
> 



From peter.wang at mediatek.com  Tue Dec 23 22:16:34 2025
From: peter.wang at mediatek.com (=?utf-8?B?UGV0ZXIgV2FuZyAo546L5L+h5Y+LKQ==?=)
Date: Wed, 24 Dec 2025 06:16:34 +0000
Subject: [PATCH v4 09/25] scsi: ufs: mediatek: Rework the crypt-boost
 stuff
In-Reply-To: <20251218-mt8196-ufs-v4-9-ddec7a369dd2@collabora.com>
References: <20251218-mt8196-ufs-v4-0-ddec7a369dd2@collabora.com>
	 <20251218-mt8196-ufs-v4-9-ddec7a369dd2@collabora.com>
Message-ID: <a12f7ffe8448d205a7318219ea7a18f0f722727f.camel@mediatek.com>

On Thu, 2025-12-18 at 13:54 +0100, Nicolas Frattaroli wrote:
> -
> -static void ufs_mtk_init_boost_crypt(struct ufs_hba *hba)
> +static int ufs_mtk_init_boost_crypt(struct ufs_hba *hba)
> 

Hi Nicolas,

Please do not change the return type if you are not checking the return
value.


> ?{
> ??????? struct ufs_mtk_host *host = ufshcd_get_variant(hba);
> ??????? struct ufs_mtk_crypt_cfg *cfg;
> ??????? struct device *dev = hba->dev;
> -?????? struct regulator *reg;
> -?????? u32 volt;
> +?????? int ret;
> 
> -?????? host->crypt = devm_kzalloc(dev, sizeof(*(host->crypt)),
> -????????????????????????????????? GFP_KERNEL);
> -?????? if (!host->crypt)
> -?????????????? goto disable_caps;
> +?????? cfg = devm_kzalloc(dev, sizeof(*cfg), GFP_KERNEL);
> +?????? if (!cfg)
> +?????????????? return -ENOMEM;
> 
> -?????? reg = devm_regulator_get_optional(dev, "dvfsrc-vcore");
> -?????? if (IS_ERR(reg)) {
> -?????????????? dev_info(dev, "failed to get dvfsrc-vcore: %ld",
> -??????????????????????? PTR_ERR(reg));
> -?????????????? goto disable_caps;
> +?????? cfg->reg_vcore = devm_regulator_get_optional(dev, "dvfsrc-
> vcore");
> +?????? if (IS_ERR(cfg->reg_vcore)) {
> +?????????????? dev_err(dev, "Failed to get dvfsrc-vcore: %pe", cfg-
> >reg_vcore);
> 

Should free the cfg memory?

> +?????????????? return PTR_ERR(cfg->reg_vcore);
> ??????? }
> 
> -?????? if (of_property_read_u32(dev->of_node, "boost-crypt-vcore-
> min",
> -??????????????????????????????? &volt)) {
> -?????????????? dev_info(dev, "failed to get boost-crypt-vcore-min");
> -?????????????? goto disable_caps;
> +?????? ret = of_property_read_u32(dev->of_node, "mediatek,boost-
> crypt-vcore-min",
> +????????????????????????????????? &cfg->vcore_volt);
> +?????? if (ret) {
> +?????????????? dev_err(dev, "Failed to get mediatek,boost-crypt-
> vcore-min: %pe\n",
> +?????????????????????? ERR_PTR(ret));
> +?????????????? return ret;
> ??????? }
> 
> -?????? cfg = host->crypt;
> -?????? if (ufs_mtk_init_host_clk(hba, "crypt_mux",
> -???????????????????????????????? &cfg->clk_crypt_mux))
> -?????????????? goto disable_caps;
> +?????? cfg->clk_crypt_mux = devm_clk_get(dev, "crypt_mux");
> +?????? if (IS_ERR(cfg->clk_crypt_mux)) {
> +?????????????? dev_err(dev, "Failed to get clock crypt_mux: %pe\n",
> cfg->clk_crypt_mux);
> +?????????????? return PTR_ERR(cfg->clk_crypt_mux);
> +?????? }
> 
> -?????? if (ufs_mtk_init_host_clk(hba, "crypt_lp",
> -???????????????????????????????? &cfg->clk_crypt_lp))
> -?????????????? goto disable_caps;
> +?????? cfg->clk_crypt_lp = devm_clk_get(dev, "crypt_lp");
> +?????? if (IS_ERR(cfg->clk_crypt_lp)) {
> +?????????????? dev_err(dev, "Failed to get clock crypt_lp: %pe\n",
> cfg->clk_crypt_lp);
> +?????????????? return PTR_ERR(cfg->clk_crypt_lp);
> +?????? }
> 
> -?????? if (ufs_mtk_init_host_clk(hba, "crypt_perf",
> -???????????????????????????????? &cfg->clk_crypt_perf))
> -?????????????? goto disable_caps;
> +?????? cfg->clk_crypt_perf = devm_clk_get(dev, "crypt_perf");
> +?????? if (IS_ERR(cfg->clk_crypt_perf)) {
> +?????????????? dev_err(dev, "Failed to get clock crypt_perf: %pe\n",
> cfg->clk_crypt_perf);
> +?????????????? return PTR_ERR(cfg->clk_crypt_perf);
> +?????? }
> 
> -?????? cfg->reg_vcore = reg;
> -?????? cfg->vcore_volt = volt;
> +?????? host->crypt = cfg;
> ??????? host->caps |= UFS_MTK_CAP_BOOST_CRYPT_ENGINE;
> 
> -disable_caps:
> -?????? return;
> +?????? return 0;
> ?}
> 
> ?static void ufs_mtk_init_host_caps(struct ufs_hba *hba)
> 
> --
> 2.52.0
> 


From u-kumar1 at ti.com  Tue Dec 23 22:29:01 2025
From: u-kumar1 at ti.com (Kumar, Udit)
Date: Wed, 24 Dec 2025 11:59:01 +0530
Subject: [PATCH] arm64: dts: ti: Remove 4 watchdogs from common file and
 move them to J784S4
In-Reply-To: <20251224055410.208516-1-a-kumar2@ti.com>
References: <20251224055410.208516-1-a-kumar2@ti.com>
Message-ID: <f9322bd0-8285-4e2b-bb23-fd0373d11ae9@ti.com>


On 12/24/2025 11:24 AM, Abhash Kumar Jha wrote:
> As the J742S2 SOC has only 4 cores, remove the extra watchdogs and add
> them only for J784S4 SOC.

Thanks for catching this.

Fixes tag please


> Signed-off-by: Abhash Kumar Jha <a-kumar2 at ti.com>
> ---
>   .../dts/ti/k3-j784s4-j742s2-main-common.dtsi  | 36 -------------------
>   arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi    | 36 +++++++++++++++++++
>   2 files changed, 36 insertions(+), 36 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi
> index 9cc0901d58fb..c2636e624f18 100644
> --- a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi
> +++ b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi
> @@ -2378,42 +2378,6 @@ watchdog3: watchdog at 2230000 {
>   		assigned-clock-parents = <&k3_clks 351 4>;
>   	};
>   
> [..]


From kylehsieh1995 at gmail.com  Tue Dec 23 22:40:39 2025
From: kylehsieh1995 at gmail.com (Kyle Hsieh)
Date: Wed, 24 Dec 2025 14:40:39 +0800
Subject: [PATCH 2/2] ARM: dts: aspeed: ventura2: Add Meta ventura2 BMC
In-Reply-To: <1e21f828-1b06-492d-bfcd-ab5721621e8a@lunn.ch>
References: <20251222-ventura2_initial_dts-v1-0-1f06166c78a3@gmail.com>
 <20251222-ventura2_initial_dts-v1-2-1f06166c78a3@gmail.com>
 <c069b452-df22-4afa-bf6a-c48949f40ebc@lunn.ch> <CAF7HswN_jEXOU_9K4LpLnbhvd+RD0qqELAHxMBbp=hGtMjS4kQ@mail.gmail.com>
 <35f3eba9-5ec4-4cba-8a64-fb521dc65b79@lunn.ch> <CAF7HswN0hhJQ-gmE59cKTuPyzrs1A3rM8Xw+Z8i3_AsHRiNcug@mail.gmail.com>
 <1e21f828-1b06-492d-bfcd-ab5721621e8a@lunn.ch>
Message-ID: <CAF7HswP7Oejs42K=jG8bkNiBoDhXR2LbeHoppk0nnNon6_afwA@mail.gmail.com>

On Tue, Dec 23, 2025 at 6:35?PM Andrew Lunn <andrew at lunn.ch> wrote:
>
> > > What make/model of switch is it? Is it unmanaged, or does it use SPI
> > > or I2C for management?
>
> > The switch is connected via RMII to the MAC and is managed over MDIO.
>
> O.K. What make/model?
>
The device is a Marvell 88E6393X switch. In our design, the BMC connects
to the device via RMII with fixed link parameters to retrieve ethernet.
> > On our board, MDIO is not wired directly to the processor; instead, we
> > use a USB-to-MPSSE bridge (FT2232) to toggle the MDIO signals for
> > switch management.
>
> I have to push back on you using a closed source user space driver,
> given that i help maintain the Ethernet switch drivers...
>
> I know there have been attempts to get GPIO support added for FT2232,
> but i don't think any got as far as mainline. That is probably the
> only part you are missing. You can describe USB devices in DT. So you
> should be able to describe such a GPIO controller. You can then
> instantiate an virtual,mdio-gpio driver to give you an MDIO bus. And
> then add nodes for the switch using DSA.
>
Apologies for the confusion in my previous reply.
The BMC connects to the peer via an RMII fixed-link.
The link parameters are fixed at design time and there is no runtime
MDIO-managed PHY or switch control from the BMC.
>      Andrew


From kylehsieh1995 at gmail.com  Tue Dec 23 22:44:37 2025
From: kylehsieh1995 at gmail.com (Kyle Hsieh)
Date: Wed, 24 Dec 2025 14:44:37 +0800
Subject: [PATCH v2 0/2] Add Meta(Facebook) ventura2 BMC(AST2600)
Message-ID: <20251224-ventura2_initial_dts-v2-0-f193ba5d4073@gmail.com>

Summary:
Add linux device tree entry related to Meta(Facebook) ventura2.
specific devices connected to BMC(AST2600) SoC.

Signed-off-by: Kyle Hsieh <kylehsieh1995 at gmail.com>
---
Changes in v2:
- Remove unused mdio
- Link to v1: https://lore.kernel.org/r/20251222-ventura2_initial_dts-v1-0-1f06166c78a3 at gmail.com

---
Kyle Hsieh (2):
      dt-bindings: arm: aspeed: add Meta ventura2 board
      ARM: dts: aspeed: ventura2: Add Meta ventura2 BMC

 .../devicetree/bindings/arm/aspeed/aspeed.yaml     |    1 +
 arch/arm/boot/dts/aspeed/Makefile                  |    1 +
 .../dts/aspeed/aspeed-bmc-facebook-ventura2.dts    | 2945 ++++++++++++++++++++
 3 files changed, 2947 insertions(+)
---
base-commit: 9448598b22c50c8a5bb77a9103e2d49f134c9578
change-id: 20251222-ventura2_initial_dts-909b3277d665

Best regards,
-- 
Kyle Hsieh <kylehsieh1995 at gmail.com>



From kylehsieh1995 at gmail.com  Tue Dec 23 22:44:38 2025
From: kylehsieh1995 at gmail.com (Kyle Hsieh)
Date: Wed, 24 Dec 2025 14:44:38 +0800
Subject: [PATCH v2 1/2] dt-bindings: arm: aspeed: add Meta ventura2 board
In-Reply-To: <20251224-ventura2_initial_dts-v2-0-f193ba5d4073@gmail.com>
References: <20251224-ventura2_initial_dts-v2-0-f193ba5d4073@gmail.com>
Message-ID: <20251224-ventura2_initial_dts-v2-1-f193ba5d4073@gmail.com>

Document the new compatibles used on Facebook ventura2.

Signed-off-by: Kyle Hsieh <kylehsieh1995 at gmail.com>
---
 Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
index 9298c1a75dd1..24e19b8d108a 100644
--- a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
+++ b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
@@ -92,6 +92,7 @@ properties:
               - facebook,harma-bmc
               - facebook,minerva-cmc
               - facebook,santabarbara-bmc
+              - facebook,ventura2-bmc
               - facebook,yosemite4-bmc
               - facebook,yosemite5-bmc
               - ibm,balcones-bmc

-- 
2.34.1



From kylehsieh1995 at gmail.com  Tue Dec 23 22:44:39 2025
From: kylehsieh1995 at gmail.com (Kyle Hsieh)
Date: Wed, 24 Dec 2025 14:44:39 +0800
Subject: [PATCH v2 2/2] ARM: dts: aspeed: ventura2: Add Meta ventura2 BMC
In-Reply-To: <20251224-ventura2_initial_dts-v2-0-f193ba5d4073@gmail.com>
References: <20251224-ventura2_initial_dts-v2-0-f193ba5d4073@gmail.com>
Message-ID: <20251224-ventura2_initial_dts-v2-2-f193ba5d4073@gmail.com>

Add linux device tree entry related to the Meta(Facebook) rmc-node.
The system use an AT2600 BMC.
This node is named "ventura2".

Signed-off-by: Kyle Hsieh <kylehsieh1995 at gmail.com>
---
 arch/arm/boot/dts/aspeed/Makefile                  |    1 +
 .../dts/aspeed/aspeed-bmc-facebook-ventura2.dts    | 2945 ++++++++++++++++++++
 2 files changed, 2946 insertions(+)

diff --git a/arch/arm/boot/dts/aspeed/Makefile b/arch/arm/boot/dts/aspeed/Makefile
index 9adf9278dc94..6b96997629d4 100644
--- a/arch/arm/boot/dts/aspeed/Makefile
+++ b/arch/arm/boot/dts/aspeed/Makefile
@@ -32,6 +32,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \
 	aspeed-bmc-facebook-minipack.dtb \
 	aspeed-bmc-facebook-santabarbara.dtb \
 	aspeed-bmc-facebook-tiogapass.dtb \
+	aspeed-bmc-facebook-ventura2.dtb \
 	aspeed-bmc-facebook-wedge40.dtb \
 	aspeed-bmc-facebook-wedge100.dtb \
 	aspeed-bmc-facebook-wedge400-data64.dtb \
diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-ventura2.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-ventura2.dts
new file mode 100644
index 000000000000..e22bbaf519ea
--- /dev/null
+++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-ventura2.dts
@@ -0,0 +1,2945 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2023 Facebook Inc.
+/dts-v1/;
+
+#include "aspeed-g6.dtsi"
+#include <dt-bindings/i2c/i2c.h>
+#include <dt-bindings/gpio/aspeed-gpio.h>
+
+/ {
+	model = "Facebook ventura2 RMC";
+	compatible = "facebook,ventura2-rmc", "aspeed,ast2600";
+	aliases {
+		serial4 = &uart5;
+
+		/*
+		 * i2c switch 0-0077, pca9548, 8 child channels assigned
+		 * with bus number 16-23.
+		 */
+		i2c16 = &i2c0mux0ch0;
+		i2c17 = &i2c0mux0ch1;
+		i2c18 = &i2c0mux0ch2;
+		i2c19 = &i2c0mux0ch3;
+		i2c20 = &i2c0mux0ch4;
+		i2c21 = &i2c0mux0ch5;
+		i2c22 = &i2c0mux0ch6;
+		i2c23 = &i2c0mux0ch7;
+
+		/*
+		 * i2c switch 1-0077, pca9548, 8 child channels assigned
+		 * with bus number 24-31.
+		 */
+		i2c24 = &i2c1mux0ch0;
+		i2c25 = &i2c1mux0ch1;
+		i2c26 = &i2c1mux0ch2;
+		i2c27 = &i2c1mux0ch3;
+		i2c28 = &i2c1mux0ch4;
+		i2c29 = &i2c1mux0ch5;
+		i2c30 = &i2c1mux0ch6;
+		i2c31 = &i2c1mux0ch7;
+
+		/*
+		 * i2c switch 4-0077, pca9548, 8 child channels assigned
+		 * with bus number 32-39.
+		 */
+		i2c32 = &i2c4mux0ch0;
+		i2c33 = &i2c4mux0ch1;
+		i2c34 = &i2c4mux0ch2;
+		i2c35 = &i2c4mux0ch3;
+		i2c36 = &i2c4mux0ch4;
+		i2c37 = &i2c4mux0ch5;
+		i2c38 = &i2c4mux0ch6;
+		i2c39 = &i2c4mux0ch7;
+
+		/*
+		 * i2c switch 5-0077, pca9548, 8 child channels assigned
+		 * with bus number 40-47.
+		 */
+		i2c40 = &i2c5mux0ch0;
+		i2c41 = &i2c5mux0ch1;
+		i2c42 = &i2c5mux0ch2;
+		i2c43 = &i2c5mux0ch3;
+		i2c44 = &i2c5mux0ch4;
+		i2c45 = &i2c5mux0ch5;
+		i2c46 = &i2c5mux0ch6;
+		i2c47 = &i2c5mux0ch7;
+
+		/*
+		 * i2c switch 8-0077, pca9548, 8 child channels assigned
+		 * with bus number 48-55.
+		 */
+		i2c48 = &i2c8mux0ch0;
+		i2c49 = &i2c8mux0ch1;
+		i2c50 = &i2c8mux0ch2;
+		i2c51 = &i2c8mux0ch3;
+		i2c52 = &i2c8mux0ch4;
+		i2c53 = &i2c8mux0ch5;
+		i2c54 = &i2c8mux0ch6;
+		i2c55 = &i2c8mux0ch7;
+
+		/*
+		 * i2c switch 11-0077, pca9548, 8 child channels assigned
+		 * with bus number 56-63.
+		 */
+		i2c56 = &i2c11mux0ch0;
+		i2c57 = &i2c11mux0ch1;
+		i2c58 = &i2c11mux0ch2;
+		i2c59 = &i2c11mux0ch3;
+		i2c60 = &i2c11mux0ch4;
+		i2c61 = &i2c11mux0ch5;
+		i2c62 = &i2c11mux0ch6;
+		i2c63 = &i2c11mux0ch7;
+
+		/*
+		 * i2c switch 13-0077, pca9548, 8 child channels assigned
+		 * with bus number 64-71.
+		 */
+		i2c64 = &i2c13mux0ch0;
+		i2c65 = &i2c13mux0ch1;
+		i2c66 = &i2c13mux0ch2;
+		i2c67 = &i2c13mux0ch3;
+		i2c68 = &i2c13mux0ch4;
+		i2c69 = &i2c13mux0ch5;
+		i2c70 = &i2c13mux0ch6;
+		i2c71 = &i2c13mux0ch7;
+
+		/*
+		 * i2c switch 15-0077, pca9548, 8 child channels assigned
+		 * with bus number 72-79.
+		 */
+		i2c72 = &i2c15mux0ch0;
+		i2c73 = &i2c15mux0ch1;
+		i2c74 = &i2c15mux0ch2;
+		i2c75 = &i2c15mux0ch3;
+		i2c76 = &i2c15mux0ch4;
+		i2c77 = &i2c15mux0ch5;
+		i2c78 = &i2c15mux0ch6;
+		i2c79 = &i2c15mux0ch7;
+	};
+
+	chosen {
+		stdout-path = "serial4:57600n8";
+	};
+
+	iio-hwmon {
+		compatible = "iio-hwmon";
+		io-channels = <&adc0 0>, <&adc0 1>, <&adc0 2>, <&adc0 3>,
+		<&adc0 4>, <&adc0 5>, <&adc0 6>, <&adc0 7>,
+		<&adc1 2>;
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		led-0 {
+			label = "bmc_heartbeat_amber";
+			gpios = <&gpio0 ASPEED_GPIO(P, 7) GPIO_ACTIVE_LOW>;
+			linux,default-trigger = "heartbeat";
+		};
+
+		led-1 {
+			label = "fp_id_amber";
+			default-state = "off";
+			gpios = <&gpio0 ASPEED_GPIO(B, 5) GPIO_ACTIVE_HIGH>;
+		};
+
+		led-2 {
+			label = "bmc_ready_noled";
+			default-state = "on";
+			gpios = <&gpio0 ASPEED_GPIO(B, 3) (GPIO_ACTIVE_HIGH|GPIO_TRANSITORY)>;
+		};
+
+		led-3 {
+			label = "power_blue";
+			default-state = "off";
+			gpios = <&gpio0 ASPEED_GPIO(P, 4) GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	fan_leds {
+		compatible = "gpio-leds";
+
+		led-0 {
+			label = "fcb0fan0_ledd1_blue";
+			default-state = "off";
+			gpios = <&fan_io_expander0 0 GPIO_ACTIVE_LOW>;
+		};
+
+		led-1 {
+			label = "fcb0fan1_ledd2_blue";
+			default-state = "off";
+			gpios = <&fan_io_expander0 1 GPIO_ACTIVE_LOW>;
+		};
+
+		led-2 {
+			label = "fcb0fan2_ledd3_blue";
+			default-state = "off";
+			gpios = <&fan_io_expander1 0 GPIO_ACTIVE_LOW>;
+		};
+
+		led-3 {
+			label = "fcb0fan3_ledd4_blue";
+			default-state = "off";
+			gpios = <&fan_io_expander1 1 GPIO_ACTIVE_LOW>;
+		};
+
+		led-4 {
+			label = "fcb0fan0_ledd1_amber";
+			default-state = "off";
+			gpios = <&fan_io_expander0 4 GPIO_ACTIVE_LOW>;
+		};
+
+		led-5 {
+			label = "fcb0fan1_ledd2_amber";
+			default-state = "off";
+			gpios = <&fan_io_expander0 5 GPIO_ACTIVE_LOW>;
+		};
+
+		led-6 {
+			label = "fcb0fan2_ledd3_amber";
+			default-state = "off";
+			gpios = <&fan_io_expander1 4 GPIO_ACTIVE_LOW>;
+		};
+
+		led-7 {
+			label = "fcb0fan3_ledd4_amber";
+			default-state = "off";
+			gpios = <&fan_io_expander1 5 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	memory at 80000000 {
+		device_type = "memory";
+		reg = <0x80000000 0x80000000>;
+	};
+
+	p1v8_bmc_aux: regulator-p1v8-bmc-aux {
+		compatible = "regulator-fixed";
+		regulator-name = "p1v8_bmc_aux";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-always-on;
+	};
+
+	p2v5_bmc_aux: regulator-p2v5-bmc-aux {
+		compatible = "regulator-fixed";
+		regulator-name = "p2v5_bmc_aux";
+		regulator-min-microvolt = <2500000>;
+		regulator-max-microvolt = <2500000>;
+		regulator-always-on;
+	};
+
+	p5v_dac_aux: regulator-p5v-bmc-aux {
+		compatible = "regulator-fixed";
+		regulator-name = "p5v_dac_aux";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+	};
+
+	spi1_gpio: spi {
+		compatible = "spi-gpio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		sck-gpios = <&gpio0 ASPEED_GPIO(Z, 3) GPIO_ACTIVE_HIGH>;
+		mosi-gpios = <&gpio0 ASPEED_GPIO(Z, 4) GPIO_ACTIVE_HIGH>;
+		miso-gpios = <&gpio0 ASPEED_GPIO(Z, 5) GPIO_ACTIVE_HIGH>;
+		cs-gpios = <&gpio0 ASPEED_GPIO(Z, 0) GPIO_ACTIVE_LOW>;
+		num-chipselects = <1>;
+
+		tpm at 0 {
+			compatible = "infineon,slb9670", "tcg,tpm_tis-spi";
+			spi-max-frequency = <33000000>;
+			reg = <0>;
+		};
+	};
+};
+
+&fmc {
+	status = "okay";
+	flash at 0 {
+		status = "okay";
+		m25p,fast-read;
+		label = "bmc";
+		spi-max-frequency = <50000000>;
+		#include "openbmc-flash-layout-128.dtsi"
+	};
+	flash at 1 {
+		status = "okay";
+		m25p,fast-read;
+		label = "alt-bmc";
+		spi-max-frequency = <50000000>;
+	};
+};
+
+&peci0 {
+	status = "okay";
+};
+
+&mac2 {
+	status = "okay";
+	phy-mode = "rmii";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_rmii3_default>;
+	fixed-link {
+		speed = <100>;
+		full-duplex;
+	};
+};
+
+&mac3 {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_rmii4_default>;
+	use-ncsi;
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&ehci1 {
+	status = "okay";
+};
+
+&adc0 {
+	vref-supply = <&p1v8_bmc_aux>;
+	status = "okay";
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_adc0_default &pinctrl_adc1_default
+	&pinctrl_adc2_default &pinctrl_adc3_default
+	&pinctrl_adc4_default &pinctrl_adc5_default
+	&pinctrl_adc6_default &pinctrl_adc7_default>;
+};
+
+&adc1 {
+	vref-supply = <&p2v5_bmc_aux>;
+	status = "okay";
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_adc8_default &pinctrl_adc10_default>;
+};
+
+&gpio0 {
+	gpio-line-names =
+	/*A0-A7*/	"","","","","","","","",
+	/*B0-B7*/	"BATTERY_DETECT","","","BMC_READY_R",
+				"","FM_ID_LED","","",
+	/*C0-C7*/	"","","","","","","","",
+	/*D0-D7*/	"","","","","","","","",
+	/*E0-E7*/	"","","","","","","","",
+	/*F0-F7*/	"","","","","","","","",
+	/*G0-G7*/	"FM_MUX1_SEL_R","","","",
+				"","","","",
+	/*H0-H7*/	"","","","","","","","",
+	/*I0-I7*/	"","","","","","","","",
+	/*J0-J7*/	"","","","","","","","",
+	/*K0-K7*/	"","","","","","","","",
+	/*L0-L7*/	"","","","","","","","",
+	/*M0-M7*/	"","","","","","","","",
+	/*N0-N7*/	"LED_POSTCODE_0","LED_POSTCODE_1",
+				"LED_POSTCODE_2","LED_POSTCODE_3",
+				"LED_POSTCODE_4","LED_POSTCODE_5",
+				"LED_POSTCODE_6","LED_POSTCODE_7",
+	/*O0-O7*/	"","","","","","","","",
+	/*P0-P7*/	"PWR_BTN_BMC_BUF_N","","ID_RST_BTN_BMC_N","",
+				"PWR_LED","","","BMC_HEARTBEAT_N",
+	/*Q0-Q7*/	"","","","","","","","",
+	/*R0-R7*/	"","","","","","","","",
+	/*S0-S7*/	"","","","","","","","",
+	/*T0-T7*/	"","","","","","","","",
+	/*U0-U7*/	"","","","","","","","",
+	/*V0-V7*/	"","","","","","","","",
+	/*W0-W7*/	"","","","","","","","",
+	/*X0-X7*/	"","","","","","","","",
+	/*Y0-Y7*/	"","","","","","","","",
+	/*Z0-Z7*/	"","","","","","","","";
+};
+
+&gpio1 {
+	gpio-line-names =
+	/*18A0-18A7*/	"","","","","","","","",
+	/*18B0-18B7*/	"","","","",
+					"FM_BOARD_BMC_REV_ID0","FM_BOARD_BMC_REV_ID1",
+					"FM_BOARD_BMC_REV_ID2","",
+	/*18C0-18C7*/	"SPI_BMC_BIOS_ROM_IRQ0_R_N","","","","","","","",
+	/*18D0-18D7*/	"","","","","","","","",
+	/*18E0-18E3*/	"FM_BMC_PROT_LS_EN","AC_PWR_BMC_BTN_R_N","","";
+};
+
+&sgpiom0 {
+	status = "okay";
+	ngpios = <128>;
+	bus-frequency = <2000000>;
+	gpio-line-names =
+	/*"input pin","output pin"*/
+	/*A0 - A7*/
+	"power-chassis-good","FM_PLD_HEARTBEAT_LVC3_R",
+	"host0-ready","",
+	"CONTROL_VT2_SUPPLY1_CLOSE","FM_MDIO_SW_SEL_PLD",
+	"CONTROL_VT2_SUPPLY2_CLOSE","FM_88E6393X_BIN_UPDATE_EN_N",
+	"CONTROL_VT2_SUPPLY3_CLOSE","Sequence_TransFR_Alert",
+	"RETURN_CNTL1_FB","WATER_VALVE1_OPEN",
+	"RETURN_CNTL2_FB","WATER_VALVE2_OPEN",
+	"RETURN_CNTL3_FB","WATER_VALVE3_OPEN",
+	/*B0 - B7*/
+	"IT_STOP_PUMP_R_CPLD","WATER_VALVE1_CLOSE",
+	"IT_STOP_PUMP_SPARE_R_CPLD","WATER_VALVE2_CLOSE",
+	"IT_STOP_PUMP_2_R_CPLD","WATER_VALVE3_CLOSE",
+	"IT_STOP_PUMP_SPARE_2_R_CPLD","REPORT_VT2_SUPPLY1_CLOSE",
+	"RPU_2_READY_SPARE_PLD_R","REPORT_VT2_SUPPLY2_CLOSE",
+	"RPU_2_READY_PLD_R","REPORT_VT2_SUPPLY3_CLOSE",
+	"RPU_READY_SPARE_PLD_R","PCIE_SSD1_PRSNT_N",
+	"RPU_READY_PLD_R","",
+	/*C0 - C7*/
+	"IOEXP8_INT_N","",
+	"SUPPLY_CNTL1_FB","",
+	"SUPPLY_CNTL2_FB","",
+	"SUPPLY_CNTL3_FB","",
+	"PRSNT_TRAY1_TO_40_R_BUF_N","",
+	"PWRGD_TRAY1_TO_40_R_BUF","",
+	"SMALL_LEAK_TRAY1_TO_40_R_BUF_N","",
+	"LEAK_DETECT_TRAY1_TO_40_R_BUF_N","",
+	/*D0 - D7*/
+	"PRSNT_CANBUSP1_TRAY1_TO_32_N","",
+	"PWRGD_CANBUSP1_TRAY1_TO_32_PWROK","",
+	"SMALL_LEAK_CANBUSP1_TRAY1_TO_32_N","",
+	"LEAK_DETECT_CANBUSP1_TRAY1_TO_32_N","",
+	"PRSNT_CANBUSP2_TRAY1_TO_32_N","",
+	"PWRGD_CANBUSP2_TRAY1_TO_32_PWROK","",
+	"SMALL_LEAK_CANBUSP2_TRAY1_TO_32_N","",
+	"LEAK_DETECT_CANBUSP2_TRAY1_TO_32_N","",
+	/*E0 - E7*/
+	"PRSNT_CANBUSP3_TRAY1_TO_32_N","",
+	"PWRGD_CANBUSP3_TRAY1_TO_32_PWROK","",
+	"SMALL_LEAK_CANBUSP3_TRAY1_TO_32_N","",
+	"LEAK_DETECT_CANBUSP3_TRAY1_TO_32_N","",
+	"PRSNT_CANBUSP4_TRAY1_TO_32_N","",
+	"PWRGD_CANBUSP4_TRAY1_TO_32_PWROK","",
+	"SMALL_LEAK_CANBUSP4_TRAY1_TO_32_N","",
+	"LEAK_DETECT_CANBUSP4_TRAY1_TO_32_N","",
+	/*F0 - F7*/
+	"PRSNT_CANBUSP5_TRAY1_TO_32_N","",
+	"PWRGD_CANBUSP5_TRAY1_TO_32_PWROK","",
+	"SMALL_LEAK_CANBUSP5_TRAY1_TO_32_N","",
+	"LEAK_DETECT_CANBUSP5_TRAY1_TO_32_N","",
+	"PRSNT_CANBUSP6_TRAY1_TO_32_N","",
+	"PWRGD_CANBUSP6_TRAY1_TO_32_PWROK","",
+	"SMALL_LEAK_CANBUSP6_TRAY1_TO_32_N","",
+	"LEAK_DETECT_CANBUSP6_TRAY1_TO_32_N","",
+	/*G0 - G7*/
+	"PRSNT_CANBUSP7_TRAY1_TO_32_N","",
+	"PWRGD_CANBUSP7_TRAY1_TO_32_PWROK","",
+	"SMALL_LEAK_CANBUSP7_TRAY1_TO_32_N","",
+	"LEAK_DETECT_CANBUSP7_TRAY1_TO_32_N","",
+	"PRSNT_CANBUSP8_TRAY1_TO_32_N","",
+	"PWRGD_CANBUSP8_TRAY1_TO_32_PWROK","",
+	"SMALL_LEAK_CANBUSP8_TRAY1_TO_32_N","",
+	"LEAK_DETECT_CANBUSP8_TRAY1_TO_32_N","",
+	/*H0 - H7*/
+	"wCHASSIS0_LEAK_Q_N_R","",
+	"wCHASSIS1_LEAK_Q_N_R","",
+	"wCHASSIS2_LEAK_Q_N_R","",
+	"wCHASSIS3_LEAK_Q_N_R","",
+	"wCHASSIS4_LEAK_Q_N_R","",
+	"wCHASSIS5_LEAK_Q_N_R","",
+	"wCHASSIS6_LEAK_Q_N_R","",
+	"wCHASSIS7_LEAK_Q_N_R","",
+	/*I0 - I7*/
+	"wCHASSIS8_LEAK_Q_N_R","",
+	"wCHASSIS9_LEAK_Q_N_R","",
+	"wCHASSIS10_LEAK_Q_N_R","",
+	"wCHASSIS11_LEAK_Q_N_R","",
+	"wAALC_RPU_READY","",
+	"","",
+	"","",
+	"","",
+	/*J0 - J7*/
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
+	/*K0 - K7*/
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
+	/*L0 - L7*/
+	"wIT_GEAR_RPU_2_LINK_PRSNT_SPARE_N_R","",
+	"wIT_GEAR_RPU_2_LINK_PRSNT_N_R","",
+	"wIT_GEAR_RPU_LINK_PRSNT_SPARE_N_R","",
+	"wIT_GEAR_RPU_LINK_PRSNT_N_R","",
+	"","",
+	"","",
+	"","",
+	"","",
+	/*M0 - M7*/
+	"","",
+	"","",
+	"wPRSNT_SENSOR_N","",
+	"wPRSNT3_VT2_PLD_N","",
+	"wPRSNT2_VT2_PLD_N","",
+	"wPRSNT1_VT2_PLD_N","",
+	"wPRSNT3_RETURN_PLD_N","",
+	"wPRSNT2_RETURN_PLD_N","",
+	/*N0 - N7*/
+	"wPRSNT1_RETURN_PLD_N","",
+	"wPRSNT3_SUPPLY_PLD_N","",
+	"wPRSNT2_SUPPLY_PLD_N","",
+	"wPRSNT1_SUPPLY_PLD_N","",
+	"wPRSNT_LEAK11_SENSOR_R_PLD_N","",
+	"wPRSNT_LEAK10_SENSOR_R_PLD_N","",
+	"wPRSNT_LEAK9_SENSOR_R_PLD_N","",
+	"wPRSNT_LEAK8_SENSOR_R_PLD_N","",
+	/*O0 - O7*/
+	"wPRSNT_LEAK7_SENSOR_R_PLD_N","",
+	"wPRSNT_LEAK6_SENSOR_R_PLD_N","",
+	"wPRSNT_LEAK5_SENSOR_R_PLD_N","",
+	"wPRSNT_LEAK4_SENSOR_R_PLD_N","",
+	"wPRSNT_LEAK3_SENSOR_R_PLD_N","",
+	"wPRSNT_LEAK2_SENSOR_R_PLD_N","",
+	"wPRSNT_LEAK1_SENSOR_R_PLD_N","",
+	"wPRSNT_LEAK0_SENSOR_R_PLD_N","",
+	/*P0 - P7*/
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
+	"","",
+	"","";
+};
+
+&wdt1 {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_wdtrst1_default>;
+	aspeed,reset-type = "soc";
+	aspeed,external-signal;
+	aspeed,ext-push-pull;
+	aspeed,ext-active-high;
+	aspeed,ext-pulse-duration = <256>;
+};
+
+&i2c0 {
+	status = "okay";
+
+	i2c-mux at 77 {
+		compatible = "nxp,pca9548";
+		reg = <0x77>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		i2c0mux0ch0: i2c at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+			temp-sensor at 4c {
+				compatible = "adi,adt7461";
+				reg = <0x4c>;
+			};
+		};
+
+		i2c0mux0ch1: i2c at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+			temp-sensor at 4c {
+				compatible = "adi,adt7461";
+				reg = <0x4c>;
+			};
+		};
+
+		i2c0mux0ch2: i2c at 2 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2>;
+			status = "okay";
+		};
+
+		i2c0mux0ch3: i2c at 3 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <3>;
+			status = "okay";
+		};
+
+		i2c0mux0ch4: i2c at 4 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <4>;
+			status = "okay";
+		};
+
+		i2c0mux0ch5: i2c at 5 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <5>;
+			status = "okay";
+
+			eeprom at 56 {
+				compatible = "atmel,24c128";
+				reg = <0x56>;
+			};
+		};
+
+		i2c0mux0ch6: i2c at 6 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <6>;
+
+			eeprom at 56 {
+				compatible = "atmel,24c128";
+				reg = <0x56>;
+			};
+
+			fan_io_expander0: gpio at 20 {
+				compatible = "nxp,pca9555";
+				reg = <0x20>;
+				gpio-controller;
+				#gpio-cells = <2>;
+			};
+
+			fan_io_expander1: gpio at 21 {
+				compatible = "nxp,pca9555";
+				reg = <0x21>;
+				gpio-controller;
+				#gpio-cells = <2>;
+			};
+
+			adc at 1d {
+				compatible = "ti,adc128d818";
+				reg = <0x1d>;
+				ti,mode = /bits/ 8 <1>;
+			};
+
+			adc at 35 {
+				compatible = "maxim,max11617";
+				reg = <0x35>;
+			};
+		};
+
+		i2c0mux0ch7: i2c at 7 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <7>;
+
+			fanctl0: fan-controller at 20 {
+				compatible = "maxim,max31790";
+				reg = <0x20>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+
+			fanctl1: fan-controller at 23 {
+				compatible = "nuvoton,nct7363";
+				reg = <0x23>;
+				#pwm-cells = <2>;
+
+				fan-9 {
+					pwms = <&fanctl1 0 20000>;
+					tach-ch = /bits/ 8 <0x09>;
+				};
+
+				fan-11 {
+					pwms = <&fanctl1 0 20000>;
+					tach-ch = /bits/ 8 <0x0B>;
+				};
+
+				fan-10 {
+					pwms = <&fanctl1 4 20000>;
+					tach-ch = /bits/ 8 <0x0A>;
+				};
+
+				fan-13 {
+					pwms = <&fanctl1 4 20000>;
+					tach-ch = /bits/ 8 <0x0D>;
+				};
+
+				fan-15 {
+					pwms = <&fanctl1 6 20000>;
+					tach-ch = /bits/ 8 <0x0F>;
+				};
+
+				fan-1 {
+					pwms = <&fanctl1 6 20000>;
+					tach-ch = /bits/ 8 <0x01>;
+				};
+
+				fan-0 {
+					pwms = <&fanctl1 10 20000>;
+					tach-ch = /bits/ 8 <0x00>;
+				};
+
+				fan-3 {
+					pwms = <&fanctl1 10 20000>;
+					tach-ch = /bits/ 8 <0x03>;
+				};
+			};
+		};
+	};
+};
+
+&i2c1 {
+	status = "okay";
+
+	i2c-mux at 77 {
+		compatible = "nxp,pca9548";
+		reg = <0x77>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		i2c1mux0ch0: i2c at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+			status = "okay";
+		};
+
+		i2c1mux0ch1: i2c at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+			status = "okay";
+		};
+
+		i2c1mux0ch2: i2c at 2 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2>;
+			status = "okay";
+		};
+
+		i2c1mux0ch3: i2c at 3 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <3>;
+			status = "okay";
+		};
+
+		i2c1mux0ch4: i2c at 4 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <4>;
+			status = "okay";
+		};
+
+		i2c1mux0ch5: i2c at 5 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <5>;
+			status = "okay";
+		};
+
+		i2c1mux0ch6: i2c at 6 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <6>;
+			status = "okay";
+		};
+
+		i2c1mux0ch7: i2c at 7 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <7>;
+			status = "okay";
+		};
+	};
+};
+
+&i2c2 {
+	status = "okay";
+	bus-frequency = <400000>;
+};
+
+&i2c3 {
+	status = "okay";
+	bus-frequency = <400000>;
+
+	dac at c {
+		reg = <0x0c>;
+		compatible = "adi,ad5612";
+		vcc-supply = <&p5v_dac_aux>;
+	};
+
+	dac at e {
+		reg = <0x0e>;
+		compatible = "adi,ad5612";
+		vcc-supply = <&p5v_dac_aux>;
+	};
+
+	dac at f {
+		reg = <0x0f>;
+		compatible = "adi,ad5612";
+		vcc-supply = <&p5v_dac_aux>;
+	};
+
+	prsnt_io_expander0: gpio at 30 {
+		compatible = "nxp,pca9698";
+		reg = <0x30>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <48 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	prsnt_io_expander1: gpio at 31 {
+		compatible = "nxp,pca9698";
+		reg = <0x31>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <56 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	prsnt_io_expander2: gpio at 32 {
+		compatible = "nxp,pca9698";
+		reg = <0x32>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <64 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	prsnt_io_expander3: gpio at 33 {
+		compatible = "nxp,pca9698";
+		reg = <0x33>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <72 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	prsnt_io_expander4: gpio at 34 {
+		compatible = "nxp,pca9698";
+		reg = <0x34>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <80 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	prsnt_io_expander5: gpio at 35 {
+		compatible = "nxp,pca9698";
+		reg = <0x35>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <88 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	prsnt_io_expander6: gpio at 36 {
+		compatible = "nxp,pca9698";
+		reg = <0x36>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <96 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	prsnt_io_expander7: gpio at 37 {
+		compatible = "nxp,pca9698";
+		reg = <0x37>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <104 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	pwrgd_io_expander0: gpio at 38 {
+		compatible = "nxp,pca9698";
+		reg = <0x38>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <50 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	pwrgd_io_expander1: gpio at 39 {
+		compatible = "nxp,pca9698";
+		reg = <0x39>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <58 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	pwrgd_io_expander2: gpio at 3a {
+		compatible = "nxp,pca9698";
+		reg = <0x3a>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <66 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	pwrgd_io_expander3: gpio at 3b {
+		compatible = "nxp,pca9698";
+		reg = <0x3b>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <74 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	pwrgd_io_expander4: gpio at 3c {
+		compatible = "nxp,pca9698";
+		reg = <0x3c>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <82 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	pwrgd_io_expander5: gpio at 3d {
+		compatible = "nxp,pca9698";
+		reg = <0x3d>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <90 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	pwrgd_io_expander6: gpio at 3e {
+		compatible = "nxp,pca9698";
+		reg = <0x3e>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <98 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	pwrgd_io_expander7: gpio at 3f {
+		compatible = "nxp,pca9698";
+		reg = <0x3f>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <106 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	large_leak_io_expander0: gpio at 40 {
+		compatible = "nxp,pca9698";
+		reg = <0x40>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <54 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	large_leak_io_expander1: gpio at 41 {
+		compatible = "nxp,pca9698";
+		reg = <0x41>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <62 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	large_leak_io_expander2: gpio at 42 {
+		compatible = "nxp,pca9698";
+		reg = <0x42>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <70 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	large_leak_io_expander3: gpio at 43 {
+		compatible = "nxp,pca9698";
+		reg = <0x43>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <78 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	large_leak_io_expander4: gpio at 44 {
+		compatible = "nxp,pca9698";
+		reg = <0x44>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <86 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	large_leak_io_expander5: gpio at 45 {
+		compatible = "nxp,pca9698";
+		reg = <0x45>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <94 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	large_leak_io_expander6: gpio at 46 {
+		compatible = "nxp,pca9698";
+		reg = <0x46>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <102 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	large_leak_io_expander7: gpio at 47 {
+		compatible = "nxp,pca9698";
+		reg = <0x47>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <110 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	small_leak_io_expander0: gpio at 48 {
+		compatible = "nxp,pca9698";
+		reg = <0x48>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <52 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	small_leak_io_expander1: gpio at 49 {
+		compatible = "nxp,pca9698";
+		reg = <0x49>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <60 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	small_leak_io_expander2: gpio at 4a {
+		compatible = "nxp,pca9698";
+		reg = <0x4a>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <68 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	small_leak_io_expander3: gpio at 4b {
+		compatible = "nxp,pca9698";
+		reg = <0x4b>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <76 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	small_leak_io_expander4: gpio at 4c {
+		compatible = "nxp,pca9698";
+		reg = <0x4c>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <84 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	small_leak_io_expander5: gpio at 4d {
+		compatible = "nxp,pca9698";
+		reg = <0x4d>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <92 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	small_leak_io_expander6: gpio at 4e {
+		compatible = "nxp,pca9698";
+		reg = <0x4e>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <100 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	small_leak_io_expander7: gpio at 4f {
+		compatible = "nxp,pca9698";
+		reg = <0x4f>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <108 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	io_expander6: gpio at 23 {
+		compatible = "nxp,pca9555";
+		reg = <0x23>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+};
+
+&i2c4 {
+	status = "okay";
+
+	i2c-mux at 77 {
+		compatible = "nxp,pca9548";
+		reg = <0x77>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		i2c4mux0ch0: i2c at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			io_expander3: gpio at 23 {
+				compatible = "nxp,pca9555";
+				reg = <0x23>;
+				gpio-controller;
+				#gpio-cells = <2>;
+			};
+		};
+
+		i2c4mux0ch1: i2c at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			temp-sensor at 48 {
+				compatible = "ti,tmp75";
+				reg = <0x48>;
+			};
+
+			temp-sensor at 4a {
+				compatible = "ti,tmp75";
+				reg = <0x4a>;
+			};
+
+			eeprom at 56 {
+				compatible = "atmel,24c128";
+				reg = <0x56>;
+			};
+
+			power-monitor at 76 {
+				compatible = "infineon,xdpe15284";
+				reg = <0x76>;
+			};
+		};
+
+		i2c4mux0ch2: i2c at 2 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2>;
+			status = "okay";
+		};
+
+		i2c4mux0ch3: i2c at 3 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <3>;
+			status = "okay";
+		};
+
+		i2c4mux0ch4: i2c at 4 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <4>;
+			status = "okay";
+		};
+
+		i2c4mux0ch5: i2c at 5 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <5>;
+			status = "okay";
+		};
+
+		i2c4mux0ch6: i2c at 6 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <6>;
+			status = "okay";
+		};
+
+		i2c4mux0ch7: i2c at 7 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <7>;
+			status = "okay";
+		};
+	};
+};
+
+&i2c5 {
+	status = "okay";
+
+	io_expander4: gpio at 22 {
+		compatible = "nxp,pca9555";
+		reg = <0x22>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	io_expander5: gpio at 23 {
+		compatible = "nxp,pca9555";
+		reg = <0x23>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	temp-sensor at 4f {
+		compatible = "ti,tmp75";
+		reg = <0x4f>;
+	};
+
+	eeprom at 54 {
+		compatible = "atmel,24c128";
+		reg = <0x54>;
+	};
+
+	i2c-mux at 77 {
+		compatible = "nxp,pca9548";
+		reg = <0x77>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		i2c5mux0ch0: i2c at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+		};
+
+		i2c5mux0ch1: i2c at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+		};
+
+		i2c5mux0ch2: i2c at 2 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2>;
+
+			eeprom at 56 {
+				compatible = "atmel,24c128";
+				reg = <0x56>;
+			};
+		};
+
+		i2c5mux0ch3: i2c at 3 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <3>;
+
+			eeprom at 56 {
+				compatible = "atmel,24c128";
+				reg = <0x56>;
+			};
+		};
+
+		i2c5mux0ch4: i2c at 4 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <4>;
+
+			eeprom at 56 {
+				compatible = "atmel,24c128";
+				reg = <0x56>;
+			};
+		};
+
+		i2c5mux0ch5: i2c at 5 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <5>;
+
+			eeprom at 56 {
+				compatible = "atmel,24c128";
+				reg = <0x56>;
+			};
+		};
+
+		i2c5mux0ch6: i2c at 6 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <6>;
+
+			eeprom at 56 {
+				compatible = "atmel,24c128";
+				reg = <0x56>;
+			};
+		};
+
+		i2c5mux0ch7: i2c at 7 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <7>;
+
+			eeprom at 56 {
+				compatible = "atmel,24c128";
+				reg = <0x56>;
+			};
+		};
+	};
+};
+
+&i2c6 {
+	status = "okay";
+
+	eeprom at 50 {
+		compatible = "atmel,24c64";
+		reg = <0x50>;
+	};
+
+	io_expander0: gpio at 20 {
+		compatible = "nxp,pca9555";
+		reg = <0x20>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	io_expander1: gpio at 21 {
+		compatible = "nxp,pca9555";
+		reg = <0x21>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	io_expander2: gpio at 22 {
+		compatible = "nxp,pca9555";
+		reg = <0x22>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	io_expander7: gpio at 23 {
+		compatible = "nxp,pca9555";
+		reg = <0x23>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	rtc at 51 {
+		compatible = "nxp,pcf8563";
+		reg = <0x51>;
+	};
+};
+
+&i2c7 {
+	status = "okay";
+	bus-frequency = <100000>;
+	multi-master;
+	aspeed,hw-timeout-ms = <1000>;
+
+	ipmb at 10 {
+		compatible = "ipmb-dev";
+		reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>;
+		i2c-protocol;
+	};
+};
+
+&i2c8 {
+	status = "okay";
+
+	i2c-mux at 77 {
+		compatible = "nxp,pca9548";
+		reg = <0x77>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		i2c8mux0ch0: i2c at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+			status = "okay";
+		};
+
+		i2c8mux0ch1: i2c at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+			status = "okay";
+		};
+
+		i2c8mux0ch2: i2c at 2 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2>;
+			status = "okay";
+		};
+
+		i2c8mux0ch3: i2c at 3 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <3>;
+			status = "okay";
+		};
+
+		i2c8mux0ch4: i2c at 4 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <4>;
+			status = "okay";
+		};
+
+		i2c8mux0ch5: i2c at 5 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <5>;
+			status = "okay";
+		};
+
+		i2c8mux0ch6: i2c at 6 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <6>;
+			status = "okay";
+		};
+
+		i2c8mux0ch7: i2c at 7 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <7>;
+			status = "okay";
+		};
+	};
+};
+
+&i2c9 {
+	status = "okay";
+
+	temperature-sensor at 4b {
+		compatible = "ti,tmp75";
+		reg = <0x4b>;
+	};
+
+	eeprom at 50 {
+		compatible = "atmel,24c128";
+		reg = <0x50>;
+	};
+
+	eeprom at 51 {
+		compatible = "atmel,24c128";
+		reg = <0x51>;
+	};
+
+	eeprom at 56 {
+		compatible = "atmel,24c64";
+		reg = <0x56>;
+	};
+};
+
+&i2c10 {
+	status = "okay";
+
+	power-sensor at 41 {
+		compatible = "ti,ina238";
+		reg = <0x41>;
+		shunt-resistor = <20000>;
+	};
+
+	power-sensor at 42 {
+		compatible = "ti,ina238";
+		reg = <0x42>;
+		shunt-resistor = <1000>;
+	};
+
+	power-sensor at 43 {
+		compatible = "ti,ina238";
+		reg = <0x43>;
+		shunt-resistor = <20000>;
+	};
+
+	power-sensor at 46 {
+		compatible = "ti,ina238";
+		reg = <0x46>;
+		shunt-resistor = <1000>;
+	};
+
+	adc at 35 {
+		compatible = "maxim,max11617";
+		reg = <0x35>;
+	};
+
+	power-monitor at 14 {
+		compatible = "infineon,xdp710";
+		reg = <0x14>;
+	};
+
+	power-monitor at 44 {
+		compatible = "lltc,ltc4287";
+		reg = <0x44>;
+	};
+
+	power-monitor at 40 {
+		compatible = "ti,ina230";
+		reg = <0x40>;
+		shunt-resistor = <1000>;
+	};
+
+	power-monitor at 45 {
+		compatible = "ti,ina230";
+		reg = <0x45>;
+		shunt-resistor = <1000>;
+	};
+
+	adc at 48 {
+		compatible = "ti,ads1015";
+		reg = <0x48>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
+
+	power-monitor at 69 {
+		compatible = "pmbus";
+		reg = <0x69>;
+	};
+
+	temp-sensor at 4d {
+		compatible = "ti,tmp75";
+		reg = <0x4d>;
+	};
+
+	temp-sensor at 4c {
+		compatible = "ti,tmp75";
+		reg = <0x4c>;
+	};
+
+	temp-sensor at 4e {
+		compatible = "ti,tmp75";
+		reg = <0x4e>;
+	};
+
+	legacy_prsnt_io_expander0: gpio at 11 {
+		compatible = "nxp,pca9555";
+		reg = <0x11>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <40 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	legacy_prsnt_io_expander1: gpio at 12 {
+		compatible = "nxp,pca9555";
+		reg = <0x12>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <40 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	legacy_prsnt_io_expander2: gpio at 13 {
+		compatible = "nxp,pca9555";
+		reg = <0x13>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <40 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	legacy_pwrgd_io_expander0: gpio at 28 {
+		compatible = "nxp,pca9555";
+		reg = <0x28>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	legacy_pwrgd_io_expander1: gpio at 15 {
+		compatible = "nxp,pca9555";
+		reg = <0x15>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	legacy_pwrgd_io_expander2: gpio at 16 {
+		compatible = "nxp,pca9555";
+		reg = <0x16>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	legacy_leak_io_expander0: gpio at 17 {
+		compatible = "nxp,pca9555";
+		reg = <0x17>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <46 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	legacy_leak_io_expander1: gpio at 18 {
+		compatible = "nxp,pca9555";
+		reg = <0x18>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <46 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	legacy_leak_io_expander2: gpio at 19 {
+		compatible = "nxp,pca9555";
+		reg = <0x19>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <46 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	legacy_small_leak_io_expander0: gpio at 1a {
+		compatible = "nxp,pca9555";
+		reg = <0x1a>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <44 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	legacy_small_leak_io_expander1: gpio at 1b {
+		compatible = "nxp,pca9555";
+		reg = <0x1b>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <44 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	legacy_small_leak_io_expander2: gpio at 1c {
+		compatible = "nxp,pca9555";
+		reg = <0x1c>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&sgpiom0>;
+		interrupts = <44 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	sku_info_io_expander: gpio at 61 {
+		compatible = "nxp,pca9555";
+		reg = <0x61>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	fpga_io_expander64: gpio at 64 {
+		compatible = "nxp,pca9555";
+		reg = <0x64>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	fpga_io_expander65: gpio at 65 {
+		compatible = "nxp,pca9555";
+		reg = <0x65>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+};
+
+&i2c11 {
+	status = "okay";
+
+	i2c-mux at 77 {
+		compatible = "nxp,pca9548";
+		reg = <0x77>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		i2c11mux0ch0: i2c at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+			status = "okay";
+		};
+
+		i2c11mux0ch1: i2c at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+			status = "okay";
+		};
+
+		i2c11mux0ch2: i2c at 2 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2>;
+			status = "okay";
+		};
+
+		i2c11mux0ch3: i2c at 3 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <3>;
+			status = "okay";
+		};
+
+		i2c11mux0ch4: i2c at 4 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <4>;
+			status = "okay";
+		};
+
+		i2c11mux0ch5: i2c at 5 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <5>;
+			status = "okay";
+		};
+
+		i2c11mux0ch6: i2c at 6 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <6>;
+			status = "okay";
+		};
+
+		i2c11mux0ch7: i2c at 7 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <7>;
+			status = "okay";
+		};
+	};
+};
+
+&i2c12 {
+	status = "okay";
+	bus-frequency = <400000>;
+};
+
+&i2c13 {
+	status = "okay";
+
+	i2c-mux at 77 {
+		compatible = "nxp,pca9548";
+		reg = <0x77>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		i2c13mux0ch0: i2c at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+			status = "okay";
+		};
+
+		i2c13mux0ch1: i2c at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+			status = "okay";
+		};
+
+		i2c13mux0ch2: i2c at 2 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2>;
+			status = "okay";
+		};
+
+		i2c13mux0ch3: i2c at 3 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <3>;
+			status = "okay";
+		};
+
+		i2c13mux0ch4: i2c at 4 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <4>;
+			status = "okay";
+		};
+
+		i2c13mux0ch5: i2c at 5 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <5>;
+			status = "okay";
+		};
+
+		i2c13mux0ch6: i2c at 6 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <6>;
+			status = "okay";
+		};
+
+		i2c13mux0ch7: i2c at 7 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <7>;
+			status = "okay";
+		};
+	};
+};
+
+&i2c14 {
+	status = "okay";
+};
+
+&i2c15 {
+	status = "okay";
+
+	i2c-mux at 77 {
+		compatible = "nxp,pca9548";
+		reg = <0x77>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-mux-idle-disconnect;
+
+		i2c15mux0ch0: i2c at 0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+			status = "okay";
+		};
+
+		i2c15mux0ch1: i2c at 1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+			status = "okay";
+		};
+
+		i2c15mux0ch2: i2c at 2 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2>;
+			status = "okay";
+		};
+
+		i2c15mux0ch3: i2c at 3 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <3>;
+			status = "okay";
+		};
+
+		i2c15mux0ch4: i2c at 4 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <4>;
+			status = "okay";
+		};
+
+		i2c15mux0ch5: i2c at 5 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <5>;
+			status = "okay";
+		};
+
+		i2c15mux0ch6: i2c at 6 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <6>;
+			status = "okay";
+		};
+
+		i2c15mux0ch7: i2c at 7 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <7>;
+			status = "okay";
+		};
+	};
+};
+
+&spi2 {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_spi2_default>;
+
+	flash at 0 {
+		status = "okay";
+		m25p,fast-read;
+		label = "pnor";
+		spi-max-frequency = <12000000>;
+		spi-tx-bus-width = <2>;
+		spi-rx-bus-width = <2>;
+	};
+};
+
+&io_expander0 {
+	gpio-line-names =
+	"RST_POE_BMC_N", "POE_DISABLE_BMC_N_R",
+	"RST_FT4232_1_BMC_N_R", "RST_FT4232_2_BMC_N_R",
+	"RST_FT4232_3_BMC_N_R", "PRSNT_FANBP_0_PWR_N",
+	"PRSNT_FANBP_0_SIG_N", "PRSNT_POE_PWR_N",
+	"PRSNT_POE_SIG_N", "IRQ_POE_BMC_N_R",
+	"PWRGD_P3V3_ISO_POE_BMC_R", "88E6393X_INT_N_R",
+	"P48V_HSC_ALERT_N", "SMB_TMC75_TEMP_ALERT_N_R",
+	"DEV_DIS_N", "PCI_DIS_N";
+};
+
+&io_expander1 {
+	gpio-line-names =
+	"PWRGD_CPU_LVC3_BMC", "R_FM_BIOS_POST_CMPLT_BMC",
+	"RSVD_GPIO_BMC_B16_R", "",
+	"R_FM_CPU_ERR1_LVT3_L", "R_FM_CPU_ERR2_LVT3_L",
+	"", "ISO_FM_BMC_ONCTL_L",
+	"R_COME_THERM_L", "BMC_RST_BTN_N",
+	"", "PCIE_SSD1_PRSNT_N",
+	"", "wTRAY_PWRGD23_N_BUF_R",
+	"wTRAY_PWRGD24_N_BUF_R", "wTRAY_PWRGD29_N_BUF_R";
+};
+
+&io_expander2 {
+	gpio-line-names =
+	"BOARD_ID_0", "BOARD_ID_1",
+	"BOARD_ID_2", "BOARD_ID_3",
+	"SKU_ID_3", "SKU_ID_2",
+	"SKU_ID_1", "SKU_ID_0",
+	"FT4232_1_SUSPEND_BMC_N", "FT4232_1_PWREN_BMC_N",
+	"FT4232_2_SUSPEND_BMC_N", "FT4232_2_PWREN_BMC_N",
+	"FT4232_3_SUSPEND_BMC_N", "FT4232_3_PWREN_BMC_N",
+	"P12V_AUX_SMBALERT_R", "P52V_SENSE_ALERT";
+};
+
+&io_expander3 {
+	gpio-line-names =
+	"RSVD_GPIO_BMC_A12_R", "RSVD_GPIO_BMC_E14_R",
+	"", "RST_I2CRST_MUX1_N",
+	"RST_I2CRST_MUX2_N", "RST_I2CRST_MUX3_N",
+	"RST_I2CRST_MUX4_N", "RST_I2CRST_MUX5_N",
+	"RST_I2CRST_MUX6_N", "RST_I2CRST_MUX7_N",
+	"RST_I2CRST_MUX8_N", "P24V_EFUSE9_FAULT",
+	"wTRAY_PWRGD30_N_BUF_R", "wTRAY_PWRGD31_N_BUF_R",
+	"wTRAY_PWRGD32_N_BUF_R", "wTRAY_PWRGD37_N_BUF_R";
+};
+
+&io_expander4 {
+	gpio-line-names =
+	"R_COME_THERMTRIP_L", "R_PWRGD_PCH_PWROK",
+	"PWRGD_P3V3_STBY_D2", "R_H_MEMHOT_OUT_FET_L",
+	"", "R_FM_SOC_BMC_RST_L",
+	"", "R_FM_PCHHOT_L",
+	"R_FM_CPU_ERR0_LVT3_L", "FM_CPU_DIMM_EVENT_COD_BUF",
+	"R_ISO_FM_USB_OC0_L", "BIOS_DEBUG_MSG_DIS_L",
+	"R_IRQ_BMC_PCH_SMI_N", "wTRAY_PWRGD38_N_BUF_R",
+	"wTRAY_PWRGD39_N_BUF_R", "wTRAY_PWRGD40_N_BUF_R";
+};
+
+&io_expander5 {
+	gpio-line-names =
+	"PWRGD_P5V_AUX_R2", "",
+	"PWRGD_P1V5_AUX_R", "PWRGD_P1V05_AUX_R",
+	"PWRGD_P52V_HSC_PWROK_R", "PWRGD_P24V_AUX_2_R",
+	"PWRGD_P24V_AUX_R", "PWRGD_P12V_AUX_R2",
+	"PWRGD_P12V_SCM_R", "P24V_AUX_INA230_ALERT_N_R",
+	"P24V_AUX_2_INA230_ALERT_N_R", "PRSNT_CAN1_MCIO_N",
+	"PRSNT_CAN2_MCIO_N", "PRSNT_AALC_MCIO_N",
+	"PRSNT_RACKMON_MCIO_N", "PRSNT_RIO_RACKMON_N";
+};
+
+&io_expander6 {
+	gpio-line-names =
+	"P24V_EFUSE1_FAULT", "P24V_EFUSE2_FAULT",
+	"P24V_EFUSE3_FAULT", "P24V_EFUSE4_FAULT",
+	"P24V_EFUSE5_FAULT", "P24V_EFUSE6_FAULT",
+	"TEMP1_ALERT_N_R", "TEMP2_ALERT_N_R",
+	"RST_FT2232_N", "PRSNT_COME_N",
+	"FM_COME_BMC_RM_DEBUG_EN", "SMB_TMC75_TEMP2_ALERT_N_R",
+	"SMB_TMC75_TEMP3_ALERT_N_R", "SMB_TMC75_TEMP4_ALERT_N_R",
+	"P24V_EFUSE7_FAULT", "P24V_EFUSE8_FAULT";
+};
+
+&io_expander7 {
+	gpio-line-names =
+	"IOEXP1_INT_N", "IOEXP2_INT_N",
+	"IOEXP3_INT_N", "IOEXP4_INT_N",
+	"IOEXP5_INT_N", "IOEXP6_INT_N",
+	"IOEXP7_INT_N", "",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&prsnt_io_expander0 {
+	gpio-line-names =
+	"CAN1_TRAY1_PRSNT", "CAN1_TRAY2_PRSNT",
+	"CAN1_TRAY3_PRSNT", "CAN1_TRAY4_PRSNT",
+	"CAN1_TRAY5_PRSNT", "CAN1_TRAY6_PRSNT",
+	"CAN1_TRAY7_PRSNT", "CAN1_TRAY8_PRSNT",
+	"CAN1_TRAY9_PRSNT", "CAN1_TRAY10_PRSNT",
+	"CAN1_TRAY11_PRSNT", "CAN1_TRAY12_PRSNT",
+	"CAN1_TRAY13_PRSNT", "CAN1_TRAY14_PRSNT",
+	"CAN1_TRAY15_PRSNT", "CAN1_TRAY16_PRSNT",
+	"CAN1_TRAY17_PRSNT", "CAN1_TRAY18_PRSNT",
+	"CAN1_TRAY19_PRSNT", "CAN1_TRAY20_PRSNT",
+	"CAN1_TRAY21_PRSNT", "CAN1_TRAY22_PRSNT",
+	"CAN1_TRAY23_PRSNT", "CAN1_TRAY24_PRSNT",
+	"CAN1_TRAY25_PRSNT", "CAN1_TRAY26_PRSNT",
+	"CAN1_TRAY27_PRSNT", "CAN1_TRAY28_PRSNT",
+	"CAN1_TRAY29_PRSNT", "CAN1_TRAY30_PRSNT",
+	"CAN1_TRAY31_PRSNT", "CAN1_TRAY32_PRSNT",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&prsnt_io_expander1 {
+	gpio-line-names =
+	"CAN2_TRAY1_PRSNT", "CAN2_TRAY2_PRSNT",
+	"CAN2_TRAY3_PRSNT", "CAN2_TRAY4_PRSNT",
+	"CAN2_TRAY5_PRSNT", "CAN2_TRAY6_PRSNT",
+	"CAN2_TRAY7_PRSNT", "CAN2_TRAY8_PRSNT",
+	"CAN2_TRAY9_PRSNT", "CAN2_TRAY10_PRSNT",
+	"CAN2_TRAY11_PRSNT", "CAN2_TRAY12_PRSNT",
+	"CAN2_TRAY13_PRSNT", "CAN2_TRAY14_PRSNT",
+	"CAN2_TRAY15_PRSNT", "CAN2_TRAY16_PRSNT",
+	"CAN2_TRAY17_PRSNT", "CAN2_TRAY18_PRSNT",
+	"CAN2_TRAY19_PRSNT", "CAN2_TRAY20_PRSNT",
+	"CAN2_TRAY21_PRSNT", "CAN2_TRAY22_PRSNT",
+	"CAN2_TRAY23_PRSNT", "CAN2_TRAY24_PRSNT",
+	"CAN2_TRAY25_PRSNT", "CAN2_TRAY26_PRSNT",
+	"CAN2_TRAY27_PRSNT", "CAN2_TRAY28_PRSNT",
+	"CAN2_TRAY29_PRSNT", "CAN2_TRAY30_PRSNT",
+	"CAN2_TRAY31_PRSNT", "CAN2_TRAY32_PRSNT",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&prsnt_io_expander2 {
+	gpio-line-names =
+	"CAN3_TRAY1_PRSNT", "CAN3_TRAY2_PRSNT",
+	"CAN3_TRAY3_PRSNT", "CAN3_TRAY4_PRSNT",
+	"CAN3_TRAY5_PRSNT", "CAN3_TRAY6_PRSNT",
+	"CAN3_TRAY7_PRSNT", "CAN3_TRAY8_PRSNT",
+	"CAN3_TRAY9_PRSNT", "CAN3_TRAY10_PRSNT",
+	"CAN3_TRAY11_PRSNT", "CAN3_TRAY12_PRSNT",
+	"CAN3_TRAY13_PRSNT", "CAN3_TRAY14_PRSNT",
+	"CAN3_TRAY15_PRSNT", "CAN3_TRAY16_PRSNT",
+	"CAN3_TRAY17_PRSNT", "CAN3_TRAY18_PRSNT",
+	"CAN3_TRAY19_PRSNT", "CAN3_TRAY20_PRSNT",
+	"CAN3_TRAY21_PRSNT", "CAN3_TRAY22_PRSNT",
+	"CAN3_TRAY23_PRSNT", "CAN3_TRAY24_PRSNT",
+	"CAN3_TRAY25_PRSNT", "CAN3_TRAY26_PRSNT",
+	"CAN3_TRAY27_PRSNT", "CAN3_TRAY28_PRSNT",
+	"CAN3_TRAY29_PRSNT", "CAN3_TRAY30_PRSNT",
+	"CAN3_TRAY31_PRSNT", "CAN3_TRAY32_PRSNT",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&prsnt_io_expander3 {
+	gpio-line-names =
+	"CAN4_TRAY1_PRSNT", "CAN4_TRAY2_PRSNT",
+	"CAN4_TRAY3_PRSNT", "CAN4_TRAY4_PRSNT",
+	"CAN4_TRAY5_PRSNT", "CAN4_TRAY6_PRSNT",
+	"CAN4_TRAY7_PRSNT", "CAN4_TRAY8_PRSNT",
+	"CAN4_TRAY9_PRSNT", "CAN4_TRAY10_PRSNT",
+	"CAN4_TRAY11_PRSNT", "CAN4_TRAY12_PRSNT",
+	"CAN4_TRAY13_PRSNT", "CAN4_TRAY14_PRSNT",
+	"CAN4_TRAY15_PRSNT", "CAN4_TRAY16_PRSNT",
+	"CAN4_TRAY17_PRSNT", "CAN4_TRAY18_PRSNT",
+	"CAN4_TRAY19_PRSNT", "CAN4_TRAY20_PRSNT",
+	"CAN4_TRAY21_PRSNT", "CAN4_TRAY22_PRSNT",
+	"CAN4_TRAY23_PRSNT", "CAN4_TRAY24_PRSNT",
+	"CAN4_TRAY25_PRSNT", "CAN4_TRAY26_PRSNT",
+	"CAN4_TRAY27_PRSNT", "CAN4_TRAY28_PRSNT",
+	"CAN4_TRAY29_PRSNT", "CAN4_TRAY30_PRSNT",
+	"CAN4_TRAY31_PRSNT", "CAN4_TRAY32_PRSNT",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&prsnt_io_expander4 {
+	gpio-line-names =
+	"CAN5_TRAY1_PRSNT", "CAN5_TRAY2_PRSNT",
+	"CAN5_TRAY3_PRSNT", "CAN5_TRAY4_PRSNT",
+	"CAN5_TRAY5_PRSNT", "CAN5_TRAY6_PRSNT",
+	"CAN5_TRAY7_PRSNT", "CAN5_TRAY8_PRSNT",
+	"CAN5_TRAY9_PRSNT", "CAN5_TRAY10_PRSNT",
+	"CAN5_TRAY11_PRSNT", "CAN5_TRAY12_PRSNT",
+	"CAN5_TRAY13_PRSNT", "CAN5_TRAY14_PRSNT",
+	"CAN5_TRAY15_PRSNT", "CAN5_TRAY16_PRSNT",
+	"CAN5_TRAY17_PRSNT", "CAN5_TRAY18_PRSNT",
+	"CAN5_TRAY19_PRSNT", "CAN5_TRAY20_PRSNT",
+	"CAN5_TRAY21_PRSNT", "CAN5_TRAY22_PRSNT",
+	"CAN5_TRAY23_PRSNT", "CAN5_TRAY24_PRSNT",
+	"CAN5_TRAY25_PRSNT", "CAN5_TRAY26_PRSNT",
+	"CAN5_TRAY27_PRSNT", "CAN5_TRAY28_PRSNT",
+	"CAN5_TRAY29_PRSNT", "CAN5_TRAY30_PRSNT",
+	"CAN5_TRAY31_PRSNT", "CAN5_TRAY32_PRSNT",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&prsnt_io_expander5 {
+	gpio-line-names =
+	"CAN6_TRAY1_PRSNT", "CAN6_TRAY2_PRSNT",
+	"CAN6_TRAY3_PRSNT", "CAN6_TRAY4_PRSNT",
+	"CAN6_TRAY5_PRSNT", "CAN6_TRAY6_PRSNT",
+	"CAN6_TRAY7_PRSNT", "CAN6_TRAY8_PRSNT",
+	"CAN6_TRAY9_PRSNT", "CAN6_TRAY10_PRSNT",
+	"CAN6_TRAY11_PRSNT", "CAN6_TRAY12_PRSNT",
+	"CAN6_TRAY13_PRSNT", "CAN6_TRAY14_PRSNT",
+	"CAN6_TRAY15_PRSNT", "CAN6_TRAY16_PRSNT",
+	"CAN6_TRAY17_PRSNT", "CAN6_TRAY18_PRSNT",
+	"CAN6_TRAY19_PRSNT", "CAN6_TRAY20_PRSNT",
+	"CAN6_TRAY21_PRSNT", "CAN6_TRAY22_PRSNT",
+	"CAN6_TRAY23_PRSNT", "CAN6_TRAY24_PRSNT",
+	"CAN6_TRAY25_PRSNT", "CAN6_TRAY26_PRSNT",
+	"CAN6_TRAY27_PRSNT", "CAN6_TRAY28_PRSNT",
+	"CAN6_TRAY29_PRSNT", "CAN6_TRAY30_PRSNT",
+	"CAN6_TRAY31_PRSNT", "CAN6_TRAY32_PRSNT",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&prsnt_io_expander6 {
+	gpio-line-names =
+	"CAN7_TRAY1_PRSNT", "CAN7_TRAY2_PRSNT",
+	"CAN7_TRAY3_PRSNT", "CAN7_TRAY4_PRSNT",
+	"CAN7_TRAY5_PRSNT", "CAN7_TRAY6_PRSNT",
+	"CAN7_TRAY7_PRSNT", "CAN7_TRAY8_PRSNT",
+	"CAN7_TRAY9_PRSNT", "CAN7_TRAY10_PRSNT",
+	"CAN7_TRAY11_PRSNT", "CAN7_TRAY12_PRSNT",
+	"CAN7_TRAY13_PRSNT", "CAN7_TRAY14_PRSNT",
+	"CAN7_TRAY15_PRSNT", "CAN7_TRAY16_PRSNT",
+	"CAN7_TRAY17_PRSNT", "CAN7_TRAY18_PRSNT",
+	"CAN7_TRAY19_PRSNT", "CAN7_TRAY20_PRSNT",
+	"CAN7_TRAY21_PRSNT", "CAN7_TRAY22_PRSNT",
+	"CAN7_TRAY23_PRSNT", "CAN7_TRAY24_PRSNT",
+	"CAN7_TRAY25_PRSNT", "CAN7_TRAY26_PRSNT",
+	"CAN7_TRAY27_PRSNT", "CAN7_TRAY28_PRSNT",
+	"CAN7_TRAY29_PRSNT", "CAN7_TRAY30_PRSNT",
+	"CAN7_TRAY31_PRSNT", "CAN7_TRAY32_PRSNT",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&prsnt_io_expander7 {
+	gpio-line-names =
+	"CAN8_TRAY1_PRSNT", "CAN8_TRAY2_PRSNT",
+	"CAN8_TRAY3_PRSNT", "CAN8_TRAY4_PRSNT",
+	"CAN8_TRAY5_PRSNT", "CAN8_TRAY6_PRSNT",
+	"CAN8_TRAY7_PRSNT", "CAN8_TRAY8_PRSNT",
+	"CAN8_TRAY9_PRSNT", "CAN8_TRAY10_PRSNT",
+	"CAN8_TRAY11_PRSNT", "CAN8_TRAY12_PRSNT",
+	"CAN8_TRAY13_PRSNT", "CAN8_TRAY14_PRSNT",
+	"CAN8_TRAY15_PRSNT", "CAN8_TRAY16_PRSNT",
+	"CAN8_TRAY17_PRSNT", "CAN8_TRAY18_PRSNT",
+	"CAN8_TRAY19_PRSNT", "CAN8_TRAY20_PRSNT",
+	"CAN8_TRAY21_PRSNT", "CAN8_TRAY22_PRSNT",
+	"CAN8_TRAY23_PRSNT", "CAN8_TRAY24_PRSNT",
+	"CAN8_TRAY25_PRSNT", "CAN8_TRAY26_PRSNT",
+	"CAN8_TRAY27_PRSNT", "CAN8_TRAY28_PRSNT",
+	"CAN8_TRAY29_PRSNT", "CAN8_TRAY30_PRSNT",
+	"CAN8_TRAY31_PRSNT", "CAN8_TRAY32_PRSNT",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&pwrgd_io_expander0 {
+	gpio-line-names =
+	"CAN1_TRAY1_PWRGD", "CAN1_TRAY2_PWRGD",
+	"CAN1_TRAY3_PWRGD", "CAN1_TRAY4_PWRGD",
+	"CAN1_TRAY5_PWRGD", "CAN1_TRAY6_PWRGD",
+	"CAN1_TRAY7_PWRGD", "CAN1_TRAY8_PWRGD",
+	"CAN1_TRAY9_PWRGD", "CAN1_TRAY10_PWRGD",
+	"CAN1_TRAY11_PWRGD", "CAN1_TRAY12_PWRGD",
+	"CAN1_TRAY13_PWRGD", "CAN1_TRAY14_PWRGD",
+	"CAN1_TRAY15_PWRGD", "CAN1_TRAY16_PWRGD",
+	"CAN1_TRAY17_PWRGD", "CAN1_TRAY18_PWRGD",
+	"CAN1_TRAY19_PWRGD", "CAN1_TRAY20_PWRGD",
+	"CAN1_TRAY21_PWRGD", "CAN1_TRAY22_PWRGD",
+	"CAN1_TRAY23_PWRGD", "CAN1_TRAY24_PWRGD",
+	"CAN1_TRAY25_PWRGD", "CAN1_TRAY26_PWRGD",
+	"CAN1_TRAY27_PWRGD", "CAN1_TRAY28_PWRGD",
+	"CAN1_TRAY29_PWRGD", "CAN1_TRAY30_PWRGD",
+	"CAN1_TRAY31_PWRGD", "CAN1_TRAY32_PWRGD",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&pwrgd_io_expander1 {
+	gpio-line-names =
+	"CAN2_TRAY1_PWRGD", "CAN2_TRAY2_PWRGD",
+	"CAN2_TRAY3_PWRGD", "CAN2_TRAY4_PWRGD",
+	"CAN2_TRAY5_PWRGD", "CAN2_TRAY6_PWRGD",
+	"CAN2_TRAY7_PWRGD", "CAN2_TRAY8_PWRGD",
+	"CAN2_TRAY9_PWRGD", "CAN2_TRAY10_PWRGD",
+	"CAN2_TRAY11_PWRGD", "CAN2_TRAY12_PWRGD",
+	"CAN2_TRAY13_PWRGD", "CAN2_TRAY14_PWRGD",
+	"CAN2_TRAY15_PWRGD", "CAN2_TRAY16_PWRGD",
+	"CAN2_TRAY17_PWRGD", "CAN2_TRAY18_PWRGD",
+	"CAN2_TRAY19_PWRGD", "CAN2_TRAY20_PWRGD",
+	"CAN2_TRAY21_PWRGD", "CAN2_TRAY22_PWRGD",
+	"CAN2_TRAY23_PWRGD", "CAN2_TRAY24_PWRGD",
+	"CAN2_TRAY25_PWRGD", "CAN2_TRAY26_PWRGD",
+	"CAN2_TRAY27_PWRGD", "CAN2_TRAY28_PWRGD",
+	"CAN2_TRAY29_PWRGD", "CAN2_TRAY30_PWRGD",
+	"CAN2_TRAY31_PWRGD", "CAN2_TRAY32_PWRGD",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&pwrgd_io_expander2 {
+	gpio-line-names =
+	"CAN3_TRAY1_PWRGD", "CAN3_TRAY2_PWRGD",
+	"CAN3_TRAY3_PWRGD", "CAN3_TRAY4_PWRGD",
+	"CAN3_TRAY5_PWRGD", "CAN3_TRAY6_PWRGD",
+	"CAN3_TRAY7_PWRGD", "CAN3_TRAY8_PWRGD",
+	"CAN3_TRAY9_PWRGD", "CAN3_TRAY10_PWRGD",
+	"CAN3_TRAY11_PWRGD", "CAN3_TRAY12_PWRGD",
+	"CAN3_TRAY13_PWRGD", "CAN3_TRAY14_PWRGD",
+	"CAN3_TRAY15_PWRGD", "CAN3_TRAY16_PWRGD",
+	"CAN3_TRAY17_PWRGD", "CAN3_TRAY18_PWRGD",
+	"CAN3_TRAY19_PWRGD", "CAN3_TRAY20_PWRGD",
+	"CAN3_TRAY21_PWRGD", "CAN3_TRAY22_PWRGD",
+	"CAN3_TRAY23_PWRGD", "CAN3_TRAY24_PWRGD",
+	"CAN3_TRAY25_PWRGD", "CAN3_TRAY26_PWRGD",
+	"CAN3_TRAY27_PWRGD", "CAN3_TRAY28_PWRGD",
+	"CAN3_TRAY29_PWRGD", "CAN3_TRAY30_PWRGD",
+	"CAN3_TRAY31_PWRGD", "CAN3_TRAY32_PWRGD",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&pwrgd_io_expander3 {
+	gpio-line-names =
+	"CAN4_TRAY1_PWRGD", "CAN4_TRAY2_PWRGD",
+	"CAN4_TRAY3_PWRGD", "CAN4_TRAY4_PWRGD",
+	"CAN4_TRAY5_PWRGD", "CAN4_TRAY6_PWRGD",
+	"CAN4_TRAY7_PWRGD", "CAN4_TRAY8_PWRGD",
+	"CAN4_TRAY9_PWRGD", "CAN4_TRAY10_PWRGD",
+	"CAN4_TRAY11_PWRGD", "CAN4_TRAY12_PWRGD",
+	"CAN4_TRAY13_PWRGD", "CAN4_TRAY14_PWRGD",
+	"CAN4_TRAY15_PWRGD", "CAN4_TRAY16_PWRGD",
+	"CAN4_TRAY17_PWRGD", "CAN4_TRAY18_PWRGD",
+	"CAN4_TRAY19_PWRGD", "CAN4_TRAY20_PWRGD",
+	"CAN4_TRAY21_PWRGD", "CAN4_TRAY22_PWRGD",
+	"CAN4_TRAY23_PWRGD", "CAN4_TRAY24_PWRGD",
+	"CAN4_TRAY25_PWRGD", "CAN4_TRAY26_PWRGD",
+	"CAN4_TRAY27_PWRGD", "CAN4_TRAY28_PWRGD",
+	"CAN4_TRAY29_PWRGD", "CAN4_TRAY30_PWRGD",
+	"CAN4_TRAY31_PWRGD", "CAN4_TRAY32_PWRGD",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&pwrgd_io_expander4 {
+	gpio-line-names =
+	"CAN5_TRAY1_PWRGD", "CAN5_TRAY2_PWRGD",
+	"CAN5_TRAY3_PWRGD", "CAN5_TRAY4_PWRGD",
+	"CAN5_TRAY5_PWRGD", "CAN5_TRAY6_PWRGD",
+	"CAN5_TRAY7_PWRGD", "CAN5_TRAY8_PWRGD",
+	"CAN5_TRAY9_PWRGD", "CAN5_TRAY10_PWRGD",
+	"CAN5_TRAY11_PWRGD", "CAN5_TRAY12_PWRGD",
+	"CAN5_TRAY13_PWRGD", "CAN5_TRAY14_PWRGD",
+	"CAN5_TRAY15_PWRGD", "CAN5_TRAY16_PWRGD",
+	"CAN5_TRAY17_PWRGD", "CAN5_TRAY18_PWRGD",
+	"CAN5_TRAY19_PWRGD", "CAN5_TRAY20_PWRGD",
+	"CAN5_TRAY21_PWRGD", "CAN5_TRAY22_PWRGD",
+	"CAN5_TRAY23_PWRGD", "CAN5_TRAY24_PWRGD",
+	"CAN5_TRAY25_PWRGD", "CAN5_TRAY26_PWRGD",
+	"CAN5_TRAY27_PWRGD", "CAN5_TRAY28_PWRGD",
+	"CAN5_TRAY29_PWRGD", "CAN5_TRAY30_PWRGD",
+	"CAN5_TRAY31_PWRGD", "CAN5_TRAY32_PWRGD",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&pwrgd_io_expander5 {
+	gpio-line-names =
+	"CAN6_TRAY1_PWRGD", "CAN6_TRAY2_PWRGD",
+	"CAN6_TRAY3_PWRGD", "CAN6_TRAY4_PWRGD",
+	"CAN6_TRAY5_PWRGD", "CAN6_TRAY6_PWRGD",
+	"CAN6_TRAY7_PWRGD", "CAN6_TRAY8_PWRGD",
+	"CAN6_TRAY9_PWRGD", "CAN6_TRAY10_PWRGD",
+	"CAN6_TRAY11_PWRGD", "CAN6_TRAY12_PWRGD",
+	"CAN6_TRAY13_PWRGD", "CAN6_TRAY14_PWRGD",
+	"CAN6_TRAY15_PWRGD", "CAN6_TRAY16_PWRGD",
+	"CAN6_TRAY17_PWRGD", "CAN6_TRAY18_PWRGD",
+	"CAN6_TRAY19_PWRGD", "CAN6_TRAY20_PWRGD",
+	"CAN6_TRAY21_PWRGD", "CAN6_TRAY22_PWRGD",
+	"CAN6_TRAY23_PWRGD", "CAN6_TRAY24_PWRGD",
+	"CAN6_TRAY25_PWRGD", "CAN6_TRAY26_PWRGD",
+	"CAN6_TRAY27_PWRGD", "CAN6_TRAY28_PWRGD",
+	"CAN6_TRAY29_PWRGD", "CAN6_TRAY30_PWRGD",
+	"CAN6_TRAY31_PWRGD", "CAN6_TRAY32_PWRGD",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&pwrgd_io_expander6 {
+	gpio-line-names =
+	"CAN7_TRAY1_PWRGD", "CAN7_TRAY2_PWRGD",
+	"CAN7_TRAY3_PWRGD", "CAN7_TRAY4_PWRGD",
+	"CAN7_TRAY5_PWRGD", "CAN7_TRAY6_PWRGD",
+	"CAN7_TRAY7_PWRGD", "CAN7_TRAY8_PWRGD",
+	"CAN7_TRAY9_PWRGD", "CAN7_TRAY10_PWRGD",
+	"CAN7_TRAY11_PWRGD", "CAN7_TRAY12_PWRGD",
+	"CAN7_TRAY13_PWRGD", "CAN7_TRAY14_PWRGD",
+	"CAN7_TRAY15_PWRGD", "CAN7_TRAY16_PWRGD",
+	"CAN7_TRAY17_PWRGD", "CAN7_TRAY18_PWRGD",
+	"CAN7_TRAY19_PWRGD", "CAN7_TRAY20_PWRGD",
+	"CAN7_TRAY21_PWRGD", "CAN7_TRAY22_PWRGD",
+	"CAN7_TRAY23_PWRGD", "CAN7_TRAY24_PWRGD",
+	"CAN7_TRAY25_PWRGD", "CAN7_TRAY26_PWRGD",
+	"CAN7_TRAY27_PWRGD", "CAN7_TRAY28_PWRGD",
+	"CAN7_TRAY29_PWRGD", "CAN7_TRAY30_PWRGD",
+	"CAN7_TRAY31_PWRGD", "CAN7_TRAY32_PWRGD",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&pwrgd_io_expander7 {
+	gpio-line-names =
+	"CAN8_TRAY1_PWRGD", "CAN8_TRAY2_PWRGD",
+	"CAN8_TRAY3_PWRGD", "CAN8_TRAY4_PWRGD",
+	"CAN8_TRAY5_PWRGD", "CAN8_TRAY6_PWRGD",
+	"CAN8_TRAY7_PWRGD", "CAN8_TRAY8_PWRGD",
+	"CAN8_TRAY9_PWRGD", "CAN8_TRAY10_PWRGD",
+	"CAN8_TRAY11_PWRGD", "CAN8_TRAY12_PWRGD",
+	"CAN8_TRAY13_PWRGD", "CAN8_TRAY14_PWRGD",
+	"CAN8_TRAY15_PWRGD", "CAN8_TRAY16_PWRGD",
+	"CAN8_TRAY17_PWRGD", "CAN8_TRAY18_PWRGD",
+	"CAN8_TRAY19_PWRGD", "CAN8_TRAY20_PWRGD",
+	"CAN8_TRAY21_PWRGD", "CAN8_TRAY22_PWRGD",
+	"CAN8_TRAY23_PWRGD", "CAN8_TRAY24_PWRGD",
+	"CAN8_TRAY25_PWRGD", "CAN8_TRAY26_PWRGD",
+	"CAN8_TRAY27_PWRGD", "CAN8_TRAY28_PWRGD",
+	"CAN8_TRAY29_PWRGD", "CAN8_TRAY30_PWRGD",
+	"CAN8_TRAY31_PWRGD", "CAN8_TRAY32_PWRGD",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&large_leak_io_expander0 {
+	gpio-line-names =
+	"CAN1_TRAY1_LARGE_LEAK", "CAN1_TRAY2_LARGE_LEAK",
+	"CAN1_TRAY3_LARGE_LEAK", "CAN1_TRAY4_LARGE_LEAK",
+	"CAN1_TRAY5_LARGE_LEAK", "CAN1_TRAY6_LARGE_LEAK",
+	"CAN1_TRAY7_LARGE_LEAK", "CAN1_TRAY8_LARGE_LEAK",
+	"CAN1_TRAY9_LARGE_LEAK", "CAN1_TRAY10_LARGE_LEAK",
+	"CAN1_TRAY11_LARGE_LEAK", "CAN1_TRAY12_LARGE_LEAK",
+	"CAN1_TRAY13_LARGE_LEAK", "CAN1_TRAY14_LARGE_LEAK",
+	"CAN1_TRAY15_LARGE_LEAK", "CAN1_TRAY16_LARGE_LEAK",
+	"CAN1_TRAY17_LARGE_LEAK", "CAN1_TRAY18_LARGE_LEAK",
+	"CAN1_TRAY19_LARGE_LEAK", "CAN1_TRAY20_LARGE_LEAK",
+	"CAN1_TRAY21_LARGE_LEAK", "CAN1_TRAY22_LARGE_LEAK",
+	"CAN1_TRAY23_LARGE_LEAK", "CAN1_TRAY24_LARGE_LEAK",
+	"CAN1_TRAY25_LARGE_LEAK", "CAN1_TRAY26_LARGE_LEAK",
+	"CAN1_TRAY27_LARGE_LEAK", "CAN1_TRAY28_LARGE_LEAK",
+	"CAN1_TRAY29_LARGE_LEAK", "CAN1_TRAY30_LARGE_LEAK",
+	"CAN1_TRAY31_LARGE_LEAK", "CAN1_TRAY32_LARGE_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&large_leak_io_expander1 {
+	gpio-line-names =
+	"CAN2_TRAY1_LARGE_LEAK", "CAN2_TRAY2_LARGE_LEAK",
+	"CAN2_TRAY3_LARGE_LEAK", "CAN2_TRAY4_LARGE_LEAK",
+	"CAN2_TRAY5_LARGE_LEAK", "CAN2_TRAY6_LARGE_LEAK",
+	"CAN2_TRAY7_LARGE_LEAK", "CAN2_TRAY8_LARGE_LEAK",
+	"CAN2_TRAY9_LARGE_LEAK", "CAN2_TRAY10_LARGE_LEAK",
+	"CAN2_TRAY11_LARGE_LEAK", "CAN2_TRAY12_LARGE_LEAK",
+	"CAN2_TRAY13_LARGE_LEAK", "CAN2_TRAY14_LARGE_LEAK",
+	"CAN2_TRAY15_LARGE_LEAK", "CAN2_TRAY16_LARGE_LEAK",
+	"CAN2_TRAY17_LARGE_LEAK", "CAN2_TRAY18_LARGE_LEAK",
+	"CAN2_TRAY19_LARGE_LEAK", "CAN2_TRAY20_LARGE_LEAK",
+	"CAN2_TRAY21_LARGE_LEAK", "CAN2_TRAY22_LARGE_LEAK",
+	"CAN2_TRAY23_LARGE_LEAK", "CAN2_TRAY24_LARGE_LEAK",
+	"CAN2_TRAY25_LARGE_LEAK", "CAN2_TRAY26_LARGE_LEAK",
+	"CAN2_TRAY27_LARGE_LEAK", "CAN2_TRAY28_LARGE_LEAK",
+	"CAN2_TRAY29_LARGE_LEAK", "CAN2_TRAY30_LARGE_LEAK",
+	"CAN2_TRAY31_LARGE_LEAK", "CAN2_TRAY32_LARGE_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&large_leak_io_expander2 {
+	gpio-line-names =
+	"CAN3_TRAY1_LARGE_LEAK", "CAN3_TRAY2_LARGE_LEAK",
+	"CAN3_TRAY3_LARGE_LEAK", "CAN3_TRAY4_LARGE_LEAK",
+	"CAN3_TRAY5_LARGE_LEAK", "CAN3_TRAY6_LARGE_LEAK",
+	"CAN3_TRAY7_LARGE_LEAK", "CAN3_TRAY8_LARGE_LEAK",
+	"CAN3_TRAY9_LARGE_LEAK", "CAN3_TRAY10_LARGE_LEAK",
+	"CAN3_TRAY11_LARGE_LEAK", "CAN3_TRAY12_LARGE_LEAK",
+	"CAN3_TRAY13_LARGE_LEAK", "CAN3_TRAY14_LARGE_LEAK",
+	"CAN3_TRAY15_LARGE_LEAK", "CAN3_TRAY16_LARGE_LEAK",
+	"CAN3_TRAY17_LARGE_LEAK", "CAN3_TRAY18_LARGE_LEAK",
+	"CAN3_TRAY19_LARGE_LEAK", "CAN3_TRAY20_LARGE_LEAK",
+	"CAN3_TRAY21_LARGE_LEAK", "CAN3_TRAY22_LARGE_LEAK",
+	"CAN3_TRAY23_LARGE_LEAK", "CAN3_TRAY24_LARGE_LEAK",
+	"CAN3_TRAY25_LARGE_LEAK", "CAN3_TRAY26_LARGE_LEAK",
+	"CAN3_TRAY27_LARGE_LEAK", "CAN3_TRAY28_LARGE_LEAK",
+	"CAN3_TRAY29_LARGE_LEAK", "CAN3_TRAY30_LARGE_LEAK",
+	"CAN3_TRAY31_LARGE_LEAK", "CAN3_TRAY32_LARGE_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&large_leak_io_expander3 {
+	gpio-line-names =
+	"CAN4_TRAY1_LARGE_LEAK", "CAN4_TRAY2_LARGE_LEAK",
+	"CAN4_TRAY3_LARGE_LEAK", "CAN4_TRAY4_LARGE_LEAK",
+	"CAN4_TRAY5_LARGE_LEAK", "CAN4_TRAY6_LARGE_LEAK",
+	"CAN4_TRAY7_LARGE_LEAK", "CAN4_TRAY8_LARGE_LEAK",
+	"CAN4_TRAY9_LARGE_LEAK", "CAN4_TRAY10_LARGE_LEAK",
+	"CAN4_TRAY11_LARGE_LEAK", "CAN4_TRAY12_LARGE_LEAK",
+	"CAN4_TRAY13_LARGE_LEAK", "CAN4_TRAY14_LARGE_LEAK",
+	"CAN4_TRAY15_LARGE_LEAK", "CAN4_TRAY16_LARGE_LEAK",
+	"CAN4_TRAY17_LARGE_LEAK", "CAN4_TRAY18_LARGE_LEAK",
+	"CAN4_TRAY19_LARGE_LEAK", "CAN4_TRAY20_LARGE_LEAK",
+	"CAN4_TRAY21_LARGE_LEAK", "CAN4_TRAY22_LARGE_LEAK",
+	"CAN4_TRAY23_LARGE_LEAK", "CAN4_TRAY24_LARGE_LEAK",
+	"CAN4_TRAY25_LARGE_LEAK", "CAN4_TRAY26_LARGE_LEAK",
+	"CAN4_TRAY27_LARGE_LEAK", "CAN4_TRAY28_LARGE_LEAK",
+	"CAN4_TRAY29_LARGE_LEAK", "CAN4_TRAY30_LARGE_LEAK",
+	"CAN4_TRAY31_LARGE_LEAK", "CAN4_TRAY32_LARGE_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&large_leak_io_expander4 {
+	gpio-line-names =
+	"CAN5_TRAY1_LARGE_LEAK", "CAN5_TRAY2_LARGE_LEAK",
+	"CAN5_TRAY3_LARGE_LEAK", "CAN5_TRAY4_LARGE_LEAK",
+	"CAN5_TRAY5_LARGE_LEAK", "CAN5_TRAY6_LARGE_LEAK",
+	"CAN5_TRAY7_LARGE_LEAK", "CAN5_TRAY8_LARGE_LEAK",
+	"CAN5_TRAY9_LARGE_LEAK", "CAN5_TRAY10_LARGE_LEAK",
+	"CAN5_TRAY11_LARGE_LEAK", "CAN5_TRAY12_LARGE_LEAK",
+	"CAN5_TRAY13_LARGE_LEAK", "CAN5_TRAY14_LARGE_LEAK",
+	"CAN5_TRAY15_LARGE_LEAK", "CAN5_TRAY16_LARGE_LEAK",
+	"CAN5_TRAY17_LARGE_LEAK", "CAN5_TRAY18_LARGE_LEAK",
+	"CAN5_TRAY19_LARGE_LEAK", "CAN5_TRAY20_LARGE_LEAK",
+	"CAN5_TRAY21_LARGE_LEAK", "CAN5_TRAY22_LARGE_LEAK",
+	"CAN5_TRAY23_LARGE_LEAK", "CAN5_TRAY24_LARGE_LEAK",
+	"CAN5_TRAY25_LARGE_LEAK", "CAN5_TRAY26_LARGE_LEAK",
+	"CAN5_TRAY27_LARGE_LEAK", "CAN5_TRAY28_LARGE_LEAK",
+	"CAN5_TRAY29_LARGE_LEAK", "CAN5_TRAY30_LARGE_LEAK",
+	"CAN5_TRAY31_LARGE_LEAK", "CAN5_TRAY32_LARGE_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&large_leak_io_expander5 {
+	gpio-line-names =
+	"CAN6_TRAY1_LARGE_LEAK", "CAN6_TRAY2_LARGE_LEAK",
+	"CAN6_TRAY3_LARGE_LEAK", "CAN6_TRAY4_LARGE_LEAK",
+	"CAN6_TRAY5_LARGE_LEAK", "CAN6_TRAY6_LARGE_LEAK",
+	"CAN6_TRAY7_LARGE_LEAK", "CAN6_TRAY8_LARGE_LEAK",
+	"CAN6_TRAY9_LARGE_LEAK", "CAN6_TRAY10_LARGE_LEAK",
+	"CAN6_TRAY11_LARGE_LEAK", "CAN6_TRAY12_LARGE_LEAK",
+	"CAN6_TRAY13_LARGE_LEAK", "CAN6_TRAY14_LARGE_LEAK",
+	"CAN6_TRAY15_LARGE_LEAK", "CAN6_TRAY16_LARGE_LEAK",
+	"CAN6_TRAY17_LARGE_LEAK", "CAN6_TRAY18_LARGE_LEAK",
+	"CAN6_TRAY19_LARGE_LEAK", "CAN6_TRAY20_LARGE_LEAK",
+	"CAN6_TRAY21_LARGE_LEAK", "CAN6_TRAY22_LARGE_LEAK",
+	"CAN6_TRAY23_LARGE_LEAK", "CAN6_TRAY24_LARGE_LEAK",
+	"CAN6_TRAY25_LARGE_LEAK", "CAN6_TRAY26_LARGE_LEAK",
+	"CAN6_TRAY27_LARGE_LEAK", "CAN6_TRAY28_LARGE_LEAK",
+	"CAN6_TRAY29_LARGE_LEAK", "CAN6_TRAY30_LARGE_LEAK",
+	"CAN6_TRAY31_LARGE_LEAK", "CAN6_TRAY32_LARGE_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&large_leak_io_expander6 {
+	gpio-line-names =
+	"CAN7_TRAY1_LARGE_LEAK", "CAN7_TRAY2_LARGE_LEAK",
+	"CAN7_TRAY3_LARGE_LEAK", "CAN7_TRAY4_LARGE_LEAK",
+	"CAN7_TRAY5_LARGE_LEAK", "CAN7_TRAY6_LARGE_LEAK",
+	"CAN7_TRAY7_LARGE_LEAK", "CAN7_TRAY8_LARGE_LEAK",
+	"CAN7_TRAY9_LARGE_LEAK", "CAN7_TRAY10_LARGE_LEAK",
+	"CAN7_TRAY11_LARGE_LEAK", "CAN7_TRAY12_LARGE_LEAK",
+	"CAN7_TRAY13_LARGE_LEAK", "CAN7_TRAY14_LARGE_LEAK",
+	"CAN7_TRAY15_LARGE_LEAK", "CAN7_TRAY16_LARGE_LEAK",
+	"CAN7_TRAY17_LARGE_LEAK", "CAN7_TRAY18_LARGE_LEAK",
+	"CAN7_TRAY19_LARGE_LEAK", "CAN7_TRAY20_LARGE_LEAK",
+	"CAN7_TRAY21_LARGE_LEAK", "CAN7_TRAY22_LARGE_LEAK",
+	"CAN7_TRAY23_LARGE_LEAK", "CAN7_TRAY24_LARGE_LEAK",
+	"CAN7_TRAY25_LARGE_LEAK", "CAN7_TRAY26_LARGE_LEAK",
+	"CAN7_TRAY27_LARGE_LEAK", "CAN7_TRAY28_LARGE_LEAK",
+	"CAN7_TRAY29_LARGE_LEAK", "CAN7_TRAY30_LARGE_LEAK",
+	"CAN7_TRAY31_LARGE_LEAK", "CAN7_TRAY32_LARGE_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&large_leak_io_expander7 {
+	gpio-line-names =
+	"CAN8_TRAY1_LARGE_LEAK", "CAN8_TRAY2_LARGE_LEAK",
+	"CAN8_TRAY3_LARGE_LEAK", "CAN8_TRAY4_LARGE_LEAK",
+	"CAN8_TRAY5_LARGE_LEAK", "CAN8_TRAY6_LARGE_LEAK",
+	"CAN8_TRAY7_LARGE_LEAK", "CAN8_TRAY8_LARGE_LEAK",
+	"CAN8_TRAY9_LARGE_LEAK", "CAN8_TRAY10_LARGE_LEAK",
+	"CAN8_TRAY11_LARGE_LEAK", "CAN8_TRAY12_LARGE_LEAK",
+	"CAN8_TRAY13_LARGE_LEAK", "CAN8_TRAY14_LARGE_LEAK",
+	"CAN8_TRAY15_LARGE_LEAK", "CAN8_TRAY16_LARGE_LEAK",
+	"CAN8_TRAY17_LARGE_LEAK", "CAN8_TRAY18_LARGE_LEAK",
+	"CAN8_TRAY19_LARGE_LEAK", "CAN8_TRAY20_LARGE_LEAK",
+	"CAN8_TRAY21_LARGE_LEAK", "CAN8_TRAY22_LARGE_LEAK",
+	"CAN8_TRAY23_LARGE_LEAK", "CAN8_TRAY24_LARGE_LEAK",
+	"CAN8_TRAY25_LARGE_LEAK", "CAN8_TRAY26_LARGE_LEAK",
+	"CAN8_TRAY27_LARGE_LEAK", "CAN8_TRAY28_LARGE_LEAK",
+	"CAN8_TRAY29_LARGE_LEAK", "CAN8_TRAY30_LARGE_LEAK",
+	"CAN8_TRAY31_LARGE_LEAK", "CAN8_TRAY32_LARGE_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&small_leak_io_expander0 {
+	gpio-line-names =
+	"CAN1_TRAY1_SMALL_LEAK", "CAN1_TRAY2_SMALL_LEAK",
+	"CAN1_TRAY3_SMALL_LEAK", "CAN1_TRAY4_SMALL_LEAK",
+	"CAN1_TRAY5_SMALL_LEAK", "CAN1_TRAY6_SMALL_LEAK",
+	"CAN1_TRAY7_SMALL_LEAK", "CAN1_TRAY8_SMALL_LEAK",
+	"CAN1_TRAY9_SMALL_LEAK", "CAN1_TRAY10_SMALL_LEAK",
+	"CAN1_TRAY11_SMALL_LEAK", "CAN1_TRAY12_SMALL_LEAK",
+	"CAN1_TRAY13_SMALL_LEAK", "CAN1_TRAY14_SMALL_LEAK",
+	"CAN1_TRAY15_SMALL_LEAK", "CAN1_TRAY16_SMALL_LEAK",
+	"CAN1_TRAY17_SMALL_LEAK", "CAN1_TRAY18_SMALL_LEAK",
+	"CAN1_TRAY19_SMALL_LEAK", "CAN1_TRAY20_SMALL_LEAK",
+	"CAN1_TRAY21_SMALL_LEAK", "CAN1_TRAY22_SMALL_LEAK",
+	"CAN1_TRAY23_SMALL_LEAK", "CAN1_TRAY24_SMALL_LEAK",
+	"CAN1_TRAY25_SMALL_LEAK", "CAN1_TRAY26_SMALL_LEAK",
+	"CAN1_TRAY27_SMALL_LEAK", "CAN1_TRAY28_SMALL_LEAK",
+	"CAN1_TRAY29_SMALL_LEAK", "CAN1_TRAY30_SMALL_LEAK",
+	"CAN1_TRAY31_SMALL_LEAK", "CAN1_TRAY32_SMALL_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&small_leak_io_expander1 {
+	gpio-line-names =
+	"CAN2_TRAY1_SMALL_LEAK", "CAN2_TRAY2_SMALL_LEAK",
+	"CAN2_TRAY3_SMALL_LEAK", "CAN2_TRAY4_SMALL_LEAK",
+	"CAN2_TRAY5_SMALL_LEAK", "CAN2_TRAY6_SMALL_LEAK",
+	"CAN2_TRAY7_SMALL_LEAK", "CAN2_TRAY8_SMALL_LEAK",
+	"CAN2_TRAY9_SMALL_LEAK", "CAN2_TRAY10_SMALL_LEAK",
+	"CAN2_TRAY11_SMALL_LEAK", "CAN2_TRAY12_SMALL_LEAK",
+	"CAN2_TRAY13_SMALL_LEAK", "CAN2_TRAY14_SMALL_LEAK",
+	"CAN2_TRAY15_SMALL_LEAK", "CAN2_TRAY16_SMALL_LEAK",
+	"CAN2_TRAY17_SMALL_LEAK", "CAN2_TRAY18_SMALL_LEAK",
+	"CAN2_TRAY19_SMALL_LEAK", "CAN2_TRAY20_SMALL_LEAK",
+	"CAN2_TRAY21_SMALL_LEAK", "CAN2_TRAY22_SMALL_LEAK",
+	"CAN2_TRAY23_SMALL_LEAK", "CAN2_TRAY24_SMALL_LEAK",
+	"CAN2_TRAY25_SMALL_LEAK", "CAN2_TRAY26_SMALL_LEAK",
+	"CAN2_TRAY27_SMALL_LEAK", "CAN2_TRAY28_SMALL_LEAK",
+	"CAN2_TRAY29_SMALL_LEAK", "CAN2_TRAY30_SMALL_LEAK",
+	"CAN2_TRAY31_SMALL_LEAK", "CAN2_TRAY32_SMALL_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&small_leak_io_expander2 {
+	gpio-line-names =
+	"CAN3_TRAY1_SMALL_LEAK", "CAN3_TRAY2_SMALL_LEAK",
+	"CAN3_TRAY3_SMALL_LEAK", "CAN3_TRAY4_SMALL_LEAK",
+	"CAN3_TRAY5_SMALL_LEAK", "CAN3_TRAY6_SMALL_LEAK",
+	"CAN3_TRAY7_SMALL_LEAK", "CAN3_TRAY8_SMALL_LEAK",
+	"CAN3_TRAY9_SMALL_LEAK", "CAN3_TRAY10_SMALL_LEAK",
+	"CAN3_TRAY11_SMALL_LEAK", "CAN3_TRAY12_SMALL_LEAK",
+	"CAN3_TRAY13_SMALL_LEAK", "CAN3_TRAY14_SMALL_LEAK",
+	"CAN3_TRAY15_SMALL_LEAK", "CAN3_TRAY16_SMALL_LEAK",
+	"CAN3_TRAY17_SMALL_LEAK", "CAN3_TRAY18_SMALL_LEAK",
+	"CAN3_TRAY19_SMALL_LEAK", "CAN3_TRAY20_SMALL_LEAK",
+	"CAN3_TRAY21_SMALL_LEAK", "CAN3_TRAY22_SMALL_LEAK",
+	"CAN3_TRAY23_SMALL_LEAK", "CAN3_TRAY24_SMALL_LEAK",
+	"CAN3_TRAY25_SMALL_LEAK", "CAN3_TRAY26_SMALL_LEAK",
+	"CAN3_TRAY27_SMALL_LEAK", "CAN3_TRAY28_SMALL_LEAK",
+	"CAN3_TRAY29_SMALL_LEAK", "CAN3_TRAY30_SMALL_LEAK",
+	"CAN3_TRAY31_SMALL_LEAK", "CAN3_TRAY32_SMALL_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&small_leak_io_expander3 {
+	gpio-line-names =
+	"CAN4_TRAY1_SMALL_LEAK", "CAN4_TRAY2_SMALL_LEAK",
+	"CAN4_TRAY3_SMALL_LEAK", "CAN4_TRAY4_SMALL_LEAK",
+	"CAN4_TRAY5_SMALL_LEAK", "CAN4_TRAY6_SMALL_LEAK",
+	"CAN4_TRAY7_SMALL_LEAK", "CAN4_TRAY8_SMALL_LEAK",
+	"CAN4_TRAY9_SMALL_LEAK", "CAN4_TRAY10_SMALL_LEAK",
+	"CAN4_TRAY11_SMALL_LEAK", "CAN4_TRAY12_SMALL_LEAK",
+	"CAN4_TRAY13_SMALL_LEAK", "CAN4_TRAY14_SMALL_LEAK",
+	"CAN4_TRAY15_SMALL_LEAK", "CAN4_TRAY16_SMALL_LEAK",
+	"CAN4_TRAY17_SMALL_LEAK", "CAN4_TRAY18_SMALL_LEAK",
+	"CAN4_TRAY19_SMALL_LEAK", "CAN4_TRAY20_SMALL_LEAK",
+	"CAN4_TRAY21_SMALL_LEAK", "CAN4_TRAY22_SMALL_LEAK",
+	"CAN4_TRAY23_SMALL_LEAK", "CAN4_TRAY24_SMALL_LEAK",
+	"CAN4_TRAY25_SMALL_LEAK", "CAN4_TRAY26_SMALL_LEAK",
+	"CAN4_TRAY27_SMALL_LEAK", "CAN4_TRAY28_SMALL_LEAK",
+	"CAN4_TRAY29_SMALL_LEAK", "CAN4_TRAY30_SMALL_LEAK",
+	"CAN4_TRAY31_SMALL_LEAK", "CAN4_TRAY32_SMALL_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&small_leak_io_expander4 {
+	gpio-line-names =
+	"CAN5_TRAY1_SMALL_LEAK", "CAN5_TRAY2_SMALL_LEAK",
+	"CAN5_TRAY3_SMALL_LEAK", "CAN5_TRAY4_SMALL_LEAK",
+	"CAN5_TRAY5_SMALL_LEAK", "CAN5_TRAY6_SMALL_LEAK",
+	"CAN5_TRAY7_SMALL_LEAK", "CAN5_TRAY8_SMALL_LEAK",
+	"CAN5_TRAY9_SMALL_LEAK", "CAN5_TRAY10_SMALL_LEAK",
+	"CAN5_TRAY11_SMALL_LEAK", "CAN5_TRAY12_SMALL_LEAK",
+	"CAN5_TRAY13_SMALL_LEAK", "CAN5_TRAY14_SMALL_LEAK",
+	"CAN5_TRAY15_SMALL_LEAK", "CAN5_TRAY16_SMALL_LEAK",
+	"CAN5_TRAY17_SMALL_LEAK", "CAN5_TRAY18_SMALL_LEAK",
+	"CAN5_TRAY19_SMALL_LEAK", "CAN5_TRAY20_SMALL_LEAK",
+	"CAN5_TRAY21_SMALL_LEAK", "CAN5_TRAY22_SMALL_LEAK",
+	"CAN5_TRAY23_SMALL_LEAK", "CAN5_TRAY24_SMALL_LEAK",
+	"CAN5_TRAY25_SMALL_LEAK", "CAN5_TRAY26_SMALL_LEAK",
+	"CAN5_TRAY27_SMALL_LEAK", "CAN5_TRAY28_SMALL_LEAK",
+	"CAN5_TRAY29_SMALL_LEAK", "CAN5_TRAY30_SMALL_LEAK",
+	"CAN5_TRAY31_SMALL_LEAK", "CAN5_TRAY32_SMALL_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&small_leak_io_expander5 {
+	gpio-line-names =
+	"CAN6_TRAY1_SMALL_LEAK", "CAN6_TRAY2_SMALL_LEAK",
+	"CAN6_TRAY3_SMALL_LEAK", "CAN6_TRAY4_SMALL_LEAK",
+	"CAN6_TRAY5_SMALL_LEAK", "CAN6_TRAY6_SMALL_LEAK",
+	"CAN6_TRAY7_SMALL_LEAK", "CAN6_TRAY8_SMALL_LEAK",
+	"CAN6_TRAY9_SMALL_LEAK", "CAN6_TRAY10_SMALL_LEAK",
+	"CAN6_TRAY11_SMALL_LEAK", "CAN6_TRAY12_SMALL_LEAK",
+	"CAN6_TRAY13_SMALL_LEAK", "CAN6_TRAY14_SMALL_LEAK",
+	"CAN6_TRAY15_SMALL_LEAK", "CAN6_TRAY16_SMALL_LEAK",
+	"CAN6_TRAY17_SMALL_LEAK", "CAN6_TRAY18_SMALL_LEAK",
+	"CAN6_TRAY19_SMALL_LEAK", "CAN6_TRAY20_SMALL_LEAK",
+	"CAN6_TRAY21_SMALL_LEAK", "CAN6_TRAY22_SMALL_LEAK",
+	"CAN6_TRAY23_SMALL_LEAK", "CAN6_TRAY24_SMALL_LEAK",
+	"CAN6_TRAY25_SMALL_LEAK", "CAN6_TRAY26_SMALL_LEAK",
+	"CAN6_TRAY27_SMALL_LEAK", "CAN6_TRAY28_SMALL_LEAK",
+	"CAN6_TRAY29_SMALL_LEAK", "CAN6_TRAY30_SMALL_LEAK",
+	"CAN6_TRAY31_SMALL_LEAK", "CAN6_TRAY32_SMALL_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&small_leak_io_expander6 {
+	gpio-line-names =
+	"CAN7_TRAY1_SMALL_LEAK", "CAN7_TRAY2_SMALL_LEAK",
+	"CAN7_TRAY3_SMALL_LEAK", "CAN7_TRAY4_SMALL_LEAK",
+	"CAN7_TRAY5_SMALL_LEAK", "CAN7_TRAY6_SMALL_LEAK",
+	"CAN7_TRAY7_SMALL_LEAK", "CAN7_TRAY8_SMALL_LEAK",
+	"CAN7_TRAY9_SMALL_LEAK", "CAN7_TRAY10_SMALL_LEAK",
+	"CAN7_TRAY11_SMALL_LEAK", "CAN7_TRAY12_SMALL_LEAK",
+	"CAN7_TRAY13_SMALL_LEAK", "CAN7_TRAY14_SMALL_LEAK",
+	"CAN7_TRAY15_SMALL_LEAK", "CAN7_TRAY16_SMALL_LEAK",
+	"CAN7_TRAY17_SMALL_LEAK", "CAN7_TRAY18_SMALL_LEAK",
+	"CAN7_TRAY19_SMALL_LEAK", "CAN7_TRAY20_SMALL_LEAK",
+	"CAN7_TRAY21_SMALL_LEAK", "CAN7_TRAY22_SMALL_LEAK",
+	"CAN7_TRAY23_SMALL_LEAK", "CAN7_TRAY24_SMALL_LEAK",
+	"CAN7_TRAY25_SMALL_LEAK", "CAN7_TRAY26_SMALL_LEAK",
+	"CAN7_TRAY27_SMALL_LEAK", "CAN7_TRAY28_SMALL_LEAK",
+	"CAN7_TRAY29_SMALL_LEAK", "CAN7_TRAY30_SMALL_LEAK",
+	"CAN7_TRAY31_SMALL_LEAK", "CAN7_TRAY32_SMALL_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&small_leak_io_expander7 {
+	gpio-line-names =
+	"CAN8_TRAY1_SMALL_LEAK", "CAN8_TRAY2_SMALL_LEAK",
+	"CAN8_TRAY3_SMALL_LEAK", "CAN8_TRAY4_SMALL_LEAK",
+	"CAN8_TRAY5_SMALL_LEAK", "CAN8_TRAY6_SMALL_LEAK",
+	"CAN8_TRAY7_SMALL_LEAK", "CAN8_TRAY8_SMALL_LEAK",
+	"CAN8_TRAY9_SMALL_LEAK", "CAN8_TRAY10_SMALL_LEAK",
+	"CAN8_TRAY11_SMALL_LEAK", "CAN8_TRAY12_SMALL_LEAK",
+	"CAN8_TRAY13_SMALL_LEAK", "CAN8_TRAY14_SMALL_LEAK",
+	"CAN8_TRAY15_SMALL_LEAK", "CAN8_TRAY16_SMALL_LEAK",
+	"CAN8_TRAY17_SMALL_LEAK", "CAN8_TRAY18_SMALL_LEAK",
+	"CAN8_TRAY19_SMALL_LEAK", "CAN8_TRAY20_SMALL_LEAK",
+	"CAN8_TRAY21_SMALL_LEAK", "CAN8_TRAY22_SMALL_LEAK",
+	"CAN8_TRAY23_SMALL_LEAK", "CAN8_TRAY24_SMALL_LEAK",
+	"CAN8_TRAY25_SMALL_LEAK", "CAN8_TRAY26_SMALL_LEAK",
+	"CAN8_TRAY27_SMALL_LEAK", "CAN8_TRAY28_SMALL_LEAK",
+	"CAN8_TRAY29_SMALL_LEAK", "CAN8_TRAY30_SMALL_LEAK",
+	"CAN8_TRAY31_SMALL_LEAK", "CAN8_TRAY32_SMALL_LEAK",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&legacy_prsnt_io_expander0 {
+	gpio-line-names =
+	"wTRAY_PRSNT1_N_BUF_R", "wTRAY_PRSNT2_N_BUF_R",
+	"wTRAY_PRSNT3_N_BUF_R", "wTRAY_PRSNT4_N_BUF_R",
+	"wTRAY_PRSNT5_N_BUF_R", "wTRAY_PRSNT6_N_BUF_R",
+	"wTRAY_PRSNT7_N_BUF_R", "wTRAY_PRSNT8_N_BUF_R",
+	"wTRAY_PRSNT9_N_BUF_R", "wTRAY_PRSNT10_N_BUF_R",
+	"wTRAY_PRSNT11_N_BUF_R", "wTRAY_PRSNT12_N_BUF_R",
+	"wTRAY_PRSNT13_N_BUF_R", "wTRAY_PRSNT14_N_BUF_R",
+	"wTRAY_PRSNT15_N_BUF_R", "wTRAY_PRSNT16_N_BUF_R";
+};
+
+&legacy_prsnt_io_expander1 {
+	gpio-line-names =
+	"wTRAY_PRSNT17_N_BUF_R", "wTRAY_PRSNT18_N_BUF_R",
+	"wTRAY_PRSNT19_N_BUF_R", "wTRAY_PRSNT20_N_BUF_R",
+	"wTRAY_PRSNT21_N_BUF_R", "wTRAY_PRSNT22_N_BUF_R",
+	"wTRAY_PRSNT23_N_BUF_R", "wTRAY_PRSNT24_N_BUF_R",
+	"wTRAY_PRSNT25_N_BUF_R", "wTRAY_PRSNT26_N_BUF_R",
+	"wTRAY_PRSNT27_N_BUF_R", "wTRAY_PRSNT28_N_BUF_R",
+	"wTRAY_PRSNT29_N_BUF_R", "wTRAY_PRSNT30_N_BUF_R",
+	"wTRAY_PRSNT31_N_BUF_R", "wTRAY_PRSNT32_N_BUF_R";
+};
+
+&legacy_prsnt_io_expander2 {
+	gpio-line-names =
+	"wTRAY_PRSNT33_N_BUF_R", "wTRAY_PRSNT34_N_BUF_R",
+	"wTRAY_PRSNT35_N_BUF_R", "wTRAY_PRSNT36_N_BUF_R",
+	"wTRAY_PRSNT37_N_BUF_R", "wTRAY_PRSNT38_N_BUF_R",
+	"wTRAY_PRSNT39_N_BUF_R", "wTRAY_PRSNT40_N_BUF_R",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&legacy_pwrgd_io_expander0 {
+	gpio-line-names =
+	"wTRAY_PWRGD1_N_BUF_R", "wTRAY_PWRGD2_N_BUF_R",
+	"wTRAY_PWRGD3_N_BUF_R", "wTRAY_PWRGD4_N_BUF_R",
+	"wTRAY_PWRGD5_N_BUF_R", "wTRAY_PWRGD6_N_BUF_R",
+	"wTRAY_PWRGD7_N_BUF_R", "wTRAY_PWRGD8_N_BUF_R",
+	"wTRAY_PWRGD9_N_BUF_R", "wTRAY_PWRGD10_N_BUF_R",
+	"wTRAY_PWRGD11_N_BUF_R", "wTRAY_PWRGD12_N_BUF_R",
+	"wTRAY_PWRGD13_N_BUF_R", "wTRAY_PWRGD14_N_BUF_R",
+	"wTRAY_PWRGD15_N_BUF_R", "wTRAY_PWRGD16_N_BUF_R";
+};
+
+&legacy_pwrgd_io_expander1 {
+	gpio-line-names =
+	"wTRAY_PWRGD17_N_BUF_R", "wTRAY_PWRGD18_N_BUF_R",
+	"wTRAY_PWRGD19_N_BUF_R", "wTRAY_PWRGD20_N_BUF_R",
+	"wTRAY_PWRGD21_N_BUF_R", "wTRAY_PWRGD22_N_BUF_R",
+	"", "",
+	"wTRAY_PWRGD25_N_BUF_R", "wTRAY_PWRGD26_N_BUF_R",
+	"wTRAY_PWRGD27_N_BUF_R", "wTRAY_PWRGD28_N_BUF_R",
+	"", "",
+	"", "";
+};
+
+&legacy_pwrgd_io_expander2 {
+	gpio-line-names =
+	"wTRAY_PWRGD33_N_BUF_R", "wTRAY_PWRGD34_N_BUF_R",
+	"wTRAY_PWRGD35_N_BUF_R", "wTRAY_PWRGD36_N_BUF_R",
+	"", "",
+	"", "",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&legacy_leak_io_expander0 {
+	gpio-line-names =
+	"wTRAY_LEAK_DETECT1_N_BUF_R", "wTRAY_LEAK_DETECT2_N_BUF_R",
+	"wTRAY_LEAK_DETECT3_N_BUF_R", "wTRAY_LEAK_DETECT4_N_BUF_R",
+	"wTRAY_LEAK_DETECT5_N_BUF_R", "wTRAY_LEAK_DETECT6_N_BUF_R",
+	"wTRAY_LEAK_DETECT7_N_BUF_R", "wTRAY_LEAK_DETECT8_N_BUF_R",
+	"wTRAY_LEAK_DETECT9_N_BUF_R", "wTRAY_LEAK_DETECT10_N_BUF_R",
+	"wTRAY_LEAK_DETECT11_N_BUF_R", "wTRAY_LEAK_DETECT12_N_BUF_R",
+	"wTRAY_LEAK_DETECT13_N_BUF_R", "wTRAY_LEAK_DETECT14_N_BUF_R",
+	"wTRAY_LEAK_DETECT15_N_BUF_R", "wTRAY_LEAK_DETECT16_N_BUF_R";
+};
+
+&legacy_leak_io_expander1 {
+	gpio-line-names =
+	"wTRAY_LEAK_DETECT17_N_BUF_R", "wTRAY_LEAK_DETECT18_N_BUF_R",
+	"wTRAY_LEAK_DETECT19_N_BUF_R", "wTRAY_LEAK_DETECT20_N_BUF_R",
+	"wTRAY_LEAK_DETECT21_N_BUF_R", "wTRAY_LEAK_DETECT22_N_BUF_R",
+	"wTRAY_LEAK_DETECT23_N_BUF_R", "wTRAY_LEAK_DETECT24_N_BUF_R",
+	"wTRAY_LEAK_DETECT25_N_BUF_R", "wTRAY_LEAK_DETECT26_N_BUF_R",
+	"wTRAY_LEAK_DETECT27_N_BUF_R", "wTRAY_LEAK_DETECT28_N_BUF_R",
+	"wTRAY_LEAK_DETECT29_N_BUF_R", "wTRAY_LEAK_DETECT30_N_BUF_R",
+	"wTRAY_LEAK_DETECT31_N_BUF_R", "wTRAY_LEAK_DETECT32_N_BUF_R";
+};
+
+&legacy_leak_io_expander2 {
+	gpio-line-names =
+	"wTRAY_LEAK_DETECT33_N_BUF_R", "wTRAY_LEAK_DETECT34_N_BUF_R",
+	"wTRAY_LEAK_DETECT35_N_BUF_R", "wTRAY_LEAK_DETECT36_N_BUF_R",
+	"wTRAY_LEAK_DETECT37_N_BUF_R", "wTRAY_LEAK_DETECT38_N_BUF_R",
+	"wTRAY_LEAK_DETECT39_N_BUF_R", "wTRAY_LEAK_DETECT40_N_BUF_R",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&legacy_small_leak_io_expander0 {
+	gpio-line-names =
+	"wTRAY_SMALL_LEAK1_N_BUF_R", "wTRAY_SMALL_LEAK2_N_BUF_R",
+	"wTRAY_SMALL_LEAK3_N_BUF_R", "wTRAY_SMALL_LEAK4_N_BUF_R",
+	"wTRAY_SMALL_LEAK5_N_BUF_R", "wTRAY_SMALL_LEAK6_N_BUF_R",
+	"wTRAY_SMALL_LEAK7_N_BUF_R", "wTRAY_SMALL_LEAK8_N_BUF_R",
+	"wTRAY_SMALL_LEAK9_N_BUF_R", "wTRAY_SMALL_LEAK10_N_BUF_R",
+	"wTRAY_SMALL_LEAK11_N_BUF_R", "wTRAY_SMALL_LEAK12_N_BUF_R",
+	"wTRAY_SMALL_LEAK13_N_BUF_R", "wTRAY_SMALL_LEAK14_N_BUF_R",
+	"wTRAY_SMALL_LEAK15_N_BUF_R", "wTRAY_SMALL_LEAK16_N_BUF_R";
+};
+
+&legacy_small_leak_io_expander1 {
+	gpio-line-names =
+	"wTRAY_SMALL_LEAK17_N_BUF_R", "wTRAY_SMALL_LEAK18_N_BUF_R",
+	"wTRAY_SMALL_LEAK19_N_BUF_R", "wTRAY_SMALL_LEAK20_N_BUF_R",
+	"wTRAY_SMALL_LEAK21_N_BUF_R", "wTRAY_SMALL_LEAK22_N_BUF_R",
+	"wTRAY_SMALL_LEAK23_N_BUF_R", "wTRAY_SMALL_LEAK24_N_BUF_R",
+	"wTRAY_SMALL_LEAK25_N_BUF_R", "wTRAY_SMALL_LEAK26_N_BUF_R",
+	"wTRAY_SMALL_LEAK27_N_BUF_R", "wTRAY_SMALL_LEAK28_N_BUF_R",
+	"wTRAY_SMALL_LEAK29_N_BUF_R", "wTRAY_SMALL_LEAK30_N_BUF_R",
+	"wTRAY_SMALL_LEAK31_N_BUF_R", "wTRAY_SMALL_LEAK32_N_BUF_R";
+};
+
+&fpga_io_expander64 {
+	gpio-line-names =
+	"wTRAY_PWRGD_TEST", "wprovision_done",
+	"", "",
+	"", "",
+	"LEAK_CONFIG0", "LEAK_CONFIG1",
+	"FPGA_PWRGD_P24V_AUX_R", "FPGA_PWRGD_P24V_AUX_2_R",
+	"FPGA_PWRGD_P12V_SCM_R", "FPGA_PWRGD_P12V_AUX_R2",
+	"FPGA_PRSNT_FANBP_0_SIG_R_PLD_N", "FPGA_PRSNT_FANBP_0_PWR_R_PLD_N",
+	"FPGA_P24V_AUX_INA230_ALERT_N_R", "FPGA_SMB_TMC75_TEMP_ALERT_N_R";
+};
+
+&fpga_io_expander65 {
+	gpio-line-names =
+	"FPGA_PCI_DIS_N", "FPGA_DEV_DIS_N",
+	"FPGA_PWRGD_P3V3_AUX_R", "FPGA_PWRGD_P5V_AUX_R2",
+	"FPGA_PWRGD_P1V05_AUX_R", "FPGA_P48V_HSC_ALERT_N",
+	"FPGA_PWRGD_P1V5_AUX_R", "FPGA_PWRGD_P52V_HSC_PWROK_R",
+	"FPGA_R_COME_THERMTRIP_L", "FPGA_PRSNT_POE_SIG_PLD_N",
+	"FPGA_PRSNT_POE_PWR_PLD_N", "FPGA_PRSNT_RIO_RACKMON_N",
+	"FPGA_PRSNT_CAN2_MCIO_N", "FPGA_PRSNT_CAN1_MCIO_N",
+	"FPGA_PRSNT_RACKMON_MCIO_N", "FPGA_PRSNT_AALC_MCIO_N";
+};
+
+&legacy_small_leak_io_expander2 {
+	gpio-line-names =
+	"wTRAY_SMALL_LEAK33_N_BUF_R", "wTRAY_SMALL_LEAK34_N_BUF_R",
+	"wTRAY_SMALL_LEAK35_N_BUF_R", "wTRAY_SMALL_LEAK36_N_BUF_R",
+	"wTRAY_SMALL_LEAK37_N_BUF_R", "wTRAY_SMALL_LEAK38_N_BUF_R",
+	"wTRAY_SMALL_LEAK39_N_BUF_R", "wTRAY_SMALL_LEAK40_N_BUF_R",
+	"", "",
+	"", "",
+	"", "",
+	"", "";
+};
+
+&sku_info_io_expander {
+	gpio-line-names =
+	"", "",
+	"", "",
+	"", "",
+	"", "",
+	"support_miniSAS", "support_CAN_Bus",
+	"support_AALC", "support_Front_VT1_2",
+	"support_Front_VT1_3", "support_Rear_VT2",
+	"", "";
+};
+
+&fan_io_expander0 {
+	gpio-line-names =
+	"FM_FAN0_POWER_LED_N", "FM_FAN1_POWER_LED_N",
+	"P12V_FAN0_PWR_GD", "P12V_FAN1_PWR_GD",
+	"FM_FAN0_FAULT_LED_N", "FM_FAN1_FAULT_LED_N",
+	"P12V_FAN0_FLTB", "P12V_FAN1_FLTB",
+	"FM_FAN0_BUF_PRESENT_R", "FM_FAN1_BUF_PRESENT_R",
+	"", "",
+	"FM_FAN0_P12V_EN", "FM_FAN1_P12V_EN",
+	"", "";
+};
+
+&fan_io_expander1 {
+	gpio-line-names =
+	"FM_FAN2_POWER_LED_N", "FM_FAN3_POWER_LED_N",
+	"P12V_FAN2_PWR_GD", "P12V_FAN3_PWR_GD",
+	"FM_FAN2_FAULT_LED_N", "FM_FAN3_FAULT_LED_N",
+	"P12V_FAN2_FLTB", "P12V_FAN3_FLTB",
+	"FM_FAN2_BUF_PRESENT_R", "FM_FAN3_BUF_PRESENT_R",
+	"", "",
+	"FM_FAN2_P12V_EN", "FM_FAN3_P12V_EN",
+	"", "";
+};

-- 
2.34.1



From yeoreum.yun at arm.com  Tue Dec 23 23:00:35 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Wed, 24 Dec 2025 07:00:35 +0000
Subject: [PATCH 0/2] introduce pagetable_alloc_nolock()
In-Reply-To: <93327680-7d7d-415e-958b-0d2a667dbb52@os.amperecomputing.com>
References: <20251212161832.2067134-1-yeoreum.yun@arm.com>
 <916c17ba-22b1-456e-a184-cb3f60249af7@arm.com>
 <aUGOPd7gNRf1xHEc@e129823.arm.com>
 <100cc8da-b826-4fc2-a624-746bf6fb049d@arm.com>
 <aUKKZR0u22KOPfd7@e129823.arm.com>
 <d96ac977-222e-4e8d-9487-da1306198419@arm.com>
 <93327680-7d7d-415e-958b-0d2a667dbb52@os.amperecomputing.com>
Message-ID: <aUuPk6fj1wUPfypI@e129823.arm.com>

Hi Yang,

> On 12/17/25 9:04 PM, Ryan Roberts wrote:
> > On 17/12/2025 10:48, Yeoreum Yun wrote:
> > > Hi Ryan,
> > >
> > > > On 16/12/2025 16:52, Yeoreum Yun wrote:
> > > > > Hi Ryan,
> > > > >
> > > > > > On 12/12/2025 16:18, Yeoreum Yun wrote:
> > > > > > > Some architectures invoke pagetable_alloc() or __get_free_pages()
> > > > > > > with preemption disabled.
> > > > > > > For example, in arm64, linear_map_split_to_ptes() calls pagetable_alloc()
> > > > > > > while spliting block entry to ptes and __kpti_install_ng_mappings()
> > > > > > > calls __get_free_pages() to create kpti pagetable.
> > > > > > >
> > > > > > > Under PREEMPT_RT, calling pagetable_alloc() with
> > > > > > > preemption disabled is not allowed, because it may acquire
> > > > > > > a spin lock that becomes sleepable on RT, potentially
> > > > > > > causing a sleep during page allocation.
> > > > > > >
> > > > > > > Since above two functions is called as callback of stop_machine()
> > > > > > > where its callback is called in preemption disabled,
> > > > > > > They could make a potential problem. (sleeping in preemption disabled).
> > > > > > >
> > > > > > > To address this, introduce pagetable_alloc_nolock() API.
> > > > > > I don't really understand what the problem is that you're trying to fix. As I
> > > > > > see it, there are 2 call sites in arm64 arch code that are calling into the page
> > > > > > allocator from stop_machine() - one via via pagetable_alloc() and another via
> > > > > > __get_free_pages(). But both of those calls are passing in GFP_ATOMIC. It was my
> > > > > > understanding that the page allocator would ensure it never sleeps when
> > > > > > GFP_ATOMIC is passed in, (even for PREEMPT_RT)?
> > > > > Although GFP_ATOMIC is specify, it only affects of "water mark" of the
> > > > > page with __GFP_HIGH. and to get a page, it must grab the lock --
> > > > > zone->lock or pcp_lock in the rmqueue().
> > > > >
> > > > > This zone->lock and pcp_lock is spin_lock and it's a sleepable in
> > > > > PREEMPT_RT that's why the memory allocation/free using general API
> > > > > except nolock() version couldn't be called since
> > > > > if "contention" happens they'll sleep while waiting to get the lock.
> > > > >
> > > > > The reason why "nolock()" can use, it always uses "trylock" with
> > > > > ALLOC_TRYLOCK flags. otherwise GFP_ATOMIC also can be sleepable in
> > > > > PREEMPT_RT.
> > > > >
> > > > > > What is the actual symptom you are seeing?
> > > > > Since the place where called while smp_cpus_done() and there seems no
> > > > > contention, there seems no problem. However as I mention in another
> > > > > thread
> > > > > (https://lore.kernel.org/all/aT%2FdrjN1BkvyAGoi at e129823.arm.com/),
> > > > > This gives a the false impression --
> > > > > GFP_ATOMIC are ?safe to use in preemption disabled?
> > > > > even though they are not in PREEMPT_RT case, I've changed it.
> > > > >
> > > > > > If the page allocator is somehow ignoring the GFP_ATOMIC request for PREEMPT_RT,
> > > > > > then isn't that a bug in the page allocator? I'm not sure why you would change
> > > > > > the callsites? Can't you just change the page allocator based on GFP_ATOMIC?
> > > > > It doesn't ignore the GFP_ATOMIC feature:
> > > > >    - __GFP_HIGH: use water mark till min reserved
> > > > >    - __GFP_KSWAPD_RECLAIM: wake up kswapd if reclaim required.
> > > > >
> > > > > But, it's a restriction -- "page allocation / free" API cannot be called
> > > > > in preempt-disabled context at PREEMPT_RT.
> > > > >
> > > > > That's why I think it's wrong usage not a page allocator bug.
> > > > I've taken a look at this and I agree with your analysis. Thanks for explaining.
> > > >
> > > > Looking at other stop_machine() callbacks, there are some that call printk() and
> > > > I would assume that spinlocks could be taken there which may present the same
> > > > kind of issue or PREEMPT_RT? (I'm guessing). I don't see any others that attempt
> > > > to allocate memory though.
> > > IIRC, there was a problem related for printk while try to grab
> > > pl011_console related lock (spin_lock) while holding
> > > console_lock(raw_spin_lock) in v6.10.0-rc7 at rpi5:
> > >
> > >      [  230.381263] CPU: 2 PID: 5574 Comm: syz.4.1695 Not tainted 6.10.0-rc7-01903-g52828ea60dfd #3
> > >      [  230.381479] Hardware name: linux,dummy-virt (DT)
> > >      [  230.381565] Call trace:
> > >      [  230.381607]  dump_backtrace+0x318/0x348
> > >      [  230.381727]  show_stack+0x4c/0x80
> > >      [  230.381875]  dump_stack_lvl+0x214/0x328
> > >      [  230.382159]  dump_stack+0x3c/0x58
> > >      [  230.382456]  __lock_acquire+0x4398/0x4720
> > >      [  230.382683]  lock_acquire+0x648/0xb70
> > >      [  230.382928]  _raw_spin_lock_irqsave+0x138/0x240
> > >      [  230.383121]  pl011_console_write+0x240/0x8a0
> > >      [  230.383356]  console_flush_all+0x708/0x1368
> > >      [  230.383571]  console_unlock+0x180/0x440
> > >      [  230.383742]  vprintk_emit+0x1f8/0x9d0
> > >      [  230.383832]  vprintk_default+0x64/0x90
> > >      [  230.383914]  vprintk+0x2d0/0x400
> > >      [  230.383971]  _printk+0xdc/0x128
> > >      [  230.384229]  hrtimer_interrupt+0x8f0/0x920
> > >      [  230.384414]  arch_timer_handler_virt+0xc0/0x100
> > >      [  230.384812]  handle_percpu_devid_irq+0x20c/0x4e0
> > >      [  230.385053]  generic_handle_domain_irq+0xc0/0x120
> > >      [  230.385367]  gic_handle_irq+0x88/0x360
> > >      [  230.385559]  call_on_irq_stack+0x24/0x70
> > >      [  230.385801]  do_interrupt_handler+0xf8/0x200
> > >      [  230.386092]  el1_interrupt+0x68/0xc0
> > >      [  230.386434]  el1h_64_irq_handler+0x18/0x28
> > >      [  230.386716]  el1h_64_irq+0x64/0x68
> > >      [  230.386853]  __sanitizer_cov_trace_const_cmp2+0x30/0x68
> > >      [  230.387026]  alloc_pages_mpol_noprof+0x170/0x698
> > >      [  230.387309]  vma_alloc_folio_noprof+0x128/0x2a8
> > >      [  230.387610]  vma_alloc_zeroed_movable_folio+0xa0/0xe0
> > >      [  230.387822]  folio_prealloc+0x5c/0x280
> > >      [  230.388008]  do_wp_page+0xc30/0x3bc0
> > >      [  230.388206]  __handle_mm_fault+0xdb8/0x2ba0
> > >      [  230.388448]  handle_mm_fault+0x194/0x8a8
> > >      [  230.388676]  do_page_fault+0x6bc/0x1030
> > >      [  230.388924]  do_mem_abort+0x8c/0x240
> > >      [  230.389056]  el0_da+0xf0/0x3f8
> > >      [  230.389178]  el0t_64_sync_handler+0xb4/0x130
> > >      [  230.389452]  el0t_64_sync+0x190/0x198
> > >
> > > But this problem is gone when I try with some of patches in rt-tree
> > > related for printk which are merged in current tree
> > > (https://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git/log/?h=linux-6.10.y-rt-rebase).
> > >
> > > So I think printk() wouldn't be a problem.
> > >
> > > > Anyway, to fix the 2 arm64 callsites, I see 2 possible approaches:
> > > >
> > > > - Call the nolock variant (as you are doing). But that would just convert a
> > > > deadlock to a panic; if the lock is held when stop_machine() runs, without your
> > > > change, we now have a deadlock due to waiting on the lock inside stop_machine().
> > > > With your change, we notice the lock is already taken and panic. I guess it is
> > > > marginally better, but not by much. Certainly I would just _always_ call the
> > > > nolock variant regardless of PREEMPT_RT if we take this route; For !PREEMPT_RT,
> > > > the lock is guarranteed to be free so nolock will always succeed.
> > > >
> > > > - Preallocate the memory before entering stop_machine(). I think this would be
> > > > much more robust. For kpti_install_ng_mappings() I think you could hoist the
> > > > allocation/free out of stop_machine() and pass the pointer in pretty easily. For
> > > > linear_map_split_to_ptes() its a bit more complex; Perhaps, we need to walk the
> > > > pgtable to figure out how much to preallocate, allocate it, then set it up as a
> > > > special allocator, wrapped by an allocation function and modify the callchain to
> > > > take a callback function instead of gfp flags.
> > > >
> > > > What do you think?
> > > Definitely, second suggestoin is much better.
> > > My question is whether *memory contention* really happen in the point
> > > both functions are called.
> > My guess would be that it's unlikely, but not impossible. The secondary CPUs are
> > up, and presumably running their idle thread. I think various power management
> > things can be plugged into the idle thread; if so, then I guess it's possible
> > that the CPU could be running some hook as part of a power state transition, and
> > that could be dynamically allocating memory? That's all just a guess though; I
> > don't know the details of that part of the system.
>
> Sorry for chiming in late. I was just done my travel, but still suffered
> from jet lag. I may be out of my mind...

No worries. and I hope you feel better soon :).

>
> I agree the sleeping lock is a problem for -rt kernel. But it is hard for me
> to understand how come the lock contention could happen. When the boot CPU
> is repainting the linear map, the secondary CPUs are running in a busy loop
> to wait for idmap_kpti_bbml2_flag is cleared by the boot CPU instead of idle
> thread. And the secondary CPUs running with idmap active and init_mm
> inactive. So the nolock variant seems good enough to me if I don't miss
> anything.

As Ryan said, ?It?s unlikely, but not impossible.?

For example, suppose someone creates a kthread bound to a CPU
other than the kernel_init() task during early_initcall,
and that thread performs memory allocation.
(Of course, I don?t expect anyone to actually do this;
it?s just to illustrate that it?s not impossible.)

When that CPU comes online, the kthread will be scheduled and will attempt to allocate memory.

Meanwhile, another CPU executing smp_init() calls smp_cpus_done() and
then invokes linear_map_split_to_ptes().

If the kthread performing memory allocation is preempted
by the stopper thread at that point, linear_map_split_to_ptes() could fail,
because the memory-allocation-related lock is already held by the kthread.

So, I've sent a new version of this:
  - https://lore.kernel.org/all/20251218194750.395301-1-yeoreum.yun at arm.com/


Thanks!

--
Sincerely,
Yeoreum Yun


From peng.fan at nxp.com  Tue Dec 23 23:08:55 2025
From: peng.fan at nxp.com (Peng Fan)
Date: Wed, 24 Dec 2025 07:08:55 +0000
Subject: [PATCH v7 1/3] dt-bindings: soc: imx93-media-blk-ctrl: Add PDFC
 subnode to schema and example
In-Reply-To: <033450ab-f14d-4bf7-b7ee-aaffd014820d@lunn.ch>
References: <20251202-v6-18-topic-imx93-parallel-display-v7-0-2cce31d64608@pengutronix.de>
 <20251202-v6-18-topic-imx93-parallel-display-v7-1-2cce31d64608@pengutronix.de>
 <705773fc-5aba-4bff-b05e-272e1cd0262c@nxp.com>
 <20251215161706.2ea3wtu3xlwcxxar@pengutronix.de>
 <7127040f-55ab-4bfa-8795-1df76085470c@kernel.org>
 <20251219153537.zgxcokyhcqerw4jp@pengutronix.de>
 <033450ab-f14d-4bf7-b7ee-aaffd014820d@lunn.ch>
Message-ID: <PAXPR04MB84599D676EC1E3879694579688B2A@PAXPR04MB8459.eurprd04.prod.outlook.com>

> Subject: Re: [PATCH v7 1/3] dt-bindings: soc: imx93-media-blk-ctrl:
> Add PDFC subnode to schema and example
> 
> > We discussed the ranges/reg usage internally as well with the
> > following
> > outcome:
> >
> > - Situation
> >
> >   With i.MX8M SoCs NXP introduced MIX domains. Each domain has
> a so
> >   called BLK-CTRL IP. There is no common register layout for the
> >   BLK-CTRL IPs. In addition to this, the register fields within one
> >   register may not related to the same IP. Please see my below
> example:
> >
> >   The DISP_MUX register configures the DPI output routed to physical
> >   SoC pads as well as the internal MIPI-DSI DPI behavior. This PDFC
> >   bridge binding is only interested in the first part, not the 2nd.
> >
> >   In other words, the BLK-CTRL IP can be seen as a bunch of loose
> >   register fields.
> 
> Why do hardware engineers keep on insisting on doing this. And why
> don't software engineers when asked to review the proposed registers
> push back and say No?
> 
> I know this is out of you hands, but it is something we should
> encourage software engineers at SoC vendors to do. Otherwise we will
> have to continually live with such a mess.

This is kind of system architecture. There are several mixes in the SoC,
each mix is a group of IPs(in-house designed or 3rd party). The blk-ctrl
module is to do various settings that could be done in each IP.

I agree that BLK-CTRL is not good for software usage, and we need to
discuss with architectures for future improvements.

Thanks,
Peng.

> 
>      Andrew


From sjoerd at collabora.com  Tue Dec 23 23:30:09 2025
From: sjoerd at collabora.com (Sjoerd Simons)
Date: Wed, 24 Dec 2025 08:30:09 +0100
Subject: [PATCH 0/4] clk: mediatek: Fix no-gate mux declarations
Message-ID: <20251224-mtk-not-a-gate-v1-0-d4667e3b7856@collabora.com>

When booting a MT7981 board (OpenWRT One) with UBSAN, the following
error showed up:

```
UBSAN: shift-out-of-bounds in drivers/clk/mediatek/clk-mux.c:76:8
shift exponent 255 is too large for 64-bit type 'long unsigned int'
```

This is due to various infra muxes being declared as MUX_GATE_ even
though they don't actually have a gate.

First patch in this series adds a helper to make it easier to declare
muxes that neither have a gate nor update registers. This seems common
for MT798* infra muxes. The following ones corrects the incorrect mux
definitions by transitioning to this new declaration.

Signed-off-by: Sjoerd Simons <sjoerd at collabora.com>
---
Sjoerd Simons (4):
      clk: mediatek: clk-mux: Add helper for muxes without UPD
      clk: mediatek: Declare MT7981 infra muxes as no-gate muxes
      clk: mediatek: Declare MT7986 infra muxes as no-gate muxes
      clk: mediatek: Declare MT7988 infra muxes as no-gate muxes

 drivers/clk/mediatek/clk-mt7981-infracfg.c | 55 ++++++++-----------
 drivers/clk/mediatek/clk-mt7986-infracfg.c | 45 ++++++---------
 drivers/clk/mediatek/clk-mt7988-infracfg.c | 88 ++++++++++++++++--------------
 drivers/clk/mediatek/clk-mux.h             |  7 +++
 4 files changed, 93 insertions(+), 102 deletions(-)
---
base-commit: b927546677c876e26eba308550207c2ddf812a43
change-id: 20251224-mtk-not-a-gate-ec0b6b6851a8

Best regards,
-- 
Sjoerd Simons <sjoerd at collabora.com>



From sjoerd at collabora.com  Tue Dec 23 23:30:13 2025
From: sjoerd at collabora.com (Sjoerd Simons)
Date: Wed, 24 Dec 2025 08:30:13 +0100
Subject: [PATCH 4/4] clk: mediatek: Declare MT7988 infra muxes as no-gate
 muxes
In-Reply-To: <20251224-mtk-not-a-gate-v1-0-d4667e3b7856@collabora.com>
References: <20251224-mtk-not-a-gate-v1-0-d4667e3b7856@collabora.com>
Message-ID: <20251224-mtk-not-a-gate-v1-4-d4667e3b7856@collabora.com>

A MUX_GATE without a gate, is really just a MUX. Adjust the mux
declarations to match that. This fixes out-of-bounds shifts due to no
longer trying to enable/disable the gate with a shift of (u8)-1.

Fixes: 4b4719437d85 ("clk: mediatek: add drivers for MT7988 SoC")
Signed-off-by: Sjoerd Simons <sjoerd at collabora.com>
---
 drivers/clk/mediatek/clk-mt7988-infracfg.c | 88 ++++++++++++++++--------------
 1 file changed, 46 insertions(+), 42 deletions(-)

diff --git a/drivers/clk/mediatek/clk-mt7988-infracfg.c b/drivers/clk/mediatek/clk-mt7988-infracfg.c
index ef8267319d91..69e86fc29d73 100644
--- a/drivers/clk/mediatek/clk-mt7988-infracfg.c
+++ b/drivers/clk/mediatek/clk-mt7988-infracfg.c
@@ -56,49 +56,53 @@ static const char *const infra_pcie_gfmux_tl_ck_o_p3_parents[] __initconst = {
 
 static const struct mtk_mux infra_muxes[] = {
 	/* MODULE_CLK_SEL_0 */
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_UART0_SEL, "infra_mux_uart0_sel",
-			     infra_mux_uart0_parents, 0x0018, 0x0010, 0x0014, 0, 1, -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_UART1_SEL, "infra_mux_uart1_sel",
-			     infra_mux_uart1_parents, 0x0018, 0x0010, 0x0014, 1, 1, -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_UART2_SEL, "infra_mux_uart2_sel",
-			     infra_mux_uart2_parents, 0x0018, 0x0010, 0x0014, 2, 1, -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_SPI0_SEL, "infra_mux_spi0_sel", infra_mux_spi0_parents,
-			     0x0018, 0x0010, 0x0014, 4, 1, -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_SPI1_SEL, "infra_mux_spi1_sel", infra_mux_spi1_parents,
-			     0x0018, 0x0010, 0x0014, 5, 1, -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_SPI2_SEL, "infra_mux_spi2_sel", infra_mux_spi0_parents,
-			     0x0018, 0x0010, 0x0014, 6, 1, -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_SEL, "infra_pwm_sel", infra_pwm_bck_parents, 0x0018,
-			     0x0010, 0x0014, 14, 2, -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK1_SEL, "infra_pwm_ck1_sel", infra_pwm_bck_parents,
-			     0x0018, 0x0010, 0x0014, 16, 2, -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK2_SEL, "infra_pwm_ck2_sel", infra_pwm_bck_parents,
-			     0x0018, 0x0010, 0x0014, 18, 2, -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK3_SEL, "infra_pwm_ck3_sel", infra_pwm_bck_parents,
-			     0x0018, 0x0010, 0x0014, 20, 2, -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK4_SEL, "infra_pwm_ck4_sel", infra_pwm_bck_parents,
-			     0x0018, 0x0010, 0x0014, 22, 2, -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK5_SEL, "infra_pwm_ck5_sel", infra_pwm_bck_parents,
-			     0x0018, 0x0010, 0x0014, 24, 2, -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK6_SEL, "infra_pwm_ck6_sel", infra_pwm_bck_parents,
-			     0x0018, 0x0010, 0x0014, 26, 2, -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK7_SEL, "infra_pwm_ck7_sel", infra_pwm_bck_parents,
-			     0x0018, 0x0010, 0x0014, 28, 2, -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK8_SEL, "infra_pwm_ck8_sel", infra_pwm_bck_parents,
-			     0x0018, 0x0010, 0x0014, 30, 2, -1, -1, -1),
+	MUX_CLR_SET(CLK_INFRA_MUX_UART0_SEL, "infra_mux_uart0_sel",
+		    infra_mux_uart0_parents, 0x0018, 0x0010, 0x0014, 0, 1),
+	MUX_CLR_SET(CLK_INFRA_MUX_UART1_SEL, "infra_mux_uart1_sel",
+		    infra_mux_uart1_parents, 0x0018, 0x0010, 0x0014, 1, 1),
+	MUX_CLR_SET(CLK_INFRA_MUX_UART2_SEL, "infra_mux_uart2_sel",
+		    infra_mux_uart2_parents, 0x0018, 0x0010, 0x0014, 2, 1),
+	MUX_CLR_SET(CLK_INFRA_MUX_SPI0_SEL, "infra_mux_spi0_sel",
+		    infra_mux_spi0_parents, 0x0018, 0x0010, 0x0014, 4, 1),
+	MUX_CLR_SET(CLK_INFRA_MUX_SPI1_SEL, "infra_mux_spi1_sel",
+		    infra_mux_spi1_parents, 0x0018, 0x0010, 0x0014, 5, 1),
+	MUX_CLR_SET(CLK_INFRA_MUX_SPI2_SEL, "infra_mux_spi2_sel",
+		    infra_mux_spi0_parents, 0x0018, 0x0010, 0x0014, 6, 1),
+	MUX_CLR_SET(CLK_INFRA_PWM_SEL, "infra_pwm_sel",
+		    infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 14, 2),
+	MUX_CLR_SET(CLK_INFRA_PWM_CK1_SEL, "infra_pwm_ck1_sel",
+		    infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 16, 2),
+	MUX_CLR_SET(CLK_INFRA_PWM_CK2_SEL, "infra_pwm_ck2_sel",
+		    infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 18, 2),
+	MUX_CLR_SET(CLK_INFRA_PWM_CK3_SEL, "infra_pwm_ck3_sel",
+		    infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 20, 2),
+	MUX_CLR_SET(CLK_INFRA_PWM_CK4_SEL, "infra_pwm_ck4_sel",
+		    infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 22, 2),
+	MUX_CLR_SET(CLK_INFRA_PWM_CK5_SEL, "infra_pwm_ck5_sel",
+		    infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 24, 2),
+	MUX_CLR_SET(CLK_INFRA_PWM_CK6_SEL, "infra_pwm_ck6_sel",
+		    infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 26, 2),
+	MUX_CLR_SET(CLK_INFRA_PWM_CK7_SEL, "infra_pwm_ck7_sel",
+		    infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 28, 2),
+	MUX_CLR_SET(CLK_INFRA_PWM_CK8_SEL, "infra_pwm_ck8_sel",
+		    infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 30, 2),
 	/* MODULE_CLK_SEL_1 */
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_GFMUX_TL_O_P0_SEL, "infra_pcie_gfmux_tl_o_p0_sel",
-			     infra_pcie_gfmux_tl_ck_o_p0_parents, 0x0028, 0x0020, 0x0024, 0, 2, -1,
-			     -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_GFMUX_TL_O_P1_SEL, "infra_pcie_gfmux_tl_o_p1_sel",
-			     infra_pcie_gfmux_tl_ck_o_p1_parents, 0x0028, 0x0020, 0x0024, 2, 2, -1,
-			     -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_GFMUX_TL_O_P2_SEL, "infra_pcie_gfmux_tl_o_p2_sel",
-			     infra_pcie_gfmux_tl_ck_o_p2_parents, 0x0028, 0x0020, 0x0024, 4, 2, -1,
-			     -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_GFMUX_TL_O_P3_SEL, "infra_pcie_gfmux_tl_o_p3_sel",
-			     infra_pcie_gfmux_tl_ck_o_p3_parents, 0x0028, 0x0020, 0x0024, 6, 2, -1,
-			     -1, -1),
+	MUX_CLR_SET(CLK_INFRA_PCIE_GFMUX_TL_O_P0_SEL,
+		    "infra_pcie_gfmux_tl_o_p0_sel",
+		    infra_pcie_gfmux_tl_ck_o_p0_parents,
+		    0x0028, 0x0020, 0x0024, 0, 2),
+	MUX_CLR_SET(CLK_INFRA_PCIE_GFMUX_TL_O_P1_SEL,
+		    "infra_pcie_gfmux_tl_o_p1_sel",
+		    infra_pcie_gfmux_tl_ck_o_p1_parents,
+		    0x0028, 0x0020, 0x0024, 2, 2),
+	MUX_CLR_SET(CLK_INFRA_PCIE_GFMUX_TL_O_P2_SEL,
+		    "infra_pcie_gfmux_tl_o_p2_sel",
+		    infra_pcie_gfmux_tl_ck_o_p2_parents,
+		    0x0028, 0x0020, 0x0024, 4, 2),
+	MUX_CLR_SET(CLK_INFRA_PCIE_GFMUX_TL_O_P3_SEL,
+		    "infra_pcie_gfmux_tl_o_p3_sel",
+		    infra_pcie_gfmux_tl_ck_o_p3_parents,
+		    0x0028, 0x0020, 0x0024, 6, 2),
 };
 
 static const struct mtk_gate_regs infra0_cg_regs = {

-- 
2.51.0



From sjoerd at collabora.com  Tue Dec 23 23:30:10 2025
From: sjoerd at collabora.com (Sjoerd Simons)
Date: Wed, 24 Dec 2025 08:30:10 +0100
Subject: [PATCH 1/4] clk: mediatek: clk-mux: Add helper for muxes without
 UPD
In-Reply-To: <20251224-mtk-not-a-gate-v1-0-d4667e3b7856@collabora.com>
References: <20251224-mtk-not-a-gate-v1-0-d4667e3b7856@collabora.com>
Message-ID: <20251224-mtk-not-a-gate-v1-1-d4667e3b7856@collabora.com>

Not all muxes have an update register. This is already handled by the
driver when the upd_shift field is set negative. Add a small helper
macro to declare these muxes, without having to pass a bunch of -1's.

Signed-off-by: Sjoerd Simons <sjoerd at collabora.com>
---
 drivers/clk/mediatek/clk-mux.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/clk/mediatek/clk-mux.h b/drivers/clk/mediatek/clk-mux.h
index 151e56dcf884..1a385cdd00d0 100644
--- a/drivers/clk/mediatek/clk-mux.h
+++ b/drivers/clk/mediatek/clk-mux.h
@@ -126,6 +126,13 @@ extern const struct clk_ops mtk_mux_gate_hwv_fenc_clr_set_upd_ops;
 			0, _upd_ofs, _upd, CLK_SET_RATE_PARENT,		\
 			mtk_mux_clr_set_upd_ops)
 
+#define MUX_CLR_SET(_id, _name, _parents, _mux_ofs,			\
+		    _mux_set_ofs, _mux_clr_ofs, _shift, _width)	\
+		GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, _mux_ofs,	\
+			_mux_set_ofs, _mux_clr_ofs, _shift, _width,	\
+			0, 0, -1, CLK_SET_RATE_PARENT,		\
+			mtk_mux_clr_set_upd_ops)
+
 #define MUX_GATE_HWV_FENC_CLR_SET_UPD_FLAGS(_id, _name, _parents,			\
 				_mux_ofs, _mux_set_ofs, _mux_clr_ofs,			\
 				_hwv_sta_ofs, _hwv_set_ofs, _hwv_clr_ofs,		\

-- 
2.51.0



From sjoerd at collabora.com  Tue Dec 23 23:30:12 2025
From: sjoerd at collabora.com (Sjoerd Simons)
Date: Wed, 24 Dec 2025 08:30:12 +0100
Subject: [PATCH 3/4] clk: mediatek: Declare MT7986 infra muxes as no-gate
 muxes
In-Reply-To: <20251224-mtk-not-a-gate-v1-0-d4667e3b7856@collabora.com>
References: <20251224-mtk-not-a-gate-v1-0-d4667e3b7856@collabora.com>
Message-ID: <20251224-mtk-not-a-gate-v1-3-d4667e3b7856@collabora.com>

A MUX_GATE without a gate, is really just a MUX. Adjust the mux
declarations to match that. This fixes out-of-bounds shifts due to no
longer trying to enable/disable the gate with a shift of (u8)-1.

Fixes: ec97d23c8e22 ("clk: mediatek: add mt7986 clock support")
Signed-off-by: Sjoerd Simons <sjoerd at collabora.com>
---
 drivers/clk/mediatek/clk-mt7986-infracfg.c | 45 ++++++++++++------------------
 1 file changed, 18 insertions(+), 27 deletions(-)

diff --git a/drivers/clk/mediatek/clk-mt7986-infracfg.c b/drivers/clk/mediatek/clk-mt7986-infracfg.c
index 732c65e616de..458b26ff2efc 100644
--- a/drivers/clk/mediatek/clk-mt7986-infracfg.c
+++ b/drivers/clk/mediatek/clk-mt7986-infracfg.c
@@ -37,34 +37,25 @@ static const char *const infra_pcie_parents[] __initconst = {
 
 static const struct mtk_mux infra_muxes[] = {
 	/* MODULE_CLK_SEL_0 */
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_UART0_SEL, "infra_uart0_sel",
-			     infra_uart_parent, 0x0018, 0x0010, 0x0014, 0, 1,
-			     -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_UART1_SEL, "infra_uart1_sel",
-			     infra_uart_parent, 0x0018, 0x0010, 0x0014, 1, 1,
-			     -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_UART2_SEL, "infra_uart2_sel",
-			     infra_uart_parent, 0x0018, 0x0010, 0x0014, 2, 1,
-			     -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_SPI0_SEL, "infra_spi0_sel",
-			     infra_spi_parents, 0x0018, 0x0010, 0x0014, 4, 1,
-			     -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_SPI1_SEL, "infra_spi1_sel",
-			     infra_spi_parents, 0x0018, 0x0010, 0x0014, 5, 1,
-			     -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM1_SEL, "infra_pwm1_sel",
-			     infra_pwm_bsel_parents, 0x0018, 0x0010, 0x0014, 9,
-			     2, -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM2_SEL, "infra_pwm2_sel",
-			     infra_pwm_bsel_parents, 0x0018, 0x0010, 0x0014, 11,
-			     2, -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_BSEL, "infra_pwm_bsel",
-			     infra_pwm_bsel_parents, 0x0018, 0x0010, 0x0014, 13,
-			     2, -1, -1, -1),
+	MUX_CLR_SET(CLK_INFRA_UART0_SEL, "infra_uart0_sel",
+		    infra_uart_parent, 0x0018, 0x0010, 0x0014, 0, 1),
+	MUX_CLR_SET(CLK_INFRA_UART1_SEL, "infra_uart1_sel",
+		    infra_uart_parent, 0x0018, 0x0010, 0x0014, 1, 1),
+	MUX_CLR_SET(CLK_INFRA_UART2_SEL, "infra_uart2_sel",
+		    infra_uart_parent, 0x0018, 0x0010, 0x0014, 2, 1),
+	MUX_CLR_SET(CLK_INFRA_SPI0_SEL, "infra_spi0_sel",
+		    infra_spi_parents, 0x0018, 0x0010, 0x0014, 4, 1),
+	MUX_CLR_SET(CLK_INFRA_SPI1_SEL, "infra_spi1_sel",
+		    infra_spi_parents, 0x0018, 0x0010, 0x0014, 5, 1),
+	MUX_CLR_SET(CLK_INFRA_PWM1_SEL, "infra_pwm1_sel",
+		    infra_pwm_bsel_parents, 0x0018, 0x0010, 0x0014, 9, 2),
+	MUX_CLR_SET(CLK_INFRA_PWM2_SEL, "infra_pwm2_sel",
+		    infra_pwm_bsel_parents, 0x0018, 0x0010, 0x0014, 11, 2),
+	MUX_CLR_SET(CLK_INFRA_PWM_BSEL, "infra_pwm_bsel",
+		    infra_pwm_bsel_parents, 0x0018, 0x0010, 0x0014, 13, 2),
 	/* MODULE_CLK_SEL_1 */
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_SEL, "infra_pcie_sel",
-			     infra_pcie_parents, 0x0028, 0x0020, 0x0024, 0, 2,
-			     -1, -1, -1),
+	MUX_CLR_SET(CLK_INFRA_PCIE_SEL, "infra_pcie_sel",
+		    infra_pcie_parents, 0x0028, 0x0020, 0x0024, 0, 2),
 };
 
 static const struct mtk_gate_regs infra0_cg_regs = {

-- 
2.51.0



From sjoerd at collabora.com  Tue Dec 23 23:30:11 2025
From: sjoerd at collabora.com (Sjoerd Simons)
Date: Wed, 24 Dec 2025 08:30:11 +0100
Subject: [PATCH 2/4] clk: mediatek: Declare MT7981 infra muxes as no-gate
 muxes
In-Reply-To: <20251224-mtk-not-a-gate-v1-0-d4667e3b7856@collabora.com>
References: <20251224-mtk-not-a-gate-v1-0-d4667e3b7856@collabora.com>
Message-ID: <20251224-mtk-not-a-gate-v1-2-d4667e3b7856@collabora.com>

A MUX_GATE without a gate, is really just a MUX. Adjust the mux
declarations to match that. This fixes out-of-bounds shifts due to no
longer trying to enable/disable the gate with a shift of (u8)-1.

Fixes: 813c3b53b55b ("clk: mediatek: add MT7981 clock support")
Signed-off-by: Sjoerd Simons <sjoerd at collabora.com>
---
 drivers/clk/mediatek/clk-mt7981-infracfg.c | 55 ++++++++++++------------------
 1 file changed, 22 insertions(+), 33 deletions(-)

diff --git a/drivers/clk/mediatek/clk-mt7981-infracfg.c b/drivers/clk/mediatek/clk-mt7981-infracfg.c
index 0487b6bb80ae..574930e87fbe 100644
--- a/drivers/clk/mediatek/clk-mt7981-infracfg.c
+++ b/drivers/clk/mediatek/clk-mt7981-infracfg.c
@@ -44,40 +44,29 @@ static const char *const infra_pcie_parents[] __initconst = {
 
 static const struct mtk_mux infra_muxes[] = {
 	/* MODULE_CLK_SEL_0 */
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_UART0_SEL, "infra_uart0_sel",
-			     infra_uart_parent, 0x0018, 0x0010, 0x0014, 0, 1,
-			     -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_UART1_SEL, "infra_uart1_sel",
-			     infra_uart_parent, 0x0018, 0x0010, 0x0014, 1, 1,
-			     -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_UART2_SEL, "infra_uart2_sel",
-			     infra_uart_parent, 0x0018, 0x0010, 0x0014, 2, 1,
-			     -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_SPI0_SEL, "infra_spi0_sel",
-			     infra_spi0_parents, 0x0018, 0x0010, 0x0014, 4, 1,
-			     -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_SPI1_SEL, "infra_spi1_sel",
-			     infra_spi1_parents, 0x0018, 0x0010, 0x0014, 5, 1,
-			     -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_SPI2_SEL, "infra_spi2_sel",
-			     infra_spi0_parents, 0x0018, 0x0010, 0x0014, 6, 1,
-			     -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM1_SEL, "infra_pwm1_sel",
-			     infra_pwm1_parents, 0x0018, 0x0010, 0x0014, 9, 1,
-			     -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM2_SEL, "infra_pwm2_sel",
-			     infra_pwm1_parents, 0x0018, 0x0010, 0x0014, 11, 1,
-			     -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM3_SEL, "infra_pwm3_sel",
-			     infra_pwm1_parents, 0x0018, 0x0010, 0x0014, 15, 1,
-			     -1, -1, -1),
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_BSEL, "infra_pwm_bsel",
-			     infra_pwm_bsel_parents, 0x0018, 0x0010, 0x0014, 13,
-			     2, -1, -1, -1),
+	MUX_CLR_SET(CLK_INFRA_UART0_SEL, "infra_uart0_sel",
+		    infra_uart_parent, 0x0018, 0x0010, 0x0014, 0, 1),
+	MUX_CLR_SET(CLK_INFRA_UART1_SEL, "infra_uart1_sel",
+		    infra_uart_parent, 0x0018, 0x0010, 0x0014, 1, 1),
+	MUX_CLR_SET(CLK_INFRA_UART2_SEL, "infra_uart2_sel",
+		    infra_uart_parent, 0x0018, 0x0010, 0x0014, 2, 1),
+	MUX_CLR_SET(CLK_INFRA_SPI0_SEL, "infra_spi0_sel",
+		    infra_spi0_parents, 0x0018, 0x0010, 0x0014, 4, 1),
+	MUX_CLR_SET(CLK_INFRA_SPI1_SEL, "infra_spi1_sel",
+		    infra_spi1_parents, 0x0018, 0x0010, 0x0014, 5, 1),
+	MUX_CLR_SET(CLK_INFRA_SPI2_SEL, "infra_spi2_sel",
+		    infra_spi0_parents, 0x0018, 0x0010, 0x0014, 6, 1),
+	MUX_CLR_SET(CLK_INFRA_PWM1_SEL, "infra_pwm1_sel",
+		    infra_pwm1_parents, 0x0018, 0x0010, 0x0014, 9, 1),
+	MUX_CLR_SET(CLK_INFRA_PWM2_SEL, "infra_pwm2_sel",
+		    infra_pwm1_parents, 0x0018, 0x0010, 0x0014, 11, 1),
+	MUX_CLR_SET(CLK_INFRA_PWM3_SEL, "infra_pwm3_sel",
+		    infra_pwm1_parents, 0x0018, 0x0010, 0x0014, 15, 1),
+	MUX_CLR_SET(CLK_INFRA_PWM_BSEL, "infra_pwm_bsel",
+		    infra_pwm_bsel_parents, 0x0018, 0x0010, 0x0014, 13, 2),
 	/* MODULE_CLK_SEL_1 */
-	MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_SEL, "infra_pcie_sel",
-			     infra_pcie_parents, 0x0028, 0x0020, 0x0024, 0, 2,
-			     -1, -1, -1),
+	MUX_CLR_SET(CLK_INFRA_PCIE_SEL, "infra_pcie_sel",
+		    infra_pcie_parents, 0x0028, 0x0020, 0x0024, 0, 2),
 };
 
 static const struct mtk_gate_regs infra0_cg_regs = {

-- 
2.51.0



From vkoul at kernel.org  Tue Dec 23 23:32:43 2025
From: vkoul at kernel.org (Vinod Koul)
Date: Wed, 24 Dec 2025 13:02:43 +0530
Subject: [PATCH v3 0/9] phy: convert from clk round_rate() to
 determine_rate()
In-Reply-To: <20251212-phy-clk-round-rate-v3-0-beae3962f767@redhat.com>
References: <20251212-phy-clk-round-rate-v3-0-beae3962f767@redhat.com>
Message-ID: <176656156358.817806.16966474957670370356.b4-ty@kernel.org>


On Fri, 12 Dec 2025 08:16:18 +0900, Brian Masney wrote:
> The round_rate() clk ops is deprecated in the clk framework in favor
> of the determine_rate() clk ops, so let's go ahead and convert the
> drivers in the phy subsystem using the Coccinelle semantic patch
> posted below. I did a few minor cosmetic cleanups of the code in a
> few cases.
> 
> Changes since v2:
> - Patch 8 (phy-rockchip-samsung-hdptx): fixed merge conflict so this now
>   applies against next-20251211. Cristian / Heiko: I kept your
>   Reviewed-by since structurally the code is still the same as before.
> - Link to v2: https://lore.kernel.org/r/20250810-phy-clk-round-rate-v2-0-9162470bb9f2 at redhat.com
> 
> [...]

Applied, thanks!

[1/9] phy: freescale: phy-fsl-samsung-hdmi: convert from round_rate() to determine_rate()
      commit: efc389fa00d1b93df8f95974c4f8c11da63671da
[2/9] phy: mediatek: phy-mtk-hdmi-mt2701: convert from round_rate() to determine_rate()
      commit: ebed08490d667141085ed873309aec5806dbb3a9
[3/9] phy: mediatek: phy-mtk-hdmi-mt8173: convert from round_rate() to determine_rate()
      commit: be4267241c196745e1f649afb7d232fe4440073a
[4/9] phy: mediatek: phy-mtk-hdmi-mt8195: convert from round_rate() to determine_rate()
      commit: 7a4ce5a9b674654ab04961a9ea03d15d71edb2a9
[5/9] phy: mediatek: phy-mtk-mipi-dsi-mt8173: convert from round_rate() to determine_rate()
      commit: 8e6bb53203d5c0a0cbc4f5cd90d8b2c6f20818ba
[6/9] phy: mediatek: phy-mtk-mipi-dsi-mt8183: convert from round_rate() to determine_rate()
      commit: 0484168a352f0f75a82d9917df4b23f5466726b7
[7/9] phy: rockchip: phy-rockchip-inno-hdmi: convert from round_rate() to determine_rate()
      commit: 2f7870297ae073b0fd6e1f875a9b84c5de0dea00
[8/9] phy: rockchip: phy-rockchip-samsung-hdptx: convert from round_rate() to determine_rate()
      commit: 3d4ffdfcf108e73b7c5bf07e0358d0fe8fac28d4
[9/9] phy: ti: phy-j721e-wiz: convert from round_rate() to determine_rate()
      commit: 27287e3b52b5954b73203d32ee76ffd5f53f5074

Best regards,
-- 
~Vinod




From tianruidong at linux.alibaba.com  Tue Dec 23 23:49:21 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Wed, 24 Dec 2025 15:49:21 +0800
Subject: [PATCH v13 2/5] arm64: add support for ARCH_HAS_COPY_MC
In-Reply-To: <20241209024257.3618492-3-tongtiangen@huawei.com>
References: <20241209024257.3618492-1-tongtiangen@huawei.com>
 <20241209024257.3618492-3-tongtiangen@huawei.com>
Message-ID: <db72933f-cda7-4196-8e54-73cbefbf1a26@linux.alibaba.com>

Hi Tong:

I applied this path on 6.18 and tested on Kunpeng920, system still alive 
when i inject a error in copy from user context, but I found that user 
application receive a SIGBUS, this action is different with x86 machine 
which return -EFAULT rather than send SIGBUS.

I added a patch to fix this behavior[0]. Feel free to incorporate it 
into your series, or I can send it as a formal follow-up patch, 
whichever you prefer.

[0]: https://github.com/winterddd/linux/tree/arm-copyin

Best regards,
Ruidong

? 2024/12/9 10:42, Tong Tiangen ??:
> For the arm64 kernel, when it processes hardware memory errors for
> synchronize notifications(do_sea()), if the errors is consumed within the
> kernel, the current processing is panic. However, it is not optimal.
> 
> Take copy_from/to_user for example, If ld* triggers a memory error, even in
> kernel mode, only the associated process is affected. Killing the user
> process and isolating the corrupt page is a better choice.
> 
> Add new fixup type EX_TYPE_KACCESS_ERR_ZERO_MEM_ERR to identify insn
> that can recover from memory errors triggered by access to kernel memory,
> and this fixup type is used in __arch_copy_to_user(), This make the regular
> copy_to_user() will handle kernel memory errors.
> 
> Signed-off-by: Tong Tiangen <tongtiangen at huawei.com>
> ---
>   arch/arm64/Kconfig                   |  1 +
>   arch/arm64/include/asm/asm-extable.h | 31 +++++++++++++++++++++++-----
>   arch/arm64/include/asm/asm-uaccess.h |  4 ++++
>   arch/arm64/include/asm/extable.h     |  1 +
>   arch/arm64/lib/copy_to_user.S        | 10 ++++-----
>   arch/arm64/mm/extable.c              | 19 +++++++++++++++++
>   arch/arm64/mm/fault.c                | 30 ++++++++++++++++++++-------
>   7 files changed, 78 insertions(+), 18 deletions(-)
> 
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 100570a048c5..5fa54d31162c 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -21,6 +21,7 @@ config ARM64
>   	select ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE
>   	select ARCH_HAS_CACHE_LINE_SIZE
>   	select ARCH_HAS_CC_PLATFORM
> +	select ARCH_HAS_COPY_MC if ACPI_APEI_GHES
>   	select ARCH_HAS_CURRENT_STACK_POINTER
>   	select ARCH_HAS_DEBUG_VIRTUAL
>   	select ARCH_HAS_DEBUG_VM_PGTABLE
> diff --git a/arch/arm64/include/asm/asm-extable.h b/arch/arm64/include/asm/asm-extable.h
> index b8a5861dc7b7..0f9123efca0a 100644
> --- a/arch/arm64/include/asm/asm-extable.h
> +++ b/arch/arm64/include/asm/asm-extable.h
> @@ -5,11 +5,13 @@
>   #include <linux/bits.h>
>   #include <asm/gpr-num.h>
>   
> -#define EX_TYPE_NONE			0
> -#define EX_TYPE_BPF			1
> -#define EX_TYPE_UACCESS_ERR_ZERO	2
> -#define EX_TYPE_KACCESS_ERR_ZERO	3
> -#define EX_TYPE_LOAD_UNALIGNED_ZEROPAD	4
> +#define EX_TYPE_NONE				0
> +#define EX_TYPE_BPF				1
> +#define EX_TYPE_UACCESS_ERR_ZERO		2
> +#define EX_TYPE_KACCESS_ERR_ZERO		3
> +#define EX_TYPE_LOAD_UNALIGNED_ZEROPAD		4
> +/* kernel access memory error safe */
> +#define EX_TYPE_KACCESS_ERR_ZERO_MEM_ERR	5
>   
>   /* Data fields for EX_TYPE_UACCESS_ERR_ZERO */
>   #define EX_DATA_REG_ERR_SHIFT	0
> @@ -51,6 +53,17 @@
>   #define _ASM_EXTABLE_UACCESS(insn, fixup)				\
>   	_ASM_EXTABLE_UACCESS_ERR_ZERO(insn, fixup, wzr, wzr)
>   
> +#define _ASM_EXTABLE_KACCESS_ERR_ZERO_MEM_ERR(insn, fixup, err, zero)	\
> +	__ASM_EXTABLE_RAW(insn, fixup, 					\
> +			  EX_TYPE_KACCESS_ERR_ZERO_MEM_ERR,		\
> +			  (						\
> +			    EX_DATA_REG(ERR, err) |			\
> +			    EX_DATA_REG(ZERO, zero)			\
> +			  ))
> +
> +#define _ASM_EXTABLE_KACCESS_MEM_ERR(insn, fixup)			\
> +	_ASM_EXTABLE_KACCESS_ERR_ZERO_MEM_ERR(insn, fixup, wzr, wzr)
> +
>   /*
>    * Create an exception table entry for uaccess `insn`, which will branch to `fixup`
>    * when an unhandled fault is taken.
> @@ -69,6 +82,14 @@
>   	.endif
>   	.endm
>   
> +/*
> + * Create an exception table entry for kaccess `insn`, which will branch to
> + * `fixup` when an unhandled fault is taken.
> + */
> +	.macro          _asm_extable_kaccess_mem_err, insn, fixup
> +	_ASM_EXTABLE_KACCESS_MEM_ERR(\insn, \fixup)
> +	.endm
> +
>   #else /* __ASSEMBLY__ */
>   
>   #include <linux/stringify.h>
> diff --git a/arch/arm64/include/asm/asm-uaccess.h b/arch/arm64/include/asm/asm-uaccess.h
> index 5b6efe8abeeb..19aa0180f645 100644
> --- a/arch/arm64/include/asm/asm-uaccess.h
> +++ b/arch/arm64/include/asm/asm-uaccess.h
> @@ -57,6 +57,10 @@ alternative_else_nop_endif
>   	.endm
>   #endif
>   
> +#define KERNEL_MEM_ERR(l, x...)			\
> +9999:	x;					\
> +	_asm_extable_kaccess_mem_err	9999b, l
> +
>   #define USER(l, x...)				\
>   9999:	x;					\
>   	_asm_extable_uaccess	9999b, l
> diff --git a/arch/arm64/include/asm/extable.h b/arch/arm64/include/asm/extable.h
> index 72b0e71cc3de..bc49443bc502 100644
> --- a/arch/arm64/include/asm/extable.h
> +++ b/arch/arm64/include/asm/extable.h
> @@ -46,4 +46,5 @@ bool ex_handler_bpf(const struct exception_table_entry *ex,
>   #endif /* !CONFIG_BPF_JIT */
>   
>   bool fixup_exception(struct pt_regs *regs);
> +bool fixup_exception_me(struct pt_regs *regs);
>   #endif
> diff --git a/arch/arm64/lib/copy_to_user.S b/arch/arm64/lib/copy_to_user.S
> index 802231772608..bedab1678431 100644
> --- a/arch/arm64/lib/copy_to_user.S
> +++ b/arch/arm64/lib/copy_to_user.S
> @@ -20,7 +20,7 @@
>    *	x0 - bytes not copied
>    */
>   	.macro ldrb1 reg, ptr, val
> -	ldrb  \reg, [\ptr], \val
> +	KERNEL_MEM_ERR(9998f, ldrb  \reg, [\ptr], \val)
>   	.endm
>   
>   	.macro strb1 reg, ptr, val
> @@ -28,7 +28,7 @@
>   	.endm
>   
>   	.macro ldrh1 reg, ptr, val
> -	ldrh  \reg, [\ptr], \val
> +	KERNEL_MEM_ERR(9998f, ldrh  \reg, [\ptr], \val)
>   	.endm
>   
>   	.macro strh1 reg, ptr, val
> @@ -36,7 +36,7 @@
>   	.endm
>   
>   	.macro ldr1 reg, ptr, val
> -	ldr \reg, [\ptr], \val
> +	KERNEL_MEM_ERR(9998f, ldr \reg, [\ptr], \val)
>   	.endm
>   
>   	.macro str1 reg, ptr, val
> @@ -44,7 +44,7 @@
>   	.endm
>   
>   	.macro ldp1 reg1, reg2, ptr, val
> -	ldp \reg1, \reg2, [\ptr], \val
> +	KERNEL_MEM_ERR(9998f, ldp \reg1, \reg2, [\ptr], \val)
>   	.endm
>   
>   	.macro stp1 reg1, reg2, ptr, val
> @@ -64,7 +64,7 @@ SYM_FUNC_START(__arch_copy_to_user)
>   9997:	cmp	dst, dstin
>   	b.ne	9998f
>   	// Before being absolutely sure we couldn't copy anything, try harder
> -	ldrb	tmp1w, [srcin]
> +KERNEL_MEM_ERR(9998f, ldrb	tmp1w, [srcin])
>   USER(9998f, sttrb tmp1w, [dst])
>   	add	dst, dst, #1
>   9998:	sub	x0, end, dst			// bytes not copied
> diff --git a/arch/arm64/mm/extable.c b/arch/arm64/mm/extable.c
> index 228d681a8715..9ad2b6473b60 100644
> --- a/arch/arm64/mm/extable.c
> +++ b/arch/arm64/mm/extable.c
> @@ -72,7 +72,26 @@ bool fixup_exception(struct pt_regs *regs)
>   		return ex_handler_uaccess_err_zero(ex, regs);
>   	case EX_TYPE_LOAD_UNALIGNED_ZEROPAD:
>   		return ex_handler_load_unaligned_zeropad(ex, regs);
> +	case EX_TYPE_KACCESS_ERR_ZERO_MEM_ERR:
> +		return false;
>   	}
>   
>   	BUG();
>   }
> +
> +bool fixup_exception_me(struct pt_regs *regs)
> +{
> +	const struct exception_table_entry *ex;
> +
> +	ex = search_exception_tables(instruction_pointer(regs));
> +	if (!ex)
> +		return false;
> +
> +	switch (ex->type) {
> +	case EX_TYPE_UACCESS_ERR_ZERO:
> +	case EX_TYPE_KACCESS_ERR_ZERO_MEM_ERR:
> +		return ex_handler_uaccess_err_zero(ex, regs);
> +	}
> +
> +	return false;
> +}
> diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
> index ef63651099a9..278e67357f49 100644
> --- a/arch/arm64/mm/fault.c
> +++ b/arch/arm64/mm/fault.c
> @@ -801,21 +801,35 @@ static int do_bad(unsigned long far, unsigned long esr, struct pt_regs *regs)
>   	return 1; /* "fault" */
>   }
>   
> +/*
> + * APEI claimed this as a firmware-first notification.
> + * Some processing deferred to task_work before ret_to_user().
> + */
> +static int do_apei_claim_sea(struct pt_regs *regs)
> +{
> +	int ret;
> +
> +	ret = apei_claim_sea(regs);
> +	if (ret)
> +		return ret;
> +
> +	if (!user_mode(regs) && IS_ENABLED(CONFIG_ARCH_HAS_COPY_MC)) {
> +		if (!fixup_exception_me(regs))
> +			return -ENOENT;
> +	}
> +
> +	return ret;
> +}
> +
>   static int do_sea(unsigned long far, unsigned long esr, struct pt_regs *regs)
>   {
>   	const struct fault_info *inf;
>   	unsigned long siaddr;
>   
> -	inf = esr_to_fault_info(esr);
> -
> -	if (user_mode(regs) && apei_claim_sea(regs) == 0) {
> -		/*
> -		 * APEI claimed this as a firmware-first notification.
> -		 * Some processing deferred to task_work before ret_to_user().
> -		 */
> +	if (do_apei_claim_sea(regs) == 0)
>   		return 0;
> -	}
>   
> +	inf = esr_to_fault_info(esr);
>   	if (esr & ESR_ELx_FnV) {
>   		siaddr = 0;
>   	} else {



From linux.amoon at gmail.com  Wed Dec 24 00:04:23 2025
From: linux.amoon at gmail.com (Anand Moon)
Date: Wed, 24 Dec 2025 13:34:23 +0530
Subject: [PATCH v2 1/4] PCI: rockchip: limit RK3399 to 2.5 GT/s to prevent damage
In-Reply-To: <CAEsQvctSY7-RQEQF2TmJU2qKPZOe9TC5g-7Jat0LQKRHYz_6dQ@mail.gmail.com>
References: <cover.1763415705.git.geraldogabriel@gmail.com>
 <eaa9c75ca02a53f8bcc293b8bc73d013e26ec253.1763415706.git.geraldogabriel@gmail.com>
 <CANAwSgQ726J_vnDKEKd94Kq62kx8ToZzUGysz4r3tNAXvfAbGA@mail.gmail.com> <CAEsQvctSY7-RQEQF2TmJU2qKPZOe9TC5g-7Jat0LQKRHYz_6dQ@mail.gmail.com>
Message-ID: <CANAwSgQPQUBi6VVb+hZNraMt71vnRpki+YK_at=Luo4aPVtOPg@mail.gmail.com>

Hi Geraldo,

On Wed, 24 Dec 2025 at 11:08, Geraldo Nascimento
<geraldogabriel at gmail.com> wrote:
>
> On Wed, Dec 24, 2025 at 2:18?AM Anand Moon <linux.amoon at gmail.com> wrote:
> >
> > Hi Geraldo,
> >
> > On Tue, 18 Nov 2025 at 03:17, Geraldo Nascimento
> > <geraldogabriel at gmail.com> wrote:
> > >
> > > Shawn Lin from Rockchip has reiterated that there may be danger in using
> > > their PCIe with 5.0 GT/s speeds. Warn the user if they make a DT change
> > > from the default and drive at 2.5 GT/s only, even if the DT
> > > max-link-speed property is invalid or inexistent.
> > >
> > > This change is corroborated by RK3399 official datasheet [1], which
> > > says maximum link speed for this platform is 2.5 GT/s.
> > >
> > > [1] https://opensource.rock-chips.com/images/d/d7/Rockchip_RK3399_Datasheet_V2.1-20200323.pdf
> > >
> > To accurately determine the operating speed, we can leverage the
> > PCIE_CLIENT_BASIC_STATUS0/1 fields.
> > This provides a dynamic mechanism to resolve the issue.
> >
> > [1] https://github.com/torvalds/linux/blob/master/drivers/pci/controller/pcie-rockchip-ep.c#L533-L595
> >
> > Thanks
> > -Anand
>
> Hi Anand,
>
> not to put you down but I think your approach adds unnecessary complexity.
>
> All I care really is that the Kernel Project isn't blamed in the
> future if someone happens to lose their data.
>
Allow the hardware to negotiate the link speed based on the available
number of lanes.
I don?t anticipate any data loss, since PCIe will automatically
configure the device speed
with link training..

> Thanks,
> Geraldo Nascimento

Thanks
-Anand


From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec 24 00:38:29 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed, 24 Dec 2025 09:38:29 +0100
Subject: [PATCH 1/2] Documentation/process: maintainer-soc: Be more
 explicit about defconfig
In-Reply-To: <20251223162756.GA25011@pendragon.ideasonboard.com>
References: <20251223142726.73417-3-krzysztof.kozlowski@oss.qualcomm.com>
 <20251223150256.GI9817@pendragon.ideasonboard.com>
 <f858ea0e-24d5-4cdd-ab57-dfeebe67ae7b@oss.qualcomm.com>
 <20251223162756.GA25011@pendragon.ideasonboard.com>
Message-ID: <9a62f4c8-e707-4a0d-a374-4b0f4168f47f@oss.qualcomm.com>

On 23/12/2025 17:27, Laurent Pinchart wrote:
> On Tue, Dec 23, 2025 at 04:32:02PM +0100, Krzysztof Kozlowski wrote:
>> On 23/12/2025 16:02, Laurent Pinchart wrote:
>>> On Tue, Dec 23, 2025 at 03:27:27PM +0100, Krzysztof Kozlowski wrote:
>>>> It is already documented but people still send noticeable amount of
>>>> patches ignoring the rule - get_maintainers.pl does not work on
>>>> arm64/configs/defconfig or any other shared ARM defconfig.
>>>>
>>>> Be more explicit, that one must not rely on typical/simple approach
>>>> here for getting To/Cc list.
>>>>
>>>> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
>>>>
>>>> ---
>>>>
>>>> Incorrectly addressed patches for arm64/defconfig are around ~2 per month...
>>>> ---
>>>>  Documentation/process/maintainer-soc.rst | 6 ++++--
>>>>  1 file changed, 4 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/Documentation/process/maintainer-soc.rst b/Documentation/process/maintainer-soc.rst
>>>> index 3ba886f52a51..014c639022b2 100644
>>>> --- a/Documentation/process/maintainer-soc.rst
>>>> +++ b/Documentation/process/maintainer-soc.rst
>>>> @@ -57,8 +57,10 @@ Submitting Patches for Given SoC
>>>>  
>>>>  All typical platform related patches should be sent via SoC submaintainers
>>>>  (platform-specific maintainers).  This includes also changes to per-platform or
>>>> -shared defconfigs (scripts/get_maintainer.pl might not provide correct
>>>> -addresses in such case).
>>>> +shared defconfigs. Note that scripts/get_maintainer.pl might not provide
>>>> +correct addresses for the shared defconfig, so ignore its output and manually
>>>> +create CC-list based on MAINTAINERS file or use something like
>>>> +``scripts/get_maintainer.pl -f drivers/soc/FOO/``).
>>>
>>> I fear this will be another piece of documentation that people won't
>>> read. It would be more effective to implement custom logic in
>>> get_maintainer.pl (or at least output an informative message).
>>
>> Part of the logic is already there, but I will not grow that - I don't
>> want to touch Perl code. It's pretty obvious the tool should be do it,
>> so feel free to fix it.
> 
> Even if I knew perl, I'd have no time :-)

Same here. I see little incentive for me to spend significant amount of
time on this - considering I barely know Perl and how much I like this
language - to solve not my problem. The best I could do is to clarify
the docs. I agree however that this will be one more ignored doc, so I
don't mind skipping the patch.

Patch 2/2 is independent though, so please still consider it.

Best regards,
Krzysztof


From leon at kernel.org  Wed Dec 24 00:51:45 2025
From: leon at kernel.org (Leon Romanovsky)
Date: Wed, 24 Dec 2025 10:51:45 +0200
Subject: [PATCH 5/6] dma-mapping: Allow batched DMA sync operations if
 supported by the arch
In-Reply-To: <CAGsJ_4x9YOT2kG0iWz_5NzRVt2iDN9YeUTknZ2MKg7SwmOGOqg@mail.gmail.com>
References: <20251221115523.GI13030@unreal>
 <20251221192458.1320-1-21cnbao@gmail.com>
 <20251222084921.GA13529@unreal>
 <CAGsJ_4yuvHNqHDi8eN-8UoY2McoXUeCMmbjFAr=jSdv8GpGKeg@mail.gmail.com>
 <20251223141424.GB11869@unreal>
 <CAGsJ_4x9YOT2kG0iWz_5NzRVt2iDN9YeUTknZ2MKg7SwmOGOqg@mail.gmail.com>
Message-ID: <20251224085145.GF11869@unreal>

On Wed, Dec 24, 2025 at 02:29:13PM +1300, Barry Song wrote:
> On Wed, Dec 24, 2025 at 3:14?AM Leon Romanovsky <leon at kernel.org> wrote:
> >
> > On Tue, Dec 23, 2025 at 01:02:55PM +1300, Barry Song wrote:
> > > On Mon, Dec 22, 2025 at 9:49?PM Leon Romanovsky <leon at kernel.org> wrote:
> > > >
> > > > On Mon, Dec 22, 2025 at 03:24:58AM +0800, Barry Song wrote:
> > > > > On Sun, Dec 21, 2025 at 7:55?PM Leon Romanovsky <leon at kernel.org> wrote:
> > > > > [...]
> > > > > > > +
> > > > > >
> > > > > > I'm wondering why you don't implement this batch?sync support inside the
> > > > > > arch_sync_dma_*() functions. Doing so would minimize changes to the generic
> > > > > > kernel/dma/* code and reduce the amount of #ifdef?based spaghetti.
> > > > > >
> > > > >
> > > > > There are two cases: mapping an sg list and mapping a single
> > > > > buffer. The former can be batched with
> > > > > arch_sync_dma_*_batch_add() and flushed via
> > > > > arch_sync_dma_batch_flush(), while the latter requires all work to
> > > > > be done inside arch_sync_dma_*(). Therefore,
> > > > > arch_sync_dma_*() cannot always batch and flush.
> > > >
> > > > Probably in all cases you can call the _batch_ variant, followed by _flush_,
> > > > even when handling a single page. This keeps the code consistent across all
> > > > paths. On platforms that do not support _batch_, the _flush_ operation will be
> > > > a NOP anyway.
> > >
> > > We have a lot of code outside kernel/dma that also calls
> > > arch_sync_dma_for_* such as arch/arm, arch/mips, drivers/xen,
> > > I guess we don?t want to modify so many things?
> >
> > Aren't they using internal, arch specific, arch_sync_dma_for_* implementations?
> 
> for arch/arm, arch/mips, they are arch-specific implementations.
> xen is an exception:

Right, and this is the only location outside of kernel/dma where you need to
invoke arch_sync_dma_flush().

> 
> static void xen_swiotlb_unmap_phys(struct device *hwdev, dma_addr_t dev_addr,
>                 size_t size, enum dma_data_direction dir, unsigned long attrs)
> {
>         phys_addr_t paddr = xen_dma_to_phys(hwdev, dev_addr);
>         struct io_tlb_pool *pool;
> 
>         BUG_ON(dir == DMA_NONE);
> 
>         if (!dev_is_dma_coherent(hwdev) && !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) {
>                 if (pfn_valid(PFN_DOWN(dma_to_phys(hwdev, dev_addr))))
>                         arch_sync_dma_for_cpu(paddr, size, dir);
>                 else
>                         xen_dma_sync_for_cpu(hwdev, dev_addr, size, dir);
>         }
> 
>         /* NOTE: We use dev_addr here, not paddr! */
>         pool = xen_swiotlb_find_pool(hwdev, dev_addr);
>         if (pool)
>                 __swiotlb_tbl_unmap_single(hwdev, paddr, size, dir,
>                                            attrs, pool);
> }
> 
> >
> > >
> > > for kernel/dma, we have two "single" callers only:
> > > kernel/dma/direct.h, kernel/dma/swiotlb.c.  and they looks quite
> > > straightforward:
> > >
> > > static inline void dma_direct_sync_single_for_device(struct device *dev,
> > >                 dma_addr_t addr, size_t size, enum dma_data_direction dir)
> > > {
> > >         phys_addr_t paddr = dma_to_phys(dev, addr);
> > >
> > >         swiotlb_sync_single_for_device(dev, paddr, size, dir);
> > >
> > >         if (!dev_is_dma_coherent(dev))
> > >                 arch_sync_dma_for_device(paddr, size, dir);
> > > }
> > >
> > > I guess moving to arch_sync_dma_for_device_batch + flush
> > > doesn?t really look much better, does it?
> > >
> > > >
> > > > I would also rename arch_sync_dma_batch_flush() to arch_sync_dma_flush().
> > >
> > > Sure.
> > >
> > > >
> > > > You can also minimize changes in dma_direct_map_phys() too, by extending
> > > > it's signature to provide if flush is needed or not.
> > >
> > > Yes. I have
> > >
> > > static inline dma_addr_t __dma_direct_map_phys(struct device *dev,
> > >                 phys_addr_t phys, size_t size, enum dma_data_direction dir,
> > >                 unsigned long attrs, bool flush)
> >
> > My suggestion is to use it directly, without wrappers.
> >
> > >
> > > and two wrappers:
> > > static inline dma_addr_t dma_direct_map_phys(struct device *dev,
> > >                 phys_addr_t phys, size_t size, enum dma_data_direction dir,
> > >                 unsigned long attrs)
> > > {
> > >         return __dma_direct_map_phys(dev, phys, size, dir, attrs, true);
> > > }
> > >
> > > static inline dma_addr_t dma_direct_map_phys_batch_add(struct device *dev,
> > >                 phys_addr_t phys, size_t size, enum dma_data_direction dir,
> > >                 unsigned long attrs)
> > > {
> > >         return __dma_direct_map_phys(dev, phys, size, dir, attrs, false);
> > > }
> > >
> > > If you prefer exposing "flush" directly in dma_direct_map_phys()
> > > and updating its callers with flush=true, I think that?s fine.
> >
> > Yes
> >
> 
> OK. Could you take a look at [1] and see if any further
> improvements are needed before I send v2?

Everything looks ok, except these renames:
-			arch_sync_dma_for_cpu(paddr, sg->length, dir);
+			arch_sync_dma_for_cpu_batch_add(paddr, sg->length, dir);

Thanks

> 
> [1] https://lore.kernel.org/lkml/20251223023648.31614-1-21cnbao at gmail.com/
> 
> Thanks
> Barry
> 


From jie.gan at oss.qualcomm.com  Wed Dec 24 01:06:10 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Wed, 24 Dec 2025 17:06:10 +0800
Subject: [PATCH v9 0/8] coresight: ctcu: Enable byte-cntr function for TMC
 ETR
Message-ID: <20251224-enable-byte-cntr-for-ctcu-v9-0-886c4496fed4@oss.qualcomm.com>

The byte-cntr function provided by the CTCU device is used to count the
trace data entering the ETR. An interrupt is triggered if the data size
exceeds the threshold set in the BYTECNTRVAL register. The interrupt
handler counts the number of triggered interruptions.

Based on this concept, the irq_cnt can be used to determine whether
the etr_buf is full. The ETR device will be disabled when the active
etr_buf is nearly full or a timeout occurs. The nearly full buffer will
be switched to background after synced. A new buffer will be picked from
the etr_buf_list, then restart the ETR device.

The byte-cntr reading functions can access data from the synced and
deactivated buffer, transferring trace data from the etr_buf to userspace
without stopping the ETR device.

The byte-cntr read operation has integrated with the file node tmc_etr,
for example:
/dev/tmc_etr0
/dev/tmc_etr1

There are two scenarios for the tmc_etr file node with byte-cntr function:
1. BYTECNTRVAL register is configured and byte-cntr is enabled -> byte-cntr read
2. BYTECNTRVAL register is reset or byte-cntr is disabled -> original behavior

Shell commands to enable byte-cntr reading for etr0:
echo 0x10000 > /sys/bus/coresight/devices/ctcu0/irq_threshold0
echo 1 > /sys/bus/coresight/devices/tmc_etr0/enable_sink
echo 1 > /sys/bus/coresight/devices/etm0/enable_source
cat /dev/tmc_etr0

Reset the BYTECNTR register for etr0:
echo 0 > /sys/bus/coresight/devices/ctcu0/irq_threshold0

Changes in v9:
1. Drop the patch: add a new API to retrieve the helper device
2. Add a new patch to refactor the tmc_etr_get_catu_device function,
   making it generic to support all types of helper devices associated with ETR.
3. Optimizing the code for creating irq_threshold sysfs node.
Link to v8: https://lore.kernel.org/r/20251211-enable-byte-cntr-for-ctcu-v8-0-3e12ff313191 at oss.qualcomm.com

Changes in V8:
1. Optimizing the patch 1 and patch 2 according to Suzuki's comments.
2. Combine the patch 3 and patch 4 together.
3. Rename the interrupt-name to prevent confusion, for example:etr0->etrirq0.
Link to V7 - https://lore.kernel.org/all/20251013-enable-byte-cntr-for-ctcu-v7-0-e1e8f41e15dd at oss.qualcomm.com/

Changes in V7:
1. rebased on tag next-20251010
2. updated info for sysfs node document
Link to V6 - https://lore.kernel.org/all/20250908-enable-byte-cntr-for-tmc-v6-0-1db9e621441a at oss.qualcomm.com/

Changes in V6:
1. rebased on next-20250905.
2. fixed the issue that the dtsi file has re-named from sa8775p.dtsi to
   lemans.dtsi.
3. fixed some minor issues about comments.
Link to V5 - https://lore.kernel.org/all/20250812083731.549-1-jie.gan at oss.qualcomm.com/

Changes in V5:
1. Add Mike's reviewed-by tag for patchset 1,2,5.
2. Remove the function pointer added to helper_ops according to Mike's
   comment, it also results the patchset has been removed.
3. Optimizing the paired create/clean functions for etr_buf_list.
4. Remove the unneeded parameter "reading" from the etr_buf_node.
Link to V4 - https://lore.kernel.org/all/20250725100806.1157-1-jie.gan at oss.qualcomm.com/

Changes in V4:
1. Rename the function to coresight_get_in_port_dest regarding to Mike's
comment (patch 1/10).
2. Add lock to protect the connections regarding to Mike's comment
(patch 2/10).
3. Move all byte-cntr functions to coresight-ctcu-byte-cntr file.
4. Add tmc_read_ops to wrap all read operations for TMC device.
5. Add a function in helper_ops to check whether the byte-cntr is
enabkled.
6. Call byte-cntr's read_ops if byte-cntr is enabled when reading data
from the sysfs node.
Link to V3 resend - https://lore.kernel.org/all/20250714063109.591-1-jie.gan at oss.qualcomm.com/

Changes in V3 resend:
1. rebased on next-20250711.
Link to V3 - https://lore.kernel.org/all/20250624060438.7469-1-jie.gan at oss.qualcomm.com/

Changes in V3:
1. The previous solution has been deprecated.
2. Add a etr_buf_list to manage allcated etr buffers.
3. Add a logic to switch buffer for ETR.
4. Add read functions to read trace data from synced etr buffer.
Link to V2 - https://lore.kernel.org/all/20250410013330.3609482-1-jie.gan at oss.qualcomm.com/

Changes in V2:
1. Removed the independent file node /dev/byte_cntr.
2. Integrated the byte-cntr's file operations with current ETR file
   node.
3. Optimized the driver code of the CTCU that associated with byte-cntr.
4. Add kernel document for the export API tmc_etr_get_rwp_offset.
5. Optimized the way to read the rwp_offset according to Mike's
   suggestion.
6. Removed the dependency of the dts patch.
Link to V1 - https://lore.kernel.org/all/20250310090407.2069489-1-quic_jiegan at quicinc.com/

Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
Jie Gan (8):
      coresight: core: Refactoring ctcu_get_active_port and make it generic
      coresight: tmc: add create/clean functions for etr_buf_list
      coresight: tmc: Introduce sysfs_read_ops to wrap sysfs read operations
      coresight: etr: refactor the tmc_etr_get_catu_device function
      dt-bindings: arm: add an interrupt property for Coresight CTCU
      coresight: ctcu: enable byte-cntr for TMC ETR devices
      coresight: tmc: integrate byte-cntr's read_ops with sysfs file_ops
      arm64: dts: qcom: lemans: add interrupts to CTCU device

 .../ABI/testing/sysfs-bus-coresight-devices-ctcu   |   8 +
 .../bindings/arm/qcom,coresight-ctcu.yaml          |  10 +
 arch/arm64/boot/dts/qcom/lemans.dtsi               |   3 +
 drivers/hwtracing/coresight/Makefile               |   2 +-
 drivers/hwtracing/coresight/coresight-catu.c       |   3 +-
 drivers/hwtracing/coresight/coresight-core.c       |  24 ++
 .../hwtracing/coresight/coresight-ctcu-byte-cntr.c | 366 +++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-ctcu-core.c  | 122 +++++--
 drivers/hwtracing/coresight/coresight-ctcu.h       |  77 ++++-
 drivers/hwtracing/coresight/coresight-priv.h       |   2 +
 drivers/hwtracing/coresight/coresight-tmc-core.c   | 104 ++++--
 drivers/hwtracing/coresight/coresight-tmc-etr.c    | 144 +++++++-
 drivers/hwtracing/coresight/coresight-tmc.h        |  40 ++-
 13 files changed, 833 insertions(+), 72 deletions(-)
---
base-commit: 47b7b5e32bb7264b51b89186043e1ada4090b558
change-id: 20251203-enable-byte-cntr-for-ctcu-5a4b88f2feb9

Best regards,
-- 
Jie Gan <jie.gan at oss.qualcomm.com>



From jie.gan at oss.qualcomm.com  Wed Dec 24 01:06:11 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Wed, 24 Dec 2025 17:06:11 +0800
Subject: [PATCH v9 1/8] coresight: core: Refactoring ctcu_get_active_port
 and make it generic
In-Reply-To: <20251224-enable-byte-cntr-for-ctcu-v9-0-886c4496fed4@oss.qualcomm.com>
References: <20251224-enable-byte-cntr-for-ctcu-v9-0-886c4496fed4@oss.qualcomm.com>
Message-ID: <20251224-enable-byte-cntr-for-ctcu-v9-1-886c4496fed4@oss.qualcomm.com>

Remove ctcu_get_active_port from CTCU module and add it to the core
framework.

The port number is crucial for the CTCU device to identify which ETR
it serves. With the port number we can correctly get required parameters
of the CTCU device in TMC module.

Reviewed-by: Mike Leach <mike.leach at linaro.org>
Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 drivers/hwtracing/coresight/coresight-core.c      | 24 +++++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-ctcu-core.c | 19 +-----------------
 drivers/hwtracing/coresight/coresight-priv.h      |  2 ++
 3 files changed, 27 insertions(+), 18 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index c660cf8adb1c..0e8448784c62 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -585,6 +585,30 @@ struct coresight_device *coresight_get_sink(struct coresight_path *path)
 }
 EXPORT_SYMBOL_GPL(coresight_get_sink);
 
+/**
+ * coresight_get_in_port: Find the input port number at @csdev where a @remote
+ * device is connected to.
+ *
+ * @csdev: csdev of the device.
+ * @remote: csdev of the remote device which is connected to @csdev.
+ *
+ * Return: port number upon success or -EINVAL for fail.
+ */
+int coresight_get_in_port(struct coresight_device *csdev,
+			  struct coresight_device *remote)
+{
+	struct coresight_platform_data *pdata = remote->pdata;
+	int i;
+
+	for (i = 0; i < pdata->nr_inconns; ++i) {
+		if (pdata->in_conns[i]->src_dev == csdev)
+			return pdata->in_conns[i]->dest_port;
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(coresight_get_in_port);
+
 u32 coresight_get_sink_id(struct coresight_device *csdev)
 {
 	if (!csdev->ea)
diff --git a/drivers/hwtracing/coresight/coresight-ctcu-core.c b/drivers/hwtracing/coresight/coresight-ctcu-core.c
index abed15eb72b4..78be783b3cb2 100644
--- a/drivers/hwtracing/coresight/coresight-ctcu-core.c
+++ b/drivers/hwtracing/coresight/coresight-ctcu-core.c
@@ -118,23 +118,6 @@ static int __ctcu_set_etr_traceid(struct coresight_device *csdev, u8 traceid, in
 	return 0;
 }
 
-/*
- * Searching the sink device from helper's view in case there are multiple helper devices
- * connected to the sink device.
- */
-static int ctcu_get_active_port(struct coresight_device *sink, struct coresight_device *helper)
-{
-	struct coresight_platform_data *pdata = helper->pdata;
-	int i;
-
-	for (i = 0; i < pdata->nr_inconns; ++i) {
-		if (pdata->in_conns[i]->src_dev == sink)
-			return pdata->in_conns[i]->dest_port;
-	}
-
-	return -EINVAL;
-}
-
 static int ctcu_set_etr_traceid(struct coresight_device *csdev, struct coresight_path *path,
 				bool enable)
 {
@@ -147,7 +130,7 @@ static int ctcu_set_etr_traceid(struct coresight_device *csdev, struct coresight
 		return -EINVAL;
 	}
 
-	port_num = ctcu_get_active_port(sink, csdev);
+	port_num = coresight_get_in_port(sink, csdev);
 	if (port_num < 0)
 		return -EINVAL;
 
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
index fd896ac07942..cbf80b83e5ce 100644
--- a/drivers/hwtracing/coresight/coresight-priv.h
+++ b/drivers/hwtracing/coresight/coresight-priv.h
@@ -155,6 +155,8 @@ void coresight_remove_links(struct coresight_device *orig,
 u32 coresight_get_sink_id(struct coresight_device *csdev);
 void coresight_path_assign_trace_id(struct coresight_path *path,
 				   enum cs_mode mode);
+int coresight_get_in_port(struct coresight_device *csdev,
+			  struct coresight_device *remote);
 
 #if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM3X)
 int etm_readl_cp14(u32 off, unsigned int *val);

-- 
2.34.1



From jie.gan at oss.qualcomm.com  Wed Dec 24 01:06:12 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Wed, 24 Dec 2025 17:06:12 +0800
Subject: [PATCH v9 2/8] coresight: tmc: add create/clean functions for
 etr_buf_list
In-Reply-To: <20251224-enable-byte-cntr-for-ctcu-v9-0-886c4496fed4@oss.qualcomm.com>
References: <20251224-enable-byte-cntr-for-ctcu-v9-0-886c4496fed4@oss.qualcomm.com>
Message-ID: <20251224-enable-byte-cntr-for-ctcu-v9-2-886c4496fed4@oss.qualcomm.com>

Introduce functions for creating and inserting or removing the
etr_buf_node to/from the etr_buf_list.

The byte-cntr functionality requires two etr_buf to receive trace data.
The active etr_buf collects the trace data from source device, while the
byte-cntr reading function accesses the deactivated etr_buf after is
has been filled and synced, transferring data to the userspace.

Reviewed-by: Mike Leach <mike.leach at linaro.org>
Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 drivers/hwtracing/coresight/coresight-tmc-core.c |  1 +
 drivers/hwtracing/coresight/coresight-tmc-etr.c  | 94 ++++++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-tmc.h      | 19 +++++
 3 files changed, 114 insertions(+)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c
index 36599c431be6..1ea255ffa67c 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-core.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-core.c
@@ -840,6 +840,7 @@ static int __tmc_probe(struct device *dev, struct resource *res)
 		idr_init(&drvdata->idr);
 		mutex_init(&drvdata->idr_mutex);
 		dev_list = &etr_devs;
+		INIT_LIST_HEAD(&drvdata->etr_buf_list);
 		break;
 	case TMC_CONFIG_TYPE_ETF:
 		desc.groups = coresight_etf_groups;
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index e0d83ee01b77..2b6ca1f8bed2 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -1919,6 +1919,100 @@ const struct coresight_ops tmc_etr_cs_ops = {
 	.panic_ops	= &tmc_etr_sync_ops,
 };
 
+/**
+ * tmc_clean_etr_buf_list - clean the etr_buf_list.
+ * @drvdata:	driver data of the TMC device.
+ *
+ * Remove the allocated node from the list and free the extra buffer.
+ */
+void tmc_clean_etr_buf_list(struct tmc_drvdata *drvdata)
+{
+	struct etr_buf_node *nd, *next;
+
+	list_for_each_entry_safe(nd, next, &drvdata->etr_buf_list, node) {
+		if (nd->sysfs_buf == drvdata->sysfs_buf) {
+			if (coresight_get_mode(drvdata->csdev) == CS_MODE_DISABLED) {
+				drvdata->sysfs_buf = NULL;
+				tmc_free_etr_buf(nd->sysfs_buf);
+				nd->sysfs_buf = NULL;
+			}
+			list_del(&nd->node);
+			kfree(nd);
+		} else {
+			/* Free allocated buffers which are not utilized by ETR */
+			list_del(&nd->node);
+			tmc_free_etr_buf(nd->sysfs_buf);
+			nd->sysfs_buf = NULL;
+			kfree(nd);
+		}
+	}
+}
+EXPORT_SYMBOL_GPL(tmc_clean_etr_buf_list);
+
+/**
+ * tmc_create_etr_buf_list - create a list to manage the etr_buf_node.
+ * @drvdata:	driver data of the TMC device.
+ * @num_nodes:	number of nodes want to create with the list.
+ *
+ * Return 0 upon success and return the error number if fail.
+ */
+int tmc_create_etr_buf_list(struct tmc_drvdata *drvdata, int num_nodes)
+{
+	struct etr_buf_node *new_node;
+	struct etr_buf *sysfs_buf;
+	int i = 0, ret = 0;
+
+	/* We dont need a list if there is only one node */
+	if (num_nodes < 2)
+		return -EINVAL;
+
+	/* We expect that sysfs_buf in drvdata has already been allocated. */
+	if (drvdata->sysfs_buf) {
+		/* Directly insert the allocated sysfs_buf into the list first */
+		new_node = kzalloc(sizeof(struct etr_buf_node), GFP_KERNEL);
+		if (IS_ERR(new_node))
+			return PTR_ERR(new_node);
+
+		new_node->sysfs_buf = drvdata->sysfs_buf;
+		new_node->is_free = false;
+		list_add(&new_node->node, &drvdata->etr_buf_list);
+		i++;
+	}
+
+	while (i < num_nodes) {
+		new_node = kzalloc(sizeof(struct etr_buf_node), GFP_KERNEL);
+		if (IS_ERR(new_node)) {
+			ret = PTR_ERR(new_node);
+			break;
+		}
+
+		sysfs_buf = tmc_alloc_etr_buf(drvdata, drvdata->size, 0, cpu_to_node(0), NULL);
+		if (IS_ERR(sysfs_buf)) {
+			kfree(new_node);
+			ret = PTR_ERR(new_node);
+			break;
+		}
+
+		/* We dont have a available sysfs_buf in drvdata, setup one */
+		if (!drvdata->sysfs_buf) {
+			drvdata->sysfs_buf = sysfs_buf;
+			new_node->is_free = false;
+		} else
+			new_node->is_free = true;
+
+		new_node->sysfs_buf = sysfs_buf;
+		list_add(&new_node->node, &drvdata->etr_buf_list);
+		i++;
+	}
+
+	/* Clean the list if there is an error */
+	if (ret)
+		tmc_clean_etr_buf_list(drvdata);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(tmc_create_etr_buf_list);
+
 int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
 {
 	int ret = 0;
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 95473d131032..9b3c4e6f0a5e 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -208,6 +208,19 @@ struct tmc_resrv_buf {
 	s64		len;
 };
 
+/**
+ * @sysfs_buf:	Allocated sysfs_buf.
+ * @is_free:	Indicates whether the buffer is free to choose.
+ * @pos:	Position of the buffer.
+ * @node:	Node in etr_buf_list.
+ */
+struct etr_buf_node {
+	struct etr_buf		*sysfs_buf;
+	bool			is_free;
+	loff_t			pos;
+	struct list_head	node;
+};
+
 /**
  * struct tmc_drvdata - specifics associated to an TMC component
  * @atclk:	optional clock for the core parts of the TMC.
@@ -243,6 +256,8 @@ struct tmc_resrv_buf {
  *		(after crash) by default.
  * @crash_mdata: Reserved memory for storing tmc crash metadata.
  *		 Used by ETR/ETF.
+ * @etr_buf_list: List that is used to manage allocated etr_buf.
+ * @reading_node: Available buffer_node for byte-cntr reading.
  */
 struct tmc_drvdata {
 	struct clk		*atclk;
@@ -273,6 +288,8 @@ struct tmc_drvdata {
 	struct etr_buf		*perf_buf;
 	struct tmc_resrv_buf	resrv_buf;
 	struct tmc_resrv_buf	crash_mdata;
+	struct list_head        etr_buf_list;
+	struct etr_buf_node     *reading_node;
 };
 
 struct etr_buf_operations {
@@ -445,5 +462,7 @@ struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev,
 				   enum cs_mode mode,
 				   struct coresight_path *path);
 extern const struct attribute_group coresight_etr_group;
+void tmc_clean_etr_buf_list(struct tmc_drvdata *drvdata);
+int tmc_create_etr_buf_list(struct tmc_drvdata *drvdata, int num_nodes);
 
 #endif

-- 
2.34.1



From jie.gan at oss.qualcomm.com  Wed Dec 24 01:06:13 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Wed, 24 Dec 2025 17:06:13 +0800
Subject: [PATCH v9 3/8] coresight: tmc: Introduce sysfs_read_ops to wrap
 sysfs read operations
In-Reply-To: <20251224-enable-byte-cntr-for-ctcu-v9-0-886c4496fed4@oss.qualcomm.com>
References: <20251224-enable-byte-cntr-for-ctcu-v9-0-886c4496fed4@oss.qualcomm.com>
Message-ID: <20251224-enable-byte-cntr-for-ctcu-v9-3-886c4496fed4@oss.qualcomm.com>

Introduce sysfs_read_ops as a wrapper, wrap sysfs read operations, for reading
trace data from the TMC buffer.

Reviewed-by: Mike Leach <mike.leach at linaro.org>
Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 drivers/hwtracing/coresight/coresight-tmc-core.c | 50 +++++++++++-------------
 drivers/hwtracing/coresight/coresight-tmc.h      | 17 ++++++++
 2 files changed, 40 insertions(+), 27 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c
index 1ea255ffa67c..8b0397a77e57 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-core.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-core.c
@@ -232,17 +232,10 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata)
 {
 	int ret = 0;
 
-	switch (drvdata->config_type) {
-	case TMC_CONFIG_TYPE_ETB:
-	case TMC_CONFIG_TYPE_ETF:
-		ret = tmc_read_prepare_etb(drvdata);
-		break;
-	case TMC_CONFIG_TYPE_ETR:
-		ret = tmc_read_prepare_etr(drvdata);
-		break;
-	default:
+	if (drvdata->sysfs_ops)
+		ret = drvdata->sysfs_ops->read_prepare(drvdata);
+	else
 		ret = -EINVAL;
-	}
 
 	if (!ret)
 		dev_dbg(&drvdata->csdev->dev, "TMC read start\n");
@@ -254,17 +247,10 @@ static int tmc_read_unprepare(struct tmc_drvdata *drvdata)
 {
 	int ret = 0;
 
-	switch (drvdata->config_type) {
-	case TMC_CONFIG_TYPE_ETB:
-	case TMC_CONFIG_TYPE_ETF:
-		ret = tmc_read_unprepare_etb(drvdata);
-		break;
-	case TMC_CONFIG_TYPE_ETR:
-		ret = tmc_read_unprepare_etr(drvdata);
-		break;
-	default:
+	if (drvdata->sysfs_ops)
+		ret = drvdata->sysfs_ops->read_unprepare(drvdata);
+	else
 		ret = -EINVAL;
-	}
 
 	if (!ret)
 		dev_dbg(&drvdata->csdev->dev, "TMC read end\n");
@@ -291,13 +277,8 @@ static int tmc_open(struct inode *inode, struct file *file)
 static ssize_t tmc_get_sysfs_trace(struct tmc_drvdata *drvdata, loff_t pos, size_t len,
 				   char **bufpp)
 {
-	switch (drvdata->config_type) {
-	case TMC_CONFIG_TYPE_ETB:
-	case TMC_CONFIG_TYPE_ETF:
-		return tmc_etb_get_sysfs_trace(drvdata, pos, len, bufpp);
-	case TMC_CONFIG_TYPE_ETR:
-		return tmc_etr_get_sysfs_trace(drvdata, pos, len, bufpp);
-	}
+	if (drvdata->sysfs_ops)
+		return drvdata->sysfs_ops->get_trace_data(drvdata, pos, len, bufpp);
 
 	return -EINVAL;
 }
@@ -769,6 +750,18 @@ static void register_crash_dev_interface(struct tmc_drvdata *drvdata,
 			"Valid crash tracedata found\n");
 }
 
+static const struct sysfs_read_ops tmc_etb_sysfs_read_ops = {
+	.read_prepare	= tmc_read_prepare_etb,
+	.read_unprepare	= tmc_read_unprepare_etb,
+	.get_trace_data	= tmc_etb_get_sysfs_trace,
+};
+
+static const struct sysfs_read_ops tmc_etr_sysfs_read_ops = {
+	.read_prepare	= tmc_read_prepare_etr,
+	.read_unprepare	= tmc_read_unprepare_etr,
+	.get_trace_data	= tmc_etr_get_sysfs_trace,
+};
+
 static int __tmc_probe(struct device *dev, struct resource *res)
 {
 	int ret = 0;
@@ -828,6 +821,7 @@ static int __tmc_probe(struct device *dev, struct resource *res)
 		desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
 		desc.ops = &tmc_etb_cs_ops;
 		dev_list = &etb_devs;
+		drvdata->sysfs_ops = &tmc_etb_sysfs_read_ops;
 		break;
 	case TMC_CONFIG_TYPE_ETR:
 		desc.groups = coresight_etr_groups;
@@ -841,6 +835,7 @@ static int __tmc_probe(struct device *dev, struct resource *res)
 		mutex_init(&drvdata->idr_mutex);
 		dev_list = &etr_devs;
 		INIT_LIST_HEAD(&drvdata->etr_buf_list);
+		drvdata->sysfs_ops = &tmc_etr_sysfs_read_ops;
 		break;
 	case TMC_CONFIG_TYPE_ETF:
 		desc.groups = coresight_etf_groups;
@@ -849,6 +844,7 @@ static int __tmc_probe(struct device *dev, struct resource *res)
 		desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO;
 		desc.ops = &tmc_etf_cs_ops;
 		dev_list = &etf_devs;
+		drvdata->sysfs_ops = &tmc_etb_sysfs_read_ops;
 		break;
 	default:
 		pr_err("%s: Unsupported TMC config\n", desc.name);
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 9b3c4e6f0a5e..c9a82ff6cd00 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -221,6 +221,8 @@ struct etr_buf_node {
 	struct list_head	node;
 };
 
+struct sysfs_read_ops;
+
 /**
  * struct tmc_drvdata - specifics associated to an TMC component
  * @atclk:	optional clock for the core parts of the TMC.
@@ -258,6 +260,7 @@ struct etr_buf_node {
  *		 Used by ETR/ETF.
  * @etr_buf_list: List that is used to manage allocated etr_buf.
  * @reading_node: Available buffer_node for byte-cntr reading.
+ * @sysfs_ops:	Read operations for sysfs mode.
  */
 struct tmc_drvdata {
 	struct clk		*atclk;
@@ -290,6 +293,20 @@ struct tmc_drvdata {
 	struct tmc_resrv_buf	crash_mdata;
 	struct list_head        etr_buf_list;
 	struct etr_buf_node     *reading_node;
+	const struct sysfs_read_ops	*sysfs_ops;
+};
+
+/**
+ * struct sysfs_read_ops - read operations for TMC and its helper devices
+ * @read_prepare:	prepare operation.
+ * @read_unprepare:	unprepare operation.
+ * @get_trace_data:	read operation.
+ */
+struct sysfs_read_ops {
+	int (*read_prepare)(struct tmc_drvdata *drvdata);
+	int (*read_unprepare)(struct tmc_drvdata *drvdata);
+	ssize_t (*get_trace_data)(struct tmc_drvdata *drvdata, loff_t pos,
+				  size_t len, char **bufpp);
 };
 
 struct etr_buf_operations {

-- 
2.34.1



From jie.gan at oss.qualcomm.com  Wed Dec 24 01:06:14 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Wed, 24 Dec 2025 17:06:14 +0800
Subject: [PATCH v9 4/8] coresight: etr: refactor the
 tmc_etr_get_catu_device function
In-Reply-To: <20251224-enable-byte-cntr-for-ctcu-v9-0-886c4496fed4@oss.qualcomm.com>
References: <20251224-enable-byte-cntr-for-ctcu-v9-0-886c4496fed4@oss.qualcomm.com>
Message-ID: <20251224-enable-byte-cntr-for-ctcu-v9-4-886c4496fed4@oss.qualcomm.com>

Refactor tmc_etr_get_catu_device to retrieve the helper device connected
to the TMC ETR based on helper_subtype.

Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 drivers/hwtracing/coresight/coresight-catu.c    |  3 ++-
 drivers/hwtracing/coresight/coresight-tmc-etr.c | 32 ++++++++++++++++---------
 drivers/hwtracing/coresight/coresight-tmc.h     |  3 ++-
 3 files changed, 25 insertions(+), 13 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-catu.c b/drivers/hwtracing/coresight/coresight-catu.c
index 69b36bae97ab..d3972619cc96 100644
--- a/drivers/hwtracing/coresight/coresight-catu.c
+++ b/drivers/hwtracing/coresight/coresight-catu.c
@@ -334,7 +334,8 @@ static int catu_alloc_etr_buf(struct tmc_drvdata *tmc_drvdata,
 	struct tmc_sg_table *catu_table;
 	struct catu_etr_buf *catu_buf;
 
-	csdev = tmc_etr_get_catu_device(tmc_drvdata);
+	csdev = tmc_etr_get_helper_device(tmc_drvdata,
+			CORESIGHT_DEV_SUBTYPE_HELPER_CATU);
 	if (!csdev)
 		return -ENODEV;
 	catu_buf = kzalloc(sizeof(*catu_buf), GFP_KERNEL);
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 2b6ca1f8bed2..18981b6cc172 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -844,28 +844,37 @@ static const struct etr_buf_operations etr_sg_buf_ops = {
 };
 
 /*
- * TMC ETR could be connected to a CATU device, which can provide address
- * translation service. This is represented by the Output port of the TMC
- * (ETR) connected to the input port of the CATU.
+ * TMC ETR could be connected to the helper device, which can provide address
+ * translation service(CATU) or data filter function(CTCU). This is represented
+ * by the Output port of the TMC (ETR) connected to the input port of the helper.
  *
- * Returns	: coresight_device ptr for the CATU device if a CATU is found.
+ * @drvdata	: drvdata of the TMC device
+ * @subtype	: helper_subtype of the helper device
+ *
+ * Returns	: coresight_device ptr for the helper device if a helper is found.
  *		: NULL otherwise.
  */
 struct coresight_device *
-tmc_etr_get_catu_device(struct tmc_drvdata *drvdata)
+tmc_etr_get_helper_device(struct tmc_drvdata *drvdata,
+			  enum coresight_dev_subtype_helper subtype)
 {
 	struct coresight_device *etr = drvdata->csdev;
-	union coresight_dev_subtype catu_subtype = {
-		.helper_subtype = CORESIGHT_DEV_SUBTYPE_HELPER_CATU
+	union coresight_dev_subtype helper_subtype = {
+		.helper_subtype = subtype
 	};
 
-	if (!IS_ENABLED(CONFIG_CORESIGHT_CATU))
+
+	if (subtype == CORESIGHT_DEV_SUBTYPE_HELPER_CATU &&
+	    !IS_ENABLED(CONFIG_CORESIGHT_CATU))
+		return NULL;
+	else if (subtype == CORESIGHT_DEV_SUBTYPE_HELPER_CTCU &&
+		 !IS_ENABLED(CONFIG_CORESIGHT_CTCU))
 		return NULL;
 
 	return coresight_find_output_type(etr->pdata, CORESIGHT_DEV_TYPE_HELPER,
-					  catu_subtype);
+					  helper_subtype);
 }
-EXPORT_SYMBOL_GPL(tmc_etr_get_catu_device);
+EXPORT_SYMBOL_GPL(tmc_etr_get_helper_device);
 
 static const struct etr_buf_operations *etr_buf_ops[] = {
 	[ETR_MODE_FLAT] = &etr_flat_buf_ops,
@@ -913,7 +922,8 @@ static void get_etr_buf_hw(struct device *dev, struct etr_buf_hw *buf_hw)
 
 	buf_hw->has_iommu = iommu_get_domain_for_dev(dev->parent);
 	buf_hw->has_etr_sg = tmc_etr_has_cap(drvdata, TMC_ETR_SG);
-	buf_hw->has_catu = !!tmc_etr_get_catu_device(drvdata);
+	buf_hw->has_catu = !!tmc_etr_get_helper_device(drvdata,
+			CORESIGHT_DEV_SUBTYPE_HELPER_CATU);
 	buf_hw->has_resrv = tmc_has_reserved_buffer(drvdata);
 }
 
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index c9a82ff6cd00..7690a70069da 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -471,7 +471,8 @@ static inline uint32_t find_crash_tracedata_crc(struct tmc_drvdata *drvdata,
 	return crc32_le(0, (void *)drvdata->resrv_buf.vaddr, crc_size);
 }
 
-struct coresight_device *tmc_etr_get_catu_device(struct tmc_drvdata *drvdata);
+struct coresight_device *tmc_etr_get_helper_device(struct tmc_drvdata *drvdata,
+						   enum coresight_dev_subtype_helper subtype);
 
 void tmc_etr_set_catu_ops(const struct etr_buf_operations *catu);
 void tmc_etr_remove_catu_ops(void);

-- 
2.34.1



From jie.gan at oss.qualcomm.com  Wed Dec 24 01:06:15 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Wed, 24 Dec 2025 17:06:15 +0800
Subject: [PATCH v9 5/8] dt-bindings: arm: add an interrupt property for
 Coresight CTCU
In-Reply-To: <20251224-enable-byte-cntr-for-ctcu-v9-0-886c4496fed4@oss.qualcomm.com>
References: <20251224-enable-byte-cntr-for-ctcu-v9-0-886c4496fed4@oss.qualcomm.com>
Message-ID: <20251224-enable-byte-cntr-for-ctcu-v9-5-886c4496fed4@oss.qualcomm.com>

Add an interrupt property to CTCU device. The interrupt will be triggered
when the data size in the ETR buffer exceeds the threshold of the
BYTECNTRVAL register. Programming a threshold in the BYTECNTRVAL register
of CTCU device will enable the interrupt.

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
Reviewed-by: Mike Leach <mike.leach at linaro.org>
Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
index c969c16c21ef..ac27a8b89085 100644
--- a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
+++ b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
@@ -39,6 +39,11 @@ properties:
     items:
       - const: apb
 
+  interrupts:
+    items:
+      - description: Interrupt for the ETR device connected to in-port0.
+      - description: Interrupt for the ETR device connected to in-port1.
+
   label:
     description:
       Description of a coresight device.
@@ -60,6 +65,8 @@ additionalProperties: false
 
 examples:
   - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
     ctcu at 1001000 {
         compatible = "qcom,sa8775p-ctcu";
         reg = <0x1001000 0x1000>;
@@ -67,6 +74,9 @@ examples:
         clocks = <&aoss_qmp>;
         clock-names = "apb";
 
+        interrupts = <GIC_SPI 270 IRQ_TYPE_EDGE_RISING>,
+                     <GIC_SPI 262 IRQ_TYPE_EDGE_RISING>;
+
         in-ports {
             #address-cells = <1>;
             #size-cells = <0>;

-- 
2.34.1



From jie.gan at oss.qualcomm.com  Wed Dec 24 01:06:16 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Wed, 24 Dec 2025 17:06:16 +0800
Subject: [PATCH v9 6/8] coresight: ctcu: enable byte-cntr for TMC ETR
 devices
In-Reply-To: <20251224-enable-byte-cntr-for-ctcu-v9-0-886c4496fed4@oss.qualcomm.com>
References: <20251224-enable-byte-cntr-for-ctcu-v9-0-886c4496fed4@oss.qualcomm.com>
Message-ID: <20251224-enable-byte-cntr-for-ctcu-v9-6-886c4496fed4@oss.qualcomm.com>

The byte-cntr function provided by the CTCU device is used to transfer data
from the ETR buffer to the userspace. An interrupt is triggered if the data
size exceeds the threshold set in the BYTECNTRVAL register. The interrupt
handler counts the number of triggered interruptions and the read function
will read the data from the synced ETR buffer.

Switching the sysfs_buf when current buffer is full or the timeout is
triggered and resets rrp and rwp registers after switched the buffer.
The synced buffer will become available for reading after the switch.

Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 .../ABI/testing/sysfs-bus-coresight-devices-ctcu   |   8 +
 drivers/hwtracing/coresight/Makefile               |   2 +-
 .../hwtracing/coresight/coresight-ctcu-byte-cntr.c | 366 +++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-ctcu-core.c  | 103 +++++-
 drivers/hwtracing/coresight/coresight-ctcu.h       |  77 ++++-
 drivers/hwtracing/coresight/coresight-tmc-etr.c    |  18 +
 drivers/hwtracing/coresight/coresight-tmc.h        |   1 +
 7 files changed, 562 insertions(+), 13 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-ctcu b/Documentation/ABI/testing/sysfs-bus-coresight-devices-ctcu
new file mode 100644
index 000000000000..3230c19dc701
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-ctcu
@@ -0,0 +1,8 @@
+What:           /sys/bus/coresight/devices/<ctcu-name>/irq_threshold[0:1]
+Date:           Dec. 2025
+KernelVersion:  6.20
+Contact:        Tingwei Zhang <tingwei.zhang at oss.qualcomm.com>; Jinlong Mao <jinlong.mao at oss.qualcomm.com>; Jie Gan <jie.gan at oss.qualcomm.com>
+Description:
+		(RW) Configure the byte-cntr IRQ register for the specified ETR device
+		based on its port number. An interrupt is generated when the data size
+		exceeds the value set in the IRQ register.
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile
index ab16d06783a5..821a1b06b20c 100644
--- a/drivers/hwtracing/coresight/Makefile
+++ b/drivers/hwtracing/coresight/Makefile
@@ -55,5 +55,5 @@ coresight-cti-y := coresight-cti-core.o	coresight-cti-platform.o \
 obj-$(CONFIG_ULTRASOC_SMB) += ultrasoc-smb.o
 obj-$(CONFIG_CORESIGHT_DUMMY) += coresight-dummy.o
 obj-$(CONFIG_CORESIGHT_CTCU) += coresight-ctcu.o
-coresight-ctcu-y := coresight-ctcu-core.o
+coresight-ctcu-y := coresight-ctcu-core.o coresight-ctcu-byte-cntr.o
 obj-$(CONFIG_CORESIGHT_KUNIT_TESTS) += coresight-kunit-tests.o
diff --git a/drivers/hwtracing/coresight/coresight-ctcu-byte-cntr.c b/drivers/hwtracing/coresight/coresight-ctcu-byte-cntr.c
new file mode 100644
index 000000000000..6842b3d3daa0
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-ctcu-byte-cntr.c
@@ -0,0 +1,366 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/coresight.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/of_irq.h>
+#include <linux/uaccess.h>
+
+#include "coresight-ctcu.h"
+#include "coresight-priv.h"
+#include "coresight-tmc.h"
+
+static irqreturn_t byte_cntr_handler(int irq, void *data)
+{
+	struct ctcu_byte_cntr *byte_cntr_data = (struct ctcu_byte_cntr *)data;
+
+	atomic_inc(&byte_cntr_data->irq_cnt);
+	wake_up(&byte_cntr_data->wq);
+
+	return IRQ_HANDLED;
+}
+
+static void ctcu_reset_sysfs_buf(struct tmc_drvdata *drvdata)
+{
+	u32 sts;
+
+	CS_UNLOCK(drvdata->base);
+	tmc_write_rrp(drvdata, drvdata->sysfs_buf->hwaddr);
+	tmc_write_rwp(drvdata, drvdata->sysfs_buf->hwaddr);
+	sts = readl_relaxed(drvdata->base + TMC_STS) & ~TMC_STS_FULL;
+	writel_relaxed(sts, drvdata->base + TMC_STS);
+	CS_LOCK(drvdata->base);
+}
+
+static void ctcu_cfg_byte_cntr_reg(struct tmc_drvdata *drvdata, u32 val, u32 offset)
+{
+	struct ctcu_drvdata *ctcu_drvdata;
+	struct coresight_device *helper;
+
+	helper = tmc_etr_get_helper_device(drvdata, CORESIGHT_DEV_SUBTYPE_HELPER_CTCU);
+	if (!helper)
+		return;
+
+	ctcu_drvdata = dev_get_drvdata(helper->dev.parent);
+	/* A one value for IRQCTRL register represents 8 bytes */
+	ctcu_program_register(ctcu_drvdata, val / 8, offset);
+}
+
+static struct ctcu_byte_cntr *ctcu_get_byte_cntr_data(struct tmc_drvdata *drvdata)
+{
+	struct ctcu_byte_cntr *byte_cntr_data;
+	struct ctcu_drvdata *ctcu_drvdata;
+	struct coresight_device *helper;
+	int port;
+
+	helper = tmc_etr_get_helper_device(drvdata, CORESIGHT_DEV_SUBTYPE_HELPER_CTCU);
+	if (!helper)
+		return NULL;
+
+	port = coresight_get_in_port(drvdata->csdev, helper);
+	if (port < 0)
+		return NULL;
+
+	ctcu_drvdata = dev_get_drvdata(helper->dev.parent);
+	byte_cntr_data = &ctcu_drvdata->byte_cntr_data[port];
+	return byte_cntr_data;
+}
+
+static bool ctcu_byte_cntr_switch_buffer(struct tmc_drvdata *drvdata,
+					 struct ctcu_byte_cntr *byte_cntr_data)
+{
+	struct etr_buf_node *nd, *next, *curr_node, *picked_node;
+	struct etr_buf *curr_buf = drvdata->sysfs_buf;
+	bool found_free_buf = false;
+
+	if (WARN_ON(!drvdata || !byte_cntr_data))
+		return found_free_buf;
+
+	/* Stop the ETR before we start the switch */
+	if (coresight_get_mode(drvdata->csdev) != CS_MODE_DISABLED)
+		tmc_etr_enable_disable_hw(drvdata, false);
+
+	list_for_each_entry_safe(nd, next, &drvdata->etr_buf_list, node) {
+		/* curr_buf is free for next round */
+		if (nd->sysfs_buf == curr_buf) {
+			nd->is_free = true;
+			curr_node = nd;
+		}
+
+		if (!found_free_buf && nd->is_free && nd->sysfs_buf != curr_buf) {
+			picked_node = nd;
+			found_free_buf = true;
+		}
+	}
+
+	if (found_free_buf) {
+		curr_node->pos = 0;
+		drvdata->reading_node = curr_node;
+		drvdata->sysfs_buf = picked_node->sysfs_buf;
+		drvdata->etr_buf = picked_node->sysfs_buf;
+		picked_node->is_free = false;
+		/* Reset irq_cnt for next etr_buf */
+		atomic_set(&byte_cntr_data->irq_cnt, 0);
+		/* Reset rrp and rwp when the system has switched the buffer*/
+		ctcu_reset_sysfs_buf(drvdata);
+		/* Restart the ETR when we find a free buffer */
+		if (coresight_get_mode(drvdata->csdev) != CS_MODE_DISABLED)
+			tmc_etr_enable_disable_hw(drvdata, true);
+	}
+
+	return found_free_buf;
+}
+
+/*
+ * ctcu_byte_cntr_get_data() - reads data from the deactivated and filled buffer.
+ * The byte-cntr reading work reads data from the deactivated and filled buffer.
+ * The read operation waits for a buffer to become available, either filled or
+ * upon timeout, and then reads trace data from the synced buffer.
+ */
+static ssize_t ctcu_byte_cntr_get_data(struct tmc_drvdata *drvdata, loff_t pos,
+				       size_t len, char **bufpp)
+{
+	struct etr_buf *sysfs_buf = drvdata->sysfs_buf;
+	struct device *dev = &drvdata->csdev->dev;
+	ssize_t actual, size = sysfs_buf->size;
+	struct ctcu_byte_cntr *byte_cntr_data;
+	size_t thresh_val;
+	atomic_t *irq_cnt;
+	int ret;
+
+	byte_cntr_data = ctcu_get_byte_cntr_data(drvdata);
+	if (!byte_cntr_data)
+		return -EINVAL;
+
+	thresh_val = byte_cntr_data->thresh_val;
+	irq_cnt = &byte_cntr_data->irq_cnt;
+
+wait_buffer:
+	if (!byte_cntr_data->reading_buf) {
+		ret = wait_event_interruptible_timeout(byte_cntr_data->wq,
+				((atomic_read(irq_cnt) + 1) * thresh_val >= size) ||
+				!byte_cntr_data->enable,
+				BYTE_CNTR_TIMEOUT);
+		if (ret < 0)
+			return ret;
+		/*
+		 * The current etr_buf is almost full or timeout is triggered,
+		 * so switch the buffer and mark the switched buffer as reading.
+		 */
+		if (byte_cntr_data->enable) {
+			if (!ctcu_byte_cntr_switch_buffer(drvdata, byte_cntr_data)) {
+				dev_err(dev, "Switch buffer failed for byte-cntr\n");
+				return -EINVAL;
+			}
+
+			byte_cntr_data->reading_buf = true;
+		} else {
+			/*
+			 * TMC-ETR has been disabled, so directly reads data from
+			 * the drvdata->sysfs_buf.
+			 */
+			actual = drvdata->sysfs_ops->get_trace_data(drvdata, pos, len, bufpp);
+			if (actual > 0) {
+				byte_cntr_data->total_size += actual;
+				return actual;
+			}
+
+			/* Exit byte-cntr reading */
+			return 0;
+		}
+	}
+
+	/* Check the status of current etr_buf*/
+	if ((atomic_read(irq_cnt) + 1) * thresh_val >= size)
+		/*
+		 * Unlikely to find a free buffer to switch, so just disable
+		 * the ETR for a while.
+		 */
+		if (!ctcu_byte_cntr_switch_buffer(drvdata, byte_cntr_data))
+			dev_warn(dev, "No available buffer to store data, disable ETR\n");
+
+	pos = drvdata->reading_node->pos;
+	actual = drvdata->sysfs_ops->get_trace_data(drvdata, pos, len, bufpp);
+	if (actual <= 0) {
+		/* Reset flags upon reading is finished or failed */
+		byte_cntr_data->reading_buf = false;
+		drvdata->reading_node = NULL;
+
+		/*
+		 * Nothing in the buffer, waiting for the next buffer
+		 * to be filled.
+		 */
+		if (actual == 0)
+			goto wait_buffer;
+	} else
+		byte_cntr_data->total_size += actual;
+
+	return actual;
+}
+
+static int ctcu_read_prepare_byte_cntr(struct tmc_drvdata *drvdata)
+{
+	struct ctcu_byte_cntr *byte_cntr_data;
+	unsigned long flags;
+	int ret = 0;
+
+	/* config types are set a boot time and never change */
+	if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR))
+		return -EINVAL;
+
+	/*
+	 * Byte counter reading should start only after the TMC-ETR has been
+	 * enabled, which implies that the sysfs_buf has already been setup
+	 * in drvdata.
+	 */
+	if (!drvdata->sysfs_buf)
+		return -EINVAL;
+
+	byte_cntr_data = ctcu_get_byte_cntr_data(drvdata);
+	if (!byte_cntr_data)
+		return -EINVAL;
+
+	/*
+	 * The threshold value must not exceed the buffer size.
+	 * A margin should be maintained between the two values to account
+	 * for the time gap between the interrupt and buffer switching.
+	 */
+	if (byte_cntr_data->thresh_val + SZ_16K >= drvdata->size) {
+		dev_err(&drvdata->csdev->dev, "The threshold value is too large\n");
+		return -EINVAL;
+	}
+
+	raw_spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (byte_cntr_data->reading) {
+		ret = -EBUSY;
+		goto out_unlock;
+	}
+
+	byte_cntr_data->reading = true;
+	raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+	/* Setup an available etr_buf_list for byte-cntr */
+	ret = tmc_create_etr_buf_list(drvdata, 2);
+	if (ret)
+		goto out;
+
+	raw_spin_lock_irqsave(&drvdata->spinlock, flags);
+	atomic_set(&byte_cntr_data->irq_cnt, 0);
+	/* Configure the byte-cntr register to enable IRQ */
+	ctcu_cfg_byte_cntr_reg(drvdata, byte_cntr_data->thresh_val,
+			       byte_cntr_data->irq_ctrl_offset);
+	enable_irq_wake(byte_cntr_data->irq);
+	byte_cntr_data->total_size = 0;
+
+out_unlock:
+	raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+out:
+	return ret;
+}
+
+static int ctcu_read_unprepare_byte_cntr(struct tmc_drvdata *drvdata)
+{
+	struct device *dev = &drvdata->csdev->dev;
+	struct ctcu_byte_cntr *byte_cntr_data;
+	unsigned long flags;
+
+	byte_cntr_data = ctcu_get_byte_cntr_data(drvdata);
+	if (!byte_cntr_data)
+		return -EINVAL;
+
+	raw_spin_lock_irqsave(&drvdata->spinlock, flags);
+	/* Configure the byte-cntr register to disable IRQ */
+	ctcu_cfg_byte_cntr_reg(drvdata, 0, byte_cntr_data->irq_ctrl_offset);
+	disable_irq_wake(byte_cntr_data->irq);
+	byte_cntr_data->reading = false;
+	byte_cntr_data->reading_buf = false;
+	drvdata->reading_node = NULL;
+	raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+	dev_dbg(dev, "send data total size:%llu bytes\n", byte_cntr_data->total_size);
+	tmc_clean_etr_buf_list(drvdata);
+
+	return 0;
+}
+
+static const struct sysfs_read_ops byte_cntr_sysfs_read_ops = {
+	.read_prepare	= ctcu_read_prepare_byte_cntr,
+	.read_unprepare	= ctcu_read_unprepare_byte_cntr,
+	.get_trace_data	= ctcu_byte_cntr_get_data,
+};
+
+/* Start the byte-cntr function when the path is enabled. */
+void ctcu_byte_cntr_start(struct coresight_device *csdev, struct coresight_path *path)
+{
+	struct ctcu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	struct coresight_device *sink = coresight_get_sink(path);
+	struct ctcu_byte_cntr *byte_cntr_data;
+	int port_num;
+
+	if (!sink)
+		return;
+
+	port_num = coresight_get_in_port(sink, csdev);
+	if (port_num < 0)
+		return;
+
+	byte_cntr_data = &drvdata->byte_cntr_data[port_num];
+	/* Don't start byte-cntr function when threshold is not set. */
+	if (!byte_cntr_data->thresh_val || byte_cntr_data->enable)
+		return;
+
+	guard(raw_spinlock_irqsave)(&byte_cntr_data->spin_lock);
+	byte_cntr_data->enable = true;
+	byte_cntr_data->reading_buf = false;
+}
+
+/* Stop the byte-cntr function when the path is disabled. */
+void ctcu_byte_cntr_stop(struct coresight_device *csdev, struct coresight_path *path)
+{
+	struct ctcu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	struct coresight_device *sink = coresight_get_sink(path);
+	struct ctcu_byte_cntr *byte_cntr_data;
+	int port_num;
+
+	if (!sink || coresight_get_mode(sink) == CS_MODE_SYSFS)
+		return;
+
+	port_num = coresight_get_in_port(sink, csdev);
+	if (port_num < 0)
+		return;
+
+	byte_cntr_data = &drvdata->byte_cntr_data[port_num];
+	guard(raw_spinlock_irqsave)(&byte_cntr_data->spin_lock);
+	byte_cntr_data->enable = false;
+}
+
+void ctcu_byte_cntr_init(struct device *dev, struct ctcu_drvdata *drvdata, int etr_num)
+{
+	struct ctcu_byte_cntr *byte_cntr_data;
+	struct device_node *nd = dev->of_node;
+	int irq_num, ret, i;
+
+	drvdata->byte_cntr_sysfs_read_ops = &byte_cntr_sysfs_read_ops;
+	for (i = 0; i < etr_num; i++) {
+		byte_cntr_data = &drvdata->byte_cntr_data[i];
+		irq_num = of_irq_get(nd, i);
+		if (irq_num < 0) {
+			dev_err(dev, "Failed to get IRQ from DT for port%d\n", i);
+			continue;
+		}
+
+		ret = devm_request_irq(dev, irq_num, byte_cntr_handler,
+				       IRQF_TRIGGER_RISING | IRQF_SHARED,
+				       dev_name(dev), byte_cntr_data);
+		if (ret) {
+			dev_err(dev, "Failed to register IRQ for port%d\n", i);
+			continue;
+		}
+
+		byte_cntr_data->irq = irq_num;
+		init_waitqueue_head(&byte_cntr_data->wq);
+	}
+}
diff --git a/drivers/hwtracing/coresight/coresight-ctcu-core.c b/drivers/hwtracing/coresight/coresight-ctcu-core.c
index 78be783b3cb2..0e5cadaac350 100644
--- a/drivers/hwtracing/coresight/coresight-ctcu-core.c
+++ b/drivers/hwtracing/coresight/coresight-ctcu-core.c
@@ -15,6 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
+#include <linux/sizes.h>
 
 #include "coresight-ctcu.h"
 #include "coresight-priv.h"
@@ -45,17 +46,21 @@ DEFINE_CORESIGHT_DEVLIST(ctcu_devs, "ctcu");
 
 #define CTCU_ATID_REG_BIT(traceid)	(traceid % 32)
 #define CTCU_ATID_REG_SIZE		0x10
+#define CTCU_ETR0_IRQCTRL               0x6c
+#define CTCU_ETR1_IRQCTRL               0x70
 #define CTCU_ETR0_ATID0			0xf8
 #define CTCU_ETR1_ATID0			0x108
 
 static const struct ctcu_etr_config sa8775p_etr_cfgs[] = {
 	{
-		.atid_offset	= CTCU_ETR0_ATID0,
-		.port_num	= 0,
+		.atid_offset		= CTCU_ETR0_ATID0,
+		.irq_ctrl_offset	= CTCU_ETR0_IRQCTRL,
+		.port_num		= 0,
 	},
 	{
-		.atid_offset	= CTCU_ETR1_ATID0,
-		.port_num	= 1,
+		.atid_offset		= CTCU_ETR1_ATID0,
+		.irq_ctrl_offset	= CTCU_ETR1_IRQCTRL,
+		.port_num		= 1,
 	},
 };
 
@@ -64,6 +69,88 @@ static const struct ctcu_config sa8775p_cfgs = {
 	.num_etr_config	= ARRAY_SIZE(sa8775p_etr_cfgs),
 };
 
+void ctcu_program_register(struct ctcu_drvdata *drvdata, u32 val, u32 offset)
+{
+	CS_UNLOCK(drvdata->base);
+	ctcu_writel(drvdata, val, offset);
+	CS_LOCK(drvdata->base);
+}
+
+static ssize_t irq_threshold_show(struct device *dev,
+				  struct device_attribute *attr,
+				  char *buf)
+{
+	struct ctcu_byte_cntr_irq_attribute *irq_attr =
+		container_of(attr, struct ctcu_byte_cntr_irq_attribute, attr);
+	struct ctcu_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	u8 port = irq_attr->port;
+
+	if (!drvdata->byte_cntr_data[port].irq_ctrl_offset)
+		return -EINVAL;
+
+	return sysfs_emit(buf, "%u\n",
+			(unsigned int)drvdata->byte_cntr_data[port].thresh_val);
+}
+
+static ssize_t irq_threshold_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf,
+				   size_t size)
+{
+	struct ctcu_byte_cntr_irq_attribute *irq_attr =
+		container_of(attr, struct ctcu_byte_cntr_irq_attribute, attr);
+	struct ctcu_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	u8 port = irq_attr->port;
+	unsigned long val;
+
+	if (kstrtoul(buf, 0, &val))
+		return -EINVAL;
+
+	/* Threshold 0 disables the interruption. */
+	guard(raw_spinlock_irqsave)(&drvdata->spin_lock);
+	/* A small threshold will result in a large number of interruptions */
+	if (val && val < SZ_4K)
+		return -EINVAL;
+
+	if (drvdata->byte_cntr_data[port].irq_ctrl_offset)
+		drvdata->byte_cntr_data[port].thresh_val = val;
+
+	return size;
+}
+
+static umode_t irq_threshold_is_visible(struct kobject *kobj,
+					struct attribute *attr, int n)
+{
+	struct device_attribute *dev_attr =
+		container_of(attr, struct device_attribute, attr);
+	struct ctcu_byte_cntr_irq_attribute *irq_attr =
+		container_of(dev_attr, struct ctcu_byte_cntr_irq_attribute, attr);
+	struct device *dev = kobj_to_dev(kobj);
+	struct ctcu_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	u8 port = irq_attr->port;
+
+	if (drvdata && drvdata->byte_cntr_data[port].irq_ctrl_offset)
+		return attr->mode;
+
+	return 0;
+}
+
+static struct attribute *ctcu_attrs[] = {
+	ctcu_byte_cntr_irq_rw(0),
+	ctcu_byte_cntr_irq_rw(1),
+	NULL,
+};
+
+static struct attribute_group ctcu_attr_grp = {
+	.attrs = ctcu_attrs,
+	.is_visible = irq_threshold_is_visible,
+};
+
+static const struct attribute_group *ctcu_attr_grps[] = {
+	&ctcu_attr_grp,
+	NULL,
+};
+
 static void ctcu_program_atid_register(struct ctcu_drvdata *drvdata, u32 reg_offset,
 				       u8 bit, bool enable)
 {
@@ -142,11 +229,15 @@ static int ctcu_set_etr_traceid(struct coresight_device *csdev, struct coresight
 static int ctcu_enable(struct coresight_device *csdev, enum cs_mode mode,
 		       struct coresight_path *path)
 {
+	ctcu_byte_cntr_start(csdev, path);
+
 	return ctcu_set_etr_traceid(csdev, path, true);
 }
 
 static int ctcu_disable(struct coresight_device *csdev, struct coresight_path *path)
 {
+	ctcu_byte_cntr_stop(csdev, path);
+
 	return ctcu_set_etr_traceid(csdev, path, false);
 }
 
@@ -197,7 +288,10 @@ static int ctcu_probe(struct platform_device *pdev)
 			for (i = 0; i < cfgs->num_etr_config; i++) {
 				etr_cfg = &cfgs->etr_cfgs[i];
 				drvdata->atid_offset[i] = etr_cfg->atid_offset;
+				drvdata->byte_cntr_data[i].irq_ctrl_offset =
+					etr_cfg->irq_ctrl_offset;
 			}
+			ctcu_byte_cntr_init(dev, drvdata, cfgs->num_etr_config);
 		}
 	}
 
@@ -209,6 +303,7 @@ static int ctcu_probe(struct platform_device *pdev)
 	desc.subtype.helper_subtype = CORESIGHT_DEV_SUBTYPE_HELPER_CTCU;
 	desc.pdata = pdata;
 	desc.dev = dev;
+	desc.groups = ctcu_attr_grps;
 	desc.ops = &ctcu_ops;
 	desc.access = CSDEV_ACCESS_IOMEM(base);
 
diff --git a/drivers/hwtracing/coresight/coresight-ctcu.h b/drivers/hwtracing/coresight/coresight-ctcu.h
index e9594c38dd91..4ff01f697903 100644
--- a/drivers/hwtracing/coresight/coresight-ctcu.h
+++ b/drivers/hwtracing/coresight/coresight-ctcu.h
@@ -5,19 +5,26 @@
 
 #ifndef _CORESIGHT_CTCU_H
 #define _CORESIGHT_CTCU_H
+
+#include <linux/time.h>
 #include "coresight-trace-id.h"
 
 /* Maximum number of supported ETR devices for a single CTCU. */
 #define ETR_MAX_NUM	2
 
+#define BYTE_CNTR_TIMEOUT	(5 * HZ)
+
 /**
  * struct ctcu_etr_config
  * @atid_offset:	offset to the ATID0 Register.
- * @port_num:		in-port number of CTCU device that connected to ETR.
+ * @port_num:		in-port number of the CTCU device that connected to ETR.
+ * @irq_ctrl_offset:    offset to the BYTECNTRVAL register.
+ * @irq_name:           IRQ name in dt node.
  */
 struct ctcu_etr_config {
 	const u32 atid_offset;
 	const u32 port_num;
+	const u32 irq_ctrl_offset;
 };
 
 struct ctcu_config {
@@ -25,15 +32,69 @@ struct ctcu_config {
 	int num_etr_config;
 };
 
-struct ctcu_drvdata {
-	void __iomem		*base;
-	struct clk		*apb_clk;
-	struct device		*dev;
-	struct coresight_device	*csdev;
+/**
+ * struct ctcu_byte_cntr
+ * @enable:		indicates that byte_cntr function is enabled or not.
+ * @reading:		indicates that byte-cntr reading is started.
+ * @reading_buf:	indicates that byte-cntr is reading data from the buffer.
+ * @thresh_val:		threshold to trigger a interruption.
+ * @total_size:		total size of transferred data.
+ * @irq:		allocated number of the IRQ.
+ * @irq_cnt:		IRQ count number for triggered interruptions.
+ * @wq:			waitqueue for reading data from ETR buffer.
+ * @spin_lock:		spinlock of byte_cntr_data.
+ * @irq_ctrl_offset:	offset to the BYTECNTVAL Register.
+ */
+struct ctcu_byte_cntr {
+	bool			enable;
+	bool                    reading;
+	bool			reading_buf;
+	u32			thresh_val;
+	u64			total_size;
+	int			irq;
+	atomic_t		irq_cnt;
+	wait_queue_head_t	wq;
 	raw_spinlock_t		spin_lock;
-	u32			atid_offset[ETR_MAX_NUM];
+	u32			irq_ctrl_offset;
+};
+
+struct ctcu_drvdata {
+	void __iomem			*base;
+	struct clk			*apb_clk;
+	struct device			*dev;
+	struct coresight_device		*csdev;
+	struct ctcu_byte_cntr		byte_cntr_data[ETR_MAX_NUM];
+	raw_spinlock_t			spin_lock;
+	u32				atid_offset[ETR_MAX_NUM];
 	/* refcnt for each traceid of each sink */
-	u8			traceid_refcnt[ETR_MAX_NUM][CORESIGHT_TRACE_ID_RES_TOP];
+	u8				traceid_refcnt[ETR_MAX_NUM][CORESIGHT_TRACE_ID_RES_TOP];
+	const struct sysfs_read_ops	*byte_cntr_sysfs_read_ops;
 };
 
+/**
+ * struct ctcu_irq_thresh_attribute
+ * @attr:	The device attribute.
+ * @idx:	port number.
+ */
+struct ctcu_byte_cntr_irq_attribute {
+	struct device_attribute	attr;
+	u8			port;
+};
+
+#define ctcu_byte_cntr_irq_rw(port)					\
+	(&((struct ctcu_byte_cntr_irq_attribute[]) {			\
+	   {								\
+		__ATTR(irq_threshold##port, 0644, irq_threshold_show,	\
+		irq_threshold_store),					\
+		port,							\
+	   }								\
+	})[0].attr.attr)
+
+void ctcu_program_register(struct ctcu_drvdata *drvdata, u32 val, u32 offset);
+
+/* Byte-cntr functions */
+void ctcu_byte_cntr_start(struct coresight_device *csdev, struct coresight_path *path);
+void ctcu_byte_cntr_stop(struct coresight_device *csdev, struct coresight_path *path);
+void ctcu_byte_cntr_init(struct device *dev, struct ctcu_drvdata *drvdata, int port_num);
+
 #endif
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 18981b6cc172..9440c1cb155d 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -1173,6 +1173,10 @@ ssize_t tmc_etr_get_sysfs_trace(struct tmc_drvdata *drvdata,
 	ssize_t actual = len;
 	struct etr_buf *etr_buf = drvdata->sysfs_buf;
 
+	/* Reading the buffer from the buf_node if it exists*/
+	if (drvdata->reading_node)
+		etr_buf = drvdata->reading_node->sysfs_buf;
+
 	if (pos + actual > etr_buf->len)
 		actual = etr_buf->len - pos;
 	if (actual <= 0)
@@ -1236,6 +1240,20 @@ static void __tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
 
 }
 
+/**
+ * tmc_etr_enable_disable_hw - enable/disable the ETR hw.
+ * @drvdata:	drvdata of the TMC device.
+ * @enable:	indicates enable/disable.
+ */
+void tmc_etr_enable_disable_hw(struct tmc_drvdata *drvdata, bool enable)
+{
+	if (enable)
+		__tmc_etr_enable_hw(drvdata);
+	else
+		__tmc_etr_disable_hw(drvdata);
+}
+EXPORT_SYMBOL_GPL(tmc_etr_enable_disable_hw);
+
 void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
 {
 	__tmc_etr_disable_hw(drvdata);
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 7690a70069da..5e827bb00386 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -482,5 +482,6 @@ struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev,
 extern const struct attribute_group coresight_etr_group;
 void tmc_clean_etr_buf_list(struct tmc_drvdata *drvdata);
 int tmc_create_etr_buf_list(struct tmc_drvdata *drvdata, int num_nodes);
+void tmc_etr_enable_disable_hw(struct tmc_drvdata *drvdata, bool enable);
 
 #endif

-- 
2.34.1



From jie.gan at oss.qualcomm.com  Wed Dec 24 01:06:17 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Wed, 24 Dec 2025 17:06:17 +0800
Subject: [PATCH v9 7/8] coresight: tmc: integrate byte-cntr's read_ops with
 sysfs file_ops
In-Reply-To: <20251224-enable-byte-cntr-for-ctcu-v9-0-886c4496fed4@oss.qualcomm.com>
References: <20251224-enable-byte-cntr-for-ctcu-v9-0-886c4496fed4@oss.qualcomm.com>
Message-ID: <20251224-enable-byte-cntr-for-ctcu-v9-7-886c4496fed4@oss.qualcomm.com>

Add code logic to invoke byte-cntr's sysfs_read_ops if the byte-cntr
is enabled.

Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 drivers/hwtracing/coresight/coresight-tmc-core.c | 53 +++++++++++++++++++++++-
 1 file changed, 52 insertions(+), 1 deletion(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c
index 8b0397a77e57..5e74f33f6a23 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-core.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-core.c
@@ -31,6 +31,7 @@
 
 #include "coresight-priv.h"
 #include "coresight-tmc.h"
+#include "coresight-ctcu.h"
 
 DEFINE_CORESIGHT_DEVLIST(etb_devs, "tmc_etb");
 DEFINE_CORESIGHT_DEVLIST(etf_devs, "tmc_etf");
@@ -228,15 +229,47 @@ static int tmc_prepare_crashdata(struct tmc_drvdata *drvdata)
 	return 0;
 }
 
+/* Return the byte-cntr's sysfs_read_ops if in use */
+static const struct sysfs_read_ops *tmc_get_byte_cntr_sysfs_ops(struct tmc_drvdata *drvdata)
+{
+	struct ctcu_byte_cntr *byte_cntr_data;
+	struct ctcu_drvdata *ctcu_drvdata;
+	struct coresight_device *helper;
+	int port;
+
+	helper = tmc_etr_get_helper_device(drvdata, CORESIGHT_DEV_SUBTYPE_HELPER_CTCU);
+	if (!helper)
+		return NULL;
+
+	port = coresight_get_in_port(drvdata->csdev, helper);
+	if (port < 0)
+		return NULL;
+
+	ctcu_drvdata = dev_get_drvdata(helper->dev.parent);
+	byte_cntr_data = &ctcu_drvdata->byte_cntr_data[port];
+	if (byte_cntr_data && byte_cntr_data->thresh_val)
+		return ctcu_drvdata->byte_cntr_sysfs_read_ops;
+
+	return NULL;
+}
+
 static int tmc_read_prepare(struct tmc_drvdata *drvdata)
 {
+	const struct sysfs_read_ops *byte_cntr_sysfs_read_ops;
 	int ret = 0;
 
+	byte_cntr_sysfs_read_ops = tmc_get_byte_cntr_sysfs_ops(drvdata);
+	if (byte_cntr_sysfs_read_ops) {
+		ret = byte_cntr_sysfs_read_ops->read_prepare(drvdata);
+		goto out;
+	}
+
 	if (drvdata->sysfs_ops)
 		ret = drvdata->sysfs_ops->read_prepare(drvdata);
 	else
 		ret = -EINVAL;
 
+out:
 	if (!ret)
 		dev_dbg(&drvdata->csdev->dev, "TMC read start\n");
 
@@ -245,13 +278,21 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata)
 
 static int tmc_read_unprepare(struct tmc_drvdata *drvdata)
 {
+	const struct sysfs_read_ops *byte_cntr_sysfs_read_ops;
 	int ret = 0;
 
+	byte_cntr_sysfs_read_ops = tmc_get_byte_cntr_sysfs_ops(drvdata);
+	if (byte_cntr_sysfs_read_ops) {
+		ret = byte_cntr_sysfs_read_ops->read_unprepare(drvdata);
+		goto out;
+	}
+
 	if (drvdata->sysfs_ops)
 		ret = drvdata->sysfs_ops->read_unprepare(drvdata);
 	else
 		ret = -EINVAL;
 
+out:
 	if (!ret)
 		dev_dbg(&drvdata->csdev->dev, "TMC read end\n");
 
@@ -277,6 +318,12 @@ static int tmc_open(struct inode *inode, struct file *file)
 static ssize_t tmc_get_sysfs_trace(struct tmc_drvdata *drvdata, loff_t pos, size_t len,
 				   char **bufpp)
 {
+	const struct sysfs_read_ops *byte_cntr_sysfs_read_ops;
+
+	byte_cntr_sysfs_read_ops = tmc_get_byte_cntr_sysfs_ops(drvdata);
+	if (byte_cntr_sysfs_read_ops)
+		return byte_cntr_sysfs_read_ops->get_trace_data(drvdata, pos, len, bufpp);
+
 	if (drvdata->sysfs_ops)
 		return drvdata->sysfs_ops->get_trace_data(drvdata, pos, len, bufpp);
 
@@ -300,7 +347,11 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len,
 		return -EFAULT;
 	}
 
-	*ppos += actual;
+	if (drvdata->reading_node)
+		drvdata->reading_node->pos += actual;
+	else
+		*ppos += actual;
+
 	dev_dbg(&drvdata->csdev->dev, "%zu bytes copied\n", actual);
 
 	return actual;

-- 
2.34.1



From jie.gan at oss.qualcomm.com  Wed Dec 24 01:06:18 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Wed, 24 Dec 2025 17:06:18 +0800
Subject: [PATCH v9 8/8] arm64: dts: qcom: lemans: add interrupts to CTCU
 device
In-Reply-To: <20251224-enable-byte-cntr-for-ctcu-v9-0-886c4496fed4@oss.qualcomm.com>
References: <20251224-enable-byte-cntr-for-ctcu-v9-0-886c4496fed4@oss.qualcomm.com>
Message-ID: <20251224-enable-byte-cntr-for-ctcu-v9-8-886c4496fed4@oss.qualcomm.com>

Add interrupts to enable byte-cntr function for TMC ETR devices.

Reviewed-by: Konrad Dybcio <konrad.dybcio at oss.qualcomm.com>
Signed-off-by: Jie Gan <jie.gan at oss.qualcomm.com>
---
 arch/arm64/boot/dts/qcom/lemans.dtsi | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi
index 0b154d57ba24..75a468ddbf53 100644
--- a/arch/arm64/boot/dts/qcom/lemans.dtsi
+++ b/arch/arm64/boot/dts/qcom/lemans.dtsi
@@ -2776,6 +2776,9 @@ ctcu at 4001000 {
 			clocks = <&aoss_qmp>;
 			clock-names = "apb";
 
+			interrupts = <GIC_SPI 270 IRQ_TYPE_EDGE_RISING>,
+				     <GIC_SPI 262 IRQ_TYPE_EDGE_RISING>;
+
 			in-ports {
 				#address-cells = <1>;
 				#size-cells = <0>;

-- 
2.34.1



From krzk at kernel.org  Wed Dec 24 01:10:43 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 24 Dec 2025 10:10:43 +0100
Subject: [PATCH v2 1/2] dt-bindings: arm: aspeed: add Meta ventura2 board
In-Reply-To: <20251224-ventura2_initial_dts-v2-1-f193ba5d4073@gmail.com>
References: <20251224-ventura2_initial_dts-v2-0-f193ba5d4073@gmail.com>
 <20251224-ventura2_initial_dts-v2-1-f193ba5d4073@gmail.com>
Message-ID: <20251224-bustard-of-major-growth-b9cd89@quoll>

On Wed, Dec 24, 2025 at 02:44:38PM +0800, Kyle Hsieh wrote:
> Document the new compatibles used on Facebook ventura2.
> 
> Signed-off-by: Kyle Hsieh <kylehsieh1995 at gmail.com>
> ---
>  Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml | 1 +
>  1 file changed, 1 insertion(+)
>

<form letter>
This is a friendly reminder during the review process.

It looks like you received a tag and forgot to add it.

If you do not know the process, here is a short explanation:
Please add Acked-by/Reviewed-by/Tested-by tags when posting new
versions of patchset, under or above your Signed-off-by tag, unless
patch changed significantly (e.g. new properties added to the DT
bindings). Tag is "received", when provided in a message replied to you
on the mailing list. Tools like b4 can help here. However, there's no
need to repost patches *only* to add the tags. The upstream maintainer
will do that for tags received on the version they apply.

Please read:
https://elixir.bootlin.com/linux/v6.12-rc3/source/Documentation/process/submitting-patches.rst#L577

If a tag was not added on purpose, please state why and what changed.
</form letter>

Best regards,
Krzysztof



From andrew at lunn.ch  Wed Dec 24 01:20:19 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Wed, 24 Dec 2025 10:20:19 +0100
Subject: [PATCH 2/2] ARM: dts: aspeed: ventura2: Add Meta ventura2 BMC
In-Reply-To: <CAF7HswP7Oejs42K=jG8bkNiBoDhXR2LbeHoppk0nnNon6_afwA@mail.gmail.com>
References: <20251222-ventura2_initial_dts-v1-0-1f06166c78a3@gmail.com>
 <20251222-ventura2_initial_dts-v1-2-1f06166c78a3@gmail.com>
 <c069b452-df22-4afa-bf6a-c48949f40ebc@lunn.ch>
 <CAF7HswN_jEXOU_9K4LpLnbhvd+RD0qqELAHxMBbp=hGtMjS4kQ@mail.gmail.com>
 <35f3eba9-5ec4-4cba-8a64-fb521dc65b79@lunn.ch>
 <CAF7HswN0hhJQ-gmE59cKTuPyzrs1A3rM8Xw+Z8i3_AsHRiNcug@mail.gmail.com>
 <1e21f828-1b06-492d-bfcd-ab5721621e8a@lunn.ch>
 <CAF7HswP7Oejs42K=jG8bkNiBoDhXR2LbeHoppk0nnNon6_afwA@mail.gmail.com>
Message-ID: <32ff7ca8-9cb0-4889-adb0-a6dae735630b@lunn.ch>

On Wed, Dec 24, 2025 at 02:40:39PM +0800, Kyle Hsieh wrote:
> On Tue, Dec 23, 2025 at 6:35?PM Andrew Lunn <andrew at lunn.ch> wrote:
> >
> > > > What make/model of switch is it? Is it unmanaged, or does it use SPI
> > > > or I2C for management?
> >
> > > The switch is connected via RMII to the MAC and is managed over MDIO.
> >
> > O.K. What make/model?
> >
> The device is a Marvell 88E6393X switch. In our design, the BMC connects

Which Linux does have a driver for.

> to the device via RMII with fixed link parameters to retrieve ethernet.
> > > On our board, MDIO is not wired directly to the processor; instead, we
> > > use a USB-to-MPSSE bridge (FT2232) to toggle the MDIO signals for
> > > switch management.
> >
> > I have to push back on you using a closed source user space driver,
> > given that i help maintain the Ethernet switch drivers...
> >
> > I know there have been attempts to get GPIO support added for FT2232,
> > but i don't think any got as far as mainline. That is probably the
> > only part you are missing. You can describe USB devices in DT. So you
> > should be able to describe such a GPIO controller. You can then
> > instantiate an virtual,mdio-gpio driver to give you an MDIO bus. And
> > then add nodes for the switch using DSA.

> Apologies for the confusion in my previous reply.
> The BMC connects to the peer via an RMII fixed-link.
> The link parameters are fixed at design time and there is no runtime
> MDIO-managed PHY or switch control from the BMC.

So you use the USB-MDIO to program the EEPROM? The switch boots using
the settings in the EEPROM? It is then an unmanaged hub? You are not
using UMSD in userspace? That code looks terrible.

So if you connect multiple of these unmanaged hubs together in a loop,
your network disappears in a broadcast storm? Yes, you can use these
switches in a dumb mode, but it has consequences. If you let Linux
manage it, you gain a lot of functionality, such as STP, to break
loops.

But you seem to be opposed to this. At least add in a comment
explaining the purpose of the fixed link. DT describes hardware, so
there is no harm in describing the hardware, even if it is a comment
and not real properties.

	Andrew


From u.kleine-koenig at baylibre.com  Wed Dec 24 01:54:54 2025
From: u.kleine-koenig at baylibre.com (Uwe =?utf-8?Q?Kleine-K=C3=B6nig?=)
Date: Wed, 24 Dec 2025 10:54:54 +0100
Subject: [PATCH v2 2/4] pwm: sun50i: Add H616 PWM support
In-Reply-To: <20251217082504.80226-3-richard.genoud@bootlin.com>
References: <20251217082504.80226-1-richard.genoud@bootlin.com>
 <20251217082504.80226-3-richard.genoud@bootlin.com>
Message-ID: <en7wscywn3xpw7cxvc2ngwrmjfciglzxgaje5qc5ngiehrjufh@jbvgp2neyzzx>

Hello,

this patch isn't checkpatch clean.

On Wed, Dec 17, 2025 at 09:25:02AM +0100, Richard Genoud wrote:
> Add driver for Allwinner H616 PWM controller, supporting up to 6
> channels.
> Those channels output can be either a PWM signal output or a clock
> output, thanks to the bypass.
> 
> The channels are paired (0/1, 2/3 and 4/5) and each pair has a
> prescaler/mux/gate.
> Moreover, each channel has its own prescaler and bypass.
> 
> Tested-by: Joao Schim <joao at schimsalabim.eu>
> Signed-off-by: Richard Genoud <richard.genoud at bootlin.com>
> ---
>  drivers/pwm/Kconfig           |  12 +
>  drivers/pwm/Makefile          |   1 +
>  drivers/pwm/pwm-sun50i-h616.c | 892 ++++++++++++++++++++++++++++++++++
>  3 files changed, 905 insertions(+)
>  create mode 100644 drivers/pwm/pwm-sun50i-h616.c
> 
> diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
> index 6f3147518376..66534e033761 100644
> --- a/drivers/pwm/Kconfig
> +++ b/drivers/pwm/Kconfig
> @@ -736,6 +736,18 @@ config PWM_SUN4I
>  	  To compile this driver as a module, choose M here: the module
>  	  will be called pwm-sun4i.
>  
> +config PWM_SUN50I_H616
> +	tristate "Allwinner H616 PWM support"
> +	depends on ARCH_SUNXI || COMPILE_TEST
> +	depends on HAS_IOMEM && COMMON_CLK
> +	help
> +	  Generic PWM framework driver for Allwinner H616 SoCs.
> +	  It supports generic PWM, but can also provides a plain clock.
> +	  The AC300 PHY integrated in H616 SoC needs such a clock.
> +
> +	  To compile this driver as a module, choose M here: the module
> +	  will be called pwm-h616.
> +
>  config PWM_SUNPLUS
>  	tristate "Sunplus PWM support"
>  	depends on ARCH_SUNPLUS || COMPILE_TEST
> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> index 0dc0d2b69025..a16ae9eef9e5 100644
> --- a/drivers/pwm/Makefile
> +++ b/drivers/pwm/Makefile
> @@ -67,6 +67,7 @@ obj-$(CONFIG_PWM_STM32)		+= pwm-stm32.o
>  obj-$(CONFIG_PWM_STM32_LP)	+= pwm-stm32-lp.o
>  obj-$(CONFIG_PWM_STMPE)		+= pwm-stmpe.o
>  obj-$(CONFIG_PWM_SUN4I)		+= pwm-sun4i.o
> +obj-$(CONFIG_PWM_SUN50I_H616)	+= pwm-sun50i-h616.o
>  obj-$(CONFIG_PWM_SUNPLUS)	+= pwm-sunplus.o
>  obj-$(CONFIG_PWM_TEGRA)		+= pwm-tegra.o
>  obj-$(CONFIG_PWM_TH1520)	+= pwm_th1520.o
> diff --git a/drivers/pwm/pwm-sun50i-h616.c b/drivers/pwm/pwm-sun50i-h616.c
> new file mode 100644
> index 000000000000..b002ea5935e4
> --- /dev/null
> +++ b/drivers/pwm/pwm-sun50i-h616.c
> @@ -0,0 +1,892 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Driver for Allwinner H616 Pulse Width Modulation Controller
> + *
> + * (C) Copyright 2025 Richard Genoud, Bootlin <richard.genoud at bootlin.com>
> + *
> + * Based on drivers/pwm/pwm-sun4i.c with Copyright:
> + *
> + * Copyright (C) 2014 Alexandre Belloni <alexandre.belloni at bootlin.com>
> + *
> + * Limitations:
> + * - When outputing the source clock directly, the PWM logic is bypassed and the
> + *   currently running period is not guaranteed to be completed.
> + * - As the channels are paired (0/1, 2/3, 4/5), they share the same clock
> + *   source and prescaler(div_m), but they also have their own prescaler(div_k)
> + *   and bypass.
> + *
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/bits.h>
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/math64.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/pwm.h>
> +#include <linux/reset.h>
> +#include <linux/spinlock.h>
> +#include <linux/time.h>
> +
> +#ifndef UINT32_MAX
> +#define UINT32_MAX 0xffffffffU
> +#endif

Please include <linux/limits.h> and use U32_MAX.

> +
> +/* PWM IRQ Enable Register */
> +#define PWM_IER				0x0

Use a driver specific prefix for your defines. Otherwise these constants
look more generic than they are.

> +/* PWM IRQ Status Register */
> +#define PWM_ISR				0x4
> +
> +/* PWM Capture IRQ Enable Register */
> +#define PWM_CIER			0x10
> +
> +/* PWM Capture IRQ Status Register */
> +#define PWM_CISR			0x14
> +
> +/* PWMCC Pairs Clock Configuration Registers */
> +#define PWM_XY_CLK_CR(pair)		(0x20 + ((pair) * 0x4))
> +#define PWM_XY_CLK_CR_SRC_SHIFT		7
> +#define PWM_XY_CLK_CR_SRC_MASK		1

Please do:

	#define H616_PWM_XY_CLK_CR_SRC		BIT(7)

and then use the helper functions from bitfield.h 

> +#define PWM_XY_CLK_CR_GATE_BIT		4
> +#define PWM_XY_CLK_CR_BYPASS_BIT(chan)	((chan) % 2 + 5)
> +#define PWM_XY_CLK_CR_DIV_M_SHIFT	0
> +
> +/* PWMCC Pairs Dead Zone Control Registers */
> +#define PWM_XY_DZ(pair)			(0x30 + ((pair) * 0x4))
> +
> +/* PWM Enable Register */
> +#define PWM_ENR				0x40
> +#define PWM_ENABLE(x)			BIT(x)

Please use the full register name as prefix for bitfields.

> +/* PWM Capture Enable Register */
> +#define PWM_CER				0x44
> +
> +/* PWM Control Register */
> +#define PWM_CTRL_REG(chan)		(0x60 + (chan) * 0x20)
> +#define PWM_CTRL_PRESCAL_K_SHIFT	0
> +#define PWM_CTRL_PRESCAL_K_WIDTH	8
> +#define PWM_CTRL_ACTIVE_STATE		BIT(8)
> +
> +/* PWM Period Register */
> +#define PWM_PERIOD_REG(ch)		(0x64 + (ch) * 0x20)
> +#define PWM_PERIOD_MASK			GENMASK(31, 16)
> +#define PWM_DUTY_MASK			GENMASK(15, 0)
> +#define PWM_REG_PERIOD(reg)		(FIELD_GET(PWM_PERIOD_MASK, reg) + 1)
> +#define PWM_REG_DUTY(reg)		FIELD_GET(PWM_DUTY_MASK, reg)
> +#define PWM_PERIOD(prd)			FIELD_PREP(PWM_PERIOD_MASK, (prd) - 1)
> +#define PWM_DUTY(dty)			FIELD_PREP(PWM_DUTY_MASK, dty)
> +#define PWM_PERIOD_MAX			FIELD_MAX(PWM_PERIOD_MASK)
> +
> +
> +/* PWM Count Register */
> +#define PWM_CNT_REG(x)			(0x68 + (x) * 0x20)
> +
> +/* PWM Capture Control Register */
> +#define PWM_CCR(x)			(0x6c + (x) * 0x20)
> +
> +/* PWM Capture Rise Lock Register */
> +#define PWM_CRLR(x)			(0x70 + (x) * 0x20)
> +
> +/* PWM Capture Fall Lock Register */
> +#define PWM_CFLR(x)			(0x74 + (x) * 0x20)
> +
> +#define PWM_PAIR_IDX(chan)		((chan) >> 2)
> +
> +/*
> + * Block diagram of the PWM clock controller:
> + *
> + *             _____      ______      ________
> + * OSC24M --->|     |    |      |    |        |
> + * APB1 ----->| Mux |--->| Gate |--->| /div_m |-----> PWM_clock_src_xy
> + *            |_____|    |______|    |________|
> + *                           ________
> + *                          |        |
> + *                       +->| /div_k |---> PWM_clock_x
> + *                       |  |________|
> + *                       |    ______
> + *                       |   |      |
> + *                       +-->| Gate |----> PWM_bypass_clock_x
> + *                       |   |______|
> + * PWM_clock_src_xy -----+   ________
> + *                       |  |        |
> + *                       +->| /div_k |---> PWM_clock_y
> + *                       |  |________|
> + *                       |    ______
> + *                       |   |      |
> + *                       +-->| Gate |----> PWM_bypass_clock_y
> + *                           |______|
> + *
> + * NB: when the bypass is set, all the PWM logic is bypassed.
> + * So, the duty cycle and polarity can't be modified (we just have a clock).
> + * The bypass in PWM mode is used to achieve a 1/2 duty cycle with the fastest
> + * clock.

1/2 *relative* duty cycle.

> + *
> + * PWM_clock_x/y serve for the PWM purpose.
> + * PWM_bypass_clock_x/y serve for the clock-provider purpose.
> + *
> + */
> +
> +/*
> + * Table used for /div_m (diviser before obtaining PWM_clock_src_xy)
> + * It's actually CLK_DIVIDER_POWER_OF_TWO, but limited to /256
> + */
> +static const struct clk_div_table clk_table_div_m[] = {
> +	{ .val = 0, .div = 1, },
> +	{ .val = 1, .div = 2, },
> +	{ .val = 2, .div = 4, },
> +	{ .val = 3, .div = 8, },
> +	{ .val = 4, .div = 16, },
> +	{ .val = 5, .div = 32, },
> +	{ .val = 6, .div = 64, },
> +	{ .val = 7, .div = 128, },
> +	{ .val = 8, .div = 256, },
> +	{ .val = 0, .div = 0, }, /* last entry */
> +};

.div is just 1 << .val, so I would expect you can better use math
expressions instead of this table.

> +#define PWM_XY_SRC_GATE(_pair, _reg)			\
> +struct clk_gate gate_xy_##_pair = {			\
> +	.reg = (void *)_reg,				\
> +	.bit_idx = PWM_XY_CLK_CR_GATE_BIT,		\
> +	.hw.init = &(struct clk_init_data){		\
> +		.ops =  &clk_gate_ops,			\
> +	}						\

I would consider

	.hw.init.ops = ...;

and

	.hw = {
		.init = {
			.ops = ...;
		},
	},

natural here. The middleway you chose looks strange to me.
Also s/  / /.

> +}
> +
> +#define PWM_XY_SRC_MUX(_pair, _reg)			\
> +struct clk_mux mux_xy_##_pair = {			\
> +	.reg = (void *)_reg,				\
> +	.shift = PWM_XY_CLK_CR_SRC_SHIFT,		\
> +	.mask = PWM_XY_CLK_CR_SRC_MASK,			\

Huh, why does this structure has both a shift and a mask value? What is
the difference between

	.shift = 7,
	.mask = 1,

and

	.shift = 0,
	.mask = 1 << 7,

? If the latter is equivalent, you could just pass
H616_PWM_XY_CLK_CR_SRC and get rid of the extra definitions for _SHIFT
and _MASK.

> +	.flags = CLK_MUX_ROUND_CLOSEST,			\
> +	.hw.init = &(struct clk_init_data){		\
> +		.ops =  &clk_mux_ops,			\
> +	}						\
> +}
> +
> +#define PWM_XY_SRC_DIV(_pair, _reg)			\
> +struct clk_divider rate_xy_##_pair = {			\
> +	.reg = (void *)_reg,				\
> +	.shift = PWM_XY_CLK_CR_DIV_M_SHIFT,		\
> +	.table = clk_table_div_m,			\
> +	.hw.init = &(struct clk_init_data){		\
> +		.ops =  &clk_divider_ops,		\
> +	}						\
> +}
> +
> +#define PWM_X_DIV(_idx, _reg)				\
> +struct clk_divider rate_x_##_idx = {			\
> +	.reg = (void *)_reg,				\
> +	.shift = PWM_CTRL_PRESCAL_K_SHIFT,		\
> +	.width = PWM_CTRL_PRESCAL_K_WIDTH,		\
> +	.hw.init = &(struct clk_init_data){		\
> +		.ops =  &clk_divider_ops,		\
> +	}						\
> +}
> +
> +#define PWM_X_BYPASS_GATE(_idx)				\
> +struct clk_gate gate_x_bypass_##_idx = {		\
> +	.reg = (void *)PWM_ENR,				\
> +	.bit_idx = _idx,				\
> +	.hw.init = &(struct clk_init_data){		\
> +		.ops =  &clk_gate_ops,			\
> +	}						\
> +}
> +
> +#define PWM_XY_CLK_SRC(_pair, _reg)			\
> +	static PWM_XY_SRC_MUX(_pair, _reg);		\
> +	static PWM_XY_SRC_GATE(_pair, _reg);		\
> +	static PWM_XY_SRC_DIV(_pair, _reg)
> +
> +#define PWM_X_CLK(_idx)					\
> +	static PWM_X_DIV(_idx, PWM_CTRL_REG(_idx))
> +
> +#define PWM_X_BYPASS_CLK(_idx)						\
> +	PWM_X_BYPASS_GATE(_idx)
> +
> +#define REF_CLK_XY_SRC(_pair)						\
> +	{								\
> +		.name = "pwm-clk-src" #_pair,				\
> +		.mux_hw = &mux_xy_##_pair.hw,				\
> +		.gate_hw = &gate_xy_##_pair.hw,				\
> +		.rate_hw = &rate_xy_##_pair.hw,				\
> +	}
> +
> +#define REF_CLK_X(_idx, _pair)						\
> +	{								\
> +		.name = "pwm-clk" #_idx,				\
> +		.parent_names = (const char *[]){ "pwm-clk-src" #_pair }, \
> +		.num_parents = 1,					\
> +		.rate_hw = &rate_x_##_idx.hw,				\
> +		.flags = CLK_SET_RATE_PARENT,				\
> +	}
> +
> +#define REF_CLK_BYPASS(_idx, _pair)					\
> +	{								\
> +		.name = "pwm-clk-bypass" #_idx,				\
> +		.parent_names = (const char *[]){ "pwm-clk-src" #_pair }, \
> +		.num_parents = 1,					\
> +		.gate_hw = &gate_x_bypass_##_idx.hw,			\
> +		.flags = CLK_SET_RATE_PARENT,	\
> +	}
> +
> +/*
> + * PWM_clock_src_xy generation:
> + *             _____      ______      ________
> + * OSC24M --->|     |    |      |    |        |
> + * APB1 ----->| Mux |--->| Gate |--->| /div_m |-----> PWM_clock_src_xy
> + *            |_____|    |______|    |________|
> + */
> +PWM_XY_CLK_SRC(01, PWM_XY_CLK_CR(0));
> +PWM_XY_CLK_SRC(23, PWM_XY_CLK_CR(1));
> +PWM_XY_CLK_SRC(45, PWM_XY_CLK_CR(2));
> +
> +/*
> + * PWM_clock_x_div generation:
> + *                       ________
> + *                      |        | PWM_clock_x/y
> + * PWM_clock_src_xy --->| /div_k |--------------->
> + *                      |________|
> + */
> +PWM_X_CLK(0);
> +PWM_X_CLK(1);
> +PWM_X_CLK(2);
> +PWM_X_CLK(3);
> +PWM_X_CLK(4);
> +PWM_X_CLK(5);
> +
> +/*
> + * PWM_bypass_clock_xy generation:
> + *                        ______
> + *                       |      |
> + * PWM_clock_src_xy ---->| Gate |-------> PWM_bypass_clock_x
> + *                       |______|
> + *
> + * The gate is actually PWM_ENR register.
> + */
> +PWM_X_BYPASS_CLK(0);
> +PWM_X_BYPASS_CLK(1);
> +PWM_X_BYPASS_CLK(2);
> +PWM_X_BYPASS_CLK(3);
> +PWM_X_BYPASS_CLK(4);
> +PWM_X_BYPASS_CLK(5);
> +
> +struct clk_pwm_data {
> +	const char *name;
> +	const char **parent_names;
> +	unsigned int num_parents;
> +	struct clk_hw *mux_hw;
> +	struct clk_hw *rate_hw;
> +	struct clk_hw *gate_hw;
> +	unsigned long flags;
> +};
> +
> +#define CLK_BYPASS(h616chip, ch) ((h616chip)->data->npwm + (ch))
> +#define CLK_XY_SRC_IDX(h616chip, ch) ((h616chip)->data->npwm * 2 + ((ch) >> 1))
> +static struct clk_pwm_data pwmcc_data[] = {
> +	REF_CLK_X(0, 01),
> +	REF_CLK_X(1, 01),
> +	REF_CLK_X(2, 23),
> +	REF_CLK_X(3, 23),
> +	REF_CLK_X(4, 45),
> +	REF_CLK_X(5, 45),
> +	REF_CLK_BYPASS(0, 01),
> +	REF_CLK_BYPASS(1, 01),
> +	REF_CLK_BYPASS(2, 23),
> +	REF_CLK_BYPASS(3, 23),
> +	REF_CLK_BYPASS(4, 45),
> +	REF_CLK_BYPASS(5, 45),
> +	REF_CLK_XY_SRC(01),
> +	REF_CLK_XY_SRC(23),
> +	REF_CLK_XY_SRC(45),
> +	{ /* sentinel */ },
> +};
> +
> +enum h616_pwm_mode {
> +	H616_PWM_MODE_NONE,
> +	H616_PWM_MODE_PWM,
> +	H616_PWM_MODE_CLK,
> +};
> +
> +struct h616_pwm_data {
> +	unsigned int npwm;
> +};
> +
> +struct h616_pwm_channel {
> +	struct clk *pwm_clk;
> +	unsigned long rate;
> +	unsigned int entire_cycles;
> +	unsigned int active_cycles;
> +	enum h616_pwm_mode mode;
> +	bool bypass;
> +};
> +
> +struct clk_pwm_pdata {
> +	struct clk_hw_onecell_data *hw_data;
> +	spinlock_t lock;
> +	void __iomem *reg;
> +};
> +
> +struct h616_pwm_chip {
> +	struct clk_pwm_pdata *clk_pdata;
> +	struct h616_pwm_channel *channels;
> +	struct clk *bus_clk;
> +	struct reset_control *rst;
> +	void __iomem *base;
> +	const struct h616_pwm_data *data;
> +};
> +
> +static inline struct h616_pwm_chip *to_h616_pwm_chip(struct pwm_chip *chip)

It probably doesn't help much, but conceptually this could be

	static inline struct h616_pwm_chip *to_h616_pwm_chip(const struct pwm_chip *chip)

> +{
> +	return pwmchip_get_drvdata(chip);
> +}
> +
> +static inline u32 h616_pwm_readl(struct h616_pwm_chip *h616chip,
> +				 unsigned long offset)
> +{
> +	return readl(h616chip->base + offset);
> +}
> +
> +static inline void h616_pwm_writel(struct h616_pwm_chip *h616chip,
> +				   u32 val, unsigned long offset)
> +{
> +	writel(val, h616chip->base + offset);
> +}
> +
> +static void h616_pwm_set_bypass(struct h616_pwm_chip *h616chip, unsigned int idx,
> +				bool en_bypass)
> +{
> +	unsigned long flags;
> +	u32 val;
> +
> +	spin_lock_irqsave(&h616chip->clk_pdata->lock, flags);
> +
> +	val = h616_pwm_readl(h616chip, PWM_XY_CLK_CR(PWM_PAIR_IDX(idx)));
> +	if (en_bypass)
> +		val |= BIT(PWM_XY_CLK_CR_BYPASS_BIT(idx));
> +	else
> +		val &= ~BIT(PWM_XY_CLK_CR_BYPASS_BIT(idx));
> +
> +	h616_pwm_writel(h616chip, val, PWM_XY_CLK_CR(PWM_PAIR_IDX(idx)));
> +
> +	spin_unlock_irqrestore(&h616chip->clk_pdata->lock, flags);
> +}
> +
> +static int h616_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
> +{
> +	struct h616_pwm_chip *h616chip = to_h616_pwm_chip(chip);
> +	struct h616_pwm_channel *chan = &h616chip->channels[pwm->hwpwm];
> +	struct device *dev = pwmchip_parent(chip);
> +	unsigned long flags;
> +	int ret = 0;
> +
> +	spin_lock_irqsave(&h616chip->clk_pdata->lock, flags);
> +
> +	if (chan->mode == H616_PWM_MODE_CLK)
> +		ret = -EBUSY;
> +	else
> +		chan->mode = H616_PWM_MODE_PWM;
> +
> +	spin_unlock_irqrestore(&h616chip->clk_pdata->lock, flags);
> +	if (ret)
> +		goto out;

You could simplify that to:

	scoped_guard(spinlock_irqsave, &h616chip->clk_pdata->lock) {
		if (chan->mode == H616_PWM_MODE_CLK)
			return -EBUSY;
		else
			chan->mode = H616_PWM_MODE_PWM;
	}

> +
> +	ret = clk_prepare_enable(chan->pwm_clk);
> +	if (ret < 0) {
> +		dev_err(dev, "Failed to enable clock %s: %d\n",
> +			__clk_get_name(chan->pwm_clk), ret);
> +	}

Please no error messages in the runtime callbacks.

> +out:
> +	return ret;
> +}
> +
> +static void h616_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
> +{
> +	struct h616_pwm_chip *h616chip = to_h616_pwm_chip(chip);
> +	struct h616_pwm_channel *chan = &h616chip->channels[pwm->hwpwm];
> +
> +	clk_disable_unprepare(chan->pwm_clk);
> +	chan->mode = H616_PWM_MODE_NONE;
> +}
> +
> +static int h616_pwm_get_state(struct pwm_chip *chip,
> +			      struct pwm_device *pwm,
> +			      struct pwm_state *state)
> +{
> +	struct h616_pwm_chip *h616chip = to_h616_pwm_chip(chip);
> +	struct h616_pwm_channel *chan = &h616chip->channels[pwm->hwpwm];
> +	u64 clk_rate, tmp;
> +	u32 val;
> +
> +	clk_rate = clk_get_rate(chan->pwm_clk);
> +	if (!clk_rate)
> +		return -EINVAL;
> +
> +	val = h616_pwm_readl(h616chip, PWM_ENR);
> +	state->enabled = !!(PWM_ENABLE(pwm->hwpwm) & val);
> +
> +	val = h616_pwm_readl(h616chip, PWM_XY_CLK_CR(PWM_PAIR_IDX(pwm->hwpwm)));
> +	if (val & BIT(PWM_XY_CLK_CR_BYPASS_BIT(pwm->hwpwm))) {
> +		/*
> +		 * When bypass is enabled, the PWM logic is inactive.
> +		 * The PWM_clock_src_xy is directly routed to PWM_clock_x
> +		 */
> +		state->period = DIV_ROUND_UP_ULL(NSEC_PER_SEC, clk_rate);
> +		state->duty_cycle = DIV_ROUND_UP_ULL(state->period, 2);
> +		state->polarity = PWM_POLARITY_NORMAL;
> +		return 0;
> +	}
> +
> +	state->enabled &= !!(BIT(PWM_XY_CLK_CR_GATE_BIT) & val);
> +
> +	val = h616_pwm_readl(h616chip, PWM_CTRL_REG(pwm->hwpwm));
> +	if (val & PWM_CTRL_ACTIVE_STATE)
> +		state->polarity = PWM_POLARITY_NORMAL;
> +	else
> +		state->polarity = PWM_POLARITY_INVERSED;
> +
> +	val = h616_pwm_readl(h616chip, PWM_PERIOD_REG(pwm->hwpwm));
> +
> +	tmp = NSEC_PER_SEC * PWM_REG_DUTY(val);
> +	state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate);
> +
> +	tmp = NSEC_PER_SEC * PWM_REG_PERIOD(val);
> +	state->period = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate);

This needs to use uprounding. Ideally enabling CONFIG_PWM_DEBUG and
extensive testing should catch that error.

> +
> +	return 0;
> +}
> +
> +static int h616_pwm_calc(struct pwm_chip *chip, unsigned int idx,
> +			 const struct pwm_state *state)
> +{
> +	struct h616_pwm_chip *h616chip = to_h616_pwm_chip(chip);
> +	struct h616_pwm_channel *chan = &h616chip->channels[idx];
> +	unsigned int cnt, duty_cnt;
> +	unsigned long max_rate;
> +	long calc_rate;
> +	u64 duty, period, freq;
> +
> +	duty = state->duty_cycle;
> +	period = state->period;
> +
> +	max_rate = clk_round_rate(chan->pwm_clk, UINT32_MAX);

Huh, is this an artificial limitation? Do you rely on how clk_round_rate
picks the return value? (I.e. nearest value? nearest time? round up?
round down?)

> +	dev_dbg(pwmchip_parent(chip), "max_rate: %ld Hz\n", max_rate);
> +
> +	if ((period * max_rate >= NSEC_PER_SEC) &&

If period is big, this overflows.

> +	    (period * max_rate < 2 * NSEC_PER_SEC) &&
> +	    (duty * max_rate * 2 >= NSEC_PER_SEC)) {
> +		/*
> +		 * If the requested period is to small to be generated by the
> +		 * PWM, we can just select the highest clock and bypass the
> +		 * PWM logic
> +		 */
> +		dev_dbg(pwmchip_parent(chip), "Setting bypass (period=%lld)\n",
> +			period);
> +		freq = div64_u64(NSEC_PER_SEC, period);
> +		chan->bypass = true;
> +		duty = period / 2;

You must not round up duty. So if a small period and duty_cycle <
period/2 is requested, you have to return an error value. (Note that
with waveforms the semantic is a bit different.)

> +	} else {
> +		chan->bypass = false;
> +		freq = div64_u64(NSEC_PER_SEC * (u64)PWM_PERIOD_MAX, period);
> +		if (freq > UINT32_MAX)
> +			freq = UINT32_MAX;
> +	}
> +
> +	calc_rate = clk_round_rate(chan->pwm_clk, freq);
> +	if (calc_rate <= 0) {
> +		dev_err(pwmchip_parent(chip),
> +			"Invalid source clock frequency %llu\n", freq);
> +		return calc_rate ? calc_rate : -EINVAL;
> +	}
> +
> +	dev_dbg(pwmchip_parent(chip), "calc_rate: %ld Hz\n", calc_rate);
> +
> +	cnt = mul_u64_u64_div_u64(calc_rate, period, NSEC_PER_SEC);

Please use a better name here, something like period_ticks would be
good.

> +	if ((cnt == 0) || (cnt > PWM_PERIOD_MAX)) {
> +		dev_err(pwmchip_parent(chip), "Period out of range\n");
> +		return -EINVAL;
> +	}

If the requested value is too big, clamp it to the maximal possible
value.

> +	duty_cnt = mul_u64_u64_div_u64(calc_rate, duty, NSEC_PER_SEC);
> +
> +	if (duty_cnt >= cnt)
> +		duty_cnt = cnt - 1;

Does that mean the PWM cannot produce a 100% relative duty cycle?

> +	dev_dbg(pwmchip_parent(chip), "period=%llu cnt=%u duty=%llu duty_cnt=%u\n",
> +		period, cnt, duty, duty_cnt);

This is little helpful without the input parameters.

> +	chan->active_cycles = duty_cnt;
> +	chan->entire_cycles = cnt;
> +
> +	chan->rate = calc_rate;
> +
> +	return 0;
> +}
> +
> +static int h616_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
> +			  const struct pwm_state *state)
> +{

Please consider implementing .round_waveform_tohw(),
.round_waveform_fromhw(), .read_waveform() and .write_waveform() instead
of .apply() and .get_state().

> +	struct h616_pwm_chip *h616chip = to_h616_pwm_chip(chip);
> +	struct h616_pwm_channel *chan = &h616chip->channels[pwm->hwpwm];
> +	struct pwm_state cstate;
> +	unsigned long flags;
> +	u32 val;
> +	int ret;
> +
> +	ret = h616_pwm_calc(chip, pwm->hwpwm, state);
> +	if (ret) {
> +		dev_err(pwmchip_parent(chip), "period exceeds the maximum value\n");
> +		return ret;
> +	}
> +
> +	pwm_get_state(pwm, &cstate);

Don't call PWM API functions. (h616_pwm_apply() is called by
pwm_apply_{might_sleep,atomic} which grabs the chip lock. That
pwm_get_state() doesn't is an implementation detail that you should not
rely on.) I would prefer that you don't access pwm->state at all but
determine the state by looking at the registers.

> +	ret = clk_set_rate(chan->pwm_clk, chan->rate);
> +	if (ret) {
> +		dev_err(pwmchip_parent(chip), "failed to set PWM %d clock rate to %lu\n",
> +			pwm->hwpwm, chan->rate);
> +		return ret;
> +	}
> +
> +	h616_pwm_set_bypass(h616chip, pwm->hwpwm, chan->bypass);
> +
> +	/*
> +	 * If bypass is set, the PWM logic (polarity, duty) can't be applied
> +	 */
> +
> +	if (chan->bypass && (state->polarity == PWM_POLARITY_INVERSED)) {
> +		dev_warn(pwmchip_parent(chip),
> +			 "Can't set inversed polarity with bypass enabled\n");
> +	} else {
> +		val = h616_pwm_readl(h616chip, PWM_CTRL_REG(pwm->hwpwm));
> +		val &= ~PWM_CTRL_ACTIVE_STATE;
> +		if (state->polarity == PWM_POLARITY_NORMAL)
> +			val |= PWM_CTRL_ACTIVE_STATE;
> +		h616_pwm_writel(h616chip, val, PWM_CTRL_REG(pwm->hwpwm));
> +	}
> +
> +	if (chan->bypass && (state->duty_cycle * 2 != state->period)) {
> +		dev_warn(pwmchip_parent(chip),
> +			 "Can't set a duty cycle with bypass enabled\n");
> +	}

Please no output in runtime callbacks. (And even then

	state->period / 2 != state->duty_cycle

would probaly be the nicer check as it also works for uneven periods.)

> +
> +	if (!chan->bypass) {
> +		val = PWM_DUTY(chan->active_cycles);
> +		val |= PWM_PERIOD(chan->entire_cycles);
> +		h616_pwm_writel(h616chip, val, PWM_PERIOD_REG(pwm->hwpwm));
> +	}
> +
> +	if (state->enabled == cstate.enabled)
> +		return 0;
> +
> +	if (cstate.enabled) {
> +		unsigned long delay_us;
> +
> +		/*
> +		 * We need a full period to elapse before
> +		 * disabling the channel.

You need a full period between what and disabling? Assuming this is
about period and duty setting: Why not skip it if you disable?

> +		 */
> +		delay_us = DIV_ROUND_UP_ULL(cstate.period, NSEC_PER_USEC);
> +		fsleep(delay_us);

Huu, sleeping while holding a spin_lock and having disabled irqs :-\

> +	}
> +
> +	spin_lock_irqsave(&h616chip->clk_pdata->lock, flags);
> +
> +	val = h616_pwm_readl(h616chip, PWM_ENR);
> +	if (state->enabled)
> +		val |= PWM_ENABLE(pwm->hwpwm);
> +	else
> +		val &= ~PWM_ENABLE(pwm->hwpwm);
> +	h616_pwm_writel(h616chip, val, PWM_ENR);
> +
> +	spin_unlock_irqrestore(&h616chip->clk_pdata->lock, flags);
> +
> +	return 0;
> +}
> +
> +static const struct pwm_ops h616_pwm_ops = {
> +	.apply = h616_pwm_apply,
> +	.get_state = h616_pwm_get_state,
> +	.request = h616_pwm_request,
> +	.free = h616_pwm_free,
> +};
> +
> +static struct clk_hw *h616_pwm_of_clk_get(struct of_phandle_args *clkspec,
> +					  void *data)
> +{
> +	struct h616_pwm_chip *h616chip = data;
> +	struct clk_hw_onecell_data *hw_data = h616chip->clk_pdata->hw_data;
> +	unsigned int idx = clkspec->args[0];
> +	struct h616_pwm_channel *chan;
> +	struct clk_hw *ret_clk = NULL;
> +	unsigned long flags;
> +
> +	if (idx >= h616chip->data->npwm)
> +		return ERR_PTR(-EINVAL);
> +
> +	chan = &h616chip->channels[idx];
> +
> +	spin_lock_irqsave(&h616chip->clk_pdata->lock, flags);
> +
> +	if (chan->mode == H616_PWM_MODE_PWM) {
> +		ret_clk = ERR_PTR(-EBUSY);
> +	} else {
> +		chan->mode = H616_PWM_MODE_CLK;
> +		ret_clk = hw_data->hws[CLK_BYPASS(h616chip, idx)];
> +	}
> +	spin_unlock_irqrestore(&h616chip->clk_pdata->lock, flags);
> +
> +	if (IS_ERR(ret_clk))
> +		goto out;
> +
> +	chan->bypass = true;
> +	h616_pwm_set_bypass(h616chip, idx, chan->bypass);
> +out:
> +	return ret_clk;
> +}
> +
> +static int h616_add_composite_clk(struct clk_pwm_data *data,
> +				  void __iomem *reg, spinlock_t *lock,
> +				  struct device *dev, struct clk_hw **hw)
> +{
> +	const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, *rate_ops = NULL;
> +	struct clk_hw *mux_hw = NULL, *gate_hw = NULL, *rate_hw = NULL;
> +	struct device_node *node = dev->of_node;
> +
> +	if (data->mux_hw) {
> +		struct clk_mux *mux;
> +
> +		mux_hw = data->mux_hw;
> +		mux = to_clk_mux(mux_hw);
> +		mux->lock = lock;
> +		mux_ops = mux_hw->init->ops;
> +		mux->reg = (u64)mux->reg + reg;
> +	}
> +
> +	if (data->gate_hw) {
> +		struct clk_gate *gate;
> +
> +		gate_hw = data->gate_hw;
> +		gate = to_clk_gate(gate_hw);
> +		gate->lock = lock;
> +		gate_ops = gate_hw->init->ops;
> +		gate->reg = (u64)gate->reg + reg;
> +	}
> +
> +	if (data->rate_hw) {
> +		struct clk_divider *rate;
> +
> +		rate_hw = data->rate_hw;
> +		rate = to_clk_divider(rate_hw);
> +		rate_ops = rate_hw->init->ops;
> +		rate->lock = lock;
> +		rate->reg = (u64)rate->reg + reg;
> +
> +		if (rate->table) {
> +			const struct clk_div_table *clkt;
> +			int table_size = 0;
> +
> +			for (clkt = rate->table; clkt->div; clkt++)
> +				table_size++;
> +			rate->width = order_base_2(table_size);
> +		}
> +	}
> +
> +	/*
> +	 * Retrieve the parent clock names from DTS for pwm-clk-srcxy
> +	 */
> +	if (!data->parent_names) {
> +		data->num_parents = of_clk_get_parent_count(node);
> +		if (data->num_parents == 0)
> +			return -ENOENT;
> +
> +		data->parent_names = devm_kzalloc(dev,
> +						  sizeof(*data->parent_names),
> +						  GFP_KERNEL);
> +		for (unsigned int i = 0; i < data->num_parents; i++)
> +			data->parent_names[i] = of_clk_get_parent_name(node, i);
> +	}
> +
> +	*hw = clk_hw_register_composite(dev, data->name, data->parent_names,
> +					data->num_parents, mux_hw,
> +					mux_ops, rate_hw, rate_ops,
> +					gate_hw, gate_ops, data->flags);
> +
> +	return PTR_ERR_OR_ZERO(*hw);
> +}
> +
> +static int h616_pwm_init_clocks(struct platform_device *pdev,
> +				struct h616_pwm_chip *h616chip)
> +{
> +	struct clk_pwm_pdata *pdata;
> +	struct device *dev = &pdev->dev;
> +	int num_clocks = 0;
> +	int ret;
> +
> +	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
> +	if (!pdata)
> +		return -ENOMEM;
> +
> +	while (pwmcc_data[num_clocks].name)
> +		num_clocks++;
> +
> +	pdata->hw_data = devm_kzalloc(dev, struct_size(pdata->hw_data, hws, num_clocks),
> +				      GFP_KERNEL);
> +	if (!pdata->hw_data)
> +		return -ENOMEM;
> +
> +	pdata->hw_data->num = num_clocks;
> +	pdata->reg = h616chip->base;
> +
> +	spin_lock_init(&pdata->lock);
> +
> +	for (int i = 0; i < num_clocks; i++) {
> +		struct clk_hw **hw = &pdata->hw_data->hws[i];
> +
> +		ret = h616_add_composite_clk(&pwmcc_data[i], pdata->reg,
> +					     &pdata->lock, dev, hw);
> +		if (ret) {
> +			dev_err_probe(dev, ret,
> +				      "Failed to register hw clock %s\n",
> +				      pwmcc_data[i].name);
> +			for (i--; i >= 0; i--)
> +				clk_hw_unregister_composite(pdata->hw_data->hws[i]);
> +			return ret;
> +		}
> +	}
> +
> +	h616chip->clk_pdata = pdata;
> +
> +	return 0;
> +}
> +
> +static int h616_pwm_probe(struct platform_device *pdev)
> +{
> +	const struct h616_pwm_data *data;
> +	struct device *dev = &pdev->dev;
> +	struct h616_pwm_chip *h616chip;
> +	struct pwm_chip *chip;
> +	int ret;
> +
> +	data = of_device_get_match_data(dev);
> +	if (!data)
> +		return -ENODEV;

error message please. (Or at least a comment that this cannot happen.)

> +
> +	chip = devm_pwmchip_alloc(dev, data->npwm, sizeof(*h616chip));
> +	if (IS_ERR(chip))
> +		return dev_err_probe(dev, PTR_ERR(chip),
> +				     "Failed to allocate pwmchip\n");
> +
> +	h616chip = to_h616_pwm_chip(chip);
> +	h616chip->data = data;
> +	h616chip->base = devm_platform_ioremap_resource(pdev, 0);
> +	if (IS_ERR(h616chip->base))
> +		return dev_err_probe(dev, PTR_ERR(h616chip->base),
> +				     "Failed to get PWM base address\n");
> +
> +	h616chip->bus_clk = devm_clk_get_enabled(dev, "bus");
> +	if (IS_ERR(h616chip->bus_clk))
> +		return dev_err_probe(dev, PTR_ERR(h616chip->bus_clk),
> +				     "Failed to get bus clock\n");
> +
> +	h616chip->channels = devm_kmalloc_array(dev, data->npwm,
> +						sizeof(*(h616chip->channels)),
> +						GFP_KERNEL);

There is a big amount of allocations here. Would be great to have this
reduced to save some memory management overhead and get some cache
locality in return.

> +	if (!h616chip->channels)
> +		return dev_err_probe(dev, -ENOMEM,
> +				     "Failed to allocate %d channels array\n",
> +				     data->npwm);
> +
> +	h616chip->rst = devm_reset_control_get_shared(dev, NULL);
> +	if (IS_ERR(h616chip->rst))
> +		return dev_err_probe(dev, PTR_ERR(h616chip->rst),
> +				     "Failed to get reset control\n");
> +
> +	chip->ops = &h616_pwm_ops;
> +
> +	ret = h616_pwm_init_clocks(pdev, h616chip);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "Failed to initialize clocks\n");

h616_pwm_init_clocks() already emits error messages.

> +	for (unsigned int i = 0; i < data->npwm; i++) {

Huh, AFAIK we're not using declarations in for loops in the kernel.

> +		struct h616_pwm_channel *chan = &h616chip->channels[i];
> +		struct clk_hw **hw = &h616chip->clk_pdata->hw_data->hws[i];
> +
> +		chan->pwm_clk = devm_clk_hw_get_clk(dev, *hw, NULL);
> +		if (IS_ERR(chan->pwm_clk)) {
> +			ret = dev_err_probe(dev, PTR_ERR(chan->pwm_clk),
> +					    "Failed to register PWM clock %d\n", i);
> +			goto err_get_clk;
> +		}
> +		chan->mode = H616_PWM_MODE_NONE;
> +	}
> +
> +	ret = devm_of_clk_add_hw_provider(dev, h616_pwm_of_clk_get, h616chip);
> +	if (ret) {
> +		dev_err_probe(dev, ret, "Failed to add HW clock provider\n");
> +		goto err_add_clk_provider;
> +	}
> +
> +	/* Deassert reset */
> +	ret = reset_control_deassert(h616chip->rst);
> +	if (ret) {
> +		dev_err_probe(dev, ret, "Cannot deassert reset control\n");
> +		goto err_ctrl_deassert;
> +	}
> +
> +	ret = pwmchip_add(chip);
> +	if (ret < 0) {
> +		dev_err_probe(dev, ret, "Failed to add PWM chip\n");
> +		goto err_pwm_add;
> +	}
> +
> +	platform_set_drvdata(pdev, chip);

this is unused.

> +	return 0;
> +
> +err_pwm_add:
> +	reset_control_assert(h616chip->rst);
> +
> +err_ctrl_deassert:
> +err_add_clk_provider:
> +err_get_clk:
> +	for (int i = 0; i < h616chip->clk_pdata->hw_data->num; i++)
> +		clk_hw_unregister_composite(h616chip->clk_pdata->hw_data->hws[i]);
> +
> +	return ret;
> +}

You need to implement a .remove() callback to not leak resources (or use
devm functions).

> +
> +static const struct h616_pwm_data sun50i_h616_pwm_data = {
> +	.npwm = 6,
> +};
> +
> +static const struct of_device_id h616_pwm_dt_ids[] = {
> +	{
> +		.compatible = "allwinner,sun50i-h616-pwm",
> +		.data = &sun50i_h616_pwm_data,
> +	}, {
> +		/* sentinel */
> +	},

no , here.

> +};
> +MODULE_DEVICE_TABLE(of, h616_pwm_dt_ids);
> +
> +

A single empty line is enough here.

> +static struct platform_driver h616_pwm_driver = {
> +	.driver = {
> +		.name = "h616-pwm",
> +		.of_match_table = h616_pwm_dt_ids,
> +	},
> +	.probe = h616_pwm_probe,
> +};
> +module_platform_driver(h616_pwm_driver);
> +
> +MODULE_AUTHOR("Richard Genoud <richard.genoud at bootlin.com>");
> +MODULE_DESCRIPTION("Allwinner H616 PWM driver");
> +MODULE_LICENSE("GPL");

Best regards
Uwe
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/b443ccd3/attachment-0001.sig>

From u.kleine-koenig at baylibre.com  Wed Dec 24 01:58:40 2025
From: u.kleine-koenig at baylibre.com (Uwe =?utf-8?Q?Kleine-K=C3=B6nig?=)
Date: Wed, 24 Dec 2025 10:58:40 +0100
Subject: [PATCH v2 0/4] Introduce Allwinner H616 PWM controller
In-Reply-To: <160e221e-98a8-4097-8340-94ac7d208136@bootlin.com>
References: <20251217082504.80226-1-richard.genoud@bootlin.com>
 <6113404.MhkbZ0Pkbq@jernej-laptop>
 <160e221e-98a8-4097-8340-94ac7d208136@bootlin.com>
Message-ID: <5ih4qxr7572x6fakxjsx2vrxnt3yey2dtvdyaiwyuvulivh3ef@hebpjfdginev>

Hello Richard,

On Mon, Dec 22, 2025 at 10:17:07AM +0100, Richard GENOUD wrote:
> Le 21/12/2025 ? 20:12, Jernej ?krabec a ?crit?:
> [...]
> 
> That's why I put aside the pwm-clock and I went for this instead.

I havn't tried to understand the issue in detail, but would it help to
use assigned-clocks to make pwm-clk suitable? Assuming this allows to
drop all the clk stuff from the driver that would we very appreciated.

Best regards
Uwe
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/89b163b7/attachment.sig>

From qiang.yu at oss.qualcomm.com  Wed Dec 24 02:10:46 2025
From: qiang.yu at oss.qualcomm.com (Qiang Yu)
Date: Wed, 24 Dec 2025 02:10:46 -0800
Subject: [PATCH] PCI: dwc: Remove duplicate
 dw_pcie_ep_hide_ext_capability() function
Message-ID: <20251224-remove_dw_pcie_ep_hide_ext_capability-v1-1-4302c9cdc316@oss.qualcomm.com>

Remove dw_pcie_ep_hide_ext_capability() and replace its usage with
dw_pcie_remove_ext_capability(). Both functions serve the same purpose
of hiding PCIe extended capabilities, but dw_pcie_remove_ext_capability()
provides a cleaner API that doesn't require the caller to specify the
previous capability ID.

Compile-tested only. Runtime testing on RK3588 hardware would be
appreciated.

Suggested-by: Niklas Cassel <cassel at kernel.org>
Signed-off-by: Qiang Yu <qiang.yu at oss.qualcomm.com>
---
 drivers/pci/controller/dwc/pcie-designware-ep.c | 39 -------------------------
 drivers/pci/controller/dwc/pcie-designware.h    |  7 -----
 drivers/pci/controller/dwc/pcie-dw-rockchip.c   |  4 +--
 3 files changed, 1 insertion(+), 49 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index 1195d401df19eafbab2fb267f5cda3c24ecdfbd1..cfd59899c7b85fd0dddc9c6ce6b9c9fed84ad7a3 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -75,45 +75,6 @@ static u8 dw_pcie_ep_find_capability(struct dw_pcie_ep *ep, u8 func_no, u8 cap)
 				 cap, NULL, ep, func_no);
 }
 
-/**
- * dw_pcie_ep_hide_ext_capability - Hide a capability from the linked list
- * @pci: DWC PCI device
- * @prev_cap: Capability preceding the capability that should be hidden
- * @cap: Capability that should be hidden
- *
- * Return: 0 if success, errno otherwise.
- */
-int dw_pcie_ep_hide_ext_capability(struct dw_pcie *pci, u8 prev_cap, u8 cap)
-{
-	u16 prev_cap_offset, cap_offset;
-	u32 prev_cap_header, cap_header;
-
-	prev_cap_offset = dw_pcie_find_ext_capability(pci, prev_cap);
-	if (!prev_cap_offset)
-		return -EINVAL;
-
-	prev_cap_header = dw_pcie_readl_dbi(pci, prev_cap_offset);
-	cap_offset = PCI_EXT_CAP_NEXT(prev_cap_header);
-	cap_header = dw_pcie_readl_dbi(pci, cap_offset);
-
-	/* cap must immediately follow prev_cap. */
-	if (PCI_EXT_CAP_ID(cap_header) != cap)
-		return -EINVAL;
-
-	/* Clear next ptr. */
-	prev_cap_header &= ~GENMASK(31, 20);
-
-	/* Set next ptr to next ptr of cap. */
-	prev_cap_header |= cap_header & GENMASK(31, 20);
-
-	dw_pcie_dbi_ro_wr_en(pci);
-	dw_pcie_writel_dbi(pci, prev_cap_offset, prev_cap_header);
-	dw_pcie_dbi_ro_wr_dis(pci);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(dw_pcie_ep_hide_ext_capability);
-
 static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
 				   struct pci_epf_header *hdr)
 {
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 3a81d46e60b00f7cb92d9634eba6708244bce976..c5fff03073ea3945a5c38b1626838c6a67d21c57 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -909,7 +909,6 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
 int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, u8 func_no,
 				       u16 interrupt_num);
 void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar);
-int dw_pcie_ep_hide_ext_capability(struct dw_pcie *pci, u8 prev_cap, u8 cap);
 struct dw_pcie_ep_func *
 dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no);
 #else
@@ -967,12 +966,6 @@ static inline void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
 {
 }
 
-static inline int dw_pcie_ep_hide_ext_capability(struct dw_pcie *pci,
-						 u8 prev_cap, u8 cap)
-{
-	return 0;
-}
-
 static inline struct dw_pcie_ep_func *
 dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no)
 {
diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
index 352f513ebf0363ff0ec79fdd8d8b245eeb28474c..77c4e6a4ddead91fe12eb6c727e77350207ef5fa 100644
--- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c
+++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
@@ -347,9 +347,7 @@ static void rockchip_pcie_ep_hide_broken_ats_cap_rk3588(struct dw_pcie_ep *ep)
 	if (!of_device_is_compatible(dev->of_node, "rockchip,rk3588-pcie-ep"))
 		return;
 
-	if (dw_pcie_ep_hide_ext_capability(pci, PCI_EXT_CAP_ID_SECPCI,
-					   PCI_EXT_CAP_ID_ATS))
-		dev_err(dev, "failed to hide ATS capability\n");
+	dw_pcie_remove_ext_capability(pci, PCI_EXT_CAP_ID_ATS);
 }
 
 static void rockchip_pcie_ep_init(struct dw_pcie_ep *ep)

---
base-commit: 37781eb814e16c75abb78dec2f9412d2e4d88298
change-id: 20251224-remove_dw_pcie_ep_hide_ext_capability-3dba1507a331

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



From krzk at kernel.org  Wed Dec 24 02:21:08 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 24 Dec 2025 11:21:08 +0100
Subject: [PATCH v3 01/15] include: dt-bindings: add LAN969x clock bindings
In-Reply-To: <20251223201921.1332786-2-robert.marko@sartura.hr>
References: <20251223201921.1332786-1-robert.marko@sartura.hr>
 <20251223201921.1332786-2-robert.marko@sartura.hr>
Message-ID: <20251224-berserk-mackerel-of-snow-4cae54@quoll>

On Tue, Dec 23, 2025 at 09:16:12PM +0100, Robert Marko wrote:
> Add the required LAN969x clock bindings.

I do not see clock bindings actually here. Where is the actual binding?
Commit msg does not help me at all to understand why you are doing this
without actual required bindings.

Please use subject prefixes matching the subsystem. You can get them for
example with 'git log --oneline -- DIRECTORY_OR_FILE' on the directory
your patch is touching. For bindings, the preferred subjects are
explained here:
https://www.kernel.org/doc/html/latest/devicetree/bindings/submitting-patches.html#i-for-patch-submitters
Bindings never have a "include" prefix.

A nit, subject: drop second/last, redundant "bindings". The
"dt-bindings" prefix is already stating that these are bindings.
See also:
https://elixir.bootlin.com/linux/v6.17-rc3/source/Documentation/devicetree/bindings/submitting-patches.rst#L18

Best regards,
Krzysztof



From robert.marko at sartura.hr  Wed Dec 24 02:30:14 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Wed, 24 Dec 2025 11:30:14 +0100
Subject: [PATCH v3 01/15] include: dt-bindings: add LAN969x clock bindings
In-Reply-To: <20251224-berserk-mackerel-of-snow-4cae54@quoll>
References: <20251223201921.1332786-1-robert.marko@sartura.hr>
 <20251223201921.1332786-2-robert.marko@sartura.hr> <20251224-berserk-mackerel-of-snow-4cae54@quoll>
Message-ID: <CA+HBbNGym6Q9b166n-P=h_JssOHm0yfyL73JZ+G9P81muK=g4A@mail.gmail.com>

On Wed, Dec 24, 2025 at 11:21?AM Krzysztof Kozlowski <krzk at kernel.org> wrote:
>
> On Tue, Dec 23, 2025 at 09:16:12PM +0100, Robert Marko wrote:
> > Add the required LAN969x clock bindings.
>
> I do not see clock bindings actually here. Where is the actual binding?
> Commit msg does not help me at all to understand why you are doing this
> without actual required bindings.

I guess it is a bit confusing, there is no schema here, these are the
clock indexes that
reside in dt-bindings and are used by the SoC DTSI.

I guess I should have titled this something like:
dt-bindings: clock: lan969x: add binding includes for LAN969x clock IDs

Regards,
Robert

>
> Please use subject prefixes matching the subsystem. You can get them for
> example with 'git log --oneline -- DIRECTORY_OR_FILE' on the directory
> your patch is touching. For bindings, the preferred subjects are
> explained here:
> https://www.kernel.org/doc/html/latest/devicetree/bindings/submitting-patches.html#i-for-patch-submitters
> Bindings never have a "include" prefix.
>
> A nit, subject: drop second/last, redundant "bindings". The
> "dt-bindings" prefix is already stating that these are bindings.
> See also:
> https://elixir.bootlin.com/linux/v6.17-rc3/source/Documentation/devicetree/bindings/submitting-patches.rst#L18
>
> Best regards,
> Krzysztof
>


-- 
Robert Marko
Staff Embedded Linux Engineer
Sartura d.d.
Lendavska ulica 16a
10000 Zagreb, Croatia
Email: robert.marko at sartura.hr
Web: www.sartura.hr


From arnd at arndb.de  Wed Dec 24 02:39:26 2025
From: arnd at arndb.de (Arnd Bergmann)
Date: Wed, 24 Dec 2025 11:39:26 +0100
Subject: [PATCH 3/4] ARM: remove support for highmem on VIVT
In-Reply-To: <aUtPRFdbpSQ20eOx@nvidia.com>
References: <20251219161559.556737-1-arnd@kernel.org>
 <20251219161559.556737-4-arnd@kernel.org>
 <20251219171412.GG254720@nvidia.com>
 <513078d3-976a-4e6d-b311-dcfcfea99238@app.fastmail.com>
 <aUtPRFdbpSQ20eOx@nvidia.com>
Message-ID: <f6c49549-57af-4640-a09e-896c47bb8657@app.fastmail.com>

On Wed, Dec 24, 2025, at 03:26, Jason Gunthorpe wrote:
> On Fri, Dec 19, 2025 at 09:34:33PM +0100, Arnd Bergmann wrote:
>> On Fri, Dec 19, 2025, at 18:14, Jason Gunthorpe wrote:
>> >
>> > This looks great, but do you think there should be a boot time crash
>> > if a VIVT and HIGHMEM are enabled, just incase?
>> 
>> Do you mean in the common code or just for Arm?
>> 
>> We could use the Arm specific cache_is_vivt() macro, but it feels like
>> the 'dpends on !CPU_CACHE_VIVT' Kconfig check I added is both
>> safer and simpler.
>
> Okay, so maybe I'm asking if !CPU_CACHE_VIVT then the kernel fails to
> boot on vivt systems, maybe it already does?
>

Yes, in two separate ways:

- you can build a kernel for any combination of armv4/v4t/v5 CPUs
  (all VIVT), or any combination of armv6/v6k/v7/v7ve/v8 CPUs
  (all VIPT or PIPT), but we already enforce that you cannot mix
  the two in any way. The two sets are sufficiently different in
  terms of instruction set, MMU cache and FPU that trying to boot
  the wrong one probably doesn't even get to the point of printing
  any output.

- If something changed about the assumption above, any Arm kernel
  still needs to enable support for each individual CPU model that
  you may want to boot on. Enabling a SoC family will select the
  CPUs used in that SoC, and enabling a CPU type selects
  the cache features like CPU_CACHE_VIVT. Attempting to boot
  on a CPU model that is not enabled in the kernel build makes
  it fail in setup_arch() with:

                pr_err("CPU%u: configuration botched (ID %08x), CPU halted\n",
                       smp_processor_id(), midr);
                while (1)
                        ;

     Arnd


From weibu at redadmin.org  Wed Dec 24 00:38:45 2025
From: weibu at redadmin.org (Akiyoshi Kurita)
Date: Wed, 24 Dec 2025 17:38:45 +0900
Subject: [PATCH] docs: dt-bindings: hwmon: aspeed-pwm-tacho: fix typos
Message-ID: <20251224083845.2727976-1-weibu@redadmin.org>

Fix "upto" -> "up to" occurrences and add missing "be" in one sentence.

Signed-off-by: Akiyoshi Kurita <weibu at redadmin.org>
---
 .../devicetree/bindings/hwmon/aspeed-pwm-tacho.txt        | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt b/Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt
index 8645cd3b867a..d1db4adb2df7 100644
--- a/Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt
+++ b/Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt
@@ -1,9 +1,9 @@
 ASPEED AST2400/AST2500 PWM and Fan Tacho controller device driver
 
-The ASPEED PWM controller can support upto 8 PWM outputs. The ASPEED Fan Tacho
-controller can support upto 16 Fan tachometer inputs.
+The ASPEED PWM controller can support up to 8 PWM outputs. The ASPEED Fan Tacho
+controller can support up to 16 Fan tachometer inputs.
 
-There can be upto 8 fans supported. Each fan can have one PWM output and
+There can be up to 8 fans supported. Each fan can have one PWM output and
 one/two Fan tach inputs.
 
 Required properties for pwm-tacho node:
@@ -28,7 +28,7 @@ Required properties for pwm-tacho node:
 
 fan subnode format:
 ===================
-Under fan subnode there can upto 8 child nodes, with each child node
+Under fan subnode there can be up to 8 child nodes, with each child node
 representing a fan. If there are 8 fans each fan can have one PWM port and
 one/two Fan tach inputs.
 For PWM port can be configured cooling-levels to create cooling device.
-- 
2.47.3



From baolin.wang at linux.alibaba.com  Wed Dec 24 02:54:07 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Wed, 24 Dec 2025 18:54:07 +0800
Subject: [PATCH] arm64: mm: fix passing the incorrect 'CONT_PTES' for non-batched APIs
In-Reply-To: <3b427d9010a6d52f2b91342760f12be097d21cf6.1766455378.git.baolin.wang@linux.alibaba.com>
References: <3b427d9010a6d52f2b91342760f12be097d21cf6.1766455378.git.baolin.wang@linux.alibaba.com>
Message-ID: <38f3d9fbd486bdd75874a833a24a8c704b6b5a95.1766573044.git.baolin.wang@linux.alibaba.com>

Since contpte_test_and_clear_young_ptes() and contpte_clear_flush_young_ptes
have  already performed CONT_PTE_SIZE alignment and will clear the young flag
for the entire cont block, Their non-batched callers do not need to pass in
'CONT_PTES' to specify the cont block range. Otherwise, it may exceed the
range of a single cont block for the non-batched cases.

Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
---
Hi Andrew,

As I conducted more tests, I found that the ptep_test_and_clear_young() operation
may clear the young flag beyond a single cont block range, causing issues.
Please fold this fixup into this patch to solve this issue. Thanks.
---
 arch/arm64/include/asm/pgtable.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index d5fbe72e820a..5e9ff16146c3 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -1823,7 +1823,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
 	if (likely(!pte_valid_cont(orig_pte)))
 		return __ptep_test_and_clear_young(vma, addr, ptep);
 
-	return contpte_test_and_clear_young_ptes(vma, addr, ptep, CONT_PTES);
+	return contpte_test_and_clear_young_ptes(vma, addr, ptep, 1);
 }
 
 #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
@@ -1835,7 +1835,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
 	if (likely(!pte_valid_cont(orig_pte)))
 		return __ptep_clear_flush_young(vma, addr, ptep);
 
-	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
+	return contpte_clear_flush_young_ptes(vma, addr, ptep, 1);
 }
 
 #define wrprotect_ptes wrprotect_ptes
-- 
2.47.3



From xu.yang_2 at nxp.com  Wed Dec 24 03:06:50 2025
From: xu.yang_2 at nxp.com (Xu Yang)
Date: Wed, 24 Dec 2025 19:06:50 +0800
Subject: [PATCH] phy: fsl-imx8mq-usb: add debugfs to access control
 register
In-Reply-To: <aUqk3z8CSVldoO5V@vaman>
References: <20251219075447.3672833-1-xu.yang_2@nxp.com>
 <aUqk3z8CSVldoO5V@vaman>
Message-ID: <kvxt4hm3y5hsjiir2nnycr5kqgflswt2lra4b2akh5zju6ahqw@4w2xmkjgho22>

On Tue, Dec 23, 2025 at 07:49:11PM +0530, Vinod Koul wrote:
> On 19-12-25, 15:54, Xu Yang wrote:
> > The CR port is a simple 16-bit data/address parallel port that is
> > provided for on-chip access to the control registers inside the
> > USB 3.0 femtoPHY. While access to these registers is not required
> > for normal PHY operation, this interface enables you to access
> > some of the PHY?s diagnostic features during normal operation or
> > to override some basic PHY control signals.
> > 
> > 3 debugfs files are created to read and write control registers,
> > all use hexadecimal format:
> > ctrl_reg_base: the register offset to write, or the start offset
> >                to read.
> > ctrl_reg_count: how many continuous registers to be read.
> > ctrl_reg_value: read to show the continuous registers value from
> >                 the offset in ctrl_reg_base, to ctrl_reg_base
> >                 + ctrl_reg_count - 1, one line for one register.
> >                 when write, override the register at ctrl_reg_base,
> >                 one time can only change one 16bits register.
> > 
> > Signed-off-by: Li Jun <jun.li at nxp.com>
> > Signed-off-by: Xu Yang <xu.yang_2 at nxp.com>
> > ---
> >  drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 221 ++++++++++++++++++++-
> >  1 file changed, 220 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> > index ad8a55012e42..cb2392008ad2 100644
> > --- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> > +++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> > @@ -1,8 +1,9 @@
> >  // SPDX-License-Identifier: GPL-2.0+
> > -/* Copyright (c) 2017 NXP. */
> > +/* Copyright (c) 2017-2025 NXP. */
> >  
> >  #include <linux/bitfield.h>
> >  #include <linux/clk.h>
> > +#include <linux/debugfs.h>
> >  #include <linux/delay.h>
> >  #include <linux/io.h>
> >  #include <linux/module.h>
> > @@ -52,6 +53,21 @@
> >  
> >  #define PHY_TUNE_DEFAULT		0xffffffff
> >  
> > +/* PHY control register access */
> > +#define PHY_CTRL_REG_COUNT_MAX		0x42
> > +#define PHY_CTRL_REG_OFFSET_MAX		0x201f
> > +
> > +#define PHY_CRCTL			0x30
> > +#define PHY_CRCTL_DATA_IN_MASK		GENMASK(15, 0)
> > +#define PHY_CRCTL_CAP_ADDR		BIT(16)
> > +#define PHY_CRCTL_CAP_DATA		BIT(17)
> > +#define PHY_CRCTL_CR_WRITE		BIT(18)
> > +#define PHY_CRCTL_CR_READ		BIT(19)
> > +
> > +#define PHY_CRSR			0x34
> > +#define PHY_CRSR_DATA_OUT_MASK		GENMASK(15, 0)
> > +#define PHY_CRSR_CR_ACK			BIT(16)
> > +
> >  #define TCA_CLK_RST			0x00
> >  #define TCA_CLK_RST_SW			BIT(9)
> >  #define TCA_CLK_RST_REF_CLK_EN		BIT(1)
> > @@ -113,6 +129,9 @@ struct imx8mq_usb_phy {
> >  	void __iomem *base;
> >  	struct regulator *vbus;
> >  	struct tca_blk *tca;
> > +	struct dentry *debugfs;
> > +	u16 cr_access_base;
> > +	u16 cr_read_count;
> >  	u32 pcs_tx_swing_full;
> >  	u32 pcs_tx_deemph_3p5db;
> >  	u32 tx_vref_tune;
> > @@ -420,6 +439,204 @@ static u32 phy_pcs_tx_swing_full_from_property(u32 percent)
> >  	percent = min(percent, 100U);
> >  
> >  	return (percent * 127) / 100;
> > +};
> > +
> > +#define IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT 500000
> 
> empty line here, possibly move this to top of file

I'm going to remove it after I add a helper.

> 
> > +static int imx8mq_phy_ctrl_reg_addr(struct imx8mq_usb_phy *imx_phy, u16 offset)
> > +{
> > +	void __iomem	*cr_ctrl = imx_phy->base + PHY_CRCTL;
> > +	void __iomem	*cr_sr = imx_phy->base + PHY_CRSR;
> > +	struct device	*dev = &imx_phy->phy->dev;
> > +	int i;
> > +
> > +	/* Address Phrase */
> > +	writel(offset, cr_ctrl);
> > +	writel(readl(cr_ctrl) | PHY_CRCTL_CAP_ADDR, cr_ctrl);
> > +
> > +	/* Wait CRSR[16] == 1 */
> > +	i = IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT;
> > +	while (!(readl(cr_sr) & PHY_CRSR_CR_ACK) && i > 0)
> > +		i--;
> > +	if (i == 0)
> > +		goto cr_addr_err;
> > +
> > +	writel(readl(cr_ctrl) & (~PHY_CRCTL_CAP_ADDR), cr_ctrl);
> > +
> > +	/* Wait CRSR[16] == 0 */
> > +	i = IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT;
> > +	while ((readl(cr_sr) & PHY_CRSR_CR_ACK) && i > 0)
> > +		i--;
> > +	if (i == 0)
> > +		goto cr_addr_err;
> > +
> > +	return 0;
> > +
> > +cr_addr_err:
> > +	dev_err(dev, "Failed to address reg 0x%x.\n", offset);
> > +	return -EIO;
> > +}
> > +
> > +static int imx8mq_phy_ctrl_reg_read(struct imx8mq_usb_phy *imx_phy, u16 offset)
> > +{
> > +	void __iomem	*cr_ctrl = imx_phy->base + PHY_CRCTL;
> > +	void __iomem	*cr_sr = imx_phy->base + PHY_CRSR;
> > +	struct device	*dev = &imx_phy->phy->dev;
> > +	int val, i;
> > +
> > +	/* Address Phrase */
> > +	val = imx8mq_phy_ctrl_reg_addr(imx_phy, offset);
> > +	if (val)
> > +		return val;
> > +
> > +	/* Read Phrase */
> > +	writel(readl(cr_ctrl) | PHY_CRCTL_CR_READ, cr_ctrl);
> > +
> > +	/* Wait CRSR[16] == 1 */
> > +	i = IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT;
> > +	while (!(readl(cr_sr) & PHY_CRSR_CR_ACK) && i > 0)
> > +		i--;
> > +	if (i == 0)
> > +		goto cr_read_err;
> > +
> > +	val = readl(cr_sr);
> > +	writel(val & ~PHY_CRCTL_CR_READ, cr_ctrl);
> > +
> > +	/* Wait CRSR[16] == 0 */
> > +	i = IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT;
> > +	while (!(readl(cr_sr) & PHY_CRSR_CR_ACK) && i > 0)
> > +		i--;
> > +	if (i == 0)
> > +		goto cr_read_err;
> > +
> > +	return val;
> > +
> > +cr_read_err:
> > +	dev_err(dev, "Failed to read reg 0x%x.\n", offset);
> > +	return -EIO;
> > +}
> > +
> > +static int imx8mq_phy_ctrl_reg_write(struct imx8mq_usb_phy *imx_phy,
> > +				     u16 offset, u16 val)
> > +{
> > +	void __iomem	*cr_ctrl = imx_phy->base + PHY_CRCTL;
> > +	void __iomem	*cr_sr = imx_phy->base + PHY_CRSR;
> > +	struct device	*dev = &imx_phy->phy->dev;
> > +	int i, ret;
> > +
> > +	/* Address Phrase */
> > +	ret = imx8mq_phy_ctrl_reg_addr(imx_phy, offset);
> > +	if (ret)
> > +		return ret;
> > +
> > +	writel(val, cr_ctrl);
> > +
> > +	/* Set cr_cap_data to be 1'b1 */
> > +	writel(readl(cr_ctrl) | PHY_CRCTL_CAP_DATA, cr_ctrl);
> > +	/* Wait CRSR[16] == 1 */
> > +	i = IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT;
> > +	while (!(readl(cr_sr) & PHY_CRSR_CR_ACK) && i > 0)
> > +		i--;
> > +	if (i == 0)
> > +		goto cr_write_err;
> 
> seems like a repeated pattern, maybe move to a helper. (if driver used
> regmap, it could have used helpers from regmap for this polling)

Yes, good suggestion! I'll add a helper for this.

> 
> > +
> > +	/* Clear cr_cap_data to be 1'br0 */
> > +	writel(readl(cr_ctrl) & ~PHY_CRCTL_CAP_DATA, cr_ctrl);
> > +	/* Wait CRSR[16] == 0 */
> > +	i = IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT;
> > +	while ((readl(cr_sr) & PHY_CRSR_CR_ACK) && i > 0)
> > +		i--;
> > +	if (i == 0)
> > +		goto cr_write_err;
> > +
> > +	/* Set cr_write to be 1'b1 */
> > +	writel(readl(cr_ctrl) | PHY_CRCTL_CR_WRITE, cr_ctrl);
> > +	/* Wait CRSR[16] == 1 */
> > +	i = IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT;
> > +	while (!(readl(cr_sr) & PHY_CRSR_CR_ACK) && i > 0)
> > +		i--;
> > +	if (i == 0)
> > +		goto cr_write_err;
> > +
> > +	/* Clear cr_write to be 1'br0 */
> > +	writel(readl(cr_ctrl) & ~PHY_CRCTL_CR_WRITE, cr_ctrl);
> > +	/* Wait CRSR[16] == 0 */
> > +	i = IMX8M_PHY_DEBUG_PORT_LOOP_TIMEOUT;
> > +	while ((readl(cr_sr) & PHY_CRSR_CR_ACK) && i > 0)
> > +		i--;
> > +	if (i == 0)
> > +		goto cr_write_err;
> > +
> > +	return 0;
> > +
> > +cr_write_err:
> > +	dev_err(dev, "Failed to write reg 0x%x.\n", offset);
> > +	return -EIO;
> > +}
> > +
> > +static int ctrl_reg_value_show(struct seq_file *s, void *unused)
> > +{
> > +	struct imx8mq_usb_phy *imx_phy = s->private;
> > +	u16 i, val, base = imx_phy->cr_access_base;
> > +
> > +	for (i = 0; i < imx_phy->cr_read_count; i++) {
> > +		val = imx8mq_phy_ctrl_reg_read(imx_phy, base + i);
> > +		seq_printf(s, "Control Register 0x%x value is 0x%4x\n",
> > +			   base + i, val);
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int ctrl_reg_value_open(struct inode *inode, struct file *file)
> > +{
> > +	return single_open(file, ctrl_reg_value_show, inode->i_private);
> > +}
> > +
> > +static ssize_t ctrl_reg_value_write(struct file *file, const char __user *ubuf,
> > +				    size_t count, loff_t *ppos)
> > +{
> > +	struct seq_file		*s = file->private_data;
> > +	struct imx8mq_usb_phy	*imx_phy = s->private;
> > +	u16			cr_value;
> > +	int			ret;
> > +
> > +	ret = kstrtou16_from_user(ubuf, count, 16, &cr_value);
> > +	if (ret)
> > +		return ret;
> > +
> > +	imx8mq_phy_ctrl_reg_write(imx_phy, imx_phy->cr_access_base, cr_value);
> > +
> > +	return count;
> > +}
> > +
> > +static const struct file_operations ctrl_reg_value_fops = {
> > +	.open		= ctrl_reg_value_open,
> > +	.write		= ctrl_reg_value_write,
> > +	.read		= seq_read,
> > +	.llseek		= seq_lseek,
> > +	.release	= single_release,
> > +};
> 
> please use DEFINE_DEBUGFS_ATTRIBUTE for this

This "ctrl_reg_value" file can output more than one register value. So I
can't use DEFINE_DEBUGFS_ATTRIBUTE because it can only support one register
one time. I'm going to use DEFINE_SHOW_STORE_ATTRIBUTE instead. 

> 
> > +
> > +static void debug_create_files(struct imx8mq_usb_phy *imx_phy)
> > +{
> > +	struct device *dev = &imx_phy->phy->dev;
> > +
> > +	imx_phy->debugfs = debugfs_create_dir(dev_name(dev), imx_phy->phy->debugfs);
> > +
> > +	debugfs_create_x16("ctrl_reg_base", 0600, imx_phy->debugfs,
> > +			   &imx_phy->cr_access_base);
> > +	debugfs_create_x16("ctrl_reg_count", 0600, imx_phy->debugfs,
> > +			   &imx_phy->cr_read_count);
> > +	debugfs_create_file("ctrl_reg_value", 0600, imx_phy->debugfs,
> > +			    imx_phy, &ctrl_reg_value_fops);
> > +
> > +	imx_phy->cr_access_base = 0;
> > +	imx_phy->cr_read_count = 1;
> > +}
> > +
> > +static void debug_remove_files(struct imx8mq_usb_phy *imx_phy)
> > +{
> > +	debugfs_remove_recursive(imx_phy->debugfs);
> >  }
> >  
> >  static void imx8m_get_phy_tuning_data(struct imx8mq_usb_phy *imx_phy)
> > @@ -724,6 +941,7 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
> >  					"failed to get tca\n");
> >  
> >  	imx8m_get_phy_tuning_data(imx_phy);
> > +	debug_create_files(imx_phy);
> 
> please use phy->debugfs as root node

Okay. Will do.

Thanks,
Xu Yang


From xu.yang_2 at nxp.com  Wed Dec 24 03:17:16 2025
From: xu.yang_2 at nxp.com (Xu Yang)
Date: Wed, 24 Dec 2025 19:17:16 +0800
Subject: [PATCH v2] phy: fsl-imx8mq-usb: add debugfs to access control register
Message-ID: <20251224111716.2925597-1-xu.yang_2@nxp.com>

The CR port is a simple 16-bit data/address parallel port that is
provided for on-chip access to the control registers inside the
USB 3.0 femtoPHY. While access to these registers is not required
for normal PHY operation, this interface enables you to access
some of the PHY?s diagnostic features during normal operation or
to override some basic PHY control signals.

3 debugfs files are created to read and write control registers,
all use hexadecimal format:
ctrl_reg_base: the register offset to write, or the start offset
               to read.
ctrl_reg_count: how many continuous registers to be read.
ctrl_reg_value: read to show the continuous registers value from
                the offset in ctrl_reg_base, to ctrl_reg_base
                + ctrl_reg_count - 1, one line for one register.
                when write, override the register at ctrl_reg_base,
                one time can only change one 16bits register.

Signed-off-by: Li Jun <jun.li at nxp.com>
Signed-off-by: Xu Yang <xu.yang_2 at nxp.com>

---
Changes in v2:
 - correct copyright
 - add imx8mq_phy_wait_for_cr_ack() helper and use it
 - use DEFINE_SHOW_STORE_ATTRIBUTE()
 - directly create debugfs file under imx phy debugfs
 - remove debug_remove_files() since the phy core will handle it
---
 drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 180 ++++++++++++++++++++-
 1 file changed, 178 insertions(+), 2 deletions(-)

diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
index e991a480b882..a5a6321f1f27 100644
--- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
+++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
@@ -1,10 +1,11 @@
 // SPDX-License-Identifier: GPL-2.0+
-/* Copyright (c) 2017 NXP. */
+/* Copyright 2017-2025 NXP. */
 
 #include <linux/bitfield.h>
 #include <linux/clk.h>
+#include <linux/debugfs.h>
 #include <linux/delay.h>
-#include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/phy/phy.h>
@@ -57,6 +58,20 @@
 
 #define PHY_TUNE_DEFAULT		0xffffffff
 
+/* PHY control register access */
+#define PHY_CTRL_REG_OFFSET_MAX		0x201f
+
+#define PHY_CRCTL			0x30
+#define PHY_CRCTL_DATA_IN_MASK		GENMASK(15, 0)
+#define PHY_CRCTL_CAP_ADDR		BIT(16)
+#define PHY_CRCTL_CAP_DATA		BIT(17)
+#define PHY_CRCTL_CR_WRITE		BIT(18)
+#define PHY_CRCTL_CR_READ		BIT(19)
+
+#define PHY_CRSR			0x34
+#define PHY_CRSR_DATA_OUT_MASK		GENMASK(15, 0)
+#define PHY_CRSR_CR_ACK			BIT(16)
+
 #define TCA_CLK_RST			0x00
 #define TCA_CLK_RST_SW			BIT(9)
 #define TCA_CLK_RST_REF_CLK_EN		BIT(1)
@@ -118,6 +133,9 @@ struct imx8mq_usb_phy {
 	void __iomem *base;
 	struct regulator *vbus;
 	struct tca_blk *tca;
+	struct dentry *debugfs;
+	u16 cr_access_base;
+	u16 cr_read_count;
 	u32 pcs_tx_swing_full;
 	u32 pcs_tx_deemph_3p5db;
 	u32 tx_vref_tune;
@@ -425,6 +443,163 @@ static u32 phy_pcs_tx_swing_full_from_property(u32 percent)
 	percent = min(percent, 100U);
 
 	return (percent * 127) / 100;
+};
+
+static int imx8mq_phy_wait_for_cr_ack(struct imx8mq_usb_phy *imx_phy,
+				      u32 stage, u32 *data)
+{
+	void __iomem	*cr_ctrl = imx_phy->base + PHY_CRCTL;
+	void __iomem	*cr_sr = imx_phy->base + PHY_CRSR;
+	u32		val;
+	int		ret;
+
+	writel(readl(cr_ctrl) | stage, cr_ctrl);
+	/* Wait CRSR[16] == 1 */
+	ret = readl_poll_timeout(cr_sr, val,
+				 (val & PHY_CRSR_CR_ACK) == PHY_CRSR_CR_ACK,
+				 1, 100);
+	if (ret)
+		return ret;
+
+	if (stage == PHY_CRCTL_CR_READ)
+		*data = readl(cr_sr) & 0xffff;
+
+	writel(readl(cr_ctrl) & (~stage), cr_ctrl);
+	/* Wait CRSR[16] == 0 */
+	return readl_poll_timeout(cr_sr, val, (val & PHY_CRSR_CR_ACK) == 0, 1, 100);
+}
+
+static int imx8mq_phy_ctrl_reg_addr(struct imx8mq_usb_phy *imx_phy, u16 offset)
+{
+	void __iomem	*cr_ctrl = imx_phy->base + PHY_CRCTL;
+	struct device	*dev = &imx_phy->phy->dev;
+	int		ret;
+
+	writel(offset, cr_ctrl);
+	ret = imx8mq_phy_wait_for_cr_ack(imx_phy, PHY_CRCTL_CAP_ADDR, NULL);
+	if (ret < 0) {
+		dev_err(dev, "Failed to address reg 0x%04x\n", offset);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int imx8mq_phy_ctrl_reg_read(struct imx8mq_usb_phy *imx_phy,
+				    u16 offset, u32 *val)
+{
+	struct device *dev = &imx_phy->phy->dev;
+	int ret;
+
+	if (offset > PHY_CTRL_REG_OFFSET_MAX) {
+		dev_err(dev, "Invalid reg address 0x%04x\n", offset);
+		return -EINVAL;
+	}
+
+	/* Address stage */
+	ret = imx8mq_phy_ctrl_reg_addr(imx_phy, offset);
+	if (ret)
+		return ret;
+
+	/* Read data stage */
+	ret = imx8mq_phy_wait_for_cr_ack(imx_phy, PHY_CRCTL_CR_READ, val);
+	if (ret < 0) {
+		dev_err(dev, "Failed to read reg 0x%04x\n", offset);
+		return -EIO;
+	}
+
+	return ret;
+}
+
+static int imx8mq_phy_ctrl_reg_write(struct imx8mq_usb_phy *imx_phy,
+				     u16 offset, u16 val)
+{
+	struct device	*dev = &imx_phy->phy->dev;
+	void __iomem	*cr_ctrl = imx_phy->base + PHY_CRCTL;
+	int		ret;
+
+	if (offset > PHY_CTRL_REG_OFFSET_MAX) {
+		dev_err(dev, "Invalid reg address 0x%04x\n", offset);
+		return -EINVAL;
+	}
+
+	/* Address stage */
+	ret = imx8mq_phy_ctrl_reg_addr(imx_phy, offset);
+	if (ret)
+		return ret;
+
+	/* Capture data stage */
+	writel(val, cr_ctrl);
+	ret = imx8mq_phy_wait_for_cr_ack(imx_phy, PHY_CRCTL_CAP_DATA, NULL);
+	if (ret < 0)
+		goto cr_write_err;
+
+	/* Write data stage */
+	ret = imx8mq_phy_wait_for_cr_ack(imx_phy, PHY_CRCTL_CR_WRITE, NULL);
+	if (ret < 0)
+		goto cr_write_err;
+
+	return 0;
+
+cr_write_err:
+	dev_err(dev, "Failed to write reg 0x%04x\n", offset);
+	return -EIO;
+}
+
+static int ctrl_reg_value_show(struct seq_file *s, void *unused)
+{
+	struct imx8mq_usb_phy *imx_phy = s->private;
+	u16 base = imx_phy->cr_access_base;
+	u32 val;
+	int i, ret;
+
+	for (i = 0; i < imx_phy->cr_read_count; i++) {
+		ret = imx8mq_phy_ctrl_reg_read(imx_phy, base + i, &val);
+		if (ret < 0)
+			return ret;
+
+		seq_printf(s, "Control Register 0x%04x value is 0x%04x\n",
+			   base + i, val);
+	}
+
+	return 0;
+}
+
+static ssize_t ctrl_reg_value_write(struct file *file, const char __user *ubuf,
+				    size_t count, loff_t *ppos)
+
+{
+	struct seq_file		*s = file->private_data;
+	struct imx8mq_usb_phy	*imx_phy = s->private;
+	u16			cr_value;
+	int			ret;
+
+	ret = kstrtou16_from_user(ubuf, count, 16, &cr_value);
+	if (ret)
+		return ret;
+
+	ret = imx8mq_phy_ctrl_reg_write(imx_phy, imx_phy->cr_access_base, cr_value);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+DEFINE_SHOW_STORE_ATTRIBUTE(ctrl_reg_value);
+
+static void imx8m_create_debug_files(struct imx8mq_usb_phy *imx_phy)
+{
+	struct dentry *debugfs = imx_phy->phy->debugfs;
+
+	debugfs_create_x16("ctrl_reg_base", 0600, debugfs,
+			   &imx_phy->cr_access_base);
+	debugfs_create_x16("ctrl_reg_count", 0600, debugfs,
+			   &imx_phy->cr_read_count);
+	debugfs_create_file("ctrl_reg_value", 0600, debugfs,
+			    imx_phy, &ctrl_reg_value_fops);
+
+	imx_phy->cr_access_base = 0;
+	imx_phy->cr_read_count = 1;
 }
 
 static void imx8m_get_phy_tuning_data(struct imx8mq_usb_phy *imx_phy)
@@ -744,6 +919,7 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
 					"failed to get tca\n");
 
 	imx8m_get_phy_tuning_data(imx_phy);
+	imx8m_create_debug_files(imx_phy);
 
 	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
 
-- 
2.34.1



From xu.yang_2 at nxp.com  Wed Dec 24 03:18:07 2025
From: xu.yang_2 at nxp.com (Xu Yang)
Date: Wed, 24 Dec 2025 19:18:07 +0800
Subject: [PATCH v2] phy: fsl-imx8mq-usb: enable RxTermination_override_sel
Message-ID: <20251224111807.2925675-1-xu.yang_2@nxp.com>

This is to resolve the problem of wakeup system by USB3 device insertion
if HSIOMIX on, in that case, the USB3 device detects RX term on so the
USB3 device doesn't downgrade to high-speed, we can't expect CONN wakeup
(for USB3) happen because the 24MHz OSC is required ON to trigger it.
Because the device works at Super-speed so DP/DM wakeup can't happen
either. Then the entire systen can't be waken up by such device attach
event.

With this override bit we can force the RX term off when enters system
suspend, and disable the override after system resume. Therefore, the
USB3 device will always downgrade to High-speed, then DP/DM wakeup can
always happen. It will correctly switch to Super-speed later when the
host reset it after the system resume back.

Signed-off-by: Li Jun <jun.li at nxp.com>
Signed-off-by: Xu Yang <xu.yang_2 at nxp.com>

---
Changes in v2:
 - rephase the message
---
 drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
index 92c5c233bad9..e991a480b882 100644
--- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
+++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
@@ -51,6 +51,7 @@
 #define PHY_CTRL5_PCS_TX_SWING_FULL_MASK	GENMASK(6, 0)
 
 #define PHY_CTRL6			0x18
+#define PHY_CTRL6_RXTERM_OVERRIDE_SEL	BIT(29)
 #define PHY_CTRL6_ALT_CLK_EN		BIT(1)
 #define PHY_CTRL6_ALT_CLK_SEL		BIT(0)
 
@@ -630,6 +631,7 @@ static int imx8mp_usb_phy_init(struct phy *phy)
 static int imx8mq_phy_power_on(struct phy *phy)
 {
 	struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
+	u32 value;
 	int ret;
 
 	ret = regulator_enable(imx_phy->vbus);
@@ -646,12 +648,23 @@ static int imx8mq_phy_power_on(struct phy *phy)
 		return ret;
 	}
 
-	return ret;
+	/* Disable rx term override */
+	value = readl(imx_phy->base + PHY_CTRL6);
+	value &= ~PHY_CTRL6_RXTERM_OVERRIDE_SEL;
+	writel(value, imx_phy->base + PHY_CTRL6);
+
+	return 0;
 }
 
 static int imx8mq_phy_power_off(struct phy *phy)
 {
 	struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
+	u32 value;
+
+	/* Override rx term to be 0 */
+	value = readl(imx_phy->base + PHY_CTRL6);
+	value |= PHY_CTRL6_RXTERM_OVERRIDE_SEL;
+	writel(value, imx_phy->base + PHY_CTRL6);
 
 	clk_disable_unprepare(imx_phy->alt_clk);
 	clk_disable_unprepare(imx_phy->clk);
-- 
2.34.1



From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec 24 03:22:40 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed, 24 Dec 2025 12:22:40 +0100
Subject: [PATCH 1/3] clk: lmk04832: Simplify with scoped for each OF child loop
Message-ID: <20251224112239.83735-4-krzysztof.kozlowski@oss.qualcomm.com>

Use scoped for-each loop when iterating over device nodes to make code a
bit simpler.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/clk/clk-lmk04832.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/clk/clk-lmk04832.c b/drivers/clk/clk-lmk04832.c
index b2107b31efa2..9bf86caad829 100644
--- a/drivers/clk/clk-lmk04832.c
+++ b/drivers/clk/clk-lmk04832.c
@@ -1400,7 +1400,6 @@ static int lmk04832_probe(struct spi_device *spi)
 {
 	const struct lmk04832_device_info *info;
 	int rdbk_pin = RDBK_CLKIN_SEL1;
-	struct device_node *child;
 	struct lmk04832 *lmk;
 	u8 tmp[3];
 	int ret;
@@ -1462,14 +1461,13 @@ static int lmk04832_probe(struct spi_device *spi)
 	device_property_read_u32(lmk->dev, "ti,sysref-pulse-count",
 				 &lmk->sysref_pulse_cnt);
 
-	for_each_child_of_node(lmk->dev->of_node, child) {
+	for_each_child_of_node_scoped(lmk->dev->of_node, child) {
 		int reg;
 
 		ret = of_property_read_u32(child, "reg", &reg);
 		if (ret) {
 			dev_err(lmk->dev, "missing reg property in child: %s\n",
 				child->full_name);
-			of_node_put(child);
 			return ret;
 		}
 
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec 24 03:22:41 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed, 24 Dec 2025 12:22:41 +0100
Subject: [PATCH 2/3] clk: scpi: Simplify with scoped for each OF child loop
In-Reply-To: <20251224112239.83735-4-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251224112239.83735-4-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <20251224112239.83735-5-krzysztof.kozlowski@oss.qualcomm.com>

Use scoped for-each loop when iterating over device nodes to make code a
bit simpler.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/clk/clk-scpi.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/clk/clk-scpi.c b/drivers/clk/clk-scpi.c
index 0b592de7bdb2..7806569cd0d5 100644
--- a/drivers/clk/clk-scpi.c
+++ b/drivers/clk/clk-scpi.c
@@ -265,20 +265,19 @@ static int scpi_clocks_probe(struct platform_device *pdev)
 {
 	int ret;
 	struct device *dev = &pdev->dev;
-	struct device_node *child, *np = dev->of_node;
+	struct device_node *np = dev->of_node;
 	const struct of_device_id *match;
 
 	if (!get_scpi_ops())
 		return -ENXIO;
 
-	for_each_available_child_of_node(np, child) {
+	for_each_available_child_of_node_scoped(np, child) {
 		match = of_match_node(scpi_clk_match, child);
 		if (!match)
 			continue;
 		ret = scpi_clk_add(dev, child, match);
 		if (ret) {
 			scpi_clocks_remove(pdev);
-			of_node_put(child);
 			return ret;
 		}
 
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec 24 03:22:42 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed, 24 Dec 2025 12:22:42 +0100
Subject: [PATCH 3/3] clk: versatile: impd1: Simplify with scoped for each OF child loop
In-Reply-To: <20251224112239.83735-4-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251224112239.83735-4-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <20251224112239.83735-6-krzysztof.kozlowski@oss.qualcomm.com>

Use scoped for-each loop when iterating over device nodes to make code a
bit simpler.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/clk/versatile/clk-impd1.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/clk/versatile/clk-impd1.c b/drivers/clk/versatile/clk-impd1.c
index 85c395df9c00..328dd47f1e43 100644
--- a/drivers/clk/versatile/clk-impd1.c
+++ b/drivers/clk/versatile/clk-impd1.c
@@ -104,15 +104,12 @@ static int integrator_impd1_clk_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct device_node *np = dev->of_node;
-	struct device_node *child;
 	int ret = 0;
 
-	for_each_available_child_of_node(np, child) {
+	for_each_available_child_of_node_scoped(np, child) {
 		ret = integrator_impd1_clk_spawn(dev, np, child);
-		if (ret) {
-			of_node_put(child);
+		if (ret)
 			break;
-		}
 	}
 
 	return ret;
-- 
2.51.0



From chleroy at kernel.org  Wed Dec 24 03:35:31 2025
From: chleroy at kernel.org (Christophe Leroy (CS GROUP))
Date: Wed, 24 Dec 2025 12:35:31 +0100
Subject: [PATCH 1/4] arch/*: increase lowmem size to avoid highmem use
In-Reply-To: <20251219161559.556737-2-arnd@kernel.org>
References: <20251219161559.556737-1-arnd@kernel.org>
 <20251219161559.556737-2-arnd@kernel.org>
Message-ID: <6089e76b-80aa-4254-af70-12b96d115a2e@kernel.org>



Le 19/12/2025 ? 17:15, Arnd Bergmann a ?crit?:
> From: Arnd Bergmann <arnd at arndb.de>
> 
> Most of the common 32-bit architectures (x86, arm, powerpc) all use the
> default virtual memory layout that was already in place for i386 systems
> in the 1990s, using exactly 3GiB of user TASK_SIZE, with the upper 1GiB
> of addresses split between (at most 896MiB) lowmem and vmalloc.
> 
> Linux-2.3 introduced CONFIG_HIGHMEM for large x86 server machines that
> had 4GiB of RAM or more, with the VMSPLIT_3G/2G/1G options added in
> v2.6.16 for machines that had one or two gigabytes of memory but wanted
> to avoid the overhead from managing highmem. Over time, similar options
> appeared on other 32-bit architectures.
> 
> Twenty years later, it makes sense to reconsider the default settings,
> as the tradeoffs have changed a bit:
> 
>   - Configurations with more than 2GiB have become extremely rare,
>     as any users with large memory have moved on to 64-bit systems.
>     There were only ever a few Laptop models in this category: Apple
>     Powerbook G4 (2005), Macbook (2006), IBM Thinkpad X60 (2006), Arm
>     Chromebooks based on Exynos 5800 (2014), Tegra K1 (2014) and RK3288
>     (2015), and manufacturer support for all of these has ended in 2020
>     or (much) earlier.
>     Embedded systems with more than 2GiB use additional SoCs of a
>     similar vintage: Intel Atom Z5xx (2008), Freescale QorIQ (2008),
>     Marvell Armada XP (2010), Freescale i.MX6Q (2011), LSI Axxia (2013),
>     TI Keystone2 (2014), Renesas RZ/G1M (2015). Most boards based on
>     these have stopped receiving kernel upgrades. Newer 32-bit chips
>     only support smaller memory configurations, though in particular the
>     i.MX6Q and Keystone2 families have expected support cycles past 2035.
>     While 32-bit server installations used to support even larger memory,
>     none of those seem to still be used in production on any architecture.
> 
>   - While general-purpose distributes for 32-bit targets were common,
>     it was rather risky to change the CONFIG_VMSPLIT setting because
>     there is always a possibility of running into device driver bugs or
>     applications that need a large virtual memory size. Presumably
>     a lot of these issues have been resolved now, so most setups should
>     be fine using a custom vmsplit instead of highmem now.
> 
>   - As fewer users test highmem, the expectation is that it will
>     increasingly break in the future, so getting users to change the
>     vmsplit means that even if there is a bug to fix initially,
>     it improves the situation in the long run.
> 
>   - Highmem will ultimately need to be removed, at least for the page
>     cache and most other code using it today. In a previous discussion, I
>     had suggested doing this as early as 2029, but based on the discussions
>     since ELC, the plan is now to leave highmem-enabled page cache as an
>     option until at least 2029, at which point remaining users will have
>     the choice between no longer updating kernels or using a combination of
>     a custom vmsplit and zram/zswap. Changing the defaults now should both
>     speed up the highmem deprecation and make it less painful for users.
> 
>   - The most VM space intensive applications tend to be web browsers,
>     specifcally Chrome/ChromeOS and Firefox. Both have now stopped
>     providing binary updates, but Firefox can still be built from source.
>     Testing various combinations on Debian/armhf, I found that Firefox 140
>     can still show complex websites with VMSPLIT_2G_OPT with and without
>     HIGHMEM, though it failed for me both with the small address space
>     of VMSPLIT_1G and the small lowmem of VMSPLIT_3G_OPT when HIGHMEM
>     is disabled.
>     This is likely to get worse with future versions, so embedded users
>     may still be forced to migrate to specialized browsers like WPE Webkit
>     when HIGHMEM pagecache is finally removed.
> 
> Based on the above observations and the discussion at the kernel summit,
> change the defaults to the most appropriate values: use 1GiB of lowmem on
> non-highmem configurations, and either 2GiB or 1.75GiB of lowmem on highmem
> builds, depending on what is available on the architecture.  As ARM_LPAE
> and X86_PAE builds both require a gigabyte-aligned vmsplit, those get
> to use VMSPLIT_2G. The result is that the majority of previous highmem
> users now only need lowmem. For platform specific defconfig files that
> are known to only support up to 1GiB of RAM, drop the CONFIG_HIGHMEM line
> as well as a simplification.
> 
> On PowerPC and Microblaze, the options have somewhat different names but
> should have the same effect. MIPS and Xtensa cannot support a larger
> than 512MB of lowmem but are limited to small DDR2 memory in most
> implementations, with MT7621 being a notable exception. ARC and C-Sky
> could support a configurable vmsplit in theory, but it's not clear
> if anyone still cares.
> SPARC is currently limited to 192MB of lowmem and should get patched
> to behave either like arm/x86 or powerpc/microblaze to support 2GiB
> of lowmem.
> 
> There are likely going to be regressions from the changed defaults,
> in particular when hitting previously hidden device driver bugs
> that fail to set the correct DMA mask, or from applications that
> need a large virtual address space.
> Ideally the in-kernel problems should all be fixable, but the previous
> behavior is still selectable as a fallback with CONFIG_EXPERT=y
> 
> Cc: Russell King <linux at armlinux.org.uk>
> Cc: linux-arm-kernel at lists.infradead.org
> Cc: Thomas Gleixner <tglx at linutronix.de>
> Cc: Ingo Molnar <mingo at redhat.com>
> Cc: Borislav Petkov <bp at alien8.de>
> Cc: Dave Hansen <dave.hansen at linux.intel.com>
> Cc: x86 at kernel.org
> Cc: "H. Peter Anvin" <hpa at zytor.com>
> Cc: Madhavan Srinivasan <maddy at linux.ibm.com>
> Cc: Michael Ellerman <mpe at ellerman.id.au>
> Cc: Nicholas Piggin <npiggin at gmail.com>
> Cc: Christophe Leroy (CS GROUP) <chleroy at kernel.org>
> Cc: linuxppc-dev at lists.ozlabs.org
> Cc: Michal Simek <monstr at monstr.eu>
> Cc: Andrew Morton <akpm at linux-foundation.org>
> Cc: David Hildenbrand <david at kernel.org>
> Cc: Lorenzo Stoakes <lorenzo.stoakes at oracle.com>
> Cc: Liam R. Howlett <Liam.Howlett at oracle.com>
> Cc: Vlastimil Babka <vbabka at suse.cz>
> Cc: Mike Rapoport <rppt at kernel.org>
> Cc: Suren Baghdasaryan <surenb at google.com>
> Cc: Michal Hocko <mhocko at suse.com>
> Cc: Matthew Wilcox <willy at infradead.org>
> Cc: linux-mm at kvack.org
> Cc: Richard Weinberger <richard at nod.at>
> Cc: Linus Walleij <linus.walleij at linaro.org>
> Cc: Nishanth Menon <nm at ti.com>
> Cc: Andreas Larsson <andreas at gaisler.com>
> Cc: Lucas Stach <l.stach at pengutronix.de>
> Signed-off-by: Arnd Bergmann <arnd at arndb.de>
> ---
>   arch/arm/Kconfig                            |  5 ++++-
>   arch/arm/configs/aspeed_g5_defconfig        |  1 -
>   arch/arm/configs/dove_defconfig             |  2 --
>   arch/arm/configs/mv78xx0_defconfig          |  2 --
>   arch/arm/configs/u8500_defconfig            |  1 -
>   arch/arm/configs/vt8500_v6_v7_defconfig     |  3 ---
>   arch/arm/mach-omap2/Kconfig                 |  1 -
>   arch/microblaze/Kconfig                     |  9 ++++++---
>   arch/microblaze/configs/mmu_defconfig       |  1 -
>   arch/powerpc/Kconfig                        | 17 +++++++++++------
>   arch/powerpc/configs/44x/akebono_defconfig  |  1 -
>   arch/powerpc/configs/85xx/ksi8560_defconfig |  1 -
>   arch/powerpc/configs/85xx/stx_gp3_defconfig |  1 -

Reviewed-by: Christophe Leroy (CS GROUP) <chleroy at kernel.org>

Be aware that it will likely trivialy conflict with 
https://lore.kernel.org/linuxppc-dev/6a2575420770d075cd090b5a316730a2ffafdee4.1766574657.git.chleroy at kernel.org/

Another point is that it will increase the overall memory usage when 
people activate KASAN as KASAN reserves 1/8 of RAM for lowmem memory. I 
think we need to look at the impact on available virtual memory, because 
1/8 of 2G is 256M which is the size of the last segment shared by KASAN 
shadow mem and vmalloc.

Christophe



From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec 24 03:42:11 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed, 24 Dec 2025 12:42:11 +0100
Subject: [PATCH 1/3] clk: zynqmp: divider: Fix zynqmp_clk_divider_determine_rate kerneldoc
Message-ID: <20251224114210.139817-4-krzysztof.kozlowski@oss.qualcomm.com>

After renaming round_rate->determine, kerneldoc does not match anymore,
causing W=1 warnings:

  Warning: drivers/clk/zynqmp/divider.c:122 function parameter 'req' not described in 'zynqmp_clk_divider_determine_rate'
  Warning: drivers/clk/zynqmp/divider.c:122 expecting prototype for zynqmp_clk_divider_round_rate(). Prototype was for zynqmp_clk_divider_determine_rate() instead

Fixes: 0f9cf96a01fd ("clk: zynqmp: divider: convert from round_rate() to determine_rate()")
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/clk/zynqmp/divider.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/clk/zynqmp/divider.c b/drivers/clk/zynqmp/divider.c
index c824eeacd8eb..5baa967aa7c9 100644
--- a/drivers/clk/zynqmp/divider.c
+++ b/drivers/clk/zynqmp/divider.c
@@ -111,10 +111,9 @@ static unsigned long zynqmp_clk_divider_recalc_rate(struct clk_hw *hw,
 }
 
 /**
- * zynqmp_clk_divider_round_rate() - Round rate of divider clock
+ * zynqmp_clk_divider_determine_rate() - Determine rate of divider clock
  * @hw:			handle between common and hardware-specific interfaces
- * @rate:		rate of clock to be set
- * @prate:		rate of parent clock
+ * @req:		rate of clock to be set
  *
  * Return: 0 on success else error+reason
  */
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec 24 03:42:12 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed, 24 Dec 2025 12:42:12 +0100
Subject: [PATCH 2/3] clk: zynqmp: pll: Fix zynqmp_clk_divider_determine_rate kerneldoc
In-Reply-To: <20251224114210.139817-4-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251224114210.139817-4-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <20251224114210.139817-5-krzysztof.kozlowski@oss.qualcomm.com>

After renaming round_rate->determine, kerneldoc does not match anymore,
causing W=1 warnings:

  pll.c:102 function parameter 'req' not described in 'zynqmp_pll_determine_rate'
  pll.c:102 expecting prototype for zynqmp_pll_round_rate(). Prototype was for zynqmp_pll_determine_rate() instead

Fixes: 193650c7a873 ("clk: zynqmp: pll: convert from round_rate() to determine_rate()")
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/clk/zynqmp/pll.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/clk/zynqmp/pll.c b/drivers/clk/zynqmp/pll.c
index 630a3936c97c..6bc2c3934f56 100644
--- a/drivers/clk/zynqmp/pll.c
+++ b/drivers/clk/zynqmp/pll.c
@@ -91,10 +91,9 @@ static inline void zynqmp_pll_set_mode(struct clk_hw *hw, bool on)
 }
 
 /**
- * zynqmp_pll_round_rate() - Round a clock frequency
+ * zynqmp_pll_determine_rate() - Round a clock frequency
  * @hw:		Handle between common and hardware-specific interfaces
- * @rate:	Desired clock frequency
- * @prate:	Clock frequency of parent clock
+ * @req:	Desired clock frequency
  *
  * Return: Frequency closest to @rate the hardware can generate
  */
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec 24 03:42:13 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed, 24 Dec 2025 12:42:13 +0100
Subject: [PATCH 3/3] clk: zynqmp: ipi-mailbox: Simplify with scoped for each OF child loop
In-Reply-To: <20251224114210.139817-4-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251224114210.139817-4-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <20251224114210.139817-6-krzysztof.kozlowski@oss.qualcomm.com>

Use scoped for-each loop when iterating over device nodes to make code a
bit simpler.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/mailbox/zynqmp-ipi-mailbox.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/mailbox/zynqmp-ipi-mailbox.c b/drivers/mailbox/zynqmp-ipi-mailbox.c
index 967967b2b8a9..42d2583e44ca 100644
--- a/drivers/mailbox/zynqmp-ipi-mailbox.c
+++ b/drivers/mailbox/zynqmp-ipi-mailbox.c
@@ -904,7 +904,7 @@ static void zynqmp_ipi_free_mboxes(struct zynqmp_ipi_pdata *pdata)
 static int zynqmp_ipi_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct device_node *nc, *np = pdev->dev.of_node;
+	struct device_node *np = pdev->dev.of_node;
 	struct zynqmp_ipi_pdata *pdata;
 	struct of_phandle_args out_irq;
 	struct zynqmp_ipi_mbox *mbox;
@@ -940,13 +940,12 @@ static int zynqmp_ipi_probe(struct platform_device *pdev)
 	pdata->num_mboxes = num_mboxes;
 
 	mbox = pdata->ipi_mboxes;
-	for_each_available_child_of_node(np, nc) {
+	for_each_available_child_of_node_scoped(np, nc) {
 		mbox->pdata = pdata;
 		mbox->setup_ipi_fn = ipi_fn;
 
 		ret = zynqmp_ipi_mbox_probe(mbox, nc);
 		if (ret) {
-			of_node_put(nc);
 			dev_err(dev, "failed to probe subdev.\n");
 			ret = -EINVAL;
 			goto free_mbox_dev;
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec 24 03:44:10 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed, 24 Dec 2025 12:44:10 +0100
Subject: [PATCH 3/3] clk: zynqmp: ipi-mailbox: Simplify with scoped for
 each OF child loop
In-Reply-To: <20251224114210.139817-6-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251224114210.139817-4-krzysztof.kozlowski@oss.qualcomm.com>
 <20251224114210.139817-6-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <9a99ad41-10b2-4032-9ad9-e49940e1d241@oss.qualcomm.com>

On 24/12/2025 12:42, Krzysztof Kozlowski wrote:
> Use scoped for-each loop when iterating over device nodes to make code a
> bit simpler.
> 
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
> ---
>  drivers/mailbox/zynqmp-ipi-mailbox.c | 5 ++---

I am sorry, that's a mailbox patch and should be in different patchset.
Please review/pick only the first two.

Best regards,
Krzysztof


From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec 24 03:44:53 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed, 24 Dec 2025 12:44:53 +0100
Subject: [PATCH 1/2] mailbox: mtk-cmdq: Simplify with scoped for each OF child loop
Message-ID: <20251224114452.141689-3-krzysztof.kozlowski@oss.qualcomm.com>

Use scoped for-each loop when iterating over device nodes to make code a
bit simpler.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/mailbox/mtk-cmdq-mailbox.c | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/drivers/mailbox/mtk-cmdq-mailbox.c b/drivers/mailbox/mtk-cmdq-mailbox.c
index 1bf6984948ef..9da16b30eb41 100644
--- a/drivers/mailbox/mtk-cmdq-mailbox.c
+++ b/drivers/mailbox/mtk-cmdq-mailbox.c
@@ -636,7 +636,7 @@ static struct mbox_chan *cmdq_xlate(struct mbox_controller *mbox,
 static int cmdq_get_clocks(struct device *dev, struct cmdq *cmdq)
 {
 	static const char * const gce_name = "gce";
-	struct device_node *node, *parent = dev->of_node->parent;
+	struct device_node *parent = dev->of_node->parent;
 	struct clk_bulk_data *clks;
 
 	cmdq->clocks = devm_kcalloc(dev, cmdq->pdata->gce_num,
@@ -661,7 +661,7 @@ static int cmdq_get_clocks(struct device *dev, struct cmdq *cmdq)
 	 * as the clock of the main GCE must be enabled for additional IPs
 	 * to be reachable.
 	 */
-	for_each_child_of_node(parent, node) {
+	for_each_child_of_node_scoped(parent, node) {
 		int alias_id = of_alias_get_id(node, gce_name);
 
 		if (alias_id < 0 || alias_id >= cmdq->pdata->gce_num)
@@ -670,17 +670,13 @@ static int cmdq_get_clocks(struct device *dev, struct cmdq *cmdq)
 		clks = &cmdq->clocks[alias_id];
 
 		clks->id = devm_kasprintf(dev, GFP_KERNEL, "gce%d", alias_id);
-		if (!clks->id) {
-			of_node_put(node);
+		if (!clks->id)
 			return -ENOMEM;
-		}
 
 		clks->clk = of_clk_get(node, 0);
-		if (IS_ERR(clks->clk)) {
-			of_node_put(node);
+		if (IS_ERR(clks->clk))
 			return dev_err_probe(dev, PTR_ERR(clks->clk),
 					     "failed to get gce%d clock\n", alias_id);
-		}
 	}
 
 	return 0;
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec 24 03:44:54 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed, 24 Dec 2025 12:44:54 +0100
Subject: [PATCH 2/2] mailbox: zynqmp-ipi: Simplify with scoped for each OF child loop
In-Reply-To: <20251224114452.141689-3-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251224114452.141689-3-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <20251224114452.141689-4-krzysztof.kozlowski@oss.qualcomm.com>

Use scoped for-each loop when iterating over device nodes to make code a
bit simpler.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/mailbox/zynqmp-ipi-mailbox.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/mailbox/zynqmp-ipi-mailbox.c b/drivers/mailbox/zynqmp-ipi-mailbox.c
index 967967b2b8a9..42d2583e44ca 100644
--- a/drivers/mailbox/zynqmp-ipi-mailbox.c
+++ b/drivers/mailbox/zynqmp-ipi-mailbox.c
@@ -904,7 +904,7 @@ static void zynqmp_ipi_free_mboxes(struct zynqmp_ipi_pdata *pdata)
 static int zynqmp_ipi_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct device_node *nc, *np = pdev->dev.of_node;
+	struct device_node *np = pdev->dev.of_node;
 	struct zynqmp_ipi_pdata *pdata;
 	struct of_phandle_args out_irq;
 	struct zynqmp_ipi_mbox *mbox;
@@ -940,13 +940,12 @@ static int zynqmp_ipi_probe(struct platform_device *pdev)
 	pdata->num_mboxes = num_mboxes;
 
 	mbox = pdata->ipi_mboxes;
-	for_each_available_child_of_node(np, nc) {
+	for_each_available_child_of_node_scoped(np, nc) {
 		mbox->pdata = pdata;
 		mbox->setup_ipi_fn = ipi_fn;
 
 		ret = zynqmp_ipi_mbox_probe(mbox, nc);
 		if (ret) {
-			of_node_put(nc);
 			dev_err(dev, "failed to probe subdev.\n");
 			ret = -EINVAL;
 			goto free_mbox_dev;
-- 
2.51.0



From vincenzo.frascino at arm.com  Wed Dec 24 03:58:44 2025
From: vincenzo.frascino at arm.com (Vincenzo Frascino)
Date: Wed, 24 Dec 2025 11:58:44 +0000
Subject: [PATCH 1/2] arm64: dts: arm: Use hyphen in node names
In-Reply-To: <20251223152457.155392-3-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251223152457.155392-3-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <10a089d2-4823-4406-b1a9-d38f05ba0760@arm.com>



On 23/12/2025 15:24, Krzysztof Kozlowski wrote:
> DTS coding style prefers hyphens instead of underscores in the node
> names.  Change should be safe, because node names are not considered an
> ABI.
> 
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
>

Acked-by: Vincenzo Frascino <vincenzo.frascino at arm.com>

> ---
> 
> Patches done with sed, verified with comparing unflattened DTB and
> dtx_diff.
> ---
>  arch/arm64/boot/dts/arm/morello-fvp.dts | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/arm/morello-fvp.dts b/arch/arm64/boot/dts/arm/morello-fvp.dts
> index 2072c0b72325..4a3f217555f7 100644
> --- a/arch/arm64/boot/dts/arm/morello-fvp.dts
> +++ b/arch/arm64/boot/dts/arm/morello-fvp.dts
> @@ -25,25 +25,25 @@ bp_refclock24mhz: clock-24000000 {
>  		clock-output-names = "bp:clock24mhz";
>  	};
>  
> -	block_0: virtio_block at 1c170000 {
> +	block_0: virtio-block at 1c170000 {
>  		compatible = "virtio,mmio";
>  		reg = <0x0 0x1c170000 0x0 0x200>;
>  		interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
>  	};
>  
> -	net_0: virtio_net at 1c180000 {
> +	net_0: virtio-net at 1c180000 {
>  		compatible = "virtio,mmio";
>  		reg = <0x0 0x1c180000 0x0 0x200>;
>  		interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
>  	};
>  
> -	rng_0: virtio_rng at 1c190000 {
> +	rng_0: virtio-rng at 1c190000 {
>  		compatible = "virtio,mmio";
>  		reg = <0x0 0x1c190000 0x0 0x200>;
>  		interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
>  	};
>  
> -	p9_0: virtio_p9 at 1c1a0000 {
> +	p9_0: virtio-p9 at 1c1a0000 {
>  		compatible = "virtio,mmio";
>  		reg = <0x0 0x1c1a0000 0x0 0x200>;
>  		interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;

-- 
Regards,
Vincenzo



From vincenzo.frascino at arm.com  Wed Dec 24 03:59:41 2025
From: vincenzo.frascino at arm.com (Vincenzo Frascino)
Date: Wed, 24 Dec 2025 11:59:41 +0000
Subject: [PATCH 2/2] arm64: dts: arm: Use lowercase hex
In-Reply-To: <20251223152457.155392-4-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251223152457.155392-3-krzysztof.kozlowski@oss.qualcomm.com>
 <20251223152457.155392-4-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <161e78f7-1c87-4bd8-9184-f2044e7383a8@arm.com>



On 23/12/2025 15:24, Krzysztof Kozlowski wrote:
> The DTS code coding style expects lowercase hex for values and unit
> addresses.
> 
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Acked-by: Vincenzo Frascino <vincenzo.frascino at arm.com>

> ---
>  arch/arm/boot/dts/arm/arm-realview-eb.dtsi    | 2 +-
>  arch/arm/boot/dts/arm/arm-realview-pb1176.dts | 2 +-
>  arch/arm/boot/dts/arm/arm-realview-pb11mp.dts | 2 +-
>  arch/arm/boot/dts/arm/arm-realview-pbx.dtsi   | 2 +-
>  4 files changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm/boot/dts/arm/arm-realview-eb.dtsi b/arch/arm/boot/dts/arm/arm-realview-eb.dtsi
> index 16f784da5a55..ae370d4eb9d8 100644
> --- a/arch/arm/boot/dts/arm/arm-realview-eb.dtsi
> +++ b/arch/arm/boot/dts/arm/arm-realview-eb.dtsi
> @@ -234,7 +234,7 @@ oscclk0: clock-controller at c {
>  				reg = <0x0c 0x04>;
>  				#clock-cells = <0>;
>  				lock-offset = <0x20>;
> -				vco-offset = <0x0C>;
> +				vco-offset = <0x0c>;
>  				clocks = <&xtal24mhz>;
>  			};
>  			oscclk1: clock-controller at 10 {
> diff --git a/arch/arm/boot/dts/arm/arm-realview-pb1176.dts b/arch/arm/boot/dts/arm/arm-realview-pb1176.dts
> index b9b10cbd65aa..a75d8b107fe1 100644
> --- a/arch/arm/boot/dts/arm/arm-realview-pb1176.dts
> +++ b/arch/arm/boot/dts/arm/arm-realview-pb1176.dts
> @@ -260,7 +260,7 @@ oscclk0: clock-controller at c {
>  				reg = <0x0c 0x04>;
>  				#clock-cells = <0>;
>  				lock-offset = <0x20>;
> -				vco-offset = <0x0C>;
> +				vco-offset = <0x0c>;
>  				clocks = <&xtal24mhz>;
>  			};
>  			oscclk1: clock-controller at 10 {
> diff --git a/arch/arm/boot/dts/arm/arm-realview-pb11mp.dts b/arch/arm/boot/dts/arm/arm-realview-pb11mp.dts
> index db1b6793cd2c..59c78def83f2 100644
> --- a/arch/arm/boot/dts/arm/arm-realview-pb11mp.dts
> +++ b/arch/arm/boot/dts/arm/arm-realview-pb11mp.dts
> @@ -343,7 +343,7 @@ oscclk0: clock-controller at c {
>  				reg = <0x0c 0x04>;
>  				#clock-cells = <0>;
>  				lock-offset = <0x20>;
> -				vco-offset = <0x0C>;
> +				vco-offset = <0x0c>;
>  				clocks = <&xtal24mhz>;
>  			};
>  			oscclk1: clock-controller at 10 {
> diff --git a/arch/arm/boot/dts/arm/arm-realview-pbx.dtsi b/arch/arm/boot/dts/arm/arm-realview-pbx.dtsi
> index e625403a9456..0d3d96ffa6e6 100644
> --- a/arch/arm/boot/dts/arm/arm-realview-pbx.dtsi
> +++ b/arch/arm/boot/dts/arm/arm-realview-pbx.dtsi
> @@ -256,7 +256,7 @@ oscclk0: clock-controller at c {
>  				reg = <0x0c 0x04>;
>  				#clock-cells = <0>;
>  				lock-offset = <0x20>;
> -				vco-offset = <0x0C>;
> +				vco-offset = <0x0c>;
>  				clocks = <&xtal24mhz>;
>  			};
>  			oscclk1: clock-controller at 10 {

-- 
Regards,
Vincenzo



From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec 24 04:44:08 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed, 24 Dec 2025 13:44:08 +0100
Subject: [PATCH 1/3] phy: rockchip: usb: Simplify with scoped for each OF child loop
Message-ID: <20251224124407.208354-4-krzysztof.kozlowski@oss.qualcomm.com>

Use scoped for-each loop when iterating over device nodes to make code a
bit simpler.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/phy/rockchip/phy-rockchip-usb.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usb.c b/drivers/phy/rockchip/phy-rockchip-usb.c
index c3c30df29c3e..cef96739cf3f 100644
--- a/drivers/phy/rockchip/phy-rockchip-usb.c
+++ b/drivers/phy/rockchip/phy-rockchip-usb.c
@@ -446,7 +446,6 @@ static int rockchip_usb_phy_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct rockchip_usb_phy_base *phy_base;
 	struct phy_provider *phy_provider;
-	struct device_node *child;
 	int err;
 
 	phy_base = devm_kzalloc(dev, sizeof(*phy_base), GFP_KERNEL);
@@ -472,12 +471,10 @@ static int rockchip_usb_phy_probe(struct platform_device *pdev)
 		return PTR_ERR(phy_base->reg_base);
 	}
 
-	for_each_available_child_of_node(dev->of_node, child) {
+	for_each_available_child_of_node_scoped(dev->of_node, child) {
 		err = rockchip_usb_phy_init(phy_base, child);
-		if (err) {
-			of_node_put(child);
+		if (err)
 			return err;
-		}
 	}
 
 	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec 24 04:44:09 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed, 24 Dec 2025 13:44:09 +0100
Subject: [PATCH 2/3] phy: core: Simplify with scoped for each OF child loop
In-Reply-To: <20251224124407.208354-4-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251224124407.208354-4-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <20251224124407.208354-5-krzysztof.kozlowski@oss.qualcomm.com>

Use scoped for-each loop when iterating over device nodes to make code a
bit simpler.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/phy/phy-core.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index 8d227890a345..d57c9525fa38 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -138,17 +138,14 @@ static struct phy *phy_find(struct device *dev, const char *con_id)
 static struct phy_provider *of_phy_provider_lookup(struct device_node *node)
 {
 	struct phy_provider *phy_provider;
-	struct device_node *child;
 
 	list_for_each_entry(phy_provider, &phy_provider_list, list) {
 		if (phy_provider->dev->of_node == node)
 			return phy_provider;
 
-		for_each_child_of_node(phy_provider->children, child)
-			if (child == node) {
-				of_node_put(child);
+		for_each_child_of_node_scoped(phy_provider->children, child)
+			if (child == node)
 				return phy_provider;
-			}
 	}
 
 	return ERR_PTR(-EPROBE_DEFER);
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec 24 04:44:10 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed, 24 Dec 2025 13:44:10 +0100
Subject: [PATCH 3/3] phy: renesas: rcar-gen2: Simplify with scoped for each OF child loop
In-Reply-To: <20251224124407.208354-4-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251224124407.208354-4-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <20251224124407.208354-6-krzysztof.kozlowski@oss.qualcomm.com>

Use scoped for-each loop when iterating over device nodes to make code a
bit simpler.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/phy/renesas/phy-rcar-gen2.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/phy/renesas/phy-rcar-gen2.c b/drivers/phy/renesas/phy-rcar-gen2.c
index c0221e7258c0..89454ea270d3 100644
--- a/drivers/phy/renesas/phy-rcar-gen2.c
+++ b/drivers/phy/renesas/phy-rcar-gen2.c
@@ -337,7 +337,6 @@ static int rcar_gen2_phy_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct rcar_gen2_phy_driver *drv;
 	struct phy_provider *provider;
-	struct device_node *np;
 	void __iomem *base;
 	struct clk *clk;
 	const struct rcar_gen2_phy_data *data;
@@ -379,7 +378,7 @@ static int rcar_gen2_phy_probe(struct platform_device *pdev)
 	if (!drv->channels)
 		return -ENOMEM;
 
-	for_each_child_of_node(dev->of_node, np) {
+	for_each_child_of_node_scoped(dev->of_node, np) {
 		struct rcar_gen2_channel *channel = drv->channels + i;
 		u32 channel_num;
 		int error, n;
@@ -391,7 +390,6 @@ static int rcar_gen2_phy_probe(struct platform_device *pdev)
 		error = of_property_read_u32(np, "reg", &channel_num);
 		if (error || channel_num >= data->num_channels) {
 			dev_err(dev, "Invalid \"reg\" property\n");
-			of_node_put(np);
 			return error;
 		}
 		channel->select_mask = select_mask[channel_num];
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec 24 04:44:32 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed, 24 Dec 2025 13:44:32 +0100
Subject: [PATCH 1/4] mmc: atmel-mci: Simplify with scoped for each OF child loop
Message-ID: <20251224124431.208434-5-krzysztof.kozlowski@oss.qualcomm.com>

Use scoped for-each loop when iterating over device nodes to make code a
bit simpler.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/mmc/host/atmel-mci.c | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index fdf6926ea468..3b4928f5b9b2 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -629,14 +629,13 @@ static int atmci_of_init(struct atmel_mci *host)
 {
 	struct device *dev = host->dev;
 	struct device_node *np = dev->of_node;
-	struct device_node *cnp;
 	u32 slot_id;
 	int err;
 
 	if (!np)
 		return dev_err_probe(dev, -EINVAL, "device node not found\n");
 
-	for_each_child_of_node(np, cnp) {
+	for_each_child_of_node_scoped(np, cnp) {
 		if (of_property_read_u32(cnp, "reg", &slot_id)) {
 			dev_warn(dev, "reg property is missing for %pOF\n", cnp);
 			continue;
@@ -645,7 +644,6 @@ static int atmci_of_init(struct atmel_mci *host)
 		if (slot_id >= ATMCI_MAX_NR_SLOTS) {
 			dev_warn(dev, "can't have more than %d slots\n",
 			         ATMCI_MAX_NR_SLOTS);
-			of_node_put(cnp);
 			break;
 		}
 
@@ -658,10 +656,8 @@ static int atmci_of_init(struct atmel_mci *host)
 					      "cd", GPIOD_IN, "cd-gpios");
 		err = PTR_ERR_OR_ZERO(host->pdata[slot_id].detect_pin);
 		if (err) {
-			if (err != -ENOENT) {
-				of_node_put(cnp);
+			if (err != -ENOENT)
 				return err;
-			}
 			host->pdata[slot_id].detect_pin = NULL;
 		}
 
@@ -673,10 +669,8 @@ static int atmci_of_init(struct atmel_mci *host)
 					      "wp", GPIOD_IN, "wp-gpios");
 		err = PTR_ERR_OR_ZERO(host->pdata[slot_id].wp_pin);
 		if (err) {
-			if (err != -ENOENT) {
-				of_node_put(cnp);
+			if (err != -ENOENT)
 				return err;
-			}
 			host->pdata[slot_id].wp_pin = NULL;
 		}
 	}
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec 24 04:44:33 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed, 24 Dec 2025 13:44:33 +0100
Subject: [PATCH 2/4] mmc: cavium-octeon: Simplify with scoped for each OF child loop
In-Reply-To: <20251224124431.208434-5-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251224124431.208434-5-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <20251224124431.208434-6-krzysztof.kozlowski@oss.qualcomm.com>

Use scoped for-each loop when iterating over device nodes to make code a
bit simpler.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/mmc/host/cavium-octeon.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/cavium-octeon.c b/drivers/mmc/host/cavium-octeon.c
index 0592f356b1e5..8a0daddd9200 100644
--- a/drivers/mmc/host/cavium-octeon.c
+++ b/drivers/mmc/host/cavium-octeon.c
@@ -148,7 +148,7 @@ static void octeon_mmc_dmar_fixup_done(struct cvm_mmc_host *host)
 
 static int octeon_mmc_probe(struct platform_device *pdev)
 {
-	struct device_node *cn, *node = pdev->dev.of_node;
+	struct device_node *node = pdev->dev.of_node;
 	struct cvm_mmc_host *host;
 	void __iomem *base;
 	int mmc_irq[9];
@@ -268,7 +268,7 @@ static int octeon_mmc_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, host);
 
 	i = 0;
-	for_each_child_of_node(node, cn) {
+	for_each_child_of_node_scoped(node, cn) {
 		host->slot_pdev[i] =
 			of_platform_device_create(cn, NULL, &pdev->dev);
 		if (!host->slot_pdev[i]) {
@@ -279,7 +279,6 @@ static int octeon_mmc_probe(struct platform_device *pdev)
 		if (ret) {
 			dev_err(&pdev->dev, "Error populating slots\n");
 			octeon_mmc_set_shared_power(host, 0);
-			of_node_put(cn);
 			goto error;
 		}
 		i++;
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec 24 04:44:34 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed, 24 Dec 2025 13:44:34 +0100
Subject: [PATCH 3/4] mmc: jz4740: Fix Wvoid-pointer-to-enum-cast warning
In-Reply-To: <20251224124431.208434-5-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251224124431.208434-5-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <20251224124431.208434-7-krzysztof.kozlowski@oss.qualcomm.com>

"jz4740" is an enum, thus cast of pointer on 64-bit compile test with
clang W=1 causes:

  jz4740_mmc.c:1055:18: error: cast to smaller integer type 'enum jz4740_mmc_version' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast]

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/mmc/host/jz4740_mmc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c
index 6a0d0250d47b..6a3c26b7c82d 100644
--- a/drivers/mmc/host/jz4740_mmc.c
+++ b/drivers/mmc/host/jz4740_mmc.c
@@ -1052,7 +1052,7 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
 	host = mmc_priv(mmc);
 
 	/* Default if no match is JZ4740 */
-	host->version = (enum jz4740_mmc_version)device_get_match_data(&pdev->dev);
+	host->version = (unsigned long)device_get_match_data(&pdev->dev);
 
 	ret = mmc_of_parse(mmc);
 	if (ret)
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec 24 04:44:35 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed, 24 Dec 2025 13:44:35 +0100
Subject: [PATCH 4/4] mmc: sdhci: aspeed: Simplify with scoped for each OF child loop
In-Reply-To: <20251224124431.208434-5-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251224124431.208434-5-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <20251224124431.208434-8-krzysztof.kozlowski@oss.qualcomm.com>

Use scoped for-each loop when iterating over device nodes to make code a
bit simpler.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/mmc/host/sdhci-of-aspeed.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspeed.c
index ca97b01996b1..4296def69436 100644
--- a/drivers/mmc/host/sdhci-of-aspeed.c
+++ b/drivers/mmc/host/sdhci-of-aspeed.c
@@ -519,7 +519,7 @@ static struct platform_driver aspeed_sdhci_driver = {
 static int aspeed_sdc_probe(struct platform_device *pdev)
 
 {
-	struct device_node *parent, *child;
+	struct device_node *parent;
 	struct aspeed_sdc *sdc;
 	int ret;
 
@@ -548,12 +548,11 @@ static int aspeed_sdc_probe(struct platform_device *pdev)
 	dev_set_drvdata(&pdev->dev, sdc);
 
 	parent = pdev->dev.of_node;
-	for_each_available_child_of_node(parent, child) {
+	for_each_available_child_of_node_scoped(parent, child) {
 		struct platform_device *cpdev;
 
 		cpdev = of_platform_device_create(child, NULL, &pdev->dev);
 		if (!cpdev) {
-			of_node_put(child);
 			ret = -ENODEV;
 			goto err_clk;
 		}
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec 24 04:45:32 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed, 24 Dec 2025 13:45:32 +0100
Subject: [PATCH 1/2] dmaengine: axi-dmac: Simplify with scoped for each OF child loop
Message-ID: <20251224124531.208682-3-krzysztof.kozlowski@oss.qualcomm.com>

Use scoped for-each loop when iterating over device nodes to make code a
bit simpler.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/dma/dma-axi-dmac.c | 15 ++++++---------
 1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c
index 5b06b0dc67ee..45364b1e47f4 100644
--- a/drivers/dma/dma-axi-dmac.c
+++ b/drivers/dma/dma-axi-dmac.c
@@ -925,24 +925,21 @@ static int axi_dmac_parse_chan_dt(struct device_node *of_chan,
 
 static int axi_dmac_parse_dt(struct device *dev, struct axi_dmac *dmac)
 {
-	struct device_node *of_channels, *of_chan;
-	int ret;
+	struct device_node *of_channels;
+	int ret = 0;
 
 	of_channels = of_get_child_by_name(dev->of_node, "adi,channels");
 	if (of_channels == NULL)
 		return -ENODEV;
 
-	for_each_child_of_node(of_channels, of_chan) {
+	for_each_child_of_node_scoped(of_channels, of_chan) {
 		ret = axi_dmac_parse_chan_dt(of_chan, &dmac->chan);
-		if (ret) {
-			of_node_put(of_chan);
-			of_node_put(of_channels);
-			return -EINVAL;
-		}
+		if (ret)
+			break;
 	}
 	of_node_put(of_channels);
 
-	return 0;
+	return ret;
 }
 
 static int axi_dmac_read_chan_config(struct device *dev, struct axi_dmac *dmac)
-- 
2.51.0



From krzysztof.kozlowski at oss.qualcomm.com  Wed Dec 24 04:45:33 2025
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Wed, 24 Dec 2025 13:45:33 +0100
Subject: [PATCH 2/2] dmaengine: xilinx: Simplify with scoped for each OF child loop
In-Reply-To: <20251224124531.208682-3-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251224124531.208682-3-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <20251224124531.208682-4-krzysztof.kozlowski@oss.qualcomm.com>

Use scoped for-each loop when iterating over device nodes to make code a
bit simpler.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 drivers/dma/xilinx/xilinx_dma.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index 89a8254d9cdc..21c8bff07dcf 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -3159,7 +3159,7 @@ static int xilinx_dma_probe(struct platform_device *pdev)
 					= axivdma_clk_init;
 	struct device_node *node = pdev->dev.of_node;
 	struct xilinx_dma_device *xdev;
-	struct device_node *child, *np = pdev->dev.of_node;
+	struct device_node *np = pdev->dev.of_node;
 	u32 num_frames, addr_width = XILINX_DMA_DFAULT_ADDRWIDTH, len_width;
 	int i, err;
 
@@ -3299,12 +3299,10 @@ static int xilinx_dma_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, xdev);
 
 	/* Initialize the channels */
-	for_each_child_of_node(node, child) {
+	for_each_child_of_node_scoped(node, child) {
 		err = xilinx_dma_child_probe(xdev, child);
-		if (err < 0) {
-			of_node_put(child);
+		if (err < 0)
 			goto error;
-		}
 	}
 
 	if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
-- 
2.51.0



From dsimic at manjaro.org  Wed Dec 24 04:55:29 2025
From: dsimic at manjaro.org (Dragan Simic)
Date: Wed, 24 Dec 2025 13:55:29 +0100
Subject: =?utf-8?q?Re=3A?= [PATCH v2 1/4] =?utf-8?q?PCI=3A?==?utf-8?q?_rockchip=3A?= 
 limit RK3399 to =?utf-8?q?2=2E5?= GT/s to prevent damage
In-Reply-To: <CANAwSgQPQUBi6VVb+hZNraMt71vnRpki+YK_at=Luo4aPVtOPg@mail.gmail.com>
References: <cover.1763415705.git.geraldogabriel@gmail.com>
 <eaa9c75ca02a53f8bcc293b8bc73d013e26ec253.1763415706.git.geraldogabriel@gmail.com>
 <CANAwSgQ726J_vnDKEKd94Kq62kx8ToZzUGysz4r3tNAXvfAbGA@mail.gmail.com> <CAEsQvctSY7-RQEQF2TmJU2qKPZOe9TC5g-7Jat0LQKRHYz_6dQ@mail.gmail.com> <CANAwSgQPQUBi6VVb+hZNraMt71vnRpki+YK_at=Luo4aPVtOPg@mail.gmail.com>
Message-ID: <0afea20b-be22-2404-5a8e-c798ed45f2fd@manjaro.org>

Hello Anand,

On Wednesday, December 24, 2025 09:04 CET, Anand Moon <linux.amoon at gmail.com> wrote:
> On Wed, 24 Dec 2025 at 11:08, Geraldo Nascimento
> <geraldogabriel at gmail.com> wrote:
> > On Wed, Dec 24, 2025 at 2:18?AM Anand Moon <linux.amoon at gmail.com> wrote:
> > > On Tue, 18 Nov 2025 at 03:17, Geraldo Nascimento
> > > <geraldogabriel at gmail.com> wrote:
> > > > Shawn Lin from Rockchip has reiterated that there may be danger in using
> > > > their PCIe with 5.0 GT/s speeds. Warn the user if they make a DT change
> > > > from the default and drive at 2.5 GT/s only, even if the DT
> > > > max-link-speed property is invalid or inexistent.
> > > >
> > > > This change is corroborated by RK3399 official datasheet [1], which
> > > > says maximum link speed for this platform is 2.5 GT/s.
> > > >
> > > > [1] https://opensource.rock-chips.com/images/d/d7/Rockchip_RK3399_Datasheet_V2.1-20200323.pdf
> > > >
> > > To accurately determine the operating speed, we can leverage the
> > > PCIE_CLIENT_BASIC_STATUS0/1 fields.
> > > This provides a dynamic mechanism to resolve the issue.
> > >
> > > [1] https://github.com/torvalds/linux/blob/master/drivers/pci/controller/pcie-rockchip-ep.c#L533-L595
> >
> > not to put you down but I think your approach adds unnecessary complexity.
> >
> > All I care really is that the Kernel Project isn't blamed in the
> > future if someone happens to lose their data.
> >
> Allow the hardware to negotiate the link speed based on the
> available number of lanes.
> I don?t anticipate any data loss, since PCIe will automatically
> configure the device speed with link training..

Please, note that this isn't about performing auto negotiation
and following its results, but about "artificially" limiting the
PCIe link speed to 2.5 GT/s on RK3399, because it's well known
by Rockchip that 5 GT/s on RK3399's PCIe interface may cause
issues and data corruption in certain corner cases.



From krzk at kernel.org  Wed Dec 24 05:05:04 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 24 Dec 2025 14:05:04 +0100
Subject: [PATCH v3 01/15] include: dt-bindings: add LAN969x clock bindings
In-Reply-To: <CA+HBbNGym6Q9b166n-P=h_JssOHm0yfyL73JZ+G9P81muK=g4A@mail.gmail.com>
References: <20251223201921.1332786-1-robert.marko@sartura.hr>
 <20251223201921.1332786-2-robert.marko@sartura.hr>
 <20251224-berserk-mackerel-of-snow-4cae54@quoll>
 <CA+HBbNGym6Q9b166n-P=h_JssOHm0yfyL73JZ+G9P81muK=g4A@mail.gmail.com>
Message-ID: <78bf252c-fd5e-4a36-b1a3-ca8ed26fde7a@kernel.org>

On 24/12/2025 11:30, Robert Marko wrote:
> On Wed, Dec 24, 2025 at 11:21?AM Krzysztof Kozlowski <krzk at kernel.org> wrote:
>>
>> On Tue, Dec 23, 2025 at 09:16:12PM +0100, Robert Marko wrote:
>>> Add the required LAN969x clock bindings.
>>
>> I do not see clock bindings actually here. Where is the actual binding?
>> Commit msg does not help me at all to understand why you are doing this
>> without actual required bindings.
> 
> I guess it is a bit confusing, there is no schema here, these are the
> clock indexes that
> reside in dt-bindings and are used by the SoC DTSI.

I understand as not used by drivers? Then no ABI and there is no point
in putting them into bindings.

Best regards,
Krzysztof


From ryan.roberts at arm.com  Wed Dec 24 05:24:39 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Wed, 24 Dec 2025 13:24:39 +0000
Subject: [PATCH v4 1/5] mm: rmap: support batched checks of the references
 for large folios
In-Reply-To: <e9ff5fa689740f3b6f3ed1c1ec0e3244f20c1f06.1766455378.git.baolin.wang@linux.alibaba.com>
References: <cover.1766455377.git.baolin.wang@linux.alibaba.com>
 <e9ff5fa689740f3b6f3ed1c1ec0e3244f20c1f06.1766455378.git.baolin.wang@linux.alibaba.com>
Message-ID: <ec49f0fe-9df8-4762-b315-240cbb1ed3ce@arm.com>

On 23/12/2025 05:48, Baolin Wang wrote:
> Currently, folio_referenced_one() always checks the young flag for each PTE
> sequentially, which is inefficient for large folios. This inefficiency is
> especially noticeable when reclaiming clean file-backed large folios, where
> folio_referenced() is observed as a significant performance hotspot.
> 
> Moreover, on Arm64 architecture, which supports contiguous PTEs, there is already
> an optimization to clear the young flags for PTEs within a contiguous range.
> However, this is not sufficient. We can extend this to perform batched operations
> for the entire large folio (which might exceed the contiguous range: CONT_PTE_SIZE).
> 
> Introduce a new API: clear_flush_young_ptes() to facilitate batched checking
> of the young flags and flushing TLB entries, thereby improving performance
> during large folio reclamation. And it will be overridden by the architecture
> that implements a more efficient batch operation in the following patches.
> 
> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>

With the 2 niggles below addressed:

Reviewed-by: Ryan Roberts <ryan.roberts at arm.com>

> ---
>  include/linux/mmu_notifier.h |  9 +++++----
>  include/linux/pgtable.h      | 35 +++++++++++++++++++++++++++++++++++
>  mm/rmap.c                    | 29 +++++++++++++++++++++++++++--
>  3 files changed, 67 insertions(+), 6 deletions(-)
> 
> diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h
> index d1094c2d5fb6..dbbdcef4abf1 100644
> --- a/include/linux/mmu_notifier.h
> +++ b/include/linux/mmu_notifier.h
> @@ -515,16 +515,17 @@ static inline void mmu_notifier_range_init_owner(
>  	range->owner = owner;
>  }
>  
> -#define ptep_clear_flush_young_notify(__vma, __address, __ptep)		\
> +#define ptep_clear_flush_young_notify(__vma, __address, __ptep, __nr)	\

I think I previously suggested that this should be renamed to
clear_flush_young_ptes_notify() given that it is now a batch operation. Were
others against that or did you forget?

>  ({									\
>  	int __young;							\
>  	struct vm_area_struct *___vma = __vma;				\
>  	unsigned long ___address = __address;				\
> -	__young = ptep_clear_flush_young(___vma, ___address, __ptep);	\
> +	unsigned int ___nr = __nr;					\
> +	__young = clear_flush_young_ptes(___vma, ___address, __ptep, ___nr);	\
>  	__young |= mmu_notifier_clear_flush_young(___vma->vm_mm,	\
>  						  ___address,		\
>  						  ___address +		\
> -							PAGE_SIZE);	\
> +						  ___nr * PAGE_SIZE);	\
>  	__young;							\
>  })
>  
> @@ -650,7 +651,7 @@ static inline void mmu_notifier_subscriptions_destroy(struct mm_struct *mm)
>  
>  #define mmu_notifier_range_update_to_read_only(r) false
>  
> -#define ptep_clear_flush_young_notify ptep_clear_flush_young
> +#define ptep_clear_flush_young_notify clear_flush_young_ptes
>  #define pmdp_clear_flush_young_notify pmdp_clear_flush_young
>  #define ptep_clear_young_notify ptep_test_and_clear_young
>  #define pmdp_clear_young_notify pmdp_test_and_clear_young
> diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
> index 2f0dd3a4ace1..fcf7a7820061 100644
> --- a/include/linux/pgtable.h
> +++ b/include/linux/pgtable.h
> @@ -1087,6 +1087,41 @@ static inline void wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
>  }
>  #endif
>  
> +#ifndef clear_flush_young_ptes
> +/**
> + * clear_flush_young_ptes - Clear the access bit and perform a TLB flush for PTEs
> + *			    that map consecutive pages of the same folio.
> + * @vma: The virtual memory area the pages are mapped into.
> + * @addr: Address the first page is mapped at.
> + * @ptep: Page table pointer for the first entry.
> + * @nr: Number of entries to clear access bit.
> + *
> + * May be overridden by the architecture; otherwise, implemented as a simple
> + * loop over ptep_clear_flush_young().
> + *
> + * Note that PTE bits in the PTE range besides the PFN can differ. For example,
> + * some PTEs might be write-protected.
> + *
> + * Context: The caller holds the page table lock.  The PTEs map consecutive
> + * pages that belong to the same folio.  The PTEs are all in the same PMD.
> + */
> +static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
> +					 unsigned long addr, pte_t *ptep,
> +					 unsigned int nr)
> +{
> +	int young;
> +
> +	young = ptep_clear_flush_young(vma, addr, ptep);
> +	while (--nr) {
> +		ptep++;
> +		addr += PAGE_SIZE;
> +		young |= ptep_clear_flush_young(vma, addr, ptep);
> +	}

I think it's better to avoid the two ptep_clear_flush_young() calls if we can.
Personally I think we should just go for the simple:

	for (i = 0; i < nr; ++i, ++ptep, addr += PAGE_SIZE)
		young |= ptep_clear_flush_young(vma, addr, ptep);

> +
> +	return young;
> +}
> +#endif
> +
>  /*
>   * On some architectures hardware does not set page access bit when accessing
>   * memory page, it is responsibility of software setting this bit. It brings
> diff --git a/mm/rmap.c b/mm/rmap.c
> index d6799afe1114..a0fc05f5966f 100644
> --- a/mm/rmap.c
> +++ b/mm/rmap.c
> @@ -827,9 +827,11 @@ static bool folio_referenced_one(struct folio *folio,
>  	struct folio_referenced_arg *pra = arg;
>  	DEFINE_FOLIO_VMA_WALK(pvmw, folio, vma, address, 0);
>  	int ptes = 0, referenced = 0;
> +	unsigned int nr;
>  
>  	while (page_vma_mapped_walk(&pvmw)) {
>  		address = pvmw.address;
> +		nr = 1;
>  
>  		if (vma->vm_flags & VM_LOCKED) {
>  			ptes++;
> @@ -874,9 +876,24 @@ static bool folio_referenced_one(struct folio *folio,
>  			if (lru_gen_look_around(&pvmw))
>  				referenced++;
>  		} else if (pvmw.pte) {
> +			if (folio_test_large(folio)) {
> +				unsigned long end_addr =
> +					pmd_addr_end(address, vma->vm_end);
> +				unsigned int max_nr =
> +					(end_addr - address) >> PAGE_SHIFT;
> +				pte_t pteval = ptep_get(pvmw.pte);
> +
> +				nr = folio_pte_batch(folio, pvmw.pte,
> +						     pteval, max_nr);
> +			}
> +
> +			ptes += nr;
>  			if (ptep_clear_flush_young_notify(vma, address,
> -						pvmw.pte))
> +						pvmw.pte, nr))
>  				referenced++;
> +			/* Skip the batched PTEs */
> +			pvmw.pte += nr - 1;
> +			pvmw.address += (nr - 1) * PAGE_SIZE;
>  		} else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) {
>  			if (pmdp_clear_flush_young_notify(vma, address,
>  						pvmw.pmd))
> @@ -886,7 +903,15 @@ static bool folio_referenced_one(struct folio *folio,
>  			WARN_ON_ONCE(1);
>  		}
>  
> -		pra->mapcount--;
> +		pra->mapcount -= nr;
> +		/*
> +		 * If we are sure that we batched the entire folio,
> +		 * we can just optimize and stop right here.
> +		 */
> +		if (ptes == pvmw.nr_pages) {
> +			page_vma_mapped_walk_done(&pvmw);
> +			break;
> +		}
>  	}
>  
>  	if (referenced)



From paul at crapouillou.net  Wed Dec 24 05:30:56 2025
From: paul at crapouillou.net (Paul Cercueil)
Date: Wed, 24 Dec 2025 14:30:56 +0100
Subject: [PATCH 3/4] mmc: jz4740: Fix Wvoid-pointer-to-enum-cast warning
In-Reply-To: <20251224124431.208434-7-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251224124431.208434-5-krzysztof.kozlowski@oss.qualcomm.com>
	 <20251224124431.208434-7-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <e661a947f0cefb1651dcd3f7f57855313ad9fd7a.camel@crapouillou.net>

Hi Krzysztof,

Le mercredi 24 d?cembre 2025 ? 13:44 +0100, Krzysztof Kozlowski a
?crit?:
> "jz4740" is an enum, thus cast of pointer on 64-bit compile test with
> clang W=1 causes:
> 
> ? jz4740_mmc.c:1055:18: error: cast to smaller integer type 'enum
> jz4740_mmc_version' from 'const void *' [-Werror,-Wvoid-pointer-to-
> enum-cast]
> 
> Signed-off-by: Krzysztof Kozlowski
> <krzysztof.kozlowski at oss.qualcomm.com>

Reviewed-by: Paul Cercueil <paul at crapouillou.net>

Cheers,
-Paul

> ---
> ?drivers/mmc/host/jz4740_mmc.c | 2 +-
> ?1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/mmc/host/jz4740_mmc.c
> b/drivers/mmc/host/jz4740_mmc.c
> index 6a0d0250d47b..6a3c26b7c82d 100644
> --- a/drivers/mmc/host/jz4740_mmc.c
> +++ b/drivers/mmc/host/jz4740_mmc.c
> @@ -1052,7 +1052,7 @@ static int jz4740_mmc_probe(struct
> platform_device* pdev)
> ?	host = mmc_priv(mmc);
> ?
> ?	/* Default if no match is JZ4740 */
> -	host->version = (enum
> jz4740_mmc_version)device_get_match_data(&pdev->dev);
> +	host->version = (unsigned long)device_get_match_data(&pdev-
> >dev);
> ?
> ?	ret = mmc_of_parse(mmc);
> ?	if (ret)


From james.clark at linaro.org  Wed Dec 24 05:40:44 2025
From: james.clark at linaro.org (James Clark)
Date: Wed, 24 Dec 2025 13:40:44 +0000
Subject: [PATCH] perf unwind-libdw: fix a cross-arch unwinding bug
In-Reply-To: <20251223-cross-arch-unwind-v1-1-4d71ee7db512@skydio.com>
References: <20251223-cross-arch-unwind-v1-1-4d71ee7db512@skydio.com>
Message-ID: <c25d5032-5a41-4e95-ae76-3466875241a0@linaro.org>



On 24/12/2025 2:19 am, Shimin Guo via B4 Relay wrote:
> From: Shimin Guo <shimin.guo at skydio.com>
> 
> The set_initial_registers field of Dwfl_Thread_Callbacks needs to be set
> according to the arch of the stack samples being analyzed, not the arch
> that perf itself is built for. Currently perf fails to unwind stack samples
> collected from archs different from that of the host perf is running on.
> This patch moves the arch-specific implementations of set_initial_registers
> from tools/perf/arch to tools/perf/utli/unwind-libdw-arch, similar to the
> way the perf-regs-arch folder contains arch-specific functions related to
> registers, and chooses the implementation based on the arch of the data
> being processed.
> 
> Signed-off-by: Shimin Guo <shimin.guo at skydio.com>
> ---
> checkpatch flagged three issues:
>> tools/perf/util/unwind-libdw-arch/Build:232: WARNING: added, moved
> or deleted file(s), does MAINTAINERS need updating?
> 
> Not sure what to do about that.
> 

You don't need to do anything here because there's a blanket rule for 
the Perf dir.

>> checkpatch.pl: tools/perf/util/unwind-libdw.c:228: WARNING:
> Non-declarative macros with multiple statements should be enclosed in
> a do - while loop

I think you can ignore this one.

>> checkpatch.pl: tools/perf/util/unwind-libdw.c:228: WARNING: macros
> should not use a trailing semicolon
> 
> Are these two false positives? I'm defining static global variables
> with the macro.

But I don't see a reason not to follow this one, just remove the semicolon.

> ---
>   tools/perf/arch/arm/util/Build                     |  1 -
>   tools/perf/arch/arm64/util/Build                   |  1 -
>   tools/perf/arch/csky/util/Build                    |  2 -
>   tools/perf/arch/powerpc/util/Build                 |  1 -
>   tools/perf/arch/riscv/util/Build                   |  1 -
>   tools/perf/arch/s390/util/Build                    |  2 -
>   tools/perf/arch/x86/util/Build                     |  1 -
>   tools/perf/util/Build                              |  1 +
>   tools/perf/util/unwind-libdw-arch/Build            |  8 ++++
>   .../unwind-libdw-arch/unwind-libdw-arm.c}          |  4 +-
>   .../unwind-libdw-arch/unwind-libdw-arm64.c}        |  4 +-
>   .../unwind-libdw-arch/unwind-libdw-csky.c}         |  6 +--
>   .../unwind-libdw-arch/unwind-libdw-loongarch.c}    |  4 +-
>   .../unwind-libdw-arch/unwind-libdw-powerpc.c}      |  4 +-
>   .../unwind-libdw-arch/unwind-libdw-riscv.c}        |  4 +-
>   .../unwind-libdw-arch/unwind-libdw-s390.c}         |  6 +--
>   .../unwind-libdw-arch/unwind-libdw-x86.c}          |  2 +-
>   tools/perf/util/unwind-libdw.c                     | 49 +++++++++++++++++++---
>   tools/perf/util/unwind-libdw.h                     | 10 ++++-
>   19 files changed, 79 insertions(+), 32 deletions(-)
> 
> diff --git a/tools/perf/arch/arm/util/Build b/tools/perf/arch/arm/util/Build
> index fd695e1fdaee2ccc300a206131b8b38a763b00ce..3291f893b943df0722dff583523fff4ae79919bc 100644
> --- a/tools/perf/arch/arm/util/Build
> +++ b/tools/perf/arch/arm/util/Build
> @@ -1,6 +1,5 @@
>   perf-util-y += perf_regs.o
>   
>   perf-util-$(CONFIG_LOCAL_LIBUNWIND)    += unwind-libunwind.o
> -perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
>   
>   perf-util-y += pmu.o auxtrace.o cs-etm.o
> diff --git a/tools/perf/arch/arm64/util/Build b/tools/perf/arch/arm64/util/Build
> index d63881081d2eb1e9a83eabf82104d75308f7fc79..0177af19cc00038d6a6005592ddc530bf7eb1557 100644
> --- a/tools/perf/arch/arm64/util/Build
> +++ b/tools/perf/arch/arm64/util/Build
> @@ -1,4 +1,3 @@
> -perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
>   perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
>   perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
>   perf-util-y += ../../arm/util/auxtrace.o
> diff --git a/tools/perf/arch/csky/util/Build b/tools/perf/arch/csky/util/Build
> index 5e6ea82c42021d3d5651ca4c4a3a6e5138574e4e..6b2d0e021b11464e46d6b53974260d32ea969732 100644
> --- a/tools/perf/arch/csky/util/Build
> +++ b/tools/perf/arch/csky/util/Build
> @@ -1,3 +1 @@
>   perf-util-y += perf_regs.o
> -
> -perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
> diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build
> index 3d0d5427aef7f26a8c05c883cc7ad763f08cbb30..5fd28ec713a4db74ecd1d26866a65ddb20e94bd3 100644
> --- a/tools/perf/arch/powerpc/util/Build
> +++ b/tools/perf/arch/powerpc/util/Build
> @@ -9,5 +9,4 @@ perf-util-y += evsel.o
>   perf-util-$(CONFIG_LIBDW) += skip-callchain-idx.o
>   
>   perf-util-$(CONFIG_LIBUNWIND) += unwind-libunwind.o
> -perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
>   perf-util-y += auxtrace.o
> diff --git a/tools/perf/arch/riscv/util/Build b/tools/perf/arch/riscv/util/Build
> index 58a672246024dd0f72e767d11e9958bd9913ec3c..628b9ebd418bde8cdf1ab1332bf79f7c9d50760e 100644
> --- a/tools/perf/arch/riscv/util/Build
> +++ b/tools/perf/arch/riscv/util/Build
> @@ -2,4 +2,3 @@ perf-util-y += perf_regs.o
>   perf-util-y += header.o
>   
>   perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
> -perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
> diff --git a/tools/perf/arch/s390/util/Build b/tools/perf/arch/s390/util/Build
> index c64eb18dbdae93adafabf8542e4c9a763ecfe057..5391d26fedd46b7d30a1bef0bff2ec2d58ec30ed 100644
> --- a/tools/perf/arch/s390/util/Build
> +++ b/tools/perf/arch/s390/util/Build
> @@ -2,8 +2,6 @@ perf-util-y += header.o
>   perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
>   perf-util-y += perf_regs.o
>   
> -perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
> -
>   perf-util-y += machine.o
>   perf-util-y += pmu.o
>   
> diff --git a/tools/perf/arch/x86/util/Build b/tools/perf/arch/x86/util/Build
> index c0dc5965f3624a6f02525a04d287dff755356d20..fad256252bb95a8f8350b6bb1a54e8074eaebbec 100644
> --- a/tools/perf/arch/x86/util/Build
> +++ b/tools/perf/arch/x86/util/Build
> @@ -12,7 +12,6 @@ perf-util-y += evsel.o
>   perf-util-y += iostat.o
>   
>   perf-util-$(CONFIG_LOCAL_LIBUNWIND)    += unwind-libunwind.o
> -perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
>   
>   perf-util-y += auxtrace.o
>   perf-util-y += archinsn.o
> diff --git a/tools/perf/util/Build b/tools/perf/util/Build
> index 1c2a43e1dc68e7f751ec6082352b10de9ffeea62..15f8a4f4b24a46b6300e824f672dd9c0d5b7865f 100644
> --- a/tools/perf/util/Build
> +++ b/tools/perf/util/Build
> @@ -226,6 +226,7 @@ perf-util-$(CONFIG_LIBDW) += debuginfo.o
>   perf-util-$(CONFIG_LIBDW) += annotate-data.o
>   
>   perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
> +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-arch/
>   perf-util-$(CONFIG_LOCAL_LIBUNWIND)    += unwind-libunwind-local.o
>   perf-util-$(CONFIG_LIBUNWIND)          += unwind-libunwind.o
>   perf-util-$(CONFIG_LIBUNWIND_X86)      += libunwind/x86_32.o
> diff --git a/tools/perf/util/unwind-libdw-arch/Build b/tools/perf/util/unwind-libdw-arch/Build
> new file mode 100644
> index 0000000000000000000000000000000000000000..e016d54ae2a40ecba47156c8f09cb72156105727
> --- /dev/null
> +++ b/tools/perf/util/unwind-libdw-arch/Build
> @@ -0,0 +1,8 @@
> +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-x86.o
> +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-arm.o
> +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-arm64.o
> +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-csky.o
> +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-loongarch.o
> +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-powerpc.o
> +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-riscv.o
> +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-s390.o
> \ No newline at end of file
> diff --git a/tools/perf/arch/arm/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-arm.c
> similarity index 88%
> rename from tools/perf/arch/arm/util/unwind-libdw.c
> rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-arm.c
> index fbb643f224ec4b27ce9d67051fe0bc4ad555b05e..c2718d6b6cff131cd67883e24bb0d3d963c8095a 100644
> --- a/tools/perf/arch/arm/util/unwind-libdw.c
> +++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-arm.c
> @@ -1,11 +1,11 @@
>   // SPDX-License-Identifier: GPL-2.0
>   #include <elfutils/libdwfl.h>
> -#include "perf_regs.h"
> +#include "../../../arch/arm/include/uapi/asm/perf_regs.h"
>   #include "../../../util/unwind-libdw.h"
>   #include "../../../util/perf_regs.h"
>   #include "../../../util/sample.h"
>   
> -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
> +bool libdw_set_initial_registers_arm(Dwfl_Thread *thread, void *arg)
>   {
>   	struct unwind_info *ui = arg;
>   	struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
> diff --git a/tools/perf/arch/arm64/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-arm64.c
> similarity index 92%
> rename from tools/perf/arch/arm64/util/unwind-libdw.c
> rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-arm64.c
> index b89b0a7e5ad919fed23643d219fbdc3d84deff1e..87602503e057badc6efd37169cc60c96cf3949ab 100644
> --- a/tools/perf/arch/arm64/util/unwind-libdw.c
> +++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-arm64.c
> @@ -1,11 +1,11 @@
>   // SPDX-License-Identifier: GPL-2.0
>   #include <elfutils/libdwfl.h>
> -#include "perf_regs.h"
> +#include "../../../arch/arm64/include/uapi/asm/perf_regs.h"
>   #include "../../../util/unwind-libdw.h"
>   #include "../../../util/perf_regs.h"
>   #include "../../../util/sample.h"
>   
> -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
> +bool libdw_set_initial_registers_arm64(Dwfl_Thread *thread, void *arg)
>   {
>   	struct unwind_info *ui = arg;
>   	struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
> diff --git a/tools/perf/arch/csky/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-csky.c
> similarity index 92%
> rename from tools/perf/arch/csky/util/unwind-libdw.c
> rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-csky.c
> index b20b1569783d7e982e91b1b40120d29ccf2f01d1..889d3b788931f3af55b03ef8b91d5def364972e5 100644
> --- a/tools/perf/arch/csky/util/unwind-libdw.c
> +++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-csky.c
> @@ -2,12 +2,12 @@
>   // Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd.
>   
>   #include <elfutils/libdwfl.h>
> -#include "perf_regs.h"
> +#include "../../../arch/csky/include/uapi/asm/perf_regs.h"
>   #include "../../util/unwind-libdw.h"
>   #include "../../util/perf_regs.h"
> -#include "../../util/event.h"
> +#include "../../util/sample.h"
>   
> -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
> +bool libdw_set_initial_registers_csky(Dwfl_Thread *thread, void *arg)
>   {
>   	struct unwind_info *ui = arg;
>   	struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
> diff --git a/tools/perf/arch/loongarch/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-loongarch.c
> similarity index 91%
> rename from tools/perf/arch/loongarch/util/unwind-libdw.c
> rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-loongarch.c
> index 60b1144bedd5f325e1512eeab05c29a1e8de2b03..1c5753ace6f63be771aa92365d3174ad8ed3a6fd 100644
> --- a/tools/perf/arch/loongarch/util/unwind-libdw.c
> +++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-loongarch.c
> @@ -2,12 +2,12 @@
>   /* Copyright (C) 2020-2023 Loongson Technology Corporation Limited */
>   
>   #include <elfutils/libdwfl.h>
> -#include "perf_regs.h"
> +#include "../../../arch/loongarch/include/uapi/asm/perf_regs.h"
>   #include "../../util/unwind-libdw.h"
>   #include "../../util/perf_regs.h"
>   #include "../../util/sample.h"
>   
> -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
> +bool libdw_set_initial_registers_loongarch(Dwfl_Thread *thread, void *arg)
>   {
>   	struct unwind_info *ui = arg;
>   	struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
> diff --git a/tools/perf/arch/powerpc/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-powerpc.c
> similarity index 93%
> rename from tools/perf/arch/powerpc/util/unwind-libdw.c
> rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-powerpc.c
> index 82d0c28ae3459ecdb0039cac1f534420d142739b..28635af3c4aa420faa4de7e53428d82917f78021 100644
> --- a/tools/perf/arch/powerpc/util/unwind-libdw.c
> +++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-powerpc.c
> @@ -1,7 +1,7 @@
>   // SPDX-License-Identifier: GPL-2.0
>   #include <elfutils/libdwfl.h>
>   #include <linux/kernel.h>
> -#include "perf_regs.h"
> +#include "../../../arch/powerpc/include/uapi/asm/perf_regs.h"
>   #include "../../../util/unwind-libdw.h"
>   #include "../../../util/perf_regs.h"
>   #include "../../../util/sample.h"
> @@ -13,7 +13,7 @@ static const int special_regs[3][2] = {
>   	{ 109, PERF_REG_POWERPC_CTR },
>   };
>   
> -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
> +bool libdw_set_initial_registers_powerpc(Dwfl_Thread *thread, void *arg)
>   {
>   	struct unwind_info *ui = arg;
>   	struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
> diff --git a/tools/perf/arch/riscv/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-riscv.c
> similarity index 92%
> rename from tools/perf/arch/riscv/util/unwind-libdw.c
> rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-riscv.c
> index dc1476e16321736de897ad53a00fbc813bd706db..2a5442b3b5bdc27252378de0073deb8a620f8779 100644
> --- a/tools/perf/arch/riscv/util/unwind-libdw.c
> +++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-riscv.c
> @@ -2,12 +2,12 @@
>   /* Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd. */
>   
>   #include <elfutils/libdwfl.h>
> -#include "perf_regs.h"
> +#include "../../../arch/riscv/include/uapi/asm/perf_regs.h"
>   #include "../../util/unwind-libdw.h"
>   #include "../../util/perf_regs.h"
>   #include "../../util/sample.h"
>   
> -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
> +bool libdw_set_initial_registers_riscv(Dwfl_Thread *thread, void *arg)
>   {
>   	struct unwind_info *ui = arg;
>   	struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
> diff --git a/tools/perf/arch/s390/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-s390.c
> similarity index 89%
> rename from tools/perf/arch/s390/util/unwind-libdw.c
> rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-s390.c
> index c27c7a0d1076c890c35ba19543932c4ed5ac9c2a..18d44074a55bc1c7fa2d7150afc1f1a93d4eadf8 100644
> --- a/tools/perf/arch/s390/util/unwind-libdw.c
> +++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-s390.c
> @@ -4,11 +4,11 @@
>   #include "../../util/perf_regs.h"
>   #include "../../util/event.h"
>   #include "../../util/sample.h"
> -#include "dwarf-regs-table.h"
> -#include "perf_regs.h"
> +#include "../../arch/s390/include/dwarf-regs-table.h"
> +#include "../../../arch/s390/include/uapi/asm/perf_regs.h"
>   
>   
> -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
> +bool libdw_set_initial_registers_s390(Dwfl_Thread *thread, void *arg)
>   {
>   	struct unwind_info *ui = arg;
>   	struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
> diff --git a/tools/perf/arch/x86/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-x86.c
> similarity index 94%
> rename from tools/perf/arch/x86/util/unwind-libdw.c
> rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-x86.c
> index 798493e887d7308cb293e29e4ba11054d0fda722..822e799fe1543d82dab27a8efeada3f5cde08a44 100644
> --- a/tools/perf/arch/x86/util/unwind-libdw.c
> +++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-x86.c

You missed converting the unwind-libdw-x86.c perf_regs.h paths to a 
static arch so now Perf can only be built on x86. If you try to build 
for another arch then you get the local header and then missing x86 
definitions.

Unfortunately you also have to convert the one in 
tools/perf/arch/x86/include/perf_regs.h which is a bit weird, but the 
build seems to work.

Other than that, looks good.

> @@ -5,7 +5,7 @@
>   #include "../../../util/perf_regs.h"
>   #include "util/sample.h"
>   
> -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
> +bool libdw_set_initial_registers_x86(Dwfl_Thread *thread, void *arg)
>   {
>   	struct unwind_info *ui = arg;
>   	struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
> diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
> index ae70fb56a05729b9f06a411d162eabebbf29ac52..4a0f13bc5af99de446d440c551c718ef0187e195 100644
> --- a/tools/perf/util/unwind-libdw.c
> +++ b/tools/perf/util/unwind-libdw.c
> @@ -225,12 +225,46 @@ static bool memory_read(Dwfl *dwfl __maybe_unused, Dwarf_Addr addr, Dwarf_Word *
>   	return true;
>   }
>   
> -static const Dwfl_Thread_Callbacks callbacks = {
> -	.next_thread		= next_thread,
> -	.memory_read		= memory_read,
> -	.set_initial_registers	= libdw__arch_set_initial_registers,
> +#define DEFINE_DWFL_THREAD_CALLBACKS(arch)                           \
> +static const Dwfl_Thread_Callbacks callbacks_##arch = {              \
> +	.next_thread           = next_thread,                        \
> +	.memory_read           = memory_read,                        \
> +	.set_initial_registers = libdw_set_initial_registers_##arch, \
>   };
>   
> +DEFINE_DWFL_THREAD_CALLBACKS(x86)
> +DEFINE_DWFL_THREAD_CALLBACKS(arm)
> +DEFINE_DWFL_THREAD_CALLBACKS(arm64)
> +DEFINE_DWFL_THREAD_CALLBACKS(csky)
> +DEFINE_DWFL_THREAD_CALLBACKS(loongarch)
> +DEFINE_DWFL_THREAD_CALLBACKS(powerpc)
> +DEFINE_DWFL_THREAD_CALLBACKS(riscv)
> +DEFINE_DWFL_THREAD_CALLBACKS(s390)
> +
> +static const Dwfl_Thread_Callbacks *get_thread_callbacks(const char *arch)
> +{
> +	if (!strcmp(arch, "arm"))
> +		return &callbacks_arm;
> +	else if (!strcmp(arch, "arm64"))
> +		return &callbacks_arm64;
> +	else if (!strcmp(arch, "csky"))
> +		return &callbacks_csky;
> +	else if (!strcmp(arch, "loongarch"))
> +		return &callbacks_loongarch;
> +	else if (!strcmp(arch, "powerpc"))
> +		return &callbacks_powerpc;
> +	else if (!strcmp(arch, "riscv"))
> +		return &callbacks_riscv;
> +	else if (!strcmp(arch, "s390"))
> +		return &callbacks_s390;
> +	else if (!strcmp(arch, "x86"))
> +		return &callbacks_x86;
> +
> +	pr_err("Fail to get thread callbacks for arch %s, returns NULL\n",
> +	       arch);
> +	return NULL;
> +}
> +
>   static int
>   frame_callback(Dwfl_Frame *state, void *arg)
>   {
> @@ -278,6 +312,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
>   	const char *arch = perf_env__arch(ui_buf.machine->env);
>   	Dwarf_Word ip;
>   	int err = -EINVAL, i;
> +	const Dwfl_Thread_Callbacks *callbacks;
>   
>   	if (!data->user_regs || !data->user_regs->regs)
>   		return -EINVAL;
> @@ -300,7 +335,11 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
>   	if (err)
>   		goto out;
>   
> -	err = !dwfl_attach_state(ui->dwfl, EM_NONE, thread__tid(thread), &callbacks, ui);
> +	callbacks = get_thread_callbacks(arch);
> +	if (!callbacks)
> +		goto out;
> +
> +	err = !dwfl_attach_state(ui->dwfl, EM_NONE, thread__tid(thread), callbacks, ui);
>   	if (err)
>   		goto out;
>   
> diff --git a/tools/perf/util/unwind-libdw.h b/tools/perf/util/unwind-libdw.h
> index 8c88bc4f2304b59561ffd482469ca63ce0f531f0..574b29848cce31e6bfd93021f752b518cebf73b7 100644
> --- a/tools/perf/util/unwind-libdw.h
> +++ b/tools/perf/util/unwind-libdw.h
> @@ -9,7 +9,15 @@ struct machine;
>   struct perf_sample;
>   struct thread;
>   
> -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg);
> +bool libdw_set_initial_registers_x86(Dwfl_Thread *thread, void *arg);
> +bool libdw_set_initial_registers_arm(Dwfl_Thread *thread, void *arg);
> +bool libdw_set_initial_registers_arm64(Dwfl_Thread *thread, void *arg);
> +bool libdw_set_initial_registers_csky(Dwfl_Thread *thread, void *arg);
> +bool libdw_set_initial_registers_loongarch(Dwfl_Thread *thread, void *arg);
> +bool libdw_set_initial_registers_mips(Dwfl_Thread *thread, void *arg);
> +bool libdw_set_initial_registers_powerpc(Dwfl_Thread *thread, void *arg);
> +bool libdw_set_initial_registers_riscv(Dwfl_Thread *thread, void *arg);
> +bool libdw_set_initial_registers_s390(Dwfl_Thread *thread, void *arg);
>   
>   struct unwind_info {
>   	Dwfl			*dwfl;
> 
> ---
> base-commit: cbd41c6d4c26c161a2b0e70ad411d3885ff13507
> change-id: 20251223-cross-arch-unwind-d890d6a5ff0a
> 
> Best regards,



From frederic at kernel.org  Wed Dec 24 05:44:47 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:44:47 +0100
Subject: [PATCH 00/33 v5] cpuset/isolation: Honour kthreads preferred affinity
Message-ID: <20251224134520.33231-1-frederic@kernel.org>

Hi,

The kthread code was enhanced lately to provide an infrastructure which
manages the preferred affinity of unbound kthreads (node or custom
cpumask) against housekeeping constraints and CPU hotplug events.

One crucial missing piece is cpuset: when an isolated partition is
created, deleted, or its CPUs updated, all the unbound kthreads in the
top cpuset are affine to _all_ the non-isolated CPUs, possibly breaking
their preferred affinity along the way

Solve this with performing the kthreads affinity update from cpuset to
the kthreads consolidated relevant code instead so that preferred
affinities are honoured.

The dispatch of the new cpumasks to workqueues and kthreads is performed
by housekeeping, as per the nice Tejun's suggestion.

As a welcome side effect, HK_TYPE_DOMAIN then integrates both the set
from isolcpus= and cpuset isolated partitions. Housekeeping cpumasks are
now modifyable with specific synchronization. A big step toward making
nohz_full= also mutable through cpuset in the future.

Changes since v4:

* Add more tags

* Rebase on v6.19-rc2 with latest cpuset changes

* Accomodate timers migration isolation

* Rename housekeeping_update() parameter from mask to isol_mask (Chen Ridong)

* Link housekeeping documentation to core-api

git://git.kernel.org/pub/scm/linux/kernel/git/frederic/linux-dynticks.git
	kthread/core-v5

HEAD: 3c0ee047f05f361f215521424f5e789dfffcafc1

Merry Christmas,
	Frederic
---

Frederic Weisbecker (33):
      PCI: Prepare to protect against concurrent isolated cpuset change
      cpu: Revert "cpu/hotplug: Prevent self deadlock on CPU hot-unplug"
      memcg: Prepare to protect against concurrent isolated cpuset change
      mm: vmstat: Prepare to protect against concurrent isolated cpuset change
      sched/isolation: Save boot defined domain flags
      cpuset: Convert boot_hk_cpus to use HK_TYPE_DOMAIN_BOOT
      driver core: cpu: Convert /sys/devices/system/cpu/isolated to use HK_TYPE_DOMAIN_BOOT
      net: Keep ignoring isolated cpuset change
      block: Protect against concurrent isolated cpuset change
      timers/migration: Prevent from lockdep false positive warning
      cpu: Provide lockdep check for CPU hotplug lock write-held
      cpuset: Provide lockdep check for cpuset lock held
      sched/isolation: Convert housekeeping cpumasks to rcu pointers
      cpuset: Update HK_TYPE_DOMAIN cpumask from cpuset
      sched/isolation: Flush memcg workqueues on cpuset isolated partition change
      sched/isolation: Flush vmstat workqueues on cpuset isolated partition change
      PCI: Flush PCI probe workqueue on cpuset isolated partition change
      cpuset: Propagate cpuset isolation update to workqueue through housekeeping
      cpuset: Propagate cpuset isolation update to timers through housekeeping
      timers/migration: Remove superfluous cpuset isolation test
      cpuset: Remove cpuset_cpu_is_isolated()
      sched/isolation: Remove HK_TYPE_TICK test from cpu_is_isolated()
      PCI: Remove superfluous HK_TYPE_WQ check
      kthread: Refine naming of affinity related fields
      kthread: Include unbound kthreads in the managed affinity list
      kthread: Include kthreadd to the managed affinity list
      kthread: Rely on HK_TYPE_DOMAIN for preferred affinity management
      sched: Switch the fallback task allowed cpumask to HK_TYPE_DOMAIN
      sched/arm64: Move fallback task cpumask to HK_TYPE_DOMAIN
      kthread: Honour kthreads preferred affinity after cpuset changes
      kthread: Comment on the purpose and placement of kthread_affine_node() call
      kthread: Document kthread_affine_preferred()
      doc: Add housekeeping documentation

 Documentation/core-api/housekeeping.rst | 111 ++++++++++++++++++++++
 Documentation/core-api/index.rst        |   1 +
 arch/arm64/kernel/cpufeature.c          |  18 +++-
 block/blk-mq.c                          |   6 +-
 drivers/base/cpu.c                      |   2 +-
 drivers/pci/pci-driver.c                |  71 ++++++++++----
 include/linux/cpu.h                     |   4 +
 include/linux/cpuhplock.h               |   1 +
 include/linux/cpuset.h                  |   8 +-
 include/linux/kthread.h                 |   1 +
 include/linux/memcontrol.h              |   4 +
 include/linux/mmu_context.h             |   2 +-
 include/linux/pci.h                     |   3 +
 include/linux/percpu-rwsem.h            |   1 +
 include/linux/sched/isolation.h         |  16 +++-
 include/linux/vmstat.h                  |   2 +
 include/linux/workqueue.h               |   2 +-
 init/Kconfig                            |   1 +
 kernel/cgroup/cpuset.c                  |  68 +++++++-------
 kernel/cpu.c                            |  42 ++++-----
 kernel/kthread.c                        | 160 +++++++++++++++++++++-----------
 kernel/sched/isolation.c                | 144 +++++++++++++++++++++++-----
 kernel/sched/sched.h                    |   4 +
 kernel/time/timer_migration.c           |  25 +++--
 kernel/workqueue.c                      |  17 ++--
 mm/memcontrol.c                         |  25 ++++-
 mm/vmstat.c                             |  15 ++-
 net/core/net-sysfs.c                    |   2 +-
 28 files changed, 554 insertions(+), 202 deletions(-)


From frederic at kernel.org  Wed Dec 24 05:44:48 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:44:48 +0100
Subject: [PATCH 01/33] PCI: Prepare to protect against concurrent isolated cpuset change
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-2-frederic@kernel.org>

HK_TYPE_DOMAIN will soon integrate cpuset isolated partitions and
therefore be made modifiable at runtime. Synchronize against the cpumask
update using RCU.

The RCU locked section includes both the housekeeping CPU target
election for the PCI probe work and the work enqueue.

This way the housekeeping update side will simply need to flush the
pending related works after updating the housekeeping mask in order to
make sure that no PCI work ever executes on an isolated CPU. This part
will be handled in a subsequent patch.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 drivers/pci/pci-driver.c | 47 ++++++++++++++++++++++++++++++++--------
 1 file changed, 38 insertions(+), 9 deletions(-)

diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 7c2d9d596258..786d6ce40999 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -302,9 +302,8 @@ struct drv_dev_and_id {
 	const struct pci_device_id *id;
 };
 
-static long local_pci_probe(void *_ddi)
+static int local_pci_probe(struct drv_dev_and_id *ddi)
 {
-	struct drv_dev_and_id *ddi = _ddi;
 	struct pci_dev *pci_dev = ddi->dev;
 	struct pci_driver *pci_drv = ddi->drv;
 	struct device *dev = &pci_dev->dev;
@@ -338,6 +337,19 @@ static long local_pci_probe(void *_ddi)
 	return 0;
 }
 
+struct pci_probe_arg {
+	struct drv_dev_and_id *ddi;
+	struct work_struct work;
+	int ret;
+};
+
+static void local_pci_probe_callback(struct work_struct *work)
+{
+	struct pci_probe_arg *arg = container_of(work, struct pci_probe_arg, work);
+
+	arg->ret = local_pci_probe(arg->ddi);
+}
+
 static bool pci_physfn_is_probed(struct pci_dev *dev)
 {
 #ifdef CONFIG_PCI_IOV
@@ -362,34 +374,51 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
 	dev->is_probed = 1;
 
 	cpu_hotplug_disable();
-
 	/*
 	 * Prevent nesting work_on_cpu() for the case where a Virtual Function
 	 * device is probed from work_on_cpu() of the Physical device.
 	 */
 	if (node < 0 || node >= MAX_NUMNODES || !node_online(node) ||
 	    pci_physfn_is_probed(dev)) {
-		cpu = nr_cpu_ids;
+		error = local_pci_probe(&ddi);
 	} else {
 		cpumask_var_t wq_domain_mask;
+		struct pci_probe_arg arg = { .ddi = &ddi };
+
+		INIT_WORK_ONSTACK(&arg.work, local_pci_probe_callback);
 
 		if (!zalloc_cpumask_var(&wq_domain_mask, GFP_KERNEL)) {
 			error = -ENOMEM;
 			goto out;
 		}
+
+		/*
+		 * The target election and the enqueue of the work must be within
+		 * the same RCU read side section so that when the workqueue pool
+		 * is flushed after a housekeeping cpumask update, further readers
+		 * are guaranteed to queue the probing work to the appropriate
+		 * targets.
+		 */
+		rcu_read_lock();
 		cpumask_and(wq_domain_mask,
 			    housekeeping_cpumask(HK_TYPE_WQ),
 			    housekeeping_cpumask(HK_TYPE_DOMAIN));
 
 		cpu = cpumask_any_and(cpumask_of_node(node),
 				      wq_domain_mask);
+		if (cpu < nr_cpu_ids) {
+			schedule_work_on(cpu, &arg.work);
+			rcu_read_unlock();
+			flush_work(&arg.work);
+			error = arg.ret;
+		} else {
+			rcu_read_unlock();
+			error = local_pci_probe(&ddi);
+		}
+
 		free_cpumask_var(wq_domain_mask);
+		destroy_work_on_stack(&arg.work);
 	}
-
-	if (cpu < nr_cpu_ids)
-		error = work_on_cpu(cpu, local_pci_probe, &ddi);
-	else
-		error = local_pci_probe(&ddi);
 out:
 	dev->is_probed = 0;
 	cpu_hotplug_enable();
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:44:49 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:44:49 +0100
Subject: [PATCH 02/33] cpu: Revert "cpu/hotplug: Prevent self deadlock on CPU hot-unplug"
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-3-frederic@kernel.org>

1) The commit:

	2b8272ff4a70 ("cpu/hotplug: Prevent self deadlock on CPU hot-unplug")

was added to fix an issue where the hotplug control task (BP) was
throttled between CPUHP_AP_IDLE_DEAD and CPUHP_HRTIMERS_PREPARE waiting
in the hrtimer blindspot for the bandwidth callback queued in the dead
CPU.

2) Later on, the commit:

	38685e2a0476 ("cpu/hotplug: Don't offline the last non-isolated CPU")

plugged on the target selection for the workqueue offloaded CPU down
process to prevent from destroying the last CPU domain.

3) Finally:

	5c0930ccaad5 ("hrtimers: Push pending hrtimers away from outgoing CPU earlier")

removed entirely the conditions for the race exposed and partially fixed
in 1). The offloading of the CPU down process to a workqueue on another
CPU then becomes unnecessary. But the last CPU belonging to scheduler
domains must still remain online.

Therefore revert the now obsolete commit
2b8272ff4a70b866106ae13c36be7ecbef5d5da2 and move the housekeeping check
under the cpu_hotplug_lock write held. Since HK_TYPE_DOMAIN will include
both isolcpus and cpuset isolated partition, the hotplug lock will
synchronize against concurrent cpuset partition updates.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 kernel/cpu.c | 37 +++++++++++--------------------------
 1 file changed, 11 insertions(+), 26 deletions(-)

diff --git a/kernel/cpu.c b/kernel/cpu.c
index 8df2d773fe3b..40b8496f47c5 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -1410,6 +1410,16 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen,
 
 	cpus_write_lock();
 
+	/*
+	 * Keep at least one housekeeping cpu onlined to avoid generating
+	 * an empty sched_domain span.
+	 */
+	if (cpumask_any_and(cpu_online_mask,
+			    housekeeping_cpumask(HK_TYPE_DOMAIN)) >= nr_cpu_ids) {
+		ret = -EBUSY;
+		goto out;
+	}
+
 	cpuhp_tasks_frozen = tasks_frozen;
 
 	prev_state = cpuhp_set_state(cpu, st, target);
@@ -1456,22 +1466,8 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen,
 	return ret;
 }
 
-struct cpu_down_work {
-	unsigned int		cpu;
-	enum cpuhp_state	target;
-};
-
-static long __cpu_down_maps_locked(void *arg)
-{
-	struct cpu_down_work *work = arg;
-
-	return _cpu_down(work->cpu, 0, work->target);
-}
-
 static int cpu_down_maps_locked(unsigned int cpu, enum cpuhp_state target)
 {
-	struct cpu_down_work work = { .cpu = cpu, .target = target, };
-
 	/*
 	 * If the platform does not support hotplug, report it explicitly to
 	 * differentiate it from a transient offlining failure.
@@ -1480,18 +1476,7 @@ static int cpu_down_maps_locked(unsigned int cpu, enum cpuhp_state target)
 		return -EOPNOTSUPP;
 	if (cpu_hotplug_disabled)
 		return -EBUSY;
-
-	/*
-	 * Ensure that the control task does not run on the to be offlined
-	 * CPU to prevent a deadlock against cfs_b->period_timer.
-	 * Also keep at least one housekeeping cpu onlined to avoid generating
-	 * an empty sched_domain span.
-	 */
-	for_each_cpu_and(cpu, cpu_online_mask, housekeeping_cpumask(HK_TYPE_DOMAIN)) {
-		if (cpu != work.cpu)
-			return work_on_cpu(cpu, __cpu_down_maps_locked, &work);
-	}
-	return -EBUSY;
+	return _cpu_down(cpu, 0, target);
 }
 
 static int cpu_down(unsigned int cpu, enum cpuhp_state target)
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:44:50 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:44:50 +0100
Subject: [PATCH 03/33] memcg: Prepare to protect against concurrent isolated cpuset change
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-4-frederic@kernel.org>

The HK_TYPE_DOMAIN housekeeping cpumask will soon be made modifiable at
runtime. In order to synchronize against memcg workqueue to make sure
that no asynchronous draining is pending or executing on a newly made
isolated CPU, target and queue a drain work under the same RCU critical
section.

Whenever housekeeping will update the HK_TYPE_DOMAIN cpumask, a memcg
workqueue flush will also be issued in a further change to make sure
that no work remains pending after a CPU has been made isolated.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 mm/memcontrol.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index be810c1fbfc3..c3c473c3dfca 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -2003,6 +2003,13 @@ static bool is_memcg_drain_needed(struct memcg_stock_pcp *stock,
 	return flush;
 }
 
+static void schedule_drain_work(int cpu, struct work_struct *work)
+{
+	guard(rcu)();
+	if (!cpu_is_isolated(cpu))
+		schedule_work_on(cpu, work);
+}
+
 /*
  * Drains all per-CPU charge caches for given root_memcg resp. subtree
  * of the hierarchy under it.
@@ -2032,8 +2039,8 @@ void drain_all_stock(struct mem_cgroup *root_memcg)
 				      &memcg_st->flags)) {
 			if (cpu == curcpu)
 				drain_local_memcg_stock(&memcg_st->work);
-			else if (!cpu_is_isolated(cpu))
-				schedule_work_on(cpu, &memcg_st->work);
+			else
+				schedule_drain_work(cpu, &memcg_st->work);
 		}
 
 		if (!test_bit(FLUSHING_CACHED_CHARGE, &obj_st->flags) &&
@@ -2042,8 +2049,8 @@ void drain_all_stock(struct mem_cgroup *root_memcg)
 				      &obj_st->flags)) {
 			if (cpu == curcpu)
 				drain_local_obj_stock(&obj_st->work);
-			else if (!cpu_is_isolated(cpu))
-				schedule_work_on(cpu, &obj_st->work);
+			else
+				schedule_drain_work(cpu, &obj_st->work);
 		}
 	}
 	migrate_enable();
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:44:51 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:44:51 +0100
Subject: [PATCH 04/33] mm: vmstat: Prepare to protect against concurrent isolated cpuset change
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-5-frederic@kernel.org>

The HK_TYPE_DOMAIN housekeeping cpumask will soon be made modifiable at
runtime. In order to synchronize against vmstat workqueue to make sure
that no asynchronous vmstat work is pending or executing on a newly made
isolated CPU, target and queue a vmstat work under the same RCU read
side critical section.

Whenever housekeeping will update the HK_TYPE_DOMAIN cpumask, a vmstat
workqueue flush will also be issued in a further change to make sure
that no work remains pending after a CPU has been made isolated.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 mm/vmstat.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/mm/vmstat.c b/mm/vmstat.c
index 65de88cdf40e..ed19c0d42de6 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -2144,11 +2144,13 @@ static void vmstat_shepherd(struct work_struct *w)
 		 * infrastructure ever noticing. Skip regular flushing from vmstat_shepherd
 		 * for all isolated CPUs to avoid interference with the isolated workload.
 		 */
-		if (cpu_is_isolated(cpu))
-			continue;
+		scoped_guard(rcu) {
+			if (cpu_is_isolated(cpu))
+				continue;
 
-		if (!delayed_work_pending(dw) && need_update(cpu))
-			queue_delayed_work_on(cpu, mm_percpu_wq, dw, 0);
+			if (!delayed_work_pending(dw) && need_update(cpu))
+				queue_delayed_work_on(cpu, mm_percpu_wq, dw, 0);
+		}
 
 		cond_resched();
 	}
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:44:52 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:44:52 +0100
Subject: [PATCH 05/33] sched/isolation: Save boot defined domain flags
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-6-frederic@kernel.org>

HK_TYPE_DOMAIN will soon integrate not only boot defined isolcpus= CPUs
but also cpuset isolated partitions.

Housekeeping still needs a way to record what was initially passed
to isolcpus= in order to keep these CPUs isolated after a cpuset
isolated partition is modified or destroyed while containing some of
them.

Create a new HK_TYPE_DOMAIN_BOOT to keep track of those.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
Reviewed-by: Phil Auld <pauld at redhat.com>
---
 include/linux/sched/isolation.h | 4 ++++
 kernel/sched/isolation.c        | 5 +++--
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/include/linux/sched/isolation.h b/include/linux/sched/isolation.h
index d8501f4709b5..109a2149e21a 100644
--- a/include/linux/sched/isolation.h
+++ b/include/linux/sched/isolation.h
@@ -7,8 +7,12 @@
 #include <linux/tick.h>
 
 enum hk_type {
+	/* Revert of boot-time isolcpus= argument */
+	HK_TYPE_DOMAIN_BOOT,
 	HK_TYPE_DOMAIN,
+	/* Revert of boot-time isolcpus=managed_irq argument */
 	HK_TYPE_MANAGED_IRQ,
+	/* Revert of boot-time nohz_full= or isolcpus=nohz arguments */
 	HK_TYPE_KERNEL_NOISE,
 	HK_TYPE_MAX,
 
diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c
index 3ad0d6df6a0a..11a623fa6320 100644
--- a/kernel/sched/isolation.c
+++ b/kernel/sched/isolation.c
@@ -11,6 +11,7 @@
 #include "sched.h"
 
 enum hk_flags {
+	HK_FLAG_DOMAIN_BOOT	= BIT(HK_TYPE_DOMAIN_BOOT),
 	HK_FLAG_DOMAIN		= BIT(HK_TYPE_DOMAIN),
 	HK_FLAG_MANAGED_IRQ	= BIT(HK_TYPE_MANAGED_IRQ),
 	HK_FLAG_KERNEL_NOISE	= BIT(HK_TYPE_KERNEL_NOISE),
@@ -239,7 +240,7 @@ static int __init housekeeping_isolcpus_setup(char *str)
 
 		if (!strncmp(str, "domain,", 7)) {
 			str += 7;
-			flags |= HK_FLAG_DOMAIN;
+			flags |= HK_FLAG_DOMAIN | HK_FLAG_DOMAIN_BOOT;
 			continue;
 		}
 
@@ -269,7 +270,7 @@ static int __init housekeeping_isolcpus_setup(char *str)
 
 	/* Default behaviour for isolcpus without flags */
 	if (!flags)
-		flags |= HK_FLAG_DOMAIN;
+		flags |= HK_FLAG_DOMAIN | HK_FLAG_DOMAIN_BOOT;
 
 	return housekeeping_setup(str, flags);
 }
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:44:53 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:44:53 +0100
Subject: [PATCH 06/33] cpuset: Convert boot_hk_cpus to use HK_TYPE_DOMAIN_BOOT
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-7-frederic@kernel.org>

boot_hk_cpus is an ad-hoc copy of HK_TYPE_DOMAIN_BOOT. Remove it and use
the official version.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
Reviewed-by: Phil Auld <pauld at redhat.com>
Reviewed-by: Chen Ridong <chenridong at huawei.com>
---
 kernel/cgroup/cpuset.c | 22 +++++++---------------
 1 file changed, 7 insertions(+), 15 deletions(-)

diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 6e6eb09b8db6..3afa72f8d579 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -88,12 +88,6 @@ static cpumask_var_t	isolated_cpus;
  */
 static bool isolated_cpus_updating;
 
-/*
- * Housekeeping (HK_TYPE_DOMAIN) CPUs at boot
- */
-static cpumask_var_t	boot_hk_cpus;
-static bool		have_boot_isolcpus;
-
 /*
  * A flag to force sched domain rebuild at the end of an operation.
  * It can be set in
@@ -1453,15 +1447,16 @@ static bool isolated_cpus_can_update(struct cpumask *add_cpus,
  * @new_cpus: cpu mask
  * Return: true if there is conflict, false otherwise
  *
- * CPUs outside of boot_hk_cpus, if defined, can only be used in an
+ * CPUs outside of HK_TYPE_DOMAIN_BOOT, if defined, can only be used in an
  * isolated partition.
  */
 static bool prstate_housekeeping_conflict(int prstate, struct cpumask *new_cpus)
 {
-	if (!have_boot_isolcpus)
+	if (!housekeeping_enabled(HK_TYPE_DOMAIN_BOOT))
 		return false;
 
-	if ((prstate != PRS_ISOLATED) && !cpumask_subset(new_cpus, boot_hk_cpus))
+	if ((prstate != PRS_ISOLATED) &&
+	    !cpumask_subset(new_cpus, housekeeping_cpumask(HK_TYPE_DOMAIN_BOOT)))
 		return true;
 
 	return false;
@@ -3892,12 +3887,9 @@ int __init cpuset_init(void)
 
 	BUG_ON(!alloc_cpumask_var(&cpus_attach, GFP_KERNEL));
 
-	have_boot_isolcpus = housekeeping_enabled(HK_TYPE_DOMAIN);
-	if (have_boot_isolcpus) {
-		BUG_ON(!alloc_cpumask_var(&boot_hk_cpus, GFP_KERNEL));
-		cpumask_copy(boot_hk_cpus, housekeeping_cpumask(HK_TYPE_DOMAIN));
-		cpumask_andnot(isolated_cpus, cpu_possible_mask, boot_hk_cpus);
-	}
+	if (housekeeping_enabled(HK_TYPE_DOMAIN_BOOT))
+		cpumask_andnot(isolated_cpus, cpu_possible_mask,
+			       housekeeping_cpumask(HK_TYPE_DOMAIN_BOOT));
 
 	return 0;
 }
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:44:54 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:44:54 +0100
Subject: [PATCH 07/33] driver core: cpu: Convert /sys/devices/system/cpu/isolated to use HK_TYPE_DOMAIN_BOOT
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-8-frederic@kernel.org>

Make sure /sys/devices/system/cpu/isolated only prints what was passed
through the isolcpus= parameter before HK_TYPE_DOMAIN will also
integrate cpuset isolated partitions.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 drivers/base/cpu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index c6c57b6f61c6..3e3fa031e605 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -291,7 +291,7 @@ static ssize_t print_cpus_isolated(struct device *dev,
 		return -ENOMEM;
 
 	cpumask_andnot(isolated, cpu_possible_mask,
-		       housekeeping_cpumask(HK_TYPE_DOMAIN));
+		       housekeeping_cpumask(HK_TYPE_DOMAIN_BOOT));
 	len = sysfs_emit(buf, "%*pbl\n", cpumask_pr_args(isolated));
 
 	free_cpumask_var(isolated);
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:44:56 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:44:56 +0100
Subject: [PATCH 09/33] block: Protect against concurrent isolated cpuset change
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-10-frederic@kernel.org>

The block subsystem prevents running the workqueue to isolated CPUs,
including those defined by cpuset isolated partitions. Since
HK_TYPE_DOMAIN will soon contain both and be subject to runtime
modifications, synchronize against housekeeping using the relevant lock.

For full support of cpuset changes, the block subsystem may need to
propagate changes to isolated cpumask through the workqueue in the
future.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 block/blk-mq.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/block/blk-mq.c b/block/blk-mq.c
index 1978eef95dca..0037af1216f3 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -4257,12 +4257,16 @@ static void blk_mq_map_swqueue(struct request_queue *q)
 
 		/*
 		 * Rule out isolated CPUs from hctx->cpumask to avoid
-		 * running block kworker on isolated CPUs
+		 * running block kworker on isolated CPUs.
+		 * FIXME: cpuset should propagate further changes to isolated CPUs
+		 * here.
 		 */
+		rcu_read_lock();
 		for_each_cpu(cpu, hctx->cpumask) {
 			if (cpu_is_isolated(cpu))
 				cpumask_clear_cpu(cpu, hctx->cpumask);
 		}
+		rcu_read_unlock();
 
 		/*
 		 * Initialize batch roundrobin counts
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:44:57 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:44:57 +0100
Subject: [PATCH 10/33] timers/migration: Prevent from lockdep false positive warning
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-11-frederic@kernel.org>

Testing housekeeping_cpu() will soon require that either the RCU "lock"
is held or the cpuset mutex.

When CPUs get isolated through cpuset, the change is propagated to
timer migration such that isolation is also performed from the migration
tree. However that propagation is done using workqueue which tests if
the target is actually isolated before proceeding.

Lockdep doesn't know that the workqueue caller holds cpuset mutex and
that it waits for the work, making the housekeeping cpumask read safe.

Shut down the future warning by removing this test. It is unecessary
beyond hotplug, the workqueue is already targeted towards isolated CPUs.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 kernel/time/timer_migration.c | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/kernel/time/timer_migration.c b/kernel/time/timer_migration.c
index 18dda1aa782d..3879575a4975 100644
--- a/kernel/time/timer_migration.c
+++ b/kernel/time/timer_migration.c
@@ -1497,7 +1497,7 @@ static int tmigr_clear_cpu_available(unsigned int cpu)
 	return 0;
 }
 
-static int tmigr_set_cpu_available(unsigned int cpu)
+static int __tmigr_set_cpu_available(unsigned int cpu)
 {
 	struct tmigr_cpu *tmc = this_cpu_ptr(&tmigr_cpu);
 
@@ -1505,9 +1505,6 @@ static int tmigr_set_cpu_available(unsigned int cpu)
 	if (WARN_ON_ONCE(!tmc->tmgroup))
 		return -EINVAL;
 
-	if (tmigr_is_isolated(cpu))
-		return 0;
-
 	guard(mutex)(&tmigr_available_mutex);
 
 	cpumask_set_cpu(cpu, tmigr_available_cpumask);
@@ -1523,6 +1520,14 @@ static int tmigr_set_cpu_available(unsigned int cpu)
 	return 0;
 }
 
+static int tmigr_set_cpu_available(unsigned int cpu)
+{
+	if (tmigr_is_isolated(cpu))
+		return 0;
+
+	return __tmigr_set_cpu_available(cpu);
+}
+
 static void tmigr_cpu_isolate(struct work_struct *ignored)
 {
 	tmigr_clear_cpu_available(smp_processor_id());
@@ -1530,7 +1535,12 @@ static void tmigr_cpu_isolate(struct work_struct *ignored)
 
 static void tmigr_cpu_unisolate(struct work_struct *ignored)
 {
-	tmigr_set_cpu_available(smp_processor_id());
+	/*
+	 * Don't call tmigr_is_isolated() ->housekeeping_cpu() directly because
+	 * the cpuset mutex is correctly held by the workqueue caller but lockdep
+	 * doesn't know that.
+	 */
+	__tmigr_set_cpu_available(smp_processor_id());
 }
 
 /**
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:44:58 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:44:58 +0100
Subject: [PATCH 11/33] cpu: Provide lockdep check for CPU hotplug lock write-held
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-12-frederic@kernel.org>

cpuset modifies partitions, including isolated, while holding the cpu
hotplug lock read-held.

This means that write-holding the CPU hotplug lock is safe to
synchronize against housekeeping cpumask changes.

Provide a lockdep check to validate that.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 include/linux/cpuhplock.h    | 1 +
 include/linux/percpu-rwsem.h | 1 +
 kernel/cpu.c                 | 5 +++++
 3 files changed, 7 insertions(+)

diff --git a/include/linux/cpuhplock.h b/include/linux/cpuhplock.h
index f7aa20f62b87..286b3ab92e15 100644
--- a/include/linux/cpuhplock.h
+++ b/include/linux/cpuhplock.h
@@ -13,6 +13,7 @@
 struct device;
 
 extern int lockdep_is_cpus_held(void);
+extern int lockdep_is_cpus_write_held(void);
 
 #ifdef CONFIG_HOTPLUG_CPU
 void cpus_write_lock(void);
diff --git a/include/linux/percpu-rwsem.h b/include/linux/percpu-rwsem.h
index 288f5235649a..c8cb010d655e 100644
--- a/include/linux/percpu-rwsem.h
+++ b/include/linux/percpu-rwsem.h
@@ -161,6 +161,7 @@ extern void percpu_free_rwsem(struct percpu_rw_semaphore *);
 	__percpu_init_rwsem(sem, #sem, &rwsem_key);		\
 })
 
+#define percpu_rwsem_is_write_held(sem)	lockdep_is_held_type(sem, 0)
 #define percpu_rwsem_is_held(sem)	lockdep_is_held(sem)
 #define percpu_rwsem_assert_held(sem)	lockdep_assert_held(sem)
 
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 40b8496f47c5..01968a5c4a16 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -534,6 +534,11 @@ int lockdep_is_cpus_held(void)
 {
 	return percpu_rwsem_is_held(&cpu_hotplug_lock);
 }
+
+int lockdep_is_cpus_write_held(void)
+{
+	return percpu_rwsem_is_write_held(&cpu_hotplug_lock);
+}
 #endif
 
 static void lockdep_acquire_cpus_lock(void)
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:44:59 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:44:59 +0100
Subject: [PATCH 12/33] cpuset: Provide lockdep check for cpuset lock held
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-13-frederic@kernel.org>

cpuset modifies partitions, including isolated, while holding the cpuset
mutex.

This means that holding the cpuset mutex is safe to synchronize against
housekeeping cpumask changes.

Provide a lockdep check to validate that.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 include/linux/cpuset.h | 2 ++
 kernel/cgroup/cpuset.c | 7 +++++++
 2 files changed, 9 insertions(+)

diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h
index a98d3330385c..1c49ffd2ca9b 100644
--- a/include/linux/cpuset.h
+++ b/include/linux/cpuset.h
@@ -18,6 +18,8 @@
 #include <linux/mmu_context.h>
 #include <linux/jump_label.h>
 
+extern bool lockdep_is_cpuset_held(void);
+
 #ifdef CONFIG_CPUSETS
 
 /*
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 3afa72f8d579..5e2e3514c22e 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -283,6 +283,13 @@ void cpuset_full_unlock(void)
 	cpus_read_unlock();
 }
 
+#ifdef CONFIG_LOCKDEP
+bool lockdep_is_cpuset_held(void)
+{
+	return lockdep_is_held(&cpuset_mutex);
+}
+#endif
+
 static DEFINE_SPINLOCK(callback_lock);
 
 void cpuset_callback_lock_irq(void)
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:45:00 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:45:00 +0100
Subject: [PATCH 13/33] sched/isolation: Convert housekeeping cpumasks to rcu pointers
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-14-frederic@kernel.org>

HK_TYPE_DOMAIN's cpumask will soon be made modifiable by cpuset.
A synchronization mechanism is then needed to synchronize the updates
with the housekeeping cpumask readers.

Turn the housekeeping cpumasks into RCU pointers. Once a housekeeping
cpumask will be modified, the update side will wait for an RCU grace
period and propagate the change to interested subsystem when deemed
necessary.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 kernel/sched/isolation.c | 58 +++++++++++++++++++++++++---------------
 kernel/sched/sched.h     |  1 +
 2 files changed, 37 insertions(+), 22 deletions(-)

diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c
index 11a623fa6320..83be49ec2b06 100644
--- a/kernel/sched/isolation.c
+++ b/kernel/sched/isolation.c
@@ -21,7 +21,7 @@ DEFINE_STATIC_KEY_FALSE(housekeeping_overridden);
 EXPORT_SYMBOL_GPL(housekeeping_overridden);
 
 struct housekeeping {
-	cpumask_var_t cpumasks[HK_TYPE_MAX];
+	struct cpumask __rcu *cpumasks[HK_TYPE_MAX];
 	unsigned long flags;
 };
 
@@ -33,17 +33,28 @@ bool housekeeping_enabled(enum hk_type type)
 }
 EXPORT_SYMBOL_GPL(housekeeping_enabled);
 
+const struct cpumask *housekeeping_cpumask(enum hk_type type)
+{
+	if (static_branch_unlikely(&housekeeping_overridden)) {
+		if (housekeeping.flags & BIT(type)) {
+			return rcu_dereference_check(housekeeping.cpumasks[type], 1);
+		}
+	}
+	return cpu_possible_mask;
+}
+EXPORT_SYMBOL_GPL(housekeeping_cpumask);
+
 int housekeeping_any_cpu(enum hk_type type)
 {
 	int cpu;
 
 	if (static_branch_unlikely(&housekeeping_overridden)) {
 		if (housekeeping.flags & BIT(type)) {
-			cpu = sched_numa_find_closest(housekeeping.cpumasks[type], smp_processor_id());
+			cpu = sched_numa_find_closest(housekeeping_cpumask(type), smp_processor_id());
 			if (cpu < nr_cpu_ids)
 				return cpu;
 
-			cpu = cpumask_any_and_distribute(housekeeping.cpumasks[type], cpu_online_mask);
+			cpu = cpumask_any_and_distribute(housekeeping_cpumask(type), cpu_online_mask);
 			if (likely(cpu < nr_cpu_ids))
 				return cpu;
 			/*
@@ -59,28 +70,18 @@ int housekeeping_any_cpu(enum hk_type type)
 }
 EXPORT_SYMBOL_GPL(housekeeping_any_cpu);
 
-const struct cpumask *housekeeping_cpumask(enum hk_type type)
-{
-	if (static_branch_unlikely(&housekeeping_overridden))
-		if (housekeeping.flags & BIT(type))
-			return housekeeping.cpumasks[type];
-	return cpu_possible_mask;
-}
-EXPORT_SYMBOL_GPL(housekeeping_cpumask);
-
 void housekeeping_affine(struct task_struct *t, enum hk_type type)
 {
 	if (static_branch_unlikely(&housekeeping_overridden))
 		if (housekeeping.flags & BIT(type))
-			set_cpus_allowed_ptr(t, housekeeping.cpumasks[type]);
+			set_cpus_allowed_ptr(t, housekeeping_cpumask(type));
 }
 EXPORT_SYMBOL_GPL(housekeeping_affine);
 
 bool housekeeping_test_cpu(int cpu, enum hk_type type)
 {
-	if (static_branch_unlikely(&housekeeping_overridden))
-		if (housekeeping.flags & BIT(type))
-			return cpumask_test_cpu(cpu, housekeeping.cpumasks[type]);
+	if (static_branch_unlikely(&housekeeping_overridden) && housekeeping.flags & BIT(type))
+		return cpumask_test_cpu(cpu, housekeeping_cpumask(type));
 	return true;
 }
 EXPORT_SYMBOL_GPL(housekeeping_test_cpu);
@@ -96,20 +97,33 @@ void __init housekeeping_init(void)
 
 	if (housekeeping.flags & HK_FLAG_KERNEL_NOISE)
 		sched_tick_offload_init();
-
+	/*
+	 * Realloc with a proper allocator so that any cpumask update
+	 * can indifferently free the old version with kfree().
+	 */
 	for_each_set_bit(type, &housekeeping.flags, HK_TYPE_MAX) {
+		struct cpumask *omask, *nmask = kmalloc(cpumask_size(), GFP_KERNEL);
+
+		if (WARN_ON_ONCE(!nmask))
+			return;
+
+		omask = rcu_dereference(housekeeping.cpumasks[type]);
+
 		/* We need at least one CPU to handle housekeeping work */
-		WARN_ON_ONCE(cpumask_empty(housekeeping.cpumasks[type]));
+		WARN_ON_ONCE(cpumask_empty(omask));
+		cpumask_copy(nmask, omask);
+		RCU_INIT_POINTER(housekeeping.cpumasks[type], nmask);
+		memblock_free(omask, cpumask_size());
 	}
 }
 
 static void __init housekeeping_setup_type(enum hk_type type,
 					   cpumask_var_t housekeeping_staging)
 {
+	struct cpumask *mask = memblock_alloc_or_panic(cpumask_size(), SMP_CACHE_BYTES);
 
-	alloc_bootmem_cpumask_var(&housekeeping.cpumasks[type]);
-	cpumask_copy(housekeeping.cpumasks[type],
-		     housekeeping_staging);
+	cpumask_copy(mask, housekeeping_staging);
+	RCU_INIT_POINTER(housekeeping.cpumasks[type], mask);
 }
 
 static int __init housekeeping_setup(char *str, unsigned long flags)
@@ -162,7 +176,7 @@ static int __init housekeeping_setup(char *str, unsigned long flags)
 
 		for_each_set_bit(type, &iter_flags, HK_TYPE_MAX) {
 			if (!cpumask_equal(housekeeping_staging,
-					   housekeeping.cpumasks[type])) {
+					   housekeeping_cpumask(type))) {
 				pr_warn("Housekeeping: nohz_full= must match isolcpus=\n");
 				goto free_housekeeping_staging;
 			}
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index d30cca6870f5..475bdab3b8db 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -42,6 +42,7 @@
 #include <linux/ktime_api.h>
 #include <linux/lockdep_api.h>
 #include <linux/lockdep.h>
+#include <linux/memblock.h>
 #include <linux/minmax.h>
 #include <linux/mm.h>
 #include <linux/module.h>
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:45:01 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:45:01 +0100
Subject: [PATCH 14/33] cpuset: Update HK_TYPE_DOMAIN cpumask from cpuset
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-15-frederic@kernel.org>

Until now, HK_TYPE_DOMAIN used to only include boot defined isolated
CPUs passed through isolcpus= boot option. Users interested in also
knowing the runtime defined isolated CPUs through cpuset must use
different APIs: cpuset_cpu_is_isolated(), cpu_is_isolated(), etc...

There are many drawbacks to that approach:

1) Most interested subsystems want to know about all isolated CPUs, not
  just those defined on boot time.

2) cpuset_cpu_is_isolated() / cpu_is_isolated() are not synchronized with
  concurrent cpuset changes.

3) Further cpuset modifications are not propagated to subsystems

Solve 1) and 2) and centralize all isolated CPUs within the
HK_TYPE_DOMAIN housekeeping cpumask.

Subsystems can rely on RCU to synchronize against concurrent changes.

The propagation mentioned in 3) will be handled in further patches.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 include/linux/sched/isolation.h |  7 +++
 kernel/cgroup/cpuset.c          |  3 ++
 kernel/sched/isolation.c        | 76 ++++++++++++++++++++++++++++++---
 kernel/sched/sched.h            |  1 +
 4 files changed, 81 insertions(+), 6 deletions(-)

diff --git a/include/linux/sched/isolation.h b/include/linux/sched/isolation.h
index 109a2149e21a..6842a1ba4d13 100644
--- a/include/linux/sched/isolation.h
+++ b/include/linux/sched/isolation.h
@@ -9,6 +9,11 @@
 enum hk_type {
 	/* Revert of boot-time isolcpus= argument */
 	HK_TYPE_DOMAIN_BOOT,
+	/*
+	 * Same as HK_TYPE_DOMAIN_BOOT but also includes the
+	 * revert of cpuset isolated partitions. As such it
+	 * is always a subset of HK_TYPE_DOMAIN_BOOT.
+	 */
 	HK_TYPE_DOMAIN,
 	/* Revert of boot-time isolcpus=managed_irq argument */
 	HK_TYPE_MANAGED_IRQ,
@@ -35,6 +40,7 @@ extern const struct cpumask *housekeeping_cpumask(enum hk_type type);
 extern bool housekeeping_enabled(enum hk_type type);
 extern void housekeeping_affine(struct task_struct *t, enum hk_type type);
 extern bool housekeeping_test_cpu(int cpu, enum hk_type type);
+extern int housekeeping_update(struct cpumask *isol_mask, enum hk_type type);
 extern void __init housekeeping_init(void);
 
 #else
@@ -62,6 +68,7 @@ static inline bool housekeeping_test_cpu(int cpu, enum hk_type type)
 	return true;
 }
 
+static inline int housekeeping_update(struct cpumask *isol_mask, enum hk_type type) { return 0; }
 static inline void housekeeping_init(void) { }
 #endif /* CONFIG_CPU_ISOLATION */
 
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 5e2e3514c22e..e13e32491ebf 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -1490,6 +1490,9 @@ static void update_isolation_cpumasks(void)
 	ret = tmigr_isolated_exclude_cpumask(isolated_cpus);
 	WARN_ON_ONCE(ret < 0);
 
+	ret = housekeeping_update(isolated_cpus, HK_TYPE_DOMAIN);
+	WARN_ON_ONCE(ret < 0);
+
 	isolated_cpus_updating = false;
 }
 
diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c
index 83be49ec2b06..a124f1119f2e 100644
--- a/kernel/sched/isolation.c
+++ b/kernel/sched/isolation.c
@@ -29,18 +29,48 @@ static struct housekeeping housekeeping;
 
 bool housekeeping_enabled(enum hk_type type)
 {
-	return !!(housekeeping.flags & BIT(type));
+	return !!(READ_ONCE(housekeeping.flags) & BIT(type));
 }
 EXPORT_SYMBOL_GPL(housekeeping_enabled);
 
+static bool housekeeping_dereference_check(enum hk_type type)
+{
+	if (IS_ENABLED(CONFIG_LOCKDEP) && type == HK_TYPE_DOMAIN) {
+		/* Cpuset isn't even writable yet? */
+		if (system_state <= SYSTEM_SCHEDULING)
+			return true;
+
+		/* CPU hotplug write locked, so cpuset partition can't be overwritten */
+		if (IS_ENABLED(CONFIG_HOTPLUG_CPU) && lockdep_is_cpus_write_held())
+			return true;
+
+		/* Cpuset lock held, partitions not writable */
+		if (IS_ENABLED(CONFIG_CPUSETS) && lockdep_is_cpuset_held())
+			return true;
+
+		return false;
+	}
+
+	return true;
+}
+
+static inline struct cpumask *housekeeping_cpumask_dereference(enum hk_type type)
+{
+	return rcu_dereference_all_check(housekeeping.cpumasks[type],
+					 housekeeping_dereference_check(type));
+}
+
 const struct cpumask *housekeeping_cpumask(enum hk_type type)
 {
+	const struct cpumask *mask = NULL;
+
 	if (static_branch_unlikely(&housekeeping_overridden)) {
-		if (housekeeping.flags & BIT(type)) {
-			return rcu_dereference_check(housekeeping.cpumasks[type], 1);
-		}
+		if (READ_ONCE(housekeeping.flags) & BIT(type))
+			mask = housekeeping_cpumask_dereference(type);
 	}
-	return cpu_possible_mask;
+	if (!mask)
+		mask = cpu_possible_mask;
+	return mask;
 }
 EXPORT_SYMBOL_GPL(housekeeping_cpumask);
 
@@ -80,12 +110,46 @@ EXPORT_SYMBOL_GPL(housekeeping_affine);
 
 bool housekeeping_test_cpu(int cpu, enum hk_type type)
 {
-	if (static_branch_unlikely(&housekeeping_overridden) && housekeeping.flags & BIT(type))
+	if (static_branch_unlikely(&housekeeping_overridden) &&
+	    READ_ONCE(housekeeping.flags) & BIT(type))
 		return cpumask_test_cpu(cpu, housekeeping_cpumask(type));
 	return true;
 }
 EXPORT_SYMBOL_GPL(housekeeping_test_cpu);
 
+int housekeeping_update(struct cpumask *isol_mask, enum hk_type type)
+{
+	struct cpumask *trial, *old = NULL;
+
+	if (type != HK_TYPE_DOMAIN)
+		return -ENOTSUPP;
+
+	trial = kmalloc(cpumask_size(), GFP_KERNEL);
+	if (!trial)
+		return -ENOMEM;
+
+	cpumask_andnot(trial, housekeeping_cpumask(HK_TYPE_DOMAIN_BOOT), isol_mask);
+	if (!cpumask_intersects(trial, cpu_online_mask)) {
+		kfree(trial);
+		return -EINVAL;
+	}
+
+	if (!housekeeping.flags)
+		static_branch_enable(&housekeeping_overridden);
+
+	if (housekeeping.flags & BIT(type))
+		old = housekeeping_cpumask_dereference(type);
+	else
+		WRITE_ONCE(housekeeping.flags, housekeeping.flags | BIT(type));
+	rcu_assign_pointer(housekeeping.cpumasks[type], trial);
+
+	synchronize_rcu();
+
+	kfree(old);
+
+	return 0;
+}
+
 void __init housekeeping_init(void)
 {
 	enum hk_type type;
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 475bdab3b8db..653e898a996a 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -30,6 +30,7 @@
 #include <linux/context_tracking.h>
 #include <linux/cpufreq.h>
 #include <linux/cpumask_api.h>
+#include <linux/cpuset.h>
 #include <linux/ctype.h>
 #include <linux/file.h>
 #include <linux/fs_api.h>
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:45:02 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:45:02 +0100
Subject: [PATCH 15/33] sched/isolation: Flush memcg workqueues on cpuset isolated partition change
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-16-frederic@kernel.org>

The HK_TYPE_DOMAIN housekeeping cpumask is now modifiable at runtime. In
order to synchronize against memcg workqueue to make sure that no
asynchronous draining is still pending or executing on a newly made
isolated CPU, the housekeeping susbsystem must flush the memcg
workqueues.

However the memcg workqueues can't be flushed easily since they are
queued to the main per-CPU workqueue pool.

Solve this with creating a memcg specific pool and provide and use the
appropriate flushing API.

Acked-by: Shakeel Butt <shakeel.butt at linux.dev>
Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 include/linux/memcontrol.h |  4 ++++
 kernel/sched/isolation.c   |  2 ++
 kernel/sched/sched.h       |  1 +
 mm/memcontrol.c            | 12 +++++++++++-
 4 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 0651865a4564..5b004b95648b 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -1037,6 +1037,8 @@ static inline u64 cgroup_id_from_mm(struct mm_struct *mm)
 	return id;
 }
 
+void mem_cgroup_flush_workqueue(void);
+
 extern int mem_cgroup_init(void);
 #else /* CONFIG_MEMCG */
 
@@ -1436,6 +1438,8 @@ static inline u64 cgroup_id_from_mm(struct mm_struct *mm)
 	return 0;
 }
 
+static inline void mem_cgroup_flush_workqueue(void) { }
+
 static inline int mem_cgroup_init(void) { return 0; }
 #endif /* CONFIG_MEMCG */
 
diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c
index a124f1119f2e..bb6c36d2b97b 100644
--- a/kernel/sched/isolation.c
+++ b/kernel/sched/isolation.c
@@ -145,6 +145,8 @@ int housekeeping_update(struct cpumask *isol_mask, enum hk_type type)
 
 	synchronize_rcu();
 
+	mem_cgroup_flush_workqueue();
+
 	kfree(old);
 
 	return 0;
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 653e898a996a..65dfa48e54b7 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -44,6 +44,7 @@
 #include <linux/lockdep_api.h>
 #include <linux/lockdep.h>
 #include <linux/memblock.h>
+#include <linux/memcontrol.h>
 #include <linux/minmax.h>
 #include <linux/mm.h>
 #include <linux/module.h>
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index c3c473c3dfca..89bf93cf97b9 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -96,6 +96,8 @@ static bool cgroup_memory_nokmem __ro_after_init;
 /* BPF memory accounting disabled? */
 static bool cgroup_memory_nobpf __ro_after_init;
 
+static struct workqueue_struct *memcg_wq __ro_after_init;
+
 static struct kmem_cache *memcg_cachep;
 static struct kmem_cache *memcg_pn_cachep;
 
@@ -2007,7 +2009,7 @@ static void schedule_drain_work(int cpu, struct work_struct *work)
 {
 	guard(rcu)();
 	if (!cpu_is_isolated(cpu))
-		schedule_work_on(cpu, work);
+		queue_work_on(cpu, memcg_wq, work);
 }
 
 /*
@@ -5119,6 +5121,11 @@ void mem_cgroup_sk_uncharge(const struct sock *sk, unsigned int nr_pages)
 	refill_stock(memcg, nr_pages);
 }
 
+void mem_cgroup_flush_workqueue(void)
+{
+	flush_workqueue(memcg_wq);
+}
+
 static int __init cgroup_memory(char *s)
 {
 	char *token;
@@ -5161,6 +5168,9 @@ int __init mem_cgroup_init(void)
 	cpuhp_setup_state_nocalls(CPUHP_MM_MEMCQ_DEAD, "mm/memctrl:dead", NULL,
 				  memcg_hotplug_cpu_dead);
 
+	memcg_wq = alloc_workqueue("memcg", WQ_PERCPU, 0);
+	WARN_ON(!memcg_wq);
+
 	for_each_possible_cpu(cpu) {
 		INIT_WORK(&per_cpu_ptr(&memcg_stock, cpu)->work,
 			  drain_local_memcg_stock);
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:45:04 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:45:04 +0100
Subject: [PATCH 17/33] PCI: Flush PCI probe workqueue on cpuset isolated partition change
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-18-frederic@kernel.org>

The HK_TYPE_DOMAIN housekeeping cpumask is now modifiable at runtime. In
order to synchronize against PCI probe works and make sure that no
asynchronous probing is still pending or executing on a newly isolated
CPU, the housekeeping subsystem must flush the PCI probe works.

However the PCI probe works can't be flushed easily since they are
queued to the main per-CPU workqueue pool.

Solve this with creating a PCI probe-specific pool and provide and use
the appropriate flushing API.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 drivers/pci/pci-driver.c | 17 ++++++++++++++++-
 include/linux/pci.h      |  3 +++
 kernel/sched/isolation.c |  2 ++
 3 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 786d6ce40999..d87f781e5ce9 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -337,6 +337,8 @@ static int local_pci_probe(struct drv_dev_and_id *ddi)
 	return 0;
 }
 
+static struct workqueue_struct *pci_probe_wq;
+
 struct pci_probe_arg {
 	struct drv_dev_and_id *ddi;
 	struct work_struct work;
@@ -407,7 +409,11 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
 		cpu = cpumask_any_and(cpumask_of_node(node),
 				      wq_domain_mask);
 		if (cpu < nr_cpu_ids) {
-			schedule_work_on(cpu, &arg.work);
+			struct workqueue_struct *wq = pci_probe_wq;
+
+			if (WARN_ON_ONCE(!wq))
+				wq = system_percpu_wq;
+			queue_work_on(cpu, wq, &arg.work);
 			rcu_read_unlock();
 			flush_work(&arg.work);
 			error = arg.ret;
@@ -425,6 +431,11 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
 	return error;
 }
 
+void pci_probe_flush_workqueue(void)
+{
+	flush_workqueue(pci_probe_wq);
+}
+
 /**
  * __pci_device_probe - check if a driver wants to claim a specific PCI device
  * @drv: driver to call to check if it wants the PCI device
@@ -1762,6 +1773,10 @@ static int __init pci_driver_init(void)
 {
 	int ret;
 
+	pci_probe_wq = alloc_workqueue("sync_wq", WQ_PERCPU, 0);
+	if (!pci_probe_wq)
+		return -ENOMEM;
+
 	ret = bus_register(&pci_bus_type);
 	if (ret)
 		return ret;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 864775651c6f..f14f467e50de 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1206,6 +1206,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
 				    struct pci_ops *ops, void *sysdata,
 				    struct list_head *resources);
 int pci_host_probe(struct pci_host_bridge *bridge);
+void pci_probe_flush_workqueue(void);
 int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax);
 int pci_bus_update_busn_res_end(struct pci_bus *b, int busmax);
 void pci_bus_release_busn_res(struct pci_bus *b);
@@ -2079,6 +2080,8 @@ static inline int pci_has_flag(int flag) { return 0; }
 _PCI_NOP_ALL(read, *)
 _PCI_NOP_ALL(write,)
 
+static inline void pci_probe_flush_workqueue(void) { }
+
 static inline struct pci_dev *pci_get_device(unsigned int vendor,
 					     unsigned int device,
 					     struct pci_dev *from)
diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c
index 8aac3c9f7c7f..7dbe037ea8df 100644
--- a/kernel/sched/isolation.c
+++ b/kernel/sched/isolation.c
@@ -8,6 +8,7 @@
  *
  */
 #include <linux/sched/isolation.h>
+#include <linux/pci.h>
 #include "sched.h"
 
 enum hk_flags {
@@ -145,6 +146,7 @@ int housekeeping_update(struct cpumask *isol_mask, enum hk_type type)
 
 	synchronize_rcu();
 
+	pci_probe_flush_workqueue();
 	mem_cgroup_flush_workqueue();
 	vmstat_flush_workqueue();
 
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:45:05 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:45:05 +0100
Subject: [PATCH 18/33] cpuset: Propagate cpuset isolation update to workqueue through housekeeping
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-19-frederic@kernel.org>

Until now, cpuset would propagate isolated partition changes to
workqueues so that unbound workers get properly reaffined.

Since housekeeping now centralizes, synchronize and propagates isolation
cpumask changes, perform the work from that subsystem for consolidation
and consistency purposes.

For simplification purpose, the target function is adapted to take the
new housekeeping mask instead of the isolated mask.

Suggested-by: Tejun Heo <tj at kernel.org>
Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 include/linux/workqueue.h |  2 +-
 init/Kconfig              |  1 +
 kernel/cgroup/cpuset.c    |  9 +++------
 kernel/sched/isolation.c  |  4 +++-
 kernel/workqueue.c        | 17 ++++++++++-------
 5 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index dabc351cc127..a4749f56398f 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -588,7 +588,7 @@ struct workqueue_attrs *alloc_workqueue_attrs_noprof(void);
 void free_workqueue_attrs(struct workqueue_attrs *attrs);
 int apply_workqueue_attrs(struct workqueue_struct *wq,
 			  const struct workqueue_attrs *attrs);
-extern int workqueue_unbound_exclude_cpumask(cpumask_var_t cpumask);
+extern int workqueue_unbound_housekeeping_update(const struct cpumask *hk);
 
 extern bool queue_work_on(int cpu, struct workqueue_struct *wq,
 			struct work_struct *work);
diff --git a/init/Kconfig b/init/Kconfig
index fa79feb8fe57..518830fb812f 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1254,6 +1254,7 @@ config CPUSETS
 	bool "Cpuset controller"
 	depends on SMP
 	select UNION_FIND
+	select CPU_ISOLATION
 	help
 	  This option will let you create and manage CPUSETs which
 	  allow dynamically partitioning a system into sets of CPUs and
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index e13e32491ebf..a492d23dd622 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -1484,15 +1484,12 @@ static void update_isolation_cpumasks(void)
 
 	lockdep_assert_cpus_held();
 
-	ret = workqueue_unbound_exclude_cpumask(isolated_cpus);
-	WARN_ON_ONCE(ret < 0);
-
-	ret = tmigr_isolated_exclude_cpumask(isolated_cpus);
-	WARN_ON_ONCE(ret < 0);
-
 	ret = housekeeping_update(isolated_cpus, HK_TYPE_DOMAIN);
 	WARN_ON_ONCE(ret < 0);
 
+	ret = tmigr_isolated_exclude_cpumask(isolated_cpus);
+	WARN_ON_ONCE(ret < 0);
+
 	isolated_cpus_updating = false;
 }
 
diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c
index 7dbe037ea8df..d224bca299ed 100644
--- a/kernel/sched/isolation.c
+++ b/kernel/sched/isolation.c
@@ -121,6 +121,7 @@ EXPORT_SYMBOL_GPL(housekeeping_test_cpu);
 int housekeeping_update(struct cpumask *isol_mask, enum hk_type type)
 {
 	struct cpumask *trial, *old = NULL;
+	int err;
 
 	if (type != HK_TYPE_DOMAIN)
 		return -ENOTSUPP;
@@ -149,10 +150,11 @@ int housekeeping_update(struct cpumask *isol_mask, enum hk_type type)
 	pci_probe_flush_workqueue();
 	mem_cgroup_flush_workqueue();
 	vmstat_flush_workqueue();
+	err = workqueue_unbound_housekeeping_update(housekeeping_cpumask(type));
 
 	kfree(old);
 
-	return 0;
+	return err;
 }
 
 void __init housekeeping_init(void)
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 253311af47c6..eb5660013222 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -6959,13 +6959,16 @@ static int workqueue_apply_unbound_cpumask(const cpumask_var_t unbound_cpumask)
 }
 
 /**
- * workqueue_unbound_exclude_cpumask - Exclude given CPUs from unbound cpumask
- * @exclude_cpumask: the cpumask to be excluded from wq_unbound_cpumask
+ * workqueue_unbound_housekeeping_update - Propagate housekeeping cpumask update
+ * @hk: the new housekeeping cpumask
  *
- * This function can be called from cpuset code to provide a set of isolated
- * CPUs that should be excluded from wq_unbound_cpumask.
+ * Update the unbound workqueue cpumask on top of the new housekeeping cpumask such
+ * that the effective unbound affinity is the intersection of the new housekeeping
+ * with the requested affinity set via nohz_full=/isolcpus= or sysfs.
+ *
+ * Return: 0 on success and -errno on failure.
  */
-int workqueue_unbound_exclude_cpumask(cpumask_var_t exclude_cpumask)
+int workqueue_unbound_housekeeping_update(const struct cpumask *hk)
 {
 	cpumask_var_t cpumask;
 	int ret = 0;
@@ -6981,14 +6984,14 @@ int workqueue_unbound_exclude_cpumask(cpumask_var_t exclude_cpumask)
 	 * (HK_TYPE_WQ ? HK_TYPE_DOMAIN) house keeping mask and rewritten
 	 * by any subsequent write to workqueue/cpumask sysfs file.
 	 */
-	if (!cpumask_andnot(cpumask, wq_requested_unbound_cpumask, exclude_cpumask))
+	if (!cpumask_and(cpumask, wq_requested_unbound_cpumask, hk))
 		cpumask_copy(cpumask, wq_requested_unbound_cpumask);
 	if (!cpumask_equal(cpumask, wq_unbound_cpumask))
 		ret = workqueue_apply_unbound_cpumask(cpumask);
 
 	/* Save the current isolated cpumask & export it via sysfs */
 	if (!ret)
-		cpumask_copy(wq_isolated_cpumask, exclude_cpumask);
+		cpumask_andnot(wq_isolated_cpumask, cpu_possible_mask, hk);
 
 	mutex_unlock(&wq_pool_mutex);
 	free_cpumask_var(cpumask);
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:45:06 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:45:06 +0100
Subject: [PATCH 19/33] cpuset: Propagate cpuset isolation update to timers through housekeeping
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-20-frederic@kernel.org>

Until now, cpuset would propagate isolated partition changes to
timer migration so that unbound timers don't get migrated to isolated
CPUs.

Since housekeeping now centralizes, synchronize and propagates isolation
cpumask changes, perform the work from that subsystem for consolidation
and consistency purposes.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 kernel/cgroup/cpuset.c   | 3 ---
 kernel/sched/isolation.c | 5 +++++
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index a492d23dd622..25ac6c98113c 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -1487,9 +1487,6 @@ static void update_isolation_cpumasks(void)
 	ret = housekeeping_update(isolated_cpus, HK_TYPE_DOMAIN);
 	WARN_ON_ONCE(ret < 0);
 
-	ret = tmigr_isolated_exclude_cpumask(isolated_cpus);
-	WARN_ON_ONCE(ret < 0);
-
 	isolated_cpus_updating = false;
 }
 
diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c
index d224bca299ed..84a257d05918 100644
--- a/kernel/sched/isolation.c
+++ b/kernel/sched/isolation.c
@@ -150,7 +150,12 @@ int housekeeping_update(struct cpumask *isol_mask, enum hk_type type)
 	pci_probe_flush_workqueue();
 	mem_cgroup_flush_workqueue();
 	vmstat_flush_workqueue();
+
 	err = workqueue_unbound_housekeeping_update(housekeeping_cpumask(type));
+	WARN_ON_ONCE(err < 0);
+
+	err = tmigr_isolated_exclude_cpumask(isol_mask);
+	WARN_ON_ONCE(err < 0);
 
 	kfree(old);
 
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:45:07 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:45:07 +0100
Subject: [PATCH 20/33] timers/migration: Remove superfluous cpuset isolation test
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-21-frederic@kernel.org>

Cpuset isolated partitions are now included in HK_TYPE_DOMAIN. Testing
if a CPU is part of an isolated partition alone is now useless.

Remove the superflous test.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 kernel/time/timer_migration.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/kernel/time/timer_migration.c b/kernel/time/timer_migration.c
index 3879575a4975..6da9cd562b20 100644
--- a/kernel/time/timer_migration.c
+++ b/kernel/time/timer_migration.c
@@ -466,9 +466,8 @@ static inline bool tmigr_is_isolated(int cpu)
 {
 	if (!static_branch_unlikely(&tmigr_exclude_isolated))
 		return false;
-	return (!housekeeping_cpu(cpu, HK_TYPE_DOMAIN) ||
-		cpuset_cpu_is_isolated(cpu)) &&
-	       housekeeping_cpu(cpu, HK_TYPE_KERNEL_NOISE);
+	return (!housekeeping_cpu(cpu, HK_TYPE_DOMAIN) &&
+		housekeeping_cpu(cpu, HK_TYPE_KERNEL_NOISE));
 }
 
 /*
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:45:08 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:45:08 +0100
Subject: [PATCH 21/33] cpuset: Remove cpuset_cpu_is_isolated()
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-22-frederic@kernel.org>

The set of cpuset isolated CPUs is now included in HK_TYPE_DOMAIN
housekeeping cpumask. There is no usecase left interested in just
checking what is isolated by cpuset and not by the isolcpus= kernel
boot parameter.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 include/linux/cpuset.h          |  6 ------
 include/linux/sched/isolation.h |  4 +---
 kernel/cgroup/cpuset.c          | 12 ------------
 3 files changed, 1 insertion(+), 21 deletions(-)

diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h
index 1c49ffd2ca9b..a4aa2f1767d0 100644
--- a/include/linux/cpuset.h
+++ b/include/linux/cpuset.h
@@ -79,7 +79,6 @@ extern void cpuset_unlock(void);
 extern void cpuset_cpus_allowed_locked(struct task_struct *p, struct cpumask *mask);
 extern void cpuset_cpus_allowed(struct task_struct *p, struct cpumask *mask);
 extern bool cpuset_cpus_allowed_fallback(struct task_struct *p);
-extern bool cpuset_cpu_is_isolated(int cpu);
 extern nodemask_t cpuset_mems_allowed(struct task_struct *p);
 #define cpuset_current_mems_allowed (current->mems_allowed)
 void cpuset_init_current_mems_allowed(void);
@@ -215,11 +214,6 @@ static inline bool cpuset_cpus_allowed_fallback(struct task_struct *p)
 	return false;
 }
 
-static inline bool cpuset_cpu_is_isolated(int cpu)
-{
-	return false;
-}
-
 static inline nodemask_t cpuset_mems_allowed(struct task_struct *p)
 {
 	return node_possible_map;
diff --git a/include/linux/sched/isolation.h b/include/linux/sched/isolation.h
index 6842a1ba4d13..19905adbb705 100644
--- a/include/linux/sched/isolation.h
+++ b/include/linux/sched/isolation.h
@@ -2,7 +2,6 @@
 #define _LINUX_SCHED_ISOLATION_H
 
 #include <linux/cpumask.h>
-#include <linux/cpuset.h>
 #include <linux/init.h>
 #include <linux/tick.h>
 
@@ -84,8 +83,7 @@ static inline bool housekeeping_cpu(int cpu, enum hk_type type)
 static inline bool cpu_is_isolated(int cpu)
 {
 	return !housekeeping_test_cpu(cpu, HK_TYPE_DOMAIN) ||
-	       !housekeeping_test_cpu(cpu, HK_TYPE_TICK) ||
-	       cpuset_cpu_is_isolated(cpu);
+	       !housekeeping_test_cpu(cpu, HK_TYPE_TICK);
 }
 
 #endif /* _LINUX_SCHED_ISOLATION_H */
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 25ac6c98113c..cd6119c02beb 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -29,7 +29,6 @@
 #include <linux/mempolicy.h>
 #include <linux/mm.h>
 #include <linux/memory.h>
-#include <linux/export.h>
 #include <linux/rcupdate.h>
 #include <linux/sched.h>
 #include <linux/sched/deadline.h>
@@ -1490,17 +1489,6 @@ static void update_isolation_cpumasks(void)
 	isolated_cpus_updating = false;
 }
 
-/**
- * cpuset_cpu_is_isolated - Check if the given CPU is isolated
- * @cpu: the CPU number to be checked
- * Return: true if CPU is used in an isolated partition, false otherwise
- */
-bool cpuset_cpu_is_isolated(int cpu)
-{
-	return cpumask_test_cpu(cpu, isolated_cpus);
-}
-EXPORT_SYMBOL_GPL(cpuset_cpu_is_isolated);
-
 /**
  * rm_siblings_excl_cpus - Remove exclusive CPUs that are used by sibling cpusets
  * @parent: Parent cpuset containing all siblings
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:45:09 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:45:09 +0100
Subject: [PATCH 22/33] sched/isolation: Remove HK_TYPE_TICK test from cpu_is_isolated()
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-23-frederic@kernel.org>

It doesn't make sense to use nohz_full without also isolating the
related CPUs from the domain topology, either through the use of
isolcpus= or cpuset isolated partitions.

And now HK_TYPE_DOMAIN includes all kinds of domain isolated CPUs.

This means that HK_TYPE_KERNEL_NOISE (of which HK_TYPE_TICK is only an
alias) should always be a subset of HK_TYPE_DOMAIN.

Therefore if a CPU is not HK_TYPE_DOMAIN, it shouldn't be
HK_TYPE_KERNEL_NOISE either. Testing the former is then enough.

Simplify cpu_is_isolated() accordingly.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 include/linux/sched/isolation.h | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/include/linux/sched/isolation.h b/include/linux/sched/isolation.h
index 19905adbb705..cbb1d30f699a 100644
--- a/include/linux/sched/isolation.h
+++ b/include/linux/sched/isolation.h
@@ -82,8 +82,7 @@ static inline bool housekeeping_cpu(int cpu, enum hk_type type)
 
 static inline bool cpu_is_isolated(int cpu)
 {
-	return !housekeeping_test_cpu(cpu, HK_TYPE_DOMAIN) ||
-	       !housekeeping_test_cpu(cpu, HK_TYPE_TICK);
+	return !housekeeping_test_cpu(cpu, HK_TYPE_DOMAIN);
 }
 
 #endif /* _LINUX_SCHED_ISOLATION_H */
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:45:10 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:45:10 +0100
Subject: [PATCH 23/33] PCI: Remove superfluous HK_TYPE_WQ check
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-24-frederic@kernel.org>

It doesn't make sense to use nohz_full without also isolating the
related CPUs from the domain topology, either through the use of
isolcpus= or cpuset isolated partitions.

And now HK_TYPE_DOMAIN includes all kinds of domain isolated CPUs.

This means that HK_TYPE_KERNEL_NOISE (of which HK_TYPE_WQ is only an
alias) should always be a subset of HK_TYPE_DOMAIN.

Therefore sane configurations verify:

	HK_TYPE_KERNEL_NOISE | HK_TYPE_DOMAIN == HK_TYPE_DOMAIN

Simplify the PCI probe target election accordingly.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 drivers/pci/pci-driver.c | 17 +++--------------
 1 file changed, 3 insertions(+), 14 deletions(-)

diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index d87f781e5ce9..a9590601835a 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -384,16 +384,9 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
 	    pci_physfn_is_probed(dev)) {
 		error = local_pci_probe(&ddi);
 	} else {
-		cpumask_var_t wq_domain_mask;
 		struct pci_probe_arg arg = { .ddi = &ddi };
 
 		INIT_WORK_ONSTACK(&arg.work, local_pci_probe_callback);
-
-		if (!zalloc_cpumask_var(&wq_domain_mask, GFP_KERNEL)) {
-			error = -ENOMEM;
-			goto out;
-		}
-
 		/*
 		 * The target election and the enqueue of the work must be within
 		 * the same RCU read side section so that when the workqueue pool
@@ -402,12 +395,9 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
 		 * targets.
 		 */
 		rcu_read_lock();
-		cpumask_and(wq_domain_mask,
-			    housekeeping_cpumask(HK_TYPE_WQ),
-			    housekeeping_cpumask(HK_TYPE_DOMAIN));
-
 		cpu = cpumask_any_and(cpumask_of_node(node),
-				      wq_domain_mask);
+				      housekeeping_cpumask(HK_TYPE_DOMAIN));
+
 		if (cpu < nr_cpu_ids) {
 			struct workqueue_struct *wq = pci_probe_wq;
 
@@ -422,10 +412,9 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
 			error = local_pci_probe(&ddi);
 		}
 
-		free_cpumask_var(wq_domain_mask);
 		destroy_work_on_stack(&arg.work);
 	}
-out:
+
 	dev->is_probed = 0;
 	cpu_hotplug_enable();
 	return error;
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:45:11 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:45:11 +0100
Subject: [PATCH 24/33] kthread: Refine naming of affinity related fields
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-25-frederic@kernel.org>

The kthreads preferred affinity related fields use "hotplug" as the base
of their naming because the affinity management was initially deemed to
deal with CPU hotplug.

The scope of this role is going to broaden now and also deal with
cpuset isolated partition updates.

Switch the naming accordingly.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 kernel/kthread.c | 38 +++++++++++++++++++-------------------
 1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/kernel/kthread.c b/kernel/kthread.c
index 99a3808d086f..f1e4f1f35cae 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -35,8 +35,8 @@ static DEFINE_SPINLOCK(kthread_create_lock);
 static LIST_HEAD(kthread_create_list);
 struct task_struct *kthreadd_task;
 
-static LIST_HEAD(kthreads_hotplug);
-static DEFINE_MUTEX(kthreads_hotplug_lock);
+static LIST_HEAD(kthread_affinity_list);
+static DEFINE_MUTEX(kthread_affinity_lock);
 
 struct kthread_create_info
 {
@@ -69,7 +69,7 @@ struct kthread {
 	/* To store the full name if task comm is truncated. */
 	char *full_name;
 	struct task_struct *task;
-	struct list_head hotplug_node;
+	struct list_head affinity_node;
 	struct cpumask *preferred_affinity;
 };
 
@@ -128,7 +128,7 @@ bool set_kthread_struct(struct task_struct *p)
 
 	init_completion(&kthread->exited);
 	init_completion(&kthread->parked);
-	INIT_LIST_HEAD(&kthread->hotplug_node);
+	INIT_LIST_HEAD(&kthread->affinity_node);
 	p->vfork_done = &kthread->exited;
 
 	kthread->task = p;
@@ -323,10 +323,10 @@ void __noreturn kthread_exit(long result)
 {
 	struct kthread *kthread = to_kthread(current);
 	kthread->result = result;
-	if (!list_empty(&kthread->hotplug_node)) {
-		mutex_lock(&kthreads_hotplug_lock);
-		list_del(&kthread->hotplug_node);
-		mutex_unlock(&kthreads_hotplug_lock);
+	if (!list_empty(&kthread->affinity_node)) {
+		mutex_lock(&kthread_affinity_lock);
+		list_del(&kthread->affinity_node);
+		mutex_unlock(&kthread_affinity_lock);
 
 		if (kthread->preferred_affinity) {
 			kfree(kthread->preferred_affinity);
@@ -390,9 +390,9 @@ static void kthread_affine_node(void)
 			return;
 		}
 
-		mutex_lock(&kthreads_hotplug_lock);
-		WARN_ON_ONCE(!list_empty(&kthread->hotplug_node));
-		list_add_tail(&kthread->hotplug_node, &kthreads_hotplug);
+		mutex_lock(&kthread_affinity_lock);
+		WARN_ON_ONCE(!list_empty(&kthread->affinity_node));
+		list_add_tail(&kthread->affinity_node, &kthread_affinity_list);
 		/*
 		 * The node cpumask is racy when read from kthread() but:
 		 * - a racing CPU going down will either fail on the subsequent
@@ -402,7 +402,7 @@ static void kthread_affine_node(void)
 		 */
 		kthread_fetch_affinity(kthread, affinity);
 		set_cpus_allowed_ptr(current, affinity);
-		mutex_unlock(&kthreads_hotplug_lock);
+		mutex_unlock(&kthread_affinity_lock);
 
 		free_cpumask_var(affinity);
 	}
@@ -873,16 +873,16 @@ int kthread_affine_preferred(struct task_struct *p, const struct cpumask *mask)
 		goto out;
 	}
 
-	mutex_lock(&kthreads_hotplug_lock);
+	mutex_lock(&kthread_affinity_lock);
 	cpumask_copy(kthread->preferred_affinity, mask);
-	WARN_ON_ONCE(!list_empty(&kthread->hotplug_node));
-	list_add_tail(&kthread->hotplug_node, &kthreads_hotplug);
+	WARN_ON_ONCE(!list_empty(&kthread->affinity_node));
+	list_add_tail(&kthread->affinity_node, &kthread_affinity_list);
 	kthread_fetch_affinity(kthread, affinity);
 
 	scoped_guard (raw_spinlock_irqsave, &p->pi_lock)
 		set_cpus_allowed_force(p, affinity);
 
-	mutex_unlock(&kthreads_hotplug_lock);
+	mutex_unlock(&kthread_affinity_lock);
 out:
 	free_cpumask_var(affinity);
 
@@ -903,9 +903,9 @@ static int kthreads_online_cpu(unsigned int cpu)
 	struct kthread *k;
 	int ret;
 
-	guard(mutex)(&kthreads_hotplug_lock);
+	guard(mutex)(&kthread_affinity_lock);
 
-	if (list_empty(&kthreads_hotplug))
+	if (list_empty(&kthread_affinity_list))
 		return 0;
 
 	if (!zalloc_cpumask_var(&affinity, GFP_KERNEL))
@@ -913,7 +913,7 @@ static int kthreads_online_cpu(unsigned int cpu)
 
 	ret = 0;
 
-	list_for_each_entry(k, &kthreads_hotplug, hotplug_node) {
+	list_for_each_entry(k, &kthread_affinity_list, affinity_node) {
 		if (WARN_ON_ONCE((k->task->flags & PF_NO_SETAFFINITY) ||
 				 kthread_is_per_cpu(k->task))) {
 			ret = -EINVAL;
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:45:12 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:45:12 +0100
Subject: [PATCH 25/33] kthread: Include unbound kthreads in the managed affinity list
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-26-frederic@kernel.org>

The managed affinity list currently contains only unbound kthreads that
have affinity preferences. Unbound kthreads globally affine by default
are outside of the list because their affinity is automatically managed
by the scheduler (through the fallback housekeeping mask) and by cpuset.

However in order to preserve the preferred affinity of kthreads, cpuset
will delegate the isolated partition update propagation to the
housekeeping and kthread code.

Prepare for that with including all unbound kthreads in the managed
affinity list.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 kernel/kthread.c | 70 ++++++++++++++++++++++++++++--------------------
 1 file changed, 41 insertions(+), 29 deletions(-)

diff --git a/kernel/kthread.c b/kernel/kthread.c
index f1e4f1f35cae..51c0908d3d02 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -365,9 +365,10 @@ static void kthread_fetch_affinity(struct kthread *kthread, struct cpumask *cpum
 	if (kthread->preferred_affinity) {
 		pref = kthread->preferred_affinity;
 	} else {
-		if (WARN_ON_ONCE(kthread->node == NUMA_NO_NODE))
-			return;
-		pref = cpumask_of_node(kthread->node);
+		if (kthread->node == NUMA_NO_NODE)
+			pref = housekeeping_cpumask(HK_TYPE_KTHREAD);
+		else
+			pref = cpumask_of_node(kthread->node);
 	}
 
 	cpumask_and(cpumask, pref, housekeeping_cpumask(HK_TYPE_KTHREAD));
@@ -380,32 +381,29 @@ static void kthread_affine_node(void)
 	struct kthread *kthread = to_kthread(current);
 	cpumask_var_t affinity;
 
-	WARN_ON_ONCE(kthread_is_per_cpu(current));
+	if (WARN_ON_ONCE(kthread_is_per_cpu(current)))
+		return;
 
-	if (kthread->node == NUMA_NO_NODE) {
-		housekeeping_affine(current, HK_TYPE_KTHREAD);
-	} else {
-		if (!zalloc_cpumask_var(&affinity, GFP_KERNEL)) {
-			WARN_ON_ONCE(1);
-			return;
-		}
-
-		mutex_lock(&kthread_affinity_lock);
-		WARN_ON_ONCE(!list_empty(&kthread->affinity_node));
-		list_add_tail(&kthread->affinity_node, &kthread_affinity_list);
-		/*
-		 * The node cpumask is racy when read from kthread() but:
-		 * - a racing CPU going down will either fail on the subsequent
-		 *   call to set_cpus_allowed_ptr() or be migrated to housekeepers
-		 *   afterwards by the scheduler.
-		 * - a racing CPU going up will be handled by kthreads_online_cpu()
-		 */
-		kthread_fetch_affinity(kthread, affinity);
-		set_cpus_allowed_ptr(current, affinity);
-		mutex_unlock(&kthread_affinity_lock);
-
-		free_cpumask_var(affinity);
+	if (!zalloc_cpumask_var(&affinity, GFP_KERNEL)) {
+		WARN_ON_ONCE(1);
+		return;
 	}
+
+	mutex_lock(&kthread_affinity_lock);
+	WARN_ON_ONCE(!list_empty(&kthread->affinity_node));
+	list_add_tail(&kthread->affinity_node, &kthread_affinity_list);
+	/*
+	 * The node cpumask is racy when read from kthread() but:
+	 * - a racing CPU going down will either fail on the subsequent
+	 *   call to set_cpus_allowed_ptr() or be migrated to housekeepers
+	 *   afterwards by the scheduler.
+	 * - a racing CPU going up will be handled by kthreads_online_cpu()
+	 */
+	kthread_fetch_affinity(kthread, affinity);
+	set_cpus_allowed_ptr(current, affinity);
+	mutex_unlock(&kthread_affinity_lock);
+
+	free_cpumask_var(affinity);
 }
 
 static int kthread(void *_create)
@@ -919,8 +917,22 @@ static int kthreads_online_cpu(unsigned int cpu)
 			ret = -EINVAL;
 			continue;
 		}
-		kthread_fetch_affinity(k, affinity);
-		set_cpus_allowed_ptr(k->task, affinity);
+
+		/*
+		 * Unbound kthreads without preferred affinity are already affine
+		 * to housekeeping, whether those CPUs are online or not. So no need
+		 * to handle newly online CPUs for them.
+		 *
+		 * But kthreads with a preferred affinity or node are different:
+		 * if none of their preferred CPUs are online and part of
+		 * housekeeping at the same time, they must be affine to housekeeping.
+		 * But as soon as one of their preferred CPU becomes online, they must
+		 * be affine to them.
+		 */
+		if (k->preferred_affinity || k->node != NUMA_NO_NODE) {
+			kthread_fetch_affinity(k, affinity);
+			set_cpus_allowed_ptr(k->task, affinity);
+		}
 	}
 
 	free_cpumask_var(affinity);
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:45:13 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:45:13 +0100
Subject: [PATCH 26/33] kthread: Include kthreadd to the managed affinity list
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-27-frederic@kernel.org>

The unbound kthreads affinity management performed by cpuset is going to
be imported to the kthread core code for consolidation purposes.

Treat kthreadd just like any other kthread.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 kernel/kthread.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/kernel/kthread.c b/kernel/kthread.c
index 51c0908d3d02..85ccf5bb17c9 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -818,12 +818,13 @@ int kthreadd(void *unused)
 	/* Setup a clean context for our children to inherit. */
 	set_task_comm(tsk, comm);
 	ignore_signals(tsk);
-	set_cpus_allowed_ptr(tsk, housekeeping_cpumask(HK_TYPE_KTHREAD));
 	set_mems_allowed(node_states[N_MEMORY]);
 
 	current->flags |= PF_NOFREEZE;
 	cgroup_init_kthreadd();
 
+	kthread_affine_node();
+
 	for (;;) {
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (list_empty(&kthread_create_list))
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:45:14 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:45:14 +0100
Subject: [PATCH 27/33] kthread: Rely on HK_TYPE_DOMAIN for preferred affinity management
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-28-frederic@kernel.org>

Unbound kthreads want to run neither on nohz_full CPUs nor on domain
isolated CPUs. And since nohz_full implies domain isolation, checking
the latter is enough to verify both.

Therefore exclude kthreads from domain isolation.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 kernel/kthread.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/kernel/kthread.c b/kernel/kthread.c
index 85ccf5bb17c9..968fa5868d21 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -362,18 +362,20 @@ static void kthread_fetch_affinity(struct kthread *kthread, struct cpumask *cpum
 {
 	const struct cpumask *pref;
 
+	guard(rcu)();
+
 	if (kthread->preferred_affinity) {
 		pref = kthread->preferred_affinity;
 	} else {
 		if (kthread->node == NUMA_NO_NODE)
-			pref = housekeeping_cpumask(HK_TYPE_KTHREAD);
+			pref = housekeeping_cpumask(HK_TYPE_DOMAIN);
 		else
 			pref = cpumask_of_node(kthread->node);
 	}
 
-	cpumask_and(cpumask, pref, housekeeping_cpumask(HK_TYPE_KTHREAD));
+	cpumask_and(cpumask, pref, housekeeping_cpumask(HK_TYPE_DOMAIN));
 	if (cpumask_empty(cpumask))
-		cpumask_copy(cpumask, housekeeping_cpumask(HK_TYPE_KTHREAD));
+		cpumask_copy(cpumask, housekeeping_cpumask(HK_TYPE_DOMAIN));
 }
 
 static void kthread_affine_node(void)
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:45:15 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:45:15 +0100
Subject: [PATCH 28/33] sched: Switch the fallback task allowed cpumask to HK_TYPE_DOMAIN
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-29-frederic@kernel.org>

Tasks that have all their allowed CPUs offline don't want their affinity
to fallback on either nohz_full CPUs or on domain isolated CPUs. And
since nohz_full implies domain isolation, checking the latter is enough
to verify both.

Therefore exclude domain isolation from fallback task affinity.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 include/linux/mmu_context.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/mmu_context.h b/include/linux/mmu_context.h
index ac01dc4eb2ce..ed3dd0f3fe19 100644
--- a/include/linux/mmu_context.h
+++ b/include/linux/mmu_context.h
@@ -24,7 +24,7 @@ static inline void leave_mm(void) { }
 #ifndef task_cpu_possible_mask
 # define task_cpu_possible_mask(p)	cpu_possible_mask
 # define task_cpu_possible(cpu, p)	true
-# define task_cpu_fallback_mask(p)	housekeeping_cpumask(HK_TYPE_TICK)
+# define task_cpu_fallback_mask(p)	housekeeping_cpumask(HK_TYPE_DOMAIN)
 #else
 # define task_cpu_possible(cpu, p)	cpumask_test_cpu((cpu), task_cpu_possible_mask(p))
 #endif
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:45:16 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:45:16 +0100
Subject: [PATCH 29/33] sched/arm64: Move fallback task cpumask to HK_TYPE_DOMAIN
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-30-frederic@kernel.org>

When none of the allowed CPUs of a task are online, it gets migrated
to the fallback cpumask which is all the non nohz_full CPUs.

However just like nohz_full CPUs, domain isolated CPUs don't want to be
disturbed by tasks that have lost their CPU affinities.

And since nohz_full rely on domain isolation to work correctly, the
housekeeping mask of domain isolated CPUs should always be a superset of
the housekeeping mask of nohz_full CPUs (there can be CPUs that are
domain isolated but not nohz_full, OTOH there shouldn't be nohz_full
CPUs that are not domain isolated):

	HK_TYPE_DOMAIN | HK_TYPE_KERNEL_NOISE == HK_TYPE_DOMAIN

Therefore use HK_TYPE_DOMAIN as the appropriate fallback target for
tasks and since this cpumask can be modified at runtime, make sure
that 32 bits support CPUs on ARM64 mismatched systems are not isolated
by cpusets.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 arch/arm64/kernel/cpufeature.c | 18 +++++++++++++++---
 include/linux/cpu.h            |  4 ++++
 kernel/cgroup/cpuset.c         | 17 ++++++++++++++---
 3 files changed, 33 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index c840a93b9ef9..70b0e45e299a 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -1656,6 +1656,18 @@ has_cpuid_feature(const struct arm64_cpu_capabilities *entry, int scope)
 	return feature_matches(val, entry);
 }
 
+/*
+ * 32 bits support CPUs can't be isolated because tasks may be
+ * arbitrarily affine to them, defeating the purpose of isolation.
+ */
+bool arch_isolated_cpus_can_update(struct cpumask *new_cpus)
+{
+	if (static_branch_unlikely(&arm64_mismatched_32bit_el0))
+		return !cpumask_intersects(cpu_32bit_el0_mask, new_cpus);
+	else
+		return true;
+}
+
 const struct cpumask *system_32bit_el0_cpumask(void)
 {
 	if (!system_supports_32bit_el0())
@@ -1669,7 +1681,7 @@ const struct cpumask *system_32bit_el0_cpumask(void)
 
 const struct cpumask *task_cpu_fallback_mask(struct task_struct *p)
 {
-	return __task_cpu_possible_mask(p, housekeeping_cpumask(HK_TYPE_TICK));
+	return __task_cpu_possible_mask(p, housekeeping_cpumask(HK_TYPE_DOMAIN));
 }
 
 static int __init parse_32bit_el0_param(char *str)
@@ -3987,8 +3999,8 @@ static int enable_mismatched_32bit_el0(unsigned int cpu)
 	bool cpu_32bit = false;
 
 	if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) {
-		if (!housekeeping_cpu(cpu, HK_TYPE_TICK))
-			pr_info("Treating adaptive-ticks CPU %u as 64-bit only\n", cpu);
+		if (!housekeeping_cpu(cpu, HK_TYPE_DOMAIN))
+			pr_info("Treating domain isolated CPU %u as 64-bit only\n", cpu);
 		else
 			cpu_32bit = true;
 	}
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index 487b3bf2e1ea..0b48af25ab5c 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -229,4 +229,8 @@ static inline bool cpu_attack_vector_mitigated(enum cpu_attack_vectors v)
 #define smt_mitigations SMT_MITIGATIONS_OFF
 #endif
 
+struct cpumask;
+
+bool arch_isolated_cpus_can_update(struct cpumask *new_cpus);
+
 #endif /* _LINUX_CPU_H_ */
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index cd6119c02beb..1cc83a3c25f6 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -1408,14 +1408,22 @@ static void partition_xcpus_del(int old_prs, struct cpuset *parent,
 	cpumask_or(parent->effective_cpus, parent->effective_cpus, xcpus);
 }
 
+bool __weak arch_isolated_cpus_can_update(struct cpumask *new_cpus)
+{
+	return true;
+}
+
 /*
- * isolated_cpus_can_update - check for isolated & nohz_full conflicts
+ * isolated_cpus_can_update - check for conflicts against housekeeping and
+ *                            CPUs capabilities.
  * @add_cpus: cpu mask for cpus that are going to be isolated
  * @del_cpus: cpu mask for cpus that are no longer isolated, can be NULL
  * Return: false if there is conflict, true otherwise
  *
- * If nohz_full is enabled and we have isolated CPUs, their combination must
- * still leave housekeeping CPUs.
+ * Check for conflicts:
+ * - If nohz_full is enabled and there are isolated CPUs, their combination must
+ *   still leave housekeeping CPUs.
+ * - Architecture has CPU capabilities incompatible with being isolated
  *
  * TBD: Should consider merging this function into
  *      prstate_housekeeping_conflict().
@@ -1426,6 +1434,9 @@ static bool isolated_cpus_can_update(struct cpumask *add_cpus,
 	cpumask_var_t full_hk_cpus;
 	int res = true;
 
+	if (!arch_isolated_cpus_can_update(add_cpus))
+		return false;
+
 	if (!housekeeping_enabled(HK_TYPE_KERNEL_NOISE))
 		return true;
 
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:45:17 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:45:17 +0100
Subject: [PATCH 30/33] kthread: Honour kthreads preferred affinity after cpuset changes
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-31-frederic@kernel.org>

When cpuset isolated partitions get updated, unbound kthreads get
indifferently affine to all non isolated CPUs, regardless of their
individual affinity preferences.

For example kswapd is a per-node kthread that prefers to be affine to
the node it refers to. Whenever an isolated partition is created,
updated or deleted, kswapd's node affinity is going to be broken if any
CPU in the related node is not isolated because kswapd will be affine
globally.

Fix this with letting the consolidated kthread managed affinity code do
the affinity update on behalf of cpuset.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 include/linux/kthread.h  |  1 +
 kernel/cgroup/cpuset.c   |  5 ++---
 kernel/kthread.c         | 41 ++++++++++++++++++++++++++++++----------
 kernel/sched/isolation.c |  3 +++
 4 files changed, 37 insertions(+), 13 deletions(-)

diff --git a/include/linux/kthread.h b/include/linux/kthread.h
index 8d27403888ce..c92c1149ee6e 100644
--- a/include/linux/kthread.h
+++ b/include/linux/kthread.h
@@ -100,6 +100,7 @@ void kthread_unpark(struct task_struct *k);
 void kthread_parkme(void);
 void kthread_exit(long result) __noreturn;
 void kthread_complete_and_exit(struct completion *, long) __noreturn;
+int kthreads_update_housekeeping(void);
 
 int kthreadd(void *unused);
 extern struct task_struct *kthreadd_task;
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 1cc83a3c25f6..c8cfaf5cd4a1 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -1208,11 +1208,10 @@ void cpuset_update_tasks_cpumask(struct cpuset *cs, struct cpumask *new_cpus)
 
 		if (top_cs) {
 			/*
+			 * PF_KTHREAD tasks are handled by housekeeping.
 			 * PF_NO_SETAFFINITY tasks are ignored.
-			 * All per cpu kthreads should have PF_NO_SETAFFINITY
-			 * flag set, see kthread_set_per_cpu().
 			 */
-			if (task->flags & PF_NO_SETAFFINITY)
+			if (task->flags & (PF_KTHREAD | PF_NO_SETAFFINITY))
 				continue;
 			cpumask_andnot(new_cpus, possible_mask, subpartitions_cpus);
 		} else {
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 968fa5868d21..03008154249c 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -891,14 +891,7 @@ int kthread_affine_preferred(struct task_struct *p, const struct cpumask *mask)
 }
 EXPORT_SYMBOL_GPL(kthread_affine_preferred);
 
-/*
- * Re-affine kthreads according to their preferences
- * and the newly online CPU. The CPU down part is handled
- * by select_fallback_rq() which default re-affines to
- * housekeepers from other nodes in case the preferred
- * affinity doesn't apply anymore.
- */
-static int kthreads_online_cpu(unsigned int cpu)
+static int kthreads_update_affinity(bool force)
 {
 	cpumask_var_t affinity;
 	struct kthread *k;
@@ -924,7 +917,8 @@ static int kthreads_online_cpu(unsigned int cpu)
 		/*
 		 * Unbound kthreads without preferred affinity are already affine
 		 * to housekeeping, whether those CPUs are online or not. So no need
-		 * to handle newly online CPUs for them.
+		 * to handle newly online CPUs for them. However housekeeping changes
+		 * have to be applied.
 		 *
 		 * But kthreads with a preferred affinity or node are different:
 		 * if none of their preferred CPUs are online and part of
@@ -932,7 +926,7 @@ static int kthreads_online_cpu(unsigned int cpu)
 		 * But as soon as one of their preferred CPU becomes online, they must
 		 * be affine to them.
 		 */
-		if (k->preferred_affinity || k->node != NUMA_NO_NODE) {
+		if (force || k->preferred_affinity || k->node != NUMA_NO_NODE) {
 			kthread_fetch_affinity(k, affinity);
 			set_cpus_allowed_ptr(k->task, affinity);
 		}
@@ -943,6 +937,33 @@ static int kthreads_online_cpu(unsigned int cpu)
 	return ret;
 }
 
+/**
+ * kthreads_update_housekeeping - Update kthreads affinity on cpuset change
+ *
+ * When cpuset changes a partition type to/from "isolated" or updates related
+ * cpumasks, propagate the housekeeping cpumask change to preferred kthreads
+ * affinity.
+ *
+ * Returns 0 if successful, -ENOMEM if temporary mask couldn't
+ * be allocated or -EINVAL in case of internal error.
+ */
+int kthreads_update_housekeeping(void)
+{
+	return kthreads_update_affinity(true);
+}
+
+/*
+ * Re-affine kthreads according to their preferences
+ * and the newly online CPU. The CPU down part is handled
+ * by select_fallback_rq() which default re-affines to
+ * housekeepers from other nodes in case the preferred
+ * affinity doesn't apply anymore.
+ */
+static int kthreads_online_cpu(unsigned int cpu)
+{
+	return kthreads_update_affinity(false);
+}
+
 static int kthreads_init(void)
 {
 	return cpuhp_setup_state(CPUHP_AP_KTHREADS_ONLINE, "kthreads:online",
diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c
index 84a257d05918..c499474866b8 100644
--- a/kernel/sched/isolation.c
+++ b/kernel/sched/isolation.c
@@ -157,6 +157,9 @@ int housekeeping_update(struct cpumask *isol_mask, enum hk_type type)
 	err = tmigr_isolated_exclude_cpumask(isol_mask);
 	WARN_ON_ONCE(err < 0);
 
+	err = kthreads_update_housekeeping();
+	WARN_ON_ONCE(err < 0);
+
 	kfree(old);
 
 	return err;
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:45:19 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:45:19 +0100
Subject: [PATCH 32/33] kthread: Document kthread_affine_preferred()
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-33-frederic@kernel.org>

The documentation of this new API has been overlooked during its
introduction. Fill the gap.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 kernel/kthread.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/kernel/kthread.c b/kernel/kthread.c
index 51f419139dea..c50f4c0eabfe 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -856,6 +856,18 @@ int kthreadd(void *unused)
 	return 0;
 }
 
+/**
+ * kthread_affine_preferred - Define a kthread's preferred affinity
+ * @p: thread created by kthread_create().
+ * @mask: preferred mask of CPUs (might not be online, must be possible) for @p
+ *        to run on.
+ *
+ * Similar to kthread_bind_mask() except that the affinity is not a requirement
+ * but rather a preference that can be constrained by CPU isolation or CPU hotplug.
+ * Must be called before the first wakeup of the kthread.
+ *
+ * Returns 0 if the affinity has been applied.
+ */
 int kthread_affine_preferred(struct task_struct *p, const struct cpumask *mask)
 {
 	struct kthread *kthread = to_kthread(p);
-- 
2.51.1



From andrew at lunn.ch  Wed Dec 24 05:51:11 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Wed, 24 Dec 2025 14:51:11 +0100
Subject: [PATCH v2] phy: fsl-imx8mq-usb: add debugfs to access control
 register
In-Reply-To: <20251224111716.2925597-1-xu.yang_2@nxp.com>
References: <20251224111716.2925597-1-xu.yang_2@nxp.com>
Message-ID: <9870fd41-bafb-4ab0-91ff-8fcea53ca0a9@lunn.ch>

On Wed, Dec 24, 2025 at 07:17:16PM +0800, Xu Yang wrote:
> The CR port is a simple 16-bit data/address parallel port that is
> provided for on-chip access to the control registers inside the
> USB 3.0 femtoPHY. While access to these registers is not required
> for normal PHY operation, this interface enables you to access
> some of the PHY?s diagnostic features during normal operation or
> to override some basic PHY control signals.
> 
> 3 debugfs files are created to read and write control registers,
> all use hexadecimal format:
> ctrl_reg_base: the register offset to write, or the start offset
>                to read.
> ctrl_reg_count: how many continuous registers to be read.
> ctrl_reg_value: read to show the continuous registers value from
>                 the offset in ctrl_reg_base, to ctrl_reg_base
>                 + ctrl_reg_count - 1, one line for one register.
>                 when write, override the register at ctrl_reg_base,
>                 one time can only change one 16bits register.

Are the registers openly documented somewhere? Could you include a
link in the commit message.

     Andrew


From ryan.roberts at arm.com  Wed Dec 24 05:51:22 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Wed, 24 Dec 2025 13:51:22 +0000
Subject: [PATCH v4 2/5] arm64: mm: factor out the address and ptep
 alignment into a new helper
In-Reply-To: <47e29030347c23ffce238ff5ed752da01a8cc7cb.1766455378.git.baolin.wang@linux.alibaba.com>
References: <cover.1766455377.git.baolin.wang@linux.alibaba.com>
 <47e29030347c23ffce238ff5ed752da01a8cc7cb.1766455378.git.baolin.wang@linux.alibaba.com>
Message-ID: <6440050d-844b-4587-8531-038038d32f67@arm.com>

On 23/12/2025 05:48, Baolin Wang wrote:
> Factor out the contpte block's address and ptep alignment into a new helper,
> and will be reused in the following patch.
> 
> No functional changes.
> 
> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>

LGTM:

Reviewed-by: Ryan Roberts <ryan.roberts at arm.com>

> ---
>  arch/arm64/mm/contpte.c | 29 +++++++++++++++++++++--------
>  1 file changed, 21 insertions(+), 8 deletions(-)
> 
> diff --git a/arch/arm64/mm/contpte.c b/arch/arm64/mm/contpte.c
> index 589bcf878938..e4ddeb46f25d 100644
> --- a/arch/arm64/mm/contpte.c
> +++ b/arch/arm64/mm/contpte.c
> @@ -26,6 +26,26 @@ static inline pte_t *contpte_align_down(pte_t *ptep)
>  	return PTR_ALIGN_DOWN(ptep, sizeof(*ptep) * CONT_PTES);
>  }
>  
> +static inline pte_t *contpte_align_addr_ptep(unsigned long *start,
> +					     unsigned long *end, pte_t *ptep,
> +					     unsigned int nr)
> +{
> +	/*
> +	 * Note: caller must ensure these nr PTEs are consecutive (present)
> +	 * PTEs that map consecutive pages of the same large folio within a
> +	 * single VMA and a single page table.
> +	 */
> +	if (pte_cont(__ptep_get(ptep + nr - 1)))
> +		*end = ALIGN(*end, CONT_PTE_SIZE);
> +
> +	if (pte_cont(__ptep_get(ptep))) {
> +		*start = ALIGN_DOWN(*start, CONT_PTE_SIZE);
> +		ptep = contpte_align_down(ptep);
> +	}
> +
> +	return ptep;
> +}
> +
>  static void contpte_try_unfold_partial(struct mm_struct *mm, unsigned long addr,
>  					pte_t *ptep, unsigned int nr)
>  {
> @@ -569,14 +589,7 @@ void contpte_clear_young_dirty_ptes(struct vm_area_struct *vma,
>  	unsigned long start = addr;
>  	unsigned long end = start + nr * PAGE_SIZE;
>  
> -	if (pte_cont(__ptep_get(ptep + nr - 1)))
> -		end = ALIGN(end, CONT_PTE_SIZE);
> -
> -	if (pte_cont(__ptep_get(ptep))) {
> -		start = ALIGN_DOWN(start, CONT_PTE_SIZE);
> -		ptep = contpte_align_down(ptep);
> -	}
> -
> +	ptep = contpte_align_addr_ptep(&start, &end, ptep, nr);
>  	__clear_young_dirty_ptes(vma, start, ptep, (end - start) / PAGE_SIZE, flags);
>  }
>  EXPORT_SYMBOL_GPL(contpte_clear_young_dirty_ptes);



From frederic at kernel.org  Wed Dec 24 05:44:55 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:44:55 +0100
Subject: [PATCH 08/33] net: Keep ignoring isolated cpuset change
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-9-frederic@kernel.org>

RPS cpumask can be overriden through sysfs/syctl. The boot defined
isolated CPUs are then excluded from that cpumask.

However HK_TYPE_DOMAIN will soon integrate cpuset isolated
CPUs updates and the RPS infrastructure needs more thoughts to be able
to propagate such changes and synchronize against them.

Keep handling only what was passed through "isolcpus=" for now.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 net/core/net-sysfs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index ca878525ad7c..07624b682b08 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -1022,7 +1022,7 @@ static int netdev_rx_queue_set_rps_mask(struct netdev_rx_queue *queue,
 int rps_cpumask_housekeeping(struct cpumask *mask)
 {
 	if (!cpumask_empty(mask)) {
-		cpumask_and(mask, mask, housekeeping_cpumask(HK_TYPE_DOMAIN));
+		cpumask_and(mask, mask, housekeeping_cpumask(HK_TYPE_DOMAIN_BOOT));
 		cpumask_and(mask, mask, housekeeping_cpumask(HK_TYPE_WQ));
 		if (cpumask_empty(mask))
 			return -EINVAL;
-- 
2.51.1



From joaopeixoto at osyx.tech  Wed Dec 24 05:52:12 2025
From: joaopeixoto at osyx.tech (joaopeixoto at osyx.tech)
Date: Wed, 24 Dec 2025 13:52:12 +0000
Subject: [PATCH 0/5] virt: Add Bao hypervisor IPC and I/O dispatcher drivers
Message-ID: <20251224135217.25350-1-joaopeixoto@osyx.tech>

From: Jo?o Peixoto <joaopeixoto at osyx.tech>

This series introduces support for the Bao hypervisor guest-side drivers
under drivers/virt/bao and the associated Device Tree bindings, UAPI,
and MAINTAINERS entries.

Bao is a lightweight static-partitioning hypervisor for embedded and
safety-critical systems. This series adds:
- The Bao IPC shared memory driver, which enables Linux guests to
  communicate with each other through shared memory regions.
- The Bao I/O Dispatcher driver, which allows Bao's VMs to share I/O
  devices using device paravirtualization (VirtIO).

Patch overview:

1. dt-bindings: Add Bao IPC shared memory driver binding
   - Provides a standardized DT description for Bao IPC shared memory
     devices used for inter-VM communication.

2. virt: add Bao IPC shared memory driver
   - Character device driver that maps shared-memory regions and
     communicates with the hypervisor via architecture-specific hypercalls
     (SMC/HVC on ARM, SBI ecall on RISC-V).

3. dt-bindings: Add Bao I/O dispatcher driver binding
   - DT binding for the Bao I/O Dispatcher, describing memory regions,
     interrupts, and compatible strings for backend VMs.

4. virt: add Bao I/O dispatcher driver
   - Implements the I/O Dispatcher kernel module bridging Bao Remote I/O
     with VirtIO backend devices.
   - Includes architecture-specific headers for ARM, ARM64, and RISC-V,
     driver framework files, UAPI headers, Kconfig/Makefile integration,
     and ioctl documentation.

5. MAINTAINERS: Add entries for Bao hypervisor drivers
   - Registers maintainers for all Bao hypervisor components to ensure
     proper kernel review and notifications.

This series has been validated on Linux guests running under Bao hypervisor,
ensuring correct initialization, read/write operations for IPC shared
memory, and proper I/O Dispatcher functionality for backend VMs.

Feedback and review from maintainers of virtualization, architecture-specific
code (ARM, ARM64, RISC-V), Device Tree bindings, and UAPI are welcome.

Jo?o Peixoto (5):
  dt-bindings: Add Bao IPC shared memory driver binding
  virt: add Bao IPC shared memory driver
  dt-bindings: Add Bao I/O dispatcher driver binding
  virt: add Bao I/O dispatcher driver
  MAINTAINERS: Add entries for Bao hypervisor drivers, headers, and DT
    bindings

 .../bindings/bao/io-dispatcher.yaml           |  67 +++
 .../devicetree/bindings/bao/ipcshmem.yaml     |  99 ++++
 .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
 .../userspace-api/ioctl/ioctl-number.rst      |   2 +
 MAINTAINERS                                   |  12 +
 arch/arm/include/asm/bao.h                    |  62 ++
 arch/arm64/include/asm/bao.h                  |  62 ++
 arch/riscv/include/asm/bao.h                  |  61 ++
 drivers/virt/Kconfig                          |   2 +
 drivers/virt/Makefile                         |   2 +
 drivers/virt/bao/Kconfig                      |   5 +
 drivers/virt/bao/Makefile                     |   4 +
 drivers/virt/bao/io-dispatcher/Kconfig        |  16 +
 drivers/virt/bao/io-dispatcher/Makefile       |   4 +
 drivers/virt/bao/io-dispatcher/bao_drv.h      | 386 +++++++++++++
 drivers/virt/bao/io-dispatcher/dm.c           | 330 +++++++++++
 drivers/virt/bao/io-dispatcher/driver.c       | 348 +++++++++++
 drivers/virt/bao/io-dispatcher/hypercall.h    |  30 +
 drivers/virt/bao/io-dispatcher/intc.c         |  68 +++
 drivers/virt/bao/io-dispatcher/io_client.c    | 435 ++++++++++++++
 .../virt/bao/io-dispatcher/io_dispatcher.c    | 207 +++++++
 drivers/virt/bao/io-dispatcher/ioctls.c       | 145 +++++
 drivers/virt/bao/io-dispatcher/ioeventfd.c    | 336 +++++++++++
 drivers/virt/bao/io-dispatcher/irqfd.c        | 341 +++++++++++
 drivers/virt/bao/ipcshmem/Kconfig             |   9 +
 drivers/virt/bao/ipcshmem/Makefile            |   3 +
 drivers/virt/bao/ipcshmem/ipcshmem.c          | 539 ++++++++++++++++++
 include/uapi/linux/bao.h                      | 124 ++++
 28 files changed, 3701 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/bao/io-dispatcher.yaml
 create mode 100644 Documentation/devicetree/bindings/bao/ipcshmem.yaml
 create mode 100644 arch/arm/include/asm/bao.h
 create mode 100644 arch/arm64/include/asm/bao.h
 create mode 100644 arch/riscv/include/asm/bao.h
 create mode 100644 drivers/virt/bao/Kconfig
 create mode 100644 drivers/virt/bao/Makefile
 create mode 100644 drivers/virt/bao/io-dispatcher/Kconfig
 create mode 100644 drivers/virt/bao/io-dispatcher/Makefile
 create mode 100644 drivers/virt/bao/io-dispatcher/bao_drv.h
 create mode 100644 drivers/virt/bao/io-dispatcher/dm.c
 create mode 100644 drivers/virt/bao/io-dispatcher/driver.c
 create mode 100644 drivers/virt/bao/io-dispatcher/hypercall.h
 create mode 100644 drivers/virt/bao/io-dispatcher/intc.c
 create mode 100644 drivers/virt/bao/io-dispatcher/io_client.c
 create mode 100644 drivers/virt/bao/io-dispatcher/io_dispatcher.c
 create mode 100644 drivers/virt/bao/io-dispatcher/ioctls.c
 create mode 100644 drivers/virt/bao/io-dispatcher/ioeventfd.c
 create mode 100644 drivers/virt/bao/io-dispatcher/irqfd.c
 create mode 100644 drivers/virt/bao/ipcshmem/Kconfig
 create mode 100644 drivers/virt/bao/ipcshmem/Makefile
 create mode 100644 drivers/virt/bao/ipcshmem/ipcshmem.c
 create mode 100644 include/uapi/linux/bao.h

-- 
2.43.0



From joaopeixoto at osyx.tech  Wed Dec 24 05:52:17 2025
From: joaopeixoto at osyx.tech (joaopeixoto at osyx.tech)
Date: Wed, 24 Dec 2025 13:52:17 +0000
Subject: [PATCH 5/5] MAINTAINERS: Add entries for Bao hypervisor drivers, headers, and DT bindings
In-Reply-To: <20251224135217.25350-1-joaopeixoto@osyx.tech>
References: <20251224135217.25350-1-joaopeixoto@osyx.tech>
Message-ID: <20251224135217.25350-6-joaopeixoto@osyx.tech>

From: Jo?o Peixoto <joaopeixoto at osyx.tech>

Add MAINTAINERS entries for the Bao hypervisor components including:
- Bao IPC shared memory driver and its device tree bindings
- Bao I/O dispatcher driver and its device tree bindings
- Kernel headers for Bao (ARM, ARM64, and RISC-V)
- UAPI header

This ensures that the kernel review and notification system correctly
identifies the maintainers for all Bao hypervisor components in the
kernel tree.

Signed-off-by: Jo?o Peixoto <joaopeixoto at osyx.tech>
---
 MAINTAINERS | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index dc731d37c8fe..e50ad6a1bc4a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4321,6 +4321,18 @@ F:	drivers/video/backlight/
 F:	include/linux/backlight.h
 F:	include/linux/pwm_backlight.h
 
+BAO HYPERVISOR
+M:	Jos? Martins <jose at osyx.tech>
+M:	David Cerdeira <davidmcerdeira at osyx.tech>
+M:	Jo?o Peixoto <joaopeixoto at osyx.tech>
+S:	Maintained
+F:	Documentation/devicetree/bindings/bao/
+F:	arch/arm/include/asm/bao.h
+F:	arch/arm64/include/asm/bao.h
+F:	arch/riscv/include/asm/bao.h
+F:	drivers/virt/bao
+F:	include/uapi/linux/bao.h
+
 BARCO P50 GPIO DRIVER
 M:	Santosh Kumar Yadav <santoshkumar.yadav at barco.com>
 M:	Peter Korsgaard <peter.korsgaard at barco.com>
-- 
2.43.0



From frederic at kernel.org  Wed Dec 24 05:45:03 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:45:03 +0100
Subject: [PATCH 16/33] sched/isolation: Flush vmstat workqueues on cpuset isolated partition change
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-17-frederic@kernel.org>

The HK_TYPE_DOMAIN housekeeping cpumask is now modifiable at runtime.
In order to synchronize against vmstat workqueue to make sure
that no asynchronous vmstat work is still pending or executing on a
newly made isolated CPU, the housekeeping susbsystem must flush the
vmstat workqueues.

This involves flushing the whole mm_percpu_wq workqueue, shared with
LRU drain, introducing here a welcome side effect.

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 include/linux/vmstat.h   | 2 ++
 kernel/sched/isolation.c | 1 +
 kernel/sched/sched.h     | 1 +
 mm/vmstat.c              | 5 +++++
 4 files changed, 9 insertions(+)

diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h
index 3398a345bda8..1909b945b3ea 100644
--- a/include/linux/vmstat.h
+++ b/include/linux/vmstat.h
@@ -303,6 +303,7 @@ int calculate_pressure_threshold(struct zone *zone);
 int calculate_normal_threshold(struct zone *zone);
 void set_pgdat_percpu_threshold(pg_data_t *pgdat,
 				int (*calculate_pressure)(struct zone *));
+void vmstat_flush_workqueue(void);
 #else /* CONFIG_SMP */
 
 /*
@@ -403,6 +404,7 @@ static inline void __dec_node_page_state(struct page *page,
 static inline void refresh_zone_stat_thresholds(void) { }
 static inline void cpu_vm_stats_fold(int cpu) { }
 static inline void quiet_vmstat(void) { }
+static inline void vmstat_flush_workqueue(void) { }
 
 static inline void drain_zonestat(struct zone *zone,
 			struct per_cpu_zonestat *pzstats) { }
diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c
index bb6c36d2b97b..8aac3c9f7c7f 100644
--- a/kernel/sched/isolation.c
+++ b/kernel/sched/isolation.c
@@ -146,6 +146,7 @@ int housekeeping_update(struct cpumask *isol_mask, enum hk_type type)
 	synchronize_rcu();
 
 	mem_cgroup_flush_workqueue();
+	vmstat_flush_workqueue();
 
 	kfree(old);
 
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 65dfa48e54b7..2d0c408fca0b 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -68,6 +68,7 @@
 #include <linux/types.h>
 #include <linux/u64_stats_sync_api.h>
 #include <linux/uaccess.h>
+#include <linux/vmstat.h>
 #include <linux/wait_api.h>
 #include <linux/wait_bit.h>
 #include <linux/workqueue_api.h>
diff --git a/mm/vmstat.c b/mm/vmstat.c
index ed19c0d42de6..d6e814c82952 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -2124,6 +2124,11 @@ static void vmstat_shepherd(struct work_struct *w);
 
 static DECLARE_DEFERRABLE_WORK(shepherd, vmstat_shepherd);
 
+void vmstat_flush_workqueue(void)
+{
+	flush_workqueue(mm_percpu_wq);
+}
+
 static void vmstat_shepherd(struct work_struct *w)
 {
 	int cpu;
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:45:18 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:45:18 +0100
Subject: [PATCH 31/33] kthread: Comment on the purpose and placement of kthread_affine_node() call
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-32-frederic@kernel.org>

It may not appear obvious why kthread_affine_node() is not called before
the kthread creation completion instead of after the first wake-up.

The reason is that kthread_affine_node() applies a default affinity
behaviour that only takes place if no affinity preference have already
been passed by the kthread creation call site.

Add a comment to clarify that.

Reported-by: Peter Zijlstra <peterz at infradead.org>
Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 kernel/kthread.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/kernel/kthread.c b/kernel/kthread.c
index 03008154249c..51f419139dea 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -453,6 +453,10 @@ static int kthread(void *_create)
 
 	self->started = 1;
 
+	/*
+	 * Apply default node affinity if no call to kthread_bind[_mask]() nor
+	 * kthread_affine_preferred() was issued before the first wake-up.
+	 */
 	if (!(current->flags & PF_NO_SETAFFINITY) && !self->preferred_affinity)
 		kthread_affine_node();
 
-- 
2.51.1



From frederic at kernel.org  Wed Dec 24 05:45:20 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 24 Dec 2025 14:45:20 +0100
Subject: [PATCH 33/33] doc: Add housekeeping documentation
In-Reply-To: <20251224134520.33231-1-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
Message-ID: <20251224134520.33231-34-frederic@kernel.org>

Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
---
 Documentation/core-api/housekeeping.rst | 111 ++++++++++++++++++++++++
 Documentation/core-api/index.rst        |   1 +
 2 files changed, 112 insertions(+)
 create mode 100644 Documentation/core-api/housekeeping.rst

diff --git a/Documentation/core-api/housekeeping.rst b/Documentation/core-api/housekeeping.rst
new file mode 100644
index 000000000000..e5417302774c
--- /dev/null
+++ b/Documentation/core-api/housekeeping.rst
@@ -0,0 +1,111 @@
+======================================
+Housekeeping
+======================================
+
+
+CPU Isolation moves away kernel work that may otherwise run on any CPU.
+The purpose of its related features is to reduce the OS jitter that some
+extreme workloads can't stand, such as in some DPDK usecases.
+
+The kernel work moved away by CPU isolation is commonly described as
+"housekeeping" because it includes ground work that performs cleanups,
+statistics maintainance and actions relying on them, memory release,
+various deferrals etc...
+
+Sometimes housekeeping is just some unbound work (unbound workqueues,
+unbound timers, ...) that gets easily assigned to non-isolated CPUs.
+But sometimes housekeeping is tied to a specific CPU and requires
+elaborated tricks to be offloaded to non-isolated CPUs (RCU_NOCB, remote
+scheduler tick, etc...).
+
+Thus, a housekeeping CPU can be considered as the reverse of an isolated
+CPU. It is simply a CPU that can execute housekeeping work. There must
+always be at least one online housekeeping CPU at any time. The CPUs that
+are not	isolated are automatically assigned as housekeeping.
+
+Housekeeping is currently divided in four features described
+by the ``enum hk_type type``:
+
+1.	HK_TYPE_DOMAIN matches the work moved away by scheduler domain
+	isolation performed through ``isolcpus=domain`` boot parameter or
+	isolated cpuset partitions in cgroup v2. This includes scheduler
+	load balancing, unbound workqueues and timers.
+
+2.	HK_TYPE_KERNEL_NOISE matches the work moved away by tick isolation
+	performed through ``nohz_full=`` or ``isolcpus=nohz`` boot
+	parameters. This includes remote scheduler tick, vmstat and lockup
+	watchdog.
+
+3.	HK_TYPE_MANAGED_IRQ matches the IRQ handlers moved away by managed
+	IRQ isolation performed through ``isolcpus=managed_irq``.
+
+4.	HK_TYPE_DOMAIN_BOOT matches the work moved away by scheduler domain
+	isolation performed through ``isolcpus=domain`` only. It is similar
+	to HK_TYPE_DOMAIN except it ignores the isolation performed by
+	cpusets.
+
+
+Housekeeping cpumasks
+=================================
+
+Housekeeping cpumasks include the CPUs that can execute the work moved
+away by the matching isolation feature. These cpumasks are returned by
+the following function::
+
+	const struct cpumask *housekeeping_cpumask(enum hk_type type)
+
+By default, if neither ``nohz_full=``, nor ``isolcpus``, nor cpuset's
+isolated partitions are used, which covers most usecases, this function
+returns the cpu_possible_mask.
+
+Otherwise the function returns the cpumask complement of the isolation
+feature. For example:
+
+With isolcpus=domain,7 the following will return a mask with all possible
+CPUs except 7::
+
+	housekeeping_cpumask(HK_TYPE_DOMAIN)
+
+Similarly with nohz_full=5,6 the following will return a mask with all
+possible CPUs except 5,6::
+
+	housekeeping_cpumask(HK_TYPE_KERNEL_NOISE)
+
+
+Synchronization against cpusets
+=================================
+
+Cpuset can modify the HK_TYPE_DOMAIN housekeeping cpumask while creating,
+modifying or deleting an isolated partition.
+
+The users of HK_TYPE_DOMAIN cpumask must then make sure to synchronize
+properly against cpuset in order to make sure that:
+
+1.	The cpumask snapshot stays coherent.
+
+2.	No housekeeping work is queued on a newly made isolated CPU.
+
+3.	Pending housekeeping work that was queued to a non isolated
+	CPU which just turned isolated through cpuset must be flushed
+	before the related created/modified isolated partition is made
+	available to userspace.
+
+This synchronization is maintained by an RCU based scheme. The cpuset update
+side waits for an RCU grace period after updating the HK_TYPE_DOMAIN
+cpumask and before flushing pending works. On the read side, care must be
+taken to gather the housekeeping target election and the work enqueue within
+the same RCU read side critical section.
+
+A typical layout example would look like this on the update side
+(``housekeeping_update()``)::
+
+	rcu_assign_pointer(housekeeping_cpumasks[type], trial);
+	synchronize_rcu();
+	flush_workqueue(example_workqueue);
+
+And then on the read side::
+
+	rcu_read_lock();
+	cpu = housekeeping_any_cpu(HK_TYPE_DOMAIN);
+	queue_work_on(cpu, example_workqueue, work);
+	rcu_read_unlock();
diff --git a/Documentation/core-api/index.rst b/Documentation/core-api/index.rst
index 5eb0fbbbc323..79fe7735692e 100644
--- a/Documentation/core-api/index.rst
+++ b/Documentation/core-api/index.rst
@@ -25,6 +25,7 @@ it.
    symbol-namespaces
    asm-annotations
    real-time/index
+   housekeeping.rst
 
 Data structures and low-level utilities
 =======================================
-- 
2.51.1



From robert.marko at sartura.hr  Wed Dec 24 06:01:13 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Wed, 24 Dec 2025 15:01:13 +0100
Subject: [PATCH v3 01/15] include: dt-bindings: add LAN969x clock bindings
In-Reply-To: <78bf252c-fd5e-4a36-b1a3-ca8ed26fde7a@kernel.org>
References: <20251223201921.1332786-1-robert.marko@sartura.hr>
 <20251223201921.1332786-2-robert.marko@sartura.hr> <20251224-berserk-mackerel-of-snow-4cae54@quoll>
 <CA+HBbNGym6Q9b166n-P=h_JssOHm0yfyL73JZ+G9P81muK=g4A@mail.gmail.com> <78bf252c-fd5e-4a36-b1a3-ca8ed26fde7a@kernel.org>
Message-ID: <CA+HBbNG+ZVD6grGDp32Ninx7H1AyEbGvP0nwc0zUv94tOV8hYg@mail.gmail.com>

On Wed, Dec 24, 2025 at 2:05?PM Krzysztof Kozlowski <krzk at kernel.org> wrote:
>
> On 24/12/2025 11:30, Robert Marko wrote:
> > On Wed, Dec 24, 2025 at 11:21?AM Krzysztof Kozlowski <krzk at kernel.org> wrote:
> >>
> >> On Tue, Dec 23, 2025 at 09:16:12PM +0100, Robert Marko wrote:
> >>> Add the required LAN969x clock bindings.
> >>
> >> I do not see clock bindings actually here. Where is the actual binding?
> >> Commit msg does not help me at all to understand why you are doing this
> >> without actual required bindings.
> >
> > I guess it is a bit confusing, there is no schema here, these are the
> > clock indexes that
> > reside in dt-bindings and are used by the SoC DTSI.
>
> I understand as not used by drivers? Then no ABI and there is no point
> in putting them into bindings.

It is not included by the driver directly, but it requires these exact
indexes to be passed
so its effectively ABI.
LAN966x does the same, but they differ in number of clocks and their indexes.

Regards,
Robert

>
> Best regards,
> Krzysztof



-- 
Robert Marko
Staff Embedded Linux Engineer
Sartura d.d.
Lendavska ulica 16a
10000 Zagreb, Croatia
Email: robert.marko at sartura.hr
Web: www.sartura.hr


From ryan.roberts at arm.com  Wed Dec 24 06:07:34 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Wed, 24 Dec 2025 14:07:34 +0000
Subject: [PATCH v4 3/5] arm64: mm: support batch clearing of the young
 flag for large folios
In-Reply-To: <3b427d9010a6d52f2b91342760f12be097d21cf6.1766455378.git.baolin.wang@linux.alibaba.com>
References: <cover.1766455377.git.baolin.wang@linux.alibaba.com>
 <3b427d9010a6d52f2b91342760f12be097d21cf6.1766455378.git.baolin.wang@linux.alibaba.com>
Message-ID: <c5df1f9f-952a-4e83-9ae0-bd0a83dedd36@arm.com>

On 23/12/2025 05:48, Baolin Wang wrote:
> Currently, contpte_ptep_test_and_clear_young() and contpte_ptep_clear_flush_young()
> only clear the young flag and flush TLBs for PTEs within the contiguous range.
> To support batch PTE operations for other sized large folios in the following
> patches, adding a new parameter to specify the number of PTEs that map consecutive
> pages of the same large folio in a single VMA and a single page table.
> 
> While we are at it, rename the functions to maintain consistency with other
> contpte_*() functions.
> 
> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
> ---
>  arch/arm64/include/asm/pgtable.h | 12 ++++++------
>  arch/arm64/mm/contpte.c          | 33 ++++++++++++++++++--------------
>  2 files changed, 25 insertions(+), 20 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
> index 445e18e92221..d5fbe72e820a 100644
> --- a/arch/arm64/include/asm/pgtable.h
> +++ b/arch/arm64/include/asm/pgtable.h
> @@ -1648,10 +1648,10 @@ extern void contpte_clear_full_ptes(struct mm_struct *mm, unsigned long addr,
>  extern pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
>  				unsigned long addr, pte_t *ptep,
>  				unsigned int nr, int full);
> -extern int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
> -				unsigned long addr, pte_t *ptep);
> -extern int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
> -				unsigned long addr, pte_t *ptep);
> +int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
> +				unsigned long addr, pte_t *ptep, unsigned int nr);
> +int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
> +				unsigned long addr, pte_t *ptep, unsigned int nr);
>  extern void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
>  				pte_t *ptep, unsigned int nr);
>  extern int contpte_ptep_set_access_flags(struct vm_area_struct *vma,
> @@ -1823,7 +1823,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
>  	if (likely(!pte_valid_cont(orig_pte)))
>  		return __ptep_test_and_clear_young(vma, addr, ptep);
>  
> -	return contpte_ptep_test_and_clear_young(vma, addr, ptep);
> +	return contpte_test_and_clear_young_ptes(vma, addr, ptep, CONT_PTES);

As per your fixup patch, I agree that nr should be 1 here, not CONT_PTES.

>  }
>  
>  #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
> @@ -1835,7 +1835,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
>  	if (likely(!pte_valid_cont(orig_pte)))
>  		return __ptep_clear_flush_young(vma, addr, ptep);
>  
> -	return contpte_ptep_clear_flush_young(vma, addr, ptep);
> +	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);

And same here.

>  }
>  
>  #define wrprotect_ptes wrprotect_ptes
> diff --git a/arch/arm64/mm/contpte.c b/arch/arm64/mm/contpte.c
> index e4ddeb46f25d..b929a455103f 100644
> --- a/arch/arm64/mm/contpte.c
> +++ b/arch/arm64/mm/contpte.c
> @@ -508,8 +508,9 @@ pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
>  }
>  EXPORT_SYMBOL_GPL(contpte_get_and_clear_full_ptes);
>  
> -int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
> -					unsigned long addr, pte_t *ptep)
> +int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
> +					unsigned long addr, pte_t *ptep,
> +					unsigned int nr)
>  {
>  	/*
>  	 * ptep_clear_flush_young() technically requires us to clear the access
> @@ -518,41 +519,45 @@ int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
>  	 * contig range when the range is covered by a single folio, we can get
>  	 * away with clearing young for the whole contig range here, so we avoid
>  	 * having to unfold.
> +	 *
> +	 * The 'nr' means consecutive (present) PTEs that map consecutive pages
> +	 * of the same large folio in a single VMA and a single page table.
>  	 */
>  
> +	unsigned long end = addr + nr * PAGE_SIZE;
>  	int young = 0;
> -	int i;
>  
> -	ptep = contpte_align_down(ptep);
> -	addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
> -
> -	for (i = 0; i < CONT_PTES; i++, ptep++, addr += PAGE_SIZE)
> +	ptep = contpte_align_addr_ptep(&addr, &end, ptep, nr);
> +	for (; addr != end; ptep++, addr += PAGE_SIZE)
>  		young |= __ptep_test_and_clear_young(vma, addr, ptep);
>  
>  	return young;
>  }
> -EXPORT_SYMBOL_GPL(contpte_ptep_test_and_clear_young);
> +EXPORT_SYMBOL_GPL(contpte_test_and_clear_young_ptes);
>  
> -int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
> -					unsigned long addr, pte_t *ptep)
> +int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
> +				unsigned long addr, pte_t *ptep,
> +				unsigned int nr)
>  {
>  	int young;
>  
> -	young = contpte_ptep_test_and_clear_young(vma, addr, ptep);
> +	young = contpte_test_and_clear_young_ptes(vma, addr, ptep, nr);
>  
>  	if (young) {
> +		unsigned long end = addr + nr * PAGE_SIZE;
> +
> +		contpte_align_addr_ptep(&addr, &end, ptep, nr);
>  		/*
>  		 * See comment in __ptep_clear_flush_young(); same rationale for
>  		 * eliding the trailing DSB applies here.
>  		 */
> -		addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
> -		__flush_tlb_range_nosync(vma->vm_mm, addr, addr + CONT_PTE_SIZE,
> +		__flush_tlb_range_nosync(vma->vm_mm, addr, end,
>  					 PAGE_SIZE, true, 3);

Hmm... The requirement is that we must flush the _page_ if clearing access for a
pte that does not have the contiguous bit set, or we must flush the _contpte
block_ if clearing access for a pte that does have the contiguous bit set.

With your changes, you may call for a large range that covers multiple contpte
blocks but only has a single pte in a single contpte block for which the access
bit was previously set. But that will cause flushing the TLB for the full range.
Could this cause a performance issue? Yes, no, maybe... I think it's unlikely
but I wouldn't rule it out in some edge case.

I wonder if it's better to track the sub-ranges where access was cleared and
only issue tlbi for those sub-ranges? Probably just keep it simple (the way you
have done it) until/unless we see an actual problem?

Thanks,
Ryan

>  	}
>  
>  	return young;
>  }
> -EXPORT_SYMBOL_GPL(contpte_ptep_clear_flush_young);
> +EXPORT_SYMBOL_GPL(contpte_clear_flush_young_ptes);
>  
>  void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
>  					pte_t *ptep, unsigned int nr)



From ryan.roberts at arm.com  Wed Dec 24 06:09:51 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Wed, 24 Dec 2025 14:09:51 +0000
Subject: [PATCH v4 4/5] arm64: mm: implement the architecture-specific
 clear_flush_young_ptes()
In-Reply-To: <e1e57d89fed939e3f7ff877e4f406d807a7eebd4.1766455378.git.baolin.wang@linux.alibaba.com>
References: <cover.1766455377.git.baolin.wang@linux.alibaba.com>
 <e1e57d89fed939e3f7ff877e4f406d807a7eebd4.1766455378.git.baolin.wang@linux.alibaba.com>
Message-ID: <ca465273-13ec-4397-a4f0-a38ad0dab2dc@arm.com>

On 23/12/2025 05:48, Baolin Wang wrote:
> Implement the Arm64 architecture-specific clear_flush_young_ptes() to enable
> batched checking of young flags and TLB flushing, improving performance during
> large folio reclamation.
> 
> Performance testing:
> Allocate 10G clean file-backed folios by mmap() in a memory cgroup, and try to
> reclaim 8G file-backed folios via the memory.reclaim interface. I can observe
> 33% performance improvement on my Arm64 32-core server (and 10%+ improvement
> on my X86 machine). Meanwhile, the hotspot folio_check_references() dropped
> from approximately 35% to around 5%.
> 
> W/o patchset:
> real	0m1.518s
> user	0m0.000s
> sys	0m1.518s
> 
> W/ patchset:
> real	0m1.018s
> user	0m0.000s
> sys	0m1.018s
> 
> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>

Reviewed-by: Ryan Roberts <ryan.roberts at arm.com>

> ---
>  arch/arm64/include/asm/pgtable.h | 11 +++++++++++
>  1 file changed, 11 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
> index d5fbe72e820a..84a6bdabb1f9 100644
> --- a/arch/arm64/include/asm/pgtable.h
> +++ b/arch/arm64/include/asm/pgtable.h
> @@ -1838,6 +1838,17 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
>  	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
>  }
>  
> +#define clear_flush_young_ptes clear_flush_young_ptes
> +static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
> +					unsigned long addr, pte_t *ptep,
> +					unsigned int nr)
> +{
> +	if (likely(nr == 1 && !pte_cont(__ptep_get(ptep))))
> +		return __ptep_clear_flush_young(vma, addr, ptep);
> +
> +	return contpte_clear_flush_young_ptes(vma, addr, ptep, nr);
> +}
> +
>  #define wrprotect_ptes wrprotect_ptes
>  static __always_inline void wrprotect_ptes(struct mm_struct *mm,
>  				unsigned long addr, pte_t *ptep, unsigned int nr)



From ryan.roberts at arm.com  Wed Dec 24 06:11:24 2025
From: ryan.roberts at arm.com (Ryan Roberts)
Date: Wed, 24 Dec 2025 14:11:24 +0000
Subject: [PATCH v4 5/5] mm: rmap: support batched unmapping for file large
 folios
In-Reply-To: <d869ae45a7be322f342ace62ffcdd4b47f4154fc.1766455378.git.baolin.wang@linux.alibaba.com>
References: <cover.1766455377.git.baolin.wang@linux.alibaba.com>
 <d869ae45a7be322f342ace62ffcdd4b47f4154fc.1766455378.git.baolin.wang@linux.alibaba.com>
Message-ID: <20821c02-e16b-4e5f-95b0-b3e8b9192117@arm.com>

On 23/12/2025 05:48, Baolin Wang wrote:
> Similar to folio_referenced_one(), we can apply batched unmapping for file
> large folios to optimize the performance of file folios reclamation.
> 
> Barry previously implemented batched unmapping for lazyfree anonymous large
> folios[1] and did not further optimize anonymous large folios or file-backed
> large folios at that stage. As for file-backed large folios, the batched
> unmapping support is relatively straightforward, as we only need to clear
> the consecutive (present) PTE entries for file-backed large folios.
> 
> Performance testing:
> Allocate 10G clean file-backed folios by mmap() in a memory cgroup, and try to
> reclaim 8G file-backed folios via the memory.reclaim interface. I can observe
> 75% performance improvement on my Arm64 32-core server (and 50%+ improvement
> on my X86 machine) with this patch.
> 
> W/o patch:
> real    0m1.018s
> user    0m0.000s
> sys     0m1.018s
> 
> W/ patch:
> real	0m0.249s
> user	0m0.000s
> sys	0m0.249s
> 
> [1] https://lore.kernel.org/all/20250214093015.51024-4-21cnbao at gmail.com/T/#u
> Acked-by: Barry Song <baohua at kernel.org>
> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>

Reviewed-by: Ryan Roberts <ryan.roberts at arm.com>

> ---
>  mm/rmap.c | 7 ++++---
>  1 file changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/mm/rmap.c b/mm/rmap.c
> index a0fc05f5966f..7482121d4e92 100644
> --- a/mm/rmap.c
> +++ b/mm/rmap.c
> @@ -1862,9 +1862,10 @@ static inline unsigned int folio_unmap_pte_batch(struct folio *folio,
>  	end_addr = pmd_addr_end(addr, vma->vm_end);
>  	max_nr = (end_addr - addr) >> PAGE_SHIFT;
>  
> -	/* We only support lazyfree batching for now ... */
> -	if (!folio_test_anon(folio) || folio_test_swapbacked(folio))
> +	/* We only support lazyfree or file folios batching for now ... */
> +	if (folio_test_anon(folio) && folio_test_swapbacked(folio))
>  		return 1;
> +
>  	if (pte_unused(pte))
>  		return 1;
>  
> @@ -2230,7 +2231,7 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
>  			 *
>  			 * See Documentation/mm/mmu_notifier.rst
>  			 */
> -			dec_mm_counter(mm, mm_counter_file(folio));
> +			add_mm_counter(mm, mm_counter_file(folio), -nr_pages);
>  		}
>  discard:
>  		if (unlikely(folio_test_hugetlb(folio))) {



From nicolas at ndufresne.ca  Wed Dec 24 06:24:20 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 24 Dec 2025 09:24:20 -0500
Subject: [PATCH v2 02/22] media: v4l2-common: add has_alpha to
 v4l2_format_info
In-Reply-To: <20251203-spu-rga3-v2-2-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
	 <20251203-spu-rga3-v2-2-989a67947f71@pengutronix.de>
Message-ID: <fffbec0dbb95fe0aa34e847c89499e91ebc1df43.camel@ndufresne.ca>

Le mercredi 03 d?cembre 2025 ? 16:52 +0100, Sven P?schel a ?crit?:
> Add a has_alpha value to the v4l2_format_info struct to indicate if the
> format contains an alpha component. The implementation is based on the
> drm_format_info implementation.
> 
> Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?drivers/media/v4l2-core/v4l2-common.c | 14 +++++++-------
> ?include/media/v4l2-common.h?????????? |? 2 ++
> ?2 files changed, 9 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
> index 554c591e11133..2c7ac70c0f486 100644
> --- a/drivers/media/v4l2-core/v4l2-common.c
> +++ b/drivers/media/v4l2-core/v4l2-common.c
> @@ -256,10 +256,10 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
> ?		{ .format = V4L2_PIX_FMT_XRGB32,? .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> ?		{ .format = V4L2_PIX_FMT_RGBX32,? .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> ?		{ .format = V4L2_PIX_FMT_HSV32,?? .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> -		{ .format = V4L2_PIX_FMT_ARGB32,? .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> -		{ .format = V4L2_PIX_FMT_RGBA32,? .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> -		{ .format = V4L2_PIX_FMT_ABGR32,? .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> -		{ .format = V4L2_PIX_FMT_BGRA32,? .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> +		{ .format = V4L2_PIX_FMT_ARGB32,? .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
> +		{ .format = V4L2_PIX_FMT_RGBA32,? .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
> +		{ .format = V4L2_PIX_FMT_ABGR32,? .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
> +		{ .format = V4L2_PIX_FMT_BGRA32,? .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
> ?		{ .format = V4L2_PIX_FMT_RGB565,? .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> ?		{ .format = V4L2_PIX_FMT_RGB565X, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> ?		{ .format = V4L2_PIX_FMT_RGB555,? .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> @@ -267,10 +267,10 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
> ?		{ .format = V4L2_PIX_FMT_BGR48_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> ?		{ .format = V4L2_PIX_FMT_BGR48, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> ?		{ .format = V4L2_PIX_FMT_RGB48, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> -		{ .format = V4L2_PIX_FMT_ABGR64_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> -		{ .format = V4L2_PIX_FMT_RGBA1010102, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> +		{ .format = V4L2_PIX_FMT_ABGR64_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
> +		{ .format = V4L2_PIX_FMT_RGBA1010102, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
> ?		{ .format = V4L2_PIX_FMT_RGBX1010102, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> -		{ .format = V4L2_PIX_FMT_ARGB2101010, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> +		{ .format = V4L2_PIX_FMT_ARGB2101010, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
> ?
> ?		/* YUV packed formats */
> ?		{ .format = V4L2_PIX_FMT_YUYV,??? .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 },
> diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
> index f8b1faced79c8..401d8506c24b5 100644
> --- a/include/media/v4l2-common.h
> +++ b/include/media/v4l2-common.h
> @@ -520,6 +520,7 @@ enum v4l2_pixel_encoding {
> ? * @vdiv: Vertical chroma subsampling factor
> ? * @block_w: Per-plane macroblock pixel width (optional)
> ? * @block_h: Per-plane macroblock pixel height (optional)
> + * @has_alpha: Does the format embeds an alpha component?
> ? */
> ?struct v4l2_format_info {
> ?	u32 format;
> @@ -532,6 +533,7 @@ struct v4l2_format_info {
> ?	u8 vdiv;
> ?	u8 block_w[4];
> ?	u8 block_h[4];
> +	bool has_alpha;
> ?};
> ?
> ?static inline bool v4l2_is_format_rgb(const struct v4l2_format_info *f)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/6e7be012/attachment.sig>

From nicolas at ndufresne.ca  Wed Dec 24 06:47:39 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 24 Dec 2025 09:47:39 -0500
Subject: [PATCH v2 03/22] media: v4l2-common: add
 v4l2_fill_pixfmt_mp_aligned helper
In-Reply-To: <20251203-spu-rga3-v2-3-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
	 <20251203-spu-rga3-v2-3-989a67947f71@pengutronix.de>
Message-ID: <43c953bd75ad65f249cf71115bb87179b6ba3f47.camel@ndufresne.ca>

Hi,

Le mercredi 03 d?cembre 2025 ? 16:52 +0100, Sven P?schel a ?crit?:
> Add a v4l2_fill_pixfmt_mp_aligned helper which allows the user to
> specify a custom stride alignment in bytes. This is necessary for
> hardware like the Rockchip RGA3, which requires the stride value to be
> aligned to a 16 byte boundary.

                  byte -> bytes

You way aligned to bytes here ...


> 
> Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
> ---
> ?drivers/media/v4l2-core/v4l2-common.c | 34 ++++++++++++++++++++++++----------
> ?include/media/v4l2-common.h?????????? |? 4 ++++
> ?2 files changed, 28 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
> index 2c7ac70c0f486..f86e7d7d29b8e 100644
> --- a/drivers/media/v4l2-core/v4l2-common.c
> +++ b/drivers/media/v4l2-core/v4l2-common.c
> @@ -404,11 +404,12 @@ static inline unsigned int v4l2_format_block_height(const struct v4l2_format_inf
> ?}
> ?
> ?static inline unsigned int v4l2_format_plane_stride(const struct v4l2_format_info *info, int plane,
> -						??? unsigned int width)
> +						??? unsigned int width, u8 alignment)
> ?{
> ?	unsigned int hdiv = plane ? info->hdiv : 1;
> ?	unsigned int aligned_width =
> ?		ALIGN(width, v4l2_format_block_width(info, plane));
> +	aligned_width = ALIGN(aligned_width, alignment);

But you actually align the width, which can already be achieved using frmsize-
>step_width and v4l2_apply_frmsize_constraints(). It would make little sense for
the step to not be a multiple of the block for tiled format, but it shows you
forgot to take into considering the fact that block_width has precedence here,
since you can't split tiles.

If you go back to your original idea, stride alignment, remember that you cannot
break the block alignment. For non-mplane format, you also need to special case
subsampled planer format (3 planes) so that userspace can guess the subsequence
plane strides (which is done by dividing the luma plane stride by 2, and if you
need 16 bytes alignment across all strides, then you need the luma plane to be
32 bytes alignment). The mplane format don't have this requirement, since you
pass explicitly the stride of each planes, though, you may want to double it
anyway for compatibility reason (small cost, big gain).

Nicolas

> ?
> ?	return DIV_ROUND_UP(aligned_width, hdiv) *
> ?	?????? info->bpp[plane] / info->bpp_div[plane];
> @@ -425,9 +426,10 @@ static inline unsigned int v4l2_format_plane_height(const struct v4l2_format_inf
> ?}
> ?
> ?static inline unsigned int v4l2_format_plane_size(const struct v4l2_format_info *info, int plane,
> -						? unsigned int width, unsigned int height)
> +						? unsigned int width, unsigned int height,
> +						? u8 stride_alignment)
> ?{
> -	return v4l2_format_plane_stride(info, plane, width) *
> +	return v4l2_format_plane_stride(info, plane, width, stride_alignment) *
> ?	?????? v4l2_format_plane_height(info, plane, height);
> ?}
> ?
> @@ -448,8 +450,9 @@ void v4l2_apply_frmsize_constraints(u32 *width, u32 *height,
> ?}
> ?EXPORT_SYMBOL_GPL(v4l2_apply_frmsize_constraints);
> ?
> -int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
> -			u32 pixelformat, u32 width, u32 height)
> +int v4l2_fill_pixfmt_mp_aligned(struct v4l2_pix_format_mplane *pixfmt,
> +				u32 pixelformat, u32 width, u32 height,
> +				u8 stride_alignment)
> ?{
> ?	const struct v4l2_format_info *info;
> ?	struct v4l2_plane_pix_format *plane;
> @@ -466,23 +469,34 @@ int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
> ?
> ?	if (info->mem_planes == 1) {
> ?		plane = &pixfmt->plane_fmt[0];
> -		plane->bytesperline = v4l2_format_plane_stride(info, 0, width);
> +		plane->bytesperline = v4l2_format_plane_stride(info, 0, width,
> +							?????? stride_alignment);
> ?		plane->sizeimage = 0;
> ?
> ?		for (i = 0; i < info->comp_planes; i++)
> ?			plane->sizeimage +=
> -				v4l2_format_plane_size(info, i, width, height);
> +				v4l2_format_plane_size(info, i, width, height,
> +						?????? stride_alignment);
> ?	} else {
> ?		for (i = 0; i < info->comp_planes; i++) {
> ?			plane = &pixfmt->plane_fmt[i];
> ?			plane->bytesperline =
> -				v4l2_format_plane_stride(info, i, width);
> +				v4l2_format_plane_stride(info, i, width,
> +							 stride_alignment);
> ?			plane->sizeimage = plane->bytesperline *
> ?				v4l2_format_plane_height(info, i, height);
> ?		}
> ?	}
> ?	return 0;
> ?}
> +EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt_mp_aligned);
> +
> +int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
> +			u32 pixelformat, u32 width, u32 height)
> +{
> +	return v4l2_fill_pixfmt_mp_aligned(pixfmt, pixelformat,
> +					?? width, height, 1);
> +}
> ?EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt_mp);
> ?
> ?int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat,
> @@ -502,12 +516,12 @@ int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat,
> ?	pixfmt->width = width;
> ?	pixfmt->height = height;
> ?	pixfmt->pixelformat = pixelformat;
> -	pixfmt->bytesperline = v4l2_format_plane_stride(info, 0, width);
> +	pixfmt->bytesperline = v4l2_format_plane_stride(info, 0, width, 1);
> ?	pixfmt->sizeimage = 0;
> ?
> ?	for (i = 0; i < info->comp_planes; i++)
> ?		pixfmt->sizeimage +=
> -			v4l2_format_plane_size(info, i, width, height);
> +			v4l2_format_plane_size(info, i, width, height, 1);
> ?	return 0;
> ?}
> ?EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt);
> diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
> index 401d8506c24b5..edd416178c333 100644
> --- a/include/media/v4l2-common.h
> +++ b/include/media/v4l2-common.h
> @@ -558,6 +558,10 @@ int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat,
> ?		???? u32 width, u32 height);
> ?int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, u32 pixelformat,
> ?			u32 width, u32 height);
> +/* @stride_alignment is a power of 2 value in bytes */
> +int v4l2_fill_pixfmt_mp_aligned(struct v4l2_pix_format_mplane *pixfmt,
> +				u32 pixelformat, u32 width, u32 height,
> +				u8 stride_alignment);
> ?
> ?/**
> ? * v4l2_get_link_freq - Get link rate from transmitter
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/e2364dfb/attachment-0001.sig>

From nicolas at ndufresne.ca  Wed Dec 24 06:48:35 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 24 Dec 2025 09:48:35 -0500
Subject: [PATCH v2 04/22] media: rockchip: rga: use clk_bulk api
In-Reply-To: <20251203-spu-rga3-v2-4-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
	 <20251203-spu-rga3-v2-4-989a67947f71@pengutronix.de>
Message-ID: <43caf038367d00217d11237e54c82240c3caea5a.camel@ndufresne.ca>

Le mercredi 03 d?cembre 2025 ? 16:52 +0100, Sven P?schel a ?crit?:
> Use the clk_bulk API to avoid code duplication for each of the three
> clocks.
> 
> Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?drivers/media/platform/rockchip/rga/rga.c | 64 ++++---------------------------
> ?drivers/media/platform/rockchip/rga/rga.h |? 5 +--
> ?2 files changed, 9 insertions(+), 60 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
> index 43f6a8d993811..ef568b3758380 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -698,48 +698,10 @@ static const struct video_device rga_videodev = {
> ?	.device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING,
> ?};
> ?
> -static int rga_enable_clocks(struct rockchip_rga *rga)
> -{
> -	int ret;
> -
> -	ret = clk_prepare_enable(rga->sclk);
> -	if (ret) {
> -		dev_err(rga->dev, "Cannot enable rga sclk: %d\n", ret);
> -		return ret;
> -	}
> -
> -	ret = clk_prepare_enable(rga->aclk);
> -	if (ret) {
> -		dev_err(rga->dev, "Cannot enable rga aclk: %d\n", ret);
> -		goto err_disable_sclk;
> -	}
> -
> -	ret = clk_prepare_enable(rga->hclk);
> -	if (ret) {
> -		dev_err(rga->dev, "Cannot enable rga hclk: %d\n", ret);
> -		goto err_disable_aclk;
> -	}
> -
> -	return 0;
> -
> -err_disable_aclk:
> -	clk_disable_unprepare(rga->aclk);
> -err_disable_sclk:
> -	clk_disable_unprepare(rga->sclk);
> -
> -	return ret;
> -}
> -
> -static void rga_disable_clocks(struct rockchip_rga *rga)
> -{
> -	clk_disable_unprepare(rga->sclk);
> -	clk_disable_unprepare(rga->hclk);
> -	clk_disable_unprepare(rga->aclk);
> -}
> -
> ?static int rga_parse_dt(struct rockchip_rga *rga)
> ?{
> ?	struct reset_control *core_rst, *axi_rst, *ahb_rst;
> +	int ret;
> ?
> ?	core_rst = devm_reset_control_get(rga->dev, "core");
> ?	if (IS_ERR(core_rst)) {
> @@ -771,22 +733,10 @@ static int rga_parse_dt(struct rockchip_rga *rga)
> ?	udelay(1);
> ?	reset_control_deassert(ahb_rst);
> ?
> -	rga->sclk = devm_clk_get(rga->dev, "sclk");
> -	if (IS_ERR(rga->sclk)) {
> -		dev_err(rga->dev, "failed to get sclk clock\n");
> -		return PTR_ERR(rga->sclk);
> -	}
> -
> -	rga->aclk = devm_clk_get(rga->dev, "aclk");
> -	if (IS_ERR(rga->aclk)) {
> -		dev_err(rga->dev, "failed to get aclk clock\n");
> -		return PTR_ERR(rga->aclk);
> -	}
> -
> -	rga->hclk = devm_clk_get(rga->dev, "hclk");
> -	if (IS_ERR(rga->hclk)) {
> -		dev_err(rga->dev, "failed to get hclk clock\n");
> -		return PTR_ERR(rga->hclk);
> +	ret = devm_clk_bulk_get(rga->dev, ARRAY_SIZE(rga->clks), rga->clks);
> +	if (ret) {
> +		dev_err(rga->dev, "failed to get clocks\n");
> +		return ret;
> ?	}
> ?
> ?	return 0;
> @@ -935,7 +885,7 @@ static int __maybe_unused rga_runtime_suspend(struct device *dev)
> ?{
> ?	struct rockchip_rga *rga = dev_get_drvdata(dev);
> ?
> -	rga_disable_clocks(rga);
> +	clk_bulk_disable_unprepare(ARRAY_SIZE(rga->clks), rga->clks);
> ?
> ?	return 0;
> ?}
> @@ -944,7 +894,7 @@ static int __maybe_unused rga_runtime_resume(struct device *dev)
> ?{
> ?	struct rockchip_rga *rga = dev_get_drvdata(dev);
> ?
> -	return rga_enable_clocks(rga);
> +	return clk_bulk_prepare_enable(ARRAY_SIZE(rga->clks), rga->clks);
> ?}
> ?
> ?static const struct dev_pm_ops rga_pm = {
> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
> index 72a28b120fabf..a922fac0c01a3 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -6,6 +6,7 @@
> ?#ifndef __RGA_H__
> ?#define __RGA_H__
> ?
> +#include <linux/clk.h>
> ?#include <linux/platform_device.h>
> ?#include <media/videobuf2-v4l2.h>
> ?#include <media/v4l2-ctrls.h>
> @@ -81,9 +82,7 @@ struct rockchip_rga {
> ?	struct device *dev;
> ?	struct regmap *grf;
> ?	void __iomem *regs;
> -	struct clk *sclk;
> -	struct clk *aclk;
> -	struct clk *hclk;
> +	struct clk_bulk_data clks[3];
> ?	struct rockchip_rga_version version;
> ?
> ?	/* vfd lock */
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/19b7a217/attachment.sig>

From marco.crivellari at suse.com  Wed Dec 24 06:57:38 2025
From: marco.crivellari at suse.com (Marco Crivellari)
Date: Wed, 24 Dec 2025 15:57:38 +0100
Subject: [PATCH] drm/exynos: hdmi: replace use of system_wq with system_percpu_wq
In-Reply-To: <20251104112923.143408-1-marco.crivellari@suse.com>
References: <20251104112923.143408-1-marco.crivellari@suse.com>
Message-ID: <CAAofZF4OJi5eEfjhE12RWi6wDU+A9Rghsd2721SxZR4AC08sYg@mail.gmail.com>

On Tue, Nov 4, 2025 at 12:29?PM Marco Crivellari
<marco.crivellari at suse.com> wrote:
> [...]
> ---
>  drivers/gpu/drm/exynos/exynos_hdmi.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)

Gentle ping.

Thanks!

-- 

Marco Crivellari

L3 Support Engineer


From nicolas at ndufresne.ca  Wed Dec 24 07:03:10 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 24 Dec 2025 10:03:10 -0500
Subject: [PATCH v2 06/22] media: rockchip: rga: remove redundant
 rga_frame variables
In-Reply-To: <20251203-spu-rga3-v2-6-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
	 <20251203-spu-rga3-v2-6-989a67947f71@pengutronix.de>
Message-ID: <2e84355c399fbce499d86e2b35b88d406460d6b1.camel@ndufresne.ca>

Le mercredi 03 d?cembre 2025 ? 16:52 +0100, Sven P?schel a ?crit?:
> Remove the redundant rga_frame variables width, height and color space.
> The value of these variables is already contained in the pix member
> of rga_frame. The code also keeps these values in sync. Therefore drop
> them in favor of the existing pix member.
> 
> Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?drivers/media/platform/rockchip/rga/rga-buf.c |? 6 ++---
> ?drivers/media/platform/rockchip/rga/rga-hw.c? |? 6 ++---
> ?drivers/media/platform/rockchip/rga/rga.c???? | 32 ++++++++++-----------------
> ?drivers/media/platform/rockchip/rga/rga.h???? |? 5 -----
> ?4 files changed, 18 insertions(+), 31 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
> index b5e6b1b527ca8..0c59a4d330888 100644
> --- a/drivers/media/platform/rockchip/rga/rga-buf.c
> +++ b/drivers/media/platform/rockchip/rga/rga-buf.c
> @@ -100,10 +100,10 @@ static int get_plane_offset(struct rga_frame *f,
> ?	if (plane == 0)
> ?		return 0;
> ?	if (plane == 1)
> -		return stride * f->height;
> +		return stride * f->pix.height;
> ?	if (plane == 2)
> -		return stride * f->height +
> -		?????? (stride * f->height / info->hdiv / info->vdiv);
> +		return stride * f->pix.height +
> +		?????? (stride * f->pix.height / info->hdiv / info->vdiv);
> ?
> ?	return -EINVAL;
> ?}
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
> index 43ed742a16492..f1d5237472941 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
> @@ -53,7 +53,7 @@ rga_get_addr_offset(struct rga_frame *frm, struct rga_addr_offset *offset,
> ?	x_div = frm->fmt->x_div;
> ?	y_div = frm->fmt->y_div;
> ?	uv_stride = frm->stride / x_div;
> -	pixel_width = frm->stride / frm->width;
> +	pixel_width = frm->stride / frm->pix.width;
> ?
> ?	lt->y_off = offset->y_off + y * frm->stride + x * pixel_width;
> ?	lt->u_off = offset->u_off + (y / y_div) * uv_stride + x / x_div;
> @@ -191,7 +191,7 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
> ?
> ?	if (RGA_COLOR_FMT_IS_YUV(ctx->in.fmt->hw_format) &&
> ?	??? RGA_COLOR_FMT_IS_RGB(ctx->out.fmt->hw_format)) {
> -		switch (ctx->in.colorspace) {
> +		switch (ctx->in.pix.colorspace) {
> ?		case V4L2_COLORSPACE_REC709:
> ?			src_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
> ?			break;
> @@ -203,7 +203,7 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
> ?
> ?	if (RGA_COLOR_FMT_IS_RGB(ctx->in.fmt->hw_format) &&
> ?	??? RGA_COLOR_FMT_IS_YUV(ctx->out.fmt->hw_format)) {
> -		switch (ctx->out.colorspace) {
> +		switch (ctx->out.pix.colorspace) {
> ?		case V4L2_COLORSPACE_REC709:
> ?			dst_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
> ?			break;
> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
> index ef568b3758380..f50fbbab0645e 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -345,9 +345,6 @@ static struct rga_fmt *rga_fmt_find(u32 pixelformat)
> ?}
> ?
> ?static struct rga_frame def_frame = {
> -	.width = DEFAULT_WIDTH,
> -	.height = DEFAULT_HEIGHT,
> -	.colorspace = V4L2_COLORSPACE_DEFAULT,
> ?	.crop.left = 0,
> ?	.crop.top = 0,
> ?	.crop.width = DEFAULT_WIDTH,
> @@ -379,9 +376,9 @@ static int rga_open(struct file *file)
> ?	ctx->out = def_frame;
> ?
> ?	v4l2_fill_pixfmt_mp(&ctx->in.pix,
> -			??? ctx->in.fmt->fourcc, ctx->out.width, ctx->out.height);
> +			??? ctx->in.fmt->fourcc, DEFAULT_WIDTH, DEFAULT_HEIGHT);
> ?	v4l2_fill_pixfmt_mp(&ctx->out.pix,
> -			??? ctx->out.fmt->fourcc, ctx->out.width, ctx->out.height);
> +			??? ctx->out.fmt->fourcc, DEFAULT_WIDTH, DEFAULT_HEIGHT);
> ?
> ?	if (mutex_lock_interruptible(&rga->mutex)) {
> ?		kfree(ctx);
> @@ -469,10 +466,8 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
> ?	if (IS_ERR(frm))
> ?		return PTR_ERR(frm);
> ?
> -	v4l2_fill_pixfmt_mp(pix_fmt, frm->fmt->fourcc, frm->width, frm->height);
> -
> +	*pix_fmt = frm->pix;
> ?	pix_fmt->field = V4L2_FIELD_NONE;
> -	pix_fmt->colorspace = frm->colorspace;
> ?
> ?	return 0;
> ?}
> @@ -521,27 +516,24 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
> ?	frm = rga_get_frame(ctx, f->type);
> ?	if (IS_ERR(frm))
> ?		return PTR_ERR(frm);
> -	frm->width = pix_fmt->width;
> -	frm->height = pix_fmt->height;
> ?	frm->size = 0;
> ?	for (i = 0; i < pix_fmt->num_planes; i++)
> ?		frm->size += pix_fmt->plane_fmt[i].sizeimage;
> ?	frm->fmt = rga_fmt_find(pix_fmt->pixelformat);
> ?	frm->stride = pix_fmt->plane_fmt[0].bytesperline;
> -	frm->colorspace = pix_fmt->colorspace;
> ?
> ?	/* Reset crop settings */
> ?	frm->crop.left = 0;
> ?	frm->crop.top = 0;
> -	frm->crop.width = frm->width;
> -	frm->crop.height = frm->height;
> +	frm->crop.width = pix_fmt->width;
> +	frm->crop.height = pix_fmt->height;
> ?
> ?	frm->pix = *pix_fmt;
> ?
> ?	v4l2_dbg(debug, 1, &rga->v4l2_dev,
> ?		 "[%s] fmt - %p4cc %dx%d (stride %d, sizeimage %d)\n",
> ?		? V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
> -		? &frm->fmt->fourcc, frm->width, frm->height,
> +		? &frm->fmt->fourcc, pix_fmt->width, pix_fmt->height,
> ?		? frm->stride, frm->size);
> ?
> ?	for (i = 0; i < pix_fmt->num_planes; i++) {
> @@ -595,8 +587,8 @@ static int vidioc_g_selection(struct file *file, void *priv,
> ?	} else {
> ?		s->r.left = 0;
> ?		s->r.top = 0;
> -		s->r.width = f->width;
> -		s->r.height = f->height;
> +		s->r.width = f->pix.width;
> +		s->r.height = f->pix.height;
> ?	}
> ?
> ?	return 0;
> @@ -645,8 +637,8 @@ static int vidioc_s_selection(struct file *file, void *priv,
> ?		return -EINVAL;
> ?	}
> ?
> -	if (s->r.left + s->r.width > f->width ||
> -	??? s->r.top + s->r.height > f->height ||
> +	if (s->r.left + s->r.width > f->pix.width ||
> +	??? s->r.top + s->r.height > f->pix.height ||
> ?	??? s->r.width < MIN_WIDTH || s->r.height < MIN_HEIGHT) {
> ?		v4l2_dbg(debug, 1, &rga->v4l2_dev, "unsupported crop value.\n");
> ?		return -EINVAL;
> @@ -836,8 +828,8 @@ static int rga_probe(struct platform_device *pdev)
> ?		goto rel_m2m;
> ?	}
> ?
> -	def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3;
> -	def_frame.size = def_frame.stride * def_frame.height;
> +	def_frame.stride = (DEFAULT_WIDTH * def_frame.fmt->depth) >> 3;
> +	def_frame.size = def_frame.stride * DEFAULT_HEIGHT;
> ?
> ?	ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
> ?	if (ret) {
> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
> index a922fac0c01a3..7ec1fcc03ed32 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -25,11 +25,6 @@ struct rga_fmt {
> ?};
> ?
> ?struct rga_frame {
> -	/* Original dimensions */
> -	u32 width;
> -	u32 height;
> -	u32 colorspace;
> -
> ?	/* Crop */
> ?	struct v4l2_rect crop;
> ?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/f27a874d/attachment-0001.sig>

From nicolas at ndufresne.ca  Wed Dec 24 07:05:57 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 24 Dec 2025 10:05:57 -0500
Subject: [PATCH v2 07/22] media: rockchip: rga: move hw specific parts
 to a dedicated struct
In-Reply-To: <20251203-spu-rga3-v2-7-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
	 <20251203-spu-rga3-v2-7-989a67947f71@pengutronix.de>
Message-ID: <be6c72090cdbf79d86dab5cc75a05db81cd1585c.camel@ndufresne.ca>

Le mercredi 03 d?cembre 2025 ? 16:52 +0100, Sven P?schel a ?crit?:
> In preparation for the RGA3 unit, move RGA2 specific parts from rga.c
> to rga-hw.c and create a struct to reference the RGA2 specific functions
> and formats. This also allows to remove the rga-hw.h reference from the
> include list of the rga driver.
> 
> Also document the command finish interrupt with a dedicated define.
> 
> Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?drivers/media/platform/rockchip/rga/rga-hw.c | 183 ++++++++++++++++++++-
> ?drivers/media/platform/rockchip/rga/rga-hw.h |?? 5 +-
> ?drivers/media/platform/rockchip/rga/rga.c??? | 228 +++++----------------------
> ?drivers/media/platform/rockchip/rga/rga.h??? |? 23 ++-
> ?4 files changed, 245 insertions(+), 194 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
> index f1d5237472941..7419784efc693 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
> @@ -437,8 +437,8 @@ static void rga_cmd_set(struct rga_ctx *ctx,
> ?		PAGE_SIZE, DMA_BIDIRECTIONAL);
> ?}
> ?
> -void rga_hw_start(struct rockchip_rga *rga,
> -		? struct rga_vb_buffer *src, struct rga_vb_buffer *dst)
> +static void rga_hw_start(struct rockchip_rga *rga,
> +			 struct rga_vb_buffer *src,? struct rga_vb_buffer *dst)
> ?{
> ?	struct rga_ctx *ctx = rga->curr;
> ?
> @@ -452,3 +452,182 @@ void rga_hw_start(struct rockchip_rga *rga,
> ?
> ?	rga_write(rga, RGA_CMD_CTRL, 0x1);
> ?}
> +
> +static bool rga_handle_irq(struct rockchip_rga *rga)
> +{
> +	int intr;
> +
> +	intr = rga_read(rga, RGA_INT) & 0xf;
> +
> +	rga_mod(rga, RGA_INT, intr << 4, 0xf << 4);
> +
> +	return intr & RGA_INT_COMMAND_FINISHED;
> +}
> +
> +static void rga_get_version(struct rockchip_rga *rga)
> +{
> +	rga->version.major = (rga_read(rga, RGA_VERSION_INFO) >> 24) & 0xFF;
> +	rga->version.minor = (rga_read(rga, RGA_VERSION_INFO) >> 20) & 0x0F;
> +}
> +
> +static struct rga_fmt formats[] = {
> +	{
> +		.fourcc = V4L2_PIX_FMT_ARGB32,
> +		.color_swap = RGA_COLOR_ALPHA_SWAP,
> +		.hw_format = RGA_COLOR_FMT_ABGR8888,
> +		.depth = 32,
> +		.uv_factor = 1,
> +		.y_div = 1,
> +		.x_div = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_ABGR32,
> +		.color_swap = RGA_COLOR_RB_SWAP,
> +		.hw_format = RGA_COLOR_FMT_ABGR8888,
> +		.depth = 32,
> +		.uv_factor = 1,
> +		.y_div = 1,
> +		.x_div = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_XBGR32,
> +		.color_swap = RGA_COLOR_RB_SWAP,
> +		.hw_format = RGA_COLOR_FMT_XBGR8888,
> +		.depth = 32,
> +		.uv_factor = 1,
> +		.y_div = 1,
> +		.x_div = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_RGB24,
> +		.color_swap = RGA_COLOR_NONE_SWAP,
> +		.hw_format = RGA_COLOR_FMT_RGB888,
> +		.depth = 24,
> +		.uv_factor = 1,
> +		.y_div = 1,
> +		.x_div = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_BGR24,
> +		.color_swap = RGA_COLOR_RB_SWAP,
> +		.hw_format = RGA_COLOR_FMT_RGB888,
> +		.depth = 24,
> +		.uv_factor = 1,
> +		.y_div = 1,
> +		.x_div = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_ARGB444,
> +		.color_swap = RGA_COLOR_RB_SWAP,
> +		.hw_format = RGA_COLOR_FMT_ABGR4444,
> +		.depth = 16,
> +		.uv_factor = 1,
> +		.y_div = 1,
> +		.x_div = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_ARGB555,
> +		.color_swap = RGA_COLOR_RB_SWAP,
> +		.hw_format = RGA_COLOR_FMT_ABGR1555,
> +		.depth = 16,
> +		.uv_factor = 1,
> +		.y_div = 1,
> +		.x_div = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_RGB565,
> +		.color_swap = RGA_COLOR_RB_SWAP,
> +		.hw_format = RGA_COLOR_FMT_BGR565,
> +		.depth = 16,
> +		.uv_factor = 1,
> +		.y_div = 1,
> +		.x_div = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_NV21,
> +		.color_swap = RGA_COLOR_UV_SWAP,
> +		.hw_format = RGA_COLOR_FMT_YUV420SP,
> +		.depth = 12,
> +		.uv_factor = 4,
> +		.y_div = 2,
> +		.x_div = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_NV61,
> +		.color_swap = RGA_COLOR_UV_SWAP,
> +		.hw_format = RGA_COLOR_FMT_YUV422SP,
> +		.depth = 16,
> +		.uv_factor = 2,
> +		.y_div = 1,
> +		.x_div = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_NV12,
> +		.color_swap = RGA_COLOR_NONE_SWAP,
> +		.hw_format = RGA_COLOR_FMT_YUV420SP,
> +		.depth = 12,
> +		.uv_factor = 4,
> +		.y_div = 2,
> +		.x_div = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_NV12M,
> +		.color_swap = RGA_COLOR_NONE_SWAP,
> +		.hw_format = RGA_COLOR_FMT_YUV420SP,
> +		.depth = 12,
> +		.uv_factor = 4,
> +		.y_div = 2,
> +		.x_div = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_NV16,
> +		.color_swap = RGA_COLOR_NONE_SWAP,
> +		.hw_format = RGA_COLOR_FMT_YUV422SP,
> +		.depth = 16,
> +		.uv_factor = 2,
> +		.y_div = 1,
> +		.x_div = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_YUV420,
> +		.color_swap = RGA_COLOR_NONE_SWAP,
> +		.hw_format = RGA_COLOR_FMT_YUV420P,
> +		.depth = 12,
> +		.uv_factor = 4,
> +		.y_div = 2,
> +		.x_div = 2,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_YUV422P,
> +		.color_swap = RGA_COLOR_NONE_SWAP,
> +		.hw_format = RGA_COLOR_FMT_YUV422P,
> +
> +		.depth = 16,
> +		.uv_factor = 2,
> +		.y_div = 1,
> +		.x_div = 2,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_YVU420,
> +		.color_swap = RGA_COLOR_UV_SWAP,
> +		.hw_format = RGA_COLOR_FMT_YUV420P,
> +		.depth = 12,
> +		.uv_factor = 4,
> +		.y_div = 2,
> +		.x_div = 2,
> +	},
> +};
> +
> +const struct rga_hw rga2_hw = {
> +	.formats = formats,
> +	.num_formats = ARRAY_SIZE(formats),
> +	.cmdbuf_size = RGA_CMDBUF_SIZE,
> +	.min_width = MIN_WIDTH,
> +	.max_width = MAX_WIDTH,
> +	.min_height = MIN_HEIGHT,
> +	.max_height = MAX_HEIGHT,
> +
> +	.start = rga_hw_start,
> +	.handle_irq = rga_handle_irq,
> +	.get_version = rga_get_version,
> +};
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.h b/drivers/media/platform/rockchip/rga/rga-hw.h
> index cc6bd7f5b0300..f4752aa823051 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.h
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.h
> @@ -15,9 +15,6 @@
> ?#define MIN_WIDTH 34
> ?#define MIN_HEIGHT 34
> ?
> -#define DEFAULT_WIDTH 100
> -#define DEFAULT_HEIGHT 100
> -
> ?#define RGA_TIMEOUT 500
> ?
> ?/* Registers address */
> @@ -178,6 +175,8 @@
> ?#define RGA_ALPHA_COLOR_NORMAL 0
> ?#define RGA_ALPHA_COLOR_MULTIPLY_CAL 1
> ?
> +#define RGA_INT_COMMAND_FINISHED 4
> +
> ?/* Registers union */
> ?union rga_mode_ctrl {
> ?	unsigned int val;
> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
> index f50fbbab0645e..d8b14c2d9f6a4 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -25,7 +25,6 @@
> ?#include <media/videobuf2-dma-sg.h>
> ?#include <media/videobuf2-v4l2.h>
> ?
> -#include "rga-hw.h"
> ?#include "rga.h"
> ?
> ?static int debug;
> @@ -47,7 +46,7 @@ static void device_run(void *prv)
> ?
> ?	dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
> ?
> -	rga_hw_start(rga, vb_to_rga(src), vb_to_rga(dst));
> +	rga->hw->start(rga, vb_to_rga(src), vb_to_rga(dst));
> ?
> ?	spin_unlock_irqrestore(&rga->ctrl_lock, flags);
> ?}
> @@ -55,13 +54,8 @@ static void device_run(void *prv)
> ?static irqreturn_t rga_isr(int irq, void *prv)
> ?{
> ?	struct rockchip_rga *rga = prv;
> -	int intr;
> ?
> -	intr = rga_read(rga, RGA_INT) & 0xf;
> -
> -	rga_mod(rga, RGA_INT, intr << 4, 0xf << 4);
> -
> -	if (intr & 0x04) {
> +	if (rga->hw->handle_irq(rga)) {
> ?		struct vb2_v4l2_buffer *src, *dst;
> ?		struct rga_ctx *ctx = rga->curr;
> ?
> @@ -184,174 +178,17 @@ static int rga_setup_ctrls(struct rga_ctx *ctx)
> ?	return 0;
> ?}
> ?
> -static struct rga_fmt formats[] = {
> -	{
> -		.fourcc = V4L2_PIX_FMT_ARGB32,
> -		.color_swap = RGA_COLOR_ALPHA_SWAP,
> -		.hw_format = RGA_COLOR_FMT_ABGR8888,
> -		.depth = 32,
> -		.uv_factor = 1,
> -		.y_div = 1,
> -		.x_div = 1,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_ABGR32,
> -		.color_swap = RGA_COLOR_RB_SWAP,
> -		.hw_format = RGA_COLOR_FMT_ABGR8888,
> -		.depth = 32,
> -		.uv_factor = 1,
> -		.y_div = 1,
> -		.x_div = 1,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_XBGR32,
> -		.color_swap = RGA_COLOR_RB_SWAP,
> -		.hw_format = RGA_COLOR_FMT_XBGR8888,
> -		.depth = 32,
> -		.uv_factor = 1,
> -		.y_div = 1,
> -		.x_div = 1,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_RGB24,
> -		.color_swap = RGA_COLOR_NONE_SWAP,
> -		.hw_format = RGA_COLOR_FMT_RGB888,
> -		.depth = 24,
> -		.uv_factor = 1,
> -		.y_div = 1,
> -		.x_div = 1,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_BGR24,
> -		.color_swap = RGA_COLOR_RB_SWAP,
> -		.hw_format = RGA_COLOR_FMT_RGB888,
> -		.depth = 24,
> -		.uv_factor = 1,
> -		.y_div = 1,
> -		.x_div = 1,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_ARGB444,
> -		.color_swap = RGA_COLOR_RB_SWAP,
> -		.hw_format = RGA_COLOR_FMT_ABGR4444,
> -		.depth = 16,
> -		.uv_factor = 1,
> -		.y_div = 1,
> -		.x_div = 1,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_ARGB555,
> -		.color_swap = RGA_COLOR_RB_SWAP,
> -		.hw_format = RGA_COLOR_FMT_ABGR1555,
> -		.depth = 16,
> -		.uv_factor = 1,
> -		.y_div = 1,
> -		.x_div = 1,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_RGB565,
> -		.color_swap = RGA_COLOR_RB_SWAP,
> -		.hw_format = RGA_COLOR_FMT_BGR565,
> -		.depth = 16,
> -		.uv_factor = 1,
> -		.y_div = 1,
> -		.x_div = 1,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_NV21,
> -		.color_swap = RGA_COLOR_UV_SWAP,
> -		.hw_format = RGA_COLOR_FMT_YUV420SP,
> -		.depth = 12,
> -		.uv_factor = 4,
> -		.y_div = 2,
> -		.x_div = 1,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_NV61,
> -		.color_swap = RGA_COLOR_UV_SWAP,
> -		.hw_format = RGA_COLOR_FMT_YUV422SP,
> -		.depth = 16,
> -		.uv_factor = 2,
> -		.y_div = 1,
> -		.x_div = 1,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_NV12,
> -		.color_swap = RGA_COLOR_NONE_SWAP,
> -		.hw_format = RGA_COLOR_FMT_YUV420SP,
> -		.depth = 12,
> -		.uv_factor = 4,
> -		.y_div = 2,
> -		.x_div = 1,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_NV12M,
> -		.color_swap = RGA_COLOR_NONE_SWAP,
> -		.hw_format = RGA_COLOR_FMT_YUV420SP,
> -		.depth = 12,
> -		.uv_factor = 4,
> -		.y_div = 2,
> -		.x_div = 1,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_NV16,
> -		.color_swap = RGA_COLOR_NONE_SWAP,
> -		.hw_format = RGA_COLOR_FMT_YUV422SP,
> -		.depth = 16,
> -		.uv_factor = 2,
> -		.y_div = 1,
> -		.x_div = 1,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_YUV420,
> -		.color_swap = RGA_COLOR_NONE_SWAP,
> -		.hw_format = RGA_COLOR_FMT_YUV420P,
> -		.depth = 12,
> -		.uv_factor = 4,
> -		.y_div = 2,
> -		.x_div = 2,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_YUV422P,
> -		.color_swap = RGA_COLOR_NONE_SWAP,
> -		.hw_format = RGA_COLOR_FMT_YUV422P,
> -		.depth = 16,
> -		.uv_factor = 2,
> -		.y_div = 1,
> -		.x_div = 2,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_YVU420,
> -		.color_swap = RGA_COLOR_UV_SWAP,
> -		.hw_format = RGA_COLOR_FMT_YUV420P,
> -		.depth = 12,
> -		.uv_factor = 4,
> -		.y_div = 2,
> -		.x_div = 2,
> -	},
> -};
> -
> -#define NUM_FORMATS ARRAY_SIZE(formats)
> -
> -static struct rga_fmt *rga_fmt_find(u32 pixelformat)
> +static struct rga_fmt *rga_fmt_find(struct rockchip_rga *rga, u32 pixelformat)
> ?{
> ?	unsigned int i;
> ?
> -	for (i = 0; i < NUM_FORMATS; i++) {
> -		if (formats[i].fourcc == pixelformat)
> -			return &formats[i];
> +	for (i = 0; i < rga->hw->num_formats; i++) {
> +		if (rga->hw->formats[i].fourcc == pixelformat)
> +			return &rga->hw->formats[i];
> ?	}
> ?	return NULL;
> ?}
> ?
> -static struct rga_frame def_frame = {
> -	.crop.left = 0,
> -	.crop.top = 0,
> -	.crop.width = DEFAULT_WIDTH,
> -	.crop.height = DEFAULT_HEIGHT,
> -	.fmt = &formats[0],
> -};
> -
> ?struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type)
> ?{
> ?	if (V4L2_TYPE_IS_OUTPUT(type))
> @@ -366,6 +203,18 @@ static int rga_open(struct file *file)
> ?	struct rockchip_rga *rga = video_drvdata(file);
> ?	struct rga_ctx *ctx = NULL;
> ?	int ret = 0;
> +	u32 def_width = clamp(DEFAULT_WIDTH, rga->hw->min_width, rga->hw->max_width);
> +	u32 def_height = clamp(DEFAULT_HEIGHT, rga->hw->min_height, rga->hw->max_height);
> +	struct rga_frame def_frame = {
> +		.crop.left = 0,
> +		.crop.top = 0,
> +		.crop.width = def_width,
> +		.crop.height = def_height,
> +		.fmt = &rga->hw->formats[0],
> +	};
> +
> +	def_frame.stride = (def_width * def_frame.fmt->depth) >> 3;
> +	def_frame.size = def_frame.stride * def_height;
> ?
> ?	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> ?	if (!ctx)
> @@ -376,9 +225,9 @@ static int rga_open(struct file *file)
> ?	ctx->out = def_frame;
> ?
> ?	v4l2_fill_pixfmt_mp(&ctx->in.pix,
> -			??? ctx->in.fmt->fourcc, DEFAULT_WIDTH, DEFAULT_HEIGHT);
> +			??? ctx->in.fmt->fourcc, def_width, def_height);
> ?	v4l2_fill_pixfmt_mp(&ctx->out.pix,
> -			??? ctx->out.fmt->fourcc, DEFAULT_WIDTH, DEFAULT_HEIGHT);
> +			??? ctx->out.fmt->fourcc, def_width, def_height);
> ?
> ?	if (mutex_lock_interruptible(&rga->mutex)) {
> ?		kfree(ctx);
> @@ -445,12 +294,13 @@ vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
> ?
> ?static int vidioc_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f)
> ?{
> +	struct rockchip_rga *rga = video_drvdata(file);
> ?	struct rga_fmt *fmt;
> ?
> -	if (f->index >= NUM_FORMATS)
> +	if (f->index >= rga->hw->num_formats)
> ?		return -EINVAL;
> ?
> -	fmt = &formats[f->index];
> +	fmt = &rga->hw->formats[f->index];
> ?	f->pixelformat = fmt->fourcc;
> ?
> ?	return 0;
> @@ -475,16 +325,18 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
> ?static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
> ?{
> ?	struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp;
> +	struct rockchip_rga *rga = video_drvdata(file);
> +	const struct rga_hw *hw = rga->hw;
> ?	struct rga_fmt *fmt;
> ?
> -	fmt = rga_fmt_find(pix_fmt->pixelformat);
> +	fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
> ?	if (!fmt)
> -		fmt = &formats[0];
> +		fmt = &hw->formats[0];
> ?
> ?	pix_fmt->width = clamp(pix_fmt->width,
> -			?????? (u32)MIN_WIDTH, (u32)MAX_WIDTH);
> +			?????? hw->min_width, hw->max_width);
> ?	pix_fmt->height = clamp(pix_fmt->height,
> -				(u32)MIN_HEIGHT, (u32)MAX_HEIGHT);
> +				hw->min_height, hw->max_height);
> ?
> ?	v4l2_fill_pixfmt_mp(pix_fmt, fmt->fourcc, pix_fmt->width, pix_fmt->height);
> ?	pix_fmt->field = V4L2_FIELD_NONE;
> @@ -519,7 +371,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
> ?	frm->size = 0;
> ?	for (i = 0; i < pix_fmt->num_planes; i++)
> ?		frm->size += pix_fmt->plane_fmt[i].sizeimage;
> -	frm->fmt = rga_fmt_find(pix_fmt->pixelformat);
> +	frm->fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
> ?	frm->stride = pix_fmt->plane_fmt[0].bytesperline;
> ?
> ?	/* Reset crop settings */
> @@ -639,7 +491,7 @@ static int vidioc_s_selection(struct file *file, void *priv,
> ?
> ?	if (s->r.left + s->r.width > f->pix.width ||
> ?	??? s->r.top + s->r.height > f->pix.height ||
> -	??? s->r.width < MIN_WIDTH || s->r.height < MIN_HEIGHT) {
> +	??? s->r.width < rga->hw->min_width || s->r.height < rga->hw->min_height) {
> ?		v4l2_dbg(debug, 1, &rga->v4l2_dev, "unsupported crop value.\n");
> ?		return -EINVAL;
> ?	}
> @@ -748,6 +600,10 @@ static int rga_probe(struct platform_device *pdev)
> ?	if (!rga)
> ?		return -ENOMEM;
> ?
> +	rga->hw = of_device_get_match_data(&pdev->dev);
> +	if (!rga->hw)
> +		return dev_err_probe(&pdev->dev, -ENODEV, "failed to get match data\n");
> +
> ?	rga->dev = &pdev->dev;
> ?	spin_lock_init(&rga->ctrl_lock);
> ?	mutex_init(&rga->mutex);
> @@ -811,8 +667,7 @@ static int rga_probe(struct platform_device *pdev)
> ?	if (ret < 0)
> ?		goto rel_m2m;
> ?
> -	rga->version.major = (rga_read(rga, RGA_VERSION_INFO) >> 24) & 0xFF;
> -	rga->version.minor = (rga_read(rga, RGA_VERSION_INFO) >> 20) & 0x0F;
> +	rga->hw->get_version(rga);
> ?
> ?	v4l2_info(&rga->v4l2_dev, "HW Version: 0x%02x.%02x\n",
> ?		? rga->version.major, rga->version.minor);
> @@ -820,7 +675,7 @@ static int rga_probe(struct platform_device *pdev)
> ?	pm_runtime_put(rga->dev);
> ?
> ?	/* Create CMD buffer */
> -	rga->cmdbuf_virt = dma_alloc_attrs(rga->dev, RGA_CMDBUF_SIZE,
> +	rga->cmdbuf_virt = dma_alloc_attrs(rga->dev, rga->hw->cmdbuf_size,
> ?					?? &rga->cmdbuf_phy, GFP_KERNEL,
> ?					?? DMA_ATTR_WRITE_COMBINE);
> ?	if (!rga->cmdbuf_virt) {
> @@ -828,9 +683,6 @@ static int rga_probe(struct platform_device *pdev)
> ?		goto rel_m2m;
> ?	}
> ?
> -	def_frame.stride = (DEFAULT_WIDTH * def_frame.fmt->depth) >> 3;
> -	def_frame.size = def_frame.stride * DEFAULT_HEIGHT;
> -
> ?	ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
> ?	if (ret) {
> ?		v4l2_err(&rga->v4l2_dev, "Failed to register video device\n");
> @@ -843,7 +695,7 @@ static int rga_probe(struct platform_device *pdev)
> ?	return 0;
> ?
> ?free_dma:
> -	dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, rga->cmdbuf_virt,
> +	dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, rga->cmdbuf_virt,
> ?		?????? rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
> ?rel_m2m:
> ?	v4l2_m2m_release(rga->m2m_dev);
> @@ -861,7 +713,7 @@ static void rga_remove(struct platform_device *pdev)
> ?{
> ?	struct rockchip_rga *rga = platform_get_drvdata(pdev);
> ?
> -	dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, rga->cmdbuf_virt,
> +	dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, rga->cmdbuf_virt,
> ?		?????? rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
> ?
> ?	v4l2_info(&rga->v4l2_dev, "Removing\n");
> @@ -897,9 +749,11 @@ static const struct dev_pm_ops rga_pm = {
> ?static const struct of_device_id rockchip_rga_match[] = {
> ?	{
> ?		.compatible = "rockchip,rk3288-rga",
> +		.data = &rga2_hw,
> ?	},
> ?	{
> ?		.compatible = "rockchip,rk3399-rga",
> +		.data = &rga2_hw,
> ?	},
> ?	{},
> ?};
> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
> index 7ec1fcc03ed32..98635ddd50d7c 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -14,6 +14,9 @@
> ?
> ?#define RGA_NAME "rockchip-rga"
> ?
> +#define DEFAULT_WIDTH 100
> +#define DEFAULT_HEIGHT 100
> +
> ?struct rga_fmt {
> ?	u32 fourcc;
> ?	int depth;
> @@ -69,6 +72,8 @@ static inline struct rga_ctx *file_to_rga_ctx(struct file *filp)
> ?	return container_of(file_to_v4l2_fh(filp), struct rga_ctx, fh);
> ?}
> ?
> +struct rga_hw;
> +
> ?struct rockchip_rga {
> ?	struct v4l2_device v4l2_dev;
> ?	struct v4l2_m2m_dev *m2m_dev;
> @@ -88,6 +93,8 @@ struct rockchip_rga {
> ?	struct rga_ctx *curr;
> ?	dma_addr_t cmdbuf_phy;
> ?	void *cmdbuf_virt;
> +
> +	const struct rga_hw *hw;
> ?};
> ?
> ?struct rga_addr_offset {
> @@ -138,7 +145,19 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
> ?	rga_write(rga, reg, temp);
> ?};
> ?
> -void rga_hw_start(struct rockchip_rga *rga,
> -		? struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
> +struct rga_hw {
> +	struct rga_fmt *formats;
> +	u32 num_formats;
> +	size_t cmdbuf_size;
> +	u32 min_width, min_height;
> +	u32 max_width, max_height;
> +
> +	void (*start)(struct rockchip_rga *rga,
> +		????? struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
> +	bool (*handle_irq)(struct rockchip_rga *rga);
> +	void (*get_version)(struct rockchip_rga *rga);
> +};
> +
> +extern const struct rga_hw rga2_hw;
> ?
> ?#endif
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/61dba539/attachment.sig>

From nicolas at ndufresne.ca  Wed Dec 24 07:00:34 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 24 Dec 2025 10:00:34 -0500
Subject: [PATCH v2 05/22] media: rockchip: rga: use stride for offset
 calculation
In-Reply-To: <20251203-spu-rga3-v2-5-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
	 <20251203-spu-rga3-v2-5-989a67947f71@pengutronix.de>
Message-ID: <7d9f41a8609fdae7631305585cab47fd45297c5c.camel@ndufresne.ca>

Le mercredi 03 d?cembre 2025 ? 16:52 +0100, Sven P?schel a ?crit?:
> Use the stride instead of the width for the offset calculation. This
> ensures that the bytesperline value doesn't need to match the width
> value of the image.
> 
> Furthermore this patch removes the dependency on the uv_factor property
> and instead reuses the v4l2_format_info to determine the correct
> division factor.
> 
> Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
> ---
> ?drivers/media/platform/rockchip/rga/rga-buf.c | 14 +++++++++-----
> ?1 file changed, 9 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
> index 730bdf98565a5..b5e6b1b527ca8 100644
> --- a/drivers/media/platform/rockchip/rga/rga-buf.c
> +++ b/drivers/media/platform/rockchip/rga/rga-buf.c
> @@ -14,7 +14,6 @@
> ?#include <media/videobuf2-dma-sg.h>
> ?#include <media/videobuf2-v4l2.h>
> ?
> -#include "rga-hw.h"
> ?#include "rga.h"
> ?
> ?static ssize_t fill_descriptors(struct rga_dma_desc *desc, size_t max_desc,
> @@ -92,14 +91,19 @@ static int rga_buf_init(struct vb2_buffer *vb)
> ?	return 0;
> ?}
> ?
> -static int get_plane_offset(struct rga_frame *f, int plane)
> +static int get_plane_offset(struct rga_frame *f,
> +			??? const struct v4l2_format_info *info,
> +			??? int plane)
> ?{
> +	u32 stride = f->pix.plane_fmt[0].bytesperline;
> +
> ?	if (plane == 0)
> ?		return 0;
> ?	if (plane == 1)
> -		return f->width * f->height;
> +		return stride * f->height;
> ?	if (plane == 2)
> -		return f->width * f->height + (f->width * f->height / f->fmt->uv_factor);
> +		return stride * f->height +
> +		?????? (stride * f->height / info->hdiv / info->vdiv);

This was the only user of uv_factor, please cleanup rga.h/rga.c. I see there is
also redudant x_div/y_div, with this similar code re-implemented in
rga_get_addr_offset(), can you check for v3 if we can cleanup some more ?

One thought though is that this code is already hidden inside v4l2-common,
perhaps you could just expose it, this ensure that we don't accidently have
different information when configuring the HW and communicating with the user.

Nicolas

> ?
> ?	return -EINVAL;
> ?}
> @@ -145,7 +149,7 @@ static int rga_buf_prepare(struct vb2_buffer *vb)
> ?	/* Fill the remaining planes */
> ?	info = v4l2_format_info(f->fmt->fourcc);
> ?	for (i = info->mem_planes; i < info->comp_planes; i++)
> -		offsets[i] = get_plane_offset(f, i);
> +		offsets[i] = get_plane_offset(f, info, i);
> ?
> ?	rbuf->offset.y_off = offsets[0];
> ?	rbuf->offset.u_off = offsets[1];
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/000c2e78/attachment-0001.sig>

From nicolas at ndufresne.ca  Wed Dec 24 07:21:10 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 24 Dec 2025 10:21:10 -0500
Subject: [PATCH v2 08/22] media: rockchip: rga: move cmdbuf to rga_ctx
In-Reply-To: <20251203-spu-rga3-v2-8-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
	 <20251203-spu-rga3-v2-8-989a67947f71@pengutronix.de>
Message-ID: <b8dac5e182ed5142506ac730911c4158daeb4fd4.camel@ndufresne.ca>

Hi,

Le mercredi 03 d?cembre 2025 ? 16:52 +0100, Sven P?schel a ?crit?:
> Move the command buffer to the rga_ctx struct in preparation to reuse
> an already prepared command buffer. Having a command buffer per context
> allows to reuse the command buffer for other frames even when
> multiple applications are using the RGA in at the same time.

So the command buffer is only holding commands for a single render, and its not
possible to append to it right ? It has no sync point or anything that would let
us program it live ?

In this context, that sounds about right. Though please rework the commit
message, I find it a little miss-leading, since in the code you still program it
in device_run(), which is during the idle portion of the hardware.

To really benefit, you would have to program and flush it on the context qbuf,
so that once device_run() is call, you just have to set the command buf for the
context and trigger. Basically, no performance is gained from this patch I
believe.

> 
> Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>

With a clear commit message:

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?drivers/media/platform/rockchip/rga/rga-hw.c | 28 +++++++---------
> ?drivers/media/platform/rockchip/rga/rga.c??? | 48 ++++++++++++++++-----------
> -
> ?drivers/media/platform/rockchip/rga/rga.h??? |? 5 +--
> ?3 files changed, 41 insertions(+), 40 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c
> b/drivers/media/platform/rockchip/rga/rga-hw.c
> index 7419784efc693..79bf911e74779 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
> @@ -113,8 +113,7 @@ static struct rga_addr_offset *rga_lookup_draw_pos(struct
> ?
> ?static void rga_cmd_set_src_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)
> ?{
> -	struct rockchip_rga *rga = ctx->rga;
> -	u32 *dest = rga->cmdbuf_virt;
> +	u32 *dest = ctx->cmdbuf_virt;
> ?	unsigned int reg;
> ?
> ?	reg = RGA_MMU_SRC_BASE - RGA_MODE_BASE_REG;
> @@ -126,8 +125,7 @@ static void rga_cmd_set_src_addr(struct rga_ctx *ctx,
> dma_addr_t dma_addr)
> ?
> ?static void rga_cmd_set_src1_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)
> ?{
> -	struct rockchip_rga *rga = ctx->rga;
> -	u32 *dest = rga->cmdbuf_virt;
> +	u32 *dest = ctx->cmdbuf_virt;
> ?	unsigned int reg;
> ?
> ?	reg = RGA_MMU_SRC1_BASE - RGA_MODE_BASE_REG;
> @@ -139,8 +137,7 @@ static void rga_cmd_set_src1_addr(struct rga_ctx *ctx,
> dma_addr_t dma_addr)
> ?
> ?static void rga_cmd_set_dst_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)
> ?{
> -	struct rockchip_rga *rga = ctx->rga;
> -	u32 *dest = rga->cmdbuf_virt;
> +	u32 *dest = ctx->cmdbuf_virt;
> ?	unsigned int reg;
> ?
> ?	reg = RGA_MMU_DST_BASE - RGA_MODE_BASE_REG;
> @@ -153,7 +150,7 @@ static void rga_cmd_set_dst_addr(struct rga_ctx *ctx,
> dma_addr_t dma_addr)
> ?static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
> ?{
> ?	struct rockchip_rga *rga = ctx->rga;
> -	u32 *dest = rga->cmdbuf_virt;
> +	u32 *dest = ctx->cmdbuf_virt;
> ?	unsigned int scale_dst_w, scale_dst_h;
> ?	unsigned int src_h, src_w, dst_h, dst_w;
> ?	union rga_src_info src_info;
> @@ -313,8 +310,7 @@ static void rga_cmd_set_src_info(struct rga_ctx *ctx,
> ?				 struct rga_addr_offset *offset)
> ?{
> ?	struct rga_corners_addr_offset src_offsets;
> -	struct rockchip_rga *rga = ctx->rga;
> -	u32 *dest = rga->cmdbuf_virt;
> +	u32 *dest = ctx->cmdbuf_virt;
> ?	unsigned int src_h, src_w, src_x, src_y;
> ?
> ?	src_h = ctx->in.crop.height;
> @@ -341,8 +337,7 @@ static void rga_cmd_set_dst_info(struct rga_ctx *ctx,
> ?{
> ?	struct rga_addr_offset *dst_offset;
> ?	struct rga_corners_addr_offset offsets;
> -	struct rockchip_rga *rga = ctx->rga;
> -	u32 *dest = rga->cmdbuf_virt;
> +	u32 *dest = ctx->cmdbuf_virt;
> ?	unsigned int dst_h, dst_w, dst_x, dst_y;
> ?	unsigned int mir_mode = 0;
> ?	unsigned int rot_mode = 0;
> @@ -388,8 +383,7 @@ static void rga_cmd_set_dst_info(struct rga_ctx *ctx,
> ?
> ?static void rga_cmd_set_mode(struct rga_ctx *ctx)
> ?{
> -	struct rockchip_rga *rga = ctx->rga;
> -	u32 *dest = rga->cmdbuf_virt;
> +	u32 *dest = ctx->cmdbuf_virt;
> ?	union rga_mode_ctrl mode;
> ?	union rga_alpha_ctrl0 alpha_ctrl0;
> ?	union rga_alpha_ctrl1 alpha_ctrl1;
> @@ -414,7 +408,7 @@ static void rga_cmd_set(struct rga_ctx *ctx,
> ?{
> ?	struct rockchip_rga *rga = ctx->rga;
> ?
> -	memset(rga->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);
> +	memset(ctx->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);
> ?
> ?	rga_cmd_set_src_addr(ctx, src->dma_desc_pa);
> ?	/*
> @@ -430,11 +424,11 @@ static void rga_cmd_set(struct rga_ctx *ctx,
> ?	rga_cmd_set_dst_info(ctx, &dst->offset);
> ?	rga_cmd_set_trans_info(ctx);
> ?
> -	rga_write(rga, RGA_CMD_BASE, rga->cmdbuf_phy);
> +	rga_write(rga, RGA_CMD_BASE, ctx->cmdbuf_phy);
> ?
> ?	/* sync CMD buf for RGA */
> -	dma_sync_single_for_device(rga->dev, rga->cmdbuf_phy,
> -		PAGE_SIZE, DMA_BIDIRECTIONAL);
> +	dma_sync_single_for_device(rga->dev, ctx->cmdbuf_phy,
> +				?? PAGE_SIZE, DMA_BIDIRECTIONAL);
> ?}
> ?
> ?static void rga_hw_start(struct rockchip_rga *rga,
> diff --git a/drivers/media/platform/rockchip/rga/rga.c
> b/drivers/media/platform/rockchip/rga/rga.c
> index d8b14c2d9f6a4..74d94c7fe31ff 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -219,6 +219,16 @@ static int rga_open(struct file *file)
> ?	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> ?	if (!ctx)
> ?		return -ENOMEM;
> +
> +	/* Create CMD buffer */
> +	ctx->cmdbuf_virt = dma_alloc_attrs(rga->dev, rga->hw->cmdbuf_size,
> +					?? &ctx->cmdbuf_phy, GFP_KERNEL,
> +					?? DMA_ATTR_WRITE_COMBINE);
> +	if (!ctx->cmdbuf_virt) {
> +		ret = -ENOMEM;
> +		goto rel_ctx;
> +	}
> +
> ?	ctx->rga = rga;
> ?	/* Set default formats */
> ?	ctx->in = def_frame;
> @@ -230,15 +240,13 @@ static int rga_open(struct file *file)
> ?			??? ctx->out.fmt->fourcc, def_width, def_height);
> ?
> ?	if (mutex_lock_interruptible(&rga->mutex)) {
> -		kfree(ctx);
> -		return -ERESTARTSYS;
> +		ret = -ERESTARTSYS;
> +		goto rel_cmdbuf;
> ?	}
> ?	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(rga->m2m_dev, ctx, &queue_init);
> ?	if (IS_ERR(ctx->fh.m2m_ctx)) {
> ?		ret = PTR_ERR(ctx->fh.m2m_ctx);
> -		mutex_unlock(&rga->mutex);
> -		kfree(ctx);
> -		return ret;
> +		goto unlock_mutex;
> ?	}
> ?	v4l2_fh_init(&ctx->fh, video_devdata(file));
> ?	v4l2_fh_add(&ctx->fh, file);
> @@ -252,6 +260,15 @@ static int rga_open(struct file *file)
> ?	mutex_unlock(&rga->mutex);
> ?
> ?	return 0;
> +
> +unlock_mutex:
> +	mutex_unlock(&rga->mutex);
> +rel_cmdbuf:
> +	dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, ctx->cmdbuf_virt,
> +		?????? ctx->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
> +rel_ctx:
> +	kfree(ctx);
> +	return ret;
> ?}
> ?
> ?static int rga_release(struct file *file)
> @@ -266,6 +283,10 @@ static int rga_release(struct file *file)
> ?	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
> ?	v4l2_fh_del(&ctx->fh, file);
> ?	v4l2_fh_exit(&ctx->fh);
> +
> +	dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, ctx->cmdbuf_virt,
> +		?????? ctx->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
> +
> ?	kfree(ctx);
> ?
> ?	mutex_unlock(&rga->mutex);
> @@ -674,19 +695,10 @@ static int rga_probe(struct platform_device *pdev)
> ?
> ?	pm_runtime_put(rga->dev);
> ?
> -	/* Create CMD buffer */
> -	rga->cmdbuf_virt = dma_alloc_attrs(rga->dev, rga->hw->cmdbuf_size,
> -					?? &rga->cmdbuf_phy, GFP_KERNEL,
> -					?? DMA_ATTR_WRITE_COMBINE);
> -	if (!rga->cmdbuf_virt) {
> -		ret = -ENOMEM;
> -		goto rel_m2m;
> -	}
> -
> ?	ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
> ?	if (ret) {
> ?		v4l2_err(&rga->v4l2_dev, "Failed to register video
> device\n");
> -		goto free_dma;
> +		goto rel_m2m;
> ?	}
> ?
> ?	v4l2_info(&rga->v4l2_dev, "Registered %s as /dev/%s\n",
> @@ -694,9 +706,6 @@ static int rga_probe(struct platform_device *pdev)
> ?
> ?	return 0;
> ?
> -free_dma:
> -	dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, rga->cmdbuf_virt,
> -		?????? rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
> ?rel_m2m:
> ?	v4l2_m2m_release(rga->m2m_dev);
> ?rel_vdev:
> @@ -713,9 +722,6 @@ static void rga_remove(struct platform_device *pdev)
> ?{
> ?	struct rockchip_rga *rga = platform_get_drvdata(pdev);
> ?
> -	dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, rga->cmdbuf_virt,
> -		?????? rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
> -
> ?	v4l2_info(&rga->v4l2_dev, "Removing\n");
> ?
> ?	v4l2_m2m_release(rga->m2m_dev);
> diff --git a/drivers/media/platform/rockchip/rga/rga.h
> b/drivers/media/platform/rockchip/rga/rga.h
> index 98635ddd50d7c..f8c932fdec21a 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -56,6 +56,9 @@ struct rga_ctx {
> ?	struct rga_frame out;
> ?	struct v4l2_ctrl_handler ctrl_handler;
> ?
> +	void *cmdbuf_virt;
> +	dma_addr_t cmdbuf_phy;
> +
> ?	int osequence;
> ?	int csequence;
> ?
> @@ -91,8 +94,6 @@ struct rockchip_rga {
> ?	spinlock_t ctrl_lock;
> ?
> ?	struct rga_ctx *curr;
> -	dma_addr_t cmdbuf_phy;
> -	void *cmdbuf_virt;
> ?
> ?	const struct rga_hw *hw;
> ?};
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/dcd181e9/attachment.sig>

From joaopeixoto at osyx.tech  Wed Dec 24 05:52:16 2025
From: joaopeixoto at osyx.tech (joaopeixoto at osyx.tech)
Date: Wed, 24 Dec 2025 13:52:16 +0000
Subject: [PATCH 4/5] virt: add Bao I/O dispatcher driver
In-Reply-To: <20251224135217.25350-1-joaopeixoto@osyx.tech>
References: <20251224135217.25350-1-joaopeixoto@osyx.tech>
Message-ID: <20251224135217.25350-5-joaopeixoto@osyx.tech>

From: Jo?o Peixoto <joaopeixoto at osyx.tech>

Introduce the Bao I/O Dispatcher, a kernel module that can be loaded
into backend VMs. It provides the bridge between the Bao hypervisor
Remote I/O system (Bao's mechanism for forwarding I/O requests from
frontend VMs to backend VMs) and the VirtIO backend device, offering
a unified API to support various VirtIO backends.

This patch includes:
    - Architecture-specific headers for ARM, ARM64, and RISC-V
    - Driver framework in drivers/virt/bao/ including dm, driver, intc,
    io_client, io_dispatcher, ioctls, ioeventfd, and irqfd
    - Kconfig and Makefile entries to enable building the module
    - UAPI header for userspace API exposure
    - Documentation update for ioctl number references

Signed-off-by: Jo?o Peixoto <joaopeixoto at osyx.tech>
---
 .../userspace-api/ioctl/ioctl-number.rst      |   2 +
 arch/arm/include/asm/bao.h                    |  62 +++
 arch/arm64/include/asm/bao.h                  |  62 +++
 arch/riscv/include/asm/bao.h                  |  61 +++
 drivers/virt/Makefile                         |   1 +
 drivers/virt/bao/Kconfig                      |   2 +
 drivers/virt/bao/Makefile                     |   1 +
 drivers/virt/bao/io-dispatcher/Kconfig        |  16 +
 drivers/virt/bao/io-dispatcher/Makefile       |   4 +
 drivers/virt/bao/io-dispatcher/bao_drv.h      | 386 ++++++++++++++++
 drivers/virt/bao/io-dispatcher/dm.c           | 330 +++++++++++++
 drivers/virt/bao/io-dispatcher/driver.c       | 348 ++++++++++++++
 drivers/virt/bao/io-dispatcher/hypercall.h    |  30 ++
 drivers/virt/bao/io-dispatcher/intc.c         |  68 +++
 drivers/virt/bao/io-dispatcher/io_client.c    | 435 ++++++++++++++++++
 .../virt/bao/io-dispatcher/io_dispatcher.c    | 207 +++++++++
 drivers/virt/bao/io-dispatcher/ioctls.c       | 145 ++++++
 drivers/virt/bao/io-dispatcher/ioeventfd.c    | 336 ++++++++++++++
 drivers/virt/bao/io-dispatcher/irqfd.c        | 341 ++++++++++++++
 include/uapi/linux/bao.h                      | 124 +++++
 20 files changed, 2961 insertions(+)
 create mode 100644 arch/arm/include/asm/bao.h
 create mode 100644 arch/arm64/include/asm/bao.h
 create mode 100644 arch/riscv/include/asm/bao.h
 create mode 100644 drivers/virt/bao/io-dispatcher/Kconfig
 create mode 100644 drivers/virt/bao/io-dispatcher/Makefile
 create mode 100644 drivers/virt/bao/io-dispatcher/bao_drv.h
 create mode 100644 drivers/virt/bao/io-dispatcher/dm.c
 create mode 100644 drivers/virt/bao/io-dispatcher/driver.c
 create mode 100644 drivers/virt/bao/io-dispatcher/hypercall.h
 create mode 100644 drivers/virt/bao/io-dispatcher/intc.c
 create mode 100644 drivers/virt/bao/io-dispatcher/io_client.c
 create mode 100644 drivers/virt/bao/io-dispatcher/io_dispatcher.c
 create mode 100644 drivers/virt/bao/io-dispatcher/ioctls.c
 create mode 100644 drivers/virt/bao/io-dispatcher/ioeventfd.c
 create mode 100644 drivers/virt/bao/io-dispatcher/irqfd.c
 create mode 100644 include/uapi/linux/bao.h

diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst
index 7232b3544cec..b0dbc307a9cb 100644
--- a/Documentation/userspace-api/ioctl/ioctl-number.rst
+++ b/Documentation/userspace-api/ioctl/ioctl-number.rst
@@ -349,6 +349,8 @@ Code  Seq#    Include File                                             Comments
                                                                        <mailto:luzmaximilian at gmail.com>
 0xA5  20-2F  linux/surface_aggregator/dtx.h                            Microsoft Surface DTX driver
                                                                        <mailto:luzmaximilian at gmail.com>
+0xA6  all    uapi/linux/bao.h                                          Bao hypervisor
+                                                                       <mailto:info at bao-project.org>
 0xAA  00-3F  linux/uapi/linux/userfaultfd.h
 0xAB  00-1F  linux/nbd.h
 0xAC  00-1F  linux/raw.h
diff --git a/arch/arm/include/asm/bao.h b/arch/arm/include/asm/bao.h
new file mode 100644
index 000000000000..9474ce459987
--- /dev/null
+++ b/arch/arm/include/asm/bao.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Hypercall for Bao Hypervisor on ARM
+ *
+ * Copyright (c) Bao Project and Contributors. All rights reserved.
+ *
+ * Authors:
+ *	Jo?o Peixoto <joaopeixoto at osyx.tech>
+ *	Jos? Martins <jose at osyx.tech>
+ *	David Cerdeira <davidmcerdeira at osyx.tech>
+ */
+
+#ifndef __ASM_ARM_BAO_H
+#define __ASM_ARM_BAO_H
+
+#include <asm/bao.h>
+#include <linux/bao.h>
+#include <linux/arm-smccc.h>
+
+/**
+ * asm_bao_hypercall_remio - Perform a Bao Remote I/O hypercall
+ * @request: Bao VirtIO request
+ *
+ * Executes a Bao Remote I/O hypercall using ARM HVC instruction.
+ *
+ * Return: Filled remio_hypercall_ret structure containing the results.
+ */
+static inline struct remio_hypercall_ret
+asm_bao_hypercall_remio(struct bao_virtio_request *request)
+{
+	register int x0 asm("r0") =
+		ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64,
+				   ARM_SMCCC_OWNER_VENDOR_HYP, REMIO_HC_ID);
+	register u32 x1 asm("r1") = request->dm_id;
+	register u32 x2 asm("r2") = request->addr;
+	register u32 x3 asm("r3") = request->op;
+	register u32 x4 asm("r4") = request->value;
+	register u32 x5 asm("r5") = request->request_id;
+	register u32 x6 asm("r6") = 0;
+
+	struct remio_hypercall_ret ret;
+
+	asm volatile("hvc 0\n\t"
+		     : "=r"(x0), "=r"(x1), "=r"(x2), "=r"(x3), "=r"(x4),
+		       "=r"(x5), "=r"(x6)
+		     : "r"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4), "r"(x5)
+		     : "memory");
+
+	ret.hyp_ret = 0;
+	ret.remio_hyp_ret = x0;
+	ret.pending_requests = x6;
+
+	request->addr = x1;
+	request->op = x2;
+	request->value = x3;
+	request->access_width = x4;
+	request->request_id = x5;
+
+	return ret;
+}
+
+#endif /* __ASM_ARM_BAO_H */
diff --git a/arch/arm64/include/asm/bao.h b/arch/arm64/include/asm/bao.h
new file mode 100644
index 000000000000..047b7204edd4
--- /dev/null
+++ b/arch/arm64/include/asm/bao.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Hypercall for Bao Hypervisor on ARM64
+ *
+ * Copyright (c) Bao Project and Contributors. All rights reserved.
+ *
+ * Authors:
+ *	Jo?o Peixoto <joaopeixoto at osyx.tech>
+ *	Jos? Martins <jose at osyx.tech>
+ *	David Cerdeira <davidmcerdeira at osyx.tech>
+ */
+
+#ifndef __ASM_ARM64_BAO_H
+#define __ASM_ARM64_BAO_H
+
+#include <asm/bao.h>
+#include <linux/bao.h>
+#include <linux/arm-smccc.h>
+
+/**
+ * asm_bao_hypercall_remio - Perform a Bao Remote I/O hypercall
+ * @request: Bao VirtIO request
+ *
+ * Executes a Bao Remote I/O hypercall using ARM64 HVC instruction.
+ *
+ * Return: Filled bao_virtio_request structure containing the results.
+ */
+static inline struct remio_hypercall_ret
+asm_bao_hypercall_remio(struct bao_virtio_request *request)
+{
+	register int x0 asm("x0") =
+		ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64,
+				   ARM_SMCCC_OWNER_VENDOR_HYP, REMIO_HC_ID);
+	register u64 x1 asm("x1") = request->dm_id;
+	register u64 x2 asm("x2") = request->addr;
+	register u64 x3 asm("x3") = request->op;
+	register u64 x4 asm("x4") = request->value;
+	register u64 x5 asm("x5") = request->request_id;
+	register u64 x6 asm("x6") = 0;
+
+	struct remio_hypercall_ret ret;
+
+	asm volatile("hvc 0\n\t"
+		     : "=r"(x0), "=r"(x1), "=r"(x2), "=r"(x3), "=r"(x4),
+		       "=r"(x5), "=r"(x6)
+		     : "r"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4), "r"(x5)
+		     : "memory");
+
+	ret.hyp_ret = 0;
+	ret.remio_hyp_ret = x0;
+	ret.pending_requests = x6;
+
+	request->addr = x1;
+	request->op = x2;
+	request->value = x3;
+	request->access_width = x4;
+	request->request_id = x5;
+
+	return ret;
+}
+
+#endif /* __ASM_ARM64_BAO_H */
diff --git a/arch/riscv/include/asm/bao.h b/arch/riscv/include/asm/bao.h
new file mode 100644
index 000000000000..e2a1bd492a9a
--- /dev/null
+++ b/arch/riscv/include/asm/bao.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Hypercall for Bao Hypervisor on RISC-V
+ *
+ * Copyright (c) Bao Project and Contributors. All rights reserved.
+ *
+ * Authors:
+ *	Jo?o Peixoto <joaopeixoto at osyx.tech>
+ *	Jos? Martins <jose at osyx.tech>
+ *	David Cerdeira <davidmcerdeira at osyx.tech>
+ */
+
+#ifndef __ASM_RISCV_BAO_H
+#define __ASM_RISCV_BAO_H
+
+#include <asm/sbi.h>
+#include <linux/bao.h>
+
+/**
+ * asm_bao_hypercall_remio - Perform a Bao Remote I/O hypercall
+ * @request: Bao VirtIO request
+ *
+ * Executes a Bao hypercall using inline assembly.
+ *
+ * Return: Filled bao_virtio_request structure containing the results.
+ */
+static inline struct remio_hypercall_ret
+asm_bao_hypercall_remio(struct bao_virtio_request *request)
+{
+	struct remio_hypercall_ret ret;
+
+	register uintptr_t a0 asm("a0") = (uintptr_t)(request->dm_id);
+	register uintptr_t a1 asm("a1") = (uintptr_t)(request->addr);
+	register uintptr_t a2 asm("a2") = (uintptr_t)(request->op);
+	register uintptr_t a3 asm("a3") = (uintptr_t)(request->value);
+	register uintptr_t a4 asm("a4") = (uintptr_t)(request->request_id);
+	register uintptr_t a5 asm("a5") = (uintptr_t)(0);
+	register uintptr_t a6 asm("a6") = (uintptr_t)(REMIO_HC_ID);
+	register uintptr_t a7 asm("a7") = (uintptr_t)(0x08000ba0);
+
+	asm volatile("ecall"
+		     : "+r"(a0), "+r"(a1), "+r"(a2), "+r"(a3), "+r"(a4),
+		       "+r"(a5), "+r"(a6), "+r"(a7)
+		     : "r"(a0), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5),
+		       "r"(a6), "r"(a7)
+		     : "memory");
+
+	ret.hyp_ret = a0;
+	ret.remio_hyp_ret = a1;
+	ret.pending_requests = a7;
+
+	request->addr = a2;
+	request->op = a3;
+	request->value = a4;
+	request->access_width = a5;
+	request->request_id = a6;
+
+	return ret;
+}
+
+#endif /* __ASM_RISCV_BAO_H */
diff --git a/drivers/virt/Makefile b/drivers/virt/Makefile
index 623a671f8711..8bffc7ccd29e 100644
--- a/drivers/virt/Makefile
+++ b/drivers/virt/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_NITRO_ENCLAVES)	+= nitro_enclaves/
 obj-$(CONFIG_ACRN_HSM)		+= acrn/
 obj-y				+= coco/
 obj-$(CONFIG_BAO_SHMEM)		+= bao/
+obj-$(CONFIG_BAO_IO_DISPATCHER)	+= bao/
diff --git a/drivers/virt/bao/Kconfig b/drivers/virt/bao/Kconfig
index 4f7929d57475..ab08a20db8c4 100644
--- a/drivers/virt/bao/Kconfig
+++ b/drivers/virt/bao/Kconfig
@@ -1,3 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
 
 source "drivers/virt/bao/ipcshmem/Kconfig"
+
+source "drivers/virt/bao/io-dispatcher/Kconfig"
diff --git a/drivers/virt/bao/Makefile b/drivers/virt/bao/Makefile
index 68f5d3f282c4..c463f04cf206 100644
--- a/drivers/virt/bao/Makefile
+++ b/drivers/virt/bao/Makefile
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
 
 obj-$(CONFIG_BAO_SHMEM) += ipcshmem/
+obj-$(CONFIG_BAO_IO_DISPATCHER) += io-dispatcher/
diff --git a/drivers/virt/bao/io-dispatcher/Kconfig b/drivers/virt/bao/io-dispatcher/Kconfig
new file mode 100644
index 000000000000..fc9226e20790
--- /dev/null
+++ b/drivers/virt/bao/io-dispatcher/Kconfig
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0
+config BAO_IO_DISPATCHER
+	tristate "Bao Hypervisor I/O Dispatcher"
+	select EVENTFD
+
+	help
+	  The Bao I/O Dispatcher is a kernel module for backend Linux VMs
+	  running under the Bao hypervisor. It establishes the connection
+	  between the Remote I/O system (Bao's mechanism for forwarding
+	  I/O requests from frontend VMs to the backend VMs) and the
+	  VirtIO backend device.
+
+	  This provides a unified API to support various VirtIO backends,
+	  allowing Bao guests to perform I/O through the hypervisor
+	  transparently.
+
diff --git a/drivers/virt/bao/io-dispatcher/Makefile b/drivers/virt/bao/io-dispatcher/Makefile
new file mode 100644
index 000000000000..19225f524217
--- /dev/null
+++ b/drivers/virt/bao/io-dispatcher/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_BAO_IO_DISPATCHER) += bao.o
+bao-objs += ioctls.o ioeventfd.o io_client.o io_dispatcher.o irqfd.o dm.o intc.o driver.o
+
diff --git a/drivers/virt/bao/io-dispatcher/bao_drv.h b/drivers/virt/bao/io-dispatcher/bao_drv.h
new file mode 100644
index 000000000000..4abcdf2eae10
--- /dev/null
+++ b/drivers/virt/bao/io-dispatcher/bao_drv.h
@@ -0,0 +1,386 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Provides some definitions for the Bao Hypervisor modules
+ *
+ * Copyright (c) Bao Project and Contributors. All rights reserved.
+ *
+ * Authors:
+ *	Jo?o Peixoto <joaopeixoto at osyx.tech>
+ *	Jos? Martins <jose at osyx.tech>
+ *	David Cerdeira <davidmcerdeira at osyx.tech>
+ */
+
+#ifndef __BAO_DRV_H
+#define __BAO_DRV_H
+
+#include <linux/bao.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/mutex.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/interrupt.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/bitops.h>
+
+#define BAO_IOEVENTFD_FLAG_DATAMATCH BIT(1)
+#define BAO_IOEVENTFD_FLAG_DEASSIGN BIT(2)
+#define BAO_IRQFD_FLAG_DEASSIGN 1U
+#define BAO_IO_CLIENT_DESTROYING 0U
+#define BAO_DM_FLAG_DESTROYING 0U
+#define BAO_DM_FLAG_CLEARING_IOREQ 1U
+
+struct bao_dm;
+struct bao_io_client;
+
+typedef int (*bao_io_client_handler_t)(struct bao_io_client *client,
+				       struct bao_virtio_request *req);
+
+/**
+ * struct bao_io_client - Bao I/O client
+ * @name: Client name
+ * @dm: The DM that the client belongs to
+ * @list: List node for this bao_io_client
+ * @is_control: If this client is the control client
+ * @flags: Flags (BAO_IO_CLIENT_*)
+ * @virtio_requests: List of free I/O requests
+ * @range_list: I/O ranges
+ * @handler: I/O request handler for this client
+ * @thread: Kernel thread executing the handler
+ * @wq: Wait queue used for thread parking
+ * @priv: Private data for the handler
+ */
+struct bao_io_client {
+	char name[BAO_NAME_MAX_LEN];
+	struct bao_dm *dm;
+	struct list_head list;
+	bool is_control;
+	unsigned long flags;
+	struct list_head virtio_requests;
+
+	/* protects virtio_requests list */
+	struct mutex virtio_requests_lock;
+
+	struct list_head range_list;
+
+	/* protects range_list */
+	struct rw_semaphore range_lock;
+
+	bao_io_client_handler_t handler;
+	struct task_struct *thread;
+	wait_queue_head_t wq;
+	void *priv;
+};
+
+/**
+ * struct bao_dm - Bao backend device model (DM)
+ * @list: Entry within global list of all DMs
+ * @info: DM information (id, shmem_addr, shmem_size, irq, fd)
+ * @shmem_base_addr: The base address of the shared memory (only used for unmapping purposes)
+ * @flags: Flags (BAO_IO_DISPATCHER_DM_*)
+ * @ioeventfds: List of all ioeventfds
+ * @ioeventfd_client: Ioeventfd client
+ * @irqfds: List of all irqfds
+ * @irqfd_server: Workqueue responsible for irqfd handling
+ * @io_clients: List of all bao_io_client
+ * @control_client: Control client
+ */
+struct bao_dm {
+	struct list_head list;
+	struct bao_dm_info info;
+	void *shmem_base_addr;
+	unsigned long flags;
+
+	struct list_head ioeventfds;
+
+	/* protects ioeventfds list */
+	struct mutex ioeventfds_lock;
+
+	struct bao_io_client *ioeventfd_client;
+
+	struct list_head irqfds;
+
+	/* protects irqfds list */
+	struct mutex irqfds_lock;
+
+	struct workqueue_struct *irqfd_server;
+
+	/* protects io_clients list */
+	struct rw_semaphore io_clients_lock;
+
+	struct list_head io_clients;
+	struct bao_io_client *control_client;
+};
+
+/**
+ * struct bao_io_range - Represents a range of I/O addresses
+ * @list: List node for linking multiple ranges
+ * @start: Start address of the range
+ * @end: End address of the range (inclusive)
+ */
+struct bao_io_range {
+	struct list_head list;
+	u64 start;
+	u64 end;
+};
+
+/* Global list of all Bao device models */
+extern struct list_head bao_dm_list;
+
+/* Lock protecting access to bao_dm_list */
+extern rwlock_t bao_dm_list_lock;
+
+/**
+ * bao_dm_create - Create a backend device model (DM)
+ * @info: DM information (id, shmem_addr, shmem_size, irq, fd)
+ *
+ * Return: Pointer to the created DM on success, NULL on error.
+ */
+struct bao_dm *bao_dm_create(struct bao_dm_info *info);
+
+/**
+ * bao_dm_destroy - Destroy a backend device model (DM)
+ * @dm: DM to be destroyed
+ */
+void bao_dm_destroy(struct bao_dm *dm);
+
+/**
+ * bao_dm_get_info - Retrieve information of a DM
+ * @info: Structure to be filled; id field must contain the DM ID
+ *
+ * Return: true on success, false on error.
+ */
+bool bao_dm_get_info(struct bao_dm_info *info);
+
+/**
+ * bao_dm_ioctl - Handle DM-related ioctls
+ * @filp: Open file pointer
+ * @cmd: IOCTL command
+ * @ioctl_param: Pointer to IOCTL parameter
+ *
+ * Return: ioctl result code.
+ */
+long bao_dm_ioctl(struct file *filp, unsigned int cmd,
+		  unsigned long ioctl_param);
+
+/**
+ * bao_io_client_create - Create a backend I/O client
+ * @dm: DM this client belongs to
+ * @handler: I/O client handler for requests
+ * @data: Private data passed to the handler
+ * @is_control: True if this is the control client
+ * @name: Name of the I/O client
+ *
+ * Return: Pointer to the created I/O client, or NULL on failure.
+ */
+struct bao_io_client *bao_io_client_create(struct bao_dm *dm,
+					   bao_io_client_handler_t handler,
+					   void *data, bool is_control,
+					   const char *name);
+
+/**
+ * bao_io_clients_destroy - Destroy all I/O clients of a DM
+ * @dm: DM whose I/O clients are to be destroyed
+ */
+void bao_io_clients_destroy(struct bao_dm *dm);
+
+/**
+ * bao_io_client_attach - Attach a thread to an I/O client
+ * @client: I/O client to attach
+ *
+ * The thread will wait for I/O requests on this client.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int bao_io_client_attach(struct bao_io_client *client);
+
+/**
+ * bao_io_client_range_add - Add an I/O range to monitor in a client
+ * @client: I/O client
+ * @start: Start address of the range
+ * @end: End address of the range (inclusive)
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int bao_io_client_range_add(struct bao_io_client *client, u64 start, u64 end);
+
+/**
+ * bao_io_client_range_del - Remove an I/O range from a client
+ * @client: I/O client
+ * @start: Start address of the range
+ * @end: End address of the range (inclusive)
+ */
+void bao_io_client_range_del(struct bao_io_client *client, u64 start, u64 end);
+
+/**
+ * bao_io_client_request - Retrieve the oldest I/O request from a client
+ * @client: I/O client
+ * @req: Pointer to virtio request structure to fill
+ *
+ * Return: 0 on success, negative error code if no request is available.
+ */
+int bao_io_client_request(struct bao_io_client *client,
+			  struct bao_virtio_request *req);
+
+/**
+ * bao_io_client_push_request - Push an I/O request into a client
+ * @client: I/O client
+ * @req: I/O request to push
+ *
+ * Return: true if a request was pushed, false otherwise.
+ */
+bool bao_io_client_push_request(struct bao_io_client *client,
+				struct bao_virtio_request *req);
+
+/**
+ * bao_io_client_pop_request - Pop the oldest I/O request from a client
+ * @client: I/O client
+ * @req:    Buffer to store the popped request
+ *
+ * Return: true if a request was popped, false if the queue was empty.
+ */
+bool bao_io_client_pop_request(struct bao_io_client *client, struct bao_virtio_request *req);
+
+/**
+ * bao_io_client_find - Find the I/O client for a given request
+ * @dm: DM that the I/O request belongs to
+ * @req: I/O request to locate
+ *
+ * Return: Pointer to the I/O client handling the request, or NULL if none found.
+ */
+struct bao_io_client *bao_io_client_find(struct bao_dm *dm,
+					 struct bao_virtio_request *req);
+
+/**
+ * bao_ioeventfd_client_init - Initialize the Ioeventfd client for a DM
+ * @dm: DM that the Ioeventfd client belongs to
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int bao_ioeventfd_client_init(struct bao_dm *dm);
+
+/**
+ * bao_ioeventfd_client_destroy - Destroy the Ioeventfd client for a DM
+ * @dm: DM that the Ioeventfd client belongs to
+ */
+void bao_ioeventfd_client_destroy(struct bao_dm *dm);
+
+/**
+ * bao_ioeventfd_client_config - Configure an Ioeventfd client
+ * @dm: DM that the Ioeventfd client belongs to
+ * @config: Ioeventfd configuration to apply
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int bao_ioeventfd_client_config(struct bao_dm *dm,
+				struct bao_ioeventfd *config);
+
+/**
+ * bao_irqfd_server_init - Initialize the Irqfd server for a DM
+ * @dm: DM that the Irqfd server belongs to
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int bao_irqfd_server_init(struct bao_dm *dm);
+
+/**
+ * bao_irqfd_server_destroy - Destroy the Irqfd server for a DM
+ * @dm: DM that the Irqfd server belongs to
+ */
+void bao_irqfd_server_destroy(struct bao_dm *dm);
+
+/**
+ * bao_irqfd_server_config - Configure an Irqfd server
+ * @dm: DM that the Irqfd server belongs to
+ * @config: Irqfd configuration to apply
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int bao_irqfd_server_config(struct bao_dm *dm, struct bao_irqfd *config);
+
+/**
+ * bao_io_dispatcher_init - Initialize the I/O Dispatcher for a DM
+ * @dm: DM to initialize on the I/O Dispatcher
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int bao_io_dispatcher_init(struct bao_dm *dm);
+
+/**
+ * bao_io_dispatcher_destroy - Destroy the I/O Dispatcher for a DM
+ * @dm: DM to destroy on the I/O Dispatcher
+ */
+void bao_io_dispatcher_destroy(struct bao_dm *dm);
+
+/**
+ * bao_io_dispatcher_setup - Setup the I/O Dispatcher
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int bao_io_dispatcher_setup(void);
+
+/**
+ * bao_io_dispatcher_remove - Remove the I/O Dispatcher
+ */
+void bao_io_dispatcher_remove(void);
+
+/**
+ * bao_dispatch_io - Acquire and dispatch I/O requests from the Bao Hypervisor
+ * @dm: DM whose I/O clients will handle the requests
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int bao_dispatch_io(struct bao_dm *dm);
+
+/**
+ * bao_io_dispatcher_pause - Pause the I/O Dispatcher for a DM
+ * @dm: DM to pause
+ */
+void bao_io_dispatcher_pause(struct bao_dm *dm);
+
+/**
+ * bao_io_dispatcher_resume - Resume the I/O Dispatcher for a DM
+ * @dm: DM to resume
+ */
+void bao_io_dispatcher_resume(struct bao_dm *dm);
+
+/**
+ * bao_intc_register - Register the interrupt controller for a DM
+ * @dm: DM that the interrupt controller belongs to
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int bao_intc_register(struct bao_dm *dm);
+
+/**
+ * bao_intc_unregister - Unregister the interrupt controller for a DM
+ * @dm: DM that the interrupt controller belongs to
+ */
+void bao_intc_unregister(struct bao_dm *dm);
+
+/**
+ * bao_intc_setup_handler - Setup the interrupt controller handler
+ * @handler: Function pointer to the interrupt handler
+ * @dm: DM that the interrupt controller belongs to
+ */
+void bao_intc_setup_handler(void (*handler)(struct bao_dm *dm));
+
+/**
+ * bao_intc_remove_handler - Remove the interrupt controller handler
+ */
+void bao_intc_remove_handler(void);
+
+/**
+ * bao_io_dispatcher_driver_ioctl - Handle I/O Dispatcher ioctls
+ * @filp: Open file pointer
+ * @cmd: IOCTL command
+ * @ioctl_param: Pointer to IOCTL parameter
+ *
+ * Return: ioctl result code.
+ */
+long bao_io_dispatcher_driver_ioctl(struct file *filp, unsigned int cmd,
+				    unsigned long ioctl_param);
+
+#endif /* __BAO_DRV_H */
diff --git a/drivers/virt/bao/io-dispatcher/dm.c b/drivers/virt/bao/io-dispatcher/dm.c
new file mode 100644
index 000000000000..633d9dd206e1
--- /dev/null
+++ b/drivers/virt/bao/io-dispatcher/dm.c
@@ -0,0 +1,330 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Bao Hypervisor Backend Device Model (DM)
+ *
+ * Copyright (c) Bao Project and Contributors. All rights reserved.
+ *
+ * Authors:
+ *	Jo?o Peixoto <joaopeixoto at osyx.tech>
+ *	Jos? Martins <jose at osyx.tech>
+ *	David Cerdeira <davidmcerdeira at osyx.tech>
+ */
+
+#include "bao_drv.h"
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/anon_inodes.h>
+#include <linux/miscdevice.h>
+#include "hypercall.h"
+
+/*
+ * List of all backend device models (DMs)
+ */
+LIST_HEAD(bao_dm_list);
+
+/*
+ * Lock to protect bao_dm_list:
+ * - Read: worker thread dispatching I/O requests
+ * - Write: DM creation via ioctl
+ */
+DEFINE_RWLOCK(bao_dm_list_lock);
+
+static int bao_dm_open(struct inode *inode, struct file *filp)
+{
+	return 0;
+}
+
+static int bao_dm_release(struct inode *inode, struct file *filp)
+{
+	struct bao_dm *dm = filp->private_data;
+
+	if (WARN_ON_ONCE(!dm))
+		return -ENODEV;
+
+	bao_dm_destroy(dm);
+
+	kfree(dm);
+	filp->private_data = NULL;
+
+	return 0;
+}
+
+/**
+ * bao_dm_mmap - mmap backend DM shared memory to userspace
+ * @filp: File pointer for the DM device
+ * @vma: Virtual memory area for mapping
+ *
+ * Maps the previously allocated kernel memory region of the backend
+ * DM into the userspace address space.
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+static int bao_dm_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct bao_dm *dm = filp->private_data;
+	unsigned long vsize, offset;
+	phys_addr_t phys;
+
+	if (WARN_ON_ONCE(!dm))
+		return -ENODEV;
+
+	vsize = vma->vm_end - vma->vm_start;
+	offset = vma->vm_pgoff << PAGE_SHIFT;
+
+	if (!vsize || offset)
+		return -EINVAL;
+
+	if (vsize > dm->info.shmem_size)
+		return -EINVAL;
+
+	phys = dm->info.shmem_addr;
+	if (!PAGE_ALIGNED(phys))
+		return -EINVAL;
+
+	if (remap_pfn_range(vma, vma->vm_start, phys >> PAGE_SHIFT,
+			    vsize, vma->vm_page_prot))
+		return -EFAULT;
+
+	return 0;
+}
+
+/**
+ * bao_dm_llseek - Adjust file offset for backend DM device
+ * @file: File pointer for the DM device
+ * @offset: Offset to seek
+ * @whence: Reference point (SEEK_SET, SEEK_CUR, SEEK_END)
+ *
+ * Adjusts the file position for the backend DM device, allowing
+ * userspace to seek within the shared memory region.
+ *
+ * Return: New file position on success, negative errno on failure
+ */
+static loff_t bao_dm_llseek(struct file *file, loff_t offset, int whence)
+{
+	struct bao_dm *bao = file->private_data;
+	loff_t new_pos;
+
+	if (WARN_ON_ONCE(!bao))
+		return -ENODEV;
+
+	switch (whence) {
+	case SEEK_SET:
+		new_pos = offset;
+		break;
+	case SEEK_CUR:
+		new_pos = file->f_pos + offset;
+		break;
+	case SEEK_END:
+		new_pos = bao->info.shmem_size + offset;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (new_pos < 0 || new_pos > bao->info.shmem_size)
+		return -EINVAL;
+
+	file->f_pos = new_pos;
+	return new_pos;
+}
+
+static const struct file_operations bao_dm_fops = {
+	.owner = THIS_MODULE,
+	.open = bao_dm_open,
+	.release = bao_dm_release,
+	.unlocked_ioctl = bao_dm_ioctl,
+	.llseek = bao_dm_llseek,
+	.mmap = bao_dm_mmap,
+};
+
+struct bao_dm *bao_dm_create(struct bao_dm_info *info)
+{
+	struct bao_dm *dm;
+	char name[BAO_NAME_MAX_LEN];
+
+	if (WARN_ON(!info))
+		return NULL;
+
+	/* Check if a DM with the same ID already exists */
+	read_lock(&bao_dm_list_lock);
+	list_for_each_entry(dm, &bao_dm_list, list) {
+		if (dm->info.id == info->id) {
+			read_unlock(&bao_dm_list_lock);
+			return NULL;
+		}
+	}
+	read_unlock(&bao_dm_list_lock);
+
+	/* Allocate the DM structure */
+	dm = kzalloc(sizeof(*dm), GFP_KERNEL);
+	if (!dm)
+		return NULL;
+
+	INIT_LIST_HEAD(&dm->io_clients);
+	init_rwsem(&dm->io_clients_lock);
+
+	dm->info = *info;
+
+	/* Initialize IO dispatcher */
+	bao_io_dispatcher_init(dm);
+
+	/* Add DM to global list */
+	write_lock_bh(&bao_dm_list_lock);
+	list_add(&dm->list, &bao_dm_list);
+	write_unlock_bh(&bao_dm_list_lock);
+
+	/* Create control client */
+	snprintf(name, sizeof(name), "bao-ioctlc%u", dm->info.id);
+	dm->control_client = bao_io_client_create(dm, NULL, NULL, true, name);
+	if (!dm->control_client) {
+		pr_err("%s: failed to create control client for DM %u\n",
+		       __func__, dm->info.id);
+		goto err_remove_dm;
+	}
+
+	/* Initialize IOEVENTFD client */
+	if (bao_ioeventfd_client_init(dm)) {
+		pr_err("%s: failed to initialize ioeventfd for DM %u\n",
+		       __func__, dm->info.id);
+		goto err_destroy_io_clients;
+	}
+
+	/* Initialize IRQFD server */
+	if (bao_irqfd_server_init(dm)) {
+		pr_err("%s: failed to initialize irqfd for DM %u\n",
+		       __func__, dm->info.id);
+		goto err_destroy_io_clients;
+	}
+
+	/* Map shared memory */
+	dm->shmem_base_addr =
+		memremap(dm->info.shmem_addr, dm->info.shmem_size, MEMREMAP_WB);
+	if (!dm->shmem_base_addr) {
+		pr_err("%s: failed to map memory region for DM %u\n",
+		       __func__, dm->info.id);
+		goto err_destroy_irqfd;
+	}
+
+	return dm;
+
+err_destroy_irqfd:
+	bao_irqfd_server_destroy(dm);
+
+err_destroy_io_clients:
+	bao_io_clients_destroy(dm);
+
+err_remove_dm:
+	write_lock_bh(&bao_dm_list_lock);
+	list_del(&dm->list);
+	write_unlock_bh(&bao_dm_list_lock);
+	kfree(dm);
+
+	return NULL;
+}
+
+void bao_dm_destroy(struct bao_dm *dm)
+{
+	if (WARN_ON_ONCE(!dm))
+		return;
+
+	/* Mark DM as destroying to prevent concurrent access */
+	set_bit(BAO_DM_FLAG_DESTROYING, &dm->flags);
+
+	/* Remove from global DM list */
+	write_lock_bh(&bao_dm_list_lock);
+	list_del_init(&dm->list);
+	write_unlock_bh(&bao_dm_list_lock);
+
+	/* Clear DM info for safety */
+	dm->info.id = 0;
+	dm->info.shmem_addr = 0;
+	dm->info.shmem_size = 0;
+	dm->info.irq = 0;
+
+	/* Unmap shared memory */
+	if (dm->shmem_base_addr)
+		memunmap(dm->shmem_base_addr);
+
+	/* Close the associated file descriptor if any */
+	if (dm->info.fd >= 0)
+		put_unused_fd(dm->info.fd);
+
+	/* Destroy all server/client resources */
+	bao_irqfd_server_destroy(dm);
+	bao_io_clients_destroy(dm);
+	bao_io_dispatcher_destroy(dm);
+
+	/* Clear destroying flag */
+	clear_bit(BAO_DM_FLAG_DESTROYING, &dm->flags);
+
+	/* Free DM structure */
+	kfree(dm);
+}
+
+/**
+ * bao_dm_create_anonymous_inode - Create an anonymous inode for a backend DM
+ * @dm: The backend device model (DM)
+ *
+ * Creates an anonymous inode that exposes the backend DM to userspace.
+ * The frontend DM can use the returned file descriptor to request
+ * services from the backend DM directly.
+ *
+ * Return: File descriptor on success, negative errno on failure
+ */
+static int bao_dm_create_anonymous_inode(struct bao_dm *dm)
+{
+	char name[BAO_NAME_MAX_LEN];
+	struct file *file;
+	int fd;
+
+	if (WARN_ON_ONCE(!dm))
+		return -EINVAL;
+
+	/* Allocate an unused file descriptor */
+	fd = get_unused_fd_flags(O_CLOEXEC);
+	if (fd < 0)
+		return fd;
+
+	/* Create anonymous inode for this DM */
+	snprintf(name, sizeof(name), "bao-dm%u", dm->info.id);
+	file = anon_inode_getfile(name, &bao_dm_fops, dm, O_RDWR);
+	if (IS_ERR(file)) {
+		put_unused_fd(fd);
+		return PTR_ERR(file);
+	}
+
+	/* Install the file descriptor and store in DM */
+	fd_install(fd, file);
+	dm->info.fd = fd;
+
+	return fd;
+}
+
+bool bao_dm_get_info(struct bao_dm_info *info)
+{
+	struct bao_dm *dm;
+	bool found = false;
+
+	if (WARN_ON_ONCE(!info))
+		return false;
+
+	/* Search the global DM list for matching ID */
+	list_for_each_entry(dm, &bao_dm_list, list) {
+		if (dm->info.id == info->id) {
+			info->shmem_addr = dm->info.shmem_addr;
+			info->shmem_size = dm->info.shmem_size;
+			info->irq = dm->info.irq;
+
+			/* Create anonymous inode and store FD */
+			info->fd = bao_dm_create_anonymous_inode(dm);
+
+			found = true;
+			break;
+		}
+	}
+
+	return found;
+}
diff --git a/drivers/virt/bao/io-dispatcher/driver.c b/drivers/virt/bao/io-dispatcher/driver.c
new file mode 100644
index 000000000000..11d73107e8ca
--- /dev/null
+++ b/drivers/virt/bao/io-dispatcher/driver.c
@@ -0,0 +1,348 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Bao Hypervisor I/O Dispatcher Kernel Driver
+ *
+ * Copyright (c) Bao Project and Contributors. All rights reserved.
+ *
+ * Authors:
+ *	Jo?o Peixoto <joaopeixoto at osyx.tech>
+ *	Jos? Martins <jose at osyx.tech>
+ *	David Cerdeira <davidmcerdeira at osyx.tech>
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/of_irq.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/poll.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/mm.h>
+#include "bao_drv.h"
+
+#define DEV_NAME "bao-io-dispatcher"
+
+static dev_t bao_iodispatcher_devt;
+struct class *bao_iodispatcher_cl;
+
+/**
+ * struct bao_iodispatcher_drv - Bao I/O Dispatcher driver
+ * @cdev: Character device for the dispatcher
+ * @dev: Pointer to the device
+ *
+ * Represents the Bao I/O Dispatcher kernel module instance and its
+ * associated character device.
+ */
+struct bao_iodispatcher_drv {
+	struct cdev cdev;
+	struct device *dev;
+};
+
+/**
+ * bao_io_dispatcher_driver_open_fops - Open the Bao I/O Dispatcher device
+ * @inode: Inode representing the character device
+ * @filp: File pointer for the opened device
+ *
+ * Sets the private_data pointer in @filp to the Bao I/O Dispatcher
+ * driver instance and takes a reference to its kobject.
+ *
+ * Return: 0 on success
+ */
+static int bao_io_dispatcher_driver_open_fops(struct inode *inode,
+					      struct file *filp)
+{
+	struct bao_iodispatcher_drv *drv;
+
+	if (WARN_ON_ONCE(!inode || !inode->i_cdev))
+		return -ENODEV;
+
+	drv = container_of(inode->i_cdev, struct bao_iodispatcher_drv, cdev);
+	filp->private_data = drv;
+
+	/* Increment reference count for the underlying device */
+	kobject_get(&drv->dev->kobj);
+
+	return 0;
+}
+
+/**
+ * bao_io_dispatcher_driver_release_fops - Release the Bao I/O Dispatcher device
+ * @inode: Inode representing the character device
+ * @filp: File pointer for the device being released
+ *
+ * Clears the private_data pointer in @filp and drops the reference
+ * to the device's kobject.
+ *
+ * Return: 0 on success
+ */
+static int bao_io_dispatcher_driver_release_fops(struct inode *inode,
+						 struct file *filp)
+{
+	struct bao_iodispatcher_drv *drv;
+
+	if (WARN_ON_ONCE(!inode || !inode->i_cdev))
+		return -ENODEV;
+
+	drv = container_of(inode->i_cdev, struct bao_iodispatcher_drv, cdev);
+
+	/* Clear private data to avoid dangling pointer */
+	filp->private_data = NULL;
+
+	/* Decrement reference count of the underlying device */
+	kobject_put(&drv->dev->kobj);
+
+	return 0;
+}
+
+/**
+ * bao_io_dispatcher_driver_ioctl_fops - File operations ioctl handler
+ * @filp: File pointer for the device
+ * @cmd: IOCTL command
+ * @arg: Argument for the IOCTL command
+ *
+ * Wrapper function to call the main Bao I/O Dispatcher IOCTL handler.
+ *
+ * Return: Result from bao_io_dispatcher_driver_ioctl()
+ */
+static long bao_io_dispatcher_driver_ioctl_fops(struct file *filp,
+						unsigned int cmd,
+						unsigned long arg)
+{
+	return bao_io_dispatcher_driver_ioctl(filp, cmd, arg);
+}
+
+static const struct file_operations bao_io_dispatcher_driver_fops = {
+	.owner = THIS_MODULE,
+	.open = bao_io_dispatcher_driver_open_fops,
+	.release = bao_io_dispatcher_driver_release_fops,
+	.unlocked_ioctl = bao_io_dispatcher_driver_ioctl_fops,
+};
+
+/**
+ * bao_io_dispatcher_driver_register - Register the Bao I/O Dispatcher driver
+ * @pdev: Platform device pointer
+ *
+ * This function sets up the Bao I/O Dispatcher backend for the given platform
+ * device. It allocates the character device, creates device models (DMs) for
+ * each backend, registers interrupts, and creates the
+ * device nodes for userspace access.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int bao_io_dispatcher_driver_register(struct platform_device *pdev)
+{
+	int ret, irq;
+	struct module *owner = THIS_MODULE;
+	struct resource *r;
+	dev_t devt;
+	resource_size_t reg_size;
+	struct bao_iodispatcher_drv *drv;
+	struct bao_dm *dm;
+	struct bao_dm_info dm_info;
+
+	/* Setup the I/O dispatcher hardware */
+	ret = bao_io_dispatcher_setup();
+	if (ret) {
+		dev_err(&pdev->dev, "setup I/O Dispatcher failed!\n");
+		return ret;
+	}
+
+	/* Allocate driver structure */
+	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+	if (!drv) {
+		ret = -ENOMEM;
+		goto err_io_dispatcher;
+	}
+
+	/* Create DM instances */
+	for (int i = 0; i < BAO_IO_MAX_DMS; i++) {
+		r = platform_get_resource(pdev, IORESOURCE_MEM, i);
+		if (!r)
+			break;
+
+		irq = platform_get_irq(pdev, i);
+		if (irq < 0) {
+			dev_err(&pdev->dev,
+				"Failed to read interrupt number at index %d\n",
+				i);
+			ret = irq;
+			goto err_unregister_dms;
+		}
+
+		reg_size = resource_size(r);
+
+		dm_info.id = i;
+		dm_info.shmem_addr = (unsigned long)r->start;
+		dm_info.shmem_size = (unsigned long)reg_size;
+		dm_info.irq = irq;
+		dm_info.fd = 0;
+
+		dm = bao_dm_create(&dm_info);
+		if (!dm) {
+			dev_err(&pdev->dev,
+				"failed to create Bao DM %d\n", i);
+			ret = -ENOMEM;
+			goto err_unregister_dms;
+		}
+
+		ret = bao_intc_register(dm);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to register interrupt %d\n", irq);
+			goto err_unregister_dms;
+		}
+	}
+
+	/* Initialize character device */
+	cdev_init(&drv->cdev, &bao_io_dispatcher_driver_fops);
+	drv->cdev.owner = owner;
+
+	devt = MKDEV(MAJOR(bao_iodispatcher_devt), 0);
+	ret = cdev_add(&drv->cdev, devt, 1);
+	if (ret)
+		goto err_unregister_irqs;
+
+	/* Create device node */
+	drv->dev = device_create(bao_iodispatcher_cl, &pdev->dev, devt, drv, DEV_NAME);
+	if (IS_ERR(drv->dev)) {
+		ret = PTR_ERR(drv->dev);
+		goto err_cdev;
+	}
+
+	dev_set_drvdata(drv->dev, drv);
+	return 0;
+
+err_cdev:
+	cdev_del(&drv->cdev);
+
+err_unregister_irqs:
+	list_for_each_entry(dm, &bao_dm_list, list)
+		bao_intc_unregister(dm);
+
+err_unregister_dms:
+	list_for_each_entry(dm, &bao_dm_list, list)
+		bao_dm_destroy(dm);
+
+err_io_dispatcher:
+	bao_io_dispatcher_remove();
+	dev_err(&pdev->dev, "failed initialization\n");
+	return ret;
+}
+
+/**
+ * bao_io_dispatcher_driver_unregister - Unregister the Bao I/O Dispatcher driver
+ * @pdev: Platform device pointer
+ *
+ * This function tears down the Bao I/O Dispatcher backend for the given
+ * platform device. It removes the dispatcher, destroys all backend
+ * device models (DMs), and unregisters their associated interrupts.
+ */
+static void bao_io_dispatcher_driver_unregister(struct platform_device *pdev)
+{
+	struct bao_dm *dm, *tmp;
+
+	/* Remove I/O dispatcher hardware */
+	bao_io_dispatcher_remove();
+
+	/* Destroy all DM instances safely */
+	list_for_each_entry_safe(dm, tmp, &bao_dm_list, list) {
+		/* Remove DM from list and free resources */
+		bao_dm_destroy(dm);
+
+		/* Unregister associated interrupts */
+		bao_intc_unregister(dm);
+	}
+}
+
+static const struct of_device_id bao_io_dispatcher_driver_dt_ids[] = {
+	{ .compatible = "bao,io-dispatcher" },
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, bao_io_dispatcher_driver_dt_ids);
+
+static struct platform_driver bao_io_dispatcher_driver = {
+	.probe = bao_io_dispatcher_driver_register,
+	.remove = bao_io_dispatcher_driver_unregister,
+	.driver = {
+		   .name = "bao-io-dispatcher",
+		   .of_match_table =
+		   of_match_ptr(bao_io_dispatcher_driver_dt_ids),
+		   .owner = THIS_MODULE,
+		    },
+};
+
+/**
+ * bao_io_dispatcher_driver_init - Module initialization for Bao I/O Dispatcher
+ *
+ * Allocates the character device region, creates the device class, and
+ * registers the platform driver for the Bao I/O Dispatcher.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+static int __init bao_io_dispatcher_driver_init(void)
+{
+	int ret;
+
+	/* Create device class */
+	bao_iodispatcher_cl = class_create(DEV_NAME);
+	if (IS_ERR(bao_iodispatcher_cl)) {
+		ret = PTR_ERR(bao_iodispatcher_cl);
+		pr_err("unable to create class %s\n", DEV_NAME);
+		return ret;
+	}
+
+	/* Allocate character device numbers */
+	ret = alloc_chrdev_region(&bao_iodispatcher_devt, 0, BAO_IO_MAX_DMS, DEV_NAME);
+	if (ret < 0) {
+		pr_err("unable to allocate chrdev region for %s\n", DEV_NAME);
+		class_destroy(bao_iodispatcher_cl);
+		return ret;
+	}
+
+	/* Register the platform driver */
+	ret = platform_driver_register(&bao_io_dispatcher_driver);
+	if (ret < 0) {
+		pr_err("unable to register platform driver for %s\n", DEV_NAME);
+		unregister_chrdev_region(bao_iodispatcher_devt, BAO_IO_MAX_DMS);
+		class_destroy(bao_iodispatcher_cl);
+	}
+
+	return ret;
+}
+
+/**
+ * bao_io_dispatcher_driver_exit - Module cleanup for Bao I/O Dispatcher
+ *
+ * Unregisters the platform driver, frees the character device region, and
+ * destroys the device class.
+ */
+static void __exit bao_io_dispatcher_driver_exit(void)
+{
+	/* Unregister the platform driver */
+	platform_driver_unregister(&bao_io_dispatcher_driver);
+
+	/* Release character device numbers */
+	unregister_chrdev_region(bao_iodispatcher_devt, BAO_IO_MAX_DMS);
+
+	/* Destroy the device class */
+	class_destroy(bao_iodispatcher_cl);
+}
+
+module_init(bao_io_dispatcher_driver_init);
+module_exit(bao_io_dispatcher_driver_exit);
+
+MODULE_AUTHOR("Jo?o Peixoto <joaopeixoto at osyx.tech>");
+MODULE_AUTHOR("David Cerdeira <davidmcerdeira at osyx.tech>");
+MODULE_AUTHOR("Jos? Martins <jose at osyx.tech>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Bao Hypervisor I/O Dispatcher Kernel Driver");
diff --git a/drivers/virt/bao/io-dispatcher/hypercall.h b/drivers/virt/bao/io-dispatcher/hypercall.h
new file mode 100644
index 000000000000..49b58075558a
--- /dev/null
+++ b/drivers/virt/bao/io-dispatcher/hypercall.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Hypercall API for Bao Hypervisor
+ *
+ * Copyright (c) Bao Project and Contributors. All rights reserved.
+ *
+ * Authors:
+ *	Jo?o Peixoto <joaopeixoto at osyx.tech>
+ *	Jos? Martins <jose at osyx.tech>
+ *	David Cerdeira <davidmcerdeira at osyx.tech>
+ */
+
+#ifndef __BAO_HYPERCALL_H
+#define __BAO_HYPERCALL_H
+
+#include <asm/bao.h>
+#include <linux/bao.h>
+
+/**
+ * bao_hypercall_remio() - Performs a Remote I/O Hypercall
+ * @request:	Bao VirtIO request
+ *
+ * @return:	The VirtIO request structure
+ */
+static inline struct remio_hypercall_ret bao_hypercall_remio(struct bao_virtio_request *request)
+{
+	return asm_bao_hypercall_remio(request);
+}
+
+#endif /* __BAO_HYPERCALL_H */
diff --git a/drivers/virt/bao/io-dispatcher/intc.c b/drivers/virt/bao/io-dispatcher/intc.c
new file mode 100644
index 000000000000..61c0248c0a8e
--- /dev/null
+++ b/drivers/virt/bao/io-dispatcher/intc.c
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Bao Hypervisor I/O Dispatcher Interrupt Controller
+ *
+ * Copyright (c) Bao Project and Contributors. All rights reserved.
+ *
+ * Authors:
+ *	Jo?o Peixoto <joaopeixoto at osyx.tech>
+ *	Jos? Martins <jose at osyx.tech>
+ *	David Cerdeira <davidmcerdeira at osyx.tech>
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/of_irq.h>
+#include "bao_drv.h"
+
+/* Top-level handler registered by the Bao interrupt controller */
+static void (*bao_intc_handler)(struct bao_dm *dm);
+
+/**
+ * bao_interrupt_handler - Top-level interrupt handler for Bao DM
+ * @irq: Interrupt number
+ * @dev: Pointer to the Bao device model (struct bao_dm)
+ *
+ * Invokes the registered Bao interrupt controller handler, if any.
+ */
+static irqreturn_t bao_interrupt_handler(int irq, void *dev)
+{
+	struct bao_dm *dm = (struct bao_dm *)dev;
+
+	if (bao_intc_handler)
+		bao_intc_handler(dm);
+
+	return IRQ_HANDLED;
+}
+
+void bao_intc_setup_handler(void (*handler)(struct bao_dm *dm))
+{
+	bao_intc_handler = handler;
+}
+
+void bao_intc_remove_handler(void)
+{
+	bao_intc_handler = NULL;
+}
+
+int bao_intc_register(struct bao_dm *dm)
+{
+	char name[BAO_NAME_MAX_LEN];
+
+	if (WARN_ON_ONCE(!dm))
+		return -EINVAL;
+
+	scnprintf(name, sizeof(name), "bao-iodintc%d", dm->info.id);
+
+	return request_irq(dm->info.irq, bao_interrupt_handler, 0, name, dm);
+}
+
+void bao_intc_unregister(struct bao_dm *dm)
+{
+	if (WARN_ON_ONCE(!dm))
+		return;
+
+	free_irq(dm->info.irq, dm);
+}
diff --git a/drivers/virt/bao/io-dispatcher/io_client.c b/drivers/virt/bao/io-dispatcher/io_client.c
new file mode 100644
index 000000000000..ab7fb46c5e6a
--- /dev/null
+++ b/drivers/virt/bao/io-dispatcher/io_client.c
@@ -0,0 +1,435 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Bao Hypervisor I/O Client
+ *
+ * Copyright (c) Bao Project and Contributors. All rights reserved.
+ *
+ * Authors:
+ *	Jo?o Peixoto <joaopeixoto at osyx.tech>
+ *	Jos? Martins <jose at osyx.tech>
+ *	David Cerdeira <davidmcerdeira at osyx.tech>
+ */
+
+#include "bao_drv.h"
+#include "hypercall.h"
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/io.h>
+
+/**
+ * struct bao_io_request - Bao I/O request structure
+ * @list: List node linking all requests
+ * @virtio_request: The VirtIO I/O request payload
+ *
+ * Represents a single I/O request for a Bao I/O client.
+ */
+struct bao_io_request {
+	struct list_head list;
+	struct bao_virtio_request virtio_request;
+};
+
+/**
+ * bao_io_client_has_pending_requests - Check if an I/O client has pending requests
+ * @client: The bao_io_client to check
+ *
+ * Return true if there are pending VirtIO requests.
+ */
+static inline bool
+bao_io_client_has_pending_requests(struct bao_io_client *client)
+{
+	if (WARN_ON_ONCE(!client))
+		return false;
+
+	return !list_empty(&client->virtio_requests);
+}
+
+/**
+ * bao_io_client_is_destroying - Check if an I/O client is being destroyed
+ * @client: The bao_io_client to check
+ *
+ * Return true if the client is in the process of being destroyed.
+ */
+static inline bool bao_io_client_is_destroying(struct bao_io_client *client)
+{
+	if (WARN_ON_ONCE(!client))
+		return true;
+
+	return test_bit(BAO_IO_CLIENT_DESTROYING, &client->flags);
+}
+
+bool bao_io_client_push_request(struct bao_io_client *client,
+				struct bao_virtio_request *req)
+{
+	struct bao_io_request *io_req;
+
+	if (WARN_ON_ONCE(!client || !req))
+		return false;
+
+	io_req = kzalloc(sizeof(*io_req), GFP_KERNEL);
+	if (!io_req)
+		return false;
+
+	io_req->virtio_request = *req;
+
+	mutex_lock(&client->virtio_requests_lock);
+	list_add_tail(&io_req->list, &client->virtio_requests);
+	mutex_unlock(&client->virtio_requests_lock);
+
+	return true;
+}
+
+bool bao_io_client_pop_request(struct bao_io_client *client, struct bao_virtio_request *ret)
+{
+	struct bao_io_request *req;
+
+	if (WARN_ON_ONCE(!client || !ret))
+		return false;
+
+	mutex_lock(&client->virtio_requests_lock);
+
+	/* Get the first request or NULL if list is empty */
+	req = list_first_entry_or_null(&client->virtio_requests,
+				       struct bao_io_request, list);
+	if (!req) {
+		mutex_unlock(&client->virtio_requests_lock);
+		return false;
+	}
+
+	/* Remove from list and copy the virtio request */
+	list_del(&req->list);
+	*ret = req->virtio_request;
+
+	mutex_unlock(&client->virtio_requests_lock);
+
+	/* Free the allocated request */
+	kfree(req);
+
+	return true;
+}
+
+/**
+ * bao_io_client_destroy - Destroy an I/O client
+ * @client: The bao_io_client to destroy
+ *
+ * Stops the client's thread if needed, frees all I/O ranges, removes
+ * the client from its DM lists, and releases associated resources.
+ */
+static void bao_io_client_destroy(struct bao_io_client *client)
+{
+	struct bao_io_client *range, *next;
+	struct bao_dm *dm;
+
+	if (WARN_ON_ONCE(!client))
+		return;
+
+	dm = client->dm;
+
+	/* Pause the IO dispatcher to avoid races */
+	bao_io_dispatcher_pause(dm);
+
+	/* Mark client as destroying */
+	set_bit(BAO_IO_CLIENT_DESTROYING, &client->flags);
+
+	/* Stop client-specific resources */
+	if (client->is_control) {
+		wake_up_interruptible(&client->wq);
+	} else {
+		/* Stop eventfd client and associated thread */
+		bao_ioeventfd_client_destroy(dm);
+		if (client->thread)
+			kthread_stop(client->thread);
+	}
+
+	/* Free range list safely */
+	down_write(&client->range_lock);
+	list_for_each_entry_safe(range, next, &client->range_list, list) {
+		list_del(&range->list);
+		kfree(range);
+	}
+	up_write(&client->range_lock);
+
+	/* Remove client from DM */
+	down_write(&dm->io_clients_lock);
+	if (client->is_control)
+		dm->control_client = NULL;
+	else
+		dm->ioeventfd_client = NULL;
+
+	list_del(&client->list);
+	up_write(&dm->io_clients_lock);
+
+	/* Resume the IO dispatcher */
+	bao_io_dispatcher_resume(dm);
+
+	/* Free the client structure */
+	kfree(client);
+}
+
+void bao_io_clients_destroy(struct bao_dm *dm)
+{
+	struct bao_io_client *client, *next;
+
+	if (WARN_ON_ONCE(!dm))
+		return;
+
+	list_for_each_entry_safe(client, next, &dm->io_clients, list) {
+		bao_io_client_destroy(client);
+	}
+}
+
+int bao_io_client_attach(struct bao_io_client *client)
+{
+	if (WARN_ON_ONCE(!client))
+		return -EINVAL;
+
+	if (client->is_control) {
+		/*
+		 * In the Control client, a user space thread waits on the waitqueue.
+		 * The thread should wait until:
+		 * - There are pending I/O requests to be processed
+		 * - The I/O client is going to be destroyed
+		 */
+		wait_event_interruptible(client->wq,
+					 bao_io_client_has_pending_requests(client) ||
+				bao_io_client_is_destroying(client));
+		if (bao_io_client_is_destroying(client))
+			return -EPERM;
+	} else {
+		/*
+		 * In the non-control client (e.g., Ioeventfd Client), a kernel space
+		 * thread waits on the waitqueue.
+		 * The thread should wait until:
+		 * - There are pending I/O requests to be processed
+		 * - The I/O client is going to be destroyed
+		 * - The kernel thread is going to be stopped
+		 */
+		wait_event_interruptible(client->wq,
+					 bao_io_client_has_pending_requests(client) ||
+				bao_io_client_is_destroying(client) ||
+				kthread_should_stop());
+		if (bao_io_client_is_destroying(client) ||
+		    kthread_should_stop()) {
+			if (kthread_should_stop())
+				bao_io_client_destroy(client);
+			return -EPERM;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * bao_io_client_kernel_thread - Thread for processing a kernel I/O client
+ * @data: Pointer to the bao_io_client structure
+ *
+ * Return: 0 on completion
+ */
+static int bao_io_client_kernel_thread(void *data)
+{
+	struct bao_io_client *client = data;
+	struct bao_virtio_request req;
+	struct remio_hypercall_ret hret;
+	bool stop = false;
+	int ret;
+
+	if (WARN_ON_ONCE(!client))
+		return -EINVAL;
+
+	while (!stop && !kthread_should_stop()) {
+		/* Attach client and wait for pending requests or destruction */
+		ret = bao_io_client_attach(client);
+		if (ret < 0) {
+			stop = true;
+			break;
+		}
+
+		/* Process all pending requests */
+		while (bao_io_client_has_pending_requests(client) && !stop) {
+			if (!bao_io_client_pop_request(client, &req)) {
+				pr_err("%s: failed to pop I/O request\n", __func__);
+				stop = true;
+				break;
+			}
+
+			/* Invoke the client's handler */
+			ret = client->handler(client, &req);
+			if (ret < 0) {
+				pr_warn("%s: client handler returned %d\n", __func__, ret);
+				break;
+			}
+
+			/* Perform hypercall */
+			hret = bao_hypercall_remio(&req);
+			if (hret.hyp_ret || hret.remio_hyp_ret) {
+				pr_err("%s: hypercall failed: hyp_ret=%lld, remio_hyp_ret=%lld\n",
+				       __func__, hret.hyp_ret, hret.remio_hyp_ret);
+				stop = true;
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
+struct bao_io_client *bao_io_client_create(struct bao_dm *dm,
+					   bao_io_client_handler_t handler,
+					   void *data, bool is_control,
+					   const char *name)
+{
+	struct bao_io_client *client;
+
+	if (WARN_ON_ONCE(!dm || !name))
+		return NULL;
+
+	if (!handler && !is_control)
+		return NULL;
+
+	client = kzalloc(sizeof(*client), GFP_KERNEL);
+	if (!client)
+		return NULL;
+
+	/* Initialize client fields */
+	client->handler = handler;
+	client->dm = dm;
+	client->priv = data;
+	client->is_control = is_control;
+	if (name)
+		strscpy(client->name, name, sizeof(client->name));
+
+	INIT_LIST_HEAD(&client->virtio_requests);
+	init_rwsem(&client->range_lock);
+	INIT_LIST_HEAD(&client->range_list);
+	init_waitqueue_head(&client->wq);
+
+	/* Start kernel thread if handler is provided */
+	if (client->handler) {
+		client->thread = kthread_run(bao_io_client_kernel_thread,
+					     client, "%s-kthread",
+					     client->name);
+		if (IS_ERR(client->thread)) {
+			kfree(client);
+			return NULL;
+		}
+	}
+
+	/* Add client to DM safely */
+	down_write(&dm->io_clients_lock);
+	if (is_control)
+		dm->control_client = client;
+	else
+		dm->ioeventfd_client = client;
+
+	list_add(&client->list, &dm->io_clients);
+	up_write(&dm->io_clients_lock);
+
+	/* Process any pending requests for control client */
+	if (is_control) {
+		while (bao_dispatch_io(dm) > 0)
+			;
+	}
+
+	return client;
+}
+
+int bao_io_client_request(struct bao_io_client *client,
+			  struct bao_virtio_request *req)
+{
+	if (WARN_ON_ONCE(!client))
+		return -EINVAL;
+
+	if (!bao_io_client_pop_request(client, req))
+		return -EFAULT;
+
+	return 0;
+}
+
+int bao_io_client_range_add(struct bao_io_client *client, u64 start, u64 end)
+{
+	struct bao_io_range *range;
+
+	if (WARN_ON_ONCE(!client))
+		return -EINVAL;
+
+	if (end < start)
+		return -EINVAL;
+
+	range = kzalloc(sizeof(*range), GFP_KERNEL);
+	if (!range)
+		return -ENOMEM;
+
+	range->start = start;
+	range->end = end;
+
+	/* Add the range to the client's list safely */
+	down_write(&client->range_lock);
+	list_add(&range->list, &client->range_list);
+	up_write(&client->range_lock);
+
+	return 0;
+}
+
+void bao_io_client_range_del(struct bao_io_client *client, u64 start, u64 end)
+{
+	struct bao_io_range *range, *tmp;
+
+	if (WARN_ON_ONCE(!client))
+		return;
+
+	down_write(&client->range_lock);
+	list_for_each_entry_safe(range, tmp, &client->range_list, list) {
+		if (range->start == start && range->end == end) {
+			list_del(&range->list);
+			kfree(range);
+			break;
+		}
+	}
+	up_write(&client->range_lock);
+}
+
+/**
+ * bao_io_request_in_range - Check if the I/O request is in the range
+ * @range: The I/O request range
+ * @req: The I/O request to be checked
+ *
+ * @return True if the I/O request is in the range, False otherwise
+ */
+static bool bao_io_request_in_range(struct bao_io_range *range,
+				    struct bao_virtio_request *req)
+{
+	if (WARN_ON_ONCE(!range || !req))
+		return false;
+
+	if (req->addr >= range->start &&
+	    (req->addr + req->access_width - 1) <= range->end)
+		return true;
+
+	return false;
+}
+
+struct bao_io_client *bao_io_client_find(struct bao_dm *dm,
+					 struct bao_virtio_request *req)
+{
+	struct bao_io_client *client, *found = NULL;
+	struct bao_io_range *range;
+
+	if (WARN_ON_ONCE(!dm || !req))
+		return NULL;
+
+	list_for_each_entry(client, &dm->io_clients, list) {
+		down_read(&client->range_lock);
+		list_for_each_entry(range, &client->range_list, list) {
+			if (bao_io_request_in_range(range, req)) {
+				found = client;
+				break;
+			}
+		}
+		up_read(&client->range_lock);
+
+		if (found)
+			break;
+	}
+
+	/* Fallback to control client if no matching client found */
+	return found ? found : dm->control_client;
+}
diff --git a/drivers/virt/bao/io-dispatcher/io_dispatcher.c b/drivers/virt/bao/io-dispatcher/io_dispatcher.c
new file mode 100644
index 000000000000..a7aa768f98ca
--- /dev/null
+++ b/drivers/virt/bao/io-dispatcher/io_dispatcher.c
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Bao Hypervisor I/O Dispatcher
+ *
+ * Copyright (c) Bao Project and Contributors. All rights reserved.
+ *
+ * Authors:
+ *	Jo?o Peixoto <joaopeixoto at osyx.tech>
+ *	Jos? Martins <jose at osyx.tech>
+ *	David Cerdeira <davidmcerdeira at osyx.tech>
+ */
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kthread.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/eventfd.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+
+#include <linux/bao.h>
+#include "bao_drv.h"
+#include "hypercall.h"
+
+/**
+ * struct bao_io_dispatcher_work - Work item for I/O dispatching
+ * @work: Work struct for scheduling on workqueue
+ * @dm: Pointer to the associated Bao device model
+ *
+ * Represents a single work item that dispatches I/O requests
+ * for a specific Bao device model.
+ */
+struct bao_io_dispatcher_work {
+	struct work_struct work;
+	struct bao_dm *dm;
+};
+
+/* Array of I/O dispatcher work items, one per Bao DM */
+static struct bao_io_dispatcher_work io_dispatcher_work[BAO_IO_MAX_DMS];
+
+/* Workqueues dedicated to dispatching I/O requests for each Bao DM */
+static struct workqueue_struct *bao_io_dispatcher_wq[BAO_IO_MAX_DMS];
+
+void bao_io_dispatcher_destroy(struct bao_dm *dm)
+{
+	if (WARN_ON_ONCE(!dm))
+		return;
+
+	if (bao_io_dispatcher_wq[dm->info.id]) {
+		/* Pause dispatching to prevent races */
+		bao_io_dispatcher_pause(dm);
+
+		/* Destroy the workqueue */
+		destroy_workqueue(bao_io_dispatcher_wq[dm->info.id]);
+		bao_io_dispatcher_wq[dm->info.id] = NULL;
+
+		/* Remove the registered interrupt handler */
+		bao_intc_remove_handler();
+	}
+}
+
+int bao_dispatch_io(struct bao_dm *dm)
+{
+	struct bao_io_client *client;
+	struct bao_virtio_request req;
+	struct remio_hypercall_ret ret;
+
+	if (WARN_ON_ONCE(!dm))
+		return -EINVAL;
+
+	/* Prepare request for hypercall */
+	req.dm_id = dm->info.id;
+	req.op = BAO_IO_ASK;
+	req.addr = 0;
+	req.value = 0;
+	req.request_id = 0;
+
+	/* Perform hypercall to retrieve I/O request */
+	ret = bao_hypercall_remio(&req);
+	if (ret.hyp_ret || ret.remio_hyp_ret)
+		return -EFAULT;
+
+	/* Find the appropriate client for this request */
+	down_read(&dm->io_clients_lock);
+	client = bao_io_client_find(dm, &req);
+	if (!client) {
+		up_read(&dm->io_clients_lock);
+		return -EEXIST;
+	}
+
+	/* Push request to client's queue */
+	if (!bao_io_client_push_request(client, &req)) {
+		up_read(&dm->io_clients_lock);
+		return -EINVAL;
+	}
+
+	/* Wake up the client thread if waiting */
+	wake_up_interruptible(&client->wq);
+	up_read(&dm->io_clients_lock);
+
+	/* Return the number of pending requests left to process */
+	return ret.pending_requests;
+}
+
+/**
+ * io_dispatcher - Workqueue handler for dispatching I/O
+ * @work: Work struct representing this dispatch operation
+ *
+ * Handles all pending I/O requests for the associated Bao DM.
+ * Executed in process context by the workqueue.
+ */
+static void io_dispatcher(struct work_struct *work)
+{
+	struct bao_io_dispatcher_work *bao_dm_work;
+	struct bao_dm *dm;
+
+	if (WARN_ON_ONCE(!work))
+		return;
+
+	bao_dm_work = container_of(work, struct bao_io_dispatcher_work, work);
+	dm = bao_dm_work->dm;
+
+	if (WARN_ON_ONCE(!dm))
+		return;
+
+	/*
+	 * Dispatch I/O requests for the device model
+	 * until there are no more pending requests.
+	 */
+	while (bao_dispatch_io(dm) > 0)
+		cpu_relax();
+}
+
+/**
+ * io_dispatcher_intc_handler - Interrupt handler for I/O requests
+ * @dm: Bao device model that triggered the interrupt
+ *
+ * Invoked by the interrupt controller when a new I/O request is available.
+ * Queues the corresponding work item onto the I/O dispatcher workqueue
+ * for processing in process context.
+ */
+static void io_dispatcher_intc_handler(struct bao_dm *dm)
+{
+	if (WARN_ON_ONCE(!dm || !bao_io_dispatcher_wq[dm->info.id]))
+		return;
+
+	queue_work(bao_io_dispatcher_wq[dm->info.id],
+		   &io_dispatcher_work[dm->info.id].work);
+}
+
+void bao_io_dispatcher_pause(struct bao_dm *dm)
+{
+	if (WARN_ON_ONCE(!dm || !bao_io_dispatcher_wq[dm->info.id]))
+		return;
+
+	/* Remove the interrupt handler to prevent new work */
+	bao_intc_remove_handler();
+
+	/* Drain any pending work to ensure no tasks are running */
+	drain_workqueue(bao_io_dispatcher_wq[dm->info.id]);
+}
+
+void bao_io_dispatcher_resume(struct bao_dm *dm)
+{
+	if (WARN_ON_ONCE(!dm || !bao_io_dispatcher_wq[dm->info.id]))
+		return;
+
+	/* Reinstall the interrupt handler */
+	bao_intc_setup_handler(io_dispatcher_intc_handler);
+
+	/* Queue a work item to resume dispatching */
+	queue_work(bao_io_dispatcher_wq[dm->info.id],
+		   &io_dispatcher_work[dm->info.id].work);
+}
+
+int bao_io_dispatcher_init(struct bao_dm *dm)
+{
+	char name[BAO_NAME_MAX_LEN];
+
+	if (WARN_ON_ONCE(!dm))
+		return -EINVAL;
+
+	snprintf(name, sizeof(name), "bao-iodwq%u", dm->info.id);
+
+	bao_io_dispatcher_wq[dm->info.id] =
+		alloc_workqueue(name, WQ_HIGHPRI | WQ_MEM_RECLAIM, 1);
+	if (!bao_io_dispatcher_wq[dm->info.id])
+		return -ENOMEM;
+
+	io_dispatcher_work[dm->info.id].dm = dm;
+	INIT_WORK(&io_dispatcher_work[dm->info.id].work, io_dispatcher);
+
+	/* Setup interrupt handler for this dispatcher */
+	bao_intc_setup_handler(io_dispatcher_intc_handler);
+
+	return 0;
+}
+
+int bao_io_dispatcher_setup(void)
+{
+	return 0;
+}
+
+void bao_io_dispatcher_remove(void)
+{
+}
diff --git a/drivers/virt/bao/io-dispatcher/ioctls.c b/drivers/virt/bao/io-dispatcher/ioctls.c
new file mode 100644
index 000000000000..77a177800882
--- /dev/null
+++ b/drivers/virt/bao/io-dispatcher/ioctls.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Bao Hypervisor IOCTLs Handler for the I/O Dispatcher kernel module
+ *
+ * Copyright (c) Bao Project and Contributors. All rights reserved.
+ *
+ * Authors:
+ *	Jo?o Peixoto <joaopeixoto at osyx.tech>
+ *	Jos? Martins <jose at osyx.tech>
+ *	David Cerdeira <davidmcerdeira at osyx.tech>
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/file.h>
+#include <linux/cpu.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/anon_inodes.h>
+#include <linux/bao.h>
+#include "bao_drv.h"
+#include "hypercall.h"
+
+long bao_io_dispatcher_driver_ioctl(struct file *filp, unsigned int cmd,
+				    unsigned long arg)
+{
+	struct bao_dm_info *info;
+
+	switch (cmd) {
+	case BAO_IOCTL_DM_GET_INFO:
+		info = memdup_user((void __user *)arg, sizeof(*info));
+		if (IS_ERR(info))
+			return PTR_ERR(info);
+
+		if (!bao_dm_get_info(info)) {
+			kfree(info);
+			return -ENOENT;
+		}
+
+		if (copy_to_user((void __user *)arg, info, sizeof(*info))) {
+			kfree(info);
+			return -EFAULT;
+		}
+
+		kfree(info);
+		return 0;
+
+	default:
+		return -ENOTTY;
+	}
+}
+
+long bao_dm_ioctl(struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	struct bao_dm *dm = filp->private_data;
+	int rc;
+
+	if (WARN_ON_ONCE(!dm))
+		return -ENODEV;
+
+	switch (cmd) {
+	case BAO_IOCTL_IO_CLIENT_ATTACH: {
+		struct bao_virtio_request *req;
+
+		req = memdup_user((void __user *)arg, sizeof(*req));
+		if (IS_ERR(req)) {
+			rc = PTR_ERR(req);
+			break;
+		}
+
+		if (!dm->control_client) {
+			rc = -ENOENT;
+			goto out_free;
+		}
+
+		rc = bao_io_client_attach(dm->control_client);
+		if (rc)
+			goto out_free;
+
+		rc = bao_io_client_request(dm->control_client, req);
+		if (rc)
+			goto out_free;
+
+		if (copy_to_user((void __user *)arg, req, sizeof(*req))) {
+			rc = -EFAULT;
+			goto out_free;
+		}
+
+		rc = 0;
+
+out_free:
+	kfree(req);
+	break;
+	}
+	case BAO_IOCTL_IO_REQUEST_COMPLETE: {
+		struct bao_virtio_request *req;
+		struct remio_hypercall_ret hret;
+
+		req = memdup_user((void __user *)arg, sizeof(*req));
+		if (IS_ERR(req)) {
+			rc = PTR_ERR(req);
+			break;
+		}
+
+		hret = bao_hypercall_remio(req);
+		kfree(req);
+
+		/* Translate hypercall result to proper errno */
+		if (hret.hyp_ret || hret.remio_hyp_ret)
+			rc = -EIO;
+		else
+			rc = 0;
+
+		break;
+	}
+	case BAO_IOCTL_IOEVENTFD: {
+		struct bao_ioeventfd ioeventfd;
+
+		if (copy_from_user(&ioeventfd, (void __user *)arg,
+				   sizeof(struct bao_ioeventfd)))
+			return -EFAULT;
+
+		rc = bao_ioeventfd_client_config(dm, &ioeventfd);
+		break;
+	}
+	case BAO_IOCTL_IRQFD: {
+		struct bao_irqfd irqfd;
+
+		if (copy_from_user(&irqfd, (void __user *)arg,
+				   sizeof(struct bao_irqfd)))
+			return -EFAULT;
+
+		rc = bao_irqfd_server_config(dm, &irqfd);
+		break;
+	}
+	default:
+		rc = -ENOTTY;
+		break;
+	}
+
+	return rc;
+}
diff --git a/drivers/virt/bao/io-dispatcher/ioeventfd.c b/drivers/virt/bao/io-dispatcher/ioeventfd.c
new file mode 100644
index 000000000000..8eb92193e31b
--- /dev/null
+++ b/drivers/virt/bao/io-dispatcher/ioeventfd.c
@@ -0,0 +1,336 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Bao Hypervisor Ioeventfd Client
+ *
+ * Copyright (c) Bao Project and Contributors. All rights reserved.
+ *
+ * Authors:
+ *	Jo?o Peixoto <joaopeixoto at osyx.tech>
+ *	Jos? Martins <jose at osyx.tech>
+ *	David Cerdeira <davidmcerdeira at osyx.tech>
+ */
+
+#include "bao_drv.h"
+#include <linux/eventfd.h>
+
+/**
+ * struct ioeventfd - Properties of an I/O eventfd
+ * @list: List node linking this ioeventfd
+ * @eventfd: Associated eventfd context
+ * @addr: Start address of the I/O range
+ * @data: Data used for matching (if not wildcard)
+ * @length: Length of the I/O range
+ * @wildcard: True if data matching is not required
+ *
+ * Represents an I/O eventfd registered for a Bao device model.
+ */
+struct ioeventfd {
+	struct list_head list;
+	struct eventfd_ctx *eventfd;
+	u64 addr;
+	u64 data;
+	int length;
+	bool wildcard;
+};
+
+/**
+ * bao_ioeventfd_shutdown - Release and remove an ioeventfd
+ * @dm: Bao device model owning the ioeventfd (lock must be held)
+ * @p: Ioeventfd to shut down
+ */
+static void bao_ioeventfd_shutdown(struct bao_dm *dm, struct ioeventfd *p)
+{
+	lockdep_assert_held(&dm->ioeventfds_lock);
+
+	if (WARN_ON_ONCE(!p))
+		return;
+
+	eventfd_ctx_put(p->eventfd);
+	list_del(&p->list);
+	kfree(p);
+}
+
+/**
+ * bao_ioeventfd_config_valid - Validate ioeventfd configuration
+ * @config: Ioeventfd configuration
+ *
+ * Returns true if config is non-NULL, address+length does not wrap,
+ * and length is 1, 2, 4, or 8 bytes.
+ */
+static bool bao_ioeventfd_config_valid(struct bao_ioeventfd *config)
+{
+	if (WARN_ON_ONCE(!config))
+		return false;
+
+	/* Check for address overflow */
+	if (config->addr + config->len < config->addr)
+		return false;
+
+	/* Only allow standard byte widths */
+	if (!(config->len == 1 || config->len == 2 || config->len == 4 ||
+	      config->len == 8))
+		return false;
+
+	return true;
+}
+
+/**
+ * bao_ioeventfd_is_conflict - Check if an ioeventfd conflicts with existing ones
+ * @dm: Bao device model (lock must be held)
+ * @ioeventfd: Ioeventfd to check
+ *
+ * Returns true if an existing ioeventfd matches address, eventfd,
+ * and optionally data.
+ */
+static bool bao_ioeventfd_is_conflict(struct bao_dm *dm,
+				      struct ioeventfd *ioeventfd)
+{
+	struct ioeventfd *p;
+
+	lockdep_assert_held(&dm->ioeventfds_lock);
+
+	if (WARN_ON_ONCE(!dm || !ioeventfd))
+		return true;
+
+	list_for_each_entry(p, &dm->ioeventfds, list) {
+		if (p->eventfd == ioeventfd->eventfd &&
+		    p->addr == ioeventfd->addr &&
+		    (p->wildcard || ioeventfd->wildcard || p->data == ioeventfd->data)) {
+			return true;
+		}
+	}
+
+	return false;
+}
+
+/**
+ * bao_ioeventfd_match - Find ioeventfd matching an I/O request
+ * @dm: Bao device model (lock must be held)
+ * @addr: I/O request address
+ * @data: I/O request data
+ * @len: I/O request length
+ *
+ * Returns the matching ioeventfd, or NULL if none matches.
+ */
+static struct ioeventfd *bao_ioeventfd_match(struct bao_dm *dm, u64 addr,
+					     u64 data, int len)
+{
+	struct ioeventfd *p;
+
+	lockdep_assert_held(&dm->ioeventfds_lock);
+
+	if (WARN_ON_ONCE(!dm))
+		return NULL;
+
+	list_for_each_entry(p, &dm->ioeventfds, list) {
+		if (p->addr == addr &&
+		    p->length >= len &&
+		    (p->wildcard || p->data == data)) {
+			return p;
+		}
+	}
+
+	return NULL;
+}
+
+/**
+ * bao_ioeventfd_assign - Assign and create an eventfd for a DM
+ * @dm: Bao device model to assign the eventfd to
+ * @config: Configuration of the eventfd to create
+ *
+ * Creates a new ioeventfd associated with the given eventfd and
+ * adds it to the Bao DM. Validates the configuration, checks for
+ * conflicts with existing ioeventfds, and registers the corresponding
+ * I/O client address range. Supports optional data matching for
+ * virtio 1.0 notifications; if not set, wildcard matching is used.
+ *
+ * Returns 0 on success or a negative error code on failure:
+ * -EINVAL: Invalid configuration
+ * -ENOMEM: Memory allocation failure
+ * -EEXIST: Conflicting ioeventfd already exists
+ * Other negative values may be returned by bao_io_client_range_add().
+ */
+static int bao_ioeventfd_assign(struct bao_dm *dm, struct bao_ioeventfd *config)
+{
+	struct eventfd_ctx *eventfd;
+	struct ioeventfd *new;
+	int rc = 0;
+
+	if (WARN_ON_ONCE(!dm || !config))
+		return -EINVAL;
+
+	if (!bao_ioeventfd_config_valid(config))
+		return -EINVAL;
+
+	eventfd = eventfd_ctx_fdget(config->fd);
+	if (IS_ERR(eventfd))
+		return PTR_ERR(eventfd);
+
+	new = kzalloc(sizeof(*new), GFP_KERNEL);
+	if (!new) {
+		rc = -ENOMEM;
+		goto err_put_eventfd;
+	}
+
+	INIT_LIST_HEAD(&new->list);
+	new->addr = config->addr;
+	new->length = config->len;
+	new->eventfd = eventfd;
+	new->wildcard = !(config->flags & BAO_IOEVENTFD_FLAG_DATAMATCH);
+	if (!new->wildcard)
+		new->data = config->data;
+
+	mutex_lock(&dm->ioeventfds_lock);
+
+	if (bao_ioeventfd_is_conflict(dm, new)) {
+		rc = -EEXIST;
+		goto err_unlock_free;
+	}
+
+	rc = bao_io_client_range_add(dm->ioeventfd_client,
+				     new->addr, new->addr + new->length - 1);
+	if (rc < 0)
+		goto err_unlock_free;
+
+	list_add_tail(&new->list, &dm->ioeventfds);
+	mutex_unlock(&dm->ioeventfds_lock);
+
+	return 0;
+
+err_unlock_free:
+	mutex_unlock(&dm->ioeventfds_lock);
+	kfree(new);
+err_put_eventfd:
+	eventfd_ctx_put(eventfd);
+	return rc;
+}
+
+/**
+ * bao_ioeventfd_deassign - Deassign and destroy an eventfd from a DM
+ * @dm: Bao device model to deassign the eventfd from
+ * @config: Configuration of the eventfd to remove
+ *
+ * Finds the ioeventfd associated with the given eventfd and removes
+ * it from the Bao DM. The corresponding I/O client range is deleted,
+ * the ioeventfd is shut down, and the eventfd context is released.
+ *
+ * Returns 0 on success or a negative error code if the eventfd lookup fails.
+ */
+static int bao_ioeventfd_deassign(struct bao_dm *dm,
+				  struct bao_ioeventfd *config)
+{
+	struct ioeventfd *p;
+	struct eventfd_ctx *eventfd;
+
+	if (WARN_ON_ONCE(!dm || !config))
+		return -EINVAL;
+
+	eventfd = eventfd_ctx_fdget(config->fd);
+	if (IS_ERR(eventfd))
+		return PTR_ERR(eventfd);
+
+	mutex_lock(&dm->ioeventfds_lock);
+
+	list_for_each_entry(p, &dm->ioeventfds, list) {
+		if (p->eventfd != eventfd)
+			continue;
+
+		/* Remove the associated client I/O range */
+		bao_io_client_range_del(dm->ioeventfd_client,
+					p->addr, p->addr + p->length - 1);
+
+		/* Shutdown and free the ioeventfd */
+		bao_ioeventfd_shutdown(dm, p);
+		break;
+	}
+
+	mutex_unlock(&dm->ioeventfds_lock);
+	eventfd_ctx_put(eventfd);
+
+	return 0;
+}
+
+/**
+ * bao_ioeventfd_handler - Handle an Ioeventfd client I/O request
+ * @client: Ioeventfd client associated with the request
+ * @req: I/O request to process
+ *
+ * Processes I/O requests from the Bao I/O client kernel thread
+ * (bao_io_client_kernel_thread). For READ operations, the value is
+ * ignored and set to 0 since virtio MMIO drivers only write to the
+ * `QueueNotify` field. WRITE operations are checked against the
+ * registered ioeventfds, and the corresponding eventfd is signaled
+ * if a match is found.
+ *
+ * Returns 0 on success.
+ */
+static int bao_ioeventfd_handler(struct bao_io_client *client,
+				 struct bao_virtio_request *req)
+{
+	struct ioeventfd *p;
+
+	if (WARN_ON_ONCE(!client || !req))
+		return -EINVAL;
+
+	/* Handle read requests: just return 0 */
+	if (req->op == BAO_IO_READ) {
+		req->value = 0;
+		return 0;
+	}
+
+	/* Handle write requests */
+	mutex_lock(&client->dm->ioeventfds_lock);
+
+	p = bao_ioeventfd_match(client->dm, req->addr, req->value,
+				req->access_width);
+	if (p)
+		eventfd_signal(p->eventfd);
+
+	mutex_unlock(&client->dm->ioeventfds_lock);
+
+	return 0;
+}
+
+int bao_ioeventfd_client_config(struct bao_dm *dm, struct bao_ioeventfd *config)
+{
+	if (WARN_ON_ONCE(!dm || !config))
+		return -EINVAL;
+
+	if (config->flags & BAO_IOEVENTFD_FLAG_DEASSIGN)
+		bao_ioeventfd_deassign(dm, config);
+
+	return bao_ioeventfd_assign(dm, config);
+}
+
+int bao_ioeventfd_client_init(struct bao_dm *dm)
+{
+	char name[BAO_NAME_MAX_LEN];
+
+	if (WARN_ON_ONCE(!dm))
+		return -EINVAL;
+
+	mutex_init(&dm->ioeventfds_lock);
+	INIT_LIST_HEAD(&dm->ioeventfds);
+
+	snprintf(name, sizeof(name), "bao-ioevfdc%u", dm->info.id);
+
+	dm->ioeventfd_client = bao_io_client_create(dm, bao_ioeventfd_handler,
+						    NULL, false, name);
+	if (!dm->ioeventfd_client)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void bao_ioeventfd_client_destroy(struct bao_dm *dm)
+{
+	struct ioeventfd *p, *next;
+
+	if (WARN_ON_ONCE(!dm))
+		return;
+
+	mutex_lock(&dm->ioeventfds_lock);
+	list_for_each_entry_safe(p, next, &dm->ioeventfds, list)
+		bao_ioeventfd_shutdown(dm, p);
+	mutex_unlock(&dm->ioeventfds_lock);
+}
diff --git a/drivers/virt/bao/io-dispatcher/irqfd.c b/drivers/virt/bao/io-dispatcher/irqfd.c
new file mode 100644
index 000000000000..145ed7428d9c
--- /dev/null
+++ b/drivers/virt/bao/io-dispatcher/irqfd.c
@@ -0,0 +1,341 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Bao Hypervisor Irqfd Server
+ *
+ * Copyright (c) Bao Project and Contributors. All rights reserved.
+ *
+ * Authors:
+ *	Jo?o Peixoto <joaopeixoto at osyx.tech>
+ *	Jos? Martins <jose at osyx.tech>
+ *	David Cerdeira <davidmcerdeira at osyx.tech>
+ */
+
+#include <linux/eventfd.h>
+#include <linux/file.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include "hypercall.h"
+
+#include "bao_drv.h"
+
+/**
+ * struct irqfd - Properties of an IRQ eventfd
+ * @dm: Associated Bao device model
+ * @wait: Wait queue entry for blocking/waking
+ * @shutdown: Work struct for async shutdown
+ * @eventfd: Eventfd used to signal interrupts
+ * @list: List node within &bao_dm.irqfds
+ * @pt: Poll table for select/poll on the eventfd
+ *
+ * Represents an IRQ eventfd registered to a Bao device model.
+ */
+struct irqfd {
+	struct bao_dm *dm;
+	wait_queue_entry_t wait;
+	struct work_struct shutdown;
+	struct eventfd_ctx *eventfd;
+	struct list_head list;
+	poll_table pt;
+};
+
+/**
+ * bao_irqfd_shutdown - Release and remove an irqfd
+ * @irqfd: IRQ eventfd to shut down (lock must be held)
+ *
+ * Removes the irqfd from the DM list, unregisters it from the
+ * eventfd wait queue, releases the eventfd, and frees the struct.
+ */
+static void bao_irqfd_shutdown(struct irqfd *irqfd)
+{
+	u64 cnt;
+
+	if (WARN_ON_ONCE(!irqfd || !irqfd->dm))
+		return;
+
+	lockdep_assert_held(&irqfd->dm->irqfds_lock);
+
+	/* Remove from DM list */
+	list_del_init(&irqfd->list);
+
+	/* Remove wait queue from eventfd context */
+	eventfd_ctx_remove_wait_queue(irqfd->eventfd, &irqfd->wait, &cnt);
+
+	/* Release the eventfd context */
+	eventfd_ctx_put(irqfd->eventfd);
+
+	/* Free irqfd structure */
+	kfree(irqfd);
+}
+
+/**
+ * bao_irqfd_inject - Inject a notify hypercall into the Bao hypervisor
+ * @id: Bao DM ID
+ *
+ * Sends a BAO_IO_NOTIFY hypercall to the hypervisor for the specified DM.
+ *
+ * Returns 0 on success or -EFAULT if the hypercall fails.
+ */
+static int bao_irqfd_inject(int id)
+{
+	struct bao_virtio_request request = {
+		.dm_id	      = id,
+		.addr         = 0,
+		.op           = BAO_IO_NOTIFY,
+		.value        = 0,
+		.access_width = 0,
+		.request_id   = 0,
+	};
+	struct remio_hypercall_ret ret;
+
+	ret = bao_hypercall_remio(&request);
+	if (ret.hyp_ret != 0 || ret.remio_hyp_ret != 0)
+		return -EFAULT;
+
+	return 0;
+}
+
+/**
+ * bao_irqfd_wakeup - Custom wake-up handler for eventfd signaling
+ * @wait: Wait queue entry
+ * @mode: Mode flags
+ * @sync: Sync indicator
+ * @key: Poll bits (cast from void *)
+ *
+ * Called by the Linux kernel poll table when the underlying eventfd is signaled.
+ * Injects a Bao notify hypercall on POLLIN or schedules shutdown on POLLHUP.
+ *
+ * Returns 0.
+ */
+static int bao_irqfd_wakeup(wait_queue_entry_t *wait, unsigned int mode,
+			    int sync, void *key)
+{
+	struct irqfd *irqfd;
+	struct bao_dm *dm;
+	unsigned long poll_bits;
+
+	if (WARN_ON_ONCE(!wait || !key))
+		return -EINVAL;
+
+	irqfd = container_of(wait, struct irqfd, wait);
+	dm = irqfd->dm;
+	poll_bits = (unsigned long)key;
+
+	/* Inject IRQ on POLLIN */
+	if (poll_bits & POLLIN)
+		bao_irqfd_inject(dm->info.id);
+
+	/* Schedule shutdown on POLLHUP */
+	if (poll_bits & POLLHUP)
+		queue_work(dm->irqfd_server, &irqfd->shutdown);
+
+	return 0;
+}
+
+/**
+ * bao_irqfd_poll_func - Register an IRQFD with a poll table
+ * @file: File to poll
+ * @wqh: Wait queue head
+ * @pt: Poll table
+ *
+ * Adds the irqfd's wait queue entry to the kernel wait queue for event monitoring.
+ */
+static void bao_irqfd_poll_func(struct file *file, wait_queue_head_t *wqh,
+				poll_table *pt)
+{
+	struct irqfd *irqfd;
+
+	if (WARN_ON_ONCE(!pt || !wqh))
+		return;
+
+	irqfd = container_of(pt, struct irqfd, pt);
+	add_wait_queue(wqh, &irqfd->wait);
+}
+
+/**
+ * irqfd_shutdown_work - Workqueue handler to shutdown an irqfd
+ * @work: Work struct for the shutdown operation
+ *
+ * Removes and frees the irqfd from the DM under lock if it is still linked.
+ */
+static void irqfd_shutdown_work(struct work_struct *work)
+{
+	struct irqfd *irqfd;
+	struct bao_dm *dm;
+
+	if (WARN_ON_ONCE(!work))
+		return;
+
+	irqfd = container_of(work, struct irqfd, shutdown);
+	dm = irqfd->dm;
+
+	if (WARN_ON_ONCE(!dm))
+		return;
+
+	mutex_lock(&dm->irqfds_lock);
+	if (!list_empty(&irqfd->list))
+		bao_irqfd_shutdown(irqfd);
+	mutex_unlock(&dm->irqfds_lock);
+}
+
+/**
+ * bao_irqfd_assign - Assign an eventfd to a DM and create an irqfd
+ * @dm: Bao device model to assign the eventfd
+ * @args: Configuration of the irqfd to assign
+ *
+ * Allocates and initializes an irqfd for the given eventfd, registers
+ * it with the DM, sets up the wait queue and poll table, and triggers
+ * an initial notify if the eventfd is already signaled.
+ *
+ * Returns 0 on success or a negative error code on failure:
+ * -ENOMEM if allocation fails
+ * -EBADF if the file descriptor is invalid
+ * -EBUSY if an irqfd with the same eventfd already exists
+ * Other negative values may be returned by eventfd_ctx_fileget().
+ */
+static int bao_irqfd_assign(struct bao_dm *dm, struct bao_irqfd *args)
+{
+	struct eventfd_ctx *eventfd = NULL;
+	struct irqfd *irqfd, *tmp;
+	__poll_t events;
+	struct fd f;
+	int ret = 0;
+
+	if (WARN_ON_ONCE(!dm || !args))
+		return -EINVAL;
+
+	irqfd = kzalloc(sizeof(*irqfd), GFP_KERNEL);
+	if (!irqfd)
+		return -ENOMEM;
+
+	irqfd->dm = dm;
+	INIT_LIST_HEAD(&irqfd->list);
+	INIT_WORK(&irqfd->shutdown, irqfd_shutdown_work);
+
+	/* Get the file descriptor and associated eventfd context */
+	f = fdget(args->fd);
+	if (!fd_file(f)) {
+		ret = -EBADF;
+		goto out_free_irqfd;
+	}
+
+	eventfd = eventfd_ctx_fileget(fd_file(f));
+	if (IS_ERR(eventfd)) {
+		ret = PTR_ERR(eventfd);
+		goto out_fdput;
+	}
+	irqfd->eventfd = eventfd;
+
+	/* Initialize wait queue and poll table for this irqfd */
+	init_waitqueue_func_entry(&irqfd->wait, bao_irqfd_wakeup);
+	init_poll_funcptr(&irqfd->pt, bao_irqfd_poll_func);
+
+	/* Check for conflicts with existing irqfds */
+	mutex_lock(&dm->irqfds_lock);
+	list_for_each_entry(tmp, &dm->irqfds, list) {
+		if (irqfd->eventfd == tmp->eventfd) {
+			ret = -EBUSY;
+			mutex_unlock(&dm->irqfds_lock);
+			goto out_put_eventfd;
+		}
+	}
+	list_add_tail(&irqfd->list, &dm->irqfds);
+	mutex_unlock(&dm->irqfds_lock);
+
+	/* Trigger initial notification if the eventfd is already signaled */
+	events = vfs_poll(fd_file(f), &irqfd->pt);
+	if (events & EPOLLIN)
+		bao_irqfd_inject(dm->info.id);
+
+	fdput(f);
+	return 0;
+
+out_put_eventfd:
+	eventfd_ctx_put(eventfd);
+out_fdput:
+	fdput(f);
+out_free_irqfd:
+	kfree(irqfd);
+	return ret;
+}
+
+/**
+ * bao_irqfd_deassign - Deassign an eventfd and destroy the associated irqfd
+ * @dm: Bao device model to remove the irqfd from
+ * @args: Configuration of the irqfd to deassign
+ *
+ * Finds the irqfd associated with the given eventfd in the DM,
+ * shuts it down, and releases the eventfd context.
+ *
+ * Returns 0 on success or a negative error code if the eventfd lookup fails.
+ */
+static int bao_irqfd_deassign(struct bao_dm *dm, struct bao_irqfd *args)
+{
+	struct irqfd *irqfd, *tmp;
+	struct eventfd_ctx *eventfd;
+
+	if (WARN_ON_ONCE(!dm || !args))
+		return -EINVAL;
+
+	eventfd = eventfd_ctx_fdget(args->fd);
+	if (IS_ERR(eventfd))
+		return PTR_ERR(eventfd);
+
+	mutex_lock(&dm->irqfds_lock);
+	list_for_each_entry_safe(irqfd, tmp, &dm->irqfds, list) {
+		if (irqfd->eventfd == eventfd) {
+			bao_irqfd_shutdown(irqfd);
+			break;
+		}
+	}
+	mutex_unlock(&dm->irqfds_lock);
+
+	eventfd_ctx_put(eventfd);
+
+	return 0;
+}
+
+int bao_irqfd_server_config(struct bao_dm *dm, struct bao_irqfd *config)
+{
+	if (WARN_ON_ONCE(!dm || !config))
+		return -EINVAL;
+
+	if (config->flags & BAO_IRQFD_FLAG_DEASSIGN)
+		return bao_irqfd_deassign(dm, config);
+
+	return bao_irqfd_assign(dm, config);
+}
+
+int bao_irqfd_server_init(struct bao_dm *dm)
+{
+	char name[BAO_NAME_MAX_LEN];
+
+	if (WARN_ON_ONCE(!dm))
+		return -EINVAL;
+
+	mutex_init(&dm->irqfds_lock);
+	INIT_LIST_HEAD(&dm->irqfds);
+
+	snprintf(name, sizeof(name), "bao-ioirqfds%u", dm->info.id);
+
+	dm->irqfd_server = alloc_workqueue(name, WQ_UNBOUND | WQ_HIGHPRI, 0);
+	if (!dm->irqfd_server)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void bao_irqfd_server_destroy(struct bao_dm *dm)
+{
+	struct irqfd *irqfd, *next;
+
+	if (WARN_ON_ONCE(!dm))
+		return;
+
+	if (dm->irqfd_server)
+		destroy_workqueue(dm->irqfd_server);
+
+	mutex_lock(&dm->irqfds_lock);
+	list_for_each_entry_safe(irqfd, next, &dm->irqfds, list)
+		bao_irqfd_shutdown(irqfd);
+	mutex_unlock(&dm->irqfds_lock);
+}
diff --git a/include/uapi/linux/bao.h b/include/uapi/linux/bao.h
new file mode 100644
index 000000000000..581b094861ce
--- /dev/null
+++ b/include/uapi/linux/bao.h
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * Provides the Bao Hypervisor IOCTLs and global structures
+ *
+ * Copyright (c) Bao Project and Contributors. All rights reserved.
+ *
+ * Authors:
+ *	Jo?o Peixoto <joaopeixoto at osyx.tech>
+ *	Jos? Martins <jose at osyx.tech>
+ *	David Cerdeira <davidmcerdeira at osyx.tech>
+ */
+
+#ifndef _UAPI_BAO_H
+#define _UAPI_BAO_H
+
+#include <linux/types.h>
+#include <linux/uuid.h>
+#include <linux/list.h>
+
+#define BAO_IO_WRITE 0x0
+#define BAO_IO_READ 0x1
+#define BAO_IO_ASK 0x2
+#define BAO_IO_NOTIFY 0x3
+
+#define BAO_NAME_MAX_LEN 16
+#define BAO_IO_REQUEST_MAX 64
+#define BAO_IO_MAX_DMS 16
+
+/**
+ * struct bao_virtio_request - Parameters of a Bao VirtIO request
+ * @dm_id: Device model ID
+ * @addr: MMIO register address accessed
+ * @op: Operation type (WRITE, READ, ASK, NOTIFY)
+ * @value: Value to write or read
+ * @access_width: Access width (VirtIO MMIO supports 4-byte aligned accesses)
+ * @request_id: Request ID of the I/O request
+ */
+struct bao_virtio_request {
+	__u64 dm_id;
+	__u64 addr;
+	__u64 op;
+	__u64 value;
+	__u64 access_width;
+	__u64 request_id;
+};
+
+/**
+ * struct bao_ioeventfd - Parameters of an ioeventfd request
+ * @fd: Eventfd file descriptor associated with the I/O request
+ * @flags: Logical OR of BAO_IOEVENTFD_FLAG_*
+ * @addr: Start address of the I/O range
+ * @len: Length of the I/O range
+ * @reserved: Reserved, must be 0
+ * @data: Data for matching (used if data matching is enabled)
+ */
+struct bao_ioeventfd {
+	__u32 fd;
+	__u32 flags;
+	__u64 addr;
+	__u32 len;
+	__u32 reserved;
+	__u64 data;
+};
+
+/**
+ * struct bao_irqfd - Parameters of an IRQFD request
+ * @fd: File descriptor of the eventfd
+ * @flags: Flags associated with the eventfd
+ */
+struct bao_irqfd {
+	__s32 fd;
+	__u32 flags;
+};
+
+/**
+ * struct bao_dm_info - Parameters of a Bao device model
+ * @id: Virtual ID of the DM
+ * @shmem_addr: Base address of the shared memory
+ * @shmem_size: Size of the shared memory
+ * @irq: IRQ number
+ * @fd: File descriptor of the DM
+ */
+struct bao_dm_info {
+	__u32 id;
+	__u64 shmem_addr;
+	__u64 shmem_size;
+	__u32 irq;
+	__s32 fd;
+};
+
+/*
+ * The ioctl type for Bao, documented in
+ * Documentation/userspace-api/ioctl/ioctl-number.rst
+ */
+#define BAO_IOCTL_TYPE 0xA6
+
+/*
+ * Bao userspace IOCTL commands
+ * Follows Linux kernel convention, see Documentation/driver-api/ioctl.rst
+ */
+#define BAO_IOCTL_DM_GET_INFO _IOWR(BAO_IOCTL_TYPE, 0x01, struct bao_dm_info)
+#define BAO_IOCTL_IO_CLIENT_ATTACH \
+	_IOWR(BAO_IOCTL_TYPE, 0x02, struct bao_virtio_request)
+#define BAO_IOCTL_IO_REQUEST_COMPLETE \
+	_IOW(BAO_IOCTL_TYPE, 0x03, struct bao_virtio_request)
+#define BAO_IOCTL_IOEVENTFD _IOW(BAO_IOCTL_TYPE, 0x04, struct bao_ioeventfd)
+#define BAO_IOCTL_IRQFD _IOW(BAO_IOCTL_TYPE, 0x05, struct bao_irqfd)
+
+/* Remote I/O Hypercall ID */
+#define REMIO_HC_ID 0x2
+
+/**
+ * struct remio_hypercall_ret - Remote I/O hypercall return values
+ * @hyp_ret:          Generic return value from the Bao hypercall
+ * @remio_hyp_ret:    Remote I/O?specific return value
+ * @pending_requests: Number of pending requests (only for Remote I/O Ask hypercall)
+ */
+struct remio_hypercall_ret {
+	u64 hyp_ret;
+	u64 remio_hyp_ret;
+	u64 pending_requests;
+};
+
+#endif /* _UAPI_BAO_H */
-- 
2.43.0



From marco.crivellari at suse.com  Wed Dec 24 07:25:08 2025
From: marco.crivellari at suse.com (Marco Crivellari)
Date: Wed, 24 Dec 2025 16:25:08 +0100
Subject: [PATCH v2] wifi: mt76: replace use of system_wq with system_percpu_wq
In-Reply-To: <20251114104325.116471-1-marco.crivellari@suse.com>
References: <20251114104325.116471-1-marco.crivellari@suse.com>
Message-ID: <CAAofZF51pkOzrg_nO0Mhx6g9b3JPtO3n+0YE=WtSgj_F6wnY4w@mail.gmail.com>

On Fri, Nov 14, 2025 at 11:43?AM Marco Crivellari
<marco.crivellari at suse.com> wrote:
>[...]
>  drivers/net/wireless/mediatek/mt76/mt7921/init.c | 2 +-
>  drivers/net/wireless/mediatek/mt76/mt7925/init.c | 2 +-
>  2 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
> index b9098a7331b1..95764b82da39 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
> @@ -343,7 +343,7 @@ int mt7921_register_device(struct mt792x_dev *dev)
>         dev->mphy.hw->wiphy->available_antennas_rx = dev->mphy.chainmask;
>         dev->mphy.hw->wiphy->available_antennas_tx = dev->mphy.chainmask;
>
> -       queue_work(system_wq, &dev->init_work);
> +       queue_work(system_percpu_wq, &dev->init_work);
>
>         return 0;
>  }
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/init.c b/drivers/net/wireless/mediatek/mt76/mt7925/init.c
> index d7d5afe365ed..e33ab4849e8a 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7925/init.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7925/init.c
> @@ -420,7 +420,7 @@ int mt7925_register_device(struct mt792x_dev *dev)
>         dev->mphy.hw->wiphy->available_antennas_rx = dev->mphy.chainmask;
>         dev->mphy.hw->wiphy->available_antennas_tx = dev->mphy.chainmask;
>
> -       queue_work(system_wq, &dev->init_work);
> +       queue_work(system_percpu_wq, &dev->init_work);
>
>         return 0;
>  }


Gentle ping.

Thanks!

-- 

Marco Crivellari

L3 Support Engineer


From nicolas at ndufresne.ca  Wed Dec 24 07:26:41 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 24 Dec 2025 10:26:41 -0500
Subject: [PATCH v2 09/22] media: rockchip: rga: align stride to 4 bytes
In-Reply-To: <20251203-spu-rga3-v2-9-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
	 <20251203-spu-rga3-v2-9-989a67947f71@pengutronix.de>
Message-ID: <98a11ef7e0004267f58a18ad97ea9cb11a68a626.camel@ndufresne.ca>

Hi,

Le mercredi 03 d?cembre 2025 ? 16:52 +0100, Sven P?schel a ?crit?:
> Add an alignment setting to rga_hw to set the desired stride alignment.
> As the RGA2 register for the stride counts in word units, the code
> already divides the bytesperline value by 4 when writing it into the
> register. Therefore fix the alignment to a multiple of 4 to avoid
> potential off by one errors due from the division.

If you decide to keep the stride alignment to be width alignment, then please
make use struct v4l2_frmsize_stepwise and v4l2_apply_frmsize_constraints
instead.

It will also make the per-variant description a lot more clear, with the min/max
resolution exposed.

Nicolas

> 
> Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
> ---
> ?drivers/media/platform/rockchip/rga/rga-hw.c |? 1 +
> ?drivers/media/platform/rockchip/rga/rga.c??? | 11 ++++++-----
> ?drivers/media/platform/rockchip/rga/rga.h??? |? 1 +
> ?3 files changed, 8 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
> index 79bf911e74779..56a2558539bfb 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
> @@ -620,6 +620,7 @@ const struct rga_hw rga2_hw = {
> ?	.max_width = MAX_WIDTH,
> ?	.min_height = MIN_HEIGHT,
> ?	.max_height = MAX_HEIGHT,
> +	.stride_alignment = 4,
> ?
> ?	.start = rga_hw_start,
> ?	.handle_irq = rga_handle_irq,
> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
> index 74d94c7fe31ff..592c977a07cf3 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -234,10 +234,10 @@ static int rga_open(struct file *file)
> ?	ctx->in = def_frame;
> ?	ctx->out = def_frame;
> ?
> -	v4l2_fill_pixfmt_mp(&ctx->in.pix,
> -			??? ctx->in.fmt->fourcc, def_width, def_height);
> -	v4l2_fill_pixfmt_mp(&ctx->out.pix,
> -			??? ctx->out.fmt->fourcc, def_width, def_height);
> +	v4l2_fill_pixfmt_mp_aligned(&ctx->in.pix, ctx->in.fmt->fourcc,
> +				??? def_width, def_height, rga->hw->stride_alignment);
> +	v4l2_fill_pixfmt_mp_aligned(&ctx->out.pix, ctx->out.fmt->fourcc,
> +				??? def_width, def_height, rga->hw->stride_alignment);
> ?
> ?	if (mutex_lock_interruptible(&rga->mutex)) {
> ?		ret = -ERESTARTSYS;
> @@ -359,7 +359,8 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
> ?	pix_fmt->height = clamp(pix_fmt->height,
> ?				hw->min_height, hw->max_height);
> ?
> -	v4l2_fill_pixfmt_mp(pix_fmt, fmt->fourcc, pix_fmt->width, pix_fmt->height);
> +	v4l2_fill_pixfmt_mp_aligned(pix_fmt, pix_fmt->pixelformat,
> +				??? pix_fmt->width, pix_fmt->height, hw->stride_alignment);
> ?	pix_fmt->field = V4L2_FIELD_NONE;
> ?
> ?	return 0;
> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
> index f8c932fdec21a..0aef348dddb95 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -152,6 +152,7 @@ struct rga_hw {
> ?	size_t cmdbuf_size;
> ?	u32 min_width, min_height;
> ?	u32 max_width, max_height;
> +	u8 stride_alignment;
> ?
> ?	void (*start)(struct rockchip_rga *rga,
> ?		????? struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/c4663458/attachment.sig>

From nicolas at ndufresne.ca  Wed Dec 24 07:29:41 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 24 Dec 2025 10:29:41 -0500
Subject: [PATCH v2 10/22] media: rockchip: rga: prepare cmdbuf on
 streamon
In-Reply-To: <20251203-spu-rga3-v2-10-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
	 <20251203-spu-rga3-v2-10-989a67947f71@pengutronix.de>
Message-ID: <8c3a3299036dd1bab158bdcd589abd027d2864b6.camel@ndufresne.ca>

Hi,

Le mercredi 03 d?cembre 2025 ? 16:52 +0100, Sven P?schel a ?crit?:
> Prepare the command buffer on streamon to reuse it's contents instead of
> completely writing it for every frame. Due to the stream settings being
> fixed after a streamon we only need to replace the source and destination
> addresses for each frame. This reduces the amount of CPU and memory
> operations done in each frame.

My speculation is that flushing to device is usually more expensive then this,
but I didn't check closely if you have enabled the caches. That being said, this
is good change. It highlight the inflexible nature of V4L2 imho, which in this
case can be used to optimize.

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> 
> Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
> ---
> ?drivers/media/platform/rockchip/rga/rga-hw.c | 13 +++++++++----
> ?drivers/media/platform/rockchip/rga/rga.c??? | 13 ++++++++++++-
> ?drivers/media/platform/rockchip/rga/rga.h??? |? 1 +
> ?3 files changed, 22 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
> index 56a2558539bfb..8cdfe089fd636 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
> @@ -408,8 +408,6 @@ static void rga_cmd_set(struct rga_ctx *ctx,
> ?{
> ?	struct rockchip_rga *rga = ctx->rga;
> ?
> -	memset(ctx->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);
> -
> ?	rga_cmd_set_src_addr(ctx, src->dma_desc_pa);
> ?	/*
> ?	 * Due to hardware bug,
> @@ -418,11 +416,9 @@ static void rga_cmd_set(struct rga_ctx *ctx,
> ?	rga_cmd_set_src1_addr(ctx, dst->dma_desc_pa);
> ?
> ?	rga_cmd_set_dst_addr(ctx, dst->dma_desc_pa);
> -	rga_cmd_set_mode(ctx);
> ?
> ?	rga_cmd_set_src_info(ctx, &src->offset);
> ?	rga_cmd_set_dst_info(ctx, &dst->offset);
> -	rga_cmd_set_trans_info(ctx);
> ?
> ?	rga_write(rga, RGA_CMD_BASE, ctx->cmdbuf_phy);
> ?
> @@ -431,6 +427,14 @@ static void rga_cmd_set(struct rga_ctx *ctx,
> ?				?? PAGE_SIZE, DMA_BIDIRECTIONAL);
> ?}
> ?
> +static void rga_hw_setup_cmdbuf(struct rga_ctx *ctx)
> +{
> +	memset(ctx->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);
> +
> +	rga_cmd_set_mode(ctx);
> +	rga_cmd_set_trans_info(ctx);
> +}
> +
> ?static void rga_hw_start(struct rockchip_rga *rga,
> ?			 struct rga_vb_buffer *src,? struct rga_vb_buffer *dst)
> ?{
> @@ -622,6 +626,7 @@ const struct rga_hw rga2_hw = {
> ?	.max_height = MAX_HEIGHT,
> ?	.stride_alignment = 4,
> ?
> +	.setup_cmdbuf = rga_hw_setup_cmdbuf,
> ?	.start = rga_hw_start,
> ?	.handle_irq = rga_handle_irq,
> ?	.get_version = rga_get_version,
> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
> index 592c977a07cf3..f02ae02de26ca 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -523,6 +523,17 @@ static int vidioc_s_selection(struct file *file, void *priv,
> ?	return ret;
> ?}
> ?
> +static int vidioc_streamon(struct file *file, void *priv,
> +			?? enum v4l2_buf_type type)
> +{
> +	struct rga_ctx *ctx = file_to_rga_ctx(file);
> +	const struct rga_hw *hw = ctx->rga->hw;
> +
> +	hw->setup_cmdbuf(ctx);
> +
> +	return v4l2_m2m_streamon(file, ctx->fh.m2m_ctx, type);
> +}
> +
> ?static const struct v4l2_ioctl_ops rga_ioctl_ops = {
> ?	.vidioc_querycap = vidioc_querycap,
> ?
> @@ -547,7 +558,7 @@ static const struct v4l2_ioctl_ops rga_ioctl_ops = {
> ?	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
> ?	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
> ?
> -	.vidioc_streamon = v4l2_m2m_ioctl_streamon,
> +	.vidioc_streamon = vidioc_streamon,
> ?	.vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
> ?
> ?	.vidioc_g_selection = vidioc_g_selection,
> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
> index 0aef348dddb95..93162b118d069 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -154,6 +154,7 @@ struct rga_hw {
> ?	u32 max_width, max_height;
> ?	u8 stride_alignment;
> ?
> +	void (*setup_cmdbuf)(struct rga_ctx *ctx);
> ?	void (*start)(struct rockchip_rga *rga,
> ?		????? struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
> ?	bool (*handle_irq)(struct rockchip_rga *rga);
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/ae5171f6/attachment-0001.sig>

From joaopeixoto at osyx.tech  Wed Dec 24 05:52:15 2025
From: joaopeixoto at osyx.tech (joaopeixoto at osyx.tech)
Date: Wed, 24 Dec 2025 13:52:15 +0000
Subject: [PATCH 3/5] dt-bindings: Add Bao I/O dispatcher driver binding
In-Reply-To: <20251224135217.25350-1-joaopeixoto@osyx.tech>
References: <20251224135217.25350-1-joaopeixoto@osyx.tech>
Message-ID: <20251224135217.25350-4-joaopeixoto@osyx.tech>

From: Jo?o Peixoto <joaopeixoto at osyx.tech>

This patch adds a Device Tree binding for the Bao I/O Dispatcher kernel
module, which can be loaded into backend VMs. The I/O Dispatcher
provides the bridge between the Bao hypervisor Remote I/O system and the
frontend device model in userspace, offering a unified API to support
various VirtIO backends.

The dispatcher handles hypercalls to the Bao hypervisor, IRQ/eventfd
forwarding, and provides a character device interface for frontend
devices, enabling efficient communication between the hypervisor and
userspace device models.

The binding documents the following properties:
  - compatible: "bao,io-dispatcher"
  - reg: Memory regions for the dispatcher (multiple VirtIO devices)
  - interrupts: Interrupts used by the devices
  - interrupt-parent: Parent interrupt controller

This enables kernel drivers to correctly instantiate and configure Bao
I/O Dispatcher modules based on the DT description.

Signed-off-by: Jo?o Peixoto <joaopeixoto at osyx.tech>
---
 .../bindings/bao/io-dispatcher.yaml           | 67 +++++++++++++++++++
 1 file changed, 67 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/bao/io-dispatcher.yaml

diff --git a/Documentation/devicetree/bindings/bao/io-dispatcher.yaml b/Documentation/devicetree/bindings/bao/io-dispatcher.yaml
new file mode 100644
index 000000000000..7795f55d3ff9
--- /dev/null
+++ b/Documentation/devicetree/bindings/bao/io-dispatcher.yaml
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/bao/io-dispatcher.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Bao I/O Dispatcher Device
+
+maintainers:
+  - Jo?o Peixoto <joaopeixoto at osyx.tech>
+  - Jos? Martins <jose at osyx.tech>
+  - David Cerdeira <davidmcerdeira at osyx.tech>
+
+description: |
+  I/O Dispatcher device for Bao hypervisor guests. Handles multiple VirtIO
+  backend devices and their interrupts.
+
+properties:
+  compatible:
+    const: "bao,io-dispatcher"
+    description: Device compatible string.
+
+  reg:
+    description: |
+      Memory regions for each VirtIO backend device.
+    maxItems: 20
+    type: array
+    items:
+      type: integer
+
+  interrupts:
+    description: |
+      Interrupt numbers for each VirtIO backend device.
+    type: array
+    items:
+      type: integer
+    minItems: 3
+    maxItems: 3
+
+  interrupt-parent:
+    description: Parent interrupt controller node
+    type: string
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-parent
+
+additionalProperties: false
+
+examples:
+  - |
+    bao_io_dispatcher: bao-io-dispatcher {
+        compatible = "bao,io-dispatcher";
+        reg = <0x0 0x50000000 0x0 0x01000000
+               0x0 0x51000000 0x0 0x01000000
+               0x0 0x52000000 0x0 0x01000000
+               0x0 0x53000000 0x0 0x01000000
+               0x0 0x54000000 0x0 0x01000000>;
+        interrupts = <0x0 0x08 0x1
+                      0x0 0x09 0x1
+                      0x0 0x0a 0x1
+                      0x0 0x0b 0x1
+                      0x0 0x0c 0x1>;
+        interrupt-parent = <&gic>;
+    };
-- 
2.43.0



From nicolas at ndufresne.ca  Wed Dec 24 07:39:33 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 24 Dec 2025 10:39:33 -0500
Subject: [PATCH v2 11/22] media: rockchip: rga: check scaling factor
In-Reply-To: <20251203-spu-rga3-v2-11-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
	 <20251203-spu-rga3-v2-11-989a67947f71@pengutronix.de>
Message-ID: <02ac025c0ecf17354377c7f2c2fc83b40a3a41e1.camel@ndufresne.ca>

Le mercredi 03 d?cembre 2025 ? 16:52 +0100, Sven P?schel a ?crit?:
> Check the scaling factor to avoid potential problems. This is relevant
> for the upcoming RGA3 support, as it can hang when the scaling factor
> is exceeded.
> 
> There are two relevant scenarios that have to be considered to protect
> against invalid scaling values:
> 
> When the output or capture is already streaming, setting the format on
> the other side should consider the max scaling factor and clamp it
> accordingly. This is only done in the streaming case, as it otherwise
> may unintentionally clamp the value when the application sets the first
> format (due to a default format on the other side).
> 
> When the format is set on both sides first, then the format won't be
> corrected by above means. Therefore the second streamon call has to
> check the scaling factor and fail otherwise.

In codec specifications, we resolve this issue by resetting the capture format
every-time the output format is set. But without specification for color
transforms, its impossible to say if this is right or wrong, and I don't expect
perfect interroperability between drivers until someone make the effort to
specify this type of hardware.

What you describe is fine of course, but its a bit off nature of the way format
is normally being fixed by the driver to stay valid.

> 
> Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
> ---
> ?drivers/media/platform/rockchip/rga/rga-hw.c |? 1 +
> ?drivers/media/platform/rockchip/rga/rga-hw.h |? 1 +
> ?drivers/media/platform/rockchip/rga/rga.c??? | 60 +++++++++++++++++++++++++---
> ?drivers/media/platform/rockchip/rga/rga.h??? |? 1 +
> ?4 files changed, 58 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
> index 8cdfe089fd636..2ed4f22a999d5 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
> @@ -624,6 +624,7 @@ const struct rga_hw rga2_hw = {
> ?	.max_width = MAX_WIDTH,
> ?	.min_height = MIN_HEIGHT,
> ?	.max_height = MAX_HEIGHT,
> +	.max_scaling_factor = MAX_SCALING_FACTOR,
> ?	.stride_alignment = 4,
> ?
> ?	.setup_cmdbuf = rga_hw_setup_cmdbuf,
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.h b/drivers/media/platform/rockchip/rga/rga-hw.h
> index f4752aa823051..fffcab0131225 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.h
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.h
> @@ -14,6 +14,7 @@
> ?
> ?#define MIN_WIDTH 34
> ?#define MIN_HEIGHT 34
> +#define MAX_SCALING_FACTOR 16
> ?
> ?#define RGA_TIMEOUT 500
> ?
> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
> index f02ae02de26ca..46dc94db6f85e 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -346,18 +346,47 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
> ?static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
> ?{
> ?	struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp;
> -	struct rockchip_rga *rga = video_drvdata(file);
> +	struct rga_ctx *ctx = file_to_rga_ctx(file);
> +	struct rockchip_rga *rga = ctx->rga;
> ?	const struct rga_hw *hw = rga->hw;
> ?	struct rga_fmt *fmt;
> +	u32 min_width = hw->min_width;
> +	u32 max_width = hw->max_width;
> +	u32 min_height = hw->min_height;
> +	u32 max_height = hw->max_height;
> ?
> ?	fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
> ?	if (!fmt)
> ?		fmt = &hw->formats[0];
> ?
> -	pix_fmt->width = clamp(pix_fmt->width,
> -			?????? hw->min_width, hw->max_width);
> -	pix_fmt->height = clamp(pix_fmt->height,
> -				hw->min_height, hw->max_height);
> +	if (V4L2_TYPE_IS_OUTPUT(f->type) &&
> +	??? v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx)->streaming) {

What if userspace wanted to get the buffer size computed, so it can allocate
externally before it calls streamoff ? Hans did mention recently that try
function should only be state aware if specified.

I'd like other reviewers feedback on what should be done here, of course writing
a spec would be ideal.

Nicolas

> +		min_width =
> +			MAX(min_width, DIV_ROUND_UP(ctx->out.pix.width,
> +						??? hw->max_scaling_factor));
> +		max_width = MIN(max_width,
> +				ctx->out.pix.width * hw->max_scaling_factor);
> +		min_height =
> +			MAX(min_height, DIV_ROUND_UP(ctx->out.pix.height,
> +						???? hw->max_scaling_factor));
> +		max_height = MIN(max_height,
> +				 ctx->out.pix.height * hw->max_scaling_factor);
> +	} else if (V4L2_TYPE_IS_CAPTURE(f->type) &&
> +		?? v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx)->streaming) {
> +		min_width =
> +			MAX(min_width, DIV_ROUND_UP(ctx->in.pix.width,
> +						??? hw->max_scaling_factor));
> +		max_width = MIN(max_width,
> +				ctx->in.pix.width * hw->max_scaling_factor);
> +		min_height =
> +			MAX(min_height, DIV_ROUND_UP(ctx->in.pix.height,
> +						???? hw->max_scaling_factor));
> +		max_height = MIN(max_height,
> +				 ctx->in.pix.height * hw->max_scaling_factor);
> +	}
> +
> +	pix_fmt->width = clamp(pix_fmt->width, min_width, max_width);
> +	pix_fmt->height = clamp(pix_fmt->height, min_height, max_height);
> ?
> ?	v4l2_fill_pixfmt_mp_aligned(pix_fmt, pix_fmt->pixelformat,
> ?				??? pix_fmt->width, pix_fmt->height, hw->stride_alignment);
> @@ -523,12 +552,33 @@ static int vidioc_s_selection(struct file *file, void *priv,
> ?	return ret;
> ?}
> ?
> +static bool check_scaling(const struct rga_hw *hw, u32 src_size, u32 dst_size)
> +{
> +	if (src_size < dst_size)
> +		return src_size * hw->max_scaling_factor >= dst_size;
> +	else
> +		return dst_size * hw->max_scaling_factor >= src_size;
> +}
> +
> ?static int vidioc_streamon(struct file *file, void *priv,
> ?			?? enum v4l2_buf_type type)
> ?{
> ?	struct rga_ctx *ctx = file_to_rga_ctx(file);
> ?	const struct rga_hw *hw = ctx->rga->hw;
> ?
> +	if ((V4L2_TYPE_IS_OUTPUT(type) &&
> +	???? v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx)->streaming) ||
> +	??? (V4L2_TYPE_IS_CAPTURE(type) &&
> +	???? v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx)->streaming)) {
> +		/*
> +		 * As the other side is already streaming,
> +		 * check that the max scaling factor isn't exceeded.
> +		 */
> +		if (!check_scaling(hw, ctx->in.pix.width, ctx->out.pix.width) ||
> +		??? !check_scaling(hw, ctx->in.pix.height, ctx->out.pix.height))
> +			return -EINVAL;
> +	}
> +
> ?	hw->setup_cmdbuf(ctx);
> ?
> ?	return v4l2_m2m_streamon(file, ctx->fh.m2m_ctx, type);
> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
> index 93162b118d069..d02d5730b4e3b 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -152,6 +152,7 @@ struct rga_hw {
> ?	size_t cmdbuf_size;
> ?	u32 min_width, min_height;
> ?	u32 max_width, max_height;
> +	u8 max_scaling_factor;
> ?	u8 stride_alignment;
> ?
> ?	void (*setup_cmdbuf)(struct rga_ctx *ctx);
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/0919085f/attachment.sig>

From nicolas at ndufresne.ca  Wed Dec 24 07:40:24 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 24 Dec 2025 10:40:24 -0500
Subject: [PATCH v2 12/22] media: rockchip: rga: use card type to specify
 rga type
In-Reply-To: <20251203-spu-rga3-v2-12-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
	 <20251203-spu-rga3-v2-12-989a67947f71@pengutronix.de>
Message-ID: <76ed32b0827b59a8e5c27f5aed0acad25b7346ee.camel@ndufresne.ca>

Le mercredi 03 d?cembre 2025 ? 16:52 +0100, Sven P?schel a ?crit?:
> In preparation of the RGA3 support add a filed to the rga_hw struct
> to specify the desired card type value. This allows the user to
> differentiate the RGA2 and RGA3 video device nodes.
> 
> Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?drivers/media/platform/rockchip/rga/rga-hw.c | 1 +
> ?drivers/media/platform/rockchip/rga/rga.c??? | 4 +++-
> ?drivers/media/platform/rockchip/rga/rga.h??? | 1 +
> ?3 files changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
> index 2ed4f22a999d5..8953960d33bc5 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
> @@ -617,6 +617,7 @@ static struct rga_fmt formats[] = {
> ?};
> ?
> ?const struct rga_hw rga2_hw = {
> +	.card_type = "rga2",
> ?	.formats = formats,
> ?	.num_formats = ARRAY_SIZE(formats),
> ?	.cmdbuf_size = RGA_CMDBUF_SIZE,
> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
> index 46dc94db6f85e..c9719c7bcfc1c 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -306,8 +306,10 @@ static const struct v4l2_file_operations rga_fops = {
> ?static int
> ?vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
> ?{
> +	struct rockchip_rga *rga = video_drvdata(file);
> +
> ?	strscpy(cap->driver, RGA_NAME, sizeof(cap->driver));
> -	strscpy(cap->card, "rockchip-rga", sizeof(cap->card));
> +	strscpy(cap->card, rga->hw->card_type, sizeof(cap->card));
> ?	strscpy(cap->bus_info, "platform:rga", sizeof(cap->bus_info));
> ?
> ?	return 0;
> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
> index d02d5730b4e3b..ee50f7f3ed601 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -147,6 +147,7 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
> ?};
> ?
> ?struct rga_hw {
> +	const char *card_type;
> ?	struct rga_fmt *formats;
> ?	u32 num_formats;
> ?	size_t cmdbuf_size;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/5afe3430/attachment-0001.sig>

From nicolas at ndufresne.ca  Wed Dec 24 07:41:44 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 24 Dec 2025 10:41:44 -0500
Subject: [PATCH v2 13/22] media: rockchip: rga: change offset to
 dma_addresses
In-Reply-To: <20251203-spu-rga3-v2-13-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
	 <20251203-spu-rga3-v2-13-989a67947f71@pengutronix.de>
Message-ID: <32a69cd80152bb7f52743a609a4c15cb56d008a2.camel@ndufresne.ca>

Hi,

Le mercredi 03 d?cembre 2025 ? 16:52 +0100, Sven P?schel a ?crit?:
> Change the offset to dma_addresses, as the current naming is misleading.
> The offset naming comes from the fact that it references the offset in
> the mapped iommu address space. But from the hardware point of view this
> is an address, as also pointed out by the register naming
> (e.g. RGA_DST_Y_RGB_BASE_ADDR). Therefore also change the type to
> dma_addr_t, as with an external iommu driver this would also be the
> correct type.
> 
> This change is a preparation for the RGA3 support, which uses an external
> iommu and therefore just gets an dma_addr_t for each buffer. The field
> renaming allows to reuse the existing fields of rga_vb_buffer to store
> these values.
> 
> Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?drivers/media/platform/rockchip/rga/rga-buf.c |? 12 +--
> ?drivers/media/platform/rockchip/rga/rga-hw.c? | 105 +++++++++++++------------
> -
> ?drivers/media/platform/rockchip/rga/rga.h???? |? 12 +--
> ?3 files changed, 64 insertions(+), 65 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c
> b/drivers/media/platform/rockchip/rga/rga-buf.c
> index 0c59a4d330888..8845e1f894f29 100644
> --- a/drivers/media/platform/rockchip/rga/rga-buf.c
> +++ b/drivers/media/platform/rockchip/rga/rga-buf.c
> @@ -118,7 +118,7 @@ static int rga_buf_prepare(struct vb2_buffer *vb)
> ?	size_t curr_desc = 0;
> ?	int i;
> ?	const struct v4l2_format_info *info;
> -	unsigned int offsets[VIDEO_MAX_PLANES];
> +	unsigned int dma_addrs[VIDEO_MAX_PLANES];
> ?
> ?	if (IS_ERR(f))
> ?		return PTR_ERR(f);
> @@ -142,18 +142,18 @@ static int rga_buf_prepare(struct vb2_buffer *vb)
> ?				 "Failed to map video buffer to RGA\n");
> ?			return n_desc;
> ?		}
> -		offsets[i] = curr_desc << PAGE_SHIFT;
> +		dma_addrs[i] = curr_desc << PAGE_SHIFT;
> ?		curr_desc += n_desc;
> ?	}
> ?
> ?	/* Fill the remaining planes */
> ?	info = v4l2_format_info(f->fmt->fourcc);
> ?	for (i = info->mem_planes; i < info->comp_planes; i++)
> -		offsets[i] = get_plane_offset(f, info, i);
> +		dma_addrs[i] = dma_addrs[0] + get_plane_offset(f, info, i);
> ?
> -	rbuf->offset.y_off = offsets[0];
> -	rbuf->offset.u_off = offsets[1];
> -	rbuf->offset.v_off = offsets[2];
> +	rbuf->dma_addrs.y_addr = dma_addrs[0];
> +	rbuf->dma_addrs.u_addr = dma_addrs[1];
> +	rbuf->dma_addrs.v_addr = dma_addrs[2];
> ?
> ?	return 0;
> ?}
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c
> b/drivers/media/platform/rockchip/rga/rga-hw.c
> index 8953960d33bc5..fe6f518aedd4e 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
> @@ -16,11 +16,11 @@ enum e_rga_start_pos {
> ?	RB = 3,
> ?};
> ?
> -struct rga_corners_addr_offset {
> -	struct rga_addr_offset left_top;
> -	struct rga_addr_offset right_top;
> -	struct rga_addr_offset left_bottom;
> -	struct rga_addr_offset right_bottom;
> +struct rga_corners_addrs {
> +	struct rga_addrs left_top;
> +	struct rga_addrs right_top;
> +	struct rga_addrs left_bottom;
> +	struct rga_addrs right_bottom;
> ?};
> ?
> ?static unsigned int rga_get_scaling(unsigned int src, unsigned int dst)
> @@ -36,48 +36,47 @@ static unsigned int rga_get_scaling(unsigned int src,
> unsigned int dst)
> ?	return (src > dst) ? ((dst << 16) / src) : ((src << 16) / dst);
> ?}
> ?
> -static struct rga_corners_addr_offset
> -rga_get_addr_offset(struct rga_frame *frm, struct rga_addr_offset *offset,
> -		??? unsigned int x, unsigned int y, unsigned int w, unsigned
> int h)
> +static struct rga_corners_addrs
> +rga_get_corner_addrs(struct rga_frame *frm, struct rga_addrs *addrs,
> +		???? unsigned int x, unsigned int y, unsigned int w, unsigned
> int h)
> ?{
> -	struct rga_corners_addr_offset offsets;
> -	struct rga_addr_offset *lt, *lb, *rt, *rb;
> +	struct rga_corners_addrs corner_addrs;
> +	struct rga_addrs *lt, *lb, *rt, *rb;
> ?	unsigned int x_div = 0,
> ?		???? y_div = 0, uv_stride = 0, pixel_width = 0;
> ?
> -	lt = &offsets.left_top;
> -	lb = &offsets.left_bottom;
> -	rt = &offsets.right_top;
> -	rb = &offsets.right_bottom;
> +	lt = &corner_addrs.left_top;
> +	lb = &corner_addrs.left_bottom;
> +	rt = &corner_addrs.right_top;
> +	rb = &corner_addrs.right_bottom;
> ?
> ?	x_div = frm->fmt->x_div;
> ?	y_div = frm->fmt->y_div;
> ?	uv_stride = frm->stride / x_div;
> ?	pixel_width = frm->stride / frm->pix.width;
> ?
> -	lt->y_off = offset->y_off + y * frm->stride + x * pixel_width;
> -	lt->u_off = offset->u_off + (y / y_div) * uv_stride + x / x_div;
> -	lt->v_off = offset->v_off + (y / y_div) * uv_stride + x / x_div;
> +	lt->y_addr = addrs->y_addr + y * frm->stride + x * pixel_width;
> +	lt->u_addr = addrs->u_addr + (y / y_div) * uv_stride + x / x_div;
> +	lt->v_addr = addrs->v_addr + (y / y_div) * uv_stride + x / x_div;
> ?
> -	lb->y_off = lt->y_off + (h - 1) * frm->stride;
> -	lb->u_off = lt->u_off + (h / y_div - 1) * uv_stride;
> -	lb->v_off = lt->v_off + (h / y_div - 1) * uv_stride;
> +	lb->y_addr = lt->y_addr + (h - 1) * frm->stride;
> +	lb->u_addr = lt->u_addr + (h / y_div - 1) * uv_stride;
> +	lb->v_addr = lt->v_addr + (h / y_div - 1) * uv_stride;
> ?
> -	rt->y_off = lt->y_off + (w - 1) * pixel_width;
> -	rt->u_off = lt->u_off + w / x_div - 1;
> -	rt->v_off = lt->v_off + w / x_div - 1;
> +	rt->y_addr = lt->y_addr + (w - 1) * pixel_width;
> +	rt->u_addr = lt->u_addr + w / x_div - 1;
> +	rt->v_addr = lt->v_addr + w / x_div - 1;
> ?
> -	rb->y_off = lb->y_off + (w - 1) * pixel_width;
> -	rb->u_off = lb->u_off + w / x_div - 1;
> -	rb->v_off = lb->v_off + w / x_div - 1;
> +	rb->y_addr = lb->y_addr + (w - 1) * pixel_width;
> +	rb->u_addr = lb->u_addr + w / x_div - 1;
> +	rb->v_addr = lb->v_addr + w / x_div - 1;
> ?
> -	return offsets;
> +	return corner_addrs;
> ?}
> ?
> -static struct rga_addr_offset *rga_lookup_draw_pos(struct
> -		rga_corners_addr_offset
> -		* offsets, u32 rotate_mode,
> -		u32 mirr_mode)
> +static struct rga_addrs *rga_lookup_draw_pos(struct rga_corners_addrs
> *corner_addrs,
> +					???? u32 rotate_mode,
> +					???? u32 mirr_mode)
> ?{
> ?	static enum e_rga_start_pos rot_mir_point_matrix[4][4] = {
> ?		{
> @@ -94,18 +93,18 @@ static struct rga_addr_offset *rga_lookup_draw_pos(struct
> ?		},
> ?	};
> ?
> -	if (!offsets)
> +	if (!corner_addrs)
> ?		return NULL;
> ?
> ?	switch (rot_mir_point_matrix[rotate_mode][mirr_mode]) {
> ?	case LT:
> -		return &offsets->left_top;
> +		return &corner_addrs->left_top;
> ?	case LB:
> -		return &offsets->left_bottom;
> +		return &corner_addrs->left_bottom;
> ?	case RT:
> -		return &offsets->right_top;
> +		return &corner_addrs->right_top;
> ?	case RB:
> -		return &offsets->right_bottom;
> +		return &corner_addrs->right_bottom;
> ?	}
> ?
> ?	return NULL;
> @@ -307,9 +306,9 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
> ?}
> ?
> ?static void rga_cmd_set_src_info(struct rga_ctx *ctx,
> -				 struct rga_addr_offset *offset)
> +				 struct rga_addrs *addrs)
> ?{
> -	struct rga_corners_addr_offset src_offsets;
> +	struct rga_corners_addrs src_corner_addrs;
> ?	u32 *dest = ctx->cmdbuf_virt;
> ?	unsigned int src_h, src_w, src_x, src_y;
> ?
> @@ -321,22 +320,22 @@ static void rga_cmd_set_src_info(struct rga_ctx *ctx,
> ?	/*
> ?	 * Calculate the source framebuffer base address with offset pixel.
> ?	 */
> -	src_offsets = rga_get_addr_offset(&ctx->in, offset,
> -					? src_x, src_y, src_w, src_h);
> +	src_corner_addrs = rga_get_corner_addrs(&ctx->in, addrs,
> +						src_x, src_y, src_w, src_h);
> ?
> ?	dest[(RGA_SRC_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
> -		src_offsets.left_top.y_off;
> +		src_corner_addrs.left_top.y_addr;
> ?	dest[(RGA_SRC_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
> -		src_offsets.left_top.u_off;
> +		src_corner_addrs.left_top.u_addr;
> ?	dest[(RGA_SRC_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
> -		src_offsets.left_top.v_off;
> +		src_corner_addrs.left_top.v_addr;
> ?}
> ?
> ?static void rga_cmd_set_dst_info(struct rga_ctx *ctx,
> -				 struct rga_addr_offset *offset)
> +				 struct rga_addrs *addrs)
> ?{
> -	struct rga_addr_offset *dst_offset;
> -	struct rga_corners_addr_offset offsets;
> +	struct rga_addrs *dst_addrs;
> +	struct rga_corners_addrs corner_addrs;
> ?	u32 *dest = ctx->cmdbuf_virt;
> ?	unsigned int dst_h, dst_w, dst_x, dst_y;
> ?	unsigned int mir_mode = 0;
> @@ -370,15 +369,15 @@ static void rga_cmd_set_dst_info(struct rga_ctx *ctx,
> ?	/*
> ?	 * Configure the dest framebuffer base address with pixel offset.
> ?	 */
> -	offsets = rga_get_addr_offset(&ctx->out, offset, dst_x, dst_y, dst_w,
> dst_h);
> -	dst_offset = rga_lookup_draw_pos(&offsets, rot_mode, mir_mode);
> +	corner_addrs = rga_get_corner_addrs(&ctx->out, addrs, dst_x, dst_y,
> dst_w, dst_h);
> +	dst_addrs = rga_lookup_draw_pos(&corner_addrs, rot_mode, mir_mode);
> ?
> ?	dest[(RGA_DST_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
> -		dst_offset->y_off;
> +		dst_addrs->y_addr;
> ?	dest[(RGA_DST_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
> -		dst_offset->u_off;
> +		dst_addrs->u_addr;
> ?	dest[(RGA_DST_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
> -		dst_offset->v_off;
> +		dst_addrs->v_addr;
> ?}
> ?
> ?static void rga_cmd_set_mode(struct rga_ctx *ctx)
> @@ -417,8 +416,8 @@ static void rga_cmd_set(struct rga_ctx *ctx,
> ?
> ?	rga_cmd_set_dst_addr(ctx, dst->dma_desc_pa);
> ?
> -	rga_cmd_set_src_info(ctx, &src->offset);
> -	rga_cmd_set_dst_info(ctx, &dst->offset);
> +	rga_cmd_set_src_info(ctx, &src->dma_addrs);
> +	rga_cmd_set_dst_info(ctx, &dst->dma_addrs);
> ?
> ?	rga_write(rga, RGA_CMD_BASE, ctx->cmdbuf_phy);
> ?
> diff --git a/drivers/media/platform/rockchip/rga/rga.h
> b/drivers/media/platform/rockchip/rga/rga.h
> index ee50f7f3ed601..772f7dff9a8e5 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -98,10 +98,10 @@ struct rockchip_rga {
> ?	const struct rga_hw *hw;
> ?};
> ?
> -struct rga_addr_offset {
> -	unsigned int y_off;
> -	unsigned int u_off;
> -	unsigned int v_off;
> +struct rga_addrs {
> +	dma_addr_t y_addr;
> +	dma_addr_t u_addr;
> +	dma_addr_t v_addr;
> ?};
> ?
> ?struct rga_vb_buffer {
> @@ -113,8 +113,8 @@ struct rga_vb_buffer {
> ?	dma_addr_t dma_desc_pa;
> ?	size_t n_desc;
> ?
> -	/* Plane offsets of this buffer into the mapping */
> -	struct rga_addr_offset offset;
> +	/* Plane DMA addresses after the MMU mapping of the buffer */
> +	struct rga_addrs dma_addrs;
> ?};
> ?
> ?static inline struct rga_vb_buffer *vb_to_rga(struct vb2_v4l2_buffer *vb)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/ad881cc1/attachment.sig>

From joaopeixoto at osyx.tech  Wed Dec 24 05:52:13 2025
From: joaopeixoto at osyx.tech (joaopeixoto at osyx.tech)
Date: Wed, 24 Dec 2025 13:52:13 +0000
Subject: [PATCH 1/5] dt-bindings: Add Bao IPC shared memory driver binding
In-Reply-To: <20251224135217.25350-1-joaopeixoto@osyx.tech>
References: <20251224135217.25350-1-joaopeixoto@osyx.tech>
Message-ID: <20251224135217.25350-2-joaopeixoto@osyx.tech>

From: Jo?o Peixoto <joaopeixoto at osyx.tech>

This patch adds a Device Tree binding for the Bao IPC shared memory
device, which provides a standardized description of the hardware
interface used for inter-VM communication in Bao-based systems.

The binding documents the following properties:

  - compatible: "bao,ipcshmem"
  - reg: Memory region for the shared memory device
  - id: Unique device identifier
  - read-channel: [offset, size] for reading from the shared memory
  - write-channel: [offset, size] for writing to the shared memory
  - interrupts: Interrupts used by the device

This enables kernel drivers and userspace tools to correctly
instantiate and configure Bao IPC shared memory devices based
on the DT description, facilitating efficient communication
between VMs.

Signed-off-by: Jo?o Peixoto <joaopeixoto at osyx.tech>
---
 .../devicetree/bindings/bao/ipcshmem.yaml     | 99 +++++++++++++++++++
 .../devicetree/bindings/vendor-prefixes.yaml  |  2 +
 2 files changed, 101 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/bao/ipcshmem.yaml

diff --git a/Documentation/devicetree/bindings/bao/ipcshmem.yaml b/Documentation/devicetree/bindings/bao/ipcshmem.yaml
new file mode 100644
index 000000000000..398ac610c29f
--- /dev/null
+++ b/Documentation/devicetree/bindings/bao/ipcshmem.yaml
@@ -0,0 +1,99 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/bao/ipcshmem.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Bao IPC Shared Memory Device
+
+maintainers:
+  - Jos? Martins <jose at osyx.tech>
+  - David Cerdeira <davidmcerdeira at osyx.tech>
+  - Jo?o Peixoto <joaopeixoto at osyx.tech>
+
+description: |
+  Shared memory based communication device for Bao hypervisor guests.
+  It allows the kernel to interface with guests running under
+	the Bao hypervisor, providing a character device interface
+	for exchanging data through dedicated shared-memory regions.
+
+properties:
+  compatible:
+    const: "bao,ipcshmem"
+
+  reg:
+    description: |
+      Memory resource for the shared memory device.
+    maxItems: 4
+    type: array
+    items:
+      type: integer
+
+  id:
+    description: Driver instance ID
+    type: integer
+    minimum: 0
+
+  read-channel:
+    description: |
+      Defines the shared-memory region used by the guest ? host data path.
+
+      The value is a 2-cell array describing a sub-region inside the main
+      `reg` area:
+        - The first cell is the byte offset from the beginning of the
+          shared-memory region specified in `reg`.
+        - The second cell is the size of the readable region in bytes.
+
+      The driver will only read data from this sub-region.
+    type: array
+    items:
+      type: integer
+    minItems: 2
+    maxItems: 2
+
+  write-channel:
+    description: |
+      Defines the shared-memory region used by the host ? guest data path.
+
+      The value is a 2-cell array describing a sub-region inside the main
+      `reg` area:
+        - The first cell is the byte offset from the beginning of the
+          shared-memory region specified in `reg`.
+        - The second cell is the size of the writable region in bytes.
+
+      The driver will only write data into this sub-region.
+    type: array
+    items:
+      type: integer
+    minItems: 2
+    maxItems: 2
+
+  interrupts:
+    description: |
+      Interrupt specification for the device.
+    type: array
+    items:
+      type: integer
+    minItems: 3
+    maxItems: 3
+
+required:
+  - compatible
+  - reg
+  - id
+  - read-channel
+  - write-channel
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    bao-ipc at f0000000 {
+        compatible = "bao,ipcshmem";
+        reg = <0x0 0xf0000000 0x0 0x00010000>;
+        read-channel = <0x0 0x2000>;
+        write-channel = <0x2000 0x2000>;
+        interrupts = <0 52 1>;
+        id = <0>;
+    };
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index c7591b2aec2a..c047fbd6b91a 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -223,6 +223,8 @@ patternProperties:
     description: Shenzhen AZW Technology Co., Ltd.
   "^baikal,.*":
     description: BAIKAL ELECTRONICS, JSC
+  "^bao,.*":
+    description: Bao Hypervisor
   "^bananapi,.*":
     description: BIPAI KEJI LIMITED
   "^beacon,.*":
-- 
2.43.0



From nicolas at ndufresne.ca  Wed Dec 24 07:50:08 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 24 Dec 2025 10:50:08 -0500
Subject: [PATCH v2 14/22] media: rockchip: rga: support external iommus
In-Reply-To: <20251203-spu-rga3-v2-14-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
	 <20251203-spu-rga3-v2-14-989a67947f71@pengutronix.de>
Message-ID: <c5b6707e3e6748bf923aaf34db1ae231c7e121ad.camel@ndufresne.ca>

Le mercredi 03 d?cembre 2025 ? 16:52 +0100, Sven P?schel a ?crit?:
> In preparation for the RGA3 add support for external iommus. This is a
> transition step to just disable the RGA2 specific mmu table setup code.
> 
> Currently a simple rga_hw struct field is used to set the internal iommu.
> But to handle the case of more sophisticated detection mechanisms
> (e.g. check for an iommu property in the device tree), it is abstracted
> by an inline function.
> 
> Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
> ---
> ?drivers/media/platform/rockchip/rga/rga-buf.c | 46 ++++++++++++++++-----------
> ?drivers/media/platform/rockchip/rga/rga-hw.c? |? 1 +
> ?drivers/media/platform/rockchip/rga/rga.c???? | 11 +++++--
> ?drivers/media/platform/rockchip/rga/rga.h???? |? 6 ++++
> ?4 files changed, 43 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
> index 8845e1f894f29..e8d1e2e579140 100644
> --- a/drivers/media/platform/rockchip/rga/rga-buf.c
> +++ b/drivers/media/platform/rockchip/rga/rga-buf.c
> @@ -12,6 +12,7 @@
> ?#include <media/v4l2-ioctl.h>
> ?#include <media/v4l2-mem2mem.h>
> ?#include <media/videobuf2-dma-sg.h>
> +#include <media/videobuf2-dma-contig.h>
> ?#include <media/videobuf2-v4l2.h>
> ?
> ?#include "rga.h"
> @@ -79,14 +80,16 @@ static int rga_buf_init(struct vb2_buffer *vb)
> ?	struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type);
> ?	size_t n_desc = 0;
> ?
> -	n_desc = DIV_ROUND_UP(f->size, PAGE_SIZE);
> +	if (rga_has_internal_iommu(rga)) {
> +		n_desc = DIV_ROUND_UP(f->size, PAGE_SIZE);

n_desc is not used outside of this scope, perhap drop the definition with the 0
init, and use:

		const size_t n_desc = DIV_ROUND_UP(f->size, PAGE_SIZE);
		
> ?
> -	rbuf->n_desc = n_desc;
> -	rbuf->dma_desc = dma_alloc_coherent(rga->dev,
> -					??? rbuf->n_desc * sizeof(*rbuf->dma_desc),
> -					??? &rbuf->dma_desc_pa, GFP_KERNEL);
> -	if (!rbuf->dma_desc)
> -		return -ENOMEM;
> +		rbuf->n_desc = n_desc;
> +		rbuf->dma_desc = dma_alloc_coherent(rga->dev,
> +						??? rbuf->n_desc * sizeof(*rbuf->dma_desc),
> +						??? &rbuf->dma_desc_pa, GFP_KERNEL);
> +		if (!rbuf->dma_desc)
> +			return -ENOMEM;
> +	}
> ?
> ?	return 0;
> ?}
> @@ -133,17 +136,21 @@ static int rga_buf_prepare(struct vb2_buffer *vb)
> ?	for (i = 0; i < vb->num_planes; i++) {
> ?		vb2_set_plane_payload(vb, i, f->pix.plane_fmt[i].sizeimage);
> ?
> -		/* Create local MMU table for RGA */
> -		n_desc = fill_descriptors(&rbuf->dma_desc[curr_desc],
> -					? rbuf->n_desc - curr_desc,
> -					? vb2_dma_sg_plane_desc(vb, i));
> -		if (n_desc < 0) {
> -			v4l2_err(&ctx->rga->v4l2_dev,
> -				 "Failed to map video buffer to RGA\n");
> -			return n_desc;
> +		if (rga_has_internal_iommu(ctx->rga)) {
> +			/* Create local MMU table for RGA */
> +			n_desc = fill_descriptors(&rbuf->dma_desc[curr_desc],
> +						? rbuf->n_desc - curr_desc,
> +						? vb2_dma_sg_plane_desc(vb, i));
> +			if (n_desc < 0) {
> +				v4l2_err(&ctx->rga->v4l2_dev,
> +					 "Failed to map video buffer to RGA\n");
> +				return n_desc;
> +			}
> +			dma_addrs[i] = curr_desc << PAGE_SHIFT;
> +			curr_desc += n_desc;
> +		} else {
> +			dma_addrs[i] = vb2_dma_contig_plane_dma_addr(vb, i);
> ?		}
> -		dma_addrs[i] = curr_desc << PAGE_SHIFT;
> -		curr_desc += n_desc;
> ?	}
> ?
> ?	/* Fill the remaining planes */
> @@ -173,8 +180,9 @@ static void rga_buf_cleanup(struct vb2_buffer *vb)
> ?	struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
> ?	struct rockchip_rga *rga = ctx->rga;
> ?
> -	dma_free_coherent(rga->dev, rbuf->n_desc * sizeof(*rbuf->dma_desc),
> -			? rbuf->dma_desc, rbuf->dma_desc_pa);
> +	if (rga_has_internal_iommu(rga))
> +		dma_free_coherent(rga->dev, rbuf->n_desc * sizeof(*rbuf->dma_desc),
> +				? rbuf->dma_desc, rbuf->dma_desc_pa);
> ?}
> ?
> ?static void rga_buf_return_buffers(struct vb2_queue *q,
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
> index fe6f518aedd4e..fb0389ae8e132 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
> @@ -617,6 +617,7 @@ static struct rga_fmt formats[] = {
> ?
> ?const struct rga_hw rga2_hw = {
> ?	.card_type = "rga2",
> +	.has_internal_iommu = true,
> ?	.formats = formats,
> ?	.num_formats = ARRAY_SIZE(formats),
> ?	.cmdbuf_size = RGA_CMDBUF_SIZE,
> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
> index c9719c7bcfc1c..f28ec88c186fa 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -23,6 +23,7 @@
> ?#include <media/v4l2-ioctl.h>
> ?#include <media/v4l2-mem2mem.h>
> ?#include <media/videobuf2-dma-sg.h>
> +#include <media/videobuf2-dma-contig.h>
> ?#include <media/videobuf2-v4l2.h>
> ?
> ?#include "rga.h"
> @@ -95,13 +96,16 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
> ?	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
> ?	src_vq->drv_priv = ctx;
> ?	src_vq->ops = &rga_qops;
> -	src_vq->mem_ops = &vb2_dma_sg_memops;
> +	src_vq->mem_ops = &vb2_dma_contig_memops;

That's a bit I'm less knowledgeable here, since I never used the sg_memops in
any of my work, but what is the consequence ? (appart from gaining external
iommu support)

> ?	src_vq->gfp_flags = __GFP_DMA32;
> ?	src_vq->buf_struct_size = sizeof(struct rga_vb_buffer);
> ?	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
> ?	src_vq->lock = &ctx->rga->mutex;
> ?	src_vq->dev = ctx->rga->v4l2_dev.dev;
> ?
> +	if (rga_has_internal_iommu(ctx->rga))
> +		src_vq->mem_ops = &vb2_dma_sg_memops;
> +
> ?	ret = vb2_queue_init(src_vq);
> ?	if (ret)
> ?		return ret;
> @@ -110,13 +114,16 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
> ?	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
> ?	dst_vq->drv_priv = ctx;
> ?	dst_vq->ops = &rga_qops;
> -	dst_vq->mem_ops = &vb2_dma_sg_memops;
> +	dst_vq->mem_ops = &vb2_dma_contig_memops;
> ?	dst_vq->gfp_flags = __GFP_DMA32;
> ?	dst_vq->buf_struct_size = sizeof(struct rga_vb_buffer);
> ?	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
> ?	dst_vq->lock = &ctx->rga->mutex;
> ?	dst_vq->dev = ctx->rga->v4l2_dev.dev;
> ?
> +	if (rga_has_internal_iommu(ctx->rga))
> +		dst_vq->mem_ops = &vb2_dma_sg_memops;
> +
> ?	return vb2_queue_init(dst_vq);
> ?}
> ?
> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
> index 772f7dff9a8e5..fc81bc5562792 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -148,6 +148,7 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
> ?
> ?struct rga_hw {
> ?	const char *card_type;
> +	bool has_internal_iommu;
> ?	struct rga_fmt *formats;
> ?	u32 num_formats;
> ?	size_t cmdbuf_size;
> @@ -163,6 +164,11 @@ struct rga_hw {
> ?	void (*get_version)(struct rockchip_rga *rga);
> ?};
> ?
> +static inline bool rga_has_internal_iommu(const struct rockchip_rga *rga)
> +{
> +	return rga->hw->has_internal_iommu;
> +}
> +
> ?extern const struct rga_hw rga2_hw;
> ?
> ?#endif
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/12e5f5dc/attachment.sig>

From nicolas at ndufresne.ca  Wed Dec 24 07:50:42 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 24 Dec 2025 10:50:42 -0500
Subject: [PATCH v2 15/22] media: rockchip: rga: share the interrupt when
 an external iommu is used
In-Reply-To: <20251203-spu-rga3-v2-15-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
	 <20251203-spu-rga3-v2-15-989a67947f71@pengutronix.de>
Message-ID: <d09691bfde08f80e4cb47cc365d86bd53d0aaa7c.camel@ndufresne.ca>

Le mercredi 03 d?cembre 2025 ? 16:52 +0100, Sven P?schel a ?crit?:
> From: Michael Olbrich <m.olbrich at pengutronix.de>
> 
> The RGA3 and the corresponding iommu share the interrupt. So in that
> case, request a shared interrupt so that the iommu driver can request
> it as well.
> 
> Signed-off-by: Michael Olbrich <m.olbrich at pengutronix.de>
> Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?drivers/media/platform/rockchip/rga/rga.c | 3 ++-
> ?1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga.c
> b/drivers/media/platform/rockchip/rga/rga.c
> index f28ec88c186fa..1bfc4021f4a7b 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -718,7 +718,8 @@ static int rga_probe(struct platform_device *pdev)
> ?		goto err_put_clk;
> ?	}
> ?
> -	ret = devm_request_irq(rga->dev, irq, rga_isr, 0,
> +	ret = devm_request_irq(rga->dev, irq, rga_isr,
> +			?????? rga_has_internal_iommu(rga) ? 0 : IRQF_SHARED,
> ?			?????? dev_name(rga->dev), rga);
> ?	if (ret < 0) {
> ?		dev_err(rga->dev, "failed to request irq\n");
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/f34abb7d/attachment.sig>

From gregkh at linuxfoundation.org  Wed Dec 24 07:53:34 2025
From: gregkh at linuxfoundation.org (Greg KH)
Date: Wed, 24 Dec 2025 16:53:34 +0100
Subject: [PATCH 2/5] virt: add Bao IPC shared memory driver
In-Reply-To: <20251224135217.25350-3-joaopeixoto@osyx.tech>
References: <20251224135217.25350-1-joaopeixoto@osyx.tech>
 <20251224135217.25350-3-joaopeixoto@osyx.tech>
Message-ID: <2025122459-blimp-bobble-c772@gregkh>

On Wed, Dec 24, 2025 at 01:52:14PM +0000, joaopeixoto at osyx.tech wrote:
> From: Jo?o Peixoto <joaopeixoto at osyx.tech>
> 
> Add a new driver providing an interface for communication with guests
> hosted by the Bao hypervisor using shared-memory channels. The driver
> exposes read/write regions defined in device tree and notifies the
> hypervisor via an architecture-specific hypercall (SMC/HVC on ARM and
> SBI ecall on RISC-V).
> 
> The patch introduces:
>   - drivers/bao/ with the initial Bao IPC shared-memory implementation
>   - Kconfig entry enabling BAO_SHMEM
>   - Makefile integration for building the driver
>   - A character device interface supporting mmap(), read(), and write()
>   - Platform driver support using DT properties for channel layout
> 
> Each device instance maps its assigned shared-memory region, validates
> read/write channel configuration, and exposes a /dev/baoipc<N> node
> used by user space to exchange data with Bao guests.
> 
> Signed-off-by: Jo?o Peixoto <joaopeixoto at osyx.tech>
> ---
>  drivers/virt/Kconfig                 |   2 +
>  drivers/virt/Makefile                |   1 +
>  drivers/virt/bao/Kconfig             |   3 +
>  drivers/virt/bao/Makefile            |   3 +
>  drivers/virt/bao/ipcshmem/Kconfig    |   9 +
>  drivers/virt/bao/ipcshmem/Makefile   |   3 +
>  drivers/virt/bao/ipcshmem/ipcshmem.c | 539 +++++++++++++++++++++++++++

Why two subdirs deep for a single .c file?  Why not just put this in
drivers/virt/ instead?

thanks,

greg k-h


From nicolas at ndufresne.ca  Wed Dec 24 07:54:36 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 24 Dec 2025 10:54:36 -0500
Subject: [PATCH v2 16/22] media: rockchip: rga: remove size from
 rga_frame
In-Reply-To: <20251203-spu-rga3-v2-16-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
	 <20251203-spu-rga3-v2-16-989a67947f71@pengutronix.de>
Message-ID: <7c25b77adbadf5f325ce15996ff609c893a1e7b8.camel@ndufresne.ca>

Le mercredi 03 d?cembre 2025 ? 16:52 +0100, Sven P?schel a ?crit?:
> The size member is only used for the mmu page table mapping.
> Therefore avoid storing the value and instead only calculate it
> in place. This also avoids the calculation entirely when an external
> iommu is used.
> 
> Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
> ---
> ?drivers/media/platform/rockchip/rga/rga-buf.c | 6 +++++-
> ?drivers/media/platform/rockchip/rga/rga.c???? | 8 ++------
> ?drivers/media/platform/rockchip/rga/rga.h???? | 1 -
> ?3 files changed, 7 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
> index e8d1e2e579140..8de6b9c3fd615 100644
> --- a/drivers/media/platform/rockchip/rga/rga-buf.c
> +++ b/drivers/media/platform/rockchip/rga/rga-buf.c
> @@ -79,9 +79,13 @@ static int rga_buf_init(struct vb2_buffer *vb)
> ?	struct rockchip_rga *rga = ctx->rga;
> ?	struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type);
> ?	size_t n_desc = 0;
> +	u32 size = 0;
> +	u8 i;

Move in it the scope it is being used.

> ?
> ?	if (rga_has_internal_iommu(rga)) {

though, after looking more attentively, this function is a no-op when the is an
external iommu. Using an early return would make this so much clearer, and you
can then drop the indent.

	if (rga_has_internal_iommu(rga))
		return 0;

Perhaps a comment to be applied on patch 14 though.

> -		n_desc = DIV_ROUND_UP(f->size, PAGE_SIZE);
> +		for (i = 0; i < f->pix.num_planes; i++)
> +			size += f->pix.plane_fmt[i].sizeimage;
> +		n_desc = DIV_ROUND_UP(size, PAGE_SIZE);
> ?
> ?		rbuf->n_desc = n_desc;
> ?		rbuf->dma_desc = dma_alloc_coherent(rga->dev,
> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
> index 1bfc4021f4a7b..0d7b0bcac950e 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -221,7 +221,6 @@ static int rga_open(struct file *file)
> ?	};
> ?
> ?	def_frame.stride = (def_width * def_frame.fmt->depth) >> 3;
> -	def_frame.size = def_frame.stride * def_height;
> ?
> ?	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> ?	if (!ctx)
> @@ -428,9 +427,6 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
> ?	frm = rga_get_frame(ctx, f->type);
> ?	if (IS_ERR(frm))
> ?		return PTR_ERR(frm);
> -	frm->size = 0;
> -	for (i = 0; i < pix_fmt->num_planes; i++)
> -		frm->size += pix_fmt->plane_fmt[i].sizeimage;
> ?	frm->fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
> ?	frm->stride = pix_fmt->plane_fmt[0].bytesperline;
> ?
> @@ -443,10 +439,10 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
> ?	frm->pix = *pix_fmt;
> ?
> ?	v4l2_dbg(debug, 1, &rga->v4l2_dev,
> -		 "[%s] fmt - %p4cc %dx%d (stride %d, sizeimage %d)\n",
> +		 "[%s] fmt - %p4cc %dx%d (stride %d)\n",
> ?		? V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
> ?		? &frm->fmt->fourcc, pix_fmt->width, pix_fmt->height,
> -		? frm->stride, frm->size);
> +		? frm->stride);
> ?
> ?	for (i = 0; i < pix_fmt->num_planes; i++) {
> ?		v4l2_dbg(debug, 1, &rga->v4l2_dev,
> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
> index fc81bc5562792..466d568b9e614 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -37,7 +37,6 @@ struct rga_frame {
> ?
> ?	/* Variables that can calculated once and reused */
> ?	u32 stride;
> -	u32 size;
> ?};
> ?
> ?struct rga_dma_desc {
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/08066363/attachment.sig>

From gregkh at linuxfoundation.org  Wed Dec 24 07:54:40 2025
From: gregkh at linuxfoundation.org (Greg KH)
Date: Wed, 24 Dec 2025 16:54:40 +0100
Subject: [PATCH 2/5] virt: add Bao IPC shared memory driver
In-Reply-To: <20251224135217.25350-3-joaopeixoto@osyx.tech>
References: <20251224135217.25350-1-joaopeixoto@osyx.tech>
 <20251224135217.25350-3-joaopeixoto@osyx.tech>
Message-ID: <2025122401-drainer-pedigree-45ae@gregkh>

On Wed, Dec 24, 2025 at 01:52:14PM +0000, joaopeixoto at osyx.tech wrote:
> +struct class *cl;

Why not just use the misc device api instead?  No need for a full class
for just one char device, right?  Or even if you have multiple ones,
again, no need for a whole class.  That should make the code much
simpler overall.

thanks,

greg k-h


From joaopeixoto at osyx.tech  Wed Dec 24 05:52:14 2025
From: joaopeixoto at osyx.tech (joaopeixoto at osyx.tech)
Date: Wed, 24 Dec 2025 13:52:14 +0000
Subject: [PATCH 2/5] virt: add Bao IPC shared memory driver
In-Reply-To: <20251224135217.25350-1-joaopeixoto@osyx.tech>
References: <20251224135217.25350-1-joaopeixoto@osyx.tech>
Message-ID: <20251224135217.25350-3-joaopeixoto@osyx.tech>

From: Jo?o Peixoto <joaopeixoto at osyx.tech>

Add a new driver providing an interface for communication with guests
hosted by the Bao hypervisor using shared-memory channels. The driver
exposes read/write regions defined in device tree and notifies the
hypervisor via an architecture-specific hypercall (SMC/HVC on ARM and
SBI ecall on RISC-V).

The patch introduces:
  - drivers/bao/ with the initial Bao IPC shared-memory implementation
  - Kconfig entry enabling BAO_SHMEM
  - Makefile integration for building the driver
  - A character device interface supporting mmap(), read(), and write()
  - Platform driver support using DT properties for channel layout

Each device instance maps its assigned shared-memory region, validates
read/write channel configuration, and exposes a /dev/baoipc<N> node
used by user space to exchange data with Bao guests.

Signed-off-by: Jo?o Peixoto <joaopeixoto at osyx.tech>
---
 drivers/virt/Kconfig                 |   2 +
 drivers/virt/Makefile                |   1 +
 drivers/virt/bao/Kconfig             |   3 +
 drivers/virt/bao/Makefile            |   3 +
 drivers/virt/bao/ipcshmem/Kconfig    |   9 +
 drivers/virt/bao/ipcshmem/Makefile   |   3 +
 drivers/virt/bao/ipcshmem/ipcshmem.c | 539 +++++++++++++++++++++++++++
 7 files changed, 560 insertions(+)
 create mode 100644 drivers/virt/bao/Kconfig
 create mode 100644 drivers/virt/bao/Makefile
 create mode 100644 drivers/virt/bao/ipcshmem/Kconfig
 create mode 100644 drivers/virt/bao/ipcshmem/Makefile
 create mode 100644 drivers/virt/bao/ipcshmem/ipcshmem.c

diff --git a/drivers/virt/Kconfig b/drivers/virt/Kconfig
index 52eb7e4ba71f..cb98c4c52fd1 100644
--- a/drivers/virt/Kconfig
+++ b/drivers/virt/Kconfig
@@ -47,6 +47,8 @@ source "drivers/virt/nitro_enclaves/Kconfig"
 
 source "drivers/virt/acrn/Kconfig"
 
+source "drivers/virt/bao/Kconfig"
+
 endif
 
 source "drivers/virt/coco/Kconfig"
diff --git a/drivers/virt/Makefile b/drivers/virt/Makefile
index f29901bd7820..623a671f8711 100644
--- a/drivers/virt/Makefile
+++ b/drivers/virt/Makefile
@@ -10,3 +10,4 @@ obj-y				+= vboxguest/
 obj-$(CONFIG_NITRO_ENCLAVES)	+= nitro_enclaves/
 obj-$(CONFIG_ACRN_HSM)		+= acrn/
 obj-y				+= coco/
+obj-$(CONFIG_BAO_SHMEM)		+= bao/
diff --git a/drivers/virt/bao/Kconfig b/drivers/virt/bao/Kconfig
new file mode 100644
index 000000000000..4f7929d57475
--- /dev/null
+++ b/drivers/virt/bao/Kconfig
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+source "drivers/virt/bao/ipcshmem/Kconfig"
diff --git a/drivers/virt/bao/Makefile b/drivers/virt/bao/Makefile
new file mode 100644
index 000000000000..68f5d3f282c4
--- /dev/null
+++ b/drivers/virt/bao/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_BAO_SHMEM) += ipcshmem/
diff --git a/drivers/virt/bao/ipcshmem/Kconfig b/drivers/virt/bao/ipcshmem/Kconfig
new file mode 100644
index 000000000000..42690073e819
--- /dev/null
+++ b/drivers/virt/bao/ipcshmem/Kconfig
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+config BAO_SHMEM
+	tristate "Bao hypervisor shared memory support"
+
+	help
+	This enables support for Bao shared memory communication.
+	It allows the kernel to interface with guests running under
+	the Bao hypervisor, providing a character device interface
+	for exchanging data through dedicated shared-memory regions.
diff --git a/drivers/virt/bao/ipcshmem/Makefile b/drivers/virt/bao/ipcshmem/Makefile
new file mode 100644
index 000000000000..e027dcdb06aa
--- /dev/null
+++ b/drivers/virt/bao/ipcshmem/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_BAO_SHMEM) += bao.o
+bao-objs += ipcshmem.o
diff --git a/drivers/virt/bao/ipcshmem/ipcshmem.c b/drivers/virt/bao/ipcshmem/ipcshmem.c
new file mode 100644
index 000000000000..cadb79bfca6e
--- /dev/null
+++ b/drivers/virt/bao/ipcshmem/ipcshmem.c
@@ -0,0 +1,539 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Bao Hypervisor IPC Through Shared-memory Driver
+ *
+ * Copyright (c) Bao Project and Contributors. All rights reserved.
+ *
+ * Authors:
+ *	David Cerdeira <davidmcerdeira at osyx.tech>
+ *	Jos? Martins <jose at osyx.tech>
+ *	Jo?o Peixoto <joaopeixoto at osyx.tech>
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/poll.h>
+#include <linux/platform_device.h>
+#include <linux/ioctl.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/mm.h>
+
+#if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
+#include <linux/arm-smccc.h>
+#include <asm/memory.h>
+#elif CONFIG_RISCV
+#include <asm/sbi.h>
+#endif
+
+#define DEV_NAME "baoipc"
+#define MAX_DEVICES 16
+#define NAME_LEN 32
+
+static dev_t bao_ipcshmem_devt;
+struct class *cl;
+
+/**
+ * struct bao_ipcshmem - Bao IPC shared memory device
+ * @cdev: Character device interface
+ * @dev: Device structure
+ * @id: Device instance ID
+ * @label: Name/label of the device
+ * @read_base: Base address of the read channel
+ * @read_size: Size of the read channel
+ * @write_base: Base address of the write channel
+ * @write_size: Size of the write channel
+ * @physical_base: Physical memory base address
+ * @shmem_size: Total size of the shared memory region
+ */
+struct bao_ipcshmem {
+	struct cdev cdev;
+	struct device *dev;
+	int id;
+	char label[NAME_LEN];
+	void *read_base;
+	size_t read_size;
+	void *write_base;
+	size_t write_size;
+	phys_addr_t *physical_base;
+	size_t shmem_size;
+};
+
+#ifdef CONFIG_ARM64
+/**
+ * bao_ipcshmem_notify - Notify the Bao hypervisor of an IPC shared memory event (ARM64)
+ * @dev: IPC shared memory device
+ *
+ * Executes a fast SMC hypercall to notify the hypervisor of an event
+ * associated with the given IPC shared memory device.
+ *
+ * Return: Hypercall return value.
+ */
+static uint64_t bao_ipcshmem_notify(struct bao_ipcshmem *dev)
+{
+	register uint64_t x0 asm("x0") =
+		ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64,
+				   ARM_SMCCC_OWNER_VENDOR_HYP, 1);
+	register uint64_t x1 asm("x1") = dev->id;
+	register uint64_t x2 asm("x2") = 0;
+
+	asm volatile("hvc 0\t\n" : "=r"(x0) : "r"(x0), "r"(x1), "r"(x2));
+
+	return x0;
+}
+#elif CONFIG_ARM
+/**
+ * bao_ipcshmem_notify - Notify the Bao hypervisor of an IPC shared memory event (ARM)
+ * @dev: IPC shared memory device
+ *
+ * Executes a fast SMC hypercall to notify the hypervisor of an event
+ * associated with the given IPC shared memory device.
+ *
+ * Return: Hypercall return value.
+ */
+static uint32_t bao_ipcshmem_notify(struct bao_ipcshmem *dev)
+{
+	register uint32_t r0 asm("r0") =
+		ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32,
+				   ARM_SMCCC_OWNER_VENDOR_HYP, 1);
+	register uint32_t r1 asm("r1") = dev->id;
+	register uint32_t r2 asm("r2") = 0;
+
+	asm volatile("hvc #0\t\n" : "=r"(r0) : "r"(r0), "r"(r1), "r"(r2));
+
+	return r0;
+}
+#elif CONFIG_RISCV
+/**
+ * bao_ipcshmem_notify - Notify the Bao hypervisor of an IPC shared memory event (RISC-V)
+ * @dev: IPC shared memory device
+ *
+ * Executes an SBI call to notify the Bao hypervisor of an IPC shared memory event.
+ *
+ * Return: SBI call error code.
+ */
+static uint64_t bao_ipcshmem_notify(struct bao_ipcshmem *dev)
+{
+	struct sbiret ret = sbi_ecall(0x08000ba0, 1, dev->id, 0, 0, 0, 0, 0);
+
+	return ret.error;
+}
+#endif
+
+/**
+ * bao_ipcshmem_mmap_fops - mmap handler for IPC shared memory
+ * @filp: File pointer
+ * @vma: Virtual memory area
+ *
+ * Maps the physical shared memory of the Bao IPC device into
+ * userspace using remap_pfn_range.
+ *
+ * Return: 0 on success, -EFAULT on failure.
+ */
+static int bao_ipcshmem_mmap_fops(struct file *filp, struct vm_area_struct *vma)
+{
+	struct bao_ipcshmem *bao = filp->private_data;
+	unsigned long vsize = vma->vm_end - vma->vm_start;
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	phys_addr_t paddr;
+
+	if (WARN_ON_ONCE(!bao))
+		return -ENODEV;
+
+	if (!vsize)
+		return -EINVAL;
+
+	if (offset >= bao->shmem_size)
+		return -EINVAL;
+
+	if (vsize > bao->shmem_size - offset)
+		return -EINVAL;
+
+	paddr = (phys_addr_t)bao->physical_base + offset;
+
+	if (!PAGE_ALIGNED(paddr))
+		return -EINVAL;
+
+	if (remap_pfn_range(vma, vma->vm_start,
+			    paddr >> PAGE_SHIFT,
+			    vsize, vma->vm_page_prot))
+		return -EFAULT;
+
+	return 0;
+}
+
+/**
+ * bao_ipcshmem_read_fops - read handler for IPC shared memory
+ * @filp: File pointer
+ * @buf: Userspace buffer
+ * @count: Number of bytes to read
+ * @ppos: File offset
+ *
+ * Copies data from the Bao IPC read buffer to userspace.
+ *
+ * Return: Number of bytes read, or 0 if EOF.
+ */
+static ssize_t bao_ipcshmem_read_fops(struct file *filp, char __user *buf,
+				      size_t count, loff_t *ppos)
+{
+	struct bao_ipcshmem *bao = filp->private_data;
+	size_t available;
+
+	if (WARN_ON_ONCE(!bao || !buf || !ppos))
+		return -EINVAL;
+
+	if (*ppos >= bao->read_size)
+		return 0;
+
+	available = bao->read_size - *ppos;
+	if (count > available)
+		count = available;
+
+	if (copy_to_user(buf, bao->read_base + *ppos, count))
+		return -EFAULT;
+
+	*ppos += count;
+	return count;
+}
+
+/**
+ * bao_ipcshmem_write_fops - write handler for IPC shared memory
+ * @filp: File pointer
+ * @buf: Userspace buffer
+ * @count: Number of bytes to write
+ * @ppos: File offset
+ *
+ * Copies data from userspace to the Bao IPC write buffer and
+ * notifies the hypervisor of the update.
+ *
+ * Return: Number of bytes written.
+ */
+static ssize_t bao_ipcshmem_write_fops(struct file *filp, const char __user *buf,
+				       size_t count, loff_t *ppos)
+{
+	struct bao_ipcshmem *bao = filp->private_data;
+	size_t avail;
+
+	if (WARN_ON_ONCE(!bao || !buf || !ppos))
+		return -EINVAL;
+
+	if (*ppos >= bao->write_size)
+		return 0;
+
+	avail = bao->write_size - *ppos;
+	if (count > avail)
+		count = avail;
+
+	if (copy_from_user(bao->write_base + *ppos, buf, count))
+		return -EFAULT;
+
+	*ppos += count;
+
+	/* Notify any listeners that new data is available */
+	bao_ipcshmem_notify(bao);
+
+	return count;
+}
+
+/**
+ * bao_ipcshmem_open_fops - open handler for IPC shared memory
+ * @inode: Inode pointer
+ * @filp: File pointer
+ *
+ * Associates the file with the Bao IPC device and increments
+ * the kobject reference.
+ *
+ * Return: 0 on success.
+ */
+static int bao_ipcshmem_open_fops(struct inode *inode, struct file *filp)
+{
+	struct bao_ipcshmem *bao;
+
+	if (WARN_ON_ONCE(!inode || !filp))
+		return -EINVAL;
+
+	bao = container_of(inode->i_cdev, struct bao_ipcshmem, cdev);
+	filp->private_data = bao;
+
+	kobject_get(&bao->dev->kobj);
+
+	return 0;
+}
+
+/**
+ * bao_ipcshmem_release_fops - release handler for IPC shared memory
+ * @inode: Inode pointer
+ * @filp: File pointer
+ *
+ * Disassociates the file from the Bao IPC device and decrements
+ * the kobject reference.
+ *
+ * Return: 0 on success.
+ */
+static int bao_ipcshmem_release_fops(struct inode *inode, struct file *filp)
+{
+	struct bao_ipcshmem *bao;
+
+	if (WARN_ON_ONCE(!inode || !filp))
+		return -EINVAL;
+
+	bao = container_of(inode->i_cdev, struct bao_ipcshmem, cdev);
+	filp->private_data = NULL;
+
+	kobject_put(&bao->dev->kobj);
+
+	return 0;
+}
+
+static const struct file_operations bao_ipcshmem_fops = {
+	.owner = THIS_MODULE,
+	.read = bao_ipcshmem_read_fops,
+	.write = bao_ipcshmem_write_fops,
+	.mmap = bao_ipcshmem_mmap_fops,
+	.open = bao_ipcshmem_open_fops,
+	.release = bao_ipcshmem_release_fops
+};
+
+/**
+ * bao_ipcshmem_register - Register a Bao IPC shared memory device
+ * @pdev: Platform device
+ *
+ * Maps the shared memory region, validates channel layout, initializes
+ * the read/write buffers, registers the character device, and creates
+ * the sysfs device entry.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+static int bao_ipcshmem_register(struct platform_device *pdev)
+{
+	int ret = 0, id = -1;
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct module *owner = THIS_MODULE;
+	struct resource *r;
+	dev_t devt;
+	resource_size_t shmem_size;
+	u32 write_offset, read_offset, write_size, read_size;
+	bool rd_in_range, wr_in_range, disjoint;
+	void *shmem_base_addr = NULL;
+	struct bao_ipcshmem *bao;
+
+	/* Get memory resource */
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r) {
+		dev_err(dev, "failed to get memory resource\n");
+		return -EINVAL;
+	}
+
+	/* Read channel offsets and sizes */
+	of_property_read_u32_index(np, "read-channel", 0, &read_offset);
+	of_property_read_u32_index(np, "read-channel", 1, &read_size);
+	of_property_read_u32_index(np, "write-channel", 0, &write_offset);
+	of_property_read_u32_index(np, "write-channel", 1, &write_size);
+
+	/* Validate memory layout */
+	rd_in_range = (r->start + read_offset + read_size) <= r->end;
+	wr_in_range = (r->start + write_offset + write_size) <= r->end;
+	disjoint = ((read_offset + read_size) <= write_offset) ||
+		   ((write_offset + write_size) <= read_offset);
+
+	if (!rd_in_range || !wr_in_range || !disjoint) {
+		dev_err(dev, "invalid channel layout\n");
+		dev_err(dev, "rd_in_range=%d, wr_in_range=%d, disjoint=%d\n",
+			rd_in_range, wr_in_range, disjoint);
+		return -EINVAL;
+	}
+
+	/* Map shared memory */
+	shmem_size = r->end - r->start + 1;
+	shmem_base_addr = memremap(r->start, shmem_size, MEMREMAP_WB);
+	if (!shmem_base_addr) {
+		dev_err(dev, "failed to map shared memory\n");
+		return -ENOMEM;
+	}
+
+	/* Read device ID from device tree */
+	of_property_read_u32(np, "id", &id);
+	if (id >= MAX_DEVICES) {
+		dev_err(dev, "invalid device id %d\n", id);
+		ret = -EINVAL;
+		goto err_unmap;
+	}
+
+	/* Allocate and initialize device structure */
+	bao = devm_kzalloc(dev, sizeof(*bao), GFP_KERNEL);
+	if (!bao) {
+		ret = -ENOMEM;
+		goto err_unmap;
+	}
+
+	snprintf(bao->label, NAME_LEN, "%s%d", DEV_NAME, id);
+	bao->id = id;
+	bao->read_size = read_size;
+	bao->write_size = write_size;
+	bao->read_base = shmem_base_addr + read_offset;
+	bao->write_base = shmem_base_addr + write_offset;
+	bao->physical_base = (void *)r->start;
+	bao->shmem_size = shmem_size;
+
+	cdev_init(&bao->cdev, &bao_ipcshmem_fops);
+	bao->cdev.owner = owner;
+
+	/* Add character device */
+	devt = MKDEV(MAJOR(bao_ipcshmem_devt), id);
+	ret = cdev_add(&bao->cdev, devt, 1);
+	if (ret)
+		goto err_unmap;
+
+	/* Create device node */
+	bao->dev = device_create(cl, dev, devt, bao, bao->label);
+	if (IS_ERR(bao->dev)) {
+		ret = PTR_ERR(bao->dev);
+		goto err_cdev;
+	}
+	dev_set_drvdata(bao->dev, bao);
+
+	return 0;
+
+err_cdev:
+	cdev_del(&bao->cdev);
+err_unmap:
+	memunmap(shmem_base_addr);
+	dev_err(dev, "failed initialization\n");
+	return ret;
+}
+
+/**
+ * bao_ipcshmem_unregister - Unregister a Bao IPC shared memory device
+ * @pdev: Platform device
+ *
+ * Unmaps the shared memory region, destroys the sysfs device, and
+ * deletes the character device.
+ */
+static void bao_ipcshmem_unregister(struct platform_device *pdev)
+{
+	struct bao_ipcshmem *bao;
+	void *shmem_base;
+
+	/* Retrieve the driver data */
+	bao = dev_get_drvdata(&pdev->dev);
+	if (!bao)
+		return;
+
+	/* Unmap shared memory */
+	if (bao->read_base)
+		shmem_base = (void *)((uintptr_t)bao->read_base -
+				      ((uintptr_t)bao->read_base - (uintptr_t)bao->physical_base));
+	else
+		shmem_base = NULL;
+
+	if (shmem_base)
+		memunmap(shmem_base);
+
+	/* Destroy device node */
+	if (bao->dev)
+		device_destroy(cl, bao->cdev.dev);
+
+	/* Delete character device */
+	cdev_del(&bao->cdev);
+}
+
+static const struct of_device_id of_bao_ipcshmem_match[] = {
+	{
+		.compatible = "bao,ipcshmem",
+	},
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, of_bao_ipcshmem_match);
+
+static struct platform_driver bao_ipcshmem_driver = {
+	.probe = bao_ipcshmem_register,
+	.remove = bao_ipcshmem_unregister,
+	.driver = {
+		   .name = DEV_NAME,
+		   .of_match_table = of_bao_ipcshmem_match,
+		    },
+};
+
+/**
+ * bao_ipcshmem_init - Module initialization for Bao IPC shared memory
+ *
+ * Creates a device class, allocates a range of character device numbers,
+ * and registers the platform driver.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+static int __init bao_ipcshmem_init(void)
+{
+	int ret;
+
+	/* Create device class */
+	cl = class_create(DEV_NAME);
+	if (IS_ERR(cl)) {
+		ret = PTR_ERR(cl);
+		pr_err("unable to create class %s\n", DEV_NAME);
+		return ret;
+	}
+
+	/* Allocate major/minor numbers for character devices */
+	ret = alloc_chrdev_region(&bao_ipcshmem_devt, 0, MAX_DEVICES, DEV_NAME);
+	if (ret) {
+		pr_err("unable to allocate chrdev region for %s\n", DEV_NAME);
+		goto err_class_destroy;
+	}
+
+	/* Register platform driver */
+	ret = platform_driver_register(&bao_ipcshmem_driver);
+	if (ret) {
+		pr_err("unable to register platform driver for %s\n", DEV_NAME);
+		goto err_unregister_chrdev;
+	}
+
+	return 0;
+
+err_unregister_chrdev:
+	unregister_chrdev_region(bao_ipcshmem_devt, MAX_DEVICES);
+err_class_destroy:
+	class_destroy(cl);
+	return ret;
+}
+
+/**
+ * bao_ipcshmem_exit - Module exit for Bao IPC shared memory
+ *
+ * Unregisters the platform driver, releases the character device region,
+ * and destroys the device class.
+ */
+static void __exit bao_ipcshmem_exit(void)
+{
+	/* Unregister the platform driver */
+	platform_driver_unregister(&bao_ipcshmem_driver);
+
+	/* Release the allocated character device numbers */
+	unregister_chrdev_region(bao_ipcshmem_devt, MAX_DEVICES);
+
+	/* Destroy the device class */
+	class_destroy(cl);
+}
+
+module_init(bao_ipcshmem_init);
+module_exit(bao_ipcshmem_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Cerdeira <davidmcerdeira at osyx.tech>");
+MODULE_AUTHOR("Jos? Martins <jose at osyx.tech>");
+MODULE_AUTHOR("Jo?o Peixoto <joaopeixoto at osyx.tech>");
+MODULE_DESCRIPTION("Bao Hypervisor IPC Through Shared-memory Driver");
-- 
2.43.0



From nicolas at ndufresne.ca  Wed Dec 24 07:59:49 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 24 Dec 2025 10:59:49 -0500
Subject: [PATCH v2 18/22] media: rockchip: rga: move rga_fmt to rga-hw.h
In-Reply-To: <20251203-spu-rga3-v2-18-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
	 <20251203-spu-rga3-v2-18-989a67947f71@pengutronix.de>
Message-ID: <de09023e7bdb1698c0bcdeb8d625101cbf647595.camel@ndufresne.ca>

Le mercredi 03 d?cembre 2025 ? 16:52 +0100, Sven P?schel a ?crit?:
> Move rga_fmt to rga-hw in preparation of the RGA3 addition, as the struct
> contains many RGA2 specific values. They are used to write the correct
> register values quickly based on the chosen format. Therefore the
> pointer to the rga_fmt struct is kept but changed to an opaque void
> pointer outside of the rga-hw.h.
> 
> To enumerate and set the correct formats, two helper functions need to
> be exposed in the rga_hw struct:
> 
> enum_format just get's the vidioc_enum_fmt format and it's return value
> is also returned from vidioc_enum_fmt. This is a simple pass-through,
> as the implementation is very simple.
> 
> adjust_and_map_format is a simple abstraction around the previous
> rga_find_format. But unlike rga_find_format, it always returns a valid
> format. Therefore the passed format value is also a pointer to update
> it in case the values are not supported by the hardware.
> Due to the RGA3 supporting different formats on the capture and output
> side, an additional parameter is_capture has been added to support
> this use-case.
> 
> Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
> ---
> ?drivers/media/platform/rockchip/rga/rga-buf.c |? 2 +-
> ?drivers/media/platform/rockchip/rga/rga-hw.c? | 53 +++++++++++++++++++++------
> ?drivers/media/platform/rockchip/rga/rga-hw.h? | 12 ++++++
> ?drivers/media/platform/rockchip/rga/rga.c???? | 38 +++++--------------
> ?drivers/media/platform/rockchip/rga/rga.h???? | 17 ++-------
> ?5 files changed, 68 insertions(+), 54 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
> index 8de6b9c3fd615..b0f226f7f06d9 100644
> --- a/drivers/media/platform/rockchip/rga/rga-buf.c
> +++ b/drivers/media/platform/rockchip/rga/rga-buf.c
> @@ -158,7 +158,7 @@ static int rga_buf_prepare(struct vb2_buffer *vb)
> ?	}
> ?
> ?	/* Fill the remaining planes */
> -	info = v4l2_format_info(f->fmt->fourcc);
> +	info = v4l2_format_info(f->pix.pixelformat);
> ?	for (i = info->mem_planes; i < info->comp_planes; i++)
> ?		dma_addrs[i] = dma_addrs[0] + get_plane_offset(f, info, i);
> ?
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
> index 4dee33d8f7206..a868a34a1452e 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
> @@ -44,14 +44,15 @@ rga_get_corner_addrs(struct rga_frame *frm, struct rga_addrs *addrs,
> ?	struct rga_addrs *lt, *lb, *rt, *rb;
> ?	unsigned int x_div = 0,
> ?		???? y_div = 0, y_stride = 0, uv_stride = 0, pixel_width = 0;
> +	struct rga_fmt *fmt = frm->fmt;
> ?
> ?	lt = &corner_addrs.left_top;
> ?	lb = &corner_addrs.left_bottom;
> ?	rt = &corner_addrs.right_top;
> ?	rb = &corner_addrs.right_bottom;
> ?
> -	x_div = frm->fmt->x_div;
> -	y_div = frm->fmt->y_div;
> +	x_div = fmt->x_div;
> +	y_div = fmt->y_div;
> ?	y_stride = frm->pix.plane_fmt[0].bytesperline;
> ?	uv_stride = y_stride / x_div;
> ?	pixel_width = y_stride / frm->pix.width;
> @@ -162,6 +163,8 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
> ?	union rga_dst_vir_info dst_vir_info;
> ?	union rga_dst_act_info dst_act_info;
> ?	u32 in_stride, out_stride;
> +	struct rga_fmt *in_fmt = ctx->in.fmt;
> +	struct rga_fmt *out_fmt = ctx->out.fmt;
> ?
> ?	src_h = ctx->in.crop.height;
> ?	src_w = ctx->in.crop.width;
> @@ -177,18 +180,18 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
> ?	dst_vir_info.val = dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2];
> ?	dst_act_info.val = dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2];
> ?
> -	src_info.data.format = ctx->in.fmt->hw_format;
> -	src_info.data.swap = ctx->in.fmt->color_swap;
> -	dst_info.data.format = ctx->out.fmt->hw_format;
> -	dst_info.data.swap = ctx->out.fmt->color_swap;
> +	src_info.data.format = in_fmt->hw_format;
> +	src_info.data.swap = in_fmt->color_swap;
> +	dst_info.data.format = out_fmt->hw_format;
> +	dst_info.data.swap = out_fmt->color_swap;
> ?
> ?	/*
> ?	 * CSC mode must only be set when the colorspace families differ between
> ?	 * input and output. It must remain unset (zeroed) if both are the same.
> ?	 */
> ?
> -	if (RGA_COLOR_FMT_IS_YUV(ctx->in.fmt->hw_format) &&
> -	??? RGA_COLOR_FMT_IS_RGB(ctx->out.fmt->hw_format)) {
> +	if (RGA_COLOR_FMT_IS_YUV(in_fmt->hw_format) &&
> +	??? RGA_COLOR_FMT_IS_RGB(out_fmt->hw_format)) {
> ?		switch (ctx->in.pix.colorspace) {
> ?		case V4L2_COLORSPACE_REC709:
> ?			src_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
> @@ -199,8 +202,8 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
> ?		}
> ?	}
> ?
> -	if (RGA_COLOR_FMT_IS_RGB(ctx->in.fmt->hw_format) &&
> -	??? RGA_COLOR_FMT_IS_YUV(ctx->out.fmt->hw_format)) {
> +	if (RGA_COLOR_FMT_IS_RGB(in_fmt->hw_format) &&
> +	??? RGA_COLOR_FMT_IS_YUV(out_fmt->hw_format)) {
> ?		switch (ctx->out.pix.colorspace) {
> ?		case V4L2_COLORSPACE_REC709:
> ?			dst_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
> @@ -619,11 +622,35 @@ static struct rga_fmt formats[] = {
> ?	},
> ?};
> ?
> +static void *rga_adjust_and_map_format(struct v4l2_pix_format_mplane *format,
> +				?????? bool is_output)
> +{
> +	unsigned int i;
> +
> +	if (!format)
> +		return &formats[0];
> +
> +	for (i = 0; i < ARRAY_SIZE(formats); i++) {
> +		if (formats[i].fourcc == format->pixelformat)
> +			return &formats[i];
> +	}
> +
> +	format->pixelformat = formats[0].fourcc;
> +	return &formats[0];
> +}
> +
> +static int rga_enum_format(struct v4l2_fmtdesc *f)
> +{
> +	if (f->index >= ARRAY_SIZE(formats))
> +		return -EINVAL;
> +
> +	f->pixelformat = formats[f->index].fourcc;
> +	return 0;
> +}
> +
> ?const struct rga_hw rga2_hw = {
> ?	.card_type = "rga2",
> ?	.has_internal_iommu = true,
> -	.formats = formats,
> -	.num_formats = ARRAY_SIZE(formats),
> ?	.cmdbuf_size = RGA_CMDBUF_SIZE,
> ?	.min_width = MIN_WIDTH,
> ?	.max_width = MAX_WIDTH,
> @@ -636,4 +663,6 @@ const struct rga_hw rga2_hw = {
> ?	.start = rga_hw_start,
> ?	.handle_irq = rga_handle_irq,
> ?	.get_version = rga_get_version,
> +	.adjust_and_map_format = rga_adjust_and_map_format,
> +	.enum_format = rga_enum_format,
> ?};
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.h b/drivers/media/platform/rockchip/rga/rga-hw.h
> index fffcab0131225..3bc4b1f5acba2 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.h
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.h
> @@ -6,6 +6,8 @@
> ?#ifndef __RGA_HW_H__
> ?#define __RGA_HW_H__
> ?
> +#include <linux/types.h>
> +
> ?#define RGA_CMDBUF_SIZE 0x20
> ?
> ?/* Hardware limits */
> @@ -431,4 +433,14 @@ union rga_pat_con {
> ?	} data;
> ?};
> ?
> +struct rga_fmt {
> +	u32 fourcc;
> +	int depth;
> +	u8 uv_factor;
> +	u8 y_div;
> +	u8 x_div;
> +	u8 color_swap;
> +	u8 hw_format;
> +};
> +
> ?#endif
> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
> index 7e30fafb25fab..c991cc64b4b7f 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -185,17 +185,6 @@ static int rga_setup_ctrls(struct rga_ctx *ctx)
> ?	return 0;
> ?}
> ?
> -static struct rga_fmt *rga_fmt_find(struct rockchip_rga *rga, u32 pixelformat)
> -{
> -	unsigned int i;
> -
> -	for (i = 0; i < rga->hw->num_formats; i++) {
> -		if (rga->hw->formats[i].fourcc == pixelformat)
> -			return &rga->hw->formats[i];
> -	}
> -	return NULL;
> -}
> -
> ?struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type)
> ?{
> ?	if (V4L2_TYPE_IS_OUTPUT(type))
> @@ -217,7 +206,6 @@ static int rga_open(struct file *file)
> ?		.crop.top = 0,
> ?		.crop.width = def_width,
> ?		.crop.height = def_height,
> -		.fmt = &rga->hw->formats[0],
> ?	};
> ?
> ?	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> @@ -238,9 +226,11 @@ static int rga_open(struct file *file)
> ?	ctx->in = def_frame;
> ?	ctx->out = def_frame;
> ?
> -	v4l2_fill_pixfmt_mp_aligned(&ctx->in.pix, ctx->in.fmt->fourcc,
> +	ctx->in.fmt = rga->hw->adjust_and_map_format(&ctx->in.pix, true);
> +	v4l2_fill_pixfmt_mp_aligned(&ctx->in.pix, ctx->in.pix.pixelformat,
> ?				??? def_width, def_height, rga->hw->stride_alignment);
> -	v4l2_fill_pixfmt_mp_aligned(&ctx->out.pix, ctx->out.fmt->fourcc,
> +	ctx->out.fmt = rga->hw->adjust_and_map_format(&ctx->out.pix, false);
> +	v4l2_fill_pixfmt_mp_aligned(&ctx->out.pix, ctx->out.pix.pixelformat,
> ?				??? def_width, def_height, rga->hw->stride_alignment);
> ?
> ?	if (mutex_lock_interruptible(&rga->mutex)) {
> @@ -322,15 +312,8 @@ vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
> ?static int vidioc_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f)
> ?{
> ?	struct rockchip_rga *rga = video_drvdata(file);
> -	struct rga_fmt *fmt;
> ?
> -	if (f->index >= rga->hw->num_formats)
> -		return -EINVAL;
> -
> -	fmt = &rga->hw->formats[f->index];
> -	f->pixelformat = fmt->fourcc;
> -
> -	return 0;
> +	return rga->hw->enum_format(f);
> ?}
> ?
> ?static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
> @@ -355,15 +338,13 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
> ?	struct rga_ctx *ctx = file_to_rga_ctx(file);
> ?	struct rockchip_rga *rga = ctx->rga;
> ?	const struct rga_hw *hw = rga->hw;
> -	struct rga_fmt *fmt;
> ?	u32 min_width = hw->min_width;
> ?	u32 max_width = hw->max_width;
> ?	u32 min_height = hw->min_height;
> ?	u32 max_height = hw->max_height;
> ?
> -	fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
> -	if (!fmt)
> -		fmt = &hw->formats[0];
> +	hw->adjust_and_map_format(pix_fmt,
> +				? V4L2_TYPE_IS_OUTPUT(f->type));
> ?
> ?	if (V4L2_TYPE_IS_OUTPUT(f->type) &&
> ?	??? v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx)->streaming) {
> @@ -425,7 +406,8 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
> ?	frm = rga_get_frame(ctx, f->type);
> ?	if (IS_ERR(frm))
> ?		return PTR_ERR(frm);
> -	frm->fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
> +	frm->fmt = rga->hw->adjust_and_map_format(pix_fmt,
> +						? V4L2_TYPE_IS_OUTPUT(f->type));
> ?
> ?	/* Reset crop settings */
> ?	frm->crop.left = 0;
> @@ -438,7 +420,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
> ?	v4l2_dbg(debug, 1, &rga->v4l2_dev,
> ?		 "[%s] fmt - %p4cc %dx%d (stride %d)\n",
> ?		? V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
> -		? &frm->fmt->fourcc, pix_fmt->width, pix_fmt->height,
> +		? &pix_fmt->pixelformat, pix_fmt->width, pix_fmt->height,
> ?		? pix_fmt->plane_fmt[0].bytesperline);
> ?
> ?	for (i = 0; i < pix_fmt->num_planes; i++) {
> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
> index a7f891b94a478..980f70f842317 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -17,22 +17,12 @@
> ?#define DEFAULT_WIDTH 100
> ?#define DEFAULT_HEIGHT 100
> ?
> -struct rga_fmt {
> -	u32 fourcc;
> -	int depth;
> -	u8 uv_factor;
> -	u8 y_div;
> -	u8 x_div;
> -	u8 color_swap;
> -	u8 hw_format;
> -};

Ah! here's the removal of the unused variable. Not review friendly, but at last
removed.

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> -
> ?struct rga_frame {
> ?	/* Crop */
> ?	struct v4l2_rect crop;
> ?
> ?	/* Image format */
> -	struct rga_fmt *fmt;
> +	void *fmt;
> ?	struct v4l2_pix_format_mplane pix;
> ?};
> ?
> @@ -145,8 +135,6 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
> ?struct rga_hw {
> ?	const char *card_type;
> ?	bool has_internal_iommu;
> -	struct rga_fmt *formats;
> -	u32 num_formats;
> ?	size_t cmdbuf_size;
> ?	u32 min_width, min_height;
> ?	u32 max_width, max_height;
> @@ -158,6 +146,9 @@ struct rga_hw {
> ?		????? struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
> ?	bool (*handle_irq)(struct rockchip_rga *rga);
> ?	void (*get_version)(struct rockchip_rga *rga);
> +	void *(*adjust_and_map_format)(struct v4l2_pix_format_mplane *format,
> +				?????? bool is_output);
> +	int (*enum_format)(struct v4l2_fmtdesc *f);
> ?};
> ?
> ?static inline bool rga_has_internal_iommu(const struct rockchip_rga *rga)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/bd6b744c/attachment.sig>

From nicolas at ndufresne.ca  Wed Dec 24 08:00:37 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 24 Dec 2025 11:00:37 -0500
Subject: [PATCH v2 19/22] media: rockchip: rga: add feature flags
In-Reply-To: <20251203-spu-rga3-v2-19-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
	 <20251203-spu-rga3-v2-19-989a67947f71@pengutronix.de>
Message-ID: <a5abd83b62220e86fd5ce627aa67c7236efb57e3.camel@ndufresne.ca>

Le mercredi 03 d?cembre 2025 ? 16:52 +0100, Sven P?schel a ?crit?:
> In preparation to the RGA3 addition add feature flags, which can limit
> the exposed feature set of the video device, like rotating or selection
> support. This is necessary as the RGA3 doesn't initially implement the
> full feature set currently exposed by the driver.
> 
> Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?drivers/media/platform/rockchip/rga/rga-hw.c |? 4 ++++
> ?drivers/media/platform/rockchip/rga/rga.c??? | 23 +++++++++++++++--------
> ?drivers/media/platform/rockchip/rga/rga.h??? |? 7 +++++++
> ?3 files changed, 26 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c
> b/drivers/media/platform/rockchip/rga/rga-hw.c
> index a868a34a1452e..0d1cf911af0d5 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
> @@ -658,6 +658,10 @@ const struct rga_hw rga2_hw = {
> ?	.max_height = MAX_HEIGHT,
> ?	.max_scaling_factor = MAX_SCALING_FACTOR,
> ?	.stride_alignment = 4,
> +	.features = RGA_FEATURE_FLIP
> +		? | RGA_FEATURE_ROTATE
> +		? | RGA_FEATURE_BG_COLOR
> +		? | RGA_FEATURE_SELECTION,
> ?
> ?	.setup_cmdbuf = rga_hw_setup_cmdbuf,
> ?	.start = rga_hw_start,
> diff --git a/drivers/media/platform/rockchip/rga/rga.c
> b/drivers/media/platform/rockchip/rga/rga.c
> index c991cc64b4b7f..3958e71b8987d 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -162,17 +162,21 @@ static int rga_setup_ctrls(struct rga_ctx *ctx)
> ?
> ?	v4l2_ctrl_handler_init(&ctx->ctrl_handler, 4);
> ?
> -	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
> -			? V4L2_CID_HFLIP, 0, 1, 1, 0);
> +	if (rga->hw->features & RGA_FEATURE_FLIP) {
> +		v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
> +				? V4L2_CID_HFLIP, 0, 1, 1, 0);
> ?
> -	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
> -			? V4L2_CID_VFLIP, 0, 1, 1, 0);
> +		v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
> +				? V4L2_CID_VFLIP, 0, 1, 1, 0);
> +	}
> ?
> -	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
> -			? V4L2_CID_ROTATE, 0, 270, 90, 0);
> +	if (rga->hw->features & RGA_FEATURE_ROTATE)
> +		v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
> +				? V4L2_CID_ROTATE, 0, 270, 90, 0);
> ?
> -	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
> -			? V4L2_CID_BG_COLOR, 0, 0xffffffff, 1, 0);
> +	if (rga->hw->features & RGA_FEATURE_BG_COLOR)
> +		v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
> +				? V4L2_CID_BG_COLOR, 0, 0xffffffff, 1, 0);
> ?
> ?	if (ctx->ctrl_handler.error) {
> ?		int err = ctx->ctrl_handler.error;
> @@ -489,6 +493,9 @@ static int vidioc_s_selection(struct file *file, void
> *priv,
> ?	struct rga_frame *f;
> ?	int ret = 0;
> ?
> +	if (!(rga->hw->features & RGA_FEATURE_SELECTION))
> +		return -EINVAL;
> +
> ?	f = rga_get_frame(ctx, s->type);
> ?	if (IS_ERR(f))
> ?		return PTR_ERR(f);
> diff --git a/drivers/media/platform/rockchip/rga/rga.h
> b/drivers/media/platform/rockchip/rga/rga.h
> index 980f70f842317..b9c75b5fda4dc 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -6,6 +6,7 @@
> ?#ifndef __RGA_H__
> ?#define __RGA_H__
> ?
> +#include <linux/bits.h>
> ?#include <linux/clk.h>
> ?#include <linux/platform_device.h>
> ?#include <media/videobuf2-v4l2.h>
> @@ -132,6 +133,11 @@ static inline void rga_mod(struct rockchip_rga *rga, u32
> reg, u32 val, u32 mask)
> ?	rga_write(rga, reg, temp);
> ?};
> ?
> +#define RGA_FEATURE_FLIP	BIT(0)
> +#define RGA_FEATURE_ROTATE	BIT(1)
> +#define RGA_FEATURE_BG_COLOR	BIT(2)
> +#define RGA_FEATURE_SELECTION	BIT(3)
> +
> ?struct rga_hw {
> ?	const char *card_type;
> ?	bool has_internal_iommu;
> @@ -140,6 +146,7 @@ struct rga_hw {
> ?	u32 max_width, max_height;
> ?	u8 max_scaling_factor;
> ?	u8 stride_alignment;
> +	u8 features;
> ?
> ?	void (*setup_cmdbuf)(struct rga_ctx *ctx);
> ?	void (*start)(struct rockchip_rga *rga,
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/8710a7ee/attachment-0001.sig>

From nicolas at ndufresne.ca  Wed Dec 24 08:02:25 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 24 Dec 2025 11:02:25 -0500
Subject: [PATCH v2 20/22] media: rockchip: rga: disable multi-core
 support
In-Reply-To: <20251203-spu-rga3-v2-20-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
	 <20251203-spu-rga3-v2-20-989a67947f71@pengutronix.de>
Message-ID: <8a026dd07133203789e91d0a1662c8b162842fe2.camel@ndufresne.ca>

Hi,

Le mercredi 03 d?cembre 2025 ? 16:52 +0100, Sven P?schel a ?crit?:
> Disable multi-core support in preparation of the RGA3 addition. The
> RK3588 SoC features two equal RGA3 cores. This allows scheduling of the
> work between both cores, which is not yet implemented. Until it is
> implemented avoid exposing both cores as independent video devices to
> prevent an ABI breakage when multi-core support is added.

Please add a Link: and reference to the Hantro patch from which is code is from.

> 
> Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?drivers/media/platform/rockchip/rga/rga.c | 28 ++++++++++++++++++++++++++++
> ?1 file changed, 28 insertions(+)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
> index 3958e71b8987d..65686228b7300 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -660,6 +660,30 @@ static int rga_parse_dt(struct rockchip_rga *rga)
> ?	return 0;
> ?}
> ?
> +static int rga_disable_multicore(struct device *dev)
> +{
> +	const char *compatible;
> +	struct device_node *node;
> +	int ret;
> +
> +	/* Intentionally ignores the fallback strings */
> +	ret = of_property_read_string(dev->of_node, "compatible", &compatible);
> +	if (ret)
> +		return ret;
> +
> +	/* first compatible node found from the root node is considered the main core */
> +	node = of_find_compatible_node(NULL, NULL, compatible);
> +	if (!node)
> +		return -EINVAL; /* broken DT? */
> +
> +	if (dev->of_node != node) {
> +		dev_info(dev, "missing multi-core support, ignoring this instance\n");
> +		return -ENODEV;
> +	}
> +
> +	return 0;
> +}
> +
> ?static int rga_probe(struct platform_device *pdev)
> ?{
> ?	struct rockchip_rga *rga;
> @@ -670,6 +694,10 @@ static int rga_probe(struct platform_device *pdev)
> ?	if (!pdev->dev.of_node)
> ?		return -ENODEV;
> ?
> +	ret = rga_disable_multicore(&pdev->dev);
> +	if (ret)
> +		return ret;
> +
> ?	rga = devm_kzalloc(&pdev->dev, sizeof(*rga), GFP_KERNEL);
> ?	if (!rga)
> ?		return -ENOMEM;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/32a064bd/attachment.sig>

From nicolas at ndufresne.ca  Wed Dec 24 07:56:17 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 24 Dec 2025 10:56:17 -0500
Subject: [PATCH v2 17/22] media: rockchip: rga: remove stride from
 rga_frame
In-Reply-To: <20251203-spu-rga3-v2-17-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
	 <20251203-spu-rga3-v2-17-989a67947f71@pengutronix.de>
Message-ID: <b84b59d5b190edfce326df824f453464c00812ac.camel@ndufresne.ca>

Le mercredi 03 d?cembre 2025 ? 16:52 +0100, Sven P?schel a ?crit?:
> Remove the stride variable from rga_frame. Despite the comment it
> didn't involve any calculation and is just a copy of the
> plane_fmt[0].bytesperline value. Therefore avoid this struct member
> and use the bytesperline value directly in the places where it is
> required.
> 
> Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>

This I believe was the only user of fmt->x_div / fmt->y_div, please cleanup the
structure definition.

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?drivers/media/platform/rockchip/rga/rga-hw.c | 20 ++++++++++++--------
> ?drivers/media/platform/rockchip/rga/rga.c??? |? 5 +----
> ?drivers/media/platform/rockchip/rga/rga.h??? |? 3 ---
> ?3 files changed, 13 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c
> b/drivers/media/platform/rockchip/rga/rga-hw.c
> index fb0389ae8e132..4dee33d8f7206 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
> @@ -43,7 +43,7 @@ rga_get_corner_addrs(struct rga_frame *frm, struct rga_addrs
> *addrs,
> ?	struct rga_corners_addrs corner_addrs;
> ?	struct rga_addrs *lt, *lb, *rt, *rb;
> ?	unsigned int x_div = 0,
> -		???? y_div = 0, uv_stride = 0, pixel_width = 0;
> +		???? y_div = 0, y_stride = 0, uv_stride = 0, pixel_width = 0;
> ?
> ?	lt = &corner_addrs.left_top;
> ?	lb = &corner_addrs.left_bottom;
> @@ -52,14 +52,15 @@ rga_get_corner_addrs(struct rga_frame *frm, struct
> rga_addrs *addrs,
> ?
> ?	x_div = frm->fmt->x_div;
> ?	y_div = frm->fmt->y_div;
> -	uv_stride = frm->stride / x_div;
> -	pixel_width = frm->stride / frm->pix.width;
> +	y_stride = frm->pix.plane_fmt[0].bytesperline;
> +	uv_stride = y_stride / x_div;
> +	pixel_width = y_stride / frm->pix.width;
> ?
> -	lt->y_addr = addrs->y_addr + y * frm->stride + x * pixel_width;
> +	lt->y_addr = addrs->y_addr + y * y_stride + x * pixel_width;
> ?	lt->u_addr = addrs->u_addr + (y / y_div) * uv_stride + x / x_div;
> ?	lt->v_addr = addrs->v_addr + (y / y_div) * uv_stride + x / x_div;
> ?
> -	lb->y_addr = lt->y_addr + (h - 1) * frm->stride;
> +	lb->y_addr = lt->y_addr + (h - 1) * y_stride;
> ?	lb->u_addr = lt->u_addr + (h / y_div - 1) * uv_stride;
> ?	lb->v_addr = lt->v_addr + (h / y_div - 1) * uv_stride;
> ?
> @@ -160,6 +161,7 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
> ?	union rga_src_act_info src_act_info;
> ?	union rga_dst_vir_info dst_vir_info;
> ?	union rga_dst_act_info dst_act_info;
> +	u32 in_stride, out_stride;
> ?
> ?	src_h = ctx->in.crop.height;
> ?	src_w = ctx->in.crop.width;
> @@ -282,13 +284,15 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
> ?	 * Calculate the framebuffer virtual strides and active size,
> ?	 * note that the step of vir_stride / vir_width is 4 byte words
> ?	 */
> -	src_vir_info.data.vir_stride = ctx->in.stride >> 2;
> -	src_vir_info.data.vir_width = ctx->in.stride >> 2;
> +	in_stride = ctx->in.pix.plane_fmt[0].bytesperline;
> +	src_vir_info.data.vir_stride = in_stride >> 2;
> +	src_vir_info.data.vir_width = in_stride >> 2;
> ?
> ?	src_act_info.data.act_height = src_h - 1;
> ?	src_act_info.data.act_width = src_w - 1;
> ?
> -	dst_vir_info.data.vir_stride = ctx->out.stride >> 2;
> +	out_stride = ctx->out.pix.plane_fmt[0].bytesperline;
> +	dst_vir_info.data.vir_stride = out_stride >> 2;
> ?	dst_act_info.data.act_height = dst_h - 1;
> ?	dst_act_info.data.act_width = dst_w - 1;
> ?
> diff --git a/drivers/media/platform/rockchip/rga/rga.c
> b/drivers/media/platform/rockchip/rga/rga.c
> index 0d7b0bcac950e..7e30fafb25fab 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -220,8 +220,6 @@ static int rga_open(struct file *file)
> ?		.fmt = &rga->hw->formats[0],
> ?	};
> ?
> -	def_frame.stride = (def_width * def_frame.fmt->depth) >> 3;
> -
> ?	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> ?	if (!ctx)
> ?		return -ENOMEM;
> @@ -428,7 +426,6 @@ static int vidioc_s_fmt(struct file *file, void *priv,
> struct v4l2_format *f)
> ?	if (IS_ERR(frm))
> ?		return PTR_ERR(frm);
> ?	frm->fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
> -	frm->stride = pix_fmt->plane_fmt[0].bytesperline;
> ?
> ?	/* Reset crop settings */
> ?	frm->crop.left = 0;
> @@ -442,7 +439,7 @@ static int vidioc_s_fmt(struct file *file, void *priv,
> struct v4l2_format *f)
> ?		 "[%s] fmt - %p4cc %dx%d (stride %d)\n",
> ?		? V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
> ?		? &frm->fmt->fourcc, pix_fmt->width, pix_fmt->height,
> -		? frm->stride);
> +		? pix_fmt->plane_fmt[0].bytesperline);
> ?
> ?	for (i = 0; i < pix_fmt->num_planes; i++) {
> ?		v4l2_dbg(debug, 1, &rga->v4l2_dev,
> diff --git a/drivers/media/platform/rockchip/rga/rga.h
> b/drivers/media/platform/rockchip/rga/rga.h
> index 466d568b9e614..a7f891b94a478 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -34,9 +34,6 @@ struct rga_frame {
> ?	/* Image format */
> ?	struct rga_fmt *fmt;
> ?	struct v4l2_pix_format_mplane pix;
> -
> -	/* Variables that can calculated once and reused */
> -	u32 stride;
> ?};
> ?
> ?struct rga_dma_desc {
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/f32665cf/attachment.sig>

From linux.amoon at gmail.com  Wed Dec 24 08:11:38 2025
From: linux.amoon at gmail.com (Anand Moon)
Date: Wed, 24 Dec 2025 21:41:38 +0530
Subject: [PATCH v2 1/4] PCI: rockchip: limit RK3399 to 2.5 GT/s to prevent damage
In-Reply-To: <0afea20b-be22-2404-5a8e-c798ed45f2fd@manjaro.org>
References: <cover.1763415705.git.geraldogabriel@gmail.com>
 <eaa9c75ca02a53f8bcc293b8bc73d013e26ec253.1763415706.git.geraldogabriel@gmail.com>
 <CANAwSgQ726J_vnDKEKd94Kq62kx8ToZzUGysz4r3tNAXvfAbGA@mail.gmail.com>
 <CAEsQvctSY7-RQEQF2TmJU2qKPZOe9TC5g-7Jat0LQKRHYz_6dQ@mail.gmail.com>
 <CANAwSgQPQUBi6VVb+hZNraMt71vnRpki+YK_at=Luo4aPVtOPg@mail.gmail.com> <0afea20b-be22-2404-5a8e-c798ed45f2fd@manjaro.org>
Message-ID: <CANAwSgS6UeR4PJnWDxxcQbdH8u_4uNiQxCTugQS35LcPvpiwMQ@mail.gmail.com>

Hi Dragan,

On Wed, 24 Dec 2025 at 18:25, Dragan Simic <dsimic at manjaro.org> wrote:
>
> Hello Anand,
>
> On Wednesday, December 24, 2025 09:04 CET, Anand Moon <linux.amoon at gmail.com> wrote:
> > On Wed, 24 Dec 2025 at 11:08, Geraldo Nascimento
> > <geraldogabriel at gmail.com> wrote:
> > > On Wed, Dec 24, 2025 at 2:18?AM Anand Moon <linux.amoon at gmail.com> wrote:
> > > > On Tue, 18 Nov 2025 at 03:17, Geraldo Nascimento
> > > > <geraldogabriel at gmail.com> wrote:
> > > > > Shawn Lin from Rockchip has reiterated that there may be danger in using
> > > > > their PCIe with 5.0 GT/s speeds. Warn the user if they make a DT change
> > > > > from the default and drive at 2.5 GT/s only, even if the DT
> > > > > max-link-speed property is invalid or inexistent.
> > > > >
> > > > > This change is corroborated by RK3399 official datasheet [1], which
> > > > > says maximum link speed for this platform is 2.5 GT/s.
> > > > >
> > > > > [1] https://opensource.rock-chips.com/images/d/d7/Rockchip_RK3399_Datasheet_V2.1-20200323.pdf
> > > > >
> > > > To accurately determine the operating speed, we can leverage the
> > > > PCIE_CLIENT_BASIC_STATUS0/1 fields.
> > > > This provides a dynamic mechanism to resolve the issue.
> > > >
> > > > [1] https://github.com/torvalds/linux/blob/master/drivers/pci/controller/pcie-rockchip-ep.c#L533-L595
> > >
> > > not to put you down but I think your approach adds unnecessary complexity.
> > >
> > > All I care really is that the Kernel Project isn't blamed in the
> > > future if someone happens to lose their data.
> > >
> > Allow the hardware to negotiate the link speed based on the
> > available number of lanes.
> > I don?t anticipate any data loss, since PCIe will automatically
> > configure the device speed with link training..
>
> Please, note that this isn't about performing auto negotiation
> and following its results, but about "artificially" limiting the
> PCIe link speed to 2.5 GT/s on RK3399, because it's well known
> by Rockchip that 5 GT/s on RK3399's PCIe interface may cause
> issues and data corruption in certain corner cases.
>
It?s possible the link speed wasn?t properly tuned. On my older
development board,
which supports this configuration, I haven?t observed any data loss.

sudo lspci -vvv | grep Speed
                LnkCap: Port #0, Speed 5GT/s, Width x1, ASPM L1, Exit
Latency L1 <8us
                LnkSta: Speed 5GT/s, Width x1
                LnkCtl2: Target Link Speed: 5GT/s, EnterCompliance- SpeedDis-
                LnkCap: Port #1, Speed 5GT/s, Width x1, ASPM L0s L1,
Exit Latency L0s unlimited, L1 <2us
                LnkSta: Speed 5GT/s, Width x1
                LnkCtl2: Target Link Speed: 5GT/s, EnterCompliance- SpeedDis-

Thanks
-Anand


From robh at kernel.org  Wed Dec 24 08:18:16 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Wed, 24 Dec 2025 10:18:16 -0600
Subject: [PATCH 3/5] dt-bindings: Add Bao I/O dispatcher driver binding
In-Reply-To: <20251224135217.25350-4-joaopeixoto@osyx.tech>
References: <20251224135217.25350-1-joaopeixoto@osyx.tech>
 <20251224135217.25350-4-joaopeixoto@osyx.tech>
Message-ID: <176659309471.2305281.17349642622422527927.robh@kernel.org>


On Wed, 24 Dec 2025 13:52:15 +0000, joaopeixoto at osyx.tech wrote:
> From: Jo?o Peixoto <joaopeixoto at osyx.tech>
> 
> This patch adds a Device Tree binding for the Bao I/O Dispatcher kernel
> module, which can be loaded into backend VMs. The I/O Dispatcher
> provides the bridge between the Bao hypervisor Remote I/O system and the
> frontend device model in userspace, offering a unified API to support
> various VirtIO backends.
> 
> The dispatcher handles hypercalls to the Bao hypervisor, IRQ/eventfd
> forwarding, and provides a character device interface for frontend
> devices, enabling efficient communication between the hypervisor and
> userspace device models.
> 
> The binding documents the following properties:
>   - compatible: "bao,io-dispatcher"
>   - reg: Memory regions for the dispatcher (multiple VirtIO devices)
>   - interrupts: Interrupts used by the devices
>   - interrupt-parent: Parent interrupt controller
> 
> This enables kernel drivers to correctly instantiate and configure Bao
> I/O Dispatcher modules based on the DT description.
> 
> Signed-off-by: Jo?o Peixoto <joaopeixoto at osyx.tech>
> ---
>  .../bindings/bao/io-dispatcher.yaml           | 67 +++++++++++++++++++
>  1 file changed, 67 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/bao/io-dispatcher.yaml
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:
./Documentation/devicetree/bindings/bao/ipcshmem.yaml:4:6: [error] string value is redundantly quoted with any quotes (quoted-strings)
./Documentation/devicetree/bindings/bao/ipcshmem.yaml:5:10: [error] string value is redundantly quoted with any quotes (quoted-strings)
./Documentation/devicetree/bindings/bao/ipcshmem.yaml:17:1: [error] syntax error: found character '\t' that cannot start any token (syntax)
./Documentation/devicetree/bindings/bao/io-dispatcher.yaml:4:6: [error] string value is redundantly quoted with any quotes (quoted-strings)
./Documentation/devicetree/bindings/bao/io-dispatcher.yaml:5:10: [error] string value is redundantly quoted with any quotes (quoted-strings)
./Documentation/devicetree/bindings/bao/io-dispatcher.yaml:20:12: [error] string value is redundantly quoted with any quotes (quoted-strings)

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/bao/ipcshmem.yaml: ignoring, error parsing file
./Documentation/devicetree/bindings/bao/ipcshmem.yaml:17:1: found a tab character where an indentation space is expected
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/bao/io-dispatcher.yaml: properties:reg: 'anyOf' conditional failed, one must be fixed:
	'type' is not one of ['maxItems', 'description', 'deprecated']
		hint: Only "maxItems" is required for a single entry if there are no constraints defined for the values.
	'items' is not one of ['maxItems', 'description', 'deprecated']
		hint: Only "maxItems" is required for a single entry if there are no constraints defined for the values.
	Additional properties are not allowed ('type' was unexpected)
		hint: Arrays must be described with a combination of minItems/maxItems/items
	'maxItems' is not one of ['description', 'deprecated', 'const', 'enum', 'minimum', 'maximum', 'multipleOf', 'default', '$ref', 'oneOf']
	'type' is not one of ['description', 'deprecated', 'const', 'enum', 'minimum', 'maximum', 'multipleOf', 'default', '$ref', 'oneOf']
	'items' is not one of ['description', 'deprecated', 'const', 'enum', 'minimum', 'maximum', 'multipleOf', 'default', '$ref', 'oneOf']
	/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/bao/io-dispatcher.yaml: properties:reg:items: 'anyOf' conditional failed, one must be fixed:
		'maxItems' is a required property
			hint: Only "maxItems" is required for a single entry if there are no constraints defined for the values.
		'type' is not one of ['maxItems', 'description', 'deprecated']
			hint: Only "maxItems" is required for a single entry if there are no constraints defined for the values.
		Additional properties are not allowed ('type' was unexpected)
			hint: Arrays must be described with a combination of minItems/maxItems/items
		'type' is not one of ['description', 'deprecated', 'const', 'enum', 'minimum', 'maximum', 'multipleOf', 'default', '$ref', 'oneOf']
			hint: "items" can be a list defining each entry or a schema applying to all items. A list has an implicit size. A schema requires minItems/maxItems to define the size.
		hint: cell array properties must define how many entries and what the entries are when there is more than one entry.
		from schema $id: http://devicetree.org/meta-schemas/cell.yaml
	1 was expected
		hint: Only "maxItems" is required for a single entry if there are no constraints defined for the values.
	hint: cell array properties must define how many entries and what the entries are when there is more than one entry.
	from schema $id: http://devicetree.org/meta-schemas/cell.yaml
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/bao/io-dispatcher.yaml: properties:reg:type: 'array' is not one of ['boolean', 'object']
	from schema $id: http://devicetree.org/meta-schemas/core.yaml
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/bao/io-dispatcher.yaml: properties:interrupts:type: 'array' is not one of ['boolean', 'object']
	from schema $id: http://devicetree.org/meta-schemas/core.yaml
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/bao/io-dispatcher.yaml: properties:interrupt-parent:type: 'string' is not one of ['boolean', 'object']
	from schema $id: http://devicetree.org/meta-schemas/core.yaml
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/bao/io-dispatcher.yaml: properties:interrupts: 'anyOf' conditional failed, one must be fixed:
	'type' is not one of ['maxItems', 'description', 'deprecated']
		hint: Only "maxItems" is required for a single entry if there are no constraints defined for the values.
	'items' is not one of ['maxItems', 'description', 'deprecated']
		hint: Only "maxItems" is required for a single entry if there are no constraints defined for the values.
	'minItems' is not one of ['maxItems', 'description', 'deprecated']
		hint: Only "maxItems" is required for a single entry if there are no constraints defined for the values.
	Additional properties are not allowed ('type' was unexpected)
		hint: Arrays must be described with a combination of minItems/maxItems/items
	'type' is not one of ['description', 'deprecated', 'const', 'enum', 'minimum', 'maximum', 'multipleOf', 'default', '$ref', 'oneOf']
	'items' is not one of ['description', 'deprecated', 'const', 'enum', 'minimum', 'maximum', 'multipleOf', 'default', '$ref', 'oneOf']
	'minItems' is not one of ['description', 'deprecated', 'const', 'enum', 'minimum', 'maximum', 'multipleOf', 'default', '$ref', 'oneOf']
	'maxItems' is not one of ['description', 'deprecated', 'const', 'enum', 'minimum', 'maximum', 'multipleOf', 'default', '$ref', 'oneOf']
	/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/bao/io-dispatcher.yaml: properties:interrupts:items: 'anyOf' conditional failed, one must be fixed:
		'maxItems' is a required property
			hint: Only "maxItems" is required for a single entry if there are no constraints defined for the values.
		'type' is not one of ['maxItems', 'description', 'deprecated']
			hint: Only "maxItems" is required for a single entry if there are no constraints defined for the values.
		Additional properties are not allowed ('type' was unexpected)
			hint: Arrays must be described with a combination of minItems/maxItems/items
		'type' is not one of ['description', 'deprecated', 'const', 'enum', 'minimum', 'maximum', 'multipleOf', 'default', '$ref', 'oneOf']
			hint: "items" can be a list defining each entry or a schema applying to all items. A list has an implicit size. A schema requires minItems/maxItems to define the size.
		hint: cell array properties must define how many entries and what the entries are when there is more than one entry.
		from schema $id: http://devicetree.org/meta-schemas/cell.yaml
	1 was expected
		hint: Only "maxItems" is required for a single entry if there are no constraints defined for the values.
	hint: cell array properties must define how many entries and what the entries are when there is more than one entry.
	from schema $id: http://devicetree.org/meta-schemas/cell.yaml
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/bao/io-dispatcher.yaml: properties: False schema does not allow {'description': 'Parent interrupt controller node', 'type': 'string'}
	from schema $id: http://devicetree.org/meta-schemas/interrupts.yaml
make[2]: *** Deleting file 'Documentation/devicetree/bindings/bao/ipcshmem.example.dts'
Documentation/devicetree/bindings/bao/ipcshmem.yaml:17:1: found a tab character where an indentation space is expected
make[2]: *** [Documentation/devicetree/bindings/Makefile:26: Documentation/devicetree/bindings/bao/ipcshmem.example.dts] Error 1
make[2]: *** Waiting for unfinished jobs....
make[1]: *** [/builds/robherring/dt-review-ci/linux/Makefile:1565: 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/20251224135217.25350-4-joaopeixoto at osyx.tech

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.



From robh at kernel.org  Wed Dec 24 08:18:17 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Wed, 24 Dec 2025 10:18:17 -0600
Subject: [PATCH 1/5] dt-bindings: Add Bao IPC shared memory driver
 binding
In-Reply-To: <20251224135217.25350-2-joaopeixoto@osyx.tech>
References: <20251224135217.25350-1-joaopeixoto@osyx.tech>
 <20251224135217.25350-2-joaopeixoto@osyx.tech>
Message-ID: <176659309602.2305345.1814998732546100865.robh@kernel.org>


On Wed, 24 Dec 2025 13:52:13 +0000, joaopeixoto at osyx.tech wrote:
> From: Jo?o Peixoto <joaopeixoto at osyx.tech>
> 
> This patch adds a Device Tree binding for the Bao IPC shared memory
> device, which provides a standardized description of the hardware
> interface used for inter-VM communication in Bao-based systems.
> 
> The binding documents the following properties:
> 
>   - compatible: "bao,ipcshmem"
>   - reg: Memory region for the shared memory device
>   - id: Unique device identifier
>   - read-channel: [offset, size] for reading from the shared memory
>   - write-channel: [offset, size] for writing to the shared memory
>   - interrupts: Interrupts used by the device
> 
> This enables kernel drivers and userspace tools to correctly
> instantiate and configure Bao IPC shared memory devices based
> on the DT description, facilitating efficient communication
> between VMs.
> 
> Signed-off-by: Jo?o Peixoto <joaopeixoto at osyx.tech>
> ---
>  .../devicetree/bindings/bao/ipcshmem.yaml     | 99 +++++++++++++++++++
>  .../devicetree/bindings/vendor-prefixes.yaml  |  2 +
>  2 files changed, 101 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/bao/ipcshmem.yaml
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:


doc reference errors (make refcheckdocs):

See https://patchwork.kernel.org/project/devicetree/patch/20251224135217.25350-2-joaopeixoto at osyx.tech

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.



From nicolas.ferre at microchip.com  Wed Dec 24 08:29:19 2025
From: nicolas.ferre at microchip.com (Nicolas Ferre)
Date: Wed, 24 Dec 2025 17:29:19 +0100
Subject: [PATCH 1/4] mmc: atmel-mci: Simplify with scoped for each OF
 child loop
In-Reply-To: <20251224124431.208434-5-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251224124431.208434-5-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <9faff0a3-0f3d-4e51-ab5b-0cf0204ee4fd@microchip.com>

On 24/12/2025 at 13:44, Krzysztof Kozlowski wrote:
> Use scoped for-each loop when iterating over device nodes to make code a
> bit simpler.
> 
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Reviewed-by: Nicolas Ferre <nicolas.ferre at microchip.com>

Thanks Krzysztof, best regards,
   Nicolas

> ---
>   drivers/mmc/host/atmel-mci.c | 12 +++---------
>   1 file changed, 3 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
> index fdf6926ea468..3b4928f5b9b2 100644
> --- a/drivers/mmc/host/atmel-mci.c
> +++ b/drivers/mmc/host/atmel-mci.c
> @@ -629,14 +629,13 @@ static int atmci_of_init(struct atmel_mci *host)
>   {
>          struct device *dev = host->dev;
>          struct device_node *np = dev->of_node;
> -       struct device_node *cnp;
>          u32 slot_id;
>          int err;
> 
>          if (!np)
>                  return dev_err_probe(dev, -EINVAL, "device node not found\n");
> 
> -       for_each_child_of_node(np, cnp) {
> +       for_each_child_of_node_scoped(np, cnp) {
>                  if (of_property_read_u32(cnp, "reg", &slot_id)) {
>                          dev_warn(dev, "reg property is missing for %pOF\n", cnp);
>                          continue;
> @@ -645,7 +644,6 @@ static int atmci_of_init(struct atmel_mci *host)
>                  if (slot_id >= ATMCI_MAX_NR_SLOTS) {
>                          dev_warn(dev, "can't have more than %d slots\n",
>                                   ATMCI_MAX_NR_SLOTS);
> -                       of_node_put(cnp);
>                          break;
>                  }
> 
> @@ -658,10 +656,8 @@ static int atmci_of_init(struct atmel_mci *host)
>                                                "cd", GPIOD_IN, "cd-gpios");
>                  err = PTR_ERR_OR_ZERO(host->pdata[slot_id].detect_pin);
>                  if (err) {
> -                       if (err != -ENOENT) {
> -                               of_node_put(cnp);
> +                       if (err != -ENOENT)
>                                  return err;
> -                       }
>                          host->pdata[slot_id].detect_pin = NULL;
>                  }
> 
> @@ -673,10 +669,8 @@ static int atmci_of_init(struct atmel_mci *host)
>                                                "wp", GPIOD_IN, "wp-gpios");
>                  err = PTR_ERR_OR_ZERO(host->pdata[slot_id].wp_pin);
>                  if (err) {
> -                       if (err != -ENOENT) {
> -                               of_node_put(cnp);
> +                       if (err != -ENOENT)
>                                  return err;
> -                       }
>                          host->pdata[slot_id].wp_pin = NULL;
>                  }
>          }
> --
> 2.51.0
> 



From nicolas at ndufresne.ca  Wed Dec 24 08:34:20 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 24 Dec 2025 11:34:20 -0500
Subject: [PATCH v2 21/22] media: rockchip: rga: add rga3 support
In-Reply-To: <20251203-spu-rga3-v2-21-989a67947f71@pengutronix.de>
References: <20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de>
	 <20251203-spu-rga3-v2-21-989a67947f71@pengutronix.de>
Message-ID: <e85f35648ce5d4b969d7305c8cde0a21488a2340.camel@ndufresne.ca>

Hi,

Le mercredi 03 d?cembre 2025 ? 16:52 +0100, Sven P?schel a ?crit?:
> Add support for the RGA3 unit contained in the RK3588.
> 
> Only a basic feature set consisting of scaling and color conversion is
> implemented. Also the BT601F color space conversion is currently hard
> coded. Currently unimplemented features include:
> - Advanced formats like 10bit YUV, FBCE mode and Tile8x8 mode
> - Colorspace conversions functions BT601L, BT709, BT2020

This one I already raised in v1 as problematic omission. I applied the changes
locally and just ran few conversions that I saved to PNG, and I could
immediately see that range handling and colors are all over the place. Comparing
reference against conversion very often show difference in brighness or small
discoloration. On top of which, the compliance is failing.

More investigation needed, but I suspect the implementation is a little too
loose. Not handling any of it while accepting to do YCbCr to RGB (or vis-versa)
incorrect and should be fixed.

> - Background color (V4L2_CID_BG_COLOR)
> - Configurable alpha value (V4L2_CID_ALPHA_COMPONENT)
> - Image flipping (V4L2_CID_HFLIP and V4L2_CID_VFLIP)
> - Image rotation (V4L2_CID_ROTATE)
> - Image cropping/composing (VIDIOC_S_SELECTION)
> 
> The register address defines were copied from the
> vendor Rockchip kernel sources and slightly adjusted to not start at 0
> again for the cmd registers.
> 
> Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
> ---
> ?drivers/media/platform/rockchip/rga/Makefile? |?? 2 +-
> ?drivers/media/platform/rockchip/rga/rga.c???? |?? 4 +
> ?drivers/media/platform/rockchip/rga/rga.h???? |?? 2 +-
> ?drivers/media/platform/rockchip/rga/rga3-hw.c | 471 ++++++++++++++++++++++++++
> ?drivers/media/platform/rockchip/rga/rga3-hw.h | 190 +++++++++++
> ?5 files changed, 667 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/Makefile b/drivers/media/platform/rockchip/rga/Makefile
> index 1bbecdc3d8df2..7326a548f3dc7 100644
> --- a/drivers/media/platform/rockchip/rga/Makefile
> +++ b/drivers/media/platform/rockchip/rga/Makefile
> @@ -1,4 +1,4 @@
> ?# SPDX-License-Identifier: GPL-2.0-only
> -rockchip-rga-objs := rga.o rga-hw.o rga-buf.o
> +rockchip-rga-objs := rga.o rga-hw.o rga3-hw.o rga-buf.o
> ?
> ?obj-$(CONFIG_VIDEO_ROCKCHIP_RGA) += rockchip-rga.o
> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
> index 65686228b7300..313d875c789bf 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -843,6 +843,10 @@ static const struct of_device_id rockchip_rga_match[] = {
> ?		.compatible = "rockchip,rk3399-rga",
> ?		.data = &rga2_hw,
> ?	},
> +	{
> +		.compatible = "rockchip,rk3588-rga3",
> +		.data = &rga3_hw,
> +	},
> ?	{},
> ?};
> ?
> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
> index b9c75b5fda4dc..2c5f0330879fa 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -163,6 +163,6 @@ static inline bool rga_has_internal_iommu(const struct rockchip_rga *rga)
> ?	return rga->hw->has_internal_iommu;
> ?}
> ?
> -extern const struct rga_hw rga2_hw;
> +extern const struct rga_hw rga2_hw, rga3_hw;

nit: Add a line instead.

> ?
> ?#endif
> diff --git a/drivers/media/platform/rockchip/rga/rga3-hw.c b/drivers/media/platform/rockchip/rga/rga3-hw.c
> new file mode 100644
> index 0000000000000..2b8cd639da39b
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/rga/rga3-hw.c
> @@ -0,0 +1,471 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) Pengutronix e.K.

No year ?

> + * Author: Sven P?schel <s.pueschel at pengutronix.de>
> + */
> +
> +#include <linux/pm_runtime.h>
> +#include <linux/bitfield.h>
> +#include <linux/delay.h>
> +#include <linux/printk.h>
> +
> +#include <media/v4l2-common.h>
> +
> +#include "rga3-hw.h"
> +#include "rga.h"
> +
> +static unsigned int rga3_get_scaling(unsigned int src, unsigned int dst)
> +{
> +	/*
> +	 * RGA3 scaling factor calculation as described in chapter 5.4.7 Resize
> +	 * of the TRM Part 2. The resulting scaling factor is a 16-bit value
> +	 * and therefore normalized with 2^16.
> +	 *
> +	 * While the TRM also mentions (dst-1)/(src-1) for the up-scaling case,
> +	 * it didn't work as the value always exceeds 16 bit. Flipping the
> +	 * factors results in a correct up-scaling. This is possible as the
> +	 * RGA3 has the RGA3_WIN_SCALE_XXX_UP bit to determine if it does
> +	 * an up or downscale.
> +	 *
> +	 * With a scaling factor of 1.0 the calculation technically also
> +	 * overflows 16 bit. This isn't relevant, as in this case the
> +	 * RGA3_WIN_SCALE_XXX_BYPASS bit completely skips the scaling operation.
> +	 */
> +	if (dst > src) {
> +		if (((src - 1) << 16) % (dst - 1) == 0)
> +			return ((src - 1) << 16) / (dst - 1) - 1;
> +		else
> +			return ((src - 1) << 16) / (dst - 1);
> +	} else {
> +		return ((dst - 1) << 16) / (src - 1) + 1;
> +	}
> +}
> +
> +/*
> + * Check if the given format can be captured, as the RGA3 doesn't support all
> + * input formats also on it's output.
> + */
> +static bool rga3_can_capture(const struct rga3_fmt *fmt)
> +{
> +	return fmt->hw_format <= RGA3_COLOR_FMT_LAST_OUTPUT;
> +}
> +
> +/*
> + * Map the transformations to the RGA3 command buffer.
> + * Currently this is just the scaling settings and a fixed alpha value.
> + */
> +static void rga3_cmd_set_trans_info(struct rga_ctx *ctx)
> +{
> +	u32 *cmd = ctx->cmdbuf_virt;
> +	unsigned int src_h, src_w, dst_h, dst_w;
> +	unsigned int reg;
> +	u16 hor_scl_fac, ver_scl_fac;
> +	const struct rga3_fmt *in = ctx->in.fmt;
> +
> +	src_h = ctx->in.pix.height;
> +	src_w = ctx->in.pix.width;
> +	dst_h = ctx->out.pix.height;
> +	dst_w = ctx->out.pix.width;

These are padded dimensions, I think there should be code here that go pick from
the selection rectangles. Can't skip that, its way too common to have 1088 src_h
as an example. Otherwise, its not clear what will be result of using a scaling
factor while doing 1088 -> 1080, where the 8 lines are actually padding.

> +
> +	reg = RGA3_WIN0_RD_CTRL - RGA3_FIRST_CMD_REG;
> +	cmd[reg >> 2] |= FIELD_PREP(RGA3_WIN_SCALE_HOR_UP, dst_w > src_w)
> +		????? |? FIELD_PREP(RGA3_WIN_SCALE_HOR_BYPASS, dst_w == src_w)
> +		????? |? FIELD_PREP(RGA3_WIN_SCALE_VER_UP, dst_h > src_h)
> +		????? |? FIELD_PREP(RGA3_WIN_SCALE_VER_BYPASS, dst_h == src_h);
> +
> +	hor_scl_fac = rga3_get_scaling(src_w, dst_w);
> +	ver_scl_fac = rga3_get_scaling(src_h, dst_h);
> +	reg = RGA3_WIN0_SCL_FAC - RGA3_FIRST_CMD_REG;
> +	cmd[reg >> 2] = FIELD_PREP(RGA3_SCALE_HOR_FAC, hor_scl_fac)
> +		????? | FIELD_PREP(RGA3_SCALE_VER_FAC, ver_scl_fac);
> +
> +	if (v4l2_format_info(in->fourcc)->has_alpha) {
> +		/* copy alpha from input */
> +		reg = RGA3_OVLP_TOP_ALPHA - RGA3_FIRST_CMD_REG;
> +		cmd[reg >> 2] = FIELD_PREP(RGA3_ALPHA_SELECT_MODE, 1)
> +			????? | FIELD_PREP(RGA3_ALPHA_BLEND_MODE, 1);
> +		reg = RGA3_OVLP_BOT_ALPHA - RGA3_FIRST_CMD_REG;
> +		cmd[reg >> 2] = FIELD_PREP(RGA3_ALPHA_SELECT_MODE, 1)
> +			????? | FIELD_PREP(RGA3_ALPHA_BLEND_MODE, 1);
> +	} else {
> +		/* just use a 255 alpha value */
> +		reg = RGA3_OVLP_TOP_CTRL - RGA3_FIRST_CMD_REG;
> +		cmd[reg >> 2] = FIELD_PREP(RGA3_OVLP_GLOBAL_ALPHA, 0xff)
> +			????? | FIELD_PREP(RGA3_OVLP_COLOR_MODE, 1);
> +		reg = RGA3_OVLP_BOT_CTRL - RGA3_FIRST_CMD_REG;
> +		cmd[reg >> 2] = FIELD_PREP(RGA3_OVLP_GLOBAL_ALPHA, 0xff)
> +			????? | FIELD_PREP(RGA3_OVLP_COLOR_MODE, 1);
> +	}
> +}
> +
> +static void rga3_cmd_set_win0_addr(struct rga_ctx *ctx,
> +				?? const struct rga_addrs *addrs)
> +{
> +	u32 *cmd = ctx->cmdbuf_virt;
> +	unsigned int reg;
> +
> +	reg = RGA3_WIN0_Y_BASE - RGA3_FIRST_CMD_REG;
> +	cmd[reg >> 2] = addrs->y_addr;
> +	reg = RGA3_WIN0_U_BASE - RGA3_FIRST_CMD_REG;
> +	cmd[reg >> 2] = addrs->u_addr;
> +}
> +
> +static void rga3_cmd_set_wr_addr(struct rga_ctx *ctx,
> +				 const struct rga_addrs *addrs)
> +{
> +	u32 *cmd = ctx->cmdbuf_virt;
> +	unsigned int reg;
> +
> +	reg = RGA3_WR_Y_BASE - RGA3_FIRST_CMD_REG;
> +	cmd[reg >> 2] = addrs->y_addr;
> +	reg = RGA3_WR_U_BASE - RGA3_FIRST_CMD_REG;
> +	cmd[reg >> 2] = addrs->u_addr;
> +}
> +
> +/* Map the input pixel format to win0 of the comamnd buffer. */
> +static void rga3_cmd_set_win0_format(struct rga_ctx *ctx)
> +{
> +	u32 *cmd = ctx->cmdbuf_virt;
> +	const struct rga3_fmt *in = ctx->in.fmt;
> +	const struct rga3_fmt *out = ctx->out.fmt;
> +	const struct v4l2_format_info *in_fmt, *out_fmt;
> +	unsigned int src_h, src_w;
> +	bool r2y, y2r;
> +	u8 rd_format;
> +	unsigned int reg;
> +
> +	src_h = ctx->in.pix.height;
> +	src_w = ctx->in.pix.width;
> +
> +	in_fmt = v4l2_format_info(in->fourcc);
> +	out_fmt = v4l2_format_info(out->fourcc);
> +	r2y = v4l2_is_format_rgb(in_fmt) && v4l2_is_format_yuv(out_fmt);
> +	y2r = v4l2_is_format_yuv(in_fmt) && v4l2_is_format_rgb(out_fmt);
> +
> +	if (in->semi_planar)
> +		rd_format = RGA3_RDWR_FORMAT_SEMI_PLANAR;
> +	else
> +		rd_format = RGA3_RDWR_FORMAT_INTERLEAVED;
> +
> +	/* set pixel format and CSC */
> +	reg = RGA3_WIN0_RD_CTRL - RGA3_FIRST_CMD_REG;
> +	cmd[reg >> 2] |= FIELD_PREP(RGA3_WIN_PIC_FORMAT, in->hw_format)
> +		????? |? FIELD_PREP(RGA3_WIN_YC_SWAP, in->yc_swap)
> +		????? |? FIELD_PREP(RGA3_WIN_RBUV_SWAP, in->rbuv_swap)
> +		????? |? FIELD_PREP(RGA3_WIN_RD_FORMAT, rd_format)
> +		????? |? FIELD_PREP(RGA3_WIN_R2Y, r2y)
> +		????? |? FIELD_PREP(RGA3_WIN_Y2R, y2r)
> +		????? |? FIELD_PREP(RGA3_WIN_CSC_MODE, RGA3_WIN_CSC_MODE_BT601_F);

I'd say don't hardcode BT601 Full-Range. This in fact explains a lot of the
weird stuff I've seen so far.

This IP is extremely limited in CSC, it would be good to limite the choice in
try_fmt. Basically BT601 is the only thing that support full range, where the
more common BT709 and 2020 coeffiicent are most commonly used. Fortunatly,
limited range is more common, I can only guess, but RGB is likely always full
range.

I'm guessing when doing YCbCr to YCbCr the CSC is untouched. Make sure the
capture and output format reflects that.

Nicolas

> +
> +	/* set stride */
> +	reg = RGA3_WIN0_VIR_STRIDE - RGA3_FIRST_CMD_REG;
> +	/* stride needs to be in words */
> +	cmd[reg >> 2] = ctx->in.pix.plane_fmt[0].bytesperline >> 2;
> +	reg = RGA3_WIN0_UV_VIR_STRIDE - RGA3_FIRST_CMD_REG;
> +	/* The Hardware only supports formats with 1/2 planes */
> +	if (ctx->in.pix.num_planes == 2)
> +		cmd[reg >> 2] = ctx->in.pix.plane_fmt[1].bytesperline >> 2;
> +	else
> +		cmd[reg >> 2] = ctx->in.pix.plane_fmt[0].bytesperline >> 2;
> +
> +	/* set size */
> +	reg = RGA3_WIN0_ACT_SIZE - RGA3_FIRST_CMD_REG;
> +	cmd[reg >> 2] = FIELD_PREP(RGA3_WIDTH, src_w)
> +		????? | FIELD_PREP(RGA3_HEIGHT, src_h);
> +	/* no cropping support. Use same value as ACT_SIZE */
> +	reg = RGA3_WIN0_SRC_SIZE - RGA3_FIRST_CMD_REG;
> +	cmd[reg >> 2] = FIELD_PREP(RGA3_WIDTH, src_w)
> +		????? | FIELD_PREP(RGA3_HEIGHT, src_h);
> +}
> +
> +static void rga3_cmd_enable_win0(struct rga_ctx *ctx)
> +{
> +	u32 *cmd = ctx->cmdbuf_virt;
> +	unsigned int reg;
> +
> +	reg = RGA3_WIN0_RD_CTRL - RGA3_FIRST_CMD_REG;
> +	cmd[reg >> 2] |= FIELD_PREP(RGA3_WIN_ENABLE, 1);
> +}
> +
> +/* Map the output pixel format to the command buffer */
> +static void rga3_cmd_set_wr_format(struct rga_ctx *ctx)
> +{
> +	u32 *cmd = ctx->cmdbuf_virt;
> +	const struct rga3_fmt *out = ctx->out.fmt;
> +	unsigned int dst_h, dst_w;
> +	u8 wr_format;
> +	unsigned int reg;
> +
> +	dst_h = ctx->out.pix.height;
> +	dst_w = ctx->out.pix.width;
> +
> +	if (out->semi_planar)
> +		wr_format = RGA3_RDWR_FORMAT_SEMI_PLANAR;
> +	else
> +		wr_format = RGA3_RDWR_FORMAT_INTERLEAVED;
> +
> +	/* set pixel format */
> +	reg = RGA3_WR_CTRL - RGA3_FIRST_CMD_REG;
> +	cmd[reg >> 2] |= FIELD_PREP(RGA3_WR_PIC_FORMAT, out->hw_format)
> +		????? |? FIELD_PREP(RGA3_WR_YC_SWAP, out->yc_swap)
> +		????? |? FIELD_PREP(RGA3_WR_RBUV_SWAP, out->rbuv_swap)
> +		????? |? FIELD_PREP(RGA3_WR_FORMAT, wr_format);
> +
> +	/* set stride */
> +	reg = RGA3_WR_VIR_STRIDE - RGA3_FIRST_CMD_REG;
> +	/* stride needs to be in words */
> +	cmd[reg >> 2] = ctx->out.pix.plane_fmt[0].bytesperline >> 2;
> +	reg = RGA3_WR_PL_VIR_STRIDE - RGA3_FIRST_CMD_REG;
> +	/* The Hardware only supports formats with 1/2 planes */
> +	if (ctx->out.pix.num_planes == 2)
> +		cmd[reg >> 2] = ctx->out.pix.plane_fmt[1].bytesperline >> 2;
> +	else
> +		cmd[reg >> 2] = ctx->out.pix.plane_fmt[0].bytesperline >> 2;
> +
> +	/* Set size.
> +	 * As two inputs are not supported, we don't use win1.
> +	 * Therefore only set the size for win0.
> +	 */
> +	reg = RGA3_WIN0_DST_SIZE - RGA3_FIRST_CMD_REG;
> +	cmd[reg >> 2] = FIELD_PREP(RGA3_WIDTH, dst_w)
> +		????? | FIELD_PREP(RGA3_HEIGHT, dst_h);
> +}
> +
> +static void rga3_cmd_disable_wr_limitation(struct rga_ctx *ctx)
> +{
> +	u32 *cmd = ctx->cmdbuf_virt;
> +	unsigned int reg;
> +
> +	/* Use the max value to avoid limiting the write speed */
> +	reg = RGA3_WR_CTRL - RGA3_FIRST_CMD_REG;
> +	cmd[reg >> 2] |= FIELD_PREP(RGA3_WR_SW_OUTSTANDING_MAX, 63);
> +}
> +
> +static void rga3_hw_setup_cmdbuf(struct rga_ctx *ctx)
> +{
> +	memset(ctx->cmdbuf_virt, 0, RGA3_CMDBUF_SIZE * 4);
> +
> +	rga3_cmd_set_win0_format(ctx);
> +	rga3_cmd_enable_win0(ctx);
> +	rga3_cmd_set_trans_info(ctx);
> +	rga3_cmd_set_wr_format(ctx);
> +	rga3_cmd_disable_wr_limitation(ctx);
> +}
> +
> +static void rga3_hw_start(struct rockchip_rga *rga,
> +			? struct rga_vb_buffer *src, struct rga_vb_buffer *dst)
> +{
> +	struct rga_ctx *ctx = rga->curr;
> +
> +	rga3_cmd_set_win0_addr(ctx, &src->dma_addrs);
> +	rga3_cmd_set_wr_addr(ctx, &dst->dma_addrs);
> +
> +	rga_write(rga, RGA3_CMD_ADDR, ctx->cmdbuf_phy);
> +
> +	/* sync CMD buf for RGA */
> +	dma_sync_single_for_device(rga->dev, ctx->cmdbuf_phy,
> +				?? PAGE_SIZE, DMA_BIDIRECTIONAL);
> +
> +	/* set to master mode and start the conversion */
> +	rga_write(rga, RGA3_SYS_CTRL,
> +		? FIELD_PREP(RGA3_CMD_MODE, RGA3_CMD_MODE_MASTER));
> +	rga_write(rga, RGA3_INT_EN, FIELD_PREP(RGA3_INT_FRM_DONE, 1));
> +	rga_write(rga, RGA3_CMD_CTRL,
> +		? FIELD_PREP(RGA3_CMD_LINE_START_PULSE, 1));
> +}
> +
> +static bool rga3_handle_irq(struct rockchip_rga *rga)
> +{
> +	u32 intr;
> +
> +	intr = rga_read(rga, RGA3_INT_RAW);
> +	/* clear all interrupts */
> +	rga_write(rga, RGA3_INT_CLR, intr);
> +
> +	return FIELD_GET(RGA3_INT_FRM_DONE, intr);
> +}
> +
> +static void rga3_get_version(struct rockchip_rga *rga)
> +{
> +	u32 version = rga_read(rga, RGA3_VERSION_NUM);
> +
> +	rga->version.major = FIELD_GET(RGA3_VERSION_NUM_MAJOR, version);
> +	rga->version.minor = FIELD_GET(RGA3_VERSION_NUM_MINOR, version);
> +}
> +
> +static struct rga3_fmt rga3_formats[] = {
> +	{
> +		.fourcc = V4L2_PIX_FMT_RGB24,
> +		.hw_format = RGA3_COLOR_FMT_BGR888,
> +		.rbuv_swap = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_BGR24,
> +		.hw_format = RGA3_COLOR_FMT_BGR888,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_ABGR32,
> +		.hw_format = RGA3_COLOR_FMT_BGRA8888,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_RGBA32,
> +		.hw_format = RGA3_COLOR_FMT_BGRA8888,
> +		.rbuv_swap = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_XBGR32,
> +		.hw_format = RGA3_COLOR_FMT_BGRA8888,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_RGBX32,
> +		.hw_format = RGA3_COLOR_FMT_BGRA8888,
> +		.rbuv_swap = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_RGB565,
> +		.hw_format = RGA3_COLOR_FMT_BGR565,
> +		.rbuv_swap = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_NV12M,
> +		.hw_format = RGA3_COLOR_FMT_YUV420,
> +		.semi_planar = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_NV12,
> +		.hw_format = RGA3_COLOR_FMT_YUV420,
> +		.semi_planar = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_NV21M,
> +		.hw_format = RGA3_COLOR_FMT_YUV420,
> +		.rbuv_swap = 1,
> +		.semi_planar = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_NV21,
> +		.hw_format = RGA3_COLOR_FMT_YUV420,
> +		.rbuv_swap = 1,
> +		.semi_planar = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_NV16M,
> +		.hw_format = RGA3_COLOR_FMT_YUV422,
> +		.semi_planar = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_NV16,
> +		.hw_format = RGA3_COLOR_FMT_YUV422,
> +		.semi_planar = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_NV61M,
> +		.hw_format = RGA3_COLOR_FMT_YUV422,
> +		.rbuv_swap = 1,
> +		.semi_planar = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_NV61,
> +		.hw_format = RGA3_COLOR_FMT_YUV422,
> +		.rbuv_swap = 1,
> +		.semi_planar = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_YUYV,
> +		.hw_format = RGA3_COLOR_FMT_YUV422,
> +		.yc_swap = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_YVYU,
> +		.hw_format = RGA3_COLOR_FMT_YUV422,
> +		.yc_swap = 1,
> +		.rbuv_swap = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_UYVY,
> +		.hw_format = RGA3_COLOR_FMT_YUV422,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_VYUY,
> +		.hw_format = RGA3_COLOR_FMT_YUV422,
> +		.rbuv_swap = 1,
> +	},
> +	/* Input only formats last to keep rga3_enum_format simple */
> +	{
> +		.fourcc = V4L2_PIX_FMT_ARGB32,
> +		.hw_format = RGA3_COLOR_FMT_ABGR8888,
> +		.rbuv_swap = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_BGRA32,
> +		.hw_format = RGA3_COLOR_FMT_ABGR8888,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_XRGB32,
> +		.hw_format = RGA3_COLOR_FMT_ABGR8888,
> +		.rbuv_swap = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_BGRX32,
> +		.hw_format = RGA3_COLOR_FMT_ABGR8888,
> +	},
> +};
> +
> +static int rga3_enum_format(struct v4l2_fmtdesc *f)
> +{
> +	struct rga3_fmt *fmt;
> +
> +	if (f->index >= ARRAY_SIZE(rga3_formats))
> +		return -EINVAL;
> +
> +	fmt = &rga3_formats[f->index];
> +	if (V4L2_TYPE_IS_CAPTURE(f->type) && !rga3_can_capture(fmt))
> +		return -EINVAL;
> +
> +	f->pixelformat = fmt->fourcc;
> +	return 0;
> +}
> +
> +static void *rga3_adjust_and_map_format(struct v4l2_pix_format_mplane *format,
> +					bool is_output)
> +{
> +	unsigned int i;
> +
> +	if (!format)
> +		return &rga3_formats[0];
> +
> +	format->ycbcr_enc = V4L2_YCBCR_ENC_601;
> +	format->quantization = V4L2_QUANTIZATION_FULL_RANGE;
> +
> +	for (i = 0; i < ARRAY_SIZE(rga3_formats); i++) {
> +		if (!is_output && !rga3_can_capture(&rga3_formats[i]))
> +			continue;
> +
> +		if (rga3_formats[i].fourcc == format->pixelformat)
> +			return &rga3_formats[i];
> +	}
> +
> +	format->pixelformat = rga3_formats[0].fourcc;
> +	return &rga3_formats[0];
> +}
> +
> +const struct rga_hw rga3_hw = {
> +	.card_type = "rga3",
> +	.has_internal_iommu = false,
> +	.cmdbuf_size = RGA3_CMDBUF_SIZE,
> +	.min_width = RGA3_MIN_WIDTH,
> +	.min_height = RGA3_MIN_HEIGHT,
> +	/* use output size, as it's a bit smaller than the input size */
> +	.max_width = RGA3_MAX_OUTPUT_WIDTH,
> +	.max_height = RGA3_MAX_OUTPUT_HEIGHT,
> +	.max_scaling_factor = RGA3_MAX_SCALING_FACTOR,
> +	.stride_alignment = 16,
> +	.features = 0,
> +
> +	.setup_cmdbuf = rga3_hw_setup_cmdbuf,
> +	.start = rga3_hw_start,
> +	.handle_irq = rga3_handle_irq,
> +	.get_version = rga3_get_version,
> +	.enum_format = rga3_enum_format,
> +	.adjust_and_map_format = rga3_adjust_and_map_format,
> +};
> diff --git a/drivers/media/platform/rockchip/rga/rga3-hw.h b/drivers/media/platform/rockchip/rga/rga3-hw.h
> new file mode 100644
> index 0000000000000..fa16b95fb43ba
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/rga/rga3-hw.h
> @@ -0,0 +1,190 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (C) Pengutronix e.K.
> + * Author: Sven P?schel <s.pueschel at pengutronix.de>
> + */
> +#ifndef __RGA3_HW_H__
> +#define __RGA3_HW_H__
> +
> +#include <linux/bits.h>
> +#include <linux/types.h>
> +
> +#define RGA3_CMDBUF_SIZE 0x2e
> +
> +#define RGA3_MIN_WIDTH 128
> +#define RGA3_MIN_HEIGHT 128
> +#define RGA3_MAX_INPUT_WIDTH (8192 - 16)
> +#define RGA3_MAX_INPUT_HEIGHT (8192 - 16)
> +#define RGA3_MAX_OUTPUT_WIDTH (8192 - 64)
> +#define RGA3_MAX_OUTPUT_HEIGHT (8192 - 64)
> +#define RGA3_MAX_SCALING_FACTOR 8
> +#define RGA3_RESET_TIMEOUT 1000
> +
> +/* Registers address */
> +/* sys reg */
> +#define RGA3_SYS_CTRL				0x000
> +#define RGA3_CMD_CTRL				0x004
> +#define RGA3_CMD_ADDR				0x008
> +#define RGA3_MI_GROUP_CTRL			0x00c
> +#define RGA3_ARQOS_CTRL				0x010
> +#define RGA3_VERSION_NUM			0x018
> +#define RGA3_VERSION_TIM			0x01c
> +#define RGA3_INT_EN				0x020
> +#define RGA3_INT_RAW				0x024
> +#define RGA3_INT_MSK				0x028
> +#define RGA3_INT_CLR				0x02c
> +#define RGA3_RO_SRST				0x030
> +#define RGA3_STATUS0				0x034
> +#define RGA3_SCAN_CNT				0x038
> +#define RGA3_CMD_STATE				0x040
> +
> +/* cmd reg */
> +#define RGA3_WIN0_RD_CTRL			0x100
> +#define RGA3_FIRST_CMD_REG			RGA3_WIN0_RD_CTRL
> +#define RGA3_WIN0_Y_BASE			0x110
> +#define RGA3_WIN0_U_BASE			0x114
> +#define RGA3_WIN0_V_BASE			0x118
> +#define RGA3_WIN0_VIR_STRIDE			0x11c
> +#define RGA3_WIN0_FBC_OFF			0x120
> +#define RGA3_WIN0_SRC_SIZE			0x124
> +#define RGA3_WIN0_ACT_OFF			0x128
> +#define RGA3_WIN0_ACT_SIZE			0x12c
> +#define RGA3_WIN0_DST_SIZE			0x130
> +#define RGA3_WIN0_SCL_FAC			0x134
> +#define RGA3_WIN0_UV_VIR_STRIDE			0x138
> +#define RGA3_WIN1_RD_CTRL			0x140
> +#define RGA3_WIN1_Y_BASE			0x150
> +#define RGA3_WIN1_U_BASE			0x154
> +#define RGA3_WIN1_V_BASE			0x158
> +#define RGA3_WIN1_VIR_STRIDE			0x15c
> +#define RGA3_WIN1_FBC_OFF			0x160
> +#define RGA3_WIN1_SRC_SIZE			0x164
> +#define RGA3_WIN1_ACT_OFF			0x168
> +#define RGA3_WIN1_ACT_SIZE			0x16c
> +#define RGA3_WIN1_DST_SIZE			0x170
> +#define RGA3_WIN1_SCL_FAC			0x174
> +#define RGA3_WIN1_UV_VIR_STRIDE			0x178
> +#define RGA3_OVLP_CTRL				0x180
> +#define RGA3_OVLP_OFF				0x184
> +#define RGA3_OVLP_TOP_KEY_MIN			0x188
> +#define RGA3_OVLP_TOP_KEY_MAX			0x18c
> +#define RGA3_OVLP_TOP_CTRL			0x190
> +#define RGA3_OVLP_BOT_CTRL			0x194
> +#define RGA3_OVLP_TOP_ALPHA			0x198
> +#define RGA3_OVLP_BOT_ALPHA			0x19c
> +#define RGA3_WR_CTRL				0x1a0
> +#define RGA3_WR_FBCE_CTRL			0x1a4
> +#define RGA3_WR_VIR_STRIDE			0x1a8
> +#define RGA3_WR_PL_VIR_STRIDE			0x1ac
> +#define RGA3_WR_Y_BASE				0x1b0
> +#define RGA3_WR_U_BASE				0x1b4
> +#define RGA3_WR_V_BASE				0x1b8
> +
> +/* Registers value */
> +#define RGA3_COLOR_FMT_YUV420		0x0
> +#define RGA3_COLOR_FMT_YUV422		0x1
> +#define RGA3_COLOR_FMT_YUV420_10B	0x2
> +#define RGA3_COLOR_FMT_YUV422_10B	0x3
> +/*
> + * Use memory ordering names
> + * instead of the datasheet naming RGB formats in big endian order
> + */
> +#define RGA3_COLOR_FMT_BGR565		0x4
> +#define RGA3_COLOR_FMT_BGR888		0x5
> +#define RGA3_COLOR_FMT_FIRST_HAS_ALPHA	RGA3_COLOR_FMT_BGRA8888
> +#define RGA3_COLOR_FMT_BGRA8888		0x6
> +#define RGA3_COLOR_FMT_LAST_OUTPUT	RGA3_COLOR_FMT_BGRA8888
> +/* the following are only supported as inputs */
> +#define RGA3_COLOR_FMT_ABGR8888		0x7
> +/*
> + * the following seem to be unnecessary,
> + * as they can be achieved with RB swaps
> + */
> +#define RGA3_COLOR_FMT_RGBA8888		0x8
> +#define RGA3_COLOR_FMT_ARGB8888		0x9
> +
> +#define RGA3_RDWR_FORMAT_SEMI_PLANAR	0x1
> +#define RGA3_RDWR_FORMAT_INTERLEAVED	0x2
> +
> +#define RGA3_CMD_MODE_MASTER 0x1
> +
> +#define RGA3_WIN_CSC_MODE_BT601_F 0x2
> +
> +/* RGA masks */
> +/* SYS_CTRL */
> +#define RGA3_CCLK_SRESET BIT(4)
> +#define RGA3_ACLK_SRESET BIT(3)
> +#define RGA3_CMD_MODE BIT(1)
> +
> +/* CMD_CTRL */
> +#define RGA3_CMD_LINE_START_PULSE BIT(0)
> +
> +/* VERSION_NUM */
> +#define RGA3_VERSION_NUM_MAJOR GENMASK(31, 28)
> +#define RGA3_VERSION_NUM_MINOR GENMASK(27, 20)
> +
> +/* INT_* */
> +#define RGA3_INT_FRM_DONE BIT(0)
> +#define RGA3_INT_DMA_READ_BUS_ERR BIT(2)
> +#define RGA3_INT_WIN0_FBC_DEC_ERR BIT(5)
> +#define RGA3_INT_WIN0_HOR_ERR BIT(6)
> +#define RGA3_INT_WIN0_VER_ERR BIT(7)
> +#define RGA3_INT_WR_VER_ERR BIT(13)
> +#define RGA3_INT_WR_HOR_ERR BIT(14)
> +#define RGA3_INT_WR_BUS_ERR BIT(15)
> +#define RGA3_INT_WIN0_IN_FIFO_WR_ERR BIT(16)
> +#define RGA3_INT_WIN0_IN_FIFO_RD_ERR BIT(17)
> +#define RGA3_INT_WIN0_HOR_FIFO_WR_ERR BIT(18)
> +#define RGA3_INT_WIN0_HOR_FIFO_RD_ERR BIT(19)
> +#define RGA3_INT_WIN0_VER_FIFO_WR_ERR BIT(20)
> +#define RGA3_INT_WIN0_VER_FIFO_RD_ERR BIT(21)
> +
> +/* RO_SRST */
> +#define RGA3_RO_SRST_DONE GENMASK(5, 0)
> +
> +/* *_SIZE */
> +#define RGA3_HEIGHT GENMASK(28, 16)
> +#define RGA3_WIDTH GENMASK(12, 0)
> +
> +/* SCL_FAC */
> +#define RGA3_SCALE_VER_FAC GENMASK(31, 16)
> +#define RGA3_SCALE_HOR_FAC GENMASK(15, 0)
> +
> +/* WINx_CTRL */
> +#define RGA3_WIN_CSC_MODE GENMASK(27, 26)
> +#define RGA3_WIN_R2Y BIT(25)
> +#define RGA3_WIN_Y2R BIT(24)
> +#define RGA3_WIN_SCALE_VER_UP BIT(23)
> +#define RGA3_WIN_SCALE_VER_BYPASS BIT(22)
> +#define RGA3_WIN_SCALE_HOR_UP BIT(21)
> +#define RGA3_WIN_SCALE_HOR_BYPASS BIT(20)
> +#define RGA3_WIN_YC_SWAP BIT(13)
> +#define RGA3_WIN_RBUV_SWAP BIT(12)
> +#define RGA3_WIN_RD_FORMAT GENMASK(9, 8)
> +#define RGA3_WIN_PIC_FORMAT GENMASK(7, 4)
> +#define RGA3_WIN_ENABLE BIT(0)
> +
> +/* COLOR_CTRL */
> +#define RGA3_OVLP_GLOBAL_ALPHA GENMASK(23, 16)
> +#define RGA3_OVLP_COLOR_MODE BIT(0)
> +
> +/* ALPHA_CTRL */
> +#define RGA3_ALPHA_SELECT_MODE BIT(4)
> +#define RGA3_ALPHA_BLEND_MODE GENMASK(3, 2)
> +
> +/* WR_CTRL */
> +#define RGA3_WR_YC_SWAP BIT(20)
> +#define RGA3_WR_SW_OUTSTANDING_MAX GENMASK(18, 13)
> +#define RGA3_WR_RBUV_SWAP BIT(12)
> +#define RGA3_WR_FORMAT GENMASK(9, 8)
> +#define RGA3_WR_PIC_FORMAT GENMASK(7, 4)
> +
> +struct rga3_fmt {
> +	u32 fourcc;
> +	u8 hw_format;
> +	bool rbuv_swap;
> +	bool yc_swap;
> +	bool semi_planar;
> +};
> +
> +#endif
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/37fa291a/attachment-0001.sig>

From dsimic at manjaro.org  Wed Dec 24 08:52:03 2025
From: dsimic at manjaro.org (Dragan Simic)
Date: Wed, 24 Dec 2025 17:52:03 +0100
Subject: =?utf-8?q?Re=3A?= [PATCH v2 1/4] =?utf-8?q?PCI=3A?==?utf-8?q?_rockchip=3A?= 
 limit RK3399 to =?utf-8?q?2=2E5?= GT/s to prevent damage
In-Reply-To: <CANAwSgS6UeR4PJnWDxxcQbdH8u_4uNiQxCTugQS35LcPvpiwMQ@mail.gmail.com>
References: <cover.1763415705.git.geraldogabriel@gmail.com>
 <eaa9c75ca02a53f8bcc293b8bc73d013e26ec253.1763415706.git.geraldogabriel@gmail.com>
 <CANAwSgQ726J_vnDKEKd94Kq62kx8ToZzUGysz4r3tNAXvfAbGA@mail.gmail.com>
 <CAEsQvctSY7-RQEQF2TmJU2qKPZOe9TC5g-7Jat0LQKRHYz_6dQ@mail.gmail.com>
 <CANAwSgQPQUBi6VVb+hZNraMt71vnRpki+YK_at=Luo4aPVtOPg@mail.gmail.com> <0afea20b-be22-2404-5a8e-c798ed45f2fd@manjaro.org> <CANAwSgS6UeR4PJnWDxxcQbdH8u_4uNiQxCTugQS35LcPvpiwMQ@mail.gmail.com>
Message-ID: <648aa5c0-9e58-2404-4250-e83b8a748601@manjaro.org>

On Wednesday, December 24, 2025 17:11 CET, Anand Moon <linux.amoon at gmail.com> wrote:
> On Wed, 24 Dec 2025 at 18:25, Dragan Simic <dsimic at manjaro.org> wrote:
> > On Wednesday, December 24, 2025 09:04 CET, Anand Moon <linux.amoon at gmail.com> wrote:
> > > On Wed, 24 Dec 2025 at 11:08, Geraldo Nascimento
> > > <geraldogabriel at gmail.com> wrote:
> > > > On Wed, Dec 24, 2025 at 2:18?AM Anand Moon <linux.amoon at gmail.com> wrote:
> > > > > On Tue, 18 Nov 2025 at 03:17, Geraldo Nascimento
> > > > > <geraldogabriel at gmail.com> wrote:
> > > > > > Shawn Lin from Rockchip has reiterated that there may be danger in using
> > > > > > their PCIe with 5.0 GT/s speeds. Warn the user if they make a DT change
> > > > > > from the default and drive at 2.5 GT/s only, even if the DT
> > > > > > max-link-speed property is invalid or inexistent.
> > > > > >
> > > > > > This change is corroborated by RK3399 official datasheet [1], which
> > > > > > says maximum link speed for this platform is 2.5 GT/s.
> > > > > >
> > > > > > [1] https://opensource.rock-chips.com/images/d/d7/Rockchip_RK3399_Datasheet_V2.1-20200323.pdf
> > > > > >
> > > > > To accurately determine the operating speed, we can leverage the
> > > > > PCIE_CLIENT_BASIC_STATUS0/1 fields.
> > > > > This provides a dynamic mechanism to resolve the issue.
> > > > >
> > > > > [1] https://github.com/torvalds/linux/blob/master/drivers/pci/controller/pcie-rockchip-ep.c#L533-L595
> > > >
> > > > not to put you down but I think your approach adds unnecessary complexity.
> > > >
> > > > All I care really is that the Kernel Project isn't blamed in the
> > > > future if someone happens to lose their data.
> > > >
> > > Allow the hardware to negotiate the link speed based on the
> > > available number of lanes.
> > > I don?t anticipate any data loss, since PCIe will automatically
> > > configure the device speed with link training..
> >
> > Please, note that this isn't about performing auto negotiation
> > and following its results, but about "artificially" limiting the
> > PCIe link speed to 2.5 GT/s on RK3399, because it's well known
> > by Rockchip that 5 GT/s on RK3399's PCIe interface may cause
> > issues and data corruption in certain corner cases.
> >
> It?s possible the link speed wasn?t properly tuned. On my older
> development board,
> which supports this configuration, I haven?t observed any data loss.
> 
> sudo lspci -vvv | grep Speed
>                 LnkCap: Port #0, Speed 5GT/s, Width x1, ASPM L1, Exit
> Latency L1 <8us
>                 LnkSta: Speed 5GT/s, Width x1
>                 LnkCtl2: Target Link Speed: 5GT/s, EnterCompliance- SpeedDis-
>                 LnkCap: Port #1, Speed 5GT/s, Width x1, ASPM L0s L1,
> Exit Latency L0s unlimited, L1 <2us
>                 LnkSta: Speed 5GT/s, Width x1
>                 LnkCtl2: Target Link Speed: 5GT/s, EnterCompliance- SpeedDis-

Let me clarify, please...  This limitation to 2.5 GT/s came straight from
Rockchip a few years ago, described back then as an undisclosed errata.
Recently, we got some more details from Rockchip that confirmed 5 GT/s
as having issues in certain corner cases that cannot be validated by
performing some field tests or by observing the PCIe behavior under load.
Those corner cases with 5 GT/s, as described by Rockchip, are quite hard
to reach, but the possibility is still real.

To sum it up, yes, multiple people have reported 5 GT/s as "working for me"
on their RK3399-based boards and devices, but that unfortunately means
nothing in this case, due to the specific nature of the underlying issue.



From vz at mleia.com  Wed Dec 24 08:58:43 2025
From: vz at mleia.com (Vladimir Zapolskiy)
Date: Wed, 24 Dec 2025 18:58:43 +0200
Subject: [PATCH 0/2] ARM: dts: lpc32xx: minor updates to NAND controller nodes
Message-ID: <20251224165845.1261926-1-vz@mleia.com>

The changeset contains two minor updates to NXP LPC32xx NAND controller device
tree nodes.

Vladimir Zapolskiy (2):
  ARM: dts: lpc32xx: change NAND controllers node names
  ARM: dts: lpc32xx: describe FLASH_INT of SLC NAND controller

 arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

-- 
2.43.0



From vz at mleia.com  Wed Dec 24 08:58:45 2025
From: vz at mleia.com (Vladimir Zapolskiy)
Date: Wed, 24 Dec 2025 18:58:45 +0200
Subject: [PATCH 2/2] ARM: dts: lpc32xx: describe FLASH_INT of SLC NAND controller
In-Reply-To: <20251224165845.1261926-1-vz@mleia.com>
References: <20251224165845.1261926-1-vz@mleia.com>
Message-ID: <20251224165845.1261926-3-vz@mleia.com>

SLC and MLC NAND flash controllers fire the muxed interrupt FLASH_INT to
the SoC, add the interrupt property to the SLC device tree node.

Signed-off-by: Vladimir Zapolskiy <vz at mleia.com>
---
 arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
index 3d5a59b2886c..5ddaea8c481a 100644
--- a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
+++ b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
@@ -65,6 +65,7 @@ iram: sram at 8000000 {
 		slc: nand-controller at 20020000 {
 			compatible = "nxp,lpc3220-slc";
 			reg = <0x20020000 0x1000>;
+			interrupts = <11 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&clk LPC32XX_CLK_SLC>;
 			status = "disabled";
 		};
-- 
2.43.0



From vz at mleia.com  Wed Dec 24 08:58:44 2025
From: vz at mleia.com (Vladimir Zapolskiy)
Date: Wed, 24 Dec 2025 18:58:44 +0200
Subject: [PATCH 1/2] ARM: dts: lpc32xx: change NAND controllers node names
In-Reply-To: <20251224165845.1261926-1-vz@mleia.com>
References: <20251224165845.1261926-1-vz@mleia.com>
Message-ID: <20251224165845.1261926-2-vz@mleia.com>

The device tree node name of NAND controllers shall be 'nand-controller',
while 'flash' name is the name of NAND chip device tree nodes.

Signed-off-by: Vladimir Zapolskiy <vz at mleia.com>
---
 arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
index 206c66bdfe41..3d5a59b2886c 100644
--- a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
+++ b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
@@ -62,14 +62,14 @@ iram: sram at 8000000 {
 		/*
 		 * Enable either SLC or MLC
 		 */
-		slc: flash at 20020000 {
+		slc: nand-controller at 20020000 {
 			compatible = "nxp,lpc3220-slc";
 			reg = <0x20020000 0x1000>;
 			clocks = <&clk LPC32XX_CLK_SLC>;
 			status = "disabled";
 		};
 
-		mlc: flash at 200a8000 {
+		mlc: nand-controller at 200a8000 {
 			compatible = "nxp,lpc3220-mlc";
 			reg = <0x200a8000 0x11000>;
 			interrupts = <11 IRQ_TYPE_LEVEL_HIGH>;
-- 
2.43.0



From sudeep.holla at arm.com  Wed Dec 24 10:04:50 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Wed, 24 Dec 2025 18:04:50 +0000
Subject: [PATCH 2/3] clk: scpi: Simplify with scoped for each OF child
 loop
In-Reply-To: <20251224112239.83735-5-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251224112239.83735-4-krzysztof.kozlowski@oss.qualcomm.com>
 <20251224112239.83735-5-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <aUwrQiALSG8MRj2L@bogus>

On Wed, Dec 24, 2025 at 12:22:41PM +0100, Krzysztof Kozlowski wrote:
> Use scoped for-each loop when iterating over device nodes to make code a
> bit simpler.
> 

Reviewed-by: Sudeep Holla <sudeep.holla at arm.com>

-- 
Regards,
Sudeep


From sudeep.holla at arm.com  Wed Dec 24 10:05:23 2025
From: sudeep.holla at arm.com (Sudeep Holla)
Date: Wed, 24 Dec 2025 18:05:23 +0000
Subject: [PATCH 3/3] clk: versatile: impd1: Simplify with scoped for each
 OF child loop
In-Reply-To: <20251224112239.83735-6-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251224112239.83735-4-krzysztof.kozlowski@oss.qualcomm.com>
 <20251224112239.83735-6-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <aUwrYwGFhRFBAizq@bogus>

On Wed, Dec 24, 2025 at 12:22:42PM +0100, Krzysztof Kozlowski wrote:
> Use scoped for-each loop when iterating over device nodes to make code a
> bit simpler.
> 

Reviewed-by: Sudeep Holla <sudeep.holla at arm.com>

-- 
Regards,
Sudeep


From amitsd at google.com  Wed Dec 24 11:07:38 2025
From: amitsd at google.com (Amit Sunil Dhamne)
Date: Wed, 24 Dec 2025 11:07:38 -0800
Subject: [PATCH v2 1/5] dt-bindings: mfd: maxim,max77759: add charger
 child node
In-Reply-To: <411802b6-517d-497e-bf7b-183e6e6d7a64@kernel.org>
References: <20251218-max77759-charger-v2-0-2b259980a686@google.com>
 <20251218-max77759-charger-v2-1-2b259980a686@google.com>
 <411802b6-517d-497e-bf7b-183e6e6d7a64@kernel.org>
Message-ID: <c3599851-6e19-4ed9-9ce7-703746b978e7@google.com>

Hi Krzysztof,

On 12/19/25 12:17 AM, Krzysztof Kozlowski wrote:
> On 18/12/2025 23:49, Amit Sunil Dhamne via B4 Relay wrote:
>> From: Amit Sunil Dhamne <amitsd at google.com>
>>
>> The Maxim MAX77759 MFD includes a charger function. Extend the max77759
>> binding to include the charger. Also, update the example to include
>> charger.
>>
>> Signed-off-by: Amit Sunil Dhamne <amitsd at google.com>
>> ---
>>  .../devicetree/bindings/mfd/maxim,max77759.yaml    | 33 ++++++++++++++++++++++
>>  1 file changed, 33 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml b/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml
>> index 525de9ab3c2b..1cffdf2e5776 100644
>> --- a/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml
>> +++ b/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml
>> @@ -37,6 +37,30 @@ properties:
>>    nvmem-0:
>>      $ref: /schemas/nvmem/maxim,max77759-nvmem.yaml
>>  
>> +  charger:
>> +    type: object
>> +    description: This is a dual input switch mode battery charger for portable
>> +      applications. It supports wired and wireless charging and can operate in
>> +      buck and boost mode.
>> +
>
> I do not see any improvements, so same comment: this should be folded
> into the parent.

I misunderstood the folding comment for merging the charger binding into
mfd.


> Please read DTS 101 slides or writing bindings or any other talks...

This gives a lot more context. Thanks for the pointer. I also reviewed a
few recently merged mfd (with charger being a cell) patches as well.

I realize that you're asking me to remove the charger node and re-anchor
its properties to the pmic mfd device. I will update it in the next
revision.


BR,

Amit

>
> Best regards,
> Krzysztof


From nicolas at ndufresne.ca  Wed Dec 24 11:10:30 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 24 Dec 2025 14:10:30 -0500
Subject: [PATCH 3/4] media: rkvdec: Add support for the VDPU346 variant
In-Reply-To: <20251206082809.2040679-4-christianshewitt@gmail.com>
References: <20251206082809.2040679-1-christianshewitt@gmail.com>
	 <20251206082809.2040679-4-christianshewitt@gmail.com>
Message-ID: <92defeb3fdc1f1dac636671f44155e5b73246e79.camel@ndufresne.ca>

Le samedi 06 d?cembre 2025 ? 08:28 +0000, Christian Hewitt a ?crit?:
> VDPU346 is derived from VDPU381 but with a single core and limited
> to 4K60 media. It is also limited to H264 L5.1 and omits AV1 and
> AVS2 capabilities. It is used with RK3566 and RK3568.
> 
> Signed-off-by: Christian Hewitt <christianshewitt at gmail.com>

Reviewed-by: Nicolas Dufresne <nicolas.collabora at collabora.com>

Please resend whenever there is a dependency update, I believe some of the
variant stuff is being modified. Another note, I tried bigger resolution, but it
only yielded green images, so the 65K max does not actually work and will need
investigation.

Nicolas

> ---
> ?.../media/platform/rockchip/rkvdec/rkvdec.c?? | 110 ++++++++++++++++++
> ?1 file changed, 110 insertions(+)
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> index a1c02ef3a97c..cf68454b2217 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> @@ -295,6 +295,62 @@ static const struct rkvdec_ctrls rkvdec_h264_ctrls = {
> ?	.num_ctrls = ARRAY_SIZE(rkvdec_h264_ctrl_descs),
> ?};
> ?
> +static const struct rkvdec_ctrl_desc vdpu346_hevc_ctrl_descs[] = {
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_SPS,
> +		.cfg.ops = &rkvdec_ctrl_ops,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_PPS,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_MODE,
> +		.cfg.min = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
> +		.cfg.max = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
> +		.cfg.def = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_START_CODE,
> +		.cfg.min = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
> +		.cfg.def = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
> +		.cfg.max = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
> +		.cfg.min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
> +		.cfg.max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
> +		.cfg.menu_skip_mask =
> +			BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE),
> +		.cfg.def = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
> +		.cfg.min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
> +		.cfg.max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS,
> +		.cfg.ops = &rkvdec_ctrl_ops,
> +		.cfg.dims = { 65 },
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS,
> +		.cfg.ops = &rkvdec_ctrl_ops,
> +		.cfg.dims = { 65 },
> +	},
> +};
> +
> +static const struct rkvdec_ctrls vdpu346_hevc_ctrls = {
> +	.ctrls = vdpu346_hevc_ctrl_descs,
> +	.num_ctrls = ARRAY_SIZE(vdpu346_hevc_ctrl_descs),
> +};
> +
> ?static const struct rkvdec_ctrl_desc vdpu38x_hevc_ctrl_descs[] = {
> ?	{
> ?		.cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS,
> @@ -449,6 +505,43 @@ static const struct rkvdec_coded_fmt_desc
> rkvdec_coded_fmts[] = {
> ?	}
> ?};
> ?
> +static const struct rkvdec_coded_fmt_desc vdpu346_coded_fmts[] = {
> +	{
> +		.fourcc = V4L2_PIX_FMT_H264_SLICE,
> +		.frmsize = {
> +			.min_width = 64,
> +			.max_width =? 65520,
> +			.step_width = 64,
> +			.min_height = 64,
> +			.max_height =? 65520,
> +			.step_height = 16,
> +		},
> +		.ctrls = &rkvdec_h264_ctrls,
> +		.ops = &rkvdec_vdpu381_h264_fmt_ops,
> +		.num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts),
> +		.decoded_fmts = rkvdec_h264_decoded_fmts,
> +		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
> +		.capability = RKVDEC_CAPABILITY_H264,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_HEVC_SLICE,
> +		.frmsize = {
> +			.min_width = 64,
> +			.max_width = 65472,
> +			.step_width = 64,
> +			.min_height = 64,
> +			.max_height = 65472,
> +			.step_height = 16,
> +		},
> +		.ctrls = &vdpu346_hevc_ctrls,
> +		.ops = &rkvdec_vdpu381_hevc_fmt_ops,
> +		.num_decoded_fmts = ARRAY_SIZE(rkvdec_hevc_decoded_fmts),
> +		.decoded_fmts = rkvdec_hevc_decoded_fmts,
> +		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
> +		.capability = RKVDEC_CAPABILITY_HEVC,
> +	},
> +};
> +
> ?static const struct rkvdec_coded_fmt_desc vdpu381_coded_fmts[] = {
> ?	{
> ?		.fourcc = V4L2_PIX_FMT_H264_SLICE,
> @@ -1654,6 +1747,19 @@ static const struct rkvdec_variant
> rk3399_rkvdec_variant = {
> ?			RKVDEC_CAPABILITY_VP9,
> ?};
> ?
> +static const struct rkvdec_variant rk3568_vdpu346_variant = {
> +	.coded_fmts = vdpu346_coded_fmts,
> +	.num_coded_fmts = ARRAY_SIZE(vdpu346_coded_fmts),
> +	.rcb_sizes = vdpu381_rcb_sizes,
> +	.num_rcb_sizes = ARRAY_SIZE(vdpu381_rcb_sizes),
> +	.irq_handler = vdpu381_irq_handler,
> +	.colmv_size = rkvdec_colmv_size,
> +	.flatten_matrices = transpose_and_flatten_matrices,
> +	.named_regs = true,
> +	.capabilities = RKVDEC_CAPABILITY_H264 |
> +			RKVDEC_CAPABILITY_HEVC,
> +};
> +
> ?static const struct rkvdec_variant rk3588_vdpu381_variant = {
> ?	.coded_fmts = vdpu381_coded_fmts,
> ?	.num_coded_fmts = ARRAY_SIZE(vdpu381_coded_fmts),
> @@ -1693,6 +1799,10 @@ static const struct of_device_id of_rkvdec_match[] = {
> ?		.compatible = "rockchip,rk3399-vdec",
> ?		.data = &rk3399_rkvdec_variant,
> ?	},
> +	{
> +		.compatible = "rockchip,rk3568-vdec",
> +		.data = &rk3568_vdpu346_variant,
> +	},
> ?	{
> ?		.compatible = "rockchip,rk3588-vdec",
> ?		.data = &rk3588_vdpu381_variant,
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/155bbb0b/attachment-0001.sig>

From amitsd at google.com  Wed Dec 24 11:11:42 2025
From: amitsd at google.com (Amit Sunil Dhamne)
Date: Wed, 24 Dec 2025 11:11:42 -0800
Subject: [PATCH v2 1/5] dt-bindings: mfd: maxim,max77759: add charger
 child node
In-Reply-To: <3d156c45-b55d-4ca4-95d6-0d06e067bbdb@kernel.org>
References: <20251218-max77759-charger-v2-0-2b259980a686@google.com>
 <20251218-max77759-charger-v2-1-2b259980a686@google.com>
 <411802b6-517d-497e-bf7b-183e6e6d7a64@kernel.org>
 <3d156c45-b55d-4ca4-95d6-0d06e067bbdb@kernel.org>
Message-ID: <27d2a9de-487a-409b-8807-d1d3bf9e8ee7@google.com>


On 12/23/25 5:32 AM, Krzysztof Kozlowski wrote:
> On 19/12/2025 09:17, Krzysztof Kozlowski wrote:
>> On 18/12/2025 23:49, Amit Sunil Dhamne via B4 Relay wrote:
>>> From: Amit Sunil Dhamne <amitsd at google.com>
>>>
>>> The Maxim MAX77759 MFD includes a charger function. Extend the max77759
>>> binding to include the charger. Also, update the example to include
>>> charger.
>>>
>>> Signed-off-by: Amit Sunil Dhamne <amitsd at google.com>
>>> ---
>>>  .../devicetree/bindings/mfd/maxim,max77759.yaml    | 33 ++++++++++++++++++++++
>>>  1 file changed, 33 insertions(+)
>>>
>>> diff --git a/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml b/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml
>>> index 525de9ab3c2b..1cffdf2e5776 100644
>>> --- a/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml
>>> +++ b/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml
>>> @@ -37,6 +37,30 @@ properties:
>>>    nvmem-0:
>>>      $ref: /schemas/nvmem/maxim,max77759-nvmem.yaml
>>>  
>>> +  charger:
>>> +    type: object
>>> +    description: This is a dual input switch mode battery charger for portable
>>> +      applications. It supports wired and wireless charging and can operate in
>>> +      buck and boost mode.
>>> +
>>
>> I do not see any improvements, so same comment: this should be folded
>> into the parent.
>>
>> Please read DTS 101 slides or writing bindings or any other talks...
>>
> No responses to my emails for a few days,so I assume discussion is done
> and I mark it as changes requested in patchwork.

Yes please. Sorry about the delay.

>
> Best regards,
> Krzysztof


From duje at dujemihanovic.xyz  Wed Dec 24 11:14:43 2025
From: duje at dujemihanovic.xyz (Duje =?UTF-8?B?TWloYW5vdmnEhw==?=)
Date: Wed, 24 Dec 2025 20:14:43 +0100
Subject: [PATCH v2 2/2] pmdomain: add audio power island for Marvell PXA1908 SoC
In-Reply-To: <20251213084843.7491-2-balejk@matfyz.cz>
References: <20251213084843.7491-1-balejk@matfyz.cz>
 <20251213084843.7491-2-balejk@matfyz.cz>
Message-ID: <5977726.DvuYhMxLoT@radijator>

On Saturday, 13 December 2025 09:48:13 Central European Standard Time Karel 
Balej wrote:
> Define power domain which needs to be enabled in order for audio to work
> on the PXA1908-based samsung,coreprimevelte smartphone. In the
> downstream code, this power-on method is marked as specific to the ULCx
> series which is allegedly a codename of sorts with ULC1 corresponding to
> the PXA1908.
> 
> No other audio components needed for sound to work on this phone are
> currently available mainline but some successful testing was performed
> with the vendor variants of the respective drivers and with the domain
> forced always-on.
> 
> Signed-off-by: Karel Balej <balejk at matfyz.cz>

Reviewed-by: Duje Mihanovi? <duje at dujemihanovic.xyz>

Regards,
--
Duje




From nicolas at ndufresne.ca  Wed Dec 24 11:18:02 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 24 Dec 2025 14:18:02 -0500
Subject: [PATCH v4 1/3] media: docs: dev-decoder: Trigger dynamic source
 change for colorspace
In-Reply-To: <20251217030227.1546-2-ming.qian@oss.nxp.com>
References: <20251217030227.1546-1-ming.qian@oss.nxp.com>
	 <20251217030227.1546-2-ming.qian@oss.nxp.com>
Message-ID: <b6ae2f157fb6fd0b80602f363b99dab1dc0b1cc6.camel@ndufresne.ca>

Le mercredi 17 d?cembre 2025 ? 11:02 +0800, ming.qian at oss.nxp.com a ?crit?:
> From: Ming Qian <ming.qian at oss.nxp.com>
> 
> If colorspace changes, the client needs to renegotiate the pipeline,
> otherwise the decoded frame may not be displayed correctly.
> 
> So add colorspace as a trigger parameter for dynamic resolution change.
> 
> Signed-off-by: Ming Qian <ming.qian at oss.nxp.com>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?Documentation/userspace-api/media/v4l/dev-decoder.rst | 5 ++++-
> ?1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/userspace-api/media/v4l/dev-decoder.rst
> b/Documentation/userspace-api/media/v4l/dev-decoder.rst
> index eb662ced0ab4..2beb6ba1b3c2 100644
> --- a/Documentation/userspace-api/media/v4l/dev-decoder.rst
> +++ b/Documentation/userspace-api/media/v4l/dev-decoder.rst
> @@ -933,7 +933,10 @@ reflected by corresponding queries):
> ?
> ?* the minimum number of buffers needed for decoding,
> ?
> -* bit-depth of the bitstream has been changed.
> +* bit-depth of the bitstream has been changed,
> +
> +* colorspace of the bitstream has been changed, but it doesn't require
> +? buffer reallocation.
> ?
> ?Whenever that happens, the decoder must proceed as follows:
> ?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/d0db1db0/attachment.sig>

From nicolas at ndufresne.ca  Wed Dec 24 11:19:58 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 24 Dec 2025 14:19:58 -0500
Subject: [PATCH v4 2/3] media: amphion: Clear last_buffer_dequeued flag
 for DEC_CMD_START
In-Reply-To: <20251217030227.1546-3-ming.qian@oss.nxp.com>
References: <20251217030227.1546-1-ming.qian@oss.nxp.com>
	 <20251217030227.1546-3-ming.qian@oss.nxp.com>
Message-ID: <5500fa4f4ee321a451360a84cf5834781c1a9615.camel@ndufresne.ca>

Le mercredi 17 d?cembre 2025 ? 11:02 +0800, ming.qian at oss.nxp.com a ?crit?:
> From: Ming Qian <ming.qian at oss.nxp.com>
> 
> The V4L2_DEC_CMD_START command may be used to handle the dynamic source
> change, which will triggers an implicit decoder drain.
> The last_buffer_dequeued flag is set in the implicit decoder drain,
> so driver need to clear it to continue the following decoding flow.
> 
> Signed-off-by: Ming Qian <ming.qian at oss.nxp.com>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?drivers/media/platform/amphion/vdec.c | 1 +
> ?1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/media/platform/amphion/vdec.c b/drivers/media/platform/amphion/vdec.c
> index c0d2aabb9e0e..f25dbcebdccf 100644
> --- a/drivers/media/platform/amphion/vdec.c
> +++ b/drivers/media/platform/amphion/vdec.c
> @@ -724,6 +724,7 @@ static int vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd
> ?	switch (cmd->cmd) {
> ?	case V4L2_DEC_CMD_START:
> ?		vdec_cmd_start(inst);
> +		vb2_clear_last_buffer_dequeued(v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx));
> ?		break;
> ?	case V4L2_DEC_CMD_STOP:
> ?		vdec_cmd_stop(inst);
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/20f08fcd/attachment-0001.sig>

From nicolas at ndufresne.ca  Wed Dec 24 11:24:59 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 24 Dec 2025 14:24:59 -0500
Subject: [PATCH v4 3/3] media: amphion: Trigger source change if
 colorspace changed
In-Reply-To: <20251217030227.1546-4-ming.qian@oss.nxp.com>
References: <20251217030227.1546-1-ming.qian@oss.nxp.com>
	 <20251217030227.1546-4-ming.qian@oss.nxp.com>
Message-ID: <8d5952b87a1456b2b2203b6321888a16980d7a8b.camel@ndufresne.ca>

Hi Ming,

Le mercredi 17 d?cembre 2025 ? 11:02 +0800, ming.qian at oss.nxp.com a ?crit?:
> From: Ming Qian <ming.qian at oss.nxp.com>
> 
> After encountering a colorspace change in the stream, the decoder
> sends a V4L2_EVENT_SOURCE_CHANGE event with changes set to
> V4L2_EVENT_SRC_CH_RESOLUTION.
> 
> Then the client can detect and handle the colorspace change without any
> buffer reallocation
> 
> Signed-off-by: Ming Qian <ming.qian at oss.nxp.com>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

> ---
> ?drivers/media/platform/amphion/vdec.c???? | 61 +++++++++++++++--------
> ?drivers/media/platform/amphion/vpu_v4l2.c |? 1 -
> ?2 files changed, 40 insertions(+), 22 deletions(-)
> 
> diff --git a/drivers/media/platform/amphion/vdec.c b/drivers/media/platform/amphion/vdec.c
> index f25dbcebdccf..beeaf75c76b4 100644
> --- a/drivers/media/platform/amphion/vdec.c
> +++ b/drivers/media/platform/amphion/vdec.c
> @@ -950,7 +950,7 @@ static void vdec_stop_done(struct vpu_inst *inst)
> ?	vpu_inst_unlock(inst);
> ?}
> ?
> -static bool vdec_check_source_change(struct vpu_inst *inst)
> +static bool vdec_check_source_change(struct vpu_inst *inst, struct vpu_dec_codec_info *hdr)
> ?{
> ?	struct vdec_t *vdec = inst->priv;
> ?	const struct vpu_format *sibling;
> @@ -962,26 +962,35 @@ static bool vdec_check_source_change(struct vpu_inst *inst)
> ?		return false;
> ?
> ?	sibling = vpu_helper_find_sibling(inst, inst->cap_format.type, inst->cap_format.pixfmt);
> -	if (sibling && vdec->codec_info.pixfmt == sibling->pixfmt)
> -		vdec->codec_info.pixfmt = inst->cap_format.pixfmt;
> +	if (sibling && hdr->pixfmt == sibling->pixfmt)
> +		hdr->pixfmt = inst->cap_format.pixfmt;
> ?
> ?	if (!vb2_is_streaming(v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx)))
> ?		return true;
> -	if (inst->cap_format.pixfmt != vdec->codec_info.pixfmt)
> +	if (inst->cap_format.pixfmt != hdr->pixfmt)
> ?		return true;
> -	if (inst->cap_format.width != vdec->codec_info.decoded_width)
> +	if (inst->cap_format.width != hdr->decoded_width)
> ?		return true;
> -	if (inst->cap_format.height != vdec->codec_info.decoded_height)
> +	if (inst->cap_format.height != hdr->decoded_height)
> ?		return true;
> ?	if (vpu_get_num_buffers(inst, inst->cap_format.type) < inst->min_buffer_cap)
> ?		return true;
> -	if (inst->crop.left != vdec->codec_info.offset_x)
> +	if (inst->crop.left != hdr->offset_x)
> ?		return true;
> -	if (inst->crop.top != vdec->codec_info.offset_y)
> +	if (inst->crop.top != hdr->offset_y)
> ?		return true;
> -	if (inst->crop.width != vdec->codec_info.width)
> +	if (inst->crop.width != hdr->width)
> ?		return true;
> -	if (inst->crop.height != vdec->codec_info.height)
> +	if (inst->crop.height != hdr->height)
> +		return true;
> +	if (!hdr->progressive)
> +		return true;
> +
> +	if (vdec->seq_hdr_found &&
> +	??? (hdr->color_primaries != vdec->codec_info.color_primaries ||
> +	???? hdr->transfer_chars != vdec->codec_info.transfer_chars ||
> +	???? hdr->matrix_coeffs != vdec->codec_info.matrix_coeffs ||
> +	???? hdr->full_range != vdec->codec_info.full_range))
> ?		return true;
> ?
> ?	return false;
> @@ -1333,20 +1342,25 @@ static void vdec_event_seq_hdr(struct vpu_inst *inst, struct vpu_dec_codec_info
> ?	struct vdec_t *vdec = inst->priv;
> ?
> ?	vpu_inst_lock(inst);
> -	memcpy(&vdec->codec_info, hdr, sizeof(vdec->codec_info));
> ?
> -	vpu_trace(inst->dev, "[%d] %d x %d, crop : (%d, %d) %d x %d, %d, %d\n",
> +	vpu_trace(inst->dev,
> +		? "[%d] %d x %d, crop : (%d, %d) %d x %d, %d, %d, colorspace: %d, %d, %d, %d\n",
> ?		? inst->id,
> -		? vdec->codec_info.decoded_width,
> -		? vdec->codec_info.decoded_height,
> -		? vdec->codec_info.offset_x,
> -		? vdec->codec_info.offset_y,
> -		? vdec->codec_info.width,
> -		? vdec->codec_info.height,
> +		? hdr->decoded_width,
> +		? hdr->decoded_height,
> +		? hdr->offset_x,
> +		? hdr->offset_y,
> +		? hdr->width,
> +		? hdr->height,
> ?		? hdr->num_ref_frms,
> -		? hdr->num_dpb_frms);
> +		? hdr->num_dpb_frms,
> +		? hdr->color_primaries,
> +		? hdr->transfer_chars,
> +		? hdr->matrix_coeffs,
> +		? hdr->full_range);
> ?	inst->min_buffer_cap = hdr->num_ref_frms + hdr->num_dpb_frms;
> -	vdec->is_source_changed = vdec_check_source_change(inst);
> +	vdec->is_source_changed = vdec_check_source_change(inst, hdr);
> +	memcpy(&vdec->codec_info, hdr, sizeof(vdec->codec_info));
> ?	vdec_init_fmt(inst);
> ?	vdec_init_crop(inst);
> ?	vdec_init_mbi(inst);
> @@ -1375,7 +1389,12 @@ static void vdec_event_resolution_change(struct vpu_inst *inst)
> ?{
> ?	struct vdec_t *vdec = inst->priv;
> ?
> -	vpu_trace(inst->dev, "[%d]\n", inst->id);
> +	vpu_trace(inst->dev, "[%d] input : %d, decoded : %d, display : %d, sequence : %d\n",
> +		? inst->id,
> +		? vdec->params.frame_count,
> +		? vdec->decoded_frame_count,
> +		? vdec->display_frame_count,
> +		? vdec->sequence);
> ?	vpu_inst_lock(inst);
> ?	vdec->seq_tag = vdec->codec_info.tag;
> ?	vdec_clear_fs(&vdec->mbi);
> diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c
> index 47dff9a35bb4..121165a7184f 100644
> --- a/drivers/media/platform/amphion/vpu_v4l2.c
> +++ b/drivers/media/platform/amphion/vpu_v4l2.c
> @@ -102,7 +102,6 @@ static int vpu_notify_eos(struct vpu_inst *inst)
> ?int vpu_notify_source_change(struct vpu_inst *inst)
> ?{
> ?	static const struct v4l2_event ev = {
> -		.id = 0,
> ?		.type = V4L2_EVENT_SOURCE_CHANGE,
> ?		.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION
> ?	};
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/03bc50c5/attachment.sig>

From nicolas at ndufresne.ca  Wed Dec 24 11:34:19 2025
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Wed, 24 Dec 2025 14:34:19 -0500
Subject: [PATCH v2 4/4] media: mediatek: jpeg: add compatible for MT8189
 SoC
In-Reply-To: <20251224031721.9942-5-jianhua.lin@mediatek.com>
References: <20251224031721.9942-1-jianhua.lin@mediatek.com>
	 <20251224031721.9942-5-jianhua.lin@mediatek.com>
Message-ID: <2974614b2440ed828f49ff7819ca7935d7bb8109.camel@ndufresne.ca>

Le mercredi 24 d?cembre 2025 ? 11:17 +0800, Jianhua Lin a ?crit?:
> Compared to the previous generation IC, the MT8189 uses 34-bit iova
> address-space (16GB) and requires a single clock configuration.
> Therefore, add new compatible to support the JPEG encoder and decoder
> of MT8189 SoC.
> 
> Signed-off-by: Jianhua Lin <jianhua.lin at mediatek.com>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

I'll have to wait for some ack on the bindings, which looks otherwise fine to
me. But due to holiday, that might be delayed a little bit.

cheers,
Nicolas

> ---
> ?.../platform/mediatek/jpeg/mtk_jpeg_core.c??? | 44 +++++++++++++++++++
> ?1 file changed, 44 insertions(+)
> 
> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> index d08fe365cbb2..9ea8d8f56e9b 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> @@ -1866,6 +1866,10 @@ static struct clk_bulk_data mt8173_jpeg_dec_clocks[] =
> {
> ?	{ .id = "jpgdec" },
> ?};
> ?
> +static struct clk_bulk_data mtk_jpeg_dec_clocks[] = {
> +	{ .id = "jpgdec" },
> +};
> +
> ?static const struct mtk_jpeg_variant mt8173_jpeg_drvdata = {
> ?	.clks = mt8173_jpeg_dec_clocks,
> ?	.num_clks = ARRAY_SIZE(mt8173_jpeg_dec_clocks),
> @@ -1897,6 +1901,38 @@ static const struct mtk_jpeg_variant mtk_jpeg_drvdata =
> {
> ?	.multi_core = false,
> ?};
> ?
> +static const struct mtk_jpeg_variant mtk8189_jpegenc_drvdata = {
> +	.clks = mtk_jpeg_clocks,
> +	.num_clks = ARRAY_SIZE(mtk_jpeg_clocks),
> +	.formats = mtk_jpeg_enc_formats,
> +	.num_formats = MTK_JPEG_ENC_NUM_FORMATS,
> +	.qops = &mtk_jpeg_enc_qops,
> +	.irq_handler = mtk_jpeg_enc_irq,
> +	.hw_reset = mtk_jpeg_enc_reset,
> +	.m2m_ops = &mtk_jpeg_enc_m2m_ops,
> +	.dev_name = "mtk-jpeg-enc",
> +	.ioctl_ops = &mtk_jpeg_enc_ioctl_ops,
> +	.out_q_default_fourcc = V4L2_PIX_FMT_YUYV,
> +	.cap_q_default_fourcc = V4L2_PIX_FMT_JPEG,
> +	.support_34bit = true,
> +};
> +
> +static const struct mtk_jpeg_variant mtk8189_jpegdec_drvdata = {
> +	.clks = mtk_jpeg_dec_clocks,
> +	.num_clks = ARRAY_SIZE(mtk_jpeg_dec_clocks),
> +	.formats = mtk_jpeg_dec_formats,
> +	.num_formats = MTK_JPEG_DEC_NUM_FORMATS,
> +	.qops = &mtk_jpeg_dec_qops,
> +	.irq_handler = mtk_jpeg_dec_irq,
> +	.hw_reset = mtk_jpeg_dec_reset,
> +	.m2m_ops = &mtk_jpeg_dec_m2m_ops,
> +	.dev_name = "mtk-jpeg-dec",
> +	.ioctl_ops = &mtk_jpeg_dec_ioctl_ops,
> +	.out_q_default_fourcc = V4L2_PIX_FMT_JPEG,
> +	.cap_q_default_fourcc = V4L2_PIX_FMT_YUV420M,
> +	.support_34bit = true,
> +};
> +
> ?static struct mtk_jpeg_variant mtk8195_jpegenc_drvdata = {
> ?	.formats = mtk_jpeg_enc_formats,
> ?	.num_formats = MTK_JPEG_ENC_NUM_FORMATS,
> @@ -1936,6 +1972,14 @@ static const struct of_device_id mtk_jpeg_match[] = {
> ?		.compatible = "mediatek,mtk-jpgenc",
> ?		.data = &mtk_jpeg_drvdata,
> ?	},
> +	{
> +		.compatible = "mediatek,mt8189-jpgenc",
> +		.data = &mtk8189_jpegenc_drvdata,
> +	},
> +	{
> +		.compatible = "mediatek,mt8189-jpgdec",
> +		.data = &mtk8189_jpegdec_drvdata,
> +	},
> ?	{
> ?		.compatible = "mediatek,mt8195-jpgenc",
> ?		.data = &mtk8195_jpegenc_drvdata,
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/3e6971db/attachment.sig>

From namhyung at kernel.org  Wed Dec 24 11:39:15 2025
From: namhyung at kernel.org (Namhyung Kim)
Date: Wed, 24 Dec 2025 11:39:15 -0800
Subject: [PATCH 0/2] arm64: Support NVIDIA Olympus for Perf Arm SPE
In-Reply-To: <20251219231325.2742580-1-bwicaksono@nvidia.com>
References: <20251219231325.2742580-1-bwicaksono@nvidia.com>
Message-ID: <aUxBY01uNp8gnEPq@google.com>

On Fri, Dec 19, 2025 at 11:13:23PM +0000, Besar Wicaksono wrote:
> This series support NVIDIA Olympus CPU in Perf Arm SPE.
> The first patch syncs the kernel header to the tools header.
> The second patch adds NVIDIA Olympus into perf's Neoverse SPE data source list.
> 
> Besar Wicaksono (2):
>   tools headers arm64: Add NVIDIA Olympus part
>   perf arm-spe: Add NVIDIA Olympus to neoverse list

Applied to perf-tools, thanks!

Best regards,
Namhyung



From nicolas.dufresne at collabora.com  Wed Dec 24 11:45:06 2025
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Wed, 24 Dec 2025 14:45:06 -0500
Subject: [PATCH v7 14/17] media: rkvdec: Add H264 support for the
 VDPU381 variant
In-Reply-To: <bf4a8049f49b8d6d8a39faecee025dce51d59db3.camel@collabora.com>
References: <20251218232829.337811-15-detlev.casanova@collabora.com>
		 <20251220164604.10052-1-liujianfeng1994@gmail.com>
	 <bf4a8049f49b8d6d8a39faecee025dce51d59db3.camel@collabora.com>
Message-ID: <75e51a60acd161884c623c991ba87827259f7731.camel@collabora.com>

Hi Detlev,

Le lundi 22 d?cembre 2025 ? 08:19 -0500, Nicolas Dufresne a ?crit?:
> Hi,
> 
> Le dimanche 21 d?cembre 2025 ? 00:46 +0800, Jianfeng Liu a ?crit?:
> > Hi,
> > 
> > On Thu, 18 Dec 2025 18:28:24 -0500, Detlev Casanova wrote:
> > > +static int rkvdec_h264_start(struct rkvdec_ctx *ctx)
> > > +{
> > > +	struct rkvdec_dev *rkvdec = ctx->dev;
> > > +	struct rkvdec_h264_priv_tbl *priv_tbl;
> > > +	struct rkvdec_h264_ctx *h264_ctx;
> > > +	struct v4l2_ctrl *ctrl;
> > > +	int ret;
> > > +
> > > +	ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> > > +			????? V4L2_CID_STATELESS_H264_SPS);
> > > +	if (!ctrl)
> > > +		return -EINVAL;
> > > +
> > > +	h264_ctx = kzalloc(sizeof(*h264_ctx), GFP_KERNEL);
> > > +	if (!h264_ctx)
> > > +		return -ENOMEM;
> > 
> > I can see the sps validation is removed:
> > 
> > 	ret = rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps);
> > 	if (ret)
> > 		return ret;
> > 
> > This should fix decoding issue with chromium when minimum size of h264
> > decoder is lower than 32. While I find this issue is caused by chromium
> > not following v4l2 stateless spec, and I think checking sps at start
> > should be still necessary.
> 
> One of the missing part of rkvdec is that once you set the OUTPUT format we only
> reset the capture format, but we should also reset the SPS control to a matching
> default, matching the resolution and resetting the depth. In fact, I don't even
> see code that verify the bit depth against already allocated memory, and the is
> not capable of converting.
> 
> I tend to agree with Jianfeng, that we should leave that un-modified until we
> have time to fully address and test this situation.

I digged more, and by removing this check, userspace would endup doing:

- S_FMT(OUT, 800x600)
- S_CTRL(SPS, 800x600)
- S_FMT(OUT, 640x480)

And still succeed streamon with that SPS. Since the SPS rarely changes, and
there is no requirement to send it again, a frame decode can be requested, and
this miss-match can trigger the hardware to possibly overrun.

For this reason, I cannot take v7.

Nicolas

> 
> Nicolas
> 
> > 
> > I have sent a fix to chromium[1] and it should get merged later.
> > 
> > [1] https://chromium-review.googlesource.com/c/chromium/src/+/7274555
> > 
> > Best regards,
> > Jianfeng
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251224/5546cd51/attachment.sig>

From linusw at kernel.org  Wed Dec 24 12:57:02 2025
From: linusw at kernel.org (Linus Walleij)
Date: Wed, 24 Dec 2025 21:57:02 +0100
Subject: [PATCH] ARM: dts: integrator: Fix DMA ranges mismatch warning on IM-PD1
In-Reply-To: <20251204164228.113587-1-visitorckw@gmail.com>
References: <20251204164228.113587-1-visitorckw@gmail.com>
Message-ID: <CAD++jLneTBUyMDod_fbJbuy2Y4errGQpWM3H8uVdYbKZeUNEAw@mail.gmail.com>

On Thu, Dec 4, 2025 at 5:42?PM Kuan-Wei Chiu <visitorckw at gmail.com> wrote:

> When compiling the device tree for the Integrator/AP with IM-PD1, the
> following warning is observed regarding the display controller node:
>
> arch/arm/boot/dts/arm/integratorap-im-pd1.dts:251.3-14: Warning
> (dma_ranges_format):
> /bus at c0000000/bus at c0000000/display at 1000000:dma-ranges: empty
> "dma-ranges" property but its #address-cells (2) differs from
> /bus at c0000000/bus at c0000000 (1)
>
> The display node specifies an empty "dma-ranges" property, intended to
> describe a 1:1 identity mapping. However, the node lacks explicit
> "#address-cells" and "#size-cells" properties.

(...)
> +++ b/arch/arm/boot/dts/arm/integratorap-im-pd1.dts
> @@ -248,6 +248,8 @@ display at 1000000 {
>                 /* 640x480 16bpp @ 25.175MHz is 36827428 bytes/s */
>                 max-memory-bandwidth = <40000000>;
>                 memory-region = <&impd1_ram>;
> +               #address-cells = <1>;
> +               #size-cells = <1>;
>                 dma-ranges;
>
>                 port at 0 {

This is for the *port* node and not for the
stuff mentioned in the commit message, but the port is:

                port at 0 {
                        #address-cells = <1>;
                        #size-cells = <0>;

                        clcd_pads_vga_dac: endpoint at 0 {
                                reg = <0>;
                                remote-endpoint = <&vga_bridge_in>;
                                arm,pl11x,tft-r0g0b0-pads = <0 8 16>;
                        };
                };

Devoid of any reg, so who cares?

Probably the empty dma-ranges should just be deleted again, it is
pointless for the port.

Yours,
Linus Walleij


From sboyd at kernel.org  Wed Dec 24 13:53:43 2025
From: sboyd at kernel.org (Stephen Boyd)
Date: Wed, 24 Dec 2025 11:53:43 -1000
Subject: [PATCH v3 0/9] phy: convert from clk round_rate() to determine_rate()
In-Reply-To: <176656156358.817806.16966474957670370356.b4-ty@kernel.org>
References: <20251212-phy-clk-round-rate-v3-0-beae3962f767@redhat.com> <176656156358.817806.16966474957670370356.b4-ty@kernel.org>
Message-ID: <176661322399.4169.14248756511703978007@lazor>

Quoting Vinod Koul (2025-12-23 21:32:43)
> 
> Applied, thanks!
> 

Thanks Vinod! Can you provide a tag or immutable branch so I can remove
round rate from the clk core in linux-next?


From geraldogabriel at gmail.com  Wed Dec 24 13:57:46 2025
From: geraldogabriel at gmail.com (Geraldo Nascimento)
Date: Wed, 24 Dec 2025 18:57:46 -0300
Subject: [PATCH v2 1/4] PCI: rockchip: limit RK3399 to 2.5 GT/s to prevent damage
In-Reply-To: <648aa5c0-9e58-2404-4250-e83b8a748601@manjaro.org>
References: <cover.1763415705.git.geraldogabriel@gmail.com>
 <eaa9c75ca02a53f8bcc293b8bc73d013e26ec253.1763415706.git.geraldogabriel@gmail.com>
 <CANAwSgQ726J_vnDKEKd94Kq62kx8ToZzUGysz4r3tNAXvfAbGA@mail.gmail.com>
 <CAEsQvctSY7-RQEQF2TmJU2qKPZOe9TC5g-7Jat0LQKRHYz_6dQ@mail.gmail.com>
 <CANAwSgQPQUBi6VVb+hZNraMt71vnRpki+YK_at=Luo4aPVtOPg@mail.gmail.com>
 <0afea20b-be22-2404-5a8e-c798ed45f2fd@manjaro.org> <CANAwSgS6UeR4PJnWDxxcQbdH8u_4uNiQxCTugQS35LcPvpiwMQ@mail.gmail.com>
 <648aa5c0-9e58-2404-4250-e83b8a748601@manjaro.org>
Message-ID: <CAEsQvct-AyhdOU9xhP0HnN8be+ut=tDBgUt0n3D4TT9ZMXnTbA@mail.gmail.com>

On Wed, Dec 24, 2025 at 1:52?PM Dragan Simic <dsimic at manjaro.org> wrote:
>
> On Wednesday, December 24, 2025 17:11 CET, Anand Moon <linux.amoon at gmail.com> wrote:
> > On Wed, 24 Dec 2025 at 18:25, Dragan Simic <dsimic at manjaro.org> wrote:
> > > On Wednesday, December 24, 2025 09:04 CET, Anand Moon <linux.amoon at gmail.com> wrote:
> > > > On Wed, 24 Dec 2025 at 11:08, Geraldo Nascimento
> > > > <geraldogabriel at gmail.com> wrote:
> > > > > On Wed, Dec 24, 2025 at 2:18?AM Anand Moon <linux.amoon at gmail.com> wrote:
> > > > > > On Tue, 18 Nov 2025 at 03:17, Geraldo Nascimento
> > > > > > <geraldogabriel at gmail.com> wrote:
> > > > > > > Shawn Lin from Rockchip has reiterated that there may be danger in using
> > > > > > > their PCIe with 5.0 GT/s speeds. Warn the user if they make a DT change
> > > > > > > from the default and drive at 2.5 GT/s only, even if the DT
> > > > > > > max-link-speed property is invalid or inexistent.
> > > > > > >
> > > > > > > This change is corroborated by RK3399 official datasheet [1], which
> > > > > > > says maximum link speed for this platform is 2.5 GT/s.
> > > > > > >
> > > > > > > [1] https://opensource.rock-chips.com/images/d/d7/Rockchip_RK3399_Datasheet_V2.1-20200323.pdf
> > > > > > >
> > > > > > To accurately determine the operating speed, we can leverage the
> > > > > > PCIE_CLIENT_BASIC_STATUS0/1 fields.
> > > > > > This provides a dynamic mechanism to resolve the issue.
> > > > > >
> > > > > > [1] https://github.com/torvalds/linux/blob/master/drivers/pci/controller/pcie-rockchip-ep.c#L533-L595
> > > > >
> > > > > not to put you down but I think your approach adds unnecessary complexity.
> > > > >
> > > > > All I care really is that the Kernel Project isn't blamed in the
> > > > > future if someone happens to lose their data.
> > > > >
> > > > Allow the hardware to negotiate the link speed based on the
> > > > available number of lanes.
> > > > I don?t anticipate any data loss, since PCIe will automatically
> > > > configure the device speed with link training..
> > >
> > > Please, note that this isn't about performing auto negotiation
> > > and following its results, but about "artificially" limiting the
> > > PCIe link speed to 2.5 GT/s on RK3399, because it's well known
> > > by Rockchip that 5 GT/s on RK3399's PCIe interface may cause
> > > issues and data corruption in certain corner cases.
> > >
> > It?s possible the link speed wasn?t properly tuned. On my older
> > development board,
> > which supports this configuration, I haven?t observed any data loss.
> >
> > sudo lspci -vvv | grep Speed
> >                 LnkCap: Port #0, Speed 5GT/s, Width x1, ASPM L1, Exit
> > Latency L1 <8us
> >                 LnkSta: Speed 5GT/s, Width x1
> >                 LnkCtl2: Target Link Speed: 5GT/s, EnterCompliance- SpeedDis-
> >                 LnkCap: Port #1, Speed 5GT/s, Width x1, ASPM L0s L1,
> > Exit Latency L0s unlimited, L1 <2us
> >                 LnkSta: Speed 5GT/s, Width x1
> >                 LnkCtl2: Target Link Speed: 5GT/s, EnterCompliance- SpeedDis-
>
> Let me clarify, please...  This limitation to 2.5 GT/s came straight from
> Rockchip a few years ago, described back then as an undisclosed errata.
> Recently, we got some more details from Rockchip that confirmed 5 GT/s
> as having issues in certain corner cases that cannot be validated by
> performing some field tests or by observing the PCIe behavior under load.
> Those corner cases with 5 GT/s, as described by Rockchip, are quite hard
> to reach, but the possibility is still real.
>
> To sum it up, yes, multiple people have reported 5 GT/s as "working for me"
> on their RK3399-based boards and devices, but that unfortunately means
> nothing in this case, due to the specific nature of the underlying issue.
>

Not only that but the bandwidth actually earned is very small due to the
inherent limited interrupt processing capability of a single core, meaning
the 5 GT/s bandwidth / transfer speed is never fully utilized.

It's better than to force a slightly lower actual transfer speed than to risk
the liability of someone losing their data, period.

Regards,
Geraldo Nascimento


From dmitry.baryshkov at oss.qualcomm.com  Wed Dec 24 14:28:46 2025
From: dmitry.baryshkov at oss.qualcomm.com (Dmitry Baryshkov)
Date: Thu, 25 Dec 2025 00:28:46 +0200
Subject: [PATCH v8 1/2] drm/rockchip: inno-hdmi: Convert to drm bridge
In-Reply-To: <8913609.MhkbZ0Pkbq@phil>
References: <20251016083843.76675-1-andyshrk@163.com>
 <20251016083843.76675-2-andyshrk@163.com>
 <8913609.MhkbZ0Pkbq@phil>
Message-ID: <h7iqdiolwb5hkqdkbirqjeytxu7h25p6aptspgdvndbv2husd6@mb6vroredden>

On Mon, Oct 20, 2025 at 02:45:34PM +0200, Heiko Stuebner wrote:
> Am Donnerstag, 16. Oktober 2025, 10:38:31 Mitteleurop?ische Sommerzeit schrieb Andy Yan:
> > From: Andy Yan <andy.yan at rock-chips.com>
> > 
> > Convert it to drm bridge driver, it will be convenient for us to
> > migrate the connector part to the display driver later.
> > 
> > Signed-off-by: Andy Yan <andy.yan at rock-chips.com>
> 
> Reviewed-by: Heiko Stuebner <heiko at sntech.de>
> 
> But of course I would be really happy if someone with more experience
> on general bridges could also take a look.

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>


-- 
With best wishes
Dmitry


From dmitry.baryshkov at oss.qualcomm.com  Wed Dec 24 14:29:05 2025
From: dmitry.baryshkov at oss.qualcomm.com (Dmitry Baryshkov)
Date: Thu, 25 Dec 2025 00:29:05 +0200
Subject: [PATCH v8 2/2] MAINTAINERS: Add entry for Innosilicon hdmi
 bridge library
In-Reply-To: <20251016083843.76675-3-andyshrk@163.com>
References: <20251016083843.76675-1-andyshrk@163.com>
 <20251016083843.76675-3-andyshrk@163.com>
Message-ID: <qvyyiys4vxf7bosauha3lov7uttzwdzehf2kwsu32xxzwyn3cy@jhkdjc2cvwcn>

On Thu, Oct 16, 2025 at 04:38:32PM +0800, Andy Yan wrote:
> From: Andy Yan <andy.yan at rock-chips.com>
> 
> Add entry for Innosilicon hdmi bridge library
> 
> Signed-off-by: Andy Yan <andy.yan at rock-chips.com>
> ---
> 
> (no changes since v1)
> 
>  MAINTAINERS | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 

Acked-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>

> 

-- 
With best wishes
Dmitry


From dmitry.baryshkov at oss.qualcomm.com  Wed Dec 24 14:32:25 2025
From: dmitry.baryshkov at oss.qualcomm.com (Dmitry Baryshkov)
Date: Thu, 25 Dec 2025 00:32:25 +0200
Subject: [PATCH v8 0/2] Convert inno hdmi to drm bridge
In-Reply-To: <20251016083843.76675-1-andyshrk@163.com>
References: <20251016083843.76675-1-andyshrk@163.com>
Message-ID: <176661554529.2411515.14933651749352627609.b4-ty@oss.qualcomm.com>

On Thu, 16 Oct 2025 16:38:30 +0800, Andy Yan wrote:
> Convert it to drm bridge driver, it will be convenient for us to
> migrate the connector part to the display driver later.
> 
> Patches that have already been merged in drm-misc-next are dropped.
> 
> 
> Changes in v8:
> - Rebase on latest drm-misc-next tag: drm-misc-fixes-2025-10-09
> - Link to v7: https://lore.kernel.org/linux-rockchip/20250903110825.776807-1-andyshrk at 163.com/
> 
> [...]

Applied to drm-misc-next, thanks!

[1/2] drm/rockchip: inno-hdmi: Convert to drm bridge
      commit: 969325a2597ebc4cb001a92992f06f698ab2b467
[2/2] MAINTAINERS: Add entry for Innosilicon hdmi bridge library
      commit: 130343ee6bca9895c47d314467db7dd3dcc8bc35

Best regards,
-- 
With best wishes
Dmitry




From dmitry.baryshkov at oss.qualcomm.com  Wed Dec 24 14:32:27 2025
From: dmitry.baryshkov at oss.qualcomm.com (Dmitry Baryshkov)
Date: Thu, 25 Dec 2025 00:32:27 +0200
Subject: [PATCH RESEND 0/2] drm/bridge: lontium-lt9611uxc: switch to
 DRM_BRIDGE_OP_HDMI_AUDIO
In-Reply-To: <20250803-lt9611uxc-hdmi-v1-0-cb9ce1793acf@oss.qualcomm.com>
References: <20250803-lt9611uxc-hdmi-v1-0-cb9ce1793acf@oss.qualcomm.com>
Message-ID: <176661554772.2411515.14289224108428205133.b4-ty@oss.qualcomm.com>

On Sun, 03 Aug 2025 14:53:50 +0300, Dmitry Baryshkov wrote:
> Use DRM HDMI audio helpers in order to implement HDMI audio support for
> Lontium LT9611UXC bridge.
> 
> 

Applied to drm-misc-next, thanks!

[1/2] drm/bridge: add connector argument to .hpd_notify callback
      commit: 8a717c16ddf261118e9128d7f146d68a2567f087
[2/2] drm/bridge: lontium-lt9611uxc: switch to HDMI audio helpers
      commit: c08c123d4cd6ec3ee482d607e29388d0db2d3f1d

Best regards,
-- 
With best wishes
Dmitry




From martin.blumenstingl at googlemail.com  Wed Dec 24 15:13:07 2025
From: martin.blumenstingl at googlemail.com (Martin Blumenstingl)
Date: Thu, 25 Dec 2025 00:13:07 +0100
Subject: [PATCH v2 1/4] dt-bindings: reset: Add compatible for Amlogic S6/S7/S7D
In-Reply-To: <20251223-reset-s6-s7-s7d-v2-1-958f341449f1@amlogic.com>
References: <20251223-reset-s6-s7-s7d-v2-0-958f341449f1@amlogic.com> <20251223-reset-s6-s7-s7d-v2-1-958f341449f1@amlogic.com>
Message-ID: <CAFBinCDXppQNyadCJ0dbD9JQW=pRFkcJCKt8=etN+JrNdW--Mg@mail.gmail.com>

On Tue, Dec 23, 2025 at 6:37?AM Xianwei Zhao via B4 Relay
<devnull+xianwei.zhao.amlogic.com at kernel.org> wrote:
>
> From: Xianwei Zhao <xianwei.zhao at amlogic.com>
>
> Add compatibles for Amlogic S6/S7/S7D reset controllers,
> which fall back to 'amlogic,meson-s4-reset'.
>
> Acked-by: Conor Dooley <conor.dooley at microchip.com>
> Signed-off-by: Xianwei Zhao <xianwei.zhao at amlogic.com>
Reviewed-by: Martin Blumenstingl <martin.blumenstingl at googlemail.com>


From martin.blumenstingl at googlemail.com  Wed Dec 24 15:13:59 2025
From: martin.blumenstingl at googlemail.com (Martin Blumenstingl)
Date: Thu, 25 Dec 2025 00:13:59 +0100
Subject: [PATCH v2 2/4] arm64: dts: amlogic: Add S6 Reset Controller
In-Reply-To: <20251223-reset-s6-s7-s7d-v2-2-958f341449f1@amlogic.com>
References: <20251223-reset-s6-s7-s7d-v2-0-958f341449f1@amlogic.com> <20251223-reset-s6-s7-s7d-v2-2-958f341449f1@amlogic.com>
Message-ID: <CAFBinCAYWy_VFY8a=AAGpv1+7f5AkWnHk3KDH3fqRMTZfjuNsg@mail.gmail.com>

On Tue, Dec 23, 2025 at 6:37?AM Xianwei Zhao via B4 Relay
<devnull+xianwei.zhao.amlogic.com at kernel.org> wrote:
[...]
> +#define RESET_MIP_DSI_HOST             93
should this be RESET_MIPI_DSI_HOST?

With either the typo fixed, or an explanation why MIP_DSI_HOST is correct:
Reviewed-by: Martin Blumenstingl <martin.blumenstingl at googlemail.com>


From martin.blumenstingl at googlemail.com  Wed Dec 24 15:15:45 2025
From: martin.blumenstingl at googlemail.com (Martin Blumenstingl)
Date: Thu, 25 Dec 2025 00:15:45 +0100
Subject: [PATCH v2 3/4] arm64: dts: amlogic: Add S7 Reset Controller
In-Reply-To: <20251223-reset-s6-s7-s7d-v2-3-958f341449f1@amlogic.com>
References: <20251223-reset-s6-s7-s7d-v2-0-958f341449f1@amlogic.com> <20251223-reset-s6-s7-s7d-v2-3-958f341449f1@amlogic.com>
Message-ID: <CAFBinCBQbpsqujgU2_xqy-=ZmPww8AbXq7Gy9ih23TmOzZNTOQ@mail.gmail.com>

On Tue, Dec 23, 2025 at 6:37?AM Xianwei Zhao via B4 Relay
<devnull+xianwei.zhao.amlogic.com at kernel.org> wrote:
>
> From: Xianwei Zhao <xianwei.zhao at amlogic.com>
>
> Add the device node and related header file for Amlogic
> S7 reset controller.
>
> Signed-off-by: Xianwei Zhao <xianwei.zhao at amlogic.com>
Reviewed-by: Martin Blumenstingl <martin.blumenstingl at googlemail.com>


From martin.blumenstingl at googlemail.com  Wed Dec 24 15:34:32 2025
From: martin.blumenstingl at googlemail.com (Martin Blumenstingl)
Date: Thu, 25 Dec 2025 00:34:32 +0100
Subject: [PATCH v2 4/4] arm64: dts: amlogic: Add S7D Reset Controller
In-Reply-To: <20251223-reset-s6-s7-s7d-v2-4-958f341449f1@amlogic.com>
References: <20251223-reset-s6-s7-s7d-v2-0-958f341449f1@amlogic.com> <20251223-reset-s6-s7-s7d-v2-4-958f341449f1@amlogic.com>
Message-ID: <CAFBinCAwcdfaqf-23rj1xOMK9R7skPZKM2LrQLq92VwiMDOy_w@mail.gmail.com>

On Tue, Dec 23, 2025 at 6:37?AM Xianwei Zhao via B4 Relay
<devnull+xianwei.zhao.amlogic.com at kernel.org> wrote:
[...]
> +#define RESET_BRG_A55_PIPE0            166
For S7 (without D suffix) this is called RESET_BRG_A53_PIPE0 - which
one is correct (looking at amlogic-s7.dtsi and amlogic-s7d.dtsi
possibly A55 is correct)?
unrelated side-note while I was checking amlogic-s7.dtsi and
amlogic-s7d.dtsi: why do we have D/I and L2 caches defined for one but
not the other?

[...]
> +#define RESET_BRG_NIC_EMMC             183
> +/*                                     164     */
this needs to state 184

On a related side-note: while reviewing this patch I'm wondering how
S7 differs from S7D.
Is S7 a cut-down version of the S7D SoC (e.g. some - possibly faulty -
IP blocks fused off), is S7D a slightly updated version (like rev 2.0)
of S7, ...?
What I'm missing is a "big picture" (for older SoCs we typically had
some SBC vendor publish a datasheet - for these newer SoCs there's no
public datasheets).

That said, I think the approach chosen for the reset controller (copy
& paste, except 13 reset lines) is fine because there seem to be
actual differences in the reset lines. For other
drivers/implementations this approach would likely get very hard to
review/maintain (e.g. if we end up with a 3000 line driver and there's
only 250 lines difference between the two SoCs).


Best regards,
Martin


From royluo at google.com  Wed Dec 24 16:33:21 2025
From: royluo at google.com (Roy Luo)
Date: Wed, 24 Dec 2025 16:33:21 -0800
Subject: [PATCH v9 2/2] phy: Add Google Tensor SoC USB PHY driver
In-Reply-To: <aUt6hobN9DPUGbpz@vaman>
References: <20251222-phyb4-v9-0-82c0b671b070@google.com> <20251222-phyb4-v9-2-82c0b671b070@google.com>
 <aUqhbVFHczpL9qnL@vaman> <CA+zupgxP+_2iRYABhPM1OOJtRdkrcOvrsKH=Sxk45XwsiamzTw@mail.gmail.com>
 <aUt6hobN9DPUGbpz@vaman>
Message-ID: <CA+zupgwX_zN-Mge01Ye1_J+rwy0yEQdww1+bPo8YFWnfx68n5Q@mail.gmail.com>

On Tue, Dec 23, 2025 at 9:30?PM Vinod Koul <vkoul at kernel.org> wrote:
>
> On 23-12-25, 09:53, Roy Luo wrote:
> > On Tue, Dec 23, 2025 at 6:04?AM Vinod Koul <vkoul at kernel.org> wrote:
> > >
> > > On 22-12-25, 21:31, Roy Luo wrote:
>
> > > > +struct google_usb_phy {
> > > > +     struct device *dev;
> > > > +     struct regmap *usb_cfg_regmap;
> > > > +     unsigned int usb2_cfg_offset;
> > > > +     void __iomem *usbdp_top_base;
> > > > +     struct google_usb_phy_instance insts[GOOGLE_USB_PHY_NUM];
> > >
> > > so you have an array for one phy?
> >
> > While the current patch only supports usb2, I used an array
> > to simplify future support for usb3 and DP. I understand this
> > might seem like over-engineering for now, and we could
> > certainly wait to implement the array until the second phy
> > support is added. I?m happy to move away from array if
> > you?d prefer a simpler approach for this iteration.
>
> Rather than do array, allocate mem as probe based on how many phys will
> be there and use that. That would be a better approach than static
> allocation here

Make sense, will change it in the next version.

Thanks,
Roy

>
> > > > +static int google_usb2_phy_exit(struct phy *_phy)
> > > > +{
> > > > +     struct google_usb_phy_instance *inst = phy_get_drvdata(_phy);
> > > > +     struct google_usb_phy *gphy = to_google_usb_phy(inst);
> > > > +     u32 reg;
> > > > +
> > > > +     dev_dbg(gphy->dev, "exiting usb2 phy\n");
> > > > +
> > > > +     guard(mutex)(&gphy->phy_mutex);
> > > > +
> > > > +     regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, &reg);
> > > > +     reg &= ~USBCS_USB2PHY_CFG21_PHY_ENABLE;
> > > > +     regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, reg);
> > > > +
> > > > +     reset_control_bulk_assert(inst->num_rsts, inst->rsts);
> > > > +     clk_bulk_disable_unprepare(inst->num_clks, inst->clks);
> > > > +
> > > > +     return 0;
> > > > +}
> > > > +
> > > > +static const struct phy_ops google_usb2_phy_ops = {
> > > > +     .init           = google_usb2_phy_init,
> > > > +     .exit           = google_usb2_phy_exit,
> > > > +};
> > >
> > > Only two ops? I would expect more... No power_on/off or set_mode?
> > >
> > > --
> > > ~Vinod
> >
> > No, configuring usb2 phy is pretty straightforward. The hardware
> > does not distinguish between "initialized" and "powered on" states,
> > it also does not distinguish phy mode.
>
> ok
>
> --
> ~Vinod


From baolin.wang at linux.alibaba.com  Wed Dec 24 17:01:47 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Thu, 25 Dec 2025 09:01:47 +0800
Subject: [PATCH v4 1/5] mm: rmap: support batched checks of the references
 for large folios
In-Reply-To: <ec49f0fe-9df8-4762-b315-240cbb1ed3ce@arm.com>
References: <cover.1766455377.git.baolin.wang@linux.alibaba.com>
 <e9ff5fa689740f3b6f3ed1c1ec0e3244f20c1f06.1766455378.git.baolin.wang@linux.alibaba.com>
 <ec49f0fe-9df8-4762-b315-240cbb1ed3ce@arm.com>
Message-ID: <43b6ef51-c88f-4b0c-b512-c7195afdd31b@linux.alibaba.com>

Hi Ryan,

On 2025/12/24 21:24, Ryan Roberts wrote:
> On 23/12/2025 05:48, Baolin Wang wrote:
>> Currently, folio_referenced_one() always checks the young flag for each PTE
>> sequentially, which is inefficient for large folios. This inefficiency is
>> especially noticeable when reclaiming clean file-backed large folios, where
>> folio_referenced() is observed as a significant performance hotspot.
>>
>> Moreover, on Arm64 architecture, which supports contiguous PTEs, there is already
>> an optimization to clear the young flags for PTEs within a contiguous range.
>> However, this is not sufficient. We can extend this to perform batched operations
>> for the entire large folio (which might exceed the contiguous range: CONT_PTE_SIZE).
>>
>> Introduce a new API: clear_flush_young_ptes() to facilitate batched checking
>> of the young flags and flushing TLB entries, thereby improving performance
>> during large folio reclamation. And it will be overridden by the architecture
>> that implements a more efficient batch operation in the following patches.
>>
>> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
> 
> With the 2 niggles below addressed:
> 
> Reviewed-by: Ryan Roberts <ryan.roberts at arm.com>

Thanks.

>> ---
>>   include/linux/mmu_notifier.h |  9 +++++----
>>   include/linux/pgtable.h      | 35 +++++++++++++++++++++++++++++++++++
>>   mm/rmap.c                    | 29 +++++++++++++++++++++++++++--
>>   3 files changed, 67 insertions(+), 6 deletions(-)
>>
>> diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h
>> index d1094c2d5fb6..dbbdcef4abf1 100644
>> --- a/include/linux/mmu_notifier.h
>> +++ b/include/linux/mmu_notifier.h
>> @@ -515,16 +515,17 @@ static inline void mmu_notifier_range_init_owner(
>>   	range->owner = owner;
>>   }
>>   
>> -#define ptep_clear_flush_young_notify(__vma, __address, __ptep)		\
>> +#define ptep_clear_flush_young_notify(__vma, __address, __ptep, __nr)	\
> 
> I think I previously suggested that this should be renamed to
> clear_flush_young_ptes_notify() given that it is now a batch operation. Were
> others against that or did you forget?

Sorry, I missed this comment. Yes, sounds reasonable to me. Will do in 
the next version.

>>   ({									\
>>   	int __young;							\
>>   	struct vm_area_struct *___vma = __vma;				\
>>   	unsigned long ___address = __address;				\
>> -	__young = ptep_clear_flush_young(___vma, ___address, __ptep);	\
>> +	unsigned int ___nr = __nr;					\
>> +	__young = clear_flush_young_ptes(___vma, ___address, __ptep, ___nr);	\
>>   	__young |= mmu_notifier_clear_flush_young(___vma->vm_mm,	\
>>   						  ___address,		\
>>   						  ___address +		\
>> -							PAGE_SIZE);	\
>> +						  ___nr * PAGE_SIZE);	\
>>   	__young;							\
>>   })
>>   
>> @@ -650,7 +651,7 @@ static inline void mmu_notifier_subscriptions_destroy(struct mm_struct *mm)
>>   
>>   #define mmu_notifier_range_update_to_read_only(r) false
>>   
>> -#define ptep_clear_flush_young_notify ptep_clear_flush_young
>> +#define ptep_clear_flush_young_notify clear_flush_young_ptes
>>   #define pmdp_clear_flush_young_notify pmdp_clear_flush_young
>>   #define ptep_clear_young_notify ptep_test_and_clear_young
>>   #define pmdp_clear_young_notify pmdp_test_and_clear_young
>> diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
>> index 2f0dd3a4ace1..fcf7a7820061 100644
>> --- a/include/linux/pgtable.h
>> +++ b/include/linux/pgtable.h
>> @@ -1087,6 +1087,41 @@ static inline void wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
>>   }
>>   #endif
>>   
>> +#ifndef clear_flush_young_ptes
>> +/**
>> + * clear_flush_young_ptes - Clear the access bit and perform a TLB flush for PTEs
>> + *			    that map consecutive pages of the same folio.
>> + * @vma: The virtual memory area the pages are mapped into.
>> + * @addr: Address the first page is mapped at.
>> + * @ptep: Page table pointer for the first entry.
>> + * @nr: Number of entries to clear access bit.
>> + *
>> + * May be overridden by the architecture; otherwise, implemented as a simple
>> + * loop over ptep_clear_flush_young().
>> + *
>> + * Note that PTE bits in the PTE range besides the PFN can differ. For example,
>> + * some PTEs might be write-protected.
>> + *
>> + * Context: The caller holds the page table lock.  The PTEs map consecutive
>> + * pages that belong to the same folio.  The PTEs are all in the same PMD.
>> + */
>> +static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
>> +					 unsigned long addr, pte_t *ptep,
>> +					 unsigned int nr)
>> +{
>> +	int young;
>> +
>> +	young = ptep_clear_flush_young(vma, addr, ptep);
>> +	while (--nr) {
>> +		ptep++;
>> +		addr += PAGE_SIZE;
>> +		young |= ptep_clear_flush_young(vma, addr, ptep);
>> +	}
> 
> I think it's better to avoid the two ptep_clear_flush_young() calls if we can.
> Personally I think we should just go for the simple:
> 
> 	for (i = 0; i < nr; ++i, ++ptep, addr += PAGE_SIZE)
> 		young |= ptep_clear_flush_young(vma, addr, ptep);

ACK. Thanks for reviewing.


From songwei.chai at oss.qualcomm.com  Wed Dec 24 17:52:43 2025
From: songwei.chai at oss.qualcomm.com (Songwei Chai)
Date: Thu, 25 Dec 2025 09:52:43 +0800
Subject: [PATCH v9 0/7] Provide support for Trigger Generation Unit
In-Reply-To: <20251219065902.2296896-1-songwei.chai@oss.qualcomm.com>
References: <20251219065902.2296896-1-songwei.chai@oss.qualcomm.com>
Message-ID: <cb100594-b89b-475b-9bda-5daf278be84e@oss.qualcomm.com>

Gentle Reminder.

On 12/19/2025 2:58 PM, Songwei Chai wrote:
> We propose creating a new qcom directory under drivers/hwtracing
> to host this TGU driver, as well as additional Qualcomm-specific
> hwtracing drivers that we plan to submit in the coming months.
> This structure will help organize vendor-specific implementations
> and facilitate future development and maintenance.
> 
> Feedback from the community on this proposal is highly appreciated.
> 
> - Why we are proposing this:
> 
> TGU has the ability to monitor signal conditions and trigger debug-related
> actions, serving as a programmable hardware component that enhances system
> trace and debug capabilities. Placing it under drivers/hwtracing aligns with
> its function as a trace generation utility.
> 
> We previously attempted to push this driver to drivers/hwtracing/coresight,
> but did not receive support from the maintainers of the CoreSight subsystem.
> The reason provided was: ?This component is primarily a part of the
> Qualcomm proprietary QPMDA subsystem, and is capable of operating
> independently from the CoreSight hardware trace generation system.?
> 
> Chat history : https://lore.kernel.org/all/CAJ9a7ViKxHThyZfFFDV_FkNRimk4uo1NrMtQ-kcaj1qO4ZcGnA at mail.gmail.com/
> 
> Given this, we have been considering whether it would be appropriate
> to create a dedicated drivers/hwtracing/qcom directory for
> Qualcomm-related hwtracing drivers. This would follow the precedent set
> by Intel, which maintains its own directory at drivers/hwtracing/intel_th.
> We believe this structure would significantly facilitate
> future submissions of related Qualcomm drivers.
> 
> - Maintenance of drivers/hwtracing/qcom:
> 
> Bjorn, who maintains linux-arm-msm, will be the maintainer of this
> directory ? we?ve discussed this with him and he?s aware that his task
> list may grow accordingly. Additionally, Qualcomm engineers familiar with
> the debug hardware ? such as [Tingwei Zhang, Jinlong Mao, Songwei Chai],
> will be available to review incoming patches and support ongoing
> development.
> 
> - Detail for TGU:
> 
> This component can be utilized to sense a plurality of signals and
> create a trigger into the CTI or generate interrupts to processors
> once the input signal meets the conditions. We can treat the TGU?s
> workflow as a flowsheet, it has some ?steps? regions for customization.
> In each step region, we can set the signals that we want with priority
> in priority_group, set the conditions in each step via condition_decode,
> and set the resultant action by condition_select. Meanwhile,
> some TGUs (not all) also provide timer/counter functionality.
> Based on the characteristics described above, we consider the TGU as a
> helper in the CoreSight subsystem. Its master device is the TPDM, which
> can transmit signals from other subsystems, and we reuse the existing
> ports mechanism to link the TPDM to the connected TGU.
> 
> Here is a detailed example to explain how to use the TGU:
> 
> In this example, the TGU is configured to use 2 conditions, 2 steps, and
> the timer. The goal is to look for one of two patterns which are generated
> from TPDM, giving priority to one, and then generate a trigger once the
> timer reaches a certain value. In other words, two conditions are used
> for the first step to look for the two patterns, where the one with the
> highest priority is used in the first condition. Then, in the second step,
> the timer is enabled and set to be compared to the given value at each
> clock cycle. These steps are better shown below.
>      
>                |-----------------|
>                |                 |
>                |       TPDM      |
>                |                 |
>                |-----------------|
>                         |
>                         |
>      --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ------
>      |                  |                                                 |
>      |                  |                          |--------------------| |
>      |    |---- --->    |                          |  Go to next steps  | |
>      |    |             |                |--- ---> |  Enable timer      | |
>      |    |             v                |         |                    | |
>      |    |    |-----------------|       |         |--------------------| |
>      |    |    |                 |  Yes  |                    |           |
>      |    |    |   inputs==0xB   | ----->|                    | <-------- |
>      |    |    |                 |       |                    |      No | |
>      | No |    |-----------------|       |                    v         | |
>      |    |             |                |          |-----------------| | |
>      |    |             |                |          |                 | | |
>      |    |             |                |          |      timer>=3   |-- |
>      |    |             v                |          |                 |   |
>      |    |    |-----------------|       |          |-----------------|   |
>      |    |    |                 |  Yes  |                    |           |
>      |    |--- |   inputs==0xA   | ----->|                    | Yes       |
>      |         |                 |                            |           |
>      |         |-----------------|                            v           |
>      |                                              |-----------------|   |
>      |                                              |                 |   |
>      |                                              |      Trigger    |   |
>      |                                              |                 |   |
>      |                                              |-----------------|   |
>      |  TGU                                                   |           |
>      |--- --- --- --- --- --- --- --- --- --- --- --- --- --- |--- --- -- |
>                                                               |
>                                                               v
>                                                      |-----------------|
>                                                      |The controllers  |
>                                                      |which will use   |
>                                                      |triggers further |
>                                                      |-----------------|
> 
> steps:
>      1. Reset TGU /*it will disable tgu and reset dataset*/
>      - echo 1 > /sys/bus/amba/devices/<tgu-name>/reset_tgu
> 
>      2. Set the pattern match for priority0 to 0xA = 0b1010 and for
>         priority 1 to 0xB = 0b1011.
>      - echo 0x11113232 > /sys/bus/amba/devices/<tgu-name>/step0_priority0/reg0
>      - echo 0x11113233 > /sys/bus/amba/devices/<tgu-name>/step0_priority1/reg0
> 
>      Note:
>          Bit distribution diagram for each priority register
>      |-------------------------------------------------------------------|
>      |   Bits          |       Field Nam   |    Description              |
>      |-------------------------------------------------------------------|
>      |                 |                   | 00 = bypass for OR output   |
>      |     29:28       |   SEL_BIT7_TYPE2  | 01 = bypass for AND output  |
>      |                 |                   | 10 = sense input '0' is true|
>      |                 |                   | 11 = sense input '1' is true|
>      |-------------------------------------------------------------------|
>      |                 |                   | 00 = bypass for OR output   |
>      |     25:24       |   SEL_BIT6_TYPE2  | 01 = bypass for AND output  |
>      |                 |                   | 10 = sense input '0' is true|
>      |                 |                   | 11 = sense input '1' is true|
>      |-------------------------------------------------------------------|
>      |                 |                   | 00 = bypass for OR output   |
>      |     21:20       |   SEL_BIT5_TYPE2  | 01 = bypass for AND output  |
>      |                 |                   | 10 = sense input '0' is true|
>      |                 |                   | 11 = sense input '1' is true|
>      |-------------------------------------------------------------------|
>      |                 |                   | 00 = bypass for OR output   |
>      |     17:16       |   SEL_BIT4_TYPE2  | 01 = bypass for AND output  |
>      |                 |                   | 10 = sense input '0' is true|
>      |                 |                   | 11 = sense input '1' is true|
>      |-------------------------------------------------------------------|
>      |                 |                   | 00 = bypass for OR output   |
>      |     13:12       |   SEL_BIT3_TYPE2  | 01 = bypass for AND output  |
>      |                 |                   | 10 = sense input '0' is true|
>      |                 |                   | 11 = sense input '1' is true|
>      |-------------------------------------------------------------------|
>      |                 |                   | 00 = bypass for OR output   |
>      |      9:8        |   SEL_BIT2_TYPE2  | 01 = bypass for AND output  |
>      |                 |                   | 10 = sense input '0' is true|
>      |                 |                   | 11 = sense input '1' is true|
>      |-------------------------------------------------------------------|
>      |                 |                   | 00 = bypass for OR output   |
>      |      5:4        |  SEL_BIT1_TYPE2   | 01 = bypass for AND output  |
>      |                 |                   | 10 = sense input '0' is true|
>      |                 |                   | 11 = sense input '1' is true|
>      |-------------------------------------------------------------------|
>      |                 |                   | 00 = bypass for OR output   |
>      |      1:0        |  SEL_BIT0_TYPE2   | 01 = bypass for AND output  |
>      |                 |                   | 10 = sense input '0' is true|
>      |                 |                   | 11 = sense input '1' is true|
>      |-------------------------------------------------------------------|
>      These bits are used to identify the signals we want to sense, with
>      a maximum signal number of 140. For example, to sense the signal
>      0xA (binary 1010), we set the value of bits 0 to 13 to 3232, which
>      represents 1010. The remaining bits are set to 1, as we want to use
>      AND gate to summarize all the signals we want to sense here. For
>      rising or falling edge detection of any input to the priority, set
>      the remaining bits to 0 to use an OR gate.
> 
>      3. look for the pattern for priority_i i=0,1.
>      - echo 0x3 > /sys/bus/amba/devices/<tgu-name>/step0_condition_decode/reg0
>      - echo 0x30 > /sys/bus/amba/devices/<tgu-name>/step0_condition_decode/reg1
> 
>      |-------------------------------------------------------------------------------|
>      |   Bits          |    Field Nam        |            Description                |
>      |-------------------------------------------------------------------------------|
>      |                 |                     |For each decoded condition, this       |
>      |      24         |       NOT           |inverts the output. If the condition   |
>      |                 |                     |decodes to true, and the NOT field     |
>      |                 |                     |is '1', then the output is NOT true.   |
>      |-------------------------------------------------------------------------------|
>      |                 |                     |When '1' the output from the associated|
>      |      21         |  BC0_COMP_ACTIVE    |comparator will be actively included in|
>      |                 |                     |the decoding of this particular        |
>      |                 |                     |condition.                             |
>      |-------------------------------------------------------------------------------|
>      |                 |                     |When '1' the output from the associated|
>      |                 |                     |comparator will need to be 1 to affect |
>      |      20         |   BC0_COMP_HIGH     |the decoding of this condition.        |
>      |                 |                     |Conversely, a '0' here requires a '0'  |
>      |                 |                     |from the comparator                    |
>      |-------------------------------------------------------------------------------|
>      |                 |                     |When '1' the output from the associated|
>      |      17         |                     |comparator will be actively included in|
>      |                 |  TC0_COMP_ACTIVE    |the decoding of this particular        |
>      |                 |                     |condition.                             |
>      |-------------------------------------------------------------------------------|
>      |                 |                     |When '1' the output from the associated|
>      |                 |                     |comparator will need to be 1 to affect |
>      |      16         |  TC0_COMP_HIGH      |the decoding of this particular        |
>      |                 |                     |condition.Conversely, a 0 here         |
>      |                 |                     |requires a '0' from the comparator     |
>      |-------------------------------------------------------------------------------|
>      |                 |                     |When '1' the output from Priority_n    |
>      |                 |                     |OR logic will be actively              |
>      |     4n+3        | Priority_n_OR_ACTIVE|included in the decoding of            |
>      |                 |    (n=0,1,2,3)      |this particular condition.             |
>      |                 |                     |                                       |
>      |-------------------------------------------------------------------------------|
>      |                 |                     |When '1' the output from Priority_n    |
>      |                 |                     |will need to be '1' to affect the      |
>      |     4n+2        |  Priority_n_OR_HIGH |decoding of this particular            |
>      |                 |    (n=0,1,2,3)      |condition. Conversely, a '0' here      |
>      |                 |                     |requires a '0' from Priority_n OR logic|
>      |-------------------------------------------------------------------------------|
>      |                 |                     |When '1' the output from Priority_n    |
>      |                 |                     |AND logic will be actively             |
>      |     4n+1        |Priority_n_AND_ACTIVE|included in the decoding of this       |
>      |                 |  (n=0,1,2,3)        |particular condition.                  |
>      |                 |                     |                                       |
>      |-------------------------------------------------------------------------------|
>      |                 |                     |When '1' the output from Priority_n    |
>      |                 |                     |AND logic will need to be '1' to       |
>      |      4n         | Priority_n_AND_HIGH |affect the decoding of this            |
>      |                 |   (n=0,1,2,3)       |particular condition. Conversely,      |
>      |                 |                     |a '0' here requires a '0' from         |
>      |                 |                     |Priority_n AND logic.                  |
>      |-------------------------------------------------------------------------------|
>      Since we use `priority_0` and `priority_1` with an AND output in step 2, we set `0x3`
>      and `0x30` here to activate them.
> 
>      4. Set NEXT_STEP = 1 and TC0_ENABLE = 1 so that when the conditions
>         are met then the next step will be step 1 and the timer will be enabled.
>      - echo 0x20008 > /sys/bus/amba/devices/<tgu-name>/step0_condition_select/reg0
>      - echo 0x20008 > /sys/bus/amba/devices/<tgu-name>/step0_condition_select/reg1
> 
>      |-----------------------------------------------------------------------------|
>      |   Bits          |       Field Nam   |            Description                |
>      |-----------------------------------------------------------------------------|
>      |                 |                   |This field defines the next step the   |
>      |    18:17        |     NEXT_STEP     |TGU will 'goto' for the associated     |
>      |                 |                   |Condition and Step.                    |
>      |-----------------------------------------------------------------------------|
>      |                 |                   |For each possible output trigger       |
>      |    13           |     TRIGGER       |available, set a '1' if you want       |
>      |                 |                   |the trigger to go active for the       |
>      |                 |                   |associated condition and Step.         |
>      |-----------------------------------------------------------------------------|
>      |                 |                   |This will cause BC0 to increment if the|
>      |    9            |     BC0_INC       |associated Condition is decoded for    |
>      |                 |                   |this step.                             |
>      |-----------------------------------------------------------------------------|
>      |                 |                   |This will cause BC0 to decrement if the|
>      |    8            |     BC0_DEC       |associated Condition is decoded for    |
>      |                 |                   |this step.                             |
>      |-----------------------------------------------------------------------------|
>      |                 |                   |This will clear BC0 count value to 0 if|
>      |    7            |     BC0_CLEAR     |the associated Condition is decoded    |
>      |                 |                   |for this step.                         |
>      |-----------------------------------------------------------------------------|
>      |                 |                   |This will cause TC0 to increment until |
>      |    3            |     TC0_ENABLE    |paused or cleared if the associated    |
>      |                 |                   |Condition is decoded for this step.    |
>      |-----------------------------------------------------------------------------|
>      |                 |                   |This will cause TC0 to pause until     |
>      |    2            |     TC0_PAUSE     |enabled if the associated Condition    |
>      |                 |                   |is decoded for this step.              |
>      |-----------------------------------------------------------------------------|
>      |                 |                   |This will clear TC0 count value to 0   |
>      |    1            |     TC0_CLEAR     |if the associated Condition is         |
>      |                 |                   |decoded for this step.                 |
>      |-----------------------------------------------------------------------------|
>      |                 |                   |This will set the done signal to the   |
>      |    0            |     DONE          |TGU FSM if the associated Condition    |
>      |                 |                   |is decoded for this step.              |
>      |-----------------------------------------------------------------------------|
>      Based on the distribution diagram, we set `0x20008` for `priority0` and `priority1` to
>      achieve "jump to step 1 and enable TC0" once the signal is sensed.
> 
>      5. activate the timer comparison for this step.
>      -  echo 0x30000  > /sys/bus/amba/devices/<tgu-name>/step1_condition_decode/reg0
> 
>      |-------------------------------------------------------------------------------|
>      |                 |                     |When '1' the output from the associated|
>      |      17         |                     |comparator will be actively included in|
>      |                 |  TC0_COMP_ACTIVE    |the decoding of this particular        |
>      |                 |                     |condition.                             |
>      |-------------------------------------------------------------------------------|
>      |                 |                     |When '1' the output from the associated|
>      |                 |                     |comparator will need to be 1 to affect |
>      |      16         |  TC0_COMP_HIGH      |the decoding of this particular        |
>      |                 |                     |condition.Conversely, a 0 here         |
>      |                 |                     |requires a '0' from the comparator     |
>      |-------------------------------------------------------------------------------|
>      Accroding to the decode distribution diagram , we give 0x30000 here to set 16th&17th bit
>      to enable timer comparison.
> 
>      6. Set the NEXT_STEP = 0 and TC0_PAUSE = 1 and TC0_CLEAR = 1 once the timer
>         has reached the given value.
>      - echo 0x6 > /sys/bus/amba/devices/<tgu-name>/step1_condition_select/reg0
> 
>      7. Enable Trigger 0 for TGU when the condition 0 is met in step1,
>         i.e. when the timer reaches 3.
>      - echo 0x2000 > /sys/bus/amba/devices/<tgu-name>/step1_condition_select/default
> 
>      Note:
>          1. 'default' register allows for establishing the resultant action for
>          the default condition
> 
>          2. Trigger:For each possible output trigger available from
>          the Design document, there are three triggers: interrupts, CTI,
>          and Cross-TGU mapping.All three triggers can occur, but
>          the choice of which trigger to use depends on the user's
>          needs.
> 
>      8. Compare the timer to 3 in step 1.
>      - echo 0x3 > /sys/bus/amba/devices/<tgu-name>/step1_timer/reg0
> 
>      9. enale tgu
>      - echo 1 > /sys/bus/amba/devices/<tgu-name>/enable_tgu
> ---
> Link to V8: https://lore.kernel.org/all/20251203090055.2432719-1-songwei.chai at oss.qualcomm.com/
> 
> Changes in V9:
> - Decoupled the tgu driver from coresight header file and registered it as an amba device.
> - Retained Rob's reviewed-by tag on patch1/7 since the file remains unchanged.
> - Updated the sysfs node path in the Documentation directory.
> ---
> Link to V7: https://lore.kernel.org/all/20251104064043.88972-1-songwei.chai at oss.qualcomm.com/
> 
> Changes in V8:
> - Add "select" section in bindings.
> - Update publish date in "sysfs-bus-coresight-devices-tgu".
> ---
> Link to V6: https://lore.kernel.org/all/20250709104114.22240-1-songchai at qti.qualcomm.com/
> 
> Changes in V7:
> - Move the TGU code location from 'drivers/hwtracing/coresight/' to 'drivers/hwtracing/qcom/'.
> - Rename the spinlock used in the code from 'spinlock' to 'lock'.
> - Perform the 'calculate_array_location' separately, instead of doing it within the function.
> - Update the sender email address.
> ---
> Link to V5: https://lore.kernel.org/all/20250529081949.26493-1-quic_songchai at quicinc.com/
> 
> Changes in V6:
> - Replace spinlock with guard(spinlock) in tgu_enable.
> - Remove redundant blank line.
> - Update publish date and contact member's name in "sysfs-bus-coresight-devices-tgu".
> ---
> Link to V4: https://patchwork.kernel.org/project/linux-arm-msm/cover/20250423101054.954066-1-quic_songchai at quicinc.com/
> 
> Changes in V5:
> - Update publish date and kernel_version in "sysfs-bus-coresight-devices-tgu"
> ---
> Link to V3: https://lore.kernel.org/all/20250227092640.2666894-1-quic_songchai at quicinc.com/
> 
> Changes in V4:
> - Add changlog in coverletter.
> - Correct 'year' in Copyright in patch1.
> - Correct port mechansim description in patch1.
> - Remove 'tgu-steps','tgu-regs','tgu-conditions','tgu-timer-counters' from dt-binding
> and set them through reading DEVID register as per Mike's suggestion.
> - Modify tgu_disable func to make it have single return point in patch2 as per
> Mike's suggestion.
> - Use sysfs_emit in enable_tgu_show func in ptach2.
> - Remove redundant judgement in enable_tgu_store in patch2.
> - Correct typo in description in patch3.
> - Set default ret as SYSFS_GROUP_INVISIBLE, and returnret at end in pacth3 as
> per Mike's suggestion.
> - Remove tgu_dataset_ro definition in patch3
> - Use #define constants with explanations of what they are rather than
> arbitrary magic numbers in patch3 and patch4.
> - Check -EINVAL before using 'calculate_array_location()' in array in patch4.
> - Add 'default' in 'tgu_dataset_show''s switch part in patch4.
> - Document the value needed to initiate the reset in pacth7.
> - Check "value" in 'reset_tgu_store' and bail out with an error code if 0 in patch7.
> - Remove dev_dbg in 'reset_tgu_store' in patch7.
> ---
> Link to V2: https://lore.kernel.org/all/20241010073917.16023-1-quic_songchai at quicinc.com/
> 
> Changes in V3:
> - Correct typo and format in dt-binding in patch1
> - Rebase to the latest kernel version
> ---
> Link to V1: https://lore.kernel.org/all/20240830092311.14400-1-quic_songchai at quicinc.com/
> 
> Changes in V2:
>   - Use real name instead of login name,
>   - Correct typo and format in dt-binding and code.
>   - Bring order in tgu_prob(declarations with and without assignments) as per
> Krzysztof's suggestion.
>   - Add module device table in patch2.
>   - Set const for tgu_common_grp and tgu_ids in patch2.
>   - Initialize 'data' in tgu_ids to fix the warning in pacth2.
> ---
> 
> Songwei Chai (7):
>    dt-bindings: arm: Add support for Qualcomm TGU trace
>    qcom-tgu: Add TGU driver
>    qcom-tgu: Add signal priority support
>    qcom-tgu: Add TGU decode support
>    qcom-tgu: Add support to configure next action
>    qcom-tgu: Add timer/counter functionality for TGU
>    qcom-tgu: Add reset node to initialize
> 
>   .../ABI/testing/sysfs-bus-amba-devices-tgu    |  51 ++
>   .../devicetree/bindings/arm/qcom,tgu.yaml     |  92 +++
>   drivers/Makefile                              |   1 +
>   drivers/hwtracing/Kconfig                     |   2 +
>   drivers/hwtracing/qcom/Kconfig                |  18 +
>   drivers/hwtracing/qcom/Makefile               |   3 +
>   drivers/hwtracing/qcom/tgu.c                  | 702 ++++++++++++++++++
>   drivers/hwtracing/qcom/tgu.h                  | 272 +++++++
>   8 files changed, 1141 insertions(+)
>   create mode 100644 Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
>   create mode 100644 Documentation/devicetree/bindings/arm/qcom,tgu.yaml
>   create mode 100644 drivers/hwtracing/qcom/Kconfig
>   create mode 100644 drivers/hwtracing/qcom/Makefile
>   create mode 100644 drivers/hwtracing/qcom/tgu.c
>   create mode 100644 drivers/hwtracing/qcom/tgu.h
> 



From Kyrie.Wu at mediatek.com  Wed Dec 24 18:20:41 2025
From: Kyrie.Wu at mediatek.com (=?utf-8?B?S3lyaWUgV3UgKOWQtOaZlyk=?=)
Date: Thu, 25 Dec 2025 02:20:41 +0000
Subject: [PATCH v11 01/12] media: mediatek: jpeg: fix jpeg hw count
 setting
In-Reply-To: <cd4c9c6f89d2ad506113745f4273ff6e6b65c75a.camel@ndufresne.ca>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
	 <20251202094800.6140-2-kyrie.wu@mediatek.com>
	 <cd4c9c6f89d2ad506113745f4273ff6e6b65c75a.camel@ndufresne.ca>
Message-ID: <d99811831065542167c8dae6285ecdada946104d.camel@mediatek.com>

On Tue, 2025-12-16 at 15:57 -0500, Nicolas Dufresne wrote:
> Hi,
> 
> Le mardi 02 d?cembre 2025 ? 17:47 +0800, Kyrie Wu a ?crit :
> > Different ICs have different amounts of hardware,
> > use a variable to set the amount of hardware.
> 
> Did you mean different amount of cores ? The use of "hardware" is
> strange in
> this description.
Yes, it's right. I will change it in the next version.

Thanks.
> 
> > 
> > Fixes: 934e8bccac95 ("mtk-jpegenc: support jpegenc multi-hardware")
> > Fixes: 0fa49df4222f ("media: mtk-jpegdec: support jpegdec multi-
> > hardware")
> 
> Its not clear from your description if this is in preparation of
> MT8196 or an
> actual fix. If its in preparation of, drop this, if it fixes some
> existing SoC,
> please tell use which one. And tell us how it breaks without this
> fix.
> 
> regards,
> Nicolas

Dear Nicolas,

The macro was first used to represent the amount of cores for MT8195.
However, the cores' quantity of MT8196 is different from that in the
MT8195,
and it may also differ in the coming ICs. Therefore, the definition of
the macro can not used to represent the amount of cores.

But if you think this is normal setting patch rather than a fixed one,
I will change the commit messages in the next version.

Look forward to your further reply.

Thanks.

Regards,
Kyrie.

> 
> > 
> > Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
> > Reviewed-by: AngeloGioacchino Del Regno <
> > angelogioacchino.delregno at collabora.com>
> > ---
> >  drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c   | 8 ++++---
> > -
> >  drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h   | 2 ++
> >  drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c | 1 +
> >  drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c | 1 +
> >  4 files changed, 8 insertions(+), 4 deletions(-)
> > 
> > diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > index 6268d651bdcf..6a7e01130f1c 100644
> > --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > @@ -1467,7 +1467,7 @@ static int mtk_jpegenc_get_hw(struct
> > mtk_jpeg_ctx *ctx)
> >  	int i;
> >  
> >  	spin_lock_irqsave(&jpeg->hw_lock, flags);
> > -	for (i = 0; i < MTK_JPEGENC_HW_MAX; i++) {
> > +	for (i = 0; i < jpeg->max_hw_count; i++) {
> >  		comp_jpeg = jpeg->enc_hw_dev[i];
> >  		if (comp_jpeg->hw_state == MTK_JPEG_HW_IDLE) {
> >  			hw_id = i;
> > @@ -1514,7 +1514,7 @@ static int mtk_jpegdec_get_hw(struct
> > mtk_jpeg_ctx *ctx)
> >  	int i;
> >  
> >  	spin_lock_irqsave(&jpeg->hw_lock, flags);
> > -	for (i = 0; i < MTK_JPEGDEC_HW_MAX; i++) {
> > +	for (i = 0; i < jpeg->max_hw_count; i++) {
> >  		comp_jpeg = jpeg->dec_hw_dev[i];
> >  		if (comp_jpeg->hw_state == MTK_JPEG_HW_IDLE) {
> >  			hw_id = i;
> > @@ -1597,7 +1597,7 @@ static void mtk_jpegenc_worker(struct
> > work_struct *work)
> >  		jpeg_work);
> >  	struct mtk_jpeg_dev *jpeg = ctx->jpeg;
> >  
> > -	for (i = 0; i < MTK_JPEGENC_HW_MAX; i++)
> > +	for (i = 0; i < jpeg->max_hw_count; i++)
> >  		comp_jpeg[i] = jpeg->enc_hw_dev[i];
> >  	i = 0;
> >  
> > @@ -1692,7 +1692,7 @@ static void mtk_jpegdec_worker(struct
> > work_struct *work)
> >  	struct mtk_jpeg_fb fb;
> >  	unsigned long flags;
> >  
> > -	for (i = 0; i < MTK_JPEGDEC_HW_MAX; i++)
> > +	for (i = 0; i < jpeg->max_hw_count; i++)
> >  		comp_jpeg[i] = jpeg->dec_hw_dev[i];
> >  	i = 0;
> >  
> > diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> > b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> > index 02ed0ed5b736..6be5cf30dea1 100644
> > --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> > +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> > @@ -212,6 +212,7 @@ struct mtk_jpegdec_comp_dev {
> >   * @reg_decbase:	jpg decode register base addr
> >   * @dec_hw_dev:	jpg decode hardware device
> >   * @hw_index:		jpg hw index
> > + * @max_hw_count:	jpeg hw-core count
> >   */
> >  struct mtk_jpeg_dev {
> >  	struct mutex		lock;
> > @@ -234,6 +235,7 @@ struct mtk_jpeg_dev {
> >  	void __iomem *reg_decbase[MTK_JPEGDEC_HW_MAX];
> >  	struct mtk_jpegdec_comp_dev *dec_hw_dev[MTK_JPEGDEC_HW_MAX];
> >  	atomic_t hw_index;
> > +	u32 max_hw_count;
> >  };
> >  
> >  /**
> > diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> > b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> > index e78e1d11093c..a1e54715cb7e 100644
> > --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> > +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> > @@ -664,6 +664,7 @@ static int mtk_jpegdec_hw_probe(struct
> > platform_device *pdev)
> >  	master_dev->dec_hw_dev[i] = dev;
> >  	master_dev->reg_decbase[i] = dev->reg_base;
> >  	dev->master_dev = master_dev;
> > +	master_dev->max_hw_count++;
> >  
> >  	platform_set_drvdata(pdev, dev);
> >  	pm_runtime_enable(&pdev->dev);
> > diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> > b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> > index 9ab27aee302a..28d05909c96f 100644
> > --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> > +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> > @@ -386,6 +386,7 @@ static int mtk_jpegenc_hw_probe(struct
> > platform_device *pdev)
> >  	master_dev->enc_hw_dev[i] = dev;
> >  	master_dev->reg_encbase[i] = dev->reg_base;
> >  	dev->master_dev = master_dev;
> > +	master_dev->max_hw_count++;
> >  
> >  	platform_set_drvdata(pdev, dev);
> >  	pm_runtime_enable(&pdev->dev);

From jie.gan at oss.qualcomm.com  Wed Dec 24 18:44:07 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Thu, 25 Dec 2025 10:44:07 +0800
Subject: [PATCH v9 2/7] qcom-tgu: Add TGU driver
In-Reply-To: <20251219065902.2296896-3-songwei.chai@oss.qualcomm.com>
References: <20251219065902.2296896-1-songwei.chai@oss.qualcomm.com>
 <20251219065902.2296896-3-songwei.chai@oss.qualcomm.com>
Message-ID: <458b3404-ca67-43fe-8610-f33c875b2de1@oss.qualcomm.com>



On 12/19/2025 2:58 PM, Songwei Chai wrote:
> Add driver to support device TGU (Trigger Generation Unit).
> TGU is a Data Engine which can be utilized to sense a plurality of
> signals and create a trigger into the CTI or generate interrupts to
> processors. Add probe/enable/disable functions for tgu.
> 
> Signed-off-by: Songwei Chai <songwei.chai at oss.qualcomm.com>
> ---
>   .../ABI/testing/sysfs-bus-amba-devices-tgu    |   9 +
>   drivers/Makefile                              |   1 +
>   drivers/hwtracing/Kconfig                     |   2 +
>   drivers/hwtracing/qcom/Kconfig                |  18 ++
>   drivers/hwtracing/qcom/Makefile               |   3 +
>   drivers/hwtracing/qcom/tgu.c                  | 178 ++++++++++++++++++
>   drivers/hwtracing/qcom/tgu.h                  |  51 +++++
>   7 files changed, 262 insertions(+)
>   create mode 100644 Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
>   create mode 100644 drivers/hwtracing/qcom/Kconfig
>   create mode 100644 drivers/hwtracing/qcom/Makefile
>   create mode 100644 drivers/hwtracing/qcom/tgu.c
>   create mode 100644 drivers/hwtracing/qcom/tgu.h
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
> new file mode 100644
> index 000000000000..24dcdf1d70cc
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
> @@ -0,0 +1,9 @@
> +What:		/sys/bus/amba/devices/<tgu-name>/enable_tgu
> +Date:		December 2025
> +KernelVersion	6.19
> +Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Songwei Chai <songwei.chai at oss.qualcomm.com>
> +Description:
> +		(RW) Set/Get the enable/disable status of TGU
> +		Accepts only one of the 2 values -  0 or 1.
> +		0 : disable TGU.
> +		1 : enable TGU.
> diff --git a/drivers/Makefile b/drivers/Makefile
> index ccc05f1eae3e..9608a3debb1f 100644
> --- a/drivers/Makefile
> +++ b/drivers/Makefile
> @@ -177,6 +177,7 @@ obj-$(CONFIG_RAS)		+= ras/
>   obj-$(CONFIG_USB4)		+= thunderbolt/
>   obj-$(CONFIG_CORESIGHT)		+= hwtracing/coresight/
>   obj-y				+= hwtracing/intel_th/
> +obj-y				+= hwtracing/qcom/
>   obj-$(CONFIG_STM)		+= hwtracing/stm/
>   obj-$(CONFIG_HISI_PTT)		+= hwtracing/ptt/
>   obj-y				+= android/
> diff --git a/drivers/hwtracing/Kconfig b/drivers/hwtracing/Kconfig
> index 911ee977103c..8a640218eed8 100644
> --- a/drivers/hwtracing/Kconfig
> +++ b/drivers/hwtracing/Kconfig
> @@ -7,4 +7,6 @@ source "drivers/hwtracing/intel_th/Kconfig"
>   
>   source "drivers/hwtracing/ptt/Kconfig"
>   
> +source "drivers/hwtracing/qcom/Kconfig"
> +
>   endmenu
> diff --git a/drivers/hwtracing/qcom/Kconfig b/drivers/hwtracing/qcom/Kconfig
> new file mode 100644
> index 000000000000..d6f6d4b0f28e
> --- /dev/null
> +++ b/drivers/hwtracing/qcom/Kconfig
> @@ -0,0 +1,18 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +#
> +# QCOM specific hwtracing drivers
> +#
> +menu "Qualcomm specific hwtracing drivers"
> +
> +config QCOM_TGU
> +	tristate "QCOM Trigger Generation Unit driver"

TGU is working as the helper device of the TPDM, can we say:

select CORESIGHT_TPDM


> +	help
> +	  This driver provides support for Trigger Generation Unit that is
> +	  used to detect patterns or sequences on a given set of signals.
> +	  TGU is used to monitor a particular bus within a given region to
> +	  detect illegal transaction sequences or slave responses. It is also
> +	  used to monitor a data stream to detect protocol violations and to
> +	  provide a trigger point for centering data around a specific event
> +	  within the trace data buffer.
> +
> +endmenu
> diff --git a/drivers/hwtracing/qcom/Makefile b/drivers/hwtracing/qcom/Makefile
> new file mode 100644
> index 000000000000..5a0a868c1ea0
> --- /dev/null
> +++ b/drivers/hwtracing/qcom/Makefile
> @@ -0,0 +1,3 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +obj-$(CONFIG_QCOM_TGU) += tgu.o
> diff --git a/drivers/hwtracing/qcom/tgu.c b/drivers/hwtracing/qcom/tgu.c
> new file mode 100644
> index 000000000000..dbd1acbd2fa5
> --- /dev/null
> +++ b/drivers/hwtracing/qcom/tgu.c
> @@ -0,0 +1,178 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.

Please update the copyright.
Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.

same for other new created files.

> + */
> +
> +#include <linux/amba/bus.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/pm_runtime.h>
> +
> +#include "tgu.h"
> +
> +static void tgu_write_all_hw_regs(struct tgu_drvdata *drvdata)
> +{
> +	TGU_UNLOCK(drvdata->base);
> +	/* Enable TGU to program the triggers */
> +	writel(1, drvdata->base + TGU_CONTROL);
> +	TGU_LOCK(drvdata->base);
> +}
> +
> +static int tgu_enable(struct device *dev)
> +{
> +	struct tgu_drvdata *drvdata = dev_get_drvdata(dev);
> +
> +	guard(spinlock)(&drvdata->lock);
> +	if (drvdata->enable)
> +		return -EBUSY;
> +
> +	tgu_write_all_hw_regs(drvdata);
> +	drvdata->enable = true;
> +
> +	return 0;
> +}
> +
> +static int tgu_disable(struct device *dev)

void is better as the return value always 0?

> +{
> +	struct tgu_drvdata *drvdata = dev_get_drvdata(dev);
> +
> +	guard(spinlock)(&drvdata->lock);
> +	if (drvdata->enable) {
> +		TGU_UNLOCK(drvdata->base);
> +		writel(0, drvdata->base + TGU_CONTROL);
> +		TGU_LOCK(drvdata->base);
> +
> +		drvdata->enable = false;
> +	}
> +	return 0;
> +}
> +
> +static ssize_t enable_tgu_show(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	bool enabled;
> +	struct tgu_drvdata *drvdata = dev_get_drvdata(dev);
> +
> +	guard(spinlock)(&drvdata->lock);
> +	enabled = drvdata->enable;
> +
> +	return sysfs_emit(buf, "%d\n", enabled);

Remove enabled with below:

return sysfs_emit(buf, "%d\n", (int)drvdata->enable);

It may suffer a warning during compile without cast?

> +}
> +
> +/* enable_tgu_store - Configure Trace and Gating Unit (TGU) triggers. */
> +static ssize_t enable_tgu_store(struct device *dev,
> +				struct device_attribute *attr,
> +				const char *buf,
> +				size_t size)
> +{
> +	int ret = 0;
> +	unsigned long val;

Prefer inverse christmas tree order

> +
> +	ret = kstrtoul(buf, 0, &val);
> +	if (ret)
> +		return ret;

if (kstrtoul(buf, 0, &val)
	return -EINVAL;

> +
> +	if (val) {
> +		ret = pm_runtime_resume_and_get(dev);
> +		if (ret)
> +			return ret;
> +		ret = tgu_enable(dev);
> +		if (ret)
> +			pm_runtime_put(dev);

		if (ret) {
			pm_runtime_put(dev);
			return ret;
		}


> +	} else {
> +		ret = tgu_disable(dev);

the return value here is 0, we can just ignore it, see previous comment.

> +		pm_runtime_put(dev);
> +	}
> +
> +	if (ret)
> +		return ret;

Remove if here.

> +	return size;
> +}
> +static DEVICE_ATTR_RW(enable_tgu);
> +
> +static struct attribute *tgu_common_attrs[] = {
> +	&dev_attr_enable_tgu.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group tgu_common_grp = {
> +	.attrs = tgu_common_attrs,
> +	NULL,
> +};
> +
> +static const struct attribute_group *tgu_attr_groups[] = {
> +	&tgu_common_grp,
> +	NULL,
> +};
> +
> +static int tgu_probe(struct amba_device *adev, const struct amba_id *id)
> +{
> +	struct device *dev = &adev->dev;
> +	struct tgu_drvdata *drvdata;
> +	int ret;
> +
> +	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
> +	if (!drvdata)
> +		return -ENOMEM;
> +
> +	drvdata->dev = &adev->dev;
> +	dev_set_drvdata(dev, drvdata);
> +
> +	drvdata->base = devm_ioremap_resource(dev, &adev->res);
> +	if (IS_ERR(drvdata->base))
> +		return PTR_ERR(drvdata->base);
> +
> +	spin_lock_init(&drvdata->lock);
> +
> +	ret = sysfs_create_groups(&dev->kobj, tgu_attr_groups);
> +	if (ret) {
> +		dev_err(dev, "failed to create sysfs groups: %d\n", ret);
> +		return ret;
> +	}
> +
> +	drvdata->enable = false;

default false, no need.

> +
> +	pm_runtime_put(&adev->dev);
> +	return 0;
> +}
> +
> +static void tgu_remove(struct amba_device *adev)
> +{
> +	struct device *dev = &adev->dev;
> +
> +	sysfs_remove_groups(&dev->kobj, tgu_attr_groups);
> +
> +	tgu_disable(dev);
> +	dev_set_drvdata(dev, NULL);

no need. remove will release the allocated memory.

> +}
> +
> +static const struct amba_id tgu_ids[] = {
> +	{
> +		.id = 0x000f0e00,
> +		.mask = 0x000fffff,
> +	},
> +	{ 0, 0, NULL },
> +};
> +
> +MODULE_DEVICE_TABLE(amba, tgu_ids);
> +
> +static struct amba_driver tgu_driver = {
> +	.drv = {
> +		.name = "qcom-tgu",
> +		.suppress_bind_attrs = true,
> +	},
> +	.probe = tgu_probe,
> +	.remove = tgu_remove,
> +	.id_table = tgu_ids,
> +};
> +
> +module_amba_driver(tgu_driver);
> +
> +MODULE_AUTHOR("Songwei Chai <songwei.chai at oss.qualcomm.com>");
> +MODULE_AUTHOR("Jinlong Mao <jinlong.mao at oss.qualcomm.com>");
> +MODULE_DESCRIPTION("Qualcomm Trigger Generation Unit driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/hwtracing/qcom/tgu.h b/drivers/hwtracing/qcom/tgu.h
> new file mode 100644
> index 000000000000..abc732f91dfc
> --- /dev/null
> +++ b/drivers/hwtracing/qcom/tgu.h
> @@ -0,0 +1,51 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.

Please update the copyright.
Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.

> + */
> +
> +#ifndef _QCOM_TGU_H
> +#define _QCOM_TGU_H
> +
> +/* Register addresses */
> +#define TGU_CONTROL 0x0000

#define TGU_CONTROL 0

Thanks,
Jie

> +#define TGU_LAR		0xfb0
> +#define TGU_UNLOCK_OFFSET	0xc5acce55
> +
> +static inline void TGU_LOCK(void __iomem *addr)
> +{
> +	do {
> +		/* Wait for things to settle */
> +		mb();
> +		writel_relaxed(0x0, addr + TGU_LAR);
> +	} while (0);
> +}
> +
> +static inline void TGU_UNLOCK(void __iomem *addr)
> +{
> +	do {
> +		writel_relaxed(TGU_UNLOCK_OFFSET, addr + TGU_LAR);
> +		/* Make sure everyone has seen this */
> +		mb();
> +	} while (0);
> +}
> +
> +/**
> + * struct tgu_drvdata - Data structure for a TGU (Trigger Generator Unit)
> + * @base: Memory-mapped base address of the TGU device
> + * @dev: Pointer to the associated device structure
> + * @lock: Spinlock for handling concurrent access
> + * @enable: Flag indicating whether the TGU device is enabled
> + *
> + * This structure defines the data associated with a TGU device,
> + * including its base address, device pointers, clock, spinlock for
> + * synchronization, trigger data pointers, maximum limits for various
> + * trigger-related parameters, and enable status.
> + */
> +struct tgu_drvdata {
> +	void __iomem *base;
> +	struct device *dev;
> +	spinlock_t lock;
> +	bool enable;
> +};
> +
> +#endif



From baolin.wang at linux.alibaba.com  Wed Dec 24 18:48:42 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Thu, 25 Dec 2025 10:48:42 +0800
Subject: [PATCH v4 3/5] arm64: mm: support batch clearing of the young
 flag for large folios
In-Reply-To: <c5df1f9f-952a-4e83-9ae0-bd0a83dedd36@arm.com>
References: <cover.1766455377.git.baolin.wang@linux.alibaba.com>
 <3b427d9010a6d52f2b91342760f12be097d21cf6.1766455378.git.baolin.wang@linux.alibaba.com>
 <c5df1f9f-952a-4e83-9ae0-bd0a83dedd36@arm.com>
Message-ID: <02239ca7-9701-4bfa-af0f-dcf0d05a3e89@linux.alibaba.com>



On 2025/12/24 22:07, Ryan Roberts wrote:
> On 23/12/2025 05:48, Baolin Wang wrote:
>> Currently, contpte_ptep_test_and_clear_young() and contpte_ptep_clear_flush_young()
>> only clear the young flag and flush TLBs for PTEs within the contiguous range.
>> To support batch PTE operations for other sized large folios in the following
>> patches, adding a new parameter to specify the number of PTEs that map consecutive
>> pages of the same large folio in a single VMA and a single page table.
>>
>> While we are at it, rename the functions to maintain consistency with other
>> contpte_*() functions.
>>
>> Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
>> ---
>>   arch/arm64/include/asm/pgtable.h | 12 ++++++------
>>   arch/arm64/mm/contpte.c          | 33 ++++++++++++++++++--------------
>>   2 files changed, 25 insertions(+), 20 deletions(-)
>>
>> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
>> index 445e18e92221..d5fbe72e820a 100644
>> --- a/arch/arm64/include/asm/pgtable.h
>> +++ b/arch/arm64/include/asm/pgtable.h
>> @@ -1648,10 +1648,10 @@ extern void contpte_clear_full_ptes(struct mm_struct *mm, unsigned long addr,
>>   extern pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
>>   				unsigned long addr, pte_t *ptep,
>>   				unsigned int nr, int full);
>> -extern int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
>> -				unsigned long addr, pte_t *ptep);
>> -extern int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
>> -				unsigned long addr, pte_t *ptep);
>> +int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
>> +				unsigned long addr, pte_t *ptep, unsigned int nr);
>> +int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
>> +				unsigned long addr, pte_t *ptep, unsigned int nr);
>>   extern void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
>>   				pte_t *ptep, unsigned int nr);
>>   extern int contpte_ptep_set_access_flags(struct vm_area_struct *vma,
>> @@ -1823,7 +1823,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
>>   	if (likely(!pte_valid_cont(orig_pte)))
>>   		return __ptep_test_and_clear_young(vma, addr, ptep);
>>   
>> -	return contpte_ptep_test_and_clear_young(vma, addr, ptep);
>> +	return contpte_test_and_clear_young_ptes(vma, addr, ptep, CONT_PTES);
> 
> As per your fixup patch, I agree that nr should be 1 here, not CONT_PTES.

Yes.

>>   }
>>   
>>   #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
>> @@ -1835,7 +1835,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
>>   	if (likely(!pte_valid_cont(orig_pte)))
>>   		return __ptep_clear_flush_young(vma, addr, ptep);
>>   
>> -	return contpte_ptep_clear_flush_young(vma, addr, ptep);
>> +	return contpte_clear_flush_young_ptes(vma, addr, ptep, CONT_PTES);
> 
> And same here.
> 
>>   }
>>   
>>   #define wrprotect_ptes wrprotect_ptes
>> diff --git a/arch/arm64/mm/contpte.c b/arch/arm64/mm/contpte.c
>> index e4ddeb46f25d..b929a455103f 100644
>> --- a/arch/arm64/mm/contpte.c
>> +++ b/arch/arm64/mm/contpte.c
>> @@ -508,8 +508,9 @@ pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
>>   }
>>   EXPORT_SYMBOL_GPL(contpte_get_and_clear_full_ptes);
>>   
>> -int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
>> -					unsigned long addr, pte_t *ptep)
>> +int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
>> +					unsigned long addr, pte_t *ptep,
>> +					unsigned int nr)
>>   {
>>   	/*
>>   	 * ptep_clear_flush_young() technically requires us to clear the access
>> @@ -518,41 +519,45 @@ int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
>>   	 * contig range when the range is covered by a single folio, we can get
>>   	 * away with clearing young for the whole contig range here, so we avoid
>>   	 * having to unfold.
>> +	 *
>> +	 * The 'nr' means consecutive (present) PTEs that map consecutive pages
>> +	 * of the same large folio in a single VMA and a single page table.
>>   	 */
>>   
>> +	unsigned long end = addr + nr * PAGE_SIZE;
>>   	int young = 0;
>> -	int i;
>>   
>> -	ptep = contpte_align_down(ptep);
>> -	addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
>> -
>> -	for (i = 0; i < CONT_PTES; i++, ptep++, addr += PAGE_SIZE)
>> +	ptep = contpte_align_addr_ptep(&addr, &end, ptep, nr);
>> +	for (; addr != end; ptep++, addr += PAGE_SIZE)
>>   		young |= __ptep_test_and_clear_young(vma, addr, ptep);
>>   
>>   	return young;
>>   }
>> -EXPORT_SYMBOL_GPL(contpte_ptep_test_and_clear_young);
>> +EXPORT_SYMBOL_GPL(contpte_test_and_clear_young_ptes);
>>   
>> -int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
>> -					unsigned long addr, pte_t *ptep)
>> +int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
>> +				unsigned long addr, pte_t *ptep,
>> +				unsigned int nr)
>>   {
>>   	int young;
>>   
>> -	young = contpte_ptep_test_and_clear_young(vma, addr, ptep);
>> +	young = contpte_test_and_clear_young_ptes(vma, addr, ptep, nr);
>>   
>>   	if (young) {
>> +		unsigned long end = addr + nr * PAGE_SIZE;
>> +
>> +		contpte_align_addr_ptep(&addr, &end, ptep, nr);
>>   		/*
>>   		 * See comment in __ptep_clear_flush_young(); same rationale for
>>   		 * eliding the trailing DSB applies here.
>>   		 */
>> -		addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
>> -		__flush_tlb_range_nosync(vma->vm_mm, addr, addr + CONT_PTE_SIZE,
>> +		__flush_tlb_range_nosync(vma->vm_mm, addr, end,
>>   					 PAGE_SIZE, true, 3);
> 
> Hmm... The requirement is that we must flush the _page_ if clearing access for a
> pte that does not have the contiguous bit set, or we must flush the _contpte
> block_ if clearing access for a pte that does have the contiguous bit set.
> 
> With your changes, you may call for a large range that covers multiple contpte
> blocks but only has a single pte in a single contpte block for which the access
> bit was previously set. But that will cause flushing the TLB for the full range.
> Could this cause a performance issue? Yes, no, maybe... I think it's unlikely
> but I wouldn't rule it out in some edge case.
> 
> I wonder if it's better to track the sub-ranges where access was cleared and
> only issue tlbi for those sub-ranges? Probably just keep it simple (the way you
> have done it) until/unless we see an actual problem?

Good question. Indeed, as you said, we flush the TLB per folio now, 
which might increase the flush range. However, I think this approach is 
relatively reasonable for now.

First, the mm-core also tracks the access status per folio, and it's 
really unnecessary to add excessive complexity to track the access 
status of sub-pages (or sub-ranges). I can already imagine that tracking 
the access status for each cont-block range as well as for non-cont 
pages across the entire large folio range, which can be too complicated.

Second, __flush_tlb_range_nosync() is a lightweight flush. I quickly ran 
a measurement on my machine and found that the overhead of 
__flush_tlb_range_nosync() barely changes between nr=16 and nr=256 (both 
are around 40 ns).

Therefore, I would still prefer to keep the logic here simple.


From jie.gan at oss.qualcomm.com  Wed Dec 24 18:57:46 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Thu, 25 Dec 2025 10:57:46 +0800
Subject: [PATCH v9 1/7] dt-bindings: arm: Add support for Qualcomm TGU
 trace
In-Reply-To: <20251219065902.2296896-2-songwei.chai@oss.qualcomm.com>
References: <20251219065902.2296896-1-songwei.chai@oss.qualcomm.com>
 <20251219065902.2296896-2-songwei.chai@oss.qualcomm.com>
Message-ID: <5c67a270-dc9e-4ada-af56-e97d4a925e47@oss.qualcomm.com>



On 12/19/2025 2:58 PM, Songwei Chai wrote:
> The Trigger Generation Unit (TGU) is designed to detect patterns or
> sequences within a specific region of the System on Chip (SoC). Once
> configured and activated, it monitors sense inputs and can detect a
> pre-programmed state or sequence across clock cycles, subsequently
> producing a trigger.
> 
>     TGU configuration space
>          offset table
>   x-------------------------x
>   |                         |
>   |                         |
>   |                         |                           Step configuration
>   |                         |                             space layout
>   |   coresight management  |                           x-------------x
>   |        registers        |                     |---> |             |
>   |                         |                     |     |  reserve    |
>   |                         |                     |     |             |
>   |-------------------------|                     |     |-------------|
>   |                         |                     |     | priority[3] |
>   |         step[7]         |<--                  |     |-------------|
>   |-------------------------|   |                 |     | priority[2] |
>   |                         |   |                 |     |-------------|
>   |           ...           |   |Steps region     |     | priority[1] |
>   |                         |   |                 |     |-------------|
>   |-------------------------|   |                 |     | priority[0] |
>   |                         |<--                  |     |-------------|
>   |         step[0]         |-------------------->      |             |
>   |-------------------------|                           |  condition  |
>   |                         |                           |             |
>   |     control and status  |                           x-------------x
>   |           space         |                           |             |
>   x-------------------------x                           |Timer/Counter|
>                                                         |             |
> 						       x-------------x
> TGU Configuration in Hardware
> 
> The TGU provides a step region for user configuration, similar
> to a flow chart. Each step region consists of three register clusters:
> 
> 1.Priority Region: Sets the required signals with priority.
> 2.Condition Region: Defines specific requirements (e.g., signal A
> reaches three times) and the subsequent action once the requirement is
> met.
> 3.Timer/Counter (Optional): Provides timing or counting functionality.
> 
> Add a new tgu.yaml file to describe the bindings required to
> define the TGU in the device trees.
> 
> Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
> Signed-off-by: Songwei Chai <songwei.chai at oss.qualcomm.com>
> ---
>   .../devicetree/bindings/arm/qcom,tgu.yaml     | 92 +++++++++++++++++++
>   1 file changed, 92 insertions(+)
>   create mode 100644 Documentation/devicetree/bindings/arm/qcom,tgu.yaml
> 
> diff --git a/Documentation/devicetree/bindings/arm/qcom,tgu.yaml b/Documentation/devicetree/bindings/arm/qcom,tgu.yaml
> new file mode 100644
> index 000000000000..5b6a58ebe691
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/arm/qcom,tgu.yaml
> @@ -0,0 +1,92 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> +# Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.

Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.

Thanks,
Jie

> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/arm/qcom,tgu.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Trigger Generation Unit - TGU
> +
> +description: |
> +  The Trigger Generation Unit (TGU) is a Data Engine which can be utilized
> +  to sense a plurality of signals and create a trigger into the CTI or
> +  generate interrupts to processors. The TGU is like the trigger circuit
> +  of a Logic Analyzer. The corresponding trigger logic can be realized by
> +  configuring the conditions for each step after sensing the signal.
> +  Once setup and enabled, it will observe sense inputs and based upon
> +  the activity of those inputs, even over clock cycles, may detect a
> +  preprogrammed state/sequence and then produce a trigger or interrupt.
> +
> +  The primary use case of the TGU is to detect patterns or sequences on a
> +  given set of signals within some region to identify the issue in time
> +  once there is abnormal behavior in the subsystem.
> +
> +maintainers:
> +  - Mao Jinlong <jinlong.mao at oss.qualcomm.com>
> +  - Songwei Chai <songwei.chai at oss.qualcomm.com>
> +
> +# Need a custom select here or 'arm,primecell' will match on lots of nodes
> +select:
> +  properties:
> +    compatible:
> +      contains:
> +        enum:
> +          - qcom,tgu
> +  required:
> +    - compatible
> +
> +properties:
> +  compatible:
> +    items:
> +      - const: qcom,tgu
> +      - const: arm,primecell
> +
> +  reg:
> +    maxItems: 1
> +
> +  clocks:
> +    maxItems: 1
> +
> +  clock-names:
> +    items:
> +      - const: apb_pclk
> +
> +  in-ports:
> +    $ref: /schemas/graph.yaml#/properties/ports
> +    additionalProperties: false
> +
> +    properties:
> +      port:
> +        description:
> +          The port mechanism here ensures the relationship between TGU and
> +          TPDM, as TPDM is one of the inputs for TGU. It will allow TGU to
> +          function as TPDM's helper and enable TGU when the connected
> +          TPDM is enabled.
> +        $ref: /schemas/graph.yaml#/properties/port
> +
> +required:
> +  - compatible
> +  - reg
> +  - clocks
> +  - clock-names
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    tgu at 10b0e000 {
> +        compatible = "qcom,tgu", "arm,primecell";
> +        reg = <0x10b0e000 0x1000>;
> +
> +        clocks = <&aoss_qmp>;
> +        clock-names = "apb_pclk";
> +
> +        in-ports {
> +            port {
> +                tgu_in_tpdm_swao: endpoint{
> +                    remote-endpoint = <&tpdm_swao_out_tgu>;
> +                };
> +            };
> +        };
> +    };
> +...



From jie.gan at oss.qualcomm.com  Wed Dec 24 19:20:06 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Thu, 25 Dec 2025 11:20:06 +0800
Subject: [PATCH v9 3/7] qcom-tgu: Add signal priority support
In-Reply-To: <20251219065902.2296896-4-songwei.chai@oss.qualcomm.com>
References: <20251219065902.2296896-1-songwei.chai@oss.qualcomm.com>
 <20251219065902.2296896-4-songwei.chai@oss.qualcomm.com>
Message-ID: <4ea62244-6bf5-46bc-b026-79806fa372af@oss.qualcomm.com>



On 12/19/2025 2:58 PM, Songwei Chai wrote:
> Like circuit of a Logic analyzer, in TGU, the requirement could be
> configured in each step and the trigger will be created once the
> requirements are met. Add priority functionality here to sort the
> signals into different priorities. The signal which is wanted could
> be configured in each step's priority node, the larger number means
> the higher priority and the signal with higher priority will be sensed
> more preferentially.
> 
> Signed-off-by: Songwei Chai <songwei.chai at oss.qualcomm.com>
> ---
>   .../ABI/testing/sysfs-bus-amba-devices-tgu    |   7 +
>   drivers/hwtracing/qcom/tgu.c                  | 156 ++++++++++++++++++
>   drivers/hwtracing/qcom/tgu.h                  | 113 +++++++++++++
>   3 files changed, 276 insertions(+)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
> index 24dcdf1d70cc..d04a01368089 100644
> --- a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
> +++ b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
> @@ -7,3 +7,10 @@ Description:
>   		Accepts only one of the 2 values -  0 or 1.
>   		0 : disable TGU.
>   		1 : enable TGU.
> +
> +What:		/sys/bus/amba/devices/<tgu-name>/step[0:7]_priority[0:3]/reg[0:17]
> +Date:		December 2025
> +KernelVersion	6.19
> +Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Songwei Chai <songwei.chai at oss.qualcomm.com>
> +Description:
> +		(RW) Set/Get the sensed signal with specific step and priority for TGU.
> diff --git a/drivers/hwtracing/qcom/tgu.c b/drivers/hwtracing/qcom/tgu.c
> index dbd1acbd2fa5..447d7e68d132 100644
> --- a/drivers/hwtracing/qcom/tgu.c
> +++ b/drivers/hwtracing/qcom/tgu.c
> @@ -14,14 +14,121 @@
>   
>   #include "tgu.h"
>   
> +static int calculate_array_location(struct tgu_drvdata *drvdata,
> +				   int step_index, int operation_index,
> +				   int reg_index)
> +{
> +	return operation_index * (drvdata->max_step) * (drvdata->max_reg) +
> +		step_index * (drvdata->max_reg) + reg_index;
> +}
> +
> +static ssize_t tgu_dataset_show(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	int index;

Prefer reverse Christmas tree order

> +	struct tgu_drvdata *drvdata = dev_get_drvdata(dev);
> +	struct tgu_attribute *tgu_attr =
> +			container_of(attr, struct tgu_attribute, attr);
> +
> +	index = calculate_array_location(drvdata, tgu_attr->step_index,
> +					 tgu_attr->operation_index,
> +					 tgu_attr->reg_num);
> +
> +	return sysfs_emit(buf, "0x%x\n",
> +			  drvdata->value_table->priority[index]);
> +}
> +
> +static ssize_t tgu_dataset_store(struct device *dev,
> +				 struct device_attribute *attr,
> +				 const char *buf, size_t size)
> +{
> +	int index;
> +	unsigned long val;

Prefer reverse Christmas tree order

> +
> +	struct tgu_drvdata *tgu_drvdata = dev_get_drvdata(dev);
> +	struct tgu_attribute *tgu_attr =
> +		container_of(attr, struct tgu_attribute, attr);
> +
> +	if (kstrtoul(buf, 0, &val))
> +		return -EINVAL;
> +
> +	guard(spinlock)(&tgu_drvdata->lock);
> +	index = calculate_array_location(tgu_drvdata, tgu_attr->step_index,
> +					 tgu_attr->operation_index,
> +					 tgu_attr->reg_num);
> +
> +	tgu_drvdata->value_table->priority[index] = val;
> +	return size;
> +}
> +
> +static umode_t tgu_node_visible(struct kobject *kobject,
> +				struct attribute *attr,
> +				int n)
> +{
> +	struct device *dev = kobj_to_dev(kobject);
> +	struct tgu_drvdata *drvdata = dev_get_drvdata(dev);
> +	int ret = SYSFS_GROUP_INVISIBLE;
> +
> +	struct device_attribute *dev_attr =
> +		container_of(attr, struct device_attribute, attr);
> +	struct tgu_attribute *tgu_attr =
> +		container_of(dev_attr, struct tgu_attribute, attr);
> +
> +	if (tgu_attr->step_index < drvdata->max_step) {
> +		ret = (tgu_attr->reg_num < drvdata->max_reg) ?
> +			attr->mode : 0;
> +	}
> +	return ret;

if ((tgu_attr->step_index < drvdata->max_step) &&
     (tgu_attr->reg_num < drvdata->max_reg)
	return attr->mode;

return 0;

> +}
> +
>   static void tgu_write_all_hw_regs(struct tgu_drvdata *drvdata)
>   {
> +	int i, j, k, index;
> +
>   	TGU_UNLOCK(drvdata->base);
> +	for (i = 0; i < drvdata->max_step; i++) {
> +		for (j = 0; j < MAX_PRIORITY; j++) {
> +			for (k = 0; k < drvdata->max_reg; k++) {
> +				index = calculate_array_location(
> +							drvdata, i, j, k);
> +
> +				writel(drvdata->value_table->priority[index],
> +					drvdata->base +
> +					PRIORITY_REG_STEP(i, j, k));
> +			}
> +		}
> +	}
>   	/* Enable TGU to program the triggers */
>   	writel(1, drvdata->base + TGU_CONTROL);
>   	TGU_LOCK(drvdata->base);
>   }
>   
> +static void tgu_set_reg_number(struct tgu_drvdata *drvdata)
> +{
> +	int num_sense_input;
> +	int num_reg;
> +	u32 devid;
> +
> +	devid = readl(drvdata->base + TGU_DEVID);
> +
> +	num_sense_input = TGU_DEVID_SENSE_INPUT(devid);
> +	if (((num_sense_input * NUMBER_BITS_EACH_SIGNAL) % LENGTH_REGISTER) == 0)
> +		num_reg = (num_sense_input * NUMBER_BITS_EACH_SIGNAL) / LENGTH_REGISTER;
> +	else
> +		num_reg = ((num_sense_input * NUMBER_BITS_EACH_SIGNAL) / LENGTH_REGISTER) + 1;
> +	drvdata->max_reg = num_reg;
> +
> +}
> +
> +static void tgu_set_steps(struct tgu_drvdata *drvdata)
> +{
> +	u32 devid;
> +
> +	devid = readl(drvdata->base + TGU_DEVID);
> +
> +	drvdata->max_step = TGU_DEVID_STEPS(devid);
> +}
> +
>   static int tgu_enable(struct device *dev)
>   {
>   	struct tgu_drvdata *drvdata = dev_get_drvdata(dev);
> @@ -106,6 +213,38 @@ static const struct attribute_group tgu_common_grp = {
>   
>   static const struct attribute_group *tgu_attr_groups[] = {
>   	&tgu_common_grp,
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(0, 0),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(0, 1),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(0, 2),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(0, 3),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(1, 0),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(1, 1),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(1, 2),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(1, 3),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(2, 0),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(2, 1),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(2, 2),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(2, 3),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(3, 0),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(3, 1),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(3, 2),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(3, 3),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(4, 0),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(4, 1),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(4, 2),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(4, 3),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(5, 0),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(5, 1),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(5, 2),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(5, 3),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(6, 0),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(6, 1),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(6, 2),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(6, 3),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(7, 0),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(7, 1),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(7, 2),
> +	PRIORITY_ATTRIBUTE_GROUP_INIT(7, 3),
>   	NULL,
>   };
>   
> @@ -128,12 +267,29 @@ static int tgu_probe(struct amba_device *adev, const struct amba_id *id)
>   
>   	spin_lock_init(&drvdata->lock);
>   
> +	tgu_set_reg_number(drvdata);
> +	tgu_set_steps(drvdata);
> +
>   	ret = sysfs_create_groups(&dev->kobj, tgu_attr_groups);
>   	if (ret) {
>   		dev_err(dev, "failed to create sysfs groups: %d\n", ret);
>   		return ret;
>   	}
>   
> +	drvdata->value_table =
> +		devm_kzalloc(dev, sizeof(*drvdata->value_table), GFP_KERNEL);
> +	if (!drvdata->value_table)
> +		return -ENOMEM;
> +
> +	drvdata->value_table->priority = devm_kzalloc(
> +		dev,
> +		MAX_PRIORITY * drvdata->max_reg * drvdata->max_step *
> +			sizeof(*(drvdata->value_table->priority)),
> +		GFP_KERNEL);

can we declare a pri_size for better reading?

size_t pri_size;
unsigned int *priority

pri_size = MAX_PRIORITY * drvdata->max_reg * drvdata->max_step *
		sizeof(*(drvdata->value_table->priority));

priority = devm_kzalloc(dev, pri_size, GFP_KERNEL)
if (!priority)
	return -ENOMEM;

drvdata->value_table->priority = priority;

> +
> +	if (!drvdata->value_table->priority)
> +		return -ENOMEM;
> +
>   	drvdata->enable = false;
>   
>   	pm_runtime_put(&adev->dev);
> diff --git a/drivers/hwtracing/qcom/tgu.h b/drivers/hwtracing/qcom/tgu.h
> index abc732f91dfc..2cf95c239ee7 100644
> --- a/drivers/hwtracing/qcom/tgu.h
> +++ b/drivers/hwtracing/qcom/tgu.h
> @@ -10,6 +10,113 @@
>   #define TGU_CONTROL 0x0000
>   #define TGU_LAR		0xfb0
>   #define TGU_UNLOCK_OFFSET	0xc5acce55
> +#define TGU_DEVID	0xfc8
> +
> +#define BMVAL(val, lsb, msb)	((val & GENMASK(msb, lsb)) >> lsb)
> +#define TGU_DEVID_SENSE_INPUT(devid_val) ((int) BMVAL(devid_val, 10, 17))
> +#define TGU_DEVID_STEPS(devid_val) ((int)BMVAL(devid_val, 3, 6))
> +#define NUMBER_BITS_EACH_SIGNAL 4
> +#define LENGTH_REGISTER 32
> +
> +/*
> + *  TGU configuration space                              Step configuration
> + *  offset table                                         space layout
> + * x-------------------------x$                          x-------------x$
> + * |                         |$                          |             |$
> + * |                         |                           |   reserve   |$
> + * |                         |                           |             |$
> + * |coresight management     |                           |-------------|base+n*0x1D8+0x1F4$
> + * |     registe             |                     |---> |prioroty[3]  |$
> + * |                         |                     |     |-------------|base+n*0x1D8+0x194$
> + * |                         |                     |     |prioroty[2]  |$
> + * |-------------------------|                     |     |-------------|base+n*0x1D8+0x134$
> + * |                         |                     |     |prioroty[1]  |$
> + * |         step[7]         |                     |     |-------------|base+n*0x1D8+0xD4$
> + * |-------------------------|->base+0x40+7*0x1D8  |     |prioroty[0]  |$
> + * |                         |                     |     |-------------|base+n*0x1D8+0x74$
> + * |         ...             |                     |     |  condition  |$
> + * |                         |                     |     |   select    |$
> + * |-------------------------|->base+0x40+1*0x1D8  |     |-------------|base+n*0x1D8+0x60$
> + * |                         |                     |     |  condition  |$
> + * |         step[0]         |-------------------->      |   decode    |$
> + * |-------------------------|-> base+0x40               |-------------|base+n*0x1D8+0x50$
> + * |                         |                           |             |$
> + * | Control and status space|                           |Timer/Counter|$
> + * |        space            |                           |             |$
> + * x-------------------------x->base                     x-------------x base+n*0x1D8+0x40$
> + *
> + */
> +#define STEP_OFFSET 0x1D8
> +#define PRIORITY_START_OFFSET 0x0074
> +#define PRIORITY_OFFSET 0x60
> +#define REG_OFFSET 0x4
> +
> +/* Calculate compare step addresses */
> +#define PRIORITY_REG_STEP(step, priority, reg)\
> +	(PRIORITY_START_OFFSET + PRIORITY_OFFSET * priority +\
> +	 REG_OFFSET * reg + STEP_OFFSET * step)
> +
> +#define tgu_dataset_rw(name, step_index, type, reg_num)                  \
> +	(&((struct tgu_attribute[]){ {                                   \
> +		__ATTR(name, 0644, tgu_dataset_show, tgu_dataset_store), \
> +		step_index,                                              \
> +		type,                                                    \
> +		reg_num,                                                 \
> +	} })[0].attr.attr)
> +
> +#define STEP_PRIORITY(step_index, reg_num, priority)                     \
> +	tgu_dataset_rw(reg##reg_num, step_index, TGU_PRIORITY##priority, \
> +			reg_num)
> +
> +#define STEP_PRIORITY_LIST(step_index, priority)  \
> +	{STEP_PRIORITY(step_index, 0, priority),  \
> +	 STEP_PRIORITY(step_index, 1, priority),  \
> +	 STEP_PRIORITY(step_index, 2, priority),  \
> +	 STEP_PRIORITY(step_index, 3, priority),  \
> +	 STEP_PRIORITY(step_index, 4, priority),  \
> +	 STEP_PRIORITY(step_index, 5, priority),  \
> +	 STEP_PRIORITY(step_index, 6, priority),  \
> +	 STEP_PRIORITY(step_index, 7, priority),  \
> +	 STEP_PRIORITY(step_index, 8, priority),  \
> +	 STEP_PRIORITY(step_index, 9, priority),  \
> +	 STEP_PRIORITY(step_index, 10, priority), \
> +	 STEP_PRIORITY(step_index, 11, priority), \
> +	 STEP_PRIORITY(step_index, 12, priority), \
> +	 STEP_PRIORITY(step_index, 13, priority), \
> +	 STEP_PRIORITY(step_index, 14, priority), \
> +	 STEP_PRIORITY(step_index, 15, priority), \
> +	 STEP_PRIORITY(step_index, 16, priority), \
> +	 STEP_PRIORITY(step_index, 17, priority), \
> +	 NULL                   \
> +	}
> +
> +#define PRIORITY_ATTRIBUTE_GROUP_INIT(step, priority)\
> +	(&(const struct attribute_group){\
> +		.attrs = (struct attribute*[])STEP_PRIORITY_LIST(step, priority),\
> +		.is_visible = tgu_node_visible,\
> +		.name = "step" #step "_priority" #priority \
> +	})
> +
> +enum operation_index {
> +	TGU_PRIORITY0,
> +	TGU_PRIORITY1,
> +	TGU_PRIORITY2,
> +	TGU_PRIORITY3,
> +};
> +
> +/* Maximum priority that TGU supports */
> +#define MAX_PRIORITY 4
> +
> +struct tgu_attribute {
> +	struct device_attribute attr;
> +	u32 step_index;
> +	enum operation_index operation_index;
> +	u32 reg_num;
> +};
> +
> +struct value_table {
> +	unsigned int *priority;

priority here is an array? can we declare it as unsigned int array to 
limit the allocated memory?

With the declared array, we can avoid one more memory allocation.

priority[index] that is used in code looks like a trick.

> +};

only has one member, better integrate with tgu_drvdata with proper nameing.

Thanks,
Jie

>   
>   static inline void TGU_LOCK(void __iomem *addr)
>   {
> @@ -35,6 +142,9 @@ static inline void TGU_UNLOCK(void __iomem *addr)
>    * @dev: Pointer to the associated device structure
>    * @lock: Spinlock for handling concurrent access
>    * @enable: Flag indicating whether the TGU device is enabled
> + * @value_table: Store given value based on relevant parameters.
> + * @max_reg: Maximum number of registers
> + * @max_step: Maximum step size
>    *
>    * This structure defines the data associated with a TGU device,
>    * including its base address, device pointers, clock, spinlock for
> @@ -46,6 +156,9 @@ struct tgu_drvdata {
>   	struct device *dev;
>   	spinlock_t lock;
>   	bool enable;
> +	struct value_table *value_table;
> +	int max_reg;
> +	int max_step;
>   };
>   
>   #endif



From moonafterrain at outlook.com  Wed Dec 24 20:23:01 2025
From: moonafterrain at outlook.com (Junrui Luo)
Date: Thu, 25 Dec 2025 04:23:01 +0000
Subject: [PATCH] serial: digicolor: fix use-after-free on driver unbind
In-Reply-To: <2025122232-grass-stoppage-6645@gregkh>
References: <SYBPR01MB7881327BF7F679E76A7315DEAFB4A@SYBPR01MB7881.ausprd01.prod.outlook.com>
 <2025122232-grass-stoppage-6645@gregkh>
Message-ID: <SYBPR01MB7881835C63D3E6F5F4BA81FFAFB2A@SYBPR01MB7881.ausprd01.prod.outlook.com>

On Mon, Dec 22, 2025 at 07:22:14AM +0100, Greg Kroah-Hartman wrote:
> On Mon, Dec 22, 2025 at 12:55:02PM +0800, Junrui Luo wrote:
> > The digicolor_uart_console_write() function accesses the global
> > digicolor_ports[] array to retrieve the uart port pointer, which
> > can lead to a use-after-free if the console write occurs after
> > the port has been removed via unbind.
> > 
> > digicolor_uart_remove() leaves a dangling pointer in the array.
> > 
> > Fix by clearing the array entry in digicolor_uart_remove() and
> > adding a NULL check in digicolor_uart_console_write().
> > 
> > Reported-by: Yuhao Jiang <danisjiang at gmail.com>
> > Reported-by: Junrui Luo <moonafterrain at outlook.com>
> > Fixes: 5930cb3511df ("serial: driver for Conexant Digicolor USART")
> > Signed-off-by: Junrui Luo <moonafterrain at outlook.com>
> > ---
> >  drivers/tty/serial/digicolor-usart.c | 4 ++++
> >  1 file changed, 4 insertions(+)
> > 
> > diff --git a/drivers/tty/serial/digicolor-usart.c b/drivers/tty/serial/digicolor-usart.c
> > index d2482df5cb9b..5861be2072c4 100644
> > --- a/drivers/tty/serial/digicolor-usart.c
> > +++ b/drivers/tty/serial/digicolor-usart.c
> > @@ -397,6 +397,9 @@ static void digicolor_uart_console_write(struct console *co, const char *c,
> >  	unsigned long flags;
> >  	int locked = 1;
> >  
> > +	if (!port)
> > +		return;
> > +
> 
> What prevents port from changing right after you tested this?

Thanks for the review. You're right that there's a potentially race window
between the NULL check and port usage. I found that several drivers handle
this the same way:

- meson_uart: has NULL check in console_write, clears array in remove
- sprd_serial: Fixed similar issue in commit 99038fe75afa

This check does not fully eliminate the race window, and adding stronger
synchronization in the console_write() path may have non-trivial cost. I
am willing to adopt an alternative if one is preferred.

> 
> And who is calling unbind on a port?  Why?  That's a debuggging thing
> that a developer could do, it should not be part of any normal system
> operation.

Although this may most commonly occur in development or testing
environments, it is still a legitimate bug that should be fixed.

In addition, unbind may also occur in:

- Some embedded systems using runtime device tree overlays
- Certain virtualization scenarios with device passthrough

Though these are uncommon.

thanks,
Junrui Luo

From shimin.guo at skydio.com  Wed Dec 24 21:02:28 2025
From: shimin.guo at skydio.com (Shimin Guo)
Date: Wed, 24 Dec 2025 21:02:28 -0800
Subject: [PATCH] perf unwind-libdw: fix a cross-arch unwinding bug
In-Reply-To: <c25d5032-5a41-4e95-ae76-3466875241a0@linaro.org>
References: <20251223-cross-arch-unwind-v1-1-4d71ee7db512@skydio.com> <c25d5032-5a41-4e95-ae76-3466875241a0@linaro.org>
Message-ID: <CAK3u-5hE6zAT21bnEa7H-URAP1CsNrgnYu2fJ+t8CBO=xo3tpA@mail.gmail.com>

On Wed, Dec 24, 2025 at 5:40?AM James Clark <james.clark at linaro.org> wrote:
>
>
>
> On 24/12/2025 2:19 am, Shimin Guo via B4 Relay wrote:
> > From: Shimin Guo <shimin.guo at skydio.com>
> >
> > The set_initial_registers field of Dwfl_Thread_Callbacks needs to be set
> > according to the arch of the stack samples being analyzed, not the arch
> > that perf itself is built for. Currently perf fails to unwind stack samples
> > collected from archs different from that of the host perf is running on.
> > This patch moves the arch-specific implementations of set_initial_registers
> > from tools/perf/arch to tools/perf/utli/unwind-libdw-arch, similar to the
> > way the perf-regs-arch folder contains arch-specific functions related to
> > registers, and chooses the implementation based on the arch of the data
> > being processed.
> >
> > Signed-off-by: Shimin Guo <shimin.guo at skydio.com>
> > ---
> > checkpatch flagged three issues:
> >> tools/perf/util/unwind-libdw-arch/Build:232: WARNING: added, moved
> > or deleted file(s), does MAINTAINERS need updating?
> >
> > Not sure what to do about that.
> >
>
> You don't need to do anything here because there's a blanket rule for
> the Perf dir.

PERFORMANCE EVENTS TOOLING ARM64 has a rule that matches tools/perf/arch/arm*/.
The new files for arm and arm64 will no longer be matched by the rule.

>
> >> checkpatch.pl: tools/perf/util/unwind-libdw.c:228: WARNING:
> > Non-declarative macros with multiple statements should be enclosed in
> > a do - while loop
>
> I think you can ignore this one.
>
> >> checkpatch.pl: tools/perf/util/unwind-libdw.c:228: WARNING: macros
> > should not use a trailing semicolon
> >
> > Are these two false positives? I'm defining static global variables
> > with the macro.
>
> But I don't see a reason not to follow this one, just remove the semicolon.

Maybe it doesn't matter, but after I removed the semicolon, I got a new error
from checkpatch "Macros with complex values should be enclosed in parentheses"
instead of the warning that suggests do - while.

>
> > ---
> >   tools/perf/arch/arm/util/Build                     |  1 -
> >   tools/perf/arch/arm64/util/Build                   |  1 -
> >   tools/perf/arch/csky/util/Build                    |  2 -
> >   tools/perf/arch/powerpc/util/Build                 |  1 -
> >   tools/perf/arch/riscv/util/Build                   |  1 -
> >   tools/perf/arch/s390/util/Build                    |  2 -
> >   tools/perf/arch/x86/util/Build                     |  1 -
> >   tools/perf/util/Build                              |  1 +
> >   tools/perf/util/unwind-libdw-arch/Build            |  8 ++++
> >   .../unwind-libdw-arch/unwind-libdw-arm.c}          |  4 +-
> >   .../unwind-libdw-arch/unwind-libdw-arm64.c}        |  4 +-
> >   .../unwind-libdw-arch/unwind-libdw-csky.c}         |  6 +--
> >   .../unwind-libdw-arch/unwind-libdw-loongarch.c}    |  4 +-
> >   .../unwind-libdw-arch/unwind-libdw-powerpc.c}      |  4 +-
> >   .../unwind-libdw-arch/unwind-libdw-riscv.c}        |  4 +-
> >   .../unwind-libdw-arch/unwind-libdw-s390.c}         |  6 +--
> >   .../unwind-libdw-arch/unwind-libdw-x86.c}          |  2 +-
> >   tools/perf/util/unwind-libdw.c                     | 49 +++++++++++++++++++---
> >   tools/perf/util/unwind-libdw.h                     | 10 ++++-
> >   19 files changed, 79 insertions(+), 32 deletions(-)
> >
> > diff --git a/tools/perf/arch/arm/util/Build b/tools/perf/arch/arm/util/Build
> > index fd695e1fdaee2ccc300a206131b8b38a763b00ce..3291f893b943df0722dff583523fff4ae79919bc 100644
> > --- a/tools/perf/arch/arm/util/Build
> > +++ b/tools/perf/arch/arm/util/Build
> > @@ -1,6 +1,5 @@
> >   perf-util-y += perf_regs.o
> >
> >   perf-util-$(CONFIG_LOCAL_LIBUNWIND)    += unwind-libunwind.o
> > -perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
> >
> >   perf-util-y += pmu.o auxtrace.o cs-etm.o
> > diff --git a/tools/perf/arch/arm64/util/Build b/tools/perf/arch/arm64/util/Build
> > index d63881081d2eb1e9a83eabf82104d75308f7fc79..0177af19cc00038d6a6005592ddc530bf7eb1557 100644
> > --- a/tools/perf/arch/arm64/util/Build
> > +++ b/tools/perf/arch/arm64/util/Build
> > @@ -1,4 +1,3 @@
> > -perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
> >   perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
> >   perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
> >   perf-util-y += ../../arm/util/auxtrace.o
> > diff --git a/tools/perf/arch/csky/util/Build b/tools/perf/arch/csky/util/Build
> > index 5e6ea82c42021d3d5651ca4c4a3a6e5138574e4e..6b2d0e021b11464e46d6b53974260d32ea969732 100644
> > --- a/tools/perf/arch/csky/util/Build
> > +++ b/tools/perf/arch/csky/util/Build
> > @@ -1,3 +1 @@
> >   perf-util-y += perf_regs.o
> > -
> > -perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
> > diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build
> > index 3d0d5427aef7f26a8c05c883cc7ad763f08cbb30..5fd28ec713a4db74ecd1d26866a65ddb20e94bd3 100644
> > --- a/tools/perf/arch/powerpc/util/Build
> > +++ b/tools/perf/arch/powerpc/util/Build
> > @@ -9,5 +9,4 @@ perf-util-y += evsel.o
> >   perf-util-$(CONFIG_LIBDW) += skip-callchain-idx.o
> >
> >   perf-util-$(CONFIG_LIBUNWIND) += unwind-libunwind.o
> > -perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
> >   perf-util-y += auxtrace.o
> > diff --git a/tools/perf/arch/riscv/util/Build b/tools/perf/arch/riscv/util/Build
> > index 58a672246024dd0f72e767d11e9958bd9913ec3c..628b9ebd418bde8cdf1ab1332bf79f7c9d50760e 100644
> > --- a/tools/perf/arch/riscv/util/Build
> > +++ b/tools/perf/arch/riscv/util/Build
> > @@ -2,4 +2,3 @@ perf-util-y += perf_regs.o
> >   perf-util-y += header.o
> >
> >   perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
> > -perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
> > diff --git a/tools/perf/arch/s390/util/Build b/tools/perf/arch/s390/util/Build
> > index c64eb18dbdae93adafabf8542e4c9a763ecfe057..5391d26fedd46b7d30a1bef0bff2ec2d58ec30ed 100644
> > --- a/tools/perf/arch/s390/util/Build
> > +++ b/tools/perf/arch/s390/util/Build
> > @@ -2,8 +2,6 @@ perf-util-y += header.o
> >   perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
> >   perf-util-y += perf_regs.o
> >
> > -perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
> > -
> >   perf-util-y += machine.o
> >   perf-util-y += pmu.o
> >
> > diff --git a/tools/perf/arch/x86/util/Build b/tools/perf/arch/x86/util/Build
> > index c0dc5965f3624a6f02525a04d287dff755356d20..fad256252bb95a8f8350b6bb1a54e8074eaebbec 100644
> > --- a/tools/perf/arch/x86/util/Build
> > +++ b/tools/perf/arch/x86/util/Build
> > @@ -12,7 +12,6 @@ perf-util-y += evsel.o
> >   perf-util-y += iostat.o
> >
> >   perf-util-$(CONFIG_LOCAL_LIBUNWIND)    += unwind-libunwind.o
> > -perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
> >
> >   perf-util-y += auxtrace.o
> >   perf-util-y += archinsn.o
> > diff --git a/tools/perf/util/Build b/tools/perf/util/Build
> > index 1c2a43e1dc68e7f751ec6082352b10de9ffeea62..15f8a4f4b24a46b6300e824f672dd9c0d5b7865f 100644
> > --- a/tools/perf/util/Build
> > +++ b/tools/perf/util/Build
> > @@ -226,6 +226,7 @@ perf-util-$(CONFIG_LIBDW) += debuginfo.o
> >   perf-util-$(CONFIG_LIBDW) += annotate-data.o
> >
> >   perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
> > +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-arch/
> >   perf-util-$(CONFIG_LOCAL_LIBUNWIND)    += unwind-libunwind-local.o
> >   perf-util-$(CONFIG_LIBUNWIND)          += unwind-libunwind.o
> >   perf-util-$(CONFIG_LIBUNWIND_X86)      += libunwind/x86_32.o
> > diff --git a/tools/perf/util/unwind-libdw-arch/Build b/tools/perf/util/unwind-libdw-arch/Build
> > new file mode 100644
> > index 0000000000000000000000000000000000000000..e016d54ae2a40ecba47156c8f09cb72156105727
> > --- /dev/null
> > +++ b/tools/perf/util/unwind-libdw-arch/Build
> > @@ -0,0 +1,8 @@
> > +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-x86.o
> > +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-arm.o
> > +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-arm64.o
> > +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-csky.o
> > +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-loongarch.o
> > +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-powerpc.o
> > +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-riscv.o
> > +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-s390.o
> > \ No newline at end of file
> > diff --git a/tools/perf/arch/arm/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-arm.c
> > similarity index 88%
> > rename from tools/perf/arch/arm/util/unwind-libdw.c
> > rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-arm.c
> > index fbb643f224ec4b27ce9d67051fe0bc4ad555b05e..c2718d6b6cff131cd67883e24bb0d3d963c8095a 100644
> > --- a/tools/perf/arch/arm/util/unwind-libdw.c
> > +++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-arm.c
> > @@ -1,11 +1,11 @@
> >   // SPDX-License-Identifier: GPL-2.0
> >   #include <elfutils/libdwfl.h>
> > -#include "perf_regs.h"
> > +#include "../../../arch/arm/include/uapi/asm/perf_regs.h"
> >   #include "../../../util/unwind-libdw.h"
> >   #include "../../../util/perf_regs.h"
> >   #include "../../../util/sample.h"
> >
> > -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
> > +bool libdw_set_initial_registers_arm(Dwfl_Thread *thread, void *arg)
> >   {
> >       struct unwind_info *ui = arg;
> >       struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
> > diff --git a/tools/perf/arch/arm64/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-arm64.c
> > similarity index 92%
> > rename from tools/perf/arch/arm64/util/unwind-libdw.c
> > rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-arm64.c
> > index b89b0a7e5ad919fed23643d219fbdc3d84deff1e..87602503e057badc6efd37169cc60c96cf3949ab 100644
> > --- a/tools/perf/arch/arm64/util/unwind-libdw.c
> > +++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-arm64.c
> > @@ -1,11 +1,11 @@
> >   // SPDX-License-Identifier: GPL-2.0
> >   #include <elfutils/libdwfl.h>
> > -#include "perf_regs.h"
> > +#include "../../../arch/arm64/include/uapi/asm/perf_regs.h"
> >   #include "../../../util/unwind-libdw.h"
> >   #include "../../../util/perf_regs.h"
> >   #include "../../../util/sample.h"
> >
> > -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
> > +bool libdw_set_initial_registers_arm64(Dwfl_Thread *thread, void *arg)
> >   {
> >       struct unwind_info *ui = arg;
> >       struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
> > diff --git a/tools/perf/arch/csky/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-csky.c
> > similarity index 92%
> > rename from tools/perf/arch/csky/util/unwind-libdw.c
> > rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-csky.c
> > index b20b1569783d7e982e91b1b40120d29ccf2f01d1..889d3b788931f3af55b03ef8b91d5def364972e5 100644
> > --- a/tools/perf/arch/csky/util/unwind-libdw.c
> > +++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-csky.c
> > @@ -2,12 +2,12 @@
> >   // Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd.
> >
> >   #include <elfutils/libdwfl.h>
> > -#include "perf_regs.h"
> > +#include "../../../arch/csky/include/uapi/asm/perf_regs.h"
> >   #include "../../util/unwind-libdw.h"
> >   #include "../../util/perf_regs.h"
> > -#include "../../util/event.h"
> > +#include "../../util/sample.h"
> >
> > -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
> > +bool libdw_set_initial_registers_csky(Dwfl_Thread *thread, void *arg)
> >   {
> >       struct unwind_info *ui = arg;
> >       struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
> > diff --git a/tools/perf/arch/loongarch/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-loongarch.c
> > similarity index 91%
> > rename from tools/perf/arch/loongarch/util/unwind-libdw.c
> > rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-loongarch.c
> > index 60b1144bedd5f325e1512eeab05c29a1e8de2b03..1c5753ace6f63be771aa92365d3174ad8ed3a6fd 100644
> > --- a/tools/perf/arch/loongarch/util/unwind-libdw.c
> > +++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-loongarch.c
> > @@ -2,12 +2,12 @@
> >   /* Copyright (C) 2020-2023 Loongson Technology Corporation Limited */
> >
> >   #include <elfutils/libdwfl.h>
> > -#include "perf_regs.h"
> > +#include "../../../arch/loongarch/include/uapi/asm/perf_regs.h"
> >   #include "../../util/unwind-libdw.h"
> >   #include "../../util/perf_regs.h"
> >   #include "../../util/sample.h"
> >
> > -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
> > +bool libdw_set_initial_registers_loongarch(Dwfl_Thread *thread, void *arg)
> >   {
> >       struct unwind_info *ui = arg;
> >       struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
> > diff --git a/tools/perf/arch/powerpc/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-powerpc.c
> > similarity index 93%
> > rename from tools/perf/arch/powerpc/util/unwind-libdw.c
> > rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-powerpc.c
> > index 82d0c28ae3459ecdb0039cac1f534420d142739b..28635af3c4aa420faa4de7e53428d82917f78021 100644
> > --- a/tools/perf/arch/powerpc/util/unwind-libdw.c
> > +++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-powerpc.c
> > @@ -1,7 +1,7 @@
> >   // SPDX-License-Identifier: GPL-2.0
> >   #include <elfutils/libdwfl.h>
> >   #include <linux/kernel.h>
> > -#include "perf_regs.h"
> > +#include "../../../arch/powerpc/include/uapi/asm/perf_regs.h"
> >   #include "../../../util/unwind-libdw.h"
> >   #include "../../../util/perf_regs.h"
> >   #include "../../../util/sample.h"
> > @@ -13,7 +13,7 @@ static const int special_regs[3][2] = {
> >       { 109, PERF_REG_POWERPC_CTR },
> >   };
> >
> > -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
> > +bool libdw_set_initial_registers_powerpc(Dwfl_Thread *thread, void *arg)
> >   {
> >       struct unwind_info *ui = arg;
> >       struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
> > diff --git a/tools/perf/arch/riscv/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-riscv.c
> > similarity index 92%
> > rename from tools/perf/arch/riscv/util/unwind-libdw.c
> > rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-riscv.c
> > index dc1476e16321736de897ad53a00fbc813bd706db..2a5442b3b5bdc27252378de0073deb8a620f8779 100644
> > --- a/tools/perf/arch/riscv/util/unwind-libdw.c
> > +++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-riscv.c
> > @@ -2,12 +2,12 @@
> >   /* Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd. */
> >
> >   #include <elfutils/libdwfl.h>
> > -#include "perf_regs.h"
> > +#include "../../../arch/riscv/include/uapi/asm/perf_regs.h"
> >   #include "../../util/unwind-libdw.h"
> >   #include "../../util/perf_regs.h"
> >   #include "../../util/sample.h"
> >
> > -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
> > +bool libdw_set_initial_registers_riscv(Dwfl_Thread *thread, void *arg)
> >   {
> >       struct unwind_info *ui = arg;
> >       struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
> > diff --git a/tools/perf/arch/s390/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-s390.c
> > similarity index 89%
> > rename from tools/perf/arch/s390/util/unwind-libdw.c
> > rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-s390.c
> > index c27c7a0d1076c890c35ba19543932c4ed5ac9c2a..18d44074a55bc1c7fa2d7150afc1f1a93d4eadf8 100644
> > --- a/tools/perf/arch/s390/util/unwind-libdw.c
> > +++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-s390.c
> > @@ -4,11 +4,11 @@
> >   #include "../../util/perf_regs.h"
> >   #include "../../util/event.h"
> >   #include "../../util/sample.h"
> > -#include "dwarf-regs-table.h"
> > -#include "perf_regs.h"
> > +#include "../../arch/s390/include/dwarf-regs-table.h"
> > +#include "../../../arch/s390/include/uapi/asm/perf_regs.h"
> >
> >
> > -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
> > +bool libdw_set_initial_registers_s390(Dwfl_Thread *thread, void *arg)
> >   {
> >       struct unwind_info *ui = arg;
> >       struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
> > diff --git a/tools/perf/arch/x86/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-x86.c
> > similarity index 94%
> > rename from tools/perf/arch/x86/util/unwind-libdw.c
> > rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-x86.c
> > index 798493e887d7308cb293e29e4ba11054d0fda722..822e799fe1543d82dab27a8efeada3f5cde08a44 100644
> > --- a/tools/perf/arch/x86/util/unwind-libdw.c
> > +++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-x86.c
>
> You missed converting the unwind-libdw-x86.c perf_regs.h paths to a
> static arch so now Perf can only be built on x86. If you try to build
> for another arch then you get the local header and then missing x86
> definitions.

Yeah you are right. I'm also going to change some of the relative include paths
from "../../../" to "../../" since the new files are two levels under
tools/perf instead of
three. The build worked without the change mostly by accident.

>
> Unfortunately you also have to convert the one in
> tools/perf/arch/x86/include/perf_regs.h which is a bit weird, but the
> build seems to work.

How does tools/perf/arch/x86/include/perf_regs.h come up? I seem to be able to
build an arm64 version without changing this file.

>
> Other than that, looks good.
>
> > @@ -5,7 +5,7 @@
> >   #include "../../../util/perf_regs.h"
> >   #include "util/sample.h"
> >
> > -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
> > +bool libdw_set_initial_registers_x86(Dwfl_Thread *thread, void *arg)
> >   {
> >       struct unwind_info *ui = arg;
> >       struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
> > diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
> > index ae70fb56a05729b9f06a411d162eabebbf29ac52..4a0f13bc5af99de446d440c551c718ef0187e195 100644
> > --- a/tools/perf/util/unwind-libdw.c
> > +++ b/tools/perf/util/unwind-libdw.c
> > @@ -225,12 +225,46 @@ static bool memory_read(Dwfl *dwfl __maybe_unused, Dwarf_Addr addr, Dwarf_Word *
> >       return true;
> >   }
> >
> > -static const Dwfl_Thread_Callbacks callbacks = {
> > -     .next_thread            = next_thread,
> > -     .memory_read            = memory_read,
> > -     .set_initial_registers  = libdw__arch_set_initial_registers,
> > +#define DEFINE_DWFL_THREAD_CALLBACKS(arch)                           \
> > +static const Dwfl_Thread_Callbacks callbacks_##arch = {              \
> > +     .next_thread           = next_thread,                        \
> > +     .memory_read           = memory_read,                        \
> > +     .set_initial_registers = libdw_set_initial_registers_##arch, \
> >   };
> >
> > +DEFINE_DWFL_THREAD_CALLBACKS(x86)
> > +DEFINE_DWFL_THREAD_CALLBACKS(arm)
> > +DEFINE_DWFL_THREAD_CALLBACKS(arm64)
> > +DEFINE_DWFL_THREAD_CALLBACKS(csky)
> > +DEFINE_DWFL_THREAD_CALLBACKS(loongarch)
> > +DEFINE_DWFL_THREAD_CALLBACKS(powerpc)
> > +DEFINE_DWFL_THREAD_CALLBACKS(riscv)
> > +DEFINE_DWFL_THREAD_CALLBACKS(s390)
> > +
> > +static const Dwfl_Thread_Callbacks *get_thread_callbacks(const char *arch)
> > +{
> > +     if (!strcmp(arch, "arm"))
> > +             return &callbacks_arm;
> > +     else if (!strcmp(arch, "arm64"))
> > +             return &callbacks_arm64;
> > +     else if (!strcmp(arch, "csky"))
> > +             return &callbacks_csky;
> > +     else if (!strcmp(arch, "loongarch"))
> > +             return &callbacks_loongarch;
> > +     else if (!strcmp(arch, "powerpc"))
> > +             return &callbacks_powerpc;
> > +     else if (!strcmp(arch, "riscv"))
> > +             return &callbacks_riscv;
> > +     else if (!strcmp(arch, "s390"))
> > +             return &callbacks_s390;
> > +     else if (!strcmp(arch, "x86"))
> > +             return &callbacks_x86;
> > +
> > +     pr_err("Fail to get thread callbacks for arch %s, returns NULL\n",
> > +            arch);
> > +     return NULL;
> > +}
> > +
> >   static int
> >   frame_callback(Dwfl_Frame *state, void *arg)
> >   {
> > @@ -278,6 +312,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
> >       const char *arch = perf_env__arch(ui_buf.machine->env);
> >       Dwarf_Word ip;
> >       int err = -EINVAL, i;
> > +     const Dwfl_Thread_Callbacks *callbacks;
> >
> >       if (!data->user_regs || !data->user_regs->regs)
> >               return -EINVAL;
> > @@ -300,7 +335,11 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
> >       if (err)
> >               goto out;
> >
> > -     err = !dwfl_attach_state(ui->dwfl, EM_NONE, thread__tid(thread), &callbacks, ui);
> > +     callbacks = get_thread_callbacks(arch);
> > +     if (!callbacks)
> > +             goto out;
> > +
> > +     err = !dwfl_attach_state(ui->dwfl, EM_NONE, thread__tid(thread), callbacks, ui);
> >       if (err)
> >               goto out;
> >
> > diff --git a/tools/perf/util/unwind-libdw.h b/tools/perf/util/unwind-libdw.h
> > index 8c88bc4f2304b59561ffd482469ca63ce0f531f0..574b29848cce31e6bfd93021f752b518cebf73b7 100644
> > --- a/tools/perf/util/unwind-libdw.h
> > +++ b/tools/perf/util/unwind-libdw.h
> > @@ -9,7 +9,15 @@ struct machine;
> >   struct perf_sample;
> >   struct thread;
> >
> > -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg);
> > +bool libdw_set_initial_registers_x86(Dwfl_Thread *thread, void *arg);
> > +bool libdw_set_initial_registers_arm(Dwfl_Thread *thread, void *arg);
> > +bool libdw_set_initial_registers_arm64(Dwfl_Thread *thread, void *arg);
> > +bool libdw_set_initial_registers_csky(Dwfl_Thread *thread, void *arg);
> > +bool libdw_set_initial_registers_loongarch(Dwfl_Thread *thread, void *arg);
> > +bool libdw_set_initial_registers_mips(Dwfl_Thread *thread, void *arg);
> > +bool libdw_set_initial_registers_powerpc(Dwfl_Thread *thread, void *arg);
> > +bool libdw_set_initial_registers_riscv(Dwfl_Thread *thread, void *arg);
> > +bool libdw_set_initial_registers_s390(Dwfl_Thread *thread, void *arg);
> >
> >   struct unwind_info {
> >       Dwfl                    *dwfl;
> >
> > ---
> > base-commit: cbd41c6d4c26c161a2b0e70ad411d3885ff13507
> > change-id: 20251223-cross-arch-unwind-d890d6a5ff0a
> >
> > Best regards,
>


From 21cnbao at gmail.com  Wed Dec 24 21:45:09 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Thu, 25 Dec 2025 18:45:09 +1300
Subject: [PATCH 5/6] dma-mapping: Allow batched DMA sync operations if supported by the arch
In-Reply-To: <20251224085145.GF11869@unreal>
References: <20251224085145.GF11869@unreal>
Message-ID: <20251225054509.39917-1-21cnbao@gmail.com>

> > >
> >
> > OK. Could you take a look at [1] and see if any further
> > improvements are needed before I send v2?
>
> Everything looks ok, except these renames:
> -                       arch_sync_dma_for_cpu(paddr, sg->length, dir);
> +                       arch_sync_dma_for_cpu_batch_add(paddr, sg->length, dir);

Thanks!
I'm happy to drop the rename as outlined below-feedback welcome :-)

diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h
index dd2c8586a725..487fb7c355ed 100644
--- a/arch/arm64/include/asm/cache.h
+++ b/arch/arm64/include/asm/cache.h
@@ -87,6 +87,12 @@ int cache_line_size(void);
 
 #define dma_get_cache_alignment	cache_line_size
 
+static inline void arch_sync_dma_flush(void)
+{
+	dsb(sy);
+}
+#define arch_sync_dma_flush arch_sync_dma_flush
+
 /* Compress a u64 MPIDR value into 32 bits. */
 static inline u64 arch_compact_of_hwid(u64 id)
 {
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index b2b5792b2caa..ae1ae0280eef 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -17,7 +17,7 @@ void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
 {
 	unsigned long start = (unsigned long)phys_to_virt(paddr);
 
-	dcache_clean_poc(start, start + size);
+	dcache_clean_poc_nosync(start, start + size);
 }
 
 void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
@@ -28,7 +28,7 @@ void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
 	if (dir == DMA_TO_DEVICE)
 		return;
 
-	dcache_inval_poc(start, start + size);
+	dcache_inval_poc_nosync(start, start + size);
 }
 
 void arch_dma_prep_coherent(struct page *page, size_t size)
diff --git a/include/linux/dma-map-ops.h b/include/linux/dma-map-ops.h
index 4809204c674c..e7dd8a63b40e 100644
--- a/include/linux/dma-map-ops.h
+++ b/include/linux/dma-map-ops.h
@@ -361,6 +361,12 @@ static inline void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
 }
 #endif /* ARCH_HAS_SYNC_DMA_FOR_CPU */
 
+#ifndef arch_sync_dma_flush
+static inline void arch_sync_dma_flush(void)
+{
+}
+#endif
+
 #ifdef CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU_ALL
 void arch_sync_dma_for_cpu_all(void);
 #else


From Kyrie.Wu at mediatek.com  Wed Dec 24 21:48:38 2025
From: Kyrie.Wu at mediatek.com (=?utf-8?B?S3lyaWUgV3UgKOWQtOaZlyk=?=)
Date: Thu, 25 Dec 2025 05:48:38 +0000
Subject: [PATCH v11 02/12] media: mediatek: jpeg: fix jpeg buffer payload
 setting
In-Reply-To: <36268d4980a1cd6d976bdf5de148f1c2668a92e4.camel@ndufresne.ca>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
	 <20251202094800.6140-3-kyrie.wu@mediatek.com>
	 <36268d4980a1cd6d976bdf5de148f1c2668a92e4.camel@ndufresne.ca>
Message-ID: <c133597593c69e0fcb2cb7ea5c14fcb6013302c8.camel@mediatek.com>

On Tue, 2025-12-16 at 16:15 -0500, Nicolas Dufresne wrote:
> Hi.
> 
> Le mardi 02 d?cembre 2025 ? 17:47 +0800, Kyrie Wu a ?crit :
> > For multi-core jpegdec, if one of hws gets the event of resolution
> > changing, the payload size, representing the size of Y/C data,
> 
> -> "gets the resolution change event, ..."
> 
> > needed to change. But others hws are decoding at the same time and
> 
> needed -> needs,               hws -> cores ?
> 
> It this specific to decoders or any type of cores ?
> 
> > it can not be changed immediately, which results that the payload
> 
>                                                     in the playload
> 
> > size is not equal to the real buffer length of the hw's, which
> > occurred
> 
> size to not match the real buffer lenght for the ... hw ?
> 
> > resolution changing and a warnning call trace will print.
> 
> Can't parse. You can probably split that large sentence, and it needs
> to be
> rework.
> 
> > So the setting of payload size must less than the real buffer
> > length
> > to remove the warnning logs.
> > 
> > Fixes: 0fa49df4222f ("media: mtk-jpegdec: support jpegdec multi-
> > hardware")
> > 
> 
> Don't add blank line in tags please.
> 
> > Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
> > ---
> >  .../platform/mediatek/jpeg/mtk_jpeg_core.c    | 19 ++++++++++++++-
> > ----
> >  1 file changed, 14 insertions(+), 5 deletions(-)
> > 
> > diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > index 6a7e01130f1c..0cf3dc5407e4 100644
> > --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > @@ -709,6 +709,7 @@ static int mtk_jpeg_buf_prepare(struct
> > vb2_buffer *vb)
> >  	struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
> >  	struct mtk_jpeg_q_data *q_data = NULL;
> >  	struct v4l2_plane_pix_format plane_fmt = {};
> > +	unsigned long max_size;
> 
> size_t ?
> 
> >  	int i;
> >  
> >  	q_data = mtk_jpeg_get_q_data(ctx, vb->vb2_queue->type);
> > @@ -717,12 +718,20 @@ static int mtk_jpeg_buf_prepare(struct
> > vb2_buffer *vb)
> >  
> >  	for (i = 0; i < q_data->fmt->colplanes; i++) {
> >  		plane_fmt = q_data->pix_mp.plane_fmt[i];
> > +		max_size = plane_fmt.sizeimage;
> > +
> >  		if (ctx->enable_exif &&
> > -		    q_data->fmt->fourcc == V4L2_PIX_FMT_JPEG)
> > -			vb2_set_plane_payload(vb, i,
> > plane_fmt.sizeimage +
> > -					      MTK_JPEG_MAX_EXIF_SIZE);
> > -		else
> > -			vb2_set_plane_payload(vb, i, 
> > plane_fmt.sizeimage);
> > +			q_data->fmt->fourcc == V4L2_PIX_FMT_JPEG) {
> > +			max_size += MTK_JPEG_MAX_EXIF_SIZE;
> > +
> > +			vb2_set_plane_payload(vb, i,
> > +					      MIN(vb->planes[i].length,
> > +						  max_size));
> 
> This is still not quite right. sizeimage, straight from s_fmt should
> already
> account for the EXIF headers. If enable_exif is unknown at the
> moment, then you
> should just always include that space. This way, the buffer length
> will only be
> bigger if userspace asked for more at allocation time, and wil never
> be smaller
> then this.
> 
> The point of sizeimage it to allow userspace allocate externally the
> right size,
> this driver failed at that task it seems.
> 
> Stepping back a little, I don't even understand why you set the
> payload size
> like this here. Why isn't the true payload size written once, when
> the buffer is
> encoded ? Are you using bytesused to tell the HW how much space can
> be written
> too ? Just give it the full space, wich is the allocated size
> (length).
> 
> Nicolas

Dear Nicolas,

The value, max_size = plane_fmt.sizeimage, recorded the current size,
but if the resolution changed to a smaller one, the sizeimage will
bigger
than the vb->planes[i].length, in the former sw flow, the bigger value
will set to payload size and caused a warnning call trace printed.

Here are the answers of your questions:
1. The enable_exif is a
determined value, which is set in s_ctrl before 
jpeg decoder/encoder starting.

2. If enable_exif is set as true, the buffer planes length is equal to
sizeimage + MTK_JPEG_MAX_EXIF_SIZE.

3. The reason, Why isn't the true payload size written once,
is due to this setting is used to avoid the condition descripted in
commit message. And it will set the true value in irq handler.

Thanks.

Regards,
Kyrie.
> 
> 
> > +		} else {
> > +			vb2_set_plane_payload(vb, i,
> > +					      MIN(plane_fmt.sizeimage,
> > +						  vb-
> > >planes[i].length));
> > +		}
> >  	}
> >  
> >  	return 0;

From jie.gan at oss.qualcomm.com  Wed Dec 24 21:56:37 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Thu, 25 Dec 2025 13:56:37 +0800
Subject: [PATCH v9 7/7] qcom-tgu: Add reset node to initialize
In-Reply-To: <20251219065902.2296896-8-songwei.chai@oss.qualcomm.com>
References: <20251219065902.2296896-1-songwei.chai@oss.qualcomm.com>
 <20251219065902.2296896-8-songwei.chai@oss.qualcomm.com>
Message-ID: <aa3ee735-8ef1-4f44-9528-e93ebec2a215@oss.qualcomm.com>



On 12/19/2025 2:59 PM, Songwei Chai wrote:
> Add reset node to initialize the value of
> priority/condition_decode/condition_select/timer/counter nodes.
> 
> Signed-off-by: Songwei Chai <songwei.chai at oss.qualcomm.com>
> ---
>   .../ABI/testing/sysfs-bus-amba-devices-tgu    |  7 ++
>   drivers/hwtracing/qcom/tgu.c                  | 74 +++++++++++++++++++
>   2 files changed, 81 insertions(+)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
> index 010eade0a1c5..0733b3e07b45 100644
> --- a/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
> +++ b/Documentation/ABI/testing/sysfs-bus-amba-devices-tgu
> @@ -42,3 +42,10 @@ KernelVersion	6.19
>   Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Songwei Chai <songwei.chai at oss.qualcomm.com>
>   Description:
>   		(RW) Set/Get the counter value with specific step for TGU.
> +
> +What:		/sys/bus/amba/devices/<tgu-name>/reset_tgu
> +Date:		December 2025
> +KernelVersion	6.19
> +Contact:	Jinlong Mao <jinlong.mao at oss.qualcomm.com>, Songwei Chai <songwei.chai at oss.qualcomm.com>
> +Description:
> +		(Write) Write 1 to reset the dataset for TGU.
> diff --git a/drivers/hwtracing/qcom/tgu.c b/drivers/hwtracing/qcom/tgu.c
> index d4210869556e..5a8c6af9b719 100644
> --- a/drivers/hwtracing/qcom/tgu.c
> +++ b/drivers/hwtracing/qcom/tgu.c
> @@ -425,8 +425,82 @@ static ssize_t enable_tgu_store(struct device *dev,
>   }
>   static DEVICE_ATTR_RW(enable_tgu);
>   
> +/* reset_tgu_store - Reset Trace and Gating Unit (TGU) configuration. */
> +static ssize_t reset_tgu_store(struct device *dev,
> +			       struct device_attribute *attr, const char *buf,
> +			       size_t size)
> +{
> +	unsigned long value;
> +	struct tgu_drvdata *drvdata = dev_get_drvdata(dev);
> +	int i, j, ret;
> +
> +	if (kstrtoul(buf, 0, &value) || value == 0)
> +		return -EINVAL;
> +
> +	if (!drvdata->enable) {
> +		ret = pm_runtime_get_sync(drvdata->dev);
> +		if (ret < 0) {
> +			pm_runtime_put(drvdata->dev);
> +			return ret;
> +		}
> +	}
> +
> +	guard(spinlock)(&drvdata->lock);
> +	TGU_UNLOCK(drvdata->base);
> +
> +	writel(0, drvdata->base + TGU_CONTROL);

Better move TGU_LOCK(drvdata->base) here

Thanks,
Jie

> +
> +	if (drvdata->value_table->priority)
> +		memset(drvdata->value_table->priority, 0,
> +			    MAX_PRIORITY * drvdata->max_step *
> +				drvdata->max_reg * sizeof(unsigned int));
> +
> +	if (drvdata->value_table->condition_decode)
> +		memset(drvdata->value_table->condition_decode, 0,
> +			    drvdata->max_condition_decode * drvdata->max_step *
> +				sizeof(unsigned int));
> +
> +		/* Initialize all condition registers to NOT(value=0x1000000) */
> +	for (i = 0; i < drvdata->max_step; i++) {
> +		for (j = 0; j < drvdata->max_condition_decode; j++) {
> +			drvdata->value_table
> +			->condition_decode[calculate_array_location(
> +			drvdata, i, TGU_CONDITION_DECODE, j)] =
> +			0x1000000;
> +		}
> +	}
> +
> +	if (drvdata->value_table->condition_select)
> +		memset(drvdata->value_table->condition_select, 0,
> +				drvdata->max_condition_select * drvdata->max_step *
> +				sizeof(unsigned int));
> +
> +	if (drvdata->value_table->timer)
> +		memset(drvdata->value_table->timer, 0,
> +			    (drvdata->max_step) *
> +				(drvdata->max_timer) *
> +				sizeof(unsigned int));
> +
> +	if (drvdata->value_table->counter)
> +		memset(drvdata->value_table->counter, 0,
> +			    (drvdata->max_step) *
> +				(drvdata->max_counter) *
> +				sizeof(unsigned int));
> +
> +	dev_dbg(dev, "Coresight-TGU reset complete\n");
> +
> +	TGU_LOCK(drvdata->base);
> +
> +	drvdata->enable = false;
> +	pm_runtime_put(drvdata->dev);
> +
> +	return size;
> +}
> +static DEVICE_ATTR_WO(reset_tgu);
> +
>   static struct attribute *tgu_common_attrs[] = {
>   	&dev_attr_enable_tgu.attr,
> +	&dev_attr_reset_tgu.attr,
>   	NULL,
>   };
>   



From Kyrie.Wu at mediatek.com  Wed Dec 24 22:05:41 2025
From: Kyrie.Wu at mediatek.com (=?utf-8?B?S3lyaWUgV3UgKOWQtOaZlyk=?=)
Date: Thu, 25 Dec 2025 06:05:41 +0000
Subject: [PATCH v11 03/12] media: mediatek: jpeg: fix jpeg buffer layout
In-Reply-To: <89f845b45405bbf985a5e92c195078074bcce0e2.camel@ndufresne.ca>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
	 <20251202094800.6140-4-kyrie.wu@mediatek.com>
	 <89f845b45405bbf985a5e92c195078074bcce0e2.camel@ndufresne.ca>
Message-ID: <714f2e57521e990d77b80d23a9eb773ca878b07a.camel@mediatek.com>

On Tue, 2025-12-16 at 16:22 -0500, Nicolas Dufresne wrote:
> Hi,
> 
> Le mardi 02 d?cembre 2025 ? 17:47 +0800, Kyrie Wu a ?crit :
> > For memory alloc operation of jpeg dst buffer: the mallocing
> > memory function interface use vb2_buffer as the base addr.
> > If structure mtk_jpeg_src_buf wants to be allocated to memory,
> > it needs to be placed vb2_v4l2_buffer at the starting position,
> > because structure vb2_buffer is at the starting position of
> > vb2_v4l2_buffer, and the allocated size is set to the size of
> > structure mtk_jpeg_src_buf, so as to ensure that structures
> > mtk_jpeg_src_buf, vb2_v4l2_buffer and vb2_buffer can all be
> > allocated memory.
> 
> Please correct the wording, "mallocing" is not a word, addr ->
> address. I tend
> to do the same, but refrain from giving the code a personality, the
> vb2_buffer
> have no will. This is overall complicated way to simply say:
> 
> 	Fix the size of the allocated mtk_jpeg_src_buf structure.
> 
> > 
> > Fixes: 5fb1c2361e56 ("mtk-jpegenc: add jpeg encode worker
> > interface")
> > 
> 
> Drop the blank line.
> 
> > Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
> > ---
> >  drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c | 2 +-
> >  drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h | 2 +-
> >  2 files changed, 2 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > index 0cf3dc5407e4..bd0afc93d491 100644
> > --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > @@ -1099,7 +1099,7 @@ static int mtk_jpeg_queue_init(void *priv,
> > struct vb2_queue *src_vq,
> >  	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
> >  	dst_vq->io_modes = VB2_DMABUF | VB2_MMAP;
> >  	dst_vq->drv_priv = ctx;
> > -	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
> > +	dst_vq->buf_struct_size = sizeof(struct mtk_jpeg_src_buf);
> >  	dst_vq->ops = jpeg->variant->qops;
> >  	dst_vq->mem_ops = &vb2_dma_contig_memops;
> >  	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
> > diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> > b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> > index 6be5cf30dea1..148fd41759b7 100644
> > --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> > +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> > @@ -85,10 +85,10 @@ struct mtk_jpeg_variant {
> >  };
> >  
> >  struct mtk_jpeg_src_buf {
> > -	u32 frame_num;
> >  	struct vb2_v4l2_buffer b;
> >  	struct list_head list;
> >  	u32 bs_size;
> > +	u32 frame_num;
> 
> I like the change, but this shouldn't be an issue if you use
> container_of, which
> is safer then a plain cast. Please review the code and make sure to
> use it. It
> may be confusing to include a cosmetic change in a fixes.
> 
> Nicolas

Dear Nicolas,

The driver requests memory space for mtk_jpeg_src_buf in the
function of mtk_jpeg_queue_init,
and it used struct vb2_v4l2_buffer b as the starting base address,
the parameter,frame_num, will not get a memory if we keep the old
structure. And a unknown memory would be get if we used container_of
to get the starting address of mtk_jpeg_src_buf.

Thanks.

Regards,
Kyrie.
> 
> >  	struct mtk_jpeg_dec_param dec_param;
> >  
> >  	struct mtk_jpeg_ctx *curr_ctx;

From Kyrie.Wu at mediatek.com  Wed Dec 24 22:12:33 2025
From: Kyrie.Wu at mediatek.com (=?utf-8?B?S3lyaWUgV3UgKOWQtOaZlyk=?=)
Date: Thu, 25 Dec 2025 06:12:33 +0000
Subject: [PATCH v11 04/12] media: mediatek: jpeg: fix stop streaming flow
 for multi-core
In-Reply-To: <bf9d84ad6973d55f40bafdb9a70dc49178d4af10.camel@ndufresne.ca>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
	 <20251202094800.6140-5-kyrie.wu@mediatek.com>
	 <bf9d84ad6973d55f40bafdb9a70dc49178d4af10.camel@ndufresne.ca>
Message-ID: <f658e838b75be59d0976e76b2f364420a326ce38.camel@mediatek.com>

On Tue, 2025-12-16 at 16:27 -0500, Nicolas Dufresne wrote:
> Le mardi 02 d?cembre 2025 ? 17:47 +0800, Kyrie Wu a ?crit :
> > For jpeg multi-core architecture, if all hardware run at the
> > same time, some input and output buffers are occupied.
> > If one hardware is completed firstly, while other hardwares are
> 
> is compelted -> completes
> harwares -> core, matches mtk_jpeg_core.c file name
> 
> > still running. The decoding completion signal calls
> 
> decoding -> decode.
> 
> > mtk_jpeg_dec_stop_streaming, and the function of v4l2_m2m_buf_done
> > is called in mtk_jpeg_dec_stop_streaming to complete all
> > input/output buffers. However, some buffers are occupied by other
> > hardwares, resulting in errors. It needs to add a counter to
> > calculate the used decoding buffer counts, it will increase 1 when
> > the buffer set to hardware and decrease to 0 until the all buffers
> > decoded and the function could continue to be executed.
> 
> More things to fix, also same for other of your commits, please
> reflow between
> 70 and 75 as suggested in the guide. It should look even.

Thanks a lot. I will refine the commit message.
> 
> > 
> > Fixes: 0fa49df4222f ("media: mtk-jpegdec: support jpegdec multi-
> > hardware")
> > Fixes: dedc21500334 ("media: mtk-jpegdec: add jpeg decode worker
> > interface")
> > Fixes: 934e8bccac95 ("mtk-jpegenc: support jpegenc multi-hardware")
> > Fixes: 5fb1c2361e56 ("mtk-jpegenc: add jpeg encode worker
> > interface")
> > 
> > Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
> > ---
> >  .../media/platform/mediatek/jpeg/mtk_jpeg_core.c | 16
> > ++++++++++++++++
> >  .../media/platform/mediatek/jpeg/mtk_jpeg_core.h |  2 ++
> >  .../platform/mediatek/jpeg/mtk_jpeg_dec_hw.c     |  9 +++++++++
> >  .../platform/mediatek/jpeg/mtk_jpeg_enc_hw.c     |  9 +++++++++
> >  4 files changed, 36 insertions(+)
> > 
> > diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > index bd0afc93d491..59fd79c89f88 100644
> > --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > @@ -857,8 +857,12 @@ static struct vb2_v4l2_buffer
> > *mtk_jpeg_buf_remove(struct mtk_jpeg_ctx *ctx,
> >  static void mtk_jpeg_enc_stop_streaming(struct vb2_queue *q)
> >  {
> >  	struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(q);
> > +	struct mtk_jpeg_dev *jpeg = ctx->jpeg;
> >  	struct vb2_v4l2_buffer *vb;
> >  
> > +	if (jpeg->variant->multi_core)
> > +		wait_event(jpeg->hw_wq, (atomic_read(&ctx-
> > >buf_list_cnt) == 0));
> > +
> 
> Can't it simply be solved with vb2_wait_for_all_buffers() ?
> 
> Nicolas

Dear Nicolas,

Thanks for your suggestion. I think it better than mine.
I will change to use it.

Regards,
Kyrie.
> 
> >  	while ((vb = mtk_jpeg_buf_remove(ctx, q->type)))
> >  		v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR);
> >  }
> > @@ -866,6 +870,7 @@ static void mtk_jpeg_enc_stop_streaming(struct
> > vb2_queue *q)
> >  static void mtk_jpeg_dec_stop_streaming(struct vb2_queue *q)
> >  {
> >  	struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(q);
> > +	struct mtk_jpeg_dev *jpeg = ctx->jpeg;
> >  	struct vb2_v4l2_buffer *vb;
> >  
> >  	/*
> > @@ -873,6 +878,9 @@ static void mtk_jpeg_dec_stop_streaming(struct
> > vb2_queue *q)
> >  	 * Before STREAMOFF, we still have to return the old resolution
> > and
> >  	 * subsampling. Update capture queue when the stream is off.
> >  	 */
> > +	if (jpeg->variant->multi_core)
> > +		wait_event(jpeg->hw_wq, (atomic_read(&ctx-
> > >buf_list_cnt) == 0));
> > +
> >  	if (ctx->state == MTK_JPEG_SOURCE_CHANGE &&
> >  	    V4L2_TYPE_IS_CAPTURE(q->type)) {
> >  		struct mtk_jpeg_src_buf *src_buf;
> > @@ -1181,6 +1189,7 @@ static int mtk_jpeg_open(struct file *file)
> >  	spin_lock_init(&ctx->done_queue_lock);
> >  	v4l2_fh_init(&ctx->fh, vfd);
> >  	v4l2_fh_add(&ctx->fh, file);
> > +	atomic_set(&ctx->buf_list_cnt, 0);
> >  
> >  	ctx->jpeg = jpeg;
> >  	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx,
> > @@ -1563,6 +1572,11 @@ static int mtk_jpegdec_set_hw_param(struct
> > mtk_jpeg_ctx *ctx,
> >  	return 0;
> >  }
> >  
> > +static void jpeg_buf_queue_inc(struct mtk_jpeg_ctx *ctx)
> > +{
> > +	atomic_inc(&ctx->buf_list_cnt);
> > +}
> > +
> >  static irqreturn_t mtk_jpeg_enc_done(struct mtk_jpeg_dev *jpeg)
> >  {
> >  	struct mtk_jpeg_ctx *ctx;
> > @@ -1671,6 +1685,7 @@ static void mtk_jpegenc_worker(struct
> > work_struct *work)
> >  			     &src_buf->vb2_buf);
> >  	mtk_jpeg_set_enc_params(ctx, comp_jpeg[hw_id]->reg_base);
> >  	mtk_jpeg_enc_start(comp_jpeg[hw_id]->reg_base);
> > +	jpeg_buf_queue_inc(ctx);
> >  	v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
> >  	spin_unlock_irqrestore(&comp_jpeg[hw_id]->hw_lock, flags);
> >  
> > @@ -1786,6 +1801,7 @@ static void mtk_jpegdec_worker(struct
> > work_struct *work)
> >  				&bs,
> >  				&fb);
> >  	mtk_jpeg_dec_start(comp_jpeg[hw_id]->reg_base);
> > +	jpeg_buf_queue_inc(ctx);
> >  	v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
> >  	spin_unlock_irqrestore(&comp_jpeg[hw_id]->hw_lock, flags);
> >  
> > diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> > b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> > index 148fd41759b7..33f7fbc4ca5e 100644
> > --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> > +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> > @@ -288,6 +288,7 @@ struct mtk_jpeg_q_data {
> >   * @dst_done_queue:		encoded frame buffer queue
> >   * @done_queue_lock:		encoded frame operation
> > spinlock
> >   * @last_done_frame_num:	the last encoded frame number
> > + * @buf_list_cnt:		the frame buffer count own by jpeg
> > driver
> >   */
> >  struct mtk_jpeg_ctx {
> >  	struct mtk_jpeg_dev		*jpeg;
> > @@ -306,6 +307,7 @@ struct mtk_jpeg_ctx {
> >  	/* spinlock protecting the encode done buffer */
> >  	spinlock_t done_queue_lock;
> >  	u32 last_done_frame_num;
> > +	atomic_t buf_list_cnt;
> >  };
> >  
> >  #endif /* _MTK_JPEG_CORE_H */
> > diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> > b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> > index a1e54715cb7e..84d12eea35f7 100644
> > --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> > +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> > @@ -519,6 +519,11 @@ static void mtk_jpegdec_put_buf(struct
> > mtk_jpegdec_comp_dev *jpeg)
> >  	spin_unlock_irqrestore(&ctx->done_queue_lock, flags);
> >  }
> >  
> > +static void jpeg_buf_queue_dec(struct mtk_jpeg_ctx *ctx)
> > +{
> > +	atomic_dec(&ctx->buf_list_cnt);
> > +}
> > +
> >  static void mtk_jpegdec_timeout_work(struct work_struct *work)
> >  {
> >  	enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR;
> > @@ -527,9 +532,11 @@ static void mtk_jpegdec_timeout_work(struct
> > work_struct *work)
> >  			     job_timeout_work.work);
> >  	struct mtk_jpeg_dev *master_jpeg = cjpeg->master_dev;
> >  	struct vb2_v4l2_buffer *src_buf, *dst_buf;
> > +	struct mtk_jpeg_ctx *ctx;
> >  
> >  	src_buf = cjpeg->hw_param.src_buffer;
> >  	dst_buf = cjpeg->hw_param.dst_buffer;
> > +	ctx = cjpeg->hw_param.curr_ctx;
> >  	v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
> >  
> >  	mtk_jpeg_dec_reset(cjpeg->reg_base);
> > @@ -540,6 +547,7 @@ static void mtk_jpegdec_timeout_work(struct
> > work_struct *work)
> >  	wake_up(&master_jpeg->hw_wq);
> >  	v4l2_m2m_buf_done(src_buf, buf_state);
> >  	mtk_jpegdec_put_buf(cjpeg);
> > +	jpeg_buf_queue_dec(ctx);
> >  }
> >  
> >  static irqreturn_t mtk_jpegdec_hw_irq_handler(int irq, void *priv)
> > @@ -580,6 +588,7 @@ static irqreturn_t
> > mtk_jpegdec_hw_irq_handler(int irq, void *priv)
> >  	buf_state = VB2_BUF_STATE_DONE;
> >  	v4l2_m2m_buf_done(src_buf, buf_state);
> >  	mtk_jpegdec_put_buf(jpeg);
> > +	jpeg_buf_queue_dec(ctx);
> >  	pm_runtime_put(ctx->jpeg->dev);
> >  	clk_disable_unprepare(jpeg->jdec_clk.clks->clk);
> >  
> > diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> > b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> > index 28d05909c96f..1862444f35f5 100644
> > --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> > +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> > @@ -248,6 +248,11 @@ static void mtk_jpegenc_put_buf(struct
> > mtk_jpegenc_comp_dev *jpeg)
> >  	spin_unlock_irqrestore(&ctx->done_queue_lock, flags);
> >  }
> >  
> > +static void jpeg_buf_queue_enc(struct mtk_jpeg_ctx *ctx)
> > +{
> > +	atomic_dec(&ctx->buf_list_cnt);
> > +}
> > +
> >  static void mtk_jpegenc_timeout_work(struct work_struct *work)
> >  {
> >  	struct delayed_work *dly_work = to_delayed_work(work);
> > @@ -258,9 +263,11 @@ static void mtk_jpegenc_timeout_work(struct
> > work_struct *work)
> >  	struct mtk_jpeg_dev *master_jpeg = cjpeg->master_dev;
> >  	enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR;
> >  	struct vb2_v4l2_buffer *src_buf, *dst_buf;
> > +	struct mtk_jpeg_ctx *ctx;
> >  
> >  	src_buf = cjpeg->hw_param.src_buffer;
> >  	dst_buf = cjpeg->hw_param.dst_buffer;
> > +	ctx = cjpeg->hw_param.curr_ctx;
> >  	v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
> >  
> >  	mtk_jpeg_enc_reset(cjpeg->reg_base);
> > @@ -271,6 +278,7 @@ static void mtk_jpegenc_timeout_work(struct
> > work_struct *work)
> >  	wake_up(&master_jpeg->hw_wq);
> >  	v4l2_m2m_buf_done(src_buf, buf_state);
> >  	mtk_jpegenc_put_buf(cjpeg);
> > +	jpeg_buf_queue_enc(ctx);
> >  }
> >  
> >  static irqreturn_t mtk_jpegenc_hw_irq_handler(int irq, void *priv)
> > @@ -304,6 +312,7 @@ static irqreturn_t
> > mtk_jpegenc_hw_irq_handler(int irq, void *priv)
> >  	buf_state = VB2_BUF_STATE_DONE;
> >  	v4l2_m2m_buf_done(src_buf, buf_state);
> >  	mtk_jpegenc_put_buf(jpeg);
> > +	jpeg_buf_queue_enc(ctx);
> >  	pm_runtime_put(ctx->jpeg->dev);
> >  	clk_disable_unprepare(jpeg->venc_clk.clks->clk);
> >  
> 
> 	Could not parse S/MIME message: security library: improperly
> formatted DER-encoded message. (-8183) - Decoder failed

From lkp at intel.com  Wed Dec 24 22:26:22 2025
From: lkp at intel.com (kernel test robot)
Date: Thu, 25 Dec 2025 14:26:22 +0800
Subject: [PATCH v3 09/21] drm/colorop: Factor out common paths from
 colorops helpers
In-Reply-To: <20251223-mtk-post-blend-color-pipeline-v3-9-7d969f9a37a0@collabora.com>
References: <20251223-mtk-post-blend-color-pipeline-v3-9-7d969f9a37a0@collabora.com>
Message-ID: <202512251442.dLlbaNp3-lkp@intel.com>

Hi Ariel,

kernel test robot noticed the following build warnings:

[auto build test WARNING on b96bcfba104c65db41378a04f5ccac186f79578f]

url:    https://github.com/intel-lab-lkp/linux/commits/Ariel-D-Alessandro/drm-crtc-Add-color-pipeline-to-CRTC-state/20251224-020551
base:   b96bcfba104c65db41378a04f5ccac186f79578f
patch link:    https://lore.kernel.org/r/20251223-mtk-post-blend-color-pipeline-v3-9-7d969f9a37a0%40collabora.com
patch subject: [PATCH v3 09/21] drm/colorop: Factor out common paths from colorops helpers
config: openrisc-randconfig-r073-20251225 (https://download.01.org/0day-ci/archive/20251225/202512251442.dLlbaNp3-lkp at intel.com/config)
compiler: or1k-linux-gcc (GCC) 12.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251225/202512251442.dLlbaNp3-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512251442.dLlbaNp3-lkp at intel.com/

All warnings (new ones prefixed by >>):

>> Warning: drivers/gpu/drm/drm_colorop.c:227 expecting prototype for drm_plane_colorop_curve_1d_init(). Prototype was for drm_common_colorop_curve_1d_init() instead

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From dapeng1.mi at linux.intel.com  Wed Dec 24 22:26:56 2025
From: dapeng1.mi at linux.intel.com (Mi, Dapeng)
Date: Thu, 25 Dec 2025 14:26:56 +0800
Subject: [PATCH v6 15/44] KVM: x86/pmu: Snapshot host (i.e. perf's)
 reported PMU capabilities
In-Reply-To: <20251206001720.468579-16-seanjc@google.com>
References: <20251206001720.468579-1-seanjc@google.com>
 <20251206001720.468579-16-seanjc@google.com>
Message-ID: <43d1cde6-2277-4f3c-8e7d-59e6edb2228a@linux.intel.com>


On 12/6/2025 8:16 AM, Sean Christopherson wrote:
> Take a snapshot of the unadulterated PMU capabilities provided by perf so
> that KVM can compare guest vPMU capabilities against hardware capabilities
> when determining whether or not to intercept PMU MSRs (and RDPMC).
>
> Reviewed-by: Sandipan Das <sandipan.das at amd.com>
> Tested-by: Xudong Hao <xudong.hao at intel.com>
> Signed-off-by: Sean Christopherson <seanjc at google.com>
> ---
>  arch/x86/kvm/pmu.c | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
> index 487ad19a236e..7c219305b61d 100644
> --- a/arch/x86/kvm/pmu.c
> +++ b/arch/x86/kvm/pmu.c
> @@ -108,6 +108,8 @@ void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops)
>  	bool is_intel = boot_cpu_data.x86_vendor == X86_VENDOR_INTEL;
>  	int min_nr_gp_ctrs = pmu_ops->MIN_NR_GP_COUNTERS;
>  
> +	perf_get_x86_pmu_capability(&kvm_host_pmu);
> +
>  	/*
>  	 * Hybrid PMUs don't play nice with virtualization without careful
>  	 * configuration by userspace, and KVM's APIs for reporting supported

Hi Sean,

It looks a merging error here. We don't need this patch.

The original patch "51f34b1 ("KVM: x86/pmu: Snapshot host (i.e. perf's)
reported PMU capabilities")" had been merged into upstream and subsequently
we submitted a new patch "034417c1439a ("KVM: x86/pmu: Don't try to get
perf capabilities for hybrid CPUs")" to fix the warning introduced from
previous patch? "51f34b1 ("KVM: x86/pmu: Snapshot host (i.e. perf's)
reported PMU capabilities")". Thanks.

-Dapeng Mi




From jie.gan at oss.qualcomm.com  Wed Dec 24 22:28:38 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Thu, 25 Dec 2025 14:28:38 +0800
Subject: [PATCH v9 1/7] dt-bindings: arm: Add support for Qualcomm TGU
 trace
In-Reply-To: <20251219065902.2296896-2-songwei.chai@oss.qualcomm.com>
References: <20251219065902.2296896-1-songwei.chai@oss.qualcomm.com>
 <20251219065902.2296896-2-songwei.chai@oss.qualcomm.com>
Message-ID: <ab7d3026-4172-4f8c-942e-e46d984d5f21@oss.qualcomm.com>



On 12/19/2025 2:58 PM, Songwei Chai wrote:
> The Trigger Generation Unit (TGU) is designed to detect patterns or
> sequences within a specific region of the System on Chip (SoC). Once
> configured and activated, it monitors sense inputs and can detect a
> pre-programmed state or sequence across clock cycles, subsequently
> producing a trigger.
> 
>     TGU configuration space
>          offset table
>   x-------------------------x
>   |                         |
>   |                         |
>   |                         |                           Step configuration
>   |                         |                             space layout
>   |   coresight management  |                           x-------------x
>   |        registers        |                     |---> |             |
>   |                         |                     |     |  reserve    |
>   |                         |                     |     |             |
>   |-------------------------|                     |     |-------------|
>   |                         |                     |     | priority[3] |
>   |         step[7]         |<--                  |     |-------------|
>   |-------------------------|   |                 |     | priority[2] |
>   |                         |   |                 |     |-------------|
>   |           ...           |   |Steps region     |     | priority[1] |
>   |                         |   |                 |     |-------------|
>   |-------------------------|   |                 |     | priority[0] |
>   |                         |<--                  |     |-------------|
>   |         step[0]         |-------------------->      |             |
>   |-------------------------|                           |  condition  |
>   |                         |                           |             |
>   |     control and status  |                           x-------------x
>   |           space         |                           |             |
>   x-------------------------x                           |Timer/Counter|
>                                                         |             |
> 						       x-------------x
> TGU Configuration in Hardware
> 
> The TGU provides a step region for user configuration, similar
> to a flow chart. Each step region consists of three register clusters:
> 
> 1.Priority Region: Sets the required signals with priority.
> 2.Condition Region: Defines specific requirements (e.g., signal A
> reaches three times) and the subsequent action once the requirement is
> met.
> 3.Timer/Counter (Optional): Provides timing or counting functionality.
> 
> Add a new tgu.yaml file to describe the bindings required to
> define the TGU in the device trees.
> 
> Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
> Signed-off-by: Songwei Chai <songwei.chai at oss.qualcomm.com>
> ---
>   .../devicetree/bindings/arm/qcom,tgu.yaml     | 92 +++++++++++++++++++
>   1 file changed, 92 insertions(+)
>   create mode 100644 Documentation/devicetree/bindings/arm/qcom,tgu.yaml
> 
> diff --git a/Documentation/devicetree/bindings/arm/qcom,tgu.yaml b/Documentation/devicetree/bindings/arm/qcom,tgu.yaml
> new file mode 100644
> index 000000000000..5b6a58ebe691
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/arm/qcom,tgu.yaml
> @@ -0,0 +1,92 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> +# Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/arm/qcom,tgu.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Trigger Generation Unit - TGU
> +
> +description: |
> +  The Trigger Generation Unit (TGU) is a Data Engine which can be utilized
> +  to sense a plurality of signals and create a trigger into the CTI or
> +  generate interrupts to processors. The TGU is like the trigger circuit
> +  of a Logic Analyzer. The corresponding trigger logic can be realized by
> +  configuring the conditions for each step after sensing the signal.
> +  Once setup and enabled, it will observe sense inputs and based upon
> +  the activity of those inputs, even over clock cycles, may detect a
> +  preprogrammed state/sequence and then produce a trigger or interrupt.
> +
> +  The primary use case of the TGU is to detect patterns or sequences on a
> +  given set of signals within some region to identify the issue in time
> +  once there is abnormal behavior in the subsystem.
> +
> +maintainers:
> +  - Mao Jinlong <jinlong.mao at oss.qualcomm.com>
> +  - Songwei Chai <songwei.chai at oss.qualcomm.com>
> +
> +# Need a custom select here or 'arm,primecell' will match on lots of nodes
> +select:
> +  properties:
> +    compatible:
> +      contains:
> +        enum:
> +          - qcom,tgu
> +  required:
> +    - compatible
> +
> +properties:
> +  compatible:
> +    items:
> +      - const: qcom,tgu
> +      - const: arm,primecell
> +
> +  reg:
> +    maxItems: 1
> +
> +  clocks:
> +    maxItems: 1
> +
> +  clock-names:
> +    items:
> +      - const: apb_pclk
> +
> +  in-ports:
> +    $ref: /schemas/graph.yaml#/properties/ports
> +    additionalProperties: false
> +
> +    properties:
> +      port:
> +        description:
> +          The port mechanism here ensures the relationship between TGU and
> +          TPDM, as TPDM is one of the inputs for TGU. It will allow TGU to
> +          function as TPDM's helper and enable TGU when the connected
> +          TPDM is enabled.
> +        $ref: /schemas/graph.yaml#/properties/port
> +
> +required:
> +  - compatible
> +  - reg
> +  - clocks
> +  - clock-names
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    tgu at 10b0e000 {
> +        compatible = "qcom,tgu", "arm,primecell";
> +        reg = <0x10b0e000 0x1000>;
> +
> +        clocks = <&aoss_qmp>;
> +        clock-names = "apb_pclk";
> +
> +        in-ports {
> +            port {
> +                tgu_in_tpdm_swao: endpoint{
> +                    remote-endpoint = <&tpdm_swao_out_tgu>;
> +                };
> +            };
> +        };

In Coresight driver, the helper device is enabled via enable_path, but 
for TGU, it's enabling via sysfs node manually, so why do we need 
connect the tgu with TPDM device? I didnt see the connection with 
Coresight Core framework.

Thanks,
Jie

> +    };
> +...



From Kyrie.Wu at mediatek.com  Wed Dec 24 22:35:29 2025
From: Kyrie.Wu at mediatek.com (=?utf-8?B?S3lyaWUgV3UgKOWQtOaZlyk=?=)
Date: Thu, 25 Dec 2025 06:35:29 +0000
Subject: [PATCH v11 05/12] media: mediatek: jpeg: fix multi-core clk
 suspend and resume setting
In-Reply-To: <8f985a1b2add6fbcba354a0a3d330447380a6ccb.camel@ndufresne.ca>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
	 <20251202094800.6140-6-kyrie.wu@mediatek.com>
	 <8f985a1b2add6fbcba354a0a3d330447380a6ccb.camel@ndufresne.ca>
Message-ID: <b52510632cff438751a9ef57ea6a6f184712de14.camel@mediatek.com>

On Tue, 2025-12-16 at 16:33 -0500, Nicolas Dufresne wrote:
> Hi,
> 
> Le mardi 02 d?cembre 2025 ? 17:47 +0800, Kyrie Wu a ?crit :
> > The suspend/resume callback function is defined in the dev_pm_ops
> > structure, which is defined in platform_driver. For multiple-core
> > architecture, each hardware driver will register a platform_driver
> > structure, so it is necessary to add a suspend/resume callback
> > function for each hardware to support this operation.
> > 
> > Fixes: 934e8bccac95 ("mtk-jpegenc: support jpegenc multi-hardware")
> > Fixes: 0fa49df4222f ("media: mtk-jpegdec: support jpegdec multi-
> > hardware")
> > 
> > Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
> > ---
> >  .../platform/mediatek/jpeg/mtk_jpeg_core.c    | 28 +++----
> >  .../platform/mediatek/jpeg/mtk_jpeg_dec_hw.c  | 75
> > ++++++++++++++++++-
> >  .../platform/mediatek/jpeg/mtk_jpeg_enc_hw.c  | 75
> > ++++++++++++++++++-
> >  3 files changed, 151 insertions(+), 27 deletions(-)
> > 
> > diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > index 59fd79c89f88..e45d7e82b8a0 100644
> > --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > @@ -1122,6 +1122,9 @@ static void mtk_jpeg_clk_on(struct
> > mtk_jpeg_dev *jpeg)
> >  {
> >  	int ret;
> >  
> > +	if (jpeg->variant->multi_core)
> > +		return;
> > +
> >  	ret = clk_bulk_prepare_enable(jpeg->variant->num_clks,
> >  				      jpeg->variant->clks);
> >  	if (ret)
> > @@ -1130,6 +1133,9 @@ static void mtk_jpeg_clk_on(struct
> > mtk_jpeg_dev *jpeg)
> >  
> >  static void mtk_jpeg_clk_off(struct mtk_jpeg_dev *jpeg)
> >  {
> > +	if (jpeg->variant->multi_core)
> > +		return;
> > +
> >  	clk_bulk_disable_unprepare(jpeg->variant->num_clks,
> >  				   jpeg->variant->clks);
> >  }
> > @@ -1658,13 +1664,6 @@ static void mtk_jpegenc_worker(struct
> > work_struct
> > *work)
> >  		goto enc_end;
> >  	}
> >  
> > -	ret = clk_prepare_enable(comp_jpeg[hw_id]->venc_clk.clks->clk);
> > -	if (ret) {
> > -		dev_err(jpeg->dev, "%s : %d, jpegenc clk_prepare_enable
> > fail\n",
> > -			__func__, __LINE__);
> > -		goto enc_end;
> > -	}
> > -
> >  	v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> >  	v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> >  
> > @@ -1762,20 +1761,13 @@ static void mtk_jpegdec_worker(struct
> > work_struct
> > *work)
> >  	jpeg_dst_buf->frame_num = ctx->total_frame_num;
> >  
> >  	mtk_jpegdec_set_hw_param(ctx, hw_id, src_buf, dst_buf);
> > -	ret = pm_runtime_get_sync(comp_jpeg[hw_id]->dev);
> > +	ret = pm_runtime_resume_and_get(comp_jpeg[hw_id]->dev);
> >  	if (ret < 0) {
> >  		dev_err(jpeg->dev, "%s : %d, pm_runtime_get_sync fail
> > !!!\n",
> >  			__func__, __LINE__);
> >  		goto dec_end;
> >  	}
> >  
> > -	ret = clk_prepare_enable(comp_jpeg[hw_id]->jdec_clk.clks->clk);
> > -	if (ret) {
> > -		dev_err(jpeg->dev, "%s : %d, jpegdec clk_prepare_enable
> > fail\n",
> > -			__func__, __LINE__);
> > -		goto clk_end;
> > -	}
> > -
> >  	v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> >  	v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> >  
> > @@ -1785,7 +1777,7 @@ static void mtk_jpegdec_worker(struct
> > work_struct *work)
> >  				 &dst_buf->vb2_buf, &fb)) {
> >  		dev_err(jpeg->dev, "%s : %d, mtk_jpeg_set_dec_dst
> > fail\n",
> >  			__func__, __LINE__);
> > -		goto setdst_end;
> > +		goto set_dst_fail;
> >  	}
> >  
> >  	schedule_delayed_work(&comp_jpeg[hw_id]->job_timeout_work,
> > @@ -1807,9 +1799,7 @@ static void mtk_jpegdec_worker(struct
> > work_struct *work)
> >  
> >  	return;
> >  
> > -setdst_end:
> > -	clk_disable_unprepare(comp_jpeg[hw_id]->jdec_clk.clks->clk);
> > -clk_end:
> > +set_dst_fail:
> >  	pm_runtime_put(comp_jpeg[hw_id]->dev);
> >  dec_end:
> >  	v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> > diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> > b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> > index 84d12eea35f7..5f1557dafad6 100644
> > --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> > +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> > @@ -540,14 +540,13 @@ static void mtk_jpegdec_timeout_work(struct
> > work_struct
> > *work)
> >  	v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
> >  
> >  	mtk_jpeg_dec_reset(cjpeg->reg_base);
> > -	clk_disable_unprepare(cjpeg->jdec_clk.clks->clk);
> > -	pm_runtime_put(cjpeg->dev);
> >  	cjpeg->hw_state = MTK_JPEG_HW_IDLE;
> >  	atomic_inc(&master_jpeg->hw_rdy);
> >  	wake_up(&master_jpeg->hw_wq);
> >  	v4l2_m2m_buf_done(src_buf, buf_state);
> >  	mtk_jpegdec_put_buf(cjpeg);
> >  	jpeg_buf_queue_dec(ctx);
> > +	pm_runtime_put(cjpeg->dev);
> >  }
> >  
> >  static irqreturn_t mtk_jpegdec_hw_irq_handler(int irq, void *priv)
> > @@ -589,12 +588,11 @@ static irqreturn_t
> > mtk_jpegdec_hw_irq_handler(int irq,
> > void *priv)
> >  	v4l2_m2m_buf_done(src_buf, buf_state);
> >  	mtk_jpegdec_put_buf(jpeg);
> >  	jpeg_buf_queue_dec(ctx);
> > -	pm_runtime_put(ctx->jpeg->dev);
> > -	clk_disable_unprepare(jpeg->jdec_clk.clks->clk);
> >  
> >  	jpeg->hw_state = MTK_JPEG_HW_IDLE;
> >  	wake_up(&master_jpeg->hw_wq);
> >  	atomic_inc(&master_jpeg->hw_rdy);
> > +	pm_runtime_put(jpeg->dev);
> >  
> >  	return IRQ_HANDLED;
> >  }
> > @@ -677,15 +675,84 @@ static int mtk_jpegdec_hw_probe(struct
> > platform_device
> > *pdev)
> >  
> >  	platform_set_drvdata(pdev, dev);
> >  	pm_runtime_enable(&pdev->dev);
> > +	ret = devm_clk_bulk_get(dev->dev,
> > +				jpegdec_clk->clk_num,
> > +				jpegdec_clk->clks);
> > +	if (ret) {
> > +		dev_err(&pdev->dev, "Failed to init clk\n");
> > +		return ret;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static void mtk_jpeg_clk_on(struct mtk_jpegdec_comp_dev *jpeg)
> > +{
> > +	int ret;
> > +
> > +	ret = clk_bulk_prepare_enable(jpeg->jdec_clk.clk_num,
> > +				      jpeg->jdec_clk.clks);
> > +	if (ret)
> > +		dev_err(jpeg->dev, "%s : %d, jpegdec clk_prepare_enable
> > fail\n",
> > +			__func__, __LINE__);
> > +}
> > +
> > +static void mtk_jpeg_clk_off(struct mtk_jpegdec_comp_dev *jpeg)
> > +{
> > +	clk_bulk_disable_unprepare(jpeg->jdec_clk.clk_num,
> > +				   jpeg->jdec_clk.clks);
> > +}
> > +
> > +static __maybe_unused int mtk_jpegdec_pm_suspend(struct device
> > *dev)
> 
> Its used its passed to mtk_jpegdec_pm_ops structure. Same below.
> Unless you had
> the intention to ifdef that structure and you forgot.
Thanks.
I will change to return clk_bulk_disable_unprepare(jpeg-
>jdec_clk.clk_num, jpeg->jdec_clk.clks);
> 
> > +{
> > +	struct mtk_jpegdec_comp_dev *jpeg = dev_get_drvdata(dev);
> > +
> > +	mtk_jpeg_clk_off(jpeg);
> >  
> >  	return 0;
> >  }
> >  
> > +static __maybe_unused int mtk_jpegdec_pm_resume(struct device
> > *dev)
> > +{
> > +	struct mtk_jpegdec_comp_dev *jpeg = dev_get_drvdata(dev);
> > +
> > +	mtk_jpeg_clk_on(jpeg);
> > +
> > +	return 0;
> > +}
> > +
> > +static __maybe_unused int mtk_jpegdec_suspend(struct device *dev)
> > +{
> > +	struct mtk_jpegdec_comp_dev *jpeg = dev_get_drvdata(dev);
> > +
> > +	v4l2_m2m_suspend(jpeg->master_dev->m2m_dev);
> > +	return pm_runtime_force_suspend(dev);
> > +}
> > +
> > +static __maybe_unused int mtk_jpegdec_resume(struct device *dev)
> > +{
> > +	struct mtk_jpegdec_comp_dev *jpeg = dev_get_drvdata(dev);
> > +	int ret;
> > +
> > +	ret = pm_runtime_force_resume(dev);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	v4l2_m2m_resume(jpeg->master_dev->m2m_dev);
> > +	return ret;
> > +}
> > +
> > +static const struct dev_pm_ops mtk_jpegdec_pm_ops = {
> > +	SET_SYSTEM_SLEEP_PM_OPS(mtk_jpegdec_suspend,
> > mtk_jpegdec_resume)
> > +	SET_RUNTIME_PM_OPS(mtk_jpegdec_pm_suspend,
> > mtk_jpegdec_pm_resume,
> > NULL)
> > +};
> > +
> >  static struct platform_driver mtk_jpegdec_hw_driver = {
> >  	.probe = mtk_jpegdec_hw_probe,
> >  	.driver = {
> >  		.name = "mtk-jpegdec-hw",
> >  		.of_match_table = mtk_jpegdec_hw_ids,
> > +		.pm             = &mtk_jpegdec_pm_ops,
> >  	},
> >  };
> >  
> > diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> > b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> > index 1862444f35f5..785db5ba4770 100644
> > --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> > +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> > @@ -271,14 +271,13 @@ static void mtk_jpegenc_timeout_work(struct
> > work_struct
> > *work)
> >  	v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
> >  
> >  	mtk_jpeg_enc_reset(cjpeg->reg_base);
> > -	clk_disable_unprepare(cjpeg->venc_clk.clks->clk);
> > -	pm_runtime_put(cjpeg->dev);
> >  	cjpeg->hw_state = MTK_JPEG_HW_IDLE;
> >  	atomic_inc(&master_jpeg->hw_rdy);
> >  	wake_up(&master_jpeg->hw_wq);
> >  	v4l2_m2m_buf_done(src_buf, buf_state);
> >  	mtk_jpegenc_put_buf(cjpeg);
> >  	jpeg_buf_queue_enc(ctx);
> > +	pm_runtime_put(cjpeg->dev);
> >  }
> >  
> >  static irqreturn_t mtk_jpegenc_hw_irq_handler(int irq, void *priv)
> > @@ -313,12 +312,11 @@ static irqreturn_t
> > mtk_jpegenc_hw_irq_handler(int irq,
> > void *priv)
> >  	v4l2_m2m_buf_done(src_buf, buf_state);
> >  	mtk_jpegenc_put_buf(jpeg);
> >  	jpeg_buf_queue_enc(ctx);
> > -	pm_runtime_put(ctx->jpeg->dev);
> > -	clk_disable_unprepare(jpeg->venc_clk.clks->clk);
> >  
> >  	jpeg->hw_state = MTK_JPEG_HW_IDLE;
> >  	wake_up(&master_jpeg->hw_wq);
> >  	atomic_inc(&master_jpeg->hw_rdy);
> > +	pm_runtime_put(jpeg->dev);
> >  
> >  	return IRQ_HANDLED;
> >  }
> > @@ -399,15 +397,84 @@ static int mtk_jpegenc_hw_probe(struct
> > platform_device
> > *pdev)
> >  
> >  	platform_set_drvdata(pdev, dev);
> >  	pm_runtime_enable(&pdev->dev);
> > +	ret = devm_clk_bulk_get(dev->dev,
> > +				jpegenc_clk->clk_num,
> > +				jpegenc_clk->clks);
> > +	if (ret) {
> > +		dev_err(&pdev->dev, "Failed to init clk\n");
> > +		return ret;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static void mtk_jpeg_clk_on(struct mtk_jpegenc_comp_dev *jpeg)
> > +{
> > +	int ret;
> > +
> > +	ret = clk_bulk_prepare_enable(jpeg->venc_clk.clk_num,
> > +				      jpeg->venc_clk.clks);
> > +	if (ret)
> > +		dev_err(jpeg->dev, "%s : %d, jpegenc clk_prepare_enable
> > fail\n",
> > +			__func__, __LINE__);
> > +}
> > +
> > +static void mtk_jpeg_clk_off(struct mtk_jpegenc_comp_dev *jpeg)
> > +{
> > +	clk_bulk_disable_unprepare(jpeg->venc_clk.clk_num,
> > +				   jpeg->venc_clk.clks);
> > +}
> > +
> > +static __maybe_unused int mtk_jpegenc_pm_suspend(struct device
> > *dev)
> > +{
> > +	struct mtk_jpegenc_comp_dev *jpeg = dev_get_drvdata(dev);
> > +
> > +	mtk_jpeg_clk_off(jpeg);
> 
> This is the only call to that function, move the code here.

Thanks, I will change it.
> 
> >  
> >  	return 0;
> >  }
> >  
> > +static __maybe_unused int mtk_jpegenc_pm_resume(struct device
> > *dev)
> > +{
> > +	struct mtk_jpegenc_comp_dev *jpeg = dev_get_drvdata(dev);
> > +
> > +	mtk_jpeg_clk_on(jpeg);
> 
> This is the only call to that function, move the code here. Decides
> if the ret
> value should be passed or not too, add a comment if not.
> 
> Its worrying not too, since usually if the clock are not running, we
> risk
> hanging the CPU writing to registers.

Dear Nicolas,

Thanks for your kind suggestion. I also think the return value should
be handled. I will change it in the next version.

Regards,
Kyrie.
> 
> > +
> > +	return 0;
> > +}
> > +
> > +static __maybe_unused int mtk_jpegenc_suspend(struct device *dev)
> > +{
> > +	struct mtk_jpegenc_comp_dev *jpeg = dev_get_drvdata(dev);
> > +
> > +	v4l2_m2m_suspend(jpeg->master_dev->m2m_dev);
> > +	return pm_runtime_force_suspend(dev);
> > +}
> > +
> > +static __maybe_unused int mtk_jpegenc_resume(struct device *dev)
> > +{
> > +	struct mtk_jpegenc_comp_dev *jpeg = dev_get_drvdata(dev);
> > +	int ret;
> > +
> > +	ret = pm_runtime_force_resume(dev);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	v4l2_m2m_resume(jpeg->master_dev->m2m_dev);
> > +	return ret;
> > +}
> > +
> > +static const struct dev_pm_ops mtk_jpegenc_pm_ops = {
> > +	SET_SYSTEM_SLEEP_PM_OPS(mtk_jpegenc_suspend,
> > mtk_jpegenc_resume)
> > +	SET_RUNTIME_PM_OPS(mtk_jpegenc_pm_suspend,
> > mtk_jpegenc_pm_resume,
> > NULL)
> > +};
> > +
> >  static struct platform_driver mtk_jpegenc_hw_driver = {
> >  	.probe = mtk_jpegenc_hw_probe,
> >  	.driver = {
> >  		.name = "mtk-jpegenc-hw",
> >  		.of_match_table = mtk_jpegenc_drv_ids,
> > +		.pm = &mtk_jpegenc_pm_ops,
> >  	},
> >  };
> >  
> 
> Looks like the right way though,looking forward an update.
> 
> Nicolas
> 	Could not parse S/MIME message: security library: improperly
> formatted DER-encoded message. (-8183) - Decoder failed

From ye.zhang at rock-chips.com  Wed Dec 24 22:44:41 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Thu, 25 Dec 2025 14:44:41 +0800
Subject: [PATCH v3 6/7] dt-bindings: pinctrl: rockchip: Add RMIO
 controller binding
In-Reply-To: <5154ca76-0f23-4b52-8e6d-07005c52ac6d@kernel.org>
References: <20251216112053.1927852-1-ye.zhang@rock-chips.com>
 <20251216112053.1927852-7-ye.zhang@rock-chips.com>
 <5154ca76-0f23-4b52-8e6d-07005c52ac6d@kernel.org>
Message-ID: <74125120-5d62-41b6-9c3a-904f1565fc95@rock-chips.com>


? 2025/12/16 23:52, Krzysztof Kozlowski ??:
> On 16/12/2025 12:20, Ye Zhang wrote:
>> 1. Add header file with constants for RMIO function IDs for the Rockchip
>> RK3506 SoC.
>> 2. Add device tree binding for the RMIO (Rockchip Matrix I/O) controller
>> which is a sub-device of the main pinctrl on some Rockchip SoCs.
>>
>> Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
>> ---
>>   .../bindings/pinctrl/rockchip,pinctrl.yaml    |   9 ++
>>   .../bindings/pinctrl/rockchip,rmio.yaml       | 106 +++++++++++++++++
>>   .../pinctrl/rockchip,rk3506-rmio.h            | 109 ++++++++++++++++++
>>   3 files changed, 224 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml
>>   create mode 100644 include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h
>>
>> diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
>> index 97960245676d..9a27eaf7942b 100644
>> --- a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
>> +++ b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
>> @@ -82,6 +82,15 @@ required:
>>     - rockchip,grf
>>   
>>   patternProperties:
>> +  "rmio[0-9]*$":
>> +    type: object
>> +
>> +    $ref: "/schemas/pinctrl/rockchip,rmio.yaml#"
>> +
>> +    description:
>> +      The RMIO (Rockchip Matrix I/O) controller node which functions as a
>> +      sub-device of the main pinctrl to handle flexible function routing.
> No. Your child has no resources, so it's not proper hardware
> representation. Don't use Linux driver model in the bindings.
>
> That's a NAK. Don't send the same AGAIN without addressing comments like
> you did here.
I understand your point now.? In v4, I will remove rockchip,rmio. yaml 
and drop the separate RMIO child node entirely.
Instead of creating a fake device node, I will use a phandle property 
within the main pinctrl node to reference the GRF/PMU syscon that 
contains the RMIO registers.? For example:
rockchip,rmio-grf = <&rmio_grf>;
The fixed parameters (like offset and pin count) will be moved into the 
driver code.
>> +
>>     "gpio@[0-9a-f]+$":
>>       type: object
>>   
>> diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml b/Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml
>> new file mode 100644
>> index 000000000000..af0b34512fb9
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml
>> @@ -0,0 +1,106 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/pinctrl/rockchip,rmio.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: RMIO (Rockchip Matrix I/O) Controller
>> +
>> +maintainers:
>> +  - Heiko Stuebner <heiko at sntech.de>
>> +
>> +description: |
>> +  The RMIO controller provides a flexible routing matrix that allows mapping
>> +  various internal peripheral functions (UART, SPI, PWM, etc.) to specific
>> +  physical pins. This block is typically a sub-block of the GRF
>> +  (General Register Files) or PMU (Power Management Unit).
>> +
>> +properties:
>> +  compatible:
>> +    items:
>> +      - enum:
>> +          - rockchip,rk3506-rmio
>> +      - const: rockchip,rmio
> I don't see how pinctrl deserves generic compatible. I already commented
> on this.
In v4, I will remove the generic compatible string rockchip,rmio and 
rely solely on the specific compatible.? Since the separate RMIO node is 
being removed (as per the point above), this compatible issue will 
naturally be resolved as the logic moves into the main driver.
>
>> +
>> +  rockchip,rmio-grf:
>> +    $ref: /schemas/types.yaml#/definitions/phandle
>> +    description:
>> +      The phandle of the syscon node (GRF or PMU) containing the RMIO registers.
>> +      This property is required if the RMIO registers are located in a different
>> +      syscon than the parent pinctrl node.
> Why "if"? How this can be flexible?
>
> Anyway, you did not address my previous comment at all.
>
> NAK
The description will be corrected to"Phandles to the GRF/PMU syscons 
containing the RMIO registers. These are required to access the RMIO 
controller registers"

>> +
>> +  rockchip,offset:
>> +    $ref: /schemas/types.yaml#/definitions/uint32
>> +    description:
>> +      The offset of the RMIO configuration registers within the GRF.
> No, this belongs to the phandle.
>
> Look how this is already described and do not come with other style.
In v4, I will remove rockchip,rmio. yaml

>> +
>> +  rockchip,pins-num:
>> +    $ref: /schemas/types.yaml#/definitions/uint32
>> +    description:
>> +      The number of physical pins supported by this RMIO instance.
>> +      Used for boundary checking and driver initialization.
>> +
>> +patternProperties:
>> +  "^[a-z0-9-]+$":
> No, use a prefix or suffix. See other pinctrl bindings.
In v4, I will remove rockchip,rmio. yaml

>> +    type: object
>> +    description:
>> +      Function node grouping multiple groups.
>> +
>> +    patternProperties:
>> +      "^[a-z0-9-]+$":
> Same ocmment
>
>> +        type: object
>> +        description:
>> +          Group node containing the pinmux configuration.
>> +
>> +        properties:
>> +          rockchip,rmio:
>> +            $ref: /schemas/types.yaml#/definitions/uint32-matrix
>> +            description:
>> +              A list of pin-function pairs. The format is <pin_id function_id>.
>> +            minItems: 1
>> +            items:
>> +              items:
>> +                - description: RMIO Pin ID (0 to pins-num - 1)
>> +                  minimum: 0
>> +                  maximum: 31
>> +                - description: Function ID
>> +                  minimum: 0
>> +                  maximum: 98
>> +
>> +        required:
>> +          - rockchip,rmio
> Why aren't you using standard pinctrl bindings?
The standard pinmux binding is not suitable here because RMIO acts as a 
secondary layer of muxing, distinct from the primary IOMUX.
The primary IOMUX (handled by rockchip,pins) routes the pin to the RMIO 
block, while the RMIO configuration determines the specific function 
within that block.
In v4, I plan to define rockchip,rmio as a supplemental vendor-specific 
property within the pin group, formatted as <rmio_id rmio_pin_id 
rmio_function>.

For example:

&pinctrl {
 ? ? ? ? rm_io24 {
 ? ? ? ? ? ? ? ? /omit-if-no-ref/
 ? ? ? ? ? ? ? ? rm_io24_uart1_tx: rm-io24-uart1-tx {
 ? ? ? ? ? ? ? ? ? ? ? ? rockchip,pins =
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <1 RK_PB1 16 &pcfg_pull_none>;
 ? ? ? ? ? ? ? ? ? ? ? ? rockchip,rmio =
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <0 24 RMIO_UART1_TX>;
 ? ? ? ? ? ? ? ? };
};

>> +
>> +        additionalProperties: false
>> +
>> +    additionalProperties: false
>> +
>> +required:
>> +  - compatible
>> +  - rockchip,rmio-grf
>> +  - rockchip,offset
>> +  - rockchip,pins-num
>> +
>> +additionalProperties: false
>> +
>> +examples:
>> +  - |
>> +    #include <dt-bindings/pinctrl/rockchip,rk3506-rmio.h>
>> +
>> +    pinctrl: pinctrl {
> What's this?
In v4, I will remove rockchip,rmio. yaml
>> +        rmio: rmio {
>> +            compatible = "rockchip,rk3506-rmio", "rockchip,rmio";
>> +            rockchip,rmio-grf = <&grf_pmu>;
>> +            rockchip,offset = <0x80>;
>> +            rockchip,pins-num = <32>;
>> +
>> +            rmio-uart {
>> +                rmio_pin27_uart1_tx: rmio-pin27-uart1-tx {
>> +                    rockchip,rmio = <27 RMIO_UART1_TX>;
>> +                };
>> +
>> +                rmio_pin28_uart1_rx: rmio-pin28-uart1-rx {
>> +                    rockchip,rmio = <28 RMIO_UART1_RX>;
>> +                };
>> +            };
>> +        };
>> +    };
>> diff --git a/include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h b/include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h
>> new file mode 100644
>> index 000000000000..b129e9a8c287
>> --- /dev/null
>> +++ b/include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h
>> @@ -0,0 +1,109 @@
>> +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
>> +/*
>> + * Copyright (c) 2025 Rockchip Electronics Co., Ltd.
>> + */
>> +
>> +#ifndef __DT_BINDINGS_PINCTRL_ROCKCHIP_RK3506_RMIO_H
>> +#define __DT_BINDINGS_PINCTRL_ROCKCHIP_RK3506_RMIO_H
>> +
>> +/* RMIO function definition */
>> +#define RMIO_UART1_TX			1
>> +#define RMIO_UART1_RX			2
>> +#define RMIO_UART2_TX			3
>> +#define RMIO_UART2_RX			4
>> +#define RMIO_UART3_TX			5
>> +#define RMIO_UART3_RX			6
>> +#define RMIO_UART3_CTSN			7
>> +#define RMIO_UART3_RTSN			8
>> +#define RMIO_UART4_TX			9
>> +#define RMIO_UART4_RX			10
>> +#define RMIO_UART4_CTSN			11
>> +#define RMIO_UART4_RTSN			12
>> +#define RMIO_MIPITE			13
>> +#define RMIO_CLK_32K			14
>> +#define RMIO_I2C0_SCL			15
>> +#define RMIO_I2C0_SDA			16
>
> I do not see how this is a binding. Please point me to the patch using
> this in the driver.
These macros are intended to be used in the Device Tree sources to 
improve readability, avoiding ?magic numbers? for the RMIO function IDs.

For example, instead of writing <0 24 1>, the DTS uses <0 24 
RMIO_UART1_TX>, which is much clearer.

in v4, I will provide the relevant dts
> Best regards,
> Krzysztof
>
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
>


From lkp at intel.com  Wed Dec 24 22:58:57 2025
From: lkp at intel.com (kernel test robot)
Date: Thu, 25 Dec 2025 14:58:57 +0800
Subject: [PATCH v4 14/17] ras: ATL: Unify ATL interface for ARM64 and AMD
In-Reply-To: <20251222094351.38792-16-tianruidong@linux.alibaba.com>
References: <20251222094351.38792-16-tianruidong@linux.alibaba.com>
Message-ID: <202512251419.gOeKyBqX-lkp@intel.com>

Hi Ruidong,

kernel test robot noticed the following build errors:

[auto build test ERROR on rafael-pm/linux-next]
[also build test ERROR on rafael-pm/bleeding-edge linus/master v6.19-rc2 next-20251219]
[cannot apply to arm64/for-next/core]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Ruidong-Tian/ACPI-AEST-Parse-the-AEST-table/20251222-215248
base:   https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git linux-next
patch link:    https://lore.kernel.org/r/20251222094351.38792-16-tianruidong%40linux.alibaba.com
patch subject: [PATCH v4 14/17] ras: ATL: Unify ATL interface for ARM64 and AMD
config: x86_64-rhel-9.4 (https://download.01.org/0day-ci/archive/20251225/202512251419.gOeKyBqX-lkp at intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251225/202512251419.gOeKyBqX-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512251419.gOeKyBqX-lkp at intel.com/

All errors (new ones prefixed by >>):

   drivers/ras/amd/fmpm.c: In function 'save_spa':
>> drivers/ras/amd/fmpm.c:336:15: error: implicit declaration of function 'amd_convert_umc_mca_addr_to_sys_addr'; did you mean 'convert_umc_mca_addr_to_sys_addr'? [-Wimplicit-function-declaration]
     336 |         spa = amd_convert_umc_mca_addr_to_sys_addr(&a_err);
         |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         |               convert_umc_mca_addr_to_sys_addr
--
   drivers/ras/amd/atl/umc.c: In function '_retire_row_mi300':
>> drivers/ras/amd/atl/umc.c:321:24: error: implicit declaration of function 'amd_convert_umc_mca_addr_to_sys_addr'; did you mean 'convert_umc_mca_addr_to_sys_addr'? [-Wimplicit-function-declaration]
     321 |                 addr = amd_convert_umc_mca_addr_to_sys_addr(a_err);
         |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         |                        convert_umc_mca_addr_to_sys_addr


vim +336 drivers/ras/amd/fmpm.c

6f15e617cc9932 Yazen Ghannam 2024-02-13  298  
838850c50884cd Yazen Ghannam 2024-03-01  299  static void save_spa(struct fru_rec *rec, unsigned int entry,
838850c50884cd Yazen Ghannam 2024-03-01  300  		     u64 addr, u64 id, unsigned int cpu)
838850c50884cd Yazen Ghannam 2024-03-01  301  {
838850c50884cd Yazen Ghannam 2024-03-01  302  	unsigned int i, fru_idx, spa_entry;
838850c50884cd Yazen Ghannam 2024-03-01  303  	struct atl_err a_err;
838850c50884cd Yazen Ghannam 2024-03-01  304  	unsigned long spa;
838850c50884cd Yazen Ghannam 2024-03-01  305  
838850c50884cd Yazen Ghannam 2024-03-01  306  	if (entry >= max_nr_entries) {
838850c50884cd Yazen Ghannam 2024-03-01  307  		pr_warn_once("FRU descriptor entry %d out-of-bounds (max: %d)\n",
838850c50884cd Yazen Ghannam 2024-03-01  308  			     entry, max_nr_entries);
838850c50884cd Yazen Ghannam 2024-03-01  309  		return;
838850c50884cd Yazen Ghannam 2024-03-01  310  	}
838850c50884cd Yazen Ghannam 2024-03-01  311  
838850c50884cd Yazen Ghannam 2024-03-01  312  	/* spa_nr_entries is always multiple of max_nr_entries */
838850c50884cd Yazen Ghannam 2024-03-01  313  	for (i = 0; i < spa_nr_entries; i += max_nr_entries) {
838850c50884cd Yazen Ghannam 2024-03-01  314  		fru_idx = i / max_nr_entries;
838850c50884cd Yazen Ghannam 2024-03-01  315  		if (fru_records[fru_idx] == rec)
838850c50884cd Yazen Ghannam 2024-03-01  316  			break;
838850c50884cd Yazen Ghannam 2024-03-01  317  	}
838850c50884cd Yazen Ghannam 2024-03-01  318  
838850c50884cd Yazen Ghannam 2024-03-01  319  	if (i >= spa_nr_entries) {
838850c50884cd Yazen Ghannam 2024-03-01  320  		pr_warn_once("FRU record %d not found\n", i);
838850c50884cd Yazen Ghannam 2024-03-01  321  		return;
838850c50884cd Yazen Ghannam 2024-03-01  322  	}
838850c50884cd Yazen Ghannam 2024-03-01  323  
838850c50884cd Yazen Ghannam 2024-03-01  324  	spa_entry = i + entry;
838850c50884cd Yazen Ghannam 2024-03-01  325  	if (spa_entry >= spa_nr_entries) {
838850c50884cd Yazen Ghannam 2024-03-01  326  		pr_warn_once("spa_entries[] index out-of-bounds\n");
838850c50884cd Yazen Ghannam 2024-03-01  327  		return;
838850c50884cd Yazen Ghannam 2024-03-01  328  	}
838850c50884cd Yazen Ghannam 2024-03-01  329  
838850c50884cd Yazen Ghannam 2024-03-01  330  	memset(&a_err, 0, sizeof(struct atl_err));
838850c50884cd Yazen Ghannam 2024-03-01  331  
838850c50884cd Yazen Ghannam 2024-03-01  332  	a_err.addr = addr;
838850c50884cd Yazen Ghannam 2024-03-01  333  	a_err.ipid = id;
838850c50884cd Yazen Ghannam 2024-03-01  334  	a_err.cpu  = cpu;
838850c50884cd Yazen Ghannam 2024-03-01  335  
838850c50884cd Yazen Ghannam 2024-03-01 @336  	spa = amd_convert_umc_mca_addr_to_sys_addr(&a_err);
838850c50884cd Yazen Ghannam 2024-03-01  337  	if (IS_ERR_VALUE(spa)) {
838850c50884cd Yazen Ghannam 2024-03-01  338  		pr_debug("Failed to get system address\n");
838850c50884cd Yazen Ghannam 2024-03-01  339  		return;
838850c50884cd Yazen Ghannam 2024-03-01  340  	}
838850c50884cd Yazen Ghannam 2024-03-01  341  
838850c50884cd Yazen Ghannam 2024-03-01  342  	spa_entries[spa_entry] = spa;
838850c50884cd Yazen Ghannam 2024-03-01  343  	pr_debug("fru_idx: %u, entry: %u, spa_entry: %u, spa: 0x%016llx\n",
838850c50884cd Yazen Ghannam 2024-03-01  344  		 fru_idx, entry, spa_entry, spa_entries[spa_entry]);
838850c50884cd Yazen Ghannam 2024-03-01  345  }
838850c50884cd Yazen Ghannam 2024-03-01  346  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From Kyrie.Wu at mediatek.com  Wed Dec 24 23:04:35 2025
From: Kyrie.Wu at mediatek.com (=?utf-8?B?S3lyaWUgV3UgKOWQtOaZlyk=?=)
Date: Thu, 25 Dec 2025 07:04:35 +0000
Subject: [PATCH v11 06/12] media: mediatek: jpeg: fix decoding buffer
 number setting timing issue
In-Reply-To: <043630a657ff5403b74202f6a856ff4bcfc6a192.camel@ndufresne.ca>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
	 <20251202094800.6140-7-kyrie.wu@mediatek.com>
	 <043630a657ff5403b74202f6a856ff4bcfc6a192.camel@ndufresne.ca>
Message-ID: <eeb28d5e47f581db5d7dc0428b25750441853753.camel@mediatek.com>

On Tue, 2025-12-16 at 16:37 -0500, Nicolas Dufresne wrote:
> Hi,
> 
> Le mardi 02 d?cembre 2025 ? 17:47 +0800, Kyrie Wu a ?crit :
> > move decoding buffer increase code into spinlock
> > protecting aera for multi-core
> 
> I don't understand this text, please rework.
Dear Nicolas,

The dst buf parameters only need to set when the power
set succussed and protect the setting by spinlock.

I will rework the commit message in the coming version.

Thanks.

Regards,
Kyrie.
> 
> > 
> > Fixes: dedc21500334 ("media: mtk-jpegdec: add jpeg decode worker
> > interface")
> > 
> 
> Drop that blank line.
> 
> > Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
> > ---
> >  drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c   | 9 +++--
> > ----
> >  drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c | 1 +
> >  drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c | 1 +
> >  3 files changed, 5 insertions(+), 6 deletions(-)
> > 
> > diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > index e45d7e82b8a0..5ffaee4dcd19 100644
> > --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > @@ -1746,7 +1746,6 @@ static void mtk_jpegdec_worker(struct
> > work_struct *work)
> >  
> >  	v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
> >  	jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(&src_buf->vb2_buf);
> > -	jpeg_dst_buf = mtk_jpeg_vb2_to_srcbuf(&dst_buf->vb2_buf);
> >  
> >  	if (mtk_jpeg_check_resolution_change(ctx,
> >  					     &jpeg_src_buf->dec_param)) 
> > {
> > @@ -1755,11 +1754,6 @@ static void mtk_jpegdec_worker(struct
> > work_struct *work)
> >  		goto getbuf_fail;
> >  	}
> >  
> > -	jpeg_src_buf->curr_ctx = ctx;
> > -	jpeg_src_buf->frame_num = ctx->total_frame_num;
> > -	jpeg_dst_buf->curr_ctx = ctx;
> > -	jpeg_dst_buf->frame_num = ctx->total_frame_num;
> > -
> >  	mtk_jpegdec_set_hw_param(ctx, hw_id, src_buf, dst_buf);
> >  	ret = pm_runtime_resume_and_get(comp_jpeg[hw_id]->dev);
> >  	if (ret < 0) {
> > @@ -1784,6 +1778,9 @@ static void mtk_jpegdec_worker(struct
> > work_struct *work)
> >  			     
> > msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC));
> >  
> >  	spin_lock_irqsave(&comp_jpeg[hw_id]->hw_lock, flags);
> > +	jpeg_dst_buf = mtk_jpeg_vb2_to_srcbuf(&dst_buf->vb2_buf);
> > +	jpeg_dst_buf->curr_ctx = ctx;
> > +	jpeg_dst_buf->frame_num = ctx->total_frame_num;
> >  	ctx->total_frame_num++;
> >  	mtk_jpeg_dec_reset(comp_jpeg[hw_id]->reg_base);
> >  	mtk_jpeg_dec_set_config(comp_jpeg[hw_id]->reg_base,
> > diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> > b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> > index 5f1557dafad6..b3142dc9be85 100644
> > --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> > +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> > @@ -513,6 +513,7 @@ static void mtk_jpegdec_put_buf(struct
> > mtk_jpegdec_comp_dev *jpeg)
> >  				v4l2_m2m_buf_done(&tmp_dst_done_buf->b,
> >  						  VB2_BUF_STATE_DONE);
> >  				ctx->last_done_frame_num++;
> > +				break;
> >  			}
> >  		}
> >  	}
> > diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> > b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> > index 785db5ba4770..82c971936c4d 100644
> > --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> > +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> > @@ -242,6 +242,7 @@ static void mtk_jpegenc_put_buf(struct
> > mtk_jpegenc_comp_dev *jpeg)
> >  				v4l2_m2m_buf_done(&tmp_dst_done_buf->b,
> >  						  VB2_BUF_STATE_DONE);
> >  				ctx->last_done_frame_num++;
> > +				break;
> >  			}
> >  		}
> >  	}
> 
> Normally I'd seek for the context in the code. But I think I'll wait
> for a
> proper commit message, and do a proper review then.
> 
> Nicolas

From Kyrie.Wu at mediatek.com  Wed Dec 24 23:05:32 2025
From: Kyrie.Wu at mediatek.com (=?utf-8?B?S3lyaWUgV3UgKOWQtOaZlyk=?=)
Date: Thu, 25 Dec 2025 07:05:32 +0000
Subject: [PATCH v11 07/12] media: mediatek: jpeg: fix decoding resolution
 change operation
In-Reply-To: <41e00b0f4c667ff8e8a8f8b81f64fe1bbca7c001.camel@ndufresne.ca>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
	 <20251202094800.6140-8-kyrie.wu@mediatek.com>
	 <41e00b0f4c667ff8e8a8f8b81f64fe1bbca7c001.camel@ndufresne.ca>
Message-ID: <da1ba8c74cbbd36441d567fee52072129b801544.camel@mediatek.com>

On Tue, 2025-12-16 at 16:40 -0500, Nicolas Dufresne wrote:
> Hi,
> 
> Le mardi 02 d?cembre 2025 ? 17:47 +0800, Kyrie Wu a ?crit :
> > 1.add a judgement for src buffer to avoid kernel crash
> > in the stop streaming function;
> > 2.When a resolution changing occurs, it needs to set new
> > resolution parameter immediately and then report this event.
> > Otherwise, if the original software process is maintained,
> > the resolution change event is reported firstly, the CPU is
> > dispatched to the app to process the event, and the driver
> > does not set a new resolution, which will cause parameter errors.
> > 3.After a resolution change occurred, decoding should not continue,
> > needs to wait until new buffers are ready and the state machine
> > changed.
> 
> I mention this in other patchset, very often, 3 bullets means 3
> distinct
> changes. Don't use bullets. Reflow this text, rework this text, there
> is many
> syntax error here.
> 
Thanks. I will rework it.

Kyrie.
> > 
> > Fixes: dedc21500334 ("media: mtk-jpegdec: add jpeg decode worker
> > interface")
> > 
> > Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
> > ---
> >  drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c | 9 +++++++--
> >  1 file changed, 7 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > index 5ffaee4dcd19..9233bbfe2d97 100644
> > --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > @@ -887,7 +887,8 @@ static void mtk_jpeg_dec_stop_streaming(struct
> > vb2_queue
> > *q)
> >  
> >  		vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
> >  		src_buf = mtk_jpeg_vb2_to_srcbuf(&vb->vb2_buf);
> > -		mtk_jpeg_set_queue_data(ctx, &src_buf->dec_param);
> > +		if (!IS_ERR_OR_NULL(src_buf))
> > +			mtk_jpeg_set_queue_data(ctx, &src_buf-
> > >dec_param);
> 
> The lack of vb2_wait_for_all_buffers() might explains this better,
> you might not
> need to do random null checks like this.
> 
> Nicolas
> 
> >  		ctx->state = MTK_JPEG_RUNNING;
> >  	} else if (V4L2_TYPE_IS_OUTPUT(q->type)) {
> >  		ctx->state = MTK_JPEG_INIT;
> > @@ -1749,11 +1750,15 @@ static void mtk_jpegdec_worker(struct
> > work_struct
> > *work)
> >  
> >  	if (mtk_jpeg_check_resolution_change(ctx,
> >  					     &jpeg_src_buf->dec_param)) 
> > {
> > -		mtk_jpeg_queue_src_chg_event(ctx);
> > +		mtk_jpeg_set_queue_data(ctx, &jpeg_src_buf->dec_param);
> >  		ctx->state = MTK_JPEG_SOURCE_CHANGE;
> > +		mtk_jpeg_queue_src_chg_event(ctx);
> >  		goto getbuf_fail;
> >  	}
> >  
> > +	if (ctx->state == MTK_JPEG_SOURCE_CHANGE)
> > +		goto getbuf_fail;
> > +
> >  	mtk_jpegdec_set_hw_param(ctx, hw_id, src_buf, dst_buf);
> >  	ret = pm_runtime_resume_and_get(comp_jpeg[hw_id]->dev);
> >  	if (ret < 0) {

From Kyrie.Wu at mediatek.com  Wed Dec 24 23:15:42 2025
From: Kyrie.Wu at mediatek.com (=?utf-8?B?S3lyaWUgV3UgKOWQtOaZlyk=?=)
Date: Thu, 25 Dec 2025 07:15:42 +0000
Subject: [PATCH v11 08/12] media: mediatek: jpeg: fix remove buffer
 operation for multi-core
In-Reply-To: <a8376a71b87cc8944bf05be3bc45dc2e4fe2764e.camel@ndufresne.ca>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
	 <20251202094800.6140-9-kyrie.wu@mediatek.com>
	 <a8376a71b87cc8944bf05be3bc45dc2e4fe2764e.camel@ndufresne.ca>
Message-ID: <61f6d2af71bc6dabb55a866915d765b82007fedc.camel@mediatek.com>

On Tue, 2025-12-16 at 16:43 -0500, Nicolas Dufresne wrote:
> Hi,
> 
> Le mardi 02 d?cembre 2025 ? 17:47 +0800, Kyrie Wu a ?crit :
> > move remove buffer code to spinlock protect area for multi-core
> 
> Perhaps:
> 
> Move calls to v4l2_m2m_src/dst_buf_remove() outside of the spinlock
> protected
> scope.
> 
> And perhaps extend in why this is needed. Deadlock, bad lock
> ordering?

Dear Nicolas,

move them to protected scope to avoid buffer lost if the worker
scheduled
but it hasn't enable jpeg hw succussed yet.

I will refine the commit message.

Thanks.

Regards,
Kyrie.
> 
> > 
> > Fixes: 86379bd9d399 ("media: mtk-jpeg: Fixes jpeg enc&dec worker sw
> > flow")
> > 
> 
> No blank.
> 
> > Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
> 
> Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
> 
> Nicolas
> 
> > ---
> >  drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c | 10 ++++--
> > ----
> >  1 file changed, 4 insertions(+), 6 deletions(-)
> > 
> > diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > index 9233bbfe2d97..da1ca494ed4b 100644
> > --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > @@ -1665,9 +1665,6 @@ static void mtk_jpegenc_worker(struct
> > work_struct *work)
> >  		goto enc_end;
> >  	}
> >  
> > -	v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> > -	v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> > -
> >  	schedule_delayed_work(&comp_jpeg[hw_id]->job_timeout_work,
> >  			     
> > msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC));
> >  
> > @@ -1685,6 +1682,8 @@ static void mtk_jpegenc_worker(struct
> > work_struct *work)
> >  			     &src_buf->vb2_buf);
> >  	mtk_jpeg_set_enc_params(ctx, comp_jpeg[hw_id]->reg_base);
> >  	mtk_jpeg_enc_start(comp_jpeg[hw_id]->reg_base);
> > +	v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> > +	v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> >  	jpeg_buf_queue_inc(ctx);
> >  	v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
> >  	spin_unlock_irqrestore(&comp_jpeg[hw_id]->hw_lock, flags);
> > @@ -1767,9 +1766,6 @@ static void mtk_jpegdec_worker(struct
> > work_struct *work)
> >  		goto dec_end;
> >  	}
> >  
> > -	v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> > -	v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> > -
> >  	mtk_jpeg_set_dec_src(ctx, &src_buf->vb2_buf, &bs);
> >  	if (mtk_jpeg_set_dec_dst(ctx,
> >  				 &jpeg_src_buf->dec_param,
> > @@ -1794,6 +1790,8 @@ static void mtk_jpegdec_worker(struct
> > work_struct *work)
> >  				jpeg_src_buf->bs_size,
> >  				&bs,
> >  				&fb);
> > +	v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> > +	v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> >  	mtk_jpeg_dec_start(comp_jpeg[hw_id]->reg_base);
> >  	jpeg_buf_queue_inc(ctx);
> >  	v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);

From Kyrie.Wu at mediatek.com  Wed Dec 24 23:17:55 2025
From: Kyrie.Wu at mediatek.com (=?utf-8?B?S3lyaWUgV3UgKOWQtOaZlyk=?=)
Date: Thu, 25 Dec 2025 07:17:55 +0000
Subject: [PATCH v11 12/12] media: mediatek: jpeg: add jpeg smmu sid
 setting
In-Reply-To: <086b940b975a9c0f9cb5d5cf2fabe21ddb188821.camel@ndufresne.ca>
References: <20251202094800.6140-1-kyrie.wu@mediatek.com>
	 <20251202094800.6140-13-kyrie.wu@mediatek.com>
	 <086b940b975a9c0f9cb5d5cf2fabe21ddb188821.camel@ndufresne.ca>
Message-ID: <b1f6b8f394ccef920f8838a01967dee7e4326bf1.camel@mediatek.com>

On Tue, 2025-12-16 at 16:48 -0500, Nicolas Dufresne wrote:
> Hi,
> 
> Le mardi 02 d?cembre 2025 ? 17:48 +0800, Kyrie Wu a ?crit :
> > Add a configuration to set jpeg dec & enc smmu sid
> > 
> > Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
> > ---
> >  .../platform/mediatek/jpeg/mtk_jpeg_core.c    | 37
> > +++++++++++++++++++
> >  .../platform/mediatek/jpeg/mtk_jpeg_core.h    | 15 ++++++++
> >  .../platform/mediatek/jpeg/mtk_jpeg_dec_hw.c  | 23 ++++++++++++
> >  .../platform/mediatek/jpeg/mtk_jpeg_enc_hw.c  | 23 ++++++++++++
> >  4 files changed, 98 insertions(+)
> > 
> > diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > index 10a588b92e76..625dfa8468e1 100644
> > --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> > @@ -15,6 +15,7 @@
> >  #include <linux/of_platform.h>
> >  #include <linux/platform_device.h>
> >  #include <linux/pm_runtime.h>
> > +#include <linux/regmap.h>
> >  #include <linux/slab.h>
> >  #include <linux/spinlock.h>
> >  #include <media/v4l2-event.h>
> > @@ -1613,6 +1614,20 @@ static irqreturn_t mtk_jpeg_enc_done(struct
> > mtk_jpeg_dev *jpeg)
> >  	return IRQ_HANDLED;
> >  }
> >  
> > +static void mtk_jpeg_enc_set_smmu_sid(struct mtk_jpegenc_comp_dev
> > *jpeg)
> > +{
> > +	struct mtk_jpeg_dev *mjpeg = jpeg->master_dev;
> > +
> > +	if (!mjpeg->variant->support_smmu || !jpeg->smmu_regmap)
> > +		return;
> > +
> > +	regmap_update_bits(jpeg->smmu_regmap, JPEG_ENC_SMMU_SID,
> > +			   JPG_REG_GUSER_ID_MASK <<
> > +			   JPG_REG_ENC_GUSER_ID_SHIFT,
> > +			   JPG_REG_GUSER_ID_ENC_SID <<
> > +			   JPG_REG_ENC_GUSER_ID_SHIFT);
> > +}
> > +
> >  static void mtk_jpegenc_worker(struct work_struct *work)
> >  {
> >  	struct mtk_jpegenc_comp_dev *comp_jpeg[MTK_JPEGENC_HW_MAX];
> > @@ -1674,6 +1689,9 @@ static void mtk_jpegenc_worker(struct
> > work_struct *work)
> >  	jpeg_dst_buf->frame_num = ctx->total_frame_num;
> >  	ctx->total_frame_num++;
> >  	mtk_jpeg_enc_reset(comp_jpeg[hw_id]->reg_base);
> > +
> > +	mtk_jpeg_enc_set_smmu_sid(comp_jpeg[hw_id]);
> > +
> >  	mtk_jpeg_set_enc_dst(ctx,
> >  			     comp_jpeg[hw_id]->reg_base,
> >  			     &dst_buf->vb2_buf);
> > @@ -1701,6 +1719,20 @@ static void mtk_jpegenc_worker(struct
> > work_struct *work)
> >  	v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
> >  }
> >  
> > +static void mtk_jpeg_dec_set_smmu_sid(struct mtk_jpegdec_comp_dev
> > *jpeg)
> > +{
> > +	struct mtk_jpeg_dev *mjpeg = jpeg->master_dev;
> > +
> > +	if (!mjpeg->variant->support_smmu || !jpeg->smmu_regmap)
> > +		return;
> > +
> > +	regmap_update_bits(jpeg->smmu_regmap, JPEG_DEC_SMMU_SID,
> > +			   JPG_REG_GUSER_ID_MASK <<
> > +			   JPG_REG_DEC_GUSER_ID_SHIFT,
> > +			   JPG_REG_GUSER_ID_DEC_SID <<
> > +			   JPG_REG_DEC_GUSER_ID_SHIFT);
> > +}
> 
> Can you deduplicate that function. Just make one, and pass the SID as
> parameter.

Dear Nicolas,

Thanks for your comments, I will refactor this function.

Regards,
Kyrie.
> 
> > +
> >  static void mtk_jpegdec_worker(struct work_struct *work)
> >  {
> >  	struct mtk_jpeg_ctx *ctx = container_of(work, struct
> > mtk_jpeg_ctx,
> > @@ -1784,6 +1816,9 @@ static void mtk_jpegdec_worker(struct
> > work_struct *work)
> >  	jpeg_dst_buf->frame_num = ctx->total_frame_num;
> >  	ctx->total_frame_num++;
> >  	mtk_jpeg_dec_reset(comp_jpeg[hw_id]->reg_base);
> > +
> > +	mtk_jpeg_dec_set_smmu_sid(comp_jpeg[hw_id]);
> > +
> >  	mtk_jpeg_dec_set_config(comp_jpeg[hw_id]->reg_base,
> >  				jpeg->variant->support_34bit,
> >  				&jpeg_src_buf->dec_param,
> > @@ -1943,6 +1978,7 @@ static struct mtk_jpeg_variant
> > mtk8196_jpegenc_drvdata = {
> >  	.cap_q_default_fourcc = V4L2_PIX_FMT_JPEG,
> >  	.multi_core = true,
> >  	.jpeg_worker = mtk_jpegenc_worker,
> > +	.support_smmu = true,
> >  };
> >  
> >  static const struct mtk_jpeg_variant mtk8195_jpegdec_drvdata = {
> > @@ -1969,6 +2005,7 @@ static const struct mtk_jpeg_variant
> > mtk8196_jpegdec_drvdata = {
> >  	.cap_q_default_fourcc = V4L2_PIX_FMT_YUV420M,
> >  	.multi_core = true,
> >  	.jpeg_worker = mtk_jpegdec_worker,
> > +	.support_smmu = true,
> >  };
> >  
> >  static const struct of_device_id mtk_jpeg_match[] = {
> > diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> > b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> > index 33f7fbc4ca5e..6e8304680393 100644
> > --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> > +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h
> > @@ -11,6 +11,7 @@
> >  
> >  #include <linux/clk.h>
> >  #include <linux/interrupt.h>
> > +#include <linux/mfd/syscon.h>
> >  #include <media/v4l2-ctrls.h>
> >  #include <media/v4l2-device.h>
> >  #include <media/v4l2-fh.h>
> > @@ -34,6 +35,14 @@
> >  
> >  #define MTK_JPEG_MAX_EXIF_SIZE	(64 * 1024)
> >  
> > +#define JPEG_DEC_SMMU_SID				0
> > +#define JPEG_ENC_SMMU_SID				0
> > +#define JPG_REG_GUSER_ID_MASK			0x7
> > +#define JPG_REG_GUSER_ID_DEC_SID		0x4
> > +#define JPG_REG_GUSER_ID_ENC_SID		0x5
> > +#define JPG_REG_DEC_GUSER_ID_SHIFT		8
> > +#define JPG_REG_ENC_GUSER_ID_SHIFT		4
> > +
> >  #define MTK_JPEG_ADDR_MASK GENMASK(1, 0)
> >  
> >  /**
> > @@ -65,6 +74,7 @@ enum mtk_jpeg_ctx_state {
> >   * @multi_core:		mark jpeg hw is multi_core or not
> >   * @jpeg_worker:		jpeg dec or enc worker
> >   * @support_34bit:	flag to check support for 34-bit DMA address
> > + * @support_smmu:	flag to check if support smmu
> >   */
> >  struct mtk_jpeg_variant {
> >  	struct clk_bulk_data *clks;
> > @@ -82,6 +92,7 @@ struct mtk_jpeg_variant {
> >  	bool multi_core;
> >  	void (*jpeg_worker)(struct work_struct *work);
> >  	bool support_34bit;
> > +	bool support_smmu;
> >  };
> >  
> >  struct mtk_jpeg_src_buf {
> > @@ -150,6 +161,7 @@ struct mtk_jpegdec_clk {
> >   * @hw_param:		jpeg encode hw parameters
> >   * @hw_state:		record hw state
> >   * @hw_lock:		spinlock protecting the hw device
> > resource
> > + * @smmu_regmap:	SMMU registers mapping
> >   */
> >  struct mtk_jpegenc_comp_dev {
> >  	struct device *dev;
> > @@ -163,6 +175,7 @@ struct mtk_jpegenc_comp_dev {
> >  	enum mtk_jpeg_hw_state hw_state;
> >  	/* spinlock protecting the hw device resource */
> >  	spinlock_t hw_lock;
> > +	struct regmap *smmu_regmap;
> >  };
> >  
> >  /**
> > @@ -177,6 +190,7 @@ struct mtk_jpegenc_comp_dev {
> >   * @hw_param:			jpeg decode hw parameters
> >   * @hw_state:			record hw state
> >   * @hw_lock:			spinlock protecting hw
> > + * @smmu_regmap:		SMMU registers mapping
> >   */
> >  struct mtk_jpegdec_comp_dev {
> >  	struct device *dev;
> > @@ -190,6 +204,7 @@ struct mtk_jpegdec_comp_dev {
> >  	enum mtk_jpeg_hw_state hw_state;
> >  	/* spinlock protecting the hw device resource */
> >  	spinlock_t hw_lock;
> > +	struct regmap *smmu_regmap;
> >  };
> >  
> >  /**
> > diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> > b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> > index e453a1634f33..da753a636eaa 100644
> > --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> > +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
> > @@ -624,6 +624,25 @@ static int mtk_jpegdec_hw_init_irq(struct
> > mtk_jpegdec_comp_dev *dev)
> >  	return 0;
> >  }
> >  
> > +static int mtk_jpegdec_smmu_init(struct mtk_jpegdec_comp_dev *dev)
> > +{
> > +	struct mtk_jpeg_dev *master_dev = dev->master_dev;
> > +
> > +	if (!master_dev->variant->support_smmu)
> > +		return 0;
> > +
> > +	dev->smmu_regmap =
> > +		syscon_regmap_lookup_by_phandle(dev->plat_dev-
> > >dev.of_node,
> > +						"mediatek,smmu-
> > config");
> > +	if (IS_ERR(dev->smmu_regmap)) {
> > +		return dev_err_probe(dev->dev, PTR_ERR(dev-
> > >smmu_regmap),
> > +				     "mmap smmu_base failed(%ld)\n",
> > +				     PTR_ERR(dev->smmu_regmap));
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> >  static int mtk_jpegdec_hw_probe(struct platform_device *pdev)
> >  {
> >  	struct mtk_jpegdec_clk *jpegdec_clk;
> > @@ -677,6 +696,10 @@ static int mtk_jpegdec_hw_probe(struct
> > platform_device *pdev)
> >  	dev->master_dev = master_dev;
> >  	master_dev->max_hw_count++;
> >  
> > +	ret = mtk_jpegdec_smmu_init(dev);
> > +	if (ret)
> > +		return ret;
> > +
> >  	platform_set_drvdata(pdev, dev);
> >  	pm_runtime_enable(&pdev->dev);
> >  	ret = devm_clk_bulk_get(dev->dev,
> > diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> > b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> > index b30c728c3712..8a61d5537315 100644
> > --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> > +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c
> > @@ -348,6 +348,25 @@ static int mtk_jpegenc_hw_init_irq(struct
> > mtk_jpegenc_comp_dev *dev)
> >  	return 0;
> >  }
> >  
> > +static int mtk_jpegenc_smmu_init(struct mtk_jpegenc_comp_dev *dev)
> > +{
> > +	struct mtk_jpeg_dev *master_dev = dev->master_dev;
> > +
> > +	if (!master_dev->variant->support_smmu)
> > +		return 0;
> > +
> > +	dev->smmu_regmap =
> > +		syscon_regmap_lookup_by_phandle(dev->plat_dev-
> > >dev.of_node,
> > +						"mediatek,smmu-
> > config");
> > +	if (IS_ERR(dev->smmu_regmap)) {
> > +		return dev_err_probe(dev->dev, PTR_ERR(dev-
> > >smmu_regmap),
> > +				     "mmap smmu_base failed(%ld)\n",
> > +				     PTR_ERR(dev->smmu_regmap));
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> >  static int mtk_jpegenc_hw_probe(struct platform_device *pdev)
> >  {
> >  	struct mtk_jpegenc_clk *jpegenc_clk;
> > @@ -399,6 +418,10 @@ static int mtk_jpegenc_hw_probe(struct
> > platform_device *pdev)
> >  	dev->master_dev = master_dev;
> >  	master_dev->max_hw_count++;
> >  
> > +	ret = mtk_jpegenc_smmu_init(dev);
> > +	if (ret)
> > +		return ret;
> > +
> >  	platform_set_drvdata(pdev, dev);
> >  	pm_runtime_enable(&pdev->dev);
> >  	ret = devm_clk_bulk_get(dev->dev,
> 
> With that minor fix:
> 
> Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>

From Kyrie.Wu at mediatek.com  Wed Dec 24 23:26:31 2025
From: Kyrie.Wu at mediatek.com (=?utf-8?B?S3lyaWUgV3UgKOWQtOaZlyk=?=)
Date: Thu, 25 Dec 2025 07:26:31 +0000
Subject: [PATCH v6 02/10] media: mediatek: decoder: Add a new platform
 data member
In-Reply-To: <777147df01b9d939ba86a9a006e3615d6478a773.camel@collabora.com>
References: <20251202074038.3173-1-kyrie.wu@mediatek.com>
	 <20251202074038.3173-3-kyrie.wu@mediatek.com>
	 <777147df01b9d939ba86a9a006e3615d6478a773.camel@collabora.com>
Message-ID: <890702604a2abe7a07d9ef4d43b743d3db3510a9.camel@mediatek.com>

On Thu, 2025-12-11 at 15:11 -0500, Nicolas Dufresne wrote:
> Hi,
> 
> Le mardi 02 d?cembre 2025 ? 15:40 +0800, Kyrie Wu a ?crit :
> > Add a new platform data member to indicate each decoder IC
> > to avoid the chip name definition keep growing.
> > 
> > Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
> > ---
> >  .../mediatek/vcodec/decoder/mtk_vcodec_dec.h  |   5 +
> >  .../vcodec/decoder/mtk_vcodec_dec_drv.c       |  35 +----
> >  .../vcodec/decoder/mtk_vcodec_dec_drv.h       |  15 +-
> >  .../vcodec/decoder/mtk_vcodec_dec_hw.c        |   2 +-
> >  .../vcodec/decoder/mtk_vcodec_dec_stateful.c  |   1 +
> >  .../vcodec/decoder/mtk_vcodec_dec_stateless.c | 137
> > +++++++++++++++---
> >  6 files changed, 131 insertions(+), 64 deletions(-)
> > 
> > diff --git
> > a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.h
> > b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.h
> > index 1af075fc0194..80cb46f1cded 100644
> > ---
> > a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.h
> > +++
> > b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.h
> > @@ -69,6 +69,11 @@ extern const struct v4l2_m2m_ops
> > mtk_vdec_m2m_ops;
> >  extern const struct media_device_ops mtk_vcodec_media_ops;
> >  extern const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata;
> >  extern const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata;
> > +extern const struct mtk_vcodec_dec_pdata mtk_vdec_8186_pdata;
> > +extern const struct mtk_vcodec_dec_pdata mtk_vdec_8188_pdata;
> > +extern const struct mtk_vcodec_dec_pdata mtk_vdec_8192_pdata;
> > +extern const struct mtk_vcodec_dec_pdata mtk_vdec_8195_pdata;
> > +extern const struct mtk_vcodec_dec_pdata mtk_vdec_8196_pdata;
> >  extern const struct mtk_vcodec_dec_pdata mtk_lat_sig_core_pdata;
> >  extern const struct mtk_vcodec_dec_pdata
> > mtk_vdec_single_core_pdata;
> >  
> > diff --git
> > a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv
> > .c
> > b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv
> > .c
> > index 6fb05bb00641..d7a269045fd6 100644
> > ---
> > a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv
> > .c
> > +++
> > b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv
> > .c
> > @@ -331,24 +331,7 @@ static const struct v4l2_file_operations
> > mtk_vcodec_fops = {
> >  
> >  static void mtk_vcodec_dec_get_chip_name(struct mtk_vcodec_dec_dev
> > *vdec_dev)
> >  {
> > -	struct device *dev = &vdec_dev->plat_dev->dev;
> > -
> > -	if (of_device_is_compatible(dev->of_node, "mediatek,mt8173-
> > vcodec-dec"))
> > -		vdec_dev->chip_name = MTK_VDEC_MT8173;
> > -	else if (of_device_is_compatible(dev->of_node,
> > "mediatek,mt8183-vcodec-dec"))
> > -		vdec_dev->chip_name = MTK_VDEC_MT8183;
> > -	else if (of_device_is_compatible(dev->of_node,
> > "mediatek,mt8192-vcodec-dec"))
> > -		vdec_dev->chip_name = MTK_VDEC_MT8192;
> > -	else if (of_device_is_compatible(dev->of_node,
> > "mediatek,mt8195-vcodec-dec"))
> > -		vdec_dev->chip_name = MTK_VDEC_MT8195;
> > -	else if (of_device_is_compatible(dev->of_node,
> > "mediatek,mt8186-vcodec-dec"))
> > -		vdec_dev->chip_name = MTK_VDEC_MT8186;
> > -	else if (of_device_is_compatible(dev->of_node,
> > "mediatek,mt8188-vcodec-dec"))
> > -		vdec_dev->chip_name = MTK_VDEC_MT8188;
> > -	else if (of_device_is_compatible(dev->of_node,
> > "mediatek,mt8196-vcodec-dec"))
> > -		vdec_dev->chip_name = MTK_VDEC_MT8196;
> > -	else
> > -		vdec_dev->chip_name = MTK_VDEC_INVAL;
> > +	vdec_dev->chip_name = vdec_dev->vdec_pdata->chip_name;
> >  }
> >  
> >  static int mtk_vcodec_probe(struct platform_device *pdev)
> > @@ -367,10 +350,6 @@ static int mtk_vcodec_probe(struct
> > platform_device *pdev)
> >  	dev->plat_dev = pdev;
> >  
> >  	mtk_vcodec_dec_get_chip_name(dev);
> > -	if (dev->chip_name == MTK_VDEC_INVAL) {
> > -		dev_err(&pdev->dev, "Failed to get decoder chip name");
> > -		return -EINVAL;
> > -	}
> >  
> >  	dev->vdec_pdata = of_device_get_match_data(&pdev->dev);
> >  	if (!of_property_read_u32(pdev->dev.of_node, "mediatek,vpu",
> > @@ -387,7 +366,7 @@ static int mtk_vcodec_probe(struct
> > platform_device *pdev)
> >  		return -ENODEV;
> >  	}
> >  	dma_set_max_seg_size(&pdev->dev, UINT_MAX);
> > -	if (dev->chip_name == MTK_VDEC_MT8196) {
> > +	if (dev->chip_name == 8196) {
> >  		ret = dma_set_mask_and_coherent(&pdev->dev,
> > DMA_BIT_MASK(36));
> >  		if (ret) {
> >  			dev_err(&pdev->dev, "Failed to enable 36-bit
> > DMA: %d\n", ret);
> > @@ -556,23 +535,23 @@ static const struct of_device_id
> > mtk_vcodec_match[] = {
> >  	},
> >  	{
> >  		.compatible = "mediatek,mt8192-vcodec-dec",
> > -		.data = &mtk_lat_sig_core_pdata,
> > +		.data = &mtk_vdec_8192_pdata,
> >  	},
> >  	{
> >  		.compatible = "mediatek,mt8186-vcodec-dec",
> > -		.data = &mtk_vdec_single_core_pdata,
> > +		.data = &mtk_vdec_8186_pdata,
> >  	},
> >  	{
> >  		.compatible = "mediatek,mt8195-vcodec-dec",
> > -		.data = &mtk_lat_sig_core_pdata,
> > +		.data = &mtk_vdec_8195_pdata,
> >  	},
> >  	{
> >  		.compatible = "mediatek,mt8188-vcodec-dec",
> > -		.data = &mtk_lat_sig_core_pdata,
> > +		.data = &mtk_vdec_8188_pdata,
> >  	},
> >  	{
> >  		.compatible = "mediatek,mt8196-vcodec-dec",
> > -		.data = &mtk_lat_sig_core_pdata,
> > +		.data = &mtk_vdec_8196_pdata,
> >  	},
> >  	{},
> >  };
> > diff --git
> > a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv
> > .h
> > b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv
> > .h
> > index 429b32952194..2dbde8d00e6f 100644
> > ---
> > a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv
> > .h
> > +++
> > b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv
> > .h
> > @@ -19,17 +19,6 @@
> >  #define IS_VDEC_INNER_RACING(capability) ((capability) &
> > MTK_VCODEC_INNER_RACING)
> >  #define IS_VDEC_SUPPORT_EXT(capability) ((capability) &
> > MTK_VDEC_IS_SUPPORT_EXT)
> >  
> > -enum mtk_vcodec_dec_chip_name {
> > -	MTK_VDEC_INVAL = 0,
> > -	MTK_VDEC_MT8173 = 8173,
> > -	MTK_VDEC_MT8183 = 8183,
> > -	MTK_VDEC_MT8186 = 8186,
> > -	MTK_VDEC_MT8188 = 8188,
> > -	MTK_VDEC_MT8192 = 8192,
> > -	MTK_VDEC_MT8195 = 8195,
> > -	MTK_VDEC_MT8196 = 8196,
> > -};
> > -
> >  /*
> >   * enum mtk_vdec_format_types - Structure used to get supported
> >   *		  format types according to decoder capability
> > @@ -106,6 +95,7 @@ struct vdec_pic_info {
> >   *
> >   * @is_subdev_supported: whether support parent-node
> > architecture(subdev)
> >   * @uses_stateless_api: whether the decoder uses the stateless API
> > with requests
> > + * @chip_name: platforms configuration values
> >   */
> >  struct mtk_vcodec_dec_pdata {
> >  	void (*init_vdec_params)(struct mtk_vcodec_dec_ctx *ctx);
> > @@ -127,6 +117,7 @@ struct mtk_vcodec_dec_pdata {
> >  
> >  	bool is_subdev_supported;
> >  	bool uses_stateless_api;
> > +	unsigned int chip_name;
> >  };
> >  
> >  /**
> > @@ -307,7 +298,7 @@ struct mtk_vcodec_dec_dev {
> >  	struct mutex dec_racing_info_mutex;
> >  	struct mtk_vcodec_dbgfs dbgfs;
> >  
> > -	enum mtk_vcodec_dec_chip_name chip_name;
> > +	unsigned int chip_name;
> >  };
> >  
> >  static inline struct mtk_vcodec_dec_ctx *fh_to_dec_ctx(struct
> > v4l2_fh *fh)
> > diff --git
> > a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_hw.
> > c
> > b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_hw.
> > c
> > index e4e527fe54dc..a926dc14d39d 100644
> > ---
> > a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_hw.
> > c
> > +++
> > b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_hw.
> > c
> > @@ -76,7 +76,7 @@ static void mtk_vdec_hw_clean_xpc(struct
> > mtk_vdec_hw_dev *dev)
> >  {
> >  	u32 val, mask, addr = VDEC_XPC_CLEAN_ADDR;
> >  
> > -	if (dev->main_dev->chip_name != MTK_VDEC_MT8196)
> > +	if (dev->main_dev->chip_name != 8196)
> >  		return;
> >  
> >  	val = dev->hw_idx == MTK_VDEC_LAT0 ? VDEC_XPC_LAT_VAL :
> > VDEC_XPC_CORE_VAL;
> > diff --git
> > a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teful.c
> > b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teful.c
> > index aa9bdee7a96c..8ddb61670dc6 100644
> > ---
> > a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teful.c
> > +++
> > b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teful.c
> > @@ -618,4 +618,5 @@ const struct mtk_vcodec_dec_pdata
> > mtk_vdec_8173_pdata = {
> >  	.flush_decoder = mtk_vdec_flush_decoder,
> >  	.is_subdev_supported = false,
> >  	.hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
> > +	.chip_name = 8173,
> >  };
> > diff --git
> > a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teless.c
> > b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teless.c
> > index c1cef78471a9..d249a8774948 100644
> > ---
> > a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teless.c
> > +++
> > b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teless.c
> > @@ -550,16 +550,16 @@ static void
> > mtk_vcodec_dec_fill_h264_level(struct v4l2_ctrl_config *cfg,
> >  					   struct mtk_vcodec_dec_ctx
> > *ctx)
> >  {
> >  	switch (ctx->dev->chip_name) {
> > -	case MTK_VDEC_MT8192:
> > -	case MTK_VDEC_MT8188:
> > +	case 8192:
> > +	case 8188:
> >  		cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_5_2;
> >  		break;
> > -	case MTK_VDEC_MT8195:
> > -	case MTK_VDEC_MT8196:
> > +	case 8195:
> > +	case 8196:
> >  		cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_6_0;
> >  		break;
> > -	case MTK_VDEC_MT8183:
> > -	case MTK_VDEC_MT8186:
> > +	case 8183:
> > +	case 8186:
> >  		cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_4_2;
> >  		break;
> >  	default:
> > @@ -572,9 +572,9 @@ static void
> > mtk_vcodec_dec_fill_h264_profile(struct v4l2_ctrl_config *cfg,
> >  					     struct mtk_vcodec_dec_ctx
> > *ctx)
> >  {
> >  	switch (ctx->dev->chip_name) {
> > -	case MTK_VDEC_MT8188:
> > -	case MTK_VDEC_MT8195:
> > -	case MTK_VDEC_MT8196:
> > +	case 8188:
> > +	case 8195:
> > +	case 8196:
> >  		cfg->max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10;
> >  		break;
> >  	default:
> > @@ -587,11 +587,11 @@ static void
> > mtk_vcodec_dec_fill_h265_level(struct v4l2_ctrl_config *cfg,
> >  					   struct mtk_vcodec_dec_ctx
> > *ctx)
> >  {
> >  	switch (ctx->dev->chip_name) {
> > -	case MTK_VDEC_MT8188:
> > +	case 8188:
> >  		cfg->max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1;
> >  		break;
> > -	case MTK_VDEC_MT8195:
> > -	case MTK_VDEC_MT8196:
> > +	case 8195:
> > +	case 8196:
> >  		cfg->max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2;
> >  		break;
> >  	default:
> > @@ -604,9 +604,9 @@ static void
> > mtk_vcodec_dec_fill_h265_profile(struct v4l2_ctrl_config *cfg,
> >  					     struct mtk_vcodec_dec_ctx
> > *ctx)
> >  {
> >  	switch (ctx->dev->chip_name) {
> > -	case MTK_VDEC_MT8188:
> > -	case MTK_VDEC_MT8195:
> > -	case MTK_VDEC_MT8196:
> > +	case 8188:
> > +	case 8195:
> > +	case 8196:
> >  		cfg->max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10;
> >  		break;
> >  	default:
> > @@ -619,15 +619,15 @@ static void
> > mtk_vcodec_dec_fill_vp9_level(struct v4l2_ctrl_config *cfg,
> >  					  struct mtk_vcodec_dec_ctx
> > *ctx)
> >  {
> >  	switch (ctx->dev->chip_name) {
> > -	case MTK_VDEC_MT8192:
> > -	case MTK_VDEC_MT8188:
> > +	case 8192:
> > +	case 8188:
> >  		cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_5_1;
> >  		break;
> > -	case MTK_VDEC_MT8195:
> > -	case MTK_VDEC_MT8196:
> > +	case 8195:
> > +	case 8196:
> >  		cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2;
> >  		break;
> > -	case MTK_VDEC_MT8186:
> > +	case 8186:
> >  		cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_4_1;
> >  		break;
> >  	default:
> > @@ -640,9 +640,9 @@ static void
> > mtk_vcodec_dec_fill_vp9_profile(struct v4l2_ctrl_config *cfg,
> >  					    struct mtk_vcodec_dec_ctx
> > *ctx)
> >  {
> >  	switch (ctx->dev->chip_name) {
> > -	case MTK_VDEC_MT8188:
> > -	case MTK_VDEC_MT8195:
> > -	case MTK_VDEC_MT8196:
> > +	case 8188:
> > +	case 8195:
> > +	case 8196:
> >  		cfg->max = V4L2_MPEG_VIDEO_VP9_PROFILE_2;
> >  		break;
> >  	default:
> > @@ -886,6 +886,7 @@ const struct mtk_vcodec_dec_pdata
> > mtk_vdec_8183_pdata = {
> >  	.get_cap_buffer = vdec_get_cap_buffer,
> >  	.is_subdev_supported = false,
> >  	.hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
> > +	.chip_name = 8183,
> >  };
> >  
> >  /* This platform data is used for one lat and one core
> > architecture. */
> > @@ -906,6 +907,78 @@ const struct mtk_vcodec_dec_pdata
> > mtk_lat_sig_core_pdata = {
> >  	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
> >  };
> >  
> > +const struct mtk_vcodec_dec_pdata mtk_vdec_8188_pdata = {
> > +	.init_vdec_params = mtk_init_vdec_params,
> > +	.ctrls_setup = mtk_vcodec_dec_ctrls_setup,
> > +	.vdec_vb2_ops = &mtk_vdec_request_vb2_ops,
> > +	.vdec_formats = mtk_video_formats,
> > +	.num_formats = &num_formats,
> > +	.default_out_fmt = &default_out_format,
> > +	.default_cap_fmt = &default_cap_format,
> > +	.uses_stateless_api = true,
> > +	.worker = mtk_vdec_worker,
> > +	.flush_decoder = mtk_vdec_flush_decoder,
> > +	.cap_to_disp = mtk_vdec_stateless_cap_to_disp,
> > +	.get_cap_buffer = vdec_get_cap_buffer,
> > +	.is_subdev_supported = true,
> > +	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
> > +	.chip_name = 8188,
> > +};
> > +
> > +const struct mtk_vcodec_dec_pdata mtk_vdec_8192_pdata = {
> > +	.init_vdec_params = mtk_init_vdec_params,
> > +	.ctrls_setup = mtk_vcodec_dec_ctrls_setup,
> > +	.vdec_vb2_ops = &mtk_vdec_request_vb2_ops,
> > +	.vdec_formats = mtk_video_formats,
> > +	.num_formats = &num_formats,
> > +	.default_out_fmt = &default_out_format,
> > +	.default_cap_fmt = &default_cap_format,
> > +	.uses_stateless_api = true,
> > +	.worker = mtk_vdec_worker,
> > +	.flush_decoder = mtk_vdec_flush_decoder,
> > +	.cap_to_disp = mtk_vdec_stateless_cap_to_disp,
> > +	.get_cap_buffer = vdec_get_cap_buffer,
> > +	.is_subdev_supported = true,
> > +	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
> > +	.chip_name = 8192,
> > +};
> 
> I really like the change overall, but this adds a lot of code
> duplication.
> Perhaps you could do something like:
> 
> +#define MTK_STATELESS_DEC_DATA \
> +	.init_vdec_params = mtk_init_vdec_params,
> +	.ctrls_setup = mtk_vcodec_dec_ctrls_setup,
> +	.vdec_vb2_ops = &mtk_vdec_request_vb2_ops,
> +	.vdec_formats = mtk_video_formats,
> +	.num_formats = &num_formats,
> +	.default_out_fmt = &default_out_format,
> +	.default_cap_fmt = &default_cap_format,
> +	.uses_stateless_api = true,
> +	.worker = mtk_vdec_worker,
> +	.flush_decoder = mtk_vdec_flush_decoder,
> +	.cap_to_disp = mtk_vdec_stateless_cap_to_disp,
> +	.get_cap_buffer = vdec_get_cap_buffer,
> +	.is_subdev_supported = true
> 
> +const struct mtk_vcodec_dec_pdata mtk_vdec_8192_pdata = {
> +	MTK_STATELESS_DEC_DATA,
> +	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
> +	.chip_name = 8192,
> +};
> 
> The other method also used in various drivers is to embed a pointer
> to another
> structure. The benefit of this second method is that it reduce the
> driver binary
> size. With one solution to the copy paste issue implemented, the
> patch looks
> good.
> 
> regards,
> Nicolas

Dear Nicolas,

Thanks for your suggestions. I will refine this patch.

Regards,
Kyrie.
> 
> > +
> > +const struct mtk_vcodec_dec_pdata mtk_vdec_8195_pdata = {
> > +	.init_vdec_params = mtk_init_vdec_params,
> > +	.ctrls_setup = mtk_vcodec_dec_ctrls_setup,
> > +	.vdec_vb2_ops = &mtk_vdec_request_vb2_ops,
> > +	.vdec_formats = mtk_video_formats,
> > +	.num_formats = &num_formats,
> > +	.default_out_fmt = &default_out_format,
> > +	.default_cap_fmt = &default_cap_format,
> > +	.uses_stateless_api = true,
> > +	.worker = mtk_vdec_worker,
> > +	.flush_decoder = mtk_vdec_flush_decoder,
> > +	.cap_to_disp = mtk_vdec_stateless_cap_to_disp,
> > +	.get_cap_buffer = vdec_get_cap_buffer,
> > +	.is_subdev_supported = true,
> > +	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
> > +	.chip_name = 8195,
> > +};
> > +
> > +const struct mtk_vcodec_dec_pdata mtk_vdec_8196_pdata = {
> > +	.init_vdec_params = mtk_init_vdec_params,
> > +	.ctrls_setup = mtk_vcodec_dec_ctrls_setup,
> > +	.vdec_vb2_ops = &mtk_vdec_request_vb2_ops,
> > +	.vdec_formats = mtk_video_formats,
> > +	.num_formats = &num_formats,
> > +	.default_out_fmt = &default_out_format,
> > +	.default_cap_fmt = &default_cap_format,
> > +	.uses_stateless_api = true,
> > +	.worker = mtk_vdec_worker,
> > +	.flush_decoder = mtk_vdec_flush_decoder,
> > +	.cap_to_disp = mtk_vdec_stateless_cap_to_disp,
> > +	.get_cap_buffer = vdec_get_cap_buffer,
> > +	.is_subdev_supported = true,
> > +	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
> > +	.chip_name = 8196,
> > +};
> > +
> >  const struct mtk_vcodec_dec_pdata mtk_vdec_single_core_pdata = {
> >  	.init_vdec_params = mtk_init_vdec_params,
> >  	.ctrls_setup = mtk_vcodec_dec_ctrls_setup,
> > @@ -922,3 +995,21 @@ const struct mtk_vcodec_dec_pdata
> > mtk_vdec_single_core_pdata = {
> >  	.is_subdev_supported = true,
> >  	.hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
> >  };
> > +
> > +const struct mtk_vcodec_dec_pdata mtk_vdec_8186_pdata = {
> > +	.init_vdec_params = mtk_init_vdec_params,
> > +	.ctrls_setup = mtk_vcodec_dec_ctrls_setup,
> > +	.vdec_vb2_ops = &mtk_vdec_request_vb2_ops,
> > +	.vdec_formats = mtk_video_formats,
> > +	.num_formats = &num_formats,
> > +	.default_out_fmt = &default_out_format,
> > +	.default_cap_fmt = &default_cap_format,
> > +	.uses_stateless_api = true,
> > +	.worker = mtk_vdec_worker,
> > +	.flush_decoder = mtk_vdec_flush_decoder,
> > +	.cap_to_disp = mtk_vdec_stateless_cap_to_disp,
> > +	.get_cap_buffer = vdec_get_cap_buffer,
> > +	.is_subdev_supported = true,
> > +	.hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
> > +	.chip_name = 8186,
> > +};

From Kyrie.Wu at mediatek.com  Wed Dec 24 23:28:47 2025
From: Kyrie.Wu at mediatek.com (=?utf-8?B?S3lyaWUgV3UgKOWQtOaZlyk=?=)
Date: Thu, 25 Dec 2025 07:28:47 +0000
Subject: [PATCH v6 04/10] media: mediatek: vcodec: add profile and level
 supporting for MT8189
In-Reply-To: <370389b51412209ae6aa6d8c388f29af7ed456a5.camel@collabora.com>
References: <20251202074038.3173-1-kyrie.wu@mediatek.com>
	 <20251202074038.3173-5-kyrie.wu@mediatek.com>
	 <370389b51412209ae6aa6d8c388f29af7ed456a5.camel@collabora.com>
Message-ID: <89026929a48ccbff80ebde8094a4460c0d7f79f6.camel@mediatek.com>

On Thu, 2025-12-11 at 15:19 -0500, Nicolas Dufresne wrote:
> Hi,
> 
> in the subject, supporting -> suppport.
> 
> Le mardi 02 d?cembre 2025 ? 15:40 +0800, Kyrie Wu a ?crit :
> > add profile and level supporting for H264 and vp9 of MT8189
> 
> You already said that, perhaps say:
> 
> 
>    The MT8189 SoC support H.264 up to high-10 at level 5.2, HEVC up
> to profile
>    main-still at level 4 and VP9 profile 2 up to level 5.2. 
> 
> > 
> > Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
> > Reviewed-by: AngeloGioacchino Del Regno
> > <angelogioacchino.delregno at collabora.com>
> > ---
> >  .../vcodec/decoder/mtk_vcodec_dec_drv.h       |  16 ++
> >  .../vcodec/decoder/mtk_vcodec_dec_stateful.c  |  12 ++
> >  .../vcodec/decoder/mtk_vcodec_dec_stateless.c | 177 ++++++++++--
> > ------
> >  3 files changed, 130 insertions(+), 75 deletions(-)
> > 
> > diff --git
> > a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv
> > .h
> > b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv
> > .h
> > index 2dbde8d00e6f..a8baeab98477 100644
> > ---
> > a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv
> > .h
> > +++
> > b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv
> > .h
> > @@ -76,6 +76,16 @@ struct vdec_pic_info {
> >  	unsigned int reserved;
> >  };
> >  
> > +/**
> > + * struct mtk_vcodec_dec_params - decoder supported parameters
> > + * @level: decoder supported vcodec level
> > + * @profile: decoder supported vcodec profile
> > + */
> > +struct mtk_vcodec_dec_params {
> > +	s64 level;
> > +	s64 profile;
> > +};
> > +
> >  /**
> >   * struct mtk_vcodec_dec_pdata - compatible data for each IC
> >   * @init_vdec_params: init vdec params
> > @@ -96,6 +106,9 @@ struct vdec_pic_info {
> >   * @is_subdev_supported: whether support parent-node
> > architecture(subdev)
> >   * @uses_stateless_api: whether the decoder uses the stateless API
> > with
> > requests
> >   * @chip_name: platforms configuration values
> > + * @h264_params: H264 decoder default supported params
> > + * @h265_params: H265 decoder default supported params
> > + * @vp9_params: VP9 decoder default supported params
> >   */
> >  struct mtk_vcodec_dec_pdata {
> >  	void (*init_vdec_params)(struct mtk_vcodec_dec_ctx *ctx);
> > @@ -118,6 +131,9 @@ struct mtk_vcodec_dec_pdata {
> >  	bool is_subdev_supported;
> >  	bool uses_stateless_api;
> >  	unsigned int chip_name;
> > +	struct mtk_vcodec_dec_params h264_params;
> > +	struct mtk_vcodec_dec_params h265_params;
> > +	struct mtk_vcodec_dec_params vp9_params;
> >  };
> >  
> >  /**
> > diff --git
> > a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teful.c
> > b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teful.c
> > index 8ddb61670dc6..a47906b9d717 100644
> > ---
> > a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teful.c
> > +++
> > b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teful.c
> > @@ -619,4 +619,16 @@ const struct mtk_vcodec_dec_pdata
> > mtk_vdec_8173_pdata = {
> >  	.is_subdev_supported = false,
> >  	.hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
> >  	.chip_name = 8173,
> > +	.h264_params = {
> > +		.level = V4L2_MPEG_VIDEO_H264_LEVEL_4_1,
> > +		.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
> > +	},
> > +	.h265_params = {
> > +		.level = V4L2_MPEG_VIDEO_HEVC_LEVEL_4,
> > +		.profile =
> > V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE,
> > +	},
> > +	.vp9_params = {
> > +		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_4_0,
> > +		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_1,
> > +	},
> >  };
> > diff --git
> > a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teless.c
> > b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teless.c
> > index 9e43c54f8c4d..dc3e9a2ccc2c 100644
> > ---
> > a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teless.c
> > +++
> > b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teless.c
> > @@ -549,106 +549,49 @@ static const struct v4l2_ctrl_ops
> > mtk_vcodec_dec_ctrl_ops = {
> >  static void mtk_vcodec_dec_fill_h264_level(struct v4l2_ctrl_config
> > *cfg,
> >  					   struct mtk_vcodec_dec_ctx
> > *ctx)
> >  {
> > -	switch (ctx->dev->chip_name) {
> > -	case 8192:
> > -	case 8188:
> > -		cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_5_2;
> > -		break;
> > -	case 8195:
> > -	case 8196:
> > -		cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_6_0;
> > -		break;
> > -	case 8183:
> > -	case 8186:
> > -		cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_4_2;
> > -		break;
> > -	default:
> > -		cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_4_1;
> > -		break;
> > -	}
> > +	struct mtk_vcodec_dec_dev *pdev = ctx->dev;
> > +
> > +	cfg->max = pdev->vdec_pdata->h264_params.level;
> >  }
> 
> Only remaining issue is that this is two changes. Please refactor
> first, and add
> the configuration after. This is a nice cleanup.
> 
> regards,
> Nicolas
> 
Dear Nicolas,

I will split this patch to two.

Thanks.

Regards,
Kyrie.
> >  
> >  static void mtk_vcodec_dec_fill_h264_profile(struct
> > v4l2_ctrl_config *cfg,
> >  					     struct mtk_vcodec_dec_ctx
> > *ctx)
> >  {
> > -	switch (ctx->dev->chip_name) {
> > -	case 8188:
> > -	case 8195:
> > -	case 8196:
> > -		cfg->max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10;
> > -		break;
> > -	default:
> > -		cfg->max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH;
> > -		break;
> > -	}
> > +	struct mtk_vcodec_dec_dev *pdev = ctx->dev;
> > +
> > +	cfg->max = pdev->vdec_pdata->h264_params.profile;
> >  }
> >  
> >  static void mtk_vcodec_dec_fill_h265_level(struct v4l2_ctrl_config
> > *cfg,
> >  					   struct mtk_vcodec_dec_ctx
> > *ctx)
> >  {
> > -	switch (ctx->dev->chip_name) {
> > -	case 8188:
> > -		cfg->max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1;
> > -		break;
> > -	case 8195:
> > -	case 8196:
> > -		cfg->max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2;
> > -		break;
> > -	default:
> > -		cfg->max = V4L2_MPEG_VIDEO_HEVC_LEVEL_4;
> > -		break;
> > -	}
> > +	struct mtk_vcodec_dec_dev *pdev = ctx->dev;
> > +
> > +	cfg->max = pdev->vdec_pdata->h265_params.level;
> >  }
> >  
> >  static void mtk_vcodec_dec_fill_h265_profile(struct
> > v4l2_ctrl_config *cfg,
> >  					     struct mtk_vcodec_dec_ctx
> > *ctx)
> >  {
> > -	switch (ctx->dev->chip_name) {
> > -	case 8188:
> > -	case 8195:
> > -	case 8196:
> > -		cfg->max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10;
> > -		break;
> > -	default:
> > -		cfg->max =
> > V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE;
> > -		break;
> > -	}
> > +	struct mtk_vcodec_dec_dev *pdev = ctx->dev;
> > +
> > +	cfg->max = pdev->vdec_pdata->h265_params.profile;
> >  }
> >  
> >  static void mtk_vcodec_dec_fill_vp9_level(struct v4l2_ctrl_config
> > *cfg,
> >  					  struct mtk_vcodec_dec_ctx
> > *ctx)
> >  {
> > -	switch (ctx->dev->chip_name) {
> > -	case 8192:
> > -	case 8188:
> > -		cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_5_1;
> > -		break;
> > -	case 8195:
> > -	case 8196:
> > -		cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2;
> > -		break;
> > -	case 8186:
> > -		cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_4_1;
> > -		break;
> > -	default:
> > -		cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_4_0;
> > -		break;
> > -	}
> > +	struct mtk_vcodec_dec_dev *pdev = ctx->dev;
> > +
> > +	cfg->max = pdev->vdec_pdata->vp9_params.level;
> >  }
> >  
> >  static void mtk_vcodec_dec_fill_vp9_profile(struct
> > v4l2_ctrl_config *cfg,
> >  					    struct mtk_vcodec_dec_ctx
> > *ctx)
> >  {
> > -	switch (ctx->dev->chip_name) {
> > -	case 8188:
> > -	case 8195:
> > -	case 8196:
> > -		cfg->max = V4L2_MPEG_VIDEO_VP9_PROFILE_2;
> > -		break;
> > -	default:
> > -		cfg->max = V4L2_MPEG_VIDEO_VP9_PROFILE_1;
> > -		break;
> > -	}
> > +	struct mtk_vcodec_dec_dev *pdev = ctx->dev;
> > +
> > +	cfg->max = pdev->vdec_pdata->vp9_params.profile;
> >  }
> >  
> >  static void mtk_vcodec_dec_reset_controls(struct v4l2_ctrl_config
> > *cfg,
> > @@ -887,6 +830,18 @@ const struct mtk_vcodec_dec_pdata
> > mtk_vdec_8183_pdata = {
> >  	.is_subdev_supported = false,
> >  	.hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
> >  	.chip_name = 8183,
> > +	.h264_params = {
> > +		.level = V4L2_MPEG_VIDEO_H264_LEVEL_4_2,
> > +		.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
> > +	},
> > +	.h265_params = {
> > +		.level = V4L2_MPEG_VIDEO_HEVC_LEVEL_4,
> > +		.profile =
> > V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE,
> > +	},
> > +	.vp9_params = {
> > +		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_4_0,
> > +		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_1,
> > +	},
> >  };
> >  
> >  /* This platform data is used for one lat and one core
> > architecture. */
> > @@ -923,6 +878,18 @@ const struct mtk_vcodec_dec_pdata
> > mtk_vdec_8188_pdata = {
> >  	.is_subdev_supported = true,
> >  	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
> >  	.chip_name = 8188,
> > +	.h264_params = {
> > +		.level = V4L2_MPEG_VIDEO_H264_LEVEL_5_2,
> > +		.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10,
> > +	},
> > +	.h265_params = {
> > +		.level = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1,
> > +		.profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
> > +	},
> > +	.vp9_params = {
> > +		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_1,
> > +		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
> > +	},
> >  };
> >  
> >  const struct mtk_vcodec_dec_pdata mtk_vdec_8192_pdata = {
> > @@ -941,6 +908,18 @@ const struct mtk_vcodec_dec_pdata
> > mtk_vdec_8192_pdata = {
> >  	.is_subdev_supported = true,
> >  	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
> >  	.chip_name = 8192,
> > +	.h264_params = {
> > +		.level = V4L2_MPEG_VIDEO_H264_LEVEL_5_2,
> > +		.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
> > +	},
> > +	.h265_params = {
> > +		.level = V4L2_MPEG_VIDEO_HEVC_LEVEL_4,
> > +		.profile =
> > V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE,
> > +	},
> > +	.vp9_params = {
> > +		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_1,
> > +		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_1,
> > +	},
> >  };
> >  
> >  const struct mtk_vcodec_dec_pdata mtk_vdec_8195_pdata = {
> > @@ -959,6 +938,18 @@ const struct mtk_vcodec_dec_pdata
> > mtk_vdec_8195_pdata = {
> >  	.is_subdev_supported = true,
> >  	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
> >  	.chip_name = 8195,
> > +	.h264_params = {
> > +		.level = V4L2_MPEG_VIDEO_H264_LEVEL_6_0,
> > +		.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10,
> > +	},
> > +	.h265_params = {
> > +		.level = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2,
> > +		.profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
> > +	},
> > +	.vp9_params = {
> > +		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2,
> > +		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
> > +	},
> >  };
> >  
> >  const struct mtk_vcodec_dec_pdata mtk_vdec_8196_pdata = {
> > @@ -977,6 +968,18 @@ const struct mtk_vcodec_dec_pdata
> > mtk_vdec_8196_pdata = {
> >  	.is_subdev_supported = true,
> >  	.hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
> >  	.chip_name = 8196,
> > +	.h264_params = {
> > +		.level = V4L2_MPEG_VIDEO_H264_LEVEL_6_0,
> > +		.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10,
> > +	},
> > +	.h265_params = {
> > +		.level = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2,
> > +		.profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
> > +	},
> > +	.vp9_params = {
> > +		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2,
> > +		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
> > +	},
> >  };
> >  
> >  const struct mtk_vcodec_dec_pdata mtk_vdec_single_core_pdata = {
> > @@ -1012,6 +1015,18 @@ const struct mtk_vcodec_dec_pdata
> > mtk_vdec_8186_pdata =
> > {
> >  	.is_subdev_supported = true,
> >  	.hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
> >  	.chip_name = 8186,
> > +	.h264_params = {
> > +		.level = V4L2_MPEG_VIDEO_H264_LEVEL_4_2,
> > +		.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
> > +	},
> > +	.h265_params = {
> > +		.level = V4L2_MPEG_VIDEO_HEVC_LEVEL_4,
> > +		.profile =
> > V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE,
> > +	},
> > +	.vp9_params = {
> > +		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_4_1,
> > +		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_1,
> > +	},
> >  };
> >  
> >  const struct mtk_vcodec_dec_pdata mtk_vdec_8189_pdata = {
> > @@ -1030,4 +1045,16 @@ const struct mtk_vcodec_dec_pdata
> > mtk_vdec_8189_pdata =
> > {
> >  	.is_subdev_supported = true,
> >  	.hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
> >  	.chip_name = 8189,
> > +	.h264_params = {
> > +		.level = V4L2_MPEG_VIDEO_H264_LEVEL_5_2,
> > +		.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10,
> > +	},
> > +	.h265_params = {
> > +		.level = V4L2_MPEG_VIDEO_HEVC_LEVEL_4,
> > +		.profile =
> > V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE,
> > +	},
> > +	.vp9_params = {
> > +		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2,
> > +		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
> > +	},
> >  };

From Kyrie.Wu at mediatek.com  Wed Dec 24 23:30:23 2025
From: Kyrie.Wu at mediatek.com (=?utf-8?B?S3lyaWUgV3UgKOWQtOaZlyk=?=)
Date: Thu, 25 Dec 2025 07:30:23 +0000
Subject: [PATCH v6 06/10] media: mediatek: vcodec: Add 4K prob size
 supporting for VP9 decoder
In-Reply-To: <898905035315552215b13402d29e2eeb1350c74c.camel@collabora.com>
References: <20251202074038.3173-1-kyrie.wu@mediatek.com>
	 <20251202074038.3173-7-kyrie.wu@mediatek.com>
	 <898905035315552215b13402d29e2eeb1350c74c.camel@collabora.com>
Message-ID: <61ce327121b89ebbf271c72d674f8fb4d164dded.camel@mediatek.com>

On Thu, 2025-12-11 at 15:31 -0500, Nicolas Dufresne wrote:
> Hi,
> 
> Le mardi 02 d?cembre 2025 ? 15:40 +0800, Kyrie Wu a ?crit :
> > From: Kyrie Wu <kyrie.wu at mediatek.corp-partner.google.com>
> 
> I don't think you meant to commit with your Google partner email ?
> 
> > 
> > add config to support prob size both 3840 and 2560.
> 
> Prob mean probability ? Commit message is the place to you full
> words. Can you
> extend why the difference, and use defines instead of magic number?
> 
> > 
> > Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.corp-partner.google.com>
> 
> Or even sign it ?
> 
> Nicolas
> 
Dear Nicolas,

Sorry for this mistake, I will fix it. Thanks.

Regards,
Kyrie.
> > ---
> >  .../platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h  | 2 ++
> >  .../mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c      | 1 +
> >  .../mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c     | 7
> > +++++++
> >  .../mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c     | 4 ++-
> > -
> >  4 files changed, 12 insertions(+), 2 deletions(-)
> > 
> > diff --git
> > a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv
> > .h
> > b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv
> > .h
> > index a8baeab98477..ecf0d7ad0d54 100644
> > ---
> > a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv
> > .h
> > +++
> > b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv
> > .h
> > @@ -80,10 +80,12 @@ struct vdec_pic_info {
> >   * struct mtk_vcodec_dec_params - decoder supported parameters
> >   * @level: decoder supported vcodec level
> >   * @profile: decoder supported vcodec profile
> > + * @prob_size: vp9 decoder prob size
> >   */
> >  struct mtk_vcodec_dec_params {
> >  	s64 level;
> >  	s64 profile;
> > +	size_t prob_size;
> >  };
> >  
> >  /**
> > diff --git
> > a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teful.c
> > b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teful.c
> > index a47906b9d717..99c252e0a2e1 100644
> > ---
> > a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teful.c
> > +++
> > b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teful.c
> > @@ -630,5 +630,6 @@ const struct mtk_vcodec_dec_pdata
> > mtk_vdec_8173_pdata = {
> >  	.vp9_params = {
> >  		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_4_0,
> >  		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_1,
> > +		.prob_size = 2560,
> >  	},
> >  };
> > diff --git
> > a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teless.c
> > b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teless.c
> > index dc3e9a2ccc2c..f18aafd08c76 100644
> > ---
> > a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teless.c
> > +++
> > b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teless.c
> > @@ -841,6 +841,7 @@ const struct mtk_vcodec_dec_pdata
> > mtk_vdec_8183_pdata = {
> >  	.vp9_params = {
> >  		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_4_0,
> >  		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_1,
> > +		.prob_size = 2560,
> >  	},
> >  };
> >  
> > @@ -889,6 +890,7 @@ const struct mtk_vcodec_dec_pdata
> > mtk_vdec_8188_pdata = {
> >  	.vp9_params = {
> >  		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_1,
> >  		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
> > +		.prob_size = 2560,
> >  	},
> >  };
> >  
> > @@ -919,6 +921,7 @@ const struct mtk_vcodec_dec_pdata
> > mtk_vdec_8192_pdata = {
> >  	.vp9_params = {
> >  		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_1,
> >  		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_1,
> > +		.prob_size = 2560,
> >  	},
> >  };
> >  
> > @@ -949,6 +952,7 @@ const struct mtk_vcodec_dec_pdata
> > mtk_vdec_8195_pdata = {
> >  	.vp9_params = {
> >  		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2,
> >  		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
> > +		.prob_size = 2560,
> >  	},
> >  };
> >  
> > @@ -979,6 +983,7 @@ const struct mtk_vcodec_dec_pdata
> > mtk_vdec_8196_pdata = {
> >  	.vp9_params = {
> >  		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2,
> >  		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
> > +		.prob_size = 3840,
> >  	},
> >  };
> >  
> > @@ -1026,6 +1031,7 @@ const struct mtk_vcodec_dec_pdata
> > mtk_vdec_8186_pdata =
> > {
> >  	.vp9_params = {
> >  		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_4_1,
> >  		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_1,
> > +		.prob_size = 2560,
> >  	},
> >  };
> >  
> > @@ -1056,5 +1062,6 @@ const struct mtk_vcodec_dec_pdata
> > mtk_vdec_8189_pdata =
> > {
> >  	.vp9_params = {
> >  		.level = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2,
> >  		.profile = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
> > +		.prob_size = 3840,
> >  	},
> >  };
> > diff --git
> > a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_
> > lat_if.c
> > b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_
> > lat_if.c
> > index 9513ddde7c7c..36a87b455d11 100644
> > ---
> > a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_
> > lat_if.c
> > +++
> > b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_
> > lat_if.c
> > @@ -22,7 +22,6 @@
> >  #define VP9_RESET_FRAME_CONTEXT_ALL 3
> >  
> >  #define VP9_TILE_BUF_SIZE 4096
> > -#define VP9_PROB_BUF_SIZE 2560
> >  #define VP9_COUNTS_BUF_SIZE 16384
> >  
> >  #define HDR_FLAG(x) (!!((hdr)->flags & V4L2_VP9_FRAME_FLAG_##x))
> > @@ -546,6 +545,7 @@ static int
> > vdec_vp9_slice_alloc_working_buffer(struct
> > vdec_vp9_slice_instance *i
> >  					       struct
> > vdec_vp9_slice_vsi
> > *vsi)
> >  {
> >  	struct mtk_vcodec_dec_ctx *ctx = instance->ctx;
> > +	struct mtk_vcodec_dec_dev *pdev = ctx->dev;
> >  	enum vdec_vp9_slice_resolution_level level;
> >  	/* super blocks */
> >  	unsigned int max_sb_w;
> > @@ -616,7 +616,7 @@ static int
> > vdec_vp9_slice_alloc_working_buffer(struct
> > vdec_vp9_slice_instance *i
> >  	}
> >  
> >  	if (!instance->prob.va) {
> > -		instance->prob.size = VP9_PROB_BUF_SIZE;
> > +		instance->prob.size = pdev->vdec_pdata-
> > >vp9_params.prob_size;
> >  		if (mtk_vcodec_mem_alloc(ctx, &instance->prob))
> >  			goto err;
> >  	}

From wens at kernel.org  Thu Dec 25 00:02:40 2025
From: wens at kernel.org (Chen-Yu Tsai)
Date: Thu, 25 Dec 2025 16:02:40 +0800
Subject: [PATCH] mfd: axp20x: AXP717: Add type-C CC registers
Message-ID: <20251225080241.3153453-1-wens@kernel.org>

The AXP717 has some extra registers related to type-C CC pin
negotiation. They were missing from the original submission.

Add them for completeness.

Signed-off-by: Chen-Yu Tsai <wens at kernel.org>
---
 drivers/mfd/axp20x.c       | 5 ++++-
 include/linux/mfd/axp20x.h | 3 +++
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
index c5f0ebae327f..679364189ea5 100644
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -229,6 +229,8 @@ static const struct regmap_range axp717_writeable_ranges[] = {
 	regmap_reg_range(AXP717_DCDC_OUTPUT_CONTROL, AXP717_CPUSLDO_CONTROL),
 	regmap_reg_range(AXP717_ADC_CH_EN_CONTROL, AXP717_ADC_CH_EN_CONTROL),
 	regmap_reg_range(AXP717_ADC_DATA_SEL, AXP717_ADC_DATA_SEL),
+	regmap_reg_range(AXP717_TYPEC_CC_AA_EN, AXP717_TYPEC_CC_AA_EN),
+	regmap_reg_range(AXP717_TYPEC_CC_MODE_CONTROL, AXP717_TYPEC_CC_MODE_CONTROL),
 };
 
 static const struct regmap_range axp717_volatile_ranges[] = {
@@ -237,6 +239,7 @@ static const struct regmap_range axp717_volatile_ranges[] = {
 	regmap_reg_range(AXP717_BATT_PERCENT_DATA, AXP717_BATT_PERCENT_DATA),
 	regmap_reg_range(AXP717_BATT_V_H, AXP717_BATT_CHRG_I_L),
 	regmap_reg_range(AXP717_ADC_DATA_H, AXP717_ADC_DATA_L),
+	regmap_reg_range(AXP717_TYPEC_CC_STATUS, AXP717_TYPEC_CC_STATUS),
 };
 
 static const struct regmap_access_table axp717_writeable_table = {
@@ -458,7 +461,7 @@ static const struct regmap_config axp717_regmap_config = {
 	.val_bits = 8,
 	.wr_table = &axp717_writeable_table,
 	.volatile_table = &axp717_volatile_table,
-	.max_register = AXP717_ADC_DATA_L,
+	.max_register = AXP717_TYPEC_CC_STATUS,
 	.cache_type = REGCACHE_MAPLE,
 };
 
diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h
index 3c5aecf1d4b5..b352661d99a1 100644
--- a/include/linux/mfd/axp20x.h
+++ b/include/linux/mfd/axp20x.h
@@ -174,6 +174,9 @@ enum axp20x_variants {
 #define AXP717_ADC_DATA_SEL		0xcd
 #define AXP717_ADC_DATA_H		0xce
 #define AXP717_ADC_DATA_L		0xcf
+#define AXP717_TYPEC_CC_AA_EN		0xe1
+#define AXP717_TYPEC_CC_MODE_CONTROL	0xe3
+#define AXP717_TYPEC_CC_STATUS		0xe7
 
 #define AXP806_STARTUP_SRC		0x00
 #define AXP806_CHIP_ID			0x03
-- 
2.47.3



From jernej.skrabec at gmail.com  Thu Dec 25 00:17:05 2025
From: jernej.skrabec at gmail.com (Jernej =?UTF-8?B?xaBrcmFiZWM=?=)
Date: Thu, 25 Dec 2025 09:17:05 +0100
Subject: [PATCH] mfd: axp20x: AXP717: Add type-C CC registers
In-Reply-To: <20251225080241.3153453-1-wens@kernel.org>
References: <20251225080241.3153453-1-wens@kernel.org>
Message-ID: <2827385.mvXUDI8C0e@jernej-laptop>

Dne ?etrtek, 25. december 2025 ob 09:02:40 Srednjeevropski standardni ?as je Chen-Yu Tsai napisal(a):
> The AXP717 has some extra registers related to type-C CC pin
> negotiation. They were missing from the original submission.
> 
> Add them for completeness.
> 
> Signed-off-by: Chen-Yu Tsai <wens at kernel.org>

Checked against datasheet.

Reviewed-by: Jernej Skrabec <jernej.skrabec at gmail.com>

Best regards,
Jernej




From wens at kernel.org  Thu Dec 25 00:22:11 2025
From: wens at kernel.org (Chen-Yu Tsai)
Date: Thu, 25 Dec 2025 16:22:11 +0800
Subject: [PATCH 1/7] drm/sun4i: Add support for DE33 CSC
In-Reply-To: <20251115141347.13087-2-jernej.skrabec@gmail.com>
References: <20251115141347.13087-1-jernej.skrabec@gmail.com> <20251115141347.13087-2-jernej.skrabec@gmail.com>
Message-ID: <CAGb2v64h5E+hz-G4HEBesVgu4bkFfTi5vNEpU2BQFUYHKCqY8A@mail.gmail.com>

On Sat, Nov 15, 2025 at 10:14?PM Jernej Skrabec
<jernej.skrabec at gmail.com> wrote:
>
> DE33 has channel CSC units (for each plane separately) so pipeline can
> be configured to output in desired colorspace.
>
> Signed-off-by: Jernej Skrabec <jernej.skrabec at gmail.com>

Reviewed-by: Chen-Yu Tsai <wens at kernel.org>


From krzk at kernel.org  Thu Dec 25 00:36:32 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 25 Dec 2025 09:36:32 +0100
Subject: [PATCH v3 6/7] dt-bindings: pinctrl: rockchip: Add RMIO
 controller binding
In-Reply-To: <8e126c63-1388-40ff-9046-818f7a8c969f@rock-chips.com>
References: <20251216112053.1927852-1-ye.zhang@rock-chips.com>
 <20251216112053.1927852-7-ye.zhang@rock-chips.com>
 <5154ca76-0f23-4b52-8e6d-07005c52ac6d@kernel.org>
 <8e126c63-1388-40ff-9046-818f7a8c969f@rock-chips.com>
Message-ID: <f58ccc03-286e-4ca0-acc4-6c6474a9df5c@kernel.org>

On 25/12/2025 04:25, Ye Zhang wrote:
>>> +/* RMIO function definition */
>>> +#define RMIO_UART1_TX			1
>>> +#define RMIO_UART1_RX			2
>>> +#define RMIO_UART2_TX			3
>>> +#define RMIO_UART2_RX			4
>>> +#define RMIO_UART3_TX			5
>>> +#define RMIO_UART3_RX			6
>>> +#define RMIO_UART3_CTSN			7
>>> +#define RMIO_UART3_RTSN			8
>>> +#define RMIO_UART4_TX			9
>>> +#define RMIO_UART4_RX			10
>>> +#define RMIO_UART4_CTSN			11
>>> +#define RMIO_UART4_RTSN			12
>>> +#define RMIO_MIPITE			13
>>> +#define RMIO_CLK_32K			14
>>> +#define RMIO_I2C0_SCL			15
>>> +#define RMIO_I2C0_SDA			16
>>
>> I do not see how this is a binding. Please point me to the patch using
>> this in the driver.
> These macros are intended to be used in the Device Tree sources to 
> improve readability, avoiding ?magic numbers? for the RMIO function IDs.

That was not my question. Read again what I asked.

So not a binding, remove.


Best regards,
Krzysztof


From krzk at kernel.org  Thu Dec 25 00:47:34 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 25 Dec 2025 09:47:34 +0100
Subject: [PATCH v3 01/15] include: dt-bindings: add LAN969x clock bindings
In-Reply-To: <CA+HBbNG+ZVD6grGDp32Ninx7H1AyEbGvP0nwc0zUv94tOV8hYg@mail.gmail.com>
References: <20251223201921.1332786-1-robert.marko@sartura.hr>
 <20251223201921.1332786-2-robert.marko@sartura.hr>
 <20251224-berserk-mackerel-of-snow-4cae54@quoll>
 <CA+HBbNGym6Q9b166n-P=h_JssOHm0yfyL73JZ+G9P81muK=g4A@mail.gmail.com>
 <78bf252c-fd5e-4a36-b1a3-ca8ed26fde7a@kernel.org>
 <CA+HBbNG+ZVD6grGDp32Ninx7H1AyEbGvP0nwc0zUv94tOV8hYg@mail.gmail.com>
Message-ID: <d210552f-c8bf-4084-9317-b743075d9946@kernel.org>

On 24/12/2025 15:01, Robert Marko wrote:
> On Wed, Dec 24, 2025 at 2:05?PM Krzysztof Kozlowski <krzk at kernel.org> wrote:
>>
>> On 24/12/2025 11:30, Robert Marko wrote:
>>> On Wed, Dec 24, 2025 at 11:21?AM Krzysztof Kozlowski <krzk at kernel.org> wrote:
>>>>
>>>> On Tue, Dec 23, 2025 at 09:16:12PM +0100, Robert Marko wrote:
>>>>> Add the required LAN969x clock bindings.
>>>>
>>>> I do not see clock bindings actually here. Where is the actual binding?
>>>> Commit msg does not help me at all to understand why you are doing this
>>>> without actual required bindings.
>>>
>>> I guess it is a bit confusing, there is no schema here, these are the
>>> clock indexes that
>>> reside in dt-bindings and are used by the SoC DTSI.
>>
>> I understand as not used by drivers? Then no ABI and there is no point
>> in putting them into bindings.
> 
> It is not included by the driver directly, but it requires these exact
> indexes to be passed
> so its effectively ABI.

How it requires the exact index? In what way? I do not see anything in
the gck driver using/relying on these values. Nothing. Please point me
to the line which directly uses these values.... or how many times I
will need to write this is not ABI?



Best regards,
Krzysztof


From krzk at kernel.org  Thu Dec 25 00:51:39 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 25 Dec 2025 09:51:39 +0100
Subject: [PATCH 0/5] virt: Add Bao hypervisor IPC and I/O dispatcher
 drivers
In-Reply-To: <20251224135217.25350-1-joaopeixoto@osyx.tech>
References: <20251224135217.25350-1-joaopeixoto@osyx.tech>
Message-ID: <3538f671-8a16-4b71-b15f-3ef5cfeacd40@kernel.org>

On 24/12/2025 14:52, joaopeixoto at osyx.tech wrote:
> From: Jo?o Peixoto <joaopeixoto at osyx.tech>
> 
> This series introduces support for the Bao hypervisor guest-side drivers
> under drivers/virt/bao and the associated Device Tree bindings, UAPI,
> and MAINTAINERS entries.
> 
> Bao is a lightweight static-partitioning hypervisor for embedded and
> safety-critical systems. This series adds:
> - The Bao IPC shared memory driver, which enables Linux guests to
>   communicate with each other through shared memory regions.
> - The Bao I/O Dispatcher driver, which allows Bao's VMs to share I/O
>   devices using device paravirtualization (VirtIO).
> 


None of these patches, except MAINTAINERS reached my mailbox. Fix your
submission process, so it will not be marked by spam and bounced.

Best regards,
Krzysztof


From krzk at kernel.org  Thu Dec 25 00:52:13 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 25 Dec 2025 09:52:13 +0100
Subject: [PATCH 5/5] MAINTAINERS: Add entries for Bao hypervisor drivers,
 headers, and DT bindings
In-Reply-To: <20251224135217.25350-6-joaopeixoto@osyx.tech>
References: <20251224135217.25350-1-joaopeixoto@osyx.tech>
 <20251224135217.25350-6-joaopeixoto@osyx.tech>
Message-ID: <15fcc60d-b12e-4e20-9c3d-2426a4762c55@kernel.org>

On 24/12/2025 14:52, joaopeixoto at osyx.tech wrote:
> From: Jo?o Peixoto <joaopeixoto at osyx.tech>
> 
> Add MAINTAINERS entries for the Bao hypervisor components including:
> - Bao IPC shared memory driver and its device tree bindings
> - Bao I/O dispatcher driver and its device tree bindings
> - Kernel headers for Bao (ARM, ARM64, and RISC-V)
> - UAPI header

This is irrelevant.

> 
> This ensures that the kernel review and notification system correctly
> identifies the maintainers for all Bao hypervisor components in the
> kernel tree.


This is irrelevant as well. Write concise yet useful commit msgs.

Best regards,
Krzysztof


From krzk at kernel.org  Thu Dec 25 00:57:34 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 25 Dec 2025 09:57:34 +0100
Subject: [PATCH 1/5] dt-bindings: Add Bao IPC shared memory driver binding
In-Reply-To: <20251224135217.25350-2-joaopeixoto@osyx.tech>
References: <20251224135217.25350-1-joaopeixoto@osyx.tech>
 <20251224135217.25350-2-joaopeixoto@osyx.tech>
Message-ID: <20251225-translucent-radical-coot-d3f9ee@quoll>

On Wed, Dec 24, 2025 at 01:52:13PM +0000, joaopeixoto at osyx.tech wrote:
> From: Jo?o Peixoto <joaopeixoto at osyx.tech>
> 
> This patch adds a Device Tree binding for the Bao IPC shared memory
> device, which provides a standardized description of the hardware
> interface used for inter-VM communication in Bao-based systems.
> 

All you emails bounced as spam, so you need tofix your email setup. I
found this only via lore.

> The binding documents the following properties:
> 
>   - compatible: "bao,ipcshmem"
>   - reg: Memory region for the shared memory device
>   - id: Unique device identifier
>   - read-channel: [offset, size] for reading from the shared memory
>   - write-channel: [offset, size] for writing to the shared memory
>   - interrupts: Interrupts used by the device

Irrelevant. Drop.

> 
> This enables kernel drivers and userspace tools to correctly
> instantiate and configure Bao IPC shared memory devices based
> on the DT description, facilitating efficient communication
> between VMs.
> 

Irrelevant. Describe hardware.

> Signed-off-by: Jo?o Peixoto <joaopeixoto at osyx.tech>
> ---
>  .../devicetree/bindings/bao/ipcshmem.yaml     | 99 +++++++++++++++++++
>  .../devicetree/bindings/vendor-prefixes.yaml  |  2 +
>  2 files changed, 101 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/bao/ipcshmem.yaml


Filename matching compatible.
> 
> diff --git a/Documentation/devicetree/bindings/bao/ipcshmem.yaml b/Documentation/devicetree/bindings/bao/ipcshmem.yaml
> new file mode 100644
> index 000000000000..398ac610c29f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/bao/ipcshmem.yaml
> @@ -0,0 +1,99 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: "http://devicetree.org/schemas/bao/ipcshmem.yaml#"
> +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
> +
> +title: Bao IPC Shared Memory Device
> +
> +maintainers:
> +  - Jos? Martins <jose at osyx.tech>
> +  - David Cerdeira <davidmcerdeira at osyx.tech>
> +  - Jo?o Peixoto <joaopeixoto at osyx.tech>
> +
> +description: |
> +  Shared memory based communication device for Bao hypervisor guests.
> +  It allows the kernel to interface with guests running under
> +	the Bao hypervisor, providing a character device interface
> +	for exchanging data through dedicated shared-memory regions.
> +
> +properties:
> +  compatible:
> +    const: "bao,ipcshmem"
> +
> +  reg:
> +    description: |
> +      Memory resource for the shared memory device.
> +    maxItems: 4
> +    type: array
> +    items:
> +      type: integer


Don't send us LLM junk. Nothing here is even close to proper bindings,
which means:

1. You did not write it yourself, because it is impossible to come with
syntax like that (just does not exist),

2. Did not even bother to test it.


Best regards,
Krzysztof



From krzk at kernel.org  Thu Dec 25 00:58:48 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 25 Dec 2025 09:58:48 +0100
Subject: [PATCH 3/5] dt-bindings: Add Bao I/O dispatcher driver binding
In-Reply-To: <20251224135217.25350-4-joaopeixoto@osyx.tech>
References: <20251224135217.25350-1-joaopeixoto@osyx.tech>
 <20251224135217.25350-4-joaopeixoto@osyx.tech>
Message-ID: <20251225-modest-faithful-mouflon-1c7d63@quoll>

On Wed, Dec 24, 2025 at 01:52:15PM +0000, joaopeixoto at osyx.tech wrote:
> From: Jo?o Peixoto <joaopeixoto at osyx.tech>
> 
> This patch adds a Device Tree binding for the Bao I/O Dispatcher kernel
> module, which can be loaded into backend VMs. The I/O Dispatcher
> provides the bridge between the Bao hypervisor Remote I/O system and the
> frontend device model in userspace, offering a unified API to support
> various VirtIO backends.
> 
> The dispatcher handles hypercalls to the Bao hypervisor, IRQ/eventfd
> forwarding, and provides a character device interface for frontend
> devices, enabling efficient communication between the hypervisor and
> userspace device models.
> 
> The binding documents the following properties:
>   - compatible: "bao,io-dispatcher"
>   - reg: Memory regions for the dispatcher (multiple VirtIO devices)
>   - interrupts: Interrupts used by the devices
>   - interrupt-parent: Parent interrupt controller
> 
> This enables kernel drivers to correctly instantiate and configure Bao
> I/O Dispatcher modules based on the DT description.
> 
> Signed-off-by: Jo?o Peixoto <joaopeixoto at osyx.tech>
> ---
>  .../bindings/bao/io-dispatcher.yaml           | 67 +++++++++++++++++++
>  1 file changed, 67 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/bao/io-dispatcher.yaml
> 
> diff --git a/Documentation/devicetree/bindings/bao/io-dispatcher.yaml b/Documentation/devicetree/bindings/bao/io-dispatcher.yaml
> new file mode 100644
> index 000000000000..7795f55d3ff9
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/bao/io-dispatcher.yaml
> @@ -0,0 +1,67 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: "http://devicetree.org/schemas/bao/io-dispatcher.yaml#"

You did not even bother to test it.

> +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
> +
> +title: Bao I/O Dispatcher Device
> +
> +maintainers:
> +  - Jo?o Peixoto <joaopeixoto at osyx.tech>
> +  - Jos? Martins <jose at osyx.tech>
> +  - David Cerdeira <davidmcerdeira at osyx.tech>
> +
> +description: |
> +  I/O Dispatcher device for Bao hypervisor guests. Handles multiple VirtIO
> +  backend devices and their interrupts.
> +
> +properties:
> +  compatible:
> +    const: "bao,io-dispatcher"
> +    description: Device compatible string.
> +
> +  reg:
> +    description: |
> +      Memory regions for each VirtIO backend device.
> +    maxItems: 20
> +    type: array
> +    items:
> +      type: integer

Don't send us LLM junk. You cannot come with such syntax, it does
not exist. Sending such LLM output is disregard to our time.

NAK


Best regards,
Krzysztof



From krzk at kernel.org  Thu Dec 25 01:02:15 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 25 Dec 2025 10:02:15 +0100
Subject: [PATCH 2/5] virt: add Bao IPC shared memory driver
In-Reply-To: <20251224135217.25350-3-joaopeixoto@osyx.tech>
References: <20251224135217.25350-1-joaopeixoto@osyx.tech>
 <20251224135217.25350-3-joaopeixoto@osyx.tech>
Message-ID: <20251225-nippy-umber-inchworm-ced095@quoll>

On Wed, Dec 24, 2025 at 01:52:14PM +0000, joaopeixoto at osyx.tech wrote:
> From: Jo?o Peixoto <joaopeixoto at osyx.tech>
> 
> Add a new driver providing an interface for communication with guests
> hosted by the Bao hypervisor using shared-memory channels. The driver
> exposes read/write regions defined in device tree and notifies the
> hypervisor via an architecture-specific hypercall (SMC/HVC on ARM and
> SBI ecall on RISC-V).
> 
> The patch introduces:
>   - drivers/bao/ with the initial Bao IPC shared-memory implementation
>   - Kconfig entry enabling BAO_SHMEM
>   - Makefile integration for building the driver
>   - A character device interface supporting mmap(), read(), and write()
>   - Platform driver support using DT properties for channel layout
> 
> Each device instance maps its assigned shared-memory region, validates
> read/write channel configuration, and exposes a /dev/baoipc<N> node
> used by user space to exchange data with Bao guests.
> 
> Signed-off-by: Jo?o Peixoto <joaopeixoto at osyx.tech>
> ---
>  drivers/virt/Kconfig                 |   2 +
>  drivers/virt/Makefile                |   1 +
>  drivers/virt/bao/Kconfig             |   3 +
>  drivers/virt/bao/Makefile            |   3 +
>  drivers/virt/bao/ipcshmem/Kconfig    |   9 +
>  drivers/virt/bao/ipcshmem/Makefile   |   3 +
>  drivers/virt/bao/ipcshmem/ipcshmem.c | 539 +++++++++++++++++++++++++++
>  7 files changed, 560 insertions(+)
>  create mode 100644 drivers/virt/bao/Kconfig
>  create mode 100644 drivers/virt/bao/Makefile
>  create mode 100644 drivers/virt/bao/ipcshmem/Kconfig
>  create mode 100644 drivers/virt/bao/ipcshmem/Makefile
>  create mode 100644 drivers/virt/bao/ipcshmem/ipcshmem.c
> 
> diff --git a/drivers/virt/Kconfig b/drivers/virt/Kconfig
> index 52eb7e4ba71f..cb98c4c52fd1 100644
> --- a/drivers/virt/Kconfig
> +++ b/drivers/virt/Kconfig
> @@ -47,6 +47,8 @@ source "drivers/virt/nitro_enclaves/Kconfig"
>  
>  source "drivers/virt/acrn/Kconfig"
>  
> +source "drivers/virt/bao/Kconfig"
> +
>  endif
>  
>  source "drivers/virt/coco/Kconfig"
> diff --git a/drivers/virt/Makefile b/drivers/virt/Makefile
> index f29901bd7820..623a671f8711 100644
> --- a/drivers/virt/Makefile
> +++ b/drivers/virt/Makefile
> @@ -10,3 +10,4 @@ obj-y				+= vboxguest/
>  obj-$(CONFIG_NITRO_ENCLAVES)	+= nitro_enclaves/
>  obj-$(CONFIG_ACRN_HSM)		+= acrn/
>  obj-y				+= coco/
> +obj-$(CONFIG_BAO_SHMEM)		+= bao/
> diff --git a/drivers/virt/bao/Kconfig b/drivers/virt/bao/Kconfig
> new file mode 100644
> index 000000000000..4f7929d57475
> --- /dev/null
> +++ b/drivers/virt/bao/Kconfig
> @@ -0,0 +1,3 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +source "drivers/virt/bao/ipcshmem/Kconfig"
> diff --git a/drivers/virt/bao/Makefile b/drivers/virt/bao/Makefile
> new file mode 100644
> index 000000000000..68f5d3f282c4
> --- /dev/null
> +++ b/drivers/virt/bao/Makefile
> @@ -0,0 +1,3 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +obj-$(CONFIG_BAO_SHMEM) += ipcshmem/
> diff --git a/drivers/virt/bao/ipcshmem/Kconfig b/drivers/virt/bao/ipcshmem/Kconfig
> new file mode 100644
> index 000000000000..42690073e819
> --- /dev/null
> +++ b/drivers/virt/bao/ipcshmem/Kconfig
> @@ -0,0 +1,9 @@
> +# SPDX-License-Identifier: GPL-2.0
> +config BAO_SHMEM
> +	tristate "Bao hypervisor shared memory support"
> +
> +	help
> +	This enables support for Bao shared memory communication.
> +	It allows the kernel to interface with guests running under
> +	the Bao hypervisor, providing a character device interface
> +	for exchanging data through dedicated shared-memory regions.
> diff --git a/drivers/virt/bao/ipcshmem/Makefile b/drivers/virt/bao/ipcshmem/Makefile
> new file mode 100644
> index 000000000000..e027dcdb06aa
> --- /dev/null
> +++ b/drivers/virt/bao/ipcshmem/Makefile
> @@ -0,0 +1,3 @@
> +# SPDX-License-Identifier: GPL-2.0
> +obj-$(CONFIG_BAO_SHMEM) += bao.o
> +bao-objs += ipcshmem.o
> diff --git a/drivers/virt/bao/ipcshmem/ipcshmem.c b/drivers/virt/bao/ipcshmem/ipcshmem.c
> new file mode 100644
> index 000000000000..cadb79bfca6e
> --- /dev/null
> +++ b/drivers/virt/bao/ipcshmem/ipcshmem.c
> @@ -0,0 +1,539 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Bao Hypervisor IPC Through Shared-memory Driver
> + *
> + * Copyright (c) Bao Project and Contributors. All rights reserved.
> + *
> + * Authors:
> + *	David Cerdeira <davidmcerdeira at osyx.tech>
> + *	Jos? Martins <jose at osyx.tech>
> + *	Jo?o Peixoto <joaopeixoto at osyx.tech>
> + */
> +
> +#include <linux/types.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/uaccess.h>
> +#include <linux/fs.h>
> +#include <linux/io.h>
> +#include <linux/ioport.h>
> +#include <linux/interrupt.h>
> +#include <linux/of.h>
> +#include <linux/io.h>
> +#include <linux/mutex.h>
> +#include <linux/poll.h>
> +#include <linux/platform_device.h>
> +#include <linux/ioctl.h>
> +#include <linux/cdev.h>
> +#include <linux/device.h>
> +#include <linux/spinlock.h>
> +#include <linux/mutex.h>
> +#include <linux/wait.h>
> +#include <linux/mm.h>
> +
> +#if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
> +#include <linux/arm-smccc.h>
> +#include <asm/memory.h>
> +#elif CONFIG_RISCV
> +#include <asm/sbi.h>
> +#endif
> +
> +#define DEV_NAME "baoipc"
> +#define MAX_DEVICES 16
> +#define NAME_LEN 32
> +
> +static dev_t bao_ipcshmem_devt;
> +struct class *cl;
> +
> +/**
> + * struct bao_ipcshmem - Bao IPC shared memory device
> + * @cdev: Character device interface
> + * @dev: Device structure
> + * @id: Device instance ID
> + * @label: Name/label of the device
> + * @read_base: Base address of the read channel
> + * @read_size: Size of the read channel
> + * @write_base: Base address of the write channel
> + * @write_size: Size of the write channel
> + * @physical_base: Physical memory base address
> + * @shmem_size: Total size of the shared memory region
> + */
> +struct bao_ipcshmem {
> +	struct cdev cdev;
> +	struct device *dev;
> +	int id;
> +	char label[NAME_LEN];
> +	void *read_base;
> +	size_t read_size;
> +	void *write_base;
> +	size_t write_size;
> +	phys_addr_t *physical_base;
> +	size_t shmem_size;
> +};
> +
> +#ifdef CONFIG_ARM64

No ifdefs. Read Linux coding style first.

> +/**
> + * bao_ipcshmem_notify - Notify the Bao hypervisor of an IPC shared memory event (ARM64)
> + * @dev: IPC shared memory device
> + *
> + * Executes a fast SMC hypercall to notify the hypervisor of an event
> + * associated with the given IPC shared memory device.
> + *
> + * Return: Hypercall return value.
> + */
> +static uint64_t bao_ipcshmem_notify(struct bao_ipcshmem *dev)
> +{
> +	register uint64_t x0 asm("x0") =
> +		ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64,
> +				   ARM_SMCCC_OWNER_VENDOR_HYP, 1);
> +	register uint64_t x1 asm("x1") = dev->id;
> +	register uint64_t x2 asm("x2") = 0;
> +
> +	asm volatile("hvc 0\t\n" : "=r"(x0) : "r"(x0), "r"(x1), "r"(x2));
> +
> +	return x0;
> +}
> +#elif CONFIG_ARM
> +/**
> + * bao_ipcshmem_notify - Notify the Bao hypervisor of an IPC shared memory event (ARM)
> + * @dev: IPC shared memory device
> + *
> + * Executes a fast SMC hypercall to notify the hypervisor of an event
> + * associated with the given IPC shared memory device.
> + *
> + * Return: Hypercall return value.
> + */
> +static uint32_t bao_ipcshmem_notify(struct bao_ipcshmem *dev)
> +{
> +	register uint32_t r0 asm("r0") =
> +		ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32,
> +				   ARM_SMCCC_OWNER_VENDOR_HYP, 1);
> +	register uint32_t r1 asm("r1") = dev->id;
> +	register uint32_t r2 asm("r2") = 0;
> +
> +	asm volatile("hvc #0\t\n" : "=r"(r0) : "r"(r0), "r"(r1), "r"(r2));
> +
> +	return r0;
> +}
> +#elif CONFIG_RISCV
> +/**
> + * bao_ipcshmem_notify - Notify the Bao hypervisor of an IPC shared memory event (RISC-V)
> + * @dev: IPC shared memory device
> + *
> + * Executes an SBI call to notify the Bao hypervisor of an IPC shared memory event.
> + *
> + * Return: SBI call error code.
> + */
> +static uint64_t bao_ipcshmem_notify(struct bao_ipcshmem *dev)
> +{
> +	struct sbiret ret = sbi_ecall(0x08000ba0, 1, dev->id, 0, 0, 0, 0, 0);
> +
> +	return ret.error;
> +}
> +#endif
> +
> +/**
> + * bao_ipcshmem_mmap_fops - mmap handler for IPC shared memory
> + * @filp: File pointer
> + * @vma: Virtual memory area
> + *
> + * Maps the physical shared memory of the Bao IPC device into
> + * userspace using remap_pfn_range.
> + *
> + * Return: 0 on success, -EFAULT on failure.
> + */
> +static int bao_ipcshmem_mmap_fops(struct file *filp, struct vm_area_struct *vma)
> +{
> +	struct bao_ipcshmem *bao = filp->private_data;
> +	unsigned long vsize = vma->vm_end - vma->vm_start;
> +	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
> +	phys_addr_t paddr;
> +
> +	if (WARN_ON_ONCE(!bao))
> +		return -ENODEV;
> +
> +	if (!vsize)
> +		return -EINVAL;
> +
> +	if (offset >= bao->shmem_size)
> +		return -EINVAL;
> +
> +	if (vsize > bao->shmem_size - offset)
> +		return -EINVAL;
> +
> +	paddr = (phys_addr_t)bao->physical_base + offset;
> +
> +	if (!PAGE_ALIGNED(paddr))
> +		return -EINVAL;
> +
> +	if (remap_pfn_range(vma, vma->vm_start,
> +			    paddr >> PAGE_SHIFT,
> +			    vsize, vma->vm_page_prot))
> +		return -EFAULT;
> +
> +	return 0;
> +}
> +
> +/**
> + * bao_ipcshmem_read_fops - read handler for IPC shared memory
> + * @filp: File pointer
> + * @buf: Userspace buffer
> + * @count: Number of bytes to read
> + * @ppos: File offset
> + *
> + * Copies data from the Bao IPC read buffer to userspace.
> + *
> + * Return: Number of bytes read, or 0 if EOF.
> + */
> +static ssize_t bao_ipcshmem_read_fops(struct file *filp, char __user *buf,
> +				      size_t count, loff_t *ppos)
> +{
> +	struct bao_ipcshmem *bao = filp->private_data;
> +	size_t available;
> +
> +	if (WARN_ON_ONCE(!bao || !buf || !ppos))
> +		return -EINVAL;
> +
> +	if (*ppos >= bao->read_size)
> +		return 0;
> +
> +	available = bao->read_size - *ppos;
> +	if (count > available)
> +		count = available;
> +
> +	if (copy_to_user(buf, bao->read_base + *ppos, count))
> +		return -EFAULT;
> +
> +	*ppos += count;
> +	return count;
> +}
> +
> +/**
> + * bao_ipcshmem_write_fops - write handler for IPC shared memory
> + * @filp: File pointer
> + * @buf: Userspace buffer
> + * @count: Number of bytes to write
> + * @ppos: File offset
> + *
> + * Copies data from userspace to the Bao IPC write buffer and
> + * notifies the hypervisor of the update.
> + *
> + * Return: Number of bytes written.
> + */
> +static ssize_t bao_ipcshmem_write_fops(struct file *filp, const char __user *buf,
> +				       size_t count, loff_t *ppos)
> +{
> +	struct bao_ipcshmem *bao = filp->private_data;
> +	size_t avail;
> +
> +	if (WARN_ON_ONCE(!bao || !buf || !ppos))
> +		return -EINVAL;
> +
> +	if (*ppos >= bao->write_size)
> +		return 0;
> +
> +	avail = bao->write_size - *ppos;
> +	if (count > avail)
> +		count = avail;
> +
> +	if (copy_from_user(bao->write_base + *ppos, buf, count))
> +		return -EFAULT;
> +
> +	*ppos += count;
> +
> +	/* Notify any listeners that new data is available */
> +	bao_ipcshmem_notify(bao);
> +
> +	return count;
> +}
> +
> +/**
> + * bao_ipcshmem_open_fops - open handler for IPC shared memory
> + * @inode: Inode pointer
> + * @filp: File pointer
> + *
> + * Associates the file with the Bao IPC device and increments
> + * the kobject reference.
> + *
> + * Return: 0 on success.
> + */
> +static int bao_ipcshmem_open_fops(struct inode *inode, struct file *filp)
> +{
> +	struct bao_ipcshmem *bao;
> +
> +	if (WARN_ON_ONCE(!inode || !filp))
> +		return -EINVAL;
> +
> +	bao = container_of(inode->i_cdev, struct bao_ipcshmem, cdev);
> +	filp->private_data = bao;
> +
> +	kobject_get(&bao->dev->kobj);
> +
> +	return 0;
> +}
> +
> +/**
> + * bao_ipcshmem_release_fops - release handler for IPC shared memory
> + * @inode: Inode pointer
> + * @filp: File pointer
> + *
> + * Disassociates the file from the Bao IPC device and decrements
> + * the kobject reference.
> + *
> + * Return: 0 on success.
> + */
> +static int bao_ipcshmem_release_fops(struct inode *inode, struct file *filp)
> +{
> +	struct bao_ipcshmem *bao;
> +
> +	if (WARN_ON_ONCE(!inode || !filp))
> +		return -EINVAL;
> +
> +	bao = container_of(inode->i_cdev, struct bao_ipcshmem, cdev);
> +	filp->private_data = NULL;
> +
> +	kobject_put(&bao->dev->kobj);
> +
> +	return 0;
> +}
> +
> +static const struct file_operations bao_ipcshmem_fops = {
> +	.owner = THIS_MODULE,
> +	.read = bao_ipcshmem_read_fops,
> +	.write = bao_ipcshmem_write_fops,
> +	.mmap = bao_ipcshmem_mmap_fops,
> +	.open = bao_ipcshmem_open_fops,
> +	.release = bao_ipcshmem_release_fops
> +};
> +
> +/**
> + * bao_ipcshmem_register - Register a Bao IPC shared memory device
> + * @pdev: Platform device
> + *
> + * Maps the shared memory region, validates channel layout, initializes
> + * the read/write buffers, registers the character device, and creates
> + * the sysfs device entry.
> + *
> + * Return: 0 on success, negative error code on failure.
> + */
> +static int bao_ipcshmem_register(struct platform_device *pdev)

NAK, where did you get it from? Probe functions are ABSOLUTELY NEVER
called register.

> +{
> +	int ret = 0, id = -1;
> +	struct device *dev = &pdev->dev;
> +	struct device_node *np = dev->of_node;
> +	struct module *owner = THIS_MODULE;
> +	struct resource *r;
> +	dev_t devt;

No, read Linux coding style.

> +	resource_size_t shmem_size;
> +	u32 write_offset, read_offset, write_size, read_size;
> +	bool rd_in_range, wr_in_range, disjoint;
> +	void *shmem_base_addr = NULL;
> +	struct bao_ipcshmem *bao;

This is really poor coding style, barely readable and maintainable. You
need to rewtite this driver completely to match what we expect in Linux
kernel, for example base your work on last, reviewed code.

I am not even looking at rest of this - please prove that you value our
time by sending something following Linux kernel style.

Best regards,
Krzysztof



From wens at kernel.org  Thu Dec 25 01:07:38 2025
From: wens at kernel.org (Chen-Yu Tsai)
Date: Thu, 25 Dec 2025 17:07:38 +0800
Subject: [PATCH] dt-bindings: Remove unused includes
In-Reply-To: <20251212231203.727227-1-robh@kernel.org>
References: <20251212231203.727227-1-robh@kernel.org>
Message-ID: <CAGb2v65Pt=c7rNtE-u7j_=SbT4DLw03iOw=PFchbisPQenhOtg@mail.gmail.com>

On Sat, Dec 13, 2025 at 7:12?AM Rob Herring (Arm) <robh at kernel.org> wrote:
>
> Remove includes which are not referenced by either DTS files or drivers.
>
> There's a few more which are new, so they are excluded for now.
>
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
> ---
>  include/dt-bindings/clock/oxsemi,ox810se.h    |  19 --
>  include/dt-bindings/clock/oxsemi,ox820.h      |  29 --
>  include/dt-bindings/clock/qcom,mss-sc7180.h   |  12 -
>  include/dt-bindings/clock/xlnx-versal-clk.h   | 123 ---------
>  include/dt-bindings/clock/xlnx-zynqmp-clk.h   | 133 ---------
>  include/dt-bindings/dma/jz4775-dma.h          |  44 ---
>  include/dt-bindings/dma/x2000-dma.h           |  54 ----
>  include/dt-bindings/gce/mt6779-gce.h          | 222 ---------------
>  .../dt-bindings/iio/qcom,spmi-adc7-pmr735b.h  |  30 --
>  .../dt-bindings/iio/qcom,spmi-adc7-smb139x.h  |  19 --
>  include/dt-bindings/memory/mt6779-larb-port.h | 206 --------------
>  include/dt-bindings/mux/ti-serdes.h           | 190 -------------
>  include/dt-bindings/pinctrl/mt6397-pinfunc.h  | 257 ------------------
>  .../power/allwinner,sun20i-d1-ppu.h           |  10 -

For this one, a node is present in the DT, but there are currently no
references to it, and thus no users of the header.

Also this chip hasn't seen a lot of interest after it was initially
brought up. None of the peripherals that have a separate power
domain have been enabled.


ChenYu


From krzk at kernel.org  Thu Dec 25 01:12:23 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 25 Dec 2025 10:12:23 +0100
Subject: [PATCH 4/5] virt: add Bao I/O dispatcher driver
In-Reply-To: <20251224135217.25350-5-joaopeixoto@osyx.tech>
References: <20251224135217.25350-1-joaopeixoto@osyx.tech>
 <20251224135217.25350-5-joaopeixoto@osyx.tech>
Message-ID: <20251225-friendly-raptor-of-lightning-fbafc4@quoll>

On Wed, Dec 24, 2025 at 01:52:16PM +0000, joaopeixoto at osyx.tech wrote:
> +static const struct of_device_id bao_io_dispatcher_driver_dt_ids[] = {
> +	{ .compatible = "bao,io-dispatcher" },
> +	{ /* sentinel */ }
> +};
> +
> +MODULE_DEVICE_TABLE(of, bao_io_dispatcher_driver_dt_ids);
> +
> +static struct platform_driver bao_io_dispatcher_driver = {
> +	.probe = bao_io_dispatcher_driver_register,
> +	.remove = bao_io_dispatcher_driver_unregister,
> +	.driver = {
> +		   .name = "bao-io-dispatcher",
> +		   .of_match_table =
> +		   of_match_ptr(bao_io_dispatcher_driver_dt_ids),

You have warnings here. Do extensive building of your code before
sending.

> +		   .owner = THIS_MODULE,

NAK

Don't send us 12-year-old vendor code. Tools already report this,
so you just did not run them...

Nothing here is evn formatted correctly...

Best regards,
Krzysztof



From wens at kernel.org  Thu Dec 25 01:29:24 2025
From: wens at kernel.org (Chen-Yu Tsai)
Date: Thu, 25 Dec 2025 17:29:24 +0800
Subject: [PATCH 5/7] drm/sun4i: Add planes driver
In-Reply-To: <20251115141347.13087-6-jernej.skrabec@gmail.com>
References: <20251115141347.13087-1-jernej.skrabec@gmail.com> <20251115141347.13087-6-jernej.skrabec@gmail.com>
Message-ID: <CAGb2v65wY2pF6sR+0JgnpLa4ysvjght5hAKDa1RUyo=zEKXreg@mail.gmail.com>

On Sat, Nov 15, 2025 at 10:14?PM Jernej Skrabec
<jernej.skrabec at gmail.com> wrote:
>
> This driver serves just as planes sharing manager, needed for Display
> Engine 3.3 and newer.
>
> Signed-off-by: Jernej Skrabec <jernej.skrabec at gmail.com>
> ---
>  drivers/gpu/drm/sun4i/Kconfig         |   8 +
>  drivers/gpu/drm/sun4i/Makefile        |   1 +
>  drivers/gpu/drm/sun4i/sun50i_planes.c | 205 ++++++++++++++++++++++++++
>  drivers/gpu/drm/sun4i/sun50i_planes.h |  43 ++++++
>  4 files changed, 257 insertions(+)
>  create mode 100644 drivers/gpu/drm/sun4i/sun50i_planes.c
>  create mode 100644 drivers/gpu/drm/sun4i/sun50i_planes.h
>
> diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig
> index b56ba00aabca..946dd7606094 100644
> --- a/drivers/gpu/drm/sun4i/Kconfig
> +++ b/drivers/gpu/drm/sun4i/Kconfig
> @@ -85,4 +85,12 @@ config DRM_SUN8I_TCON_TOP
>           TCON TOP is responsible for configuring display pipeline for
>           HDMI, TVE and LCD.
>
> +config DRM_SUN50I_PLANES
> +       tristate
> +       default DRM_SUN4I if DRM_SUN8I_MIXER!=n
> +       help
> +         Chose this option if you have an Allwinner Soc with the
> +         Display Engine 3.3 or newer. Planes are shared resource
> +         between multiple mixers.
> +
>  endif
> diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
> index bad7497a0d11..03f002abef15 100644
> --- a/drivers/gpu/drm/sun4i/Makefile
> +++ b/drivers/gpu/drm/sun4i/Makefile
> @@ -38,3 +38,4 @@ obj-$(CONFIG_DRM_SUN6I_DSI)   += sun6i_mipi_dsi.o
>  obj-$(CONFIG_DRM_SUN8I_DW_HDMI)        += sun8i-drm-hdmi.o
>  obj-$(CONFIG_DRM_SUN8I_MIXER)  += sun8i-mixer.o
>  obj-$(CONFIG_DRM_SUN8I_TCON_TOP) += sun8i_tcon_top.o
> +obj-$(CONFIG_DRM_SUN50I_PLANES)        += sun50i_planes.o

I don't think you can have this as a separate module:

a. You are using sun8i_vi_layer_init_one() and sun8i_ui_layer_init_one()
   from the sun8i-mixer module, and neither of them are exported symbols.

b. You export sun50i_planes_setup() for sun8i-mixer to call, which ends
   up becoming a circular dependency.

The easiest solution would be to just fold this into the sun8i-mixer module.


> diff --git a/drivers/gpu/drm/sun4i/sun50i_planes.c b/drivers/gpu/drm/sun4i/sun50i_planes.c
> new file mode 100644
> index 000000000000..a99c01122990
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun50i_planes.c
> @@ -0,0 +1,205 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/* Copyright (c) 2025 Jernej Skrabec <jernej.skrabec at gmail.com> */
> +
> +#include <linux/device.h>
> +#include <linux/io.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_graph.h>
> +#include <linux/platform_device.h>
> +
> +#include "sun50i_planes.h"
> +#include "sun8i_ui_layer.h"
> +#include "sun8i_vi_layer.h"
> +
> +static bool sun50i_planes_node_is_planes(struct device_node *node)
> +{
> +       return !!of_match_node(sun50i_planes_of_table, node);
> +}
> +
> +struct drm_plane **
> +sun50i_planes_setup(struct device *dev, struct drm_device *drm,
> +                   unsigned int mixer)
> +{
> +       struct sun50i_planes *planes = dev_get_drvdata(dev);
> +       const struct sun50i_planes_quirks *quirks;
> +       struct drm_plane **drm_planes;
> +       const struct default_map *map;
> +       unsigned int i;
> +
> +       if (!sun50i_planes_node_is_planes(dev->of_node)) {
> +               dev_err(dev, "Device is not planes driver!\n");
> +               return NULL;
> +       }
> +
> +       if (!planes) {
> +               dev_err(dev, "Planes driver is not loaded yet!\n");
> +               return NULL;
> +       }
> +
> +       if (mixer > 1) {
> +               dev_err(dev, "Mixer index is too high!\n");
> +               return NULL;
> +       }
> +
> +       quirks = planes->quirks;
> +       map = &quirks->def_map[mixer];
> +
> +       drm_planes = devm_kcalloc(drm->dev, map->num_ch + 1,

Just a note: it seems we are missing the sentinel in sun8i_layers_init().

> +                                 sizeof(*drm_planes), GFP_KERNEL);
> +       if (!drm_planes)
> +               return ERR_PTR(-ENOMEM);
> +
> +       for (i = 0; i < map->num_ch; i++) {
> +               unsigned int phy_ch = map->map[i];
> +               struct sun8i_layer *layer;
> +               enum drm_plane_type type;
> +
> +               if ((i == 0 && map->num_ch == 1) || i == 1)
> +                       type = DRM_PLANE_TYPE_PRIMARY;
> +               else
> +                       type = DRM_PLANE_TYPE_OVERLAY;
> +
> +               if (phy_ch < UI_PLANE_OFFSET)
> +                       layer = sun8i_vi_layer_init_one(drm, type, planes->regs,
> +                                                       i, phy_ch, map->num_ch,
> +                                                       &quirks->cfg);
> +               else
> +                       layer = sun8i_ui_layer_init_one(drm, type, planes->regs,
> +                                                       i, phy_ch, map->num_ch,
> +                                                       &quirks->cfg);
> +
> +               if (IS_ERR(layer)) {
> +                       dev_err(drm->dev,
> +                               "Couldn't initialize DRM plane\n");
> +                       return ERR_CAST(layer);
> +               }
> +
> +               drm_planes[i] = &layer->plane;
> +       }
> +
> +       return drm_planes;
> +}
> +EXPORT_SYMBOL(sun50i_planes_setup);
> +
> +static void sun50i_planes_init_mapping(struct sun50i_planes *planes)
> +{
> +       const struct sun50i_planes_quirks *quirks = planes->quirks;
> +       unsigned int i, j;
> +       u32 mapping;
> +
> +       mapping = 0;
> +       for (j = 0; j < MAX_DISP; j++)
> +               for (i = 0; i < quirks->def_map[j].num_ch; i++) {
> +                       unsigned int ch = quirks->def_map[j].map[i];
> +
> +                       if (ch < UI_PLANE_OFFSET)
> +                               mapping |= j << (ch * 2);
> +                       else
> +                               mapping |= j << ((ch - UI_PLANE_OFFSET) * 2 + 16);
> +               }
> +       regmap_write(planes->mapping, SUNXI_DE33_DE_CHN2CORE_MUX_REG, mapping);
> +
> +       for (j = 0; j < MAX_DISP; j++) {
> +               mapping = 0;
> +               for (i = 0; i < quirks->def_map[j].num_ch; i++) {
> +                       unsigned int ch = quirks->def_map[j].map[i];
> +
> +                       if (ch >= UI_PLANE_OFFSET)
> +                               ch += 2;
> +
> +                       mapping |= ch << (i * 4);
> +               }
> +               regmap_write(planes->mapping, SUNXI_DE33_DE_PORT02CHN_MUX_REG + j * 4, mapping);
> +       }
> +}
> +
> +static const struct regmap_config sun50i_planes_regmap_config = {
> +       .name           = "planes",
> +       .reg_bits       = 32,
> +       .val_bits       = 32,
> +       .reg_stride     = 4,
> +       .max_register   = 0x17fffc,
> +};
> +
> +static int sun50i_planes_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct sun50i_planes *planes;
> +       void __iomem *regs;
> +
> +       planes = devm_kzalloc(dev, sizeof(*planes), GFP_KERNEL);
> +       if (!planes)
> +               return -ENOMEM;
> +
> +       planes->quirks = of_device_get_match_data(&pdev->dev);
> +       if (!planes->quirks)
> +               return dev_err_probe(dev, -EINVAL, "Unable to get quirks\n");
> +
> +       planes->mapping = syscon_regmap_lookup_by_phandle(dev->of_node,
> +                                                         "allwinner,plane-mapping");
> +       if (IS_ERR(planes->mapping))
> +               return dev_err_probe(dev, PTR_ERR(planes->mapping),
> +                                    "Unable to get mapping\n");
> +
> +       regs = devm_platform_ioremap_resource(pdev, 0);
> +       if (IS_ERR(regs))
> +               return PTR_ERR(regs);
> +
> +       planes->regs = devm_regmap_init_mmio(dev, regs, &sun50i_planes_regmap_config);
> +       if (IS_ERR(planes->regs))
> +               return PTR_ERR(planes->regs);
> +
> +       dev_set_drvdata(dev, planes);
> +
> +       sun50i_planes_init_mapping(planes);
> +
> +       return 0;
> +}
> +
> +static const struct sun50i_planes_quirks sun50i_h616_planes_quirks = {
> +       .def_map = {
> +               {
> +                       .map = {0, 6, 7},
> +                       .num_ch = 3,
> +               },
> +               {
> +                       .map = {1, 2, 8},
> +                       .num_ch = 3,
> +               },
> +       },
> +       .cfg = {
> +               .de_type        = SUN8I_MIXER_DE33,
> +               /*
> +                * TODO: All planes support scaling, but driver needs
> +                * improvements to properly support it.
> +                */
> +               .scaler_mask    = 0,
> +               .scanline_yuv   = 4096,
> +       },
> +};
> +
> +/* sun4i_drv uses this list to check if a device node is a plane */
> +const struct of_device_id sun50i_planes_of_table[] = {
> +       {
> +               .compatible = "allwinner,sun50i-h616-de33-planes",
> +               .data = &sun50i_h616_planes_quirks
> +       },
> +       { }
> +};
> +MODULE_DEVICE_TABLE(of, sun50i_planes_of_table);
> +EXPORT_SYMBOL(sun50i_planes_of_table);
> +
> +static struct platform_driver sun50i_planes_platform_driver = {
> +       .probe          = sun50i_planes_probe,
> +       .driver         = {
> +               .name           = "sun50i-planes",
> +               .of_match_table = sun50i_planes_of_table,
> +       },
> +};
> +module_platform_driver(sun50i_planes_platform_driver);
> +
> +MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec at gmail.com>");
> +MODULE_DESCRIPTION("Allwinner DE33 planes driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/gpu/drm/sun4i/sun50i_planes.h b/drivers/gpu/drm/sun4i/sun50i_planes.h
> new file mode 100644
> index 000000000000..446feaeb03fc
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun50i_planes.h
> @@ -0,0 +1,43 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/* Copyright (c) 2025 Jernej Skrabec <jernej.skrabec at gmail.com> */
> +
> +#ifndef _SUN50I_PLANES_H_
> +#define _SUN50I_PLANES_H_
> +
> +#include <drm/drm_device.h>
> +#include <linux/regmap.h>

I think you could move these two to the .c file, and just use forward
declarations here.

The rest looks OK.


> +
> +#include "sun8i_mixer.h"
> +
> +/* mapping registers, located in clock register space */
> +#define SUNXI_DE33_DE_CHN2CORE_MUX_REG 0x24
> +#define SUNXI_DE33_DE_PORT02CHN_MUX_REG        0x28
> +#define SUNXI_DE33_DE_PORT12CHN_MUX_REG        0x2c
> +
> +#define MAX_DISP       2
> +#define MAX_CHANNELS   8
> +#define UI_PLANE_OFFSET        6
> +
> +struct default_map {
> +       unsigned int map[MAX_CHANNELS];
> +       unsigned int num_ch;
> +};
> +
> +struct sun50i_planes_quirks {
> +       struct default_map      def_map[MAX_DISP];
> +       struct sun8i_layer_cfg  cfg;
> +};
> +
> +struct sun50i_planes {
> +       struct regmap                           *regs;
> +       struct regmap                           *mapping;
> +       const struct sun50i_planes_quirks       *quirks;
> +};
> +
> +extern const struct of_device_id sun50i_planes_of_table[];
> +
> +struct drm_plane **
> +sun50i_planes_setup(struct device *dev, struct drm_device *drm,
> +                   unsigned int mixer);
> +
> +#endif /* _SUN50I_PLANES_H_ */
> --
> 2.51.2
>
>


From wens at kernel.org  Thu Dec 25 01:37:06 2025
From: wens at kernel.org (Chen-Yu Tsai)
Date: Thu, 25 Dec 2025 17:37:06 +0800
Subject: [PATCH 5/7] drm/sun4i: Add planes driver
In-Reply-To: <CAGb2v65wY2pF6sR+0JgnpLa4ysvjght5hAKDa1RUyo=zEKXreg@mail.gmail.com>
References: <20251115141347.13087-1-jernej.skrabec@gmail.com>
 <20251115141347.13087-6-jernej.skrabec@gmail.com> <CAGb2v65wY2pF6sR+0JgnpLa4ysvjght5hAKDa1RUyo=zEKXreg@mail.gmail.com>
Message-ID: <CAGb2v65e2a_f+UEDu-Wk3bWvgHt24erjk+iLWgMAQwB-mzcnaA@mail.gmail.com>

On Thu, Dec 25, 2025 at 5:29?PM Chen-Yu Tsai <wens at kernel.org> wrote:
>
> On Sat, Nov 15, 2025 at 10:14?PM Jernej Skrabec
> <jernej.skrabec at gmail.com> wrote:
> >
> > This driver serves just as planes sharing manager, needed for Display
> > Engine 3.3 and newer.
> >
> > Signed-off-by: Jernej Skrabec <jernej.skrabec at gmail.com>
> > ---
> >  drivers/gpu/drm/sun4i/Kconfig         |   8 +
> >  drivers/gpu/drm/sun4i/Makefile        |   1 +
> >  drivers/gpu/drm/sun4i/sun50i_planes.c | 205 ++++++++++++++++++++++++++
> >  drivers/gpu/drm/sun4i/sun50i_planes.h |  43 ++++++
> >  4 files changed, 257 insertions(+)
> >  create mode 100644 drivers/gpu/drm/sun4i/sun50i_planes.c
> >  create mode 100644 drivers/gpu/drm/sun4i/sun50i_planes.h
> >
> > diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig
> > index b56ba00aabca..946dd7606094 100644
> > --- a/drivers/gpu/drm/sun4i/Kconfig
> > +++ b/drivers/gpu/drm/sun4i/Kconfig
> > @@ -85,4 +85,12 @@ config DRM_SUN8I_TCON_TOP
> >           TCON TOP is responsible for configuring display pipeline for
> >           HDMI, TVE and LCD.
> >
> > +config DRM_SUN50I_PLANES
> > +       tristate
> > +       default DRM_SUN4I if DRM_SUN8I_MIXER!=n
> > +       help
> > +         Chose this option if you have an Allwinner Soc with the
> > +         Display Engine 3.3 or newer. Planes are shared resource
> > +         between multiple mixers.
> > +
> >  endif
> > diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
> > index bad7497a0d11..03f002abef15 100644
> > --- a/drivers/gpu/drm/sun4i/Makefile
> > +++ b/drivers/gpu/drm/sun4i/Makefile
> > @@ -38,3 +38,4 @@ obj-$(CONFIG_DRM_SUN6I_DSI)   += sun6i_mipi_dsi.o
> >  obj-$(CONFIG_DRM_SUN8I_DW_HDMI)        += sun8i-drm-hdmi.o
> >  obj-$(CONFIG_DRM_SUN8I_MIXER)  += sun8i-mixer.o
> >  obj-$(CONFIG_DRM_SUN8I_TCON_TOP) += sun8i_tcon_top.o
> > +obj-$(CONFIG_DRM_SUN50I_PLANES)        += sun50i_planes.o
>
> I don't think you can have this as a separate module:
>
> a. You are using sun8i_vi_layer_init_one() and sun8i_ui_layer_init_one()
>    from the sun8i-mixer module, and neither of them are exported symbols.
>
> b. You export sun50i_planes_setup() for sun8i-mixer to call, which ends
>    up becoming a circular dependency.
>
> The easiest solution would be to just fold this into the sun8i-mixer module.
>
>
> > diff --git a/drivers/gpu/drm/sun4i/sun50i_planes.c b/drivers/gpu/drm/sun4i/sun50i_planes.c
> > new file mode 100644
> > index 000000000000..a99c01122990
> > --- /dev/null
> > +++ b/drivers/gpu/drm/sun4i/sun50i_planes.c
> > @@ -0,0 +1,205 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/* Copyright (c) 2025 Jernej Skrabec <jernej.skrabec at gmail.com> */
> > +
> > +#include <linux/device.h>
> > +#include <linux/io.h>
> > +#include <linux/mfd/syscon.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/of_graph.h>
> > +#include <linux/platform_device.h>
> > +
> > +#include "sun50i_planes.h"
> > +#include "sun8i_ui_layer.h"
> > +#include "sun8i_vi_layer.h"
> > +
> > +static bool sun50i_planes_node_is_planes(struct device_node *node)
> > +{
> > +       return !!of_match_node(sun50i_planes_of_table, node);
> > +}
> > +
> > +struct drm_plane **
> > +sun50i_planes_setup(struct device *dev, struct drm_device *drm,
> > +                   unsigned int mixer)
> > +{
> > +       struct sun50i_planes *planes = dev_get_drvdata(dev);
> > +       const struct sun50i_planes_quirks *quirks;
> > +       struct drm_plane **drm_planes;
> > +       const struct default_map *map;
> > +       unsigned int i;
> > +
> > +       if (!sun50i_planes_node_is_planes(dev->of_node)) {
> > +               dev_err(dev, "Device is not planes driver!\n");
> > +               return NULL;
> > +       }
> > +
> > +       if (!planes) {
> > +               dev_err(dev, "Planes driver is not loaded yet!\n");
> > +               return NULL;
> > +       }
> > +
> > +       if (mixer > 1) {
> > +               dev_err(dev, "Mixer index is too high!\n");
> > +               return NULL;
> > +       }
> > +
> > +       quirks = planes->quirks;
> > +       map = &quirks->def_map[mixer];
> > +
> > +       drm_planes = devm_kcalloc(drm->dev, map->num_ch + 1,
>
> Just a note: it seems we are missing the sentinel in sun8i_layers_init().
>
> > +                                 sizeof(*drm_planes), GFP_KERNEL);
> > +       if (!drm_planes)
> > +               return ERR_PTR(-ENOMEM);
> > +
> > +       for (i = 0; i < map->num_ch; i++) {
> > +               unsigned int phy_ch = map->map[i];
> > +               struct sun8i_layer *layer;
> > +               enum drm_plane_type type;
> > +
> > +               if ((i == 0 && map->num_ch == 1) || i == 1)
> > +                       type = DRM_PLANE_TYPE_PRIMARY;
> > +               else
> > +                       type = DRM_PLANE_TYPE_OVERLAY;
> > +
> > +               if (phy_ch < UI_PLANE_OFFSET)
> > +                       layer = sun8i_vi_layer_init_one(drm, type, planes->regs,
> > +                                                       i, phy_ch, map->num_ch,
> > +                                                       &quirks->cfg);
> > +               else
> > +                       layer = sun8i_ui_layer_init_one(drm, type, planes->regs,
> > +                                                       i, phy_ch, map->num_ch,
> > +                                                       &quirks->cfg);
> > +
> > +               if (IS_ERR(layer)) {
> > +                       dev_err(drm->dev,
> > +                               "Couldn't initialize DRM plane\n");
> > +                       return ERR_CAST(layer);
> > +               }
> > +
> > +               drm_planes[i] = &layer->plane;
> > +       }
> > +
> > +       return drm_planes;
> > +}
> > +EXPORT_SYMBOL(sun50i_planes_setup);
> > +
> > +static void sun50i_planes_init_mapping(struct sun50i_planes *planes)
> > +{
> > +       const struct sun50i_planes_quirks *quirks = planes->quirks;
> > +       unsigned int i, j;
> > +       u32 mapping;
> > +
> > +       mapping = 0;
> > +       for (j = 0; j < MAX_DISP; j++)
> > +               for (i = 0; i < quirks->def_map[j].num_ch; i++) {
> > +                       unsigned int ch = quirks->def_map[j].map[i];
> > +
> > +                       if (ch < UI_PLANE_OFFSET)
> > +                               mapping |= j << (ch * 2);
> > +                       else
> > +                               mapping |= j << ((ch - UI_PLANE_OFFSET) * 2 + 16);
> > +               }
> > +       regmap_write(planes->mapping, SUNXI_DE33_DE_CHN2CORE_MUX_REG, mapping);
> > +
> > +       for (j = 0; j < MAX_DISP; j++) {
> > +               mapping = 0;
> > +               for (i = 0; i < quirks->def_map[j].num_ch; i++) {
> > +                       unsigned int ch = quirks->def_map[j].map[i];
> > +
> > +                       if (ch >= UI_PLANE_OFFSET)
> > +                               ch += 2;
> > +
> > +                       mapping |= ch << (i * 4);
> > +               }
> > +               regmap_write(planes->mapping, SUNXI_DE33_DE_PORT02CHN_MUX_REG + j * 4, mapping);
> > +       }
> > +}
> > +
> > +static const struct regmap_config sun50i_planes_regmap_config = {
> > +       .name           = "planes",
> > +       .reg_bits       = 32,
> > +       .val_bits       = 32,
> > +       .reg_stride     = 4,
> > +       .max_register   = 0x17fffc,
> > +};
> > +
> > +static int sun50i_planes_probe(struct platform_device *pdev)
> > +{
> > +       struct device *dev = &pdev->dev;
> > +       struct sun50i_planes *planes;
> > +       void __iomem *regs;
> > +
> > +       planes = devm_kzalloc(dev, sizeof(*planes), GFP_KERNEL);
> > +       if (!planes)
> > +               return -ENOMEM;
> > +
> > +       planes->quirks = of_device_get_match_data(&pdev->dev);
> > +       if (!planes->quirks)
> > +               return dev_err_probe(dev, -EINVAL, "Unable to get quirks\n");
> > +
> > +       planes->mapping = syscon_regmap_lookup_by_phandle(dev->of_node,
> > +                                                         "allwinner,plane-mapping");
> > +       if (IS_ERR(planes->mapping))
> > +               return dev_err_probe(dev, PTR_ERR(planes->mapping),
> > +                                    "Unable to get mapping\n");
> > +
> > +       regs = devm_platform_ioremap_resource(pdev, 0);
> > +       if (IS_ERR(regs))
> > +               return PTR_ERR(regs);
> > +
> > +       planes->regs = devm_regmap_init_mmio(dev, regs, &sun50i_planes_regmap_config);
> > +       if (IS_ERR(planes->regs))
> > +               return PTR_ERR(planes->regs);
> > +
> > +       dev_set_drvdata(dev, planes);
> > +
> > +       sun50i_planes_init_mapping(planes);
> > +
> > +       return 0;
> > +}
> > +
> > +static const struct sun50i_planes_quirks sun50i_h616_planes_quirks = {
> > +       .def_map = {
> > +               {
> > +                       .map = {0, 6, 7},
> > +                       .num_ch = 3,
> > +               },
> > +               {
> > +                       .map = {1, 2, 8},
> > +                       .num_ch = 3,
> > +               },
> > +       },
> > +       .cfg = {
> > +               .de_type        = SUN8I_MIXER_DE33,
> > +               /*
> > +                * TODO: All planes support scaling, but driver needs
> > +                * improvements to properly support it.
> > +                */
> > +               .scaler_mask    = 0,
> > +               .scanline_yuv   = 4096,
> > +       },
> > +};
> > +
> > +/* sun4i_drv uses this list to check if a device node is a plane */

I didn't see any usage of this in patch 7. Is this part of another
series?

Maybe just export sun50i_planes_node_is_planes() instead?

> > +const struct of_device_id sun50i_planes_of_table[] = {
> > +       {
> > +               .compatible = "allwinner,sun50i-h616-de33-planes",
> > +               .data = &sun50i_h616_planes_quirks
> > +       },
> > +       { }
> > +};
> > +MODULE_DEVICE_TABLE(of, sun50i_planes_of_table);
> > +EXPORT_SYMBOL(sun50i_planes_of_table);
> > +
> > +static struct platform_driver sun50i_planes_platform_driver = {
> > +       .probe          = sun50i_planes_probe,
> > +       .driver         = {
> > +               .name           = "sun50i-planes",
> > +               .of_match_table = sun50i_planes_of_table,
> > +       },
> > +};
> > +module_platform_driver(sun50i_planes_platform_driver);
> > +
> > +MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec at gmail.com>");
> > +MODULE_DESCRIPTION("Allwinner DE33 planes driver");
> > +MODULE_LICENSE("GPL");
> > diff --git a/drivers/gpu/drm/sun4i/sun50i_planes.h b/drivers/gpu/drm/sun4i/sun50i_planes.h
> > new file mode 100644
> > index 000000000000..446feaeb03fc
> > --- /dev/null
> > +++ b/drivers/gpu/drm/sun4i/sun50i_planes.h
> > @@ -0,0 +1,43 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +/* Copyright (c) 2025 Jernej Skrabec <jernej.skrabec at gmail.com> */
> > +
> > +#ifndef _SUN50I_PLANES_H_
> > +#define _SUN50I_PLANES_H_
> > +
> > +#include <drm/drm_device.h>
> > +#include <linux/regmap.h>
>
> I think you could move these two to the .c file, and just use forward
> declarations here.
>
> The rest looks OK.
>
>
> > +
> > +#include "sun8i_mixer.h"
> > +
> > +/* mapping registers, located in clock register space */
> > +#define SUNXI_DE33_DE_CHN2CORE_MUX_REG 0x24
> > +#define SUNXI_DE33_DE_PORT02CHN_MUX_REG        0x28
> > +#define SUNXI_DE33_DE_PORT12CHN_MUX_REG        0x2c
> > +
> > +#define MAX_DISP       2
> > +#define MAX_CHANNELS   8
> > +#define UI_PLANE_OFFSET        6
> > +
> > +struct default_map {
> > +       unsigned int map[MAX_CHANNELS];
> > +       unsigned int num_ch;
> > +};
> > +
> > +struct sun50i_planes_quirks {
> > +       struct default_map      def_map[MAX_DISP];
> > +       struct sun8i_layer_cfg  cfg;
> > +};
> > +
> > +struct sun50i_planes {
> > +       struct regmap                           *regs;
> > +       struct regmap                           *mapping;
> > +       const struct sun50i_planes_quirks       *quirks;
> > +};
> > +
> > +extern const struct of_device_id sun50i_planes_of_table[];
> > +
> > +struct drm_plane **
> > +sun50i_planes_setup(struct device *dev, struct drm_device *drm,
> > +                   unsigned int mixer);
> > +
> > +#endif /* _SUN50I_PLANES_H_ */
> > --
> > 2.51.2
> >
> >


From wens at kernel.org  Thu Dec 25 01:49:47 2025
From: wens at kernel.org (Chen-Yu Tsai)
Date: Thu, 25 Dec 2025 17:49:47 +0800
Subject: [PATCH 7/7] drm/sun4i: switch DE33 to new bindings
In-Reply-To: <20251115141347.13087-8-jernej.skrabec@gmail.com>
References: <20251115141347.13087-1-jernej.skrabec@gmail.com> <20251115141347.13087-8-jernej.skrabec@gmail.com>
Message-ID: <CAGb2v67B_2SMsDbATVu51Ed+2o+6=FRLw7KmjeL1KYgxm=gyDw@mail.gmail.com>

On Sat, Nov 15, 2025 at 10:14?PM Jernej Skrabec
<jernej.skrabec at gmail.com> wrote:
>
> Now that everything is in place, switch DE33 to new bindings.
>
> Signed-off-by: Jernej Skrabec <jernej.skrabec at gmail.com>
> ---
>  drivers/gpu/drm/sun4i/sun8i_mixer.c | 130 +++++++++++++++-------------
>  drivers/gpu/drm/sun4i/sun8i_mixer.h |  10 +--
>  2 files changed, 71 insertions(+), 69 deletions(-)
>
> diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
> index fde3b677e925..da213e54e653 100644
> --- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
> +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
> @@ -13,6 +13,7 @@
>  #include <linux/of.h>
>  #include <linux/of_device.h>
>  #include <linux/of_graph.h>
> +#include <linux/of_platform.h>
>  #include <linux/platform_device.h>
>  #include <linux/reset.h>
>
> @@ -24,6 +25,7 @@
>  #include <drm/drm_probe_helper.h>
>
>  #include "sun4i_drv.h"
> +#include "sun50i_planes.h"
>  #include "sun8i_mixer.h"
>  #include "sun8i_ui_layer.h"
>  #include "sun8i_vi_layer.h"
> @@ -256,7 +258,6 @@ static void sun8i_mixer_commit(struct sunxi_engine *engine,
>  {
>         struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
>         u32 bld_base = sun8i_blender_base(mixer);
> -       struct regmap *bld_regs = sun8i_blender_regmap(mixer);
>         struct drm_plane_state *plane_state;
>         struct drm_plane *plane;
>         u32 route = 0, pipe_en = 0;
> @@ -293,16 +294,16 @@ static void sun8i_mixer_commit(struct sunxi_engine *engine,
>                 route |= layer->index << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos);
>                 pipe_en |= SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos);
>
> -               regmap_write(bld_regs,
> +               regmap_write(engine->regs,
>                              SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos),
>                              SUN8I_MIXER_COORD(x, y));
> -               regmap_write(bld_regs,
> +               regmap_write(engine->regs,
>                              SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos),
>                              SUN8I_MIXER_SIZE(w, h));
>         }
>
> -       regmap_write(bld_regs, SUN8I_MIXER_BLEND_ROUTE(bld_base), route);
> -       regmap_write(bld_regs, SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
> +       regmap_write(engine->regs, SUN8I_MIXER_BLEND_ROUTE(bld_base), route);
> +       regmap_write(engine->regs, SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
>                      pipe_en | SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
>
>         if (mixer->cfg->de_type != SUN8I_MIXER_DE33)
> @@ -317,7 +318,6 @@ static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
>         struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
>         int plane_cnt = mixer->cfg->ui_num + mixer->cfg->vi_num;
>         enum drm_plane_type type;
> -       unsigned int phy_index;
>         int i;
>
>         planes = devm_kcalloc(drm->dev, plane_cnt, sizeof(*planes), GFP_KERNEL);
> @@ -332,12 +332,8 @@ static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
>                 else
>                         type = DRM_PLANE_TYPE_OVERLAY;
>
> -               phy_index = i;
> -               if (mixer->cfg->de_type == SUN8I_MIXER_DE33)
> -                       phy_index = mixer->cfg->map[i];
> -
>                 layer = sun8i_vi_layer_init_one(drm, type, mixer->engine.regs,
> -                                               i, phy_index, plane_cnt,
> +                                               i, i, plane_cnt,
>                                                 &mixer->cfg->lay_cfg);
>                 if (IS_ERR(layer)) {
>                         dev_err(drm->dev,
> @@ -357,12 +353,8 @@ static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
>                 else
>                         type = DRM_PLANE_TYPE_OVERLAY;
>
> -               phy_index = index;
> -               if (mixer->cfg->de_type == SUN8I_MIXER_DE33)
> -                       phy_index = mixer->cfg->map[index];
> -
>                 layer = sun8i_ui_layer_init_one(drm, type, mixer->engine.regs,
> -                                               index, phy_index, plane_cnt,
> +                                               index, index, plane_cnt,
>                                                 &mixer->cfg->lay_cfg);
>                 if (IS_ERR(layer)) {
>                         dev_err(drm->dev, "Couldn't initialize %s plane\n",
> @@ -376,16 +368,25 @@ static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
>         return planes;
>  }
>
> +static struct drm_plane **sun50i_layers_init(struct drm_device *drm,
> +                                            struct sunxi_engine *engine)
> +{
> +       struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
> +
> +       if (IS_ENABLED(CONFIG_DRM_SUN50I_PLANES))
> +               return sun50i_planes_setup(mixer->planes_dev, drm, engine->id);
> +
> +       return NULL;
> +}
> +
>  static void sun8i_mixer_mode_set(struct sunxi_engine *engine,
>                                  const struct drm_display_mode *mode)
>  {
>         struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
> -       struct regmap *bld_regs;
>         u32 bld_base, size, val;
>         bool interlaced;
>
>         bld_base = sun8i_blender_base(mixer);
> -       bld_regs = sun8i_blender_regmap(mixer);
>         interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
>         size = SUN8I_MIXER_SIZE(mode->hdisplay, mode->vdisplay);
>
> @@ -397,14 +398,14 @@ static void sun8i_mixer_mode_set(struct sunxi_engine *engine,
>         else
>                 regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_SIZE, size);
>
> -       regmap_write(bld_regs, SUN8I_MIXER_BLEND_OUTSIZE(bld_base), size);
> +       regmap_write(engine->regs, SUN8I_MIXER_BLEND_OUTSIZE(bld_base), size);
>
>         if (interlaced)
>                 val = SUN8I_MIXER_BLEND_OUTCTL_INTERLACED;
>         else
>                 val = 0;
>
> -       regmap_update_bits(bld_regs, SUN8I_MIXER_BLEND_OUTCTL(bld_base),
> +       regmap_update_bits(engine->regs, SUN8I_MIXER_BLEND_OUTCTL(bld_base),
>                            SUN8I_MIXER_BLEND_OUTCTL_INTERLACED, val);
>
>         DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
> @@ -417,8 +418,14 @@ static const struct sunxi_engine_ops sun8i_engine_ops = {
>         .mode_set       = sun8i_mixer_mode_set,
>  };
>
> +static const struct sunxi_engine_ops sun50i_engine_ops = {
> +       .commit         = sun8i_mixer_commit,
> +       .layers_init    = sun50i_layers_init,
> +       .mode_set       = sun8i_mixer_mode_set,
> +};
> +
>  static const struct regmap_config sun8i_mixer_regmap_config = {
> -       .name           = "layers",
> +       .name           = "display",
>         .reg_bits       = 32,
>         .val_bits       = 32,
>         .reg_stride     = 4,
> @@ -433,14 +440,6 @@ static const struct regmap_config sun8i_top_regmap_config = {
>         .max_register   = 0x3c,
>  };
>
> -static const struct regmap_config sun8i_disp_regmap_config = {
> -       .name           = "display",
> -       .reg_bits       = 32,
> -       .val_bits       = 32,
> -       .reg_stride     = 4,
> -       .max_register   = 0x20000,
> -};
> -
>  static int sun8i_mixer_of_get_id(struct device_node *node)
>  {
>         struct device_node *ep, *remote;
> @@ -463,17 +462,14 @@ static int sun8i_mixer_of_get_id(struct device_node *node)
>
>  static void sun8i_mixer_init(struct sun8i_mixer *mixer)
>  {
> -       struct regmap *top_regs, *disp_regs;
>         unsigned int base = sun8i_blender_base(mixer);
> +       struct regmap *top_regs;
>         int plane_cnt, i;
>
> -       if (mixer->cfg->de_type == SUN8I_MIXER_DE33) {
> +       if (mixer->cfg->de_type == SUN8I_MIXER_DE33)
>                 top_regs = mixer->top_regs;
> -               disp_regs = mixer->disp_regs;
> -       } else {
> +       else
>                 top_regs = mixer->engine.regs;
> -               disp_regs = mixer->engine.regs;
> -       }
>
>         /* Enable the mixer */
>         regmap_write(top_regs, SUN8I_MIXER_GLOBAL_CTL,
> @@ -483,25 +479,25 @@ static void sun8i_mixer_init(struct sun8i_mixer *mixer)
>                 regmap_write(top_regs, SUN50I_MIXER_GLOBAL_CLK, 1);
>
>         /* Set background color to black */
> -       regmap_write(disp_regs, SUN8I_MIXER_BLEND_BKCOLOR(base),
> +       regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR(base),
>                      SUN8I_MIXER_BLEND_COLOR_BLACK);
>
>         /*
>          * Set fill color of bottom plane to black. Generally not needed
>          * except when VI plane is at bottom (zpos = 0) and enabled.
>          */
> -       regmap_write(disp_regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
> +       regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
>                      SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
> -       regmap_write(disp_regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, 0),
> +       regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, 0),
>                      SUN8I_MIXER_BLEND_COLOR_BLACK);
>
>         plane_cnt = mixer->cfg->vi_num + mixer->cfg->ui_num;
>         for (i = 0; i < plane_cnt; i++)
> -               regmap_write(disp_regs,
> +               regmap_write(mixer->engine.regs,
>                              SUN8I_MIXER_BLEND_MODE(base, i),
>                              SUN8I_MIXER_BLEND_MODE_DEF);
>
> -       regmap_update_bits(disp_regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
> +       regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
>                            SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0);
>  }
>
> @@ -532,7 +528,6 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
>         if (!mixer)
>                 return -ENOMEM;
>         dev_set_drvdata(dev, mixer);
> -       mixer->engine.ops = &sun8i_engine_ops;
>         mixer->engine.node = dev->of_node;
>
>         if (of_property_present(dev->of_node, "iommus")) {
> @@ -562,6 +557,11 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
>         if (!mixer->cfg)
>                 return -EINVAL;
>
> +       if (mixer->cfg->de_type == SUN8I_MIXER_DE33)
> +               mixer->engine.ops = &sun50i_engine_ops;

You're missing an IS_ENABLED() clause here if you wanted to make the DE 3.3
planes driver optional. Though as I mentioned in the other patch, splittig
the two modules might not work.

> +       else
> +               mixer->engine.ops = &sun8i_engine_ops;
> +
>         regs = devm_platform_ioremap_resource(pdev, 0);
>         if (IS_ERR(regs))
>                 return PTR_ERR(regs);
> @@ -584,17 +584,6 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
>                         dev_err(dev, "Couldn't create the top regmap\n");
>                         return PTR_ERR(mixer->top_regs);
>                 }
> -
> -               regs = devm_platform_ioremap_resource_byname(pdev, "display");
> -               if (IS_ERR(regs))
> -                       return PTR_ERR(regs);
> -
> -               mixer->disp_regs = devm_regmap_init_mmio(dev, regs,
> -                                                        &sun8i_disp_regmap_config);
> -               if (IS_ERR(mixer->disp_regs)) {
> -                       dev_err(dev, "Couldn't create the disp regmap\n");
> -                       return PTR_ERR(mixer->disp_regs);
> -               }
>         }
>
>         mixer->reset = devm_reset_control_get(dev, NULL);
> @@ -634,6 +623,33 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
>
>         clk_prepare_enable(mixer->mod_clk);
>
> +       if (mixer->cfg->de_type == SUN8I_MIXER_DE33) {
> +               struct platform_device *pdev;
> +               struct device_node *np;
> +               void *data;
> +
> +               np = of_parse_phandle(dev->of_node, "allwinner,planes", 0);
> +               if (!np) {
> +                       ret = -ENODEV;
> +                       goto err_disable_mod_clk;
> +               }
> +
> +               pdev = of_find_device_by_node(np);

You need to add a matching put_device() in the unbind function.

Side note:

This bind function is using a lot of devm_ functions. These have the wrong
lifetime. I think it would be better if we could move resource acquisition
into the probe function.


> +               of_node_put(np);
> +               if (!pdev) {
> +                       ret = -EPROBE_DEFER;
> +                       goto err_disable_mod_clk;
> +               }
> +
> +               data = platform_get_drvdata(pdev);
> +               if (!data) {
> +                       put_device(&pdev->dev);
> +                       return -EPROBE_DEFER;

Should be a goto here?


ChenYu

> +               }
> +
> +               mixer->planes_dev = &pdev->dev;
> +       }
> +
>         list_add_tail(&mixer->engine.list, &drv->engine_list);
>
>         /* Reset registers and disable unused sub-engines */
> @@ -668,6 +684,8 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
>
>         return 0;
>
> +err_disable_mod_clk:
> +       clk_disable_unprepare(mixer->mod_clk);
>  err_disable_bus_clk:
>         clk_disable_unprepare(mixer->bus_clk);
>  err_assert_reset:
> @@ -863,16 +881,8 @@ static const struct sun8i_mixer_cfg sun50i_h6_mixer0_cfg = {
>  };
>
>  static const struct sun8i_mixer_cfg sun50i_h616_mixer0_cfg = {
> -       .lay_cfg = {
> -               .de_type        = SUN8I_MIXER_DE33,
> -               .scaler_mask    = 0xf,
> -               .scanline_yuv   = 4096,
> -       },
>         .de_type        = SUN8I_MIXER_DE33,
>         .mod_rate       = 600000000,
> -       .ui_num         = 3,
> -       .vi_num         = 1,
> -       .map            = {0, 6, 7, 8},
>  };
>
>  static const struct of_device_id sun8i_mixer_of_table[] = {
> diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h b/drivers/gpu/drm/sun4i/sun8i_mixer.h
> index e2f83301aae8..7abc88c898d9 100644
> --- a/drivers/gpu/drm/sun4i/sun8i_mixer.h
> +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
> @@ -202,7 +202,6 @@ struct sun8i_mixer_cfg {
>         int                     ui_num;
>         unsigned int            de_type;
>         unsigned long           mod_rate;
> -       unsigned int            map[6];
>  };
>
>  struct sun8i_mixer {
> @@ -216,7 +215,7 @@ struct sun8i_mixer {
>         struct clk                      *mod_clk;
>
>         struct regmap                   *top_regs;
> -       struct regmap                   *disp_regs;
> +       struct device                   *planes_dev;
>  };
>
>  enum {
> @@ -252,13 +251,6 @@ sun8i_blender_base(struct sun8i_mixer *mixer)
>         return mixer->cfg->de_type == SUN8I_MIXER_DE3 ? DE3_BLD_BASE : DE2_BLD_BASE;
>  }
>
> -static inline struct regmap *
> -sun8i_blender_regmap(struct sun8i_mixer *mixer)
> -{
> -       return mixer->cfg->de_type == SUN8I_MIXER_DE33 ?
> -               mixer->disp_regs : mixer->engine.regs;
> -}
> -
>  static inline u32
>  sun8i_channel_base(struct sun8i_layer *layer)
>  {
> --
> 2.51.2
>
>


From wens at kernel.org  Thu Dec 25 01:54:45 2025
From: wens at kernel.org (Chen-Yu Tsai)
Date: Thu, 25 Dec 2025 17:54:45 +0800
Subject: [PATCH] drm/sun4i: fix kernel-doc warnings in sunxi_engine.h
In-Reply-To: <20251124033301.2987159-1-rdunlap@infradead.org>
References: <20251124033301.2987159-1-rdunlap@infradead.org>
Message-ID: <CAGb2v64d5wfHHQZd7D64RH0YukqewbGyPmwABoF0SNrf-yEn3A@mail.gmail.com>

On Mon, Nov 24, 2025 at 11:33?AM Randy Dunlap <rdunlap at infradead.org> wrote:
>
> Correct the kernel-doc notation, add a missing struct member comment,
> and add a missing "Returns:" function comment to eliminate kernel-doc
> warnings:
>
> Warning: drivers/gpu/drm/sun4i/sunxi_engine.h:116 Incorrect use of
>  kernel-doc format: * @mode_set
> Warning: drivers/gpu/drm/sun4i/sunxi_engine.h:125 struct member 'mode_set'
>  not described in 'sunxi_engine_ops'
> Warning: drivers/gpu/drm/sun4i/sunxi_engine.h:144 struct member 'list'
>  not described in 'sunxi_engine'
> Warning: drivers/gpu/drm/sun4i/sunxi_engine.h:168 No description found
>  for return value of 'sunxi_engine_layers_init'
>
> Signed-off-by: Randy Dunlap <rdunlap at infradead.org>

Reviewed-by: Chen-Yu Tsai <wens at kernel.org>


From Kyrie.Wu at mediatek.com  Thu Dec 25 01:55:20 2025
From: Kyrie.Wu at mediatek.com (=?utf-8?B?S3lyaWUgV3UgKOWQtOaZlyk=?=)
Date: Thu, 25 Dec 2025 09:55:20 +0000
Subject: [PATCH v6 05/10] media: mediatek: vcodec: refactor setup dst
 buffer metadata interface for VP9 decoder
In-Reply-To: <d9a58ddf9b90d8320562ec54f2bd74fa77f0bc67.camel@collabora.com>
References: <20251202074038.3173-1-kyrie.wu@mediatek.com>
	 <20251202074038.3173-6-kyrie.wu@mediatek.com>
	 <d9a58ddf9b90d8320562ec54f2bd74fa77f0bc67.camel@collabora.com>
Message-ID: <72cae8fffc3ccd2a6f31fc777a5441c9a15c82fa.camel@mediatek.com>

On Thu, 2025-12-11 at 15:29 -0500, Nicolas Dufresne wrote:
> Hi,
> 
> Le mardi 02 d?cembre 2025 ? 15:40 +0800, Kyrie Wu a ?crit :
> > Previously, calling vdec_vp9_slice_setup_single_from_src_to_dst
> > with v4l2_m2m_next_src_buf to obtain both buffers resulted in
> > -EINVAL,
> > interrupting the decoding process. To resolve this,
> > the interface should be updated to set both src and dst buffers
> > for metadata configuration.
> 
> I'm haven't figure-out why this happens, perhaps you can add more
> details ?
> 
> > 
> > Signed-off-by: Kyrie Wu <kyrie.wu at mediatek.com>
> > ---
> >  .../vcodec/decoder/vdec/vdec_vp9_req_lat_if.c | 21 ++++++++++-----
> > ----
> >  1 file changed, 11 insertions(+), 10 deletions(-)
> > 
> > diff --git
> > a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_
> > lat_if.c
> > b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_
> > lat_if.c
> > index fa0f406f7726..9513ddde7c7c 100644
> > ---
> > a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_
> > lat_if.c
> > +++
> > b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_
> > lat_if.c
> > @@ -696,21 +696,22 @@ static int vdec_vp9_slice_tile_offset(int
> > idx, int mi_num, int tile_log2)
> >  	return min(offset, mi_num);
> >  }
> >  
> > -static
> > -int vdec_vp9_slice_setup_single_from_src_to_dst(struct
> > vdec_vp9_slice_instance *instance)
> > +static int vdec_vp9_slice_setup_single_from_src_to_dst(struct
> > vdec_vp9_slice_instance *instance,
> > +						       struct
> > mtk_vcodec_mem *bs,
> > +						       struct vdec_fb
> > *fb)
> >  {
> > -	struct vb2_v4l2_buffer *src;
> > -	struct vb2_v4l2_buffer *dst;
> > +	struct mtk_video_dec_buf *src_buf_info;
> > +	struct mtk_video_dec_buf *dst_buf_info;
> >  
> > -	src = v4l2_m2m_next_src_buf(instance->ctx->m2m_ctx);
> 
> My concern is that vdec_vp9_slice_setup_lat_from_src_buf() also
> depends on the
> tip of the OUTPUT queue, why it this problem with limited to single
> core ?
> 
> Can you apply the manual completion fixes, and check if the problem
> still
> appear? Is that something you reproduce every time ? Perhaps it
> should be kept
> out of this serie ?
> 
> 
> > -	if (!src)
> > +	src_buf_info = container_of(bs, struct mtk_video_dec_buf,
> > bs_buffer);
> > +	if (!src_buf_info)
> >  		return -EINVAL;
> 
> Its a bit of a concern in term of memory lifetime / possible use
> after free.
> Who's holding on the buffer if its not in the queue ?
> 
> Nicolas

Dear Nicolas,

Thanks for your reminding, I think this patch could abandon.
I will update the patch set in the next version.

Thanks.

Kyrie.
> 
> >  
> > -	dst = v4l2_m2m_next_dst_buf(instance->ctx->m2m_ctx);
> > -	if (!dst)
> > +	dst_buf_info = container_of(fb, struct mtk_video_dec_buf,
> > frame_buffer);
> > +	if (!dst_buf_info)
> >  		return -EINVAL;
> >  
> > -	v4l2_m2m_buf_copy_metadata(src, dst, true);
> > +	v4l2_m2m_buf_copy_metadata(&src_buf_info->m2m_buf.vb,
> > &dst_buf_info->m2m_buf.vb, true);
> >  
> >  	return 0;
> >  }
> > @@ -1800,7 +1801,7 @@ static int vdec_vp9_slice_setup_single(struct
> > vdec_vp9_slice_instance *instance,
> >  	struct vdec_vp9_slice_vsi *vsi = &pfc->vsi;
> >  	int ret;
> >  
> > -	ret = vdec_vp9_slice_setup_single_from_src_to_dst(instance);
> > +	ret = vdec_vp9_slice_setup_single_from_src_to_dst(instance, bs,
> > fb);
> >  	if (ret)
> >  		goto err;
> >  

From lkp at intel.com  Thu Dec 25 02:16:34 2025
From: lkp at intel.com (kernel test robot)
Date: Thu, 25 Dec 2025 18:16:34 +0800
Subject: [PATCH v18 01/10] power: reset: reboot-mode: Remove devres based
 allocations
In-Reply-To: <20251223-arm-psci-system_reset2-vendor-reboots-v18-1-32fa9e76efc3@oss.qualcomm.com>
References: <20251223-arm-psci-system_reset2-vendor-reboots-v18-1-32fa9e76efc3@oss.qualcomm.com>
Message-ID: <202512251820.e0ZKwuCc-lkp@intel.com>

Hi Shivendra,

kernel test robot noticed the following build errors:

[auto build test ERROR on cc3aa43b44bdb43dfbac0fcb51c56594a11338a8]

url:    https://github.com/intel-lab-lkp/linux/commits/Shivendra-Pratap/power-reset-reboot-mode-Remove-devres-based-allocations/20251224-011508
base:   cc3aa43b44bdb43dfbac0fcb51c56594a11338a8
patch link:    https://lore.kernel.org/r/20251223-arm-psci-system_reset2-vendor-reboots-v18-1-32fa9e76efc3%40oss.qualcomm.com
patch subject: [PATCH v18 01/10] power: reset: reboot-mode: Remove devres based allocations
config: powerpc64-randconfig-r072-20251225 (https://download.01.org/0day-ci/archive/20251225/202512251820.e0ZKwuCc-lkp at intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 4ef602d446057dabf5f61fb221669ecbeda49279)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251225/202512251820.e0ZKwuCc-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512251820.e0ZKwuCc-lkp at intel.com/

All errors (new ones prefixed by >>):

>> drivers/power/reset/reboot-mode.c:94:10: error: call to undeclared function 'kzalloc'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
      94 |                 info = kzalloc(sizeof(*info), GFP_KERNEL);
         |                        ^
>> drivers/power/reset/reboot-mode.c:94:8: error: incompatible integer to pointer conversion assigning to 'struct mode_info *' from 'int' [-Wint-conversion]
      94 |                 info = kzalloc(sizeof(*info), GFP_KERNEL);
         |                      ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/power/reset/reboot-mode.c:120:2: error: call to undeclared function 'kfree'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     120 |         kfree(info);
         |         ^
   drivers/power/reset/reboot-mode.c:145:3: error: call to undeclared function 'kfree'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     145 |                 kfree(info);
         |                 ^
   4 errors generated.


vim +/kzalloc +94 drivers/power/reset/reboot-mode.c

    66	
    67	/**
    68	 * reboot_mode_register - register a reboot mode driver
    69	 * @reboot: reboot mode driver
    70	 *
    71	 * Returns: 0 on success or a negative error code on failure.
    72	 */
    73	int reboot_mode_register(struct reboot_mode_driver *reboot)
    74	{
    75		struct mode_info *info;
    76		struct mode_info *next;
    77		struct property *prop;
    78		struct device_node *np = reboot->dev->of_node;
    79		size_t len = strlen(PREFIX);
    80		u32 magic;
    81		int ret;
    82	
    83		INIT_LIST_HEAD(&reboot->head);
    84	
    85		for_each_property_of_node(np, prop) {
    86			if (strncmp(prop->name, PREFIX, len))
    87				continue;
    88	
    89			if (of_property_read_u32(np, prop->name, &magic)) {
    90				pr_err("reboot mode %s without magic number\n", prop->name);
    91				continue;
    92			}
    93	
  > 94			info = kzalloc(sizeof(*info), GFP_KERNEL);
    95			if (!info) {
    96				ret = -ENOMEM;
    97				goto error;
    98			}
    99	
   100			info->mode = kstrdup_const(prop->name + len, GFP_KERNEL);
   101			if (!info->mode) {
   102				ret =  -ENOMEM;
   103				goto error;
   104			} else if (info->mode[0] == '\0') {
   105				kfree_const(info->mode);
   106				ret = -EINVAL;
   107				pr_err("invalid mode name(%s): too short!\n", prop->name);
   108				goto error;
   109			}
   110	
   111			list_add_tail(&info->list, &reboot->head);
   112		}
   113	
   114		reboot->reboot_notifier.notifier_call = reboot_mode_notify;
   115		register_reboot_notifier(&reboot->reboot_notifier);
   116	
   117		return 0;
   118	
   119	error:
 > 120		kfree(info);
   121		list_for_each_entry_safe(info, next, &reboot->head, list) {
   122			list_del(&info->list);
   123			kfree_const(info->mode);
   124			kfree(info);
   125		}
   126	
   127		return ret;
   128	}
   129	EXPORT_SYMBOL_GPL(reboot_mode_register);
   130	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From wens at kernel.org  Thu Dec 25 02:36:15 2025
From: wens at kernel.org (Chen-Yu Tsai)
Date: Thu, 25 Dec 2025 18:36:15 +0800
Subject: [PATCH 4/4] ARM: dts: allwinner: Replace status "failed" with "fail"
In-Reply-To: <20251225103616.3203473-1-wens@kernel.org>
References: <20251225103616.3203473-1-wens@kernel.org>
Message-ID: <20251225103616.3203473-5-wens@kernel.org>

The device tree bindings specify using "fail", not "failed".

Fix up all the ones that are wrong.

Signed-off-by: Chen-Yu Tsai <wens at kernel.org>
---
 arch/arm/boot/dts/allwinner/sun4i-a10-dserve-dsrv9703c.dts | 2 +-
 arch/arm/boot/dts/allwinner/sun4i-a10-pov-protab2-ips9.dts | 2 +-
 arch/arm/boot/dts/allwinner/sun6i-a31-hummingbird.dts      | 2 +-
 arch/arm/boot/dts/allwinner/sun6i-a31s-primo81.dts         | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boot/dts/allwinner/sun4i-a10-dserve-dsrv9703c.dts b/arch/arm/boot/dts/allwinner/sun4i-a10-dserve-dsrv9703c.dts
index 63e77c05bfda..f2413ba6a858 100644
--- a/arch/arm/boot/dts/allwinner/sun4i-a10-dserve-dsrv9703c.dts
+++ b/arch/arm/boot/dts/allwinner/sun4i-a10-dserve-dsrv9703c.dts
@@ -112,7 +112,7 @@ axp209: pmic at 34 {
 
 &i2c1 {
 	/* pull-ups and devices require AXP209 LDO3 */
-	status = "failed";
+	status = "fail";
 };
 
 &i2c2 {
diff --git a/arch/arm/boot/dts/allwinner/sun4i-a10-pov-protab2-ips9.dts b/arch/arm/boot/dts/allwinner/sun4i-a10-pov-protab2-ips9.dts
index c32596947647..e0c7099015da 100644
--- a/arch/arm/boot/dts/allwinner/sun4i-a10-pov-protab2-ips9.dts
+++ b/arch/arm/boot/dts/allwinner/sun4i-a10-pov-protab2-ips9.dts
@@ -96,7 +96,7 @@ axp209: pmic at 34 {
 
 &i2c1 {
 	/* pull-ups and devices require AXP209 LDO3 */
-	status = "failed";
+	status = "fail";
 };
 
 &i2c2 {
diff --git a/arch/arm/boot/dts/allwinner/sun6i-a31-hummingbird.dts b/arch/arm/boot/dts/allwinner/sun6i-a31-hummingbird.dts
index 5bce7a32651e..5dfd36e3a49d 100644
--- a/arch/arm/boot/dts/allwinner/sun6i-a31-hummingbird.dts
+++ b/arch/arm/boot/dts/allwinner/sun6i-a31-hummingbird.dts
@@ -170,7 +170,7 @@ hdmi_out_con: endpoint {
 
 &i2c0 {
 	/* pull-ups and devices require AXP221 DLDO3 */
-	status = "failed";
+	status = "fail";
 };
 
 &i2c1 {
diff --git a/arch/arm/boot/dts/allwinner/sun6i-a31s-primo81.dts b/arch/arm/boot/dts/allwinner/sun6i-a31s-primo81.dts
index b32b70ada7fd..fefd887fbc39 100644
--- a/arch/arm/boot/dts/allwinner/sun6i-a31s-primo81.dts
+++ b/arch/arm/boot/dts/allwinner/sun6i-a31s-primo81.dts
@@ -90,7 +90,7 @@ hdmi_out_con: endpoint {
 
 &i2c0 {
 	/* pull-ups and device VDDIO use AXP221 DLDO3 */
-	status = "failed";
+	status = "fail";
 };
 
 &i2c1 {
-- 
2.47.3



From wens at kernel.org  Thu Dec 25 02:36:12 2025
From: wens at kernel.org (Chen-Yu Tsai)
Date: Thu, 25 Dec 2025 18:36:12 +0800
Subject: [PATCH 1/4] dt-bindings: media: sun4i-a10-video-engine: Add interconnect properties
In-Reply-To: <20251225103616.3203473-1-wens@kernel.org>
References: <20251225103616.3203473-1-wens@kernel.org>
Message-ID: <20251225103616.3203473-2-wens@kernel.org>

The Allwinner video engine sits behind the MBUS that is represented as
an interconnect.

Make sure that the interconnect properties are valid in the binding.

Fixes: d41662e52a03 ("media: dt-bindings: media: allwinner,sun4i-a10-video-engine: Add R40 compatible")
Signed-off-by: Chen-Yu Tsai <wens at kernel.org>
---
 .../media/allwinner,sun4i-a10-video-engine.yaml        | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-video-engine.yaml b/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-video-engine.yaml
index 541325f900a1..01f2afa023f0 100644
--- a/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-video-engine.yaml
+++ b/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-video-engine.yaml
@@ -63,6 +63,16 @@ properties:
       CMA pool to use for buffers allocation instead of the default
       CMA pool.
 
+  # FIXME: This should be made required eventually once every SoC will
+  # have the MBUS declared.
+  interconnects:
+    maxItems: 1
+
+  # FIXME: This should be made required eventually once every SoC will
+  # have the MBUS declared.
+  interconnect-names:
+    const: dma-mem
+
 required:
   - compatible
   - reg
-- 
2.47.3



From wens at kernel.org  Thu Dec 25 02:36:14 2025
From: wens at kernel.org (Chen-Yu Tsai)
Date: Thu, 25 Dec 2025 18:36:14 +0800
Subject: [PATCH 3/4] ARM: dts: allwinner: sun5i-a13-utoo-p66: delete "power-gpios" property
In-Reply-To: <20251225103616.3203473-1-wens@kernel.org>
References: <20251225103616.3203473-1-wens@kernel.org>
Message-ID: <20251225103616.3203473-4-wens@kernel.org>

The P66's device tree includes the reference design dtsi files, which
defines a node and properties for the touchpanel in the common design.
The P66 dts file then overrides all the properties to match its own
design, but as the touchpanel model is different, a different schema
is matched. This other schema uses a different name for the GPIO.

The original submission added the correct GPIO property, but did not
delete the one inherited from the reference design, causing validation
errors.

Explicitly delete the incorrect GPIO property.

Fixes: 2a53aff27236 ("ARM: dts: sun5i: Enable touchscreen on Utoo P66")
Signed-off-by: Chen-Yu Tsai <wens at kernel.org>

---
Cc: Hans de Goede <hdegoede at redhat.com>
---
 arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts b/arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts
index be486d28d04f..428cab5a0e90 100644
--- a/arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts
+++ b/arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts
@@ -102,6 +102,7 @@ &touchscreen {
 	/* The P66 uses a different EINT then the reference design */
 	interrupts = <6 9 IRQ_TYPE_EDGE_FALLING>; /* EINT9 (PG9) */
 	/* The icn8318 binding expects wake-gpios instead of power-gpios */
+	/delete-property/ power-gpios;
 	wake-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; /* PB3 */
 	touchscreen-size-x = <800>;
 	touchscreen-size-y = <480>;
-- 
2.47.3



From wens at kernel.org  Thu Dec 25 02:36:11 2025
From: wens at kernel.org (Chen-Yu Tsai)
Date: Thu, 25 Dec 2025 18:36:11 +0800
Subject: [PATCH 0/4] ARM: dts: allwinner: Fix remaining DT validation errors
Message-ID: <20251225103616.3203473-1-wens@kernel.org>

Hi folks,

This series gets rid of the remaining DT validation errors for Allwinner
(sunxi) ARM 32-bit device trees. The patches are self explaining.

I plan to take all four patches through the sunxi tree.


ChenYu


Chen-Yu Tsai (4):
  dt-bindings: media: sun4i-a10-video-engine: Add interconnect
    properties
  dt-bindings: pinctrl: sunxi: Allow pinmux sub-pattern with leading
    numbers
  ARM: dts: allwinner: sun5i-a13-utoo-p66: delete "power-gpios" property
  ARM: dts: allwinner: Replace status "failed" with "fail"

 .../media/allwinner,sun4i-a10-video-engine.yaml        | 10 ++++++++++
 .../bindings/pinctrl/allwinner,sun4i-a10-pinctrl.yaml  |  2 +-
 .../boot/dts/allwinner/sun4i-a10-dserve-dsrv9703c.dts  |  2 +-
 .../boot/dts/allwinner/sun4i-a10-pov-protab2-ips9.dts  |  2 +-
 arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts     |  1 +
 arch/arm/boot/dts/allwinner/sun6i-a31-hummingbird.dts  |  2 +-
 arch/arm/boot/dts/allwinner/sun6i-a31s-primo81.dts     |  2 +-
 7 files changed, 16 insertions(+), 5 deletions(-)

-- 
2.47.3



From wens at kernel.org  Thu Dec 25 02:36:13 2025
From: wens at kernel.org (Chen-Yu Tsai)
Date: Thu, 25 Dec 2025 18:36:13 +0800
Subject: [PATCH 2/4] dt-bindings: pinctrl: sunxi: Allow pinmux sub-pattern with leading numbers
In-Reply-To: <20251225103616.3203473-1-wens@kernel.org>
References: <20251225103616.3203473-1-wens@kernel.org>
Message-ID: <20251225103616.3203473-3-wens@kernel.org>

The pattern for pinmux node names is typically the peripheral name and
instance number, followed by pingroup name if there are multiple options.

Normally the instance number is directly appended to the peripheral
name, like "mmc0" or "i2c2". But if the peripheral name ends with a
number, then it becomes confusing.

On the A20, the PS2 interface controller has two instances. This
produces pinmux node names like "ps2-0-pins". Make the sub-pattern
"[0-9]-" valid to fit this pattern. Avoid having to confusing "ps20-pins"
name.

Signed-off-by: Chen-Yu Tsai <wens at kernel.org>
---
 .../bindings/pinctrl/allwinner,sun4i-a10-pinctrl.yaml           | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/pinctrl/allwinner,sun4i-a10-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/allwinner,sun4i-a10-pinctrl.yaml
index 990b78765427..45b7a0b6c626 100644
--- a/Documentation/devicetree/bindings/pinctrl/allwinner,sun4i-a10-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/allwinner,sun4i-a10-pinctrl.yaml
@@ -106,7 +106,7 @@ patternProperties:
   #     the pin numbers then,
   #   - Finally, the name will end with either -pin or pins.
 
-  "^([rs]-)?(([a-z0-9]{3,}|[a-oq-z][a-z0-9]*?)?-)+?(p[a-ilm][0-9]*?-)??pins?$":
+  "^([rs]-)?(([a-z0-9]{3,}|[a-oq-z0-9][a-z0-9]*?)?-)+?(p[a-ilm][0-9]*?-)??pins?$":
     type: object
 
     properties:
-- 
2.47.3



From krzk at kernel.org  Thu Dec 25 04:25:07 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 25 Dec 2025 13:25:07 +0100
Subject: [PATCH 0/4] ARM: dts: allwinner: Fix remaining DT validation
 errors
In-Reply-To: <20251225103616.3203473-1-wens@kernel.org>
References: <20251225103616.3203473-1-wens@kernel.org>
Message-ID: <fd068960-33ca-4a47-9850-fde41de18995@kernel.org>

On 25/12/2025 11:36, Chen-Yu Tsai wrote:
> Hi folks,
> 
> This series gets rid of the remaining DT validation errors for Allwinner
> (sunxi) ARM 32-bit device trees. The patches are self explaining.
> 
> I plan to take all four patches through the sunxi tree.

It's v1 and not a resend, thus subsystem patches should go via subsystem
trees.

Best regards,
Krzysztof


From leon at kernel.org  Thu Dec 25 04:36:50 2025
From: leon at kernel.org (Leon Romanovsky)
Date: Thu, 25 Dec 2025 14:36:50 +0200
Subject: [PATCH 5/6] dma-mapping: Allow batched DMA sync operations if
 supported by the arch
In-Reply-To: <20251225054509.39917-1-21cnbao@gmail.com>
References: <20251224085145.GF11869@unreal>
 <20251225054509.39917-1-21cnbao@gmail.com>
Message-ID: <20251225123650.GJ11869@unreal>

On Thu, Dec 25, 2025 at 06:45:09PM +1300, Barry Song wrote:
> > > >
> > >
> > > OK. Could you take a look at [1] and see if any further
> > > improvements are needed before I send v2?
> >
> > Everything looks ok, except these renames:
> > -                       arch_sync_dma_for_cpu(paddr, sg->length, dir);
> > +                       arch_sync_dma_for_cpu_batch_add(paddr, sg->length, dir);
> 
> Thanks!
> I'm happy to drop the rename as outlined below-feedback welcome :-)
> 
> diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h
> index dd2c8586a725..487fb7c355ed 100644
> --- a/arch/arm64/include/asm/cache.h
> +++ b/arch/arm64/include/asm/cache.h
> @@ -87,6 +87,12 @@ int cache_line_size(void);
>  
>  #define dma_get_cache_alignment	cache_line_size
>  
> +static inline void arch_sync_dma_flush(void)
> +{
> +	dsb(sy);
> +}
> +#define arch_sync_dma_flush arch_sync_dma_flush
> +
>  /* Compress a u64 MPIDR value into 32 bits. */
>  static inline u64 arch_compact_of_hwid(u64 id)
>  {
> diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
> index b2b5792b2caa..ae1ae0280eef 100644
> --- a/arch/arm64/mm/dma-mapping.c
> +++ b/arch/arm64/mm/dma-mapping.c
> @@ -17,7 +17,7 @@ void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
>  {
>  	unsigned long start = (unsigned long)phys_to_virt(paddr);
>  
> -	dcache_clean_poc(start, start + size);
> +	dcache_clean_poc_nosync(start, start + size);
>  }
>  
>  void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
> @@ -28,7 +28,7 @@ void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
>  	if (dir == DMA_TO_DEVICE)
>  		return;
>  
> -	dcache_inval_poc(start, start + size);
> +	dcache_inval_poc_nosync(start, start + size);
>  }
>  
>  void arch_dma_prep_coherent(struct page *page, size_t size)
> diff --git a/include/linux/dma-map-ops.h b/include/linux/dma-map-ops.h
> index 4809204c674c..e7dd8a63b40e 100644
> --- a/include/linux/dma-map-ops.h
> +++ b/include/linux/dma-map-ops.h
> @@ -361,6 +361,12 @@ static inline void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
>  }
>  #endif /* ARCH_HAS_SYNC_DMA_FOR_CPU */
>  
> +#ifndef arch_sync_dma_flush

You likely need to wrap this in "#ifdef CONFIG_ARCH_HAS_SYNC_DMA_FLUSH"
as done in the surrounding code.

Thanks

> +static inline void arch_sync_dma_flush(void)
> +{
> +}
> +#endif
> +
>  #ifdef CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU_ALL
>  void arch_sync_dma_for_cpu_all(void);
>  #else
> 


From 21cnbao at gmail.com  Thu Dec 25 05:31:42 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Fri, 26 Dec 2025 02:31:42 +1300
Subject: [PATCH 5/6] dma-mapping: Allow batched DMA sync operations if
 supported by the arch
In-Reply-To: <20251225123650.GJ11869@unreal>
References: <20251224085145.GF11869@unreal> <20251225054509.39917-1-21cnbao@gmail.com>
 <20251225123650.GJ11869@unreal>
Message-ID: <CAGsJ_4zpWWLaynh1U4MKCS-N8tZ0tvE6tAmb0m+Pbf-kPsYQJg@mail.gmail.com>

On Fri, Dec 26, 2025 at 1:36?AM Leon Romanovsky <leon at kernel.org> wrote:
>
> On Thu, Dec 25, 2025 at 06:45:09PM +1300, Barry Song wrote:
> > > > >
> > > >
> > > > OK. Could you take a look at [1] and see if any further
> > > > improvements are needed before I send v2?
> > >
> > > Everything looks ok, except these renames:
> > > -                       arch_sync_dma_for_cpu(paddr, sg->length, dir);
> > > +                       arch_sync_dma_for_cpu_batch_add(paddr, sg->length, dir);
> >
> > Thanks!
> > I'm happy to drop the rename as outlined below-feedback welcome :-)
> >
> > diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h
> > index dd2c8586a725..487fb7c355ed 100644
> > --- a/arch/arm64/include/asm/cache.h
> > +++ b/arch/arm64/include/asm/cache.h
> > @@ -87,6 +87,12 @@ int cache_line_size(void);
> >
> >  #define dma_get_cache_alignment      cache_line_size
> >
> > +static inline void arch_sync_dma_flush(void)
> > +{
> > +     dsb(sy);
> > +}
> > +#define arch_sync_dma_flush arch_sync_dma_flush
> > +
> >  /* Compress a u64 MPIDR value into 32 bits. */
> >  static inline u64 arch_compact_of_hwid(u64 id)
> >  {
> > diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
> > index b2b5792b2caa..ae1ae0280eef 100644
> > --- a/arch/arm64/mm/dma-mapping.c
> > +++ b/arch/arm64/mm/dma-mapping.c
> > @@ -17,7 +17,7 @@ void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
> >  {
> >       unsigned long start = (unsigned long)phys_to_virt(paddr);
> >
> > -     dcache_clean_poc(start, start + size);
> > +     dcache_clean_poc_nosync(start, start + size);
> >  }
> >
> >  void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
> > @@ -28,7 +28,7 @@ void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
> >       if (dir == DMA_TO_DEVICE)
> >               return;
> >
> > -     dcache_inval_poc(start, start + size);
> > +     dcache_inval_poc_nosync(start, start + size);
> >  }
> >
> >  void arch_dma_prep_coherent(struct page *page, size_t size)
> > diff --git a/include/linux/dma-map-ops.h b/include/linux/dma-map-ops.h
> > index 4809204c674c..e7dd8a63b40e 100644
> > --- a/include/linux/dma-map-ops.h
> > +++ b/include/linux/dma-map-ops.h
> > @@ -361,6 +361,12 @@ static inline void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
> >  }
> >  #endif /* ARCH_HAS_SYNC_DMA_FOR_CPU */
> >
> > +#ifndef arch_sync_dma_flush
>
> You likely need to wrap this in "#ifdef CONFIG_ARCH_HAS_SYNC_DMA_FLUSH"
> as done in the surrounding code.

I've dropped the new Kconfig option and now rely on whether
arch_sync_dma_flush() is provided by the architecture. If an arch
does not define arch_sync_dma_flush() in its asm/cache.h, a no-op
implementation is used instead.

Do you still prefer keeping a config option to match the surrounding
code style? Note that on arm64, arch_sync_dma_flush() is already a
static inline rather than an extern, so it is not strictly aligned
with the others.
Having both CONFIG_ARCH_HAS_SYNC_DMA_FLUSH and
"#ifndef arch_sync_dma_flush" seems duplicated.

Another potential optimization would be to drop these options
entirely and handle this via ifndefs, letting each architecture
define the macros in asm/cache.h instead.

Whether arch implements arch_sync_dma_for_xx() as static inline or
as external functions makes no difference.

- #ifdef CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU
- void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,-
                enum dma_data_direction dir);
- #else
+ #ifndef arch_sync_dma_for_cpu
static inline void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
                enum dma_data_direction dir)
{
}
#endif /* ARCH_HAS_SYNC_DMA_FOR_CPU */

>
> Thanks
>
> > +static inline void arch_sync_dma_flush(void)
> > +{
> > +}
> > +#endif
> > +
> >  #ifdef CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU_ALL
> >  void arch_sync_dma_for_cpu_all(void);
> >  #else
> >

Thanks
Barry


From leon at kernel.org  Thu Dec 25 05:40:52 2025
From: leon at kernel.org (Leon Romanovsky)
Date: Thu, 25 Dec 2025 15:40:52 +0200
Subject: [PATCH 5/6] dma-mapping: Allow batched DMA sync operations if
 supported by the arch
In-Reply-To: <CAGsJ_4zpWWLaynh1U4MKCS-N8tZ0tvE6tAmb0m+Pbf-kPsYQJg@mail.gmail.com>
References: <20251224085145.GF11869@unreal>
 <20251225054509.39917-1-21cnbao@gmail.com>
 <20251225123650.GJ11869@unreal>
 <CAGsJ_4zpWWLaynh1U4MKCS-N8tZ0tvE6tAmb0m+Pbf-kPsYQJg@mail.gmail.com>
Message-ID: <20251225134052.GM11869@unreal>

On Fri, Dec 26, 2025 at 02:31:42AM +1300, Barry Song wrote:
> On Fri, Dec 26, 2025 at 1:36?AM Leon Romanovsky <leon at kernel.org> wrote:
> >
> > On Thu, Dec 25, 2025 at 06:45:09PM +1300, Barry Song wrote:
> > > > > >
> > > > >
> > > > > OK. Could you take a look at [1] and see if any further
> > > > > improvements are needed before I send v2?
> > > >
> > > > Everything looks ok, except these renames:
> > > > -                       arch_sync_dma_for_cpu(paddr, sg->length, dir);
> > > > +                       arch_sync_dma_for_cpu_batch_add(paddr, sg->length, dir);
> > >
> > > Thanks!
> > > I'm happy to drop the rename as outlined below-feedback welcome :-)
> > >
> > > diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h
> > > index dd2c8586a725..487fb7c355ed 100644
> > > --- a/arch/arm64/include/asm/cache.h
> > > +++ b/arch/arm64/include/asm/cache.h
> > > @@ -87,6 +87,12 @@ int cache_line_size(void);
> > >
> > >  #define dma_get_cache_alignment      cache_line_size
> > >
> > > +static inline void arch_sync_dma_flush(void)
> > > +{
> > > +     dsb(sy);
> > > +}
> > > +#define arch_sync_dma_flush arch_sync_dma_flush
> > > +
> > >  /* Compress a u64 MPIDR value into 32 bits. */
> > >  static inline u64 arch_compact_of_hwid(u64 id)
> > >  {
> > > diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
> > > index b2b5792b2caa..ae1ae0280eef 100644
> > > --- a/arch/arm64/mm/dma-mapping.c
> > > +++ b/arch/arm64/mm/dma-mapping.c
> > > @@ -17,7 +17,7 @@ void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
> > >  {
> > >       unsigned long start = (unsigned long)phys_to_virt(paddr);
> > >
> > > -     dcache_clean_poc(start, start + size);
> > > +     dcache_clean_poc_nosync(start, start + size);
> > >  }
> > >
> > >  void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
> > > @@ -28,7 +28,7 @@ void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
> > >       if (dir == DMA_TO_DEVICE)
> > >               return;
> > >
> > > -     dcache_inval_poc(start, start + size);
> > > +     dcache_inval_poc_nosync(start, start + size);
> > >  }
> > >
> > >  void arch_dma_prep_coherent(struct page *page, size_t size)
> > > diff --git a/include/linux/dma-map-ops.h b/include/linux/dma-map-ops.h
> > > index 4809204c674c..e7dd8a63b40e 100644
> > > --- a/include/linux/dma-map-ops.h
> > > +++ b/include/linux/dma-map-ops.h
> > > @@ -361,6 +361,12 @@ static inline void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
> > >  }
> > >  #endif /* ARCH_HAS_SYNC_DMA_FOR_CPU */
> > >
> > > +#ifndef arch_sync_dma_flush
> >
> > You likely need to wrap this in "#ifdef CONFIG_ARCH_HAS_SYNC_DMA_FLUSH"
> > as done in the surrounding code.
> 
> I've dropped the new Kconfig option and now rely on whether
> arch_sync_dma_flush() is provided by the architecture. If an arch
> does not define arch_sync_dma_flush() in its asm/cache.h, a no-op
> implementation is used instead.

I know.

> 
> Do you still prefer keeping a config option to match the surrounding
> code style?

I don't have a strong preference here. Go ahead and try your current
version and see how people respond.

> Note that on arm64, arch_sync_dma_flush() is already a
> static inline rather than an extern, so it is not strictly aligned
> with the others.
> Having both CONFIG_ARCH_HAS_SYNC_DMA_FLUSH and
> "#ifndef arch_sync_dma_flush" seems duplicated.
> 
> Another potential optimization would be to drop these options
> entirely and handle this via ifndefs, letting each architecture
> define the macros in asm/cache.h instead.
> 
> Whether arch implements arch_sync_dma_for_xx() as static inline or
> as external functions makes no difference.
> 
> - #ifdef CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU
> - void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,-
>                 enum dma_data_direction dir);
> - #else
> + #ifndef arch_sync_dma_for_cpu
> static inline void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
>                 enum dma_data_direction dir)
> {
> }
> #endif /* ARCH_HAS_SYNC_DMA_FOR_CPU */
> 
> >
> > Thanks
> >
> > > +static inline void arch_sync_dma_flush(void)
> > > +{
> > > +}
> > > +#endif
> > > +
> > >  #ifdef CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU_ALL
> > >  void arch_sync_dma_for_cpu_all(void);
> > >  #else
> > >
> 
> Thanks
> Barry
> 


From vulab at iscas.ac.cn  Thu Dec 25 06:32:56 2025
From: vulab at iscas.ac.cn (Wentao Liang)
Date: Thu, 25 Dec 2025 14:32:56 +0000
Subject: [PATCH] soc: ti: pruss: fix double free in pruss_clk_mux_setup()
Message-ID: <20251225143256.2363630-1-vulab@iscas.ac.cn>

In the pruss_clk_mux_setup(), the devm_add_action_or_reset() indirectly
calls pruss_of_free_clk_provider(), which calls of_node_put(clk_mux_np)
on the error path. However, after the devm_add_action_or_reset()
returns, the of_node_put(clk_mux_np) is called again, causing a double
free.

Fix by using a separate label to avoid the duplicate of_node_put().

Fixes: ba59c9b43c86 ("soc: ti: pruss: support CORECLK_MUX and IEPCLK_MUX")
Cc: stable at vger.kernel.org
Signed-off-by: Wentao Liang <vulab at iscas.ac.cn>
---
 drivers/soc/ti/pruss.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c
index d7634bf5413a..c16d96bebe3f 100644
--- a/drivers/soc/ti/pruss.c
+++ b/drivers/soc/ti/pruss.c
@@ -368,13 +368,14 @@ static int pruss_clk_mux_setup(struct pruss *pruss, struct clk *clk_mux,
 				       clk_mux_np);
 	if (ret) {
 		dev_err(dev, "failed to add clkmux free action %d", ret);
-		goto put_clk_mux_np;
+		goto ret_error;
 	}
 
 	return 0;
 
 put_clk_mux_np:
 	of_node_put(clk_mux_np);
+ret_error:
 	return ret;
 }
 
-- 
2.34.1



From alexandre.belloni at bootlin.com  Thu Dec 25 08:24:55 2025
From: alexandre.belloni at bootlin.com (Alexandre Belloni)
Date: Thu, 25 Dec 2025 17:24:55 +0100
Subject: [PATCH v3 01/15] include: dt-bindings: add LAN969x clock bindings
In-Reply-To: <d210552f-c8bf-4084-9317-b743075d9946@kernel.org>
References: <20251223201921.1332786-1-robert.marko@sartura.hr>
 <20251223201921.1332786-2-robert.marko@sartura.hr>
 <20251224-berserk-mackerel-of-snow-4cae54@quoll>
 <CA+HBbNGym6Q9b166n-P=h_JssOHm0yfyL73JZ+G9P81muK=g4A@mail.gmail.com>
 <78bf252c-fd5e-4a36-b1a3-ca8ed26fde7a@kernel.org>
 <CA+HBbNG+ZVD6grGDp32Ninx7H1AyEbGvP0nwc0zUv94tOV8hYg@mail.gmail.com>
 <d210552f-c8bf-4084-9317-b743075d9946@kernel.org>
Message-ID: <2025122516245554f59e2e@mail.local>

On 25/12/2025 09:47:34+0100, Krzysztof Kozlowski wrote:
> On 24/12/2025 15:01, Robert Marko wrote:
> > On Wed, Dec 24, 2025 at 2:05?PM Krzysztof Kozlowski <krzk at kernel.org> wrote:
> >>
> >> On 24/12/2025 11:30, Robert Marko wrote:
> >>> On Wed, Dec 24, 2025 at 11:21?AM Krzysztof Kozlowski <krzk at kernel.org> wrote:
> >>>>
> >>>> On Tue, Dec 23, 2025 at 09:16:12PM +0100, Robert Marko wrote:
> >>>>> Add the required LAN969x clock bindings.
> >>>>
> >>>> I do not see clock bindings actually here. Where is the actual binding?
> >>>> Commit msg does not help me at all to understand why you are doing this
> >>>> without actual required bindings.
> >>>
> >>> I guess it is a bit confusing, there is no schema here, these are the
> >>> clock indexes that
> >>> reside in dt-bindings and are used by the SoC DTSI.
> >>
> >> I understand as not used by drivers? Then no ABI and there is no point
> >> in putting them into bindings.
> > 
> > It is not included by the driver directly, but it requires these exact
> > indexes to be passed
> > so its effectively ABI.
> 
> How it requires the exact index? In what way? I do not see anything in
> the gck driver using/relying on these values. Nothing. Please point me
> to the line which directly uses these values.... or how many times I
> will need to write this is not ABI?
> 

The index here is the exact id that needs to be set in the PMC_PCR
register and so it is dictated by the hardware.


-- 
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From alexandre.belloni at bootlin.com  Thu Dec 25 08:45:12 2025
From: alexandre.belloni at bootlin.com (Alexandre Belloni)
Date: Thu, 25 Dec 2025 17:45:12 +0100
Subject: [PATCH v3 01/15] include: dt-bindings: add LAN969x clock bindings
In-Reply-To: <2025122516245554f59e2e@mail.local>
References: <20251223201921.1332786-1-robert.marko@sartura.hr>
 <20251223201921.1332786-2-robert.marko@sartura.hr>
 <20251224-berserk-mackerel-of-snow-4cae54@quoll>
 <CA+HBbNGym6Q9b166n-P=h_JssOHm0yfyL73JZ+G9P81muK=g4A@mail.gmail.com>
 <78bf252c-fd5e-4a36-b1a3-ca8ed26fde7a@kernel.org>
 <CA+HBbNG+ZVD6grGDp32Ninx7H1AyEbGvP0nwc0zUv94tOV8hYg@mail.gmail.com>
 <d210552f-c8bf-4084-9317-b743075d9946@kernel.org>
 <2025122516245554f59e2e@mail.local>
Message-ID: <20251225164512525907d8@mail.local>

On 25/12/2025 17:25:07+0100, Alexandre Belloni wrote:
> On 25/12/2025 09:47:34+0100, Krzysztof Kozlowski wrote:
> > On 24/12/2025 15:01, Robert Marko wrote:
> > > On Wed, Dec 24, 2025 at 2:05?PM Krzysztof Kozlowski <krzk at kernel.org> wrote:
> > >>
> > >> On 24/12/2025 11:30, Robert Marko wrote:
> > >>> On Wed, Dec 24, 2025 at 11:21?AM Krzysztof Kozlowski <krzk at kernel.org> wrote:
> > >>>>
> > >>>> On Tue, Dec 23, 2025 at 09:16:12PM +0100, Robert Marko wrote:
> > >>>>> Add the required LAN969x clock bindings.
> > >>>>
> > >>>> I do not see clock bindings actually here. Where is the actual binding?
> > >>>> Commit msg does not help me at all to understand why you are doing this
> > >>>> without actual required bindings.
> > >>>
> > >>> I guess it is a bit confusing, there is no schema here, these are the
> > >>> clock indexes that
> > >>> reside in dt-bindings and are used by the SoC DTSI.
> > >>
> > >> I understand as not used by drivers? Then no ABI and there is no point
> > >> in putting them into bindings.
> > > 
> > > It is not included by the driver directly, but it requires these exact
> > > indexes to be passed
> > > so its effectively ABI.
> > 
> > How it requires the exact index? In what way? I do not see anything in
> > the gck driver using/relying on these values. Nothing. Please point me
> > to the line which directly uses these values.... or how many times I
> > will need to write this is not ABI?
> > 
> 
> The index here is the exact id that needs to be set in the PMC_PCR
> register and so it is dictated by the hardware.

This is the line you are looking for:
https://elixir.bootlin.com/linux/v6.18.2/source/drivers/clk/at91/clk-generated.c#L44

	regmap_write(gck->regmap, gck->layout->offset,
		     (gck->id & gck->layout->pid_mask));

> 
> 
> -- 
> Alexandre Belloni, co-owner and COO, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com

-- 
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From visitorckw at gmail.com  Thu Dec 25 09:31:18 2025
From: visitorckw at gmail.com (Kuan-Wei Chiu)
Date: Thu, 25 Dec 2025 17:31:18 +0000
Subject: [PATCH v2] ARM: dts: integrator: Fix DMA ranges mismatch warning on IM-PD1
Message-ID: <20251225173118.580110-1-visitorckw@gmail.com>

When compiling the device tree for the Integrator/AP with IM-PD1, the
following warning is observed regarding the display controller node:

arch/arm/boot/dts/arm/integratorap-im-pd1.dts:251.3-14: Warning
(dma_ranges_format):
/bus at c0000000/bus at c0000000/display at 1000000:dma-ranges: empty
"dma-ranges" property but its #address-cells (2) differs from
/bus at c0000000/bus at c0000000 (1)

The "dma-ranges" property is intended to describe DMA address
translations for child nodes. However, the only child of the display
controller is a "port" node, which does not perform DMA memory
accesses.

Since the property is not required for the child node and triggers a
warning due to default address cell mismatch, remove it.

Fixes: 7bea67a99430 ("ARM: dts: integrator: Fix DMA ranges")
Cc: stable at vger.kernel.org
Signed-off-by: Kuan-Wei Chiu <visitorckw at gmail.com>
---
Changes in v2:
- Switch approach to remove the unused "dma-ranges" property instead of
  adding "#address-cells" and "#size-cells".

 arch/arm/boot/dts/arm/integratorap-im-pd1.dts | 1 -
 1 file changed, 1 deletion(-)

diff --git a/arch/arm/boot/dts/arm/integratorap-im-pd1.dts b/arch/arm/boot/dts/arm/integratorap-im-pd1.dts
index db13e09f2fab..0e568baf03b0 100644
--- a/arch/arm/boot/dts/arm/integratorap-im-pd1.dts
+++ b/arch/arm/boot/dts/arm/integratorap-im-pd1.dts
@@ -248,7 +248,6 @@ display at 1000000 {
 		/* 640x480 16bpp @ 25.175MHz is 36827428 bytes/s */
 		max-memory-bandwidth = <40000000>;
 		memory-region = <&impd1_ram>;
-		dma-ranges;
 
 		port at 0 {
 			#address-cells = <1>;
-- 
2.52.0.358.g0dd7633a29-goog



From bmasney at redhat.com  Thu Dec 25 09:44:41 2025
From: bmasney at redhat.com (Brian Masney)
Date: Thu, 25 Dec 2025 12:44:41 -0500
Subject: [PATCH v16 1/3] clk: aspeed: Move the existing ASPEED clk
 drivers into aspeed subdirectory.
In-Reply-To: <20251224-upstream_clk-v16-1-8c1318f56c3c@aspeedtech.com>
References: <20251224-upstream_clk-v16-0-8c1318f56c3c@aspeedtech.com>
 <20251224-upstream_clk-v16-1-8c1318f56c3c@aspeedtech.com>
Message-ID: <aU14CWYXtU6MhmhF@redhat.com>

On Wed, Dec 24, 2025 at 01:37:22PM +0800, Ryan Chen wrote:
> Prepare for long-term maintenance and future additions by introducing a
> dedicated drivers/clk/aspeed/ subdirectory for ASPEED clock drivers.
> 
> Move the existing ASPEED clock drivers into the new
> drivers/clk/aspeed/ subdirectory.
> 
> No functional change, file move only.
> 
> Signed-off-by: Ryan Chen <ryan_chen at aspeedtech.com>

Reviewed-by: Brian Masney <bmasney at redhat.com>



From bmasney at redhat.com  Thu Dec 25 09:45:16 2025
From: bmasney at redhat.com (Brian Masney)
Date: Thu, 25 Dec 2025 12:45:16 -0500
Subject: [PATCH v16 2/3] MAINTAINERS: Add entry for ASPEED clock drivers.
In-Reply-To: <20251224-upstream_clk-v16-2-8c1318f56c3c@aspeedtech.com>
References: <20251224-upstream_clk-v16-0-8c1318f56c3c@aspeedtech.com>
 <20251224-upstream_clk-v16-2-8c1318f56c3c@aspeedtech.com>
Message-ID: <aU14LCCn_Cnd8tV6@redhat.com>

On Wed, Dec 24, 2025 at 01:37:23PM +0800, Ryan Chen wrote:
> Add support entry for ASPEED clock drivers.
> 
> Signed-off-by: Ryan Chen <ryan_chen at aspeedtech.com>

Reviewed-by: Brian Masney <bmasney at redhat.com>



From bmasney at redhat.com  Thu Dec 25 09:46:55 2025
From: bmasney at redhat.com (Brian Masney)
Date: Thu, 25 Dec 2025 12:46:55 -0500
Subject: [PATCH 1/3] clk: zynqmp: divider: Fix
 zynqmp_clk_divider_determine_rate kerneldoc
In-Reply-To: <20251224114210.139817-4-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251224114210.139817-4-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <aU14j4Xxes1BJLob@redhat.com>

On Wed, Dec 24, 2025 at 12:42:11PM +0100, Krzysztof Kozlowski wrote:
> After renaming round_rate->determine, kerneldoc does not match anymore,
> causing W=1 warnings:
> 
>   Warning: drivers/clk/zynqmp/divider.c:122 function parameter 'req' not described in 'zynqmp_clk_divider_determine_rate'
>   Warning: drivers/clk/zynqmp/divider.c:122 expecting prototype for zynqmp_clk_divider_round_rate(). Prototype was for zynqmp_clk_divider_determine_rate() instead
> 
> Fixes: 0f9cf96a01fd ("clk: zynqmp: divider: convert from round_rate() to determine_rate()")
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Thanks for the fixup!

Reviewed-by: Brian Masney <bmasney at redhat.com>



From bmasney at redhat.com  Thu Dec 25 09:47:28 2025
From: bmasney at redhat.com (Brian Masney)
Date: Thu, 25 Dec 2025 12:47:28 -0500
Subject: [PATCH 2/3] clk: zynqmp: pll: Fix
 zynqmp_clk_divider_determine_rate kerneldoc
In-Reply-To: <20251224114210.139817-5-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251224114210.139817-4-krzysztof.kozlowski@oss.qualcomm.com>
 <20251224114210.139817-5-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <aU14sKwiL_wJRUO7@redhat.com>

On Wed, Dec 24, 2025 at 12:42:12PM +0100, Krzysztof Kozlowski wrote:
> After renaming round_rate->determine, kerneldoc does not match anymore,
> causing W=1 warnings:
> 
>   pll.c:102 function parameter 'req' not described in 'zynqmp_pll_determine_rate'
>   pll.c:102 expecting prototype for zynqmp_pll_round_rate(). Prototype was for zynqmp_pll_determine_rate() instead
> 
> Fixes: 193650c7a873 ("clk: zynqmp: pll: convert from round_rate() to determine_rate()")
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Thanks for the fixup!

Reviewed-by: Brian Masney <bmasney at redhat.com>



From jernej.skrabec at gmail.com  Thu Dec 25 10:25:57 2025
From: jernej.skrabec at gmail.com (Jernej =?UTF-8?B?xaBrcmFiZWM=?=)
Date: Thu, 25 Dec 2025 19:25:57 +0100
Subject: [PATCH 1/4] dt-bindings: media: sun4i-a10-video-engine: Add interconnect
 properties
In-Reply-To: <20251225103616.3203473-2-wens@kernel.org>
References: <20251225103616.3203473-1-wens@kernel.org>
 <20251225103616.3203473-2-wens@kernel.org>
Message-ID: <5967161.DvuYhMxLoT@jernej-laptop>

Dne ?etrtek, 25. december 2025 ob 11:36:12 Srednjeevropski standardni ?as je Chen-Yu Tsai napisal(a):
> The Allwinner video engine sits behind the MBUS that is represented as
> an interconnect.
> 
> Make sure that the interconnect properties are valid in the binding.
> 
> Fixes: d41662e52a03 ("media: dt-bindings: media: allwinner,sun4i-a10-video-engine: Add R40 compatible")
> Signed-off-by: Chen-Yu Tsai <wens at kernel.org>

Acked-by: Jernej Skrabec <jernej.skrabec at gmail.com>

Best regards,
Jernej




From lkp at intel.com  Thu Dec 25 10:30:49 2025
From: lkp at intel.com (kernel test robot)
Date: Fri, 26 Dec 2025 02:30:49 +0800
Subject: [PATCH 01/12] i2c: add i2c_adapter-specific printk helpers
In-Reply-To: <20251223-i2c-printk-helpers-v1-1-46a08306afdb@oss.qualcomm.com>
References: <20251223-i2c-printk-helpers-v1-1-46a08306afdb@oss.qualcomm.com>
Message-ID: <202512260206.C1TExj8d-lkp@intel.com>

Hi Bartosz,

kernel test robot noticed the following build warnings:

[auto build test WARNING on cc3aa43b44bdb43dfbac0fcb51c56594a11338a8]

url:    https://github.com/intel-lab-lkp/linux/commits/Bartosz-Golaszewski/i2c-add-i2c_adapter-specific-printk-helpers/20251223-185417
base:   cc3aa43b44bdb43dfbac0fcb51c56594a11338a8
patch link:    https://lore.kernel.org/r/20251223-i2c-printk-helpers-v1-1-46a08306afdb%40oss.qualcomm.com
patch subject: [PATCH 01/12] i2c: add i2c_adapter-specific printk helpers
config: parisc-allyesconfig (https://download.01.org/0day-ci/archive/20251226/202512260206.C1TExj8d-lkp at intel.com/config)
compiler: hppa-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251226/202512260206.C1TExj8d-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512260206.C1TExj8d-lkp at intel.com/

All warnings (new ones prefixed by >>):

>> drivers/media/pci/saa7134/saa7134-i2c.c:31:9: warning: 'i2c_dbg' redefined
      31 | #define i2c_dbg(level, fmt, arg...) do { \
         |         ^~~~~~~
   In file included from drivers/media/pci/saa7134/saa7134.h:14,
                    from drivers/media/pci/saa7134/saa7134-i2c.c:10:
   include/linux/i2c.h:775:9: note: this is the location of the previous definition
     775 | #define i2c_dbg(adap, fmt, ...) dev_dbg(&(adap)->dev, fmt, ##__VA_ARGS__)
         |         ^~~~~~~


vim +/i2c_dbg +31 drivers/media/pci/saa7134/saa7134-i2c.c

^1da177e4c3f41 drivers/media/video/saa7134/saa7134-i2c.c Linus Torvalds        2005-04-16  30  
45f38cb3b80311 drivers/media/pci/saa7134/saa7134-i2c.c   Mauro Carvalho Chehab 2015-05-13 @31  #define i2c_dbg(level, fmt, arg...) do { \
45f38cb3b80311 drivers/media/pci/saa7134/saa7134-i2c.c   Mauro Carvalho Chehab 2015-05-13  32  	if (i2c_debug == level) \
45f38cb3b80311 drivers/media/pci/saa7134/saa7134-i2c.c   Mauro Carvalho Chehab 2015-05-13  33  		printk(KERN_DEBUG pr_fmt("i2c: " fmt), ## arg); \
45f38cb3b80311 drivers/media/pci/saa7134/saa7134-i2c.c   Mauro Carvalho Chehab 2015-05-13  34  	} while (0)
45f38cb3b80311 drivers/media/pci/saa7134/saa7134-i2c.c   Mauro Carvalho Chehab 2015-05-13  35  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From jernej.skrabec at gmail.com  Thu Dec 25 10:36:06 2025
From: jernej.skrabec at gmail.com (Jernej =?UTF-8?B?xaBrcmFiZWM=?=)
Date: Thu, 25 Dec 2025 19:36:06 +0100
Subject: [PATCH 2/4] dt-bindings: pinctrl: sunxi: Allow pinmux sub-pattern with
 leading numbers
In-Reply-To: <20251225103616.3203473-3-wens@kernel.org>
References: <20251225103616.3203473-1-wens@kernel.org>
 <20251225103616.3203473-3-wens@kernel.org>
Message-ID: <5080862.31r3eYUQgx@jernej-laptop>

Dne ?etrtek, 25. december 2025 ob 11:36:13 Srednjeevropski standardni ?as je Chen-Yu Tsai napisal(a):
> The pattern for pinmux node names is typically the peripheral name and
> instance number, followed by pingroup name if there are multiple options.
> 
> Normally the instance number is directly appended to the peripheral
> name, like "mmc0" or "i2c2". But if the peripheral name ends with a
> number, then it becomes confusing.
> 
> On the A20, the PS2 interface controller has two instances. This
> produces pinmux node names like "ps2-0-pins". Make the sub-pattern
> "[0-9]-" valid to fit this pattern. Avoid having to confusing "ps20-pins"
> name.
> 
> Signed-off-by: Chen-Yu Tsai <wens at kernel.org>

Acked-by: Jernej Skrabec <jernej.skrabec at gmail.com>

Best regards,
Jernej




From jernej.skrabec at gmail.com  Thu Dec 25 10:37:18 2025
From: jernej.skrabec at gmail.com (Jernej =?UTF-8?B?xaBrcmFiZWM=?=)
Date: Thu, 25 Dec 2025 19:37:18 +0100
Subject: [PATCH 3/4] ARM: dts: allwinner: sun5i-a13-utoo-p66: delete "power-gpios"
 property
In-Reply-To: <20251225103616.3203473-4-wens@kernel.org>
References: <20251225103616.3203473-1-wens@kernel.org>
 <20251225103616.3203473-4-wens@kernel.org>
Message-ID: <2409366.ElGaqSPkdT@jernej-laptop>

Dne ?etrtek, 25. december 2025 ob 11:36:14 Srednjeevropski standardni ?as je Chen-Yu Tsai napisal(a):
> The P66's device tree includes the reference design dtsi files, which
> defines a node and properties for the touchpanel in the common design.
> The P66 dts file then overrides all the properties to match its own
> design, but as the touchpanel model is different, a different schema
> is matched. This other schema uses a different name for the GPIO.
> 
> The original submission added the correct GPIO property, but did not
> delete the one inherited from the reference design, causing validation
> errors.
> 
> Explicitly delete the incorrect GPIO property.
> 
> Fixes: 2a53aff27236 ("ARM: dts: sun5i: Enable touchscreen on Utoo P66")
> Signed-off-by: Chen-Yu Tsai <wens at kernel.org>
> 

Reviewed-by: Jernej Skrabec <jernej.skrabec at gmail.com>

Best regards,
Jernej




From jernej.skrabec at gmail.com  Thu Dec 25 10:49:30 2025
From: jernej.skrabec at gmail.com (Jernej =?UTF-8?B?xaBrcmFiZWM=?=)
Date: Thu, 25 Dec 2025 19:49:30 +0100
Subject: [PATCH 4/4] ARM: dts: allwinner: Replace status "failed" with "fail"
In-Reply-To: <20251225103616.3203473-5-wens@kernel.org>
References: <20251225103616.3203473-1-wens@kernel.org>
 <20251225103616.3203473-5-wens@kernel.org>
Message-ID: <13929653.uLZWGnKmhe@jernej-laptop>

Dne ?etrtek, 25. december 2025 ob 11:36:15 Srednjeevropski standardni ?as je Chen-Yu Tsai napisal(a):
> The device tree bindings specify using "fail", not "failed".
> 
> Fix up all the ones that are wrong.

While patch indeed fixes the issue, I wonder if "fail" is proper value?
According to specs, it means that device needs repair. What about just
keep "disabled"?

Best regards,
Jernej

> 
> Signed-off-by: Chen-Yu Tsai <wens at kernel.org>
> ---
>  arch/arm/boot/dts/allwinner/sun4i-a10-dserve-dsrv9703c.dts | 2 +-
>  arch/arm/boot/dts/allwinner/sun4i-a10-pov-protab2-ips9.dts | 2 +-
>  arch/arm/boot/dts/allwinner/sun6i-a31-hummingbird.dts      | 2 +-
>  arch/arm/boot/dts/allwinner/sun6i-a31s-primo81.dts         | 2 +-
>  4 files changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm/boot/dts/allwinner/sun4i-a10-dserve-dsrv9703c.dts b/arch/arm/boot/dts/allwinner/sun4i-a10-dserve-dsrv9703c.dts
> index 63e77c05bfda..f2413ba6a858 100644
> --- a/arch/arm/boot/dts/allwinner/sun4i-a10-dserve-dsrv9703c.dts
> +++ b/arch/arm/boot/dts/allwinner/sun4i-a10-dserve-dsrv9703c.dts
> @@ -112,7 +112,7 @@ axp209: pmic at 34 {
>  
>  &i2c1 {
>  	/* pull-ups and devices require AXP209 LDO3 */
> -	status = "failed";
> +	status = "fail";
>  };
>  
>  &i2c2 {
> diff --git a/arch/arm/boot/dts/allwinner/sun4i-a10-pov-protab2-ips9.dts b/arch/arm/boot/dts/allwinner/sun4i-a10-pov-protab2-ips9.dts
> index c32596947647..e0c7099015da 100644
> --- a/arch/arm/boot/dts/allwinner/sun4i-a10-pov-protab2-ips9.dts
> +++ b/arch/arm/boot/dts/allwinner/sun4i-a10-pov-protab2-ips9.dts
> @@ -96,7 +96,7 @@ axp209: pmic at 34 {
>  
>  &i2c1 {
>  	/* pull-ups and devices require AXP209 LDO3 */
> -	status = "failed";
> +	status = "fail";
>  };
>  
>  &i2c2 {
> diff --git a/arch/arm/boot/dts/allwinner/sun6i-a31-hummingbird.dts b/arch/arm/boot/dts/allwinner/sun6i-a31-hummingbird.dts
> index 5bce7a32651e..5dfd36e3a49d 100644
> --- a/arch/arm/boot/dts/allwinner/sun6i-a31-hummingbird.dts
> +++ b/arch/arm/boot/dts/allwinner/sun6i-a31-hummingbird.dts
> @@ -170,7 +170,7 @@ hdmi_out_con: endpoint {
>  
>  &i2c0 {
>  	/* pull-ups and devices require AXP221 DLDO3 */
> -	status = "failed";
> +	status = "fail";
>  };
>  
>  &i2c1 {
> diff --git a/arch/arm/boot/dts/allwinner/sun6i-a31s-primo81.dts b/arch/arm/boot/dts/allwinner/sun6i-a31s-primo81.dts
> index b32b70ada7fd..fefd887fbc39 100644
> --- a/arch/arm/boot/dts/allwinner/sun6i-a31s-primo81.dts
> +++ b/arch/arm/boot/dts/allwinner/sun6i-a31s-primo81.dts
> @@ -90,7 +90,7 @@ hdmi_out_con: endpoint {
>  
>  &i2c0 {
>  	/* pull-ups and device VDDIO use AXP221 DLDO3 */
> -	status = "failed";
> +	status = "fail";
>  };
>  
>  &i2c1 {
> 






From jernej.skrabec at gmail.com  Thu Dec 25 11:16:56 2025
From: jernej.skrabec at gmail.com (Jernej =?UTF-8?B?xaBrcmFiZWM=?=)
Date: Thu, 25 Dec 2025 20:16:56 +0100
Subject: [PATCH 5/7] drm/sun4i: Add planes driver
In-Reply-To: <CAGb2v65e2a_f+UEDu-Wk3bWvgHt24erjk+iLWgMAQwB-mzcnaA@mail.gmail.com>
References: <20251115141347.13087-1-jernej.skrabec@gmail.com>
 <CAGb2v65wY2pF6sR+0JgnpLa4ysvjght5hAKDa1RUyo=zEKXreg@mail.gmail.com>
 <CAGb2v65e2a_f+UEDu-Wk3bWvgHt24erjk+iLWgMAQwB-mzcnaA@mail.gmail.com>
Message-ID: <2040104.PYKUYFuaPT@jernej-laptop>

Dne ?etrtek, 25. december 2025 ob 10:37:06 Srednjeevropski standardni ?as je Chen-Yu Tsai napisal(a):
> On Thu, Dec 25, 2025 at 5:29?PM Chen-Yu Tsai <wens at kernel.org> wrote:
> >
> > On Sat, Nov 15, 2025 at 10:14?PM Jernej Skrabec
> > <jernej.skrabec at gmail.com> wrote:
> > >
> > > This driver serves just as planes sharing manager, needed for Display
> > > Engine 3.3 and newer.
> > >
> > > Signed-off-by: Jernej Skrabec <jernej.skrabec at gmail.com>
> > > ---
> > >  drivers/gpu/drm/sun4i/Kconfig         |   8 +
> > >  drivers/gpu/drm/sun4i/Makefile        |   1 +
> > >  drivers/gpu/drm/sun4i/sun50i_planes.c | 205 ++++++++++++++++++++++++++
> > >  drivers/gpu/drm/sun4i/sun50i_planes.h |  43 ++++++
> > >  4 files changed, 257 insertions(+)
> > >  create mode 100644 drivers/gpu/drm/sun4i/sun50i_planes.c
> > >  create mode 100644 drivers/gpu/drm/sun4i/sun50i_planes.h
> > >
> > > diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig
> > > index b56ba00aabca..946dd7606094 100644
> > > --- a/drivers/gpu/drm/sun4i/Kconfig
> > > +++ b/drivers/gpu/drm/sun4i/Kconfig
> > > @@ -85,4 +85,12 @@ config DRM_SUN8I_TCON_TOP
> > >           TCON TOP is responsible for configuring display pipeline for
> > >           HDMI, TVE and LCD.
> > >
> > > +config DRM_SUN50I_PLANES
> > > +       tristate
> > > +       default DRM_SUN4I if DRM_SUN8I_MIXER!=n
> > > +       help
> > > +         Chose this option if you have an Allwinner Soc with the
> > > +         Display Engine 3.3 or newer. Planes are shared resource
> > > +         between multiple mixers.
> > > +
> > >  endif
> > > diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
> > > index bad7497a0d11..03f002abef15 100644
> > > --- a/drivers/gpu/drm/sun4i/Makefile
> > > +++ b/drivers/gpu/drm/sun4i/Makefile
> > > @@ -38,3 +38,4 @@ obj-$(CONFIG_DRM_SUN6I_DSI)   += sun6i_mipi_dsi.o
> > >  obj-$(CONFIG_DRM_SUN8I_DW_HDMI)        += sun8i-drm-hdmi.o
> > >  obj-$(CONFIG_DRM_SUN8I_MIXER)  += sun8i-mixer.o
> > >  obj-$(CONFIG_DRM_SUN8I_TCON_TOP) += sun8i_tcon_top.o
> > > +obj-$(CONFIG_DRM_SUN50I_PLANES)        += sun50i_planes.o
> >
> > I don't think you can have this as a separate module:
> >
> > a. You are using sun8i_vi_layer_init_one() and sun8i_ui_layer_init_one()
> >    from the sun8i-mixer module, and neither of them are exported symbols.
> >
> > b. You export sun50i_planes_setup() for sun8i-mixer to call, which ends
> >    up becoming a circular dependency.
> >
> > The easiest solution would be to just fold this into the sun8i-mixer module.

I mimicked tcon-top module, but yeah, it's much less of a hassle to fold it
into sun8i-mixer.

> >
> >
> > > diff --git a/drivers/gpu/drm/sun4i/sun50i_planes.c b/drivers/gpu/drm/sun4i/sun50i_planes.c
> > > new file mode 100644
> > > index 000000000000..a99c01122990
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/sun4i/sun50i_planes.c
> > > @@ -0,0 +1,205 @@
> > > +// SPDX-License-Identifier: GPL-2.0+
> > > +/* Copyright (c) 2025 Jernej Skrabec <jernej.skrabec at gmail.com> */
> > > +
> > > +#include <linux/device.h>
> > > +#include <linux/io.h>
> > > +#include <linux/mfd/syscon.h>
> > > +#include <linux/module.h>
> > > +#include <linux/of.h>
> > > +#include <linux/of_graph.h>
> > > +#include <linux/platform_device.h>
> > > +
> > > +#include "sun50i_planes.h"
> > > +#include "sun8i_ui_layer.h"
> > > +#include "sun8i_vi_layer.h"
> > > +
> > > +static bool sun50i_planes_node_is_planes(struct device_node *node)
> > > +{
> > > +       return !!of_match_node(sun50i_planes_of_table, node);
> > > +}
> > > +
> > > +struct drm_plane **
> > > +sun50i_planes_setup(struct device *dev, struct drm_device *drm,
> > > +                   unsigned int mixer)
> > > +{
> > > +       struct sun50i_planes *planes = dev_get_drvdata(dev);
> > > +       const struct sun50i_planes_quirks *quirks;
> > > +       struct drm_plane **drm_planes;
> > > +       const struct default_map *map;
> > > +       unsigned int i;
> > > +
> > > +       if (!sun50i_planes_node_is_planes(dev->of_node)) {
> > > +               dev_err(dev, "Device is not planes driver!\n");
> > > +               return NULL;
> > > +       }
> > > +
> > > +       if (!planes) {
> > > +               dev_err(dev, "Planes driver is not loaded yet!\n");
> > > +               return NULL;
> > > +       }
> > > +
> > > +       if (mixer > 1) {
> > > +               dev_err(dev, "Mixer index is too high!\n");
> > > +               return NULL;
> > > +       }
> > > +
> > > +       quirks = planes->quirks;
> > > +       map = &quirks->def_map[mixer];
> > > +
> > > +       drm_planes = devm_kcalloc(drm->dev, map->num_ch + 1,
> >
> > Just a note: it seems we are missing the sentinel in sun8i_layers_init().

Why do you think so? Current mainline code has mixer->cfg->vi_num +
mixer->cfg->ui_num + 1.

> >
> > > +                                 sizeof(*drm_planes), GFP_KERNEL);
> > > +       if (!drm_planes)
> > > +               return ERR_PTR(-ENOMEM);
> > > +
> > > +       for (i = 0; i < map->num_ch; i++) {
> > > +               unsigned int phy_ch = map->map[i];
> > > +               struct sun8i_layer *layer;
> > > +               enum drm_plane_type type;
> > > +
> > > +               if ((i == 0 && map->num_ch == 1) || i == 1)
> > > +                       type = DRM_PLANE_TYPE_PRIMARY;
> > > +               else
> > > +                       type = DRM_PLANE_TYPE_OVERLAY;
> > > +
> > > +               if (phy_ch < UI_PLANE_OFFSET)
> > > +                       layer = sun8i_vi_layer_init_one(drm, type, planes->regs,
> > > +                                                       i, phy_ch, map->num_ch,
> > > +                                                       &quirks->cfg);
> > > +               else
> > > +                       layer = sun8i_ui_layer_init_one(drm, type, planes->regs,
> > > +                                                       i, phy_ch, map->num_ch,
> > > +                                                       &quirks->cfg);
> > > +
> > > +               if (IS_ERR(layer)) {
> > > +                       dev_err(drm->dev,
> > > +                               "Couldn't initialize DRM plane\n");
> > > +                       return ERR_CAST(layer);
> > > +               }
> > > +
> > > +               drm_planes[i] = &layer->plane;
> > > +       }
> > > +
> > > +       return drm_planes;
> > > +}
> > > +EXPORT_SYMBOL(sun50i_planes_setup);
> > > +
> > > +static void sun50i_planes_init_mapping(struct sun50i_planes *planes)
> > > +{
> > > +       const struct sun50i_planes_quirks *quirks = planes->quirks;
> > > +       unsigned int i, j;
> > > +       u32 mapping;
> > > +
> > > +       mapping = 0;
> > > +       for (j = 0; j < MAX_DISP; j++)
> > > +               for (i = 0; i < quirks->def_map[j].num_ch; i++) {
> > > +                       unsigned int ch = quirks->def_map[j].map[i];
> > > +
> > > +                       if (ch < UI_PLANE_OFFSET)
> > > +                               mapping |= j << (ch * 2);
> > > +                       else
> > > +                               mapping |= j << ((ch - UI_PLANE_OFFSET) * 2 + 16);
> > > +               }
> > > +       regmap_write(planes->mapping, SUNXI_DE33_DE_CHN2CORE_MUX_REG, mapping);
> > > +
> > > +       for (j = 0; j < MAX_DISP; j++) {
> > > +               mapping = 0;
> > > +               for (i = 0; i < quirks->def_map[j].num_ch; i++) {
> > > +                       unsigned int ch = quirks->def_map[j].map[i];
> > > +
> > > +                       if (ch >= UI_PLANE_OFFSET)
> > > +                               ch += 2;
> > > +
> > > +                       mapping |= ch << (i * 4);
> > > +               }
> > > +               regmap_write(planes->mapping, SUNXI_DE33_DE_PORT02CHN_MUX_REG + j * 4, mapping);
> > > +       }
> > > +}
> > > +
> > > +static const struct regmap_config sun50i_planes_regmap_config = {
> > > +       .name           = "planes",
> > > +       .reg_bits       = 32,
> > > +       .val_bits       = 32,
> > > +       .reg_stride     = 4,
> > > +       .max_register   = 0x17fffc,
> > > +};
> > > +
> > > +static int sun50i_planes_probe(struct platform_device *pdev)
> > > +{
> > > +       struct device *dev = &pdev->dev;
> > > +       struct sun50i_planes *planes;
> > > +       void __iomem *regs;
> > > +
> > > +       planes = devm_kzalloc(dev, sizeof(*planes), GFP_KERNEL);
> > > +       if (!planes)
> > > +               return -ENOMEM;
> > > +
> > > +       planes->quirks = of_device_get_match_data(&pdev->dev);
> > > +       if (!planes->quirks)
> > > +               return dev_err_probe(dev, -EINVAL, "Unable to get quirks\n");
> > > +
> > > +       planes->mapping = syscon_regmap_lookup_by_phandle(dev->of_node,
> > > +                                                         "allwinner,plane-mapping");
> > > +       if (IS_ERR(planes->mapping))
> > > +               return dev_err_probe(dev, PTR_ERR(planes->mapping),
> > > +                                    "Unable to get mapping\n");
> > > +
> > > +       regs = devm_platform_ioremap_resource(pdev, 0);
> > > +       if (IS_ERR(regs))
> > > +               return PTR_ERR(regs);
> > > +
> > > +       planes->regs = devm_regmap_init_mmio(dev, regs, &sun50i_planes_regmap_config);
> > > +       if (IS_ERR(planes->regs))
> > > +               return PTR_ERR(planes->regs);
> > > +
> > > +       dev_set_drvdata(dev, planes);
> > > +
> > > +       sun50i_planes_init_mapping(planes);
> > > +
> > > +       return 0;
> > > +}
> > > +
> > > +static const struct sun50i_planes_quirks sun50i_h616_planes_quirks = {
> > > +       .def_map = {
> > > +               {
> > > +                       .map = {0, 6, 7},
> > > +                       .num_ch = 3,
> > > +               },
> > > +               {
> > > +                       .map = {1, 2, 8},
> > > +                       .num_ch = 3,
> > > +               },
> > > +       },
> > > +       .cfg = {
> > > +               .de_type        = SUN8I_MIXER_DE33,
> > > +               /*
> > > +                * TODO: All planes support scaling, but driver needs
> > > +                * improvements to properly support it.
> > > +                */
> > > +               .scaler_mask    = 0,
> > > +               .scanline_yuv   = 4096,
> > > +       },
> > > +};
> > > +
> > > +/* sun4i_drv uses this list to check if a device node is a plane */
> 
> I didn't see any usage of this in patch 7. Is this part of another
> series?
> 
> Maybe just export sun50i_planes_node_is_planes() instead?

It's not needed if driver is folder into sun8i-mixer module. Looks like this
is remnant of tcon-top concept...

> 
> > > +const struct of_device_id sun50i_planes_of_table[] = {
> > > +       {
> > > +               .compatible = "allwinner,sun50i-h616-de33-planes",
> > > +               .data = &sun50i_h616_planes_quirks
> > > +       },
> > > +       { }
> > > +};
> > > +MODULE_DEVICE_TABLE(of, sun50i_planes_of_table);
> > > +EXPORT_SYMBOL(sun50i_planes_of_table);
> > > +
> > > +static struct platform_driver sun50i_planes_platform_driver = {
> > > +       .probe          = sun50i_planes_probe,
> > > +       .driver         = {
> > > +               .name           = "sun50i-planes",
> > > +               .of_match_table = sun50i_planes_of_table,
> > > +       },
> > > +};
> > > +module_platform_driver(sun50i_planes_platform_driver);
> > > +
> > > +MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec at gmail.com>");
> > > +MODULE_DESCRIPTION("Allwinner DE33 planes driver");
> > > +MODULE_LICENSE("GPL");
> > > diff --git a/drivers/gpu/drm/sun4i/sun50i_planes.h b/drivers/gpu/drm/sun4i/sun50i_planes.h
> > > new file mode 100644
> > > index 000000000000..446feaeb03fc
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/sun4i/sun50i_planes.h
> > > @@ -0,0 +1,43 @@
> > > +/* SPDX-License-Identifier: GPL-2.0+ */
> > > +/* Copyright (c) 2025 Jernej Skrabec <jernej.skrabec at gmail.com> */
> > > +
> > > +#ifndef _SUN50I_PLANES_H_
> > > +#define _SUN50I_PLANES_H_
> > > +
> > > +#include <drm/drm_device.h>
> > > +#include <linux/regmap.h>
> >
> > I think you could move these two to the .c file, and just use forward
> > declarations here.

Ok.

Best regards,
Jernej

> >
> > The rest looks OK.
> >
> >
> > > +
> > > +#include "sun8i_mixer.h"
> > > +
> > > +/* mapping registers, located in clock register space */
> > > +#define SUNXI_DE33_DE_CHN2CORE_MUX_REG 0x24
> > > +#define SUNXI_DE33_DE_PORT02CHN_MUX_REG        0x28
> > > +#define SUNXI_DE33_DE_PORT12CHN_MUX_REG        0x2c
> > > +
> > > +#define MAX_DISP       2
> > > +#define MAX_CHANNELS   8
> > > +#define UI_PLANE_OFFSET        6
> > > +
> > > +struct default_map {
> > > +       unsigned int map[MAX_CHANNELS];
> > > +       unsigned int num_ch;
> > > +};
> > > +
> > > +struct sun50i_planes_quirks {
> > > +       struct default_map      def_map[MAX_DISP];
> > > +       struct sun8i_layer_cfg  cfg;
> > > +};
> > > +
> > > +struct sun50i_planes {
> > > +       struct regmap                           *regs;
> > > +       struct regmap                           *mapping;
> > > +       const struct sun50i_planes_quirks       *quirks;
> > > +};
> > > +
> > > +extern const struct of_device_id sun50i_planes_of_table[];
> > > +
> > > +struct drm_plane **
> > > +sun50i_planes_setup(struct device *dev, struct drm_device *drm,
> > > +                   unsigned int mixer);
> > > +
> > > +#endif /* _SUN50I_PLANES_H_ */
> > > --
> > > 2.51.2
> > >
> > >
> 






From jernej.skrabec at gmail.com  Thu Dec 25 11:20:29 2025
From: jernej.skrabec at gmail.com (Jernej =?UTF-8?B?xaBrcmFiZWM=?=)
Date: Thu, 25 Dec 2025 20:20:29 +0100
Subject: [PATCH 7/7] drm/sun4i: switch DE33 to new bindings
In-Reply-To: <CAGb2v67B_2SMsDbATVu51Ed+2o+6=FRLw7KmjeL1KYgxm=gyDw@mail.gmail.com>
References: <20251115141347.13087-1-jernej.skrabec@gmail.com>
 <20251115141347.13087-8-jernej.skrabec@gmail.com>
 <CAGb2v67B_2SMsDbATVu51Ed+2o+6=FRLw7KmjeL1KYgxm=gyDw@mail.gmail.com>
Message-ID: <3684052.iIbC2pHGDl@jernej-laptop>

Dne ?etrtek, 25. december 2025 ob 10:49:47 Srednjeevropski standardni ?as je Chen-Yu Tsai napisal(a):
> On Sat, Nov 15, 2025 at 10:14?PM Jernej Skrabec
> <jernej.skrabec at gmail.com> wrote:
> >
> > Now that everything is in place, switch DE33 to new bindings.
> >
> > Signed-off-by: Jernej Skrabec <jernej.skrabec at gmail.com>
> > ---
> >  drivers/gpu/drm/sun4i/sun8i_mixer.c | 130 +++++++++++++++-------------
> >  drivers/gpu/drm/sun4i/sun8i_mixer.h |  10 +--
> >  2 files changed, 71 insertions(+), 69 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
> > index fde3b677e925..da213e54e653 100644
> > --- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
> > +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
> > @@ -13,6 +13,7 @@
> >  #include <linux/of.h>
> >  #include <linux/of_device.h>
> >  #include <linux/of_graph.h>
> > +#include <linux/of_platform.h>
> >  #include <linux/platform_device.h>
> >  #include <linux/reset.h>
> >
> > @@ -24,6 +25,7 @@
> >  #include <drm/drm_probe_helper.h>
> >
> >  #include "sun4i_drv.h"
> > +#include "sun50i_planes.h"
> >  #include "sun8i_mixer.h"
> >  #include "sun8i_ui_layer.h"
> >  #include "sun8i_vi_layer.h"
> > @@ -256,7 +258,6 @@ static void sun8i_mixer_commit(struct sunxi_engine *engine,
> >  {
> >         struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
> >         u32 bld_base = sun8i_blender_base(mixer);
> > -       struct regmap *bld_regs = sun8i_blender_regmap(mixer);
> >         struct drm_plane_state *plane_state;
> >         struct drm_plane *plane;
> >         u32 route = 0, pipe_en = 0;
> > @@ -293,16 +294,16 @@ static void sun8i_mixer_commit(struct sunxi_engine *engine,
> >                 route |= layer->index << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos);
> >                 pipe_en |= SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos);
> >
> > -               regmap_write(bld_regs,
> > +               regmap_write(engine->regs,
> >                              SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos),
> >                              SUN8I_MIXER_COORD(x, y));
> > -               regmap_write(bld_regs,
> > +               regmap_write(engine->regs,
> >                              SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos),
> >                              SUN8I_MIXER_SIZE(w, h));
> >         }
> >
> > -       regmap_write(bld_regs, SUN8I_MIXER_BLEND_ROUTE(bld_base), route);
> > -       regmap_write(bld_regs, SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
> > +       regmap_write(engine->regs, SUN8I_MIXER_BLEND_ROUTE(bld_base), route);
> > +       regmap_write(engine->regs, SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
> >                      pipe_en | SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
> >
> >         if (mixer->cfg->de_type != SUN8I_MIXER_DE33)
> > @@ -317,7 +318,6 @@ static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
> >         struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
> >         int plane_cnt = mixer->cfg->ui_num + mixer->cfg->vi_num;
> >         enum drm_plane_type type;
> > -       unsigned int phy_index;
> >         int i;
> >
> >         planes = devm_kcalloc(drm->dev, plane_cnt, sizeof(*planes), GFP_KERNEL);
> > @@ -332,12 +332,8 @@ static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
> >                 else
> >                         type = DRM_PLANE_TYPE_OVERLAY;
> >
> > -               phy_index = i;
> > -               if (mixer->cfg->de_type == SUN8I_MIXER_DE33)
> > -                       phy_index = mixer->cfg->map[i];
> > -
> >                 layer = sun8i_vi_layer_init_one(drm, type, mixer->engine.regs,
> > -                                               i, phy_index, plane_cnt,
> > +                                               i, i, plane_cnt,
> >                                                 &mixer->cfg->lay_cfg);
> >                 if (IS_ERR(layer)) {
> >                         dev_err(drm->dev,
> > @@ -357,12 +353,8 @@ static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
> >                 else
> >                         type = DRM_PLANE_TYPE_OVERLAY;
> >
> > -               phy_index = index;
> > -               if (mixer->cfg->de_type == SUN8I_MIXER_DE33)
> > -                       phy_index = mixer->cfg->map[index];
> > -
> >                 layer = sun8i_ui_layer_init_one(drm, type, mixer->engine.regs,
> > -                                               index, phy_index, plane_cnt,
> > +                                               index, index, plane_cnt,
> >                                                 &mixer->cfg->lay_cfg);
> >                 if (IS_ERR(layer)) {
> >                         dev_err(drm->dev, "Couldn't initialize %s plane\n",
> > @@ -376,16 +368,25 @@ static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
> >         return planes;
> >  }
> >
> > +static struct drm_plane **sun50i_layers_init(struct drm_device *drm,
> > +                                            struct sunxi_engine *engine)
> > +{
> > +       struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
> > +
> > +       if (IS_ENABLED(CONFIG_DRM_SUN50I_PLANES))
> > +               return sun50i_planes_setup(mixer->planes_dev, drm, engine->id);
> > +
> > +       return NULL;
> > +}
> > +
> >  static void sun8i_mixer_mode_set(struct sunxi_engine *engine,
> >                                  const struct drm_display_mode *mode)
> >  {
> >         struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
> > -       struct regmap *bld_regs;
> >         u32 bld_base, size, val;
> >         bool interlaced;
> >
> >         bld_base = sun8i_blender_base(mixer);
> > -       bld_regs = sun8i_blender_regmap(mixer);
> >         interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
> >         size = SUN8I_MIXER_SIZE(mode->hdisplay, mode->vdisplay);
> >
> > @@ -397,14 +398,14 @@ static void sun8i_mixer_mode_set(struct sunxi_engine *engine,
> >         else
> >                 regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_SIZE, size);
> >
> > -       regmap_write(bld_regs, SUN8I_MIXER_BLEND_OUTSIZE(bld_base), size);
> > +       regmap_write(engine->regs, SUN8I_MIXER_BLEND_OUTSIZE(bld_base), size);
> >
> >         if (interlaced)
> >                 val = SUN8I_MIXER_BLEND_OUTCTL_INTERLACED;
> >         else
> >                 val = 0;
> >
> > -       regmap_update_bits(bld_regs, SUN8I_MIXER_BLEND_OUTCTL(bld_base),
> > +       regmap_update_bits(engine->regs, SUN8I_MIXER_BLEND_OUTCTL(bld_base),
> >                            SUN8I_MIXER_BLEND_OUTCTL_INTERLACED, val);
> >
> >         DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
> > @@ -417,8 +418,14 @@ static const struct sunxi_engine_ops sun8i_engine_ops = {
> >         .mode_set       = sun8i_mixer_mode_set,
> >  };
> >
> > +static const struct sunxi_engine_ops sun50i_engine_ops = {
> > +       .commit         = sun8i_mixer_commit,
> > +       .layers_init    = sun50i_layers_init,
> > +       .mode_set       = sun8i_mixer_mode_set,
> > +};
> > +
> >  static const struct regmap_config sun8i_mixer_regmap_config = {
> > -       .name           = "layers",
> > +       .name           = "display",
> >         .reg_bits       = 32,
> >         .val_bits       = 32,
> >         .reg_stride     = 4,
> > @@ -433,14 +440,6 @@ static const struct regmap_config sun8i_top_regmap_config = {
> >         .max_register   = 0x3c,
> >  };
> >
> > -static const struct regmap_config sun8i_disp_regmap_config = {
> > -       .name           = "display",
> > -       .reg_bits       = 32,
> > -       .val_bits       = 32,
> > -       .reg_stride     = 4,
> > -       .max_register   = 0x20000,
> > -};
> > -
> >  static int sun8i_mixer_of_get_id(struct device_node *node)
> >  {
> >         struct device_node *ep, *remote;
> > @@ -463,17 +462,14 @@ static int sun8i_mixer_of_get_id(struct device_node *node)
> >
> >  static void sun8i_mixer_init(struct sun8i_mixer *mixer)
> >  {
> > -       struct regmap *top_regs, *disp_regs;
> >         unsigned int base = sun8i_blender_base(mixer);
> > +       struct regmap *top_regs;
> >         int plane_cnt, i;
> >
> > -       if (mixer->cfg->de_type == SUN8I_MIXER_DE33) {
> > +       if (mixer->cfg->de_type == SUN8I_MIXER_DE33)
> >                 top_regs = mixer->top_regs;
> > -               disp_regs = mixer->disp_regs;
> > -       } else {
> > +       else
> >                 top_regs = mixer->engine.regs;
> > -               disp_regs = mixer->engine.regs;
> > -       }
> >
> >         /* Enable the mixer */
> >         regmap_write(top_regs, SUN8I_MIXER_GLOBAL_CTL,
> > @@ -483,25 +479,25 @@ static void sun8i_mixer_init(struct sun8i_mixer *mixer)
> >                 regmap_write(top_regs, SUN50I_MIXER_GLOBAL_CLK, 1);
> >
> >         /* Set background color to black */
> > -       regmap_write(disp_regs, SUN8I_MIXER_BLEND_BKCOLOR(base),
> > +       regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR(base),
> >                      SUN8I_MIXER_BLEND_COLOR_BLACK);
> >
> >         /*
> >          * Set fill color of bottom plane to black. Generally not needed
> >          * except when VI plane is at bottom (zpos = 0) and enabled.
> >          */
> > -       regmap_write(disp_regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
> > +       regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
> >                      SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
> > -       regmap_write(disp_regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, 0),
> > +       regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, 0),
> >                      SUN8I_MIXER_BLEND_COLOR_BLACK);
> >
> >         plane_cnt = mixer->cfg->vi_num + mixer->cfg->ui_num;
> >         for (i = 0; i < plane_cnt; i++)
> > -               regmap_write(disp_regs,
> > +               regmap_write(mixer->engine.regs,
> >                              SUN8I_MIXER_BLEND_MODE(base, i),
> >                              SUN8I_MIXER_BLEND_MODE_DEF);
> >
> > -       regmap_update_bits(disp_regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
> > +       regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
> >                            SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0);
> >  }
> >
> > @@ -532,7 +528,6 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
> >         if (!mixer)
> >                 return -ENOMEM;
> >         dev_set_drvdata(dev, mixer);
> > -       mixer->engine.ops = &sun8i_engine_ops;
> >         mixer->engine.node = dev->of_node;
> >
> >         if (of_property_present(dev->of_node, "iommus")) {
> > @@ -562,6 +557,11 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
> >         if (!mixer->cfg)
> >                 return -EINVAL;
> >
> > +       if (mixer->cfg->de_type == SUN8I_MIXER_DE33)
> > +               mixer->engine.ops = &sun50i_engine_ops;
> 
> You're missing an IS_ENABLED() clause here if you wanted to make the DE 3.3
> planes driver optional. Though as I mentioned in the other patch, splittig
> the two modules might not work.

No, as I said in previous response, I'll merge it into sun8i-mixer.

> 
> > +       else
> > +               mixer->engine.ops = &sun8i_engine_ops;
> > +
> >         regs = devm_platform_ioremap_resource(pdev, 0);
> >         if (IS_ERR(regs))
> >                 return PTR_ERR(regs);
> > @@ -584,17 +584,6 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
> >                         dev_err(dev, "Couldn't create the top regmap\n");
> >                         return PTR_ERR(mixer->top_regs);
> >                 }
> > -
> > -               regs = devm_platform_ioremap_resource_byname(pdev, "display");
> > -               if (IS_ERR(regs))
> > -                       return PTR_ERR(regs);
> > -
> > -               mixer->disp_regs = devm_regmap_init_mmio(dev, regs,
> > -                                                        &sun8i_disp_regmap_config);
> > -               if (IS_ERR(mixer->disp_regs)) {
> > -                       dev_err(dev, "Couldn't create the disp regmap\n");
> > -                       return PTR_ERR(mixer->disp_regs);
> > -               }
> >         }
> >
> >         mixer->reset = devm_reset_control_get(dev, NULL);
> > @@ -634,6 +623,33 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
> >
> >         clk_prepare_enable(mixer->mod_clk);
> >
> > +       if (mixer->cfg->de_type == SUN8I_MIXER_DE33) {
> > +               struct platform_device *pdev;
> > +               struct device_node *np;
> > +               void *data;
> > +
> > +               np = of_parse_phandle(dev->of_node, "allwinner,planes", 0);
> > +               if (!np) {
> > +                       ret = -ENODEV;
> > +                       goto err_disable_mod_clk;
> > +               }
> > +
> > +               pdev = of_find_device_by_node(np);
> 
> You need to add a matching put_device() in the unbind function.
> 
> Side note:
> 
> This bind function is using a lot of devm_ functions. These have the wrong
> lifetime. I think it would be better if we could move resource acquisition
> into the probe function.

Good point. This can be clean up later.

> 
> 
> > +               of_node_put(np);
> > +               if (!pdev) {
> > +                       ret = -EPROBE_DEFER;
> > +                       goto err_disable_mod_clk;
> > +               }
> > +
> > +               data = platform_get_drvdata(pdev);
> > +               if (!data) {
> > +                       put_device(&pdev->dev);
> > +                       return -EPROBE_DEFER;
> 
> Should be a goto here?

Right.

Best regards,
Jernej

> 
> 
> ChenYu
> 
> > +               }
> > +
> > +               mixer->planes_dev = &pdev->dev;
> > +       }
> > +
> >         list_add_tail(&mixer->engine.list, &drv->engine_list);
> >
> >         /* Reset registers and disable unused sub-engines */
> > @@ -668,6 +684,8 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
> >
> >         return 0;
> >
> > +err_disable_mod_clk:
> > +       clk_disable_unprepare(mixer->mod_clk);
> >  err_disable_bus_clk:
> >         clk_disable_unprepare(mixer->bus_clk);
> >  err_assert_reset:
> > @@ -863,16 +881,8 @@ static const struct sun8i_mixer_cfg sun50i_h6_mixer0_cfg = {
> >  };
> >
> >  static const struct sun8i_mixer_cfg sun50i_h616_mixer0_cfg = {
> > -       .lay_cfg = {
> > -               .de_type        = SUN8I_MIXER_DE33,
> > -               .scaler_mask    = 0xf,
> > -               .scanline_yuv   = 4096,
> > -       },
> >         .de_type        = SUN8I_MIXER_DE33,
> >         .mod_rate       = 600000000,
> > -       .ui_num         = 3,
> > -       .vi_num         = 1,
> > -       .map            = {0, 6, 7, 8},
> >  };
> >
> >  static const struct of_device_id sun8i_mixer_of_table[] = {
> > diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h b/drivers/gpu/drm/sun4i/sun8i_mixer.h
> > index e2f83301aae8..7abc88c898d9 100644
> > --- a/drivers/gpu/drm/sun4i/sun8i_mixer.h
> > +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
> > @@ -202,7 +202,6 @@ struct sun8i_mixer_cfg {
> >         int                     ui_num;
> >         unsigned int            de_type;
> >         unsigned long           mod_rate;
> > -       unsigned int            map[6];
> >  };
> >
> >  struct sun8i_mixer {
> > @@ -216,7 +215,7 @@ struct sun8i_mixer {
> >         struct clk                      *mod_clk;
> >
> >         struct regmap                   *top_regs;
> > -       struct regmap                   *disp_regs;
> > +       struct device                   *planes_dev;
> >  };
> >
> >  enum {
> > @@ -252,13 +251,6 @@ sun8i_blender_base(struct sun8i_mixer *mixer)
> >         return mixer->cfg->de_type == SUN8I_MIXER_DE3 ? DE3_BLD_BASE : DE2_BLD_BASE;
> >  }
> >
> > -static inline struct regmap *
> > -sun8i_blender_regmap(struct sun8i_mixer *mixer)
> > -{
> > -       return mixer->cfg->de_type == SUN8I_MIXER_DE33 ?
> > -               mixer->disp_regs : mixer->engine.regs;
> > -}
> > -
> >  static inline u32
> >  sun8i_channel_base(struct sun8i_layer *layer)
> >  {
> > --
> > 2.51.2
> >
> >
> 






From wens at kernel.org  Thu Dec 25 11:30:23 2025
From: wens at kernel.org (Chen-Yu Tsai)
Date: Fri, 26 Dec 2025 03:30:23 +0800
Subject: [PATCH 5/7] drm/sun4i: Add planes driver
In-Reply-To: <2040104.PYKUYFuaPT@jernej-laptop>
References: <20251115141347.13087-1-jernej.skrabec@gmail.com>
 <CAGb2v65wY2pF6sR+0JgnpLa4ysvjght5hAKDa1RUyo=zEKXreg@mail.gmail.com>
 <CAGb2v65e2a_f+UEDu-Wk3bWvgHt24erjk+iLWgMAQwB-mzcnaA@mail.gmail.com> <2040104.PYKUYFuaPT@jernej-laptop>
Message-ID: <CAGb2v64bp0BYYdCbaS+wg0H+MD27Bk-n5i8t9X5nVGTG3_hX_Q@mail.gmail.com>

On Fri, Dec 26, 2025 at 3:17?AM Jernej ?krabec <jernej.skrabec at gmail.com> wrote:
>
> Dne ?etrtek, 25. december 2025 ob 10:37:06 Srednjeevropski standardni ?as je Chen-Yu Tsai napisal(a):
> > On Thu, Dec 25, 2025 at 5:29?PM Chen-Yu Tsai <wens at kernel.org> wrote:
> > >
> > > On Sat, Nov 15, 2025 at 10:14?PM Jernej Skrabec
> > > <jernej.skrabec at gmail.com> wrote:
> > > >
> > > > This driver serves just as planes sharing manager, needed for Display
> > > > Engine 3.3 and newer.
> > > >
> > > > Signed-off-by: Jernej Skrabec <jernej.skrabec at gmail.com>
> > > > ---
> > > >  drivers/gpu/drm/sun4i/Kconfig         |   8 +
> > > >  drivers/gpu/drm/sun4i/Makefile        |   1 +
> > > >  drivers/gpu/drm/sun4i/sun50i_planes.c | 205 ++++++++++++++++++++++++++
> > > >  drivers/gpu/drm/sun4i/sun50i_planes.h |  43 ++++++
> > > >  4 files changed, 257 insertions(+)
> > > >  create mode 100644 drivers/gpu/drm/sun4i/sun50i_planes.c
> > > >  create mode 100644 drivers/gpu/drm/sun4i/sun50i_planes.h
> > > >
> > > > diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig
> > > > index b56ba00aabca..946dd7606094 100644
> > > > --- a/drivers/gpu/drm/sun4i/Kconfig
> > > > +++ b/drivers/gpu/drm/sun4i/Kconfig
> > > > @@ -85,4 +85,12 @@ config DRM_SUN8I_TCON_TOP
> > > >           TCON TOP is responsible for configuring display pipeline for
> > > >           HDMI, TVE and LCD.
> > > >
> > > > +config DRM_SUN50I_PLANES
> > > > +       tristate
> > > > +       default DRM_SUN4I if DRM_SUN8I_MIXER!=n
> > > > +       help
> > > > +         Chose this option if you have an Allwinner Soc with the
> > > > +         Display Engine 3.3 or newer. Planes are shared resource
> > > > +         between multiple mixers.
> > > > +
> > > >  endif
> > > > diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
> > > > index bad7497a0d11..03f002abef15 100644
> > > > --- a/drivers/gpu/drm/sun4i/Makefile
> > > > +++ b/drivers/gpu/drm/sun4i/Makefile
> > > > @@ -38,3 +38,4 @@ obj-$(CONFIG_DRM_SUN6I_DSI)   += sun6i_mipi_dsi.o
> > > >  obj-$(CONFIG_DRM_SUN8I_DW_HDMI)        += sun8i-drm-hdmi.o
> > > >  obj-$(CONFIG_DRM_SUN8I_MIXER)  += sun8i-mixer.o
> > > >  obj-$(CONFIG_DRM_SUN8I_TCON_TOP) += sun8i_tcon_top.o
> > > > +obj-$(CONFIG_DRM_SUN50I_PLANES)        += sun50i_planes.o
> > >
> > > I don't think you can have this as a separate module:
> > >
> > > a. You are using sun8i_vi_layer_init_one() and sun8i_ui_layer_init_one()
> > >    from the sun8i-mixer module, and neither of them are exported symbols.
> > >
> > > b. You export sun50i_planes_setup() for sun8i-mixer to call, which ends
> > >    up becoming a circular dependency.
> > >
> > > The easiest solution would be to just fold this into the sun8i-mixer module.
>
> I mimicked tcon-top module, but yeah, it's much less of a hassle to fold it
> into sun8i-mixer.
>
> > >
> > >
> > > > diff --git a/drivers/gpu/drm/sun4i/sun50i_planes.c b/drivers/gpu/drm/sun4i/sun50i_planes.c
> > > > new file mode 100644
> > > > index 000000000000..a99c01122990
> > > > --- /dev/null
> > > > +++ b/drivers/gpu/drm/sun4i/sun50i_planes.c
> > > > @@ -0,0 +1,205 @@
> > > > +// SPDX-License-Identifier: GPL-2.0+
> > > > +/* Copyright (c) 2025 Jernej Skrabec <jernej.skrabec at gmail.com> */
> > > > +
> > > > +#include <linux/device.h>
> > > > +#include <linux/io.h>
> > > > +#include <linux/mfd/syscon.h>
> > > > +#include <linux/module.h>
> > > > +#include <linux/of.h>
> > > > +#include <linux/of_graph.h>
> > > > +#include <linux/platform_device.h>
> > > > +
> > > > +#include "sun50i_planes.h"
> > > > +#include "sun8i_ui_layer.h"
> > > > +#include "sun8i_vi_layer.h"
> > > > +
> > > > +static bool sun50i_planes_node_is_planes(struct device_node *node)
> > > > +{
> > > > +       return !!of_match_node(sun50i_planes_of_table, node);
> > > > +}
> > > > +
> > > > +struct drm_plane **
> > > > +sun50i_planes_setup(struct device *dev, struct drm_device *drm,
> > > > +                   unsigned int mixer)
> > > > +{
> > > > +       struct sun50i_planes *planes = dev_get_drvdata(dev);
> > > > +       const struct sun50i_planes_quirks *quirks;
> > > > +       struct drm_plane **drm_planes;
> > > > +       const struct default_map *map;
> > > > +       unsigned int i;
> > > > +
> > > > +       if (!sun50i_planes_node_is_planes(dev->of_node)) {
> > > > +               dev_err(dev, "Device is not planes driver!\n");
> > > > +               return NULL;
> > > > +       }
> > > > +
> > > > +       if (!planes) {
> > > > +               dev_err(dev, "Planes driver is not loaded yet!\n");
> > > > +               return NULL;
> > > > +       }
> > > > +
> > > > +       if (mixer > 1) {
> > > > +               dev_err(dev, "Mixer index is too high!\n");
> > > > +               return NULL;
> > > > +       }
> > > > +
> > > > +       quirks = planes->quirks;
> > > > +       map = &quirks->def_map[mixer];
> > > > +
> > > > +       drm_planes = devm_kcalloc(drm->dev, map->num_ch + 1,
> > >
> > > Just a note: it seems we are missing the sentinel in sun8i_layers_init().
>
> Why do you think so? Current mainline code has mixer->cfg->vi_num +
> mixer->cfg->ui_num + 1.

I believe this was changed in your previous cleanups:

https://lore.kernel.org/all/20251104180942.61538-16-jernej.skrabec at gmail.com/

ChenYu


From jernej.skrabec at gmail.com  Thu Dec 25 11:34:14 2025
From: jernej.skrabec at gmail.com (Jernej =?UTF-8?B?xaBrcmFiZWM=?=)
Date: Thu, 25 Dec 2025 20:34:14 +0100
Subject: [PATCH 5/7] drm/sun4i: Add planes driver
In-Reply-To: <CAGb2v64bp0BYYdCbaS+wg0H+MD27Bk-n5i8t9X5nVGTG3_hX_Q@mail.gmail.com>
References: <20251115141347.13087-1-jernej.skrabec@gmail.com>
 <2040104.PYKUYFuaPT@jernej-laptop>
 <CAGb2v64bp0BYYdCbaS+wg0H+MD27Bk-n5i8t9X5nVGTG3_hX_Q@mail.gmail.com>
Message-ID: <3333337.5fSG56mABF@jernej-laptop>

Dne ?etrtek, 25. december 2025 ob 20:30:23 Srednjeevropski standardni ?as je Chen-Yu Tsai napisal(a):
> On Fri, Dec 26, 2025 at 3:17?AM Jernej ?krabec <jernej.skrabec at gmail.com> wrote:
> >
> > Dne ?etrtek, 25. december 2025 ob 10:37:06 Srednjeevropski standardni ?as je Chen-Yu Tsai napisal(a):
> > > On Thu, Dec 25, 2025 at 5:29?PM Chen-Yu Tsai <wens at kernel.org> wrote:
> > > >
> > > > On Sat, Nov 15, 2025 at 10:14?PM Jernej Skrabec
> > > > <jernej.skrabec at gmail.com> wrote:
> > > > >
> > > > > This driver serves just as planes sharing manager, needed for Display
> > > > > Engine 3.3 and newer.
> > > > >
> > > > > Signed-off-by: Jernej Skrabec <jernej.skrabec at gmail.com>
> > > > > ---
> > > > >  drivers/gpu/drm/sun4i/Kconfig         |   8 +
> > > > >  drivers/gpu/drm/sun4i/Makefile        |   1 +
> > > > >  drivers/gpu/drm/sun4i/sun50i_planes.c | 205 ++++++++++++++++++++++++++
> > > > >  drivers/gpu/drm/sun4i/sun50i_planes.h |  43 ++++++
> > > > >  4 files changed, 257 insertions(+)
> > > > >  create mode 100644 drivers/gpu/drm/sun4i/sun50i_planes.c
> > > > >  create mode 100644 drivers/gpu/drm/sun4i/sun50i_planes.h
> > > > >
> > > > > diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig
> > > > > index b56ba00aabca..946dd7606094 100644
> > > > > --- a/drivers/gpu/drm/sun4i/Kconfig
> > > > > +++ b/drivers/gpu/drm/sun4i/Kconfig
> > > > > @@ -85,4 +85,12 @@ config DRM_SUN8I_TCON_TOP
> > > > >           TCON TOP is responsible for configuring display pipeline for
> > > > >           HDMI, TVE and LCD.
> > > > >
> > > > > +config DRM_SUN50I_PLANES
> > > > > +       tristate
> > > > > +       default DRM_SUN4I if DRM_SUN8I_MIXER!=n
> > > > > +       help
> > > > > +         Chose this option if you have an Allwinner Soc with the
> > > > > +         Display Engine 3.3 or newer. Planes are shared resource
> > > > > +         between multiple mixers.
> > > > > +
> > > > >  endif
> > > > > diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
> > > > > index bad7497a0d11..03f002abef15 100644
> > > > > --- a/drivers/gpu/drm/sun4i/Makefile
> > > > > +++ b/drivers/gpu/drm/sun4i/Makefile
> > > > > @@ -38,3 +38,4 @@ obj-$(CONFIG_DRM_SUN6I_DSI)   += sun6i_mipi_dsi.o
> > > > >  obj-$(CONFIG_DRM_SUN8I_DW_HDMI)        += sun8i-drm-hdmi.o
> > > > >  obj-$(CONFIG_DRM_SUN8I_MIXER)  += sun8i-mixer.o
> > > > >  obj-$(CONFIG_DRM_SUN8I_TCON_TOP) += sun8i_tcon_top.o
> > > > > +obj-$(CONFIG_DRM_SUN50I_PLANES)        += sun50i_planes.o
> > > >
> > > > I don't think you can have this as a separate module:
> > > >
> > > > a. You are using sun8i_vi_layer_init_one() and sun8i_ui_layer_init_one()
> > > >    from the sun8i-mixer module, and neither of them are exported symbols.
> > > >
> > > > b. You export sun50i_planes_setup() for sun8i-mixer to call, which ends
> > > >    up becoming a circular dependency.
> > > >
> > > > The easiest solution would be to just fold this into the sun8i-mixer module.
> >
> > I mimicked tcon-top module, but yeah, it's much less of a hassle to fold it
> > into sun8i-mixer.
> >
> > > >
> > > >
> > > > > diff --git a/drivers/gpu/drm/sun4i/sun50i_planes.c b/drivers/gpu/drm/sun4i/sun50i_planes.c
> > > > > new file mode 100644
> > > > > index 000000000000..a99c01122990
> > > > > --- /dev/null
> > > > > +++ b/drivers/gpu/drm/sun4i/sun50i_planes.c
> > > > > @@ -0,0 +1,205 @@
> > > > > +// SPDX-License-Identifier: GPL-2.0+
> > > > > +/* Copyright (c) 2025 Jernej Skrabec <jernej.skrabec at gmail.com> */
> > > > > +
> > > > > +#include <linux/device.h>
> > > > > +#include <linux/io.h>
> > > > > +#include <linux/mfd/syscon.h>
> > > > > +#include <linux/module.h>
> > > > > +#include <linux/of.h>
> > > > > +#include <linux/of_graph.h>
> > > > > +#include <linux/platform_device.h>
> > > > > +
> > > > > +#include "sun50i_planes.h"
> > > > > +#include "sun8i_ui_layer.h"
> > > > > +#include "sun8i_vi_layer.h"
> > > > > +
> > > > > +static bool sun50i_planes_node_is_planes(struct device_node *node)
> > > > > +{
> > > > > +       return !!of_match_node(sun50i_planes_of_table, node);
> > > > > +}
> > > > > +
> > > > > +struct drm_plane **
> > > > > +sun50i_planes_setup(struct device *dev, struct drm_device *drm,
> > > > > +                   unsigned int mixer)
> > > > > +{
> > > > > +       struct sun50i_planes *planes = dev_get_drvdata(dev);
> > > > > +       const struct sun50i_planes_quirks *quirks;
> > > > > +       struct drm_plane **drm_planes;
> > > > > +       const struct default_map *map;
> > > > > +       unsigned int i;
> > > > > +
> > > > > +       if (!sun50i_planes_node_is_planes(dev->of_node)) {
> > > > > +               dev_err(dev, "Device is not planes driver!\n");
> > > > > +               return NULL;
> > > > > +       }
> > > > > +
> > > > > +       if (!planes) {
> > > > > +               dev_err(dev, "Planes driver is not loaded yet!\n");
> > > > > +               return NULL;
> > > > > +       }
> > > > > +
> > > > > +       if (mixer > 1) {
> > > > > +               dev_err(dev, "Mixer index is too high!\n");
> > > > > +               return NULL;
> > > > > +       }
> > > > > +
> > > > > +       quirks = planes->quirks;
> > > > > +       map = &quirks->def_map[mixer];
> > > > > +
> > > > > +       drm_planes = devm_kcalloc(drm->dev, map->num_ch + 1,
> > > >
> > > > Just a note: it seems we are missing the sentinel in sun8i_layers_init().
> >
> > Why do you think so? Current mainline code has mixer->cfg->vi_num +
> > mixer->cfg->ui_num + 1.
> 
> I believe this was changed in your previous cleanups:
> 
> https://lore.kernel.org/all/20251104180942.61538-16-jernej.skrabec at gmail.com/

Ah, true. I'll send fix for -rc soon.

Best regards,
Jernej





From lkp at intel.com  Thu Dec 25 11:33:36 2025
From: lkp at intel.com (kernel test robot)
Date: Fri, 26 Dec 2025 03:33:36 +0800
Subject: [PATCH 01/12] i2c: add i2c_adapter-specific printk helpers
In-Reply-To: <20251223-i2c-printk-helpers-v1-1-46a08306afdb@oss.qualcomm.com>
References: <20251223-i2c-printk-helpers-v1-1-46a08306afdb@oss.qualcomm.com>
Message-ID: <202512260303.nUGs1vi7-lkp@intel.com>

Hi Bartosz,

kernel test robot noticed the following build warnings:

[auto build test WARNING on cc3aa43b44bdb43dfbac0fcb51c56594a11338a8]

url:    https://github.com/intel-lab-lkp/linux/commits/Bartosz-Golaszewski/i2c-add-i2c_adapter-specific-printk-helpers/20251223-185417
base:   cc3aa43b44bdb43dfbac0fcb51c56594a11338a8
patch link:    https://lore.kernel.org/r/20251223-i2c-printk-helpers-v1-1-46a08306afdb%40oss.qualcomm.com
patch subject: [PATCH 01/12] i2c: add i2c_adapter-specific printk helpers
config: x86_64-randconfig-013-20251225 (https://download.01.org/0day-ci/archive/20251226/202512260303.nUGs1vi7-lkp at intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251226/202512260303.nUGs1vi7-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512260303.nUGs1vi7-lkp at intel.com/

All warnings (new ones prefixed by >>):

>> drivers/media/pci/saa7134/saa7134-i2c.c:31:9: warning: 'i2c_dbg' macro redefined [-Wmacro-redefined]
      31 | #define i2c_dbg(level, fmt, arg...) do { \
         |         ^
   include/linux/i2c.h:775:9: note: previous definition is here
     775 | #define i2c_dbg(adap, fmt, ...) dev_dbg(&(adap)->dev, fmt, ##__VA_ARGS__)
         |         ^
   1 warning generated.


vim +/i2c_dbg +31 drivers/media/pci/saa7134/saa7134-i2c.c

^1da177e4c3f415 drivers/media/video/saa7134/saa7134-i2c.c Linus Torvalds        2005-04-16  30  
45f38cb3b80311a drivers/media/pci/saa7134/saa7134-i2c.c   Mauro Carvalho Chehab 2015-05-13 @31  #define i2c_dbg(level, fmt, arg...) do { \
45f38cb3b80311a drivers/media/pci/saa7134/saa7134-i2c.c   Mauro Carvalho Chehab 2015-05-13  32  	if (i2c_debug == level) \
45f38cb3b80311a drivers/media/pci/saa7134/saa7134-i2c.c   Mauro Carvalho Chehab 2015-05-13  33  		printk(KERN_DEBUG pr_fmt("i2c: " fmt), ## arg); \
45f38cb3b80311a drivers/media/pci/saa7134/saa7134-i2c.c   Mauro Carvalho Chehab 2015-05-13  34  	} while (0)
45f38cb3b80311a drivers/media/pci/saa7134/saa7134-i2c.c   Mauro Carvalho Chehab 2015-05-13  35  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From vz at mleia.com  Thu Dec 25 12:31:55 2025
From: vz at mleia.com (Vladimir Zapolskiy)
Date: Thu, 25 Dec 2025 22:31:55 +0200
Subject: [PATCH RESEND 0/2] ARM: dts: lpc32xx: set DMA and NAND flash controller properties
Message-ID: <20251225203157.1414349-1-vz@mleia.com>

The changeset adds a numbed of necessary properties to ARM PrimeCell
PL080 DMA controller and to SLC and MLC NAND flash controllers, and now
it obsoletes the platform data of the controllers populated on boot.

To respect any probable users who does not update dtb on the boards,
the platform data cannot be removed instantly, but now it's time to
declare one year timeout for such a synchronization to be completed,
the platform data of DMA and NAND flash controllers will be removed by
the end of the next year.

The changeset is based on top of the previously sent changes:
* https://lore.kernel.org/linux-arm-kernel/20251224165845.1261926-1-vz at mleia.com

Note, the changeset is marked as the resent one, it's identical to the one
https://lore.kernel.org/linux-devicetree/20251225180230.1400420-1-vz at mleia.com/
but now the changeset appears on the linux-arm-kernel mailing list as well.

Vladimir Zapolskiy (2):
  ARM: dts: lpc32xx: add DMA controller properties to the device tree node
  ARM: dts: lpc32xx: add DMA properties to NAND flash controllers

 arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi | 12 ++++++++++++
 1 file changed, 12 insertions(+)

-- 
2.43.0



From vz at mleia.com  Thu Dec 25 12:31:57 2025
From: vz at mleia.com (Vladimir Zapolskiy)
Date: Thu, 25 Dec 2025 22:31:57 +0200
Subject: [PATCH RESEND 2/2] ARM: dts: lpc32xx: add DMA properties to NAND flash controllers
In-Reply-To: <20251225203157.1414349-1-vz@mleia.com>
References: <20251225203157.1414349-1-vz@mleia.com>
Message-ID: <20251225203157.1414349-3-vz@mleia.com>

Add descriptions of DMA request signals for SLC and MLC NAND flash
controllers, for reference see Table 69 from NXP LPC32x0 User Manual.

Signed-off-by: Vladimir Zapolskiy <vz at mleia.com>
---
 arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
index a49b8e794126..9107476fd071 100644
--- a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
+++ b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
@@ -67,6 +67,8 @@ slc: nand-controller at 20020000 {
 			reg = <0x20020000 0x1000>;
 			interrupts = <11 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&clk LPC32XX_CLK_SLC>;
+			dmas = <&dma 1 0>;
+			dma-names = "rx-tx";
 			status = "disabled";
 		};
 
@@ -75,6 +77,8 @@ mlc: nand-controller at 200a8000 {
 			reg = <0x200a8000 0x11000>;
 			interrupts = <11 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&clk LPC32XX_CLK_MLC>;
+			dmas = <&dma 12 0>;
+			dma-names = "rx-tx";
 			status = "disabled";
 		};
 
-- 
2.43.0



From vz at mleia.com  Thu Dec 25 12:31:56 2025
From: vz at mleia.com (Vladimir Zapolskiy)
Date: Thu, 25 Dec 2025 22:31:56 +0200
Subject: [PATCH RESEND 1/2] ARM: dts: lpc32xx: add DMA properties to the device tree node
In-Reply-To: <20251225203157.1414349-1-vz@mleia.com>
References: <20251225203157.1414349-1-vz@mleia.com>
Message-ID: <20251225203157.1414349-2-vz@mleia.com>

Define the supported by ARM PrimeCell PL080 controller properties,
the selected values are tested with dmatest.

Signed-off-by: Vladimir Zapolskiy <vz at mleia.com>
---
 arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
index 5ddaea8c481a..a49b8e794126 100644
--- a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
+++ b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
@@ -84,6 +84,14 @@ dma: dma-controller at 31000000 {
 			interrupts = <28 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&clk LPC32XX_CLK_DMA>;
 			clock-names = "apb_pclk";
+			dma-channels = <8>;
+			dma-requests = <16>;
+			lli-bus-interface-ahb1;
+			lli-bus-interface-ahb2;
+			mem-bus-interface-ahb1;
+			mem-bus-interface-ahb2;
+			memcpy-burst-size = <256>;
+			memcpy-bus-width = <32>;
 			#dma-cells = <2>;
 		};
 
-- 
2.43.0



From andi.shyti at kernel.org  Thu Dec 25 12:32:31 2025
From: andi.shyti at kernel.org (Andi Shyti)
Date: Thu, 25 Dec 2025 21:32:31 +0100
Subject: [PATCH v3 06/15] dt-bindings: i2c: atmel,at91sam: add
 microchip,lan9691-i2c
In-Reply-To: <20251223201921.1332786-7-robert.marko@sartura.hr>
References: <20251223201921.1332786-1-robert.marko@sartura.hr>
 <20251223201921.1332786-7-robert.marko@sartura.hr>
Message-ID: <plir5hx4hpgrj4emspyu3wyvpnax6zz6tlattwq4l2ye3hohkr@ysbjwf2p53lh>

Hi Robert,

On Tue, Dec 23, 2025 at 09:16:17PM +0100, Robert Marko wrote:
> Document Microchip LAN969x I2C compatible.
> 
> Signed-off-by: Robert Marko <robert.marko at sartura.hr>
> Acked-by: Conor Dooley <conor.dooley at microchip.com>

Acked-by: Andi Shyti <andi.shyti at kernel.org>

Thanks,
Andi


From llong at redhat.com  Thu Dec 25 14:27:54 2025
From: llong at redhat.com (Waiman Long)
Date: Thu, 25 Dec 2025 17:27:54 -0500
Subject: [PATCH 05/33] sched/isolation: Save boot defined domain flags
In-Reply-To: <20251224134520.33231-6-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-6-frederic@kernel.org>
Message-ID: <04708b57-7ffe-4a97-925f-926d577061a6@redhat.com>

On 12/24/25 8:44 AM, Frederic Weisbecker wrote:
> HK_TYPE_DOMAIN will soon integrate not only boot defined isolcpus= CPUs
> but also cpuset isolated partitions.
>
> Housekeeping still needs a way to record what was initially passed
> to isolcpus= in order to keep these CPUs isolated after a cpuset
> isolated partition is modified or destroyed while containing some of
> them.
>
> Create a new HK_TYPE_DOMAIN_BOOT to keep track of those.
>
> Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
> Reviewed-by: Phil Auld <pauld at redhat.com>
> ---
>   include/linux/sched/isolation.h | 4 ++++
>   kernel/sched/isolation.c        | 5 +++--
>   2 files changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/include/linux/sched/isolation.h b/include/linux/sched/isolation.h
> index d8501f4709b5..109a2149e21a 100644
> --- a/include/linux/sched/isolation.h
> +++ b/include/linux/sched/isolation.h
> @@ -7,8 +7,12 @@
>   #include <linux/tick.h>
>   
>   enum hk_type {
> +	/* Revert of boot-time isolcpus= argument */
> +	HK_TYPE_DOMAIN_BOOT,
>   	HK_TYPE_DOMAIN,
> +	/* Revert of boot-time isolcpus=managed_irq argument */
>   	HK_TYPE_MANAGED_IRQ,
> +	/* Revert of boot-time nohz_full= or isolcpus=nohz arguments */
>   	HK_TYPE_KERNEL_NOISE,
>   	HK_TYPE_MAX,
>   

"Revert" is a verb. The term "Revert of" sound strange to me. I think 
using "Inverse of" will sound better.

Cheers,
Longman



From llong at redhat.com  Thu Dec 25 14:31:02 2025
From: llong at redhat.com (Waiman Long)
Date: Thu, 25 Dec 2025 17:31:02 -0500
Subject: [PATCH 06/33] cpuset: Convert boot_hk_cpus to use
 HK_TYPE_DOMAIN_BOOT
In-Reply-To: <20251224134520.33231-7-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-7-frederic@kernel.org>
Message-ID: <006b00ab-c8b4-4a2d-aa38-94a41eadd238@redhat.com>

On 12/24/25 8:44 AM, Frederic Weisbecker wrote:
> boot_hk_cpus is an ad-hoc copy of HK_TYPE_DOMAIN_BOOT. Remove it and use
> the official version.
>
> Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
> Reviewed-by: Phil Auld <pauld at redhat.com>
> Reviewed-by: Chen Ridong <chenridong at huawei.com>
> ---
>   kernel/cgroup/cpuset.c | 22 +++++++---------------
>   1 file changed, 7 insertions(+), 15 deletions(-)
>
> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> index 6e6eb09b8db6..3afa72f8d579 100644
> --- a/kernel/cgroup/cpuset.c
> +++ b/kernel/cgroup/cpuset.c
> @@ -88,12 +88,6 @@ static cpumask_var_t	isolated_cpus;
>    */
>   static bool isolated_cpus_updating;
>   
> -/*
> - * Housekeeping (HK_TYPE_DOMAIN) CPUs at boot
> - */
> -static cpumask_var_t	boot_hk_cpus;
> -static bool		have_boot_isolcpus;
> -
>   /*
>    * A flag to force sched domain rebuild at the end of an operation.
>    * It can be set in
> @@ -1453,15 +1447,16 @@ static bool isolated_cpus_can_update(struct cpumask *add_cpus,
>    * @new_cpus: cpu mask
>    * Return: true if there is conflict, false otherwise
>    *
> - * CPUs outside of boot_hk_cpus, if defined, can only be used in an
> + * CPUs outside of HK_TYPE_DOMAIN_BOOT, if defined, can only be used in an
>    * isolated partition.
>    */
>   static bool prstate_housekeeping_conflict(int prstate, struct cpumask *new_cpus)
>   {
> -	if (!have_boot_isolcpus)
> +	if (!housekeeping_enabled(HK_TYPE_DOMAIN_BOOT))
>   		return false;
>   
> -	if ((prstate != PRS_ISOLATED) && !cpumask_subset(new_cpus, boot_hk_cpus))
> +	if ((prstate != PRS_ISOLATED) &&
> +	    !cpumask_subset(new_cpus, housekeeping_cpumask(HK_TYPE_DOMAIN_BOOT)))
>   		return true;
>   
>   	return false;
> @@ -3892,12 +3887,9 @@ int __init cpuset_init(void)
>   
>   	BUG_ON(!alloc_cpumask_var(&cpus_attach, GFP_KERNEL));
>   
> -	have_boot_isolcpus = housekeeping_enabled(HK_TYPE_DOMAIN);
> -	if (have_boot_isolcpus) {
> -		BUG_ON(!alloc_cpumask_var(&boot_hk_cpus, GFP_KERNEL));
> -		cpumask_copy(boot_hk_cpus, housekeeping_cpumask(HK_TYPE_DOMAIN));
> -		cpumask_andnot(isolated_cpus, cpu_possible_mask, boot_hk_cpus);
> -	}
> +	if (housekeeping_enabled(HK_TYPE_DOMAIN_BOOT))
> +		cpumask_andnot(isolated_cpus, cpu_possible_mask,
> +			       housekeeping_cpumask(HK_TYPE_DOMAIN_BOOT));
>   
>   	return 0;
>   }
Reviewed-by: Waiman Long <longman at redhat.com>



From llong at redhat.com  Thu Dec 25 18:24:41 2025
From: llong at redhat.com (Waiman Long)
Date: Thu, 25 Dec 2025 21:24:41 -0500
Subject: [PATCH 14/33] cpuset: Update HK_TYPE_DOMAIN cpumask from cpuset
In-Reply-To: <20251224134520.33231-15-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-15-frederic@kernel.org>
Message-ID: <17aadc7e-7dd6-4335-a748-e66f0239df85@redhat.com>

On 12/24/25 8:45 AM, Frederic Weisbecker wrote:
> Until now, HK_TYPE_DOMAIN used to only include boot defined isolated
> CPUs passed through isolcpus= boot option. Users interested in also
> knowing the runtime defined isolated CPUs through cpuset must use
> different APIs: cpuset_cpu_is_isolated(), cpu_is_isolated(), etc...
>
> There are many drawbacks to that approach:
>
> 1) Most interested subsystems want to know about all isolated CPUs, not
>    just those defined on boot time.
>
> 2) cpuset_cpu_is_isolated() / cpu_is_isolated() are not synchronized with
>    concurrent cpuset changes.
>
> 3) Further cpuset modifications are not propagated to subsystems
>
> Solve 1) and 2) and centralize all isolated CPUs within the
> HK_TYPE_DOMAIN housekeeping cpumask.
>
> Subsystems can rely on RCU to synchronize against concurrent changes.
>
> The propagation mentioned in 3) will be handled in further patches.
>
> Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
> ---
>   include/linux/sched/isolation.h |  7 +++
>   kernel/cgroup/cpuset.c          |  3 ++
>   kernel/sched/isolation.c        | 76 ++++++++++++++++++++++++++++++---
>   kernel/sched/sched.h            |  1 +
>   4 files changed, 81 insertions(+), 6 deletions(-)
>
> diff --git a/include/linux/sched/isolation.h b/include/linux/sched/isolation.h
> index 109a2149e21a..6842a1ba4d13 100644
> --- a/include/linux/sched/isolation.h
> +++ b/include/linux/sched/isolation.h
> @@ -9,6 +9,11 @@
>   enum hk_type {
>   	/* Revert of boot-time isolcpus= argument */
>   	HK_TYPE_DOMAIN_BOOT,
> +	/*
> +	 * Same as HK_TYPE_DOMAIN_BOOT but also includes the
> +	 * revert of cpuset isolated partitions. As such it
> +	 * is always a subset of HK_TYPE_DOMAIN_BOOT.
> +	 */
>   	HK_TYPE_DOMAIN,
>   	/* Revert of boot-time isolcpus=managed_irq argument */
>   	HK_TYPE_MANAGED_IRQ,
> @@ -35,6 +40,7 @@ extern const struct cpumask *housekeeping_cpumask(enum hk_type type);
>   extern bool housekeeping_enabled(enum hk_type type);
>   extern void housekeeping_affine(struct task_struct *t, enum hk_type type);
>   extern bool housekeeping_test_cpu(int cpu, enum hk_type type);
> +extern int housekeeping_update(struct cpumask *isol_mask, enum hk_type type);
>   extern void __init housekeeping_init(void);
>   
>   #else
> @@ -62,6 +68,7 @@ static inline bool housekeeping_test_cpu(int cpu, enum hk_type type)
>   	return true;
>   }
>   
> +static inline int housekeeping_update(struct cpumask *isol_mask, enum hk_type type) { return 0; }
>   static inline void housekeeping_init(void) { }
>   #endif /* CONFIG_CPU_ISOLATION */
>   
> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> index 5e2e3514c22e..e13e32491ebf 100644
> --- a/kernel/cgroup/cpuset.c
> +++ b/kernel/cgroup/cpuset.c
> @@ -1490,6 +1490,9 @@ static void update_isolation_cpumasks(void)
>   	ret = tmigr_isolated_exclude_cpumask(isolated_cpus);
>   	WARN_ON_ONCE(ret < 0);
>   
> +	ret = housekeeping_update(isolated_cpus, HK_TYPE_DOMAIN);
> +	WARN_ON_ONCE(ret < 0);
> +
>   	isolated_cpus_updating = false;
>   }
>   
> diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c
> index 83be49ec2b06..a124f1119f2e 100644
> --- a/kernel/sched/isolation.c
> +++ b/kernel/sched/isolation.c
> @@ -29,18 +29,48 @@ static struct housekeeping housekeeping;
>   
>   bool housekeeping_enabled(enum hk_type type)
>   {
> -	return !!(housekeeping.flags & BIT(type));
> +	return !!(READ_ONCE(housekeeping.flags) & BIT(type));
>   }
>   EXPORT_SYMBOL_GPL(housekeeping_enabled);
>   
> +static bool housekeeping_dereference_check(enum hk_type type)
> +{
> +	if (IS_ENABLED(CONFIG_LOCKDEP) && type == HK_TYPE_DOMAIN) {

To be more correct, we should use IS_ENABLED(CONFIG_PROVE_LOCKING) as 
this is the real kconfig that enables most of the lockdep checking. 
PROVE_LOCKING selects LOCKDEP but not vice versa. So for some weird 
configs that set LOCKDEP but not PROVE_LOCKING, it can cause compilation 
problem.

Other than that, the rest looks good to me.

Cheers,
Longman



From llong at redhat.com  Thu Dec 25 19:20:59 2025
From: llong at redhat.com (Waiman Long)
Date: Thu, 25 Dec 2025 22:20:59 -0500
Subject: [PATCH 14/33] cpuset: Update HK_TYPE_DOMAIN cpumask from cpuset
In-Reply-To: <17aadc7e-7dd6-4335-a748-e66f0239df85@redhat.com>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-15-frederic@kernel.org>
 <17aadc7e-7dd6-4335-a748-e66f0239df85@redhat.com>
Message-ID: <5b019a5c-1db4-41d9-aca9-2e3eaf1cece9@redhat.com>

On 12/25/25 9:24 PM, Waiman Long wrote:
> On 12/24/25 8:45 AM, Frederic Weisbecker wrote:
>> Until now, HK_TYPE_DOMAIN used to only include boot defined isolated
>> CPUs passed through isolcpus= boot option. Users interested in also
>> knowing the runtime defined isolated CPUs through cpuset must use
>> different APIs: cpuset_cpu_is_isolated(), cpu_is_isolated(), etc...
>>
>> There are many drawbacks to that approach:
>>
>> 1) Most interested subsystems want to know about all isolated CPUs, not
>> ?? just those defined on boot time.
>>
>> 2) cpuset_cpu_is_isolated() / cpu_is_isolated() are not synchronized 
>> with
>> ?? concurrent cpuset changes.
>>
>> 3) Further cpuset modifications are not propagated to subsystems
>>
>> Solve 1) and 2) and centralize all isolated CPUs within the
>> HK_TYPE_DOMAIN housekeeping cpumask.
>>
>> Subsystems can rely on RCU to synchronize against concurrent changes.
>>
>> The propagation mentioned in 3) will be handled in further patches.
>>
>> Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
>> ---
>> ? include/linux/sched/isolation.h |? 7 +++
>> ? kernel/cgroup/cpuset.c????????? |? 3 ++
>> ? kernel/sched/isolation.c??????? | 76 ++++++++++++++++++++++++++++++---
>> ? kernel/sched/sched.h??????????? |? 1 +
>> ? 4 files changed, 81 insertions(+), 6 deletions(-)
>>
>> diff --git a/include/linux/sched/isolation.h 
>> b/include/linux/sched/isolation.h
>> index 109a2149e21a..6842a1ba4d13 100644
>> --- a/include/linux/sched/isolation.h
>> +++ b/include/linux/sched/isolation.h
>> @@ -9,6 +9,11 @@
>> ? enum hk_type {
>> ????? /* Revert of boot-time isolcpus= argument */
>> ????? HK_TYPE_DOMAIN_BOOT,
>> +??? /*
>> +???? * Same as HK_TYPE_DOMAIN_BOOT but also includes the
>> +???? * revert of cpuset isolated partitions. As such it
>> +???? * is always a subset of HK_TYPE_DOMAIN_BOOT.
>> +???? */
>> ????? HK_TYPE_DOMAIN,
>> ????? /* Revert of boot-time isolcpus=managed_irq argument */
>> ????? HK_TYPE_MANAGED_IRQ,
>> @@ -35,6 +40,7 @@ extern const struct cpumask 
>> *housekeeping_cpumask(enum hk_type type);
>> ? extern bool housekeeping_enabled(enum hk_type type);
>> ? extern void housekeeping_affine(struct task_struct *t, enum hk_type 
>> type);
>> ? extern bool housekeeping_test_cpu(int cpu, enum hk_type type);
>> +extern int housekeeping_update(struct cpumask *isol_mask, enum 
>> hk_type type);
>> ? extern void __init housekeeping_init(void);
>> ? ? #else
>> @@ -62,6 +68,7 @@ static inline bool housekeeping_test_cpu(int cpu, 
>> enum hk_type type)
>> ????? return true;
>> ? }
>> ? +static inline int housekeeping_update(struct cpumask *isol_mask, 
>> enum hk_type type) { return 0; }
>> ? static inline void housekeeping_init(void) { }
>> ? #endif /* CONFIG_CPU_ISOLATION */
>> ? diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
>> index 5e2e3514c22e..e13e32491ebf 100644
>> --- a/kernel/cgroup/cpuset.c
>> +++ b/kernel/cgroup/cpuset.c
>> @@ -1490,6 +1490,9 @@ static void update_isolation_cpumasks(void)
>> ????? ret = tmigr_isolated_exclude_cpumask(isolated_cpus);
>> ????? WARN_ON_ONCE(ret < 0);
>> ? +??? ret = housekeeping_update(isolated_cpus, HK_TYPE_DOMAIN);
>> +??? WARN_ON_ONCE(ret < 0);
>> +
>> ????? isolated_cpus_updating = false;
>> ? }
>> ? diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c
>> index 83be49ec2b06..a124f1119f2e 100644
>> --- a/kernel/sched/isolation.c
>> +++ b/kernel/sched/isolation.c
>> @@ -29,18 +29,48 @@ static struct housekeeping housekeeping;
>> ? ? bool housekeeping_enabled(enum hk_type type)
>> ? {
>> -??? return !!(housekeeping.flags & BIT(type));
>> +??? return !!(READ_ONCE(housekeeping.flags) & BIT(type));
>> ? }
>> ? EXPORT_SYMBOL_GPL(housekeeping_enabled);
>> ? +static bool housekeeping_dereference_check(enum hk_type type)
>> +{
>> +??? if (IS_ENABLED(CONFIG_LOCKDEP) && type == HK_TYPE_DOMAIN) {
>
> To be more correct, we should use IS_ENABLED(CONFIG_PROVE_LOCKING) as 
> this is the real kconfig that enables most of the lockdep checking. 
> PROVE_LOCKING selects LOCKDEP but not vice versa. So for some weird 
> configs that set LOCKDEP but not PROVE_LOCKING, it can cause 
> compilation problem. 

I think I get confused too. The various lockdep* helpers should be 
defined when CONFIG_LOCKDEP is enabled even if they may not do anything 
useful. So using IS_ENABLED(CONFIG_LOCKDEP) should be fine. Sorry for 
the noise.

Reviewed-by: Waiman Long <longman at redhat.com>



From devnull+guptarud.gmail.com at kernel.org  Thu Dec 25 19:43:19 2025
From: devnull+guptarud.gmail.com at kernel.org (Rudraksha Gupta via B4 Relay)
Date: Thu, 25 Dec 2025 19:43:19 -0800
Subject: [PATCH v6 1/2] arm64: dts: rockchip: Add magnetometer sensor to
 Pinephone Pro
In-Reply-To: <20251225-ppp_light_accel_mag_vol-down-v6-0-8c79a4e87001@gmail.com>
References: <20251225-ppp_light_accel_mag_vol-down-v6-0-8c79a4e87001@gmail.com>
Message-ID: <20251225-ppp_light_accel_mag_vol-down-v6-1-8c79a4e87001@gmail.com>

From: Ondrej Jirman <megi at xff.cz>

Pinephone Pro uses AF8133J according to the schematic.

The mount-matrix was added by Leonardo on top of Ondrej's work of adding
the magnetometer. It was verified with Leonardo's compass app:

https://gitlab.com/lgtrombetta/compass

Co-developed-by: Leonardo G. Trombetta <lgtrombetta at gmx.com>
Signed-off-by: Leonardo G. Trombetta <lgtrombetta at gmx.com>
Signed-off-by: Ondrej Jirman <megi at xff.cz>
Reviewed-by: Pavel Machek <pavel at ucw.cz>
Signed-off-by: Rudraksha Gupta <guptarud at gmail.com>
---
 .../boot/dts/rockchip/rk3399-pinephone-pro.dts     | 23 ++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
index 2dca1dca20b8..1d3baa557c70 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -537,6 +537,23 @@ mpu6500 at 68 {
 	};
 };
 
+&i2c4 {
+	af8133j: compass at 1c {
+		compatible = "voltafield,af8133j";
+		reg = <0x1c>;
+		avdd-supply = <&vcc_3v0>;
+		dvdd-supply = <&vcc_1v8>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&compass_rst_l>;
+		reset-gpios = <&gpio1 RK_PA1 GPIO_ACTIVE_LOW>;
+
+		mount-matrix =
+			"0", "1", "0",
+			"-1", "0", "0",
+			"0", "0", "1";
+	};
+};
+
 &io_domains {
 	bt656-supply = <&vcc1v8_dvp>;
 	audio-supply = <&vcca1v8_codec>;
@@ -649,6 +666,12 @@ dvp_pdn0_h: dvp-pdn0-h {
 		};
 	};
 
+	compass {
+		compass_rst_l: compass-rst-l {
+			rockchip,pins = <1 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
 	leds {
 		red_led_pin: red-led-pin {
 			rockchip,pins = <4 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;

-- 
2.52.0




From devnull+guptarud.gmail.com at kernel.org  Thu Dec 25 19:43:18 2025
From: devnull+guptarud.gmail.com at kernel.org (Rudraksha Gupta via B4 Relay)
Date: Thu, 25 Dec 2025 19:43:18 -0800
Subject: [PATCH v6 0/2] Upstreaming Pinephone Pro Patches
Message-ID: <20251225-ppp_light_accel_mag_vol-down-v6-0-8c79a4e87001@gmail.com>

Throughout the years, many have contributed to the Pinephone Pro (ppp)
development. Unfortunately, these patches are scattered around various
repositories in different states.

I will be attempting to upstream these patches. I will start off with the
following small series:
- Add light/proximity sensor support
  - Link: https://codeberg.org/megi/linux/commit/f171bc7013bc7ad3de9af817bfbcbfa548ebe01c
- Add magnetometer sensor support
  - Link: https://codeberg.org/megi/linux/commit/2f7e67f451f16eaf15b81aa1dbdf126d54927d35
- Add mount-matrix for magnetometer
  - Link: https://codeberg.org/megi/linux/commit/d7cd2eab931e32fa94408a96d73b4e6c0616107a

Already upstreamed:
- Add accelerometer sensor support
  - Link: https://codeberg.org/megi/linux/commit/b0bb7633e073a6760fa213b8c4a78ea2e73c7bf1
- Fix voltage threshold for volume down key
  - Link: https://codeberg.org/megi/linux/commit/7c496a5cc27ed4e38b740f36c2d8b2c62f80ae54

Signed-off-by: Rudraksha Gupta <guptarud at gmail.com>
---
Changes in v6:
- rebased to 6.18
- sorted nodes alphabetically in compass and light/proximity
- added pinctrl to compass
- dropped accelerometer and volume patches as they are merged
- Link to v5: https://lore.kernel.org/r/20251124-ppp_light_accel_mag_vol-down-v5-0-f9a10a0a50eb at gmail.com

Changes in v5:
- use monitor-sensor to verify accelerometer's mount-matrix, lux, proximity
- use Leonardo's compass add to verify the compass's mount matrix
- Link to v4: https://lore.kernel.org/r/20250929-ppp_light_accel_mag_vol-down-v4-0-6598f22d3451 at gmail.com

Changes in v4:
- remove leda-supply and vdd-supply from dts to suppress warning
- credit Martijn and Kamil for the light sensor and accelerometer patches
  - Link: https://fosstodon.org/@martijnbraam/115272859701389599
  - Link: https://codeberg.org/megi/linux/commit/fc5660685ebe4ecf60226bfa27a1ce47c1c1d020
- combine the magnetometer related patches
- corrected accelerometer's mount matrix to Documentation/devicetree/bindings/iio/mount-matrix.txt
- filled out commit messages
- rebased onto v6.17
- Link to v3: https://lore.kernel.org/r/20250921-ppp_light_accel_mag_vol-down-v3-0-7af6651f77e4 at gmail.com

Changes in v3:
- change magnetometer mount matrix
- update volume button threshold
- Link to v2: https://lore.kernel.org/r/20250921-ppp_light_accel_mag_vol-down-v2-0-e6bcc6ca74ae at gmail.com

Changes in v2:
- remove usb-typec node in dts from light/proximity sensor patch
- Link to v1: https://lore.kernel.org/r/20250920-ppp_light_accel_mag_vol-down-v1-0-c8bbcd3e2e94 at gmail.com

---
Ondrej Jirman (2):
      arm64: dts: rockchip: Add magnetometer sensor to Pinephone Pro
      arm64: dts: rockchip: Add light/proximity sensor to Pinephone Pro

 .../boot/dts/rockchip/rk3399-pinephone-pro.dts     | 39 ++++++++++++++++++++++
 1 file changed, 39 insertions(+)
---
base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
change-id: 20250920-ppp_light_accel_mag_vol-down-817c84fdae8d

Best regards,
-- 
Rudraksha Gupta <guptarud at gmail.com>




From devnull+guptarud.gmail.com at kernel.org  Thu Dec 25 19:43:20 2025
From: devnull+guptarud.gmail.com at kernel.org (Rudraksha Gupta via B4 Relay)
Date: Thu, 25 Dec 2025 19:43:20 -0800
Subject: [PATCH v6 2/2] arm64: dts: rockchip: Add light/proximity sensor to
 Pinephone Pro
In-Reply-To: <20251225-ppp_light_accel_mag_vol-down-v6-0-8c79a4e87001@gmail.com>
References: <20251225-ppp_light_accel_mag_vol-down-v6-0-8c79a4e87001@gmail.com>
Message-ID: <20251225-ppp_light_accel_mag_vol-down-v6-2-8c79a4e87001@gmail.com>

From: Ondrej Jirman <megi at xff.cz>

Pinephone Pro uses STK3311 according to the schematics.

Tests:
~ $ monitor-sensor --light
    // When the sensor is exposed, it get's fluctating values such as
    Light changed: 1.800000 (lux)
    Light changed: 1.700000 (lux)
    Light changed: 1.800000 (lux)
    Light changed: 1.700000 (lux)
    Light changed: 1.600000 (lux)
    Light changed: 1.100000 (lux)
    // When covering the sensor, it prints a low value and stops printing
    Light changed: 0.200000 (lux)

~ $ monitor-sensor --proximity
    // When it goes away from an object
    Proximity value changed: 0
    // When it comes near an object
    Proximity value changed: 1

Co-developed-by: Martijn Braam <martijn at brixit.nl>
Signed-off-by: Martijn Braam <martijn at brixit.nl>
Co-developed-by: Kamil Trzci?ski <ayufan at ayufan.eu>
Signed-off-by: Kamil Trzci?ski <ayufan at ayufan.eu>
Signed-off-by: Ondrej Jirman <megi at xff.cz>
Signed-off-by: Rudraksha Gupta <guptarud at gmail.com>
---
 arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
index 1d3baa557c70..e89759613b55 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -520,6 +520,16 @@ touchscreen at 14 {
 		touchscreen-size-x = <720>;
 		touchscreen-size-y = <1440>;
 	};
+
+	light-sensor at 48 {
+		compatible = "sensortek,stk3311";
+		reg = <0x48>;
+		interrupt-parent = <&gpio4>;
+		interrupts = <RK_PD3 IRQ_TYPE_EDGE_FALLING>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&light_int_l>;
+		proximity-near-level = <300>;
+	};
 };
 
 &i2c4 {
@@ -712,6 +722,12 @@ vcc1v8_codec_en: vcc1v8-codec-en {
 		};
 	};
 
+	stk3311 {
+		light_int_l: light-int-l {
+			rockchip,pins = <4 RK_PD3 RK_FUNC_GPIO &pcfg_input_pull_up>;
+		};
+	};
+
 	wifi {
 		wifi_host_wake_l: wifi-host-wake-l {
 			rockchip,pins = <4 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>;

-- 
2.52.0




From vulab at iscas.ac.cn  Thu Dec 25 20:17:11 2025
From: vulab at iscas.ac.cn (Wentao Liang)
Date: Fri, 26 Dec 2025 04:17:11 +0000
Subject: [PATCH] phy: rockchip: inno-usb2: Fix a double free bug in rockchip_usb2phy_probe()
Message-ID: <20251226041711.2369638-1-vulab@iscas.ac.cn>

The for_each_available_child_of_node() calls of_node_put() to
release child_np in each success loop. After breaking from the
loop with the child_np has been released, the code will jump to
the put_child label and will call the of_node_put() again if the
devm_request_threaded_irq() fails. These cause a double free bug.

Fix by using a separate label to avoid the duplicate of_node_put().

Fixes: ed2b5a8e6b98 ("phy: phy-rockchip-inno-usb2: support muxed interrupts")
Cc: stable at vger.kernel.org
Signed-off-by: Wentao Liang <vulab at iscas.ac.cn>
---
 drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
index b0f23690ec30..f754c3b1c357 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
@@ -1491,7 +1491,7 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev)
 						rphy);
 		if (ret) {
 			dev_err_probe(rphy->dev, ret, "failed to request usb2phy irq handle\n");
-			goto put_child;
+			goto ret_error;
 		}
 	}
 
@@ -1499,6 +1499,7 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev)
 
 put_child:
 	of_node_put(child_np);
+ret_error:
 	return ret;
 }
 
-- 
2.34.1



From baolin.wang at linux.alibaba.com  Thu Dec 25 22:07:54 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Fri, 26 Dec 2025 14:07:54 +0800
Subject: [PATCH v5 0/5] support batch checking of references and unmapping for large folios
Message-ID: <cover.1766631066.git.baolin.wang@linux.alibaba.com>

Currently, folio_referenced_one() always checks the young flag for each PTE
sequentially, which is inefficient for large folios. This inefficiency is
especially noticeable when reclaiming clean file-backed large folios, where
folio_referenced() is observed as a significant performance hotspot.

Moreover, on Arm architecture, which supports contiguous PTEs, there is already
an optimization to clear the young flags for PTEs within a contiguous range.
However, this is not sufficient. We can extend this to perform batched operations
for the entire large folio (which might exceed the contiguous range: CONT_PTE_SIZE).

Similar to folio_referenced_one(), we can also apply batched unmapping for large
file folios to optimize the performance of file folio reclamation. By supporting
batched checking of the young flags, flushing TLB entries, and unmapping, I can
observed a significant performance improvements in my performance tests for file
folios reclamation. Please check the performance data in the commit message of
each patch.

Run stress-ng and mm selftests, no issues were found.

Patch 1: Add a new generic batched PTE helper that supports batched checks of
the references for large folios.
Patch 2 - 3: Preparation patches.
patch 4: Implement the Arm64 arch-specific clear_flush_young_ptes().
Patch 5: Support batched unmapping for file large folios.

Changes from v4:
 - Fix passing the incorrect 'CONT_PTES' for non-batched APIs.
 - Rename ptep_clear_flush_young_notify() to clear_flush_young_ptes_notify() (per Ryan).
 - Fix some coding style issues (per Ryan).
 - Add reviewed tag from Ryan. Thanks.

Changes from v3:
 - Fix using an incorrect parameter in ptep_clear_flush_young_notify()
   (per Liam).

Changes from v2:
 - Rearrange the patch set (per Ryan).
 - Add pte_cont() check in clear_flush_young_ptes() (per Ryan).
 - Add a helper to do contpte block alignment (per Ryan).
 - Fix some coding style issues (per Lorenzo and Ryan).
 - Add more comments and update the commit message (per Lorenzo and Ryan).
 - Add acked tag from Barry. Thanks. 

Changes from v1:
 - Add a new patch to support batched unmapping for file large folios.
 - Update the cover letter

Baolin Wang (5):
  mm: rmap: support batched checks of the references for large folios
  arm64: mm: factor out the address and ptep alignment into a new helper
  arm64: mm: support batch clearing of the young flag for large folios
  arm64: mm: implement the architecture-specific
    clear_flush_young_ptes()
  mm: rmap: support batched unmapping for file large folios

 arch/arm64/include/asm/pgtable.h | 23 ++++++++----
 arch/arm64/mm/contpte.c          | 62 ++++++++++++++++++++------------
 include/linux/mmu_notifier.h     |  9 ++---
 include/linux/pgtable.h          | 31 ++++++++++++++++
 mm/rmap.c                        | 38 ++++++++++++++++----
 5 files changed, 125 insertions(+), 38 deletions(-)

-- 
2.47.3



From baolin.wang at linux.alibaba.com  Thu Dec 25 22:07:56 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Fri, 26 Dec 2025 14:07:56 +0800
Subject: [PATCH v5 2/5] arm64: mm: factor out the address and ptep alignment into a new helper
In-Reply-To: <cover.1766631066.git.baolin.wang@linux.alibaba.com>
References: <cover.1766631066.git.baolin.wang@linux.alibaba.com>
Message-ID: <70499ea05beb23fe386b3d4423249a817cec17d4.1766631066.git.baolin.wang@linux.alibaba.com>

Factor out the contpte block's address and ptep alignment into a new helper,
and will be reused in the following patch.

No functional changes.

Reviewed-by: Ryan Roberts <ryan.roberts at arm.com>
Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
---
 arch/arm64/mm/contpte.c | 29 +++++++++++++++++++++--------
 1 file changed, 21 insertions(+), 8 deletions(-)

diff --git a/arch/arm64/mm/contpte.c b/arch/arm64/mm/contpte.c
index 589bcf878938..e4ddeb46f25d 100644
--- a/arch/arm64/mm/contpte.c
+++ b/arch/arm64/mm/contpte.c
@@ -26,6 +26,26 @@ static inline pte_t *contpte_align_down(pte_t *ptep)
 	return PTR_ALIGN_DOWN(ptep, sizeof(*ptep) * CONT_PTES);
 }
 
+static inline pte_t *contpte_align_addr_ptep(unsigned long *start,
+					     unsigned long *end, pte_t *ptep,
+					     unsigned int nr)
+{
+	/*
+	 * Note: caller must ensure these nr PTEs are consecutive (present)
+	 * PTEs that map consecutive pages of the same large folio within a
+	 * single VMA and a single page table.
+	 */
+	if (pte_cont(__ptep_get(ptep + nr - 1)))
+		*end = ALIGN(*end, CONT_PTE_SIZE);
+
+	if (pte_cont(__ptep_get(ptep))) {
+		*start = ALIGN_DOWN(*start, CONT_PTE_SIZE);
+		ptep = contpte_align_down(ptep);
+	}
+
+	return ptep;
+}
+
 static void contpte_try_unfold_partial(struct mm_struct *mm, unsigned long addr,
 					pte_t *ptep, unsigned int nr)
 {
@@ -569,14 +589,7 @@ void contpte_clear_young_dirty_ptes(struct vm_area_struct *vma,
 	unsigned long start = addr;
 	unsigned long end = start + nr * PAGE_SIZE;
 
-	if (pte_cont(__ptep_get(ptep + nr - 1)))
-		end = ALIGN(end, CONT_PTE_SIZE);
-
-	if (pte_cont(__ptep_get(ptep))) {
-		start = ALIGN_DOWN(start, CONT_PTE_SIZE);
-		ptep = contpte_align_down(ptep);
-	}
-
+	ptep = contpte_align_addr_ptep(&start, &end, ptep, nr);
 	__clear_young_dirty_ptes(vma, start, ptep, (end - start) / PAGE_SIZE, flags);
 }
 EXPORT_SYMBOL_GPL(contpte_clear_young_dirty_ptes);
-- 
2.47.3



From baolin.wang at linux.alibaba.com  Thu Dec 25 22:07:55 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Fri, 26 Dec 2025 14:07:55 +0800
Subject: [PATCH v5 1/5] mm: rmap: support batched checks of the references for large folios
In-Reply-To: <cover.1766631066.git.baolin.wang@linux.alibaba.com>
References: <cover.1766631066.git.baolin.wang@linux.alibaba.com>
Message-ID: <18b3eb9c730d16756e5d23c7be22efe2f6219911.1766631066.git.baolin.wang@linux.alibaba.com>

Currently, folio_referenced_one() always checks the young flag for each PTE
sequentially, which is inefficient for large folios. This inefficiency is
especially noticeable when reclaiming clean file-backed large folios, where
folio_referenced() is observed as a significant performance hotspot.

Moreover, on Arm64 architecture, which supports contiguous PTEs, there is already
an optimization to clear the young flags for PTEs within a contiguous range.
However, this is not sufficient. We can extend this to perform batched operations
for the entire large folio (which might exceed the contiguous range: CONT_PTE_SIZE).

Introduce a new API: clear_flush_young_ptes() to facilitate batched checking
of the young flags and flushing TLB entries, thereby improving performance
during large folio reclamation. And it will be overridden by the architecture
that implements a more efficient batch operation in the following patches.

While we are at it, rename ptep_clear_flush_young_notify() to
clear_flush_young_ptes_notify() to indicate that this is a batch operation.

Reviewed-by: Ryan Roberts <ryan.roberts at arm.com>
Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
---
 include/linux/mmu_notifier.h |  9 +++++----
 include/linux/pgtable.h      | 31 +++++++++++++++++++++++++++++++
 mm/rmap.c                    | 31 ++++++++++++++++++++++++++++---
 3 files changed, 64 insertions(+), 7 deletions(-)

diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h
index d1094c2d5fb6..07a2bbaf86e9 100644
--- a/include/linux/mmu_notifier.h
+++ b/include/linux/mmu_notifier.h
@@ -515,16 +515,17 @@ static inline void mmu_notifier_range_init_owner(
 	range->owner = owner;
 }
 
-#define ptep_clear_flush_young_notify(__vma, __address, __ptep)		\
+#define clear_flush_young_ptes_notify(__vma, __address, __ptep, __nr)	\
 ({									\
 	int __young;							\
 	struct vm_area_struct *___vma = __vma;				\
 	unsigned long ___address = __address;				\
-	__young = ptep_clear_flush_young(___vma, ___address, __ptep);	\
+	unsigned int ___nr = __nr;					\
+	__young = clear_flush_young_ptes(___vma, ___address, __ptep, ___nr);	\
 	__young |= mmu_notifier_clear_flush_young(___vma->vm_mm,	\
 						  ___address,		\
 						  ___address +		\
-							PAGE_SIZE);	\
+						  ___nr * PAGE_SIZE);	\
 	__young;							\
 })
 
@@ -650,7 +651,7 @@ static inline void mmu_notifier_subscriptions_destroy(struct mm_struct *mm)
 
 #define mmu_notifier_range_update_to_read_only(r) false
 
-#define ptep_clear_flush_young_notify ptep_clear_flush_young
+#define clear_flush_young_ptes_notify clear_flush_young_ptes
 #define pmdp_clear_flush_young_notify pmdp_clear_flush_young
 #define ptep_clear_young_notify ptep_test_and_clear_young
 #define pmdp_clear_young_notify pmdp_test_and_clear_young
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index 2f0dd3a4ace1..eb8aacba3698 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -1087,6 +1087,37 @@ static inline void wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
 }
 #endif
 
+#ifndef clear_flush_young_ptes
+/**
+ * clear_flush_young_ptes - Clear the access bit and perform a TLB flush for PTEs
+ *			    that map consecutive pages of the same folio.
+ * @vma: The virtual memory area the pages are mapped into.
+ * @addr: Address the first page is mapped at.
+ * @ptep: Page table pointer for the first entry.
+ * @nr: Number of entries to clear access bit.
+ *
+ * May be overridden by the architecture; otherwise, implemented as a simple
+ * loop over ptep_clear_flush_young().
+ *
+ * Note that PTE bits in the PTE range besides the PFN can differ. For example,
+ * some PTEs might be write-protected.
+ *
+ * Context: The caller holds the page table lock.  The PTEs map consecutive
+ * pages that belong to the same folio.  The PTEs are all in the same PMD.
+ */
+static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
+					 unsigned long addr, pte_t *ptep,
+					 unsigned int nr)
+{
+	int i, young = 0;
+
+	for (i = 0; i < nr; ++i, ++ptep, addr += PAGE_SIZE)
+		young |= ptep_clear_flush_young(vma, addr, ptep);
+
+	return young;
+}
+#endif
+
 /*
  * On some architectures hardware does not set page access bit when accessing
  * memory page, it is responsibility of software setting this bit. It brings
diff --git a/mm/rmap.c b/mm/rmap.c
index e805ddc5a27b..985ab0b085ba 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -828,9 +828,11 @@ static bool folio_referenced_one(struct folio *folio,
 	struct folio_referenced_arg *pra = arg;
 	DEFINE_FOLIO_VMA_WALK(pvmw, folio, vma, address, 0);
 	int ptes = 0, referenced = 0;
+	unsigned int nr;
 
 	while (page_vma_mapped_walk(&pvmw)) {
 		address = pvmw.address;
+		nr = 1;
 
 		if (vma->vm_flags & VM_LOCKED) {
 			ptes++;
@@ -875,9 +877,24 @@ static bool folio_referenced_one(struct folio *folio,
 			if (lru_gen_look_around(&pvmw))
 				referenced++;
 		} else if (pvmw.pte) {
-			if (ptep_clear_flush_young_notify(vma, address,
-						pvmw.pte))
+			if (folio_test_large(folio)) {
+				unsigned long end_addr =
+					pmd_addr_end(address, vma->vm_end);
+				unsigned int max_nr =
+					(end_addr - address) >> PAGE_SHIFT;
+				pte_t pteval = ptep_get(pvmw.pte);
+
+				nr = folio_pte_batch(folio, pvmw.pte,
+						     pteval, max_nr);
+			}
+
+			ptes += nr;
+			if (clear_flush_young_ptes_notify(vma, address,
+						pvmw.pte, nr))
 				referenced++;
+			/* Skip the batched PTEs */
+			pvmw.pte += nr - 1;
+			pvmw.address += (nr - 1) * PAGE_SIZE;
 		} else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) {
 			if (pmdp_clear_flush_young_notify(vma, address,
 						pvmw.pmd))
@@ -887,7 +904,15 @@ static bool folio_referenced_one(struct folio *folio,
 			WARN_ON_ONCE(1);
 		}
 
-		pra->mapcount--;
+		pra->mapcount -= nr;
+		/*
+		 * If we are sure that we batched the entire folio,
+		 * we can just optimize and stop right here.
+		 */
+		if (ptes == pvmw.nr_pages) {
+			page_vma_mapped_walk_done(&pvmw);
+			break;
+		}
 	}
 
 	if (referenced)
-- 
2.47.3



From baolin.wang at linux.alibaba.com  Thu Dec 25 22:07:58 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Fri, 26 Dec 2025 14:07:58 +0800
Subject: [PATCH v5 4/5] arm64: mm: implement the architecture-specific clear_flush_young_ptes()
In-Reply-To: <cover.1766631066.git.baolin.wang@linux.alibaba.com>
References: <cover.1766631066.git.baolin.wang@linux.alibaba.com>
Message-ID: <9d866a2644051e13a41ef4d6ca3909c6e1f9e229.1766631066.git.baolin.wang@linux.alibaba.com>

Implement the Arm64 architecture-specific clear_flush_young_ptes() to enable
batched checking of young flags and TLB flushing, improving performance during
large folio reclamation.

Performance testing:
Allocate 10G clean file-backed folios by mmap() in a memory cgroup, and try to
reclaim 8G file-backed folios via the memory.reclaim interface. I can observe
33% performance improvement on my Arm64 32-core server (and 10%+ improvement
on my X86 machine). Meanwhile, the hotspot folio_check_references() dropped
from approximately 35% to around 5%.

W/o patchset:
real	0m1.518s
user	0m0.000s
sys	0m1.518s

W/ patchset:
real	0m1.018s
user	0m0.000s
sys	0m1.018s

Reviewed-by: Ryan Roberts <ryan.roberts at arm.com>
Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
---
 arch/arm64/include/asm/pgtable.h | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 5e9ff16146c3..aa8f642f1260 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -1838,6 +1838,17 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
 	return contpte_clear_flush_young_ptes(vma, addr, ptep, 1);
 }
 
+#define clear_flush_young_ptes clear_flush_young_ptes
+static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
+					 unsigned long addr, pte_t *ptep,
+					 unsigned int nr)
+{
+	if (likely(nr == 1 && !pte_cont(__ptep_get(ptep))))
+		return __ptep_clear_flush_young(vma, addr, ptep);
+
+	return contpte_clear_flush_young_ptes(vma, addr, ptep, nr);
+}
+
 #define wrprotect_ptes wrprotect_ptes
 static __always_inline void wrprotect_ptes(struct mm_struct *mm,
 				unsigned long addr, pte_t *ptep, unsigned int nr)
-- 
2.47.3



From baolin.wang at linux.alibaba.com  Thu Dec 25 22:07:59 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Fri, 26 Dec 2025 14:07:59 +0800
Subject: [PATCH v5 5/5] mm: rmap: support batched unmapping for file large folios
In-Reply-To: <cover.1766631066.git.baolin.wang@linux.alibaba.com>
References: <cover.1766631066.git.baolin.wang@linux.alibaba.com>
Message-ID: <142919ac14d3cf70cba370808d85debe089df7b4.1766631066.git.baolin.wang@linux.alibaba.com>

Similar to folio_referenced_one(), we can apply batched unmapping for file
large folios to optimize the performance of file folios reclamation.

Barry previously implemented batched unmapping for lazyfree anonymous large
folios[1] and did not further optimize anonymous large folios or file-backed
large folios at that stage. As for file-backed large folios, the batched
unmapping support is relatively straightforward, as we only need to clear
the consecutive (present) PTE entries for file-backed large folios.

Performance testing:
Allocate 10G clean file-backed folios by mmap() in a memory cgroup, and try to
reclaim 8G file-backed folios via the memory.reclaim interface. I can observe
75% performance improvement on my Arm64 32-core server (and 50%+ improvement
on my X86 machine) with this patch.

W/o patch:
real    0m1.018s
user    0m0.000s
sys     0m1.018s

W/ patch:
real	0m0.249s
user	0m0.000s
sys	0m0.249s

[1] https://lore.kernel.org/all/20250214093015.51024-4-21cnbao at gmail.com/T/#u
Reviewed-by: Ryan Roberts <ryan.roberts at arm.com>
Acked-by: Barry Song <baohua at kernel.org>
Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
---
 mm/rmap.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/mm/rmap.c b/mm/rmap.c
index 985ab0b085ba..e1d16003c514 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1863,9 +1863,10 @@ static inline unsigned int folio_unmap_pte_batch(struct folio *folio,
 	end_addr = pmd_addr_end(addr, vma->vm_end);
 	max_nr = (end_addr - addr) >> PAGE_SHIFT;
 
-	/* We only support lazyfree batching for now ... */
-	if (!folio_test_anon(folio) || folio_test_swapbacked(folio))
+	/* We only support lazyfree or file folios batching for now ... */
+	if (folio_test_anon(folio) && folio_test_swapbacked(folio))
 		return 1;
+
 	if (pte_unused(pte))
 		return 1;
 
@@ -2231,7 +2232,7 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
 			 *
 			 * See Documentation/mm/mmu_notifier.rst
 			 */
-			dec_mm_counter(mm, mm_counter_file(folio));
+			add_mm_counter(mm, mm_counter_file(folio), -nr_pages);
 		}
 discard:
 		if (unlikely(folio_test_hugetlb(folio))) {
-- 
2.47.3



From baolin.wang at linux.alibaba.com  Thu Dec 25 22:07:57 2025
From: baolin.wang at linux.alibaba.com (Baolin Wang)
Date: Fri, 26 Dec 2025 14:07:57 +0800
Subject: [PATCH v5 3/5] arm64: mm: support batch clearing of the young flag for large folios
In-Reply-To: <cover.1766631066.git.baolin.wang@linux.alibaba.com>
References: <cover.1766631066.git.baolin.wang@linux.alibaba.com>
Message-ID: <a5138065a70a7588904d0bcfc569a5d856dcc65e.1766631066.git.baolin.wang@linux.alibaba.com>

Currently, contpte_ptep_test_and_clear_young() and contpte_ptep_clear_flush_young()
only clear the young flag and flush TLBs for PTEs within the contiguous range.
To support batch PTE operations for other sized large folios in the following
patches, adding a new parameter to specify the number of PTEs that map consecutive
pages of the same large folio in a single VMA and a single page table.

While we are at it, rename the functions to maintain consistency with other
contpte_*() functions.

Signed-off-by: Baolin Wang <baolin.wang at linux.alibaba.com>
---
 arch/arm64/include/asm/pgtable.h | 12 ++++++------
 arch/arm64/mm/contpte.c          | 33 ++++++++++++++++++--------------
 2 files changed, 25 insertions(+), 20 deletions(-)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 445e18e92221..5e9ff16146c3 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -1648,10 +1648,10 @@ extern void contpte_clear_full_ptes(struct mm_struct *mm, unsigned long addr,
 extern pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
 				unsigned long addr, pte_t *ptep,
 				unsigned int nr, int full);
-extern int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
-				unsigned long addr, pte_t *ptep);
-extern int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
-				unsigned long addr, pte_t *ptep);
+int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
+				unsigned long addr, pte_t *ptep, unsigned int nr);
+int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
+				unsigned long addr, pte_t *ptep, unsigned int nr);
 extern void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
 				pte_t *ptep, unsigned int nr);
 extern int contpte_ptep_set_access_flags(struct vm_area_struct *vma,
@@ -1823,7 +1823,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
 	if (likely(!pte_valid_cont(orig_pte)))
 		return __ptep_test_and_clear_young(vma, addr, ptep);
 
-	return contpte_ptep_test_and_clear_young(vma, addr, ptep);
+	return contpte_test_and_clear_young_ptes(vma, addr, ptep, 1);
 }
 
 #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
@@ -1835,7 +1835,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
 	if (likely(!pte_valid_cont(orig_pte)))
 		return __ptep_clear_flush_young(vma, addr, ptep);
 
-	return contpte_ptep_clear_flush_young(vma, addr, ptep);
+	return contpte_clear_flush_young_ptes(vma, addr, ptep, 1);
 }
 
 #define wrprotect_ptes wrprotect_ptes
diff --git a/arch/arm64/mm/contpte.c b/arch/arm64/mm/contpte.c
index e4ddeb46f25d..b929a455103f 100644
--- a/arch/arm64/mm/contpte.c
+++ b/arch/arm64/mm/contpte.c
@@ -508,8 +508,9 @@ pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
 }
 EXPORT_SYMBOL_GPL(contpte_get_and_clear_full_ptes);
 
-int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
-					unsigned long addr, pte_t *ptep)
+int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
+					unsigned long addr, pte_t *ptep,
+					unsigned int nr)
 {
 	/*
 	 * ptep_clear_flush_young() technically requires us to clear the access
@@ -518,41 +519,45 @@ int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
 	 * contig range when the range is covered by a single folio, we can get
 	 * away with clearing young for the whole contig range here, so we avoid
 	 * having to unfold.
+	 *
+	 * The 'nr' means consecutive (present) PTEs that map consecutive pages
+	 * of the same large folio in a single VMA and a single page table.
 	 */
 
+	unsigned long end = addr + nr * PAGE_SIZE;
 	int young = 0;
-	int i;
 
-	ptep = contpte_align_down(ptep);
-	addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
-
-	for (i = 0; i < CONT_PTES; i++, ptep++, addr += PAGE_SIZE)
+	ptep = contpte_align_addr_ptep(&addr, &end, ptep, nr);
+	for (; addr != end; ptep++, addr += PAGE_SIZE)
 		young |= __ptep_test_and_clear_young(vma, addr, ptep);
 
 	return young;
 }
-EXPORT_SYMBOL_GPL(contpte_ptep_test_and_clear_young);
+EXPORT_SYMBOL_GPL(contpte_test_and_clear_young_ptes);
 
-int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
-					unsigned long addr, pte_t *ptep)
+int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
+				unsigned long addr, pte_t *ptep,
+				unsigned int nr)
 {
 	int young;
 
-	young = contpte_ptep_test_and_clear_young(vma, addr, ptep);
+	young = contpte_test_and_clear_young_ptes(vma, addr, ptep, nr);
 
 	if (young) {
+		unsigned long end = addr + nr * PAGE_SIZE;
+
+		contpte_align_addr_ptep(&addr, &end, ptep, nr);
 		/*
 		 * See comment in __ptep_clear_flush_young(); same rationale for
 		 * eliding the trailing DSB applies here.
 		 */
-		addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
-		__flush_tlb_range_nosync(vma->vm_mm, addr, addr + CONT_PTE_SIZE,
+		__flush_tlb_range_nosync(vma->vm_mm, addr, end,
 					 PAGE_SIZE, true, 3);
 	}
 
 	return young;
 }
-EXPORT_SYMBOL_GPL(contpte_ptep_clear_flush_young);
+EXPORT_SYMBOL_GPL(contpte_clear_flush_young_ptes);
 
 void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
 					pte_t *ptep, unsigned int nr)
-- 
2.47.3



From tongweilin at linux.alibaba.com  Thu Dec 25 22:38:00 2025
From: tongweilin at linux.alibaba.com (Weilin Tong)
Date: Fri, 26 Dec 2025 14:38:00 +0800
Subject: [RFC PATCH] arm64: Kconfig: enable ARCH_WANTS_THP_SWAP for all pagesizes
Message-ID: <20251226063759.4020782-2-tongweilin@linux.alibaba.com>

Currently, ARCH_WANTS_THP_SWAP was limited to 4K page size ARM64 kernels, but
large folios requiring swapping also exist in other page size configurations
(e.g. 64K). Without this config, large folios in these kernels cannot be swapped
out.

Here we enable ARCH_WANTS_THP_SWAP for all ARM64 page sizes.

Signed-off-by: Weilin Tong <tongweilin at linux.alibaba.com>
---
 arch/arm64/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 93173f0a09c7..58f7b4405f81 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -120,7 +120,7 @@ config ARM64
 	select ARCH_WANT_LD_ORPHAN_WARN
 	select ARCH_WANTS_EXECMEM_LATE
 	select ARCH_WANTS_NO_INSTR
-	select ARCH_WANTS_THP_SWAP if ARM64_4K_PAGES
+	select ARCH_WANTS_THP_SWAP
 	select ARCH_HAS_UBSAN
 	select ARM_AMBA
 	select ARM_ARCH_TIMER
-- 
2.43.7



From 21cnbao at gmail.com  Thu Dec 25 22:52:44 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Fri, 26 Dec 2025 19:52:44 +1300
Subject: [RFC PATCH] arm64: Kconfig: enable ARCH_WANTS_THP_SWAP for all pagesizes
In-Reply-To: <20251226063759.4020782-2-tongweilin@linux.alibaba.com>
References: <20251226063759.4020782-2-tongweilin@linux.alibaba.com>
Message-ID: <CAGsJ_4zd+SMa4Mj23tjF5OwsP3LQyvYTrwN4y81=k8FSFgbH3Q@mail.gmail.com>

On Fri, Dec 26, 2025 at 7:39?PM Weilin Tong
<tongweilin at linux.alibaba.com> wrote:
>
> Currently, ARCH_WANTS_THP_SWAP was limited to 4K page size ARM64 kernels, but
> large folios requiring swapping also exist in other page size configurations
> (e.g. 64K). Without this config, large folios in these kernels cannot be swapped
> out.
>
> Here we enable ARCH_WANTS_THP_SWAP for all ARM64 page sizes.

I no longer recall why this was not enabled for sizes other than
4 KB in commit d0637c505f8a ("arm64: enable THP_SWAP for arm64"), but
it appears to be fine, and the swap cluster size should also be
more friendly to PMD alignment.


#ifdef CONFIG_THP_SWAP
#define SWAPFILE_CLUSTER        HPAGE_PMD_NR
#define swap_entry_order(order) (order)
#else
#define SWAPFILE_CLUSTER        256
#define swap_entry_order(order) 0
#endif

>
> Signed-off-by: Weilin Tong <tongweilin at linux.alibaba.com>
> ---
>  arch/arm64/Kconfig | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 93173f0a09c7..58f7b4405f81 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -120,7 +120,7 @@ config ARM64
>         select ARCH_WANT_LD_ORPHAN_WARN
>         select ARCH_WANTS_EXECMEM_LATE
>         select ARCH_WANTS_NO_INSTR
> -       select ARCH_WANTS_THP_SWAP if ARM64_4K_PAGES
> +       select ARCH_WANTS_THP_SWAP
>         select ARCH_HAS_UBSAN
>         select ARM_AMBA
>         select ARM_ARCH_TIMER
> --
> 2.43.7

Thanks
Barry


From lucaswei at google.com  Thu Dec 25 23:41:03 2025
From: lucaswei at google.com (Lucas Wei)
Date: Fri, 26 Dec 2025 07:41:03 +0000
Subject: [PATCH] arm64: errata: Workaround for SI L1 downstream coherency issue
Message-ID: <20251226074106.3751725-1-lucaswei@google.com>

When software issues a Cache Maintenance Operation (CMO) targeting a
dirty cache line, the CPU and DSU cluster may optimize the operation by
combining the CopyBack Write and CMO into a single combined CopyBack
Write plus CMO transaction presented to the interconnect (MCN).
For these combined transactions, the MCN splits the operation into two
separate transactions, one Write and one CMO, and then propagates the
write and optionally the CMO to the downstream memory system or external
Point of Serialization (PoS).
However, the MCN may return an early CompCMO response to the DSU cluster
before the corresponding Write and CMO transactions have completed at
the external PoS or downstream memory. As a result, stale data may be
observed by external observers that are directly connected to the
external PoS or downstream memory.

This erratum affects any system topology in which the following
conditions apply:
 - The Point of Serialization (PoS) is located downstream of the
   interconnect.
 - A downstream observer accesses memory directly, bypassing the
   interconnect.

Conditions:
This erratum occurs only when all of the following conditions are met:
 1. Software executes a data cache maintenance operation, specifically,
    a clean or invalidate by virtual address (DC CVAC, DC CIVAC, or DC
    IVAC), that hits on unique dirty data in the CPU or DSU cache. This
    results in a combined CopyBack and CMO being issued to the
    interconnect.
 2. The interconnect splits the combined transaction into separate Write
    and CMO transactions and returns an early completion response to the
    CPU or DSU before the write has completed at the downstream memory
    or PoS.
 3. A downstream observer accesses the affected memory address after the
    early completion response is issued but before the actual memory
    write has completed. This allows the observer to read stale data
    that has not yet been updated at the PoS or downstream memory.

The implementation of workaround put a second loop of CMOs at the same
virtual address whose operation meet erratum conditions to wait until
cache data be cleaned to PoC.. This way of implementation mitigates
performance panalty compared to purly duplicate orignial CMO.

Cc: stable at vger.kernel.org # 6.12.x
Signed-off-by: Lucas Wei <lucaswei at google.com>
---
 Documentation/arch/arm64/silicon-errata.rst |  3 ++
 arch/arm64/Kconfig                          | 19 +++++++++++++
 arch/arm64/include/asm/assembler.h          | 10 +++++++
 arch/arm64/kernel/cpu_errata.c              | 31 +++++++++++++++++++++
 arch/arm64/mm/cache.S                       | 13 ++++++++-
 arch/arm64/tools/cpucaps                    |  1 +
 6 files changed, 76 insertions(+), 1 deletion(-)

diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst
index a7ec57060f64..98efdf528719 100644
--- a/Documentation/arch/arm64/silicon-errata.rst
+++ b/Documentation/arch/arm64/silicon-errata.rst
@@ -213,6 +213,9 @@ stable kernels.
 | ARM            | GIC-700         | #2941627        | ARM64_ERRATUM_2941627       |
 +----------------+-----------------+-----------------+-----------------------------+
 +----------------+-----------------+-----------------+-----------------------------+
+| ARM            | SI L1           | #4311569        | ARM64_ERRATUM_4311569       |
++----------------+-----------------+-----------------+-----------------------------+
++----------------+-----------------+-----------------+-----------------------------+
 | Broadcom       | Brahma-B53      | N/A             | ARM64_ERRATUM_845719        |
 +----------------+-----------------+-----------------+-----------------------------+
 | Broadcom       | Brahma-B53      | N/A             | ARM64_ERRATUM_843419        |
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 93173f0a09c7..89326bb26f48 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1155,6 +1155,25 @@ config ARM64_ERRATUM_3194386
 
 	  If unsure, say Y.
 
+config ARM64_ERRATUM_4311569
+	bool "SI L1: 4311569: workaround for premature CMO completion erratum"
+	default y
+	help
+	  This option adds the workaround for ARM SI L1 erratum 4311569.
+
+	  The erratum of SI L1 can cause an early response to a combined write
+	  and cache maintenance operation (WR+CMO) before the operation is fully
+	  completed to the Point of Serialization (POS).
+	  This can result in a non-I/O coherent agent observing stale data,
+	  potentially leading to system instability or incorrect behavior.
+
+	  Enabling this option implements a software workaround by inserting a
+	  second loop of Cache Maintenance Operation (CMO) immediately following the
+	  end of function to do CMOs. This ensures that the data is correctly serialized
+	  before the buffer is handed off to a non-coherent agent.
+
+	  If unsure, say Y.
+
 config CAVIUM_ERRATUM_22375
 	bool "Cavium erratum 22375, 24313"
 	default y
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index f0ca7196f6fa..d3d46e5f7188 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -381,6 +381,9 @@ alternative_endif
 	.macro dcache_by_myline_op op, domain, start, end, linesz, tmp, fixup
 	sub	\tmp, \linesz, #1
 	bic	\start, \start, \tmp
+alternative_if ARM64_WORKAROUND_4311569
+	mov	\tmp, \start
+alternative_else_nop_endif
 .Ldcache_op\@:
 	.ifc	\op, cvau
 	__dcache_op_workaround_clean_cache \op, \start
@@ -402,6 +405,13 @@ alternative_endif
 	add	\start, \start, \linesz
 	cmp	\start, \end
 	b.lo	.Ldcache_op\@
+alternative_if ARM64_WORKAROUND_4311569
+	.ifnc	\op, cvau
+	mov	\start, \tmp
+	mov	\tmp, xzr
+	cbnz	\start, .Ldcache_op\@
+	.endif
+alternative_else_nop_endif
 	dsb	\domain
 
 	_cond_uaccess_extable .Ldcache_op\@, \fixup
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index 8cb3b575a031..c69678c512f1 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -141,6 +141,30 @@ has_mismatched_cache_type(const struct arm64_cpu_capabilities *entry,
 	return (ctr_real != sys) && (ctr_raw != sys);
 }
 
+#ifdef CONFIG_ARM64_ERRATUM_4311569
+DEFINE_STATIC_KEY_FALSE(arm_si_l1_workaround_4311569);
+static int __init early_arm_si_l1_workaround_4311569_cfg(char *arg)
+{
+	static_branch_enable(&arm_si_l1_workaround_4311569);
+	pr_info("Enabling cache maintenance workaround for ARM SI-L1 erratum 4311569\n");
+
+	return 0;
+}
+early_param("arm_si_l1_workaround_4311569", early_arm_si_l1_workaround_4311569_cfg);
+
+/*
+ * We have some earlier use cases to call cache maintenance operation functions, for example,
+ * dcache_inval_poc() and dcache_clean_poc() in head.S, before making decision to turn on this
+ * workaround. Since the scope of this workaround is limited to non-coherent DMA agents, its
+ * safe to have the workaround off by default.
+ */
+static bool
+need_arm_si_l1_workaround_4311569(const struct arm64_cpu_capabilities *entry, int scope)
+{
+	return static_branch_unlikely(&arm_si_l1_workaround_4311569);
+}
+#endif
+
 static void
 cpu_enable_trap_ctr_access(const struct arm64_cpu_capabilities *cap)
 {
@@ -870,6 +894,13 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
 		ERRATA_MIDR_RANGE_LIST(erratum_spec_ssbs_list),
 	},
 #endif
+#ifdef CONFIG_ARM64_ERRATUM_4311569
+	{
+		.capability = ARM64_WORKAROUND_4311569,
+		.type = ARM64_CPUCAP_SYSTEM_FEATURE,
+		.matches = need_arm_si_l1_workaround_4311569,
+	},
+#endif
 #ifdef CONFIG_ARM64_WORKAROUND_SPECULATIVE_UNPRIV_LOAD
 	{
 		.desc = "ARM errata 2966298, 3117295",
diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S
index 503567c864fd..ddf0097624ed 100644
--- a/arch/arm64/mm/cache.S
+++ b/arch/arm64/mm/cache.S
@@ -143,9 +143,14 @@ SYM_FUNC_END(dcache_clean_pou)
  *	- end     - kernel end address of region
  */
 SYM_FUNC_START(__pi_dcache_inval_poc)
+alternative_if ARM64_WORKAROUND_4311569
+	mov	x4, x0
+	mov	x5, x1
+	mov	x6, #1
+alternative_else_nop_endif
 	dcache_line_size x2, x3
 	sub	x3, x2, #1
-	tst	x1, x3				// end cache line aligned?
+again:	tst	x1, x3				// end cache line aligned?
 	bic	x1, x1, x3
 	b.eq	1f
 	dc	civac, x1			// clean & invalidate D / U line
@@ -158,6 +163,12 @@ SYM_FUNC_START(__pi_dcache_inval_poc)
 3:	add	x0, x0, x2
 	cmp	x0, x1
 	b.lo	2b
+alternative_if ARM64_WORKAROUND_4311569
+	mov	x0, x4
+	mov	x1, x5
+	sub	x6, x6, #1
+	cbz	x6, again
+alternative_else_nop_endif
 	dsb	sy
 	ret
 SYM_FUNC_END(__pi_dcache_inval_poc)
diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps
index 0fac75f01534..856b6cf6e71e 100644
--- a/arch/arm64/tools/cpucaps
+++ b/arch/arm64/tools/cpucaps
@@ -103,6 +103,7 @@ WORKAROUND_2077057
 WORKAROUND_2457168
 WORKAROUND_2645198
 WORKAROUND_2658417
+WORKAROUND_4311569
 WORKAROUND_AMPERE_AC03_CPU_38
 WORKAROUND_AMPERE_AC04_CPU_23
 WORKAROUND_TRBE_OVERWRITE_FILL_MODE
-- 
2.52.0.358.g0dd7633a29-goog



From chenridong at huaweicloud.com  Fri Dec 26 00:08:04 2025
From: chenridong at huaweicloud.com (Chen Ridong)
Date: Fri, 26 Dec 2025 16:08:04 +0800
Subject: [PATCH 14/33] cpuset: Update HK_TYPE_DOMAIN cpumask from cpuset
In-Reply-To: <20251224134520.33231-15-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-15-frederic@kernel.org>
Message-ID: <8ecb22ab-d719-44b4-ad40-5af0a185682a@huaweicloud.com>



On 2025/12/24 21:45, Frederic Weisbecker wrote:
> Until now, HK_TYPE_DOMAIN used to only include boot defined isolated
> CPUs passed through isolcpus= boot option. Users interested in also
> knowing the runtime defined isolated CPUs through cpuset must use
> different APIs: cpuset_cpu_is_isolated(), cpu_is_isolated(), etc...
> 
> There are many drawbacks to that approach:
> 
> 1) Most interested subsystems want to know about all isolated CPUs, not
>   just those defined on boot time.
> 
> 2) cpuset_cpu_is_isolated() / cpu_is_isolated() are not synchronized with
>   concurrent cpuset changes.
> 
> 3) Further cpuset modifications are not propagated to subsystems
> 
> Solve 1) and 2) and centralize all isolated CPUs within the
> HK_TYPE_DOMAIN housekeeping cpumask.
> 
> Subsystems can rely on RCU to synchronize against concurrent changes.
> 
> The propagation mentioned in 3) will be handled in further patches.
> 
> Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
> ---
>  include/linux/sched/isolation.h |  7 +++
>  kernel/cgroup/cpuset.c          |  3 ++
>  kernel/sched/isolation.c        | 76 ++++++++++++++++++++++++++++++---
>  kernel/sched/sched.h            |  1 +
>  4 files changed, 81 insertions(+), 6 deletions(-)
> 
> diff --git a/include/linux/sched/isolation.h b/include/linux/sched/isolation.h
> index 109a2149e21a..6842a1ba4d13 100644
> --- a/include/linux/sched/isolation.h
> +++ b/include/linux/sched/isolation.h
> @@ -9,6 +9,11 @@
>  enum hk_type {
>  	/* Revert of boot-time isolcpus= argument */
>  	HK_TYPE_DOMAIN_BOOT,
> +	/*
> +	 * Same as HK_TYPE_DOMAIN_BOOT but also includes the
> +	 * revert of cpuset isolated partitions. As such it
> +	 * is always a subset of HK_TYPE_DOMAIN_BOOT.
> +	 */
>  	HK_TYPE_DOMAIN,
>  	/* Revert of boot-time isolcpus=managed_irq argument */
>  	HK_TYPE_MANAGED_IRQ,
> @@ -35,6 +40,7 @@ extern const struct cpumask *housekeeping_cpumask(enum hk_type type);
>  extern bool housekeeping_enabled(enum hk_type type);
>  extern void housekeeping_affine(struct task_struct *t, enum hk_type type);
>  extern bool housekeeping_test_cpu(int cpu, enum hk_type type);
> +extern int housekeeping_update(struct cpumask *isol_mask, enum hk_type type);
>  extern void __init housekeeping_init(void);
>  
>  #else
> @@ -62,6 +68,7 @@ static inline bool housekeeping_test_cpu(int cpu, enum hk_type type)
>  	return true;
>  }
>  
> +static inline int housekeeping_update(struct cpumask *isol_mask, enum hk_type type) { return 0; }
>  static inline void housekeeping_init(void) { }
>  #endif /* CONFIG_CPU_ISOLATION */
>  
> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> index 5e2e3514c22e..e13e32491ebf 100644
> --- a/kernel/cgroup/cpuset.c
> +++ b/kernel/cgroup/cpuset.c
> @@ -1490,6 +1490,9 @@ static void update_isolation_cpumasks(void)
>  	ret = tmigr_isolated_exclude_cpumask(isolated_cpus);
>  	WARN_ON_ONCE(ret < 0);
>  
> +	ret = housekeeping_update(isolated_cpus, HK_TYPE_DOMAIN);
> +	WARN_ON_ONCE(ret < 0);
> +
>  	isolated_cpus_updating = false;
>  }
>  
> diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c
> index 83be49ec2b06..a124f1119f2e 100644
> --- a/kernel/sched/isolation.c
> +++ b/kernel/sched/isolation.c
> @@ -29,18 +29,48 @@ static struct housekeeping housekeeping;
>  
>  bool housekeeping_enabled(enum hk_type type)
>  {
> -	return !!(housekeeping.flags & BIT(type));
> +	return !!(READ_ONCE(housekeeping.flags) & BIT(type));
>  }
>  EXPORT_SYMBOL_GPL(housekeeping_enabled);
>  
> +static bool housekeeping_dereference_check(enum hk_type type)
> +{
> +	if (IS_ENABLED(CONFIG_LOCKDEP) && type == HK_TYPE_DOMAIN) {
> +		/* Cpuset isn't even writable yet? */
> +		if (system_state <= SYSTEM_SCHEDULING)
> +			return true;
> +
> +		/* CPU hotplug write locked, so cpuset partition can't be overwritten */
> +		if (IS_ENABLED(CONFIG_HOTPLUG_CPU) && lockdep_is_cpus_write_held())
> +			return true;
> +
> +		/* Cpuset lock held, partitions not writable */
> +		if (IS_ENABLED(CONFIG_CPUSETS) && lockdep_is_cpuset_held())
> +			return true;
> +
> +		return false;
> +	}
> +
> +	return true;
> +}
> +
> +static inline struct cpumask *housekeeping_cpumask_dereference(enum hk_type type)
> +{
> +	return rcu_dereference_all_check(housekeeping.cpumasks[type],
> +					 housekeeping_dereference_check(type));
> +}
> +
>  const struct cpumask *housekeeping_cpumask(enum hk_type type)
>  {
> +	const struct cpumask *mask = NULL;
> +
>  	if (static_branch_unlikely(&housekeeping_overridden)) {
> -		if (housekeeping.flags & BIT(type)) {
> -			return rcu_dereference_check(housekeeping.cpumasks[type], 1);
> -		}
> +		if (READ_ONCE(housekeeping.flags) & BIT(type))
> +			mask = housekeeping_cpumask_dereference(type);
>  	}
> -	return cpu_possible_mask;
> +	if (!mask)
> +		mask = cpu_possible_mask;
> +	return mask;
>  }
>  EXPORT_SYMBOL_GPL(housekeeping_cpumask);
>  
> @@ -80,12 +110,46 @@ EXPORT_SYMBOL_GPL(housekeeping_affine);
>  
>  bool housekeeping_test_cpu(int cpu, enum hk_type type)
>  {
> -	if (static_branch_unlikely(&housekeeping_overridden) && housekeeping.flags & BIT(type))
> +	if (static_branch_unlikely(&housekeeping_overridden) &&
> +	    READ_ONCE(housekeeping.flags) & BIT(type))
>  		return cpumask_test_cpu(cpu, housekeeping_cpumask(type));
>  	return true;
>  }
>  EXPORT_SYMBOL_GPL(housekeeping_test_cpu);
>  
> +int housekeeping_update(struct cpumask *isol_mask, enum hk_type type)
> +{
> +	struct cpumask *trial, *old = NULL;
> +
> +	if (type != HK_TYPE_DOMAIN)
> +		return -ENOTSUPP;
> +

Nit:

The current if statement indicates that we only support modifying the cpumask for HK_TYPE_DOMAIN,
which makes the type argument seem unnecessary. This seems to be designed for better scalability.
However, when a new type needs to be supported in the future, this statement would have to be
removed. Also, the use of cpumask_andnot below is not a general operation.

Anyway, looks good to me.

> +	trial = kmalloc(cpumask_size(), GFP_KERNEL);
> +	if (!trial)
> +		return -ENOMEM;
> +
> +	cpumask_andnot(trial, housekeeping_cpumask(HK_TYPE_DOMAIN_BOOT), isol_mask);
> +	if (!cpumask_intersects(trial, cpu_online_mask)) {
> +		kfree(trial);
> +		return -EINVAL;
> +	}
> +
> +	if (!housekeeping.flags)
> +		static_branch_enable(&housekeeping_overridden);
> +
> +	if (housekeeping.flags & BIT(type))
> +		old = housekeeping_cpumask_dereference(type);
> +	else
> +		WRITE_ONCE(housekeeping.flags, housekeeping.flags | BIT(type));
> +	rcu_assign_pointer(housekeeping.cpumasks[type], trial);
> +
> +	synchronize_rcu();
> +
> +	kfree(old);
> +
> +	return 0;
> +}
> +
>  void __init housekeeping_init(void)
>  {
>  	enum hk_type type;
> diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
> index 475bdab3b8db..653e898a996a 100644
> --- a/kernel/sched/sched.h
> +++ b/kernel/sched/sched.h
> @@ -30,6 +30,7 @@
>  #include <linux/context_tracking.h>
>  #include <linux/cpufreq.h>
>  #include <linux/cpumask_api.h>
> +#include <linux/cpuset.h>
>  #include <linux/ctype.h>
>  #include <linux/file.h>
>  #include <linux/fs_api.h>

Reviewed-by: Chen Ridong <chenridong at huawei.com>

-- 
Best regards,
Ridong



From tongweilin at linux.alibaba.com  Fri Dec 26 00:31:18 2025
From: tongweilin at linux.alibaba.com (Weilin Tong)
Date: Fri, 26 Dec 2025 16:31:18 +0800
Subject: [RFC PATCH] arm64: Kconfig: enable ARCH_WANTS_THP_SWAP for all
 pagesizes
In-Reply-To: <CAGsJ_4zd+SMa4Mj23tjF5OwsP3LQyvYTrwN4y81=k8FSFgbH3Q@mail.gmail.com>
References: <20251226063759.4020782-2-tongweilin@linux.alibaba.com>
 <CAGsJ_4zd+SMa4Mj23tjF5OwsP3LQyvYTrwN4y81=k8FSFgbH3Q@mail.gmail.com>
Message-ID: <bb9592cf-bb3a-4679-8dfb-973fa6e84bad@linux.alibaba.com>


? 2025/12/26 14:52, Barry Song ??:
> On Fri, Dec 26, 2025 at 7:39?PM Weilin Tong
> <tongweilin at linux.alibaba.com> wrote:
>> Currently, ARCH_WANTS_THP_SWAP was limited to 4K page size ARM64 kernels, but
>> large folios requiring swapping also exist in other page size configurations
>> (e.g. 64K). Without this config, large folios in these kernels cannot be swapped
>> out.
>>
>> Here we enable ARCH_WANTS_THP_SWAP for all ARM64 page sizes.
> I no longer recall why this was not enabled for sizes other than
> 4 KB in commit d0637c505f8a ("arm64: enable THP_SWAP for arm64"), but
> it appears to be fine, and the swap cluster size should also be
> more friendly to PMD alignment.
>
>
> #ifdef CONFIG_THP_SWAP
> #define SWAPFILE_CLUSTER        HPAGE_PMD_NR
> #define swap_entry_order(order) (order)
> #else
> #define SWAPFILE_CLUSTER        256
> #define swap_entry_order(order) 0
> #endif
Thank you very much for taking the time to review this patch during the 
holiday.
Wishing you a happy holiday as well!

I appreciate you pointing out this optimization. We initially noticed 
the issue because,
on ARM64 kernels with 64K page size, if large folios are used in shmem, 
they cannot be
swapped out as a whole during shmem_writeout() due to the config 
limitation, and are forced
to split instead ? which is something we wanted to avoid.

It seems that this change will help enable better swap operations for 
large folios.
Thank you again for your feedback!

>> Signed-off-by: Weilin Tong <tongweilin at linux.alibaba.com>
>> ---
>>   arch/arm64/Kconfig | 2 +-
>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>> index 93173f0a09c7..58f7b4405f81 100644
>> --- a/arch/arm64/Kconfig
>> +++ b/arch/arm64/Kconfig
>> @@ -120,7 +120,7 @@ config ARM64
>>          select ARCH_WANT_LD_ORPHAN_WARN
>>          select ARCH_WANTS_EXECMEM_LATE
>>          select ARCH_WANTS_NO_INSTR
>> -       select ARCH_WANTS_THP_SWAP if ARM64_4K_PAGES
>> +       select ARCH_WANTS_THP_SWAP
>>          select ARCH_HAS_UBSAN
>>          select ARM_AMBA
>>          select ARM_ARCH_TIMER
>> --
>> 2.43.7
> Thanks
> Barry


From 21cnbao at gmail.com  Fri Dec 26 00:31:12 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Fri, 26 Dec 2025 21:31:12 +1300
Subject: [RFC PATCH] arm64: Kconfig: enable ARCH_WANTS_THP_SWAP for all pagesizes
In-Reply-To: <915dc88b-9131-4520-a2f2-facadc887bbd@linux.alibaba.com>
References: <20251226063759.4020782-2-tongweilin@linux.alibaba.com>
 <CAGsJ_4zd+SMa4Mj23tjF5OwsP3LQyvYTrwN4y81=k8FSFgbH3Q@mail.gmail.com> <915dc88b-9131-4520-a2f2-facadc887bbd@linux.alibaba.com>
Message-ID: <CAGsJ_4yQtFK8wtMuJ72ce8KFRT7mB4SZxqS1MKi6RA1WDNkm1Q@mail.gmail.com>

On Fri, Dec 26, 2025 at 9:18?PM Weilin Tong
<tongweilin at linux.alibaba.com> wrote:
>
>
> ? 2025/12/26 14:52, Barry Song ??:
>
> On Fri, Dec 26, 2025 at 7:39?PM Weilin Tong
> <tongweilin at linux.alibaba.com> wrote:
>
> Currently, ARCH_WANTS_THP_SWAP was limited to 4K page size ARM64 kernels, but
> large folios requiring swapping also exist in other page size configurations
> (e.g. 64K). Without this config, large folios in these kernels cannot be swapped
> out.
>
> Here we enable ARCH_WANTS_THP_SWAP for all ARM64 page sizes.
>
> I no longer recall why this was not enabled for sizes other than
> 4 KB in commit d0637c505f8a ("arm64: enable THP_SWAP for arm64"), but
> it appears to be fine, and the swap cluster size should also be
> more friendly to PMD alignment.
>
>
> #ifdef CONFIG_THP_SWAP
> #define SWAPFILE_CLUSTER        HPAGE_PMD_NR
> #define swap_entry_order(order) (order)
> #else
> #define SWAPFILE_CLUSTER        256
> #define swap_entry_order(order) 0
> #endif
>
>
> Thank you very much for taking the time to review this patch during the holiday. Wishing you a happy holiday as well!
>
> I appreciate you pointing out this optimization. We initially noticed the issue because, on ARM64 kernels with 64K page size, if large folios are used in shmem, they cannot be swapped out as a whole during shmem_writeout() due to the config limitation,
> and are forced to split instead?which is something we wanted to avoid.
>
> It seems that this change will help enable better swap operations for large folios. Thank you again for your feedback!

Right, I believe this is the correct direction. Just double-check that
the MTE-related functionality works. Take a look at commit
f238b8c33c6738 ("arm64: mm: swap: support THP_SWAP on hardware with MTE").


From tongweilin at linux.alibaba.com  Fri Dec 26 00:40:31 2025
From: tongweilin at linux.alibaba.com (Weilin Tong)
Date: Fri, 26 Dec 2025 16:40:31 +0800
Subject: [RFC PATCH] arm64: Kconfig: enable ARCH_WANTS_THP_SWAP for all
 pagesizes
In-Reply-To: <CAGsJ_4yQtFK8wtMuJ72ce8KFRT7mB4SZxqS1MKi6RA1WDNkm1Q@mail.gmail.com>
References: <20251226063759.4020782-2-tongweilin@linux.alibaba.com>
 <CAGsJ_4zd+SMa4Mj23tjF5OwsP3LQyvYTrwN4y81=k8FSFgbH3Q@mail.gmail.com>
 <915dc88b-9131-4520-a2f2-facadc887bbd@linux.alibaba.com>
 <CAGsJ_4yQtFK8wtMuJ72ce8KFRT7mB4SZxqS1MKi6RA1WDNkm1Q@mail.gmail.com>
Message-ID: <a91e09e5-9735-4539-ba83-661674e7f728@linux.alibaba.com>


? 2025/12/26 16:31, Barry Song ??:
> On Fri, Dec 26, 2025 at 9:18?PM Weilin Tong
> <tongweilin at linux.alibaba.com> wrote:
>>
>> ? 2025/12/26 14:52, Barry Song ??:
>>
>> On Fri, Dec 26, 2025 at 7:39?PM Weilin Tong
>> <tongweilin at linux.alibaba.com> wrote:
>>
>> Currently, ARCH_WANTS_THP_SWAP was limited to 4K page size ARM64 kernels, but
>> large folios requiring swapping also exist in other page size configurations
>> (e.g. 64K). Without this config, large folios in these kernels cannot be swapped
>> out.
>>
>> Here we enable ARCH_WANTS_THP_SWAP for all ARM64 page sizes.
>>
>> I no longer recall why this was not enabled for sizes other than
>> 4 KB in commit d0637c505f8a ("arm64: enable THP_SWAP for arm64"), but
>> it appears to be fine, and the swap cluster size should also be
>> more friendly to PMD alignment.
>>
>>
>> #ifdef CONFIG_THP_SWAP
>> #define SWAPFILE_CLUSTER        HPAGE_PMD_NR
>> #define swap_entry_order(order) (order)
>> #else
>> #define SWAPFILE_CLUSTER        256
>> #define swap_entry_order(order) 0
>> #endif
>>
>>
>> Thank you very much for taking the time to review this patch during the holiday. Wishing you a happy holiday as well!
>>
>> I appreciate you pointing out this optimization. We initially noticed the issue because, on ARM64 kernels with 64K page size, if large folios are used in shmem, they cannot be swapped out as a whole during shmem_writeout() due to the config limitation,
>> and are forced to split instead?which is something we wanted to avoid.
>>
>> It seems that this change will help enable better swap operations for large folios. Thank you again for your feedback!
> Right, I believe this is the correct direction. Just double-check that
> the MTE-related functionality works. Take a look at commit
> f238b8c33c6738 ("arm64: mm: swap: support THP_SWAP on hardware with MTE").
Thanks, I will take a look.


From chenridong at huaweicloud.com  Fri Dec 26 00:48:10 2025
From: chenridong at huaweicloud.com (Chen Ridong)
Date: Fri, 26 Dec 2025 16:48:10 +0800
Subject: [PATCH 17/33] PCI: Flush PCI probe workqueue on cpuset isolated
 partition change
In-Reply-To: <20251224134520.33231-18-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-18-frederic@kernel.org>
Message-ID: <c724aac7-5647-4253-bf7b-4ea92ea5d167@huaweicloud.com>



On 2025/12/24 21:45, Frederic Weisbecker wrote:
> The HK_TYPE_DOMAIN housekeeping cpumask is now modifiable at runtime. In
> order to synchronize against PCI probe works and make sure that no
> asynchronous probing is still pending or executing on a newly isolated
> CPU, the housekeeping subsystem must flush the PCI probe works.
> 
> However the PCI probe works can't be flushed easily since they are
> queued to the main per-CPU workqueue pool.
> 
> Solve this with creating a PCI probe-specific pool and provide and use
> the appropriate flushing API.
> 
> Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
> ---
>  drivers/pci/pci-driver.c | 17 ++++++++++++++++-
>  include/linux/pci.h      |  3 +++
>  kernel/sched/isolation.c |  2 ++
>  3 files changed, 21 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
> index 786d6ce40999..d87f781e5ce9 100644
> --- a/drivers/pci/pci-driver.c
> +++ b/drivers/pci/pci-driver.c
> @@ -337,6 +337,8 @@ static int local_pci_probe(struct drv_dev_and_id *ddi)
>  	return 0;
>  }
>  
> +static struct workqueue_struct *pci_probe_wq;
> +
>  struct pci_probe_arg {
>  	struct drv_dev_and_id *ddi;
>  	struct work_struct work;
> @@ -407,7 +409,11 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
>  		cpu = cpumask_any_and(cpumask_of_node(node),
>  				      wq_domain_mask);
>  		if (cpu < nr_cpu_ids) {
> -			schedule_work_on(cpu, &arg.work);
> +			struct workqueue_struct *wq = pci_probe_wq;
> +
> +			if (WARN_ON_ONCE(!wq))
> +				wq = system_percpu_wq;
> +			queue_work_on(cpu, wq, &arg.work);
>  			rcu_read_unlock();
>  			flush_work(&arg.work);
>  			error = arg.ret;
> @@ -425,6 +431,11 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
>  	return error;
>  }
>  
> +void pci_probe_flush_workqueue(void)
> +{
> +	flush_workqueue(pci_probe_wq);
> +}
> +
>  /**
>   * __pci_device_probe - check if a driver wants to claim a specific PCI device
>   * @drv: driver to call to check if it wants the PCI device
> @@ -1762,6 +1773,10 @@ static int __init pci_driver_init(void)
>  {
>  	int ret;
>  
> +	pci_probe_wq = alloc_workqueue("sync_wq", WQ_PERCPU, 0);
> +	if (!pci_probe_wq)
> +		return -ENOMEM;
> +
>  	ret = bus_register(&pci_bus_type);
>  	if (ret)
>  		return ret;
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 864775651c6f..f14f467e50de 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -1206,6 +1206,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
>  				    struct pci_ops *ops, void *sysdata,
>  				    struct list_head *resources);
>  int pci_host_probe(struct pci_host_bridge *bridge);
> +void pci_probe_flush_workqueue(void);
>  int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax);
>  int pci_bus_update_busn_res_end(struct pci_bus *b, int busmax);
>  void pci_bus_release_busn_res(struct pci_bus *b);
> @@ -2079,6 +2080,8 @@ static inline int pci_has_flag(int flag) { return 0; }
>  _PCI_NOP_ALL(read, *)
>  _PCI_NOP_ALL(write,)
>  
> +static inline void pci_probe_flush_workqueue(void) { }
> +
>  static inline struct pci_dev *pci_get_device(unsigned int vendor,
>  					     unsigned int device,
>  					     struct pci_dev *from)
> diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c
> index 8aac3c9f7c7f..7dbe037ea8df 100644
> --- a/kernel/sched/isolation.c
> +++ b/kernel/sched/isolation.c
> @@ -8,6 +8,7 @@
>   *
>   */
>  #include <linux/sched/isolation.h>
> +#include <linux/pci.h>
>  #include "sched.h"
>  
>  enum hk_flags {
> @@ -145,6 +146,7 @@ int housekeeping_update(struct cpumask *isol_mask, enum hk_type type)
>  
>  	synchronize_rcu();
>  
> +	pci_probe_flush_workqueue();
>  	mem_cgroup_flush_workqueue();
>  	vmstat_flush_workqueue();
>  

I am concerned that this flush work may slow down writes to the cpuset interface. I am not sure how
significant the impact will be.

I'm concerned about potential deadlock risks. While preliminary investigation hasn't uncovered any
issues, we must ensure that the cpu write lock is not held during the work(writing cpuset interface
needs cpu read lock).

-- 
Best regards,
Ridong



From ardb at kernel.org  Fri Dec 26 02:10:02 2025
From: ardb at kernel.org (Ard Biesheuvel)
Date: Fri, 26 Dec 2025 11:10:02 +0100
Subject: [PATCH 0/2] arm64: efi: Fix NULL pointer crash in 6.19-rc2
In-Reply-To: <20251223-efi_fix_619-v1-0-e0146b8b9d73@debian.org>
References: <20251223-efi_fix_619-v1-0-e0146b8b9d73@debian.org>
Message-ID: <CAMj1kXE2rN-erQNnSZ5-CGKWw6fCQ6Hvz-2BU1pn-Vy7ftneQA@mail.gmail.com>

On Tue, 23 Dec 2025 at 11:56, Breno Leitao <leitao at debian.org> wrote:
>
> I am seeing the following crash on arm64 with 6.19-rc2 (commit 9448598b22c5
> ("Linux 6.19-rc2"))
>
>         Unable to handle kernel NULL pointer dereference at virtual address 00000000000000c8
>
>         Call trace:
>         cap_capable (security/commoncap.c:82 security/commoncap.c:128) (P)
>         security_capable (security/security.c:?)
>         ns_capable_noaudit (kernel/capability.c:342 kernel/capability.c:381)
>         __ptrace_may_access (./include/linux/rcupdate.h:895 kernel/ptrace.c:326)
>         ptrace_may_access (kernel/ptrace.c:353)
>         do_task_stat (fs/proc/array.c:467)
>         proc_tgid_stat (fs/proc/array.c:673)
>         proc_single_show (fs/proc/base.c:803)
>         seq_read_iter (fs/seq_file.c:209)
>         seq_read (./include/linux/ioprio.h:59 ./include/linux/ioprio.h:84 ./include/linux/fs.h:2177 fs/seq_file.c:158)
>         vfs_read (./arch/arm64/include/asm/uaccess.h:46 fs/read_write.c:560)
>         ksys_read (fs/read_write.c:705)
>         __arm64_sys_read (fs/read_write.c:722)
>         invoke_syscall (arch/arm64/kernel/syscall.c:46)
>         el0_svc_common+0x90/0xe0
>         do_el0_svc (arch/arm64/kernel/syscall.c:150)
>         el0_svc (arch/arm64/kernel/entry-common.c:724)
>         el0t_64_sync_handler (arch/arm64/kernel/entry-common.c:743)
>         el0t_64_sync (arch/arm64/kernel/entry.S:596)
>
> This was bissected to commit a5baf582f4 ("arm64/efi: Call EFI runtime services without
> disabling preemption").
>
> After the commit above, it crashes arm64 with a NULL pointer dereference in
> cap_capable() when running below (ocassionally). Unfortunately I still don't
> have a simple reproducer, and it takes about 10 minutes to crash on my systems.
> it always crash with below[1] application.
>
> From my investigation, the root cause is that efi_mm lacks user_ns
> initialization. When kthread_use_mm(&efi_mm) temporarily adopts efi_mm
> for EFI calls, LSM hooks expect mm->user_ns to be valid for credential
> checks. With it being NULL, capability checks crash.
>
> This series contains two patches:
>
> 1. efi: Initialize efi_mm.user_ns to &init_user_ns (the actual fix)
> 2. kthread: Add WARN_ON_ONCE() to catch similar bugs early (RFC)
>
> The second patch is mostly an RFC that adds a warning in
> kthread_use_mm() to detect any mm_struct missing user_ns initialization,
> helping prevent similar NULL pointer crashes in the future.
>
> Link: https://github.com/facebookincubator/below [1]
>
> Signed-off-by: Breno Leitao <leitao at debian.org>
> ---
> Breno Leitao (2):
>       arm64: efi: Fix NULL pointer dereference by initializing user_ns
>       kthread: Warn if mm_struct lacks user_ns in kthread_use_mm()
>

Thanks for the report - I've queued these up in the EFI fixes tree.


>  drivers/firmware/efi/efi.c | 1 +
>  kernel/kthread.c           | 1 +
>  2 files changed, 2 insertions(+)
> ---
> base-commit: 9448598b22c50c8a5bb77a9103e2d49f134c9578
> change-id: 20251223-efi_fix_619-3891ca7d2914
>
> Best regards,
> --
> Breno Leitao <leitao at debian.org>
>
>


From marek.vasut at mailbox.org  Fri Dec 26 02:24:29 2025
From: marek.vasut at mailbox.org (Marek Vasut)
Date: Fri, 26 Dec 2025 11:24:29 +0100
Subject: [PATCH] arm64: dts: imx8mp: Update Data Modul i.MX8M Plus eDM SBC
 DT to rev.903
In-Reply-To: <173531253398.3886481.9345779510218290682.robh@kernel.org>
References: <20241226171404.84095-1-marex@denx.de>
 <173531253398.3886481.9345779510218290682.robh@kernel.org>
Message-ID: <14c48d93-8ee6-4769-8dc3-5c527134bc77@mailbox.org>

On 12/27/24 4:18 PM, Rob Herring (Arm) wrote:

Hello Shawn,

> On Thu, 26 Dec 2024 18:13:27 +0100, Marek Vasut wrote:
>> Update the DT to match newest Data Modul i.MX8M Plus eDM SBC rev.903
>> board which implements significant changes. Keep some of the rev.900
>> and rev.902 nodes in the DT so that a DTO can be used to support old
>> rev.900 and rev.902 boards easily.

[...]

> arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dtb: tpm at 2e: compatible: 'oneOf' conditional failed, one must be fixed:
> 	['st,st33tphf2ei2c', 'tcg,tpm-tis-i2c'] is too long
> 	'st,st33tphf2ei2c' is not one of ['infineon,slb9673', 'nuvoton,npct75x', 'st,st33ktpm2xi2c']

This is addressed in bindings patch [1] . Can this patch and the 
bindings patch be applied ?

https://lore.kernel.org/all/20241226171124.83735-1-marex at denx.de/

Thank you.


From krzk at kernel.org  Fri Dec 26 03:07:22 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 26 Dec 2025 12:07:22 +0100
Subject: [PATCH v18 05/10] dt-bindings: arm: Document reboot mode magic
In-Reply-To: <20251223-arm-psci-system_reset2-vendor-reboots-v18-5-32fa9e76efc3@oss.qualcomm.com>
References: <20251223-arm-psci-system_reset2-vendor-reboots-v18-0-32fa9e76efc3@oss.qualcomm.com>
 <20251223-arm-psci-system_reset2-vendor-reboots-v18-5-32fa9e76efc3@oss.qualcomm.com>
Message-ID: <9483a6f6-9834-4ea6-8f94-e7e158bf68cc@kernel.org>

On 23/12/2025 18:07, Shivendra Pratap wrote:
> Add bindings to describe vendor-specific reboot modes. Values here
> correspond to valid parameters to vendor-specific reset types in PSCI
> SYSTEM_RESET2 call.
> 
> Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
> Signed-off-by: Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>
> ---
>  Documentation/devicetree/bindings/arm/psci.yaml | 42 +++++++++++++++++++++++++
>  1 file changed, 42 insertions(+)
> 


Please use scripts/get_maintainers.pl to get a list of necessary people
and lists to CC. It might happen, that command when run on an older
kernel, gives you outdated entries. Therefore please be sure you base
your patches on recent Linux kernel.

Tools like b4 or scripts/get_maintainer.pl provide you proper list of
people, so fix your workflow. Tools might also fail if you work on some
ancient tree (don't, instead use mainline) or work on fork of kernel
(don't, instead use mainline). Just use b4 and everything should be
fine, although remember about `b4 prep --auto-to-cc` if you added new
patches to the patchset.

You missed at least devicetree list (maybe more), so this won't be
tested by automated tooling. Performing review on untested code might be
a waste of time.

Please kindly resend and include all necessary To/Cc entries.


Best regards,
Krzysztof


From christianshewitt at gmail.com  Fri Dec 26 03:31:37 2025
From: christianshewitt at gmail.com (Christian Hewitt)
Date: Fri, 26 Dec 2025 11:31:37 +0000
Subject: [PATCH v2 0/3] media: rockchip: rkvdec: add support for the VDPU346 variant
Message-ID: <20251226113140.573759-1-christianshewitt@gmail.com>

This series depends upon Detlev Casanova's current v7 series for VDPU381 and
VDPU383 support [0]. It adds support for the VDPU346 IP block used for H264,
HEVC and (in active work) VP9 on the RK356X boards. VDPU346 appears to be a
close relation to VDPU381 used with RK3588, except with a single core, output
limited to 4K, and minor feature differences, e.g. HEVC level 5.1 on VDPU346
vs 6.1 on VDPU381. To handle differences we declare a new compatible.

The device-tree changes are derived from prior-art in Detlev's patches for
RK3576 and RK3588, the vendor kernel [1], and some earlier patch attempts
from Piotr Oniszczuk and Diederik de Haas.

The register differences between VDPU346 and VDPU381 appear to be minimal so
we currently and intentionally reuse the VDPU381 h264, hevc, and regs files
to avoid duplicating code. There is some evidence of buffer size changes in
testing which still need to be explored. If further register analysis needs
separate files for VDPU346 the refactoring will be beyond my current n00b
coding skills and I will either need some coaching or would be happy to pass
the series over to a more experienced developer.

NB: Testing with the v1 series showed lower mbps bitrate performance. This
appears to be resolved though it's unclear to me whether this results from
kernel changes or the ongoing reworking of ffmpeg v4l2_request support [2].
However with my current Linux 6.19-rc2 test branch [3] I'm now able to play
Jellyfish H264 and HEVC test media over 100mbps.

Changes since v1:
- Drop DO-NOT-MERGE patch as changes included in Detvlev v7 series
- Adapt to variant/capability changes in Detlev's v7 series
- Add bindings ack from Rob
- Add rkvdec ack from Nicolas
- Rebase against Linux 6.19-rc2

[0] https://patchwork.kernel.org/project/linux-rockchip/list/?series=1034794
[1] https://github.com/rockchip-linux/kernel/blob/develop-6.6/arch/arm64/boot/dts/rockchip/rk356x.dtsi#L1539
[2] https://code.ffmpeg.org/Kwiboo/FFmpeg/commits/branch/v4l2request-v3
[3] https://github.com/chewitt/linux/commits/rockchip-6.19.y

Christian Hewitt (3):
  media: dt-bindings: rockchip: Add RK3568 Video Decoder bindings
  media: rkvdec: Add support for the VDPU346 variant
  arm64: dts: rockchip: Add the vdpu346 Video Decoders on RK356X

 .../bindings/media/rockchip,vdec.yaml         |   2 +
 arch/arm64/boot/dts/rockchip/rk356x-base.dtsi |  49 +++++++++
 .../media/platform/rockchip/rkvdec/rkvdec.c   | 103 ++++++++++++++++++
 3 files changed, 154 insertions(+)

-- 
2.34.1



From christianshewitt at gmail.com  Fri Dec 26 03:31:38 2025
From: christianshewitt at gmail.com (Christian Hewitt)
Date: Fri, 26 Dec 2025 11:31:38 +0000
Subject: [PATCH v2 1/3] media: dt-bindings: rockchip: Add RK3568 Video Decoder bindings
In-Reply-To: <20251226113140.573759-1-christianshewitt@gmail.com>
References: <20251226113140.573759-1-christianshewitt@gmail.com>
Message-ID: <20251226113140.573759-2-christianshewitt@gmail.com>

The video decoder in RK356X (vdpu346) is described in the same way as
the one in RK3588 (vdpu381). A new compatible is added as the decoder
capabilities are a subset of the vdpu381 capabilities.

Signed-off-by: Christian Hewitt <christianshewitt at gmail.com>
Acked-by: Rob Herring (Arm) <robh at kernel.org>
---
 Documentation/devicetree/bindings/media/rockchip,vdec.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/media/rockchip,vdec.yaml b/Documentation/devicetree/bindings/media/rockchip,vdec.yaml
index 809fda45b3bd..656ceb1f116e 100644
--- a/Documentation/devicetree/bindings/media/rockchip,vdec.yaml
+++ b/Documentation/devicetree/bindings/media/rockchip,vdec.yaml
@@ -18,6 +18,7 @@ properties:
     oneOf:
       - const: rockchip,rk3288-vdec
       - const: rockchip,rk3399-vdec
+      - const: rockchip,rk3568-vdec
       - const: rockchip,rk3576-vdec
       - const: rockchip,rk3588-vdec
       - items:
@@ -107,6 +108,7 @@ allOf:
         compatible:
           contains:
             enum:
+              - rockchip,rk3568-vdec
               - rockchip,rk3576-vdec
               - rockchip,rk3588-vdec
     then:
-- 
2.34.1



From christianshewitt at gmail.com  Fri Dec 26 03:31:39 2025
From: christianshewitt at gmail.com (Christian Hewitt)
Date: Fri, 26 Dec 2025 11:31:39 +0000
Subject: [PATCH v2 2/3] media: rkvdec: Add support for the VDPU346 variant
In-Reply-To: <20251226113140.573759-1-christianshewitt@gmail.com>
References: <20251226113140.573759-1-christianshewitt@gmail.com>
Message-ID: <20251226113140.573759-3-christianshewitt@gmail.com>

VDPU346 is similar to VDPU381 but with a single core and limited
to 4K60 media. It is also limited to H264 L5.1 and omits AV1 and
AVS2 capabilities. VDPU346 is used with RK3566 and RK3568.

Signed-off-by: Christian Hewitt <christianshewitt at gmail.com>
Reviewed-by: Nicolas Dufresne <nicolas.collabora at collabora.com>
---
 .../media/platform/rockchip/rkvdec/rkvdec.c   | 103 ++++++++++++++++++
 1 file changed, 103 insertions(+)

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index e547057dc75f..6b39e99d8a8b 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -236,6 +236,62 @@ static const struct rkvdec_ctrls rkvdec_hevc_ctrls = {
 	.num_ctrls = ARRAY_SIZE(rkvdec_hevc_ctrl_descs),
 };
 
+static const struct rkvdec_ctrl_desc vdpu346_hevc_ctrl_descs[] = {
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_SPS,
+		.cfg.ops = &rkvdec_ctrl_ops,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_PPS,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_MODE,
+		.cfg.min = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
+		.cfg.max = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
+		.cfg.def = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_START_CODE,
+		.cfg.min = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
+		.cfg.def = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
+		.cfg.max = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
+	},
+	{
+		.cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
+		.cfg.min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
+		.cfg.max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
+		.cfg.menu_skip_mask =
+			BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE),
+		.cfg.def = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
+	},
+	{
+		.cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
+		.cfg.min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
+		.cfg.max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1,
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS,
+		.cfg.ops = &rkvdec_ctrl_ops,
+		.cfg.dims = { 65 },
+	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS,
+		.cfg.ops = &rkvdec_ctrl_ops,
+		.cfg.dims = { 65 },
+	},
+};
+
+static const struct rkvdec_ctrls vdpu346_hevc_ctrls = {
+	.ctrls = vdpu346_hevc_ctrl_descs,
+	.num_ctrls = ARRAY_SIZE(vdpu346_hevc_ctrl_descs),
+};
+
 static const struct rkvdec_ctrl_desc vdpu38x_hevc_ctrl_descs[] = {
 	{
 		.cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS,
@@ -463,6 +519,41 @@ static const struct rkvdec_coded_fmt_desc rk3288_coded_fmts[] = {
 	}
 };
 
+static const struct rkvdec_coded_fmt_desc vdpu346_coded_fmts[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_HEVC_SLICE,
+		.frmsize = {
+			.min_width = 64,
+			.max_width = 65472,
+			.step_width = 64,
+			.min_height = 64,
+			.max_height = 65472,
+			.step_height = 16,
+		},
+		.ctrls = &vdpu346_hevc_ctrls,
+		.ops = &rkvdec_vdpu381_hevc_fmt_ops,
+		.num_decoded_fmts = ARRAY_SIZE(rkvdec_hevc_decoded_fmts),
+		.decoded_fmts = rkvdec_hevc_decoded_fmts,
+		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_H264_SLICE,
+		.frmsize = {
+			.min_width = 64,
+			.max_width =  65520,
+			.step_width = 64,
+			.min_height = 64,
+			.max_height =  65520,
+			.step_height = 16,
+		},
+		.ctrls = &rkvdec_h264_ctrls,
+		.ops = &rkvdec_vdpu381_h264_fmt_ops,
+		.num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts),
+		.decoded_fmts = rkvdec_h264_decoded_fmts,
+		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
+	},
+};
+
 static const struct rkvdec_coded_fmt_desc vdpu381_coded_fmts[] = {
 	{
 		.fourcc = V4L2_PIX_FMT_HEVC_SLICE,
@@ -1643,6 +1734,14 @@ static const struct rkvdec_variant_ops vdpu381_variant_ops = {
 	.flatten_matrices = transpose_and_flatten_matrices,
 };
 
+static const struct rkvdec_variant vdpu346_variant = {
+	.coded_fmts = vdpu346_coded_fmts,
+	.num_coded_fmts = ARRAY_SIZE(vdpu346_coded_fmts),
+	.rcb_sizes = vdpu381_rcb_sizes,
+	.num_rcb_sizes = ARRAY_SIZE(vdpu381_rcb_sizes),
+	.ops = &vdpu381_variant_ops,
+};
+
 static const struct rkvdec_variant vdpu381_variant = {
 	.coded_fmts = vdpu381_coded_fmts,
 	.num_coded_fmts = ARRAY_SIZE(vdpu381_coded_fmts),
@@ -1691,6 +1790,10 @@ static const struct of_device_id of_rkvdec_match[] = {
 		.compatible = "rockchip,rk3399-vdec",
 		.data = &rk3399_rkvdec_variant,
 	},
+	{
+		.compatible = "rockchip,rk3568-vdec",
+		.data = &vdpu346_variant,
+	},
 	{
 		.compatible = "rockchip,rk3588-vdec",
 		.data = &vdpu381_variant,
-- 
2.34.1



From christianshewitt at gmail.com  Fri Dec 26 03:31:40 2025
From: christianshewitt at gmail.com (Christian Hewitt)
Date: Fri, 26 Dec 2025 11:31:40 +0000
Subject: [PATCH v2 3/3] arm64: dts: rockchip: Add the vdpu346 Video Decoders on RK356X
In-Reply-To: <20251226113140.573759-1-christianshewitt@gmail.com>
References: <20251226113140.573759-1-christianshewitt@gmail.com>
Message-ID: <20251226113140.573759-4-christianshewitt@gmail.com>

Add the vdpu346 Video Decoders to the rk356x-base devicetree to
enable support on RK3566 and RK3568 boards. Also add the needed
sram and vdec_mmu nodes.

Suggested-by: Diederik de Haas <didi.debian at cknow.org>
Suggested-by: Piotr Oniszczuk <piotr.oniszczuk at gmail.com>
Signed-off-by: Christian Hewitt <christianshewitt at gmail.com>
---
 arch/arm64/boot/dts/rockchip/rk356x-base.dtsi | 49 +++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi b/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
index 8893b7b6cc9f..b37eea56c221 100644
--- a/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
@@ -383,6 +383,19 @@ usb2phy1_grf: syscon at fdca8000 {
 		reg = <0x0 0xfdca8000 0x0 0x8000>;
 	};
 
+	sram at fdcc0000 {
+		compatible = "mmio-sram";
+		reg = <0x0 0xfdcc0000 0x0 0xb000>;
+		ranges = <0x0 0x0 0xfdcc0000 0xb000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		vdec_sram: rkvdec-sram at 0 {
+			reg = <0x0 0xb000>;
+			pool;
+		};
+	};
+
 	pmucru: clock-controller at fdd00000 {
 		compatible = "rockchip,rk3568-pmucru";
 		reg = <0x0 0xfdd00000 0x0 0x1000>;
@@ -619,6 +632,42 @@ vepu_mmu: iommu at fdee0800 {
 		#iommu-cells = <0>;
 	};
 
+	vdec: video-codec at fdf80100 {
+		compatible = "rockchip,rk3568-vdec";
+		reg = <0x0 0xfdf80200 0x0 0x500>,
+		      <0x0 0xfdf80100 0x0 0x100>,
+		      <0x0 0xfdf80700 0x0 0x100>;
+		reg-names = "function", "link", "cache";
+		interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru ACLK_RKVDEC>, <&cru HCLK_RKVDEC>,
+			 <&cru CLK_RKVDEC_CA>, <&cru CLK_RKVDEC_CORE>,
+			 <&cru CLK_RKVDEC_HEVC_CA>;
+		clock-names = "axi", "ahb", "cabac", "core", "hevc_cabac";
+		assigned-clocks = <&cru ACLK_RKVDEC>,
+				  <&cru CLK_RKVDEC_CORE>,
+				  <&cru CLK_RKVDEC_CA>,
+				  <&cru CLK_RKVDEC_HEVC_CA>;
+		assigned-clock-rates = <297000000>, <297000000>,
+				       <297000000>, <600000000>;
+		iommus = <&vdec_mmu>;
+		power-domains = <&power RK3568_PD_RKVDEC>;
+		resets = <&cru SRST_A_RKVDEC>, <&cru SRST_H_RKVDEC>,
+			 <&cru SRST_RKVDEC_CA>, <&cru SRST_RKVDEC_CORE>,
+			 <&cru SRST_RKVDEC_HEVC_CA>;
+		reset-names = "axi", "ahb", "cabac", "core", "hevc_cabac";
+		sram = <&vdec_sram>;
+	};
+
+	vdec_mmu: iommu at fdf80800 {
+		compatible = "rockchip,rk3568-iommu";
+		reg = <0x0 0xfdf80800 0x0 0x40>, <0x0 0xfdf80840 0x0 0x40>;
+		interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru ACLK_RKVDEC>, <&cru HCLK_RKVDEC>;
+		clock-names = "aclk", "iface";
+		power-domains = <&power RK3568_PD_RKVDEC>;
+		#iommu-cells = <0>;
+	};
+
 	vicap: video-capture at fdfe0000 {
 		compatible = "rockchip,rk3568-vicap";
 		reg = <0x0 0xfdfe0000 0x0 0x200>;
-- 
2.34.1



From diederik at cknow-tech.com  Fri Dec 26 04:00:04 2025
From: diederik at cknow-tech.com (Diederik de Haas)
Date: Fri, 26 Dec 2025 13:00:04 +0100
Subject: [PATCH v2 2/3] media: rkvdec: Add support for the VDPU346
 variant
In-Reply-To: <20251226113140.573759-3-christianshewitt@gmail.com>
References: <20251226113140.573759-1-christianshewitt@gmail.com>
 <20251226113140.573759-3-christianshewitt@gmail.com>
Message-ID: <DF84QZ0YBLY8.2DYCSM2EQIF5@cknow-tech.com>

Hi Christian,

On Fri Dec 26, 2025 at 12:31 PM CET, Christian Hewitt wrote:
> VDPU346 is similar to VDPU381 but with a single core and limited
> to 4K60 media. It is also limited to H264 L5.1 and omits AV1 and
> AVS2 capabilities. VDPU346 is used with RK3566 and RK3568.
>
> Signed-off-by: Christian Hewitt <christianshewitt at gmail.com>
> Reviewed-by: Nicolas Dufresne <nicolas.collabora at collabora.com>
> ---
>  .../media/platform/rockchip/rkvdec/rkvdec.c   | 103 ++++++++++++++++++
>  1 file changed, 103 insertions(+)
>
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> index e547057dc75f..6b39e99d8a8b 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> @@ -236,6 +236,62 @@ static const struct rkvdec_ctrls rkvdec_hevc_ctrls = {
>  	.num_ctrls = ARRAY_SIZE(rkvdec_hevc_ctrl_descs),
>  };
>  
> +static const struct rkvdec_ctrl_desc vdpu346_hevc_ctrl_descs[] = {
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_SPS,
> +		.cfg.ops = &rkvdec_ctrl_ops,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_PPS,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_MODE,
> +		.cfg.min = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
> +		.cfg.max = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
> +		.cfg.def = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_START_CODE,
> +		.cfg.min = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
> +		.cfg.def = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
> +		.cfg.max = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
> +		.cfg.min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
> +		.cfg.max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
> +		.cfg.menu_skip_mask =
> +			BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE),
> +		.cfg.def = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
> +		.cfg.min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
> +		.cfg.max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1,
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS,
> +		.cfg.ops = &rkvdec_ctrl_ops,
> +		.cfg.dims = { 65 },
> +	},
> +	{
> +		.cfg.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS,
> +		.cfg.ops = &rkvdec_ctrl_ops,
> +		.cfg.dims = { 65 },
> +	},
> +};
> +
> +static const struct rkvdec_ctrls vdpu346_hevc_ctrls = {
> +	.ctrls = vdpu346_hevc_ctrl_descs,
> +	.num_ctrls = ARRAY_SIZE(vdpu346_hevc_ctrl_descs),
> +};
> +
>  static const struct rkvdec_ctrl_desc vdpu38x_hevc_ctrl_descs[] = {
>  	{
>  		.cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS,
> @@ -463,6 +519,41 @@ static const struct rkvdec_coded_fmt_desc rk3288_coded_fmts[] = {
>  	}
>  };
>  
> +static const struct rkvdec_coded_fmt_desc vdpu346_coded_fmts[] = {
> +	{
> +		.fourcc = V4L2_PIX_FMT_HEVC_SLICE,
> +		.frmsize = {
> +			.min_width = 64,
> +			.max_width = 65472,

This should be 4096 according to page 469 of RK3568 TRM Part 2 ...

> +			.step_width = 64,
> +			.min_height = 64,
> +			.max_height = 65472,

... and this 2304.

> +			.step_height = 16,
> +		},
> +		.ctrls = &vdpu346_hevc_ctrls,
> +		.ops = &rkvdec_vdpu381_hevc_fmt_ops,
> +		.num_decoded_fmts = ARRAY_SIZE(rkvdec_hevc_decoded_fmts),
> +		.decoded_fmts = rkvdec_hevc_decoded_fmts,
> +		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_H264_SLICE,
> +		.frmsize = {
> +			.min_width = 64,
> +			.max_width =  65520,

This too should be 4096 according to page 469 of RK3568 TRM Part 2 ...

> +			.step_width = 64,
> +			.min_height = 64,
> +			.max_height =  65520,

... and this 2304.

I guess this also explains the 'green images' Nicolas noticed.

> +			.step_height = 16,
> +		},
> +		.ctrls = &rkvdec_h264_ctrls,
> +		.ops = &rkvdec_vdpu381_h264_fmt_ops,
> +		.num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts),
> +		.decoded_fmts = rkvdec_h264_decoded_fmts,
> +		.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
> +	},

I see you've reversed the order of the blocks so that HEVC now comes
before the H264 block. While that makes it consistent with what Detlev
has in their v7 and with the existing code in the driver ... I actually
prefer having H264 before HEVC as the alphabetical sorting order is
H264 before HEVC.
In the existing code the VP9 'stuff' is listed below H264 and HEVC.

But then Detlev should do that too in their patch set ... and 'ideally'
the order of the existing code be updated to be alphabetically too.

OTOH, a consistent order works for me too.

Cheers,
  Diederik

> +};
> +
>  static const struct rkvdec_coded_fmt_desc vdpu381_coded_fmts[] = {
>  	{
>  		.fourcc = V4L2_PIX_FMT_HEVC_SLICE,
> @@ -1643,6 +1734,14 @@ static const struct rkvdec_variant_ops vdpu381_variant_ops = {
>  	.flatten_matrices = transpose_and_flatten_matrices,
>  };
>  
> +static const struct rkvdec_variant vdpu346_variant = {
> +	.coded_fmts = vdpu346_coded_fmts,
> +	.num_coded_fmts = ARRAY_SIZE(vdpu346_coded_fmts),
> +	.rcb_sizes = vdpu381_rcb_sizes,
> +	.num_rcb_sizes = ARRAY_SIZE(vdpu381_rcb_sizes),
> +	.ops = &vdpu381_variant_ops,
> +};
> +
>  static const struct rkvdec_variant vdpu381_variant = {
>  	.coded_fmts = vdpu381_coded_fmts,
>  	.num_coded_fmts = ARRAY_SIZE(vdpu381_coded_fmts),
> @@ -1691,6 +1790,10 @@ static const struct of_device_id of_rkvdec_match[] = {
>  		.compatible = "rockchip,rk3399-vdec",
>  		.data = &rk3399_rkvdec_variant,
>  	},
> +	{
> +		.compatible = "rockchip,rk3568-vdec",
> +		.data = &vdpu346_variant,
> +	},
>  	{
>  		.compatible = "rockchip,rk3588-vdec",
>  		.data = &vdpu381_variant,



From christianshewitt at gmail.com  Fri Dec 26 04:25:09 2025
From: christianshewitt at gmail.com (Christian Hewitt)
Date: Fri, 26 Dec 2025 16:25:09 +0400
Subject: [PATCH v2 2/3] media: rkvdec: Add support for the VDPU346 variant
In-Reply-To: <DF84QZ0YBLY8.2DYCSM2EQIF5@cknow-tech.com>
References: <20251226113140.573759-1-christianshewitt@gmail.com>
 <20251226113140.573759-3-christianshewitt@gmail.com>
 <DF84QZ0YBLY8.2DYCSM2EQIF5@cknow-tech.com>
Message-ID: <71EA9FB8-83DB-4785-86C1-2E6BA9C739D9@gmail.com>

> On 26 Dec 2025, at 4:00?pm, Diederik de Haas <diederik at cknow-tech.com> wrote:
> 
> Hi Christian,
> 
> On Fri Dec 26, 2025 at 12:31 PM CET, Christian Hewitt wrote:
>> VDPU346 is similar to VDPU381 but with a single core and limited
>> to 4K60 media. It is also limited to H264 L5.1 and omits AV1 and
>> AVS2 capabilities. VDPU346 is used with RK3566 and RK3568.
>> 
>> Signed-off-by: Christian Hewitt <christianshewitt at gmail.com>
>> Reviewed-by: Nicolas Dufresne <nicolas.collabora at collabora.com>
>> ---
>> .../media/platform/rockchip/rkvdec/rkvdec.c   | 103 ++++++++++++++++++
>> 1 file changed, 103 insertions(+)
>> 
>> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
>> index e547057dc75f..6b39e99d8a8b 100644
>> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
>> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
>> @@ -236,6 +236,62 @@ static const struct rkvdec_ctrls rkvdec_hevc_ctrls = {
>> .num_ctrls = ARRAY_SIZE(rkvdec_hevc_ctrl_descs),
>> };
>> 
>> +static const struct rkvdec_ctrl_desc vdpu346_hevc_ctrl_descs[] = {
>> + {
>> + .cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS,
>> + },
>> + {
>> + .cfg.id = V4L2_CID_STATELESS_HEVC_SPS,
>> + .cfg.ops = &rkvdec_ctrl_ops,
>> + },
>> + {
>> + .cfg.id = V4L2_CID_STATELESS_HEVC_PPS,
>> + },
>> + {
>> + .cfg.id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX,
>> + },
>> + {
>> + .cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_MODE,
>> + .cfg.min = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
>> + .cfg.max = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
>> + .cfg.def = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
>> + },
>> + {
>> + .cfg.id = V4L2_CID_STATELESS_HEVC_START_CODE,
>> + .cfg.min = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
>> + .cfg.def = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
>> + .cfg.max = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
>> + },
>> + {
>> + .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
>> + .cfg.min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
>> + .cfg.max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
>> + .cfg.menu_skip_mask =
>> + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE),
>> + .cfg.def = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
>> + },
>> + {
>> + .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
>> + .cfg.min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
>> + .cfg.max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1,
>> + },
>> + {
>> + .cfg.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS,
>> + .cfg.ops = &rkvdec_ctrl_ops,
>> + .cfg.dims = { 65 },
>> + },
>> + {
>> + .cfg.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS,
>> + .cfg.ops = &rkvdec_ctrl_ops,
>> + .cfg.dims = { 65 },
>> + },
>> +};
>> +
>> +static const struct rkvdec_ctrls vdpu346_hevc_ctrls = {
>> + .ctrls = vdpu346_hevc_ctrl_descs,
>> + .num_ctrls = ARRAY_SIZE(vdpu346_hevc_ctrl_descs),
>> +};
>> +
>> static const struct rkvdec_ctrl_desc vdpu38x_hevc_ctrl_descs[] = {
>> {
>> .cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS,
>> @@ -463,6 +519,41 @@ static const struct rkvdec_coded_fmt_desc rk3288_coded_fmts[] = {
>> }
>> };
>> 
>> +static const struct rkvdec_coded_fmt_desc vdpu346_coded_fmts[] = {
>> + {
>> + .fourcc = V4L2_PIX_FMT_HEVC_SLICE,
>> + .frmsize = {
>> + .min_width = 64,
>> + .max_width = 65472,
> 
> This should be 4096 according to page 469 of RK3568 TRM Part 2 ...
> 
>> + .step_width = 64,
>> + .min_height = 64,
>> + .max_height = 65472,
> 
> ... and this 2304.
> 
>> + .step_height = 16,
>> + },
>> + .ctrls = &vdpu346_hevc_ctrls,
>> + .ops = &rkvdec_vdpu381_hevc_fmt_ops,
>> + .num_decoded_fmts = ARRAY_SIZE(rkvdec_hevc_decoded_fmts),
>> + .decoded_fmts = rkvdec_hevc_decoded_fmts,
>> + .subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
>> + },
>> + {
>> + .fourcc = V4L2_PIX_FMT_H264_SLICE,
>> + .frmsize = {
>> + .min_width = 64,
>> + .max_width =  65520,
> 
> This too should be 4096 according to page 469 of RK3568 TRM Part 2 ...
> 
>> + .step_width = 64,
>> + .min_height = 64,
>> + .max_height =  65520,
> 
> ... and this 2304.
> 
> I guess this also explains the 'green images' Nicolas noticed.

Quite probably. I?ve picked the above changes into my working tree
(for those following it) and will send a v3 series in response to
the next revision of Detlev?s patches.

> + .step_height = 16,
>> + },
>> + .ctrls = &rkvdec_h264_ctrls,
>> + .ops = &rkvdec_vdpu381_h264_fmt_ops,
>> + .num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts),
>> + .decoded_fmts = rkvdec_h264_decoded_fmts,
>> + .subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
>> + },
> 
> I see you've reversed the order of the blocks so that HEVC now comes
> before the H264 block. While that makes it consistent with what Detlev
> has in their v7 and with the existing code in the driver ... I actually
> prefer having H264 before HEVC as the alphabetical sorting order is
> H264 before HEVC.
> In the existing code the VP9 'stuff' is listed below H264 and HEVC.
> 
> But then Detlev should do that too in their patch set ... and 'ideally'
> the order of the existing code be updated to be alphabetically too.
> 
> OTOH, a consistent order works for me too.

I believe the reorder was requested by Nic (offline from the list) so
there?s probably a reason behind it. I?ll keep things aligned to the
order in Detlev?s series (whatever that is).

Christian


> Cheers,
>  Diederik
> 
>> +};
>> +
>> static const struct rkvdec_coded_fmt_desc vdpu381_coded_fmts[] = {
>> {
>> .fourcc = V4L2_PIX_FMT_HEVC_SLICE,
>> @@ -1643,6 +1734,14 @@ static const struct rkvdec_variant_ops vdpu381_variant_ops = {
>> .flatten_matrices = transpose_and_flatten_matrices,
>> };
>> 
>> +static const struct rkvdec_variant vdpu346_variant = {
>> + .coded_fmts = vdpu346_coded_fmts,
>> + .num_coded_fmts = ARRAY_SIZE(vdpu346_coded_fmts),
>> + .rcb_sizes = vdpu381_rcb_sizes,
>> + .num_rcb_sizes = ARRAY_SIZE(vdpu381_rcb_sizes),
>> + .ops = &vdpu381_variant_ops,
>> +};
>> +
>> static const struct rkvdec_variant vdpu381_variant = {
>> .coded_fmts = vdpu381_coded_fmts,
>> .num_coded_fmts = ARRAY_SIZE(vdpu381_coded_fmts),
>> @@ -1691,6 +1790,10 @@ static const struct of_device_id of_rkvdec_match[] = {
>> .compatible = "rockchip,rk3399-vdec",
>> .data = &rk3399_rkvdec_variant,
>> },
>> + {
>> + .compatible = "rockchip,rk3568-vdec",
>> + .data = &vdpu346_variant,
>> + },
>> {
>> .compatible = "rockchip,rk3588-vdec",
>> .data = &vdpu381_variant,




From dan.carpenter at linaro.org  Fri Dec 26 05:17:14 2025
From: dan.carpenter at linaro.org (Dan Carpenter)
Date: Fri, 26 Dec 2025 16:17:14 +0300
Subject: [PATCH v9 2/8] coresight: tmc: add create/clean functions for
 etr_buf_list
In-Reply-To: <20251224-enable-byte-cntr-for-ctcu-v9-2-886c4496fed4@oss.qualcomm.com>
Message-ID: <202512251923.GDSbVal1-lkp@intel.com>

Hi Jie,

kernel test robot noticed the following build warnings:

url:    https://github.com/intel-lab-lkp/linux/commits/Jie-Gan/coresight-core-Refactoring-ctcu_get_active_port-and-make-it-generic/20251224-171604
base:   47b7b5e32bb7264b51b89186043e1ada4090b558
patch link:    https://lore.kernel.org/r/20251224-enable-byte-cntr-for-ctcu-v9-2-886c4496fed4%40oss.qualcomm.com
patch subject: [PATCH v9 2/8] coresight: tmc: add create/clean functions for etr_buf_list
config: arm-randconfig-r073-20251225 (https://download.01.org/0day-ci/archive/20251225/202512251923.GDSbVal1-lkp at intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 4ef602d446057dabf5f61fb221669ecbeda49279)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Reported-by: Dan Carpenter <dan.carpenter at linaro.org>
| Closes: https://lore.kernel.org/r/202512251923.GDSbVal1-lkp at intel.com/

smatch warnings:
drivers/hwtracing/coresight/coresight-tmc-etr.c:1992 tmc_create_etr_buf_list() warn: passing freed memory 'new_node' (line 1991)
drivers/hwtracing/coresight/coresight-tmc-etr.c:1992 tmc_create_etr_buf_list() warn: passing zero to 'PTR_ERR'

vim +/new_node +1992 drivers/hwtracing/coresight/coresight-tmc-etr.c

34af91eeb7e78e Jie Gan 2025-12-24  1959  int tmc_create_etr_buf_list(struct tmc_drvdata *drvdata, int num_nodes)
34af91eeb7e78e Jie Gan 2025-12-24  1960  {
34af91eeb7e78e Jie Gan 2025-12-24  1961  	struct etr_buf_node *new_node;
34af91eeb7e78e Jie Gan 2025-12-24  1962  	struct etr_buf *sysfs_buf;
34af91eeb7e78e Jie Gan 2025-12-24  1963  	int i = 0, ret = 0;
34af91eeb7e78e Jie Gan 2025-12-24  1964  
34af91eeb7e78e Jie Gan 2025-12-24  1965  	/* We dont need a list if there is only one node */
34af91eeb7e78e Jie Gan 2025-12-24  1966  	if (num_nodes < 2)
34af91eeb7e78e Jie Gan 2025-12-24  1967  		return -EINVAL;
34af91eeb7e78e Jie Gan 2025-12-24  1968  
34af91eeb7e78e Jie Gan 2025-12-24  1969  	/* We expect that sysfs_buf in drvdata has already been allocated. */
34af91eeb7e78e Jie Gan 2025-12-24  1970  	if (drvdata->sysfs_buf) {
34af91eeb7e78e Jie Gan 2025-12-24  1971  		/* Directly insert the allocated sysfs_buf into the list first */
34af91eeb7e78e Jie Gan 2025-12-24  1972  		new_node = kzalloc(sizeof(struct etr_buf_node), GFP_KERNEL);
34af91eeb7e78e Jie Gan 2025-12-24  1973  		if (IS_ERR(new_node))
34af91eeb7e78e Jie Gan 2025-12-24  1974  			return PTR_ERR(new_node);
34af91eeb7e78e Jie Gan 2025-12-24  1975  
34af91eeb7e78e Jie Gan 2025-12-24  1976  		new_node->sysfs_buf = drvdata->sysfs_buf;
34af91eeb7e78e Jie Gan 2025-12-24  1977  		new_node->is_free = false;
34af91eeb7e78e Jie Gan 2025-12-24  1978  		list_add(&new_node->node, &drvdata->etr_buf_list);
34af91eeb7e78e Jie Gan 2025-12-24  1979  		i++;
34af91eeb7e78e Jie Gan 2025-12-24  1980  	}
34af91eeb7e78e Jie Gan 2025-12-24  1981  
34af91eeb7e78e Jie Gan 2025-12-24  1982  	while (i < num_nodes) {
34af91eeb7e78e Jie Gan 2025-12-24  1983  		new_node = kzalloc(sizeof(struct etr_buf_node), GFP_KERNEL);
34af91eeb7e78e Jie Gan 2025-12-24  1984  		if (IS_ERR(new_node)) {
34af91eeb7e78e Jie Gan 2025-12-24  1985  			ret = PTR_ERR(new_node);
34af91eeb7e78e Jie Gan 2025-12-24  1986  			break;
34af91eeb7e78e Jie Gan 2025-12-24  1987  		}
34af91eeb7e78e Jie Gan 2025-12-24  1988  
34af91eeb7e78e Jie Gan 2025-12-24  1989  		sysfs_buf = tmc_alloc_etr_buf(drvdata, drvdata->size, 0, cpu_to_node(0), NULL);
34af91eeb7e78e Jie Gan 2025-12-24  1990  		if (IS_ERR(sysfs_buf)) {
34af91eeb7e78e Jie Gan 2025-12-24 @1991  			kfree(new_node);
34af91eeb7e78e Jie Gan 2025-12-24 @1992  			ret = PTR_ERR(new_node);

s/new_node/sysfs_buf/

34af91eeb7e78e Jie Gan 2025-12-24  1993  			break;
34af91eeb7e78e Jie Gan 2025-12-24  1994  		}
34af91eeb7e78e Jie Gan 2025-12-24  1995  
34af91eeb7e78e Jie Gan 2025-12-24  1996  		/* We dont have a available sysfs_buf in drvdata, setup one */
34af91eeb7e78e Jie Gan 2025-12-24  1997  		if (!drvdata->sysfs_buf) {
34af91eeb7e78e Jie Gan 2025-12-24  1998  			drvdata->sysfs_buf = sysfs_buf;
34af91eeb7e78e Jie Gan 2025-12-24  1999  			new_node->is_free = false;
34af91eeb7e78e Jie Gan 2025-12-24  2000  		} else
34af91eeb7e78e Jie Gan 2025-12-24  2001  			new_node->is_free = true;
34af91eeb7e78e Jie Gan 2025-12-24  2002  
34af91eeb7e78e Jie Gan 2025-12-24  2003  		new_node->sysfs_buf = sysfs_buf;
34af91eeb7e78e Jie Gan 2025-12-24  2004  		list_add(&new_node->node, &drvdata->etr_buf_list);
34af91eeb7e78e Jie Gan 2025-12-24  2005  		i++;
34af91eeb7e78e Jie Gan 2025-12-24  2006  	}
34af91eeb7e78e Jie Gan 2025-12-24  2007  
34af91eeb7e78e Jie Gan 2025-12-24  2008  	/* Clean the list if there is an error */
34af91eeb7e78e Jie Gan 2025-12-24  2009  	if (ret)
34af91eeb7e78e Jie Gan 2025-12-24  2010  		tmc_clean_etr_buf_list(drvdata);
34af91eeb7e78e Jie Gan 2025-12-24  2011  
34af91eeb7e78e Jie Gan 2025-12-24  2012  	return ret;
34af91eeb7e78e Jie Gan 2025-12-24  2013  }

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki



From coxu at redhat.com  Fri Dec 26 06:11:15 2025
From: coxu at redhat.com (Coiby Xu)
Date: Fri, 26 Dec 2025 22:11:15 +0800
Subject: [PATCH] arm64/kdump: pass dm-crypt keys to kdump kernel
Message-ID: <20251226141116.1379601-1-coxu@redhat.com>

Based on the CONFIG_CRASH_DM_CRYPT feature, this patch adds
LUKS-encrypted device dump target support to ARM64 by addressing two
challenges [1],
 - Kdump kernel may not be able to decrypt the LUKS partition. For some
   machines, a system administrator may not have a chance to enter the
   password to decrypt the device in kdump initramfs after the 1st kernel
   crashes

 - LUKS2 by default use the memory-hard Argon2 key derivation function
   which is quite memory-consuming compared to the limited memory reserved
   for kdump.

1st kernel will add device tree property dmcryptkeys as similar to
elfcorehdr to pass the memory address of the stored info of dm-crypt
keys to the kdump kernel.

[1] https://lore.kernel.org/all/20250502011246.99238-1-coxu at redhat.com/

Cc: Arnaud Lefebvre <arnaud.lefebvre at clever-cloud.com>
Cc: Baoquan he <bhe at redhat.com>
Cc: Dave Young <dyoung at redhat.com>
Cc: Kairui Song <ryncsn at gmail.com>
Cc: Pingfan Liu <kernelfans at gmail.com>
Cc: Andrew Morton <akpm at linux-foundation.org>
Signed-off-by: Coiby Xu <coxu at redhat.com>
---
 arch/arm64/kernel/machine_kexec_file.c |  9 +++++++++
 drivers/of/fdt.c                       | 19 +++++++++++++++++++
 drivers/of/kexec.c                     | 19 +++++++++++++++++++
 3 files changed, 47 insertions(+)

diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
index 410060ebd86d..5f3bad8ca96d 100644
--- a/arch/arm64/kernel/machine_kexec_file.c
+++ b/arch/arm64/kernel/machine_kexec_file.c
@@ -134,6 +134,15 @@ int load_other_segments(struct kimage *image,
 
 		kexec_dprintk("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
 			      image->elf_load_addr, kbuf.bufsz, kbuf.memsz);
+
+		ret = crash_load_dm_crypt_keys(image);
+
+		if (ret == -ENOENT) {
+			kexec_dprintk("No dm crypt key to load\n");
+		} else if (ret) {
+			pr_err("Failed to load dm crypt keys\n");
+			goto out_err;
+		}
 	}
 #endif
 
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 331646d667b9..2b22dc7e2b5f 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -866,6 +866,24 @@ static void __init early_init_dt_check_for_elfcorehdr(unsigned long node)
 		 elfcorehdr_addr, elfcorehdr_size);
 }
 
+static void __init early_init_dt_check_for_dmcryptkeys(unsigned long node)
+{
+	const __be32 *prop;
+
+	if (!IS_ENABLED(CONFIG_CRASH_DM_CRYPT))
+		return;
+
+	pr_debug("Looking for dmcryptkeys property... ");
+
+	prop = of_get_flat_dt_prop(node, "linux,dmcryptkeys", NULL);
+	if (!prop)
+		return;
+
+	dm_crypt_keys_addr = dt_mem_next_cell(dt_root_addr_cells, &prop);
+
+	pr_debug("dm_crypt_keys_addr=0x%llx\n", dm_crypt_keys_addr);
+}
+
 static unsigned long chosen_node_offset = -FDT_ERR_NOTFOUND;
 
 /*
@@ -1097,6 +1115,7 @@ int __init early_init_dt_scan_chosen(char *cmdline)
 
 	early_init_dt_check_for_initrd(node);
 	early_init_dt_check_for_elfcorehdr(node);
+	early_init_dt_check_for_dmcryptkeys(node);
 
 	rng_seed = of_get_flat_dt_prop(node, "rng-seed", &l);
 	if (rng_seed && l > 0) {
diff --git a/drivers/of/kexec.c b/drivers/of/kexec.c
index 1ee2d31816ae..4bfb1ea5744e 100644
--- a/drivers/of/kexec.c
+++ b/drivers/of/kexec.c
@@ -432,6 +432,25 @@ void *of_kexec_alloc_and_setup_fdt(const struct kimage *image,
 		if (ret)
 			goto out;
 
+		if (image->dm_crypt_keys_addr != 0) {
+			ret = fdt_appendprop_addrrange(fdt, 0, chosen_node,
+						       "linux,dmcryptkeys",
+						       image->dm_crypt_keys_addr,
+						       image->dm_crypt_keys_sz);
+
+			if (ret)
+				goto out;
+
+			/*
+			 * Avoid dmcryptkeys from being stomped on in kdump kernel by
+			 * setting up memory reserve map.
+			 */
+			ret = fdt_add_mem_rsv(fdt, image->dm_crypt_keys_addr,
+					      image->dm_crypt_keys_sz);
+			if (ret)
+				goto out;
+		}
+
 #ifdef CONFIG_CRASH_DUMP
 		/* add linux,usable-memory-range */
 		ret = fdt_appendprop_addrrange(fdt, 0, chosen_node,

base-commit: ccd1cdca5cd433c8a5dff78b69a79b31d9b77ee1
prerequisite-patch-id: af871421d3653569c735073a3d2d4915412736d7
prerequisite-patch-id: 536241bdf9240e12a5b038415875d4ce417a0892
-- 
2.52.0



From helgaas at kernel.org  Fri Dec 26 09:19:19 2025
From: helgaas at kernel.org (Bjorn Helgaas)
Date: Fri, 26 Dec 2025 11:19:19 -0600
Subject: [PATCH] PCI: j721e: Add config guards for Cadence Host and
 Endpoint library APIs
In-Reply-To: <20251117113246.1460644-1-s-vadapalli@ti.com>
Message-ID: <20251226171919.GA4131469@bhelgaas>

On Mon, Nov 17, 2025 at 05:02:06PM +0530, Siddharth Vadapalli wrote:
> Commit under Fixes enabled loadable module support for the driver under
> the assumption that it shall be the sole user of the Cadence Host and
> Endpoint library APIs. This assumption guarantees that we won't end up
> in a case where the driver is built-in and the library support is built
> as a loadable module.
> 
> With the introduction of [1], this assumption is no longer valid. The
> SG2042 driver could be built as a loadable module, implying that the
> Cadence Host library is also selected as a loadable module. However, the
> pci-j721e.c driver could be built-in as indicated by CONFIG_PCI_J721E=y
> due to which the Cadence Endpoint library is built-in. Despite the
> library drivers being built as specified by their respective consumers,
> since the 'pci-j721e.c' driver has references to the Cadence Host
> library APIs as well, we run into a build error as reported at [0].
> 
> Fix this by adding config guards as a temporary workaround. The proper
> fix is to split the 'pci-j721e.c' driver into independent Host and
> Endpoint drivers as aligned at [2].

If we know what the proper fix is, why aren't we just doing that
instead of adding a temporary workaround?

> Fixes: a2790bf81f0f ("PCI: j721e: Add support to build as a loadable module")
> Reported-by: kernel test robot <lkp at intel.com>
> Closes: https://lore.kernel.org/oe-kbuild-all/202511111705.MZ7ls8Hm-lkp at intel.com/
> Cc: <stable at vger.kernel.org>
> [0]: https://lore.kernel.org/r/202511111705.MZ7ls8Hm-lkp at intel.com/
> [1]: commit 1c72774df028 ("PCI: sg2042: Add Sophgo SG2042 PCIe driver")
> [2]: https://lore.kernel.org/r/37f6f8ce-12b2-44ee-a94c-f21b29c98821 at app.fastmail.com/
> Suggested-by: Arnd Bergmann <arnd at arndb.de>
> Signed-off-by: Siddharth Vadapalli <s-vadapalli at ti.com>
> ---
>  drivers/pci/controller/cadence/pci-j721e.c | 43 +++++++++++++---------
>  1 file changed, 26 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/pci/controller/cadence/pci-j721e.c b/drivers/pci/controller/cadence/pci-j721e.c
> index 5bc5ab20aa6d..67c5e02afccf 100644
> --- a/drivers/pci/controller/cadence/pci-j721e.c
> +++ b/drivers/pci/controller/cadence/pci-j721e.c
> @@ -628,10 +628,12 @@ static int j721e_pcie_probe(struct platform_device *pdev)
>  			gpiod_set_value_cansleep(gpiod, 1);
>  		}
>  
> -		ret = cdns_pcie_host_setup(rc);
> -		if (ret < 0) {
> -			clk_disable_unprepare(pcie->refclk);
> -			goto err_pcie_setup;
> +		if (IS_ENABLED(CONFIG_PCI_J721E_HOST)) {
> +			ret = cdns_pcie_host_setup(rc);
> +			if (ret < 0) {
> +				clk_disable_unprepare(pcie->refclk);
> +				goto err_pcie_setup;
> +			}
>  		}
>  
>  		break;
> @@ -642,9 +644,11 @@ static int j721e_pcie_probe(struct platform_device *pdev)
>  			goto err_get_sync;
>  		}
>  
> -		ret = cdns_pcie_ep_setup(ep);
> -		if (ret < 0)
> -			goto err_pcie_setup;
> +		if (IS_ENABLED(CONFIG_PCI_J721E_EP)) {
> +			ret = cdns_pcie_ep_setup(ep);
> +			if (ret < 0)
> +				goto err_pcie_setup;
> +		}
>  
>  		break;
>  	}
> @@ -669,10 +673,11 @@ static void j721e_pcie_remove(struct platform_device *pdev)
>  	struct cdns_pcie_ep *ep;
>  	struct cdns_pcie_rc *rc;
>  
> -	if (pcie->mode == PCI_MODE_RC) {
> +	if (IS_ENABLED(CONFIG_PCI_J721E_HOST) &&
> +	    pcie->mode == PCI_MODE_RC) {
>  		rc = container_of(cdns_pcie, struct cdns_pcie_rc, pcie);
>  		cdns_pcie_host_disable(rc);
> -	} else {
> +	} else if (IS_ENABLED(CONFIG_PCI_J721E_EP)) {
>  		ep = container_of(cdns_pcie, struct cdns_pcie_ep, pcie);
>  		cdns_pcie_ep_disable(ep);
>  	}
> @@ -739,10 +744,12 @@ static int j721e_pcie_resume_noirq(struct device *dev)
>  			gpiod_set_value_cansleep(pcie->reset_gpio, 1);
>  		}
>  
> -		ret = cdns_pcie_host_link_setup(rc);
> -		if (ret < 0) {
> -			clk_disable_unprepare(pcie->refclk);
> -			return ret;
> +		if (IS_ENABLED(CONFIG_PCI_J721E_HOST)) {
> +			ret = cdns_pcie_host_link_setup(rc);
> +			if (ret < 0) {
> +				clk_disable_unprepare(pcie->refclk);
> +				return ret;
> +			}
>  		}
>  
>  		/*
> @@ -752,10 +759,12 @@ static int j721e_pcie_resume_noirq(struct device *dev)
>  		for (enum cdns_pcie_rp_bar bar = RP_BAR0; bar <= RP_NO_BAR; bar++)
>  			rc->avail_ib_bar[bar] = true;
>  
> -		ret = cdns_pcie_host_init(rc);
> -		if (ret) {
> -			clk_disable_unprepare(pcie->refclk);
> -			return ret;
> +		if (IS_ENABLED(CONFIG_PCI_J721E_HOST)) {
> +			ret = cdns_pcie_host_init(rc);
> +			if (ret) {
> +				clk_disable_unprepare(pcie->refclk);
> +				return ret;
> +			}
>  		}
>  	}
>  
> -- 
> 2.51.1
> 


From shivendra.pratap at oss.qualcomm.com  Fri Dec 26 09:42:52 2025
From: shivendra.pratap at oss.qualcomm.com (Shivendra Pratap)
Date: Fri, 26 Dec 2025 23:12:52 +0530
Subject: [PATCH v18 05/10] dt-bindings: arm: Document reboot mode magic
In-Reply-To: <9483a6f6-9834-4ea6-8f94-e7e158bf68cc@kernel.org>
References: <20251223-arm-psci-system_reset2-vendor-reboots-v18-0-32fa9e76efc3@oss.qualcomm.com>
 <20251223-arm-psci-system_reset2-vendor-reboots-v18-5-32fa9e76efc3@oss.qualcomm.com>
 <9483a6f6-9834-4ea6-8f94-e7e158bf68cc@kernel.org>
Message-ID: <aaf20c5c-0cbe-c1ba-c749-971ddd5b0351@oss.qualcomm.com>



On 12/26/2025 4:37 PM, Krzysztof Kozlowski wrote:
> On 23/12/2025 18:07, Shivendra Pratap wrote:
>> Add bindings to describe vendor-specific reboot modes. Values here
>> correspond to valid parameters to vendor-specific reset types in PSCI
>> SYSTEM_RESET2 call.
>>
>> Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
>> Signed-off-by: Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>
>> ---
>>  Documentation/devicetree/bindings/arm/psci.yaml | 42 +++++++++++++++++++++++++
>>  1 file changed, 42 insertions(+)
>>
> 
> 
> Please use scripts/get_maintainers.pl to get a list of necessary people
> and lists to CC. It might happen, that command when run on an older
> kernel, gives you outdated entries. Therefore please be sure you base
> your patches on recent Linux kernel.
> 
> Tools like b4 or scripts/get_maintainer.pl provide you proper list of
> people, so fix your workflow. Tools might also fail if you work on some
> ancient tree (don't, instead use mainline) or work on fork of kernel
> (don't, instead use mainline). Just use b4 and everything should be
> fine, although remember about `b4 prep --auto-to-cc` if you added new
> patches to the patchset.
> 
> You missed at least devicetree list (maybe more), so this won't be
> tested by automated tooling. Performing review on untested code might be
> a waste of time.
> 
> Please kindly resend and include all necessary To/Cc entries.

sure. thanks. Will make sure on this.

thanks,
Shivendra


From linusw at kernel.org  Fri Dec 26 09:45:59 2025
From: linusw at kernel.org (Linus Walleij)
Date: Fri, 26 Dec 2025 18:45:59 +0100
Subject: [PATCH] pinctrl: mediatek: mt8189: restore previous register base
 name array order
In-Reply-To: <20251203-mt8189-pinctrl-fix-regname-order-v1-1-16c8ff5490a7@collabora.com>
References: <20251203-mt8189-pinctrl-fix-regname-order-v1-1-16c8ff5490a7@collabora.com>
Message-ID: <CAD++jLnfTdN7Wwa+a-ze2112vkMPcTtvEUoOZDtu166hu4DP3g@mail.gmail.com>

On Wed, Dec 3, 2025 at 12:33?PM Louis-Alexis Eyraud
<louisalexis.eyraud at collabora.com> wrote:

> In mt8189-pinctrl driver, a previous commit changed the register base
> name array (mt8189_pinctrl_register_base_names) entry name and order to
> align it with the same name and order as the "mediatek,mt8189-pinctrl"
> devicetree bindings. The new order (by ascending register address) now
> causes an issue with MT8189 pinctrl configuration.
>
> MT8189 SoC has multiple base addresses for the pin configuration
> registers. Several constant data structures, declaring each pin
> configuration, are using PIN_FIELD_BASE() macro which i_base parameter
> indicates for a given pin the lookup index in the base register address
> array of the driver internal data for the configuration register
> read/write accesses. But in practice, this parameter is given a
> hardcoded numerical value that corresponds to the expected base
> register entry index in mt8189_pinctrl_register_base_names array.
> Since this array reordering, the i_base index matching is no more
> correct.
>
> So, in order to avoid modifying over a thousand of PIN_FIELD_BASE()
> calls, restore previous mt8189_pinctrl_register_base_names entry order.
>
> Fixes: 518919276c41 ("pinctrl: mediatek: mt8189: align register base names to dt-bindings ones")
> Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>

There have not been any comments on this so patch applied for
fixes.

Yours,
Linus Walleij


From linusw at kernel.org  Fri Dec 26 10:07:45 2025
From: linusw at kernel.org (Linus Walleij)
Date: Fri, 26 Dec 2025 19:07:45 +0100
Subject: [PATCH v3 6/7] dt-bindings: pinctrl: rockchip: Add RMIO
 controller binding
In-Reply-To: <20251216112053.1927852-7-ye.zhang@rock-chips.com>
References: <20251216112053.1927852-1-ye.zhang@rock-chips.com> <20251216112053.1927852-7-ye.zhang@rock-chips.com>
Message-ID: <CAD++jLntu4LY=VHOMSXeLKXOBD9MTNziv47B0qkDjxUa1xAsng@mail.gmail.com>

Hi Ye,

thanks for your patch!

On Tue, Dec 16, 2025 at 3:50?PM Ye Zhang <ye.zhang at rock-chips.com> wrote:


> diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml b/Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml

> +  rockchip,rmio-grf:
> +    $ref: /schemas/types.yaml#/definitions/phandle
> +    description:
> +      The phandle of the syscon node (GRF or PMU) containing the RMIO registers.
> +      This property is required if the RMIO registers are located in a different
> +      syscon than the parent pinctrl node.
> +
> +  rockchip,offset:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    description:
> +      The offset of the RMIO configuration registers within the GRF.

Can't this just be a cell in the phandle?

> +  rockchip,pins-num:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    description:
> +      The number of physical pins supported by this RMIO instance.
> +      Used for boundary checking and driver initialization.

Isn't this implicit from the compatible? Why is this different
between two device trees using the same compatible pin
controller? I don't get it, I think this should be a constant in the
code based on the compatible instead.

> +patternProperties:
> +  "^[a-z0-9-]+$":
> +    type: object
> +    description:
> +      Function node grouping multiple groups.
> +
> +    patternProperties:
> +      "^[a-z0-9-]+$":
> +        type: object
> +        description:
> +          Group node containing the pinmux configuration.
> +
> +        properties:
> +          rockchip,rmio:
> +            $ref: /schemas/types.yaml#/definitions/uint32-matrix
> +            description:
> +              A list of pin-function pairs. The format is <pin_id function_id>.
> +            minItems: 1
> +            items:
> +              items:
> +                - description: RMIO Pin ID (0 to pins-num - 1)
> +                  minimum: 0
> +                  maximum: 31
> +                - description: Function ID
> +                  minimum: 0
> +                  maximum: 98

Please avoid these custom properties and just use the standard
"pinmux" property. I don't want any more opaque custom bindings
for functions and groups.

Reference Documentation/devicetree/bindings/pinctrl/pinmux-node.yaml
and use pinmux from there.

You can use some shifting and defines to shoehorn your config
into a single u32 and parse that in your driver; i.e. instead of
rockchip,rmio = <1, 2>;
use
pinmux = <1 << 8 | 2 << 0>;
these shifter numerals can come from defines.
In the driver shift & mask out the components you want.

e.g.;

> +            rmio-uart {
> +                rmio_pin27_uart1_tx: rmio-pin27-uart1-tx {
> +                    rockchip,rmio = <27 RMIO_UART1_TX>;

pinmux = <27 << 8 | RMIO_UART1_TX>;

> +++ b/include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h

These number dumps are not appreciated inside the bindings
despite quite a few found their way in there.

Use something like
arch/*/dts/rockchip/rk3506-rmio-pins.dtsi
and include that into your device trees instead.

Yours,
Linus Walleij


From linusw at kernel.org  Fri Dec 26 10:14:55 2025
From: linusw at kernel.org (Linus Walleij)
Date: Fri, 26 Dec 2025 19:14:55 +0100
Subject: [PATCH] pinctrl: mediatek: make devm allocations safer and
 clearer in mtk_eint_do_init()
In-Reply-To: <20251209100217.167581-1-buaajxlj@163.com>
References: <20251209100217.167581-1-buaajxlj@163.com>
Message-ID: <CAD++jLmHWkmOm9nNbchNNoWG=TYPs3nZmB-fUEwb6fuspiTd7A@mail.gmail.com>

On Tue, Dec 9, 2025 at 11:03?AM Liang Jie <buaajxlj at 163.com> wrote:

> From: Liang Jie <liangjie at lixiang.com>
>
> mtk_eint_do_init() allocates several pointer arrays which are then
> populated in a per-instance loop and freed on error. The arrays are
> currently allocated with devm_kmalloc(), so their entries are left
> uninitialised until the per-instance allocations succeed.
>
> On a failure in the middle of the loop, the error path iterates over
> the full nbase range and calls devm_kfree() on each element. For
> indices which were never initialised, the corresponding array entries
> contain stack garbage. If any of those happen to be non-zero,
> devm_kfree() will pass them to devres_destroy(), which will WARN
> because there is no matching devm_kmalloc() resource for such bogus
> pointers.
>
> Improve the robustness and readability by:
>
>   - Using devm_kcalloc() for the pointer arrays so that all entries
>     start as NULL, ensuring that only genuinely initialised elements
>     may be freed and preventing spurious WARN_ON()s in the error path.
>   - Switching the allocations to sizeof(*ptr) / sizeof(**ptr) forms,
>     avoiding hard-coded element types and making the code more resilient
>     to future type changes.
>   - Dropping the redundant NULL checks before devm_kfree(), as
>     devm_kfree() safely handles NULL pointers.
>
> The functional behaviour in the successful initialisation path remains
> unchanged, while the error handling becomes simpler and less
> error-prone.
>
> Reviewed-by: fanggeng <fanggeng at lixiang.com>
> Signed-off-by: Liang Jie <liangjie at lixiang.com>

This looks reasonable to me, so patch applied.

Yours,
Linus Walleij


From llong at redhat.com  Fri Dec 26 12:31:26 2025
From: llong at redhat.com (Waiman Long)
Date: Fri, 26 Dec 2025 15:31:26 -0500
Subject: [PATCH 18/33] cpuset: Propagate cpuset isolation update to
 workqueue through housekeeping
In-Reply-To: <20251224134520.33231-19-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-19-frederic@kernel.org>
Message-ID: <a9aa92b5-5e5a-4e9f-bfa3-31033d190457@redhat.com>

On 12/24/25 8:45 AM, Frederic Weisbecker wrote:
> Until now, cpuset would propagate isolated partition changes to
> workqueues so that unbound workers get properly reaffined.
>
> Since housekeeping now centralizes, synchronize and propagates isolation
> cpumask changes, perform the work from that subsystem for consolidation
> and consistency purposes.
>
> For simplification purpose, the target function is adapted to take the
> new housekeeping mask instead of the isolated mask.
>
> Suggested-by: Tejun Heo <tj at kernel.org>
> Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
> ---
>   include/linux/workqueue.h |  2 +-
>   init/Kconfig              |  1 +
>   kernel/cgroup/cpuset.c    |  9 +++------
>   kernel/sched/isolation.c  |  4 +++-
>   kernel/workqueue.c        | 17 ++++++++++-------
>   5 files changed, 18 insertions(+), 15 deletions(-)
>
> diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
> index dabc351cc127..a4749f56398f 100644
> --- a/include/linux/workqueue.h
> +++ b/include/linux/workqueue.h
> @@ -588,7 +588,7 @@ struct workqueue_attrs *alloc_workqueue_attrs_noprof(void);
>   void free_workqueue_attrs(struct workqueue_attrs *attrs);
>   int apply_workqueue_attrs(struct workqueue_struct *wq,
>   			  const struct workqueue_attrs *attrs);
> -extern int workqueue_unbound_exclude_cpumask(cpumask_var_t cpumask);
> +extern int workqueue_unbound_housekeeping_update(const struct cpumask *hk);
>   
>   extern bool queue_work_on(int cpu, struct workqueue_struct *wq,
>   			struct work_struct *work);
> diff --git a/init/Kconfig b/init/Kconfig
> index fa79feb8fe57..518830fb812f 100644
> --- a/init/Kconfig
> +++ b/init/Kconfig
> @@ -1254,6 +1254,7 @@ config CPUSETS
>   	bool "Cpuset controller"
>   	depends on SMP
>   	select UNION_FIND
> +	select CPU_ISOLATION
>   	help
>   	  This option will let you create and manage CPUSETs which
>   	  allow dynamically partitioning a system into sets of CPUs and
> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> index e13e32491ebf..a492d23dd622 100644
> --- a/kernel/cgroup/cpuset.c
> +++ b/kernel/cgroup/cpuset.c
> @@ -1484,15 +1484,12 @@ static void update_isolation_cpumasks(void)
>   
>   	lockdep_assert_cpus_held();
>   
> -	ret = workqueue_unbound_exclude_cpumask(isolated_cpus);
> -	WARN_ON_ONCE(ret < 0);
> -
> -	ret = tmigr_isolated_exclude_cpumask(isolated_cpus);
> -	WARN_ON_ONCE(ret < 0);
> -
>   	ret = housekeeping_update(isolated_cpus, HK_TYPE_DOMAIN);
>   	WARN_ON_ONCE(ret < 0);
>   
> +	ret = tmigr_isolated_exclude_cpumask(isolated_cpus);
> +	WARN_ON_ONCE(ret < 0);
> +
>   	isolated_cpus_updating = false;
>   }
>   
> diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c
> index 7dbe037ea8df..d224bca299ed 100644
> --- a/kernel/sched/isolation.c
> +++ b/kernel/sched/isolation.c
> @@ -121,6 +121,7 @@ EXPORT_SYMBOL_GPL(housekeeping_test_cpu);
>   int housekeeping_update(struct cpumask *isol_mask, enum hk_type type)
>   {
>   	struct cpumask *trial, *old = NULL;
> +	int err;
>   
>   	if (type != HK_TYPE_DOMAIN)
>   		return -ENOTSUPP;
> @@ -149,10 +150,11 @@ int housekeeping_update(struct cpumask *isol_mask, enum hk_type type)
>   	pci_probe_flush_workqueue();
>   	mem_cgroup_flush_workqueue();
>   	vmstat_flush_workqueue();
> +	err = workqueue_unbound_housekeeping_update(housekeeping_cpumask(type));
>   
>   	kfree(old);
>   
> -	return 0;
> +	return err;
>   }
>   
>   void __init housekeeping_init(void)
> diff --git a/kernel/workqueue.c b/kernel/workqueue.c
> index 253311af47c6..eb5660013222 100644
> --- a/kernel/workqueue.c
> +++ b/kernel/workqueue.c
> @@ -6959,13 +6959,16 @@ static int workqueue_apply_unbound_cpumask(const cpumask_var_t unbound_cpumask)
>   }
>   
>   /**
> - * workqueue_unbound_exclude_cpumask - Exclude given CPUs from unbound cpumask
> - * @exclude_cpumask: the cpumask to be excluded from wq_unbound_cpumask
> + * workqueue_unbound_housekeeping_update - Propagate housekeeping cpumask update
> + * @hk: the new housekeeping cpumask
>    *
> - * This function can be called from cpuset code to provide a set of isolated
> - * CPUs that should be excluded from wq_unbound_cpumask.
> + * Update the unbound workqueue cpumask on top of the new housekeeping cpumask such
> + * that the effective unbound affinity is the intersection of the new housekeeping
> + * with the requested affinity set via nohz_full=/isolcpus= or sysfs.
> + *
> + * Return: 0 on success and -errno on failure.
>    */
> -int workqueue_unbound_exclude_cpumask(cpumask_var_t exclude_cpumask)
> +int workqueue_unbound_housekeeping_update(const struct cpumask *hk)
>   {
>   	cpumask_var_t cpumask;
>   	int ret = 0;
> @@ -6981,14 +6984,14 @@ int workqueue_unbound_exclude_cpumask(cpumask_var_t exclude_cpumask)
>   	 * (HK_TYPE_WQ ? HK_TYPE_DOMAIN) house keeping mask and rewritten
>   	 * by any subsequent write to workqueue/cpumask sysfs file.
>   	 */
> -	if (!cpumask_andnot(cpumask, wq_requested_unbound_cpumask, exclude_cpumask))
> +	if (!cpumask_and(cpumask, wq_requested_unbound_cpumask, hk))
>   		cpumask_copy(cpumask, wq_requested_unbound_cpumask);
>   	if (!cpumask_equal(cpumask, wq_unbound_cpumask))
>   		ret = workqueue_apply_unbound_cpumask(cpumask);
>   
>   	/* Save the current isolated cpumask & export it via sysfs */
>   	if (!ret)
> -		cpumask_copy(wq_isolated_cpumask, exclude_cpumask);
> +		cpumask_andnot(wq_isolated_cpumask, cpu_possible_mask, hk);
>   
>   	mutex_unlock(&wq_pool_mutex);
>   	free_cpumask_var(cpumask);
Reviewed-by: Waiman Long <longman at redhat.com>



From llong at redhat.com  Fri Dec 26 12:45:12 2025
From: llong at redhat.com (Waiman Long)
Date: Fri, 26 Dec 2025 15:45:12 -0500
Subject: [PATCH 20/33] timers/migration: Remove superfluous cpuset
 isolation test
In-Reply-To: <20251224134520.33231-21-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-21-frederic@kernel.org>
Message-ID: <8282d85f-37b6-4f39-a70a-de5e6c77fb0b@redhat.com>

On 12/24/25 8:45 AM, Frederic Weisbecker wrote:
> Cpuset isolated partitions are now included in HK_TYPE_DOMAIN. Testing
> if a CPU is part of an isolated partition alone is now useless.
>
> Remove the superflous test.
>
> Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
> ---
>   kernel/time/timer_migration.c | 5 ++---
>   1 file changed, 2 insertions(+), 3 deletions(-)
>
> diff --git a/kernel/time/timer_migration.c b/kernel/time/timer_migration.c
> index 3879575a4975..6da9cd562b20 100644
> --- a/kernel/time/timer_migration.c
> +++ b/kernel/time/timer_migration.c
> @@ -466,9 +466,8 @@ static inline bool tmigr_is_isolated(int cpu)
>   {
>   	if (!static_branch_unlikely(&tmigr_exclude_isolated))
>   		return false;
> -	return (!housekeeping_cpu(cpu, HK_TYPE_DOMAIN) ||
> -		cpuset_cpu_is_isolated(cpu)) &&
> -	       housekeeping_cpu(cpu, HK_TYPE_KERNEL_NOISE);
> +	return (!housekeeping_cpu(cpu, HK_TYPE_DOMAIN) &&
> +		housekeeping_cpu(cpu, HK_TYPE_KERNEL_NOISE));
>   }
>   
>   /*
Reviewed-by: Waiman Long <longman at redhat.com>



From llong at redhat.com  Fri Dec 26 12:48:08 2025
From: llong at redhat.com (Waiman Long)
Date: Fri, 26 Dec 2025 15:48:08 -0500
Subject: [PATCH 21/33] cpuset: Remove cpuset_cpu_is_isolated()
In-Reply-To: <20251224134520.33231-22-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-22-frederic@kernel.org>
Message-ID: <eb7920d4-bca6-4692-9b8f-7feb715a6ec2@redhat.com>

On 12/24/25 8:45 AM, Frederic Weisbecker wrote:
> The set of cpuset isolated CPUs is now included in HK_TYPE_DOMAIN
> housekeeping cpumask. There is no usecase left interested in just
> checking what is isolated by cpuset and not by the isolcpus= kernel
> boot parameter.
>
> Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
> ---
>   include/linux/cpuset.h          |  6 ------
>   include/linux/sched/isolation.h |  4 +---
>   kernel/cgroup/cpuset.c          | 12 ------------
>   3 files changed, 1 insertion(+), 21 deletions(-)
>
> diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h
> index 1c49ffd2ca9b..a4aa2f1767d0 100644
> --- a/include/linux/cpuset.h
> +++ b/include/linux/cpuset.h
> @@ -79,7 +79,6 @@ extern void cpuset_unlock(void);
>   extern void cpuset_cpus_allowed_locked(struct task_struct *p, struct cpumask *mask);
>   extern void cpuset_cpus_allowed(struct task_struct *p, struct cpumask *mask);
>   extern bool cpuset_cpus_allowed_fallback(struct task_struct *p);
> -extern bool cpuset_cpu_is_isolated(int cpu);
>   extern nodemask_t cpuset_mems_allowed(struct task_struct *p);
>   #define cpuset_current_mems_allowed (current->mems_allowed)
>   void cpuset_init_current_mems_allowed(void);
> @@ -215,11 +214,6 @@ static inline bool cpuset_cpus_allowed_fallback(struct task_struct *p)
>   	return false;
>   }
>   
> -static inline bool cpuset_cpu_is_isolated(int cpu)
> -{
> -	return false;
> -}
> -
>   static inline nodemask_t cpuset_mems_allowed(struct task_struct *p)
>   {
>   	return node_possible_map;
> diff --git a/include/linux/sched/isolation.h b/include/linux/sched/isolation.h
> index 6842a1ba4d13..19905adbb705 100644
> --- a/include/linux/sched/isolation.h
> +++ b/include/linux/sched/isolation.h
> @@ -2,7 +2,6 @@
>   #define _LINUX_SCHED_ISOLATION_H
>   
>   #include <linux/cpumask.h>
> -#include <linux/cpuset.h>
>   #include <linux/init.h>
>   #include <linux/tick.h>
>   
> @@ -84,8 +83,7 @@ static inline bool housekeeping_cpu(int cpu, enum hk_type type)
>   static inline bool cpu_is_isolated(int cpu)
>   {
>   	return !housekeeping_test_cpu(cpu, HK_TYPE_DOMAIN) ||
> -	       !housekeeping_test_cpu(cpu, HK_TYPE_TICK) ||
> -	       cpuset_cpu_is_isolated(cpu);
> +	       !housekeeping_test_cpu(cpu, HK_TYPE_TICK);
>   }
>   
>   #endif /* _LINUX_SCHED_ISOLATION_H */
> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> index 25ac6c98113c..cd6119c02beb 100644
> --- a/kernel/cgroup/cpuset.c
> +++ b/kernel/cgroup/cpuset.c
> @@ -29,7 +29,6 @@
>   #include <linux/mempolicy.h>
>   #include <linux/mm.h>
>   #include <linux/memory.h>
> -#include <linux/export.h>
>   #include <linux/rcupdate.h>
>   #include <linux/sched.h>
>   #include <linux/sched/deadline.h>
> @@ -1490,17 +1489,6 @@ static void update_isolation_cpumasks(void)
>   	isolated_cpus_updating = false;
>   }
>   
> -/**
> - * cpuset_cpu_is_isolated - Check if the given CPU is isolated
> - * @cpu: the CPU number to be checked
> - * Return: true if CPU is used in an isolated partition, false otherwise
> - */
> -bool cpuset_cpu_is_isolated(int cpu)
> -{
> -	return cpumask_test_cpu(cpu, isolated_cpus);
> -}
> -EXPORT_SYMBOL_GPL(cpuset_cpu_is_isolated);
> -
>   /**
>    * rm_siblings_excl_cpus - Remove exclusive CPUs that are used by sibling cpusets
>    * @parent: Parent cpuset containing all siblings
Reviewed-by: Waiman Long <longman at redhat.com>



From llong at redhat.com  Fri Dec 26 13:26:55 2025
From: llong at redhat.com (Waiman Long)
Date: Fri, 26 Dec 2025 16:26:55 -0500
Subject: [PATCH 22/33] sched/isolation: Remove HK_TYPE_TICK test from
 cpu_is_isolated()
In-Reply-To: <20251224134520.33231-23-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-23-frederic@kernel.org>
Message-ID: <bc573163-c5a8-4bb9-a280-45ca48431999@redhat.com>

On 12/24/25 8:45 AM, Frederic Weisbecker wrote:
> It doesn't make sense to use nohz_full without also isolating the
> related CPUs from the domain topology, either through the use of
> isolcpus= or cpuset isolated partitions.
>
> And now HK_TYPE_DOMAIN includes all kinds of domain isolated CPUs.
>
> This means that HK_TYPE_KERNEL_NOISE (of which HK_TYPE_TICK is only an
> alias) should always be a subset of HK_TYPE_DOMAIN.
>
> Therefore if a CPU is not HK_TYPE_DOMAIN, it shouldn't be
> HK_TYPE_KERNEL_NOISE either. Testing the former is then enough.
>
> Simplify cpu_is_isolated() accordingly.
>
> Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
> ---
>   include/linux/sched/isolation.h | 3 +--
>   1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/include/linux/sched/isolation.h b/include/linux/sched/isolation.h
> index 19905adbb705..cbb1d30f699a 100644
> --- a/include/linux/sched/isolation.h
> +++ b/include/linux/sched/isolation.h
> @@ -82,8 +82,7 @@ static inline bool housekeeping_cpu(int cpu, enum hk_type type)
>   
>   static inline bool cpu_is_isolated(int cpu)
>   {
> -	return !housekeeping_test_cpu(cpu, HK_TYPE_DOMAIN) ||
> -	       !housekeeping_test_cpu(cpu, HK_TYPE_TICK);
> +	return !housekeeping_test_cpu(cpu, HK_TYPE_DOMAIN);
>   }
>   
>   #endif /* _LINUX_SCHED_ISOLATION_H */
Acked-by: Waiman Long <longman at redhat.com>



From llong at redhat.com  Fri Dec 26 13:37:31 2025
From: llong at redhat.com (Waiman Long)
Date: Fri, 26 Dec 2025 16:37:31 -0500
Subject: [PATCH 24/33] kthread: Refine naming of affinity related fields
In-Reply-To: <20251224134520.33231-25-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-25-frederic@kernel.org>
Message-ID: <af440ae9-e6ee-4cc8-a2d6-2178d9c80a50@redhat.com>

On 12/24/25 8:45 AM, Frederic Weisbecker wrote:
> The kthreads preferred affinity related fields use "hotplug" as the base
> of their naming because the affinity management was initially deemed to
> deal with CPU hotplug.
>
> The scope of this role is going to broaden now and also deal with
> cpuset isolated partition updates.
>
> Switch the naming accordingly.
>
> Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
> ---
>   kernel/kthread.c | 38 +++++++++++++++++++-------------------
>   1 file changed, 19 insertions(+), 19 deletions(-)
>
> diff --git a/kernel/kthread.c b/kernel/kthread.c
> index 99a3808d086f..f1e4f1f35cae 100644
> --- a/kernel/kthread.c
> +++ b/kernel/kthread.c
> @@ -35,8 +35,8 @@ static DEFINE_SPINLOCK(kthread_create_lock);
>   static LIST_HEAD(kthread_create_list);
>   struct task_struct *kthreadd_task;
>   
> -static LIST_HEAD(kthreads_hotplug);
> -static DEFINE_MUTEX(kthreads_hotplug_lock);
> +static LIST_HEAD(kthread_affinity_list);
> +static DEFINE_MUTEX(kthread_affinity_lock);
>   
>   struct kthread_create_info
>   {
> @@ -69,7 +69,7 @@ struct kthread {
>   	/* To store the full name if task comm is truncated. */
>   	char *full_name;
>   	struct task_struct *task;
> -	struct list_head hotplug_node;
> +	struct list_head affinity_node;
>   	struct cpumask *preferred_affinity;
>   };
>   
> @@ -128,7 +128,7 @@ bool set_kthread_struct(struct task_struct *p)
>   
>   	init_completion(&kthread->exited);
>   	init_completion(&kthread->parked);
> -	INIT_LIST_HEAD(&kthread->hotplug_node);
> +	INIT_LIST_HEAD(&kthread->affinity_node);
>   	p->vfork_done = &kthread->exited;
>   
>   	kthread->task = p;
> @@ -323,10 +323,10 @@ void __noreturn kthread_exit(long result)
>   {
>   	struct kthread *kthread = to_kthread(current);
>   	kthread->result = result;
> -	if (!list_empty(&kthread->hotplug_node)) {
> -		mutex_lock(&kthreads_hotplug_lock);
> -		list_del(&kthread->hotplug_node);
> -		mutex_unlock(&kthreads_hotplug_lock);
> +	if (!list_empty(&kthread->affinity_node)) {
> +		mutex_lock(&kthread_affinity_lock);
> +		list_del(&kthread->affinity_node);
> +		mutex_unlock(&kthread_affinity_lock);
>   
>   		if (kthread->preferred_affinity) {
>   			kfree(kthread->preferred_affinity);
> @@ -390,9 +390,9 @@ static void kthread_affine_node(void)
>   			return;
>   		}
>   
> -		mutex_lock(&kthreads_hotplug_lock);
> -		WARN_ON_ONCE(!list_empty(&kthread->hotplug_node));
> -		list_add_tail(&kthread->hotplug_node, &kthreads_hotplug);
> +		mutex_lock(&kthread_affinity_lock);
> +		WARN_ON_ONCE(!list_empty(&kthread->affinity_node));
> +		list_add_tail(&kthread->affinity_node, &kthread_affinity_list);
>   		/*
>   		 * The node cpumask is racy when read from kthread() but:
>   		 * - a racing CPU going down will either fail on the subsequent
> @@ -402,7 +402,7 @@ static void kthread_affine_node(void)
>   		 */
>   		kthread_fetch_affinity(kthread, affinity);
>   		set_cpus_allowed_ptr(current, affinity);
> -		mutex_unlock(&kthreads_hotplug_lock);
> +		mutex_unlock(&kthread_affinity_lock);
>   
>   		free_cpumask_var(affinity);
>   	}
> @@ -873,16 +873,16 @@ int kthread_affine_preferred(struct task_struct *p, const struct cpumask *mask)
>   		goto out;
>   	}
>   
> -	mutex_lock(&kthreads_hotplug_lock);
> +	mutex_lock(&kthread_affinity_lock);
>   	cpumask_copy(kthread->preferred_affinity, mask);
> -	WARN_ON_ONCE(!list_empty(&kthread->hotplug_node));
> -	list_add_tail(&kthread->hotplug_node, &kthreads_hotplug);
> +	WARN_ON_ONCE(!list_empty(&kthread->affinity_node));
> +	list_add_tail(&kthread->affinity_node, &kthread_affinity_list);
>   	kthread_fetch_affinity(kthread, affinity);
>   
>   	scoped_guard (raw_spinlock_irqsave, &p->pi_lock)
>   		set_cpus_allowed_force(p, affinity);
>   
> -	mutex_unlock(&kthreads_hotplug_lock);
> +	mutex_unlock(&kthread_affinity_lock);
>   out:
>   	free_cpumask_var(affinity);
>   
> @@ -903,9 +903,9 @@ static int kthreads_online_cpu(unsigned int cpu)
>   	struct kthread *k;
>   	int ret;
>   
> -	guard(mutex)(&kthreads_hotplug_lock);
> +	guard(mutex)(&kthread_affinity_lock);
>   
> -	if (list_empty(&kthreads_hotplug))
> +	if (list_empty(&kthread_affinity_list))
>   		return 0;
>   
>   	if (!zalloc_cpumask_var(&affinity, GFP_KERNEL))
> @@ -913,7 +913,7 @@ static int kthreads_online_cpu(unsigned int cpu)
>   
>   	ret = 0;
>   
> -	list_for_each_entry(k, &kthreads_hotplug, hotplug_node) {
> +	list_for_each_entry(k, &kthread_affinity_list, affinity_node) {
>   		if (WARN_ON_ONCE((k->task->flags & PF_NO_SETAFFINITY) ||
>   				 kthread_is_per_cpu(k->task))) {
>   			ret = -EINVAL;
Acked-by: Waiman Long <longman at redhat.com>



From llong at redhat.com  Fri Dec 26 14:11:26 2025
From: llong at redhat.com (Waiman Long)
Date: Fri, 26 Dec 2025 17:11:26 -0500
Subject: [PATCH 25/33] kthread: Include unbound kthreads in the managed
 affinity list
In-Reply-To: <20251224134520.33231-26-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-26-frederic@kernel.org>
Message-ID: <1e530c72-75d7-4c7e-96e7-329056d6baf5@redhat.com>

On 12/24/25 8:45 AM, Frederic Weisbecker wrote:
> The managed affinity list currently contains only unbound kthreads that
> have affinity preferences. Unbound kthreads globally affine by default
> are outside of the list because their affinity is automatically managed
> by the scheduler (through the fallback housekeeping mask) and by cpuset.
>
> However in order to preserve the preferred affinity of kthreads, cpuset
> will delegate the isolated partition update propagation to the
> housekeeping and kthread code.
>
> Prepare for that with including all unbound kthreads in the managed
> affinity list.
>
> Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
> ---
>   kernel/kthread.c | 70 ++++++++++++++++++++++++++++--------------------
>   1 file changed, 41 insertions(+), 29 deletions(-)
>
> diff --git a/kernel/kthread.c b/kernel/kthread.c
> index f1e4f1f35cae..51c0908d3d02 100644
> --- a/kernel/kthread.c
> +++ b/kernel/kthread.c
> @@ -365,9 +365,10 @@ static void kthread_fetch_affinity(struct kthread *kthread, struct cpumask *cpum
>   	if (kthread->preferred_affinity) {
>   		pref = kthread->preferred_affinity;
>   	} else {
> -		if (WARN_ON_ONCE(kthread->node == NUMA_NO_NODE))
> -			return;
> -		pref = cpumask_of_node(kthread->node);
> +		if (kthread->node == NUMA_NO_NODE)
> +			pref = housekeeping_cpumask(HK_TYPE_KTHREAD);
> +		else
> +			pref = cpumask_of_node(kthread->node);
>   	}
>   
>   	cpumask_and(cpumask, pref, housekeeping_cpumask(HK_TYPE_KTHREAD));
> @@ -380,32 +381,29 @@ static void kthread_affine_node(void)
>   	struct kthread *kthread = to_kthread(current);
>   	cpumask_var_t affinity;
>   
> -	WARN_ON_ONCE(kthread_is_per_cpu(current));
> +	if (WARN_ON_ONCE(kthread_is_per_cpu(current)))
> +		return;
>   
> -	if (kthread->node == NUMA_NO_NODE) {
> -		housekeeping_affine(current, HK_TYPE_KTHREAD);
> -	} else {
> -		if (!zalloc_cpumask_var(&affinity, GFP_KERNEL)) {
> -			WARN_ON_ONCE(1);
> -			return;
> -		}
> -
> -		mutex_lock(&kthread_affinity_lock);
> -		WARN_ON_ONCE(!list_empty(&kthread->affinity_node));
> -		list_add_tail(&kthread->affinity_node, &kthread_affinity_list);
> -		/*
> -		 * The node cpumask is racy when read from kthread() but:
> -		 * - a racing CPU going down will either fail on the subsequent
> -		 *   call to set_cpus_allowed_ptr() or be migrated to housekeepers
> -		 *   afterwards by the scheduler.
> -		 * - a racing CPU going up will be handled by kthreads_online_cpu()
> -		 */
> -		kthread_fetch_affinity(kthread, affinity);
> -		set_cpus_allowed_ptr(current, affinity);
> -		mutex_unlock(&kthread_affinity_lock);
> -
> -		free_cpumask_var(affinity);
> +	if (!zalloc_cpumask_var(&affinity, GFP_KERNEL)) {
> +		WARN_ON_ONCE(1);
> +		return;
>   	}
> +
> +	mutex_lock(&kthread_affinity_lock);
> +	WARN_ON_ONCE(!list_empty(&kthread->affinity_node));
> +	list_add_tail(&kthread->affinity_node, &kthread_affinity_list);
> +	/*
> +	 * The node cpumask is racy when read from kthread() but:
> +	 * - a racing CPU going down will either fail on the subsequent
> +	 *   call to set_cpus_allowed_ptr() or be migrated to housekeepers
> +	 *   afterwards by the scheduler.
> +	 * - a racing CPU going up will be handled by kthreads_online_cpu()
> +	 */
> +	kthread_fetch_affinity(kthread, affinity);
> +	set_cpus_allowed_ptr(current, affinity);
> +	mutex_unlock(&kthread_affinity_lock);
> +
> +	free_cpumask_var(affinity);
>   }
>   
>   static int kthread(void *_create)
> @@ -919,8 +917,22 @@ static int kthreads_online_cpu(unsigned int cpu)
>   			ret = -EINVAL;
>   			continue;
>   		}
> -		kthread_fetch_affinity(k, affinity);
> -		set_cpus_allowed_ptr(k->task, affinity);
> +
> +		/*
> +		 * Unbound kthreads without preferred affinity are already affine
> +		 * to housekeeping, whether those CPUs are online or not. So no need
> +		 * to handle newly online CPUs for them.
> +		 *
> +		 * But kthreads with a preferred affinity or node are different:
> +		 * if none of their preferred CPUs are online and part of
> +		 * housekeeping at the same time, they must be affine to housekeeping.
> +		 * But as soon as one of their preferred CPU becomes online, they must
> +		 * be affine to them.
> +		 */
> +		if (k->preferred_affinity || k->node != NUMA_NO_NODE) {
> +			kthread_fetch_affinity(k, affinity);
> +			set_cpus_allowed_ptr(k->task, affinity);
> +		}
>   	}
>   
>   	free_cpumask_var(affinity);
Reviewed-by: Waiman Long <longman at redhat.com>



From llong at redhat.com  Fri Dec 26 14:13:25 2025
From: llong at redhat.com (Waiman Long)
Date: Fri, 26 Dec 2025 17:13:25 -0500
Subject: [PATCH 26/33] kthread: Include kthreadd to the managed affinity
 list
In-Reply-To: <20251224134520.33231-27-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-27-frederic@kernel.org>
Message-ID: <48f8bff9-178c-4ab7-a8ef-7edba9b0e7bb@redhat.com>

On 12/24/25 8:45 AM, Frederic Weisbecker wrote:
> The unbound kthreads affinity management performed by cpuset is going to
> be imported to the kthread core code for consolidation purposes.
>
> Treat kthreadd just like any other kthread.
>
> Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
> ---
>   kernel/kthread.c | 3 ++-
>   1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/kernel/kthread.c b/kernel/kthread.c
> index 51c0908d3d02..85ccf5bb17c9 100644
> --- a/kernel/kthread.c
> +++ b/kernel/kthread.c
> @@ -818,12 +818,13 @@ int kthreadd(void *unused)
>   	/* Setup a clean context for our children to inherit. */
>   	set_task_comm(tsk, comm);
>   	ignore_signals(tsk);
> -	set_cpus_allowed_ptr(tsk, housekeeping_cpumask(HK_TYPE_KTHREAD));
>   	set_mems_allowed(node_states[N_MEMORY]);
>   
>   	current->flags |= PF_NOFREEZE;
>   	cgroup_init_kthreadd();
>   
> +	kthread_affine_node();
> +
>   	for (;;) {
>   		set_current_state(TASK_INTERRUPTIBLE);
>   		if (list_empty(&kthread_create_list))
Reviewed-by: Waiman Long <longman at redhat.com>



From llong at redhat.com  Fri Dec 26 14:16:54 2025
From: llong at redhat.com (Waiman Long)
Date: Fri, 26 Dec 2025 17:16:54 -0500
Subject: [PATCH 27/33] kthread: Rely on HK_TYPE_DOMAIN for preferred
 affinity management
In-Reply-To: <20251224134520.33231-28-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-28-frederic@kernel.org>
Message-ID: <46a613e8-cf5b-4fbc-9299-48ab1a6f347b@redhat.com>

On 12/24/25 8:45 AM, Frederic Weisbecker wrote:
> Unbound kthreads want to run neither on nohz_full CPUs nor on domain
> isolated CPUs. And since nohz_full implies domain isolation, checking
> the latter is enough to verify both.
>
> Therefore exclude kthreads from domain isolation.
>
> Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
> ---
>   kernel/kthread.c | 8 +++++---
>   1 file changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/kernel/kthread.c b/kernel/kthread.c
> index 85ccf5bb17c9..968fa5868d21 100644
> --- a/kernel/kthread.c
> +++ b/kernel/kthread.c
> @@ -362,18 +362,20 @@ static void kthread_fetch_affinity(struct kthread *kthread, struct cpumask *cpum
>   {
>   	const struct cpumask *pref;
>   
> +	guard(rcu)();
> +
>   	if (kthread->preferred_affinity) {
>   		pref = kthread->preferred_affinity;
>   	} else {
>   		if (kthread->node == NUMA_NO_NODE)
> -			pref = housekeeping_cpumask(HK_TYPE_KTHREAD);
> +			pref = housekeeping_cpumask(HK_TYPE_DOMAIN);
>   		else
>   			pref = cpumask_of_node(kthread->node);
>   	}
>   
> -	cpumask_and(cpumask, pref, housekeeping_cpumask(HK_TYPE_KTHREAD));
> +	cpumask_and(cpumask, pref, housekeeping_cpumask(HK_TYPE_DOMAIN));
>   	if (cpumask_empty(cpumask))
> -		cpumask_copy(cpumask, housekeeping_cpumask(HK_TYPE_KTHREAD));
> +		cpumask_copy(cpumask, housekeeping_cpumask(HK_TYPE_DOMAIN));
>   }
>   
>   static void kthread_affine_node(void)
Reviewed-by: Waiman Long <longman at redhat.com>



From helgaas at kernel.org  Fri Dec 26 14:31:59 2025
From: helgaas at kernel.org (Bjorn Helgaas)
Date: Fri, 26 Dec 2025 16:31:59 -0600
Subject: [PATCH v2 1/6] Revert "PCI: dw-rockchip: Don't wait for link
 since we can detect Link Up"
In-Reply-To: <20251222064207.3246632-9-cassel@kernel.org>
Message-ID: <20251226223159.GA4143516@bhelgaas>

[+cc Ilpo]

On Mon, Dec 22, 2025 at 07:42:08AM +0100, Niklas Cassel wrote:
> This reverts commit ec9fd499b9c60a187ac8d6414c3c343c77d32e42.
> 
> While this fake hotplugging was a nice idea, it has shown that this feature
> does not handle PCIe switches correctly:
> pci_bus 0004:43: busn_res: can not insert [bus 43-41] under [bus 42-41] (conflicts with (null) [bus 42-41])

Apart from the actual problem you're fixing, it looks like some of our
bus number resource setup is a little deficient here.  The "43-41" and
"42-41" ranges are bogus and "(null)" doesn't tell us anything useful.

> pci_bus 0004:43: busn_res: [bus 43-41] end is updated to 43
> pci_bus 0004:43: busn_res: can not insert [bus 43] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci 0004:42:00.0: devices behind bridge are unusable because [bus 43] cannot be assigned for them
> pci_bus 0004:44: busn_res: can not insert [bus 44-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci_bus 0004:44: busn_res: [bus 44-41] end is updated to 44
> pci_bus 0004:44: busn_res: can not insert [bus 44] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci 0004:42:02.0: devices behind bridge are unusable because [bus 44] cannot be assigned for them
> pci_bus 0004:45: busn_res: can not insert [bus 45-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci_bus 0004:45: busn_res: [bus 45-41] end is updated to 45
> pci_bus 0004:45: busn_res: can not insert [bus 45] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci 0004:42:06.0: devices behind bridge are unusable because [bus 45] cannot be assigned for them
> pci_bus 0004:46: busn_res: can not insert [bus 46-41] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci_bus 0004:46: busn_res: [bus 46-41] end is updated to 46
> pci_bus 0004:46: busn_res: can not insert [bus 46] under [bus 42-41] (conflicts with (null) [bus 42-41])
> pci 0004:42:0e.0: devices behind bridge are unusable because [bus 46] cannot be assigned for them
> pci_bus 0004:42: busn_res: [bus 42-41] end is updated to 46
> pci_bus 0004:42: busn_res: can not insert [bus 42-46] under [bus 41] (conflicts with (null) [bus 41])
> pci 0004:41:00.0: devices behind bridge are unusable because [bus 42-46] cannot be assigned for them
> pcieport 0004:40:00.0: bridge has subordinate 41 but max busn 46
> 
> During the initial scan, PCI core doesn't see the switch and since the Root
> Port is not hot plug capable, the secondary bus number gets assigned as the
> subordinate bus number. This means, the PCI core assumes that only one bus
> will appear behind the Root Port since the Root Port is not hot plug
> capable.
> 
> This works perfectly fine for PCIe endpoints connected to the Root Port,
> since they don't extend the bus. However, if a PCIe switch is connected,
> then there is a problem when the downstream busses starts showing up and
> the PCI core doesn't extend the subordinate bus number after initial scan
> during boot.

I suppose this is could also be viewed as a resource management
problem.  

Even in the normal hotplug case, we never know what a hot-added
hierarchy will look like, so we hack around it with the compiled-in
DEFAULT_HOTPLUG_BUS_SIZE and the "hpbussize=" kernel parameter.

It would be nice if we could allocate more bus numbers at hot-add (or
link-up) time as needed.  That's hard after drivers have claimed
nearby devices, but in this case there might not be anything nearby.

> The long term plan is to migrate this driver to the pwrctrl framework,
> once it adds proper support for powering up and enumerating PCIe switches.

"Proper" is hiding some important details here.  pwrctrl already
supports powering up and enumerating switches.  I think this refers to
[1], where Mani says the plan is for pwrctrl to power up everything
before the initial bus scan so we can figure out how many buses are
needed.

Bjorn

[1] https://lore.kernel.org/linux-pci/fle74skju2rorxmfdvosmeyrx3g75rysuszov5ofvde2exj4ir at 3kfjyfyhczmn/


From 21cnbao at gmail.com  Fri Dec 26 14:52:41 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Sat, 27 Dec 2025 11:52:41 +1300
Subject: [PATCH v2 1/8] arm64: Provide dcache_by_myline_op_nosync helper
In-Reply-To: <20251226225254.46197-1-21cnbao@gmail.com>
References: <20251226225254.46197-1-21cnbao@gmail.com>
Message-ID: <20251226225254.46197-2-21cnbao@gmail.com>

From: Barry Song <baohua at kernel.org>

dcache_by_myline_op ensures completion of the data cache operations for a
region, while dcache_by_myline_op_nosync only issues them without waiting.
This enables deferred synchronization so completion for multiple regions
can be handled together later.

Cc: Leon Romanovsky <leon at kernel.org>
Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Will Deacon <will at kernel.org>
Cc: Marek Szyprowski <m.szyprowski at samsung.com>
Cc: Robin Murphy <robin.murphy at arm.com>
Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
Cc: Ard Biesheuvel <ardb at kernel.org>
Cc: Marc Zyngier <maz at kernel.org>
Cc: Anshuman Khandual <anshuman.khandual at arm.com>
Cc: Ryan Roberts <ryan.roberts at arm.com>
Cc: Suren Baghdasaryan <surenb at google.com>
Cc: Tangquan Zheng <zhengtangquan at oppo.com>
Signed-off-by: Barry Song <baohua at kernel.org>
---
 arch/arm64/include/asm/assembler.h  | 24 +++++++++++++++++++-----
 arch/arm64/kernel/relocate_kernel.S |  3 ++-
 2 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index f0ca7196f6fa..b408ed61866f 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -371,14 +371,13 @@ alternative_endif
  * [start, end) with dcache line size explicitly provided.
  *
  * 	op:		operation passed to dc instruction
- * 	domain:		domain used in dsb instruction
  * 	start:          starting virtual address of the region
  * 	end:            end virtual address of the region
  *	linesz:		dcache line size
  * 	fixup:		optional label to branch to on user fault
  * 	Corrupts:       start, end, tmp
  */
-	.macro dcache_by_myline_op op, domain, start, end, linesz, tmp, fixup
+	.macro raw_dcache_by_myline_op op, start, end, linesz, tmp, fixup
 	sub	\tmp, \linesz, #1
 	bic	\start, \start, \tmp
 .Ldcache_op\@:
@@ -402,14 +401,13 @@ alternative_endif
 	add	\start, \start, \linesz
 	cmp	\start, \end
 	b.lo	.Ldcache_op\@
-	dsb	\domain
 
 	_cond_uaccess_extable .Ldcache_op\@, \fixup
 	.endm
 
 /*
  * Macro to perform a data cache maintenance for the interval
- * [start, end)
+ * [start, end) and wait for completion
  *
  * 	op:		operation passed to dc instruction
  * 	domain:		domain used in dsb instruction
@@ -420,7 +418,23 @@ alternative_endif
  */
 	.macro dcache_by_line_op op, domain, start, end, tmp1, tmp2, fixup
 	dcache_line_size \tmp1, \tmp2
-	dcache_by_myline_op \op, \domain, \start, \end, \tmp1, \tmp2, \fixup
+	raw_dcache_by_myline_op \op, \start, \end, \tmp1, \tmp2, \fixup
+	dsb \domain
+	.endm
+
+/*
+ * Macro to perform a data cache maintenance for the interval
+ * [start, end) without waiting for completion
+ *
+ * 	op:		operation passed to dc instruction
+ * 	start:          starting virtual address of the region
+ * 	end:            end virtual address of the region
+ * 	fixup:		optional label to branch to on user fault
+ * 	Corrupts:       start, end, tmp1, tmp2
+ */
+	.macro dcache_by_line_op_nosync op, start, end, tmp1, tmp2, fixup
+	dcache_line_size \tmp1, \tmp2
+	raw_dcache_by_myline_op \op, \start, \end, \tmp1, \tmp2, \fixup
 	.endm
 
 /*
diff --git a/arch/arm64/kernel/relocate_kernel.S b/arch/arm64/kernel/relocate_kernel.S
index 413f899e4ac6..71938eb3a3a3 100644
--- a/arch/arm64/kernel/relocate_kernel.S
+++ b/arch/arm64/kernel/relocate_kernel.S
@@ -64,7 +64,8 @@ SYM_CODE_START(arm64_relocate_new_kernel)
 	mov	x19, x13
 	copy_page x13, x12, x1, x2, x3, x4, x5, x6, x7, x8
 	add	x1, x19, #PAGE_SIZE
-	dcache_by_myline_op civac, sy, x19, x1, x15, x20
+	raw_dcache_by_myline_op civac, x19, x1, x15, x20
+	dsb	sy
 	b	.Lnext
 .Ltest_indirection:
 	tbz	x16, IND_INDIRECTION_BIT, .Ltest_destination
-- 
2.43.0



From 21cnbao at gmail.com  Fri Dec 26 14:52:42 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Sat, 27 Dec 2025 11:52:42 +1300
Subject: [PATCH v2 2/8] arm64: Provide dcache_clean_poc_nosync helper
In-Reply-To: <20251226225254.46197-1-21cnbao@gmail.com>
References: <20251226225254.46197-1-21cnbao@gmail.com>
Message-ID: <20251226225254.46197-3-21cnbao@gmail.com>

From: Barry Song <baohua at kernel.org>

dcache_clean_poc_nosync does not wait for the data cache clean to
complete. Later, we wait for completion of all scatter-gather entries
together.

Cc: Leon Romanovsky <leon at kernel.org>
Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Will Deacon <will at kernel.org>
Cc: Marek Szyprowski <m.szyprowski at samsung.com>
Cc: Robin Murphy <robin.murphy at arm.com>
Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
Cc: Ard Biesheuvel <ardb at kernel.org>
Cc: Marc Zyngier <maz at kernel.org>
Cc: Anshuman Khandual <anshuman.khandual at arm.com>
Cc: Ryan Roberts <ryan.roberts at arm.com>
Cc: Suren Baghdasaryan <surenb at google.com>
Cc: Tangquan Zheng <zhengtangquan at oppo.com>
Signed-off-by: Barry Song <baohua at kernel.org>
---
 arch/arm64/include/asm/cacheflush.h |  1 +
 arch/arm64/mm/cache.S               | 15 +++++++++++++++
 2 files changed, 16 insertions(+)

diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h
index 28ab96e808ef..9b6d0a62cf3d 100644
--- a/arch/arm64/include/asm/cacheflush.h
+++ b/arch/arm64/include/asm/cacheflush.h
@@ -74,6 +74,7 @@ extern void icache_inval_pou(unsigned long start, unsigned long end);
 extern void dcache_clean_inval_poc(unsigned long start, unsigned long end);
 extern void dcache_inval_poc(unsigned long start, unsigned long end);
 extern void dcache_clean_poc(unsigned long start, unsigned long end);
+extern void dcache_clean_poc_nosync(unsigned long start, unsigned long end);
 extern void dcache_clean_pop(unsigned long start, unsigned long end);
 extern void dcache_clean_pou(unsigned long start, unsigned long end);
 extern long caches_clean_inval_user_pou(unsigned long start, unsigned long end);
diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S
index 503567c864fd..4a7c7e03785d 100644
--- a/arch/arm64/mm/cache.S
+++ b/arch/arm64/mm/cache.S
@@ -178,6 +178,21 @@ SYM_FUNC_START(__pi_dcache_clean_poc)
 SYM_FUNC_END(__pi_dcache_clean_poc)
 SYM_FUNC_ALIAS(dcache_clean_poc, __pi_dcache_clean_poc)
 
+/*
+ *	dcache_clean_poc_nosync(start, end)
+ *
+ * 	Issue the instructions of D-cache lines for the interval [start, end).
+ * 	not necessarily cleaned to the PoC till an explicit dsb sy afterward.
+ *
+ *	- start   - virtual start address of region
+ *	- end     - virtual end address of region
+ */
+SYM_FUNC_START(__pi_dcache_clean_poc_nosync)
+	dcache_by_line_op_nosync cvac, x0, x1, x2, x3
+	ret
+SYM_FUNC_END(__pi_dcache_clean_poc_nosync)
+SYM_FUNC_ALIAS(dcache_clean_poc_nosync, __pi_dcache_clean_poc_nosync)
+
 /*
  *	dcache_clean_pop(start, end)
  *
-- 
2.43.0



From 21cnbao at gmail.com  Fri Dec 26 14:52:43 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Sat, 27 Dec 2025 11:52:43 +1300
Subject: [PATCH v2 3/8] arm64: Provide dcache_inval_poc_nosync helper
In-Reply-To: <20251226225254.46197-1-21cnbao@gmail.com>
References: <20251226225254.46197-1-21cnbao@gmail.com>
Message-ID: <20251226225254.46197-4-21cnbao@gmail.com>

From: Barry Song <baohua at kernel.org>

dcache_inval_poc_nosync does not wait for the data cache invalidation to
complete. Later, we defer the synchronization so we can wait for all SG
entries together.

Cc: Leon Romanovsky <leon at kernel.org>
Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Will Deacon <will at kernel.org>
Cc: Marek Szyprowski <m.szyprowski at samsung.com>
Cc: Robin Murphy <robin.murphy at arm.com>
Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
Cc: Ard Biesheuvel <ardb at kernel.org>
Cc: Marc Zyngier <maz at kernel.org>
Cc: Anshuman Khandual <anshuman.khandual at arm.com>
Cc: Ryan Roberts <ryan.roberts at arm.com>
Cc: Suren Baghdasaryan <surenb at google.com>
Cc: Tangquan Zheng <zhengtangquan at oppo.com>
Signed-off-by: Barry Song <baohua at kernel.org>
---
 arch/arm64/include/asm/cacheflush.h |  1 +
 arch/arm64/mm/cache.S               | 42 +++++++++++++++++++++--------
 2 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h
index 9b6d0a62cf3d..382b4ac3734d 100644
--- a/arch/arm64/include/asm/cacheflush.h
+++ b/arch/arm64/include/asm/cacheflush.h
@@ -74,6 +74,7 @@ extern void icache_inval_pou(unsigned long start, unsigned long end);
 extern void dcache_clean_inval_poc(unsigned long start, unsigned long end);
 extern void dcache_inval_poc(unsigned long start, unsigned long end);
 extern void dcache_clean_poc(unsigned long start, unsigned long end);
+extern void dcache_inval_poc_nosync(unsigned long start, unsigned long end);
 extern void dcache_clean_poc_nosync(unsigned long start, unsigned long end);
 extern void dcache_clean_pop(unsigned long start, unsigned long end);
 extern void dcache_clean_pou(unsigned long start, unsigned long end);
diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S
index 4a7c7e03785d..99a093d3aecb 100644
--- a/arch/arm64/mm/cache.S
+++ b/arch/arm64/mm/cache.S
@@ -132,17 +132,7 @@ alternative_else_nop_endif
 	ret
 SYM_FUNC_END(dcache_clean_pou)
 
-/*
- *	dcache_inval_poc(start, end)
- *
- * 	Ensure that any D-cache lines for the interval [start, end)
- * 	are invalidated. Any partial lines at the ends of the interval are
- *	also cleaned to PoC to prevent data loss.
- *
- *	- start   - kernel start address of region
- *	- end     - kernel end address of region
- */
-SYM_FUNC_START(__pi_dcache_inval_poc)
+.macro raw_dcache_inval_poc_macro
 	dcache_line_size x2, x3
 	sub	x3, x2, #1
 	tst	x1, x3				// end cache line aligned?
@@ -158,11 +148,41 @@ SYM_FUNC_START(__pi_dcache_inval_poc)
 3:	add	x0, x0, x2
 	cmp	x0, x1
 	b.lo	2b
+.endm
+
+/*
+ *	dcache_inval_poc(start, end)
+ *
+ * 	Ensure that any D-cache lines for the interval [start, end)
+ * 	are invalidated. Any partial lines at the ends of the interval are
+ *	also cleaned to PoC to prevent data loss.
+ *
+ *	- start   - kernel start address of region
+ *	- end     - kernel end address of region
+ */
+SYM_FUNC_START(__pi_dcache_inval_poc)
+	raw_dcache_inval_poc_macro
 	dsb	sy
 	ret
 SYM_FUNC_END(__pi_dcache_inval_poc)
 SYM_FUNC_ALIAS(dcache_inval_poc, __pi_dcache_inval_poc)
 
+/*
+ *	dcache_inval_poc_nosync(start, end)
+ *
+ * 	Issue the instructions of D-cache lines for the interval [start, end)
+ * 	for invalidation. Not necessarily cleaned to PoC till an explicit dsb
+ *	sy is issued later
+ *
+ *	- start   - kernel start address of region
+ *	- end     - kernel end address of region
+ */
+SYM_FUNC_START(__pi_dcache_inval_poc_nosync)
+	raw_dcache_inval_poc_macro
+	ret
+SYM_FUNC_END(__pi_dcache_inval_poc_nosync)
+SYM_FUNC_ALIAS(dcache_inval_poc_nosync, __pi_dcache_inval_poc_nosync)
+
 /*
  *	dcache_clean_poc(start, end)
  *
-- 
2.43.0



From 21cnbao at gmail.com  Fri Dec 26 14:52:44 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Sat, 27 Dec 2025 11:52:44 +1300
Subject: [PATCH v2 4/8] dma-mapping: Separate DMA sync issuing and completion waiting
In-Reply-To: <20251226225254.46197-1-21cnbao@gmail.com>
References: <20251226225254.46197-1-21cnbao@gmail.com>
Message-ID: <20251226225254.46197-5-21cnbao@gmail.com>

From: Barry Song <baohua at kernel.org>

Currently, arch_sync_dma_for_cpu and arch_sync_dma_for_device
always wait for the completion of each DMA buffer. That is,
issuing the DMA sync and waiting for completion is done in a
single API call.

For scatter-gather lists with multiple entries, this means
issuing and waiting is repeated for each entry, which can hurt
performance. Architectures like ARM64 may be able to issue all
DMA sync operations for all entries first and then wait for
completion together.

To address this, arch_sync_dma_for_* now issues DMA operations in
batch, followed by a flush. On ARM64, the flush is implemented
using a dsb instruction within arch_sync_dma_flush().

For now, add arch_sync_dma_flush() after each
arch_sync_dma_for_*() call. arch_sync_dma_flush() is defined as a
no-op on all architectures except arm64, so this patch does not
change existing behavior. Subsequent patches will introduce true
batching for SG DMA buffers.

Cc: Leon Romanovsky <leon at kernel.org>
Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Will Deacon <will at kernel.org>
Cc: Marek Szyprowski <m.szyprowski at samsung.com>
Cc: Robin Murphy <robin.murphy at arm.com>
Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
Cc: Ard Biesheuvel <ardb at kernel.org>
Cc: Marc Zyngier <maz at kernel.org>
Cc: Anshuman Khandual <anshuman.khandual at arm.com>
Cc: Ryan Roberts <ryan.roberts at arm.com>
Cc: Suren Baghdasaryan <surenb at google.com>
Cc: Joerg Roedel <joro at 8bytes.org>
Cc: Juergen Gross <jgross at suse.com>
Cc: Stefano Stabellini <sstabellini at kernel.org>
Cc: Oleksandr Tyshchenko <oleksandr_tyshchenko at epam.com>
Cc: Tangquan Zheng <zhengtangquan at oppo.com>
Signed-off-by: Barry Song <baohua at kernel.org>
---
 arch/arm64/include/asm/cache.h |  6 ++++++
 arch/arm64/mm/dma-mapping.c    |  4 ++--
 drivers/iommu/dma-iommu.c      | 37 +++++++++++++++++++++++++---------
 drivers/xen/swiotlb-xen.c      | 24 ++++++++++++++--------
 include/linux/dma-map-ops.h    |  6 ++++++
 kernel/dma/direct.c            |  8 ++++++--
 kernel/dma/direct.h            |  9 +++++++--
 kernel/dma/swiotlb.c           |  4 +++-
 8 files changed, 73 insertions(+), 25 deletions(-)

diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h
index dd2c8586a725..487fb7c355ed 100644
--- a/arch/arm64/include/asm/cache.h
+++ b/arch/arm64/include/asm/cache.h
@@ -87,6 +87,12 @@ int cache_line_size(void);
 
 #define dma_get_cache_alignment	cache_line_size
 
+static inline void arch_sync_dma_flush(void)
+{
+	dsb(sy);
+}
+#define arch_sync_dma_flush arch_sync_dma_flush
+
 /* Compress a u64 MPIDR value into 32 bits. */
 static inline u64 arch_compact_of_hwid(u64 id)
 {
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index b2b5792b2caa..ae1ae0280eef 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -17,7 +17,7 @@ void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
 {
 	unsigned long start = (unsigned long)phys_to_virt(paddr);
 
-	dcache_clean_poc(start, start + size);
+	dcache_clean_poc_nosync(start, start + size);
 }
 
 void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
@@ -28,7 +28,7 @@ void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
 	if (dir == DMA_TO_DEVICE)
 		return;
 
-	dcache_inval_poc(start, start + size);
+	dcache_inval_poc_nosync(start, start + size);
 }
 
 void arch_dma_prep_coherent(struct page *page, size_t size)
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index c92088855450..6827763a3877 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -1095,8 +1095,10 @@ void iommu_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
 		return;
 
 	phys = iommu_iova_to_phys(iommu_get_dma_domain(dev), dma_handle);
-	if (!dev_is_dma_coherent(dev))
+	if (!dev_is_dma_coherent(dev)) {
 		arch_sync_dma_for_cpu(phys, size, dir);
+		arch_sync_dma_flush();
+	}
 
 	swiotlb_sync_single_for_cpu(dev, phys, size, dir);
 }
@@ -1112,8 +1114,10 @@ void iommu_dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
 	phys = iommu_iova_to_phys(iommu_get_dma_domain(dev), dma_handle);
 	swiotlb_sync_single_for_device(dev, phys, size, dir);
 
-	if (!dev_is_dma_coherent(dev))
+	if (!dev_is_dma_coherent(dev)) {
 		arch_sync_dma_for_device(phys, size, dir);
+		arch_sync_dma_flush();
+	}
 }
 
 void iommu_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl,
@@ -1122,13 +1126,16 @@ void iommu_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl,
 	struct scatterlist *sg;
 	int i;
 
-	if (sg_dma_is_swiotlb(sgl))
+	if (sg_dma_is_swiotlb(sgl)) {
 		for_each_sg(sgl, sg, nelems, i)
 			iommu_dma_sync_single_for_cpu(dev, sg_dma_address(sg),
 						      sg->length, dir);
-	else if (!dev_is_dma_coherent(dev))
-		for_each_sg(sgl, sg, nelems, i)
+	} else if (!dev_is_dma_coherent(dev)) {
+		for_each_sg(sgl, sg, nelems, i) {
 			arch_sync_dma_for_cpu(sg_phys(sg), sg->length, dir);
+			arch_sync_dma_flush();
+		}
+	}
 }
 
 void iommu_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sgl,
@@ -1143,8 +1150,10 @@ void iommu_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sgl,
 							 sg_dma_address(sg),
 							 sg->length, dir);
 	else if (!dev_is_dma_coherent(dev))
-		for_each_sg(sgl, sg, nelems, i)
+		for_each_sg(sgl, sg, nelems, i) {
 			arch_sync_dma_for_device(sg_phys(sg), sg->length, dir);
+			arch_sync_dma_flush();
+		}
 }
 
 static phys_addr_t iommu_dma_map_swiotlb(struct device *dev, phys_addr_t phys,
@@ -1219,8 +1228,10 @@ dma_addr_t iommu_dma_map_phys(struct device *dev, phys_addr_t phys, size_t size,
 			return DMA_MAPPING_ERROR;
 	}
 
-	if (!coherent && !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO)))
+	if (!coherent && !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO))) {
 		arch_sync_dma_for_device(phys, size, dir);
+		arch_sync_dma_flush();
+	}
 
 	iova = __iommu_dma_map(dev, phys, size, prot, dma_mask);
 	if (iova == DMA_MAPPING_ERROR && !(attrs & DMA_ATTR_MMIO))
@@ -1242,8 +1253,10 @@ void iommu_dma_unmap_phys(struct device *dev, dma_addr_t dma_handle,
 	if (WARN_ON(!phys))
 		return;
 
-	if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) && !dev_is_dma_coherent(dev))
+	if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) && !dev_is_dma_coherent(dev)) {
 		arch_sync_dma_for_cpu(phys, size, dir);
+		arch_sync_dma_flush();
+	}
 
 	__iommu_dma_unmap(dev, dma_handle, size);
 
@@ -1836,8 +1849,10 @@ static int __dma_iova_link(struct device *dev, dma_addr_t addr,
 	bool coherent = dev_is_dma_coherent(dev);
 	int prot = dma_info_to_prot(dir, coherent, attrs);
 
-	if (!coherent && !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO)))
+	if (!coherent && !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO))) {
 		arch_sync_dma_for_device(phys, size, dir);
+		arch_sync_dma_flush();
+	}
 
 	return iommu_map_nosync(iommu_get_dma_domain(dev), addr, phys, size,
 			prot, GFP_ATOMIC);
@@ -2008,8 +2023,10 @@ static void iommu_dma_iova_unlink_range_slow(struct device *dev,
 			end - addr, iovad->granule - iova_start_pad);
 
 		if (!dev_is_dma_coherent(dev) &&
-		    !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO)))
+		    !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO))) {
 			arch_sync_dma_for_cpu(phys, len, dir);
+			arch_sync_dma_flush();
+		}
 
 		swiotlb_tbl_unmap_single(dev, phys, len, dir, attrs);
 
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
index ccf25027bec1..b79917e785a5 100644
--- a/drivers/xen/swiotlb-xen.c
+++ b/drivers/xen/swiotlb-xen.c
@@ -262,10 +262,12 @@ static dma_addr_t xen_swiotlb_map_phys(struct device *dev, phys_addr_t phys,
 
 done:
 	if (!dev_is_dma_coherent(dev) && !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) {
-		if (pfn_valid(PFN_DOWN(dma_to_phys(dev, dev_addr))))
+		if (pfn_valid(PFN_DOWN(dma_to_phys(dev, dev_addr)))) {
 			arch_sync_dma_for_device(phys, size, dir);
-		else
+			arch_sync_dma_flush();
+		} else {
 			xen_dma_sync_for_device(dev, dev_addr, size, dir);
+		}
 	}
 	return dev_addr;
 }
@@ -287,10 +289,12 @@ static void xen_swiotlb_unmap_phys(struct device *hwdev, dma_addr_t dev_addr,
 	BUG_ON(dir == DMA_NONE);
 
 	if (!dev_is_dma_coherent(hwdev) && !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) {
-		if (pfn_valid(PFN_DOWN(dma_to_phys(hwdev, dev_addr))))
+		if (pfn_valid(PFN_DOWN(dma_to_phys(hwdev, dev_addr)))) {
 			arch_sync_dma_for_cpu(paddr, size, dir);
-		else
+			arch_sync_dma_flush();
+		} else {
 			xen_dma_sync_for_cpu(hwdev, dev_addr, size, dir);
+		}
 	}
 
 	/* NOTE: We use dev_addr here, not paddr! */
@@ -308,10 +312,12 @@ xen_swiotlb_sync_single_for_cpu(struct device *dev, dma_addr_t dma_addr,
 	struct io_tlb_pool *pool;
 
 	if (!dev_is_dma_coherent(dev)) {
-		if (pfn_valid(PFN_DOWN(dma_to_phys(dev, dma_addr))))
+		if (pfn_valid(PFN_DOWN(dma_to_phys(dev, dma_addr)))) {
 			arch_sync_dma_for_cpu(paddr, size, dir);
-		else
+			arch_sync_dma_flush();
+		} else {
 			xen_dma_sync_for_cpu(dev, dma_addr, size, dir);
+		}
 	}
 
 	pool = xen_swiotlb_find_pool(dev, dma_addr);
@@ -331,10 +337,12 @@ xen_swiotlb_sync_single_for_device(struct device *dev, dma_addr_t dma_addr,
 		__swiotlb_sync_single_for_device(dev, paddr, size, dir, pool);
 
 	if (!dev_is_dma_coherent(dev)) {
-		if (pfn_valid(PFN_DOWN(dma_to_phys(dev, dma_addr))))
+		if (pfn_valid(PFN_DOWN(dma_to_phys(dev, dma_addr)))) {
 			arch_sync_dma_for_device(paddr, size, dir);
-		else
+			arch_sync_dma_flush();
+		} else {
 			xen_dma_sync_for_device(dev, dma_addr, size, dir);
+		}
 	}
 }
 
diff --git a/include/linux/dma-map-ops.h b/include/linux/dma-map-ops.h
index 4809204c674c..e7dd8a63b40e 100644
--- a/include/linux/dma-map-ops.h
+++ b/include/linux/dma-map-ops.h
@@ -361,6 +361,12 @@ static inline void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
 }
 #endif /* ARCH_HAS_SYNC_DMA_FOR_CPU */
 
+#ifndef arch_sync_dma_flush
+static inline void arch_sync_dma_flush(void)
+{
+}
+#endif
+
 #ifdef CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU_ALL
 void arch_sync_dma_for_cpu_all(void);
 #else
diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index 50c3fe2a1d55..a219911c7b90 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -402,9 +402,11 @@ void dma_direct_sync_sg_for_device(struct device *dev,
 
 		swiotlb_sync_single_for_device(dev, paddr, sg->length, dir);
 
-		if (!dev_is_dma_coherent(dev))
+		if (!dev_is_dma_coherent(dev)) {
 			arch_sync_dma_for_device(paddr, sg->length,
 					dir);
+			arch_sync_dma_flush();
+		}
 	}
 }
 #endif
@@ -421,8 +423,10 @@ void dma_direct_sync_sg_for_cpu(struct device *dev,
 	for_each_sg(sgl, sg, nents, i) {
 		phys_addr_t paddr = dma_to_phys(dev, sg_dma_address(sg));
 
-		if (!dev_is_dma_coherent(dev))
+		if (!dev_is_dma_coherent(dev)) {
 			arch_sync_dma_for_cpu(paddr, sg->length, dir);
+			arch_sync_dma_flush();
+		}
 
 		swiotlb_sync_single_for_cpu(dev, paddr, sg->length, dir);
 
diff --git a/kernel/dma/direct.h b/kernel/dma/direct.h
index da2fadf45bcd..a69326eed266 100644
--- a/kernel/dma/direct.h
+++ b/kernel/dma/direct.h
@@ -60,8 +60,10 @@ static inline void dma_direct_sync_single_for_device(struct device *dev,
 
 	swiotlb_sync_single_for_device(dev, paddr, size, dir);
 
-	if (!dev_is_dma_coherent(dev))
+	if (!dev_is_dma_coherent(dev)) {
 		arch_sync_dma_for_device(paddr, size, dir);
+		arch_sync_dma_flush();
+	}
 }
 
 static inline void dma_direct_sync_single_for_cpu(struct device *dev,
@@ -71,6 +73,7 @@ static inline void dma_direct_sync_single_for_cpu(struct device *dev,
 
 	if (!dev_is_dma_coherent(dev)) {
 		arch_sync_dma_for_cpu(paddr, size, dir);
+		arch_sync_dma_flush();
 		arch_sync_dma_for_cpu_all();
 	}
 
@@ -109,8 +112,10 @@ static inline dma_addr_t dma_direct_map_phys(struct device *dev,
 	}
 
 	if (!dev_is_dma_coherent(dev) &&
-	    !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO)))
+	    !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO))) {
 		arch_sync_dma_for_device(phys, size, dir);
+		arch_sync_dma_flush();
+	}
 	return dma_addr;
 
 err_overflow:
diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c
index a547c7693135..7cdbfcdfef86 100644
--- a/kernel/dma/swiotlb.c
+++ b/kernel/dma/swiotlb.c
@@ -1595,8 +1595,10 @@ dma_addr_t swiotlb_map(struct device *dev, phys_addr_t paddr, size_t size,
 		return DMA_MAPPING_ERROR;
 	}
 
-	if (!dev_is_dma_coherent(dev) && !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
+	if (!dev_is_dma_coherent(dev) && !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) {
 		arch_sync_dma_for_device(swiotlb_addr, size, dir);
+		arch_sync_dma_flush();
+	}
 	return dma_addr;
 }
 
-- 
2.43.0



From 21cnbao at gmail.com  Fri Dec 26 14:52:45 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Sat, 27 Dec 2025 11:52:45 +1300
Subject: [PATCH v2 5/8] dma-mapping: Support batch mode for dma_direct_sync_sg_for_*
In-Reply-To: <20251226225254.46197-1-21cnbao@gmail.com>
References: <20251226225254.46197-1-21cnbao@gmail.com>
Message-ID: <20251226225254.46197-6-21cnbao@gmail.com>

From: Barry Song <baohua at kernel.org>

Instead of performing a flush per SG entry, issue all cache
operations first and then flush once. This ultimately benefits
__dma_sync_sg_for_cpu() and __dma_sync_sg_for_device().

Cc: Leon Romanovsky <leon at kernel.org>
Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Will Deacon <will at kernel.org>
Cc: Marek Szyprowski <m.szyprowski at samsung.com>
Cc: Robin Murphy <robin.murphy at arm.com>
Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
Cc: Ard Biesheuvel <ardb at kernel.org>
Cc: Marc Zyngier <maz at kernel.org>
Cc: Anshuman Khandual <anshuman.khandual at arm.com>
Cc: Ryan Roberts <ryan.roberts at arm.com>
Cc: Suren Baghdasaryan <surenb at google.com>
Cc: Tangquan Zheng <zhengtangquan at oppo.com>
Signed-off-by: Barry Song <baohua at kernel.org>
---
 kernel/dma/direct.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index a219911c7b90..98bacf562ca1 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -402,12 +402,12 @@ void dma_direct_sync_sg_for_device(struct device *dev,
 
 		swiotlb_sync_single_for_device(dev, paddr, sg->length, dir);
 
-		if (!dev_is_dma_coherent(dev)) {
+		if (!dev_is_dma_coherent(dev))
 			arch_sync_dma_for_device(paddr, sg->length,
 					dir);
-			arch_sync_dma_flush();
-		}
 	}
+	if (!dev_is_dma_coherent(dev))
+		arch_sync_dma_flush();
 }
 #endif
 
@@ -423,10 +423,8 @@ void dma_direct_sync_sg_for_cpu(struct device *dev,
 	for_each_sg(sgl, sg, nents, i) {
 		phys_addr_t paddr = dma_to_phys(dev, sg_dma_address(sg));
 
-		if (!dev_is_dma_coherent(dev)) {
+		if (!dev_is_dma_coherent(dev))
 			arch_sync_dma_for_cpu(paddr, sg->length, dir);
-			arch_sync_dma_flush();
-		}
 
 		swiotlb_sync_single_for_cpu(dev, paddr, sg->length, dir);
 
@@ -434,8 +432,10 @@ void dma_direct_sync_sg_for_cpu(struct device *dev,
 			arch_dma_mark_clean(paddr, sg->length);
 	}
 
-	if (!dev_is_dma_coherent(dev))
+	if (!dev_is_dma_coherent(dev)) {
+		arch_sync_dma_flush();
 		arch_sync_dma_for_cpu_all();
+	}
 }
 
 /*
-- 
2.43.0



From 21cnbao at gmail.com  Fri Dec 26 14:52:46 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Sat, 27 Dec 2025 11:52:46 +1300
Subject: [PATCH v2 6/8] dma-mapping: Support batch mode for dma_direct_{map,unmap}_sg
In-Reply-To: <20251226225254.46197-1-21cnbao@gmail.com>
References: <20251226225254.46197-1-21cnbao@gmail.com>
Message-ID: <20251226225254.46197-7-21cnbao@gmail.com>

From: Barry Song <baohua at kernel.org>

Leon suggested extending a flush argument to
dma_direct_unmap_phys(), dma_direct_map_phys(), and
dma_direct_sync_single_for_cpu(). For single-buffer cases, this
would use flush=true, while for SG cases flush=false would be
used, followed by a single flush after all cache operations are
issued in dma_direct_{map,unmap}_sg().

This ultimately benefits dma_map_sg() and dma_unmap_sg().

Cc: Leon Romanovsky <leon at kernel.org>
Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Will Deacon <will at kernel.org>
Cc: Marek Szyprowski <m.szyprowski at samsung.com>
Cc: Robin Murphy <robin.murphy at arm.com>
Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
Cc: Ard Biesheuvel <ardb at kernel.org>
Cc: Marc Zyngier <maz at kernel.org>
Cc: Anshuman Khandual <anshuman.khandual at arm.com>
Cc: Ryan Roberts <ryan.roberts at arm.com>
Cc: Suren Baghdasaryan <surenb at google.com>
Cc: Tangquan Zheng <zhengtangquan at oppo.com>
Signed-off-by: Barry Song <baohua at kernel.org>
---
 kernel/dma/direct.c  | 17 +++++++++++++----
 kernel/dma/direct.h  | 16 ++++++++++------
 kernel/dma/mapping.c |  6 +++---
 3 files changed, 26 insertions(+), 13 deletions(-)

diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index 98bacf562ca1..550a1a13148d 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -447,14 +447,19 @@ void dma_direct_unmap_sg(struct device *dev, struct scatterlist *sgl,
 {
 	struct scatterlist *sg;
 	int i;
+	bool need_sync = false;
 
 	for_each_sg(sgl,  sg, nents, i) {
-		if (sg_dma_is_bus_address(sg))
+		if (sg_dma_is_bus_address(sg)) {
 			sg_dma_unmark_bus_address(sg);
-		else
+		} else {
+			need_sync = true;
 			dma_direct_unmap_phys(dev, sg->dma_address,
-					      sg_dma_len(sg), dir, attrs);
+					      sg_dma_len(sg), dir, attrs, false);
+		}
 	}
+	if (need_sync && !dev_is_dma_coherent(dev))
+		arch_sync_dma_flush();
 }
 #endif
 
@@ -464,6 +469,7 @@ int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
 	struct pci_p2pdma_map_state p2pdma_state = {};
 	struct scatterlist *sg;
 	int i, ret;
+	bool need_sync = false;
 
 	for_each_sg(sgl, sg, nents, i) {
 		switch (pci_p2pdma_state(&p2pdma_state, dev, sg_page(sg))) {
@@ -475,8 +481,9 @@ int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
 			 */
 			break;
 		case PCI_P2PDMA_MAP_NONE:
+			need_sync = true;
 			sg->dma_address = dma_direct_map_phys(dev, sg_phys(sg),
-					sg->length, dir, attrs);
+					sg->length, dir, attrs, false);
 			if (sg->dma_address == DMA_MAPPING_ERROR) {
 				ret = -EIO;
 				goto out_unmap;
@@ -495,6 +502,8 @@ int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
 		sg_dma_len(sg) = sg->length;
 	}
 
+	if (need_sync && !dev_is_dma_coherent(dev))
+		arch_sync_dma_flush();
 	return nents;
 
 out_unmap:
diff --git a/kernel/dma/direct.h b/kernel/dma/direct.h
index a69326eed266..d4ad79828090 100644
--- a/kernel/dma/direct.h
+++ b/kernel/dma/direct.h
@@ -67,13 +67,15 @@ static inline void dma_direct_sync_single_for_device(struct device *dev,
 }
 
 static inline void dma_direct_sync_single_for_cpu(struct device *dev,
-		dma_addr_t addr, size_t size, enum dma_data_direction dir)
+		dma_addr_t addr, size_t size, enum dma_data_direction dir,
+		bool flush)
 {
 	phys_addr_t paddr = dma_to_phys(dev, addr);
 
 	if (!dev_is_dma_coherent(dev)) {
 		arch_sync_dma_for_cpu(paddr, size, dir);
-		arch_sync_dma_flush();
+		if (flush)
+			arch_sync_dma_flush();
 		arch_sync_dma_for_cpu_all();
 	}
 
@@ -85,7 +87,7 @@ static inline void dma_direct_sync_single_for_cpu(struct device *dev,
 
 static inline dma_addr_t dma_direct_map_phys(struct device *dev,
 		phys_addr_t phys, size_t size, enum dma_data_direction dir,
-		unsigned long attrs)
+		unsigned long attrs, bool flush)
 {
 	dma_addr_t dma_addr;
 
@@ -114,7 +116,8 @@ static inline dma_addr_t dma_direct_map_phys(struct device *dev,
 	if (!dev_is_dma_coherent(dev) &&
 	    !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO))) {
 		arch_sync_dma_for_device(phys, size, dir);
-		arch_sync_dma_flush();
+		if (flush)
+			arch_sync_dma_flush();
 	}
 	return dma_addr;
 
@@ -127,7 +130,8 @@ static inline dma_addr_t dma_direct_map_phys(struct device *dev,
 }
 
 static inline void dma_direct_unmap_phys(struct device *dev, dma_addr_t addr,
-		size_t size, enum dma_data_direction dir, unsigned long attrs)
+		size_t size, enum dma_data_direction dir, unsigned long attrs,
+		bool flush)
 {
 	phys_addr_t phys;
 
@@ -137,7 +141,7 @@ static inline void dma_direct_unmap_phys(struct device *dev, dma_addr_t addr,
 
 	phys = dma_to_phys(dev, addr);
 	if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
-		dma_direct_sync_single_for_cpu(dev, addr, size, dir);
+		dma_direct_sync_single_for_cpu(dev, addr, size, dir, flush);
 
 	swiotlb_tbl_unmap_single(dev, phys, size, dir,
 					 attrs | DMA_ATTR_SKIP_CPU_SYNC);
diff --git a/kernel/dma/mapping.c b/kernel/dma/mapping.c
index 37163eb49f9f..d8cfa56a3cbb 100644
--- a/kernel/dma/mapping.c
+++ b/kernel/dma/mapping.c
@@ -166,7 +166,7 @@ dma_addr_t dma_map_phys(struct device *dev, phys_addr_t phys, size_t size,
 
 	if (dma_map_direct(dev, ops) ||
 	    (!is_mmio && arch_dma_map_phys_direct(dev, phys + size)))
-		addr = dma_direct_map_phys(dev, phys, size, dir, attrs);
+		addr = dma_direct_map_phys(dev, phys, size, dir, attrs, true);
 	else if (use_dma_iommu(dev))
 		addr = iommu_dma_map_phys(dev, phys, size, dir, attrs);
 	else if (ops->map_phys)
@@ -207,7 +207,7 @@ void dma_unmap_phys(struct device *dev, dma_addr_t addr, size_t size,
 	BUG_ON(!valid_dma_direction(dir));
 	if (dma_map_direct(dev, ops) ||
 	    (!is_mmio && arch_dma_unmap_phys_direct(dev, addr + size)))
-		dma_direct_unmap_phys(dev, addr, size, dir, attrs);
+		dma_direct_unmap_phys(dev, addr, size, dir, attrs, true);
 	else if (use_dma_iommu(dev))
 		iommu_dma_unmap_phys(dev, addr, size, dir, attrs);
 	else if (ops->unmap_phys)
@@ -373,7 +373,7 @@ void __dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr, size_t size,
 
 	BUG_ON(!valid_dma_direction(dir));
 	if (dma_map_direct(dev, ops))
-		dma_direct_sync_single_for_cpu(dev, addr, size, dir);
+		dma_direct_sync_single_for_cpu(dev, addr, size, dir, true);
 	else if (use_dma_iommu(dev))
 		iommu_dma_sync_single_for_cpu(dev, addr, size, dir);
 	else if (ops->sync_single_for_cpu)
-- 
2.43.0



From 21cnbao at gmail.com  Fri Dec 26 14:52:48 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Sat, 27 Dec 2025 11:52:48 +1300
Subject: [PATCH RFC v2 8/8] dma-iommu: Support DMA sync batch mode for iommu_dma_sync_sg_for_{cpu, device}
In-Reply-To: <20251226225254.46197-1-21cnbao@gmail.com>
References: <20251226225254.46197-1-21cnbao@gmail.com>
Message-ID: <20251226225254.46197-9-21cnbao@gmail.com>

From: Barry Song <baohua at kernel.org>

Apply batched DMA synchronization to iommu_dma_sync_sg_for_cpu() and
iommu_dma_sync_sg_for_device(). For all buffers in an SG list, only
a single flush operation is needed.

I do not have the hardware to test this, so the patch is marked as
RFC. I would greatly appreciate any testing feedback.

Cc: Leon Romanovsky <leon at kernel.org>
Cc: Marek Szyprowski <m.szyprowski at samsung.com>
Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Will Deacon <will at kernel.org>
Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
Cc: Ard Biesheuvel <ardb at kernel.org>
Cc: Marc Zyngier <maz at kernel.org>
Cc: Anshuman Khandual <anshuman.khandual at arm.com>
Cc: Ryan Roberts <ryan.roberts at arm.com>
Cc: Suren Baghdasaryan <surenb at google.com>
Cc: Robin Murphy <robin.murphy at arm.com>
Cc: Joerg Roedel <joro at 8bytes.org>
Cc: Tangquan Zheng <zhengtangquan at oppo.com>
Signed-off-by: Barry Song <baohua at kernel.org>
---
 drivers/iommu/dma-iommu.c | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index ffa940bdbbaf..b68dbfcb7846 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -1131,10 +1131,9 @@ void iommu_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl,
 			iommu_dma_sync_single_for_cpu(dev, sg_dma_address(sg),
 						      sg->length, dir);
 	} else if (!dev_is_dma_coherent(dev)) {
-		for_each_sg(sgl, sg, nelems, i) {
+		for_each_sg(sgl, sg, nelems, i)
 			arch_sync_dma_for_cpu(sg_phys(sg), sg->length, dir);
-			arch_sync_dma_flush();
-		}
+		arch_sync_dma_flush();
 	}
 }
 
@@ -1144,16 +1143,16 @@ void iommu_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sgl,
 	struct scatterlist *sg;
 	int i;
 
-	if (sg_dma_is_swiotlb(sgl))
+	if (sg_dma_is_swiotlb(sgl)) {
 		for_each_sg(sgl, sg, nelems, i)
 			iommu_dma_sync_single_for_device(dev,
 							 sg_dma_address(sg),
 							 sg->length, dir);
-	else if (!dev_is_dma_coherent(dev))
-		for_each_sg(sgl, sg, nelems, i) {
+	} else if (!dev_is_dma_coherent(dev)) {
+		for_each_sg(sgl, sg, nelems, i)
 			arch_sync_dma_for_device(sg_phys(sg), sg->length, dir);
-			arch_sync_dma_flush();
-		}
+		arch_sync_dma_flush();
+	}
 }
 
 static phys_addr_t iommu_dma_map_swiotlb(struct device *dev, phys_addr_t phys,
-- 
2.43.0



From 21cnbao at gmail.com  Fri Dec 26 14:52:47 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Sat, 27 Dec 2025 11:52:47 +1300
Subject: [PATCH RFC v2 7/8] dma-iommu: Support DMA sync batch mode for IOVA link and unlink
In-Reply-To: <20251226225254.46197-1-21cnbao@gmail.com>
References: <20251226225254.46197-1-21cnbao@gmail.com>
Message-ID: <20251226225254.46197-8-21cnbao@gmail.com>

From: Barry Song <baohua at kernel.org>

Apply batched DMA synchronization to __dma_iova_link() and
iommu_dma_iova_unlink_range_slow(). For multiple
sync_dma_for_device() and sync_dma_for_cpu() calls, we only
need to wait once for the completion of all sync operations,
rather than waiting for each one individually.

I do not have the hardware to test this, so it is marked as
RFC. I would greatly appreciate it if someone could test it.

Suggested-by: Marek Szyprowski <m.szyprowski at samsung.com>
Cc: Leon Romanovsky <leon at kernel.org>
Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Will Deacon <will at kernel.org>
Cc: Marek Szyprowski <m.szyprowski at samsung.com>
Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
Cc: Ard Biesheuvel <ardb at kernel.org>
Cc: Marc Zyngier <maz at kernel.org>
Cc: Anshuman Khandual <anshuman.khandual at arm.com>
Cc: Ryan Roberts <ryan.roberts at arm.com>
Cc: Suren Baghdasaryan <surenb at google.com>
Cc: Robin Murphy <robin.murphy at arm.com>
Cc: Joerg Roedel <joro at 8bytes.org>
Cc: Tangquan Zheng <zhengtangquan at oppo.com>
Signed-off-by: Barry Song <baohua at kernel.org>
---
 drivers/iommu/dma-iommu.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 6827763a3877..ffa940bdbbaf 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -1849,10 +1849,8 @@ static int __dma_iova_link(struct device *dev, dma_addr_t addr,
 	bool coherent = dev_is_dma_coherent(dev);
 	int prot = dma_info_to_prot(dir, coherent, attrs);
 
-	if (!coherent && !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO))) {
+	if (!coherent && !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO)))
 		arch_sync_dma_for_device(phys, size, dir);
-		arch_sync_dma_flush();
-	}
 
 	return iommu_map_nosync(iommu_get_dma_domain(dev), addr, phys, size,
 			prot, GFP_ATOMIC);
@@ -1995,6 +1993,8 @@ int dma_iova_sync(struct device *dev, struct dma_iova_state *state,
 	dma_addr_t addr = state->addr + offset;
 	size_t iova_start_pad = iova_offset(iovad, addr);
 
+	if (!dev_is_dma_coherent(dev))
+		arch_sync_dma_flush();
 	return iommu_sync_map(domain, addr - iova_start_pad,
 		      iova_align(iovad, size + iova_start_pad));
 }
@@ -2008,6 +2008,8 @@ static void iommu_dma_iova_unlink_range_slow(struct device *dev,
 	struct iommu_dma_cookie *cookie = domain->iova_cookie;
 	struct iova_domain *iovad = &cookie->iovad;
 	size_t iova_start_pad = iova_offset(iovad, addr);
+	bool need_sync_dma = !dev_is_dma_coherent(dev) &&
+			!(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO));
 	dma_addr_t end = addr + size;
 
 	do {
@@ -2023,16 +2025,17 @@ static void iommu_dma_iova_unlink_range_slow(struct device *dev,
 			end - addr, iovad->granule - iova_start_pad);
 
 		if (!dev_is_dma_coherent(dev) &&
-		    !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO))) {
+		    !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO)))
 			arch_sync_dma_for_cpu(phys, len, dir);
-			arch_sync_dma_flush();
-		}
 
 		swiotlb_tbl_unmap_single(dev, phys, len, dir, attrs);
 
 		addr += len;
 		iova_start_pad = 0;
 	} while (addr < end);
+
+	if (need_sync_dma)
+		arch_sync_dma_flush();
 }
 
 static void __iommu_dma_iova_unlink(struct device *dev,
-- 
2.43.0



From llong at redhat.com  Fri Dec 26 15:08:43 2025
From: llong at redhat.com (Waiman Long)
Date: Fri, 26 Dec 2025 18:08:43 -0500
Subject: [PATCH 28/33] sched: Switch the fallback task allowed cpumask to
 HK_TYPE_DOMAIN
In-Reply-To: <20251224134520.33231-29-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-29-frederic@kernel.org>
Message-ID: <2f892ef9-1965-486d-beab-eacf0b6b0386@redhat.com>

On 12/24/25 8:45 AM, Frederic Weisbecker wrote:
> Tasks that have all their allowed CPUs offline don't want their affinity
> to fallback on either nohz_full CPUs or on domain isolated CPUs. And
> since nohz_full implies domain isolation, checking the latter is enough
> to verify both.
>
> Therefore exclude domain isolation from fallback task affinity.
>
> Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
> ---
>   include/linux/mmu_context.h | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/include/linux/mmu_context.h b/include/linux/mmu_context.h
> index ac01dc4eb2ce..ed3dd0f3fe19 100644
> --- a/include/linux/mmu_context.h
> +++ b/include/linux/mmu_context.h
> @@ -24,7 +24,7 @@ static inline void leave_mm(void) { }
>   #ifndef task_cpu_possible_mask
>   # define task_cpu_possible_mask(p)	cpu_possible_mask
>   # define task_cpu_possible(cpu, p)	true
> -# define task_cpu_fallback_mask(p)	housekeeping_cpumask(HK_TYPE_TICK)
> +# define task_cpu_fallback_mask(p)	housekeeping_cpumask(HK_TYPE_DOMAIN)
>   #else
>   # define task_cpu_possible(cpu, p)	cpumask_test_cpu((cpu), task_cpu_possible_mask(p))
>   #endif
Acked-by: Waiman Long <longman at redhat.com>



From llong at redhat.com  Fri Dec 26 15:46:02 2025
From: llong at redhat.com (Waiman Long)
Date: Fri, 26 Dec 2025 18:46:02 -0500
Subject: [PATCH 29/33] sched/arm64: Move fallback task cpumask to
 HK_TYPE_DOMAIN
In-Reply-To: <20251224134520.33231-30-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-30-frederic@kernel.org>
Message-ID: <19b001a4-0696-4efd-aaa3-902ffa42ff9e@redhat.com>

On 12/24/25 8:45 AM, Frederic Weisbecker wrote:
> When none of the allowed CPUs of a task are online, it gets migrated
> to the fallback cpumask which is all the non nohz_full CPUs.
>
> However just like nohz_full CPUs, domain isolated CPUs don't want to be
> disturbed by tasks that have lost their CPU affinities.
>
> And since nohz_full rely on domain isolation to work correctly, the
> housekeeping mask of domain isolated CPUs should always be a superset of
> the housekeeping mask of nohz_full CPUs (there can be CPUs that are
> domain isolated but not nohz_full, OTOH there shouldn't be nohz_full
> CPUs that are not domain isolated):
>
> 	HK_TYPE_DOMAIN | HK_TYPE_KERNEL_NOISE == HK_TYPE_DOMAIN
>
> Therefore use HK_TYPE_DOMAIN as the appropriate fallback target for
> tasks and since this cpumask can be modified at runtime, make sure
> that 32 bits support CPUs on ARM64 mismatched systems are not isolated
> by cpusets.
>
> Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
> ---
>   arch/arm64/kernel/cpufeature.c | 18 +++++++++++++++---
>   include/linux/cpu.h            |  4 ++++
>   kernel/cgroup/cpuset.c         | 17 ++++++++++++++---
>   3 files changed, 33 insertions(+), 6 deletions(-)
>
> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
> index c840a93b9ef9..70b0e45e299a 100644
> --- a/arch/arm64/kernel/cpufeature.c
> +++ b/arch/arm64/kernel/cpufeature.c
> @@ -1656,6 +1656,18 @@ has_cpuid_feature(const struct arm64_cpu_capabilities *entry, int scope)
>   	return feature_matches(val, entry);
>   }
>   
> +/*
> + * 32 bits support CPUs can't be isolated because tasks may be
> + * arbitrarily affine to them, defeating the purpose of isolation.
> + */
> +bool arch_isolated_cpus_can_update(struct cpumask *new_cpus)
> +{
> +	if (static_branch_unlikely(&arm64_mismatched_32bit_el0))
> +		return !cpumask_intersects(cpu_32bit_el0_mask, new_cpus);
> +	else
> +		return true;
> +}
> +
>   const struct cpumask *system_32bit_el0_cpumask(void)
>   {
>   	if (!system_supports_32bit_el0())
> @@ -1669,7 +1681,7 @@ const struct cpumask *system_32bit_el0_cpumask(void)
>   
>   const struct cpumask *task_cpu_fallback_mask(struct task_struct *p)
>   {
> -	return __task_cpu_possible_mask(p, housekeeping_cpumask(HK_TYPE_TICK));
> +	return __task_cpu_possible_mask(p, housekeeping_cpumask(HK_TYPE_DOMAIN));
>   }
>   
>   static int __init parse_32bit_el0_param(char *str)
> @@ -3987,8 +3999,8 @@ static int enable_mismatched_32bit_el0(unsigned int cpu)
>   	bool cpu_32bit = false;
>   
>   	if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) {
> -		if (!housekeeping_cpu(cpu, HK_TYPE_TICK))
> -			pr_info("Treating adaptive-ticks CPU %u as 64-bit only\n", cpu);
> +		if (!housekeeping_cpu(cpu, HK_TYPE_DOMAIN))
> +			pr_info("Treating domain isolated CPU %u as 64-bit only\n", cpu);
>   		else
>   			cpu_32bit = true;
>   	}
> diff --git a/include/linux/cpu.h b/include/linux/cpu.h
> index 487b3bf2e1ea..0b48af25ab5c 100644
> --- a/include/linux/cpu.h
> +++ b/include/linux/cpu.h
> @@ -229,4 +229,8 @@ static inline bool cpu_attack_vector_mitigated(enum cpu_attack_vectors v)
>   #define smt_mitigations SMT_MITIGATIONS_OFF
>   #endif
>   
> +struct cpumask;
> +
> +bool arch_isolated_cpus_can_update(struct cpumask *new_cpus);
> +
>   #endif /* _LINUX_CPU_H_ */
> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> index cd6119c02beb..1cc83a3c25f6 100644
> --- a/kernel/cgroup/cpuset.c
> +++ b/kernel/cgroup/cpuset.c
> @@ -1408,14 +1408,22 @@ static void partition_xcpus_del(int old_prs, struct cpuset *parent,
>   	cpumask_or(parent->effective_cpus, parent->effective_cpus, xcpus);
>   }
>   
> +bool __weak arch_isolated_cpus_can_update(struct cpumask *new_cpus)
> +{
> +	return true;
> +}
> +
>   /*
> - * isolated_cpus_can_update - check for isolated & nohz_full conflicts
> + * isolated_cpus_can_update - check for conflicts against housekeeping and
> + *                            CPUs capabilities.
>    * @add_cpus: cpu mask for cpus that are going to be isolated
>    * @del_cpus: cpu mask for cpus that are no longer isolated, can be NULL
>    * Return: false if there is conflict, true otherwise
>    *
> - * If nohz_full is enabled and we have isolated CPUs, their combination must
> - * still leave housekeeping CPUs.
> + * Check for conflicts:
> + * - If nohz_full is enabled and there are isolated CPUs, their combination must
> + *   still leave housekeeping CPUs.
> + * - Architecture has CPU capabilities incompatible with being isolated
>    *
>    * TBD: Should consider merging this function into
>    *      prstate_housekeeping_conflict().
> @@ -1426,6 +1434,9 @@ static bool isolated_cpus_can_update(struct cpumask *add_cpus,
>   	cpumask_var_t full_hk_cpus;
>   	int res = true;
>   
> +	if (!arch_isolated_cpus_can_update(add_cpus))
> +		return false;
> +
>   	if (!housekeeping_enabled(HK_TYPE_KERNEL_NOISE))
>   		return true;
>   
Reviewed-by: Waiman Long <longman at redhat.com>



From tj at kernel.org  Fri Dec 26 15:56:50 2025
From: tj at kernel.org (Tejun Heo)
Date: Fri, 26 Dec 2025 13:56:50 -1000
Subject: [PATCH 03/33] memcg: Prepare to protect against concurrent
 isolated cpuset change
In-Reply-To: <20251224134520.33231-4-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-4-frederic@kernel.org>
Message-ID: <aU8gwjlVmRkMtPZT@slm.duckdns.org>

On Wed, Dec 24, 2025 at 02:44:50PM +0100, Frederic Weisbecker wrote:
> +static void schedule_drain_work(int cpu, struct work_struct *work)
> +{
> +	guard(rcu)();
> +	if (!cpu_is_isolated(cpu))
> +		schedule_work_on(cpu, work);
> +}

As the sync rules aren't trivial, it'd be nice to have some comment
explaining what's going on.

Thanks.

-- 
tejun


From llong at redhat.com  Fri Dec 26 15:59:34 2025
From: llong at redhat.com (Waiman Long)
Date: Fri, 26 Dec 2025 18:59:34 -0500
Subject: [PATCH 30/33] kthread: Honour kthreads preferred affinity after
 cpuset changes
In-Reply-To: <20251224134520.33231-31-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-31-frederic@kernel.org>
Message-ID: <a8968902-7fc3-4dec-9a53-e9685a5705b9@redhat.com>

On 12/24/25 8:45 AM, Frederic Weisbecker wrote:
> When cpuset isolated partitions get updated, unbound kthreads get
> indifferently affine to all non isolated CPUs, regardless of their
> individual affinity preferences.
>
> For example kswapd is a per-node kthread that prefers to be affine to
> the node it refers to. Whenever an isolated partition is created,
> updated or deleted, kswapd's node affinity is going to be broken if any
> CPU in the related node is not isolated because kswapd will be affine
> globally.
>
> Fix this with letting the consolidated kthread managed affinity code do
> the affinity update on behalf of cpuset.
>
> Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
> ---
>   include/linux/kthread.h  |  1 +
>   kernel/cgroup/cpuset.c   |  5 ++---
>   kernel/kthread.c         | 41 ++++++++++++++++++++++++++++++----------
>   kernel/sched/isolation.c |  3 +++
>   4 files changed, 37 insertions(+), 13 deletions(-)
>
> diff --git a/include/linux/kthread.h b/include/linux/kthread.h
> index 8d27403888ce..c92c1149ee6e 100644
> --- a/include/linux/kthread.h
> +++ b/include/linux/kthread.h
> @@ -100,6 +100,7 @@ void kthread_unpark(struct task_struct *k);
>   void kthread_parkme(void);
>   void kthread_exit(long result) __noreturn;
>   void kthread_complete_and_exit(struct completion *, long) __noreturn;
> +int kthreads_update_housekeeping(void);
>   
>   int kthreadd(void *unused);
>   extern struct task_struct *kthreadd_task;
> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> index 1cc83a3c25f6..c8cfaf5cd4a1 100644
> --- a/kernel/cgroup/cpuset.c
> +++ b/kernel/cgroup/cpuset.c
> @@ -1208,11 +1208,10 @@ void cpuset_update_tasks_cpumask(struct cpuset *cs, struct cpumask *new_cpus)
>   
>   		if (top_cs) {
>   			/*
> +			 * PF_KTHREAD tasks are handled by housekeeping.
>   			 * PF_NO_SETAFFINITY tasks are ignored.
> -			 * All per cpu kthreads should have PF_NO_SETAFFINITY
> -			 * flag set, see kthread_set_per_cpu().
>   			 */
> -			if (task->flags & PF_NO_SETAFFINITY)
> +			if (task->flags & (PF_KTHREAD | PF_NO_SETAFFINITY))
>   				continue;
>   			cpumask_andnot(new_cpus, possible_mask, subpartitions_cpus);
>   		} else {
> diff --git a/kernel/kthread.c b/kernel/kthread.c
> index 968fa5868d21..03008154249c 100644
> --- a/kernel/kthread.c
> +++ b/kernel/kthread.c
> @@ -891,14 +891,7 @@ int kthread_affine_preferred(struct task_struct *p, const struct cpumask *mask)
>   }
>   EXPORT_SYMBOL_GPL(kthread_affine_preferred);
>   
> -/*
> - * Re-affine kthreads according to their preferences
> - * and the newly online CPU. The CPU down part is handled
> - * by select_fallback_rq() which default re-affines to
> - * housekeepers from other nodes in case the preferred
> - * affinity doesn't apply anymore.
> - */
> -static int kthreads_online_cpu(unsigned int cpu)
> +static int kthreads_update_affinity(bool force)
>   {
>   	cpumask_var_t affinity;
>   	struct kthread *k;
> @@ -924,7 +917,8 @@ static int kthreads_online_cpu(unsigned int cpu)
>   		/*
>   		 * Unbound kthreads without preferred affinity are already affine
>   		 * to housekeeping, whether those CPUs are online or not. So no need
> -		 * to handle newly online CPUs for them.
> +		 * to handle newly online CPUs for them. However housekeeping changes
> +		 * have to be applied.
>   		 *
>   		 * But kthreads with a preferred affinity or node are different:
>   		 * if none of their preferred CPUs are online and part of
> @@ -932,7 +926,7 @@ static int kthreads_online_cpu(unsigned int cpu)
>   		 * But as soon as one of their preferred CPU becomes online, they must
>   		 * be affine to them.
>   		 */
> -		if (k->preferred_affinity || k->node != NUMA_NO_NODE) {
> +		if (force || k->preferred_affinity || k->node != NUMA_NO_NODE) {
>   			kthread_fetch_affinity(k, affinity);
>   			set_cpus_allowed_ptr(k->task, affinity);
>   		}
> @@ -943,6 +937,33 @@ static int kthreads_online_cpu(unsigned int cpu)
>   	return ret;
>   }
>   
> +/**
> + * kthreads_update_housekeeping - Update kthreads affinity on cpuset change
> + *
> + * When cpuset changes a partition type to/from "isolated" or updates related
> + * cpumasks, propagate the housekeeping cpumask change to preferred kthreads
> + * affinity.
> + *
> + * Returns 0 if successful, -ENOMEM if temporary mask couldn't
> + * be allocated or -EINVAL in case of internal error.
> + */
> +int kthreads_update_housekeeping(void)
> +{
> +	return kthreads_update_affinity(true);
> +}
> +
> +/*
> + * Re-affine kthreads according to their preferences
> + * and the newly online CPU. The CPU down part is handled
> + * by select_fallback_rq() which default re-affines to
> + * housekeepers from other nodes in case the preferred
> + * affinity doesn't apply anymore.
> + */
> +static int kthreads_online_cpu(unsigned int cpu)
> +{
> +	return kthreads_update_affinity(false);
> +}
> +
>   static int kthreads_init(void)
>   {
>   	return cpuhp_setup_state(CPUHP_AP_KTHREADS_ONLINE, "kthreads:online",
> diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c
> index 84a257d05918..c499474866b8 100644
> --- a/kernel/sched/isolation.c
> +++ b/kernel/sched/isolation.c
> @@ -157,6 +157,9 @@ int housekeeping_update(struct cpumask *isol_mask, enum hk_type type)
>   	err = tmigr_isolated_exclude_cpumask(isol_mask);
>   	WARN_ON_ONCE(err < 0);
>   
> +	err = kthreads_update_housekeeping();
> +	WARN_ON_ONCE(err < 0);
> +
>   	kfree(old);
>   
>   	return err;
Reviewed-by: Waiman Long <longman at redhat.com>



From devnull+amitsd.google.com at kernel.org  Fri Dec 26 16:04:22 2025
From: devnull+amitsd.google.com at kernel.org (Amit Sunil Dhamne via B4 Relay)
Date: Sat, 27 Dec 2025 00:04:22 +0000
Subject: [PATCH v3 2/5] dt-bindings: usb: maxim,max33359: Add supply
 property for vbus
In-Reply-To: <20251227-max77759-charger-v3-0-54e664f5ca92@google.com>
References: <20251227-max77759-charger-v3-0-54e664f5ca92@google.com>
Message-ID: <20251227-max77759-charger-v3-2-54e664f5ca92@google.com>

From: Amit Sunil Dhamne <amitsd at google.com>

Add a regulator supply property for vbus. This notifies the regulator
provider to source vbus when Type-C operates in Source power mode,
while turn off sourcing vbus when operating in Sink mode or
disconnected.

Signed-off-by: Amit Sunil Dhamne <amitsd at google.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 Documentation/devicetree/bindings/usb/maxim,max33359.yaml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/usb/maxim,max33359.yaml b/Documentation/devicetree/bindings/usb/maxim,max33359.yaml
index 3de4dc40b791..e652a24902ea 100644
--- a/Documentation/devicetree/bindings/usb/maxim,max33359.yaml
+++ b/Documentation/devicetree/bindings/usb/maxim,max33359.yaml
@@ -32,6 +32,9 @@ properties:
     description:
       Properties for usb c connector.
 
+  vbus-supply:
+    description: Regulator to control sourcing Vbus.
+
 required:
   - compatible
   - reg
@@ -53,6 +56,7 @@ examples:
             reg = <0x25>;
             interrupt-parent = <&gpa8>;
             interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+            vbus-supply = <&chgin_otg_reg>;
 
             connector {
                 compatible = "usb-c-connector";

-- 
2.52.0.351.gbe84eed79e-goog




From devnull+amitsd.google.com at kernel.org  Fri Dec 26 16:04:21 2025
From: devnull+amitsd.google.com at kernel.org (Amit Sunil Dhamne via B4 Relay)
Date: Sat, 27 Dec 2025 00:04:21 +0000
Subject: [PATCH v3 1/5] dt-bindings: mfd: maxim,max77759: reference
 power-supply schema and add regulator property
In-Reply-To: <20251227-max77759-charger-v3-0-54e664f5ca92@google.com>
References: <20251227-max77759-charger-v3-0-54e664f5ca92@google.com>
Message-ID: <20251227-max77759-charger-v3-1-54e664f5ca92@google.com>

From: Amit Sunil Dhamne <amitsd at google.com>

Extend the max77759 binding to reference power-supply schema, so that
PMIC node can reference its supplier. Also, add regulator property to
control CHGIN (OTG) voltage.

Signed-off-by: Amit Sunil Dhamne <amitsd at google.com>
---
 .../devicetree/bindings/mfd/maxim,max77759.yaml          | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml b/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml
index 525de9ab3c2b..42e4a84d5204 100644
--- a/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml
+++ b/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml
@@ -16,6 +16,9 @@ description: |
   The MAX77759 includes Battery Charger, Fuel Gauge, temperature sensors, USB
   Type-C Port Controller (TCPC), NVMEM, and a GPIO expander.
 
+allOf:
+  - $ref: /schemas/power/supply/power-supply.yaml#
+
 properties:
   compatible:
     const: maxim,max77759
@@ -37,12 +40,18 @@ properties:
   nvmem-0:
     $ref: /schemas/nvmem/maxim,max77759-nvmem.yaml
 
+  chgin-otg-regulator:
+    type: object
+    description: Provides Boost for sourcing VBUS.
+    $ref: /schemas/regulator/regulator.yaml#
+    unevaluatedProperties: false
+
 required:
   - compatible
   - interrupts
   - reg
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
@@ -59,6 +68,11 @@ examples:
 
             interrupt-controller;
             #interrupt-cells = <2>;
+            power-supplies = <&maxtcpci>;
+
+            chgin-otg-regulator {
+                regulator-name = "chgin-otg";
+            };
 
             gpio {
                 compatible = "maxim,max77759-gpio";

-- 
2.52.0.351.gbe84eed79e-goog




From devnull+amitsd.google.com at kernel.org  Fri Dec 26 16:04:20 2025
From: devnull+amitsd.google.com at kernel.org (Amit Sunil Dhamne via B4 Relay)
Date: Sat, 27 Dec 2025 00:04:20 +0000
Subject: [PATCH v3 0/5] Introduce MAX77759 charger driver
Message-ID: <20251227-max77759-charger-v3-0-54e664f5ca92@google.com>

MAX77759 PMIC is used in Pixel 6 and 6 Pro (Oriole/Raven) boards.
One of the functions of the MAX77759 PMIC is a battery charger. This
patchset introduces a driver for this function. One of the unique
features of this charger driver is that it works with a USB input where
the Type-C controller is TCPCI based.

Changes to the board files will follow soon once this patchset is reviewed.

For reference to the MAX77759 MFD based patchset (present in upstream):
https://lore.kernel.org/all/20250509-max77759-mfd-v10-0-962ac15ee3ef at linaro.org/

Signed-off-by: Amit Sunil Dhamne <amitsd at google.com>
---
Changes in v3:
- Had incorrectly folded the charger sub-device with the pmic parent.
  Corrected it. (Krzysztof Kozlowski)
- Link to v2: https://lore.kernel.org/r/20251218-max77759-charger-v2-0-2b259980a686 at google.com

Changes in v2:
- Fold charger binding in maxim,max77759-charger.yaml to its parent
  node. (Krzysztof Kozlowski)
- Renamed regulator supplier & consumer. (Krzysztof Kozlowski & Heikki
  Krogerus)
- Removed explicit setting of irq trigger types in max77759 driver.
  (Andr? Draszik & Krzysztof Kozlowski)
- Complete bit definitions for IRQ registers. (Andr? Draszik)
- Consolidate all bit definitions for charger IP in mfd/max77759.h.
  (Andr? Draszik)
- Modify the handling of charger IRQs such that regmap IRQ chip handles
  masking, de-mux and acking of interrupts. (Andr? Draszik)
- Remove unused macro definitions relating to Charger modes in tcpci
  maxim driver (Andr? Draszik)
- Add dependency on Regulator class in Kconfig definition for max77759
  chg. (Kernel Test Robot)
- Link to v1: https://lore.kernel.org/r/20251123-max77759-charger-v1-0-6b2e4b8f7f54 at google.com

---
Amit Sunil Dhamne (5):
      dt-bindings: mfd: maxim,max77759: reference power-supply schema and add regulator property
      dt-bindings: usb: maxim,max33359: Add supply property for vbus
      mfd: max77759: add register bitmasks and modify irq configs for charger
      power: supply: max77759: add charger driver
      usb: typec: tcpm/tcpci_maxim: deprecate WAR for setting charger mode

 .../devicetree/bindings/mfd/maxim,max77759.yaml    |  16 +-
 .../devicetree/bindings/usb/maxim,max33359.yaml    |   4 +
 MAINTAINERS                                        |   6 +
 drivers/mfd/max77759.c                             |  91 ++-
 drivers/power/supply/Kconfig                       |  11 +
 drivers/power/supply/Makefile                      |   1 +
 drivers/power/supply/max77759_charger.c            | 764 +++++++++++++++++++++
 drivers/usb/typec/tcpm/tcpci_maxim.h               |   1 +
 drivers/usb/typec/tcpm/tcpci_maxim_core.c          |  54 +-
 include/linux/mfd/max77759.h                       | 202 +++++-
 10 files changed, 1091 insertions(+), 59 deletions(-)
---
base-commit: dd9b004b7ff3289fb7bae35130c0a5c0537266af
change-id: 20251105-max77759-charger-852b626d661a

Best regards,
-- 
Amit Sunil Dhamne <amitsd at google.com>




From devnull+amitsd.google.com at kernel.org  Fri Dec 26 16:04:25 2025
From: devnull+amitsd.google.com at kernel.org (Amit Sunil Dhamne via B4 Relay)
Date: Sat, 27 Dec 2025 00:04:25 +0000
Subject: [PATCH v3 5/5] usb: typec: tcpm/tcpci_maxim: deprecate WAR for
 setting charger mode
In-Reply-To: <20251227-max77759-charger-v3-0-54e664f5ca92@google.com>
References: <20251227-max77759-charger-v3-0-54e664f5ca92@google.com>
Message-ID: <20251227-max77759-charger-v3-5-54e664f5ca92@google.com>

From: Amit Sunil Dhamne <amitsd at google.com>

TCPCI maxim driver directly writes to the charger's register space to
set charger mode depending on the power role. As MAX77759 chg driver
exists, this WAR is not required.

Instead, use a regulator interface to source vbus when typec is in
source power mode. In other power modes, this regulator will be turned
off if active.

Signed-off-by: Amit Sunil Dhamne <amitsd at google.com>
---
 drivers/usb/typec/tcpm/tcpci_maxim.h      |  1 +
 drivers/usb/typec/tcpm/tcpci_maxim_core.c | 54 +++++++++++++++++++------------
 2 files changed, 34 insertions(+), 21 deletions(-)

diff --git a/drivers/usb/typec/tcpm/tcpci_maxim.h b/drivers/usb/typec/tcpm/tcpci_maxim.h
index b33540a42a95..b314606eb0f6 100644
--- a/drivers/usb/typec/tcpm/tcpci_maxim.h
+++ b/drivers/usb/typec/tcpm/tcpci_maxim.h
@@ -60,6 +60,7 @@ struct max_tcpci_chip {
 	struct tcpm_port *port;
 	enum contamiant_state contaminant_state;
 	bool veto_vconn_swap;
+	struct regulator *vbus_reg;
 };
 
 static inline int max_tcpci_read16(struct max_tcpci_chip *chip, unsigned int reg, u16 *val)
diff --git a/drivers/usb/typec/tcpm/tcpci_maxim_core.c b/drivers/usb/typec/tcpm/tcpci_maxim_core.c
index 19f638650796..e9e2405c5ca0 100644
--- a/drivers/usb/typec/tcpm/tcpci_maxim_core.c
+++ b/drivers/usb/typec/tcpm/tcpci_maxim_core.c
@@ -10,6 +10,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
 #include <linux/usb/pd.h>
 #include <linux/usb/tcpci.h>
 #include <linux/usb/tcpm.h>
@@ -35,12 +36,6 @@
  */
 #define TCPC_RECEIVE_BUFFER_LEN				32
 
-#define MAX_BUCK_BOOST_SID				0x69
-#define MAX_BUCK_BOOST_OP				0xb9
-#define MAX_BUCK_BOOST_OFF				0
-#define MAX_BUCK_BOOST_SOURCE				0xa
-#define MAX_BUCK_BOOST_SINK				0x5
-
 static const struct regmap_range max_tcpci_tcpci_range[] = {
 	regmap_reg_range(0x00, 0x95)
 };
@@ -202,32 +197,49 @@ static void process_rx(struct max_tcpci_chip *chip, u16 status)
 	tcpm_pd_receive(chip->port, &msg, rx_type);
 }
 
+static int get_vbus_regulator_handle(struct max_tcpci_chip *chip)
+{
+	if (IS_ERR_OR_NULL(chip->vbus_reg)) {
+		chip->vbus_reg = devm_regulator_get_exclusive(chip->dev,
+							      "vbus");
+		if (IS_ERR_OR_NULL(chip->vbus_reg)) {
+			dev_err(chip->dev,
+				"Failed to get vbus regulator handle");
+			return -ENODEV;
+		}
+	}
+
+	return 0;
+}
+
 static int max_tcpci_set_vbus(struct tcpci *tcpci, struct tcpci_data *tdata, bool source, bool sink)
 {
 	struct max_tcpci_chip *chip = tdata_to_max_tcpci(tdata);
-	u8 buffer_source[2] = {MAX_BUCK_BOOST_OP, MAX_BUCK_BOOST_SOURCE};
-	u8 buffer_sink[2] = {MAX_BUCK_BOOST_OP, MAX_BUCK_BOOST_SINK};
-	u8 buffer_none[2] = {MAX_BUCK_BOOST_OP, MAX_BUCK_BOOST_OFF};
-	struct i2c_client *i2c = chip->client;
 	int ret;
 
-	struct i2c_msg msgs[] = {
-		{
-			.addr = MAX_BUCK_BOOST_SID,
-			.flags = i2c->flags & I2C_M_TEN,
-			.len = 2,
-			.buf = source ? buffer_source : sink ? buffer_sink : buffer_none,
-		},
-	};
-
 	if (source && sink) {
 		dev_err(chip->dev, "Both source and sink set\n");
 		return -EINVAL;
 	}
 
-	ret = i2c_transfer(i2c->adapter, msgs, 1);
+	ret = get_vbus_regulator_handle(chip);
+	if (ret) {
+		/*
+		 * Regulator is not necessary for sink only applications. Return
+		 * success in cases where sink mode is being modified.
+		 */
+		return source ? ret : 1;
+	}
+
+	if (source) {
+		if (!regulator_is_enabled(chip->vbus_reg))
+			ret = regulator_enable(chip->vbus_reg);
+	} else {
+		if (regulator_is_enabled(chip->vbus_reg))
+			ret = regulator_disable(chip->vbus_reg);
+	}
 
-	return  ret < 0 ? ret : 1;
+	return ret < 0 ? ret : 1;
 }
 
 static void process_power_status(struct max_tcpci_chip *chip)

-- 
2.52.0.351.gbe84eed79e-goog




From devnull+amitsd.google.com at kernel.org  Fri Dec 26 16:04:23 2025
From: devnull+amitsd.google.com at kernel.org (Amit Sunil Dhamne via B4 Relay)
Date: Sat, 27 Dec 2025 00:04:23 +0000
Subject: [PATCH v3 3/5] mfd: max77759: add register bitmasks and modify irq
 configs for charger
In-Reply-To: <20251227-max77759-charger-v3-0-54e664f5ca92@google.com>
References: <20251227-max77759-charger-v3-0-54e664f5ca92@google.com>
Message-ID: <20251227-max77759-charger-v3-3-54e664f5ca92@google.com>

From: Amit Sunil Dhamne <amitsd at google.com>

Add register bitmasks for charger function.
In addition split the charger IRQs further such that each bit represents
an IRQ downstream of charger regmap irq chip. In addition populate the
ack_base to offload irq ack to the regmap irq chip framework.

Signed-off-by: Amit Sunil Dhamne <amitsd at google.com>
---
 drivers/mfd/max77759.c       |  91 +++++++++++++++++--
 include/linux/mfd/max77759.h | 202 ++++++++++++++++++++++++++++++++++++-------
 2 files changed, 256 insertions(+), 37 deletions(-)

diff --git a/drivers/mfd/max77759.c b/drivers/mfd/max77759.c
index 6cf6306c4a3b..a5f7da003edd 100644
--- a/drivers/mfd/max77759.c
+++ b/drivers/mfd/max77759.c
@@ -201,8 +201,24 @@ static const struct regmap_config max77759_regmap_config_charger = {
  *         - SYSUVLO_INT
  *         - FSHIP_NOT_RD
  *     - CHGR_INT: charger
- *       - CHG_INT
- *       - CHG_INT2
+ *       - INT1
+ *         - AICL
+ *         - CHGIN
+ *         - WCIN
+ *         - CHG
+ *         - BAT
+ *         - INLIM
+ *         - THM2
+ *         - BYP
+ *       - INT2
+ *         - INSEL
+ *         - SYS_UVLO1
+ *         - SYS_UVLO2
+ *         - BAT_OILO
+ *         - CHG_STA_CC
+ *         - CHG_STA_CV
+ *         - CHG_STA_TO
+ *         - CHG_STA_DONE
  */
 enum {
 	MAX77759_INT_MAXQ,
@@ -228,8 +244,22 @@ enum {
 };
 
 enum {
-	MAX77759_CHARGER_INT_1,
-	MAX77759_CHARGER_INT_2,
+	MAX77759_CHGR_INT1_AICL,
+	MAX77759_CHGR_INT1_CHGIN,
+	MAX77759_CHGR_INT1_WCIN,
+	MAX77759_CHGR_INT1_CHG,
+	MAX77759_CHGR_INT1_BAT,
+	MAX77759_CHGR_INT1_INLIM,
+	MAX77759_CHGR_INT1_THM2,
+	MAX77759_CHGR_INT1_BYP,
+	MAX77759_CHGR_INT2_INSEL,
+	MAX77759_CHGR_INT2_SYS_UVLO1,
+	MAX77759_CHGR_INT2_SYS_UVLO2,
+	MAX77759_CHGR_INT2_BAT_OILO,
+	MAX77759_CHGR_INT2_CHG_STA_CC,
+	MAX77759_CHGR_INT2_CHG_STA_CV,
+	MAX77759_CHGR_INT2_CHG_STA_TO,
+	MAX77759_CHGR_INT2_CHG_STA_DONE,
 };
 
 static const struct regmap_irq max77759_pmic_irqs[] = {
@@ -256,8 +286,38 @@ static const struct regmap_irq max77759_topsys_irqs[] = {
 };
 
 static const struct regmap_irq max77759_chgr_irqs[] = {
-	REGMAP_IRQ_REG(MAX77759_CHARGER_INT_1, 0, GENMASK(7, 0)),
-	REGMAP_IRQ_REG(MAX77759_CHARGER_INT_2, 1, GENMASK(7, 0)),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT1_AICL, 0,
+		       MAX77759_CHGR_REG_CHG_INT_AICL),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT1_CHGIN, 0,
+		       MAX77759_CHGR_REG_CHG_INT_CHGIN),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT1_WCIN, 0,
+		       MAX77759_CHGR_REG_CHG_INT_WCIN),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT1_CHG, 0,
+		       MAX77759_CHGR_REG_CHG_INT_CHG),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT1_BAT, 0,
+		       MAX77759_CHGR_REG_CHG_INT_BAT),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT1_INLIM, 0,
+		       MAX77759_CHGR_REG_CHG_INT_INLIM),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT1_THM2, 0,
+		       MAX77759_CHGR_REG_CHG_INT_THM2),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT1_BYP, 0,
+		       MAX77759_CHGR_REG_CHG_INT_BYP),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT2_INSEL, 1,
+		       MAX77759_CHGR_REG_CHG_INT2_INSEL),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT2_SYS_UVLO1, 1,
+		       MAX77759_CHGR_REG_CHG_INT2_SYS_UVLO1),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT2_SYS_UVLO2, 1,
+		       MAX77759_CHGR_REG_CHG_INT2_SYS_UVLO2),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT2_BAT_OILO, 1,
+		       MAX77759_CHGR_REG_CHG_INT2_BAT_OILO),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT2_CHG_STA_CC, 1,
+		       MAX77759_CHGR_REG_CHG_INT2_CHG_STA_CC),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT2_CHG_STA_CV, 1,
+		       MAX77759_CHGR_REG_CHG_INT2_CHG_STA_CV),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT2_CHG_STA_TO, 1,
+		       MAX77759_CHGR_REG_CHG_INT2_CHG_STA_TO),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT2_CHG_STA_DONE, 1,
+		       MAX77759_CHGR_REG_CHG_INT2_CHG_STA_DONE),
 };
 
 static const struct regmap_irq_chip max77759_pmic_irq_chip = {
@@ -302,6 +362,7 @@ static const struct regmap_irq_chip max77759_chrg_irq_chip = {
 	.domain_suffix = "CHGR",
 	.status_base = MAX77759_CHGR_REG_CHG_INT,
 	.mask_base = MAX77759_CHGR_REG_CHG_INT_MASK,
+	.ack_base = MAX77759_CHGR_REG_CHG_INT,
 	.num_regs = 2,
 	.irqs = max77759_chgr_irqs,
 	.num_irqs = ARRAY_SIZE(max77759_chgr_irqs),
@@ -325,8 +386,22 @@ static const struct resource max77759_gpio_resources[] = {
 };
 
 static const struct resource max77759_charger_resources[] = {
-	DEFINE_RES_IRQ_NAMED(MAX77759_CHARGER_INT_1, "INT1"),
-	DEFINE_RES_IRQ_NAMED(MAX77759_CHARGER_INT_2, "INT2"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_AICL,         "AICL"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_CHGIN,        "CHGIN"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_WCIN,         "WCIN"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_CHG,          "CHG"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_BAT,          "BAT"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_INLIM,        "INLIM"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_THM2,         "THM2"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_BYP,          "BYP"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_INSEL,        "INSEL"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_SYS_UVLO1,    "SYS_UVLO1"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_SYS_UVLO2,    "SYS_UVLO2"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_BAT_OILO,     "BAT_OILO"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_CHG_STA_CC,   "CHG_STA_CC"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_CHG_STA_CV,   "CHG_STA_CV"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_CHG_STA_TO,   "CHG_STA_TO"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_CHG_STA_DONE, "CHG_STA_DONE"),
 };
 
 static const struct mfd_cell max77759_cells[] = {
diff --git a/include/linux/mfd/max77759.h b/include/linux/mfd/max77759.h
index c6face34e385..e674a519e782 100644
--- a/include/linux/mfd/max77759.h
+++ b/include/linux/mfd/max77759.h
@@ -59,35 +59,65 @@
 #define MAX77759_MAXQ_REG_AP_DATAIN0            0xb1
 #define MAX77759_MAXQ_REG_UIC_SWRST             0xe0
 
-#define MAX77759_CHGR_REG_CHG_INT               0xb0
-#define MAX77759_CHGR_REG_CHG_INT2              0xb1
-#define MAX77759_CHGR_REG_CHG_INT_MASK          0xb2
-#define MAX77759_CHGR_REG_CHG_INT2_MASK         0xb3
-#define MAX77759_CHGR_REG_CHG_INT_OK            0xb4
-#define MAX77759_CHGR_REG_CHG_DETAILS_00        0xb5
-#define MAX77759_CHGR_REG_CHG_DETAILS_01        0xb6
-#define MAX77759_CHGR_REG_CHG_DETAILS_02        0xb7
-#define MAX77759_CHGR_REG_CHG_DETAILS_03        0xb8
-#define MAX77759_CHGR_REG_CHG_CNFG_00           0xb9
-#define MAX77759_CHGR_REG_CHG_CNFG_01           0xba
-#define MAX77759_CHGR_REG_CHG_CNFG_02           0xbb
-#define MAX77759_CHGR_REG_CHG_CNFG_03           0xbc
-#define MAX77759_CHGR_REG_CHG_CNFG_04           0xbd
-#define MAX77759_CHGR_REG_CHG_CNFG_05           0xbe
-#define MAX77759_CHGR_REG_CHG_CNFG_06           0xbf
-#define MAX77759_CHGR_REG_CHG_CNFG_07           0xc0
-#define MAX77759_CHGR_REG_CHG_CNFG_08           0xc1
-#define MAX77759_CHGR_REG_CHG_CNFG_09           0xc2
-#define MAX77759_CHGR_REG_CHG_CNFG_10           0xc3
-#define MAX77759_CHGR_REG_CHG_CNFG_11           0xc4
-#define MAX77759_CHGR_REG_CHG_CNFG_12           0xc5
-#define MAX77759_CHGR_REG_CHG_CNFG_13           0xc6
-#define MAX77759_CHGR_REG_CHG_CNFG_14           0xc7
-#define MAX77759_CHGR_REG_CHG_CNFG_15           0xc8
-#define MAX77759_CHGR_REG_CHG_CNFG_16           0xc9
-#define MAX77759_CHGR_REG_CHG_CNFG_17           0xca
-#define MAX77759_CHGR_REG_CHG_CNFG_18           0xcb
-#define MAX77759_CHGR_REG_CHG_CNFG_19           0xcc
+#define MAX77759_CHGR_REG_CHG_INT                      0xb0
+#define   MAX77759_CHGR_REG_CHG_INT_AICL               BIT(7)
+#define   MAX77759_CHGR_REG_CHG_INT_CHGIN              BIT(6)
+#define   MAX77759_CHGR_REG_CHG_INT_WCIN               BIT(5)
+#define   MAX77759_CHGR_REG_CHG_INT_CHG                BIT(4)
+#define   MAX77759_CHGR_REG_CHG_INT_BAT                BIT(3)
+#define   MAX77759_CHGR_REG_CHG_INT_INLIM              BIT(2)
+#define   MAX77759_CHGR_REG_CHG_INT_THM2               BIT(1)
+#define   MAX77759_CHGR_REG_CHG_INT_BYP                BIT(0)
+#define MAX77759_CHGR_REG_CHG_INT2                     0xb1
+#define   MAX77759_CHGR_REG_CHG_INT2_INSEL             BIT(7)
+#define   MAX77759_CHGR_REG_CHG_INT2_SYS_UVLO1         BIT(6)
+#define   MAX77759_CHGR_REG_CHG_INT2_SYS_UVLO2         BIT(5)
+#define   MAX77759_CHGR_REG_CHG_INT2_BAT_OILO          BIT(4)
+#define   MAX77759_CHGR_REG_CHG_INT2_CHG_STA_CC        BIT(3)
+#define   MAX77759_CHGR_REG_CHG_INT2_CHG_STA_CV        BIT(2)
+#define   MAX77759_CHGR_REG_CHG_INT2_CHG_STA_TO        BIT(1)
+#define   MAX77759_CHGR_REG_CHG_INT2_CHG_STA_DONE      BIT(0)
+#define MAX77759_CHGR_REG_CHG_INT_MASK                 0xb2
+#define MAX77759_CHGR_REG_CHG_INT2_MASK                0xb3
+#define MAX77759_CHGR_REG_CHG_INT_OK                   0xb4
+#define MAX77759_CHGR_REG_CHG_DETAILS_00               0xb5
+#define   MAX77759_CHGR_REG_CHG_DETAILS_OO_CHGIN_DTLS  GENMASK(6, 5)
+#define MAX77759_CHGR_REG_CHG_DETAILS_01               0xb6
+#define   MAX77759_CHGR_REG_CHG_DETAILS_01_BAT_DTLS    GENMASK(6, 4)
+#define   MAX77759_CHGR_REG_CHG_DETAILS_01_CHG_DTLS    GENMASK(3, 0)
+#define MAX77759_CHGR_REG_CHG_DETAILS_02               0xb7
+#define   MAX77759_CHGR_REG_CHG_DETAILS_02_CHGIN_STS   BIT(5)
+#define MAX77759_CHGR_REG_CHG_DETAILS_03               0xb8
+#define MAX77759_CHGR_REG_CHG_CNFG_00                  0xb9
+#define   MAX77759_CHGR_REG_CHG_CNFG_00_MODE           GENMASK(3, 0)
+#define MAX77759_CHGR_REG_CHG_CNFG_01                  0xba
+#define MAX77759_CHGR_REG_CHG_CNFG_02                  0xbb
+#define   MAX77759_CHGR_REG_CHG_CNFG_02_CHGCC	       GENMASK(5, 0)
+#define MAX77759_CHGR_REG_CHG_CNFG_03                  0xbc
+#define MAX77759_CHGR_REG_CHG_CNFG_04                  0xbd
+#define   MAX77759_CHGR_REG_CHG_CNFG_04_CHG_CV_PRM     GENMASK(5, 0)
+#define MAX77759_CHGR_REG_CHG_CNFG_05                  0xbe
+#define MAX77759_CHGR_REG_CHG_CNFG_06                  0xbf
+#define   MAX77759_CHGR_REG_CHG_CNFG_06_CHGPROT        GENMASK(3, 2)
+#define MAX77759_CHGR_REG_CHG_CNFG_07                  0xc0
+#define MAX77759_CHGR_REG_CHG_CNFG_08                  0xc1
+#define MAX77759_CHGR_REG_CHG_CNFG_09                  0xc2
+#define   MAX77759_CHGR_REG_CHG_CNFG_09_CHGIN_ILIM     GENMASK(6, 0)
+#define MAX77759_CHGR_REG_CHG_CNFG_10                  0xc3
+#define MAX77759_CHGR_REG_CHG_CNFG_11                  0xc4
+#define MAX77759_CHGR_REG_CHG_CNFG_12                  0xc5
+/* Wireless Charging input channel select */
+#define   MAX77759_CHGR_REG_CHG_CNFG_12_WCINSEL        BIT(6)
+/* CHGIN/USB input channel select */
+#define   MAX77759_CHGR_REG_CHG_CNFG_12_CHGINSEL       BIT(5)
+#define MAX77759_CHGR_REG_CHG_CNFG_13                  0xc6
+#define MAX77759_CHGR_REG_CHG_CNFG_14                  0xc7
+#define MAX77759_CHGR_REG_CHG_CNFG_15                  0xc8
+#define MAX77759_CHGR_REG_CHG_CNFG_16                  0xc9
+#define MAX77759_CHGR_REG_CHG_CNFG_17                  0xca
+#define MAX77759_CHGR_REG_CHG_CNFG_18                  0xcb
+#define   MAX77759_CHGR_REG_CHG_CNFG_18_WDTEN          BIT(0)
+#define MAX77759_CHGR_REG_CHG_CNFG_19                  0xcc
 
 /* MaxQ opcodes for max77759_maxq_command() */
 #define MAX77759_MAXQ_OPCODE_MAXLENGTH (MAX77759_MAXQ_REG_AP_DATAOUT32 - \
@@ -101,6 +131,120 @@
 #define MAX77759_MAXQ_OPCODE_USER_SPACE_READ     0x81
 #define MAX77759_MAXQ_OPCODE_USER_SPACE_WRITE    0x82
 
+/*
+ * Charger Input Status
+ * @MAX77759_CHGR_CHGIN_DTLS_VBUS_UNDERVOLTAGE:
+ *     Charger input voltage (Vchgin) < Under Voltage Threshold (Vuvlo)
+ * @MAX77759_CHGR_CHGIN_DTLS_VBUS_MARGINAL_VOLTAGE: Vchgin > Vuvlo and
+ *     Vchgin < (Battery Voltage (Vbatt) + system voltage (Vsys))
+ * @MAX77759_CHGR_CHGIN_DTLS_VBUS_OVERVOLTAGE:
+ *     Vchgin > Over Voltage threshold (Vovlo)
+ * @MAX77759_CHGR_CHGIN_DTLS_VBUS_VALID:
+ *     Vchgin > Vuvlo, Vchgin < Vovlo and Vchgin > (Vsys + Vbatt)
+ */
+enum max77759_chgr_chgin_dtls_status {
+	MAX77759_CHGR_CHGIN_DTLS_VBUS_UNDERVOLTAGE,
+	MAX77759_CHGR_CHGIN_DTLS_VBUS_MARGINAL_VOLTAGE,
+	MAX77759_CHGR_CHGIN_DTLS_VBUS_OVERVOLTAGE,
+	MAX77759_CHGR_CHGIN_DTLS_VBUS_VALID,
+};
+
+/*
+ * Battery Details
+ * @MAX77759_CHGR_BAT_DTLS_NO_BATT_CHG_SUSP:
+ *     No battery and the charger suspended
+ * @MAX77759_CHGR_BAT_DTLS_DEAD_BATTERY: Vbatt < Vtrickle
+ * @MAX77759_CHGR_BAT_DTLS_BAT_CHG_TIMER_FAULT:
+ *     Charging suspended due to timer fault
+ * @MAX77759_CHGR_BAT_DTLS_BAT_OKAY:
+ *     Battery okay and Vbatt > Min Sys Voltage (Vsysmin)
+ * @MAX77759_CHGR_BAT_DTLS_BAT_UNDERVOLTAGE:
+ *     Battery is okay. Vtrickle < Vbatt < Vsysmin
+ * @MAX77759_CHGR_BAT_DTLS_BAT_OVERVOLTAGE:
+ *     Battery voltage > Overvoltage threshold
+ * @MAX77759_CHGR_BAT_DTLS_BAT_OVERCURRENT:
+ *     Battery current exceeds overcurrent threshold
+ * @MAX77759_CHGR_BAT_DTLS_BAT_ONLY_MODE:
+ *     Battery only mode and battery level not available
+ */
+enum max77759_chgr_bat_dtls_states {
+	MAX77759_CHGR_BAT_DTLS_NO_BATT_CHG_SUSP,
+	MAX77759_CHGR_BAT_DTLS_DEAD_BATTERY,
+	MAX77759_CHGR_BAT_DTLS_BAT_CHG_TIMER_FAULT,
+	MAX77759_CHGR_BAT_DTLS_BAT_OKAY,
+	MAX77759_CHGR_BAT_DTLS_BAT_UNDERVOLTAGE,
+	MAX77759_CHGR_BAT_DTLS_BAT_OVERVOLTAGE,
+	MAX77759_CHGR_BAT_DTLS_BAT_OVERCURRENT,
+	MAX77759_CHGR_BAT_DTLS_BAT_ONLY_MODE,
+};
+
+/*
+ * Charger Details
+ * @MAX77759_CHGR_CHG_DTLS_PREQUAL: Charger in prequalification mode
+ * @MAX77759_CHGR_CHG_DTLS_CC:      Charger in fast charge const curr mode
+ * @MAX77759_CHGR_CHG_DTLS_CV:      Charger in fast charge const voltage mode
+ * @MAX77759_CHGR_CHG_DTLS_TO:      Charger is in top off mode
+ * @MAX77759_CHGR_CHG_DTLS_DONE:    Charger is done
+ * @MAX77759_CHGR_CHG_DTLS_RSVD_1:  Reserved
+ * @MAX77759_CHGR_CHG_DTLS_TIMER_FAULT:   Charger is in timer fault mode
+ * @MAX77759_CHGR_CHG_DTLS_SUSP_BATT_THM:
+ *     Charger is suspended as bettery removal detected
+ * @MAX77759_CHGR_CHG_DTLS_OFF:
+ *     Charger is off. Input invalid or charger disabled
+ * @MAX77759_CHGR_CHG_DTLS_RSVD_2:  Reserved
+ * @MAX77759_CHGR_CHG_DTLS_RSVD_3:  Reserved
+ * @MAX77759_CHGR_CHG_DTLS_OFF_WDOG_TIMER:
+ *     Charger is off as watchdog timer expired
+ * @MAX77759_CHGR_CHG_DTLS_SUSP_JEITA:    Charger is in JEITA control mode
+ */
+enum max77759_chgr_chg_dtls_states {
+	MAX77759_CHGR_CHG_DTLS_PREQUAL,
+	MAX77759_CHGR_CHG_DTLS_CC,
+	MAX77759_CHGR_CHG_DTLS_CV,
+	MAX77759_CHGR_CHG_DTLS_TO,
+	MAX77759_CHGR_CHG_DTLS_DONE,
+	MAX77759_CHGR_CHG_DTLS_RSVD_1,
+	MAX77759_CHGR_CHG_DTLS_TIMER_FAULT,
+	MAX77759_CHGR_CHG_DTLS_SUSP_BATT_THM,
+	MAX77759_CHGR_CHG_DTLS_OFF,
+	MAX77759_CHGR_CHG_DTLS_RSVD_2,
+	MAX77759_CHGR_CHG_DTLS_RSVD_3,
+	MAX77759_CHGR_CHG_DTLS_OFF_WDOG_TIMER,
+	MAX77759_CHGR_CHG_DTLS_SUSP_JEITA,
+};
+
+enum max77759_chgr_mode {
+	MAX77759_CHGR_MODE_OFF,
+	MAX77759_CHGR_MODE_CHG_BUCK_ON = 0x5,
+	MAX77759_CHGR_MODE_OTG_BOOST_ON = 0xA,
+};
+
+/* Fast charge current limits */
+#define MAX77759_CHGR_CHGCC_MIN_UA                     133330
+#define MAX77759_CHGR_CHGCC_MAX_UA                     4000000
+#define MAX77759_CHGR_CHGCC_STEP_UA                    66670
+#define MAX77759_CHGR_CHGCC_REG_OFFSET                 0x2
+
+/* Charge Termination Voltage Limits (in 2 ranges) */
+/* [3.8, 3.9] V range */
+#define MAX77759_CHGR_CHG_CV_PRM_LO_MIN_MV             3800
+#define MAX77759_CHGR_CHG_CV_PRM_LO_MAX_MV             3900
+#define MAX77759_CHGR_CHG_CV_PRM_LO_STEP_MV            100
+#define MAX77759_CHGR_CHG_CV_PRM_LO_MIN_REG            0x38
+#define MAX77759_CHGR_CHG_CV_PRM_LO_MAX_REG            0x39
+/* [4, 4.5] V range */
+#define MAX77759_CHGR_CHG_CV_PRM_HI_MIN_MV             4000
+#define MAX77759_CHGR_CHG_CV_PRM_HI_MAX_MV             4500
+#define MAX77759_CHGR_CHG_CV_PRM_HI_STEP_MV            10
+#define MAX77759_CHGR_CHG_CV_PRM_HI_MIN_REG            0x0
+#define MAX77759_CHGR_CHG_CV_PRM_HI_MAX_REG            0x32
+
+/* USB input current limits */
+#define MAX77759_CHGR_CHGIN_ILIM_MIN_UA                100000
+#define MAX77759_CHGR_CHGIN_ILIM_MAX_UA                3200000
+#define MAX77759_CHGR_CHGIN_ILIM_STEP_UA               25000
+#define MAX77759_CHGR_CHGIN_ILIM_REG_OFFSET            0x3
+
 /**
  * struct max77759 - core max77759 internal data structure
  *

-- 
2.52.0.351.gbe84eed79e-goog




From devnull+amitsd.google.com at kernel.org  Fri Dec 26 16:04:24 2025
From: devnull+amitsd.google.com at kernel.org (Amit Sunil Dhamne via B4 Relay)
Date: Sat, 27 Dec 2025 00:04:24 +0000
Subject: [PATCH v3 4/5] power: supply: max77759: add charger driver
In-Reply-To: <20251227-max77759-charger-v3-0-54e664f5ca92@google.com>
References: <20251227-max77759-charger-v3-0-54e664f5ca92@google.com>
Message-ID: <20251227-max77759-charger-v3-4-54e664f5ca92@google.com>

From: Amit Sunil Dhamne <amitsd at google.com>

Add support for MAX77759 battery charger driver. This is a 4A 1-Cell
Li+/LiPoly dual input switch mode charger. While the device can support
USB & wireless charger inputs, this implementation only supports USB
input. This implementation supports both buck and boost modes.

Signed-off-by: Amit Sunil Dhamne <amitsd at google.com>
---
 MAINTAINERS                             |   6 +
 drivers/power/supply/Kconfig            |  11 +
 drivers/power/supply/Makefile           |   1 +
 drivers/power/supply/max77759_charger.c | 764 ++++++++++++++++++++++++++++++++
 4 files changed, 782 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index dc731d37c8fe..26a9654ab75e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15539,6 +15539,12 @@ F:	drivers/mfd/max77759.c
 F:	drivers/nvmem/max77759-nvmem.c
 F:	include/linux/mfd/max77759.h
 
+MAXIM MAX77759 BATTERY CHARGER DRIVER
+M:	Amit Sunil Dhamne <amitsd at google.com>
+L:	linux-kernel at vger.kernel.org
+S:	Maintained
+F:	drivers/power/supply/max77759_charger.c
+
 MAXIM MAX77802 PMIC REGULATOR DEVICE DRIVER
 M:	Javier Martinez Canillas <javier at dowhile0.org>
 L:	linux-kernel at vger.kernel.org
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 92f9f7aae92f..e172fd980fde 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -1132,4 +1132,15 @@ config FUEL_GAUGE_MM8013
 	  the state of charge, temperature, cycle count, actual and design
 	  capacity, etc.
 
+config CHARGER_MAX77759
+	tristate "MAX77759 Charger Driver"
+	depends on MFD_MAX77759 && REGULATOR
+	default MFD_MAX77759
+	help
+	  Say M or Y here to enable the MAX77759 Charger Driver. MAX77759
+	  charger is a function of the MAX77759 PMIC. This is a dual input
+	  switch-mode charger. This driver supports buck and OTG boost modes.
+
+	  If built as a module, it will be called max77759_charger.
+
 endif # POWER_SUPPLY
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 4b79d5abc49a..6af905875ad5 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -128,3 +128,4 @@ obj-$(CONFIG_CHARGER_SURFACE)	+= surface_charger.o
 obj-$(CONFIG_BATTERY_UG3105)	+= ug3105_battery.o
 obj-$(CONFIG_CHARGER_QCOM_SMB2)	+= qcom_smbx.o
 obj-$(CONFIG_FUEL_GAUGE_MM8013)	+= mm8013.o
+obj-$(CONFIG_CHARGER_MAX77759)	+= max77759_charger.o
diff --git a/drivers/power/supply/max77759_charger.c b/drivers/power/supply/max77759_charger.c
new file mode 100644
index 000000000000..3d255b069fb9
--- /dev/null
+++ b/drivers/power/supply/max77759_charger.c
@@ -0,0 +1,764 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * max77759_charger.c - Battery charger driver for MAX77759 charger device.
+ *
+ * Copyright 2025 Google LLC.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/devm-helpers.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/math64.h>
+#include <linux/mfd/max77759.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/string_choices.h>
+
+/* Default values for Fast Charge Current & Float Voltage */
+#define CHG_CC_DEFAULT_UA			2266770
+#define CHG_FV_DEFAULT_MV			4300
+
+#define FOREACH_IRQ(S)			\
+	S(AICL),			\
+	S(CHGIN),			\
+	S(CHG),				\
+	S(INLIM),			\
+	S(BAT_OILO),			\
+	S(CHG_STA_CC),			\
+	S(CHG_STA_CV),			\
+	S(CHG_STA_TO),			\
+	S(CHG_STA_DONE)
+
+#define GENERATE_ENUM(e)		e
+#define GENERATE_STRING(s)		#s
+
+enum {
+	FOREACH_IRQ(GENERATE_ENUM)
+};
+
+static const char *const chgr_irqs_str[] = {
+	FOREACH_IRQ(GENERATE_STRING)
+};
+
+static int irqs[ARRAY_SIZE(chgr_irqs_str)];
+
+struct max77759_charger {
+	struct device *dev;
+	struct regmap *regmap;
+	struct power_supply *psy;
+	struct regulator_dev *chgin_otg_rdev;
+	struct notifier_block nb;
+	struct power_supply *tcpm_psy;
+	struct work_struct psy_work;
+	struct mutex lock; /* protects the state below */
+	enum max77759_chgr_mode mode;
+};
+
+static inline int regval_to_val(int reg, int reg_offset, int step, int minval)
+{
+	return ((reg - reg_offset) * step) + minval;
+}
+
+static inline int val_to_regval(int val, int minval, int step, int reg_offset)
+{
+	s64 dividend;
+
+	if (unlikely(step == 0))
+		return reg_offset;
+
+	dividend = (s64)val - minval;
+	return DIV_S64_ROUND_CLOSEST(dividend, step) + reg_offset;
+}
+
+static inline int unlock_prot_regs(struct max77759_charger *chg, bool unlock)
+{
+	return regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_06,
+				  MAX77759_CHGR_REG_CHG_CNFG_06_CHGPROT, unlock
+				  ? MAX77759_CHGR_REG_CHG_CNFG_06_CHGPROT : 0);
+}
+
+static int charger_input_valid(struct max77759_charger *chg)
+{
+	u32 val;
+	int ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_INT_OK, &val);
+	if (ret)
+		return ret;
+
+	return (val & MAX77759_CHGR_REG_CHG_INT_CHG) &&
+		(val & MAX77759_CHGR_REG_CHG_INT_CHGIN);
+}
+
+static int get_online(struct max77759_charger *chg)
+{
+	u32 val;
+	int ret;
+
+	ret = charger_input_valid(chg);
+	if (ret <= 0)
+		return ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_DETAILS_02, &val);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&chg->lock);
+	return (val & MAX77759_CHGR_REG_CHG_DETAILS_02_CHGIN_STS) &&
+		(chg->mode == MAX77759_CHGR_MODE_CHG_BUCK_ON);
+}
+
+static int get_status(struct max77759_charger *chg)
+{
+	u32 val;
+	int ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_DETAILS_01, &val);
+	if (ret)
+		return ret;
+
+	switch (FIELD_GET(MAX77759_CHGR_REG_CHG_DETAILS_01_CHG_DTLS, val)) {
+	case MAX77759_CHGR_CHG_DTLS_PREQUAL:
+	case MAX77759_CHGR_CHG_DTLS_CC:
+	case MAX77759_CHGR_CHG_DTLS_CV:
+	case MAX77759_CHGR_CHG_DTLS_TO:
+		return POWER_SUPPLY_STATUS_CHARGING;
+	case MAX77759_CHGR_CHG_DTLS_DONE:
+		return POWER_SUPPLY_STATUS_FULL;
+	case MAX77759_CHGR_CHG_DTLS_TIMER_FAULT:
+	case MAX77759_CHGR_CHG_DTLS_SUSP_BATT_THM:
+	case MAX77759_CHGR_CHG_DTLS_OFF_WDOG_TIMER:
+	case MAX77759_CHGR_CHG_DTLS_SUSP_JEITA:
+		return POWER_SUPPLY_STATUS_NOT_CHARGING;
+	case MAX77759_CHGR_CHG_DTLS_OFF:
+		return POWER_SUPPLY_STATUS_DISCHARGING;
+	default:
+		break;
+	}
+
+	return POWER_SUPPLY_STATUS_UNKNOWN;
+}
+
+static int get_charge_type(struct max77759_charger *chg)
+{
+	u32 val;
+	int ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_DETAILS_01, &val);
+	if (ret)
+		return ret;
+
+	switch (FIELD_GET(MAX77759_CHGR_REG_CHG_DETAILS_01_CHG_DTLS, val)) {
+	case MAX77759_CHGR_CHG_DTLS_PREQUAL:
+		return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+	case MAX77759_CHGR_CHG_DTLS_CC:
+	case MAX77759_CHGR_CHG_DTLS_CV:
+		return POWER_SUPPLY_CHARGE_TYPE_FAST;
+	case MAX77759_CHGR_CHG_DTLS_TO:
+		return POWER_SUPPLY_CHARGE_TYPE_STANDARD;
+	case MAX77759_CHGR_CHG_DTLS_DONE:
+	case MAX77759_CHGR_CHG_DTLS_TIMER_FAULT:
+	case MAX77759_CHGR_CHG_DTLS_SUSP_BATT_THM:
+	case MAX77759_CHGR_CHG_DTLS_OFF_WDOG_TIMER:
+	case MAX77759_CHGR_CHG_DTLS_SUSP_JEITA:
+	case MAX77759_CHGR_CHG_DTLS_OFF:
+		return POWER_SUPPLY_CHARGE_TYPE_NONE;
+	default:
+		break;
+	}
+
+	return POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+}
+
+static int get_chg_health(struct max77759_charger *chg)
+{
+	u32 val;
+	int ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_DETAILS_00, &val);
+	if (ret)
+		return ret;
+
+	switch (FIELD_GET(MAX77759_CHGR_REG_CHG_DETAILS_OO_CHGIN_DTLS, val)) {
+	case MAX77759_CHGR_CHGIN_DTLS_VBUS_UNDERVOLTAGE:
+	case MAX77759_CHGR_CHGIN_DTLS_VBUS_MARGINAL_VOLTAGE:
+		return POWER_SUPPLY_HEALTH_UNDERVOLTAGE;
+	case MAX77759_CHGR_CHGIN_DTLS_VBUS_OVERVOLTAGE:
+		return POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+	case MAX77759_CHGR_CHGIN_DTLS_VBUS_VALID:
+		return POWER_SUPPLY_HEALTH_GOOD;
+	default:
+		break;
+	}
+
+	return POWER_SUPPLY_HEALTH_UNKNOWN;
+}
+
+static int get_batt_health(struct max77759_charger *chg)
+{
+	u32 val;
+	int ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_DETAILS_01, &val);
+	if (ret)
+		return ret;
+
+	switch (FIELD_GET(MAX77759_CHGR_REG_CHG_DETAILS_01_BAT_DTLS, val)) {
+	case MAX77759_CHGR_BAT_DTLS_NO_BATT_CHG_SUSP:
+		return POWER_SUPPLY_HEALTH_NO_BATTERY;
+	case MAX77759_CHGR_BAT_DTLS_DEAD_BATTERY:
+		return POWER_SUPPLY_HEALTH_DEAD;
+	case MAX77759_CHGR_BAT_DTLS_BAT_CHG_TIMER_FAULT:
+		return POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
+	case MAX77759_CHGR_BAT_DTLS_BAT_OKAY:
+	case MAX77759_CHGR_BAT_DTLS_BAT_ONLY_MODE:
+		return POWER_SUPPLY_HEALTH_GOOD;
+	case MAX77759_CHGR_BAT_DTLS_BAT_UNDERVOLTAGE:
+		return POWER_SUPPLY_HEALTH_UNDERVOLTAGE;
+	case MAX77759_CHGR_BAT_DTLS_BAT_OVERVOLTAGE:
+		return POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+	case MAX77759_CHGR_BAT_DTLS_BAT_OVERCURRENT:
+		return POWER_SUPPLY_HEALTH_OVERCURRENT;
+	default:
+		break;
+	}
+
+	return POWER_SUPPLY_HEALTH_UNKNOWN;
+}
+
+static int get_health(struct max77759_charger *chg)
+{
+	int ret;
+
+	ret = get_online(chg);
+	if (ret < 0)
+		return ret;
+
+	if (ret) {
+		ret = get_chg_health(chg);
+		if (ret < 0 || ret != POWER_SUPPLY_HEALTH_GOOD)
+			return ret;
+	}
+
+	return get_batt_health(chg);
+}
+
+static int get_fast_charge_current(struct max77759_charger *chg)
+{
+	u32 regval;
+	int ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_02, &regval);
+	if (ret)
+		return ret;
+
+	ret = FIELD_GET(MAX77759_CHGR_REG_CHG_CNFG_02_CHGCC, regval);
+	if (ret <= MAX77759_CHGR_CHGCC_REG_OFFSET)
+		return MAX77759_CHGR_CHGCC_MIN_UA;
+
+	return regval_to_val(ret, MAX77759_CHGR_CHGCC_REG_OFFSET,
+			     MAX77759_CHGR_CHGCC_STEP_UA,
+			     MAX77759_CHGR_CHGCC_MIN_UA);
+}
+
+static int set_fast_charge_current_limit(struct max77759_charger *chg,
+					 u32 cc_max_ua)
+{
+	u32 val;
+
+	if (cc_max_ua < MAX77759_CHGR_CHGCC_MIN_UA ||
+	    cc_max_ua > MAX77759_CHGR_CHGCC_MAX_UA)
+		return -EINVAL;
+
+	val = val_to_regval(cc_max_ua, MAX77759_CHGR_CHGCC_MIN_UA,
+			    MAX77759_CHGR_CHGCC_STEP_UA,
+			    MAX77759_CHGR_CHGCC_REG_OFFSET);
+	return regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_02,
+				  MAX77759_CHGR_REG_CHG_CNFG_02_CHGCC, val);
+}
+
+static int get_float_voltage(struct max77759_charger *chg)
+{
+	u32 regval;
+	int ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_04, &regval);
+	if (ret)
+		return ret;
+
+	ret = FIELD_GET(MAX77759_CHGR_REG_CHG_CNFG_04_CHG_CV_PRM, regval);
+	switch (ret) {
+	case MAX77759_CHGR_CHG_CV_PRM_HI_MIN_REG ... MAX77759_CHGR_CHG_CV_PRM_HI_MAX_REG:
+		return regval_to_val(ret, MAX77759_CHGR_CHG_CV_PRM_HI_MIN_REG,
+				     MAX77759_CHGR_CHG_CV_PRM_HI_STEP_MV,
+				     MAX77759_CHGR_CHG_CV_PRM_HI_MIN_MV);
+	case MAX77759_CHGR_CHG_CV_PRM_LO_MIN_REG ... MAX77759_CHGR_CHG_CV_PRM_LO_MAX_REG:
+		return regval_to_val(ret, MAX77759_CHGR_CHG_CV_PRM_LO_MIN_REG,
+				     MAX77759_CHGR_CHG_CV_PRM_LO_STEP_MV,
+				     MAX77759_CHGR_CHG_CV_PRM_LO_MIN_MV);
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int set_float_voltage_limit(struct max77759_charger *chg, u32 fv_mv)
+{
+	u32 regval;
+
+	if (fv_mv >= MAX77759_CHGR_CHG_CV_PRM_LO_MIN_MV &&
+	    fv_mv <= MAX77759_CHGR_CHG_CV_PRM_LO_MAX_MV) {
+		regval = val_to_regval(fv_mv,
+				       MAX77759_CHGR_CHG_CV_PRM_LO_MIN_MV,
+				       MAX77759_CHGR_CHG_CV_PRM_LO_STEP_MV,
+				       MAX77759_CHGR_CHG_CV_PRM_LO_MIN_REG);
+	} else if (fv_mv >= MAX77759_CHGR_CHG_CV_PRM_HI_MIN_MV &&
+		   fv_mv <= MAX77759_CHGR_CHG_CV_PRM_HI_MAX_MV) {
+		regval = val_to_regval(fv_mv,
+				       MAX77759_CHGR_CHG_CV_PRM_HI_MIN_MV,
+				       MAX77759_CHGR_CHG_CV_PRM_HI_STEP_MV,
+				       MAX77759_CHGR_CHG_CV_PRM_HI_MIN_REG);
+	} else {
+		return -EINVAL;
+	}
+
+	return regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_04,
+				  MAX77759_CHGR_REG_CHG_CNFG_04_CHG_CV_PRM,
+				  regval);
+}
+
+static int get_input_current_limit(struct max77759_charger *chg)
+{
+	u32 regval;
+	int ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_09, &regval);
+	if (ret)
+		return ret;
+
+	ret = FIELD_GET(MAX77759_CHGR_REG_CHG_CNFG_09_CHGIN_ILIM, regval);
+	if (ret <= MAX77759_CHGR_CHGIN_ILIM_REG_OFFSET)
+		return MAX77759_CHGR_CHGIN_ILIM_MIN_UA;
+
+	return regval_to_val(ret, MAX77759_CHGR_CHGIN_ILIM_REG_OFFSET,
+			     MAX77759_CHGR_CHGIN_ILIM_STEP_UA,
+			     MAX77759_CHGR_CHGIN_ILIM_MIN_UA);
+}
+
+static int set_input_current_limit(struct max77759_charger *chg, int ilim_ua)
+{
+	u32 regval;
+
+	if (ilim_ua < 0)
+		return -EINVAL;
+
+	if (ilim_ua == 0)
+		ilim_ua = MAX77759_CHGR_CHGIN_ILIM_MIN_UA;
+	else if (ilim_ua > MAX77759_CHGR_CHGIN_ILIM_MAX_UA)
+		ilim_ua = MAX77759_CHGR_CHGIN_ILIM_MAX_UA;
+
+	regval = val_to_regval(ilim_ua, MAX77759_CHGR_CHGIN_ILIM_MIN_UA,
+			       MAX77759_CHGR_CHGIN_ILIM_STEP_UA,
+			       MAX77759_CHGR_CHGIN_ILIM_REG_OFFSET);
+	return regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_09,
+				  MAX77759_CHGR_REG_CHG_CNFG_09_CHGIN_ILIM,
+				  regval);
+}
+
+static const enum power_supply_property max77759_charger_props[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_CHARGE_TYPE,
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
+	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
+};
+
+static int max77759_charger_get_property(struct power_supply *psy,
+					 enum power_supply_property psp,
+					 union power_supply_propval *pval)
+{
+	struct max77759_charger *chg = power_supply_get_drvdata(psy);
+	int ret;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		ret = get_online(chg);
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		ret = charger_input_valid(chg);
+		break;
+	case POWER_SUPPLY_PROP_STATUS:
+		ret = get_status(chg);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		ret = get_charge_type(chg);
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		ret = get_health(chg);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+		ret = get_fast_charge_current(chg);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
+		ret = get_float_voltage(chg);
+		break;
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+		ret = get_input_current_limit(chg);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	pval->intval = ret;
+	return ret < 0 ? ret : 0;
+}
+
+static const struct power_supply_desc max77759_charger_desc = {
+	.name = "max77759-charger",
+	.type = POWER_SUPPLY_TYPE_USB,
+	.properties = max77759_charger_props,
+	.num_properties = ARRAY_SIZE(max77759_charger_props),
+	.get_property = max77759_charger_get_property,
+};
+
+static int charger_set_mode(struct max77759_charger *chg,
+			    enum max77759_chgr_mode mode)
+{
+	int ret;
+
+	guard(mutex)(&chg->lock);
+
+	if (chg->mode == mode)
+		return 0;
+
+	if ((mode == MAX77759_CHGR_MODE_CHG_BUCK_ON ||
+	     mode == MAX77759_CHGR_MODE_OTG_BOOST_ON) &&
+	    chg->mode != MAX77759_CHGR_MODE_OFF) {
+		dev_err(chg->dev, "Invalid mode transition from %d to %d",
+			chg->mode, mode);
+		return -EINVAL;
+	}
+
+	ret = regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_00,
+				 MAX77759_CHGR_REG_CHG_CNFG_00_MODE, mode);
+	if (ret)
+		return ret;
+
+	chg->mode = mode;
+	return 0;
+}
+
+static int enable_chgin_otg(struct regulator_dev *rdev)
+{
+	struct max77759_charger *chg = rdev_get_drvdata(rdev);
+
+	return charger_set_mode(chg, MAX77759_CHGR_MODE_OTG_BOOST_ON);
+}
+
+static int disable_chgin_otg(struct regulator_dev *rdev)
+{
+	struct max77759_charger *chg = rdev_get_drvdata(rdev);
+
+	return charger_set_mode(chg, MAX77759_CHGR_MODE_OFF);
+}
+
+static int chgin_otg_status(struct regulator_dev *rdev)
+{
+	struct max77759_charger *chg = rdev_get_drvdata(rdev);
+
+	guard(mutex)(&chg->lock);
+	return chg->mode == MAX77759_CHGR_MODE_OTG_BOOST_ON;
+}
+
+static const struct regulator_ops chgin_otg_reg_ops = {
+	.enable = enable_chgin_otg,
+	.disable = disable_chgin_otg,
+	.is_enabled = chgin_otg_status,
+};
+
+static const struct regulator_desc chgin_otg_reg_desc = {
+	.name = "chgin-otg",
+	.of_match = of_match_ptr("chgin-otg-regulator"),
+	.owner = THIS_MODULE,
+	.ops = &chgin_otg_reg_ops,
+	.fixed_uV = 5000000,
+	.n_voltages = 1,
+};
+
+static irqreturn_t irq_handler(int irq, void *data)
+{
+	struct max77759_charger *chg = data;
+	struct device *dev = chg->dev;
+	u32 chgint_ok;
+	int i;
+
+	regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_INT_OK, &chgint_ok);
+
+	for (i = 0; i < ARRAY_SIZE(irqs); i++) {
+		if (irqs[i] == irq)
+			break;
+	}
+
+	switch (i) {
+	case AICL:
+		dev_dbg(dev, "AICL mode: %s",
+			str_no_yes(chgint_ok & MAX77759_CHGR_REG_CHG_INT_AICL));
+		break;
+	case CHGIN:
+		dev_dbg(dev, "CHGIN input valid: %s",
+			str_yes_no(chgint_ok & MAX77759_CHGR_REG_CHG_INT_CHGIN));
+		break;
+	case CHG:
+		dev_dbg(dev, "CHG status okay/off: %s",
+			str_yes_no(chgint_ok & MAX77759_CHGR_REG_CHG_INT_CHG));
+		break;
+	case INLIM:
+		dev_dbg(dev, "Current Limit reached: %s",
+			str_no_yes(chgint_ok & MAX77759_CHGR_REG_CHG_INT_INLIM));
+		break;
+	case BAT_OILO:
+		dev_dbg(dev, "Battery over-current threshold crossed");
+		break;
+	case CHG_STA_CC:
+		dev_dbg(dev, "Charger reached CC stage");
+		break;
+	case CHG_STA_CV:
+		dev_dbg(dev, "Charger reached CV stage");
+		break;
+	case CHG_STA_TO:
+		dev_dbg(dev, "Charger reached TO stage");
+		break;
+	case CHG_STA_DONE:
+		dev_dbg(dev, "Charger reached TO stage");
+		break;
+	default:
+		dev_err(dev, "Unrecognized irq: %d", i);
+		return IRQ_HANDLED;
+	}
+
+	power_supply_changed(chg->psy);
+	return IRQ_HANDLED;
+}
+
+static int max77759_init_irqhandler(struct max77759_charger *chg)
+{
+	struct device *dev = chg->dev;
+	unsigned long irq_flags;
+	struct irq_data *irqd;
+	int i, ret;
+
+	for (i = 0; i < ARRAY_SIZE(chgr_irqs_str); i++) {
+		ret = platform_get_irq_byname(to_platform_device(dev),
+					      chgr_irqs_str[i]);
+		if (ret < 0) {
+			dev_err(dev,
+				"Failed to get irq resource for %s, ret=%d",
+				chgr_irqs_str[i], ret);
+			return ret;
+		}
+
+		irqs[i] = ret;
+		irq_flags = IRQF_ONESHOT;
+		irqd = irq_get_irq_data(irqs[i]);
+		if (irqd)
+			irq_flags |= irqd_get_trigger_type(irqd);
+
+		ret = devm_request_threaded_irq(dev, irqs[i], NULL, irq_handler,
+						irq_flags, dev_name(dev), chg);
+		if (ret) {
+			dev_err(dev,
+				"Unable to register irq handler for %s, ret=%d",
+				chgr_irqs_str[i], ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int max77759_charger_init(struct max77759_charger *chg)
+{
+	struct power_supply_battery_info *info;
+	u32 regval, fast_chg_curr, fv;
+	int ret;
+
+	regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_00, &regval);
+	chg->mode = FIELD_GET(MAX77759_CHGR_REG_CHG_CNFG_00_MODE, regval);
+	ret = charger_set_mode(chg, MAX77759_CHGR_MODE_OFF);
+	if (ret)
+		return ret;
+
+	if (power_supply_get_battery_info(chg->psy, &info)) {
+		fv = CHG_FV_DEFAULT_MV;
+		fast_chg_curr = CHG_CC_DEFAULT_UA;
+	} else {
+		fv = info->constant_charge_voltage_max_uv / 1000;
+		fast_chg_curr = info->constant_charge_current_max_ua;
+	}
+
+	ret = set_fast_charge_current_limit(chg, fast_chg_curr);
+	if (ret)
+		return ret;
+
+	ret = set_float_voltage_limit(chg, fv);
+	if (ret)
+		return ret;
+
+	ret = unlock_prot_regs(chg, true);
+	if (ret)
+		return ret;
+
+	/* Disable wireless charging input */
+	regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_12,
+			   MAX77759_CHGR_REG_CHG_CNFG_12_WCINSEL, 0);
+
+	regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_18,
+			   MAX77759_CHGR_REG_CHG_CNFG_18_WDTEN, 0);
+
+	return unlock_prot_regs(chg, false);
+}
+
+static void psy_work_item(struct work_struct *work)
+{
+	struct max77759_charger *chg =
+		container_of(work, struct max77759_charger, psy_work);
+	union power_supply_propval current_limit = { 0 }, online = { 0 };
+	int ret;
+
+	power_supply_get_property(chg->tcpm_psy, POWER_SUPPLY_PROP_CURRENT_MAX,
+				  &current_limit);
+	power_supply_get_property(chg->tcpm_psy, POWER_SUPPLY_PROP_ONLINE,
+				  &online);
+
+	if (online.intval && current_limit.intval) {
+		ret = set_input_current_limit(chg, current_limit.intval);
+		if (ret)
+			dev_err(chg->dev,
+				"Unable to set current limit, ret=%d", ret);
+
+		charger_set_mode(chg, MAX77759_CHGR_MODE_CHG_BUCK_ON);
+	} else {
+		charger_set_mode(chg, MAX77759_CHGR_MODE_OFF);
+	}
+}
+
+static int psy_changed(struct notifier_block *nb, unsigned long evt, void *data)
+{
+	struct max77759_charger *chg = container_of(nb, struct max77759_charger,
+						    nb);
+	const char *psy_name = "tcpm-source";
+	struct power_supply *psy = data;
+
+	if (!strnstr(psy->desc->name, psy_name, strlen(psy_name)) ||
+	    evt != PSY_EVENT_PROP_CHANGED)
+		return NOTIFY_OK;
+
+	chg->tcpm_psy = psy;
+	schedule_work(&chg->psy_work);
+	return NOTIFY_OK;
+}
+
+static void max_tcpci_unregister_psy_notifier(void *nb)
+{
+	power_supply_unreg_notifier(nb);
+}
+
+static int max77759_charger_probe(struct platform_device *pdev)
+{
+	struct regulator_config chgin_otg_reg_cfg;
+	struct power_supply_config psy_cfg;
+	struct device *dev = &pdev->dev;
+	struct max77759_charger *chg;
+	int ret;
+
+	device_set_of_node_from_dev(dev, dev->parent);
+	chg = devm_kzalloc(dev, sizeof(*chg), GFP_KERNEL);
+	if (!chg)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, chg);
+	chg->dev = dev;
+	chg->regmap = dev_get_regmap(dev->parent, "charger");
+	if (!chg->regmap)
+		return dev_err_probe(dev, -ENODEV, "Missing regmap");
+
+	ret = devm_mutex_init(dev, &chg->lock);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to initialize lock");
+
+	psy_cfg.fwnode = dev_fwnode(dev);
+	psy_cfg.drv_data = chg;
+	chg->psy = devm_power_supply_register(dev, &max77759_charger_desc,
+					      &psy_cfg);
+	if (IS_ERR(chg->psy))
+		return dev_err_probe(dev, -EPROBE_DEFER,
+				     "Failed to register psy, ret=%ld",
+				     PTR_ERR(chg->psy));
+
+	ret = max77759_charger_init(chg);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed to initialize max77759 charger");
+
+	chgin_otg_reg_cfg.dev = dev;
+	chgin_otg_reg_cfg.driver_data = chg;
+	chgin_otg_reg_cfg.of_node = dev_of_node(dev);
+	chg->chgin_otg_rdev = devm_regulator_register(dev, &chgin_otg_reg_desc,
+						      &chgin_otg_reg_cfg);
+	if (IS_ERR(chg->chgin_otg_rdev))
+		return dev_err_probe(dev, PTR_ERR(chg->chgin_otg_rdev),
+				     "Failed to register chgin otg regulator");
+
+	ret = devm_work_autocancel(dev, &chg->psy_work, psy_work_item);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to initialize psy work");
+
+	chg->nb.notifier_call = psy_changed;
+	ret = power_supply_reg_notifier(&chg->nb);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Unable to register psy notifier");
+
+	ret = devm_add_action_or_reset(dev, max_tcpci_unregister_psy_notifier,
+				       &chg->nb);
+	if (ret)
+		return ret;
+
+	ret = max77759_init_irqhandler(chg);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Unable to initialize irq handler");
+	return 0;
+}
+
+static const struct platform_device_id max77759_charger_id[] = {
+	{"max77759-charger",},
+	{ }
+};
+MODULE_DEVICE_TABLE(platform, max77759_charger_id);
+
+static struct platform_driver max77759_charger_driver = {
+	.driver = {
+		.name = "max77759-charger",
+	},
+	.probe = max77759_charger_probe,
+	.id_table = max77759_charger_id,
+};
+module_platform_driver(max77759_charger_driver);
+
+MODULE_AUTHOR("Amit Sunil Dhamne <amitsd at google.com>");
+MODULE_DESCRIPTION("Maxim MAX77759 charger driver");
+MODULE_LICENSE("GPL");

-- 
2.52.0.351.gbe84eed79e-goog




From tj at kernel.org  Fri Dec 26 16:18:05 2025
From: tj at kernel.org (Tejun Heo)
Date: Fri, 26 Dec 2025 14:18:05 -1000
Subject: [PATCH 18/33] cpuset: Propagate cpuset isolation update to
 workqueue through housekeeping
In-Reply-To: <20251224134520.33231-19-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-19-frederic@kernel.org>
Message-ID: <aU8lvW7nfTukNKGK@slm.duckdns.org>

On Wed, Dec 24, 2025 at 02:45:05PM +0100, Frederic Weisbecker wrote:
> Until now, cpuset would propagate isolated partition changes to
> workqueues so that unbound workers get properly reaffined.
> 
> Since housekeeping now centralizes, synchronize and propagates isolation
> cpumask changes, perform the work from that subsystem for consolidation
> and consistency purposes.
> 
> For simplification purpose, the target function is adapted to take the
> new housekeeping mask instead of the isolated mask.
> 
> Suggested-by: Tejun Heo <tj at kernel.org>
> Signed-off-by: Frederic Weisbecker <frederic at kernel.org>

Acked-by: Tejun Heo <tj at kernel.org>

Thanks.

-- 
tejun


From llong at redhat.com  Fri Dec 26 16:39:28 2025
From: llong at redhat.com (Waiman Long)
Date: Fri, 26 Dec 2025 19:39:28 -0500
Subject: [PATCH 33/33] doc: Add housekeeping documentation
In-Reply-To: <20251224134520.33231-34-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-34-frederic@kernel.org>
Message-ID: <370149fc-1624-4a16-ac47-dd9b2dd0ed29@redhat.com>

On 12/24/25 8:45 AM, Frederic Weisbecker wrote:
> Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
> ---
>   Documentation/core-api/housekeeping.rst | 111 ++++++++++++++++++++++++
>   Documentation/core-api/index.rst        |   1 +
>   2 files changed, 112 insertions(+)
>   create mode 100644 Documentation/core-api/housekeeping.rst
>
> diff --git a/Documentation/core-api/housekeeping.rst b/Documentation/core-api/housekeeping.rst
> new file mode 100644
> index 000000000000..e5417302774c
> --- /dev/null
> +++ b/Documentation/core-api/housekeeping.rst
> @@ -0,0 +1,111 @@
> +======================================
> +Housekeeping
> +======================================
> +
> +
> +CPU Isolation moves away kernel work that may otherwise run on any CPU.
> +The purpose of its related features is to reduce the OS jitter that some
> +extreme workloads can't stand, such as in some DPDK usecases.
Nit: "usecases" => "use cases"
> +
> +The kernel work moved away by CPU isolation is commonly described as
> +"housekeeping" because it includes ground work that performs cleanups,
> +statistics maintainance and actions relying on them, memory release,
> +various deferrals etc...
> +
> +Sometimes housekeeping is just some unbound work (unbound workqueues,
> +unbound timers, ...) that gets easily assigned to non-isolated CPUs.
> +But sometimes housekeeping is tied to a specific CPU and requires
> +elaborated tricks to be offloaded to non-isolated CPUs (RCU_NOCB, remote
> +scheduler tick, etc...).
> +
> +Thus, a housekeeping CPU can be considered as the reverse of an isolated
> +CPU. It is simply a CPU that can execute housekeeping work. There must
> +always be at least one online housekeeping CPU at any time. The CPUs that
> +are not	isolated are automatically assigned as housekeeping.
Nit: extra white spaces between "not" and "isolated".
> +
> +Housekeeping is currently divided in four features described
> +by the ``enum hk_type type``:
> +
> +1.	HK_TYPE_DOMAIN matches the work moved away by scheduler domain
> +	isolation performed through ``isolcpus=domain`` boot parameter or
> +	isolated cpuset partitions in cgroup v2. This includes scheduler
> +	load balancing, unbound workqueues and timers.
> +
> +2.	HK_TYPE_KERNEL_NOISE matches the work moved away by tick isolation
> +	performed through ``nohz_full=`` or ``isolcpus=nohz`` boot
> +	parameters. This includes remote scheduler tick, vmstat and lockup
> +	watchdog.
> +
> +3.	HK_TYPE_MANAGED_IRQ matches the IRQ handlers moved away by managed
> +	IRQ isolation performed through ``isolcpus=managed_irq``.
> +
> +4.	HK_TYPE_DOMAIN_BOOT matches the work moved away by scheduler domain
> +	isolation performed through ``isolcpus=domain`` only. It is similar
> +	to HK_TYPE_DOMAIN except it ignores the isolation performed by
> +	cpusets.
> +
> +
> +Housekeeping cpumasks
> +=================================
> +
> +Housekeeping cpumasks include the CPUs that can execute the work moved
> +away by the matching isolation feature. These cpumasks are returned by
> +the following function::
> +
> +	const struct cpumask *housekeeping_cpumask(enum hk_type type)
> +
> +By default, if neither ``nohz_full=``, nor ``isolcpus``, nor cpuset's
> +isolated partitions are used, which covers most usecases, this function
> +returns the cpu_possible_mask.
> +
> +Otherwise the function returns the cpumask complement of the isolation
> +feature. For example:
> +
> +With isolcpus=domain,7 the following will return a mask with all possible
> +CPUs except 7::
> +
> +	housekeeping_cpumask(HK_TYPE_DOMAIN)
> +
> +Similarly with nohz_full=5,6 the following will return a mask with all
> +possible CPUs except 5,6::
> +
> +	housekeeping_cpumask(HK_TYPE_KERNEL_NOISE)
> +
> +
> +Synchronization against cpusets
> +=================================
> +
> +Cpuset can modify the HK_TYPE_DOMAIN housekeeping cpumask while creating,
> +modifying or deleting an isolated partition.
> +
> +The users of HK_TYPE_DOMAIN cpumask must then make sure to synchronize
> +properly against cpuset in order to make sure that:
> +
> +1.	The cpumask snapshot stays coherent.
> +
> +2.	No housekeeping work is queued on a newly made isolated CPU.
> +
> +3.	Pending housekeeping work that was queued to a non isolated
> +	CPU which just turned isolated through cpuset must be flushed
> +	before the related created/modified isolated partition is made
> +	available to userspace.
> +
> +This synchronization is maintained by an RCU based scheme. The cpuset update
> +side waits for an RCU grace period after updating the HK_TYPE_DOMAIN
> +cpumask and before flushing pending works. On the read side, care must be
> +taken to gather the housekeeping target election and the work enqueue within
> +the same RCU read side critical section.
> +
> +A typical layout example would look like this on the update side
> +(``housekeeping_update()``)::
> +
> +	rcu_assign_pointer(housekeeping_cpumasks[type], trial);
> +	synchronize_rcu();
> +	flush_workqueue(example_workqueue);
> +
> +And then on the read side::
> +
> +	rcu_read_lock();
> +	cpu = housekeeping_any_cpu(HK_TYPE_DOMAIN);
> +	queue_work_on(cpu, example_workqueue, work);
> +	rcu_read_unlock();
> diff --git a/Documentation/core-api/index.rst b/Documentation/core-api/index.rst
> index 5eb0fbbbc323..79fe7735692e 100644
> --- a/Documentation/core-api/index.rst
> +++ b/Documentation/core-api/index.rst
> @@ -25,6 +25,7 @@ it.
>      symbol-namespaces
>      asm-annotations
>      real-time/index
> +   housekeeping.rst
>   
>   Data structures and low-level utilities
>   =======================================
Acked-by: Waiman Long <longman at redhat.com>



From 21cnbao at gmail.com  Fri Dec 26 14:52:40 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Sat, 27 Dec 2025 11:52:40 +1300
Subject: [PATCH v2 0/8] dma-mapping: arm64: support batched cache sync
Message-ID: <20251226225254.46197-1-21cnbao@gmail.com>

From: Barry Song <baohua at kernel.org>

Many embedded ARM64 SoCs still lack hardware cache coherency support, which
causes DMA mapping operations to appear as hotspots in on-CPU flame graphs.

For an SG list with *nents* entries, the current dma_map/unmap_sg() and DMA
sync APIs perform cache maintenance one entry at a time. After each entry,
the implementation synchronously waits for the corresponding region?s
D-cache operations to complete. On architectures like arm64, efficiency can
be improved by issuing all entries? operations first and then performing a
single batched wait for completion.

Tangquan's results show that batched synchronization can reduce
dma_map_sg() time by 64.61% and dma_unmap_sg() time by 66.60% on an MTK
phone platform (MediaTek Dimensity 9500). The tests were performed by
pinning the task to CPU7 and fixing the CPU frequency at 2.6 GHz,
running dma_map_sg() and dma_unmap_sg() on 10 MB buffers (10 MB / 4 KB
sg entries per buffer) for 200 iterations and then averaging the
results.

I also ran this patch set on an RK3588 Rock5B+ board and
observed that millions of DMA sync operations were batched.

v2:
 * Refine a large amount of arm64 asm code based on feedback from
   Robin, thanks!
 * Drop batch_add APIs and always use arch_sync_dma_for_* + flush,
   even for a single buffer, based on Leon?s suggestion, thanks!
 * Refine a large amount of code based on feedback from Leon, thanks!
 * Also add batch support for iommu_dma_sync_sg_for_{cpu,device}
v1 link:
 https://lore.kernel.org/lkml/20251219053658.84978-1-21cnbao at gmail.com/

v1, diff with RFC:
 * Drop a large number of #ifdef/#else/#endif blocks based on feedback
   from Catalin and Marek, thanks!
 * Also add batched iova link/unlink support, marked as RFC since I lack
   the required hardware. This was suggested by Marek, thanks!
RFC link:
 https://lore.kernel.org/lkml/20251029023115.22809-1-21cnbao at gmail.com/

Barry Song (8):
  arm64: Provide dcache_by_myline_op_nosync helper
  arm64: Provide dcache_clean_poc_nosync helper
  arm64: Provide dcache_inval_poc_nosync helper
  dma-mapping: Separate DMA sync issuing and completion waiting
  dma-mapping: Support batch mode for dma_direct_sync_sg_for_*
  dma-mapping: Support batch mode for dma_direct_{map,unmap}_sg
  dma-iommu: Support DMA sync batch mode for IOVA link and unlink
  dma-iommu: Support DMA sync batch mode for iommu_dma_sync_sg_for_{cpu,
    device}

 arch/arm64/include/asm/assembler.h  | 24 +++++++++---
 arch/arm64/include/asm/cache.h      |  6 +++
 arch/arm64/include/asm/cacheflush.h |  2 +
 arch/arm64/kernel/relocate_kernel.S |  3 +-
 arch/arm64/mm/cache.S               | 57 +++++++++++++++++++++++------
 arch/arm64/mm/dma-mapping.c         |  4 +-
 drivers/iommu/dma-iommu.c           | 35 ++++++++++++++----
 drivers/xen/swiotlb-xen.c           | 24 ++++++++----
 include/linux/dma-map-ops.h         |  6 +++
 kernel/dma/direct.c                 | 23 +++++++++---
 kernel/dma/direct.h                 | 21 ++++++++---
 kernel/dma/mapping.c                |  6 +--
 kernel/dma/swiotlb.c                |  4 +-
 13 files changed, 165 insertions(+), 50 deletions(-)

Cc: Leon Romanovsky <leon at kernel.org>
Cc: Marek Szyprowski <m.szyprowski at samsung.com>
Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Will Deacon <will at kernel.org>
Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
Cc: Ard Biesheuvel <ardb at kernel.org>
Cc: Marc Zyngier <maz at kernel.org>
Cc: Anshuman Khandual <anshuman.khandual at arm.com>
Cc: Ryan Roberts <ryan.roberts at arm.com>
Cc: Suren Baghdasaryan <surenb at google.com>
Cc: Robin Murphy <robin.murphy at arm.com>
Cc: Joerg Roedel <joro at 8bytes.org>
Cc: Juergen Gross <jgross at suse.com>
Cc: Stefano Stabellini <sstabellini at kernel.org>
Cc: Oleksandr Tyshchenko <oleksandr_tyshchenko at epam.com>
Cc: Tangquan Zheng <zhengtangquan at oppo.com>
Cc: Huacai Zhou <zhouhuacai at oppo.com>
--
2.43.0



From royluo at google.com  Fri Dec 26 16:53:27 2025
From: royluo at google.com (Roy Luo)
Date: Sat, 27 Dec 2025 00:53:27 +0000
Subject: [PATCH v10 0/2] Add Google Tensor SoC USB PHY support
Message-ID: <20251227-phyb4-v10-0-e8caf6b93fe7@google.com>

This series introduces USB PHY support for the Google Tensor G5
SoC (codename: Laguna), a new generation of Google silicon first
launched with Pixel 10 devices.

The Tensor G5 represents a significant architectural overhaul compared
to previous Tensor generations (e.g., gs101), which were based on Samsung
Exynos IP. Although the G5 still utilizes Synopsys IP for the USB
components, the custom top-level integration introduces a completely new
design for clock, reset scheme, register interfaces and programming
sequence, necessitating new drivers and device tree bindings.

The USB subsystem on Tensor G5 integrates a Synopsys DWC3 USB 3.1
DRD-Single Port controller with hibernation support, and a custom PHY
block comprising Synopsys eUSB2 and USB 3.2/DP combo PHYs. The controller
support is sent as a separate patch series.

Co-developed-by: Joy Chakraborty <joychakr at google.com>
Signed-off-by: Joy Chakraborty <joychakr at google.com>
Co-developed-by: Naveen Kumar <mnkumar at google.com>
Signed-off-by: Naveen Kumar <mnkumar at google.com>
Signed-off-by: Roy Luo <royluo at google.com>
---
Changes in v10:
- Alphabetically sort Kconfig and Makefile (some of the existing entries are
  out of order but they are not in the scope of this change).
- Updated index, num_clks, and num_rsts in struct google_usb_phy_instance to
  use unsigned int.
- Replaced the fixed-size array of PHY instances in struct google_usb_phy
  with a dynamically allocated pointer. Since container_of can no longer
  be used with the pointer, added a parent pointer to google_usb_phy_instance
  to reference the main google_usb_phy structure.
- Removed the superfluous init of ret in google_usb2_phy_init.
- Ensured google_usb2_phy_init explicitly returns 0 upon successful completion.
Link to v9: https://lore.kernel.org/r/20251222-phyb4-v9-0-82c0b671b070 at google.com

Changes in v9:
- Per Greg's feedback, remove Kconfig dependency on ARCH_GOOGLE || COMPILE_TEST.
  Remove ARCH_GOOGLE as it's not yet in the kernel, and COMPILE_TEST is no longer needed without it.
Link to v8: https://lore.kernel.org/r/20251205-phyb4-v8-0-c59ea80a4458 at google.com

Changes in v8:
- Update the Kconfig dependency to depends on ARCH_GOOGLE || COMPILE_TEST
  Note that ARCH_GOOGLE does not exist yet but will eventually
  be there when the following patch lands
  https://lore.kernel.org/r/20251111112158.3.I35b9e835ac49ab408e5ca3e0983930a1f1395814 at changeid/
- Mention SoC codename Laguna in Kconfig description.
- Sort the header alphabetically and sort the variables using the
  reverse christmas tree ordering.
- Add driver and binding files to the Tensor SoC MAINTAINER entry.
- Add detailed comment for phy_mutex
Link to v7: https://lore.kernel.org/r/20251121-phyb4-v7-0-df644fa62180 at google.com

Changes in v7:
- Change the device tree binding example node name to usb-phy to follow
 the hyphen-separated naming convention and remove label.
Link to v6: https://lore.kernel.org/r/20251120-phyb4-v6-0-b6694e1f0caf at google.com

Changes in v6:
- Use "lga" as SoC name instead of "gs5" to align with Tensor G5 device
  tree https://lore.kernel.org/lkml/20251111192422.4180216-1-dianders at chromium.org 
- Add "usb2_core" to the reg property to define the MMIO space for
  the eUSB 2.0 PHY IP.
- Rename "usb3_top" reg as "usbdp_top" and update the description to
  reflect its nature as a top-level wrapper and align with internal
  documentation.
- Use syscon to access the "usb2_cfg" MMIO space.
- Remove minItems for clocks and resets, making all listed clocks and
  resets (including USB3) mandatory.
Link to v5: https://lore.kernel.org/linux-phy/20251029214032.3175261-1-royluo at google.com

Changes in v5:
- Add usb3 registers/clks/resets to binding as suggested by Krzysztof
  Kozlowski. This ensures completeness of the binding, though the
  driver has not yet ultilized the resources. The usb3 clks and resets
  are optional if usb2-only operation is desired, this is denoted by
  minItems and descriptions in the clocks and resets properties.
  Additionally, rename existing binding entries for consistency and to
  better differntiate between usb2 and usb3.
- Move the description of the phy select to phy-cells in binding as
  suggested by Krzysztof Kozlowski.
Link to v4: https://lore.kernel.org/linux-phy/20251017235159.2417576-1-royluo at google.com

Changes in v4:
- Separate controller and phy changes into two distinct patch series.
- Remove usb2only mode configuration and the corresponding usb_top_cfg
  reg (moved to controller)
- Add more descriptions to dp_top reg to indicate it's not DP specific.
- Add u2phy_apb clk/reset
Link to v3: https://lore.kernel.org/linux-usb/20251010201607.1190967-1-royluo at google.com

Changes in v3:
- Align binding file name with the compatible string
- Simplify the compatible property in binding to a single const value.
- Add descriptive comments and use item list in binding.
- Rename binding entries for clarity and brevity.
Link to v2: https://lore.kernel.org/linux-usb/20251008060000.3136021-1-royluo at google.com

Changes in v2:
- Reorder patches to present bindings first.
- Update dt binding compatible strings to be SoC-specific (google,gs5-*).
- Better describe the hardware in dt binding commit messages and
  descriptions.
- Adjust PHY driver commit subjects to use correct prefixes ("phy:").
- Move PHY driver from a subdirectory to drivers/phy/.
Link to v1: https://lore.kernel.org/linux-usb/20251006232125.1833979-1-royluo at google.com/

---
Roy Luo (2):
      dt-bindings: phy: google: Add Google Tensor G5 USB PHY
      phy: Add Google Tensor SoC USB PHY driver

 .../bindings/phy/google,lga-usb-phy.yaml           | 133 +++++++++
 MAINTAINERS                                        |   2 +
 drivers/phy/Kconfig                                |  10 +
 drivers/phy/Makefile                               |   1 +
 drivers/phy/phy-google-usb.c                       | 296 +++++++++++++++++++++
 5 files changed, 442 insertions(+)
---
base-commit: 3f0e9c8cefa913dd9bd1d79b9a68896ea130f106
change-id: 20251119-phyb4-2e03a7c449c4

Best regards,
-- 
Roy Luo <royluo at google.com>



From royluo at google.com  Fri Dec 26 16:53:28 2025
From: royluo at google.com (Roy Luo)
Date: Sat, 27 Dec 2025 00:53:28 +0000
Subject: [PATCH v10 1/2] dt-bindings: phy: google: Add Google Tensor G5 USB PHY
In-Reply-To: <20251227-phyb4-v10-0-e8caf6b93fe7@google.com>
References: <20251227-phyb4-v10-0-e8caf6b93fe7@google.com>
Message-ID: <20251227-phyb4-v10-1-e8caf6b93fe7@google.com>

Document the device tree bindings for the USB PHY interfaces integrated
with the DWC3 controller on Google Tensor SoCs, starting with G5
generation (Laguna). The USB PHY on Tensor G5 includes two integrated
Synopsys PHY IPs: the eUSB 2.0 PHY IP and the USB 3.2/DisplayPort combo
PHY IP.

Due to a complete architectural overhaul in the Google Tensor G5, the
existing Samsung/Exynos USB PHY binding for older generations of Google
silicons such as gs101 are no longer compatible, necessitating this new
device tree binding.

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
Signed-off-by: Roy Luo <royluo at google.com>
---
 .../bindings/phy/google,lga-usb-phy.yaml           | 133 +++++++++++++++++++++
 MAINTAINERS                                        |   1 +
 2 files changed, 134 insertions(+)

diff --git a/Documentation/devicetree/bindings/phy/google,lga-usb-phy.yaml b/Documentation/devicetree/bindings/phy/google,lga-usb-phy.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..427e2e3425f645f40c0813e29d6efe4f62b20609
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/google,lga-usb-phy.yaml
@@ -0,0 +1,133 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2025, Google LLC
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/google,lga-usb-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Google Tensor Series G5 (Laguna) USB PHY
+
+maintainers:
+  - Roy Luo <royluo at google.com>
+
+description:
+  Describes the USB PHY interfaces integrated with the DWC3 USB controller on
+  Google Tensor SoCs, starting with the G5 generation (laguna).
+  Two specific PHY IPs from Synopsys are integrated, including eUSB 2.0 PHY IP
+  and USB3.2/DisplayPort combo PHY IP.
+
+properties:
+  compatible:
+    const: google,lga-usb-phy
+
+  reg:
+    items:
+      - description: USB3.2/DisplayPort combo PHY core registers.
+      - description: USB3.2/DisplayPort combo PHY Type-C Assist registers.
+      - description: eUSB 2.0 PHY core registers.
+      - description: Top-level wrapper registers for the integrated PHYs.
+
+  reg-names:
+    items:
+      - const: usb3_core
+      - const: usb3_tca
+      - const: usb2_core
+      - const: usbdp_top
+
+  "#phy-cells":
+    description: |
+      The phandle's argument in the PHY specifier selects one of the three
+      following PHY interfaces.
+      - 0 for USB high-speed.
+      - 1 for USB super-speed.
+      - 2 for DisplayPort.
+    const: 1
+
+  clocks:
+    items:
+      - description: USB2 PHY clock.
+      - description: USB2 PHY APB clock.
+      - description: USB3.2/DisplayPort combo PHY clock.
+      - description: USB3.2/DisplayPort combo PHY firmware clock.
+
+  clock-names:
+    items:
+      - const: usb2
+      - const: usb2_apb
+      - const: usb3
+      - const: usb3_fw
+
+  resets:
+    items:
+      - description: USB2 PHY reset.
+      - description: USB2 PHY APB reset.
+      - description: USB3.2/DisplayPort combo PHY reset.
+
+  reset-names:
+    items:
+      - const: usb2
+      - const: usb2_apb
+      - const: usb3
+
+  power-domains:
+    maxItems: 1
+
+  orientation-switch:
+    type: boolean
+    description:
+      Indicates the PHY as a handler of USB Type-C orientation changes
+
+  google,usb-cfg-csr:
+    description:
+      A phandle to a syscon node used to access the USB configuration
+      registers. These registers are the top-level wrapper of the USB
+      subsystem and provide control and status for the integrated USB
+      controller and USB PHY.
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    items:
+      - items:
+          - description: phandle to the syscon node.
+          - description: USB2 PHY configuration register offset.
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - "#phy-cells"
+  - clocks
+  - clock-names
+  - resets
+  - reset-names
+  - power-domains
+  - orientation-switch
+  - google,usb-cfg-csr
+
+additionalProperties: false
+
+examples:
+  - |
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        usb-phy at c410000 {
+            compatible = "google,lga-usb-phy";
+            reg = <0 0x0c410000 0 0x20000>,
+                  <0 0x0c430000 0 0x1000>,
+                  <0 0x0c440000 0 0x10000>,
+                  <0 0x0c637000 0 0xa0>;
+            reg-names = "usb3_core", "usb3_tca", "usb2_core", "usbdp_top";
+            #phy-cells = <1>;
+            clocks = <&hsion_usb2_phy_clk>, <&hsion_u2phy_apb_clk>,
+                     <&hsion_usb3_phy_clk>, <&hsion_usb3_phy_fw_clk>;
+            clock-names = "usb2", "usb2_apb", "usb3", "usb3_fw";
+            resets = <&hsion_resets_usb2_phy>,
+                     <&hsion_resets_u2phy_apb>,
+                     <&hsion_resets_usb3_phy>;
+            reset-names = "usb2", "usb2_apb", "usb3";
+            power-domains = <&hsio_n_usb_pd>;
+            orientation-switch;
+            google,usb-cfg-csr = <&usb_cfg_csr 0x14>;
+        };
+    };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index dc731d37c8feeff25613c59fe9c929927dadaa7e..faedcf6994e0be0c29c03dc424ca86bc9a1bbd70 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10721,6 +10721,7 @@ S:	Maintained
 P:	Documentation/process/maintainer-soc-clean-dts.rst
 C:	irc://irc.oftc.net/pixel6-kernel-dev
 F:	Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
+F:	Documentation/devicetree/bindings/phy/google,lga-usb-phy.yaml
 F:	Documentation/devicetree/bindings/soc/google/google,gs101-pmu-intr-gen.yaml
 F:	arch/arm64/boot/dts/exynos/google/
 F:	drivers/clk/samsung/clk-gs101.c

-- 
2.52.0.358.g0dd7633a29-goog



From royluo at google.com  Fri Dec 26 16:53:29 2025
From: royluo at google.com (Roy Luo)
Date: Sat, 27 Dec 2025 00:53:29 +0000
Subject: [PATCH v10 2/2] phy: Add Google Tensor SoC USB PHY driver
In-Reply-To: <20251227-phyb4-v10-0-e8caf6b93fe7@google.com>
References: <20251227-phyb4-v10-0-e8caf6b93fe7@google.com>
Message-ID: <20251227-phyb4-v10-2-e8caf6b93fe7@google.com>

Support the USB PHY found on Google Tensor G5 (Laguna). This
particular USB PHY supports both high-speed and super-speed
operations, and is integrated with the SNPS DWC3 controller that's
also on the SoC. This initial patch specifically adds functionality
for high-speed.

Co-developed-by: Joy Chakraborty <joychakr at google.com>
Signed-off-by: Joy Chakraborty <joychakr at google.com>
Co-developed-by: Naveen Kumar <mnkumar at google.com>
Signed-off-by: Naveen Kumar <mnkumar at google.com>
Signed-off-by: Roy Luo <royluo at google.com>
---
 MAINTAINERS                  |   1 +
 drivers/phy/Kconfig          |  10 ++
 drivers/phy/Makefile         |   1 +
 drivers/phy/phy-google-usb.c | 296 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 308 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index faedcf6994e0be0c29c03dc424ca86bc9a1bbd70..f220fbba72391ed8011e02d3e9c0dfe438c9d723 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10725,6 +10725,7 @@ F:	Documentation/devicetree/bindings/phy/google,lga-usb-phy.yaml
 F:	Documentation/devicetree/bindings/soc/google/google,gs101-pmu-intr-gen.yaml
 F:	arch/arm64/boot/dts/exynos/google/
 F:	drivers/clk/samsung/clk-gs101.c
+F:	drivers/phy/phy-google-usb.c
 F:	drivers/soc/samsung/gs101-pmu.c
 F:	drivers/phy/samsung/phy-gs101-ufs.c
 F:	include/dt-bindings/clock/google,gs101*
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 678dd0452f0aa0597773433f04d2a9ba77474d2a..07e71441dece2456423744a1cf90fa4719b6288f 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -25,6 +25,16 @@ config GENERIC_PHY_MIPI_DPHY
 	  Provides a number of helpers a core functions for MIPI D-PHY
 	  drivers to us.
 
+config PHY_GOOGLE_USB
+	tristate "Google Tensor SoC USB PHY driver"
+	select GENERIC_PHY
+	help
+	  Enable support for the USB PHY on Google Tensor SoCs, starting with
+	  the G5 generation (Laguna). This driver provides the PHY interfaces
+	  to interact with the SNPS eUSB2 and USB 3.2/DisplayPort Combo PHY,
+	  both of which are integrated with the DWC3 USB DRD controller.
+	  This driver currently supports USB high-speed.
+
 config PHY_LPC18XX_USB_OTG
 	tristate "NXP LPC18xx/43xx SoC USB OTG PHY driver"
 	depends on OF && (ARCH_LPC18XX || COMPILE_TEST)
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index bfb27fb5a494283d7fd05dd670ebd1b12df8b1a1..1d3a8333ce1512c2ec21012aacd75ddbbea81889 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -6,6 +6,7 @@
 obj-$(CONFIG_GENERIC_PHY)		+= phy-core.o
 obj-$(CONFIG_GENERIC_PHY_MIPI_DPHY)	+= phy-core-mipi-dphy.o
 obj-$(CONFIG_PHY_CAN_TRANSCEIVER)	+= phy-can-transceiver.o
+obj-$(CONFIG_PHY_GOOGLE_USB)		+= phy-google-usb.o
 obj-$(CONFIG_PHY_LPC18XX_USB_OTG)	+= phy-lpc18xx-usb-otg.o
 obj-$(CONFIG_PHY_XGENE)			+= phy-xgene.o
 obj-$(CONFIG_PHY_PISTACHIO_USB)		+= phy-pistachio-usb.o
diff --git a/drivers/phy/phy-google-usb.c b/drivers/phy/phy-google-usb.c
new file mode 100644
index 0000000000000000000000000000000000000000..ab20bc20f19eae2268ad62f9d8be4387f9bad92d
--- /dev/null
+++ b/drivers/phy/phy-google-usb.c
@@ -0,0 +1,296 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * phy-google-usb.c - Google USB PHY driver
+ *
+ * Copyright (C) 2025, Google LLC
+ */
+
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/usb/typec_mux.h>
+
+#define USBCS_USB2PHY_CFG19_OFFSET 0x0
+#define USBCS_USB2PHY_CFG19_PHY_CFG_PLL_FB_DIV GENMASK(19, 8)
+
+#define USBCS_USB2PHY_CFG21_OFFSET 0x8
+#define USBCS_USB2PHY_CFG21_PHY_ENABLE BIT(12)
+#define USBCS_USB2PHY_CFG21_REF_FREQ_SEL GENMASK(15, 13)
+#define USBCS_USB2PHY_CFG21_PHY_TX_DIG_BYPASS_SEL BIT(19)
+
+#define USBCS_PHY_CFG1_OFFSET 0x28
+#define USBCS_PHY_CFG1_SYS_VBUSVALID BIT(17)
+
+enum google_usb_phy_id {
+	GOOGLE_USB2_PHY,
+	GOOGLE_USB_PHY_NUM,
+};
+
+struct google_usb_phy_instance {
+	struct google_usb_phy *parent;
+	unsigned int index;
+	struct phy *phy;
+	unsigned int num_clks;
+	struct clk_bulk_data *clks;
+	unsigned int num_rsts;
+	struct reset_control_bulk_data *rsts;
+};
+
+struct google_usb_phy {
+	struct device *dev;
+	struct regmap *usb_cfg_regmap;
+	unsigned int usb2_cfg_offset;
+	void __iomem *usbdp_top_base;
+	struct google_usb_phy_instance *insts;
+	/*
+	 * Protect phy registers from concurrent access, specifically via
+	 * google_usb_set_orientation callback.
+	 */
+	struct mutex phy_mutex;
+	struct typec_switch_dev *sw;
+	enum typec_orientation orientation;
+};
+
+static void set_vbus_valid(struct google_usb_phy *gphy)
+{
+	u32 reg;
+
+	if (gphy->orientation == TYPEC_ORIENTATION_NONE) {
+		reg = readl(gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+		reg &= ~USBCS_PHY_CFG1_SYS_VBUSVALID;
+		writel(reg, gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+	} else {
+		reg = readl(gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+		reg |= USBCS_PHY_CFG1_SYS_VBUSVALID;
+		writel(reg, gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+	}
+}
+
+static int google_usb_set_orientation(struct typec_switch_dev *sw,
+				      enum typec_orientation orientation)
+{
+	struct google_usb_phy *gphy = typec_switch_get_drvdata(sw);
+
+	dev_dbg(gphy->dev, "set orientation %d\n", orientation);
+
+	gphy->orientation = orientation;
+
+	if (pm_runtime_suspended(gphy->dev))
+		return 0;
+
+	guard(mutex)(&gphy->phy_mutex);
+
+	set_vbus_valid(gphy);
+
+	return 0;
+}
+
+static int google_usb2_phy_init(struct phy *_phy)
+{
+	struct google_usb_phy_instance *inst = phy_get_drvdata(_phy);
+	struct google_usb_phy *gphy = inst->parent;
+	u32 reg;
+	int ret;
+
+	dev_dbg(gphy->dev, "initializing usb2 phy\n");
+
+	guard(mutex)(&gphy->phy_mutex);
+
+	regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, &reg);
+	reg &= ~USBCS_USB2PHY_CFG21_PHY_TX_DIG_BYPASS_SEL;
+	reg &= ~USBCS_USB2PHY_CFG21_REF_FREQ_SEL;
+	reg |= FIELD_PREP(USBCS_USB2PHY_CFG21_REF_FREQ_SEL, 0);
+	regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, reg);
+
+	regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG19_OFFSET, &reg);
+	reg &= ~USBCS_USB2PHY_CFG19_PHY_CFG_PLL_FB_DIV;
+	reg |= FIELD_PREP(USBCS_USB2PHY_CFG19_PHY_CFG_PLL_FB_DIV, 368);
+	regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG19_OFFSET, reg);
+
+	set_vbus_valid(gphy);
+
+	ret = clk_bulk_prepare_enable(inst->num_clks, inst->clks);
+	if (ret)
+		return ret;
+
+	ret = reset_control_bulk_deassert(inst->num_rsts, inst->rsts);
+	if (ret) {
+		clk_bulk_disable_unprepare(inst->num_clks, inst->clks);
+		return ret;
+	}
+
+	regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, &reg);
+	reg |= USBCS_USB2PHY_CFG21_PHY_ENABLE;
+	regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, reg);
+
+	return 0;
+}
+
+static int google_usb2_phy_exit(struct phy *_phy)
+{
+	struct google_usb_phy_instance *inst = phy_get_drvdata(_phy);
+	struct google_usb_phy *gphy = inst->parent;
+	u32 reg;
+
+	dev_dbg(gphy->dev, "exiting usb2 phy\n");
+
+	guard(mutex)(&gphy->phy_mutex);
+
+	regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, &reg);
+	reg &= ~USBCS_USB2PHY_CFG21_PHY_ENABLE;
+	regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, reg);
+
+	reset_control_bulk_assert(inst->num_rsts, inst->rsts);
+	clk_bulk_disable_unprepare(inst->num_clks, inst->clks);
+
+	return 0;
+}
+
+static const struct phy_ops google_usb2_phy_ops = {
+	.init		= google_usb2_phy_init,
+	.exit		= google_usb2_phy_exit,
+};
+
+static struct phy *google_usb_phy_xlate(struct device *dev,
+					const struct of_phandle_args *args)
+{
+	struct google_usb_phy *gphy = dev_get_drvdata(dev);
+
+	if (args->args[0] >= GOOGLE_USB_PHY_NUM) {
+		dev_err(dev, "invalid PHY index requested from DT\n");
+		return ERR_PTR(-ENODEV);
+	}
+	return gphy->insts[args->args[0]].phy;
+}
+
+static int google_usb_phy_probe(struct platform_device *pdev)
+{
+	struct typec_switch_desc sw_desc = { };
+	struct google_usb_phy_instance *inst;
+	struct phy_provider *phy_provider;
+	struct device *dev = &pdev->dev;
+	struct google_usb_phy *gphy;
+	struct phy *phy;
+	u32 args[1];
+	int ret;
+
+	gphy = devm_kzalloc(dev, sizeof(*gphy), GFP_KERNEL);
+	if (!gphy)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, gphy);
+	gphy->dev = dev;
+
+	ret = devm_mutex_init(dev, &gphy->phy_mutex);
+	if (ret)
+		return ret;
+
+	gphy->usb_cfg_regmap =
+		syscon_regmap_lookup_by_phandle_args(dev->of_node,
+						     "google,usb-cfg-csr",
+						     ARRAY_SIZE(args), args);
+	if (IS_ERR(gphy->usb_cfg_regmap)) {
+		return dev_err_probe(dev, PTR_ERR(gphy->usb_cfg_regmap),
+				     "invalid usb cfg csr\n");
+	}
+
+	gphy->usb2_cfg_offset = args[0];
+
+	gphy->usbdp_top_base = devm_platform_ioremap_resource_byname(pdev,
+								     "usbdp_top");
+	if (IS_ERR(gphy->usbdp_top_base))
+		return dev_err_probe(dev, PTR_ERR(gphy->usbdp_top_base),
+				    "invalid usbdp top\n");
+
+	gphy->insts = devm_kcalloc(dev, GOOGLE_USB_PHY_NUM, sizeof(*gphy->insts), GFP_KERNEL);
+	if (!gphy->insts)
+		return -ENOMEM;
+
+	inst = &gphy->insts[GOOGLE_USB2_PHY];
+	inst->parent = gphy;
+	inst->index = GOOGLE_USB2_PHY;
+	phy = devm_phy_create(dev, NULL, &google_usb2_phy_ops);
+	if (IS_ERR(phy))
+		return dev_err_probe(dev, PTR_ERR(phy),
+				     "failed to create usb2 phy instance\n");
+	inst->phy = phy;
+	phy_set_drvdata(phy, inst);
+
+	inst->num_clks = 2;
+	inst->clks = devm_kcalloc(dev, inst->num_clks, sizeof(*inst->clks), GFP_KERNEL);
+	if (!inst->clks)
+		return -ENOMEM;
+	inst->clks[0].id = "usb2";
+	inst->clks[1].id = "usb2_apb";
+	ret = devm_clk_bulk_get(dev, inst->num_clks, inst->clks);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to get u2 phy clks\n");
+
+	inst->num_rsts = 2;
+	inst->rsts = devm_kcalloc(dev, inst->num_rsts, sizeof(*inst->rsts), GFP_KERNEL);
+	if (!inst->rsts)
+		return -ENOMEM;
+	inst->rsts[0].id = "usb2";
+	inst->rsts[1].id = "usb2_apb";
+	ret = devm_reset_control_bulk_get_exclusive(dev, inst->num_rsts, inst->rsts);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to get u2 phy resets\n");
+
+	phy_provider = devm_of_phy_provider_register(dev, google_usb_phy_xlate);
+	if (IS_ERR(phy_provider))
+		return dev_err_probe(dev, PTR_ERR(phy_provider),
+				     "failed to register phy provider\n");
+
+	pm_runtime_enable(dev);
+
+	sw_desc.fwnode = dev_fwnode(dev);
+	sw_desc.drvdata = gphy;
+	sw_desc.name = fwnode_get_name(dev_fwnode(dev));
+	sw_desc.set = google_usb_set_orientation;
+
+	gphy->sw = typec_switch_register(dev, &sw_desc);
+	if (IS_ERR(gphy->sw))
+		return dev_err_probe(dev, PTR_ERR(gphy->sw),
+				     "failed to register typec switch\n");
+
+	return 0;
+}
+
+static void google_usb_phy_remove(struct platform_device *pdev)
+{
+	struct google_usb_phy *gphy = dev_get_drvdata(&pdev->dev);
+
+	typec_switch_unregister(gphy->sw);
+	pm_runtime_disable(&pdev->dev);
+}
+
+static const struct of_device_id google_usb_phy_of_match[] = {
+	{
+		.compatible = "google,lga-usb-phy",
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, google_usb_phy_of_match);
+
+static struct platform_driver google_usb_phy = {
+	.probe	= google_usb_phy_probe,
+	.remove = google_usb_phy_remove,
+	.driver = {
+		.name		= "google-usb-phy",
+		.of_match_table	= google_usb_phy_of_match,
+	}
+};
+
+module_platform_driver(google_usb_phy);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Google USB phy driver");

-- 
2.52.0.358.g0dd7633a29-goog



From ye.zhang at rock-chips.com  Fri Dec 26 18:40:45 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Sat, 27 Dec 2025 10:40:45 +0800
Subject: [PATCH v3 6/7] dt-bindings: pinctrl: rockchip: Add RMIO
 controller binding
In-Reply-To: <CAD++jLntu4LY=VHOMSXeLKXOBD9MTNziv47B0qkDjxUa1xAsng@mail.gmail.com>
References: <20251216112053.1927852-1-ye.zhang@rock-chips.com>
 <20251216112053.1927852-7-ye.zhang@rock-chips.com>
 <CAD++jLntu4LY=VHOMSXeLKXOBD9MTNziv47B0qkDjxUa1xAsng@mail.gmail.com>
Message-ID: <85032ae4-4d82-4884-aa7c-b69fee76d509@rock-chips.com>


? 2025/12/27 2:07, Linus Walleij ??:
> Hi Ye,
>
> thanks for your patch!
>
> On Tue, Dec 16, 2025 at 3:50?PM Ye Zhang <ye.zhang at rock-chips.com> wrote:
>
>
>> diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml b/Documentation/devicetree/bindings/pinctrl/rockchip,rmio.yaml
>> +  rockchip,rmio-grf:
>> +    $ref: /schemas/types.yaml#/definitions/phandle
>> +    description:
>> +      The phandle of the syscon node (GRF or PMU) containing the RMIO registers.
>> +      This property is required if the RMIO registers are located in a different
>> +      syscon than the parent pinctrl node.
>> +
>> +  rockchip,offset:
>> +    $ref: /schemas/types.yaml#/definitions/uint32
>> +    description:
>> +      The offset of the RMIO configuration registers within the GRF.
> Can't this just be a cell in the phandle?
In my upcoming v4, it will be moved into the driver code.
>> +  rockchip,pins-num:
>> +    $ref: /schemas/types.yaml#/definitions/uint32
>> +    description:
>> +      The number of physical pins supported by this RMIO instance.
>> +      Used for boundary checking and driver initialization.
> Isn't this implicit from the compatible? Why is this different
> between two device trees using the same compatible pin
> controller? I don't get it, I think this should be a constant in the
> code based on the compatible instead.
In my upcoming v4, it will be moved into the driver code.
>> +patternProperties:
>> +  "^[a-z0-9-]+$":
>> +    type: object
>> +    description:
>> +      Function node grouping multiple groups.
>> +
>> +    patternProperties:
>> +      "^[a-z0-9-]+$":
>> +        type: object
>> +        description:
>> +          Group node containing the pinmux configuration.
>> +
>> +        properties:
>> +          rockchip,rmio:
>> +            $ref: /schemas/types.yaml#/definitions/uint32-matrix
>> +            description:
>> +              A list of pin-function pairs. The format is <pin_id function_id>.
>> +            minItems: 1
>> +            items:
>> +              items:
>> +                - description: RMIO Pin ID (0 to pins-num - 1)
>> +                  minimum: 0
>> +                  maximum: 31
>> +                - description: Function ID
>> +                  minimum: 0
>> +                  maximum: 98
> Please avoid these custom properties and just use the standard
> "pinmux" property. I don't want any more opaque custom bindings
> for functions and groups.
>
> Reference Documentation/devicetree/bindings/pinctrl/pinmux-node.yaml
> and use pinmux from there.
>
> You can use some shifting and defines to shoehorn your config
> into a single u32 and parse that in your driver; i.e. instead of
> rockchip,rmio = <1, 2>;
> use
> pinmux = <1 << 8 | 2 << 0>;
> these shifter numerals can come from defines.
> In the driver shift & mask out the components you want.
>
> e.g.;
>
>> +            rmio-uart {
>> +                rmio_pin27_uart1_tx: rmio-pin27-uart1-tx {
>> +                    rockchip,rmio = <27 RMIO_UART1_TX>;
> pinmux = <27 << 8 | RMIO_UART1_TX>;

In v4, I will remove rockchip,rmio.yaml

I understand your preference for standard bindings.? However, there is a 
specific constraint here: the RMIO acts as a secondary layer of muxing, 
sitting behind the primary IOMUX controller.

The existing Rockchip pinctrl binding uses the vendor-specific 
rockchip,pins property for the primary IOMUX configuration.? If I were 
to use the standard pinmux property for RMIO, the node would contain 
mixed bindings like this:

node {
 ? ? /* Primary IOMUX (existing binding) */
 ? ? rockchip,pins = <1 RK_PB1 16 &pcfg_pull_none>;
 ? ? /* Secondary RMIO? */
 ? ? pinmux = <(RMIO_ID << 16) | (RMIO_PIN << 8) | RMIO_FUNC>;
};

Since this node describes a single hardware pin configuration that 
requires two separate hardware settings (Primary Mux + Secondary RMIO), 
I thought keeping the secondary config as a vendor-specific property 
(rockchip,rmio) alongside rockchip,pins would be more consistent and 
less confusing than mixing legacy custom bindings with standard pinmux.

In v4, I have removed the separate RMIO child node entirely.? The RMIO 
configuration is now integrated into the main pinctrl group as a 
supplemental property:

node {

rockchip,pins = <1 RK_PB1 7 &pcfg_pull_none>

/* rmio_id pin_id func_id */
rockchip,rmio-pins = <0 24 68>;
};

>
>> +++ b/include/dt-bindings/pinctrl/rockchip,rk3506-rmio.h
> These number dumps are not appreciated inside the bindings
> despite quite a few found their way in there.
>
> Use something like
> arch/*/dts/rockchip/rk3506-rmio-pins.dtsi
> and include that into your device trees instead.
In my upcoming v4, rockchip,rk3506-rmio.h will be removed.


From lkp at intel.com  Fri Dec 26 23:04:09 2025
From: lkp at intel.com (kernel test robot)
Date: Sat, 27 Dec 2025 15:04:09 +0800
Subject: [PATCH v7 14/17] media: rkvdec: Add H264 support for the VDPU381
 variant
In-Reply-To: <20251218232829.337811-15-detlev.casanova@collabora.com>
References: <20251218232829.337811-15-detlev.casanova@collabora.com>
Message-ID: <202512271444.48dPgeMW-lkp@intel.com>

Hi Detlev,

kernel test robot noticed the following build errors:

[auto build test ERROR on media-tree/master]
[also build test ERROR on linus/master v6.19-rc2]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Detlev-Casanova/media-uapi-HEVC-Add-v4l2_ctrl_hevc_ext_sps_-ls-t_rps-controls/20251219-074342
base:   git://linuxtv.org/media_tree.git master
patch link:    https://lore.kernel.org/r/20251218232829.337811-15-detlev.casanova%40collabora.com
patch subject: [PATCH v7 14/17] media: rkvdec: Add H264 support for the VDPU381 variant
config: hexagon-allmodconfig (https://download.01.org/0day-ci/archive/20251227/202512271444.48dPgeMW-lkp at intel.com/config)
compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251227/202512271444.48dPgeMW-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512271444.48dPgeMW-lkp at intel.com/

All errors (new ones prefixed by >>, old ones prefixed by <<):

>> ERROR: modpost: "__hexagon_udivdi3" [drivers/media/platform/rockchip/rkvdec/rockchip-vdec.ko] undefined!

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From sgsu.park at samsung.com  Fri Dec 26 23:06:25 2025
From: sgsu.park at samsung.com (Seongsu Park)
Date: Sat, 27 Dec 2025 16:06:25 +0900
Subject: [PATCH] arm64: Fix PIE_E1 mapping for _PAGE_READONLY_EXEC
References: <CGME20251227070633epcas1p3a8f7c19c9f5114a46765073fa16ba449@epcas1p3.samsung.com>
Message-ID: <20251227070625.217349-1-sgsu.park@samsung.com>

_PAGE_READONLY_EXEC should map to PIE_RX instead of PIE_R in PIE_E1

Signed-off-by: Seongsu Park <sgsu.park at samsung.com>
---
 arch/arm64/include/asm/pgtable-prot.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h
index 161e8660eddd..ca14f61dee81 100644
--- a/arch/arm64/include/asm/pgtable-prot.h
+++ b/arch/arm64/include/asm/pgtable-prot.h
@@ -180,7 +180,7 @@ static inline bool __pure lpa2_is_enabled(void)
 	PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_GCS),           PIE_NONE_O) | \
 	PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_GCS_RO),        PIE_NONE_O) | \
 	PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_EXECONLY),      PIE_NONE_O) | \
-	PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_READONLY_EXEC), PIE_R)      | \
+	PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_READONLY_EXEC), PIE_RX)     | \
 	PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_SHARED_EXEC),   PIE_RW)     | \
 	PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_READONLY),      PIE_R)      | \
 	PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_SHARED),        PIE_RW)     | \
-- 
2.25.1



From zengheng4 at huawei.com  Sat Dec 27 00:10:48 2025
From: zengheng4 at huawei.com (Zeng Heng)
Date: Sat, 27 Dec 2025 16:10:48 +0800
Subject: [PATCH v2 0/45] arm_mpam: Add KVM/arm64 and resctrl glue code
In-Reply-To: <20251219181147.3404071-26-ben.horgan@arm.com>
References: <20251219181147.3404071-1-ben.horgan@arm.com>
 <20251219181147.3404071-26-ben.horgan@arm.com>
Message-ID: <6aa59eae-2632-7e4d-ff6b-565fe5c2649f@huawei.com>

> One major departure from the previous snapshot branches referenced in the
> base driver series is that the same MPAM setting are used for kernel-space
> and user-space. That is, MPAM1_EL1 is set to the same value as MPAM0_EL1
> rather than keeping the default value. The advantages of this are that it
> is closer to the x86 model where the closid is globally applicable, all
> partids are usable from user-space and user-space can't bypass MPAM
> controls by doing the work in the kernel. However, this causes some
> priority inversion where a high priority task waits to take a mutex held by
> another whose resources are restricted by MPAM. It also adds some extra
> isb(). I would be interested in opinions/data on the policy for MPAM in
> kernel space, i.e how MPAM1_EL1 is set.

Another advantage is that, given the small size of the L2 cache,
frequent switching of MPAM configurations between kernel and user modes
can cause cache-capacity jitter, making it difficult to isolate
interference from noisy neighborhood.

However, in addition to the issues mentioned above, updating the
MPAM1_EL1 configuration also exposes interrupt handling to the MPAM
settings of the current task.

I still agree with the current modification of setting MPAM1_EL1 to the
same value as MPAM0_EL1. However, the ARM MPAM hardware supports more
flexible configuration schemes than x86 RDT and another approach is also
worth considering: Software can let a control group choose whether
kernel mode follows the user mode MPAM settings, or whether the kernel
mode configuration is delegated to the default control group, though
this may change the existing user interface.


Best Regards,
Zeng Heng


From alperyasinak1 at gmail.com  Sat Dec 27 00:40:37 2025
From: alperyasinak1 at gmail.com (Alper Ak)
Date: Sat, 27 Dec 2025 11:40:37 +0300
Subject: [PATCH] media: rockchip: rga: Fix possible ERR_PTR dereference in rga_buf_init()
Message-ID: <20251227084038.28679-1-alperyasinak1@gmail.com>

rga_get_frame() can return ERR_PTR(-EINVAL) when buffer type is
unsupported or invalid. rga_buf_init() does not check the return value
and unconditionally dereferences the pointer when accessing f->size.

Add proper ERR_PTR checking and return the error to prevent
dereferencing an invalid pointer.

Fixes: 6040702ade23 ("media: rockchip: rga: allocate DMA descriptors per buffer")
Signed-off-by: Alper Ak <alperyasinak1 at gmail.com>
---
 drivers/media/platform/rockchip/rga/rga-buf.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
index 730bdf98565a..bb575873f2b2 100644
--- a/drivers/media/platform/rockchip/rga/rga-buf.c
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -80,6 +80,9 @@ static int rga_buf_init(struct vb2_buffer *vb)
 	struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type);
 	size_t n_desc = 0;
 
+	if (IS_ERR(f))
+		return PTR_ERR(f);
+
 	n_desc = DIV_ROUND_UP(f->size, PAGE_SIZE);
 
 	rbuf->n_desc = n_desc;
-- 
2.43.0



From skhan at linuxfoundation.org  Sat Dec 27 01:07:24 2025
From: skhan at linuxfoundation.org (Shuah Khan)
Date: Sat, 27 Dec 2025 02:07:24 -0700
Subject: Linux 6.19-rc1 mediatek mt7921e broke badly
Message-ID: <d7f3b00d-beec-41f0-b157-7cfb871f9a46@linuxfoundation.org>

mt7921e doesn't load on my primary laptopn on Linux 6.19-rc1 and problem
still there on 6.19-rc2.

  From what I can tell from dmesg it attempts to do load firmware
in mt792x_load_firmware() during and then generates warns and
fails to load the module. dmesg excerpt below.

commit 066f417be5fd8c7fe581c5550206364735dad7a3
Author: Quan Zhou <quan.zhou at mediatek.com>
Date:   Tue Nov 18 19:54:54 2025 +0800

      wifi: mt76: mt792x: fix wifi init fail by setting MCU_RUNNING after CLC load

The above commit changes when the MCU_RUNNING bit is set in mt7925_run_firmware(),
changing it to set this bit only after mt7921_load_clc() completes.

I didn't get a chance to bisect yet and a quick revert of the patch didn't solve
the problem. This is a serious problem for me since my wifi is dead on my
primary laptop. Hope a fix is coming soon.

I am available for debug/testing help early next week.

thanks,
-- Shuah

dmesg
=====================================================================================

kern  :crit  : kernel BUG at lib/string_helpers.c:1043!
kern  :warn  : Oops: invalid opcode: 0000 [#1] SMP NOPTI
kern  :warn  : CPU: 14 UID: 0 PID: 61 Comm: kworker/14:0 Tainted: G        W
         6.19.0-rc1 #1 PREEMPT(voluntary)
kern  :warn  : Tainted: [W]=WARN
kern  :warn  : Hardware name: Framework Laptop 13 (AMD Ryzen 7040Series)/FRANMDCP07, BIOS 03.16 07/25/2025
kern  :warn  : Workqueue: events mt7921_init_work [mt7921_common]
kern  :warn  : RIP: 0010:__fortify_panic+0xd/0xf
kern  :warn  : Code: 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 40 0f b6 ff e8 c3 55 71 00 <0f> 0b 48 8b 54 24 10 48 8b 74 24 08 4c 89 e9 48 c7 c7 00 a2 d5 a0
kern  :warn  : RSP: 0018:ffffa7a5c03a3d10 EFLAGS: 00010246
kern  :warn  : RAX: ffffffffa0d7aaf2 RBX: 0000000000000000 RCX: ffffffffa0d7aaf2
kern  :warn  : RDX: 0000000000000011 RSI: ffffffffa0d5a170 RDI: ffffffffa128db10
kern  :warn  : RBP: ffff91650ae52060 R08: 0000000000000010 R09: ffffa7a5c31b2000
kern  :warn  : R10: ffffa7a5c03a3bf0 R11: 00000000ffffffff R12: 0000000000000000
kern  :warn  : R13: ffffa7a5c31b2000 R14: 0000000000001000 R15: 0000000000000000
kern  :warn  : FS:  0000000000000000(0000) GS:ffff91743e664000(0000) knlGS:0000000000000000
kern  :warn  : CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
kern  :warn  : CR2: 00007f10786c241c CR3: 00000003eca24000 CR4: 0000000000f50ef0
kern  :warn  : PKRU: 55555554
kern  :warn  : Call Trace:
kern  :warn  :  <TASK>
kern  :warn  :  mt76_connac2_load_patch.cold+0x2b/0xa41 [mt76_connac_lib]
kern  :warn  :  ? srso_alias_return_thunk+0x5/0xfbef5
kern  :warn  :  mt792x_load_firmware+0x36/0x150 [mt792x_lib]
kern  :warn  :  mt7921_run_firmware+0x2c/0x4a0 [mt7921_common]
kern  :warn  :  ? srso_alias_return_thunk+0x5/0xfbef5
kern  :warn  :  ? mt7921_rr+0x12/0x30 [mt7921e]
kern  :warn  :  ? srso_alias_return_thunk+0x5/0xfbef5
kern  :warn  :  ? ____mt76_poll_msec+0x75/0xb0 [mt76]
kern  :warn  :  mt7921e_mcu_init+0x4c/0x7a [mt7921e]
kern  :warn  :  mt7921_init_work+0x51/0x190 [mt7921_common]
kern  :warn  :  process_one_work+0x18b/0x340
kern  :warn  :  worker_thread+0x256/0x3a0
kern  :warn  :  ? __pfx_worker_thread+0x10/0x10
kern  :warn  :  kthread+0xfc/0x240
kern  :warn  :  ? __pfx_kthread+0x10/0x10
kern  :warn  :  ? __pfx_kthread+0x10/0x10
kern  :warn  :  ret_from_fork+0x254/0x290
kern  :warn  :  ? __pfx_kthread+0x10/0x10
kern  :warn  :  ret_from_fork_asm+0x1a/0x30
kern  :warn  :  </TASK>
kern  :warn  : Modules linked in: snd_hda_codec_alc269(+) snd_sof_amd_rembrandt mt7921e snd_hda_scodec_component snd_sof_amd_acp snd_hda_codec_realtek_lib mt7921_common snd_sof_pci snd_sof_xtensa_dsp snd_hda_codec_generic btusb amd_atl mt792x_lib uvcvideo snd_hda_codec_atihdmi intel_rapl_msr mt76_connac_lib snd_sof btrtl intel_rapl_common snd_hda_codec_hdmi btintel videobuf2_vmalloc mt76 videobuf2_memops btbcm uvc snd_sof_utils videobuf2_v4l2 kvm_amd btmtk hid_sensor_als snd_hda_intel mac80211 hid_sensor_trigger snd_soc_core videodev bluetooth snd_hda_codec industrialio_triggered_buffer hid_sensor_iio_common snd_compress videobuf2_common kvm snd_hwdep libarc4 kfifo_buf snd_pci_ps industrialio snd_soc_acpi_amd_match mc snd_hda_core snd_rpl_pci_acp6x irqbypass cfg80211 snd_intel_dspcfg snd_pci_acp6x amd_pmf rapl snd_pci_acp5x snd_pcm amdtee leds_cros_ec snd_rn_pci_acp3x hid_sensor_hub wmi_bmof snd_timer led_class_multicolor snd_acp_config snd_soc_acpi cros_ec_hwmon snd spd5118 ccp snd_pci_acp3x pcspkr platform_profile
kern  :warn  :  soundcore rfkill k10temp ac button amd_sfh tee amd_pmc joydev evdev msr parport_pc ppdev lp parport configfs efi_pstore nfnetlink efivarfs autofs4 ext4 mbcache jbd2 dm_crypt dm_mod usbhid amdgpu amdxcp i2c_algo_bit drm_client_lib drm_ttm_helper ttm ucsi_acpi typec_ucsi drm_exec drm_panel_backlight_quirks roles gpu_sched hid_multitouch typec drm_suballoc_helper drm_buddy hid_generic xhci_pci drm_display_helper cros_ec_debugfs cros_ec_sysfs cros_charge_control cros_ec_chardev cros_kbd_led_backlight i2c_hid_acpi xhci_hcd i2c_hid hid drm_kms_helper sp5100_tco watchdog cros_ec_dev thunderbolt drm usbcore nvme ghash_clmulni_intel cec aesni_intel nvme_core rc_core serio_raw i2c_piix4 i2c_smbus crc16 video usb_common battery wmi cros_ec_lpcs cros_ec cros_ec_proto

From yangjinqian1 at huawei.com  Sat Dec 27 01:24:48 2025
From: yangjinqian1 at huawei.com (Jinqian Yang)
Date: Sat, 27 Dec 2025 17:24:48 +0800
Subject: [PATCH] arm64: Add support for TSV110 Spectre-BHB mitigation
Message-ID: <20251227092448.732059-1-yangjinqian1@huawei.com>

The TSV110 processor is vulnerable to the Spectre-BHB (Branch History
Buffer) attack, which can be exploited to leak information through
branch prediction side channels. This commit adds the MIDR of TSV110
to the list for software mitigation.

Signed-off-by: Jinqian Yang <yangjinqian1 at huawei.com>
---
 arch/arm64/kernel/proton-pack.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/kernel/proton-pack.c b/arch/arm64/kernel/proton-pack.c
index 80a580e019c5..b3801f532b10 100644
--- a/arch/arm64/kernel/proton-pack.c
+++ b/arch/arm64/kernel/proton-pack.c
@@ -887,6 +887,7 @@ static u8 spectre_bhb_loop_affected(void)
 		MIDR_ALL_VERSIONS(MIDR_CORTEX_X2),
 		MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2),
 		MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V1),
+		MIDR_ALL_VERSIONS(MIDR_HISI_TSV110),
 		{},
 	};
 	static const struct midr_range spectre_bhb_k24_list[] = {
-- 
2.33.0



From lkp at intel.com  Sat Dec 27 01:53:46 2025
From: lkp at intel.com (kernel test robot)
Date: Sat, 27 Dec 2025 17:53:46 +0800
Subject: [PATCH] arm64: errata: Workaround for SI L1 downstream coherency
 issue
In-Reply-To: <20251226074106.3751725-1-lucaswei@google.com>
References: <20251226074106.3751725-1-lucaswei@google.com>
Message-ID: <202512271720.e5kDPkoP-lkp@intel.com>

Hi Lucas,

kernel test robot noticed the following build warnings:

[auto build test WARNING on arm64/for-next/core]
[also build test WARNING on arm-perf/for-next/perf arm/for-next arm/fixes kvmarm/next soc/for-next linus/master v6.19-rc2 next-20251219]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Lucas-Wei/arm64-errata-Workaround-for-SI-L1-downstream-coherency-issue/20251226-154541
base:   https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-next/core
patch link:    https://lore.kernel.org/r/20251226074106.3751725-1-lucaswei%40google.com
patch subject: [PATCH] arm64: errata: Workaround for SI L1 downstream coherency issue
config: arm64-randconfig-r123-20251227 (https://download.01.org/0day-ci/archive/20251227/202512271720.e5kDPkoP-lkp at intel.com/config)
compiler: aarch64-linux-gcc (GCC) 8.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251227/202512271720.e5kDPkoP-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512271720.e5kDPkoP-lkp at intel.com/

sparse warnings: (new ones prefixed by >>)
>> arch/arm64/kernel/cpu_errata.c:145:1: sparse: sparse: symbol 'arm_si_l1_workaround_4311569' was not declared. Should it be static?
   arch/arm64/kernel/cpu_errata.c:444:18: sparse: sparse: Initializer entry defined twice
   arch/arm64/kernel/cpu_errata.c:445:17: sparse:   also defined here
   arch/arm64/kernel/cpu_errata.c:450:18: sparse: sparse: Initializer entry defined twice
   arch/arm64/kernel/cpu_errata.c:451:17: sparse:   also defined here
   arch/arm64/kernel/cpu_errata.c:757:17: sparse: sparse: Initializer entry defined twice
   arch/arm64/kernel/cpu_errata.c:758:18: sparse:   also defined here

vim +/arm_si_l1_workaround_4311569 +145 arch/arm64/kernel/cpu_errata.c

   143	
   144	#ifdef CONFIG_ARM64_ERRATUM_4311569
 > 145	DEFINE_STATIC_KEY_FALSE(arm_si_l1_workaround_4311569);
   146	static int __init early_arm_si_l1_workaround_4311569_cfg(char *arg)
   147	{
   148		static_branch_enable(&arm_si_l1_workaround_4311569);
   149		pr_info("Enabling cache maintenance workaround for ARM SI-L1 erratum 4311569\n");
   150	
   151		return 0;
   152	}
   153	early_param("arm_si_l1_workaround_4311569", early_arm_si_l1_workaround_4311569_cfg);
   154	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From krzk at kernel.org  Sat Dec 27 03:17:18 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sat, 27 Dec 2025 12:17:18 +0100
Subject: [PATCH v3 01/15] include: dt-bindings: add LAN969x clock bindings
In-Reply-To: <2025122516245554f59e2e@mail.local>
References: <20251223201921.1332786-1-robert.marko@sartura.hr>
 <20251223201921.1332786-2-robert.marko@sartura.hr>
 <20251224-berserk-mackerel-of-snow-4cae54@quoll>
 <CA+HBbNGym6Q9b166n-P=h_JssOHm0yfyL73JZ+G9P81muK=g4A@mail.gmail.com>
 <78bf252c-fd5e-4a36-b1a3-ca8ed26fde7a@kernel.org>
 <CA+HBbNG+ZVD6grGDp32Ninx7H1AyEbGvP0nwc0zUv94tOV8hYg@mail.gmail.com>
 <d210552f-c8bf-4084-9317-b743075d9946@kernel.org>
 <2025122516245554f59e2e@mail.local>
Message-ID: <20251227-splendid-striped-starfish-ece074@quoll>

On Thu, Dec 25, 2025 at 05:24:55PM +0100, Alexandre Belloni wrote:
> On 25/12/2025 09:47:34+0100, Krzysztof Kozlowski wrote:
> > On 24/12/2025 15:01, Robert Marko wrote:
> > > On Wed, Dec 24, 2025 at 2:05?PM Krzysztof Kozlowski <krzk at kernel.org> wrote:
> > >>
> > >> On 24/12/2025 11:30, Robert Marko wrote:
> > >>> On Wed, Dec 24, 2025 at 11:21?AM Krzysztof Kozlowski <krzk at kernel.org> wrote:
> > >>>>
> > >>>> On Tue, Dec 23, 2025 at 09:16:12PM +0100, Robert Marko wrote:
> > >>>>> Add the required LAN969x clock bindings.
> > >>>>
> > >>>> I do not see clock bindings actually here. Where is the actual binding?
> > >>>> Commit msg does not help me at all to understand why you are doing this
> > >>>> without actual required bindings.
> > >>>
> > >>> I guess it is a bit confusing, there is no schema here, these are the
> > >>> clock indexes that
> > >>> reside in dt-bindings and are used by the SoC DTSI.
> > >>
> > >> I understand as not used by drivers? Then no ABI and there is no point
> > >> in putting them into bindings.
> > > 
> > > It is not included by the driver directly, but it requires these exact
> > > indexes to be passed
> > > so its effectively ABI.
> > 
> > How it requires the exact index? In what way? I do not see anything in
> > the gck driver using/relying on these values. Nothing. Please point me
> > to the line which directly uses these values.... or how many times I
> > will need to write this is not ABI?
> > 
> 
> The index here is the exact id that needs to be set in the PMC_PCR
> register and so it is dictated by the hardware.

So not a binding between Linux and DTS.

Best regards,
Krzysztof



From christianshewitt at gmail.com  Sat Dec 27 03:22:19 2025
From: christianshewitt at gmail.com (Christian Hewitt)
Date: Sat, 27 Dec 2025 11:22:19 +0000
Subject: [PATCH v2] wifi: mt7601u: check multiple firmware paths
Message-ID: <20251227112219.2768439-1-christianshewitt@gmail.com>

The linux-firmware repo moved mt7601u.bin from its root folder to
the mediatek sub-folder some time ago, but the driver still tries
to load firmware from the old location. Users might have firmware
in either location so update the driver to check both.

Signed-off-by: Christian Hewitt <christianshewitt at gmail.com>
---
The firmware was moved in [0]. Changes were requested to a previous
patch [1] to accomodate backwards compatibility but there was no
follow-up from the original author. So here's my novice attempt at
the requested improvement.

Current kernel with firmware in /usr/lib/firmware/mediatek/mt7601u.bin:

Nov 07 12:43:13.398922 LibreELEC kernel: mt7601u 1-1.3:1.0: ASIC revision: 76010001 MAC revision: 76010500
Nov 07 12:43:13.402276 LibreELEC kernel: mt7601u 1-1.3:1.0: Direct firmware load for mt7601u.bin failed with error -2
Nov 07 12:43:13.405524 LibreELEC kernel: mt7601u 1-1.3:1.0: probe with driver mt7601u failed with error -2

And with the patch:

Nov 07 12:43:13.274633 LibreELEC kernel: mt7601u 1-1.3:1.0: ASIC revision: 76010001 MAC revision: 76010500
Nov 07 12:43:13.311200 LibreELEC kernel: mt7601u 1-1.3:1.0: Firmware Version: 0.1.00 Build: 7640 Build time: 201302052146____
Nov 07 12:43:13.704693 LibreELEC kernel: mt7601u 1-1.3:1.0: EEPROM ver:0c fae:00

[0] https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/commit/?id=8451c2b1d529dc1a49328ac9235d3cf5bb8a8fcb
[1] https://patchwork.kernel.org/project/linux-wireless/patch/fefcbf36f13873ae0d97438a0156b87e7e1ae64e.1684191377.git.daniel at makrotopia.org/

Changes since v1:
- Reword patch description and comment to make the problem clearer
- Fix checkpatch warning for static const array declaration

 drivers/net/wireless/mediatek/mt7601u/mcu.c | 15 ++++++++++++++-
 drivers/net/wireless/mediatek/mt7601u/usb.h |  1 +
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt7601u/mcu.c b/drivers/net/wireless/mediatek/mt7601u/mcu.c
index 1b5cc271a9e1..bad6ca821400 100644
--- a/drivers/net/wireless/mediatek/mt7601u/mcu.c
+++ b/drivers/net/wireless/mediatek/mt7601u/mcu.c
@@ -403,12 +403,18 @@ mt7601u_upload_firmware(struct mt7601u_dev *dev, const struct mt76_fw *fw)
 	return ret;
 }
 
+static const char * const mt7601u_fw_paths[] = {
+	"mediatek/" MT7601U_FIRMWARE,
+	MT7601U_FIRMWARE,
+};
+
 static int mt7601u_load_firmware(struct mt7601u_dev *dev)
 {
 	const struct firmware *fw;
 	const struct mt76_fw_header *hdr;
 	int len, ret;
 	u32 val;
+	int i;
 
 	mt7601u_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN |
 					 MT_USB_DMA_CFG_TX_BULK_EN));
@@ -416,7 +422,14 @@ static int mt7601u_load_firmware(struct mt7601u_dev *dev)
 	if (firmware_running(dev))
 		return firmware_request_cache(dev->dev, MT7601U_FIRMWARE);
 
-	ret = request_firmware(&fw, MT7601U_FIRMWARE, dev->dev);
+	/* Try loading firmware from multiple locations */
+	fw = NULL;
+	for (i = 0; i < MT7601U_FIRMWARE_PATHS; i++) {
+		ret = request_firmware(&fw, mt7601u_fw_paths[i], dev->dev);
+		if (ret == 0)
+			break;
+	}
+
 	if (ret)
 		return ret;
 
diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.h b/drivers/net/wireless/mediatek/mt7601u/usb.h
index 9fdf35970339..723025f84483 100644
--- a/drivers/net/wireless/mediatek/mt7601u/usb.h
+++ b/drivers/net/wireless/mediatek/mt7601u/usb.h
@@ -9,6 +9,7 @@
 #include "mt7601u.h"
 
 #define MT7601U_FIRMWARE	"mt7601u.bin"
+#define MT7601U_FIRMWARE_PATHS	ARRAY_SIZE(mt7601u_fw_paths)
 
 #define MT_VEND_REQ_MAX_RETRY	10
 #define MT_VEND_REQ_TOUT_MS	300
-- 
2.34.1


From ye.zhang at rock-chips.com  Sat Dec 27 03:49:51 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Sat, 27 Dec 2025 19:49:51 +0800
Subject: [PATCH v4 1/7] dt-bindings: pinctrl: Add rv1126b pinctrl support
In-Reply-To: <20251227114957.3287944-1-ye.zhang@rock-chips.com>
References: <20251227114957.3287944-1-ye.zhang@rock-chips.com>
Message-ID: <20251227114957.3287944-2-ye.zhang@rock-chips.com>

The RV1126B is a new SoC that is the successor of the RV1126. It has
different pinctrl registers and is not compatible with the RV1126.
Therefore, add a new compatible string for it.

Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
---
 Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
index 125af766b992..97960245676d 100644
--- a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
@@ -51,6 +51,7 @@ properties:
       - rockchip,rk3588-pinctrl
       - rockchip,rv1108-pinctrl
       - rockchip,rv1126-pinctrl
+      - rockchip,rv1126b-pinctrl
 
   rockchip,grf:
     $ref: /schemas/types.yaml#/definitions/phandle
-- 
2.34.1



From ye.zhang at rock-chips.com  Sat Dec 27 03:49:54 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Sat, 27 Dec 2025 19:49:54 +0800
Subject: [PATCH v4 4/7] gpio: rockchip: support new version GPIO
In-Reply-To: <20251227114957.3287944-1-ye.zhang@rock-chips.com>
References: <20251227114957.3287944-1-ye.zhang@rock-chips.com>
Message-ID: <20251227114957.3287944-5-ye.zhang@rock-chips.com>

Support the next version GPIO controller on SoCs like rv1126b.

Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
Acked-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
---
 drivers/gpio/gpio-rockchip.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c
index 47174eb3ba76..c3e831c6bcf1 100644
--- a/drivers/gpio/gpio-rockchip.c
+++ b/drivers/gpio/gpio-rockchip.c
@@ -36,6 +36,7 @@
 #define GPIO_TYPE_V2		(0x01000C2B)
 #define GPIO_TYPE_V2_1		(0x0101157C)
 #define GPIO_TYPE_V2_2		(0x010219C8)
+#define GPIO_TYPE_V2_6          (0x01063F6E)
 
 static const struct rockchip_gpio_regs gpio_regs_v1 = {
 	.port_dr = 0x00,
@@ -674,6 +675,7 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank)
 	case GPIO_TYPE_V2:
 	case GPIO_TYPE_V2_1:
 	case GPIO_TYPE_V2_2:
+	case GPIO_TYPE_V2_6:
 		bank->gpio_regs = &gpio_regs_v2;
 		bank->gpio_type = GPIO_TYPE_V2;
 		bank->db_clk = of_clk_get(bank->of_node, 1);
-- 
2.34.1



From ye.zhang at rock-chips.com  Sat Dec 27 03:49:50 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Sat, 27 Dec 2025 19:49:50 +0800
Subject: [PATCH v4 0/7] pinctrl: rockchip: Add RK3506 and RV1126B pinctrl and RMIO support
Message-ID: <20251227114957.3287944-1-ye.zhang@rock-chips.com>

This series adds pinctrl support for the Rockchip RK3506 and RV1126B SoC,
and adds support for RMIO (Rockchip Matrix I/O).

The series includes:
- RK3506 pinctrl driver implementation
- RV1126B pinctrl driver implementation
- RMIO controller binding and driver support
- GPIO driver update to support new version GPIO

Note on grouping:
The RV1126B support patches are included in this series because the RV1126B
pinctrl driver implementation depends on the PIN_BANK_IOMUX_FLAGS_OFFSET_DRV_FLAGS
macro, which is introduced in the RK3506 support patches. Splitting these
patches into separate series would break the build for RV1126B if applied
independently.

Changes in v4:
- Remove rockchip,rmio.yaml and drop the separate RMIO child node.
- Remove rockchip,rk3506-rmio.h
- Refactor RK3506 RMIO implementation:
  - RMIO is now handled as a separate list within the pin group, allowing
    flexible mapping (e.g., multiple RMIO configs per group).
  - The driver now retrieves the RMIO regmap via a syscon phandle defined
    in the pinctrl node.
- Add RK3506 pinctrl and rmio DTS to match the new RMIO binding format.

Changes in v3:
- Drop already merged patches (rk3506 basic support).
- Remove unhelpful mappings in rockchip,rk3506-rmio.h
- Improve YAML schema: fix constraints and examples for RMIO.

Changes in v2:
- Added RV1126B pinctrl support (patches 3 and 4)
- Updated GPIO driver to support new version GPIO (patch 5)
- Added header file for RK3506 RMIO (patch 6)
- RMIO is now implemented as a separate pinctrl device (patches 7, 8)

Ye Zhang (7):
  dt-bindings: pinctrl: Add rv1126b pinctrl support
  pinctrl: rockchip: Add rv1126b pinctrl support
  arm64: dts: rockchip: rv1126b: Add pinconf and pinctrl dtsi for
    rv1126b
  gpio: rockchip: support new version GPIO
  dt-bindings: pinctrl: rockchip: Add rk3506 rmio support
  pinctrl: rockchip: Add RK3506 RMIO support
  ARM: dts: rockchip: rk3506: Add pinctrl and rmio dtsi for rk3506

 .../bindings/pinctrl/rockchip,pinctrl.yaml    |    25 +
 .../dts/rockchip/rk3506-pinctrl-rmio.dtsi     | 25162 ++++++++++++++++
 .../arm/boot/dts/rockchip/rk3506-pinctrl.dtsi |  1795 ++
 .../boot/dts/rockchip/rv1126b-pinconf.dtsi    |   660 +
 .../boot/dts/rockchip/rv1126b-pinctrl.dtsi    |  3218 ++
 drivers/gpio/gpio-rockchip.c                  |     2 +
 drivers/pinctrl/pinctrl-rockchip.c            |   282 +-
 drivers/pinctrl/pinctrl-rockchip.h            |    20 +
 8 files changed, 31160 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm/boot/dts/rockchip/rk3506-pinctrl-rmio.dtsi
 create mode 100644 arch/arm/boot/dts/rockchip/rk3506-pinctrl.dtsi
 create mode 100644 arch/arm64/boot/dts/rockchip/rv1126b-pinconf.dtsi
 create mode 100644 arch/arm64/boot/dts/rockchip/rv1126b-pinctrl.dtsi

-- 
2.34.1



From ye.zhang at rock-chips.com  Sat Dec 27 03:49:52 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Sat, 27 Dec 2025 19:49:52 +0800
Subject: [PATCH v4 2/7] pinctrl: rockchip: Add rv1126b pinctrl support
In-Reply-To: <20251227114957.3287944-1-ye.zhang@rock-chips.com>
References: <20251227114957.3287944-1-ye.zhang@rock-chips.com>
Message-ID: <20251227114957.3287944-3-ye.zhang@rock-chips.com>

Add gpio and pinctrl support for the 8 GPIO banks on RV1126B.

Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
---
 drivers/pinctrl/pinctrl-rockchip.c | 181 ++++++++++++++++++++++++++++-
 drivers/pinctrl/pinctrl-rockchip.h |   1 +
 2 files changed, 181 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index e44ef262beec..dc7ef12dfcb0 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -307,6 +307,20 @@
 #define RK3588_PIN_BANK_FLAGS(ID, PIN, LABEL, M, P)			\
 	PIN_BANK_IOMUX_FLAGS_PULL_FLAGS(ID, PIN, LABEL, M, M, M, M, P, P, P, P)
 
+#define PIN_BANK_IOMUX_4_OFFSET_DRV_8(id, pins, label, offset0,		\
+				      offset1, offset2, offset3)	\
+	PIN_BANK_IOMUX_FLAGS_OFFSET_DRV_FLAGS(id, pins, label,		\
+					      IOMUX_WIDTH_4BIT,		\
+					      IOMUX_WIDTH_4BIT,		\
+					      IOMUX_WIDTH_4BIT,		\
+					      IOMUX_WIDTH_4BIT,		\
+					      offset0, offset1,		\
+					      offset2, offset3,		\
+					      DRV_TYPE_IO_LEVEL_8_BIT,	\
+					      DRV_TYPE_IO_LEVEL_8_BIT,	\
+					      DRV_TYPE_IO_LEVEL_8_BIT,	\
+					      DRV_TYPE_IO_LEVEL_8_BIT)
+
 static struct regmap_config rockchip_regmap_config = {
 	.reg_bits = 32,
 	.val_bits = 32,
@@ -1701,6 +1715,136 @@ static int rv1126_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank,
 	return 0;
 }
 
+#define RV1126B_DRV_BITS_PER_PIN		8
+#define RV1126B_DRV_PINS_PER_REG		2
+#define RV1126B_DRV_GPIO0_A_OFFSET		0x100
+#define RV1126B_DRV_GPIO0_C_OFFSET		0x8120
+#define RV1126B_DRV_GPIO_OFFSET(GPION)		(0x8100 + GPION * 0x8040)
+
+static int rv1126b_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
+				       int pin_num, struct regmap **regmap,
+				       int *reg, u8 *bit)
+{
+	struct rockchip_pinctrl *info = bank->drvdata;
+
+	*regmap = info->regmap_base;
+	switch (bank->bank_num) {
+	case 0:
+		if (pin_num < 16)
+			*reg = RV1126B_DRV_GPIO0_A_OFFSET;
+		else
+			*reg = RV1126B_DRV_GPIO0_C_OFFSET - 0x20;
+		break;
+
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+	case 6:
+	case 7:
+		*reg = RV1126B_DRV_GPIO_OFFSET(bank->bank_num);
+		break;
+
+	default:
+		dev_err(info->dev, "unsupported bank_num %d\n", bank->bank_num);
+		break;
+	}
+
+	*reg += ((pin_num / RV1126B_DRV_PINS_PER_REG) * 4);
+	*bit = pin_num % RV1126B_DRV_PINS_PER_REG;
+	*bit *= RV1126B_DRV_BITS_PER_PIN;
+
+	return 0;
+}
+
+#define RV1126B_PULL_BITS_PER_PIN		2
+#define RV1126B_PULL_PINS_PER_REG		8
+#define RV1126B_PULL_GPIO0_A_OFFSET		0x300
+#define RV1126B_PULL_GPIO0_C_OFFSET		0x8308
+#define RV1126B_PULL_GPIO_OFFSET(GPION)		(0x8300 + GPION * 0x8010)
+
+static int rv1126b_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
+					int pin_num, struct regmap **regmap,
+					int *reg, u8 *bit)
+{
+	struct rockchip_pinctrl *info = bank->drvdata;
+
+	*regmap = info->regmap_base;
+	switch (bank->bank_num) {
+	case 0:
+		if (pin_num < 16)
+			*reg = RV1126B_PULL_GPIO0_A_OFFSET;
+		else
+			*reg = RV1126B_PULL_GPIO0_C_OFFSET - 0x8;
+		break;
+
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+	case 6:
+	case 7:
+		*reg = RV1126B_PULL_GPIO_OFFSET(bank->bank_num);
+		break;
+
+	default:
+		dev_err(info->dev, "unsupported bank_num %d\n", bank->bank_num);
+		break;
+	}
+
+	*reg += ((pin_num / RV1126B_PULL_PINS_PER_REG) * 4);
+	*bit = pin_num % RV1126B_PULL_PINS_PER_REG;
+	*bit *= RV1126B_PULL_BITS_PER_PIN;
+
+	return 0;
+}
+
+#define RV1126B_SMT_BITS_PER_PIN		1
+#define RV1126B_SMT_PINS_PER_REG		8
+#define RV1126B_SMT_GPIO0_A_OFFSET		0x500
+#define RV1126B_SMT_GPIO0_C_OFFSET		0x8508
+#define RV1126B_SMT_GPIO_OFFSET(GPION)		(0x8500 + GPION * 0x8010)
+
+static int rv1126b_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank,
+					   int pin_num,
+					   struct regmap **regmap,
+					   int *reg, u8 *bit)
+{
+	struct rockchip_pinctrl *info = bank->drvdata;
+
+	*regmap = info->regmap_base;
+	switch (bank->bank_num) {
+	case 0:
+		if (pin_num < 16)
+			*reg = RV1126B_SMT_GPIO0_A_OFFSET;
+		else
+			*reg = RV1126B_SMT_GPIO0_C_OFFSET - 0x8;
+		break;
+
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+	case 6:
+	case 7:
+		*reg = RV1126B_SMT_GPIO_OFFSET(bank->bank_num);
+		break;
+
+	default:
+		dev_err(info->dev, "unsupported bank_num %d\n", bank->bank_num);
+		break;
+	}
+
+	*reg += ((pin_num / RV1126B_SMT_PINS_PER_REG) * 4);
+	*bit = pin_num % RV1126B_SMT_PINS_PER_REG;
+	*bit *= RV1126B_SMT_BITS_PER_PIN;
+
+	return 0;
+}
+
 #define RK3308_SCHMITT_PINS_PER_REG		8
 #define RK3308_SCHMITT_BANK_STRIDE		16
 #define RK3308_SCHMITT_GRF_OFFSET		0x1a0
@@ -3071,7 +3215,8 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank,
 		rmask_bits = RK3588_DRV_BITS_PER_PIN;
 		ret = strength;
 		goto config;
-	} else if (ctrl->type == RK3506 ||
+	} else if (ctrl->type == RV1126B ||
+		   ctrl->type == RK3506 ||
 		   ctrl->type == RK3528 ||
 		   ctrl->type == RK3562 ||
 		   ctrl->type == RK3568) {
@@ -3237,6 +3382,7 @@ static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num)
 				: PIN_CONFIG_BIAS_DISABLE;
 	case PX30:
 	case RV1108:
+	case RV1126B:
 	case RK3188:
 	case RK3288:
 	case RK3308:
@@ -3299,6 +3445,7 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank,
 	case PX30:
 	case RV1108:
 	case RV1126:
+	case RV1126B:
 	case RK3188:
 	case RK3288:
 	case RK3308:
@@ -3582,6 +3729,7 @@ static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl,
 	case PX30:
 	case RV1108:
 	case RV1126:
+	case RV1126B:
 	case RK3188:
 	case RK3288:
 	case RK3308:
@@ -4386,6 +4534,35 @@ static struct rockchip_pin_ctrl rv1126_pin_ctrl = {
 	.schmitt_calc_reg	= rv1126_calc_schmitt_reg_and_bit,
 };
 
+static struct rockchip_pin_bank rv1126b_pin_banks[] = {
+	PIN_BANK_IOMUX_4_OFFSET_DRV_8(0, 32, "gpio0",
+				      0x0, 0x8, 0x8010, 0x8018),
+	PIN_BANK_IOMUX_4_OFFSET_DRV_8(1, 32, "gpio1",
+				      0x10020, 0x10028, 0x10030, 0x10038),
+	PIN_BANK_IOMUX_4_OFFSET_DRV_8(2, 32, "gpio2",
+				      0x18040, 0x18048, 0x18050, 0x18058),
+	PIN_BANK_IOMUX_4_OFFSET_DRV_8(3, 32, "gpio3",
+				      0x20060, 0x20068, 0x20070, 0x20078),
+	PIN_BANK_IOMUX_4_OFFSET_DRV_8(4, 32, "gpio4",
+				      0x28080, 0x28088, 0x28090, 0x28098),
+	PIN_BANK_IOMUX_4_OFFSET_DRV_8(5, 32, "gpio5",
+				      0x300a0, 0x300a8, 0x300b0, 0x300b8),
+	PIN_BANK_IOMUX_4_OFFSET_DRV_8(6, 32, "gpio6",
+				      0x380c0, 0x380c8, 0x380d0, 0x380d8),
+	PIN_BANK_IOMUX_4_OFFSET_DRV_8(7, 32, "gpio7",
+				      0x400e0, 0x400e8, 0x400f0, 0x400f8),
+};
+
+static struct rockchip_pin_ctrl rv1126b_pin_ctrl __maybe_unused = {
+	.pin_banks		= rv1126b_pin_banks,
+	.nr_banks		= ARRAY_SIZE(rv1126b_pin_banks),
+	.label			= "RV1126B-GPIO",
+	.type			= RV1126B,
+	.pull_calc_reg		= rv1126b_calc_pull_reg_and_bit,
+	.drv_calc_reg		= rv1126b_calc_drv_reg_and_bit,
+	.schmitt_calc_reg	= rv1126b_calc_schmitt_reg_and_bit,
+};
+
 static struct rockchip_pin_bank rk2928_pin_banks[] = {
 	PIN_BANK(0, 32, "gpio0"),
 	PIN_BANK(1, 32, "gpio1"),
@@ -4960,6 +5137,8 @@ static const struct of_device_id rockchip_pinctrl_dt_match[] = {
 		.data = &rv1108_pin_ctrl },
 	{ .compatible = "rockchip,rv1126-pinctrl",
 		.data = &rv1126_pin_ctrl },
+	{ .compatible = "rockchip,rv1126b-pinctrl",
+		.data = &rv1126b_pin_ctrl },
 	{ .compatible = "rockchip,rk2928-pinctrl",
 		.data = &rk2928_pin_ctrl },
 	{ .compatible = "rockchip,rk3036-pinctrl",
diff --git a/drivers/pinctrl/pinctrl-rockchip.h b/drivers/pinctrl/pinctrl-rockchip.h
index 4f4aff42a80a..fe18b62ed994 100644
--- a/drivers/pinctrl/pinctrl-rockchip.h
+++ b/drivers/pinctrl/pinctrl-rockchip.h
@@ -187,6 +187,7 @@ enum rockchip_pinctrl_type {
 	PX30,
 	RV1108,
 	RV1126,
+	RV1126B,
 	RK2928,
 	RK3066B,
 	RK3128,
-- 
2.34.1



From ye.zhang at rock-chips.com  Sat Dec 27 03:49:56 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Sat, 27 Dec 2025 19:49:56 +0800
Subject: [PATCH v4 6/7] pinctrl: rockchip: Add RK3506 RMIO support
In-Reply-To: <20251227114957.3287944-1-ye.zhang@rock-chips.com>
References: <20251227114957.3287944-1-ye.zhang@rock-chips.com>
Message-ID: <20251227114957.3287944-7-ye.zhang@rock-chips.com>

On the RK3506 SoC, some pins support a secondary muxing layer via the
RMIO (Rockchip Matrix I/O) block. This allows expanding the number of
available functions for a single physical pin.

The RMIO configuration is stored as a separate list within the pin
group, decoupled from the primary pin list, to support flexible
pin-to-RMIO mapping.

Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
---
 drivers/pinctrl/pinctrl-rockchip.c | 101 ++++++++++++++++++++++++++++-
 drivers/pinctrl/pinctrl-rockchip.h |  19 ++++++
 2 files changed, 117 insertions(+), 3 deletions(-)

diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index dc7ef12dfcb0..e0493b4bb483 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -1414,6 +1414,33 @@ static int rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
 	return ret;
 }
 
+static int rockchip_set_rmio(struct rockchip_pinctrl *info, u32 id, u32 pin, u32 func)
+{
+	struct rockchip_pin_ctrl *ctrl = info->ctrl;
+	struct rockchip_rmio_data *rmio;
+	u32 mask, data, offset;
+	int ret;
+
+	if (id >= ctrl->nr_rmios)
+		return -EINVAL;
+
+	rmio = &ctrl->rmios[id];
+	if (pin >= rmio->nr_pins)
+		return -EINVAL;
+
+	dev_dbg(info->dev, "setting func of rmio%u-%u to %u\n", id, pin, func);
+
+	mask = (1 << rmio->width) - 1;
+	data = (mask << 16) | func;
+	offset = rmio->offset + 4 * pin;
+
+	ret = regmap_write(rmio->regmap, offset, data);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
 #define PX30_PULL_PMU_OFFSET		0x10
 #define PX30_PULL_GRF_OFFSET		0x60
 #define PX30_PULL_BITS_PER_PIN		2
@@ -3660,9 +3687,10 @@ static int rockchip_pmx_set(struct pinctrl_dev *pctldev, unsigned selector,
 	struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
 	const unsigned int *pins = info->groups[group].pins;
 	const struct rockchip_pin_config *data = info->groups[group].data;
+	const struct rockchip_rmio_config *rmio;
 	struct device *dev = info->dev;
 	struct rockchip_pin_bank *bank;
-	int cnt, ret = 0;
+	int cnt, cnt_rmio = 0, ret = 0;
 
 	dev_dbg(dev, "enable function %s group %s\n",
 		info->functions[selector].name, info->groups[group].name);
@@ -3679,6 +3707,17 @@ static int rockchip_pmx_set(struct pinctrl_dev *pctldev, unsigned selector,
 			break;
 	}
 
+	if (cnt != info->groups[group].npins)
+		goto revert_setting;
+
+	for (cnt_rmio = 0; cnt_rmio < info->groups[group].nrmios; cnt_rmio++) {
+		rmio = &info->groups[group].rmios[cnt_rmio];
+		ret = rockchip_set_rmio(info, rmio->id, rmio->pin, rmio->func);
+		if (ret)
+			break;
+	}
+
+revert_setting:
 	if (ret) {
 		/* revert the already done pin settings */
 		for (cnt--; cnt >= 0; cnt--) {
@@ -3689,6 +3728,16 @@ static int rockchip_pmx_set(struct pinctrl_dev *pctldev, unsigned selector,
 		return ret;
 	}
 
+	if (ret && cnt_rmio) {
+		/* revert the already done pin settings */
+		for (cnt_rmio--; cnt_rmio >= 0; cnt_rmio--) {
+			rmio = &info->groups[group].rmios[cnt_rmio];
+			rockchip_set_rmio(info, rmio->id, rmio->pin, 0);
+		}
+
+		return ret;
+	}
+
 	return 0;
 }
 
@@ -4036,6 +4085,32 @@ static int rockchip_pinctrl_parse_groups(struct device_node *np,
 			return ret;
 	}
 
+	/*
+	 * the binding format is rockchip,rmio-pins = <id pin func>,
+	 * do sanity check and calculate pins number
+	 */
+	size = 0;
+	list = of_get_property(np, "rockchip,rmio-pins", &size);
+	if (list && size) {
+		size /= sizeof(*list);
+		if (size % 3)
+			return dev_err_probe(dev, -EINVAL,
+					     "%pOF: rockchip,rmio-pins: expected one or more of <id pin func>, got %d args instead\n",
+					     np, size);
+
+		grp->nrmios = size / 3;
+
+		grp->rmios = devm_kcalloc(dev, grp->nrmios, sizeof(*grp->rmios), GFP_KERNEL);
+		if (!grp->rmios)
+			return -ENOMEM;
+
+		for (i = 0, j = 0; i < size; i += 3, j++) {
+			grp->rmios[j].id = be32_to_cpu(*list++);
+			grp->rmios[j].pin = be32_to_cpu(*list++);
+			grp->rmios[j].func = be32_to_cpu(*list++);
+		}
+	}
+
 	return 0;
 }
 
@@ -4173,10 +4248,11 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data(
 						struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct device_node *node = dev->of_node;
+	struct device_node *node = dev->of_node, *syscon_np;
 	const struct of_device_id *match;
 	struct rockchip_pin_ctrl *ctrl;
 	struct rockchip_pin_bank *bank;
+	struct rockchip_rmio_data *rmio;
 	int grf_offs, pmu_offs, drv_grf_offs, drv_pmu_offs, i, j;
 
 	match = of_match_node(rockchip_pinctrl_dt_match, node);
@@ -4282,6 +4358,19 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data(
 		}
 	}
 
+	rmio = ctrl->rmios;
+	for (i = 0; i < ctrl->nr_rmios; ++i, ++rmio) {
+		syscon_np = of_parse_phandle(node, "rockchip,rmio", i);
+		if (syscon_np) {
+			rmio->regmap = syscon_node_to_regmap(syscon_np);
+			of_node_put(syscon_np);
+			if (IS_ERR(rmio->regmap))
+				return ERR_CAST(rmio->regmap);
+		} else {
+			return ERR_PTR(-EINVAL);
+		}
+	}
+
 	return ctrl;
 }
 
@@ -4353,7 +4442,7 @@ static int rockchip_pinctrl_probe(struct platform_device *pdev)
 	info->dev = dev;
 
 	ctrl = rockchip_pinctrl_get_soc_data(info, pdev);
-	if (!ctrl)
+	if (IS_ERR_OR_NULL(ctrl))
 		return dev_err_probe(dev, -EINVAL, "driver data not available\n");
 	info->ctrl = ctrl;
 
@@ -4941,9 +5030,15 @@ static struct rockchip_pin_bank rk3506_pin_banks[] = {
 				    1, 1, 1, 1),
 };
 
+static struct rockchip_rmio_data rk3506_rmios[] = {
+	{ .nr_pins = 32, .width = 7, .offset = 0x80 },
+};
+
 static struct rockchip_pin_ctrl rk3506_pin_ctrl __maybe_unused = {
 	.pin_banks		= rk3506_pin_banks,
 	.nr_banks		= ARRAY_SIZE(rk3506_pin_banks),
+	.rmios			= rk3506_rmios,
+	.nr_rmios		= ARRAY_SIZE(rk3506_rmios),
 	.label			= "RK3506-GPIO",
 	.type			= RK3506,
 	.pull_calc_reg		= rk3506_calc_pull_reg_and_bit,
diff --git a/drivers/pinctrl/pinctrl-rockchip.h b/drivers/pinctrl/pinctrl-rockchip.h
index fe18b62ed994..c4624df8ce07 100644
--- a/drivers/pinctrl/pinctrl-rockchip.h
+++ b/drivers/pinctrl/pinctrl-rockchip.h
@@ -390,9 +390,18 @@ struct rockchip_mux_route_data {
 	u32 route_val;
 };
 
+struct rockchip_rmio_data {
+	struct regmap			*regmap;
+	u32				nr_pins;
+	u32				width;
+	u32				offset;
+};
+
 struct rockchip_pin_ctrl {
 	struct rockchip_pin_bank	*pin_banks;
 	u32				nr_banks;
+	struct rockchip_rmio_data	*rmios;
+	u32				nr_rmios;
 	u32				nr_pins;
 	char				*label;
 	enum rockchip_pinctrl_type	type;
@@ -416,6 +425,12 @@ struct rockchip_pin_ctrl {
 				    int *reg, u8 *bit);
 };
 
+struct rockchip_rmio_config {
+	u32			id;
+	u32			pin;
+	u32			func;
+};
+
 struct rockchip_pin_config {
 	unsigned int		func;
 	unsigned long		*configs;
@@ -437,12 +452,16 @@ struct rockchip_pin_deferred {
  * @pins: the pins included in this group.
  * @npins: number of pins included in this group.
  * @data: local pin configuration
+ * @nrmios: number of RMIO configurations in this group.
+ * @rmios: list of RMIO configurations for this group.
  */
 struct rockchip_pin_group {
 	const char			*name;
 	unsigned int			npins;
 	unsigned int			*pins;
 	struct rockchip_pin_config	*data;
+	unsigned int			nrmios;
+	struct rockchip_rmio_config	*rmios;
 };
 
 /**
-- 
2.34.1



From ye.zhang at rock-chips.com  Sat Dec 27 03:49:55 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Sat, 27 Dec 2025 19:49:55 +0800
Subject: [PATCH v4 5/7] dt-bindings: pinctrl: rockchip: Add rk3506 rmio support
In-Reply-To: <20251227114957.3287944-1-ye.zhang@rock-chips.com>
References: <20251227114957.3287944-1-ye.zhang@rock-chips.com>
Message-ID: <20251227114957.3287944-6-ye.zhang@rock-chips.com>

The RK3506 SoC introduces a secondary block-level pinmux controller called
RMIO (Rockchip Matrix I/O). When the primary IOMUX is selected to a
specific function, the pin signal is routed to the RMIO block, where a
secondary selection determines the final function.

This patch adds the necessary properties to support RMIO:
- rockchip,rmio: phandle to the RMIO syscon node.
- rockchip,rmio-pins: a matrix to configure the RMIO block.

Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
---
 .../bindings/pinctrl/rockchip,pinctrl.yaml    | 24 +++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
index 97960245676d..887bec22b172 100644
--- a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
@@ -66,6 +66,13 @@ properties:
       Required for at least rk3188 and rk3288. On the rk3368 this should
       point to the PMUGRF syscon.
 
+  rockchip,rmio:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      The phandle of the syscon node for the RMIO registers, used by
+      some SoCs (e.g. rk3506) to configure the secondary block-level
+      pinmux functions.
+
   "#address-cells":
     enum: [1, 2]
 
@@ -144,6 +151,23 @@ additionalProperties:
                 The phandle of a node contains the generic pinconfig options
                 to use as described in pinctrl-bindings.txt.
 
+      rockchip,rmio-pins:
+        $ref: /schemas/types.yaml#/definitions/uint32-matrix
+        minItems: 1
+        items:
+          items:
+            - minimum: 0
+              description: RMIO ID (Controller index)
+            - minimum: 0
+              description: Pin index within the RMIO controller
+            - minimum: 0
+              description: Function Mux ID
+        description:
+          Configuration for the Rockchip Matrix I/O (RMIO) block. The format
+          is <rmio_id pin_id function_id>. This acts as a secondary muxing
+          layer when the primary 'rockchip,pins' mux is set to the RMIO
+          function.
+
 examples:
   - |
     #include <dt-bindings/interrupt-controller/arm-gic.h>
-- 
2.34.1



From ye.zhang at rock-chips.com  Sat Dec 27 03:49:53 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Sat, 27 Dec 2025 19:49:53 +0800
Subject: [PATCH v4 3/7] arm64: dts: rockchip: rv1126b: Add pinconf and pinctrl dtsi for rv1126b
In-Reply-To: <20251227114957.3287944-1-ye.zhang@rock-chips.com>
References: <20251227114957.3287944-1-ye.zhang@rock-chips.com>
Message-ID: <20251227114957.3287944-4-ye.zhang@rock-chips.com>

Add the core pinctrl device tree node and pin definitions for the
Rockchip RV1126B SoC.

Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
---
 .../boot/dts/rockchip/rv1126b-pinconf.dtsi    |  660 ++++
 .../boot/dts/rockchip/rv1126b-pinctrl.dtsi    | 3218 +++++++++++++++++
 2 files changed, 3878 insertions(+)
 create mode 100644 arch/arm64/boot/dts/rockchip/rv1126b-pinconf.dtsi
 create mode 100644 arch/arm64/boot/dts/rockchip/rv1126b-pinctrl.dtsi

diff --git a/arch/arm64/boot/dts/rockchip/rv1126b-pinconf.dtsi b/arch/arm64/boot/dts/rockchip/rv1126b-pinconf.dtsi
new file mode 100644
index 000000000000..0eacbf17a5fe
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rv1126b-pinconf.dtsi
@@ -0,0 +1,660 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2025 Rockchip Electronics Co., Ltd.
+ */
+
+&pinctrl {
+	/omit-if-no-ref/
+	pcfg_pull_up: pcfg-pull-up {
+		bias-pull-up;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down: pcfg-pull-down {
+		bias-pull-down;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none: pcfg-pull-none {
+		bias-disable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_0_25: pcfg-pull-none-drv-level-0-25 {
+		bias-disable;
+		drive-strength = <0x01>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_0_50: pcfg-pull-none-drv-level-0-50 {
+		bias-disable;
+		drive-strength = <0x02>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_0_75: pcfg-pull-none-drv-level-0-75 {
+		bias-disable;
+		drive-strength = <0x03>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_1_00: pcfg-pull-none-drv-level-1-00 {
+		bias-disable;
+		drive-strength = <0x04>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_1_25: pcfg-pull-none-drv-level-1-25 {
+		bias-disable;
+		drive-strength = <0x05>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_1_50: pcfg-pull-none-drv-level-1-50 {
+		bias-disable;
+		drive-strength = <0x06>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_1_75: pcfg-pull-none-drv-level-1-75 {
+		bias-disable;
+		drive-strength = <0x07>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_2_00: pcfg-pull-none-drv-level-2-00 {
+		bias-disable;
+		drive-strength = <0x0c>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_2_25: pcfg-pull-none-drv-level-2-25 {
+		bias-disable;
+		drive-strength = <0x0d>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_2_50: pcfg-pull-none-drv-level-2-50 {
+		bias-disable;
+		drive-strength = <0x0e>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_2_75: pcfg-pull-none-drv-level-2-75 {
+		bias-disable;
+		drive-strength = <0x0f>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_3_00: pcfg-pull-none-drv-level-3-00 {
+		bias-disable;
+		drive-strength = <0x1c>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_3_25: pcfg-pull-none-drv-level-3-25 {
+		bias-disable;
+		drive-strength = <0x1d>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_3_50: pcfg-pull-none-drv-level-3-50 {
+		bias-disable;
+		drive-strength = <0x1e>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_3_75: pcfg-pull-none-drv-level-3-75 {
+		bias-disable;
+		drive-strength = <0x1f>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_4_00: pcfg-pull-none-drv-level-4-00 {
+		bias-disable;
+		drive-strength = <0x2c>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_4_25: pcfg-pull-none-drv-level-4-25 {
+		bias-disable;
+		drive-strength = <0x2d>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_4_50: pcfg-pull-none-drv-level-4-50 {
+		bias-disable;
+		drive-strength = <0x2e>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_4_75: pcfg-pull-none-drv-level-4-75 {
+		bias-disable;
+		drive-strength = <0x2f>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_5_00: pcfg-pull-none-drv-level-5-00 {
+		bias-disable;
+		drive-strength = <0x3c>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_5_25: pcfg-pull-none-drv-level-5-25 {
+		bias-disable;
+		drive-strength = <0x3d>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_5_50: pcfg-pull-none-drv-level-5-50 {
+		bias-disable;
+		drive-strength = <0x3e>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_5_75: pcfg-pull-none-drv-level-5-75 {
+		bias-disable;
+		drive-strength = <0x3f>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_0_25: pcfg-pull-up-drv-level-0-25 {
+		bias-pull-up;
+		drive-strength = <0x01>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_0_50: pcfg-pull-up-drv-level-0-50 {
+		bias-pull-up;
+		drive-strength = <0x02>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_0_75: pcfg-pull-up-drv-level-0-75 {
+		bias-pull-up;
+		drive-strength = <0x03>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_1_00: pcfg-pull-up-drv-level-1-00 {
+		bias-pull-up;
+		drive-strength = <0x04>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_1_25: pcfg-pull-up-drv-level-1-25 {
+		bias-pull-up;
+		drive-strength = <0x05>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_1_50: pcfg-pull-up-drv-level-1-50 {
+		bias-pull-up;
+		drive-strength = <0x06>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_1_75: pcfg-pull-up-drv-level-1-75 {
+		bias-pull-up;
+		drive-strength = <0x07>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_2_00: pcfg-pull-up-drv-level-2-00 {
+		bias-pull-up;
+		drive-strength = <0x0c>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_2_25: pcfg-pull-up-drv-level-2-25 {
+		bias-pull-up;
+		drive-strength = <0x0d>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_2_50: pcfg-pull-up-drv-level-2-50 {
+		bias-pull-up;
+		drive-strength = <0x0e>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_2_75: pcfg-pull-up-drv-level-2-75 {
+		bias-pull-up;
+		drive-strength = <0x0f>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_3_00: pcfg-pull-up-drv-level-3-00 {
+		bias-pull-up;
+		drive-strength = <0x1c>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_3_25: pcfg-pull-up-drv-level-3-25 {
+		bias-pull-up;
+		drive-strength = <0x1d>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_3_50: pcfg-pull-up-drv-level-3-50 {
+		bias-pull-up;
+		drive-strength = <0x1e>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_3_75: pcfg-pull-up-drv-level-3-75 {
+		bias-pull-up;
+		drive-strength = <0x1f>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_4_00: pcfg-pull-up-drv-level-4-00 {
+		bias-pull-up;
+		drive-strength = <0x2c>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_4_25: pcfg-pull-up-drv-level-4-25 {
+		bias-pull-up;
+		drive-strength = <0x2d>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_4_50: pcfg-pull-up-drv-level-4-50 {
+		bias-pull-up;
+		drive-strength = <0x2e>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_4_75: pcfg-pull-up-drv-level-4-75 {
+		bias-pull-up;
+		drive-strength = <0x2f>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_5_00: pcfg-pull-up-drv-level-5-00 {
+		bias-pull-up;
+		drive-strength = <0x3c>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_5_25: pcfg-pull-up-drv-level-5-25 {
+		bias-pull-up;
+		drive-strength = <0x3d>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_5_50: pcfg-pull-up-drv-level-5-50 {
+		bias-pull-up;
+		drive-strength = <0x3e>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_drv_level_5_75: pcfg-pull-up-drv-level-5-75 {
+		bias-pull-up;
+		drive-strength = <0x3f>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_0_25: pcfg-pull-down-drv-level-0-25 {
+		bias-pull-down;
+		drive-strength = <0x01>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_0_50: pcfg-pull-down-drv-level-0-50 {
+		bias-pull-down;
+		drive-strength = <0x02>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_0_75: pcfg-pull-down-drv-level-0-75 {
+		bias-pull-down;
+		drive-strength = <0x03>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_1_00: pcfg-pull-down-drv-level-1-00 {
+		bias-pull-down;
+		drive-strength = <0x04>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_1_25: pcfg-pull-down-drv-level-1-25 {
+		bias-pull-down;
+		drive-strength = <0x05>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_1_50: pcfg-pull-down-drv-level-1-50 {
+		bias-pull-down;
+		drive-strength = <0x06>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_1_75: pcfg-pull-down-drv-level-1-75 {
+		bias-pull-down;
+		drive-strength = <0x07>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_2_00: pcfg-pull-down-drv-level-2-00 {
+		bias-pull-down;
+		drive-strength = <0x0c>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_2_25: pcfg-pull-down-drv-level-2-25 {
+		bias-pull-down;
+		drive-strength = <0x0d>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_2_50: pcfg-pull-down-drv-level-2-50 {
+		bias-pull-down;
+		drive-strength = <0x0e>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_2_75: pcfg-pull-down-drv-level-2-75 {
+		bias-pull-down;
+		drive-strength = <0x0f>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_3_00: pcfg-pull-down-drv-level-3-00 {
+		bias-pull-down;
+		drive-strength = <0x1c>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_3_25: pcfg-pull-down-drv-level-3-25 {
+		bias-pull-down;
+		drive-strength = <0x1d>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_3_50: pcfg-pull-down-drv-level-3-50 {
+		bias-pull-down;
+		drive-strength = <0x1e>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_3_75: pcfg-pull-down-drv-level-3-75 {
+		bias-pull-down;
+		drive-strength = <0x1f>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_4_00: pcfg-pull-down-drv-level-4-00 {
+		bias-pull-down;
+		drive-strength = <0x2c>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_4_25: pcfg-pull-down-drv-level-4-25 {
+		bias-pull-down;
+		drive-strength = <0x2d>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_4_50: pcfg-pull-down-drv-level-4-50 {
+		bias-pull-down;
+		drive-strength = <0x2e>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_4_75: pcfg-pull-down-drv-level-4-75 {
+		bias-pull-down;
+		drive-strength = <0x2f>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_5_00: pcfg-pull-down-drv-level-5-00 {
+		bias-pull-down;
+		drive-strength = <0x3c>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_5_25: pcfg-pull-down-drv-level-5-25 {
+		bias-pull-down;
+		drive-strength = <0x3d>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_5_50: pcfg-pull-down-drv-level-5-50 {
+		bias-pull-down;
+		drive-strength = <0x3e>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_drv_level_5_75: pcfg-pull-down-drv-level-5-75 {
+		bias-pull-down;
+		drive-strength = <0x3f>;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_up_smt: pcfg-pull-up-smt {
+		bias-pull-up;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_down_smt: pcfg-pull-down-smt {
+		bias-pull-down;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_smt: pcfg-pull-none-smt {
+		bias-disable;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_0_25_smt: pcfg-pull-none-drv-level-0-25-smt {
+		bias-disable;
+		drive-strength = <0x01>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_0_50_smt: pcfg-pull-none-drv-level-0-50-smt {
+		bias-disable;
+		drive-strength = <0x02>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_0_75_smt: pcfg-pull-none-drv-level-0-75-smt {
+		bias-disable;
+		drive-strength = <0x03>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_1_00_smt: pcfg-pull-none-drv-level-1-00-smt {
+		bias-disable;
+		drive-strength = <0x04>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_1_25_smt: pcfg-pull-none-drv-level-1-25-smt {
+		bias-disable;
+		drive-strength = <0x05>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_1_50_smt: pcfg-pull-none-drv-level-1-50-smt {
+		bias-disable;
+		drive-strength = <0x06>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_1_75_smt: pcfg-pull-none-drv-level-1-75-smt {
+		bias-disable;
+		drive-strength = <0x07>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_2_00_smt: pcfg-pull-none-drv-level-2-00-smt {
+		bias-disable;
+		drive-strength = <0x0c>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_2_25_smt: pcfg-pull-none-drv-level-2-25-smt {
+		bias-disable;
+		drive-strength = <0x0d>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_2_50_smt: pcfg-pull-none-drv-level-2-50-smt {
+		bias-disable;
+		drive-strength = <0x0e>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_2_75_smt: pcfg-pull-none-drv-level-2-75-smt {
+		bias-disable;
+		drive-strength = <0x0f>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_3_00_smt: pcfg-pull-none-drv-level-3-00-smt {
+		bias-disable;
+		drive-strength = <0x1c>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_3_25_smt: pcfg-pull-none-drv-level-3-25-smt {
+		bias-disable;
+		drive-strength = <0x1d>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_3_50_smt: pcfg-pull-none-drv-level-3-50-smt {
+		bias-disable;
+		drive-strength = <0x1e>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_3_75_smt: pcfg-pull-none-drv-level-3-75-smt {
+		bias-disable;
+		drive-strength = <0x1f>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_4_00_smt: pcfg-pull-none-drv-level-4-00-smt {
+		bias-disable;
+		drive-strength = <0x2c>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_4_25_smt: pcfg-pull-none-drv-level-4-25-smt {
+		bias-disable;
+		drive-strength = <0x2d>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_4_50_smt: pcfg-pull-none-drv-level-4-50-smt {
+		bias-disable;
+		drive-strength = <0x2e>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_4_75_smt: pcfg-pull-none-drv-level-4-75-smt {
+		bias-disable;
+		drive-strength = <0x2f>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_5_00_smt: pcfg-pull-none-drv-level-5-00-smt {
+		bias-disable;
+		drive-strength = <0x3c>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_5_25_smt: pcfg-pull-none-drv-level-5-25-smt {
+		bias-disable;
+		drive-strength = <0x3d>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_5_50_smt: pcfg-pull-none-drv-level-5-50-smt {
+		bias-disable;
+		drive-strength = <0x3e>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_pull_none_drv_level_5_75_smt: pcfg-pull-none-drv-level-5-75-smt {
+		bias-disable;
+		drive-strength = <0x3f>;
+		input-schmitt-enable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_output_high: pcfg-output-high {
+		output-high;
+	};
+
+	/omit-if-no-ref/
+	pcfg_output_high_pull_up: pcfg-output-high-pull-up {
+		output-high;
+		bias-pull-up;
+	};
+
+	/omit-if-no-ref/
+	pcfg_output_high_pull_down: pcfg-output-high-pull-down {
+		output-high;
+		bias-pull-down;
+	};
+
+	/omit-if-no-ref/
+	pcfg_output_high_pull_none: pcfg-output-high-pull-none {
+		output-high;
+		bias-disable;
+	};
+
+	/omit-if-no-ref/
+	pcfg_output_low: pcfg-output-low {
+		output-low;
+	};
+
+	/omit-if-no-ref/
+	pcfg_output_low_pull_up: pcfg-output-low-pull-up {
+		output-low;
+		bias-pull-up;
+	};
+
+	/omit-if-no-ref/
+	pcfg_output_low_pull_down: pcfg-output-low-pull-down {
+		output-low;
+		bias-pull-down;
+	};
+
+	/omit-if-no-ref/
+	pcfg_output_low_pull_none: pcfg-output-low-pull-none {
+		output-low;
+		bias-disable;
+	};
+};
diff --git a/arch/arm64/boot/dts/rockchip/rv1126b-pinctrl.dtsi b/arch/arm64/boot/dts/rockchip/rv1126b-pinctrl.dtsi
new file mode 100644
index 000000000000..f61e7435b4d4
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rv1126b-pinctrl.dtsi
@@ -0,0 +1,3218 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2024 Rockchip Electronics Co., Ltd.
+ */
+
+#include <dt-bindings/pinctrl/rockchip.h>
+#include "rv1126b-pinconf.dtsi"
+
+/*
+ * This file is auto generated by pin2dts tool, please keep these code
+ * by adding changes at end of this file.
+ */
+&pinctrl {
+	aupll_clk {
+		/omit-if-no-ref/
+		aupll_clk_pins: aupll-clk-pins {
+			rockchip,pins =
+				/* aupll_clk_in */
+				<7 RK_PA1 1 &pcfg_pull_none>;
+		};
+	};
+
+	cam_clk0 {
+		/omit-if-no-ref/
+		cam_clk0_pins: cam-clk0-pins {
+			rockchip,pins =
+				/* cam_clk0_out */
+				<4 RK_PB1 3 &pcfg_pull_none>;
+		};
+	};
+
+	cam_clk1 {
+		/omit-if-no-ref/
+		cam_clk1_pins: cam-clk1-pins {
+			rockchip,pins =
+				/* cam_clk1_out */
+				<4 RK_PB0 3 &pcfg_pull_none>;
+		};
+	};
+
+	cam_clk2 {
+		/omit-if-no-ref/
+		cam_clk2_pins: cam-clk2-pins {
+			rockchip,pins =
+				/* cam_clk2_out */
+				<4 RK_PA1 3 &pcfg_pull_none>;
+		};
+	};
+
+	cam_clk3 {
+		/omit-if-no-ref/
+		cam_clk3_pins: cam-clk3-pins {
+			rockchip,pins =
+				/* cam_clk3_out */
+				<4 RK_PA0 3 &pcfg_pull_none>;
+		};
+	};
+
+	can0 {
+		/omit-if-no-ref/
+		can0m0_pins: can0m0-pins {
+			rockchip,pins =
+				/* can0_rxd_m0 */
+				<5 RK_PD4 3 &pcfg_pull_none>,
+				/* can0_txd_m0 */
+				<5 RK_PD5 3 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		can0m1_pins: can0m1-pins {
+			rockchip,pins =
+				/* can0_rxd_m1 */
+				<6 RK_PA0 3 &pcfg_pull_none>,
+				/* can0_txd_m1 */
+				<6 RK_PA1 3 &pcfg_pull_none>;
+		};
+	};
+
+	can1 {
+		/omit-if-no-ref/
+		can1m0_pins: can1m0-pins {
+			rockchip,pins =
+				/* can1_rxd_m0 */
+				<5 RK_PD6 3 &pcfg_pull_none>,
+				/* can1_txd_m0 */
+				<5 RK_PD7 3 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		can1m1_pins: can1m1-pins {
+			rockchip,pins =
+				/* can1_rxd_m1 */
+				<6 RK_PA2 3 &pcfg_pull_none>,
+				/* can1_txd_m1 */
+				<6 RK_PA3 3 &pcfg_pull_none>;
+		};
+	};
+
+	clk {
+		/omit-if-no-ref/
+		clk_pins: clk-pins {
+			rockchip,pins =
+				/* clk_32k */
+				<0 RK_PA2 2 &pcfg_pull_none>;
+		};
+	};
+
+	dsm_aud {
+		/omit-if-no-ref/
+		dsm_aud_ln_pins: dsm-aud-ln-pins {
+			rockchip,pins =
+				/* dsm_aud_ln */
+				<7 RK_PA3 4 &pcfg_pull_down>;
+		};
+
+		/omit-if-no-ref/
+		dsm_aud_lp_pins: dsm-aud-lp-pins {
+			rockchip,pins =
+				/* dsm_aud_lp */
+				<7 RK_PA5 4 &pcfg_pull_down>;
+		};
+
+		/omit-if-no-ref/
+		dsm_aud_rn_pins: dsm-aud-rn-pins {
+			rockchip,pins =
+				/* dsm_aud_rn */
+				<7 RK_PB0 4 &pcfg_pull_down>;
+		};
+
+		/omit-if-no-ref/
+		dsm_aud_rp_pins: dsm-aud-rp-pins {
+			rockchip,pins =
+				/* dsm_aud_rp */
+				<7 RK_PB1 4 &pcfg_pull_down>;
+		};
+	};
+
+	dsmc {
+		/omit-if-no-ref/
+		dsmc_int_pins: dsmc-int-pins {
+			rockchip,pins =
+				/* dsmc_int0 */
+				<5 RK_PB6 5 &pcfg_pull_down>,
+				/* dsmc_int1 */
+				<5 RK_PB2 5 &pcfg_pull_down>;
+		};
+
+		/omit-if-no-ref/
+		dsmc_clk_pins: dsmc-clk-pins {
+			rockchip,pins =
+				/* dsmc_clkn */
+				<5 RK_PB6 4 &pcfg_pull_up>,
+				/* dsmc_resetn */
+				<5 RK_PB2 4 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		dsmc_csn_pins: dsmc-csn-pins {
+			rockchip,pins =
+				/* dsmc_csn0 */
+				<5 RK_PB4 4 &pcfg_pull_up>,
+				/* dsmc_csn1 */
+				<5 RK_PA0 4 &pcfg_pull_up>,
+				/* dsmc_csn2 */
+				<5 RK_PD1 4 &pcfg_pull_up>,
+				/* dsmc_csn3 */
+				<5 RK_PD0 4 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		dsmc_bus16_pins: dsmc-bus16-pins {
+			rockchip,pins =
+				/* dsmc_clkp */
+				<5 RK_PB7 4 &pcfg_pull_down>,
+				/* dsmc_d0 */
+				<5 RK_PC7 4 &pcfg_pull_down>,
+				/* dsmc_d1 */
+				<5 RK_PC6 4 &pcfg_pull_down>,
+				/* dsmc_d2 */
+				<5 RK_PC5 4 &pcfg_pull_down>,
+				/* dsmc_d3 */
+				<5 RK_PC4 4 &pcfg_pull_down>,
+				/* dsmc_d4 */
+				<5 RK_PC3 4 &pcfg_pull_down>,
+				/* dsmc_d5 */
+				<5 RK_PC2 4 &pcfg_pull_down>,
+				/* dsmc_d6 */
+				<5 RK_PC1 4 &pcfg_pull_down>,
+				/* dsmc_d7 */
+				<5 RK_PC0 4 &pcfg_pull_down>,
+				/* dsmc_d8 */
+				<5 RK_PB1 4 &pcfg_pull_down>,
+				/* dsmc_d9 */
+				<5 RK_PB0 4 &pcfg_pull_down>,
+				/* dsmc_d10 */
+				<5 RK_PA7 4 &pcfg_pull_down>,
+				/* dsmc_d11 */
+				<5 RK_PA6 4 &pcfg_pull_down>,
+				/* dsmc_d12 */
+				<5 RK_PA5 4 &pcfg_pull_down>,
+				/* dsmc_d13 */
+				<5 RK_PA4 4 &pcfg_pull_down>,
+				/* dsmc_d14 */
+				<5 RK_PA3 4 &pcfg_pull_down>,
+				/* dsmc_d15 */
+				<5 RK_PA2 4 &pcfg_pull_down>,
+				/* dsmc_dqs0 */
+				<5 RK_PB5 4 &pcfg_pull_down>,
+				/* dsmc_dqs1 */
+				<5 RK_PA1 4 &pcfg_pull_down>,
+				/* dsmc_int2 */
+				<5 RK_PD3 4 &pcfg_pull_down>,
+				/* dsmc_int3 */
+				<5 RK_PD2 4 &pcfg_pull_down>,
+				/* dsmc_rdyn */
+				<5 RK_PB3 4 &pcfg_pull_down>;
+		};
+	};
+
+	emmc {
+		/omit-if-no-ref/
+		emmc_pins: emmc-pins {
+			rockchip,pins =
+				/* emmc_clk */
+				<1 RK_PB3 1 &pcfg_pull_none>,
+				/* emmc_cmd */
+				<1 RK_PB1 1 &pcfg_pull_none>,
+				/* emmc_d0 */
+				<1 RK_PA0 1 &pcfg_pull_none>,
+				/* emmc_d1 */
+				<1 RK_PA1 1 &pcfg_pull_none>,
+				/* emmc_d2 */
+				<1 RK_PA2 1 &pcfg_pull_none>,
+				/* emmc_d3 */
+				<1 RK_PA3 1 &pcfg_pull_none>,
+				/* emmc_d4 */
+				<1 RK_PA4 1 &pcfg_pull_none>,
+				/* emmc_d5 */
+				<1 RK_PA5 1 &pcfg_pull_none>,
+				/* emmc_d6 */
+				<1 RK_PA6 1 &pcfg_pull_none>,
+				/* emmc_d7 */
+				<1 RK_PA7 1 &pcfg_pull_none>;
+		};
+	};
+
+	eth {
+		/omit-if-no-ref/
+		ethm0_miim_pins: ethm0-miim-pins {
+			rockchip,pins =
+				/* eth_mdc_m0 */
+				<6 RK_PC0 2 &pcfg_pull_none_drv_level_3_75>,
+				/* eth_mdio_m0 */
+				<6 RK_PB7 2 &pcfg_pull_none_drv_level_3_75>;
+		};
+
+		/omit-if-no-ref/
+		ethm0_mclk_pins: ethm0-mclk-pins {
+			rockchip,pins =
+				/* eth_mclk_m0 */
+				<6 RK_PB4 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		ethm0_rx_bus2_pins: ethm0-rx-bus2-pins {
+			rockchip,pins =
+				/* eth_rxctl_m0 */
+				<6 RK_PB5 2 &pcfg_pull_none>,
+				/* eth_rxd0_m0 */
+				<6 RK_PB2 2 &pcfg_pull_none>,
+				/* eth_rxd1_m0 */
+				<6 RK_PB3 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		ethm0_tx_bus2_pins: ethm0-tx-bus2-pins {
+			rockchip,pins =
+				/* eth_txctl_m0 */
+				<6 RK_PB1 2 &pcfg_pull_none>,
+				/* eth_txd0_m0 */
+				<6 RK_PA7 2 &pcfg_pull_none_drv_level_3_75>,
+				/* eth_txd1_m0 */
+				<6 RK_PB0 2 &pcfg_pull_none_drv_level_3_75>;
+		};
+
+		/omit-if-no-ref/
+		ethm0_rgmii_clk_pins: ethm0-rgmii-clk-pins {
+			rockchip,pins =
+				/* eth_rxclk_m0 */
+				<6 RK_PC3 2 &pcfg_pull_none>,
+				/* eth_txclk_m0 */
+				<6 RK_PC2 2 &pcfg_pull_none_drv_level_3_75>;
+		};
+
+		/omit-if-no-ref/
+		ethm0_rgmii_bus_pins: ethm0-rgmii-bus-pins {
+			rockchip,pins =
+				/* eth_rxd2_m0 */
+				<6 RK_PA3 2 &pcfg_pull_none>,
+				/* eth_rxd3_m0 */
+				<6 RK_PA4 2 &pcfg_pull_none>,
+				/* eth_txd2_m0 */
+				<6 RK_PA5 2 &pcfg_pull_none_drv_level_3_75>,
+				/* eth_txd3_m0 */
+				<6 RK_PA6 2 &pcfg_pull_none_drv_level_3_75>;
+		};
+
+		/omit-if-no-ref/
+		ethm0_ppsclk_pins: ethm0-ppsclk-pins {
+			rockchip,pins =
+				/* eth_ppsclk_m0 */
+				<6 RK_PA2 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		ethm0_ppstrig_pins: ethm0-ppstrig-pins {
+			rockchip,pins =
+				/* eth_ppstrig_m0 */
+				<6 RK_PA0 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		ethm1_miim_pins: ethm1-miim-pins {
+			rockchip,pins =
+				/* eth_mdc_m1 */
+				<5 RK_PB6 2 &pcfg_pull_none_drv_level_5_00>,
+				/* eth_mdio_m1 */
+				<5 RK_PB5 2 &pcfg_pull_none_drv_level_5_00>;
+		};
+
+		/omit-if-no-ref/
+		ethm1_mclk_pins: ethm1-mclk-pins {
+			rockchip,pins =
+				/* eth_mclk_m1 */
+				<5 RK_PB3 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		ethm1_rx_bus2_pins: ethm1-rx-bus2-pins {
+			rockchip,pins =
+				/* eth_rxctl_m1 */
+				<5 RK_PB0 2 &pcfg_pull_none>,
+				/* eth_rxd0_m1 */
+				<5 RK_PB1 2 &pcfg_pull_none>,
+				/* eth_rxd1_m1 */
+				<5 RK_PB2 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		ethm1_tx_bus2_pins: ethm1-tx-bus2-pins {
+			rockchip,pins =
+				/* eth_txctl_m1 */
+				<5 RK_PC2 2 &pcfg_pull_none>,
+				/* eth_txd0_m1 */
+				<5 RK_PB7 2 &pcfg_pull_none_drv_level_5_00>,
+				/* eth_txd1_m1 */
+				<5 RK_PC0 2 &pcfg_pull_none_drv_level_5_00>;
+		};
+
+		/omit-if-no-ref/
+		ethm1_rgmii_clk_pins: ethm1-rgmii-clk-pins {
+			rockchip,pins =
+				/* eth_rxclk_m1 */
+				<5 RK_PC7 2 &pcfg_pull_none>,
+				/* eth_txclk_m1 */
+				<5 RK_PC6 2 &pcfg_pull_none_drv_level_5_00>;
+		};
+
+		/omit-if-no-ref/
+		ethm1_rgmii_bus_pins: ethm1-rgmii-bus-pins {
+			rockchip,pins =
+				/* eth_rxd2_m1 */
+				<5 RK_PC3 2 &pcfg_pull_none>,
+				/* eth_rxd3_m1 */
+				<5 RK_PC4 2 &pcfg_pull_none>,
+				/* eth_txd2_m1 */
+				<5 RK_PC5 2 &pcfg_pull_none_drv_level_5_00>,
+				/* eth_txd3_m1 */
+				<5 RK_PA0 2 &pcfg_pull_none_drv_level_5_00>;
+		};
+
+		/omit-if-no-ref/
+		ethm1_ppsclk_pins: ethm1-ppsclk-pins {
+			rockchip,pins =
+				/* eth_ppsclk_m1 */
+				<5 RK_PA2 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		ethm1_ppstrig_pins: ethm1-ppstrig-pins {
+			rockchip,pins =
+				/* eth_ppstrig_m1 */
+				<5 RK_PD1 3 &pcfg_pull_none>;
+		};
+	};
+
+	eth_clk_25m {
+		/omit-if-no-ref/
+		eth_clk_25mm0_out_pins: eth-clk-25mm0-out-pins {
+			rockchip,pins =
+				/* eth_clk_25m_out_m0 */
+				<6 RK_PC1 2 &pcfg_pull_none_drv_level_3_75>;
+		};
+
+		/omit-if-no-ref/
+		eth_clk_25mm1_out_pins: eth-clk-25mm1-out-pins {
+			rockchip,pins =
+				/* eth_clk_25m_out_m1 */
+				<5 RK_PC1 2 &pcfg_pull_none_drv_level_5_00>;
+		};
+	};
+
+	eth_ptp {
+		/omit-if-no-ref/
+		ethm0_ptp_refclk_pins: ethm0-ptp-refclk-pins {
+			rockchip,pins =
+				/* ethm0_ptp_refclk */
+				<6 RK_PA1 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		ethm1_ptp_refclk_pins: ethm1-ptp-refclk-pins {
+			rockchip,pins =
+				/* ethm1_ptp_refclk */
+				<5 RK_PD0 3 &pcfg_pull_none>;
+		};
+	};
+
+	fephy {
+		/omit-if-no-ref/
+		fephym0_pins: fephym0-pins {
+			rockchip,pins =
+				/* fephy_ledlink_m0 */
+				<3 RK_PB4 6 &pcfg_pull_none>,
+				/* fephy_ledspd_m0 */
+				<3 RK_PB5 6 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		fephym1_pins: fephym1-pins {
+			rockchip,pins =
+				/* fephy_ledlink_m1 */
+				<5 RK_PD4 1 &pcfg_pull_none>,
+				/* fephy_ledspd_m1 */
+				<5 RK_PD5 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		fephym2_pins: fephym2-pins {
+			rockchip,pins =
+				/* fephy_ledlink_m2 */
+				<6 RK_PC2 3 &pcfg_pull_none>,
+				/* fephy_ledspd_m2 */
+				<6 RK_PC3 3 &pcfg_pull_none>;
+		};
+	};
+
+	flash_trig {
+		/omit-if-no-ref/
+		flash_trig_pins: flash-trig-pins {
+			rockchip,pins =
+				/* flash_trig_out */
+				<3 RK_PB2 6 &pcfg_pull_none>;
+		};
+	};
+
+	fspi0 {
+		/omit-if-no-ref/
+		fspi0_bus4_pins: fspi0-bus4-pins {
+			rockchip,pins =
+				/* fspi0_d0 */
+				<1 RK_PB4 1 &pcfg_pull_none>,
+				/* fspi0_d1 */
+				<1 RK_PB5 1 &pcfg_pull_none>,
+				/* fspi0_d2 */
+				<1 RK_PB2 1 &pcfg_pull_none>,
+				/* fspi0_d3 */
+				<1 RK_PB6 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		fspi0_clk_pins: fspi0-clk-pins {
+			rockchip,pins =
+				/* fspi0_clk */
+				<1 RK_PB7 1 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		fspi0_csn0_pins: fspi0-csn0-pins {
+			rockchip,pins =
+				/* fspi0_csn0 */
+				<1 RK_PB0 1 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		fspi0_csn1_pins: fspi0-csn1-pins {
+			rockchip,pins =
+				/* fspi0_csn1 */
+				<1 RK_PA5 2 &pcfg_pull_none>;
+		};
+	};
+
+	fspi1 {
+		/omit-if-no-ref/
+		fspi1m0_bus4_pins: fspi1m0-bus4-pins {
+			rockchip,pins =
+				/* fspi1_d0_m0 */
+				<0 RK_PB0 1 &pcfg_pull_none>,
+				/* fspi1_d1_m0 */
+				<0 RK_PB1 1 &pcfg_pull_none>,
+				/* fspi1_d2_m0 */
+				<0 RK_PA6 1 &pcfg_pull_none>,
+				/* fspi1_d3_m0 */
+				<0 RK_PA1 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		fspi1m0_clk_pins: fspi1m0-clk-pins {
+			rockchip,pins =
+				/* fspi1m0_clk */
+				<0 RK_PB2 1 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		fspi1m0_csn0_pins: fspi1m0-csn0-pins {
+			rockchip,pins =
+				/* fspi1m0_csn0 */
+				<0 RK_PA7 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		fspi1m1_bus4_pins: fspi1m1-bus4-pins {
+			rockchip,pins =
+				/* fspi1_d0_m1 */
+				<1 RK_PA0 2 &pcfg_pull_none>,
+				/* fspi1_d1_m1 */
+				<1 RK_PA1 2 &pcfg_pull_none>,
+				/* fspi1_d2_m1 */
+				<1 RK_PA2 2 &pcfg_pull_none>,
+				/* fspi1_d3_m1 */
+				<1 RK_PA3 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		fspi1m1_clk_pins: fspi1m1-clk-pins {
+			rockchip,pins =
+				/* fspi1m1_clk */
+				<1 RK_PB3 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		fspi1m1_csn0_pins: fspi1m1-csn0-pins {
+			rockchip,pins =
+				/* fspi1m1_csn0 */
+				<1 RK_PB1 2 &pcfg_pull_none>;
+		};
+	};
+
+	i2c0 {
+		/omit-if-no-ref/
+		i2c0m0_pins: i2c0m0-pins {
+			rockchip,pins =
+				/* i2c0_scl_m0 */
+				<0 RK_PC2 4 &pcfg_pull_none_smt>,
+				/* i2c0_sda_m0 */
+				<0 RK_PC3 4 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c0m1_pins: i2c0m1-pins {
+			rockchip,pins =
+				/* i2c0_scl_m1 */
+				<2 RK_PA1 3 &pcfg_pull_none_smt>,
+				/* i2c0_sda_m1 */
+				<2 RK_PA0 3 &pcfg_pull_none_smt>;
+		};
+	};
+
+	i2c1 {
+		/omit-if-no-ref/
+		i2c1m0_pins: i2c1m0-pins {
+			rockchip,pins =
+				/* i2c1_scl_m0 */
+				<0 RK_PB3 3 &pcfg_pull_none_smt>,
+				/* i2c1_sda_m0 */
+				<0 RK_PB4 3 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c1m1_pins: i2c1m1-pins {
+			rockchip,pins =
+				/* i2c1_scl_m1 */
+				<3 RK_PA2 2 &pcfg_pull_none_smt>,
+				/* i2c1_sda_m1 */
+				<3 RK_PA3 2 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c1m2_pins: i2c1m2-pins {
+			rockchip,pins =
+				/* i2c1_scl_m2 */
+				<4 RK_PA1 6 &pcfg_pull_none_smt>,
+				/* i2c1_sda_m2 */
+				<4 RK_PA0 6 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c1m3_pins: i2c1m3-pins {
+			rockchip,pins =
+				/* i2c1_scl_m3 */
+				<7 RK_PB0 5 &pcfg_pull_none_smt>,
+				/* i2c1_sda_m3 */
+				<7 RK_PB1 5 &pcfg_pull_none_smt>;
+		};
+	};
+
+	i2c2 {
+		/omit-if-no-ref/
+		i2c2m0_pins: i2c2m0-pins {
+			rockchip,pins =
+				/* i2c2_scl_m0 */
+				<0 RK_PD0 1 &pcfg_pull_none_smt>,
+				/* i2c2_sda_m0 */
+				<0 RK_PD1 1 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c2m1_pins: i2c2m1-pins {
+			rockchip,pins =
+				/* i2c2_scl_m1 */
+				<5 RK_PD4 6 &pcfg_pull_none_smt>,
+				/* i2c2_sda_m1 */
+				<5 RK_PD5 6 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c2m2_pins: i2c2m2-pins {
+			rockchip,pins =
+				/* i2c2_scl_m2 */
+				<6 RK_PC0 7 &pcfg_pull_none_smt>,
+				/* i2c2_sda_m2 */
+				<6 RK_PC3 7 &pcfg_pull_none_smt>;
+		};
+	};
+
+	i2c3 {
+		/omit-if-no-ref/
+		i2c3m0_pins: i2c3m0-pins {
+			rockchip,pins =
+				/* i2c3_scl_m0 */
+				<0 RK_PC0 1 &pcfg_pull_none_smt>,
+				/* i2c3_sda_m0 */
+				<0 RK_PC1 1 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c3m1_pins: i2c3m1-pins {
+			rockchip,pins =
+				/* i2c3_scl_m1 */
+				<4 RK_PA4 6 &pcfg_pull_none_smt>,
+				/* i2c3_sda_m1 */
+				<4 RK_PA5 6 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c3m2_pins: i2c3m2-pins {
+			rockchip,pins =
+				/* i2c3_scl_m2 */
+				<5 RK_PD0 6 &pcfg_pull_none_smt>,
+				/* i2c3_sda_m2 */
+				<5 RK_PD1 6 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c3m3_pins: i2c3m3-pins {
+			rockchip,pins =
+				/* i2c3_scl_m3 */
+				<6 RK_PA0 7 &pcfg_pull_none_smt>,
+				/* i2c3_sda_m3 */
+				<6 RK_PA1 7 &pcfg_pull_none_smt>;
+		};
+	};
+
+	i2c4 {
+		/omit-if-no-ref/
+		i2c4m0_pins: i2c4m0-pins {
+			rockchip,pins =
+				/* i2c4_scl_m0 */
+				<3 RK_PB4 5 &pcfg_pull_none_smt>,
+				/* i2c4_sda_m0 */
+				<3 RK_PB5 5 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c4m1_pins: i2c4m1-pins {
+			rockchip,pins =
+				/* i2c4_scl_m1 */
+				<6 RK_PA2 7 &pcfg_pull_none_smt>,
+				/* i2c4_sda_m1 */
+				<6 RK_PA3 7 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c4m2_pins: i2c4m2-pins {
+			rockchip,pins =
+				/* i2c4_scl_m2 */
+				<4 RK_PA7 6 &pcfg_pull_none_smt>,
+				/* i2c4_sda_m2 */
+				<4 RK_PA6 6 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c4m3_pins: i2c4m3-pins {
+			rockchip,pins =
+				/* i2c4_scl_m3 */
+				<7 RK_PA1 2 &pcfg_pull_none_smt>,
+				/* i2c4_sda_m3 */
+				<7 RK_PA4 2 &pcfg_pull_none_smt>;
+		};
+	};
+
+	i2c5 {
+		/omit-if-no-ref/
+		i2c5m0_pins: i2c5m0-pins {
+			rockchip,pins =
+				/* i2c5_scl_m0 */
+				<0 RK_PC4 4 &pcfg_pull_none_smt>,
+				/* i2c5_sda_m0 */
+				<0 RK_PC5 4 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c5m1_pins: i2c5m1-pins {
+			rockchip,pins =
+				/* i2c5_scl_m1 */
+				<3 RK_PB6 5 &pcfg_pull_none_smt>,
+				/* i2c5_sda_m1 */
+				<3 RK_PB7 5 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c5m2_pins: i2c5m2-pins {
+			rockchip,pins =
+				/* i2c5_scl_m2 */
+				<5 RK_PA1 2 &pcfg_pull_none_smt>,
+				/* i2c5_sda_m2 */
+				<5 RK_PA7 6 &pcfg_pull_none_smt>;
+		};
+
+		/omit-if-no-ref/
+		i2c5m3_pins: i2c5m3-pins {
+			rockchip,pins =
+				/* i2c5_scl_m3 */
+				<6 RK_PA4 7 &pcfg_pull_none_smt>,
+				/* i2c5_sda_m3 */
+				<6 RK_PA5 7 &pcfg_pull_none_smt>;
+		};
+	};
+
+	ir_fpa {
+		/omit-if-no-ref/
+		ir_fpa_pins: ir-fpa-pins {
+			rockchip,pins =
+				/* ir_fpa_fsync */
+				<5 RK_PD4 5 &pcfg_pull_none>,
+				/* ir_fpa_mclk */
+				<5 RK_PD5 5 &pcfg_pull_none>,
+				/* ir_fpa_sda0 */
+				<5 RK_PA0 6 &pcfg_pull_none>,
+				/* ir_fpa_sda1 */
+				<5 RK_PA1 6 &pcfg_pull_none>,
+				/* ir_fpa_sda2 */
+				<5 RK_PB0 6 &pcfg_pull_none>,
+				/* ir_fpa_sda3 */
+				<5 RK_PB1 6 &pcfg_pull_none>,
+				/* ir_fpa_sda4 */
+				<5 RK_PC0 6 &pcfg_pull_none>,
+				/* ir_fpa_sda5 */
+				<5 RK_PC1 6 &pcfg_pull_none>,
+				/* ir_fpa_sda6 */
+				<5 RK_PC2 6 &pcfg_pull_none>;
+		};
+	};
+
+	jtag {
+		/omit-if-no-ref/
+		jtagm0_pins: jtagm0-pins {
+			rockchip,pins =
+				/* jtag_tck_m0 */
+				<0 RK_PB3 4 &pcfg_pull_none>,
+				/* jtag_tms_m0 */
+				<0 RK_PB4 4 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		jtagm1_pins: jtagm1-pins {
+			rockchip,pins =
+				/* jtag_tck_m1 */
+				<2 RK_PA2 4 &pcfg_pull_none>,
+				/* jtag_tms_m1 */
+				<2 RK_PA3 4 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		jtagm2_pins: jtagm2-pins {
+			rockchip,pins =
+				/* jtag_tck_m2 */
+				<5 RK_PD6 2 &pcfg_pull_none>,
+				/* jtag_tms_m2 */
+				<5 RK_PD7 2 &pcfg_pull_none>;
+		};
+	};
+
+	pdm {
+		/omit-if-no-ref/
+		pdmm0_clk0_pins: pdmm0-clk0-pins {
+			rockchip,pins =
+				/* pdm_clk0_m0 */
+				<7 RK_PA4 3 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm0_clk1_pins: pdmm0-clk1-pins {
+			rockchip,pins =
+				/* pdm_clk1_m0 */
+				<7 RK_PA1 3 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm0_sdi0_pins: pdmm0-sdi0-pins {
+			rockchip,pins =
+				/* pdm_sdi0_m0 */
+				<7 RK_PA6 3 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm0_sdi1_pins: pdmm0-sdi1-pins {
+			rockchip,pins =
+				/* pdm_sdi1_m0 */
+				<7 RK_PB1 3 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm0_sdi2_pins: pdmm0-sdi2-pins {
+			rockchip,pins =
+				/* pdm_sdi2_m0 */
+				<7 RK_PB0 3 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm0_sdi3_pins: pdmm0-sdi3-pins {
+			rockchip,pins =
+				/* pdm_sdi3_m0 */
+				<7 RK_PA7 3 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm1_clk0_pins: pdmm1-clk0-pins {
+			rockchip,pins =
+				/* pdm_clk0_m1 */
+				<6 RK_PB4 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm1_clk1_pins: pdmm1-clk1-pins {
+			rockchip,pins =
+				/* pdm_clk1_m1 */
+				<6 RK_PB7 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm1_sdi0_pins: pdmm1-sdi0-pins {
+			rockchip,pins =
+				/* pdm_sdi0_m1 */
+				<6 RK_PB5 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm1_sdi1_pins: pdmm1-sdi1-pins {
+			rockchip,pins =
+				/* pdm_sdi1_m1 */
+				<6 RK_PB6 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm1_sdi2_pins: pdmm1-sdi2-pins {
+			rockchip,pins =
+				/* pdm_sdi2_m1 */
+				<6 RK_PB2 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm1_sdi3_pins: pdmm1-sdi3-pins {
+			rockchip,pins =
+				/* pdm_sdi3_m1 */
+				<6 RK_PB3 5 &pcfg_pull_none>;
+		};
+	};
+
+	pmu {
+		/omit-if-no-ref/
+		pmu_pins: pmu-pins {
+			rockchip,pins =
+				/* pmu_dbg */
+				<0 RK_PA2 3 &pcfg_pull_none>;
+		};
+	};
+
+	prelight_trig {
+		/omit-if-no-ref/
+		prelight_trig_pins: prelight-trig-pins {
+			rockchip,pins =
+				/* prelight_trig_out */
+				<3 RK_PB3 6 &pcfg_pull_none>;
+		};
+	};
+
+	preroll {
+		/omit-if-no-ref/
+		preroll_pins: preroll-pins {
+			rockchip,pins =
+				/* preroll_dbg */
+				<0 RK_PB3 5 &pcfg_pull_none>;
+		};
+	};
+
+	pwm0 {
+		/omit-if-no-ref/
+		pwm0m0_ch0_pins: pwm0m0-ch0-pins {
+			rockchip,pins =
+				/* pwm0m0_ch0 */
+				<0 RK_PC4 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m0_ch1_pins: pwm0m0-ch1-pins {
+			rockchip,pins =
+				/* pwm0m0_ch1 */
+				<0 RK_PC5 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m0_ch2_pins: pwm0m0-ch2-pins {
+			rockchip,pins =
+				/* pwm0m0_ch2 */
+				<0 RK_PC6 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m0_ch3_pins: pwm0m0-ch3-pins {
+			rockchip,pins =
+				/* pwm0m0_ch3 */
+				<0 RK_PC7 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m0_ch4_pins: pwm0m0-ch4-pins {
+			rockchip,pins =
+				/* pwm0m0_ch4 */
+				<0 RK_PD0 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m0_ch5_pins: pwm0m0-ch5-pins {
+			rockchip,pins =
+				/* pwm0m0_ch5 */
+				<0 RK_PD1 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m0_ch6_pins: pwm0m0-ch6-pins {
+			rockchip,pins =
+				/* pwm0m0_ch6 */
+				<0 RK_PC1 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m0_ch7_pins: pwm0m0-ch7-pins {
+			rockchip,pins =
+				/* pwm0m0_ch7 */
+				<0 RK_PC0 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pwm0m1_ch0_pins: pwm0m1-ch0-pins {
+			rockchip,pins =
+				/* pwm0m1_ch0 */
+				<5 RK_PA7 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m1_ch1_pins: pwm0m1-ch1-pins {
+			rockchip,pins =
+				/* pwm0m1_ch1 */
+				<5 RK_PA6 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m1_ch2_pins: pwm0m1-ch2-pins {
+			rockchip,pins =
+				/* pwm0m1_ch2 */
+				<5 RK_PA5 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m1_ch3_pins: pwm0m1-ch3-pins {
+			rockchip,pins =
+				/* pwm0m1_ch3 */
+				<5 RK_PA4 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m1_ch4_pins: pwm0m1-ch4-pins {
+			rockchip,pins =
+				/* pwm0m1_ch4 */
+				<4 RK_PA2 4 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m1_ch5_pins: pwm0m1-ch5-pins {
+			rockchip,pins =
+				/* pwm0m1_ch5 */
+				<4 RK_PA3 4 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m1_ch6_pins: pwm0m1-ch6-pins {
+			rockchip,pins =
+				/* pwm0m1_ch6 */
+				<4 RK_PA6 4 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m1_ch7_pins: pwm0m1-ch7-pins {
+			rockchip,pins =
+				/* pwm0m1_ch7 */
+				<4 RK_PA7 4 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pwm0m2_ch0_pins: pwm0m2-ch0-pins {
+			rockchip,pins =
+				/* pwm0m2_ch0 */
+				<6 RK_PC0 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m2_ch1_pins: pwm0m2-ch1-pins {
+			rockchip,pins =
+				/* pwm0m2_ch1 */
+				<6 RK_PC1 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m2_ch2_pins: pwm0m2-ch2-pins {
+			rockchip,pins =
+				/* pwm0m2_ch2 */
+				<6 RK_PC2 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m2_ch3_pins: pwm0m2-ch3-pins {
+			rockchip,pins =
+				/* pwm0m2_ch3 */
+				<6 RK_PC3 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m2_ch4_pins: pwm0m2-ch4-pins {
+			rockchip,pins =
+				/* pwm0m2_ch4 */
+				<5 RK_PA3 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m2_ch5_pins: pwm0m2-ch5-pins {
+			rockchip,pins =
+				/* pwm0m2_ch5 */
+				<5 RK_PA2 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m2_ch6_pins: pwm0m2-ch6-pins {
+			rockchip,pins =
+				/* pwm0m2_ch6 */
+				<5 RK_PD0 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm0m2_ch7_pins: pwm0m2-ch7-pins {
+			rockchip,pins =
+				/* pwm0m2_ch7 */
+				<5 RK_PD4 7 &pcfg_pull_none>;
+		};
+	};
+
+	pwm1 {
+		/omit-if-no-ref/
+		pwm1m0_ch0_pins: pwm1m0-ch0-pins {
+			rockchip,pins =
+				/* pwm1m0_ch0 */
+				<0 RK_PA5 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm1m0_ch1_pins: pwm1m0-ch1-pins {
+			rockchip,pins =
+				/* pwm1m0_ch1 */
+				<0 RK_PA1 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm1m0_ch2_pins: pwm1m0-ch2-pins {
+			rockchip,pins =
+				/* pwm1m0_ch2 */
+				<0 RK_PB3 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm1m0_ch3_pins: pwm1m0-ch3-pins {
+			rockchip,pins =
+				/* pwm1m0_ch3 */
+				<0 RK_PB4 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pwm1m1_ch0_pins: pwm1m1-ch0-pins {
+			rockchip,pins =
+				/* pwm1m1_ch0 */
+				<5 RK_PD3 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm1m1_ch1_pins: pwm1m1-ch1-pins {
+			rockchip,pins =
+				/* pwm1m1_ch1 */
+				<5 RK_PD2 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm1m1_ch2_pins: pwm1m1-ch2-pins {
+			rockchip,pins =
+				/* pwm1m1_ch2 */
+				<5 RK_PD1 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm1m1_ch3_pins: pwm1m1-ch3-pins {
+			rockchip,pins =
+				/* pwm1m1_ch3 */
+				<5 RK_PD5 7 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pwm1m2_ch0_pins: pwm1m2-ch0-pins {
+			rockchip,pins =
+				/* pwm1m2_ch0 */
+				<6 RK_PA0 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm1m2_ch1_pins: pwm1m2-ch1-pins {
+			rockchip,pins =
+				/* pwm1m2_ch1 */
+				<6 RK_PA1 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm1m2_ch2_pins: pwm1m2-ch2-pins {
+			rockchip,pins =
+				/* pwm1m2_ch2 */
+				<6 RK_PA2 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm1m2_ch3_pins: pwm1m2-ch3-pins {
+			rockchip,pins =
+				/* pwm1m2_ch3 */
+				<6 RK_PA3 5 &pcfg_pull_none>;
+		};
+	};
+
+	pwm2 {
+		/omit-if-no-ref/
+		pwm2m0_ch0_pins: pwm2m0-ch0-pins {
+			rockchip,pins =
+				/* pwm2m0_ch0 */
+				<3 RK_PB2 3 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m0_ch1_pins: pwm2m0-ch1-pins {
+			rockchip,pins =
+				/* pwm2m0_ch1 */
+				<3 RK_PB3 3 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m0_ch2_pins: pwm2m0-ch2-pins {
+			rockchip,pins =
+				/* pwm2m0_ch2 */
+				<3 RK_PB4 3 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m0_ch3_pins: pwm2m0-ch3-pins {
+			rockchip,pins =
+				/* pwm2m0_ch3 */
+				<3 RK_PB5 3 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m0_ch4_pins: pwm2m0-ch4-pins {
+			rockchip,pins =
+				/* pwm2m0_ch4 */
+				<5 RK_PA0 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m0_ch5_pins: pwm2m0-ch5-pins {
+			rockchip,pins =
+				/* pwm2m0_ch5 */
+				<5 RK_PA1 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m0_ch6_pins: pwm2m0-ch6-pins {
+			rockchip,pins =
+				/* pwm2m0_ch6 */
+				<5 RK_PD6 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m0_ch7_pins: pwm2m0-ch7-pins {
+			rockchip,pins =
+				/* pwm2m0_ch7 */
+				<5 RK_PD7 7 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pwm2m1_ch0_pins: pwm2m1-ch0-pins {
+			rockchip,pins =
+				/* pwm2m1_ch0 */
+				<5 RK_PB2 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m1_ch1_pins: pwm2m1-ch1-pins {
+			rockchip,pins =
+				/* pwm2m1_ch1 */
+				<5 RK_PB3 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m1_ch2_pins: pwm2m1-ch2-pins {
+			rockchip,pins =
+				/* pwm2m1_ch2 */
+				<5 RK_PB6 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m1_ch3_pins: pwm2m1-ch3-pins {
+			rockchip,pins =
+				/* pwm2m1_ch3 */
+				<5 RK_PB7 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m1_ch4_pins: pwm2m1-ch4-pins {
+			rockchip,pins =
+				/* pwm2m1_ch4 */
+				<7 RK_PA0 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m1_ch5_pins: pwm2m1-ch5-pins {
+			rockchip,pins =
+				/* pwm2m1_ch5 */
+				<7 RK_PA1 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m1_ch6_pins: pwm2m1-ch6-pins {
+			rockchip,pins =
+				/* pwm2m1_ch6 */
+				<7 RK_PA2 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m1_ch7_pins: pwm2m1-ch7-pins {
+			rockchip,pins =
+				/* pwm2m1_ch7 */
+				<7 RK_PA3 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pwm2m2_ch0_pins: pwm2m2-ch0-pins {
+			rockchip,pins =
+				/* pwm2m2_ch0 */
+				<6 RK_PA4 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m2_ch1_pins: pwm2m2-ch1-pins {
+			rockchip,pins =
+				/* pwm2m2_ch1 */
+				<6 RK_PA5 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m2_ch2_pins: pwm2m2-ch2-pins {
+			rockchip,pins =
+				/* pwm2m2_ch2 */
+				<6 RK_PA6 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm2m2_ch3_pins: pwm2m2-ch3-pins {
+			rockchip,pins =
+				/* pwm2m2_ch3 */
+				<6 RK_PA7 3 &pcfg_pull_none>;
+		};
+	};
+
+	pwm3 {
+		/omit-if-no-ref/
+		pwm3m0_ch0_pins: pwm3m0-ch0-pins {
+			rockchip,pins =
+				/* pwm3m0_ch0 */
+				<1 RK_PA0 3 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m0_ch1_pins: pwm3m0-ch1-pins {
+			rockchip,pins =
+				/* pwm3m0_ch1 */
+				<1 RK_PA1 3 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m0_ch2_pins: pwm3m0-ch2-pins {
+			rockchip,pins =
+				/* pwm3m0_ch2 */
+				<1 RK_PA2 3 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m0_ch3_pins: pwm3m0-ch3-pins {
+			rockchip,pins =
+				/* pwm3m0_ch3 */
+				<1 RK_PA3 3 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m0_ch4_pins: pwm3m0-ch4-pins {
+			rockchip,pins =
+				/* pwm3m0_ch4 */
+				<1 RK_PA4 3 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m0_ch5_pins: pwm3m0-ch5-pins {
+			rockchip,pins =
+				/* pwm3m0_ch5 */
+				<1 RK_PA5 3 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m0_ch6_pins: pwm3m0-ch6-pins {
+			rockchip,pins =
+				/* pwm3m0_ch6 */
+				<1 RK_PA6 3 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m0_ch7_pins: pwm3m0-ch7-pins {
+			rockchip,pins =
+				/* pwm3m0_ch7 */
+				<1 RK_PA7 3 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pwm3m1_ch0_pins: pwm3m1-ch0-pins {
+			rockchip,pins =
+				/* pwm3m1_ch0 */
+				<5 RK_PC0 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m1_ch1_pins: pwm3m1-ch1-pins {
+			rockchip,pins =
+				/* pwm3m1_ch1 */
+				<5 RK_PC1 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m1_ch2_pins: pwm3m1-ch2-pins {
+			rockchip,pins =
+				/* pwm3m1_ch2 */
+				<5 RK_PC2 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m1_ch3_pins: pwm3m1-ch3-pins {
+			rockchip,pins =
+				/* pwm3m1_ch3 */
+				<5 RK_PC3 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m1_ch4_pins: pwm3m1-ch4-pins {
+			rockchip,pins =
+				/* pwm3m1_ch4 */
+				<5 RK_PC4 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m1_ch5_pins: pwm3m1-ch5-pins {
+			rockchip,pins =
+				/* pwm3m1_ch5 */
+				<5 RK_PC5 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m1_ch6_pins: pwm3m1-ch6-pins {
+			rockchip,pins =
+				/* pwm3m1_ch6 */
+				<5 RK_PC6 7 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		pwm3m1_ch7_pins: pwm3m1-ch7-pins {
+			rockchip,pins =
+				/* pwm3m1_ch7 */
+				<5 RK_PC7 7 &pcfg_pull_none>;
+		};
+	};
+
+	pwr {
+		/omit-if-no-ref/
+		pwr_pins: pwr-pins {
+			rockchip,pins =
+				/* pwr_ctrl0 */
+				<0 RK_PA3 1 &pcfg_pull_none>,
+				/* pwr_ctrl1 */
+				<0 RK_PA4 1 &pcfg_pull_none>,
+				/* pwr_ctrl2 */
+				<0 RK_PC1 3 &pcfg_pull_none>;
+		};
+	};
+
+	ref_clk0 {
+		/omit-if-no-ref/
+		ref_clk0_pins: ref-clk0-pins {
+			rockchip,pins =
+				/* ref_clk0_out */
+				<0 RK_PA0 1 &pcfg_pull_none>;
+		};
+	};
+
+	rtc_32k {
+		/omit-if-no-ref/
+		rtc_32k_pins: rtc-32k-pins {
+			rockchip,pins =
+				/* rtc_32k_out */
+				<0 RK_PA2 1 &pcfg_pull_none>;
+		};
+	};
+
+	sai0 {
+		/omit-if-no-ref/
+		sai0m0_lrck_pins: sai0m0-lrck-pins {
+			rockchip,pins =
+				/* sai0_lrck_m0 */
+				<7 RK_PA3 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m0_mclk_pins: sai0m0-mclk-pins {
+			rockchip,pins =
+				/* sai0_mclk_m0 */
+				<7 RK_PA2 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m0_sclk_pins: sai0m0-sclk-pins {
+			rockchip,pins =
+				/* sai0_sclk_m0 */
+				<7 RK_PA0 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m0_sdi0_pins: sai0m0-sdi0-pins {
+			rockchip,pins =
+				/* sai0_sdi0_m0 */
+				<7 RK_PA6 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m0_sdi1_pins: sai0m0-sdi1-pins {
+			rockchip,pins =
+				/* sai0_sdi1_m0 */
+				<7 RK_PB1 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m0_sdi2_pins: sai0m0-sdi2-pins {
+			rockchip,pins =
+				/* sai0_sdi2_m0 */
+				<7 RK_PB0 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m0_sdi3_pins: sai0m0-sdi3-pins {
+			rockchip,pins =
+				/* sai0_sdi3_m0 */
+				<7 RK_PA7 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m0_sdo0_pins: sai0m0-sdo0-pins {
+			rockchip,pins =
+				/* sai0_sdo0_m0 */
+				<7 RK_PA5 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m0_sdo1_pins: sai0m0-sdo1-pins {
+			rockchip,pins =
+				/* sai0_sdo1_m0 */
+				<7 RK_PA7 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m0_sdo2_pins: sai0m0-sdo2-pins {
+			rockchip,pins =
+				/* sai0_sdo2_m0 */
+				<7 RK_PB0 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m0_sdo3_pins: sai0m0-sdo3-pins {
+			rockchip,pins =
+				/* sai0_sdo3_m0 */
+				<7 RK_PB1 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m1_lrck_pins: sai0m1-lrck-pins {
+			rockchip,pins =
+				/* sai0_lrck_m1 */
+				<6 RK_PA1 4 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m1_mclk_pins: sai0m1-mclk-pins {
+			rockchip,pins =
+				/* sai0_mclk_m1 */
+				<6 RK_PA4 4 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m1_sclk_pins: sai0m1-sclk-pins {
+			rockchip,pins =
+				/* sai0_sclk_m1 */
+				<6 RK_PA0 4 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m1_sdi0_pins: sai0m1-sdi0-pins {
+			rockchip,pins =
+				/* sai0_sdi0_m1 */
+				<6 RK_PA3 4 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m1_sdi1_pins: sai0m1-sdi1-pins {
+			rockchip,pins =
+				/* sai0_sdi1_m1 */
+				<6 RK_PB1 4 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m1_sdi2_pins: sai0m1-sdi2-pins {
+			rockchip,pins =
+				/* sai0_sdi2_m1 */
+				<6 RK_PB0 4 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m1_sdi3_pins: sai0m1-sdi3-pins {
+			rockchip,pins =
+				/* sai0_sdi3_m1 */
+				<6 RK_PA7 4 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m1_sdo0_pins: sai0m1-sdo0-pins {
+			rockchip,pins =
+				/* sai0_sdo0_m1 */
+				<6 RK_PA2 4 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m1_sdo1_pins: sai0m1-sdo1-pins {
+			rockchip,pins =
+				/* sai0_sdo1_m1 */
+				<6 RK_PA7 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m1_sdo2_pins: sai0m1-sdo2-pins {
+			rockchip,pins =
+				/* sai0_sdo2_m1 */
+				<6 RK_PB0 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai0m1_sdo3_pins: sai0m1-sdo3-pins {
+			rockchip,pins =
+				/* sai0_sdo3_m1 */
+				<6 RK_PB1 5 &pcfg_pull_none>;
+		};
+	};
+
+	sai1 {
+		/omit-if-no-ref/
+		sai1m0_lrck_pins: sai1m0-lrck-pins {
+			rockchip,pins =
+				/* sai1_lrck_m0 */
+				<1 RK_PB4 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai1m0_mclk_pins: sai1m0-mclk-pins {
+			rockchip,pins =
+				/* sai1_mclk_m0 */
+				<1 RK_PB0 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai1m0_sclk_pins: sai1m0-sclk-pins {
+			rockchip,pins =
+				/* sai1_sclk_m0 */
+				<1 RK_PB5 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai1m0_sdi_pins: sai1m0-sdi-pins {
+			rockchip,pins =
+				/* sai1m0_sdi */
+				<1 RK_PB6 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		sai1m0_sdo_pins: sai1m0-sdo-pins {
+			rockchip,pins =
+				/* sai1m0_sdo */
+				<1 RK_PB2 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai1m1_lrck_pins: sai1m1-lrck-pins {
+			rockchip,pins =
+				/* sai1_lrck_m1 */
+				<4 RK_PA5 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai1m1_mclk_pins: sai1m1-mclk-pins {
+			rockchip,pins =
+				/* sai1_mclk_m1 */
+				<4 RK_PA3 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai1m1_sclk_pins: sai1m1-sclk-pins {
+			rockchip,pins =
+				/* sai1_sclk_m1 */
+				<4 RK_PA4 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai1m1_sdi_pins: sai1m1-sdi-pins {
+			rockchip,pins =
+				/* sai1m1_sdi */
+				<4 RK_PA6 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		sai1m1_sdo_pins: sai1m1-sdo-pins {
+			rockchip,pins =
+				/* sai1m1_sdo */
+				<4 RK_PA7 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai1m2_lrck_pins: sai1m2-lrck-pins {
+			rockchip,pins =
+				/* sai1_lrck_m2 */
+				<5 RK_PC6 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai1m2_mclk_pins: sai1m2-mclk-pins {
+			rockchip,pins =
+				/* sai1_mclk_m2 */
+				<5 RK_PC3 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai1m2_sclk_pins: sai1m2-sclk-pins {
+			rockchip,pins =
+				/* sai1_sclk_m2 */
+				<5 RK_PC5 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai1m2_sdi_pins: sai1m2-sdi-pins {
+			rockchip,pins =
+				/* sai1m2_sdi */
+				<5 RK_PC7 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		sai1m2_sdo_pins: sai1m2-sdo-pins {
+			rockchip,pins =
+				/* sai1m2_sdo */
+				<5 RK_PC4 5 &pcfg_pull_none>;
+		};
+	};
+
+	sai2 {
+		/omit-if-no-ref/
+		sai2m0_lrck_pins: sai2m0-lrck-pins {
+			rockchip,pins =
+				/* sai2_lrck_m0 */
+				<3 RK_PB5 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai2m0_mclk_pins: sai2m0-mclk-pins {
+			rockchip,pins =
+				/* sai2_mclk_m0 */
+				<3 RK_PB6 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai2m0_sclk_pins: sai2m0-sclk-pins {
+			rockchip,pins =
+				/* sai2_sclk_m0 */
+				<3 RK_PB4 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai2m0_sdi0_pins: sai2m0-sdi0-pins {
+			rockchip,pins =
+				/* sai2_sdi0_m0 */
+				<3 RK_PB3 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai2m0_sdi1_pins: sai2m0-sdi1-pins {
+			rockchip,pins =
+				/* sai2_sdi1_m0 */
+				<3 RK_PB7 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai2m0_sdi2_pins: sai2m0-sdi2-pins {
+			rockchip,pins =
+				/* sai2_sdi2_m0 */
+				<3 RK_PB1 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai2m0_sdo_pins: sai2m0-sdo-pins {
+			rockchip,pins =
+				/* sai2m0_sdo */
+				<3 RK_PB2 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai2m1_lrck_pins: sai2m1-lrck-pins {
+			rockchip,pins =
+				/* sai2_lrck_m1 */
+				<5 RK_PA7 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai2m1_mclk_pins: sai2m1-mclk-pins {
+			rockchip,pins =
+				/* sai2_mclk_m1 */
+				<5 RK_PA3 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai2m1_sclk_pins: sai2m1-sclk-pins {
+			rockchip,pins =
+				/* sai2_sclk_m1 */
+				<5 RK_PA5 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai2m1_sdi0_pins: sai2m1-sdi0-pins {
+			rockchip,pins =
+				/* sai2_sdi0_m1 */
+				<5 RK_PA6 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai2m1_sdi1_pins: sai2m1-sdi1-pins {
+			rockchip,pins =
+				/* sai2_sdi1_m1 */
+				<5 RK_PA2 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai2m1_sdi2_pins: sai2m1-sdi2-pins {
+			rockchip,pins =
+				/* sai2_sdi2_m1 */
+				<5 RK_PA1 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sai2m1_sdo_pins: sai2m1-sdo-pins {
+			rockchip,pins =
+				/* sai2m1_sdo */
+				<5 RK_PA4 5 &pcfg_pull_none>;
+		};
+	};
+
+	sdmmc0 {
+		/omit-if-no-ref/
+		sdmmc0_bus4_pins: sdmmc0-bus4-pins {
+			rockchip,pins =
+				/* sdmmc0_d0 */
+				<2 RK_PA0 1 &pcfg_pull_up_drv_level_2_75>,
+				/* sdmmc0_d1 */
+				<2 RK_PA1 1 &pcfg_pull_up_drv_level_2_75>,
+				/* sdmmc0_d2 */
+				<2 RK_PA2 1 &pcfg_pull_up_drv_level_2_75>,
+				/* sdmmc0_d3 */
+				<2 RK_PA3 1 &pcfg_pull_up_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		sdmmc0_cmd_pins: sdmmc0-cmd-pins {
+			rockchip,pins =
+				/* sdmmc0_cmd */
+				<2 RK_PA5 1 &pcfg_pull_up_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		sdmmc0_clk_pins: sdmmc0-clk-pins {
+			rockchip,pins =
+				/* sdmmc0_clk */
+				<2 RK_PA4 1 &pcfg_pull_up_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		sdmmc0_detn_pins: sdmmc0-detn-pins {
+			rockchip,pins =
+				/* sdmmc0_detn */
+				<0 RK_PA5 1 &pcfg_pull_up>;
+		};
+	};
+
+	sdmmc1 {
+		/omit-if-no-ref/
+		sdmmc1_bus4_pins: sdmmc1-bus4-pins {
+			rockchip,pins =
+				/* sdmmc1_d0 */
+				<3 RK_PA2 1 &pcfg_pull_up>,
+				/* sdmmc1_d1 */
+				<3 RK_PA3 1 &pcfg_pull_up>,
+				/* sdmmc1_d2 */
+				<3 RK_PA4 1 &pcfg_pull_up>,
+				/* sdmmc1_d3 */
+				<3 RK_PA5 1 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		sdmmc1_cmd_pins: sdmmc1-cmd-pins {
+			rockchip,pins =
+				/* sdmmc1_cmd */
+				<3 RK_PA1 1 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		sdmmc1_clk_pins: sdmmc1-clk-pins {
+			rockchip,pins =
+				/* sdmmc1_clk */
+				<3 RK_PA0 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		sdmmc1_detn_pins: sdmmc1-detn-pins {
+			rockchip,pins =
+				/* sdmmc1_detn */
+				<3 RK_PB6 3 &pcfg_pull_up>;
+		};
+	};
+
+	spi0 {
+		/omit-if-no-ref/
+		spi0m0_clk_pins: spi0m0-clk-pins {
+			rockchip,pins =
+				/* spi0_clk_m0 */
+				<0 RK_PB2 2 &pcfg_pull_none_drv_level_2_75>,
+				/* spi0_miso_m0 */
+				<0 RK_PB1 2 &pcfg_pull_none_drv_level_2_75>,
+				/* spi0_mosi_m0 */
+				<0 RK_PB0 2 &pcfg_pull_none_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		spi0m0_csn0_pins: spi0m0-csn0-pins {
+			rockchip,pins =
+				/* spi0m0_csn0 */
+				<0 RK_PA7 2 &pcfg_pull_none_drv_level_2_75>;
+		};
+		/omit-if-no-ref/
+		spi0m0_csn1_pins: spi0m0-csn1-pins {
+			rockchip,pins =
+				/* spi0m0_csn1 */
+				<0 RK_PA6 2 &pcfg_pull_none_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		spi0m1_clk_pins: spi0m1-clk-pins {
+			rockchip,pins =
+				/* spi0_clk_m1 */
+				<4 RK_PA7 1 &pcfg_pull_none_drv_level_2_75>,
+				/* spi0_miso_m1 */
+				<4 RK_PA5 1 &pcfg_pull_none_drv_level_2_75>,
+				/* spi0_mosi_m1 */
+				<4 RK_PA4 1 &pcfg_pull_none_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		spi0m1_csn0_pins: spi0m1-csn0-pins {
+			rockchip,pins =
+				/* spi0m1_csn0 */
+				<4 RK_PA6 1 &pcfg_pull_none_drv_level_2_75>;
+		};
+		/omit-if-no-ref/
+		spi0m1_csn1_pins: spi0m1-csn1-pins {
+			rockchip,pins =
+				/* spi0m1_csn1 */
+				<4 RK_PA3 1 &pcfg_pull_none_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		spi0m2_clk_pins: spi0m2-clk-pins {
+			rockchip,pins =
+				/* spi0_clk_m2 */
+				<5 RK_PA6 2 &pcfg_pull_none_drv_level_2_75>,
+				/* spi0_miso_m2 */
+				<5 RK_PA5 2 &pcfg_pull_none_drv_level_2_75>,
+				/* spi0_mosi_m2 */
+				<5 RK_PA4 2 &pcfg_pull_none_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		spi0m2_csn0_pins: spi0m2-csn0-pins {
+			rockchip,pins =
+				/* spi0m2_csn0 */
+				<5 RK_PA3 2 &pcfg_pull_none_drv_level_2_75>;
+		};
+		/omit-if-no-ref/
+		spi0m2_csn1_pins: spi0m2-csn1-pins {
+			rockchip,pins =
+				/* spi0m2_csn1 */
+				<5 RK_PA7 2 &pcfg_pull_none_drv_level_2_75>;
+		};
+	};
+
+	spi1 {
+		/omit-if-no-ref/
+		spi1m0_clk_pins: spi1m0-clk-pins {
+			rockchip,pins =
+				/* spi1_clk_m0 */
+				<6 RK_PB4 3 &pcfg_pull_none_drv_level_2_75>,
+				/* spi1_miso_m0 */
+				<6 RK_PB3 3 &pcfg_pull_none_drv_level_2_75>,
+				/* spi1_mosi_m0 */
+				<6 RK_PB2 3 &pcfg_pull_none_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		spi1m0_csn0_pins: spi1m0-csn0-pins {
+			rockchip,pins =
+				/* spi1m0_csn0 */
+				<6 RK_PB1 3 &pcfg_pull_none_drv_level_2_75>;
+		};
+		/omit-if-no-ref/
+		spi1m0_csn1_pins: spi1m0-csn1-pins {
+			rockchip,pins =
+				/* spi1m0_csn1 */
+				<6 RK_PB0 3 &pcfg_pull_none_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		spi1m1_clk_pins: spi1m1-clk-pins {
+			rockchip,pins =
+				/* spi1_clk_m1 */
+				<3 RK_PB4 1 &pcfg_pull_none_drv_level_2_75>,
+				/* spi1_miso_m1 */
+				<3 RK_PB3 1 &pcfg_pull_none_drv_level_2_75>,
+				/* spi1_mosi_m1 */
+				<3 RK_PB2 1 &pcfg_pull_none_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		spi1m1_csn0_pins: spi1m1-csn0-pins {
+			rockchip,pins =
+				/* spi1m1_csn0 */
+				<3 RK_PB5 1 &pcfg_pull_none_drv_level_2_75>;
+		};
+		/omit-if-no-ref/
+		spi1m1_csn1_pins: spi1m1-csn1-pins {
+			rockchip,pins =
+				/* spi1m1_csn1 */
+				<3 RK_PB6 1 &pcfg_pull_none_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		spi1m2_clk_pins: spi1m2-clk-pins {
+			rockchip,pins =
+				/* spi1_clk_m2 */
+				<5 RK_PD1 2 &pcfg_pull_none_drv_level_2_75>,
+				/* spi1_miso_m2 */
+				<5 RK_PD3 2 &pcfg_pull_none_drv_level_2_75>,
+				/* spi1_mosi_m2 */
+				<5 RK_PD2 2 &pcfg_pull_none_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		spi1m2_csn0_pins: spi1m2-csn0-pins {
+			rockchip,pins =
+				/* spi1m2_csn0 */
+				<5 RK_PD0 2 &pcfg_pull_none_drv_level_2_75>;
+		};
+		/omit-if-no-ref/
+		spi1m2_csn1_pins: spi1m2-csn1-pins {
+			rockchip,pins =
+				/* spi1m2_csn1 */
+				<5 RK_PD4 2 &pcfg_pull_none_drv_level_2_75>;
+		};
+	};
+
+	spi2ahb {
+		/omit-if-no-ref/
+		spi2ahb_clk_pins: spi2ahb-clk-pins {
+			rockchip,pins =
+				/* spi2ahb_clk */
+				<0 RK_PC3 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		spi2ahb_csn0_pins: spi2ahb-csn0-pins {
+			rockchip,pins =
+				/* spi2ahb_csn0 */
+				<0 RK_PC2 1 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		spi2ahb_d0_pins: spi2ahb-d0-pins {
+			rockchip,pins =
+				/* spi2ahb_d0 */
+				<0 RK_PC7 1 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		spi2ahb_d1_pins: spi2ahb-d1-pins {
+			rockchip,pins =
+				/* spi2ahb_d1 */
+				<0 RK_PC6 1 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		spi2ahb_d2_pins: spi2ahb-d2-pins {
+			rockchip,pins =
+				/* spi2ahb_d2 */
+				<0 RK_PC5 1 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		spi2ahb_d3_pins: spi2ahb-d3-pins {
+			rockchip,pins =
+				/* spi2ahb_d3 */
+				<0 RK_PC4 1 &pcfg_pull_none>;
+		};
+	};
+
+	tsadc {
+		/omit-if-no-ref/
+		tsadc_pins: tsadc-pins {
+			rockchip,pins =
+				/* tsadc_shut */
+				<0 RK_PA1 3 &pcfg_pull_none>,
+				/* tsadc_shutorg */
+				<0 RK_PA1 4 &pcfg_pull_none>;
+		};
+	};
+
+	uart0 {
+		/omit-if-no-ref/
+		uart0m0_xfer_pins: uart0m0-xfer-pins {
+			rockchip,pins =
+				/* uart0_rx_m0 */
+				<2 RK_PA0 2 &pcfg_pull_up>,
+				/* uart0_tx_m0 */
+				<2 RK_PA1 2 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart0m1_xfer_pins: uart0m1-xfer-pins {
+			rockchip,pins =
+				/* uart0_rx_m1 */
+				<5 RK_PD7 1 &pcfg_pull_up>,
+				/* uart0_tx_m1 */
+				<5 RK_PD6 1 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart0m2_xfer_pins: uart0m2-xfer-pins {
+			rockchip,pins =
+				/* uart0_rx_m2 */
+				<0 RK_PB4 1 &pcfg_pull_up>,
+				/* uart0_tx_m2 */
+				<0 RK_PB3 1 &pcfg_pull_up>;
+		};
+	};
+
+	uart1 {
+		/omit-if-no-ref/
+		uart1m0_xfer_pins: uart1m0-xfer-pins {
+			rockchip,pins =
+				/* uart1_rx_m0 */
+				<0 RK_PC5 3 &pcfg_pull_up>,
+				/* uart1_tx_m0 */
+				<0 RK_PC4 3 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart1m0_ctsn_pins: uart1m0-ctsn-pins {
+			rockchip,pins =
+				/* uart1m0_ctsn */
+				<0 RK_PC7 3 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart1m0_rtsn_pins: uart1m0-rtsn-pins {
+			rockchip,pins =
+				/* uart1m0_rtsn */
+				<0 RK_PC6 3 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		uart1m1_xfer_pins: uart1m1-xfer-pins {
+			rockchip,pins =
+				/* uart1_rx_m1 */
+				<3 RK_PB7 4 &pcfg_pull_up>,
+				/* uart1_tx_m1 */
+				<3 RK_PB6 4 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart1m1_ctsn_pins: uart1m1-ctsn-pins {
+			rockchip,pins =
+				/* uart1m1_ctsn */
+				<3 RK_PB5 4 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart1m1_rtsn_pins: uart1m1-rtsn-pins {
+			rockchip,pins =
+				/* uart1m1_rtsn */
+				<3 RK_PB4 4 &pcfg_pull_none>;
+		};
+	};
+
+	uart2 {
+		/omit-if-no-ref/
+		uart2m0_xfer_pins: uart2m0-xfer-pins {
+			rockchip,pins =
+				/* uart2_rx_m0 */
+				<3 RK_PB0 4 &pcfg_pull_up>,
+				/* uart2_tx_m0 */
+				<3 RK_PB1 4 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart2m0_ctsn_pins: uart2m0-ctsn-pins {
+			rockchip,pins =
+				/* uart2m0_ctsn */
+				<3 RK_PA7 4 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart2m0_rtsn_pins: uart2m0-rtsn-pins {
+			rockchip,pins =
+				/* uart2m0_rtsn */
+				<3 RK_PA6 4 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		uart2m1_xfer_pins: uart2m1-xfer-pins {
+			rockchip,pins =
+				/* uart2_rx_m1 */
+				<7 RK_PB0 6 &pcfg_pull_up>,
+				/* uart2_tx_m1 */
+				<7 RK_PB1 6 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart2m1_ctsn_pins: uart2m1-ctsn-pins {
+			rockchip,pins =
+				/* uart2m1_ctsn */
+				<7 RK_PA4 6 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart2m1_rtsn_pins: uart2m1-rtsn-pins {
+			rockchip,pins =
+				/* uart2m1_rtsn */
+				<7 RK_PA7 6 &pcfg_pull_none>;
+		};
+	};
+
+	uart3 {
+		/omit-if-no-ref/
+		uart3m0_xfer_pins: uart3m0-xfer-pins {
+			rockchip,pins =
+				/* uart3_rx_m0 */
+				<2 RK_PA2 2 &pcfg_pull_up>,
+				/* uart3_tx_m0 */
+				<2 RK_PA3 2 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart3m0_ctsn_pins: uart3m0-ctsn-pins {
+			rockchip,pins =
+				/* uart3m0_ctsn */
+				<2 RK_PA5 2 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart3m0_rtsn_pins: uart3m0-rtsn-pins {
+			rockchip,pins =
+				/* uart3m0_rtsn */
+				<2 RK_PA4 2 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		uart3m1_xfer_pins: uart3m1-xfer-pins {
+			rockchip,pins =
+				/* uart3_rx_m1 */
+				<5 RK_PD5 8 &pcfg_pull_up>,
+				/* uart3_tx_m1 */
+				<5 RK_PD4 8 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart3m1_ctsn_pins: uart3m1-ctsn-pins {
+			rockchip,pins =
+				/* uart3m1_ctsn */
+				<5 RK_PD3 8 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart3m1_rtsn_pins: uart3m1-rtsn-pins {
+			rockchip,pins =
+				/* uart3m1_rtsn */
+				<5 RK_PD2 8 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		uart3m2_xfer_pins: uart3m2-xfer-pins {
+			rockchip,pins =
+				/* uart3_rx_m2 */
+				<6 RK_PC3 6 &pcfg_pull_up>,
+				/* uart3_tx_m2 */
+				<6 RK_PC2 6 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart3m2_ctsn_pins: uart3m2-ctsn-pins {
+			rockchip,pins =
+				/* uart3m2_ctsn */
+				<6 RK_PC1 6 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart3m2_rtsn_pins: uart3m2-rtsn-pins {
+			rockchip,pins =
+				/* uart3m2_rtsn */
+				<6 RK_PC0 6 &pcfg_pull_none>;
+		};
+	};
+
+	uart4 {
+		/omit-if-no-ref/
+		uart4m0_xfer_pins: uart4m0-xfer-pins {
+			rockchip,pins =
+				/* uart4_rx_m0 */
+				<4 RK_PA2 5 &pcfg_pull_up>,
+				/* uart4_tx_m0 */
+				<4 RK_PA3 5 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart4m0_ctsn_pins: uart4m0-ctsn-pins {
+			rockchip,pins =
+				/* uart4m0_ctsn */
+				<4 RK_PA1 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart4m0_rtsn_pins: uart4m0-rtsn-pins {
+			rockchip,pins =
+				/* uart4m0_rtsn */
+				<4 RK_PA0 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		uart4m1_xfer_pins: uart4m1-xfer-pins {
+			rockchip,pins =
+				/* uart4_rx_m1 */
+				<5 RK_PA3 8 &pcfg_pull_up>,
+				/* uart4_tx_m1 */
+				<5 RK_PA2 8 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart4m1_ctsn_pins: uart4m1-ctsn-pins {
+			rockchip,pins =
+				/* uart4m1_ctsn */
+				<5 RK_PA1 8 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart4m1_rtsn_pins: uart4m1-rtsn-pins {
+			rockchip,pins =
+				/* uart4m1_rtsn */
+				<5 RK_PA0 8 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		uart4m2_xfer_pins: uart4m2-xfer-pins {
+			rockchip,pins =
+				/* uart4_rx_m2 */
+				<6 RK_PA1 6 &pcfg_pull_up>,
+				/* uart4_tx_m2 */
+				<6 RK_PA0 6 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart4m2_ctsn_pins: uart4m2-ctsn-pins {
+			rockchip,pins =
+				/* uart4m2_ctsn */
+				<6 RK_PA7 6 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart4m2_rtsn_pins: uart4m2-rtsn-pins {
+			rockchip,pins =
+				/* uart4m2_rtsn */
+				<6 RK_PA6 6 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		uart4m3_xfer_pins: uart4m3-xfer-pins {
+			rockchip,pins =
+				/* uart4_rx_m3 */
+				<2 RK_PA4 3 &pcfg_pull_up>,
+				/* uart4_tx_m3 */
+				<2 RK_PA5 3 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart4m3_ctsn_pins: uart4m3-ctsn-pins {
+			rockchip,pins =
+				/* uart4m3_ctsn */
+				<2 RK_PA3 3 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart4m3_rtsn_pins: uart4m3-rtsn-pins {
+			rockchip,pins =
+				/* uart4m3_rtsn */
+				<2 RK_PA2 3 &pcfg_pull_none>;
+		};
+	};
+
+	uart5 {
+		/omit-if-no-ref/
+		uart5m0_xfer_pins: uart5m0-xfer-pins {
+			rockchip,pins =
+				/* uart5_rx_m0 */
+				<4 RK_PA7 5 &pcfg_pull_up>,
+				/* uart5_tx_m0 */
+				<4 RK_PA6 5 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart5m0_ctsn_pins: uart5m0-ctsn-pins {
+			rockchip,pins =
+				/* uart5m0_ctsn */
+				<4 RK_PB1 5 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart5m0_rtsn_pins: uart5m0-rtsn-pins {
+			rockchip,pins =
+				/* uart5m0_rtsn */
+				<4 RK_PB0 5 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		uart5m1_xfer_pins: uart5m1-xfer-pins {
+			rockchip,pins =
+				/* uart5_rx_m1 */
+				<5 RK_PA5 8 &pcfg_pull_up>,
+				/* uart5_tx_m1 */
+				<5 RK_PA4 8 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart5m1_ctsn_pins: uart5m1-ctsn-pins {
+			rockchip,pins =
+				/* uart5m1_ctsn */
+				<5 RK_PA7 8 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart5m1_rtsn_pins: uart5m1-rtsn-pins {
+			rockchip,pins =
+				/* uart5m1_rtsn */
+				<5 RK_PA6 8 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		uart5m2_xfer_pins: uart5m2-xfer-pins {
+			rockchip,pins =
+				/* uart5_rx_m2 */
+				<6 RK_PA3 6 &pcfg_pull_up>,
+				/* uart5_tx_m2 */
+				<6 RK_PA2 6 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart5m2_ctsn_pins: uart5m2-ctsn-pins {
+			rockchip,pins =
+				/* uart5m2_ctsn */
+				<6 RK_PA5 6 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart5m2_rtsn_pins: uart5m2-rtsn-pins {
+			rockchip,pins =
+				/* uart5m2_rtsn */
+				<6 RK_PA4 6 &pcfg_pull_none>;
+		};
+	};
+
+	uart6 {
+		/omit-if-no-ref/
+		uart6m0_xfer_pins: uart6m0-xfer-pins {
+			rockchip,pins =
+				/* uart6_rx_m0 */
+				<5 RK_PB1 8 &pcfg_pull_up>,
+				/* uart6_tx_m0 */
+				<5 RK_PB0 8 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart6m0_ctsn_pins: uart6m0-ctsn-pins {
+			rockchip,pins =
+				/* uart6m0_ctsn */
+				<5 RK_PB3 8 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart6m0_rtsn_pins: uart6m0-rtsn-pins {
+			rockchip,pins =
+				/* uart6m0_rtsn */
+				<5 RK_PB2 8 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		uart6m1_xfer_pins: uart6m1-xfer-pins {
+			rockchip,pins =
+				/* uart6_rx_m1 */
+				<6 RK_PB1 6 &pcfg_pull_up>,
+				/* uart6_tx_m1 */
+				<6 RK_PB0 6 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart6m1_ctsn_pins: uart6m1-ctsn-pins {
+			rockchip,pins =
+				/* uart6m1_ctsn */
+				<6 RK_PB3 6 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart6m1_rtsn_pins: uart6m1-rtsn-pins {
+			rockchip,pins =
+				/* uart6m1_rtsn */
+				<6 RK_PB2 6 &pcfg_pull_none>;
+		};
+	};
+
+	uart7 {
+		/omit-if-no-ref/
+		uart7m0_xfer_pins: uart7m0-xfer-pins {
+			rockchip,pins =
+				/* uart7_rx_m0 */
+				<5 RK_PB5 8 &pcfg_pull_up>,
+				/* uart7_tx_m0 */
+				<5 RK_PB4 8 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart7m0_ctsn_pins: uart7m0-ctsn-pins {
+			rockchip,pins =
+				/* uart7m0_ctsn */
+				<5 RK_PB7 8 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart7m0_rtsn_pins: uart7m0-rtsn-pins {
+			rockchip,pins =
+				/* uart7m0_rtsn */
+				<5 RK_PB6 8 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		uart7m1_xfer_pins: uart7m1-xfer-pins {
+			rockchip,pins =
+				/* uart7_rx_m1 */
+				<6 RK_PB5 6 &pcfg_pull_up>,
+				/* uart7_tx_m1 */
+				<6 RK_PB4 6 &pcfg_pull_up>;
+		};
+
+		/omit-if-no-ref/
+		uart7m1_ctsn_pins: uart7m1-ctsn-pins {
+			rockchip,pins =
+				/* uart7m1_ctsn */
+				<6 RK_PB7 6 &pcfg_pull_none>;
+		};
+		/omit-if-no-ref/
+		uart7m1_rtsn_pins: uart7m1-rtsn-pins {
+			rockchip,pins =
+				/* uart7m1_rtsn */
+				<6 RK_PB6 6 &pcfg_pull_none>;
+		};
+	};
+
+	vi_cif {
+		/omit-if-no-ref/
+		vi_cifm0_pins: vi-cifm0-pins {
+			rockchip,pins =
+				/* vi_cif_clkin_m0 */
+				<6 RK_PC1 1 &pcfg_pull_none>,
+				/* vi_cif_clkout_m0 */
+				<6 RK_PC2 1 &pcfg_pull_none>,
+				/* vi_cif_d0_m0 */
+				<6 RK_PA0 1 &pcfg_pull_none>,
+				/* vi_cif_d10_m0 */
+				<6 RK_PB2 1 &pcfg_pull_none>,
+				/* vi_cif_d11_m0 */
+				<6 RK_PB3 1 &pcfg_pull_none>,
+				/* vi_cif_d12_m0 */
+				<6 RK_PB4 1 &pcfg_pull_none>,
+				/* vi_cif_d13_m0 */
+				<6 RK_PB5 1 &pcfg_pull_none>,
+				/* vi_cif_d14_m0 */
+				<6 RK_PB6 1 &pcfg_pull_none>,
+				/* vi_cif_d15_m0 */
+				<6 RK_PB7 1 &pcfg_pull_none>,
+				/* vi_cif_d1_m0 */
+				<6 RK_PA1 1 &pcfg_pull_none>,
+				/* vi_cif_d2_m0 */
+				<6 RK_PA2 1 &pcfg_pull_none>,
+				/* vi_cif_d3_m0 */
+				<6 RK_PA3 1 &pcfg_pull_none>,
+				/* vi_cif_d4_m0 */
+				<6 RK_PA4 1 &pcfg_pull_none>,
+				/* vi_cif_d5_m0 */
+				<6 RK_PA5 1 &pcfg_pull_none>,
+				/* vi_cif_d6_m0 */
+				<6 RK_PA6 1 &pcfg_pull_none>,
+				/* vi_cif_d7_m0 */
+				<6 RK_PA7 1 &pcfg_pull_none>,
+				/* vi_cif_d8_m0 */
+				<6 RK_PB0 1 &pcfg_pull_none>,
+				/* vi_cif_d9_m0 */
+				<6 RK_PB1 1 &pcfg_pull_none>,
+				/* vi_cif_hsync_m0 */
+				<6 RK_PC3 1 &pcfg_pull_none>,
+				/* vi_cif_vsync_m0 */
+				<6 RK_PC0 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		vi_cifm1_pins: vi-cifm1-pins {
+			rockchip,pins =
+				/* vi_cif_clkin_m1 */
+				<5 RK_PC6 3 &pcfg_pull_none>,
+				/* vi_cif_clkout_m1 */
+				<5 RK_PC5 3 &pcfg_pull_none>,
+				/* vi_cif_d0_m1 */
+				<5 RK_PA0 3 &pcfg_pull_none>,
+				/* vi_cif_d10_m1 */
+				<5 RK_PB6 3 &pcfg_pull_none>,
+				/* vi_cif_d11_m1 */
+				<5 RK_PB7 3 &pcfg_pull_none>,
+				/* vi_cif_d12_m1 */
+				<5 RK_PC0 3 &pcfg_pull_none>,
+				/* vi_cif_d13_m1 */
+				<5 RK_PC1 3 &pcfg_pull_none>,
+				/* vi_cif_d14_m1 */
+				<5 RK_PC2 3 &pcfg_pull_none>,
+				/* vi_cif_d15_m1 */
+				<5 RK_PC3 3 &pcfg_pull_none>,
+				/* vi_cif_d1_m1 */
+				<5 RK_PA1 3 &pcfg_pull_none>,
+				/* vi_cif_d2_m1 */
+				<5 RK_PA2 3 &pcfg_pull_none>,
+				/* vi_cif_d3_m1 */
+				<5 RK_PA7 3 &pcfg_pull_none>,
+				/* vi_cif_d4_m1 */
+				<5 RK_PB0 3 &pcfg_pull_none>,
+				/* vi_cif_d5_m1 */
+				<5 RK_PB1 3 &pcfg_pull_none>,
+				/* vi_cif_d6_m1 */
+				<5 RK_PB2 3 &pcfg_pull_none>,
+				/* vi_cif_d7_m1 */
+				<5 RK_PB3 3 &pcfg_pull_none>,
+				/* vi_cif_d8_m1 */
+				<5 RK_PB4 3 &pcfg_pull_none>,
+				/* vi_cif_d9_m1 */
+				<5 RK_PB5 3 &pcfg_pull_none>,
+				/* vi_cif_hsync_m1 */
+				<5 RK_PC7 3 &pcfg_pull_none>,
+				/* vi_cif_vsync_m1 */
+				<5 RK_PC4 3 &pcfg_pull_none>;
+		};
+	};
+
+	vo_lcdc {
+		/omit-if-no-ref/
+		vo_lcdc_pins: vo-lcdc-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d0 */
+				<5 RK_PA0 1 &pcfg_pull_none>,
+				/* vo_lcdc_d1 */
+				<5 RK_PA1 1 &pcfg_pull_none>,
+				/* vo_lcdc_d2 */
+				<5 RK_PA2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d3 */
+				<5 RK_PA3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d4 */
+				<5 RK_PA4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d5 */
+				<5 RK_PA5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d6 */
+				<5 RK_PA6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d7 */
+				<5 RK_PA7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d8 */
+				<5 RK_PB0 1 &pcfg_pull_none>,
+				/* vo_lcdc_d9 */
+				<5 RK_PB1 1 &pcfg_pull_none>,
+				/* vo_lcdc_d10 */
+				<5 RK_PB2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d11 */
+				<5 RK_PB3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d12 */
+				<5 RK_PB4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d13 */
+				<5 RK_PB5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d14 */
+				<5 RK_PB6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d15 */
+				<5 RK_PB7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d16 */
+				<5 RK_PC0 1 &pcfg_pull_none>,
+				/* vo_lcdc_d17 */
+				<5 RK_PC1 1 &pcfg_pull_none>,
+				/* vo_lcdc_d18 */
+				<5 RK_PC2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d19 */
+				<5 RK_PC3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d20 */
+				<5 RK_PC4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d21 */
+				<5 RK_PC5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d22 */
+				<5 RK_PC6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d23 */
+				<5 RK_PC7 1 &pcfg_pull_none>,
+				/* vo_lcdc_den */
+				<5 RK_PD0 1 &pcfg_pull_none>,
+				/* vo_lcdc_hsync */
+				<5 RK_PD1 1 &pcfg_pull_none>,
+				/* vo_lcdc_vsync */
+				<5 RK_PD2 1 &pcfg_pull_none>;
+		};
+	};
+};
+
+/*
+ * This part is edited handly.
+ */
+&pinctrl {
+	dsmc {
+		/omit-if-no-ref/
+		dsmc_csn_idle: dsmc-csn-idle {
+			rockchip,pins =
+				/* dsmc_csn0 */
+				<5 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>,
+				/* dsmc_csn1 */
+				<5 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>,
+				/* dsmc_csn2 */
+				<5 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>,
+				/* dsmc_csn3 */
+				<5 RK_PD0 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	pdm {
+		/omit-if-no-ref/
+		pdmm0_clk0_idle: pdmm0-clk0-idle {
+			rockchip,pins =
+				/* pdm_clk0_m0 */
+				<7 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm0_clk1_idle: pdmm0-clk1-idle {
+			rockchip,pins =
+				/* pdm_clk1_m0 */
+				<7 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm1_clk0_idle: pdmm1-clk0-idle {
+			rockchip,pins =
+				/* pdm_clk0_m1 */
+				<6 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		pdmm1_clk1_idle: pdmm1-clk1-idle {
+			rockchip,pins =
+				/* pdm_clk1_m1 */
+				<6 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	sdmmc0 {
+		/omit-if-no-ref/
+		sdmmc0_idle_pins: sdmmc0-idle-pins {
+			rockchip,pins =
+				<2 RK_PA0 RK_FUNC_GPIO &pcfg_pull_down>,
+				<2 RK_PA1 RK_FUNC_GPIO &pcfg_pull_down>,
+				<2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_down>,
+				<2 RK_PA3 RK_FUNC_GPIO &pcfg_pull_down>,
+				<2 RK_PA4 RK_FUNC_GPIO &pcfg_pull_down>,
+				<2 RK_PA5 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+	};
+
+	sdmmc1 {
+		/omit-if-no-ref/
+		sdmmc1_idle_pins: sdmmc1-idle-pins {
+			rockchip,pins =
+				<3 RK_PA0 RK_FUNC_GPIO &pcfg_pull_down>,
+				<3 RK_PA1 RK_FUNC_GPIO &pcfg_pull_down>,
+				<3 RK_PA2 RK_FUNC_GPIO &pcfg_pull_down>,
+				<3 RK_PA3 RK_FUNC_GPIO &pcfg_pull_down>,
+				<3 RK_PA4 RK_FUNC_GPIO &pcfg_pull_down>,
+				<3 RK_PA5 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+	};
+
+	vo_lcdc {
+		/omit-if-no-ref/
+		bt1120_pins: bt1120-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none_drv_level_4_75>,
+				/* vo_lcdc_d3 */
+				<5 RK_PA3 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d4 */
+				<5 RK_PA4 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d5 */
+				<5 RK_PA5 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d6 */
+				<5 RK_PA6 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d7 */
+				<5 RK_PA7 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d10 */
+				<5 RK_PB2 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d11 */
+				<5 RK_PB3 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d12 */
+				<5 RK_PB4 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d13 */
+				<5 RK_PB5 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d14 */
+				<5 RK_PB6 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d15 */
+				<5 RK_PB7 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d19 */
+				<5 RK_PC3 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d20 */
+				<5 RK_PC4 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d21 */
+				<5 RK_PC5 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d22 */
+				<5 RK_PC6 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d23 */
+				<5 RK_PC7 1 &pcfg_pull_none_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		bt656_m0_pins: bt656-m0-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none_drv_level_4_75>,
+				/* vo_lcdc_d3 */
+				<5 RK_PA3 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d4 */
+				<5 RK_PA4 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d5 */
+				<5 RK_PA5 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d6 */
+				<5 RK_PA6 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d7 */
+				<5 RK_PA7 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d10 */
+				<5 RK_PB2 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d11 */
+				<5 RK_PB3 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d12 */
+				<5 RK_PB4 1 &pcfg_pull_none_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		bt656_m1_pins: bt656-m1-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none_drv_level_4_75>,
+				/* vo_lcdc_d13 */
+				<5 RK_PB5 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d14 */
+				<5 RK_PB6 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d15 */
+				<5 RK_PB7 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d19 */
+				<5 RK_PC3 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d20 */
+				<5 RK_PC4 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d21 */
+				<5 RK_PC5 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d22 */
+				<5 RK_PC6 1 &pcfg_pull_none_drv_level_2_75>,
+				/* vo_lcdc_d23 */
+				<5 RK_PC7 1 &pcfg_pull_none_drv_level_2_75>;
+		};
+
+		/omit-if-no-ref/
+		mcu_rgb3x8_rgb2x8_m0_pins: mcu-rgb3x8-rgb2x8-m0-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d3 */
+				<5 RK_PA3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d4 */
+				<5 RK_PA4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d5 */
+				<5 RK_PA5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d6 */
+				<5 RK_PA6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d7 */
+				<5 RK_PA7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d10 */
+				<5 RK_PB2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d11 */
+				<5 RK_PB3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d12 */
+				<5 RK_PB4 1 &pcfg_pull_none>,
+				/* vo_lcdc_den */
+				<5 RK_PD0 1 &pcfg_pull_none>,
+				/* vo_lcdc_hsync */
+				<5 RK_PD1 1 &pcfg_pull_none>,
+				/* vo_lcdc_vsync */
+				<5 RK_PD2 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		mcu_rgb3x8_rgb2x8_m1_pins: mcu-rgb3x8-rgb2x8-m1-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d13 */
+				<5 RK_PB5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d14 */
+				<5 RK_PB6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d15 */
+				<5 RK_PB7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d19 */
+				<5 RK_PC3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d20 */
+				<5 RK_PC4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d21 */
+				<5 RK_PC5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d22 */
+				<5 RK_PC6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d23 */
+				<5 RK_PC7 1 &pcfg_pull_none>,
+				/* vo_lcdc_den */
+				<5 RK_PD0 1 &pcfg_pull_none>,
+				/* vo_lcdc_hsync */
+				<5 RK_PD1 1 &pcfg_pull_none>,
+				/* vo_lcdc_vsync */
+				<5 RK_PD2 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		mcu_rgb565_pins: mcu-rgb565-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d3 */
+				<5 RK_PA3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d4 */
+				<5 RK_PA4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d5 */
+				<5 RK_PA5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d6 */
+				<5 RK_PA6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d7 */
+				<5 RK_PA7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d10 */
+				<5 RK_PB2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d11 */
+				<5 RK_PB3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d12 */
+				<5 RK_PB4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d13 */
+				<5 RK_PB5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d14 */
+				<5 RK_PB6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d15 */
+				<5 RK_PB7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d19 */
+				<5 RK_PC3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d20 */
+				<5 RK_PC4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d21 */
+				<5 RK_PC5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d22 */
+				<5 RK_PC6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d23 */
+				<5 RK_PC7 1 &pcfg_pull_none>,
+				/* vo_lcdc_den */
+				<5 RK_PD0 1 &pcfg_pull_none>,
+				/* vo_lcdc_hsync */
+				<5 RK_PD1 1 &pcfg_pull_none>,
+				/* vo_lcdc_vsync */
+				<5 RK_PD2 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		mcu_rgb666_pins: mcu-rgb666-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d2 */
+				<5 RK_PA2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d3 */
+				<5 RK_PA3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d4 */
+				<5 RK_PA4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d5 */
+				<5 RK_PA5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d6 */
+				<5 RK_PA6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d7 */
+				<5 RK_PA7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d10 */
+				<5 RK_PB2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d11 */
+				<5 RK_PB3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d12 */
+				<5 RK_PB4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d13 */
+				<5 RK_PB5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d14 */
+				<5 RK_PB6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d15 */
+				<5 RK_PB7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d18 */
+				<5 RK_PC2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d19 */
+				<5 RK_PC3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d20 */
+				<5 RK_PC4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d21 */
+				<5 RK_PC5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d22 */
+				<5 RK_PC6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d23 */
+				<5 RK_PC7 1 &pcfg_pull_none>,
+				/* vo_lcdc_den */
+				<5 RK_PD0 1 &pcfg_pull_none>,
+				/* vo_lcdc_hsync */
+				<5 RK_PD1 1 &pcfg_pull_none>,
+				/* vo_lcdc_vsync */
+				<5 RK_PD2 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		mcu_rgb888_pins: mcu-rgb888-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d0 */
+				<5 RK_PA0 1 &pcfg_pull_none>,
+				/* vo_lcdc_d1 */
+				<5 RK_PA1 1 &pcfg_pull_none>,
+				/* vo_lcdc_d2 */
+				<5 RK_PA2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d3 */
+				<5 RK_PA3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d4 */
+				<5 RK_PA4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d5 */
+				<5 RK_PA5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d6 */
+				<5 RK_PA6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d7 */
+				<5 RK_PA7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d8 */
+				<5 RK_PB0 1 &pcfg_pull_none>,
+				/* vo_lcdc_d9 */
+				<5 RK_PB1 1 &pcfg_pull_none>,
+				/* vo_lcdc_d10 */
+				<5 RK_PB2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d11 */
+				<5 RK_PB3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d12 */
+				<5 RK_PB4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d13 */
+				<5 RK_PB5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d14 */
+				<5 RK_PB6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d15 */
+				<5 RK_PB7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d16 */
+				<5 RK_PC0 1 &pcfg_pull_none>,
+				/* vo_lcdc_d17 */
+				<5 RK_PC1 1 &pcfg_pull_none>,
+				/* vo_lcdc_d18 */
+				<5 RK_PC2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d19 */
+				<5 RK_PC3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d20 */
+				<5 RK_PC4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d21 */
+				<5 RK_PC5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d22 */
+				<5 RK_PC6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d23 */
+				<5 RK_PC7 1 &pcfg_pull_none>,
+				/* vo_lcdc_den */
+				<5 RK_PD0 1 &pcfg_pull_none>,
+				/* vo_lcdc_hsync */
+				<5 RK_PD1 1 &pcfg_pull_none>,
+				/* vo_lcdc_vsync */
+				<5 RK_PD2 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		rgb3x8_rgb2x8_m0_pins: rgb3x8-rgb2x8-m0-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d3 */
+				<5 RK_PA3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d4 */
+				<5 RK_PA4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d5 */
+				<5 RK_PA5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d6 */
+				<5 RK_PA6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d7 */
+				<5 RK_PA7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d10 */
+				<5 RK_PB2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d11 */
+				<5 RK_PB3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d12 */
+				<5 RK_PB4 1 &pcfg_pull_none>,
+				/* vo_lcdc_den */
+				<5 RK_PD0 1 &pcfg_pull_none>,
+				/* vo_lcdc_hsync */
+				<5 RK_PD1 1 &pcfg_pull_none>,
+				/* vo_lcdc_vsync */
+				<5 RK_PD2 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		rgb3x8_rgb2x8_m1_pins: rgb3x8-rgb2x8-m1-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d13 */
+				<5 RK_PB5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d14 */
+				<5 RK_PB6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d15 */
+				<5 RK_PB7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d19 */
+				<5 RK_PC3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d20 */
+				<5 RK_PC4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d21 */
+				<5 RK_PC5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d22 */
+				<5 RK_PC6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d23 */
+				<5 RK_PC7 1 &pcfg_pull_none>,
+				/* vo_lcdc_den */
+				<5 RK_PD0 1 &pcfg_pull_none>,
+				/* vo_lcdc_hsync */
+				<5 RK_PD1 1 &pcfg_pull_none>,
+				/* vo_lcdc_vsync */
+				<5 RK_PD2 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		rgb565_pins: rgb565-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d3 */
+				<5 RK_PA3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d4 */
+				<5 RK_PA4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d5 */
+				<5 RK_PA5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d6 */
+				<5 RK_PA6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d7 */
+				<5 RK_PA7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d10 */
+				<5 RK_PB2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d11 */
+				<5 RK_PB3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d12 */
+				<5 RK_PB4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d13 */
+				<5 RK_PB5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d14 */
+				<5 RK_PB6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d15 */
+				<5 RK_PB7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d19 */
+				<5 RK_PC3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d20 */
+				<5 RK_PC4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d21 */
+				<5 RK_PC5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d22 */
+				<5 RK_PC6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d23 */
+				<5 RK_PC7 1 &pcfg_pull_none>,
+				/* vo_lcdc_den */
+				<5 RK_PD0 1 &pcfg_pull_none>,
+				/* vo_lcdc_hsync */
+				<5 RK_PD1 1 &pcfg_pull_none>,
+				/* vo_lcdc_vsync */
+				<5 RK_PD2 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		rgb666_pins: rgb666-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d2 */
+				<5 RK_PA2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d3 */
+				<5 RK_PA3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d4 */
+				<5 RK_PA4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d5 */
+				<5 RK_PA5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d6 */
+				<5 RK_PA6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d7 */
+				<5 RK_PA7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d10 */
+				<5 RK_PB2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d11 */
+				<5 RK_PB3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d12 */
+				<5 RK_PB4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d13 */
+				<5 RK_PB5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d14 */
+				<5 RK_PB6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d15 */
+				<5 RK_PB7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d18 */
+				<5 RK_PC2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d19 */
+				<5 RK_PC3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d20 */
+				<5 RK_PC4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d21 */
+				<5 RK_PC5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d22 */
+				<5 RK_PC6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d23 */
+				<5 RK_PC7 1 &pcfg_pull_none>,
+				/* vo_lcdc_den */
+				<5 RK_PD0 1 &pcfg_pull_none>,
+				/* vo_lcdc_hsync */
+				<5 RK_PD1 1 &pcfg_pull_none>,
+				/* vo_lcdc_vsync */
+				<5 RK_PD2 1 &pcfg_pull_none>;
+		};
+
+		/omit-if-no-ref/
+		rgb888_pins: rgb888-pins {
+			rockchip,pins =
+				/* vo_lcdc_clk */
+				<5 RK_PD3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d0 */
+				<5 RK_PA0 1 &pcfg_pull_none>,
+				/* vo_lcdc_d1 */
+				<5 RK_PA1 1 &pcfg_pull_none>,
+				/* vo_lcdc_d2 */
+				<5 RK_PA2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d3 */
+				<5 RK_PA3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d4 */
+				<5 RK_PA4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d5 */
+				<5 RK_PA5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d6 */
+				<5 RK_PA6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d7 */
+				<5 RK_PA7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d8 */
+				<5 RK_PB0 1 &pcfg_pull_none>,
+				/* vo_lcdc_d9 */
+				<5 RK_PB1 1 &pcfg_pull_none>,
+				/* vo_lcdc_d10 */
+				<5 RK_PB2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d11 */
+				<5 RK_PB3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d12 */
+				<5 RK_PB4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d13 */
+				<5 RK_PB5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d14 */
+				<5 RK_PB6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d15 */
+				<5 RK_PB7 1 &pcfg_pull_none>,
+				/* vo_lcdc_d16 */
+				<5 RK_PC0 1 &pcfg_pull_none>,
+				/* vo_lcdc_d17 */
+				<5 RK_PC1 1 &pcfg_pull_none>,
+				/* vo_lcdc_d18 */
+				<5 RK_PC2 1 &pcfg_pull_none>,
+				/* vo_lcdc_d19 */
+				<5 RK_PC3 1 &pcfg_pull_none>,
+				/* vo_lcdc_d20 */
+				<5 RK_PC4 1 &pcfg_pull_none>,
+				/* vo_lcdc_d21 */
+				<5 RK_PC5 1 &pcfg_pull_none>,
+				/* vo_lcdc_d22 */
+				<5 RK_PC6 1 &pcfg_pull_none>,
+				/* vo_lcdc_d23 */
+				<5 RK_PC7 1 &pcfg_pull_none>,
+				/* vo_lcdc_den */
+				<5 RK_PD0 1 &pcfg_pull_none>,
+				/* vo_lcdc_hsync */
+				<5 RK_PD1 1 &pcfg_pull_none>,
+				/* vo_lcdc_vsync */
+				<5 RK_PD2 1 &pcfg_pull_none>;
+		};
+	};
+};
-- 
2.34.1



From leo.yeo at luaberry.com  Sat Dec 27 04:15:27 2025
From: leo.yeo at luaberry.com (Leo Yeo)
Date: Sat, 27 Dec 2025 21:15:27 +0900
Subject: [PATCH] arm64: mm: prevent context switching during idmap is mapped
In-Reply-To: <20251202004223.108388-1-leo.yeo@luaberry.com>
References: <20251202004223.108388-1-leo.yeo@luaberry.com>
Message-ID: <CAMV_mXF-X968OQQ4zAqjXNjfAFZJ=bU5EJ1371RMOF-m0pK3Jg@mail.gmail.com>

On Tue, Dec 2, 2025 at 9:43?AM Jeongin Yeo <leo.yeo at luaberry.com> wrote:
>
>  cpu_install_idmap replaces ttbr0 to install idmap. replace_phys uses
>  idmap_cpu_replace_ttbr1 which is located in idmap,
>  thus it requires ttbr0 to point idmap.
>
>  However, if a kernel task has switched out right after
>  cpu_install_idmap, when kernel task is loaded, its ttbr0 is
>  mapped to reserved_pg_dir which doesn't contain any idmap
>  functions.
>  Therefore, the kernel task cannot find any functions to run,
>  causing memory fault.
>
>  As far as I can verify from the current arm64 tree,
>  no in-tree caller invokes this function from a preemptible context.
>
>  Nevertheless, future work might allow this function to be called in
>  preemptive state. Encapsulating the idmap sequence with
>  preempt_disable() and preempt_enable() prevents this possible problem.

Hi,

Gentle ping on this patch (sent on Dec 1).
Is there any feedback or concerns I should address?

Thanks.

>
> Signed-off-by: Jeongin Yeo <leo.yeo at luaberry.com>
> ---
>  arch/arm64/mm/mmu.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index 2ba01dc8ef82..c3da836ebe8d 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -29,6 +29,7 @@
>  #include <linux/mm_inline.h>
>  #include <linux/pagewalk.h>
>  #include <linux/stop_machine.h>
> +#include <linux/preempt.h>
>
>  #include <asm/barrier.h>
>  #include <asm/cputype.h>
> @@ -2136,7 +2137,7 @@ void __cpu_replace_ttbr1(pgd_t *pgdp, bool cnp)
>                 ttbr1 |= TTBR_CNP_BIT;
>
>         replace_phys = (void *)__pa_symbol(idmap_cpu_replace_ttbr1);
> -
> +       preempt_disable();
>         cpu_install_idmap();
>
>         /*
> @@ -2148,6 +2149,7 @@ void __cpu_replace_ttbr1(pgd_t *pgdp, bool cnp)
>         local_daif_restore(daif);
>
>         cpu_uninstall_idmap();
> +       preempt_enable();
>  }
>
>  #ifdef CONFIG_ARCH_HAS_PKEYS
> --
> 2.43.0
>


From mpdesouza at suse.com  Sat Dec 27 04:16:07 2025
From: mpdesouza at suse.com (Marcos Paulo de Souza)
Date: Sat, 27 Dec 2025 09:16:07 -0300
Subject: [PATCH 00/19] printk cleanup - part 3
Message-ID: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>

The parts 1 and 2 can be found here [1] and here[2].

The changes proposed in this part 3 are mostly to clarify the usage of
the interfaces for NBCON, and use the printk helpers more broadly.
Besides it, it also introduces a new way to register consoles
and drop thes the CON_ENABLED flag. It seems too much, but in reality
the changes are not complex, and as the title says, it's basically a
cleanup without changing the functional changes.

This patchset includes a patch from part 2 that needed more work [3], as
suggested by Petr Mladek.

These changes were tested by reverting f79b163c4231
("Revert "serial: 8250: Switch to nbcon console""), and used qemu to test
suspend/resume cycles, and everything worked as expected.

PS: b4 --auto-to-cc added a bunch of people as CC, so I'm not sure if
I should remove some or not, so I'm leaving the list as it is. If the
patchset needs a v2, and you feel that you don't need to copied, just
let me know.

Thanks for checking the patches, and happy holidays!

[1]: https://lore.kernel.org/lkml/20250226-printk-renaming-v1-0-0b878577f2e6 at suse.com/#t
[2]: https://lore.kernel.org/linux-serial/20251121-printk-cleanup-part2-v2-0-57b8b78647f4 at suse.com/
[3]: https://lore.kernel.org/linux-serial/aSgeqM3DWvR8-cMY at pathway.suse.cz/

Signed-off-by: Marcos Paulo de Souza <mpdesouza at suse.com>
---
Marcos Paulo de Souza (19):
      printk/nbcon: Use an enum to specify the required callback in console_is_usable()
      printk: Introduce console_is_nbcon
      printk: Drop flags argument from console_is_usable
      printk: Reintroduce consoles_suspended global state
      printk: Add more context to suspend/resume functions
      printk: Introduce register_console_force
      drivers: netconsole: Migrate to register_console_force helper
      debug: debug_core: Migrate to register_console_force helper
      m68k: emu: nfcon.c: Migrate to register_console_force helper
      fs: pstore: platform: Migrate to register_console_force helper
      powerpc: kernel: udbg: Migrate to register_console_force helper
      sparc: kernel: btext: Migrate to register_console_force helper
      um: drivers: mconsole_kern.c: Migrate to register_console_force helper
      drivers: hwtracing: stm: console.c: Migrate to register_console_force helper
      drivers: tty: serial: mux.c: Migrate to register_console_force helper
      drivers: tty: serial: ma35d1_serial: Migrate to register_console_force helper
      drivers: tty: ehv_bytechan: Migrate to register_console_force helper
      drivers: braille: console: Drop CON_ENABLED console flag
      printk: Remove CON_ENABLED flag

 arch/m68k/emu/nfcon.c                           |   5 +-
 arch/powerpc/kernel/udbg.c                      |   4 +-
 arch/sparc/kernel/btext.c                       |   4 +-
 arch/um/drivers/mconsole_kern.c                 |   3 +-
 arch/um/kernel/kmsg_dump.c                      |   2 +-
 drivers/accessibility/braille/braille_console.c |   1 -
 drivers/hwtracing/stm/console.c                 |   4 +-
 drivers/net/netconsole.c                        |  13 +--
 drivers/tty/ehv_bytechan.c                      |   4 +-
 drivers/tty/serial/ma35d1_serial.c              |   4 +-
 drivers/tty/serial/mux.c                        |   4 +-
 drivers/tty/tty_io.c                            |   6 +-
 fs/proc/consoles.c                              |   1 -
 fs/pstore/platform.c                            |   6 +-
 include/linux/console.h                         | 143 +++++++++++++++++++-----
 kernel/debug/debug_core.c                       |   6 +-
 kernel/debug/kdb/kdb_io.c                       |   6 +-
 kernel/printk/nbcon.c                           |  17 +--
 kernel/printk/printk.c                          | 140 ++++++++++++-----------
 19 files changed, 230 insertions(+), 143 deletions(-)
---
base-commit: 93d65587479cfc97c0d7e41b5e8c6378ca681632
change-id: 20251202-printk-cleanup-part3-ea116b11b3a6

Best regards,
--  
Marcos Paulo de Souza <mpdesouza at suse.com>



From mpdesouza at suse.com  Sat Dec 27 04:16:08 2025
From: mpdesouza at suse.com (Marcos Paulo de Souza)
Date: Sat, 27 Dec 2025 09:16:08 -0300
Subject: [PATCH 01/19] printk/nbcon: Use an enum to specify the required
 callback in console_is_usable()
In-Reply-To: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
References: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
Message-ID: <20251227-printk-cleanup-part3-v1-1-21a291bcf197@suse.com>

The current usage of console_is_usable() is clumsy. The parameter
@use_atomic is boolean and thus not self-explanatory. The function is
called twice in situations when there are no-strict requirements.

Replace it with enum nbcon_write_cb which provides a more descriptive
values for all 3 situations: atomic, thread or any.

Note that console_is_usable() checks only NBCON_USE_ATOMIC because
.write_thread() callback is mandatory. But the other two values still
make sense because they describe the intention of the caller.

Suggested-by: Petr Mladek <pmladek at suse.com>
Signed-off-by: Marcos Paulo de Souza <mpdesouza at suse.com>
---
 arch/um/kernel/kmsg_dump.c |  3 ++-
 include/linux/console.h    | 20 +++++++++++++++++---
 kernel/debug/kdb/kdb_io.c  |  2 +-
 kernel/printk/nbcon.c      |  8 ++++----
 kernel/printk/printk.c     | 16 ++++++++--------
 5 files changed, 32 insertions(+), 17 deletions(-)

diff --git a/arch/um/kernel/kmsg_dump.c b/arch/um/kernel/kmsg_dump.c
index fc0f543d1d8e..8ae38308b67c 100644
--- a/arch/um/kernel/kmsg_dump.c
+++ b/arch/um/kernel/kmsg_dump.c
@@ -31,7 +31,8 @@ static void kmsg_dumper_stdout(struct kmsg_dumper *dumper,
 		 * expected to output the crash information.
 		 */
 		if (strcmp(con->name, "ttynull") != 0 &&
-		    console_is_usable(con, console_srcu_read_flags(con), true)) {
+		    console_is_usable(con, console_srcu_read_flags(con),
+				      NBCON_USE_ATOMIC)) {
 			break;
 		}
 	}
diff --git a/include/linux/console.h b/include/linux/console.h
index fc9f5c5c1b04..35c03fc4ed51 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -202,6 +202,19 @@ enum cons_flags {
 	CON_NBCON_ATOMIC_UNSAFE	= BIT(9),
 };
 
+/**
+ * enum nbcon_write_cb - Defines which nbcon write() callback must be used based
+ *                       on the caller context.
+ * @NBCON_USE_ATOMIC: Use con->write_atomic().
+ * @NBCON_USE_THREAD: Use con->write_thread().
+ * @NBCON_USE_ANY:    The caller does not have any strict requirements.
+ */
+enum nbcon_write_cb {
+	NBCON_USE_ATOMIC,
+	NBCON_USE_THREAD,
+	NBCON_USE_ANY,
+};
+
 /**
  * struct nbcon_state - console state for nbcon consoles
  * @atom:	Compound of the state fields for atomic operations
@@ -622,7 +635,8 @@ extern void nbcon_kdb_release(struct nbcon_write_context *wctxt);
  * which can also play a role in deciding if @con can be used to print
  * records.
  */
-static inline bool console_is_usable(struct console *con, short flags, bool use_atomic)
+static inline bool console_is_usable(struct console *con, short flags,
+				     enum nbcon_write_cb nwc)
 {
 	if (!(flags & CON_ENABLED))
 		return false;
@@ -631,7 +645,7 @@ static inline bool console_is_usable(struct console *con, short flags, bool use_
 		return false;
 
 	if (flags & CON_NBCON) {
-		if (use_atomic) {
+		if (nwc & NBCON_USE_ATOMIC) {
 			/* The write_atomic() callback is optional. */
 			if (!con->write_atomic)
 				return false;
@@ -679,7 +693,7 @@ static inline bool nbcon_kdb_try_acquire(struct console *con,
 					 struct nbcon_write_context *wctxt) { return false; }
 static inline void nbcon_kdb_release(struct nbcon_write_context *wctxt) { }
 static inline bool console_is_usable(struct console *con, short flags,
-				     bool use_atomic) { return false; }
+				     enum nbcon_write_cb nwc) { return false; }
 #endif
 
 extern int console_set_on_cmdline;
diff --git a/kernel/debug/kdb/kdb_io.c b/kernel/debug/kdb/kdb_io.c
index 61c1690058ed..6ffb962392a4 100644
--- a/kernel/debug/kdb/kdb_io.c
+++ b/kernel/debug/kdb/kdb_io.c
@@ -591,7 +591,7 @@ static void kdb_msg_write(const char *msg, int msg_len)
 	for_each_console_srcu(c) {
 		short flags = console_srcu_read_flags(c);
 
-		if (!console_is_usable(c, flags, true))
+		if (!console_is_usable(c, flags, NBCON_USE_ATOMIC))
 			continue;
 		if (c == dbg_io_ops->cons)
 			continue;
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index be5a04367e60..13865ef85990 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -1184,7 +1184,7 @@ static bool nbcon_kthread_should_wakeup(struct console *con, struct nbcon_contex
 	cookie = console_srcu_read_lock();
 
 	flags = console_srcu_read_flags(con);
-	if (console_is_usable(con, flags, false)) {
+	if (console_is_usable(con, flags, NBCON_USE_THREAD)) {
 		/* Bring the sequence in @ctxt up to date */
 		ctxt->seq = nbcon_seq_read(con);
 
@@ -1251,7 +1251,7 @@ static int nbcon_kthread_func(void *__console)
 
 		con_flags = console_srcu_read_flags(con);
 
-		if (console_is_usable(con, con_flags, false))
+		if (console_is_usable(con, con_flags, NBCON_USE_THREAD))
 			backlog = nbcon_emit_one(&wctxt, false);
 
 		console_srcu_read_unlock(cookie);
@@ -1650,7 +1650,7 @@ static void __nbcon_atomic_flush_pending(u64 stop_seq)
 		if (!(flags & CON_NBCON))
 			continue;
 
-		if (!console_is_usable(con, flags, true))
+		if (!console_is_usable(con, flags, NBCON_USE_ATOMIC))
 			continue;
 
 		if (nbcon_seq_read(con) >= stop_seq)
@@ -1904,7 +1904,7 @@ void nbcon_device_release(struct console *con)
 	 */
 	cookie = console_srcu_read_lock();
 	printk_get_console_flush_type(&ft);
-	if (console_is_usable(con, console_srcu_read_flags(con), true) &&
+	if (console_is_usable(con, console_srcu_read_flags(con), NBCON_USE_ATOMIC) &&
 	    !ft.nbcon_offload &&
 	    prb_read_valid(prb, nbcon_seq_read(con), NULL)) {
 		/*
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 7394f1b6033b..5f4b84f9562e 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3203,7 +3203,9 @@ static bool console_flush_one_record(bool do_cond_resched, u64 *next_seq, bool *
 		if ((flags & CON_NBCON) && (ft.nbcon_atomic || ft.nbcon_offload))
 			continue;
 
-		if (!console_is_usable(con, flags, !do_cond_resched))
+		if (!console_is_usable(con, flags,
+				       do_cond_resched ? NBCON_USE_THREAD
+						       : NBCON_USE_ATOMIC))
 			continue;
 		any_usable = true;
 
@@ -3392,7 +3394,7 @@ void console_unblank(void)
 	 */
 	cookie = console_srcu_read_lock();
 	for_each_console_srcu(c) {
-		if (!console_is_usable(c, console_srcu_read_flags(c), true))
+		if (!console_is_usable(c, console_srcu_read_flags(c), NBCON_USE_ATOMIC))
 			continue;
 
 		if (c->unblank) {
@@ -3432,7 +3434,7 @@ void console_unblank(void)
 
 	cookie = console_srcu_read_lock();
 	for_each_console_srcu(c) {
-		if (!console_is_usable(c, console_srcu_read_flags(c), true))
+		if (!console_is_usable(c, console_srcu_read_flags(c), NBCON_USE_ATOMIC))
 			continue;
 
 		if (c->unblank)
@@ -3633,7 +3635,7 @@ static bool legacy_kthread_should_wakeup(void)
 		if ((flags & CON_NBCON) && (ft.nbcon_atomic || ft.nbcon_offload))
 			continue;
 
-		if (!console_is_usable(con, flags, false))
+		if (!console_is_usable(con, flags, NBCON_USE_THREAD))
 			continue;
 
 		if (flags & CON_NBCON) {
@@ -4204,7 +4206,7 @@ static int unregister_console_locked(struct console *console)
 
 	if (!console_is_registered_locked(console))
 		res = -ENODEV;
-	else if (console_is_usable(console, console->flags, true))
+	else if (console_is_usable(console, console->flags, NBCON_USE_ATOMIC))
 		__pr_flush(console, 1000, true);
 
 	/* Disable it unconditionally */
@@ -4485,10 +4487,8 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
 			 * that they make forward progress, so only increment
 			 * @diff for usable consoles.
 			 */
-			if (!console_is_usable(c, flags, true) &&
-			    !console_is_usable(c, flags, false)) {
+			if (!console_is_usable(c, flags, NBCON_USE_ANY))
 				continue;
-			}
 
 			if (flags & CON_NBCON) {
 				printk_seq = nbcon_seq_read(c);

-- 
2.52.0



From mpdesouza at suse.com  Sat Dec 27 04:16:09 2025
From: mpdesouza at suse.com (Marcos Paulo de Souza)
Date: Sat, 27 Dec 2025 09:16:09 -0300
Subject: [PATCH 02/19] printk: Introduce console_is_nbcon
In-Reply-To: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
References: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
Message-ID: <20251227-printk-cleanup-part3-v1-2-21a291bcf197@suse.com>

Besides checking if the current console is NBCON or not, console->flags
is also being read in order to serve as argument of the console_is_usable
function.

But CON_NBCON flag is unique: it's set just once in the console
registration and never cleared. In this case it can be possible to read
the flag when console_srcu_lock is held (which is the case when using
for_each_console).

This change makes possible to remove the flags argument from
console_is_usable in the next patches.

Signed-off-by: Petr Mladek <pmladek at suse.com>
Signed-off-by: Marcos Paulo de Souza <mpdesouza at suse.com>
---
 include/linux/console.h   | 27 +++++++++++++++++++++++++++
 kernel/debug/kdb/kdb_io.c |  2 +-
 kernel/printk/nbcon.c     |  2 +-
 kernel/printk/printk.c    | 15 ++++++---------
 4 files changed, 35 insertions(+), 11 deletions(-)

diff --git a/include/linux/console.h b/include/linux/console.h
index 35c03fc4ed51..dd4ec7a5bff9 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -561,6 +561,33 @@ static inline void console_srcu_write_flags(struct console *con, short flags)
 	WRITE_ONCE(con->flags, flags);
 }
 
+/**
+ * console_srcu_is_nbcon - Locklessly check whether the console is nbcon
+ * @con:	struct console pointer of console to check
+ *
+ * Requires console_srcu_read_lock to be held, which implies that @con might
+ * be a registered console. The purpose of holding console_srcu_read_lock is
+ * to guarantee that no exit/cleanup routines will run if the console
+ * is currently undergoing unregistration.
+ *
+ * If the caller is holding the console_list_lock or it is _certain_ that
+ * @con is not and will not become registered, the caller may read
+ * @con->flags directly instead.
+ *
+ * Context: Any context.
+ * Return: True when CON_NBCON flag is set.
+ */
+static inline bool console_is_nbcon(const struct console *con)
+{
+	WARN_ON_ONCE(!console_srcu_read_lock_is_held());
+
+	/*
+	 * The CON_NBCON flag is statically initialized and is never
+	 * set or cleared at runtime.
+	 */
+	return data_race(con->flags & CON_NBCON);
+}
+
 /* Variant of console_is_registered() when the console_list_lock is held. */
 static inline bool console_is_registered_locked(const struct console *con)
 {
diff --git a/kernel/debug/kdb/kdb_io.c b/kernel/debug/kdb/kdb_io.c
index 6ffb962392a4..d6de512b433a 100644
--- a/kernel/debug/kdb/kdb_io.c
+++ b/kernel/debug/kdb/kdb_io.c
@@ -596,7 +596,7 @@ static void kdb_msg_write(const char *msg, int msg_len)
 		if (c == dbg_io_ops->cons)
 			continue;
 
-		if (flags & CON_NBCON) {
+		if (console_is_nbcon(c)) {
 			struct nbcon_write_context wctxt = { };
 
 			/*
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 13865ef85990..f0f42e212caa 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -1647,7 +1647,7 @@ static void __nbcon_atomic_flush_pending(u64 stop_seq)
 	for_each_console_srcu(con) {
 		short flags = console_srcu_read_flags(con);
 
-		if (!(flags & CON_NBCON))
+		if (!console_is_nbcon(con))
 			continue;
 
 		if (!console_is_usable(con, flags, NBCON_USE_ATOMIC))
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 5f4b84f9562e..bd0d574be3cf 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3200,7 +3200,7 @@ static bool console_flush_one_record(bool do_cond_resched, u64 *next_seq, bool *
 		 * nbcon consoles when the nbcon consoles cannot print via
 		 * their atomic or threaded flushing.
 		 */
-		if ((flags & CON_NBCON) && (ft.nbcon_atomic || ft.nbcon_offload))
+		if (console_is_nbcon(con) && (ft.nbcon_atomic || ft.nbcon_offload))
 			continue;
 
 		if (!console_is_usable(con, flags,
@@ -3209,7 +3209,7 @@ static bool console_flush_one_record(bool do_cond_resched, u64 *next_seq, bool *
 			continue;
 		any_usable = true;
 
-		if (flags & CON_NBCON) {
+		if (console_is_nbcon(con)) {
 			progress = nbcon_legacy_emit_next_record(con, handover, cookie,
 								 !do_cond_resched);
 			printk_seq = nbcon_seq_read(con);
@@ -3458,7 +3458,6 @@ void console_unblank(void)
 static void __console_rewind_all(void)
 {
 	struct console *c;
-	short flags;
 	int cookie;
 	u64 seq;
 
@@ -3466,9 +3465,7 @@ static void __console_rewind_all(void)
 
 	cookie = console_srcu_read_lock();
 	for_each_console_srcu(c) {
-		flags = console_srcu_read_flags(c);
-
-		if (flags & CON_NBCON) {
+		if (console_is_nbcon(c)) {
 			nbcon_seq_force(c, seq);
 		} else {
 			/*
@@ -3632,13 +3629,13 @@ static bool legacy_kthread_should_wakeup(void)
 		 * consoles when the nbcon consoles cannot print via their
 		 * atomic or threaded flushing.
 		 */
-		if ((flags & CON_NBCON) && (ft.nbcon_atomic || ft.nbcon_offload))
+		if (console_is_nbcon(con) && (ft.nbcon_atomic || ft.nbcon_offload))
 			continue;
 
 		if (!console_is_usable(con, flags, NBCON_USE_THREAD))
 			continue;
 
-		if (flags & CON_NBCON) {
+		if (console_is_nbcon(con)) {
 			printk_seq = nbcon_seq_read(con);
 		} else {
 			/*
@@ -4490,7 +4487,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
 			if (!console_is_usable(c, flags, NBCON_USE_ANY))
 				continue;
 
-			if (flags & CON_NBCON) {
+			if (console_is_nbcon(c)) {
 				printk_seq = nbcon_seq_read(c);
 			} else {
 				printk_seq = c->seq;

-- 
2.52.0



From mpdesouza at suse.com  Sat Dec 27 04:16:10 2025
From: mpdesouza at suse.com (Marcos Paulo de Souza)
Date: Sat, 27 Dec 2025 09:16:10 -0300
Subject: [PATCH 03/19] printk: Drop flags argument from console_is_usable
In-Reply-To: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
References: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
Message-ID: <20251227-printk-cleanup-part3-v1-3-21a291bcf197@suse.com>

The flags argument was also used to check if CON_NBCON was set, but their
usage was fixed in the last commit. All current users are reading the
variable just to call console_is_usable.

By calling console_srcu_read_flags inside console_is_usable makes the
code cleaner and removes one argument from the function.

Along with it, create a variant called __console_is_usable that can be
used under console_list_lock(), like unregister_console_locked.

Signed-off-by: Marcos Paulo de Souza <mpdesouza at suse.com>
---
 arch/um/kernel/kmsg_dump.c |  3 +--
 include/linux/console.h    | 25 +++++++++++++++++--------
 kernel/debug/kdb/kdb_io.c  |  4 +---
 kernel/printk/nbcon.c      | 15 ++++-----------
 kernel/printk/printk.c     | 20 +++++++-------------
 5 files changed, 30 insertions(+), 37 deletions(-)

diff --git a/arch/um/kernel/kmsg_dump.c b/arch/um/kernel/kmsg_dump.c
index 8ae38308b67c..ca80232cfa2a 100644
--- a/arch/um/kernel/kmsg_dump.c
+++ b/arch/um/kernel/kmsg_dump.c
@@ -31,8 +31,7 @@ static void kmsg_dumper_stdout(struct kmsg_dumper *dumper,
 		 * expected to output the crash information.
 		 */
 		if (strcmp(con->name, "ttynull") != 0 &&
-		    console_is_usable(con, console_srcu_read_flags(con),
-				      NBCON_USE_ATOMIC)) {
+		    console_is_usable(con, NBCON_USE_ATOMIC)) {
 			break;
 		}
 	}
diff --git a/include/linux/console.h b/include/linux/console.h
index dd4ec7a5bff9..648cf10e3f93 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -656,13 +656,8 @@ extern bool nbcon_kdb_try_acquire(struct console *con,
 				  struct nbcon_write_context *wctxt);
 extern void nbcon_kdb_release(struct nbcon_write_context *wctxt);
 
-/*
- * Check if the given console is currently capable and allowed to print
- * records. Note that this function does not consider the current context,
- * which can also play a role in deciding if @con can be used to print
- * records.
- */
-static inline bool console_is_usable(struct console *con, short flags,
+/* Variant of console_is_usable() when the console_list_lock is held. */
+static inline bool __console_is_usable(struct console *con, short flags,
 				     enum nbcon_write_cb nwc)
 {
 	if (!(flags & CON_ENABLED))
@@ -707,6 +702,18 @@ static inline bool console_is_usable(struct console *con, short flags,
 	return true;
 }
 
+/*
+ * Check if the given console is currently capable and allowed to print
+ * records. Note that this function does not consider the current context,
+ * which can also play a role in deciding if @con can be used to print
+ * records.
+ */
+static inline bool console_is_usable(struct console *con,
+				     enum nbcon_write_cb nwc)
+{
+	return __console_is_usable(con, console_srcu_read_flags(con), nwc);
+}
+
 #else
 static inline void nbcon_cpu_emergency_enter(void) { }
 static inline void nbcon_cpu_emergency_exit(void) { }
@@ -719,7 +726,9 @@ static inline void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt) { }
 static inline bool nbcon_kdb_try_acquire(struct console *con,
 					 struct nbcon_write_context *wctxt) { return false; }
 static inline void nbcon_kdb_release(struct nbcon_write_context *wctxt) { }
-static inline bool console_is_usable(struct console *con, short flags,
+static inline bool __console_is_usable(struct console *con, short flags,
+				       enum nbcon_write_cb nwc) { return false; }
+static inline bool console_is_usable(struct console *con,
 				     enum nbcon_write_cb nwc) { return false; }
 #endif
 
diff --git a/kernel/debug/kdb/kdb_io.c b/kernel/debug/kdb/kdb_io.c
index d6de512b433a..642eab746577 100644
--- a/kernel/debug/kdb/kdb_io.c
+++ b/kernel/debug/kdb/kdb_io.c
@@ -589,9 +589,7 @@ static void kdb_msg_write(const char *msg, int msg_len)
 	 */
 	cookie = console_srcu_read_lock();
 	for_each_console_srcu(c) {
-		short flags = console_srcu_read_flags(c);
-
-		if (!console_is_usable(c, flags, NBCON_USE_ATOMIC))
+		if (!console_is_usable(c, NBCON_USE_ATOMIC))
 			continue;
 		if (c == dbg_io_ops->cons)
 			continue;
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index f0f42e212caa..f0659c1e50ed 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -1164,7 +1164,6 @@ static bool nbcon_emit_one(struct nbcon_write_context *wctxt, bool use_atomic)
 static bool nbcon_kthread_should_wakeup(struct console *con, struct nbcon_context *ctxt)
 {
 	bool ret = false;
-	short flags;
 	int cookie;
 
 	if (kthread_should_stop())
@@ -1183,8 +1182,7 @@ static bool nbcon_kthread_should_wakeup(struct console *con, struct nbcon_contex
 
 	cookie = console_srcu_read_lock();
 
-	flags = console_srcu_read_flags(con);
-	if (console_is_usable(con, flags, NBCON_USE_THREAD)) {
+	if (console_is_usable(con, NBCON_USE_THREAD)) {
 		/* Bring the sequence in @ctxt up to date */
 		ctxt->seq = nbcon_seq_read(con);
 
@@ -1209,7 +1207,6 @@ static int nbcon_kthread_func(void *__console)
 		.ctxt.prio	= NBCON_PRIO_NORMAL,
 	};
 	struct nbcon_context *ctxt = &ACCESS_PRIVATE(&wctxt, ctxt);
-	short con_flags;
 	bool backlog;
 	int cookie;
 
@@ -1249,9 +1246,7 @@ static int nbcon_kthread_func(void *__console)
 		 */
 		cookie = console_srcu_read_lock();
 
-		con_flags = console_srcu_read_flags(con);
-
-		if (console_is_usable(con, con_flags, NBCON_USE_THREAD))
+		if (console_is_usable(con, NBCON_USE_THREAD))
 			backlog = nbcon_emit_one(&wctxt, false);
 
 		console_srcu_read_unlock(cookie);
@@ -1645,12 +1640,10 @@ static void __nbcon_atomic_flush_pending(u64 stop_seq)
 
 	cookie = console_srcu_read_lock();
 	for_each_console_srcu(con) {
-		short flags = console_srcu_read_flags(con);
-
 		if (!console_is_nbcon(con))
 			continue;
 
-		if (!console_is_usable(con, flags, NBCON_USE_ATOMIC))
+		if (!console_is_usable(con, NBCON_USE_ATOMIC))
 			continue;
 
 		if (nbcon_seq_read(con) >= stop_seq)
@@ -1904,7 +1897,7 @@ void nbcon_device_release(struct console *con)
 	 */
 	cookie = console_srcu_read_lock();
 	printk_get_console_flush_type(&ft);
-	if (console_is_usable(con, console_srcu_read_flags(con), NBCON_USE_ATOMIC) &&
+	if (console_is_usable(con, NBCON_USE_ATOMIC) &&
 	    !ft.nbcon_offload &&
 	    prb_read_valid(prb, nbcon_seq_read(con), NULL)) {
 		/*
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index bd0d574be3cf..b03ffc23c27c 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3191,7 +3191,6 @@ static bool console_flush_one_record(bool do_cond_resched, u64 *next_seq, bool *
 
 	cookie = console_srcu_read_lock();
 	for_each_console_srcu(con) {
-		short flags = console_srcu_read_flags(con);
 		u64 printk_seq;
 		bool progress;
 
@@ -3203,9 +3202,8 @@ static bool console_flush_one_record(bool do_cond_resched, u64 *next_seq, bool *
 		if (console_is_nbcon(con) && (ft.nbcon_atomic || ft.nbcon_offload))
 			continue;
 
-		if (!console_is_usable(con, flags,
-				       do_cond_resched ? NBCON_USE_THREAD
-						       : NBCON_USE_ATOMIC))
+		if (!console_is_usable(con, do_cond_resched ? NBCON_USE_THREAD
+							    : NBCON_USE_ATOMIC))
 			continue;
 		any_usable = true;
 
@@ -3394,7 +3392,7 @@ void console_unblank(void)
 	 */
 	cookie = console_srcu_read_lock();
 	for_each_console_srcu(c) {
-		if (!console_is_usable(c, console_srcu_read_flags(c), NBCON_USE_ATOMIC))
+		if (!console_is_usable(c, NBCON_USE_ATOMIC))
 			continue;
 
 		if (c->unblank) {
@@ -3434,7 +3432,7 @@ void console_unblank(void)
 
 	cookie = console_srcu_read_lock();
 	for_each_console_srcu(c) {
-		if (!console_is_usable(c, console_srcu_read_flags(c), NBCON_USE_ATOMIC))
+		if (!console_is_usable(c, NBCON_USE_ATOMIC))
 			continue;
 
 		if (c->unblank)
@@ -3621,7 +3619,6 @@ static bool legacy_kthread_should_wakeup(void)
 
 	cookie = console_srcu_read_lock();
 	for_each_console_srcu(con) {
-		short flags = console_srcu_read_flags(con);
 		u64 printk_seq;
 
 		/*
@@ -3632,7 +3629,7 @@ static bool legacy_kthread_should_wakeup(void)
 		if (console_is_nbcon(con) && (ft.nbcon_atomic || ft.nbcon_offload))
 			continue;
 
-		if (!console_is_usable(con, flags, NBCON_USE_THREAD))
+		if (!console_is_usable(con, NBCON_USE_THREAD))
 			continue;
 
 		if (console_is_nbcon(con)) {
@@ -4203,7 +4200,7 @@ static int unregister_console_locked(struct console *console)
 
 	if (!console_is_registered_locked(console))
 		res = -ENODEV;
-	else if (console_is_usable(console, console->flags, NBCON_USE_ATOMIC))
+	else if (__console_is_usable(console, console->flags, NBCON_USE_ATOMIC))
 		__pr_flush(console, 1000, true);
 
 	/* Disable it unconditionally */
@@ -4430,7 +4427,6 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
 	struct console *c;
 	u64 last_diff = 0;
 	u64 printk_seq;
-	short flags;
 	int cookie;
 	u64 diff;
 	u64 seq;
@@ -4477,14 +4473,12 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
 			if (con && con != c)
 				continue;
 
-			flags = console_srcu_read_flags(c);
-
 			/*
 			 * If consoles are not usable, it cannot be expected
 			 * that they make forward progress, so only increment
 			 * @diff for usable consoles.
 			 */
-			if (!console_is_usable(c, flags, NBCON_USE_ANY))
+			if (!console_is_usable(c, NBCON_USE_ANY))
 				continue;
 
 			if (console_is_nbcon(c)) {

-- 
2.52.0



From mpdesouza at suse.com  Sat Dec 27 04:16:11 2025
From: mpdesouza at suse.com (Marcos Paulo de Souza)
Date: Sat, 27 Dec 2025 09:16:11 -0300
Subject: [PATCH 04/19] printk: Reintroduce consoles_suspended global state
In-Reply-To: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
References: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
Message-ID: <20251227-printk-cleanup-part3-v1-4-21a291bcf197@suse.com>

This change partially reverts commit 9e70a5e109a4
("printk: Add per-console suspended state"). The intent of the original
commit was to move the management of the console suspended state to the
consoles themselves to be able to use SRCU instead of console lock.

But having a global state is still useful when checking if the global
suspend was triggered by power management. This way, instead of setting
the state of each individual console, the code would only set/read from the
global state.

Along with this change, two more fixes are necessary: change
console_{suspend,resume} to set/clear CON_SUSPEND instead of setting
CON_ENABLED and change show_cons_active to call __console_is_usable to
check console usefulness.

Link: https://lore.kernel.org/lkml/844j4lepak.fsf at jogness.linutronix.de/
Signed-off-by: Petr Mladek <pmladek at suse.com>
[mpdesouza at suse.com: Adapted code related to console_is_usable]
Signed-off-by: Marcos Paulo de Souza <mpdesouza at suse.com>
---
 drivers/tty/tty_io.c    |  6 +++---
 include/linux/console.h | 53 +++++++++++++++++++++++++++++++++++++++++++++++--
 kernel/printk/printk.c  | 23 +++++++++++----------
 3 files changed, 67 insertions(+), 15 deletions(-)

diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index e2d92cf70eb7..7d2bded75b75 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -3552,9 +3552,9 @@ static ssize_t show_cons_active(struct device *dev,
 	for_each_console(c) {
 		if (!c->device)
 			continue;
-		if (!(c->flags & CON_NBCON) && !c->write)
-			continue;
-		if ((c->flags & CON_ENABLED) == 0)
+		if (!__console_is_usable(c, c->flags,
+					 consoles_suspended,
+					 NBCON_USE_ANY))
 			continue;
 		cs[i++] = c;
 		if (i >= ARRAY_SIZE(cs))
diff --git a/include/linux/console.h b/include/linux/console.h
index 648cf10e3f93..caf9b0951129 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -509,6 +509,7 @@ extern void console_list_lock(void) __acquires(console_mutex);
 extern void console_list_unlock(void) __releases(console_mutex);
 
 extern struct hlist_head console_list;
+extern bool consoles_suspended;
 
 /**
  * console_srcu_read_flags - Locklessly read flags of a possibly registered
@@ -561,6 +562,47 @@ static inline void console_srcu_write_flags(struct console *con, short flags)
 	WRITE_ONCE(con->flags, flags);
 }
 
+/**
+ * consoles_suspended_srcu_read - Locklessly read the global flag for
+ *				suspending all consoles.
+ *
+ * The global "consoles_suspended" flag is synchronized using console_list_lock
+ * and console_srcu_read_lock. It is the same approach as CON_SUSPENDED flag.
+ * See console_srcu_read_flags() for more details.
+ *
+ * Context: Any context.
+ * Return: The current value of the global "consoles_suspended" flag.
+ */
+static inline bool consoles_suspended_srcu_read(void)
+{
+	WARN_ON_ONCE(!console_srcu_read_lock_is_held());
+
+	/*
+	 * The READ_ONCE() matches the WRITE_ONCE() when "consoles_suspended"
+	 * is modified with consoles_suspended_srcu_write().
+	 */
+	return data_race(READ_ONCE(consoles_suspended));
+}
+
+/**
+ * consoles_suspended_srcu_write - Write the global flag for suspending
+ *			all consoles.
+ * @suspend:	new value to write
+ *
+ * The write must be done under the console_list_lock. The caller is responsible
+ * for calling synchronize_srcu() to make sure that all callers checking the
+ * usablility of registered consoles see the new state.
+ *
+ * Context: Any context.
+ */
+static inline void consoles_suspended_srcu_write(bool suspend)
+{
+	lockdep_assert_console_list_lock_held();
+
+	/* This matches the READ_ONCE() in consoles_suspended_srcu_read(). */
+	WRITE_ONCE(consoles_suspended, suspend);
+}
+
 /**
  * console_srcu_is_nbcon - Locklessly check whether the console is nbcon
  * @con:	struct console pointer of console to check
@@ -658,8 +700,12 @@ extern void nbcon_kdb_release(struct nbcon_write_context *wctxt);
 
 /* Variant of console_is_usable() when the console_list_lock is held. */
 static inline bool __console_is_usable(struct console *con, short flags,
-				     enum nbcon_write_cb nwc)
+				       bool all_suspended,
+				       enum nbcon_write_cb nwc)
 {
+	if (all_suspended)
+		return false;
+
 	if (!(flags & CON_ENABLED))
 		return false;
 
@@ -711,7 +757,9 @@ static inline bool __console_is_usable(struct console *con, short flags,
 static inline bool console_is_usable(struct console *con,
 				     enum nbcon_write_cb nwc)
 {
-	return __console_is_usable(con, console_srcu_read_flags(con), nwc);
+	return __console_is_usable(con, console_srcu_read_flags(con),
+				   consoles_suspended_srcu_read(),
+				   nwc);
 }
 
 #else
@@ -727,6 +775,7 @@ static inline bool nbcon_kdb_try_acquire(struct console *con,
 					 struct nbcon_write_context *wctxt) { return false; }
 static inline void nbcon_kdb_release(struct nbcon_write_context *wctxt) { }
 static inline bool __console_is_usable(struct console *con, short flags,
+				       bool all_suspended,
 				       enum nbcon_write_cb nwc) { return false; }
 static inline bool console_is_usable(struct console *con,
 				     enum nbcon_write_cb nwc) { return false; }
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index b03ffc23c27c..173c14e08afe 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -104,6 +104,13 @@ DEFINE_STATIC_SRCU(console_srcu);
  */
 int __read_mostly suppress_printk;
 
+/*
+ * Global flag for calling down all consoles during suspend.
+ * There is also a per-console flag which is used when the related
+ * device HW gets disabled, see CON_SUSPEND.
+ */
+bool consoles_suspended;
+
 #ifdef CONFIG_LOCKDEP
 static struct lockdep_map console_lock_dep_map = {
 	.name = "console_lock"
@@ -2731,8 +2738,6 @@ MODULE_PARM_DESC(console_no_auto_verbose, "Disable console loglevel raise to hig
  */
 void console_suspend_all(void)
 {
-	struct console *con;
-
 	if (console_suspend_enabled)
 		pr_info("Suspending console(s) (use no_console_suspend to debug)\n");
 
@@ -2749,8 +2754,7 @@ void console_suspend_all(void)
 		return;
 
 	console_list_lock();
-	for_each_console(con)
-		console_srcu_write_flags(con, con->flags | CON_SUSPENDED);
+	consoles_suspended_srcu_write(true);
 	console_list_unlock();
 
 	/*
@@ -2765,7 +2769,6 @@ void console_suspend_all(void)
 void console_resume_all(void)
 {
 	struct console_flush_type ft;
-	struct console *con;
 
 	/*
 	 * Allow queueing irq_work. After restoring console state, deferred
@@ -2776,8 +2779,7 @@ void console_resume_all(void)
 
 	if (console_suspend_enabled) {
 		console_list_lock();
-		for_each_console(con)
-			console_srcu_write_flags(con, con->flags & ~CON_SUSPENDED);
+		consoles_suspended_srcu_write(false);
 		console_list_unlock();
 
 		/*
@@ -3557,7 +3559,7 @@ void console_suspend(struct console *console)
 {
 	__pr_flush(console, 1000, true);
 	console_list_lock();
-	console_srcu_write_flags(console, console->flags & ~CON_ENABLED);
+	console_srcu_write_flags(console, console->flags | CON_SUSPENDED);
 	console_list_unlock();
 
 	/*
@@ -3576,7 +3578,7 @@ void console_resume(struct console *console)
 	bool is_nbcon;
 
 	console_list_lock();
-	console_srcu_write_flags(console, console->flags | CON_ENABLED);
+	console_srcu_write_flags(console, console->flags & ~CON_SUSPENDED);
 	is_nbcon = console->flags & CON_NBCON;
 	console_list_unlock();
 
@@ -4200,7 +4202,8 @@ static int unregister_console_locked(struct console *console)
 
 	if (!console_is_registered_locked(console))
 		res = -ENODEV;
-	else if (__console_is_usable(console, console->flags, NBCON_USE_ATOMIC))
+	else if (__console_is_usable(console, console->flags,
+				     consoles_suspended, NBCON_USE_ATOMIC))
 		__pr_flush(console, 1000, true);
 
 	/* Disable it unconditionally */

-- 
2.52.0



From mpdesouza at suse.com  Sat Dec 27 04:16:12 2025
From: mpdesouza at suse.com (Marcos Paulo de Souza)
Date: Sat, 27 Dec 2025 09:16:12 -0300
Subject: [PATCH 05/19] printk: Add more context to suspend/resume functions
In-Reply-To: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
References: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
Message-ID: <20251227-printk-cleanup-part3-v1-5-21a291bcf197@suse.com>

The new comments clarifies from where the functions are supposed to be
called.

Signed-off-by: Marcos Paulo de Souza <mpdesouza at suse.com>
---
 kernel/printk/printk.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 173c14e08afe..85a8b6521d9e 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2734,7 +2734,8 @@ MODULE_PARM_DESC(console_no_auto_verbose, "Disable console loglevel raise to hig
 /**
  * console_suspend_all - suspend the console subsystem
  *
- * This disables printk() while we go into suspend states
+ * This disables printk() while we go into suspend states. Called by the power
+ * management subsystem.
  */
 void console_suspend_all(void)
 {
@@ -2766,6 +2767,12 @@ void console_suspend_all(void)
 	synchronize_srcu(&console_srcu);
 }
 
+/**
+ * console_resume_all - resume the console subsystem
+ *
+ * This resumes printk() when the system is being restored. Called by the power
+ * management subsystem.
+ */
 void console_resume_all(void)
 {
 	struct console_flush_type ft;
@@ -3553,7 +3560,7 @@ struct tty_driver *console_device(int *index)
 /*
  * Prevent further output on the passed console device so that (for example)
  * serial drivers can suspend console output before suspending a port, and can
- * re-enable output afterwards.
+ * re-enable output afterwards. Called by console drivers.
  */
 void console_suspend(struct console *console)
 {
@@ -3572,6 +3579,7 @@ void console_suspend(struct console *console)
 }
 EXPORT_SYMBOL(console_suspend);
 
+/* Resumes printing on the passed console device. Called by console drivers. */
 void console_resume(struct console *console)
 {
 	struct console_flush_type ft;

-- 
2.52.0



From mpdesouza at suse.com  Sat Dec 27 04:16:13 2025
From: mpdesouza at suse.com (Marcos Paulo de Souza)
Date: Sat, 27 Dec 2025 09:16:13 -0300
Subject: [PATCH 06/19] printk: Introduce register_console_force
In-Reply-To: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
References: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
Message-ID: <20251227-printk-cleanup-part3-v1-6-21a291bcf197@suse.com>

The register_console_force function will register a console even if it
wasn't specified on boot. The new function will act like all consoles
being registered were using the CON_ENABLED flag.

The CON_ENABLED flag will be removed in the following patches and the
drivers that use it will migrate to register_console_force instead.

Signed-off-by: Marcos Paulo de Souza <mpdesouza at suse.com>
---
 include/linux/console.h |  1 +
 kernel/printk/printk.c  | 65 ++++++++++++++++++++++++++++++++-----------------
 2 files changed, 43 insertions(+), 23 deletions(-)

diff --git a/include/linux/console.h b/include/linux/console.h
index caf9b0951129..7d374a29a625 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -792,6 +792,7 @@ enum con_flush_mode {
 extern int add_preferred_console(const char *name, const short idx, char *options);
 extern void console_force_preferred_locked(struct console *con);
 extern void register_console(struct console *);
+extern void register_console_force(struct console *c);
 extern int unregister_console(struct console *);
 extern void console_lock(void);
 extern int console_trylock(void);
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 85a8b6521d9e..c5c05e4d0a67 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3858,7 +3858,7 @@ static int console_call_setup(struct console *newcon, char *options)
  * enabled such as netconsole
  */
 static int try_enable_preferred_console(struct console *newcon,
-					bool user_specified)
+					bool user_specified, bool force)
 {
 	struct console_cmdline *c;
 	int i, err;
@@ -3896,12 +3896,15 @@ static int try_enable_preferred_console(struct console *newcon,
 		return 0;
 	}
 
+	if (force)
+		newcon->flags |= CON_ENABLED;
+
 	/*
 	 * Some consoles, such as pstore and netconsole, can be enabled even
 	 * without matching. Accept the pre-enabled consoles only when match()
 	 * and setup() had a chance to be called.
 	 */
-	if (newcon->flags & CON_ENABLED && c->user_specified ==	user_specified)
+	if (newcon->flags & CON_ENABLED && c->user_specified == user_specified)
 		return 0;
 
 	return -ENOENT;
@@ -4001,26 +4004,11 @@ static u64 get_init_console_seq(struct console *newcon, bool bootcon_registered)
 
 static int unregister_console_locked(struct console *console);
 
-/*
- * The console driver calls this routine during kernel initialization
- * to register the console printing procedure with printk() and to
- * print any messages that were printed by the kernel before the
- * console driver was initialized.
- *
- * This can happen pretty early during the boot process (because of
- * early_printk) - sometimes before setup_arch() completes - be careful
- * of what kernel features are used - they may not be initialised yet.
- *
- * There are two types of consoles - bootconsoles (early_printk) and
- * "real" consoles (everything which is not a bootconsole) which are
- * handled differently.
- *  - Any number of bootconsoles can be registered at any time.
- *  - As soon as a "real" console is registered, all bootconsoles
- *    will be unregistered automatically.
- *  - Once a "real" console is registered, any attempt to register a
- *    bootconsoles will be rejected
+/**
+ * __register_console: Register a new console
+ * @force: Register the console even if not specified on boot
  */
-void register_console(struct console *newcon)
+static void __register_console(struct console *newcon, bool force)
 {
 	bool use_device_lock = (newcon->flags & CON_NBCON) && newcon->write_atomic;
 	bool bootcon_registered = false;
@@ -4080,11 +4068,11 @@ void register_console(struct console *newcon)
 	}
 
 	/* See if this console matches one we selected on the command line */
-	err = try_enable_preferred_console(newcon, true);
+	err = try_enable_preferred_console(newcon, true, force);
 
 	/* If not, try to match against the platform default(s) */
 	if (err == -ENOENT)
-		err = try_enable_preferred_console(newcon, false);
+		err = try_enable_preferred_console(newcon, false, force);
 
 	/* printk() messages are not printed to the Braille console. */
 	if (err || newcon->flags & CON_BRL) {
@@ -4185,8 +4173,39 @@ void register_console(struct console *newcon)
 unlock:
 	console_list_unlock();
 }
+
+/*
+ * The console driver calls this routine during kernel initialization
+ * to register the console printing procedure with printk() and to
+ * print any messages that were printed by the kernel before the
+ * console driver was initialized.
+ *
+ * This can happen pretty early during the boot process (because of
+ * early_printk) - sometimes before setup_arch() completes - be careful
+ * of what kernel features are used - they may not be initialised yet.
+ *
+ * There are two types of consoles - bootconsoles (early_printk) and
+ * "real" consoles (everything which is not a bootconsole) which are
+ * handled differently.
+ *  - Any number of bootconsoles can be registered at any time.
+ *  - As soon as a "real" console is registered, all bootconsoles
+ *    will be unregistered automatically.
+ *  - Once a "real" console is registered, any attempt to register a
+ *    bootconsoles will be rejected
+ */
+void register_console(struct console *newcon)
+{
+	__register_console(newcon, false);
+}
 EXPORT_SYMBOL(register_console);
 
+
+void register_console_force(struct console *newcon)
+{
+	__register_console(newcon, true);
+}
+EXPORT_SYMBOL(register_console_force);
+
 /* Must be called under console_list_lock(). */
 static int unregister_console_locked(struct console *console)
 {

-- 
2.52.0



From mpdesouza at suse.com  Sat Dec 27 04:16:14 2025
From: mpdesouza at suse.com (Marcos Paulo de Souza)
Date: Sat, 27 Dec 2025 09:16:14 -0300
Subject: [PATCH 07/19] drivers: netconsole: Migrate to
 register_console_force helper
In-Reply-To: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
References: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
Message-ID: <20251227-printk-cleanup-part3-v1-7-21a291bcf197@suse.com>

The register_console_force function was introduced to register consoles
even on the presence of default consoles, replacing the CON_ENABLE flag
that was forcing the same behavior.

Signed-off-by: Marcos Paulo de Souza <mpdesouza at suse.com>
---
 drivers/net/netconsole.c | 13 +++++--------
 1 file changed, 5 insertions(+), 8 deletions(-)

diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index bb6e03a92956..509ab629d95f 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -583,16 +583,14 @@ static ssize_t enabled_store(struct config_item *item,
 		}
 
 		if (nt->extended && !console_is_registered(&netconsole_ext)) {
-			netconsole_ext.flags |= CON_ENABLED;
-			register_console(&netconsole_ext);
+			register_console_force(&netconsole_ext);
 		}
 
 		/* User might be enabling the basic format target for the very
 		 * first time, make sure the console is registered.
 		 */
 		if (!nt->extended && !console_is_registered(&netconsole)) {
-			netconsole.flags |= CON_ENABLED;
-			register_console(&netconsole);
+			register_console_force(&netconsole);
 		}
 
 		/*
@@ -1917,13 +1915,12 @@ static void free_param_target(struct netconsole_target *nt)
 
 static struct console netconsole_ext = {
 	.name	= "netcon_ext",
-	.flags	= CON_ENABLED | CON_EXTENDED,
+	.flags	= CON_EXTENDED,
 	.write	= write_ext_msg,
 };
 
 static struct console netconsole = {
 	.name	= "netcon",
-	.flags	= CON_ENABLED,
 	.write	= write_msg,
 };
 
@@ -1971,9 +1968,9 @@ static int __init init_netconsole(void)
 		goto undonotifier;
 
 	if (console_type_needed & CONS_EXTENDED)
-		register_console(&netconsole_ext);
+		register_console_force(&netconsole_ext);
 	if (console_type_needed & CONS_BASIC)
-		register_console(&netconsole);
+		register_console_force(&netconsole);
 	pr_info("network logging started\n");
 
 	return err;

-- 
2.52.0



From mpdesouza at suse.com  Sat Dec 27 04:16:15 2025
From: mpdesouza at suse.com (Marcos Paulo de Souza)
Date: Sat, 27 Dec 2025 09:16:15 -0300
Subject: [PATCH 08/19] debug: debug_core: Migrate to register_console_force
 helper
In-Reply-To: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
References: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
Message-ID: <20251227-printk-cleanup-part3-v1-8-21a291bcf197@suse.com>

The register_console_force function was introduced to register consoles
even on the presence of default consoles, replacing the CON_ENABLE flag
that was forcing the same behavior.

No functional changes.

Signed-off-by: Marcos Paulo de Souza <mpdesouza at suse.com>
---
 kernel/debug/debug_core.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c
index 0b9495187fba..4bf736e5a059 100644
--- a/kernel/debug/debug_core.c
+++ b/kernel/debug/debug_core.c
@@ -941,7 +941,7 @@ static void kgdb_console_write(struct console *co, const char *s,
 static struct console kgdbcons = {
 	.name		= "kgdb",
 	.write		= kgdb_console_write,
-	.flags		= CON_PRINTBUFFER | CON_ENABLED,
+	.flags		= CON_PRINTBUFFER,
 	.index		= -1,
 };
 
@@ -950,7 +950,7 @@ static int __init opt_kgdb_con(char *str)
 	kgdb_use_con = 1;
 
 	if (kgdb_io_module_registered && !kgdb_con_registered) {
-		register_console(&kgdbcons);
+		register_console_force(&kgdbcons);
 		kgdb_con_registered = 1;
 	}
 
@@ -1071,7 +1071,7 @@ static void kgdb_register_callbacks(void)
 		register_sysrq_key('g', &sysrq_dbg_op);
 #endif
 		if (kgdb_use_con && !kgdb_con_registered) {
-			register_console(&kgdbcons);
+			register_console_force(&kgdbcons);
 			kgdb_con_registered = 1;
 		}
 	}

-- 
2.52.0



From mpdesouza at suse.com  Sat Dec 27 04:16:16 2025
From: mpdesouza at suse.com (Marcos Paulo de Souza)
Date: Sat, 27 Dec 2025 09:16:16 -0300
Subject: [PATCH 09/19] m68k: emu: nfcon.c: Migrate to
 register_console_force helper
In-Reply-To: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
References: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
Message-ID: <20251227-printk-cleanup-part3-v1-9-21a291bcf197@suse.com>

The register_console_force function was introduced to register consoles
even on the presence of default consoles, replacing the CON_ENABLE flag
that was forcing the same behavior.

No functional changes.

Signed-off-by: Marcos Paulo de Souza <mpdesouza at suse.com>
---
 arch/m68k/emu/nfcon.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/arch/m68k/emu/nfcon.c b/arch/m68k/emu/nfcon.c
index d41260672e24..3504bbb4aedc 100644
--- a/arch/m68k/emu/nfcon.c
+++ b/arch/m68k/emu/nfcon.c
@@ -110,10 +110,9 @@ static int __init nf_debug_setup(char *arg)
 		/*
 		 * The console will be enabled when debug=nfcon is specified
 		 * as a kernel parameter. Since this is a non-standard way
-		 * of enabling consoles, it must be explicitly enabled.
+		 * of enabling consoles, it must be explicitly forced.
 		 */
-		nf_console.flags |= CON_ENABLED;
-		register_console(&nf_console);
+		register_console_force(&nf_console);
 	}
 
 	return 0;

-- 
2.52.0



From mpdesouza at suse.com  Sat Dec 27 04:16:17 2025
From: mpdesouza at suse.com (Marcos Paulo de Souza)
Date: Sat, 27 Dec 2025 09:16:17 -0300
Subject: [PATCH 10/19] fs: pstore: platform: Migrate to
 register_console_force helper
In-Reply-To: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
References: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
Message-ID: <20251227-printk-cleanup-part3-v1-10-21a291bcf197@suse.com>

The register_console_force function was introduced to register consoles
even on the presence of default consoles, replacing the CON_ENABLE flag
that was forcing the same behavior.

No functional changes.

Signed-off-by: Marcos Paulo de Souza <mpdesouza at suse.com>
---
 fs/pstore/platform.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index f8b9c9c73997..9d42c0f2de9e 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -418,10 +418,10 @@ static void pstore_register_console(void)
 		sizeof(pstore_console.name));
 	/*
 	 * Always initialize flags here since prior unregister_console()
-	 * calls may have changed settings (specifically CON_ENABLED).
+	 * calls may have changed settings.
 	 */
-	pstore_console.flags = CON_PRINTBUFFER | CON_ENABLED | CON_ANYTIME;
-	register_console(&pstore_console);
+	pstore_console.flags = CON_PRINTBUFFER | CON_ANYTIME;
+	register_console_force(&pstore_console);
 }
 
 static void pstore_unregister_console(void)

-- 
2.52.0



From mpdesouza at suse.com  Sat Dec 27 04:16:18 2025
From: mpdesouza at suse.com (Marcos Paulo de Souza)
Date: Sat, 27 Dec 2025 09:16:18 -0300
Subject: [PATCH 11/19] powerpc: kernel: udbg: Migrate to
 register_console_force helper
In-Reply-To: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
References: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
Message-ID: <20251227-printk-cleanup-part3-v1-11-21a291bcf197@suse.com>

The register_console_force function was introduced to register consoles
even on the presence of default consoles, replacing the CON_ENABLE flag
that was forcing the same behavior.

No functional changes.

Signed-off-by: Marcos Paulo de Souza <mpdesouza at suse.com>
---
 arch/powerpc/kernel/udbg.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c
index 862b22b2b616..0f88b7697755 100644
--- a/arch/powerpc/kernel/udbg.c
+++ b/arch/powerpc/kernel/udbg.c
@@ -142,7 +142,7 @@ static void udbg_console_write(struct console *con, const char *s,
 static struct console udbg_console = {
 	.name	= "udbg",
 	.write	= udbg_console_write,
-	.flags	= CON_PRINTBUFFER | CON_ENABLED | CON_BOOT | CON_ANYTIME,
+	.flags	= CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME,
 	.index	= 0,
 };
 
@@ -163,7 +163,7 @@ void __init register_early_udbg_console(void)
 		udbg_console.flags &= ~CON_BOOT;
 	}
 	early_console = &udbg_console;
-	register_console(&udbg_console);
+	register_console_force(&udbg_console);
 }
 
 #if 0   /* if you want to use this as a regular output console */

-- 
2.52.0



From mpdesouza at suse.com  Sat Dec 27 04:16:19 2025
From: mpdesouza at suse.com (Marcos Paulo de Souza)
Date: Sat, 27 Dec 2025 09:16:19 -0300
Subject: [PATCH 12/19] sparc: kernel: btext: Migrate to
 register_console_force helper
In-Reply-To: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
References: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
Message-ID: <20251227-printk-cleanup-part3-v1-12-21a291bcf197@suse.com>

The register_console_force function was introduced to register consoles
even on the presence of default consoles, replacing the CON_ENABLE flag
that was forcing the same behavior.

No functional changes.

Signed-off-by: Marcos Paulo de Souza <mpdesouza at suse.com>
---
 arch/sparc/kernel/btext.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/sparc/kernel/btext.c b/arch/sparc/kernel/btext.c
index 2bf558a0c568..951de7733632 100644
--- a/arch/sparc/kernel/btext.c
+++ b/arch/sparc/kernel/btext.c
@@ -301,7 +301,7 @@ static void btext_console_write(struct console *con, const char *s,
 static struct console btext_console = {
 	.name	= "btext",
 	.write	= btext_console_write,
-	.flags	= CON_PRINTBUFFER | CON_ENABLED | CON_BOOT | CON_ANYTIME,
+	.flags	= CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME,
 	.index	= 0,
 };
 
@@ -320,7 +320,7 @@ int __init btext_find_display(void)
 	ret = btext_initialize(node);
 	if (!ret) {
 		btext_clearscreen();
-		register_console(&btext_console);
+		register_console_force(&btext_console);
 	}
 	return ret;
 }

-- 
2.52.0



From mpdesouza at suse.com  Sat Dec 27 04:16:20 2025
From: mpdesouza at suse.com (Marcos Paulo de Souza)
Date: Sat, 27 Dec 2025 09:16:20 -0300
Subject: [PATCH 13/19] um: drivers: mconsole_kern.c: Migrate to
 register_console_force helper
In-Reply-To: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
References: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
Message-ID: <20251227-printk-cleanup-part3-v1-13-21a291bcf197@suse.com>

The register_console_force function was introduced to register consoles
even on the presence of default consoles, replacing the CON_ENABLE flag
that was forcing the same behavior.

No functional changes.

Signed-off-by: Marcos Paulo de Souza <mpdesouza at suse.com>
---
 arch/um/drivers/mconsole_kern.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
index ff4bda95b9c7..ce4f4ceb7f27 100644
--- a/arch/um/drivers/mconsole_kern.c
+++ b/arch/um/drivers/mconsole_kern.c
@@ -582,12 +582,11 @@ static void console_write(struct console *console, const char *string,
 
 static struct console mc_console = { .name	= "mc",
 				     .write	= console_write,
-				     .flags	= CON_ENABLED,
 				     .index	= -1 };
 
 static int mc_add_console(void)
 {
-	register_console(&mc_console);
+	register_console_force(&mc_console);
 	return 0;
 }
 

-- 
2.52.0



From mpdesouza at suse.com  Sat Dec 27 04:16:21 2025
From: mpdesouza at suse.com (Marcos Paulo de Souza)
Date: Sat, 27 Dec 2025 09:16:21 -0300
Subject: [PATCH 14/19] drivers: hwtracing: stm: console.c: Migrate to
 register_console_force helper
In-Reply-To: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
References: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
Message-ID: <20251227-printk-cleanup-part3-v1-14-21a291bcf197@suse.com>

The register_console_force function was introduced to register consoles
even on the presence of default consoles, replacing the CON_ENABLE flag
that was forcing the same behavior.

No functional changes.

Signed-off-by: Marcos Paulo de Souza <mpdesouza at suse.com>
---
 drivers/hwtracing/stm/console.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/hwtracing/stm/console.c b/drivers/hwtracing/stm/console.c
index 097a00ac43a7..d3ae633e3bf1 100644
--- a/drivers/hwtracing/stm/console.c
+++ b/drivers/hwtracing/stm/console.c
@@ -42,8 +42,8 @@ static int stm_console_link(struct stm_source_data *data)
 
 	strcpy(sc->console.name, "stm_console");
 	sc->console.write = stm_console_write;
-	sc->console.flags = CON_ENABLED | CON_PRINTBUFFER;
-	register_console(&sc->console);
+	sc->console.flags = CON_PRINTBUFFER;
+	register_console_force(&sc->console);
 
 	return 0;
 }

-- 
2.52.0



From mpdesouza at suse.com  Sat Dec 27 04:16:22 2025
From: mpdesouza at suse.com (Marcos Paulo de Souza)
Date: Sat, 27 Dec 2025 09:16:22 -0300
Subject: [PATCH 15/19] drivers: tty: serial: mux.c: Migrate to
 register_console_force helper
In-Reply-To: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
References: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
Message-ID: <20251227-printk-cleanup-part3-v1-15-21a291bcf197@suse.com>

The register_console_force function was introduced to register consoles
even on the presence of default consoles, replacing the CON_ENABLE flag
that was forcing the same behavior.

No functional changes.

Signed-off-by: Marcos Paulo de Souza <mpdesouza at suse.com>
---
 drivers/tty/serial/mux.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c
index b417faead20f..5a2d706b9cbc 100644
--- a/drivers/tty/serial/mux.c
+++ b/drivers/tty/serial/mux.c
@@ -390,7 +390,7 @@ static struct console mux_console = {
 	.write =	mux_console_write,
 	.device =	uart_console_device,
 	.setup =	mux_console_setup,
-	.flags =	CON_ENABLED | CON_PRINTBUFFER,
+	.flags =	CON_PRINTBUFFER,
 	.index =	0,
 	.data =		&mux_driver,
 };
@@ -547,7 +547,7 @@ static int __init mux_init(void)
 		mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY);
 
 #ifdef CONFIG_SERIAL_MUX_CONSOLE
-	        register_console(&mux_console);
+		register_console_force(&mux_console);
 #endif
 	}
 

-- 
2.52.0



From mpdesouza at suse.com  Sat Dec 27 04:16:23 2025
From: mpdesouza at suse.com (Marcos Paulo de Souza)
Date: Sat, 27 Dec 2025 09:16:23 -0300
Subject: [PATCH 16/19] drivers: tty: serial: ma35d1_serial: Migrate to
 register_console_force helper
In-Reply-To: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
References: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
Message-ID: <20251227-printk-cleanup-part3-v1-16-21a291bcf197@suse.com>

The register_console_force function was introduced to register consoles
even on the presence of default consoles, replacing the CON_ENABLE flag
that was forcing the same behavior.

No functional changes.

Signed-off-by: Marcos Paulo de Souza <mpdesouza at suse.com>
---
 drivers/tty/serial/ma35d1_serial.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/ma35d1_serial.c b/drivers/tty/serial/ma35d1_serial.c
index 285b0fe41a86..d1e03dee5579 100644
--- a/drivers/tty/serial/ma35d1_serial.c
+++ b/drivers/tty/serial/ma35d1_serial.c
@@ -633,7 +633,7 @@ static struct console ma35d1serial_console = {
 	.write   = ma35d1serial_console_write,
 	.device  = uart_console_device,
 	.setup   = ma35d1serial_console_setup,
-	.flags   = CON_PRINTBUFFER | CON_ENABLED,
+	.flags   = CON_PRINTBUFFER,
 	.index   = -1,
 	.data    = &ma35d1serial_reg,
 };
@@ -657,7 +657,7 @@ static void ma35d1serial_console_init_port(void)
 static int __init ma35d1serial_console_init(void)
 {
 	ma35d1serial_console_init_port();
-	register_console(&ma35d1serial_console);
+	register_console_force(&ma35d1serial_console);
 	return 0;
 }
 console_initcall(ma35d1serial_console_init);

-- 
2.52.0



From mpdesouza at suse.com  Sat Dec 27 04:16:24 2025
From: mpdesouza at suse.com (Marcos Paulo de Souza)
Date: Sat, 27 Dec 2025 09:16:24 -0300
Subject: [PATCH 17/19] drivers: tty: ehv_bytechan: Migrate to
 register_console_force helper
In-Reply-To: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
References: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
Message-ID: <20251227-printk-cleanup-part3-v1-17-21a291bcf197@suse.com>

The register_console_force function was introduced to register consoles
even on the presence of default consoles, replacing the CON_ENABLE flag
that was forcing the same behavior.

No functional changes.

Signed-off-by: Marcos Paulo de Souza <mpdesouza at suse.com>
---
 drivers/tty/ehv_bytechan.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c
index 69508d7a4135..a2aab48d11ae 100644
--- a/drivers/tty/ehv_bytechan.c
+++ b/drivers/tty/ehv_bytechan.c
@@ -299,7 +299,7 @@ static struct console ehv_bc_console = {
 	.name		= "ttyEHV",
 	.write		= ehv_bc_console_write,
 	.device		= ehv_bc_console_device,
-	.flags		= CON_PRINTBUFFER | CON_ENABLED,
+	.flags		= CON_PRINTBUFFER,
 };
 
 /*
@@ -331,7 +331,7 @@ static int __init ehv_bc_console_init(void)
 	   byte channels here, either, since we only care about one. */
 
 	add_preferred_console(ehv_bc_console.name, ehv_bc_console.index, NULL);
-	register_console(&ehv_bc_console);
+	register_console_force(&ehv_bc_console);
 
 	pr_info("ehv-bc: registered console driver for byte channel %u\n",
 		stdout_bc);

-- 
2.52.0



From mpdesouza at suse.com  Sat Dec 27 04:16:25 2025
From: mpdesouza at suse.com (Marcos Paulo de Souza)
Date: Sat, 27 Dec 2025 09:16:25 -0300
Subject: [PATCH 18/19] drivers: braille: console: Drop CON_ENABLED console
 flag
In-Reply-To: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
References: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
Message-ID: <20251227-printk-cleanup-part3-v1-18-21a291bcf197@suse.com>

The braille console doesn't take the same path on register_console
that other console drivers. At this point, it only registers the console
and do not receive any printk message, so we can drop the CON_ENABLED.

Signed-off-by: Marcos Paulo de Souza <mpdesouza at suse.com>
---
 drivers/accessibility/braille/braille_console.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/accessibility/braille/braille_console.c b/drivers/accessibility/braille/braille_console.c
index 06b43b678d6e..0b7ec68b305c 100644
--- a/drivers/accessibility/braille/braille_console.c
+++ b/drivers/accessibility/braille/braille_console.c
@@ -360,7 +360,6 @@ int braille_register_console(struct console *console, int index,
 		if (ret != 0)
 			return ret;
 	}
-	console->flags |= CON_ENABLED;
 	console->index = index;
 	braille_co = console;
 	register_keyboard_notifier(&keyboard_notifier_block);

-- 
2.52.0



From mpdesouza at suse.com  Sat Dec 27 04:16:26 2025
From: mpdesouza at suse.com (Marcos Paulo de Souza)
Date: Sat, 27 Dec 2025 09:16:26 -0300
Subject: [PATCH 19/19] printk: Remove CON_ENABLED flag
In-Reply-To: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
References: <20251227-printk-cleanup-part3-v1-0-21a291bcf197@suse.com>
Message-ID: <20251227-printk-cleanup-part3-v1-19-21a291bcf197@suse.com>

All remaining usages of CON_ENABLED were removed from console drivers
that were being registered without being specified on boot using console=
argument.

The usefulness of the flag was questionable since at first it meant that
the console was ready to print records. Later on, console drivers started
to set the flag when registering the console to make sure that the
console would be registered even without being specified by a kernel
argument.

With the inclusion a global state for system wide suspend/resume
in place, with console_{suspend,resume} handling CON_SUSPEND, and with
console_is_usable helper being more used, the CON_ENABLED flag can be
safely removed.

Signed-off-by: Marcos Paulo de Souza <mpdesouza at suse.com>
---
 fs/proc/consoles.c      |  1 -
 include/linux/console.h | 27 ++++++++++-----------------
 kernel/printk/printk.c  | 15 ++-------------
 3 files changed, 12 insertions(+), 31 deletions(-)

diff --git a/fs/proc/consoles.c b/fs/proc/consoles.c
index b7cab1ad990d..b6916ed7957b 100644
--- a/fs/proc/consoles.c
+++ b/fs/proc/consoles.c
@@ -18,7 +18,6 @@ static int show_console_dev(struct seq_file *m, void *v)
 		short flag;
 		char name;
 	} con_flags[] = {
-		{ CON_ENABLED,		'E' },
 		{ CON_CONSDEV,		'C' },
 		{ CON_BOOT,		'B' },
 		{ CON_NBCON,		'N' },
diff --git a/include/linux/console.h b/include/linux/console.h
index 7d374a29a625..0ab02f7ba307 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -164,9 +164,6 @@ static inline void con_debug_leave(void) { }
  *			consoles or read by userspace via syslog() syscall.
  * @CON_CONSDEV:	Indicates that the console driver is backing
  *			/dev/console.
- * @CON_ENABLED:	Indicates if a console is allowed to print records. If
- *			false, the console also will not advance to later
- *			records.
  * @CON_BOOT:		Marks the console driver as early console driver which
  *			is used during boot before the real driver becomes
  *			available. It will be automatically unregistered
@@ -192,14 +189,13 @@ static inline void con_debug_leave(void) { }
 enum cons_flags {
 	CON_PRINTBUFFER		= BIT(0),
 	CON_CONSDEV		= BIT(1),
-	CON_ENABLED		= BIT(2),
-	CON_BOOT		= BIT(3),
-	CON_ANYTIME		= BIT(4),
-	CON_BRL			= BIT(5),
-	CON_EXTENDED		= BIT(6),
-	CON_SUSPENDED		= BIT(7),
-	CON_NBCON		= BIT(8),
-	CON_NBCON_ATOMIC_UNSAFE	= BIT(9),
+	CON_BOOT		= BIT(2),
+	CON_ANYTIME		= BIT(3),
+	CON_BRL			= BIT(4),
+	CON_EXTENDED		= BIT(5),
+	CON_SUSPENDED		= BIT(6),
+	CON_NBCON		= BIT(7),
+	CON_NBCON_ATOMIC_UNSAFE	= BIT(8),
 };
 
 /**
@@ -522,9 +518,9 @@ extern bool consoles_suspended;
  *
  * Requires console_srcu_read_lock to be held, which implies that @con might
  * be a registered console. The purpose of holding console_srcu_read_lock is
- * to guarantee that the console state is valid (CON_SUSPENDED/CON_ENABLED)
- * and that no exit/cleanup routines will run if the console is currently
- * undergoing unregistration.
+ * to guarantee that the console state is valid (CON_SUSPENDED) and that no
+ * exit/cleanup routines will run if the console is currently undergoing
+ * unregistration.
  *
  * If the caller is holding the console_list_lock or it is _certain_ that
  * @con is not and will not become registered, the caller may read
@@ -706,9 +702,6 @@ static inline bool __console_is_usable(struct console *con, short flags,
 	if (all_suspended)
 		return false;
 
-	if (!(flags & CON_ENABLED))
-		return false;
-
 	if ((flags & CON_SUSPENDED))
 		return false;
 
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index c5c05e4d0a67..9cb0911997e5 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3890,21 +3890,17 @@ static int try_enable_preferred_console(struct console *newcon,
 			if (err)
 				return err;
 		}
-		newcon->flags |= CON_ENABLED;
 		if (i == preferred_console)
 			newcon->flags |= CON_CONSDEV;
 		return 0;
 	}
 
-	if (force)
-		newcon->flags |= CON_ENABLED;
-
 	/*
 	 * Some consoles, such as pstore and netconsole, can be enabled even
 	 * without matching. Accept the pre-enabled consoles only when match()
 	 * and setup() had a chance to be called.
 	 */
-	if (newcon->flags & CON_ENABLED && c->user_specified == user_specified)
+	if (force && c->user_specified == user_specified)
 		return 0;
 
 	return -ENOENT;
@@ -3919,8 +3915,6 @@ static void try_enable_default_console(struct console *newcon)
 	if (console_call_setup(newcon, NULL) != 0)
 		return;
 
-	newcon->flags |= CON_ENABLED;
-
 	if (newcon->device)
 		newcon->flags |= CON_CONSDEV;
 }
@@ -3977,10 +3971,8 @@ static u64 get_init_console_seq(struct console *newcon, bool bootcon_registered)
 				for_each_console(con) {
 					u64 seq;
 
-					if (!(con->flags & CON_BOOT) ||
-					    !(con->flags & CON_ENABLED)) {
+					if (!(con->flags & CON_BOOT))
 						continue;
-					}
 
 					if (con->flags & CON_NBCON)
 						seq = nbcon_seq_read(con);
@@ -4233,9 +4225,6 @@ static int unregister_console_locked(struct console *console)
 				     consoles_suspended, NBCON_USE_ATOMIC))
 		__pr_flush(console, 1000, true);
 
-	/* Disable it unconditionally */
-	console_srcu_write_flags(console, console->flags & ~CON_ENABLED);
-
 	if (res < 0)
 		return res;
 

-- 
2.52.0



From linux at weissschuh.net  Sat Dec 27 04:25:49 2025
From: linux at weissschuh.net (Thomas =?utf-8?Q?Wei=C3=9Fschuh?=)
Date: Sat, 27 Dec 2025 13:25:49 +0100
Subject: Linux 6.19-rc1 mediatek mt7921e broke badly
In-Reply-To: <d7f3b00d-beec-41f0-b157-7cfb871f9a46@linuxfoundation.org>
References: <d7f3b00d-beec-41f0-b157-7cfb871f9a46@linuxfoundation.org>
Message-ID: <756e3f65-b2f2-4da3-985a-17754a7a872d@t-8ch.de>

Hi Shuah,

On 2025-12-27 02:07:24-0700, Shuah Khan wrote:
> mt7921e doesn't load on my primary laptopn on Linux 6.19-rc1 and problem
> still there on 6.19-rc2.

This should be a duplicate of
https://lore.kernel.org/all/CABXGCsMeAZyNJ-Axt_CUCXgyieWPV3rrcLpWsveMPT8R0YPGnQ at mail.gmail.com/

(...)


Thomas


From krzk at kernel.org  Sat Dec 27 04:32:57 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sat, 27 Dec 2025 13:32:57 +0100
Subject: [PATCH v2 3/4] dt-bindings: media: mediatek-jpeg-encoder: add
 MT8189 compatible string
In-Reply-To: <20251224031721.9942-4-jianhua.lin@mediatek.com>
References: <20251224031721.9942-1-jianhua.lin@mediatek.com>
 <20251224031721.9942-4-jianhua.lin@mediatek.com>
Message-ID: <20251227-glittering-opalescent-caterpillar-3c24d8@quoll>

On Wed, Dec 24, 2025 at 11:17:20AM +0800, Jianhua Lin wrote:
> Compared to the previous generation IC, the MT8189 uses 34-bit iova
> address-space (16GB)  and requires a single clock configuration.
> Therefore, add "mediatek,mt8189-jpgenc" compatible to the binding document.
> Additionally, it corrects the inheritance for MT8188, aligning it

Two different issues. Don't mix them up. See submitting patches.

> with MT8189 due to their shared architecture and 34-bit iova address
> space (16GB) requirements.
> Previously, MT8188 was incorrectly defined alongside SoCs with 32-bit
> iova address-space (4GB), such as "mediatek,mtk-jpgenc". This mismatch
> results in an ABI break, as MT8188 cannot function correctly under
> the 32-bit iova address-space (4GB) configuration.
> 
> Key changes include:

How is this related to above?
> - Introducing "mediatek,mt8189-jpgenc" as a new compatible string to
>   represent the correct architecture.

Why are you repeating the same?

> - Updating MT8188 to inherit from MT8189, ensuring proper support for
>   34-bit iova address-space (16GB).
> - Add property "mediatek,larb" for MT8189 requirements.
> - Improved formatting for better readability and consistency.
> 
> These changes ensure that both MT8188 and MT8189 are correctly supported
> with the necessary 34-bit iova address-space (16GB), while maintaining
> compatibility with their shared architecture.

This is not a contest who writes the longest commit msg by repeating
obvious things.

> 
> Extensive internal review and testing have been conducted to validate
> these changes and ensure compliance with DT binding standards.

Really, no.

Best regards,
Krzysztof



From krzk at kernel.org  Sat Dec 27 04:33:45 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sat, 27 Dec 2025 13:33:45 +0100
Subject: [PATCH v2 2/4] dt-bindings: media: mediatek-jpeg-decoder: add
 MT8189 compatible string
In-Reply-To: <20251224031721.9942-3-jianhua.lin@mediatek.com>
References: <20251224031721.9942-1-jianhua.lin@mediatek.com>
 <20251224031721.9942-3-jianhua.lin@mediatek.com>
Message-ID: <20251227-romantic-crystal-vole-4bb126@quoll>

On Wed, Dec 24, 2025 at 11:17:19AM +0800, Jianhua Lin wrote:
> Compared to the previous generation IC, the MT8189 uses 34-bit iova
> address-space (16GB) and requires a single clock configuration.
> Therefore, add "mediatek,mt8189-jpgdec" compatible to the binding document.
> Additionally, it corrects the inheritance for MT8188, aligning it
> with MT8189 due to their shared architecture and 34-bit iova address
> space (16GB) and singlesingle clock requirement.
> Previously, MT8188 was incorrectly defined alongside SoCs with 32-bit
> iova address-space (4GB), such as "mediatek,mt2701-jpgdec". This mismatch
> results in an ABI break, as MT8188 cannot function correctly under
> the 32-bit iova address-space (4GB) configuration.
> 
> Key changes include:
> - Introducing "mediatek,mt8189-jpgdec" as a new compatible string to
>   represent the correct architecture.
> - Updating MT8188 to inherit from MT8189, ensuring proper support for
>   34-bit iova address-space (16GB) and simplifying clock configuration.
> - Add property "mediatek,larb" for MT8189 requirements.
> - Improved formatting for better readability and consistency.
> 
> These changes ensure that both MT8188 and MT8189 are correctly supported
> with the necessary 34-bit iova address-space (16GB), while maintaining
> compatibility with their shared architecture.
> 
> Extensive internal review and testing have been conducted to validate
> these changes and ensure compliance with DT binding standards.

That's not even true. If you did extensive internal review, then people
would have tell you that you never mix fixes with new features in one
commit. Never, that's like basic rule.

Best regards,
Krzysztof



From krzk at kernel.org  Sat Dec 27 04:34:30 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sat, 27 Dec 2025 13:34:30 +0100
Subject: [PATCH v2 1/4] arm64: dts: mt8188: update JPEG encoder/decoder
 compatible
In-Reply-To: <20251224031721.9942-2-jianhua.lin@mediatek.com>
References: <20251224031721.9942-1-jianhua.lin@mediatek.com>
 <20251224031721.9942-2-jianhua.lin@mediatek.com>
Message-ID: <20251227-overjoyed-illustrious-snail-9323e9@quoll>

On Wed, Dec 24, 2025 at 11:17:18AM +0800, Jianhua Lin wrote:
> The JPEG encoder and decoder of MT8188 share the same architecture
> and features as those of MT8189, both use a 34-bit iova
> address-space (16GB) and a single clock configuration.
> 
> Previously, MT8188 was incorrectly defined alongside SoCs with 32-bit
> iova address-space (4GB), such as "mediatek,mt2701-jpgdec" and
> "mediatek,mtk-jpgenc". This mismatch results in an ABI break,

How this mismatch can result in ABI break?

> as MT8188 cannot function correctly under the 32-bit iova
> address-space (4GB) configuration.

Do you understand what is an ABI break? This commit is the ABI break.

Best regards,
Krzysztof



From krzk at kernel.org  Sat Dec 27 04:50:47 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sat, 27 Dec 2025 13:50:47 +0100
Subject: [PATCH 5/8] dt-bindings: mmc: axiado: Add axiado eMMC variant
In-Reply-To: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-5-5457d0ebcdb4@axiado.com>
References: <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-0-5457d0ebcdb4@axiado.com>
 <20251222-axiado-ax3000-add-emmc-host-driver-support-v1-5-5457d0ebcdb4@axiado.com>
Message-ID: <20251227-industrious-mammoth-of-culture-ff9dbe@quoll>

On Mon, Dec 22, 2025 at 04:45:04PM +0800, Tzu-Hao Wei wrote:
> From: SriNavmani A <srinavmani at axiado.com>
> 
> Add device tree binding variant for the Axiado AX3000 Arasan eMMC
> controller. This variant identifies the specific eMMC controller
> implementation used on the AX3000 SoC and enables the appropriate
> driver configuration.
> 
> Signed-off-by: Tzu-Hao Wei <twei at axiado.com>

Incorrect DCO chain.


Best regards,
Krzysztof



From krzk at kernel.org  Sat Dec 27 05:02:34 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sat, 27 Dec 2025 14:02:34 +0100
Subject: [PATCH v1 1/4] dt-bindings: arm: fsl: Add Apalis iMX8QP
In-Reply-To: <20251223162833.138286-2-francesco@dolcini.it>
References: <20251223162833.138286-1-francesco@dolcini.it>
 <20251223162833.138286-2-francesco@dolcini.it>
Message-ID: <20251227-polite-malachite-chameleon-f446cc@quoll>

On Tue, Dec 23, 2025 at 05:28:27PM +0100, Francesco Dolcini wrote:
> From: Francesco Dolcini <francesco.dolcini at toradex.com>
> 
> Add binding documentation for the Apalis iMX8QP SoM mated with Apalis
> Ixora and Apalis Evaluation board.
> 
> Apalis iMX8QP is a variant of the Apalis iMX8QM, using an NXP i.MX8QP
> SoC instead of the i.MX8QM. The two SoCs are pin to pin compatible, with
> the i.MX8QP being a lower end variant, with a slower GPU and one Cortex
> A72 core instead of two.
> 
> The two Apalis SoMs variants share the same schematics and PCB, and the
> iMX8QP variant exists only on revision V1.1 of board.
> 
> Link: https://www.nxp.com/products/i.MX8
> Link: https://www.toradex.com/computer-on-modules/apalis-arm-family/nxp-imx-8
> Signed-off-by: Francesco Dolcini <francesco.dolcini at toradex.com>
> ---

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof



From krzk at kernel.org  Sat Dec 27 05:03:36 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sat, 27 Dec 2025 14:03:36 +0100
Subject: [PATCH 1/2] dt-bindings: phy: Add PHY_TYPE_XAUI definition
In-Reply-To: <20251224054905.763399-2-s-vadapalli@ti.com>
References: <20251224054905.763399-1-s-vadapalli@ti.com>
 <20251224054905.763399-2-s-vadapalli@ti.com>
Message-ID: <20251227-airborne-energetic-kingfisher-adc4fb@quoll>

On Wed, Dec 24, 2025 at 11:18:58AM +0530, Siddharth Vadapalli wrote:
> From: Swapnil Jakhade <sjakhade at cadence.com>
> 
> Add definition for XAUI phy type.

What is XAUI?

Your commit msg duplicates subject and is obvious - repeats what is
in the diff. Pretty pointless.

Best regards,
Krzysztof



From krzk at kernel.org  Sat Dec 27 05:14:16 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sat, 27 Dec 2025 14:14:16 +0100
Subject: [PATCH] arm64/kdump: pass dm-crypt keys to kdump kernel
In-Reply-To: <20251226141116.1379601-1-coxu@redhat.com>
References: <20251226141116.1379601-1-coxu@redhat.com>
Message-ID: <20251227-funky-swallow-from-pluto-910b9d@quoll>

On Fri, Dec 26, 2025 at 10:11:15PM +0800, Coiby Xu wrote:
> Based on the CONFIG_CRASH_DM_CRYPT feature, this patch adds

Don't use "this patch". See submitting patches.

> LUKS-encrypted device dump target support to ARM64 by addressing two
> challenges [1],


...

> +static void __init early_init_dt_check_for_dmcryptkeys(unsigned long node)
> +{
> +	const __be32 *prop;
> +
> +	if (!IS_ENABLED(CONFIG_CRASH_DM_CRYPT))
> +		return;
> +
> +	pr_debug("Looking for dmcryptkeys property... ");
> +
> +	prop = of_get_flat_dt_prop(node, "linux,dmcryptkeys", NULL);

Where did you document the ABI?


Best regards,
Krzysztof



From josua at solid-run.com  Sat Dec 27 05:24:05 2025
From: josua at solid-run.com (Josua Mayer)
Date: Sat, 27 Dec 2025 14:24:05 +0100
Subject: [PATCH] ARM: imx_v4_v5_defconfig: update for v6.19-rc1
Message-ID: <20251227-armv45defconfig-fix-v1-1-d7b64abda9fe@solid-run.com>

The i.MX5/6 defconfig has gone out of sync with some dead options, some
removed and some missing.

1. Add missing options no longer enabled by default:
- CONFIG_I2C=y
- CONFIG_LCD_CLASS_DEVICE=y

2. Remove options enabled by default:
- CONFIG_CS89x0=y
- CONFIG_MEDIA_CAMERA_SUPPORT=y

3. Remove options that have no effect:
- # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
- # CONFIG_INET_XFRM_MODE_TUNNEL is not set
- # CONFIG_INET_XFRM_MODE_BEET is not set

4. Remove options that have been removed completely from the kernel:
- CONFIG_USB_EHCI_MXC=y
  Removed by commit e7018751d2e6 ("usb: host: ehci-mxc: Remove the
driver").
- CONFIG_SMC911X=y
  Removed by commit a2fd08448f2b ("net: remove smc911x driver").
- -CONFIG_SND_SOC_MX27VIS_AIC32X4=y
  Removed by commit 3fbb01fb583f ("ASoC: mx27vis-aic32x4: Remove unused
driver").
- CONFIG_SND_SOC_PHYCORE_AC97=y
  Removed by commit 440534a0ecfd ("ASoC: phycore-ac97: Remove unused
driver").
- CONFIG_SND_SOC_IMX_MC13783=y
  Removed by commit 83e7e2278680 ("ASoC: imx-mc13783: Remove unused
driver").

Signed-off-by: Josua Mayer <josua at solid-run.com>
---
 arch/arm/configs/imx_v4_v5_defconfig | 12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/arch/arm/configs/imx_v4_v5_defconfig b/arch/arm/configs/imx_v4_v5_defconfig
index 875c8cdbada7d..9139d1784c708 100644
--- a/arch/arm/configs/imx_v4_v5_defconfig
+++ b/arch/arm/configs/imx_v4_v5_defconfig
@@ -29,9 +29,6 @@ CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
 CONFIG_NETFILTER=y
@@ -58,11 +55,9 @@ CONFIG_BLK_DEV_SD=y
 CONFIG_ATA=y
 CONFIG_PATA_IMX=y
 CONFIG_NETDEVICES=y
-CONFIG_CS89x0=y
 CONFIG_CS89x0_PLATFORM=y
 CONFIG_DM9000=y
 CONFIG_SMC91X=y
-CONFIG_SMC911X=y
 CONFIG_SMSC911X=y
 CONFIG_SMSC_PHY=y
 CONFIG_INPUT_EVDEV=y
@@ -78,6 +73,7 @@ CONFIG_SERIAL_8250=m
 CONFIG_SERIAL_IMX=y
 CONFIG_SERIAL_IMX_CONSOLE=y
 # CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_IMX=y
 CONFIG_SPI=y
@@ -100,12 +96,12 @@ CONFIG_REGULATOR_GPIO=y
 CONFIG_REGULATOR_MC13783=y
 CONFIG_REGULATOR_MC13892=y
 CONFIG_MEDIA_SUPPORT=y
-CONFIG_MEDIA_CAMERA_SUPPORT=y
 CONFIG_V4L_PLATFORM_DRIVERS=y
 CONFIG_V4L_MEM2MEM_DRIVERS=y
 CONFIG_VIDEO_CODA=y
 CONFIG_FB=y
 CONFIG_FB_IMX=y
+CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_LCD_L4F00242T03=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
@@ -115,16 +111,12 @@ CONFIG_SND=y
 # CONFIG_SND_SPI is not set
 CONFIG_SND_SOC=y
 CONFIG_SND_IMX_SOC=y
-CONFIG_SND_SOC_MX27VIS_AIC32X4=y
-CONFIG_SND_SOC_PHYCORE_AC97=y
 CONFIG_SND_SOC_EUKREA_TLV320=y
-CONFIG_SND_SOC_IMX_MC13783=y
 CONFIG_SND_SOC_FSL_ASOC_CARD=y
 CONFIG_SND_SOC_SGTL5000=y
 CONFIG_USB_HID=m
 CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_MXC=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_CHIPIDEA=y
 CONFIG_USB_CHIPIDEA_UDC=y

---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20251227-armv45defconfig-fix-9f8186a4c5c7

Best regards,
-- 
Josua Mayer <josua at solid-run.com>




From sjg at chromium.org  Sat Dec 27 06:21:44 2025
From: sjg at chromium.org (Simon Glass)
Date: Sat, 27 Dec 2025 07:21:44 -0700
Subject: [PATCH v8 0/6] scripts/make_fit: Support ramdisks and faster operations
Message-ID: <20251227142200.2241198-1-sjg@chromium.org>

This series updates 'make image.fit' to support adding a ramdisk to the
FIT, provided as a parameter.

It also includes a few performance improvement, so that building a FIT
from ~450MB of kernel/module/devicetree files only takes a few seconds
on a modern machine.

For this version I have dropped inclusion of built modules, as there is
still more discussion to happen in that area.

Changes in v8:
- Drop erroneous line 'kbuild: Allow adding modules into the FIT ...'

Changes in v7:
- Add a note about the " -> ' change
- Add a new patch with the MAKE_FIT_FLAGS change
- Mention xz as well, in the commit message
- Drop patch 'scripts/make_fit: Provide a way to add built modules'
- Drop patch 'kbuild: Split out module targets into a variable'
- Drop patch 'kbuild: Allow adding modules into the FIT ramdisk'

Changes in v6:
- Drop the load address for ramdisk, as it is not needed
- Bring back the ramdisk 'compression' property, set to 'none'

Changes in v5:
- Fix 'use' typo

Changes in v4:
- Update the commit message

Changes in v3:
- Move the ramdisk chunk into the correct patch
- Add a comment at the top of the file about the -r option
- Count the ramdisk in the total files
- Update the commit message

Changes in v2:
- Don't compress the ramdisk as it is already compressed

Simon Glass (6):
  scripts/make_fit: Speed up operation
  scripts/make_fit: Support an initial ramdisk
  scripts/make_fit: Move dtb processing into a function
  kbuild: Support a MAKE_FIT_FLAGS environment variable
  scripts/make_fit: Support a few more parallel compressors
  scripts/make_fit: Compress dtbs in parallel

 scripts/Makefile.lib |   2 +-
 scripts/make_fit.py  | 179 ++++++++++++++++++++++++++++++++++---------
 2 files changed, 145 insertions(+), 36 deletions(-)

-- 
2.43.0

base-commit: c53f467229a78287efa5b9f65bd22de64416660f
branch: fita8


From sjg at chromium.org  Sat Dec 27 06:21:45 2025
From: sjg at chromium.org (Simon Glass)
Date: Sat, 27 Dec 2025 07:21:45 -0700
Subject: [PATCH v8 1/6] scripts/make_fit: Speed up operation
In-Reply-To: <20251227142200.2241198-1-sjg@chromium.org>
References: <20251227142200.2241198-1-sjg@chromium.org>
Message-ID: <20251227142200.2241198-2-sjg@chromium.org>

The kernel is likely at least 16MB so we may as well use that as a step
size when reallocating space for the FIT in memory. Pack the FIT at the
end, so there is no wasted space.

This reduces the time to pack by an order of magnitude, or so.

Signed-off-by: Simon Glass <sjg at chromium.org>
Reviewed-by: Nicolas Schier <nsc at kernel.org>
Reviewed-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
Tested-by: Chen-Yu Tsai <wenst at chromium.org>
---

(no changes since v3)

Changes in v3:
- Move the ramdisk chunk into the correct patch

 scripts/make_fit.py | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/scripts/make_fit.py b/scripts/make_fit.py
index 1683e5ec6e67..0f5e7c4b8aed 100755
--- a/scripts/make_fit.py
+++ b/scripts/make_fit.py
@@ -98,7 +98,7 @@ def setup_fit(fsw, name):
         fsw (libfdt.FdtSw): Object to use for writing
         name (str): Name of kernel image
     """
-    fsw.INC_SIZE = 65536
+    fsw.INC_SIZE = 16 << 20
     fsw.finish_reservemap()
     fsw.begin_node('')
     fsw.property_string('description', f'{name} with devicetree set')
@@ -299,7 +299,9 @@ def build_fit(args):
     finish_fit(fsw, entries)
 
     # Include the kernel itself in the returned file count
-    return fsw.as_fdt().as_bytearray(), seq + 1, size
+    fdt = fsw.as_fdt()
+    fdt.pack()
+    return fdt.as_bytearray(), seq + 1, size
 
 
 def run_make_fit():
-- 
2.43.0



From sjg at chromium.org  Sat Dec 27 06:21:46 2025
From: sjg at chromium.org (Simon Glass)
Date: Sat, 27 Dec 2025 07:21:46 -0700
Subject: [PATCH v8 2/6] scripts/make_fit: Support an initial ramdisk
In-Reply-To: <20251227142200.2241198-1-sjg@chromium.org>
References: <20251227142200.2241198-1-sjg@chromium.org>
Message-ID: <20251227142200.2241198-3-sjg@chromium.org>

FIT (Flat Image Tree) allows a ramdisk to be included in each
configuration. Add support for this to the script.

This feature is not available via 'make image.fit' since the ramdisk
likely needs to be built separately anyway, e.g. using modules from
the kernel build. Future work may provide support for doing that.

Note that the uncompressed size is not correct when a ramdisk is used,
since it is too expensive to decompress the ramdisk.

Signed-off-by: Simon Glass <sjg at chromium.org>
Reviewed-by: Nicolas Schier <nsc at kernel.org>
Reviewed-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---

(no changes since v6)

Changes in v6:
- Drop the load address for ramdisk, as it is not needed
- Bring back the ramdisk 'compression' property, set to 'none'

Changes in v5:
- Fix 'use' typo

Changes in v4:
- Update the commit message

Changes in v3:
- Add a comment at the top of the file about the -r option
- Count the ramdisk in the total files
- Update the commit message

Changes in v2:
- Don't compress the ramdisk as it is already compressed

 scripts/make_fit.py | 52 ++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 44 insertions(+), 8 deletions(-)

diff --git a/scripts/make_fit.py b/scripts/make_fit.py
index 0f5e7c4b8aed..66cd73711506 100755
--- a/scripts/make_fit.py
+++ b/scripts/make_fit.py
@@ -10,10 +10,14 @@
 Usage:
     make_fit.py -A arm64 -n 'Linux-6.6' -O linux
         -o arch/arm64/boot/image.fit -k /tmp/kern/arch/arm64/boot/image.itk
-        @arch/arm64/boot/dts/dtbs-list -E -c gzip
+        -r /boot/initrd.img-6.14.0-27-generic @arch/arm64/boot/dts/dtbs-list
+        -E -c gzip
 
-Creates a FIT containing the supplied kernel and a set of devicetree files,
-either specified individually or listed in a file (with an '@' prefix).
+Creates a FIT containing the supplied kernel, an optional ramdisk, and a set of
+devicetree files, either specified individually or listed in a file (with an
+'@' prefix).
+
+Use -r to specify an existing ramdisk/initrd file.
 
 Use -E to generate an external FIT (where the data is placed after the
 FIT data structure). This allows parsing of the data without loading
@@ -29,8 +33,6 @@ looks at the .cmd files produced by the kernel build.
 
 The resulting FIT can be booted by bootloaders which support FIT, such
 as U-Boot, Linuxboot, Tianocore, etc.
-
-Note that this tool does not yet support adding a ramdisk / initrd.
 """
 
 import argparse
@@ -81,6 +83,8 @@ def parse_args():
           help='Specifies the operating system')
     parser.add_argument('-k', '--kernel', type=str, required=True,
           help='Specifies the (uncompressed) kernel input file (.itk)')
+    parser.add_argument('-r', '--ramdisk', type=str,
+          help='Specifies the ramdisk/initrd input file')
     parser.add_argument('-v', '--verbose', action='store_true',
                         help='Enable verbose output')
     parser.add_argument('dtbs', type=str, nargs='*',
@@ -133,7 +137,28 @@ def write_kernel(fsw, data, args):
         fsw.property_u32('entry', 0)
 
 
-def finish_fit(fsw, entries):
+def write_ramdisk(fsw, data, args):
+    """Write out the ramdisk image
+
+    Writes a ramdisk node along with the required properties
+
+    Args:
+        fsw (libfdt.FdtSw): Object to use for writing
+        data (bytes): Data to write (possibly compressed)
+        args (Namespace): Contains necessary strings:
+            arch: FIT architecture, e.g. 'arm64'
+            fit_os: Operating Systems, e.g. 'linux'
+    """
+    with fsw.add_node('ramdisk'):
+        fsw.property_string('description', 'Ramdisk')
+        fsw.property_string('type', 'ramdisk')
+        fsw.property_string('arch', args.arch)
+        fsw.property_string('compression', 'none')
+        fsw.property_string('os', args.os)
+        fsw.property('data', data)
+
+
+def finish_fit(fsw, entries, has_ramdisk=False):
     """Finish the FIT ready for use
 
     Writes the /configurations node and subnodes
@@ -143,6 +168,7 @@ def finish_fit(fsw, entries):
         entries (list of tuple): List of configurations:
             str: Description of model
             str: Compatible stringlist
+        has_ramdisk (bool): True if a ramdisk is included in the FIT
     """
     fsw.end_node()
     seq = 0
@@ -154,6 +180,8 @@ def finish_fit(fsw, entries):
                 fsw.property_string('description', model)
                 fsw.property('fdt', bytes(''.join(f'fdt-{x}\x00' for x in files), "ascii"))
                 fsw.property_string('kernel', 'kernel')
+                if has_ramdisk:
+                    fsw.property_string('ramdisk', 'ramdisk')
     fsw.end_node()
 
 
@@ -274,6 +302,14 @@ def build_fit(args):
     size += os.path.getsize(args.kernel)
     write_kernel(fsw, comp_data, args)
 
+    # Handle the ramdisk if provided. Compression is not supported as it is
+    # already compressed.
+    if args.ramdisk:
+        with open(args.ramdisk, 'rb') as inf:
+            data = inf.read()
+        size += len(data)
+        write_ramdisk(fsw, data, args)
+
     for fname in args.dtbs:
         # Ignore non-DTB (*.dtb) files
         if os.path.splitext(fname)[1] != '.dtb':
@@ -296,12 +332,12 @@ def build_fit(args):
 
         entries.append([model, compat, files_seq])
 
-    finish_fit(fsw, entries)
+    finish_fit(fsw, entries, bool(args.ramdisk))
 
     # Include the kernel itself in the returned file count
     fdt = fsw.as_fdt()
     fdt.pack()
-    return fdt.as_bytearray(), seq + 1, size
+    return fdt.as_bytearray(), seq + 1 + bool(args.ramdisk), size
 
 
 def run_make_fit():
-- 
2.43.0



From sjg at chromium.org  Sat Dec 27 06:21:47 2025
From: sjg at chromium.org (Simon Glass)
Date: Sat, 27 Dec 2025 07:21:47 -0700
Subject: [PATCH v8 3/6] scripts/make_fit: Move dtb processing into a function
In-Reply-To: <20251227142200.2241198-1-sjg@chromium.org>
References: <20251227142200.2241198-1-sjg@chromium.org>
Message-ID: <20251227142200.2241198-4-sjg@chromium.org>

Since build_fit() is getting quite long, move the dtb processing into a
separate function.

Change the double quotes in the write() call to single, to match the
rest of the script.

Signed-off-by: Simon Glass <sjg at chromium.org>
Reviewed-by: Nicolas Schier <nsc at kernel.org>
Reviewed-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
Reviewed-by: Chen-Yu Tsai <wenst at chromium.org>
---

(no changes since v7)

Changes in v7:
- Add a note about the " -> ' change

 scripts/make_fit.py | 67 +++++++++++++++++++++++++++++----------------
 1 file changed, 44 insertions(+), 23 deletions(-)

diff --git a/scripts/make_fit.py b/scripts/make_fit.py
index 66cd73711506..7ddaf3c0d783 100755
--- a/scripts/make_fit.py
+++ b/scripts/make_fit.py
@@ -277,6 +277,47 @@ def process_dtb(fname, args):
 
     return (model, compat, files)
 
+
+def _process_dtbs(args, fsw, entries, fdts):
+    """Process all DTB files and add them to the FIT
+
+    Args:
+        args: Program arguments
+        fsw: FIT writer object
+        entries: List to append entries to
+        fdts: Dictionary of processed DTBs
+
+    Returns:
+        tuple:
+            Number of files processed
+            Total size of files processed
+    """
+    seq = 0
+    size = 0
+    for fname in args.dtbs:
+        # Ignore non-DTB (*.dtb) files
+        if os.path.splitext(fname)[1] != '.dtb':
+            continue
+
+        try:
+            (model, compat, files) = process_dtb(fname, args)
+        except Exception as e:
+            sys.stderr.write(f'Error processing {fname}:\n')
+            raise e
+
+        for fn in files:
+            if fn not in fdts:
+                seq += 1
+                size += os.path.getsize(fn)
+                output_dtb(fsw, seq, fn, args.arch, args.compress)
+                fdts[fn] = seq
+
+        files_seq = [fdts[fn] for fn in files]
+        entries.append([model, compat, files_seq])
+
+    return seq, size
+
+
 def build_fit(args):
     """Build the FIT from the provided files and arguments
 
@@ -289,7 +330,6 @@ def build_fit(args):
             int: Number of configurations generated
             size: Total uncompressed size of data
     """
-    seq = 0
     size = 0
     fsw = libfdt.FdtSw()
     setup_fit(fsw, args.name)
@@ -310,34 +350,15 @@ def build_fit(args):
         size += len(data)
         write_ramdisk(fsw, data, args)
 
-    for fname in args.dtbs:
-        # Ignore non-DTB (*.dtb) files
-        if os.path.splitext(fname)[1] != '.dtb':
-            continue
-
-        try:
-            (model, compat, files) = process_dtb(fname, args)
-        except Exception as e:
-            sys.stderr.write(f"Error processing {fname}:\n")
-            raise e
-
-        for fn in files:
-            if fn not in fdts:
-                seq += 1
-                size += os.path.getsize(fn)
-                output_dtb(fsw, seq, fn, args.arch, args.compress)
-                fdts[fn] = seq
-
-        files_seq = [fdts[fn] for fn in files]
-
-        entries.append([model, compat, files_seq])
+    count, fdt_size = _process_dtbs(args, fsw, entries, fdts)
+    size += fdt_size
 
     finish_fit(fsw, entries, bool(args.ramdisk))
 
     # Include the kernel itself in the returned file count
     fdt = fsw.as_fdt()
     fdt.pack()
-    return fdt.as_bytearray(), seq + 1 + bool(args.ramdisk), size
+    return fdt.as_bytearray(), count + 1 + bool(args.ramdisk), size
 
 
 def run_make_fit():
-- 
2.43.0



From sjg at chromium.org  Sat Dec 27 06:21:48 2025
From: sjg at chromium.org (Simon Glass)
Date: Sat, 27 Dec 2025 07:21:48 -0700
Subject: [PATCH v8 4/6] kbuild: Support a MAKE_FIT_FLAGS environment variable
In-Reply-To: <20251227142200.2241198-1-sjg@chromium.org>
References: <20251227142200.2241198-1-sjg@chromium.org>
Message-ID: <20251227142200.2241198-5-sjg@chromium.org>

In some cases it is useful to be able to pass additional flags to the
make_fit.py script. For example, since ramdisks are typically large,
passing -E to use external data can be helpful.

Add a new MAKE_FIT_FLAGS variable for this.

Signed-off-by: Simon Glass <sjg at chromium.org>
---

(no changes since v7)

Changes in v7:
- Add a new patch with the MAKE_FIT_FLAGS change

 scripts/Makefile.lib | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 28a1c08e3b22..a5641a6538b1 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -400,7 +400,7 @@ FIT_COMPRESSION ?= gzip
 
 quiet_cmd_fit = FIT     $@
       cmd_fit = $(MAKE_FIT) -o $@ --arch $(UIMAGE_ARCH) --os linux \
-		--name '$(UIMAGE_NAME)' \
+		--name '$(UIMAGE_NAME)' $(MAKE_FIT_FLAGS) \
 		$(if $(findstring 1,$(KBUILD_VERBOSE)),-v) \
 		$(if $(FIT_DECOMPOSE_DTBS),--decompose-dtbs) \
 		--compress $(FIT_COMPRESSION) -k $< @$(word 2,$^)
-- 
2.43.0



From sjg at chromium.org  Sat Dec 27 06:21:49 2025
From: sjg at chromium.org (Simon Glass)
Date: Sat, 27 Dec 2025 07:21:49 -0700
Subject: [PATCH v8 5/6] scripts/make_fit: Support a few more parallel compressors
In-Reply-To: <20251227142200.2241198-1-sjg@chromium.org>
References: <20251227142200.2241198-1-sjg@chromium.org>
Message-ID: <20251227142200.2241198-6-sjg@chromium.org>

Add support for pbzip2, xz and plzip which can compress in parallel.
This speeds up the ramdisk compression.

Signed-off-by: Simon Glass <sjg at chromium.org>
---

(no changes since v7)

Changes in v7:
- Mention xz as well, in the commit message

 scripts/make_fit.py | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/scripts/make_fit.py b/scripts/make_fit.py
index 7ddaf3c0d783..defb87f223d7 100755
--- a/scripts/make_fit.py
+++ b/scripts/make_fit.py
@@ -50,11 +50,12 @@ import libfdt
 CompTool = collections.namedtuple('CompTool', 'ext,tools')
 
 COMP_TOOLS = {
-    'bzip2': CompTool('.bz2', 'bzip2'),
+    'bzip2': CompTool('.bz2', 'pbzip2,bzip2'),
     'gzip': CompTool('.gz', 'pigz,gzip'),
     'lz4': CompTool('.lz4', 'lz4'),
-    'lzma': CompTool('.lzma', 'lzma'),
+    'lzma': CompTool('.lzma', 'plzip,lzma'),
     'lzo': CompTool('.lzo', 'lzop'),
+    'xz': CompTool('.xz', 'xz'),
     'zstd': CompTool('.zstd', 'zstd'),
 }
 
@@ -207,7 +208,12 @@ def compress_data(inf, compress):
             done = False
             for tool in comp.tools.split(','):
                 try:
-                    subprocess.call([tool, '-c'], stdin=inf, stdout=outf)
+                    # Add parallel flags for tools that support them
+                    cmd = [tool]
+                    if tool in ('zstd', 'xz'):
+                        cmd.extend(['-T0'])  # Use all available cores
+                    cmd.append('-c')
+                    subprocess.call(cmd, stdin=inf, stdout=outf)
                     done = True
                     break
                 except FileNotFoundError:
-- 
2.43.0



From sjg at chromium.org  Sat Dec 27 06:21:50 2025
From: sjg at chromium.org (Simon Glass)
Date: Sat, 27 Dec 2025 07:21:50 -0700
Subject: [PATCH v8 6/6] scripts/make_fit: Compress dtbs in parallel
In-Reply-To: <20251227142200.2241198-1-sjg@chromium.org>
References: <20251227142200.2241198-1-sjg@chromium.org>
Message-ID: <20251227142200.2241198-7-sjg@chromium.org>

When there are 1500 device tree files it takes quite a while to compress
them. Do it in parallel.

Signed-off-by: Simon Glass <sjg at chromium.org>
---

Changes in v8:
- Drop erroneous line 'kbuild: Allow adding modules into the FIT ...'

 scripts/make_fit.py | 56 ++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 50 insertions(+), 6 deletions(-)

diff --git a/scripts/make_fit.py b/scripts/make_fit.py
index defb87f223d7..e923cc8b05b7 100755
--- a/scripts/make_fit.py
+++ b/scripts/make_fit.py
@@ -37,6 +37,7 @@ as U-Boot, Linuxboot, Tianocore, etc.
 
 import argparse
 import collections
+import multiprocessing
 import os
 import subprocess
 import sys
@@ -225,15 +226,31 @@ def compress_data(inf, compress):
     return comp_data
 
 
-def output_dtb(fsw, seq, fname, arch, compress):
+def compress_dtb(fname, compress):
+    """Compress a single DTB file
+
+    Args:
+        fname (str): Filename containing the DTB
+        compress (str): Compression algorithm, e.g. 'gzip'
+
+    Returns:
+        tuple: (str: fname, bytes: compressed_data)
+    """
+    with open(fname, 'rb') as inf:
+        compressed = compress_data(inf, compress)
+    return fname, compressed
+
+
+def output_dtb(fsw, seq, fname, arch, compress, data=None):
     """Write out a single devicetree to the FIT
 
     Args:
         fsw (libfdt.FdtSw): Object to use for writing
         seq (int): Sequence number (1 for first)
         fname (str): Filename containing the DTB
-        arch: FIT architecture, e.g. 'arm64'
+        arch (str): FIT architecture, e.g. 'arm64'
         compress (str): Compressed algorithm, e.g. 'gzip'
+        data (bytes): Pre-compressed data (optional)
     """
     with fsw.add_node(f'fdt-{seq}'):
         fsw.property_string('description', os.path.basename(fname))
@@ -241,9 +258,10 @@ def output_dtb(fsw, seq, fname, arch, compress):
         fsw.property_string('arch', arch)
         fsw.property_string('compression', compress)
 
-        with open(fname, 'rb') as inf:
-            compressed = compress_data(inf, compress)
-        fsw.property('data', compressed)
+        if data is None:
+            with open(fname, 'rb') as inf:
+                data = compress_data(inf, compress)
+        fsw.property('data', data)
 
 
 def process_dtb(fname, args):
@@ -300,6 +318,11 @@ def _process_dtbs(args, fsw, entries, fdts):
     """
     seq = 0
     size = 0
+
+    # First figure out the unique DTB files that need compression
+    todo = []
+    file_info = []  # List of (fname, model, compat, files) tuples
+
     for fname in args.dtbs:
         # Ignore non-DTB (*.dtb) files
         if os.path.splitext(fname)[1] != '.dtb':
@@ -311,11 +334,32 @@ def _process_dtbs(args, fsw, entries, fdts):
             sys.stderr.write(f'Error processing {fname}:\n')
             raise e
 
+        file_info.append((fname, model, compat, files))
+        for fn in files:
+            if fn not in fdts and fn not in todo:
+                todo.append(fn)
+
+    # Compress all DTBs in parallel
+    cache = {}
+    if todo and args.compress != 'none':
+        if args.verbose:
+            print(f'Compressing {len(todo)} DTBs...')
+
+        with multiprocessing.Pool() as pool:
+            compress_args = [(fn, args.compress) for fn in todo]
+            # unpacks each tuple, calls compress_dtb(fn, compress) in parallel
+            results = pool.starmap(compress_dtb, compress_args)
+
+        cache = dict(results)
+
+    # Now write all DTBs to the FIT using pre-compressed data
+    for fname, model, compat, files in file_info:
         for fn in files:
             if fn not in fdts:
                 seq += 1
                 size += os.path.getsize(fn)
-                output_dtb(fsw, seq, fn, args.arch, args.compress)
+                output_dtb(fsw, seq, fn, args.arch, args.compress,
+                           cache.get(fn))
                 fdts[fn] = seq
 
         files_seq = [fdts[fn] for fn in files]
-- 
2.43.0



From YeoReum.Yun at arm.com  Sat Dec 27 07:46:58 2025
From: YeoReum.Yun at arm.com (Yeo Reum Yun)
Date: Sat, 27 Dec 2025 15:46:58 +0000
Subject: [PATCH] arm64: Fix PIE_E1 mapping for _PAGE_READONLY_EXEC
In-Reply-To: <20251227070625.217349-1-sgsu.park@samsung.com>
References: <CGME20251227070633epcas1p3a8f7c19c9f5114a46765073fa16ba449@epcas1p3.samsung.com>
 <20251227070625.217349-1-sgsu.park@samsung.com>
Message-ID: <GV1PR08MB105210D9BD328C2446CA8C551FBB1A@GV1PR08MB10521.eurprd08.prod.outlook.com>

Hi Seongsu, 

> diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h
> index 161e8660eddd..ca14f61dee81 100644
> --- a/arch/arm64/include/asm/pgtable-prot.h
> +++ b/arch/arm64/include/asm/pgtable-prot.h
> @@ -180,7 +180,7 @@ static inline bool __pure lpa2_is_enabled(void)
> ? ? ? PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_GCS), ? ? ? ? ? PIE_NONE_O) | \
> ? ? ? PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_GCS_RO), ? ? ? ?PIE_NONE_O) | \
>? ? ? ? PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_EXECONLY), ? ? ?PIE_NONE_O) | \
> - ? ? ? PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_READONLY_EXEC), PIE_R) ? ? ?| \
> + ? ? ? PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_READONLY_EXEC), PIE_RX) ? ? | \
>? ? ? ? PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_SHARED_EXEC), ? PIE_RW) ? ? | \
> ? ? ? PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_READONLY), ? ? ?PIE_R) ? ? ?| \
>? ? ? ? PIRx_ELx_PERM_PREP(pte_pi_index(_PAGE_SHARED), ? ? ? ?PIE_RW) ? ? | \


NIT: This looks like it allows executing user code from the kernel.
Why is this necessary?


-- ?
Sincerely,
Yeoreum Yun


From bjorn at mork.no  Sat Dec 27 08:12:33 2025
From: bjorn at mork.no (=?utf-8?Q?Bj=C3=B8rn_Mork?=)
Date: Sat, 27 Dec 2025 17:12:33 +0100
Subject: [PATCH net-next 0/9] XPCS polarity inversion via generic device
 tree properties
In-Reply-To: <20251122193341.332324-1-vladimir.oltean@nxp.com> (Vladimir
	Oltean's message of "Sat, 22 Nov 2025 21:33:32 +0200")
References: <20251122193341.332324-1-vladimir.oltean@nxp.com>
Message-ID: <87qzsfewem.fsf@miraculix.mork.no>

Vladimir Oltean <vladimir.oltean at nxp.com> writes:

> This set contains an implementation of a generic feature that should
> cater to all known needs that were identified during my documentation
> phase. I've added a new user - the XPCS - and I've converted an existing
> user - the EN8811H Ethernet PHY.

Hello Vladimir!

Will there be a new version of this patch set?

The firmware for AN8811HB has now been submitted [1], so I plan to move
forward with the driver. And without this series then I don't see any
other reasonable alternative than continuing with "airoha,pnswap-rx/tx",
like the existing EN8811H driver.


Bj?rn

[1] https://lore.kernel.org/linux-firmware/20251225163003.4797-1-lucienzx159 at gmail.com/T/#u


From pabeni at redhat.com  Sat Dec 27 08:24:31 2025
From: pabeni at redhat.com (Paolo Abeni)
Date: Sat, 27 Dec 2025 17:24:31 +0100
Subject: [PATCH net-next v2] net: stmmac: dwmac: Add a fixup for the
 Micrel KSZ9131 PHY
In-Reply-To: <20251223101240.10634-1-eichest@gmail.com>
References: <20251223101240.10634-1-eichest@gmail.com>
Message-ID: <80be718c-3592-43bf-b3ab-8e1b9d3cf41a@redhat.com>

On 12/23/25 11:10 AM, Stefan Eichenberger wrote:
> From: Stefan Eichenberger <stefan.eichenberger at toradex.com>
> 
> Add a fixup to the stmmac driver to keep the preamble before the SFD
> (Start Frame Delimiter) on the Micrel KSZ9131 PHY when the driver is
> used on an NXP i.MX8MP SoC.
> 
> This allows to workaround errata ERR050694 of the NXP i.MX8MP that
> states:
> ENET_QOS: MAC incorrectly discards the received packets when Preamble
> Byte does not precede SFD or SMD.
> 
> The bit which disables this feature is not documented in the datasheet
> from Micrel, but has been found by NXP and Micrel following this
> discussion:
> https://community.nxp.com/t5/i-MX-Processors/iMX8MP-eqos-not-working-for-10base-t/m-p/2151032
> 
> It has been tested on Verdin iMX8MP from Toradex by forcing the PHY to
> 10MBit. Without bit 2 being set in the remote loopback register, no
> packets are received. With the bit set, reception works fine.
> 
> Signed-off-by: Stefan Eichenberger <stefan.eichenberger at toradex.com>

## Form letter - net-next-closed

The net-next tree is closed for new drivers, features, code refactoring
and optimizations due to the merge window and the winter break. We are
currently accepting bug fixes only.

Please repost when net-next reopens after Jan 2nd.

RFC patches sent for review only are obviously welcome at any time.



From josua.mayer at jm0.eu  Sat Dec 27 08:28:15 2025
From: josua.mayer at jm0.eu (Josua Mayer)
Date: Sat, 27 Dec 2025 17:28:15 +0100
Subject: [PATCH 3/3] ARM: dts: imx: imx50-kobo-aura: add description for
 battery
In-Reply-To: <20251227-kobo-aura-battery-v1-0-328a90ef5122@jm0.eu>
References: <20251227-kobo-aura-battery-v1-0-328a90ef5122@jm0.eu>
Message-ID: <20251227-kobo-aura-battery-v1-3-328a90ef5122@jm0.eu>

Kobo Aura has a rechargable battery that is monitored by the embedded
controller.

Battery markings: PR-285083 3.7V Typ. 1500mAh; 575327416288 5.55Wh.

Add description for this battery and link it for monitoring by the
embedded controller.

Signed-off-by: Josua Mayer <josua.mayer at jm0.eu>
---
 arch/arm/boot/dts/nxp/imx/imx50-kobo-aura.dts | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm/boot/dts/nxp/imx/imx50-kobo-aura.dts b/arch/arm/boot/dts/nxp/imx/imx50-kobo-aura.dts
index b1a6a9c58ac33..dc8d9fd45cd23 100644
--- a/arch/arm/boot/dts/nxp/imx/imx50-kobo-aura.dts
+++ b/arch/arm/boot/dts/nxp/imx/imx50-kobo-aura.dts
@@ -16,6 +16,14 @@ chosen {
 		stdout-path = "serial1:115200n8";
 	};
 
+	battery: battery {
+		compatible = "simple-battery";
+		voltage-min-design-microvolt = <3400000>;
+		voltage-max-design-microvolt = <4100000>;
+		energy-full-design-microwatt-hours = <5550000>;
+		charge-full-design-microamp-hours = <1500000>;
+	};
+
 	memory at 70000000 {
 		device_type = "memory";
 		reg = <0x70000000 0x10000000>;
@@ -151,6 +159,7 @@ embedded-controller at 43 {
 		system-power-controller;
 		interrupts-extended = <&gpio4 11 IRQ_TYPE_EDGE_FALLING>;
 		#pwm-cells = <2>;
+		monitored-battery = <&battery>;
 	};
 };
 

-- 
2.51.0



From josua.mayer at jm0.eu  Sat Dec 27 08:28:13 2025
From: josua.mayer at jm0.eu (Josua Mayer)
Date: Sat, 27 Dec 2025 17:28:13 +0100
Subject: [PATCH 1/3] power: supply: add battery driver for netronix ec
In-Reply-To: <20251227-kobo-aura-battery-v1-0-328a90ef5122@jm0.eu>
References: <20251227-kobo-aura-battery-v1-0-328a90ef5122@jm0.eu>
Message-ID: <20251227-kobo-aura-battery-v1-1-328a90ef5122@jm0.eu>

Implement a simple battery driver for monitoring voltage with the
netronix embedded controller found in certain ebook readers.

Signed-off-by: Josua Mayer <josua.mayer at jm0.eu>
---
 drivers/mfd/ntxec.c                  |   1 +
 drivers/power/supply/Kconfig         |   9 ++++
 drivers/power/supply/Makefile        |   1 +
 drivers/power/supply/ntxec-battery.c | 101 +++++++++++++++++++++++++++++++++++
 4 files changed, 112 insertions(+)

diff --git a/drivers/mfd/ntxec.c b/drivers/mfd/ntxec.c
index 08c68de0f01bc..d5059b8862aa8 100644
--- a/drivers/mfd/ntxec.c
+++ b/drivers/mfd/ntxec.c
@@ -139,6 +139,7 @@ static const struct regmap_config regmap_config = {
 static const struct mfd_cell ntxec_subdev[] = {
 	{ .name = "ntxec-rtc" },
 	{ .name = "ntxec-pwm" },
+	{ .name = "ntxec-battery" },
 };
 
 static const struct mfd_cell ntxec_subdev_pwm[] = {
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 92f9f7aae92f2..5674a23ba7bd6 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -1132,4 +1132,13 @@ config FUEL_GAUGE_MM8013
 	  the state of charge, temperature, cycle count, actual and design
 	  capacity, etc.
 
+config BATTERY_NTXEC
+	tristate "Battery driver for Netronix embedded controller"
+	depends on MFD_NTXEC
+	help
+	  Say yes here to enable netronix ec battery monitoring driver.
+	  It enables the monitoring battery voltage on certain e-book readers
+	  using an embedded controller by ODM Netronix. Battery design
+	  characteristics are read from Firmware Tables if available.
+
 endif # POWER_SUPPLY
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 4b79d5abc49a7..db6fc815f9da2 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -128,3 +128,4 @@ obj-$(CONFIG_CHARGER_SURFACE)	+= surface_charger.o
 obj-$(CONFIG_BATTERY_UG3105)	+= ug3105_battery.o
 obj-$(CONFIG_CHARGER_QCOM_SMB2)	+= qcom_smbx.o
 obj-$(CONFIG_FUEL_GAUGE_MM8013)	+= mm8013.o
+obj-$(CONFIG_BATTERY_NTXEC)	+= ntxec-battery.o
diff --git a/drivers/power/supply/ntxec-battery.c b/drivers/power/supply/ntxec-battery.c
new file mode 100644
index 0000000000000..f49f0966d18dd
--- /dev/null
+++ b/drivers/power/supply/ntxec-battery.c
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * The Netronix embedded controller is a microcontroller found in some
+ * e-book readers designed by the original design manufacturer Netronix, Inc.
+ * It contains RTC, battery monitoring, system power management, and PWM
+ * functionality.
+ *
+ * This driver implements battery monitoring.
+ *
+ * Copyright 2021 Josua Mayer <josua.mayer at jm0.eu>
+ */
+
+#include <linux/mfd/ntxec.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+
+static const enum power_supply_property ntxec_battery_properties[] = {
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+};
+
+struct ntxec_battery {
+	struct ntxec *ec;
+};
+
+#define NTXEC_REG_READ_BATTERY	0x41
+
+static int ntxec_battery_get_property(struct power_supply *psy,
+				     enum power_supply_property psp,
+				     union power_supply_propval *val)
+{
+	struct ntxec_battery *priv = power_supply_get_drvdata(psy);
+	int ret;
+	unsigned int value;
+
+	switch (psp) {
+		case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+			ret = regmap_read(priv->ec->regmap, NTXEC_REG_READ_BATTERY, &value);
+			if (ret < 0)
+				return ret;
+
+			/* ec value to microvolt conversion:
+			 * vendor kernel source suggests linear behaviour from 3V to 4.2V
+			 * with readings 767 to 1023; each increment represents 4687,5uV.
+			 * adjust 3V boundary slightly to report exactly 4.2V when full.
+			 */
+			val->intval = 2999872 + (value - 767) * 4688;
+			break;
+		default:
+			dev_err(&psy->dev, "%s: invalid property %u\n", __func__, psp);
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct power_supply_desc ntxec_battery_desc = {
+	.name = "ec-battery",
+	.type = POWER_SUPPLY_TYPE_BATTERY,
+	.properties = ntxec_battery_properties,
+	.get_property = ntxec_battery_get_property,
+	.num_properties = ARRAY_SIZE(ntxec_battery_properties),
+};
+
+static int ntxec_battery_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct ntxec *ec = dev_get_drvdata(dev->parent);
+	struct power_supply_config psy_cfg = {};
+	struct ntxec_battery *priv;
+	struct power_supply *psy;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->ec = ec;
+	psy_cfg.drv_data = priv;
+	psy_cfg.fwnode = dev_fwnode(dev->parent);
+	psy_cfg.no_wakeup_source = true;
+	psy = devm_power_supply_register(dev, &ntxec_battery_desc, &psy_cfg);
+	if (IS_ERR(psy))
+		return PTR_ERR(psy);
+
+	return 0;
+}
+
+static struct platform_driver ntxec_battery_driver = {
+	.driver = {
+		.name = "ntxec-battery",
+	},
+	.probe = ntxec_battery_probe,
+};
+module_platform_driver(ntxec_battery_driver);
+
+MODULE_AUTHOR("Josua Mayer <josua.mayer at jm0.eu>");
+MODULE_DESCRIPTION("Battery driver for Netronix EC");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ntxec-battery");

-- 
2.51.0



From josua.mayer at jm0.eu  Sat Dec 27 08:28:14 2025
From: josua.mayer at jm0.eu (Josua Mayer)
Date: Sat, 27 Dec 2025 17:28:14 +0100
Subject: [PATCH 2/3] dt-bindings: mfd: netronix,ntxec: add reference to
 power-supply
In-Reply-To: <20251227-kobo-aura-battery-v1-0-328a90ef5122@jm0.eu>
References: <20251227-kobo-aura-battery-v1-0-328a90ef5122@jm0.eu>
Message-ID: <20251227-kobo-aura-battery-v1-2-328a90ef5122@jm0.eu>

The Netronix Embedded Controller supports monitoring of battery voltage.

Voltage monitoring functionality is self-contained and requires no
supply- or battery-specific runtime configuration.

Battery design characteristics (e.g. voltage-min-design-microvolt) are
useful for users to understand the charge level and are commonly
provided by a separate battery node linked with monitored-battery
property.

Add reference to power-supply.yaml so that power-supplies and
monitored-battery properties become available.

Further drop reg property description and replace it with maxItems 1 as
is common for i2c devices with single bus address.

Finally replace additionalProperties with unevaluatedProperties to
allow properties from referenced schemas.

Signed-off-by: Josua Mayer <josua at solid-run.com>
---
 Documentation/devicetree/bindings/mfd/netronix,ntxec.yaml | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/mfd/netronix,ntxec.yaml b/Documentation/devicetree/bindings/mfd/netronix,ntxec.yaml
index 37fbb953ea12e..6599dcf0eceb0 100644
--- a/Documentation/devicetree/bindings/mfd/netronix,ntxec.yaml
+++ b/Documentation/devicetree/bindings/mfd/netronix,ntxec.yaml
@@ -13,13 +13,15 @@ description: |
   This EC is found in e-book readers of multiple brands (e.g. Kobo, Tolino), and
   is typically implemented as a TI MSP430 microcontroller.
 
+allOf:
+  - $ref: /schemas/power/supply/power-supply.yaml
+
 properties:
   compatible:
     const: netronix,ntxec
 
   reg:
-    items:
-      - description: The I2C address of the EC
+    maxItems: 1
 
   system-power-controller:
     type: boolean
@@ -42,7 +44,7 @@ required:
   - compatible
   - reg
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
@@ -61,5 +63,6 @@ examples:
                 interrupt-parent = <&gpio4>;
                 interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
                 #pwm-cells = <2>;
+                monitored-battery = <&battery>;
         };
     };

-- 
2.51.0



From josua.mayer at jm0.eu  Sat Dec 27 08:28:12 2025
From: josua.mayer at jm0.eu (Josua Mayer)
Date: Sat, 27 Dec 2025 17:28:12 +0100
Subject: [PATCH 0/3] power: supply: add battery driver for netronix ec
Message-ID: <20251227-kobo-aura-battery-v1-0-328a90ef5122@jm0.eu>

Signed-off-by: Josua Mayer <josua.mayer at jm0.eu>
---
Josua Mayer (3):
      power: supply: add battery driver for netronix ec
      dt-bindings: mfd: netronix,ntxec: add reference to power-supply
      ARM: dts: imx: imx50-kobo-aura: add description for battery

 .../devicetree/bindings/mfd/netronix,ntxec.yaml    |   9 +-
 arch/arm/boot/dts/nxp/imx/imx50-kobo-aura.dts      |   9 ++
 drivers/mfd/ntxec.c                                |   1 +
 drivers/power/supply/Kconfig                       |   9 ++
 drivers/power/supply/Makefile                      |   1 +
 drivers/power/supply/ntxec-battery.c               | 101 +++++++++++++++++++++
 6 files changed, 127 insertions(+), 3 deletions(-)
---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20251227-kobo-aura-battery-3e60bc159d16

Best regards,
-- 
Josua Mayer <josua.mayer at jm0.eu>



From cristian.marussi at arm.com  Sat Dec 27 08:41:30 2025
From: cristian.marussi at arm.com (Cristian Marussi)
Date: Sat, 27 Dec 2025 16:41:30 +0000
Subject: [PATCH 0/2] Rework protocol version negotiation core logic
Message-ID: <20251227164132.1311988-1-cristian.marussi@arm.com>

Hi,

this small series rectifies the protocol negotiation logic employed by the
core SCMI stack when trying to cope with newer unknown protocol versions
advertised by the platform under any circumstances.

The existing protocol negotiation logic per-se was fine, but unfortunately
the whole negotiation process was started at the end of the per-protocol
initialization phase since it relies on the version querying performed by
each protocol initialization logic.

Unfortunately, this means that if the protocol initialization failed
upfront as a whole, maybe exactly due to version incompatibilities, the
negotiation itself will never be started, effectively failing to negotiate
a better version in the exact scenario where negotiation would be mostly
needed.

This series simply moves the version_get query process out of the single
protocol units and delegates to the core SCMI stack the whole procedure:
this way, the supported protocol version querying and any further needed
negotiation exchanges are performed by the core SCMI stack right before
the start of the protocol initialization phase: as a consequence the
protocol initialization phase will now be performed using the appropriate
protocol version as negotiated in advance, when needed.

As a consequence per-protocol versioning code is considerably simplified.

Based on v6.19-rc2.

Any feedback, as usual, it is very much welcome.

Thanks,

Cristian


Cristian Marussi (2):
  firmware: arm_scmi: Rework protocol version negotiation logic
  firmware: arm_scmi: Remove legacy protocol versioning logic

 drivers/firmware/arm_scmi/base.c              | 11 +--
 drivers/firmware/arm_scmi/clock.c             | 24 ++---
 drivers/firmware/arm_scmi/driver.c            | 98 +++++++++++++++----
 drivers/firmware/arm_scmi/perf.c              | 57 ++++-------
 drivers/firmware/arm_scmi/pinctrl.c           | 12 +--
 drivers/firmware/arm_scmi/power.c             | 18 +---
 drivers/firmware/arm_scmi/powercap.c          | 21 ++--
 drivers/firmware/arm_scmi/protocols.h         |  9 +-
 drivers/firmware/arm_scmi/reset.c             | 18 +---
 drivers/firmware/arm_scmi/sensors.c           | 22 ++---
 drivers/firmware/arm_scmi/system.c            | 14 +--
 .../arm_scmi/vendors/imx/imx-sm-bbm.c         | 10 +-
 .../arm_scmi/vendors/imx/imx-sm-cpu.c         |  9 +-
 .../arm_scmi/vendors/imx/imx-sm-lmm.c         |  9 +-
 .../arm_scmi/vendors/imx/imx-sm-misc.c        | 10 +-
 drivers/firmware/arm_scmi/voltage.c           | 13 +--
 16 files changed, 153 insertions(+), 202 deletions(-)

-- 
2.52.0



From cristian.marussi at arm.com  Sat Dec 27 08:41:31 2025
From: cristian.marussi at arm.com (Cristian Marussi)
Date: Sat, 27 Dec 2025 16:41:31 +0000
Subject: [PATCH 1/2] firmware: arm_scmi: Rework protocol version negotiation logic
In-Reply-To: <20251227164132.1311988-1-cristian.marussi@arm.com>
References: <20251227164132.1311988-1-cristian.marussi@arm.com>
Message-ID: <20251227164132.1311988-2-cristian.marussi@arm.com>

Protocol version negotiation can be used by an agent to request the server
to downgrade the version effectively utilized by a specific protocol
during the current session, if the latest version used by the server is
newer than the latest version known to the client.

In order for the negotiation process to be fully effective at preventing
any possible version incompatibility, it must happen early on, well before
the specific protocol initialization phase takes place.

Delegate protocol version querying to the core SCMI stack and rework the
protocol negotiation logic in order to execute the needed negotiation
exchanges upfront, right before the initialization phase takes place.

Signed-off-by: Cristian Marussi <cristian.marussi at arm.com>
---
 drivers/firmware/arm_scmi/driver.c    | 93 ++++++++++++++++++++++-----
 drivers/firmware/arm_scmi/protocols.h |  4 ++
 2 files changed, 81 insertions(+), 16 deletions(-)

diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index 5caa9191a8d1..094cfcf51d28 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -2112,6 +2112,76 @@ static int scmi_protocol_version_negotiate(struct scmi_protocol_handle *ph)
 	return ret;
 }
 
+/**
+ * scmi_protocol_version_initialize  - Initialize protocol version
+ * @dev: A device reference.
+ * @pi: A reference to the protocol instance being initialized
+ *
+ * At first retrieve the newest protocol version supported by the platform for
+ * this specific protoocol.
+ *
+ * Negotiation is attempted only when the platform advertised a protocol
+ * version newer than the most recent version known to this agent, since
+ * backward compatibility is NOT assured in general between versions.
+ *
+ * Failing to negotiate a fallback version or to query supported version at
+ * all will result in an attempt to use the newest version known to this agent
+ * even though compatibility is NOT assured.
+ *
+ * Versions are defined as:
+ *
+ * pi->version: the version supported by the platform as returned by the query.
+ * pi->proto->supported_version: the newest version supported by this agent
+ *				 for this protocol.
+ * pi->negotiated_version: The version successfully negotiated with the platform.
+ * ph->version: The final version effectively chosen for this session.
+ */
+static void scmi_protocol_version_initialize(struct device *dev,
+					     struct scmi_protocol_instance *pi)
+{
+	struct scmi_protocol_handle *ph = &pi->ph;
+	int ret;
+
+	/*
+	 * Query and store platform supported protocol version: this is usually
+	 * the newest version the platfom can support.
+	 */
+	ret = version_get(ph, &pi->version);
+	if (ret) {
+		dev_warn(dev,
+			 "Failed to query supported version for protocol 0x%X.\n",
+			 pi->proto->id);
+		goto best_effort;
+	}
+
+	/* Need to negotiate at all ? */
+	if (pi->version <= pi->proto->supported_version) {
+		ph->version = pi->version;
+		return;
+	}
+
+	/* Attempt negotiation */
+	ret = scmi_protocol_version_negotiate(ph);
+	if (!ret) {
+		ph->version = pi->negotiated_version;
+		dev_info(dev,
+			 "Protocol 0x%X successfully negotiated version 0x%X\n",
+			 pi->proto->id, ph->version);
+		return;
+	}
+
+	dev_warn(dev,
+		 "Detected UNSUPPORTED higher version 0x%X for protocol 0x%X.\n",
+		 pi->version, pi->proto->id);
+
+best_effort:
+	/* Fallback to use newest version known to this agent */
+	ph->version = pi->proto->supported_version;
+	dev_warn(dev,
+		 "Trying version 0x%X. Backward compatibility is NOT assured.\n",
+		 ph->version);
+}
+
 /**
  * scmi_alloc_init_protocol_instance  - Allocate and initialize a protocol
  * instance descriptor.
@@ -2157,6 +2227,13 @@ scmi_alloc_init_protocol_instance(struct scmi_info *info,
 	pi->ph.set_priv = scmi_set_protocol_priv;
 	pi->ph.get_priv = scmi_get_protocol_priv;
 	refcount_set(&pi->users, 1);
+
+	/*
+	 * Initialize effectively used protocol version performing any
+	 * possibly needed negotiations.
+	 */
+	scmi_protocol_version_initialize(handle->dev, pi);
+
 	/* proto->init is assured NON NULL by scmi_protocol_register */
 	ret = pi->proto->instance_init(&pi->ph);
 	if (ret)
@@ -2184,22 +2261,6 @@ scmi_alloc_init_protocol_instance(struct scmi_info *info,
 	devres_close_group(handle->dev, pi->gid);
 	dev_dbg(handle->dev, "Initialized protocol: 0x%X\n", pi->proto->id);
 
-	if (pi->version > proto->supported_version) {
-		ret = scmi_protocol_version_negotiate(&pi->ph);
-		if (!ret) {
-			dev_info(handle->dev,
-				 "Protocol 0x%X successfully negotiated version 0x%X\n",
-				 proto->id, pi->negotiated_version);
-		} else {
-			dev_warn(handle->dev,
-				 "Detected UNSUPPORTED higher version 0x%X for protocol 0x%X.\n",
-				 pi->version, pi->proto->id);
-			dev_warn(handle->dev,
-				 "Trying version 0x%X. Backward compatibility is NOT assured.\n",
-				 pi->proto->supported_version);
-		}
-	}
-
 	return pi;
 
 clean:
diff --git a/drivers/firmware/arm_scmi/protocols.h b/drivers/firmware/arm_scmi/protocols.h
index d62c4469d1fd..2766c2b822b5 100644
--- a/drivers/firmware/arm_scmi/protocols.h
+++ b/drivers/firmware/arm_scmi/protocols.h
@@ -159,6 +159,9 @@ struct scmi_proto_helpers_ops;
  * struct scmi_protocol_handle  - Reference to an initialized protocol instance
  *
  * @dev: A reference to the associated SCMI instance device (handle->dev).
+ * @version: The protocol version currently effectively in use by this
+ *	     initialized instance of the protocol as determined at the end of
+ *	     any possibly needed negotiations performed by the core.
  * @xops: A reference to a struct holding refs to the core xfer operations that
  *	  can be used by the protocol implementation to generate SCMI messages.
  * @set_priv: A method to set protocol private data for this instance.
@@ -177,6 +180,7 @@ struct scmi_proto_helpers_ops;
  */
 struct scmi_protocol_handle {
 	struct device *dev;
+	unsigned int version;
 	const struct scmi_xfer_ops *xops;
 	const struct scmi_proto_helpers_ops *hops;
 	int (*set_priv)(const struct scmi_protocol_handle *ph, void *priv,
-- 
2.52.0



From cristian.marussi at arm.com  Sat Dec 27 08:41:32 2025
From: cristian.marussi at arm.com (Cristian Marussi)
Date: Sat, 27 Dec 2025 16:41:32 +0000
Subject: [PATCH 2/2] firmware: arm_scmi: Remove legacy protocol versioning logic
In-Reply-To: <20251227164132.1311988-1-cristian.marussi@arm.com>
References: <20251227164132.1311988-1-cristian.marussi@arm.com>
Message-ID: <20251227164132.1311988-3-cristian.marussi@arm.com>

Protocol version negotiation logic is centralized in the SCMI core stack
so that most of the legacy per-protocol versioning logic is redundant and
can be removed.

Remove protocol-specific versioning code and refactor all the protocols to
use the new simplified centralized logic.

Signed-off-by: Cristian Marussi <cristian.marussi at arm.com>
---
 drivers/firmware/arm_scmi/base.c              | 11 +---
 drivers/firmware/arm_scmi/clock.c             | 24 +++-----
 drivers/firmware/arm_scmi/driver.c            |  5 +-
 drivers/firmware/arm_scmi/perf.c              | 57 +++++++------------
 drivers/firmware/arm_scmi/pinctrl.c           | 12 +---
 drivers/firmware/arm_scmi/power.c             | 18 ++----
 drivers/firmware/arm_scmi/powercap.c          | 21 +++----
 drivers/firmware/arm_scmi/protocols.h         |  5 +-
 drivers/firmware/arm_scmi/reset.c             | 18 ++----
 drivers/firmware/arm_scmi/sensors.c           | 22 +++----
 drivers/firmware/arm_scmi/system.c            | 14 +----
 .../arm_scmi/vendors/imx/imx-sm-bbm.c         | 10 +---
 .../arm_scmi/vendors/imx/imx-sm-cpu.c         |  9 +--
 .../arm_scmi/vendors/imx/imx-sm-lmm.c         |  9 +--
 .../arm_scmi/vendors/imx/imx-sm-misc.c        | 10 +---
 drivers/firmware/arm_scmi/voltage.c           | 13 +----
 16 files changed, 72 insertions(+), 186 deletions(-)

diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c
index 86b376c50a13..22267bbd0f4d 100644
--- a/drivers/firmware/arm_scmi/base.c
+++ b/drivers/firmware/arm_scmi/base.c
@@ -375,18 +375,13 @@ static int scmi_base_protocol_init(const struct scmi_protocol_handle *ph)
 {
 	int id, ret;
 	u8 *prot_imp;
-	u32 version;
 	char name[SCMI_SHORT_NAME_MAX_SIZE];
 	struct device *dev = ph->dev;
 	struct scmi_revision_info *rev = scmi_revision_area_get(ph);
 
-	ret = ph->xops->version_get(ph, &version);
-	if (ret)
-		return ret;
-
-	rev->major_ver = PROTOCOL_REV_MAJOR(version);
-	rev->minor_ver = PROTOCOL_REV_MINOR(version);
-	ph->set_priv(ph, rev, version);
+	rev->major_ver = PROTOCOL_REV_MAJOR(ph->version);
+	rev->minor_ver = PROTOCOL_REV_MINOR(ph->version);
+	ph->set_priv(ph, rev);
 
 	ret = scmi_base_attributes_get(ph);
 	if (ret)
diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c
index afa7981efe82..ab36871650a1 100644
--- a/drivers/firmware/arm_scmi/clock.c
+++ b/drivers/firmware/arm_scmi/clock.c
@@ -157,7 +157,6 @@ struct scmi_clock_rate_notify_payld {
 };
 
 struct clock_info {
-	u32 version;
 	int num_clocks;
 	int max_async_req;
 	bool notify_rate_changed_cmd;
@@ -346,8 +345,7 @@ scmi_clock_get_permissions(const struct scmi_protocol_handle *ph, u32 clk_id,
 }
 
 static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
-				     u32 clk_id, struct clock_info *cinfo,
-				     u32 version)
+				     u32 clk_id, struct clock_info *cinfo)
 {
 	int ret;
 	u32 attributes;
@@ -370,7 +368,7 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
 		attributes = le32_to_cpu(attr->attributes);
 		strscpy(clk->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE);
 		/* clock_enable_latency field is present only since SCMI v3.1 */
-		if (PROTOCOL_REV_MAJOR(version) >= 0x2)
+		if (PROTOCOL_REV_MAJOR(ph->version) >= 0x2)
 			latency = le32_to_cpu(attr->clock_enable_latency);
 		clk->enable_latency = latency ? : U32_MAX;
 	}
@@ -381,7 +379,7 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
 	 * If supported overwrite short name with the extended one;
 	 * on error just carry on and use already provided short name.
 	 */
-	if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x2) {
+	if (!ret && PROTOCOL_REV_MAJOR(ph->version) >= 0x2) {
 		if (SUPPORTS_EXTENDED_NAMES(attributes))
 			ph->hops->extended_name_get(ph, CLOCK_NAME_GET, clk_id,
 						    NULL, clk->name,
@@ -393,7 +391,7 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
 		if (cinfo->notify_rate_change_requested_cmd &&
 		    SUPPORTS_RATE_CHANGE_REQUESTED_NOTIF(attributes))
 			clk->rate_change_requested_notifications = true;
-		if (PROTOCOL_REV_MAJOR(version) >= 0x3) {
+		if (PROTOCOL_REV_MAJOR(ph->version) >= 0x3) {
 			if (SUPPORTS_PARENT_CLOCK(attributes))
 				scmi_clock_possible_parents(ph, clk_id, clk);
 			if (SUPPORTS_GET_PERMISSIONS(attributes))
@@ -1068,16 +1066,11 @@ static const struct scmi_protocol_events clk_protocol_events = {
 
 static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph)
 {
-	u32 version;
 	int clkid, ret;
 	struct clock_info *cinfo;
 
-	ret = ph->xops->version_get(ph, &version);
-	if (ret)
-		return ret;
-
 	dev_dbg(ph->dev, "Clock Version %d.%d\n",
-		PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+		PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
 
 	cinfo = devm_kzalloc(ph->dev, sizeof(*cinfo), GFP_KERNEL);
 	if (!cinfo)
@@ -1095,12 +1088,12 @@ static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph)
 	for (clkid = 0; clkid < cinfo->num_clocks; clkid++) {
 		struct scmi_clock_info *clk = cinfo->clk + clkid;
 
-		ret = scmi_clock_attributes_get(ph, clkid, cinfo, version);
+		ret = scmi_clock_attributes_get(ph, clkid, cinfo);
 		if (!ret)
 			scmi_clock_describe_rates_get(ph, clkid, clk);
 	}
 
-	if (PROTOCOL_REV_MAJOR(version) >= 0x3) {
+	if (PROTOCOL_REV_MAJOR(ph->version) >= 0x3) {
 		cinfo->clock_config_set = scmi_clock_config_set_v2;
 		cinfo->clock_config_get = scmi_clock_config_get_v2;
 	} else {
@@ -1108,8 +1101,7 @@ static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph)
 		cinfo->clock_config_get = scmi_clock_config_get;
 	}
 
-	cinfo->version = version;
-	return ph->set_priv(ph, cinfo, version);
+	return ph->set_priv(ph, cinfo);
 }
 
 static const struct scmi_protocol scmi_clock = {
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index 094cfcf51d28..3e76a3204ba4 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -1627,17 +1627,15 @@ static int version_get(const struct scmi_protocol_handle *ph, u32 *version)
  *
  * @ph: A reference to the protocol handle.
  * @priv: The private data to set.
- * @version: The detected protocol version for the core to register.
  *
  * Return: 0 on Success
  */
 static int scmi_set_protocol_priv(const struct scmi_protocol_handle *ph,
-				  void *priv, u32 version)
+				  void *priv)
 {
 	struct scmi_protocol_instance *pi = ph_to_pi(ph);
 
 	pi->priv = priv;
-	pi->version = version;
 
 	return 0;
 }
@@ -1657,7 +1655,6 @@ static void *scmi_get_protocol_priv(const struct scmi_protocol_handle *ph)
 }
 
 static const struct scmi_xfer_ops xfer_ops = {
-	.version_get = version_get,
 	.xfer_get_init = xfer_get_init,
 	.reset_rx_to_maxsz = reset_rx_to_maxsz,
 	.do_xfer = do_xfer,
diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c
index 683fd9b85c5c..c4f6284ccb31 100644
--- a/drivers/firmware/arm_scmi/perf.c
+++ b/drivers/firmware/arm_scmi/perf.c
@@ -178,7 +178,6 @@ struct perf_dom_info {
 })
 
 struct scmi_perf_info {
-	u32 version;
 	u16 num_domains;
 	enum scmi_power_scale power_scale;
 	u64 stats_addr;
@@ -215,7 +214,7 @@ static int scmi_perf_attributes_get(const struct scmi_protocol_handle *ph,
 
 		if (POWER_SCALE_IN_MILLIWATT(flags))
 			pi->power_scale = SCMI_POWER_MILLIWATTS;
-		if (PROTOCOL_REV_MAJOR(pi->version) >= 0x3)
+		if (PROTOCOL_REV_MAJOR(ph->version) >= 0x3)
 			if (POWER_SCALE_IN_MICROWATT(flags))
 				pi->power_scale = SCMI_POWER_MICROWATTS;
 
@@ -251,8 +250,7 @@ static void scmi_perf_xa_destroy(void *data)
 static int
 scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
 				struct perf_dom_info *dom_info,
-				bool notify_lim_cmd, bool notify_lvl_cmd,
-				u32 version)
+				bool notify_lim_cmd, bool notify_lvl_cmd)
 {
 	int ret;
 	u32 flags;
@@ -280,7 +278,7 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
 			dom_info->perf_level_notify =
 				SUPPORTS_PERF_LEVEL_NOTIFY(flags);
 		dom_info->perf_fastchannels = SUPPORTS_PERF_FASTCHANNELS(flags);
-		if (PROTOCOL_REV_MAJOR(version) >= 0x4)
+		if (PROTOCOL_REV_MAJOR(ph->version) >= 0x4)
 			dom_info->level_indexing_mode =
 				SUPPORTS_LEVEL_INDEXING(flags);
 		dom_info->rate_limit_us = le32_to_cpu(attr->rate_limit_us) &
@@ -323,7 +321,7 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
 	 * If supported overwrite short name with the extended one;
 	 * on error just carry on and use already provided short name.
 	 */
-	if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 &&
+	if (!ret && PROTOCOL_REV_MAJOR(ph->version) >= 0x3 &&
 	    SUPPORTS_EXTENDED_NAMES(flags))
 		ph->hops->extended_name_get(ph, PERF_DOMAIN_NAME_GET,
 					    dom_info->id, NULL, dom_info->info.name,
@@ -345,19 +343,14 @@ static int opp_cmp_func(const void *opp1, const void *opp2)
 	return t1->perf - t2->perf;
 }
 
-struct scmi_perf_ipriv {
-	u32 version;
-	struct perf_dom_info *perf_dom;
-};
-
 static void iter_perf_levels_prepare_message(void *message,
 					     unsigned int desc_index,
 					     const void *priv)
 {
 	struct scmi_msg_perf_describe_levels *msg = message;
-	const struct scmi_perf_ipriv *p = priv;
+	const struct perf_dom_info *perf_dom = priv;
 
-	msg->domain = cpu_to_le32(p->perf_dom->id);
+	msg->domain = cpu_to_le32(perf_dom->id);
 	/* Set the number of OPPs to be skipped/already read */
 	msg->level_index = cpu_to_le32(desc_index);
 }
@@ -445,21 +438,21 @@ iter_perf_levels_process_response(const struct scmi_protocol_handle *ph,
 {
 	int ret;
 	struct scmi_opp *opp;
-	struct scmi_perf_ipriv *p = priv;
+	struct perf_dom_info *perf_dom = priv;
 
-	opp = &p->perf_dom->opp[p->perf_dom->opp_count];
-	if (PROTOCOL_REV_MAJOR(p->version) <= 0x3)
-		ret = process_response_opp(ph->dev, p->perf_dom, opp,
+	opp = &perf_dom->opp[perf_dom->opp_count];
+	if (PROTOCOL_REV_MAJOR(ph->version) <= 0x3)
+		ret = process_response_opp(ph->dev, perf_dom, opp,
 					   st->loop_idx, response);
 	else
-		ret = process_response_opp_v4(ph->dev, p->perf_dom, opp,
+		ret = process_response_opp_v4(ph->dev, perf_dom, opp,
 					      st->loop_idx, response);
 
 	/* Skip BAD duplicates received from firmware */
 	if (ret)
 		return ret == -EBUSY ? 0 : ret;
 
-	p->perf_dom->opp_count++;
+	perf_dom->opp_count++;
 
 	dev_dbg(ph->dev, "Level %d Power %d Latency %dus Ifreq %d Index %d\n",
 		opp->perf, opp->power, opp->trans_latency_us,
@@ -470,7 +463,7 @@ iter_perf_levels_process_response(const struct scmi_protocol_handle *ph,
 
 static int
 scmi_perf_describe_levels_get(const struct scmi_protocol_handle *ph,
-			      struct perf_dom_info *perf_dom, u32 version)
+			      struct perf_dom_info *perf_dom)
 {
 	int ret;
 	void *iter;
@@ -479,15 +472,11 @@ scmi_perf_describe_levels_get(const struct scmi_protocol_handle *ph,
 		.update_state = iter_perf_levels_update_state,
 		.process_response = iter_perf_levels_process_response,
 	};
-	struct scmi_perf_ipriv ppriv = {
-		.version = version,
-		.perf_dom = perf_dom,
-	};
 
 	iter = ph->hops->iter_response_init(ph, &ops, MAX_OPPS,
 					    PERF_DESCRIBE_LEVELS,
 					    sizeof(struct scmi_msg_perf_describe_levels),
-					    &ppriv);
+					    perf_dom);
 	if (IS_ERR(iter))
 		return PTR_ERR(iter);
 
@@ -576,7 +565,6 @@ static int __scmi_perf_limits_set(const struct scmi_protocol_handle *ph,
 static int scmi_perf_limits_set(const struct scmi_protocol_handle *ph,
 				u32 domain, u32 max_perf, u32 min_perf)
 {
-	struct scmi_perf_info *pi = ph->get_priv(ph);
 	struct perf_dom_info *dom;
 
 	dom = scmi_perf_domain_lookup(ph, domain);
@@ -586,7 +574,7 @@ static int scmi_perf_limits_set(const struct scmi_protocol_handle *ph,
 	if (!dom->set_limits)
 		return -EOPNOTSUPP;
 
-	if (PROTOCOL_REV_MAJOR(pi->version) >= 0x3 && !max_perf && !min_perf)
+	if (PROTOCOL_REV_MAJOR(ph->version) >= 0x3 && !max_perf && !min_perf)
 		return -EINVAL;
 
 	if (dom->level_indexing_mode) {
@@ -1281,22 +1269,15 @@ static const struct scmi_protocol_events perf_protocol_events = {
 static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph)
 {
 	int domain, ret;
-	u32 version;
 	struct scmi_perf_info *pinfo;
 
-	ret = ph->xops->version_get(ph, &version);
-	if (ret)
-		return ret;
-
 	dev_dbg(ph->dev, "Performance Version %d.%d\n",
-		PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+		PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
 
 	pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
 	if (!pinfo)
 		return -ENOMEM;
 
-	pinfo->version = version;
-
 	ret = scmi_perf_attributes_get(ph, pinfo);
 	if (ret)
 		return ret;
@@ -1311,8 +1292,8 @@ static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph)
 
 		dom->id = domain;
 		scmi_perf_domain_attributes_get(ph, dom, pinfo->notify_lim_cmd,
-						pinfo->notify_lvl_cmd, version);
-		scmi_perf_describe_levels_get(ph, dom, version);
+						pinfo->notify_lvl_cmd);
+		scmi_perf_describe_levels_get(ph, dom);
 
 		if (dom->perf_fastchannels)
 			scmi_perf_domain_init_fc(ph, dom);
@@ -1322,7 +1303,7 @@ static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph)
 	if (ret)
 		return ret;
 
-	return ph->set_priv(ph, pinfo, version);
+	return ph->set_priv(ph, pinfo);
 }
 
 static const struct scmi_protocol scmi_perf = {
diff --git a/drivers/firmware/arm_scmi/pinctrl.c b/drivers/firmware/arm_scmi/pinctrl.c
index 3855c98caf06..ecb83b329f23 100644
--- a/drivers/firmware/arm_scmi/pinctrl.c
+++ b/drivers/firmware/arm_scmi/pinctrl.c
@@ -117,7 +117,6 @@ struct scmi_pin_info {
 };
 
 struct scmi_pinctrl_info {
-	u32 version;
 	int nr_groups;
 	int nr_functions;
 	int nr_pins;
@@ -843,15 +842,10 @@ static const struct scmi_pinctrl_proto_ops pinctrl_proto_ops = {
 static int scmi_pinctrl_protocol_init(const struct scmi_protocol_handle *ph)
 {
 	int ret;
-	u32 version;
 	struct scmi_pinctrl_info *pinfo;
 
-	ret = ph->xops->version_get(ph, &version);
-	if (ret)
-		return ret;
-
 	dev_dbg(ph->dev, "Pinctrl Version %d.%d\n",
-		PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+		PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
 
 	pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
 	if (!pinfo)
@@ -876,9 +870,7 @@ static int scmi_pinctrl_protocol_init(const struct scmi_protocol_handle *ph)
 	if (!pinfo->functions)
 		return -ENOMEM;
 
-	pinfo->version = version;
-
-	return ph->set_priv(ph, pinfo, version);
+	return ph->set_priv(ph, pinfo);
 }
 
 static int scmi_pinctrl_protocol_deinit(const struct scmi_protocol_handle *ph)
diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c
index 59aa16444c64..bb5062ab8280 100644
--- a/drivers/firmware/arm_scmi/power.c
+++ b/drivers/firmware/arm_scmi/power.c
@@ -67,7 +67,6 @@ struct power_dom_info {
 };
 
 struct scmi_power_info {
-	u32 version;
 	bool notify_state_change_cmd;
 	int num_domains;
 	u64 stats_addr;
@@ -109,7 +108,7 @@ static int scmi_power_attributes_get(const struct scmi_protocol_handle *ph,
 static int
 scmi_power_domain_attributes_get(const struct scmi_protocol_handle *ph,
 				 u32 domain, struct power_dom_info *dom_info,
-				 u32 version, bool notify_state_change_cmd)
+				 bool notify_state_change_cmd)
 {
 	int ret;
 	u32 flags;
@@ -141,7 +140,7 @@ scmi_power_domain_attributes_get(const struct scmi_protocol_handle *ph,
 	 * If supported overwrite short name with the extended one;
 	 * on error just carry on and use already provided short name.
 	 */
-	if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 &&
+	if (!ret && PROTOCOL_REV_MAJOR(ph->version) >= 0x3 &&
 	    SUPPORTS_EXTENDED_NAMES(flags)) {
 		ph->hops->extended_name_get(ph, POWER_DOMAIN_NAME_GET,
 					    domain, NULL, dom_info->name,
@@ -323,15 +322,10 @@ static const struct scmi_protocol_events power_protocol_events = {
 static int scmi_power_protocol_init(const struct scmi_protocol_handle *ph)
 {
 	int domain, ret;
-	u32 version;
 	struct scmi_power_info *pinfo;
 
-	ret = ph->xops->version_get(ph, &version);
-	if (ret)
-		return ret;
-
 	dev_dbg(ph->dev, "Power Version %d.%d\n",
-		PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+		PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
 
 	pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
 	if (!pinfo)
@@ -349,13 +343,11 @@ static int scmi_power_protocol_init(const struct scmi_protocol_handle *ph)
 	for (domain = 0; domain < pinfo->num_domains; domain++) {
 		struct power_dom_info *dom = pinfo->dom_info + domain;
 
-		scmi_power_domain_attributes_get(ph, domain, dom, version,
+		scmi_power_domain_attributes_get(ph, domain, dom,
 						 pinfo->notify_state_change_cmd);
 	}
 
-	pinfo->version = version;
-
-	return ph->set_priv(ph, pinfo, version);
+	return ph->set_priv(ph, pinfo);
 }
 
 static const struct scmi_protocol scmi_power = {
diff --git a/drivers/firmware/arm_scmi/powercap.c b/drivers/firmware/arm_scmi/powercap.c
index 1fa79bba492e..ab9733f4458b 100644
--- a/drivers/firmware/arm_scmi/powercap.c
+++ b/drivers/firmware/arm_scmi/powercap.c
@@ -122,7 +122,6 @@ struct scmi_powercap_state {
 };
 
 struct powercap_info {
-	u32 version;
 	int num_domains;
 	bool notify_cap_cmd;
 	bool notify_measurements_cmd;
@@ -434,7 +433,7 @@ static int __scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
 	}
 
 	/* Save the last explicitly set non-zero powercap value */
-	if (PROTOCOL_REV_MAJOR(pi->version) >= 0x2 && !ret && power_cap)
+	if (PROTOCOL_REV_MAJOR(ph->version) >= 0x2 && !ret && power_cap)
 		pi->states[domain_id].last_pcap = power_cap;
 
 	return ret;
@@ -454,7 +453,7 @@ static int scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
 		return -EINVAL;
 
 	/* Just log the last set request if acting on a disabled domain */
-	if (PROTOCOL_REV_MAJOR(pi->version) >= 0x2 &&
+	if (PROTOCOL_REV_MAJOR(ph->version) >= 0x2 &&
 	    !pi->states[domain_id].enabled) {
 		pi->states[domain_id].last_pcap = power_cap;
 		return 0;
@@ -635,7 +634,7 @@ static int scmi_powercap_cap_enable_set(const struct scmi_protocol_handle *ph,
 	u32 power_cap;
 	struct powercap_info *pi = ph->get_priv(ph);
 
-	if (PROTOCOL_REV_MAJOR(pi->version) < 0x2)
+	if (PROTOCOL_REV_MAJOR(ph->version) < 0x2)
 		return -EINVAL;
 
 	if (enable == pi->states[domain_id].enabled)
@@ -676,7 +675,7 @@ static int scmi_powercap_cap_enable_get(const struct scmi_protocol_handle *ph,
 	struct powercap_info *pi = ph->get_priv(ph);
 
 	*enable = true;
-	if (PROTOCOL_REV_MAJOR(pi->version) < 0x2)
+	if (PROTOCOL_REV_MAJOR(ph->version) < 0x2)
 		return 0;
 
 	/*
@@ -961,15 +960,10 @@ static int
 scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph)
 {
 	int domain, ret;
-	u32 version;
 	struct powercap_info *pinfo;
 
-	ret = ph->xops->version_get(ph, &version);
-	if (ret)
-		return ret;
-
 	dev_dbg(ph->dev, "Powercap Version %d.%d\n",
-		PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+		PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
 
 	pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
 	if (!pinfo)
@@ -1006,7 +1000,7 @@ scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph)
 						     &pinfo->powercaps[domain].fc_info);
 
 		/* Grab initial state when disable is supported. */
-		if (PROTOCOL_REV_MAJOR(version) >= 0x2) {
+		if (PROTOCOL_REV_MAJOR(ph->version) >= 0x2) {
 			ret = __scmi_powercap_cap_get(ph,
 						      &pinfo->powercaps[domain],
 						      &pinfo->states[domain].last_pcap);
@@ -1018,8 +1012,7 @@ scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph)
 		}
 	}
 
-	pinfo->version = version;
-	return ph->set_priv(ph, pinfo, version);
+	return ph->set_priv(ph, pinfo);
 }
 
 static const struct scmi_protocol scmi_powercap = {
diff --git a/drivers/firmware/arm_scmi/protocols.h b/drivers/firmware/arm_scmi/protocols.h
index 2766c2b822b5..4c75970326e6 100644
--- a/drivers/firmware/arm_scmi/protocols.h
+++ b/drivers/firmware/arm_scmi/protocols.h
@@ -183,8 +183,7 @@ struct scmi_protocol_handle {
 	unsigned int version;
 	const struct scmi_xfer_ops *xops;
 	const struct scmi_proto_helpers_ops *hops;
-	int (*set_priv)(const struct scmi_protocol_handle *ph, void *priv,
-			u32 version);
+	int (*set_priv)(const struct scmi_protocol_handle *ph, void *priv);
 	void *(*get_priv)(const struct scmi_protocol_handle *ph);
 };
 
@@ -291,7 +290,6 @@ struct scmi_proto_helpers_ops {
 
 /**
  * struct scmi_xfer_ops  - References to the core SCMI xfer operations.
- * @version_get: Get this version protocol.
  * @xfer_get_init: Initialize one struct xfer if any xfer slot is free.
  * @reset_rx_to_maxsz: Reset rx size to max transport size.
  * @do_xfer: Do the SCMI transfer.
@@ -304,7 +302,6 @@ struct scmi_proto_helpers_ops {
  * another protocol.
  */
 struct scmi_xfer_ops {
-	int (*version_get)(const struct scmi_protocol_handle *ph, u32 *version);
 	int (*xfer_get_init)(const struct scmi_protocol_handle *ph, u8 msg_id,
 			     size_t tx_size, size_t rx_size,
 			     struct scmi_xfer **p);
diff --git a/drivers/firmware/arm_scmi/reset.c b/drivers/firmware/arm_scmi/reset.c
index 0aa82b96f41b..06df8e40c6c6 100644
--- a/drivers/firmware/arm_scmi/reset.c
+++ b/drivers/firmware/arm_scmi/reset.c
@@ -65,7 +65,6 @@ struct reset_dom_info {
 };
 
 struct scmi_reset_info {
-	u32 version;
 	int num_domains;
 	bool notify_reset_cmd;
 	struct reset_dom_info *dom_info;
@@ -100,8 +99,7 @@ static int scmi_reset_attributes_get(const struct scmi_protocol_handle *ph,
 
 static int
 scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph,
-				 struct scmi_reset_info *pinfo,
-				 u32 domain, u32 version)
+				 struct scmi_reset_info *pinfo, u32 domain)
 {
 	int ret;
 	u32 attributes;
@@ -137,7 +135,7 @@ scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph,
 	 * If supported overwrite short name with the extended one;
 	 * on error just carry on and use already provided short name.
 	 */
-	if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 &&
+	if (!ret && PROTOCOL_REV_MAJOR(ph->version) >= 0x3 &&
 	    SUPPORTS_EXTENDED_NAMES(attributes))
 		ph->hops->extended_name_get(ph, RESET_DOMAIN_NAME_GET, domain,
 					    NULL, dom_info->name,
@@ -340,15 +338,10 @@ static const struct scmi_protocol_events reset_protocol_events = {
 static int scmi_reset_protocol_init(const struct scmi_protocol_handle *ph)
 {
 	int domain, ret;
-	u32 version;
 	struct scmi_reset_info *pinfo;
 
-	ret = ph->xops->version_get(ph, &version);
-	if (ret)
-		return ret;
-
 	dev_dbg(ph->dev, "Reset Version %d.%d\n",
-		PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+		PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
 
 	pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
 	if (!pinfo)
@@ -364,10 +357,9 @@ static int scmi_reset_protocol_init(const struct scmi_protocol_handle *ph)
 		return -ENOMEM;
 
 	for (domain = 0; domain < pinfo->num_domains; domain++)
-		scmi_reset_domain_attributes_get(ph, pinfo, domain, version);
+		scmi_reset_domain_attributes_get(ph, pinfo, domain);
 
-	pinfo->version = version;
-	return ph->set_priv(ph, pinfo, version);
+	return ph->set_priv(ph, pinfo);
 }
 
 static const struct scmi_protocol scmi_reset = {
diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c
index 791efd0f82d7..882d55f987d2 100644
--- a/drivers/firmware/arm_scmi/sensors.c
+++ b/drivers/firmware/arm_scmi/sensors.c
@@ -214,7 +214,6 @@ struct scmi_sensor_update_notify_payld {
 };
 
 struct sensors_info {
-	u32 version;
 	bool notify_trip_point_cmd;
 	bool notify_continuos_update_cmd;
 	int num_sensors;
@@ -524,8 +523,7 @@ scmi_sensor_axis_extended_names_get(const struct scmi_protocol_handle *ph,
 }
 
 static int scmi_sensor_axis_description(const struct scmi_protocol_handle *ph,
-					struct scmi_sensor_info *s,
-					u32 version)
+					struct scmi_sensor_info *s)
 {
 	int ret;
 	void *iter;
@@ -555,7 +553,7 @@ static int scmi_sensor_axis_description(const struct scmi_protocol_handle *ph,
 	if (ret)
 		return ret;
 
-	if (PROTOCOL_REV_MAJOR(version) >= 0x3 &&
+	if (PROTOCOL_REV_MAJOR(ph->version) >= 0x3 &&
 	    apriv.any_axes_support_extended_names)
 		ret = scmi_sensor_axis_extended_names_get(ph, s);
 
@@ -621,7 +619,7 @@ iter_sens_descr_process_response(const struct scmi_protocol_handle *ph,
 	s->type = SENSOR_TYPE(attrh);
 	/* Use pre-allocated pool wherever possible */
 	s->intervals.desc = s->intervals.prealloc_pool;
-	if (si->version == SCMIv2_SENSOR_PROTOCOL) {
+	if (ph->version == SCMIv2_SENSOR_PROTOCOL) {
 		s->intervals.segmented = false;
 		s->intervals.count = 1;
 		/*
@@ -659,7 +657,7 @@ iter_sens_descr_process_response(const struct scmi_protocol_handle *ph,
 	 * one; on error just carry on and use already provided
 	 * short name.
 	 */
-	if (PROTOCOL_REV_MAJOR(si->version) >= 0x3 &&
+	if (PROTOCOL_REV_MAJOR(ph->version) >= 0x3 &&
 	    SUPPORTS_EXTENDED_NAMES(attrl))
 		ph->hops->extended_name_get(ph, SENSOR_NAME_GET, s->id,
 					    NULL, s->name, SCMI_MAX_STR_SIZE);
@@ -683,7 +681,7 @@ iter_sens_descr_process_response(const struct scmi_protocol_handle *ph,
 	}
 
 	if (s->num_axis > 0)
-		ret = scmi_sensor_axis_description(ph, s, si->version);
+		ret = scmi_sensor_axis_description(ph, s);
 
 	st->priv = ((u8 *)sdesc + dsize);
 
@@ -1148,21 +1146,15 @@ static const struct scmi_protocol_events sensor_protocol_events = {
 
 static int scmi_sensors_protocol_init(const struct scmi_protocol_handle *ph)
 {
-	u32 version;
 	int ret;
 	struct sensors_info *sinfo;
 
-	ret = ph->xops->version_get(ph, &version);
-	if (ret)
-		return ret;
-
 	dev_dbg(ph->dev, "Sensor Version %d.%d\n",
-		PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+		PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
 
 	sinfo = devm_kzalloc(ph->dev, sizeof(*sinfo), GFP_KERNEL);
 	if (!sinfo)
 		return -ENOMEM;
-	sinfo->version = version;
 
 	ret = scmi_sensor_attributes_get(ph, sinfo);
 	if (ret)
@@ -1176,7 +1168,7 @@ static int scmi_sensors_protocol_init(const struct scmi_protocol_handle *ph)
 	if (ret)
 		return ret;
 
-	return ph->set_priv(ph, sinfo, version);
+	return ph->set_priv(ph, sinfo);
 }
 
 static const struct scmi_protocol scmi_sensors = {
diff --git a/drivers/firmware/arm_scmi/system.c b/drivers/firmware/arm_scmi/system.c
index ec3d355d1772..0f51c36f6a9d 100644
--- a/drivers/firmware/arm_scmi/system.c
+++ b/drivers/firmware/arm_scmi/system.c
@@ -34,7 +34,6 @@ struct scmi_system_power_state_notifier_payld {
 };
 
 struct scmi_system_info {
-	u32 version;
 	bool graceful_timeout_supported;
 	bool power_state_notify_cmd;
 };
@@ -141,29 +140,22 @@ static const struct scmi_protocol_events system_protocol_events = {
 
 static int scmi_system_protocol_init(const struct scmi_protocol_handle *ph)
 {
-	int ret;
-	u32 version;
 	struct scmi_system_info *pinfo;
 
-	ret = ph->xops->version_get(ph, &version);
-	if (ret)
-		return ret;
-
 	dev_dbg(ph->dev, "System Power Version %d.%d\n",
-		PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+		PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
 
 	pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
 	if (!pinfo)
 		return -ENOMEM;
 
-	pinfo->version = version;
-	if (PROTOCOL_REV_MAJOR(pinfo->version) >= 0x2)
+	if (PROTOCOL_REV_MAJOR(ph->version) >= 0x2)
 		pinfo->graceful_timeout_supported = true;
 
 	if (!ph->hops->protocol_msg_check(ph, SYSTEM_POWER_STATE_NOTIFY, NULL))
 		pinfo->power_state_notify_cmd = true;
 
-	return ph->set_priv(ph, pinfo, version);
+	return ph->set_priv(ph, pinfo);
 }
 
 static const struct scmi_protocol scmi_system = {
diff --git a/drivers/firmware/arm_scmi/vendors/imx/imx-sm-bbm.c b/drivers/firmware/arm_scmi/vendors/imx/imx-sm-bbm.c
index aa176c1a5eef..33f9ebf6092b 100644
--- a/drivers/firmware/arm_scmi/vendors/imx/imx-sm-bbm.c
+++ b/drivers/firmware/arm_scmi/vendors/imx/imx-sm-bbm.c
@@ -48,7 +48,6 @@ enum scmi_imx_bbm_protocol_cmd {
 #define SCMI_IMX_BBM_EVENT_RTC_MASK		GENMASK(31, 24)
 
 struct scmi_imx_bbm_info {
-	u32 version;
 	int nr_rtc;
 	int nr_gpr;
 };
@@ -345,16 +344,11 @@ static const struct scmi_imx_bbm_proto_ops scmi_imx_bbm_proto_ops = {
 
 static int scmi_imx_bbm_protocol_init(const struct scmi_protocol_handle *ph)
 {
-	u32 version;
 	int ret;
 	struct scmi_imx_bbm_info *binfo;
 
-	ret = ph->xops->version_get(ph, &version);
-	if (ret)
-		return ret;
-
 	dev_info(ph->dev, "NXP SM BBM Version %d.%d\n",
-		 PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+		 PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
 
 	binfo = devm_kzalloc(ph->dev, sizeof(*binfo), GFP_KERNEL);
 	if (!binfo)
@@ -364,7 +358,7 @@ static int scmi_imx_bbm_protocol_init(const struct scmi_protocol_handle *ph)
 	if (ret)
 		return ret;
 
-	return ph->set_priv(ph, binfo, version);
+	return ph->set_priv(ph, binfo);
 }
 
 static const struct scmi_protocol scmi_imx_bbm = {
diff --git a/drivers/firmware/arm_scmi/vendors/imx/imx-sm-cpu.c b/drivers/firmware/arm_scmi/vendors/imx/imx-sm-cpu.c
index 66f47f5371e5..753274af11d2 100644
--- a/drivers/firmware/arm_scmi/vendors/imx/imx-sm-cpu.c
+++ b/drivers/firmware/arm_scmi/vendors/imx/imx-sm-cpu.c
@@ -233,15 +233,10 @@ static int scmi_imx_cpu_attributes_get(const struct scmi_protocol_handle *ph,
 static int scmi_imx_cpu_protocol_init(const struct scmi_protocol_handle *ph)
 {
 	struct scmi_imx_cpu_info *info;
-	u32 version;
 	int ret, i;
 
-	ret = ph->xops->version_get(ph, &version);
-	if (ret)
-		return ret;
-
 	dev_info(ph->dev, "NXP SM CPU Protocol Version %d.%d\n",
-		 PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+		 PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
 
 	info = devm_kzalloc(ph->dev, sizeof(*info), GFP_KERNEL);
 	if (!info)
@@ -257,7 +252,7 @@ static int scmi_imx_cpu_protocol_init(const struct scmi_protocol_handle *ph)
 			return ret;
 	}
 
-	return ph->set_priv(ph, info, version);
+	return ph->set_priv(ph, info);
 }
 
 static const struct scmi_protocol scmi_imx_cpu = {
diff --git a/drivers/firmware/arm_scmi/vendors/imx/imx-sm-lmm.c b/drivers/firmware/arm_scmi/vendors/imx/imx-sm-lmm.c
index b519c67fe920..c56ae247774d 100644
--- a/drivers/firmware/arm_scmi/vendors/imx/imx-sm-lmm.c
+++ b/drivers/firmware/arm_scmi/vendors/imx/imx-sm-lmm.c
@@ -226,15 +226,10 @@ static int scmi_imx_lmm_protocol_attributes_get(const struct scmi_protocol_handl
 static int scmi_imx_lmm_protocol_init(const struct scmi_protocol_handle *ph)
 {
 	struct scmi_imx_lmm_priv *info;
-	u32 version;
 	int ret;
 
-	ret = ph->xops->version_get(ph, &version);
-	if (ret)
-		return ret;
-
 	dev_info(ph->dev, "NXP SM LMM Version %d.%d\n",
-		 PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+		 PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
 
 	info = devm_kzalloc(ph->dev, sizeof(*info), GFP_KERNEL);
 	if (!info)
@@ -244,7 +239,7 @@ static int scmi_imx_lmm_protocol_init(const struct scmi_protocol_handle *ph)
 	if (ret)
 		return ret;
 
-	return ph->set_priv(ph, info, version);
+	return ph->set_priv(ph, info);
 }
 
 static const struct scmi_protocol scmi_imx_lmm = {
diff --git a/drivers/firmware/arm_scmi/vendors/imx/imx-sm-misc.c b/drivers/firmware/arm_scmi/vendors/imx/imx-sm-misc.c
index 700a3f24f4ef..73d80f221b9d 100644
--- a/drivers/firmware/arm_scmi/vendors/imx/imx-sm-misc.c
+++ b/drivers/firmware/arm_scmi/vendors/imx/imx-sm-misc.c
@@ -32,7 +32,6 @@ enum scmi_imx_misc_protocol_cmd {
 };
 
 struct scmi_imx_misc_info {
-	u32 version;
 	u32 nr_dev_ctrl;
 	u32 nr_brd_ctrl;
 	u32 nr_reason;
@@ -380,15 +379,10 @@ static const struct scmi_imx_misc_proto_ops scmi_imx_misc_proto_ops = {
 static int scmi_imx_misc_protocol_init(const struct scmi_protocol_handle *ph)
 {
 	struct scmi_imx_misc_info *minfo;
-	u32 version;
 	int ret;
 
-	ret = ph->xops->version_get(ph, &version);
-	if (ret)
-		return ret;
-
 	dev_info(ph->dev, "NXP SM MISC Version %d.%d\n",
-		 PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+		 PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
 
 	minfo = devm_kzalloc(ph->dev, sizeof(*minfo), GFP_KERNEL);
 	if (!minfo)
@@ -410,7 +404,7 @@ static int scmi_imx_misc_protocol_init(const struct scmi_protocol_handle *ph)
 	if (ret && ret != -EOPNOTSUPP)
 		return ret;
 
-	return ph->set_priv(ph, minfo, version);
+	return ph->set_priv(ph, minfo);
 }
 
 static const struct scmi_protocol scmi_imx_misc = {
diff --git a/drivers/firmware/arm_scmi/voltage.c b/drivers/firmware/arm_scmi/voltage.c
index 17127880e10a..b9391c1ee8a0 100644
--- a/drivers/firmware/arm_scmi/voltage.c
+++ b/drivers/firmware/arm_scmi/voltage.c
@@ -66,7 +66,6 @@ struct scmi_resp_voltage_level_set_complete {
 };
 
 struct voltage_info {
-	unsigned int version;
 	unsigned int num_domains;
 	struct scmi_voltage_info *domains;
 };
@@ -243,7 +242,7 @@ static int scmi_voltage_descriptors_get(const struct scmi_protocol_handle *ph,
 		 * If supported overwrite short name with the extended one;
 		 * on error just carry on and use already provided short name.
 		 */
-		if (PROTOCOL_REV_MAJOR(vinfo->version) >= 0x2) {
+		if (PROTOCOL_REV_MAJOR(ph->version) >= 0x2) {
 			if (SUPPORTS_EXTENDED_NAMES(attributes))
 				ph->hops->extended_name_get(ph,
 							VOLTAGE_DOMAIN_NAME_GET,
@@ -405,20 +404,14 @@ static const struct scmi_voltage_proto_ops voltage_proto_ops = {
 static int scmi_voltage_protocol_init(const struct scmi_protocol_handle *ph)
 {
 	int ret;
-	u32 version;
 	struct voltage_info *vinfo;
 
-	ret = ph->xops->version_get(ph, &version);
-	if (ret)
-		return ret;
-
 	dev_dbg(ph->dev, "Voltage Version %d.%d\n",
-		PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+		PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
 
 	vinfo = devm_kzalloc(ph->dev, sizeof(*vinfo), GFP_KERNEL);
 	if (!vinfo)
 		return -ENOMEM;
-	vinfo->version = version;
 
 	ret = scmi_protocol_attributes_get(ph, vinfo);
 	if (ret)
@@ -437,7 +430,7 @@ static int scmi_voltage_protocol_init(const struct scmi_protocol_handle *ph)
 		dev_warn(ph->dev, "No Voltage domains found.\n");
 	}
 
-	return ph->set_priv(ph, vinfo, version);
+	return ph->set_priv(ph, vinfo);
 }
 
 static const struct scmi_protocol scmi_voltage = {
-- 
2.52.0



From sgsu.park at samsung.com  Sat Dec 27 09:38:59 2025
From: sgsu.park at samsung.com (Seongsu Park)
Date: Sun, 28 Dec 2025 02:38:59 +0900
Subject: [PATCH] arm64: Fix PIE_E1 mapping for _PAGE_READONLY_EXEC
In-Reply-To: <GV1PR08MB105210D9BD328C2446CA8C551FBB1A@GV1PR08MB10521.eurprd08.prod.outlook.com>
References: <CGME20251227070633epcas1p3a8f7c19c9f5114a46765073fa16ba449@epcas1p3.samsung.com>
	<20251227070625.217349-1-sgsu.park@samsung.com>
	<GV1PR08MB105210D9BD328C2446CA8C551FBB1A@GV1PR08MB10521.eurprd08.prod.outlook.com>
Message-ID: <000001dc7757$af3294a0$0d97bde0$@samsung.com>

Hi Yeoreum,

> NIT: This looks like it allows executing user code from the kernel.
> Why is this necessary?

Good Catch. You're absolutely right.
I misunderstood how PIE separates EL0/EL1 permissions.
The kernel should only have read access to the executing user code pages.
The original PIE_EL1 mapping to PIE_R is correct.
My patch would be a security regression. Please disregard.

Thanks for the careful review,
Seongsu Park.



From jic23 at kernel.org  Sat Dec 27 09:43:55 2025
From: jic23 at kernel.org (Jonathan Cameron)
Date: Sat, 27 Dec 2025 17:43:55 +0000
Subject: [PATCH 1/3] iio: adc: aspeed: Simplify probe() with local 'dev'
 and 'np'
In-Reply-To: <20251221142602.47368-4-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251221142602.47368-4-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <20251227174355.0677f93f@jic23-huawei>

On Sun, 21 Dec 2025 15:26:03 +0100
Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com> wrote:

> Simplify the probe function by using local 'dev' and 'np' variables
> instead of full pointer dereferences.  This makes several lines shorter,
> which allows to avoid wrapping making code more readable.  While
> touching the return line, simplify by avoiding unnecessary 'ret'
> assignment.
> 
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
All 3 patches applied to the togreg branch of iio.git.
Initially pushed out as testing to let the bots have a play.

Jonathan


From festevam at gmail.com  Sat Dec 27 10:07:21 2025
From: festevam at gmail.com (Fabio Estevam)
Date: Sat, 27 Dec 2025 15:07:21 -0300
Subject: [PATCH] ARM: imx_v4_v5_defconfig: update for v6.19-rc1
In-Reply-To: <20251227-armv45defconfig-fix-v1-1-d7b64abda9fe@solid-run.com>
References: <20251227-armv45defconfig-fix-v1-1-d7b64abda9fe@solid-run.com>
Message-ID: <CAOMZO5C=TcDSQE6Snuzs4Ry-2qP36qDZmoDCL7qJ+UHDUgkVYA@mail.gmail.com>

On Sat, Dec 27, 2025 at 10:24?AM Josua Mayer <josua at solid-run.com> wrote:
>
> The i.MX5/6 defconfig has gone out of sync with some dead options, some
> removed and some missing.

You mention "i.MX5/6 defconfig" here, but this patch touches
imx_v4_v5_defconfig.

i.MX5/6 is covered by imx_v6_v7_defconfig.


From nsc at kernel.org  Sat Dec 27 08:34:36 2025
From: nsc at kernel.org (Nicolas Schier)
Date: Sat, 27 Dec 2025 17:34:36 +0100
Subject: [PATCH v8 5/6] scripts/make_fit: Support a few more parallel
 compressors
In-Reply-To: <20251227142200.2241198-6-sjg@chromium.org>
References: <20251227142200.2241198-1-sjg@chromium.org>
 <20251227142200.2241198-6-sjg@chromium.org>
Message-ID: <aVAKnJ4p0jhpO-vc@levanger>

On Sat, Dec 27, 2025 at 07:21:49AM -0700, Simon Glass wrote:
> Add support for pbzip2, xz and plzip which can compress in parallel.
> This speeds up the ramdisk compression.
> 
> Signed-off-by: Simon Glass <sjg at chromium.org>
> ---
> 
> (no changes since v7)
> 
> Changes in v7:
> - Mention xz as well, in the commit message
> 
>  scripts/make_fit.py | 12 +++++++++---
>  1 file changed, 9 insertions(+), 3 deletions(-)
> 

Reviewed-by: Nicolas Schier <nsc at kernel.org>

-- 
Nicolas


From nsc at kernel.org  Sat Dec 27 08:36:23 2025
From: nsc at kernel.org (Nicolas Schier)
Date: Sat, 27 Dec 2025 17:36:23 +0100
Subject: [PATCH v8 4/6] kbuild: Support a MAKE_FIT_FLAGS environment
 variable
In-Reply-To: <20251227142200.2241198-5-sjg@chromium.org>
References: <20251227142200.2241198-1-sjg@chromium.org>
 <20251227142200.2241198-5-sjg@chromium.org>
Message-ID: <aVALB4hBkHlTelXA@levanger>

On Sat, Dec 27, 2025 at 07:21:48AM -0700, Simon Glass wrote:
> In some cases it is useful to be able to pass additional flags to the
> make_fit.py script. For example, since ramdisks are typically large,
> passing -E to use external data can be helpful.
> 
> Add a new MAKE_FIT_FLAGS variable for this.
> 
> Signed-off-by: Simon Glass <sjg at chromium.org>
> ---
> 
> (no changes since v7)
> 
> Changes in v7:
> - Add a new patch with the MAKE_FIT_FLAGS change
> 
>  scripts/Makefile.lib | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 

Reviewed-by: Nicolas Schier <nsc at kernel.org>

-- 
Nicolas


From leon at kernel.org  Sat Dec 27 12:07:06 2025
From: leon at kernel.org (Leon Romanovsky)
Date: Sat, 27 Dec 2025 22:07:06 +0200
Subject: [PATCH v2 4/8] dma-mapping: Separate DMA sync issuing and
 completion waiting
In-Reply-To: <20251226225254.46197-5-21cnbao@gmail.com>
References: <20251226225254.46197-1-21cnbao@gmail.com>
 <20251226225254.46197-5-21cnbao@gmail.com>
Message-ID: <20251227200706.GN11869@unreal>

On Sat, Dec 27, 2025 at 11:52:44AM +1300, Barry Song wrote:
> From: Barry Song <baohua at kernel.org>
> 
> Currently, arch_sync_dma_for_cpu and arch_sync_dma_for_device
> always wait for the completion of each DMA buffer. That is,
> issuing the DMA sync and waiting for completion is done in a
> single API call.
> 
> For scatter-gather lists with multiple entries, this means
> issuing and waiting is repeated for each entry, which can hurt
> performance. Architectures like ARM64 may be able to issue all
> DMA sync operations for all entries first and then wait for
> completion together.
> 
> To address this, arch_sync_dma_for_* now issues DMA operations in
> batch, followed by a flush. On ARM64, the flush is implemented
> using a dsb instruction within arch_sync_dma_flush().
> 
> For now, add arch_sync_dma_flush() after each
> arch_sync_dma_for_*() call. arch_sync_dma_flush() is defined as a
> no-op on all architectures except arm64, so this patch does not
> change existing behavior. Subsequent patches will introduce true
> batching for SG DMA buffers.
> 
> Cc: Leon Romanovsky <leon at kernel.org>
> Cc: Catalin Marinas <catalin.marinas at arm.com>
> Cc: Will Deacon <will at kernel.org>
> Cc: Marek Szyprowski <m.szyprowski at samsung.com>
> Cc: Robin Murphy <robin.murphy at arm.com>
> Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
> Cc: Ard Biesheuvel <ardb at kernel.org>
> Cc: Marc Zyngier <maz at kernel.org>
> Cc: Anshuman Khandual <anshuman.khandual at arm.com>
> Cc: Ryan Roberts <ryan.roberts at arm.com>
> Cc: Suren Baghdasaryan <surenb at google.com>
> Cc: Joerg Roedel <joro at 8bytes.org>
> Cc: Juergen Gross <jgross at suse.com>
> Cc: Stefano Stabellini <sstabellini at kernel.org>
> Cc: Oleksandr Tyshchenko <oleksandr_tyshchenko at epam.com>
> Cc: Tangquan Zheng <zhengtangquan at oppo.com>
> Signed-off-by: Barry Song <baohua at kernel.org>
> ---
>  arch/arm64/include/asm/cache.h |  6 ++++++
>  arch/arm64/mm/dma-mapping.c    |  4 ++--
>  drivers/iommu/dma-iommu.c      | 37 +++++++++++++++++++++++++---------
>  drivers/xen/swiotlb-xen.c      | 24 ++++++++++++++--------
>  include/linux/dma-map-ops.h    |  6 ++++++
>  kernel/dma/direct.c            |  8 ++++++--
>  kernel/dma/direct.h            |  9 +++++++--
>  kernel/dma/swiotlb.c           |  4 +++-
>  8 files changed, 73 insertions(+), 25 deletions(-)

<...>

> +#ifndef arch_sync_dma_flush
> +static inline void arch_sync_dma_flush(void)
> +{
> +}
> +#endif

Over the weekend I realized a useful advantage of the ARCH_HAVE_* config
options: they make it straightforward to inspect the entire DMA path simply
by looking at the .config.

Thanks,
Reviewed-by: Leon Romanovsky <leonro at nvidia.com>


From leon at kernel.org  Sat Dec 27 12:09:33 2025
From: leon at kernel.org (Leon Romanovsky)
Date: Sat, 27 Dec 2025 22:09:33 +0200
Subject: [PATCH v2 5/8] dma-mapping: Support batch mode for
 dma_direct_sync_sg_for_*
In-Reply-To: <20251226225254.46197-6-21cnbao@gmail.com>
References: <20251226225254.46197-1-21cnbao@gmail.com>
 <20251226225254.46197-6-21cnbao@gmail.com>
Message-ID: <20251227200933.GO11869@unreal>

On Sat, Dec 27, 2025 at 11:52:45AM +1300, Barry Song wrote:
> From: Barry Song <baohua at kernel.org>
> 
> Instead of performing a flush per SG entry, issue all cache
> operations first and then flush once. This ultimately benefits
> __dma_sync_sg_for_cpu() and __dma_sync_sg_for_device().
> 
> Cc: Leon Romanovsky <leon at kernel.org>
> Cc: Catalin Marinas <catalin.marinas at arm.com>
> Cc: Will Deacon <will at kernel.org>
> Cc: Marek Szyprowski <m.szyprowski at samsung.com>
> Cc: Robin Murphy <robin.murphy at arm.com>
> Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
> Cc: Ard Biesheuvel <ardb at kernel.org>
> Cc: Marc Zyngier <maz at kernel.org>
> Cc: Anshuman Khandual <anshuman.khandual at arm.com>
> Cc: Ryan Roberts <ryan.roberts at arm.com>
> Cc: Suren Baghdasaryan <surenb at google.com>
> Cc: Tangquan Zheng <zhengtangquan at oppo.com>
> Signed-off-by: Barry Song <baohua at kernel.org>
> ---
>  kernel/dma/direct.c | 14 +++++++-------
>  1 file changed, 7 insertions(+), 7 deletions(-)

<...>

> -		if (!dev_is_dma_coherent(dev)) {
> +		if (!dev_is_dma_coherent(dev))
>  			arch_sync_dma_for_device(paddr, sg->length,
>  					dir);
> -			arch_sync_dma_flush();
> -		}
>  	}
> +	if (!dev_is_dma_coherent(dev))
> +		arch_sync_dma_flush();

This patch should be squashed into the previous one. You introduced
arch_sync_dma_flush() there, and now you are placing it elsewhere.

Thanks


From leon at kernel.org  Sat Dec 27 12:14:06 2025
From: leon at kernel.org (Leon Romanovsky)
Date: Sat, 27 Dec 2025 22:14:06 +0200
Subject: [PATCH v2 6/8] dma-mapping: Support batch mode for
 dma_direct_{map,unmap}_sg
In-Reply-To: <20251226225254.46197-7-21cnbao@gmail.com>
References: <20251226225254.46197-1-21cnbao@gmail.com>
 <20251226225254.46197-7-21cnbao@gmail.com>
Message-ID: <20251227201406.GP11869@unreal>

On Sat, Dec 27, 2025 at 11:52:46AM +1300, Barry Song wrote:
> From: Barry Song <baohua at kernel.org>
> 
> Leon suggested extending a flush argument to

Let's move this sentence out of the commit message and place it in the
changelog instead.

> dma_direct_unmap_phys(), dma_direct_map_phys(), and
> dma_direct_sync_single_for_cpu(). For single-buffer cases, this
> would use flush=true, while for SG cases flush=false would be
> used, followed by a single flush after all cache operations are
> issued in dma_direct_{map,unmap}_sg().
> 
> This ultimately benefits dma_map_sg() and dma_unmap_sg().
> 
> Cc: Leon Romanovsky <leon at kernel.org>
> Cc: Catalin Marinas <catalin.marinas at arm.com>
> Cc: Will Deacon <will at kernel.org>
> Cc: Marek Szyprowski <m.szyprowski at samsung.com>
> Cc: Robin Murphy <robin.murphy at arm.com>
> Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
> Cc: Ard Biesheuvel <ardb at kernel.org>
> Cc: Marc Zyngier <maz at kernel.org>
> Cc: Anshuman Khandual <anshuman.khandual at arm.com>
> Cc: Ryan Roberts <ryan.roberts at arm.com>
> Cc: Suren Baghdasaryan <surenb at google.com>
> Cc: Tangquan Zheng <zhengtangquan at oppo.com>
> Signed-off-by: Barry Song <baohua at kernel.org>
> ---
>  kernel/dma/direct.c  | 17 +++++++++++++----
>  kernel/dma/direct.h  | 16 ++++++++++------
>  kernel/dma/mapping.c |  6 +++---
>  3 files changed, 26 insertions(+), 13 deletions(-)

Thanks,
Reviewed-by: Leon Romanovsky <leon at kernel.org>


From leon at kernel.org  Sat Dec 27 12:16:42 2025
From: leon at kernel.org (Leon Romanovsky)
Date: Sat, 27 Dec 2025 22:16:42 +0200
Subject: [PATCH RFC v2 8/8] dma-iommu: Support DMA sync batch mode for
 iommu_dma_sync_sg_for_{cpu, device}
In-Reply-To: <20251226225254.46197-9-21cnbao@gmail.com>
References: <20251226225254.46197-1-21cnbao@gmail.com>
 <20251226225254.46197-9-21cnbao@gmail.com>
Message-ID: <20251227201642.GQ11869@unreal>

On Sat, Dec 27, 2025 at 11:52:48AM +1300, Barry Song wrote:
> From: Barry Song <baohua at kernel.org>
> 
> Apply batched DMA synchronization to iommu_dma_sync_sg_for_cpu() and
> iommu_dma_sync_sg_for_device(). For all buffers in an SG list, only
> a single flush operation is needed.
> 
> I do not have the hardware to test this, so the patch is marked as
> RFC. I would greatly appreciate any testing feedback.
> 
> Cc: Leon Romanovsky <leon at kernel.org>
> Cc: Marek Szyprowski <m.szyprowski at samsung.com>
> Cc: Catalin Marinas <catalin.marinas at arm.com>
> Cc: Will Deacon <will at kernel.org>
> Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
> Cc: Ard Biesheuvel <ardb at kernel.org>
> Cc: Marc Zyngier <maz at kernel.org>
> Cc: Anshuman Khandual <anshuman.khandual at arm.com>
> Cc: Ryan Roberts <ryan.roberts at arm.com>
> Cc: Suren Baghdasaryan <surenb at google.com>
> Cc: Robin Murphy <robin.murphy at arm.com>
> Cc: Joerg Roedel <joro at 8bytes.org>
> Cc: Tangquan Zheng <zhengtangquan at oppo.com>
> Signed-off-by: Barry Song <baohua at kernel.org>
> ---
>  drivers/iommu/dma-iommu.c | 15 +++++++--------
>  1 file changed, 7 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
> index ffa940bdbbaf..b68dbfcb7846 100644
> --- a/drivers/iommu/dma-iommu.c
> +++ b/drivers/iommu/dma-iommu.c
> @@ -1131,10 +1131,9 @@ void iommu_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl,
>  			iommu_dma_sync_single_for_cpu(dev, sg_dma_address(sg),
>  						      sg->length, dir);
>  	} else if (!dev_is_dma_coherent(dev)) {
> -		for_each_sg(sgl, sg, nelems, i) {
> +		for_each_sg(sgl, sg, nelems, i)
>  			arch_sync_dma_for_cpu(sg_phys(sg), sg->length, dir);
> -			arch_sync_dma_flush();
> -		}
> +		arch_sync_dma_flush();

This and previous patches should be squashed into the one which
introduced arch_sync_dma_flush().

Thanks


From 21cnbao at gmail.com  Sat Dec 27 12:52:05 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Sun, 28 Dec 2025 09:52:05 +1300
Subject: [PATCH v2 5/8] dma-mapping: Support batch mode for dma_direct_sync_sg_for_*
In-Reply-To: <20251227200933.GO11869@unreal>
References: <20251226225254.46197-1-21cnbao@gmail.com> <20251226225254.46197-6-21cnbao@gmail.com>
 <20251227200933.GO11869@unreal>
Message-ID: <CAGsJ_4yA83-K7PXiEtyidzF_j6qqKkt92z485KBS9+zGe_rjnw@mail.gmail.com>

On Sun, Dec 28, 2025 at 9:09?AM Leon Romanovsky <leon at kernel.org> wrote:
>
> On Sat, Dec 27, 2025 at 11:52:45AM +1300, Barry Song wrote:
> > From: Barry Song <baohua at kernel.org>
> >
> > Instead of performing a flush per SG entry, issue all cache
> > operations first and then flush once. This ultimately benefits
> > __dma_sync_sg_for_cpu() and __dma_sync_sg_for_device().
> >
> > Cc: Leon Romanovsky <leon at kernel.org>
> > Cc: Catalin Marinas <catalin.marinas at arm.com>
> > Cc: Will Deacon <will at kernel.org>
> > Cc: Marek Szyprowski <m.szyprowski at samsung.com>
> > Cc: Robin Murphy <robin.murphy at arm.com>
> > Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
> > Cc: Ard Biesheuvel <ardb at kernel.org>
> > Cc: Marc Zyngier <maz at kernel.org>
> > Cc: Anshuman Khandual <anshuman.khandual at arm.com>
> > Cc: Ryan Roberts <ryan.roberts at arm.com>
> > Cc: Suren Baghdasaryan <surenb at google.com>
> > Cc: Tangquan Zheng <zhengtangquan at oppo.com>
> > Signed-off-by: Barry Song <baohua at kernel.org>
> > ---
> >  kernel/dma/direct.c | 14 +++++++-------
> >  1 file changed, 7 insertions(+), 7 deletions(-)
>
> <...>
>
> > -             if (!dev_is_dma_coherent(dev)) {
> > +             if (!dev_is_dma_coherent(dev))
> >                       arch_sync_dma_for_device(paddr, sg->length,
> >                                       dir);
> > -                     arch_sync_dma_flush();
> > -             }
> >       }
> > +     if (!dev_is_dma_coherent(dev))
> > +             arch_sync_dma_flush();
>
> This patch should be squashed into the previous one. You introduced
> arch_sync_dma_flush() there, and now you are placing it elsewhere.

Hi Leon,

The previous patch replaces all arch_sync_dma_for_* calls with
arch_sync_dma_for_* plus arch_sync_dma_flush(), without any
functional change. The subsequent patches then implement the
actual batching. I feel this is a better approach for reviewing
each change independently. Otherwise, the previous patch would
be too large.

Thanks
Barry


From 21cnbao at gmail.com  Sat Dec 27 12:59:18 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Sun, 28 Dec 2025 09:59:18 +1300
Subject: [PATCH RFC v2 8/8] dma-iommu: Support DMA sync batch mode for
 iommu_dma_sync_sg_for_{cpu, device}
In-Reply-To: <20251227201642.GQ11869@unreal>
References: <20251226225254.46197-1-21cnbao@gmail.com> <20251226225254.46197-9-21cnbao@gmail.com>
 <20251227201642.GQ11869@unreal>
Message-ID: <CAGsJ_4xssfB7hNOWLDianQfx+9wC2e4qZKtRBUzEZ-v97Sa63Q@mail.gmail.com>

On Sun, Dec 28, 2025 at 9:16?AM Leon Romanovsky <leon at kernel.org> wrote:
>
> On Sat, Dec 27, 2025 at 11:52:48AM +1300, Barry Song wrote:
> > From: Barry Song <baohua at kernel.org>
> >
> > Apply batched DMA synchronization to iommu_dma_sync_sg_for_cpu() and
> > iommu_dma_sync_sg_for_device(). For all buffers in an SG list, only
> > a single flush operation is needed.
> >
> > I do not have the hardware to test this, so the patch is marked as
> > RFC. I would greatly appreciate any testing feedback.
> >
> > Cc: Leon Romanovsky <leon at kernel.org>
> > Cc: Marek Szyprowski <m.szyprowski at samsung.com>
> > Cc: Catalin Marinas <catalin.marinas at arm.com>
> > Cc: Will Deacon <will at kernel.org>
> > Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
> > Cc: Ard Biesheuvel <ardb at kernel.org>
> > Cc: Marc Zyngier <maz at kernel.org>
> > Cc: Anshuman Khandual <anshuman.khandual at arm.com>
> > Cc: Ryan Roberts <ryan.roberts at arm.com>
> > Cc: Suren Baghdasaryan <surenb at google.com>
> > Cc: Robin Murphy <robin.murphy at arm.com>
> > Cc: Joerg Roedel <joro at 8bytes.org>
> > Cc: Tangquan Zheng <zhengtangquan at oppo.com>
> > Signed-off-by: Barry Song <baohua at kernel.org>
> > ---
> >  drivers/iommu/dma-iommu.c | 15 +++++++--------
> >  1 file changed, 7 insertions(+), 8 deletions(-)
> >
> > diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
> > index ffa940bdbbaf..b68dbfcb7846 100644
> > --- a/drivers/iommu/dma-iommu.c
> > +++ b/drivers/iommu/dma-iommu.c
> > @@ -1131,10 +1131,9 @@ void iommu_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl,
> >                       iommu_dma_sync_single_for_cpu(dev, sg_dma_address(sg),
> >                                                     sg->length, dir);
> >       } else if (!dev_is_dma_coherent(dev)) {
> > -             for_each_sg(sgl, sg, nelems, i) {
> > +             for_each_sg(sgl, sg, nelems, i)
> >                       arch_sync_dma_for_cpu(sg_phys(sg), sg->length, dir);
> > -                     arch_sync_dma_flush();
> > -             }
> > +             arch_sync_dma_flush();
>
> This and previous patches should be squashed into the one which
> introduced arch_sync_dma_flush().

Hi Leon,

The series is structured to first introduce no functional change by
replacing all arch_sync_dma_for_* calls with arch_sync_dma_for_* plus
arch_sync_dma_flush(). Subsequent patches then add batching for
different scenarios as separate changes.

Another issue is that I was unable to find a board that both runs
mainline and exercises the IOMMU paths affected by these changes.
As a result, patches 7 and 8 are marked as RFC, while the other
patches have been tested on a real board running mainline + changes.

Thanks
Barry


From andreas at kemnade.info  Sat Dec 27 13:38:15 2025
From: andreas at kemnade.info (Andreas Kemnade)
Date: Sat, 27 Dec 2025 22:38:15 +0100
Subject: [PATCH 1/3] power: supply: add battery driver for netronix ec
In-Reply-To: <20251227-kobo-aura-battery-v1-1-328a90ef5122@jm0.eu>
References: <20251227-kobo-aura-battery-v1-0-328a90ef5122@jm0.eu>
	<20251227-kobo-aura-battery-v1-1-328a90ef5122@jm0.eu>
Message-ID: <20251227223815.17dea51d@kemnade.info>

On Sat, 27 Dec 2025 17:28:13 +0100
Josua Mayer <josua.mayer at jm0.eu> wrote:

> Implement a simple battery driver for monitoring voltage with the
> netronix embedded controller found in certain ebook readers.
> 
> Signed-off-by: Josua Mayer <josua.mayer at jm0.eu>

This also produces a value somehow depending on battery voltage
on the Tolino vision.
[...]
> diff --git a/drivers/mfd/ntxec.c b/drivers/mfd/ntxec.c
> index 08c68de0f01bc..d5059b8862aa8 100644
> --- a/drivers/mfd/ntxec.c
> +++ b/drivers/mfd/ntxec.c
> @@ -139,6 +139,7 @@ static const struct regmap_config regmap_config = {
> static const struct mfd_cell ntxec_subdev[] = {
> 	{ .name = "ntxec-rtc" },
> 	{ .name = "ntxec-pwm" },
> +	{ .name = "ntxec-battery" },
> };
> 
> static const struct mfd_cell ntxec_subdev_pwm[] = {

I think that should be a separate patch for mfd.

[...]
> +	switch (psp) {
> +		case POWER_SUPPLY_PROP_VOLTAGE_NOW:
> +			ret = regmap_read(priv->ec->regmap, NTXEC_REG_READ_BATTERY, &value);
> +			if (ret < 0)
> +				return ret;
> +
> +			/* ec value to microvolt conversion:
> +			 * vendor kernel source suggests linear behaviour from 3V to 4.2V
> +			 * with readings 767 to 1023; each increment represents 4687,5uV.
> +			 * adjust 3V boundary slightly to report exactly 4.2V when full.
> +			 */
> +			val->intval = 2999872 + (value - 767) * 4688;
> +			break;
I find this code both in some kobo 2.6.35.3 code and on the tolino 3.0.35:

        const unsigned short battGasgauge[] = {
        //      3.0V, 3.1V, 3.2V, 3.3V, 3.4V, 3.5V, 3.6V, 3.7V, 3.8V, 3.9V, 4.0V, 4.1V, 4.2V,
//               743,  767,  791,  812,  835,  860,  885,  909,  935,  960,  985, 1010, 1023,
                 767,  791,  812,  833,  852,  877,  903,  928,  950,  979,  993, 1019, 1023,
        };

This does not look very linear... We have offsets
24
21
21
19
25
26
25
22
29
14
26
4

Do you have something looking more sane?
No idea what should produce such flaky offsets besides of
improper measurements. At least that should be commented.
And why do these tables exist at all?

Hmm, the more weird thing is that these voltages are translated linearly
inot capacity. So maybe they are just adjusted to have the capacity look
more sane. That would explain the 4 units step between 4.1V and 4.2V.
Having linear adc result -> voltage and nonlinear voltage-> capcity would
make more sense.

looking at such code snippet like this:
case POWER_SUPPLY_PROP_CAPACITY:
                if (POWER_SUPPLY_STATUS_NOT_CHARGING == g_ntx_bat_di->battery_status) {
                        val->intval = 100;
                        return 0;
                }
                value = ntx_up_battery_vol();
[...]
                                val->intval  = 100 - ((4100000 - value)/7000);


I am wondering whether we should just return capacity that way without
calculating voltage...

Regards,
Andreas


From 21cnbao at gmail.com  Sat Dec 27 13:45:13 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Sun, 28 Dec 2025 10:45:13 +1300
Subject: [PATCH v2 4/8] dma-mapping: Separate DMA sync issuing and
 completion waiting
In-Reply-To: <20251227200706.GN11869@unreal>
References: <20251226225254.46197-1-21cnbao@gmail.com> <20251226225254.46197-5-21cnbao@gmail.com>
 <20251227200706.GN11869@unreal>
Message-ID: <CAGsJ_4zyascnpQ1cB-BMO9PDeeRZTBAh8Z-j-ip=RcxApa4zSg@mail.gmail.com>

On Sun, Dec 28, 2025 at 9:07?AM Leon Romanovsky <leon at kernel.org> wrote:
>
> On Sat, Dec 27, 2025 at 11:52:44AM +1300, Barry Song wrote:
> > From: Barry Song <baohua at kernel.org>
> >
> > Currently, arch_sync_dma_for_cpu and arch_sync_dma_for_device
> > always wait for the completion of each DMA buffer. That is,
> > issuing the DMA sync and waiting for completion is done in a
> > single API call.
> >
> > For scatter-gather lists with multiple entries, this means
> > issuing and waiting is repeated for each entry, which can hurt
> > performance. Architectures like ARM64 may be able to issue all
> > DMA sync operations for all entries first and then wait for
> > completion together.
> >
> > To address this, arch_sync_dma_for_* now issues DMA operations in
> > batch, followed by a flush. On ARM64, the flush is implemented
> > using a dsb instruction within arch_sync_dma_flush().
> >
> > For now, add arch_sync_dma_flush() after each
> > arch_sync_dma_for_*() call. arch_sync_dma_flush() is defined as a
> > no-op on all architectures except arm64, so this patch does not
> > change existing behavior. Subsequent patches will introduce true
> > batching for SG DMA buffers.
> >
> > Cc: Leon Romanovsky <leon at kernel.org>
> > Cc: Catalin Marinas <catalin.marinas at arm.com>
> > Cc: Will Deacon <will at kernel.org>
> > Cc: Marek Szyprowski <m.szyprowski at samsung.com>
> > Cc: Robin Murphy <robin.murphy at arm.com>
> > Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
> > Cc: Ard Biesheuvel <ardb at kernel.org>
> > Cc: Marc Zyngier <maz at kernel.org>
> > Cc: Anshuman Khandual <anshuman.khandual at arm.com>
> > Cc: Ryan Roberts <ryan.roberts at arm.com>
> > Cc: Suren Baghdasaryan <surenb at google.com>
> > Cc: Joerg Roedel <joro at 8bytes.org>
> > Cc: Juergen Gross <jgross at suse.com>
> > Cc: Stefano Stabellini <sstabellini at kernel.org>
> > Cc: Oleksandr Tyshchenko <oleksandr_tyshchenko at epam.com>
> > Cc: Tangquan Zheng <zhengtangquan at oppo.com>
> > Signed-off-by: Barry Song <baohua at kernel.org>
> > ---
> >  arch/arm64/include/asm/cache.h |  6 ++++++
> >  arch/arm64/mm/dma-mapping.c    |  4 ++--
> >  drivers/iommu/dma-iommu.c      | 37 +++++++++++++++++++++++++---------
> >  drivers/xen/swiotlb-xen.c      | 24 ++++++++++++++--------
> >  include/linux/dma-map-ops.h    |  6 ++++++
> >  kernel/dma/direct.c            |  8 ++++++--
> >  kernel/dma/direct.h            |  9 +++++++--
> >  kernel/dma/swiotlb.c           |  4 +++-
> >  8 files changed, 73 insertions(+), 25 deletions(-)
>
> <...>
>
> > +#ifndef arch_sync_dma_flush
> > +static inline void arch_sync_dma_flush(void)
> > +{
> > +}
> > +#endif
>
> Over the weekend I realized a useful advantage of the ARCH_HAVE_* config
> options: they make it straightforward to inspect the entire DMA path simply
> by looking at the .config.

I am not quite sure how much this benefits users, as the same
information could also be obtained by grepping for
#define arch_sync_dma_flush in the source code.

>
> Thanks,
> Reviewed-by: Leon Romanovsky <leonro at nvidia.com>

Thanks very much, Leon, for reviewing this over the weekend. One thing
you might have missed is that I place arch_sync_dma_flush() after all
arch_sync_dma_for_*() calls, for both single and sg cases. I also
used a Python script to scan the code and verify that every
arch_sync_dma_for_*() is followed by arch_sync_dma_flush(), to ensure
that no call is left out.

In the subsequent patches, for sg cases, the per-entry flush is
replaced by a single flush of the entire sg. Each sg case has
different characteristics: some are straightforward, while others
can be tricky and involve additional contexts.

Thanks
Barry


From josua.mayer at jm0.eu  Sat Dec 27 15:34:20 2025
From: josua.mayer at jm0.eu (Ing. Josua Mayer)
Date: Sun, 28 Dec 2025 00:34:20 +0100
Subject: [PATCH 1/3] power: supply: add battery driver for netronix ec
In-Reply-To: <20251227223815.17dea51d@kemnade.info>
References: <20251227-kobo-aura-battery-v1-0-328a90ef5122@jm0.eu>
 <20251227-kobo-aura-battery-v1-1-328a90ef5122@jm0.eu>
 <20251227223815.17dea51d@kemnade.info>
Message-ID: <0087cd4f-4e85-4cd0-8732-cd5b175e9eaa@jm0.eu>

Am 27.12.25 um 22:38 schrieb Andreas Kemnade:
> On Sat, 27 Dec 2025 17:28:13 +0100
> Josua Mayer <josua.mayer at jm0.eu> wrote:
> 
>> Implement a simple battery driver for monitoring voltage with the
>> netronix embedded controller found in certain ebook readers.
>>
>> Signed-off-by: Josua Mayer <josua.mayer at jm0.eu>
> 
> This also produces a value somehow depending on battery voltage
> on the Tolino vision.
Good!

> [...]
>> diff --git a/drivers/mfd/ntxec.c b/drivers/mfd/ntxec.c
>> index 08c68de0f01bc..d5059b8862aa8 100644
>> --- a/drivers/mfd/ntxec.c
>> +++ b/drivers/mfd/ntxec.c
>> @@ -139,6 +139,7 @@ static const struct regmap_config regmap_config = {
>> static const struct mfd_cell ntxec_subdev[] = {
>> 	{ .name = "ntxec-rtc" },
>> 	{ .name = "ntxec-pwm" },
>> +	{ .name = "ntxec-battery" },
>> };
>>
>> static const struct mfd_cell ntxec_subdev_pwm[] = {
> 
> I think that should be a separate patch for mfd.
Okay

> [...]
>> +	switch (psp) {
>> +		case POWER_SUPPLY_PROP_VOLTAGE_NOW:
>> +			ret = regmap_read(priv->ec->regmap, NTXEC_REG_READ_BATTERY, &value);
>> +			if (ret < 0)
>> +				return ret;
>> +
>> +			/* ec value to microvolt conversion:
>> +			 * vendor kernel source suggests linear behaviour from 3V to 4.2V
>> +			 * with readings 767 to 1023; each increment represents 4687,5uV.
>> +			 * adjust 3V boundary slightly to report exactly 4.2V when full.
>> +			 */
>> +			val->intval = 2999872 + (value - 767) * 4688;
>> +			break;
> I find this code both in some kobo 2.6.35.3 code and on the tolino 3.0.35:
> 
>          const unsigned short battGasgauge[] = {
>          //      3.0V, 3.1V, 3.2V, 3.3V, 3.4V, 3.5V, 3.6V, 3.7V, 3.8V, 3.9V, 4.0V, 4.1V, 4.2V,
> //               743,  767,  791,  812,  835,  860,  885,  909,  935,  960,  985, 1010, 1023,
>                   767,  791,  812,  833,  852,  877,  903,  928,  950,  979,  993, 1019, 1023,
>          };
> 
> This does not look very linear... We have offsets
> 24
> 21
> 21
> 19
> 25
> 26
> 25
> 22
> 29
> 14
> 26
> 4
> 
> Do you have something looking more sane?
No, I based on the same but simplified it.
> No idea what should produce such flaky offsets besides of
> improper measurements. At least that should be commented.
> And why do these tables exist at all?
> 
> Hmm, the more weird thing is that these voltages are translated linearly
> inot capacity.
Indeed - this is why I decided on a linear relationship ...
matching minimal and maixmal voltage as close as possible.

> So maybe they are just adjusted to have the capacity look
> more sane. That would explain the 4 units step between 4.1V and 4.2V.
4.1 is the full voltage of the lion battery if charger was disconnected.
However 4.2 I think is the final voltage reached while charging.

> Having linear adc result -> voltage and nonlinear voltage-> capcity would
> make more sense.
Indeed.
But if it was intended as percentage, then why would he register not 
just read from 0-100 :(
So I still guess it is some adc result.

> 
> looking at such code snippet like this:
> case POWER_SUPPLY_PROP_CAPACITY:
>                  if (POWER_SUPPLY_STATUS_NOT_CHARGING == g_ntx_bat_di->battery_status) {
>                          val->intval = 100;
>                          return 0;
>                  }
>                  value = ntx_up_battery_vol();
> [...]
>                                  val->intval  = 100 - ((4100000 - value)/7000);
> 
> 
> I am wondering whether we should just return capacity that way without
> calculating voltage...
I suppose it depends on whether it is more likely that the ec provides 
voltage, or a charge estimation.

br
Josua


From wbg at kernel.org  Sat Dec 27 22:52:40 2025
From: wbg at kernel.org (William Breathitt Gray)
Date: Sun, 28 Dec 2025 15:52:40 +0900
Subject: [PATCH v3 3/3] counter: Add STM based counter
In-Reply-To: <20251217075000.2592966-4-daniel.lezcano@linaro.org>
References: <20251217075000.2592966-4-daniel.lezcano@linaro.org>
Message-ID: <20251228065241.21144-1-wbg@kernel.org>

On Wed, Dec 17, 2025 at 08:49:57AM +0100, Daniel Lezcano wrote:
> The NXP S32G2 automotive platform integrates four Cortex-A53 cores and
> three Cortex-M7 cores, along with a large number of timers and
> counters. These hardware blocks can be used as clocksources or
> clockevents, or as timestamp counters shared across the various
> subsystems running alongside the Linux kernel, such as firmware
> components. Their actual usage depends on the overall platform
> software design.
> 
> In a Linux-based system, the kernel controls the counter, which is a
> read-only shared resource for the other subsystems. One of its primary
> purposes is to act as a common timestamp source for messages or
> traces, allowing correlation of events occurring in different
> operating system contexts.
> 
> These changes introduce a basic counter driver that can start, stop,
> and reset the counter. It also handles overflow accounting and
> configures the prescaler value.
> 
> Signed-off-by: Daniel Lezcano <daniel.lezcano at linaro.org>

Hi Daniel,

It sounds like you're trying to implement a clock for timestamping.
Although the Generic Counter interface is flexible enough to shoehorn a
a clock into its representation, I don't believe it's the right
abstraction for this particular device. Perhaps reimplementing this
driver under the Linux common clock framework would be a better approach
to achieve what you want.

Regardless, if you do pursue a Counter driver you'll need to follow the
Generic Counter paradigm[^1] and define at least three core components:
a Signal, a Synapse, and a Count. Resetting the Count is typically
implemented by defining a struct counter_ops counter_write()
callback[^2], while overflows are typically implemented by pushing
COUNTER_EVENT_OVERFLOW Counter events[^3] that can be watched by
userspace.

William Breathitt Gray

[^1] https://docs.kernel.org/driver-api/generic-counter.html#paradigm
[^2] https://docs.kernel.org/driver-api/generic-counter.html#c.counter_ops
[^3] https://docs.kernel.org/driver-api/generic-counter.html#counter-events


From rdunlap at infradead.org  Sat Dec 27 23:10:41 2025
From: rdunlap at infradead.org (Randy Dunlap)
Date: Sat, 27 Dec 2025 23:10:41 -0800
Subject: [PATCH] ASoC: pxa: drop unused Kconfig symbol
Message-ID: <20251228071041.2246718-1-rdunlap@infradead.org>

Drop a bogus dangling Kconfig symbol for select SND_SOC_AC97_BUS_NEW.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=216748
Fixes: 1c8bc7b3de5e ("ASoC: pxa: switch to new ac97 bus support")
Signed-off-by: Randy Dunlap <rdunlap at infradead.org>
---
Cc: Robert Jarzmik <robert.jarzmik at free.fr>
Cc: Daniel Mack <daniel at zonque.org>
Cc: Haojian Zhuang <haojian.zhuang at gmail.com>
Cc: linux-arm-kernel at lists.infradead.org
Cc: Liam Girdwood <lgirdwood at gmail.com>
Cc: Mark Brown <broonie at kernel.org>
Cc: linux-sound at vger.kernel.org
Cc: Jaroslav Kysela <perex at perex.cz>
Cc: Takashi Iwai <tiwai at suse.com>

 sound/soc/pxa/Kconfig |    1 -
 1 file changed, 1 deletion(-)

--- linux-next-20251219.orig/sound/soc/pxa/Kconfig
+++ linux-next-20251219/sound/soc/pxa/Kconfig
@@ -18,7 +18,6 @@ config SND_PXA2XX_SOC_AC97
 	select AC97_BUS_NEW
 	select SND_PXA2XX_LIB
 	select SND_PXA2XX_LIB_AC97
-	select SND_SOC_AC97_BUS_NEW
 
 config SND_PXA2XX_SOC_I2S
 	select SND_PXA2XX_LIB


From lkp at intel.com  Sat Dec 27 23:52:27 2025
From: lkp at intel.com (kernel test robot)
Date: Sun, 28 Dec 2025 15:52:27 +0800
Subject: [PATCH v7 14/17] media: rkvdec: Add H264 support for the VDPU381
 variant
In-Reply-To: <20251218232829.337811-15-detlev.casanova@collabora.com>
References: <20251218232829.337811-15-detlev.casanova@collabora.com>
Message-ID: <202512281536.56iWFq03-lkp@intel.com>

Hi Detlev,

kernel test robot noticed the following build errors:

[auto build test ERROR on media-tree/master]
[also build test ERROR on linus/master v6.19-rc2]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Detlev-Casanova/media-uapi-HEVC-Add-v4l2_ctrl_hevc_ext_sps_-ls-t_rps-controls/20251219-074342
base:   git://linuxtv.org/media_tree.git master
patch link:    https://lore.kernel.org/r/20251218232829.337811-15-detlev.casanova%40collabora.com
patch subject: [PATCH v7 14/17] media: rkvdec: Add H264 support for the VDPU381 variant
config: arm-randconfig-r071-20251224 (https://download.01.org/0day-ci/archive/20251228/202512281536.56iWFq03-lkp at intel.com/config)
compiler: arm-linux-gnueabi-gcc (GCC) 8.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251228/202512281536.56iWFq03-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512281536.56iWFq03-lkp at intel.com/

All errors (new ones prefixed by >>, old ones prefixed by <<):

>> ERROR: modpost: "__aeabi_uldivmod" [drivers/media/platform/rockchip/rkvdec/rockchip-vdec.ko] undefined!
>> ERROR: modpost: "__aeabi_ldivmod" [drivers/media/platform/rockchip/rkvdec/rockchip-vdec.ko] undefined!

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From syzbot+list754a4a62455c8c172e46 at syzkaller.appspotmail.com  Sun Dec 28 00:47:20 2025
From: syzbot+list754a4a62455c8c172e46 at syzkaller.appspotmail.com (syzbot)
Date: Sun, 28 Dec 2025 00:47:20 -0800
Subject: [syzbot] Monthly arm report (Dec 2025)
Message-ID: <6950ee98.a70a0220.c527.0009.GAE@google.com>

Hello arm maintainers/developers,

This is a 31-day syzbot report for the arm subsystem.
All related reports/information can be found at:
https://syzkaller.appspot.com/upstream/s/arm

During the period, 0 new issues were detected and 0 were fixed.
In total, 4 issues are still open and 7 have already been fixed.

Some of the still happening issues:

Ref Crashes Repro Title
<1> 294     Yes   WARNING in delayed_work_timer_fn
                  https://syzkaller.appspot.com/bug?extid=e13e654d315d4da1277c
<2> 66      Yes   INFO: task hung in truncate_inode_pages_final (2)
                  https://syzkaller.appspot.com/bug?extid=760777ae7038cad77437
<3> 15      Yes   WARNING in fpsimd_restore_current_state
                  https://syzkaller.appspot.com/bug?extid=d4ab35af21e99d07ce67

---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller at googlegroups.com.

To disable reminders for individual bugs, reply with the following command:
#syz set <Ref> no-reminders

To change bug's subsystems, reply with:
#syz set <Ref> subsystems: new-subsystem

You may send multiple commands in a single email message.


From krzk at kernel.org  Sun Dec 28 02:30:39 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sun, 28 Dec 2025 11:30:39 +0100
Subject: [PATCH v4 1/7] dt-bindings: pinctrl: Add rv1126b pinctrl support
In-Reply-To: <20251227114957.3287944-2-ye.zhang@rock-chips.com>
References: <20251227114957.3287944-1-ye.zhang@rock-chips.com>
 <20251227114957.3287944-2-ye.zhang@rock-chips.com>
Message-ID: <20251228-airborne-elated-asp-c8f1fb@quoll>

On Sat, Dec 27, 2025 at 07:49:51PM +0800, Ye Zhang wrote:
> The RV1126B is a new SoC that is the successor of the RV1126. It has
> different pinctrl registers and is not compatible with the RV1126.
> Therefore, add a new compatible string for it.
> 
> Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
> ---
>  Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml | 1 +
>  1 file changed, 1 insertion(+)

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof



From marcus.folkesson at gmail.com  Sun Dec 28 02:34:49 2025
From: marcus.folkesson at gmail.com (Marcus Folkesson)
Date: Sun, 28 Dec 2025 11:34:49 +0100
Subject: [PATCH RESEND v3 0/5] I2C Mux per channel bus speed
In-Reply-To: <20251202-i2c-mux-v3-0-877dcf478a9f@gmail.com>
References: <20251202-i2c-mux-v3-0-877dcf478a9f@gmail.com>
Message-ID: <aVEHyUsijrnFUWfD@gmail.com>

On Tue, Dec 02, 2025 at 09:09:47AM +0100, Marcus Folkesson wrote:
> This was a RFC on how to implement a feature to have different bus
> speeds on different channels with an I2C multiplexer/switch.
> As no major complaints on the design came up during the review, I
> decided to submit the series without the RFC tag.
> 
> The benefit with this feature is that you may group devices after
> the fastest bus speed they can handle.
> A real-world example is that you could have e.g. a display running @400kHz
> and a smart battery running @100kHz using the same I2C controller.
> 
> There are many corner cases where this may cause a problem for some
> hardware topologies. I've tried to describe those I could think of
> in the documentation, see Patch #5.
> 
> E.g. one risk is that if the mux driver does not disconnect channels
> when Idle, this may cause a higher frequency to "leak" through to
> devices that are supposed to run at lower bus speed.
> This is not only a "problem" for changing bus speed but could also be
> an issue for potential address conflicts.
> 
> The implementation is split up into several patches:
> 
> Patch #1 Introduce a callback for the i2c controller to set bus speed
> Patch #2 Introduce functionality to adjust bus speed depending on mux
>          channel.
> Patch #3 Cleanup i2c-davinci driver a bit to prepare it for set_clk_freq
> Parch #4 Implement set_clk_freq for the i2c-davinci driver
> Parch #5 Update documentation with this feature
> 
> Signed-off-by: Marcus Folkesson <marcus.folkesson at gmail.com>

Ping on this series.

Best regards,
Marcus Folkesson
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251228/ac532667/attachment-0001.sig>

From krzk at kernel.org  Sun Dec 28 02:37:35 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sun, 28 Dec 2025 11:37:35 +0100
Subject: [PATCH v4 7/7] ARM: dts: rockchip: rk3506: Add pinctrl and rmio
 dtsi for rk3506
In-Reply-To: <20251227114957.3287944-8-ye.zhang@rock-chips.com>
References: <20251227114957.3287944-1-ye.zhang@rock-chips.com>
 <20251227114957.3287944-8-ye.zhang@rock-chips.com>
Message-ID: <ebb720f6-4756-437f-a71a-d94f45d732e8@kernel.org>

On 27/12/2025 12:49, Ye Zhang wrote:
> +		/omit-if-no-ref/
> +		rm_io28_touch_key_in6: rm-io28-touch-key-in6 {
> +			rockchip,pins =
> +				<1 RK_PC3 7 &pcfg_pull_none>;
> +			rockchip,rmio-pins =
> +				<0 28 49>;
> +		};
> +
> +		/omit-if-no-ref/
> +		rm_io28_touch_key_in7: rm-io28-touch-key-in7 {
> +			rockchip,pins =
> +				<1 RK_PC3 7 &pcfg_pull_none>;
> +			rockchip,rmio-pins =
> +				<0 28 50>;
> +		};
> +
> +		/omit-if-no-ref/
> +		rm_io28_sai0_mclk: rm-io28-sai0-mclk {
> +			rockchip,pins =
> +				<1 RK_PC3 7 &pcfg_pull_none>;
> +			rockchip,rmio-pins =
> +				<0 28 51>;
> +		};
> +
> +		/omit-if-no-ref/
> +		rm_io28_sai0_sclk: rm-io28-sai0-sclk {
> +			rockchip,pins =
> +				<1 RK_PC3 7 &pcfg_pull_none>;
> +			rockchip,rmio-pins =
> +				<0 28 52>;
> +		};
> +
> +		/omit-if-no-ref/
> +		rm_io28_sai0_lrck: rm-io28-sai0-lrck {
> +			rockchip,pins =
> +				<1 RK_PC3 7 &pcfg_pull_none>;
> +			rockchip,rmio-pins =
> +				<0 28 53>;
> +		};
> +
> +		/omit-if-no-ref/
> +		rm_io28_sai0_sdi0: rm-io28-sai0-sdi0 {
> +			rockchip,pins =
> +				<1 RK_PC3 7 &pcfg_pull_none>;
> +			rockchip,rmio-pins =
> +				<0 28 54>;
> +		};

Why are you defining all pins? This is wrong, your driver has to do it,
not DTS. All these definitions when not used are just pointless.


Best regards,
Krzysztof


From krzk at kernel.org  Sun Dec 28 02:37:40 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sun, 28 Dec 2025 11:37:40 +0100
Subject: [PATCH v4 5/7] dt-bindings: pinctrl: rockchip: Add rk3506 rmio
 support
In-Reply-To: <20251227114957.3287944-6-ye.zhang@rock-chips.com>
References: <20251227114957.3287944-1-ye.zhang@rock-chips.com>
 <20251227114957.3287944-6-ye.zhang@rock-chips.com>
Message-ID: <20251228-olive-termite-of-painting-1bee5b@quoll>

On Sat, Dec 27, 2025 at 07:49:55PM +0800, Ye Zhang wrote:
> The RK3506 SoC introduces a secondary block-level pinmux controller called
> RMIO (Rockchip Matrix I/O). When the primary IOMUX is selected to a
> specific function, the pin signal is routed to the RMIO block, where a
> secondary selection determines the final function.
> 
> This patch adds the necessary properties to support RMIO:
> - rockchip,rmio: phandle to the RMIO syscon node.
> - rockchip,rmio-pins: a matrix to configure the RMIO block.
> 
> Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
> ---
>  .../bindings/pinctrl/rockchip,pinctrl.yaml    | 24 +++++++++++++++++++
>  1 file changed, 24 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
> index 97960245676d..887bec22b172 100644
> --- a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
> +++ b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
> @@ -66,6 +66,13 @@ properties:
>        Required for at least rk3188 and rk3288. On the rk3368 this should
>        point to the PMUGRF syscon.
>  
> +  rockchip,rmio:
> +    $ref: /schemas/types.yaml#/definitions/phandle
> +    description:
> +      The phandle of the syscon node for the RMIO registers, used by
> +      some SoCs (e.g. rk3506) to configure the secondary block-level
> +      pinmux functions.
> +

You need to disallow it for other variants in if:then: block.

>    "#address-cells":
>      enum: [1, 2]
>  
> @@ -144,6 +151,23 @@ additionalProperties:
>                  The phandle of a node contains the generic pinconfig options
>                  to use as described in pinctrl-bindings.txt.
>  
> +      rockchip,rmio-pins:
> +        $ref: /schemas/types.yaml#/definitions/uint32-matrix
> +        minItems: 1
> +        items:
> +          items:
> +            - minimum: 0

That's redundant. 0 is already minimum.

> +              description: RMIO ID (Controller index)

Why do you need this? Is this pin controller having multiple RMIO IDs?
Nothing like that was expressed in previous DTS. No other IDs are
present in this DTS, either...

> +            - minimum: 0
> +              description: Pin index within the RMIO controller
> +            - minimum: 0
> +              description: Function Mux ID
> +        description:
> +          Configuration for the Rockchip Matrix I/O (RMIO) block. The format
> +          is <rmio_id pin_id function_id>. This acts as a secondary muxing
> +          layer when the primary 'rockchip,pins' mux is set to the RMIO
> +          function.
> +
>  examples:
>    - |
>      #include <dt-bindings/interrupt-controller/arm-gic.h>
> -- 
> 2.34.1
> 


From robert.jarzmik at free.fr  Sun Dec 28 03:11:59 2025
From: robert.jarzmik at free.fr (Robert Jarzmik)
Date: Sun, 28 Dec 2025 12:11:59 +0100
Subject: [PATCH] ARM: dts: intel: Drop pxa2xx
In-Reply-To: <35405ed3-1319-4d3a-84a5-ad67f4c823ad@app.fastmail.com> (Arnd
	Bergmann's message of "Wed, 17 Dec 2025 17:04:05 +0100")
References: <20251212203226.458694-4-robh@kernel.org> <m2345fmkg7.fsf@free.fr>
	<35405ed3-1319-4d3a-84a5-ad67f4c823ad@app.fastmail.com>
Message-ID: <m2wm26lv28.fsf@free.fr>

"Arnd Bergmann" <arnd at arndb.de> writes:

> Robert, let me know if you or someone else is able to spend
> some time on sending (warning-free) dts files for pxa2xx
> machines soon. If not, I'd plan to remove whatever is there
> along with the board files and drivers.

Here is one attached, the previously mentioned mioa701 board dts 
file
I've been using for years (the date of the patch should be funny
enough). It was first submitted here :
  https://lkml.org/lkml/2018/9/15/321

I'm not very sure pxa25x and pxa27x should survive though. Lately, 
the
platform which I have left have 64MB of RAM, and cannot cope with 
recent
binaries sizes. And to my best knowledge, pxa2xx architecture are 
not
built anymore nor supported ...
The drivers might still be useful (the DMA, the SPI for intel CPU, 
...).

Cheers.

--
Robert

-- >8 --
>From a3cbbe846c4651d71edcf36d114f5e48f4455347 Mon Sep 17 00:00:00 
2001
From: Robert Jarzmik <robert.jarzmik at free.fr>
Date: Mon, 1 Sep 2014 13:26:56 +0200
Subject: [PATCH] arm: dts: add mioa701 board description

Add device-tree description of the Mitac MIO A701 board.

Signed-off-by: Robert Jarzmik <robert.jarzmik at free.fr>
---
 arch/arm/boot/dts/intel/pxa/Makefile    |   1 +
 arch/arm/boot/dts/intel/pxa/mioa701.dts | 309 
 ++++++++++++++++++++++++
 2 files changed, 310 insertions(+)
 create mode 100644 arch/arm/boot/dts/intel/pxa/mioa701.dts

diff --git a/arch/arm/boot/dts/intel/pxa/Makefile 
b/arch/arm/boot/dts/intel/pxa/Makefile
index 24d5240f08e7..29670ec5861b 100644
--- a/arch/arm/boot/dts/intel/pxa/Makefile
+++ b/arch/arm/boot/dts/intel/pxa/Makefile
@@ -6,3 +6,4 @@ dtb-$(CONFIG_ARCH_PXA) += \
 	pxa300-raumfeld-speaker-m.dtb \
 	pxa300-raumfeld-speaker-one.dtb \
 	pxa300-raumfeld-speaker-s.dtb
+dtb-$(CONFIG_ARCH_PXA) += mioa701.dtb
diff --git a/arch/arm/boot/dts/intel/pxa/mioa701.dts 
b/arch/arm/boot/dts/intel/pxa/mioa701.dts
new file mode 100644
index 000000000000..b8a27e6db2b2
--- /dev/null
+++ b/arch/arm/boot/dts/intel/pxa/mioa701.dts
@@ -0,0 +1,309 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  Copyright (C) Robert Jarzmik <robert.jarzmik at free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or 
modify
+ *  it under the terms of the GNU General Public License version 
2 as
+ *  publishhed by the Free Software Foundation.
+ */
+
+/dts-v1/;
+#include "pxa27x.dtsi"
+#include "dt-bindings/gpio/gpio.h"
+
+#define PMGROUP(pin) #pin
+#define PMMUX(func, pin, af)			\
+	mux- ## func {				\
+		groups = PMGROUP(P ## pin);	\
+		function = #af;			\
+	}
+#define PMMUX_LPM_LOW(func, pin, af)		\
+	mux- ## func {				\
+		groups = PMGROUP(P ## pin);	\
+		function = #af;			\
+		low-power-disable;		\
+	}
+#define PMMUX_LPM_HIGH(func, pin, af)		\
+	mux- ## func {				\
+		groups = PMGROUP(P ## pin);	\
+		function = #af;			\
+		low-power-enable;		\
+	}
+
+/ {
+	model = "Mitac Mio A701 Board";
+	/* compatible = "mitac,mioa701"; */
+	compatible = "marvell,pxa270";
+
+	chosen {
+		bootargs = 
"mtdparts=docg3.0:256k at 3456k(barebox)ro,256k(barebox-logo),128k(barebox-env),4M(kernel),-(root) 
ubi.mtd=4 rootfstype=ubifs root=ubi0:linux_root ro";
+	};
+
+	memory {
+		reg = <0xa0000000 0x04000000>;
+
+		reserved-memory {
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			pstore_region:region at a2000000 {
+				compatible = 
"linux,contiguous-memory-region";
+				reg = <0xa2000000 1048576>;
+			};
+		};
+	};
+
+	cpus {
+		cpu {
+			cpu-supply = <&vcc_core>;
+		};
+	};
+
+	pxabus {
+		pinctrl: pinctrl at 40e00000 {
+			status = "okay";
+			pinctrl_mmc_default: mmc-default {
+				PMMUX(sd-insert, 15, gpio_in);
+				PMMUX(mmclk, 32, MMCLK);
+				PMMUX(sd-ro, 78, gpio_in);
+				PMMUX(sd-enable, 91, gpio_out);
+				PMMUX(mmdat0, 92, MMDAT<0>);
+				PMMUX(mmdat1, 109, MMDAT<1>);
+				PMMUX(mmdat2, 110, MMDAT<2>);
+				PMMUX(mmdat3, 111, MMDAT<3>);
+				PMMUX(mmcmd, 112, MMCMD);
+			};
+			pinctrl_leds_default: leds-default {
+				PMMUX(led-charging, 10, gpio_out);
+				PMMUX(led-vibra, 82, gpio_out);
+				PMMUX(led-blue, 97, gpio_out);
+				PMMUX_LPM_LOW(led-orange, 98, 
gpio_out);
+				PMMUX_LPM_HIGH(led-keyboard, 115, 
gpio_out);
+			};
+		};
+
+		gpio: gpio at 40e00000 {
+			status = "okay";
+		};
+
+		uart at 40100000 {
+			status = "okay";
+		};
+
+		uart at 40200000 {
+			status = "okay";
+		};
+
+		uart at 40700000 {
+			status = "okay";
+		};
+
+		usb2phy: gpio-vbus at 13 {
+			compatible = "usb-nop-xceiv";
+			vbus-detect-gpio = <&gpio 13 
GPIO_ACTIVE_LOW>;
+			#phy-cells = <0>;
+			wakeup;
+		};
+
+		pxa27x_udc: udc at 40600000 {
+			    status = "okay";
+			    gpios = <&gpio 22 0>;
+			    phys = <&usb2phy>;
+			    phys-names = "usb2phy";
+		};
+
+		i2c at 40f00180 {
+			status = "okay";
+
+			max1586 at 14 {
+				compatible = "maxim,max1586";
+				reg = <0x14>;
+				#address-cells = <0x1>;
+				#size-cells = <0x1>;
+				v3-gain = <1000000>;
+
+				regulators {
+					vcc_core: v3 {
+						regulator-name = 
"vcc_core";
+ 
regulator-compatible = "Output_V3";
+ 
regulator-min-microvolt = <1000000>;
+ 
regulator-max-microvolt = <1705000>;
+ 
regulator-always-on;
+					};
+				};
+			};
+		};
+
+		pxai2c1: i2c at 40301680 {
+			mrvl,i2c-fast-mode;
+			status = "okay";
+
+			mt9m111: camera at 5d {
+				compatible = "micron,mt9m111";
+				reg = <0x5d>;
+				gpios = <&gpio 56 
GPIO_ACTIVE_HIGH>;
+			};
+		};
+
+		keypad: keypad at 41500000 {
+			status = "okay";
+
+			keypad,num-rows = <3>;
+			keypad,num-columns = <3>;
+			linux,keymap = <
+				0x00000067	/* KEY_UP */
+				0x0001006a	/* KEY_RIGHT */
+				0x000200e2	/* KEY_MEDIA */
+				0x0100006c	/* KEY_DOWN */
+				0x0101001c	/* KEY_ENTER */
+				0x010200da	/* KEY_CONNECT */
+				0x02000069	/* KEY_LEFT */
+				0x020100a9	/* KEY_PHONE */
+				0x020200d4>;	/* KEY_CAMERA */
+			marvell,debounce-interval = <0>;
+		};
+
+		gpio-keys {
+			compatible = "gpio-keys";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			autorepeat;
+			status = "okay";
+
+			button at 0 {
+				label = "GPIO Key Power";
+				linux,code = <174>;
+				gpios = <&gpio 0 0>;
+				gpio-key,wakeup;
+			};
+			button at 12 {
+				label = "HP jack detect";
+				linux,code = <211>;
+				gpios = <&gpio 12 0>;
+			};
+			button at 93 {
+				label = "Volume Up Key";
+				linux,code = <115>;
+				gpios = <&gpio 93 0>;
+			};
+			button at 94 {
+				label = "Volume Down Key";
+				linux,code = <114>;
+				gpios = <&gpio 94 0>;
+			};
+		};
+
+		mmc0: mmc at 41100000 {
+			vmmc-supply = <&reg_vmmc>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_mmc_default>;
+			status = "okay";
+		};
+
+		pxa_camera: imaging at 50000000 {
+			status = "okay";
+		};
+
+		lcd-controller at 40500000 {
+			status = "okay";
+			port {
+				lcdc_out: endpoint {
+					remote-endpoint = 
<&panel_in>;
+					bus-width = <16>;
+				};
+			};
+		};
+	};
+
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		reg_vmmc: regulator at 0 {
+			compatible = "regulator-fixed";
+			regulator-name = "vmmc";
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			regulator-always-on;
+		};
+	};
+
+	backlight {
+		compatible = "pwm-backlight";
+		pwms = <&pwm0 40960000>;
+		pwm-names = "backlight";
+
+		brightness-levels = <0 4 8 16 32 64 128 255>;
+		default-brightness-level = <2>;
+	};
+
+	docg3: flash at 0 {
+		compatible = "m-systems,diskonchip-g3";
+		reg = <0x0 0x2000>;
+	};
+
+	panel {
+		compatible = "toshiba,ltm0305a776";
+		lcd-type = "color-tft";
+
+		port {
+			panel_in: endpoint {
+				remote-endpoint = <&lcdc_out>;
+			};
+		};
+
+		display-timings {
+			native-mode = <&timing0>;
+			timing0: 240p {
+				/* 240x320p24 */
+				clock-frequency = <4545000>;
+				hactive = <240>;
+				vactive = <320>;
+				hfront-porch = <4>;
+				hback-porch = <6>;
+				hsync-len = <4>;
+				vback-porch = <5>;
+				vfront-porch = <3>;
+				vsync-len = <2>;
+			};
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_leds_default>;
+
+		charger-led {
+			label = "mioa701:charging";
+			gpios = <&gpio 10 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		vibrator {
+			label = "mioa701:vibra";
+			gpios = <&gpio 82 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		bluetooth-led {
+			label = "mioa701:blue";
+			gpios = <&gpio 97 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		orange-led {
+			label = "mioa701:orange";
+			gpios = <&gpio 98 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		keyboard-led {
+			label = "mioa701:keyboard";
+			gpios = <&gpio 115 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+	};
+};
-- 
2.50.1 (Apple Git-155)



From krzk at kernel.org  Sun Dec 28 03:32:26 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sun, 28 Dec 2025 12:32:26 +0100
Subject: (subset) [PATCH v4 0/5] soc: samsung: exynos-chipid: add gs101
 support
In-Reply-To: <20251222-gs101-chipid-v4-0-aa8e20ce7bb3@linaro.org>
References: <20251222-gs101-chipid-v4-0-aa8e20ce7bb3@linaro.org>
Message-ID: <176692154663.58022.10187099781030304762.b4-ty@kernel.org>


On Mon, 22 Dec 2025 16:30:04 +0000, Tudor Ambarus wrote:
> Dependency
> ==========
> Typical dependency of the DT patch depending on the bindings patch,
> thus the bindings patch could go via the Samsung SoC tree with
> Srinivas's ack.
> 
> Description
> ===========
> GS101 is different (but also e850 and autov9 I assume) from the SoCs
> that are currently handled by the exynos-chipid driver because the
> chip ID info is part of the OTP registers. GS101 OTP has a clock, an
> interrupt line, a register space (that contains product and chip ID,
> TMU data, ASV, etc) and a 32Kbit memory space that can be
> read/program/locked with specific commands. On GS101 the "ChipID block"
> is just an abstraction, it's not a physical device. When the power-on
> sequence progresses, the OTP chipid values are loaded to the OTP
> registers.
> 
> [...]

Applied, thanks!

[1/5] dt-bindings: nvmem: add google,gs101-otp
      https://git.kernel.org/krzk/linux/c/12da6f08a07ddaddd336af878350d30449d23a54
[2/5] soc: samsung: exynos-chipid: rename method
      https://git.kernel.org/krzk/linux/c/9133ae2119cb3c948675dc566eebf11cc4bb1681
[3/5] soc: samsung: exynos-chipid: downgrade dev_info to dev_dbg for soc info
      https://git.kernel.org/krzk/linux/c/c38cfc303db9ab4d5f482ae8e36e5a677db8eee6
[4/5] soc: samsung: exynos-chipid: add google,gs101-otp support
      https://git.kernel.org/krzk/linux/c/732af51910960535382db3f6e0b33e2e2b0ff7b6

Best regards,
-- 
Krzysztof Kozlowski <krzk at kernel.org>



From krzk at kernel.org  Sun Dec 28 03:33:06 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sun, 28 Dec 2025 12:33:06 +0100
Subject: (subset) [PATCH v4 0/5] soc: samsung: exynos-chipid: add gs101
 support
In-Reply-To: <20251222-gs101-chipid-v4-0-aa8e20ce7bb3@linaro.org>
References: <20251222-gs101-chipid-v4-0-aa8e20ce7bb3@linaro.org>
Message-ID: <176692158656.58608.1877617154747572001.b4-ty@kernel.org>


On Mon, 22 Dec 2025 16:30:04 +0000, Tudor Ambarus wrote:
> Dependency
> ==========
> Typical dependency of the DT patch depending on the bindings patch,
> thus the bindings patch could go via the Samsung SoC tree with
> Srinivas's ack.
> 
> Description
> ===========
> GS101 is different (but also e850 and autov9 I assume) from the SoCs
> that are currently handled by the exynos-chipid driver because the
> chip ID info is part of the OTP registers. GS101 OTP has a clock, an
> interrupt line, a register space (that contains product and chip ID,
> TMU data, ASV, etc) and a 32Kbit memory space that can be
> read/program/locked with specific commands. On GS101 the "ChipID block"
> is just an abstraction, it's not a physical device. When the power-on
> sequence progresses, the OTP chipid values are loaded to the OTP
> registers.
> 
> [...]

Applied, thanks!

[5/5] arm64: dts: exynos: gs101: add OTP node
      https://git.kernel.org/krzk/linux/c/9afdf3e1a59e23180540ecb1fe3287c308cc8113

Best regards,
-- 
Krzysztof Kozlowski <krzk at kernel.org>



From krzk at kernel.org  Sun Dec 28 03:37:33 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sun, 28 Dec 2025 12:37:33 +0100
Subject: [PATCH v3 2/5] pinctrl: samsung: fix incorrect pin-bank entries
 on Exynos2200/7885/8890/8895
In-Reply-To: <20251202093613.852109-3-youngmin.nam@samsung.com>
References: <20251202093613.852109-1-youngmin.nam@samsung.com>
 <CGME20251202093027epcas2p24adbd3226dd50b2780baceee6588f3ba@epcas2p2.samsung.com>
 <20251202093613.852109-3-youngmin.nam@samsung.com>
Message-ID: <8f58391d-36b8-4b1c-a585-80cb114b3b46@kernel.org>

On 02/12/2025 10:36, Youngmin Nam wrote:
> This patch corrects wrong pin bank table definitions for 4 SoCs based on

Please do not use "This commit/patch/change", but imperative mood. See
longer explanation here:
https://elixir.bootlin.com/linux/v6.16/source/Documentation/process/submitting-patches.rst#L94


> their TRMs.
> 
> Exynos2200
> - gpq0/1/2 were using EXYNOS_PIN_BANK_EINTN(), which implies a
>   'bank_type_off' layout (.fld_width = {4,1,2,2,2,2}).
> - Per the SoC TRM these banks must use the 'alive' layout
>   (.fld_width = {4,1,4,4}).
> - Switch them to EXYNOS9_PIN_BANK_EINTN(exynos9_bank_type_alive, ...).
> 
> Exynos7885
> - etc0, etc1: update bank type to match the SoC TRM.
> - gpq0 is a non-wakeup interrupt bank; change EINTW -> EINTN accordingly.
> 
> Exynos8890
> - Per the SoC TRM, rename bank ect0 to gpb3 and mark it as
>   a non-external interrupt bank.
> - gpi1, gpi2: update bank type to match the SoC TRM.
>   exynos8895_bank_type_off (.fld_width = {4,1,2,3,2,2}) ->
>   exynos5433_bank_type_off (.fld_width = {4,1,2,4,2,2})
> - Per the SoC TRM, mark etc1 as a non-external interrupt bank.
> - apply lower case style for hex numbers.
> 
> Exynos8895
> - gpa4 is a non-wakeup interrupt bank per the SoC TRM.
>   change EINTW -> EINTN. (The bank_type itself was correct and is kept
>   unchanged.)
> - apply lower case style for hex numbers.

Please separate logical changes into separate commits. Fix for given
commit is one commit.

Also, fixes cannot be in the middle of the patchset.

> 
> This aligns the pin-bank tables with the documented bitfield layouts and
> wakeup domains. No DT/ABI change.
> 
> Signed-off-by: Youngmin Nam <youngmin.nam at samsung.com>
> Reviewed-by: Sam Protsenko <semen.protsenko at linaro.org>
> Reviewed-by: Ivaylo Ivanov <ivo.ivanov.ivanov1 at gmail.com>
> Tested-by: Sam Protsenko <semen.protsenko at linaro.org>

Missing Fixes tags.


Best regards,
Krzysztof


From krzk at kernel.org  Sun Dec 28 03:40:36 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sun, 28 Dec 2025 12:40:36 +0100
Subject: [PATCH v3 1/5] pinctrl: samsung: Consolidate pin-bank macros
 under EXYNOS9_* and pass bank_type explicitly
In-Reply-To: <20251202093613.852109-2-youngmin.nam@samsung.com>
References: <20251202093613.852109-1-youngmin.nam@samsung.com>
 <CGME20251202093026epcas2p28ddfd32305695df996841fd73b231b6b@epcas2p2.samsung.com>
 <20251202093613.852109-2-youngmin.nam@samsung.com>
Message-ID: <8b97f7a0-5d43-41ed-85a7-e48488c49264@kernel.org>

On 02/12/2025 10:36, Youngmin Nam wrote:
> Modern Exynos platforms have several near-duplicate pin-bank macro
> families (EXYNOS850_*, EXYNOS8895_*, EXYNOS7870_*), which makes
> tables verbose and harder to share across SoCs that differ only by
> bank_type (alive/off) layout.

I do not see at all how you reduced duplication, reduced verbosity or
made here anything easier to read.

Previous explicit EXYNOS850_PIN_BANK_EINTW() - so having one information
about SoC - is now containing more verbose two informations:

EXYNOS9_PIN_BANK_EINTW + exynos9_bank_type_alive,


> 
> This patch unifies them into one EXYNOS9_* macro family and makes the
> bank_type an explicit argument. The common 850-era bank types are also
> renamed to 'exynos9_bank_type_{alive,off}' to reflect their reuse on
> later Exynos 9xxx-generation parts.
> 
> Naming rationale:
> - Use of the EXYNOS9_* prefix indicates that these macros target
>   current Exynos generations sharing the same register layout and
>   EINT wiring model. Compared to SoC-specific prefixes

There is no exynos9 chip. There is also no need to rename Exynos850 to
Exynos9, because old name is correct, accurate and probably even older,
thus more suitable choice.


>   (EXYNOS850_*, EXYNOS8895_*),
>   EXYNOS9_* is clearer and more future-proof for modern parts.
> 
> Key changes:
> - Introduce:
>   - 'EXYNOS9_PIN_BANK_EINTN(bank_type, pins, reg, id)'
>   - 'EXYNOS9_PIN_BANK_EINTG(bank_type, pins, reg, id, offs)'
>   - 'EXYNOS9_PIN_BANK_EINTW(bank_type, pins, reg, id, offs)'
> - Rename:
>   - 'exynos850_bank_type_alive'-> 'exynos9_bank_type_alive'
>   - 'exynos850_bank_type_off'  -> 'exynos9_bank_type_off'
> - Convert pin-bank tables for:
>   - Exynos2200, 7870, 7885, 850, 990, 9810, 8890, 8895,
>     AutoV9, AutoV920, FSD
> - Update GS101/EXYNOSV920 helpers to reference 'exynos9_bank_type_*'
>   instead of the old exynos850 names.
> - Standardize on EXYNOS9_* macros while keeping SoC-specific
>   '*_bank_type_*' when layouts differ (e.g., 7870/8895).
> 
> No functional change intended.
> 
> Signed-off-by: Youngmin Nam <youngmin.nam at samsung.com>
> Reviewed-by: Sam Protsenko <semen.protsenko at linaro.org>
> Tested-by: Sam Protsenko <semen.protsenko at linaro.org>
> ---
>  .../pinctrl/samsung/pinctrl-exynos-arm64.c    | 785 +++++++++---------
>  drivers/pinctrl/samsung/pinctrl-exynos.h      |  49 +-
>  2 files changed, 402 insertions(+), 432 deletions(-)
> 
> diff --git a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
> index 627dca504d7a..d11b2d4ca913 100644
> --- a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
> +++ b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
> @@ -53,7 +53,7 @@ static const struct samsung_pin_bank_type exynos7870_bank_type_alive = {
>   * Bank type for non-alive type. Bit fields:
>   * CON: 4, DAT: 1, PUD: 4, DRV: 4, CONPDN: 2, PUDPDN: 4
>   */
> -static const struct samsung_pin_bank_type exynos850_bank_type_off  = {
> +static const struct samsung_pin_bank_type exynos9_bank_type_off = {

This is completely pointless.

>  	.fld_width = { 4, 1, 4, 4, 2, 4, },
>  	.reg_offset = { 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, },
>  };
> @@ -62,7 +62,7 @@ static const struct samsung_pin_bank_type exynos850_bank_type_off  = {
>   * Bank type for alive type. Bit fields:
>   * CON: 4, DAT: 1, PUD: 4, DRV: 4
>   */
> -static const struct samsung_pin_bank_type exynos850_bank_type_alive = {
> +static const struct samsung_pin_bank_type exynos9_bank_type_alive = {
>  	.fld_width = { 4, 1, 4, 4, },
>  	.reg_offset = { 0x00, 0x04, 0x08, 0x0c, },
>  };
> @@ -90,11 +90,11 @@ static atomic_t exynos_shared_retention_refcnt;
>  
>  /* pin banks of exynos2200 pin-controller - ALIVE */
>  static const struct samsung_pin_bank_data exynos2200_pin_banks0[] __initconst = {
> -	EXYNOS850_PIN_BANK_EINTW(8, 0x0, "gpa0", 0x00),
> -	EXYNOS850_PIN_BANK_EINTW(8, 0x20, "gpa1", 0x04),
> -	EXYNOS850_PIN_BANK_EINTW(8, 0x40, "gpa2", 0x08),
> -	EXYNOS850_PIN_BANK_EINTW(8, 0x60, "gpa3", 0x0c),
> -	EXYNOS850_PIN_BANK_EINTW(2, 0x80, "gpa4", 0x10),
> +	EXYNOS9_PIN_BANK_EINTW(exynos9_bank_type_alive, 8, 0x0, "gpa0", 0x00),

And this is less readable.

Best regards,
Krzysztof


From krzk at kernel.org  Sun Dec 28 03:41:44 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sun, 28 Dec 2025 12:41:44 +0100
Subject: [PATCH v3 3/5] pinctrl: samsung: add per-bank FLTCON offset to
 EXYNOS9_PIN_BANK_* and fix tables
In-Reply-To: <20251202093613.852109-4-youngmin.nam@samsung.com>
References: <20251202093613.852109-1-youngmin.nam@samsung.com>
 <CGME20251202093028epcas2p456b6a2bfebfc76384f706a9962266fcf@epcas2p4.samsung.com>
 <20251202093613.852109-4-youngmin.nam@samsung.com>
Message-ID: <39a6dce9-ea6e-4a43-9bbc-54d822118db4@kernel.org>

On 02/12/2025 10:36, Youngmin Nam wrote:
> Several Exynos9-era pin-bank tables were implicitly assuming that the
> filter control (FLTCON) registers are laid out contiguously from the
> EINT base offset. Per the TRMs this is not always true. FLTCON can live
> at a separate per-bank offset, and the current tables cause the driver
> to program the wrong FLTCON addresses for some banks.

"Can live" or "Does live"? Adding unused offset is not improving the
code. The implicit offset is fine, if it is correct.


Best regards,
Krzysztof


From krzk at kernel.org  Sun Dec 28 03:43:51 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sun, 28 Dec 2025 12:43:51 +0100
Subject: [PATCH v3 5/5] pinctrl: samsung: rename gs101_pinctrl_* to
 exynos9_pinctrl_*
In-Reply-To: <20251202093613.852109-6-youngmin.nam@samsung.com>
References: <20251202093613.852109-1-youngmin.nam@samsung.com>
 <CGME20251202093029epcas2p19224bab81f8ed2b9f63613fdd010ab57@epcas2p1.samsung.com>
 <20251202093613.852109-6-youngmin.nam@samsung.com>
Message-ID: <20d454a7-1606-4418-8996-6755c1ea3180@kernel.org>

On 02/12/2025 10:36, Youngmin Nam wrote:
> The suspend/resume helpers named gs101_pinctrl_{suspend,resume} are not
> GS101-specific. They implement the generic save/restore sequence used by
> Exynos9-style controllers that have EINT filter configuration
> (eint_fltcon) to preserve.
> 
> Rename them to exynos9_pinctrl_{suspend,resume} and update all users:

Why? Exynos9 does not exist, there is no such SoC. All other SoCs can
use GS101 naming, just like GS101 could use Exynos-foo. You need to come
with a reason why Exynos9 is better than GS101.


Best regards,
Krzysztof


From Markus.Elfring at web.de  Sun Dec 28 04:31:52 2025
From: Markus.Elfring at web.de (Markus Elfring)
Date: Sun, 28 Dec 2025 13:31:52 +0100
Subject: [PATCH] phy: rockchip: inno-usb2: Fix a double free bug in
 rockchip_usb2phy_probe()
In-Reply-To: <20251226041711.2369638-1-vulab@iscas.ac.cn>
References: <20251226041711.2369638-1-vulab@iscas.ac.cn>
Message-ID: <0108245e-1979-4eba-97e1-eb2056294c0e@web.de>

?
> Fix by using a separate label to avoid the duplicate of_node_put().

May you return directly?
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/coding-style.rst?h=v6.19-rc2#n532


See also once more:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/submitting-patches.rst?h=v6.19-rc2#n659

Regards,
Markus



From zilin at seu.edu.cn  Sun Dec 28 04:52:26 2025
From: zilin at seu.edu.cn (Zilin Guan)
Date: Sun, 28 Dec 2025 12:52:26 +0000
Subject: [PATCH] soc: mediatek: SVS: Fix memory leak in svs_enable_debug_write()
Message-ID: <20251228125226.3684517-1-zilin@seu.edu.cn>

In svs_enable_debug_write(), the buf is allocated via memdup_user_nul().
If kstrtoint() fails, the function returns directly without freeing the
allocated memory, leading to a memory leak.

Fix this by freeing buf before returning the error code.

Fixes: 13f1bbcfb582 ("soc: mediatek: SVS: add debug commands")
Co-developed-by: Jianhao Xu <jianhao.xu at seu.edu.cn>
Signed-off-by: Jianhao Xu <jianhao.xu at seu.edu.cn>
Signed-off-by: Zilin Guan <zilin at seu.edu.cn>
---
 drivers/soc/mediatek/mtk-svs.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c
index f45537546553..691e7e6be654 100644
--- a/drivers/soc/mediatek/mtk-svs.c
+++ b/drivers/soc/mediatek/mtk-svs.c
@@ -799,8 +799,10 @@ static ssize_t svs_enable_debug_write(struct file *filp,
 		return PTR_ERR(buf);
 
 	ret = kstrtoint(buf, 10, &enabled);
-	if (ret)
+	if (ret) {
+		kfree(buf);
 		return ret;
+	}
 
 	if (!enabled) {
 		svs_bank_disable_and_restore_default_volts(svsp, svsb);
-- 
2.34.1



From Markus.Elfring at web.de  Sun Dec 28 04:55:07 2025
From: Markus.Elfring at web.de (Markus Elfring)
Date: Sun, 28 Dec 2025 13:55:07 +0100
Subject: [PATCH] soc: ti: pruss: fix double free in pruss_clk_mux_setup()
In-Reply-To: <20251225143256.2363630-1-vulab@iscas.ac.cn>
References: <20251225143256.2363630-1-vulab@iscas.ac.cn>
Message-ID: <8570d445-30d9-4742-afc6-5484cb7d3d75@web.de>

?
> Fix by using a separate label to avoid the duplicate of_node_put().

May you return directly?
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/coding-style.rst?h=v6.19-rc2#n532

Regards,
Markus


From robert.hoo.linux at gmail.com  Sun Dec 28 05:21:25 2025
From: robert.hoo.linux at gmail.com (Robert Hoo)
Date: Sun, 28 Dec 2025 21:21:25 +0800
Subject: [PATCH v2 4/5] KVM: arm64: Enable HDBSS support and handle HDBSSF
 events
In-Reply-To: <f8e59e80-33b2-47cd-a042-11f28cc61645@huawei.com>
References: <20251121092342.3393318-1-zhengtian10@huawei.com>
 <20251121092342.3393318-5-zhengtian10@huawei.com>
 <87df4cba-b191-49cf-9486-fc379470a6eb@gmail.com>
 <f8e59e80-33b2-47cd-a042-11f28cc61645@huawei.com>
Message-ID: <77111894-1b9f-4970-b41f-48e3a4c4b754@gmail.com>

On 12/24/2025 2:15 PM, Tian Zheng wrote:
> 
> 
> On 12/17/2025 9:39 PM, Robert Hoo wrote:
>> On 11/21/2025 5:23 PM, Tian Zheng wrote:
>>> From: eillon <yezhenyu2 at huawei.com>
>>>
>>> Implement the HDBSS enable/disable functionality using the
>>> KVM_CAP_ARM_HW_DIRTY_STATE_TRACK ioctl.
>>>
>>> Userspace (e.g., QEMU) can enable HDBSS by invoking the ioctl
>>> at the start of live migration, configuring the buffer size.
>>> The feature is disabled by invoking the ioctl again with size
>>> set to 0 once migration completes.
>>>
>>> Add support for updating the dirty bitmap based on the HDBSS
>>> buffer. Similar to the x86 PML implementation, KVM flushes the
>>> buffer on all VM-Exits, so running vCPUs only need to be kicked
>>> to force a VM-Exit.
>>>
>>> Signed-off-by: eillon <yezhenyu2 at huawei.com>
>>> Signed-off-by: Tian Zheng <zhengtian10 at huawei.com>
>>> ---
>>> ? arch/arm64/include/asm/kvm_host.h |? 10 +++
>>> ? arch/arm64/include/asm/kvm_mmu.h? |? 17 +++++
>>> ? arch/arm64/kvm/arm.c????????????? | 107 ++++++++++++++++++++++++++++++
>>> ? arch/arm64/kvm/handle_exit.c????? |? 45 +++++++++++++
>>> ? arch/arm64/kvm/hyp/vhe/switch.c?? |?? 1 +
>>> ? arch/arm64/kvm/mmu.c????????????? |? 10 +++
>>> ? arch/arm64/kvm/reset.c??????????? |?? 3 +
>>> ? include/linux/kvm_host.h????????? |?? 1 +
>>> ? 8 files changed, 194 insertions(+)
>>>
>>> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/ 
>>> asm/kvm_host.h
>>> index d962932f0e5f..408e4c2b3d1a 100644
>>> --- a/arch/arm64/include/asm/kvm_host.h
>>> +++ b/arch/arm64/include/asm/kvm_host.h
>>> @@ -87,6 +87,7 @@ int __init kvm_arm_init_sve(void);
>>> ? u32 __attribute_const__ kvm_target_cpu(void);
>>> ? void kvm_reset_vcpu(struct kvm_vcpu *vcpu);
>>> ? void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu);
>>> +void kvm_arm_vcpu_free_hdbss(struct kvm_vcpu *vcpu);
>>>
>>> ? struct kvm_hyp_memcache {
>>> ????? phys_addr_t head;
>>> @@ -793,6 +794,12 @@ struct vcpu_reset_state {
>>> ????? bool??????? reset;
>>> ? };
>>>
>>> +struct vcpu_hdbss_state {
>>> +??? phys_addr_t base_phys;
>>> +??? u32 size;
>>> +??? u32 next_index;
>>> +};
>>> +
>>> ? struct vncr_tlb;
>>>
>>> ? struct kvm_vcpu_arch {
>>> @@ -897,6 +904,9 @@ struct kvm_vcpu_arch {
>>>
>>> ????? /* Per-vcpu TLB for VNCR_EL2 -- NULL when !NV */
>>> ????? struct vncr_tlb??? *vncr_tlb;
>>> +
>>> +??? /* HDBSS registers info */
>>> +??? struct vcpu_hdbss_state hdbss;
>>> ? };
>>>
>>> ? /*
>>> diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/ 
>>> asm/kvm_mmu.h
>>> index e4069f2ce642..6ace1080aed5 100644
>>> --- a/arch/arm64/include/asm/kvm_mmu.h
>>> +++ b/arch/arm64/include/asm/kvm_mmu.h
>>> @@ -331,6 +331,23 @@ static __always_inline void __load_stage2(struct 
>>> kvm_s2_mmu *mmu,
>>> ????? asm(ALTERNATIVE("nop", "isb", ARM64_WORKAROUND_SPECULATIVE_AT));
>>> ? }
>>>
>>> +static __always_inline void __load_hdbss(struct kvm_vcpu *vcpu)
>>> +{
>>> +??? struct kvm *kvm = vcpu->kvm;
>>> +??? u64 br_el2, prod_el2;
>>> +
>>> +??? if (!kvm->enable_hdbss)
>>> +??????? return;
>>> +
>>> +??? br_el2 = HDBSSBR_EL2(vcpu->arch.hdbss.base_phys, vcpu- >arch.hdbss.size);
>>> +??? prod_el2 = vcpu->arch.hdbss.next_index;
>>> +
>>> +??? write_sysreg_s(br_el2, SYS_HDBSSBR_EL2);
>>> +??? write_sysreg_s(prod_el2, SYS_HDBSSPROD_EL2);
>>> +
>>> +??? isb();
>>> +}
>>> +
>>> ? static inline struct kvm *kvm_s2_mmu_to_kvm(struct kvm_s2_mmu *mmu)
>>> ? {
>>> ????? return container_of(mmu->arch, struct kvm, arch);
>>> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
>>> index 870953b4a8a7..64f65e3c2a89 100644
>>> --- a/arch/arm64/kvm/arm.c
>>> +++ b/arch/arm64/kvm/arm.c
>>> @@ -79,6 +79,92 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
>>> ????? return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE;
>>> ? }
>>>
>>> +void kvm_arm_vcpu_free_hdbss(struct kvm_vcpu *vcpu)
>>> +{
>>> +??? struct page *hdbss_pg = NULL;
>>> +
>>> +??? hdbss_pg = phys_to_page(vcpu->arch.hdbss.base_phys);
>>> +??? if (hdbss_pg)
>>> +??????? __free_pages(hdbss_pg, vcpu->arch.hdbss.size);
>>> +
>>> +??? vcpu->arch.hdbss = (struct vcpu_hdbss_state) {
>>> +??????? .base_phys = 0,
>>> +??????? .size = 0,
>>> +??????? .next_index = 0,
>>> +??? };
>>> +}
>>> +
>>> +static int kvm_cap_arm_enable_hdbss(struct kvm *kvm,
>>> +??????????????????? struct kvm_enable_cap *cap)
>>> +{
>>> +??? unsigned long i;
>>> +??? struct kvm_vcpu *vcpu;
>>> +??? struct page *hdbss_pg = NULL;
>>> +??? int size = cap->args[0];
>>> +??? int ret = 0;
>>> +
>>> +??? if (!system_supports_hdbss()) {
>>> +??????? kvm_err("This system does not support HDBSS!\n");
>>> +??????? return -EINVAL;
>>> +??? }
>>> +
>>> +??? if (size < 0 || size > HDBSS_MAX_SIZE) {
>>> +??????? kvm_err("Invalid HDBSS buffer size: %d!\n", size);
>>> +??????? return -EINVAL;
>>> +??? }
>>> +
>>
>> I think you should check if it's already enabled here. What if user space 
>> calls this twice?
> 
> Ok, I review the implement of qemu, when disable the hdbss feature in
> ram_save_cleanup, size=0 will be set, so here can add a check, if (size
> && kvm->arch.enable_hdbss), we will do nothing.
> 

I mean you should check if ' kvm->enable_hdbss' is already set, if so, return 
rather than alloc_pages() in below (you have allocated in previous call with 
valid 'size').

qemu is just one of the user space applications that would possibly call this 
API, you cannot rely on your qemu patch's flow/sequence as assumption to design 
a KVM API's implementation.

>>
>>> +??? /* Enable the HDBSS feature if size > 0, otherwise disable it. */
>>> +??? if (size) {
>>> +??????? kvm_for_each_vcpu(i, vcpu, kvm) {
>>> +??????????? hdbss_pg = alloc_pages(GFP_KERNEL_ACCOUNT, size);
>>> +??????????? if (!hdbss_pg) {
>>> +??????????????? kvm_err("Alloc HDBSS buffer failed!\n");
>>> +??????????????? ret = -ENOMEM;
>>> +??????????????? goto error_alloc;
>>> +??????????? }
>>> +
>>> +??????????? vcpu->arch.hdbss = (struct vcpu_hdbss_state) {
>>> +??????????????? .base_phys = page_to_phys(hdbss_pg),
>>> +??????????????? .size = size,
>>> +??????????????? .next_index = 0,
>>> +??????????? };
>>> +??????? }
>>> +
>>> +??????? kvm->enable_hdbss = true;
>>> +??????? kvm->arch.mmu.vtcr |= VTCR_EL2_HD | VTCR_EL2_HDBSS;
>>




From cleger at rivosinc.com  Sun Dec 28 05:50:43 2025
From: cleger at rivosinc.com (=?UTF-8?B?Q2zDqW1lbnQgTMOpZ2Vy?=)
Date: Sun, 28 Dec 2025 14:50:43 +0100
Subject: [External] [PATCH v8 4/5] perf: RISC-V: add support for SSE event
In-Reply-To: <CAEEQ3wmLvBy0rVCwP_LcF9ube0=a1K6QFyp9jnE7JRMXxL11nw@mail.gmail.com>
References: <20251105082639.342973-1-cleger@rivosinc.com> <20251105082639.342973-5-cleger@rivosinc.com>
 <CAEEQ3wnQiUdNVjUpdDgAx1=y76vSo66vCD0Wf3EGes274jnkxw@mail.gmail.com>
 <CADGDLFgnx3z9WMZBjURx7eEFeeDwb9tj+8WAik4siR_G8erk0Q@mail.gmail.com> <CAEEQ3wmLvBy0rVCwP_LcF9ube0=a1K6QFyp9jnE7JRMXxL11nw@mail.gmail.com>
Message-ID: <CADGDLFgN5QvqoKpe3HUK3K9qkkmsqKaXVDYkaJexhd7xZUGJCA@mail.gmail.com>

Hi Yunhui,

The specification states that each event ID act as the default
priority so there is no need to actually set another priority:
https://github.com/riscv-non-isa/riscv-sbi-doc/blob/master/src/ext-sse.adoc#software-event-priority

As I said, currently, the SSE infra is requiring a priority to be set
at registration time and most of the code passes 0 (which is wrong).
I'll rework that for my next version.

Thanks,

Cl?ment
Bu maybe I missed something

On Wed, Dec 17, 2025 at 3:22?AM yunhui cui <cuiyunhui at bytedance.com> wrote:
>
> Hi Cl?ment,
>
> On Wed, Dec 17, 2025 at 4:36?AM Cl?ment L?ger <cleger at rivosinc.com> wrote:
> >
> > On Fri, Dec 12, 2025 at 4:17?AM yunhui cui <cuiyunhui at bytedance.com> wrote:
> > >
> > > Hi Cl?ment,
> > >
> > > On Wed, Nov 5, 2025 at 4:29?PM Cl?ment L?ger <cleger at rivosinc.com> wrote:
> > > >
> > > > In order to use SSE within PMU drivers, register a SSE handler for the
> > > > local PMU event. Reuse the existing overflow IRQ handler and pass
> > > > appropriate pt_regs. Add a config option RISCV_PMU_SSE to select event
> > > > delivery via SSE events.
> > > >
> > > > Signed-off-by: Cl?ment L?ger <cleger at rivosinc.com>
> > > > ---
> > > >  drivers/perf/Kconfig           | 10 +++++
> > > >  drivers/perf/riscv_pmu.c       | 23 +++++++++++
> > > >  drivers/perf/riscv_pmu_sbi.c   | 71 +++++++++++++++++++++++++++++-----
> > > >  include/linux/perf/riscv_pmu.h |  5 +++
> > > >  4 files changed, 99 insertions(+), 10 deletions(-)
> > > >
> > > > diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig
> > > > index 638321fc9800..d6ffc2b036e5 100644
> > > > --- a/drivers/perf/Kconfig
> > > > +++ b/drivers/perf/Kconfig
> > > > @@ -105,6 +105,16 @@ config RISCV_PMU_SBI
> > > >           full perf feature support i.e. counter overflow, privilege mode
> > > >           filtering, counter configuration.
> > > >
> > > > +config RISCV_PMU_SBI_SSE
> > > > +       depends on RISCV_PMU && RISCV_SBI_SSE
> > > > +       bool "RISC-V PMU SSE events"
> > > > +       default n
> > > > +       help
> > > > +         Say y if you want to use SSE events to deliver PMU interrupts. This
> > > > +         provides a way to profile the kernel at any level by using NMI-like
> > > > +         SSE events. SSE events being really intrusive, this option allows
> > > > +         to select it only if needed.
> > > > +
> > > >  config STARFIVE_STARLINK_PMU
> > > >         depends on ARCH_STARFIVE || COMPILE_TEST
> > > >         depends on 64BIT
> > > > diff --git a/drivers/perf/riscv_pmu.c b/drivers/perf/riscv_pmu.c
> > > > index 7644147d50b4..dda2814801c0 100644
> > > > --- a/drivers/perf/riscv_pmu.c
> > > > +++ b/drivers/perf/riscv_pmu.c
> > > > @@ -13,6 +13,7 @@
> > > >  #include <linux/irqdesc.h>
> > > >  #include <linux/perf/riscv_pmu.h>
> > > >  #include <linux/printk.h>
> > > > +#include <linux/riscv_sbi_sse.h>
> > > >  #include <linux/smp.h>
> > > >  #include <linux/sched_clock.h>
> > > >
> > > > @@ -254,6 +255,24 @@ void riscv_pmu_start(struct perf_event *event, int flags)
> > > >         perf_event_update_userpage(event);
> > > >  }
> > > >
> > > > +#ifdef CONFIG_RISCV_PMU_SBI_SSE
> > > > +static void riscv_pmu_disable(struct pmu *pmu)
> > > > +{
> > > > +       struct riscv_pmu *rvpmu = to_riscv_pmu(pmu);
> > > > +
> > > > +       if (rvpmu->sse_evt)
> > > > +               sse_event_disable_local(rvpmu->sse_evt);
> > > > +}
> > > > +
> > > > +static void riscv_pmu_enable(struct pmu *pmu)
> > > > +{
> > > > +       struct riscv_pmu *rvpmu = to_riscv_pmu(pmu);
> > > > +
> > > > +       if (rvpmu->sse_evt)
> > > > +               sse_event_enable_local(rvpmu->sse_evt);
> > > > +}
> > > > +#endif
> > > > +
> > > >  static int riscv_pmu_add(struct perf_event *event, int flags)
> > > >  {
> > > >         struct riscv_pmu *rvpmu = to_riscv_pmu(event->pmu);
> > > > @@ -411,6 +430,10 @@ struct riscv_pmu *riscv_pmu_alloc(void)
> > > >                 .event_mapped   = riscv_pmu_event_mapped,
> > > >                 .event_unmapped = riscv_pmu_event_unmapped,
> > > >                 .event_idx      = riscv_pmu_event_idx,
> > > > +#ifdef CONFIG_RISCV_PMU_SBI_SSE
> > > > +               .pmu_enable     = riscv_pmu_enable,
> > > > +               .pmu_disable    = riscv_pmu_disable,
> > > > +#endif
> > > >                 .add            = riscv_pmu_add,
> > > >                 .del            = riscv_pmu_del,
> > > >                 .start          = riscv_pmu_start,
> > > > diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
> > > > index e255c1b069ec..c852f64a5022 100644
> > > > --- a/drivers/perf/riscv_pmu_sbi.c
> > > > +++ b/drivers/perf/riscv_pmu_sbi.c
> > > > @@ -17,6 +17,7 @@
> > > >  #include <linux/irqdomain.h>
> > > >  #include <linux/of_irq.h>
> > > >  #include <linux/of.h>
> > > > +#include <linux/riscv_sbi_sse.h>
> > > >  #include <linux/cpu_pm.h>
> > > >  #include <linux/sched/clock.h>
> > > >  #include <linux/soc/andes/irq.h>
> > > > @@ -1038,10 +1039,10 @@ static void pmu_sbi_start_overflow_mask(struct riscv_pmu *pmu,
> > > >                 pmu_sbi_start_ovf_ctrs_sbi(cpu_hw_evt, ctr_ovf_mask);
> > > >  }
> > > >
> > > > -static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
> > > > +static irqreturn_t pmu_sbi_ovf_handler(struct cpu_hw_events *cpu_hw_evt,
> > > > +                                      struct pt_regs *regs, bool from_sse)
> > > >  {
> > > >         struct perf_sample_data data;
> > > > -       struct pt_regs *regs;
> > > >         struct hw_perf_event *hw_evt;
> > > >         union sbi_pmu_ctr_info *info;
> > > >         int lidx, hidx, fidx;
> > > > @@ -1049,7 +1050,6 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
> > > >         struct perf_event *event;
> > > >         u64 overflow;
> > > >         u64 overflowed_ctrs = 0;
> > > > -       struct cpu_hw_events *cpu_hw_evt = dev;
> > > >         u64 start_clock = sched_clock();
> > > >         struct riscv_pmu_snapshot_data *sdata = cpu_hw_evt->snapshot_addr;
> > > >
> > > > @@ -1059,13 +1059,15 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
> > > >         /* Firmware counter don't support overflow yet */
> > > >         fidx = find_first_bit(cpu_hw_evt->used_hw_ctrs, RISCV_MAX_COUNTERS);
> > > >         if (fidx == RISCV_MAX_COUNTERS) {
> > > > -               csr_clear(CSR_SIP, BIT(riscv_pmu_irq_num));
> > > > +               if (!from_sse)
> > > > +                       csr_clear(CSR_SIP, BIT(riscv_pmu_irq_num));
> > > >                 return IRQ_NONE;
> > > >         }
> > > >
> > > >         event = cpu_hw_evt->events[fidx];
> > > >         if (!event) {
> > > > -               ALT_SBI_PMU_OVF_CLEAR_PENDING(riscv_pmu_irq_mask);
> > > > +               if (!from_sse)
> > > > +                       ALT_SBI_PMU_OVF_CLEAR_PENDING(riscv_pmu_irq_mask);
> > > >                 return IRQ_NONE;
> > > >         }
> > > >
> > > > @@ -1080,16 +1082,16 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
> > > >
> > > >         /*
> > > >          * Overflow interrupt pending bit should only be cleared after stopping
> > > > -        * all the counters to avoid any race condition.
> > > > +        * all the counters to avoid any race condition. When using SSE,
> > > > +        * interrupt is cleared when stopping counters.
> > > >          */
> > > > -       ALT_SBI_PMU_OVF_CLEAR_PENDING(riscv_pmu_irq_mask);
> > > > +       if (!from_sse)
> > > > +               ALT_SBI_PMU_OVF_CLEAR_PENDING(riscv_pmu_irq_mask);
> > > >
> > > >         /* No overflow bit is set */
> > > >         if (!overflow)
> > > >                 return IRQ_NONE;
> > > >
> > > > -       regs = get_irq_regs();
> > > > -
> > > >         for_each_set_bit(lidx, cpu_hw_evt->used_hw_ctrs, RISCV_MAX_COUNTERS) {
> > > >                 struct perf_event *event = cpu_hw_evt->events[lidx];
> > > >
> > > > @@ -1145,6 +1147,51 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
> > > >         return IRQ_HANDLED;
> > > >  }
> > > >
> > > > +static irqreturn_t pmu_sbi_ovf_irq_handler(int irq, void *dev)
> > > > +{
> > > > +       return pmu_sbi_ovf_handler(dev, get_irq_regs(), false);
> > > > +}
> > > > +
> > > > +#ifdef CONFIG_RISCV_PMU_SBI_SSE
> > > > +static int pmu_sbi_ovf_sse_handler(u32 evt, void *arg, struct pt_regs *regs)
> > > > +{
> > > > +       struct cpu_hw_events __percpu *hw_events = arg;
> > > > +       struct cpu_hw_events *hw_event = raw_cpu_ptr(hw_events);
> > > > +
> > > > +       pmu_sbi_ovf_handler(hw_event, regs, true);
> > > > +
> > > > +       return 0;
> > > > +}
> > > > +
> > > > +static int pmu_sbi_setup_sse(struct riscv_pmu *pmu)
> > > > +{
> > > > +       int ret;
> > > > +       struct sse_event *evt;
> > > > +       struct cpu_hw_events __percpu *hw_events = pmu->hw_events;
> > > > +
> > > > +       evt = sse_event_register(SBI_SSE_EVENT_LOCAL_PMU_OVERFLOW, 0,
> > > > +                                pmu_sbi_ovf_sse_handler, hw_events);
> > >
> > > As Radim suggested, we had better preset a priority for different
> > > events, such as these events and future ones:
> > > SBI_SSE_EVENT_LOCAL_HIGH_PRIO_RAS
> > > SBI_SSE_EVENT_LOCAL_DOUBLE_TRAP
> > > SBI_SSE_EVENT_GLOBAL_HIGH_PRIO_RAS
> > > SBI_SSE_EVENT_LOCAL_PMU_OVERFLOW
> > > SBI_SSE_EVENT_LOCAL_LOW_PRIO_RAS
> > > SBI_SSE_EVENT_GLOBAL_LOW_PRIO_RAS
> > > SBI_SSE_EVENT_LOCAL_SOFTWARE_INJECTED
> > > SBI_SSE_EVENT_LOCAL_UNKNOWN_NMI
> > > SBI_SSE_EVENT_GLOBAL_SOFTWARE_INJECTED
> >
> > Hey Yunhui,
> >
> > What do you mean exactly ? Events have default priority based on their
> > ID. However, the register call will set a priority = 0 for the event.
> > I'll modify that to allow using an optional priority (or even remove
> > it)
>
> Actually, each event needs to be assigned a reasonable priority.
> Reference: https://lore.kernel.org/all/CAEEQ3wmEVVHC=S795dFsQ9iM5Xkz-KOBe_CxXbvzyDBUo3wU6A at mail.gmail.com/
>
> >
> > Thanks,
> >
> > Cl?ment
> >
> > >
> > > Could you please help add a "global priority enum"?
> > >
> > >
> > > > +       if (IS_ERR(evt))
> > > > +               return PTR_ERR(evt);
> > > > +
> > > > +       ret = sse_event_enable(evt);
> > > > +       if (ret) {
> > > > +               sse_event_unregister(evt);
> > > > +               return ret;
> > > > +       }
> > > > +
> > > > +       pr_info("using SSE for PMU event delivery\n");
> > > > +       pmu->sse_evt = evt;
> > > > +
> > > > +       return ret;
> > > > +}
> > > > +#else
> > > > +static int pmu_sbi_setup_sse(struct riscv_pmu *pmu)
> > > > +{
> > > > +       return -EOPNOTSUPP;
> > > > +}
> > > > +#endif
> > > > +
> > > >  static int pmu_sbi_starting_cpu(unsigned int cpu, struct hlist_node *node)
> > > >  {
> > > >         struct riscv_pmu *pmu = hlist_entry_safe(node, struct riscv_pmu, node);
> > > > @@ -1195,6 +1242,10 @@ static int pmu_sbi_setup_irqs(struct riscv_pmu *pmu, struct platform_device *pde
> > > >         struct cpu_hw_events __percpu *hw_events = pmu->hw_events;
> > > >         struct irq_domain *domain = NULL;
> > > >
> > > > +       ret = pmu_sbi_setup_sse(pmu);
> > > > +       if (!ret)
> > > > +               return 0;
> > > > +
> > > >         if (riscv_isa_extension_available(NULL, SSCOFPMF)) {
> > > >                 riscv_pmu_irq_num = RV_IRQ_PMU;
> > > >                 riscv_pmu_use_irq = true;
> > > > @@ -1229,7 +1280,7 @@ static int pmu_sbi_setup_irqs(struct riscv_pmu *pmu, struct platform_device *pde
> > > >                 return -ENODEV;
> > > >         }
> > > >
> > > > -       ret = request_percpu_irq(riscv_pmu_irq, pmu_sbi_ovf_handler, "riscv-pmu", hw_events);
> > > > +       ret = request_percpu_irq(riscv_pmu_irq, pmu_sbi_ovf_irq_handler, "riscv-pmu", hw_events);
> > > >         if (ret) {
> > > >                 pr_err("registering percpu irq failed [%d]\n", ret);
> > > >                 return ret;
> > > > diff --git a/include/linux/perf/riscv_pmu.h b/include/linux/perf/riscv_pmu.h
> > > > index f82a28040594..08fdcf6baf4e 100644
> > > > --- a/include/linux/perf/riscv_pmu.h
> > > > +++ b/include/linux/perf/riscv_pmu.h
> > > > @@ -28,6 +28,8 @@
> > > >
> > > >  #define RISCV_PMU_CONFIG1_GUEST_EVENTS 0x1
> > > >
> > > > +struct sse_event;
> > > > +
> > > >  struct cpu_hw_events {
> > > >         /* currently enabled events */
> > > >         int                     n_events;
> > > > @@ -54,6 +56,9 @@ struct riscv_pmu {
> > > >         char            *name;
> > > >
> > > >         irqreturn_t     (*handle_irq)(int irq_num, void *dev);
> > > > +#ifdef CONFIG_RISCV_PMU_SBI_SSE
> > > > +       struct sse_event *sse_evt;
> > > > +#endif
> > > >
> > > >         unsigned long   cmask;
> > > >         u64             (*ctr_read)(struct perf_event *event);
> > > > --
> > > > 2.43.0
> > > >
> > >
> > > Thanks,
> > > Yunhui
>
> Thanks,
> Yunhui


From Markus.Elfring at web.de  Sun Dec 28 06:19:00 2025
From: Markus.Elfring at web.de (Markus Elfring)
Date: Sun, 28 Dec 2025 15:19:00 +0100
Subject: [PATCH] soc: mediatek: SVS: Fix memory leak in
 svs_enable_debug_write()
In-Reply-To: <20251228125226.3684517-1-zilin@seu.edu.cn>
References: <20251228125226.3684517-1-zilin@seu.edu.cn>
Message-ID: <20dca540-1c20-460a-9079-718db465c518@web.de>

?
> Fix this by freeing buf before returning the error code.

How do you think about to use the attribute ?__free(kfree)??
https://elixir.bootlin.com/linux/v6.19-rc2/source/include/linux/slab.h#L512
https://elixir.bootlin.com/linux/v6.19-rc2/source/drivers/soc/mediatek/mtk-svs.c#L785-L813

Regards,
Markus


From zenghui.yu at linux.dev  Sun Dec 28 06:27:48 2025
From: zenghui.yu at linux.dev (Zenghui Yu)
Date: Sun, 28 Dec 2025 22:27:48 +0800
Subject: [PATCH] arm64: Add support for TSV110 Spectre-BHB mitigation
In-Reply-To: <20251227092448.732059-1-yangjinqian1@huawei.com>
References: <20251227092448.732059-1-yangjinqian1@huawei.com>
Message-ID: <0c9456b1-d7c8-4a90-ac21-fa2e5ee4a170@linux.dev>

On 2025/12/27 17:24, Jinqian Yang wrote:
> The TSV110 processor is vulnerable to the Spectre-BHB (Branch History
> Buffer) attack, which can be exploited to leak information through
> branch prediction side channels. This commit adds the MIDR of TSV110
> to the list for software mitigation.
> 
> Signed-off-by: Jinqian Yang <yangjinqian1 at huawei.com>
> ---
>  arch/arm64/kernel/proton-pack.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/arch/arm64/kernel/proton-pack.c b/arch/arm64/kernel/proton-pack.c
> index 80a580e019c5..b3801f532b10 100644
> --- a/arch/arm64/kernel/proton-pack.c
> +++ b/arch/arm64/kernel/proton-pack.c
> @@ -887,6 +887,7 @@ static u8 spectre_bhb_loop_affected(void)
>  		MIDR_ALL_VERSIONS(MIDR_CORTEX_X2),
>  		MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2),
>  		MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V1),
> +		MIDR_ALL_VERSIONS(MIDR_HISI_TSV110),
>  		{},
>  	};
>  	static const struct midr_range spectre_bhb_k24_list[] = {

Looks good, thanks!

Reviewed-by: Zenghui Yu <zenghui.yu at linux.dev>

Zenghui


From leon at kernel.org  Sun Dec 28 06:49:09 2025
From: leon at kernel.org (Leon Romanovsky)
Date: Sun, 28 Dec 2025 16:49:09 +0200
Subject: [PATCH v2 4/8] dma-mapping: Separate DMA sync issuing and
 completion waiting
In-Reply-To: <CAGsJ_4zyascnpQ1cB-BMO9PDeeRZTBAh8Z-j-ip=RcxApa4zSg@mail.gmail.com>
References: <20251226225254.46197-1-21cnbao@gmail.com>
 <20251226225254.46197-5-21cnbao@gmail.com>
 <20251227200706.GN11869@unreal>
 <CAGsJ_4zyascnpQ1cB-BMO9PDeeRZTBAh8Z-j-ip=RcxApa4zSg@mail.gmail.com>
Message-ID: <20251228144909.GR11869@unreal>

On Sun, Dec 28, 2025 at 10:45:13AM +1300, Barry Song wrote:
> On Sun, Dec 28, 2025 at 9:07?AM Leon Romanovsky <leon at kernel.org> wrote:
> >
> > On Sat, Dec 27, 2025 at 11:52:44AM +1300, Barry Song wrote:
> > > From: Barry Song <baohua at kernel.org>
> > >
> > > Currently, arch_sync_dma_for_cpu and arch_sync_dma_for_device
> > > always wait for the completion of each DMA buffer. That is,
> > > issuing the DMA sync and waiting for completion is done in a
> > > single API call.
> > >
> > > For scatter-gather lists with multiple entries, this means
> > > issuing and waiting is repeated for each entry, which can hurt
> > > performance. Architectures like ARM64 may be able to issue all
> > > DMA sync operations for all entries first and then wait for
> > > completion together.
> > >
> > > To address this, arch_sync_dma_for_* now issues DMA operations in
> > > batch, followed by a flush. On ARM64, the flush is implemented
> > > using a dsb instruction within arch_sync_dma_flush().
> > >
> > > For now, add arch_sync_dma_flush() after each
> > > arch_sync_dma_for_*() call. arch_sync_dma_flush() is defined as a
> > > no-op on all architectures except arm64, so this patch does not
> > > change existing behavior. Subsequent patches will introduce true
> > > batching for SG DMA buffers.
> > >
> > > Cc: Leon Romanovsky <leon at kernel.org>
> > > Cc: Catalin Marinas <catalin.marinas at arm.com>
> > > Cc: Will Deacon <will at kernel.org>
> > > Cc: Marek Szyprowski <m.szyprowski at samsung.com>
> > > Cc: Robin Murphy <robin.murphy at arm.com>
> > > Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
> > > Cc: Ard Biesheuvel <ardb at kernel.org>
> > > Cc: Marc Zyngier <maz at kernel.org>
> > > Cc: Anshuman Khandual <anshuman.khandual at arm.com>
> > > Cc: Ryan Roberts <ryan.roberts at arm.com>
> > > Cc: Suren Baghdasaryan <surenb at google.com>
> > > Cc: Joerg Roedel <joro at 8bytes.org>
> > > Cc: Juergen Gross <jgross at suse.com>
> > > Cc: Stefano Stabellini <sstabellini at kernel.org>
> > > Cc: Oleksandr Tyshchenko <oleksandr_tyshchenko at epam.com>
> > > Cc: Tangquan Zheng <zhengtangquan at oppo.com>
> > > Signed-off-by: Barry Song <baohua at kernel.org>
> > > ---
> > >  arch/arm64/include/asm/cache.h |  6 ++++++
> > >  arch/arm64/mm/dma-mapping.c    |  4 ++--
> > >  drivers/iommu/dma-iommu.c      | 37 +++++++++++++++++++++++++---------
> > >  drivers/xen/swiotlb-xen.c      | 24 ++++++++++++++--------
> > >  include/linux/dma-map-ops.h    |  6 ++++++
> > >  kernel/dma/direct.c            |  8 ++++++--
> > >  kernel/dma/direct.h            |  9 +++++++--
> > >  kernel/dma/swiotlb.c           |  4 +++-
> > >  8 files changed, 73 insertions(+), 25 deletions(-)
> >
> > <...>
> >
> > > +#ifndef arch_sync_dma_flush
> > > +static inline void arch_sync_dma_flush(void)
> > > +{
> > > +}
> > > +#endif
> >
> > Over the weekend I realized a useful advantage of the ARCH_HAVE_* config
> > options: they make it straightforward to inspect the entire DMA path simply
> > by looking at the .config.
> 
> I am not quite sure how much this benefits users, as the same
> information could also be obtained by grepping for
> #define arch_sync_dma_flush in the source code.

It differs slightly. Users no longer need to grep around or guess whether this
platform used the arch_sync_dma_flush path. A simple grep for ARCH_HAVE_ in
/proc/config.gz provides the answer.

> 
> >
> > Thanks,
> > Reviewed-by: Leon Romanovsky <leonro at nvidia.com>
> 
> Thanks very much, Leon, for reviewing this over the weekend. One thing
> you might have missed is that I place arch_sync_dma_flush() after all
> arch_sync_dma_for_*() calls, for both single and sg cases. I also
> used a Python script to scan the code and verify that every
> arch_sync_dma_for_*() is followed by arch_sync_dma_flush(), to ensure
> that no call is left out.
> 
> In the subsequent patches, for sg cases, the per-entry flush is
> replaced by a single flush of the entire sg. Each sg case has
> different characteristics: some are straightforward, while others
> can be tricky and involve additional contexts.

I didn't overlook it, and I understand your rationale. However, this is
not how kernel patches should be structured. You should not introduce
code in patch X and then move it elsewhere in patch X + Y.

Place the code in the correct location from the start. Your patches are
small enough to review as is.

Thanks"
> 
> Thanks
> Barry


From leon at kernel.org  Sun Dec 28 06:50:41 2025
From: leon at kernel.org (Leon Romanovsky)
Date: Sun, 28 Dec 2025 16:50:41 +0200
Subject: [PATCH v2 5/8] dma-mapping: Support batch mode for
 dma_direct_sync_sg_for_*
In-Reply-To: <CAGsJ_4yA83-K7PXiEtyidzF_j6qqKkt92z485KBS9+zGe_rjnw@mail.gmail.com>
References: <20251226225254.46197-1-21cnbao@gmail.com>
 <20251226225254.46197-6-21cnbao@gmail.com>
 <20251227200933.GO11869@unreal>
 <CAGsJ_4yA83-K7PXiEtyidzF_j6qqKkt92z485KBS9+zGe_rjnw@mail.gmail.com>
Message-ID: <20251228145041.GS11869@unreal>

On Sun, Dec 28, 2025 at 09:52:05AM +1300, Barry Song wrote:
> On Sun, Dec 28, 2025 at 9:09?AM Leon Romanovsky <leon at kernel.org> wrote:
> >
> > On Sat, Dec 27, 2025 at 11:52:45AM +1300, Barry Song wrote:
> > > From: Barry Song <baohua at kernel.org>
> > >
> > > Instead of performing a flush per SG entry, issue all cache
> > > operations first and then flush once. This ultimately benefits
> > > __dma_sync_sg_for_cpu() and __dma_sync_sg_for_device().
> > >
> > > Cc: Leon Romanovsky <leon at kernel.org>
> > > Cc: Catalin Marinas <catalin.marinas at arm.com>
> > > Cc: Will Deacon <will at kernel.org>
> > > Cc: Marek Szyprowski <m.szyprowski at samsung.com>
> > > Cc: Robin Murphy <robin.murphy at arm.com>
> > > Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
> > > Cc: Ard Biesheuvel <ardb at kernel.org>
> > > Cc: Marc Zyngier <maz at kernel.org>
> > > Cc: Anshuman Khandual <anshuman.khandual at arm.com>
> > > Cc: Ryan Roberts <ryan.roberts at arm.com>
> > > Cc: Suren Baghdasaryan <surenb at google.com>
> > > Cc: Tangquan Zheng <zhengtangquan at oppo.com>
> > > Signed-off-by: Barry Song <baohua at kernel.org>
> > > ---
> > >  kernel/dma/direct.c | 14 +++++++-------
> > >  1 file changed, 7 insertions(+), 7 deletions(-)
> >
> > <...>
> >
> > > -             if (!dev_is_dma_coherent(dev)) {
> > > +             if (!dev_is_dma_coherent(dev))
> > >                       arch_sync_dma_for_device(paddr, sg->length,
> > >                                       dir);
> > > -                     arch_sync_dma_flush();
> > > -             }
> > >       }
> > > +     if (!dev_is_dma_coherent(dev))
> > > +             arch_sync_dma_flush();
> >
> > This patch should be squashed into the previous one. You introduced
> > arch_sync_dma_flush() there, and now you are placing it elsewhere.
> 
> Hi Leon,
> 
> The previous patch replaces all arch_sync_dma_for_* calls with
> arch_sync_dma_for_* plus arch_sync_dma_flush(), without any
> functional change. The subsequent patches then implement the
> actual batching. I feel this is a better approach for reviewing
> each change independently. Otherwise, the previous patch would
> be too large.

Don't worry about it. Your patches are small enough.

> 
> Thanks
> Barry


From olsajiri at gmail.com  Sun Dec 28 07:22:18 2025
From: olsajiri at gmail.com (Jiri Olsa)
Date: Sun, 28 Dec 2025 16:22:18 +0100
Subject: [PATCHv5 bpf-next 9/9] bpf,x86: Use single ftrace_ops for direct
 calls
In-Reply-To: <aUUanPijlWsDlS0X@krava>
References: <20251215211402.353056-1-jolsa@kernel.org>
 <20251215211402.353056-10-jolsa@kernel.org>
 <20251218112608.11a14a4a@gandalf.local.home>
 <aUUanPijlWsDlS0X@krava>
Message-ID: <aVFLKgZ56wt5aLci@krava>

On Fri, Dec 19, 2025 at 10:27:56AM +0100, Jiri Olsa wrote:

> > > diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
> > > index 4661b9e606e0..1ad2e307c834 100644
> > > --- a/kernel/trace/Kconfig
> > > +++ b/kernel/trace/Kconfig
> > > @@ -50,6 +50,9 @@ config HAVE_DYNAMIC_FTRACE_WITH_REGS
> > >  config HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
> > >  	bool
> > >  
> > > +config HAVE_SINGLE_FTRACE_DIRECT_OPS
> > > +	bool
> > > +
> > 
> > Now you could add:
> > 
> >   config SINGLE_FTRACE_DIRECT_OPS
> > 	bool
> > 	default y
> > 	depends on HAVE_SINGLE_FTRACE_DIRECT_OPS && DYNAMIC_FTRACE_WITH_DIRECT_CALLS
> 
> ok, the dependency is more ovbvious, will change
> 
> thanks,
> jirka

actualy, it seems that having it the original way with adding the rest
of the wrappers for !CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS case is
easier AFAICS

jirka


---
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 80527299f859..53bf2cf7ff6f 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -336,6 +336,7 @@ config X86
 	select SCHED_SMT			if SMP
 	select ARCH_SUPPORTS_SCHED_CLUSTER	if SMP
 	select ARCH_SUPPORTS_SCHED_MC		if SMP
+	select HAVE_SINGLE_FTRACE_DIRECT_OPS	if X86_64 && DYNAMIC_FTRACE_WITH_DIRECT_CALLS
 
 config INSTRUCTION_DECODER
 	def_bool y
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index e5a0d58ed6dc..a8b3f510280a 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -33,12 +33,40 @@ static DEFINE_MUTEX(trampoline_mutex);
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
 static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mutex);
 
+#ifdef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS
+static struct bpf_trampoline *direct_ops_ip_lookup(struct ftrace_ops *ops, unsigned long ip)
+{
+	struct hlist_head *head_ip;
+	struct bpf_trampoline *tr;
+
+	mutex_lock(&trampoline_mutex);
+	head_ip = &trampoline_ip_table[hash_64(ip, TRAMPOLINE_HASH_BITS)];
+	hlist_for_each_entry(tr, head_ip, hlist_ip) {
+		if (tr->ip == ip)
+			goto out;
+	}
+	tr = NULL;
+out:
+	mutex_unlock(&trampoline_mutex);
+	return tr;
+}
+#else
+static struct bpf_trampoline *direct_ops_ip_lookup(struct ftrace_ops *ops, unsigned long ip)
+{
+	return ops->private;
+}
+#endif /* CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS */
+
 static int bpf_tramp_ftrace_ops_func(struct ftrace_ops *ops, unsigned long ip,
 				     enum ftrace_ops_cmd cmd)
 {
-	struct bpf_trampoline *tr = ops->private;
+	struct bpf_trampoline *tr;
 	int ret = 0;
 
+	tr = direct_ops_ip_lookup(ops, ip);
+	if (!tr)
+		return -EINVAL;
+
 	if (cmd == FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_SELF) {
 		/* This is called inside register_ftrace_direct_multi(), so
 		 * tr->mutex is already locked.
@@ -137,6 +165,159 @@ void bpf_image_ksym_del(struct bpf_ksym *ksym)
 			   PAGE_SIZE, true, ksym->name);
 }
 
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
+#ifdef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS
+/*
+ * We have only single direct_ops which contains all the direct call
+ * sites and is the only global ftrace_ops for all trampolines.
+ *
+ * We use 'update_ftrace_direct_*' api for attachment.
+ */
+struct ftrace_ops direct_ops = {
+	.ops_func = bpf_tramp_ftrace_ops_func,
+};
+
+static int direct_ops_alloc(struct bpf_trampoline *tr)
+{
+	tr->fops = &direct_ops;
+	return 0;
+}
+
+static void direct_ops_free(struct bpf_trampoline *tr) { }
+
+static struct ftrace_hash *hash_from_ip(struct bpf_trampoline *tr, void *ptr)
+{
+	unsigned long ip, addr = (unsigned long) ptr;
+	struct ftrace_hash *hash;
+
+	ip = ftrace_location(tr->ip);
+	if (!ip)
+		return NULL;
+	hash = alloc_ftrace_hash(FTRACE_HASH_DEFAULT_BITS);
+	if (!hash)
+		return NULL;
+	if (bpf_trampoline_use_jmp(tr->flags))
+		addr = ftrace_jmp_set(addr);
+	if (!add_ftrace_hash_entry_direct(hash, ip, addr)) {
+		free_ftrace_hash(hash);
+		return NULL;
+	}
+	return hash;
+}
+
+static int direct_ops_add(struct bpf_trampoline *tr, void *addr)
+{
+	struct ftrace_hash *hash = hash_from_ip(tr, addr);
+	int err = -ENOMEM;
+
+	if (hash)
+		err = update_ftrace_direct_add(tr->fops, hash);
+	free_ftrace_hash(hash);
+	return err;
+}
+
+static int direct_ops_del(struct bpf_trampoline *tr, void *addr)
+{
+	struct ftrace_hash *hash = hash_from_ip(tr, addr);
+	int err = -ENOMEM;
+
+	if (hash)
+		err = update_ftrace_direct_del(tr->fops, hash);
+	free_ftrace_hash(hash);
+	return err;
+}
+
+static int direct_ops_mod(struct bpf_trampoline *tr, void *addr, bool lock_direct_mutex)
+{
+	struct ftrace_hash *hash = hash_from_ip(tr, addr);
+	int err = -ENOMEM;
+
+	if (hash)
+		err = update_ftrace_direct_mod(tr->fops, hash, lock_direct_mutex);
+	free_ftrace_hash(hash);
+	return err;
+}
+#else
+/*
+ * We allocate ftrace_ops object for each trampoline and it contains
+ * call site specific for that trampoline.
+ *
+ * We use *_ftrace_direct api for attachment.
+ */
+static int direct_ops_alloc(struct bpf_trampoline *tr)
+{
+	tr->fops = kzalloc(sizeof(struct ftrace_ops), GFP_KERNEL);
+	if (!tr->fops)
+		return -ENOMEM;
+	tr->fops->private = tr;
+	tr->fops->ops_func = bpf_tramp_ftrace_ops_func;
+	return 0;
+}
+
+static void direct_ops_free(struct bpf_trampoline *tr)
+{
+	if (tr->fops) {
+		ftrace_free_filter(tr->fops);
+		kfree(tr->fops);
+	}
+}
+
+static int direct_ops_add(struct bpf_trampoline *tr, void *ptr)
+{
+	unsigned long addr = (unsigned long) ptr;
+	struct ftrace_ops *ops = tr->fops;
+	int ret;
+
+	if (bpf_trampoline_use_jmp(tr->flags))
+		addr = ftrace_jmp_set(addr);
+
+	ret = ftrace_set_filter_ip(ops, tr->ip, 0, 1);
+	if (ret)
+		return ret;
+	return register_ftrace_direct(ops, addr);
+}
+
+static int direct_ops_del(struct bpf_trampoline *tr, void *addr)
+{
+	return unregister_ftrace_direct(tr->fops, (long)addr, false);
+}
+
+static int direct_ops_mod(struct bpf_trampoline *tr, void *ptr, bool lock_direct_mutex)
+{
+	unsigned long addr = (unsigned long) ptr;
+	struct ftrace_ops *ops = tr->fops;
+
+	if (bpf_trampoline_use_jmp(tr->flags))
+		addr = ftrace_jmp_set(addr);
+	if (lock_direct_mutex)
+		return modify_ftrace_direct(ops, addr);
+	return modify_ftrace_direct_nolock(ops, addr);
+}
+#endif /* CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS */
+#else
+static void direct_ops_free(struct bpf_trampoline *tr) { }
+
+static int direct_ops_alloc(struct bpf_trampoline *tr)
+{
+	return 0;
+}
+
+static int direct_ops_add(struct bpf_trampoline *tr, void *addr)
+{
+	return -ENODEV;
+}
+
+static int direct_ops_del(struct bpf_trampoline *tr, void *addr)
+{
+	return -ENODEV;
+}
+
+static int direct_ops_mod(struct bpf_trampoline *tr, void *ptr, bool lock_direct_mutex)
+{
+	return -ENODEV;
+}
+#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
+
 static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
 {
 	struct bpf_trampoline *tr;
@@ -154,16 +335,11 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
 	tr = kzalloc(sizeof(*tr), GFP_KERNEL);
 	if (!tr)
 		goto out;
-#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
-	tr->fops = kzalloc(sizeof(struct ftrace_ops), GFP_KERNEL);
-	if (!tr->fops) {
+	if (direct_ops_alloc(tr)) {
 		kfree(tr);
 		tr = NULL;
 		goto out;
 	}
-	tr->fops->private = tr;
-	tr->fops->ops_func = bpf_tramp_ftrace_ops_func;
-#endif
 
 	tr->key = key;
 	tr->ip = ftrace_location(ip);
@@ -206,7 +382,7 @@ static int unregister_fentry(struct bpf_trampoline *tr, u32 orig_flags,
 	int ret;
 
 	if (tr->func.ftrace_managed)
-		ret = unregister_ftrace_direct(tr->fops, (long)old_addr, false);
+		ret = direct_ops_del(tr, old_addr);
 	else
 		ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr, NULL);
 
@@ -220,15 +396,7 @@ static int modify_fentry(struct bpf_trampoline *tr, u32 orig_flags,
 	int ret;
 
 	if (tr->func.ftrace_managed) {
-		unsigned long addr = (unsigned long) new_addr;
-
-		if (bpf_trampoline_use_jmp(tr->flags))
-			addr = ftrace_jmp_set(addr);
-
-		if (lock_direct_mutex)
-			ret = modify_ftrace_direct(tr->fops, addr);
-		else
-			ret = modify_ftrace_direct_nolock(tr->fops, addr);
+		ret = direct_ops_mod(tr, new_addr, lock_direct_mutex);
 	} else {
 		ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr,
 						   new_addr);
@@ -251,15 +419,7 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
 	}
 
 	if (tr->func.ftrace_managed) {
-		unsigned long addr = (unsigned long) new_addr;
-
-		if (bpf_trampoline_use_jmp(tr->flags))
-			addr = ftrace_jmp_set(addr);
-
-		ret = ftrace_set_filter_ip(tr->fops, (unsigned long)ip, 0, 1);
-		if (ret)
-			return ret;
-		ret = register_ftrace_direct(tr->fops, addr);
+		ret = direct_ops_add(tr, new_addr);
 	} else {
 		ret = bpf_trampoline_update_fentry(tr, 0, NULL, new_addr);
 	}
@@ -910,10 +1070,7 @@ void bpf_trampoline_put(struct bpf_trampoline *tr)
 	 */
 	hlist_del(&tr->hlist_key);
 	hlist_del(&tr->hlist_ip);
-	if (tr->fops) {
-		ftrace_free_filter(tr->fops);
-		kfree(tr->fops);
-	}
+	direct_ops_free(tr);
 	kfree(tr);
 out:
 	mutex_unlock(&trampoline_mutex);
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index bfa2ec46e075..d7042a09fe46 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -50,6 +50,9 @@ config HAVE_DYNAMIC_FTRACE_WITH_REGS
 config HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
 	bool
 
+config HAVE_SINGLE_FTRACE_DIRECT_OPS
+	bool
+
 config HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS
 	bool
 
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 02030f62d737..4ed910d3d00d 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -2631,8 +2631,13 @@ unsigned long ftrace_find_rec_direct(unsigned long ip)
 static void call_direct_funcs(unsigned long ip, unsigned long pip,
 			      struct ftrace_ops *ops, struct ftrace_regs *fregs)
 {
-	unsigned long addr = READ_ONCE(ops->direct_call);
+	unsigned long addr;
 
+#ifdef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS
+	addr = ftrace_find_rec_direct(ip);
+#else
+	addr = READ_ONCE(ops->direct_call);
+#endif
 	if (!addr)
 		return;
 


From ulf.hansson at linaro.org  Sun Dec 28 07:51:04 2025
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Sun, 28 Dec 2025 16:51:04 +0100
Subject: [PATCH v4] pmdomain: imx: Fix reference count leak in imx_gpc_probe()
In-Reply-To: <20251211040252.497759-1-vulab@iscas.ac.cn>
References: <20251211040252.497759-1-vulab@iscas.ac.cn>
Message-ID: <CAPDyKFrPZqwDmgFuPfbpX+FF3-r9F-r+9+Mm5v8z5Wb7TQJvmg@mail.gmail.com>

On Thu, 11 Dec 2025 at 05:03, Wentao Liang <vulab at iscas.ac.cn> wrote:
>
> of_get_child_by_name() returns a node pointer with refcount incremented.
> Use the __free() attribute to manage the pgc_node reference, ensuring
> automatic of_node_put() cleanup when pgc_node goes out of scope.
>
> This eliminates the need for explicit error handling paths and avoids
> reference count leaks.
>
> Fixes: 721cabf6c660 ("soc: imx: move PGC handling to a new GPC driver")
> Cc: stable at vger.kernel.org
> Signed-off-by: Wentao Liang <vulab at iscas.ac.cn>

Applied for fixes, thanks!

Kind regards
Uffe


>
> ---
> Change in V4:
> - Fix typo error in code
>
> Change in V3:
> - Ensure variable is assigned when using cleanup attribute
>
> Change in V2:
> - Use __free() attribute instead of explicit of_node_put() calls
> ---
>  drivers/pmdomain/imx/gpc.c | 5 ++---
>  1 file changed, 2 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/pmdomain/imx/gpc.c b/drivers/pmdomain/imx/gpc.c
> index f18c7e6e75dd..56a78cc86584 100644
> --- a/drivers/pmdomain/imx/gpc.c
> +++ b/drivers/pmdomain/imx/gpc.c
> @@ -403,13 +403,12 @@ static int imx_gpc_old_dt_init(struct device *dev, struct regmap *regmap,
>  static int imx_gpc_probe(struct platform_device *pdev)
>  {
>         const struct imx_gpc_dt_data *of_id_data = device_get_match_data(&pdev->dev);
> -       struct device_node *pgc_node;
> +       struct device_node *pgc_node __free(device_node)
> +               = of_get_child_by_name(pdev->dev.of_node, "pgc");
>         struct regmap *regmap;
>         void __iomem *base;
>         int ret;
>
> -       pgc_node = of_get_child_by_name(pdev->dev.of_node, "pgc");
> -
>         /* bail out if DT too old and doesn't provide the necessary info */
>         if (!of_property_present(pdev->dev.of_node, "#power-domain-cells") &&
>             !pgc_node)
> --
> 2.34.1
>
>


From ulf.hansson at linaro.org  Sun Dec 28 07:51:11 2025
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Sun, 28 Dec 2025 16:51:11 +0100
Subject: [PATCH v2] pmdomain: mtk-pm-domains: improve spinlock recursion
 fix in probe with correcting reference count
In-Reply-To: <20251128041722.3540037-1-macpaul.lin@mediatek.com>
References: <20251128041722.3540037-1-macpaul.lin@mediatek.com>
Message-ID: <CAPDyKFranQ=UU5waLcw27E4SG30bps80DmGs+zZs6N9=iZa_zg@mail.gmail.com>

On Fri, 28 Nov 2025 at 05:17, Macpaul Lin <macpaul.lin at mediatek.com> wrote:
>
> Remove scpsys_get_legacy_regmap(), replacing its usage with
> of_find_node_with_property().  Explicitly call of_node_get(np) before each
> of_find_node_with_property() to maintain correct node reference counting.
>
> The of_find_node_with_property() function "consumes" its input by calling
> of_node_put() internally, whether or not it finds a match.
> Currently, dev->of_node (np) is passed multiple times in sequence without
> incrementing its reference count, causing it to be decremented multiple times
> and risking early memory release.
>
> Adding of_node_get(np) before each call balances the reference count,
> preventing premature node release.
>
> Fixes: c1bac49fe91f ("pmdomains: mtk-pm-domains: Fix spinlock recursion in probe")
> Cc: Stable at vger.kernel.org
> Signed-off-by: Macpaul Lin <macpaul.lin at mediatek.com>
> Tested-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>

Applied for fixes, thanks!

Kind regards
Uffe



> ---
>  drivers/pmdomain/mediatek/mtk-pm-domains.c | 21 ++++++---------------
>  1 file changed, 6 insertions(+), 15 deletions(-)
>
> Changes for v2:
>  - Rewording commit message.
>  - Add Fixes: and Tested-by: tag, thanks.
>
> diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c
> index 80561d27f2b2..f64f24d520dd 100644
> --- a/drivers/pmdomain/mediatek/mtk-pm-domains.c
> +++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c
> @@ -984,18 +984,6 @@ static void scpsys_domain_cleanup(struct scpsys *scpsys)
>         }
>  }
>
> -static struct device_node *scpsys_get_legacy_regmap(struct device_node *np, const char *pn)
> -{
> -       struct device_node *local_node;
> -
> -       for_each_child_of_node(np, local_node) {
> -               if (of_property_present(local_node, pn))
> -                       return local_node;
> -       }
> -
> -       return NULL;
> -}
> -
>  static int scpsys_get_bus_protection_legacy(struct device *dev, struct scpsys *scpsys)
>  {
>         const u8 bp_blocks[3] = {
> @@ -1017,7 +1005,8 @@ static int scpsys_get_bus_protection_legacy(struct device *dev, struct scpsys *s
>          * this makes it then possible to allocate the array of bus_prot
>          * regmaps and convert all to the new style handling.
>          */
> -       node = scpsys_get_legacy_regmap(np, "mediatek,infracfg");
> +       of_node_get(np);
> +       node = of_find_node_with_property(np, "mediatek,infracfg");
>         if (node) {
>                 regmap[0] = syscon_regmap_lookup_by_phandle(node, "mediatek,infracfg");
>                 of_node_put(node);
> @@ -1030,7 +1019,8 @@ static int scpsys_get_bus_protection_legacy(struct device *dev, struct scpsys *s
>                 regmap[0] = NULL;
>         }
>
> -       node = scpsys_get_legacy_regmap(np, "mediatek,smi");
> +       of_node_get(np);
> +       node = of_find_node_with_property(np, "mediatek,smi");
>         if (node) {
>                 smi_np = of_parse_phandle(node, "mediatek,smi", 0);
>                 of_node_put(node);
> @@ -1048,7 +1038,8 @@ static int scpsys_get_bus_protection_legacy(struct device *dev, struct scpsys *s
>                 regmap[1] = NULL;
>         }
>
> -       node = scpsys_get_legacy_regmap(np, "mediatek,infracfg-nao");
> +       of_node_get(np);
> +       node = of_find_node_with_property(np, "mediatek,infracfg-nao");
>         if (node) {
>                 regmap[2] = syscon_regmap_lookup_by_phandle(node, "mediatek,infracfg-nao");
>                 num_regmaps++;
> --
> 2.45.2
>


From ulf.hansson at linaro.org  Sun Dec 28 07:51:19 2025
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Sun, 28 Dec 2025 16:51:19 +0100
Subject: [PATCH v3 0/3] i.MX91/93 BLK-CTRL improvements
In-Reply-To: <20251215-v6-18-topic-imx93-blkctrl-v3-0-51dbd1333938@pengutronix.de>
References: <20251215-v6-18-topic-imx93-blkctrl-v3-0-51dbd1333938@pengutronix.de>
Message-ID: <CAPDyKFqjJV8=PH7bTkWKJD4Dc7JoT6p02mPMrKA3uGuAKGsYvQ@mail.gmail.com>

On Mon, 15 Dec 2025 at 20:18, Marco Felsch <m.felsch at pengutronix.de> wrote:
>
> Hi,
>
> there were several approaches to bring the sub-devices population
> mainline [1,2] but non of them made it upstream. Both approaches were
> part of either the i.MX93 LVDS or MIPI-CSI enablement.
>
> This small patchset decouples the blk-ctrl changes which allows the
> MIPI-CSI and LVDS patchstack to be rebased ontop of this patchset.
>
> Before adding the sub-device supprt, I converted the driver to devm_*
> only API.
>
> Regards,
>   Marco
>
> [1] https://lore.kernel.org/all/20250701-95_cam-v1-3-c5172bab387b at nxp.com/
> [2] https://lore.kernel.org/all/20250304154929.1785200-4-alexander.stein at ew.tq-group.com/
>
> ---
> Changes in v3:
> - Link to v2: https://lore.kernel.org/r/20251202-v6-18-topic-imx93-blkctrl-v2-0-e73501034adc at pengutronix.de
> - Add r-b (Frank)
> - Rebase to v6.19-rc1
>
> Changes in v2:
> - Link to v1: https://lore.kernel.org/r/20251201-v6-18-topic-imx93-blkctrl-v1-0-b57a72e60105 at pengutronix.de
> - Adapt patch2 commit message (Frank)
> - Check devm_pm_runtime_enable() return (Frank)
> - Add r-b tags (Frank, Alexander)
>
> ---
> Marco Felsch (3):
>       pmdomain: imx93-blk-ctrl: cleanup error path
>       pmdomain: imx93-blk-ctrl: convert to devm_* only
>       pmdomain: imx93-blk-ctrl: add support for optional subnodes
>
>  drivers/pmdomain/imx/imx93-blk-ctrl.c | 77 ++++++++++++++++-------------------
>  1 file changed, 36 insertions(+), 41 deletions(-)
> ---
> base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
> change-id: 20251201-v6-18-topic-imx93-blkctrl-341220f7084d
>
> Best regards,
> --
> Marco Felsch <m.felsch at pengutronix.de>
>

The series applied for next, thanks!

Kind regards
Uffe


From bjorn at mork.no  Sun Dec 28 08:11:06 2025
From: bjorn at mork.no (=?UTF-8?q?Bj=C3=B8rn=20Mork?=)
Date: Sun, 28 Dec 2025 17:11:06 +0100
Subject: [PATCH] mt7996: trust eeprom data from nvmem for now
Message-ID: <20251228161106.1424861-1-bjorn@mork.no>

The iFEM/eFEM classification does not currently support some of the ADIE
combinations in use by vendors. Trust nvmem provided data instead of
falling back to wrong defaults.

Signed-off-by: Bj?rn Mork <bjorn at mork.no>
---
 mt7996/eeprom.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
index 8f60772913b4..3e7670a60fea 100644
--- a/mt7996/eeprom.c
+++ b/mt7996/eeprom.c
@@ -172,7 +172,7 @@ static int mt7996_eeprom_load(struct mt7996_dev *dev)
 
 	if (ret && !mt7996_check_eeprom(dev)) {
 		dev->flash_mode = true;
-		goto out;
+		return 0;
 	}
 
 	if (!dev->flash_mode) {
-- 
2.47.3



From zilin at seu.edu.cn  Sun Dec 28 08:21:49 2025
From: zilin at seu.edu.cn (Zilin Guan)
Date: Sun, 28 Dec 2025 16:21:49 +0000
Subject: [PATCH] soc: mediatek: SVS: Fix memory leak in svs_enable_debug_write()
In-Reply-To: <20dca540-1c20-460a-9079-718db465c518@web.de>
References: <20dca540-1c20-460a-9079-718db465c518@web.de>
Message-ID: <20251228162149.3825287-1-zilin@seu.edu.cn>

On Sun, Dec 28, 2025 at 03:19:00PM+0100, Markus Elfring wrote:
> ?
> > Fix this by freeing buf before returning the error code.
> 
> How do you think about to use the attribute ?__free(kfree)??
> https://elixir.bootlin.com/linux/v6.19-rc2/source/include/linux/slab.h#L512
> https://elixir.bootlin.com/linux/v6.19-rc2/source/drivers/soc/mediatek/mtk-svs.c#L785-L813
> 
> Regards,
> Markus

Hi Markus,

Thanks for the suggestion.

I agree that using the "__free(kfree)" attribute is a good way to 
simplify memory management here. I will apply this change in the 
v2 patch.

Regards,
Zilin Guan


From zilin at seu.edu.cn  Sun Dec 28 08:26:36 2025
From: zilin at seu.edu.cn (Zilin Guan)
Date: Sun, 28 Dec 2025 16:26:36 +0000
Subject: [PATCH v2] soc: mediatek: svs: Fix memory leak in svs_enable_debug_write()
Message-ID: <20251228162636.3829733-1-zilin@seu.edu.cn>

In svs_enable_debug_write(), the buf allocated by memdup_user_nul()
is leaked if kstrtoint() fails.

Fix this by using __free(kfree) to automatically free buf, eliminating
the need for explicit kfree() calls and preventing leaks.

Fixes: 13f1bbcfb582 ("soc: mediatek: SVS: add debug commands")
Co-developed-by: Jianhao Xu <jianhao.xu at seu.edu.cn>
Signed-off-by: Jianhao Xu <jianhao.xu at seu.edu.cn>
Signed-off-by: Zilin Guan <zilin at seu.edu.cn>
---
Changes in v2:
- Use __free(kfree) to simplify memory management.
---
 drivers/soc/mediatek/mtk-svs.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c
index f45537546553..5ede59299613 100644
--- a/drivers/soc/mediatek/mtk-svs.c
+++ b/drivers/soc/mediatek/mtk-svs.c
@@ -789,7 +789,7 @@ static ssize_t svs_enable_debug_write(struct file *filp,
 	struct svs_bank *svsb = file_inode(filp)->i_private;
 	struct svs_platform *svsp = dev_get_drvdata(svsb->dev);
 	int enabled, ret;
-	char *buf = NULL;
+	char *buf __free(kfree) = NULL;
 
 	if (count >= PAGE_SIZE)
 		return -EINVAL;
@@ -807,8 +807,6 @@ static ssize_t svs_enable_debug_write(struct file *filp,
 		svsb->mode_support = SVSB_MODE_ALL_DISABLE;
 	}
 
-	kfree(buf);
-
 	return count;
 }
 
-- 
2.34.1



From shivendra.pratap at oss.qualcomm.com  Sun Dec 28 09:20:18 2025
From: shivendra.pratap at oss.qualcomm.com (Shivendra Pratap)
Date: Sun, 28 Dec 2025 22:50:18 +0530
Subject: [PATCH v19 00/10] Implement PSCI reboot mode driver for PSCI
 resets
Message-ID: <20251228-arm-psci-system_reset2-vendor-reboots-v19-0-ebb956053098@oss.qualcomm.com>

Userspace should be able to initiate device reboots using the various
PSCI SYSTEM_RESET and SYSTEM_RESET2 types defined by PSCI spec. This
patch series introduces psci-reboot-mode driver that registers with
reboot-mode framework to provide this functionality.

The PSCI system reset calls takes two arguments: reset_type and cookie.
It defines predefined reset types, such as warm and cold reset, and
vendor-specific reset types which are SoC vendor specific. To support
these requirements, the reboot-mode framework is enhanced in two key
ways:
1. 64-bit magic support: Extend reboot-mode to handle two 32-bit
arguments (reset_type and cookie) by encoding them into a single 64-bit
magic value.
2. Predefined modes: Add support for predefined reboot modes in the
framework.

With these enhancements, the patch series enables:
 - Warm reset and cold reset as predefined reboot modes.
 - Vendor-specific resets exposed as tunables, configurable via the
   SoC-specific device tree.

Together, these changes allow userspace to trigger all above PSCI resets
from userspace.

Currently three drivers register with reboot-mode framework -
syscon-reboot-mode, nvmem-reboot-mode and qcom-pon. Consolidated
list of commands currently added across various vendor DTs:
 mode-loader
 mode-normal
 mode-bootloader
 mode-charge
 mode-fastboot
 mode-reboot-ab-update
 mode-recovery
 mode-rescue
 mode-shutdown-thermal
 mode-shutdown-thermal-battery

On gs101 we also pass kernel-generated modes from kernel_restart()
or panic(), specifically DM verity's 'dm-verity device corrupted':
	mode-dm-verity-device-corrupted = <0x50>;

- thanks Andre' for providing this.

Detailed list of commands being used by syscon-reboot-mode:
    arm64/boot/dts/exynos/exynosautov9.dtsi:
	mode-bootloader = <EXYNOSAUTOV9_BOOT_BOOTLOADER>;
	mode-fastboot = <EXYNOSAUTOV9_BOOT_FASTBOOT>;
	mode-recovery = <EXYNOSAUTOV9_BOOT_RECOVERY>;

    arm64/boot/dts/exynos/google/gs101.dtsi:
    	mode-bootloader = <0xfc>;
    	mode-charge = <0x0a>;
    	mode-fastboot = <0xfa>;
    	mode-reboot-ab-update = <0x52>;
    	mode-recovery = <0xff>;
    	mode-rescue = <0xf9>;
    	mode-shutdown-thermal = <0x51>;
    	mode-shutdown-thermal-battery = <0x51>;

    arm64/boot/dts/hisilicon/hi3660-hikey960.dts:
    	mode-normal = <0x77665501>;
    	mode-bootloader = <0x77665500>;
    	mode-recovery = <0x77665502>;

    arm64/boot/dts/hisilicon/hi6220-hikey.dts:
    	mode-normal = <0x77665501>;
    	mode-bootloader = <0x77665500>;
    	mode-recovery = <0x77665502>;

    arm64/boot/dts/rockchip/px30.dtsi:
    	mode-bootloader = <BOOT_BL_DOWNLOAD>;
    	mode-fastboot = <BOOT_FASTBOOT>;
    	mode-loader = <BOOT_BL_DOWNLOAD>;
    	mode-normal = <BOOT_NORMAL>;
    	mode-recovery = <BOOT_RECOVERY>;

    arm64/boot/dts/rockchip/rk3308.dtsi:
    	mode-bootloader = <BOOT_BL_DOWNLOAD>;
    	mode-loader = <BOOT_BL_DOWNLOAD>;
    	mode-normal = <BOOT_NORMAL>;
    	mode-recovery = <BOOT_RECOVERY>;
    	mode-fastboot = <BOOT_FASTBOOT>;

    arm64/boot/dts/rockchip/rk3566-lckfb-tspi.dts:
    	mode-normal = <BOOT_NORMAL>;
    	mode-loader = <BOOT_BL_DOWNLOAD>;
			mode-recovery = <BOOT_RECOVERY>;
			mode-bootloader = <BOOT_FASTBOOT>;

Detailed list of commands being used by nvmem-reboot-mode:
    arm64/boot/dts/qcom/pmXXXX.dtsi:(multiple qcom DTs)
			mode-recovery = <0x01>;
			mode-bootloader = <0x02>;

The patch is tested on rb3Gen2, lemans-ride, lemans-evk, monaco-ride,
qcs615-ride.

@Florian/@Kathiravan, Please note that reset_type in DT needs to be
full in itself with 31st bit set. (eg: 0x80000000).

PS: As advised from Lorenzo, "PSCI maintainers should be added as
maintainers for psci-reboot-mode".

Previous discussions around SYSTEM_RESET2:
- https://lore.kernel.org/lkml/20230724223057.1208122-2-quic_eberman at quicinc.com/T/
- https://lore.kernel.org/all/4a679542-b48d-7e11-f33a-63535a5c68cb at quicinc.com/

Signed-off-by: Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>

Changes in v19:
- Add missing To/Cc entries (include devicetree list) ? Thanks to
  Krzysztof for pointing this out.
- Fix compilation error in reboot-mode.c for ARCH=powerpc by explicitly
  including <linux/slab.h>.
- Link to v18: https://lore.kernel.org/r/20251223-arm-psci-system_reset2-vendor-reboots-v18-0-32fa9e76efc3 at oss.qualcomm.com

Changes in v18:
 power: reset: reboot-mode: Remove devres based allocations
 - Update commit text for alignment. ? Bart
 - Read magic before assigning kzalloc(info) in reboot_mode_register. - Mukesh
 - Update error handling path. - Mukesh
By Bjorn
 - Expose sysfs for reboot-mode bisected to different series-
   Link: https://lore.kernel.org/all/20251222-next-15nov_expose_sysfs-v21-0-244614135fd8 at oss.qualcomm.com/
By Bjorn/Lorenzo/Mukesh
  power: reset: reboot-mode: Add support for 64 bit magic
  - Use FIELD_GET/FIELD_PREP for u64 magic wherever required.
  - Update commit text and add documentation for structure of 64 bit magic.
By Lorenzo
 - Remove direct reboot-mode registration by psci driver.
 - Add support for predefined reboot modes in reboot-mode framework.
 - Add psci-reboot-mode driver and implement a psci-resets to accommodate
   all psci-resets including warm, cold and customizable vendor-resets.
By Bjorn
 - Update DT patches for qcm6490, lemans, monaco and tolos.
  - Update commit text to include more details ? By Bjorn
For Alignment
 - dt-bindings: arm: Document reboot mode magic
   - Update reboot mode documentation to clarify that argument1 should provide
     full value of reset_type along with the 31st bit wherever required.
 - DT patches for qcm6490, lemans, monaco and tolos.
   - Provide full value of reset_type including 31st bit.(eg:0x80000001).
- Link to v17: https://lore.kernel.org/r/20251109-arm-psci-system_reset2-vendor-reboots-v17-0-46e085bca4cc at oss.qualcomm.com

Changes in v17:
 Remove the patch to synchronize list traversal - Bjorn
 power: reset: reboot-mode: Remove devres based allocations
   - Remove devres based allocations as a fix   - Bartosz
 power: reset: reboot-mode: Expose sysfs for registered reboot_modes
   - remove devres based allocations in create_reboot_mode_device
     and manually free resources on failure.    - Bartosz
   - Add driver data while creating reboot device and
     retrive the same in reboot_mode_show.      - Bartosz
   - Remove the mutex lock.
 firmware: psci: Implement vendor-specific resets as reboot-mode
   - Call put_device(np) once processing is complete - Pavan Kondeti
 Move reboot-mode to SOC DT wherever applicable - Mukesh Ojha
- Link to v16: https://lore.kernel.org/r/20251015-arm-psci-system_reset2-vendor-reboots-v16-0-b98aedaa23ee at oss.qualcomm.com

Changes in v16:
 firmware: psci: Implement vendor-specific resets as reboot-mode
  - Use GENMASK(31, 0) instead of 0xffffffff - by Kathiravan
- Link to v15: https://lore.kernel.org/r/20250922-arm-psci-system_reset2-vendor-reboots-v15-0-7ce3a08878f1 at oss.qualcomm.com

Changes in v15:
By Sebastian:
  power: reset: reboot-mode: Synchronize list traversal
   - Change mutex locking to scoped_guard() and a Fixes: tag
  power: reset: reboot-mode: Add device tree node-based registration
   - Change reboot_mode_register external call to use fwnode
  power: reset: reboot-mode: Expose sysfs for registered reboot_modes
   - Use sysfs_emit_at for printing sysfs entries
   - Add driver_name to struct reboot_mode_driver instead of passing
     as argument
   - Update reboot_mode_register, devm_reboot_mode_register and
     create_reboot_mode_device for same.
  firmware: psci: Implement vendor-specific resets as reboot-mode
   - Update psci to use updated reboot_mode_register and store driver_name
     to struct reboot_mode_driver
- Add DT nodes for PSCI SYSTEM_RESET2 types for lemans-evk, qcs8300-ride,
  monaco-evk and qcs615-ride boards.
- Link to v14: https://lore.kernel.org/r/20250815-arm-psci-system_reset2-vendor-reboots-v14-0-37d29f59ac9a at oss.qualcomm.com

Changes in v14:
- mode-dm-verity-device-corrupted documented in cover letter -by Andr?
 ABI Documentation:
- Updated KernelVersion in ABI documentation to reflect base commit
  version. ? by Andr?
- Revised ABI documentation to clarify space-separated format for
  supported reboot-mode commands. ? by Andr?
 power: reset: reboot-mode: Expose sysfs patch
- Modified `show_modes` to output a space-separated list of supported
  reboot modes ? by Andr?
- Added error handling in `create_reboot_mode_device()` to ensure
  proper cleanup on failure.
 firmware: psci:
- Locate psci/reboot-mode node using psci compatible. - by Krzysztof,
  Dmitry, Sudeep.
- Added error handling for additional code for compatible.
- Converted hex values to lowercase for consistency. ? by Andr?
- Introduced panic notifier to disable valid vendor-reset flag in
  panic path. ? by Andr?
- Added check for `psci_system_reset2` before registering vendor reset
  commands.
- Updated Commit text.
 dts: sa8775p:
- DT file name changed from sa8775p to lemans and commit text updated
  accordingly. ? for dt renaming in base commit (sa8775p to lemans).
- Link to v13: https://lore.kernel.org/r/20250727-arm-psci-system_reset2-vendor-reboots-v13-0-6b8d23315898 at oss.qualcomm.com

Changes in v13:
- Split patch1 into two (Synchronize list traversal and DT node-based
  registration) - by Dmitry.
- Move mutex lock inside get_reboot_mode_magic - by Dmitry.
- Reorder the patches ? pull patch8 for exposing reboot-mode sysfs before
  psci patch - to align the change in reboot-mode sysfs patch.
- Update patch- reboot-mode: Expose sysfs for registered reboot_modes
     - Introduce a driver_name in reboot_mode_register. This will be used
       in sysfs creation  -  by Arnd.
     - Update documentation and commit text for above.
     - Fix release function to properly call delete attr file.
     - Fix sparse warning for devres_find.
     - Add error handling for devres_find.
- Split ABI documentation as a separate patch and update ABI documentation
  for usage of driver-name in sysfs - by Arnd
- Update patch - psci: Implement vendor-specific resets as reboot-mode
     - Fix Kconfig for CONFIG related warning.
     - Add driver_name as "psci" in register call to reboot-mode - by Arnd
- Link to v12: https://lore.kernel.org/r/20250721-arm-psci-system_reset2-vendor-reboots-v12-0-87bac3ec422e at oss.qualcomm.com

Changes in v12:
- Added lock for list traversals in reboot-mode - by Dmitry.
- Added proper handling for BE and LE cases in reboot-mode - by Dmitry.
- Removed type casting for u64 to u32 conversions. Added limit checks
  and used bitwise operations for same - by Andrew.
- Link to v11: https://lore.kernel.org/r/20250717-arm-psci-system_reset2-vendor-reboots-v11-0-df3e2b2183c3 at oss.qualcomm.com

Changes in v11:
- Remove reference of cookie in reboot-mode ? Arnd/Rob
- Introduce 64-bit magic in reboot-mode to accommodate two 32-bit
  arguments ? Arnd
- Change reset-type to reboot-mode in psci device tree binding ? Arnd
	- binding no more mandates two arguments as in v10.
	- dt changes done to support this binding.
- Remove obvious comments in psci reset path ? Konrad
- Merge sysfs and ABI doc into single patch.
- Fix compilation issue on X86 configs.
- Fix warnings for pr_fmt.
- Link to v10: https://lore.kernel.org/all/569f154d-c714-1714-b898-83a42a38771c at oss.qualcomm.com/

Changes in V10:
- Change in reset-type binding to make cookie as a mandatory
  argument.
- Change reboot-mode binding to support additional argument
  "cookie".
 From Lorenzo:
- Use reboot-mode framework for implementing vendor-resets.
- Modify reboot-mode framework to support two arguments
  (magic and cookie).
- Expose sysfs for supported reboot-modes commands.
- List out all existing reboot-mode commands and their users.
   - Added this to cover letter.
 From Dmitry:
- Modify reboot-mode to support non-device based registration.
- Modify reboot-mode to create a class and device to expose
  sysfs interface.
- Link to v9: https://lore.kernel.org/all/20250303-arm-psci-system_reset2-vendor-reboots-v9-0-b2cf4a20feda at oss.qualcomm.com/

Changes in v9:
- Don't fallback to architecturally defined resets from Lorenzo.
- Link to v8: https://lore.kernel.org/r/20241107-arm-psci-system_reset2-vendor-reboots-v8-0-e8715fa65cb5 at quicinc.com

Changes in v8:
- Code style nits from Stephen
- Add rb3gen2
- Link to v7: https://lore.kernel.org/r/20241028-arm-psci-system_reset2-vendor-reboots-v7-0-a4c40b0ebc54 at quicinc.com

Changes in v7:
- Code style nits from Stephen
- Dropped unnecessary hunk from the sa8775p-ride patch
- Link to v6: https://lore.kernel.org/r/20241018-arm-psci-system_reset2-vendor-reboots-v6-0-50cbe88b0a24 at quicinc.com

Changes in v6:
- Rebase to v6.11 and fix trivial conflicts in qcm6490-idp
- Add sa8775p-ride support (same as qcm6490-idp)
- Link to v5: https://lore.kernel.org/r/20240617-arm-psci-system_reset2-vendor-reboots-v5-0-086950f650c8 at quicinc.com

Changes in v5:
- Drop the nested "items" in prep for future dtschema tools
- Link to v4: https://lore.kernel.org/r/20240611-arm-psci-system_reset2-vendor-reboots-v4-0-98f55aa74ae8 at quicinc.com

Changes in v4:
- Change mode- properties from uint32-matrix to uint32-array
- Restructure the reset-types node so only the restriction is in the
  if/then schemas and not the entire definition
- Link to v3: https://lore.kernel.org/r/20240515-arm-psci-system_reset2-vendor-reboots-v3-0-16dd4f9c0ab4 at quicinc.com

Changes in v3:
- Limit outer number of items to 1 for mode-* properties
- Move the reboot-mode for psci under a subnode "reset-types"
- Fix the DT node in qcm6490-idp so it doesn't overwrite the one from
  sc7820.dtsi
- Link to v2: https://lore.kernel.org/r/20240414-arm-psci-system_reset2-vendor-reboots-v2-0-da9a055a648f at quicinc.com

Changes in v2:
- Fixes to schema as suggested by Rob and Krzysztof
- Add qcm6490 idp as first Qualcomm device to support
- Link to v1: https://lore.kernel.org/r/20231117-arm-psci-system_reset2-vendor-reboots-v1-0-03c4612153e2 at quicinc.com

Changes in v1:
- Reference reboot-mode bindings as suggeted by Rob.
- Link to RFC: https://lore.kernel.org/r/20231030-arm-psci-system_reset2-vendor-reboots-v1-0-dcdd63352ad1 at quicinc.com

---
Shivendra Pratap (10):
      power: reset: reboot-mode: Remove devres based allocations
      power: reset: reboot-mode: Add support for 64 bit magic
      power: reset: reboot-mode: Add support for predefined reboot modes
      firmware: psci: Introduce command-based reset in psci_sys_reset
      dt-bindings: arm: Document reboot mode magic
      power: reset: Add psci-reboot-mode driver
      arm64: dts: qcom: qcm6490: Add psci reboot-modes
      arm64: dts: qcom: lemans: Add psci reboot-modes
      arm64: dts: qcom: monaco: Add psci reboot-modes
      arm64: dts: qcom: talos: Add psci reboot-modes

 Documentation/devicetree/bindings/arm/psci.yaml |  42 +++++++++
 arch/arm64/boot/dts/qcom/kodiak.dtsi            |   2 +-
 arch/arm64/boot/dts/qcom/lemans.dtsi            |   5 ++
 arch/arm64/boot/dts/qcom/monaco.dtsi            |   5 ++
 arch/arm64/boot/dts/qcom/qcm6490-idp.dts        |   7 ++
 arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts    |   7 ++
 arch/arm64/boot/dts/qcom/talos.dtsi             |   5 ++
 drivers/firmware/psci/psci.c                    |  46 +++++++++-
 drivers/power/reset/Kconfig                     |  10 +++
 drivers/power/reset/Makefile                    |   1 +
 drivers/power/reset/nvmem-reboot-mode.c         |  11 ++-
 drivers/power/reset/psci-reboot-mode.c          | 111 ++++++++++++++++++++++++
 drivers/power/reset/qcom-pon.c                  |   9 +-
 drivers/power/reset/reboot-mode.c               |  80 ++++++++++++-----
 drivers/power/reset/syscon-reboot-mode.c        |   9 +-
 include/linux/psci.h                            |   2 +
 include/linux/reboot-mode.h                     |  15 +++-
 17 files changed, 332 insertions(+), 35 deletions(-)
---
base-commit: cc3aa43b44bdb43dfbac0fcb51c56594a11338a8
change-id: 20250709-arm-psci-system_reset2-vendor-reboots-46c80044afcf

Best regards,
-- 
Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>



From shivendra.pratap at oss.qualcomm.com  Sun Dec 28 09:20:19 2025
From: shivendra.pratap at oss.qualcomm.com (Shivendra Pratap)
Date: Sun, 28 Dec 2025 22:50:19 +0530
Subject: [PATCH v19 01/10] power: reset: reboot-mode: Remove devres based
 allocations
In-Reply-To: <20251228-arm-psci-system_reset2-vendor-reboots-v19-0-ebb956053098@oss.qualcomm.com>
References: <20251228-arm-psci-system_reset2-vendor-reboots-v19-0-ebb956053098@oss.qualcomm.com>
Message-ID: <20251228-arm-psci-system_reset2-vendor-reboots-v19-1-ebb956053098@oss.qualcomm.com>

Devres APIs are intended for use in drivers, where the managed lifetime
of resources is tied directly to the driver attach/detach cycle. In
shared subsystem code, there is no guarantee that the subsystem
functions will only be called after a driver has been attached, nor that
they will not be referenced after the managed resources have been
released during driver detach.

To ensure correct lifetime handling, avoid using devres-based
allocations in the reboot-mode and explicitly handle allocation and
cleanup of resources.

Fixes: 4fcd504edbf7 ("power: reset: add reboot mode driver")
Signed-off-by: Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>
---
 drivers/power/reset/reboot-mode.c | 34 ++++++++++++++++++++++------------
 1 file changed, 22 insertions(+), 12 deletions(-)

diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c
index fba53f638da04655e756b5f8b7d2d666d1379535..3af6bc16a76daee686e8110b74e71b0e62b13ef8 100644
--- a/drivers/power/reset/reboot-mode.c
+++ b/drivers/power/reset/reboot-mode.c
@@ -3,6 +3,8 @@
  * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd
  */
 
+#define pr_fmt(fmt)	"reboot-mode: " fmt
+
 #include <linux/device.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -10,6 +12,7 @@
 #include <linux/of.h>
 #include <linux/reboot.h>
 #include <linux/reboot-mode.h>
+#include <linux/slab.h>
 
 #define PREFIX "mode-"
 
@@ -71,9 +74,11 @@ static int reboot_mode_notify(struct notifier_block *this,
 int reboot_mode_register(struct reboot_mode_driver *reboot)
 {
 	struct mode_info *info;
+	struct mode_info *next;
 	struct property *prop;
 	struct device_node *np = reboot->dev->of_node;
 	size_t len = strlen(PREFIX);
+	u32 magic;
 	int ret;
 
 	INIT_LIST_HEAD(&reboot->head);
@@ -82,19 +87,17 @@ int reboot_mode_register(struct reboot_mode_driver *reboot)
 		if (strncmp(prop->name, PREFIX, len))
 			continue;
 
-		info = devm_kzalloc(reboot->dev, sizeof(*info), GFP_KERNEL);
+		if (of_property_read_u32(np, prop->name, &magic)) {
+			pr_err("reboot mode %s without magic number\n", prop->name);
+			continue;
+		}
+
+		info = kzalloc(sizeof(*info), GFP_KERNEL);
 		if (!info) {
 			ret = -ENOMEM;
 			goto error;
 		}
 
-		if (of_property_read_u32(np, prop->name, &info->magic)) {
-			dev_err(reboot->dev, "reboot mode %s without magic number\n",
-				info->mode);
-			devm_kfree(reboot->dev, info);
-			continue;
-		}
-
 		info->mode = kstrdup_const(prop->name + len, GFP_KERNEL);
 		if (!info->mode) {
 			ret =  -ENOMEM;
@@ -102,8 +105,7 @@ int reboot_mode_register(struct reboot_mode_driver *reboot)
 		} else if (info->mode[0] == '\0') {
 			kfree_const(info->mode);
 			ret = -EINVAL;
-			dev_err(reboot->dev, "invalid mode name(%s): too short!\n",
-				prop->name);
+			pr_err("invalid mode name(%s): too short!\n", prop->name);
 			goto error;
 		}
 
@@ -116,8 +118,12 @@ int reboot_mode_register(struct reboot_mode_driver *reboot)
 	return 0;
 
 error:
-	list_for_each_entry(info, &reboot->head, list)
+	kfree(info);
+	list_for_each_entry_safe(info, next, &reboot->head, list) {
+		list_del(&info->list);
 		kfree_const(info->mode);
+		kfree(info);
+	}
 
 	return ret;
 }
@@ -130,11 +136,15 @@ EXPORT_SYMBOL_GPL(reboot_mode_register);
 int reboot_mode_unregister(struct reboot_mode_driver *reboot)
 {
 	struct mode_info *info;
+	struct mode_info *next;
 
 	unregister_reboot_notifier(&reboot->reboot_notifier);
 
-	list_for_each_entry(info, &reboot->head, list)
+	list_for_each_entry_safe(info, next, &reboot->head, list) {
+		list_del(&info->list);
 		kfree_const(info->mode);
+		kfree(info);
+	}
 
 	return 0;
 }

-- 
2.34.1



From shivendra.pratap at oss.qualcomm.com  Sun Dec 28 09:20:20 2025
From: shivendra.pratap at oss.qualcomm.com (Shivendra Pratap)
Date: Sun, 28 Dec 2025 22:50:20 +0530
Subject: [PATCH v19 02/10] power: reset: reboot-mode: Add support for 64
 bit magic
In-Reply-To: <20251228-arm-psci-system_reset2-vendor-reboots-v19-0-ebb956053098@oss.qualcomm.com>
References: <20251228-arm-psci-system_reset2-vendor-reboots-v19-0-ebb956053098@oss.qualcomm.com>
Message-ID: <20251228-arm-psci-system_reset2-vendor-reboots-v19-2-ebb956053098@oss.qualcomm.com>

Current reboot-mode supports a single 32-bit argument for any
supported mode. Some reboot-mode based drivers may require
passing two independent 32-bit arguments during a reboot
sequence, for uses-cases, where a mode requires an additional
argument. Such drivers may not be able to use the reboot-mode
driver. For example, ARM PSCI vendor-specific resets, need two
arguments for its operation ? reset_type and cookie, to complete
the reset operation. If a driver wants to implement this
firmware-based reset, it cannot use reboot-mode framework.

Introduce 64-bit magic values in reboot-mode driver to
accommodate up-to two 32-bit arguments.
u64 magic
--------------------------------------------
|    Higher 32 bit  |   Lower 32 bit       |
|	 arg2	    | 	    arg1	   |
--------------------------------------------

Update current reboot-mode drivers for 64-bit magic.

Reviewed-by: Umang Chheda <umang.chheda at oss.qualcomm.com>
Reviewed-by: Nirmesh Kumar Singh <nirmesh.singh at oss.qualcomm.com>
Signed-off-by: Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>
---
 drivers/power/reset/nvmem-reboot-mode.c  | 10 ++++++----
 drivers/power/reset/qcom-pon.c           |  8 +++++---
 drivers/power/reset/reboot-mode.c        | 24 ++++++++++++++++++------
 drivers/power/reset/syscon-reboot-mode.c |  8 +++++---
 include/linux/reboot-mode.h              |  6 +++++-
 5 files changed, 39 insertions(+), 17 deletions(-)

diff --git a/drivers/power/reset/nvmem-reboot-mode.c b/drivers/power/reset/nvmem-reboot-mode.c
index 41530b70cfc48c2a83fbbd96f523d5816960a0d1..b3d21d39b0f732254c40103db1b51fb7045ce344 100644
--- a/drivers/power/reset/nvmem-reboot-mode.c
+++ b/drivers/power/reset/nvmem-reboot-mode.c
@@ -16,15 +16,17 @@ struct nvmem_reboot_mode {
 	struct nvmem_cell *cell;
 };
 
-static int nvmem_reboot_mode_write(struct reboot_mode_driver *reboot,
-				    unsigned int magic)
+static int nvmem_reboot_mode_write(struct reboot_mode_driver *reboot, u64 magic)
 {
-	int ret;
 	struct nvmem_reboot_mode *nvmem_rbm;
+	u32 magic_arg1;
+	int ret;
 
+	/* Use low 32 bits of magic for argument_1 */
+	magic_arg1 = FIELD_GET(GENMASK_ULL(31, 0), magic);
 	nvmem_rbm = container_of(reboot, struct nvmem_reboot_mode, reboot);
 
-	ret = nvmem_cell_write(nvmem_rbm->cell, &magic, sizeof(magic));
+	ret = nvmem_cell_write(nvmem_rbm->cell, &magic_arg1, sizeof(magic_arg1));
 	if (ret < 0)
 		dev_err(reboot->dev, "update reboot mode bits failed\n");
 
diff --git a/drivers/power/reset/qcom-pon.c b/drivers/power/reset/qcom-pon.c
index 7e108982a582e8243c5c806bd4a793646b87189f..ccce1673b2ec47d02524edd44811d4f528c243e8 100644
--- a/drivers/power/reset/qcom-pon.c
+++ b/drivers/power/reset/qcom-pon.c
@@ -27,17 +27,19 @@ struct qcom_pon {
 	long reason_shift;
 };
 
-static int qcom_pon_reboot_mode_write(struct reboot_mode_driver *reboot,
-				    unsigned int magic)
+static int qcom_pon_reboot_mode_write(struct reboot_mode_driver *reboot, u64 magic)
 {
 	struct qcom_pon *pon = container_of
 			(reboot, struct qcom_pon, reboot_mode);
+	u32 magic_arg1;
 	int ret;
 
+	/* Use low 32 bits of magic for argument_1 */
+	magic_arg1 = FIELD_GET(GENMASK_ULL(31, 0), magic);
 	ret = regmap_update_bits(pon->regmap,
 				 pon->baseaddr + PON_SOFT_RB_SPARE,
 				 GENMASK(7, pon->reason_shift),
-				 magic << pon->reason_shift);
+				 magic_arg1 << pon->reason_shift);
 	if (ret < 0)
 		dev_err(pon->dev, "update reboot mode bits failed\n");
 
diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c
index 3af6bc16a76daee686e8110b74e71b0e62b13ef8..1e85f2c052c916e153c7c9ac0b184c91d7153402 100644
--- a/drivers/power/reset/reboot-mode.c
+++ b/drivers/power/reset/reboot-mode.c
@@ -18,12 +18,11 @@
 
 struct mode_info {
 	const char *mode;
-	u32 magic;
+	u64 magic;
 	struct list_head list;
 };
 
-static unsigned int get_reboot_mode_magic(struct reboot_mode_driver *reboot,
-					  const char *cmd)
+static u64 get_reboot_mode_magic(struct reboot_mode_driver *reboot, const char *cmd)
 {
 	const char *normal = "normal";
 	struct mode_info *info;
@@ -55,7 +54,7 @@ static int reboot_mode_notify(struct notifier_block *this,
 			      unsigned long mode, void *cmd)
 {
 	struct reboot_mode_driver *reboot;
-	unsigned int magic;
+	u64 magic;
 
 	reboot = container_of(this, struct reboot_mode_driver, reboot_notifier);
 	magic = get_reboot_mode_magic(reboot, cmd);
@@ -78,7 +77,8 @@ int reboot_mode_register(struct reboot_mode_driver *reboot)
 	struct property *prop;
 	struct device_node *np = reboot->dev->of_node;
 	size_t len = strlen(PREFIX);
-	u32 magic;
+	u32 magic_arg1;
+	u32 magic_arg2;
 	int ret;
 
 	INIT_LIST_HEAD(&reboot->head);
@@ -87,10 +87,13 @@ int reboot_mode_register(struct reboot_mode_driver *reboot)
 		if (strncmp(prop->name, PREFIX, len))
 			continue;
 
-		if (of_property_read_u32(np, prop->name, &magic)) {
+		if (of_property_read_u32(np, prop->name, &magic_arg1)) {
 			pr_err("reboot mode %s without magic number\n", prop->name);
 			continue;
 		}
+		/* Default magic_arg2 to zero */
+		if (of_property_read_u32_index(np, prop->name, 1, &magic_arg2))
+			magic_arg2 = 0;
 
 		info = kzalloc(sizeof(*info), GFP_KERNEL);
 		if (!info) {
@@ -98,6 +101,15 @@ int reboot_mode_register(struct reboot_mode_driver *reboot)
 			goto error;
 		}
 
+		/**
+		 * Format of u64 magic
+		 *-------------------------------------------
+		 *|    Higher 32 bit  |   Lower 32 bit      |
+		 *|        arg2       |       arg1          |
+		 *-------------------------------------------
+		 */
+		info->magic = FIELD_PREP(GENMASK_ULL(63, 32), magic_arg2) |
+			      FIELD_PREP(GENMASK_ULL(31, 0), magic_arg1);
 		info->mode = kstrdup_const(prop->name + len, GFP_KERNEL);
 		if (!info->mode) {
 			ret =  -ENOMEM;
diff --git a/drivers/power/reset/syscon-reboot-mode.c b/drivers/power/reset/syscon-reboot-mode.c
index e0772c9f70f7a19cd8ec8a0b7fdbbaa7ba44afd0..eb7fc5b7d6a7ed8a833d4920991c4c40b5b13ca7 100644
--- a/drivers/power/reset/syscon-reboot-mode.c
+++ b/drivers/power/reset/syscon-reboot-mode.c
@@ -20,16 +20,18 @@ struct syscon_reboot_mode {
 	u32 mask;
 };
 
-static int syscon_reboot_mode_write(struct reboot_mode_driver *reboot,
-				    unsigned int magic)
+static int syscon_reboot_mode_write(struct reboot_mode_driver *reboot, u64 magic)
 {
 	struct syscon_reboot_mode *syscon_rbm;
+	u32 magic_arg1;
 	int ret;
 
+	/* Use low 32 bits of magic for argument_1 */
+	magic_arg1 = FIELD_GET(GENMASK_ULL(31, 0), magic);
 	syscon_rbm = container_of(reboot, struct syscon_reboot_mode, reboot);
 
 	ret = regmap_update_bits(syscon_rbm->map, syscon_rbm->offset,
-				 syscon_rbm->mask, magic);
+				 syscon_rbm->mask, magic_arg1);
 	if (ret < 0)
 		dev_err(reboot->dev, "update reboot mode bits failed\n");
 
diff --git a/include/linux/reboot-mode.h b/include/linux/reboot-mode.h
index 4a2abb38d1d612ec0fdf05eb18c98b210f631b7f..a359dc0c6dede0ac5ce67190a00d46a7e7856707 100644
--- a/include/linux/reboot-mode.h
+++ b/include/linux/reboot-mode.h
@@ -2,10 +2,14 @@
 #ifndef __REBOOT_MODE_H__
 #define __REBOOT_MODE_H__
 
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/types.h>
+
 struct reboot_mode_driver {
 	struct device *dev;
 	struct list_head head;
-	int (*write)(struct reboot_mode_driver *reboot, unsigned int magic);
+	int (*write)(struct reboot_mode_driver *reboot, u64 magic);
 	struct notifier_block reboot_notifier;
 };
 

-- 
2.34.1



From shivendra.pratap at oss.qualcomm.com  Sun Dec 28 09:20:21 2025
From: shivendra.pratap at oss.qualcomm.com (Shivendra Pratap)
Date: Sun, 28 Dec 2025 22:50:21 +0530
Subject: [PATCH v19 03/10] power: reset: reboot-mode: Add support for
 predefined reboot modes
In-Reply-To: <20251228-arm-psci-system_reset2-vendor-reboots-v19-0-ebb956053098@oss.qualcomm.com>
References: <20251228-arm-psci-system_reset2-vendor-reboots-v19-0-ebb956053098@oss.qualcomm.com>
Message-ID: <20251228-arm-psci-system_reset2-vendor-reboots-v19-3-ebb956053098@oss.qualcomm.com>

reboot-mode based drivers can define a reboot-mode by adding it under
the reboot-mode node in device tree. This limits such drivers, to define
any predefined reboot-modes statically within the driver and creates a
dependency on device-tree.

Introduce a list for predefined modes in the reboot-mode framework and
process the predefined reboot-modes along with the device-tree defined
reboot-modes. Modify existing reboot-mode based drivers to initialize
the predefined list-head as empty.

This patch enables a reboot mode driver to define reboot-modes through a
predefined static list, in addition to the device-tree based reboot-modes.

Signed-off-by: Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>
---
 drivers/power/reset/nvmem-reboot-mode.c  |  1 +
 drivers/power/reset/qcom-pon.c           |  1 +
 drivers/power/reset/reboot-mode.c        | 28 ++++++++++++++++++++++------
 drivers/power/reset/syscon-reboot-mode.c |  1 +
 include/linux/reboot-mode.h              |  9 +++++++++
 5 files changed, 34 insertions(+), 6 deletions(-)

diff --git a/drivers/power/reset/nvmem-reboot-mode.c b/drivers/power/reset/nvmem-reboot-mode.c
index b3d21d39b0f732254c40103db1b51fb7045ce344..b02a2af31aac52cb0ab19cf5d4d315d17c208f6e 100644
--- a/drivers/power/reset/nvmem-reboot-mode.c
+++ b/drivers/power/reset/nvmem-reboot-mode.c
@@ -44,6 +44,7 @@ static int nvmem_reboot_mode_probe(struct platform_device *pdev)
 
 	nvmem_rbm->reboot.dev = &pdev->dev;
 	nvmem_rbm->reboot.write = nvmem_reboot_mode_write;
+	INIT_LIST_HEAD(&nvmem_rbm->reboot.predefined_modes);
 
 	nvmem_rbm->cell = devm_nvmem_cell_get(&pdev->dev, "reboot-mode");
 	if (IS_ERR(nvmem_rbm->cell)) {
diff --git a/drivers/power/reset/qcom-pon.c b/drivers/power/reset/qcom-pon.c
index ccce1673b2ec47d02524edd44811d4f528c243e8..bf7b9f0bcdcc4c168aa7ff8d6494122d898814b5 100644
--- a/drivers/power/reset/qcom-pon.c
+++ b/drivers/power/reset/qcom-pon.c
@@ -75,6 +75,7 @@ static int qcom_pon_probe(struct platform_device *pdev)
 		pon->reboot_mode.dev = &pdev->dev;
 		pon->reason_shift = reason_shift;
 		pon->reboot_mode.write = qcom_pon_reboot_mode_write;
+		INIT_LIST_HEAD(&pon->reboot_mode.predefined_modes);
 		error = devm_reboot_mode_register(&pdev->dev, &pon->reboot_mode);
 		if (error) {
 			dev_err(&pdev->dev, "can't register reboot mode\n");
diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c
index 1e85f2c052c916e153c7c9ac0b184c91d7153402..877c2459a3b2e47679ee2e9fbb9b0329dc3b1e0f 100644
--- a/drivers/power/reset/reboot-mode.c
+++ b/drivers/power/reset/reboot-mode.c
@@ -16,12 +16,6 @@
 
 #define PREFIX "mode-"
 
-struct mode_info {
-	const char *mode;
-	u64 magic;
-	struct list_head list;
-};
-
 static u64 get_reboot_mode_magic(struct reboot_mode_driver *reboot, const char *cmd)
 {
 	const char *normal = "normal";
@@ -72,6 +66,7 @@ static int reboot_mode_notify(struct notifier_block *this,
  */
 int reboot_mode_register(struct reboot_mode_driver *reboot)
 {
+	struct mode_info *info_predef;
 	struct mode_info *info;
 	struct mode_info *next;
 	struct property *prop;
@@ -83,6 +78,9 @@ int reboot_mode_register(struct reboot_mode_driver *reboot)
 
 	INIT_LIST_HEAD(&reboot->head);
 
+	if (!np)
+		goto predefined_modes;
+
 	for_each_property_of_node(np, prop) {
 		if (strncmp(prop->name, PREFIX, len))
 			continue;
@@ -124,6 +122,24 @@ int reboot_mode_register(struct reboot_mode_driver *reboot)
 		list_add_tail(&info->list, &reboot->head);
 	}
 
+predefined_modes:
+	list_for_each_entry(info_predef, &reboot->predefined_modes, list) {
+		info = kzalloc(sizeof(*info), GFP_KERNEL);
+		if (!info) {
+			ret = -ENOMEM;
+			goto error;
+		}
+
+		info->mode = kstrdup_const(info_predef->mode, GFP_KERNEL);
+		if (!info->mode) {
+			ret = -ENOMEM;
+			goto error;
+		}
+
+		info->magic = info_predef->magic;
+		list_add_tail(&info->list, &reboot->head);
+	}
+
 	reboot->reboot_notifier.notifier_call = reboot_mode_notify;
 	register_reboot_notifier(&reboot->reboot_notifier);
 
diff --git a/drivers/power/reset/syscon-reboot-mode.c b/drivers/power/reset/syscon-reboot-mode.c
index eb7fc5b7d6a7ed8a833d4920991c4c40b5b13ca7..74e2e14c5d87c54ac24ef63c7905b3266d736439 100644
--- a/drivers/power/reset/syscon-reboot-mode.c
+++ b/drivers/power/reset/syscon-reboot-mode.c
@@ -50,6 +50,7 @@ static int syscon_reboot_mode_probe(struct platform_device *pdev)
 	syscon_rbm->reboot.dev = &pdev->dev;
 	syscon_rbm->reboot.write = syscon_reboot_mode_write;
 	syscon_rbm->mask = 0xffffffff;
+	INIT_LIST_HEAD(&syscon_rbm->reboot.predefined_modes);
 
 	syscon_rbm->map = syscon_node_to_regmap(pdev->dev.parent->of_node);
 	if (IS_ERR(syscon_rbm->map))
diff --git a/include/linux/reboot-mode.h b/include/linux/reboot-mode.h
index a359dc0c6dede0ac5ce67190a00d46a7e7856707..bddec9b7f94187dcb056540df79eea34c25b1d0d 100644
--- a/include/linux/reboot-mode.h
+++ b/include/linux/reboot-mode.h
@@ -4,11 +4,20 @@
 
 #include <linux/bitfield.h>
 #include <linux/bits.h>
+#include <linux/reboot.h>
 #include <linux/types.h>
 
+struct mode_info {
+	const char *mode;
+	u64 magic;
+	struct list_head list;
+};
+
 struct reboot_mode_driver {
 	struct device *dev;
 	struct list_head head;
+	/* List of predefined reboot-modes, a reboot-mode-driver may populate. */
+	struct list_head predefined_modes;
 	int (*write)(struct reboot_mode_driver *reboot, u64 magic);
 	struct notifier_block reboot_notifier;
 };

-- 
2.34.1



From shivendra.pratap at oss.qualcomm.com  Sun Dec 28 09:20:22 2025
From: shivendra.pratap at oss.qualcomm.com (Shivendra Pratap)
Date: Sun, 28 Dec 2025 22:50:22 +0530
Subject: [PATCH v19 04/10] firmware: psci: Introduce command-based reset in
 psci_sys_reset
In-Reply-To: <20251228-arm-psci-system_reset2-vendor-reboots-v19-0-ebb956053098@oss.qualcomm.com>
References: <20251228-arm-psci-system_reset2-vendor-reboots-v19-0-ebb956053098@oss.qualcomm.com>
Message-ID: <20251228-arm-psci-system_reset2-vendor-reboots-v19-4-ebb956053098@oss.qualcomm.com>

PSCI currently supports only COLD reset and ARCH WARM reset based on the
Linux reboot_mode variable. The PSCI specification now includes
SYSTEM_RESET2 for vendor-specific resets, but there's no mechanism to
issue these through psci_sys_reset.

Add a command-based reset mechanism that allows external drivers to set
the psci reset command via a new psci_set_reset_cmd() function.

The psci command-based reset is disabled by default and the
psci_sys_reset follows its original flow until a psci_reset command is
set or a kernel panic is in progress.

Signed-off-by: Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>
---
 drivers/firmware/psci/psci.c | 46 ++++++++++++++++++++++++++++++++++++++++++--
 include/linux/psci.h         |  2 ++
 2 files changed, 46 insertions(+), 2 deletions(-)

diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c
index 38ca190d4a22d6e7e0f06420e8478a2b0ec2fe6f..ad7a3267276f9e26740aea99c11f171ac715f9ba 100644
--- a/drivers/firmware/psci/psci.c
+++ b/drivers/firmware/psci/psci.c
@@ -51,6 +51,15 @@ static int resident_cpu = -1;
 struct psci_operations psci_ops;
 static enum arm_smccc_conduit psci_conduit = SMCCC_CONDUIT_NONE;
 
+struct psci_sys_reset_params {
+	u32 system_reset;
+	u32 reset_type;
+	u32 cookie;
+	bool cmd;
+};
+
+static struct psci_sys_reset_params psci_reset;
+
 bool psci_tos_resident_on(int cpu)
 {
 	return cpu == resident_cpu;
@@ -80,6 +89,29 @@ static u32 psci_cpu_suspend_feature;
 static bool psci_system_reset2_supported;
 static bool psci_system_off2_hibernate_supported;
 
+/**
+ * psci_set_reset_cmd - Sets the psci_reset_cmd for command-based
+ * reset which will be used in psci_sys_reset call.
+ *
+ * @cmd_sys_rst2: Set to true for SYSTEM_RESET2 based resets.
+ * @cmd_reset_type: Set the reset_type argument for psci_sys_reset.
+ * @cmd_cookie: Set the cookie argument for psci_sys_reset.
+ */
+void psci_set_reset_cmd(bool cmd_sys_rst2, u32 cmd_reset_type, u32 cmd_cookie)
+{
+	if (cmd_sys_rst2 && psci_system_reset2_supported) {
+		psci_reset.system_reset = PSCI_FN_NATIVE(1_1, SYSTEM_RESET2);
+		psci_reset.reset_type = cmd_reset_type;
+		psci_reset.cookie = cmd_cookie;
+	} else {
+		psci_reset.system_reset = PSCI_0_2_FN_SYSTEM_RESET;
+		psci_reset.reset_type = 0;
+		psci_reset.cookie = 0;
+	}
+	psci_reset.cmd = true;
+}
+EXPORT_SYMBOL_GPL(psci_set_reset_cmd);
+
 static inline bool psci_has_ext_power_state(void)
 {
 	return psci_cpu_suspend_feature &
@@ -309,14 +341,24 @@ static int get_set_conduit_method(const struct device_node *np)
 static int psci_sys_reset(struct notifier_block *nb, unsigned long action,
 			  void *data)
 {
-	if ((reboot_mode == REBOOT_WARM || reboot_mode == REBOOT_SOFT) &&
-	    psci_system_reset2_supported) {
+	if (((reboot_mode == REBOOT_WARM || reboot_mode == REBOOT_SOFT) &&
+	     psci_system_reset2_supported) && (panic_in_progress() || !psci_reset.cmd)) {
 		/*
 		 * reset_type[31] = 0 (architectural)
 		 * reset_type[30:0] = 0 (SYSTEM_WARM_RESET)
 		 * cookie = 0 (ignored by the implementation)
 		 */
 		invoke_psci_fn(PSCI_FN_NATIVE(1_1, SYSTEM_RESET2), 0, 0, 0);
+	} else if (!panic_in_progress() && psci_reset.cmd) {
+		/*
+		 * Commands are being set in psci_set_reset_cmd
+		 * This issues, SYSTEM_RESET2 arch warm reset or
+		 * SYSTEM_RESET2 vendor-specific reset or
+		 * a SYSTEM_RESET cold reset in accordance with
+		 * the reboot-mode command.
+		 */
+		invoke_psci_fn(psci_reset.system_reset, psci_reset.reset_type,
+			       psci_reset.cookie, 0);
 	} else {
 		invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0);
 	}
diff --git a/include/linux/psci.h b/include/linux/psci.h
index 4ca0060a3fc42ba1ca751c7862fb4ad8dda35a4c..d13ceca88eab8932894051e7c86e806c2ad8a73a 100644
--- a/include/linux/psci.h
+++ b/include/linux/psci.h
@@ -45,8 +45,10 @@ struct psci_0_1_function_ids get_psci_0_1_function_ids(void);
 
 #if defined(CONFIG_ARM_PSCI_FW)
 int __init psci_dt_init(void);
+void psci_set_reset_cmd(bool cmd_sys_rst2, u32 cmd_reset_type, u32 cmd_cookie);
 #else
 static inline int psci_dt_init(void) { return 0; }
+static inline void psci_set_reset_cmd(bool cmd_sys_rst2, u32 cmd_reset_type, u32 cmd_cookie) { }
 #endif
 
 #if defined(CONFIG_ARM_PSCI_FW) && defined(CONFIG_ACPI)

-- 
2.34.1



From shivendra.pratap at oss.qualcomm.com  Sun Dec 28 09:20:23 2025
From: shivendra.pratap at oss.qualcomm.com (Shivendra Pratap)
Date: Sun, 28 Dec 2025 22:50:23 +0530
Subject: [PATCH v19 05/10] dt-bindings: arm: Document reboot mode magic
In-Reply-To: <20251228-arm-psci-system_reset2-vendor-reboots-v19-0-ebb956053098@oss.qualcomm.com>
References: <20251228-arm-psci-system_reset2-vendor-reboots-v19-0-ebb956053098@oss.qualcomm.com>
Message-ID: <20251228-arm-psci-system_reset2-vendor-reboots-v19-5-ebb956053098@oss.qualcomm.com>

Add bindings to describe vendor-specific reboot modes. Values here
correspond to valid parameters to vendor-specific reset types in PSCI
SYSTEM_RESET2 call.

Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>
---
 Documentation/devicetree/bindings/arm/psci.yaml | 42 +++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/psci.yaml b/Documentation/devicetree/bindings/arm/psci.yaml
index 6e2e0c551841111fbb0aa8c0951dca411b94035c..5fdcbf331ea5620363638feb6f8105427a87c00f 100644
--- a/Documentation/devicetree/bindings/arm/psci.yaml
+++ b/Documentation/devicetree/bindings/arm/psci.yaml
@@ -98,6 +98,26 @@ properties:
       [1] Kernel documentation - ARM idle states bindings
         Documentation/devicetree/bindings/cpu/idle-states.yaml
 
+  reboot-mode:
+    type: object
+    $ref: /schemas/power/reset/reboot-mode.yaml#
+    unevaluatedProperties: false
+    properties:
+      # "mode-normal" is just SYSTEM_RESET
+      mode-normal: false
+    patternProperties:
+      "^mode-.*$":
+        minItems: 1
+        maxItems: 2
+        description: |
+          Describes a vendor-specific reset type. The string after "mode-"
+          maps a reboot mode to the parameters in the PSCI SYSTEM_RESET2 call.
+
+          Parameters are named mode-xxx = <type[, cookie]>, where xxx is the
+          name of the magic reboot mode, type corresponds to the reset_type
+          and the values should be provided as per the PSCI SYSTEM_RESET2
+          specs. The cookie value is optional and defaulted to zero.
+
 patternProperties:
   "^power-domain-":
     $ref: /schemas/power/power-domain.yaml#
@@ -137,6 +157,15 @@ allOf:
       required:
         - cpu_off
         - cpu_on
+  - if:
+      not:
+        properties:
+          compatible:
+            contains:
+              const: arm,psci-1.0
+    then:
+      properties:
+        reboot-mode: false
 
 additionalProperties: false
 
@@ -260,4 +289,17 @@ examples:
         domain-idle-states = <&cluster_ret>, <&cluster_pwrdn>;
       };
     };
+
+  - |+
+
+    // Case 5: SYSTEM_RESET2 vendor resets
+    psci {
+      compatible = "arm,psci-1.0";
+      method = "smc";
+
+      reboot-mode {
+        mode-edl = <0x80000000 1>;
+        mode-bootloader = <0x80010001 2>;
+      };
+    };
 ...

-- 
2.34.1



From shivendra.pratap at oss.qualcomm.com  Sun Dec 28 09:20:24 2025
From: shivendra.pratap at oss.qualcomm.com (Shivendra Pratap)
Date: Sun, 28 Dec 2025 22:50:24 +0530
Subject: [PATCH v19 06/10] power: reset: Add psci-reboot-mode driver
In-Reply-To: <20251228-arm-psci-system_reset2-vendor-reboots-v19-0-ebb956053098@oss.qualcomm.com>
References: <20251228-arm-psci-system_reset2-vendor-reboots-v19-0-ebb956053098@oss.qualcomm.com>
Message-ID: <20251228-arm-psci-system_reset2-vendor-reboots-v19-6-ebb956053098@oss.qualcomm.com>

PSCI supports different types of resets like COLD reset, ARCH WARM
reset, vendor-specific resets. Currently there is no common driver that
handles all supported psci resets at one place. Additionally, there is
no common mechanism to issue the supported psci resets from userspace.

Add a PSCI reboot mode driver and define two types of PSCI resets in the
driver as reboot-modes: predefined resets controlled by Linux
reboot_mode and customizable resets defined by SoC vendors in their
device tree under the psci:reboot-mode node.

Register the driver with the reboot-mode framework to interface these
resets to userspace. When userspace initiates a supported command, pass
the reset arguments to the PSCI driver to enable command-based reset.

This change allows userspace to issue supported PSCI reset commands
using the standard reboot system calls while enabling SoC vendors to
define their specific resets for PSCI.

Signed-off-by: Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>
---
 drivers/power/reset/Kconfig            |  10 +++
 drivers/power/reset/Makefile           |   1 +
 drivers/power/reset/psci-reboot-mode.c | 111 +++++++++++++++++++++++++++++++++
 3 files changed, 122 insertions(+)

diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index f6c1bcbb57deff3568d6b1b326454add3b3bbf06..529d6c7d3555601f7b7e6199acd29838030fcef2 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -348,6 +348,16 @@ config NVMEM_REBOOT_MODE
 	  then the bootloader can read it and take different
 	  action according to the mode.
 
+config PSCI_REBOOT_MODE
+	bool "PSCI reboot mode driver"
+	depends on OF && ARM_PSCI_FW
+	select REBOOT_MODE
+	help
+	  Say y here will enable PSCI reboot mode driver. This gets
+          the PSCI reboot mode arguments and passes them to psci
+	  driver. psci driver uses these arguments for issuing
+	  device reset into different boot states.
+
 config POWER_MLXBF
 	tristate "Mellanox BlueField power handling driver"
 	depends on (GPIO_MLXBF2 || GPIO_MLXBF3) && ACPI
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index 0e4ae6f6b5c55729cf60846d47e6fe0fec24f3cc..49774b42cdf61fd57a5b70f286c65c9d66bbc0cb 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -40,4 +40,5 @@ obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o
 obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o
 obj-$(CONFIG_POWER_RESET_SC27XX) += sc27xx-poweroff.o
 obj-$(CONFIG_NVMEM_REBOOT_MODE) += nvmem-reboot-mode.o
+obj-$(CONFIG_PSCI_REBOOT_MODE) += psci-reboot-mode.o
 obj-$(CONFIG_POWER_MLXBF) += pwr-mlxbf.o
diff --git a/drivers/power/reset/psci-reboot-mode.c b/drivers/power/reset/psci-reboot-mode.c
new file mode 100644
index 0000000000000000000000000000000000000000..499cf504071e88022fa5b5b32e26b7a674da8691
--- /dev/null
+++ b/drivers/power/reset/psci-reboot-mode.c
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/device/faux.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/psci.h>
+#include <linux/reboot.h>
+#include <linux/reboot-mode.h>
+#include <linux/types.h>
+
+/*
+ * Predefined reboot-modes:
+ * reset_type(arg1) is zero; cookie(arg2) is stored in magic.
+ * psci_reboot_mode_set_predefined_modes to move values to higher 32 bit of magic.
+ */
+static struct mode_info psci_resets[] = {
+	{ .mode = "warm", .magic = REBOOT_WARM},
+	{ .mode = "soft", .magic = REBOOT_SOFT},
+	{ .mode = "cold", .magic = REBOOT_COLD},
+};
+
+static void psci_reboot_mode_set_predefined_modes(struct reboot_mode_driver *reboot)
+{
+	INIT_LIST_HEAD(&reboot->predefined_modes);
+	for (u32 i = 0; i < ARRAY_SIZE(psci_resets); i++) {
+		/* Move values to higher 32 bit of magic */
+		psci_resets[i].magic = FIELD_PREP(GENMASK_ULL(63, 32), psci_resets[i].magic);
+		INIT_LIST_HEAD(&psci_resets[i].list);
+		list_add_tail(&psci_resets[i].list, &reboot->predefined_modes);
+	}
+}
+
+/*
+ * magic is 64 bit.
+ * arg1 - reset_type(Low 32 bit of magic).
+ * arg2 - cookie(High 32 bit of magic).
+ * arg2(cookie) decides the mode, If arg1(reset_type) is 0;
+ */
+static int psci_reboot_mode_write(struct reboot_mode_driver *reboot, u64 magic)
+{
+	u32 reset_type = FIELD_GET(GENMASK_ULL(31, 0), magic);
+	u32 cookie = FIELD_GET(GENMASK_ULL(63, 32), magic);
+
+	if (reset_type == 0) {
+		if (cookie == REBOOT_WARM || cookie == REBOOT_SOFT)
+			psci_set_reset_cmd(true, 0, 0);
+		else
+			psci_set_reset_cmd(false, 0, 0);
+	} else {
+		psci_set_reset_cmd(true, reset_type, cookie);
+	}
+
+	return NOTIFY_DONE;
+}
+
+static int psci_reboot_mode_probe(struct faux_device *fdev)
+{
+	struct reboot_mode_driver *reboot;
+	struct device_node *psci_np;
+	struct device_node *np;
+	int ret;
+
+	psci_np = of_find_compatible_node(NULL, NULL, "arm,psci-1.0");
+	if (!psci_np)
+		return -ENODEV;
+
+	/*
+	 * Find the psci:reboot-mode node.
+	 * If NULL, continue to register predefined modes.
+	 * np refcount to be handled by dev;
+	 * psci_np refcount is decremented by of_find_node_by_name;
+	 */
+	np = of_find_node_by_name(psci_np, "reboot-mode");
+	fdev->dev.of_node = np;
+
+	reboot = devm_kzalloc(&fdev->dev, sizeof(*reboot), GFP_KERNEL);
+	if (!reboot)
+		return -ENOMEM;
+
+	psci_reboot_mode_set_predefined_modes(reboot);
+	reboot->write = psci_reboot_mode_write;
+	reboot->dev = &fdev->dev;
+
+	ret = devm_reboot_mode_register(&fdev->dev, reboot);
+	if (ret) {
+		dev_err(&fdev->dev, "devm_reboot_mode_register failed %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct faux_device_ops psci_reboot_mode_ops = {
+	.probe = psci_reboot_mode_probe,
+};
+
+static int __init psci_reboot_mode_init(void)
+{
+	struct faux_device *fdev;
+
+	fdev = faux_device_create("psci-reboot-mode", NULL, &psci_reboot_mode_ops);
+	if (!fdev)
+		return -ENODEV;
+
+	return 0;
+}
+device_initcall(psci_reboot_mode_init);

-- 
2.34.1



From shivendra.pratap at oss.qualcomm.com  Sun Dec 28 09:20:25 2025
From: shivendra.pratap at oss.qualcomm.com (Shivendra Pratap)
Date: Sun, 28 Dec 2025 22:50:25 +0530
Subject: [PATCH v19 07/10] arm64: dts: qcom: qcm6490: Add psci reboot-modes
In-Reply-To: <20251228-arm-psci-system_reset2-vendor-reboots-v19-0-ebb956053098@oss.qualcomm.com>
References: <20251228-arm-psci-system_reset2-vendor-reboots-v19-0-ebb956053098@oss.qualcomm.com>
Message-ID: <20251228-arm-psci-system_reset2-vendor-reboots-v19-7-ebb956053098@oss.qualcomm.com>

Add PSCI SYSTEM_RESET2 reboot-modes for qcm6490-idp and qcs6490-rb3gen2
for use by the psci_reboot_mode driver.
The following modes are defined:
- bootloader: reboot into fastboot mode for fastboot flashing.
- edl: reboot into emergency download mode for image loading via
  the Firehose protocol.

Support for these modes is firmware dependent and not available across
all sc7280 based boards.

Signed-off-by: Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>
---
 arch/arm64/boot/dts/qcom/kodiak.dtsi         | 2 +-
 arch/arm64/boot/dts/qcom/qcm6490-idp.dts     | 7 +++++++
 arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts | 7 +++++++
 3 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/qcom/kodiak.dtsi b/arch/arm64/boot/dts/qcom/kodiak.dtsi
index c2ccbb67f800cb9927627f991e3d97174cc73c64..e319a1894901cc9c56a89cb8b8ad0acb7a18dc99 100644
--- a/arch/arm64/boot/dts/qcom/kodiak.dtsi
+++ b/arch/arm64/boot/dts/qcom/kodiak.dtsi
@@ -858,7 +858,7 @@ pmu-a78 {
 		interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_LOW>;
 	};
 
-	psci {
+	psci: psci {
 		compatible = "arm,psci-1.0";
 		method = "smc";
 
diff --git a/arch/arm64/boot/dts/qcom/qcm6490-idp.dts b/arch/arm64/boot/dts/qcom/qcm6490-idp.dts
index 089a027c57d5caed103f41f20c01fe1294b4c950..5816cc1c033c396f49fddbbcd4b09e5a633bc804 100644
--- a/arch/arm64/boot/dts/qcom/qcm6490-idp.dts
+++ b/arch/arm64/boot/dts/qcom/qcm6490-idp.dts
@@ -695,6 +695,13 @@ &pon_resin {
 	status = "okay";
 };
 
+&psci {
+	reboot-mode {
+		mode-bootloader = <0x80010001 0x2>;
+		mode-edl = <0x80000000 0x1>;
+	};
+};
+
 &qupv3_id_0 {
 	status = "okay";
 };
diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
index f29a352b0288e9ef554ecfff59820ba39bf2cdb1..6e836e476d595b7e1b69a0859cf2f697c529cbfa 100644
--- a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
+++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
@@ -935,6 +935,13 @@ &pon_resin {
 	status = "okay";
 };
 
+&psci {
+	reboot-mode {
+		mode-bootloader = <0x80010001 0x2>;
+		mode-edl = <0x80000000 0x1>;
+	};
+};
+
 &qup_uart7_cts {
 	/*
 	 * Configure a bias-bus-hold on CTS to lower power

-- 
2.34.1



From shivendra.pratap at oss.qualcomm.com  Sun Dec 28 09:20:26 2025
From: shivendra.pratap at oss.qualcomm.com (Shivendra Pratap)
Date: Sun, 28 Dec 2025 22:50:26 +0530
Subject: [PATCH v19 08/10] arm64: dts: qcom: lemans: Add psci reboot-modes
In-Reply-To: <20251228-arm-psci-system_reset2-vendor-reboots-v19-0-ebb956053098@oss.qualcomm.com>
References: <20251228-arm-psci-system_reset2-vendor-reboots-v19-0-ebb956053098@oss.qualcomm.com>
Message-ID: <20251228-arm-psci-system_reset2-vendor-reboots-v19-8-ebb956053098@oss.qualcomm.com>

Add PSCI SYSTEM_RESET2 reboot-modes for lemans based boards, for use by
the psci_reboot_mode driver.

The following modes are defined:
- bootloader: reboot into fastboot mode for fastboot flashing.
- edl: reboot into emergency download mode for image loading via
  the Firehose protocol.

Support for these modes is firmware dependent.

Signed-off-by: Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>
---
 arch/arm64/boot/dts/qcom/lemans.dtsi | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi
index 0b154d57ba24e69a9d900f06bbb22baa2781cc3f..cc70316d6949c8a36280b85931c4adec9cd60f62 100644
--- a/arch/arm64/boot/dts/qcom/lemans.dtsi
+++ b/arch/arm64/boot/dts/qcom/lemans.dtsi
@@ -698,6 +698,11 @@ system_pd: power-domain-system {
 			#power-domain-cells = <0>;
 			domain-idle-states = <&cluster_sleep_apss_rsc_pc>;
 		};
+
+		reboot-mode {
+			mode-bootloader = <0x80010001 0x2>;
+			mode-edl = <0x80000000 0x1>;
+		};
 	};
 
 	reserved-memory {

-- 
2.34.1



From shivendra.pratap at oss.qualcomm.com  Sun Dec 28 09:20:27 2025
From: shivendra.pratap at oss.qualcomm.com (Shivendra Pratap)
Date: Sun, 28 Dec 2025 22:50:27 +0530
Subject: [PATCH v19 09/10] arm64: dts: qcom: monaco: Add psci reboot-modes
In-Reply-To: <20251228-arm-psci-system_reset2-vendor-reboots-v19-0-ebb956053098@oss.qualcomm.com>
References: <20251228-arm-psci-system_reset2-vendor-reboots-v19-0-ebb956053098@oss.qualcomm.com>
Message-ID: <20251228-arm-psci-system_reset2-vendor-reboots-v19-9-ebb956053098@oss.qualcomm.com>

Add PSCI SYSTEM_RESET2 reboot-modes for monaco based boards, for use by
the psci_reboot_mode driver.

The following modes are defined:
- bootloader: reboot into fastboot mode for fastboot flashing.
- edl: reboot into emergency download mode for image loading via
  the Firehose protocol.

Support for these modes is firmware dependent.

Signed-off-by: Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>
---
 arch/arm64/boot/dts/qcom/monaco.dtsi | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/monaco.dtsi b/arch/arm64/boot/dts/qcom/monaco.dtsi
index 816fa2af8a9a663b8ad176f93d2f18284a08c3d1..9c8087f870fc8889edffda63c62f4d5167729cbc 100644
--- a/arch/arm64/boot/dts/qcom/monaco.dtsi
+++ b/arch/arm64/boot/dts/qcom/monaco.dtsi
@@ -732,6 +732,11 @@ system_pd: power-domain-system {
 			#power-domain-cells = <0>;
 			domain-idle-states = <&system_sleep>;
 		};
+
+		reboot-mode {
+			mode-bootloader = <0x80010001 0x2>;
+			mode-edl = <0x80000000 0x1>;
+		};
 	};
 
 	reserved-memory {

-- 
2.34.1



From shivendra.pratap at oss.qualcomm.com  Sun Dec 28 09:20:28 2025
From: shivendra.pratap at oss.qualcomm.com (Shivendra Pratap)
Date: Sun, 28 Dec 2025 22:50:28 +0530
Subject: [PATCH v19 10/10] arm64: dts: qcom: talos: Add psci reboot-modes
In-Reply-To: <20251228-arm-psci-system_reset2-vendor-reboots-v19-0-ebb956053098@oss.qualcomm.com>
References: <20251228-arm-psci-system_reset2-vendor-reboots-v19-0-ebb956053098@oss.qualcomm.com>
Message-ID: <20251228-arm-psci-system_reset2-vendor-reboots-v19-10-ebb956053098@oss.qualcomm.com>

Add PSCI SYSTEM_RESET2 reboot-modes for talos based boards, for use by
the psci_reboot_mode driver.

The following modes are defined:
- bootloader: reboot into fastboot mode for fastboot flashing.
- edl: reboot into emergency download mode for image loading via
  the Firehose protocol.

Support for these modes is firmware dependent.

Signed-off-by: Song Xue <quic_songxue at quicinc.com>
Signed-off-by: Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>
---
 arch/arm64/boot/dts/qcom/talos.dtsi | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi
index 95d26e3136229f9015d49e2be22f6b28f1e842f4..11a2cfa209065776a8ae61c6e661c09bb871c400 100644
--- a/arch/arm64/boot/dts/qcom/talos.dtsi
+++ b/arch/arm64/boot/dts/qcom/talos.dtsi
@@ -613,6 +613,11 @@ cluster_pd: power-domain-cluster {
 					      &cluster_sleep_1
 					      &cluster_sleep_2>;
 		};
+
+		reboot-mode {
+			mode-bootloader = <0x80010001 0x2>;
+			mode-edl = <0x80000000 0x1>;
+		};
 	};
 
 	reserved-memory {

-- 
2.34.1



From daniel.lezcano at linaro.org  Sun Dec 28 09:37:22 2025
From: daniel.lezcano at linaro.org (Daniel Lezcano)
Date: Sun, 28 Dec 2025 18:37:22 +0100
Subject: [PATCH v3 3/3] counter: Add STM based counter
In-Reply-To: <20251228065241.21144-1-wbg@kernel.org>
References: <20251217075000.2592966-4-daniel.lezcano@linaro.org>
 <20251228065241.21144-1-wbg@kernel.org>
Message-ID: <ba28863a-a5fe-498f-92a0-d71c356e7189@linaro.org>


Hi William,

On 12/28/25 07:52, William Breathitt Gray wrote:
> On Wed, Dec 17, 2025 at 08:49:57AM +0100, Daniel Lezcano wrote:
>> The NXP S32G2 automotive platform integrates four Cortex-A53 cores and
>> three Cortex-M7 cores, along with a large number of timers and
>> counters. These hardware blocks can be used as clocksources or
>> clockevents, or as timestamp counters shared across the various
>> subsystems running alongside the Linux kernel, such as firmware
>> components. Their actual usage depends on the overall platform
>> software design.
>>
>> In a Linux-based system, the kernel controls the counter, which is a
>> read-only shared resource for the other subsystems. One of its primary
>> purposes is to act as a common timestamp source for messages or
>> traces, allowing correlation of events occurring in different
>> operating system contexts.
>>
>> These changes introduce a basic counter driver that can start, stop,
>> and reset the counter. It also handles overflow accounting and
>> configures the prescaler value.
>>
>> Signed-off-by: Daniel Lezcano <daniel.lezcano at linaro.org>
> 
> Hi Daniel,
> 
> It sounds like you're trying to implement a clock for timestamping.

Well no, it is a counter which is used for timestamping. It is an 
automotive design.

> Although the Generic Counter interface is flexible enough to shoehorn a
> a clock into its representation, I don't believe it's the right
> abstraction for this particular device.
 >
> Perhaps reimplementing this
> driver under the Linux common clock framework would be a better approach
> to achieve what you want.

The common clock framework ? Sorry I may have misunderstood the CCF but 
how a counter exported and controlled by the userspace can be managed by 
the CCF. Can you elaborate ?

> Regardless, if you do pursue a Counter driver you'll need to follow the
> Generic Counter paradigm[^1] and define at least three core components:
> a Signal, a Synapse, and a Count. Resetting the Count is typically
> implemented by defining a struct counter_ops counter_write()
> callback[^2], while overflows are typically implemented by pushing
> COUNTER_EVENT_OVERFLOW Counter events[^3] that can be watched by
> userspace.

Yes, I think the Generic counter makes sense here for the goal to be 
achieved. Thanks for the pointers, I'll see how the counter fits with 
the paradigm.

   -- Daniel


> William Breathitt Gray
> 
> [^1] https://docs.kernel.org/driver-api/generic-counter.html#paradigm
> [^2] https://docs.kernel.org/driver-api/generic-counter.html#c.counter_ops
> [^3] https://docs.kernel.org/driver-api/generic-counter.html#counter-events


-- 
<http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog


From j.neuschaefer at gmx.net  Sun Dec 28 09:56:38 2025
From: j.neuschaefer at gmx.net (=?utf-8?Q?J=2E_Neusch=C3=A4fer?=)
Date: Sun, 28 Dec 2025 18:56:38 +0100
Subject: [PATCH 1/3] power: supply: add battery driver for netronix ec
In-Reply-To: <20251227-kobo-aura-battery-v1-1-328a90ef5122@jm0.eu>
References: <20251227-kobo-aura-battery-v1-0-328a90ef5122@jm0.eu>
 <20251227-kobo-aura-battery-v1-1-328a90ef5122@jm0.eu>
Message-ID: <aVFvVtXe58q84NOk@probook>

Hello!

Nice to see someone work on the Netronix EC :-)

On Sat, Dec 27, 2025 at 05:28:13PM +0100, Josua Mayer wrote:
> Implement a simple battery driver for monitoring voltage with the
> netronix embedded controller found in certain ebook readers.
> 
> Signed-off-by: Josua Mayer <josua.mayer at jm0.eu>
> ---
>  drivers/mfd/ntxec.c                  |   1 +
>  drivers/power/supply/Kconfig         |   9 ++++
>  drivers/power/supply/Makefile        |   1 +
>  drivers/power/supply/ntxec-battery.c | 101 +++++++++++++++++++++++++++++++++++
>  4 files changed, 112 insertions(+)
> 
> diff --git a/drivers/mfd/ntxec.c b/drivers/mfd/ntxec.c
> index 08c68de0f01bc..d5059b8862aa8 100644
> --- a/drivers/mfd/ntxec.c
> +++ b/drivers/mfd/ntxec.c
> @@ -139,6 +139,7 @@ static const struct regmap_config regmap_config = {
>  static const struct mfd_cell ntxec_subdev[] = {
>  	{ .name = "ntxec-rtc" },
>  	{ .name = "ntxec-pwm" },
> +	{ .name = "ntxec-battery" },
>  };
>  
>  static const struct mfd_cell ntxec_subdev_pwm[] = {
> diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
> index 92f9f7aae92f2..5674a23ba7bd6 100644
> --- a/drivers/power/supply/Kconfig
> +++ b/drivers/power/supply/Kconfig
> @@ -1132,4 +1132,13 @@ config FUEL_GAUGE_MM8013
>  	  the state of charge, temperature, cycle count, actual and design
>  	  capacity, etc.
>  
> +config BATTERY_NTXEC
> +	tristate "Battery driver for Netronix embedded controller"
> +	depends on MFD_NTXEC
> +	help
> +	  Say yes here to enable netronix ec battery monitoring driver.
> +	  It enables the monitoring battery voltage on certain e-book readers
> +	  using an embedded controller by ODM Netronix. Battery design
> +	  characteristics are read from Firmware Tables if available.

What do you mean by Firmware Tables, and where does this happen?

(I guess it means devicetree/fwnode, but "git grep -i 'firmware tables'"
doesn't show many uses of that term)

> +
>  endif # POWER_SUPPLY
> diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
> index 4b79d5abc49a7..db6fc815f9da2 100644
> --- a/drivers/power/supply/Makefile
> +++ b/drivers/power/supply/Makefile
> @@ -128,3 +128,4 @@ obj-$(CONFIG_CHARGER_SURFACE)	+= surface_charger.o
>  obj-$(CONFIG_BATTERY_UG3105)	+= ug3105_battery.o
>  obj-$(CONFIG_CHARGER_QCOM_SMB2)	+= qcom_smbx.o
>  obj-$(CONFIG_FUEL_GAUGE_MM8013)	+= mm8013.o
> +obj-$(CONFIG_BATTERY_NTXEC)	+= ntxec-battery.o
> diff --git a/drivers/power/supply/ntxec-battery.c b/drivers/power/supply/ntxec-battery.c
> new file mode 100644
> index 0000000000000..f49f0966d18dd
> --- /dev/null
> +++ b/drivers/power/supply/ntxec-battery.c
> @@ -0,0 +1,101 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * The Netronix embedded controller is a microcontroller found in some
> + * e-book readers designed by the original design manufacturer Netronix, Inc.
> + * It contains RTC, battery monitoring, system power management, and PWM
> + * functionality.
> + *
> + * This driver implements battery monitoring.
> + *
> + * Copyright 2021 Josua Mayer <josua.mayer at jm0.eu>
> + */
> +
> +#include <linux/mfd/ntxec.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/power_supply.h>
> +#include <linux/property.h>
> +#include <linux/regmap.h>
> +
> +static const enum power_supply_property ntxec_battery_properties[] = {
> +	POWER_SUPPLY_PROP_VOLTAGE_NOW,
> +};
> +
> +struct ntxec_battery {
> +	struct ntxec *ec;
> +};
> +
> +#define NTXEC_REG_READ_BATTERY	0x41
> +
> +static int ntxec_battery_get_property(struct power_supply *psy,
> +				     enum power_supply_property psp,
> +				     union power_supply_propval *val)
> +{
> +	struct ntxec_battery *priv = power_supply_get_drvdata(psy);
> +	int ret;
> +	unsigned int value;
> +
> +	switch (psp) {
> +		case POWER_SUPPLY_PROP_VOLTAGE_NOW:
> +			ret = regmap_read(priv->ec->regmap, NTXEC_REG_READ_BATTERY, &value);
> +			if (ret < 0)
> +				return ret;
> +
> +			/* ec value to microvolt conversion:
> +			 * vendor kernel source suggests linear behaviour from 3V to 4.2V
> +			 * with readings 767 to 1023; each increment represents 4687,5uV.
> +			 * adjust 3V boundary slightly to report exactly 4.2V when full.
> +			 */
> +			val->intval = 2999872 + (value - 767) * 4688;
> +			break;
> +		default:
> +			dev_err(&psy->dev, "%s: invalid property %u\n", __func__, psp);
> +			return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct power_supply_desc ntxec_battery_desc = {
> +	.name = "ec-battery",
> +	.type = POWER_SUPPLY_TYPE_BATTERY,
> +	.properties = ntxec_battery_properties,
> +	.get_property = ntxec_battery_get_property,
> +	.num_properties = ARRAY_SIZE(ntxec_battery_properties),
> +};
> +
> +static int ntxec_battery_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct ntxec *ec = dev_get_drvdata(dev->parent);
> +	struct power_supply_config psy_cfg = {};
> +	struct ntxec_battery *priv;
> +	struct power_supply *psy;
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->ec = ec;
> +	psy_cfg.drv_data = priv;
> +	psy_cfg.fwnode = dev_fwnode(dev->parent);
> +	psy_cfg.no_wakeup_source = true;
> +	psy = devm_power_supply_register(dev, &ntxec_battery_desc, &psy_cfg);
> +	if (IS_ERR(psy))
> +		return PTR_ERR(psy);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver ntxec_battery_driver = {
> +	.driver = {
> +		.name = "ntxec-battery",
> +	},
> +	.probe = ntxec_battery_probe,
> +};
> +module_platform_driver(ntxec_battery_driver);
> +
> +MODULE_AUTHOR("Josua Mayer <josua.mayer at jm0.eu>");
> +MODULE_DESCRIPTION("Battery driver for Netronix EC");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:ntxec-battery");

Thanks,
J. Neusch?fer


From j.neuschaefer at gmx.net  Sun Dec 28 10:01:01 2025
From: j.neuschaefer at gmx.net (=?utf-8?Q?J=2E_Neusch=C3=A4fer?=)
Date: Sun, 28 Dec 2025 19:01:01 +0100
Subject: [PATCH 3/3] ARM: dts: imx: imx50-kobo-aura: add description for
 battery
In-Reply-To: <20251227-kobo-aura-battery-v1-3-328a90ef5122@jm0.eu>
References: <20251227-kobo-aura-battery-v1-0-328a90ef5122@jm0.eu>
 <20251227-kobo-aura-battery-v1-3-328a90ef5122@jm0.eu>
Message-ID: <aVFwXWkPPW_kya-h@probook>

On Sat, Dec 27, 2025 at 05:28:15PM +0100, Josua Mayer wrote:
> Kobo Aura has a rechargable battery that is monitored by the embedded
> controller.
> 
> Battery markings: PR-285083 3.7V Typ. 1500mAh; 575327416288 5.55Wh.
> 
> Add description for this battery and link it for monitoring by the
> embedded controller.
> 
> Signed-off-by: Josua Mayer <josua.mayer at jm0.eu>
> ---

Reviewed-by: J. Neusch?fer <j.neuschaefer at gmx.net>

Thanks!

>  arch/arm/boot/dts/nxp/imx/imx50-kobo-aura.dts | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/nxp/imx/imx50-kobo-aura.dts b/arch/arm/boot/dts/nxp/imx/imx50-kobo-aura.dts
> index b1a6a9c58ac33..dc8d9fd45cd23 100644
> --- a/arch/arm/boot/dts/nxp/imx/imx50-kobo-aura.dts
> +++ b/arch/arm/boot/dts/nxp/imx/imx50-kobo-aura.dts
> @@ -16,6 +16,14 @@ chosen {
>  		stdout-path = "serial1:115200n8";
>  	};
>  
> +	battery: battery {
> +		compatible = "simple-battery";
> +		voltage-min-design-microvolt = <3400000>;
> +		voltage-max-design-microvolt = <4100000>;
> +		energy-full-design-microwatt-hours = <5550000>;
> +		charge-full-design-microamp-hours = <1500000>;
> +	};
> +
>  	memory at 70000000 {
>  		device_type = "memory";
>  		reg = <0x70000000 0x10000000>;
> @@ -151,6 +159,7 @@ embedded-controller at 43 {
>  		system-power-controller;
>  		interrupts-extended = <&gpio4 11 IRQ_TYPE_EDGE_FALLING>;
>  		#pwm-cells = <2>;
> +		monitored-battery = <&battery>;
>  	};
>  };
>  
> 
> -- 
> 2.51.0
> 


From alex at chimac.ro  Sun Dec 28 10:05:39 2025
From: alex at chimac.ro (Alexandru Chimac)
Date: Sun, 28 Dec 2025 18:05:39 +0000
Subject: [PATCH v2 0/3] pinctrl: samsung: add Exynos9610 pinctrl support
Message-ID: <20251228-exynos9610-pinctrl-v2-0-c9bbeee4c54b@chimac.ro>

This patchset adds support for the pin controller found on Exynos9610.

Signed-off-by: Alexandru Chimac <alex at chimac.ro>
---
v2:
- Set proper FLTCON offsets for ALIVE, FSYS, DISPAUD, TOP pin banks
- Define samsung_pin_bank_data structures as initialization constants
---
Alexandru Chimac (3):
      dt-bindings: pinctrl: samsung: Add exynos9610-pinctrl compatible
      dt-bindings: pinctrl: samsung: Add exynos9610-wakeup-eint node
      pinctrl: samsung: Add Exynos9610 pinctrl configuration

 .../pinctrl/samsung,pinctrl-wakeup-interrupt.yaml  |   2 +
 .../bindings/pinctrl/samsung,pinctrl.yaml          |   1 +
 drivers/pinctrl/samsung/pinctrl-exynos-arm64.c     | 109 +++++++++++++++++++++
 drivers/pinctrl/samsung/pinctrl-samsung.c          |   2 +
 drivers/pinctrl/samsung/pinctrl-samsung.h          |   1 +
 5 files changed, 115 insertions(+)
---
base-commit: 48c4c0b684f394721b7db809e1cc282fccdb33da
change-id: 20250914-exynos9610-pinctrl-b44cdfaeeed1

Best regards,
--
Alexandru Chimac <alex at chimac.ro>

---
Alexandru Chimac (3):
      dt-bindings: pinctrl: samsung: Add exynos9610-pinctrl compatible
      dt-bindings: pinctrl: samsung: Add exynos9610-wakeup-eint node
      pinctrl: samsung: Add Exynos9610 pinctrl configuration

 .../pinctrl/samsung,pinctrl-wakeup-interrupt.yaml  |   2 +
 .../bindings/pinctrl/samsung,pinctrl.yaml          |   1 +
 drivers/pinctrl/samsung/pinctrl-exynos-arm64.c     | 117 +++++++++++++++++++++
 drivers/pinctrl/samsung/pinctrl-samsung.c          |   2 +
 drivers/pinctrl/samsung/pinctrl-samsung.h          |   1 +
 5 files changed, 123 insertions(+)
---
base-commit: 3e7f562e20ee87a25e104ef4fce557d39d62fa85
change-id: 20251228-exynos9610-pinctrl-7d7988fd50a1

Best regards,
-- 
Alexandru Chimac <alex at chimac.ro>




From alex at chimac.ro  Sun Dec 28 10:05:46 2025
From: alex at chimac.ro (Alexandru Chimac)
Date: Sun, 28 Dec 2025 18:05:46 +0000
Subject: [PATCH v2 1/3] dt-bindings: pinctrl: samsung: Add exynos9610-pinctrl compatible
In-Reply-To: <20251228-exynos9610-pinctrl-v2-0-c9bbeee4c54b@chimac.ro>
References: <20251228-exynos9610-pinctrl-v2-0-c9bbeee4c54b@chimac.ro>
Message-ID: <20251228-exynos9610-pinctrl-v2-1-c9bbeee4c54b@chimac.ro>

Document pin controller support on Exynos9610-series SoCs.

Signed-off-by: Alexandru Chimac <alex at chimac.ro>
---
 Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml
index ddc5e2efff21..7b006009ca0e 100644
--- a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml
@@ -55,6 +55,7 @@ properties:
       - samsung,exynos850-pinctrl
       - samsung,exynos8890-pinctrl
       - samsung,exynos8895-pinctrl
+      - samsung,exynos9610-pinctrl
       - samsung,exynos9810-pinctrl
       - samsung,exynos990-pinctrl
       - samsung,exynosautov9-pinctrl

-- 
2.51.0




From alex at chimac.ro  Sun Dec 28 10:05:52 2025
From: alex at chimac.ro (Alexandru Chimac)
Date: Sun, 28 Dec 2025 18:05:52 +0000
Subject: [PATCH v2 2/3] dt-bindings: pinctrl: samsung: Add exynos9610-wakeup-eint node
In-Reply-To: <20251228-exynos9610-pinctrl-v2-0-c9bbeee4c54b@chimac.ro>
References: <20251228-exynos9610-pinctrl-v2-0-c9bbeee4c54b@chimac.ro>
Message-ID: <20251228-exynos9610-pinctrl-v2-2-c9bbeee4c54b@chimac.ro>

Add a dedicated compatible for the exynos9610-wakeup-eint node,
which is compatbile with Exynos850's implementation (and the
Exynos7 fallback).

Signed-off-by: Alexandru Chimac <alex at chimac.ro>
---
 .../devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml   | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml
index f3c433015b12..deb2730855bd 100644
--- a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml
@@ -48,6 +48,7 @@ properties:
           - enum:
               - google,gs101-wakeup-eint
               - samsung,exynos2200-wakeup-eint
+              - samsung,exynos9610-wakeup-eint
               - samsung,exynos9810-wakeup-eint
               - samsung,exynos990-wakeup-eint
               - samsung,exynosautov9-wakeup-eint
@@ -107,6 +108,7 @@ allOf:
           contains:
             enum:
               - samsung,exynos850-wakeup-eint
+              - samsung,exynos9610-wakeup-eint
               - samsung,exynosautov920-wakeup-eint
     then:
       properties:

-- 
2.51.0




From alex at chimac.ro  Sun Dec 28 10:05:55 2025
From: alex at chimac.ro (Alexandru Chimac)
Date: Sun, 28 Dec 2025 18:05:55 +0000
Subject: [PATCH v2 3/3] pinctrl: samsung: Add Exynos9610 pinctrl configuration
In-Reply-To: <20251228-exynos9610-pinctrl-v2-0-c9bbeee4c54b@chimac.ro>
References: <20251228-exynos9610-pinctrl-v2-0-c9bbeee4c54b@chimac.ro>
Message-ID: <20251228-exynos9610-pinctrl-v2-3-c9bbeee4c54b@chimac.ro>

Add pinctrl configuration for Exynos9610. The bank types
used are the same as on Exynos850 and gs101, so we can
reuse the macros.

Signed-off-by: Alexandru Chimac <alex at chimac.ro>
---
 drivers/pinctrl/samsung/pinctrl-exynos-arm64.c | 117 +++++++++++++++++++++++++
 drivers/pinctrl/samsung/pinctrl-samsung.c      |   2 +
 drivers/pinctrl/samsung/pinctrl-samsung.h      |   1 +
 3 files changed, 120 insertions(+)

diff --git a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
index 627dca504d7a..fe9f92cb037e 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
+++ b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
@@ -1770,6 +1770,123 @@ const struct samsung_pinctrl_of_match_data exynos8895_of_data __initconst = {
 	.num_ctrl	= ARRAY_SIZE(exynos8895_pin_ctrl),
 };
 
+/* pin banks of exynos9610 pin-controller 0 (ALIVE) */
+static const struct samsung_pin_bank_data exynos9610_pin_banks0[] __initconst = {
+	EXYNOS850_PIN_BANK_EINTN(6, 0x000, "etc0"),
+	GS101_PIN_BANK_EINTW(8, 0x020, "gpa0", 0x00, 0x00),
+	GS101_PIN_BANK_EINTW(8, 0x040, "gpa1", 0x04, 0x08),
+	GS101_PIN_BANK_EINTW(8, 0x060, "gpa2", 0x08, 0x0c),
+	EXYNOS850_PIN_BANK_EINTN(5, 0x080, "gpq0"),
+};
+
+/* pin banks of exynos9610 pin-controller 1 (CMGP) */
+static const struct samsung_pin_bank_data exynos9610_pin_banks1[] __initconst = {
+	EXYNOS850_PIN_BANK_EINTW(1, 0x000, "gpm0", 0x00),
+	EXYNOS850_PIN_BANK_EINTW(1, 0x020, "gpm1", 0x04),
+	EXYNOS850_PIN_BANK_EINTW(1, 0x040, "gpm2", 0x08),
+	EXYNOS850_PIN_BANK_EINTW(1, 0x060, "gpm3", 0x0C),
+	EXYNOS850_PIN_BANK_EINTW(1, 0x080, "gpm4", 0x10),
+	EXYNOS850_PIN_BANK_EINTW(1, 0x0A0, "gpm5", 0x14),
+	EXYNOS850_PIN_BANK_EINTW(1, 0x0C0, "gpm6", 0x18),
+	EXYNOS850_PIN_BANK_EINTW(1, 0x0E0, "gpm7", 0x1C),
+	EXYNOS850_PIN_BANK_EINTW(1, 0x100, "gpm8", 0x20),
+	EXYNOS850_PIN_BANK_EINTW(1, 0x120, "gpm9", 0x24),
+	EXYNOS850_PIN_BANK_EINTW(1, 0x140, "gpm10", 0x28),
+	EXYNOS850_PIN_BANK_EINTW(1, 0x160, "gpm11", 0x2C),
+	EXYNOS850_PIN_BANK_EINTW(1, 0x180, "gpm12", 0x30),
+	EXYNOS850_PIN_BANK_EINTW(1, 0x1A0, "gpm13", 0x34),
+	EXYNOS850_PIN_BANK_EINTW(1, 0x1C0, "gpm14", 0x38),
+	EXYNOS850_PIN_BANK_EINTW(1, 0x1E0, "gpm15", 0x3C),
+	EXYNOS850_PIN_BANK_EINTW(1, 0x200, "gpm16", 0x40),
+	EXYNOS850_PIN_BANK_EINTW(1, 0x220, "gpm17", 0x44),
+	EXYNOS850_PIN_BANK_EINTW(1, 0x240, "gpm18", 0x48),
+	EXYNOS850_PIN_BANK_EINTW(1, 0x260, "gpm19", 0x4C),
+	EXYNOS850_PIN_BANK_EINTW(1, 0x280, "gpm20", 0x50),
+	EXYNOS850_PIN_BANK_EINTW(1, 0x2A0, "gpm21", 0x54),
+	EXYNOS850_PIN_BANK_EINTW(1, 0x2C0, "gpm22", 0x58),
+	EXYNOS850_PIN_BANK_EINTW(1, 0x2E0, "gpm23", 0x5C),
+	EXYNOS850_PIN_BANK_EINTW(1, 0x300, "gpm24", 0x60),
+	EXYNOS850_PIN_BANK_EINTW(1, 0x320, "gpm25", 0x64),
+};
+
+/* pin banks of exynos9610 pin-controller 2 (DISPAUD) */
+static const struct samsung_pin_bank_data exynos9610_pin_banks2[] __initconst = {
+	GS101_PIN_BANK_EINTG(5, 0x000, "gpb0", 0x00, 0x00),
+	GS101_PIN_BANK_EINTG(4, 0x020, "gpb1", 0x04, 0x08),
+	GS101_PIN_BANK_EINTG(5, 0x040, "gpb2", 0x08, 0x0c),
+};
+
+/* pin banks of exynos9610 pin-controller 3 (FSYS) */
+static const struct samsung_pin_bank_data exynos9610_pin_banks3[] __initconst = {
+	GS101_PIN_BANK_EINTG(4, 0x000, "gpf0", 0x00, 0x00),
+	GS101_PIN_BANK_EINTG(8, 0x020, "gpf1", 0x04, 0x04),
+	GS101_PIN_BANK_EINTG(6, 0x040, "gpf2", 0x08, 0x0c),
+};
+
+/* pin banks of exynos9610 pin-controller 4 (TOP) */
+static const struct samsung_pin_bank_data exynos9610_pin_banks4[] __initconst = {
+	GS101_PIN_BANK_EINTG(8, 0x000, "gpp0", 0x00, 0x00),
+	GS101_PIN_BANK_EINTG(6, 0x020, "gpp1", 0x04, 0x08),
+	GS101_PIN_BANK_EINTG(8, 0x040, "gpp2", 0x08, 0x10),
+	GS101_PIN_BANK_EINTG(8, 0x060, "gpc0", 0x0C, 0x18),
+	GS101_PIN_BANK_EINTG(8, 0x080, "gpc1", 0x10, 0x20),
+	GS101_PIN_BANK_EINTG(5, 0x0A0, "gpc2", 0x14, 0x28),
+	GS101_PIN_BANK_EINTG(8, 0x0C0, "gpg0", 0x18, 0x30),
+	GS101_PIN_BANK_EINTG(8, 0x0E0, "gpg1", 0x1C, 0x38),
+	GS101_PIN_BANK_EINTG(8, 0x100, "gpg2", 0x20, 0x40),
+	GS101_PIN_BANK_EINTG(6, 0x120, "gpg3", 0x24, 0x48),
+	GS101_PIN_BANK_EINTG(3, 0x140, "gpg4", 0x28, 0x50),
+};
+
+/* pin banks of exynos9610 pin-controller 5 (SHUB) */
+static const struct samsung_pin_bank_data exynos9610_pin_banks5[] __initconst = {
+	EXYNOS850_PIN_BANK_EINTG(4, 0x000, "gph0", 0x00),
+	EXYNOS850_PIN_BANK_EINTG(3, 0x020, "gph1", 0x04),
+};
+
+static const struct samsung_pin_ctrl exynos9610_pin_ctrl[] __initconst = {
+	{
+		/* pin-controller instance 0 ALIVE data */
+		.pin_banks	= exynos9610_pin_banks0,
+		.nr_banks	= ARRAY_SIZE(exynos9610_pin_banks0),
+		.eint_wkup_init = exynos_eint_wkup_init,
+		.suspend	= exynos_pinctrl_suspend,
+		.resume		= exynos_pinctrl_resume,
+	}, {
+		/* pin-controller instance 1 CMGP data */
+		.pin_banks	= exynos9610_pin_banks1,
+		.nr_banks	= ARRAY_SIZE(exynos9610_pin_banks1),
+		.eint_wkup_init = exynos_eint_wkup_init,
+		.suspend	= exynos_pinctrl_suspend,
+		.resume		= exynos_pinctrl_resume,
+	}, {
+		/* pin-controller instance 2 DISPAUD data */
+		.pin_banks	= exynos9610_pin_banks2,
+		.nr_banks	= ARRAY_SIZE(exynos9610_pin_banks2),
+	}, {
+		/* pin-controller instance 3 FSYS data */
+		.pin_banks	= exynos9610_pin_banks3,
+		.nr_banks	= ARRAY_SIZE(exynos9610_pin_banks3),
+		.suspend	= exynos_pinctrl_suspend,
+		.resume		= exynos_pinctrl_resume,
+	}, {
+		/* pin-controller instance 4 TOP data */
+		.pin_banks	= exynos9610_pin_banks4,
+		.nr_banks	= ARRAY_SIZE(exynos9610_pin_banks4),
+		.suspend	= exynos_pinctrl_suspend,
+		.resume		= exynos_pinctrl_resume,
+	}, {
+		/* pin-controller instance 5 SHUB data */
+		.pin_banks	= exynos9610_pin_banks5,
+		.nr_banks	= ARRAY_SIZE(exynos9610_pin_banks5),
+	},
+};
+
+const struct samsung_pinctrl_of_match_data exynos9610_of_data __initconst = {
+	.ctrl		= exynos9610_pin_ctrl,
+	.num_ctrl	= ARRAY_SIZE(exynos9610_pin_ctrl),
+};
+
 /*
  * Pinctrl driver data for Tesla FSD SoC. FSD SoC includes three
  * gpio/pin-mux/pinconfig controllers.
diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c
index e374effba25a..5ac6f6b02327 100644
--- a/drivers/pinctrl/samsung/pinctrl-samsung.c
+++ b/drivers/pinctrl/samsung/pinctrl-samsung.c
@@ -1504,6 +1504,8 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = {
 		.data = &exynos8890_of_data },
 	{ .compatible = "samsung,exynos8895-pinctrl",
 		.data = &exynos8895_of_data },
+	{ .compatible = "samsung,exynos9610-pinctrl",
+		.data = &exynos9610_of_data },
 	{ .compatible = "samsung,exynos9810-pinctrl",
 		.data = &exynos9810_of_data },
 	{ .compatible = "samsung,exynos990-pinctrl",
diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h
index 0f7b2ea98158..937600430a6e 100644
--- a/drivers/pinctrl/samsung/pinctrl-samsung.h
+++ b/drivers/pinctrl/samsung/pinctrl-samsung.h
@@ -398,6 +398,7 @@ extern const struct samsung_pinctrl_of_match_data exynos7885_of_data;
 extern const struct samsung_pinctrl_of_match_data exynos850_of_data;
 extern const struct samsung_pinctrl_of_match_data exynos8890_of_data;
 extern const struct samsung_pinctrl_of_match_data exynos8895_of_data;
+extern const struct samsung_pinctrl_of_match_data exynos9610_of_data;
 extern const struct samsung_pinctrl_of_match_data exynos9810_of_data;
 extern const struct samsung_pinctrl_of_match_data exynos990_of_data;
 extern const struct samsung_pinctrl_of_match_data exynosautov9_of_data;

-- 
2.51.0




From rdunlap at infradead.org  Sun Dec 28 11:05:02 2025
From: rdunlap at infradead.org (Randy Dunlap)
Date: Sun, 28 Dec 2025 11:05:02 -0800
Subject: [PATCH] stm class: Kconfig: correct symbol name
Message-ID: <20251228190502.2480758-1-rdunlap@infradead.org>

Drop the leading "CONFIG_" when referring to Kconfig symbols--
it is supplied by the kconfig software.
This make the default values work as (apparently) expected.

Fixes: a02509f301c6 ("stm class: Factor out default framing protocol")
Fixes: d69d5e83110f ("stm class: Add MIPI SyS-T protocol support")
Signed-off-by: Randy Dunlap <rdunlap at infradead.org>
---
Cc: Alexander Shishkin <alexander.shishkin at linux.intel.com>
Cc: Maxime Coquelin <mcoquelin.stm32 at gmail.com>
Cc: Alexandre Torgue <alexandre.torgue at foss.st.com>
Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
Cc: linux-stm32 at st-md-mailman.stormreply.com
Cc: linux-arm-kernel at lists.infradead.org

 drivers/hwtracing/stm/Kconfig |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

--- linux-next-20251219.orig/drivers/hwtracing/stm/Kconfig
+++ linux-next-20251219/drivers/hwtracing/stm/Kconfig
@@ -13,7 +13,7 @@ if STM
 
 config STM_PROTO_BASIC
 	tristate "Basic STM framing protocol driver"
-	default CONFIG_STM
+	default STM
 	help
 	  This is a simple framing protocol for sending data over STM
 	  devices. This was the protocol that the STM framework used
@@ -28,7 +28,7 @@ config STM_PROTO_BASIC
 
 config STM_PROTO_SYS_T
 	tristate "MIPI SyS-T STM framing protocol driver"
-	default CONFIG_STM
+	default STM
 	help
 	  This is an implementation of MIPI SyS-T protocol to be used
 	  over the STP transport. In addition to the data payload, it


From 21cnbao at gmail.com  Sun Dec 28 13:38:26 2025
From: 21cnbao at gmail.com (Barry Song)
Date: Mon, 29 Dec 2025 10:38:26 +1300
Subject: [PATCH v2 4/8] dma-mapping: Separate DMA sync issuing and
 completion waiting
In-Reply-To: <20251228144909.GR11869@unreal>
References: <20251226225254.46197-1-21cnbao@gmail.com> <20251226225254.46197-5-21cnbao@gmail.com>
 <20251227200706.GN11869@unreal> <CAGsJ_4zyascnpQ1cB-BMO9PDeeRZTBAh8Z-j-ip=RcxApa4zSg@mail.gmail.com>
 <20251228144909.GR11869@unreal>
Message-ID: <CAGsJ_4y=yoYZn+_ztdfuOCj_dS-M0h8YWO51AXubPbeR1FH6uQ@mail.gmail.com>

On Mon, Dec 29, 2025 at 3:49?AM Leon Romanovsky <leon at kernel.org> wrote:
>
> On Sun, Dec 28, 2025 at 10:45:13AM +1300, Barry Song wrote:
> > On Sun, Dec 28, 2025 at 9:07?AM Leon Romanovsky <leon at kernel.org> wrote:
> > >
> > > On Sat, Dec 27, 2025 at 11:52:44AM +1300, Barry Song wrote:
> > > > From: Barry Song <baohua at kernel.org>
> > > >
> > > > Currently, arch_sync_dma_for_cpu and arch_sync_dma_for_device
> > > > always wait for the completion of each DMA buffer. That is,
> > > > issuing the DMA sync and waiting for completion is done in a
> > > > single API call.
> > > >
> > > > For scatter-gather lists with multiple entries, this means
> > > > issuing and waiting is repeated for each entry, which can hurt
> > > > performance. Architectures like ARM64 may be able to issue all
> > > > DMA sync operations for all entries first and then wait for
> > > > completion together.
> > > >
> > > > To address this, arch_sync_dma_for_* now issues DMA operations in
> > > > batch, followed by a flush. On ARM64, the flush is implemented
> > > > using a dsb instruction within arch_sync_dma_flush().
> > > >
> > > > For now, add arch_sync_dma_flush() after each
> > > > arch_sync_dma_for_*() call. arch_sync_dma_flush() is defined as a
> > > > no-op on all architectures except arm64, so this patch does not
> > > > change existing behavior. Subsequent patches will introduce true
> > > > batching for SG DMA buffers.
> > > >
> > > > Cc: Leon Romanovsky <leon at kernel.org>
> > > > Cc: Catalin Marinas <catalin.marinas at arm.com>
> > > > Cc: Will Deacon <will at kernel.org>
> > > > Cc: Marek Szyprowski <m.szyprowski at samsung.com>
> > > > Cc: Robin Murphy <robin.murphy at arm.com>
> > > > Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
> > > > Cc: Ard Biesheuvel <ardb at kernel.org>
> > > > Cc: Marc Zyngier <maz at kernel.org>
> > > > Cc: Anshuman Khandual <anshuman.khandual at arm.com>
> > > > Cc: Ryan Roberts <ryan.roberts at arm.com>
> > > > Cc: Suren Baghdasaryan <surenb at google.com>
> > > > Cc: Joerg Roedel <joro at 8bytes.org>
> > > > Cc: Juergen Gross <jgross at suse.com>
> > > > Cc: Stefano Stabellini <sstabellini at kernel.org>
> > > > Cc: Oleksandr Tyshchenko <oleksandr_tyshchenko at epam.com>
> > > > Cc: Tangquan Zheng <zhengtangquan at oppo.com>
> > > > Signed-off-by: Barry Song <baohua at kernel.org>
> > > > ---
> > > >  arch/arm64/include/asm/cache.h |  6 ++++++
> > > >  arch/arm64/mm/dma-mapping.c    |  4 ++--
> > > >  drivers/iommu/dma-iommu.c      | 37 +++++++++++++++++++++++++---------
> > > >  drivers/xen/swiotlb-xen.c      | 24 ++++++++++++++--------
> > > >  include/linux/dma-map-ops.h    |  6 ++++++
> > > >  kernel/dma/direct.c            |  8 ++++++--
> > > >  kernel/dma/direct.h            |  9 +++++++--
> > > >  kernel/dma/swiotlb.c           |  4 +++-
> > > >  8 files changed, 73 insertions(+), 25 deletions(-)
> > >
> > > <...>
> > >
> > > > +#ifndef arch_sync_dma_flush
> > > > +static inline void arch_sync_dma_flush(void)
> > > > +{
> > > > +}
> > > > +#endif
> > >
> > > Over the weekend I realized a useful advantage of the ARCH_HAVE_* config
> > > options: they make it straightforward to inspect the entire DMA path simply
> > > by looking at the .config.
> >
> > I am not quite sure how much this benefits users, as the same
> > information could also be obtained by grepping for
> > #define arch_sync_dma_flush in the source code.
>
> It differs slightly. Users no longer need to grep around or guess whether this
> platform used the arch_sync_dma_flush path. A simple grep for ARCH_HAVE_ in
> /proc/config.gz provides the answer.

In any case, it is only two or three lines of code, so I am fine with
either approach. Perhaps Marek, Robin, and others have a point here?

>
> >
> > >
> > > Thanks,
> > > Reviewed-by: Leon Romanovsky <leonro at nvidia.com>
> >
> > Thanks very much, Leon, for reviewing this over the weekend. One thing
> > you might have missed is that I place arch_sync_dma_flush() after all
> > arch_sync_dma_for_*() calls, for both single and sg cases. I also
> > used a Python script to scan the code and verify that every
> > arch_sync_dma_for_*() is followed by arch_sync_dma_flush(), to ensure
> > that no call is left out.
> >
> > In the subsequent patches, for sg cases, the per-entry flush is
> > replaced by a single flush of the entire sg. Each sg case has
> > different characteristics: some are straightforward, while others
> > can be tricky and involve additional contexts.
>
> I didn't overlook it, and I understand your rationale. However, this is
> not how kernel patches should be structured. You should not introduce
> code in patch X and then move it elsewhere in patch X + Y.

I am not quite convinced by this concern. This patch only
separates DMA sync issuing from completion waiting, and it
reflects that the development is done step by step.

>
> Place the code in the correct location from the start. Your patches are
> small enough to review as is.

My point is that this patch places the code in the correct locations
from the start. It splits arch_sync_dma_for_*() into
arch_sync_dma_for_*() plus arch_sync_dma_flush() everywhere, without
introducing any functional changes from the outset.
The subsequent patches clearly show which parts are truly batched.

In the meantime, I do not have a strong preference here. If you think
it is better to move some of the straightforward batching code here,
I can follow that approach. Perhaps I could move patch 5, patch 8,
and the iommu_dma_iova_unlink_range_slow change from patch 7 here,
while keeping

  [PATCH 6] dma-mapping: Support batch mode for
  dma_direct_{map,unmap}_sg

and the IOVA link part from patch 7 as separate patches, since that
part is not straightforward. The IOVA link changes affect both
__dma_iova_link() and dma_iova_sync(), which are two separate
functions and require a deeper understanding of the contexts to
determine correctness. That part also lacks testing.

Would that be okay with you?

Thanks
Barry


From vz at mleia.com  Sun Dec 28 14:21:21 2025
From: vz at mleia.com (Vladimir Zapolskiy)
Date: Mon, 29 Dec 2025 00:21:21 +0200
Subject: [PATCH RESEND 0/2] ARM: dts: lpc32xx: set DMA and NAND flash
 controller properties
In-Reply-To: <20251225203157.1414349-1-vz@mleia.com>
References: <20251225203157.1414349-1-vz@mleia.com>
Message-ID: <379f38ac-ab4a-4615-894b-e404bea4a6a1@mleia.com>

On 12/25/25 22:31, Vladimir Zapolskiy wrote:
> The changeset adds a numbed of necessary properties to ARM PrimeCell
> PL080 DMA controller and to SLC and MLC NAND flash controllers, and now
> it obsoletes the platform data of the controllers populated on boot.
> 
> To respect any probable users who does not update dtb on the boards,
> the platform data cannot be removed instantly, but now it's time to
> declare one year timeout for such a synchronization to be completed,
> the platform data of DMA and NAND flash controllers will be removed by
> the end of the next year.
> 
> The changeset is based on top of the previously sent changes:
> * https://lore.kernel.org/linux-arm-kernel/20251224165845.1261926-1-vz at mleia.com
> 
> Note, the changeset is marked as the resent one, it's identical to the one
> https://lore.kernel.org/linux-devicetree/20251225180230.1400420-1-vz at mleia.com/
> but now the changeset appears on the linux-arm-kernel mailing list as well.
> 
> Vladimir Zapolskiy (2):
>    ARM: dts: lpc32xx: add DMA controller properties to the device tree node
>    ARM: dts: lpc32xx: add DMA properties to NAND flash controllers
> 
>   arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi | 12 ++++++++++++
>   1 file changed, 12 insertions(+)
> 

Found a previously unapplied change, which is more comprehensive and
substitutes this series, still have to add {lli,mem}-bus-interface-ahb2
property to the DMA controller device tree node:

https://lore.kernel.org/linux-arm-kernel/20240627150046.258795-6-piotr.wojtaszczyk at timesys.com/

Will apply the one from Piotr.

-- 
Best wishes,
Vladimir


From vz at mleia.com  Sun Dec 28 14:49:05 2025
From: vz at mleia.com (Vladimir Zapolskiy)
Date: Mon, 29 Dec 2025 00:49:05 +0200
Subject: [PATCH 0/2] arm: dts: lpc32xx: Set motor control PWM clock as required one
Message-ID: <20251228224907.1729627-1-vz@mleia.com>

Motor Control PWM depends on its own supply clock, the clock gate control
is present in TIMCLK_CTRL1 register.

Vladimir Zapolskiy (2):
  dt-bindings: pwm: nxp,lpc32xx-pwm: Specify clocks property as mandatory
  arm: dts: lpc32xx: add clocks property to Motor Control PWM device tree node

 Documentation/devicetree/bindings/pwm/nxp,lpc3220-pwm.yaml | 4 ++++
 arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi                     | 1 +
 2 files changed, 5 insertions(+)

-- 
2.43.0



From vz at mleia.com  Sun Dec 28 14:49:06 2025
From: vz at mleia.com (Vladimir Zapolskiy)
Date: Mon, 29 Dec 2025 00:49:06 +0200
Subject: [PATCH 1/2] dt-bindings: pwm: nxp,lpc32xx-pwm: Specify clocks property as mandatory
In-Reply-To: <20251228224907.1729627-1-vz@mleia.com>
References: <20251228224907.1729627-1-vz@mleia.com>
Message-ID: <20251228224907.1729627-2-vz@mleia.com>

Both described in the binding PWM controllers depend on supply clocks,
thus it's necessary to specify 'clocks' property in the correspondent
device tree nodes.

Signed-off-by: Vladimir Zapolskiy <vz at mleia.com>
---
 Documentation/devicetree/bindings/pwm/nxp,lpc3220-pwm.yaml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/pwm/nxp,lpc3220-pwm.yaml b/Documentation/devicetree/bindings/pwm/nxp,lpc3220-pwm.yaml
index d8ebb0735c96..cdd83ac29caf 100644
--- a/Documentation/devicetree/bindings/pwm/nxp,lpc3220-pwm.yaml
+++ b/Documentation/devicetree/bindings/pwm/nxp,lpc3220-pwm.yaml
@@ -27,6 +27,7 @@ properties:
 required:
   - compatible
   - reg
+  - clocks
   - '#pwm-cells'
 
 allOf:
@@ -36,9 +37,12 @@ unevaluatedProperties: false
 
 examples:
   - |
+    #include <dt-bindings/clock/lpc32xx-clock.h>
+
     pwm at 4005c000 {
         compatible = "nxp,lpc3220-pwm";
         reg = <0x4005c000 0x4>;
+        clocks = <&clk LPC32XX_CLK_PWM1>;
         #pwm-cells = <3>;
     };
 
-- 
2.43.0



From vz at mleia.com  Sun Dec 28 14:49:07 2025
From: vz at mleia.com (Vladimir Zapolskiy)
Date: Mon, 29 Dec 2025 00:49:07 +0200
Subject: [PATCH 2/2] arm: dts: lpc32xx: add clocks property to Motor Control PWM device tree node
In-Reply-To: <20251228224907.1729627-1-vz@mleia.com>
References: <20251228224907.1729627-1-vz@mleia.com>
Message-ID: <20251228224907.1729627-3-vz@mleia.com>

Motor Control PWM depends on its own supply clock, the clock gate control
is present in TIMCLK_CTRL1 register.

Signed-off-by: Vladimir Zapolskiy <vz at mleia.com>
---
 arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
index 39af48470ed5..abd401fda94e 100644
--- a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
+++ b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
@@ -304,6 +304,7 @@ i2c2: i2c at 400a8000 {
 			mpwm: pwm at 400e8000 {
 				compatible = "nxp,lpc3220-motor-pwm";
 				reg = <0x400e8000 0x78>;
+				clocks = <&clk LPC32XX_CLK_MCPWM>;
 				#pwm-cells = <3>;
 				status = "disabled";
 			};
-- 
2.43.0



From rdunlap at infradead.org  Sun Dec 28 15:28:27 2025
From: rdunlap at infradead.org (Randy Dunlap)
Date: Sun, 28 Dec 2025 15:28:27 -0800
Subject: [PATCH] arm: npcm: drop unused Kconfig ERRATA symbol
Message-ID: <20251228232827.2638379-1-rdunlap@infradead.org>

The code for this errata was not merged. See
https://lore.kernel.org/linux-arm-kernel/CAL_JsqK--G_7nO_UQ6jyomA1Sq6GUKtXVZpBF0dXjYA2iE047w at mail.gmail.com/

Fixes: 7bffa14c9aed ("arm: npcm: add basic support for Nuvoton BMCs")
Signed-off-by: Randy Dunlap <rdunlap at infradead.org>
---
KernelVersion: 6.19-rc3

Cc: Brendan Higgins <brendanhiggins at google.com>
Cc: Arnd Bergmann <arnd at arndb.de>
Cc: Avi Fishman <avifishman70 at gmail.com>
Cc: Tomer Maimon <tmaimon77 at gmail.com>
Cc: Tali Perry <tali.perry1 at gmail.com>
Cc: openbmc at lists.ozlabs.org
Cc: Russell King <linux at armlinux.org.uk>

 arch/arm/mach-npcm/Kconfig |    1 -
 1 file changed, 1 deletion(-)

--- linux-next-20251219.orig/arch/arm/mach-npcm/Kconfig
+++ linux-next-20251219/arch/arm/mach-npcm/Kconfig
@@ -30,7 +30,6 @@ config ARCH_NPCM7XX
 	select ARM_ERRATA_764369 if SMP
 	select ARM_ERRATA_720789
 	select ARM_ERRATA_754322
-	select ARM_ERRATA_794072
 	select PL310_ERRATA_588369
 	select PL310_ERRATA_727915
 	select MFD_SYSCON


From dawei.li at linux.dev  Sun Dec 28 16:23:54 2025
From: dawei.li at linux.dev (Dawei Li)
Date: Mon, 29 Dec 2025 08:23:54 +0800
Subject: [PATCH] iommu/arm-smmu-v3: Maintain valid access attributes for non-coherent SMMU
Message-ID: <20251229002354.162872-1-dawei.li@linux.dev>

According to SMMUv3 architecture specification, IO-coherent access for
SMMU is supported for:
- Translation table walks.
- Fetches of L1STD, STE, L1CD and CD.
- Command queue, Event queue and PRI queue access.
- GERROR, CMD_SYNC, Event queue and PRI queue MSIs, if supported

In other words, if a SMMU implementation doesn't support IO coherent
access(SMMUIDR0.COHACC==0), all fields above accessed by SMMU is
expected to be non-coherent and S/W is supposed to maintain proper
access attributes to achieve expected behavior.

Unfortunately, for non-coherent SMMU implementation, current codebase
only takes care of translation table walking. Fix it by providing right
attributes(cacheability, shareablility, cache allocation hints, e.g) to
other fields.

Fixes: 4f41845b3407 ("iommu/io-pgtable: Replace IO_PGTABLE_QUIRK_NO_DMA with specific flag")
Fixes: 9e6ea59f3ff3 ("iommu/io-pgtable: Support non-coherent page tables")
Cc: stable at vger.kernel.org
Signed-off-by: Dawei Li <dawei.li at linux.dev>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 73 +++++++++++++++------
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h |  1 +
 2 files changed, 54 insertions(+), 20 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index d16d35c78c06..4f00bf53d26c 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -265,8 +265,14 @@ static int queue_remove_raw(struct arm_smmu_queue *q, u64 *ent)
 	return 0;
 }
 
+static __always_inline bool smmu_coherent(struct arm_smmu_device *smmu)
+{
+	return !!(smmu->features & ARM_SMMU_FEAT_COHERENCY);
+}
+
 /* High-level queue accessors */
-static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent)
+static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent,
+				   struct arm_smmu_device *smmu)
 {
 	memset(cmd, 0, 1 << CMDQ_ENT_SZ_SHIFT);
 	cmd[0] |= FIELD_PREP(CMDQ_0_OP, ent->opcode);
@@ -358,8 +364,13 @@ static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent)
 		} else {
 			cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_CS, CMDQ_SYNC_0_CS_SEV);
 		}
-		cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_MSH, ARM_SMMU_SH_ISH);
-		cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_MSIATTR, ARM_SMMU_MEMATTR_OIWB);
+		if (smmu_coherent(smmu)) {
+			cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_MSH, ARM_SMMU_SH_ISH);
+			cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_MSIATTR, ARM_SMMU_MEMATTR_OIWB);
+		} else {
+			cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_MSH, ARM_SMMU_SH_OSH);
+			cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_MSIATTR, ARM_SMMU_MEMATTR_OINC);
+		}
 		break;
 	default:
 		return -ENOENT;
@@ -405,7 +416,7 @@ static void arm_smmu_cmdq_build_sync_cmd(u64 *cmd, struct arm_smmu_device *smmu,
 				   q->ent_dwords * 8;
 	}
 
-	arm_smmu_cmdq_build_cmd(cmd, &ent);
+	arm_smmu_cmdq_build_cmd(cmd, &ent, smmu);
 	if (arm_smmu_cmdq_needs_busy_polling(smmu, cmdq))
 		u64p_replace_bits(cmd, CMDQ_SYNC_0_CS_NONE, CMDQ_SYNC_0_CS);
 }
@@ -461,7 +472,7 @@ void __arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu,
 		dev_err(smmu->dev, "\t0x%016llx\n", (unsigned long long)cmd[i]);
 
 	/* Convert the erroneous command into a CMD_SYNC */
-	arm_smmu_cmdq_build_cmd(cmd, &cmd_sync);
+	arm_smmu_cmdq_build_cmd(cmd, &cmd_sync, smmu);
 	if (arm_smmu_cmdq_needs_busy_polling(smmu, cmdq))
 		u64p_replace_bits(cmd, CMDQ_SYNC_0_CS_NONE, CMDQ_SYNC_0_CS);
 
@@ -913,7 +924,7 @@ static int __arm_smmu_cmdq_issue_cmd(struct arm_smmu_device *smmu,
 {
 	u64 cmd[CMDQ_ENT_DWORDS];
 
-	if (unlikely(arm_smmu_cmdq_build_cmd(cmd, ent))) {
+	if (unlikely(arm_smmu_cmdq_build_cmd(cmd, ent, smmu))) {
 		dev_warn(smmu->dev, "ignoring unknown CMDQ opcode 0x%x\n",
 			 ent->opcode);
 		return -EINVAL;
@@ -965,7 +976,7 @@ static void arm_smmu_cmdq_batch_add(struct arm_smmu_device *smmu,
 	}
 
 	index = cmds->num * CMDQ_ENT_DWORDS;
-	if (unlikely(arm_smmu_cmdq_build_cmd(&cmds->cmds[index], cmd))) {
+	if (unlikely(arm_smmu_cmdq_build_cmd(&cmds->cmds[index], cmd, smmu))) {
 		dev_warn(smmu->dev, "ignoring unknown CMDQ opcode 0x%x\n",
 			 cmd->opcode);
 		return;
@@ -1603,6 +1614,7 @@ void arm_smmu_make_cdtable_ste(struct arm_smmu_ste *target,
 {
 	struct arm_smmu_ctx_desc_cfg *cd_table = &master->cd_table;
 	struct arm_smmu_device *smmu = master->smmu;
+	u64 val;
 
 	memset(target, 0, sizeof(*target));
 	target->data[0] = cpu_to_le64(
@@ -1612,11 +1624,18 @@ void arm_smmu_make_cdtable_ste(struct arm_smmu_ste *target,
 		(cd_table->cdtab_dma & STRTAB_STE_0_S1CTXPTR_MASK) |
 		FIELD_PREP(STRTAB_STE_0_S1CDMAX, cd_table->s1cdmax));
 
+	if (smmu_coherent(smmu)) {
+		val = FIELD_PREP(STRTAB_STE_1_S1CIR, STRTAB_STE_1_S1C_CACHE_WBRA) |
+		      FIELD_PREP(STRTAB_STE_1_S1COR, STRTAB_STE_1_S1C_CACHE_WBRA) |
+		      FIELD_PREP(STRTAB_STE_1_S1CSH, ARM_SMMU_SH_ISH);
+	} else {
+		val = FIELD_PREP(STRTAB_STE_1_S1CIR, STRTAB_STE_1_S1C_CACHE_NC) |
+		      FIELD_PREP(STRTAB_STE_1_S1COR, STRTAB_STE_1_S1C_CACHE_NC) |
+		      FIELD_PREP(STRTAB_STE_1_S1CSH, ARM_SMMU_SH_OSH);
+	}
+
 	target->data[1] = cpu_to_le64(
-		FIELD_PREP(STRTAB_STE_1_S1DSS, s1dss) |
-		FIELD_PREP(STRTAB_STE_1_S1CIR, STRTAB_STE_1_S1C_CACHE_WBRA) |
-		FIELD_PREP(STRTAB_STE_1_S1COR, STRTAB_STE_1_S1C_CACHE_WBRA) |
-		FIELD_PREP(STRTAB_STE_1_S1CSH, ARM_SMMU_SH_ISH) |
+		FIELD_PREP(STRTAB_STE_1_S1DSS, s1dss) | val |
 		((smmu->features & ARM_SMMU_FEAT_STALLS &&
 		  !master->stall_enabled) ?
 			 STRTAB_STE_1_S1STALLD :
@@ -3746,7 +3765,7 @@ int arm_smmu_init_one_queue(struct arm_smmu_device *smmu,
 	q->cons_reg	= page + cons_off;
 	q->ent_dwords	= dwords;
 
-	q->q_base  = Q_BASE_RWA;
+	q->q_base  = smmu_coherent(smmu) ? Q_BASE_RWA : 0;
 	q->q_base |= q->base_dma & Q_BASE_ADDR_MASK;
 	q->q_base |= FIELD_PREP(Q_BASE_LOG2SIZE, q->llq.max_n_shift);
 
@@ -4093,6 +4112,7 @@ static void arm_smmu_write_strtab(struct arm_smmu_device *smmu)
 	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
 	dma_addr_t dma;
 	u32 reg;
+	u64 val;
 
 	if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
 		reg = FIELD_PREP(STRTAB_BASE_CFG_FMT,
@@ -4107,8 +4127,12 @@ static void arm_smmu_write_strtab(struct arm_smmu_device *smmu)
 		      FIELD_PREP(STRTAB_BASE_CFG_LOG2SIZE, smmu->sid_bits);
 		dma = cfg->linear.ste_dma;
 	}
-	writeq_relaxed((dma & STRTAB_BASE_ADDR_MASK) | STRTAB_BASE_RA,
-		       smmu->base + ARM_SMMU_STRTAB_BASE);
+
+	val = dma & STRTAB_BASE_ADDR_MASK;
+	if (smmu_coherent(smmu))
+		val |= STRTAB_BASE_RA;
+
+	writeq_relaxed(val, smmu->base + ARM_SMMU_STRTAB_BASE);
 	writel_relaxed(reg, smmu->base + ARM_SMMU_STRTAB_BASE_CFG);
 }
 
@@ -4130,12 +4154,21 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu)
 		return ret;
 
 	/* CR1 (table and queue memory attributes) */
-	reg = FIELD_PREP(CR1_TABLE_SH, ARM_SMMU_SH_ISH) |
-	      FIELD_PREP(CR1_TABLE_OC, CR1_CACHE_WB) |
-	      FIELD_PREP(CR1_TABLE_IC, CR1_CACHE_WB) |
-	      FIELD_PREP(CR1_QUEUE_SH, ARM_SMMU_SH_ISH) |
-	      FIELD_PREP(CR1_QUEUE_OC, CR1_CACHE_WB) |
-	      FIELD_PREP(CR1_QUEUE_IC, CR1_CACHE_WB);
+	if (smmu_coherent(smmu)) {
+		reg = FIELD_PREP(CR1_TABLE_SH, ARM_SMMU_SH_ISH) |
+		      FIELD_PREP(CR1_TABLE_OC, CR1_CACHE_WB) |
+		      FIELD_PREP(CR1_TABLE_IC, CR1_CACHE_WB) |
+		      FIELD_PREP(CR1_QUEUE_SH, ARM_SMMU_SH_ISH) |
+		      FIELD_PREP(CR1_QUEUE_OC, CR1_CACHE_WB) |
+		      FIELD_PREP(CR1_QUEUE_IC, CR1_CACHE_WB);
+	} else {
+		reg = FIELD_PREP(CR1_TABLE_SH, ARM_SMMU_SH_OSH) |
+		      FIELD_PREP(CR1_TABLE_OC, CR1_CACHE_NC) |
+		      FIELD_PREP(CR1_TABLE_IC, CR1_CACHE_NC) |
+		      FIELD_PREP(CR1_QUEUE_SH, ARM_SMMU_SH_OSH) |
+		      FIELD_PREP(CR1_QUEUE_OC, CR1_CACHE_NC) |
+		      FIELD_PREP(CR1_QUEUE_IC, CR1_CACHE_NC);
+	}
 	writel_relaxed(reg, smmu->base + ARM_SMMU_CR1);
 
 	/* CR2 (random crap) */
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index ae23aacc3840..7a5f76e165dc 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -183,6 +183,7 @@ struct arm_vsmmu;
 #define ARM_SMMU_SH_ISH			3
 #define ARM_SMMU_MEMATTR_DEVICE_nGnRE	0x1
 #define ARM_SMMU_MEMATTR_OIWB		0xf
+#define ARM_SMMU_MEMATTR_OINC		0x5
 
 #define Q_IDX(llq, p)			((p) & ((1 << (llq)->max_n_shift) - 1))
 #define Q_WRP(llq, p)			((p) & (1 << (llq)->max_n_shift))
-- 
2.25.1



From jie.gan at oss.qualcomm.com  Sun Dec 28 17:10:14 2025
From: jie.gan at oss.qualcomm.com (Jie Gan)
Date: Mon, 29 Dec 2025 09:10:14 +0800
Subject: [PATCH v9 2/8] coresight: tmc: add create/clean functions for
 etr_buf_list
In-Reply-To: <202512251923.GDSbVal1-lkp@intel.com>
References: <202512251923.GDSbVal1-lkp@intel.com>
Message-ID: <c60288a5-189d-4761-99eb-4681effe1252@oss.qualcomm.com>



On 12/26/2025 9:17 PM, Dan Carpenter wrote:
> Hi Jie,
> 
> kernel test robot noticed the following build warnings:
> 
> url:    https://github.com/intel-lab-lkp/linux/commits/Jie-Gan/coresight-core-Refactoring-ctcu_get_active_port-and-make-it-generic/20251224-171604
> base:   47b7b5e32bb7264b51b89186043e1ada4090b558
> patch link:    https://lore.kernel.org/r/20251224-enable-byte-cntr-for-ctcu-v9-2-886c4496fed4%40oss.qualcomm.com
> patch subject: [PATCH v9 2/8] coresight: tmc: add create/clean functions for etr_buf_list
> config: arm-randconfig-r073-20251225 (https://download.01.org/0day-ci/archive/20251225/202512251923.GDSbVal1-lkp at intel.com/config)
> compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 4ef602d446057dabf5f61fb221669ecbeda49279)
> 
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp at intel.com>
> | Reported-by: Dan Carpenter <dan.carpenter at linaro.org>
> | Closes: https://lore.kernel.org/r/202512251923.GDSbVal1-lkp at intel.com/
> 
> smatch warnings:
> drivers/hwtracing/coresight/coresight-tmc-etr.c:1992 tmc_create_etr_buf_list() warn: passing freed memory 'new_node' (line 1991)
> drivers/hwtracing/coresight/coresight-tmc-etr.c:1992 tmc_create_etr_buf_list() warn: passing zero to 'PTR_ERR'
> 
> vim +/new_node +1992 drivers/hwtracing/coresight/coresight-tmc-etr.c
> 
> 34af91eeb7e78e Jie Gan 2025-12-24  1959  int tmc_create_etr_buf_list(struct tmc_drvdata *drvdata, int num_nodes)
> 34af91eeb7e78e Jie Gan 2025-12-24  1960  {
> 34af91eeb7e78e Jie Gan 2025-12-24  1961  	struct etr_buf_node *new_node;
> 34af91eeb7e78e Jie Gan 2025-12-24  1962  	struct etr_buf *sysfs_buf;
> 34af91eeb7e78e Jie Gan 2025-12-24  1963  	int i = 0, ret = 0;
> 34af91eeb7e78e Jie Gan 2025-12-24  1964
> 34af91eeb7e78e Jie Gan 2025-12-24  1965  	/* We dont need a list if there is only one node */
> 34af91eeb7e78e Jie Gan 2025-12-24  1966  	if (num_nodes < 2)
> 34af91eeb7e78e Jie Gan 2025-12-24  1967  		return -EINVAL;
> 34af91eeb7e78e Jie Gan 2025-12-24  1968
> 34af91eeb7e78e Jie Gan 2025-12-24  1969  	/* We expect that sysfs_buf in drvdata has already been allocated. */
> 34af91eeb7e78e Jie Gan 2025-12-24  1970  	if (drvdata->sysfs_buf) {
> 34af91eeb7e78e Jie Gan 2025-12-24  1971  		/* Directly insert the allocated sysfs_buf into the list first */
> 34af91eeb7e78e Jie Gan 2025-12-24  1972  		new_node = kzalloc(sizeof(struct etr_buf_node), GFP_KERNEL);
> 34af91eeb7e78e Jie Gan 2025-12-24  1973  		if (IS_ERR(new_node))
> 34af91eeb7e78e Jie Gan 2025-12-24  1974  			return PTR_ERR(new_node);
> 34af91eeb7e78e Jie Gan 2025-12-24  1975
> 34af91eeb7e78e Jie Gan 2025-12-24  1976  		new_node->sysfs_buf = drvdata->sysfs_buf;
> 34af91eeb7e78e Jie Gan 2025-12-24  1977  		new_node->is_free = false;
> 34af91eeb7e78e Jie Gan 2025-12-24  1978  		list_add(&new_node->node, &drvdata->etr_buf_list);
> 34af91eeb7e78e Jie Gan 2025-12-24  1979  		i++;
> 34af91eeb7e78e Jie Gan 2025-12-24  1980  	}
> 34af91eeb7e78e Jie Gan 2025-12-24  1981
> 34af91eeb7e78e Jie Gan 2025-12-24  1982  	while (i < num_nodes) {
> 34af91eeb7e78e Jie Gan 2025-12-24  1983  		new_node = kzalloc(sizeof(struct etr_buf_node), GFP_KERNEL);
> 34af91eeb7e78e Jie Gan 2025-12-24  1984  		if (IS_ERR(new_node)) {
> 34af91eeb7e78e Jie Gan 2025-12-24  1985  			ret = PTR_ERR(new_node);
> 34af91eeb7e78e Jie Gan 2025-12-24  1986  			break;
> 34af91eeb7e78e Jie Gan 2025-12-24  1987  		}
> 34af91eeb7e78e Jie Gan 2025-12-24  1988
> 34af91eeb7e78e Jie Gan 2025-12-24  1989  		sysfs_buf = tmc_alloc_etr_buf(drvdata, drvdata->size, 0, cpu_to_node(0), NULL);
> 34af91eeb7e78e Jie Gan 2025-12-24  1990  		if (IS_ERR(sysfs_buf)) {
> 34af91eeb7e78e Jie Gan 2025-12-24 @1991  			kfree(new_node);
> 34af91eeb7e78e Jie Gan 2025-12-24 @1992  			ret = PTR_ERR(new_node);
> 
> s/new_node/sysfs_buf/

Thanks for reporting. Will fix it.

-Jie

> 
> 34af91eeb7e78e Jie Gan 2025-12-24  1993  			break;
> 34af91eeb7e78e Jie Gan 2025-12-24  1994  		}
> 34af91eeb7e78e Jie Gan 2025-12-24  1995
> 34af91eeb7e78e Jie Gan 2025-12-24  1996  		/* We dont have a available sysfs_buf in drvdata, setup one */
> 34af91eeb7e78e Jie Gan 2025-12-24  1997  		if (!drvdata->sysfs_buf) {
> 34af91eeb7e78e Jie Gan 2025-12-24  1998  			drvdata->sysfs_buf = sysfs_buf;
> 34af91eeb7e78e Jie Gan 2025-12-24  1999  			new_node->is_free = false;
> 34af91eeb7e78e Jie Gan 2025-12-24  2000  		} else
> 34af91eeb7e78e Jie Gan 2025-12-24  2001  			new_node->is_free = true;
> 34af91eeb7e78e Jie Gan 2025-12-24  2002
> 34af91eeb7e78e Jie Gan 2025-12-24  2003  		new_node->sysfs_buf = sysfs_buf;
> 34af91eeb7e78e Jie Gan 2025-12-24  2004  		list_add(&new_node->node, &drvdata->etr_buf_list);
> 34af91eeb7e78e Jie Gan 2025-12-24  2005  		i++;
> 34af91eeb7e78e Jie Gan 2025-12-24  2006  	}
> 34af91eeb7e78e Jie Gan 2025-12-24  2007
> 34af91eeb7e78e Jie Gan 2025-12-24  2008  	/* Clean the list if there is an error */
> 34af91eeb7e78e Jie Gan 2025-12-24  2009  	if (ret)
> 34af91eeb7e78e Jie Gan 2025-12-24  2010  		tmc_clean_etr_buf_list(drvdata);
> 34af91eeb7e78e Jie Gan 2025-12-24  2011
> 34af91eeb7e78e Jie Gan 2025-12-24  2012  	return ret;
> 34af91eeb7e78e Jie Gan 2025-12-24  2013  }
> 



From peter.chen at cixtech.com  Sun Dec 28 17:24:26 2025
From: peter.chen at cixtech.com (Peter Chen)
Date: Mon, 29 Dec 2025 09:24:26 +0800
Subject: [PATCH] mailbox: cix: fix typo in error message
In-Reply-To: <20251223120622.4316-1-lakshmicar.2023@gmail.com>
References: <20251223120622.4316-1-lakshmicar.2023@gmail.com>
Message-ID: <aVHYSvMpM-zcGSZH@nchen-desktop>

On 25-12-23 17:36:22, Lakshmi S wrote:
> 
> Fix typo "overlow" -> "overflow" in FIFO overflow error message.
> 
> Signed-off-by: Lakshmi S <lakshmicar.2023 at gmail.com>
> ---
>  drivers/mailbox/cix-mailbox.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/mailbox/cix-mailbox.c b/drivers/mailbox/cix-mailbox.c
> index 5bb1416c26a5..443620e8ae37 100644
> --- a/drivers/mailbox/cix-mailbox.c
> +++ b/drivers/mailbox/cix-mailbox.c
> @@ -346,7 +346,7 @@ static void cix_mbox_isr_fifo(struct mbox_chan *chan)
>                 /* FIFO overflow is generated */
>                 if (int_status & CIX_FIFO_OFLOW_INT) {
>                         status = cix_mbox_read(priv, CIX_FIFO_STAS);
> -                       dev_err(priv->dev, "fifo overlow: int_stats %d\n", status);
> +                       dev_err(priv->dev, "fifo overflow: int_stats %d\n", status);

Reviewed-by: Peter Chen <peter.chen at cixtech.com>

-- 

Best regards,
Peter


From peter.chen at cixtech.com  Sun Dec 28 17:40:10 2025
From: peter.chen at cixtech.com (Peter Chen)
Date: Mon, 29 Dec 2025 09:40:10 +0800
Subject: [PATCH] arm64: dts: cix: Use lowercase hex
In-Reply-To: <20251223152424.155253-2-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251223152424.155253-2-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <aVHb-kbi2QbChxj9@nchen-desktop>

On 25-12-23 16:24:25, Krzysztof Kozlowski wrote:
> EXTERNAL EMAIL
> 
> The DTS code coding style expects lowercase hex for values and unit
> addresses.
> 
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
> 
> ---
> 
> Patches done with sed, verified with comparing unflattened DTB and
> dtx_diff.
> ---
>  arch/arm64/boot/dts/cix/sky1.dtsi | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/boot/dts/cix/sky1.dtsi b/arch/arm64/boot/dts/cix/sky1.dtsi
> index 64b76905cbff..fb8c826bbc97 100644
> --- a/arch/arm64/boot/dts/cix/sky1.dtsi
> +++ b/arch/arm64/boot/dts/cix/sky1.dtsi
> @@ -523,7 +523,7 @@ pcie_x1_1_rc: pcie at a0e0000 {
>                         reg-names = "reg", "cfg", "rcsu_strap", "rcsu_status", "msg";
>                         ranges = <0x01000000 0x0 0x38100000 0x0 0x38100000 0x0 0x00100000>,
>                                  <0x02000000 0x0 0x38200000 0x0 0x38200000 0x0 0x07e00000>,
> -                                <0x43000000 0x0C 0x00000000 0x0C 0x00000000 0x04 0x00000000>;
> +                                <0x43000000 0x0c 0x00000000 0x0c 0x00000000 0x04 0x00000000>;

Sorry, I could not apply for v6.19-rc1, could you?

-- 

Best regards,
Peter


From peter.chen at cixtech.com  Sun Dec 28 17:56:11 2025
From: peter.chen at cixtech.com (Peter Chen)
Date: Mon, 29 Dec 2025 09:56:11 +0800
Subject: [PATCH v2 1/2] dt-bindings: arm: cix: add OrangePi 6 Plus board
In-Reply-To: <20251219133553.1440970-2-gary.yang@cixtech.com>
References: <20251219133553.1440970-1-gary.yang@cixtech.com>
 <20251219133553.1440970-2-gary.yang@cixtech.com>
Message-ID: <aVHfu5mcX3ZVqQih@nchen-desktop>

On 25-12-19 21:35:52, Gary Yang wrote:
> OrangePi 6 Plus adopts CIX CD8180/CD8160 SoC,
> built-in 12-core 64-bit processor + NPU processor,
> integrated graphics processor, equipped with 16GB/32GB/64GB
> LPDDR5, and provides two M.2 KEY-M interfaces 2280 for NVMe SSD,
> as well as SPI FLASH and TF slots to meet the needs of fast
> read/write and high-capacity storage;
> 
> Signed-off-by: Gary Yang <gary.yang at cixtech.com>
> ---
>  Documentation/devicetree/bindings/arm/cix.yaml | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/devicetree/bindings/arm/cix.yaml b/Documentation/devicetree/bindings/arm/cix.yaml
> index 114dab4bc4d2..e2cc0bb8b908 100644
> --- a/Documentation/devicetree/bindings/arm/cix.yaml
> +++ b/Documentation/devicetree/bindings/arm/cix.yaml
> @@ -18,7 +18,9 @@ properties:
>  
>        - description: Radxa Orion O6
>          items:
> -          - const: radxa,orion-o6
> +          - enum:
> +              - radxa,orion-o6
> +              - xunlong,orangepi-6-plus

The description is for Radxa O6, would you please add one description for
this orangepi-6-plus board?

-- 

Best regards,
Peter


From shawnguo at kernel.org  Sun Dec 28 18:42:30 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Mon, 29 Dec 2025 10:42:30 +0800
Subject: [PATCH] arm64: dts: imx8mp: Update Data Modul i.MX8M Plus eDM
 SBC DT to rev.903
In-Reply-To: <14c48d93-8ee6-4769-8dc3-5c527134bc77@mailbox.org>
References: <20241226171404.84095-1-marex@denx.de>
 <173531253398.3886481.9345779510218290682.robh@kernel.org>
 <14c48d93-8ee6-4769-8dc3-5c527134bc77@mailbox.org>
Message-ID: <aVHqlnNGNGmaF14m@dragon>

On Fri, Dec 26, 2025 at 11:24:29AM +0100, Marek Vasut wrote:
> On 12/27/24 4:18 PM, Rob Herring (Arm) wrote:
> 
> Hello Shawn,
> 
> > On Thu, 26 Dec 2024 18:13:27 +0100, Marek Vasut wrote:
> > > Update the DT to match newest Data Modul i.MX8M Plus eDM SBC rev.903
> > > board which implements significant changes. Keep some of the rev.900
> > > and rev.902 nodes in the DT so that a DTO can be used to support old
> > > rev.900 and rev.902 boards easily.
> 
> [...]
> 
> > arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dtb: tpm at 2e: compatible: 'oneOf' conditional failed, one must be fixed:
> > 	['st,st33tphf2ei2c', 'tcg,tpm-tis-i2c'] is too long
> > 	'st,st33tphf2ei2c' is not one of ['infineon,slb9673', 'nuvoton,npct75x', 'st,st33ktpm2xi2c']
> 
> This is addressed in bindings patch [1] . Can this patch and the bindings
> patch be applied ?
> 
> https://lore.kernel.org/all/20241226171124.83735-1-marex at denx.de/

Could you resend them?

Shawn


From shawnguo at kernel.org  Sun Dec 28 18:50:20 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Mon, 29 Dec 2025 10:50:20 +0800
Subject: [PATCH v3 5/6] arm64: dts: imx8qm: add ddr perf device node
In-Reply-To: <20251103-qm_dts-v3-5-2bfda8ee14c2@nxp.com>
References: <20251103-qm_dts-v3-0-2bfda8ee14c2@nxp.com>
 <20251103-qm_dts-v3-5-2bfda8ee14c2@nxp.com>
Message-ID: <aVHsbK-HEfYqpS9G@dragon>

On Mon, Nov 03, 2025 at 04:48:32PM -0500, Frank Li wrote:
> Add ddr perf monitor device node for i.MX8QM. Change imx8-ss-ddr.dtsi's
> compatible string to fsl,imx8qxp-ddr-pmu. i.MX8QM overwrite to
> fsl,imx8qm-ddr-pmu. All fallback to fsl,imx8-ddr-pmu.
> 
> Signed-off-by: Joakim Zhang <qiangqing.zhang at nxp.com>
> Signed-off-by: Frank Li <Frank.Li at nxp.com>

Applied, thanks!


From shawnguo at kernel.org  Sun Dec 28 18:50:41 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Mon, 29 Dec 2025 10:50:41 +0800
Subject: [PATCH v3 6/6] arm64: dts: imx8dxl-ss-ddr: Add DB (system
 interconnects) pmu support for i.MX8DXL
In-Reply-To: <20251103-qm_dts-v3-6-2bfda8ee14c2@nxp.com>
References: <20251103-qm_dts-v3-0-2bfda8ee14c2@nxp.com>
 <20251103-qm_dts-v3-6-2bfda8ee14c2@nxp.com>
Message-ID: <aVHsgSN5-gzJ4jt0@dragon>

On Mon, Nov 03, 2025 at 04:48:33PM -0500, Frank Li wrote:
> From: Jacky Bai <ping.bai at nxp.com>
> 
> Add DB pmu related nodes. This pmu is in DB (system interconnects).
> 
> Signed-off-by: Jacky Bai <ping.bai at nxp.com>
> Signed-off-by: Frank Li <Frank.Li at nxp.com>

Applied, thanks!


From marek.vasut at mailbox.org  Sun Dec 28 18:53:53 2025
From: marek.vasut at mailbox.org (Marek Vasut)
Date: Mon, 29 Dec 2025 03:53:53 +0100
Subject: [PATCH] arm64: dts: imx8mp: Update Data Modul i.MX8M Plus eDM SBC
 DT to rev.903
In-Reply-To: <aVHqlnNGNGmaF14m@dragon>
References: <20241226171404.84095-1-marex@denx.de>
 <173531253398.3886481.9345779510218290682.robh@kernel.org>
 <14c48d93-8ee6-4769-8dc3-5c527134bc77@mailbox.org> <aVHqlnNGNGmaF14m@dragon>
Message-ID: <b61fc304-26e0-422f-bb31-303e7bcbb824@mailbox.org>

On 12/29/25 3:42 AM, Shawn Guo wrote:
> On Fri, Dec 26, 2025 at 11:24:29AM +0100, Marek Vasut wrote:
>> On 12/27/24 4:18 PM, Rob Herring (Arm) wrote:
>>
>> Hello Shawn,
>>
>>> On Thu, 26 Dec 2024 18:13:27 +0100, Marek Vasut wrote:
>>>> Update the DT to match newest Data Modul i.MX8M Plus eDM SBC rev.903
>>>> board which implements significant changes. Keep some of the rev.900
>>>> and rev.902 nodes in the DT so that a DTO can be used to support old
>>>> rev.900 and rev.902 boards easily.
>>
>> [...]
>>
>>> arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dtb: tpm at 2e: compatible: 'oneOf' conditional failed, one must be fixed:
>>> 	['st,st33tphf2ei2c', 'tcg,tpm-tis-i2c'] is too long
>>> 	'st,st33tphf2ei2c' is not one of ['infineon,slb9673', 'nuvoton,npct75x', 'st,st33ktpm2xi2c']
>>
>> This is addressed in bindings patch [1] . Can this patch and the bindings
>> patch be applied ?
>>
>> https://lore.kernel.org/all/20241226171124.83735-1-marex at denx.de/
> 
> Could you resend them?
Why ? The emails are in lore/patchwork and the patches still apply just 
fine, don't they ?


From shawnguo at kernel.org  Sun Dec 28 18:54:05 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Mon, 29 Dec 2025 10:54:05 +0800
Subject: [PATCH 1/1] arm64: dts: imx8mp-evk: add camera ov5640 and
 related nodes
In-Reply-To: <20251114155001.1195702-1-Frank.Li@nxp.com>
References: <20251114155001.1195702-1-Frank.Li@nxp.com>
Message-ID: <aVHtTRNYQS6ju_yQ@dragon>

On Fri, Nov 14, 2025 at 10:50:01AM -0500, Frank Li wrote:
> Add camera ov5640 and related nodes.
> 
> Signed-off-by: Frank Li <Frank.Li at nxp.com>
> ---
>  arch/arm64/boot/dts/freescale/imx8mp-evk.dts | 80 ++++++++++++++++++++
>  1 file changed, 80 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
> index 3730792daf501..f5c19549acce5 100644
> --- a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
> +++ b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
> @@ -74,6 +74,27 @@ pcie0_refclk: pcie0-refclk {
>  		clock-frequency = <100000000>;
>  	};
>  
> +	reg_1v5: regulator-1v5 {
> +		compatible = "regulator-fixed";
> +		regulator-name = "1v5";
> +		regulator-min-microvolt = <1500000>;
> +		regulator-max-microvolt = <1500000>;
> +	};
> +
> +	reg_1v8: regulator-1v8 {
> +		compatible = "regulator-fixed";
> +		regulator-name = "1v8";
> +		regulator-min-microvolt = <1500000>;
> +		regulator-max-microvolt = <1500000>;

1800000 ?

> +	};
> +
> +	reg_2v8: regulator-1v8 {
> +		compatible = "regulator-fixed";
> +		regulator-name = "2v8";
> +		regulator-min-microvolt = <1500000>;
> +		regulator-max-microvolt = <1500000>;

2800000 ?

Shawn

> +	};
> +
>  	reg_audio_3v3: regulator-audio-3v3 {
>  		compatible = "regulator-fixed";
>  		regulator-name = "audio-3v3";
> @@ -556,6 +577,30 @@ &i2c2 {
>  	pinctrl-0 = <&pinctrl_i2c2>;
>  	status = "okay";
>  
> +	camera at 3c {
> +	       compatible = "ovti,ov5640";
> +	       reg = <0x3c>;
> +	       pinctrl-names = "default";
> +	       pinctrl-0 = <&pinctrl_csi0_pwn>, <&pinctrl_csi0_rst>, <&pinctrl_csi_mclk>;
> +	       clocks = <&clk IMX8MP_CLK_IPP_DO_CLKO2>;
> +	       clock-names = "xclk";
> +	       assigned-clocks = <&clk IMX8MP_CLK_IPP_DO_CLKO2>;
> +	       assigned-clock-parents = <&clk IMX8MP_CLK_24M>;
> +	       assigned-clock-rates = <24000000>;
> +	       powerdown-gpios = <&gpio2 11 GPIO_ACTIVE_HIGH>;
> +	       AVDD-supply = <&reg_2v8>;
> +	       DVDD-supply = <&reg_1v5>;
> +	       DOVDD-supply = <&reg_1v8>;
> +	       status = "okay";
> +
> +	       port {
> +		       ov5640_mipi_0_ep: endpoint {
> +			       remote-endpoint = <&mipi_csi0_ep>;
> +			       data-lanes = <1 2>;
> +		       };
> +	       };
> +	};
> +
>  	hdmi at 3d {
>  		compatible = "adi,adv7535";
>  		reg = <0x3d>;
> @@ -660,6 +705,10 @@ &i2c5 {
>  	 */
>  };
>  
> +&isi_0 {
> +	status = "okay";
> +};
> +
>  &lcdif1 {
>  	status = "okay";
>  };
> @@ -678,6 +727,19 @@ &micfil {
>  	status = "okay";
>  };
>  
> +&mipi_csi_0 {
> +	status = "okay";
> +
> +	ports {
> +	       port at 0 {
> +		       mipi_csi0_ep: endpoint {
> +				remote-endpoint = <&ov5640_mipi_0_ep>;
> +				data-lanes = <1 2>;
> +		       };
> +	       };
> +	};
> +};
> +
>  &mipi_dsi {
>  	samsung,esc-clock-frequency = <10000000>;
>  	status = "okay";
> @@ -849,6 +911,24 @@ MX8MP_IOMUXC_SAI3_RXC__GPIO4_IO29		0xd6
>  		>;
>  	};
>  
> +	pinctrl_csi_mclk: csi_mclk_grp {
> +		fsl,pins = <
> +			MX8MP_IOMUXC_GPIO1_IO15__CCM_CLKO2	0x50
> +		>;
> +	};
> +
> +	pinctrl_csi0_pwn: csi0_pwn_grp {
> +		fsl,pins = <
> +			MX8MP_IOMUXC_SD1_STROBE__GPIO2_IO11	0x10
> +		>;
> +	};
> +
> +	pinctrl_csi0_rst: csi0_rst_grp {
> +		fsl,pins = <
> +			MX8MP_IOMUXC_GPIO1_IO06__GPIO1_IO06	0x10
> +		>;
> +	};
> +
>  	pinctrl_eqos: eqosgrp {
>  		fsl,pins = <
>  			MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC				0x2
> -- 
> 2.34.1
> 


From shawnguo at kernel.org  Sun Dec 28 19:22:05 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Mon, 29 Dec 2025 11:22:05 +0800
Subject: [PATCH 0/2] arm64: dts: imx943-evk: add ENETC, EMDIO and PTP
 Timer support
In-Reply-To: <20251116013558.855256-1-wei.fang@nxp.com>
References: <20251116013558.855256-1-wei.fang@nxp.com>
Message-ID: <aVHz3aDIptmJ5llD@dragon>

On Sun, Nov 16, 2025 at 09:35:56AM +0800, Wei Fang wrote:
> This series add ENETC, EMDIO and PTP Timer support for the i.MX943-EVK
> board.
> 
> Wei Fang (2):
>   arm64: dts: imx94: add basic NETC related nodes
>   arm64: dts: imx943-evk: add ENETC, EMDIO and PTP Timer support

Applied both, thanks!


From zhangqiao22 at huawei.com  Sun Dec 28 19:23:56 2025
From: zhangqiao22 at huawei.com (Zhang Qiao)
Date: Mon, 29 Dec 2025 11:23:56 +0800
Subject: [PATCH 01/33] PCI: Prepare to protect against concurrent isolated
 cpuset change
In-Reply-To: <20251224134520.33231-2-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-2-frederic@kernel.org>
Message-ID: <e01189e1-d8ef-2791-632c-90d4d897859b@huawei.com>

Hi, Weisbecker?

? 2025/12/24 21:44, Frederic Weisbecker ??:
> HK_TYPE_DOMAIN will soon integrate cpuset isolated partitions and
> therefore be made modifiable at runtime. Synchronize against the cpumask
> update using RCU.
> 
> The RCU locked section includes both the housekeeping CPU target
> election for the PCI probe work and the work enqueue.
> 
> This way the housekeeping update side will simply need to flush the
> pending related works after updating the housekeeping mask in order to
> make sure that no PCI work ever executes on an isolated CPU. This part
> will be handled in a subsequent patch.
> 
> Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
> ---
>  drivers/pci/pci-driver.c | 47 ++++++++++++++++++++++++++++++++--------
>  1 file changed, 38 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
> index 7c2d9d596258..786d6ce40999 100644
> --- a/drivers/pci/pci-driver.c
> +++ b/drivers/pci/pci-driver.c
> @@ -302,9 +302,8 @@ struct drv_dev_and_id {
>  	const struct pci_device_id *id;
>  };
>  
> -static long local_pci_probe(void *_ddi)
> +static int local_pci_probe(struct drv_dev_and_id *ddi)
>  {
> -	struct drv_dev_and_id *ddi = _ddi;
>  	struct pci_dev *pci_dev = ddi->dev;
>  	struct pci_driver *pci_drv = ddi->drv;
>  	struct device *dev = &pci_dev->dev;
> @@ -338,6 +337,19 @@ static long local_pci_probe(void *_ddi)
>  	return 0;
>  }
>  
> +struct pci_probe_arg {
> +	struct drv_dev_and_id *ddi;
> +	struct work_struct work;
> +	int ret;
> +};
> +
> +static void local_pci_probe_callback(struct work_struct *work)
> +{
> +	struct pci_probe_arg *arg = container_of(work, struct pci_probe_arg, work);
> +
> +	arg->ret = local_pci_probe(arg->ddi);
> +}
> +
>  static bool pci_physfn_is_probed(struct pci_dev *dev)
>  {
>  #ifdef CONFIG_PCI_IOV
> @@ -362,34 +374,51 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
>  	dev->is_probed = 1;
>  
>  	cpu_hotplug_disable();
> -
>  	/*
>  	 * Prevent nesting work_on_cpu() for the case where a Virtual Function
>  	 * device is probed from work_on_cpu() of the Physical device.
>  	 */
>  	if (node < 0 || node >= MAX_NUMNODES || !node_online(node) ||
>  	    pci_physfn_is_probed(dev)) {
> -		cpu = nr_cpu_ids;
> +		error = local_pci_probe(&ddi);
>  	} else {
>  		cpumask_var_t wq_domain_mask;
> +		struct pci_probe_arg arg = { .ddi = &ddi };
> +
> +		INIT_WORK_ONSTACK(&arg.work, local_pci_probe_callback);
>  
>  		if (!zalloc_cpumask_var(&wq_domain_mask, GFP_KERNEL)) {
>  			error = -ENOMEM;

If we return from here, arg.work will not be destroyed.



>  			goto out;
>  		}
> +
> +		/*
> +		 * The target election and the enqueue of the work must be within
> +		 * the same RCU read side section so that when the workqueue pool
> +		 * is flushed after a housekeeping cpumask update, further readers
> +		 * are guaranteed to queue the probing work to the appropriate
> +		 * targets.
> +		 */
> +		rcu_read_lock();
>  		cpumask_and(wq_domain_mask,
>  			    housekeeping_cpumask(HK_TYPE_WQ),
>  			    housekeeping_cpumask(HK_TYPE_DOMAIN));
>  
>  		cpu = cpumask_any_and(cpumask_of_node(node),
>  				      wq_domain_mask);
> +		if (cpu < nr_cpu_ids) {
> +			schedule_work_on(cpu, &arg.work);
> +			rcu_read_unlock();
> +			flush_work(&arg.work);
> +			error = arg.ret;
> +		} else {
> +			rcu_read_unlock();
> +			error = local_pci_probe(&ddi);
> +		}
> +
>  		free_cpumask_var(wq_domain_mask);
> +		destroy_work_on_stack(&arg.work);
>  	}
> -
> -	if (cpu < nr_cpu_ids)
> -		error = work_on_cpu(cpu, local_pci_probe, &ddi);
> -	else
> -		error = local_pci_probe(&ddi);
>  out:
>  	dev->is_probed = 0;
>  	cpu_hotplug_enable();
> 


From lucaswei at google.com  Sun Dec 28 19:36:19 2025
From: lucaswei at google.com (Lucas Wei)
Date: Mon, 29 Dec 2025 03:36:19 +0000
Subject: [PATCH v2] arm64: errata: Workaround for SI L1 downstream coherency issue
Message-ID: <20251229033621.996546-1-lucaswei@google.com>

When software issues a Cache Maintenance Operation (CMO) targeting a
dirty cache line, the CPU and DSU cluster may optimize the operation by
combining the CopyBack Write and CMO into a single combined CopyBack
Write plus CMO transaction presented to the interconnect (MCN).
For these combined transactions, the MCN splits the operation into two
separate transactions, one Write and one CMO, and then propagates the
write and optionally the CMO to the downstream memory system or external
Point of Serialization (PoS).
However, the MCN may return an early CompCMO response to the DSU cluster
before the corresponding Write and CMO transactions have completed at
the external PoS or downstream memory. As a result, stale data may be
observed by external observers that are directly connected to the
external PoS or downstream memory.

This erratum affects any system topology in which the following
conditions apply:
 - The Point of Serialization (PoS) is located downstream of the
   interconnect.
 - A downstream observer accesses memory directly, bypassing the
   interconnect.

Conditions:
This erratum occurs only when all of the following conditions are met:
 1. Software executes a data cache maintenance operation, specifically,
    a clean or invalidate by virtual address (DC CVAC, DC CIVAC, or DC
    IVAC), that hits on unique dirty data in the CPU or DSU cache. This
    results in a combined CopyBack and CMO being issued to the
    interconnect.
 2. The interconnect splits the combined transaction into separate Write
    and CMO transactions and returns an early completion response to the
    CPU or DSU before the write has completed at the downstream memory
    or PoS.
 3. A downstream observer accesses the affected memory address after the
    early completion response is issued but before the actual memory
    write has completed. This allows the observer to read stale data
    that has not yet been updated at the PoS or downstream memory.

The implementation of workaround put a second loop of CMOs at the same
virtual address whose operation meet erratum conditions to wait until
cache data be cleaned to PoC.. This way of implementation mitigates
performance panalty compared to purly duplicate orignial CMO.

Reported-by: kernel test robot <lkp at intel.com>
Cc: stable at vger.kernel.org # 6.12.x
Signed-off-by: Lucas Wei <lucaswei at google.com>
---

Changes in v2:

 1. Fixed warning from kernel test robot by changing
    arm_si_l1_workaround_4311569 to static 
    [Reported-by: kernel test robot <lkp at intel.com>]

---
 Documentation/arch/arm64/silicon-errata.rst |  3 ++
 arch/arm64/Kconfig                          | 19 +++++++++++++
 arch/arm64/include/asm/assembler.h          | 10 +++++++
 arch/arm64/kernel/cpu_errata.c              | 31 +++++++++++++++++++++
 arch/arm64/mm/cache.S                       | 13 ++++++++-
 arch/arm64/tools/cpucaps                    |  1 +
 6 files changed, 76 insertions(+), 1 deletion(-)

diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst
index a7ec57060f64..98efdf528719 100644
--- a/Documentation/arch/arm64/silicon-errata.rst
+++ b/Documentation/arch/arm64/silicon-errata.rst
@@ -213,6 +213,9 @@ stable kernels.
 | ARM            | GIC-700         | #2941627        | ARM64_ERRATUM_2941627       |
 +----------------+-----------------+-----------------+-----------------------------+
 +----------------+-----------------+-----------------+-----------------------------+
+| ARM            | SI L1           | #4311569        | ARM64_ERRATUM_4311569       |
++----------------+-----------------+-----------------+-----------------------------+
++----------------+-----------------+-----------------+-----------------------------+
 | Broadcom       | Brahma-B53      | N/A             | ARM64_ERRATUM_845719        |
 +----------------+-----------------+-----------------+-----------------------------+
 | Broadcom       | Brahma-B53      | N/A             | ARM64_ERRATUM_843419        |
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 65db12f66b8f..a834d30859cc 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1153,6 +1153,25 @@ config ARM64_ERRATUM_3194386
 
 	  If unsure, say Y.
 
+config ARM64_ERRATUM_4311569
+	bool "SI L1: 4311569: workaround for premature CMO completion erratum"
+	default y
+	help
+	  This option adds the workaround for ARM SI L1 erratum 4311569.
+
+	  The erratum of SI L1 can cause an early response to a combined write
+	  and cache maintenance operation (WR+CMO) before the operation is fully
+	  completed to the Point of Serialization (POS).
+	  This can result in a non-I/O coherent agent observing stale data,
+	  potentially leading to system instability or incorrect behavior.
+
+	  Enabling this option implements a software workaround by inserting a
+	  second loop of Cache Maintenance Operation (CMO) immediately following the
+	  end of function to do CMOs. This ensures that the data is correctly serialized
+	  before the buffer is handed off to a non-coherent agent.
+
+	  If unsure, say Y.
+
 config CAVIUM_ERRATUM_22375
 	bool "Cavium erratum 22375, 24313"
 	default y
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index f0ca7196f6fa..d3d46e5f7188 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -381,6 +381,9 @@ alternative_endif
 	.macro dcache_by_myline_op op, domain, start, end, linesz, tmp, fixup
 	sub	\tmp, \linesz, #1
 	bic	\start, \start, \tmp
+alternative_if ARM64_WORKAROUND_4311569
+	mov	\tmp, \start
+alternative_else_nop_endif
 .Ldcache_op\@:
 	.ifc	\op, cvau
 	__dcache_op_workaround_clean_cache \op, \start
@@ -402,6 +405,13 @@ alternative_endif
 	add	\start, \start, \linesz
 	cmp	\start, \end
 	b.lo	.Ldcache_op\@
+alternative_if ARM64_WORKAROUND_4311569
+	.ifnc	\op, cvau
+	mov	\start, \tmp
+	mov	\tmp, xzr
+	cbnz	\start, .Ldcache_op\@
+	.endif
+alternative_else_nop_endif
 	dsb	\domain
 
 	_cond_uaccess_extable .Ldcache_op\@, \fixup
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index 8cb3b575a031..5c0ab6bfd44a 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -141,6 +141,30 @@ has_mismatched_cache_type(const struct arm64_cpu_capabilities *entry,
 	return (ctr_real != sys) && (ctr_raw != sys);
 }
 
+#ifdef CONFIG_ARM64_ERRATUM_4311569
+static DEFINE_STATIC_KEY_FALSE(arm_si_l1_workaround_4311569);
+static int __init early_arm_si_l1_workaround_4311569_cfg(char *arg)
+{
+	static_branch_enable(&arm_si_l1_workaround_4311569);
+	pr_info("Enabling cache maintenance workaround for ARM SI-L1 erratum 4311569\n");
+
+	return 0;
+}
+early_param("arm_si_l1_workaround_4311569", early_arm_si_l1_workaround_4311569_cfg);
+
+/*
+ * We have some earlier use cases to call cache maintenance operation functions, for example,
+ * dcache_inval_poc() and dcache_clean_poc() in head.S, before making decision to turn on this
+ * workaround. Since the scope of this workaround is limited to non-coherent DMA agents, its
+ * safe to have the workaround off by default.
+ */
+static bool
+need_arm_si_l1_workaround_4311569(const struct arm64_cpu_capabilities *entry, int scope)
+{
+	return static_branch_unlikely(&arm_si_l1_workaround_4311569);
+}
+#endif
+
 static void
 cpu_enable_trap_ctr_access(const struct arm64_cpu_capabilities *cap)
 {
@@ -870,6 +894,13 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
 		ERRATA_MIDR_RANGE_LIST(erratum_spec_ssbs_list),
 	},
 #endif
+#ifdef CONFIG_ARM64_ERRATUM_4311569
+	{
+		.capability = ARM64_WORKAROUND_4311569,
+		.type = ARM64_CPUCAP_SYSTEM_FEATURE,
+		.matches = need_arm_si_l1_workaround_4311569,
+	},
+#endif
 #ifdef CONFIG_ARM64_WORKAROUND_SPECULATIVE_UNPRIV_LOAD
 	{
 		.desc = "ARM errata 2966298, 3117295",
diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S
index 503567c864fd..ddf0097624ed 100644
--- a/arch/arm64/mm/cache.S
+++ b/arch/arm64/mm/cache.S
@@ -143,9 +143,14 @@ SYM_FUNC_END(dcache_clean_pou)
  *	- end     - kernel end address of region
  */
 SYM_FUNC_START(__pi_dcache_inval_poc)
+alternative_if ARM64_WORKAROUND_4311569
+	mov	x4, x0
+	mov	x5, x1
+	mov	x6, #1
+alternative_else_nop_endif
 	dcache_line_size x2, x3
 	sub	x3, x2, #1
-	tst	x1, x3				// end cache line aligned?
+again:	tst	x1, x3				// end cache line aligned?
 	bic	x1, x1, x3
 	b.eq	1f
 	dc	civac, x1			// clean & invalidate D / U line
@@ -158,6 +163,12 @@ SYM_FUNC_START(__pi_dcache_inval_poc)
 3:	add	x0, x0, x2
 	cmp	x0, x1
 	b.lo	2b
+alternative_if ARM64_WORKAROUND_4311569
+	mov	x0, x4
+	mov	x1, x5
+	sub	x6, x6, #1
+	cbz	x6, again
+alternative_else_nop_endif
 	dsb	sy
 	ret
 SYM_FUNC_END(__pi_dcache_inval_poc)
diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps
index 1b32c1232d28..3b18734f9744 100644
--- a/arch/arm64/tools/cpucaps
+++ b/arch/arm64/tools/cpucaps
@@ -101,6 +101,7 @@ WORKAROUND_2077057
 WORKAROUND_2457168
 WORKAROUND_2645198
 WORKAROUND_2658417
+WORKAROUND_4311569
 WORKAROUND_AMPERE_AC03_CPU_38
 WORKAROUND_AMPERE_AC04_CPU_23
 WORKAROUND_TRBE_OVERWRITE_FILL_MODE

base-commit: edde060637b92607f3522252c03d64ad06369933
-- 
2.52.0.358.g0dd7633a29-goog



From wei.fang at nxp.com  Sun Dec 28 19:41:58 2025
From: wei.fang at nxp.com (Wei Fang)
Date: Mon, 29 Dec 2025 03:41:58 +0000
Subject: [PATCH net] net: stmmac: fix the crash issue for zero copy XDP_TX
 action
In-Reply-To: <20251204071332.1907111-1-wei.fang@nxp.com>
References: <20251204071332.1907111-1-wei.fang@nxp.com>
Message-ID: <PAXPR04MB8510BCFE90FBBBDF2915B89388BFA@PAXPR04MB8510.eurprd04.prod.outlook.com>

> There is a crash issue when running zero copy XDP_TX action, the crash
> log is shown below.
> 
> [  216.122464] Unable to handle kernel paging request at virtual address
> fffeffff80000000
> [  216.187524] Internal error: Oops: 0000000096000144 [#1]  SMP
> [  216.301694] Call trace:
> [  216.304130]  dcache_clean_poc+0x20/0x38 (P)
> [  216.308308]  __dma_sync_single_for_device+0x1bc/0x1e0
> [  216.313351]  stmmac_xdp_xmit_xdpf+0x354/0x400
> [  216.317701]  __stmmac_xdp_run_prog+0x164/0x368
> [  216.322139]  stmmac_napi_poll_rxtx+0xba8/0xf00
> [  216.326576]  __napi_poll+0x40/0x218
> [  216.408054] Kernel panic - not syncing: Oops: Fatal exception in interrupt
> 
> For XDP_TX action, the xdp_buff is converted to xdp_frame by
> xdp_convert_buff_to_frame(). The memory type of the resulting xdp_frame
> depends on the memory type of the xdp_buff. For page pool based xdp_buff
> it produces xdp_frame with memory type MEM_TYPE_PAGE_POOL. For zero
> copy
> XSK pool based xdp_buff it produces xdp_frame with memory type
> MEM_TYPE_PAGE_ORDER0. However, stmmac_xdp_xmit_back() does not
> check the
> memory type and always uses the page pool type, this leads to invalid
> mappings and causes the crash. Therefore, check the xdp_buff memory type
> in stmmac_xdp_xmit_back() to fix this issue.
> 
> Fixes: bba2556efad6 ("net: stmmac: Enable RX via AF_XDP zero-copy")
> Signed-off-by: Wei Fang <wei.fang at nxp.com>
> ---
>  .../net/ethernet/stmicro/stmmac/stmmac_main.c   | 17
> +++++++++++++++--

Hi,

Could this patch be applied?



From shawnguo at kernel.org  Sun Dec 28 19:45:21 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Mon, 29 Dec 2025 11:45:21 +0800
Subject: [PATCH] arm64: dts: imx8mp: Update Data Modul i.MX8M Plus eDM
 SBC DT to rev.903
In-Reply-To: <b61fc304-26e0-422f-bb31-303e7bcbb824@mailbox.org>
References: <20241226171404.84095-1-marex@denx.de>
 <173531253398.3886481.9345779510218290682.robh@kernel.org>
 <14c48d93-8ee6-4769-8dc3-5c527134bc77@mailbox.org>
 <aVHqlnNGNGmaF14m@dragon>
 <b61fc304-26e0-422f-bb31-303e7bcbb824@mailbox.org>
Message-ID: <aVH5Ua2g8WbpW3Ge@dragon>

On Mon, Dec 29, 2025 at 03:53:53AM +0100, Marek Vasut wrote:
> On 12/29/25 3:42 AM, Shawn Guo wrote:
> > On Fri, Dec 26, 2025 at 11:24:29AM +0100, Marek Vasut wrote:
> > > On 12/27/24 4:18 PM, Rob Herring (Arm) wrote:
> > > 
> > > Hello Shawn,
> > > 
> > > > On Thu, 26 Dec 2024 18:13:27 +0100, Marek Vasut wrote:
> > > > > Update the DT to match newest Data Modul i.MX8M Plus eDM SBC rev.903
> > > > > board which implements significant changes. Keep some of the rev.900
> > > > > and rev.902 nodes in the DT so that a DTO can be used to support old
> > > > > rev.900 and rev.902 boards easily.
> > > 
> > > [...]
> > > 
> > > > arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dtb: tpm at 2e: compatible: 'oneOf' conditional failed, one must be fixed:
> > > > 	['st,st33tphf2ei2c', 'tcg,tpm-tis-i2c'] is too long
> > > > 	'st,st33tphf2ei2c' is not one of ['infineon,slb9673', 'nuvoton,npct75x', 'st,st33ktpm2xi2c']
> > > 
> > > This is addressed in bindings patch [1] . Can this patch and the bindings
> > > patch be applied ?
> > > 
> > > https://lore.kernel.org/all/20241226171124.83735-1-marex at denx.de/
> > 
> > Could you resend them?
> Why ? The emails are in lore/patchwork and the patches still apply just
> fine, don't they ?

A couple of reasons:

- The patches were sent one year ago.
- They should be in a single series, as binding change is a prerequisite of DTS one.

Shawn


From shawnguo at kernel.org  Sun Dec 28 19:52:21 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Mon, 29 Dec 2025 11:52:21 +0800
Subject: [PATCH v2 0/2] Add and Update display overlays for libra
In-Reply-To: <20251117124515.26675-1-y.varakala@phytec.de>
References: <20251117124515.26675-1-y.varakala@phytec.de>
Message-ID: <aVH69fio_tx5XR2f@dragon>

On Mon, Nov 17, 2025 at 01:45:13PM +0100, Yashwanth Varakala wrote:
> Add ph128800t006-zhc01 multimedia dispaly overlay for the onboard imx8mp
> libra. Update panel node naming style in etml1010g3dra onboard dispaly
> overlay.
> 
> Also add the PEB-AV-10 expansion board overlay that can support audio
> without the display.
> 
> Update panel and backlight node naming style of the i.MX8MP Libra RDK
> devicetree.
> 
> Yashwanth Varakala (2):
>   arm64: dts: imx8mp libra: add and update display overlays
>   arm64: dts: imx8mp libra: add peb-av-10 expansion board overlay

Applied both, thanks!


From llong at redhat.com  Sun Dec 28 19:53:41 2025
From: llong at redhat.com (Waiman Long)
Date: Sun, 28 Dec 2025 22:53:41 -0500
Subject: [PATCH 01/33] PCI: Prepare to protect against concurrent isolated
 cpuset change
In-Reply-To: <e01189e1-d8ef-2791-632c-90d4d897859b@huawei.com>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-2-frederic@kernel.org>
 <e01189e1-d8ef-2791-632c-90d4d897859b@huawei.com>
Message-ID: <81f201cc-395a-48d7-a1b0-db8c62b93c9e@redhat.com>

On 12/28/25 10:23 PM, Zhang Qiao wrote:
> Hi, Weisbecker?
>
> ? 2025/12/24 21:44, Frederic Weisbecker ??:
>> HK_TYPE_DOMAIN will soon integrate cpuset isolated partitions and
>> therefore be made modifiable at runtime. Synchronize against the cpumask
>> update using RCU.
>>
>> The RCU locked section includes both the housekeeping CPU target
>> election for the PCI probe work and the work enqueue.
>>
>> This way the housekeeping update side will simply need to flush the
>> pending related works after updating the housekeeping mask in order to
>> make sure that no PCI work ever executes on an isolated CPU. This part
>> will be handled in a subsequent patch.
>>
>> Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
>> ---
>>   drivers/pci/pci-driver.c | 47 ++++++++++++++++++++++++++++++++--------
>>   1 file changed, 38 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
>> index 7c2d9d596258..786d6ce40999 100644
>> --- a/drivers/pci/pci-driver.c
>> +++ b/drivers/pci/pci-driver.c
>> @@ -302,9 +302,8 @@ struct drv_dev_and_id {
>>   	const struct pci_device_id *id;
>>   };
>>   
>> -static long local_pci_probe(void *_ddi)
>> +static int local_pci_probe(struct drv_dev_and_id *ddi)
>>   {
>> -	struct drv_dev_and_id *ddi = _ddi;
>>   	struct pci_dev *pci_dev = ddi->dev;
>>   	struct pci_driver *pci_drv = ddi->drv;
>>   	struct device *dev = &pci_dev->dev;
>> @@ -338,6 +337,19 @@ static long local_pci_probe(void *_ddi)
>>   	return 0;
>>   }
>>   
>> +struct pci_probe_arg {
>> +	struct drv_dev_and_id *ddi;
>> +	struct work_struct work;
>> +	int ret;
>> +};
>> +
>> +static void local_pci_probe_callback(struct work_struct *work)
>> +{
>> +	struct pci_probe_arg *arg = container_of(work, struct pci_probe_arg, work);
>> +
>> +	arg->ret = local_pci_probe(arg->ddi);
>> +}
>> +
>>   static bool pci_physfn_is_probed(struct pci_dev *dev)
>>   {
>>   #ifdef CONFIG_PCI_IOV
>> @@ -362,34 +374,51 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
>>   	dev->is_probed = 1;
>>   
>>   	cpu_hotplug_disable();
>> -
>>   	/*
>>   	 * Prevent nesting work_on_cpu() for the case where a Virtual Function
>>   	 * device is probed from work_on_cpu() of the Physical device.
>>   	 */
>>   	if (node < 0 || node >= MAX_NUMNODES || !node_online(node) ||
>>   	    pci_physfn_is_probed(dev)) {
>> -		cpu = nr_cpu_ids;
>> +		error = local_pci_probe(&ddi);
>>   	} else {
>>   		cpumask_var_t wq_domain_mask;
>> +		struct pci_probe_arg arg = { .ddi = &ddi };
>> +
>> +		INIT_WORK_ONSTACK(&arg.work, local_pci_probe_callback);
>>   
>>   		if (!zalloc_cpumask_var(&wq_domain_mask, GFP_KERNEL)) {
>>   			error = -ENOMEM;
> If we return from here, arg.work will not be destroyed.
>
>
Right. INIT_WORK_ONSTACK() should be called after successful 
cpumask_var_t allocation.

Cheers,
Longman

>>   			goto out;
>>   		}
>> +
>> +		/*
>> +		 * The target election and the enqueue of the work must be within
>> +		 * the same RCU read side section so that when the workqueue pool
>> +		 * is flushed after a housekeeping cpumask update, further readers
>> +		 * are guaranteed to queue the probing work to the appropriate
>> +		 * targets.
>> +		 */
>> +		rcu_read_lock();
>>   		cpumask_and(wq_domain_mask,
>>   			    housekeeping_cpumask(HK_TYPE_WQ),
>>   			    housekeeping_cpumask(HK_TYPE_DOMAIN));
>>   
>>   		cpu = cpumask_any_and(cpumask_of_node(node),
>>   				      wq_domain_mask);
>> +		if (cpu < nr_cpu_ids) {
>> +			schedule_work_on(cpu, &arg.work);
>> +			rcu_read_unlock();
>> +			flush_work(&arg.work);
>> +			error = arg.ret;
>> +		} else {
>> +			rcu_read_unlock();
>> +			error = local_pci_probe(&ddi);
>> +		}
>> +
>>   		free_cpumask_var(wq_domain_mask);
>> +		destroy_work_on_stack(&arg.work);
>>   	}
>> -
>> -	if (cpu < nr_cpu_ids)
>> -		error = work_on_cpu(cpu, local_pci_probe, &ddi);
>> -	else
>> -		error = local_pci_probe(&ddi);
>>   out:
>>   	dev->is_probed = 0;
>>   	cpu_hotplug_enable();
>>



From sumit.garg at kernel.org  Sun Dec 28 21:39:29 2025
From: sumit.garg at kernel.org (Sumit Garg)
Date: Mon, 29 Dec 2025 11:09:29 +0530
Subject: [PATCH v20 1/6] dt-bindings: firmware: Add TEE remoteproc
 service binding
In-Reply-To: <20251217153917.3998544-2-arnaud.pouliquen@foss.st.com>
References: <20251217153917.3998544-1-arnaud.pouliquen@foss.st.com>
 <20251217153917.3998544-2-arnaud.pouliquen@foss.st.com>
Message-ID: <aVIUEafDoVQv0rHf@sumit-xelite>

On Wed, Dec 17, 2025 at 04:39:12PM +0100, Arnaud Pouliquen wrote:
> Add a device tree binding for the TEE-based remote processor control
> service implemented as an OP-TEE Trusted Application identified by
> UUID 80a4c275-0a47-4905-8285-1486a9771a08.
> 
> The TEE service node is a child of the "linaro,optee-tz" firmware node and
> acts as a container for remoteproc devices that are controlled via TEE.
> 
> In addition, the "linaro,optee-tz" binding is updated to specify the
> '#address-cells' and '#size-cells' values used for child TEE service
> nodes.
> 
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen at foss.st.com>
> ---
>  .../arm/firmware/linaro,optee-tz.yaml         |  6 +++
>  .../bindings/remoteproc/remoteproc-tee.yaml   | 47 +++++++++++++++++++
>  2 files changed, 53 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/remoteproc/remoteproc-tee.yaml
> 
> diff --git a/Documentation/devicetree/bindings/arm/firmware/linaro,optee-tz.yaml b/Documentation/devicetree/bindings/arm/firmware/linaro,optee-tz.yaml
> index 5d033570b57b..ab69eecba9ad 100644
> --- a/Documentation/devicetree/bindings/arm/firmware/linaro,optee-tz.yaml
> +++ b/Documentation/devicetree/bindings/arm/firmware/linaro,optee-tz.yaml
> @@ -41,6 +41,12 @@ properties:
>        HVC #0, register assignments
>        register assignments are specified in drivers/tee/optee/optee_smc.h
>  
> +  "#address-cells":
> +    const: 1
> +
> +  "#size-cells":
> +    const: 0
> +
>  required:
>    - compatible
>    - method
> diff --git a/Documentation/devicetree/bindings/remoteproc/remoteproc-tee.yaml b/Documentation/devicetree/bindings/remoteproc/remoteproc-tee.yaml
> new file mode 100644
> index 000000000000..083ecf1f38cf
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/remoteproc/remoteproc-tee.yaml
> @@ -0,0 +1,47 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/remoteproc/remoteproc-tee.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: TEE Remote Processor Control Service (UUID 80a4c275-0a47-4905-8285-1486a9771a08)
> +
> +maintainers:
> +  - Arnaud Pouliquen <arnaud.pouliquen at foss.st.com>
> +
> +description: |
> +  Node describing a TEE-based remote processor control service implemented as
> +  a Trusted Application identified by UUID 80a4c275-0a47-4905-8285-1486a9771a08.
> +
> +  It is a child of the OP-TEE firmware node ("linaro,optee-tz") and acts as a
> +  container for child remoteproc devices (for example, the STM32MP15 M4 core
> +  described by "st,stm32mp1-tee").
> +
> +properties:
> +  compatible:
> +    const: rproc-service-80a4c275-0a47-4905-8285-1486a9771a08

This should just be "80a4c275-0a47-4905-8285-1486a9771a08" which is the
device/service identity on TEE bus.

-Sumit

> +
> +  reg:
> +    description: |
> +      Logical identifier of the TEE remoteproc service instance.
> +    maxItems: 1
> +
> +  "#address-cells":
> +    const: 1
> +
> +  "#size-cells":
> +    const: 0
> +
> +patternProperties:
> +  "^[a-zA-Z0-9,._-]+@[0-9a-fA-F]+$":
> +    type: object
> +
> +
> +required:
> +  - compatible
> +  - reg
> +  - "#address-cells"
> +  - "#size-cells"
> +
> +additionalProperties: false
> +...
> -- 
> 2.43.0
> 


From sumit.garg at kernel.org  Sun Dec 28 21:50:47 2025
From: sumit.garg at kernel.org (Sumit Garg)
Date: Mon, 29 Dec 2025 11:20:47 +0530
Subject: [PATCH v20 5/6] remoteproc: Add TEE support
In-Reply-To: <20251217153917.3998544-6-arnaud.pouliquen@foss.st.com>
References: <20251217153917.3998544-1-arnaud.pouliquen@foss.st.com>
 <20251217153917.3998544-6-arnaud.pouliquen@foss.st.com>
Message-ID: <aVIWt5bWP9R9j7nx@sumit-xelite>

On Wed, Dec 17, 2025 at 04:39:16PM +0100, Arnaud Pouliquen wrote:
> Add a remoteproc TEE (Trusted Execution Environment) driver that will be
> probed by the TEE bus. If the associated Trusted application is supported
> on the secure part, this driver offers a client interface to load firmware
> by the secure part.
> This firmware could be authenticated by the secure trusted application.
> 
> A specificity of the implementation is that the firmware has to be
> authenticated and optionally decrypted to access the resource table.
> 
> Consequently, the boot sequence is:
> 
> 1) rproc_parse_fw --> rproc_tee_parse_fw
>    remoteproc TEE:
>    - Requests the TEE application to authenticate and load the firmware
>      in the remote processor memories.
>    - Requests the TEE application for the address of the resource table.
>    - Creates a copy of the resource table stored in rproc->cached_table.
> 
> 2) rproc_load_segments --> rproc_tee_load_fw
>    remoteproc TEE:
>    - Requests the TEE application to load the firmware. Nothing is done
>      at the TEE application as the firmware is already loaded.
>    - In case of recovery, the TEE application has to reload the firmware.
> 
> 3) rproc_tee_get_loaded_rsc_table
>    remoteproc TEE requests the TEE application for the address of the
>    resource table.
> 
> 4) rproc_start --> rproc_tee_start
>    - Requests the TEE application to start the remote processor.
> 
> The shutdown sequence is:
> 
> 5) rproc_stop --> rproc_tee_stop
>    - Requests the TEE application to stop the remote processor.
> 
> 6) rproc_tee_release_fw
>    This function is used to request the TEE application to perform actions
>    to return to the initial state on stop or on error during the boot
>    sequence.
> 
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen at foss.st.com>
> ---
> Version 20 updates:
> - rework probe. the remoteproc-tee now probe the remoteproc devices
>   defined in device tree as child.
>   - creation of rproc-service-80a4c275-0a47-4905-8285-1486a9771a08 compatible
>   - use of of_find_compatible_node() to find node in DT
>   - use of of_platform_populate() to probe remoteproc devices
> - remove device_link_add() as now managed by of_platform_populate)
> - add "auto_boot" parameter in rproc_tee_register()
> - rename TA_RPROC_FW_CMD_* TEE CMD in  TA_RPROC_CMD_* command
> - use of DEFINE_MUTEX
> 
> Version 19 updates:
> - rework/fix function headers
> - use memremap instead of ioremap for the resource table.
> - realign comments to 80 chars limit, with few exceptions for readability
> - replace spinlock by mutex and and protect APIs from concurrent access
> - add support of 64-bit address in rproc_tee_get_loaded_rsc_table()
> - update copyright year
> 
> Version 18 updates:
> Fix warning:
> warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
> ---
>  drivers/remoteproc/Kconfig          |  10 +
>  drivers/remoteproc/Makefile         |   1 +
>  drivers/remoteproc/remoteproc_tee.c | 771 ++++++++++++++++++++++++++++
>  include/linux/remoteproc_tee.h      |  89 ++++
>  4 files changed, 871 insertions(+)
>  create mode 100644 drivers/remoteproc/remoteproc_tee.c
>  create mode 100644 include/linux/remoteproc_tee.h
> 
> diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
> index 48a0d3a69ed0..75265f3f5008 100644
> --- a/drivers/remoteproc/Kconfig
> +++ b/drivers/remoteproc/Kconfig
> @@ -23,6 +23,16 @@ config REMOTEPROC_CDEV
>  
>  	  It's safe to say N if you don't want to use this interface.
>  
> +config REMOTEPROC_TEE
> +	bool "Remoteproc support by a TEE application"
> +	depends on OPTEE
> +	help
> +	  Support a remote processor that is managed by an application running in a Trusted
> +	  Execution Environment (TEE). This application is responsible for loading the remote
> +	  processor firmware image and managing its lifecycle.
> +
> +	  It's safe to say N if the remote processor is not managed by a TEE.
> +
>  config IMX_REMOTEPROC
>  	tristate "i.MX remoteproc support"
>  	depends on ARCH_MXC
> diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
> index 1c7598b8475d..a1a5201982d4 100644
> --- a/drivers/remoteproc/Makefile
> +++ b/drivers/remoteproc/Makefile
> @@ -11,6 +11,7 @@ remoteproc-y				+= remoteproc_sysfs.o
>  remoteproc-y				+= remoteproc_virtio.o
>  remoteproc-y				+= remoteproc_elf_loader.o
>  obj-$(CONFIG_REMOTEPROC_CDEV)		+= remoteproc_cdev.o
> +obj-$(CONFIG_REMOTEPROC_TEE)		+= remoteproc_tee.o
>  obj-$(CONFIG_IMX_REMOTEPROC)		+= imx_rproc.o
>  obj-$(CONFIG_IMX_DSP_REMOTEPROC)	+= imx_dsp_rproc.o
>  obj-$(CONFIG_INGENIC_VPU_RPROC)		+= ingenic_rproc.o
> diff --git a/drivers/remoteproc/remoteproc_tee.c b/drivers/remoteproc/remoteproc_tee.c
> new file mode 100644
> index 000000000000..081420c35c88
> --- /dev/null
> +++ b/drivers/remoteproc/remoteproc_tee.c
> @@ -0,0 +1,771 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) STMicroelectronics 2025
> + * Author: Arnaud Pouliquen <arnaud.pouliquen at foss.st.com>
> + */
> +
> +#include <linux/firmware.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/mutex.h>
> +#include <linux/remoteproc.h>
> +#include <linux/remoteproc_tee.h>
> +#include <linux/slab.h>
> +#include <linux/tee_drv.h>
> +
> +#include "remoteproc_internal.h"
> +
> +#define MAX_TEE_PARAM_ARRAY_MEMBER	4
> +
> +/*
> + * Authentication and load of the firmware image in the remote processor
> + * memories by the TEE. After this step the firmware is installed in destination
> + * memories, which can then be locked to prevent access by Linux.
> + *
> + * [in]  params[0].value.a: remote processor identifier
> + * [in]  params[1].memref:  buffer containing a temporary copy of the signed
> + *			    image to load.
> + */
> +#define TA_RPROC_CMD_LOAD_FW		1
> +
> +/*
> + * Start the remote processor by the TEE
> + *
> + * [in]  params[0].value.a: remote processor identifier
> + */
> +#define TA_RPROC_CMD_START		2
> +
> +/*
> + * Stop the remote processor by the TEE
> + *
> + * [in]  params[0].value.a: remote processor identifier
> + */
> +#define TA_RPROC_CMD_STOP		3
> +
> +/*
> + * Return the address of the resource table, or 0 if not found.
> + *
> + * [in]  params[0].value.a: remote processor identifier
> + * [out] params[1].value.a: 32bit LSB resource table memory address
> + * [out] params[1].value.b: 32bit MSB resource table memory address
> + * [out] params[2].value.a: 32bit LSB resource table memory size
> + * [out] params[2].value.b: 32bit MSB resource table memory size
> + */
> +#define TA_RPROC_CMD_GET_RSC_TABLE	4
> +
> +/*
> + * Release remote processor firmware images and associated resources.
> + * This command should be used in case an error occurs between the loading of
> + * the firmware images (TA_RPROC_CMD_LOAD_FW) and the starting of the remote
> + * processor (TA_RPROC_CMD_START) or after stopping the remote processor
> + * to release associated resources (TA_RPROC_CMD_STOP).
> + *
> + * [in]  params[0].value.a: remote processor identifier
> + */
> +#define TA_RPROC_CMD_RELEASE_FW		6
> +
> +struct rproc_tee_context {
> +	struct list_head	rproc_list;
> +	struct tee_context	*tee_ctx;
> +	struct device		*dev;
> +};
> +
> +/**
> + * struct rproc_tee - TEE remoteproc structure
> + * @node:       Reference in list
> + * @rproc:      Remoteproc reference
> + * @rproc_id:   remote processor identifier
> + * @session_id: TEE session identifier
> + */
> +struct rproc_tee {
> +	struct list_head node;
> +	struct rproc *rproc;
> +	u32 rproc_id;
> +	u32 session_id;
> +};
> +
> +static struct rproc_tee_context rproc_tee_ctx;
> +static DEFINE_MUTEX(ctx_lock); /* Protects concurrent manipulations of the rproc_tee_ctx*/
> +
> +static struct rproc_tee *rproc_to_trproc(struct rproc *rproc)
> +{
> +	struct rproc_tee *trproc;
> +
> +	list_for_each_entry(trproc, &rproc_tee_ctx.rproc_list, node)
> +		if (trproc->rproc == rproc)
> +			return trproc;
> +	return NULL;
> +}
> +
> +static void rproc_tee_prepare_args(struct rproc_tee *trproc, int cmd,
> +				   struct tee_ioctl_invoke_arg *arg,
> +				   struct tee_param *param,
> +				   unsigned int num_params)
> +{
> +	memset(arg, 0, sizeof(*arg));
> +	memset(param, 0, MAX_TEE_PARAM_ARRAY_MEMBER * sizeof(*param));
> +
> +	arg->func = cmd;
> +	arg->session = trproc->session_id;
> +	arg->num_params = num_params + 1;
> +
> +	param[0] = (struct tee_param) {
> +		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
> +		.u.value.a = trproc->rproc_id,
> +	};
> +}
> +
> +/**
> + * rproc_tee_release_fw() - Release the firmware for a TEE-based remote processor
> + * @rproc: Pointer to the struct rproc representing the remote processor
> + *
> + * This function invokes the TA_RPROC_CMD_RELEASE_FW TEE client function to
> + * release the firmware. It should only be called when the remoteproc state is
> + * RPROC_OFFLINE or RPROC_DETACHED. The function requests the TEE remoteproc
> + * application to release the firmware loaded by rproc_tee_load_fw().
> + * The request is ignored if the rproc state is RPROC_DETACHED as the remote
> + * processor is still running.
> + */
> +void rproc_tee_release_fw(struct rproc *rproc)
> +{
> +	struct tee_param param[MAX_TEE_PARAM_ARRAY_MEMBER];
> +	struct rproc_tee *trproc;
> +	struct tee_ioctl_invoke_arg arg;
> +	int ret;
> +
> +	ret = mutex_lock_interruptible(&ctx_lock);
> +	if (ret)
> +		return;
> +
> +	if (!rproc_tee_ctx.dev)
> +		goto out;
> +
> +	trproc = rproc_to_trproc(rproc);
> +	if (!trproc)
> +		goto out;
> +
> +	/*
> +	 * If the remote processor state is RPROC_DETACHED, just ignore the
> +	 * request, as the remote processor is still running.
> +	 */
> +	if (rproc->state == RPROC_DETACHED)
> +		goto out;
> +
> +	if (rproc->state != RPROC_OFFLINE) {
> +		dev_err(rproc_tee_ctx.dev, "unexpected rproc state: %d\n", rproc->state);
> +		goto out;
> +	}
> +
> +	rproc_tee_prepare_args(trproc, TA_RPROC_CMD_RELEASE_FW, &arg, param, 0);
> +
> +	ret = tee_client_invoke_func(rproc_tee_ctx.tee_ctx, &arg, param);
> +	if (ret < 0 || arg.ret != 0) {
> +		dev_err(rproc_tee_ctx.dev,
> +			"TA_RPROC_CMD_RELEASE_FW invoke failed TEE err: %#x, ret:%d\n",
> +			arg.ret, ret);
> +	}
> +
> +out:
> +	mutex_unlock(&ctx_lock);
> +}
> +EXPORT_SYMBOL_GPL(rproc_tee_release_fw);
> +
> +/**
> + * rproc_tee_load_fw() - Load firmware from TEE application
> + * @rproc: Pointer to the struct rproc representing the remote processor
> + * @fw: Pointer to the firmware structure containing the firmware data and size
> + *
> + * This function invokes the TA_RPROC_CMD_LOAD_FW TEE client function to load
> + * the firmware. It registers the fw->data as a shared memory region with the
> + * TEE, and request the TEE to load the firmware. This function can be called
> + * twice during the remote processor boot, a first by rproc_tee_parse_fw() to
> + * parse the resource table , and a second time by rproc_tee_load_fw().
> + * The TEE application should ignores the command if the firmware
> + * is already loaded by rproc_tee_parse_fw().
> + *
> + * Return: 0 on success, or an error code on failure
> + */
> +int rproc_tee_load_fw(struct rproc *rproc, const struct firmware *fw)
> +{
> +	struct tee_param param[MAX_TEE_PARAM_ARRAY_MEMBER];
> +	struct rproc_tee *trproc;
> +	struct tee_ioctl_invoke_arg arg;
> +	struct tee_shm *fw_shm;
> +	int ret;
> +
> +	ret = mutex_lock_interruptible(&ctx_lock);
> +	if (ret)
> +		return ret;
> +
> +	if (!rproc_tee_ctx.dev) {
> +		ret = -ENODEV;
> +		goto out;
> +	}
> +
> +	trproc = rproc_to_trproc(rproc);
> +	if (!trproc) {
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	fw_shm = tee_shm_register_kernel_buf(rproc_tee_ctx.tee_ctx, (void *)fw->data, fw->size);
> +	if (IS_ERR(fw_shm)) {
> +		ret = PTR_ERR(fw_shm);
> +		goto out;
> +	}
> +
> +	rproc_tee_prepare_args(trproc, TA_RPROC_CMD_LOAD_FW, &arg, param, 1);
> +
> +	/* Provide the address of the firmware image */
> +	param[1] = (struct tee_param) {
> +		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT,
> +		.u.memref = {
> +			.shm = fw_shm,
> +			.size = fw->size,
> +			.shm_offs = 0,
> +		},
> +	};
> +
> +	ret = tee_client_invoke_func(rproc_tee_ctx.tee_ctx, &arg, param);
> +	if (ret < 0 || arg.ret != 0) {
> +		dev_err(rproc_tee_ctx.dev,
> +			"TA_RPROC_CMD_LOAD_FW invoke failed TEE err: %#x, ret:%d\n",
> +			arg.ret, ret);
> +		if (!ret)
> +			ret = -EIO;
> +	}
> +
> +	tee_shm_free(fw_shm);
> +
> +out:
> +	mutex_unlock(&ctx_lock);
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(rproc_tee_load_fw);
> +
> +static int rproc_tee_get_loaded_rsc_table(struct rproc *rproc, phys_addr_t *rsc_pa,
> +					  size_t *table_sz)
> +{
> +	struct tee_param param[MAX_TEE_PARAM_ARRAY_MEMBER];
> +	struct rproc_tee *trproc;
> +	struct tee_ioctl_invoke_arg arg;
> +	int ret;
> +
> +	ret = mutex_lock_interruptible(&ctx_lock);
> +	if (ret)
> +		return ret;
> +
> +	if (!rproc_tee_ctx.dev) {
> +		ret = -ENODEV;
> +		goto out;
> +	}
> +
> +	trproc = rproc_to_trproc(rproc);
> +	if (!trproc) {
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	rproc_tee_prepare_args(trproc, TA_RPROC_CMD_GET_RSC_TABLE, &arg, param, 2);
> +
> +	param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
> +	param[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
> +
> +	ret = tee_client_invoke_func(rproc_tee_ctx.tee_ctx, &arg, param);
> +	if (ret < 0 || arg.ret != 0) {
> +		dev_err(rproc_tee_ctx.dev,
> +			"TA_RPROC_CMD_GET_RSC_TABLE invoke failed TEE err: %#x, ret:%d\n",
> +			arg.ret, ret);
> +		ret = -EIO;
> +		goto out;
> +	}
> +
> +	*table_sz = param[2].u.value.a;
> +	if (sizeof(phys_addr_t) == sizeof(u64))
> +		*table_sz |= param[2].u.value.b << 32;
> +
> +	if (*table_sz) {
> +		*rsc_pa = param[1].u.value.a;
> +		if (sizeof(phys_addr_t) == sizeof(u64))
> +			*rsc_pa |= param[1].u.value.b << 32;
> +	} else {
> +		*rsc_pa = 0;
> +	}
> +
> +out:
> +	mutex_unlock(&ctx_lock);
> +	return ret;
> +}
> +
> +/**
> + * rproc_tee_parse_fw() - Get the resource table from TEE application
> + * @rproc: Pointer to the struct rproc representing the remote processor
> + * @fw: Pointer to the firmware structure containing the firmware data and size
> + *
> + * This function retrieves the loaded resource table and creates a cached_table
> + * copy. Since the firmware image is signed and potentially encrypted, the
> + * firmware must be loaded first to access the loaded resource table.
> + *
> + * Return: 0 on success, or an error code on failure
> + */
> +int rproc_tee_parse_fw(struct rproc *rproc, const struct firmware *fw)
> +{
> +	phys_addr_t rsc_table;
> +	void *rsc_va;
> +	size_t table_sz;
> +	int ret;
> +
> +	if (!rproc)
> +		return -EINVAL;
> +
> +	/* We need first to Load the firmware, to be able to get the resource table. */
> +	ret = rproc_tee_load_fw(rproc, fw);
> +	if (ret)
> +		return ret;
> +
> +	ret = rproc_tee_get_loaded_rsc_table(rproc, &rsc_table, &table_sz);
> +	if (ret)
> +		goto release_fw;
> +
> +	/*
> +	 * We assume here that the memory mapping is the same between the TEE
> +	 * and Linux kernel contexts. Else a new TEE remoteproc service could be
> +	 * needed to get a copy of the resource table.
> +	 */
> +	rsc_va = memremap(rsc_table, table_sz, MEMREMAP_WC);
> +	if (!rsc_va) {
> +		dev_err(rproc_tee_ctx.dev, "Unable to map memory region: %pa+%zx\n",
> +			&rsc_table, table_sz);
> +		ret = -ENOMEM;
> +		goto release_fw;
> +	}
> +
> +	/*
> +	 * Create a copy of the resource table to have the same behavior as the
> +	 * ELF loader. This cached table will be used by the remoteproc core
> +	 * after the remoteproc stops to free resources and for crash recovery
> +	 * to reapply the settings.
> +	 * The cached table will be freed by the remoteproc core.
> +	 */
> +	rproc->cached_table = kmemdup(rsc_va, table_sz, GFP_KERNEL);
> +	memunmap(rsc_va);
> +
> +	if (!rproc->cached_table) {
> +		ret = -ENOMEM;
> +		goto release_fw;
> +	}
> +
> +	rproc->table_ptr = rproc->cached_table;
> +	rproc->table_sz = table_sz;
> +
> +	return 0;
> +
> +release_fw:
> +	rproc_tee_release_fw(rproc);
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(rproc_tee_parse_fw);
> +
> +/**
> + * rproc_tee_find_loaded_rsc_table() - Find the loaded resource table loaded by
> + *				       the TEE application
> + * @rproc: Pointer to the struct rproc representing the remote processor
> + * @fw: Pointer to the firmware structure containing the firmware data and size
> + *
> + * This function retrieves the physical address and size of the resource table
> + * loaded by the TEE application.
> + *
> + * Return: pointer to the resource table if found, or NULL if not found or size
> + * is 0
> + */
> +struct resource_table *rproc_tee_find_loaded_rsc_table(struct rproc *rproc,
> +						       const struct firmware *fw)
> +{
> +	phys_addr_t rsc_table;
> +	size_t table_sz;
> +	int ret;
> +
> +	ret = rproc_tee_get_loaded_rsc_table(rproc, &rsc_table, &table_sz);
> +	if (ret)
> +		return NULL;
> +
> +	rproc->table_sz = table_sz;
> +	if (!table_sz)
> +		return NULL;
> +
> +	/*
> +	 * At this step the memory area that contains the resource table should
> +	 * have been registered by the remote proc platform driver and allocated
> +	 * by rproc_alloc_registered_carveouts().
> +	 */
> +	return rproc_pa_to_va(rproc, rsc_table, table_sz, NULL);
> +}
> +EXPORT_SYMBOL_GPL(rproc_tee_find_loaded_rsc_table);
> +
> +/**
> + * rproc_tee_start() - Request the TEE application to start the remote processor
> + * @rproc: Pointer to the struct rproc representing the remote processor
> + *
> + * This function invokes the TA_RPROC_CMD_START command to start the remote
> + * processor.
> + *
> + * Return: Returns 0 on success, -EINVAL or -EIO on failure
> + */
> +int rproc_tee_start(struct rproc *rproc)
> +{
> +	struct tee_param param[MAX_TEE_PARAM_ARRAY_MEMBER];
> +	struct rproc_tee *trproc;
> +	struct tee_ioctl_invoke_arg arg;
> +	int ret;
> +
> +	ret = mutex_lock_interruptible(&ctx_lock);
> +	if (ret)
> +		return ret;
> +
> +	if (!rproc_tee_ctx.dev) {
> +		ret = -ENODEV;
> +		goto out;
> +	}
> +
> +	trproc = rproc_to_trproc(rproc);
> +	if (!trproc) {
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	rproc_tee_prepare_args(trproc, TA_RPROC_CMD_START, &arg, param, 0);
> +
> +	ret = tee_client_invoke_func(rproc_tee_ctx.tee_ctx, &arg, param);
> +	if (ret < 0 || arg.ret != 0) {
> +		dev_err(rproc_tee_ctx.dev,
> +			"TA_RPROC_CMD_START invoke failed TEE err: %#x, ret:%d\n", arg.ret, ret);
> +		if (!ret)
> +			ret = -EIO;
> +	}
> +
> +out:
> +	mutex_unlock(&ctx_lock);
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(rproc_tee_start);
> +
> +/**
> + * rproc_tee_stop() - Request the TEE application to start the remote processor
> + * @rproc: Pointer to the struct rproc representing the remote processor
> + *
> + * This function invokes the TA_RPROC_CMD_STOP command to stop the remote
> + * processor.
> + *
> + * Return: Returns 0 on success, -EINVAL or -EIO on failure
> + */
> +int rproc_tee_stop(struct rproc *rproc)
> +{
> +	struct tee_param param[MAX_TEE_PARAM_ARRAY_MEMBER];
> +	struct rproc_tee *trproc;
> +	struct tee_ioctl_invoke_arg arg;
> +	int ret;
> +
> +	ret = mutex_lock_interruptible(&ctx_lock);
> +	if (ret)
> +		return ret;
> +
> +	if (!rproc_tee_ctx.dev) {
> +		ret = -ENODEV;
> +		goto out;
> +	}
> +
> +	trproc = rproc_to_trproc(rproc);
> +	if (!trproc) {
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	rproc_tee_prepare_args(trproc, TA_RPROC_CMD_STOP, &arg, param, 0);
> +
> +	ret = tee_client_invoke_func(rproc_tee_ctx.tee_ctx, &arg, param);
> +	if (ret < 0 || arg.ret != 0) {
> +		dev_err(rproc_tee_ctx.dev,
> +			"TA_RPROC_CMD_STOP invoke failed TEE err: %#x, ret:%d\n", arg.ret, ret);
> +		if (!ret)
> +			ret = -EIO;
> +	}
> +
> +out:
> +	mutex_unlock(&ctx_lock);
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(rproc_tee_stop);
> +
> +static const struct rproc_ops rproc_tee_default_ops = {
> +	.start		= rproc_tee_start,
> +	.stop		= rproc_tee_stop,
> +	.load		= rproc_tee_load_fw,
> +	.parse_fw	= rproc_tee_parse_fw,
> +	.find_loaded_rsc_table = rproc_tee_find_loaded_rsc_table,
> +	.release_fw	= rproc_tee_release_fw,
> +};
> +
> +static const struct tee_client_device_id rproc_tee_id_table[] = {
> +	{UUID_INIT(0x80a4c275, 0x0a47, 0x4905, 0x82, 0x85, 0x14, 0x86, 0xa9, 0x77, 0x1a, 0x08)},
> +	{ /* sentinel */ }
> +};
> +
> +/**
> + * rproc_tee_register() - Register a remote processor controlled by the TEE application.
> + * @dev: Pointer to client rproc device
> + * @rproc: Pointer to the struct rproc representing the remote processor
> + * @rproc_id: ID of the remote processor
> + * @auto_boot: flag to indicate if remote processor should be auto-started
> + *
> + * This function registers a remote processor that will be managed by a TEE
> + * application, by opening a session with the TEE client.
> + *
> + * Return: Returns 0 on success, or an error code on failure
> + */
> +int rproc_tee_register(struct device *dev, struct rproc **rproc,
> +		       unsigned int rproc_id, bool auto_boot)
> +{
> +	struct tee_param param[MAX_TEE_PARAM_ARRAY_MEMBER];
> +	struct tee_ioctl_open_session_arg sess_arg;
> +	struct device_node *np = dev->of_node;
> +	struct tee_client_device *tee_device;
> +	struct rproc *new_rproc;
> +	struct rproc_tee *trproc;
> +	const char *fw_name;
> +	int ret;
> +
> +	ret = mutex_lock_interruptible(&ctx_lock);
> +	if (ret)
> +		return ret;
> +
> +	if (!rproc_tee_ctx.dev) {
> +		ret = -ENODEV;
> +		goto out;
> +	}
> +
> +	trproc = kzalloc(sizeof(*trproc), GFP_KERNEL);
> +	if (!trproc) {
> +		ret = -ENOMEM;
> +		goto out;
> +	}
> +
> +	/* Look for an optional firmware name */
> +	ret = rproc_of_parse_firmware(dev, 0, &fw_name);
> +	if (ret < 0 && ret != -EINVAL)
> +		goto free_tproc;
> +
> +	new_rproc = rproc_alloc(dev, np->name, &rproc_tee_default_ops,
> +				fw_name, sizeof(*trproc));
> +	if (!new_rproc) {
> +		ret = -ENOMEM;
> +		goto free_tproc;
> +	}
> +
> +	tee_device = to_tee_client_device(rproc_tee_ctx.dev);
> +	memset(&sess_arg, 0, sizeof(sess_arg));
> +
> +	memcpy(sess_arg.uuid, tee_device->id.uuid.b, TEE_IOCTL_UUID_LEN);
> +
> +	sess_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL;
> +	sess_arg.num_params = 1;
> +
> +	param[0] = (struct tee_param) {
> +		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
> +		.u.value.a = rproc_id,
> +	};
> +
> +	ret = tee_client_open_session(rproc_tee_ctx.tee_ctx, &sess_arg, param);
> +	if (ret < 0 || sess_arg.ret != 0) {
> +		dev_err(dev, "tee_client_open_session failed, err: %#x\n", sess_arg.ret);
> +		ret = -EINVAL;
> +		goto free_rproc;
> +	}
> +
> +	trproc->rproc_id = rproc_id;
> +	trproc->session_id = sess_arg.session;
> +	new_rproc->auto_boot = auto_boot;
> +
> +	ret = rproc_add(new_rproc);
> +	if (ret)
> +		goto close_tee;
> +
> +	trproc->rproc = new_rproc;
> +	*rproc = new_rproc;
> +
> +	list_add_tail(&trproc->node, &rproc_tee_ctx.rproc_list);
> +
> +	mutex_unlock(&ctx_lock);
> +
> +	return 0;
> +
> +close_tee:
> +	if (tee_client_close_session(rproc_tee_ctx.tee_ctx, trproc->session_id))
> +		dev_err(rproc_tee_ctx.dev, "tee_client_close_session failed\n");
> +free_rproc:
> +	rproc_free(new_rproc);
> +free_tproc:
> +	kfree(trproc);
> +out:
> +	mutex_unlock(&ctx_lock);
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(rproc_tee_register);
> +
> +/**
> + * rproc_tee_unregister - Unregister a remote processor controlled by the TEE
> + *                        application.
> + * @dev: Pointer to client rproc device
> + * @rproc: Pointer to the struct rproc representing the remote processor
> + *
> + * This function unregisters a remote processor previously registered by the
> + * rproc_tee_register() function.
> + *
> + * Return: Returns 0 on success, or an error code on failure
> + */
> +int rproc_tee_unregister(struct device *dev, struct rproc *rproc)
> +{
> +	struct rproc_tee *trproc;
> +	int ret;
> +
> +	if (!rproc_tee_ctx.dev) {
> +		ret = -ENODEV;
> +		return ret;
> +	}
> +
> +	trproc = rproc_to_trproc(rproc);
> +	if (!trproc) {
> +		ret = -EINVAL;
> +		return ret;
> +	}
> +
> +	rproc_del(rproc);
> +	rproc_free(rproc);
> +
> +	ret = mutex_lock_interruptible(&ctx_lock);
> +	if (ret)
> +		return ret;
> +
> +	ret = tee_client_close_session(rproc_tee_ctx.tee_ctx, trproc->session_id);
> +	if (ret < 0)
> +		dev_err(rproc_tee_ctx.dev, "tee_client_close_session failed, err: %#x\n", ret);
> +	list_del(&trproc->node);
> +	kfree(trproc);
> +	mutex_unlock(&ctx_lock);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(rproc_tee_unregister);
> +
> +static int rproc_tee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
> +{
> +	/* Today we support only the OP-TEE, could be extend to other tees */
> +	return (ver->impl_id == TEE_IMPL_ID_OPTEE);
> +}
> +
> +static const struct of_device_id remoteproc_tee_of_match[] = {
> +	{ .compatible = "rproc-service-80a4c275-0a47-4905-8285-1486a9771a08" },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, remoteproc_tee_of_match);

You don't need to define this redundant table but instead...

> +
> +static int rproc_tee_probe(struct device *dev)
> +{
> +	struct tee_context *tee_ctx;
> +	struct device_node *np;
> +	int ret;
> +
> +	pr_err("%s %d", __func__, __LINE__);
> +	np = of_find_compatible_node(NULL, NULL,
> +				     remoteproc_tee_of_match[0].compatible);

...you can get the UUID from device being passed here. With that you
should be able to fetch device specific DT properties.

-Sumit

> +	if (!np) {
> +		dev_err(dev, "Device node not found\n");
> +		return -ENODEV;
> +	}
> +
> +	/* Open context with TEE driver */
> +	tee_ctx = tee_client_open_context(NULL, rproc_tee_ctx_match, NULL, NULL);
> +	if (IS_ERR(tee_ctx)) {
> +		ret = PTR_ERR(tee_ctx);
> +		goto put_node;
> +	}
> +
> +	ret = mutex_lock_interruptible(&ctx_lock);
> +	if (ret)
> +		goto close_ctx;
> +
> +	rproc_tee_ctx.dev = dev;
> +	rproc_tee_ctx.tee_ctx = tee_ctx;
> +	INIT_LIST_HEAD(&rproc_tee_ctx.rproc_list);
> +
> +	mutex_unlock(&ctx_lock);
> +
> +	ret = device_add_of_node(dev, np);
> +	if (ret)
> +		goto clean_ctx;
> +
> +	ret = of_platform_populate(np, NULL, NULL, dev);
> +	if (ret) {
> +		dev_err(dev, "cannot populate node (%d)\n", ret);
> +		goto clean_ctx;
> +	}
> +
> +	return 0;
> +
> +clean_ctx:
> +	mutex_lock(&ctx_lock);
> +	rproc_tee_ctx.dev = NULL;
> +	rproc_tee_ctx.tee_ctx = NULL;
> +	mutex_unlock(&ctx_lock);
> +
> +close_ctx:
> +	tee_client_close_context(tee_ctx);
> +
> +put_node:
> +	of_node_put(np);
> +	return ret;
> +}
> +
> +static int rproc_tee_remove(struct device *dev)
> +{
> +	of_platform_depopulate(dev);
> +
> +	device_remove_of_node(dev);
> +
> +	mutex_lock(&ctx_lock);
> +	tee_client_close_context(rproc_tee_ctx.tee_ctx);
> +	rproc_tee_ctx.dev = NULL;
> +	rproc_tee_ctx.tee_ctx = NULL;
> +	mutex_unlock(&ctx_lock);
> +
> +	return 0;
> +}
> +
> +MODULE_DEVICE_TABLE(tee, rproc_tee_id_table);
> +
> +static struct tee_client_driver rproc_tee_fw_driver = {
> +	.id_table	= rproc_tee_id_table,
> +	.driver		= {
> +		.name		= KBUILD_MODNAME,
> +		.bus		= &tee_bus_type,
> +		.probe		= rproc_tee_probe,
> +		.remove		= rproc_tee_remove,
> +	},
> +};
> +
> +static int __init rproc_tee_fw_mod_init(void)
> +{
> +	return driver_register(&rproc_tee_fw_driver.driver);
> +}
> +
> +static void __exit rproc_tee_fw_mod_exit(void)
> +{
> +	driver_unregister(&rproc_tee_fw_driver.driver);
> +}
> +
> +module_init(rproc_tee_fw_mod_init);
> +module_exit(rproc_tee_fw_mod_exit);
> +
> +MODULE_DESCRIPTION("remote processor TEE module");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/remoteproc_tee.h b/include/linux/remoteproc_tee.h
> new file mode 100644
> index 000000000000..33150cff7a5a
> --- /dev/null
> +++ b/include/linux/remoteproc_tee.h
> @@ -0,0 +1,89 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Copyright(c) 2025 STMicroelectronics
> + */
> +
> +#ifndef REMOTEPROC_TEE_H
> +#define REMOTEPROC_TEE_H
> +
> +#include <linux/tee_drv.h>
> +#include <linux/firmware.h>
> +#include <linux/remoteproc.h>
> +
> +#if IS_ENABLED(CONFIG_REMOTEPROC_TEE)
> +
> +int rproc_tee_register(struct device *dev, struct rproc **rproc,
> +		       unsigned int rproc_id, bool auto_boot);
> +int rproc_tee_unregister(struct device *dev, struct rproc *rproc);
> +int rproc_tee_parse_fw(struct rproc *rproc, const struct firmware *fw);
> +int rproc_tee_load_fw(struct rproc *rproc, const struct firmware *fw);
> +void rproc_tee_release_fw(struct rproc *rproc);
> +struct resource_table *rproc_tee_find_loaded_rsc_table(struct rproc *rproc,
> +						       const struct firmware *fw);
> +int rproc_tee_start(struct rproc *rproc);
> +int rproc_tee_stop(struct rproc *rproc);
> +int rproc_tee_pa_to_da(struct rproc *rproc, phys_addr_t pa, size_t size, u64 *da);
> +#else
> +
> +static inline int rproc_tee_register(struct device *dev, struct rproc **rproc,
> +				     unsigned int rproc_id, bool auto_boot)
> +{
> +	return -ENODEV;
> +}
> +
> +static inline int rproc_tee_parse_fw(struct rproc *rproc, const struct firmware *fw)
> +{
> +	/* This shouldn't be possible */
> +	WARN_ON(1);
> +
> +	return 0;
> +}
> +
> +static inline int rproc_tee_unregister(struct device *dev, struct rproc *rproc)
> +{
> +	/* This shouldn't be possible */
> +	WARN_ON(1);
> +
> +	return 0;
> +}
> +
> +static inline int rproc_tee_load_fw(struct rproc *rproc, const struct firmware *fw)
> +{
> +	/* This shouldn't be possible */
> +	WARN_ON(1);
> +
> +	return 0;
> +}
> +
> +static inline int rproc_tee_start(struct rproc *rproc)
> +{
> +	/* This shouldn't be possible */
> +	WARN_ON(1);
> +
> +	return 0;
> +}
> +
> +static inline int rproc_tee_stop(struct rproc *rproc)
> +{
> +	/* This shouldn't be possible */
> +	WARN_ON(1);
> +
> +	return 0;
> +}
> +
> +static inline void rproc_tee_release_fw(struct rproc *rproc)
> +{
> +	/* This shouldn't be possible */
> +	WARN_ON(1);
> +}
> +
> +static inline struct resource_table *
> +rproc_tee_find_loaded_rsc_table(struct rproc *rproc, const struct firmware *fw)
> +{
> +	/* This shouldn't be possible */
> +	WARN_ON(1);
> +
> +	return NULL;
> +}
> +#endif /* CONFIG_REMOTEPROC_TEE */
> +#endif /* REMOTEPROC_TEE_H */
> -- 
> 2.43.0
> 


From rppt at kernel.org  Sun Dec 28 22:56:34 2025
From: rppt at kernel.org (Mike Rapoport)
Date: Mon, 29 Dec 2025 08:56:34 +0200
Subject: [PATCH 18/26] mm/memblock: Add MEMBLOCK_INSPECT flag
In-Reply-To: <20251119154427.1033475-19-eugen.hristev@linaro.org>
References: <20251119154427.1033475-1-eugen.hristev@linaro.org>
 <20251119154427.1033475-19-eugen.hristev@linaro.org>
Message-ID: <aVImIneFgOngYdSn@kernel.org>

Hi Eugen,

On Wed, Nov 19, 2025 at 05:44:19PM +0200, Eugen Hristev wrote:
> This memblock flag indicates that a specific block is registered
> into an inspection table.
> The block can be marked for inspection using memblock_mark_inspect()
> and cleared with memblock_clear_inspect()

Can you explain why memblock should treat memory registered for inspection
differently?

> Signed-off-by: Eugen Hristev <eugen.hristev at linaro.org>
> ---
>  include/linux/memblock.h |  7 +++++++
>  mm/memblock.c            | 36 ++++++++++++++++++++++++++++++++++++
>  2 files changed, 43 insertions(+)
> 
> diff --git a/include/linux/memblock.h b/include/linux/memblock.h
> index 221118b5a16e..c3e55a4475cf 100644
> --- a/include/linux/memblock.h
> +++ b/include/linux/memblock.h
> @@ -51,6 +51,10 @@ extern unsigned long long max_possible_pfn;
>   * memory reservations yet, so we get scratch memory from the previous
>   * kernel that we know is good to use. It is the only memory that
>   * allocations may happen from in this phase.
> + * @MEMBLOCK_INSPECT: memory region is annotated in kernel memory inspection
> + * table. This means a dedicated entry will be created for this region which
> + * will contain the memory's address and size. This allows kernel inspectors
> + * to retrieve the memory.
>   */
>  enum memblock_flags {
>  	MEMBLOCK_NONE		= 0x0,	/* No special request */
> @@ -61,6 +65,7 @@ enum memblock_flags {
>  	MEMBLOCK_RSRV_NOINIT	= 0x10,	/* don't initialize struct pages */
>  	MEMBLOCK_RSRV_KERN	= 0x20,	/* memory reserved for kernel use */
>  	MEMBLOCK_KHO_SCRATCH	= 0x40,	/* scratch memory for kexec handover */
> +	MEMBLOCK_INSPECT	= 0x80,	/* memory selected for kernel inspection */
>  };
>  
>  /**
> @@ -149,6 +154,8 @@ unsigned long memblock_addrs_overlap(phys_addr_t base1, phys_addr_t size1,
>  bool memblock_overlaps_region(struct memblock_type *type,
>  			      phys_addr_t base, phys_addr_t size);
>  bool memblock_validate_numa_coverage(unsigned long threshold_bytes);
> +int memblock_mark_inspect(phys_addr_t base, phys_addr_t size);
> +int memblock_clear_inspect(phys_addr_t base, phys_addr_t size);
>  int memblock_mark_hotplug(phys_addr_t base, phys_addr_t size);
>  int memblock_clear_hotplug(phys_addr_t base, phys_addr_t size);
>  int memblock_mark_mirror(phys_addr_t base, phys_addr_t size);
> diff --git a/mm/memblock.c b/mm/memblock.c
> index e23e16618e9b..a5df5ab286e5 100644
> --- a/mm/memblock.c
> +++ b/mm/memblock.c
> @@ -17,6 +17,7 @@
>  #include <linux/seq_file.h>
>  #include <linux/memblock.h>
>  #include <linux/mutex.h>
> +#include <linux/meminspect.h>
>  
>  #ifdef CONFIG_KEXEC_HANDOVER
>  #include <linux/libfdt.h>
> @@ -1016,6 +1017,40 @@ static int __init_memblock memblock_setclr_flag(struct memblock_type *type,
>  	return 0;
>  }
>  
> +/**
> + * memblock_mark_inspect - Mark inspectable memory with flag MEMBLOCK_INSPECT.
> + * @base: the base phys addr of the region
> + * @size: the size of the region
> + *
> + * Return: 0 on success, -errno on failure.
> + */
> +int __init_memblock memblock_mark_inspect(phys_addr_t base, phys_addr_t size)
> +{
> +	int ret;
> +
> +	ret = memblock_setclr_flag(&memblock.memory, base, size, 1, MEMBLOCK_INSPECT);
> +	if (ret)
> +		return ret;
> +
> +	meminspect_lock_register_pa(base, size);
> +
> +	return 0;
> +}
> +
> +/**
> + * memblock_clear_inspect - Clear flag MEMBLOCK_INSPECT for a specified region.
> + * @base: the base phys addr of the region
> + * @size: the size of the region
> + *
> + * Return: 0 on success, -errno on failure.
> + */
> +int __init_memblock memblock_clear_inspect(phys_addr_t base, phys_addr_t size)
> +{
> +	meminspect_lock_unregister_pa(base, size);
> +
> +	return memblock_setclr_flag(&memblock.memory, base, size, 0, MEMBLOCK_INSPECT);
> +}
> +
>  /**
>   * memblock_mark_hotplug - Mark hotpluggable memory with flag MEMBLOCK_HOTPLUG.
>   * @base: the base phys addr of the region
> @@ -2704,6 +2739,7 @@ static const char * const flagname[] = {
>  	[ilog2(MEMBLOCK_RSRV_NOINIT)] = "RSV_NIT",
>  	[ilog2(MEMBLOCK_RSRV_KERN)] = "RSV_KERN",
>  	[ilog2(MEMBLOCK_KHO_SCRATCH)] = "KHO_SCRATCH",
> +	[ilog2(MEMBLOCK_INSPECT)] = "INSPECT",
>  };
>  
>  static int memblock_debug_show(struct seq_file *m, void *private)
> -- 
> 2.43.0
> 

-- 
Sincerely yours,
Mike.


From rppt at kernel.org  Sun Dec 28 22:58:14 2025
From: rppt at kernel.org (Mike Rapoport)
Date: Mon, 29 Dec 2025 08:58:14 +0200
Subject: [PATCH 19/26] mm/numa: Register information into meminspect
In-Reply-To: <20251119154427.1033475-20-eugen.hristev@linaro.org>
References: <20251119154427.1033475-1-eugen.hristev@linaro.org>
 <20251119154427.1033475-20-eugen.hristev@linaro.org>
Message-ID: <aVImhhgEsHInebeh@kernel.org>

Hi Eugen,

On Wed, Nov 19, 2025 at 05:44:20PM +0200, Eugen Hristev wrote:
> Register dynamic information into meminspect:
>  - dynamic node data for each node
> 
> This information is being allocated for each node, as physical address,
> so call memblock_mark_inspect that will mark the block accordingly.
> 
> Signed-off-by: Eugen Hristev <eugen.hristev at linaro.org>
> ---
>  mm/numa.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/mm/numa.c b/mm/numa.c
> index 7d5e06fe5bd4..379065dd633e 100644
> --- a/mm/numa.c
> +++ b/mm/numa.c
> @@ -4,6 +4,7 @@
>  #include <linux/printk.h>
>  #include <linux/numa.h>
>  #include <linux/numa_memblks.h>
> +#include <linux/meminspect.h>
>  
>  struct pglist_data *node_data[MAX_NUMNODES];
>  EXPORT_SYMBOL(node_data);
> @@ -20,6 +21,7 @@ void __init alloc_node_data(int nid)
>  	if (!nd_pa)
>  		panic("Cannot allocate %zu bytes for node %d data\n",
>  		      nd_size, nid);
> +	memblock_mark_inspect(nd_pa, nd_size);

Won't plain meminspect_register_pa() work here?

>  	/* report and initialize */
>  	pr_info("NODE_DATA(%d) allocated [mem %#010Lx-%#010Lx]\n", nid,
> -- 
> 2.43.0
> 

-- 
Sincerely yours,
Mike.


From rppt at kernel.org  Sun Dec 28 22:59:05 2025
From: rppt at kernel.org (Mike Rapoport)
Date: Mon, 29 Dec 2025 08:59:05 +0200
Subject: [PATCH 20/26] mm/sparse: Register information into meminspect
In-Reply-To: <20251119154427.1033475-21-eugen.hristev@linaro.org>
References: <20251119154427.1033475-1-eugen.hristev@linaro.org>
 <20251119154427.1033475-21-eugen.hristev@linaro.org>
Message-ID: <aVImuURq0FXsfsrp@kernel.org>

Hi Eugen,

On Wed, Nov 19, 2025 at 05:44:21PM +0200, Eugen Hristev wrote:
> Annotate vital static information into meminspect:
>  - mem_section
> 
> Information on these variables is stored into inspection table.
> 
> Register dynamic information into meminspect:
>  - section
>  - mem_section_usage
> 
> This information is being allocated for each node, so call
> memblock_mark_inspect to mark the block accordingly.
> 
> Signed-off-by: Eugen Hristev <eugen.hristev at linaro.org>
> ---
>  mm/sparse.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/mm/sparse.c b/mm/sparse.c
> index 17c50a6415c2..80530e39c8b2 100644
> --- a/mm/sparse.c
> +++ b/mm/sparse.c
> @@ -15,6 +15,7 @@
>  #include <linux/swapops.h>
>  #include <linux/bootmem_info.h>
>  #include <linux/vmstat.h>
> +#include <linux/meminspect.h>
>  #include "internal.h"
>  #include <asm/dma.h>
>  
> @@ -30,6 +31,7 @@ struct mem_section mem_section[NR_SECTION_ROOTS][SECTIONS_PER_ROOT]
>  	____cacheline_internodealigned_in_smp;
>  #endif
>  EXPORT_SYMBOL(mem_section);
> +MEMINSPECT_SIMPLE_ENTRY(mem_section);
>  
>  #ifdef NODE_NOT_IN_PAGE_FLAGS
>  /*
> @@ -253,6 +255,7 @@ static void __init memblocks_present(void)
>  		size = sizeof(struct mem_section *) * NR_SECTION_ROOTS;
>  		align = 1 << (INTERNODE_CACHE_SHIFT);
>  		mem_section = memblock_alloc_or_panic(size, align);
> +		memblock_mark_inspect(virt_to_phys(mem_section), size);

Why not meminspect_register_va()?

>  	}
>  #endif
>  
> @@ -343,6 +346,7 @@ sparse_early_usemaps_alloc_pgdat_section(struct pglist_data *pgdat,
>  		limit = MEMBLOCK_ALLOC_ACCESSIBLE;
>  		goto again;
>  	}
> +	memblock_mark_inspect(virt_to_phys(usage), size);
>  	return usage;
>  }
>  
> -- 
> 2.43.0
> 

-- 
Sincerely yours,
Mike.


From krzk at kernel.org  Sun Dec 28 23:17:15 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 29 Dec 2025 08:17:15 +0100
Subject: [PATCH] arm64: dts: cix: Use lowercase hex
In-Reply-To: <aVHb-kbi2QbChxj9@nchen-desktop>
References: <20251223152424.155253-2-krzysztof.kozlowski@oss.qualcomm.com>
 <aVHb-kbi2QbChxj9@nchen-desktop>
Message-ID: <88e9e4c4-13c9-4b96-88cc-abb581011e87@kernel.org>

On 29/12/2025 02:40, Peter Chen wrote:
> On 25-12-23 16:24:25, Krzysztof Kozlowski wrote:
>> EXTERNAL EMAIL
>>
>> The DTS code coding style expects lowercase hex for values and unit
>> addresses.
>>
>> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
>>
>> ---
>>
>> Patches done with sed, verified with comparing unflattened DTB and
>> dtx_diff.
>> ---
>>  arch/arm64/boot/dts/cix/sky1.dtsi | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/boot/dts/cix/sky1.dtsi b/arch/arm64/boot/dts/cix/sky1.dtsi
>> index 64b76905cbff..fb8c826bbc97 100644
>> --- a/arch/arm64/boot/dts/cix/sky1.dtsi
>> +++ b/arch/arm64/boot/dts/cix/sky1.dtsi
>> @@ -523,7 +523,7 @@ pcie_x1_1_rc: pcie at a0e0000 {
>>                         reg-names = "reg", "cfg", "rcsu_strap", "rcsu_status", "msg";
>>                         ranges = <0x01000000 0x0 0x38100000 0x0 0x38100000 0x0 0x00100000>,
>>                                  <0x02000000 0x0 0x38200000 0x0 0x38200000 0x0 0x07e00000>,
>> -                                <0x43000000 0x0C 0x00000000 0x0C 0x00000000 0x04 0x00000000>;
>> +                                <0x43000000 0x0c 0x00000000 0x0c 0x00000000 0x04 0x00000000>;
> 
> Sorry, I could not apply for v6.19-rc1, could you?

What do you mean? It applies cleanly on v6.19-rc1 and on next. Your
branches are not really updated, so maybe you need to fix this.

And no, I cannot apply this, because this would mean CIX is
legacy/abandoned platform. Shall I mark it as such?


Best regards,
Krzysztof


From mikko.rapeli at linaro.org  Sun Dec 28 23:34:19 2025
From: mikko.rapeli at linaro.org (Mikko Rapeli)
Date: Mon, 29 Dec 2025 09:34:19 +0200
Subject: get_maintainer.pl and arch/arm64/configs/defconfig (was Re: [PATCH]
 arm64: defconfig: remove SLIM_QCOM_CTRL )
In-Reply-To: <b8efa1f8-1e6d-4069-a57a-ab58d5dbc2ce@kernel.org>
References: <20251223134807.3543642-1-mikko.rapeli@linaro.org>
 <c06878f7-bb93-4de2-b54a-e97fbc1a333e@kernel.org>
 <aUqgFCgmBy7H9yW0@nuoska>
 <4f99f3ba-ef5b-4163-ad1a-99527dd96f8a@kernel.org>
 <aUqo9AV2zSJqr_oE@nuoska>
 <6f425362-ad11-43d3-b74f-4576a7dc9954@kernel.org>
 <b8efa1f8-1e6d-4069-a57a-ab58d5dbc2ce@kernel.org>
Message-ID: <aVIu-9cnyXXBkpoE@nuoska>

Hi,

On Tue, Dec 23, 2025 at 04:30:04PM +0100, Krzysztof Kozlowski wrote:
> On 23/12/2025 16:27, Krzysztof Kozlowski wrote:
> > On 23/12/2025 15:36, Mikko Rapeli wrote:
> >>>
> >>>>
> >>>> I sent to addresses reported by get_maintainers.pl.
> >>>
> >>> There is no output of get_maintainers.pl for this file. It's one of
> >>> cases where script does not work (I think already documented in
> >>> maintainer soc profile).
> >>
> >> Sorry, I don't get it. This issue is a generic one since now arm64 defconfig
> >> has one unknown option. Tools which check kernel config for unknown options
> >> trigger warnings when arm64 defconfig is used.
> >>
> >> If get_maintainers.pl is broken for this file, then please fix it. I don't
> >> know how to fix it.
> > 
> > No one knows, partially because it is very, very difficult task, that's
> > the problem.
> 
> Ah, wait, it was fixed already! You just run get_maintainers incorrectly
> - You cannot use git fallback here, it's pointless. You could have read
> the get_maintainers.pl output.

Could you mention what is the correct way to run get_maintainer.pl then?

I don't contribute patches to kernel on a regular basis so of course
I can make a lot of mistakes but I tried to do the right thing:

$ ./scripts/get_maintainer.pl arch/arm64/configs/defconfig 
Krzysztof Kozlowski <krzk at kernel.org> (commit_signer:27/70=39%,authored:4/70=6%,added_lines:13/116=11%,removed_lines:7/43=16%)
Bjorn Andersson <bjorn.andersson at oss.qualcomm.com> (commit_signer:14/70=20%)
Geert Uytterhoeven <geert+renesas at glider.be> (commit_signer:13/70=19%)
Arnd Bergmann <arnd at arndb.de> (commit_signer:10/70=14%)
Nishanth Menon <nm at ti.com> (commit_signer:8/70=11%)
Eric Biggers <ebiggers at kernel.org> (authored:5/70=7%,removed_lines:5/43=12%)
"Andr? Draszik" <andre.draszik at linaro.org> (authored:4/70=6%)
"N?colas F. R. A. Prado" <nfraprado at collabora.com> (added_lines:9/116=8%)
Andrea della Porta <andrea.porta at suse.com> (added_lines:6/116=5%)
Nicolas Frattaroli <nicolas.frattaroli at collabora.com> (added_lines:6/116=5%)
Fabrice Gasnier <fabrice.gasnier at foss.st.com> (added_lines:6/116=5%)
Lad Prabhakar <prabhakar.mahadev-lad.rj at bp.renesas.com> (removed_lines:23/43=53%)
Kuninori Morimoto <kuninori.morimoto.gx at renesas.com> (removed_lines:3/43=7%)
linux-kernel at vger.kernel.org (open list)

and collect the emails from this output and fed them to git send-email.

Cheers,

-Mikko


From krzk at kernel.org  Sun Dec 28 23:48:45 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 29 Dec 2025 08:48:45 +0100
Subject: get_maintainer.pl and arch/arm64/configs/defconfig (was Re:
 [PATCH] arm64: defconfig: remove SLIM_QCOM_CTRL )
In-Reply-To: <aVIu-9cnyXXBkpoE@nuoska>
References: <20251223134807.3543642-1-mikko.rapeli@linaro.org>
 <c06878f7-bb93-4de2-b54a-e97fbc1a333e@kernel.org> <aUqgFCgmBy7H9yW0@nuoska>
 <4f99f3ba-ef5b-4163-ad1a-99527dd96f8a@kernel.org> <aUqo9AV2zSJqr_oE@nuoska>
 <6f425362-ad11-43d3-b74f-4576a7dc9954@kernel.org>
 <b8efa1f8-1e6d-4069-a57a-ab58d5dbc2ce@kernel.org> <aVIu-9cnyXXBkpoE@nuoska>
Message-ID: <e2495d62-ae02-4af2-be48-6a5c9266e009@kernel.org>

On 29/12/2025 08:34, Mikko Rapeli wrote:
> Hi,
> 
> On Tue, Dec 23, 2025 at 04:30:04PM +0100, Krzysztof Kozlowski wrote:
>> On 23/12/2025 16:27, Krzysztof Kozlowski wrote:
>>> On 23/12/2025 15:36, Mikko Rapeli wrote:
>>>>>
>>>>>>
>>>>>> I sent to addresses reported by get_maintainers.pl.
>>>>>
>>>>> There is no output of get_maintainers.pl for this file. It's one of
>>>>> cases where script does not work (I think already documented in
>>>>> maintainer soc profile).

I wrote it here - script does not work.

>>>>
>>>> Sorry, I don't get it. This issue is a generic one since now arm64 defconfig
>>>> has one unknown option. Tools which check kernel config for unknown options
>>>> trigger warnings when arm64 defconfig is used.
>>>>
>>>> If get_maintainers.pl is broken for this file, then please fix it. I don't
>>>> know how to fix it.
>>>
>>> No one knows, partially because it is very, very difficult task, that's
>>> the problem.
>>
>> Ah, wait, it was fixed already! You just run get_maintainers incorrectly
>> - You cannot use git fallback here, it's pointless. You could have read
>> the get_maintainers.pl output.
> 
> Could you mention what is the correct way to run get_maintainer.pl then?
> 
> I don't contribute patches to kernel on a regular basis so of course
> I can make a lot of mistakes but I tried to do the right thing:
> 
> $ ./scripts/get_maintainer.pl arch/arm64/configs/defconfig 

Just like I mentioned already - you cannot use git fallback, thus you
miss --no-git-fallback.

> Krzysztof Kozlowski <krzk at kernel.org> (commit_signer:27/70=39%,authored:4/70=6%,added_lines:13/116=11%,removed_lines:7/43=16%)
> Bjorn Andersson <bjorn.andersson at oss.qualcomm.com> (commit_signer:14/70=20%)
> Geert Uytterhoeven <geert+renesas at glider.be> (commit_signer:13/70=19%)
> Arnd Bergmann <arnd at arndb.de> (commit_signer:10/70=14%)
> Nishanth Menon <nm at ti.com> (commit_signer:8/70=11%)
> Eric Biggers <ebiggers at kernel.org> (authored:5/70=7%,removed_lines:5/43=12%)
> "Andr? Draszik" <andre.draszik at linaro.org> (authored:4/70=6%)
> "N?colas F. R. A. Prado" <nfraprado at collabora.com> (added_lines:9/116=8%)
> Andrea della Porta <andrea.porta at suse.com> (added_lines:6/116=5%)
> Nicolas Frattaroli <nicolas.frattaroli at collabora.com> (added_lines:6/116=5%)
> Fabrice Gasnier <fabrice.gasnier at foss.st.com> (added_lines:6/116=5%)
> Lad Prabhakar <prabhakar.mahadev-lad.rj at bp.renesas.com> (removed_lines:23/43=53%)
> Kuninori Morimoto <kuninori.morimoto.gx at renesas.com> (removed_lines:3/43=7%)

And by reading this output you would notice - no single maintainer.

> linux-kernel at vger.kernel.org (open list)
> 
> and collect the emails from this output and fed them to git send-email.
> 
> Cheers,
> 
> -Mikko


Best regards,
Krzysztof


From shawnguo at kernel.org  Mon Dec 29 00:10:29 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Mon, 29 Dec 2025 16:10:29 +0800
Subject: [PATCH v4 1/2] dt-bindings: arm: fsl: add TQ-Systems boards
 MBLS1028A and MBLS1028A-IND
In-Reply-To: <20251117130916.803047-1-alexander.stein@ew.tq-group.com>
References: <20251117130916.803047-1-alexander.stein@ew.tq-group.com>
Message-ID: <aVI3dRAEh77-PVND@dragon>

On Mon, Nov 17, 2025 at 02:09:12PM +0100, Alexander Stein wrote:
> From: Matthias Schiffer <matthias.schiffer at tq-group.com>
> 
> Add two mainboards for the TQ-Systems TQMLS1028A SoM, based on the NXP
> Layerscape LS1028A.
> 
> Signed-off-by: Matthias Schiffer <matthias.schiffer at tq-group.com>
> Reviewed-by: Frank Li <Frank.Li at nxp.com>
> Acked-by: Conor Dooley <conor.dooley at microchip.com>
> Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>

Applied both, thanks!


From Qing-wu.Li at leica-geosystems.com.cn  Mon Dec 29 00:16:29 2025
From: Qing-wu.Li at leica-geosystems.com.cn (LI Qingwu)
Date: Mon, 29 Dec 2025 08:16:29 +0000
Subject: [PATCH V1] i2c: imx: Fix SMBus block read hang on zero length
Message-ID: <20251229081629.4081452-1-Qing-wu.Li@leica-geosystems.com.cn>

SMBus block read transfers encode the payload length in the first data
byte. When this first byte is zero, there is no payload and the
transaction should terminate immediately.

On i.MX, if the first byte of an SMBus block read is zero, the driver
unconditionally overwrites the state with IMX_I2C_STATE_READ_CONTINUE.
This causes the state machine to enter an endless read loop, eventually
overrunning internal buffers and leading to a crash.

At the same time, the controller remains in master receive mode and
never generates a proper STOP condition, leaving the I2C bus permanently
busy and preventing any further transfers on the bus.

Fix this by handling the zero-length case explicitly: when the first
byte is zero, ensure that a clean STOP is generated. In this situation
the controller is in master receive mode, so it must be switched to
master transmit mode before stopping. This is done by draining the
pending received byte from I2DR, setting I2CR_MTX to enter transmit
mode, waiting briefly for the mode change, and then proceeding with the
normal STOP sequence.

This change has been tested on i.MX 8M Plus platform.

Signed-off-by: LI Qingwu <Qing-wu.Li at leica-geosystems.com.cn>
---
 drivers/i2c/busses/i2c-imx.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index dcce882f3eba..f40deecf0f66 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -735,6 +735,16 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx, bool atomic)
 		temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
 		if (!(temp & I2CR_MSTA))
 			i2c_imx->stopped = 1;
+		if ((temp & I2CR_MSTA) && !(temp & I2CR_MTX)) {
+			(void)imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
+			temp |= I2CR_MTX;
+			imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+			if (atomic)
+				udelay(25);
+			else
+				usleep_range(25, 50);
+			temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+		}
 		temp &= ~(I2CR_MSTA | I2CR_MTX);
 		if (i2c_imx->dma)
 			temp &= ~I2CR_DMAEN;
@@ -1103,7 +1113,8 @@ static irqreturn_t i2c_imx_master_isr(struct imx_i2c_struct *i2c_imx, unsigned i
 
 	case IMX_I2C_STATE_READ_BLOCK_DATA_LEN:
 		i2c_imx_isr_read_block_data_len(i2c_imx);
-		i2c_imx->state = IMX_I2C_STATE_READ_CONTINUE;
+		if (i2c_imx->state == IMX_I2C_STATE_READ_BLOCK_DATA_LEN)
+			i2c_imx->state = IMX_I2C_STATE_READ_CONTINUE;
 		break;
 
 	case IMX_I2C_STATE_WRITE:
-- 
2.43.0



From Markus.Elfring at web.de  Mon Dec 29 00:19:19 2025
From: Markus.Elfring at web.de (Markus Elfring)
Date: Mon, 29 Dec 2025 09:19:19 +0100
Subject: [PATCH v2] soc: mediatek: svs: Fix memory leak in
 svs_enable_debug_write()
In-Reply-To: <20251228162636.3829733-1-zilin@seu.edu.cn>
References: <20251228162636.3829733-1-zilin@seu.edu.cn>
Message-ID: <1d9b46ba-728e-459a-9d82-0f49e2fe08b9@web.de>

?
> +++ b/drivers/soc/mediatek/mtk-svs.c
> @@ -789,7 +789,7 @@ static ssize_t svs_enable_debug_write(struct file *filp,
>  	struct svs_bank *svsb = file_inode(filp)->i_private;
>  	struct svs_platform *svsp = dev_get_drvdata(svsb->dev);
>  	int enabled, ret;
> -	char *buf = NULL;
> +	char *buf __free(kfree) = NULL;
>  
>  	if (count >= PAGE_SIZE)
>  		return -EINVAL;
?

You may reduce the scopes for involved local variables,
don't you?


See also:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/submitting-patches.rst?h=v6.19-rc3#n262

Regards,
Markus


From shawnguo at kernel.org  Mon Dec 29 00:21:07 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Mon, 29 Dec 2025 16:21:07 +0800
Subject: [PATCH v4 4/5] arm64: dts: freescale: Add the GOcontroll
 Moduline IV
In-Reply-To: <20251117-mini_iv-v4-4-5aa63832f51a@gocontroll.com>
References: <20251117-mini_iv-v4-0-5aa63832f51a@gocontroll.com>
 <20251117-mini_iv-v4-4-5aa63832f51a@gocontroll.com>
Message-ID: <aVI5875EkE3aGBqI@dragon>

On Mon, Nov 17, 2025 at 04:01:29PM +0100, Maud Spierings via B4 Relay wrote:
> From: Maud Spierings <maudspierings at gocontroll.com>
> 
> The Moduline IV is a part of the wider GOcontroll Moduline ecosystem. These
> are embedded controllers that focus on modularity with their swappable IO
> modules.
> 
> Features:
> - up to 8 Moduline IO modules
> - 4 CAN busses
> - 1 LIN bus
> - 1 Ethernet
> - 4 RGB leds
> - optional Wi-Fi/Bluetooth
> - optional 4G/GPS
> 
> Signed-off-by: Maud Spierings <maudspierings at gocontroll.com>
> ---
>  arch/arm64/boot/dts/freescale/Makefile             |   2 +
>  .../imx8mm-tx8m-1610-moduline-iv-306-d.dts         | 800 +++++++++++++++++++++
>  2 files changed, 802 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
> index 525ef180481d..b2fef44e0a37 100644
> --- a/arch/arm64/boot/dts/freescale/Makefile
> +++ b/arch/arm64/boot/dts/freescale/Makefile
> @@ -124,6 +124,8 @@ imx8mm-evk-pcie-ep-dtbs += imx8mm-evk.dtb imx-pcie0-ep.dtbo
>  imx8mm-evkb-pcie-ep-dtbs += imx8mm-evkb.dtb imx-pcie0-ep.dtbo
>  dtb-$(CONFIG_ARCH_MXC) += imx8mm-evk-pcie-ep.dtb imx8mm-evkb-pcie-ep.dtb
>  
> +dtb-$(CONFIG_ARCH_MXC) += imx8mm-tx8m-1610-moduline-iv-306-d.dtb
> +
>  dtb-$(CONFIG_ARCH_MXC) += imx8mm-icore-mx8mm-ctouch2.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx8mm-icore-mx8mm-edimm2.2.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx8mm-iot-gateway.dtb
> diff --git a/arch/arm64/boot/dts/freescale/imx8mm-tx8m-1610-moduline-iv-306-d.dts b/arch/arm64/boot/dts/freescale/imx8mm-tx8m-1610-moduline-iv-306-d.dts
> new file mode 100644
> index 000000000000..01df9d77fa51
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx8mm-tx8m-1610-moduline-iv-306-d.dts
> @@ -0,0 +1,800 @@
> +// SPDX-License-Identifier: (GPL-2.0 OR MIT)
> +/*
> + * Copyright (C) 2025 Maud Spierings <maudspierings at gocontroll.com>
> + */
> +
> +/dts-v1/;
> +
> +#include "imx8mm-tx8m-1610.dtsi"
> +#include <dt-bindings/leds/common.h>
> +
> +/ {
> +	chassis-type = "embedded";
> +	compatible = "gocontroll,moduline-iv-306-d", "karo,imx8mm-tx8m-1610", "fsl,imx8mm";
> +	hardware = "Moduline IV V3.06-D";
> +	model = "GOcontroll Moduline IV";
> +
> +	aliases {
> +		usb-host = &usbotg2;
> +		usbotg = &usbotg1;
> +		spi0 = &ecspi2; /* spidev number compatibility */
> +		spi1 = &ecspi3; /* spidev number compatibility */
> +		spi2 = &ecspi1; /* spidev number compatibility */

Can we order aliases alphabetically?

Shawn


From hejunhao3 at h-partners.com  Mon Dec 29 00:27:23 2025
From: hejunhao3 at h-partners.com (hejunhao)
Date: Mon, 29 Dec 2025 16:27:23 +0800
Subject: [PATCH v4 2/3] coresight: tmc: refactor the tmc-etr mode setting
 to avoid race conditions
In-Reply-To: <a0ff9d15-c0e8-4ba2-9187-2abbe5676b01@arm.com>
References: <20251111122149.1981162-1-hejunhao3@h-partners.com>
 <20251111122149.1981162-3-hejunhao3@h-partners.com>
 <15868ecb-c1e7-4273-a2e2-5c10f2701c0b@arm.com>
 <14a564bf-f9a2-c49c-9cd6-a5b68bc43500@h-partners.com>
 <a0ff9d15-c0e8-4ba2-9187-2abbe5676b01@arm.com>
Message-ID: <0406ae9f-28f6-44e1-26dd-8f243e7fc9fb@h-partners.com>


On 2025/11/19 22:46, Suzuki K Poulose wrote:
> On 15/11/2025 02:09, hejunhao wrote:
>>
>>
>> On 2025/11/13 23:02, Suzuki K Poulose wrote:
>>> Hi Junhao,
>>>
>>> While your patch fixes the problem it introduces imbalance in the
>>> way perf vs sysfs modes are handled.
>>>
>>
>> Hi Suzuki,
>>
>> Thank you for your comments.
>>
>> What you mean is that, as long as tmc_etr_enable_hw() has not yet been
>> called (i.e., ETR hasn't been fully enabled), both the perf and sysfs 
>> sessions
>> have the opportunity to take ownership of ETR device?
>>
>> Based on the following sysfs-based ETR enablement sequence, the 
>> spinlock is
>> released at two points (denoted as points a and b).
>> At either of these points, perf may acquire the lock and invoke
>> tmc_etr_enable_hw() to complete the ETR initialization, resulting in
>> ETR_mode == PERF. This would interrupt the ongoing sysfs enablement
>> flow and effectively give precedence to perf over sysfs.
>>
>> mode:
>>    [sysfs mode]
>>    tmc_enable_etr_sink_sysfs()
>>      tmc_etr_get_sysfs_buffer()
>>        spin_lock(&drvdata->spinlock)
>>        sysfs_buf = READ_ONCE(drvdata->sysfs_buf);
>>        if (!sysfs_buf || (sysfs_buf->size != drvdata->size))
>>          spin_unlock(&drvdata->spinlock)  <-- point a
>>          [sysfs buffer allocation]
>>          spin_lock(&drvdata->spinlock)
>>        drvdata->sysfs_buf = new_buf;
>>        spin_unlock(&drvdata->spinlock)  <-- point b
>>      spin_lock(&drvdata->spinlock)
>>      tmc_etr_enable_hw()
>>      spin_unlock(&drvdata->spinlock)
>>
>>    [perf mode]
>>    tmc_enable_etr_sink_perf()
>>      spin_lock(&drvdata->spinlock)
>>      tmc_etr_enable_hw()
>>      spin_unlock(&drvdata->spinlock)
>>
>> After the patch, both the perf and sysfs sessions contend fairly for 
>> the lock at
>> the entry point of tmc_enable_etr_sink(). The first to acquire the 
>> lock gains
>> exclusive control over the ETR sink for the remainder of the session.
>
> TBH, we don't care about fairness of the different modes of operation.
>
> 1. Perf must be given the priority - Because that provides a full easy
> framework for making any meaningful sense of the trace.
>
> 2. Sysfs mode should be only used for custom use cases, where you have
> full control of the system. (e.g., System bringup, Validation or event
> crash capture).
>
> In other words, if someone wants to use sysfs mode they must know what
> they are doing and not run any perf session in parallel.
>
Hi Suzuki,

I understand now.
This issue has been present for some time. Based on the discussion 
above, the
quickest way to resolve it is to revert to patch [1]. I will rebase the 
series onto
for-next, submit the next version.

Additionally, I might delay or suspend the planned refactoring of
the mode handling.

Thanks
Junhao

[1] 
https://lore.kernel.org/linux-arm-kernel/20241202092419.11777-1-yangyicong at huawei.com/

> Thanks
> Suzuki
>
>
>>
>>> On 11/11/2025 12:21, Junhao He wrote:
>>>> From: Junhao He <hejunhao3 at huawei.com>
>>>>
>>>> When trying to run perf and sysfs mode simultaneously, the WARN_ON()
>>>> in tmc_etr_enable_hw() is triggered sometimes:
>>>>
>>>>   WARNING: CPU: 42 PID: 3911571 at drivers/hwtracing/coresight/ 
>>>> coresight-tmc-etr.c:1060 tmc_etr_enable_hw+0xc0/0xd8 [coresight_tmc]
>>>>   [..snip..]
>>>>   Call trace:
>>>>    tmc_etr_enable_hw+0xc0/0xd8 [coresight_tmc] (P)
>>>>    tmc_enable_etr_sink+0x11c/0x250 [coresight_tmc] (L)
>>>>    tmc_enable_etr_sink+0x11c/0x250 [coresight_tmc]
>>>>    coresight_enable_path+0x1c8/0x218 [coresight]
>>>>    coresight_enable_sysfs+0xa4/0x228 [coresight]
>>>>    enable_source_store+0x58/0xa8 [coresight]
>>>>    dev_attr_store+0x20/0x40
>>>>    sysfs_kf_write+0x4c/0x68
>>>>    kernfs_fop_write_iter+0x120/0x1b8
>>>>    vfs_write+0x2c8/0x388
>>>>    ksys_write+0x74/0x108
>>>>    __arm64_sys_write+0x24/0x38
>>>>    el0_svc_common.constprop.0+0x64/0x148
>>>>    do_el0_svc+0x24/0x38
>>>>    el0_svc+0x3c/0x130
>>>>    el0t_64_sync_handler+0xc8/0xd0
>>>>    el0t_64_sync+0x1ac/0x1b0
>>>>   ---[ end trace 0000000000000000 ]---
>>>>
>>>> Since the sysfs buffer allocation and the hardware enablement is not
>>>> in the same critical region, it's possible to race with the perf
>>>>
>>>> mode:
>>>>    [sysfs mode]                   [perf mode]
>>>>    tmc_etr_get_sysfs_buffer()
>>>>      spin_lock(&drvdata->spinlock)
>>>>      [sysfs buffer allocation]
>>>>      spin_unlock(&drvdata->spinlock)
>>>> spin_lock(&drvdata->spinlock)
>>>>                                   tmc_etr_enable_hw()
>>>>                                     drvdata->etr_buf = 
>>>> etr_perf->etr_buf
>>>> spin_unlock(&drvdata->spinlock)
>>>>   spin_lock(&drvdata->spinlock)
>>>
>>> ^^ Could we not double check the mode here and break out ?
>>>
>>> Something like this :
>>>
>>>
>>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/ 
>>> drivers/hwtracing/coresight/coresight-tmc-etr.c
>>> index e0d83ee01b77..2097c57d19d0 100644
>>> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>>> @@ -1314,6 +1314,9 @@ static int tmc_enable_etr_sink_sysfs(struct 
>>> coresight_device *csdev)
>>>         if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
>>>                 csdev->refcnt++;
>>>                 goto out;
>>> +       } else if (coresight_get_mode(csdev) != CS_MODE_DISABLED) {
>>> +               ret = -EBUSY;
>>> +               goto out;
>>>         }
>>>
>>>         ret = tmc_etr_enable_hw(drvdata, sysfs_buf);
>>>
>>>
>>> Suzuki
>>
>> Indeed, this approach addresses only the race condition between the 
>> perf and sysfs
>> components. It represents the simplest viable solution.
>>
>> This patch also resolves the potential null pointer dereference of 
>> drvdata->sysfs_buf,
>> which could occur when the buffer size is modified after ETR has 
>> already been
>> enabled, followed by enabling a second source device [1].
>>
>> If the refactored patch introduces additional issues, the 
>> implementation may be
>> reworked based on Yicong's original patches [2] ?
>>
>> [1]https://lore.kernel.org/linux-arm-kernel/20241202092419.11777-2- 
>> yangyicong at huawei.com/
>> [2]https://lore.kernel.org/linux-arm-kernel/20241202092419.11777-4- 
>> yangyicong at huawei.com/
>>
>> Best regards,
>> Junhao.
>>
>>>
>>>
>>>>   tmc_etr_enable_hw()
>>>>     WARN_ON(drvdata->etr_buf) // WARN sicne etr_buf initialized at
>>>>                                  the perf side
>>>>    spin_unlock(&drvdata->spinlock)
>>>>
>>>> A race condition is introduced here, perf always prioritizes 
>>>> execution, and
>>>> warnings can lead to concerns about potential hidden bugs, such as 
>>>> getting
>>>> out of sync.
>>>>
>>>> To fix this, configure the tmc-etr mode before invoking 
>>>> enable_etr_perf()
>>>> or enable_etr_sysfs(), explicitly check if the tmc-etr sink is already
>>>> enabled in a different mode, and simplily the setup and checks for 
>>>> "mode".
>>>> To prevent race conditions between mode transitions.
>>>>
>>>> Fixes: 296b01fd106e ("coresight: Refactor out buffer allocation 
>>>> function for ETR")
>>>> Reported-by: Yicong Yang <yangyicong at hisilicon.com>
>>>> Closes: https://lore.kernel.org/linux-arm- 
>>>> kernel/20241202092419.11777-2-yangyicong at huawei.com/
>>>> Signed-off-by: Junhao He <hejunhao3 at huawei.com>
>>>> Tested-by: Yicong Yang <yangyicong at hisilicon.com>
>>>> Signed-off-by: Junhao He <hejunhao3 at h-partners.com>
>>>> ---
>>>>   .../hwtracing/coresight/coresight-tmc-etr.c   | 106 
>>>> +++++++++---------
>>>>   1 file changed, 55 insertions(+), 51 deletions(-)
>>>>
>>>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/ 
>>>> drivers/hwtracing/coresight/coresight-tmc-etr.c
>>>> index b07fcdb3fe1a..fe1d5e8a0d2b 100644
>>>> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>>>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>>>> @@ -1263,11 +1263,6 @@ static struct etr_buf 
>>>> *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev)
>>>>           raw_spin_lock_irqsave(&drvdata->spinlock, flags);
>>>>       }
>>>>   -    if (drvdata->reading || coresight_get_mode(csdev) == 
>>>> CS_MODE_PERF) {
>>>> -        ret = -EBUSY;
>>>> -        goto out;
>>>> -    }
>>>> -
>>>>       /*
>>>>        * If we don't have a buffer or it doesn't match the 
>>>> requested size,
>>>>        * use the buffer allocated above. Otherwise reuse the 
>>>> existing buffer.
>>>> @@ -1278,7 +1273,6 @@ static struct etr_buf 
>>>> *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev)
>>>>           drvdata->sysfs_buf = new_buf;
>>>>       }
>>>>   -out:
>>>>       raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
>>>>         /* Free memory outside the spinlock if need be */
>>>> @@ -1289,7 +1283,7 @@ static struct etr_buf 
>>>> *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev)
>>>>     static int tmc_enable_etr_sink_sysfs(struct coresight_device 
>>>> *csdev)
>>>>   {
>>>> -    int ret = 0;
>>>> +    int ret;
>>>>       unsigned long flags;
>>>>       struct tmc_drvdata *drvdata = 
>>>> dev_get_drvdata(csdev->dev.parent);
>>>>       struct etr_buf *sysfs_buf = tmc_etr_get_sysfs_buffer(csdev);
>>>> @@ -1299,23 +1293,10 @@ static int tmc_enable_etr_sink_sysfs(struct 
>>>> coresight_device *csdev)
>>>>         raw_spin_lock_irqsave(&drvdata->spinlock, flags);
>>>>   -    /*
>>>> -     * In sysFS mode we can have multiple writers per sink. Since 
>>>> this
>>>> -     * sink is already enabled no memory is needed and the HW need 
>>>> not be
>>>> -     * touched, even if the buffer size has changed.
>>>> -     */
>>>> -    if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
>>>> -        csdev->refcnt++;
>>>> -        goto out;
>>>> -    }
>>>> -
>>>>       ret = tmc_etr_enable_hw(drvdata, sysfs_buf);
>>>> -    if (!ret) {
>>>> -        coresight_set_mode(csdev, CS_MODE_SYSFS);
>>>> +    if (!ret)
>>>>           csdev->refcnt++;
>>>> -    }
>>>>   -out:
>>>>       raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
>>>>         if (!ret)
>>>> @@ -1729,39 +1710,24 @@ static int tmc_enable_etr_sink_perf(struct 
>>>> coresight_device *csdev, void *data)
>>>>   {
>>>>       int rc = 0;
>>>>       pid_t pid;
>>>> -    unsigned long flags;
>>>>       struct tmc_drvdata *drvdata = 
>>>> dev_get_drvdata(csdev->dev.parent);
>>>>       struct perf_output_handle *handle = data;
>>>>       struct etr_perf_buffer *etr_perf = etm_perf_sink_config(handle);
>>>>   -    raw_spin_lock_irqsave(&drvdata->spinlock, flags);
>>>> -     /* Don't use this sink if it is already claimed by sysFS */
>>>> -    if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
>>>> -        rc = -EBUSY;
>>>> -        goto unlock_out;
>>>> -    }
>>>> -
>>>> -    if (WARN_ON(!etr_perf || !etr_perf->etr_buf)) {
>>>> -        rc = -EINVAL;
>>>> -        goto unlock_out;
>>>> -    }
>>>> +    if (WARN_ON(!etr_perf || !etr_perf->etr_buf))
>>>> +        return -EINVAL;
>>>>         /* Get a handle on the pid of the session owner */
>>>>       pid = etr_perf->pid;
>>>>         /* Do not proceed if this device is associated with another 
>>>> session */
>>>> -    if (drvdata->pid != -1 && drvdata->pid != pid) {
>>>> -        rc = -EBUSY;
>>>> -        goto unlock_out;
>>>> -    }
>>>> +    if (drvdata->pid != -1 && drvdata->pid != pid)
>>>> +        return -EBUSY;
>>>>   -    /*
>>>> -     * No HW configuration is needed if the sink is already in
>>>> -     * use for this session.
>>>> -     */
>>>> +    /* The sink is already in use for this session */
>>>>       if (drvdata->pid == pid) {
>>>>           csdev->refcnt++;
>>>> -        goto unlock_out;
>>>> +        return rc;
>>>>       }
>>>>         rc = tmc_etr_enable_hw(drvdata, etr_perf->etr_buf);
>>>> @@ -1773,22 +1739,60 @@ static int tmc_enable_etr_sink_perf(struct 
>>>> coresight_device *csdev, void *data)
>>>>           csdev->refcnt++;
>>>>       }
>>>>   -unlock_out:
>>>> -    raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
>>>>       return rc;
>>>>   }
>>>>     static int tmc_enable_etr_sink(struct coresight_device *csdev,
>>>>                      enum cs_mode mode, void *data)
>>>>   {
>>>> -    switch (mode) {
>>>> -    case CS_MODE_SYSFS:
>>>> -        return tmc_enable_etr_sink_sysfs(csdev);
>>>> -    case CS_MODE_PERF:
>>>> -        return tmc_enable_etr_sink_perf(csdev, data);
>>>> -    default:
>>>> -        return -EINVAL;
>>>> +    struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
>>>> +    int rc;
>>>> +
>>>> +retry:
>>>> +    scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) {
>>>> +        if (coresight_get_mode(csdev) != CS_MODE_DISABLED &&
>>>> +            coresight_get_mode(csdev) != mode)
>>>> +            return -EBUSY;
>>>> +
>>>> +        switch (mode) {
>>>> +        case CS_MODE_SYSFS:
>>>> +            if (drvdata->reading)
>>>> +                return -EBUSY;
>>>> +
>>>> +            if (csdev->refcnt) {
>>>> +                /* The sink is already enabled via sysfs */
>>>> +                csdev->refcnt++;
>>>> +                return 0;
>>>> +            }
>>>> +
>>>> +            /*
>>>> +             * A sysfs session is currently enabling ETR, preventing
>>>> +             * a second sysfs process from repeatedly triggering the
>>>> +             * enable procedure.
>>>> +             */
>>>> +            if (coresight_get_mode(csdev) == CS_MODE_SYSFS && ! 
>>>> csdev->refcnt)
>>>> +                goto retry;
>>>> +
>>>> +            /*
>>>> +             * Set ETR to sysfs mode before it is fully enabled, to
>>>> +             * prevent race conditions during mode transitions.
>>>> +             */
>>>> +            coresight_set_mode(csdev, mode);
>>>> +            break;
>>>> +        case CS_MODE_PERF:
>>>> +            return tmc_enable_etr_sink_perf(csdev, data);
>>>> +        default:
>>>> +            return -EINVAL;
>>>> +        }
>>>> +    }
>>>> +
>>>> +    rc = tmc_enable_etr_sink_sysfs(csdev);
>>>> +    if (rc) {
>>>> + guard(raw_spinlock_irqsave)(&drvdata->spinlock);
>>>> +        coresight_set_mode(csdev, CS_MODE_DISABLED);
>>>>       }
>>>> +
>>>> +    return rc;
>>>>   }
>>>>     static int tmc_disable_etr_sink(struct coresight_device *csdev)
>>>
>>>
>>> .
>>>
>>
>
>
> .
>



From shawnguo at kernel.org  Mon Dec 29 00:28:32 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Mon, 29 Dec 2025 16:28:32 +0800
Subject: [PATCH v4 5/5] arm64: dts: freescale: Add the GOcontroll
 Moduline Mini
In-Reply-To: <20251117-mini_iv-v4-5-5aa63832f51a@gocontroll.com>
References: <20251117-mini_iv-v4-0-5aa63832f51a@gocontroll.com>
 <20251117-mini_iv-v4-5-5aa63832f51a@gocontroll.com>
Message-ID: <aVI7sOngq0be4vXy@dragon>

On Mon, Nov 17, 2025 at 04:01:30PM +0100, Maud Spierings via B4 Relay wrote:
> From: Maud Spierings <maudspierings at gocontroll.com>
> 
> The Moduline Mini is a part of the wider GOcontroll Moduline ecosystem. These
> are embedded controllers that focus on modularity with their swappable IO
> modules.
> 
> Features:
> - up to 4 Moduline IO modules
> - 2 CAN busses
> - 1 Ethernet
> - 4 RGB leds
> - 1 3D accelerometer
> - optional Wi-Fi/Bluetooth
> - optional 4G/GPS
> 
> Signed-off-by: Maud Spierings <maudspierings at gocontroll.com>
> ---
>  arch/arm64/boot/dts/freescale/Makefile             |   1 +
>  .../imx8mm-tx8m-1610-moduline-mini-111.dts         | 688 +++++++++++++++++++++
>  2 files changed, 689 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
> index b2fef44e0a37..0a84c7dc89e3 100644
> --- a/arch/arm64/boot/dts/freescale/Makefile
> +++ b/arch/arm64/boot/dts/freescale/Makefile
> @@ -125,6 +125,7 @@ imx8mm-evkb-pcie-ep-dtbs += imx8mm-evkb.dtb imx-pcie0-ep.dtbo
>  dtb-$(CONFIG_ARCH_MXC) += imx8mm-evk-pcie-ep.dtb imx8mm-evkb-pcie-ep.dtb
>  
>  dtb-$(CONFIG_ARCH_MXC) += imx8mm-tx8m-1610-moduline-iv-306-d.dtb
> +dtb-$(CONFIG_ARCH_MXC) += imx8mm-tx8m-1610-moduline-mini-111.dtb
>  
>  dtb-$(CONFIG_ARCH_MXC) += imx8mm-icore-mx8mm-ctouch2.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx8mm-icore-mx8mm-edimm2.2.dtb
> diff --git a/arch/arm64/boot/dts/freescale/imx8mm-tx8m-1610-moduline-mini-111.dts b/arch/arm64/boot/dts/freescale/imx8mm-tx8m-1610-moduline-mini-111.dts
> new file mode 100644
> index 000000000000..0091196a27d2
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx8mm-tx8m-1610-moduline-mini-111.dts
> @@ -0,0 +1,688 @@
> +// SPDX-License-Identifier: (GPL-2.0 OR MIT)
> +/*
> + * Copyright (C) 2025 Maud Spierings <maudspierings at gocontroll.com>
> + */
> +
> +/dts-v1/;
> +
> +#include "imx8mm-tx8m-1610.dtsi"
> +#include <dt-bindings/leds/common.h>
> +
> +/ {
> +	chassis-type = "embedded";
> +	compatible = "gocontroll,moduline-mini-111", "karo,imx8mm-tx8m-1610", "fsl,imx8mm";
> +	hardware = "Moduline Mini V1.11";
> +	model = "GOcontroll Moduline Mini";
> +
> +	aliases {
> +		usb-host = &usbotg2;
> +		usbotg = &usbotg1;
> +		spi0 = &ecspi2; /* spidev number compatibility */
> +		spi1 = &ecspi3; /* spidev number compatibility */
> +		spi2 = &ecspi1; /* spidev number compatibility */

Alphabetical order?

> +	};
> +
> +	chosen {
> +		stdout-path = "serial2:115200n8";
> +	};
> +
> +	mcp_clock: mcp-clock {
> +		compatible = "fixed-clock";
> +		#clock-cells = <0>;
> +		clock-frequency = <20000000>;
> +	};
> +
> +	reg_3v3_comm: regulator-3v3-communication {
> +		compatible = "regulator-fixed";
> +		enable-active-high;
> +		gpio = <&gpio1 11 GPIO_ACTIVE_HIGH>;
> +		pinctrl-0 = <&pinctrl_reg_comm>;
> +		pinctrl-names = "default";
> +		power-supply = <&reg_6v4>;
> +		/* also powers the cellular modem which can't vote on the regulator */
> +		regulator-always-on;
> +		regulator-max-microvolt = <3300000>;
> +		regulator-min-microvolt = <3300000>;
> +		regulator-name = "3v3_comm";
> +	};
> +
> +	reg_5v0: regulator-5v0 {
> +		compatible = "regulator-fixed";
> +		power-supply = <&reg_6v4>;
> +		regulator-always-on;
> +		regulator-max-microvolt = <5000000>;
> +		regulator-min-microvolt = <5000000>;
> +		regulator-name = "5v0";
> +	};
> +
> +	reg_6v4: regulator-6v4 {
> +		compatible = "regulator-fixed";
> +		regulator-always-on;
> +		regulator-max-microvolt = <6400000>;
> +		regulator-min-microvolt = <6400000>;
> +		regulator-name = "6v4";
> +	};
> +
> +	reg_can1_stby: regulator-can1-stby {
> +		compatible = "regulator-fixed";
> +		gpio = <&gpio2 12 GPIO_ACTIVE_LOW>;
> +		pinctrl-0 = <&pinctrl_can1_reg>;
> +		pinctrl-names = "default";
> +		regulator-max-microvolt = <3300000>;
> +		regulator-min-microvolt = <3300000>;
> +		regulator-name = "can1-stby";
> +	};
> +
> +	reg_can2_stby: regulator-can2-stby {
> +		compatible = "regulator-fixed";
> +		gpio = <&gpio3 15 GPIO_ACTIVE_LOW>;
> +		pinctrl-0 = <&pinctrl_can2_reg>;
> +		pinctrl-names = "default";
> +		regulator-max-microvolt = <3300000>;
> +		regulator-min-microvolt = <3300000>;
> +		regulator-name = "can2-stby";
> +	};
> +
> +	wifi_pwrseq: wifi-pwrseq {
> +		compatible = "mmc-pwrseq-simple";
> +		pinctrl-0 = <&pinctrl_wl_reg>;
> +		pinctrl-names = "default";
> +		post-power-on-delay-ms = <100>;
> +		power-off-delay-us = <500000>;
> +		reset-gpios = <&gpio5 28 GPIO_ACTIVE_LOW>;
> +	};
> +};
> +
> +&ecspi1 {
> +	cs-gpios = <&gpio4 27 GPIO_ACTIVE_LOW>,
> +		   <&gpio3 23 GPIO_ACTIVE_LOW>,
> +		   <&gpio3 1 GPIO_ACTIVE_LOW>;
> +	pinctrl-0 = <&pinctrl_ecspi1>;
> +	pinctrl-names = "default";
> +	status = "okay";
> +
> +	connector at 0 {
> +		compatible = "gocontroll,moduline-module-slot";
> +		reg = <0>;
> +		i2c-bus = <&i2c2>;
> +		interrupt-parent = <&gpio4>;
> +		interrupts = <26 IRQ_TYPE_EDGE_FALLING>;
> +		reset-gpios = <&gpio4 28 GPIO_ACTIVE_LOW>;
> +		slot-number = <3>;
> +		spi-max-frequency = <54000000>;
> +		sync-gpios = <&gpio3 7 GPIO_ACTIVE_HIGH>;
> +		vddhpp-supply = <&reg_6v4>;
> +		vddp-supply = <&reg_5v0>;
> +		vdd-supply = <&reg_vdd_3v3>;
> +	};
> +
> +	connector at 1 {
> +		compatible = "gocontroll,moduline-module-slot";
> +		reg = <1>;
> +		i2c-bus = <&i2c2>;
> +		interrupt-parent = <&gpio3>;
> +		interrupts = <19 IRQ_TYPE_EDGE_FALLING>;
> +		reset-gpios = <&gpio3 21 GPIO_ACTIVE_LOW>;
> +		slot-number = <4>;
> +		spi-max-frequency = <54000000>;
> +		sync-gpios = <&gpio3 7 GPIO_ACTIVE_HIGH>;
> +		vddhpp-supply = <&reg_6v4>;
> +		vddp-supply = <&reg_5v0>;
> +		vdd-supply = <&reg_vdd_3v3>;
> +	};
> +
> +	adc at 2 {
> +		compatible = "microchip,mcp3004";
> +		reg = <2>;
> +		spi-max-frequency = <2300000>;
> +		vref-supply = <&reg_vdd_3v3>;
> +	};
> +};
> +
> +&ecspi2 {
> +	cs-gpios = <&gpio3 24 GPIO_ACTIVE_LOW>,
> +		   <&gpio3 9 GPIO_ACTIVE_LOW>;
> +	pinctrl-0 = <&pinctrl_ecspi2>;
> +	pinctrl-names = "default";
> +	status = "okay";
> +
> +	can at 0 {
> +		compatible = "microchip,mcp25625";
> +		reg = <0>;
> +		clocks = <&mcp_clock>;
> +		interrupt-parent = <&gpio3>;
> +		interrupts = <22 IRQ_TYPE_LEVEL_LOW>;
> +		pinctrl-0 = <&pinctrl_can1>;
> +		pinctrl-names = "default";
> +		spi-max-frequency = <10000000>;
> +		vdd-supply = <&reg_vdd_3v3>;
> +		xceiver-supply = <&reg_can1_stby>;
> +	};
> +
> +	can at 1 {
> +		compatible = "microchip,mcp25625";
> +		reg = <1>;
> +		clocks = <&mcp_clock>;
> +		interrupt-parent = <&gpio3>;
> +		interrupts = <6 IRQ_TYPE_LEVEL_LOW>;
> +		pinctrl-0 = <&pinctrl_can2>;
> +		pinctrl-names = "default";
> +		spi-max-frequency = <10000000>;
> +		vdd-supply = <&reg_vdd_3v3>;
> +		xceiver-supply = <&reg_can2_stby>;
> +	};
> +};
> +
> +&ecspi3 {
> +	cs-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>,
> +		   <&gpio1 2 GPIO_ACTIVE_LOW>;
> +	pinctrl-0 = <&pinctrl_ecspi3>;
> +	pinctrl-names = "default";
> +	status = "okay";
> +
> +	connector at 0 {
> +		compatible = "gocontroll,moduline-module-slot";
> +		reg = <0>;
> +		i2c-bus = <&i2c2>;
> +		interrupt-parent = <&gpio1>;
> +		interrupts = <10 IRQ_TYPE_EDGE_FALLING>;
> +		reset-gpios = <&gpio1 7 GPIO_ACTIVE_LOW>;
> +		slot-number = <1>;
> +		spi-max-frequency = <54000000>;
> +		sync-gpios = <&gpio3 7 GPIO_ACTIVE_HIGH>;
> +		vddhpp-supply = <&reg_6v4>;
> +		vddp-supply = <&reg_5v0>;
> +		vdd-supply = <&reg_vdd_3v3>;
> +	};
> +
> +	connector at 1 {
> +		compatible = "gocontroll,moduline-module-slot";
> +		reg = <1>;
> +		i2c-bus = <&i2c2>;
> +		interrupt-parent = <&gpio1>;
> +		interrupts = <5 IRQ_TYPE_EDGE_FALLING>;
> +		reset-gpios = <&gpio5 21 GPIO_ACTIVE_LOW>;
> +		slot-number = <2>;
> +		spi-max-frequency = <54000000>;
> +		sync-gpios = <&gpio3 7 GPIO_ACTIVE_HIGH>;
> +		vddhpp-supply = <&reg_6v4>;
> +		vddp-supply = <&reg_5v0>;
> +		vdd-supply = <&reg_vdd_3v3>;
> +	};
> +};
> +
> +&gpu_2d {
> +	status = "disabled";
> +};
> +
> +&gpu_3d {
> +	status = "disabled";
> +};
> +
> +&i2c2 {
> +	clock-frequency = <400000>;
> +	pinctrl-0 = <&pinctrl_i2c2>;
> +	pinctrl-1 = <&pinctrl_i2c2_gpio>;
> +	pinctrl-names = "default", "gpio";
> +	scl-gpios = <&gpio5 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
> +	sda-gpios = <&gpio5 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
> +	status = "okay";
> +};
> +
> +&i2c3 {
> +	clock-frequency = <400000>;
> +	pinctrl-0 = <&pinctrl_i2c3>;
> +	pinctrl-1 = <&pinctrl_i2c3_gpio>;
> +	pinctrl-names = "default", "gpio";
> +	scl-gpios = <&gpio5 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
> +	sda-gpios = <&gpio5 19 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
> +	status = "okay";
> +
> +	lp5012 at 14 {

Can we use a generic node name, maybe led-controller?

Shawn

> +		compatible = "ti,lp5012";
> +		reg = <0x14>;
> +		vled-supply = <&reg_6v4>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		multi-led at 0 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <0>;
> +			color = <LED_COLOR_ID_RGB>;
> +			label = "case-led1";
> +
> +			led at 0 {
> +				reg = <0>;
> +				color = <LED_COLOR_ID_RED>;
> +			};
> +
> +			led at 1 {
> +				reg = <1>;
> +				color = <LED_COLOR_ID_GREEN>;
> +			};
> +
> +			led at 2 {
> +				reg = <2>;
> +				color = <LED_COLOR_ID_BLUE>;
> +			};
> +		};
> +
> +		multi-led at 1 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <1>;
> +			color = <LED_COLOR_ID_RGB>;
> +			label = "case-led2";
> +
> +			led at 0 {
> +				reg = <0>;
> +				color = <LED_COLOR_ID_RED>;
> +			};
> +
> +			led at 1 {
> +				reg = <1>;
> +				color = <LED_COLOR_ID_GREEN>;
> +			};
> +
> +			led at 2 {
> +				reg = <2>;
> +				color = <LED_COLOR_ID_BLUE>;
> +			};
> +		};
> +
> +		multi-led at 2 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <2>;
> +			color = <LED_COLOR_ID_RGB>;
> +			label = "case-led3";
> +
> +			led at 0 {
> +				reg = <0>;
> +				color = <LED_COLOR_ID_RED>;
> +			};
> +
> +			led at 1 {
> +				reg = <1>;
> +				color = <LED_COLOR_ID_GREEN>;
> +			};
> +
> +			led at 2 {
> +				reg = <2>;
> +				color = <LED_COLOR_ID_BLUE>;
> +			};
> +		};
> +
> +		multi-led at 3 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <3>;
> +			color = <LED_COLOR_ID_RGB>;
> +			label = "case-led4";
> +
> +			led at 0 {
> +				reg = <0>;
> +				color = <LED_COLOR_ID_RED>;
> +			};
> +
> +			led at 1 {
> +				reg = <1>;
> +				color = <LED_COLOR_ID_GREEN>;
> +			};
> +
> +			led at 2 {
> +				reg = <2>;
> +				color = <LED_COLOR_ID_BLUE>;
> +			};
> +		};
> +	};
> +
> +	accelerometer at 18 {
> +		compatible = "st,lis2dw12";
> +		reg = <0x18>;
> +		interrupt-parent = <&gpio5>;
> +		interrupts = <3 IRQ_TYPE_EDGE_RISING>, <5 IRQ_TYPE_EDGE_RISING>;
> +		pinctrl-0 = <&pinctrl_lis_int>;
> +		pinctrl-names = "default";
> +		vddio-supply = <&reg_vdd_3v3>;
> +		vdd-supply = <&reg_vdd_3v3>;
> +	};
> +
> +	humidity-sensor at 5f {
> +		compatible = "st,hts221";
> +		reg = <0x5f>;
> +		interrupt-parent = <&gpio3>;
> +		interrupts = <10 IRQ_TYPE_EDGE_RISING>;
> +		pinctrl-0 = <&pinctrl_hts_int>;
> +		pinctrl-names = "default";
> +		vdd-supply = <&reg_vdd_3v3>;
> +	};
> +};
> +
> +&iomuxc {
> +	pinctrl_bt: btgrp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_GPIO1_IO01_GPIO1_IO1
> +				MX8MM_DSE_X1
> +			MX8MM_IOMUXC_SAI5_MCLK_GPIO3_IO25
> +				(MX8MM_PULL_UP | MX8MM_PULL_ENABLE | MX8MM_HYS_SCHMITT)
> +			MX8MM_IOMUXC_ECSPI2_SS0_GPIO5_IO13
> +				MX8MM_DSE_X1
> +		>;
> +	};
> +
> +	pinctrl_can1: can1grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_SAI2_TXC_GPIO4_IO25
> +				(MX8MM_PULL_UP | MX8MM_PULL_ENABLE)
> +			MX8MM_IOMUXC_SAI5_RXD1_GPIO3_IO22
> +				(MX8MM_PULL_UP | MX8MM_PULL_ENABLE | MX8MM_HYS_SCHMITT)
> +		>;
> +	};
> +
> +	pinctrl_can1_reg: can1reggrp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12
> +				(MX8MM_DSE_X2 | MX8MM_FSEL_FAST | MX8MM_PULL_UP | MX8MM_PULL_ENABLE)
> +		>;
> +	};
> +
> +	pinctrl_can2: can2grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_NAND_CLE_GPIO3_IO5
> +				(MX8MM_PULL_UP | MX8MM_PULL_ENABLE)
> +			MX8MM_IOMUXC_NAND_DATA00_GPIO3_IO6
> +				(MX8MM_PULL_UP | MX8MM_PULL_ENABLE | MX8MM_HYS_SCHMITT)
> +		>;
> +	};
> +
> +	pinctrl_can2_reg: can2reggrp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_NAND_RE_B_GPIO3_IO15
> +				(MX8MM_DSE_X2 | MX8MM_FSEL_FAST | MX8MM_PULL_UP | MX8MM_PULL_ENABLE)
> +		>;
> +	};
> +
> +	pinctrl_ecspi1: ecspi1grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI
> +				MX8MM_DSE_X4
> +			MX8MM_IOMUXC_ECSPI1_MISO_ECSPI1_MISO
> +				(MX8MM_DSE_X4 | MX8MM_HYS_SCHMITT)
> +			MX8MM_IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK
> +				MX8MM_DSE_X4
> +			MX8MM_IOMUXC_SAI2_MCLK_GPIO4_IO27
> +				MX8MM_DSE_X1
> +			MX8MM_IOMUXC_SAI5_RXD2_GPIO3_IO23
> +				MX8MM_DSE_X1
> +			MX8MM_IOMUXC_NAND_CE0_B_GPIO3_IO1
> +				MX8MM_DSE_X1
> +		>;
> +	};
> +
> +	pinctrl_ecspi2: ecspi2grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_ECSPI2_MOSI_ECSPI2_MOSI
> +				MX8MM_DSE_X4
> +			MX8MM_IOMUXC_ECSPI2_MISO_ECSPI2_MISO
> +				(MX8MM_DSE_X4 | MX8MM_HYS_SCHMITT)
> +			MX8MM_IOMUXC_ECSPI2_SCLK_ECSPI2_SCLK
> +				MX8MM_DSE_X4
> +			MX8MM_IOMUXC_SAI5_RXD3_GPIO3_IO24
> +				MX8MM_DSE_X1
> +			MX8MM_IOMUXC_NAND_DATA03_GPIO3_IO9
> +				MX8MM_DSE_X1
> +		>;
> +	};
> +
> +	pinctrl_ecspi3: ecspi3grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_UART1_TXD_ECSPI3_MOSI
> +				MX8MM_DSE_X4
> +			MX8MM_IOMUXC_UART2_RXD_ECSPI3_MISO
> +				(MX8MM_DSE_X4 | MX8MM_HYS_SCHMITT)
> +			MX8MM_IOMUXC_UART1_RXD_ECSPI3_SCLK
> +				MX8MM_DSE_X4
> +			MX8MM_IOMUXC_GPIO1_IO09_GPIO1_IO9
> +				MX8MM_DSE_X1
> +			MX8MM_IOMUXC_GPIO1_IO02_GPIO1_IO2
> +				MX8MM_DSE_X1
> +		>;
> +	};
> +
> +	pinctrl_hts_int: htsintgrp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_NAND_DATA04_GPIO3_IO10
> +				(MX8MM_PULL_ENABLE | MX8MM_HYS_SCHMITT)
> +		>;
> +	};
> +
> +	pinctrl_i2c2: i2c2grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_I2C2_SCL_I2C2_SCL
> +				MX8MM_I2C_DEFAULT
> +			MX8MM_IOMUXC_I2C2_SDA_I2C2_SDA
> +				MX8MM_I2C_DEFAULT
> +		>;
> +	};
> +
> +	pinctrl_i2c2_gpio: i2c2-gpiogrp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_I2C2_SCL_GPIO5_IO16
> +				MX8MM_I2C_DEFAULT
> +			MX8MM_IOMUXC_I2C2_SDA_GPIO5_IO17
> +				MX8MM_I2C_DEFAULT
> +		>;
> +	};
> +
> +	pinctrl_i2c3: i2c3grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_I2C3_SCL_I2C3_SCL
> +				MX8MM_I2C_DEFAULT
> +			MX8MM_IOMUXC_I2C3_SDA_I2C3_SDA
> +				MX8MM_I2C_DEFAULT
> +		>;
> +	};
> +
> +	pinctrl_i2c3_gpio: i2c3-gpiogrp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_I2C3_SCL_GPIO5_IO18
> +				MX8MM_I2C_DEFAULT
> +			MX8MM_IOMUXC_I2C3_SDA_GPIO5_IO19
> +				MX8MM_I2C_DEFAULT
> +		>;
> +	};
> +
> +	pinctrl_lis_int: lisintgrp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_SPDIF_TX_GPIO5_IO3
> +				(MX8MM_PULL_ENABLE | MX8MM_HYS_SCHMITT)
> +			MX8MM_IOMUXC_SPDIF_EXT_CLK_GPIO5_IO5
> +				(MX8MM_PULL_ENABLE | MX8MM_HYS_SCHMITT)
> +		>;
> +	};
> +
> +	pinctrl_reg_comm: reg_commgrp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_GPIO1_IO11_GPIO1_IO11
> +				MX8MM_DSE_X1
> +		>;
> +	};
> +
> +	pinctrl_sysfs_gpios: sysfsgpiogrp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_GPIO1_IO07_GPIO1_IO7
> +				MX8MM_DSE_X1
> +			MX8MM_IOMUXC_I2C4_SDA_GPIO5_IO21
> +				MX8MM_DSE_X1
> +			MX8MM_IOMUXC_SAI3_RXFS_GPIO4_IO28
> +				MX8MM_DSE_X1
> +			MX8MM_IOMUXC_SAI5_RXD0_GPIO3_IO21
> +				MX8MM_DSE_X1
> +			MX8MM_IOMUXC_SD2_WP_GPIO2_IO20
> +				MX8MM_DSE_X1
> +			MX8MM_IOMUXC_GPIO1_IO00_GPIO1_IO0
> +				MX8MM_DSE_X1
> +			MX8MM_IOMUXC_GPIO1_IO04_GPIO1_IO4
> +				MX8MM_DSE_X1
> +			MX8MM_IOMUXC_GPIO1_IO06_GPIO1_IO6
> +				MX8MM_DSE_X1
> +		>;
> +	};
> +
> +	pinctrl_uart1: uart1grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_SAI2_RXC_UART1_DCE_RX
> +				(MX8MM_PULL_UP | MX8MM_PULL_ENABLE)
> +			MX8MM_IOMUXC_SAI2_RXFS_UART1_DCE_TX
> +				(MX8MM_PULL_UP | MX8MM_PULL_ENABLE)
> +			MX8MM_IOMUXC_SAI2_RXD0_UART1_DCE_RTS_B
> +				(MX8MM_PULL_UP | MX8MM_PULL_ENABLE)
> +			MX8MM_IOMUXC_SAI2_TXFS_UART1_DCE_CTS_B
> +				(MX8MM_PULL_UP | MX8MM_PULL_ENABLE)
> +		>;
> +	};
> +
> +	pinctrl_uart2: uart2grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_SAI3_TXFS_UART2_DCE_RX
> +				(MX8MM_PULL_UP | MX8MM_PULL_ENABLE)
> +			MX8MM_IOMUXC_SAI3_TXC_UART2_DCE_TX
> +				(MX8MM_PULL_UP | MX8MM_PULL_ENABLE)
> +			MX8MM_IOMUXC_SAI3_RXD_UART2_DCE_RTS_B
> +				(MX8MM_PULL_UP | MX8MM_PULL_ENABLE)
> +			MX8MM_IOMUXC_SAI3_RXC_UART2_DCE_CTS_B
> +				(MX8MM_PULL_UP | MX8MM_PULL_ENABLE)
> +		>;
> +	};
> +
> +	pinctrl_uart3: uart3grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_UART3_RXD_UART3_DCE_RX
> +				(MX8MM_PULL_UP | MX8MM_PULL_ENABLE)
> +			MX8MM_IOMUXC_UART3_TXD_UART3_DCE_TX
> +				(MX8MM_PULL_UP | MX8MM_PULL_ENABLE)
> +		>;
> +	};
> +
> +	pinctrl_usdhc2: pinctrlusdhc2grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK
> +				(MX8MM_DSE_X2 | MX8MM_FSEL_FAST | MX8MM_PULL_ENABLE)
> +			MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD
> +				(MX8MM_DSE_X2 | MX8MM_USDHC_DATA_DEFAULT)
> +			MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0
> +				(MX8MM_DSE_X2 | MX8MM_USDHC_DATA_DEFAULT)
> +			MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1
> +				(MX8MM_DSE_X2 | MX8MM_USDHC_DATA_DEFAULT)
> +			MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2
> +				(MX8MM_DSE_X2 | MX8MM_USDHC_DATA_DEFAULT)
> +			MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3
> +				(MX8MM_DSE_X2 | MX8MM_USDHC_DATA_DEFAULT)
> +		>;
> +	};
> +
> +	pinctrl_wl_int: wlintgrp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_SAI5_RXC_GPIO3_IO20
> +				(MX8MM_PULL_UP | MX8MM_HYS_SCHMITT | MX8MM_PULL_ENABLE)
> +		>;
> +	};
> +
> +	pinctrl_wl_reg: wlreggrp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_UART4_RXD_GPIO5_IO28
> +				MX8MM_DSE_X1
> +		>;
> +	};
> +};
> +
> +&uart1 {
> +	pinctrl-0 = <&pinctrl_uart1>;
> +	pinctrl-names = "default";
> +	uart-has-rtscts;
> +	status = "okay";
> +
> +	bluetooth {
> +		compatible = "infineon,cyw43439-bt", "brcm,bcm4329-bt";
> +		device-wakeup-gpios = <&gpio5 13 GPIO_ACTIVE_HIGH>;
> +		interrupt-names = "host-wakeup";
> +		interrupt-parent = <&gpio3>;
> +		interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
> +		max-speed = <921600>;
> +		pinctrl-0 = <&pinctrl_bt>;
> +		pinctrl-names = "default";
> +		shutdown-gpios = <&gpio1 1 GPIO_ACTIVE_HIGH>;
> +		vbat-supply = <&reg_3v3_comm>;
> +		vddio-supply = <&reg_3v3_comm>;
> +	};
> +};
> +
> +&uart2 {
> +	pinctrl-0 = <&pinctrl_uart2>;
> +	pinctrl-names = "default";
> +	uart-has-rtscts;
> +	status = "okay";
> +};
> +
> +&uart3 {
> +	pinctrl-0 = <&pinctrl_uart3>;
> +	pinctrl-names = "default";
> +	status = "okay";
> +};
> +
> +&usbotg1 {
> +	disable-over-current;
> +	dr_mode = "peripheral";
> +	status = "okay";
> +};
> +
> +&usbotg2 {
> +	disable-over-current;
> +	dr_mode = "host";
> +	vbus-supply = <&reg_5v0>;
> +	status = "okay";
> +};
> +
> +&usdhc2 {
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +	cap-power-off-card;
> +	keep-power-in-suspend;
> +	max-frequency = <50000000>;
> +	mmc-pwrseq = <&wifi_pwrseq>;
> +	non-removable;
> +	pinctrl-0 = <&pinctrl_usdhc2>;
> +	pinctrl-names = "default";
> +	sd-uhs-sdr25;
> +	vmmc-supply = <&reg_3v3_comm>;
> +	status = "okay";
> +
> +	wifi at 1 {
> +		compatible = "infineon,cyw43439-fmac", "brcm,bcm4329-fmac";
> +		reg = <1>;
> +		pinctrl-0 = <&pinctrl_wl_int>;
> +		pinctrl-names = "default";
> +		interrupt-names = "host-wake";
> +		interrupt-parent = <&gpio3>;
> +		interrupts = <20 IRQ_TYPE_LEVEL_LOW>;
> +		brcm,board-type = "GOcontroll,moduline";
> +	};
> +};
> +
> +&vpu_blk_ctrl {
> +	status = "disabled";
> +};
> +
> +&vpu_g1 {
> +	status = "disabled";
> +};
> +
> +&vpu_g2 {
> +	status = "disabled";
> +};
> +
> +&wdog1 {
> +	status = "okay";
> +};
> 
> -- 
> 2.51.2
> 
> 


From shawnguo at kernel.org  Mon Dec 29 00:30:28 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Mon, 29 Dec 2025 16:30:28 +0800
Subject: [PATCH] arm64: dts: imx95: correct I3C2 pclk to
 IMX95_CLK_BUSWAKEUP
In-Reply-To: <20251118062855.1417564-1-carlos.song@nxp.com>
References: <20251118062855.1417564-1-carlos.song@nxp.com>
Message-ID: <aVI8JKPm8eTx9NgA@dragon>

On Tue, Nov 18, 2025 at 02:28:54PM +0800, Carlos Song wrote:
> I3C2 is in WAKEUP domain. Its pclk should be IMX95_CLK_BUSWAKEUP.
> 
> Fixes: 969497ebefcf ("arm64: dts: imx95: Add i3c1 and i3c2")
> Signed-off-by: Carlos Song <carlos.song at nxp.com>
> Cc: <stable at vger.kernel.org>

Applied, thanks!


From piotr.kaminski at corpiza.com  Mon Dec 29 00:35:36 2025
From: piotr.kaminski at corpiza.com (=?UTF-8?Q? Piotr_Kami=C5=84ski ?=)
Date: Mon, 29 Dec 2025 08:35:36 GMT
Subject: =?UTF-8?Q?Prosz=C4=99_o_kontakt?=
Message-ID: <20251229084501-0.1.ad.14282.0.2zh0mi4xnp@corpiza.com>

Dzie? dobry,

Czy jest mo?liwo?? nawi?zania wsp??pracy z Pa?stwem?

Z ch?ci? porozmawiam z osob? zajmuj?c? si? dzia?aniami zwi?zanymi ze sprzeda??.

Pomagamy skutecznie pozyskiwa? nowych klient?w.

Zapraszam do kontaktu.


Pozdrawiam
Piotr Kami?ski


From krzk at kernel.org  Mon Dec 29 00:47:54 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 29 Dec 2025 09:47:54 +0100
Subject: [PATCH v4 7/7] ARM: dts: rockchip: rk3506: Add pinctrl and rmio
 dtsi for rk3506
In-Reply-To: <AGkAtwAtJy-UDFfi3M2RSaqR.3.1766993111418.Hmail.ye.zhang@rock-chips.com>
References: <20251227114957.3287944-1-ye.zhang@rock-chips.com>
 <20251227114957.3287944-8-ye.zhang@rock-chips.com>
 <ebb720f6-4756-437f-a71a-d94f45d732e8@kernel.org>
 <AGkAtwAtJy-UDFfi3M2RSaqR.3.1766993111418.Hmail.ye.zhang@rock-chips.com>
Message-ID: <57d27a43-4c3a-415b-b633-3d52c9f96f5a@kernel.org>

On 29/12/2025 08:25, ?? wrote:
> ? 2025/12/28 18:37, Krzysztof Kozlowski ??:
> &gt; On 27/12/2025 12:49, Ye Zhang wrote:
> &gt;&gt; +		/omit-if-no-ref/
> &gt;&gt; +		rm_io28_touch_key_in6: rm-io28-touch-key-in6 {
> &gt;&gt; +			rockchip,pins =
> &gt;&gt; +				&lt;1 RK_PC3 7 &amp;pcfg_pull_none&gt;;
> &gt;&gt; +			rockchip,rmio-pins =
> &gt;&gt; +				&lt;0 28 49&gt;;
> &gt;&gt; +		};
> &gt;&gt; +
> &gt;&gt; +		/omit-if-no-ref/
> &gt;&gt; +		rm_io28_touch_key_in7: rm-io28-touch-key-in7 {
> &gt;&gt; +			rockchip,pins =
> &gt;&gt; +				&lt;1 RK_PC3 7 &amp;pcfg_pull_none&gt;;
> &gt;&gt; +			rockchip,rmio-pins =
> &gt;&gt; +				&lt;0 28 50&gt;;
> &gt;&gt; +		};
> &gt;&gt; +
> &gt;&gt; +		/omit-if-no-ref/
> &gt;&gt; +		rm_io28_sai0_mclk: rm-io28-sai0-mclk {
> &gt;&gt; +			rockchip,pins =
> &gt;&gt; +				&lt;1 RK_PC3 7 &amp;pcfg_pull_none&gt;;
> &gt;&gt; +			rockchip,rmio-pins =
> &gt;&gt; +				&lt;0 28 51&gt;;
> &gt;&gt; +		};
> &gt;&gt; +
> &gt;&gt; +		/omit-if-no-ref/
> &gt;&gt; +		rm_io28_sai0_sclk: rm-io28-sai0-sclk {
> &gt;&gt; +			rockchip,pins =
> &gt;&gt; +				&lt;1 RK_PC3 7 &amp;pcfg_pull_none&gt;;
> &gt;&gt; +			rockchip,rmio-pins =
> &gt;&gt; +				&lt;0 28 52&gt;;
> &gt;&gt; +		};
> &gt;&gt; +
> &gt;&gt; +		/omit-if-no-ref/
> &gt;&gt; +		rm_io28_sai0_lrck: rm-io28-sai0-lrck {
> &gt;&gt; +			rockchip,pins =
> &gt;&gt; +				&lt;1 RK_PC3 7 &amp;pcfg_pull_none&gt;;
> &gt;&gt; +			rockchip,rmio-pins =
> &gt;&gt; +				&lt;0 28 53&gt;;
> &gt;&gt; +		};
> &gt;&gt; +
> &gt;&gt; +		/omit-if-no-ref/
> &gt;&gt; +		rm_io28_sai0_sdi0: rm-io28-sai0-sdi0 {
> &gt;&gt; +			rockchip,pins =
> &gt;&gt; +				&lt;1 RK_PC3 7 &amp;pcfg_pull_none&gt;;
> &gt;&gt; +			rockchip,rmio-pins =
> &gt;&gt; +				&lt;0 28 54&gt;;
> &gt;&gt; +		};
> &gt;
> &gt; Why are you defining all pins? This is wrong, your driver has to do it,
> &gt; not DTS. All these definitions when not used are just pointless.
> &gt;

Don't send HTML to us. I cannot parse above.

Best regards,
Krzysztof


From shawnguo at kernel.org  Mon Dec 29 00:48:52 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Mon, 29 Dec 2025 16:48:52 +0800
Subject: [PATCH 4/4] arm64: dts: imx8mn: Add ifm VHIP4 EvalBoard v1 and v2
In-Reply-To: <20251118121513.88352-4-marex@nabladev.com>
References: <20251118121513.88352-1-marex@nabladev.com>
 <20251118121513.88352-4-marex@nabladev.com>
Message-ID: <aVJAdCxd7GwRQDJE@dragon>

On Tue, Nov 18, 2025 at 01:13:13PM +0100, Marek Vasut wrote:
> From: Fedor Ross <fedor.ross at ifm.com>
> 
> Add support for ifm i.MX8MN VHIP4 EvalBoard v1 and v2 reference design.
> This system exists in two generations, v1 and v2, which share a lot of
> commonality. The boards come with either single gigabit ethernet or an
> KSZ8794 fast-ethernet switch, boot from eMMC, and offer CAN interfaces
> via Microchip MCP25xx SPI CAN controllers, UART, and USB host. The GPU
> is not available in the SoC populated on these devices.
> 
> Signed-off-by: Fedor Ross <fedor.ross at ifm.com>
> Signed-off-by: Marek Vasut <marex at nabladev.com>
> ---
> Cc: Christian Eggers <ceggers at arri.de>
> Cc: Conor Dooley <conor+dt at kernel.org>
> Cc: Fabio Estevam <festevam at gmail.com>
> Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
> Cc: Krzysztof Kozlowski <krzk+dt at kernel.org>
> Cc: Markus Heidelberg <m.heidelberg at cab.de>
> Cc: Rob Herring <robh at kernel.org>
> Cc: Shawn Guo <shawnguo at kernel.org>
> Cc: devicetree at vger.kernel.org
> Cc: imx at lists.linux.dev
> Cc: linux-arm-kernel at lists.infradead.org
> Cc: linux-kernel at vger.kernel.org
> ---
>  arch/arm64/boot/dts/freescale/Makefile        |  19 +
>  .../imx8mn-vhip4-evalboard-common.dtsi        | 404 ++++++++++++++++++
>  ...imx8mn-vhip4-evalboard-ksz8794-common.dtsi |  97 +++++
>  ...mn-vhip4-evalboard-v1-overlay-ksz8794.dtso |  24 ++
>  ...mn-vhip4-evalboard-v1-overlay-ksz9031.dtso |  49 +++
>  .../freescale/imx8mn-vhip4-evalboard-v1.dts   | 260 +++++++++++
>  ...n-vhip4-evalboard-v2-overlay-adin1300.dtso |  63 +++
>  ...mn-vhip4-evalboard-v2-overlay-ksz8794.dtso |  24 ++
>  .../freescale/imx8mn-vhip4-evalboard-v2.dts   | 221 ++++++++++
>  9 files changed, 1161 insertions(+)
>  create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-common.dtsi
>  create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-ksz8794-common.dtsi
>  create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtso
>  create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtso
>  create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1.dts
>  create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtso
>  create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtso
>  create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2.dts
> 
> diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
> index f30d3fd724d0c..01b2ec5ad81ff 100644
> --- a/arch/arm64/boot/dts/freescale/Makefile
> +++ b/arch/arm64/boot/dts/freescale/Makefile
> @@ -191,6 +191,25 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mn-tqma8mqnl-mba8mx.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx8mn-var-som-symphony.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx8mn-venice-gw7902.dtb
>  
> +imx8mn-vhip4-evalboard-v1-overlay-ksz8794-dtbs := imx8mn-vhip4-evalboard-v1.dtb \
> +						  imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtbo
> +imx8mn-vhip4-evalboard-v1-overlay-ksz9031-dtbs := imx8mn-vhip4-evalboard-v1.dtb \
> +						  imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtbo
> +imx8mn-vhip4-evalboard-v2-overlay-ksz8794-dtbs := imx8mn-vhip4-evalboard-v2.dtb \
> +						  imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtbo
> +imx8mn-vhip4-evalboard-v2-overlay-adin1300-dtbs := imx8mn-vhip4-evalboard-v2.dtb \
> +						   imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtbo
> +dtb-$(CONFIG_ARCH_MXC) += imx8mn-vhip4-evalboard-v1.dtb \
> +			  imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtb \
> +			  imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtbo \
> +			  imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtb \
> +			  imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtbo \
> +			  imx8mn-vhip4-evalboard-v2.dtb \
> +			  imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtb \
> +			  imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtbo \
> +			  imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtb \
> +			  imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtbo
> +
>  imx8mn-tqma8mqnl-mba8mx-lvds-tm070jvhg33-dtbs += imx8mn-tqma8mqnl-mba8mx.dtb imx8mn-tqma8mqnl-mba8mx-lvds-tm070jvhg33.dtbo
>  imx8mn-tqma8mqnl-mba8mx-usbotg-dtbs += imx8mn-tqma8mqnl-mba8mx.dtb imx8mn-tqma8mqnl-mba8mx-usbotg.dtbo
>  dtb-$(CONFIG_ARCH_MXC) += imx8mn-tqma8mqnl-mba8mx-lvds-tm070jvhg33.dtb
> diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-common.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-common.dtsi
> new file mode 100644
> index 0000000000000..5fff183dbdc20
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-common.dtsi
> @@ -0,0 +1,404 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright 2020-2024 Fedor Ross <fedor.ross at ifm.com>
> + */
> +
> +#include "imx8mn.dtsi"
> +#include <dt-bindings/leds/common.h>
> +
> +/ {
> +	model = "ifm i.MX8MNano VHIP4 Evaluation Board";
> +	compatible = "ifm,imx8mn-vhip4-evalboard", "ifm,imx8mn-vhip4", "fsl,imx8mn";
> +
> +	aliases {
> +		mmc0 = &usdhc3;
> +		mmc1 = &usdhc1;
> +		mmc2 = &usdhc2;
> +		rtc0 = &hw_rtc;
> +		rtc1 = &snvs_rtc;
> +	};
> +
> +	chosen {
> +		bootargs = "console=ttymxc2,115200 earlycon=ec_imx6q,0x30880000,115200 rootwait";
> +		stdout-path = &uart3;
> +	};
> +
> +	memory at 40000000 {
> +		device_type = "memory";
> +		reg = <0x0 0x40000000 0 0x40000000>;
> +	};
> +
> +	can_clk20m: can-clk20m {
> +		compatible = "fixed-clock";
> +		#clock-cells = <0>;
> +		clock-frequency = <20000000>;
> +	};
> +
> +	can_clk40m: can-clk40m {
> +		compatible = "fixed-clock";
> +		#clock-cells = <0>;
> +		clock-frequency = <40000000>;
> +	};
> +
> +	gpio-keys {
> +		compatible = "gpio-keys";
> +		pinctrl-0 = <&pinctrl_gpio_button>;
> +		pinctrl-names = "default";
> +
> +		button-2 {
> +			label = "Button2";
> +			gpios = <&gpio2 16 GPIO_ACTIVE_LOW>;
> +			linux,code = <KEY_2>;
> +		};
> +
> +		button-3 {
> +			label = "Button3";
> +			gpios = <&gpio2 18 GPIO_ACTIVE_LOW>;
> +			linux,code = <KEY_3>;
> +		};
> +	};
> +
> +	ifm_led: led {
> +		compatible = "gpio-leds";
> +		pinctrl-0 = <&pinctrl_gpio_led>;
> +		pinctrl-names = "default", "extended";
> +
> +		led-0 {
> +			function = LED_FUNCTION_STATUS;
> +			function-enumerator = <1>;
> +			color = <LED_COLOR_ID_YELLOW>;
> +			gpios = <&gpio2 13 GPIO_ACTIVE_HIGH>;
> +			default-state = "keep";
> +		};
> +
> +		led-1 {
> +			function = LED_FUNCTION_STATUS;
> +			function-enumerator = <2>;
> +			color = <LED_COLOR_ID_GREEN>;
> +			gpios = <&gpio2 15 GPIO_ACTIVE_HIGH>;
> +			default-state = "keep";
> +		};
> +	};
> +};
> +
> +&A53_0 {
> +	cpu-supply = <&buck2_reg>;
> +};
> +
> +&A53_1 {
> +	cpu-supply = <&buck2_reg>;
> +};
> +
> +&A53_2 {
> +	cpu-supply = <&buck2_reg>;
> +};
> +
> +&A53_3 {
> +	cpu-supply = <&buck2_reg>;
> +};
> +
> +&ddrc {
> +	operating-points-v2 = <&ddrc_opp_table>;
> +
> +	ddrc_opp_table: opp-table {
> +		compatible = "operating-points-v2";
> +
> +		opp-25000000 {
> +			opp-hz = /bits/ 64 <25000000>;
> +		};
> +
> +		opp-100000000 {
> +			opp-hz = /bits/ 64 <100000000>;
> +		};
> +
> +		opp-600000000 {
> +			opp-hz = /bits/ 64 <600000000>;
> +		};
> +	};
> +};
> +
> +&ecspi1 {
> +	pinctrl-names = "default", "cs";
> +	pinctrl-0 = <&pinctrl_ecspi1>;
> +	pinctrl-1 = <&pinctrl_ecspi1_cs>;
> +	/delete-property/ dmas;
> +	/delete-property/ dma-names;
> +};
> +
> +&ecspi3 {
> +	pinctrl-names = "default", "cs";
> +	pinctrl-0 = <&pinctrl_ecspi3>;
> +	pinctrl-1 = <&pinctrl_ecspi3_cs>;
> +	/delete-property/ dmas;
> +	/delete-property/ dma-names;
> +};
> +
> +&gpu {
> +	/* SoC has GPU fused off. */
> +	status = "disabled";
> +};
> +
> +&i2c1 {
> +	clock-frequency = <100000>;
> +	pinctrl-names = "default", "gpio";
> +	pinctrl-0 = <&pinctrl_i2c1>;
> +	pinctrl-1 = <&pinctrl_i2c1_gpio>;
> +
> +	eeprom at 51 {
> +		compatible = "atmel,24c128";
> +		reg = <0x51>;
> +	};
> +
> +	hw_rtc: rtc at 52 {
> +		compatible = "microcrystal,rv3028";
> +		reg = <0x52>;
> +	};
> +};
> +
> +&i2c3 {
> +	clock-frequency = <100000>;
> +	pinctrl-names = "default", "gpio";
> +	pinctrl-0 = <&pinctrl_i2c3>;
> +	pinctrl-1 = <&pinctrl_i2c3_gpio>;
> +
> +	ifm_pmic: pmic at 4b {
> +		compatible = "rohm,bd71847";
> +		reg = <0x4b>;
> +		pinctrl-0 = <&pinctrl_pmic>;
> +		rohm,reset-snvs-powered;
> +
> +		regulators {
> +			buck1_reg: BUCK1 {
> +				regulator-name = "buck1";
> +				regulator-min-microvolt = <790000>;
> +				regulator-max-microvolt = <860000>;
> +				regulator-boot-on;
> +				regulator-always-on;
> +				regulator-ramp-delay = <1250>;
> +			};
> +
> +			buck2_reg: BUCK2 {
> +				regulator-name = "buck2";
> +				regulator-min-microvolt = <840000>;
> +				regulator-max-microvolt = <960000>;
> +				regulator-boot-on;
> +				regulator-always-on;
> +				regulator-ramp-delay = <1250>;
> +			};
> +
> +			buck3_reg: BUCK3 {
> +				// BUCK5 in datasheet
> +				regulator-name = "buck3";
> +				regulator-min-microvolt = <700000>;
> +				regulator-max-microvolt = <1350000>;
> +			};
> +
> +			buck4_reg: BUCK4 {
> +				// BUCK6 in datasheet
> +				regulator-name = "buck4";
> +				regulator-min-microvolt = <3300000>;
> +				regulator-max-microvolt = <3300000>;
> +				regulator-boot-on;
> +				regulator-always-on;
> +			};
> +
> +			buck5_reg: BUCK5 {
> +				// BUCK7 in datasheet
> +				regulator-name = "buck5";
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <1800000>;
> +				regulator-boot-on;
> +				regulator-always-on;
> +			};
> +
> +			buck6_reg: BUCK6 {
> +				// BUCK8 in datasheet
> +				regulator-name = "buck6";
> +				regulator-min-microvolt = <1100000>;
> +				regulator-max-microvolt = <1100000>;
> +				regulator-boot-on;
> +				regulator-always-on;
> +			};
> +
> +			ldo1_reg: LDO1 {
> +				regulator-name = "ldo1";
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <1800000>;
> +				regulator-boot-on;
> +				regulator-always-on;
> +			};
> +
> +			ldo2_reg: LDO2 {
> +				regulator-name = "ldo2";
> +				regulator-min-microvolt = <800000>;
> +				regulator-max-microvolt = <800000>;
> +				regulator-boot-on;
> +				regulator-always-on;
> +			};
> +
> +			ldo3_reg: LDO3 {
> +				regulator-name = "ldo3";
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <1800000>;
> +				regulator-boot-on;
> +				regulator-always-on;
> +			};
> +
> +			ldo4_reg: LDO4 {
> +				regulator-name = "ldo4";
> +				regulator-min-microvolt = <900000>;
> +				regulator-max-microvolt = <1800000>;
> +			};
> +
> +			ldo5_reg: LDO5 {
> +				regulator-name = "ldo5";
> +				regulator-min-microvolt = <3300000>;
> +				regulator-max-microvolt = <3300000>;
> +			};
> +
> +			ldo6_reg: LDO6 {
> +				regulator-name = "ldo6";
> +				regulator-min-microvolt = <1200000>;
> +				regulator-max-microvolt = <1200000>;
> +				regulator-boot-on;
> +				regulator-always-on;
> +			};
> +		};
> +	};
> +};
> +
> +&iomuxc {
> +	pinctrl_ecspi1: ecspi1-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK		0x110
> +			MX8MN_IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI		0x110
> +			MX8MN_IOMUXC_ECSPI1_MISO_ECSPI1_MISO		0x190
> +		>;
> +	};
> +
> +	pinctrl_ecspi3: ecspi3-grp {
> +		fsl,pins = <
> +			/* SPI3_CAN_CLK */
> +			MX8MN_IOMUXC_UART1_RXD_ECSPI3_SCLK		0x110
> +			/* SPI3_CAN_MOSI */
> +			MX8MN_IOMUXC_UART1_TXD_ECSPI3_MOSI		0x110
> +			/* SPI3_CAN_MISO */
> +			MX8MN_IOMUXC_UART2_RXD_ECSPI3_MISO		0x190
> +		>;
> +	};
> +
> +	pinctrl_gpio_button: gpiobutton-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_SD2_DATA1_GPIO2_IO16		0x96
> +			MX8MN_IOMUXC_SD2_DATA3_GPIO2_IO18		0x96
> +		>;
> +	};
> +
> +	pinctrl_gpio_led: gpioled-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_SD2_CLK_GPIO2_IO13			0x116
> +			MX8MN_IOMUXC_SD2_DATA0_GPIO2_IO15		0x116
> +		>;
> +	};
> +
> +	pinctrl_usdhc3: usdhc3-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK		0x40000110
> +			MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d0
> +			MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d0
> +			MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d0
> +			MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d0
> +			MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d0
> +			MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d0
> +			MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d0
> +			MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d0
> +			MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d0
> +			MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x190
> +			MX8MN_IOMUXC_NAND_READY_B_USDHC3_RESET_B	0x150
> +		>;
> +	};
> +
> +	pinctrl_usdhc3_100mhz: usdhc3-100mhz-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK		0x40000114
> +			MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d4
> +			MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d4
> +			MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d4
> +			MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d4
> +			MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d4
> +			MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d4
> +			MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d4
> +			MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d4
> +			MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d4
> +			MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x194
> +			MX8MN_IOMUXC_NAND_READY_B_USDHC3_RESET_B	0x150
> +		>;
> +	};
> +
> +	pinctrl_usdhc3_200mhz: usdhc3-200mhz-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK		0x40000116
> +			MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d6
> +			MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d6
> +			MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d6
> +			MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d6
> +			MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d6
> +			MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d6
> +			MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d6
> +			MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d6
> +			MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d6
> +			MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x196
> +			MX8MN_IOMUXC_NAND_READY_B_USDHC3_RESET_B	0x150
> +		>;
> +	};
> +
> +	pinctrl_wdog: wdog-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B		0x64
> +		>;
> +	};
> +};
> +
> +&pgc_gpumix {
> +	/* SoC has GPU fused off. */
> +	status = "disabled";
> +};
> +
> +&snvs {
> +	snvs-lpgpr {
> +		compatible = "fsl,imx7d-snvs-lpgpr";

I wonder why this SoC specific compatible is defined in board level DTS.

> +	};
> +};
> +
> +&snvs_pwrkey {
> +	status = "okay";
> +};
> +
> +&uart3 { /* console */
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_uart3>;
> +	status = "okay";
> +};
> +
> +&usbotg1 {
> +	status = "okay";
> +};
> +
> +&usdhc3 {
> +	assigned-clocks = <&clk IMX8MN_CLK_USDHC3_ROOT>;
> +	assigned-clock-rates = <400000000>;
> +	pinctrl-names = "default", "state_100mhz", "state_200mhz";
> +	pinctrl-0 = <&pinctrl_usdhc3>;
> +	pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
> +	pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
> +	bus-width = <8>;
> +	non-removable;
> +	status = "okay";
> +};
> +
> +&wdog1 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_wdog>;
> +	fsl,ext-reset-output;
> +	status = "okay";
> +};
> diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-ksz8794-common.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-ksz8794-common.dtsi
> new file mode 100644
> index 0000000000000..06917a26a5bef
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-ksz8794-common.dtsi
> @@ -0,0 +1,97 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright (C) 2025 Fedor Ross <fedor.ross at ifm.com>
> + */
> +
> +#include <dt-bindings/gpio/gpio.h>
> +
> +#include "imx8mn-pinfunc.h"
> +
> +&ecspi1 {
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +	status = "okay";
> +
> +	ksz8794: ethernet-switch at 1 {
> +		compatible = "microchip,ksz8794";
> +		pinctrl-names = "default", "reset";
> +		pinctrl-0 = <&pinctrl_ks8794>;
> +		pinctrl-1 = <&pinctrl_ks8794>;
> +		reg = <1>;
> +

Nit: unneeded newline.

> +		reset-gpios = <&gpio4 28 GPIO_ACTIVE_LOW>;
> +		spi-max-frequency = <5000000>;
> +		status = "okay";

Unneeded "okay" status?

> +
> +		ethernet-ports {
> +			#address-cells = <1>;
> +			#size-cells = <0>;

Have a newline between properties and child node.

> +			port at 0 {
> +				reg = <0>;
> +				label = "lan1";
> +			};

Have a newline between nodes.

> +			port at 1 {
> +				reg = <1>;
> +				label = "lan2";
> +			};
> +			port at 2 {
> +				reg = <2>;
> +				label = "lan3";
> +			};
> +			port at 4 {
> +				reg = <4>;
> +				label = "cpu";
> +				ethernet = <&fec1>;
> +				phy-mode = "rgmii-id";
> +				rx-internal-delay-ps = <2000>;
> +				tx-internal-delay-ps = <2000>;
> +				fixed-link {
> +					full-duplex;
> +					speed = <1000>;
> +				};
> +			};
> +		};
> +	};
> +};
> +
> +&fec1 {
> +	fsl,magic-packet;
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_fec1>;
> +	status = "okay";
> +
> +	phy-mode = "rgmii-id";

Move it above 'status'.

> +	fixed-link {
> +		full-duplex;
> +		speed = <1000>;
> +	};
> +};
> +
> +&iomuxc {
> +	pinctrl_fec1: fec1-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_ENET_MDC_ENET1_MDC			0x16
> +			MX8MN_IOMUXC_ENET_MDIO_ENET1_MDIO		0x96
> +			MX8MN_IOMUXC_ENET_TD3_ENET1_RGMII_TD3		0x16
> +			MX8MN_IOMUXC_ENET_TD2_ENET1_RGMII_TD2		0x16
> +			MX8MN_IOMUXC_ENET_TD1_ENET1_RGMII_TD1		0x16
> +			MX8MN_IOMUXC_ENET_TD0_ENET1_RGMII_TD0		0x16
> +			MX8MN_IOMUXC_ENET_RD3_ENET1_RGMII_RD3		0x96
> +			MX8MN_IOMUXC_ENET_RD2_ENET1_RGMII_RD2		0x96
> +			MX8MN_IOMUXC_ENET_RD1_ENET1_RGMII_RD1		0x96
> +			MX8MN_IOMUXC_ENET_RD0_ENET1_RGMII_RD0		0x96
> +			MX8MN_IOMUXC_ENET_TXC_ENET1_RGMII_TXC		0x10
> +			MX8MN_IOMUXC_ENET_RXC_ENET1_RGMII_RXC		0x96
> +			MX8MN_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x96
> +			MX8MN_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x16
> +			MX8MN_IOMUXC_SAI3_TXFS_GPIO4_IO31		0x1d6
> +		>;
> +	};
> +
> +	pinctrl_ks8794: ks8794-grp {
> +		fsl,pins = <
> +			/* KSZ8794 reset line */
> +			MX8MN_IOMUXC_SAI3_RXFS_GPIO4_IO28		0x16
> +		>;
> +	};
> +};
> diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtso b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtso
> new file mode 100644
> index 0000000000000..20eb427f3dd66
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtso
> @@ -0,0 +1,24 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright (C) 2021 Marek Vasut
> + */
> +/dts-v1/;
> +/plugin/;
> +
> +#include <dt-bindings/gpio/gpio.h>
> +
> +#include "imx8mn-pinfunc.h"
> +
> +&pinctrl_ecspi1 {
> +	fsl,pins = <
> +		MX8MN_IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK		0x10
> +		MX8MN_IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI		0x10
> +		MX8MN_IOMUXC_ECSPI1_MISO_ECSPI1_MISO		0x90
> +		/* KS8794 nCS */
> +		MX8MN_IOMUXC_I2C4_SDA_GPIO5_IO21		0x150
> +		/* ANV32C81 nCS */
> +		MX8MN_IOMUXC_ECSPI1_SS0_GPIO5_IO9		0x150
> +	>;
> +};
> +
> +#include "imx8mn-vhip4-evalboard-ksz8794-common.dtsi"
> diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtso b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtso
> new file mode 100644
> index 0000000000000..405e69752f214
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtso
> @@ -0,0 +1,49 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright (C) 2021 Marek Vasut
> + */
> +/dts-v1/;
> +/plugin/;
> +
> +#include "imx8mn-pinfunc.h"
> +
> +&fec1 {
> +	fsl,magic-packet;
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_fec1>;
> +	status = "okay";
> +
> +	phy-handle = <&ethphy0>;
> +	phy-mode = "rgmii-id";

Ditto

> +	mdio {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		ethphy0: ethernet-phy at 0 {
> +			compatible = "ethernet-phy-ieee802.3-c22";
> +			reg = <0>;
> +		};
> +	};
> +};
> +
> +&iomuxc {
> +	pinctrl_fec1: fec1-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_ENET_MDC_ENET1_MDC			0x16
> +			MX8MN_IOMUXC_ENET_MDIO_ENET1_MDIO		0x96
> +			MX8MN_IOMUXC_ENET_TD3_ENET1_RGMII_TD3		0x16
> +			MX8MN_IOMUXC_ENET_TD2_ENET1_RGMII_TD2		0x16
> +			MX8MN_IOMUXC_ENET_TD1_ENET1_RGMII_TD1		0x16
> +			MX8MN_IOMUXC_ENET_TD0_ENET1_RGMII_TD0		0x16
> +			MX8MN_IOMUXC_ENET_RD3_ENET1_RGMII_RD3		0x96
> +			MX8MN_IOMUXC_ENET_RD2_ENET1_RGMII_RD2		0x96
> +			MX8MN_IOMUXC_ENET_RD1_ENET1_RGMII_RD1		0x96
> +			MX8MN_IOMUXC_ENET_RD0_ENET1_RGMII_RD0		0x96
> +			MX8MN_IOMUXC_ENET_TXC_ENET1_RGMII_TXC		0x16
> +			MX8MN_IOMUXC_ENET_RXC_ENET1_RGMII_RXC		0x96
> +			MX8MN_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x96
> +			MX8MN_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x16
> +			MX8MN_IOMUXC_SAI3_TXFS_GPIO4_IO31		0x1d6
> +		>;
> +	};
> +};
> diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1.dts b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1.dts
> new file mode 100644
> index 0000000000000..6d1cebffcae5d
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1.dts
> @@ -0,0 +1,260 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright 2020-2024 Fedor Ross <fedor.ross at ifm.com>
> + */
> +
> +/dts-v1/;
> +
> +#include "imx8mn-vhip4-evalboard-common.dtsi"
> +
> +/ {
> +	model = "ifm i.MX8MNano VHIP4 Evaluation Board v1";
> +	compatible = "ifm,imx8mn-vhip4-evalboard-v1", "ifm,imx8mn-vhip4-evalboard",
> +		     "ifm,imx8mn-vhip4", "fsl,imx8mn";
> +};
> +
> +&ifm_led {
> +	pinctrl-1 = <&pinctrl_gpio_led_v1>;
> +
> +	led-2 {
> +		function = LED_FUNCTION_STATUS;
> +		function-enumerator = <3>;
> +		color = <LED_COLOR_ID_YELLOW>;
> +		gpios = <&gpio2 17 GPIO_ACTIVE_HIGH>;
> +		default-state = "keep";
> +	};
> +
> +	led-3 {
> +		function = LED_FUNCTION_STATUS;
> +		function-enumerator = <4>;
> +		color = <LED_COLOR_ID_GREEN>;
> +		gpios = <&gpio2 19 GPIO_ACTIVE_HIGH>;
> +		default-state = "keep";
> +	};
> +};
> +
> +&ecspi1 {
> +	cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>, <&gpio5 21 GPIO_ACTIVE_LOW>;
> +	status = "okay";
> +
> +	eeprom at 0 {
> +		compatible = "anvo,anv32c81w", "atmel,at25";
> +		reg = <0>;
> +		spi-max-frequency = <20000000>;
> +		spi-cpha;
> +		spi-cpol;
> +		pagesize = <1>;
> +		size = <32768>;
> +		address-width = <16>;
> +	};
> +};
> +
> +&ecspi3 {
> +	cs-gpios = <&gpio5 25 GPIO_ACTIVE_LOW>, <&gpio5 4 GPIO_ACTIVE_LOW>;
> +	status = "okay";
> +
> +	can0: can at 0 {
> +		compatible = "microchip,mcp25625";
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&pinctrl_mcp25625>;
> +		reg = <0>;
> +		clocks = <&can_clk20m>;
> +		interrupt-parent = <&gpio4>;
> +		interrupts = <21 IRQ_TYPE_LEVEL_LOW>;
> +		gpio-controller;
> +		#gpio-cells = <2>;
> +	};
> +
> +	can1: can at 1 {
> +		compatible = "microchip,mcp2518fd";
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&pinctrl_mcp2518>;
> +		reg = <1>;
> +		clocks = <&can_clk40m>;
> +		interrupt-parent = <&gpio5>;
> +		interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
> +		microchip,rx-int-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>;
> +		spi-max-frequency = <20000000>;
> +	};
> +};
> +
> +&gpio4 {
> +	/*
> +	 * Hog USB-nRESET high here, since neither U-Boot nor Linux
> +	 * has any support for USB Hub GPIO reset so far.
> +	 */
> +	usb-nreset-hog {
> +		gpio-hog;
> +		gpios = <29 GPIO_ACTIVE_HIGH>;
> +		line-name = "USB_nRESET";
> +		output-high;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&pinctrl_usb_nreset>;
> +	};
> +};
> +
> +&i2c1 {
> +	scl-gpios = <&gpio5 14 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
> +	sda-gpios = <&gpio5 15 GPIO_ACTIVE_HIGH>;
> +	status = "okay";
> +
> +	lm75 at 48 {
> +		compatible = "national,lm75";
> +		reg = <0x48>;
> +	};
> +
> +	eeprom at 50 {
> +		compatible = "atmel,24c128";
> +		reg = <0x50>;
> +	};
> +};
> +
> +&i2c2 {
> +	clock-frequency = <100000>;
> +	pinctrl-names = "default", "gpio";
> +	pinctrl-0 = <&pinctrl_i2c2>;
> +	pinctrl-1 = <&pinctrl_i2c2_gpio>;
> +	scl-gpios = <&gpio5 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
> +	sda-gpios = <&gpio5 17 GPIO_ACTIVE_HIGH>;
> +	status = "okay";
> +};
> +
> +&i2c3 {
> +	scl-gpios = <&gpio2 10 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
> +	sda-gpios = <&gpio2 11 GPIO_ACTIVE_HIGH>;
> +	status = "okay";
> +};
> +
> +&ifm_pmic {
> +	interrupt-parent = <&gpio2>;
> +	interrupts = <0 GPIO_ACTIVE_LOW>;
> +};
> +
> +&iomuxc {
> +	pinctrl_ecspi1_cs: ecspi1-cs-grp {
> +		fsl,pins = <
> +			/* KS8794 nCS */
> +			MX8MN_IOMUXC_I2C4_SDA_GPIO5_IO21		0x150
> +			/* ANV32C81 nCS */
> +			MX8MN_IOMUXC_ECSPI1_SS0_GPIO5_IO9		0x150
> +		>;
> +	};
> +
> +	pinctrl_ecspi3_cs: ecspi3-cs-grp {
> +		fsl,pins = <
> +			/* MCP25625 nCS */
> +			MX8MN_IOMUXC_UART2_TXD_GPIO5_IO25		0x150
> +			/* MCP2518FD nCS */
> +			MX8MN_IOMUXC_SPDIF_RX_GPIO5_IO4			0x150
> +		>;
> +	};
> +
> +	pinctrl_gpio_led_v1: gpioled-v1-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_SD2_DATA2_GPIO2_IO17		0x116
> +			MX8MN_IOMUXC_SD2_RESET_B_GPIO2_IO19		0x116
> +		>;
> +	};
> +
> +	pinctrl_i2c1: i2c1-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_I2C1_SCL_I2C1_SCL			0x40000056
> +			MX8MN_IOMUXC_I2C1_SDA_I2C1_SDA			0x400000d6
> +		>;
> +	};
> +
> +	pinctrl_i2c1_gpio: i2c1-gpio-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_I2C1_SCL_GPIO5_IO14		0x56
> +			MX8MN_IOMUXC_I2C1_SDA_GPIO5_IO15		0xd6
> +		>;
> +	};
> +
> +	pinctrl_i2c2: i2c2-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_I2C2_SCL_I2C2_SCL			0x40000056
> +			MX8MN_IOMUXC_I2C2_SDA_I2C2_SDA			0x400000d6
> +		>;
> +	};
> +
> +	pinctrl_i2c2_gpio: i2c2-gpio-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_I2C2_SCL_GPIO5_IO16		0x56
> +			MX8MN_IOMUXC_I2C2_SDA_GPIO5_IO17		0xd6
> +		>;
> +	};
> +
> +	pinctrl_i2c3: i2c3-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_SD1_RESET_B_I2C3_SCL		0x40000056
> +			MX8MN_IOMUXC_SD1_STROBE_I2C3_SDA		0x400000d6
> +		>;
> +	};
> +
> +	pinctrl_i2c3_gpio: i2c3-gpio-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_SD1_RESET_B_GPIO2_IO10		0x56
> +			MX8MN_IOMUXC_SD1_STROBE_GPIO2_IO11		0xd6
> +		>;
> +	};
> +
> +	pinctrl_mcp2518: mcp2518-grp {
> +		fsl,pins = <
> +			/* MCP2518 nINT line */
> +			MX8MN_IOMUXC_SAI3_MCLK_GPIO5_IO2		0x116
> +			/* MCP2518 nINT1/GPIO1 line */
> +			MX8MN_IOMUXC_SAI3_TXD_GPIO5_IO1			0x116
> +		>;
> +	};
> +
> +	pinctrl_mcp25625: mcp25625-grp {
> +		fsl,pins = <
> +			/* MCP25625 nINT line */
> +			MX8MN_IOMUXC_SAI2_RXFS_GPIO4_IO21		0x156
> +		>;
> +	};
> +
> +	pinctrl_pmic: pmic-irq-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_SD1_CLK_GPIO2_IO0			0x16
> +		>;
> +	};
> +
> +	pinctrl_uart3: uart3-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_UART3_RXD_UART3_DCE_RX		0x142
> +			MX8MN_IOMUXC_UART3_TXD_UART3_DCE_TX		0x142
> +		>;
> +	};
> +
> +	pinctrl_usb_nreset: usbnreset-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_SAI3_RXC_GPIO4_IO29                0x14a
> +		>;
> +	};
> +
> +	pinctrl_gpio_5: gpio5-grp {
> +		fsl,pins = <
> +			/* CFG_EEPROM_WP */
> +			MX8MN_IOMUXC_I2C4_SCL_GPIO5_IO20		0x140
> +		>;
> +	};
> +
> +	pinctrl_wdog: wdog-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B		0x64
> +		>;
> +	};
> +};
> +
> +&gpio5 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_gpio_5>;
> +	gpio-line-names =
> +		"", "", "", "", "", "", "", "",
> +		"", "", "", "", "", "", "", "",
> +		"", "", "", "",
> +		"ifm_device_info_eeprom_wp",
> +		"", "", "",
> +		"", "", "", "", "", "", "", "";
> +};
> diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtso b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtso
> new file mode 100644
> index 0000000000000..be6bf4ba7458f
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtso
> @@ -0,0 +1,63 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright 2024 Fedor Ross <fedor.ross at ifm.com>
> + */
> +
> +/dts-v1/;
> +/plugin/;
> +
> +#include <dt-bindings/gpio/gpio.h>
> +#include <dt-bindings/interrupt-controller/arm-gic.h>
> +#include "imx8mn-pinfunc.h"
> +
> +&fec1 {
> +	fsl,magic-packet;
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_fec1>;
> +	status = "okay";
> +
> +	phy-handle = <&ethphy0>;
> +	phy-mode = "rgmii-id";

Ditto

> +
> +	mdio {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		ethphy0: ethernet-phy at 0 {
> +			reg = <0>;
> +
> +			adi,rx-internal-delay-ps = <1800>;
> +			adi,tx-internal-delay-ps = <2200>;
> +

Nit: not sure these newlines in middle of property list are useful.

Shawn

> +			interrupts-extended = <&gpio4 31 IRQ_TYPE_LEVEL_LOW>;
> +			reset-gpios = <&gpio4 28 GPIO_ACTIVE_LOW>;
> +			reset-assert-us = <10000>;
> +			reset-deassert-us = <10000>;
> +		};
> +	};
> +};
> +
> +&iomuxc {
> +	pinctrl_fec1: fec1-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_ENET_MDC_ENET1_MDC			0x16
> +			MX8MN_IOMUXC_ENET_MDIO_ENET1_MDIO		0x96
> +			MX8MN_IOMUXC_ENET_TD3_ENET1_RGMII_TD3		0x16
> +			MX8MN_IOMUXC_ENET_TD2_ENET1_RGMII_TD2		0x16
> +			MX8MN_IOMUXC_ENET_TD1_ENET1_RGMII_TD1		0x16
> +			MX8MN_IOMUXC_ENET_TD0_ENET1_RGMII_TD0		0x16
> +			MX8MN_IOMUXC_ENET_RD3_ENET1_RGMII_RD3		0x96
> +			MX8MN_IOMUXC_ENET_RD2_ENET1_RGMII_RD2		0x96
> +			MX8MN_IOMUXC_ENET_RD1_ENET1_RGMII_RD1		0x96
> +			MX8MN_IOMUXC_ENET_RD0_ENET1_RGMII_RD0		0x96
> +			MX8MN_IOMUXC_ENET_TXC_ENET1_RGMII_TXC		0x16
> +			MX8MN_IOMUXC_ENET_RXC_ENET1_RGMII_RXC		0x96
> +			MX8MN_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x96
> +			MX8MN_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x16
> +			/* nRST */
> +			MX8MN_IOMUXC_SAI3_RXFS_GPIO4_IO28		0x156
> +			/* nIRQ */
> +			MX8MN_IOMUXC_SAI3_TXFS_GPIO4_IO31		0x1d6
> +		>;
> +	};
> +};
> diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtso b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtso
> new file mode 100644
> index 0000000000000..ab1304ebd965e
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtso
> @@ -0,0 +1,24 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright (C) 2021 Marek Vasut
> + */
> +/dts-v1/;
> +/plugin/;
> +
> +#include <dt-bindings/gpio/gpio.h>
> +
> +#include "imx8mn-pinfunc.h"
> +
> +&pinctrl_ecspi1 {
> +	fsl,pins = <
> +		MX8MN_IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK		0x10
> +		MX8MN_IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI		0x10
> +		MX8MN_IOMUXC_ECSPI1_MISO_ECSPI1_MISO		0x90
> +		/* KS8794 nCS */
> +		MX8MN_IOMUXC_GPIO1_IO11_GPIO1_IO11		0x150
> +		/* ANV32C81 nCS */
> +		MX8MN_IOMUXC_ECSPI1_SS0_GPIO5_IO9		0x150
> +	>;
> +};
> +
> +#include "imx8mn-vhip4-evalboard-ksz8794-common.dtsi"
> diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2.dts b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2.dts
> new file mode 100644
> index 0000000000000..5c17f309b93ab
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2.dts
> @@ -0,0 +1,221 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright 2024 Fedor Ross <fedor.ross at ifm.com>
> + */
> +
> +/dts-v1/;
> +
> +#include "imx8mn-vhip4-evalboard-common.dtsi"
> +
> +/ {
> +	model = "ifm i.MX8MNano VHIP4 Evaluation Board v2";
> +	compatible = "ifm,imx8mn-vhip4-evalboard-v2", "ifm,imx8mn-vhip4-evalboard",
> +		     "ifm,imx8mn-vhip4", "fsl,imx8mn";
> +
> +	multi-led {
> +		compatible = "leds-group-multicolor";
> +		color = <LED_COLOR_ID_RGB>;
> +		function = LED_FUNCTION_INDICATOR;
> +		leds = <&rgb_0>, <&rgb_1>, <&rgb_2>;
> +	};
> +};
> +
> +&ifm_led {
> +	pinctrl-1 = <&pinctrl_gpio_led_v2>;
> +
> +	rgb_0: rgb-led-red {
> +		color = <LED_COLOR_ID_RED>;
> +		gpios = <&gpio2 17 GPIO_ACTIVE_HIGH>;
> +		default-state = "keep";
> +	};
> +
> +	rgb_1: rgb-led-green {
> +		color = <LED_COLOR_ID_GREEN>;
> +		gpios = <&gpio2 19 GPIO_ACTIVE_HIGH>;
> +		default-state = "keep";
> +	};
> +
> +	rgb_2: rgb-led-blue {
> +		color = <LED_COLOR_ID_BLUE>;
> +		gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>;
> +		default-state = "keep";
> +	};
> +};
> +
> +&ecspi1 {
> +	cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>, <&gpio1 11 GPIO_ACTIVE_LOW>;
> +	status = "okay";
> +
> +	eeprom at 0 {
> +		compatible = "fujitsu,mb85rs64", "atmel,at25";
> +		reg = <0>;
> +		spi-max-frequency = <20000000>;
> +		spi-cpha;
> +		spi-cpol;
> +		pagesize = <1>;
> +		size = <32768>;
> +		address-width = <16>;
> +	};
> +};
> +
> +&ecspi3 {
> +	cs-gpios = <&gpio5 25 GPIO_ACTIVE_LOW>;
> +	status = "okay";
> +
> +	can0: can at 0 {
> +		compatible = "microchip,mcp2518fd";
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&pinctrl_mcp2518>;
> +		reg = <0>;
> +		clocks = <&can_clk40m>;
> +		interrupt-parent = <&gpio1>;
> +		interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
> +		microchip,rx-int-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
> +		spi-max-frequency = <20000000>;
> +	};
> +};
> +
> +&i2c1 {
> +	scl-gpios = <&gpio2 6 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
> +	sda-gpios = <&gpio2 7 GPIO_ACTIVE_HIGH>;
> +	status = "okay";
> +
> +	tmp1075 at 48 {
> +		compatible = "ti,tmp1075";
> +		reg = <0x48>;
> +	};
> +
> +	eeprom at 54 {
> +		compatible = "atmel,24c128";
> +		reg = <0x54>;
> +	};
> +};
> +
> +&i2c3 {
> +	scl-gpios = <&gpio5 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
> +	sda-gpios = <&gpio5 19 GPIO_ACTIVE_HIGH>;
> +	status = "okay";
> +};
> +
> +&ifm_pmic {
> +	interrupt-parent = <&gpio5>;
> +	interrupts = <17 GPIO_ACTIVE_LOW>;
> +};
> +
> +&iomuxc {
> +	pinctrl_ecspi1_cs: ecspi1-cs-grp {
> +		fsl,pins = <
> +			/* KS8794 nCS */
> +			MX8MN_IOMUXC_GPIO1_IO11_GPIO1_IO11		0x150
> +			/* Retain memory nCS (FRAM or MRAM) */
> +			MX8MN_IOMUXC_ECSPI1_SS0_GPIO5_IO9		0x150
> +			/* RETAIN_nHOLD */
> +			MX8MN_IOMUXC_SPDIF_RX_GPIO5_IO4			0x140
> +		>;
> +	};
> +
> +	pinctrl_ecspi3_cs: ecspi3-cs-grp {
> +		fsl,pins = <
> +			/* MCP2518FD nCS */
> +			MX8MN_IOMUXC_UART2_TXD_GPIO5_IO25		0x150
> +		>;
> +	};
> +
> +	pinctrl_gpio_led_v2: gpioled-v2-grp {
> +		fsl,pins = <
> +			/* LED_RGB_RED */
> +			MX8MN_IOMUXC_SD2_DATA2_GPIO2_IO17		0x116
> +			/* LED_RGB_GREEN */
> +			MX8MN_IOMUXC_SD2_RESET_B_GPIO2_IO19		0x116
> +			/* LED_RGB_BLUE */
> +			MX8MN_IOMUXC_SD2_WP_GPIO2_IO20			0x116
> +		>;
> +	};
> +
> +	pinctrl_i2c1: i2c1-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_SD1_DATA4_I2C1_SCL			0x40000056
> +			MX8MN_IOMUXC_SD1_DATA5_I2C1_SDA			0x400000d6
> +		>;
> +	};
> +
> +	pinctrl_i2c1_gpio: i2c1-gpio-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_SD1_DATA4_GPIO2_IO6		0x56
> +			MX8MN_IOMUXC_SD1_DATA5_GPIO2_IO7		0xd6
> +			/* CFG_EEPROM_WP */
> +			MX8MN_IOMUXC_SD1_STROBE_GPIO2_IO11		0x140
> +			/* RTC_nIRQ */
> +			MX8MN_IOMUXC_SPDIF_EXT_CLK_GPIO5_IO5		0x116
> +			/* LOG_EE_WP */
> +			MX8MN_IOMUXC_SPDIF_TX_GPIO5_IO3			0x140
> +		>;
> +	};
> +
> +	pinctrl_i2c3: i2c3-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_I2C3_SCL_I2C3_SCL			0x40000056
> +			MX8MN_IOMUXC_I2C3_SDA_I2C3_SDA			0x400000d6
> +		>;
> +	};
> +
> +	pinctrl_i2c3_gpio: i2c3-gpio-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_I2C3_SCL_GPIO5_IO18		0x56
> +			MX8MN_IOMUXC_I2C3_SDA_GPIO5_IO19		0xd6
> +		>;
> +	};
> +
> +	pinctrl_mcp2518: mcp2518-grp {
> +		fsl,pins = <
> +			/* CAN0_CLKO */
> +			MX8MN_IOMUXC_GPIO1_IO00_GPIO1_IO0		0x116
> +			/* CAN0_nINT0 */
> +			MX8MN_IOMUXC_GPIO1_IO03_GPIO1_IO3		0x116
> +			/* CAN0_nINT1 */
> +			MX8MN_IOMUXC_GPIO1_IO04_GPIO1_IO4		0x116
> +			/* CAN0_nINT */
> +			MX8MN_IOMUXC_GPIO1_IO01_GPIO1_IO1		0x116
> +		>;
> +	};
> +
> +	pinctrl_pmic: pmic-irq-grp {
> +		fsl,pins = <
> +			/* PMIC_nIRQ */
> +			MX8MN_IOMUXC_I2C2_SDA_GPIO5_IO17		0x1d6
> +		>;
> +	};
> +
> +	pinctrl_uart3: uart3-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_SD1_DATA6_UART3_DCE_TX		0x142
> +			MX8MN_IOMUXC_SD1_DATA7_UART3_DCE_RX		0x142
> +		>;
> +	};
> +
> +	pinctrl_wdog: wdog-grp {
> +		fsl,pins = <
> +			MX8MN_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B		0x64
> +		>;
> +	};
> +};
> +
> +&gpio2 {
> +	gpio-line-names =
> +		"", "", "", "", "", "", "", "",
> +		"", "", "",
> +		"ifm_device_info_eeprom_wp",
> +		"", "", "", "",
> +		"", "", "", "", "", "", "", "",
> +		"", "", "", "", "", "", "", "";
> +};
> +
> +&gpio5 {
> +	gpio-line-names =
> +		"", "", "",
> +		"ifm_logging_eeprom_wp",
> +		"", "", "", "",
> +		"", "", "", "", "", "", "", "",
> +		"", "", "", "",	"", "", "", "",
> +		"", "", "", "", "", "", "", "";
> +};
> -- 
> 2.51.0
> 


From krzk at kernel.org  Mon Dec 29 00:50:24 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 29 Dec 2025 09:50:24 +0100
Subject: [PATCH v3 1/5] dt-bindings: mfd: maxim,max77759: reference
 power-supply schema and add regulator property
In-Reply-To: <20251227-max77759-charger-v3-1-54e664f5ca92@google.com>
References: <20251227-max77759-charger-v3-0-54e664f5ca92@google.com>
 <20251227-max77759-charger-v3-1-54e664f5ca92@google.com>
Message-ID: <20251229-festive-daft-boobook-838fb6@quoll>

On Sat, Dec 27, 2025 at 12:04:21AM +0000, Amit Sunil Dhamne wrote:
> Extend the max77759 binding to reference power-supply schema, so that
> PMIC node can reference its supplier. Also, add regulator property to
> control CHGIN (OTG) voltage.
> 
> Signed-off-by: Amit Sunil Dhamne <amitsd at google.com>
> ---
>  .../devicetree/bindings/mfd/maxim,max77759.yaml          | 16 +++++++++++++++-
>  1 file changed, 15 insertions(+), 1 deletion(-)

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof



From shawnguo at kernel.org  Mon Dec 29 00:51:27 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Mon, 29 Dec 2025 16:51:27 +0800
Subject: [PATCH] ARM: dts: nxp: imx: Fix mc13xxx LED node names
In-Reply-To: <20251118213551.44116-1-robh@kernel.org>
References: <20251118213551.44116-1-robh@kernel.org>
Message-ID: <aVJBDxyrhCzUgTiL@dragon>

On Tue, Nov 18, 2025 at 03:35:50PM -0600, Rob Herring (Arm) wrote:
> Node names are supposed to be generic and use hexadecimal unit-addresses.
> 
> Signed-off-by: Rob Herring (Arm) <robh at kernel.org>

Applied, thanks!


From shawnguo at kernel.org  Mon Dec 29 00:53:24 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Mon, 29 Dec 2025 16:53:24 +0800
Subject: [PATCH v2 0/2] two small fixes for imx8qm-mek board
In-Reply-To: <20251119-dts-imx8qm-v2-0-2579434f95cb@nxp.com>
References: <20251119-dts-imx8qm-v2-0-2579434f95cb@nxp.com>
Message-ID: <aVJBhP5lIZWaGUqi@dragon>

On Wed, Nov 19, 2025 at 11:22:38AM +0800, Haibo Chen wrote:
> Signed-off-by: Haibo Chen <haibo.chen at nxp.com>
> ---
> Changes in v2:
> - PATCH 1: add fix tag
> - PATCH 2: add Frank's ack.
> - Link to v1: https://lore.kernel.org/r/20251118-dts-imx8qm-v1-0-63e226ffe512 at nxp.com
> 
> ---
> Haibo Chen (2):
>       arm64: dts: imx8qm-mek: correct the light sensor interrupt type to low level
>       arm64: dts: add off-on-delay-us for usdhc2 regulator

Applied both, thanks!


From alchark at gmail.com  Mon Dec 29 02:11:57 2025
From: alchark at gmail.com (Alexey Charkov)
Date: Mon, 29 Dec 2025 14:11:57 +0400
Subject: [PATCH 0/7] arm64: dts: rockchip: Sound fixes and additions on
 RK3576 boards
Message-ID: <20251229-rk3576-sound-v1-0-2f59ef0d19b1@gmail.com>

Here are some device tree updates to improve sound output on RK3576
boards.

The first two patches fix analog audio output on FriendlyElec NanoPi M5,
as it doesn't work with the current device tree.

The third one is purely cosmetic, to present a more user-friendly sound
card name to the userspace on NanoPi M5.

The rest add new functionality: HDMI sound output on three boards that
didn't enable it, and analog sound on RK3576 EVB1.

Signed-off-by: Alexey Charkov <alchark at gmail.com>
---
Alexey Charkov (7):
      arm64: dts: rockchip: Fix headphones widget name on NanoPi M5
      arm64: dts: rockchip: Configure MCLK for analog sound on NanoPi M5
      arm64: dts: rockchip: Use a readable audio card name on NanoPi M5
      arm64: dts: rockchip: Enable HDMI sound on FriendlyElec NanoPi M5
      arm64: dts: rockchip: Enable HDMI sound on Luckfox Core3576
      arm64: dts: rockchip: Enable HDMI sound on RK3576 EVB1
      arm64: dts: rockchip: Enable analog sound on RK3576 EVB1

 arch/arm64/boot/dts/rockchip/rk3576-evb1-v10.dts   | 107 +++++++++++++++++++++
 .../boot/dts/rockchip/rk3576-luckfox-core3576.dtsi |   8 ++
 arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts  |  22 ++++-
 3 files changed, 132 insertions(+), 5 deletions(-)
---
base-commit: cc3aa43b44bdb43dfbac0fcb51c56594a11338a8
change-id: 20251222-rk3576-sound-0c26e3b16924

Best regards,
-- 
Alexey Charkov <alchark at gmail.com>



From alchark at gmail.com  Mon Dec 29 02:11:58 2025
From: alchark at gmail.com (Alexey Charkov)
Date: Mon, 29 Dec 2025 14:11:58 +0400
Subject: [PATCH 1/7] arm64: dts: rockchip: Fix headphones widget name on
 NanoPi M5
In-Reply-To: <20251229-rk3576-sound-v1-0-2f59ef0d19b1@gmail.com>
References: <20251229-rk3576-sound-v1-0-2f59ef0d19b1@gmail.com>
Message-ID: <20251229-rk3576-sound-v1-1-2f59ef0d19b1@gmail.com>

Fix the mismatch between the simple-audio-card routing table vs. widget
names, which caused the following error at boot preventing the sound
card from getting added:

[    6.625634] asoc-simple-card sound: ASoC: DAPM unknown pin Headphones
[    6.627247] asoc-simple-card sound: ASoC: Failed to add route HPOL -> Headphones(*)
[    6.627988] asoc-simple-card sound: ASoC: Failed to add route HPOR -> Headphones(*)

Fixes: 96cbdfdd3ac2 ("arm64: dts: rockchip: Add FriendlyElec NanoPi M5 support")
Cc: <stable at vger.kernel.org>
Signed-off-by: Alexey Charkov <alchark at gmail.com>
---
 arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts b/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts
index cce34c541f7c..37184913f918 100644
--- a/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts
@@ -211,7 +211,7 @@ sound {
 			"Headphones", "HPOR",
 			"IN1P", "Microphone Jack";
 		simple-audio-card,widgets =
-			"Headphone", "Headphone Jack",
+			"Headphone", "Headphones",
 			"Microphone", "Microphone Jack";
 
 		simple-audio-card,codec {

-- 
2.51.2



From alchark at gmail.com  Mon Dec 29 02:11:59 2025
From: alchark at gmail.com (Alexey Charkov)
Date: Mon, 29 Dec 2025 14:11:59 +0400
Subject: [PATCH 2/7] arm64: dts: rockchip: Configure MCLK for analog sound
 on NanoPi M5
In-Reply-To: <20251229-rk3576-sound-v1-0-2f59ef0d19b1@gmail.com>
References: <20251229-rk3576-sound-v1-0-2f59ef0d19b1@gmail.com>
Message-ID: <20251229-rk3576-sound-v1-2-2f59ef0d19b1@gmail.com>

NanoPi M5 derives its analog sound signal from SAI2 in M0 pin mode, so the
MCLK pin should be configured accordingly for the sound codec to get its
I2S signal from the SoC. Request the required pin config.

The clock itself should also be CLK_SAI2_MCLKOUT_TO_IO for the sound to
work (otherwise there is only silence out of the audio out jack).

Fixes: 96cbdfdd3ac2 ("arm64: dts: rockchip: Add FriendlyElec NanoPi M5 support")
Cc: <stable at vger.kernel.org>
Signed-off-by: Alexey Charkov <alchark at gmail.com>
---
 arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts b/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts
index 37184913f918..bb2cc2814b83 100644
--- a/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts
@@ -201,6 +201,7 @@ sound {
 		pinctrl-names = "default";
 		pinctrl-0 = <&hp_det_l>;
 
+		simple-audio-card,bitclock-master = <&masterdai>;
 		simple-audio-card,format = "i2s";
 		simple-audio-card,hp-det-gpios = <&gpio2 RK_PD6 GPIO_ACTIVE_LOW>;
 		simple-audio-card,mclk-fs = <256>;
@@ -218,8 +219,9 @@ simple-audio-card,codec {
 			sound-dai = <&rt5616>;
 		};
 
-		simple-audio-card,cpu {
+		masterdai: simple-audio-card,cpu {
 			sound-dai = <&sai2>;
+			system-clock-frequency = <12288000>;
 		};
 	};
 };
@@ -727,10 +729,12 @@ &i2c5 {
 	rt5616: audio-codec at 1b {
 		compatible = "realtek,rt5616";
 		reg = <0x1b>;
-		assigned-clocks = <&cru CLK_SAI2_MCLKOUT>;
+		assigned-clocks = <&cru CLK_SAI2_MCLKOUT_TO_IO>;
 		assigned-clock-rates = <12288000>;
-		clocks = <&cru CLK_SAI2_MCLKOUT>;
+		clocks = <&cru CLK_SAI2_MCLKOUT_TO_IO>;
 		clock-names = "mclk";
+		pinctrl-0 = <&sai2m0_mclk>;
+		pinctrl-names = "default";
 		#sound-dai-cells = <0>;
 	};
 };

-- 
2.51.2



From alchark at gmail.com  Mon Dec 29 02:12:00 2025
From: alchark at gmail.com (Alexey Charkov)
Date: Mon, 29 Dec 2025 14:12:00 +0400
Subject: [PATCH 3/7] arm64: dts: rockchip: Use a readable audio card name
 on NanoPi M5
In-Reply-To: <20251229-rk3576-sound-v1-0-2f59ef0d19b1@gmail.com>
References: <20251229-rk3576-sound-v1-0-2f59ef0d19b1@gmail.com>
Message-ID: <20251229-rk3576-sound-v1-3-2f59ef0d19b1@gmail.com>

'simple-audio-card,name' ends up in user visible places such as ALSA mixer
names, so use a more human-readable name instead of realtek,rt5616-codec

Signed-off-by: Alexey Charkov <alchark at gmail.com>
---
 arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts b/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts
index bb2cc2814b83..f350e96de1f0 100644
--- a/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts
@@ -205,7 +205,7 @@ sound {
 		simple-audio-card,format = "i2s";
 		simple-audio-card,hp-det-gpios = <&gpio2 RK_PD6 GPIO_ACTIVE_LOW>;
 		simple-audio-card,mclk-fs = <256>;
-		simple-audio-card,name = "realtek,rt5616-codec";
+		simple-audio-card,name = "Onboard Analog RT5616";
 
 		simple-audio-card,routing =
 			"Headphones", "HPOL",

-- 
2.51.2



From alchark at gmail.com  Mon Dec 29 02:12:01 2025
From: alchark at gmail.com (Alexey Charkov)
Date: Mon, 29 Dec 2025 14:12:01 +0400
Subject: [PATCH 4/7] arm64: dts: rockchip: Enable HDMI sound on
 FriendlyElec NanoPi M5
In-Reply-To: <20251229-rk3576-sound-v1-0-2f59ef0d19b1@gmail.com>
References: <20251229-rk3576-sound-v1-0-2f59ef0d19b1@gmail.com>
Message-ID: <20251229-rk3576-sound-v1-4-2f59ef0d19b1@gmail.com>

All RK3576 boards get their HDMI sound from SAI6, which is internally
connected to the HDMI codec. Enable this for FriendlyElec NanoPi M5.

Signed-off-by: Alexey Charkov <alchark at gmail.com>
---
 arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts b/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts
index f350e96de1f0..41d352994892 100644
--- a/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts
@@ -326,6 +326,10 @@ hdmi_out_con: endpoint {
 	};
 };
 
+&hdmi_sound {
+	status = "okay";
+};
+
 &hdptxphy {
 	status = "okay";
 };
@@ -852,6 +856,10 @@ &sai2 {
 	status = "okay";
 };
 
+&sai6 {
+	status = "okay";
+};
+
 &saradc {
 	vref-supply = <&vcca_1v8_s0>;
 	status = "okay";

-- 
2.51.2



From alchark at gmail.com  Mon Dec 29 02:12:02 2025
From: alchark at gmail.com (Alexey Charkov)
Date: Mon, 29 Dec 2025 14:12:02 +0400
Subject: [PATCH 5/7] arm64: dts: rockchip: Enable HDMI sound on Luckfox
 Core3576
In-Reply-To: <20251229-rk3576-sound-v1-0-2f59ef0d19b1@gmail.com>
References: <20251229-rk3576-sound-v1-0-2f59ef0d19b1@gmail.com>
Message-ID: <20251229-rk3576-sound-v1-5-2f59ef0d19b1@gmail.com>

All RK3576 boards get their HDMI sound from SAI6, which is internally
connected to the HDMI codec. Enable this for Luckfox Core3576

Signed-off-by: Alexey Charkov <alchark at gmail.com>
---
 arch/arm64/boot/dts/rockchip/rk3576-luckfox-core3576.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3576-luckfox-core3576.dtsi b/arch/arm64/boot/dts/rockchip/rk3576-luckfox-core3576.dtsi
index 9187012d6fa4..749f0a54b478 100644
--- a/arch/arm64/boot/dts/rockchip/rk3576-luckfox-core3576.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3576-luckfox-core3576.dtsi
@@ -246,6 +246,10 @@ hdmi_out_con: endpoint {
 	};
 };
 
+&hdmi_sound {
+	status = "okay";
+};
+
 &hdptxphy {
 	status = "okay";
 };
@@ -691,6 +695,10 @@ &rng {
 	status = "okay";
 };
 
+&sai6 {
+	status = "okay";
+};
+
 &saradc {
 	vref-supply = <&vcca_1v8_s0>;
 	status = "okay";

-- 
2.51.2



From alchark at gmail.com  Mon Dec 29 02:12:03 2025
From: alchark at gmail.com (Alexey Charkov)
Date: Mon, 29 Dec 2025 14:12:03 +0400
Subject: [PATCH 6/7] arm64: dts: rockchip: Enable HDMI sound on RK3576 EVB1
In-Reply-To: <20251229-rk3576-sound-v1-0-2f59ef0d19b1@gmail.com>
References: <20251229-rk3576-sound-v1-0-2f59ef0d19b1@gmail.com>
Message-ID: <20251229-rk3576-sound-v1-6-2f59ef0d19b1@gmail.com>

All RK3576 boards get their HDMI sound from SAI6, which is internally
connected to the HDMI codec. Enable this for Rockchip RK3576 EVB1

Signed-off-by: Alexey Charkov <alchark at gmail.com>
---
 arch/arm64/boot/dts/rockchip/rk3576-evb1-v10.dts | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3576-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3576-evb1-v10.dts
index db8fef7a4f1b..deab20ff4d97 100644
--- a/arch/arm64/boot/dts/rockchip/rk3576-evb1-v10.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3576-evb1-v10.dts
@@ -315,6 +315,10 @@ hdmi_out_con: endpoint {
 	};
 };
 
+&hdmi_sound {
+	status = "okay";
+};
+
 &hdptxphy {
 	status = "okay";
 };
@@ -835,6 +839,10 @@ wifi_wake_host: wifi-wake-host {
 	};
 };
 
+&sai6 {
+	status = "okay";
+};
+
 &sdhci {
 	bus-width = <8>;
 	full-pwr-cycle-in-suspend;

-- 
2.51.2



From alchark at gmail.com  Mon Dec 29 02:12:04 2025
From: alchark at gmail.com (Alexey Charkov)
Date: Mon, 29 Dec 2025 14:12:04 +0400
Subject: [PATCH 7/7] arm64: dts: rockchip: Enable analog sound on RK3576
 EVB1
In-Reply-To: <20251229-rk3576-sound-v1-0-2f59ef0d19b1@gmail.com>
References: <20251229-rk3576-sound-v1-0-2f59ef0d19b1@gmail.com>
Message-ID: <20251229-rk3576-sound-v1-7-2f59ef0d19b1@gmail.com>

Rockchip RK3576 EVB1 board uses the typical configuration with an ES8388
analog codec driven from built-in SAI I2S.

Add device tree nodes for it.

Signed-off-by: Alexey Charkov <alchark at gmail.com>
---
 arch/arm64/boot/dts/rockchip/rk3576-evb1-v10.dts | 99 ++++++++++++++++++++++++
 1 file changed, 99 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3576-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3576-evb1-v10.dts
index deab20ff4d97..0789733c2073 100644
--- a/arch/arm64/boot/dts/rockchip/rk3576-evb1-v10.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3576-evb1-v10.dts
@@ -246,6 +246,63 @@ vcc_wifi_reg_on: regulator-wifi-reg-on {
 		regulator-max-microvolt = <1800000>;
 		vin-supply = <&vcc_1v8_s3>;
 	};
+
+	sound {
+		compatible = "simple-audio-card";
+		pinctrl-names = "default";
+		pinctrl-0 = <&hp_det>;
+		simple-audio-card,name = "On-board Analog ES8388";
+		simple-audio-card,aux-devs = <&hp_power>, <&spk_power>;
+		simple-audio-card,bitclock-master = <&masterdai>;
+		simple-audio-card,format = "i2s";
+		simple-audio-card,frame-master = <&masterdai>;
+		simple-audio-card,hp-det-gpios = <&gpio0 RK_PD3 GPIO_ACTIVE_LOW>;
+		simple-audio-card,mclk-fs = <256>;
+		simple-audio-card,routing =
+			"Headphone Power INL", "LOUT1",
+			"Headphone Power INR", "ROUT1",
+			"Speaker Power INL", "LOUT2",
+			"Speaker Power INR", "ROUT2",
+			"Headphones", "Headphone Power OUTL",
+			"Headphones", "Headphone Power OUTR",
+			"Speaker", "Speaker Power OUTL",
+			"Speaker", "Speaker Power OUTR",
+			"LINPUT1", "Main Mic",
+			"LINPUT2", "Main Mic",
+			"RINPUT1", "Headset Mic",
+			"RINPUT2", "Headset Mic";
+		simple-audio-card,widgets =
+			"Microphone", "Main Mic",
+			"Microphone", "Headset Mic",
+			"Headphone", "Headphones",
+			"Speaker", "Speaker";
+
+		simple-audio-card,cpu {
+			sound-dai = <&sai1>;
+		};
+
+		masterdai: simple-audio-card,codec {
+			sound-dai = <&es8388>;
+			system-clock-frequency = <12288000>;
+		};
+	};
+
+	hp_power: headphone-amplifier {
+		compatible = "simple-audio-amplifier";
+		enable-gpios = <&gpio3 RK_PD6 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&hp_ctl>;
+		sound-name-prefix = "Headphone Power";
+	};
+
+	spk_power: speaker-amplifier {
+		compatible = "simple-audio-amplifier";
+		enable-gpios = <&gpio2 RK_PB1 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&spk_ctl>;
+		sound-name-prefix = "Speaker Power";
+		VCC-supply = <&vcc5v0_device>;
+	};
 };
 
 &cpu_l0 {
@@ -712,6 +769,25 @@ hym8563: rtc at 51 {
 	};
 };
 
+&i2c3 {
+	status = "okay";
+
+	es8388: audio-codec at 10 {
+		compatible = "everest,es8388", "everest,es8328";
+		reg = <0x10>;
+		AVDD-supply = <&vcca_3v3_s0>;
+		DVDD-supply = <&vcc_1v8_s0>;
+		HPVDD-supply = <&vcca_3v3_s0>;
+		PVDD-supply = <&vcc_1v8_s0>;
+		assigned-clocks = <&cru CLK_SAI1_MCLKOUT_TO_IO>;
+		assigned-clock-rates = <12288000>;
+		clocks = <&cru CLK_SAI1_MCLKOUT_TO_IO>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&sai1m0_mclk>;
+		#sound-dai-cells = <0>;
+	};
+};
+
 &mdio0 {
 	rgmii_phy0: ethernet-phy at 1 {
 		compatible = "ethernet-phy-id001c.c916";
@@ -778,6 +854,20 @@ &pcie1 {
 };
 
 &pinctrl {
+	audio {
+		hp_det: hp-det {
+			rockchip,pins = <0 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+
+		hp_ctl: hp-ctl {
+			rockchip,pins = <3 RK_PD6 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+
+		spk_ctl: spk-ctl {
+			rockchip,pins = <2 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
 	bluetooth {
 		bt_reg_on: bt-reg-on {
 			rockchip,pins = <1 RK_PC7 RK_FUNC_GPIO &pcfg_pull_up>;
@@ -839,6 +929,15 @@ wifi_wake_host: wifi-wake-host {
 	};
 };
 
+&sai1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&sai1m0_lrck
+		     &sai1m0_sclk
+		     &sai1m0_sdi0
+		     &sai1m0_sdo0>;
+	status = "okay";
+};
+
 &sai6 {
 	status = "okay";
 };

-- 
2.51.2



From geert at linux-m68k.org  Mon Dec 29 02:18:52 2025
From: geert at linux-m68k.org (Geert Uytterhoeven)
Date: Mon, 29 Dec 2025 11:18:52 +0100
Subject: [PATCH v3 9/9] phy: ti: phy-j721e-wiz: convert from round_rate()
 to determine_rate()
In-Reply-To: <20251212-phy-clk-round-rate-v3-9-beae3962f767@redhat.com>
References: <20251212-phy-clk-round-rate-v3-0-beae3962f767@redhat.com> <20251212-phy-clk-round-rate-v3-9-beae3962f767@redhat.com>
Message-ID: <CAMuHMdXudWW3MPKqP0-d+DyMNRF-X62oyHRnj=MM_9MSpJw6sw@mail.gmail.com>

Hi Brian,

On Fri, 12 Dec 2025 at 00:21, Brian Masney <bmasney at redhat.com> wrote:
> The round_rate() clk ops is deprecated, so migrate this driver from
> round_rate() to determine_rate() using the Coccinelle semantic patch
> on the cover letter of this series.
>
> Signed-off-by: Brian Masney <bmasney at redhat.com>

Thanks for your patch, which is now commit 27287e3b52b5954b ("phy:
ti: phy-j721e-wiz: convert from round_rate() to determine_rate()")
in phy/next

> --- a/drivers/phy/ti/phy-j721e-wiz.c
> +++ b/drivers/phy/ti/phy-j721e-wiz.c
> @@ -934,12 +934,15 @@ static unsigned long wiz_clk_div_recalc_rate(struct clk_hw *hw,
>         return divider_recalc_rate(hw, parent_rate, val, div->table, 0x0, 2);
>  }
>
> -static long wiz_clk_div_round_rate(struct clk_hw *hw, unsigned long rate,
> -                                  unsigned long *prate)
> +static int wiz_clk_div_determine_rate(struct clk_hw *hw,
> +                                     struct clk_rate_request *req)
>  {
>         struct wiz_clk_divider *div = to_wiz_clk_div(hw);
>
> -       return divider_round_rate(hw, rate, prate, div->table, 2, 0x0);
> +       req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate,
> +                                      div->table, 2, 0x0);

Is this correct?  divider_round_rate() can return a negative error code
(from divider_ro_determine_rate()), which is not handled here?

Looks like several other users of divider_round_rate() use this
same logic, and thus are affected, too.

> +
> +       return 0;
>  }
>
>  static int wiz_clk_div_set_rate(struct clk_hw *hw, unsigned long rate,

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds


From josua.mayer at jm0.eu  Mon Dec 29 03:09:55 2025
From: josua.mayer at jm0.eu (Ing. Josua Mayer)
Date: Mon, 29 Dec 2025 12:09:55 +0100
Subject: [PATCH 1/3] power: supply: add battery driver for netronix ec
In-Reply-To: <aVFvVtXe58q84NOk@probook>
References: <20251227-kobo-aura-battery-v1-0-328a90ef5122@jm0.eu>
 <20251227-kobo-aura-battery-v1-1-328a90ef5122@jm0.eu>
 <aVFvVtXe58q84NOk@probook>
Message-ID: <f413cdc1-1461-4896-b68e-6d78343b3fe1@jm0.eu>

Am 28.12.25 um 18:56 schrieb J. Neusch?fer:
> Hello!
> 
> Nice to see someone work on the Netronix EC :-)
> 
> On Sat, Dec 27, 2025 at 05:28:13PM +0100, Josua Mayer wrote:
>> Implement a simple battery driver for monitoring voltage with the
>> netronix embedded controller found in certain ebook readers.
>>
>> Signed-off-by: Josua Mayer <josua.mayer at jm0.eu>
>> ---
>>   drivers/mfd/ntxec.c                  |   1 +
>>   drivers/power/supply/Kconfig         |   9 ++++
>>   drivers/power/supply/Makefile        |   1 +
>>   drivers/power/supply/ntxec-battery.c | 101 +++++++++++++++++++++++++++++++++++
>>   4 files changed, 112 insertions(+)
>>
>> diff --git a/drivers/mfd/ntxec.c b/drivers/mfd/ntxec.c
>> index 08c68de0f01bc..d5059b8862aa8 100644
>> --- a/drivers/mfd/ntxec.c
>> +++ b/drivers/mfd/ntxec.c
>> @@ -139,6 +139,7 @@ static const struct regmap_config regmap_config = {
>>   static const struct mfd_cell ntxec_subdev[] = {
>>   	{ .name = "ntxec-rtc" },
>>   	{ .name = "ntxec-pwm" },
>> +	{ .name = "ntxec-battery" },
>>   };
>>   
>>   static const struct mfd_cell ntxec_subdev_pwm[] = {
>> diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
>> index 92f9f7aae92f2..5674a23ba7bd6 100644
>> --- a/drivers/power/supply/Kconfig
>> +++ b/drivers/power/supply/Kconfig
>> @@ -1132,4 +1132,13 @@ config FUEL_GAUGE_MM8013
>>   	  the state of charge, temperature, cycle count, actual and design
>>   	  capacity, etc.
>>   
>> +config BATTERY_NTXEC
>> +	tristate "Battery driver for Netronix embedded controller"
>> +	depends on MFD_NTXEC
>> +	help
>> +	  Say yes here to enable netronix ec battery monitoring driver.
>> +	  It enables the monitoring battery voltage on certain e-book readers
>> +	  using an embedded controller by ODM Netronix. Battery design
>> +	  characteristics are read from Firmware Tables if available.
> 
> What do you mean by Firmware Tables, and where does this happen?
Effectively I mean device-tree.

This happens in power-supply core automatically for type battery:

static struct power_supply *__must_check
__power_supply_register(struct device *parent,
				   const struct power_supply_desc *desc,
				   const struct power_supply_config *cfg)
{
	...
	/*
	 * Expose constant battery info, if it is available. While there are
	 * some chargers accessing constant battery data, we only want to
	 * expose battery data to userspace for battery devices.
	 */
	if (desc->type == POWER_SUPPLY_TYPE_BATTERY) {
		rc = power_supply_get_battery_info(psy, &psy->battery_info);
		if (rc && rc != -ENODEV && rc != -ENOENT)
			goto check_supplies_failed;
	}
	...
}

This code particular is the reason I marked it optional in DT binding.

> 
> (I guess it means devicetree/fwnode, but "git grep -i 'firmware tables'"
Yes, given that power_supply_get_battery_info uses fwnode_* functions.

> doesn't show many uses of that term)
I was struggling with the phrasing - can change to something better.

> 
>> +
>>   endif # POWER_SUPPLY
>> diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
>> index 4b79d5abc49a7..db6fc815f9da2 100644
>> --- a/drivers/power/supply/Makefile
>> +++ b/drivers/power/supply/Makefile
>> @@ -128,3 +128,4 @@ obj-$(CONFIG_CHARGER_SURFACE)	+= surface_charger.o
>>   obj-$(CONFIG_BATTERY_UG3105)	+= ug3105_battery.o
>>   obj-$(CONFIG_CHARGER_QCOM_SMB2)	+= qcom_smbx.o
>>   obj-$(CONFIG_FUEL_GAUGE_MM8013)	+= mm8013.o
>> +obj-$(CONFIG_BATTERY_NTXEC)	+= ntxec-battery.o
>> diff --git a/drivers/power/supply/ntxec-battery.c b/drivers/power/supply/ntxec-battery.c
>> new file mode 100644
>> index 0000000000000..f49f0966d18dd
>> --- /dev/null
>> +++ b/drivers/power/supply/ntxec-battery.c
>> @@ -0,0 +1,101 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + * The Netronix embedded controller is a microcontroller found in some
>> + * e-book readers designed by the original design manufacturer Netronix, Inc.
>> + * It contains RTC, battery monitoring, system power management, and PWM
>> + * functionality.
>> + *
>> + * This driver implements battery monitoring.
>> + *
>> + * Copyright 2021 Josua Mayer <josua.mayer at jm0.eu>
>> + */
>> +
>> +#include <linux/mfd/ntxec.h>
>> +#include <linux/module.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/power_supply.h>
>> +#include <linux/property.h>
>> +#include <linux/regmap.h>
>> +
>> +static const enum power_supply_property ntxec_battery_properties[] = {
>> +	POWER_SUPPLY_PROP_VOLTAGE_NOW,
>> +};
>> +
>> +struct ntxec_battery {
>> +	struct ntxec *ec;
>> +};
>> +
>> +#define NTXEC_REG_READ_BATTERY	0x41
>> +
>> +static int ntxec_battery_get_property(struct power_supply *psy,
>> +				     enum power_supply_property psp,
>> +				     union power_supply_propval *val)
>> +{
>> +	struct ntxec_battery *priv = power_supply_get_drvdata(psy);
>> +	int ret;
>> +	unsigned int value;
>> +
>> +	switch (psp) {
>> +		case POWER_SUPPLY_PROP_VOLTAGE_NOW:
>> +			ret = regmap_read(priv->ec->regmap, NTXEC_REG_READ_BATTERY, &value);
>> +			if (ret < 0)
>> +				return ret;
>> +
>> +			/* ec value to microvolt conversion:
>> +			 * vendor kernel source suggests linear behaviour from 3V to 4.2V
>> +			 * with readings 767 to 1023; each increment represents 4687,5uV.
>> +			 * adjust 3V boundary slightly to report exactly 4.2V when full.
>> +			 */
>> +			val->intval = 2999872 + (value - 767) * 4688;
>> +			break;
>> +		default:
>> +			dev_err(&psy->dev, "%s: invalid property %u\n", __func__, psp);
>> +			return -EINVAL;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct power_supply_desc ntxec_battery_desc = {
>> +	.name = "ec-battery",
>> +	.type = POWER_SUPPLY_TYPE_BATTERY,
>> +	.properties = ntxec_battery_properties,
>> +	.get_property = ntxec_battery_get_property,
>> +	.num_properties = ARRAY_SIZE(ntxec_battery_properties),
>> +};
>> +
>> +static int ntxec_battery_probe(struct platform_device *pdev)
>> +{
>> +	struct device *dev = &pdev->dev;
>> +	struct ntxec *ec = dev_get_drvdata(dev->parent);
>> +	struct power_supply_config psy_cfg = {};
>> +	struct ntxec_battery *priv;
>> +	struct power_supply *psy;
>> +
>> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
>> +	if (!priv)
>> +		return -ENOMEM;
>> +
>> +	priv->ec = ec;
>> +	psy_cfg.drv_data = priv;
>> +	psy_cfg.fwnode = dev_fwnode(dev->parent);
>> +	psy_cfg.no_wakeup_source = true;
>> +	psy = devm_power_supply_register(dev, &ntxec_battery_desc, &psy_cfg);
>> +	if (IS_ERR(psy))
>> +		return PTR_ERR(psy);
>> +
>> +	return 0;
>> +}
>> +
>> +static struct platform_driver ntxec_battery_driver = {
>> +	.driver = {
>> +		.name = "ntxec-battery",
>> +	},
>> +	.probe = ntxec_battery_probe,
>> +};
>> +module_platform_driver(ntxec_battery_driver);
>> +
>> +MODULE_AUTHOR("Josua Mayer <josua.mayer at jm0.eu>");
>> +MODULE_DESCRIPTION("Battery driver for Netronix EC");
>> +MODULE_LICENSE("GPL");
>> +MODULE_ALIAS("platform:ntxec-battery");
> 
> Thanks,
> J. Neusch?fer



From christianshewitt at gmail.com  Mon Dec 29 03:15:14 2025
From: christianshewitt at gmail.com (Christian Hewitt)
Date: Mon, 29 Dec 2025 15:15:14 +0400
Subject: [PATCH RFC v1] drm/meson: venc: add support for HDMI DMT modes up
 to 3840x2160
In-Reply-To: <20251108134236.1299630-1-martin.blumenstingl@googlemail.com>
References: <20251108134236.1299630-1-martin.blumenstingl@googlemail.com>
Message-ID: <A9CFD913-A6AD-4078-90C2-C1E46EF5E74D@gmail.com>

> On 8 Nov 2025, at 5:42?pm, Martin Blumenstingl <martin.blumenstingl at googlemail.com> wrote:
> 
> Commit 5d0bfe448481 ("drm/meson: Add HDMI 1.4 4k modes") added support
> for HDMI 1.4 4k modes, which is what TVs need. For computer monitors
> the code is using the DMT code-path, which ends up in
> meson_venc_hdmi_supported_mode(), which does not allow the 4k modes yet.
> 
> The datasheet for all supported SoCs mentions "4Kx2K at 60". It's not
> clear whether "4K" here means 3840 or 4096 pixels.
> 
> Allow resolutions up to 3840x2160 pixels (including middle steps, such
> as WQHD at 2560x1440 pixels) so they can be used with computer monitors
> (using the DMT code-path in the driver).
> 
> Signed-off-by: Martin Blumenstingl <martin.blumenstingl at googlemail.com>

This is not a TB to kernel standards, but it seems not many folk
have ultra-wide monitors so this is as good as it gets:

Tested-by: Khadas forum user with a VIM3 running patched 6.18 :)

https://forum.khadas.com/t/can-not-set-display-resolution-to-3440x1440-for-dell-monitor/26271/8

Christian

> ---
> I'm sending this as RFC as I'm hoping to get some comments on the
> "4Kx2K at 60" note from the datasheets.
> 
> I have tested it myself on a GXL Le Potato board using a computer
> monitor at 2560x1440 pixels.
> 
> This is the spiritual successor of a patch titled "drm/meson: add
> support for 2560x1440 resolution output" from [0]
> 
> [0] https://lore.kernel.org/linux-amlogic/20250927130239.825060-1-christianshewitt at gmail.com/
> 
> 
> drivers/gpu/drm/meson/meson_venc.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
> index 3bf0d6e4fc30..4abd0c09b442 100644
> --- a/drivers/gpu/drm/meson/meson_venc.c
> +++ b/drivers/gpu/drm/meson/meson_venc.c
> @@ -868,10 +868,10 @@ meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode)
>    DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC))
> return MODE_BAD;
> 
> - if (mode->hdisplay < 400 || mode->hdisplay > 1920)
> + if (mode->hdisplay < 400 || mode->hdisplay > 3840)
> return MODE_BAD_HVALUE;
> 
> - if (mode->vdisplay < 480 || mode->vdisplay > 1920)
> + if (mode->vdisplay < 480 || mode->vdisplay > 2160)
> return MODE_BAD_VVALUE;
> 
> return MODE_OK;
> -- 
> 2.51.2
> 



From thomas.weissschuh at linutronix.de  Mon Dec 29 03:16:10 2025
From: thomas.weissschuh at linutronix.de (Thomas =?utf-8?Q?Wei=C3=9Fschuh?=)
Date: Mon, 29 Dec 2025 12:16:10 +0100
Subject: [PATCH v8 4/6] kbuild: Support a MAKE_FIT_FLAGS environment
 variable
In-Reply-To: <20251227142200.2241198-5-sjg@chromium.org>
References: <20251227142200.2241198-1-sjg@chromium.org>
 <20251227142200.2241198-5-sjg@chromium.org>
Message-ID: <20251229121440-55a7d82a-6fd9-4875-9399-ab6b3ab05740@linutronix.de>

On Sat, Dec 27, 2025 at 07:21:48AM -0700, Simon Glass wrote:
> In some cases it is useful to be able to pass additional flags to the
> make_fit.py script. For example, since ramdisks are typically large,
> passing -E to use external data can be helpful.
> 
> Add a new MAKE_FIT_FLAGS variable for this.

The new variable's name is a bit inconsistent with the other ones.
I would have used `FIT_EXTRA_ARGUMENTS` or such.

> Signed-off-by: Simon Glass <sjg at chromium.org>

In any case:
Reviewed-by: Thomas Wei?schuh <thomas.weissschuh at linutronix.de>


From ulf.hansson at linaro.org  Mon Dec 29 03:49:01 2025
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Mon, 29 Dec 2025 12:49:01 +0100
Subject: [PATCH v2 2/2] pmdomain: add audio power island for Marvell
 PXA1908 SoC
In-Reply-To: <20251213084843.7491-2-balejk@matfyz.cz>
References: <20251213084843.7491-1-balejk@matfyz.cz> <20251213084843.7491-2-balejk@matfyz.cz>
Message-ID: <CAPDyKFrX45baw9ezWebF=sNHpaNtJYfvdTkghZYRWi2RfdGN_Q@mail.gmail.com>

On Sat, 13 Dec 2025 at 09:49, Karel Balej <balejk at matfyz.cz> wrote:
>
> Define power domain which needs to be enabled in order for audio to work
> on the PXA1908-based samsung,coreprimevelte smartphone. In the
> downstream code, this power-on method is marked as specific to the ULCx
> series which is allegedly a codename of sorts with ULC1 corresponding to
> the PXA1908.
>
> No other audio components needed for sound to work on this phone are
> currently available mainline but some successful testing was performed
> with the vendor variants of the respective drivers and with the domain
> forced always-on.
>
> Signed-off-by: Karel Balej <balejk at matfyz.cz>

Both patches applied for next, thanks!

Kind regards
Uffe


> ---
>
> Notes:
>     v2:
>     - APMU_AUD_CLK -> APMU_AUDIO_CLK and group it with other register
>       definitions. (Duje)
>     - Move default function exit path inside the switch. (Duje)
>     - Modify the commit message with information provided by Duje (thanks!).
>
>  .../marvell/pxa1908-power-controller.c        | 39 +++++++++++++++++--
>  1 file changed, 35 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/pmdomain/marvell/pxa1908-power-controller.c b/drivers/pmdomain/marvell/pxa1908-power-controller.c
> index ff5e6e82d3f8..543e8d33ac0c 100644
> --- a/drivers/pmdomain/marvell/pxa1908-power-controller.c
> +++ b/drivers/pmdomain/marvell/pxa1908-power-controller.c
> @@ -24,12 +24,15 @@
>  #define APMU_DEBUG             0x88
>  #define DSI_PHY_DVM_MASK       BIT(31)
>
> +#define APMU_AUDIO_CLK         0x80
> +#define AUDIO_ULCX_ENABLE      0x0d
> +
>  #define POWER_ON_LATENCY_US    300
>  #define POWER_OFF_LATENCY_US   20
>  #define POWER_POLL_TIMEOUT_US  (25 * USEC_PER_MSEC)
>  #define POWER_POLL_SLEEP_US    6
>
> -#define NR_DOMAINS     5
> +#define NR_DOMAINS     6
>
>  #define to_pxa1908_pd(_genpd) container_of(_genpd, struct pxa1908_pd, genpd)
>
> @@ -59,9 +62,14 @@ static inline bool pxa1908_pd_is_on(struct pxa1908_pd *pd)
>  {
>         struct pxa1908_pd_ctrl *ctrl = pd->ctrl;
>
> -       return pd->data.id != PXA1908_POWER_DOMAIN_DSI
> -               ? regmap_test_bits(ctrl->base, APMU_PWR_STATUS_REG, pd->data.pwr_state)
> -               : regmap_test_bits(ctrl->base, APMU_DEBUG, DSI_PHY_DVM_MASK);
> +       switch (pd->data.id) {
> +       case PXA1908_POWER_DOMAIN_AUDIO:
> +               return regmap_test_bits(ctrl->base, APMU_AUDIO_CLK, AUDIO_ULCX_ENABLE);
> +       case PXA1908_POWER_DOMAIN_DSI:
> +               return regmap_test_bits(ctrl->base, APMU_DEBUG, DSI_PHY_DVM_MASK);
> +       default:
> +               return regmap_test_bits(ctrl->base, APMU_PWR_STATUS_REG, pd->data.pwr_state);
> +       }
>  }
>
>  static int pxa1908_pd_power_on(struct generic_pm_domain *genpd)
> @@ -123,6 +131,22 @@ static inline int pxa1908_dsi_power_off(struct generic_pm_domain *genpd)
>         return regmap_clear_bits(ctrl->base, APMU_DEBUG, DSI_PHY_DVM_MASK);
>  }
>
> +static inline int pxa1908_audio_power_on(struct generic_pm_domain *genpd)
> +{
> +       struct pxa1908_pd *pd = to_pxa1908_pd(genpd);
> +       struct pxa1908_pd_ctrl *ctrl = pd->ctrl;
> +
> +       return regmap_set_bits(ctrl->base, APMU_AUDIO_CLK, AUDIO_ULCX_ENABLE);
> +}
> +
> +static inline int pxa1908_audio_power_off(struct generic_pm_domain *genpd)
> +{
> +       struct pxa1908_pd *pd = to_pxa1908_pd(genpd);
> +       struct pxa1908_pd_ctrl *ctrl = pd->ctrl;
> +
> +       return regmap_clear_bits(ctrl->base, APMU_AUDIO_CLK, AUDIO_ULCX_ENABLE);
> +}
> +
>  #define DOMAIN(_id, _name, ctrl, mode, state) \
>         [_id] = { \
>                 .data = { \
> @@ -159,6 +183,13 @@ static struct pxa1908_pd domains[NR_DOMAINS] = {
>                         .keep_on = true,
>                 },
>         },
> +       [PXA1908_POWER_DOMAIN_AUDIO] = {
> +               .genpd = {
> +                       .name = "audio",
> +                       .power_on = pxa1908_audio_power_on,
> +                       .power_off = pxa1908_audio_power_off,
> +               },
> +       },
>  };
>
>  static void pxa1908_pd_remove(struct auxiliary_device *auxdev)
> --
> 2.51.2
>


From ulf.hansson at linaro.org  Mon Dec 29 03:52:13 2025
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Mon, 29 Dec 2025 12:52:13 +0100
Subject: [PATCH v2 0/4] Make MT8196 get its Mali GPU shader_present from nvmem
In-Reply-To: <20251220-mt8196-shader-present-v2-0-45b1ff1dfab0@collabora.com>
References: <20251220-mt8196-shader-present-v2-0-45b1ff1dfab0@collabora.com>
Message-ID: <CAPDyKFqkPg5rWYk7cwDywRn_pexQhd2V3R63atjruJnSpYxfZQ@mail.gmail.com>

On Sat, 20 Dec 2025 at 19:50, Nicolas Frattaroli
<nicolas.frattaroli at collabora.com> wrote:
>
> The MediaTek MT8196 SoC's Mali SHADER_PRESENT register does not list
> only functional shader cores, but also those that are fused off to
> improve yield.
>
> The SHADER_PRESENT bitmask with the one fused off core omitted is to be
> found in an efuse. However, the efuse address is considered
> confidential, and is not public knowledge.
>
> The MT8196 GPUEB MCU, which does the power management for the Mali GPU
> on this SoC, knows and reads the efuse however, and exposes it in the
> shared memory intended to communicate state to the application
> processor. Reading the bitmask from this shared memory area is the
> vendor's intended solution.
>
> This series models this in the binding and implements it in the
> corresponding Linux drivers:
> - the mali-valhall-csf binding gets an nvmem-cells/nvmem-cell-names
>   property to declare that shader-present is in a different castle
> - the mt8196-gpufreq binding requires nodes to expose the shader-present
>   cell
> - panthor checks for the presence of the shader-present cell and uses it
>   as the shader-present value if it's found, instead of the Mali GPU
>   register contents
> - mtk-mfg-pmdomain becomes an nvmem provider and will happily serve
>   queries for the shader-present cell
>
> While it would be preferable if we could read the efuse directly, it's
> not possible as things stand, and insisting on it will just keep this
> hardware from working in mainline. Running a GPU workload with a
> SHADER_PRESENT bitmask that includes a faulty core results in corrupt
> GPU rendering output.
>
> Modelling the mt8196-gpufreq device as a nvmem-cell provider however is
> not lying about the hardware's capabilities, as it truly does provide
> access to the nvmem-cell, even if it acts as a proxy.
>
> From a bindings and panthor perspective, this is also generic enough to
> where hypothetical other vendors doing the same thing (even with direct
> efuse access) can rely on the same cell name and implementation.
>
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>

I have applied the pmdomain changes in patch2 and patch 4 for next, thanks!

I assume the gpu changes will be funneled via another tree, but let me
know if there is a reason to keep these changes together.

Kind regards
Uffe


> ---
> Changes in v2:
> - panthor: move to nvmem_cell_read_variable_le_u64
> - mtk-mfg-pmdomain: put of_node in error path
> - mtk-mfg-pmdomain: remove leftover stray of_node_put on NULL
> - Link to v1: https://lore.kernel.org/r/20251217-mt8196-shader-present-v1-0-f6f8f3aa1e93 at collabora.com
>
> ---
> Nicolas Frattaroli (4):
>       dt-bindings: gpu: mali-valhall-csf: Add shader-present nvmem cell
>       dt-bindings: power: mt8196-gpufreq: Describe nvmem provider ability
>       drm/panthor: Implement reading shader_present from nvmem
>       pmdomain: mediatek: mtk-mfg: Expose shader_present as nvmem cell
>
>  .../bindings/gpu/arm,mali-valhall-csf.yaml         | 14 +++++
>  .../bindings/power/mediatek,mt8196-gpufreq.yaml    | 13 +++++
>  drivers/gpu/drm/panthor/panthor_hw.c               | 36 ++++++++++---
>  drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c       | 59 ++++++++++++++++++++++
>  4 files changed, 116 insertions(+), 6 deletions(-)
> ---
> base-commit: 638148c6ffa31d2e4958d51708ff3675221e2da7
> change-id: 20251217-mt8196-shader-present-e2dc3f97fc74
>
> Best regards,
> --
> Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
>


From ahmed.tiba at arm.com  Mon Dec 29 03:54:36 2025
From: ahmed.tiba at arm.com (Ahmed Tiba)
Date: Mon, 29 Dec 2025 11:54:36 +0000
Subject: [PATCH 00/12] ras: share firmware-first estatus handling
In-Reply-To: <20251221013534.GAaUdO5vWqMWAdbWbd@renoirsky.local>
Message-ID: <20251229115440.2734800-1-ahmed.tiba@arm.com>


On Sun, Dec 21, 2025 at 02:35:34 +0100, Borislav Petkov wrote:
> On Wed, Dec 17, 2025 at 11:28:33AM +0000, Ahmed Tiba wrote:
>> Platforms that rely on firmware-first RAS today only get the full Linux
>> handling pipeline when the records arrive through ACPI/APEI GHES. This
>> series lifts the generic parts of GHES into a reusable estatus core, wires
>
> Why is this thing called "error status"?

By ?error status? I?m referring to the UEFI CPER Generic Error Status block,
which is the standard firmware-produced error payload that Linux already
consumes via GHES on ACPI systems. I?m not introducing a new error model
here; the intent is to reuse the existing CPER decoding and handling once
that payload exists.

> Why is error status so significant so that you need to call it a thing,
> much less a "core"?

The reason this shows up as a separate ?core? is that CPER parsing,
logging, and vendor dispatch are provider-agnostic once a Generic Error
Status block exists, independent of how it was discovered or notified.

> It looks like you basically want to dump error records from a system
> which doesn't support GHES into the common path so they get decoded?
>
> I mean, I'm only guessing because I don't get any wiser from this text.
>
> So how about you give the high-level, practical use spiel first? What's
> the use case?

The practical use case is firmware-first RAS platforms that emit CPER
records but do not use ACPI/APEI GHES for discovery or notification. Today,
those platforms either have to duplicate CPER parsing logic or miss out on
the common Linux RAS handling (standard logging, memory failure flow,
vendor notification paths). As a result, the full firmware-first RAS
pipeline effectively only works when CPER arrives through GHES.

GHES remains one transport for delivering CPER records, but this
series separates the transport from the decoding so that other firmware-
first providers can reuse the same handling without duplicating code or
depending on ACPI/APEI internals.

As far as I can tell from the scope of https://uefi.org/specifications,
the UEFI specifications don?t define a notification mechanism for
DeviceTree systems?only the ACPI/APEI path is spelled out. Right now the DT
transport is described solely by the binding in patch 9/12. If there?s a
better place to document or name this, I?d appreciate guidance
so it?s clear how firmware-first notification happens on DT outside ACPI.

Thanks,
Ahmed


From robert.marko at sartura.hr  Mon Dec 29 04:07:13 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Mon, 29 Dec 2025 13:07:13 +0100
Subject: [PATCH v3 01/15] include: dt-bindings: add LAN969x clock bindings
In-Reply-To: <20251227-splendid-striped-starfish-ece074@quoll>
References: <20251223201921.1332786-1-robert.marko@sartura.hr>
 <20251223201921.1332786-2-robert.marko@sartura.hr> <20251224-berserk-mackerel-of-snow-4cae54@quoll>
 <CA+HBbNGym6Q9b166n-P=h_JssOHm0yfyL73JZ+G9P81muK=g4A@mail.gmail.com>
 <78bf252c-fd5e-4a36-b1a3-ca8ed26fde7a@kernel.org> <CA+HBbNG+ZVD6grGDp32Ninx7H1AyEbGvP0nwc0zUv94tOV8hYg@mail.gmail.com>
 <d210552f-c8bf-4084-9317-b743075d9946@kernel.org> <2025122516245554f59e2e@mail.local>
 <20251227-splendid-striped-starfish-ece074@quoll>
Message-ID: <CA+HBbNEqq9ZqBR88DFSSSrYw=LBzAreFC0kL88-HZCGAsOrqZw@mail.gmail.com>

On Sat, Dec 27, 2025 at 12:17?PM Krzysztof Kozlowski <krzk at kernel.org> wrote:
>
> On Thu, Dec 25, 2025 at 05:24:55PM +0100, Alexandre Belloni wrote:
> > On 25/12/2025 09:47:34+0100, Krzysztof Kozlowski wrote:
> > > On 24/12/2025 15:01, Robert Marko wrote:
> > > > On Wed, Dec 24, 2025 at 2:05?PM Krzysztof Kozlowski <krzk at kernel.org> wrote:
> > > >>
> > > >> On 24/12/2025 11:30, Robert Marko wrote:
> > > >>> On Wed, Dec 24, 2025 at 11:21?AM Krzysztof Kozlowski <krzk at kernel.org> wrote:
> > > >>>>
> > > >>>> On Tue, Dec 23, 2025 at 09:16:12PM +0100, Robert Marko wrote:
> > > >>>>> Add the required LAN969x clock bindings.
> > > >>>>
> > > >>>> I do not see clock bindings actually here. Where is the actual binding?
> > > >>>> Commit msg does not help me at all to understand why you are doing this
> > > >>>> without actual required bindings.
> > > >>>
> > > >>> I guess it is a bit confusing, there is no schema here, these are the
> > > >>> clock indexes that
> > > >>> reside in dt-bindings and are used by the SoC DTSI.
> > > >>
> > > >> I understand as not used by drivers? Then no ABI and there is no point
> > > >> in putting them into bindings.
> > > >
> > > > It is not included by the driver directly, but it requires these exact
> > > > indexes to be passed
> > > > so its effectively ABI.
> > >
> > > How it requires the exact index? In what way? I do not see anything in
> > > the gck driver using/relying on these values. Nothing. Please point me
> > > to the line which directly uses these values.... or how many times I
> > > will need to write this is not ABI?
> > >
> >
> > The index here is the exact id that needs to be set in the PMC_PCR
> > register and so it is dictated by the hardware.
>
> So not a binding between Linux and DTS.
>

What would be your suggestion on moving forwarding regarding the clock
HW indexes?

LAN966x does the same with HW clock indexes in the dt-bindings includes.

Regards,
Robert

> Best regards,
> Krzysztof
>


-- 
Robert Marko
Staff Embedded Linux Engineer
Sartura d.d.
Lendavska ulica 16a
10000 Zagreb, Croatia
Email: robert.marko at sartura.hr
Web: www.sartura.hr


From shawnguo at kernel.org  Mon Dec 29 04:18:33 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Mon, 29 Dec 2025 20:18:33 +0800
Subject: [PATCH v2] arm64: dts: imx943-evk: add flexcan support
In-Reply-To: <20251119-dts-v2-1-e8f8d91280dd@nxp.com>
References: <20251119-dts-v2-1-e8f8d91280dd@nxp.com>
Message-ID: <aVJxmWaSgG1-dEdo@dragon>

On Wed, Nov 19, 2025 at 11:34:18AM +0800, Haibo Chen wrote:
> Add flexcan2 and flexcan4, and related phys support.
> 
> Signed-off-by: Haibo Chen <haibo.chen at nxp.com>

Applied, thanks!


From shawnguo at kernel.org  Mon Dec 29 04:43:47 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Mon, 29 Dec 2025 20:43:47 +0800
Subject: [PATCH 1/1] arm64: dts: mba8xx: replace 0 with IMX_LPCG_CLK_0
 for lpcg indices
In-Reply-To: <20251120214318.347483-1-Frank.Li@nxp.com>
References: <20251120214318.347483-1-Frank.Li@nxp.com>
Message-ID: <aVJ3g_V_xWStfGHi@dragon>

On Thu, Nov 20, 2025 at 04:43:18PM -0500, Frank Li wrote:
> Replace the 0 with IMX_LPCG_CLK_0 for LPCG clock indices. Although the
> numerical value is identical, the LPCG input is defined as
> IMX_LPCG_CLK_<n>, so using the symbolic constant improves clarity and
> consistency with the LPCG clock naming convention.
> 
> Signed-off-by: Frank Li <Frank.Li at nxp.com>

Applied, thanks!


From shawnguo at kernel.org  Mon Dec 29 04:45:39 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Mon, 29 Dec 2025 20:45:39 +0800
Subject: [PATCH v2 1/1] arm64: dts: imx8qxp-mek: Add sensors under i2c1
 bus
In-Reply-To: <20251120215350.352117-1-Frank.Li@nxp.com>
References: <20251120215350.352117-1-Frank.Li@nxp.com>
Message-ID: <aVJ3895nxmH_M8au@dragon>

On Thu, Nov 20, 2025 at 04:53:50PM -0500, Frank Li wrote:
> Add sensors under i2c1 bus.
> 
> Signed-off-by: Frank Li <Frank.Li at nxp.com>

Applied, thanks!


From krzk at kernel.org  Mon Dec 29 04:46:06 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 29 Dec 2025 13:46:06 +0100
Subject: [PATCH v3 01/15] include: dt-bindings: add LAN969x clock bindings
In-Reply-To: <CA+HBbNEqq9ZqBR88DFSSSrYw=LBzAreFC0kL88-HZCGAsOrqZw@mail.gmail.com>
References: <20251223201921.1332786-1-robert.marko@sartura.hr>
 <20251223201921.1332786-2-robert.marko@sartura.hr>
 <20251224-berserk-mackerel-of-snow-4cae54@quoll>
 <CA+HBbNGym6Q9b166n-P=h_JssOHm0yfyL73JZ+G9P81muK=g4A@mail.gmail.com>
 <78bf252c-fd5e-4a36-b1a3-ca8ed26fde7a@kernel.org>
 <CA+HBbNG+ZVD6grGDp32Ninx7H1AyEbGvP0nwc0zUv94tOV8hYg@mail.gmail.com>
 <d210552f-c8bf-4084-9317-b743075d9946@kernel.org>
 <2025122516245554f59e2e@mail.local>
 <20251227-splendid-striped-starfish-ece074@quoll>
 <CA+HBbNEqq9ZqBR88DFSSSrYw=LBzAreFC0kL88-HZCGAsOrqZw@mail.gmail.com>
Message-ID: <756ead5d-8c9b-480d-8ae5-71667575ab7c@kernel.org>

On 29/12/2025 13:07, Robert Marko wrote:
>>>>>> I understand as not used by drivers? Then no ABI and there is no point
>>>>>> in putting them into bindings.
>>>>>
>>>>> It is not included by the driver directly, but it requires these exact
>>>>> indexes to be passed
>>>>> so its effectively ABI.
>>>>
>>>> How it requires the exact index? In what way? I do not see anything in
>>>> the gck driver using/relying on these values. Nothing. Please point me
>>>> to the line which directly uses these values.... or how many times I
>>>> will need to write this is not ABI?
>>>>
>>>
>>> The index here is the exact id that needs to be set in the PMC_PCR
>>> register and so it is dictated by the hardware.
>>
>> So not a binding between Linux and DTS.
>>
> 
> What would be your suggestion on moving forwarding regarding the clock
> HW indexes?

The same as for every other hardware constant, like interrupts,
registers and addresses - you use the value directly.

If you want nicer names, we moved them to DTS headers for several
platforms (see several commits in the past).

Best regards,
Krzysztof


From shawnguo at kernel.org  Mon Dec 29 04:47:27 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Mon, 29 Dec 2025 20:47:27 +0800
Subject: [PATCH 1/2] arm64: dts: tqma8xxs: replace 0 with IMX_LPCG_CLK_0
 for lpcg indices
In-Reply-To: <20251121073142.3367642-1-alexander.stein@ew.tq-group.com>
References: <20251121073142.3367642-1-alexander.stein@ew.tq-group.com>
Message-ID: <aVJ4X5-Ra2W3hhQy@dragon>

On Fri, Nov 21, 2025 at 08:31:40AM +0100, Alexander Stein wrote:
> Replace the 0 with IMX_LPCG_CLK_0 for LPCG clock indices. Although the
> numerical value is identical, the LPCG input is defined as
> IMX_LPCG_CLK_<n>, so using the symbolic constant improves clarity and
> consistency with the LPCG clock naming convention.
> 
> Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>

Applied both, thanks!


From shawnguo at kernel.org  Mon Dec 29 04:59:19 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Mon, 29 Dec 2025 20:59:19 +0800
Subject: [PATCH v6 1/2] dt-bindings: arm: fsl: Add i.MX8MP FRDM board
In-Reply-To: <20251123181444.266030-1-rpimentel.silva@gmail.com>
References: <20251123181444.266030-1-rpimentel.silva@gmail.com>
Message-ID: <aVJ7JxBxsnEmrbSq@dragon>

On Sun, Nov 23, 2025 at 01:14:43PM -0500, Rogerio Pimentel wrote:
> Add device tree compatible string for the i.MX8MP FRDM board.
> 
> Acked-by: Conor Dooley <conor.dooley at microchip.com>
> Signed-off-by: Rogerio Pimentel <rpimentel.silva at gmail.com>

Applied both, thanks!


From shawnguo at kernel.org  Mon Dec 29 05:00:51 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Mon, 29 Dec 2025 21:00:51 +0800
Subject: [PATCH] arm64: dts: imx8mm: Add label to thermal-zones
In-Reply-To: <20251124092242.3378017-1-d.schultz@phytec.de>
References: <20251124092242.3378017-1-d.schultz@phytec.de>
Message-ID: <aVJ7g9bcilXJEbND@dragon>

On Mon, Nov 24, 2025 at 01:22:42AM -0800, Daniel Schultz wrote:
> Add 'thermal_zones' as a label to the thermal-zones node.
> 
> Without this label, it is not possible to add additional
> trip points in board files. For example, to add an active
> trip point for controlling a fan.
> 
> Signed-off-by: Daniel Schultz <d.schultz at phytec.de>

Applied, thanks!


From shawnguo at kernel.org  Mon Dec 29 05:06:28 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Mon, 29 Dec 2025 21:06:28 +0800
Subject: [PATCH v3] arm64: dts: imx943-evk: add flexcan support
In-Reply-To: <20251126-dts-v3-1-7545d957e795@nxp.com>
References: <20251126-dts-v3-1-7545d957e795@nxp.com>
Message-ID: <aVJ81FF64kmAgOOG@dragon>

On Wed, Nov 26, 2025 at 04:06:44PM +0800, Haibo Chen wrote:
> Add flexcan2 and flexcan4, and related phys support.
> 
> Signed-off-by: Haibo Chen <haibo.chen at nxp.com>

Applied v3 instead, thanks!


From shawnguo at kernel.org  Mon Dec 29 05:09:26 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Mon, 29 Dec 2025 21:09:26 +0800
Subject: [PATCH v6 5/5] arm64: dts: imx8ulp: add sim lpav node
In-Reply-To: <20251126124218.803-6-laurentiumihalcea111@gmail.com>
References: <20251126124218.803-1-laurentiumihalcea111@gmail.com>
 <20251126124218.803-6-laurentiumihalcea111@gmail.com>
Message-ID: <aVJ9hngpYQg5c123@dragon>

On Wed, Nov 26, 2025 at 04:42:18AM -0800, Laurentiu Mihalcea wrote:
> From: Laurentiu Mihalcea <laurentiu.mihalcea at nxp.com>
> 
> Add DT node for the SIM LPAV module.
> 
> Reviewed-by: Daniel Baluta <daniel.baluta at nxp.com>
> Reviewed-by: Frank Li <Frank.Li at nxp.com>
> Signed-off-by: Laurentiu Mihalcea <laurentiu.mihalcea at nxp.com>

Applied, thanks!


From konrad.dybcio at oss.qualcomm.com  Mon Dec 29 05:09:55 2025
From: konrad.dybcio at oss.qualcomm.com (Konrad Dybcio)
Date: Mon, 29 Dec 2025 14:09:55 +0100
Subject: [PATCH v8 5/5] arm64: dts: qcom: monaco-evk-camera: Add DT
 overlay
In-Reply-To: <20251222095914.1995041-6-quic_nihalkum@quicinc.com>
References: <20251222095914.1995041-1-quic_nihalkum@quicinc.com>
 <20251222095914.1995041-6-quic_nihalkum@quicinc.com>
Message-ID: <47cfbdbe-1b73-4fbb-aa55-fd1b29ddbb18@oss.qualcomm.com>

On 12/22/25 10:59 AM, Nihal Kumar Gupta wrote:
> Monaco EVK board does not include a camera sensor in its default hardware
> configuration. Introducing a device tree overlay to support optional
> integration of the IMX577 sensor via CSIPHY1.
> 
> Camera reset is handled through an I2C expander, and power is enabled
> via TLMM GPIO74.
> 
> An example media-ctl pipeline for the imx577 is:
> 
> media-ctl --reset
> media-ctl -V '"imx577 3-001a":0[fmt:SRGGB10/4056x3040 field:none]'
> media-ctl -V '"msm_csiphy1":0[fmt:SRGGB10/4056x3040]'
> media-ctl -V '"msm_csid0":0[fmt:SRGGB10/4056x3040]'
> media-ctl -V '"msm_vfe0_rdi0":0[fmt:SRGGB10/4056x3040]'
> media-ctl -l '"msm_csiphy1":1->"msm_csid0":0[1]'
> media-ctl -l '"msm_csid0":1->"msm_vfe0_rdi0":0[1]'
> yavta -B capture-mplane -c -I -n 5 -f SRGGB10P -s 4056x3040 -F /dev/video1
> 
> Signed-off-by: Nihal Kumar Gupta <quic_nihalkum at quicinc.com>
> Co-developed-by: Ravi Shankar <quic_rshankar at quicinc.com>
> Signed-off-by: Ravi Shankar <quic_rshankar at quicinc.com>
> Co-developed-by: Vishal Verma <quic_vishverm at quicinc.com>
> Signed-off-by: Vishal Verma <quic_vishverm at quicinc.com>
> Signed-off-by: Vikram Sharma <quic_vikramsa at quicinc.com>
> Reviewed-by: Vladimir Zapolskiy <vladimir.zapolskiy at linaro.org>
> Reviewed-by: Bryan O'Donoghue <bryan.odonoghue at linaro.org>
> ---

Reviewed-by: Konrad Dybcio <konrad.dybcio at oss.qualcomm.com>

Konrad


From shawnguo at kernel.org  Mon Dec 29 05:12:00 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Mon, 29 Dec 2025 21:12:00 +0800
Subject: [PATCH] ARM: multi_v7_defconfig: enable DA9052 and MC13XXX
In-Reply-To: <20251128-imx53-qsrb-pmics-v1-1-a96f43ddbb59@oss.qualcomm.com>
References: <20251128-imx53-qsrb-pmics-v1-1-a96f43ddbb59@oss.qualcomm.com>
Message-ID: <aVJ-IGz9YZajTzaP@dragon>

On Fri, Nov 28, 2025 at 06:02:42AM +0200, Dmitry Baryshkov wrote:
> Enable PMICs used on i.MX53 Quick-Start Boards: DA9052 for i.MX53 QSB
> and MC13XXX for i.MX53 QSRB (it has Freescale MC34708 PMIC).
> 
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>

Applied, thanks!


From shawnguo at kernel.org  Mon Dec 29 05:14:02 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Mon, 29 Dec 2025 21:14:02 +0800
Subject: [PATCH v1 0/2] arm64: dts: imx95-toradex-smarc: Fix ethphy1
 interrupt and GPIO labels
In-Reply-To: <20251128150030.35931-1-ivitro@gmail.com>
References: <20251128150030.35931-1-ivitro@gmail.com>
Message-ID: <aVJ-mpr3bHw2Dmv8@dragon>

On Fri, Nov 28, 2025 at 03:00:26PM +0000, Vitor Soares wrote:
> From: Vitor Soares <vitor.soares at toradex.com>
> 
> This series fixes the ethphy1 interrupt configuration and corrects GPIO
> expander line names for the i.MX95 Toradex SMARC.
> 
> The first patch changes the interrupt trigger type from level-triggered
> to edge-triggered to match the PCA9745 GPIO expander hardware
> capabilities.
> 
> The second patch fixes the SMARC_SDIO_WP gpio-line-name position to
> line 15.
> 
> Vitor Soares (2):
>   arm64: dts: freescale: imx95-toradex-smarc: use edge trigger for
>     ethphy1 interrupt
>   arm64: dts: freescale: imx95-toradex-smarc: fix SMARC_SDIO_WP label
>     position

Applied both, thanks!


From shawnguo at kernel.org  Mon Dec 29 05:17:13 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Mon, 29 Dec 2025 21:17:13 +0800
Subject: [PATCH 0/2] arm64: dts: imx93-14x14-evk: Add bt-sco and audio
 XCVR sound cards
In-Reply-To: <20251201065844.3823323-1-chancel.liu@nxp.com>
References: <20251201065844.3823323-1-chancel.liu@nxp.com>
Message-ID: <aVJ_WYf23l93i65y@dragon>

On Mon, Dec 01, 2025 at 03:58:42PM +0900, Chancel Liu wrote:
> Add bt-sco and audio XCVR sound cards
> 
> Chancel Liu (2):
>   arm64: dts: imx93-14x14-evk: Add bt-sco sound card support
>   arm64: dts: imx93-14x14-evk: Add audio XCVR sound card

Applied both, thanks!


From zilin at seu.edu.cn  Mon Dec 29 05:17:12 2025
From: zilin at seu.edu.cn (Zilin Guan)
Date: Mon, 29 Dec 2025 13:17:12 +0000
Subject: [PATCH v2] soc: mediatek: svs: Fix memory leak in svs_enable_debug_write()
In-Reply-To: <1d9b46ba-728e-459a-9d82-0f49e2fe08b9@web.de>
References: <1d9b46ba-728e-459a-9d82-0f49e2fe08b9@web.de>
Message-ID: <20251229131712.388207-1-zilin@seu.edu.cn>

On Mon, Dec 29, 2025 at 09:19:19AM +0100, Markus Elfring wrote:
> ?
> > +++ b/drivers/soc/mediatek/mtk-svs.c
> > @@ -789,7 +789,7 @@ static ssize_t svs_enable_debug_write(struct file *filp,
> >  	struct svs_bank *svsb = file_inode(filp)->i_private;
> >  	struct svs_platform *svsp = dev_get_drvdata(svsb->dev);
> >  	int enabled, ret;
> > -	char *buf = NULL;
> > +	char *buf __free(kfree) = NULL;
> >  
> >  	if (count >= PAGE_SIZE)
> >  		return -EINVAL;
> ?
> 
> You may reduce the scopes for involved local variables,
> don't you?

Thanks for your suggestion. I will reduce the scope of the local variables 
in v3.

> See also:
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/submitting-patches.rst?h=v6.19-rc3#n262
> 
> Regards,
> Markus

Thanks, I will add your suggested Cc tag in v3.

Regards,
Zilin Guan


From zilin at seu.edu.cn  Mon Dec 29 05:25:26 2025
From: zilin at seu.edu.cn (Zilin Guan)
Date: Mon, 29 Dec 2025 13:25:26 +0000
Subject: [PATCH v3] soc: mediatek: svs: Fix memory leak in svs_enable_debug_write()
Message-ID: <20251229132526.394235-1-zilin@seu.edu.cn>

In svs_enable_debug_write(), the buf allocated by memdup_user_nul()
is leaked if kstrtoint() fails.

Fix this by using __free(kfree) to automatically free buf, eliminating
the need for explicit kfree() calls and preventing leaks.

Fixes: 13f1bbcfb582 ("soc: mediatek: SVS: add debug commands")
Cc: stable at vger.kernel.org
Co-developed-by: Jianhao Xu <jianhao.xu at seu.edu.cn>
Signed-off-by: Jianhao Xu <jianhao.xu at seu.edu.cn>
Signed-off-by: Zilin Guan <zilin at seu.edu.cn>
---
Changes in v3:
- Reduce the scope of the involved local variable.
- Add Cc to stable.

Changes in v2:
- Use __free(kfree) to simplify memory management.

 drivers/soc/mediatek/mtk-svs.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c
index f45537546553..475926a606fd 100644
--- a/drivers/soc/mediatek/mtk-svs.c
+++ b/drivers/soc/mediatek/mtk-svs.c
@@ -789,12 +789,11 @@ static ssize_t svs_enable_debug_write(struct file *filp,
 	struct svs_bank *svsb = file_inode(filp)->i_private;
 	struct svs_platform *svsp = dev_get_drvdata(svsb->dev);
 	int enabled, ret;
-	char *buf = NULL;
 
 	if (count >= PAGE_SIZE)
 		return -EINVAL;
 
-	buf = (char *)memdup_user_nul(buffer, count);
+	char *buf __free(kfree) = (char *)memdup_user_nul(buffer, count);
 	if (IS_ERR(buf))
 		return PTR_ERR(buf);
 
@@ -807,8 +806,6 @@ static ssize_t svs_enable_debug_write(struct file *filp,
 		svsb->mode_support = SVSB_MODE_ALL_DISABLE;
 	}
 
-	kfree(buf);
-
 	return count;
 }
 
-- 
2.34.1



From wbg at kernel.org  Mon Dec 29 05:50:01 2025
From: wbg at kernel.org (William Breathitt Gray)
Date: Mon, 29 Dec 2025 22:50:01 +0900
Subject: [PATCH v3 3/3] counter: Add STM based counter
In-Reply-To: <ba28863a-a5fe-498f-92a0-d71c356e7189@linaro.org>
Message-ID: <20251229135006.10133-1-wbg@kernel.org>

On Sun, Dec 28, 2025 at 06:37:22PM +0100, Daniel Lezcano wrote:
> 
> Hi William,
> 
> On 12/28/25 07:52, William Breathitt Gray wrote:
> > On Wed, Dec 17, 2025 at 08:49:57AM +0100, Daniel Lezcano wrote:
> >> The NXP S32G2 automotive platform integrates four Cortex-A53 cores and
> >> three Cortex-M7 cores, along with a large number of timers and
> >> counters. These hardware blocks can be used as clocksources or
> >> clockevents, or as timestamp counters shared across the various
> >> subsystems running alongside the Linux kernel, such as firmware
> >> components. Their actual usage depends on the overall platform
> >> software design.
> >>
> >> In a Linux-based system, the kernel controls the counter, which is a
> >> read-only shared resource for the other subsystems. One of its primary
> >> purposes is to act as a common timestamp source for messages or
> >> traces, allowing correlation of events occurring in different
> >> operating system contexts.
> >>
> >> These changes introduce a basic counter driver that can start, stop,
> >> and reset the counter. It also handles overflow accounting and
> >> configures the prescaler value.
> >>
> >> Signed-off-by: Daniel Lezcano <daniel.lezcano at linaro.org>
> >
> > Hi Daniel,
> >
> > It sounds like you're trying to implement a clock for timestamping.
> 
> Well no, it is a counter which is used for timestamping. It is an
> automotive design.

I'm sorry, I misunderstood your device earlier. We'll continue with the
Counter driver implementation in that case.

> > Regardless, if you do pursue a Counter driver you'll need to follow the
> > Generic Counter paradigm[^1] and define at least three core components:
> > a Signal, a Synapse, and a Count. Resetting the Count is typically
> > implemented by defining a struct counter_ops counter_write()

Oops, I should have written count_write() there; when a user sets the
Count back to 0, it can be considered a reset.

> > callback[^2], while overflows are typically implemented by pushing
> > COUNTER_EVENT_OVERFLOW Counter events[^3] that can be watched by
> > userspace.
> 
> Yes, I think the Generic counter makes sense here for the goal to be
> achieved. Thanks for the pointers, I'll see how the counter fits with
> the paradigm.
> 
>    -- Daniel

I suspect you'll define a Signal after the peripheral clock input to the
counter device block; if it's possible to read the instataneous level of
this signal, define a signal_read() callback for it.

Your Synapse action is dependent on the edge sensitivity (i.e. rising,
falling, or both edges) of your counter device; e.g. a rising edge
configuration corresponds to a COUNTER_SYNAPSE_ACTION_RISING_EDGE action
in action_read(). If your counter only ever increases, then you can
report a COUNTER_FUNCTION_INCREASE function in the function_read()
callback.

Finally, the component names should be intuitive so give the Count a
more intuitive name than "stm-cnt". The same idea applies to the name
you give the Signal.

William Breathitt Gray


From leon at kernel.org  Mon Dec 29 06:40:12 2025
From: leon at kernel.org (Leon Romanovsky)
Date: Mon, 29 Dec 2025 16:40:12 +0200
Subject: [PATCH v2 4/8] dma-mapping: Separate DMA sync issuing and
 completion waiting
In-Reply-To: <CAGsJ_4y=yoYZn+_ztdfuOCj_dS-M0h8YWO51AXubPbeR1FH6uQ@mail.gmail.com>
References: <20251226225254.46197-1-21cnbao@gmail.com>
 <20251226225254.46197-5-21cnbao@gmail.com>
 <20251227200706.GN11869@unreal>
 <CAGsJ_4zyascnpQ1cB-BMO9PDeeRZTBAh8Z-j-ip=RcxApa4zSg@mail.gmail.com>
 <20251228144909.GR11869@unreal>
 <CAGsJ_4y=yoYZn+_ztdfuOCj_dS-M0h8YWO51AXubPbeR1FH6uQ@mail.gmail.com>
Message-ID: <20251229144012.GT11869@unreal>

On Mon, Dec 29, 2025 at 10:38:26AM +1300, Barry Song wrote:
> On Mon, Dec 29, 2025 at 3:49?AM Leon Romanovsky <leon at kernel.org> wrote:
> >
> > On Sun, Dec 28, 2025 at 10:45:13AM +1300, Barry Song wrote:
> > > On Sun, Dec 28, 2025 at 9:07?AM Leon Romanovsky <leon at kernel.org> wrote:
> > > >
> > > > On Sat, Dec 27, 2025 at 11:52:44AM +1300, Barry Song wrote:
> > > > > From: Barry Song <baohua at kernel.org>
> > > > >
> > > > > Currently, arch_sync_dma_for_cpu and arch_sync_dma_for_device
> > > > > always wait for the completion of each DMA buffer. That is,
> > > > > issuing the DMA sync and waiting for completion is done in a
> > > > > single API call.
> > > > >
> > > > > For scatter-gather lists with multiple entries, this means
> > > > > issuing and waiting is repeated for each entry, which can hurt
> > > > > performance. Architectures like ARM64 may be able to issue all
> > > > > DMA sync operations for all entries first and then wait for
> > > > > completion together.
> > > > >
> > > > > To address this, arch_sync_dma_for_* now issues DMA operations in
> > > > > batch, followed by a flush. On ARM64, the flush is implemented
> > > > > using a dsb instruction within arch_sync_dma_flush().
> > > > >
> > > > > For now, add arch_sync_dma_flush() after each
> > > > > arch_sync_dma_for_*() call. arch_sync_dma_flush() is defined as a
> > > > > no-op on all architectures except arm64, so this patch does not
> > > > > change existing behavior. Subsequent patches will introduce true
> > > > > batching for SG DMA buffers.
> > > > >
> > > > > Cc: Leon Romanovsky <leon at kernel.org>
> > > > > Cc: Catalin Marinas <catalin.marinas at arm.com>
> > > > > Cc: Will Deacon <will at kernel.org>
> > > > > Cc: Marek Szyprowski <m.szyprowski at samsung.com>
> > > > > Cc: Robin Murphy <robin.murphy at arm.com>
> > > > > Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
> > > > > Cc: Ard Biesheuvel <ardb at kernel.org>
> > > > > Cc: Marc Zyngier <maz at kernel.org>
> > > > > Cc: Anshuman Khandual <anshuman.khandual at arm.com>
> > > > > Cc: Ryan Roberts <ryan.roberts at arm.com>
> > > > > Cc: Suren Baghdasaryan <surenb at google.com>
> > > > > Cc: Joerg Roedel <joro at 8bytes.org>
> > > > > Cc: Juergen Gross <jgross at suse.com>
> > > > > Cc: Stefano Stabellini <sstabellini at kernel.org>
> > > > > Cc: Oleksandr Tyshchenko <oleksandr_tyshchenko at epam.com>
> > > > > Cc: Tangquan Zheng <zhengtangquan at oppo.com>
> > > > > Signed-off-by: Barry Song <baohua at kernel.org>
> > > > > ---
> > > > >  arch/arm64/include/asm/cache.h |  6 ++++++
> > > > >  arch/arm64/mm/dma-mapping.c    |  4 ++--
> > > > >  drivers/iommu/dma-iommu.c      | 37 +++++++++++++++++++++++++---------
> > > > >  drivers/xen/swiotlb-xen.c      | 24 ++++++++++++++--------
> > > > >  include/linux/dma-map-ops.h    |  6 ++++++
> > > > >  kernel/dma/direct.c            |  8 ++++++--
> > > > >  kernel/dma/direct.h            |  9 +++++++--
> > > > >  kernel/dma/swiotlb.c           |  4 +++-
> > > > >  8 files changed, 73 insertions(+), 25 deletions(-)
> > > >
> > > > <...>
> > > >
> > > > > +#ifndef arch_sync_dma_flush
> > > > > +static inline void arch_sync_dma_flush(void)
> > > > > +{
> > > > > +}
> > > > > +#endif
> > > >
> > > > Over the weekend I realized a useful advantage of the ARCH_HAVE_* config
> > > > options: they make it straightforward to inspect the entire DMA path simply
> > > > by looking at the .config.
> > >
> > > I am not quite sure how much this benefits users, as the same
> > > information could also be obtained by grepping for
> > > #define arch_sync_dma_flush in the source code.
> >
> > It differs slightly. Users no longer need to grep around or guess whether this
> > platform used the arch_sync_dma_flush path. A simple grep for ARCH_HAVE_ in
> > /proc/config.gz provides the answer.
> 
> In any case, it is only two or three lines of code, so I am fine with
> either approach. Perhaps Marek, Robin, and others have a point here?
> 
> >
> > >
> > > >
> > > > Thanks,
> > > > Reviewed-by: Leon Romanovsky <leonro at nvidia.com>
> > >
> > > Thanks very much, Leon, for reviewing this over the weekend. One thing
> > > you might have missed is that I place arch_sync_dma_flush() after all
> > > arch_sync_dma_for_*() calls, for both single and sg cases. I also
> > > used a Python script to scan the code and verify that every
> > > arch_sync_dma_for_*() is followed by arch_sync_dma_flush(), to ensure
> > > that no call is left out.
> > >
> > > In the subsequent patches, for sg cases, the per-entry flush is
> > > replaced by a single flush of the entire sg. Each sg case has
> > > different characteristics: some are straightforward, while others
> > > can be tricky and involve additional contexts.
> >
> > I didn't overlook it, and I understand your rationale. However, this is
> > not how kernel patches should be structured. You should not introduce
> > code in patch X and then move it elsewhere in patch X + Y.
> 
> I am not quite convinced by this concern. This patch only
> separates DMA sync issuing from completion waiting, and it
> reflects that the development is done step by step.
> 
> >
> > Place the code in the correct location from the start. Your patches are
> > small enough to review as is.
> 
> My point is that this patch places the code in the correct locations
> from the start. It splits arch_sync_dma_for_*() into
> arch_sync_dma_for_*() plus arch_sync_dma_flush() everywhere, without
> introducing any functional changes from the outset.
> The subsequent patches clearly show which parts are truly batched.
> 
> In the meantime, I do not have a strong preference here. If you think
> it is better to move some of the straightforward batching code here,
> I can follow that approach. Perhaps I could move patch 5, patch 8,
> and the iommu_dma_iova_unlink_range_slow change from patch 7 here,
> while keeping
> 
>   [PATCH 6] dma-mapping: Support batch mode for
>   dma_direct_{map,unmap}_sg
> 
> and the IOVA link part from patch 7 as separate patches, since that
> part is not straightforward. The IOVA link changes affect both
> __dma_iova_link() and dma_iova_sync(), which are two separate
> functions and require a deeper understanding of the contexts to
> determine correctness. That part also lacks testing.

Don't worry about testing. NVME, RDMA and GPU are using this path
and someone will test it.

> 
> Would that be okay with you?

I don't know, need to see the code.

Thanks

> 
> Thanks
> Barry


From nandor.han at gehealthcare.com  Mon Dec 29 06:49:58 2025
From: nandor.han at gehealthcare.com (Nandor Han)
Date: Mon, 29 Dec 2025 16:49:58 +0200
Subject: [PATCH 0/2] watchdog: imx2_wdt: Allow to run in low power mode
Message-ID: <20251229145000.421426-1-nandor.han@gehealthcare.com>

Description
-----------
Add the possibility for the user to allow the configuration of watchdog
in low power mode.

Testing
-------
It was verified on a i.MX7D based system that once enabled the watchdog
will reset the device when the system enter in low power mode.

Nandor Han (2):
  watchdog: imx2_wdt: Allow to continue in low power mode
  dt-bindings: watchdog: fsl-imx: document continue in low power mode

 .../devicetree/bindings/watchdog/fsl-imx-wdt.yaml          | 6 ++++++
 drivers/watchdog/imx2_wdt.c                                | 7 ++++++-
 2 files changed, 12 insertions(+), 1 deletion(-)

-- 
2.39.5



From nandor.han at gehealthcare.com  Mon Dec 29 06:50:00 2025
From: nandor.han at gehealthcare.com (Nandor Han)
Date: Mon, 29 Dec 2025 16:50:00 +0200
Subject: [PATCH 2/2] dt-bindings: watchdog: fsl-imx: document continue in low power mode
In-Reply-To: <20251229145000.421426-1-nandor.han@gehealthcare.com>
References: <20251229145000.421426-1-nandor.han@gehealthcare.com>
Message-ID: <20251229145000.421426-3-nandor.han@gehealthcare.com>

Property "fsl,wdt-continue-in-low-power" allows the watchdog to continue
running in low power modes (STOP and DOZE). By default, the watchdog is
suspended in these modes. This property provides the option to keep the
watchdog active during low power states when needed.

Signed-off-by: Nandor Han <nandor.han at gehealthcare.com>
---
 Documentation/devicetree/bindings/watchdog/fsl-imx-wdt.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/watchdog/fsl-imx-wdt.yaml b/Documentation/devicetree/bindings/watchdog/fsl-imx-wdt.yaml
index 34951783a633..4dd9cc81c926 100644
--- a/Documentation/devicetree/bindings/watchdog/fsl-imx-wdt.yaml
+++ b/Documentation/devicetree/bindings/watchdog/fsl-imx-wdt.yaml
@@ -64,6 +64,12 @@ properties:
       If present, the watchdog device is suspended in WAIT mode
       (Suspend-to-Idle). Only supported on certain devices.
 
+  fsl,wdt-continue-in-low-power:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description: |
+      If present, the watchdog device continues to run in low power modes
+      (STOP and DOZE). By default, the watchdog is suspended in these modes.
+
 required:
   - compatible
   - interrupts
-- 
2.39.5



From nandor.han at gehealthcare.com  Mon Dec 29 06:49:59 2025
From: nandor.han at gehealthcare.com (Nandor Han)
Date: Mon, 29 Dec 2025 16:49:59 +0200
Subject: [PATCH 1/2] watchdog: imx2_wdt: Allow to continue in low power mode
In-Reply-To: <20251229145000.421426-1-nandor.han@gehealthcare.com>
References: <20251229145000.421426-1-nandor.han@gehealthcare.com>
Message-ID: <20251229145000.421426-2-nandor.han@gehealthcare.com>

By default, the driver suspends the watchdog in low power modes (STOP
and DOZE). In some situations this is not desired.

Add the possibility to configure the continuation of the watchdog timer
in the above mentioned low power modes.

Note:
Please be advised that the difference between the variable name and the
device tree option has been intentionally selected to uphold the
prevailing driver functionality. This ensures that the watchdog remains
suspended by default in low power mode, while also facilitating a clear
and intelligible device tree option name.

Signed-off-by: Nandor Han <nandor.han at gehealthcare.com>
---
 drivers/watchdog/imx2_wdt.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c
index 4b3a192ee3e8..6e837cfc3c5a 100644
--- a/drivers/watchdog/imx2_wdt.c
+++ b/drivers/watchdog/imx2_wdt.c
@@ -71,6 +71,7 @@ struct imx2_wdt_device {
 	struct watchdog_device wdog;
 	const struct imx2_wdt_data *data;
 	bool ext_reset;
+	bool wdt_suspend_in_low_power;
 	bool clk_is_on;
 	bool no_ping;
 	bool sleep_wait;
@@ -135,7 +136,8 @@ static inline void imx2_wdt_setup(struct watchdog_device *wdog)
 	regmap_read(wdev->regmap, IMX2_WDT_WCR, &val);
 
 	/* Suspend timer in low power mode, write once-only */
-	val |= IMX2_WDT_WCR_WDZST;
+	if (wdev->wdt_suspend_in_low_power)
+		val |= IMX2_WDT_WCR_WDZST;
 	/* Suspend timer in low power WAIT mode, write once-only */
 	if (wdev->sleep_wait)
 		val |= IMX2_WDT_WCR_WDW;
@@ -326,6 +328,9 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
 	wdev->ext_reset = of_property_read_bool(dev->of_node,
 						"fsl,ext-reset-output");
 
+	wdev->wdt_suspend_in_low_power = !of_property_read_bool(dev->of_node,
+						"fsl,wdt-continue-in-low-power");
+
 	if (of_property_read_bool(dev->of_node, "fsl,suspend-in-wait")) {
 		if (!wdev->data->wdw_supported) {
 			dev_err(dev, "suspend-in-wait not supported\n");
-- 
2.39.5



From andreas at kemnade.info  Mon Dec 29 06:54:27 2025
From: andreas at kemnade.info (Andreas Kemnade)
Date: Mon, 29 Dec 2025 15:54:27 +0100
Subject: [PATCH 05/12] i2c: omap: set device parent and of_node through
 the adapter struct
In-Reply-To: <20251223-i2c-adap-dev-config-v1-5-4829b1cf0834@oss.qualcomm.com>
References: <20251223-i2c-adap-dev-config-v1-0-4829b1cf0834@oss.qualcomm.com>
	<20251223-i2c-adap-dev-config-v1-5-4829b1cf0834@oss.qualcomm.com>
Message-ID: <20251229155427.2ffcf120@kemnade.info>

On Tue, 23 Dec 2025 11:04:43 +0100
Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com> wrote:

> Configure the parent device and the OF-node using dedicated fields in
> struct i2c_adapter and avoid dereferencing the internal struct device.
> 
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>

Reviewed-by: Andreas Kemnade <andreas at kemnade.info>


From ahmed.tiba at arm.com  Mon Dec 29 07:01:21 2025
From: ahmed.tiba at arm.com (Ahmed Tiba)
Date: Mon, 29 Dec 2025 15:01:21 +0000
Subject: [PATCH 03/12] ras: add estatus vendor handling and processing
In-Reply-To: <20251222091334.5cb8465f@foz.lan>
Message-ID: <20251229150234.2789600-1-ahmed.tiba@arm.com>

On Mon, Dec 22, 2025 at 09:13:34 +0100, Mauro Carvalho Chehab wrote:
>Em Fri, 19 Dec 2025 18:11:54 +0000
>Ahmed Tiba <ahmed.tiba at arm.com> escreveu:
>
>> On Fri, Dec 19, 2025 at 04:30:40PM +0100, Mauro Carvalho Chehab wrote:
>> >On Fri, Dec 19, 2025 at 02:49:02PM +0000, Ahmed Tiba wrote: 
>> >>
>> >> On Wed, Dec 18, 2025 at 05:04:53PM +0100, Mauro Carvalho Chehab wrote:
>> >> 
>> >> >> Teach the estatus core how to walk CPER records and expose the vendor
>> >> >> record notification path. This adds the section iteration helpers,
>> >> >> the logging helpers that mirror the GHES behaviour, and the deferred
>> >> >> work used to hand vendor GUIDs to interested drivers. No users switch
>> >> >> over yet; this simply moves the common logic out of GHES so the next
>> >> >> patches can wire it up.
>> >> >>
>> >> >> Signed-off-by: Ahmed Tiba <ahmed.tiba at arm.com> 
>> >> >
>> >> >...
>> >> > 
>> >> >> +static bool estatus_handle_arm_hw_error(estatus_generic_data *gdata, int sev, bool sync) 
>> >> >
>> >> > Huh?
>> >> >
>> >> > This is a CPER record from GHES. Why are you moving CPER code out
>> >> > of ghes.c, placing in a file named estatus.c? Doesn't make much
>> >> > sense on my eyes...
>> >> >
>> >> > Same applies to to other GHES CPER record types. 
>> >>
>> >> GHES still fills in the CPER record, but the parsing and logging logic is
>> >> shared with the new DeviceTree provider so I pulled those helpers into the
>> >> estatus core. 
>> >
>> > I see, but this is not really estatus core. Instead, it is part of GHES CPER
>> > handling logic, which is defined at ACPI and UEFI specs. moving it to estatus
>> > sounds odd, at least on my eyes.
>> >
>> > Perhaps I'm failing to see where at ACPI/UEFI specs how CPER would be
>> > integrated with an OpenFirmware approach to handle CPER without GHES.
>> > Care to point to the relevant specs, if any? 
>>
>> ACPI/APEI (via GHES) defines how CPER records are discovered and notified on ACPI systems,
>> but there is no ACPI or UEFI-defined equivalent for OpenFirmware/DeviceTree platforms.
>> UEFI standardises the CPER record format itself, not the transport or discovery mechanism.
>>
>> On non-ACPI systems we still receive the same UEFI-defined CPER payload
>> from firmware, but Linux needs a different, platform-specific contract
>> to locate and acknowledge it. The DT binding is a Linux-side description
>> of that contract rather than something defined by ACPI/UEFI.
>
> That's where I'm failing to understand: CPER is part of UEFI spec, and
> the only deliverable mechanism I'm aware of for CPER is via GHES or
> GHESv2 - e.g. via ACPI.
>
> Within the scope of https://uefi.org/specifications, I'm failing
> to see any other deliverable mechanism.

Right, the UEFI specs only describe the GHES/ACPI path. There isn?t
a spec-defined transport for firmware-first CPER delivery outside ACPI/GHES,
which is why patch 9/12 describes a Linux-side DT contract
for exposing the CPER status buffer and notification path.
If there?s a better place to document or name that DT transport, I?d appreciate pointers.

>> >> Both providers already call into the same notifier chain and
>> >> memory-pool helpers; this patch just moves the generic CPER walking routines
>> >> next to the rest of the common code so the DT path doesn?t have to grow its
>> >> own copy. If you?d prefer a different file layout or naming to make that
>> >> intent clearer, I?m happy to adjust. 
>>
>> > Moving the code from ghes.c to estatus.c or to elsewhere shouldn't make any
>> > difference, as the DT handling logic could simply be calling the functions
>> > from ghes.c (or estatus.c). I fail to see why they need to be moved. 
>>
>> The motivation is to provide a shared implementation for non-ACPI providers,
>> so that the DT path does not depend on ACPI/APEI.
>>
>> While the helpers currently live in ghes.c, they are CPER-specific and do not rely on ACPI tables,
>> APEI infrastructure, or GHES notification semantics. Keeping them there effectively makes GHES
>> the only place those helpers can live, even though the logic itself is provider-agnostic.
>
> The logic is related to GHES, as this seems to be the only standardized
> mechanism to report CPER records. As it is part of APEI, get_maintainers
> points to the people that have been maintaining it as:
>
>        $ ./scripts/get_maintainer.pl -f ./drivers/acpi/apei/ghes.c
>        "Rafael J. Wysocki" <rafael at kernel.org> (maintainer:ACPI APEI,commit_signer:6/13=46%)
>        Tony Luck <tony.luck at intel.com> (reviewer:ACPI APEI,commit_signer:3/13=23%)
>        Borislav Petkov <bp at alien8.de> (reviewer:ACPI APEI,removed_lines:5/62=8%)
>        Hanjun Guo <guohanjun at huawei.com> (reviewer:ACPI APEI,commit_signer:4/13=31%)
>        Mauro Carvalho Chehab <mchehab at kernel.org> (reviewer:ACPI APEI,authored:1/13=8%,removed_lines:6/62=10%)
>        Shuai Xue <xueshuai at linux.alibaba.com> (reviewer:ACPI APEI,commit_signer:5/13=38%,authored:2/13=15%,added_lines:56/218=26%,removed_lines:34/62=55%)
>        Len Brown <lenb at kernel.org> (reviewer:ACPI)
>        Jonathan Cameron <Jonathan.Cameron at huawei.com> (commit_signer:5/13=38%)
>        Breno Leitao <leitao at debian.org> (authored:2/13=15%,added_lines:38/218=17%)
>        Smita Koralahalli <Smita.KoralahalliChannabasappa at amd.com> (authored:2/13=15%,added_lines:103/218=47%)
>        Ankit Agrawal <ankita at nvidia.com> (authored:1/13=8%,removed_lines:6/62=10%)
>        Jason Tian <jason at os.amperecomputing.com> (removed_lines:7/62=11%)
>        linux-acpi at vger.kernel.org (open list:ACPI APEI)
>        linux-kernel at vger.kernel.org (open list)
>
> Moving it elsewhere would make it confusing, as the expected deliverable
> mechanism for CPER is via GHES - as this is the only one defined at the
> uefi.org specs.
>
> While it might be moved to EFI and placed under cper.c,
> get_maintainers.pl would point to:
>
>        $ ./scripts/get_maintainer.pl -f ./drivers/firmware/efi/cper.c
>        Ard Biesheuvel <ardb at kernel.org> (maintainer:EXTENSIBLE FIRMWARE INTERFACE (EFI))
>        linux-efi at vger.kernel.org (open list:EXTENSIBLE FIRMWARE INTERFACE (EFI))
>        linux-kernel at vger.kernel.org (open list)
>
> which is not the people that have been maintaining RAS.
>
> Placing it under a "estatus.c" file would make it completely
> dissociated with UEFI/ACPI specs, as this name means nothing at
> the specs.
>
> Also, adding a new maintainer's entry won't make any sense, as the
> people that currently reviews and maintains GHES/CPER records
> should be kept.

You?re right that per UEFI/ACPI, GHES is the only standardised delivery path.
My goal isn?t to redefine that; it?s to avoid duplicating the CPER parsing/logging
code for non-ACPI platforms. I?m happy to restructure the helpers however you
think best so we keep the existing ACPI/APEI maintainer model intact.

>> By moving the CPER parsing and logging pieces into a common location,
>> both GHES and the DT provider can reuse the same implementation,
>> while the ACPI-specific discovery and notification code remains under drivers/acpi/apei/.
>> This avoids having the DT provider reach into GHES internals or duplicate CPER handling code.
>
> As Boris mentioned on patch 00/12, we need to better understand
> the high level scenario, as it is still not clear to me how a
> firmware-first notification would happen without ACPI.

That scenario is a firmware-first platform where firmware still produces a UEFI
CPER Generic Error Status block but signals Linux via the DT-described transport.
Once the buffer is available, the provider feeds it into the same estatus decoding path as GHES.

>> If the current naming or file layout makes that separation unclear, I?m happy to adjust it.

Thanks,
Ahmed


From stefano.radaelli21 at gmail.com  Mon Dec 29 07:04:08 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Mon, 29 Dec 2025 16:04:08 +0100
Subject: [PATCH v1 0/3] Add support for Variscite DART-MX95 and Sonata board
Message-ID: <20251229150421.57616-1-stefano.r@variscite.com>

From: Stefano Radaelli <stefano.r at variscite.com>

This patch series adds support for the Variscite DART-MX95 system on
module and the Sonata carrier board.

The series includes:
- Device tree bindings documentation for both SOM and carrier board
- SOM device tree with on-module peripherals
- Sonata carrier board device tree with board-specific features

The implementation follows the standard SOM + carrier board pattern
where the SOM dtsi contains only peripherals mounted on the module,
while carrier-specific interfaces are enabled in the board dts.

Stefano Radaelli (3):
  dt-bindings: arm: fsl: add Variscite DART-MX95 Boards
  arm64: dts: freescale: Add support for Variscite DART-MX95
  arm64: dts: imx95-var-dart: Add support for Variscite Sonata board

 .../devicetree/bindings/arm/fsl.yaml          |   6 +
 arch/arm64/boot/dts/freescale/Makefile        |   1 +
 .../dts/freescale/imx95-var-dart-sonata.dts   | 588 ++++++++++++++++++
 .../boot/dts/freescale/imx95-var-dart.dtsi    | 462 ++++++++++++++
 4 files changed, 1057 insertions(+)
 create mode 100644 arch/arm64/boot/dts/freescale/imx95-var-dart-sonata.dts
 create mode 100644 arch/arm64/boot/dts/freescale/imx95-var-dart.dtsi


base-commit: 40fbbd64bba6c6e7a72885d2f59b6a3be9991eeb
-- 
2.47.3



From stefano.radaelli21 at gmail.com  Mon Dec 29 07:04:09 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Mon, 29 Dec 2025 16:04:09 +0100
Subject: [PATCH v1 1/3] dt-bindings: arm: fsl: add Variscite DART-MX95 Boards
In-Reply-To: <20251229150421.57616-1-stefano.r@variscite.com>
References: <20251229150421.57616-1-stefano.r@variscite.com>
Message-ID: <20251229150421.57616-2-stefano.r@variscite.com>

From: Stefano Radaelli <stefano.r at variscite.com>

Add DT compatible strings for Variscite DART-MX95 SoM and Variscite
development carrier Board.

Link: https://variscite.com/system-on-module-som/i-mx-9/dart-mx95/
Link: https://variscite.com/carrier-boards/sonata-board/
Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 Documentation/devicetree/bindings/arm/fsl.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
index 68a2d5fecc43..2a957a593abe 100644
--- a/Documentation/devicetree/bindings/arm/fsl.yaml
+++ b/Documentation/devicetree/bindings/arm/fsl.yaml
@@ -1449,6 +1449,12 @@ properties:
           - const: toradex,smarc-imx95     # Toradex SMARC iMX95 Module
           - const: fsl,imx95
 
+      - description: Variscite DART-MX95 based Boards
+        items:
+          - const: variscite,var-dart-mx95-sonata # Variscite DART-MX95 SOM on Sonata Development Board
+          - const: variscite,var-dart-mx95 # Variscite DART-MX95 SOM
+          - const: fsl,imx95
+
       - description: i.MXRT1050 based Boards
         items:
           - enum:
-- 
2.47.3



From stefano.radaelli21 at gmail.com  Mon Dec 29 07:04:10 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Mon, 29 Dec 2025 16:04:10 +0100
Subject: [PATCH v1 2/3] arm64: dts: freescale: Add support for Variscite DART-MX95
In-Reply-To: <20251229150421.57616-1-stefano.r@variscite.com>
References: <20251229150421.57616-1-stefano.r@variscite.com>
Message-ID: <20251229150421.57616-3-stefano.r@variscite.com>

From: Stefano Radaelli <stefano.r at variscite.com>

Add device tree support for the Variscite DART-MX95 system on module.
This SOM is designed to be used with various carrier boards.

The module includes:
- NXP i.MX95 MPU processor
- Up to 16GB of LPDDR5 memory
- Up to 128GB of eMMC storage memory
- Integrated 10/100/1000 Mbps Ethernet Transceiver
- Codec audio WM8904
- WIFI6 dual-band 802.11ax/ac/a/b/g/n with optional 802.15.4 and Bluetooth

Only SOM-specific peripherals are enabled by default. Carrier board
specific interfaces are left disabled to be enabled in the respective
carrier board device trees.

Link: https://variscite.com/system-on-module-som/i-mx-9/i-mx-95/dart-mx95/
Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../boot/dts/freescale/imx95-var-dart.dtsi    | 462 ++++++++++++++++++
 1 file changed, 462 insertions(+)
 create mode 100644 arch/arm64/boot/dts/freescale/imx95-var-dart.dtsi

diff --git a/arch/arm64/boot/dts/freescale/imx95-var-dart.dtsi b/arch/arm64/boot/dts/freescale/imx95-var-dart.dtsi
new file mode 100644
index 000000000000..ed93701a8e4c
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx95-var-dart.dtsi
@@ -0,0 +1,462 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Common dtsi for Variscite DART-MX95
+ *
+ * Link: https://variscite.com/system-on-module-som/i-mx-9/i-mx-95/dart-mx95/
+ *
+ * Copyright (C) 2025 Variscite Ltd. - https://www.variscite.com/
+ *
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/usb/pd.h>
+#include "imx95.dtsi"
+
+/ {
+	model = "Variscite DART-MX95 Module";
+	compatible = "variscite,var-dart-mx95", "fsl,imx95";
+
+	memory at 80000000 {
+		device_type = "memory";
+		reg = <0x0 0x80000000 0 0x80000000>;
+	};
+
+	reg_1p8v: regulator-1p8v {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <1800000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-name = "+V1.8_SW";
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "+V3.3_SW";
+	};
+
+	reg_audio: regulator-audio-vdd {
+		compatible = "regulator-fixed";
+		regulator-name = "wm8904_supply";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	reg_vref_1v8: regulator-adc-vref {
+		compatible = "regulator-fixed";
+		regulator-name = "vref_1v8";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	reserved-memory {
+		ranges;
+		#address-cells = <2>;
+		#size-cells = <2>;
+
+		linux_cma: linux,cma {
+			compatible = "shared-dma-pool";
+			alloc-ranges = <0 0x80000000 0 0x7F000000>;
+			reusable;
+			size = <0 0x3c000000>;
+			linux,cma-default;
+		};
+
+		vdev0vring0: vdev0vring0 at 88000000 {
+			reg = <0 0x88000000 0 0x8000>;
+			no-map;
+		};
+
+		vdev0vring1: vdev0vring1 at 88008000 {
+			reg = <0 0x88008000 0 0x8000>;
+			no-map;
+		};
+
+		vdev1vring0: vdev1vring0 at 88010000 {
+			reg = <0 0x88010000 0 0x8000>;
+			no-map;
+		};
+
+		vdev1vring1: vdev1vring1 at 88018000 {
+			reg = <0 0x88018000 0 0x8000>;
+			no-map;
+		};
+
+		vdevbuffer: vdevbuffer at 88020000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x88020000 0 0x100000>;
+			no-map;
+		};
+
+		rsc_table: rsc-table at 88220000 {
+			reg = <0 0x88220000 0 0x1000>;
+			no-map;
+		};
+
+		vpu_boot: vpu_boot at a0000000 {
+			reg = <0 0xa0000000 0 0x100000>;
+			no-map;
+		};
+	};
+
+	sound-wm8904 {
+		compatible = "simple-audio-card";
+		simple-audio-card,bitclock-master = <&codec_dai>;
+		simple-audio-card,format = "i2s";
+		simple-audio-card,frame-master = <&codec_dai>;
+		simple-audio-card,mclk-fs = <256>;
+		simple-audio-card,name = "wm8904-audio";
+		simple-audio-card,routing =
+			"Headphone Jack", "HPOUTL",
+			"Headphone Jack", "HPOUTR",
+			"IN2L", "Line In Jack",
+			"IN2R", "Line In Jack",
+			"IN1L", "Microphone Jack",
+			"IN1R", "Microphone Jack";
+		simple-audio-card,widgets =
+			"Microphone", "Microphone Jack",
+			"Headphone", "Headphone Jack",
+			"Line", "Line In Jack";
+
+		codec_dai: simple-audio-card,codec {
+			sound-dai = <&wm8904>;
+		};
+
+		simple-audio-card,cpu {
+			sound-dai = <&sai3>;
+		};
+	};
+
+	wifi_pwrseq: wifi-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		post-power-on-delay-ms = <100>;
+		power-off-delay-us = <10000>;
+		reset-gpios = <&gpio4 29 GPIO_ACTIVE_LOW>, /* WIFI_RESET */
+			      <&gpio2 27 GPIO_ACTIVE_LOW>; /* WIFI_PWR_EN */
+	};
+};
+
+&adc1 {
+	vref-supply = <&reg_vref_1v8>;
+	status = "okay";
+};
+
+&enetc_port0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_enetc0>;
+	phy-handle = <&ethphy0>;
+	/*
+	 * The required RGMII TX and RX 2ns delays are implemented directly
+	 * in hardware via passive delay elements on the SOM PCB.
+	 * No delay configuration is needed in software via PHY driver.
+	 */
+	phy-mode = "rgmii";
+	status = "okay";
+};
+
+&lpi2c8 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default","gpio","sleep";
+	pinctrl-0 = <&pinctrl_lpi2c8>;
+	pinctrl-1 = <&pinctrl_lpi2c8_gpio>;
+	pinctrl-2 = <&pinctrl_lpi2c8_gpio>;
+	scl-gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>;
+	sda-gpios = <&gpio2 11 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+
+	wm8904: codec at 1a {
+		compatible = "wlf,wm8904";
+		reg = <0x1a>;
+		#sound-dai-cells = <0>;
+		clocks = <&scmi_clk IMX95_CLK_SAI3>;
+		clock-names = "mclk";
+		AVDD-supply = <&reg_audio>;
+		CPVDD-supply = <&reg_audio>;
+		DBVDD-supply = <&reg_audio>;
+		DCVDD-supply = <&reg_audio>;
+		MICVDD-supply = <&reg_audio>;
+		wlf,drc-cfg-names = "default", "peaklimiter", "tradition",
+				    "soft", "music";
+		/*
+		 * Config registers per name, respectively:
+		 * KNEE_IP = 0,   KNEE_OP = 0,     HI_COMP = 1,   LO_COMP = 1
+		 * KNEE_IP = -24, KNEE_OP = -6,    HI_COMP = 1/4, LO_COMP = 1
+		 * KNEE_IP = -42, KNEE_OP = -3,    HI_COMP = 0,   LO_COMP = 1
+		 * KNEE_IP = -45, KNEE_OP = -9,    HI_COMP = 1/8, LO_COMP = 1
+		 * KNEE_IP = -30, KNEE_OP = -10.5, HI_COMP = 1/4, LO_COMP = 1
+		 */
+		wlf,drc-cfg-regs = /bits/ 16 <0x01af 0x3248 0x0000 0x0000>,
+				   /bits/ 16 <0x04af 0x324b 0x0010 0x0408>,
+				   /bits/ 16 <0x04af 0x324b 0x0028 0x0704>,
+				   /bits/ 16 <0x04af 0x324b 0x0018 0x078c>,
+				   /bits/ 16 <0x04af 0x324b 0x0010 0x050e>;
+		/* GPIO1 = DMIC_CLK, don't touch others */
+		wlf,gpio-cfg = <0x0018>, <0xffff>, <0xffff>, <0xffff>;
+	};
+};
+
+/* BT */
+&lpuart5 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart5>, <&pinctrl_bt>;
+	status = "okay";
+
+	bluetooth {
+		compatible = "nxp,88w8987-bt";
+	};
+};
+
+&mu7 {
+	status = "okay";
+};
+
+&netc_emdio {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_emdio>, <&pinctrl_phy0res>;
+	status = "okay";
+
+	ethphy0: ethernet-phy at 0 {
+		reg = <0>;
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reset-gpios = <&gpio5 16 GPIO_ACTIVE_LOW>;
+		reset-assert-us = <10000>;
+		reset-deassert-us = <100000>;
+
+		leds {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			led at 0 {
+				reg = <0>;
+				color = <LED_COLOR_ID_YELLOW>;
+				function = LED_FUNCTION_LAN;
+				linux,default-trigger = "netdev";
+			};
+
+			led at 1 {
+				reg = <1>;
+				color = <LED_COLOR_ID_GREEN>;
+				function = LED_FUNCTION_LAN;
+				linux,default-trigger = "netdev";
+			};
+		};
+	};
+};
+
+&netc_timer {
+	status = "okay";
+};
+
+&sai3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_sai3>;
+	assigned-clocks = <&scmi_clk IMX95_CLK_AUDIOPLL1_VCO>,
+			  <&scmi_clk IMX95_CLK_AUDIOPLL2_VCO>,
+			  <&scmi_clk IMX95_CLK_AUDIOPLL1>,
+			  <&scmi_clk IMX95_CLK_AUDIOPLL2>,
+			  <&scmi_clk IMX95_CLK_SAI3>;
+	assigned-clock-parents = <0>, <0>, <0>, <0>,
+				 <&scmi_clk IMX95_CLK_AUDIOPLL1>;
+	assigned-clock-rates = <3932160000>,
+			       <3612672000>, <393216000>,
+			       <361267200>, <12288000>;
+	#sound-dai-cells = <0>;
+	fsl,sai-mclk-direction-output;
+	status = "okay";
+};
+
+&scmi_iomuxc {
+	pinctrl_bt: btgrp {
+		fsl,pins = <
+			IMX95_PAD_CCM_CLKO3__GPIO4_IO_BIT28				0x31e
+		>;
+	};
+
+	pinctrl_emdio: emdiogrp{
+		fsl,pins = <
+			IMX95_PAD_ENET1_MDC__NETCMIX_TOP_NETC_MDC			0x57e
+			IMX95_PAD_ENET1_MDIO__NETCMIX_TOP_NETC_MDIO			0x97e
+		>;
+	};
+
+	pinctrl_phy0res: phy0resgrp{
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO36__GPIO5_IO_BIT16				0x31e
+		>;
+	};
+
+	pinctrl_enetc0: enetc0grp {
+		fsl,pins = <
+			IMX95_PAD_ENET1_TD3__NETCMIX_TOP_ETH0_RGMII_TD3			0x57e
+			IMX95_PAD_ENET1_TD2__NETCMIX_TOP_ETH0_RGMII_TD2			0x57e
+			IMX95_PAD_ENET1_TD1__NETCMIX_TOP_ETH0_RGMII_TD1			0x57e
+			IMX95_PAD_ENET1_TD0__NETCMIX_TOP_ETH0_RGMII_TD0			0x57e
+			IMX95_PAD_ENET1_TX_CTL__NETCMIX_TOP_ETH0_RGMII_TX_CTL		0x57e
+			IMX95_PAD_ENET1_TXC__NETCMIX_TOP_ETH0_RGMII_TX_CLK		0x58e
+			IMX95_PAD_ENET1_RX_CTL__NETCMIX_TOP_ETH0_RGMII_RX_CTL		0x57e
+			IMX95_PAD_ENET1_RXC__NETCMIX_TOP_ETH0_RGMII_RX_CLK		0x58e
+			IMX95_PAD_ENET1_RD0__NETCMIX_TOP_ETH0_RGMII_RD0			0x57e
+			IMX95_PAD_ENET1_RD1__NETCMIX_TOP_ETH0_RGMII_RD1			0x57e
+			IMX95_PAD_ENET1_RD2__NETCMIX_TOP_ETH0_RGMII_RD2			0x57e
+			IMX95_PAD_ENET1_RD3__NETCMIX_TOP_ETH0_RGMII_RD3			0x57e
+		>;
+	};
+
+	pinctrl_lpi2c8: lpi2c8grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO10__LPI2C8_SDA					0x40000b9e
+			IMX95_PAD_GPIO_IO11__LPI2C8_SCL					0x40000b9e
+		>;
+	};
+
+	pinctrl_lpi2c8_gpio: lpi2c8gpiogrp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO10__GPIO2_IO_BIT10				0x31e
+			IMX95_PAD_GPIO_IO11__GPIO2_IO_BIT11				0x31e
+		>;
+	};
+
+	pinctrl_sai3: sai3grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO17__SAI3_MCLK					0x31e
+			IMX95_PAD_GPIO_IO16__SAI3_TX_BCLK				0x31e
+			IMX95_PAD_GPIO_IO26__SAI3_TX_SYNC				0x31e
+			IMX95_PAD_GPIO_IO20__SAI3_RX_DATA_BIT0				0x31e
+			IMX95_PAD_GPIO_IO21__SAI3_TX_DATA_BIT0				0x31e
+		>;
+	};
+
+	pinctrl_uart5: uart5grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO00__LPUART5_TX					0x31e
+			IMX95_PAD_GPIO_IO01__LPUART5_RX					0x31e
+			IMX95_PAD_GPIO_IO02__LPUART5_CTS_B				0x31e
+			IMX95_PAD_GPIO_IO03__LPUART5_RTS_B				0x31e
+		>;
+	};
+
+	pinctrl_usdhc1: usdhc1grp {
+		fsl,pins = <
+			IMX95_PAD_SD1_CLK__USDHC1_CLK					0x158e
+			IMX95_PAD_SD1_CMD__USDHC1_CMD					0x138e
+			IMX95_PAD_SD1_DATA0__USDHC1_DATA0				0x138e
+			IMX95_PAD_SD1_DATA1__USDHC1_DATA1				0x138e
+			IMX95_PAD_SD1_DATA2__USDHC1_DATA2				0x138e
+			IMX95_PAD_SD1_DATA3__USDHC1_DATA3				0x138e
+			IMX95_PAD_SD1_DATA4__USDHC1_DATA4				0x138e
+			IMX95_PAD_SD1_DATA5__USDHC1_DATA5				0x138e
+			IMX95_PAD_SD1_DATA6__USDHC1_DATA6				0x138e
+			IMX95_PAD_SD1_DATA7__USDHC1_DATA7				0x138e
+			IMX95_PAD_SD1_STROBE__USDHC1_STROBE				0x158e
+		>;
+	};
+
+	pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp {
+		fsl,pins = <
+			IMX95_PAD_SD1_CLK__USDHC1_CLK					0x158e
+			IMX95_PAD_SD1_CMD__USDHC1_CMD					0x138e
+			IMX95_PAD_SD1_DATA0__USDHC1_DATA0				0x138e
+			IMX95_PAD_SD1_DATA1__USDHC1_DATA1				0x138e
+			IMX95_PAD_SD1_DATA2__USDHC1_DATA2				0x138e
+			IMX95_PAD_SD1_DATA3__USDHC1_DATA3				0x138e
+			IMX95_PAD_SD1_DATA4__USDHC1_DATA4				0x138e
+			IMX95_PAD_SD1_DATA5__USDHC1_DATA5				0x138e
+			IMX95_PAD_SD1_DATA6__USDHC1_DATA6				0x138e
+			IMX95_PAD_SD1_DATA7__USDHC1_DATA7				0x138e
+			IMX95_PAD_SD1_STROBE__USDHC1_STROBE				0x158e
+		>;
+	};
+
+	pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp {
+		fsl,pins = <
+			IMX95_PAD_SD1_CLK__USDHC1_CLK					0x15fe
+			IMX95_PAD_SD1_CMD__USDHC1_CMD					0x13fe
+			IMX95_PAD_SD1_DATA0__USDHC1_DATA0				0x13fe
+			IMX95_PAD_SD1_DATA1__USDHC1_DATA1				0x13fe
+			IMX95_PAD_SD1_DATA2__USDHC1_DATA2				0x13fe
+			IMX95_PAD_SD1_DATA3__USDHC1_DATA3				0x13fe
+			IMX95_PAD_SD1_DATA4__USDHC1_DATA4				0x13fe
+			IMX95_PAD_SD1_DATA5__USDHC1_DATA5				0x13fe
+			IMX95_PAD_SD1_DATA6__USDHC1_DATA6				0x13fe
+			IMX95_PAD_SD1_DATA7__USDHC1_DATA7				0x13fe
+			IMX95_PAD_SD1_STROBE__USDHC1_STROBE				0x15fe
+		>;
+	};
+
+	pinctrl_usdhc3_gpio: usdhc3gpiogrp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO27__GPIO2_IO_BIT27				0x31e
+			IMX95_PAD_CCM_CLKO4__GPIO4_IO_BIT29				0x31e
+		>;
+	};
+
+	pinctrl_usdhc3: usdhc3grp {
+		fsl,pins = <
+			IMX95_PAD_SD3_CLK__USDHC3_CLK					0x158e
+			IMX95_PAD_SD3_CMD__USDHC3_CMD					0x138e
+			IMX95_PAD_SD3_DATA0__USDHC3_DATA0				0x138e
+			IMX95_PAD_SD3_DATA1__USDHC3_DATA1				0x138e
+			IMX95_PAD_SD3_DATA2__USDHC3_DATA2				0x138e
+			IMX95_PAD_SD3_DATA3__USDHC3_DATA3				0x138e
+		>;
+	};
+
+	pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp {
+		fsl,pins = <
+			IMX95_PAD_SD3_CLK__USDHC3_CLK					0x158e
+			IMX95_PAD_SD3_CMD__USDHC3_CMD					0x138e
+			IMX95_PAD_SD3_DATA0__USDHC3_DATA0				0x138e
+			IMX95_PAD_SD3_DATA1__USDHC3_DATA1				0x138e
+			IMX95_PAD_SD3_DATA2__USDHC3_DATA2				0x138e
+			IMX95_PAD_SD3_DATA3__USDHC3_DATA3				0x138e
+		>;
+	};
+
+	pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp {
+		fsl,pins = <
+			IMX95_PAD_SD3_CLK__USDHC3_CLK					0x15fe
+			IMX95_PAD_SD3_CMD__USDHC3_CMD					0x13fe
+			IMX95_PAD_SD3_DATA0__USDHC3_DATA0				0x13fe
+			IMX95_PAD_SD3_DATA1__USDHC3_DATA1				0x13fe
+			IMX95_PAD_SD3_DATA2__USDHC3_DATA2				0x13fe
+			IMX95_PAD_SD3_DATA3__USDHC3_DATA3				0x13fe
+		>;
+	};
+};
+
+/* eMMC */
+&usdhc1 {
+	pinctrl-names = "default","state_100mhz","state_200mhz","sleep";
+	pinctrl-0 = <&pinctrl_usdhc1>;
+	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
+	pinctrl-3 = <&pinctrl_usdhc1>;
+	bus-width = <8>;
+	non-removable;
+	no-sdio;
+	no-sd;
+	status = "okay";
+};
+
+/* WiFi */
+&usdhc3 {
+	pinctrl-names = "default","state_100mhz","state_200mhz","sleep";
+	pinctrl-0 = <&pinctrl_usdhc3>, <&pinctrl_usdhc3_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc3_100mhz>, <&pinctrl_usdhc3_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc3_200mhz>, <&pinctrl_usdhc3_gpio>;
+	pinctrl-3 = <&pinctrl_usdhc3>, <&pinctrl_usdhc3_gpio>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	bus-width = <4>;
+	non-removable;
+	wakeup-source;
+	keep-power-in-suspend;
+	status = "okay";
+};
+
+&wdog3 {
+	fsl,ext-reset-output;
+	status = "okay";
+};
-- 
2.47.3



From stefano.radaelli21 at gmail.com  Mon Dec 29 07:04:11 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Mon, 29 Dec 2025 16:04:11 +0100
Subject: [PATCH v1 3/3] arm64: dts: imx95-var-dart: Add support for Variscite Sonata board
In-Reply-To: <20251229150421.57616-1-stefano.r@variscite.com>
References: <20251229150421.57616-1-stefano.r@variscite.com>
Message-ID: <20251229150421.57616-4-stefano.r@variscite.com>

From: Stefano Radaelli <stefano.r at variscite.com>

Add device tree support for the Variscite Sonata carrier board with
the DART-MX95 system on module.

The Sonata board includes
- uSD Card support
- USB ports and OTG
- Additional Gigabit Ethernet interface
- 10Gb Ethernet SFP+ connector
- Uart interfaces
- OV5640 Camera support
- GPIO Expanders
- RTC module
- TPM module
- PCIE support

Link: https://variscite.com/carrier-boards/sonata-board/
Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 arch/arm64/boot/dts/freescale/Makefile        |   1 +
 .../dts/freescale/imx95-var-dart-sonata.dts   | 588 ++++++++++++++++++
 2 files changed, 589 insertions(+)
 create mode 100644 arch/arm64/boot/dts/freescale/imx95-var-dart-sonata.dts

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index f30d3fd724d0..411f86013ec6 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -404,6 +404,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx95-19x19-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx95-19x19-evk-sof.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx95-toradex-smarc-dev.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx95-tqma9596sa-mb-smarc-2.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx95-var-dart-sonata.dtb
 
 imx95-15x15-evk-pcie0-ep-dtbs = imx95-15x15-evk.dtb imx-pcie0-ep.dtbo
 dtb-$(CONFIG_ARCH_MXC) += imx95-15x15-evk-pcie0-ep.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx95-var-dart-sonata.dts b/arch/arm64/boot/dts/freescale/imx95-var-dart-sonata.dts
new file mode 100644
index 000000000000..ac7544831b24
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx95-var-dart-sonata.dts
@@ -0,0 +1,588 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Variscite Sonata carrier board for DART-MX95
+ *
+ * Link: https://variscite.com/carrier-boards/sonata-board/
+ *
+ * Copyright (C) 2025 Variscite Ltd. - https://www.variscite.com/
+ *
+ */
+
+#include "imx95-var-dart.dtsi"
+
+/ {
+	model = "Variscite DART-MX95 on Sonata-Board";
+	compatible = "variscite,var-dart-mx95-sonata",
+		     "variscite,var-dart-mx95",
+		     "fsl,imx95";
+
+	aliases {
+		mmc0 = &usdhc1;
+		mmc1 = &usdhc2;
+		serial0 = &lpuart1;
+		ethernet0 = &enetc_port0;
+		ethernet1 = &enetc_port1;
+		ethernet2 = &enetc_port2;
+	};
+
+	chosen {
+		stdout-path = &lpuart1;
+	};
+
+	typec_con: connector {
+		compatible = "usb-c-connector";
+		data-role = "dual";
+		label = "USB-C";
+		op-sink-microwatt = <0>;
+		power-role = "dual";
+		self-powered;
+		sink-pdos = <PDO_FIXED(5000, 0, PDO_FIXED_USB_COMM)>;
+		source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
+		try-power-role = "sink";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+				typec_con_hs: endpoint {
+					remote-endpoint = <&usb3_data_hs>;
+				};
+			};
+
+			port at 1 {
+				reg = <1>;
+				typec_con_ss: endpoint {
+					remote-endpoint = <&usb3_data_ss>;
+				};
+			};
+		};
+	};
+
+	clk_osc_can0: clock-osc-40m {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <40000000>;
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpio_leds>;
+
+		led-heartbeat {
+			label = "Heartbeat";
+			gpios = <&gpio3 27 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		button-back {
+			label = "Back";
+			linux,code = <KEY_BACK>;
+			gpios = <&pca6408_1 7 GPIO_ACTIVE_LOW>;
+			wakeup-source;
+		};
+
+		button-up {
+			label = "Up";
+			linux,code = <KEY_UP>;
+			gpios = <&pca6408_1 5 GPIO_ACTIVE_LOW>;
+			wakeup-source;
+		};
+
+		button-home {
+			label = "Home";
+			linux,code = <KEY_HOME>;
+			gpios = <&pca6408_1 4 GPIO_ACTIVE_LOW>;
+			wakeup-source;
+		};
+
+		button-down {
+			label = "Down";
+			linux,code = <KEY_DOWN>;
+			gpios = <&pca6408_1 6 GPIO_ACTIVE_LOW>;
+			wakeup-source;
+		};
+	};
+
+	reg_usdhc2_vmmc: regulator-vmmc-usdhc2 {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
+		regulator-name = "VDD_SD2_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio3 7 GPIO_ACTIVE_HIGH>;
+		off-on-delay-us = <12000>;
+		enable-active-high;
+	};
+
+	reg_phy1_supply: regulator-phy1 {
+		compatible = "regulator-fixed";
+		regulator-name = "SUPPLY_PHY1";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&pca6408_2 0 GPIO_ACTIVE_LOW>;
+		startup-delay-us = <10000>;
+		enable-active-high;
+		regulator-always-on;
+	};
+};
+
+&enetc_port1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_enetc1>;
+	phy-handle = <&ethphy1>;
+	/*
+	 * The required RGMII TX and RX 2ns delays are implemented directly
+	 * in hardware via passive delay elements on the SOM PCB.
+	 * No delay configuration is needed in software via PHY driver.
+	 */
+	phy-mode = "rgmii";
+	status = "okay";
+};
+
+&enetc_port2 {
+	phy-mode = "10gbase-r";
+	status = "okay";
+
+	fixed-link {
+		speed = <10000>;
+		full-duplex;
+		link-gpios = <&pca9534 1 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&flexcan1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_flexcan1>;
+	status = "okay";
+};
+
+&lpi2c3 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default", "gpio", "sleep";
+	pinctrl-0 = <&pinctrl_lpi2c3>;
+	pinctrl-1 = <&pinctrl_lpi2c3_gpio>;
+	pinctrl-2 = <&pinctrl_lpi2c3_gpio>;
+	scl-gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>;
+	sda-gpios = <&gpio2 29 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+
+	/* DS1337 RTC module */
+	rtc at 68 {
+		compatible = "dallas,ds1337";
+		reg = <0x68>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_rtc>;
+		interrupt-parent = <&gpio5>;
+		interrupts = <12 IRQ_TYPE_EDGE_FALLING>;
+		wakeup-source;
+	};
+
+	/* Capacitive touch controller */
+	ft5x06_ts: ft5x06_ts at 38 {
+		compatible = "edt,edt-ft5206";
+		reg = <0x38>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_captouch>;
+		reset-gpios = <&pca6408_2 4 GPIO_ACTIVE_LOW>;
+		interrupt-parent = <&gpio5>;
+		interrupts = <13 IRQ_TYPE_EDGE_FALLING>;
+		touchscreen-size-x = <800>;
+		touchscreen-size-y = <480>;
+		touchscreen-inverted-x;
+		touchscreen-inverted-y;
+		wakeup-source;
+	};
+
+	pca9534: gpio at 22 {
+		compatible = "nxp,pca9534";
+		reg = <0x22>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&gpio5>;
+		interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
+
+		pcie2-sel-hog {
+			gpio-hog;
+			gpios = <6 GPIO_ACTIVE_HIGH>;
+			output-low;
+			line-name = "pcie-clk-sw";
+		};
+
+		sfp-sel-hog {
+			gpio-hog;
+			gpios = <5 GPIO_ACTIVE_HIGH>;
+			output-high;
+			line-name = "sfp-sw";
+		};
+	};
+
+	typec at 3d {
+		compatible = "nxp,ptn5150";
+		reg = <0x3d>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_ptn5150>;
+		interrupt-parent = <&gpio5>;
+		interrupts = <14 IRQ_TYPE_LEVEL_HIGH>;
+
+		port {
+			typec_dr_sw: endpoint {
+				remote-endpoint = <&usb3_drd_sw>;
+			};
+		};
+	};
+};
+
+&lpi2c4 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&pinctrl_lpi2c4>;
+	pinctrl-1 = <&pinctrl_lpi2c4>;
+	status = "okay";
+};
+
+&lpi2c8 {
+	pca6408_1: gpio at 20 {
+		compatible = "nxp,pcal6408";
+		reg = <0x20>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&gpio5>;
+		interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	pca6408_2: gpio at 21 {
+		compatible = "nxp,pcal6408";
+		reg = <0x21>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&gpio5>;
+		interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	st33ktpm2xi2c: tpm at 2e {
+		compatible = "st,st33ktpm2xi2c", "tcg,tpm-tis-i2c";
+		reg = <0x2e>;
+	};
+};
+
+&lpspi7 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_lpspi7>;
+	cs-gpios = <&gpio2 4 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	/* Resistive touch controller */
+	ads7846 at 0 {
+		compatible = "ti,ads7846";
+		reg = <0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_restouch>;
+		interrupt-parent = <&gpio2>;
+		interrupts = <24 IRQ_TYPE_EDGE_FALLING>;
+		pendown-gpio = <&gpio2 24 GPIO_ACTIVE_LOW>;
+		spi-max-frequency = <1500000>;
+		ti,x-min = /bits/ 16 <125>;
+		ti,x-max = /bits/ 16 <4008>;
+		ti,y-min = /bits/ 16 <282>;
+		ti,y-max = /bits/ 16 <3864>;
+		ti,x-plate-ohms = /bits/ 16 <180>;
+		ti,pressure-max = /bits/ 16 <255>;
+		ti,debounce-max = /bits/ 16 <10>;
+		ti,debounce-tol = /bits/ 16 <3>;
+		ti,debounce-rep = /bits/ 16 <1>;
+		ti,settle-delay-usec = /bits/ 16 <150>;
+		ti,keep-vref-on;
+		wakeup-source;
+	};
+};
+
+/* Console */
+&lpuart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart1>;
+	status = "okay";
+};
+
+/* Header (J12.4, J12.6) */
+&lpuart8 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart8>;
+	status = "okay";
+};
+
+&netc_emdio {
+
+	ethphy1: ethernet-phy at 1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <1>;
+		reset-gpios = <&pca6408_2 0 GPIO_ACTIVE_LOW>;
+		reset-assert-us = <10000>;
+		reset-deassert-us = <100000>;
+
+		leds {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			led at 0 {
+				reg = <0>;
+				color = <LED_COLOR_ID_YELLOW>;
+				function = LED_FUNCTION_LAN;
+				linux,default-trigger = "netdev";
+			};
+
+			led at 1 {
+				reg = <1>;
+				color = <LED_COLOR_ID_GREEN>;
+				function = LED_FUNCTION_LAN;
+				linux,default-trigger = "netdev";
+			};
+		};
+	};
+};
+
+&pcie0 {
+	reset-gpio = <&pca6408_2 3 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&pcie1 {
+	reset-gpio = <&pca6408_2 2 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&scmi_iomuxc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_hog>;
+
+	pinctrl_hog: hoggrp {
+		fsl,pins = <
+			/* GPIO Expanders shared IRQ */
+			IMX95_PAD_GPIO_IO37__GPIO5_IO_BIT17				0x31e
+		>;
+	};
+
+	pinctrl_captouch: captouchgrp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO33__GPIO5_IO_BIT13				0x31e
+		>;
+	};
+
+	pinctrl_enetc1: enetc1grp {
+		fsl,pins = <
+			IMX95_PAD_ENET2_TXC__NETCMIX_TOP_ETH1_RGMII_TX_CLK		0x57e
+			IMX95_PAD_ENET2_TX_CTL__NETCMIX_TOP_ETH1_RGMII_TX_CTL		0x57e
+			IMX95_PAD_ENET2_TD3__NETCMIX_TOP_ETH1_RGMII_TD3			0x57e
+			IMX95_PAD_ENET2_TD2__NETCMIX_TOP_ETH1_RGMII_TD2			0x57e
+			IMX95_PAD_ENET2_TD1__NETCMIX_TOP_ETH1_RGMII_TD1			0x57e
+			IMX95_PAD_ENET2_TD0__NETCMIX_TOP_ETH1_RGMII_TD0			0x57e
+			IMX95_PAD_ENET2_RXC__NETCMIX_TOP_ETH1_RGMII_RX_CLK		0x57e
+			IMX95_PAD_ENET2_RX_CTL__NETCMIX_TOP_ETH1_RGMII_RX_CTL		0x57e
+			IMX95_PAD_ENET2_RD0__NETCMIX_TOP_ETH1_RGMII_RD0			0x57e
+			IMX95_PAD_ENET2_RD1__NETCMIX_TOP_ETH1_RGMII_RD1			0x57e
+			IMX95_PAD_ENET2_RD2__NETCMIX_TOP_ETH1_RGMII_RD2			0x57e
+			IMX95_PAD_ENET2_RD3__NETCMIX_TOP_ETH1_RGMII_RD3			0x37e /* Enable pull-up to strap MXL86110 MDIO address */
+		>;
+	};
+
+	pinctrl_flexcan1: flexcan1grp {
+		fsl,pins = <
+			IMX95_PAD_PDM_CLK__AONMIX_TOP_CAN1_TX				0x39e
+			IMX95_PAD_PDM_BIT_STREAM0__AONMIX_TOP_CAN1_RX			0x39e
+		>;
+	};
+
+	pinctrl_gpio_leds: ledgrp {
+		fsl,pins = <
+			IMX95_PAD_CCM_CLKO2__GPIO3_IO_BIT27				0x31e
+		>;
+	};
+
+	pinctrl_lpi2c3: lpi2c3grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO28__LPI2C3_SDA					0x40000b9e
+			IMX95_PAD_GPIO_IO29__LPI2C3_SCL					0x40000b9e
+		>;
+	};
+
+	pinctrl_lpi2c3_gpio: lpi2c3gpiogrp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO28__GPIO2_IO_BIT28				0x31e
+			IMX95_PAD_GPIO_IO29__GPIO2_IO_BIT29				0x31e
+		>;
+	};
+
+	pinctrl_lpi2c4: lpi2c4grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO30__LPI2C4_SDA					0x40000b9e
+			IMX95_PAD_GPIO_IO31__LPI2C4_SCL					0x40000b9e
+		>;
+	};
+
+	pinctrl_lpspi7: lpspi7grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO04__GPIO2_IO_BIT4				0x3fe		/* j16.4 ADS7846 */
+			IMX95_PAD_UART2_TXD__AONMIX_TOP_GPIO1_IO_BIT7			0x3fe		/* j14.4 MCP2518FDT */
+			IMX95_PAD_XSPI1_DATA4__GPIO5_IO_BIT4				0x3fe		/* j25.2 spidev */
+			IMX95_PAD_GPIO_IO05__LPSPI7_SIN					0x3fe
+			IMX95_PAD_GPIO_IO06__LPSPI7_SOUT				0x3fe
+			IMX95_PAD_GPIO_IO07__LPSPI7_SCK					0x3fe
+		>;
+	};
+
+	pinctrl_ptn5150: ptn5150grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO34__GPIO5_IO_BIT14				0x31e
+		>;
+	};
+
+	pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
+		fsl,pins = <
+			IMX95_PAD_SD2_RESET_B__GPIO3_IO_BIT7				0x31e
+		>;
+	};
+
+	pinctrl_restouch: restouchgrp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO24__GPIO2_IO_BIT24				0x31e
+		>;
+	};
+
+	pinctrl_rtc: rtcgrp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO32__GPIO5_IO_BIT12				0x31e
+		>;
+	};
+
+	pinctrl_uart1: uart1grp {
+		fsl,pins = <
+			IMX95_PAD_UART1_RXD__AONMIX_TOP_LPUART1_RX			0x31e
+			IMX95_PAD_UART1_TXD__AONMIX_TOP_LPUART1_TX			0x31e
+		>;
+	};
+
+	pinctrl_uart8: uart8grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO13__LPUART8_RX					0x31e
+			IMX95_PAD_GPIO_IO12__LPUART8_TX					0x31e
+		>;
+	};
+
+	pinctrl_usdhc2_gpio: usdhc2gpiogrp {
+		fsl,pins = <
+			IMX95_PAD_SD2_CD_B__GPIO3_IO_BIT0				0x31e
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			IMX95_PAD_SD2_CLK__USDHC2_CLK					0x158e
+			IMX95_PAD_SD2_CMD__USDHC2_CMD					0x138e
+			IMX95_PAD_SD2_DATA0__USDHC2_DATA0				0x138e
+			IMX95_PAD_SD2_DATA1__USDHC2_DATA1				0x138e
+			IMX95_PAD_SD2_DATA2__USDHC2_DATA2				0x138e
+			IMX95_PAD_SD2_DATA3__USDHC2_DATA3				0x138e
+			IMX95_PAD_SD2_VSELECT__USDHC2_VSELECT				0x51e
+		>;
+	};
+
+	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+		fsl,pins = <
+			IMX95_PAD_SD2_CLK__USDHC2_CLK					0x158e
+			IMX95_PAD_SD2_CMD__USDHC2_CMD					0x138e
+			IMX95_PAD_SD2_DATA0__USDHC2_DATA0				0x138e
+			IMX95_PAD_SD2_DATA1__USDHC2_DATA1				0x138e
+			IMX95_PAD_SD2_DATA2__USDHC2_DATA2				0x138e
+			IMX95_PAD_SD2_DATA3__USDHC2_DATA3				0x138e
+			IMX95_PAD_SD2_VSELECT__USDHC2_VSELECT				0x51e
+		>;
+	};
+
+	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+		fsl,pins = <
+			IMX95_PAD_SD2_CLK__USDHC2_CLK					0x15fe
+			IMX95_PAD_SD2_CMD__USDHC2_CMD					0x13fe
+			IMX95_PAD_SD2_DATA0__USDHC2_DATA0				0x13fe
+			IMX95_PAD_SD2_DATA1__USDHC2_DATA1				0x13fe
+			IMX95_PAD_SD2_DATA2__USDHC2_DATA2				0x13fe
+			IMX95_PAD_SD2_DATA3__USDHC2_DATA3				0x13fe
+			IMX95_PAD_SD2_VSELECT__USDHC2_VSELECT				0x51e
+		>;
+	};
+};
+
+&usb2 {
+	dr_mode = "host";
+	adp-disable;
+	hnp-disable;
+	srp-disable;
+	disable-over-current;
+	status = "okay";
+};
+
+&usb3 {
+	status = "okay";
+};
+
+&usb3_dwc3 {
+	dr_mode = "otg";
+	hnp-disable;
+	srp-disable;
+	adp-disable;
+	usb-role-switch;
+	snps,dis-u1-entry-quirk;
+	snps,dis-u2-entry-quirk;
+	status = "okay";
+
+	port {
+		usb3_drd_sw: endpoint {
+			remote-endpoint = <&typec_dr_sw>;
+		};
+	};
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			reg = <0>;
+			usb3_data_hs: endpoint {
+				remote-endpoint = <&typec_con_hs>;
+			};
+		};
+
+		port at 1 {
+			reg = <1>;
+			usb3_data_ss: endpoint {
+				remote-endpoint = <&typec_con_ss>;
+			};
+		};
+	};
+};
+
+&usb3_phy {
+	fsl,phy-pcs-tx-deemph-3p5db-attenuation-db = <17>;
+	fsl,phy-pcs-tx-swing-full-percent = <100>;
+	fsl,phy-tx-preemp-amp-tune-microamp = <600>;
+	fsl,phy-tx-vboost-level-microvolt = <1156>;
+	status = "okay";
+};
+
+&usdhc2 {
+	pinctrl-names = "default","state_100mhz","state_200mhz","sleep";
+	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-3 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	cd-gpios = <&gpio3 0 GPIO_ACTIVE_LOW>;
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	bus-width = <4>;
+	status = "okay";
+};
-- 
2.47.3



From Frank.li at nxp.com  Mon Dec 29 07:09:24 2025
From: Frank.li at nxp.com (Frank Li)
Date: Mon, 29 Dec 2025 10:09:24 -0500
Subject: [PATCH v3 2/2] media: nxp: Add i.MX9 CSI pixel formatter v4l2
 driver
In-Reply-To: <AS8PR04MB9080817D9A557B9D96F55066FAB4A@AS8PR04MB9080.eurprd04.prod.outlook.com>
References: <20251219-csi_formatter-v3-0-8680d6d87091@nxp.com>
 <20251219-csi_formatter-v3-2-8680d6d87091@nxp.com>
 <aUV4enryGRDdIkIb@lizhi-Precision-Tower-5810>
 <AS8PR04MB9080817D9A557B9D96F55066FAB4A@AS8PR04MB9080.eurprd04.prod.outlook.com>
Message-ID: <aVKZpOKuST0s6bNY@lizhi-Precision-Tower-5810>

On Mon, Dec 22, 2025 at 03:29:10AM +0000, G.N. Zhou wrote:
> Hi Frank,
>
> Thanks for your review.
>
> > -----Original Message-----
> > From: Frank Li <frank.li at nxp.com>
> > Sent: Saturday, December 20, 2025 12:08 AM
> > To: G.N. Zhou (OSS) <guoniu.zhou at oss.nxp.com>
> > Cc: Mauro Carvalho Chehab <mchehab at kernel.org>; Rob Herring
> > <robh at kernel.org>; Krzysztof Kozlowski <krzk+dt at kernel.org>; Conor Dooley
> > <conor+dt at kernel.org>; Shawn Guo <shawnguo at kernel.org>; Sascha Hauer
> > <s.hauer at pengutronix.de>; Pengutronix Kernel Team
> > <kernel at pengutronix.de>; Fabio Estevam <festevam at gmail.com>; Laurent
> > Pinchart <laurent.pinchart at ideasonboard.com>; imx at lists.linux.dev; linux-
> > media at vger.kernel.org; devicetree at vger.kernel.org; linux-arm-
> > kernel at lists.infradead.org; linux-kernel at vger.kernel.org; G.N. Zhou
> > <guoniu.zhou at nxp.com>
> > Subject: Re: [PATCH v3 2/2] media: nxp: Add i.MX9 CSI pixel formatter v4l2
> > driver
> >
> > On Fri, Dec 19, 2025 at 09:50:58AM +0800, Guoniu Zhou wrote:
> > > From: Guoniu Zhou <guoniu.zhou at nxp.com>
> > >
> > > The CSI pixel formatter is a module found on i.MX95 used to reformat
> > > packet info, pixel and non-pixel data from CSI-2 host controller to
> > > match Pixel Link(PL) definition.
> > >
> > > Add data formatting support.
> > >
> > > Signed-off-by: Guoniu Zhou <guoniu.zhou at nxp.com>
> > > ---
> > >  MAINTAINERS                                     |   8 +
> > >  drivers/media/platform/nxp/Kconfig              |  14 +
> > >  drivers/media/platform/nxp/Makefile             |   1 +
> > >  drivers/media/platform/nxp/imx9-csi-formatter.c | 880
> > > ++++++++++++++++++++++++
> > >  4 files changed, 903 insertions(+)
> > >
> > > diff --git a/MAINTAINERS b/MAINTAINERS index
> > >
> > 4205ca007e076f869613032b51e8cc5bff06b98e..3878957b81156e5cb41da26
> > 99b2f
> > > 588e49521724 100644
> > > --- a/MAINTAINERS
> > > +++ b/MAINTAINERS
> > > @@ -18626,6 +18626,14 @@ S:	Maintained
> > >  F:	Documentation/devicetree/bindings/media/nxp,imx8-jpeg.yaml
> > >  F:	drivers/media/platform/nxp/imx-jpeg
> > >
> > > +NXP i.MX 9 CSI PIXEL FORMATTER V4L2 DRIVER
> > > +M:	Guoniu Zhou <guoniu.zhou at nxp.com>
> > > +L:	imx at lists.linux.dev
> > > +L:	linux-media at vger.kernel.org
> > > +S:	Maintained
> > > +F:	Documentation/devicetree/bindings/media/fsl,imx9-csi-formatter.yaml
> > > +F:	drivers/media/platform/nxp/imx9-csi-formatter.c
> > > +
> > >  NXP i.MX CLOCK DRIVERS
> > >  M:	Abel Vesa <abelvesa at kernel.org>
> > >  R:	Peng Fan <peng.fan at nxp.com>
> > > diff --git a/drivers/media/platform/nxp/Kconfig
> > > b/drivers/media/platform/nxp/Kconfig
> > > index
> > >
> > 40e3436669e213fdc5da70821dc0b420e1821f4f..a7bb62a2b0249659ffdfeac50
> > fa4
> > > 88aee9590a87 100644
> > > --- a/drivers/media/platform/nxp/Kconfig
> > > +++ b/drivers/media/platform/nxp/Kconfig
> > > @@ -28,6 +28,20 @@ config VIDEO_IMX8MQ_MIPI_CSI2
> > >  	  Video4Linux2 driver for the MIPI CSI-2 receiver found on the i.MX8MQ
> > >  	  SoC.
> > >
> > > +config VIDEO_IMX9_CSI_FORMATTER
> > > +	tristate "NXP i.MX9 CSI Pixel Formatter driver"
> > > +	depends on ARCH_MXC || COMPILE_TEST
> > > +	depends on VIDEO_DEV
> > > +	select MEDIA_CONTROLLER
> > > +	select V4L2_FWNODE
> > > +	select VIDEO_V4L2_SUBDEV_API
> > > +	help
> > > +	  This driver provides support for the CSI Pixel Formatter found on
> > > +	  i.MX9 series SoC. This module unpacks the pixels received by the
> > > +	  formatter and reformats them to meet the pixel link format
> > requirement.
> > > +
> > > +	  Say Y here to enable CSI Pixel Formater module for i.MX9 SoC.
> > > +
> > >  config VIDEO_IMX_MIPI_CSIS
> > >  	tristate "NXP MIPI CSI-2 CSIS receiver found on i.MX7 and i.MX8
> > models"
> > >  	depends on ARCH_MXC || COMPILE_TEST
> > > diff --git a/drivers/media/platform/nxp/Makefile
> > > b/drivers/media/platform/nxp/Makefile
> > > index
> > >
> > 4d90eb71365259ebdda84ea58483e1c4131d3ac7..39ba5660ba923141e7637b
> > 01b5b3
> > > 4a021dad7bb3 100644
> > > --- a/drivers/media/platform/nxp/Makefile
> > > +++ b/drivers/media/platform/nxp/Makefile
> > > @@ -6,6 +6,7 @@ obj-y += imx8-isi/
> > >
> > >  obj-$(CONFIG_VIDEO_IMX7_CSI) += imx7-media-csi.o
> > >  obj-$(CONFIG_VIDEO_IMX8MQ_MIPI_CSI2) += imx8mq-mipi-csi2.o
> > > +obj-$(CONFIG_VIDEO_IMX9_CSI_FORMATTER) += imx9-csi-formatter.o
> > >  obj-$(CONFIG_VIDEO_IMX_MIPI_CSIS) += imx-mipi-csis.o
> > >  obj-$(CONFIG_VIDEO_IMX_PXP) += imx-pxp.o
> > >  obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o diff --git
> > > a/drivers/media/platform/nxp/imx9-csi-formatter.c
> > > b/drivers/media/platform/nxp/imx9-csi-formatter.c
> > > new file mode 100644
> > > index
> > >
> > 0000000000000000000000000000000000000000..5786e4690e31ee471caf82
> > 01329c
> > > 8e02a2cc0ee6
> > > --- /dev/null
> > > +++ b/drivers/media/platform/nxp/imx9-csi-formatter.c
> > > @@ -0,0 +1,880 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/*
> > > + * Copyright 2025 NXP
> > > + */
> > > +
> > ...
> > > +
> > > +static const struct dt_index formatter_dt_to_index_map[] = {
> > > +	{ .dtype = MIPI_CSI2_DT_YUV420_8B,        .index = 0 },
> > > +	{ .dtype = MIPI_CSI2_DT_YUV420_8B_LEGACY, .index = 2 },
> > > +	{ .dtype = MIPI_CSI2_DT_YUV422_8B,        .index = 6 },
> > > +	{ .dtype = MIPI_CSI2_DT_RGB444,		  .index = 8 },
> > > +	{ .dtype = MIPI_CSI2_DT_RGB555,           .index = 9 },
> > > +	{ .dtype = MIPI_CSI2_DT_RGB565,           .index = 10 },
> > > +	{ .dtype = MIPI_CSI2_DT_RGB666,           .index = 11 },
> > > +	{ .dtype = MIPI_CSI2_DT_RGB888,           .index = 12 },
> > > +	{ .dtype = MIPI_CSI2_DT_RAW6,             .index = 16 },
> > > +	{ .dtype = MIPI_CSI2_DT_RAW7,             .index = 17 },
> > > +	{ .dtype = MIPI_CSI2_DT_RAW8,             .index = 18 },
> > > +	{ .dtype = MIPI_CSI2_DT_RAW10,            .index = 19 },
> > > +	{ .dtype = MIPI_CSI2_DT_RAW12,            .index = 20 },
> > > +	{ .dtype = MIPI_CSI2_DT_RAW14,            .index = 21 },
> > > +	{ .dtype = MIPI_CSI2_DT_RAW16,            .index = 22 },
> >
> > what's these index value from? register bit?
>
> Yes, they represent pixel data type for each virtual channel. You could refer to
> i.MX95 RM Rev2 section "142.5.1.55 Table 913" for more details.

Okay, can you add comments said these value need match hardware settings.

Frank

>
> Best Regards
> G.N Zhou
>
>
> >
> > Frank
> > > +
> > > +static u8 get_index_by_dt(u8 data_type) {
> > > +	unsigned int i;
> > > +
> > > +	for (i = 0; i < ARRAY_SIZE(formatter_dt_to_index_map); ++i)
> > > +		if (data_type == formatter_dt_to_index_map[i].dtype)
> > > +			break;
> > > +
> > > +	if (i == ARRAY_SIZE(formatter_dt_to_index_map))
> > > +		return formatter_dt_to_index_map[0].index;
> > > +
> > > +	return formatter_dt_to_index_map[i].index;
> > > +}
> > > +
> > ...
> > >
> > > --
> > > 2.34.1
> > >


From Frank.li at nxp.com  Mon Dec 29 07:20:25 2025
From: Frank.li at nxp.com (Frank Li)
Date: Mon, 29 Dec 2025 10:20:25 -0500
Subject: [PATCH] ARM: dts: lpc32xx: Update spi clock properties
In-Reply-To: <20251224045205.1204414-1-vz@mleia.com>
References: <20251224045205.1204414-1-vz@mleia.com>
Message-ID: <aVKcOXWW084h5aTC@lizhi-Precision-Tower-5810>

On Wed, Dec 24, 2025 at 06:52:05AM +0200, Vladimir Zapolskiy wrote:
> From: Kuldeep Singh <singh.kuldeep87k at gmail.com>
>
> PL022 binding require two clocks to be defined but NXP LPC32xx platform
> doesn't comply with the bindings and define only one clock i.e apb_pclk.
>
> Update SPI clocks and clocks-names property by adding appropriate clock
> reference to make it compliant with the bindings.
>
> Noteworthy, strictly speaking the change tackles DT ABI by changing
> the order in the list of clock-names property values, however this level
> of impact is considered as acceptable.
>
> Cc: Vladimir Zapolskiy <vz at mleia.com>
> Signed-off-by: Kuldeep Singh <singh.kuldeep87k at gmail.com>
> [vzapolskiy: rebased and minor update to the commit message]
> Signed-off-by: Vladimir Zapolskiy <vz at mleia.com>

Reviewed-by: Frank Li <Frank.Li at nxp.com>

> ---
> I do resend the unapplied change from the past, which raised a discussion:
> * https://lore.kernel.org/all/20220311093800.18778-4-singh.kuldeep87k at gmail.com/
>
> A functionally identical change has been sent recently:
> * https://lore.kernel.org/all/20251029202801.3963952-2-Frank.Li at nxp.com/
> ---
>  arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
> index e780451fd335..206c66bdfe41 100644
> --- a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
> +++ b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
> @@ -172,8 +172,8 @@ ssp0: spi at 20084000 {
>  				compatible = "arm,pl022", "arm,primecell";
>  				reg = <0x20084000 0x1000>;
>  				interrupts = <20 IRQ_TYPE_LEVEL_HIGH>;
> -				clocks = <&clk LPC32XX_CLK_SSP0>;
> -				clock-names = "apb_pclk";
> +				clocks = <&clk LPC32XX_CLK_SSP0>, <&clk LPC32XX_CLK_SSP0>;
> +				clock-names = "sspclk", "apb_pclk";
>  				#address-cells = <1>;
>  				#size-cells = <0>;
>  				status = "disabled";
> @@ -196,8 +196,8 @@ ssp1: spi at 2008c000 {
>  				compatible = "arm,pl022", "arm,primecell";
>  				reg = <0x2008c000 0x1000>;
>  				interrupts = <21 IRQ_TYPE_LEVEL_HIGH>;
> -				clocks = <&clk LPC32XX_CLK_SSP1>;
> -				clock-names = "apb_pclk";
> +				clocks = <&clk LPC32XX_CLK_SSP1>, <&clk LPC32XX_CLK_SSP1>;
> +				clock-names = "sspclk", "apb_pclk";
>  				#address-cells = <1>;
>  				#size-cells = <0>;
>  				status = "disabled";
> --
> 2.43.0
>


From rostedt at goodmis.org  Mon Dec 29 08:03:37 2025
From: rostedt at goodmis.org (Steven Rostedt)
Date: Mon, 29 Dec 2025 11:03:37 -0500
Subject: [PATCHv5 bpf-next 9/9] bpf,x86: Use single ftrace_ops for
 direct calls
In-Reply-To: <aVFLKgZ56wt5aLci@krava>
References: <20251215211402.353056-1-jolsa@kernel.org>
	<20251215211402.353056-10-jolsa@kernel.org>
	<20251218112608.11a14a4a@gandalf.local.home>
	<aUUanPijlWsDlS0X@krava>
	<aVFLKgZ56wt5aLci@krava>
Message-ID: <20251229110337.030232e0@gandalf.local.home>

On Sun, 28 Dec 2025 16:22:18 +0100
Jiri Olsa <olsajiri at gmail.com> wrote:

> actualy, it seems that having it the original way with adding the rest
> of the wrappers for !CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS case is
> easier AFAICS

I'm fine either way.

-- Steve


From Frank.Li at nxp.com  Mon Dec 29 08:31:01 2025
From: Frank.Li at nxp.com (Frank Li)
Date: Mon, 29 Dec 2025 11:31:01 -0500
Subject: [PATCH v2 1/1] arm64: dts: imx8mp-evk: add camera ov5640 and related nodes
Message-ID: <20251229163101.4004478-1-Frank.Li@nxp.com>

Add camera ov5640 and related nodes.

Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
change in v2
- correct regulator voltage.
---
 arch/arm64/boot/dts/freescale/imx8mp-evk.dts | 80 ++++++++++++++++++++
 1 file changed, 80 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
index c6facb2ad9aaa..e7fe90ae59353 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
@@ -74,6 +74,27 @@ pcie0_refclk: pcie0-refclk {
 		clock-frequency = <100000000>;
 	};
 
+	reg_1v5: regulator-1v5 {
+		compatible = "regulator-fixed";
+		regulator-name = "1v5";
+		regulator-min-microvolt = <1500000>;
+		regulator-max-microvolt = <1500000>;
+	};
+
+	reg_1v8: regulator-1v8 {
+		compatible = "regulator-fixed";
+		regulator-name = "1v8";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	reg_2v8: regulator-1v8 {
+		compatible = "regulator-fixed";
+		regulator-name = "2v8";
+		regulator-min-microvolt = <2800000>;
+		regulator-max-microvolt = <2800000>;
+	};
+
 	reg_audio_3v3: regulator-audio-3v3 {
 		compatible = "regulator-fixed";
 		regulator-name = "audio-3v3";
@@ -560,6 +581,30 @@ &i2c2 {
 	pinctrl-0 = <&pinctrl_i2c2>;
 	status = "okay";
 
+	camera at 3c {
+	       compatible = "ovti,ov5640";
+	       reg = <0x3c>;
+	       pinctrl-names = "default";
+	       pinctrl-0 = <&pinctrl_csi0_pwn>, <&pinctrl_csi0_rst>, <&pinctrl_csi_mclk>;
+	       clocks = <&clk IMX8MP_CLK_IPP_DO_CLKO2>;
+	       clock-names = "xclk";
+	       assigned-clocks = <&clk IMX8MP_CLK_IPP_DO_CLKO2>;
+	       assigned-clock-parents = <&clk IMX8MP_CLK_24M>;
+	       assigned-clock-rates = <24000000>;
+	       powerdown-gpios = <&gpio2 11 GPIO_ACTIVE_HIGH>;
+	       AVDD-supply = <&reg_2v8>;
+	       DVDD-supply = <&reg_1v5>;
+	       DOVDD-supply = <&reg_1v8>;
+	       status = "okay";
+
+	       port {
+		       ov5640_mipi_0_ep: endpoint {
+			       remote-endpoint = <&mipi_csi0_ep>;
+			       data-lanes = <1 2>;
+		       };
+	       };
+	};
+
 	hdmi at 3d {
 		compatible = "adi,adv7535";
 		reg = <0x3d>;
@@ -664,6 +709,10 @@ &i2c5 {
 	 */
 };
 
+&isi_0 {
+	status = "okay";
+};
+
 &lcdif1 {
 	status = "okay";
 };
@@ -682,6 +731,19 @@ &micfil {
 	status = "okay";
 };
 
+&mipi_csi_0 {
+	status = "okay";
+
+	ports {
+	       port at 0 {
+		       mipi_csi0_ep: endpoint {
+				remote-endpoint = <&ov5640_mipi_0_ep>;
+				data-lanes = <1 2>;
+		       };
+	       };
+	};
+};
+
 &mipi_dsi {
 	samsung,esc-clock-frequency = <10000000>;
 	status = "okay";
@@ -855,6 +917,24 @@ MX8MP_IOMUXC_SAI3_RXC__GPIO4_IO29		0xd6
 		>;
 	};
 
+	pinctrl_csi_mclk: csi_mclk_grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO15__CCM_CLKO2	0x50
+		>;
+	};
+
+	pinctrl_csi0_pwn: csi0_pwn_grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_STROBE__GPIO2_IO11	0x10
+		>;
+	};
+
+	pinctrl_csi0_rst: csi0_rst_grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO06__GPIO1_IO06	0x10
+		>;
+	};
+
 	pinctrl_eqos: eqosgrp {
 		fsl,pins = <
 			MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC				0x2
-- 
2.34.1



From patchwork-bot+netdevbpf at kernel.org  Mon Dec 29 08:40:06 2025
From: patchwork-bot+netdevbpf at kernel.org (patchwork-bot+netdevbpf at kernel.org)
Date: Mon, 29 Dec 2025 16:40:06 +0000
Subject: [PATCH net] net: stmmac: fix the crash issue for zero copy XDP_TX
 action
In-Reply-To: <20251204071332.1907111-1-wei.fang@nxp.com>
References: <20251204071332.1907111-1-wei.fang@nxp.com>
Message-ID: <176702640604.3003866.8845654519033252561.git-patchwork-notify@kernel.org>

Hello:

This patch was applied to netdev/net.git (main)
by Paolo Abeni <pabeni at redhat.com>:

On Thu,  4 Dec 2025 15:13:32 +0800 you wrote:
> There is a crash issue when running zero copy XDP_TX action, the crash
> log is shown below.
> 
> [  216.122464] Unable to handle kernel paging request at virtual address fffeffff80000000
> [  216.187524] Internal error: Oops: 0000000096000144 [#1]  SMP
> [  216.301694] Call trace:
> [  216.304130]  dcache_clean_poc+0x20/0x38 (P)
> [  216.308308]  __dma_sync_single_for_device+0x1bc/0x1e0
> [  216.313351]  stmmac_xdp_xmit_xdpf+0x354/0x400
> [  216.317701]  __stmmac_xdp_run_prog+0x164/0x368
> [  216.322139]  stmmac_napi_poll_rxtx+0xba8/0xf00
> [  216.326576]  __napi_poll+0x40/0x218
> [  216.408054] Kernel panic - not syncing: Oops: Fatal exception in interrupt
> 
> [...]

Here is the summary with links:
  - [net] net: stmmac: fix the crash issue for zero copy XDP_TX action
    https://git.kernel.org/netdev/net/c/a48e23221000

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html




From Frank.Li at nxp.com  Mon Dec 29 08:51:27 2025
From: Frank.Li at nxp.com (Frank Li)
Date: Mon, 29 Dec 2025 11:51:27 -0500
Subject: [PATCH 1/1] arm64: dts: imx8mp-skov: add pinctrl-name 'reset' to fix CHECK_DTB warning
Message-ID: <20251229165127.4006134-1-Frank.Li@nxp.com>

Add pinctrl-name 'reset' to fix below CHECK_DTB warnings:
  arch/arm64/boot/dts/freescale/imx8mp-skov-basic.dtb: switch at 5f (microchip,ksz9893): pinctrl-names: ['default'] is too short
	from schema $id: http://devicetree.org/schemas/net/dsa/microchip,ksz.yaml#

The commit (e469b87e0fb0d dt-bindings: net: dsa: microchip: Add strap
description to set SPI mode" force use two pinctrl-name 'default' and
'reset'. switch at 5f doesn't use SPI, so it is safe to use the same pinctrl
setting for both.

Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
 arch/arm64/boot/dts/freescale/imx8mp-skov-reva.dtsi | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-skov-reva.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-skov-reva.dtsi
index 020f20c8ce667..7d2fc5fdd3bd1 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-skov-reva.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-skov-reva.dtsi
@@ -373,8 +373,8 @@ &i2c4 {
 
 	switch: switch at 5f {
 		compatible = "microchip,ksz9893";
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_switch>;
+		pinctrl-names = "default", "reset";
+		pinctrl-0 = <&pinctrl_switch>, <&pinctrl_switch>;
 		reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>;
 		reg = <0x5f>;
 
-- 
2.34.1



From nm at ti.com  Mon Dec 29 09:46:38 2025
From: nm at ti.com (Nishanth Menon)
Date: Mon, 29 Dec 2025 11:46:38 -0600
Subject: [PATCH v6] dt-bindings: arm: keystone: add boot_* mboxes to
 ti,sci
In-Reply-To: <e516b73b-2dc3-4ae4-966b-278a946491c8@kernel.org>
References: <20251222-k3_syscon_add_boot_mailboxes-v6-1-b93ada9f1d47@ti.com>
 <1844147d-543d-4739-a1ec-a59f8a4564fb@kernel.org>
 <DF5GPF5U7NPA.2ODE22YOF8E1R@ti.com>
 <e516b73b-2dc3-4ae4-966b-278a946491c8@kernel.org>
Message-ID: <20251229174638.btuhliymlmuy5op3@submarine>

Anshul,

On 14:40-20251223, Krzysztof Kozlowski wrote:
> On 23/12/2025 09:44, Anshul Dalal wrote:
> > On Mon Dec 22, 2025 at 2:23 PM IST, Krzysztof Kozlowski wrote:
> >> On 22/12/2025 09:43, Anshul Dalal wrote:
> >>> The bootloader on K3 devices makes use of mailboxes as per the ROM spec
> >>> which might be different than one's available to the kernel (firmware
> >>> spec).
> >>>
> >>> Therefore, this patch adds the missing mailbox entries to the DT binding
> >>> if the matching compatible is ti,am654-sci to represent the mailboxes
> >>> exposed by the hardware during boot for the purpose of loading the
> >>> firmware.
> >>>
> >>> The new ti,am642-sci compatible is also added to represent SoCs which do
> >>> not expose a "notify" channel as part of their TI-SCI spec such as AM64x
> >>> or the AM62 family. The newly added mboxes are made optional by keeping
> >>> minItems as 2 to remain compliant with existing device-trees.
> >>>
> >>> Signed-off-by: Anshul Dalal <anshuld at ti.com>
> >>> ---
> >>> Changes in v6:
> >>> - Added ti,am642-sci compatible to represent SoCs without a "notify" channel
> >>> - Added new examples instead of editing existing ones
> >>
> >> Why? Rob asked not to.
> > 
> > I had followed what Nishanth had said[1], I'll wait for him and Rob to
> > align first before posting the next revision.
> 
> 
> Existing examples are fine. There is no rule saying you need to keep
> updating examples or keep adding new device to examples. If someone told
> you about such rule, tell them to stop inventing rules...

As I had responded to Rob (the reference you posted), leave the
existing example in the binding as is, we do not need to add new
examples either for each of the compatibles. We have enough examples
in device tree now. So, IMHO, just update the binding.

-- 
Regards,
Nishanth Menon
Key (0xDDB5849D1736249D) / Fingerprint: F8A2 8693 54EB 8232 17A3  1A34 DDB5 849D 1736 249D
https://ti.com/opensource


From kevin.brodsky at arm.com  Mon Dec 29 10:03:35 2025
From: kevin.brodsky at arm.com (Kevin Brodsky)
Date: Mon, 29 Dec 2025 19:03:35 +0100
Subject: [PATCH v10 11/16] entry: Split syscall_exit_to_user_mode_work()
 for arch reuse
In-Reply-To: <20251222114737.1334364-12-ruanjinjie@huawei.com>
References: <20251222114737.1334364-1-ruanjinjie@huawei.com>
 <20251222114737.1334364-12-ruanjinjie@huawei.com>
Message-ID: <f3c32e7f-f940-4cb0-941c-cb7f7f628d88@arm.com>

On 22/12/2025 12:47, Jinjie Ruan wrote:
> In the generic entry code, the beginning of
> syscall_exit_to_user_mode_work() can be reused on arm64 so it makes
> sense to split it.
>
> In preparation for moving arm64 over to the generic entry
> code, split out syscall_exit_to_user_mode_work_prepare() helper from
> syscall_exit_to_user_mode_work().
>
> No functional changes.
>
> Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
> Reviewed-by: Thomas Gleixner <tglx at linutronix.de>
> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
> ---
>  include/linux/entry-common.h | 35 ++++++++++++++++++++++-------------
>  1 file changed, 22 insertions(+), 13 deletions(-)
>
> diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h
> index 87efb38b7081..0de0e60630e1 100644
> --- a/include/linux/entry-common.h
> +++ b/include/linux/entry-common.h
> @@ -121,20 +121,11 @@ static __always_inline long syscall_enter_from_user_mode(struct pt_regs *regs, l
>   */
>  void syscall_exit_work(struct pt_regs *regs, unsigned long work);
>  
> -/**
> - * syscall_exit_to_user_mode_work - Handle work before returning to user mode
> - * @regs:	Pointer to currents pt_regs
> - *
> - * Same as step 1 and 2 of syscall_exit_to_user_mode() but without calling
> - * exit_to_user_mode() to perform the final transition to user mode.
> - *
> - * Calling convention is the same as for syscall_exit_to_user_mode() and it
> - * returns with all work handled and interrupts disabled. The caller must
> - * invoke exit_to_user_mode() before actually switching to user mode to
> - * make the final state transitions. Interrupts must stay disabled between
> - * return from this function and the invocation of exit_to_user_mode().
> +/*
> + * Syscall specific exit to user mode preparation. Runs with interrupts
> + * enabled.
>   */
> -static __always_inline void syscall_exit_to_user_mode_work(struct pt_regs *regs)
> +static __always_inline void syscall_exit_to_user_mode_work_prepare(struct pt_regs *regs)
>  {
>  	unsigned long work = READ_ONCE(current_thread_info()->syscall_work);
>  	unsigned long nr = syscall_get_nr(current, regs);
> @@ -155,6 +146,24 @@ static __always_inline void syscall_exit_to_user_mode_work(struct pt_regs *regs)
>  	 */
>  	if (unlikely(work & SYSCALL_WORK_EXIT))
>  		syscall_exit_work(regs, work);
> +}
> +
> +/**
> + * syscall_exit_to_user_mode_work - Handle work before returning to user mode
> + * @regs:	Pointer to currents pt_regs
> + *
> + * Same as step 1 and 2 of syscall_exit_to_user_mode() but without calling
> + * exit_to_user_mode() to perform the final transition to user mode.
> + *
> + * Calling convention is the same as for syscall_exit_to_user_mode() and it
> + * returns with all work handled and interrupts disabled. The caller must
> + * invoke exit_to_user_mode() before actually switching to user mode to
> + * make the final state transitions. Interrupts must stay disabled between
> + * return from this function and the invocation of exit_to_user_mode().
> + */
> +static __always_inline void syscall_exit_to_user_mode_work(struct pt_regs *regs)
> +{
> +	syscall_exit_to_user_mode_work_prepare(regs);

The naming is getting awfully confusing, with the separate introduction
of syscall_exit_to_user_mode_prepare().

Having had a closer look, do we really need
syscall_exit_to_user_mode_work() as it currently stands? Nothing calls
it except the generic syscall_exit_to_user_mode(). Which makes me think:
how about moving the two lines below into syscall_exit_to_user_mode()
instead of creating a new helper? IOW:

@@ -155,8 +155,6 @@ static __always_inline void
syscall_exit_to_user_mode_work(struct pt_regs *regs)
? ? ? */
? ? ?if (unlikely(work & SYSCALL_WORK_EXIT))
? ? ? ? ?syscall_exit_work(regs, work);
-? ? local_irq_disable_exit_to_user();
-? ? syscall_exit_to_user_mode_prepare(regs);
?}
?
?/**
@@ -192,6 +190,8 @@ static __always_inline void
syscall_exit_to_user_mode(struct pt_regs *regs)
?{
? ? ?instrumentation_begin();
? ? ?syscall_exit_to_user_mode_work(regs);
+? ? local_irq_disable_exit_to_user();
+? ? syscall_exit_to_user_mode_prepare(regs);
? ? ?instrumentation_end();
? ? ?exit_to_user_mode();
?}

- Kevin

>  	local_irq_disable_exit_to_user();
>  	syscall_exit_to_user_mode_prepare(regs);
>  }


From andrew at lunn.ch  Mon Dec 29 10:20:35 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Mon, 29 Dec 2025 19:20:35 +0100
Subject: [PATCH v1 2/3] arm64: dts: freescale: Add support for Variscite
 DART-MX95
In-Reply-To: <20251229150421.57616-3-stefano.r@variscite.com>
References: <20251229150421.57616-1-stefano.r@variscite.com>
 <20251229150421.57616-3-stefano.r@variscite.com>
Message-ID: <b8349d9c-7a18-43bb-baaa-7e2ec62218b2@lunn.ch>

> +&enetc_port0 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_enetc0>;
> +	phy-handle = <&ethphy0>;
> +	/*
> +	 * The required RGMII TX and RX 2ns delays are implemented directly
> +	 * in hardware via passive delay elements on the SOM PCB.
> +	 * No delay configuration is needed in software via PHY driver.
> +	 */
> +	phy-mode = "rgmii";
> +	status = "okay";
> +};

> +&netc_emdio {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_emdio>, <&pinctrl_phy0res>;
> +	status = "okay";
> +
> +	ethphy0: ethernet-phy at 0 {
> +		reg = <0>;
> +		compatible = "ethernet-phy-ieee802.3-c22";
> +		reset-gpios = <&gpio5 16 GPIO_ACTIVE_LOW>;
> +		reset-assert-us = <10000>;
> +		reset-deassert-us = <100000>;
> +
> +		leds {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +
> +			led at 0 {
> +				reg = <0>;
> +				color = <LED_COLOR_ID_YELLOW>;
> +				function = LED_FUNCTION_LAN;
> +				linux,default-trigger = "netdev";
> +			};
> +
> +			led at 1 {
> +				reg = <1>;
> +				color = <LED_COLOR_ID_GREEN>;
> +				function = LED_FUNCTION_LAN;
> +				linux,default-trigger = "netdev";
> +			};
> +		};
> +	};
> +};

For these two nodes only:

Reviewed-by: Andrew Lunn <andrew at lunn.ch>

    Andrew


From andrew at lunn.ch  Mon Dec 29 10:24:50 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Mon, 29 Dec 2025 19:24:50 +0100
Subject: [PATCH v1 3/3] arm64: dts: imx95-var-dart: Add support for
 Variscite Sonata board
In-Reply-To: <20251229150421.57616-4-stefano.r@variscite.com>
References: <20251229150421.57616-1-stefano.r@variscite.com>
 <20251229150421.57616-4-stefano.r@variscite.com>
Message-ID: <0afc0945-af65-410d-8556-1d09792981cb@lunn.ch>

> +&enetc_port1 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_enetc1>;
> +	phy-handle = <&ethphy1>;
> +	/*
> +	 * The required RGMII TX and RX 2ns delays are implemented directly
> +	 * in hardware via passive delay elements on the SOM PCB.
> +	 * No delay configuration is needed in software via PHY driver.
> +	 */
> +	phy-mode = "rgmii";
> +	status = "okay";
> +};

This node is O.K, thanks for the comment.

> +
> +&enetc_port2 {
> +	phy-mode = "10gbase-r";
> +	status = "okay";
> +
> +	fixed-link {
> +		speed = <10000>;
> +		full-duplex;
> +		link-gpios = <&pca9534 1 GPIO_ACTIVE_LOW>;
> +	};
> +};

What is this ethernet connected to? In the commit message you mention
an SFP? So i would expect a phandle pointing to the SFP cage node,
which follows:

Documentation/devicetree/bindings/net/sff,sfp.yam

	Andrew


From robert.marko at sartura.hr  Mon Dec 29 10:37:41 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Mon, 29 Dec 2025 19:37:41 +0100
Subject: [PATCH v4 00/15] Add support for Microchip LAN969x
Message-ID: <20251229184004.571837-1-robert.marko@sartura.hr>

This series adds support for the Microchip LAN969x switch SoC family.

Series is a bit long since after discussions in previous versions, it was
recommended[1][2] to add SoC specific compatibles for device nodes so it
includes the required bindings updates.

[1] https://lore.kernel.org/all/20251203-splendor-cubbyhole-eda2d6982b46 at spud/
[2] https://lore.kernel.org/all/173412c8-c2fb-4c38-8de7-5b1c2eebdbf9 at microchip.com/
[3] https://lore.kernel.org/all/20251203-duly-leotard-86b83bd840c6 at spud/
[4] https://lore.kernel.org/all/756ead5d-8c9b-480d-8ae5-71667575ab7c at kernel.org/

Signed-off-by: Robert Marko <robert.marko at sartura.hr>

Changes in v4:
* Pick Acked-by from Andi for I2C bindings
* Move clock indexes from dt-bindings into a DTS header as suggested by
Krzysztof[4]

Changes in v3:
* Pick Acked-by from Conor
* Drop HWMON binding as it was picked into hwmon already
* Document EV23X71A into AT91 binding
* Drop SparX-5 and AT91 bindings merge
* Apply remark from Conor on DMA binding regarding merging cases

Changes in v2:
* Change LAN969x wildcards to LAN9691 in patches
* Split SoC DTSI and evaluation board patches
* Add the suggested binding changes required for SoC specific compatibles
* Merge SparX-5 and AT91 bindings as suggested[3]

Robert Marko (15):
  dt-bindings: usb: Add Microchip LAN969x support
  dt-bindings: mfd: atmel,sama5d2-flexcom: add microchip,lan9691-flexcom
  dt-bindings: serial: atmel,at91-usart: add microchip,lan9691-usart
  dt-bindings: spi: at91: add microchip,lan9691-spi
  dt-bindings: i2c: atmel,at91sam: add microchip,lan9691-i2c
  dt-bindings: rng: atmel,at91-trng: add microchip,lan9691-trng
  dt-bindings: crypto: atmel,at91sam9g46-aes: add microchip,lan9691-aes
  dt-bindings: crypto: atmel,at91sam9g46-sha: add microchip,lan9691-sha
  dt-bindings: dma: atmel: add microchip,lan9691-dma
  dt-bindings: net: mscc-miim: add microchip,lan9691-miim
  dt-bindings: pinctrl: pinctrl-microchip-sgpio: add LAN969x
  arm64: dts: microchip: add LAN969x clock header file
  arm64: dts: microchip: add LAN969x support
  dt-bindings: arm: AT91: document EV23X71A board
  arm64: dts: microchip: add EV23X71A board

 .../devicetree/bindings/arm/atmel-at91.yaml   |   6 +
 .../crypto/atmel,at91sam9g46-aes.yaml         |   1 +
 .../crypto/atmel,at91sam9g46-sha.yaml         |   1 +
 .../bindings/dma/atmel,sama5d4-dma.yaml       |   4 +-
 .../bindings/i2c/atmel,at91sam-i2c.yaml       |   1 +
 .../bindings/mfd/atmel,sama5d2-flexcom.yaml   |   1 +
 .../devicetree/bindings/net/mscc,miim.yaml    |  11 +-
 .../pinctrl/microchip,sparx5-sgpio.yaml       |  20 +-
 .../bindings/rng/atmel,at91-trng.yaml         |   1 +
 .../bindings/serial/atmel,at91-usart.yaml     |   1 +
 .../bindings/spi/atmel,at91rm9200-spi.yaml    |   1 +
 .../bindings/usb/microchip,lan9691-dwc3.yaml  |  66 ++
 arch/arm64/boot/dts/microchip/Makefile        |   1 +
 arch/arm64/boot/dts/microchip/clk-lan9691.h   |  24 +
 arch/arm64/boot/dts/microchip/lan9691.dtsi    | 488 +++++++++++
 .../boot/dts/microchip/lan9696-ev23x71a.dts   | 757 ++++++++++++++++++
 16 files changed, 1375 insertions(+), 9 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/usb/microchip,lan9691-dwc3.yaml
 create mode 100644 arch/arm64/boot/dts/microchip/clk-lan9691.h
 create mode 100644 arch/arm64/boot/dts/microchip/lan9691.dtsi
 create mode 100644 arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts

-- 
2.52.0



From robert.marko at sartura.hr  Mon Dec 29 10:37:42 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Mon, 29 Dec 2025 19:37:42 +0100
Subject: [PATCH v4 01/15] dt-bindings: usb: Add Microchip LAN969x support
In-Reply-To: <20251229184004.571837-1-robert.marko@sartura.hr>
References: <20251229184004.571837-1-robert.marko@sartura.hr>
Message-ID: <20251229184004.571837-2-robert.marko@sartura.hr>

Microchip LAN969x has DWC3 compatible controller, though limited to 2.0(HS)
speed, so document it.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
---
Changes in v2:
* Fix example indentation

 .../bindings/usb/microchip,lan9691-dwc3.yaml  | 66 +++++++++++++++++++
 1 file changed, 66 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/usb/microchip,lan9691-dwc3.yaml

diff --git a/Documentation/devicetree/bindings/usb/microchip,lan9691-dwc3.yaml b/Documentation/devicetree/bindings/usb/microchip,lan9691-dwc3.yaml
new file mode 100644
index 000000000000..08113eac74b8
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/microchip,lan9691-dwc3.yaml
@@ -0,0 +1,66 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/microchip,lan9691-dwc3.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Microchip LAN969x SuperSpeed DWC3 USB SoC controller
+
+maintainers:
+  - Robert Marko <robert.marko at sartura.hr>
+
+select:
+  properties:
+    compatible:
+      contains:
+        enum:
+          - microchip,lan9691-dwc3
+  required:
+    - compatible
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - microchip,lan9691-dwc3
+      - const: snps,dwc3
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: Gated USB DRD clock
+      - description: Controller reference clock
+
+  clock-names:
+    items:
+      - const: bus_early
+      - const: ref
+
+unevaluatedProperties: false
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+
+allOf:
+  - $ref: snps,dwc3.yaml#
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    usb at 300000 {
+        compatible = "microchip,lan9691-dwc3", "snps,dwc3";
+        reg = <0x300000 0x80000>;
+        interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&clks 12>, <&clks 11>;
+        clock-names = "bus_early", "ref";
+    };
-- 
2.52.0



From robert.marko at sartura.hr  Mon Dec 29 10:37:43 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Mon, 29 Dec 2025 19:37:43 +0100
Subject: [PATCH v4 02/15] dt-bindings: mfd: atmel,sama5d2-flexcom: add microchip,lan9691-flexcom
In-Reply-To: <20251229184004.571837-1-robert.marko@sartura.hr>
References: <20251229184004.571837-1-robert.marko@sartura.hr>
Message-ID: <20251229184004.571837-3-robert.marko@sartura.hr>

Add binding documentation for Microchip LAN969x.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
Changes in v3:
* Pick Acked-by from Conor

 Documentation/devicetree/bindings/mfd/atmel,sama5d2-flexcom.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/mfd/atmel,sama5d2-flexcom.yaml b/Documentation/devicetree/bindings/mfd/atmel,sama5d2-flexcom.yaml
index c7d6cf96796c..5e5dec2f6564 100644
--- a/Documentation/devicetree/bindings/mfd/atmel,sama5d2-flexcom.yaml
+++ b/Documentation/devicetree/bindings/mfd/atmel,sama5d2-flexcom.yaml
@@ -20,6 +20,7 @@ properties:
       - const: atmel,sama5d2-flexcom
       - items:
           - enum:
+              - microchip,lan9691-flexcom
               - microchip,sam9x7-flexcom
               - microchip,sama7d65-flexcom
               - microchip,sama7g5-flexcom
-- 
2.52.0



From robert.marko at sartura.hr  Mon Dec 29 10:37:44 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Mon, 29 Dec 2025 19:37:44 +0100
Subject: [PATCH v4 03/15] dt-bindings: serial: atmel,at91-usart: add microchip,lan9691-usart
In-Reply-To: <20251229184004.571837-1-robert.marko@sartura.hr>
References: <20251229184004.571837-1-robert.marko@sartura.hr>
Message-ID: <20251229184004.571837-4-robert.marko@sartura.hr>

Document Microchip LAN969x USART compatible.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
Changes in v3:
* Pick Acked-by from Conor

 Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml b/Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml
index 087a8926f8b4..375cd50bc5cc 100644
--- a/Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml
+++ b/Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml
@@ -24,6 +24,7 @@ properties:
           - const: atmel,at91sam9260-usart
       - items:
           - enum:
+              - microchip,lan9691-usart
               - microchip,sam9x60-usart
               - microchip,sam9x7-usart
               - microchip,sama7d65-usart
-- 
2.52.0



From robert.marko at sartura.hr  Mon Dec 29 10:37:45 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Mon, 29 Dec 2025 19:37:45 +0100
Subject: [PATCH v4 04/15] dt-bindings: spi: at91: add microchip,lan9691-spi
In-Reply-To: <20251229184004.571837-1-robert.marko@sartura.hr>
References: <20251229184004.571837-1-robert.marko@sartura.hr>
Message-ID: <20251229184004.571837-5-robert.marko@sartura.hr>

Document Microchip LAN969x SPI compatible.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
Changes in v3:
* Pick Acked-by from Conor

 Documentation/devicetree/bindings/spi/atmel,at91rm9200-spi.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/spi/atmel,at91rm9200-spi.yaml b/Documentation/devicetree/bindings/spi/atmel,at91rm9200-spi.yaml
index 11885d0cc209..a8539b68a2f3 100644
--- a/Documentation/devicetree/bindings/spi/atmel,at91rm9200-spi.yaml
+++ b/Documentation/devicetree/bindings/spi/atmel,at91rm9200-spi.yaml
@@ -19,6 +19,7 @@ properties:
       - const: atmel,at91rm9200-spi
       - items:
           - enum:
+              - microchip,lan9691-spi
               - microchip,sam9x60-spi
               - microchip,sam9x7-spi
               - microchip,sama7d65-spi
-- 
2.52.0



From robert.marko at sartura.hr  Mon Dec 29 10:37:46 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Mon, 29 Dec 2025 19:37:46 +0100
Subject: [PATCH v4 05/15] dt-bindings: i2c: atmel,at91sam: add microchip,lan9691-i2c
In-Reply-To: <20251229184004.571837-1-robert.marko@sartura.hr>
References: <20251229184004.571837-1-robert.marko@sartura.hr>
Message-ID: <20251229184004.571837-6-robert.marko@sartura.hr>

Document Microchip LAN969x I2C compatible.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
Acked-by: Andi Shyti <andi.shyti at kernel.org>
---
Changes in v4:
* Pick Acked-by from Andi

Changes in v3:
* Pick Acked-by from Conor

 Documentation/devicetree/bindings/i2c/atmel,at91sam-i2c.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/i2c/atmel,at91sam-i2c.yaml b/Documentation/devicetree/bindings/i2c/atmel,at91sam-i2c.yaml
index e61cdb5b16ef..c83674c3183b 100644
--- a/Documentation/devicetree/bindings/i2c/atmel,at91sam-i2c.yaml
+++ b/Documentation/devicetree/bindings/i2c/atmel,at91sam-i2c.yaml
@@ -26,6 +26,7 @@ properties:
               - microchip,sam9x60-i2c
       - items:
           - enum:
+              - microchip,lan9691-i2c
               - microchip,sama7d65-i2c
               - microchip,sama7g5-i2c
               - microchip,sam9x7-i2c
-- 
2.52.0



From robert.marko at sartura.hr  Mon Dec 29 10:37:47 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Mon, 29 Dec 2025 19:37:47 +0100
Subject: [PATCH v4 06/15] dt-bindings: rng: atmel,at91-trng: add microchip,lan9691-trng
In-Reply-To: <20251229184004.571837-1-robert.marko@sartura.hr>
References: <20251229184004.571837-1-robert.marko@sartura.hr>
Message-ID: <20251229184004.571837-7-robert.marko@sartura.hr>

Document Microchip LAN9696X TRNG compatible.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
Changes in v3:
* Pick Acked-by from Conor

 Documentation/devicetree/bindings/rng/atmel,at91-trng.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/rng/atmel,at91-trng.yaml b/Documentation/devicetree/bindings/rng/atmel,at91-trng.yaml
index f78614100ea8..3628251b8c51 100644
--- a/Documentation/devicetree/bindings/rng/atmel,at91-trng.yaml
+++ b/Documentation/devicetree/bindings/rng/atmel,at91-trng.yaml
@@ -19,6 +19,7 @@ properties:
           - microchip,sam9x60-trng
       - items:
           - enum:
+              - microchip,lan9691-trng
               - microchip,sama7g5-trng
           - const: atmel,at91sam9g45-trng
       - items:
-- 
2.52.0



From robert.marko at sartura.hr  Mon Dec 29 10:37:48 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Mon, 29 Dec 2025 19:37:48 +0100
Subject: [PATCH v4 07/15] dt-bindings: crypto: atmel,at91sam9g46-aes: add microchip,lan9691-aes
In-Reply-To: <20251229184004.571837-1-robert.marko@sartura.hr>
References: <20251229184004.571837-1-robert.marko@sartura.hr>
Message-ID: <20251229184004.571837-8-robert.marko@sartura.hr>

Document Microchip LAN969x AES compatible.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
Changes in v3:
* Pick Acked-by from Conor

 .../devicetree/bindings/crypto/atmel,at91sam9g46-aes.yaml        | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-aes.yaml b/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-aes.yaml
index 19010f90198a..f3b6af6baf15 100644
--- a/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-aes.yaml
+++ b/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-aes.yaml
@@ -16,6 +16,7 @@ properties:
       - const: atmel,at91sam9g46-aes
       - items:
           - enum:
+              - microchip,lan9691-aes
               - microchip,sam9x7-aes
               - microchip,sama7d65-aes
           - const: atmel,at91sam9g46-aes
-- 
2.52.0



From robert.marko at sartura.hr  Mon Dec 29 10:37:49 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Mon, 29 Dec 2025 19:37:49 +0100
Subject: [PATCH v4 08/15] dt-bindings: crypto: atmel,at91sam9g46-sha: add microchip,lan9691-sha
In-Reply-To: <20251229184004.571837-1-robert.marko@sartura.hr>
References: <20251229184004.571837-1-robert.marko@sartura.hr>
Message-ID: <20251229184004.571837-9-robert.marko@sartura.hr>

Document Microchip LAN969x SHA compatible.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
Changes in v3:
* Pick Acked-by from Conor

 .../devicetree/bindings/crypto/atmel,at91sam9g46-sha.yaml        | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-sha.yaml b/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-sha.yaml
index 39e076b275b3..16704ff0dd7f 100644
--- a/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-sha.yaml
+++ b/Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-sha.yaml
@@ -16,6 +16,7 @@ properties:
       - const: atmel,at91sam9g46-sha
       - items:
           - enum:
+              - microchip,lan9691-sha
               - microchip,sam9x7-sha
               - microchip,sama7d65-sha
           - const: atmel,at91sam9g46-sha
-- 
2.52.0



From robert.marko at sartura.hr  Mon Dec 29 10:37:50 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Mon, 29 Dec 2025 19:37:50 +0100
Subject: [PATCH v4 09/15] dt-bindings: dma: atmel: add microchip,lan9691-dma
In-Reply-To: <20251229184004.571837-1-robert.marko@sartura.hr>
References: <20251229184004.571837-1-robert.marko@sartura.hr>
Message-ID: <20251229184004.571837-10-robert.marko@sartura.hr>

Document Microchip LAN969x DMA compatible which is compatible to SAMA7G5.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
---
Changes in v3:
* Merged with microchip,sama7d65-dma since that also falls back to
microchip,sama7g5-dma

 Documentation/devicetree/bindings/dma/atmel,sama5d4-dma.yaml | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/dma/atmel,sama5d4-dma.yaml b/Documentation/devicetree/bindings/dma/atmel,sama5d4-dma.yaml
index 73fc13b902b3..197efb19b07a 100644
--- a/Documentation/devicetree/bindings/dma/atmel,sama5d4-dma.yaml
+++ b/Documentation/devicetree/bindings/dma/atmel,sama5d4-dma.yaml
@@ -33,7 +33,9 @@ properties:
               - microchip,sam9x7-dma
           - const: atmel,sama5d4-dma
       - items:
-          - const: microchip,sama7d65-dma
+          - enum:
+              - microchip,lan9691-dma
+              - microchip,sama7d65-dma
           - const: microchip,sama7g5-dma
 
   "#dma-cells":
-- 
2.52.0



From robert.marko at sartura.hr  Mon Dec 29 10:37:51 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Mon, 29 Dec 2025 19:37:51 +0100
Subject: [PATCH v4 10/15] dt-bindings: net: mscc-miim: add microchip,lan9691-miim
In-Reply-To: <20251229184004.571837-1-robert.marko@sartura.hr>
References: <20251229184004.571837-1-robert.marko@sartura.hr>
Message-ID: <20251229184004.571837-11-robert.marko@sartura.hr>

Document Microchip LAN969x MIIM compatible.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
Changes in v3:
* Pick Acked-by from Conor

 Documentation/devicetree/bindings/net/mscc,miim.yaml | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/mscc,miim.yaml b/Documentation/devicetree/bindings/net/mscc,miim.yaml
index 792f26b06b06..2207b33aee76 100644
--- a/Documentation/devicetree/bindings/net/mscc,miim.yaml
+++ b/Documentation/devicetree/bindings/net/mscc,miim.yaml
@@ -14,9 +14,14 @@ allOf:
 
 properties:
   compatible:
-    enum:
-      - mscc,ocelot-miim
-      - microchip,lan966x-miim
+    oneOf:
+      - enum:
+          - mscc,ocelot-miim
+          - microchip,lan966x-miim
+      - items:
+          - enum:
+              - microchip,lan9691-miim
+          - const: mscc,ocelot-miim
 
   "#address-cells":
     const: 1
-- 
2.52.0



From robert.marko at sartura.hr  Mon Dec 29 10:37:52 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Mon, 29 Dec 2025 19:37:52 +0100
Subject: [PATCH v4 11/15] dt-bindings: pinctrl: pinctrl-microchip-sgpio: add LAN969x
In-Reply-To: <20251229184004.571837-1-robert.marko@sartura.hr>
References: <20251229184004.571837-1-robert.marko@sartura.hr>
Message-ID: <20251229184004.571837-12-robert.marko@sartura.hr>

Document LAN969x compatibles for SGPIO.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
Changes in v3:
* Pick Acked-by from Conor

 .../pinctrl/microchip,sparx5-sgpio.yaml       | 20 ++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/Documentation/devicetree/bindings/pinctrl/microchip,sparx5-sgpio.yaml b/Documentation/devicetree/bindings/pinctrl/microchip,sparx5-sgpio.yaml
index fa47732d7cef..9fbbafcdc063 100644
--- a/Documentation/devicetree/bindings/pinctrl/microchip,sparx5-sgpio.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/microchip,sparx5-sgpio.yaml
@@ -21,10 +21,15 @@ properties:
     pattern: '^gpio@[0-9a-f]+$'
 
   compatible:
-    enum:
-      - microchip,sparx5-sgpio
-      - mscc,ocelot-sgpio
-      - mscc,luton-sgpio
+    oneOf:
+      - enum:
+          - microchip,sparx5-sgpio
+          - mscc,ocelot-sgpio
+          - mscc,luton-sgpio
+      - items:
+          - enum:
+              - microchip,lan9691-sgpio
+          - const: microchip,sparx5-sgpio
 
   '#address-cells':
     const: 1
@@ -80,7 +85,12 @@ patternProperties:
     type: object
     properties:
       compatible:
-        const: microchip,sparx5-sgpio-bank
+        oneOf:
+          - items:
+              - enum:
+                  - microchip,lan9691-sgpio-bank
+              - const: microchip,sparx5-sgpio-bank
+          - const: microchip,sparx5-sgpio-bank
 
       reg:
         description: |
-- 
2.52.0



From robert.marko at sartura.hr  Mon Dec 29 10:37:53 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Mon, 29 Dec 2025 19:37:53 +0100
Subject: [PATCH v4 12/15] arm64: dts: microchip: add LAN969x clock header file
In-Reply-To: <20251229184004.571837-1-robert.marko@sartura.hr>
References: <20251229184004.571837-1-robert.marko@sartura.hr>
Message-ID: <20251229184004.571837-13-robert.marko@sartura.hr>

LAN969x uses hardware clock indexes, so document theses in a header to make
them humanly readable.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
---
Changes in v4:
* Move clock indexes from dt-bindings to a DTS header

Changes in v2:
* Rename file to microchip,lan9691.h

 arch/arm64/boot/dts/microchip/clk-lan9691.h | 24 +++++++++++++++++++++
 1 file changed, 24 insertions(+)
 create mode 100644 arch/arm64/boot/dts/microchip/clk-lan9691.h

diff --git a/arch/arm64/boot/dts/microchip/clk-lan9691.h b/arch/arm64/boot/dts/microchip/clk-lan9691.h
new file mode 100644
index 000000000000..f0006a603747
--- /dev/null
+++ b/arch/arm64/boot/dts/microchip/clk-lan9691.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+
+#ifndef _DTS_CLK_LAN9691_H
+#define _DTS_CLK_LAN9691_H
+
+#define GCK_ID_QSPI0		0
+#define GCK_ID_QSPI2		1
+#define GCK_ID_SDMMC0		2
+#define GCK_ID_SDMMC1		3
+#define GCK_ID_MCAN0		4
+#define GCK_ID_MCAN1		5
+#define GCK_ID_FLEXCOM0		6
+#define GCK_ID_FLEXCOM1		7
+#define GCK_ID_FLEXCOM2		8
+#define GCK_ID_FLEXCOM3		9
+#define GCK_ID_TIMER		10
+#define GCK_ID_USB_REFCLK	11
+
+/* Gate clocks */
+#define GCK_GATE_USB_DRD	12
+#define GCK_GATE_MCRAMC		13
+#define GCK_GATE_HMATRIX	14
+
+#endif
-- 
2.52.0



From robert.marko at sartura.hr  Mon Dec 29 10:37:54 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Mon, 29 Dec 2025 19:37:54 +0100
Subject: [PATCH v4 13/15] arm64: dts: microchip: add LAN969x support
In-Reply-To: <20251229184004.571837-1-robert.marko@sartura.hr>
References: <20251229184004.571837-1-robert.marko@sartura.hr>
Message-ID: <20251229184004.571837-14-robert.marko@sartura.hr>

Add support for Microchip LAN969x switch SoC series by adding the SoC DTSI.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
---
Changes in v4:
* Adapt to clock indexes now being in a DTS header only

Changes in v2:
* Rename to lan9691
* Split SoC DTSI and evaluation board commits
* Use SoC specific compatibles for devices
* Alphanumerically sort remaining nodes
* Apply DTS coding style

 arch/arm64/boot/dts/microchip/lan9691.dtsi | 488 +++++++++++++++++++++
 1 file changed, 488 insertions(+)
 create mode 100644 arch/arm64/boot/dts/microchip/lan9691.dtsi

diff --git a/arch/arm64/boot/dts/microchip/lan9691.dtsi b/arch/arm64/boot/dts/microchip/lan9691.dtsi
new file mode 100644
index 000000000000..235e56bebbdb
--- /dev/null
+++ b/arch/arm64/boot/dts/microchip/lan9691.dtsi
@@ -0,0 +1,488 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT)
+/*
+ * Copyright (c) 2025 Microchip Technology Inc. and its subsidiaries.
+ */
+
+#include <dt-bindings/dma/at91.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/mfd/at91-usart.h>
+#include <dt-bindings/mfd/atmel-flexcom.h>
+
+#include "clk-lan9691.h"
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	model = "Microchip LAN969x";
+	compatible = "microchip,lan9691";
+	interrupt-parent = <&gic>;
+
+	clocks {
+		fx100_clk: fx100-clk {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <320000000>;
+		};
+
+		cpu_clk: cpu-clk {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <1000000000>;
+		};
+
+		ddr_clk: ddr-clk {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <600000000>;
+		};
+
+		fabric_clk: fabric-clk {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <250000000>;
+		};
+	};
+
+	cpus {
+		#address-cells = <2>;
+		#size-cells = <0>;
+
+		cpu0: cpu at 0 {
+			compatible = "arm,cortex-a53";
+			device_type = "cpu";
+			reg = <0x0 0x0>;
+			next-level-cache = <&l2_0>;
+		};
+
+		l2_0: l2-cache {
+			compatible = "cache";
+			cache-level = <2>;
+			cache-unified;
+		};
+	};
+
+	psci {
+		compatible = "arm,psci-1.0";
+		method = "smc";
+	};
+
+	pmu {
+		compatible = "arm,cortex-a53-pmu";
+		interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>, /* Secure Phys IRQ */
+			     <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>, /* Non-secure Phys IRQ */
+			     <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>, /* Virt IRQ */
+			     <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>; /* Hyp IRQ */
+	};
+
+	axi: axi {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		usb: usb at 300000 {
+			compatible = "microchip,lan9691-dwc3", "snps,dwc3";
+			reg = <0x300000 0x80000>;
+			interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clks GCK_GATE_USB_DRD>,
+				 <&clks GCK_ID_USB_REFCLK>;
+			clock-names = "bus_early", "ref";
+			assigned-clocks = <&clks GCK_ID_USB_REFCLK>;
+			assigned-clock-rates = <60000000>;
+			maximum-speed = "high-speed";
+			dr_mode = "host";
+			status = "disabled";
+		};
+
+		flx0: flexcom at e0040000 {
+			compatible = "microchip,lan9691-flexcom", "atmel,sama5d2-flexcom";
+			reg = <0xe0040000 0x100>;
+			ranges = <0x0 0xe0040000 0x800>;
+			clocks = <&clks GCK_ID_FLEXCOM0>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			status = "disabled";
+
+			usart0: serial at 200 {
+				compatible = "microchip,lan9691-usart", "atmel,at91sam9260-usart";
+				reg = <0x200 0x200>;
+				interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
+				       <&dma AT91_XDMAC_DT_PERID(2)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				clock-names = "usart";
+				atmel,fifo-size = <32>;
+				atmel,usart-mode = <AT91_USART_MODE_SERIAL>;
+				status = "disabled";
+			};
+
+			spi0: spi at 400 {
+				compatible = "microchip,lan9691-spi", "atmel,at91rm9200-spi";
+				reg = <0x400 0x200>;
+				interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
+				       <&dma AT91_XDMAC_DT_PERID(2)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				clock-names = "spi_clk";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				atmel,fifo-size = <32>;
+				status = "disabled";
+			};
+
+			i2c0: i2c at 600 {
+				compatible = "microchip,lan9691-i2c", "microchip,sam9x60-i2c";
+				reg = <0x600 0x200>;
+				interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
+				       <&dma AT91_XDMAC_DT_PERID(2)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+		};
+
+		flx1: flexcom at e0044000 {
+			compatible = "microchip,lan9691-flexcom", "atmel,sama5d2-flexcom";
+			reg = <0xe0044000 0x100>;
+			ranges = <0x0 0xe0044000 0x800>;
+			clocks = <&clks GCK_ID_FLEXCOM1>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			status = "disabled";
+
+			usart1: serial at 200 {
+				compatible = "microchip,lan9691-usart", "atmel,at91sam9260-usart";
+				reg = <0x200 0x200>;
+				interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
+				       <&dma AT91_XDMAC_DT_PERID(2)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				clock-names = "usart";
+				atmel,fifo-size = <32>;
+				atmel,usart-mode = <AT91_USART_MODE_SERIAL>;
+				status = "disabled";
+			};
+
+			spi1: spi at 400 {
+				compatible = "microchip,lan9691-spi", "atmel,at91rm9200-spi";
+				reg = <0x400 0x200>;
+				interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
+				       <&dma AT91_XDMAC_DT_PERID(2)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				clock-names = "spi_clk";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				atmel,fifo-size = <32>;
+				status = "disabled";
+			};
+
+			i2c1: i2c at 600 {
+				compatible = "microchip,lan9691-i2c", "microchip,sam9x60-i2c";
+				reg = <0x600 0x200>;
+				interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
+				       <&dma AT91_XDMAC_DT_PERID(2)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+		};
+
+		trng: rng at e0048000 {
+			compatible = "microchip,lan9691-trng", "atmel,at91sam9g45-trng";
+			reg = <0xe0048000 0x100>;
+			clocks = <&fabric_clk>;
+			status = "disabled";
+		};
+
+		aes: crypto at e004c000 {
+			compatible = "microchip,lan9691-aes", "atmel,at91sam9g46-aes";
+			reg = <0xe004c000 0x100>;
+			interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&dma AT91_XDMAC_DT_PERID(12)>,
+			       <&dma AT91_XDMAC_DT_PERID(13)>;
+			dma-names = "tx", "rx";
+			clocks = <&fabric_clk>;
+			clock-names = "aes_clk";
+			status = "disabled";
+		};
+
+		flx2: flexcom at e0060000 {
+			compatible = "microchip,lan9691-flexcom", "atmel,sama5d2-flexcom";
+			reg = <0xe0060000 0x100>;
+			ranges = <0x0 0xe0060000 0x800>;
+			clocks = <&clks GCK_ID_FLEXCOM2>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			status = "disabled";
+
+			usart2: serial at 200 {
+				compatible = "microchip,lan9691-usart", "atmel,at91sam9260-usart";
+				reg = <0x200 0x200>;
+				interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(7)>,
+				       <&dma AT91_XDMAC_DT_PERID(6)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				clock-names = "usart";
+				atmel,fifo-size = <32>;
+				atmel,usart-mode = <AT91_USART_MODE_SERIAL>;
+				status = "disabled";
+			};
+
+			spi2: spi at 400 {
+				compatible = "microchip,lan9691-spi", "atmel,at91rm9200-spi";
+				reg = <0x400 0x200>;
+				interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(7)>,
+				       <&dma AT91_XDMAC_DT_PERID(6)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				clock-names = "spi_clk";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				atmel,fifo-size = <32>;
+				status = "disabled";
+			};
+
+			i2c2: i2c at 600 {
+				compatible = "microchip,lan9691-i2c", "microchip,sam9x60-i2c";
+				reg = <0x600 0x200>;
+				interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(7)>,
+				       <&dma AT91_XDMAC_DT_PERID(6)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+		};
+
+		flx3: flexcom at e0064000 {
+			compatible = "microchip,lan9691-flexcom", "atmel,sama5d2-flexcom";
+			reg = <0xe0064000 0x100>;
+			ranges = <0x0 0xe0064000 0x800>;
+			clocks = <&clks GCK_ID_FLEXCOM3>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			status = "disabled";
+
+			usart3: serial at 200 {
+				compatible = "microchip,lan9691-usart", "atmel,at91sam9260-usart";
+				reg = <0x200 0x200>;
+				interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(9)>,
+				       <&dma AT91_XDMAC_DT_PERID(8)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				clock-names = "usart";
+				atmel,fifo-size = <32>;
+				atmel,usart-mode = <AT91_USART_MODE_SERIAL>;
+				status = "disabled";
+			};
+
+			spi3: spi at 400 {
+				compatible = "microchip,lan9691-spi", "atmel,at91rm9200-spi";
+				reg = <0x400 0x200>;
+				interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(9)>,
+				       <&dma AT91_XDMAC_DT_PERID(8)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				clock-names = "spi_clk";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				atmel,fifo-size = <32>;
+				status = "disabled";
+			};
+
+			i2c3: i2c at 600 {
+				compatible = "microchip,lan9691-i2c", "microchip,sam9x60-i2c";
+				reg = <0x600 0x200>;
+				interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&dma AT91_XDMAC_DT_PERID(9)>,
+				       <&dma AT91_XDMAC_DT_PERID(8)>;
+				dma-names = "tx", "rx";
+				clocks = <&fabric_clk>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+		};
+
+		dma: dma-controller at e0068000 {
+			compatible = "microchip,lan9691-dma", "microchip,sama7g5-dma";
+			reg = <0xe0068000 0x1000>;
+			interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+			dma-channels = <16>;
+			#dma-cells = <1>;
+			clocks = <&fabric_clk>;
+			clock-names = "dma_clk";
+		};
+
+		sha: crypto at e006c000 {
+			compatible = "microchip,lan9691-sha", "atmel,at91sam9g46-sha";
+			reg = <0xe006c000 0xec>;
+			interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&dma AT91_XDMAC_DT_PERID(14)>;
+			dma-names = "tx";
+			clocks = <&fabric_clk>;
+			clock-names = "sha_clk";
+			status = "disabled";
+		};
+
+		timer: timer at e008c000 {
+			compatible = "snps,dw-apb-timer";
+			reg = <0xe008c000 0x400>;
+			clocks = <&fabric_clk>;
+			clock-names = "timer";
+			interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
+		};
+
+		watchdog: watchdog at e0090000 {
+			compatible = "snps,dw-wdt";
+			reg = <0xe0090000 0x1000>;
+			interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&fabric_clk>;
+		};
+
+		cpu_ctrl: syscon at e00c0000 {
+			compatible = "microchip,lan966x-cpu-syscon", "syscon";
+			reg = <0xe00c0000 0x350>;
+		};
+
+		switch: switch at e00c0000 {
+			compatible = "microchip,lan9691-switch";
+			reg = <0xe00c0000 0x0010000>,
+			      <0xe2010000 0x1410000>;
+			reg-names = "cpu", "devices";
+			interrupt-names = "xtr", "fdma", "ptp";
+			interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI  9 IRQ_TYPE_LEVEL_HIGH>;
+			resets = <&reset 0>;
+			reset-names = "switch";
+			status = "disabled";
+		};
+
+		clks: clock-controller at e00c00b4 {
+			compatible = "microchip,lan9691-gck";
+			reg = <0xe00c00b4 0x30>, <0xe00c0308 0x4>;
+			#clock-cells = <1>;
+			clocks = <&cpu_clk>, <&ddr_clk>, <&fx100_clk>;
+			clock-names = "cpu", "ddr", "sys";
+		};
+
+		reset: reset-controller at e201000c {
+			compatible = "microchip,lan9691-switch-reset",
+				     "microchip,lan966x-switch-reset";
+			reg = <0xe201000c 0x4>;
+			reg-names = "gcb";
+			#reset-cells = <1>;
+			cpu-syscon = <&cpu_ctrl>;
+		};
+
+		gpio: pinctrl at e20100d4 {
+			compatible = "microchip,lan9691-pinctrl";
+			reg = <0xe20100d4 0xd4>,
+			      <0xe2010370 0xa8>;
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&gpio 0 0 66>;
+			interrupt-controller;
+			interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+			#interrupt-cells = <2>;
+		};
+
+		mdio0: mdio at e20101a8 {
+			compatible = "microchip,lan9691-miim", "mscc,ocelot-miim";
+			reg = <0xe20101a8 0x24>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clocks = <&fx100_clk>;
+			status = "disabled";
+		};
+
+		mdio1: mdio at e20101cc {
+			compatible = "microchip,lan9691-miim", "mscc,ocelot-miim";
+			reg = <0xe20101cc 0x24>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clocks = <&fx100_clk>;
+			status = "disabled";
+		};
+
+		sgpio: gpio at e2010230 {
+			compatible = "microchip,lan9691-sgpio", "microchip,sparx5-sgpio";
+			reg = <0xe2010230 0x118>;
+			clocks = <&fx100_clk>;
+			resets = <&reset 0>;
+			reset-names = "switch";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+
+			sgpio_in: gpio at 0 {
+				compatible = "microchip,lan9691-sgpio-bank",
+					     "microchip,sparx5-sgpio-bank";
+				reg = <0>;
+				gpio-controller;
+				#gpio-cells = <3>;
+				interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-controller;
+				#interrupt-cells = <3>;
+			};
+
+			sgpio_out: gpio at 1 {
+				compatible = "microchip,lan9691-sgpio-bank",
+					     "microchip,sparx5-sgpio-bank";
+				reg = <1>;
+				gpio-controller;
+				#gpio-cells = <3>;
+			};
+		};
+
+		tmon: hwmon at e2020100 {
+			compatible = "microchip,lan9691-temp", "microchip,sparx5-temp";
+			reg = <0xe2020100 0xc>;
+			clocks = <&fx100_clk>;
+			#thermal-sensor-cells = <0>;
+		};
+
+		serdes: serdes at e3410000 {
+			compatible = "microchip,lan9691-serdes";
+			reg = <0xe3410000 0x150000>;
+			#phy-cells = <1>;
+			clocks = <&fabric_clk>;
+		};
+
+		gic: interrupt-controller at e8c11000 {
+			compatible = "arm,gic-400";
+			reg = <0xe8c11000 0x1000>, /* Distributor GICD_ */
+			      <0xe8c12000 0x2000>, /* CPU interface GICC_ */
+			      <0xe8c14000 0x2000>, /* Virt interface control */
+			      <0xe8c16000 0x2000>; /* Virt CPU interface */
+			#interrupt-cells = <3>;
+			interrupt-controller;
+			interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+		};
+	};
+};
-- 
2.52.0



From robert.marko at sartura.hr  Mon Dec 29 10:37:55 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Mon, 29 Dec 2025 19:37:55 +0100
Subject: [PATCH v4 14/15] dt-bindings: arm: AT91: document EV23X71A board
In-Reply-To: <20251229184004.571837-1-robert.marko@sartura.hr>
References: <20251229184004.571837-1-robert.marko@sartura.hr>
Message-ID: <20251229184004.571837-15-robert.marko@sartura.hr>

Microchip EV23X71A board is an LAN9696 based evaluation board.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
---
 Documentation/devicetree/bindings/arm/atmel-at91.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.yaml b/Documentation/devicetree/bindings/arm/atmel-at91.yaml
index 3a34b7a2e8d4..b0065e2f3713 100644
--- a/Documentation/devicetree/bindings/arm/atmel-at91.yaml
+++ b/Documentation/devicetree/bindings/arm/atmel-at91.yaml
@@ -241,6 +241,12 @@ properties:
           - const: microchip,lan9668
           - const: microchip,lan966
 
+      - description: Microchip LAN9696 EV23X71A Evaluation Board
+        items:
+          - const: microchip,ev23x71a
+          - const: microchip,lan9696
+          - const: microchip,lan9691
+
       - description: Kontron KSwitch D10 MMT series
         items:
           - enum:
-- 
2.52.0



From robert.marko at sartura.hr  Mon Dec 29 10:37:56 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Mon, 29 Dec 2025 19:37:56 +0100
Subject: [PATCH v4 15/15] arm64: dts: microchip: add EV23X71A board
In-Reply-To: <20251229184004.571837-1-robert.marko@sartura.hr>
References: <20251229184004.571837-1-robert.marko@sartura.hr>
Message-ID: <20251229184004.571837-16-robert.marko@sartura.hr>

Microchip EV23X71A is an LAN9696 based evaluation board.

Signed-off-by: Robert Marko <robert.marko at sartura.hr>
---
Changes in v2:
* Split from SoC DTSI commit
* Apply DTS coding style
* Enclose array in i2c-mux
* Alphanumericaly sort nodes
* Change management port mode to RGMII-ID 

 arch/arm64/boot/dts/microchip/Makefile        |   1 +
 .../boot/dts/microchip/lan9696-ev23x71a.dts   | 757 ++++++++++++++++++
 2 files changed, 758 insertions(+)
 create mode 100644 arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts

diff --git a/arch/arm64/boot/dts/microchip/Makefile b/arch/arm64/boot/dts/microchip/Makefile
index c6e0313eea0f..09d16fc1ce9a 100644
--- a/arch/arm64/boot/dts/microchip/Makefile
+++ b/arch/arm64/boot/dts/microchip/Makefile
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
+dtb-$(CONFIG_ARCH_LAN969X) += lan9696-ev23x71a.dtb
 dtb-$(CONFIG_ARCH_SPARX5) += sparx5_pcb125.dtb
 dtb-$(CONFIG_ARCH_SPARX5) += sparx5_pcb134.dtb sparx5_pcb134_emmc.dtb
 dtb-$(CONFIG_ARCH_SPARX5) += sparx5_pcb135.dtb sparx5_pcb135_emmc.dtb
diff --git a/arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts b/arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts
new file mode 100644
index 000000000000..435df455b078
--- /dev/null
+++ b/arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts
@@ -0,0 +1,757 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT)
+/*
+ * Copyright (c) 2025 Microchip Technology Inc. and its subsidiaries.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
+#include "lan9691.dtsi"
+
+/ {
+	model = "Microchip EV23X71A";
+	compatible = "microchip,ev23x71a", "microchip,lan9696", "microchip,lan9691";
+
+	aliases {
+		serial0 = &usart0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	gpio-restart {
+		compatible = "gpio-restart";
+		gpios = <&gpio 60 GPIO_ACTIVE_LOW>;
+		open-source;
+		priority = <200>;
+	};
+
+	i2c-mux {
+		compatible = "i2c-mux-gpio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-parent = <&i2c3>;
+		idle-state = <0x8>;
+		mux-gpios = <&sgpio_out 0 1 GPIO_ACTIVE_HIGH>,
+			    <&sgpio_out 0 2 GPIO_ACTIVE_HIGH>,
+			    <&sgpio_out 0 3 GPIO_ACTIVE_HIGH>;
+		settle-time-us = <100>;
+
+		i2c_sfp0: i2c at 0 {
+			reg = <0x0>;
+		};
+
+		i2c_sfp1: i2c at 1 {
+			reg = <0x1>;
+		};
+
+		i2c_sfp2: i2c at 2 {
+			reg = <0x2>;
+		};
+
+		i2c_sfp3: i2c at 3 {
+			reg = <0x3>;
+		};
+
+		i2c_poe: i2c at 7 {
+			reg = <0x7>;
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		led-status {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_STATUS;
+			gpios = <&gpio 61 GPIO_ACTIVE_LOW>;
+		};
+
+		led-sfp1-green {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_LAN;
+			function-enumerator = <0>;
+			gpios = <&sgpio_out 6 0 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-sfp1-yellow {
+			color = <LED_COLOR_ID_YELLOW>;
+			function = LED_FUNCTION_LAN;
+			function-enumerator = <0>;
+			gpios = <&sgpio_out 6 1 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-sfp2-green {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_LAN;
+			function-enumerator = <1>;
+			gpios = <&sgpio_out 7 0 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-sfp2-yellow {
+			color = <LED_COLOR_ID_YELLOW>;
+			function = LED_FUNCTION_LAN;
+			function-enumerator = <1>;
+			gpios = <&sgpio_out 7 1 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-sfp3-green {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_LAN;
+			function-enumerator = <2>;
+			gpios = <&sgpio_out 8 0 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-sfp3-yellow {
+			color = <LED_COLOR_ID_YELLOW>;
+			function = LED_FUNCTION_LAN;
+			function-enumerator = <2>;
+			gpios = <&sgpio_out 8 1 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-sfp4-green {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_LAN;
+			function-enumerator = <3>;
+			gpios = <&sgpio_out 9 0 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-sfp4-yellow {
+			color = <LED_COLOR_ID_YELLOW>;
+			function = LED_FUNCTION_LAN;
+			function-enumerator = <3>;
+			gpios = <&sgpio_out 9 1 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+	};
+
+	mux-controller {
+		compatible = "gpio-mux";
+		#mux-control-cells = <0>;
+		mux-gpios = <&sgpio_out 1 2 GPIO_ACTIVE_LOW>,
+			    <&sgpio_out 1 3 GPIO_ACTIVE_LOW>;
+	};
+
+	sfp0: sfp0 {
+		compatible = "sff,sfp";
+		i2c-bus = <&i2c_sfp0>;
+		tx-disable-gpios = <&sgpio_out 6 2 GPIO_ACTIVE_HIGH>;
+		los-gpios = <&sgpio_in 6 0 GPIO_ACTIVE_HIGH>;
+		mod-def0-gpios = <&sgpio_in 6 1 GPIO_ACTIVE_LOW>;
+		tx-fault-gpios = <&sgpio_in 6 2 GPIO_ACTIVE_HIGH>;
+	};
+
+	sfp1: sfp1 {
+		compatible = "sff,sfp";
+		i2c-bus = <&i2c_sfp1>;
+		tx-disable-gpios = <&sgpio_out 7 2 GPIO_ACTIVE_HIGH>;
+		los-gpios = <&sgpio_in 7 0 GPIO_ACTIVE_HIGH>;
+		mod-def0-gpios = <&sgpio_in 7 1 GPIO_ACTIVE_LOW>;
+		tx-fault-gpios = <&sgpio_in 7 2 GPIO_ACTIVE_HIGH>;
+	};
+
+	sfp2: sfp2 {
+		compatible = "sff,sfp";
+		i2c-bus = <&i2c_sfp2>;
+		tx-disable-gpios = <&sgpio_out 8 2 GPIO_ACTIVE_HIGH>;
+		los-gpios = <&sgpio_in 8 0 GPIO_ACTIVE_HIGH>;
+		mod-def0-gpios = <&sgpio_in 8 1 GPIO_ACTIVE_LOW>;
+		tx-fault-gpios = <&sgpio_in 8 2 GPIO_ACTIVE_HIGH>;
+	};
+
+	sfp3: sfp3 {
+		compatible = "sff,sfp";
+		i2c-bus = <&i2c_sfp3>;
+		tx-disable-gpios = <&sgpio_out 9 2 GPIO_ACTIVE_HIGH>;
+		los-gpios = <&sgpio_in 9 0 GPIO_ACTIVE_HIGH>;
+		mod-def0-gpios = <&sgpio_in 9 1 GPIO_ACTIVE_LOW>;
+		tx-fault-gpios = <&sgpio_in 9 2 GPIO_ACTIVE_HIGH>;
+	};
+};
+
+&gpio {
+	emmc_sd_pins: emmc-sd-pins {
+		/* eMMC_SD - CMD, CLK, D0, D1, D2, D3, D4, D5, D6, D7, RSTN */
+		pins = "GPIO_14", "GPIO_15", "GPIO_16", "GPIO_17",
+		       "GPIO_18", "GPIO_19", "GPIO_20", "GPIO_21",
+		       "GPIO_22", "GPIO_23", "GPIO_24";
+		function = "emmc_sd";
+	};
+
+	fan_pins: fan-pins {
+		pins = "GPIO_25", "GPIO_26";
+		function = "fan";
+	};
+
+	fc0_pins: fc0-pins {
+		pins = "GPIO_3", "GPIO_4";
+		function = "fc";
+	};
+
+	fc2_pins: fc2-pins {
+		pins = "GPIO_64", "GPIO_65", "GPIO_66";
+		function = "fc";
+	};
+
+	fc3_pins: fc3-pins {
+		pins = "GPIO_55", "GPIO_56";
+		function = "fc";
+	};
+
+	mdio_pins: mdio-pins {
+		pins = "GPIO_9", "GPIO_10";
+		function = "miim";
+	};
+
+	mdio_irq_pins: mdio-irq-pins {
+		pins = "GPIO_11";
+		function = "miim_irq";
+	};
+
+	sgpio_pins: sgpio-pins {
+		/* SCK, D0, D1, LD */
+		pins = "GPIO_5", "GPIO_6", "GPIO_7", "GPIO_8";
+		function = "sgpio_a";
+	};
+
+	usb_ulpi_pins: usb-ulpi-pins {
+		pins = "GPIO_30", "GPIO_31", "GPIO_32", "GPIO_33",
+		       "GPIO_34", "GPIO_35", "GPIO_36", "GPIO_37",
+		       "GPIO_38", "GPIO_39", "GPIO_40", "GPIO_41";
+		function = "usb_ulpi";
+	};
+
+	usb_rst_pins: usb-rst-pins {
+		pins = "GPIO_12";
+		function = "usb2phy_rst";
+	};
+
+	usb_over_pins: usb-over-pins {
+		pins = "GPIO_13";
+		function = "usb_over_detect";
+	};
+
+	usb_power_pins: usb-power-pins {
+		pins = "GPIO_1";
+		function = "usb_power";
+	};
+
+	ptp_out_pins: ptp-out-pins {
+		pins = "GPIO_58";
+		function = "ptpsync_4";
+	};
+
+	ptp_ext_pins: ptp-ext-pins {
+		pins = "GPIO_59";
+		function = "ptpsync_5";
+	};
+};
+
+&flx0 {
+	atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_USART>;
+	status = "okay";
+};
+
+&flx2 {
+	atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_SPI>;
+	status = "okay";
+};
+
+&flx3 {
+	atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_TWI>;
+	status = "okay";
+};
+
+&i2c3 {
+	pinctrl-0 = <&fc3_pins>;
+	pinctrl-names = "default";
+	i2c-analog-filter;
+	i2c-digital-filter;
+	i2c-digital-filter-width-ns = <35>;
+	i2c-sda-hold-time-ns = <1500>;
+	status = "okay";
+};
+
+&mdio0 {
+	pinctrl-0 = <&mdio_pins>, <&mdio_irq_pins>;
+	pinctrl-names = "default";
+	reset-gpios = <&gpio 62 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	phy3: phy at 3 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <3>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy4: phy at 4 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <4>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy5: phy at 5 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <5>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy6: phy at 6 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <6>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy7: phy at 7 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <7>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy8: phy at 8 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <8>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy9: phy at 9 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <9>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy10: phy at 10 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <10>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy11: phy at 11 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <11>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy12: phy at 12 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <12>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy13: phy at 13 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <13>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy14: phy at 14 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <14>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy15: phy at 15 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <15>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy16: phy at 16 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <16>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy17: phy at 17 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <17>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy18: phy at 18 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <18>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy19: phy at 19 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <19>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy20: phy at 20 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <20>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy21: phy at 21 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <21>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy22: phy at 22 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <22>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy23: phy at 23 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <23>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy24: phy at 24 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <24>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy25: phy at 25 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <25>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy26: phy at 26 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <26>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+
+	phy27: phy at 27 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <27>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio>;
+	};
+};
+
+&serdes {
+	status = "okay";
+};
+
+&sgpio {
+	pinctrl-0 = <&sgpio_pins>;
+	pinctrl-names = "default";
+	microchip,sgpio-port-ranges = <0 1>, <6 9>;
+	status = "okay";
+
+	gpio at 0 {
+		ngpios = <128>;
+	};
+	gpio at 1 {
+		ngpios = <128>;
+	};
+};
+
+&spi2 {
+	pinctrl-0 = <&fc2_pins>;
+	pinctrl-names = "default";
+	cs-gpios = <&gpio 63 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&switch {
+	pinctrl-0 = <&ptp_out_pins>, <&ptp_ext_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	ethernet-ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port0: port at 0 {
+			reg = <0>;
+			phy-handle = <&phy4>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 0>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port1: port at 1 {
+			reg = <1>;
+			phy-handle = <&phy5>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 0>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port2: port at 2 {
+			reg = <2>;
+			phy-handle = <&phy6>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 0>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port3: port at 3 {
+			reg = <3>;
+			phy-handle = <&phy7>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 0>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port4: port at 4 {
+			reg = <4>;
+			phy-handle = <&phy8>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 1>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port5: port at 5 {
+			reg = <5>;
+			phy-handle = <&phy9>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 1>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port6: port at 6 {
+			reg = <6>;
+			phy-handle = <&phy10>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 1>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port7: port at 7 {
+			reg = <7>;
+			phy-handle = <&phy11>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 1>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port8: port at 8 {
+			reg = <8>;
+			phy-handle = <&phy12>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 2>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port9: port at 9 {
+			reg = <9>;
+			phy-handle = <&phy13>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 2>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port10: port at 10 {
+			reg = <10>;
+			phy-handle = <&phy14>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 2>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port11: port at 11 {
+			reg = <11>;
+			phy-handle = <&phy15>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 2>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port12: port at 12 {
+			reg = <12>;
+			phy-handle = <&phy16>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 3>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port13: port at 13 {
+			reg = <13>;
+			phy-handle = <&phy17>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 3>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port14: port at 14 {
+			reg = <14>;
+			phy-handle = <&phy18>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 3>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port15: port at 15 {
+			reg = <15>;
+			phy-handle = <&phy19>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 3>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port16: port at 16 {
+			reg = <16>;
+			phy-handle = <&phy20>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 4>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port17: port at 17 {
+			reg = <17>;
+			phy-handle = <&phy21>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 4>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port18: port at 18 {
+			reg = <18>;
+			phy-handle = <&phy22>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 4>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port19: port at 19 {
+			reg = <19>;
+			phy-handle = <&phy23>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 4>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port20: port at 20 {
+			reg = <20>;
+			phy-handle = <&phy24>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 5>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port21: port at 21 {
+			reg = <21>;
+			phy-handle = <&phy25>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 5>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port22: port at 22 {
+			reg = <22>;
+			phy-handle = <&phy26>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 5>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port23: port at 23 {
+			reg = <23>;
+			phy-handle = <&phy27>;
+			phy-mode = "qsgmii";
+			phys = <&serdes 5>;
+			microchip,bandwidth = <1000>;
+		};
+
+		port24: port at 24 {
+			reg = <24>;
+			phys = <&serdes 6>;
+			phy-mode = "10gbase-r";
+			sfp = <&sfp0>;
+			managed = "in-band-status";
+			microchip,bandwidth = <10000>;
+			microchip,sd-sgpio = <24>;
+		};
+
+		port25: port at 25 {
+			reg = <25>;
+			phys = <&serdes 7>;
+			phy-mode = "10gbase-r";
+			sfp = <&sfp1>;
+			managed = "in-band-status";
+			microchip,bandwidth = <10000>;
+			microchip,sd-sgpio = <28>;
+		};
+
+		port26: port at 26 {
+			reg = <26>;
+			phys = <&serdes 8>;
+			phy-mode = "10gbase-r";
+			sfp = <&sfp2>;
+			managed = "in-band-status";
+			microchip,bandwidth = <10000>;
+			microchip,sd-sgpio = <32>;
+		};
+
+		port27: port at 27 {
+			reg = <27>;
+			phys = <&serdes 9>;
+			phy-mode = "10gbase-r";
+			sfp = <&sfp3>;
+			managed = "in-band-status";
+			microchip,bandwidth = <10000>;
+			microchip,sd-sgpio = <36>;
+		};
+
+		port29: port at 29 {
+			reg = <29>;
+			phys = <&serdes 11>;
+			phy-handle = <&phy3>;
+			phy-mode = "rgmii-id";
+			microchip,bandwidth = <1000>;
+		};
+	};
+};
+
+&tmon {
+	pinctrl-0 = <&fan_pins>;
+	pinctrl-names = "default";
+};
+
+&usart0 {
+	pinctrl-0 = <&fc0_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&usb {
+	pinctrl-0 = <&usb_ulpi_pins>, <&usb_rst_pins>, <&usb_over_pins>, <&usb_power_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
-- 
2.52.0



From wiagn233 at outlook.com  Mon Dec 29 10:53:44 2025
From: wiagn233 at outlook.com (Shengyu Qu)
Date: Tue, 30 Dec 2025 02:53:44 +0800
Subject: [PATCH 00/11] Plane Color Pipeline support for MediaTek
In-Reply-To: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
References: <20251223-mtk-ovl-pre-blend-colorops-v1-0-0cb99bd0ab33@collabora.com>
Message-ID: <TY4PR01MB144323B0DDC18B05EE1472B5298BFA@TY4PR01MB14432.jpnprd01.prod.outlook.com>



? 2025/12/24 3:44, N? colas F. R. A. Prado ??:
> This series implements a plane color pipeline for MediaTek platforms,
> specifically for MT8195-compatible SoCs.
> 
> The pipeline is composed of the following blocks:
> 
> Inverse Gamma -> RGB to RGB Color Space Conversion (R2R CSC) -> Gamma
> (1D Curve)       (3x3 Matrix)                                   (1D Curve)
> 
> The curves supported by Inverse Gamma are:
> * scRGB
> * BT.709

scRGB? That means this HW supports float point format surface, are you 
sure this is not standard sRGB?

> The curves supported by Gamma are:
> * scRGB
> * BT.709
> * BT.2020
> * HLG
> 
> Given the lack of support for writeback connectors on the MediaTek KMS
> driver, combined with limited hardware documentation, I haven't been
> able to verify the correctness of each curve, only that they were
> visually sane (gamma curves made the image on the display brighter,
> while inverse gamma made it darker).

Hmmm I don't think this is acceptable. sRGB/scRGB has two transfer 
functions mentioned in original specification[1]. To keep color 
accuracy, we need someone from mediatek confirm whether this is 
piece-wise or pure power 2.2 transfer function, this is already done in 
original amdgpu color pipeline series, sRGB means piece-wise while also 
dedicated power 2.2 function exists.

Also +cc Xaver for a review as userspace compositor developer.

[1] https://gitlab.freedesktop.org/pq/color-and-hdr/-/issues/30

> This series depends on "drm: Color pipeline teardown and follow-up
> fixes/improvements" [1].
> 
> This series was tested on the MT8195-Tomato Chromebook.
> 
> Regarding the support of color operations in OVL for different SoCs:
> * it's not supported by MT8183, and presumably also not by older
>    generations
> * On MT8192 it's supported by ovl0 and ovl_2l0, but not ovl_2l2 (despite
>    the same compatible as ovl_2l0).
> 
> For this series I'm only enabling it on MT8195 since that's the one
> where I can readily test.
> 
> [1] https://lore.kernel.org/all/20251219065614.190834-1-chaitanya.kumar.borah at intel.com/#t
> 
> Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
> ---
> N?colas F. R. A. Prado (11):
>        drm/mediatek: Introduce DDP plane_colorops_init() hook
>        drm/mediatek: Initialize colorops when creating plane
>        drm/mediatek: ovl: Add supports_plane_colorops flag
>        drm/mediatek: ovl: Enable per-plane color operations on MT8195
>        drm/mediatek: ovl: Implement support for Inverse Gamma
>        drm/mediatek: Add plane_colorops_init() DDP hook for OVL
>        drm/colorop: Introduce HLG EOTF
>        drm/mediatek: ovl: Implement support for Gamma
>        drm/colorop: Introduce 3x3 Matrix
>        drm/mediatek: ovl: Enable support for R2R Color Space Conversion
>        drm/mediatek: Check 3x3 Matrix colorop has DATA set
> 
>   drivers/gpu/drm/drm_atomic.c            |   1 +
>   drivers/gpu/drm/drm_atomic_uapi.c       |   3 +
>   drivers/gpu/drm/drm_colorop.c           |  22 +++
>   drivers/gpu/drm/mediatek/mtk_crtc.c     |  36 +++-
>   drivers/gpu/drm/mediatek/mtk_ddp_comp.c |   1 +
>   drivers/gpu/drm/mediatek/mtk_ddp_comp.h |   2 +
>   drivers/gpu/drm/mediatek/mtk_disp_drv.h |   1 +
>   drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 287 ++++++++++++++++++++++++++++++++
>   include/drm/drm_colorop.h               |  13 ++
>   include/uapi/drm/drm_mode.h             |  16 ++
>   10 files changed, 381 insertions(+), 1 deletion(-)
> ---
> base-commit: 1783cdadb70e74a30dfee250f8c2dc13b4e61128
> change-id: 20251219-mtk-ovl-pre-blend-colorops-95b7b2883d95
> 
> Best regards,

-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_0xE3520CC91929C8E7.asc
Type: application/pgp-keys
Size: 6868 bytes
Desc: OpenPGP public key
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251230/3d28fc15/attachment-0001.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature.asc
Type: application/pgp-signature
Size: 840 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251230/3d28fc15/attachment-0001.sig>

From dinguyen at kernel.org  Mon Dec 29 11:17:18 2025
From: dinguyen at kernel.org (Dinh Nguyen)
Date: Mon, 29 Dec 2025 13:17:18 -0600
Subject: [PATCH 1/2] net: stmmac: socfpga: add call to assert/deassert ahb
 reset line
In-Reply-To: <20251229-remove_ocp-v1-0-594294e04bd4@kernel.org>
References: <20251229-remove_ocp-v1-0-594294e04bd4@kernel.org>
Message-ID: <20251229-remove_ocp-v1-1-594294e04bd4@kernel.org>

The "stmmaceth-ocp" reset line of stmmac controller on the SoCFPGA
platform is essentially the "ahb" reset on the standard stmmac
controller. But since stmmaceth-ocp has already been introduced into
the wild, we cannot just remove support for it. But what we can do is
to support both "stmmaceth-ocp" and "ahb" reset names. Going forward we
will be using "ahb", but in order to not break ABI, we will be call reset
assert/de-assert both ahb and stmmaceth-ocp.

The ethernet hardware on SoCFPGA requires either the stmmaceth-ocp or
ahb reset to be asserted every time before changing the phy mode, then
de-asserted when the phy mode has been set.

With this change, we should be able to revert patch:
commit 62a40a0d5634 ("arm: dts: socfpga: use reset-name "stmmaceth-ocp"
instead of "ahb"")

Signed-off-by: Dinh Nguyen <dinguyen at kernel.org>
---
 drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
index a2b52d2c4eb6..79df55515c71 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
@@ -407,6 +407,7 @@ static int socfpga_gen5_set_phy_mode(struct socfpga_dwmac *dwmac)
 
 	/* Assert reset to the enet controller before changing the phy mode */
 	reset_control_assert(dwmac->stmmac_ocp_rst);
+	reset_control_assert(dwmac->plat_dat->stmmac_ahb_rst);
 	reset_control_assert(dwmac->stmmac_rst);
 
 	regmap_read(sys_mgr_base_addr, reg_offset, &ctrl);
@@ -436,6 +437,7 @@ static int socfpga_gen5_set_phy_mode(struct socfpga_dwmac *dwmac)
 	 * the enet controller, and operation to start in requested mode
 	 */
 	reset_control_deassert(dwmac->stmmac_ocp_rst);
+	reset_control_deassert(dwmac->plat_dat->stmmac_ahb_rst);
 	reset_control_deassert(dwmac->stmmac_rst);
 	if (phymode == PHY_INTERFACE_MODE_SGMII)
 		socfpga_sgmii_config(dwmac, true);
@@ -463,6 +465,7 @@ static int socfpga_gen10_set_phy_mode(struct socfpga_dwmac *dwmac)
 
 	/* Assert reset to the enet controller before changing the phy mode */
 	reset_control_assert(dwmac->stmmac_ocp_rst);
+	reset_control_assert(dwmac->plat_dat->stmmac_ahb_rst);
 	reset_control_assert(dwmac->stmmac_rst);
 
 	regmap_read(sys_mgr_base_addr, reg_offset, &ctrl);
@@ -489,6 +492,7 @@ static int socfpga_gen10_set_phy_mode(struct socfpga_dwmac *dwmac)
 	 * the enet controller, and operation to start in requested mode
 	 */
 	reset_control_deassert(dwmac->stmmac_ocp_rst);
+	reset_control_deassert(dwmac->plat_dat->stmmac_ahb_rst);
 	reset_control_deassert(dwmac->stmmac_rst);
 	if (phymode == PHY_INTERFACE_MODE_SGMII)
 		socfpga_sgmii_config(dwmac, true);

-- 
2.42.0.411.g813d9a9188



From dinguyen at kernel.org  Mon Dec 29 11:17:17 2025
From: dinguyen at kernel.org (Dinh Nguyen)
Date: Mon, 29 Dec 2025 13:17:17 -0600
Subject: [PATCH 0/2] net: stmmac: socfpga: support both stmmaceth-ocp and
 ahb reset names
Message-ID: <20251229-remove_ocp-v1-0-594294e04bd4@kernel.org>

The dwmac-socfpga stmmac ethernet controller supports 2 standard reset
lines, named "stmmaceth" and "stmmaceth-ocp". At the time of upstreaming
support for the platform, the "stmmaceth-ocp" name was used for the 2nd
reset name. We later realized that the "stmmaceth-ocp" reset name is
the same as the "ahb" name that is used by the standard stmmac driver.
But since the "stmmaceth-ocp" name support has already been introduced
to the wild, it cannot just be removed from the driver, thus we can
modify the driver to support both "stmmaceth-ocp" and "ahb", with the
idea that "ahb" will be used going forward.

This series add the support to call reset assert/de-assert both "abh"
and "stmmaceth-ocp" to the dwmac-socfpga platform driver, then reverts
the patch that uses the DTS "stmmaceth-ocp" reset name.

Signed-off-by: Dinh Nguyen <dinguyen at kernel.org>
---
Dinh Nguyen (2):
      net: stmmac: socfpga: add call to assert/deassert ahb reset line
      Revert "arm: dts: socfpga: use reset-name "stmmaceth-ocp" instead of "ahb""

 arch/arm/boot/dts/intel/socfpga/socfpga_arria10.dtsi | 6 +++---
 drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c  | 4 ++++
 2 files changed, 7 insertions(+), 3 deletions(-)
---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20251229-remove_ocp-44786389b052

Best regards,
-- 
Dinh Nguyen <dinguyen at kernel.org>



From dinguyen at kernel.org  Mon Dec 29 11:17:19 2025
From: dinguyen at kernel.org (Dinh Nguyen)
Date: Mon, 29 Dec 2025 13:17:19 -0600
Subject: [PATCH 2/2] Revert "arm: dts: socfpga: use reset-name
 "stmmaceth-ocp" instead of "ahb""
In-Reply-To: <20251229-remove_ocp-v1-0-594294e04bd4@kernel.org>
References: <20251229-remove_ocp-v1-0-594294e04bd4@kernel.org>
Message-ID: <20251229-remove_ocp-v1-2-594294e04bd4@kernel.org>

This reverts commit 62a40a0d5634834790f7166ab592be247390d857.

With the patch "add call to assert/deassert ahb reset line" in place, we can
safely remove the "stmmaceth-ocp" reset name and just use the standard
"ahb" reset name.

Signed-off-by: Dinh Nguyen <dinguyen at kernel.org>
---
 arch/arm/boot/dts/intel/socfpga/socfpga_arria10.dtsi | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm/boot/dts/intel/socfpga/socfpga_arria10.dtsi b/arch/arm/boot/dts/intel/socfpga/socfpga_arria10.dtsi
index b108265e9bde..6b6e77596ffa 100644
--- a/arch/arm/boot/dts/intel/socfpga/socfpga_arria10.dtsi
+++ b/arch/arm/boot/dts/intel/socfpga/socfpga_arria10.dtsi
@@ -440,7 +440,7 @@ gmac0: ethernet at ff800000 {
 			clocks = <&l4_mp_clk>, <&peri_emac_ptp_clk>;
 			clock-names = "stmmaceth", "ptp_ref";
 			resets = <&rst EMAC0_RESET>, <&rst EMAC0_OCP_RESET>;
-			reset-names = "stmmaceth", "stmmaceth-ocp";
+			reset-names = "stmmaceth", "ahb";
 			snps,axi-config = <&socfpga_axi_setup>;
 			status = "disabled";
 		};
@@ -460,7 +460,7 @@ gmac1: ethernet at ff802000 {
 			clocks = <&l4_mp_clk>, <&peri_emac_ptp_clk>;
 			clock-names = "stmmaceth", "ptp_ref";
 			resets = <&rst EMAC1_RESET>, <&rst EMAC1_OCP_RESET>;
-			reset-names = "stmmaceth", "stmmaceth-ocp";
+			reset-names = "stmmaceth", "ahb";
 			snps,axi-config = <&socfpga_axi_setup>;
 			status = "disabled";
 		};
@@ -480,7 +480,7 @@ gmac2: ethernet at ff804000 {
 			clocks = <&l4_mp_clk>, <&peri_emac_ptp_clk>;
 			clock-names = "stmmaceth", "ptp_ref";
 			resets = <&rst EMAC2_RESET>, <&rst EMAC2_OCP_RESET>;
-			reset-names = "stmmaceth", "stmmaceth-ocp";
+			reset-names = "stmmaceth", "ahb";
 			snps,axi-config = <&socfpga_axi_setup>;
 			status = "disabled";
 		};

-- 
2.42.0.411.g813d9a9188



From marex at nabladev.com  Mon Dec 29 11:36:40 2025
From: marex at nabladev.com (Marek Vasut)
Date: Mon, 29 Dec 2025 20:36:40 +0100
Subject: [PATCH v2 1/4] dt-bindings: vendor-prefixes: Document ifm electronic gmbh
Message-ID: <20251229193706.73564-1-marex@nabladev.com>

ifm is a manufacturer of industrial sensors, control technology and
automation solutions. Document their vendor prefix, which is already
used for ifm,ac14xx and other powerpc devices.

Acked-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Marek Vasut <marex at nabladev.com>
---
Cc: Christian Eggers <ceggers at arri.de>
Cc: Conor Dooley <conor+dt at kernel.org>
Cc: Fabio Estevam <festevam at gmail.com>
Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
Cc: Krzysztof Kozlowski <krzk+dt at kernel.org>
Cc: Markus Heidelberg <m.heidelberg at cab.de>
Cc: Rob Herring <robh at kernel.org>
Cc: Shawn Guo <shawnguo at kernel.org>
Cc: devicetree at vger.kernel.org
Cc: imx at lists.linux.dev
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-kernel at vger.kernel.org
---
V2: Add AB from Rob
---
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index b7c6c528e0185..70d99ac01aa34 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -755,6 +755,8 @@ patternProperties:
     description: IEI Integration Corp.
   "^ifi,.*":
     description: Ingenieurburo Fur Ic-Technologie (I/F/I)
+  "^ifm,.*":
+    description: ifm electronic gmbh
   "^ilitek,.*":
     description: ILI Technology Corporation (ILITEK)
   "^imagis,.*":
-- 
2.51.0



From marex at nabladev.com  Mon Dec 29 11:36:42 2025
From: marex at nabladev.com (Marek Vasut)
Date: Mon, 29 Dec 2025 20:36:42 +0100
Subject: [PATCH v2 3/4] arm64: dts: imx8mn: Add SNVS LPGPR
In-Reply-To: <20251229193706.73564-1-marex@nabladev.com>
References: <20251229193706.73564-1-marex@nabladev.com>
Message-ID: <20251229193706.73564-3-marex@nabladev.com>

Add SNVS LPGPR bindings to MX8M Nano, the LPGPR is used to store
boot counter.

Signed-off-by: Marek Vasut <marex at nabladev.com>
---
Cc: Christian Eggers <ceggers at arri.de>
Cc: Conor Dooley <conor+dt at kernel.org>
Cc: Fabio Estevam <festevam at gmail.com>
Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
Cc: Krzysztof Kozlowski <krzk+dt at kernel.org>
Cc: Markus Heidelberg <m.heidelberg at cab.de>
Cc: Rob Herring <robh at kernel.org>
Cc: Shawn Guo <shawnguo at kernel.org>
Cc: devicetree at vger.kernel.org
Cc: imx at lists.linux.dev
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-kernel at vger.kernel.org
---
V2: New patch
---
 arch/arm64/boot/dts/freescale/imx8mn.dtsi | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mn.dtsi b/arch/arm64/boot/dts/freescale/imx8mn.dtsi
index b98b3d0ddf25a..3199bc0966b03 100644
--- a/arch/arm64/boot/dts/freescale/imx8mn.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mn.dtsi
@@ -628,6 +628,11 @@ snvs_pwrkey: snvs-powerkey {
 					wakeup-source;
 					status = "disabled";
 				};
+
+				snvs_lpgpr: snvs-lpgpr {
+					compatible = "fsl,imx8mn-snvs-lpgpr",
+						     "fsl,imx7d-snvs-lpgpr";
+				};
 			};
 
 			clk: clock-controller at 30380000 {
-- 
2.51.0



From marex at nabladev.com  Mon Dec 29 11:36:41 2025
From: marex at nabladev.com (Marek Vasut)
Date: Mon, 29 Dec 2025 20:36:41 +0100
Subject: [PATCH v2 2/4] dt-bindings: arm: fsl: Document ifm VHIP4 EvalBoard v1 and v2
In-Reply-To: <20251229193706.73564-1-marex@nabladev.com>
References: <20251229193706.73564-1-marex@nabladev.com>
Message-ID: <20251229193706.73564-2-marex@nabladev.com>

Document ifm i.MX8MN VHIP4 EvalBoard v1 and v2 reference design binding.
This system exists in two generations, v1 and v2, which share a lot of
commonality. The boards come with either single gigabit ethernet or an
KSZ8794 fast-ethernet switch, boot from eMMC, and offer CAN interfaces
via Microchip MCP25xx SPI CAN controllers, UART, and USB host. The GPU
is not available in the SoC populated on these devices.

Acked-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Marek Vasut <marex at nabladev.com>
---
Cc: Christian Eggers <ceggers at arri.de>
Cc: Conor Dooley <conor+dt at kernel.org>
Cc: Fabio Estevam <festevam at gmail.com>
Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
Cc: Krzysztof Kozlowski <krzk+dt at kernel.org>
Cc: Markus Heidelberg <m.heidelberg at cab.de>
Cc: Rob Herring <robh at kernel.org>
Cc: Shawn Guo <shawnguo at kernel.org>
Cc: devicetree at vger.kernel.org
Cc: imx at lists.linux.dev
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-kernel at vger.kernel.org
---
V2: Add AB from Rob
---
 Documentation/devicetree/bindings/arm/fsl.yaml | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
index 68a2d5fecc43b..4d0aee780bcb2 100644
--- a/Documentation/devicetree/bindings/arm/fsl.yaml
+++ b/Documentation/devicetree/bindings/arm/fsl.yaml
@@ -1071,6 +1071,15 @@ properties:
               - gw,imx8mn-gw7902          # i.MX8MM Gateworks Board
           - const: fsl,imx8mn
 
+      - description: ifm i.MX8MN VHIP4 based boards
+        items:
+          - enum:
+              - ifm,imx8mn-vhip4-evalboard-v1
+              - ifm,imx8mn-vhip4-evalboard-v2
+          - const: ifm,imx8mn-vhip4-evalboard
+          - const: ifm,imx8mn-vhip4
+          - const: fsl,imx8mn
+
       - description: Variscite VAR-SOM-MX8MN based boards
         items:
           - enum:
-- 
2.51.0



From marex at nabladev.com  Mon Dec 29 11:36:43 2025
From: marex at nabladev.com (Marek Vasut)
Date: Mon, 29 Dec 2025 20:36:43 +0100
Subject: [PATCH v2 4/4] arm64: dts: imx8mn: Add ifm VHIP4 EvalBoard v1 and v2
In-Reply-To: <20251229193706.73564-1-marex@nabladev.com>
References: <20251229193706.73564-1-marex@nabladev.com>
Message-ID: <20251229193706.73564-4-marex@nabladev.com>

From: Fedor Ross <fedor.ross at ifm.com>

Add support for ifm i.MX8MN VHIP4 EvalBoard v1 and v2 reference design.
This system exists in two generations, v1 and v2, which share a lot of
commonality. The boards come with either single gigabit ethernet or an
KSZ8794 fast-ethernet switch, boot from eMMC, and offer CAN interfaces
via Microchip MCP25xx SPI CAN controllers, UART, and USB host. The GPU
is not available in the SoC populated on these devices.

Signed-off-by: Fedor Ross <fedor.ross at ifm.com>
Signed-off-by: Marek Vasut <marex at nabladev.com>
---
Cc: Christian Eggers <ceggers at arri.de>
Cc: Conor Dooley <conor+dt at kernel.org>
Cc: Fabio Estevam <festevam at gmail.com>
Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
Cc: Krzysztof Kozlowski <krzk+dt at kernel.org>
Cc: Markus Heidelberg <m.heidelberg at cab.de>
Cc: Rob Herring <robh at kernel.org>
Cc: Shawn Guo <shawnguo at kernel.org>
Cc: devicetree at vger.kernel.org
Cc: imx at lists.linux.dev
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-kernel at vger.kernel.org
---
V2: - Drop snvs-lpgpr node in favor of separate patch to imx8mn.dtsi
    - Sort properties and update newlines according to V1 feedback
---
 arch/arm64/boot/dts/freescale/Makefile        |  19 +
 .../imx8mn-vhip4-evalboard-common.dtsi        | 398 ++++++++++++++++++
 ...imx8mn-vhip4-evalboard-ksz8794-common.dtsi |  99 +++++
 ...mn-vhip4-evalboard-v1-overlay-ksz8794.dtso |  24 ++
 ...mn-vhip4-evalboard-v1-overlay-ksz9031.dtso |  49 +++
 .../freescale/imx8mn-vhip4-evalboard-v1.dts   | 260 ++++++++++++
 ...n-vhip4-evalboard-v2-overlay-adin1300.dtso |  61 +++
 ...mn-vhip4-evalboard-v2-overlay-ksz8794.dtso |  24 ++
 .../freescale/imx8mn-vhip4-evalboard-v2.dts   | 221 ++++++++++
 9 files changed, 1155 insertions(+)
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-common.dtsi
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-ksz8794-common.dtsi
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtso
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtso
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1.dts
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtso
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtso
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2.dts

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index f30d3fd724d0c..01b2ec5ad81ff 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -191,6 +191,25 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mn-tqma8mqnl-mba8mx.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-var-som-symphony.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-venice-gw7902.dtb
 
+imx8mn-vhip4-evalboard-v1-overlay-ksz8794-dtbs := imx8mn-vhip4-evalboard-v1.dtb \
+						  imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtbo
+imx8mn-vhip4-evalboard-v1-overlay-ksz9031-dtbs := imx8mn-vhip4-evalboard-v1.dtb \
+						  imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtbo
+imx8mn-vhip4-evalboard-v2-overlay-ksz8794-dtbs := imx8mn-vhip4-evalboard-v2.dtb \
+						  imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtbo
+imx8mn-vhip4-evalboard-v2-overlay-adin1300-dtbs := imx8mn-vhip4-evalboard-v2.dtb \
+						   imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtbo
+dtb-$(CONFIG_ARCH_MXC) += imx8mn-vhip4-evalboard-v1.dtb \
+			  imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtb \
+			  imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtbo \
+			  imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtb \
+			  imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtbo \
+			  imx8mn-vhip4-evalboard-v2.dtb \
+			  imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtb \
+			  imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtbo \
+			  imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtb \
+			  imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtbo
+
 imx8mn-tqma8mqnl-mba8mx-lvds-tm070jvhg33-dtbs += imx8mn-tqma8mqnl-mba8mx.dtb imx8mn-tqma8mqnl-mba8mx-lvds-tm070jvhg33.dtbo
 imx8mn-tqma8mqnl-mba8mx-usbotg-dtbs += imx8mn-tqma8mqnl-mba8mx.dtb imx8mn-tqma8mqnl-mba8mx-usbotg.dtbo
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-tqma8mqnl-mba8mx-lvds-tm070jvhg33.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-common.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-common.dtsi
new file mode 100644
index 0000000000000..a9506ecf9647b
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-common.dtsi
@@ -0,0 +1,398 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2020-2024 Fedor Ross <fedor.ross at ifm.com>
+ */
+
+#include "imx8mn.dtsi"
+#include <dt-bindings/leds/common.h>
+
+/ {
+	model = "ifm i.MX8MNano VHIP4 Evaluation Board";
+	compatible = "ifm,imx8mn-vhip4-evalboard", "ifm,imx8mn-vhip4", "fsl,imx8mn";
+
+	aliases {
+		mmc0 = &usdhc3;
+		mmc1 = &usdhc1;
+		mmc2 = &usdhc2;
+		rtc0 = &hw_rtc;
+		rtc1 = &snvs_rtc;
+	};
+
+	chosen {
+		bootargs = "console=ttymxc2,115200 earlycon=ec_imx6q,0x30880000,115200 rootwait";
+		stdout-path = &uart3;
+	};
+
+	memory at 40000000 {
+		device_type = "memory";
+		reg = <0x0 0x40000000 0 0x40000000>;
+	};
+
+	can_clk20m: can-clk20m {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <20000000>;
+	};
+
+	can_clk40m: can-clk40m {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <40000000>;
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+		pinctrl-0 = <&pinctrl_gpio_button>;
+		pinctrl-names = "default";
+
+		button-2 {
+			label = "Button2";
+			gpios = <&gpio2 16 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_2>;
+		};
+
+		button-3 {
+			label = "Button3";
+			gpios = <&gpio2 18 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_3>;
+		};
+	};
+
+	ifm_led: led {
+		compatible = "gpio-leds";
+		pinctrl-0 = <&pinctrl_gpio_led>;
+		pinctrl-names = "default", "extended";
+
+		led-0 {
+			function = LED_FUNCTION_STATUS;
+			function-enumerator = <1>;
+			color = <LED_COLOR_ID_YELLOW>;
+			gpios = <&gpio2 13 GPIO_ACTIVE_HIGH>;
+			default-state = "keep";
+		};
+
+		led-1 {
+			function = LED_FUNCTION_STATUS;
+			function-enumerator = <2>;
+			color = <LED_COLOR_ID_GREEN>;
+			gpios = <&gpio2 15 GPIO_ACTIVE_HIGH>;
+			default-state = "keep";
+		};
+	};
+};
+
+&A53_0 {
+	cpu-supply = <&buck2_reg>;
+};
+
+&A53_1 {
+	cpu-supply = <&buck2_reg>;
+};
+
+&A53_2 {
+	cpu-supply = <&buck2_reg>;
+};
+
+&A53_3 {
+	cpu-supply = <&buck2_reg>;
+};
+
+&ddrc {
+	operating-points-v2 = <&ddrc_opp_table>;
+
+	ddrc_opp_table: opp-table {
+		compatible = "operating-points-v2";
+
+		opp-25000000 {
+			opp-hz = /bits/ 64 <25000000>;
+		};
+
+		opp-100000000 {
+			opp-hz = /bits/ 64 <100000000>;
+		};
+
+		opp-600000000 {
+			opp-hz = /bits/ 64 <600000000>;
+		};
+	};
+};
+
+&ecspi1 {
+	pinctrl-names = "default", "cs";
+	pinctrl-0 = <&pinctrl_ecspi1>;
+	pinctrl-1 = <&pinctrl_ecspi1_cs>;
+	/delete-property/ dmas;
+	/delete-property/ dma-names;
+};
+
+&ecspi3 {
+	pinctrl-names = "default", "cs";
+	pinctrl-0 = <&pinctrl_ecspi3>;
+	pinctrl-1 = <&pinctrl_ecspi3_cs>;
+	/delete-property/ dmas;
+	/delete-property/ dma-names;
+};
+
+&gpu {
+	/* SoC has GPU fused off. */
+	status = "disabled";
+};
+
+&i2c1 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default", "gpio";
+	pinctrl-0 = <&pinctrl_i2c1>;
+	pinctrl-1 = <&pinctrl_i2c1_gpio>;
+
+	eeprom at 51 {
+		compatible = "atmel,24c128";
+		reg = <0x51>;
+	};
+
+	hw_rtc: rtc at 52 {
+		compatible = "microcrystal,rv3028";
+		reg = <0x52>;
+	};
+};
+
+&i2c3 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default", "gpio";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	pinctrl-1 = <&pinctrl_i2c3_gpio>;
+
+	ifm_pmic: pmic at 4b {
+		compatible = "rohm,bd71847";
+		reg = <0x4b>;
+		pinctrl-0 = <&pinctrl_pmic>;
+		rohm,reset-snvs-powered;
+
+		regulators {
+			buck1_reg: BUCK1 {
+				regulator-name = "buck1";
+				regulator-min-microvolt = <790000>;
+				regulator-max-microvolt = <860000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <1250>;
+			};
+
+			buck2_reg: BUCK2 {
+				regulator-name = "buck2";
+				regulator-min-microvolt = <840000>;
+				regulator-max-microvolt = <960000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <1250>;
+			};
+
+			buck3_reg: BUCK3 {
+				// BUCK5 in datasheet
+				regulator-name = "buck3";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1350000>;
+			};
+
+			buck4_reg: BUCK4 {
+				// BUCK6 in datasheet
+				regulator-name = "buck4";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			buck5_reg: BUCK5 {
+				// BUCK7 in datasheet
+				regulator-name = "buck5";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			buck6_reg: BUCK6 {
+				// BUCK8 in datasheet
+				regulator-name = "buck6";
+				regulator-min-microvolt = <1100000>;
+				regulator-max-microvolt = <1100000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo1_reg: LDO1 {
+				regulator-name = "ldo1";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo2_reg: LDO2 {
+				regulator-name = "ldo2";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo3_reg: LDO3 {
+				regulator-name = "ldo3";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo4_reg: LDO4 {
+				regulator-name = "ldo4";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1800000>;
+			};
+
+			ldo5_reg: LDO5 {
+				regulator-name = "ldo5";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+			};
+
+			ldo6_reg: LDO6 {
+				regulator-name = "ldo6";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+		};
+	};
+};
+
+&iomuxc {
+	pinctrl_ecspi1: ecspi1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK		0x110
+			MX8MN_IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI		0x110
+			MX8MN_IOMUXC_ECSPI1_MISO_ECSPI1_MISO		0x190
+		>;
+	};
+
+	pinctrl_ecspi3: ecspi3-grp {
+		fsl,pins = <
+			/* SPI3_CAN_CLK */
+			MX8MN_IOMUXC_UART1_RXD_ECSPI3_SCLK		0x110
+			/* SPI3_CAN_MOSI */
+			MX8MN_IOMUXC_UART1_TXD_ECSPI3_MOSI		0x110
+			/* SPI3_CAN_MISO */
+			MX8MN_IOMUXC_UART2_RXD_ECSPI3_MISO		0x190
+		>;
+	};
+
+	pinctrl_gpio_button: gpiobutton-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD2_DATA1_GPIO2_IO16		0x96
+			MX8MN_IOMUXC_SD2_DATA3_GPIO2_IO18		0x96
+		>;
+	};
+
+	pinctrl_gpio_led: gpioled-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD2_CLK_GPIO2_IO13			0x116
+			MX8MN_IOMUXC_SD2_DATA0_GPIO2_IO15		0x116
+		>;
+	};
+
+	pinctrl_usdhc3: usdhc3-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK		0x40000110
+			MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d0
+			MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d0
+			MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d0
+			MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d0
+			MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d0
+			MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d0
+			MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d0
+			MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d0
+			MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d0
+			MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x190
+			MX8MN_IOMUXC_NAND_READY_B_USDHC3_RESET_B	0x150
+		>;
+	};
+
+	pinctrl_usdhc3_100mhz: usdhc3-100mhz-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK		0x40000114
+			MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d4
+			MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d4
+			MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d4
+			MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d4
+			MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d4
+			MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d4
+			MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d4
+			MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d4
+			MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d4
+			MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x194
+			MX8MN_IOMUXC_NAND_READY_B_USDHC3_RESET_B	0x150
+		>;
+	};
+
+	pinctrl_usdhc3_200mhz: usdhc3-200mhz-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK		0x40000116
+			MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d6
+			MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d6
+			MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d6
+			MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d6
+			MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d6
+			MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d6
+			MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d6
+			MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d6
+			MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d6
+			MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x196
+			MX8MN_IOMUXC_NAND_READY_B_USDHC3_RESET_B	0x150
+		>;
+	};
+
+	pinctrl_wdog: wdog-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B		0x64
+		>;
+	};
+};
+
+&pgc_gpumix {
+	/* SoC has GPU fused off. */
+	status = "disabled";
+};
+
+&snvs_pwrkey {
+	status = "okay";
+};
+
+&uart3 { /* console */
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart3>;
+	status = "okay";
+};
+
+&usbotg1 {
+	status = "okay";
+};
+
+&usdhc3 {
+	assigned-clocks = <&clk IMX8MN_CLK_USDHC3_ROOT>;
+	assigned-clock-rates = <400000000>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc3>;
+	pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
+	bus-width = <8>;
+	non-removable;
+	status = "okay";
+};
+
+&wdog1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_wdog>;
+	fsl,ext-reset-output;
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-ksz8794-common.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-ksz8794-common.dtsi
new file mode 100644
index 0000000000000..ed3c580dddde6
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-ksz8794-common.dtsi
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2025 Fedor Ross <fedor.ross at ifm.com>
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+
+#include "imx8mn-pinfunc.h"
+
+&ecspi1 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+
+	ksz8794: ethernet-switch at 1 {
+		compatible = "microchip,ksz8794";
+		pinctrl-names = "default", "reset";
+		pinctrl-0 = <&pinctrl_ks8794>;
+		pinctrl-1 = <&pinctrl_ks8794>;
+		reg = <1>;
+		reset-gpios = <&gpio4 28 GPIO_ACTIVE_LOW>;
+		spi-max-frequency = <5000000>;
+
+		ethernet-ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+				label = "lan1";
+			};
+
+			port at 1 {
+				reg = <1>;
+				label = "lan2";
+			};
+
+			port at 2 {
+				reg = <2>;
+				label = "lan3";
+			};
+
+			port at 4 {
+				reg = <4>;
+				label = "cpu";
+				ethernet = <&fec1>;
+				phy-mode = "rgmii-id";
+				rx-internal-delay-ps = <2000>;
+				tx-internal-delay-ps = <2000>;
+				fixed-link {
+					full-duplex;
+					speed = <1000>;
+				};
+			};
+		};
+	};
+};
+
+&fec1 {
+	fsl,magic-packet;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_fec1>;
+	phy-mode = "rgmii-id";
+	status = "okay";
+
+	fixed-link {
+		full-duplex;
+		speed = <1000>;
+	};
+};
+
+&iomuxc {
+	pinctrl_fec1: fec1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_ENET_MDC_ENET1_MDC			0x16
+			MX8MN_IOMUXC_ENET_MDIO_ENET1_MDIO		0x96
+			MX8MN_IOMUXC_ENET_TD3_ENET1_RGMII_TD3		0x16
+			MX8MN_IOMUXC_ENET_TD2_ENET1_RGMII_TD2		0x16
+			MX8MN_IOMUXC_ENET_TD1_ENET1_RGMII_TD1		0x16
+			MX8MN_IOMUXC_ENET_TD0_ENET1_RGMII_TD0		0x16
+			MX8MN_IOMUXC_ENET_RD3_ENET1_RGMII_RD3		0x96
+			MX8MN_IOMUXC_ENET_RD2_ENET1_RGMII_RD2		0x96
+			MX8MN_IOMUXC_ENET_RD1_ENET1_RGMII_RD1		0x96
+			MX8MN_IOMUXC_ENET_RD0_ENET1_RGMII_RD0		0x96
+			MX8MN_IOMUXC_ENET_TXC_ENET1_RGMII_TXC		0x10
+			MX8MN_IOMUXC_ENET_RXC_ENET1_RGMII_RXC		0x96
+			MX8MN_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x96
+			MX8MN_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x16
+			MX8MN_IOMUXC_SAI3_TXFS_GPIO4_IO31		0x1d6
+		>;
+	};
+
+	pinctrl_ks8794: ks8794-grp {
+		fsl,pins = <
+			/* KSZ8794 reset line */
+			MX8MN_IOMUXC_SAI3_RXFS_GPIO4_IO28		0x16
+		>;
+	};
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtso b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtso
new file mode 100644
index 0000000000000..20eb427f3dd66
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtso
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2021 Marek Vasut
+ */
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+#include "imx8mn-pinfunc.h"
+
+&pinctrl_ecspi1 {
+	fsl,pins = <
+		MX8MN_IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK		0x10
+		MX8MN_IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI		0x10
+		MX8MN_IOMUXC_ECSPI1_MISO_ECSPI1_MISO		0x90
+		/* KS8794 nCS */
+		MX8MN_IOMUXC_I2C4_SDA_GPIO5_IO21		0x150
+		/* ANV32C81 nCS */
+		MX8MN_IOMUXC_ECSPI1_SS0_GPIO5_IO9		0x150
+	>;
+};
+
+#include "imx8mn-vhip4-evalboard-ksz8794-common.dtsi"
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtso b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtso
new file mode 100644
index 0000000000000..84ea915b4cd54
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtso
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2021 Marek Vasut
+ */
+/dts-v1/;
+/plugin/;
+
+#include "imx8mn-pinfunc.h"
+
+&fec1 {
+	fsl,magic-packet;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_fec1>;
+	phy-handle = <&ethphy0>;
+	phy-mode = "rgmii-id";
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy0: ethernet-phy at 0 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <0>;
+		};
+	};
+};
+
+&iomuxc {
+	pinctrl_fec1: fec1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_ENET_MDC_ENET1_MDC			0x16
+			MX8MN_IOMUXC_ENET_MDIO_ENET1_MDIO		0x96
+			MX8MN_IOMUXC_ENET_TD3_ENET1_RGMII_TD3		0x16
+			MX8MN_IOMUXC_ENET_TD2_ENET1_RGMII_TD2		0x16
+			MX8MN_IOMUXC_ENET_TD1_ENET1_RGMII_TD1		0x16
+			MX8MN_IOMUXC_ENET_TD0_ENET1_RGMII_TD0		0x16
+			MX8MN_IOMUXC_ENET_RD3_ENET1_RGMII_RD3		0x96
+			MX8MN_IOMUXC_ENET_RD2_ENET1_RGMII_RD2		0x96
+			MX8MN_IOMUXC_ENET_RD1_ENET1_RGMII_RD1		0x96
+			MX8MN_IOMUXC_ENET_RD0_ENET1_RGMII_RD0		0x96
+			MX8MN_IOMUXC_ENET_TXC_ENET1_RGMII_TXC		0x16
+			MX8MN_IOMUXC_ENET_RXC_ENET1_RGMII_RXC		0x96
+			MX8MN_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x96
+			MX8MN_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x16
+			MX8MN_IOMUXC_SAI3_TXFS_GPIO4_IO31		0x1d6
+		>;
+	};
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1.dts b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1.dts
new file mode 100644
index 0000000000000..6d1cebffcae5d
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1.dts
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2020-2024 Fedor Ross <fedor.ross at ifm.com>
+ */
+
+/dts-v1/;
+
+#include "imx8mn-vhip4-evalboard-common.dtsi"
+
+/ {
+	model = "ifm i.MX8MNano VHIP4 Evaluation Board v1";
+	compatible = "ifm,imx8mn-vhip4-evalboard-v1", "ifm,imx8mn-vhip4-evalboard",
+		     "ifm,imx8mn-vhip4", "fsl,imx8mn";
+};
+
+&ifm_led {
+	pinctrl-1 = <&pinctrl_gpio_led_v1>;
+
+	led-2 {
+		function = LED_FUNCTION_STATUS;
+		function-enumerator = <3>;
+		color = <LED_COLOR_ID_YELLOW>;
+		gpios = <&gpio2 17 GPIO_ACTIVE_HIGH>;
+		default-state = "keep";
+	};
+
+	led-3 {
+		function = LED_FUNCTION_STATUS;
+		function-enumerator = <4>;
+		color = <LED_COLOR_ID_GREEN>;
+		gpios = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+		default-state = "keep";
+	};
+};
+
+&ecspi1 {
+	cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>, <&gpio5 21 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	eeprom at 0 {
+		compatible = "anvo,anv32c81w", "atmel,at25";
+		reg = <0>;
+		spi-max-frequency = <20000000>;
+		spi-cpha;
+		spi-cpol;
+		pagesize = <1>;
+		size = <32768>;
+		address-width = <16>;
+	};
+};
+
+&ecspi3 {
+	cs-gpios = <&gpio5 25 GPIO_ACTIVE_LOW>, <&gpio5 4 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	can0: can at 0 {
+		compatible = "microchip,mcp25625";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_mcp25625>;
+		reg = <0>;
+		clocks = <&can_clk20m>;
+		interrupt-parent = <&gpio4>;
+		interrupts = <21 IRQ_TYPE_LEVEL_LOW>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	can1: can at 1 {
+		compatible = "microchip,mcp2518fd";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_mcp2518>;
+		reg = <1>;
+		clocks = <&can_clk40m>;
+		interrupt-parent = <&gpio5>;
+		interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+		microchip,rx-int-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>;
+		spi-max-frequency = <20000000>;
+	};
+};
+
+&gpio4 {
+	/*
+	 * Hog USB-nRESET high here, since neither U-Boot nor Linux
+	 * has any support for USB Hub GPIO reset so far.
+	 */
+	usb-nreset-hog {
+		gpio-hog;
+		gpios = <29 GPIO_ACTIVE_HIGH>;
+		line-name = "USB_nRESET";
+		output-high;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_usb_nreset>;
+	};
+};
+
+&i2c1 {
+	scl-gpios = <&gpio5 14 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	sda-gpios = <&gpio5 15 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+
+	lm75 at 48 {
+		compatible = "national,lm75";
+		reg = <0x48>;
+	};
+
+	eeprom at 50 {
+		compatible = "atmel,24c128";
+		reg = <0x50>;
+	};
+};
+
+&i2c2 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default", "gpio";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	pinctrl-1 = <&pinctrl_i2c2_gpio>;
+	scl-gpios = <&gpio5 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	sda-gpios = <&gpio5 17 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+&i2c3 {
+	scl-gpios = <&gpio2 10 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	sda-gpios = <&gpio2 11 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+&ifm_pmic {
+	interrupt-parent = <&gpio2>;
+	interrupts = <0 GPIO_ACTIVE_LOW>;
+};
+
+&iomuxc {
+	pinctrl_ecspi1_cs: ecspi1-cs-grp {
+		fsl,pins = <
+			/* KS8794 nCS */
+			MX8MN_IOMUXC_I2C4_SDA_GPIO5_IO21		0x150
+			/* ANV32C81 nCS */
+			MX8MN_IOMUXC_ECSPI1_SS0_GPIO5_IO9		0x150
+		>;
+	};
+
+	pinctrl_ecspi3_cs: ecspi3-cs-grp {
+		fsl,pins = <
+			/* MCP25625 nCS */
+			MX8MN_IOMUXC_UART2_TXD_GPIO5_IO25		0x150
+			/* MCP2518FD nCS */
+			MX8MN_IOMUXC_SPDIF_RX_GPIO5_IO4			0x150
+		>;
+	};
+
+	pinctrl_gpio_led_v1: gpioled-v1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD2_DATA2_GPIO2_IO17		0x116
+			MX8MN_IOMUXC_SD2_RESET_B_GPIO2_IO19		0x116
+		>;
+	};
+
+	pinctrl_i2c1: i2c1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C1_SCL_I2C1_SCL			0x40000056
+			MX8MN_IOMUXC_I2C1_SDA_I2C1_SDA			0x400000d6
+		>;
+	};
+
+	pinctrl_i2c1_gpio: i2c1-gpio-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C1_SCL_GPIO5_IO14		0x56
+			MX8MN_IOMUXC_I2C1_SDA_GPIO5_IO15		0xd6
+		>;
+	};
+
+	pinctrl_i2c2: i2c2-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C2_SCL_I2C2_SCL			0x40000056
+			MX8MN_IOMUXC_I2C2_SDA_I2C2_SDA			0x400000d6
+		>;
+	};
+
+	pinctrl_i2c2_gpio: i2c2-gpio-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C2_SCL_GPIO5_IO16		0x56
+			MX8MN_IOMUXC_I2C2_SDA_GPIO5_IO17		0xd6
+		>;
+	};
+
+	pinctrl_i2c3: i2c3-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD1_RESET_B_I2C3_SCL		0x40000056
+			MX8MN_IOMUXC_SD1_STROBE_I2C3_SDA		0x400000d6
+		>;
+	};
+
+	pinctrl_i2c3_gpio: i2c3-gpio-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD1_RESET_B_GPIO2_IO10		0x56
+			MX8MN_IOMUXC_SD1_STROBE_GPIO2_IO11		0xd6
+		>;
+	};
+
+	pinctrl_mcp2518: mcp2518-grp {
+		fsl,pins = <
+			/* MCP2518 nINT line */
+			MX8MN_IOMUXC_SAI3_MCLK_GPIO5_IO2		0x116
+			/* MCP2518 nINT1/GPIO1 line */
+			MX8MN_IOMUXC_SAI3_TXD_GPIO5_IO1			0x116
+		>;
+	};
+
+	pinctrl_mcp25625: mcp25625-grp {
+		fsl,pins = <
+			/* MCP25625 nINT line */
+			MX8MN_IOMUXC_SAI2_RXFS_GPIO4_IO21		0x156
+		>;
+	};
+
+	pinctrl_pmic: pmic-irq-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD1_CLK_GPIO2_IO0			0x16
+		>;
+	};
+
+	pinctrl_uart3: uart3-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_UART3_RXD_UART3_DCE_RX		0x142
+			MX8MN_IOMUXC_UART3_TXD_UART3_DCE_TX		0x142
+		>;
+	};
+
+	pinctrl_usb_nreset: usbnreset-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SAI3_RXC_GPIO4_IO29                0x14a
+		>;
+	};
+
+	pinctrl_gpio_5: gpio5-grp {
+		fsl,pins = <
+			/* CFG_EEPROM_WP */
+			MX8MN_IOMUXC_I2C4_SCL_GPIO5_IO20		0x140
+		>;
+	};
+
+	pinctrl_wdog: wdog-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B		0x64
+		>;
+	};
+};
+
+&gpio5 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_gpio_5>;
+	gpio-line-names =
+		"", "", "", "", "", "", "", "",
+		"", "", "", "", "", "", "", "",
+		"", "", "", "",
+		"ifm_device_info_eeprom_wp",
+		"", "", "",
+		"", "", "", "", "", "", "", "";
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtso b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtso
new file mode 100644
index 0000000000000..535163a80d2d1
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtso
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2024 Fedor Ross <fedor.ross at ifm.com>
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include "imx8mn-pinfunc.h"
+
+&fec1 {
+	fsl,magic-packet;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_fec1>;
+	phy-handle = <&ethphy0>;
+	phy-mode = "rgmii-id";
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy0: ethernet-phy at 0 {
+			reg = <0>;
+
+			adi,rx-internal-delay-ps = <1800>;
+			adi,tx-internal-delay-ps = <2200>;
+			interrupts-extended = <&gpio4 31 IRQ_TYPE_LEVEL_LOW>;
+			reset-gpios = <&gpio4 28 GPIO_ACTIVE_LOW>;
+			reset-assert-us = <10000>;
+			reset-deassert-us = <10000>;
+		};
+	};
+};
+
+&iomuxc {
+	pinctrl_fec1: fec1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_ENET_MDC_ENET1_MDC			0x16
+			MX8MN_IOMUXC_ENET_MDIO_ENET1_MDIO		0x96
+			MX8MN_IOMUXC_ENET_TD3_ENET1_RGMII_TD3		0x16
+			MX8MN_IOMUXC_ENET_TD2_ENET1_RGMII_TD2		0x16
+			MX8MN_IOMUXC_ENET_TD1_ENET1_RGMII_TD1		0x16
+			MX8MN_IOMUXC_ENET_TD0_ENET1_RGMII_TD0		0x16
+			MX8MN_IOMUXC_ENET_RD3_ENET1_RGMII_RD3		0x96
+			MX8MN_IOMUXC_ENET_RD2_ENET1_RGMII_RD2		0x96
+			MX8MN_IOMUXC_ENET_RD1_ENET1_RGMII_RD1		0x96
+			MX8MN_IOMUXC_ENET_RD0_ENET1_RGMII_RD0		0x96
+			MX8MN_IOMUXC_ENET_TXC_ENET1_RGMII_TXC		0x16
+			MX8MN_IOMUXC_ENET_RXC_ENET1_RGMII_RXC		0x96
+			MX8MN_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x96
+			MX8MN_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x16
+			/* nRST */
+			MX8MN_IOMUXC_SAI3_RXFS_GPIO4_IO28		0x156
+			/* nIRQ */
+			MX8MN_IOMUXC_SAI3_TXFS_GPIO4_IO31		0x1d6
+		>;
+	};
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtso b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtso
new file mode 100644
index 0000000000000..ab1304ebd965e
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtso
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2021 Marek Vasut
+ */
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+#include "imx8mn-pinfunc.h"
+
+&pinctrl_ecspi1 {
+	fsl,pins = <
+		MX8MN_IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK		0x10
+		MX8MN_IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI		0x10
+		MX8MN_IOMUXC_ECSPI1_MISO_ECSPI1_MISO		0x90
+		/* KS8794 nCS */
+		MX8MN_IOMUXC_GPIO1_IO11_GPIO1_IO11		0x150
+		/* ANV32C81 nCS */
+		MX8MN_IOMUXC_ECSPI1_SS0_GPIO5_IO9		0x150
+	>;
+};
+
+#include "imx8mn-vhip4-evalboard-ksz8794-common.dtsi"
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2.dts b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2.dts
new file mode 100644
index 0000000000000..5c17f309b93ab
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2.dts
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2024 Fedor Ross <fedor.ross at ifm.com>
+ */
+
+/dts-v1/;
+
+#include "imx8mn-vhip4-evalboard-common.dtsi"
+
+/ {
+	model = "ifm i.MX8MNano VHIP4 Evaluation Board v2";
+	compatible = "ifm,imx8mn-vhip4-evalboard-v2", "ifm,imx8mn-vhip4-evalboard",
+		     "ifm,imx8mn-vhip4", "fsl,imx8mn";
+
+	multi-led {
+		compatible = "leds-group-multicolor";
+		color = <LED_COLOR_ID_RGB>;
+		function = LED_FUNCTION_INDICATOR;
+		leds = <&rgb_0>, <&rgb_1>, <&rgb_2>;
+	};
+};
+
+&ifm_led {
+	pinctrl-1 = <&pinctrl_gpio_led_v2>;
+
+	rgb_0: rgb-led-red {
+		color = <LED_COLOR_ID_RED>;
+		gpios = <&gpio2 17 GPIO_ACTIVE_HIGH>;
+		default-state = "keep";
+	};
+
+	rgb_1: rgb-led-green {
+		color = <LED_COLOR_ID_GREEN>;
+		gpios = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+		default-state = "keep";
+	};
+
+	rgb_2: rgb-led-blue {
+		color = <LED_COLOR_ID_BLUE>;
+		gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>;
+		default-state = "keep";
+	};
+};
+
+&ecspi1 {
+	cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>, <&gpio1 11 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	eeprom at 0 {
+		compatible = "fujitsu,mb85rs64", "atmel,at25";
+		reg = <0>;
+		spi-max-frequency = <20000000>;
+		spi-cpha;
+		spi-cpol;
+		pagesize = <1>;
+		size = <32768>;
+		address-width = <16>;
+	};
+};
+
+&ecspi3 {
+	cs-gpios = <&gpio5 25 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	can0: can at 0 {
+		compatible = "microchip,mcp2518fd";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_mcp2518>;
+		reg = <0>;
+		clocks = <&can_clk40m>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
+		microchip,rx-int-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
+		spi-max-frequency = <20000000>;
+	};
+};
+
+&i2c1 {
+	scl-gpios = <&gpio2 6 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	sda-gpios = <&gpio2 7 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+
+	tmp1075 at 48 {
+		compatible = "ti,tmp1075";
+		reg = <0x48>;
+	};
+
+	eeprom at 54 {
+		compatible = "atmel,24c128";
+		reg = <0x54>;
+	};
+};
+
+&i2c3 {
+	scl-gpios = <&gpio5 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	sda-gpios = <&gpio5 19 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+&ifm_pmic {
+	interrupt-parent = <&gpio5>;
+	interrupts = <17 GPIO_ACTIVE_LOW>;
+};
+
+&iomuxc {
+	pinctrl_ecspi1_cs: ecspi1-cs-grp {
+		fsl,pins = <
+			/* KS8794 nCS */
+			MX8MN_IOMUXC_GPIO1_IO11_GPIO1_IO11		0x150
+			/* Retain memory nCS (FRAM or MRAM) */
+			MX8MN_IOMUXC_ECSPI1_SS0_GPIO5_IO9		0x150
+			/* RETAIN_nHOLD */
+			MX8MN_IOMUXC_SPDIF_RX_GPIO5_IO4			0x140
+		>;
+	};
+
+	pinctrl_ecspi3_cs: ecspi3-cs-grp {
+		fsl,pins = <
+			/* MCP2518FD nCS */
+			MX8MN_IOMUXC_UART2_TXD_GPIO5_IO25		0x150
+		>;
+	};
+
+	pinctrl_gpio_led_v2: gpioled-v2-grp {
+		fsl,pins = <
+			/* LED_RGB_RED */
+			MX8MN_IOMUXC_SD2_DATA2_GPIO2_IO17		0x116
+			/* LED_RGB_GREEN */
+			MX8MN_IOMUXC_SD2_RESET_B_GPIO2_IO19		0x116
+			/* LED_RGB_BLUE */
+			MX8MN_IOMUXC_SD2_WP_GPIO2_IO20			0x116
+		>;
+	};
+
+	pinctrl_i2c1: i2c1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD1_DATA4_I2C1_SCL			0x40000056
+			MX8MN_IOMUXC_SD1_DATA5_I2C1_SDA			0x400000d6
+		>;
+	};
+
+	pinctrl_i2c1_gpio: i2c1-gpio-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD1_DATA4_GPIO2_IO6		0x56
+			MX8MN_IOMUXC_SD1_DATA5_GPIO2_IO7		0xd6
+			/* CFG_EEPROM_WP */
+			MX8MN_IOMUXC_SD1_STROBE_GPIO2_IO11		0x140
+			/* RTC_nIRQ */
+			MX8MN_IOMUXC_SPDIF_EXT_CLK_GPIO5_IO5		0x116
+			/* LOG_EE_WP */
+			MX8MN_IOMUXC_SPDIF_TX_GPIO5_IO3			0x140
+		>;
+	};
+
+	pinctrl_i2c3: i2c3-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C3_SCL_I2C3_SCL			0x40000056
+			MX8MN_IOMUXC_I2C3_SDA_I2C3_SDA			0x400000d6
+		>;
+	};
+
+	pinctrl_i2c3_gpio: i2c3-gpio-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C3_SCL_GPIO5_IO18		0x56
+			MX8MN_IOMUXC_I2C3_SDA_GPIO5_IO19		0xd6
+		>;
+	};
+
+	pinctrl_mcp2518: mcp2518-grp {
+		fsl,pins = <
+			/* CAN0_CLKO */
+			MX8MN_IOMUXC_GPIO1_IO00_GPIO1_IO0		0x116
+			/* CAN0_nINT0 */
+			MX8MN_IOMUXC_GPIO1_IO03_GPIO1_IO3		0x116
+			/* CAN0_nINT1 */
+			MX8MN_IOMUXC_GPIO1_IO04_GPIO1_IO4		0x116
+			/* CAN0_nINT */
+			MX8MN_IOMUXC_GPIO1_IO01_GPIO1_IO1		0x116
+		>;
+	};
+
+	pinctrl_pmic: pmic-irq-grp {
+		fsl,pins = <
+			/* PMIC_nIRQ */
+			MX8MN_IOMUXC_I2C2_SDA_GPIO5_IO17		0x1d6
+		>;
+	};
+
+	pinctrl_uart3: uart3-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD1_DATA6_UART3_DCE_TX		0x142
+			MX8MN_IOMUXC_SD1_DATA7_UART3_DCE_RX		0x142
+		>;
+	};
+
+	pinctrl_wdog: wdog-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B		0x64
+		>;
+	};
+};
+
+&gpio2 {
+	gpio-line-names =
+		"", "", "", "", "", "", "", "",
+		"", "", "",
+		"ifm_device_info_eeprom_wp",
+		"", "", "", "",
+		"", "", "", "", "", "", "", "",
+		"", "", "", "", "", "", "", "";
+};
+
+&gpio5 {
+	gpio-line-names =
+		"", "", "",
+		"ifm_logging_eeprom_wp",
+		"", "", "", "",
+		"", "", "", "", "", "", "", "",
+		"", "", "", "",	"", "", "", "",
+		"", "", "", "", "", "", "", "";
+};
-- 
2.51.0



From robh at kernel.org  Mon Dec 29 12:39:24 2025
From: robh at kernel.org (Rob Herring)
Date: Mon, 29 Dec 2025 14:39:24 -0600
Subject: [PATCH v2 0/2] Add Meta(Facebook) ventura2 BMC(AST2600)
In-Reply-To: <20251224-ventura2_initial_dts-v2-0-f193ba5d4073@gmail.com>
References: <20251224-ventura2_initial_dts-v2-0-f193ba5d4073@gmail.com>
Message-ID: <176703895393.2172377.12837341812506226854.robh@kernel.org>


On Wed, 24 Dec 2025 14:44:37 +0800, Kyle Hsieh wrote:
> Summary:
> Add linux device tree entry related to Meta(Facebook) ventura2.
> specific devices connected to BMC(AST2600) SoC.
> 
> Signed-off-by: Kyle Hsieh <kylehsieh1995 at gmail.com>
> ---
> Changes in v2:
> - Remove unused mdio
> - Link to v1: https://lore.kernel.org/r/20251222-ventura2_initial_dts-v1-0-1f06166c78a3 at gmail.com
> 
> ---
> Kyle Hsieh (2):
>       dt-bindings: arm: aspeed: add Meta ventura2 board
>       ARM: dts: aspeed: ventura2: Add Meta ventura2 BMC
> 
>  .../devicetree/bindings/arm/aspeed/aspeed.yaml     |    1 +
>  arch/arm/boot/dts/aspeed/Makefile                  |    1 +
>  .../dts/aspeed/aspeed-bmc-facebook-ventura2.dts    | 2945 ++++++++++++++++++++
>  3 files changed, 2947 insertions(+)
> ---
> base-commit: 9448598b22c50c8a5bb77a9103e2d49f134c9578
> change-id: 20251222-ventura2_initial_dts-909b3277d665
> 
> Best regards,
> --
> Kyle Hsieh <kylehsieh1995 at gmail.com>
> 
> 
> 


My bot found new DTB warnings on the .dts files added or changed in this
series.

Some warnings may be from an existing SoC .dtsi. Or perhaps the warnings
are fixed by another series. Ultimately, it is up to the platform
maintainer whether these warnings are acceptable or not. No need to reply
unless the platform maintainer has comments.

If you already ran DT checks and didn't see these error(s), then
make sure dt-schema is up to date:

  pip3 install dtschema --upgrade


This patch series was applied (using b4) to base:
 Base: 9448598b22c50c8a5bb77a9103e2d49f134c9578 (use --merge-base to override)

If this is not the correct base, please add 'base-commit' tag
(or use b4 which does this automatically)

New warnings running 'make CHECK_DTBS=y for arch/arm/boot/dts/aspeed/' for 20251224-ventura2_initial_dts-v2-0-f193ba5d4073 at gmail.com:

arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-ventura2.dtb: / (facebook,ventura2-rmc): compatible: 'oneOf' conditional failed, one must be fixed:
	'facebook,ventura2-rmc' is not one of ['delta,ahe50dc-bmc', 'facebook,galaxy100-bmc', 'facebook,wedge100-bmc', 'facebook,wedge40-bmc', 'microsoft,olympus-bmc', 'quanta,q71l-bmc', 'tyan,palmetto-bmc', 'yadro,vesnin-bmc']
	'facebook,ventura2-rmc' is not one of ['amd,daytonax-bmc', 'amd,ethanolx-bmc', 'ampere,mtjade-bmc', 'aspeed,ast2500-evb', 'asrock,e3c246d4i-bmc', 'asrock,e3c256d4i-bmc', 'asrock,romed8hm3-bmc', 'asrock,spc621d8hm3-bmc', 'asrock,x570d4u-bmc', 'bytedance,g220a-bmc', 'facebook,cmm-bmc', 'facebook,minipack-bmc', 'facebook,tiogapass-bmc', 'facebook,yamp-bmc', 'facebook,yosemitev2-bmc', 'facebook,wedge400-bmc', 'facebook,wedge400-data64-bmc', 'hxt,stardragon4800-rep2-bmc', 'ibm,mihawk-bmc', 'ibm,mowgli-bmc', 'ibm,romulus-bmc', 'ibm,swift-bmc', 'ibm,witherspoon-bmc', 'ingrasys,zaius-bmc', 'inspur,fp5280g2-bmc', 'inspur,nf5280m6-bmc', 'inspur,on5263m5-bmc', 'intel,s2600wf-bmc', 'inventec,lanyang-bmc', 'lenovo,hr630-bmc', 'lenovo,hr855xg2-bmc', 'portwell,neptune-bmc', 'qcom,centriq2400-rep-bmc', 'supermicro,x11spi-bmc', 'tyan,s7106-bmc', 'tyan,s8036-bmc', 'yadro,nicole-bmc', 'yadro,vegman-n110-bmc', 'yadro,vegman-rx20-bmc', 'yadro,vegman-sx20-bmc']
	'facebook,ventura2-rmc' is not one of ['ampere,mtjefferson-bmc', 'ampere,mtmitchell-bmc', 'aspeed,ast2600-evb', 'aspeed,ast2600-evb-a1', 'asus,x4tf-bmc', 'facebook,bletchley-bmc', 'facebook,catalina-bmc', 'facebook,clemente-bmc', 'facebook,cloudripper-bmc', 'facebook,darwin-bmc', 'facebook,elbert-bmc', 'facebook,fuji-bmc', 'facebook,fuji-data64-bmc', 'facebook,greatlakes-bmc', 'facebook,harma-bmc', 'facebook,minerva-cmc', 'facebook,santabarbara-bmc', 'facebook,ventura2-bmc', 'facebook,yosemite4-bmc', 'facebook,yosemite5-bmc', 'ibm,balcones-bmc', 'ibm,blueridge-bmc', 'ibm,bonnell-bmc', 'ibm,everest-bmc', 'ibm,fuji-bmc', 'ibm,rainier-bmc', 'ibm,sbp1-bmc', 'ibm,system1-bmc', 'ibm,tacoma-bmc', 'inventec,starscream-bmc', 'inventec,transformer-bmc', 'jabil,rbp-bmc', 'nvidia,gb200nvl-bmc', 'qcom,dc-scm-v1-bmc', 'quanta,s6q-bmc', 'ufispace,ncplite-bmc']
	'aspeed,ast2400' was expected
	'aspeed,ast2500' was expected
	from schema $id: http://devicetree.org/schemas/arm/aspeed/aspeed.yaml
arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-ventura2.dtb: /: failed to match any schema with compatible: ['facebook,ventura2-rmc', 'aspeed,ast2600']
arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-ventura2.dtb: timer (arm,armv7-timer): 'clocks' does not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/timer/arm,arch_timer.yaml
arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-ventura2.dtb: sdram at 1e6e0000 (aspeed,ast2600-sdram-edac): compatible: ['aspeed,ast2600-sdram-edac', 'syscon'] is too long
	from schema $id: http://devicetree.org/schemas/edac/aspeed,ast2400-sdram-edac.yaml
arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-ventura2.dtb: bus at 1e600000 (aspeed,ast2600-ahbc): compatible: ['aspeed,ast2600-ahbc', 'syscon'] is too long
	from schema $id: http://devicetree.org/schemas/bus/aspeed,ast2600-ahbc.yaml
arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-ventura2.dtb: syscon at 1e6e2000 (aspeed,ast2600-scu): 'smp-memram at 180' does not match any of the regexes: '^interrupt-controller@[0-9a-f]+$', '^p2a-control@[0-9a-f]+$', '^pinctrl(@[0-9a-f]+)?$', '^pinctrl-[0-9]+$', '^silicon-id@[0-9a-f]+$'
	from schema $id: http://devicetree.org/schemas/mfd/aspeed,ast2x00-scu.yaml
arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-ventura2.dtb: /ahb/apb/syscon at 1e6e2000/smp-memram at 180: failed to match any schema with compatible: ['aspeed,ast2600-smpmem']
arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-ventura2.dtb: adc at 1e6e9000 (aspeed,ast2600-adc0): 'interrupts' does not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/iio/adc/aspeed,ast2600-adc.yaml
arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-ventura2.dtb: adc at 1e6e9100 (aspeed,ast2600-adc1): 'interrupts' does not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/iio/adc/aspeed,ast2600-adc.yaml
arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-ventura2.dtb: crypto at 1e6fa000 (aspeed,ast2600-acry): 'aspeed,ahbc' does not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/crypto/aspeed,ast2600-acry.yaml
arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-ventura2.dtb: /ahb/apb/lpc at 1e789000/lhc at a0: failed to match any schema with compatible: ['aspeed,ast2600-lhc']
arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-ventura2.dtb: i2c at 400 (aspeed,ast2600-i2c-bus): Unevaluated properties are not allowed ('aspeed,hw-timeout-ms' was unexpected)
	from schema $id: http://devicetree.org/schemas/i2c/aspeed,i2c.yaml
arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-ventura2.dtb: /ahb/apb/bus at 1e78a000/i2c at 580/power-monitor at 69: failed to match any schema with compatible: ['pmbus']
arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-ventura2.dtb: /ahb/apb/dma-controller at 1e79e000: failed to match any schema with compatible: ['aspeed,ast2600-udma']







From robh at kernel.org  Mon Dec 29 12:39:25 2025
From: robh at kernel.org (Rob Herring)
Date: Mon, 29 Dec 2025 14:39:25 -0600
Subject: [PATCH v2] ARM: dts: integrator: Fix DMA ranges mismatch
 warning on IM-PD1
In-Reply-To: <20251225173118.580110-1-visitorckw@gmail.com>
References: <20251225173118.580110-1-visitorckw@gmail.com>
Message-ID: <176703895443.2172504.7231951665641312391.robh@kernel.org>


On Thu, 25 Dec 2025 17:31:18 +0000, Kuan-Wei Chiu wrote:
> When compiling the device tree for the Integrator/AP with IM-PD1, the
> following warning is observed regarding the display controller node:
> 
> arch/arm/boot/dts/arm/integratorap-im-pd1.dts:251.3-14: Warning
> (dma_ranges_format):
> /bus at c0000000/bus at c0000000/display at 1000000:dma-ranges: empty
> "dma-ranges" property but its #address-cells (2) differs from
> /bus at c0000000/bus at c0000000 (1)
> 
> The "dma-ranges" property is intended to describe DMA address
> translations for child nodes. However, the only child of the display
> controller is a "port" node, which does not perform DMA memory
> accesses.
> 
> Since the property is not required for the child node and triggers a
> warning due to default address cell mismatch, remove it.
> 
> Fixes: 7bea67a99430 ("ARM: dts: integrator: Fix DMA ranges")
> Cc: stable at vger.kernel.org
> Signed-off-by: Kuan-Wei Chiu <visitorckw at gmail.com>
> ---
> Changes in v2:
> - Switch approach to remove the unused "dma-ranges" property instead of
>   adding "#address-cells" and "#size-cells".
> 
>  arch/arm/boot/dts/arm/integratorap-im-pd1.dts | 1 -
>  1 file changed, 1 deletion(-)
> 


My bot found new DTB warnings on the .dts files added or changed in this
series.

Some warnings may be from an existing SoC .dtsi. Or perhaps the warnings
are fixed by another series. Ultimately, it is up to the platform
maintainer whether these warnings are acceptable or not. No need to reply
unless the platform maintainer has comments.

If you already ran DT checks and didn't see these error(s), then
make sure dt-schema is up to date:

  pip3 install dtschema --upgrade


This patch series was applied (using b4) to base:
 Base: attempting to guess base-commit...
 Base: tags/next-20251219 (exact match)
 Base: tags/next-20251219 (use --merge-base to override)

If this is not the correct base, please add 'base-commit' tag
(or use b4 which does this automatically)

New warnings running 'make CHECK_DTBS=y for arch/arm/boot/dts/arm/' for 20251225173118.580110-1-visitorckw at gmail.com:

arch/arm/boot/dts/arm/integratorap-im-pd1.dtb: display at 1000000 (arm,pl110): 'port at 0' does not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/display/arm,pl11x.yaml







From stefano.radaelli21 at gmail.com  Mon Dec 29 12:58:58 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Mon, 29 Dec 2025 21:58:58 +0100
Subject: [PATCH v1 3/3] arm64: dts: imx95-var-dart: Add support for
 Variscite Sonata board
In-Reply-To: <0afc0945-af65-410d-8556-1d09792981cb@lunn.ch>
References: <20251229150421.57616-1-stefano.r@variscite.com>
 <20251229150421.57616-4-stefano.r@variscite.com>
 <0afc0945-af65-410d-8556-1d09792981cb@lunn.ch>
Message-ID: <aVLrkqgjrsX7jfYw@Lord-Beerus.station>

On Mon, Dec 29, 2025 at 07:24:50PM +0100, Andrew Lunn wrote:
> 
> What is this ethernet connected to? In the commit message you mention
> an SFP? So i would expect a phandle pointing to the SFP cage node,
> which follows:
> 
> Documentation/devicetree/bindings/net/sff,sfp.yam
> 
> 	Andrew

Hi Andrew,

You're absolutely right, thanks for pointing that out!

I mistakenly thought fixed-link alone was sufficient, but after reading
the sff,sfp.yaml binding I understand the sfp node is needed to properly
handle the SFP+ cage and transceiver module detection via I2C.

I've updated the patch to include the sfp node with i2c-bus and
los-gpios properties.

Sending v2 shortly.

Thanks,
Stefano


From stefano.radaelli21 at gmail.com  Mon Dec 29 13:37:14 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Mon, 29 Dec 2025 22:37:14 +0100
Subject: [PATCH v2 0/3] Add support for Variscite DART-MX95 and Sonata board
Message-ID: <20251229213726.79374-1-stefano.r@variscite.com>

From: Stefano Radaelli <stefano.r at variscite.com>

This patch series adds support for the Variscite DART-MX95 system on
module and the Sonata carrier board.

The series includes:
- Device tree bindings documentation for both SOM and carrier board
- SOM device tree with on-module peripherals
- Sonata carrier board device tree with board-specific features

The implementation follows the standard SOM + carrier board pattern
where the SOM dtsi contains only peripherals mounted on the module,
while carrier-specific interfaces are enabled in the board dts.

v2:
- Add SFP cage node for enetc_port2 following sff,sfp.yaml binding

Stefano Radaelli (3):
  dt-bindings: arm: fsl: add Variscite DART-MX95 Boards
  arm64: dts: freescale: Add support for Variscite DART-MX95
  arm64: dts: imx95-var-dart: Add support for Variscite Sonata board

 .../devicetree/bindings/arm/fsl.yaml          |   6 +
 arch/arm64/boot/dts/freescale/Makefile        |   1 +
 .../dts/freescale/imx95-var-dart-sonata.dts   | 595 ++++++++++++++++++
 .../boot/dts/freescale/imx95-var-dart.dtsi    | 462 ++++++++++++++
 4 files changed, 1064 insertions(+)
 create mode 100644 arch/arm64/boot/dts/freescale/imx95-var-dart-sonata.dts
 create mode 100644 arch/arm64/boot/dts/freescale/imx95-var-dart.dtsi


base-commit: 40fbbd64bba6c6e7a72885d2f59b6a3be9991eeb
-- 
2.47.3



From stefano.radaelli21 at gmail.com  Mon Dec 29 13:37:15 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Mon, 29 Dec 2025 22:37:15 +0100
Subject: [PATCH v2 1/3] dt-bindings: arm: fsl: add Variscite DART-MX95 Boards
In-Reply-To: <20251229213726.79374-1-stefano.r@variscite.com>
References: <20251229213726.79374-1-stefano.r@variscite.com>
Message-ID: <20251229213726.79374-2-stefano.r@variscite.com>

From: Stefano Radaelli <stefano.r at variscite.com>

Add DT compatible strings for Variscite DART-MX95 SoM and Variscite
development carrier Board.

Link: https://variscite.com/system-on-module-som/i-mx-9/dart-mx95/
Link: https://variscite.com/carrier-boards/sonata-board/
Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 Documentation/devicetree/bindings/arm/fsl.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
index 68a2d5fecc43..2a957a593abe 100644
--- a/Documentation/devicetree/bindings/arm/fsl.yaml
+++ b/Documentation/devicetree/bindings/arm/fsl.yaml
@@ -1449,6 +1449,12 @@ properties:
           - const: toradex,smarc-imx95     # Toradex SMARC iMX95 Module
           - const: fsl,imx95
 
+      - description: Variscite DART-MX95 based Boards
+        items:
+          - const: variscite,var-dart-mx95-sonata # Variscite DART-MX95 SOM on Sonata Development Board
+          - const: variscite,var-dart-mx95 # Variscite DART-MX95 SOM
+          - const: fsl,imx95
+
       - description: i.MXRT1050 based Boards
         items:
           - enum:
-- 
2.47.3



From stefano.radaelli21 at gmail.com  Mon Dec 29 13:37:16 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Mon, 29 Dec 2025 22:37:16 +0100
Subject: [PATCH v2 2/3] arm64: dts: freescale: Add support for Variscite DART-MX95
In-Reply-To: <20251229213726.79374-1-stefano.r@variscite.com>
References: <20251229213726.79374-1-stefano.r@variscite.com>
Message-ID: <20251229213726.79374-3-stefano.r@variscite.com>

From: Stefano Radaelli <stefano.r at variscite.com>

Add device tree support for the Variscite DART-MX95 system on module.
This SOM is designed to be used with various carrier boards.

The module includes:
- NXP i.MX95 MPU processor
- Up to 16GB of LPDDR5 memory
- Up to 128GB of eMMC storage memory
- Integrated 10/100/1000 Mbps Ethernet Transceiver
- Codec audio WM8904
- WIFI6 dual-band 802.11ax/ac/a/b/g/n with optional 802.15.4 and Bluetooth

Only SOM-specific peripherals are enabled by default. Carrier board
specific interfaces are left disabled to be enabled in the respective
carrier board device trees.

Link: https://variscite.com/system-on-module-som/i-mx-9/i-mx-95/dart-mx95/
Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
 .../boot/dts/freescale/imx95-var-dart.dtsi    | 462 ++++++++++++++++++
 1 file changed, 462 insertions(+)
 create mode 100644 arch/arm64/boot/dts/freescale/imx95-var-dart.dtsi

diff --git a/arch/arm64/boot/dts/freescale/imx95-var-dart.dtsi b/arch/arm64/boot/dts/freescale/imx95-var-dart.dtsi
new file mode 100644
index 000000000000..ed93701a8e4c
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx95-var-dart.dtsi
@@ -0,0 +1,462 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Common dtsi for Variscite DART-MX95
+ *
+ * Link: https://variscite.com/system-on-module-som/i-mx-9/i-mx-95/dart-mx95/
+ *
+ * Copyright (C) 2025 Variscite Ltd. - https://www.variscite.com/
+ *
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/usb/pd.h>
+#include "imx95.dtsi"
+
+/ {
+	model = "Variscite DART-MX95 Module";
+	compatible = "variscite,var-dart-mx95", "fsl,imx95";
+
+	memory at 80000000 {
+		device_type = "memory";
+		reg = <0x0 0x80000000 0 0x80000000>;
+	};
+
+	reg_1p8v: regulator-1p8v {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <1800000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-name = "+V1.8_SW";
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "+V3.3_SW";
+	};
+
+	reg_audio: regulator-audio-vdd {
+		compatible = "regulator-fixed";
+		regulator-name = "wm8904_supply";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	reg_vref_1v8: regulator-adc-vref {
+		compatible = "regulator-fixed";
+		regulator-name = "vref_1v8";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	reserved-memory {
+		ranges;
+		#address-cells = <2>;
+		#size-cells = <2>;
+
+		linux_cma: linux,cma {
+			compatible = "shared-dma-pool";
+			alloc-ranges = <0 0x80000000 0 0x7F000000>;
+			reusable;
+			size = <0 0x3c000000>;
+			linux,cma-default;
+		};
+
+		vdev0vring0: vdev0vring0 at 88000000 {
+			reg = <0 0x88000000 0 0x8000>;
+			no-map;
+		};
+
+		vdev0vring1: vdev0vring1 at 88008000 {
+			reg = <0 0x88008000 0 0x8000>;
+			no-map;
+		};
+
+		vdev1vring0: vdev1vring0 at 88010000 {
+			reg = <0 0x88010000 0 0x8000>;
+			no-map;
+		};
+
+		vdev1vring1: vdev1vring1 at 88018000 {
+			reg = <0 0x88018000 0 0x8000>;
+			no-map;
+		};
+
+		vdevbuffer: vdevbuffer at 88020000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x88020000 0 0x100000>;
+			no-map;
+		};
+
+		rsc_table: rsc-table at 88220000 {
+			reg = <0 0x88220000 0 0x1000>;
+			no-map;
+		};
+
+		vpu_boot: vpu_boot at a0000000 {
+			reg = <0 0xa0000000 0 0x100000>;
+			no-map;
+		};
+	};
+
+	sound-wm8904 {
+		compatible = "simple-audio-card";
+		simple-audio-card,bitclock-master = <&codec_dai>;
+		simple-audio-card,format = "i2s";
+		simple-audio-card,frame-master = <&codec_dai>;
+		simple-audio-card,mclk-fs = <256>;
+		simple-audio-card,name = "wm8904-audio";
+		simple-audio-card,routing =
+			"Headphone Jack", "HPOUTL",
+			"Headphone Jack", "HPOUTR",
+			"IN2L", "Line In Jack",
+			"IN2R", "Line In Jack",
+			"IN1L", "Microphone Jack",
+			"IN1R", "Microphone Jack";
+		simple-audio-card,widgets =
+			"Microphone", "Microphone Jack",
+			"Headphone", "Headphone Jack",
+			"Line", "Line In Jack";
+
+		codec_dai: simple-audio-card,codec {
+			sound-dai = <&wm8904>;
+		};
+
+		simple-audio-card,cpu {
+			sound-dai = <&sai3>;
+		};
+	};
+
+	wifi_pwrseq: wifi-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		post-power-on-delay-ms = <100>;
+		power-off-delay-us = <10000>;
+		reset-gpios = <&gpio4 29 GPIO_ACTIVE_LOW>, /* WIFI_RESET */
+			      <&gpio2 27 GPIO_ACTIVE_LOW>; /* WIFI_PWR_EN */
+	};
+};
+
+&adc1 {
+	vref-supply = <&reg_vref_1v8>;
+	status = "okay";
+};
+
+&enetc_port0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_enetc0>;
+	phy-handle = <&ethphy0>;
+	/*
+	 * The required RGMII TX and RX 2ns delays are implemented directly
+	 * in hardware via passive delay elements on the SOM PCB.
+	 * No delay configuration is needed in software via PHY driver.
+	 */
+	phy-mode = "rgmii";
+	status = "okay";
+};
+
+&lpi2c8 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default","gpio","sleep";
+	pinctrl-0 = <&pinctrl_lpi2c8>;
+	pinctrl-1 = <&pinctrl_lpi2c8_gpio>;
+	pinctrl-2 = <&pinctrl_lpi2c8_gpio>;
+	scl-gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>;
+	sda-gpios = <&gpio2 11 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+
+	wm8904: codec at 1a {
+		compatible = "wlf,wm8904";
+		reg = <0x1a>;
+		#sound-dai-cells = <0>;
+		clocks = <&scmi_clk IMX95_CLK_SAI3>;
+		clock-names = "mclk";
+		AVDD-supply = <&reg_audio>;
+		CPVDD-supply = <&reg_audio>;
+		DBVDD-supply = <&reg_audio>;
+		DCVDD-supply = <&reg_audio>;
+		MICVDD-supply = <&reg_audio>;
+		wlf,drc-cfg-names = "default", "peaklimiter", "tradition",
+				    "soft", "music";
+		/*
+		 * Config registers per name, respectively:
+		 * KNEE_IP = 0,   KNEE_OP = 0,     HI_COMP = 1,   LO_COMP = 1
+		 * KNEE_IP = -24, KNEE_OP = -6,    HI_COMP = 1/4, LO_COMP = 1
+		 * KNEE_IP = -42, KNEE_OP = -3,    HI_COMP = 0,   LO_COMP = 1
+		 * KNEE_IP = -45, KNEE_OP = -9,    HI_COMP = 1/8, LO_COMP = 1
+		 * KNEE_IP = -30, KNEE_OP = -10.5, HI_COMP = 1/4, LO_COMP = 1
+		 */
+		wlf,drc-cfg-regs = /bits/ 16 <0x01af 0x3248 0x0000 0x0000>,
+				   /bits/ 16 <0x04af 0x324b 0x0010 0x0408>,
+				   /bits/ 16 <0x04af 0x324b 0x0028 0x0704>,
+				   /bits/ 16 <0x04af 0x324b 0x0018 0x078c>,
+				   /bits/ 16 <0x04af 0x324b 0x0010 0x050e>;
+		/* GPIO1 = DMIC_CLK, don't touch others */
+		wlf,gpio-cfg = <0x0018>, <0xffff>, <0xffff>, <0xffff>;
+	};
+};
+
+/* BT */
+&lpuart5 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart5>, <&pinctrl_bt>;
+	status = "okay";
+
+	bluetooth {
+		compatible = "nxp,88w8987-bt";
+	};
+};
+
+&mu7 {
+	status = "okay";
+};
+
+&netc_emdio {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_emdio>, <&pinctrl_phy0res>;
+	status = "okay";
+
+	ethphy0: ethernet-phy at 0 {
+		reg = <0>;
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reset-gpios = <&gpio5 16 GPIO_ACTIVE_LOW>;
+		reset-assert-us = <10000>;
+		reset-deassert-us = <100000>;
+
+		leds {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			led at 0 {
+				reg = <0>;
+				color = <LED_COLOR_ID_YELLOW>;
+				function = LED_FUNCTION_LAN;
+				linux,default-trigger = "netdev";
+			};
+
+			led at 1 {
+				reg = <1>;
+				color = <LED_COLOR_ID_GREEN>;
+				function = LED_FUNCTION_LAN;
+				linux,default-trigger = "netdev";
+			};
+		};
+	};
+};
+
+&netc_timer {
+	status = "okay";
+};
+
+&sai3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_sai3>;
+	assigned-clocks = <&scmi_clk IMX95_CLK_AUDIOPLL1_VCO>,
+			  <&scmi_clk IMX95_CLK_AUDIOPLL2_VCO>,
+			  <&scmi_clk IMX95_CLK_AUDIOPLL1>,
+			  <&scmi_clk IMX95_CLK_AUDIOPLL2>,
+			  <&scmi_clk IMX95_CLK_SAI3>;
+	assigned-clock-parents = <0>, <0>, <0>, <0>,
+				 <&scmi_clk IMX95_CLK_AUDIOPLL1>;
+	assigned-clock-rates = <3932160000>,
+			       <3612672000>, <393216000>,
+			       <361267200>, <12288000>;
+	#sound-dai-cells = <0>;
+	fsl,sai-mclk-direction-output;
+	status = "okay";
+};
+
+&scmi_iomuxc {
+	pinctrl_bt: btgrp {
+		fsl,pins = <
+			IMX95_PAD_CCM_CLKO3__GPIO4_IO_BIT28				0x31e
+		>;
+	};
+
+	pinctrl_emdio: emdiogrp{
+		fsl,pins = <
+			IMX95_PAD_ENET1_MDC__NETCMIX_TOP_NETC_MDC			0x57e
+			IMX95_PAD_ENET1_MDIO__NETCMIX_TOP_NETC_MDIO			0x97e
+		>;
+	};
+
+	pinctrl_phy0res: phy0resgrp{
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO36__GPIO5_IO_BIT16				0x31e
+		>;
+	};
+
+	pinctrl_enetc0: enetc0grp {
+		fsl,pins = <
+			IMX95_PAD_ENET1_TD3__NETCMIX_TOP_ETH0_RGMII_TD3			0x57e
+			IMX95_PAD_ENET1_TD2__NETCMIX_TOP_ETH0_RGMII_TD2			0x57e
+			IMX95_PAD_ENET1_TD1__NETCMIX_TOP_ETH0_RGMII_TD1			0x57e
+			IMX95_PAD_ENET1_TD0__NETCMIX_TOP_ETH0_RGMII_TD0			0x57e
+			IMX95_PAD_ENET1_TX_CTL__NETCMIX_TOP_ETH0_RGMII_TX_CTL		0x57e
+			IMX95_PAD_ENET1_TXC__NETCMIX_TOP_ETH0_RGMII_TX_CLK		0x58e
+			IMX95_PAD_ENET1_RX_CTL__NETCMIX_TOP_ETH0_RGMII_RX_CTL		0x57e
+			IMX95_PAD_ENET1_RXC__NETCMIX_TOP_ETH0_RGMII_RX_CLK		0x58e
+			IMX95_PAD_ENET1_RD0__NETCMIX_TOP_ETH0_RGMII_RD0			0x57e
+			IMX95_PAD_ENET1_RD1__NETCMIX_TOP_ETH0_RGMII_RD1			0x57e
+			IMX95_PAD_ENET1_RD2__NETCMIX_TOP_ETH0_RGMII_RD2			0x57e
+			IMX95_PAD_ENET1_RD3__NETCMIX_TOP_ETH0_RGMII_RD3			0x57e
+		>;
+	};
+
+	pinctrl_lpi2c8: lpi2c8grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO10__LPI2C8_SDA					0x40000b9e
+			IMX95_PAD_GPIO_IO11__LPI2C8_SCL					0x40000b9e
+		>;
+	};
+
+	pinctrl_lpi2c8_gpio: lpi2c8gpiogrp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO10__GPIO2_IO_BIT10				0x31e
+			IMX95_PAD_GPIO_IO11__GPIO2_IO_BIT11				0x31e
+		>;
+	};
+
+	pinctrl_sai3: sai3grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO17__SAI3_MCLK					0x31e
+			IMX95_PAD_GPIO_IO16__SAI3_TX_BCLK				0x31e
+			IMX95_PAD_GPIO_IO26__SAI3_TX_SYNC				0x31e
+			IMX95_PAD_GPIO_IO20__SAI3_RX_DATA_BIT0				0x31e
+			IMX95_PAD_GPIO_IO21__SAI3_TX_DATA_BIT0				0x31e
+		>;
+	};
+
+	pinctrl_uart5: uart5grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO00__LPUART5_TX					0x31e
+			IMX95_PAD_GPIO_IO01__LPUART5_RX					0x31e
+			IMX95_PAD_GPIO_IO02__LPUART5_CTS_B				0x31e
+			IMX95_PAD_GPIO_IO03__LPUART5_RTS_B				0x31e
+		>;
+	};
+
+	pinctrl_usdhc1: usdhc1grp {
+		fsl,pins = <
+			IMX95_PAD_SD1_CLK__USDHC1_CLK					0x158e
+			IMX95_PAD_SD1_CMD__USDHC1_CMD					0x138e
+			IMX95_PAD_SD1_DATA0__USDHC1_DATA0				0x138e
+			IMX95_PAD_SD1_DATA1__USDHC1_DATA1				0x138e
+			IMX95_PAD_SD1_DATA2__USDHC1_DATA2				0x138e
+			IMX95_PAD_SD1_DATA3__USDHC1_DATA3				0x138e
+			IMX95_PAD_SD1_DATA4__USDHC1_DATA4				0x138e
+			IMX95_PAD_SD1_DATA5__USDHC1_DATA5				0x138e
+			IMX95_PAD_SD1_DATA6__USDHC1_DATA6				0x138e
+			IMX95_PAD_SD1_DATA7__USDHC1_DATA7				0x138e
+			IMX95_PAD_SD1_STROBE__USDHC1_STROBE				0x158e
+		>;
+	};
+
+	pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp {
+		fsl,pins = <
+			IMX95_PAD_SD1_CLK__USDHC1_CLK					0x158e
+			IMX95_PAD_SD1_CMD__USDHC1_CMD					0x138e
+			IMX95_PAD_SD1_DATA0__USDHC1_DATA0				0x138e
+			IMX95_PAD_SD1_DATA1__USDHC1_DATA1				0x138e
+			IMX95_PAD_SD1_DATA2__USDHC1_DATA2				0x138e
+			IMX95_PAD_SD1_DATA3__USDHC1_DATA3				0x138e
+			IMX95_PAD_SD1_DATA4__USDHC1_DATA4				0x138e
+			IMX95_PAD_SD1_DATA5__USDHC1_DATA5				0x138e
+			IMX95_PAD_SD1_DATA6__USDHC1_DATA6				0x138e
+			IMX95_PAD_SD1_DATA7__USDHC1_DATA7				0x138e
+			IMX95_PAD_SD1_STROBE__USDHC1_STROBE				0x158e
+		>;
+	};
+
+	pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp {
+		fsl,pins = <
+			IMX95_PAD_SD1_CLK__USDHC1_CLK					0x15fe
+			IMX95_PAD_SD1_CMD__USDHC1_CMD					0x13fe
+			IMX95_PAD_SD1_DATA0__USDHC1_DATA0				0x13fe
+			IMX95_PAD_SD1_DATA1__USDHC1_DATA1				0x13fe
+			IMX95_PAD_SD1_DATA2__USDHC1_DATA2				0x13fe
+			IMX95_PAD_SD1_DATA3__USDHC1_DATA3				0x13fe
+			IMX95_PAD_SD1_DATA4__USDHC1_DATA4				0x13fe
+			IMX95_PAD_SD1_DATA5__USDHC1_DATA5				0x13fe
+			IMX95_PAD_SD1_DATA6__USDHC1_DATA6				0x13fe
+			IMX95_PAD_SD1_DATA7__USDHC1_DATA7				0x13fe
+			IMX95_PAD_SD1_STROBE__USDHC1_STROBE				0x15fe
+		>;
+	};
+
+	pinctrl_usdhc3_gpio: usdhc3gpiogrp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO27__GPIO2_IO_BIT27				0x31e
+			IMX95_PAD_CCM_CLKO4__GPIO4_IO_BIT29				0x31e
+		>;
+	};
+
+	pinctrl_usdhc3: usdhc3grp {
+		fsl,pins = <
+			IMX95_PAD_SD3_CLK__USDHC3_CLK					0x158e
+			IMX95_PAD_SD3_CMD__USDHC3_CMD					0x138e
+			IMX95_PAD_SD3_DATA0__USDHC3_DATA0				0x138e
+			IMX95_PAD_SD3_DATA1__USDHC3_DATA1				0x138e
+			IMX95_PAD_SD3_DATA2__USDHC3_DATA2				0x138e
+			IMX95_PAD_SD3_DATA3__USDHC3_DATA3				0x138e
+		>;
+	};
+
+	pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp {
+		fsl,pins = <
+			IMX95_PAD_SD3_CLK__USDHC3_CLK					0x158e
+			IMX95_PAD_SD3_CMD__USDHC3_CMD					0x138e
+			IMX95_PAD_SD3_DATA0__USDHC3_DATA0				0x138e
+			IMX95_PAD_SD3_DATA1__USDHC3_DATA1				0x138e
+			IMX95_PAD_SD3_DATA2__USDHC3_DATA2				0x138e
+			IMX95_PAD_SD3_DATA3__USDHC3_DATA3				0x138e
+		>;
+	};
+
+	pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp {
+		fsl,pins = <
+			IMX95_PAD_SD3_CLK__USDHC3_CLK					0x15fe
+			IMX95_PAD_SD3_CMD__USDHC3_CMD					0x13fe
+			IMX95_PAD_SD3_DATA0__USDHC3_DATA0				0x13fe
+			IMX95_PAD_SD3_DATA1__USDHC3_DATA1				0x13fe
+			IMX95_PAD_SD3_DATA2__USDHC3_DATA2				0x13fe
+			IMX95_PAD_SD3_DATA3__USDHC3_DATA3				0x13fe
+		>;
+	};
+};
+
+/* eMMC */
+&usdhc1 {
+	pinctrl-names = "default","state_100mhz","state_200mhz","sleep";
+	pinctrl-0 = <&pinctrl_usdhc1>;
+	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
+	pinctrl-3 = <&pinctrl_usdhc1>;
+	bus-width = <8>;
+	non-removable;
+	no-sdio;
+	no-sd;
+	status = "okay";
+};
+
+/* WiFi */
+&usdhc3 {
+	pinctrl-names = "default","state_100mhz","state_200mhz","sleep";
+	pinctrl-0 = <&pinctrl_usdhc3>, <&pinctrl_usdhc3_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc3_100mhz>, <&pinctrl_usdhc3_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc3_200mhz>, <&pinctrl_usdhc3_gpio>;
+	pinctrl-3 = <&pinctrl_usdhc3>, <&pinctrl_usdhc3_gpio>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	bus-width = <4>;
+	non-removable;
+	wakeup-source;
+	keep-power-in-suspend;
+	status = "okay";
+};
+
+&wdog3 {
+	fsl,ext-reset-output;
+	status = "okay";
+};
-- 
2.47.3



From stefano.radaelli21 at gmail.com  Mon Dec 29 13:37:17 2025
From: stefano.radaelli21 at gmail.com (Stefano Radaelli)
Date: Mon, 29 Dec 2025 22:37:17 +0100
Subject: [PATCH v2 3/3] arm64: dts: imx95-var-dart: Add support for Variscite Sonata board
In-Reply-To: <20251229213726.79374-1-stefano.r@variscite.com>
References: <20251229213726.79374-1-stefano.r@variscite.com>
Message-ID: <20251229213726.79374-4-stefano.r@variscite.com>

From: Stefano Radaelli <stefano.r at variscite.com>

Add device tree support for the Variscite Sonata carrier board with
the DART-MX95 system on module.

The Sonata board includes
- uSD Card support
- USB ports and OTG
- Additional Gigabit Ethernet interface
- 10Gb Ethernet SFP+ connector
- Uart interfaces
- OV5640 Camera support
- GPIO Expanders
- RTC module
- TPM module
- PCIE support

Link: https://variscite.com/carrier-boards/sonata-board/
Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
---
v2:
- Add SFP cage node for enetc_port2 following sff,sfp.yaml binding

 arch/arm64/boot/dts/freescale/Makefile        |   1 +
 .../dts/freescale/imx95-var-dart-sonata.dts   | 595 ++++++++++++++++++
 2 files changed, 596 insertions(+)
 create mode 100644 arch/arm64/boot/dts/freescale/imx95-var-dart-sonata.dts

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index f30d3fd724d0..411f86013ec6 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -404,6 +404,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx95-19x19-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx95-19x19-evk-sof.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx95-toradex-smarc-dev.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx95-tqma9596sa-mb-smarc-2.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx95-var-dart-sonata.dtb
 
 imx95-15x15-evk-pcie0-ep-dtbs = imx95-15x15-evk.dtb imx-pcie0-ep.dtbo
 dtb-$(CONFIG_ARCH_MXC) += imx95-15x15-evk-pcie0-ep.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx95-var-dart-sonata.dts b/arch/arm64/boot/dts/freescale/imx95-var-dart-sonata.dts
new file mode 100644
index 000000000000..540af642abad
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx95-var-dart-sonata.dts
@@ -0,0 +1,595 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Variscite Sonata carrier board for DART-MX95
+ *
+ * Link: https://variscite.com/carrier-boards/sonata-board/
+ *
+ * Copyright (C) 2025 Variscite Ltd. - https://www.variscite.com/
+ *
+ */
+
+#include "imx95-var-dart.dtsi"
+
+/ {
+	model = "Variscite DART-MX95 on Sonata-Board";
+	compatible = "variscite,var-dart-mx95-sonata",
+		     "variscite,var-dart-mx95",
+		     "fsl,imx95";
+
+	aliases {
+		mmc0 = &usdhc1;
+		mmc1 = &usdhc2;
+		serial0 = &lpuart1;
+		ethernet0 = &enetc_port0;
+		ethernet1 = &enetc_port1;
+		ethernet2 = &enetc_port2;
+	};
+
+	chosen {
+		stdout-path = &lpuart1;
+	};
+
+	typec_con: connector {
+		compatible = "usb-c-connector";
+		data-role = "dual";
+		label = "USB-C";
+		op-sink-microwatt = <0>;
+		power-role = "dual";
+		self-powered;
+		sink-pdos = <PDO_FIXED(5000, 0, PDO_FIXED_USB_COMM)>;
+		source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
+		try-power-role = "sink";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+				typec_con_hs: endpoint {
+					remote-endpoint = <&usb3_data_hs>;
+				};
+			};
+
+			port at 1 {
+				reg = <1>;
+				typec_con_ss: endpoint {
+					remote-endpoint = <&usb3_data_ss>;
+				};
+			};
+		};
+	};
+
+	clk_osc_can0: clock-osc-40m {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <40000000>;
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpio_leds>;
+
+		led-heartbeat {
+			label = "Heartbeat";
+			gpios = <&gpio3 27 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		button-back {
+			label = "Back";
+			linux,code = <KEY_BACK>;
+			gpios = <&pca6408_1 7 GPIO_ACTIVE_LOW>;
+			wakeup-source;
+		};
+
+		button-up {
+			label = "Up";
+			linux,code = <KEY_UP>;
+			gpios = <&pca6408_1 5 GPIO_ACTIVE_LOW>;
+			wakeup-source;
+		};
+
+		button-home {
+			label = "Home";
+			linux,code = <KEY_HOME>;
+			gpios = <&pca6408_1 4 GPIO_ACTIVE_LOW>;
+			wakeup-source;
+		};
+
+		button-down {
+			label = "Down";
+			linux,code = <KEY_DOWN>;
+			gpios = <&pca6408_1 6 GPIO_ACTIVE_LOW>;
+			wakeup-source;
+		};
+	};
+
+	reg_usdhc2_vmmc: regulator-vmmc-usdhc2 {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
+		regulator-name = "VDD_SD2_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio3 7 GPIO_ACTIVE_HIGH>;
+		off-on-delay-us = <12000>;
+		enable-active-high;
+	};
+
+	reg_phy1_supply: regulator-phy1 {
+		compatible = "regulator-fixed";
+		regulator-name = "SUPPLY_PHY1";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&pca6408_2 0 GPIO_ACTIVE_LOW>;
+		startup-delay-us = <10000>;
+		enable-active-high;
+		regulator-always-on;
+	};
+
+	sfp0: sfp {
+		compatible = "sff,sfp";
+		i2c-bus = <&lpi2c3>;
+		los-gpios = <&pca9534 1 GPIO_ACTIVE_HIGH>;
+		maximum-power-milliwatt = <2000>;
+	};
+};
+
+&enetc_port1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_enetc1>;
+	phy-handle = <&ethphy1>;
+	/*
+	 * The required RGMII TX and RX 2ns delays are implemented directly
+	 * in hardware via passive delay elements on the SOM PCB.
+	 * No delay configuration is needed in software via PHY driver.
+	 */
+	phy-mode = "rgmii";
+	status = "okay";
+};
+
+&enetc_port2 {
+	phy-mode = "10gbase-r";
+	sfp = <&sfp0>;
+	status = "okay";
+
+	fixed-link {
+		speed = <10000>;
+		full-duplex;
+	};
+};
+
+&flexcan1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_flexcan1>;
+	status = "okay";
+};
+
+&lpi2c3 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default", "gpio", "sleep";
+	pinctrl-0 = <&pinctrl_lpi2c3>;
+	pinctrl-1 = <&pinctrl_lpi2c3_gpio>;
+	pinctrl-2 = <&pinctrl_lpi2c3_gpio>;
+	scl-gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>;
+	sda-gpios = <&gpio2 29 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+
+	/* DS1337 RTC module */
+	rtc at 68 {
+		compatible = "dallas,ds1337";
+		reg = <0x68>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_rtc>;
+		interrupt-parent = <&gpio5>;
+		interrupts = <12 IRQ_TYPE_EDGE_FALLING>;
+		wakeup-source;
+	};
+
+	/* Capacitive touch controller */
+	ft5x06_ts: ft5x06_ts at 38 {
+		compatible = "edt,edt-ft5206";
+		reg = <0x38>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_captouch>;
+		reset-gpios = <&pca6408_2 4 GPIO_ACTIVE_LOW>;
+		interrupt-parent = <&gpio5>;
+		interrupts = <13 IRQ_TYPE_EDGE_FALLING>;
+		touchscreen-size-x = <800>;
+		touchscreen-size-y = <480>;
+		touchscreen-inverted-x;
+		touchscreen-inverted-y;
+		wakeup-source;
+	};
+
+	pca9534: gpio at 22 {
+		compatible = "nxp,pca9534";
+		reg = <0x22>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&gpio5>;
+		interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
+
+		pcie2-sel-hog {
+			gpio-hog;
+			gpios = <6 GPIO_ACTIVE_HIGH>;
+			output-low;
+			line-name = "pcie-clk-sw";
+		};
+
+		sfp-sel-hog {
+			gpio-hog;
+			gpios = <5 GPIO_ACTIVE_HIGH>;
+			output-high;
+			line-name = "sfp-sw";
+		};
+	};
+
+	typec at 3d {
+		compatible = "nxp,ptn5150";
+		reg = <0x3d>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_ptn5150>;
+		interrupt-parent = <&gpio5>;
+		interrupts = <14 IRQ_TYPE_LEVEL_HIGH>;
+
+		port {
+			typec_dr_sw: endpoint {
+				remote-endpoint = <&usb3_drd_sw>;
+			};
+		};
+	};
+};
+
+&lpi2c4 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&pinctrl_lpi2c4>;
+	pinctrl-1 = <&pinctrl_lpi2c4>;
+	status = "okay";
+};
+
+&lpi2c8 {
+	pca6408_1: gpio at 20 {
+		compatible = "nxp,pcal6408";
+		reg = <0x20>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&gpio5>;
+		interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	pca6408_2: gpio at 21 {
+		compatible = "nxp,pcal6408";
+		reg = <0x21>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&gpio5>;
+		interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	st33ktpm2xi2c: tpm at 2e {
+		compatible = "st,st33ktpm2xi2c", "tcg,tpm-tis-i2c";
+		reg = <0x2e>;
+	};
+};
+
+&lpspi7 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_lpspi7>;
+	cs-gpios = <&gpio2 4 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	/* Resistive touch controller */
+	ads7846 at 0 {
+		compatible = "ti,ads7846";
+		reg = <0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_restouch>;
+		interrupt-parent = <&gpio2>;
+		interrupts = <24 IRQ_TYPE_EDGE_FALLING>;
+		pendown-gpio = <&gpio2 24 GPIO_ACTIVE_LOW>;
+		spi-max-frequency = <1500000>;
+		ti,x-min = /bits/ 16 <125>;
+		ti,x-max = /bits/ 16 <4008>;
+		ti,y-min = /bits/ 16 <282>;
+		ti,y-max = /bits/ 16 <3864>;
+		ti,x-plate-ohms = /bits/ 16 <180>;
+		ti,pressure-max = /bits/ 16 <255>;
+		ti,debounce-max = /bits/ 16 <10>;
+		ti,debounce-tol = /bits/ 16 <3>;
+		ti,debounce-rep = /bits/ 16 <1>;
+		ti,settle-delay-usec = /bits/ 16 <150>;
+		ti,keep-vref-on;
+		wakeup-source;
+	};
+};
+
+/* Console */
+&lpuart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart1>;
+	status = "okay";
+};
+
+/* Header (J12.4, J12.6) */
+&lpuart8 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart8>;
+	status = "okay";
+};
+
+&netc_emdio {
+
+	ethphy1: ethernet-phy at 1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <1>;
+		reset-gpios = <&pca6408_2 0 GPIO_ACTIVE_LOW>;
+		reset-assert-us = <10000>;
+		reset-deassert-us = <100000>;
+
+		leds {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			led at 0 {
+				reg = <0>;
+				color = <LED_COLOR_ID_YELLOW>;
+				function = LED_FUNCTION_LAN;
+				linux,default-trigger = "netdev";
+			};
+
+			led at 1 {
+				reg = <1>;
+				color = <LED_COLOR_ID_GREEN>;
+				function = LED_FUNCTION_LAN;
+				linux,default-trigger = "netdev";
+			};
+		};
+	};
+};
+
+&pcie0 {
+	reset-gpio = <&pca6408_2 3 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&pcie1 {
+	reset-gpio = <&pca6408_2 2 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&scmi_iomuxc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_hog>;
+
+	pinctrl_hog: hoggrp {
+		fsl,pins = <
+			/* GPIO Expanders shared IRQ */
+			IMX95_PAD_GPIO_IO37__GPIO5_IO_BIT17				0x31e
+		>;
+	};
+
+	pinctrl_captouch: captouchgrp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO33__GPIO5_IO_BIT13				0x31e
+		>;
+	};
+
+	pinctrl_enetc1: enetc1grp {
+		fsl,pins = <
+			IMX95_PAD_ENET2_TXC__NETCMIX_TOP_ETH1_RGMII_TX_CLK		0x57e
+			IMX95_PAD_ENET2_TX_CTL__NETCMIX_TOP_ETH1_RGMII_TX_CTL		0x57e
+			IMX95_PAD_ENET2_TD3__NETCMIX_TOP_ETH1_RGMII_TD3			0x57e
+			IMX95_PAD_ENET2_TD2__NETCMIX_TOP_ETH1_RGMII_TD2			0x57e
+			IMX95_PAD_ENET2_TD1__NETCMIX_TOP_ETH1_RGMII_TD1			0x57e
+			IMX95_PAD_ENET2_TD0__NETCMIX_TOP_ETH1_RGMII_TD0			0x57e
+			IMX95_PAD_ENET2_RXC__NETCMIX_TOP_ETH1_RGMII_RX_CLK		0x57e
+			IMX95_PAD_ENET2_RX_CTL__NETCMIX_TOP_ETH1_RGMII_RX_CTL		0x57e
+			IMX95_PAD_ENET2_RD0__NETCMIX_TOP_ETH1_RGMII_RD0			0x57e
+			IMX95_PAD_ENET2_RD1__NETCMIX_TOP_ETH1_RGMII_RD1			0x57e
+			IMX95_PAD_ENET2_RD2__NETCMIX_TOP_ETH1_RGMII_RD2			0x57e
+			IMX95_PAD_ENET2_RD3__NETCMIX_TOP_ETH1_RGMII_RD3			0x37e /* Enable pull-up to strap MXL86110 MDIO address */
+		>;
+	};
+
+	pinctrl_flexcan1: flexcan1grp {
+		fsl,pins = <
+			IMX95_PAD_PDM_CLK__AONMIX_TOP_CAN1_TX				0x39e
+			IMX95_PAD_PDM_BIT_STREAM0__AONMIX_TOP_CAN1_RX			0x39e
+		>;
+	};
+
+	pinctrl_gpio_leds: ledgrp {
+		fsl,pins = <
+			IMX95_PAD_CCM_CLKO2__GPIO3_IO_BIT27				0x31e
+		>;
+	};
+
+	pinctrl_lpi2c3: lpi2c3grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO28__LPI2C3_SDA					0x40000b9e
+			IMX95_PAD_GPIO_IO29__LPI2C3_SCL					0x40000b9e
+		>;
+	};
+
+	pinctrl_lpi2c3_gpio: lpi2c3gpiogrp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO28__GPIO2_IO_BIT28				0x31e
+			IMX95_PAD_GPIO_IO29__GPIO2_IO_BIT29				0x31e
+		>;
+	};
+
+	pinctrl_lpi2c4: lpi2c4grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO30__LPI2C4_SDA					0x40000b9e
+			IMX95_PAD_GPIO_IO31__LPI2C4_SCL					0x40000b9e
+		>;
+	};
+
+	pinctrl_lpspi7: lpspi7grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO04__GPIO2_IO_BIT4				0x3fe		/* j16.4 ADS7846 */
+			IMX95_PAD_UART2_TXD__AONMIX_TOP_GPIO1_IO_BIT7			0x3fe		/* j14.4 MCP2518FDT */
+			IMX95_PAD_XSPI1_DATA4__GPIO5_IO_BIT4				0x3fe		/* j25.2 spidev */
+			IMX95_PAD_GPIO_IO05__LPSPI7_SIN					0x3fe
+			IMX95_PAD_GPIO_IO06__LPSPI7_SOUT				0x3fe
+			IMX95_PAD_GPIO_IO07__LPSPI7_SCK					0x3fe
+		>;
+	};
+
+	pinctrl_ptn5150: ptn5150grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO34__GPIO5_IO_BIT14				0x31e
+		>;
+	};
+
+	pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
+		fsl,pins = <
+			IMX95_PAD_SD2_RESET_B__GPIO3_IO_BIT7				0x31e
+		>;
+	};
+
+	pinctrl_restouch: restouchgrp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO24__GPIO2_IO_BIT24				0x31e
+		>;
+	};
+
+	pinctrl_rtc: rtcgrp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO32__GPIO5_IO_BIT12				0x31e
+		>;
+	};
+
+	pinctrl_uart1: uart1grp {
+		fsl,pins = <
+			IMX95_PAD_UART1_RXD__AONMIX_TOP_LPUART1_RX			0x31e
+			IMX95_PAD_UART1_TXD__AONMIX_TOP_LPUART1_TX			0x31e
+		>;
+	};
+
+	pinctrl_uart8: uart8grp {
+		fsl,pins = <
+			IMX95_PAD_GPIO_IO13__LPUART8_RX					0x31e
+			IMX95_PAD_GPIO_IO12__LPUART8_TX					0x31e
+		>;
+	};
+
+	pinctrl_usdhc2_gpio: usdhc2gpiogrp {
+		fsl,pins = <
+			IMX95_PAD_SD2_CD_B__GPIO3_IO_BIT0				0x31e
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			IMX95_PAD_SD2_CLK__USDHC2_CLK					0x158e
+			IMX95_PAD_SD2_CMD__USDHC2_CMD					0x138e
+			IMX95_PAD_SD2_DATA0__USDHC2_DATA0				0x138e
+			IMX95_PAD_SD2_DATA1__USDHC2_DATA1				0x138e
+			IMX95_PAD_SD2_DATA2__USDHC2_DATA2				0x138e
+			IMX95_PAD_SD2_DATA3__USDHC2_DATA3				0x138e
+			IMX95_PAD_SD2_VSELECT__USDHC2_VSELECT				0x51e
+		>;
+	};
+
+	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+		fsl,pins = <
+			IMX95_PAD_SD2_CLK__USDHC2_CLK					0x158e
+			IMX95_PAD_SD2_CMD__USDHC2_CMD					0x138e
+			IMX95_PAD_SD2_DATA0__USDHC2_DATA0				0x138e
+			IMX95_PAD_SD2_DATA1__USDHC2_DATA1				0x138e
+			IMX95_PAD_SD2_DATA2__USDHC2_DATA2				0x138e
+			IMX95_PAD_SD2_DATA3__USDHC2_DATA3				0x138e
+			IMX95_PAD_SD2_VSELECT__USDHC2_VSELECT				0x51e
+		>;
+	};
+
+	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+		fsl,pins = <
+			IMX95_PAD_SD2_CLK__USDHC2_CLK					0x15fe
+			IMX95_PAD_SD2_CMD__USDHC2_CMD					0x13fe
+			IMX95_PAD_SD2_DATA0__USDHC2_DATA0				0x13fe
+			IMX95_PAD_SD2_DATA1__USDHC2_DATA1				0x13fe
+			IMX95_PAD_SD2_DATA2__USDHC2_DATA2				0x13fe
+			IMX95_PAD_SD2_DATA3__USDHC2_DATA3				0x13fe
+			IMX95_PAD_SD2_VSELECT__USDHC2_VSELECT				0x51e
+		>;
+	};
+};
+
+&usb2 {
+	dr_mode = "host";
+	adp-disable;
+	hnp-disable;
+	srp-disable;
+	disable-over-current;
+	status = "okay";
+};
+
+&usb3 {
+	status = "okay";
+};
+
+&usb3_dwc3 {
+	dr_mode = "otg";
+	hnp-disable;
+	srp-disable;
+	adp-disable;
+	usb-role-switch;
+	snps,dis-u1-entry-quirk;
+	snps,dis-u2-entry-quirk;
+	status = "okay";
+
+	port {
+		usb3_drd_sw: endpoint {
+			remote-endpoint = <&typec_dr_sw>;
+		};
+	};
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			reg = <0>;
+			usb3_data_hs: endpoint {
+				remote-endpoint = <&typec_con_hs>;
+			};
+		};
+
+		port at 1 {
+			reg = <1>;
+			usb3_data_ss: endpoint {
+				remote-endpoint = <&typec_con_ss>;
+			};
+		};
+	};
+};
+
+&usb3_phy {
+	fsl,phy-pcs-tx-deemph-3p5db-attenuation-db = <17>;
+	fsl,phy-pcs-tx-swing-full-percent = <100>;
+	fsl,phy-tx-preemp-amp-tune-microamp = <600>;
+	fsl,phy-tx-vboost-level-microvolt = <1156>;
+	status = "okay";
+};
+
+&usdhc2 {
+	pinctrl-names = "default","state_100mhz","state_200mhz","sleep";
+	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-3 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	cd-gpios = <&gpio3 0 GPIO_ACTIVE_LOW>;
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	bus-width = <4>;
+	status = "okay";
+};
-- 
2.47.3



From lists at philpem.me.uk  Mon Dec 29 13:48:35 2025
From: lists at philpem.me.uk (Philip Pemberton)
Date: Mon, 29 Dec 2025 21:48:35 +0000
Subject: EP29xx (TS-7200/TS-7300) board status
Message-ID: <022f07dd-9c48-42d8-b5c2-172cf755f30f@philpem.me.uk>

Hi,

I wondered if anyone knew what condition the EP39xx kernel support was 
currently in, and whether anything special (configuration etc.) was 
needed to get recent kernels to boot on the TS-7300 hardware?

The latest kernel I've had working out-of-box was 4.17.19, which gets as 
far as trying to mount the root filesystem (the initrd the TS bootloader 
loads doesn't seem to be recognised).
4.18.1 also works works, so long as I run "make menuconfig" after "make 
ep93xx_defconfig" and set CONFIG_STACKPROTECTOR_STRONG=n.

4.19.1 and 4.20.9 crash before printing the "Uncompressing Linux" banner 
and eventually reboot. This holds for every later kernel I've tried.
I've also seen this error while bisecting from 4.18.1 to 4.19.1:
   Uncompressing Linux... done, booting the kernel.
   Warning: Neither atags nor dtb found
Which doesn't make any sense. But nor did the bad commit:
   # first bad commit: [9a76aba02a37718242d7cdc294f0a3901928aa57] Merge 
git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next

The boot sector loads the compressed kernel in SDRAM at 0x218000, the 
initrd at 0x01000000, and the ATAGS end up at 0x100.

I'm using the gcc-linaro-6.4.1-2017.11-x86_64_arm-linux-gnueabihf 
compiler as it's a similar vintage to the 4.x kernels and I wanted to 
rule out issues with the gcc-13 Debian gcc.

Thanks.
-- 
Phil.
philpem at philpem.me.uk
http://www.philpem.me.uk



From beata.michalska at arm.com  Mon Dec 29 14:12:06 2025
From: beata.michalska at arm.com (Beata Michalska)
Date: Mon, 29 Dec 2025 23:12:06 +0100
Subject: [PATCH v6 0/3] arm64: topology: Handle AMU FIE setup on CPU
 hotplug
In-Reply-To: <62ad0257-aa50-4ab6-bd46-64c3963e4b94@huawei.com>
References: <20251119081356.2495290-1-zhenglifeng1@huawei.com>
 <aS2z0EURwHbbGZab@arm.com>
 <9b6882dc-a91a-42d6-bf76-347338930d71@huawei.com>
 <aS8GZOuaS1-j14MD@arm.com>
 <29253319-ced9-4ab6-a58e-28afdf235cde@huawei.com>
 <aTx2V4am0FNHm03R@google.com>
 <62ad0257-aa50-4ab6-bd46-64c3963e4b94@huawei.com>
Message-ID: <aVL8tp7k1ne9DWSX@arm.com>

On Sat, Dec 20, 2025 at 05:09:52PM +0800, zhenglifeng (A) wrote:
> On 2025/12/13 4:08, Will Deacon wrote:
> > On Fri, Dec 12, 2025 at 05:27:09PM +0800, zhenglifeng (A) wrote:
> >> On 2025/12/2 23:31, Beata Michalska wrote:
> >>> On Tue, Dec 02, 2025 at 11:05:25AM +0800, zhenglifeng (A) wrote:
> >>>> On 2025/12/1 23:27, Beata Michalska wrote:
> >>>>> Hi,
> >>>>>
> >>>>> Apologies for the delay in reviewing this - currently in progress....
> >>>>> Out of curiosity: what's the cpufreq driver used for testing this series ?
> >>>>
> >>>> I used cppc_cpufreq for testing this. But with some modifications in
> >>>> processor_driver.c, or you'll find that the driver will fail to load with
> >>>> maxcpus set. The modification below is only a temporary solution. I'm still
> >>>> working on that.
> >>>>
> >>> Right, so overall the implementation looks good - thanks for that.
> >>> There are two issues though with the cppc cpufreq driver.
> >>>
> >>> One: as you have already noticed - it fails to register when
> >>> cpumask_present != cpumask_online.
> >>>
> >>> Second: it will mix the sources of the freq scale if not all CPUs within the
> >>> policy have AMUs enabled/valid. This is due to the fact that at the time of
> >>> registering the driver and initializing the FIE support policy->cpus ==
> >>> policy->related_cpus. Assuming scenario when there are two CPUs within the
> >>> policy, one being offline and missing valid AMU counters,
> >>> the topology_set_scale_freq_source from cppc cpufreq driver will register
> >>> the tick handler for both CPUs, whereas AMU support will (rightly so) register
> >>> only for the firs one. When the second CPU comes online, the mismatch will be
> >>> detected and the arch callback will get cleared for the first CPU, but the
> >>> second one will remain unchanged.
> >>>
> >>> That said, I do not think any of those issues is a blocker for this series.
> >>> But both would need fixing.
> >>
> >> I believe Beata is OK with this series. So I think we can move ahead with it
> >> now.
> > 
> > Please repost at -rc1. It would be nice to have an Ack from Beata...
> 
> Hi Beata,
> 
> It would be nice if you could give this patch an Ack.
> 
> Thanks.
> 
Apologies, 've been away.

Acked-by: Beata Michalska <beata.michalska at arm.com>

---
BR
Beata
> > 
> > Will
> > 
> 


From robh at kernel.org  Mon Dec 29 15:25:30 2025
From: robh at kernel.org (Rob Herring)
Date: Mon, 29 Dec 2025 17:25:30 -0600
Subject: [PATCH v20 1/6] dt-bindings: firmware: Add TEE remoteproc
 service binding
In-Reply-To: <20251217153917.3998544-2-arnaud.pouliquen@foss.st.com>
References: <20251217153917.3998544-1-arnaud.pouliquen@foss.st.com>
 <20251217153917.3998544-2-arnaud.pouliquen@foss.st.com>
Message-ID: <20251229232530.GA2753472-robh@kernel.org>

On Wed, Dec 17, 2025 at 04:39:12PM +0100, Arnaud Pouliquen wrote:
> Add a device tree binding for the TEE-based remote processor control
> service implemented as an OP-TEE Trusted Application identified by
> UUID 80a4c275-0a47-4905-8285-1486a9771a08.
> 
> The TEE service node is a child of the "linaro,optee-tz" firmware node and
> acts as a container for remoteproc devices that are controlled via TEE.

Is this generic for any remoteproc device or just ST's remoteproc. Looks 
like the latter to me.

> In addition, the "linaro,optee-tz" binding is updated to specify the
> '#address-cells' and '#size-cells' values used for child TEE service
> nodes.

I'm pretty sure I already rejected per service/app child nodes for 
OP-TEE when its binding was submitted. If we do need something in DT 
to define some resources, then can't we have some sort of 
standard/common communications channel? I don't care to see some sort of 
free-for-all where we have every vendor doing their own thing. OP-TEE 
needs to standarize this.

Rob


From robh at kernel.org  Mon Dec 29 15:35:12 2025
From: robh at kernel.org (Rob Herring)
Date: Mon, 29 Dec 2025 17:35:12 -0600
Subject: [PATCH 2/6] dt-bindings: usb: cdns,usb3: support USB devices in
 DT
In-Reply-To: <20251218152058.1521806-3-alexander.stein@ew.tq-group.com>
References: <20251218152058.1521806-1-alexander.stein@ew.tq-group.com>
 <20251218152058.1521806-3-alexander.stein@ew.tq-group.com>
Message-ID: <20251229233512.GA2785770-robh@kernel.org>

On Thu, Dec 18, 2025 at 04:20:49PM +0100, Alexander Stein wrote:
> Reference usb-hxci.yaml in host mode in order to support on-board USB
> hubs.
> 
> Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
> ---
>  Documentation/devicetree/bindings/usb/cdns,usb3.yaml | 11 +++++++++++
>  1 file changed, 11 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/usb/cdns,usb3.yaml b/Documentation/devicetree/bindings/usb/cdns,usb3.yaml
> index f454ddd9bbaa6..1f7f0adc3b1ed 100644
> --- a/Documentation/devicetree/bindings/usb/cdns,usb3.yaml
> +++ b/Documentation/devicetree/bindings/usb/cdns,usb3.yaml
> @@ -85,6 +85,17 @@ required:
>  
>  allOf:
>    - $ref: usb-drd.yaml#
> +  - if:
> +      properties:
> +        dr_mode:
> +          const: peripheral
> +
> +      required:
> +        - dr_mode
> +    then:
> +      $ref: usb.yaml#
> +    else:
> +      $ref: usb-xhci.yaml#

I would just do:

allOf:
  - $ref: usb-drd.yaml#
  - $ref: usb-xhci.yaml#  (includes usb.yaml)

2 reasons:

As I remember, 'dr_mode' is at least typically what the default mode is 
rather than the only mode the h/w supports.

Even if you are peripheral only, I don't think it is too important to 
disallow otherwise valid properties. (It's random, unspecified 
properties I care about.)

Rob


From robh at kernel.org  Mon Dec 29 15:39:25 2025
From: robh at kernel.org (Rob Herring)
Date: Mon, 29 Dec 2025 17:39:25 -0600
Subject: [PATCH 09/12] dt-bindings: media: st: dcmi: add DMA-MDMA
 chaining properties
In-Reply-To: <20251218-stm32-dcmi-dma-chaining-v1-9-39948ca6cbf6@foss.st.com>
References: <20251218-stm32-dcmi-dma-chaining-v1-0-39948ca6cbf6@foss.st.com>
 <20251218-stm32-dcmi-dma-chaining-v1-9-39948ca6cbf6@foss.st.com>
Message-ID: <20251229233925.GA2796847-robh@kernel.org>

On Thu, Dec 18, 2025 at 07:44:49PM +0100, Alain Volmat wrote:
> Add properties update and new sram property necessary in order
> to enable the DMA-MDMA chaining.
> 
> Signed-off-by: Alain Volmat <alain.volmat at foss.st.com>
> ---
>  Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml | 13 ++++++++++++-
>  1 file changed, 12 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml b/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml
> index 34147127192f..ccaa2d0a2669 100644
> --- a/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml
> +++ b/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml
> @@ -27,11 +27,14 @@ properties:
>        - const: mclk
>  
>    dmas:
> -    maxItems: 1
> +    minItems: 1
> +    maxItems: 2
>  
>    dma-names:
>      items:
>        - const: tx
> +      - const: mdma_tx
> +    minItems: 1
>  
>    resets:
>      maxItems: 1
> @@ -40,6 +43,14 @@ properties:
>      minItems: 1
>      maxItems: 2
>  
> +  sram:
> +    $ref: /schemas/types.yaml#/definitions/phandle
> +    description:
> +      phandles to a reserved SRAM region which is used as temporary

phandle to...

> +      storage memory between DMA and MDMA engines.

> +      The region should be defined as child nodes of the AHB SRAM node
> +      as per the generic bindings in Documentation/devicetree/bindings/sram/sram.yaml

Drop this sentence.

Rob


From sean.wang at kernel.org  Mon Dec 29 15:41:53 2025
From: sean.wang at kernel.org (Sean Wang)
Date: Mon, 29 Dec 2025 17:41:53 -0600
Subject: [PATCH v2] wifi: mt76: replace use of system_wq with system_percpu_wq
In-Reply-To: <CAAofZF51pkOzrg_nO0Mhx6g9b3JPtO3n+0YE=WtSgj_F6wnY4w@mail.gmail.com>
References: <20251114104325.116471-1-marco.crivellari@suse.com> <CAAofZF51pkOzrg_nO0Mhx6g9b3JPtO3n+0YE=WtSgj_F6wnY4w@mail.gmail.com>
Message-ID: <CAGp9Lzoj2jeGF+t-UP0gAykCZ96-OkjummeJRGniYfagvY-BPA@mail.gmail.com>

On Wed, Dec 24, 2025 at 9:27?AM Marco Crivellari
<marco.crivellari at suse.com> wrote:
>
> On Fri, Nov 14, 2025 at 11:43?AM Marco Crivellari
> <marco.crivellari at suse.com> wrote:
> >[...]
> >  drivers/net/wireless/mediatek/mt76/mt7921/init.c | 2 +-
> >  drivers/net/wireless/mediatek/mt76/mt7925/init.c | 2 +-
> >  2 files changed, 2 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
> > index b9098a7331b1..95764b82da39 100644
> > --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c
> > +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
> > @@ -343,7 +343,7 @@ int mt7921_register_device(struct mt792x_dev *dev)
> >         dev->mphy.hw->wiphy->available_antennas_rx = dev->mphy.chainmask;
> >         dev->mphy.hw->wiphy->available_antennas_tx = dev->mphy.chainmask;
> >
> > -       queue_work(system_wq, &dev->init_work);
> > +       queue_work(system_percpu_wq, &dev->init_work);
> >
> >         return 0;
> >  }
> > diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/init.c b/drivers/net/wireless/mediatek/mt76/mt7925/init.c
> > index d7d5afe365ed..e33ab4849e8a 100644
> > --- a/drivers/net/wireless/mediatek/mt76/mt7925/init.c
> > +++ b/drivers/net/wireless/mediatek/mt76/mt7925/init.c
> > @@ -420,7 +420,7 @@ int mt7925_register_device(struct mt792x_dev *dev)
> >         dev->mphy.hw->wiphy->available_antennas_rx = dev->mphy.chainmask;
> >         dev->mphy.hw->wiphy->available_antennas_tx = dev->mphy.chainmask;
> >
> > -       queue_work(system_wq, &dev->init_work);
> > +       queue_work(system_percpu_wq, &dev->init_work);
> >
> >         return 0;
> >  }
>
>
> Gentle ping.
>
> Thanks!

Hi Marco,

The patch has been queued in the mt76 tree. Thanks for your work on this.
https://github.com/nbd168/wireless/commit/ee518f914cd901c16fa08a6f228b266551f72a6a

            Sean

>
> --
>
> Marco Crivellari
>
> L3 Support Engineer
>


From robh at kernel.org  Mon Dec 29 15:42:56 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Mon, 29 Dec 2025 17:42:56 -0600
Subject: [PATCH] dt-bindings: mediatek: Drop inactive MandyJH Liu
In-Reply-To: <20251219074035.13001-2-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251219074035.13001-2-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <176705177359.2804367.15136995230648619621.robh@kernel.org>


On Fri, 19 Dec 2025 08:40:36 +0100, Krzysztof Kozlowski wrote:
> There are no emails from MandyJH Liu, no reviews [1] of these bindings, so
> clearly no maintenance is happening here.  Switch to Mediatek SoC
> maintainers.
> 
> Cc: MandyJH Liu <mandyjh.liu at mediatek.com>
> Link: https://lore.kernel.org/all/?q=f%3Amandyjh.liu%40mediatek.com [1]
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
> ---
>  .../devicetree/bindings/mfd/mediatek,mt8195-scpsys.yaml        | 3 ++-
>  .../devicetree/bindings/power/mediatek,power-controller.yaml   | 2 +-
>  2 files changed, 3 insertions(+), 2 deletions(-)
> 

Applied, thanks!



From seanjc at google.com  Mon Dec 29 15:57:21 2025
From: seanjc at google.com (Sean Christopherson)
Date: Mon, 29 Dec 2025 15:57:21 -0800
Subject: [PATCH v6 15/44] KVM: x86/pmu: Snapshot host (i.e. perf's)
 reported PMU capabilities
In-Reply-To: <43d1cde6-2277-4f3c-8e7d-59e6edb2228a@linux.intel.com>
References: <20251206001720.468579-1-seanjc@google.com> <20251206001720.468579-16-seanjc@google.com>
 <43d1cde6-2277-4f3c-8e7d-59e6edb2228a@linux.intel.com>
Message-ID: <aVMVYY_WkNClfXuj@google.com>

On Thu, Dec 25, 2025, Dapeng Mi wrote:
> 
> On 12/6/2025 8:16 AM, Sean Christopherson wrote:
> > Take a snapshot of the unadulterated PMU capabilities provided by perf so
> > that KVM can compare guest vPMU capabilities against hardware capabilities
> > when determining whether or not to intercept PMU MSRs (and RDPMC).
> >
> > Reviewed-by: Sandipan Das <sandipan.das at amd.com>
> > Tested-by: Xudong Hao <xudong.hao at intel.com>
> > Signed-off-by: Sean Christopherson <seanjc at google.com>
> > ---
> >  arch/x86/kvm/pmu.c | 2 ++
> >  1 file changed, 2 insertions(+)
> >
> > diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
> > index 487ad19a236e..7c219305b61d 100644
> > --- a/arch/x86/kvm/pmu.c
> > +++ b/arch/x86/kvm/pmu.c
> > @@ -108,6 +108,8 @@ void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops)
> >  	bool is_intel = boot_cpu_data.x86_vendor == X86_VENDOR_INTEL;
> >  	int min_nr_gp_ctrs = pmu_ops->MIN_NR_GP_COUNTERS;
> >  
> > +	perf_get_x86_pmu_capability(&kvm_host_pmu);
> > +
> >  	/*
> >  	 * Hybrid PMUs don't play nice with virtualization without careful
> >  	 * configuration by userspace, and KVM's APIs for reporting supported
> 
> Hi Sean,
> 
> It looks a merging error here. We don't need this patch.

Gah, right you are.  I overlooked it because it didn't conflict on a rebase, and
I once again forgot to test on a hybrid PMU, grr.

Thanks!

> The original patch "51f34b1 ("KVM: x86/pmu: Snapshot host (i.e. perf's)
> reported PMU capabilities")" had been merged into upstream and subsequently
> we submitted a new patch "034417c1439a ("KVM: x86/pmu: Don't try to get
> perf capabilities for hybrid CPUs")" to fix the warning introduced from
> previous patch? "51f34b1 ("KVM: x86/pmu: Snapshot host (i.e. perf's)
> reported PMU capabilities")". Thanks.
> 
> -Dapeng Mi
> 
> 


From axboe at kernel.dk  Mon Dec 29 16:37:29 2025
From: axboe at kernel.dk (Jens Axboe)
Date: Mon, 29 Dec 2025 17:37:29 -0700
Subject: [PATCH 09/33] block: Protect against concurrent isolated cpuset
 change
In-Reply-To: <20251224134520.33231-10-frederic@kernel.org>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-10-frederic@kernel.org>
Message-ID: <0f65c4fe-8b10-403d-b5b6-ed33fc4eb69c@kernel.dk>

On 12/24/25 6:44 AM, Frederic Weisbecker wrote:
> The block subsystem prevents running the workqueue to isolated CPUs,
> including those defined by cpuset isolated partitions. Since
> HK_TYPE_DOMAIN will soon contain both and be subject to runtime
> modifications, synchronize against housekeeping using the relevant lock.
> 
> For full support of cpuset changes, the block subsystem may need to
> propagate changes to isolated cpumask through the workqueue in the
> future.
> 
> Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
> ---
>  block/blk-mq.c | 6 +++++-
>  1 file changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/block/blk-mq.c b/block/blk-mq.c
> index 1978eef95dca..0037af1216f3 100644
> --- a/block/blk-mq.c
> +++ b/block/blk-mq.c
> @@ -4257,12 +4257,16 @@ static void blk_mq_map_swqueue(struct request_queue *q)
>  
>  		/*
>  		 * Rule out isolated CPUs from hctx->cpumask to avoid
> -		 * running block kworker on isolated CPUs
> +		 * running block kworker on isolated CPUs.
> +		 * FIXME: cpuset should propagate further changes to isolated CPUs
> +		 * here.
>  		 */
> +		rcu_read_lock();
>  		for_each_cpu(cpu, hctx->cpumask) {
>  			if (cpu_is_isolated(cpu))
>  				cpumask_clear_cpu(cpu, hctx->cpumask);
>  		}
> +		rcu_read_unlock();

Want me to just take this one separately and get it out of your hair?
Doesn't seem to have any dependencies.

-- 
Jens Axboe


From torvalds at linux-foundation.org  Mon Dec 29 16:41:03 2025
From: torvalds at linux-foundation.org (Linus Torvalds)
Date: Mon, 29 Dec 2025 16:41:03 -0800
Subject: Linux 6.19-rc1 mediatek mt7921e broke badly
In-Reply-To: <756e3f65-b2f2-4da3-985a-17754a7a872d@t-8ch.de>
References: <d7f3b00d-beec-41f0-b157-7cfb871f9a46@linuxfoundation.org> <756e3f65-b2f2-4da3-985a-17754a7a872d@t-8ch.de>
Message-ID: <CAHk-=wjO-7uR5HBi-MFnkxAxjhpgfbAQ+HCMKPiXFVwM+AJ7tA@mail.gmail.com>

On Sat, 27 Dec 2025 at 04:25, Thomas Wei?schuh <linux at weissschuh.net> wrote:
>
> Hi Shuah,
>
> On 2025-12-27 02:07:24-0700, Shuah Khan wrote:
> > mt7921e doesn't load on my primary laptopn on Linux 6.19-rc1 and problem
> > still there on 6.19-rc2.
>
> This should be a duplicate of
> https://lore.kernel.org/all/CABXGCsMeAZyNJ-Axt_CUCXgyieWPV3rrcLpWsveMPT8R0YPGnQ at mail.gmail.com/

Hmm. I wonder if we could instead do this:

  --- a/lib/string.c
  +++ b/lib/string.c
  @@ -113,7 +113,7 @@ EXPORT_SYMBOL(strncpy);
   ssize_t sized_strscpy(char *dest, const char *src, size_t count)
   {
          const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
  -       size_t max = count;
  +       size_t max = count - 1;
          long res = 0;

          if (count == 0 || WARN_ON_ONCE(count > INT_MAX))

(intentionally whitespace-damaged patch, because I want people to
think about it).

It basically says that if the size of the 'strscpy()' buffer is N,
then we do the "word-at-a-time" only up to 'N-1' bytes, because we
don't even need to read the last byte of the source, because we will
always NUL-terminate the destination...

That would basically make it ok to use a destination that is one byte
larger than the source (in order to fit NUL termination that doesn't
exist in the source).

The downside, of course, is that it means that we possibly miss out of
doing the last word of the copy a word-at-a-time. But possibly not a
big downside, and it would make strscpy() able to deal with this case
natively.

The *real* issue is that we don't have a "source is this big,
destination is that big" version of string copy.

Normally that is a non-issue - just pick the smaller size of the two.
Except for this particular case, where the destination is exactly one
byte larger, and wants to be NUL-terminated while the source might not
be.

I haven't really thought this through fully, which is why that patch
is very much whitespace-damaged. Somebody else should verify my
thinking.

                   Linus


From kylehsieh1995 at gmail.com  Mon Dec 29 17:02:02 2025
From: kylehsieh1995 at gmail.com (Kyle Hsieh)
Date: Tue, 30 Dec 2025 09:02:02 +0800
Subject: [PATCH 2/2] ARM: dts: aspeed: ventura2: Add Meta ventura2 BMC
In-Reply-To: <32ff7ca8-9cb0-4889-adb0-a6dae735630b@lunn.ch>
References: <20251222-ventura2_initial_dts-v1-0-1f06166c78a3@gmail.com>
 <20251222-ventura2_initial_dts-v1-2-1f06166c78a3@gmail.com>
 <c069b452-df22-4afa-bf6a-c48949f40ebc@lunn.ch> <CAF7HswN_jEXOU_9K4LpLnbhvd+RD0qqELAHxMBbp=hGtMjS4kQ@mail.gmail.com>
 <35f3eba9-5ec4-4cba-8a64-fb521dc65b79@lunn.ch> <CAF7HswN0hhJQ-gmE59cKTuPyzrs1A3rM8Xw+Z8i3_AsHRiNcug@mail.gmail.com>
 <1e21f828-1b06-492d-bfcd-ab5721621e8a@lunn.ch> <CAF7HswP7Oejs42K=jG8bkNiBoDhXR2LbeHoppk0nnNon6_afwA@mail.gmail.com>
 <32ff7ca8-9cb0-4889-adb0-a6dae735630b@lunn.ch>
Message-ID: <CAF7HswMRrs9hwKo_uHCLMtx7+h46-DPEJRcEqu0-zEG4CVvvjg@mail.gmail.com>

On Wed, Dec 24, 2025 at 5:20?PM Andrew Lunn <andrew at lunn.ch> wrote:
>
> On Wed, Dec 24, 2025 at 02:40:39PM +0800, Kyle Hsieh wrote:
> > On Tue, Dec 23, 2025 at 6:35?PM Andrew Lunn <andrew at lunn.ch> wrote:
> > >
> > > > > What make/model of switch is it? Is it unmanaged, or does it use SPI
> > > > > or I2C for management?
> > >
> > > > The switch is connected via RMII to the MAC and is managed over MDIO.
> > >
> > > O.K. What make/model?
> > >
> > The device is a Marvell 88E6393X switch. In our design, the BMC connects
>
> Which Linux does have a driver for.
>
> > to the device via RMII with fixed link parameters to retrieve ethernet.
> > > > On our board, MDIO is not wired directly to the processor; instead, we
> > > > use a USB-to-MPSSE bridge (FT2232) to toggle the MDIO signals for
> > > > switch management.
> > >
> > > I have to push back on you using a closed source user space driver,
> > > given that i help maintain the Ethernet switch drivers...
> > >
> > > I know there have been attempts to get GPIO support added for FT2232,
> > > but i don't think any got as far as mainline. That is probably the
> > > only part you are missing. You can describe USB devices in DT. So you
> > > should be able to describe such a GPIO controller. You can then
> > > instantiate an virtual,mdio-gpio driver to give you an MDIO bus. And
> > > then add nodes for the switch using DSA.
>
> > Apologies for the confusion in my previous reply.
> > The BMC connects to the peer via an RMII fixed-link.
> > The link parameters are fixed at design time and there is no runtime
> > MDIO-managed PHY or switch control from the BMC.
>
> So you use the USB-MDIO to program the EEPROM? The switch boots using
> the settings in the EEPROM? It is then an unmanaged hub? You are not
> using UMSD in userspace? That code looks terrible.
>
> So if you connect multiple of these unmanaged hubs together in a loop,
> your network disappears in a broadcast storm? Yes, you can use these
> switches in a dumb mode, but it has consequences. If you let Linux
> manage it, you gain a lot of functionality, such as STP, to break
> loops.
>
> But you seem to be opposed to this. At least add in a comment
> explaining the purpose of the fixed link. DT describes hardware, so
> there is no harm in describing the hardware, even if it is a comment
> and not real properties.
Thanks for the comments.
I understand the concern about the DTS. I will add a clear comment in the
device tree explaining why a fixed-link is used and that the switch is
initialized via hardware straps and EEPROM, with no runtime management
from Linux.
>
>         Andrew


From robh at kernel.org  Mon Dec 29 17:32:25 2025
From: robh at kernel.org (Rob Herring)
Date: Mon, 29 Dec 2025 19:32:25 -0600
Subject: [PATCH v2 2/7] ASoC: dt-bindings: update tdm-slot.txt references
 to tdm-slot.yaml
In-Reply-To: <20251221-tdm-idle-slots-v2-2-ed4d96413aec@gmail.com>
References: <20251221-tdm-idle-slots-v2-0-ed4d96413aec@gmail.com>
 <20251221-tdm-idle-slots-v2-2-ed4d96413aec@gmail.com>
Message-ID: <20251230013225.GA3037280-robh@kernel.org>

On Sun, Dec 21, 2025 at 07:35:58PM +1000, James Calligeros wrote:
> Ensure that all references to tdm-slot.txt have been updated to
> tdm-slot.yaml, and are schema-compliant.
> 
> Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
> ---
>  .../bindings/sound/imx-audio-card.yaml   | 14 ++++++--------
>  .../bindings/sound/simple-card.yaml      | 14 ++------------
>  2 files changed, 8 insertions(+), 20 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/sound/imx-audio-card.yaml b/Documentation/devicetree/bindings/sound/imx-audio-card.yaml
> index 3c75c8c78987..eb702f48d694 100644
> --- a/Documentation/devicetree/bindings/sound/imx-audio-card.yaml
> +++ b/Documentation/devicetree/bindings/sound/imx-audio-card.yaml
> @@ -31,6 +31,12 @@ patternProperties:
>          $ref: /schemas/types.yaml#/definitions/string
>          maxItems: 1
>  
> +      dai-tdm-slot-num:
> +        $ref: tdm-slot.yaml#/$defs/dai-tdm-slot-num
> +
> +      dai-tdm-slot-width:
> +        $ref: tdm-slot.yaml#/$defs/dai-tdm-slot-width

Drop these and add just '$ref: tdm-slot.yaml#' up a level (with 
'properties').

You may need 'unevaluatedProperties' or you can put 
'dai-tdm-slot-num: true' here if you want to define which properties are 
used.

> +
>        format:
>          description: audio format.
>          items:
> @@ -38,14 +44,6 @@ patternProperties:
>              - i2s
>              - dsp_b
>  
> -      dai-tdm-slot-num:
> -        description: see tdm-slot.txt.
> -        $ref: /schemas/types.yaml#/definitions/uint32
> -
> -      dai-tdm-slot-width:
> -        description: see tdm-slot.txt.
> -        $ref: /schemas/types.yaml#/definitions/uint32
> -
>        playback-only:
>          description: link is used only for playback
>          $ref: /schemas/types.yaml#/definitions/flag
> diff --git a/Documentation/devicetree/bindings/sound/simple-card.yaml b/Documentation/devicetree/bindings/sound/simple-card.yaml
> index 533d0a1da56e..a14716b2732f 100644
> --- a/Documentation/devicetree/bindings/sound/simple-card.yaml
> +++ b/Documentation/devicetree/bindings/sound/simple-card.yaml
> @@ -27,14 +27,6 @@ definitions:
>      description: dai-link uses bit clock inversion
>      $ref: /schemas/types.yaml#/definitions/flag
>  
> -  dai-tdm-slot-num:
> -    description: see tdm-slot.txt.
> -    $ref: /schemas/types.yaml#/definitions/uint32
> -
> -  dai-tdm-slot-width:
> -    description: see tdm-slot.txt.
> -    $ref: /schemas/types.yaml#/definitions/uint32
> -
>    system-clock-frequency:
>      description: |
>        If a clock is specified and a multiplication factor is given with
> @@ -115,6 +107,8 @@ definitions:
>  
>    dai:
>      type: object
> +    $ref: tdm-slot.yaml#
> +
>      properties:
>        sound-dai:
>          maxItems: 1
> @@ -133,10 +127,6 @@ definitions:
>        bitclock-master:
>          $ref: /schemas/types.yaml#/definitions/flag
>  
> -      dai-tdm-slot-num:
> -        $ref: "#/definitions/dai-tdm-slot-num"
> -      dai-tdm-slot-width:
> -        $ref: "#/definitions/dai-tdm-slot-width"
>        clocks:
>          maxItems: 1
>        system-clock-frequency:
> 
> -- 
> 2.52.0
> 


From robh at kernel.org  Mon Dec 29 17:35:04 2025
From: robh at kernel.org (Rob Herring)
Date: Mon, 29 Dec 2025 19:35:04 -0600
Subject: [PATCH v2 1/7] ASoC: dt-bindings: convert tdm-slot to YAML
In-Reply-To: <20251221-tdm-idle-slots-v2-1-ed4d96413aec@gmail.com>
References: <20251221-tdm-idle-slots-v2-0-ed4d96413aec@gmail.com>
 <20251221-tdm-idle-slots-v2-1-ed4d96413aec@gmail.com>
Message-ID: <20251230013504.GB3037280-robh@kernel.org>

On Sun, Dec 21, 2025 at 07:35:57PM +1000, James Calligeros wrote:
> This schema was still in plaintext form. Convert to YAML format.
> 
> Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
> ---
>  .../bindings/sound/tdm-slot.txt          | 29 ---------------
>  .../bindings/sound/tdm-slot.yaml         | 49 +++++++++++++++++++++++++
>  2 files changed, 49 insertions(+), 29 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/sound/tdm-slot.txt b/Documentation/devicetree/bindings/sound/tdm-slot.txt
> deleted file mode 100644
> index 4bb513ae62fc..000000000000
> --- a/Documentation/devicetree/bindings/sound/tdm-slot.txt
> +++ /dev/null
> @@ -1,29 +0,0 @@
> -TDM slot:
> -
> -This specifies audio DAI's TDM slot.
> -
> -TDM slot properties:
> -dai-tdm-slot-num : Number of slots in use.
> -dai-tdm-slot-width : Width in bits for each slot.
> -dai-tdm-slot-tx-mask : Transmit direction slot mask, optional
> -dai-tdm-slot-rx-mask : Receive direction slot mask, optional
> -
> -For instance:
> -	dai-tdm-slot-num = <2>;
> -	dai-tdm-slot-width = <8>;
> -	dai-tdm-slot-tx-mask = <0 1>;
> -	dai-tdm-slot-rx-mask = <1 0>;
> -
> -And for each specified driver, there could be one .of_xlate_tdm_slot_mask()
> -to specify an explicit mapping of the channels and the slots. If it's absent
> -the default snd_soc_of_xlate_tdm_slot_mask() will be used to generating the
> -tx and rx masks.
> -
> -For snd_soc_of_xlate_tdm_slot_mask(), the tx and rx masks will use a 1 bit
> -for an active slot as default, and the default active bits are at the LSB of
> -the masks.
> -
> -The explicit masks are given as array of integers, where the first
> -number presents bit-0 (LSB), second presents bit-1, etc. Any non zero
> -number is considered 1 and 0 is 0. snd_soc_of_xlate_tdm_slot_mask()
> -does not do anything, if either mask is set non zero value.
> diff --git a/Documentation/devicetree/bindings/sound/tdm-slot.yaml b/Documentation/devicetree/bindings/sound/tdm-slot.yaml
> new file mode 100644
> index 000000000000..5bc46048d689
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/tdm-slot.yaml
> @@ -0,0 +1,49 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/tdm-slot.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Time Division Multiplexing (TDM) Slot Parameters
> +
> +maintainers:
> +  - Liam Girdwood <lgirdwood at gmail.com>
> +
> +select: false
> +
> +$defs:
> +  dai-tdm-slot-num:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    description: Number of slots in use
> +
> +  dai-tdm-slot-width:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    description: Width, in bits, of each slot
> +
> +  dai-tdm-slot-tx-mask:
> +    $ref: /schemas/types.yaml#/definitions/uint32-array
> +    description: Transmit direction slot mask. Optional. Drivers may specify an
> +      .xlate_tdm_slot_mask() to generate a slot mask dynamically. If neither
> +      this property nor a driver-specific function are specified, the default
> +      snd_soc_xlate_tdm_slot_mask() function will be used to generate a mask.
> +      The first element of the array is slot 0 (LSB). Any nonzero value will be
> +      treated as 1.
> +
> +  dai-tdm-slot-rx-mask:
> +    $ref: /schemas/types.yaml#/definitions/uint32-array
> +    description: Receive direction slot mask. Optional. Identical to TX mask.

Just move each of these to the properties below as they are only used 
once.

> +
> +properties:
> +  dai-tdm-slot-num:
> +    $ref: "#/$defs/dai-tdm-slot-num"
> +
> +  dai-tdm-slot-width:
> +    $ref: "#/$defs/dai-tdm-slot-width"
> +
> +  dai-tdm-slot-tx-mask:
> +    $ref: "#/$defs/dai-tdm-slot-tx-mask"
> +
> +  dai-tdm-slot-rx-mask:
> +    $ref: "#/$defs/dai-tdm-slot-rx-mask"
> +
> +additionalProperties: true
> 
> -- 
> 2.52.0
> 


From robh at kernel.org  Mon Dec 29 17:38:07 2025
From: robh at kernel.org (Rob Herring)
Date: Mon, 29 Dec 2025 19:38:07 -0600
Subject: [PATCH v2 3/7] ASoC: dt-bindings: add TDM slot idle mode
 properties
In-Reply-To: <20251221-tdm-idle-slots-v2-3-ed4d96413aec@gmail.com>
References: <20251221-tdm-idle-slots-v2-0-ed4d96413aec@gmail.com>
 <20251221-tdm-idle-slots-v2-3-ed4d96413aec@gmail.com>
Message-ID: <20251230013807.GA3063323-robh@kernel.org>

On Sun, Dec 21, 2025 at 07:35:59PM +1000, James Calligeros wrote:
> Add properties to describe TDM slot idle behaviour. These properties can
> be used to describe how a DAI is supposed to behave when not active.
> 
> For example, Apple Silicon laptops split a single I2S bus between two
> physical lines which are combined at an OR gate in front of the
> receiving port. One codec on each line is expected to transmit zeroes
> during the active TDM slots of the opposite line, or we will have corrupted
> data at the receiver.
> 
> Signed-off-by: James Calligeros <jcalligeros99 at gmail.com>
> ---
>  .../bindings/sound/tdm-slot.yaml         | 33 +++++++++++++++++++++++++
>  1 file changed, 33 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/sound/tdm-slot.yaml b/Documentation/devicetree/bindings/sound/tdm-slot.yaml
> index 5bc46048d689..e8b2d35a7c37 100644
> --- a/Documentation/devicetree/bindings/sound/tdm-slot.yaml
> +++ b/Documentation/devicetree/bindings/sound/tdm-slot.yaml
> @@ -33,6 +33,17 @@ $defs:
>      $ref: /schemas/types.yaml#/definitions/uint32-array
>      description: Receive direction slot mask. Optional. Identical to TX mask.
>  
> +  dai-tdm-idle-mode:
> +    $ref: /schemas/types.yaml#/definitions/string
> +    enum:
> +      - none
> +      - off
> +      - zero
> +      - pulldown
> +      - hiz
> +      - pullup
> +      - drivehigh
> +
>  properties:
>    dai-tdm-slot-num:
>      $ref: "#/$defs/dai-tdm-slot-num"
> @@ -46,4 +57,26 @@ properties:
>    dai-tdm-slot-rx-mask:
>      $ref: "#/$defs/dai-tdm-slot-rx-mask"
>  
> +  dai-tdm-slot-tx-idle-mode:
> +    $ref: "#/$defs/dai-tdm-idle-mode"
> +    description: Transmit direction idle slot mode. Optional. For hardware
> +      that can configure its behaviour during idle TDM slots via
> +      .set_tdm_idle(). "None" represents UB/unspecified behaviour and is the
> +      same as not setting this property.
> +
> +  dai-tdm-slot-rx-idle-mode:
> +    $ref: "#/$defs/dai-tdm-idle-mode"
> +    description: Receive direction idle slot mode. Optional. Identical to TX
> +      idle slot mode.
> +
> +  dai-tdm-slot-tx-idle-mask:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    description: Transmit direction idle slot mask. Optional. 1 represents
> +      an idle slot.
> +
> +  dai-tdm-slot-rx-idle-mask:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    description: Receive direction idle slot mask. Optional. Identical to
> +      TX mask.

These can be under a patternProperties:

patternProperties:
  '^dai-tdm-slot-[rt]x-idle-mode$':
    ...

  '^dai-tdm-slot-[rt]x-idle-mask$':
    ...

And then remove the $defs.

Rob


From marek.vasut at mailbox.org  Mon Dec 29 17:40:35 2025
From: marek.vasut at mailbox.org (Marek Vasut)
Date: Tue, 30 Dec 2025 02:40:35 +0100
Subject: [PATCH v2 2/2] arm64: dts: imx8mp: Update Data Modul i.MX8M Plus eDM SBC DT to rev.903
In-Reply-To: <20251230014047.149677-1-marek.vasut@mailbox.org>
References: <20251230014047.149677-1-marek.vasut@mailbox.org>
Message-ID: <20251230014047.149677-2-marek.vasut@mailbox.org>

Update the DT to match newest Data Modul i.MX8M Plus eDM SBC rev.903
board which implements significant changes. Keep some of the rev.900
and rev.902 nodes in the DT so that a DTO can be used to support old
rev.900 and rev.902 boards easily.

The changes from rev.900 to rev.902 are:
- Both ethernet PHYs replaced from AR8031 to BCM54213PE
- Both ethernet PHYs MDIO address changed
- PCIe WiFi now comes with dedicated regulator
- I2C TPM chip address
- Additional GPIO expander for LVDS panel control added
- Current EEPROM I2C address changed
- Another optional EEPROM added onto another I2C bus

The changes from rev.902 to rev.903 are:
- Additional GPIO expander for WiFi and LVDS panel control added
- Multiple GPIOs are reassigned

Signed-off-by: Marek Vasut <marek.vasut at mailbox.org>
---
Cc: Conor Dooley <conor+dt at kernel.org>
Cc: Fabio Estevam <festevam at gmail.com>
Cc: Jarkko Sakkinen <jarkko at kernel.org>
Cc: Jason Gunthorpe <jgg at ziepe.ca>
Cc: Krzysztof Kozlowski <krzk+dt at kernel.org>
Cc: Lukas Wunner <lukas at wunner.de>
Cc: Pengutronix Kernel Team <kernel at pengutronix.de>
Cc: Peter Huewe <peterhuewe at gmx.de>
Cc: Rob Herring <robh at kernel.org>
Cc: Sascha Hauer <s.hauer at pengutronix.de>
Cc: Shawn Guo <shawnguo at kernel.org>
Cc: devicetree at vger.kernel.org
Cc: imx at lists.linux.dev
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-integrity at vger.kernel.org
Cc: linux-kernel at vger.kernel.org
---
V2: - Rebase on current next, update email address
---
 .../freescale/imx8mp-data-modul-edm-sbc.dts   | 148 +++++++++++++++---
 1 file changed, 129 insertions(+), 19 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts b/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts
index 16078ff60ef08..7e46537a22a01 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts
@@ -93,6 +93,17 @@ reg_panel_vcc: regulator-panel-vcc {
 		status = "disabled";
 	};
 
+	reg_pcie0: regulator-pcie {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_wifi>;
+		regulator-name = "WIFI_BT_RST#";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio2 2 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
 	reg_usdhc2_vmmc: regulator-usdhc2-vmmc {
 		compatible = "regulator-fixed";
 		pinctrl-names = "default";
@@ -190,7 +201,7 @@ &ecspi3 {	/* Display connector SPI */
 &eqos {	/* First ethernet */
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_eqos>;
-	phy-handle = <&phy_eqos>;
+	phy-handle = <&phy_eqos_bcm>;
 	phy-mode = "rgmii-id";
 	status = "okay";
 
@@ -200,7 +211,7 @@ mdio {
 		#size-cells = <0>;
 
 		/* Atheros AR8031 PHY */
-		phy_eqos: ethernet-phy at 0 {
+		phy_eqos_ath: ethernet-phy at 0 {
 			compatible = "ethernet-phy-ieee802.3-c22";
 			reg = <0>;
 			/*
@@ -213,6 +224,7 @@ phy_eqos: ethernet-phy at 0 {
 			reset-deassert-us = <10000>;
 			qca,keep-pll-enabled;
 			vddio-supply = <&vddio_eqos>;
+			status = "disabled";
 
 			vddio_eqos: vddio-regulator {
 				regulator-name = "VDDIO_EQOS";
@@ -224,13 +236,27 @@ vddh_eqos: vddh-regulator {
 				regulator-name = "VDDH_EQOS";
 			};
 		};
+
+		/* Broadcom BCM54213PE PHY */
+		phy_eqos_bcm: ethernet-phy at 1 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <1>;
+			/*
+			 * Dedicated ENET_INT# and ENET_WOL# signals are
+			 * unused, the PHY does not provide cable detect
+			 * interrupt.
+			 */
+			reset-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
+			reset-assert-us = <10000>;
+			reset-deassert-us = <10000>;
+		};
 	};
 };
 
 &fec {	/* Second ethernet */
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_fec>;
-	phy-handle = <&phy_fec>;
+	phy-handle = <&phy_fec_bcm>;
 	phy-mode = "rgmii-id";
 	fsl,magic-packet;
 	status = "okay";
@@ -240,7 +266,7 @@ mdio {
 		#size-cells = <0>;
 
 		/* Atheros AR8031 PHY */
-		phy_fec: ethernet-phy at 0 {
+		phy_fec_ath: ethernet-phy at 0 {
 			compatible = "ethernet-phy-ieee802.3-c22";
 			reg = <0>;
 			/*
@@ -253,6 +279,7 @@ phy_fec: ethernet-phy at 0 {
 			reset-deassert-us = <10000>;
 			qca,keep-pll-enabled;
 			vddio-supply = <&vddio_fec>;
+			status = "disabled";
 
 			vddio_fec: vddio-regulator {
 				regulator-name = "VDDIO_FEC";
@@ -264,6 +291,20 @@ vddh_fec: vddh-regulator {
 				regulator-name = "VDDH_FEC";
 			};
 		};
+
+		/* Broadcom BCM54213PE PHY */
+		phy_fec_bcm: ethernet-phy at 1 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <1>;
+			/*
+			 * Dedicated ENET_INT# and ENET_WOL# signals are
+			 * unused, the PHY does not provide cable detect
+			 * interrupt.
+			 */
+			reset-gpios = <&gpio2 9 GPIO_ACTIVE_LOW>;
+			reset-assert-us = <10000>;
+			reset-deassert-us = <10000>;
+		};
 	};
 };
 
@@ -378,13 +419,26 @@ usb-hub at 2c {
 		self-powered;
 	};
 
-	eeprom: eeprom at 50 {
+	tpm: tpm at 2e {
+		compatible = "st,st33tphf2ei2c", "tcg,tpm-tis-i2c";
+		reg = <0x2e>;
+	};
+
+	eeprom900: eeprom at 50 {	/* board rev.900 */
 		compatible = "atmel,24c32";
 		reg = <0x50>;
 		pagesize = <32>;
+		status = "disabled";
+	};
+
+	eeprom902: eeprom at 51 {	/* board rev.902 */
+		compatible = "atmel,24c32";
+		reg = <0x51>;
+		pagesize = <32>;
 	};
 
 	rtc: rtc at 68 {
+		#clock-cells = <1>;
 		compatible = "st,m41t62";
 		reg = <0x68>;
 		pinctrl-names = "default";
@@ -408,6 +462,46 @@ &i2c2 {
 	scl-gpios = <&gpio5 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
 	sda-gpios = <&gpio5 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
 	status = "okay";
+
+	gpiolvds: io-expander at 20 {
+		compatible = "nxp,pca9554";
+		reg = <0x20>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		gpio-line-names =
+			"BL_ENABLE_V", "SEL_BL_12V",
+			"SEL_PANEL_5V", "SEL_PANEL_12V",
+			"SEL_BL_PWM", "SEL_BL_EN",
+			"REVERSE_SCAN_PANEL", "GND_REV903";
+	};
+
+	gpiowifi: io-expander at 21 {
+		compatible = "nxp,pca9554";
+		reg = <0x21>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		gpio-line-names =
+			"BL_LVDS_ENABLE_3V3", "BL_LVDS_PWM_3V3",
+			"M2_BT_WAKE_3V3#", "M2_W_DISABLE2_3V3#",
+			"TFT_PANEL_ENABLE_3V3", "TPM_RESET_3V3#",
+			"CSI2_PD_3V3", "CSI2_RESET_3V3#";
+
+		/* BL_LVDS_PWM_3V3 is patch-wired to BL_PWM_3V3 on rev.903 */
+		pwm-input-hog {
+			gpio-hog;
+			gpios = <1 0>;
+			input;
+			line-name = "BL_LVDS_PWM_3V3_HOG";
+		};
+	};
+
+	eepromlvds: eeprom at 51 {
+		compatible = "atmel,24c32";
+		reg = <0x51>;
+		pagesize = <32>;
+		/* Optional EEPROM, disabled by default. */
+		status = "disabled";
+	};
 };
 
 &i2c3 {
@@ -521,6 +615,7 @@ &pcie {
 	pinctrl-0 = <&pinctrl_pcie0>;
 	fsl,max-link-speed = <3>;
 	reset-gpio = <&gpio1 5 GPIO_ACTIVE_LOW>;
+	vpcie-supply = <&reg_pcie0>;
 	status = "okay";
 };
 
@@ -598,7 +693,17 @@ &uart3 {	/* A53 Debug */
 &uart4 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_uart4>;
-	status = "disabled";
+	uart-has-rtscts;
+	status = "okay";
+
+	bluetooth {
+		compatible = "infineon,cyw55572-bt";
+		brcm,requires-autobaud-mode;
+		clocks = <&rtc 0>;
+		clock-names = "txco";
+		max-speed = <921600>;
+		shutdown-gpios = <&gpiowifi 3 GPIO_ACTIVE_HIGH>;
+	};
 };
 
 &usb3_phy0 {
@@ -686,8 +791,6 @@ MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2	0x91
 			MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3	0x91
 			/* ENET_RST# */
 			MX8MP_IOMUXC_GPIO1_IO15__GPIO1_IO15		0x6
-			/* ENET_INT# */
-			MX8MP_IOMUXC_GPIO1_IO11__GPIO1_IO11		0x40000090
 		>;
 	};
 
@@ -709,8 +812,6 @@ MX8MP_IOMUXC_SAI1_TXD4__ENET1_RGMII_TX_CTL	0x1f
 			MX8MP_IOMUXC_SAI1_TXD5__ENET1_RGMII_TXC		0x1f
 			/* ENET2_RST# */
 			MX8MP_IOMUXC_SD1_DATA7__GPIO2_IO09		0x6
-			/* ENET2_INT# */
-			MX8MP_IOMUXC_SD1_DATA0__GPIO2_IO02		0x40000090
 		>;
 	};
 
@@ -754,10 +855,6 @@ MX8MP_IOMUXC_GPIO1_IO10__GPIO1_IO10		0x40000090
 
 			/* PG_V_IN_VAR# */
 			MX8MP_IOMUXC_NAND_CE0_B__GPIO3_IO01		0x40000000
-			/* CSI2_PD_1V8 */
-			MX8MP_IOMUXC_NAND_DATA02__GPIO3_IO08		0x0
-			/* CSI2_RESET_1V8# */
-			MX8MP_IOMUXC_NAND_DATA03__GPIO3_IO09		0x0
 
 			/* DIS_USB_DN1 */
 			MX8MP_IOMUXC_SAI2_RXFS__GPIO4_IO21		0x0
@@ -771,8 +868,14 @@ MX8MP_IOMUXC_SAI5_RXD0__GPIO3_IO21		0x0
 			/* GRAPHICS_PRSNT_1V8# */
 			MX8MP_IOMUXC_SAI1_TXD6__GPIO4_IO18		0x40000000
 
+			/* TOUCH_RESET_3V3# */
+			MX8MP_IOMUXC_GPIO1_IO00__GPIO1_IO00		0x2
+			/* TOUCH_INT# */
+			MX8MP_IOMUXC_GPIO1_IO10__GPIO1_IO10		0x40000140
 			/* CLK_CCM_CLKO1_3V3 */
 			MX8MP_IOMUXC_GPIO1_IO14__CCM_CLKO1		0x10
+			/* ENET_INT# (rev.900,901) or M2_WDIS_BTIRQ_3V3# (rev.903) */
+			MX8MP_IOMUXC_GPIO1_IO11__GPIO1_IO11		0x40000092
 		>;
 	};
 
@@ -875,12 +978,10 @@ pinctrl_pcie0: pcie-grp {
 		fsl,pins = <
 			/* M2_PCIE_RST# */
 			MX8MP_IOMUXC_GPIO1_IO05__GPIO1_IO05		0x2
-			/* M2_W_DISABLE1_1V8# */
+			/* M2_PCIE_WAKE_1V8# */
 			MX8MP_IOMUXC_SAI5_RXD2__GPIO3_IO23		0x2
-			/* M2_W_DISABLE2_1V8# */
-			MX8MP_IOMUXC_SAI5_RXD3__GPIO3_IO24		0x2
-			/* CLK_M2_32K768 */
-			MX8MP_IOMUXC_GPIO1_IO00__CCM_EXT_CLK1		0x14
+			/* M2_UART_WAKE_1V8# */
+			MX8MP_IOMUXC_SAI5_RXD3__GPIO3_IO24		0x40000002
 			/* M2_PCIE_WAKE# */
 			MX8MP_IOMUXC_GPIO1_IO06__GPIO1_IO06		0x40000140
 			/* M2_PCIE_CLKREQ# */
@@ -974,6 +1075,8 @@ pinctrl_uart4: uart4-grp {
 		fsl,pins = <
 			MX8MP_IOMUXC_UART4_RXD__UART4_DCE_RX		0x49
 			MX8MP_IOMUXC_UART4_TXD__UART4_DCE_TX		0x49
+			MX8MP_IOMUXC_NAND_DATA02__UART4_DCE_CTS		0x149
+			MX8MP_IOMUXC_NAND_DATA03__UART4_DCE_RTS		0x149
 		>;
 	};
 
@@ -1100,4 +1203,11 @@ MX8MP_IOMUXC_SPDIF_EXT_CLK__GPIO5_IO05		0x6
 			MX8MP_IOMUXC_SD1_DATA6__GPIO2_IO08		0x26
 		>;
 	};
+
+	pinctrl_wifi: wifi-grp {
+		fsl,pins = <
+			/* WIFI_BT_RST_3V3# */
+			MX8MP_IOMUXC_SD1_DATA0__GPIO2_IO02		0x40000090
+		>;
+	};
 };
-- 
2.51.0



From marek.vasut at mailbox.org  Mon Dec 29 17:40:34 2025
From: marek.vasut at mailbox.org (Marek Vasut)
Date: Tue, 30 Dec 2025 02:40:34 +0100
Subject: [PATCH v2 1/2] dt-bindings: tpm: Add st,st33tphf2ei2c
Message-ID: <20251230014047.149677-1-marek.vasut@mailbox.org>

Add the ST chip st33tphf2ei2c to the supported compatible strings of the
TPM TIS I2C schema. The chip is compliant with the TCG PC Client TPM
Profile specification.

For reference, a databrief is available at:
https://www.st.com/resource/en/data_brief/st33tphf2ei2c.pdf

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
Signed-off-by: Marek Vasut <marek.vasut at mailbox.org>
---
Cc: Conor Dooley <conor+dt at kernel.org>
Cc: Fabio Estevam <festevam at gmail.com>
Cc: Jarkko Sakkinen <jarkko at kernel.org>
Cc: Jason Gunthorpe <jgg at ziepe.ca>
Cc: Krzysztof Kozlowski <krzk+dt at kernel.org>
Cc: Lukas Wunner <lukas at wunner.de>
Cc: Pengutronix Kernel Team <kernel at pengutronix.de>
Cc: Peter Huewe <peterhuewe at gmx.de>
Cc: Rob Herring <robh at kernel.org>
Cc: Sascha Hauer <s.hauer at pengutronix.de>
Cc: Shawn Guo <shawnguo at kernel.org>
Cc: devicetree at vger.kernel.org
Cc: imx at lists.linux.dev
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-integrity at vger.kernel.org
Cc: linux-kernel at vger.kernel.org
---
V2: - Rebase on current next, update email address
    - Add AB from Krzysztof
---
 Documentation/devicetree/bindings/tpm/tcg,tpm-tis-i2c.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/tpm/tcg,tpm-tis-i2c.yaml b/Documentation/devicetree/bindings/tpm/tcg,tpm-tis-i2c.yaml
index af7720dc4a12c..fdd7fd874e01e 100644
--- a/Documentation/devicetree/bindings/tpm/tcg,tpm-tis-i2c.yaml
+++ b/Documentation/devicetree/bindings/tpm/tcg,tpm-tis-i2c.yaml
@@ -33,6 +33,7 @@ properties:
               - infineon,slb9673
               - nuvoton,npct75x
               - st,st33ktpm2xi2c
+              - st,st33tphf2ei2c
           - const: tcg,tpm-tis-i2c
 
       - description: TPM 1.2 and 2.0 chips with vendor-specific I?C interface
-- 
2.51.0



From marek.vasut at mailbox.org  Mon Dec 29 17:53:38 2025
From: marek.vasut at mailbox.org (Marek Vasut)
Date: Tue, 30 Dec 2025 02:53:38 +0100
Subject: [PATCH] arm64: dts: imx95: Use GPU_CGC as core clock for GPU
In-Reply-To: <aTYxm_dfMwF4H0_b@oss.nxp.com>
References: <20251129143220.14834-1-marek.vasut@mailbox.org>
 <aS-lEibp3zTsaR6T@oss.nxp.com>
 <c6e0e55a-06da-4665-972e-e9b5b8c08bf7@mailbox.org>
 <aTACuRjC_Zpf8IOU@oss.nxp.com>
 <de36091e-c890-4897-b3e3-2a7575029a5d@mailbox.org>
 <aTD5np-HGaJqhzkD@oss.nxp.com>
 <5944d872-01a3-47e9-977b-029f3be4fd83@mailbox.org>
 <aTKVMAMQ6v_BwD6R@oss.nxp.com>
 <9b593731-898f-46a7-8ee5-68f8c170351c@mailbox.org>
 <aTYxm_dfMwF4H0_b@oss.nxp.com>
Message-ID: <53ea529f-3538-4ab5-aa99-0caa6729b4cd@mailbox.org>

On 12/8/25 3:02 AM, Rain Yang wrote:

>>> Okay, I?ll submit a patch later.
>>> The commit message should reflect that only CLK_GPU_CGC is enabled.
>>
>> The commit message , and this change , is unrelated to GPUAPB clock.
> The commit message is ambiguous. Could you clarify which parent clock
> you are referring to, and whether it can be enabled by CLK_GPU_CGC?
> If it was CLK_GPU, CLK_GPU_CGC can't be able to control it.

The commit message clearly states "These new GPU_CGC clock
gate the existing GPU clock." and "GPU_CGC as well as its parent GPU 
clock." , I don't perceive any ambiguity, sorry.

Frankly, the whole GPUAPB discussion is entirely unrelated and it only 
stalls application of this bugfix and keeps upstream broken. This is not 
helping.

So unless there is anything in particular that is on-topic and prevents 
this patch from being applied, it would be good to apply it, otherwise 
the GPU on MX95 in mainline Linux is not working.


From marek.vasut at mailbox.org  Mon Dec 29 18:00:02 2025
From: marek.vasut at mailbox.org (Marek Vasut)
Date: Tue, 30 Dec 2025 03:00:02 +0100
Subject: [PATCH] arm64: guard AMU register access with ARM64_HAS_AMU_EXTN
In-Reply-To: <87sef83azt.wl-maz@kernel.org>
References: <20251022133621.178546-1-marek.vasut+renesas@mailbox.org>
 <86347bvx0f.wl-maz@kernel.org>
 <07391913-aab6-4d92-b75f-278506f51397@mailbox.org>
 <861pmvvv2g.wl-maz@kernel.org>
 <24c8da41-37db-4e69-b9aa-e33b2154acb0@mailbox.org>
 <87y0p13dlh.wl-maz@kernel.org>
 <adefdb3e-7a10-42a2-b2fc-8c1490762454@mailbox.org>
 <87sef83azt.wl-maz@kernel.org>
Message-ID: <b0e0afff-2693-4bee-9fb2-afee5565d4aa@mailbox.org>

On 10/24/25 11:27 AM, Marc Zyngier wrote:

Hello again,

>> Similar to what Linux already does on the various speculative
>> execution bugs on x86, something like this?
>>
>> "
>> MDS CPU bug present and SMT on, data leak possible. See
>> https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/mds.html
>> for more details.
>> "
> 
> You're completely off base. The problem at hand has nothing to do with
> speculation, and everything to do with access permission to counter
> registers.
> 
> I also wouldn't be surprised if you could take your whole machine down
> from userspace just by ticking some of the AM*_EL0 registers (the
> pseudocode clearly shows that there is a route to EL3 in this case).
> 
> Honestly, I think you should stop trying to papering over this issue
> behind the user's back. If you want this addressed, do it so that the
> user knows their machine is fsck'd, and that they are OK with that. Do
> it by implementing an ID register override that requires a kernel
> command-line argument.
> 
> Do I sound like a stuck record? Probably. But that's IMO the only
> acceptable solution for what you have. I'm looking forward to
> reviewing a patch implementing that suggestion, but I'll stop even
> thinking of how to paper over this in the way you suggest.
Just to wrap this one up. TFA master shortly after 2.14 release now 
contains X5H support with fixed AMU enablement, so this AMU access issue 
is gone. I think this thread can be closed.


From peter.chen at cixtech.com  Mon Dec 29 18:05:23 2025
From: peter.chen at cixtech.com (Peter Chen)
Date: Tue, 30 Dec 2025 10:05:23 +0800
Subject: [PATCH] arm64: dts: cix: Use lowercase hex
In-Reply-To: <88e9e4c4-13c9-4b96-88cc-abb581011e87@kernel.org>
References: <20251223152424.155253-2-krzysztof.kozlowski@oss.qualcomm.com>
 <aVHb-kbi2QbChxj9@nchen-desktop>
 <88e9e4c4-13c9-4b96-88cc-abb581011e87@kernel.org>
Message-ID: <aVMzY2VTFn-mNCEA@nchen-desktop>

On 25-12-29 08:17:15, Krzysztof Kozlowski wrote:
> EXTERNAL EMAIL
> 
> On 29/12/2025 02:40, Peter Chen wrote:
> > On 25-12-23 16:24:25, Krzysztof Kozlowski wrote:
> >> EXTERNAL EMAIL
> >>
> >> The DTS code coding style expects lowercase hex for values and unit
> >> addresses.
> >>
> >> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
> >>
> >> ---
> >>
> >> Patches done with sed, verified with comparing unflattened DTB and
> >> dtx_diff.
> >> ---
> >>  arch/arm64/boot/dts/cix/sky1.dtsi | 2 +-
> >>  1 file changed, 1 insertion(+), 1 deletion(-)
> >>
> >> diff --git a/arch/arm64/boot/dts/cix/sky1.dtsi b/arch/arm64/boot/dts/cix/sky1.dtsi
> >> index 64b76905cbff..fb8c826bbc97 100644
> >> --- a/arch/arm64/boot/dts/cix/sky1.dtsi
> >> +++ b/arch/arm64/boot/dts/cix/sky1.dtsi
> >> @@ -523,7 +523,7 @@ pcie_x1_1_rc: pcie at a0e0000 {
> >>                         reg-names = "reg", "cfg", "rcsu_strap", "rcsu_status", "msg";
> >>                         ranges = <0x01000000 0x0 0x38100000 0x0 0x38100000 0x0 0x00100000>,
> >>                                  <0x02000000 0x0 0x38200000 0x0 0x38200000 0x0 0x07e00000>,
> >> -                                <0x43000000 0x0C 0x00000000 0x0C 0x00000000 0x04 0x00000000>;
> >> +                                <0x43000000 0x0c 0x00000000 0x0c 0x00000000 0x04 0x00000000>;
> >
> > Sorry, I could not apply for v6.19-rc1, could you?
> 
> What do you mean? It applies cleanly on v6.19-rc1 and on next. Your
> branches are not really updated, so maybe you need to fix this.
> 

Sorry for confusing. The patch was inserted by some special characters,
See below: "=", and "3D". But no these kinds of characters when I save
internal patch for upstream. Our IT is checking this issue.

diff --git a/arch/arm64/boot/dts/cix/sky1.dtsi b/arch/arm64/boot/dts/cix/sk=
y1.dtsi
index 64b76905cbff..fb8c826bbc97 100644
--- a/arch/arm64/boot/dts/cix/sky1.dtsi
+++ b/arch/arm64/boot/dts/cix/sky1.dtsi
@@ -523,7 +523,7 @@ pcie_x1_1_rc: pcie at a0e0000 {
                        reg-names =3D "reg", "cfg", "rcsu_strap", "rcsu_sta=
tus", "msg";
                        ranges =3D <0x01000000 0x0 0x38100000 0x0 0x3810000=
0 0x0 0x00100000>,
                                 <0x02000000 0x0 0x38200000 0x0 0x38200000 =
0x0 0x07e00000>,
-                                <0x43000000 0x0C 0x00000000 0x0C 0x0000000=
0 0x04 0x00000000>;
+                                <0x43000000 0x0c 0x00000000 0x0c 0x0000000=
0 0x04 0x00000000>;
                        #address-cells =3D <3>;
                        #size-cells =3D <2>;
                        bus-range =3D <0x30 0x5f>;

I have downloaded this patch from patchwork and applied. Thanks for
improving our dts

-- 

Best regards,
Peter


From shawnguo at kernel.org  Mon Dec 29 18:05:47 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 10:05:47 +0800
Subject: [PATCH 1/1] arm64: dts: tqmls1046a: Move BMAN/QMAN buffers to
 DRAM1 area
In-Reply-To: <20251201070333.6804-1-alexander.stein@ew.tq-group.com>
References: <20251201070333.6804-1-alexander.stein@ew.tq-group.com>
Message-ID: <aVMzew2DNhm0Vwf7@dragon>

On Mon, Dec 01, 2025 at 08:03:33AM +0100, Alexander Stein wrote:
> DRAM1 is only 2GiB in size (0x00_8000_0000 - 0x01_0000_0000) which is
> already used by Linux kernel, etc. Move the allocation area of BMAN and
> QMAN to DRAM1 region. This frees the complete DRAM2 area for e.g. CMA.
> 
> Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>

Applied, thanks!


From shawnguo at kernel.org  Mon Dec 29 18:19:40 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 10:19:40 +0800
Subject: [PATCH] ARM: dts: imx6q-ba16: fix RTC interrupt level
In-Reply-To: <20251201095606.990-1-ian.ray@gehealthcare.com>
References: <20251201095606.990-1-ian.ray@gehealthcare.com>
Message-ID: <aVM2vJIPggFjHn2t@dragon>

On Mon, Dec 01, 2025 at 11:56:05AM +0200, Ian Ray wrote:
> RTC interrupt level should be set to "LOW". This was revealed by the
> introduction of commit:
> 
>   f181987ef477 ("rtc: m41t80: use IRQ flags obtained from fwnode")
> 
> which changed the way IRQ type is obtained.
> 
> Fixes: 56c27310c1b4 ("ARM: dts: imx: Add Advantech BA-16 Qseven module")
> Signed-off-by: Ian Ray <ian.ray at gehealthcare.com>

Applied, thanks!


From robh at kernel.org  Mon Dec 29 18:22:41 2025
From: robh at kernel.org (Rob Herring)
Date: Mon, 29 Dec 2025 20:22:41 -0600
Subject: [PATCH] docs: dt-bindings: hwmon: aspeed-pwm-tacho: fix typos
In-Reply-To: <20251224083845.2727976-1-weibu@redadmin.org>
References: <20251224083845.2727976-1-weibu@redadmin.org>
Message-ID: <20251230022241.GA3214066-robh@kernel.org>

On Wed, Dec 24, 2025 at 05:38:45PM +0900, Akiyoshi Kurita wrote:
> Fix "upto" -> "up to" occurrences and add missing "be" in one sentence.

This is in the process of being converted to schema. Please review that 
patch and check these issues are not copied over.

In general, don't fix .txt bindings. Convert to schema if you want to 
improve them.

Rob



From ynaffit at google.com  Mon Dec 29 18:22:49 2025
From: ynaffit at google.com (Tiffany Yang)
Date: Mon, 29 Dec 2025 18:22:49 -0800
Subject: [PATCH 6.1.y RESEND v2] KVM: arm64: sys_regs: disable
 -Wuninitialized-const-pointer warning
In-Reply-To: <20251205-stable-disable-unit-ptr-warn-v2-1-cec53a8f736b@google.com>
 (Justin Stitt's message of "Fri, 05 Dec 2025 14:51:41 -0800")
References: <20251205-stable-disable-unit-ptr-warn-v2-1-cec53a8f736b@google.com>
Message-ID: <dbx8ikdoso7a.fsf@ynaffit-andsys.c.googlers.com>

Justin Stitt <justinstitt at google.com> writes:

> A new warning in Clang 22 [1] complains that @clidr passed to
> get_clidr_el1() is an uninitialized const pointer. get_clidr_el1()
> doesn't really care since it casts away the const-ness anyways -- it is
> a false positive.

<snip>

Reviewed-by: Tiffany Yang <ynaffit at google.com>

-- 
Tiffany Y. Yang


From shawnguo at kernel.org  Mon Dec 29 18:23:04 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 10:23:04 +0800
Subject: [PATCH v2 0/3] arm64: dts: freescale: moduline-display: several
 fixes
In-Reply-To: <20251201-disp_fix-v2-0-9b03026311b6@gocontroll.com>
References: <20251201-disp_fix-v2-0-9b03026311b6@gocontroll.com>
Message-ID: <aVM3iCWrKkpcqe2N@dragon>

On Mon, Dec 01, 2025 at 12:56:49PM +0100, Maud Spierings via B4 Relay wrote:
> A couple of issues where discovered:
> - compatibles should integrate the SoM
> - the eqos mac address is stored in eth_mac1
> 
> The first one is breaking, but it is early enough that it can be
> corrected without causing any issues.
> 
> Signed-off-by: Maud Spierings <maudspierings at gocontroll.com>
> ---
> Changes in v2:
> - re-add the old compatible to fsl.yaml
> - expand the reasoning for these changes in the commit messages
> - Link to v1: https://lore.kernel.org/r/20251114-disp_fix-v1-0-49cbe826afc2 at gocontroll.com
> 
> ---
> Maud Spierings (3):
>       dt-bindings: arm: fsl: moduline-display: fix compatible
>       arm64: dts: freescale: moduline-display: fix compatible
>       arm64: dts: freescale: tx8p-ml81: fix eqos nvmem-cells

Applied all, thanks!


From ynaffit at google.com  Mon Dec 29 18:24:41 2025
From: ynaffit at google.com (Tiffany Yang)
Date: Mon, 29 Dec 2025 18:24:41 -0800
Subject: [PATCH 5.15.y RESEND] KVM: arm64: sys_regs: disable
 -Wuninitialized-const-pointer warning
In-Reply-To: <20251204-b4-stable-disable-uninit-ptr-warn-5-15-v1-1-41212e2c6409@google.com>
 (Justin Stitt's message of "Thu, 04 Dec 2025 12:44:48 -0800")
References: <20251204-b4-stable-disable-uninit-ptr-warn-5-15-v1-1-41212e2c6409@google.com>
Message-ID: <dbx8cy3wso46.fsf@ynaffit-andsys.c.googlers.com>

Justin Stitt <justinstitt at google.com> writes:

> A new warning in Clang 22 [1] complains that @clidr passed to
> get_clidr_el1() is an uninitialized const pointer. get_clidr_el1()
> doesn't really care since it casts away the const-ness anyways -- it is
> a false positive.

> |  ../arch/arm64/kvm/sys_regs.c:2838:23: warning: variable 'clidr' is  
> uninitialized when passed as a const pointer argument here  
> [-Wuninitialized-const-pointer]
> |   2838 |         get_clidr_el1(NULL, &clidr); /* Ugly... */
> |        |                              ^~~~~

> This patch isn't needed for anything past 6.1 as this code section was
> reworked in Commit 7af0c2534f4c ("KVM: arm64: Normalize cache
> configuration"). Since there is no upstream equivalent, this patch just
> needs to be applied to 5.15.


This error has also been showing up in 5.10 since KernelCI started using
clang-21.

> Disable this warning for sys_regs.o with an iron fist as it doesn't make
> sense to waste maintainer's time or potentially break builds by
> backporting large changelists from 6.2+.

> Cc: stable at vger.kernel.org
> Fixes: 7c8c5e6a9101e ("arm64: KVM: system register handling")
> Link:  
> https://github.com/llvm/llvm-project/commit/00dacf8c22f065cb52efb14cd091d441f19b319e  
> [1]
> Reviewed-by: Nathan Chancellor <nathan at kernel.org>
> Signed-off-by: Justin Stitt <justinstitt at google.com>
<snip>

Reviewed-by: Tiffany Yang <ynaffit at google.com>

-- 
Tiffany Y. Yang


From shawnguo at kernel.org  Mon Dec 29 18:28:27 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 10:28:27 +0800
Subject: [PATCH v2] arm64: dts: imx93-9x9-qsb: add CAN support overlay
 file
In-Reply-To: <20251202-b4-9391-can-dts-v2-1-edab562615a7@nxp.com>
References: <20251202-b4-9391-can-dts-v2-1-edab562615a7@nxp.com>
Message-ID: <aVM4ywIkJCsRdy2U@dragon>

On Tue, Dec 02, 2025 at 02:04:33PM +0800, Haibo Chen wrote:
> CAN1 and Micfil share pins on imx93-9x9-qsb board, use TMUX1574RSVR
> to control the connection: put sel to high, select CAN1, put sel to
> low, select Micfil. In default, sel keep low.
> 
> To support CAN1, need to put the sel to high. Besides, CAN1 use phy
> TJA1057GT/3.
> 
> ---
> Signed-off-by: Haibo Chen <haibo.chen at nxp.com>

This line should be above "---".  Otherwise, it gets lost.

Fixed it up and applied the patch.

Shawn

> ---
> Changes in v2:
> - change commit title
> - Keep order by alphabet in Makefile
> - Link to v1: https://lore.kernel.org/r/20251126-b4-9391-can-dts-v1-1-c23145f0d2db at nxp.com
> ---
>  arch/arm64/boot/dts/freescale/Makefile             |  2 +
>  .../boot/dts/freescale/imx93-9x9-qsb-can1.dtso     | 63 ++++++++++++++++++++++
>  2 files changed, 65 insertions(+)


From shawnguo at kernel.org  Mon Dec 29 18:31:37 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 10:31:37 +0800
Subject: [PATCH] arm64: dts: imx8mp: Fix LAN8740Ai PHY reference clock on
 DH electronics i.MX8M Plus DHCOM
In-Reply-To: <20251202134200.8397-1-marek.vasut@mailbox.org>
References: <20251202134200.8397-1-marek.vasut@mailbox.org>
Message-ID: <aVM5iadHU5ipnQ0M@dragon>

On Tue, Dec 02, 2025 at 02:41:51PM +0100, Marek Vasut wrote:
> Add missing 'clocks' property to LAN8740Ai PHY node, to allow the PHY driver
> to manage LAN8740Ai CLKIN reference clock supply. This fixes sporadic link
> bouncing caused by interruptions on the PHY reference clock, by letting the
> PHY driver manage the reference clock and assure there are no interruptions.
> 
> This follows the matching PHY driver recommendation described in commit
> bedd8d78aba3 ("net: phy: smsc: LAN8710/20: add phy refclk in support")
> 
> Fixes: 8d6712695bc8 ("arm64: dts: imx8mp: Add support for DH electronics i.MX8M Plus DHCOM and PDK2")
> Signed-off-by: Marek Vasut <marek.vasut at mailbox.org>

Applied, thanks!


From shawnguo at kernel.org  Mon Dec 29 18:34:35 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 10:34:35 +0800
Subject: [PATCH V2] arm64: dts: imx8qm-ss-dma: correct the dma channels
 of lpuart
In-Reply-To: <20251203015956.116364-1-sherry.sun@nxp.com>
References: <20251203015956.116364-1-sherry.sun@nxp.com>
Message-ID: <aVM6O4OMk0I9F0Cc@dragon>

On Wed, Dec 03, 2025 at 09:59:56AM +0800, Sherry Sun wrote:
> The commit 616effc0272b5 ("arm64: dts: imx8: Fix lpuart DMA channel
> order") swap uart rx and tx channel at common imx8-ss-dma.dtsi. But miss
> update imx8qm-ss-dma.dtsi.
> 
> The commit 5a8e9b022e569 ("arm64: dts: imx8qm-ss-dma: Pass lpuart
> dma-names") just simple add dma-names as binding doc requirement.
> 
> Correct lpuart0 - lpuart3 dma rx and tx channels, and use defines for
> the FSL_EDMA_RX flag.
> 
> Fixes: 5a8e9b022e56 ("arm64: dts: imx8qm-ss-dma: Pass lpuart dma-names")
> Signed-off-by: Sherry Sun <sherry.sun at nxp.com>

Applied, thanks!


From shawnguo at kernel.org  Mon Dec 29 18:42:14 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 10:42:14 +0800
Subject: [PATCH 1/5] arm64: dts: imx91-11x11-evk: Refine label and node
 name of WM8962
In-Reply-To: <20251203070605.1868821-2-chancel.liu@nxp.com>
References: <20251203070605.1868821-1-chancel.liu@nxp.com>
 <20251203070605.1868821-2-chancel.liu@nxp.com>
Message-ID: <aVM8Btd9CYEfg9zz@dragon>

On Wed, Dec 03, 2025 at 04:06:01PM +0900, Chancel Liu wrote:
> Refine label with "wm8962" and node name with "codec" to follow
> devicetree specification.
> 
> Signed-off-by: Chancel Liu <chancel.liu at nxp.com>
> ---
>  arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts b/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
> index aca78768dbd4..313ebc7e8a9c 100644
> --- a/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
> +++ b/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
> @@ -132,7 +132,7 @@ &lpi2c1 {
>  	pinctrl-names = "default";
>  	status = "okay";
>  
> -	audio_codec: wm8962 at 1a {
> +	wm8962: codec at 1a {

The node name could be better named as audio-codec.

I fixed it up and applied the series.

Shawn

>  		compatible = "wlf,wm8962";
>  		reg = <0x1a>;
>  		clocks = <&clk IMX93_CLK_SAI3_GATE>;
> -- 
> 2.50.1
> 


From shawnguo at kernel.org  Mon Dec 29 18:50:56 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 10:50:56 +0800
Subject: [PATCH v2 0/4] arm64: dts: additions for imx8mp-phyboard-pollux
In-Reply-To: <20251205-imx8mp-dts-additions-v2-0-d4db54fbadd0@phytec.de>
References: <20251205-imx8mp-dts-additions-v2-0-d4db54fbadd0@phytec.de>
Message-ID: <aVM-EKLH10KzU1ks@dragon>

On Fri, Dec 05, 2025 at 10:33:24AM +0100, Yannic Moog wrote:
> This series adds missing miscellaneous hardware description to the
> respective device tree files as well as a bluetooth/wifi expansion
> board.
> 
> - i2c3 (basis for camera overlays)
> - missing supply voltages
> - PEB-WLBT-05 expansion board
> 
> ---
> Changes in v2:
> - improved wording of i2c3 commit description
> - removed regulator-always-on and regulator-boot-on properties
> - rebased
> - Link to v1: https://lore.kernel.org/r/20251020-imx8mp-dts-additions-v1-0-ea9ac5652b8b at phytec.de
> 
> ---
> Stefan Riedmueller (1):
>       arm64: dts: imx8mp-phyboard-pollux: Enable i2c3
> 
> Yannic Moog (3):
>       arm64: dts: imx8mp-phyboard-pollux: add fan-supply
>       arm64: dts: imx8mp-phycore-som: add spi-nor supply vcc
>       arm64: dts: imx8mp-phyboard-pollux: add PEB-WLBT-05 expansion board

Applied all, thanks!


From jiyu.yang at oss.nxp.com  Mon Dec 29 18:53:50 2025
From: jiyu.yang at oss.nxp.com (Rain Yang)
Date: Tue, 30 Dec 2025 10:53:50 +0800
Subject: [PATCH] arm64: dts: imx95: Use GPU_CGC as core clock for GPU
In-Reply-To: <53ea529f-3538-4ab5-aa99-0caa6729b4cd@mailbox.org>
References: <aS-lEibp3zTsaR6T@oss.nxp.com>
 <c6e0e55a-06da-4665-972e-e9b5b8c08bf7@mailbox.org>
 <aTACuRjC_Zpf8IOU@oss.nxp.com>
 <de36091e-c890-4897-b3e3-2a7575029a5d@mailbox.org>
 <aTD5np-HGaJqhzkD@oss.nxp.com>
 <5944d872-01a3-47e9-977b-029f3be4fd83@mailbox.org>
 <aTKVMAMQ6v_BwD6R@oss.nxp.com>
 <9b593731-898f-46a7-8ee5-68f8c170351c@mailbox.org>
 <aTYxm_dfMwF4H0_b@oss.nxp.com>
 <53ea529f-3538-4ab5-aa99-0caa6729b4cd@mailbox.org>
Message-ID: <aVM-mSkSubMPd7Du@oss.nxp.com>

On Tue, Dec 30, 2025 at 02:53:38AM +0100, Marek Vasut wrote:
>On 12/8/25 3:02 AM, Rain Yang wrote:
>
>> > > Okay, I?ll submit a patch later.
>> > > The commit message should reflect that only CLK_GPU_CGC is enabled.
>> > 
>> > The commit message , and this change , is unrelated to GPUAPB clock.
>> The commit message is ambiguous. Could you clarify which parent clock
>> you are referring to, and whether it can be enabled by CLK_GPU_CGC?
>> If it was CLK_GPU, CLK_GPU_CGC can't be able to control it.
>
>The commit message clearly states "These new GPU_CGC clock
>gate the existing GPU clock." and "GPU_CGC as well as its parent GPU clock."
>, I don't perceive any ambiguity, sorry.
>
>Frankly, the whole GPUAPB discussion is entirely unrelated and it only stalls
>application of this bugfix and keeps upstream broken. This is not helping.
>
>So unless there is anything in particular that is on-topic and prevents this
>patch from being applied, it would be good to apply it, otherwise the GPU on
>MX95 in mainline Linux is not working.
Hi Marek,

I?m not opposed to this patch being merged into mainline, but the commit
message needs to be accurate. the parent CLK_GPU cannot be enabled or
disabled externally. The last sentence should clearly state:

When the panthor driver enables the GPU core clock, it enables the GPU_CGC.

This ensures the description reflects the actual hardware behavior and
avoids confusion for future maintainers.
Thanks for addressing this issue ? once the commit message is corrected,
I?m fine with this going in.


From shawnguo at kernel.org  Mon Dec 29 18:57:31 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 10:57:31 +0800
Subject: [PATCH v1 0/4] arm64: dts: imx93-var-som-symphony: align DTS
 with hw revision
In-Reply-To: <20251205182258.50397-1-stefano.r@variscite.com>
References: <20251205182258.50397-1-stefano.r@variscite.com>
Message-ID: <aVM_m_qAo91E5oKM@dragon>

On Fri, Dec 05, 2025 at 07:22:53PM +0100, Stefano Radaelli wrote:
> This series adds support for several peripherals available on the
> Variscite Symphony carrier board for the VAR-SOM-MX93 module.
> 
> The patches introduce:
> 
> - GPIO aliases cleanup to better expose available GPIOs
> - FT5x06 capacitive touch controller
> - USB1 (OTG, via PTN5150 Type-C controller) and USB2 (host-only) support
> - LPSPI6 controller exposed on the expansion connector
> 
> These changes describe real hardware connections and make the exposed
> interfaces available to user applications.
> 
> Tested on the Symphony board with a VAR-SOM-MX93.
> 
> Stefano Radaelli (4):
>   arm64: dts: imx93-var-som-symphony: Update gpio aliases
>   arm64: dts: imx93-var-som-symphony: Add support for ft5x06 touch
>     controller
>   arm64: dts: imx93-var-som-symphony: Add USB support
>   arm64: dts: imx93-var-som-symphony: Enable LPSPI6 controller

Applied all, thanks!


From shawnguo at kernel.org  Mon Dec 29 18:59:48 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 10:59:48 +0800
Subject: [PATCH v1] arm64: dts: freescale: imx8-apalis: Add ethernet alias
In-Reply-To: <20251209085747.39009-1-francesco@dolcini.it>
References: <20251209085747.39009-1-francesco@dolcini.it>
Message-ID: <aVNAJDTkBihpsmi8@dragon>

On Tue, Dec 09, 2025 at 09:57:46AM +0100, Francesco Dolcini wrote:
> From: Francesco Dolcini <francesco.dolcini at toradex.com>
> 
> Add alias for the apalis first ethernet interface, this ensures
> consistent interface naming (e.g. `end0`) and this is used by the
> firmware to correctly set the MAC address.
> 
> Signed-off-by: Francesco Dolcini <francesco.dolcini at toradex.com>

Applied, thanks!


From shawnguo at kernel.org  Mon Dec 29 19:13:26 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 11:13:26 +0800
Subject: [PATCH v1 0/3] arm64: dts: freescale:
 imx8mp-(verdin|toradex-smarc): Add HDMI audio support
In-Reply-To: <20251209101754.54067-1-francesco@dolcini.it>
References: <20251209101754.54067-1-francesco@dolcini.it>
Message-ID: <aVNDVu0ELBsKR11J@dragon>

On Tue, Dec 09, 2025 at 11:17:48AM +0100, Francesco Dolcini wrote:
> From: Francesco Dolcini <francesco.dolcini at toradex.com>
> 
> Add support for HDMI audio on Verdin and Toradex SMARC iMX8M Plus boards, as
> done in commit b21f87b8322f ("arm64: dts: imx8mp-evk: enable hdmi_pai device")
> on the NXP i.MX8MP EVK board.
> 
> In addition a small cleanup on spurious comments.
> 
> Francesco Dolcini (3):
>   arm64: dts: freescale: imx8mp-verdin: Remove obsolete TODO comments
>   arm64: dts: freescale: imx8mp-verdin: enable hdmi_pai device
>   arm64: dts: freescale: imx8mp-toradex-smarc: enable hdmi_pai device

Applied all, thanks!


From shawnguo at kernel.org  Mon Dec 29 19:17:48 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 11:17:48 +0800
Subject: [PATCH v2 0/8] TQMa8MPxL DT fixes
In-Reply-To: <20251209105318.977102-1-alexander.stein@ew.tq-group.com>
References: <20251209105318.977102-1-alexander.stein@ew.tq-group.com>
Message-ID: <aVNEXMxhkWMumfvG@dragon>

On Tue, Dec 09, 2025 at 11:53:06AM +0100, Alexander Stein wrote:
> Hi,
> 
> this seris includes small fixes for TQMa8MPxL both on MBa8MPxL and
> MBa8MP-RAS314. The ethernet IRQ type has been changed to level-low and CEC
> pad configuration has been fixed to use open-drain output.
> For both boards the HDMI audio output support has been added as well as
> the ENET event2 signal on MBa8MPxL, which can be enabled using
> /sys/class/ptp/ptp1/period.
> 
> Best regards,
> Alexander
> 
> Changes in v2:
> * Collected R-b
> * Fixed typos
> 
> Alexander Stein (8):
>   arm64: dts: tqma8mpql-mba8mpxl: Adjust copyright text format
>   arm64: dts: tqma8mpql-mba8mpxl: Fix Ethernet PHY IRQ support
>   arm64: dts: tqma8mpql-mba8mpxl: Fix HDMI CEC pad control settings
>   arm64: dts: tqma8mpql-mba8mpxl: Add HDMI audio output support
>   arm64: dts: tqma8mpql-mba8mpxl: Configure IEEE 1588 event out signal
>   arm64: dts: tqma8mpql-mba8mp-ras314: Fix Ethernet PHY IRQ support
>   arm64: dts: tqma8mpql-mba8mp-ras314: Fix HDMI CEC pad control settings
>   arm64: dts: tqma8mpql-mba8mp-ras314: Add HDMI audio output support

Applied all, thanks!


From shawnguo at kernel.org  Mon Dec 29 19:19:01 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 11:19:01 +0800
Subject: [PATCH] arm64: dts: imx8m{m,p}-venice-gw71xx: Add Magetometer
In-Reply-To: <20251209205828.689999-1-tharvey@gateworks.com>
References: <20251209205828.689999-1-tharvey@gateworks.com>
Message-ID: <aVNEpXM3XG8Dfczl@dragon>

On Tue, Dec 09, 2025 at 12:58:28PM -0800, Tim Harvey wrote:
> Add support for the optional LIS2MDL magnetometer on GW71xx baseboards.
> 
> Signed-off-by: Tim Harvey <tharvey at gateworks.com>

Applied, thanks!


From shawnguo at kernel.org  Mon Dec 29 19:28:16 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 11:28:16 +0800
Subject: [PATCH v10 4/4] arm64: dt: imx95: Add the missed ref clock for
 PCIe[0,1]
In-Reply-To: <20251211064821.2707001-5-hongxing.zhu@nxp.com>
References: <20251211064821.2707001-1-hongxing.zhu@nxp.com>
 <20251211064821.2707001-5-hongxing.zhu@nxp.com>
Message-ID: <aVNG0BjbEVHhgNCa@dragon>

On Thu, Dec 11, 2025 at 02:48:21PM +0800, Richard Zhu wrote:
> i.MX95 PCIes have two reference clock inputs, one of them is from
> internal PLL. It's wired inside chip and present as "ref" clock. It's
> not an optional clock.
> 
> Add the missed ref clock for PCIe[0,1].
> 
> Signed-off-by: Richard Zhu <hongxing.zhu at nxp.com>

It doesn't seem to apply to my tree.

Shawn

> ---
>  .../boot/dts/freescale/imx95-tqma9596sa-mb-smarc-2.dts | 10 ++++++----
>  1 file changed, 6 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/freescale/imx95-tqma9596sa-mb-smarc-2.dts b/arch/arm64/boot/dts/freescale/imx95-tqma9596sa-mb-smarc-2.dts
> index 5b6b2bb80b288..1258fcb54681e 100644
> --- a/arch/arm64/boot/dts/freescale/imx95-tqma9596sa-mb-smarc-2.dts
> +++ b/arch/arm64/boot/dts/freescale/imx95-tqma9596sa-mb-smarc-2.dts
> @@ -237,8 +237,9 @@ &pcie0 {
>  	clocks = <&scmi_clk IMX95_CLK_HSIO>,
>  		 <&pcieclk 1>,
>  		 <&scmi_clk IMX95_CLK_HSIOPLL_VCO>,
> -		 <&scmi_clk IMX95_CLK_HSIOPCIEAUX>;
> -	clock-names = "pcie", "pcie_bus", "pcie_phy", "pcie_aux";
> +		 <&scmi_clk IMX95_CLK_HSIOPCIEAUX>,
> +		 <&hsio_blk_ctl 0>;
> +	clock-names = "pcie", "pcie_bus", "pcie_phy", "pcie_aux", "ref";
>  	reset-gpio = <&expander2 9 GPIO_ACTIVE_LOW>;
>  	status = "okay";
>  };
> @@ -250,8 +251,9 @@ &pcie1 {
>  	clocks = <&scmi_clk IMX95_CLK_HSIO>,
>  		 <&pcieclk 0>,
>  		 <&scmi_clk IMX95_CLK_HSIOPLL_VCO>,
> -		 <&scmi_clk IMX95_CLK_HSIOPCIEAUX>;
> -	clock-names = "pcie", "pcie_bus", "pcie_phy", "pcie_aux";
> +		 <&scmi_clk IMX95_CLK_HSIOPCIEAUX>,
> +		 <&hsio_blk_ctl 0>;
> +	clock-names = "pcie", "pcie_bus", "pcie_phy", "pcie_aux", "ref";
>  	reset-gpio = <&expander2 10 GPIO_ACTIVE_LOW>;
>  	status = "okay";
>  };
> -- 
> 2.37.1
> 


From shawnguo at kernel.org  Mon Dec 29 20:11:00 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 12:11:00 +0800
Subject: [PATCH v2 2/2] arm64: dts: freescale: Add FRDM-IMX91 basic
 support
In-Reply-To: <20251212-imx91_frdm-v2-2-4dd6d289e81d@nxp.com>
References: <20251212-imx91_frdm-v2-0-4dd6d289e81d@nxp.com>
 <20251212-imx91_frdm-v2-2-4dd6d289e81d@nxp.com>
Message-ID: <aVNQ1FbyIFnNO9bK@dragon>

On Fri, Dec 12, 2025 at 11:31:34AM +0900, Joseph Guo wrote:
> The FRDM i.MX 91 development board is a low-cost and
> compact developmentboard featuring the i.MX 91 applications processor:
> https://www.nxp.com/design/design-center/development-boards-and-designs/FRDM-IMX91
> 
> Add FRDM-IMX91 board dts support.
> - Enable ADC1.
> - Enable lpuart1 and lpuart5.
> - Enable network eqos and fec.
> - Enable I2C bus and children nodes under I2C bus.
> - Enable USB and related nodes.
> - Enable uSDHC1, uSDHC2 and uSDHC3.
> - Enable MU1 and MU2.
> - Enable Watchdog3.
> - Enable MQS
> 
> Co-developed-by: Tom Zheng <haidong.zheng at nxp.com>
> Signed-off-by: Tom Zheng <haidong.zheng at nxp.com>
> Co-developed-by: Steven Yang <steven.yang at nxp.com>
> Signed-off-by: Steven Yang <steven.yang at nxp.com>
> Signed-off-by: Joseph Guo <qijian.guo at nxp.com>
> ---
> Changes in v2:
> - rename compatible 'frdm-imx91' to 'imx91-11x11-frdm'
> - rename model to 'NXP i.MX91 11x11 FRDM Board'
> - rename 'sw-keys' to 'gpio-keys'
> - rename 'user_btn' to 'button-k'
> - drop lpspi3 node
> - rename iomuxc 'grpsleep' to 'sleepgrp'
> - use CAN PHY to manage the stby gpio of flexcan2
> - drop realtek property
> - add pcf2131 aliase
> - add bootph- property for nodes should be kept in bootloader phase
> - add reset-gpio and assert for eqos and fec
> - delete unused alias
> ---
>  arch/arm64/boot/dts/freescale/Makefile             |   1 +
>  arch/arm64/boot/dts/freescale/imx91-11x11-frdm.dts | 904 +++++++++++++++++++++
>  2 files changed, 905 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
> index f30d3fd724d0ce6b38f7bef10e3970ac34f70f4a..d0808ec3c1c4ab848ad9edf45cf453ce40a5f2c6 100644
> --- a/arch/arm64/boot/dts/freescale/Makefile
> +++ b/arch/arm64/boot/dts/freescale/Makefile
> @@ -368,6 +368,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8qxp-tqma8xqps-mb-smarc-2.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx8ulp-9x9-evk.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx8ulp-evk.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx91-11x11-evk.dtb
> +dtb-$(CONFIG_ARCH_MXC) += imx91-11x11-frdm.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx91-phyboard-segin.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx91-tqma9131-mba91xxca.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx93-9x9-qsb.dtb
> diff --git a/arch/arm64/boot/dts/freescale/imx91-11x11-frdm.dts b/arch/arm64/boot/dts/freescale/imx91-11x11-frdm.dts
> new file mode 100644
> index 0000000000000000000000000000000000000000..066a319b4df824515843f20076533857064a09be
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx91-11x11-frdm.dts
> @@ -0,0 +1,904 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright 2025 NXP
> + */
> +
> +/dts-v1/;
> +
> +#include <dt-bindings/usb/pd.h>
> +#include "imx91.dtsi"
> +
> +/ {
> +	compatible = "fsl,imx91-11x11-frdm", "fsl,imx91";
> +	model = "NXP i.MX91 11x11 FRDM Board";
> +
> +	aliases {
> +		ethernet0 = &fec;
> +		ethernet1 = &eqos;
> +		gpio0 = &gpio1;
> +		gpio1 = &gpio2;
> +		gpio2 = &gpio3;
> +		gpio3 = &gpio4;
> +		i2c0 = &lpi2c1;
> +		i2c1 = &lpi2c2;
> +		i2c2 = &lpi2c3;
> +		mmc0 = &usdhc1;
> +		mmc1 = &usdhc2;
> +		mmc2 = &usdhc3;
> +		rtc0 = &bbnsm_rtc;
> +		rtc1 = &pcf2131;
> +		serial0 = &lpuart1;
> +		serial4 = &lpuart5;
> +	};
> +
> +	chosen {
> +		stdout-path = &lpuart1;
> +	};
> +
> +	flexcan_phy: can-phy {
> +		compatible = "nxp,tja1051";
> +		#phy-cells = <0>;
> +		max-bitrate = <5000000>;
> +		enable-gpios = <&pcal6524 23 GPIO_ACTIVE_LOW>;
> +	};
> +
> +	gpio-keys {
> +		compatible = "gpio-keys";
> +
> +		button-k2 {
> +			interrupt-parent = <&pcal6524>;
> +			interrupts = <5 IRQ_TYPE_EDGE_FALLING>;
> +			label = "Button K2";
> +			gpios = <&pcal6524 5 GPIO_PULL_UP>;
> +			linux,code = <BTN_1>;
> +		};
> +
> +		button-k3 {
> +			interrupt-parent = <&pcal6524>;
> +			interrupts = <6 IRQ_TYPE_EDGE_FALLING>;
> +			label = "Button K3";
> +			gpios = <&pcal6524 6 GPIO_PULL_UP>;
> +			linux,code = <BTN_2>;
> +		};
> +	};
> +
> +	reg_vref_1v8: regulator-adc-vref {
> +		compatible = "regulator-fixed";
> +		regulator-max-microvolt = <1800000>;
> +		regulator-min-microvolt = <1800000>;
> +		regulator-name = "vref_1v8";
> +	};
> +
> +	reg_m2_pwr: regulator-m2-pwr {
> +		compatible = "regulator-fixed";
> +		regulator-max-microvolt = <3300000>;
> +		regulator-min-microvolt = <3300000>;
> +		regulator-name = "M.2-power";
> +		gpio = <&pcal6524 13 GPIO_ACTIVE_HIGH>;
> +		enable-active-high;
> +	};
> +
> +	reg_usdhc2_vmmc: regulator-usdhc2 {
> +		compatible = "regulator-fixed";
> +		off-on-delay-us = <12000>;
> +		pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
> +		pinctrl-names = "default";
> +		regulator-max-microvolt = <3300000>;
> +		regulator-min-microvolt = <3300000>;
> +		regulator-name = "VSD_3V3";
> +		gpio = <&gpio3 7 GPIO_ACTIVE_HIGH>;
> +		enable-active-high;
> +		bootph-pre-ram;
> +		bootph-some-ram;
> +	};
> +
> +	reg_usdhc3_vmmc: regulator-usdhc3 {
> +		compatible = "regulator-fixed";
> +		regulator-max-microvolt = <3300000>;
> +		regulator-min-microvolt = <3300000>;
> +		regulator-name = "WLAN_EN";
> +		vin-supply = <&reg_m2_pwr>;
> +		gpio = <&pcal6524 20 GPIO_ACTIVE_HIGH>;
> +		enable-active-high;
> +		/*
> +		 * This regulator defined as PDn pin of the IW610 wifi module.
> +		 * IW610 wifi chip needs more delay than other wifi chips to complete
> +		 * the host interface initialization after power up, otherwise the
> +		 * internal state of IW610 may be unstable, resulting in the failure of
> +		 * the SDIO3.0 switch voltage.
> +		 */
> +		startup-delay-us = <20000>;
> +	};
> +
> +	reg_vdd_12v: regulator-vdd-12v {
> +		compatible = "regulator-fixed";
> +		regulator-max-microvolt = <12000000>;
> +		regulator-min-microvolt = <12000000>;
> +		regulator-name = "reg_vdd_12v";
> +		gpio = <&pcal6524 14 GPIO_ACTIVE_HIGH>;
> +		enable-active-high;
> +	};
> +
> +	reg_vexp_3v3: regulator-vexp-3v3 {
> +		compatible = "regulator-fixed";
> +		regulator-max-microvolt = <3300000>;
> +		regulator-min-microvolt = <3300000>;
> +		regulator-name = "VEXP_3V3";
> +		vin-supply = <&buck4>;
> +		gpio = <&pcal6524 2 GPIO_ACTIVE_HIGH>;
> +		enable-active-high;
> +	};
> +
> +	reg_vexp_5v: regulator-vexp-5v {
> +		compatible = "regulator-fixed";
> +		regulator-max-microvolt = <5000000>;
> +		regulator-min-microvolt = <5000000>;
> +		regulator-name = "VEXP_5V";
> +		gpio = <&pcal6524 8 GPIO_ACTIVE_HIGH>;
> +		enable-active-high;
> +	};
> +
> +	reserved-memory {
> +		ranges;
> +		#address-cells = <2>;
> +		#size-cells = <2>;
> +
> +		linux,cma {
> +			compatible = "shared-dma-pool";
> +			alloc-ranges = <0 0x80000000 0 0x30000000>;
> +			reusable;
> +			size = <0 0x10000000>;
> +			linux,cma-default;
> +		};
> +	};
> +
> +	soc at 0 {
> +		bootph-all;
> +		bootph-pre-ram;
> +	};
> +
> +	sound-mqs {
> +		compatible = "fsl,imx6sx-sdb-mqs",
> +			     "fsl,imx-audio-mqs";
> +		audio-codec = <&mqs1>;
> +		audio-cpu = <&sai1>;
> +		model = "mqs-audio";
> +	};
> +
> +	usdhc3_pwrseq: usdhc3-pwrseq {
> +		compatible = "mmc-pwrseq-simple";
> +		reset-gpios = <&pcal6524 12 GPIO_ACTIVE_LOW>;
> +	};
> +};
> +
> +&adc1 {
> +	vref-supply = <&reg_vref_1v8>;
> +	status = "okay";
> +};
> +
> +&aips1 {
> +	bootph-pre-ram;
> +	bootph-all;
> +};
> +
> +&aips2 {
> +	bootph-pre-ram;
> +	bootph-some-ram;
> +};
> +
> +&aips3 {
> +	bootph-pre-ram;
> +	bootph-some-ram;
> +};
> +
> +&clk {
> +	bootph-all;
> +	bootph-pre-ram;
> +};
> +
> +&clk_ext1 {
> +	bootph-all;
> +	bootph-pre-ram;
> +};
> +
> +&eqos {
> +	phy-handle = <&ethphy1>;
> +	phy-mode = "rgmii-id";
> +	pinctrl-0 = <&pinctrl_eqos>;
> +	pinctrl-1 = <&pinctrl_eqos_sleep>;
> +	pinctrl-names = "default", "sleep";
> +	status = "okay";
> +
> +	mdio {
> +		compatible = "snps,dwmac-mdio";
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		clock-frequency = <5000000>;
> +
> +		ethphy1: ethernet-phy at 1 {
> +			reg = <1>;
> +			reset-gpios = <&pcal6524 15 GPIO_ACTIVE_LOW>;
> +			reset-assert-us = <15000>;
> +			reset-deassert-us = <100000>;
> +		};
> +	};
> +};
> +
> +&fec {
> +	phy-handle = <&ethphy2>;
> +	phy-mode = "rgmii-id";
> +	pinctrl-0 = <&pinctrl_fec>;
> +	pinctrl-1 = <&pinctrl_fec_sleep>;
> +	pinctrl-names = "default", "sleep";
> +	fsl,magic-packet;
> +	status = "okay";
> +
> +	mdio {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		clock-frequency = <5000000>;
> +
> +		ethphy2: ethernet-phy at 2 {
> +			reg = <2>;
> +			reset-gpios = <&pcal6524 16 GPIO_ACTIVE_LOW>;
> +			reset-assert-us = <15000>;
> +			reset-deassert-us = <100000>;
> +		};
> +	};
> +};
> +
> +&flexcan2 {
> +	pinctrl-0 = <&pinctrl_flexcan2>;
> +	pinctrl-1 = <&pinctrl_flexcan2_sleep>;
> +	pinctrl-names = "default", "sleep";
> +	phys = <&flexcan_phy>;
> +	status = "okay";
> +};
> +
> +&gpio1 {
> +	bootph-pre-ram;
> +	bootph-some-ram;
> +};
> +
> +&gpio2 {
> +	bootph-pre-ram;
> +	bootph-some-ram;
> +};
> +
> +&gpio3 {
> +	bootph-pre-ram;
> +	bootph-some-ram;
> +};
> +
> +&gpio4 {
> +	bootph-pre-ram;
> +	bootph-some-ram;
> +};
> +
> +&lpi2c1 {
> +	clock-frequency = <400000>;
> +	pinctrl-0 = <&pinctrl_lpi2c1>;
> +	pinctrl-names = "default";
> +	status = "okay";
> +	bootph-pre-ram;
> +	bootph-some-ram;
> +
> +	pcal6408: gpio at 20 {
> +		compatible = "nxp,pcal9554b";
> +		reg = <0x20>;
> +		#gpio-cells = <2>;
> +		gpio-controller;
> +		vcc-supply = <&reg_usdhc3_vmmc>;
> +		status = "okay";
> +	};
> +};
> +
> +&lpi2c2 {
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +	clock-frequency = <400000>;
> +	pinctrl-0 = <&pinctrl_lpi2c2>;
> +	pinctrl-names = "default";
> +	status = "okay";
> +	bootph-pre-ram;
> +	bootph-some-ram;

Can we end property list with 'status'?

> +
> +	pcal6524: gpio at 22 {
> +		compatible = "nxp,pcal6524";
> +		reg = <0x22>;
> +		#interrupt-cells = <2>;
> +		interrupt-controller;
> +		interrupts = <27 IRQ_TYPE_LEVEL_LOW>;
> +		#gpio-cells = <2>;
> +		gpio-controller;
> +		interrupt-parent = <&gpio3>;
> +		pinctrl-0 = <&pinctrl_pcal6524>;
> +		pinctrl-names = "default";
> +	};
> +
> +	pmic at 25 {
> +		compatible = "nxp,pca9451a";
> +		reg = <0x25>;
> +		interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
> +		interrupt-parent = <&pcal6524>;
> +		bootph-pre-ram;
> +		bootph-some-ram;
> +
> +		regulators {
> +			bootph-pre-ram;
> +			bootph-some-ram;

Have a newline between property list and child node.

Shawn

> +			buck1: BUCK1 {
> +				regulator-always-on;
> +				regulator-boot-on;
> +				regulator-max-microvolt = <2237500>;
> +				regulator-min-microvolt = <650000>;
> +				regulator-name = "BUCK1";
> +				regulator-ramp-delay = <3125>;
> +			};
> +
> +			buck2: BUCK2 {
> +				regulator-always-on;
> +				regulator-boot-on;
> +				regulator-max-microvolt = <2187500>;
> +				regulator-min-microvolt = <600000>;
> +				regulator-name = "BUCK2";
> +				regulator-ramp-delay = <3125>;
> +			};
> +
> +			buck4: BUCK4 {
> +				regulator-always-on;
> +				regulator-boot-on;
> +				regulator-max-microvolt = <3400000>;
> +				regulator-min-microvolt = <600000>;
> +				regulator-name = "BUCK4";
> +			};
> +
> +			buck5: BUCK5 {
> +				regulator-always-on;
> +				regulator-boot-on;
> +				regulator-max-microvolt = <3400000>;
> +				regulator-min-microvolt = <600000>;
> +				regulator-name = "BUCK5";
> +			};
> +
> +			buck6: BUCK6 {
> +				regulator-always-on;
> +				regulator-boot-on;
> +				regulator-max-microvolt = <3400000>;
> +				regulator-min-microvolt = <600000>;
> +				regulator-name = "BUCK6";
> +			};
> +
> +			ldo1: LDO1 {
> +				regulator-always-on;
> +				regulator-boot-on;
> +				regulator-max-microvolt = <3300000>;
> +				regulator-min-microvolt = <1600000>;
> +				regulator-name = "LDO1";
> +			};
> +
> +			ldo4: LDO4 {
> +				regulator-always-on;
> +				regulator-boot-on;
> +				regulator-max-microvolt = <3300000>;
> +				regulator-min-microvolt = <800000>;
> +				regulator-name = "LDO4";
> +			};
> +
> +			ldo5: LDO5 {
> +				regulator-always-on;
> +				regulator-boot-on;
> +				regulator-max-microvolt = <3300000>;
> +				regulator-min-microvolt = <1800000>;
> +				regulator-name = "LDO5";
> +			};
> +		};
> +	};
> +};
> +
> +&lpi2c3 {
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +	clock-frequency = <400000>;
> +	pinctrl-0 = <&pinctrl_lpi2c3>;
> +	pinctrl-names = "default";
> +	status = "okay";
> +	bootph-pre-ram;
> +	bootph-some-ram;
> +
> +	ptn5110: tcpc at 50 {
> +		compatible = "nxp,ptn5110", "tcpci";
> +		reg = <0x50>;
> +		interrupts = <27 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-parent = <&gpio3>;
> +
> +		typec1_con: connector {
> +			compatible = "usb-c-connector";
> +			data-role = "dual";
> +			label = "USB-C";
> +			op-sink-microwatt = <15000000>;
> +			power-role = "dual";
> +			self-powered;
> +			sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)
> +				     PDO_VAR(5000, 20000, 3000)>;
> +			source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
> +			try-power-role = "sink";
> +
> +			ports {
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +
> +				port at 0 {
> +					reg = <0>;
> +
> +					typec1_dr_sw: endpoint {
> +						remote-endpoint = <&usb1_drd_sw>;
> +					};
> +				};
> +			};
> +		};
> +	};
> +
> +	pcf2131: rtc at 53 {
> +		compatible = "nxp,pcf2131";
> +		reg = <0x53>;
> +		interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
> +		interrupt-parent = <&pcal6524>;
> +		status = "okay";
> +	};
> +};
> +
> +&lpuart1 {
> +	pinctrl-0 = <&pinctrl_uart1>;
> +	pinctrl-names = "default";
> +	status = "okay";
> +	bootph-pre-ram;
> +	bootph-some-ram;
> +};
> +
> +&lpuart5 {
> +	pinctrl-0 = <&pinctrl_uart5>;
> +	pinctrl-names = "default";
> +	status = "okay";
> +
> +	bluetooth {
> +		compatible = "nxp,88w8987-bt";
> +	};
> +};
> +
> +&mqs1 {
> +	clocks = <&clk IMX93_CLK_MQS1_GATE>;
> +	clock-names = "mclk";
> +	pinctrl-0 = <&pinctrl_mqs1>;
> +	pinctrl-names = "default";
> +	status = "okay";
> +};
> +
> +&osc_32k {
> +	bootph-all;
> +	bootph-pre-ram;
> +};
> +
> +&osc_24m {
> +	bootph-all;
> +	bootph-pre-ram;
> +};
> +
> +&sai1 {
> +	clocks = <&clk IMX93_CLK_SAI1_IPG>, <&clk IMX93_CLK_DUMMY>,
> +		 <&clk IMX93_CLK_SAI1_GATE>, <&clk IMX93_CLK_DUMMY>,
> +		 <&clk IMX93_CLK_DUMMY>, <&clk IMX93_CLK_AUDIO_PLL>;
> +	clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3", "pll8k";
> +	assigned-clocks = <&clk IMX93_CLK_SAI1>;
> +	assigned-clock-parents = <&clk IMX93_CLK_AUDIO_PLL>;
> +	assigned-clock-rates = <24576000>;
> +	#sound-dai-cells = <0>;
> +	fsl,sai-mclk-direction-output;
> +	status = "okay";
> +};
> +
> +&usbotg1 {
> +	adp-disable;
> +	disable-over-current;
> +	dr_mode = "otg";
> +	hnp-disable;
> +	srp-disable;
> +	usb-role-switch;
> +	samsung,picophy-dc-vol-level-adjust = <7>;
> +	samsung,picophy-pre-emp-curr-control = <3>;
> +	status = "okay";
> +
> +	port {
> +		usb1_drd_sw: endpoint {
> +			remote-endpoint = <&typec1_dr_sw>;
> +		};
> +	};
> +};
> +
> +&usbotg2 {
> +	disable-over-current;
> +	dr_mode = "host";
> +	samsung,picophy-dc-vol-level-adjust = <7>;
> +	samsung,picophy-pre-emp-curr-control = <3>;
> +	status = "okay";
> +};
> +
> +&usdhc1 {
> +	bus-width = <8>;
> +	non-removable;
> +	pinctrl-0 = <&pinctrl_usdhc1>;
> +	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
> +	pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
> +	pinctrl-names = "default", "state_100mhz", "state_200mhz";
> +	status = "okay";
> +	bootph-pre-ram;
> +	bootph-some-ram;
> +};
> +
> +&usdhc2 {
> +	bus-width = <4>;
> +	cd-gpios = <&gpio3 00 GPIO_ACTIVE_LOW>;
> +	no-mmc;
> +	no-sdio;
> +	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
> +	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
> +	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
> +	pinctrl-3 = <&pinctrl_usdhc2_sleep>, <&pinctrl_usdhc2_gpio_sleep>;
> +	pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
> +	vmmc-supply = <&reg_usdhc2_vmmc>;
> +	status = "okay";
> +	bootph-pre-ram;
> +	bootph-some-ram;
> +};
> +
> +&usdhc3 {
> +	bus-width = <4>;
> +	keep-power-in-suspend;
> +	mmc-pwrseq = <&usdhc3_pwrseq>;
> +	non-removable;
> +	pinctrl-0 = <&pinctrl_usdhc3>, <&pinctrl_usdhc3_wlan>;
> +	pinctrl-1 = <&pinctrl_usdhc3_100mhz>, <&pinctrl_usdhc3_wlan>;
> +	pinctrl-2 = <&pinctrl_usdhc3_200mhz>, <&pinctrl_usdhc3_wlan>;
> +	pinctrl-3 = <&pinctrl_usdhc3_sleep>, <&pinctrl_usdhc3_wlan>;
> +	pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
> +	vmmc-supply = <&reg_usdhc3_vmmc>;
> +	wakeup-source;
> +	status = "okay";
> +};
> +
> +&wdog3 {
> +	fsl,ext-reset-output;
> +	status = "okay";
> +};
> +
> +&iomuxc {
> +	bootph-pre-ram;
> +	bootph-some-ram;
> +	pinctrl_eqos: eqosgrp {
> +		fsl,pins = <
> +			MX91_PAD_ENET1_MDC__ENET1_MDC				0x57e
> +			MX91_PAD_ENET1_MDIO__ENET_QOS_MDIO			0x57e
> +			MX91_PAD_ENET1_RD0__ENET_QOS_RGMII_RD0			0x57e
> +			MX91_PAD_ENET1_RD1__ENET_QOS_RGMII_RD1			0x57e
> +			MX91_PAD_ENET1_RD2__ENET_QOS_RGMII_RD2			0x57e
> +			MX91_PAD_ENET1_RD3__ENET_QOS_RGMII_RD3			0x57e
> +			MX91_PAD_ENET1_RXC__ENET_QOS_RGMII_RXC			0x5fe
> +			MX91_PAD_ENET1_RX_CTL__ENET_QOS_RGMII_RX_CTL		0x57e
> +			MX91_PAD_ENET1_TD0__ENET_QOS_RGMII_TD0			0x57e
> +			MX91_PAD_ENET1_TD1__ENET1_RGMII_TD1			0x57e
> +			MX91_PAD_ENET1_TD2__ENET_QOS_RGMII_TD2			0x57e
> +			MX91_PAD_ENET1_TD3__ENET_QOS_RGMII_TD3			0x57e
> +			MX91_PAD_ENET1_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK	0x5fe
> +			MX91_PAD_ENET1_TX_CTL__ENET_QOS_RGMII_TX_CTL		0x57e
> +		>;
> +	};
> +
> +	pinctrl_eqos_sleep: eqossleepgrp {
> +		fsl,pins = <
> +			MX91_PAD_ENET1_MDC__GPIO4_IO0				0x31e
> +			MX91_PAD_ENET1_MDIO__GPIO4_IO1				0x31e
> +			MX91_PAD_ENET1_RD0__GPIO4_IO10				0x31e
> +			MX91_PAD_ENET1_RD1__GPIO4_IO11				0x31e
> +			MX91_PAD_ENET1_RD2__GPIO4_IO12				0x31e
> +			MX91_PAD_ENET1_RD3__GPIO4_IO13				0x31e
> +			MX91_PAD_ENET1_RXC__GPIO4_IO9				0x31e
> +			MX91_PAD_ENET1_RX_CTL__GPIO4_IO8			0x31e
> +			MX91_PAD_ENET1_TD0__GPIO4_IO5				0x31e
> +			MX91_PAD_ENET1_TD1__GPIO4_IO4				0x31e
> +			MX91_PAD_ENET1_TD2__GPIO4_IO3				0x31e
> +			MX91_PAD_ENET1_TD3__GPIO4_IO2				0x31e
> +			MX91_PAD_ENET1_TXC__GPIO4_IO7				0x31e
> +			MX91_PAD_ENET1_TX_CTL__GPIO4_IO6			0x31e
> +		>;
> +	};
> +
> +	pinctrl_fec: fecgrp {
> +		fsl,pins = <
> +			MX91_PAD_ENET2_MDC__ENET2_MDC				0x57e
> +			MX91_PAD_ENET2_MDIO__ENET2_MDIO				0x57e
> +			MX91_PAD_ENET2_RD0__ENET2_RGMII_RD0			0x57e
> +			MX91_PAD_ENET2_RD1__ENET2_RGMII_RD1			0x57e
> +			MX91_PAD_ENET2_RD2__ENET2_RGMII_RD2			0x57e
> +			MX91_PAD_ENET2_RD3__ENET2_RGMII_RD3			0x57e
> +			MX91_PAD_ENET2_RXC__ENET2_RGMII_RXC			0x5fe
> +			MX91_PAD_ENET2_RX_CTL__ENET2_RGMII_RX_CTL		0x57e
> +			MX91_PAD_ENET2_TD0__ENET2_RGMII_TD0			0x57e
> +			MX91_PAD_ENET2_TD1__ENET2_RGMII_TD1			0x57e
> +			MX91_PAD_ENET2_TD2__ENET2_RGMII_TD2			0x57e
> +			MX91_PAD_ENET2_TD3__ENET2_RGMII_TD3			0x57e
> +			MX91_PAD_ENET2_TXC__ENET2_RGMII_TXC			0x5fe
> +			MX91_PAD_ENET2_TX_CTL__ENET2_RGMII_TX_CTL		0x57e
> +		>;
> +	};
> +
> +	pinctrl_fec_sleep: fecsleepgrp {
> +		fsl,pins = <
> +			MX91_PAD_ENET2_MDC__GPIO4_IO14				0x51e
> +			MX91_PAD_ENET2_MDIO__GPIO4_IO15				0x51e
> +			MX91_PAD_ENET2_RD0__GPIO4_IO24				0x51e
> +			MX91_PAD_ENET2_RD1__GPIO4_IO25				0x51e
> +			MX91_PAD_ENET2_RD2__GPIO4_IO26				0x51e
> +			MX91_PAD_ENET2_RD3__GPIO4_IO27				0x51e
> +			MX91_PAD_ENET2_RXC__GPIO4_IO23				0x51e
> +			MX91_PAD_ENET2_RX_CTL__GPIO4_IO22			0x51e
> +			MX91_PAD_ENET2_TD0__GPIO4_IO19				0x51e
> +			MX91_PAD_ENET2_TD1__GPIO4_IO18				0x51e
> +			MX91_PAD_ENET2_TD2__GPIO4_IO17				0x51e
> +			MX91_PAD_ENET2_TD3__GPIO4_IO16				0x51e
> +			MX91_PAD_ENET2_TXC__GPIO4_IO21				0x51e
> +			MX91_PAD_ENET2_TX_CTL__GPIO4_IO20			0x51e
> +		>;
> +	};
> +
> +	pinctrl_flexcan2: flexcan2grp {
> +		fsl,pins = <
> +			MX91_PAD_GPIO_IO25__CAN2_TX				0x139e
> +			MX91_PAD_GPIO_IO27__CAN2_RX				0x139e
> +		>;
> +	};
> +
> +	pinctrl_flexcan2_sleep: flexcan2sleepgrp {
> +		fsl,pins = <
> +			MX91_PAD_GPIO_IO25__GPIO2_IO25				0x31e
> +			MX91_PAD_GPIO_IO27__GPIO2_IO27				0x31e
> +		>;
> +	};
> +
> +	pinctrl_lpi2c1: lpi2c1grp {
> +		fsl,pins = <
> +			MX91_PAD_I2C1_SCL__LPI2C1_SCL				0x40000b9e
> +			MX91_PAD_I2C1_SDA__LPI2C1_SDA				0x40000b9e
> +		>;
> +		bootph-pre-ram;
> +		bootph-some-ram;
> +	};
> +
> +	pinctrl_lpi2c2: lpi2c2grp {
> +		fsl,pins = <
> +			MX91_PAD_I2C2_SCL__LPI2C2_SCL				0x40000b9e
> +			MX91_PAD_I2C2_SDA__LPI2C2_SDA				0x40000b9e
> +		>;
> +		bootph-pre-ram;
> +		bootph-some-ram;
> +	};
> +
> +	pinctrl_lpi2c3: lpi2c3grp {
> +		fsl,pins = <
> +			MX91_PAD_GPIO_IO28__LPI2C3_SDA				0x40000b9e
> +			MX91_PAD_GPIO_IO29__LPI2C3_SCL				0x40000b9e
> +		>;
> +		bootph-pre-ram;
> +		bootph-some-ram;
> +	};
> +
> +	pinctrl_lpspi3: lpspi3grp {
> +		fsl,pins = <
> +			MX91_PAD_GPIO_IO08__GPIO2_IO8				0x3fe
> +			MX91_PAD_GPIO_IO09__LPSPI3_SIN				0x3fe
> +			MX91_PAD_GPIO_IO10__LPSPI3_SOUT				0x3fe
> +			MX91_PAD_GPIO_IO11__LPSPI3_SCK				0x3fe
> +		>;
> +	};
> +
> +	pinctrl_mqs1: mqs1grp {
> +		fsl,pins = <
> +			MX91_PAD_PDM_CLK__MQS1_LEFT				0x31e
> +			MX91_PAD_PDM_BIT_STREAM0__MQS1_RIGHT			0x31e
> +		>;
> +	};
> +
> +	pinctrl_pcal6524: pcal6524grp {
> +		fsl,pins = <
> +			MX91_PAD_CCM_CLKO2__GPIO3_IO27				0x31e
> +		>;
> +	};
> +
> +	pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
> +		fsl,pins = <
> +			MX91_PAD_SD2_RESET_B__GPIO3_IO7				0x31e
> +		>;
> +		bootph-pre-ram;
> +	};
> +
> +	pinctrl_uart1: uart1grp {
> +		fsl,pins = <
> +			MX91_PAD_UART1_RXD__LPUART1_RX				0x31e
> +			MX91_PAD_UART1_TXD__LPUART1_TX				0x31e
> +		>;
> +		bootph-pre-ram;
> +		bootph-some-ram;
> +	};
> +
> +	pinctrl_uart5: uart5grp {
> +		fsl,pins = <
> +			MX91_PAD_DAP_TDO_TRACESWO__LPUART5_TX			0x31e
> +			MX91_PAD_DAP_TDI__LPUART5_RX				0x31e
> +			MX91_PAD_DAP_TMS_SWDIO__LPUART5_RTS_B			0x31e
> +			MX91_PAD_DAP_TCLK_SWCLK__LPUART5_CTS_B			0x31e
> +		>;
> +	};
> +
> +	pinctrl_usdhc1: usdhc1grp {
> +		fsl,pins = <
> +			MX91_PAD_SD1_CLK__USDHC1_CLK				0x1582
> +			MX91_PAD_SD1_CMD__USDHC1_CMD				0x1382
> +			MX91_PAD_SD1_DATA0__USDHC1_DATA0			0x1382
> +			MX91_PAD_SD1_DATA1__USDHC1_DATA1			0x1382
> +			MX91_PAD_SD1_DATA2__USDHC1_DATA2			0x1382
> +			MX91_PAD_SD1_DATA3__USDHC1_DATA3			0x1382
> +			MX91_PAD_SD1_DATA4__USDHC1_DATA4			0x1382
> +			MX91_PAD_SD1_DATA5__USDHC1_DATA5			0x1382
> +			MX91_PAD_SD1_DATA6__USDHC1_DATA6			0x1382
> +			MX91_PAD_SD1_DATA7__USDHC1_DATA7			0x1382
> +			MX91_PAD_SD1_STROBE__USDHC1_STROBE			0x1582
> +		>;
> +		bootph-pre-ram;
> +		bootph-some-ram;
> +	};
> +
> +	pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp {
> +		fsl,pins = <
> +			MX91_PAD_SD1_CLK__USDHC1_CLK				0x158e
> +			MX91_PAD_SD1_CMD__USDHC1_CMD				0x138e
> +			MX91_PAD_SD1_DATA0__USDHC1_DATA0			0x138e
> +			MX91_PAD_SD1_DATA1__USDHC1_DATA1			0x138e
> +			MX91_PAD_SD1_DATA2__USDHC1_DATA2			0x138e
> +			MX91_PAD_SD1_DATA3__USDHC1_DATA3			0x138e
> +			MX91_PAD_SD1_DATA4__USDHC1_DATA4			0x138e
> +			MX91_PAD_SD1_DATA5__USDHC1_DATA5			0x138e
> +			MX91_PAD_SD1_DATA6__USDHC1_DATA6			0x138e
> +			MX91_PAD_SD1_DATA7__USDHC1_DATA7			0x138e
> +			MX91_PAD_SD1_STROBE__USDHC1_STROBE			0x158e
> +		>;
> +	};
> +
> +	pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp {
> +		fsl,pins = <
> +			MX91_PAD_SD1_CLK__USDHC1_CLK				0x15fe
> +			MX91_PAD_SD1_CMD__USDHC1_CMD				0x13fe
> +			MX91_PAD_SD1_DATA0__USDHC1_DATA0			0x13fe
> +			MX91_PAD_SD1_DATA1__USDHC1_DATA1			0x13fe
> +			MX91_PAD_SD1_DATA2__USDHC1_DATA2			0x13fe
> +			MX91_PAD_SD1_DATA3__USDHC1_DATA3			0x13fe
> +			MX91_PAD_SD1_DATA4__USDHC1_DATA4			0x13fe
> +			MX91_PAD_SD1_DATA5__USDHC1_DATA5			0x13fe
> +			MX91_PAD_SD1_DATA6__USDHC1_DATA6			0x13fe
> +			MX91_PAD_SD1_DATA7__USDHC1_DATA7			0x13fe
> +			MX91_PAD_SD1_STROBE__USDHC1_STROBE			0x15fe
> +		>;
> +	};
> +
> +	pinctrl_usdhc2_gpio: usdhc2gpiogrp {
> +		fsl,pins = <
> +			MX91_PAD_SD2_CD_B__GPIO3_IO0				0x31e
> +		>;
> +		bootph-pre-ram;
> +		bootph-some-ram;
> +	};
> +
> +	pinctrl_usdhc2_gpio_sleep: usdhc2gpiosleepgrp {
> +		fsl,pins = <
> +			MX91_PAD_SD2_CD_B__GPIO3_IO0				0x51e
> +		>;
> +	};
> +
> +	pinctrl_usdhc2: usdhc2grp {
> +		fsl,pins = <
> +			MX91_PAD_SD2_CLK__USDHC2_CLK				0x1582
> +			MX91_PAD_SD2_CMD__USDHC2_CMD				0x1382
> +			MX91_PAD_SD2_DATA0__USDHC2_DATA0			0x1382
> +			MX91_PAD_SD2_DATA1__USDHC2_DATA1			0x1382
> +			MX91_PAD_SD2_DATA2__USDHC2_DATA2			0x1382
> +			MX91_PAD_SD2_DATA3__USDHC2_DATA3			0x1382
> +			MX91_PAD_SD2_VSELECT__USDHC2_VSELECT			0x51e
> +		>;
> +		bootph-pre-ram;
> +		bootph-some-ram;
> +	};
> +
> +	pinctrl_usdhc2_sleep: usdhc2sleepgrp {
> +		fsl,pins = <
> +			MX91_PAD_SD2_CLK__GPIO3_IO1				0x51e
> +			MX91_PAD_SD2_CMD__GPIO3_IO2				0x51e
> +			MX91_PAD_SD2_DATA0__GPIO3_IO3				0x51e
> +			MX91_PAD_SD2_DATA1__GPIO3_IO4				0x51e
> +			MX91_PAD_SD2_DATA2__GPIO3_IO5				0x51e
> +			MX91_PAD_SD2_DATA3__GPIO3_IO6				0x51e
> +			MX91_PAD_SD2_VSELECT__GPIO3_IO19			0x51e
> +		>;
> +	};
> +
> +	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
> +		fsl,pins = <
> +			MX91_PAD_SD2_CLK__USDHC2_CLK				0x158e
> +			MX91_PAD_SD2_CMD__USDHC2_CMD				0x138e
> +			MX91_PAD_SD2_DATA0__USDHC2_DATA0			0x138e
> +			MX91_PAD_SD2_DATA1__USDHC2_DATA1			0x138e
> +			MX91_PAD_SD2_DATA2__USDHC2_DATA2			0x138e
> +			MX91_PAD_SD2_DATA3__USDHC2_DATA3			0x138e
> +			MX91_PAD_SD2_VSELECT__USDHC2_VSELECT			0x51e
> +		>;
> +	};
> +
> +	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
> +		fsl,pins = <
> +			MX91_PAD_SD2_CLK__USDHC2_CLK				0x15fe
> +			MX91_PAD_SD2_CMD__USDHC2_CMD				0x13fe
> +			MX91_PAD_SD2_DATA0__USDHC2_DATA0			0x13fe
> +			MX91_PAD_SD2_DATA1__USDHC2_DATA1			0x13fe
> +			MX91_PAD_SD2_DATA2__USDHC2_DATA2			0x13fe
> +			MX91_PAD_SD2_DATA3__USDHC2_DATA3			0x13fe
> +			MX91_PAD_SD2_VSELECT__USDHC2_VSELECT			0x51e
> +		>;
> +	};
> +
> +	pinctrl_usdhc3: usdhc3grp {
> +		fsl,pins = <
> +			MX91_PAD_SD3_CLK__USDHC3_CLK				0x1582
> +			MX91_PAD_SD3_CMD__USDHC3_CMD				0x1382
> +			MX91_PAD_SD3_DATA0__USDHC3_DATA0			0x1382
> +			MX91_PAD_SD3_DATA1__USDHC3_DATA1			0x1382
> +			MX91_PAD_SD3_DATA2__USDHC3_DATA2			0x1382
> +			MX91_PAD_SD3_DATA3__USDHC3_DATA3			0x1382
> +		>;
> +	};
> +
> +	pinctrl_usdhc3_sleep: usdhc3sleepgrp {
> +		fsl,pins = <
> +			MX91_PAD_SD3_CLK__GPIO3_IO20				0x31e
> +			MX91_PAD_SD3_CMD__GPIO3_IO21				0x31e
> +			MX91_PAD_SD3_DATA0__GPIO3_IO22				0x31e
> +			MX91_PAD_SD3_DATA1__GPIO3_IO23				0x31e
> +			MX91_PAD_SD3_DATA2__GPIO3_IO24				0x31e
> +			MX91_PAD_SD3_DATA3__GPIO3_IO25				0x31e
> +		>;
> +	};
> +
> +	pinctrl_usdhc3_wlan: usdhc3wlangrp {
> +		fsl,pins = <
> +			MX91_PAD_CCM_CLKO1__GPIO3_IO26				0x31e
> +		>;
> +	};
> +
> +	pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp {
> +		fsl,pins = <
> +			MX91_PAD_SD3_CLK__USDHC3_CLK				0x158e
> +			MX91_PAD_SD3_CMD__USDHC3_CMD				0x138e
> +			MX91_PAD_SD3_DATA0__USDHC3_DATA0			0x138e
> +			MX91_PAD_SD3_DATA1__USDHC3_DATA1			0x138e
> +			MX91_PAD_SD3_DATA2__USDHC3_DATA2			0x138e
> +			MX91_PAD_SD3_DATA3__USDHC3_DATA3			0x138e
> +		>;
> +	};
> +
> +	pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp {
> +		fsl,pins = <
> +			MX91_PAD_SD3_CLK__USDHC3_CLK				0x15fe
> +			MX91_PAD_SD3_CMD__USDHC3_CMD				0x13fe
> +			MX91_PAD_SD3_DATA0__USDHC3_DATA0			0x13fe
> +			MX91_PAD_SD3_DATA1__USDHC3_DATA1			0x13fe
> +			MX91_PAD_SD3_DATA2__USDHC3_DATA2			0x13fe
> +			MX91_PAD_SD3_DATA3__USDHC3_DATA3			0x13fe
> +		>;
> +	};
> +};
> 
> -- 
> 2.34.1
> 


From matthew.schwartz at linux.dev  Mon Dec 29 20:21:48 2025
From: matthew.schwartz at linux.dev (Matthew Schwartz)
Date: Mon, 29 Dec 2025 20:21:48 -0800
Subject: Linux 6.19-rc1 mediatek mt7921e broke badly
In-Reply-To: <CAHk-=wjO-7uR5HBi-MFnkxAxjhpgfbAQ+HCMKPiXFVwM+AJ7tA@mail.gmail.com>
References: <d7f3b00d-beec-41f0-b157-7cfb871f9a46@linuxfoundation.org>
 <756e3f65-b2f2-4da3-985a-17754a7a872d@t-8ch.de>
 <CAHk-=wjO-7uR5HBi-MFnkxAxjhpgfbAQ+HCMKPiXFVwM+AJ7tA@mail.gmail.com>
Message-ID: <6fc04df5-b753-4b2d-b978-0e59a7f48ff7@linux.dev>

On 12/29/25 4:41 PM, Linus Torvalds wrote:
> On Sat, 27 Dec 2025 at 04:25, Thomas Wei?schuh <linux at weissschuh.net> wrote:
>>
>> Hi Shuah,
>>
>> On 2025-12-27 02:07:24-0700, Shuah Khan wrote:
>>> mt7921e doesn't load on my primary laptopn on Linux 6.19-rc1 and problem
>>> still there on 6.19-rc2.
>>
>> This should be a duplicate of
>> https://lore.kernel.org/all/CABXGCsMeAZyNJ-Axt_CUCXgyieWPV3rrcLpWsveMPT8R0YPGnQ at mail.gmail.com/
> 
> Hmm. I wonder if we could instead do this:
> 
>   --- a/lib/string.c
>   +++ b/lib/string.c
>   @@ -113,7 +113,7 @@ EXPORT_SYMBOL(strncpy);
>    ssize_t sized_strscpy(char *dest, const char *src, size_t count)
>    {
>           const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
>   -       size_t max = count;
>   +       size_t max = count - 1;
>           long res = 0;
> 
>           if (count == 0 || WARN_ON_ONCE(count > INT_MAX))
> 
> (intentionally whitespace-damaged patch, because I want people to
> think about it).

I gave this a try on its own but I was still experiencing a kernel crash:

[    3.339408] strnlen: detected buffer overflow: 17 byte read of buffer size 16
[    3.339804] WARNING: lib/string_helpers.c:1035 at __fortify_report+0x41/0x50, CPU#14: kworker/14:0/105
[    3.352248]  __fortify_panic+0xd/0xf
[    3.352259]  mt76_connac2_load_patch.cold+0x2b/0x95a [mt76_connac_lib 8f0d0f7b30f881af23462dac0a8cc5ff88d08cd0]

However, applying a similar diff in the fortify wrapper does prevent the crash:

--- a/include/linux/fortify-string.h
+++ b/include/linux/fortify-string.h
@@ -306,13 +306,13 @@ __FORTIFY_INLINE ssize_t sized_strscpy(char * const POS p, const char * const PO
      * This call protects from read overflow, because len will default to q
      * length if it smaller than size.
      */
-    len = strnlen(q, size);
+    len = strnlen(q, size - 1);
     /*
      * If len equals size, we will copy only size bytes which leads to
      * -E2BIG being returned.
      * Otherwise we will copy len + 1 because of the final '\O'.
      */
-    len = len == size ? size : len + 1;
+    len = len == size - 1 ? size : len + 1;
 
     /*
      * Generate a runtime write overflow error if len is greater than

Not sure what the implications of such a change would be relative to the proposed
fix here: https://lore.kernel.org/all/20251205161202.48409-1-mikhail.v.gavrilov at gmail.com/

Matt

> 
> It basically says that if the size of the 'strscpy()' buffer is N,
> then we do the "word-at-a-time" only up to 'N-1' bytes, because we
> don't even need to read the last byte of the source, because we will
> always NUL-terminate the destination...
> 
> That would basically make it ok to use a destination that is one byte
> larger than the source (in order to fit NUL termination that doesn't
> exist in the source).
> 
> The downside, of course, is that it means that we possibly miss out of
> doing the last word of the copy a word-at-a-time. But possibly not a
> big downside, and it would make strscpy() able to deal with this case
> natively.
> 
> The *real* issue is that we don't have a "source is this big,
> destination is that big" version of string copy.
> 
> Normally that is a non-issue - just pick the smaller size of the two.
> Except for this particular case, where the destination is exactly one
> byte larger, and wants to be NUL-terminated while the source might not
> be.
> 
> I haven't really thought this through fully, which is why that patch
> is very much whitespace-damaged. Somebody else should verify my
> thinking.
> 
>                    Linus
> 



From daeinki at gmail.com  Mon Dec 29 21:47:59 2025
From: daeinki at gmail.com (Inki Dae)
Date: Tue, 30 Dec 2025 14:47:59 +0900
Subject: [PATCH] drm/exynos: hdmi: replace use of system_wq with system_percpu_wq
In-Reply-To: <CAAofZF4OJi5eEfjhE12RWi6wDU+A9Rghsd2721SxZR4AC08sYg@mail.gmail.com>
References: <20251104112923.143408-1-marco.crivellari@suse.com> <CAAofZF4OJi5eEfjhE12RWi6wDU+A9Rghsd2721SxZR4AC08sYg@mail.gmail.com>
Message-ID: <CAAQKjZPVi1KHuS4p6G2uAeKMAg=PEbECj7DHW7OYNYLG-S9hmQ@mail.gmail.com>

Hi,

Sorry for late reply. Merged.

Thanks,
Inki Dae

2025? 12? 25? (?) AM 12:01, Marco Crivellari <marco.crivellari at suse.com>?? ??:
>
> On Tue, Nov 4, 2025 at 12:29?PM Marco Crivellari
> <marco.crivellari at suse.com> wrote:
> > [...]
> > ---
> >  drivers/gpu/drm/exynos/exynos_hdmi.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
>
> Gentle ping.
>
> Thanks!
>
> --
>
> Marco Crivellari
>
> L3 Support Engineer
>


From rdunlap at infradead.org  Mon Dec 29 21:52:30 2025
From: rdunlap at infradead.org (Randy Dunlap)
Date: Mon, 29 Dec 2025 21:52:30 -0800
Subject: [PATCH] ARM: omap1: drop unused Kconfig symbol
Message-ID: <20251230055230.3212260-1-rdunlap@infradead.org>

"select ARCH_HAS_HOLES_MEMORYMODEL" was mistakenly merged here
due to a botched rebase (says Arnd [1]).

Drop that line since that symbol is not used anywhere else in the
kernel source tree.

[1] https://lore.kernel.org/all/5e335232-89b4-4c35-93bd-efad7e4d8995 at app.fastmail.com/
Fixes: 7036440eab3e ("ARM: omap1: enable multiplatform")
Signed-off-by: Randy Dunlap <rdunlap at infradead.org>
---
KernelVersion: 6.19-rc1

Cc: Arnd Bergmann <arnd at arndb.de>
Cc: patches at armlinux.org.uk
Cc: Aaro Koskinen <aaro.koskinen at iki.fi>
Cc: Janusz Krzysztofik <jmkrzyszt at gmail.com>
Cc: Tony Lindgren <tony at atomide.com>
Cc: linux-omap at vger.kernel.org
Cc: Russell King <linux at armlinux.org.uk>

 arch/arm/mach-omap1/Kconfig |    1 -
 1 file changed, 1 deletion(-)

--- linux-next-20251219.orig/arch/arm/mach-omap1/Kconfig
+++ linux-next-20251219/arch/arm/mach-omap1/Kconfig
@@ -4,7 +4,6 @@ menuconfig ARCH_OMAP1
 	depends on ARCH_MULTI_V4T || ARCH_MULTI_V5
 	depends on CPU_LITTLE_ENDIAN
 	depends on ATAGS
-	select ARCH_HAS_HOLES_MEMORYMODEL
 	select ARCH_OMAP
 	select CLKSRC_MMIO
 	select FORCE_PCI if PCCARD


From jacky_chou at aspeedtech.com  Mon Dec 29 21:57:57 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Tue, 30 Dec 2025 13:57:57 +0800
Subject: [PATCH v8 0/4] Add ASPEED PCIe PHY support
Message-ID: <20251230-upstream_pcie_rc-v8-0-03598cdd80cd@aspeedtech.com>

This patch series adds support for the ASPEED PCIe PHY,
including device tree bindings and PCIe PHY driver. 
The patches introduce the necessary device tree nodes.

Summary of changes:
- Add device tree binding documents for ASPEED PCIe PHY
- Update MAINTAINERS for new bindings and driver
- Implement ASPEED PCIe PHY driver

This series has been tested on AST2600/AST2700 platforms and enables PCIe device
enumeration and operation.

Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
---
Changes in v8:
- Update the title of cover letter
- Remove 'default y' from Kconfig
- Change 'PHY:' to 'phy:' in the title of ASPEED PCIe PHY commit.
- Remove unnecessary headers from phy-aspeed-pcie.c.
- Add ASPEED PCIe PHY MAINTAINERS
- Remove applied patches
  [v7,2/7] dt-bindings: PCI: Add ASPEED PCIe RC support
  [v7,5/7] PCI: Add FMT, TYPE and CPL status definition for TLP header
  [v7,6/7] PCI: aspeed: Add ASPEED PCIe RC driver
  [v7,7/7] MAINTAINERS: Add ASPEED PCIe RC driver
- Link to v7: https://lore.kernel.org/r/20251216-upstream_pcie_rc-v7-0-4aeb0f53c4ce at aspeedtech.com

Changes in v7:
- Add PCIe port into aspeed,ast2600-pci.yaml.
- Remove aspeed_pcie_init_ports() and merge aspeed_pcie_port_init() to
  aspeed_pcie_parse_port()
- Refactor aspeed remap pcie addr to aspeed_pcie_map_ranges()
- Link to v6: https://lore.kernel.org/r/20251201-upstream_pcie_rc-v6-0-8c8800c56b16 at aspeedtech.com

Changes in v6:
- Refer to pci-cpi-bridge.yaml to update aspeed,ast2600-pcie.yaml and
  the pcie node of aspeed-g6.dtsi.
- 'dt-bindings: pinctrl: aspeed,ast2600-pinctrl: Add PCIe RC PERST#
  group' have applied, remove it from this version.
- Adjust the defnitions in pci.h. 
- Link to v5: https://lore.kernel.org/r/20251117-upstream_pcie_rc-v5-0-b4a198576acf at aspeedtech.com

Changes in v5:
- Remove legacy-interrupt-controller and the INTx points to pcie node itself.
- Correct bar mapping description and implementation to PCIe address
  configuration in pcie-aspeed.c driver.
- Link to v4: https://lore.kernel.org/r/20251027095825.181161-1-jacky_chou at aspeedtech.com/

Changes in v4:
- Remove aspeed,ast2700-pcie-cfg.yaml
- Add more descriptions for AST2600 PCIe RC in aspeed,ast2600-pcie.yaml
- Change interrupt-controller to legacy-interrupt-controller in yaml
  and dtsi
- Remove msi-parent property in yaml and dtsi
- Modify the bus range to starting from 0x00 in aspeed-g6.dtsi
- Fixed the typo on MODULE_DEVICE_TABLE() in phy-aspeed-pcie.c
- Add PCIE_CPL_STS_SUCCESS definition in pci/pci.h
- Add prefix ASPEED_ for register definition in RC driver
- Add a flag to indicate clear msi status twice for AST2700 workaround
- Remove getting domain number
- Remove scanning AST2600 HOST bridge on device number 0
- Remove all codes about CONFIG_PCI_MSI
- Get root but number from resouce list by IORESOURCE_BUS
- Change module_platform_driver to builtin_platform_driver
- Link to v3: https://lore.kernel.org/r/20250901055922.1553550-1-jacky_chou at aspeedtech.com/

Changes in v3:
- Add ASPEED PCIe PHY driver
- Remove the aspeed,pciecfg property from AST2600 RC node, merged into RC node
- Update the binding doc for aspeed,ast2700-pcie-cfg to reflect the changes
- Update the binding doc for aspeed,ast2600-pcie to reflect the changes
- Update the binding doc for aspeed,ast2600-pinctrl to reflect the changes
- Update the device tree source to reflect the changes
- Adjusted the use of mutex in RC drivers to use GRAND
- Updated from reviewer comments
- Link to v2: https://lore.kernel.org/r/20250715034320.2553837-1-jacky_chou at aspeedtech.com/

Changes in v2:
- Moved ASPEED PCIe PHY yaml binding to `soc/aspeed` directory and
  changed it as syscon
- Added `MAINTAINERS` entry for the new PCIe RC driver
- Updated device tree bindings to reflect the new structure
- Refactored configuration read and write functions to main bus and
  child bus ops
- Refactored initialization to implement multiple ports support
- Added PCIe FMT and TYPE definitions for TLP header in
  `include/uapi/linux/pci_regs.h`
- Updated from reviewer comments
- Link to v1: https://lore.kernel.org/r/20250613033001.3153637-1-jacky_chou at aspeedtech.com/

---
Jacky Chou (4):
      dt-bindings: phy: aspeed: Add ASPEED PCIe PHY
      ARM: dts: aspeed-g6: Add PCIe RC and PCIe PHY node
      phy: aspeed: Add ASPEED PCIe PHY driver
      MAINTAINERS: Add ASPEED PCIe PHY driver

 .../bindings/phy/aspeed,ast2600-pcie-phy.yaml      |  42 +++++
 MAINTAINERS                                        |   8 +
 arch/arm/boot/dts/aspeed/aspeed-g6-pinctrl.dtsi    |   5 +
 arch/arm/boot/dts/aspeed/aspeed-g6.dtsi            |  53 ++++++
 drivers/phy/Kconfig                                |   1 +
 drivers/phy/Makefile                               |   1 +
 drivers/phy/aspeed/Kconfig                         |  14 ++
 drivers/phy/aspeed/Makefile                        |   2 +
 drivers/phy/aspeed/phy-aspeed-pcie.c               | 194 +++++++++++++++++++++
 9 files changed, 320 insertions(+)
---
base-commit: 8640b74557fc8b4c300030f6ccb8cd078f665ec8
change-id: 20251103-upstream_pcie_rc-8445759db813

Best regards,
-- 
Jacky Chou <jacky_chou at aspeedtech.com>



From jacky_chou at aspeedtech.com  Mon Dec 29 21:57:58 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Tue, 30 Dec 2025 13:57:58 +0800
Subject: [PATCH v8 1/4] dt-bindings: phy: aspeed: Add ASPEED PCIe PHY
In-Reply-To: <20251230-upstream_pcie_rc-v8-0-03598cdd80cd@aspeedtech.com>
References: <20251230-upstream_pcie_rc-v8-0-03598cdd80cd@aspeedtech.com>
Message-ID: <20251230-upstream_pcie_rc-v8-1-03598cdd80cd@aspeedtech.com>

Introduce device-binding for ASPEED AST2600/2700 PCIe PHY.
The PCIe PHY is used for PCIe RC to configure as RC mode.

Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
---
 .../bindings/phy/aspeed,ast2600-pcie-phy.yaml      | 42 ++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/Documentation/devicetree/bindings/phy/aspeed,ast2600-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/aspeed,ast2600-pcie-phy.yaml
new file mode 100644
index 000000000000..71a5cd91fb3f
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/aspeed,ast2600-pcie-phy.yaml
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/aspeed,ast2600-pcie-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ASPEED PCIe PHY
+
+maintainers:
+  - Jacky Chou <jacky_chou at aspeedtech.com>
+
+description:
+  The ASPEED PCIe PHY provides the physical layer functionality for PCIe
+  controllers in the SoC.
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - aspeed,ast2600-pcie-phy
+          - aspeed,ast2700-pcie-phy
+
+  reg:
+    maxItems: 1
+
+  "#phy-cells":
+    const: 0
+
+required:
+  - compatible
+  - reg
+  - "#phy-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    phy at 1e6ed200 {
+      compatible = "aspeed,ast2600-pcie-phy";
+      reg = <0x1e6ed200 0x100>;
+      #phy-cells = <0>;
+    };

-- 
2.34.1



From jacky_chou at aspeedtech.com  Mon Dec 29 21:57:59 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Tue, 30 Dec 2025 13:57:59 +0800
Subject: [PATCH v8 2/4] ARM: dts: aspeed-g6: Add PCIe RC and PCIe PHY node
In-Reply-To: <20251230-upstream_pcie_rc-v8-0-03598cdd80cd@aspeedtech.com>
References: <20251230-upstream_pcie_rc-v8-0-03598cdd80cd@aspeedtech.com>
Message-ID: <20251230-upstream_pcie_rc-v8-2-03598cdd80cd@aspeedtech.com>

The AST2600 has one PCIe RC and add the PCIe PHY for RC.
And add pinctrl support for PCIe RC PERST#.

Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
---
 arch/arm/boot/dts/aspeed/aspeed-g6-pinctrl.dtsi |  5 +++
 arch/arm/boot/dts/aspeed/aspeed-g6.dtsi         | 53 +++++++++++++++++++++++++
 2 files changed, 58 insertions(+)

diff --git a/arch/arm/boot/dts/aspeed/aspeed-g6-pinctrl.dtsi b/arch/arm/boot/dts/aspeed/aspeed-g6-pinctrl.dtsi
index e87c4b58994a..d46f2047135c 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-g6-pinctrl.dtsi
+++ b/arch/arm/boot/dts/aspeed/aspeed-g6-pinctrl.dtsi
@@ -2,6 +2,11 @@
 // Copyright 2019 IBM Corp.
 
 &pinctrl {
+	pinctrl_pcierc1_default: pcierc1-default {
+		function = "PCIERC1";
+		groups = "PCIERC1";
+	};
+
 	pinctrl_adc0_default: adc0_default {
 		function = "ADC0";
 		groups = "ADC0";
diff --git a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
index f8662c8ac089..dde8f87db2e3 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
+++ b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
@@ -379,6 +379,59 @@ rng: hwrng at 1e6e2524 {
 				quality = <100>;
 			};
 
+			pcie_phy1: phy at 1e6ed200 {
+				compatible = "aspeed,ast2600-pcie-phy";
+				reg = <0x1e6ed200 0x100>;
+				#phy-cells = <0>;
+
+				status = "disabled";
+			};
+
+			pcie0: pcie at 1e770000 {
+				compatible = "aspeed,ast2600-pcie";
+				device_type = "pci";
+				reg = <0x1e770000 0x100>;
+				#address-cells = <3>;
+				#size-cells = <2>;
+				interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+				bus-range = <0x00 0xff>;
+
+				ranges = <0x01000000 0x0 0x00018000 0x00018000 0x0 0x00008000
+					  0x02000000 0x0 0x60000000 0x60000000 0x0 0x20000000>;
+
+				status = "disabled";
+
+				resets = <&syscon ASPEED_RESET_H2X>;
+				reset-names = "h2x";
+
+				#interrupt-cells = <1>;
+				msi-controller;
+
+				aspeed,ahbc = <&ahbc>;
+
+				interrupt-controller;
+				interrupt-map-mask = <0 0 0 7>;
+				interrupt-map = <0 0 0 1 &pcie0 0>,
+						<0 0 0 2 &pcie0 1>,
+						<0 0 0 3 &pcie0 2>,
+						<0 0 0 4 &pcie0 3>;
+
+				pcie at 8,0 {
+					compatible = "pciclass,0604";
+					reg = <0x00004000 0 0 0 0>;
+					#address-cells = <3>;
+					#size-cells = <2>;
+					device_type = "pci";
+					resets = <&syscon ASPEED_RESET_PCIE_RC_O>;
+					reset-names = "perst";
+					clocks = <&syscon ASPEED_CLK_GATE_BCLK>;
+					pinctrl-names = "default";
+					pinctrl-0 = <&pinctrl_pcierc1_default>;
+					phys = <&pcie_phy1>;
+					ranges;
+				};
+			};
+
 			gfx: display at 1e6e6000 {
 				compatible = "aspeed,ast2600-gfx", "syscon";
 				reg = <0x1e6e6000 0x1000>;

-- 
2.34.1



From jacky_chou at aspeedtech.com  Mon Dec 29 21:58:01 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Tue, 30 Dec 2025 13:58:01 +0800
Subject: [PATCH v8 4/4] MAINTAINERS: Add ASPEED PCIe PHY driver
In-Reply-To: <20251230-upstream_pcie_rc-v8-0-03598cdd80cd@aspeedtech.com>
References: <20251230-upstream_pcie_rc-v8-0-03598cdd80cd@aspeedtech.com>
Message-ID: <20251230-upstream_pcie_rc-v8-4-03598cdd80cd@aspeedtech.com>

Add maintainer entry for ASPEED PCIe PHY driver.

Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
---
 MAINTAINERS | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 765ad2daa218..bcb94fe3faa6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3843,6 +3843,14 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/crypto/aspeed,*
 F:	drivers/crypto/aspeed/
 
+ASPEED PCIE PHY DRIVER
+M:	Jacky Chou <jacky_chou at aspeedtech.com>
+L:	linux-aspeed at lists.ozlabs.org (moderated for non-subscribers)
+L:	linux-phy at lists.infradead.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/phy/aspeed,ast2600-pcie-phy.yaml
+F:	drivers/phy/aspeed/pcie-phy-aspeed.c
+
 ASPEED PECI CONTROLLER
 M:	Iwona Winiarska <iwona.winiarska at intel.com>
 L:	linux-aspeed at lists.ozlabs.org (moderated for non-subscribers)

-- 
2.34.1



From jacky_chou at aspeedtech.com  Mon Dec 29 21:58:00 2025
From: jacky_chou at aspeedtech.com (Jacky Chou)
Date: Tue, 30 Dec 2025 13:58:00 +0800
Subject: [PATCH v8 3/4] phy: aspeed: Add ASPEED PCIe PHY driver
In-Reply-To: <20251230-upstream_pcie_rc-v8-0-03598cdd80cd@aspeedtech.com>
References: <20251230-upstream_pcie_rc-v8-0-03598cdd80cd@aspeedtech.com>
Message-ID: <20251230-upstream_pcie_rc-v8-3-03598cdd80cd@aspeedtech.com>

Introduce support for Aspeed PCIe PHY controller available in
AST2600/2700.

Signed-off-by: Jacky Chou <jacky_chou at aspeedtech.com>
---
 drivers/phy/Kconfig                  |   1 +
 drivers/phy/Makefile                 |   1 +
 drivers/phy/aspeed/Kconfig           |  14 +++
 drivers/phy/aspeed/Makefile          |   2 +
 drivers/phy/aspeed/phy-aspeed-pcie.c | 194 +++++++++++++++++++++++++++++++++++
 5 files changed, 212 insertions(+)

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 678dd0452f0a..f6a8f06fd244 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -103,6 +103,7 @@ config PHY_NXP_PTN3222
 
 source "drivers/phy/allwinner/Kconfig"
 source "drivers/phy/amlogic/Kconfig"
+source "drivers/phy/aspeed/Kconfig"
 source "drivers/phy/broadcom/Kconfig"
 source "drivers/phy/cadence/Kconfig"
 source "drivers/phy/freescale/Kconfig"
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index bfb27fb5a494..18990c87dfb0 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_PHY_AIROHA_PCIE)		+= phy-airoha-pcie.o
 obj-$(CONFIG_PHY_NXP_PTN3222)		+= phy-nxp-ptn3222.o
 obj-y					+= allwinner/	\
 					   amlogic/	\
+					   aspeed/	\
 					   broadcom/	\
 					   cadence/	\
 					   freescale/	\
diff --git a/drivers/phy/aspeed/Kconfig b/drivers/phy/aspeed/Kconfig
new file mode 100644
index 000000000000..f7aad553f3fd
--- /dev/null
+++ b/drivers/phy/aspeed/Kconfig
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Phy drivers for Aspeed platforms
+#
+config PHY_ASPEED_PCIE
+	tristate "ASPEED PCIe PHY driver"
+	select GENERIC_PHY
+	depends on ARCH_ASPEED
+	help
+	  This option enables support for the ASPEED PCIe PHY driver.
+	  The driver provides the necessary interface to control and
+	  configure the PCIe PHY hardware found on ASPEED SoCs.
+	  It is required for proper operation of PCIe devices on
+	  platforms using ASPEED chips.
diff --git a/drivers/phy/aspeed/Makefile b/drivers/phy/aspeed/Makefile
new file mode 100644
index 000000000000..3edce7f522e1
--- /dev/null
+++ b/drivers/phy/aspeed/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_PHY_ASPEED_PCIE)		+= phy-aspeed-pcie.o
diff --git a/drivers/phy/aspeed/phy-aspeed-pcie.c b/drivers/phy/aspeed/phy-aspeed-pcie.c
new file mode 100644
index 000000000000..a3a696df459e
--- /dev/null
+++ b/drivers/phy/aspeed/phy-aspeed-pcie.c
@@ -0,0 +1,194 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 Aspeed Technology Inc.
+ */
+
+#include <linux/phy/pcie.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+
+/* AST2600 PCIe Host Controller Registers */
+#define PEHR_GLOBAL		0x30
+#define  AST2600_PORT_TYPE_MASK		GENMASK(5, 4)
+#define  AST2600_PORT_TYPE(x)		FIELD_PREP(AST2600_PORT_TYPE_MASK, x)
+#define PEHR_LOCK		0x7c
+#define  PCIE_UNLOCK			0xa8
+
+/* AST2700 PEHR */
+#define PEHR_MISC_58		0x58
+#define  LOCAL_SCALE_SUP		BIT(0)
+#define PEHR_MISC_5C		0x5c
+#define  CONFIG_RC_DEVICE		BIT(30)
+#define PEHR_MISC_60		0x60
+#define  AST2700_PORT_TYPE_MASK		GENMASK(7, 4)
+#define  PORT_TYPE_ROOT			BIT(6)
+#define PEHR_MISC_70		0x70
+#define  POSTED_DATA_CREDITS(x)		FIELD_PREP(GENMASK(15, 0), x)
+#define  POSTED_HEADER_CREDITS(x)	FIELD_PREP(GENMASK(27, 16), x)
+#define PEHR_MISC_78		0x78
+#define  COMPLETION_DATA_CREDITS(x)	FIELD_PREP(GENMASK(15, 0), x)
+#define  COMPLETION_HEADER_CREDITS(x)	FIELD_PREP(GENMASK(27, 16), x)
+
+/**
+ * struct aspeed_pcie_phy - PCIe PHY information
+ * @dev: pointer to device structure
+ * @reg: PCIe host register base address
+ * @phy: pointer to PHY structure
+ * @platform: platform specific information
+ */
+struct aspeed_pcie_phy {
+	struct device *dev;
+	void __iomem *reg;
+	struct phy *phy;
+	const struct aspeed_pcie_phy_platform *platform;
+};
+
+/**
+ * struct aspeed_pcie_phy_platform - Platform information
+ * @phy_ops: phy operations
+ */
+struct aspeed_pcie_phy_platform {
+	const struct phy_ops *phy_ops;
+};
+
+static int ast2600_phy_init(struct phy *phy)
+{
+	struct aspeed_pcie_phy *pcie_phy = phy_get_drvdata(phy);
+
+	writel(PCIE_UNLOCK, pcie_phy->reg + PEHR_LOCK);
+
+	return 0;
+}
+
+static int ast2600_phy_set_mode(struct phy *phy, enum phy_mode mode,
+				int submode)
+{
+	struct aspeed_pcie_phy *pcie_phy = phy_get_drvdata(phy);
+
+	switch (submode) {
+	case PHY_MODE_PCIE_RC:
+		writel(AST2600_PORT_TYPE(0x3), pcie_phy->reg + PEHR_GLOBAL);
+		break;
+	default:
+		dev_err(&phy->dev, "Unsupported submode %d\n", submode);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct phy_ops ast2600_phy_ops = {
+	.init		= ast2600_phy_init,
+	.set_mode	= ast2600_phy_set_mode,
+	.owner		= THIS_MODULE,
+};
+
+static int ast2700_phy_init(struct phy *phy)
+{
+	struct aspeed_pcie_phy *pcie_phy = phy_get_drvdata(phy);
+
+	writel(POSTED_DATA_CREDITS(0xc0) | POSTED_HEADER_CREDITS(0xa),
+	       pcie_phy->reg + PEHR_MISC_70);
+	writel(COMPLETION_DATA_CREDITS(0x30) | COMPLETION_HEADER_CREDITS(0x8),
+	       pcie_phy->reg + PEHR_MISC_78);
+	writel(LOCAL_SCALE_SUP, pcie_phy->reg + PEHR_MISC_58);
+
+	return 0;
+}
+
+static int ast2700_phy_set_mode(struct phy *phy, enum phy_mode mode,
+				int submode)
+{
+	struct aspeed_pcie_phy *pcie_phy = phy_get_drvdata(phy);
+	u32 cfg_val;
+
+	switch (submode) {
+	case PHY_MODE_PCIE_RC:
+		writel(CONFIG_RC_DEVICE, pcie_phy->reg + PEHR_MISC_5C);
+		cfg_val = readl(pcie_phy->reg + PEHR_MISC_60);
+		cfg_val &= ~AST2700_PORT_TYPE_MASK;
+		cfg_val |= PORT_TYPE_ROOT;
+		writel(cfg_val, pcie_phy->reg + PEHR_MISC_60);
+		break;
+	default:
+		dev_err(&phy->dev, "Unsupported submode %d\n", submode);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct phy_ops ast2700_phy_ops = {
+	.init		= ast2700_phy_init,
+	.set_mode	= ast2700_phy_set_mode,
+	.owner		= THIS_MODULE,
+};
+
+const struct aspeed_pcie_phy_platform pcie_phy_ast2600 = {
+	.phy_ops = &ast2600_phy_ops,
+};
+
+const struct aspeed_pcie_phy_platform pcie_phy_ast2700 = {
+	.phy_ops = &ast2700_phy_ops,
+};
+
+static int aspeed_pcie_phy_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct phy_provider *phy_provider;
+	struct aspeed_pcie_phy *pcie_phy;
+	const struct aspeed_pcie_phy_platform *md;
+
+	md = of_device_get_match_data(dev);
+	if (!md)
+		return -ENODEV;
+
+	pcie_phy = devm_kzalloc(dev, sizeof(*pcie_phy), GFP_KERNEL);
+	if (!pcie_phy)
+		return -ENOMEM;
+
+	pcie_phy->reg = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(pcie_phy->reg))
+		return PTR_ERR(pcie_phy->reg);
+
+	pcie_phy->dev = dev;
+	pcie_phy->platform = md;
+
+	pcie_phy->phy = devm_phy_create(dev, dev->of_node,
+					pcie_phy->platform->phy_ops);
+	if (IS_ERR(pcie_phy->phy))
+		return dev_err_probe(dev, PTR_ERR(pcie_phy->phy),
+				     "failed to create PHY\n");
+
+	phy_set_drvdata(pcie_phy->phy, pcie_phy);
+	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+	return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id aspeed_pcie_phy_of_match_table[] = {
+	{
+		.compatible = "aspeed,ast2600-pcie-phy",
+		.data = &pcie_phy_ast2600,
+	},
+	{
+		.compatible = "aspeed,ast2700-pcie-phy",
+		.data = &pcie_phy_ast2700,
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, aspeed_pcie_phy_of_match_table);
+
+static struct platform_driver aspeed_pcie_driver = {
+	.probe		= aspeed_pcie_phy_probe,
+	.driver = {
+		.name	= "aspeed-pcie-phy",
+		.of_match_table = aspeed_pcie_phy_of_match_table,
+	},
+};
+
+module_platform_driver(aspeed_pcie_driver);
+
+MODULE_AUTHOR("Jacky Chou <jacky_chou at aspeedtech.com>");
+MODULE_DESCRIPTION("ASPEED PCIe PHY");
+MODULE_LICENSE("GPL");

-- 
2.34.1



From hongxing.zhu at nxp.com  Mon Dec 29 22:31:47 2025
From: hongxing.zhu at nxp.com (Hongxing Zhu)
Date: Tue, 30 Dec 2025 06:31:47 +0000
Subject: [PATCH v10 4/4] arm64: dt: imx95: Add the missed ref clock for
 PCIe[0,1]
In-Reply-To: <aVNG0BjbEVHhgNCa@dragon>
References: <20251211064821.2707001-1-hongxing.zhu@nxp.com>
 <20251211064821.2707001-5-hongxing.zhu@nxp.com> <aVNG0BjbEVHhgNCa@dragon>
Message-ID: <AS8PR04MB8833950FABA4829299CA3D6E8CBCA@AS8PR04MB8833.eurprd04.prod.outlook.com>

> -----Original Message-----
> From: Shawn Guo <shawnguo at kernel.org>
> Sent: 2025?12?30? 11:28
> To: Hongxing Zhu <hongxing.zhu at nxp.com>
> Cc: robh at kernel.org; krzk+dt at kernel.org; conor+dt at kernel.org;
> bhelgaas at google.com; Frank Li <frank.li at nxp.com>; l.stach at pengutronix.de;
> lpieralisi at kernel.org; kwilczynski at kernel.org; mani at kernel.org;
> s.hauer at pengutronix.de; kernel at pengutronix.de; festevam at gmail.com;
> linux-pci at vger.kernel.org; linux-arm-kernel at lists.infradead.org;
> devicetree at vger.kernel.org; imx at lists.linux.dev;
> linux-kernel at vger.kernel.org
> Subject: Re: [PATCH v10 4/4] arm64: dt: imx95: Add the missed ref clock for
> PCIe[0,1]
> 
> On Thu, Dec 11, 2025 at 02:48:21PM +0800, Richard Zhu wrote:
> > i.MX95 PCIes have two reference clock inputs, one of them is from
> > internal PLL. It's wired inside chip and present as "ref" clock. It's
> > not an optional clock.
> >
> > Add the missed ref clock for PCIe[0,1].
> >
> > Signed-off-by: Richard Zhu <hongxing.zhu at nxp.com>
> 
> It doesn't seem to apply to my tree.
Hi Shawn
Thanks for your concerns.
You're right.
I create this patch based on r6.18-rc1. And it wouldn?t be applied to r6.19-rc1.
Please ignore it. Thanks.

Best Regards
Richard Zhu
> 
> Shawn
> 
> > ---
> >  .../boot/dts/freescale/imx95-tqma9596sa-mb-smarc-2.dts | 10
> > ++++++----
> >  1 file changed, 6 insertions(+), 4 deletions(-)
> >
> > diff --git
> > a/arch/arm64/boot/dts/freescale/imx95-tqma9596sa-mb-smarc-2.dts
> > b/arch/arm64/boot/dts/freescale/imx95-tqma9596sa-mb-smarc-2.dts
> > index 5b6b2bb80b288..1258fcb54681e 100644
> > --- a/arch/arm64/boot/dts/freescale/imx95-tqma9596sa-mb-smarc-2.dts
> > +++ b/arch/arm64/boot/dts/freescale/imx95-tqma9596sa-mb-smarc-2.dts
> > @@ -237,8 +237,9 @@ &pcie0 {
> >  	clocks = <&scmi_clk IMX95_CLK_HSIO>,
> >  		 <&pcieclk 1>,
> >  		 <&scmi_clk IMX95_CLK_HSIOPLL_VCO>,
> > -		 <&scmi_clk IMX95_CLK_HSIOPCIEAUX>;
> > -	clock-names = "pcie", "pcie_bus", "pcie_phy", "pcie_aux";
> > +		 <&scmi_clk IMX95_CLK_HSIOPCIEAUX>,
> > +		 <&hsio_blk_ctl 0>;
> > +	clock-names = "pcie", "pcie_bus", "pcie_phy", "pcie_aux", "ref";
> >  	reset-gpio = <&expander2 9 GPIO_ACTIVE_LOW>;
> >  	status = "okay";
> >  };
> > @@ -250,8 +251,9 @@ &pcie1 {
> >  	clocks = <&scmi_clk IMX95_CLK_HSIO>,
> >  		 <&pcieclk 0>,
> >  		 <&scmi_clk IMX95_CLK_HSIOPLL_VCO>,
> > -		 <&scmi_clk IMX95_CLK_HSIOPCIEAUX>;
> > -	clock-names = "pcie", "pcie_bus", "pcie_phy", "pcie_aux";
> > +		 <&scmi_clk IMX95_CLK_HSIOPCIEAUX>,
> > +		 <&hsio_blk_ctl 0>;
> > +	clock-names = "pcie", "pcie_bus", "pcie_phy", "pcie_aux", "ref";
> >  	reset-gpio = <&expander2 10 GPIO_ACTIVE_LOW>;
> >  	status = "okay";
> >  };
> > --
> > 2.37.1
> >

From shawnguo at kernel.org  Mon Dec 29 22:44:17 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 14:44:17 +0800
Subject: [PATCH 1/2] dt-bindings: power: fsl,imx-gpc: Document
 address-cells
In-Reply-To: <20251212085902.103507-1-alexander.stein@ew.tq-group.com>
References: <20251212085902.103507-1-alexander.stein@ew.tq-group.com>
Message-ID: <aVN0wfPKqE-iyYOg@dragon>

On Fri, Dec 12, 2025 at 09:58:59AM +0100, Alexander Stein wrote:
> The GPC power controller is an interrupt controllers and can be referenced
> in interrupt-map properties, e.g. PCIe controller, thus the node should
> have address-cells property.
> 
> Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>

Applied both, thanks!


From shawnguo at kernel.org  Mon Dec 29 23:02:39 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 15:02:39 +0800
Subject: [PATCH 0/3] arm64: dts: freescale: Use phys to replace
 xceiver-supply
In-Reply-To: <20251212-imx9-can-phy-v1-0-a421d7023e13@nxp.com>
References: <20251212-imx9-can-phy-v1-0-a421d7023e13@nxp.com>
Message-ID: <aVN5D6PqZVLumY89@dragon>

On Fri, Dec 12, 2025 at 05:57:18PM +0800, Peng Fan (OSS) wrote:
> This is a pick up of patch 6-8 from [1].
> 
> The drivers changes have been picked in 6.18, just resend the dts changes.
> 
> [1]https://lore.kernel.org/linux-phy/20251001-can-v7-0-fad29efc3884 at nxp.com/
> 
> There are still some other device trees not converted to use phys,
> those will be converted later.
> 
> Signed-off-by: Peng Fan <peng.fan at nxp.com>
> ---
> Peng Fan (3):
>       arm64: dts: imx95-15x15-evk: Use phys to replace xceiver-supply
>       arm64: dts: imx8mp-evk: Use phys to replace xceiver-supply
>       arm64: dts: imx93-11x11-evk: Use phys to replace xceiver-supply

Applied all, thanks!


From thomas.weissschuh at linutronix.de  Mon Dec 29 23:10:55 2025
From: thomas.weissschuh at linutronix.de (=?utf-8?q?Thomas_Wei=C3=9Fschuh?=)
Date: Tue, 30 Dec 2025 08:10:55 +0100
Subject: [PATCH 0/5] uapi: fix remaining kconfig leaks in UAPI headers
Message-ID: <20251230-headers_install-config-leak-v1-0-efba5c58073d@linutronix.de>

A few UAPI headers still contained references to kconfig symbols.
Clean them all up and afterwards remove the now useless exception
machinery in headers_install.sh.

Intended to be routed through the kbuild tree.

Signed-off-by: Thomas Wei?schuh <thomas.weissschuh at linutronix.de>
---
Thomas Wei?schuh (5):
      ARC: uapi: Stop leaking CONFIG_ARC_HAS_SWAPE reference to userspace
      ARM: uapi: Stop leaking CONFIG_CPU_ENDIAN_BE8 reference to userspace
      nios2: uapi: Stop leaking CONFIG_NIOS2_CI_SWAB_{NO,SUPPORT} references to userspace
      x86/uapi: Stop leaking kconfig references to userspace
      scripts: headers_install.sh: Remove config leak ignore machinery

 arch/arc/include/uapi/asm/swab.h   |  2 +-
 arch/arm/include/uapi/asm/ptrace.h |  2 +-
 arch/nios2/include/uapi/asm/swab.h |  2 ++
 arch/x86/include/uapi/asm/auxvec.h |  2 +-
 scripts/headers_install.sh         | 30 ++----------------------------
 5 files changed, 7 insertions(+), 31 deletions(-)
---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20251229-headers_install-config-leak-b8a9219d8b3c

Best regards,
-- 
Thomas Wei?schuh <thomas.weissschuh at linutronix.de>



From thomas.weissschuh at linutronix.de  Mon Dec 29 23:10:56 2025
From: thomas.weissschuh at linutronix.de (=?utf-8?q?Thomas_Wei=C3=9Fschuh?=)
Date: Tue, 30 Dec 2025 08:10:56 +0100
Subject: [PATCH 1/5] ARC: uapi: Stop leaking CONFIG_ARC_HAS_SWAPE reference
 to userspace
In-Reply-To: <20251230-headers_install-config-leak-v1-0-efba5c58073d@linutronix.de>
References: <20251230-headers_install-config-leak-v1-0-efba5c58073d@linutronix.de>
Message-ID: <20251230-headers_install-config-leak-v1-1-efba5c58073d@linutronix.de>

UAPI headers are not supposed to leak references to kconfig symbols.
These won't be set when building userspace. Hide the kconfig reference
behind 'if defined(__KERNEL__)', so it will be stripped by
headers_install.sh. The result for userspace will be the same, but the
exception in headers_install.sh can also be removed.

Signed-off-by: Thomas Wei?schuh <thomas.weissschuh at linutronix.de>
---
 arch/arc/include/uapi/asm/swab.h | 2 +-
 scripts/headers_install.sh       | 1 -
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/arc/include/uapi/asm/swab.h b/arch/arc/include/uapi/asm/swab.h
index 8d1f1ef44ba7..b2cede1b74b9 100644
--- a/arch/arc/include/uapi/asm/swab.h
+++ b/arch/arc/include/uapi/asm/swab.h
@@ -20,7 +20,7 @@
 #include <linux/types.h>
 
 /* Native single cycle endian swap insn */
-#ifdef CONFIG_ARC_HAS_SWAPE
+#if defined(__KERNEL__) && defined(CONFIG_ARC_HAS_SWAPE)
 
 #define __arch_swab32(x)		\
 ({					\
diff --git a/scripts/headers_install.sh b/scripts/headers_install.sh
index 0e4e939efc94..727f7f82c2c7 100755
--- a/scripts/headers_install.sh
+++ b/scripts/headers_install.sh
@@ -70,7 +70,6 @@ configs=$(sed -e '
 #
 # The format is <file-name>:<CONFIG-option> in each line.
 config_leak_ignores="
-arch/arc/include/uapi/asm/swab.h:CONFIG_ARC_HAS_SWAPE
 arch/arm/include/uapi/asm/ptrace.h:CONFIG_CPU_ENDIAN_BE8
 arch/nios2/include/uapi/asm/swab.h:CONFIG_NIOS2_CI_SWAB_NO
 arch/nios2/include/uapi/asm/swab.h:CONFIG_NIOS2_CI_SWAB_SUPPORT

-- 
2.52.0



From thomas.weissschuh at linutronix.de  Mon Dec 29 23:10:57 2025
From: thomas.weissschuh at linutronix.de (=?utf-8?q?Thomas_Wei=C3=9Fschuh?=)
Date: Tue, 30 Dec 2025 08:10:57 +0100
Subject: [PATCH 2/5] ARM: uapi: Stop leaking CONFIG_CPU_ENDIAN_BE8
 reference to userspace
In-Reply-To: <20251230-headers_install-config-leak-v1-0-efba5c58073d@linutronix.de>
References: <20251230-headers_install-config-leak-v1-0-efba5c58073d@linutronix.de>
Message-ID: <20251230-headers_install-config-leak-v1-2-efba5c58073d@linutronix.de>

UAPI headers are not supposed to leak references to kconfig symbols.
These won't be set when building userspace. Hide the kconfig reference
behind 'if defined(__KERNEL__)', so it will be stripped by
headers_install.sh, the same way other kconfig references in this file
are handled. The result for userspace will be the same, but the
exception in headers_install.sh can also be removed.

Signed-off-by: Thomas Wei?schuh <thomas.weissschuh at linutronix.de>
---
 arch/arm/include/uapi/asm/ptrace.h | 2 +-
 scripts/headers_install.sh         | 1 -
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/arm/include/uapi/asm/ptrace.h b/arch/arm/include/uapi/asm/ptrace.h
index 8896c23ccba7..fe656da1701b 100644
--- a/arch/arm/include/uapi/asm/ptrace.h
+++ b/arch/arm/include/uapi/asm/ptrace.h
@@ -105,7 +105,7 @@
 /*
  * Default endianness state
  */
-#ifdef CONFIG_CPU_ENDIAN_BE8
+#if defined(__KERNEL__) && defined(CONFIG_CPU_ENDIAN_BE8)
 #define PSR_ENDSTATE	PSR_E_BIT
 #else
 #define PSR_ENDSTATE	0
diff --git a/scripts/headers_install.sh b/scripts/headers_install.sh
index 727f7f82c2c7..4f03521f4026 100755
--- a/scripts/headers_install.sh
+++ b/scripts/headers_install.sh
@@ -70,7 +70,6 @@ configs=$(sed -e '
 #
 # The format is <file-name>:<CONFIG-option> in each line.
 config_leak_ignores="
-arch/arm/include/uapi/asm/ptrace.h:CONFIG_CPU_ENDIAN_BE8
 arch/nios2/include/uapi/asm/swab.h:CONFIG_NIOS2_CI_SWAB_NO
 arch/nios2/include/uapi/asm/swab.h:CONFIG_NIOS2_CI_SWAB_SUPPORT
 arch/x86/include/uapi/asm/auxvec.h:CONFIG_IA32_EMULATION

-- 
2.52.0



From thomas.weissschuh at linutronix.de  Mon Dec 29 23:10:59 2025
From: thomas.weissschuh at linutronix.de (=?utf-8?q?Thomas_Wei=C3=9Fschuh?=)
Date: Tue, 30 Dec 2025 08:10:59 +0100
Subject: [PATCH 4/5] x86/uapi: Stop leaking kconfig references to userspace
In-Reply-To: <20251230-headers_install-config-leak-v1-0-efba5c58073d@linutronix.de>
References: <20251230-headers_install-config-leak-v1-0-efba5c58073d@linutronix.de>
Message-ID: <20251230-headers_install-config-leak-v1-4-efba5c58073d@linutronix.de>

UAPI headers are not supposed to leak references to kconfig symbols.
These won't be set when building userspace. Hide the kconfig reference
behind 'if defined(__KERNEL__)', so it will be stripped by
headers_install.sh. The result for userspace will be the same, but the
exceptions in headers_install.sh can also be removed.

Signed-off-by: Thomas Wei?schuh <thomas.weissschuh at linutronix.de>
---
 arch/x86/include/uapi/asm/auxvec.h | 2 +-
 scripts/headers_install.sh         | 2 --
 2 files changed, 1 insertion(+), 3 deletions(-)

diff --git a/arch/x86/include/uapi/asm/auxvec.h b/arch/x86/include/uapi/asm/auxvec.h
index 6beb55bbefa4..bdde9e18f94e 100644
--- a/arch/x86/include/uapi/asm/auxvec.h
+++ b/arch/x86/include/uapi/asm/auxvec.h
@@ -11,7 +11,7 @@
 #define AT_SYSINFO_EHDR		33
 
 /* entries in ARCH_DLINFO: */
-#if defined(CONFIG_IA32_EMULATION) || !defined(CONFIG_X86_64)
+#if defined(__KERNEL__) && (defined(CONFIG_IA32_EMULATION) || !defined(CONFIG_X86_64))
 # define AT_VECTOR_SIZE_ARCH 3
 #else /* else it's non-compat x86-64 */
 # define AT_VECTOR_SIZE_ARCH 2
diff --git a/scripts/headers_install.sh b/scripts/headers_install.sh
index 613f400a67d1..1301ba68d772 100755
--- a/scripts/headers_install.sh
+++ b/scripts/headers_install.sh
@@ -70,8 +70,6 @@ configs=$(sed -e '
 #
 # The format is <file-name>:<CONFIG-option> in each line.
 config_leak_ignores="
-arch/x86/include/uapi/asm/auxvec.h:CONFIG_IA32_EMULATION
-arch/x86/include/uapi/asm/auxvec.h:CONFIG_X86_64
 "
 
 for c in $configs

-- 
2.52.0



From thomas.weissschuh at linutronix.de  Mon Dec 29 23:10:58 2025
From: thomas.weissschuh at linutronix.de (=?utf-8?q?Thomas_Wei=C3=9Fschuh?=)
Date: Tue, 30 Dec 2025 08:10:58 +0100
Subject: [PATCH 3/5] nios2: uapi: Stop leaking
 CONFIG_NIOS2_CI_SWAB_{NO,SUPPORT} references to userspace
In-Reply-To: <20251230-headers_install-config-leak-v1-0-efba5c58073d@linutronix.de>
References: <20251230-headers_install-config-leak-v1-0-efba5c58073d@linutronix.de>
Message-ID: <20251230-headers_install-config-leak-v1-3-efba5c58073d@linutronix.de>

UAPI headers are not supposed to leak references to kconfig symbols.
These won't be set when building userspace. Hide the kconfig reference
behind 'ifdef __KERNEL__', so it will be stripped by
headers_install.sh. The result for userspace will be the same, but the
exceptions in headers_install.sh can also be removed.

Signed-off-by: Thomas Wei?schuh <thomas.weissschuh at linutronix.de>
---
 arch/nios2/include/uapi/asm/swab.h | 2 ++
 scripts/headers_install.sh         | 2 --
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/nios2/include/uapi/asm/swab.h b/arch/nios2/include/uapi/asm/swab.h
index 9750547a5f82..bbfa9bd10b2f 100644
--- a/arch/nios2/include/uapi/asm/swab.h
+++ b/arch/nios2/include/uapi/asm/swab.h
@@ -14,6 +14,7 @@
 #include <linux/types.h>
 #include <asm-generic/swab.h>
 
+#ifdef __KERNEL__
 #ifdef CONFIG_NIOS2_CI_SWAB_SUPPORT
 #ifdef __GNUC__
 
@@ -34,5 +35,6 @@ static inline __attribute__((const)) __u32 __arch_swab32(__u32 x)
 
 #endif /* __GNUC__ */
 #endif /* CONFIG_NIOS2_CI_SWAB_SUPPORT */
+#endif /* __KERNEL__ */
 
 #endif /* _ASM_NIOS2_SWAB_H */
diff --git a/scripts/headers_install.sh b/scripts/headers_install.sh
index 4f03521f4026..613f400a67d1 100755
--- a/scripts/headers_install.sh
+++ b/scripts/headers_install.sh
@@ -70,8 +70,6 @@ configs=$(sed -e '
 #
 # The format is <file-name>:<CONFIG-option> in each line.
 config_leak_ignores="
-arch/nios2/include/uapi/asm/swab.h:CONFIG_NIOS2_CI_SWAB_NO
-arch/nios2/include/uapi/asm/swab.h:CONFIG_NIOS2_CI_SWAB_SUPPORT
 arch/x86/include/uapi/asm/auxvec.h:CONFIG_IA32_EMULATION
 arch/x86/include/uapi/asm/auxvec.h:CONFIG_X86_64
 "

-- 
2.52.0



From thomas.weissschuh at linutronix.de  Mon Dec 29 23:11:00 2025
From: thomas.weissschuh at linutronix.de (=?utf-8?q?Thomas_Wei=C3=9Fschuh?=)
Date: Tue, 30 Dec 2025 08:11:00 +0100
Subject: [PATCH 5/5] scripts: headers_install.sh: Remove config leak ignore
 machinery
In-Reply-To: <20251230-headers_install-config-leak-v1-0-efba5c58073d@linutronix.de>
References: <20251230-headers_install-config-leak-v1-0-efba5c58073d@linutronix.de>
Message-ID: <20251230-headers_install-config-leak-v1-5-efba5c58073d@linutronix.de>

There are no entries left to ignore and none should be added again.

Remove the now unused logic.

Signed-off-by: Thomas Wei?schuh <thomas.weissschuh at linutronix.de>
---
 scripts/headers_install.sh | 24 ++----------------------
 1 file changed, 2 insertions(+), 22 deletions(-)

diff --git a/scripts/headers_install.sh b/scripts/headers_install.sh
index 1301ba68d772..9c15e748761c 100755
--- a/scripts/headers_install.sh
+++ b/scripts/headers_install.sh
@@ -64,30 +64,10 @@ configs=$(sed -e '
 	d
 ' $OUTFILE)
 
-# The entries in the following list do not result in an error.
-# Please do not add a new entry. This list is only for existing ones.
-# The list will be reduced gradually, and deleted eventually. (hopefully)
-#
-# The format is <file-name>:<CONFIG-option> in each line.
-config_leak_ignores="
-"
-
 for c in $configs
 do
-	leak_error=1
-
-	for ignore in $config_leak_ignores
-	do
-		if echo "$INFILE:$c" | grep -q "$ignore$"; then
-			leak_error=
-			break
-		fi
-	done
-
-	if [ "$leak_error" = 1 ]; then
-		echo "error: $INFILE: leak $c to user-space" >&2
-		exit 1
-	fi
+	echo "error: $INFILE: leak $c to user-space" >&2
+	exit 1
 done
 
 rm -f $TMPFILE

-- 
2.52.0



From krzk at kernel.org  Mon Dec 29 23:19:51 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 30 Dec 2025 08:19:51 +0100
Subject: [PATCH] arm64: dts: cix: Use lowercase hex
In-Reply-To: <aVMzY2VTFn-mNCEA@nchen-desktop>
References: <20251223152424.155253-2-krzysztof.kozlowski@oss.qualcomm.com>
 <aVHb-kbi2QbChxj9@nchen-desktop>
 <88e9e4c4-13c9-4b96-88cc-abb581011e87@kernel.org>
 <aVMzY2VTFn-mNCEA@nchen-desktop>
Message-ID: <97f2d191-c8c7-4c47-bde2-9167991c4aba@kernel.org>

On 30/12/2025 03:05, Peter Chen wrote:
> On 25-12-29 08:17:15, Krzysztof Kozlowski wrote:
>> EXTERNAL EMAIL
>>
>> On 29/12/2025 02:40, Peter Chen wrote:
>>> On 25-12-23 16:24:25, Krzysztof Kozlowski wrote:
>>>> EXTERNAL EMAIL
>>>>
>>>> The DTS code coding style expects lowercase hex for values and unit
>>>> addresses.
>>>>
>>>> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
>>>>
>>>> ---
>>>>
>>>> Patches done with sed, verified with comparing unflattened DTB and
>>>> dtx_diff.
>>>> ---
>>>>  arch/arm64/boot/dts/cix/sky1.dtsi | 2 +-
>>>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>>>
>>>> diff --git a/arch/arm64/boot/dts/cix/sky1.dtsi b/arch/arm64/boot/dts/cix/sky1.dtsi
>>>> index 64b76905cbff..fb8c826bbc97 100644
>>>> --- a/arch/arm64/boot/dts/cix/sky1.dtsi
>>>> +++ b/arch/arm64/boot/dts/cix/sky1.dtsi
>>>> @@ -523,7 +523,7 @@ pcie_x1_1_rc: pcie at a0e0000 {
>>>>                         reg-names = "reg", "cfg", "rcsu_strap", "rcsu_status", "msg";
>>>>                         ranges = <0x01000000 0x0 0x38100000 0x0 0x38100000 0x0 0x00100000>,
>>>>                                  <0x02000000 0x0 0x38200000 0x0 0x38200000 0x0 0x07e00000>,
>>>> -                                <0x43000000 0x0C 0x00000000 0x0C 0x00000000 0x04 0x00000000>;
>>>> +                                <0x43000000 0x0c 0x00000000 0x0c 0x00000000 0x04 0x00000000>;
>>>
>>> Sorry, I could not apply for v6.19-rc1, could you?
>>
>> What do you mean? It applies cleanly on v6.19-rc1 and on next. Your
>> branches are not really updated, so maybe you need to fix this.
>>
> 
> Sorry for confusing. The patch was inserted by some special characters,
> See below: "=", and "3D". But no these kinds of characters when I save
> internal patch for upstream. Our IT is checking this issue.

The patch does not have them. It must have been your email system, which
broke it or you did not save it correctly. I suggest to apply patches
with b4, see my talk from LPC 2023 - Beginner Linux kernel maintainer's
toolbox.


Best regards,
Krzysztof


From qijian.guo at nxp.com  Mon Dec 29 23:58:53 2025
From: qijian.guo at nxp.com (Joseph Guo)
Date: Tue, 30 Dec 2025 16:58:53 +0900
Subject: [PATCH v3 1/2] dt-bindings: arm: imx Add FRDM-IMX91 board
In-Reply-To: <20251230-imx91_frdm-v3-0-60cac61c96ec@nxp.com>
References: <20251230-imx91_frdm-v3-0-60cac61c96ec@nxp.com>
Message-ID: <20251230-imx91_frdm-v3-1-60cac61c96ec@nxp.com>

Add the board FRDM-IMX91 in the binding document.

Reviewed-by: Daniel Baluta <daniel.baluta at nxp.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
Reviewed-by: Francesco Valla <francesco at valla.it>
Tested-by: Francesco Valla <francesco at valla.it>
Signed-off-by: Joseph Guo <qijian.guo at nxp.com>
---
Changes in v2:
- rename 'frdm-imx91' to 'imx91-11x11-frdm'

Changes in v3:
- add code-review trailers
---
 Documentation/devicetree/bindings/arm/fsl.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
index 68a2d5fecc43b06711e2efce61ac1fc2794b79bc..12d72057b1b817283754a2857d8106a409b594e7 100644
--- a/Documentation/devicetree/bindings/arm/fsl.yaml
+++ b/Documentation/devicetree/bindings/arm/fsl.yaml
@@ -1412,6 +1412,7 @@ properties:
         items:
           - enum:
               - fsl,imx91-11x11-evk       # i.MX91 11x11 EVK Board
+              - fsl,imx91-11x11-frdm      # FRDM i.MX91 Development Board
           - const: fsl,imx91
 
       - description: i.MX93 based Boards

-- 
2.34.1



From qijian.guo at nxp.com  Mon Dec 29 23:58:52 2025
From: qijian.guo at nxp.com (Joseph Guo)
Date: Tue, 30 Dec 2025 16:58:52 +0900
Subject: [PATCH v3 0/2] Add FRDM i.MX 91 Development board support
Message-ID: <20251230-imx91_frdm-v3-0-60cac61c96ec@nxp.com>

FRDM-IMX91 board is a low cost development platform based on i.MX91 SoC:
https://www.nxp.com/design/design-center/development-boards-and-designs/FRDM-IMX91

Add device tree and dt-binding for FRDM-IMX91.

Signed-off-by: Joseph Guo <qijian.guo at nxp.com>
---
Changes in v3:
- end property list with 'status'
- add newline between property list and child node
- add code-review trailers 
- Link to v2: https://lore.kernel.org/r/20251212-imx91_frdm-v2-0-4dd6d289e81d at nxp.com

Changes in v2:
- rename compatible 'frdm-imx91' to 'imx91-11x11-frdm'
- rename 'sw-keys' to 'gpio-keys'
- rename 'user_btn' to 'button-k'
- drop lpspi3 node
- rename iomuxc 'grpsleep' to 'sleepgrp'
- move dt-binding patch before the dts patch
- add board page link in cover letter
- use CAN PHY to manage the stby gpio of flexcan2
- drop realtek property
- add pcf2131 aliase
- add bootph- property for nodes should be kept in bootloader phase
- add reset-gpio and assert for eqos and fec
- delete unused alias
- Link to v1: https://lore.kernel.org/r/20251114-imx91_frdm-v1-0-e5763bdf9336 at nxp.com

---
Joseph Guo (2):
      dt-bindings: arm: imx Add FRDM-IMX91 board
      arm64: dts: freescale: Add FRDM-IMX91 basic support

 Documentation/devicetree/bindings/arm/fsl.yaml     |   1 +
 arch/arm64/boot/dts/freescale/Makefile             |   1 +
 arch/arm64/boot/dts/freescale/imx91-11x11-frdm.dts | 906 +++++++++++++++++++++
 3 files changed, 908 insertions(+)
---
base-commit: 73f1e611b076de705c2f1c26cfdfc5b8e96f4733
change-id: 20251114-imx91_frdm-add2b2c07e78

Best regards,
-- 
Joseph Guo <qijian.guo at nxp.com>



From qijian.guo at nxp.com  Mon Dec 29 23:58:54 2025
From: qijian.guo at nxp.com (Joseph Guo)
Date: Tue, 30 Dec 2025 16:58:54 +0900
Subject: [PATCH v3 2/2] arm64: dts: freescale: Add FRDM-IMX91 basic support
In-Reply-To: <20251230-imx91_frdm-v3-0-60cac61c96ec@nxp.com>
References: <20251230-imx91_frdm-v3-0-60cac61c96ec@nxp.com>
Message-ID: <20251230-imx91_frdm-v3-2-60cac61c96ec@nxp.com>

The FRDM i.MX 91 development board is a low-cost and
compact developmentboard featuring the i.MX 91 applications processor:
https://www.nxp.com/design/design-center/development-boards-and-designs/FRDM-IMX91

Add FRDM-IMX91 board dts support.
- Enable ADC1.
- Enable lpuart1 and lpuart5.
- Enable network eqos and fec.
- Enable I2C bus and children nodes under I2C bus.
- Enable USB and related nodes.
- Enable uSDHC1, uSDHC2 and uSDHC3.
- Enable MU1 and MU2.
- Enable Watchdog3.
- Enable MQS

Co-developed-by: Tom Zheng <haidong.zheng at nxp.com>
Signed-off-by: Tom Zheng <haidong.zheng at nxp.com>
Co-developed-by: Steven Yang <steven.yang at nxp.com>
Signed-off-by: Steven Yang <steven.yang at nxp.com>
Reviewed-by: Andrew Lunn <andrew at lunn.ch>
Reviewed-by: Francesco Valla <francesco at valla.it>
Tested-by: Francesco Valla <francesco at valla.it>
Signed-off-by: Joseph Guo <qijian.guo at nxp.com>
---
Changes in v2:
- rename compatible 'frdm-imx91' to 'imx91-11x11-frdm'
- rename model to 'NXP i.MX91 11x11 FRDM Board'
- rename 'sw-keys' to 'gpio-keys'
- rename 'user_btn' to 'button-k'
- drop lpspi3 node
- rename iomuxc 'grpsleep' to 'sleepgrp'
- use CAN PHY to manage the stby gpio of flexcan2
- drop realtek property
- add pcf2131 aliase
- add bootph- property for nodes should be kept in bootloader phase
- add reset-gpio and assert for eqos and fec
- delete unused alias

Changes in v3:
- end property list with 'status'
- add newline between property list and child node
- add code-review trailers
---
 arch/arm64/boot/dts/freescale/Makefile             |   1 +
 arch/arm64/boot/dts/freescale/imx91-11x11-frdm.dts | 906 +++++++++++++++++++++
 2 files changed, 907 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index f30d3fd724d0ce6b38f7bef10e3970ac34f70f4a..d0808ec3c1c4ab848ad9edf45cf453ce40a5f2c6 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -368,6 +368,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8qxp-tqma8xqps-mb-smarc-2.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8ulp-9x9-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8ulp-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx91-11x11-evk.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx91-11x11-frdm.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx91-phyboard-segin.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx91-tqma9131-mba91xxca.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx93-9x9-qsb.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx91-11x11-frdm.dts b/arch/arm64/boot/dts/freescale/imx91-11x11-frdm.dts
new file mode 100644
index 0000000000000000000000000000000000000000..0d1acf8a55a5b4ac649fc8eb7c7aa2c0724b267d
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx91-11x11-frdm.dts
@@ -0,0 +1,906 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2025 NXP
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/usb/pd.h>
+#include "imx91.dtsi"
+
+/ {
+	compatible = "fsl,imx91-11x11-frdm", "fsl,imx91";
+	model = "NXP i.MX91 11x11 FRDM Board";
+
+	aliases {
+		ethernet0 = &fec;
+		ethernet1 = &eqos;
+		gpio0 = &gpio1;
+		gpio1 = &gpio2;
+		gpio2 = &gpio3;
+		gpio3 = &gpio4;
+		i2c0 = &lpi2c1;
+		i2c1 = &lpi2c2;
+		i2c2 = &lpi2c3;
+		mmc0 = &usdhc1;
+		mmc1 = &usdhc2;
+		mmc2 = &usdhc3;
+		rtc0 = &bbnsm_rtc;
+		rtc1 = &pcf2131;
+		serial0 = &lpuart1;
+		serial4 = &lpuart5;
+	};
+
+	chosen {
+		stdout-path = &lpuart1;
+	};
+
+	flexcan_phy: can-phy {
+		compatible = "nxp,tja1051";
+		#phy-cells = <0>;
+		max-bitrate = <5000000>;
+		enable-gpios = <&pcal6524 23 GPIO_ACTIVE_LOW>;
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		button-k2 {
+			interrupt-parent = <&pcal6524>;
+			interrupts = <5 IRQ_TYPE_EDGE_FALLING>;
+			label = "Button K2";
+			gpios = <&pcal6524 5 GPIO_PULL_UP>;
+			linux,code = <BTN_1>;
+		};
+
+		button-k3 {
+			interrupt-parent = <&pcal6524>;
+			interrupts = <6 IRQ_TYPE_EDGE_FALLING>;
+			label = "Button K3";
+			gpios = <&pcal6524 6 GPIO_PULL_UP>;
+			linux,code = <BTN_2>;
+		};
+	};
+
+	reg_vref_1v8: regulator-adc-vref {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <1800000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-name = "vref_1v8";
+	};
+
+	reg_m2_pwr: regulator-m2-pwr {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "M.2-power";
+		gpio = <&pcal6524 13 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_usdhc2_vmmc: regulator-usdhc2 {
+		compatible = "regulator-fixed";
+		off-on-delay-us = <12000>;
+		pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
+		pinctrl-names = "default";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "VSD_3V3";
+		gpio = <&gpio3 7 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		bootph-pre-ram;
+		bootph-some-ram;
+	};
+
+	reg_usdhc3_vmmc: regulator-usdhc3 {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "WLAN_EN";
+		vin-supply = <&reg_m2_pwr>;
+		gpio = <&pcal6524 20 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		/*
+		 * This regulator defined as PDn pin of the IW610 wifi module.
+		 * IW610 wifi chip needs more delay than other wifi chips to complete
+		 * the host interface initialization after power up, otherwise the
+		 * internal state of IW610 may be unstable, resulting in the failure of
+		 * the SDIO3.0 switch voltage.
+		 */
+		startup-delay-us = <20000>;
+	};
+
+	reg_vdd_12v: regulator-vdd-12v {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <12000000>;
+		regulator-min-microvolt = <12000000>;
+		regulator-name = "reg_vdd_12v";
+		gpio = <&pcal6524 14 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_vexp_3v3: regulator-vexp-3v3 {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "VEXP_3V3";
+		vin-supply = <&buck4>;
+		gpio = <&pcal6524 2 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_vexp_5v: regulator-vexp-5v {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <5000000>;
+		regulator-min-microvolt = <5000000>;
+		regulator-name = "VEXP_5V";
+		gpio = <&pcal6524 8 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reserved-memory {
+		ranges;
+		#address-cells = <2>;
+		#size-cells = <2>;
+
+		linux,cma {
+			compatible = "shared-dma-pool";
+			alloc-ranges = <0 0x80000000 0 0x30000000>;
+			reusable;
+			size = <0 0x10000000>;
+			linux,cma-default;
+		};
+	};
+
+	soc at 0 {
+		bootph-all;
+		bootph-pre-ram;
+	};
+
+	sound-mqs {
+		compatible = "fsl,imx6sx-sdb-mqs",
+			     "fsl,imx-audio-mqs";
+		audio-codec = <&mqs1>;
+		audio-cpu = <&sai1>;
+		model = "mqs-audio";
+	};
+
+	usdhc3_pwrseq: usdhc3-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&pcal6524 12 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&adc1 {
+	vref-supply = <&reg_vref_1v8>;
+	status = "okay";
+};
+
+&aips1 {
+	bootph-pre-ram;
+	bootph-all;
+};
+
+&aips2 {
+	bootph-pre-ram;
+	bootph-some-ram;
+};
+
+&aips3 {
+	bootph-pre-ram;
+	bootph-some-ram;
+};
+
+&clk {
+	bootph-all;
+	bootph-pre-ram;
+};
+
+&clk_ext1 {
+	bootph-all;
+	bootph-pre-ram;
+};
+
+&eqos {
+	phy-handle = <&ethphy1>;
+	phy-mode = "rgmii-id";
+	pinctrl-0 = <&pinctrl_eqos>;
+	pinctrl-1 = <&pinctrl_eqos_sleep>;
+	pinctrl-names = "default", "sleep";
+	status = "okay";
+
+	mdio {
+		compatible = "snps,dwmac-mdio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-frequency = <5000000>;
+
+		ethphy1: ethernet-phy at 1 {
+			reg = <1>;
+			reset-gpios = <&pcal6524 15 GPIO_ACTIVE_LOW>;
+			reset-assert-us = <15000>;
+			reset-deassert-us = <100000>;
+		};
+	};
+};
+
+&fec {
+	phy-handle = <&ethphy2>;
+	phy-mode = "rgmii-id";
+	pinctrl-0 = <&pinctrl_fec>;
+	pinctrl-1 = <&pinctrl_fec_sleep>;
+	pinctrl-names = "default", "sleep";
+	fsl,magic-packet;
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-frequency = <5000000>;
+
+		ethphy2: ethernet-phy at 2 {
+			reg = <2>;
+			reset-gpios = <&pcal6524 16 GPIO_ACTIVE_LOW>;
+			reset-assert-us = <15000>;
+			reset-deassert-us = <100000>;
+		};
+	};
+};
+
+&flexcan2 {
+	pinctrl-0 = <&pinctrl_flexcan2>;
+	pinctrl-1 = <&pinctrl_flexcan2_sleep>;
+	pinctrl-names = "default", "sleep";
+	phys = <&flexcan_phy>;
+	status = "okay";
+};
+
+&gpio1 {
+	bootph-pre-ram;
+	bootph-some-ram;
+};
+
+&gpio2 {
+	bootph-pre-ram;
+	bootph-some-ram;
+};
+
+&gpio3 {
+	bootph-pre-ram;
+	bootph-some-ram;
+};
+
+&gpio4 {
+	bootph-pre-ram;
+	bootph-some-ram;
+};
+
+&lpi2c1 {
+	clock-frequency = <400000>;
+	pinctrl-0 = <&pinctrl_lpi2c1>;
+	pinctrl-names = "default";
+	bootph-pre-ram;
+	bootph-some-ram;
+	status = "okay";
+
+	pcal6408: gpio at 20 {
+		compatible = "nxp,pcal9554b";
+		reg = <0x20>;
+		#gpio-cells = <2>;
+		gpio-controller;
+		vcc-supply = <&reg_usdhc3_vmmc>;
+		status = "okay";
+	};
+};
+
+&lpi2c2 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	clock-frequency = <400000>;
+	pinctrl-0 = <&pinctrl_lpi2c2>;
+	pinctrl-names = "default";
+	bootph-pre-ram;
+	bootph-some-ram;
+	status = "okay";
+
+	pcal6524: gpio at 22 {
+		compatible = "nxp,pcal6524";
+		reg = <0x22>;
+		#interrupt-cells = <2>;
+		interrupt-controller;
+		interrupts = <27 IRQ_TYPE_LEVEL_LOW>;
+		#gpio-cells = <2>;
+		gpio-controller;
+		interrupt-parent = <&gpio3>;
+		pinctrl-0 = <&pinctrl_pcal6524>;
+		pinctrl-names = "default";
+	};
+
+	pmic at 25 {
+		compatible = "nxp,pca9451a";
+		reg = <0x25>;
+		interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
+		interrupt-parent = <&pcal6524>;
+		bootph-pre-ram;
+		bootph-some-ram;
+
+		regulators {
+			bootph-pre-ram;
+			bootph-some-ram;
+
+			buck1: BUCK1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <2237500>;
+				regulator-min-microvolt = <650000>;
+				regulator-name = "BUCK1";
+				regulator-ramp-delay = <3125>;
+			};
+
+			buck2: BUCK2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <2187500>;
+				regulator-min-microvolt = <600000>;
+				regulator-name = "BUCK2";
+				regulator-ramp-delay = <3125>;
+			};
+
+			buck4: BUCK4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <3400000>;
+				regulator-min-microvolt = <600000>;
+				regulator-name = "BUCK4";
+			};
+
+			buck5: BUCK5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <3400000>;
+				regulator-min-microvolt = <600000>;
+				regulator-name = "BUCK5";
+			};
+
+			buck6: BUCK6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <3400000>;
+				regulator-min-microvolt = <600000>;
+				regulator-name = "BUCK6";
+			};
+
+			ldo1: LDO1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <3300000>;
+				regulator-min-microvolt = <1600000>;
+				regulator-name = "LDO1";
+			};
+
+			ldo4: LDO4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <3300000>;
+				regulator-min-microvolt = <800000>;
+				regulator-name = "LDO4";
+			};
+
+			ldo5: LDO5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-max-microvolt = <3300000>;
+				regulator-min-microvolt = <1800000>;
+				regulator-name = "LDO5";
+			};
+		};
+	};
+};
+
+&lpi2c3 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	clock-frequency = <400000>;
+	pinctrl-0 = <&pinctrl_lpi2c3>;
+	pinctrl-names = "default";
+	bootph-pre-ram;
+	bootph-some-ram;
+	status = "okay";
+
+	ptn5110: tcpc at 50 {
+		compatible = "nxp,ptn5110", "tcpci";
+		reg = <0x50>;
+		interrupts = <27 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-parent = <&gpio3>;
+
+		typec1_con: connector {
+			compatible = "usb-c-connector";
+			data-role = "dual";
+			label = "USB-C";
+			op-sink-microwatt = <15000000>;
+			power-role = "dual";
+			self-powered;
+			sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)
+				     PDO_VAR(5000, 20000, 3000)>;
+			source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
+			try-power-role = "sink";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+
+					typec1_dr_sw: endpoint {
+						remote-endpoint = <&usb1_drd_sw>;
+					};
+				};
+			};
+		};
+	};
+
+	pcf2131: rtc at 53 {
+		compatible = "nxp,pcf2131";
+		reg = <0x53>;
+		interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
+		interrupt-parent = <&pcal6524>;
+		status = "okay";
+	};
+};
+
+&lpuart1 {
+	pinctrl-0 = <&pinctrl_uart1>;
+	pinctrl-names = "default";
+	bootph-pre-ram;
+	bootph-some-ram;
+	status = "okay";
+};
+
+&lpuart5 {
+	pinctrl-0 = <&pinctrl_uart5>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	bluetooth {
+		compatible = "nxp,88w8987-bt";
+	};
+};
+
+&mqs1 {
+	clocks = <&clk IMX93_CLK_MQS1_GATE>;
+	clock-names = "mclk";
+	pinctrl-0 = <&pinctrl_mqs1>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&osc_32k {
+	bootph-all;
+	bootph-pre-ram;
+};
+
+&osc_24m {
+	bootph-all;
+	bootph-pre-ram;
+};
+
+&sai1 {
+	clocks = <&clk IMX93_CLK_SAI1_IPG>, <&clk IMX93_CLK_DUMMY>,
+		 <&clk IMX93_CLK_SAI1_GATE>, <&clk IMX93_CLK_DUMMY>,
+		 <&clk IMX93_CLK_DUMMY>, <&clk IMX93_CLK_AUDIO_PLL>;
+	clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3", "pll8k";
+	assigned-clocks = <&clk IMX93_CLK_SAI1>;
+	assigned-clock-parents = <&clk IMX93_CLK_AUDIO_PLL>;
+	assigned-clock-rates = <24576000>;
+	#sound-dai-cells = <0>;
+	fsl,sai-mclk-direction-output;
+	status = "okay";
+};
+
+&usbotg1 {
+	adp-disable;
+	disable-over-current;
+	dr_mode = "otg";
+	hnp-disable;
+	srp-disable;
+	usb-role-switch;
+	samsung,picophy-dc-vol-level-adjust = <7>;
+	samsung,picophy-pre-emp-curr-control = <3>;
+	status = "okay";
+
+	port {
+		usb1_drd_sw: endpoint {
+			remote-endpoint = <&typec1_dr_sw>;
+		};
+	};
+};
+
+&usbotg2 {
+	disable-over-current;
+	dr_mode = "host";
+	samsung,picophy-dc-vol-level-adjust = <7>;
+	samsung,picophy-pre-emp-curr-control = <3>;
+	status = "okay";
+};
+
+&usdhc1 {
+	bus-width = <8>;
+	non-removable;
+	pinctrl-0 = <&pinctrl_usdhc1>;
+	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	bootph-pre-ram;
+	bootph-some-ram;
+	status = "okay";
+};
+
+&usdhc2 {
+	bus-width = <4>;
+	cd-gpios = <&gpio3 00 GPIO_ACTIVE_LOW>;
+	no-mmc;
+	no-sdio;
+	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-3 = <&pinctrl_usdhc2_sleep>, <&pinctrl_usdhc2_gpio_sleep>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	bootph-pre-ram;
+	bootph-some-ram;
+	status = "okay";
+};
+
+&usdhc3 {
+	bus-width = <4>;
+	keep-power-in-suspend;
+	mmc-pwrseq = <&usdhc3_pwrseq>;
+	non-removable;
+	pinctrl-0 = <&pinctrl_usdhc3>, <&pinctrl_usdhc3_wlan>;
+	pinctrl-1 = <&pinctrl_usdhc3_100mhz>, <&pinctrl_usdhc3_wlan>;
+	pinctrl-2 = <&pinctrl_usdhc3_200mhz>, <&pinctrl_usdhc3_wlan>;
+	pinctrl-3 = <&pinctrl_usdhc3_sleep>, <&pinctrl_usdhc3_wlan>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
+	vmmc-supply = <&reg_usdhc3_vmmc>;
+	wakeup-source;
+	status = "okay";
+};
+
+&wdog3 {
+	fsl,ext-reset-output;
+	status = "okay";
+};
+
+&iomuxc {
+	bootph-pre-ram;
+	bootph-some-ram;
+
+	pinctrl_eqos: eqosgrp {
+		fsl,pins = <
+			MX91_PAD_ENET1_MDC__ENET1_MDC				0x57e
+			MX91_PAD_ENET1_MDIO__ENET_QOS_MDIO			0x57e
+			MX91_PAD_ENET1_RD0__ENET_QOS_RGMII_RD0			0x57e
+			MX91_PAD_ENET1_RD1__ENET_QOS_RGMII_RD1			0x57e
+			MX91_PAD_ENET1_RD2__ENET_QOS_RGMII_RD2			0x57e
+			MX91_PAD_ENET1_RD3__ENET_QOS_RGMII_RD3			0x57e
+			MX91_PAD_ENET1_RXC__ENET_QOS_RGMII_RXC			0x5fe
+			MX91_PAD_ENET1_RX_CTL__ENET_QOS_RGMII_RX_CTL		0x57e
+			MX91_PAD_ENET1_TD0__ENET_QOS_RGMII_TD0			0x57e
+			MX91_PAD_ENET1_TD1__ENET1_RGMII_TD1			0x57e
+			MX91_PAD_ENET1_TD2__ENET_QOS_RGMII_TD2			0x57e
+			MX91_PAD_ENET1_TD3__ENET_QOS_RGMII_TD3			0x57e
+			MX91_PAD_ENET1_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK	0x5fe
+			MX91_PAD_ENET1_TX_CTL__ENET_QOS_RGMII_TX_CTL		0x57e
+		>;
+	};
+
+	pinctrl_eqos_sleep: eqossleepgrp {
+		fsl,pins = <
+			MX91_PAD_ENET1_MDC__GPIO4_IO0				0x31e
+			MX91_PAD_ENET1_MDIO__GPIO4_IO1				0x31e
+			MX91_PAD_ENET1_RD0__GPIO4_IO10				0x31e
+			MX91_PAD_ENET1_RD1__GPIO4_IO11				0x31e
+			MX91_PAD_ENET1_RD2__GPIO4_IO12				0x31e
+			MX91_PAD_ENET1_RD3__GPIO4_IO13				0x31e
+			MX91_PAD_ENET1_RXC__GPIO4_IO9				0x31e
+			MX91_PAD_ENET1_RX_CTL__GPIO4_IO8			0x31e
+			MX91_PAD_ENET1_TD0__GPIO4_IO5				0x31e
+			MX91_PAD_ENET1_TD1__GPIO4_IO4				0x31e
+			MX91_PAD_ENET1_TD2__GPIO4_IO3				0x31e
+			MX91_PAD_ENET1_TD3__GPIO4_IO2				0x31e
+			MX91_PAD_ENET1_TXC__GPIO4_IO7				0x31e
+			MX91_PAD_ENET1_TX_CTL__GPIO4_IO6			0x31e
+		>;
+	};
+
+	pinctrl_fec: fecgrp {
+		fsl,pins = <
+			MX91_PAD_ENET2_MDC__ENET2_MDC				0x57e
+			MX91_PAD_ENET2_MDIO__ENET2_MDIO				0x57e
+			MX91_PAD_ENET2_RD0__ENET2_RGMII_RD0			0x57e
+			MX91_PAD_ENET2_RD1__ENET2_RGMII_RD1			0x57e
+			MX91_PAD_ENET2_RD2__ENET2_RGMII_RD2			0x57e
+			MX91_PAD_ENET2_RD3__ENET2_RGMII_RD3			0x57e
+			MX91_PAD_ENET2_RXC__ENET2_RGMII_RXC			0x5fe
+			MX91_PAD_ENET2_RX_CTL__ENET2_RGMII_RX_CTL		0x57e
+			MX91_PAD_ENET2_TD0__ENET2_RGMII_TD0			0x57e
+			MX91_PAD_ENET2_TD1__ENET2_RGMII_TD1			0x57e
+			MX91_PAD_ENET2_TD2__ENET2_RGMII_TD2			0x57e
+			MX91_PAD_ENET2_TD3__ENET2_RGMII_TD3			0x57e
+			MX91_PAD_ENET2_TXC__ENET2_RGMII_TXC			0x5fe
+			MX91_PAD_ENET2_TX_CTL__ENET2_RGMII_TX_CTL		0x57e
+		>;
+	};
+
+	pinctrl_fec_sleep: fecsleepgrp {
+		fsl,pins = <
+			MX91_PAD_ENET2_MDC__GPIO4_IO14				0x51e
+			MX91_PAD_ENET2_MDIO__GPIO4_IO15				0x51e
+			MX91_PAD_ENET2_RD0__GPIO4_IO24				0x51e
+			MX91_PAD_ENET2_RD1__GPIO4_IO25				0x51e
+			MX91_PAD_ENET2_RD2__GPIO4_IO26				0x51e
+			MX91_PAD_ENET2_RD3__GPIO4_IO27				0x51e
+			MX91_PAD_ENET2_RXC__GPIO4_IO23				0x51e
+			MX91_PAD_ENET2_RX_CTL__GPIO4_IO22			0x51e
+			MX91_PAD_ENET2_TD0__GPIO4_IO19				0x51e
+			MX91_PAD_ENET2_TD1__GPIO4_IO18				0x51e
+			MX91_PAD_ENET2_TD2__GPIO4_IO17				0x51e
+			MX91_PAD_ENET2_TD3__GPIO4_IO16				0x51e
+			MX91_PAD_ENET2_TXC__GPIO4_IO21				0x51e
+			MX91_PAD_ENET2_TX_CTL__GPIO4_IO20			0x51e
+		>;
+	};
+
+	pinctrl_flexcan2: flexcan2grp {
+		fsl,pins = <
+			MX91_PAD_GPIO_IO25__CAN2_TX				0x139e
+			MX91_PAD_GPIO_IO27__CAN2_RX				0x139e
+		>;
+	};
+
+	pinctrl_flexcan2_sleep: flexcan2sleepgrp {
+		fsl,pins = <
+			MX91_PAD_GPIO_IO25__GPIO2_IO25				0x31e
+			MX91_PAD_GPIO_IO27__GPIO2_IO27				0x31e
+		>;
+	};
+
+	pinctrl_lpi2c1: lpi2c1grp {
+		fsl,pins = <
+			MX91_PAD_I2C1_SCL__LPI2C1_SCL				0x40000b9e
+			MX91_PAD_I2C1_SDA__LPI2C1_SDA				0x40000b9e
+		>;
+		bootph-pre-ram;
+		bootph-some-ram;
+	};
+
+	pinctrl_lpi2c2: lpi2c2grp {
+		fsl,pins = <
+			MX91_PAD_I2C2_SCL__LPI2C2_SCL				0x40000b9e
+			MX91_PAD_I2C2_SDA__LPI2C2_SDA				0x40000b9e
+		>;
+		bootph-pre-ram;
+		bootph-some-ram;
+	};
+
+	pinctrl_lpi2c3: lpi2c3grp {
+		fsl,pins = <
+			MX91_PAD_GPIO_IO28__LPI2C3_SDA				0x40000b9e
+			MX91_PAD_GPIO_IO29__LPI2C3_SCL				0x40000b9e
+		>;
+		bootph-pre-ram;
+		bootph-some-ram;
+	};
+
+	pinctrl_lpspi3: lpspi3grp {
+		fsl,pins = <
+			MX91_PAD_GPIO_IO08__GPIO2_IO8				0x3fe
+			MX91_PAD_GPIO_IO09__LPSPI3_SIN				0x3fe
+			MX91_PAD_GPIO_IO10__LPSPI3_SOUT				0x3fe
+			MX91_PAD_GPIO_IO11__LPSPI3_SCK				0x3fe
+		>;
+	};
+
+	pinctrl_mqs1: mqs1grp {
+		fsl,pins = <
+			MX91_PAD_PDM_CLK__MQS1_LEFT				0x31e
+			MX91_PAD_PDM_BIT_STREAM0__MQS1_RIGHT			0x31e
+		>;
+	};
+
+	pinctrl_pcal6524: pcal6524grp {
+		fsl,pins = <
+			MX91_PAD_CCM_CLKO2__GPIO3_IO27				0x31e
+		>;
+	};
+
+	pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
+		fsl,pins = <
+			MX91_PAD_SD2_RESET_B__GPIO3_IO7				0x31e
+		>;
+		bootph-pre-ram;
+	};
+
+	pinctrl_uart1: uart1grp {
+		fsl,pins = <
+			MX91_PAD_UART1_RXD__LPUART1_RX				0x31e
+			MX91_PAD_UART1_TXD__LPUART1_TX				0x31e
+		>;
+		bootph-pre-ram;
+		bootph-some-ram;
+	};
+
+	pinctrl_uart5: uart5grp {
+		fsl,pins = <
+			MX91_PAD_DAP_TDO_TRACESWO__LPUART5_TX			0x31e
+			MX91_PAD_DAP_TDI__LPUART5_RX				0x31e
+			MX91_PAD_DAP_TMS_SWDIO__LPUART5_RTS_B			0x31e
+			MX91_PAD_DAP_TCLK_SWCLK__LPUART5_CTS_B			0x31e
+		>;
+	};
+
+	pinctrl_usdhc1: usdhc1grp {
+		fsl,pins = <
+			MX91_PAD_SD1_CLK__USDHC1_CLK				0x1582
+			MX91_PAD_SD1_CMD__USDHC1_CMD				0x1382
+			MX91_PAD_SD1_DATA0__USDHC1_DATA0			0x1382
+			MX91_PAD_SD1_DATA1__USDHC1_DATA1			0x1382
+			MX91_PAD_SD1_DATA2__USDHC1_DATA2			0x1382
+			MX91_PAD_SD1_DATA3__USDHC1_DATA3			0x1382
+			MX91_PAD_SD1_DATA4__USDHC1_DATA4			0x1382
+			MX91_PAD_SD1_DATA5__USDHC1_DATA5			0x1382
+			MX91_PAD_SD1_DATA6__USDHC1_DATA6			0x1382
+			MX91_PAD_SD1_DATA7__USDHC1_DATA7			0x1382
+			MX91_PAD_SD1_STROBE__USDHC1_STROBE			0x1582
+		>;
+		bootph-pre-ram;
+		bootph-some-ram;
+	};
+
+	pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp {
+		fsl,pins = <
+			MX91_PAD_SD1_CLK__USDHC1_CLK				0x158e
+			MX91_PAD_SD1_CMD__USDHC1_CMD				0x138e
+			MX91_PAD_SD1_DATA0__USDHC1_DATA0			0x138e
+			MX91_PAD_SD1_DATA1__USDHC1_DATA1			0x138e
+			MX91_PAD_SD1_DATA2__USDHC1_DATA2			0x138e
+			MX91_PAD_SD1_DATA3__USDHC1_DATA3			0x138e
+			MX91_PAD_SD1_DATA4__USDHC1_DATA4			0x138e
+			MX91_PAD_SD1_DATA5__USDHC1_DATA5			0x138e
+			MX91_PAD_SD1_DATA6__USDHC1_DATA6			0x138e
+			MX91_PAD_SD1_DATA7__USDHC1_DATA7			0x138e
+			MX91_PAD_SD1_STROBE__USDHC1_STROBE			0x158e
+		>;
+	};
+
+	pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp {
+		fsl,pins = <
+			MX91_PAD_SD1_CLK__USDHC1_CLK				0x15fe
+			MX91_PAD_SD1_CMD__USDHC1_CMD				0x13fe
+			MX91_PAD_SD1_DATA0__USDHC1_DATA0			0x13fe
+			MX91_PAD_SD1_DATA1__USDHC1_DATA1			0x13fe
+			MX91_PAD_SD1_DATA2__USDHC1_DATA2			0x13fe
+			MX91_PAD_SD1_DATA3__USDHC1_DATA3			0x13fe
+			MX91_PAD_SD1_DATA4__USDHC1_DATA4			0x13fe
+			MX91_PAD_SD1_DATA5__USDHC1_DATA5			0x13fe
+			MX91_PAD_SD1_DATA6__USDHC1_DATA6			0x13fe
+			MX91_PAD_SD1_DATA7__USDHC1_DATA7			0x13fe
+			MX91_PAD_SD1_STROBE__USDHC1_STROBE			0x15fe
+		>;
+	};
+
+	pinctrl_usdhc2_gpio: usdhc2gpiogrp {
+		fsl,pins = <
+			MX91_PAD_SD2_CD_B__GPIO3_IO0				0x31e
+		>;
+		bootph-pre-ram;
+		bootph-some-ram;
+	};
+
+	pinctrl_usdhc2_gpio_sleep: usdhc2gpiosleepgrp {
+		fsl,pins = <
+			MX91_PAD_SD2_CD_B__GPIO3_IO0				0x51e
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			MX91_PAD_SD2_CLK__USDHC2_CLK				0x1582
+			MX91_PAD_SD2_CMD__USDHC2_CMD				0x1382
+			MX91_PAD_SD2_DATA0__USDHC2_DATA0			0x1382
+			MX91_PAD_SD2_DATA1__USDHC2_DATA1			0x1382
+			MX91_PAD_SD2_DATA2__USDHC2_DATA2			0x1382
+			MX91_PAD_SD2_DATA3__USDHC2_DATA3			0x1382
+			MX91_PAD_SD2_VSELECT__USDHC2_VSELECT			0x51e
+		>;
+		bootph-pre-ram;
+		bootph-some-ram;
+	};
+
+	pinctrl_usdhc2_sleep: usdhc2sleepgrp {
+		fsl,pins = <
+			MX91_PAD_SD2_CLK__GPIO3_IO1				0x51e
+			MX91_PAD_SD2_CMD__GPIO3_IO2				0x51e
+			MX91_PAD_SD2_DATA0__GPIO3_IO3				0x51e
+			MX91_PAD_SD2_DATA1__GPIO3_IO4				0x51e
+			MX91_PAD_SD2_DATA2__GPIO3_IO5				0x51e
+			MX91_PAD_SD2_DATA3__GPIO3_IO6				0x51e
+			MX91_PAD_SD2_VSELECT__GPIO3_IO19			0x51e
+		>;
+	};
+
+	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+		fsl,pins = <
+			MX91_PAD_SD2_CLK__USDHC2_CLK				0x158e
+			MX91_PAD_SD2_CMD__USDHC2_CMD				0x138e
+			MX91_PAD_SD2_DATA0__USDHC2_DATA0			0x138e
+			MX91_PAD_SD2_DATA1__USDHC2_DATA1			0x138e
+			MX91_PAD_SD2_DATA2__USDHC2_DATA2			0x138e
+			MX91_PAD_SD2_DATA3__USDHC2_DATA3			0x138e
+			MX91_PAD_SD2_VSELECT__USDHC2_VSELECT			0x51e
+		>;
+	};
+
+	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+		fsl,pins = <
+			MX91_PAD_SD2_CLK__USDHC2_CLK				0x15fe
+			MX91_PAD_SD2_CMD__USDHC2_CMD				0x13fe
+			MX91_PAD_SD2_DATA0__USDHC2_DATA0			0x13fe
+			MX91_PAD_SD2_DATA1__USDHC2_DATA1			0x13fe
+			MX91_PAD_SD2_DATA2__USDHC2_DATA2			0x13fe
+			MX91_PAD_SD2_DATA3__USDHC2_DATA3			0x13fe
+			MX91_PAD_SD2_VSELECT__USDHC2_VSELECT			0x51e
+		>;
+	};
+
+	pinctrl_usdhc3: usdhc3grp {
+		fsl,pins = <
+			MX91_PAD_SD3_CLK__USDHC3_CLK				0x1582
+			MX91_PAD_SD3_CMD__USDHC3_CMD				0x1382
+			MX91_PAD_SD3_DATA0__USDHC3_DATA0			0x1382
+			MX91_PAD_SD3_DATA1__USDHC3_DATA1			0x1382
+			MX91_PAD_SD3_DATA2__USDHC3_DATA2			0x1382
+			MX91_PAD_SD3_DATA3__USDHC3_DATA3			0x1382
+		>;
+	};
+
+	pinctrl_usdhc3_sleep: usdhc3sleepgrp {
+		fsl,pins = <
+			MX91_PAD_SD3_CLK__GPIO3_IO20				0x31e
+			MX91_PAD_SD3_CMD__GPIO3_IO21				0x31e
+			MX91_PAD_SD3_DATA0__GPIO3_IO22				0x31e
+			MX91_PAD_SD3_DATA1__GPIO3_IO23				0x31e
+			MX91_PAD_SD3_DATA2__GPIO3_IO24				0x31e
+			MX91_PAD_SD3_DATA3__GPIO3_IO25				0x31e
+		>;
+	};
+
+	pinctrl_usdhc3_wlan: usdhc3wlangrp {
+		fsl,pins = <
+			MX91_PAD_CCM_CLKO1__GPIO3_IO26				0x31e
+		>;
+	};
+
+	pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp {
+		fsl,pins = <
+			MX91_PAD_SD3_CLK__USDHC3_CLK				0x158e
+			MX91_PAD_SD3_CMD__USDHC3_CMD				0x138e
+			MX91_PAD_SD3_DATA0__USDHC3_DATA0			0x138e
+			MX91_PAD_SD3_DATA1__USDHC3_DATA1			0x138e
+			MX91_PAD_SD3_DATA2__USDHC3_DATA2			0x138e
+			MX91_PAD_SD3_DATA3__USDHC3_DATA3			0x138e
+		>;
+	};
+
+	pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp {
+		fsl,pins = <
+			MX91_PAD_SD3_CLK__USDHC3_CLK				0x15fe
+			MX91_PAD_SD3_CMD__USDHC3_CMD				0x13fe
+			MX91_PAD_SD3_DATA0__USDHC3_DATA0			0x13fe
+			MX91_PAD_SD3_DATA1__USDHC3_DATA1			0x13fe
+			MX91_PAD_SD3_DATA2__USDHC3_DATA2			0x13fe
+			MX91_PAD_SD3_DATA3__USDHC3_DATA3			0x13fe
+		>;
+	};
+};

-- 
2.34.1



From zhenglifeng1 at huawei.com  Tue Dec 30 00:01:13 2025
From: zhenglifeng1 at huawei.com (Lifeng Zheng)
Date: Tue, 30 Dec 2025 16:01:13 +0800
Subject: [REPOST PATCH v6 1/3] arm64: topology: Skip already covered CPUs when setting freq source
In-Reply-To: <20251230080115.2120612-1-zhenglifeng1@huawei.com>
References: <20251230080115.2120612-1-zhenglifeng1@huawei.com>
Message-ID: <20251230080115.2120612-2-zhenglifeng1@huawei.com>

The scale freq source of the CPUs in 'amu_fie_cpus' mask are already set to
AMU tick before, so in amu_fie_setup(), only the CPUs in the 'cpus' mask
should be set.

Signed-off-by: Lifeng Zheng <zhenglifeng1 at huawei.com>
Reviewed-by: Beata Michalska <beata.michalska at arm.com>
Reviewed-by: Jie Zhan <zhanjie9 at hisilicon.com>
---
 arch/arm64/kernel/topology.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index 5d24dc53799b..cf9bb761af3a 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -272,7 +272,7 @@ static void amu_fie_setup(const struct cpumask *cpus)
 
 	cpumask_or(amu_fie_cpus, amu_fie_cpus, cpus);
 
-	topology_set_scale_freq_source(&amu_sfd, amu_fie_cpus);
+	topology_set_scale_freq_source(&amu_sfd, cpus);
 
 	pr_debug("CPUs[%*pbl]: counters will be used for FIE.",
 		 cpumask_pr_args(cpus));
-- 
2.33.0



From zhenglifeng1 at huawei.com  Tue Dec 30 00:01:14 2025
From: zhenglifeng1 at huawei.com (Lifeng Zheng)
Date: Tue, 30 Dec 2025 16:01:14 +0800
Subject: [REPOST PATCH v6 2/3] cpufreq: Add new helper function returning cpufreq policy
In-Reply-To: <20251230080115.2120612-1-zhenglifeng1@huawei.com>
References: <20251230080115.2120612-1-zhenglifeng1@huawei.com>
Message-ID: <20251230080115.2120612-3-zhenglifeng1@huawei.com>

cpufreq_cpu_get_raw() gets cpufreq policy only if the CPU is in
policy->cpus mask, which means the CPU is already online. But in some
cases, the policy is needed before the CPU is added to cpus mask. Add a
function to get the policy in these cases.

Signed-off-by: Lifeng Zheng <zhenglifeng1 at huawei.com>
Reviewed-by: Rafael J. Wysocki (Intel) <rafael at kernel.org>
Reviewed-by: Jie Zhan <zhanjie9 at hisilicon.com>
---
 drivers/cpufreq/cpufreq.c | 6 ++++++
 include/linux/cpufreq.h   | 5 +++++
 2 files changed, 11 insertions(+)

diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 50dde2980f1b..a7a69f4d7675 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -198,6 +198,12 @@ struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu)
 }
 EXPORT_SYMBOL_GPL(cpufreq_cpu_get_raw);
 
+struct cpufreq_policy *cpufreq_cpu_policy(unsigned int cpu)
+{
+	return per_cpu(cpufreq_cpu_data, cpu);
+}
+EXPORT_SYMBOL_GPL(cpufreq_cpu_policy);
+
 unsigned int cpufreq_generic_get(unsigned int cpu)
 {
 	struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu);
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 0465d1e6f72a..cc894fc38971 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -203,6 +203,7 @@ struct cpufreq_freqs {
 
 #ifdef CONFIG_CPU_FREQ
 struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu);
+struct cpufreq_policy *cpufreq_cpu_policy(unsigned int cpu);
 struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu);
 void cpufreq_cpu_put(struct cpufreq_policy *policy);
 #else
@@ -210,6 +211,10 @@ static inline struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu)
 {
 	return NULL;
 }
+static inline struct cpufreq_policy *cpufreq_cpu_policy(unsigned int cpu)
+{
+	return NULL;
+}
 static inline struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
 {
 	return NULL;
-- 
2.33.0



From zhenglifeng1 at huawei.com  Tue Dec 30 00:01:12 2025
From: zhenglifeng1 at huawei.com (Lifeng Zheng)
Date: Tue, 30 Dec 2025 16:01:12 +0800
Subject: [REPOST PATCH v6 0/3] arm64: topology: Handle AMU FIE setup on CPU hotplug
Message-ID: <20251230080115.2120612-1-zhenglifeng1@huawei.com>

Solve a problem that causes CPUs Setup AMU FIE failed in a corner case,
even though they're eligible.

Changelog:

v6:

 - discard the modifications in cpufreq.c, and instead, make
   supports_scale_freq_counters() checks that at least one CPU in the
   policy supports AMU FIE, instead of all
 - based on Beata's feedback, optimize cpuhp_topology_online() to make it
   more readable
 - use pr_warn instead of WARN_ON to show warning message when the
   freq_counters_valid() check fails in cpuhp_topology_online()
 - modify commit message as Beata and Rafael suggested

v5:

 - add a default implementation for cpufreq_cpu_policy() when
   CONFIG_CPU_FREQ is not defined

v4:

 - change the function's name in patch 2 from
   'cpufreq_cpu_get_raw_no_check' to 'cpufreq_cpu_policy'
 - use only one line in the function body of cpufreq_cpu_policy()
 - use cpus mask instead of related_cpus when calling arch_set_freq_scale()
   in cpufreq.c
 - add a warning when the freq_counters_valid() check fails in
   cpuhp_topology_online()

v3:

 - add a patch to optimize amu_fie_setup()
 - add a patch to add a function to get cpufreq policy without checking if
   the CPU is online
 - discard the reuse of amu_fie_setup() in cpuhp_topology_online() and keep
   all the new logic in cpuhp_topology_online()
 - test only the CPU which is going online in cpuhp_topology_online()
 - when the freq_counters_valid() check fails, not only clear the scale
   freq source but also clear all the related CPUs from amu_fie_cpus mask
 - add some comments

v2:

 - keep init_amu_fie_notifier for setting up AMU FIE when the cpufreq
   policy is being created
 - set up AMU FIE only for online CPUs instead of related_cpus in
   init_amu_fie_callback()
 - check and set all the online CPUs in the same policy when hotplug one
 - clear scale freq source for all the online CPUs in the same policy to
   avoid using different source of the freq scale

---
Discussions of previous version:
v1: https://lore.kernel.org/all/20250607094533.416368-1-zhenglifeng1 at huawei.com/
v2: https://lore.kernel.org/all/20250725102813.1404322-1-zhenglifeng1 at huawei.com/
v3: https://lore.kernel.org/all/20250805093330.3715444-1-zhenglifeng1 at huawei.com/
v4: https://lore.kernel.org/all/20250814072853.3426386-1-zhenglifeng1 at huawei.com/
v5: https://lore.kernel.org/all/20250819072931.1647431-1-zhenglifeng1 at huawei.com/

Lifeng Zheng (3):
  arm64: topology: Skip already covered CPUs when setting freq source
  cpufreq: Add new helper function returning cpufreq policy
  arm64: topology: Handle AMU FIE setup on CPU hotplug

 arch/arm64/kernel/topology.c | 67 ++++++++++++++++++++++++++++++++++--
 drivers/base/arch_topology.c |  9 ++++-
 drivers/cpufreq/cpufreq.c    |  6 ++++
 include/linux/cpufreq.h      |  5 +++
 4 files changed, 83 insertions(+), 4 deletions(-)

-- 
2.33.0



From zhenglifeng1 at huawei.com  Tue Dec 30 00:01:15 2025
From: zhenglifeng1 at huawei.com (Lifeng Zheng)
Date: Tue, 30 Dec 2025 16:01:15 +0800
Subject: [REPOST PATCH v6 3/3] arm64: topology: Handle AMU FIE setup on CPU hotplug
In-Reply-To: <20251230080115.2120612-1-zhenglifeng1@huawei.com>
References: <20251230080115.2120612-1-zhenglifeng1@huawei.com>
Message-ID: <20251230080115.2120612-4-zhenglifeng1@huawei.com>

Currently, when a cpufreq policy is created, the AMU FIE setup process
checks all CPUs in the policy -- including those that are offline. If any
of these CPUs are offline at that time, their AMU capability flag hasn't
been verified yet, leading the check fail. As a result, AMU FIE is not
enabled, even if the CPUs that are online do support it.

Later, when the previously offline CPUs come online and report AMU support,
there's no mechanism in place to re-enable AMU FIE for the policy. This
leaves the entire frequency domain without AMU FIE, despite being eligible.

Restrict the initial AMU FIE check to only those CPUs that are online at
the time the policy is created, and allow CPUs that come online later to
join the policy with AMU FIE enabled.

Signed-off-by: Lifeng Zheng <zhenglifeng1 at huawei.com>
Acked-by: Beata Michalska <beata.michalska at arm.com>
---
 arch/arm64/kernel/topology.c | 65 ++++++++++++++++++++++++++++++++++--
 drivers/base/arch_topology.c |  9 ++++-
 2 files changed, 71 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index cf9bb761af3a..539b38935182 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -284,7 +284,7 @@ static int init_amu_fie_callback(struct notifier_block *nb, unsigned long val,
 	struct cpufreq_policy *policy = data;
 
 	if (val == CPUFREQ_CREATE_POLICY)
-		amu_fie_setup(policy->related_cpus);
+		amu_fie_setup(policy->cpus);
 
 	/*
 	 * We don't need to handle CPUFREQ_REMOVE_POLICY event as the AMU
@@ -303,10 +303,71 @@ static struct notifier_block init_amu_fie_notifier = {
 	.notifier_call = init_amu_fie_callback,
 };
 
+static int cpuhp_topology_online(unsigned int cpu)
+{
+	struct cpufreq_policy *policy = cpufreq_cpu_policy(cpu);
+
+	/* Those are cheap checks */
+
+	/*
+	 * Skip this CPU if:
+	 *  - it has no cpufreq policy assigned yet,
+	 *  - no policy exists that spans CPUs with AMU counters, or
+	 *  - it was already handled.
+	 */
+	if (unlikely(!policy) || !cpumask_available(amu_fie_cpus) ||
+	    cpumask_test_cpu(cpu, amu_fie_cpus))
+		return 0;
+
+	/*
+	 * Only proceed if all already-online CPUs in this policy
+	 * support AMU counters.
+	 */
+	if (unlikely(!cpumask_subset(policy->cpus, amu_fie_cpus)))
+		return 0;
+
+	/*
+	 * If the new online CPU cannot pass this check, all the CPUs related to
+	 * the same policy should be clear from amu_fie_cpus mask, otherwise they
+	 * may use different source of the freq scale.
+	 */
+	if (!freq_counters_valid(cpu)) {
+		pr_warn("CPU[%u] doesn't support AMU counters\n", cpu);
+		topology_clear_scale_freq_source(SCALE_FREQ_SOURCE_ARCH,
+						 policy->related_cpus);
+		cpumask_andnot(amu_fie_cpus, amu_fie_cpus, policy->related_cpus);
+		return 0;
+	}
+
+	cpumask_set_cpu(cpu, amu_fie_cpus);
+
+	topology_set_scale_freq_source(&amu_sfd, cpumask_of(cpu));
+
+	pr_debug("CPU[%u]: counter will be used for FIE.", cpu);
+
+	return 0;
+}
+
 static int __init init_amu_fie(void)
 {
-	return cpufreq_register_notifier(&init_amu_fie_notifier,
+	int ret;
+
+	ret = cpufreq_register_notifier(&init_amu_fie_notifier,
 					CPUFREQ_POLICY_NOTIFIER);
+	if (ret)
+		return ret;
+
+	ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
+					"arm64/topology:online",
+					cpuhp_topology_online,
+					NULL);
+	if (ret < 0) {
+		cpufreq_unregister_notifier(&init_amu_fie_notifier,
+					    CPUFREQ_POLICY_NOTIFIER);
+		return ret;
+	}
+
+	return 0;
 }
 core_initcall(init_amu_fie);
 
diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
index 84ec92bff642..c0ef6ea9c111 100644
--- a/drivers/base/arch_topology.c
+++ b/drivers/base/arch_topology.c
@@ -34,7 +34,14 @@ EXPORT_PER_CPU_SYMBOL_GPL(capacity_freq_ref);
 
 static bool supports_scale_freq_counters(const struct cpumask *cpus)
 {
-	return cpumask_subset(cpus, &scale_freq_counters_mask);
+	int i;
+
+	for_each_cpu(i, cpus) {
+		if (cpumask_test_cpu(i, &scale_freq_counters_mask))
+			return true;
+	}
+
+	return false;
 }
 
 bool topology_scale_freq_invariant(void)
-- 
2.33.0



From shawnguo at kernel.org  Tue Dec 30 00:04:17 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 16:04:17 +0800
Subject: [PATCH v4 0/6] arm64: dts: imx8mp-var-som: align DTS with
 hardware revision
In-Reply-To: <20251214215256.5812-1-stefano.r@variscite.com>
References: <20251214215256.5812-1-stefano.r@variscite.com>
Message-ID: <aVOHgR1XEo5zqOIz@dragon>

On Sun, Dec 14, 2025 at 10:52:47PM +0100, Stefano Radaelli wrote:
> Stefano Radaelli (6):
>   arm64: dts: imx8mp-var-som: Move USDHC2 support to Symphony carrier
>   arm64: dts: imx8mp-var-som: Move PCA9534 GPIO expander to Symphony
>     carrier
>   arm64: dts: imx8mp-var-som: Move UART2 description to Symphony carrier
>   arm64: dts: imx8mp-var-som: Add WiFi and Bluetooth support
>   arm64: dts: imx8mp-var-som: Add support for WM8904 audio codec
>   arm64: dts: imx8mp-var-som: Add support for TSC2046 touchscreen

Applied all, thanks!


From shawnguo at kernel.org  Tue Dec 30 00:09:09 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 16:09:09 +0800
Subject: [PATCH 1/1] arm64: dts: mba8mx: Fix Ethernet PHY IRQ support
In-Reply-To: <20251216131529.886546-1-alexander.stein@ew.tq-group.com>
References: <20251216131529.886546-1-alexander.stein@ew.tq-group.com>
Message-ID: <aVOIpTeEmhFrs5rO@dragon>

On Tue, Dec 16, 2025 at 02:15:28PM +0100, Alexander Stein wrote:
> Ethernet PHY interrupt mode is level triggered. Adjust the mode
> accordingly.
> 
> Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>

Applied with tag:

  Fixes: 70cf622bb16e ("arm64: dts: mba8mx: Add Ethernet PHY IRQ support")

Shawn


From shawnguo at kernel.org  Tue Dec 30 00:23:20 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 16:23:20 +0800
Subject: [PATCH 1/4] arm64: dts: imx8mm-tqma8mqml: remove virtual 3.3V
 regulator
In-Reply-To: <20251216133110.905950-1-alexander.stein@ew.tq-group.com>
References: <20251216133110.905950-1-alexander.stein@ew.tq-group.com>
Message-ID: <aVOL-NbrSOme1_P9@dragon>

On Tue, Dec 16, 2025 at 02:31:04PM +0100, Alexander Stein wrote:
> From: Markus Niebel <Markus.Niebel at ew.tq-group.com>
> 
> BUCK4 rail supplies the 3.3V rail. Use the actual regulator
> instead of a virtual fixed regulator.
> 
> Signed-off-by: Markus Niebel <Markus.Niebel at ew.tq-group.com>
> Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>

Applied all, thanks!


From shawnguo at kernel.org  Tue Dec 30 00:24:49 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 16:24:49 +0800
Subject: [PATCH 1/3] arm64: dts: imx8mn-tqma8mqnl: remove virtual 3.3V
 regulator
In-Reply-To: <20251216133927.913039-1-alexander.stein@ew.tq-group.com>
References: <20251216133927.913039-1-alexander.stein@ew.tq-group.com>
Message-ID: <aVOMUUfMIgBfn9NR@dragon>

On Tue, Dec 16, 2025 at 02:39:23PM +0100, Alexander Stein wrote:
> From: Markus Niebel <Markus.Niebel at ew.tq-group.com>
> 
> BUCK4 rail supplies the 3.3V rail. Use the actual regulator
> instead of a virtual fixed regulator.
> 
> Signed-off-by: Markus Niebel <Markus.Niebel at ew.tq-group.com>
> Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>

Applied all, thanks!


From shawnguo at kernel.org  Tue Dec 30 00:27:52 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 16:27:52 +0800
Subject: [PATCH 1/1] ARM: imx_v6_v7_defconfig: Configure
 CONFIG_SND_SOC_FSL_ASOC_CARD as module
In-Reply-To: <20251216143522.1064563-1-alexander.stein@ew.tq-group.com>
References: <20251216143522.1064563-1-alexander.stein@ew.tq-group.com>
Message-ID: <aVONCCVuPbfqVPN5@dragon>

On Tue, Dec 16, 2025 at 03:35:21PM +0100, Alexander Stein wrote:
> This option explicitly selects other options, e.g. SND_SOC_FSL_SAI.
> These SAI drivers use DMA which in turn is dependent on CONFIG_IMX_SDMA.
> SDMA needs a firmware which is not yet present if the driver is built-in.
> Thus build CONFIG_SND_SOC_FSL_ASOC_CARD to avoid useless driver probe
> deferrals due to missing DMA channels.
> 
> Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>

Applied, thanks!


From shawnguo at kernel.org  Tue Dec 30 00:30:35 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 16:30:35 +0800
Subject: [PATCH 1/1] arm64: dts: mb-smarc-2: Add PCIe support
In-Reply-To: <20251217084806.41853-1-alexander.stein@ew.tq-group.com>
References: <20251217084806.41853-1-alexander.stein@ew.tq-group.com>
Message-ID: <aVONq0pHbzhQABZ0@dragon>

On Wed, Dec 17, 2025 at 09:48:04AM +0100, Alexander Stein wrote:
> TQMa8XxS on MB-SMARC-2 supports mPCIe on X44.
> 
> Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>

Applied, thanks!


From shawnguo at kernel.org  Tue Dec 30 00:39:43 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 16:39:43 +0800
Subject: [PATCH v4 0/2] Add devicetree for NXP i.MX93 FRDM board
In-Reply-To: <20251218-fpg-nxp-imx93-frdm-v4-0-cd3a9f6ac89a@pengutronix.de>
References: <20251218-fpg-nxp-imx93-frdm-v4-0-cd3a9f6ac89a@pengutronix.de>
Message-ID: <aVOPz3LOrLHqOM-w@dragon>

On Thu, Dec 18, 2025 at 12:39:20PM +0100, Fabian Pflug wrote:
> Fabian Pflug (2):
>       dt-bindings: arm: fsl: add i.MX93 11x11 FRDM board
>       arm64: dts: freescale: add support for NXP i.MX93 FRDM

Applied both, thanks!


From shawnguo at kernel.org  Tue Dec 30 00:45:53 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 16:45:53 +0800
Subject: [PATCH] arm64: boot: dts: imx8mm-phycore-som: Update eth phy
 impedance
In-Reply-To: <20251218-wip-t-remmet-phytec-de-bspimx8m-3841_upstream-v1-1-2ea15181aaf2@phytec.de>
References: <20251218-wip-t-remmet-phytec-de-bspimx8m-3841_upstream-v1-1-2ea15181aaf2@phytec.de>
Message-ID: <aVORQQlMpbgonBlw@dragon>

On Thu, Dec 18, 2025 at 01:00:06PM +0100, Teresa Remmet wrote:
> Update the DP83867 ethernet phy impedance settings to
> to optimize signal quality and reduce potential signal integrity issues.
> 
> Signed-off-by: Teresa Remmet <t.remmet at phytec.de>

Subject prefix "arm64: dts: imx8mm-phycore-som: ..." is good enough.

I fixed it up and applied the patch.

Shawn


From coxu at redhat.com  Tue Dec 30 00:48:14 2025
From: coxu at redhat.com (Coiby Xu)
Date: Tue, 30 Dec 2025 16:48:14 +0800
Subject: [PATCH] arm64/kdump: pass dm-crypt keys to kdump kernel
In-Reply-To: <20251227-funky-swallow-from-pluto-910b9d@quoll>
References: <20251226141116.1379601-1-coxu@redhat.com>
 <20251227-funky-swallow-from-pluto-910b9d@quoll>
Message-ID: <aVIR84RJSv42YEP1@Rk>

Hi Krzysztof,

Thanks for your prompt feedback!

On Sat, Dec 27, 2025 at 02:14:16PM +0100, Krzysztof Kozlowski wrote:
>On Fri, Dec 26, 2025 at 10:11:15PM +0800, Coiby Xu wrote:
>> Based on the CONFIG_CRASH_DM_CRYPT feature, this patch adds
>
>Don't use "this patch". See submitting patches.

I'll use imperative mood in next version, thanks for the reminder!

>
>> LUKS-encrypted device dump target support to ARM64 by addressing two
>> challenges [1],
>
>
>...
>
>> +static void __init early_init_dt_check_for_dmcryptkeys(unsigned long node)
>> +{
>> +	const __be32 *prop;
>> +
>> +	if (!IS_ENABLED(CONFIG_CRASH_DM_CRYPT))
>> +		return;
>> +
>> +	pr_debug("Looking for dmcryptkeys property... ");
>> +
>> +	prop = of_get_flat_dt_prop(node, "linux,dmcryptkeys", NULL);
>
>Where did you document the ABI?

Thanks for raising the concern! I'll send a PR to  
https://github.com/devicetree-org/dt-schema
and include the link in next version.

>
>
>Best regards,
>Krzysztof
>
>

-- 
Best regards,
Coiby



From kernel at airkyi.com  Tue Dec 30 01:02:46 2025
From: kernel at airkyi.com (Chaoyi Chen)
Date: Tue, 30 Dec 2025 17:02:46 +0800
Subject: [PATCH] arm64: dts: rockchip: Fix wrong register range of rk3576 gpu
Message-ID: <20251230090246.46-1-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

According to RK3576 TRM part1 page13, the size of the GPU registers
is 128 KB.

Fixes: 57b1ce903966 ("arm64: dts: rockchip: Add rk3576 SoC base DT")
Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
---
 arch/arm64/boot/dts/rockchip/rk3576.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3576.dtsi b/arch/arm64/boot/dts/rockchip/rk3576.dtsi
index 6284e7bdc442..b375015f0662 100644
--- a/arch/arm64/boot/dts/rockchip/rk3576.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3576.dtsi
@@ -1271,7 +1271,7 @@ power-domain at RK3576_PD_VO1 {
 
 		gpu: gpu at 27800000 {
 			compatible = "rockchip,rk3576-mali", "arm,mali-bifrost";
-			reg = <0x0 0x27800000 0x0 0x200000>;
+			reg = <0x0 0x27800000 0x0 0x20000>;
 			assigned-clocks = <&scmi_clk SCMI_CLK_GPU>;
 			assigned-clock-rates = <198000000>;
 			clocks = <&cru CLK_GPU>;
-- 
2.51.1



From tianruidong at linux.alibaba.com  Tue Dec 30 01:09:28 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Tue, 30 Dec 2025 17:09:28 +0800
Subject: [PATCH v5 00/17] ARM Error Source Table V2 Support
Message-ID: <20251230090945.43969-1-tianruidong@linux.alibaba.com>

This series introduces support for the ARM Error Source Table (AEST), aligning
with version 2.0 of ACPI for Armv8 RAS Extensions [0].

AEST provides a critical mechanism for hardware to directly notify the
operating system kernel about RAS errors via interrupts, a concept known as
Kernel-first error handling. Compared to firmware-first error handling
(e.g., GHES), AEST offers a more lightweight approach. This efficiency allows
the OS to potentially report every Corrected Error (CE), enabling upper-layer
applications to leverage CE information for error prediction[1][2].

This series is based on Tyler Baicar's preliminary patches [3], which have not
yet been sent to the mailing list as v2.

AEST Driver Architecture
========================

The AEST driver is structured into three primary components:
  - AEST device: Responsible for handling interrupts, managing the lifecycle
                 of AEST nodes, and processing error records.
  - AEST node: Corresponds directly to a RAS node in the hardware
  - AEST record: Represents a set of RAS registers associated with a specific
                 error source.

These components are organized hierarchically as follows:

 ????????????????????????????????????????????????????
 ?             AEST Driver Device Management        ?
 ????????????????    ????????????     ????????????? ?
 ?? AEST Device ??????AEST Node ???????AEST Record? ?
 ???????????????? ?  ????????????  ?  ????????????? ?
 ?                ?       .        ?  ????????????? ?
 ?                ?       .        ????AEST Record? ?
 ?                ?       .        ?  ????????????? ?
 ?                ?  ????????????  ?        .       ?
 ?                ????AEST Node ?  ?        .       ?
 ?                ?  ????????????  ?        .       ?
 ?                ?                ?  ????????????? ?
 ?                ?  ????????????  ????AEST Record? ?
 ?                ????AEST Node ?     ????????????? ?
 ?                   ????????????                   ?
 ????????????????????????????????????????????????????

AEST Interrupt Handle
=====================

Upon an AEST interrupt, the driver performs the following sequence:
1. The AEST device iterates through all registered AEST nodes to identify the
   specific node(s) and record(s) that reported an error.
2. Each node typically contains two types of records:
      - report record: Errors can be located efficiently through a bitmap
                       in the `ERRGSR` register.
      - poll record: The node must individually poll all records to determine
                     if an error has occurred.
3. process record:
      - if error is corrected, The CE threshold is reset, and the error event
        is logged.
      - if error is defered, Relevant registers are dumped, and
        `memory_failure()` is invoked.
      - if error is uncorrected, panic, While UEs typically trigger an
        exception rather than an interrupt, if detected, the system will panic.
4. decode record: The AEST driver notifies other relevant drivers, such as
   EDAC, to further decode the reported RAS register information.

Address Translation
===================

As described in section 2.2 [0], error addresses reported by AEST records
may be "node-specific Logical Addresses" rather than the "System Physical
Addresses" (SPA) used by the kernel. Therefore, the driver needs to translate
these Logical Addresses (LA) to SPA. This translation mechanism is conceptually
similar to AMD's Address Translation Logic (ATL) [4], leading patch 0014 to
introduce a common translation function for both AMD and ARM architectures.

Testing
===================
I have tested this series on THead Yitian710 SOC with customized BIOS. Someone
can also use QEMU[5] for preliminary driver testing.

1. Boot Qemu

qemu-system-aarch64 -smp 4 -m 32G \
  -cpu host --enable-kvm -machine virt,gic-version=3 \
  -kernel Image -initrd initrd.cpio.gz \
  -device virtio-net-pci,netdev=t0 -netdev user,id=t0 \
  -bios /usr/share/edk2/aarch64/QEMU_EFI.fd  \
  -append "rdinit=/sbin/init earlycon verbose debug console=ttyAMA0 aest.dyndbg='+pt'" \
  -nographic -d guest_errors -D qemu.log

2. inject error
devmem 0x90d0808 l 0xc4800390

2.1 Memory error
[   64.959849] AEST: {1}[Hardware Error]: Hardware error from AEST memory.90d0000
[   64.959852] AEST: {1}[Hardware Error]:  Error from memory at SRAT proximity domain 0x0
[   64.959855] AEST: {1}[Hardware Error]:   ERR0FR: 0x40000080044081
[   64.959858] AEST: {1}[Hardware Error]:   ERR0CTRL: 0x108
[   64.959859] AEST: {1}[Hardware Error]:   ERR0STATUS: 0xc4800390
[   64.959860] AEST: {1}[Hardware Error]:   ERR0ADDR: 0x8400000043344521
[   64.959861] AEST: {1}[Hardware Error]:   ERR0MISC0: 0x7fff00000000
[   64.959861] AEST: {1}[Hardware Error]:   ERR0MISC1: 0x0
[   64.959862] AEST: {1}[Hardware Error]:   ERR0MISC2: 0x0
[   64.959863] AEST: {1}[Hardware Error]:   ERR0MISC3: 0x0
[   64.959873] Memory failure: 0x43344: recovery action for free buddy page: Recovered

2.2 CMN error
[  132.044283] AEST: {2}[Hardware Error]: Hardware error from AEST XP
[  132.044286] AEST: {2}[Hardware Error]:  Error from vendor hid ARMHC700 uid 0x0
[  132.044288] AEST: {2}[Hardware Error]:   ERR0FR: 0x48a5
[  132.044290] AEST: {2}[Hardware Error]:   ERR0CTRL: 0x108
[  132.044292] AEST: {2}[Hardware Error]:   ERR0STATUS: 0xc4800390
[  132.044293] AEST: {2}[Hardware Error]:   ERR0ADDR: 0x8400000043344521
[  132.044295] AEST: {2}[Hardware Error]:   ERR0MISC0: 0x0
[  132.044296] AEST: {2}[Hardware Error]:   ERR0MISC1: 0x0
[  132.044298] AEST: {2}[Hardware Error]:   ERR0MISC2: 0x0
[  132.044299] AEST: {2}[Hardware Error]:   ERR0MISC3: 0x0
[  132.044302] Memory failure: 0x43344: recovery action for already poisoned page: Failed

[0]: https://developer.arm.com/documentation/den0085/0101/
[1]: Intel: Predicting Uncorrectable Memory Errors from the Correctable Error History
[2]: Alibaba. Predicting DRAM-Caused Risky VMs in Large-Scale Clouds. Published in HPCA2025
[3]: https://lore.kernel.org/all/20211124170708.3874-1-baicar at os.amperecomputing.com/
[4]: https://lore.kernel.org/all/20240123041401.79812-2-yazen.ghannam at amd.com/
[5]: https://github.com/winterddd/qemu/tree/error_record

Change from V4:
https://lore.kernel.org/all/20251222094351.38792-1-tianruidong at linux.alibaba.com/
1. Fix build warning in 0010 and 0014 report by kernel test robot:
    https://lore.kernel.org/all/202512230122.CfXZcF76-lkp at intel.com/
    https://lore.kernel.org/all/202512230007.Vs6IvFVD-lkp at intel.com/
2. Dropped the extra patch(0014) that was mistakenly included in v4.

Change from V3:
https://lore.kernel.org/all/20250115084228.107573-1-tianruidong at linux.alibaba.com/
1. Add vendor AEST node framework and support CMN700
2. Borislav Petkov
    - Split into multiple smaller patches for easier review.
    - refined the English in the cover letter for better flow.
3. Accept Tomohiro Misono's comment

Change from V2:
https://lore.kernel.org/all/20240321025317.114621-1-tianruidong at linux.alibaba.com/
1. Tomohiro Misono
    - dump register before panic
2. Baolin Wang & Shuai Xue: accept all comment.
3. Support AEST V2.

Change from V1:
https://lore.kernel.org/all/20240304111517.33001-1-tianruidong at linux.alibaba.com/
1. Marc Zyngier
  - Use readq/writeq_relaxed instead of readq/writeq for MMIO address.
  - Add sync for system register operation.
  - Use irq_is_percpu_devid() helper to identify a per-CPU interrupt.
  - Other fix.
2. Set RAS CE threshold in AEST driver.
3. Enable RAS interrupt explicitly in driver.
4. UER and UEO trigger memory_failure other than panic.

Ruidong Tian (17):
  ACPI/AEST: Parse the AEST table
  ras: AEST: Add probe/remove for AEST driver
  ras: AEST: support different group format
  ras: AEST: Unify the read/write interface for system and MMIO register
  ras: AEST: Probe RAS system architecture version
  ras: AEST: Support RAS Common Fault Injection Model Extension
  ras: AEST: Support CE threshold of error record
  ras: AEST: Enable and register IRQs
  ras: AEST: Add cpuhp callback
  ras: AEST: Introduce AEST driver sysfs interface
  ras: AEST: Add error count tracking and debugfs interface
  ras: AEST: Allow configuring CE threshold via debugfs
  ras: AEST: Introduce AEST inject interface to test AEST driver
  ras: ATL: Unify ATL interface for ARM64 and AMD
  ras: AEST: Add framework to process AEST vendor node
  ras: AEST: support vendor node CMN700
  trace, ras: add ARM RAS extension trace event

 Documentation/ABI/testing/debugfs-aest |   99 +++
 MAINTAINERS                            |   11 +
 arch/arm64/include/asm/arm-cmn.h       |   47 ++
 arch/arm64/include/asm/ras.h           |   95 +++
 drivers/acpi/arm64/Kconfig             |   11 +
 drivers/acpi/arm64/Makefile            |    1 +
 drivers/acpi/arm64/aest.c              |  311 +++++++
 drivers/edac/amd64_edac.c              |    2 +-
 drivers/perf/arm-cmn.c                 |   37 +-
 drivers/ras/Kconfig                    |    1 +
 drivers/ras/Makefile                   |    1 +
 drivers/ras/aest/Kconfig               |   17 +
 drivers/ras/aest/Makefile              |    8 +
 drivers/ras/aest/aest-cmn.c            |  332 ++++++++
 drivers/ras/aest/aest-core.c           | 1057 ++++++++++++++++++++++++
 drivers/ras/aest/aest-inject.c         |  131 +++
 drivers/ras/aest/aest-sysfs.c          |  228 +++++
 drivers/ras/aest/aest.h                |  410 +++++++++
 drivers/ras/amd/atl/core.c             |    4 +-
 drivers/ras/amd/atl/internal.h         |    2 +-
 drivers/ras/amd/atl/umc.c              |    5 +-
 drivers/ras/amd/fmpm.c                 |    2 +-
 drivers/ras/ras.c                      |   27 +-
 include/linux/acpi_aest.h              |   75 ++
 include/linux/cpuhotplug.h             |    1 +
 include/linux/ras.h                    |   17 +-
 include/ras/ras_event.h                |   71 ++
 27 files changed, 2942 insertions(+), 61 deletions(-)
 create mode 100644 Documentation/ABI/testing/debugfs-aest
 create mode 100644 arch/arm64/include/asm/arm-cmn.h
 create mode 100644 arch/arm64/include/asm/ras.h
 create mode 100644 drivers/acpi/arm64/aest.c
 create mode 100644 drivers/ras/aest/Kconfig
 create mode 100644 drivers/ras/aest/Makefile
 create mode 100644 drivers/ras/aest/aest-cmn.c
 create mode 100644 drivers/ras/aest/aest-core.c
 create mode 100644 drivers/ras/aest/aest-inject.c
 create mode 100644 drivers/ras/aest/aest-sysfs.c
 create mode 100644 drivers/ras/aest/aest.h
 create mode 100644 include/linux/acpi_aest.h

-- 
2.47.3



From tianruidong at linux.alibaba.com  Tue Dec 30 01:09:29 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Tue, 30 Dec 2025 17:09:29 +0800
Subject: [PATCH v5 01/17] ACPI/AEST: Parse the AEST table
In-Reply-To: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
References: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
Message-ID: <20251230090945.43969-2-tianruidong@linux.alibaba.com>

This patch introduces the creation of AEST platform devices, where each
device represents a logical "error node device" grouping one or more
AEST nodes from the ACPI table.

Instead of relying on the optional 'error_node_device' field in the AEST
table[1], this commit uses the interrupt number as the sole identifier for
the parent device. This design simplifies the driver logic by providing a
single, consistent mechanism for grouping nodes.

The 'error_node_device' field can be unspecified, but an AEST node is
always physically associated with a parent component. The interrupt
number serves as a reliable proxy for this association. This approach
is based on the safe assumption that distinct hardware components (e.g.,
SMMU, CMN, GIC) are assigned unique error interrupts and do not share
them.

[1]: https://developer.arm.com/documentation/den0085/latest

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 MAINTAINERS                  |   8 +
 arch/arm64/include/asm/ras.h |  15 ++
 drivers/acpi/arm64/Kconfig   |  11 ++
 drivers/acpi/arm64/Makefile  |   1 +
 drivers/acpi/arm64/aest.c    | 311 +++++++++++++++++++++++++++++++++++
 include/linux/acpi_aest.h    |  56 +++++++
 6 files changed, 402 insertions(+)
 create mode 100644 arch/arm64/include/asm/ras.h
 create mode 100644 drivers/acpi/arm64/aest.c
 create mode 100644 include/linux/acpi_aest.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 0dbf349fc1ed..8bfb6f049ea5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -341,6 +341,14 @@ S:	Maintained
 F:	drivers/acpi/arm64
 F:	include/linux/acpi_iort.h
 
+ACPI AEST
+M:	Ruidong Tian <tianruidond at linux.alibaba.com>
+L:	linux-acpi at vger.kernel.org
+L:	linux-arm-kernel at lists.infradead.org
+S:	Supported
+F:	drivers/acpi/arm64/aest.c
+F:	include/linux/acpi_aest.h
+
 ACPI FOR RISC-V (ACPI/riscv)
 M:	Sunil V L <sunilvl at ventanamicro.com>
 L:	linux-acpi at vger.kernel.org
diff --git a/arch/arm64/include/asm/ras.h b/arch/arm64/include/asm/ras.h
new file mode 100644
index 000000000000..b6640b9972bf
--- /dev/null
+++ b/arch/arm64/include/asm/ras.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_RAS_H
+#define __ASM_RAS_H
+
+#include <linux/types.h>
+
+struct ras_ext_regs {
+	u64 err_fr;
+	u64 err_ctlr;
+	u64 err_status;
+	u64 err_addr;
+	u64 err_misc[4];
+};
+
+#endif /* __ASM_RAS_H */
diff --git a/drivers/acpi/arm64/Kconfig b/drivers/acpi/arm64/Kconfig
index f2fd79f22e7d..52df190356c8 100644
--- a/drivers/acpi/arm64/Kconfig
+++ b/drivers/acpi/arm64/Kconfig
@@ -24,3 +24,14 @@ config ACPI_APMT
 
 config ACPI_MPAM
 	bool
+
+config ACPI_AEST
+	bool "ARM Error Source Table Support"
+	depends on ARM64_RAS_EXTN
+
+	help
+	  The Arm Error Source Table (AEST) provides details on ACPI
+	  extensions that enable kernel-first handling of errors in a
+	  system that supports the Armv8 RAS extensions.
+
+	  If set, the kernel will report and log hardware errors.
diff --git a/drivers/acpi/arm64/Makefile b/drivers/acpi/arm64/Makefile
index 9390b57cb564..bad77fdbf8dd 100644
--- a/drivers/acpi/arm64/Makefile
+++ b/drivers/acpi/arm64/Makefile
@@ -7,5 +7,6 @@ obj-$(CONFIG_ACPI_IORT) 	+= iort.o
 obj-$(CONFIG_ACPI_MPAM) 	+= mpam.o
 obj-$(CONFIG_ACPI_PROCESSOR_IDLE) += cpuidle.o
 obj-$(CONFIG_ARM_AMBA)		+= amba.o
+obj-$(CONFIG_ACPI_AEST) 	+= aest.o
 obj-y				+= dma.o init.o
 obj-y				+= thermal_cpufreq.o
diff --git a/drivers/acpi/arm64/aest.c b/drivers/acpi/arm64/aest.c
new file mode 100644
index 000000000000..b8359b95f40f
--- /dev/null
+++ b/drivers/acpi/arm64/aest.c
@@ -0,0 +1,311 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ARM Error Source Table Support
+ *
+ * Copyright (c) 2025, Alibaba Group.
+ */
+
+#include <linux/xarray.h>
+#include <linux/platform_device.h>
+#include <linux/acpi_aest.h>
+
+#include "init.h"
+
+#undef pr_fmt
+#define pr_fmt(fmt) "ACPI AEST: " fmt
+
+static struct xarray *aest_array;
+
+static void __init aest_init_interface(struct acpi_aest_hdr *hdr,
+				       struct acpi_aest_node *node)
+{
+	struct acpi_aest_node_interface_header *interface;
+
+	interface = ACPI_ADD_PTR(struct acpi_aest_node_interface_header, hdr,
+				 hdr->node_interface_offset);
+
+	node->type = hdr->type;
+	node->interface_hdr = interface;
+
+	switch (interface->group_format) {
+	case ACPI_AEST_NODE_GROUP_FORMAT_4K: {
+		struct acpi_aest_node_interface_4k *interface_4k =
+			(struct acpi_aest_node_interface_4k *)(interface + 1);
+
+		node->common = &interface_4k->common;
+		node->record_implemented =
+			(unsigned long *)&interface_4k->error_record_implemented;
+		node->status_reporting =
+			(unsigned long *)&interface_4k->error_status_reporting;
+		node->addressing_mode =
+			(unsigned long *)&interface_4k->addressing_mode;
+		break;
+	}
+	case ACPI_AEST_NODE_GROUP_FORMAT_16K: {
+		struct acpi_aest_node_interface_16k *interface_16k =
+			(struct acpi_aest_node_interface_16k *)(interface + 1);
+
+		node->common = &interface_16k->common;
+		node->record_implemented =
+			(unsigned long *)interface_16k->error_record_implemented;
+		node->status_reporting =
+			(unsigned long *)interface_16k->error_status_reporting;
+		node->addressing_mode =
+			(unsigned long *)interface_16k->addressing_mode;
+		break;
+	}
+	case ACPI_AEST_NODE_GROUP_FORMAT_64K: {
+		struct acpi_aest_node_interface_64k *interface_64k =
+			(struct acpi_aest_node_interface_64k *)(interface + 1);
+
+		node->common = &interface_64k->common;
+		node->record_implemented =
+			(unsigned long *)interface_64k->error_record_implemented;
+		node->status_reporting =
+			(unsigned long *)interface_64k->error_status_reporting;
+		node->addressing_mode =
+			(unsigned long *)interface_64k->addressing_mode;
+		break;
+	}
+	default:
+		pr_err("invalid group format: %d\n", interface->group_format);
+	}
+
+	node->interrupt = ACPI_ADD_PTR(struct acpi_aest_node_interrupt_v2, hdr,
+				       hdr->node_interrupt_offset);
+
+	node->interrupt_count = hdr->node_interrupt_count;
+}
+
+static struct aest_hnode *__init
+acpi_aest_alloc_ahnode(struct acpi_aest_node *node, u64 error_device_id)
+{
+	struct aest_hnode *ahnode __free(kfree) = NULL;
+
+	ahnode = kzalloc(sizeof(*ahnode), GFP_KERNEL);
+	if (!ahnode)
+		return NULL;
+
+	INIT_LIST_HEAD(&ahnode->list);
+	ahnode->id = error_device_id;
+	ahnode->count = 0;
+	ahnode->type = node->type;
+
+	return_ptr(ahnode);
+}
+static int __init acpi_aest_init_node(struct acpi_aest_hdr *aest_hdr)
+{
+	struct aest_hnode *ahnode;
+	u64 error_device_id;
+	struct acpi_aest_node *node;
+
+	node = kzalloc(sizeof(*node), GFP_KERNEL);
+	if (!node)
+		return -ENOMEM;
+
+	node->spec_pointer =
+		ACPI_ADD_PTR(void, aest_hdr, aest_hdr->node_specific_offset);
+	if (aest_hdr->type == ACPI_AEST_PROCESSOR_ERROR_NODE)
+		node->processor_spec_pointer =
+			ACPI_ADD_PTR(void, node->spec_pointer,
+				     sizeof(struct acpi_aest_processor));
+
+	aest_init_interface(aest_hdr, node);
+
+	if (node->interrupt_count <= 0)
+		return -EINVAL;
+
+	error_device_id = node->interrupt[0].gsiv;
+	ahnode = xa_load(aest_array, error_device_id);
+	if (!ahnode) {
+		ahnode = acpi_aest_alloc_ahnode(node, error_device_id);
+		if (!ahnode)
+			return -ENOMEM;
+		xa_store(aest_array, error_device_id, ahnode, GFP_KERNEL);
+	}
+
+	list_add_tail(&node->list, &ahnode->list);
+	ahnode->count++;
+
+	return 0;
+}
+
+static int __init acpi_aest_init_nodes(struct acpi_table_header *aest_table)
+{
+	struct acpi_aest_hdr *aest_node, *aest_end;
+	struct acpi_table_aest *aest;
+	int rc;
+
+	aest = (struct acpi_table_aest *)aest_table;
+	aest_node = ACPI_ADD_PTR(struct acpi_aest_hdr, aest,
+				 sizeof(struct acpi_table_header));
+	aest_end = ACPI_ADD_PTR(struct acpi_aest_hdr, aest, aest_table->length);
+
+	while (aest_node < aest_end) {
+		if (((u64)aest_node + aest_node->length) > (u64)aest_end) {
+			pr_warn(FW_WARN
+				"AEST node pointer overflow, bad table.\n");
+			return -EINVAL;
+		}
+
+		rc = acpi_aest_init_node(aest_node);
+		if (rc)
+			return rc;
+
+		aest_node = ACPI_ADD_PTR(struct acpi_aest_hdr, aest_node,
+					 aest_node->length);
+	}
+
+	return 0;
+}
+
+static int acpi_aest_parse_irqs(struct platform_device *pdev,
+				struct acpi_aest_node *anode,
+				struct resource *res, int *res_idx, int irqs[2])
+{
+	int i;
+	struct acpi_aest_node_interrupt_v2 *interrupt;
+	int trigger, irq;
+
+	for (i = 0; i < anode->interrupt_count; i++) {
+		interrupt = &anode->interrupt[i];
+		if (irqs[interrupt->type])
+			continue;
+
+		trigger = (interrupt->flags & AEST_INTERRUPT_MODE) ?
+				  ACPI_LEVEL_SENSITIVE :
+				  ACPI_EDGE_SENSITIVE;
+
+		irq = acpi_register_gsi(&pdev->dev, interrupt->gsiv, trigger,
+					ACPI_ACTIVE_HIGH);
+		if (irq <= 0) {
+			pr_err("failed to map AEST GSI %d\n", interrupt->gsiv);
+			return irq;
+		}
+
+		res[*res_idx].start = irq;
+		res[*res_idx].end = irq;
+		res[*res_idx].flags = IORESOURCE_IRQ;
+		res[*res_idx].name = interrupt->type ? AEST_ERI_NAME :
+						       AEST_FHI_NAME;
+
+		(*res_idx)++;
+
+		irqs[interrupt->type] = irq;
+	}
+
+	return 0;
+}
+
+DEFINE_FREE(res, struct resource *, if (_T) kfree(_T))
+static struct platform_device *__init
+acpi_aest_alloc_pdev(struct aest_hnode *ahnode, int index)
+{
+	struct platform_device *pdev __free(platform_device_put) =
+		platform_device_alloc("AEST", index++);
+	struct resource *res __free(res);
+	struct acpi_aest_node *anode;
+	int ret, size, j, irq[AEST_MAX_INTERRUPT_PER_NODE] = { 0 };
+
+	if (!pdev)
+		return ERR_PTR(-ENOMEM);
+
+	res = kcalloc(ahnode->count + AEST_MAX_INTERRUPT_PER_NODE, sizeof(*res),
+		      GFP_KERNEL);
+	if (!res)
+		return ERR_PTR(-ENOMEM);
+
+	j = 0;
+	list_for_each_entry(anode, &ahnode->list, list) {
+		if (anode->interface_hdr->type !=
+		    ACPI_AEST_NODE_SYSTEM_REGISTER) {
+			res[j].name = AEST_NODE_NAME;
+			res[j].start = anode->interface_hdr->address;
+			switch (anode->interface_hdr->group_format) {
+			case ACPI_AEST_NODE_GROUP_FORMAT_4K:
+				size = 4 * KB;
+				break;
+			case ACPI_AEST_NODE_GROUP_FORMAT_16K:
+				size = 16 * KB;
+				break;
+			case ACPI_AEST_NODE_GROUP_FORMAT_64K:
+				size = 64 * KB;
+				break;
+			default:
+				size = 4 * KB;
+			}
+			res[j].end = res[j].start + size - 1;
+			res[j].flags = IORESOURCE_MEM;
+		}
+
+		ret = acpi_aest_parse_irqs(pdev, anode, res, &j, irq);
+		if (ret)
+			return ERR_PTR(ret);
+	}
+
+	ret = platform_device_add_resources(pdev, res, j);
+	if (ret)
+		return ERR_PTR(ret);
+
+	ret = platform_device_add_data(pdev, &ahnode, sizeof(ahnode));
+	if (ret)
+		return ERR_PTR(ret);
+
+	ret = platform_device_add(pdev);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return_ptr(pdev);
+}
+static int __init acpi_aest_alloc_pdevs(void)
+{
+	int ret = 0, index = 0;
+	struct aest_hnode *ahnode = NULL;
+	unsigned long i;
+
+	xa_for_each(aest_array, i, ahnode) {
+		struct platform_device *pdev =
+			acpi_aest_alloc_pdev(ahnode, index++);
+
+		if (IS_ERR(pdev)) {
+			ret = PTR_ERR(pdev);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int __init acpi_aest_init(void)
+{
+	int ret;
+
+	if (acpi_disabled)
+		return 0;
+
+	struct acpi_table_header *aest_table __free(acpi_put_table) =
+		acpi_get_table_pointer(ACPI_SIG_AEST, 0);
+	if (IS_ERR(aest_table))
+		return 0;
+
+	aest_array = kzalloc(sizeof(struct xarray), GFP_KERNEL);
+	if (!aest_array)
+		return -ENOMEM;
+
+	xa_init(aest_array);
+
+	ret = acpi_aest_init_nodes(aest_table);
+	if (ret) {
+		pr_err("Failed init aest node %d\n", ret);
+		return ret;
+	}
+
+	ret = acpi_aest_alloc_pdevs();
+	if (ret) {
+		pr_err("Failed alloc pdev %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+subsys_initcall_sync(acpi_aest_init);
diff --git a/include/linux/acpi_aest.h b/include/linux/acpi_aest.h
new file mode 100644
index 000000000000..53c1970e7583
--- /dev/null
+++ b/include/linux/acpi_aest.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ACPI_AEST_H__
+#define __ACPI_AEST_H__
+
+#include <asm/ras.h>
+#include <linux/acpi.h>
+
+/* AEST resource name */
+#define AEST_NODE_NAME "AEST:NODE"
+#define AEST_FHI_NAME "AEST:FHI"
+#define AEST_ERI_NAME "AEST:ERI"
+
+/* AEST interrupt */
+#define AEST_INTERRUPT_MODE BIT(0)
+
+#define AEST_MAX_INTERRUPT_PER_NODE 2
+
+#define KB 1024
+#define MB (1024 * KB)
+#define GB (1024 * MB)
+
+struct aest_hnode {
+	struct list_head list;
+	int count;
+	u32 id;
+	int type;
+};
+
+struct acpi_aest_node {
+	struct list_head list;
+	int type;
+	struct acpi_aest_node_interface_header *interface_hdr;
+	unsigned long *record_implemented;
+	unsigned long *status_reporting;
+	unsigned long *addressing_mode;
+	struct acpi_aest_node_interface_common *common;
+	union {
+		struct acpi_aest_processor *processor;
+		struct acpi_aest_memory *memory;
+		struct acpi_aest_smmu *smmu;
+		struct acpi_aest_vendor_v2 *vendor;
+		struct acpi_aest_gic *gic;
+		struct acpi_aest_pcie *pcie;
+		struct acpi_aest_proxy *proxy;
+		void *spec_pointer;
+	};
+	union {
+		struct acpi_aest_processor_cache *cache;
+		struct acpi_aest_processor_tlb *tlb;
+		struct acpi_aest_processor_generic *generic;
+		void *processor_spec_pointer;
+	};
+	struct acpi_aest_node_interrupt_v2 *interrupt;
+	int interrupt_count;
+};
+#endif /* __ACPI_AEST_H__ */
-- 
2.47.3



From tianruidong at linux.alibaba.com  Tue Dec 30 01:09:30 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Tue, 30 Dec 2025 17:09:30 +0800
Subject: [PATCH v5 02/17] ras: AEST: Add probe/remove for AEST driver
In-Reply-To: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
References: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
Message-ID: <20251230090945.43969-3-tianruidong@linux.alibaba.com>

Parse register information from the AEST table in the probe function,
create corresponding structures, and mappings AEST record.

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 MAINTAINERS                  |   2 +
 drivers/ras/Kconfig          |   1 +
 drivers/ras/Makefile         |   1 +
 drivers/ras/aest/Kconfig     |  17 +++
 drivers/ras/aest/Makefile    |   5 +
 drivers/ras/aest/aest-core.c | 217 +++++++++++++++++++++++++++++++++++
 drivers/ras/aest/aest.h      | 124 ++++++++++++++++++++
 include/linux/acpi_aest.h    |   9 ++
 8 files changed, 376 insertions(+)
 create mode 100644 drivers/ras/aest/Kconfig
 create mode 100644 drivers/ras/aest/Makefile
 create mode 100644 drivers/ras/aest/aest-core.c
 create mode 100644 drivers/ras/aest/aest.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 8bfb6f049ea5..e2ffd89c6bb8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -346,7 +346,9 @@ M:	Ruidong Tian <tianruidond at linux.alibaba.com>
 L:	linux-acpi at vger.kernel.org
 L:	linux-arm-kernel at lists.infradead.org
 S:	Supported
+F:	arch/arm64/include/asm/ras.h
 F:	drivers/acpi/arm64/aest.c
+F:	drivers/ras/aest/
 F:	include/linux/acpi_aest.h
 
 ACPI FOR RISC-V (ACPI/riscv)
diff --git a/drivers/ras/Kconfig b/drivers/ras/Kconfig
index fc4f4bb94a4c..61a2a05d9c94 100644
--- a/drivers/ras/Kconfig
+++ b/drivers/ras/Kconfig
@@ -33,6 +33,7 @@ if RAS
 
 source "arch/x86/ras/Kconfig"
 source "drivers/ras/amd/atl/Kconfig"
+source "drivers/ras/aest/Kconfig"
 
 config RAS_FMPM
 	tristate "FRU Memory Poison Manager"
diff --git a/drivers/ras/Makefile b/drivers/ras/Makefile
index 11f95d59d397..72411ee9deaf 100644
--- a/drivers/ras/Makefile
+++ b/drivers/ras/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_RAS_CEC)	+= cec.o
 
 obj-$(CONFIG_RAS_FMPM)	+= amd/fmpm.o
 obj-y			+= amd/atl/
+obj-y 			+= aest/
diff --git a/drivers/ras/aest/Kconfig b/drivers/ras/aest/Kconfig
new file mode 100644
index 000000000000..0b09a5d5acce
--- /dev/null
+++ b/drivers/ras/aest/Kconfig
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# ARM Error Source Table Support
+#
+# Copyright (c) 2025, Alibaba Group.
+#
+
+config AEST
+	tristate "ARM AEST Driver"
+	depends on ACPI_AEST && RAS
+
+	help
+	  The Arm Error Source Table (AEST) provides details on ACPI
+	  extensions that enable kernel-first handling of errors in a
+	  system that supports the Armv8 RAS extensions.
+
+	  If set, the kernel will report and log hardware errors.
diff --git a/drivers/ras/aest/Makefile b/drivers/ras/aest/Makefile
new file mode 100644
index 000000000000..a6ba7e36fb43
--- /dev/null
+++ b/drivers/ras/aest/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_AEST) 	+= aest.o
+
+aest-y		:= aest-core.o
diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
new file mode 100644
index 000000000000..c7ef6c13fd44
--- /dev/null
+++ b/drivers/ras/aest/aest-core.c
@@ -0,0 +1,217 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ARM Error Source Table Support
+ *
+ * Copyright (c) 2025, Alibaba Group.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/xarray.h>
+#include <linux/ras.h>
+
+#include "aest.h"
+
+DEFINE_PER_CPU(struct aest_device, percpu_adev);
+
+#undef pr_fmt
+#define pr_fmt(fmt) "AEST: " fmt
+
+static int aest_init_record(struct aest_record *record, int i,
+			    struct aest_node *node)
+{
+	struct device *dev = node->adev->dev;
+
+	record->name = devm_kasprintf(dev, GFP_KERNEL, "record%d", i);
+	if (!record->name)
+		return -ENOMEM;
+
+	if (node->base)
+		record->regs_base =
+			node->base + sizeof(struct ras_ext_regs) * i;
+
+	record->addressing_mode = test_bit(i, node->info->addressing_mode);
+	record->index = i;
+	record->node = node;
+
+	aest_record_dbg(record, "base: %p, index: %d, address mode: %x\n",
+			record->regs_base, record->index,
+			record->addressing_mode);
+	return 0;
+}
+
+static void aest_device_remove(struct platform_device *pdev)
+{
+	platform_set_drvdata(pdev, NULL);
+}
+
+static char *alloc_aest_node_name(struct aest_node *node)
+{
+	char *name;
+
+	switch (node->type) {
+	case ACPI_AEST_PROCESSOR_ERROR_NODE:
+		name = devm_kasprintf(node->adev->dev, GFP_KERNEL, "%s.%d",
+				      aest_node_name[node->type],
+				      node->info->processor->processor_id);
+		break;
+	case ACPI_AEST_MEMORY_ERROR_NODE:
+	case ACPI_AEST_SMMU_ERROR_NODE:
+	case ACPI_AEST_VENDOR_ERROR_NODE:
+	case ACPI_AEST_GIC_ERROR_NODE:
+	case ACPI_AEST_PCIE_ERROR_NODE:
+	case ACPI_AEST_PROXY_ERROR_NODE:
+		name = devm_kasprintf(node->adev->dev, GFP_KERNEL, "%s.%llx",
+				      aest_node_name[node->type],
+				      node->info->interface_hdr->address);
+		break;
+	default:
+		name = devm_kasprintf(node->adev->dev, GFP_KERNEL, "Unknown");
+	}
+
+	return name;
+}
+
+static int aest_node_set_errgsr(struct aest_device *adev,
+				struct aest_node *node)
+{
+	struct acpi_aest_node *anode = node->info;
+	u64 errgsr_base = anode->common->error_group_register_base;
+
+	if (anode->interface_hdr->type != ACPI_AEST_NODE_MEMORY_MAPPED)
+		return 0;
+
+	if (!node->base)
+		return 0;
+
+	if (!(anode->interface_hdr->flags & AEST_XFACE_FLAG_ERROR_GROUP)) {
+		node->errgsr = node->base + ERXGROUP;
+		return 0;
+	}
+
+	if (!errgsr_base)
+		return -EINVAL;
+
+	node->errgsr = devm_ioremap(adev->dev, errgsr_base, PAGE_SIZE);
+	if (!node->errgsr)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int aest_init_node(struct aest_device *adev, struct aest_node *node,
+			  struct acpi_aest_node *anode)
+{
+	int i, ret;
+	u64 address;
+
+	node->adev = adev;
+	node->info = anode;
+	node->type = anode->type;
+	node->name = alloc_aest_node_name(node);
+	if (!node->name)
+		return -ENOMEM;
+	node->record_implemented = anode->record_implemented;
+	node->status_reporting = anode->status_reporting;
+
+	address = anode->interface_hdr->address;
+	if (address) {
+		node->base = devm_ioremap(adev->dev, address, PAGE_SIZE);
+		if (!node->base)
+			return -ENOMEM;
+	}
+
+	ret = aest_node_set_errgsr(adev, node);
+	if (ret)
+		return ret;
+
+	node->record_count = anode->interface_hdr->error_record_count;
+	node->records = devm_kcalloc(adev->dev, node->record_count,
+				     sizeof(struct aest_record), GFP_KERNEL);
+	if (!node->records)
+		return -ENOMEM;
+
+	for (i = 0; i < node->record_count; i++) {
+		ret = aest_init_record(&node->records[i], i, node);
+		if (ret)
+			return ret;
+	}
+	aest_node_dbg(node, "%d records, base: %llx, errgsr: %llx\n",
+		      node->record_count, (u64)node->base, (u64)node->errgsr);
+	return 0;
+}
+
+static int aest_init_nodes(struct aest_device *adev, struct aest_hnode *ahnode)
+{
+	struct acpi_aest_node *anode;
+	struct aest_node *node;
+	int ret, i = 0;
+
+	adev->node_cnt = ahnode->count;
+	adev->nodes = devm_kcalloc(adev->dev, adev->node_cnt,
+				   sizeof(struct aest_node), GFP_KERNEL);
+	if (!adev->nodes)
+		return -ENOMEM;
+
+	list_for_each_entry(anode, &ahnode->list, list) {
+		adev->type = anode->type;
+
+		node = &adev->nodes[i++];
+		ret = aest_init_node(adev, node, anode);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int aest_device_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct aest_device *adev;
+	struct aest_hnode *ahnode;
+
+	ahnode = *((struct aest_hnode **)pdev->dev.platform_data);
+	if (!ahnode)
+		return -ENODEV;
+
+	adev = devm_kzalloc(&pdev->dev, sizeof(*adev), GFP_KERNEL);
+	if (!adev)
+		return -ENOMEM;
+
+	adev->dev = &pdev->dev;
+	adev->id = pdev->id;
+	aest_set_name(adev, ahnode);
+	ret = aest_init_nodes(adev, ahnode);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, adev);
+
+	aest_dev_dbg(adev, "Node cnt: %x, id: %x\n", adev->node_cnt, adev->id);
+
+	return 0;
+}
+
+static struct platform_driver aest_driver = {
+	.driver	= {
+		.name	= "AEST",
+	},
+	.probe	= aest_device_probe,
+	.remove = aest_device_remove,
+};
+
+static int __init aest_init(void)
+{
+	return platform_driver_register(&aest_driver);
+}
+module_init(aest_init);
+
+static void __exit aest_exit(void)
+{
+	platform_driver_unregister(&aest_driver);
+}
+module_exit(aest_exit);
+
+MODULE_DESCRIPTION("ARM AEST Driver");
+MODULE_AUTHOR("Ruidong Tian <tianruidong at linux.alibaba.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ras/aest/aest.h b/drivers/ras/aest/aest.h
new file mode 100644
index 000000000000..d918240c3f57
--- /dev/null
+++ b/drivers/ras/aest/aest.h
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * ARM Error Source Table Support
+ *
+ * Copyright (c) 2025, Alibaba Group.
+ */
+
+#include <linux/acpi_aest.h>
+#include <asm/ras.h>
+
+#define MAX_GSI_PER_NODE 2
+
+#define aest_dev_err(__adev, format, ...) \
+	dev_err((__adev)->dev, format, ##__VA_ARGS__)
+#define aest_dev_info(__adev, format, ...) \
+	dev_info((__adev)->dev, format, ##__VA_ARGS__)
+#define aest_dev_dbg(__adev, format, ...) \
+	dev_dbg((__adev)->dev, format, ##__VA_ARGS__)
+
+#define aest_node_err(__node, format, ...)                          \
+	dev_err((__node)->adev->dev, "%s: " format, (__node)->name, \
+		##__VA_ARGS__)
+#define aest_node_info(__node, format, ...)                          \
+	dev_info((__node)->adev->dev, "%s: " format, (__node)->name, \
+		 ##__VA_ARGS__)
+#define aest_node_dbg(__node, format, ...)                          \
+	dev_dbg((__node)->adev->dev, "%s: " format, (__node)->name, \
+		##__VA_ARGS__)
+
+#define aest_record_err(__record, format, ...)                  \
+	dev_err((__record)->node->adev->dev, "%s: %s: " format, \
+		(__record)->node->name, (__record)->name, ##__VA_ARGS__)
+#define aest_record_info(__record, format, ...)                  \
+	dev_info((__record)->node->adev->dev, "%s: %s: " format, \
+		 (__record)->node->name, (__record)->name, ##__VA_ARGS__)
+#define aest_record_dbg(__record, format, ...)                  \
+	dev_dbg((__record)->node->adev->dev, "%s: %s: " format, \
+		(__record)->node->name, (__record)->name, ##__VA_ARGS__)
+
+#define ERXGROUP 0xE00
+
+struct aest_record {
+	char *name;
+	int index;
+	void __iomem *regs_base;
+
+	/*
+	 * This bit specifies the addressing mode  to populate the ERR_ADDR
+	 * register:
+	 *   0b: Error record reports System Physical Addresses (SPA) in
+	 *       the ERR_ADDR register.
+	 *   1b: Error record reports error node-specific Logical Addresses(LA)
+	 *       in the ERR_ADD register. OS must use other means to translate
+	 *       the reported LA into SPA
+	 */
+	int addressing_mode;
+	struct aest_node *node;
+};
+
+struct aest_node {
+	char *name;
+	u8 type;
+	void *errgsr;
+	void *base;
+
+	/*
+	 * This bitmap indicates which of the error records within this error
+	 * node must be polled for error status.
+	 * Bit[n] of this field pertains to error record corresponding to
+	 * index n in this error group.
+	 * Bit[n] = 0b: Error record at index n needs to be polled.
+	 * Bit[n] = 1b: Error record at index n do not needs to be polled.
+	 */
+	unsigned long *record_implemented;
+	/*
+	 * This bitmap indicates which of the error records within this error
+	 * node support error status reporting using ERRGSR register.
+	 * Bit[n] of this field pertains to error record corresponding to
+	 * index n in this error group.
+	 * Bit[n] = 0b: Error record at index n supports error status reporting
+	 *              through ERRGSR.S.
+	 * Bit[n] = 1b: Error record at index n does not support error reporting
+	 *              through the ERRGSR.S bit If this error record is
+	 *              implemented, then it must be polled explicitly for
+	 *              error events.
+	 */
+	unsigned long *status_reporting;
+
+	struct aest_device *adev;
+	struct acpi_aest_node *info;
+
+	int record_count;
+	struct aest_record *records;
+};
+
+struct aest_device {
+	struct device *dev;
+	u32 type;
+	int node_cnt;
+	struct aest_node *nodes;
+	u32 id;
+};
+
+static const char *const aest_node_name[] = {
+	[ACPI_AEST_PROCESSOR_ERROR_NODE] = "processor",
+	[ACPI_AEST_MEMORY_ERROR_NODE] = "memory",
+	[ACPI_AEST_SMMU_ERROR_NODE] = "smmu",
+	[ACPI_AEST_VENDOR_ERROR_NODE] = "vendor",
+	[ACPI_AEST_GIC_ERROR_NODE] = "gic",
+	[ACPI_AEST_PCIE_ERROR_NODE] = "pcie",
+	[ACPI_AEST_PROXY_ERROR_NODE] = "proxy",
+};
+
+static inline int aest_set_name(struct aest_device *adev,
+				struct aest_hnode *ahnode)
+{
+	adev->dev->init_name = devm_kasprintf(adev->dev, GFP_KERNEL, "%s%d",
+					      aest_node_name[ahnode->type],
+					      adev->id);
+	if (!adev->dev->init_name)
+		return -ENOMEM;
+
+	return 0;
+}
diff --git a/include/linux/acpi_aest.h b/include/linux/acpi_aest.h
index 53c1970e7583..77187ce43d44 100644
--- a/include/linux/acpi_aest.h
+++ b/include/linux/acpi_aest.h
@@ -15,6 +15,15 @@
 
 #define AEST_MAX_INTERRUPT_PER_NODE 2
 
+/* AEST interface */
+#define AEST_XFACE_FLAG_SHARED (1 << 0)
+#define AEST_XFACE_FLAG_CLEAR_MISC (1 << 1)
+#define AEST_XFACE_FLAG_ERROR_DEVICE (1 << 2)
+#define AEST_XFACE_FLAG_AFFINITY (1 << 3)
+#define AEST_XFACE_FLAG_ERROR_GROUP (1 << 4)
+#define AEST_XFACE_FLAG_FAULT_INJECT (1 << 5)
+#define AEST_XFACE_FLAG_INT_CONFIG (1 << 6)
+
 #define KB 1024
 #define MB (1024 * KB)
 #define GB (1024 * MB)
-- 
2.47.3



From tianruidong at linux.alibaba.com  Tue Dec 30 01:09:31 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Tue, 30 Dec 2025 17:09:31 +0800
Subject: [PATCH v5 03/17] ras: AEST: support different group format
In-Reply-To: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
References: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
Message-ID: <20251230090945.43969-4-tianruidong@linux.alibaba.com>

Support for various AEST group formats allows for flexible configuration of
AEST node address space sizes and maximum record counts per group.

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 drivers/ras/aest/aest-core.c |  6 ++++--
 drivers/ras/aest/aest.h      | 39 +++++++++++++++++++++++++++++++++++-
 2 files changed, 42 insertions(+), 3 deletions(-)

diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index c7ef6c13fd44..acebb293ac75 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -84,7 +84,7 @@ static int aest_node_set_errgsr(struct aest_device *adev,
 		return 0;
 
 	if (!(anode->interface_hdr->flags & AEST_XFACE_FLAG_ERROR_GROUP)) {
-		node->errgsr = node->base + ERXGROUP;
+		node->errgsr = node->base + node->group->errgsr_offset;
 		return 0;
 	}
 
@@ -112,10 +112,12 @@ static int aest_init_node(struct aest_device *adev, struct aest_node *node,
 		return -ENOMEM;
 	node->record_implemented = anode->record_implemented;
 	node->status_reporting = anode->status_reporting;
+	node->group = &aest_group_config[anode->interface_hdr->group_format];
 
 	address = anode->interface_hdr->address;
 	if (address) {
-		node->base = devm_ioremap(adev->dev, address, PAGE_SIZE);
+		node->base =
+			devm_ioremap(adev->dev, address, node->group->size);
 		if (!node->base)
 			return -ENOMEM;
 	}
diff --git a/drivers/ras/aest/aest.h b/drivers/ras/aest/aest.h
index d918240c3f57..3250675e99b7 100644
--- a/drivers/ras/aest/aest.h
+++ b/drivers/ras/aest/aest.h
@@ -37,7 +37,15 @@
 	dev_dbg((__record)->node->adev->dev, "%s: %s: " format, \
 		(__record)->node->name, (__record)->name, ##__VA_ARGS__)
 
-#define ERXGROUP 0xE00
+#define ERXGROUP_4K_OFFSET 0xE00
+#define ERXGROUP_16K_OFFSET 0x3800
+#define ERXGROUP_64K_OFFSET 0xE000
+#define ERXGROUP_4K_SIZE (4 * KB)
+#define ERXGROUP_16K_SIZE (16 * KB)
+#define ERXGROUP_64K_SIZE (64 * KB)
+#define ERXGROUP_4K_ERRGSR_NUM 1
+#define ERXGROUP_16K_ERRGSR_NUM 4
+#define ERXGROUP_64K_ERRGSR_NUM 14
 
 struct aest_record {
 	char *name;
@@ -57,6 +65,34 @@ struct aest_record {
 	struct aest_node *node;
 };
 
+struct aest_group {
+	int type;
+	int errgsr_num;
+	size_t size;
+	u64 errgsr_offset;
+};
+
+static const struct aest_group aest_group_config[] = {
+	[ACPI_AEST_NODE_GROUP_FORMAT_4K] = {
+		.type = ACPI_AEST_NODE_GROUP_FORMAT_4K,
+		.errgsr_num = ERXGROUP_4K_ERRGSR_NUM,
+		.size = ERXGROUP_4K_SIZE,
+		.errgsr_offset = ERXGROUP_4K_OFFSET,
+	},
+	[ACPI_AEST_NODE_GROUP_FORMAT_16K] = {
+		.type = ACPI_AEST_NODE_GROUP_FORMAT_16K,
+		.errgsr_num = ERXGROUP_16K_ERRGSR_NUM,
+		.size = ERXGROUP_16K_SIZE,
+		.errgsr_offset = ERXGROUP_16K_OFFSET,
+	},
+	[ACPI_AEST_NODE_GROUP_FORMAT_64K] = {
+		.type = ACPI_AEST_NODE_GROUP_FORMAT_64K,
+		.errgsr_num = ERXGROUP_64K_ERRGSR_NUM,
+		.size = ERXGROUP_64K_SIZE,
+		.errgsr_offset = ERXGROUP_64K_OFFSET,
+	},
+};
+
 struct aest_node {
 	char *name;
 	u8 type;
@@ -86,6 +122,7 @@ struct aest_node {
 	 */
 	unsigned long *status_reporting;
 
+	const struct aest_group *group;
 	struct aest_device *adev;
 	struct acpi_aest_node *info;
 
-- 
2.47.3



From tianruidong at linux.alibaba.com  Tue Dec 30 01:09:32 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Tue, 30 Dec 2025 17:09:32 +0800
Subject: [PATCH v5 04/17] ras: AEST: Unify the read/write interface for system and MMIO register
In-Reply-To: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
References: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
Message-ID: <20251230090945.43969-5-tianruidong@linux.alibaba.com>

Use record_read/write to simultaneously read and write system registers and
MMIO registers while maintaining code conciseness.

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 drivers/ras/aest/aest-core.c |  1 +
 drivers/ras/aest/aest.h      | 94 ++++++++++++++++++++++++++++++++++++
 2 files changed, 95 insertions(+)

diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index acebb293ac75..f4a5119dc513 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -29,6 +29,7 @@ static int aest_init_record(struct aest_record *record, int i,
 		record->regs_base =
 			node->base + sizeof(struct ras_ext_regs) * i;
 
+	record->access = &aest_access[node->info->interface_hdr->type];
 	record->addressing_mode = test_bit(i, node->info->addressing_mode);
 	record->index = i;
 	record->node = node;
diff --git a/drivers/ras/aest/aest.h b/drivers/ras/aest/aest.h
index 3250675e99b7..31131cce9928 100644
--- a/drivers/ras/aest/aest.h
+++ b/drivers/ras/aest/aest.h
@@ -10,6 +10,11 @@
 
 #define MAX_GSI_PER_NODE 2
 
+#define record_read(record, offset) \
+	record->access->read(record->regs_base, offset)
+#define record_write(record, offset, val) \
+	record->access->write(record->regs_base, offset, val)
+
 #define aest_dev_err(__adev, format, ...) \
 	dev_err((__adev)->dev, format, ##__VA_ARGS__)
 #define aest_dev_info(__adev, format, ...) \
@@ -47,6 +52,20 @@
 #define ERXGROUP_16K_ERRGSR_NUM 4
 #define ERXGROUP_64K_ERRGSR_NUM 14
 
+#define ERXFR 0x0
+#define ERXCTLR 0x8
+#define ERXSTATUS 0x10
+#define ERXADDR 0x18
+#define ERXMISC0 0x20
+#define ERXMISC1 0x28
+#define ERXMISC2 0x30
+#define ERXMISC3 0x38
+
+struct aest_access {
+	u64 (*read)(void *base, u32 offset);
+	void (*write)(void *base, u32 offset, u64 val);
+};
+
 struct aest_record {
 	char *name;
 	int index;
@@ -63,6 +82,7 @@ struct aest_record {
 	 */
 	int addressing_mode;
 	struct aest_node *node;
+	const struct aest_access *access;
 };
 
 struct aest_group {
@@ -159,3 +179,77 @@ static inline int aest_set_name(struct aest_device *adev,
 
 	return 0;
 }
+
+#define CASE_READ(res, x)                           \
+	case (x): {                                 \
+		res = read_sysreg_s(SYS_##x##_EL1); \
+		break;                              \
+	}
+
+#define CASE_WRITE(val, x)                            \
+	case (x): {                                   \
+		write_sysreg_s((val), SYS_##x##_EL1); \
+		break;                                \
+	}
+
+static inline u64 aest_sysreg_read(void *__unused, u32 offset)
+{
+	u64 res;
+
+	switch (offset) {
+		CASE_READ(res, ERXFR)
+		CASE_READ(res, ERXCTLR)
+		CASE_READ(res, ERXSTATUS)
+		CASE_READ(res, ERXADDR)
+		CASE_READ(res, ERXMISC0)
+		CASE_READ(res, ERXMISC1)
+		CASE_READ(res, ERXMISC2)
+		CASE_READ(res, ERXMISC3)
+	default :
+		res = 0;
+	}
+	return res;
+}
+
+static inline void aest_sysreg_write(void *base, u32 offset, u64 val)
+{
+	switch (offset) {
+		CASE_WRITE(val, ERXFR)
+		CASE_WRITE(val, ERXCTLR)
+		CASE_WRITE(val, ERXSTATUS)
+		CASE_WRITE(val, ERXADDR)
+		CASE_WRITE(val, ERXMISC0)
+		CASE_WRITE(val, ERXMISC1)
+		CASE_WRITE(val, ERXMISC2)
+		CASE_WRITE(val, ERXMISC3)
+	default :
+		return;
+	}
+}
+
+static inline u64 aest_iomem_read(void *base, u32 offset)
+{
+	return readq_relaxed(base + offset);
+}
+
+static inline void aest_iomem_write(void *base, u32 offset, u64 val)
+{
+	writeq_relaxed(val, base + offset);
+}
+
+/* access type is decided by AEST interface type. */
+static const struct aest_access aest_access[] = {
+	[ACPI_AEST_NODE_SYSTEM_REGISTER] = {
+		.read = aest_sysreg_read,
+		.write = aest_sysreg_write,
+	},
+	[ACPI_AEST_NODE_MEMORY_MAPPED] = {
+		.read = aest_iomem_read,
+		.write = aest_iomem_write,
+	},
+	[ACPI_AEST_NODE_SINGLE_RECORD_MEMORY_MAPPED] = {
+		.read = aest_iomem_read,
+		.write = aest_iomem_write,
+	},
+	{ }
+};
-- 
2.47.3



From tianruidong at linux.alibaba.com  Tue Dec 30 01:09:33 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Tue, 30 Dec 2025 17:09:33 +0800
Subject: [PATCH v5 05/17] ras: AEST: Probe RAS system architecture version
In-Reply-To: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
References: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
Message-ID: <20251230090945.43969-6-tianruidong@linux.alibaba.com>

The RAS version of a component can be probed via its ERRDEVARCH register.

In cases where a component (e.g., SMMU) does not implement an ERRDEVARCH
register, the driver falls back to using the RAS version of the Processing
Element (PE).

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 arch/arm64/include/asm/ras.h |  3 +++
 drivers/ras/aest/aest-core.c | 22 ++++++++++++++++++++++
 drivers/ras/aest/aest.h      |  3 +++
 3 files changed, 28 insertions(+)

diff --git a/arch/arm64/include/asm/ras.h b/arch/arm64/include/asm/ras.h
index b6640b9972bf..da7c441252fe 100644
--- a/arch/arm64/include/asm/ras.h
+++ b/arch/arm64/include/asm/ras.h
@@ -4,6 +4,9 @@
 
 #include <linux/types.h>
 
+/* ERRDEVARCH */
+#define ERRDEVARCH_REV GENMASK(19, 16)
+
 struct ras_ext_regs {
 	u64 err_fr;
 	u64 err_ctlr;
diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index f4a5119dc513..84b2fb8127ff 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -16,6 +16,27 @@ DEFINE_PER_CPU(struct aest_device, percpu_adev);
 #undef pr_fmt
 #define pr_fmt(fmt) "AEST: " fmt
 
+static int get_aest_node_ver(struct aest_node *node)
+{
+	u64 reg;
+	void *devarch_base;
+
+	if (node->type == ACPI_AEST_GIC_ERROR_NODE) {
+		devarch_base = ioremap(node->info->interface_hdr->address +
+					       GIC_ERRDEVARCH,
+				       PAGE_SIZE);
+		if (!devarch_base)
+			return 0;
+
+		reg = readl_relaxed(devarch_base);
+		iounmap(devarch_base);
+
+		return FIELD_GET(ERRDEVARCH_REV, reg);
+	}
+
+	return FIELD_GET(ID_AA64PFR0_EL1_RAS_MASK, read_cpuid(ID_AA64PFR0_EL1));
+}
+
 static int aest_init_record(struct aest_record *record, int i,
 			    struct aest_node *node)
 {
@@ -108,6 +129,7 @@ static int aest_init_node(struct aest_device *adev, struct aest_node *node,
 	node->adev = adev;
 	node->info = anode;
 	node->type = anode->type;
+	node->version = get_aest_node_ver(node);
 	node->name = alloc_aest_node_name(node);
 	if (!node->name)
 		return -ENOMEM;
diff --git a/drivers/ras/aest/aest.h b/drivers/ras/aest/aest.h
index 31131cce9928..bf0b9a49fdaa 100644
--- a/drivers/ras/aest/aest.h
+++ b/drivers/ras/aest/aest.h
@@ -61,6 +61,8 @@
 #define ERXMISC2 0x30
 #define ERXMISC3 0x38
 
+#define GIC_ERRDEVARCH 0xFFBC
+
 struct aest_access {
 	u64 (*read)(void *base, u32 offset);
 	void (*write)(void *base, u32 offset, u64 val);
@@ -141,6 +143,7 @@ struct aest_node {
 	 *              error events.
 	 */
 	unsigned long *status_reporting;
+	int version;
 
 	const struct aest_group *group;
 	struct aest_device *adev;
-- 
2.47.3



From tianruidong at linux.alibaba.com  Tue Dec 30 01:09:34 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Tue, 30 Dec 2025 17:09:34 +0800
Subject: [PATCH v5 06/17] ras: AEST: Support RAS Common Fault Injection Model Extension
In-Reply-To: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
References: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
Message-ID: <20251230090945.43969-7-tianruidong@linux.alibaba.com>

Add inject register descripted in Common Fault Injection Model
Extension.

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 drivers/ras/aest/aest-core.c | 15 ++++++++++++++-
 drivers/ras/aest/aest.h      | 10 ++++++++++
 2 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index 84b2fb8127ff..1218ae51079c 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -124,7 +124,7 @@ static int aest_init_node(struct aest_device *adev, struct aest_node *node,
 			  struct acpi_aest_node *anode)
 {
 	int i, ret;
-	u64 address;
+	u64 address, flags;
 
 	node->adev = adev;
 	node->info = anode;
@@ -145,6 +145,19 @@ static int aest_init_node(struct aest_device *adev, struct aest_node *node,
 			return -ENOMEM;
 	}
 
+	flags = anode->interface_hdr->flags;
+	address = node->info->common->fault_inject_register_base;
+	if ((flags & AEST_XFACE_FLAG_FAULT_INJECT) && address) {
+		if (address - anode->interface_hdr->address < node->group->size)
+			node->inj = node->base +
+				    (address - anode->interface_hdr->address);
+		else {
+			node->inj = devm_ioremap(adev->dev, address, PAGE_SIZE);
+			if (!node->inj)
+				return -ENOMEM;
+		}
+	}
+
 	ret = aest_node_set_errgsr(adev, node);
 	if (ret)
 		return ret;
diff --git a/drivers/ras/aest/aest.h b/drivers/ras/aest/aest.h
index bf0b9a49fdaa..505ecd9635bc 100644
--- a/drivers/ras/aest/aest.h
+++ b/drivers/ras/aest/aest.h
@@ -60,6 +60,9 @@
 #define ERXMISC1 0x28
 #define ERXMISC2 0x30
 #define ERXMISC3 0x38
+#define ERXPFGF 0x800
+#define ERXPFGCTL 0x808
+#define ERXPFGCDN 0x810
 
 #define GIC_ERRDEVARCH 0xFFBC
 
@@ -120,6 +123,7 @@ struct aest_node {
 	u8 type;
 	void *errgsr;
 	void *base;
+	void *inj;
 
 	/*
 	 * This bitmap indicates which of the error records within this error
@@ -208,6 +212,9 @@ static inline u64 aest_sysreg_read(void *__unused, u32 offset)
 		CASE_READ(res, ERXMISC1)
 		CASE_READ(res, ERXMISC2)
 		CASE_READ(res, ERXMISC3)
+		CASE_READ(res, ERXPFGF)
+		CASE_READ(res, ERXPFGCTL)
+		CASE_READ(res, ERXPFGCDN)
 	default :
 		res = 0;
 	}
@@ -225,6 +232,9 @@ static inline void aest_sysreg_write(void *base, u32 offset, u64 val)
 		CASE_WRITE(val, ERXMISC1)
 		CASE_WRITE(val, ERXMISC2)
 		CASE_WRITE(val, ERXMISC3)
+		CASE_WRITE(val, ERXPFGF)
+		CASE_WRITE(val, ERXPFGCTL)
+		CASE_WRITE(val, ERXPFGCDN)
 	default :
 		return;
 	}
-- 
2.47.3



From tianruidong at linux.alibaba.com  Tue Dec 30 01:09:35 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Tue, 30 Dec 2025 17:09:35 +0800
Subject: [PATCH v5 07/17] ras: AEST: Support CE threshold of error record
In-Reply-To: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
References: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
Message-ID: <20251230090945.43969-8-tianruidong@linux.alibaba.com>

The CE threshold defines the number of Correctable Errors (CE) that
must occur in a record before triggering an interrupt. Error records
support multiple threshold configurations, including 8B, 16B, and 32B.
This patch detects the supported threshold settings for error records
and sets the default threshold to 1, ensuring an interrupt is generated
for every CE occurrence.

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 arch/arm64/include/asm/ras.h | 41 ++++++++++++++++++++
 drivers/ras/aest/aest-core.c | 74 ++++++++++++++++++++++++++++++++++++
 drivers/ras/aest/aest.h      | 17 +++++++++
 include/linux/acpi_aest.h    |  3 ++
 4 files changed, 135 insertions(+)

diff --git a/arch/arm64/include/asm/ras.h b/arch/arm64/include/asm/ras.h
index da7c441252fe..6c51d27520c0 100644
--- a/arch/arm64/include/asm/ras.h
+++ b/arch/arm64/include/asm/ras.h
@@ -4,9 +4,50 @@
 
 #include <linux/types.h>
 
+/* ERR<n>FR */
+#define ERR_FR_CE GENMASK_ULL(54, 53)
+#define ERR_FR_RP BIT(15)
+#define ERR_FR_CEC GENMASK_ULL(14, 12)
+
+#define ERR_FR_RP_SINGLE_COUNTER 0
+#define ERR_FR_RP_DOUBLE_COUNTER 1
+
+#define ERR_FR_CEC_0B_COUNTER 0
+#define ERR_FR_CEC_8B_COUNTER BIT(1)
+#define ERR_FR_CEC_16B_COUNTER BIT(2)
+
+/* ERR<n>MISC0 */
+
+/* ERR<n>FR.CEC == 0b010, ERR<n>FR.RP == 0  */
+#define ERR_MISC0_8B_OF BIT(39)
+#define ERR_MISC0_8B_CEC GENMASK_ULL(38, 32)
+
+/* ERR<n>FR.CEC == 0b100, ERR<n>FR.RP == 0  */
+#define ERR_MISC0_16B_OF BIT(47)
+#define ERR_MISC0_16B_CEC GENMASK_ULL(46, 32)
+
+#define ERR_MISC0_CEC_SHIFT 31
+
+#define ERR_8B_CEC_MAX (ERR_MISC0_8B_CEC >> ERR_MISC0_CEC_SHIFT)
+#define ERR_16B_CEC_MAX (ERR_MISC0_16B_CEC >> ERR_MISC0_CEC_SHIFT)
+
+/* ERR<n>FR.CEC == 0b100, ERR<n>FR.RP == 1  */
+#define ERR_MISC0_16B_OFO BIT(63)
+#define ERR_MISC0_16B_CECO GENMASK_ULL(62, 48)
+#define ERR_MISC0_16B_OFR BIT(47)
+#define ERR_MISC0_16B_CECR GENMASK_ULL(46, 32)
+
 /* ERRDEVARCH */
 #define ERRDEVARCH_REV GENMASK(19, 16)
 
+enum ras_ce_threshold {
+	RAS_CE_THRESHOLD_0B,
+	RAS_CE_THRESHOLD_8B,
+	RAS_CE_THRESHOLD_16B,
+	RAS_CE_THRESHOLD_32B,
+	UNKNOWN,
+};
+
 struct ras_ext_regs {
 	u64 err_fr;
 	u64 err_ctlr;
diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index 1218ae51079c..5cfe91a6d72a 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -16,6 +16,79 @@ DEFINE_PER_CPU(struct aest_device, percpu_adev);
 #undef pr_fmt
 #define pr_fmt(fmt) "AEST: " fmt
 
+static enum ras_ce_threshold aest_get_ce_threshold(struct aest_record *record)
+{
+	u64 err_fr, err_fr_cec, err_fr_rp = -1;
+
+	err_fr = record_read(record, ERXFR);
+	err_fr_cec = FIELD_GET(ERR_FR_CEC, err_fr);
+	err_fr_rp = FIELD_GET(ERR_FR_RP, err_fr);
+
+	if (err_fr_cec == ERR_FR_CEC_0B_COUNTER)
+		return RAS_CE_THRESHOLD_0B;
+	else if (err_fr_rp == ERR_FR_RP_DOUBLE_COUNTER)
+		return RAS_CE_THRESHOLD_32B;
+	else if (err_fr_cec == ERR_FR_CEC_8B_COUNTER)
+		return RAS_CE_THRESHOLD_8B;
+	else if (err_fr_cec == ERR_FR_CEC_16B_COUNTER)
+		return RAS_CE_THRESHOLD_16B;
+	else
+		return UNKNOWN;
+}
+
+static const struct ce_threshold_info ce_info[] = {
+	[RAS_CE_THRESHOLD_0B] = { 0 },
+	[RAS_CE_THRESHOLD_8B] = {
+		.max_count = ERR_8B_CEC_MAX,
+		.mask = ERR_MISC0_8B_CEC,
+		.shift = ERR_MISC0_CEC_SHIFT,
+	},
+	[RAS_CE_THRESHOLD_16B] = {
+		.max_count = ERR_16B_CEC_MAX,
+		.mask = ERR_MISC0_16B_CEC,
+		.shift = ERR_MISC0_CEC_SHIFT,
+	},
+};
+
+static void aest_set_ce_threshold(struct aest_record *record)
+{
+	u64 err_misc0;
+	struct ce_threshold *ce = &record->ce;
+	const struct ce_threshold_info *info;
+
+	record->threshold_type = aest_get_ce_threshold(record);
+
+	switch (record->threshold_type) {
+	case RAS_CE_THRESHOLD_0B:
+		aest_record_dbg(record, "do not support CE threshold!\n");
+		return;
+	case RAS_CE_THRESHOLD_8B:
+		aest_record_dbg(record, "support 8 bit CE threshold!\n");
+		break;
+	case RAS_CE_THRESHOLD_16B:
+		aest_record_dbg(record, "support 16 bit CE threshold!\n");
+		break;
+	case RAS_CE_THRESHOLD_32B:
+		aest_record_dbg(record, "not support 32 bit CE threshold!\n");
+		break;
+	default:
+		aest_record_dbg(record, "Unknown misc0 ce threshold!\n");
+	}
+
+	err_misc0 = record_read(record, ERXMISC0);
+	info = &ce_info[record->threshold_type];
+	ce->info = info;
+
+	// Default CE threshold is 1.
+	ce->count = info->max_count;
+	ce->threshold = DEFAULT_CE_THRESHOLD;
+	ce->reg_val = err_misc0 | info->mask;
+
+	record_write(record, ERXMISC0, ce->reg_val);
+	aest_record_dbg(record, "CE threshold is %llx, controlled by Kernel",
+			ce->threshold);
+}
+
 static int get_aest_node_ver(struct aest_node *node)
 {
 	u64 reg;
@@ -54,6 +127,7 @@ static int aest_init_record(struct aest_record *record, int i,
 	record->addressing_mode = test_bit(i, node->info->addressing_mode);
 	record->index = i;
 	record->node = node;
+	aest_set_ce_threshold(record);
 
 	aest_record_dbg(record, "base: %p, index: %d, address mode: %x\n",
 			record->regs_base, record->index,
diff --git a/drivers/ras/aest/aest.h b/drivers/ras/aest/aest.h
index 505ecd9635bc..85eeed79bcbe 100644
--- a/drivers/ras/aest/aest.h
+++ b/drivers/ras/aest/aest.h
@@ -9,6 +9,7 @@
 #include <asm/ras.h>
 
 #define MAX_GSI_PER_NODE 2
+#define DEFAULT_CE_THRESHOLD 1
 
 #define record_read(record, offset) \
 	record->access->read(record->regs_base, offset)
@@ -71,6 +72,19 @@ struct aest_access {
 	void (*write)(void *base, u32 offset, u64 val);
 };
 
+struct ce_threshold_info {
+	const u64 max_count;
+	const u64 mask;
+	const u64 shift;
+};
+
+struct ce_threshold {
+	const struct ce_threshold_info *info;
+	u64 count;
+	u64 threshold;
+	u64 reg_val;
+};
+
 struct aest_record {
 	char *name;
 	int index;
@@ -88,6 +102,9 @@ struct aest_record {
 	int addressing_mode;
 	struct aest_node *node;
 	const struct aest_access *access;
+
+	struct ce_threshold ce;
+	enum ras_ce_threshold threshold_type;
 };
 
 struct aest_group {
diff --git a/include/linux/acpi_aest.h b/include/linux/acpi_aest.h
index 77187ce43d44..a7898c643896 100644
--- a/include/linux/acpi_aest.h
+++ b/include/linux/acpi_aest.h
@@ -13,6 +13,9 @@
 /* AEST interrupt */
 #define AEST_INTERRUPT_MODE BIT(0)
 
+#define AEST_INTERRUPT_FHI_UE_SUPPORT		BIT(0)
+#define AEST_INTERRUPT_FHI_UE_NO_SUPPORT		BIT(1)
+
 #define AEST_MAX_INTERRUPT_PER_NODE 2
 
 /* AEST interface */
-- 
2.47.3



From tianruidong at linux.alibaba.com  Tue Dec 30 01:09:36 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Tue, 30 Dec 2025 17:09:36 +0800
Subject: [PATCH v5 08/17] ras: AEST: Enable and register IRQs
In-Reply-To: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
References: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
Message-ID: <20251230090945.43969-9-tianruidong@linux.alibaba.com>

The interrupt numbers for certain error records may be explicitly
programmed into their configuration register.

And for PPIs, each core will maintains its own copy of the aest_device
structure.

Given that handling RAS errors entails complex processes such as EDAC
and memory_failure, all handling is deferred to and handled within a
bottom-half context.

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 arch/arm64/include/asm/ras.h |  36 +++
 drivers/ras/aest/aest-core.c | 531 ++++++++++++++++++++++++++++++++++-
 drivers/ras/aest/aest.h      |  56 ++++
 include/linux/acpi_aest.h    |   7 +
 include/linux/ras.h          |   8 +
 5 files changed, 637 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/ras.h b/arch/arm64/include/asm/ras.h
index 6c51d27520c0..02cf15278d9f 100644
--- a/arch/arm64/include/asm/ras.h
+++ b/arch/arm64/include/asm/ras.h
@@ -2,6 +2,7 @@
 #ifndef __ASM_RAS_H
 #define __ASM_RAS_H
 
+#include <linux/bits.h>
 #include <linux/types.h>
 
 /* ERR<n>FR */
@@ -37,6 +38,41 @@
 #define ERR_MISC0_16B_OFR BIT(47)
 #define ERR_MISC0_16B_CECR GENMASK_ULL(46, 32)
 
+/* ERR<n>STATUS */
+#define ERR_STATUS_AV BIT(31)
+#define ERR_STATUS_V BIT(30)
+#define ERR_STATUS_UE BIT(29)
+#define ERR_STATUS_ER BIT(28)
+#define ERR_STATUS_OF BIT(27)
+#define ERR_STATUS_MV BIT(26)
+#define ERR_STATUS_CE (BIT(25) | BIT(24))
+#define ERR_STATUS_DE BIT(23)
+#define ERR_STATUS_PN BIT(22)
+#define ERR_STATUS_UET (BIT(21) | BIT(20))
+#define ERR_STATUS_CI BIT(19)
+#define ERR_STATUS_IERR GENMASK_ULL(15, 8)
+#define ERR_STATUS_SERR GENMASK_ULL(7, 0)
+
+/* Theses bits are	 write-one-to-clear */
+#define ERR_STATUS_W1TC                                                  \
+	(ERR_STATUS_AV | ERR_STATUS_V | ERR_STATUS_UE | ERR_STATUS_ER |  \
+	 ERR_STATUS_OF | ERR_STATUS_MV | ERR_STATUS_CE | ERR_STATUS_DE | \
+	 ERR_STATUS_PN | ERR_STATUS_UET | ERR_STATUS_CI)
+
+#define ERR_STATUS_UET_UC 0
+#define ERR_STATUS_UET_UEU 1
+#define ERR_STATUS_UET_UEO 2
+#define ERR_STATUS_UET_UER 3
+
+/* ERR<n>ADDR */
+#define ERR_ADDR_AI BIT(61)
+#define ERR_ADDR_PADDR GENMASK_ULL(55, 0)
+
+/* ERR<n>CTLR */
+#define ERR_CTLR_CFI BIT(8)
+#define ERR_CTLR_FI BIT(3)
+#define ERR_CTLR_UI BIT(2)
+
 /* ERRDEVARCH */
 #define ERRDEVARCH_REV GENMASK(19, 16)
 
diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index 5cfe91a6d72a..5ec0ba38f51b 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -5,8 +5,11 @@
  * Copyright (c) 2025, Alibaba Group.
  */
 
+#include <linux/interrupt.h>
+#include <linux/panic.h>
 #include <linux/platform_device.h>
 #include <linux/xarray.h>
+#include <linux/genalloc.h>
 #include <linux/ras.h>
 
 #include "aest.h"
@@ -16,6 +19,439 @@ DEFINE_PER_CPU(struct aest_device, percpu_adev);
 #undef pr_fmt
 #define pr_fmt(fmt) "AEST: " fmt
 
+/*
+ * This memory pool is only to be used to save AEST node in AEST irq context.
+ * There can be 500 AEST node at most.
+ */
+#define AEST_NODE_ALLOCED_MAX 500
+
+#define AEST_LOG_PREFIX_BUFFER 64
+
+BLOCKING_NOTIFIER_HEAD(aest_decoder_chain);
+
+static void aest_print(struct aest_event *event)
+{
+	static atomic_t seqno = { 0 };
+	unsigned int curr_seqno;
+	char pfx_seq[AEST_LOG_PREFIX_BUFFER];
+	int index;
+	struct ras_ext_regs *regs;
+
+	curr_seqno = atomic_inc_return(&seqno);
+	snprintf(pfx_seq, sizeof(pfx_seq), "{%u}" HW_ERR, curr_seqno);
+	pr_info("%sHardware error from AEST %s\n", pfx_seq, event->node_name);
+
+	switch (event->type) {
+	case ACPI_AEST_PROCESSOR_ERROR_NODE:
+		pr_err("%s Error from CPU%d\n", pfx_seq, event->id0);
+		break;
+	case ACPI_AEST_MEMORY_ERROR_NODE:
+		pr_err("%s Error from memory at SRAT proximity domain %#x\n",
+		       pfx_seq, event->id0);
+		break;
+	case ACPI_AEST_SMMU_ERROR_NODE:
+		pr_err("%s Error from SMMU IORT node %#x subcomponent %#x\n",
+		       pfx_seq, event->id0, event->id1);
+		break;
+	case ACPI_AEST_VENDOR_ERROR_NODE:
+		pr_err("%s Error from vendor hid %8.8s uid %#x\n", pfx_seq,
+		       event->hid, event->id1);
+		break;
+	case ACPI_AEST_GIC_ERROR_NODE:
+		pr_err("%s Error from GIC type %#x instance %#x\n", pfx_seq,
+		       event->id0, event->id1);
+		break;
+	default:
+		pr_err("%s Unknown AEST node type\n", pfx_seq);
+		return;
+	}
+
+	index = event->index;
+	regs = &event->regs;
+
+	pr_err("%s  ERR%dFR: 0x%llx\n", pfx_seq, index, regs->err_fr);
+	pr_err("%s  ERR%dCTRL: 0x%llx\n", pfx_seq, index, regs->err_ctlr);
+	pr_err("%s  ERR%dSTATUS: 0x%llx\n", pfx_seq, index, regs->err_status);
+	if (regs->err_status & ERR_STATUS_AV)
+		pr_err("%s  ERR%dADDR: 0x%llx\n", pfx_seq, index,
+		       regs->err_addr);
+
+	if (regs->err_status & ERR_STATUS_MV) {
+		pr_err("%s  ERR%dMISC0: 0x%llx\n", pfx_seq, index,
+		       regs->err_misc[0]);
+		pr_err("%s  ERR%dMISC1: 0x%llx\n", pfx_seq, index,
+		       regs->err_misc[1]);
+		pr_err("%s  ERR%dMISC2: 0x%llx\n", pfx_seq, index,
+		       regs->err_misc[2]);
+		pr_err("%s  ERR%dMISC3: 0x%llx\n", pfx_seq, index,
+		       regs->err_misc[3]);
+	}
+}
+
+static void aest_handle_memory_failure(u64 addr)
+{
+	unsigned long pfn;
+
+	pfn = PHYS_PFN(addr);
+
+	if (!pfn_valid(pfn)) {
+		pr_warn(HW_ERR "Invalid physical address: %#llx\n", addr);
+		return;
+	}
+
+#ifdef CONFIG_MEMORY_FAILURE
+	memory_failure(pfn, 0);
+#endif
+}
+
+static void init_aest_event(struct aest_event *event,
+			    struct aest_record *record,
+			    struct ras_ext_regs *regs)
+{
+	struct aest_node *node = record->node;
+	struct acpi_aest_node *info = node->info;
+
+	event->type = node->type;
+	event->node_name = node->name;
+	switch (node->type) {
+	case ACPI_AEST_PROCESSOR_ERROR_NODE:
+		if (info->processor->flags &
+		    (ACPI_AEST_PROC_FLAG_SHARED | ACPI_AEST_PROC_FLAG_GLOBAL))
+			event->id0 = smp_processor_id();
+		else
+			event->id0 = get_cpu_for_acpi_id(
+				info->processor->processor_id);
+
+		event->id1 = info->processor->resource_type;
+		break;
+	case ACPI_AEST_MEMORY_ERROR_NODE:
+		event->id0 = info->memory->srat_proximity_domain;
+		break;
+	case ACPI_AEST_SMMU_ERROR_NODE:
+		event->id0 = info->smmu->iort_node_reference;
+		event->id1 = info->smmu->subcomponent_reference;
+		break;
+	case ACPI_AEST_VENDOR_ERROR_NODE:
+		event->id0 = 0;
+		event->id1 = info->vendor->acpi_uid;
+		event->hid = info->vendor->acpi_hid;
+		break;
+	case ACPI_AEST_GIC_ERROR_NODE:
+		event->id0 = info->gic->interface_type;
+		event->id1 = info->gic->instance_id;
+		break;
+	default:
+		event->id0 = 0;
+		event->id1 = 0;
+	}
+
+	memcpy(&event->regs, regs, sizeof(*regs));
+	event->index = record->index;
+	event->addressing_mode = record->addressing_mode;
+}
+
+static int aest_node_gen_pool_add(struct aest_device *adev,
+				  struct aest_record *record,
+				  struct ras_ext_regs *regs)
+{
+	struct aest_event *event;
+
+	if (!adev->pool)
+		return -EINVAL;
+
+	event = (void *)gen_pool_alloc(adev->pool, sizeof(*event));
+	if (!event)
+		return -ENOMEM;
+
+	init_aest_event(event, record, regs);
+	llist_add(&event->llnode, &adev->event_list);
+
+	return 0;
+}
+
+static void aest_log(struct aest_record *record, struct ras_ext_regs *regs)
+{
+	struct aest_device *adev = record->node->adev;
+
+	if (!aest_node_gen_pool_add(adev, record, regs))
+		schedule_work(&adev->aest_work);
+}
+
+void aest_register_decode_chain(struct notifier_block *nb)
+{
+	blocking_notifier_chain_register(&aest_decoder_chain, nb);
+}
+EXPORT_SYMBOL_GPL(aest_register_decode_chain);
+
+void aest_unregister_decode_chain(struct notifier_block *nb)
+{
+	blocking_notifier_chain_unregister(&aest_decoder_chain, nb);
+}
+EXPORT_SYMBOL_GPL(aest_unregister_decode_chain);
+
+static void aest_node_pool_process(struct work_struct *work)
+{
+	struct llist_node *head;
+	struct aest_event *event;
+	struct aest_device *adev =
+		container_of(work, struct aest_device, aest_work);
+	u64 status, addr;
+
+	head = llist_del_all(&adev->event_list);
+	if (!head)
+		return;
+
+	head = llist_reverse_order(head);
+	llist_for_each_entry(event, head, llnode) {
+		aest_print(event);
+
+		status = event->regs.err_status;
+		if (!(event->regs.err_addr & ERR_ADDR_AI) &&
+		    (status & (ERR_STATUS_UE | ERR_STATUS_DE))) {
+			if (event->addressing_mode == AEST_ADDREESS_SPA)
+				addr = event->regs.err_addr & PHYS_MASK;
+			aest_handle_memory_failure(addr);
+		}
+
+		blocking_notifier_call_chain(&aest_decoder_chain, 0, event);
+		gen_pool_free(adev->pool, (unsigned long)event, sizeof(*event));
+	}
+}
+
+static int aest_node_pool_init(struct aest_device *adev)
+{
+	unsigned long addr, size;
+
+	size = ilog2(sizeof(struct aest_event));
+	adev->pool =
+		devm_gen_pool_create(adev->dev, size, -1, dev_name(adev->dev));
+	if (!adev->pool)
+		return -ENOMEM;
+
+	size = PAGE_ALIGN(size * AEST_NODE_ALLOCED_MAX);
+	addr = (unsigned long)devm_kzalloc(adev->dev, size, GFP_KERNEL);
+	if (!addr)
+		return -ENOMEM;
+
+	return gen_pool_add(adev->pool, addr, size, -1);
+}
+
+static void aest_panic(struct aest_record *record, struct ras_ext_regs *regs,
+		       char *msg)
+{
+	struct aest_event event = { 0 };
+
+	init_aest_event(&event, record, regs);
+
+	aest_print(&event);
+
+	panic(msg);
+}
+
+static void aest_proc_record(struct aest_record *record, void *data)
+{
+	struct ras_ext_regs regs = { 0 };
+	int *count = data;
+	u64 ue;
+
+	regs.err_status = record_read(record, ERXSTATUS);
+	if (!(regs.err_status & ERR_STATUS_V))
+		return;
+
+	(*count)++;
+
+	if (regs.err_status & ERR_STATUS_AV)
+		regs.err_addr = record_read(record, ERXADDR);
+
+	regs.err_fr = record_read(record, ERXFR);
+	regs.err_ctlr = record_read(record, ERXCTLR);
+
+	if (regs.err_status & ERR_STATUS_MV) {
+		regs.err_misc[0] = record_read(record, ERXMISC0);
+		regs.err_misc[1] = record_read(record, ERXMISC1);
+		if (record->node->version >= ID_AA64PFR0_EL1_RAS_V1P1) {
+			regs.err_misc[2] = record_read(record, ERXMISC2);
+			regs.err_misc[3] = record_read(record, ERXMISC3);
+		}
+
+		if (record->node->info->interface_hdr->flags &
+		    AEST_XFACE_FLAG_CLEAR_MISC) {
+			record_write(record, ERXMISC0, 0);
+			record_write(record, ERXMISC1, 0);
+			if (record->node->version >= ID_AA64PFR0_EL1_RAS_V1P1) {
+				record_write(record, ERXMISC2, 0);
+				record_write(record, ERXMISC3, 0);
+			}
+			/* ce count is 0 if record do not support ce */
+		} else if (record->ce.count > 0)
+			record_write(record, ERXMISC0, record->ce.reg_val);
+	}
+
+	/* panic if unrecoverable and uncontainable error encountered */
+	ue = FIELD_GET(ERR_STATUS_UET, regs.err_status);
+	if ((regs.err_status & ERR_STATUS_UE) &&
+	    (ue == ERR_STATUS_UET_UC || ue == ERR_STATUS_UET_UEU))
+		aest_panic(record, &regs,
+			   "AEST: unrecoverable error encountered");
+
+	aest_log(record, &regs);
+
+	/* Write-one-to-clear the bits we've seen */
+	regs.err_status &= ERR_STATUS_W1TC;
+
+	/* Multi bit filed need to write all-ones to clear. */
+	if (regs.err_status & ERR_STATUS_CE)
+		regs.err_status |= ERR_STATUS_CE;
+
+	/* Multi bit filed need to write all-ones to clear. */
+	if (regs.err_status & ERR_STATUS_UET)
+		regs.err_status |= ERR_STATUS_UET;
+
+	record_write(record, ERXSTATUS, regs.err_status);
+}
+
+static void aest_node_foreach_record(void (*func)(struct aest_record *, void *),
+				     struct aest_node *node, void *data,
+				     unsigned long *bitmap)
+{
+	int i;
+
+	for_each_clear_bit(i, bitmap, node->record_count) {
+		aest_select_record(node, i);
+
+		func(&node->records[i], data);
+
+		aest_sync(node);
+	}
+}
+
+static int aest_proc(struct aest_node *node)
+{
+	int count = 0, i, j, size = node->record_count;
+	u64 err_group = 0;
+
+	aest_node_dbg(node, "Poll bitmap %*pb\n", size,
+		      node->record_implemented);
+	aest_node_foreach_record(aest_proc_record, node, &count,
+				 node->record_implemented);
+
+	if (!node->errgsr)
+		return count;
+
+	aest_node_dbg(node, "Report bitmap %*pb\n", size,
+		      node->status_reporting);
+	for (i = 0; i < BITS_TO_U64(size); i++) {
+		err_group = readq_relaxed((void *)node->errgsr + i * 8);
+		aest_node_dbg(node, "errgsr[%d]: 0x%llx\n", i, err_group);
+
+		for_each_set_bit(j, (unsigned long *)&err_group,
+				 BITS_PER_LONG) {
+			/*
+			 * Error group base is only valid in Memory Map node,
+			 * so driver do not need to write select register and
+			 * sync.
+			 */
+			if (test_bit(i * BITS_PER_LONG + j,
+				     node->status_reporting))
+				continue;
+			aest_proc_record(&node->records[j], &count);
+		}
+	}
+
+	return count;
+}
+
+static irqreturn_t aest_irq_func(int irq, void *input)
+{
+	struct aest_device *adev = input;
+	int i;
+
+	for (i = 0; i < adev->node_cnt; i++)
+		aest_proc(&adev->nodes[i]);
+
+	return IRQ_HANDLED;
+}
+
+static int aest_register_irq(struct aest_device *adev)
+{
+	int i, irq, ret;
+	char *irq_desc;
+
+	irq_desc = devm_kasprintf(adev->dev, GFP_KERNEL, "%s.%s.",
+				  dev_driver_string(adev->dev),
+				  dev_name(adev->dev));
+	if (!irq_desc)
+		return -ENOMEM;
+
+	for (i = 0; i < MAX_GSI_PER_NODE; i++) {
+		irq = adev->irq[i];
+
+		if (!irq)
+			continue;
+
+		if (irq_is_percpu_devid(irq)) {
+			ret = request_percpu_irq(irq, aest_irq_func, irq_desc,
+						 adev->adev_oncore);
+			if (ret)
+				goto free;
+		} else {
+			ret = devm_request_irq(adev->dev, irq, aest_irq_func, 0,
+					       irq_desc, adev);
+			if (ret)
+				return ret;
+		}
+	}
+	return 0;
+
+free:
+	for (; i >= 0; i--) {
+		irq = adev->irq[i];
+
+		if (irq_is_percpu_devid(irq))
+			free_percpu_irq(irq, adev->adev_oncore);
+	}
+
+	return ret;
+}
+
+static void aest_enable_irq(struct aest_record *record)
+{
+	u64 err_ctlr;
+	struct aest_device *adev = record->node->adev;
+
+	err_ctlr = record_read(record, ERXCTLR);
+
+	if (adev->irq[ACPI_AEST_NODE_FAULT_HANDLING])
+		err_ctlr |= (ERR_CTLR_FI | ERR_CTLR_CFI);
+	if (adev->irq[ACPI_AEST_NODE_ERROR_RECOVERY])
+		err_ctlr |= ERR_CTLR_UI;
+
+	record_write(record, ERXCTLR, err_ctlr);
+}
+
+static void aest_config_irq(struct aest_node *node)
+{
+	int i;
+	struct acpi_aest_node_interrupt_v2 *interrupt;
+
+	if (!node->irq_config)
+		return;
+
+	for (i = 0; i < node->info->interrupt_count; i++) {
+		interrupt = &node->info->interrupt[i];
+
+		if (interrupt->type == ACPI_AEST_NODE_FAULT_HANDLING)
+			writeq_relaxed(interrupt->gsiv, node->irq_config);
+
+		if (interrupt->type == ACPI_AEST_NODE_ERROR_RECOVERY)
+			writeq_relaxed(interrupt->gsiv, node->irq_config + 8);
+
+		aest_node_dbg(node, "config irq type %d gsiv %d at %llx",
+			      interrupt->type, interrupt->gsiv,
+			      (u64)node->irq_config);
+	}
+}
+
 static enum ras_ce_threshold aest_get_ce_threshold(struct aest_record *record)
 {
 	u64 err_fr, err_fr_cec, err_fr_rp = -1;
@@ -128,6 +564,7 @@ static int aest_init_record(struct aest_record *record, int i,
 	record->index = i;
 	record->node = node;
 	aest_set_ce_threshold(record);
+	aest_enable_irq(record);
 
 	aest_record_dbg(record, "base: %p, index: %d, address mode: %x\n",
 			record->regs_base, record->index,
@@ -232,6 +669,21 @@ static int aest_init_node(struct aest_device *adev, struct aest_node *node,
 		}
 	}
 
+	address = node->info->common->interrupt_config_register_base;
+	if ((flags & AEST_XFACE_FLAG_INT_CONFIG) && address) {
+		if (address - anode->interface_hdr->address < node->group->size)
+			node->irq_config =
+				node->base +
+				(address - anode->interface_hdr->address);
+		else {
+			node->irq_config =
+				devm_ioremap(adev->dev, address, PAGE_SIZE);
+			if (!node->irq_config)
+				return -ENOMEM;
+		}
+	}
+	aest_config_irq(node);
+
 	ret = aest_node_set_errgsr(adev, node);
 	if (ret)
 		return ret;
@@ -276,6 +728,66 @@ static int aest_init_nodes(struct aest_device *adev, struct aest_hnode *ahnode)
 	return 0;
 }
 
+static int __setup_ppi(struct aest_device *adev)
+{
+	int cpu, i;
+	struct aest_device *oncore_adev;
+	struct aest_node *oncore_node;
+	size_t size;
+
+	adev->adev_oncore = &percpu_adev;
+	for_each_possible_cpu(cpu) {
+		oncore_adev = per_cpu_ptr(&percpu_adev, cpu);
+		memcpy(oncore_adev, adev, sizeof(struct aest_device));
+
+		oncore_adev->nodes =
+			devm_kcalloc(adev->dev, oncore_adev->node_cnt,
+				     sizeof(struct aest_node), GFP_KERNEL);
+		if (!oncore_adev->nodes)
+			return -ENOMEM;
+
+		size = adev->node_cnt * sizeof(struct aest_node);
+		memcpy(oncore_adev->nodes, adev->nodes, size);
+		for (i = 0; i < oncore_adev->node_cnt; i++) {
+			oncore_node = &oncore_adev->nodes[i];
+			oncore_node->records = devm_kcalloc(
+				adev->dev, oncore_node->record_count,
+				sizeof(struct aest_record), GFP_KERNEL);
+			if (!oncore_node->records)
+				return -ENOMEM;
+
+			size = oncore_node->record_count *
+			       sizeof(struct aest_record);
+			memcpy(oncore_node->records, adev->nodes[i].records,
+			       size);
+		}
+
+		aest_dev_dbg(adev, "Init device on CPU%d.\n", cpu);
+	}
+
+	return 0;
+}
+
+static int aest_setup_irq(struct platform_device *pdev,
+			  struct aest_device *adev)
+{
+	int fhi_irq, eri_irq;
+
+	fhi_irq = platform_get_irq_byname_optional(pdev, AEST_FHI_NAME);
+	if (fhi_irq > 0)
+		adev->irq[0] = fhi_irq;
+
+	eri_irq = platform_get_irq_byname_optional(pdev, AEST_ERI_NAME);
+	if (eri_irq > 0)
+		adev->irq[1] = eri_irq;
+
+	/* Allocate and initialise the percpu device pointer for PPI */
+	if (irq_is_percpu(fhi_irq) || irq_is_percpu(eri_irq))
+		return __setup_ppi(adev);
+
+	return 0;
+}
+
 static int aest_device_probe(struct platform_device *pdev)
 {
 	int ret;
@@ -289,14 +801,31 @@ static int aest_device_probe(struct platform_device *pdev)
 	adev = devm_kzalloc(&pdev->dev, sizeof(*adev), GFP_KERNEL);
 	if (!adev)
 		return -ENOMEM;
-
 	adev->dev = &pdev->dev;
 	adev->id = pdev->id;
 	aest_set_name(adev, ahnode);
+
+	INIT_WORK(&adev->aest_work, aest_node_pool_process);
+	ret = aest_node_pool_init(adev);
+	if (ret) {
+		aest_dev_err(adev, "Failed init aest node pool.\n");
+		return ret;
+	}
+	init_llist_head(&adev->event_list);
+
 	ret = aest_init_nodes(adev, ahnode);
 	if (ret)
 		return ret;
 
+	ret = aest_setup_irq(pdev, adev);
+	if (ret)
+		return ret;
+
+	ret = aest_register_irq(adev);
+	if (ret) {
+		aest_dev_err(adev, "register irq failed\n");
+		return ret;
+	}
 	platform_set_drvdata(pdev, adev);
 
 	aest_dev_dbg(adev, "Node cnt: %x, id: %x\n", adev->node_cnt, adev->id);
diff --git a/drivers/ras/aest/aest.h b/drivers/ras/aest/aest.h
index 85eeed79bcbe..a5e43b2a2e90 100644
--- a/drivers/ras/aest/aest.h
+++ b/drivers/ras/aest/aest.h
@@ -67,6 +67,34 @@
 
 #define GIC_ERRDEVARCH 0xFFBC
 
+struct aest_event {
+	struct llist_node llnode;
+	char *node_name;
+	u32 type;
+	/*
+	 * Different nodes have different meanings:
+	 *   - Processor node	: processor number.
+	 *   - Memory node	: SRAT proximity domain.
+	 *   - SMMU node	: IORT proximity domain.
+	 *   - GIC node		: interface type.
+	 */
+	u32 id0;
+	/*
+	 * Different nodes have different meanings:
+	 *   - Processor node	: processor resource type.
+	 *   - Memory node	: Non.
+	 *   - SMMU node	: subcomponent reference.
+	 *   - Vendor node	: Unique ID.
+	 *   - GIC node		: instance identifier.
+	 */
+	u32 id1;
+	/* Vendor node	: hardware ID. */
+	char *hid;
+	u32 index;
+	int addressing_mode;
+	struct ras_ext_regs regs;
+};
+
 struct aest_access {
 	u64 (*read)(void *base, u32 offset);
 	void (*write)(void *base, u32 offset, u64 val);
@@ -141,6 +169,7 @@ struct aest_node {
 	void *errgsr;
 	void *base;
 	void *inj;
+	void *irq_config;
 
 	/*
 	 * This bitmap indicates which of the error records within this error
@@ -172,6 +201,7 @@ struct aest_node {
 
 	int record_count;
 	struct aest_record *records;
+	struct aest_node __percpu *oncore_node;
 };
 
 struct aest_device {
@@ -180,6 +210,12 @@ struct aest_device {
 	int node_cnt;
 	struct aest_node *nodes;
 	u32 id;
+	int irq[MAX_GSI_PER_NODE];
+
+	struct work_struct aest_work;
+	struct gen_pool *pool;
+	struct llist_head event_list;
+	struct aest_device __percpu *adev_oncore;
 };
 
 static const char *const aest_node_name[] = {
@@ -283,3 +319,23 @@ static const struct aest_access aest_access[] = {
 	},
 	{ }
 };
+
+/*
+ * Each PE may has multi error record, you must selects an error
+ * record to be accessed through the Error Record System
+ * registers.
+ */
+static inline void aest_select_record(struct aest_node *node, int index)
+{
+	if (node->type == ACPI_AEST_PROCESSOR_ERROR_NODE) {
+		write_sysreg_s(index, SYS_ERRSELR_EL1);
+		isb();
+	}
+}
+
+/* Ensure all writes has taken effect. */
+static inline void aest_sync(struct aest_node *node)
+{
+	if (node->type == ACPI_AEST_PROCESSOR_ERROR_NODE)
+		isb();
+}
diff --git a/include/linux/acpi_aest.h b/include/linux/acpi_aest.h
index a7898c643896..3a899f57f92f 100644
--- a/include/linux/acpi_aest.h
+++ b/include/linux/acpi_aest.h
@@ -10,6 +10,13 @@
 #define AEST_FHI_NAME "AEST:FHI"
 #define AEST_ERI_NAME "AEST:ERI"
 
+/* AEST component */
+#define ACPI_AEST_PROC_FLAG_GLOBAL	(1<<0)
+#define ACPI_AEST_PROC_FLAG_SHARED	(1<<1)
+
+#define AEST_ADDREESS_SPA	0
+#define AEST_ADDREESS_LA	1
+
 /* AEST interrupt */
 #define AEST_INTERRUPT_MODE BIT(0)
 
diff --git a/include/linux/ras.h b/include/linux/ras.h
index 468941bfe855..05096f049dac 100644
--- a/include/linux/ras.h
+++ b/include/linux/ras.h
@@ -63,4 +63,12 @@ amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err) { return -EINVAL; }
 #define GET_LOGICAL_INDEX(mpidr) -EINVAL
 #endif /* CONFIG_ARM || CONFIG_ARM64 */
 
+#if IS_ENABLED(CONFIG_AEST)
+void aest_register_decode_chain(struct notifier_block *nb);
+void aest_unregister_decode_chain(struct notifier_block *nb);
+#else
+static inline void aest_register_decode_chain(struct notifier_block *nb) {}
+static inline void aest_unregister_decode_chain(struct notifier_block *nb) {}
+#endif /* CONFIG_AEST */
+
 #endif /* __RAS_H__ */
-- 
2.47.3



From tianruidong at linux.alibaba.com  Tue Dec 30 01:09:38 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Tue, 30 Dec 2025 17:09:38 +0800
Subject: [PATCH v5 10/17] ras: AEST: Introduce AEST driver sysfs interface
In-Reply-To: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
References: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
Message-ID: <20251230090945.43969-11-tianruidong@linux.alibaba.com>

Exposes certain AEST driver information to userspace.

Only ROOT can access these interface because it includes
hardware-sensitive information:

  ls /sys/kernel/debug/aest/
  memory<id> smmu<id> ...

  ls /sys/kernel/debug/aest/memory<id>/
  record0 record1 ...

All details at:
        Documentation/ABI/testing/debugfs-aest

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 Documentation/ABI/testing/debugfs-aest |  32 +++++++
 MAINTAINERS                            |   1 +
 drivers/ras/aest/Makefile              |   1 +
 drivers/ras/aest/aest-core.c           |  13 +++
 drivers/ras/aest/aest-sysfs.c          | 118 +++++++++++++++++++++++++
 drivers/ras/aest/aest.h                |   8 ++
 6 files changed, 173 insertions(+)
 create mode 100644 Documentation/ABI/testing/debugfs-aest
 create mode 100644 drivers/ras/aest/aest-sysfs.c

diff --git a/Documentation/ABI/testing/debugfs-aest b/Documentation/ABI/testing/debugfs-aest
new file mode 100644
index 000000000000..8bacc6bb20b6
--- /dev/null
+++ b/Documentation/ABI/testing/debugfs-aest
@@ -0,0 +1,32 @@
+What:		/sys/kernel/debug/aest/<name>.<id>/
+Date:		Dec 2025
+KernelVersion:	6.19
+Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
+Description:
+		Directory represented a AEST device, <name> means device type,
+		like:
+
+		- processor
+		- memory
+		- smmu
+		- ...
+
+		<id> is the unique ID for this device.
+
+What:		/sys/kernel/debug/aest/<name>.<id>/<node_name>/*
+Date:		Dec 2025
+KernelVersion:	6.19
+Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
+Description:
+		Attibute for aest node which belong this device, the format
+		of node name is: <Node Type>-<Node Address>
+
+		See more at:
+			https://developer.arm.com/documentation/den0085/latest/
+
+What:		/sys/kernel/debug/aest/<name>.<id>/<node_name>/record<index>/err_*
+Date:		Dec 2025
+KernelVersion:	6.19
+Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
+Description:
+		(RO) Read err_* register and return val.
diff --git a/MAINTAINERS b/MAINTAINERS
index e2ffd89c6bb8..1b6e2300d11d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -346,6 +346,7 @@ M:	Ruidong Tian <tianruidond at linux.alibaba.com>
 L:	linux-acpi at vger.kernel.org
 L:	linux-arm-kernel at lists.infradead.org
 S:	Supported
+F:	Documentation/ABI/testing/debugfs-aest
 F:	arch/arm64/include/asm/ras.h
 F:	drivers/acpi/arm64/aest.c
 F:	drivers/ras/aest/
diff --git a/drivers/ras/aest/Makefile b/drivers/ras/aest/Makefile
index a6ba7e36fb43..75495413d2b6 100644
--- a/drivers/ras/aest/Makefile
+++ b/drivers/ras/aest/Makefile
@@ -3,3 +3,4 @@
 obj-$(CONFIG_AEST) 	+= aest.o
 
 aest-y		:= aest-core.o
+aest-y		+= aest-sysfs.o
diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index 686dde6f2e68..3bcc635cf8e4 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -20,6 +20,9 @@ DEFINE_PER_CPU(struct aest_device, percpu_adev);
 #undef pr_fmt
 #define pr_fmt(fmt) "AEST: " fmt
 
+#ifdef CONFIG_DEBUG_FS
+struct dentry *aest_debugfs;
+#endif
 /*
  * This memory pool is only to be used to save AEST node in AEST irq context.
  * There can be 500 AEST node at most.
@@ -940,6 +943,8 @@ static int aest_device_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, adev);
 
+	aest_dev_init_debugfs(adev);
+
 	aest_dev_dbg(adev, "Node cnt: %x, id: %x\n", adev->node_cnt, adev->id);
 
 	return 0;
@@ -955,12 +960,20 @@ static struct platform_driver aest_driver = {
 
 static int __init aest_init(void)
 {
+#ifdef CONFIG_DEBUG_FS
+	aest_debugfs = debugfs_create_dir("aest", NULL);
+#endif
+
 	return platform_driver_register(&aest_driver);
 }
 module_init(aest_init);
 
 static void __exit aest_exit(void)
 {
+#ifdef CONFIG_DEBUG_FS
+	debugfs_remove(aest_debugfs);
+#endif
+
 	platform_driver_unregister(&aest_driver);
 }
 module_exit(aest_exit);
diff --git a/drivers/ras/aest/aest-sysfs.c b/drivers/ras/aest/aest-sysfs.c
new file mode 100644
index 000000000000..f3b5427ff4f0
--- /dev/null
+++ b/drivers/ras/aest/aest-sysfs.c
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ARM Error Source Table Support
+ *
+ * Copyright (c) 2025, Alibaba Group.
+ */
+
+#include "aest.h"
+
+/*******************************************************************************
+ *
+ * Attribute for AEST record
+ *
+ ******************************************************************************/
+
+#define DEFINE_AEST_DEBUGFS_ATTR(name, offset) \
+static int name##_get(void *data, u64 *val) \
+{ \
+	struct aest_record *record = data; \
+	*val = record_read(record, offset); \
+	return 0; \
+} \
+static int name##_set(void *data, u64 val) \
+{ \
+	struct aest_record *record = data; \
+	record_write(record, offset, val); \
+	return 0; \
+} \
+DEFINE_DEBUGFS_ATTRIBUTE(name##_ops, name##_get, name##_set, "%#llx\n")
+
+DEFINE_AEST_DEBUGFS_ATTR(err_fr, ERXFR);
+DEFINE_AEST_DEBUGFS_ATTR(err_ctrl, ERXCTLR);
+DEFINE_AEST_DEBUGFS_ATTR(err_status, ERXSTATUS);
+DEFINE_AEST_DEBUGFS_ATTR(err_addr, ERXADDR);
+DEFINE_AEST_DEBUGFS_ATTR(err_misc0, ERXMISC0);
+DEFINE_AEST_DEBUGFS_ATTR(err_misc1, ERXMISC1);
+DEFINE_AEST_DEBUGFS_ATTR(err_misc2, ERXMISC2);
+DEFINE_AEST_DEBUGFS_ATTR(err_misc3, ERXMISC3);
+
+static void aest_record_init_debugfs(struct aest_record *record)
+{
+	debugfs_create_file("err_fr", 0600, record->debugfs, record,
+								&err_fr_ops);
+	debugfs_create_file("err_ctrl", 0600, record->debugfs, record,
+								&err_ctrl_ops);
+	debugfs_create_file("err_status", 0600, record->debugfs, record,
+								&err_status_ops);
+	debugfs_create_file("err_addr", 0600, record->debugfs, record,
+								&err_addr_ops);
+	debugfs_create_file("err_misc0", 0600, record->debugfs, record,
+								&err_misc0_ops);
+	debugfs_create_file("err_misc1", 0600, record->debugfs, record,
+								&err_misc1_ops);
+	debugfs_create_file("err_misc2", 0600, record->debugfs, record,
+								&err_misc2_ops);
+	debugfs_create_file("err_misc3", 0600, record->debugfs, record,
+								&err_misc3_ops);
+}
+
+static void
+aest_node_init_debugfs(struct aest_node *node)
+{
+	int i;
+	struct aest_record *record;
+
+	for (i = 0; i < node->record_count; i++) {
+		record = &node->records[i];
+		if (!record->name)
+			continue;
+		record->debugfs = debugfs_create_dir(record->name,
+								node->debugfs);
+		aest_record_init_debugfs(record);
+	}
+}
+
+static void
+aest_oncore_dev_init_debugfs(struct aest_device *adev)
+{
+	int cpu, i;
+	struct aest_node *node;
+	struct aest_device *percpu_dev;
+	char name[16];
+
+	for_each_possible_cpu(cpu) {
+		percpu_dev = this_cpu_ptr(adev->adev_oncore);
+
+		snprintf(name, sizeof(name), "processor%u", cpu);
+		percpu_dev->debugfs = debugfs_create_dir(name, aest_debugfs);
+
+		for (i = 0; i < adev->node_cnt; i++) {
+			node = &adev->nodes[i];
+
+			node->debugfs = debugfs_create_dir(node->name,
+							percpu_dev->debugfs);
+			aest_node_init_debugfs(node);
+		}
+	}
+}
+
+void aest_dev_init_debugfs(struct aest_device *adev)
+{
+	int i;
+	struct aest_node *node;
+
+	adev->debugfs = debugfs_create_dir(dev_name(adev->dev), aest_debugfs);
+	if (aest_dev_is_oncore(adev)) {
+		aest_oncore_dev_init_debugfs(adev);
+		return;
+	}
+
+	for (i = 0; i < adev->node_cnt; i++) {
+		node = &adev->nodes[i];
+		if (!node->name)
+			continue;
+		node->debugfs = debugfs_create_dir(node->name, adev->debugfs);
+		aest_node_init_debugfs(node);
+	}
+}
diff --git a/drivers/ras/aest/aest.h b/drivers/ras/aest/aest.h
index f85e81ff35a6..ceb9e32bcee3 100644
--- a/drivers/ras/aest/aest.h
+++ b/drivers/ras/aest/aest.h
@@ -7,6 +7,7 @@
 
 #include <linux/acpi_aest.h>
 #include <asm/ras.h>
+#include <linux/debugfs.h>
 
 #define MAX_GSI_PER_NODE 2
 #define DEFAULT_CE_THRESHOLD 1
@@ -67,6 +68,8 @@
 
 #define GIC_ERRDEVARCH 0xFFBC
 
+extern struct dentry *aest_debugfs;
+
 struct aest_event {
 	struct llist_node llnode;
 	char *node_name;
@@ -133,6 +136,7 @@ struct aest_record {
 
 	struct ce_threshold ce;
 	enum ras_ce_threshold threshold_type;
+	struct dentry *debugfs;
 };
 
 struct aest_group {
@@ -201,6 +205,7 @@ struct aest_node {
 
 	int record_count;
 	struct aest_record *records;
+	struct dentry *debugfs;
 	struct aest_node __percpu *oncore_node;
 };
 
@@ -215,6 +220,7 @@ struct aest_device {
 	struct work_struct aest_work;
 	struct gen_pool *pool;
 	struct llist_head event_list;
+	struct dentry *debugfs;
 	struct aest_device __percpu *adev_oncore;
 };
 
@@ -344,3 +350,5 @@ static inline bool aest_dev_is_oncore(struct aest_device *adev)
 {
 	return adev->type == ACPI_AEST_PROCESSOR_ERROR_NODE;
 }
+
+void aest_dev_init_debugfs(struct aest_device *adev);
-- 
2.47.3



From tianruidong at linux.alibaba.com  Tue Dec 30 01:09:37 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Tue, 30 Dec 2025 17:09:37 +0800
Subject: [PATCH v5 09/17] ras: AEST: Add cpuhp callback
In-Reply-To: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
References: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
Message-ID: <20251230090945.43969-10-tianruidong@linux.alibaba.com>

Move the configuration of interrupts and CE thresholds
into the CPU hotplug callbacks for the per-CPU AEST node.

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 drivers/ras/aest/aest-core.c | 118 ++++++++++++++++++++++++++++++++++-
 drivers/ras/aest/aest.h      |   5 ++
 include/linux/cpuhotplug.h   |   1 +
 3 files changed, 121 insertions(+), 3 deletions(-)

diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index 5ec0ba38f51b..686dde6f2e68 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -5,6 +5,7 @@
  * Copyright (c) 2025, Alibaba Group.
  */
 
+#include <linux/cpu.h>
 #include <linux/interrupt.h>
 #include <linux/panic.h>
 #include <linux/platform_device.h>
@@ -563,8 +564,6 @@ static int aest_init_record(struct aest_record *record, int i,
 	record->addressing_mode = test_bit(i, node->info->addressing_mode);
 	record->index = i;
 	record->node = node;
-	aest_set_ce_threshold(record);
-	aest_enable_irq(record);
 
 	aest_record_dbg(record, "base: %p, index: %d, address mode: %x\n",
 			record->regs_base, record->index,
@@ -572,9 +571,113 @@ static int aest_init_record(struct aest_record *record, int i,
 	return 0;
 }
 
+static void aest_online_record(struct aest_record *record, void *data)
+{
+	if (record_read(record, ERXFR) & ERR_FR_CE)
+		aest_set_ce_threshold(record);
+
+	aest_enable_irq(record);
+}
+
+static void aest_online_oncore_node(struct aest_node *node)
+{
+	int count;
+
+	count = aest_proc(node);
+	aest_node_dbg(node, "Find %d error on CPU%d before AEST probe\n", count,
+		      smp_processor_id());
+
+	aest_node_foreach_record(aest_online_record, node, NULL,
+				 node->record_implemented);
+
+	aest_node_foreach_record(aest_online_record, node, NULL,
+				 node->status_reporting);
+}
+
+static void aest_online_oncore_dev(void *data)
+{
+	int fhi_irq, eri_irq, i;
+	struct aest_device *adev = this_cpu_ptr(data);
+
+	for (i = 0; i < adev->node_cnt; i++)
+		aest_online_oncore_node(&adev->nodes[i]);
+
+	fhi_irq = adev->irq[ACPI_AEST_NODE_FAULT_HANDLING];
+	if (fhi_irq > 0)
+		enable_percpu_irq(fhi_irq, IRQ_TYPE_NONE);
+	eri_irq = adev->irq[ACPI_AEST_NODE_ERROR_RECOVERY];
+	if (eri_irq > 0)
+		enable_percpu_irq(eri_irq, IRQ_TYPE_NONE);
+}
+
+static void aest_offline_oncore_dev(void *data)
+{
+	int fhi_irq, eri_irq;
+	struct aest_device *adev = this_cpu_ptr(data);
+
+	fhi_irq = adev->irq[ACPI_AEST_NODE_FAULT_HANDLING];
+	if (fhi_irq > 0)
+		disable_percpu_irq(fhi_irq);
+	eri_irq = adev->irq[ACPI_AEST_NODE_ERROR_RECOVERY];
+	if (eri_irq > 0)
+		disable_percpu_irq(eri_irq);
+}
+
+static void aest_online_dev(struct aest_device *adev)
+{
+	int count, i;
+	struct aest_node *node;
+
+	for (i = 0; i < adev->node_cnt; i++) {
+		node = &adev->nodes[i];
+
+		if (!node->name)
+			continue;
+
+		count = aest_proc(node);
+		aest_node_dbg(node, "Find %d error before AEST probe\n", count);
+
+		aest_config_irq(node);
+
+		aest_node_foreach_record(aest_online_record, node, NULL,
+					 node->record_implemented);
+		aest_node_foreach_record(aest_online_record, node, NULL,
+					 node->status_reporting);
+	}
+}
+
+static int aest_starting_cpu(unsigned int cpu)
+{
+	pr_debug("CPU%d starting\n", cpu);
+	aest_online_oncore_dev(&percpu_adev);
+
+	return 0;
+}
+
+static int aest_dying_cpu(unsigned int cpu)
+{
+	pr_debug("CPU%d dying\n", cpu);
+	aest_offline_oncore_dev(&percpu_adev);
+
+	return 0;
+}
+
 static void aest_device_remove(struct platform_device *pdev)
 {
+	struct aest_device *adev = platform_get_drvdata(pdev);
+	int i;
+
 	platform_set_drvdata(pdev, NULL);
+
+	if (adev->type != ACPI_AEST_PROCESSOR_ERROR_NODE)
+		return;
+
+	on_each_cpu(aest_offline_oncore_dev, adev->adev_oncore, 1);
+
+	for (i = 0; i < MAX_GSI_PER_NODE; i++) {
+		if (adev->irq[i])
+			free_percpu_irq(adev->irq[i], adev->adev_oncore);
+	}
 }
 
 static char *alloc_aest_node_name(struct aest_node *node)
@@ -682,7 +785,6 @@ static int aest_init_node(struct aest_device *adev, struct aest_node *node,
 				return -ENOMEM;
 		}
 	}
-	aest_config_irq(node);
 
 	ret = aest_node_set_errgsr(adev, node);
 	if (ret)
@@ -826,6 +928,16 @@ static int aest_device_probe(struct platform_device *pdev)
 		aest_dev_err(adev, "register irq failed\n");
 		return ret;
 	}
+
+	if (aest_dev_is_oncore(adev))
+		ret = cpuhp_setup_state(CPUHP_AP_ARM_AEST_STARTING,
+					"drivers/acpi/arm64/aest:starting",
+					aest_starting_cpu, aest_dying_cpu);
+	else
+		aest_online_dev(adev);
+	if (ret)
+		return ret;
+
 	platform_set_drvdata(pdev, adev);
 
 	aest_dev_dbg(adev, "Node cnt: %x, id: %x\n", adev->node_cnt, adev->id);
diff --git a/drivers/ras/aest/aest.h b/drivers/ras/aest/aest.h
index a5e43b2a2e90..f85e81ff35a6 100644
--- a/drivers/ras/aest/aest.h
+++ b/drivers/ras/aest/aest.h
@@ -339,3 +339,8 @@ static inline void aest_sync(struct aest_node *node)
 	if (node->type == ACPI_AEST_PROCESSOR_ERROR_NODE)
 		isb();
 }
+
+static inline bool aest_dev_is_oncore(struct aest_device *adev)
+{
+	return adev->type == ACPI_AEST_PROCESSOR_ERROR_NODE;
+}
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 62cd7b35a29c..831fe9011943 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -179,6 +179,7 @@ enum cpuhp_state {
 	CPUHP_AP_HYPERV_TIMER_STARTING,
 	/* Must be the last timer callback */
 	CPUHP_AP_DUMMY_TIMER_STARTING,
+	CPUHP_AP_ARM_AEST_STARTING,
 	CPUHP_AP_ARM_XEN_STARTING,
 	CPUHP_AP_ARM_XEN_RUNSTATE_STARTING,
 	CPUHP_AP_ARM_CORESIGHT_STARTING,
-- 
2.47.3



From tianruidong at linux.alibaba.com  Tue Dec 30 01:09:39 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Tue, 30 Dec 2025 17:09:39 +0800
Subject: [PATCH v5 11/17] ras: AEST: Add error count tracking and debugfs interface
In-Reply-To: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
References: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
Message-ID: <20251230090945.43969-12-tianruidong@linux.alibaba.com>

This commit introduces error counting functionality for AEST records.
Previously, error statistics were not directly available for individual
error records or AEST nodes.

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 Documentation/ABI/testing/debugfs-aest | 14 ++++++
 drivers/ras/aest/aest-core.c           | 21 +++++++++
 drivers/ras/aest/aest-sysfs.c          | 64 ++++++++++++++++++++++++++
 drivers/ras/aest/aest.h                | 10 ++++
 4 files changed, 109 insertions(+)

diff --git a/Documentation/ABI/testing/debugfs-aest b/Documentation/ABI/testing/debugfs-aest
index 8bacc6bb20b6..295df9e9b455 100644
--- a/Documentation/ABI/testing/debugfs-aest
+++ b/Documentation/ABI/testing/debugfs-aest
@@ -24,9 +24,23 @@ Description:
 		See more at:
 			https://developer.arm.com/documentation/den0085/latest/
 
+What:		/sys/kernel/debug/aest/<name>.<id>/<node_name>/err_count
+Date:		Dec 2025
+KernelVersion	6.19
+Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
+Description:
+		(RO) Outputs error statistics for all error records of this node.
+
 What:		/sys/kernel/debug/aest/<name>.<id>/<node_name>/record<index>/err_*
 Date:		Dec 2025
 KernelVersion:	6.19
 Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
 Description:
 		(RO) Read err_* register and return val.
+
+What:		/sys/kernel/debug/aest/<name>.<id>/<node_name>/record<index>/err_count
+Date:		Dec 2025
+KernelVersion	6.19
+Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
+Description:
+		(RO) Outputs error statistics for all this records.
diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index 3bcc635cf8e4..75cca98024ad 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -170,6 +170,27 @@ static int aest_node_gen_pool_add(struct aest_device *adev,
 	init_aest_event(event, record, regs);
 	llist_add(&event->llnode, &adev->event_list);
 
+	if (regs->err_status & ERR_STATUS_CE)
+		record->count.ce++;
+	if (regs->err_status & ERR_STATUS_DE)
+		record->count.de++;
+	if (regs->err_status & ERR_STATUS_UE) {
+		switch (regs->err_status & ERR_STATUS_UET) {
+		case ERR_STATUS_UET_UC:
+			record->count.uc++;
+			break;
+		case ERR_STATUS_UET_UEU:
+			record->count.ueu++;
+			break;
+		case ERR_STATUS_UET_UER:
+			record->count.uer++;
+			break;
+		case ERR_STATUS_UET_UEO:
+			record->count.ueo++;
+			break;
+		}
+	}
+
 	return 0;
 }
 
diff --git a/drivers/ras/aest/aest-sysfs.c b/drivers/ras/aest/aest-sysfs.c
index f3b5427ff4f0..b54e879506aa 100644
--- a/drivers/ras/aest/aest-sysfs.c
+++ b/drivers/ras/aest/aest-sysfs.c
@@ -7,6 +7,46 @@
 
 #include "aest.h"
 
+static void
+aest_error_count(struct aest_record *record, void *data)
+{
+	struct record_count *count = data;
+
+	count->ce += record->count.ce;
+	count->de += record->count.de;
+	count->uc += record->count.uc;
+	count->ueu += record->count.ueu;
+	count->uer += record->count.uer;
+	count->ueo += record->count.ueo;
+}
+
+/*******************************************************************************
+ *
+ * Debugfs for AEST node
+ *
+ ******************************************************************************/
+
+static int aest_node_err_count_show(struct seq_file *m, void *data)
+{
+	struct aest_node *node = m->private;
+	struct record_count count = { 0 };
+	int i;
+
+	for (i = 0; i < node->record_count; i++)
+		aest_error_count(&node->records[i], &count);
+
+	seq_printf(m, "CE: %llu\n"
+				"DE: %llu\n"
+				"UC: %llu\n"
+				"UEU: %llu\n"
+				"UEO: %llu\n"
+				"UER: %llu\n",
+				count.ce, count.de, count.uc, count.ueu,
+				count.uer, count.ueo);
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(aest_node_err_count);
+
 /*******************************************************************************
  *
  * Attribute for AEST record
@@ -37,6 +77,25 @@ DEFINE_AEST_DEBUGFS_ATTR(err_misc1, ERXMISC1);
 DEFINE_AEST_DEBUGFS_ATTR(err_misc2, ERXMISC2);
 DEFINE_AEST_DEBUGFS_ATTR(err_misc3, ERXMISC3);
 
+static int aest_record_err_count_show(struct seq_file *m, void *data)
+{
+	struct aest_record *record = m->private;
+	struct record_count count = { 0 };
+
+	aest_error_count(record, &count);
+
+	seq_printf(m, "CE: %llu\n"
+				"DE: %llu\n"
+				"UC: %llu\n"
+				"UEU: %llu\n"
+				"UEO: %llu\n"
+				"UER: %llu\n",
+				count.ce, count.de, count.uc, count.ueu,
+				count.uer, count.ueo);
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(aest_record_err_count);
+
 static void aest_record_init_debugfs(struct aest_record *record)
 {
 	debugfs_create_file("err_fr", 0600, record->debugfs, record,
@@ -55,6 +114,8 @@ static void aest_record_init_debugfs(struct aest_record *record)
 								&err_misc2_ops);
 	debugfs_create_file("err_misc3", 0600, record->debugfs, record,
 								&err_misc3_ops);
+	debugfs_create_file("err_count", 0400, record->debugfs, record,
+						&aest_record_err_count_fops);
 }
 
 static void
@@ -63,6 +124,9 @@ aest_node_init_debugfs(struct aest_node *node)
 	int i;
 	struct aest_record *record;
 
+	debugfs_create_file("err_count", 0400, node->debugfs, node,
+					&aest_node_err_count_fops);
+
 	for (i = 0; i < node->record_count; i++) {
 		record = &node->records[i];
 		if (!record->name)
diff --git a/drivers/ras/aest/aest.h b/drivers/ras/aest/aest.h
index ceb9e32bcee3..802430857dc4 100644
--- a/drivers/ras/aest/aest.h
+++ b/drivers/ras/aest/aest.h
@@ -116,6 +116,15 @@ struct ce_threshold {
 	u64 reg_val;
 };
 
+struct record_count {
+	u64 ce;
+	u64 de;
+	u64 uc;
+	u64 uer;
+	u64 ueo;
+	u64 ueu;
+};
+
 struct aest_record {
 	char *name;
 	int index;
@@ -136,6 +145,7 @@ struct aest_record {
 
 	struct ce_threshold ce;
 	enum ras_ce_threshold threshold_type;
+	struct record_count count;
 	struct dentry *debugfs;
 };
 
-- 
2.47.3



From tianruidong at linux.alibaba.com  Tue Dec 30 01:12:51 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Tue, 30 Dec 2025 17:12:51 +0800
Subject: [PATCH v5 12/17] ras: AEST: Allow configuring CE threshold via debugfs
In-Reply-To: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
References: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
Message-ID: <20251230091251.49205-1-tianruidong@linux.alibaba.com>

This commit introduces the ability to configure the Corrected Error (CE)
threshold for AEST records through debugfs. This allows administrators to
dynamically adjust the CE threshold for error reporting.

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 Documentation/ABI/testing/debugfs-aest | 16 ++++++++++
 drivers/ras/aest/aest-sysfs.c          | 42 ++++++++++++++++++++++++++
 2 files changed, 58 insertions(+)

diff --git a/Documentation/ABI/testing/debugfs-aest b/Documentation/ABI/testing/debugfs-aest
index 295df9e9b455..4d160072d37a 100644
--- a/Documentation/ABI/testing/debugfs-aest
+++ b/Documentation/ABI/testing/debugfs-aest
@@ -24,6 +24,14 @@ Description:
 		See more at:
 			https://developer.arm.com/documentation/den0085/latest/
 
+What:		/sys/kernel/debug/aest/<name>.<id>/<node_name>/ce_threshold
+Date:		Dec 2025
+KernelVersion	6.19
+Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
+Description:
+		(WO) Write the ce threshold to all records of this node. Failed
+		if input exceeded the maximum threshold
+
 What:		/sys/kernel/debug/aest/<name>.<id>/<node_name>/err_count
 Date:		Dec 2025
 KernelVersion	6.19
@@ -38,6 +46,14 @@ Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
 Description:
 		(RO) Read err_* register and return val.
 
+What:		/sys/kernel/debug/aest/<name>.<id>/<node_name>/record<index>/ce_threshold
+Date:		Dec 2025
+KernelVersion	6.19
+Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
+Description:
+		(RW) Read and write the ce threshold to this record. Failed
+		if input exceeded the maximum threshold
+
 What:		/sys/kernel/debug/aest/<name>.<id>/<node_name>/record<index>/err_count
 Date:		Dec 2025
 KernelVersion	6.19
diff --git a/drivers/ras/aest/aest-sysfs.c b/drivers/ras/aest/aest-sysfs.c
index b54e879506aa..392e7ad8328e 100644
--- a/drivers/ras/aest/aest-sysfs.c
+++ b/drivers/ras/aest/aest-sysfs.c
@@ -7,6 +7,25 @@
 
 #include "aest.h"
 
+static void
+aest_store_threshold(struct aest_record *record, void *data)
+{
+	u64 err_misc0, *threshold = data;
+	struct ce_threshold *ce = &record->ce;
+
+	if (*threshold > ce->info->max_count)
+		return;
+
+	ce->threshold = *threshold;
+	ce->count = ce->info->max_count - ce->threshold + 1;
+
+	err_misc0 = record_read(record, ERXMISC0);
+	ce->reg_val = (err_misc0 & ~ce->info->mask) |
+			(ce->count << ce->info->shift);
+
+	record_write(record, ERXMISC0, ce->reg_val);
+}
+
 static void
 aest_error_count(struct aest_record *record, void *data)
 {
@@ -77,6 +96,27 @@ DEFINE_AEST_DEBUGFS_ATTR(err_misc1, ERXMISC1);
 DEFINE_AEST_DEBUGFS_ATTR(err_misc2, ERXMISC2);
 DEFINE_AEST_DEBUGFS_ATTR(err_misc3, ERXMISC3);
 
+static int record_ce_threshold_get(void *data, u64 *val)
+{
+	struct aest_record *record = data;
+
+	*val = record->ce.threshold;
+	return 0;
+}
+
+static int record_ce_threshold_set(void *data, u64 val)
+{
+	u64 threshold = val;
+	struct aest_record *record = data;
+
+	aest_store_threshold(record, &threshold);
+
+	return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(record_ce_threshold_ops, record_ce_threshold_get,
+					record_ce_threshold_set, "%llu\n");
+
 static int aest_record_err_count_show(struct seq_file *m, void *data)
 {
 	struct aest_record *record = m->private;
@@ -116,6 +156,8 @@ static void aest_record_init_debugfs(struct aest_record *record)
 								&err_misc3_ops);
 	debugfs_create_file("err_count", 0400, record->debugfs, record,
 						&aest_record_err_count_fops);
+	debugfs_create_file("ce_threshold", 0600, record->debugfs, record,
+						&record_ce_threshold_ops);
 }
 
 static void
-- 
2.47.3



From tianruidong at linux.alibaba.com  Tue Dec 30 01:13:10 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Tue, 30 Dec 2025 17:13:10 +0800
Subject: [PATCH v5 13/17] ras: AEST: Introduce AEST inject interface to test AEST driver
In-Reply-To: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
References: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
Message-ID: <20251230091310.49641-1-tianruidong@linux.alibaba.com>

AEST offers both soft and hard injection. Soft injection simulates errors
in software, providing flexibility to define the error register content.
Hard injection, on the other hand, utilizes error injection registers to
introduce hardware faults, strictly requiring values that adhere to their
specifications.

Read Documentation/ABI/testing/debugfs-aest to learn how to use them.

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 Documentation/ABI/testing/debugfs-aest |  37 +++++++
 drivers/ras/aest/Makefile              |   1 +
 drivers/ras/aest/aest-core.c           |  24 +++--
 drivers/ras/aest/aest-inject.c         | 131 +++++++++++++++++++++++++
 drivers/ras/aest/aest-sysfs.c          |   8 +-
 drivers/ras/aest/aest.h                |   2 +
 6 files changed, 193 insertions(+), 10 deletions(-)
 create mode 100644 drivers/ras/aest/aest-inject.c

diff --git a/Documentation/ABI/testing/debugfs-aest b/Documentation/ABI/testing/debugfs-aest
index 4d160072d37a..cc41ea7032c7 100644
--- a/Documentation/ABI/testing/debugfs-aest
+++ b/Documentation/ABI/testing/debugfs-aest
@@ -60,3 +60,40 @@ KernelVersion	6.19
 Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
 Description:
 		(RO) Outputs error statistics for all this records.
+
+What:		/sys/kernel/debug/aest/<name>.<id>/<node_name>/record<index>/inject/err_*
+Date:		Dec 2025
+KernelVersion	6.19
+Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
+Description:
+		(RW) These registers are used to simulate soft injection errors
+		by holding error register values. You can write any values
+		to them. To trigger the injection, you need to write soft_inject
+		at last. The validity of the injected error depends on the
+		value written to err_status.
+
+		Accepts values -  any.
+
+What:		/sys/kernel/debug/aest/<name>.<id>/<node_name>/record<index>/inject/soft_inject
+Date:		Dec 2025
+KernelVersion	6.19
+Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
+Description:
+		(WO) Write any value to this file to trigger the error
+		injection. Make sure you have specified all necessary error
+		parameters, i.e. this write should be the last step when
+		injecting errors.
+
+		Accepts values -  any.
+
+What:		/sys/kernel/debug/aest/<name>.<id>/<node_name>/record<index>/inject/hard_inject
+Date:		Dec 2025
+KernelVersion	6.19
+Contact:	Ruidong Tian <tianruidong at linux.alibaba.com>
+Description:
+		(WO) If the AEST table provides error injection registers,
+		you can write to them via this interface. For instance,
+		values can be written to the ERXPFGCTL register. The post-injection
+		behavior is then determined by the hardware specification.
+
+		Accepts values - any.
diff --git a/drivers/ras/aest/Makefile b/drivers/ras/aest/Makefile
index 75495413d2b6..5ee10fc8b2e9 100644
--- a/drivers/ras/aest/Makefile
+++ b/drivers/ras/aest/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_AEST) 	+= aest.o
 
 aest-y		:= aest-core.o
 aest-y		+= aest-sysfs.o
+aest-y		+= aest-inject.o
diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index 75cca98024ad..a290b482bf8b 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -273,7 +273,7 @@ static void aest_panic(struct aest_record *record, struct ras_ext_regs *regs,
 	panic(msg);
 }
 
-static void aest_proc_record(struct aest_record *record, void *data)
+void aest_proc_record(struct aest_record *record, void *data, bool fake)
 {
 	struct ras_ext_regs regs = { 0 };
 	int *count = data;
@@ -315,9 +315,15 @@ static void aest_proc_record(struct aest_record *record, void *data)
 	/* panic if unrecoverable and uncontainable error encountered */
 	ue = FIELD_GET(ERR_STATUS_UET, regs.err_status);
 	if ((regs.err_status & ERR_STATUS_UE) &&
-	    (ue == ERR_STATUS_UET_UC || ue == ERR_STATUS_UET_UEU))
-		aest_panic(record, &regs,
-			   "AEST: unrecoverable error encountered");
+	    (ue == ERR_STATUS_UET_UC || ue == ERR_STATUS_UET_UEU)) {
+		if (fake)
+			aest_record_info(
+				record,
+				"Simulated error! Skip panic due to fault injection\n");
+		else
+			aest_panic(record, &regs,
+				   "AEST: unrecoverable error encountered");
+	}
 
 	aest_log(record, &regs);
 
@@ -335,7 +341,8 @@ static void aest_proc_record(struct aest_record *record, void *data)
 	record_write(record, ERXSTATUS, regs.err_status);
 }
 
-static void aest_node_foreach_record(void (*func)(struct aest_record *, void *),
+static void aest_node_foreach_record(void (*func)(struct aest_record *, void *,
+						  bool),
 				     struct aest_node *node, void *data,
 				     unsigned long *bitmap)
 {
@@ -344,7 +351,7 @@ static void aest_node_foreach_record(void (*func)(struct aest_record *, void *),
 	for_each_clear_bit(i, bitmap, node->record_count) {
 		aest_select_record(node, i);
 
-		func(&node->records[i], data);
+		func(&node->records[i], data, false);
 
 		aest_sync(node);
 	}
@@ -379,7 +386,7 @@ static int aest_proc(struct aest_node *node)
 			if (test_bit(i * BITS_PER_LONG + j,
 				     node->status_reporting))
 				continue;
-			aest_proc_record(&node->records[j], &count);
+			aest_proc_record(&node->records[j], &count, false);
 		}
 	}
 
@@ -595,7 +602,8 @@ static int aest_init_record(struct aest_record *record, int i,
 	return 0;
 }
 
-static void aest_online_record(struct aest_record *record, void *data)
+static void aest_online_record(struct aest_record *record, void *data,
+			       bool __unused)
 {
 	if (record_read(record, ERXFR) & ERR_FR_CE)
 		aest_set_ce_threshold(record);
diff --git a/drivers/ras/aest/aest-inject.c b/drivers/ras/aest/aest-inject.c
new file mode 100644
index 000000000000..fe6ccac8338e
--- /dev/null
+++ b/drivers/ras/aest/aest-inject.c
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ARM Error Source Table Support
+ *
+ * Copyright (c) 2024, Alibaba Group.
+ */
+
+#include "aest.h"
+
+static struct ras_ext_regs regs_inj;
+
+struct inj_attr {
+	struct attribute attr;
+	ssize_t (*show)(struct aest_node *n, struct inj_attr *a, char *b);
+	ssize_t (*store)(struct aest_node *n, struct inj_attr *a, const char *b,
+				size_t c);
+};
+
+struct aest_inject {
+	struct aest_node *node;
+	struct kobject kobj;
+};
+
+#define to_inj(k)	container_of(k, struct aest_inject, kobj)
+#define to_inj_attr(a)	container_of(a, struct inj_attr, attr)
+
+static u64 aest_sysreg_read_inject(void *__unused, u32 offset)
+{
+	u64 *p = (u64 *)&regs_inj;
+
+	return p[offset/8];
+}
+
+static void aest_sysreg_write_inject(void *base, u32 offset, u64 val)
+{
+	u64 *p = (u64 *)&regs_inj;
+
+	p[offset/8] = val;
+}
+
+static u64 aest_iomem_read_inject(void *base, u32 offset)
+{
+	u64 *p = (u64 *)&regs_inj;
+
+	return p[offset/8];
+}
+
+static void aest_iomem_write_inject(void *base, u32 offset, u64 val)
+{
+	u64 *p = (u64 *)&regs_inj;
+
+	p[offset/8] = val;
+}
+
+static struct aest_access aest_access_inject[] = {
+	[ACPI_AEST_NODE_SYSTEM_REGISTER] = {
+		.read = aest_sysreg_read_inject,
+		.write = aest_sysreg_write_inject,
+	},
+
+	[ACPI_AEST_NODE_MEMORY_MAPPED] = {
+		.read = aest_iomem_read_inject,
+		.write = aest_iomem_write_inject,
+	},
+	[ACPI_AEST_NODE_SINGLE_RECORD_MEMORY_MAPPED] = {
+		.read = aest_iomem_read_inject,
+		.write = aest_iomem_write_inject,
+	},
+	{ }
+};
+
+static int soft_inject_store(void *data, u64 val)
+{
+	int count = 0;
+	struct aest_record record_inj, *record = data;
+	struct aest_node node_inj, *node = record->node;
+
+	memcpy(&node_inj, node, sizeof(*node));
+	node_inj.name = "AEST-injection";
+
+	record_inj.access = &aest_access_inject[node->info->interface_hdr->type];
+	record_inj.node = &node_inj;
+	record_inj.index = record->index;
+
+	regs_inj.err_status |= ERR_STATUS_V;
+
+	aest_proc_record(&record_inj, &count, true);
+
+	if (count != 1)
+		return -EIO;
+
+	return 0;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(soft_inject_ops, NULL, soft_inject_store, "%llu\n");
+
+static int hard_inject_store(void *data, u64 val)
+{
+	struct aest_record *record = data;
+	struct aest_node *node = record->node;
+
+	if (!node->inj)
+		return -EPERM;
+
+	aest_select_record(node, record->index);
+	record_write(record, ERXPFGCTL, val);
+	record_write(record, ERXPFGCDN, 0x100);
+	aest_sync(node);
+
+	return 0;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(hard_inject_ops, NULL, hard_inject_store, "%llu\n");
+
+void aest_inject_init_debugfs(struct aest_record *record)
+{
+	struct dentry *inj;
+
+	inj = debugfs_create_dir("inject", record->debugfs);
+
+	debugfs_create_u64("err_fr", 0600, inj, &regs_inj.err_fr);
+	debugfs_create_u64("err_ctrl", 0600, inj, &regs_inj.err_ctlr);
+	debugfs_create_u64("err_status", 0600, inj, &regs_inj.err_status);
+	debugfs_create_u64("err_addr", 0600, inj, &regs_inj.err_addr);
+	debugfs_create_u64("err_misc0", 0600, inj, &regs_inj.err_misc[0]);
+	debugfs_create_u64("err_misc1", 0600, inj, &regs_inj.err_misc[1]);
+	debugfs_create_u64("err_misc2", 0600, inj, &regs_inj.err_misc[2]);
+	debugfs_create_u64("err_misc3", 0600, inj, &regs_inj.err_misc[3]);
+	debugfs_create_file("soft_inject", 0400, inj, record, &soft_inject_ops);
+
+	if (record->node->inj)
+		debugfs_create_file("hard_inject", 0400, inj, record, &hard_inject_ops);
+}
diff --git a/drivers/ras/aest/aest-sysfs.c b/drivers/ras/aest/aest-sysfs.c
index 392e7ad8328e..66e9c1103f99 100644
--- a/drivers/ras/aest/aest-sysfs.c
+++ b/drivers/ras/aest/aest-sysfs.c
@@ -158,6 +158,7 @@ static void aest_record_init_debugfs(struct aest_record *record)
 						&aest_record_err_count_fops);
 	debugfs_create_file("ce_threshold", 0600, record->debugfs, record,
 						&record_ce_threshold_ops);
+	aest_inject_init_debugfs(record);
 }
 
 static void
@@ -190,8 +191,8 @@ aest_oncore_dev_init_debugfs(struct aest_device *adev)
 	for_each_possible_cpu(cpu) {
 		percpu_dev = this_cpu_ptr(adev->adev_oncore);
 
-		snprintf(name, sizeof(name), "processor%u", cpu);
-		percpu_dev->debugfs = debugfs_create_dir(name, aest_debugfs);
+		snprintf(name, sizeof(name), "processor%u%u", cpu);
+		percpu_dev->debugfs = debugfs_create_dir(name, adev->debugfs);
 
 		for (i = 0; i < adev->node_cnt; i++) {
 			node = &adev->nodes[i];
@@ -208,6 +209,9 @@ void aest_dev_init_debugfs(struct aest_device *adev)
 	int i;
 	struct aest_node *node;
 
+	if (!aest_debugfs)
+		dev_err(adev->dev, "debugfs not enabled\n");
+
 	adev->debugfs = debugfs_create_dir(dev_name(adev->dev), aest_debugfs);
 	if (aest_dev_is_oncore(adev)) {
 		aest_oncore_dev_init_debugfs(adev);
diff --git a/drivers/ras/aest/aest.h b/drivers/ras/aest/aest.h
index 802430857dc4..2f6a7b9ca4ef 100644
--- a/drivers/ras/aest/aest.h
+++ b/drivers/ras/aest/aest.h
@@ -362,3 +362,5 @@ static inline bool aest_dev_is_oncore(struct aest_device *adev)
 }
 
 void aest_dev_init_debugfs(struct aest_device *adev);
+void aest_inject_init_debugfs(struct aest_record *record);
+void aest_proc_record(struct aest_record *record, void *data, bool fake);
-- 
2.47.3



From tianruidong at linux.alibaba.com  Tue Dec 30 01:13:22 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Tue, 30 Dec 2025 17:13:22 +0800
Subject: [PATCH v5 14/17] ras: ATL: Unify ATL interface for ARM64 and AMD
In-Reply-To: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
References: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
Message-ID: <20251230091322.50015-1-tianruidong@linux.alibaba.com>

Certain components report errors using their internal physical
addresses. For instance, on AMD platforms, the UMC reports
normalized addresses, while on Arm systems, memory controllers
may report logical addresses. These addresses must be translated
into System Physical Addresses (SPA) before the OS can utilize
them effectively.

AMD already provides the amd_atl_umc_na_to_spa interface for
physical address translation. This patch introduces a common
function, atl_ras_la_to_spa, intended for use by both AMD and
Arm64 architectures. The parameters of this function are
architecture-specific data required for the address translation
process.

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 drivers/edac/amd64_edac.c      |  2 +-
 drivers/ras/aest/aest-core.c   |  3 +++
 drivers/ras/amd/atl/core.c     |  4 ++--
 drivers/ras/amd/atl/internal.h |  2 +-
 drivers/ras/amd/atl/umc.c      |  5 +++--
 drivers/ras/amd/fmpm.c         |  2 +-
 drivers/ras/ras.c              | 24 +++++++++++-------------
 include/linux/ras.h            |  9 ++++-----
 8 files changed, 26 insertions(+), 25 deletions(-)

diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 2391f3469961..478cfef37892 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -2847,7 +2847,7 @@ static void decode_umc_error(int node_id, struct mce *m)
 	a_err.ipid = m->ipid;
 	a_err.cpu  = m->extcpu;
 
-	sys_addr = amd_convert_umc_mca_addr_to_sys_addr(&a_err);
+	sys_addr = convert_ras_la_to_spa(&a_err);
 	if (IS_ERR_VALUE(sys_addr)) {
 		err.err_code = ERR_NORM_ADDR;
 		goto log_error;
diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index a290b482bf8b..052211ca3e2a 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -235,6 +235,9 @@ static void aest_node_pool_process(struct work_struct *work)
 		    (status & (ERR_STATUS_UE | ERR_STATUS_DE))) {
 			if (event->addressing_mode == AEST_ADDREESS_SPA)
 				addr = event->regs.err_addr & PHYS_MASK;
+			else
+				addr = convert_ras_la_to_spa(event);
+
 			aest_handle_memory_failure(addr);
 		}
 
diff --git a/drivers/ras/amd/atl/core.c b/drivers/ras/amd/atl/core.c
index 0f7cd6dab0b0..4f44c0ce97ec 100644
--- a/drivers/ras/amd/atl/core.c
+++ b/drivers/ras/amd/atl/core.c
@@ -210,7 +210,7 @@ static int __init amd_atl_init(void)
 
 	/* Increment this module's recount so that it can't be easily unloaded. */
 	__module_get(THIS_MODULE);
-	amd_atl_register_decoder(convert_umc_mca_addr_to_sys_addr);
+	atl_register_decoder(convert_umc_mca_addr_to_sys_addr);
 
 	pr_info("AMD Address Translation Library initialized\n");
 	return 0;
@@ -222,7 +222,7 @@ static int __init amd_atl_init(void)
  */
 static void __exit amd_atl_exit(void)
 {
-	amd_atl_unregister_decoder();
+	atl_unregister_decoder();
 }
 
 module_init(amd_atl_init);
diff --git a/drivers/ras/amd/atl/internal.h b/drivers/ras/amd/atl/internal.h
index 82a56d9c2be1..423a6193fdc7 100644
--- a/drivers/ras/amd/atl/internal.h
+++ b/drivers/ras/amd/atl/internal.h
@@ -279,7 +279,7 @@ int denormalize_address(struct addr_ctx *ctx);
 int dehash_address(struct addr_ctx *ctx);
 
 unsigned long norm_to_sys_addr(u8 socket_id, u8 die_id, u8 coh_st_inst_id, unsigned long addr);
-unsigned long convert_umc_mca_addr_to_sys_addr(struct atl_err *err);
+unsigned long convert_umc_mca_addr_to_sys_addr(void *data);
 
 u64 add_base_and_hole(struct addr_ctx *ctx, u64 addr);
 u64 remove_base_and_hole(struct addr_ctx *ctx, u64 addr);
diff --git a/drivers/ras/amd/atl/umc.c b/drivers/ras/amd/atl/umc.c
index befc616d5e8a..a688550604bd 100644
--- a/drivers/ras/amd/atl/umc.c
+++ b/drivers/ras/amd/atl/umc.c
@@ -318,7 +318,7 @@ static void _retire_row_mi300(struct atl_err *a_err)
 		a_err->addr &= ~MI300_UMC_MCA_COL;
 		a_err->addr |= FIELD_PREP(MI300_UMC_MCA_COL, col);
 
-		addr = amd_convert_umc_mca_addr_to_sys_addr(a_err);
+		addr = convert_ras_la_to_spa(a_err);
 		if (IS_ERR_VALUE(addr))
 			continue;
 
@@ -399,8 +399,9 @@ static u8 get_coh_st_inst_id(struct atl_err *err)
 	return FIELD_GET(UMC_CHANNEL_NUM, err->ipid);
 }
 
-unsigned long convert_umc_mca_addr_to_sys_addr(struct atl_err *err)
+unsigned long convert_umc_mca_addr_to_sys_addr(void *data)
 {
+	struct atl_err *err = data;
 	u8 socket_id = topology_physical_package_id(err->cpu);
 	u8 coh_st_inst_id = get_coh_st_inst_id(err);
 	unsigned long addr = get_addr(err->addr);
diff --git a/drivers/ras/amd/fmpm.c b/drivers/ras/amd/fmpm.c
index 8877c6ff64c4..d9fdd367644f 100644
--- a/drivers/ras/amd/fmpm.c
+++ b/drivers/ras/amd/fmpm.c
@@ -333,7 +333,7 @@ static void save_spa(struct fru_rec *rec, unsigned int entry,
 	a_err.ipid = id;
 	a_err.cpu  = cpu;
 
-	spa = amd_convert_umc_mca_addr_to_sys_addr(&a_err);
+	spa = convert_ras_la_to_spa(&a_err);
 	if (IS_ERR_VALUE(spa)) {
 		pr_debug("Failed to get system address\n");
 		return;
diff --git a/drivers/ras/ras.c b/drivers/ras/ras.c
index 2a5b5a9fdcb3..050b49466a18 100644
--- a/drivers/ras/ras.c
+++ b/drivers/ras/ras.c
@@ -10,36 +10,34 @@
 #include <linux/ras.h>
 #include <linux/uuid.h>
 
-#if IS_ENABLED(CONFIG_AMD_ATL)
 /*
  * Once set, this function pointer should never be unset.
  *
  * The library module will set this pointer if it successfully loads. The module
  * should not be unloaded except for testing and debug purposes.
  */
-static unsigned long (*amd_atl_umc_na_to_spa)(struct atl_err *err);
+static unsigned long (*atl_ras_la_to_spa)(void *err);
 
-void amd_atl_register_decoder(unsigned long (*f)(struct atl_err *))
+void atl_register_decoder(unsigned long (*f)(void *))
 {
-	amd_atl_umc_na_to_spa = f;
+	atl_ras_la_to_spa = f;
 }
-EXPORT_SYMBOL_GPL(amd_atl_register_decoder);
+EXPORT_SYMBOL_GPL(atl_register_decoder);
 
-void amd_atl_unregister_decoder(void)
+void atl_unregister_decoder(void)
 {
-	amd_atl_umc_na_to_spa = NULL;
+	atl_ras_la_to_spa = NULL;
 }
-EXPORT_SYMBOL_GPL(amd_atl_unregister_decoder);
+EXPORT_SYMBOL_GPL(atl_unregister_decoder);
 
-unsigned long amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err)
+unsigned long convert_ras_la_to_spa(void *err)
 {
-	if (!amd_atl_umc_na_to_spa)
+	if (!atl_ras_la_to_spa)
 		return -EINVAL;
 
-	return amd_atl_umc_na_to_spa(err);
+	return atl_ras_la_to_spa(err);
 }
-EXPORT_SYMBOL_GPL(amd_convert_umc_mca_addr_to_sys_addr);
-#endif /* CONFIG_AMD_ATL */
+EXPORT_SYMBOL_GPL(convert_ras_la_to_spa);
 
 #define CREATE_TRACE_POINTS
 #define TRACE_INCLUDE_PATH ../../include/ras
diff --git a/include/linux/ras.h b/include/linux/ras.h
index 05096f049dac..2270a8eb1038 100644
--- a/include/linux/ras.h
+++ b/include/linux/ras.h
@@ -42,14 +42,9 @@ struct atl_err {
 };
 
 #if IS_ENABLED(CONFIG_AMD_ATL)
-void amd_atl_register_decoder(unsigned long (*f)(struct atl_err *));
-void amd_atl_unregister_decoder(void);
 void amd_retire_dram_row(struct atl_err *err);
-unsigned long amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err);
 #else
 static inline void amd_retire_dram_row(struct atl_err *err) { }
-static inline unsigned long
-amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err) { return -EINVAL; }
 #endif /* CONFIG_AMD_ATL */
 
 #if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
@@ -63,6 +58,10 @@ amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err) { return -EINVAL; }
 #define GET_LOGICAL_INDEX(mpidr) -EINVAL
 #endif /* CONFIG_ARM || CONFIG_ARM64 */
 
+void atl_register_decoder(unsigned long (*f)(void *));
+void atl_unregister_decoder(void);
+unsigned long convert_ras_la_to_spa(void *err);
+
 #if IS_ENABLED(CONFIG_AEST)
 void aest_register_decode_chain(struct notifier_block *nb);
 void aest_unregister_decode_chain(struct notifier_block *nb);
-- 
2.47.3



From tianruidong at linux.alibaba.com  Tue Dec 30 01:13:32 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Tue, 30 Dec 2025 17:13:32 +0800
Subject: [PATCH v5 15/17] ras: AEST: Add framework to process AEST vendor node
In-Reply-To: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
References: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
Message-ID: <20251230091332.50209-1-tianruidong@linux.alibaba.com>

AEST table include vendor error node to support the component that do
not implement standard Arm RAS architecture[1]. Each vendor node may
have their own initialize and interrupt handle function. This patch
supply a framework to process vendor error nodes, the vendor process
function is binded with vendor HID.

[1]: https://developer.arm.com/documentation/ddi0587/latest/

Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 drivers/ras/aest/aest-core.c | 28 +++++++++++++++++++++++++++-
 drivers/ras/aest/aest.h      |  5 +++++
 2 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index 052211ca3e2a..4d20e54832fd 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -925,6 +925,29 @@ static int aest_setup_irq(struct platform_device *pdev,
 	return 0;
 }
 
+static struct aest_vendor_match vendor_match[] = {
+	{  },
+};
+
+static int
+aest_vendor_probe(struct aest_device *adev, struct aest_hnode *ahnode)
+{
+	int i;
+	struct acpi_aest_node *anode;
+
+	anode = list_first_entry(&ahnode->list, struct acpi_aest_node, list);
+	if (!anode)
+		return -ENODEV;
+
+	aest_dev_dbg(adev, "Try to probe vendor node %s\n", anode->vendor->acpi_hid);
+	for (i = 0; i < ARRAY_SIZE(vendor_match); i++) {
+		if (!strncmp(vendor_match[i].hid, anode->vendor->acpi_hid, 8))
+			return vendor_match[i].probe(adev, ahnode);
+	}
+
+	return -ENODEV;
+}
+
 static int aest_device_probe(struct platform_device *pdev)
 {
 	int ret;
@@ -950,7 +973,10 @@ static int aest_device_probe(struct platform_device *pdev)
 	}
 	init_llist_head(&adev->event_list);
 
-	ret = aest_init_nodes(adev, ahnode);
+	if (ahnode->type == ACPI_AEST_VENDOR_ERROR_NODE)
+		ret = aest_vendor_probe(adev, ahnode);
+	else
+		ret = aest_init_nodes(adev, ahnode);
 	if (ret)
 		return ret;
 
diff --git a/drivers/ras/aest/aest.h b/drivers/ras/aest/aest.h
index 2f6a7b9ca4ef..304c03839d31 100644
--- a/drivers/ras/aest/aest.h
+++ b/drivers/ras/aest/aest.h
@@ -244,6 +244,11 @@ static const char *const aest_node_name[] = {
 	[ACPI_AEST_PROXY_ERROR_NODE] = "proxy",
 };
 
+struct aest_vendor_match {
+	char hid[ACPI_ID_LEN];
+	int (*probe)(struct aest_device *adev, struct aest_hnode *anode);
+};
+
 static inline int aest_set_name(struct aest_device *adev,
 				struct aest_hnode *ahnode)
 {
-- 
2.47.3



From tianruidong at linux.alibaba.com  Tue Dec 30 01:13:42 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Tue, 30 Dec 2025 17:13:42 +0800
Subject: [PATCH v5 16/17] ras: AEST: support vendor node CMN700
In-Reply-To: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
References: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
Message-ID: <20251230091342.50404-1-tianruidong@linux.alibaba.com>

The CMN (Coherent Mesh Network) architecture incorporates five distinct
device types. Each device type is associated with an error group register
set. The struct aest_cmn_700 models a single CMN instance, while struct
aest_cmn_700_child represents an individual CMN device.

CMN's error records utilize a memory-mapped single error record view [1].
Critically, one error record corresponds to one AEST node, implying that
a single CMN instance can generate hundreds of AEST nodes. To manage this
scale, this driver introduces a virtual AEST node, which represents an
entire CMN device, such as an HNI or HNF. This allows an HNF AEST node,
for instance, to leverage its errgsr register to pinpoint which specific
error record has reported an error.

During the AEST probe phase, the CMN AEST driver identifies the CMN node
type using the cmn_node_info register. It then reorganizes all AEST nodes
belonging to the same CMN node type into a cohesive CMN AEST node
structure. To locate the relevant CMN register addresses, the CMN's
presence in the DSDT is required, along with the CMN node offset
specified in the AEST vendor specification data [1].

[1]: https://developer.arm.com/documentation/102308/latest/

Link: https://lore.kernel.org/r/20251222094351.38792-18-tianruidong at linux.alibaba.com
Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 arch/arm64/include/asm/arm-cmn.h |  47 +++++
 drivers/perf/arm-cmn.c           |  37 +---
 drivers/ras/aest/Makefile        |   1 +
 drivers/ras/aest/aest-cmn.c      | 332 +++++++++++++++++++++++++++++++
 drivers/ras/aest/aest-core.c     |  42 ++--
 drivers/ras/aest/aest.h          |  39 ++++
 6 files changed, 446 insertions(+), 52 deletions(-)
 create mode 100644 arch/arm64/include/asm/arm-cmn.h
 create mode 100644 drivers/ras/aest/aest-cmn.c

diff --git a/arch/arm64/include/asm/arm-cmn.h b/arch/arm64/include/asm/arm-cmn.h
new file mode 100644
index 000000000000..1b9f50679794
--- /dev/null
+++ b/arch/arm64/include/asm/arm-cmn.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2015 ARM Ltd.
+ */
+#ifndef __ASM_ARM_CMN_H
+#define __ASM_ARM_CMN_H
+
+#include <asm/sysreg.h>
+
+/* Common register stuff */
+#define CMN_NODE_INFO			0x0000
+#define CMN_NI_NODE_TYPE		GENMASK_ULL(15, 0)
+#define CMN_NI_NODE_ID			GENMASK_ULL(31, 16)
+#define CMN_NI_LOGICAL_ID		GENMASK_ULL(47, 32)
+
+enum cmn_node_type {
+	CMN_TYPE_INVALID,
+	CMN_TYPE_DVM,
+	CMN_TYPE_CFG,
+	CMN_TYPE_DTC,
+	CMN_TYPE_HNI,
+	CMN_TYPE_HNF,
+	CMN_TYPE_XP,
+	CMN_TYPE_SBSX,
+	CMN_TYPE_MPAM_S,
+	CMN_TYPE_MPAM_NS,
+	CMN_TYPE_RNI,
+	CMN_TYPE_RND = 0xd,
+	CMN_TYPE_RNSAM = 0xf,
+	CMN_TYPE_MTSX,
+	CMN_TYPE_HNP,
+	CMN_TYPE_CXRA = 0x100,
+	CMN_TYPE_CXHA,
+	CMN_TYPE_CXLA,
+	CMN_TYPE_CCRA,
+	CMN_TYPE_CCHA,
+	CMN_TYPE_CCLA,
+	CMN_TYPE_CCLA_RNI,
+	CMN_TYPE_HNS = 0x200,
+	CMN_TYPE_HNS_MPAM_S,
+	CMN_TYPE_HNS_MPAM_NS,
+	CMN_TYPE_APB = 0x1000,
+	/* Not a real node type */
+	CMN_TYPE_WP = 0x7770
+};
+
+#endif /* __ASM_ARM_CMN_H */
diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c
index 23245352a3fc..989482096dfb 100644
--- a/drivers/perf/arm-cmn.c
+++ b/drivers/perf/arm-cmn.c
@@ -2,6 +2,7 @@
 // Copyright (C) 2016-2020 Arm Limited
 // ARM CMN/CI interconnect PMU driver
 
+#include <asm/arm-cmn.h>
 #include <linux/acpi.h>
 #include <linux/bitfield.h>
 #include <linux/bitops.h>
@@ -19,11 +20,6 @@
 #include <linux/sort.h>
 
 /* Common register stuff */
-#define CMN_NODE_INFO			0x0000
-#define CMN_NI_NODE_TYPE		GENMASK_ULL(15, 0)
-#define CMN_NI_NODE_ID			GENMASK_ULL(31, 16)
-#define CMN_NI_LOGICAL_ID		GENMASK_ULL(47, 32)
-
 #define CMN_CHILD_INFO			0x0080
 #define CMN_CI_CHILD_COUNT		GENMASK_ULL(15, 0)
 #define CMN_CI_CHILD_PTR_OFFSET		GENMASK_ULL(31, 16)
@@ -241,37 +237,6 @@ enum cmn_revision {
 	REV_CI700_R2P0,
 };
 
-enum cmn_node_type {
-	CMN_TYPE_INVALID,
-	CMN_TYPE_DVM,
-	CMN_TYPE_CFG,
-	CMN_TYPE_DTC,
-	CMN_TYPE_HNI,
-	CMN_TYPE_HNF,
-	CMN_TYPE_XP,
-	CMN_TYPE_SBSX,
-	CMN_TYPE_MPAM_S,
-	CMN_TYPE_MPAM_NS,
-	CMN_TYPE_RNI,
-	CMN_TYPE_RND = 0xd,
-	CMN_TYPE_RNSAM = 0xf,
-	CMN_TYPE_MTSX,
-	CMN_TYPE_HNP,
-	CMN_TYPE_CXRA = 0x100,
-	CMN_TYPE_CXHA,
-	CMN_TYPE_CXLA,
-	CMN_TYPE_CCRA,
-	CMN_TYPE_CCHA,
-	CMN_TYPE_CCLA,
-	CMN_TYPE_CCLA_RNI,
-	CMN_TYPE_HNS = 0x200,
-	CMN_TYPE_HNS_MPAM_S,
-	CMN_TYPE_HNS_MPAM_NS,
-	CMN_TYPE_APB = 0x1000,
-	/* Not a real node type */
-	CMN_TYPE_WP = 0x7770
-};
-
 enum cmn_filter_select {
 	SEL_NONE = -1,
 	SEL_OCCUP1ID,
diff --git a/drivers/ras/aest/Makefile b/drivers/ras/aest/Makefile
index 5ee10fc8b2e9..e5a45fde6d36 100644
--- a/drivers/ras/aest/Makefile
+++ b/drivers/ras/aest/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_AEST) 	+= aest.o
 aest-y		:= aest-core.o
 aest-y		+= aest-sysfs.o
 aest-y		+= aest-inject.o
+aest-y		+= aest-cmn.o
diff --git a/drivers/ras/aest/aest-cmn.c b/drivers/ras/aest/aest-cmn.c
new file mode 100644
index 000000000000..456203377c79
--- /dev/null
+++ b/drivers/ras/aest/aest-cmn.c
@@ -0,0 +1,332 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ARM Error Source Table CMN700 Support
+ *
+ * Copyright (c) 2025, Alibaba Inc
+ */
+
+#include "linux/bitfield.h"
+#include "linux/io.h"
+#include <asm/arm-cmn.h>
+
+#include "aest.h"
+
+/*
+ * CMN include 5 device types, each device type has an error group register set
+ * which contains a set of error records. The struct aest_cmn_700 represents
+ * one CMN Instance, and the struct aest_cmn_700_child represent one CMN device.
+ * The error record of CMN use memory-mapped single error record view, so one
+ * record is correspond to one AEST node, it means there will be hundreds of
+ * AEST node of CMN. As described in chapters 2.6.3.4 of Arm ACPI Spec[1], we
+ * use vendor define data to recognize the device type of an AEST node. So AEST
+ * driver can enumerate all CMN AEST node to initialize struct aest_cmn_700 and
+ * aest_cmn_700_child with HID, UID and other CMN info described in AEST or CMN
+ * register.
+ *
+ * Each CMN Instance has their own error interrupt and the struct aest_cmn_700
+ * is passed to interrupt context. OS check error group register set to locate
+ * record which report error. All procedure is similar with chapters 3.8 in
+ * Arm CMN Spec[2].
+ *
+ * The CMN RAS architecture is showed as follow:
+ *
+ *                     +----+
+ *                  -->|XP  |     ......
+ *                  |  +----+
+ *                  |
+ *                  |  +----+     ......
+ *                  |  |HNI |     +----------------+
+ *                  |  +----+   ->|record/AEST node|
+ *                  |           | +----------------+
+ *  +------------+  |  +----+   |    .
+ *  |CMN Instance|--|  |HNF |---|    .
+ *  +------------+  |  +----+   |    .
+ *                  |           | +----------------+
+ *                  |  +----+   ->|record/AEST node|
+ *                  |  |SBSX|     +----------------+
+ *                  |  +----+     ......
+ *                  |
+ *                  |  +----+
+ *                  -->|CCG |     ......
+ *                     +----+
+ *
+ * [1]: https://developer.arm.com/documentation/den0093/latest
+ * [2]: https://developer.arm.com/documentation/102308/latest
+ */
+
+#define CMN_RAS_DEV_NUM 6
+#define CMN700_ERRGSR_NUM 8
+#define CMN_MAX_UID 8
+#define CMN_ERRDEVARCH 0x3FB8
+#define CMN_ERRDEVARCH_REV GENMASK(19, 16)
+#define CMN_ERRGSR_OFFSET 0x3000
+
+struct cmn_vendor_data {
+	int node_type;
+	int node_id;
+	int logic_id;
+};
+
+struct cmn_config {
+	int errgsr_num;
+	int dev_num;
+	int ras_ver;
+	const int *node_id_map;
+	const char *const *node_name;
+	int (*errgsr_mapping)(int errgsr_bit);
+	u64 (*errgsr_offset)(u64 hnd_ofset, int node_idx);
+};
+
+static const char *const cmn700_node_name[] = {
+	[CMN_TYPE_HNI] = "HNI",	 [CMN_TYPE_HNF] = "HNF",
+	[CMN_TYPE_XP] = "XP",	 [CMN_TYPE_SBSX] = "SBSX",
+	[CMN_TYPE_CXRA] = "RND", [CMN_TYPE_MTSX] = "MTSX",
+};
+
+static const int cmn700_node_id_map[] = {
+	[CMN_TYPE_HNI] = 1,  [CMN_TYPE_HNF] = 2,  [CMN_TYPE_XP] = 0,
+	[CMN_TYPE_SBSX] = 3, [CMN_TYPE_CXRA] = 4, [CMN_TYPE_MTSX] = 5,
+};
+
+static u64 cmn_dev_array[CMN_MAX_UID];
+static struct cmn_config *cmn_config;
+
+static u64 cmn700_errgsr_offset(u64 hnd_offset, int node_idx)
+{
+	return hnd_offset + CMN_ERRGSR_OFFSET +
+	       (node_idx * 2) * CMN700_ERRGSR_NUM * 8;
+}
+
+static struct cmn_config cmn700_config = {
+	.errgsr_num = CMN700_ERRGSR_NUM,
+	.dev_num = CMN_RAS_DEV_NUM,
+	.ras_ver = 1,
+	.node_name = cmn700_node_name,
+	.node_id_map = cmn700_node_id_map,
+	.errgsr_mapping = cmn700_errgsr_mapping,
+	.errgsr_offset = cmn700_errgsr_offset,
+};
+
+static acpi_status aest_cmn_700_resource_ioremap(struct acpi_resource *res,
+						 void *data)
+{
+	struct acpi_resource_address64 addr64;
+	u32 *uid = data;
+	acpi_status status;
+
+	status = acpi_resource_to_address64(res, &addr64);
+	if (ACPI_FAILURE(status) || (addr64.resource_type != ACPI_MEMORY_RANGE))
+		return AE_OK;
+
+	cmn_dev_array[*uid] = (u64)ioremap(addr64.address.minimum,
+					   addr64.address.address_length);
+
+	pr_debug("CMN device resource [%llx-%llx] ioremap to %llx\n",
+		 addr64.address.minimum, addr64.address.maximum,
+		 cmn_dev_array[*uid]);
+
+	return AE_CTRL_TERMINATE;
+}
+
+static acpi_status aest_cmn_get_dev_by_uid(acpi_handle handle, u32 level,
+					   void *data, void **return_value)
+{
+	u32 *match_uid = data;
+	acpi_status status;
+	unsigned long long uid;
+
+	status = acpi_evaluate_integer(handle, METHOD_NAME__UID, NULL, &uid);
+	if (ACPI_FAILURE(status)) {
+		pr_err("Do not find devive\n");
+		return_ACPI_STATUS(status);
+	}
+
+	if (uid != *match_uid)
+		return AE_OK;
+
+	pr_debug("CMN device instance %llx, walk through resource\n", uid);
+
+	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
+				     aest_cmn_700_resource_ioremap, data);
+
+	if (ACPI_FAILURE(status)) {
+		pr_err("Device do not have resource\n");
+		return_ACPI_STATUS(status);
+	}
+
+	return AE_CTRL_TERMINATE;
+}
+
+static inline int aest_cmn_node_ver(void *base)
+{
+	return FIELD_GET(CMN_ERRDEVARCH_REV,
+			 readl_relaxed(base + CMN_ERRDEVARCH));
+}
+
+static int aest_cmn_init_node(struct aest_device *adev,
+			      struct aest_node *cmn_node,
+			      struct acpi_aest_node *anode, u64 type,
+			      u64 errgsr_addr)
+{
+	cmn_node->info = anode;
+	cmn_node->name = devm_kasprintf(adev->dev, GFP_KERNEL, "%s",
+					cmn_config->node_name[type]);
+	if (!cmn_node->name)
+		return -ENOMEM;
+	cmn_node->errgsr = (void *)errgsr_addr;
+	cmn_node->type = anode->type;
+	cmn_node->adev = adev;
+	cmn_node->version = cmn_config->ras_ver;
+	cmn_node->errgsr_num = cmn_config->errgsr_num;
+	cmn_node->errgsr_mapping = cmn_config->errgsr_mapping;
+	cmn_node->record_count = cmn_node->errgsr_num * BITS_PER_LONG / 2;
+	cmn_node->record_implemented = devm_bitmap_zalloc(
+		adev->dev, cmn_node->record_count, GFP_KERNEL);
+	if (!cmn_node->record_implemented)
+		return -ENOMEM;
+	bitmap_set(cmn_node->record_implemented, 0, cmn_node->record_count);
+
+	cmn_node->status_reporting = devm_bitmap_zalloc(
+		adev->dev, cmn_node->record_count, GFP_KERNEL);
+	if (!cmn_node->status_reporting)
+		return -ENOMEM;
+	bitmap_set(cmn_node->status_reporting, 0, cmn_node->record_count);
+
+	cmn_node->records = devm_kcalloc(adev->dev, cmn_node->record_count,
+					 sizeof(struct aest_record),
+					 GFP_KERNEL);
+	if (!cmn_node->records)
+		return -ENOMEM;
+
+	aest_node_dbg(cmn_node, "Node init with errgsr %llx\n", errgsr_addr);
+
+	return 0;
+}
+
+static int aest_cmn_reorgnize_node(struct aest_device *adev,
+				   struct acpi_aest_node *anode, u64 base)
+{
+	struct aest_node *cmn_node;
+	u64 hnd_offset, cmn_node_offset, reg, logic_id, type, node_id;
+	u64 errgsr_addr, hnd_base;
+	struct aest_record *record;
+	int ret, node_index;
+	struct cmn_vendor_data *vendor_data;
+
+	if (anode->interface_hdr->type !=
+	    ACPI_AEST_NODE_SINGLE_RECORD_MEMORY_MAPPED) {
+		aest_dev_err(adev, "CMN just use single memory mapping\n");
+		return -ENODEV;
+	}
+
+	hnd_offset = *((u64 *)anode->vendor->vendor_specific_data);
+	cmn_node_offset = *((u64 *)&anode->vendor->vendor_specific_data[8]);
+
+	reg = readq_relaxed((void *)base + cmn_node_offset + CMN_NODE_INFO);
+
+	logic_id = FIELD_GET(CMN_NI_LOGICAL_ID, reg);
+	type = FIELD_GET(CMN_NI_NODE_TYPE, reg);
+	node_id = FIELD_GET(CMN_NI_NODE_ID, reg);
+
+	hnd_base = base + hnd_offset;
+	node_index = cmn_config->node_id_map[type];
+	errgsr_addr = base + cmn_config->errgsr_offset(hnd_offset, node_index);
+
+	// node not register, create it
+	cmn_node = &adev->nodes[node_index];
+	if (!cmn_node->errgsr) {
+		ret = aest_cmn_init_node(adev, cmn_node, anode, type,
+					 errgsr_addr);
+		if (ret)
+			return -ENOMEM;
+	}
+
+	aest_dev_dbg(adev, "node type %llx, id %llx, offset %llx\n", type,
+		     logic_id, cmn_node_offset);
+
+	if (!test_bit(0, anode->record_implemented))
+		clear_bit(logic_id, cmn_node->record_implemented);
+
+	if (!test_bit(0, anode->status_reporting))
+		clear_bit(logic_id, cmn_node->status_reporting);
+
+	record = &cmn_node->records[logic_id];
+	record->name =
+		devm_kasprintf(adev->dev, GFP_KERNEL, "record%lld", logic_id);
+	if (!record->name)
+		return -ENOMEM;
+	record->regs_base = devm_ioremap(
+		adev->dev, (resource_size_t)anode->interface_hdr->address,
+		sizeof(struct ras_ext_regs));
+	if (!record->regs_base)
+		return -ENOMEM;
+	record->addressing_mode = test_bit(0, anode->addressing_mode);
+	record->node = cmn_node;
+	record->index = logic_id;
+	record->access = &aest_access[anode->interface_hdr->type];
+
+	vendor_data = devm_kzalloc(adev->dev, sizeof(struct cmn_vendor_data),
+				   GFP_KERNEL);
+	vendor_data->node_type = type;
+	vendor_data->node_id = node_id;
+	vendor_data->logic_id = logic_id;
+
+	record->vendor_data = vendor_data;
+	record->vendor_data_size = sizeof(struct cmn_vendor_data);
+
+	aest_record_dbg(record, "base %llx\n", anode->interface_hdr->address);
+
+	return 0;
+}
+
+// reorgnize cmn node
+static int aest_cmn_probe(struct aest_device *adev, struct aest_hnode *ahnode)
+{
+	acpi_status status;
+	u64 base;
+	int ret = 0;
+	struct acpi_aest_node *anode;
+	char name[9];
+
+	anode = list_first_entry(&ahnode->list, struct acpi_aest_node, list);
+	if (!anode)
+		return -ENODEV;
+
+	if (!cmn_dev_array[anode->vendor->acpi_uid]) {
+		snprintf(name, 9, "%s", anode->vendor->acpi_hid);
+		status = acpi_get_devices(name, aest_cmn_get_dev_by_uid,
+					  &anode->vendor->acpi_uid, NULL);
+		if (ACPI_FAILURE(status)) {
+			aest_dev_err(adev, "Can not find base\n");
+			return_ACPI_STATUS(status);
+		}
+	}
+	base = cmn_dev_array[anode->vendor->acpi_uid];
+	if (!base) {
+		aest_dev_err(adev, "Device base invalid\n");
+		return -ENODEV;
+	}
+
+	adev->type = anode->type;
+	adev->node_cnt = cmn_config->dev_num;
+	adev->nodes = devm_kcalloc(adev->dev, adev->node_cnt,
+				   sizeof(struct aest_node), GFP_KERNEL);
+	if (!adev->nodes)
+		return -ENOMEM;
+	aest_set_name(adev, ahnode);
+
+	list_for_each_entry(anode, &ahnode->list, list) {
+		ret = aest_cmn_reorgnize_node(adev, anode, base);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int aest_cmn700_probe(struct aest_device *adev, struct aest_hnode *ahnode)
+{
+	cmn_config = &cmn700_config;
+
+	return aest_cmn_probe(adev, ahnode);
+}
diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index 4d20e54832fd..33e1f32c5892 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -152,6 +152,8 @@ static void init_aest_event(struct aest_event *event,
 	memcpy(&event->regs, regs, sizeof(*regs));
 	event->index = record->index;
 	event->addressing_mode = record->addressing_mode;
+	event->vendor_data_size = record->vendor_data_size;
+	event->vendor_data = record->vendor_data;
 }
 
 static int aest_node_gen_pool_add(struct aest_device *adev,
@@ -344,10 +346,9 @@ void aest_proc_record(struct aest_record *record, void *data, bool fake)
 	record_write(record, ERXSTATUS, regs.err_status);
 }
 
-static void aest_node_foreach_record(void (*func)(struct aest_record *, void *,
-						  bool),
-				     struct aest_node *node, void *data,
-				     unsigned long *bitmap)
+void aest_node_foreach_record(void (*func)(struct aest_record *, void *, bool),
+			      struct aest_node *node, void *data,
+			      unsigned long *bitmap)
 {
 	int i;
 
@@ -362,7 +363,7 @@ static void aest_node_foreach_record(void (*func)(struct aest_record *, void *,
 
 static int aest_proc(struct aest_node *node)
 {
-	int count = 0, i, j, size = node->record_count;
+	int count = 0, i, j, size = node->record_count, record_idx;
 	u64 err_group = 0;
 
 	aest_node_dbg(node, "Poll bitmap %*pb\n", size,
@@ -377,19 +378,21 @@ static int aest_proc(struct aest_node *node)
 		      node->status_reporting);
 	for (i = 0; i < BITS_TO_U64(size); i++) {
 		err_group = readq_relaxed((void *)node->errgsr + i * 8);
-		aest_node_dbg(node, "errgsr[%d]: 0x%llx\n", i, err_group);
-
 		for_each_set_bit(j, (unsigned long *)&err_group,
 				 BITS_PER_LONG) {
+			record_idx =
+				node->errgsr_mapping(i * BITS_PER_LONG + j);
+			aest_node_dbg(node, "errgsr[%d]: bit %d occur error\n",
+				      i, record_idx);
 			/*
 			 * Error group base is only valid in Memory Map node,
 			 * so driver do not need to write select register and
 			 * sync.
 			 */
-			if (test_bit(i * BITS_PER_LONG + j,
-				     node->status_reporting))
+			if (test_bit(record_idx, node->status_reporting))
 				continue;
-			aest_proc_record(&node->records[j], &count, false);
+			aest_proc_record(&node->records[record_idx], &count,
+					 false);
 		}
 	}
 
@@ -401,8 +404,11 @@ static irqreturn_t aest_irq_func(int irq, void *input)
 	struct aest_device *adev = input;
 	int i;
 
-	for (i = 0; i < adev->node_cnt; i++)
+	for (i = 0; i < adev->node_cnt; i++) {
+		if (!adev->nodes[i].record_count)
+			continue;
 		aest_proc(&adev->nodes[i]);
+	}
 
 	return IRQ_HANDLED;
 }
@@ -779,6 +785,7 @@ static int aest_init_node(struct aest_device *adev, struct aest_node *node,
 	node->info = anode;
 	node->type = anode->type;
 	node->version = get_aest_node_ver(node);
+	node->errgsr_mapping = default_errgsr_mapping;
 	node->name = alloc_aest_node_name(node);
 	if (!node->name)
 		return -ENOMEM;
@@ -831,6 +838,7 @@ static int aest_init_node(struct aest_device *adev, struct aest_node *node,
 	if (!node->records)
 		return -ENOMEM;
 
+	node->errgsr_num = DIV_ROUND_UP(node->record_count, BITS_PER_LONG);
 	for (i = 0; i < node->record_count; i++) {
 		ret = aest_init_record(&node->records[i], i, node);
 		if (ret)
@@ -926,11 +934,12 @@ static int aest_setup_irq(struct platform_device *pdev,
 }
 
 static struct aest_vendor_match vendor_match[] = {
-	{  },
+	{ "ARMHC700", &aest_cmn700_probe },
+	{},
 };
 
-static int
-aest_vendor_probe(struct aest_device *adev, struct aest_hnode *ahnode)
+static int aest_vendor_probe(struct aest_device *adev,
+			     struct aest_hnode *ahnode)
 {
 	int i;
 	struct acpi_aest_node *anode;
@@ -939,13 +948,14 @@ aest_vendor_probe(struct aest_device *adev, struct aest_hnode *ahnode)
 	if (!anode)
 		return -ENODEV;
 
-	aest_dev_dbg(adev, "Try to probe vendor node %s\n", anode->vendor->acpi_hid);
+	aest_dev_dbg(adev, "Try to probe vendor node %s\n",
+		     anode->vendor->acpi_hid);
 	for (i = 0; i < ARRAY_SIZE(vendor_match); i++) {
 		if (!strncmp(vendor_match[i].hid, anode->vendor->acpi_hid, 8))
 			return vendor_match[i].probe(adev, ahnode);
 	}
 
-	return -ENODEV;
+	return 0;
 }
 
 static int aest_device_probe(struct platform_device *pdev)
diff --git a/drivers/ras/aest/aest.h b/drivers/ras/aest/aest.h
index 304c03839d31..9d67d79eb4a2 100644
--- a/drivers/ras/aest/aest.h
+++ b/drivers/ras/aest/aest.h
@@ -94,8 +94,16 @@ struct aest_event {
 	/* Vendor node	: hardware ID. */
 	char *hid;
 	u32 index;
+	u64 ce_threshold;
 	int addressing_mode;
 	struct ras_ext_regs regs;
+
+	/*
+	 * This field is used to store vendor specific data for decoding error
+	 * record by EDAC driver.
+	 */
+	void *vendor_data;
+	size_t vendor_data_size;
 };
 
 struct aest_access {
@@ -147,6 +155,9 @@ struct aest_record {
 	enum ras_ce_threshold threshold_type;
 	struct record_count count;
 	struct dentry *debugfs;
+
+	void *vendor_data;
+	size_t vendor_data_size;
 };
 
 struct aest_group {
@@ -208,6 +219,19 @@ struct aest_node {
 	 */
 	unsigned long *status_reporting;
 	int version;
+	/*
+	 * Usually bit[n] in errgsr indicates [n]th error record within this
+	 * error node report error. But some compoent may have different rules.
+	 * For example, CMN700 TRM 4.3.5.12 say:
+	 *	``` Error occurs when the index is even and Fault
+	 *	    occurs when the index is odd. ```
+	 *	Bit[n]: record[n] report ERROR.
+	 *	Bit[n + 1]: record[n] report FAULT.
+	 * errgsr_mapping function is used to map errgsr bit to record index
+	 * for various components.
+	 */
+	int (*errgsr_mapping)(int errgsr_bit);
+	int errgsr_num;
 
 	const struct aest_group *group;
 	struct aest_device *adev;
@@ -366,6 +390,21 @@ static inline bool aest_dev_is_oncore(struct aest_device *adev)
 	return adev->type == ACPI_AEST_PROCESSOR_ERROR_NODE;
 }
 
+static inline int default_errgsr_mapping(int errgsr_bit)
+{
+	return errgsr_bit;
+}
+
+static inline int cmn700_errgsr_mapping(int errgsr_bit)
+{
+	return errgsr_bit / 2;
+}
+
 void aest_dev_init_debugfs(struct aest_device *adev);
 void aest_inject_init_debugfs(struct aest_record *record);
 void aest_proc_record(struct aest_record *record, void *data, bool fake);
+void aest_node_foreach_record(void (*func)(struct aest_record *, void *, bool),
+			      struct aest_node *node, void *data,
+			      unsigned long *bitmap);
+
+int aest_cmn700_probe(struct aest_device *adev, struct aest_hnode *ahnode);
-- 
2.47.3



From tianruidong at linux.alibaba.com  Tue Dec 30 01:13:53 2025
From: tianruidong at linux.alibaba.com (Ruidong Tian)
Date: Tue, 30 Dec 2025 17:13:53 +0800
Subject: [PATCH v5 17/17] trace, ras: add ARM RAS extension trace event
In-Reply-To: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
References: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
Message-ID: <20251230091353.50626-1-tianruidong@linux.alibaba.com>

Add a trace event for hardware errors reported by the ARMv8
RAS extension registers. userspace app can monitor this
trace event and decode error information.

Link: https://lore.kernel.org/r/20251222094351.38792-19-tianruidong at linux.alibaba.com
Signed-off-by: Ruidong Tian <tianruidong at linux.alibaba.com>
---
 drivers/ras/aest/aest-core.c |  6 +++
 drivers/ras/ras.c            |  3 ++
 include/ras/ras_event.h      | 71 ++++++++++++++++++++++++++++++++++++
 3 files changed, 80 insertions(+)

diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
index 33e1f32c5892..9f06ac0b7c16 100644
--- a/drivers/ras/aest/aest-core.c
+++ b/drivers/ras/aest/aest-core.c
@@ -13,6 +13,8 @@
 #include <linux/genalloc.h>
 #include <linux/ras.h>
 
+#include <ras/ras_event.h>
+
 #include "aest.h"
 
 DEFINE_PER_CPU(struct aest_device, percpu_adev);
@@ -90,6 +92,10 @@ static void aest_print(struct aest_event *event)
 		pr_err("%s  ERR%dMISC3: 0x%llx\n", pfx_seq, index,
 		       regs->err_misc[3]);
 	}
+
+	trace_arm_ras_ext_event(event->type, event->id0, event->id1,
+				event->index, event->hid, &event->regs,
+				event->vendor_data, event->vendor_data_size);
 }
 
 static void aest_handle_memory_failure(u64 addr)
diff --git a/drivers/ras/ras.c b/drivers/ras/ras.c
index 050b49466a18..3c0ba6c02d27 100644
--- a/drivers/ras/ras.c
+++ b/drivers/ras/ras.c
@@ -109,6 +109,9 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(extlog_mem_event);
 EXPORT_TRACEPOINT_SYMBOL_GPL(mc_event);
 EXPORT_TRACEPOINT_SYMBOL_GPL(non_standard_event);
 EXPORT_TRACEPOINT_SYMBOL_GPL(arm_event);
+#ifdef CONFIG_ARM64_RAS_EXTN
+EXPORT_TRACEPOINT_SYMBOL_GPL(arm_ras_ext_event);
+#endif
 
 static int __init parse_ras_param(char *str)
 {
diff --git a/include/ras/ras_event.h b/include/ras/ras_event.h
index eaecc3c5f772..3a4a0c0e4dbe 100644
--- a/include/ras/ras_event.h
+++ b/include/ras/ras_event.h
@@ -377,6 +377,77 @@ TRACE_EVENT(aer_event,
 			"Not available")
 );
 #endif /* CONFIG_PCIEAER */
+
+/*
+ * ARM RAS Extension Events Report
+ *
+ * This event is generated when an error reported by the ARM RAS extension
+ * hardware is detected.
+ */
+
+#ifdef CONFIG_ARM64_RAS_EXTN
+#include <asm/ras.h>
+TRACE_EVENT(arm_ras_ext_event,
+
+	TP_PROTO(const u8 type,
+		 const u32 id0,
+		 const u32 id1,
+		 const u32 index,
+		 char *hid,
+		 struct ras_ext_regs *regs,
+		 const u8 *data,
+		 const u32 len),
+
+	TP_ARGS(type, id0, id1, index, hid, regs, data, len),
+
+	TP_STRUCT__entry(
+		__field(u8,  type)
+		__field(u32, id0)
+		__field(u32, id1)
+		__field(u32, index)
+		__field(char *, hid)
+		__field(u64, err_fr)
+		__field(u64, err_ctlr)
+		__field(u64, err_status)
+		__field(u64, err_addr)
+		__field(u64, err_misc0)
+		__field(u64, err_misc1)
+		__field(u64, err_misc2)
+		__field(u64, err_misc3)
+		__field(u32, len)
+		__dynamic_array(u8, buf, len)
+	),
+
+	TP_fast_assign(
+		__entry->type = type;
+		__entry->id0 = id0;
+		__entry->id1 = id1;
+		__entry->index = index;
+		__entry->hid = hid;
+		__entry->err_fr = regs->err_fr;
+		__entry->err_ctlr = regs->err_ctlr;
+		__entry->err_status = regs->err_status;
+		__entry->err_addr = regs->err_addr;
+		__entry->err_misc0 = regs->err_misc[0];
+		__entry->err_misc1 = regs->err_misc[1];
+		__entry->err_misc2 = regs->err_misc[2];
+		__entry->err_misc3 = regs->err_misc[3];
+		__entry->len = len;
+		memcpy(__get_dynamic_array(buf), data, len);
+	),
+
+	TP_printk("type: %d; id0: %d; id1: %d; index: %d; hid: %s; "
+		  "ERR_FR: %llx; ERR_CTLR: %llx; ERR_STATUS: %llx; "
+		  "ERR_ADDR: %llx; ERR_MISC0: %llx; ERR_MISC1: %llx; "
+		  "ERR_MISC2: %llx; ERR_MISC3: %llx; data len:%d; raw data:%s",
+		  __entry->type, __entry->id0, __entry->id1, __entry->index,
+		  __entry->hid, __entry->err_fr, __entry->err_ctlr,
+		  __entry->err_status, __entry->err_addr, __entry->err_misc0,
+		  __entry->err_misc1, __entry->err_misc2, __entry->err_misc3,
+		  __entry->len,
+		  __print_hex(__get_dynamic_array(buf), __entry->len))
+);
+#endif /* CONFIG_ARM64_RAS_EXTN */
 #endif /* _TRACE_HW_EVENT_MC_H */
 
 /* This part must be outside protection */
-- 
2.47.3



From luca.ceresoli at bootlin.com  Tue Dec 30 01:17:13 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Tue, 30 Dec 2025 10:17:13 +0100
Subject: [PATCH v3 00/22] drm/bridge: add of_drm_find_and_get_bridge()
 and a managed *next_bridge, deprecate of_drm_find_bridge()
In-Reply-To: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
References: <20251216-drm-bridge-alloc-getput-drm_of_find_bridge-v3-0-b5165fab8058@bootlin.com>
Message-ID: <176708623356.127863.8623917477288453126.b4-ty@bootlin.com>


On Tue, 16 Dec 2025 18:58:33 +0100, Luca Ceresoli wrote:
> This series deprecates of_drm_find_bridge(), adds a replacement which
> handles bridge refcounting, and converts some of the direct users.
> 
> This is part of the work to support hotplug of DRM bridges. The grand plan
> was discussed in [0].
> 
> Here's the work breakdown (? marks the current series):
> 
> [...]

Applied, thanks!

[01/22] drm/bridge: add of_drm_find_and_get_bridge()
        commit: 293a8fd7721a90987d9bf149feab60e756dac269
[02/22] drm/bridge: deprecate of_drm_find_bridge()
        commit: 9da0e06abda87b1f97014113d5231fdeb4700749
[03/22] drm/todo: add entry about converting to of_drm_find_and_get_bridge()
        commit: c637217efb892ac5d0d5f9aea3df92147c2e24db
[04/22] drm/bridge: make of_drm_find_bridge() a wrapper of of_drm_find_and_get_bridge()
        commit: 5d7cb36254b5facd2a349331c1a47102d4e66e40
[05/22] drm/arcpgu: convert to of_drm_find_and_get_bridge()
        commit: 7282066e55347b26cb31784059ab62c2de8a3e01
[06/22] drm/bridge: add next_bridge pointer to struct drm_bridge
        commit: 3fdeae134ba956aacbd87d5532c025913c98fc49
[07/22] drm/bridge: ite-it66121: get/put the next bridge
        commit: 8f92a5fcbfe33f86b08f5f74dcc58a41425ea8c0
[08/22] drm/bridge: imx8qxp-pixel-combiner: get/put the next bridge
        commit: ae754f049ce1c01f09d175f80265970f0d5b4489
[09/22] drm/bridge: simple-bridge: get/put the next bridge
        commit: b9a7d5918bd436d64699b80af061f21c168df699
[10/22] drm/meson: encoder_cvbs: get/put the next bridge
        commit: 47fa48b3faa7cae925c9b14b18376cdc4622bae0
[11/22] drm/meson: encoder_dsi: get/put the next bridge
        commit: bfb8f5d0a9e756c57d4fc0f7966e4873bbfb34a5
[12/22] drm/meson: encoder_hdmi: get/put the next bridge
        commit: c87ad784aacb89cf88c00cde78970543010a6d67
[13/22] drm/bridge: imx8qxp-pxl2dpi: simplify put of device_node pointers
        commit: ceea3f7806a109baba4a23c9066eb9e86659408b
[14/22] drm/bridge: imx8qxp-pxl2dpi: remove excess error message
        commit: 54af17788629fbf343c5a9ebc55454d6a5486ff8
[15/22] drm/bridge: imx8qxp-pxl2dpi: imx8qxp_pxl2dpi_find_next_bridge: return int, not ERR_PTR
        commit: 0dc4a8d6d096f97a00b10919e8ffe2466666f03c
[16/22] drm/bridge: imx8qxp-pxl2dpi: get/put the next bridge
        commit: 6802c7ee360d98a018962adb8412d42dcca28272
[17/22] drm/bridge: imx8qxp-pxl2dpi: get/put the companion bridge
        commit: 900699ba830fd3558ba00f55fbf014022dc7ecdb
[18/22] drm/bridge: imx8qxp-pixel-link: simplify logic to find next bridge
        (no commit info)
[19/22] drm/bridge: imx8qxp-pixel-link: simplify freeing of the remote device_node
        (no commit info)
[20/22] drm/bridge: imx8qxp-pixel-link: remove excess error message
        commit: 40630210211a34f0714fe976530ccf1291e5ef78
[21/22] drm/bridge: imx8qxp-pixel-link: imx8qxp_pixel_link_find_next_bridge: return int, not ERR_PTR
        (no commit info)
[22/22] drm/bridge: imx8qxp-pixel-link: get/put the next bridge
        (no commit info)

Best regards,
-- 
Luca Ceresoli <luca.ceresoli at bootlin.com>



From krzk at kernel.org  Tue Dec 30 01:51:54 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 30 Dec 2025 10:51:54 +0100
Subject: [PATCH v2 2/3] dt-bindings: pinctrl: samsung: Add
 exynos9610-wakeup-eint node
In-Reply-To: <20251228-exynos9610-pinctrl-v2-2-c9bbeee4c54b@chimac.ro>
References: <20251228-exynos9610-pinctrl-v2-0-c9bbeee4c54b@chimac.ro>
 <20251228-exynos9610-pinctrl-v2-2-c9bbeee4c54b@chimac.ro>
Message-ID: <20251230-dramatic-gregarious-stallion-15bc07@quoll>

On Sun, Dec 28, 2025 at 06:05:52PM +0000, Alexandru Chimac wrote:
> Add a dedicated compatible for the exynos9610-wakeup-eint node,
> which is compatbile with Exynos850's implementation (and the
> Exynos7 fallback).
> 
> Signed-off-by: Alexandru Chimac <alex at chimac.ro>
> ---
>  .../devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml   | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml
> index f3c433015b12..deb2730855bd 100644
> --- a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml
> +++ b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml
> @@ -48,6 +48,7 @@ properties:
>            - enum:
>                - google,gs101-wakeup-eint
>                - samsung,exynos2200-wakeup-eint
> +              - samsung,exynos9610-wakeup-eint
>                - samsung,exynos9810-wakeup-eint
>                - samsung,exynos990-wakeup-eint
>                - samsung,exynosautov9-wakeup-eint
> @@ -107,6 +108,7 @@ allOf:
>            contains:
>              enum:
>                - samsung,exynos850-wakeup-eint
> +              - samsung,exynos9610-wakeup-eint

This is not needed. Device has 850 fallback, no?


Best regards,
Krzysztof



From marco.crivellari at suse.com  Tue Dec 30 01:56:13 2025
From: marco.crivellari at suse.com (Marco Crivellari)
Date: Tue, 30 Dec 2025 10:56:13 +0100
Subject: [PATCH] drm/exynos: hdmi: replace use of system_wq with system_percpu_wq
In-Reply-To: <CAAQKjZPVi1KHuS4p6G2uAeKMAg=PEbECj7DHW7OYNYLG-S9hmQ@mail.gmail.com>
References: <20251104112923.143408-1-marco.crivellari@suse.com>
 <CAAofZF4OJi5eEfjhE12RWi6wDU+A9Rghsd2721SxZR4AC08sYg@mail.gmail.com> <CAAQKjZPVi1KHuS4p6G2uAeKMAg=PEbECj7DHW7OYNYLG-S9hmQ@mail.gmail.com>
Message-ID: <CAAofZF5Fi7x0JyyNm=pSh9H=qp7qCH1xawB5Ad6+=-xzwre+Ew@mail.gmail.com>

On Tue, Dec 30, 2025 at 6:48?AM Inki Dae <daeinki at gmail.com> wrote:
>
> Hi,
>
> Sorry for late reply. Merged.

Hi,

No problem, thank you!

-- 

Marco Crivellari

L3 Support Engineer


From marco.crivellari at suse.com  Tue Dec 30 02:00:07 2025
From: marco.crivellari at suse.com (Marco Crivellari)
Date: Tue, 30 Dec 2025 11:00:07 +0100
Subject: [PATCH v2] wifi: mt76: replace use of system_wq with system_percpu_wq
In-Reply-To: <CAGp9Lzoj2jeGF+t-UP0gAykCZ96-OkjummeJRGniYfagvY-BPA@mail.gmail.com>
References: <20251114104325.116471-1-marco.crivellari@suse.com>
 <CAAofZF51pkOzrg_nO0Mhx6g9b3JPtO3n+0YE=WtSgj_F6wnY4w@mail.gmail.com> <CAGp9Lzoj2jeGF+t-UP0gAykCZ96-OkjummeJRGniYfagvY-BPA@mail.gmail.com>
Message-ID: <CAAofZF7KguhtNs_cXQdWgz8XdaChMG8G_LtEmhKfgC5_yq3iRA@mail.gmail.com>

On Tue, Dec 30, 2025 at 12:42?AM Sean Wang <sean.wang at kernel.org> wrote:
> Hi Marco,
>
> The patch has been queued in the mt76 tree. Thanks for your work on this.
> https://github.com/nbd168/wireless/commit/ee518f914cd901c16fa08a6f228b266551f72a6a
>
>             Sean

Many thanks Sean!

-- 

Marco Crivellari

L3 Support Engineer


From james.clark at linaro.org  Tue Dec 30 02:10:29 2025
From: james.clark at linaro.org (James Clark)
Date: Tue, 30 Dec 2025 10:10:29 +0000
Subject: [PATCH] perf unwind-libdw: fix a cross-arch unwinding bug
In-Reply-To: <CAK3u-5hE6zAT21bnEa7H-URAP1CsNrgnYu2fJ+t8CBO=xo3tpA@mail.gmail.com>
References: <20251223-cross-arch-unwind-v1-1-4d71ee7db512@skydio.com>
 <c25d5032-5a41-4e95-ae76-3466875241a0@linaro.org>
 <CAK3u-5hE6zAT21bnEa7H-URAP1CsNrgnYu2fJ+t8CBO=xo3tpA@mail.gmail.com>
Message-ID: <ec96d30c-56c2-484f-b64d-05bab7071c89@linaro.org>



On 25/12/2025 5:02 am, Shimin Guo wrote:
> On Wed, Dec 24, 2025 at 5:40?AM James Clark <james.clark at linaro.org> wrote:
>>
>>
>>
>> On 24/12/2025 2:19 am, Shimin Guo via B4 Relay wrote:
>>> From: Shimin Guo <shimin.guo at skydio.com>
>>>
>>> The set_initial_registers field of Dwfl_Thread_Callbacks needs to be set
>>> according to the arch of the stack samples being analyzed, not the arch
>>> that perf itself is built for. Currently perf fails to unwind stack samples
>>> collected from archs different from that of the host perf is running on.
>>> This patch moves the arch-specific implementations of set_initial_registers
>>> from tools/perf/arch to tools/perf/utli/unwind-libdw-arch, similar to the
>>> way the perf-regs-arch folder contains arch-specific functions related to
>>> registers, and chooses the implementation based on the arch of the data
>>> being processed.
>>>
>>> Signed-off-by: Shimin Guo <shimin.guo at skydio.com>
>>> ---
>>> checkpatch flagged three issues:
>>>> tools/perf/util/unwind-libdw-arch/Build:232: WARNING: added, moved
>>> or deleted file(s), does MAINTAINERS need updating?
>>>
>>> Not sure what to do about that.
>>>
>>
>> You don't need to do anything here because there's a blanket rule for
>> the Perf dir.
> 
> PERFORMANCE EVENTS TOOLING ARM64 has a rule that matches tools/perf/arch/arm*/.
> The new files for arm and arm64 will no longer be matched by the rule.
> 

Oh I see, I thought it was a generic question. In this case I still 
think the blanket rule is ok for this folder.

>>
>>>> checkpatch.pl: tools/perf/util/unwind-libdw.c:228: WARNING:
>>> Non-declarative macros with multiple statements should be enclosed in
>>> a do - while loop
>>
>> I think you can ignore this one.
>>
>>>> checkpatch.pl: tools/perf/util/unwind-libdw.c:228: WARNING: macros
>>> should not use a trailing semicolon
>>>
>>> Are these two false positives? I'm defining static global variables
>>> with the macro.
>>
>> But I don't see a reason not to follow this one, just remove the semicolon.
> 
> Maybe it doesn't matter, but after I removed the semicolon, I got a new error
> from checkpatch "Macros with complex values should be enclosed in parentheses"
> instead of the warning that suggests do - while.
> 

It explains in that warning. It's because Dwfl_Thread_Callbacks is 
typedef'd and doesn't need 'struct' so the heuristic doesn't work. That 
one can be ignored but I think the one about removing the semicolon is 
the right thing to do.

>>
>>> ---
>>>    tools/perf/arch/arm/util/Build                     |  1 -
>>>    tools/perf/arch/arm64/util/Build                   |  1 -
>>>    tools/perf/arch/csky/util/Build                    |  2 -
>>>    tools/perf/arch/powerpc/util/Build                 |  1 -
>>>    tools/perf/arch/riscv/util/Build                   |  1 -
>>>    tools/perf/arch/s390/util/Build                    |  2 -
>>>    tools/perf/arch/x86/util/Build                     |  1 -
>>>    tools/perf/util/Build                              |  1 +
>>>    tools/perf/util/unwind-libdw-arch/Build            |  8 ++++
>>>    .../unwind-libdw-arch/unwind-libdw-arm.c}          |  4 +-
>>>    .../unwind-libdw-arch/unwind-libdw-arm64.c}        |  4 +-
>>>    .../unwind-libdw-arch/unwind-libdw-csky.c}         |  6 +--
>>>    .../unwind-libdw-arch/unwind-libdw-loongarch.c}    |  4 +-
>>>    .../unwind-libdw-arch/unwind-libdw-powerpc.c}      |  4 +-
>>>    .../unwind-libdw-arch/unwind-libdw-riscv.c}        |  4 +-
>>>    .../unwind-libdw-arch/unwind-libdw-s390.c}         |  6 +--
>>>    .../unwind-libdw-arch/unwind-libdw-x86.c}          |  2 +-
>>>    tools/perf/util/unwind-libdw.c                     | 49 +++++++++++++++++++---
>>>    tools/perf/util/unwind-libdw.h                     | 10 ++++-
>>>    19 files changed, 79 insertions(+), 32 deletions(-)
>>>
>>> diff --git a/tools/perf/arch/arm/util/Build b/tools/perf/arch/arm/util/Build
>>> index fd695e1fdaee2ccc300a206131b8b38a763b00ce..3291f893b943df0722dff583523fff4ae79919bc 100644
>>> --- a/tools/perf/arch/arm/util/Build
>>> +++ b/tools/perf/arch/arm/util/Build
>>> @@ -1,6 +1,5 @@
>>>    perf-util-y += perf_regs.o
>>>
>>>    perf-util-$(CONFIG_LOCAL_LIBUNWIND)    += unwind-libunwind.o
>>> -perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
>>>
>>>    perf-util-y += pmu.o auxtrace.o cs-etm.o
>>> diff --git a/tools/perf/arch/arm64/util/Build b/tools/perf/arch/arm64/util/Build
>>> index d63881081d2eb1e9a83eabf82104d75308f7fc79..0177af19cc00038d6a6005592ddc530bf7eb1557 100644
>>> --- a/tools/perf/arch/arm64/util/Build
>>> +++ b/tools/perf/arch/arm64/util/Build
>>> @@ -1,4 +1,3 @@
>>> -perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
>>>    perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
>>>    perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
>>>    perf-util-y += ../../arm/util/auxtrace.o
>>> diff --git a/tools/perf/arch/csky/util/Build b/tools/perf/arch/csky/util/Build
>>> index 5e6ea82c42021d3d5651ca4c4a3a6e5138574e4e..6b2d0e021b11464e46d6b53974260d32ea969732 100644
>>> --- a/tools/perf/arch/csky/util/Build
>>> +++ b/tools/perf/arch/csky/util/Build
>>> @@ -1,3 +1 @@
>>>    perf-util-y += perf_regs.o
>>> -
>>> -perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
>>> diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build
>>> index 3d0d5427aef7f26a8c05c883cc7ad763f08cbb30..5fd28ec713a4db74ecd1d26866a65ddb20e94bd3 100644
>>> --- a/tools/perf/arch/powerpc/util/Build
>>> +++ b/tools/perf/arch/powerpc/util/Build
>>> @@ -9,5 +9,4 @@ perf-util-y += evsel.o
>>>    perf-util-$(CONFIG_LIBDW) += skip-callchain-idx.o
>>>
>>>    perf-util-$(CONFIG_LIBUNWIND) += unwind-libunwind.o
>>> -perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
>>>    perf-util-y += auxtrace.o
>>> diff --git a/tools/perf/arch/riscv/util/Build b/tools/perf/arch/riscv/util/Build
>>> index 58a672246024dd0f72e767d11e9958bd9913ec3c..628b9ebd418bde8cdf1ab1332bf79f7c9d50760e 100644
>>> --- a/tools/perf/arch/riscv/util/Build
>>> +++ b/tools/perf/arch/riscv/util/Build
>>> @@ -2,4 +2,3 @@ perf-util-y += perf_regs.o
>>>    perf-util-y += header.o
>>>
>>>    perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
>>> -perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
>>> diff --git a/tools/perf/arch/s390/util/Build b/tools/perf/arch/s390/util/Build
>>> index c64eb18dbdae93adafabf8542e4c9a763ecfe057..5391d26fedd46b7d30a1bef0bff2ec2d58ec30ed 100644
>>> --- a/tools/perf/arch/s390/util/Build
>>> +++ b/tools/perf/arch/s390/util/Build
>>> @@ -2,8 +2,6 @@ perf-util-y += header.o
>>>    perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
>>>    perf-util-y += perf_regs.o
>>>
>>> -perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
>>> -
>>>    perf-util-y += machine.o
>>>    perf-util-y += pmu.o
>>>
>>> diff --git a/tools/perf/arch/x86/util/Build b/tools/perf/arch/x86/util/Build
>>> index c0dc5965f3624a6f02525a04d287dff755356d20..fad256252bb95a8f8350b6bb1a54e8074eaebbec 100644
>>> --- a/tools/perf/arch/x86/util/Build
>>> +++ b/tools/perf/arch/x86/util/Build
>>> @@ -12,7 +12,6 @@ perf-util-y += evsel.o
>>>    perf-util-y += iostat.o
>>>
>>>    perf-util-$(CONFIG_LOCAL_LIBUNWIND)    += unwind-libunwind.o
>>> -perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
>>>
>>>    perf-util-y += auxtrace.o
>>>    perf-util-y += archinsn.o
>>> diff --git a/tools/perf/util/Build b/tools/perf/util/Build
>>> index 1c2a43e1dc68e7f751ec6082352b10de9ffeea62..15f8a4f4b24a46b6300e824f672dd9c0d5b7865f 100644
>>> --- a/tools/perf/util/Build
>>> +++ b/tools/perf/util/Build
>>> @@ -226,6 +226,7 @@ perf-util-$(CONFIG_LIBDW) += debuginfo.o
>>>    perf-util-$(CONFIG_LIBDW) += annotate-data.o
>>>
>>>    perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
>>> +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-arch/
>>>    perf-util-$(CONFIG_LOCAL_LIBUNWIND)    += unwind-libunwind-local.o
>>>    perf-util-$(CONFIG_LIBUNWIND)          += unwind-libunwind.o
>>>    perf-util-$(CONFIG_LIBUNWIND_X86)      += libunwind/x86_32.o
>>> diff --git a/tools/perf/util/unwind-libdw-arch/Build b/tools/perf/util/unwind-libdw-arch/Build
>>> new file mode 100644
>>> index 0000000000000000000000000000000000000000..e016d54ae2a40ecba47156c8f09cb72156105727
>>> --- /dev/null
>>> +++ b/tools/perf/util/unwind-libdw-arch/Build
>>> @@ -0,0 +1,8 @@
>>> +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-x86.o
>>> +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-arm.o
>>> +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-arm64.o
>>> +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-csky.o
>>> +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-loongarch.o
>>> +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-powerpc.o
>>> +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-riscv.o
>>> +perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-s390.o
>>> \ No newline at end of file
>>> diff --git a/tools/perf/arch/arm/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-arm.c
>>> similarity index 88%
>>> rename from tools/perf/arch/arm/util/unwind-libdw.c
>>> rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-arm.c
>>> index fbb643f224ec4b27ce9d67051fe0bc4ad555b05e..c2718d6b6cff131cd67883e24bb0d3d963c8095a 100644
>>> --- a/tools/perf/arch/arm/util/unwind-libdw.c
>>> +++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-arm.c
>>> @@ -1,11 +1,11 @@
>>>    // SPDX-License-Identifier: GPL-2.0
>>>    #include <elfutils/libdwfl.h>
>>> -#include "perf_regs.h"
>>> +#include "../../../arch/arm/include/uapi/asm/perf_regs.h"
>>>    #include "../../../util/unwind-libdw.h"
>>>    #include "../../../util/perf_regs.h"
>>>    #include "../../../util/sample.h"
>>>
>>> -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
>>> +bool libdw_set_initial_registers_arm(Dwfl_Thread *thread, void *arg)
>>>    {
>>>        struct unwind_info *ui = arg;
>>>        struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
>>> diff --git a/tools/perf/arch/arm64/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-arm64.c
>>> similarity index 92%
>>> rename from tools/perf/arch/arm64/util/unwind-libdw.c
>>> rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-arm64.c
>>> index b89b0a7e5ad919fed23643d219fbdc3d84deff1e..87602503e057badc6efd37169cc60c96cf3949ab 100644
>>> --- a/tools/perf/arch/arm64/util/unwind-libdw.c
>>> +++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-arm64.c
>>> @@ -1,11 +1,11 @@
>>>    // SPDX-License-Identifier: GPL-2.0
>>>    #include <elfutils/libdwfl.h>
>>> -#include "perf_regs.h"
>>> +#include "../../../arch/arm64/include/uapi/asm/perf_regs.h"
>>>    #include "../../../util/unwind-libdw.h"
>>>    #include "../../../util/perf_regs.h"
>>>    #include "../../../util/sample.h"
>>>
>>> -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
>>> +bool libdw_set_initial_registers_arm64(Dwfl_Thread *thread, void *arg)
>>>    {
>>>        struct unwind_info *ui = arg;
>>>        struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
>>> diff --git a/tools/perf/arch/csky/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-csky.c
>>> similarity index 92%
>>> rename from tools/perf/arch/csky/util/unwind-libdw.c
>>> rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-csky.c
>>> index b20b1569783d7e982e91b1b40120d29ccf2f01d1..889d3b788931f3af55b03ef8b91d5def364972e5 100644
>>> --- a/tools/perf/arch/csky/util/unwind-libdw.c
>>> +++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-csky.c
>>> @@ -2,12 +2,12 @@
>>>    // Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd.
>>>
>>>    #include <elfutils/libdwfl.h>
>>> -#include "perf_regs.h"
>>> +#include "../../../arch/csky/include/uapi/asm/perf_regs.h"
>>>    #include "../../util/unwind-libdw.h"
>>>    #include "../../util/perf_regs.h"
>>> -#include "../../util/event.h"
>>> +#include "../../util/sample.h"
>>>
>>> -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
>>> +bool libdw_set_initial_registers_csky(Dwfl_Thread *thread, void *arg)
>>>    {
>>>        struct unwind_info *ui = arg;
>>>        struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
>>> diff --git a/tools/perf/arch/loongarch/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-loongarch.c
>>> similarity index 91%
>>> rename from tools/perf/arch/loongarch/util/unwind-libdw.c
>>> rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-loongarch.c
>>> index 60b1144bedd5f325e1512eeab05c29a1e8de2b03..1c5753ace6f63be771aa92365d3174ad8ed3a6fd 100644
>>> --- a/tools/perf/arch/loongarch/util/unwind-libdw.c
>>> +++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-loongarch.c
>>> @@ -2,12 +2,12 @@
>>>    /* Copyright (C) 2020-2023 Loongson Technology Corporation Limited */
>>>
>>>    #include <elfutils/libdwfl.h>
>>> -#include "perf_regs.h"
>>> +#include "../../../arch/loongarch/include/uapi/asm/perf_regs.h"
>>>    #include "../../util/unwind-libdw.h"
>>>    #include "../../util/perf_regs.h"
>>>    #include "../../util/sample.h"
>>>
>>> -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
>>> +bool libdw_set_initial_registers_loongarch(Dwfl_Thread *thread, void *arg)
>>>    {
>>>        struct unwind_info *ui = arg;
>>>        struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
>>> diff --git a/tools/perf/arch/powerpc/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-powerpc.c
>>> similarity index 93%
>>> rename from tools/perf/arch/powerpc/util/unwind-libdw.c
>>> rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-powerpc.c
>>> index 82d0c28ae3459ecdb0039cac1f534420d142739b..28635af3c4aa420faa4de7e53428d82917f78021 100644
>>> --- a/tools/perf/arch/powerpc/util/unwind-libdw.c
>>> +++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-powerpc.c
>>> @@ -1,7 +1,7 @@
>>>    // SPDX-License-Identifier: GPL-2.0
>>>    #include <elfutils/libdwfl.h>
>>>    #include <linux/kernel.h>
>>> -#include "perf_regs.h"
>>> +#include "../../../arch/powerpc/include/uapi/asm/perf_regs.h"
>>>    #include "../../../util/unwind-libdw.h"
>>>    #include "../../../util/perf_regs.h"
>>>    #include "../../../util/sample.h"
>>> @@ -13,7 +13,7 @@ static const int special_regs[3][2] = {
>>>        { 109, PERF_REG_POWERPC_CTR },
>>>    };
>>>
>>> -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
>>> +bool libdw_set_initial_registers_powerpc(Dwfl_Thread *thread, void *arg)
>>>    {
>>>        struct unwind_info *ui = arg;
>>>        struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
>>> diff --git a/tools/perf/arch/riscv/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-riscv.c
>>> similarity index 92%
>>> rename from tools/perf/arch/riscv/util/unwind-libdw.c
>>> rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-riscv.c
>>> index dc1476e16321736de897ad53a00fbc813bd706db..2a5442b3b5bdc27252378de0073deb8a620f8779 100644
>>> --- a/tools/perf/arch/riscv/util/unwind-libdw.c
>>> +++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-riscv.c
>>> @@ -2,12 +2,12 @@
>>>    /* Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd. */
>>>
>>>    #include <elfutils/libdwfl.h>
>>> -#include "perf_regs.h"
>>> +#include "../../../arch/riscv/include/uapi/asm/perf_regs.h"
>>>    #include "../../util/unwind-libdw.h"
>>>    #include "../../util/perf_regs.h"
>>>    #include "../../util/sample.h"
>>>
>>> -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
>>> +bool libdw_set_initial_registers_riscv(Dwfl_Thread *thread, void *arg)
>>>    {
>>>        struct unwind_info *ui = arg;
>>>        struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
>>> diff --git a/tools/perf/arch/s390/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-s390.c
>>> similarity index 89%
>>> rename from tools/perf/arch/s390/util/unwind-libdw.c
>>> rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-s390.c
>>> index c27c7a0d1076c890c35ba19543932c4ed5ac9c2a..18d44074a55bc1c7fa2d7150afc1f1a93d4eadf8 100644
>>> --- a/tools/perf/arch/s390/util/unwind-libdw.c
>>> +++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-s390.c
>>> @@ -4,11 +4,11 @@
>>>    #include "../../util/perf_regs.h"
>>>    #include "../../util/event.h"
>>>    #include "../../util/sample.h"
>>> -#include "dwarf-regs-table.h"
>>> -#include "perf_regs.h"
>>> +#include "../../arch/s390/include/dwarf-regs-table.h"
>>> +#include "../../../arch/s390/include/uapi/asm/perf_regs.h"
>>>
>>>
>>> -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
>>> +bool libdw_set_initial_registers_s390(Dwfl_Thread *thread, void *arg)
>>>    {
>>>        struct unwind_info *ui = arg;
>>>        struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
>>> diff --git a/tools/perf/arch/x86/util/unwind-libdw.c b/tools/perf/util/unwind-libdw-arch/unwind-libdw-x86.c
>>> similarity index 94%
>>> rename from tools/perf/arch/x86/util/unwind-libdw.c
>>> rename to tools/perf/util/unwind-libdw-arch/unwind-libdw-x86.c
>>> index 798493e887d7308cb293e29e4ba11054d0fda722..822e799fe1543d82dab27a8efeada3f5cde08a44 100644
>>> --- a/tools/perf/arch/x86/util/unwind-libdw.c
>>> +++ b/tools/perf/util/unwind-libdw-arch/unwind-libdw-x86.c
>>
>> You missed converting the unwind-libdw-x86.c perf_regs.h paths to a
>> static arch so now Perf can only be built on x86. If you try to build
>> for another arch then you get the local header and then missing x86
>> definitions.
> 
> Yeah you are right. I'm also going to change some of the relative include paths
> from "../../../" to "../../" since the new files are two levels under
> tools/perf instead of
> three. The build worked without the change mostly by accident.
> 
>>
>> Unfortunately you also have to convert the one in
>> tools/perf/arch/x86/include/perf_regs.h which is a bit weird, but the
>> build seems to work.
> 
> How does tools/perf/arch/x86/include/perf_regs.h come up? I seem to be able to
> build an arm64 version without changing this file.
> 

You're right. I changed one too many other ones trying to get it to 
compile which resulted in me needing to change that one too.

>>
>> Other than that, looks good.
>>
>>> @@ -5,7 +5,7 @@
>>>    #include "../../../util/perf_regs.h"
>>>    #include "util/sample.h"
>>>
>>> -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
>>> +bool libdw_set_initial_registers_x86(Dwfl_Thread *thread, void *arg)
>>>    {
>>>        struct unwind_info *ui = arg;
>>>        struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
>>> diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
>>> index ae70fb56a05729b9f06a411d162eabebbf29ac52..4a0f13bc5af99de446d440c551c718ef0187e195 100644
>>> --- a/tools/perf/util/unwind-libdw.c
>>> +++ b/tools/perf/util/unwind-libdw.c
>>> @@ -225,12 +225,46 @@ static bool memory_read(Dwfl *dwfl __maybe_unused, Dwarf_Addr addr, Dwarf_Word *
>>>        return true;
>>>    }
>>>
>>> -static const Dwfl_Thread_Callbacks callbacks = {
>>> -     .next_thread            = next_thread,
>>> -     .memory_read            = memory_read,
>>> -     .set_initial_registers  = libdw__arch_set_initial_registers,
>>> +#define DEFINE_DWFL_THREAD_CALLBACKS(arch)                           \
>>> +static const Dwfl_Thread_Callbacks callbacks_##arch = {              \
>>> +     .next_thread           = next_thread,                        \
>>> +     .memory_read           = memory_read,                        \
>>> +     .set_initial_registers = libdw_set_initial_registers_##arch, \
>>>    };
>>>
>>> +DEFINE_DWFL_THREAD_CALLBACKS(x86)
>>> +DEFINE_DWFL_THREAD_CALLBACKS(arm)
>>> +DEFINE_DWFL_THREAD_CALLBACKS(arm64)
>>> +DEFINE_DWFL_THREAD_CALLBACKS(csky)
>>> +DEFINE_DWFL_THREAD_CALLBACKS(loongarch)
>>> +DEFINE_DWFL_THREAD_CALLBACKS(powerpc)
>>> +DEFINE_DWFL_THREAD_CALLBACKS(riscv)
>>> +DEFINE_DWFL_THREAD_CALLBACKS(s390)
>>> +
>>> +static const Dwfl_Thread_Callbacks *get_thread_callbacks(const char *arch)
>>> +{
>>> +     if (!strcmp(arch, "arm"))
>>> +             return &callbacks_arm;
>>> +     else if (!strcmp(arch, "arm64"))
>>> +             return &callbacks_arm64;
>>> +     else if (!strcmp(arch, "csky"))
>>> +             return &callbacks_csky;
>>> +     else if (!strcmp(arch, "loongarch"))
>>> +             return &callbacks_loongarch;
>>> +     else if (!strcmp(arch, "powerpc"))
>>> +             return &callbacks_powerpc;
>>> +     else if (!strcmp(arch, "riscv"))
>>> +             return &callbacks_riscv;
>>> +     else if (!strcmp(arch, "s390"))
>>> +             return &callbacks_s390;
>>> +     else if (!strcmp(arch, "x86"))
>>> +             return &callbacks_x86;
>>> +
>>> +     pr_err("Fail to get thread callbacks for arch %s, returns NULL\n",
>>> +            arch);
>>> +     return NULL;
>>> +}
>>> +
>>>    static int
>>>    frame_callback(Dwfl_Frame *state, void *arg)
>>>    {
>>> @@ -278,6 +312,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
>>>        const char *arch = perf_env__arch(ui_buf.machine->env);
>>>        Dwarf_Word ip;
>>>        int err = -EINVAL, i;
>>> +     const Dwfl_Thread_Callbacks *callbacks;
>>>
>>>        if (!data->user_regs || !data->user_regs->regs)
>>>                return -EINVAL;
>>> @@ -300,7 +335,11 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
>>>        if (err)
>>>                goto out;
>>>
>>> -     err = !dwfl_attach_state(ui->dwfl, EM_NONE, thread__tid(thread), &callbacks, ui);
>>> +     callbacks = get_thread_callbacks(arch);
>>> +     if (!callbacks)
>>> +             goto out;
>>> +
>>> +     err = !dwfl_attach_state(ui->dwfl, EM_NONE, thread__tid(thread), callbacks, ui);
>>>        if (err)
>>>                goto out;
>>>
>>> diff --git a/tools/perf/util/unwind-libdw.h b/tools/perf/util/unwind-libdw.h
>>> index 8c88bc4f2304b59561ffd482469ca63ce0f531f0..574b29848cce31e6bfd93021f752b518cebf73b7 100644
>>> --- a/tools/perf/util/unwind-libdw.h
>>> +++ b/tools/perf/util/unwind-libdw.h
>>> @@ -9,7 +9,15 @@ struct machine;
>>>    struct perf_sample;
>>>    struct thread;
>>>
>>> -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg);
>>> +bool libdw_set_initial_registers_x86(Dwfl_Thread *thread, void *arg);
>>> +bool libdw_set_initial_registers_arm(Dwfl_Thread *thread, void *arg);
>>> +bool libdw_set_initial_registers_arm64(Dwfl_Thread *thread, void *arg);
>>> +bool libdw_set_initial_registers_csky(Dwfl_Thread *thread, void *arg);
>>> +bool libdw_set_initial_registers_loongarch(Dwfl_Thread *thread, void *arg);
>>> +bool libdw_set_initial_registers_mips(Dwfl_Thread *thread, void *arg);
>>> +bool libdw_set_initial_registers_powerpc(Dwfl_Thread *thread, void *arg);
>>> +bool libdw_set_initial_registers_riscv(Dwfl_Thread *thread, void *arg);
>>> +bool libdw_set_initial_registers_s390(Dwfl_Thread *thread, void *arg);
>>>
>>>    struct unwind_info {
>>>        Dwfl                    *dwfl;
>>>
>>> ---
>>> base-commit: cbd41c6d4c26c161a2b0e70ad411d3885ff13507
>>> change-id: 20251223-cross-arch-unwind-d890d6a5ff0a
>>>
>>> Best regards,
>>



From cassel at kernel.org  Tue Dec 30 02:14:10 2025
From: cassel at kernel.org (Niklas Cassel)
Date: Tue, 30 Dec 2025 11:14:10 +0100
Subject: [PATCH v2 1/6] Revert "PCI: dw-rockchip: Don't wait for link
 since we can detect Link Up"
In-Reply-To: <20251226223159.GA4143516@bhelgaas>
References: <20251222064207.3246632-9-cassel@kernel.org>
 <20251226223159.GA4143516@bhelgaas>
Message-ID: <aVOl8mfKiYX51gRL@ryzen>

Hello Bjorn,

On Fri, Dec 26, 2025 at 04:31:59PM -0600, Bjorn Helgaas wrote:
> > The long term plan is to migrate this driver to the pwrctrl framework,
> > once it adds proper support for powering up and enumerating PCIe switches.
> 
> "Proper" is hiding some important details here.  pwrctrl already
> supports powering up and enumerating switches.  I think this refers to
> [1], where Mani says the plan is for pwrctrl to power up everything
> before the initial bus scan so we can figure out how many buses are
> needed.
> 
> [1] https://lore.kernel.org/linux-pci/fle74skju2rorxmfdvosmeyrx3g75rysuszov5ofvde2exj4ir at 3kfjyfyhczmn/

Correct.

This series has already been merged to the pci/controller/dwc branch
(although for some reason this branch is not merged to pci/next yet),
and I can see that Mani have rephrased the commit messages to be more
specific and to avoid the word proper.

Please tell me if there is some futher action needed from my part.


Kind regards,
Niklas


From francesco at dolcini.it  Tue Dec 30 02:25:25 2025
From: francesco at dolcini.it (Francesco Dolcini)
Date: Tue, 30 Dec 2025 11:25:25 +0100
Subject: [PATCH v1 0/3] arm64: dts: imx8x-colibri: add additional
 functionality
In-Reply-To: <20251031125003.275033-1-max.oss.09@gmail.com>
References: <20251031125003.275033-1-max.oss.09@gmail.com>
Message-ID: <aVOolTfi5s9jqG2v@livingston.pivistrello.it>

Hello Shawn,

On Fri, Oct 31, 2025 at 01:49:40PM +0100, max.oss.09 at gmail.com wrote:
> Provide a pwm-backlight.
> Provide the 32kHz Wi-Fi clock used during low-power operation.
> Configure CMA from the device tree.

This series was not applied, any concern? Anything to change?

Thanks,
Francesco




From andrew at lunn.ch  Tue Dec 30 02:46:33 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Tue, 30 Dec 2025 11:46:33 +0100
Subject: [PATCH v2 4/4] arm64: dts: imx8mn: Add ifm VHIP4 EvalBoard v1
 and v2
In-Reply-To: <20251229193706.73564-4-marex@nabladev.com>
References: <20251229193706.73564-1-marex@nabladev.com>
 <20251229193706.73564-4-marex@nabladev.com>
Message-ID: <e3d305ce-cdfa-4a11-bd54-9648b12a013f@lunn.ch>

> +&fec1 {
> +	fsl,magic-packet;

Upps, i probably cut out too much context. This FEC is connected to the Ethernet switch.

WoL for a port connected to a switch? Have you tested this? Normally
you would have WoL on each port of the switch, and not on the conduit
interface.

> +&fec1 {
> +	fsl,magic-packet;

Have you tested WoL?

> +&fec1 {
> +	fsl,magic-packet;

WoL again?

	Andrew


From andrew at lunn.ch  Tue Dec 30 02:53:17 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Tue, 30 Dec 2025 11:53:17 +0100
Subject: [PATCH v2 3/3] arm64: dts: imx95-var-dart: Add support for
 Variscite Sonata board
In-Reply-To: <20251229213726.79374-4-stefano.r@variscite.com>
References: <20251229213726.79374-1-stefano.r@variscite.com>
 <20251229213726.79374-4-stefano.r@variscite.com>
Message-ID: <138b59d1-e001-4c9b-bf8b-a5af703d747a@lunn.ch>

> +	sfp0: sfp {
> +		compatible = "sff,sfp";
> +		i2c-bus = <&lpi2c3>;
> +		los-gpios = <&pca9534 1 GPIO_ACTIVE_HIGH>;

Minimalist for GPIOs, but O.K.

> +		maximum-power-milliwatt = <2000>;
> +	};
> +};
> +
> +&enetc_port1 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_enetc1>;
> +	phy-handle = <&ethphy1>;
> +	/*
> +	 * The required RGMII TX and RX 2ns delays are implemented directly
> +	 * in hardware via passive delay elements on the SOM PCB.
> +	 * No delay configuration is needed in software via PHY driver.
> +	 */
> +	phy-mode = "rgmii";
> +	status = "okay";
> +};
> +
> +&enetc_port2 {
> +	phy-mode = "10gbase-r";
> +	sfp = <&sfp0>;
> +	status = "okay";
> +
> +	fixed-link {
> +		speed = <10000>;
> +		full-duplex;
> +	};
> +};

The fixed link is not needed. phylink will ask the SFP plugged into
the cage what it is, and then configure the MAC as needed, 10GBase-R,
5GBase-X, 2.5BaseX, 1000BaseX, SGMII etc.

	Andrew


From sumit.garg at kernel.org  Tue Dec 30 03:10:21 2025
From: sumit.garg at kernel.org (Sumit Garg)
Date: Tue, 30 Dec 2025 16:40:21 +0530
Subject: [PATCH v20 1/6] dt-bindings: firmware: Add TEE remoteproc
 service binding
In-Reply-To: <20251229232530.GA2753472-robh@kernel.org>
References: <20251217153917.3998544-1-arnaud.pouliquen@foss.st.com>
 <20251217153917.3998544-2-arnaud.pouliquen@foss.st.com>
 <20251229232530.GA2753472-robh@kernel.org>
Message-ID: <aVOzHWmlJ-eneS-2@sumit-xelite>

On Mon, Dec 29, 2025 at 05:25:30PM -0600, Rob Herring wrote:
> On Wed, Dec 17, 2025 at 04:39:12PM +0100, Arnaud Pouliquen wrote:
> > Add a device tree binding for the TEE-based remote processor control
> > service implemented as an OP-TEE Trusted Application identified by
> > UUID 80a4c275-0a47-4905-8285-1486a9771a08.
> > 
> > The TEE service node is a child of the "linaro,optee-tz" firmware node and
> > acts as a container for remoteproc devices that are controlled via TEE.
> 
> Is this generic for any remoteproc device or just ST's remoteproc. Looks 
> like the latter to me.

That's true, the DT description of the remoteproc subnode is very
specific to the vendor which in this case is ST.

> 
> > In addition, the "linaro,optee-tz" binding is updated to specify the
> > '#address-cells' and '#size-cells' values used for child TEE service
> > nodes.
> 
> I'm pretty sure I already rejected per service/app child nodes for 
> OP-TEE when its binding was submitted.

That was the reason to have discoverable TEE bus in first place and I
have been motivating people to dynamically discover firmware properties
rather than hardcoding in the DT.

> If we do need something in DT 
> to define some resources, then can't we have some sort of 
> standard/common communications channel? I don't care to see some sort of 
> free-for-all where we have every vendor doing their own thing. OP-TEE 
> needs to standarize this.

I suppose this requires a wider scope work as you can see the DT resource
dependence from here [1]. By standardize communication channel, do you
mean to say if adding an alternative backend to fwnode for TEE in
parallel to DT, ACPI or swnode is the way to go for discovering fw
properties? Or do you have any other suggestion here?

Along with that the corresponding subsystems has to adopt fwnode APIs
instead of OF APIs.

[1] https://lore.kernel.org/all/0e5a44df-f60a-4523-a791-6318b3c81425 at foss.st.com/

-Sumit


From andrew at lunn.ch  Tue Dec 30 03:11:32 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Tue, 30 Dec 2025 12:11:32 +0100
Subject: [PATCH 2/2] Revert "arm: dts: socfpga: use reset-name
 "stmmaceth-ocp" instead of "ahb""
In-Reply-To: <20251229-remove_ocp-v1-2-594294e04bd4@kernel.org>
References: <20251229-remove_ocp-v1-0-594294e04bd4@kernel.org>
 <20251229-remove_ocp-v1-2-594294e04bd4@kernel.org>
Message-ID: <8997facb-068b-4088-b996-1c0898dea19a@lunn.ch>

On Mon, Dec 29, 2025 at 01:17:19PM -0600, Dinh Nguyen wrote:
> This reverts commit 62a40a0d5634834790f7166ab592be247390d857.
> 
> With the patch "add call to assert/deassert ahb reset line" in place, we can
> safely remove the "stmmaceth-ocp" reset name and just use the standard
> "ahb" reset name.

altr,socfpga-stmmac.yamle says:

  # TODO: Determine how to handle the Arria10 reset-name, stmmaceth-ocp, that
  # does not validate against net/snps,dwmac.yaml.

Please add a patch to the series adding stmmaceth-ocp, but mark it as
deprecated, and comment that ahb should be used instead.

    Andrew

---
pw-bot: cr


From festevam at gmail.com  Tue Dec 30 03:12:37 2025
From: festevam at gmail.com (Fabio Estevam)
Date: Tue, 30 Dec 2025 08:12:37 -0300
Subject: [PATCH v2 3/3] arm64: dts: imx95-var-dart: Add support for
 Variscite Sonata board
In-Reply-To: <20251229213726.79374-4-stefano.r@variscite.com>
References: <20251229213726.79374-1-stefano.r@variscite.com> <20251229213726.79374-4-stefano.r@variscite.com>
Message-ID: <CAOMZO5CjdQiy2nJTEL-HK+xzZ9EyAE1PMhoUroP2nTZ07pJbzg@mail.gmail.com>

On Mon, Dec 29, 2025 at 6:37?PM Stefano Radaelli
<stefano.radaelli21 at gmail.com> wrote:

> +       /* Capacitive touch controller */
> +       ft5x06_ts: ft5x06_ts at 38 {

Node names should be generic: touchscreen at 38

> +       /* Resistive touch controller */
> +       ads7846 at 0 {

touchscreen at 0


From festevam at gmail.com  Tue Dec 30 03:13:13 2025
From: festevam at gmail.com (Fabio Estevam)
Date: Tue, 30 Dec 2025 08:13:13 -0300
Subject: [PATCH v2 2/3] arm64: dts: freescale: Add support for Variscite DART-MX95
In-Reply-To: <20251229213726.79374-3-stefano.r@variscite.com>
References: <20251229213726.79374-1-stefano.r@variscite.com> <20251229213726.79374-3-stefano.r@variscite.com>
Message-ID: <CAOMZO5CsN-DMKoJ2Fz063tVKVqsr6Y1dq7B1Mg=Krz+_g1tQcg@mail.gmail.com>

On Mon, Dec 29, 2025 at 6:37?PM Stefano Radaelli
<stefano.radaelli21 at gmail.com> wrote:

> +       reg_audio: regulator-audio-vdd {
> +               compatible = "regulator-fixed";
> +               regulator-name = "wm8904_supply";
> +               regulator-min-microvolt = <3300000>;
> +               regulator-max-microvolt = <3300000>;
> +               regulator-always-on;

Please drop 'regulator-always-on'. reg_audio is consumed by the audio codec.

> +&lpi2c8 {
> +       clock-frequency = <400000>;
> +       pinctrl-names = "default","gpio","sleep";
> +       pinctrl-0 = <&pinctrl_lpi2c8>;
> +       pinctrl-1 = <&pinctrl_lpi2c8_gpio>;
> +       pinctrl-2 = <&pinctrl_lpi2c8_gpio>;
> +       scl-gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>;
> +       sda-gpios = <&gpio2 11 GPIO_ACTIVE_HIGH>;
> +       status = "okay";
> +
> +       wm8904: codec at 1a {

audio-codec at 1a


From krzk at kernel.org  Tue Dec 30 03:16:14 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 30 Dec 2025 12:16:14 +0100
Subject: [PATCH v2 1/3] dt-bindings: arm: fsl: add Variscite DART-MX95
 Boards
In-Reply-To: <20251229213726.79374-2-stefano.r@variscite.com>
References: <20251229213726.79374-1-stefano.r@variscite.com>
 <20251229213726.79374-2-stefano.r@variscite.com>
Message-ID: <20251230-cerulean-manatee-from-mars-be5ace@quoll>

On Mon, Dec 29, 2025 at 10:37:15PM +0100, Stefano Radaelli wrote:
> From: Stefano Radaelli <stefano.r at variscite.com>
> 
> Add DT compatible strings for Variscite DART-MX95 SoM and Variscite
> development carrier Board.
> 
> Link: https://variscite.com/system-on-module-som/i-mx-9/dart-mx95/
> Link: https://variscite.com/carrier-boards/sonata-board/
> Signed-off-by: Stefano Radaelli <stefano.r at variscite.com>
> ---
>  Documentation/devicetree/bindings/arm/fsl.yaml | 6 ++++++

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof



From krzk at kernel.org  Tue Dec 30 03:32:29 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 30 Dec 2025 12:32:29 +0100
Subject: [PATCH 2/3] dt-bindings: mfd: netronix,ntxec: add reference to
 power-supply
In-Reply-To: <20251227-kobo-aura-battery-v1-2-328a90ef5122@jm0.eu>
References: <20251227-kobo-aura-battery-v1-0-328a90ef5122@jm0.eu>
 <20251227-kobo-aura-battery-v1-2-328a90ef5122@jm0.eu>
Message-ID: <20251230-defiant-frisky-bull-95ecd0@quoll>

On Sat, Dec 27, 2025 at 05:28:14PM +0100, Josua Mayer wrote:
> The Netronix Embedded Controller supports monitoring of battery voltage.
> 
> Voltage monitoring functionality is self-contained and requires no
> supply- or battery-specific runtime configuration.
> 
> Battery design characteristics (e.g. voltage-min-design-microvolt) are
> useful for users to understand the charge level and are commonly
> provided by a separate battery node linked with monitored-battery
> property.
> 
> Add reference to power-supply.yaml so that power-supplies and
> monitored-battery properties become available.
> 
> Further drop reg property description and replace it with maxItems 1 as
> is common for i2c devices with single bus address.
> 
> Finally replace additionalProperties with unevaluatedProperties to
> allow properties from referenced schemas.
> 
> Signed-off-by: Josua Mayer <josua at solid-run.com>

This does not match From address. Please use consistent identities for
both.

Best regards,
Krzysztof



From krzk at kernel.org  Tue Dec 30 04:34:44 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 30 Dec 2025 13:34:44 +0100
Subject: [PATCH 2/2] dt-bindings: watchdog: fsl-imx: document continue in
 low power mode
In-Reply-To: <20251229145000.421426-3-nandor.han@gehealthcare.com>
References: <20251229145000.421426-1-nandor.han@gehealthcare.com>
 <20251229145000.421426-3-nandor.han@gehealthcare.com>
Message-ID: <20251230-hidden-okapi-of-reputation-6ef8be@quoll>

On Mon, Dec 29, 2025 at 04:50:00PM +0200, Nandor Han wrote:
> Property "fsl,wdt-continue-in-low-power" allows the watchdog to continue
> running in low power modes (STOP and DOZE). By default, the watchdog is
> suspended in these modes. This property provides the option to keep the
> watchdog active during low power states when needed.

And why exactly would that be a DT property? If system is sleeping
(assuming this is what you meant by low power), no one will pet the dog,
thus watchdog makes no sense.

Otherwise I fail to see how this is a hardware property and we do not
accept SW properties (see writing bindings, numerous presentations).

Best regards,
Krzysztof



From krzk at kernel.org  Tue Dec 30 04:35:25 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 30 Dec 2025 13:35:25 +0100
Subject: [PATCH 1/2] watchdog: imx2_wdt: Allow to continue in low power
 mode
In-Reply-To: <20251229145000.421426-2-nandor.han@gehealthcare.com>
References: <20251229145000.421426-1-nandor.han@gehealthcare.com>
 <20251229145000.421426-2-nandor.han@gehealthcare.com>
Message-ID: <20251230-pastoral-enigmatic-chamois-b65343@quoll>

On Mon, Dec 29, 2025 at 04:49:59PM +0200, Nandor Han wrote:
> By default, the driver suspends the watchdog in low power modes (STOP
> and DOZE). In some situations this is not desired.
> 
> Add the possibility to configure the continuation of the watchdog timer
> in the above mentioned low power modes.
> 
> Note:
> Please be advised that the difference between the variable name and the
> device tree option has been intentionally selected to uphold the
> prevailing driver functionality. This ensures that the watchdog remains
> suspended by default in low power mode, while also facilitating a clear
> and intelligible device tree option name.
>

Please organize the patch documenting the compatible (DT bindings)
before the patch using that compatible.
See also: https://elixir.bootlin.com/linux/v6.14-rc6/source/Documentation/devicetree/bindings/submitting-patches.rst#L46

Best regards,
Krzysztof



From shawnguo at kernel.org  Tue Dec 30 04:47:02 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 20:47:02 +0800
Subject: [PATCH v5 5/7] arm64: dts: add description for solidrun imx8mp
 hummingboard-iiot
In-Reply-To: <20251221-imx8mp-hb-iiot-v5-5-4a4dad916348@solid-run.com>
References: <20251221-imx8mp-hb-iiot-v5-0-4a4dad916348@solid-run.com>
 <20251221-imx8mp-hb-iiot-v5-5-4a4dad916348@solid-run.com>
Message-ID: <aVPJxlrT8GG2A75r@dragon>

On Sun, Dec 21, 2025 at 12:28:54PM +0100, Josua Mayer wrote:
> Add description for the SolidRun i.MX8MP HummingBoard IIoT.
> The board is a new design around the i.MX8MP System on Module, not
> sharing much with previous HummingBoards.
> 
> It comes with some common features:
> - 3x USB-3.0 Type A connector
> - 2x 1Gbps RJ45 Ethernet
> - USB Type-C Console Port
> - microSD connector
> - RTC with backup battery
> - RGB Status LED
> - 1x M.2 M-Key connector with PCI-E Gen. 3 x1
> - 1x M.2 B-Key connector with USB-2.0/3.0 + SIM card holder
> - 1x LVDS Display Connector
> - 1x DSI Display Connector
> - GPIO header
> - 2x RS232/RS485 ports (configurable)
> - 2x CAN
> 
> In addition there is a board-to-board expansion connector to support
> custom daughter boards with access to SPI, a range of GPIOs and -
> notably - CAN and UART. Both 2x CAN and 2x UART can be muxed either
> to this b2b connector, or a termianl block connector on the base board.
> 
> The routing choice for UART and CAN is expressed through gpio
> mux-controllers in DT and can be changed by applying dtb addons.
> 
> Four dtb addons are provided:
> 
> - dsi panel Winstar WJ70N3TYJHMNG0
> - lvds panel Winstar WF70A8SYJHLNGA
> - RS485 on UART port "A" (default rs232)
> - RS485 on UART port "B" (default rs232)
> 
> Signed-off-by: Josua Mayer <josua at solid-run.com>
> ---
>  arch/arm64/boot/dts/freescale/Makefile             |   6 +
>  ...hummingboard-iiot-panel-dsi-WJ70N3TYJHMNG0.dtso |  69 ++
>  ...ummingboard-iiot-panel-lvds-WF70A8SYJHLNGA.dtso | 105 +++
>  .../imx8mp-hummingboard-iiot-rs485-a.dtso          |  18 +
>  .../imx8mp-hummingboard-iiot-rs485-b.dtso          |  18 +
>  .../dts/freescale/imx8mp-hummingboard-iiot.dts     | 719 +++++++++++++++++++++
>  6 files changed, 935 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
> index c4c6fd6de9637..97e6000154640 100644
> --- a/arch/arm64/boot/dts/freescale/Makefile
> +++ b/arch/arm64/boot/dts/freescale/Makefile
> @@ -213,6 +213,12 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mp-dhcom-pdk3.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx8mp-dhcom-picoitx.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx8mp-edm-g-wb.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk.dtb
> +dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-iiot.dtb
> +DTC_FLAGS_imx8mp-hummingboard-iiot := -@
> +dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-iiot-panel-dsi-WJ70N3TYJHMNG0.dtbo
> +dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-iiot-panel-lvds-WF70A8SYJHLNGA.dtbo
> +dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-iiot-rs485-a.dtbo
> +dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-iiot-rs485-b.dtbo
>  dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-mate.dtb
>  DTC_FLAGS_imx8mp-hummingboard-mate := -@
>  dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-pro.dtb
> diff --git a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-panel-dsi-WJ70N3TYJHMNG0.dtso b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-panel-dsi-WJ70N3TYJHMNG0.dtso
> new file mode 100644
> index 0000000000000..e66ee2ce69d8d
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-panel-dsi-WJ70N3TYJHMNG0.dtso
> @@ -0,0 +1,69 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright 2025 Josua Mayer <josua at solid-run.com>
> + *
> + * Overlay for enabling HummingBoard IIoT MIPI-DSI connector
> + * with Winstar WJ70N3TYJHMNG0 panel.
> + */
> +
> +/dts-v1/;
> +/plugin/;
> +
> +#include <dt-bindings/gpio/gpio.h>
> +#include <dt-bindings/interrupt-controller/irq.h>
> +
> +&{/} {
> +	dsi_backlight: dsi-backlight {
> +		compatible = "gpio-backlight";
> +		gpios = <&tca6408_u48 3 GPIO_ACTIVE_LOW>;
> +	};
> +};
> +
> +&i2c_dsi {
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +
> +	touchscreen at 41 {
> +		compatible = "ilitek,ili2130";
> +		reg = <0x41>;
> +		reset-gpios = <&tca6408_u48 6 GPIO_ACTIVE_LOW>;
> +		interrupts-extended = <&tca6416_u21 13 IRQ_TYPE_LEVEL_LOW>;
> +	};
> +};
> +
> +&lcdif1 {
> +	status = "okay";
> +};
> +
> +&mipi_dsi {
> +	samsung,esc-clock-frequency = <10000000>;
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +	status = "okay";
> +
> +	panel at 0 {
> +		/* This is a Winstar panel, but the ronbo panel uses same controls. */
> +		compatible = "ronbo,rb070d30";
> +		reg = <0>;
> +		vcc-lcd-supply = <&reg_dsi_panel>;
> +		power-gpios = <&tca6408_u48 2 GPIO_ACTIVE_HIGH>;
> +		/* reset is active-low but driver inverts it internally */
> +		reset-gpios = <&tca6408_u48 1 GPIO_ACTIVE_HIGH>;
> +		updn-gpios = <&tca6408_u48 5 GPIO_ACTIVE_HIGH>;
> +		shlr-gpios = <&tca6408_u48 4 GPIO_ACTIVE_LOW>;
> +		backlight = <&dsi_backlight>;
> +
> +		port {
> +			panel_from_dsim: endpoint {
> +				remote-endpoint = <&dsim_to_panel>;
> +			};
> +		};
> +	};
> +
> +	port at 1 {
> +		dsim_to_panel: endpoint {
> +			remote-endpoint = <&panel_from_dsim>;
> +			data-lanes = <1 2 3 4>;
> +		};
> +	};
> +};
> diff --git a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-panel-lvds-WF70A8SYJHLNGA.dtso b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-panel-lvds-WF70A8SYJHLNGA.dtso
> new file mode 100644
> index 0000000000000..f8fb7fd0e4e49
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-panel-lvds-WF70A8SYJHLNGA.dtso
> @@ -0,0 +1,105 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright 2025 Josua Mayer <josua at solid-run.com>
> + *
> + * Overlay for enabling HummingBoard IIoT LVDS connector
> + * with Winstar WF70A8SYJHLNGA panel.
> + */
> +
> +/dts-v1/;
> +/plugin/;
> +
> +#include <dt-bindings/gpio/gpio.h>
> +#include <dt-bindings/interrupt-controller/irq.h>
> +
> +&{/} {
> +	lvds_backlight: lvds-backlight {
> +		compatible = "gpio-backlight";
> +		gpios = <&tca6408_u37 3 GPIO_ACTIVE_LOW>;
> +	};
> +
> +	panel-lvds {
> +		compatible = "winstar,wf70a8syjhlnga", "panel-lvds";
> +		backlight = <&lvds_backlight>;
> +		power-supply = <&reg_dsi_panel>;
> +		enable-gpios = <&tca6408_u37 2 GPIO_ACTIVE_HIGH>;
> +		reset-gpios = <&tca6408_u37 1 GPIO_ACTIVE_HIGH>;
> +		data-mapping = "vesa-24";
> +		width-mm = <154>;
> +		height-mm = <86>;
> +
> +		panel-timing {
> +			/*
> +			 * Note: NXP BSP hard-codes 74MHz clock in ldb driver:
> +			 * drivers/gpu/drm/imx/imx8mp-ldb.c
> +			 * SolidRun BSP carries patch.
> +			 */
> +			clock-frequency = <49500000>;
> +			hactive = <1024>;
> +			vactive = <600>;
> +			hfront-porch = <40>;
> +			hback-porch = <144>;
> +			hsync-len = <104>;
> +			hsync-active = <0>;
> +			vfront-porch = <3>;
> +			vback-porch = <11>;
> +			vsync-len = <10>;
> +			vsync-active = <1>;
> +			de-active = <1>;
> +		};
> +
> +		port {
> +			panel_from_lvds: endpoint {
> +				remote-endpoint = <&lvds_ch0_out>;
> +			};
> +		};
> +	};
> +};
> +
> +&i2c_lvds {
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +
> +	touchscreen at 41 {
> +		compatible = "ilitek,ili2130";
> +		reg = <0x41>;
> +		reset-gpios = <&tca6408_u37 6 GPIO_ACTIVE_LOW>;
> +		interrupts-extended = <&tca6416_u21 13 IRQ_TYPE_LEVEL_LOW>;
> +	};
> +};
> +
> +&lcdif2 {
> +	status = "okay";
> +};
> +
> +&lvds_bridge {
> +	status = "okay";
> +
> +	ports {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		status = "okay";

Is it disabled somewhere so that you need to flip 'status' here?

> +
> +		port at 1 {
> +			lvds_ch0_out: endpoint {
> +				remote-endpoint = <&panel_from_lvds>;
> +			};
> +		};
> +	};
> +};
> +
> +&tca6408_u37 {
> +	lvds-lr-hog {
> +		gpio-hog;
> +		gpios = <4 GPIO_ACTIVE_HIGH>;
> +		output-high;
> +		line-name = "lvds-l/r";
> +	};
> +
> +	lvds-ud-hog {
> +		gpio-hog;
> +		gpios = <5 GPIO_ACTIVE_HIGH>;
> +		output-high;
> +		line-name = "lvds-u/d";
> +	};
> +};
> diff --git a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-rs485-a.dtso b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-rs485-a.dtso
> new file mode 100644
> index 0000000000000..7bbf800b78fb1
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-rs485-a.dtso
> @@ -0,0 +1,18 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright 2025 Josua Mayer <josua at solid-run.com>
> + *
> + * Overlay for enabling HummingBoard IIoT on-board RS485 Port A on connector J5004.
> + */
> +
> +/dts-v1/;
> +/plugin/;
> +
> +&uart3_rs_232_485_mux {
> +	/* select rs485 */
> +	idle-state = <1>;
> +};
> +
> +&uart3 {
> +	linux,rs485-enabled-at-boot-time;
> +};
> diff --git a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-rs485-b.dtso b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-rs485-b.dtso
> new file mode 100644
> index 0000000000000..d4bfea886ad12
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot-rs485-b.dtso
> @@ -0,0 +1,18 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright 2025 Josua Mayer <josua at solid-run.com>
> + *
> + * Overlay for enabling HummingBoard IIoT on-board RS485 Port B on connector J5004.
> + */
> +
> +/dts-v1/;
> +/plugin/;
> +
> +&uart4_rs_232_485_mux {
> +	/* select rs485 */
> +	idle-state = <1>;
> +};
> +
> +&uart4 {
> +	linux,rs485-enabled-at-boot-time;
> +};
> diff --git a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot.dts b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot.dts
> new file mode 100644
> index 0000000000000..32351d4db9ced
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-iiot.dts
> @@ -0,0 +1,719 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright 2024 Yazan Shhady <yazan.shhady at solid-run.com>
> + * Copyright 2025 Josua Mayer <josua at solid-run.com>
> + */
> +
> +/dts-v1/;
> +
> +#include <dt-bindings/leds/common.h>
> +#include <dt-bindings/phy/phy-imx8-pcie.h>
> +
> +#include "imx8mp-sr-som.dtsi"
> +
> +/ {
> +	model = "SolidRun i.MX8MP HummingBoard IIoT";
> +	compatible = "solidrun,imx8mp-hummingboard-iiot",
> +		     "solidrun,imx8mp-sr-som", "fsl,imx8mp";
> +
> +	aliases {
> +		ethernet0 = &eqos; /* J10 */
> +		ethernet1 = &fec; /* J11 */
> +		rtc0 = &carrier_rtc;
> +		rtc1 = &snvs_rtc;

Could you sort aliases alphabetically?

> +		gpio5 = &tca6408_u48;
> +		gpio6 = &tca6408_u37;
> +		gpio7 = &tca6416_u20;
> +		gpio8 = &tca6416_u21;
> +		i2c6 = &i2c_exp;
> +		i2c7 = &i2c_csi;
> +		i2c8 = &i2c_dsi;
> +		i2c9 = &i2c_lvds;
> +	};
> +
> +	v_1_2: regulator-1-2 {
> +		compatible = "regulator-fixed";
> +		regulator-name = "1v2";
> +		regulator-min-microvolt = <1800000>;
> +		regulator-max-microvolt = <1800000>;
> +	};
> +
> +	reg_dsi_panel: regulator-dsi-panel {
> +		compatible = "regulator-fixed";
> +		regulator-name = "dsi-panel";
> +		regulator-min-microvolt = <11200000>;
> +		regulator-max-microvolt = <11200000>;
> +		gpios = <&tca6416_u20 15 GPIO_ACTIVE_HIGH>;
> +		enable-active-high;
> +	};
> +
> +	/* power for M.2 B-Key connector (J6) */
> +	regulator-m2-b {
> +		compatible = "regulator-fixed";
> +		regulator-name = "m2-b";
> +		regulator-min-microvolt = <3300000>;
> +		regulator-max-microvolt = <3300000>;
> +		gpios = <&tca6416_u20 5 GPIO_ACTIVE_HIGH>;
> +		enable-active-high;
> +		regulator-always-on;
> +	};
> +
> +	/* power for M.2 M-Key connector (J4) */
> +	regulator-m2-m {
> +		compatible = "regulator-fixed";
> +		regulator-name = "m2-m";
> +		regulator-min-microvolt = <3300000>;
> +		regulator-max-microvolt = <3300000>;
> +		gpios = <&tca6416_u20 6 GPIO_ACTIVE_HIGH>;
> +		enable-active-high;
> +		regulator-always-on;
> +	};
> +
> +	vmmc: regulator-mmc {
> +		compatible = "regulator-fixed";
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&vmmc_pins>;
> +		regulator-name = "vmmc";
> +		regulator-min-microvolt = <3300000>;
> +		regulator-max-microvolt = <3300000>;
> +		gpio = <&gpio2 19 GPIO_ACTIVE_LOW>;
> +		enable-active-high;

enable-active-high conflicts with GPIO_ACTIVE_LOW.

> +		startup-delay-us = <250>;
> +	};
> +
> +	/* power for USB-A J5003 */
> +	vbus1: regulator-vbus-1 {
> +		compatible = "regulator-fixed";
> +		regulator-name = "vbus1";
> +		gpio = <&tca6416_u20 14 GPIO_ACTIVE_HIGH>;
> +		enable-active-high;
> +		regulator-min-microvolt = <5000000>;
> +		regulator-max-microvolt = <5000000>;
> +	};
> +
> +	/* power for USB-A J27 behind USB Hub Port 3 */
> +	regulator-vbus-2 {
> +		compatible = "regulator-fixed";
> +		regulator-name = "vbus2";
> +		gpio = <&tca6416_u20 12 GPIO_ACTIVE_HIGH>;
> +		enable-active-high;
> +		regulator-min-microvolt = <5000000>;
> +		regulator-max-microvolt = <5000000>;
> +		regulator-always-on;
> +	};
> +
> +	/* power for USB-A J27 behind USB Hub Port 4 */
> +	regulator-vbus-3 {
> +		compatible = "regulator-fixed";
> +		regulator-name = "vbus3";
> +		gpio = <&tca6416_u20 13 GPIO_ACTIVE_HIGH>;
> +		enable-active-high;
> +		regulator-min-microvolt = <5000000>;
> +		regulator-max-microvolt = <5000000>;
> +		regulator-always-on;
> +	};
> +
> +	rfkill-m2-b-gnss {
> +		compatible = "rfkill-gpio";
> +		label = "m2-b gnss";
> +		radio-type = "gps";
> +		/* rfkill-gpio inverts internally */
> +		shutdown-gpios = <&tca6416_u20 10 GPIO_ACTIVE_HIGH>;
> +	};
> +
> +	rfkill-m2-b-wwan {
> +		compatible = "rfkill-gpio";
> +		label = "m2-b radio";
> +		radio-type = "wwan";
> +		/* rfkill-gpio inverts internally */
> +		shutdown-gpios = <&tca6416_u20 9 GPIO_ACTIVE_HIGH>;
> +	};
> +
> +	flexcan1_flexcan2_b2b_mux: mux-controller-0 {
> +		compatible = "gpio-mux";
> +		#mux-control-cells = <0>;
> +		/*
> +		 * Mux switches both flexcan1 and flexcan2 tx/rx between
> +		 * expansion connector (J22) and on-board transceivers
> +		 * using one GPIO: 0 = on-board, 1 connector.
> +		 */
> +		mux-gpios = <&tca6416_u20 3 GPIO_ACTIVE_HIGH>;
> +		/* default on-board */
> +		idle-state = <0>;
> +	};
> +
> +	mux-controller-1 {
> +		compatible = "gpio-mux";
> +		#mux-control-cells = <0>;
> +		/*
> +		 * Mux switches can bus between different SoM board-to-board
> +		 * connector pins which is used to support different SoMs.
> +		 * i.MX8M Plus uses J7-12/16 and J9-54/56 for 2x flexcan.
> +		 */
> +		mux-gpios = <&tca6416_u20 4 GPIO_ACTIVE_HIGH>;
> +		idle-state = <1>;
> +	};
> +
> +	spi_mux: mux-controller-2 {
> +		compatible = "gpio-mux";
> +		#mux-control-cells = <0>;
> +		/*
> +		 * Mux switches spi bus between on-board tpm
> +		 * and expansion connector (J22).
> +		 */
> +		mux-gpios = <&tca6416_u21 0 GPIO_ACTIVE_HIGH>;
> +		/* default on-board */
> +		idle-state = <0>;
> +	};
> +
> +	uart3_uart4_b2b_mux: mux-controller-3 {
> +		compatible = "gpio-mux";
> +		#mux-control-cells = <0>;
> +		/*
> +		 * Mux switches both uart3 and uart4 tx/rx between expansion
> +		 * connector (J22) and on-board rs232/rs485 transceivers
> +		 * using one GPIO: 0 = on-board, 1 connector.
> +		 */
> +		mux-gpios = <&tca6416_u20 0 GPIO_ACTIVE_HIGH>;
> +		/* default on-board */
> +		idle-state = <0>;
> +	};
> +
> +	uart3_rs_232_485_mux: mux-controller-4 {
> +		compatible = "gpio-mux";
> +		#mux-control-cells = <0>;
> +		/*
> +		 * Mux switches uart3 tx/rx between rs232 and rs485
> +		 * transceivers. using one GPIO: 0 = rs232; 1 = rs485.
> +		 */
> +		mux-gpios = <&tca6416_u20 1 GPIO_ACTIVE_HIGH>;
> +		/* default rs232 */
> +		idle-state = <0>;
> +	};
> +
> +	uart4_rs_232_485_mux: mux-controller-5 {
> +		compatible = "gpio-mux";
> +		#mux-control-cells = <0>;
> +		/*
> +		 * Mux switches uart4 tx/rx between rs232 and rs485
> +		 * transceivers. using one GPIO: 0 = rs232; 1 = rs485.
> +		 */
> +		mux-gpios = <&tca6416_u20 2 GPIO_ACTIVE_HIGH>;
> +		/* default rs232 */
> +		idle-state = <0>;
> +	};
> +
> +	gpio-keys {
> +		compatible = "gpio-keys";
> +
> +		wakeup-event {
> +			label = "m2-m-wakeup";
> +			interrupts-extended = <&tca6416_u21 11 IRQ_TYPE_EDGE_FALLING>;
> +			linux,code = <KEY_WAKEUP>;
> +			wakeup-source;
> +		};
> +	};
> +};
> +
> +&ecspi2 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&ecspi2_pins>;
> +	num-cs = <1>;
> +	cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
> +	status = "okay";
> +
> +	ecspi2_muxed: spi at 0 {
> +		compatible = "spi-mux";
> +		reg = <0>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		/* mux bandwidth is 2GHz, soc max. spi clock is 166MHz */
> +		spi-max-frequency = <166000000>;
> +		mux-controls = <&spi_mux>;
> +
> +		tpm at 0 {
> +			compatible = "infineon,slb9670", "tcg,tpm_tis-spi";
> +			reg = <0>;
> +			spi-max-frequency = <43000000>;
> +			reset-gpios = <&tca6416_u21 1 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>;
> +			interrupts-extended = <&tca6416_u21 9 IRQ_TYPE_LEVEL_LOW>;
> +		};
> +	};
> +};
> +
> +&flexcan1 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&can1_pins>;
> +	status = "okay";
> +
> +	can-transceiver {
> +		max-bitrate = <8000000>;
> +	};
> +};
> +
> +&flexcan2 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&can2_pins>;
> +	status = "okay";
> +
> +	can-transceiver {
> +		max-bitrate = <8000000>;
> +	};
> +};
> +
> +&i2c2 {
> +	i2c-mux at 70 {
> +		compatible = "nxp,pca9546";
> +		reg = <0x70>;
> +		/*
> +		 * This reset is open drain,
> +		 * but reset core does not support GPIO_OPEN_DRAIN flag.
> +		 */
> +		reset-gpios = <&tca6416_u21 2 GPIO_ACTIVE_LOW>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		/* channel 0 routed to expansion connector (J22) */
> +		i2c_exp: i2c at 0 {
> +			reg = <0>;
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +		};
> +
> +		/* channel 1 routed to mipi-csi connector (J23) */
> +		i2c_csi: i2c at 1 {
> +			reg = <1>;
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +		};
> +
> +		/* channel 2 routed to mipi-dsi connector (J25) */
> +		i2c_dsi: i2c at 2 {
> +			reg = <2>;
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +
> +			tca6408_u48: gpio at 21 {
> +				compatible = "ti,tca6408";
> +				reg = <0x21>;
> +				/*
> +				 * reset shared between U37 and U48, to be
> +				 * supported once gpio-pca953x switches to
> +				 * reset framework.
> +				 *
> +				 * reset-gpios = <&tca6416_u21 4 (GPIO_ACTIVE_LOW|GPIO_PULL_UP|GPIO_OPEN_DRAIN)>;
> +				 */
> +				gpio-controller;
> +				#gpio-cells = <2>;
> +				gpio-line-names = "CAM_RST#", "DSI_RESET",
> +						  "DSI_STBYB", "DSI_PWM_BL",
> +						  "DSI_L/R", "DSI_U/D",
> +						  "DSI_CTP_/RST", "CAM_TRIG";
> +			};
> +		};
> +
> +		/* channel 2 routed to lvds connector (J24) */
> +		i2c_lvds: i2c at 3 {
> +			reg = <3>;
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +
> +			tca6408_u37: gpio at 20 {
> +				compatible = "ti,tca6408";
> +				reg = <0x20>;
> +				/*
> +				 * reset shared between U37 and U48, to be
> +				 * supported once gpio-pca953x switches to
> +				 * reset framework.
> +				 *
> +				 * reset-gpios = <&tca6416_u21 4 (GPIO_ACTIVE_LOW|GPIO_PULL_UP|GPIO_OPEN_DRAIN)>;
> +				 */
> +				gpio-controller;
> +				#gpio-cells = <2>;
> +				gpio-line-names = "SELB", "LVDS_RESET",
> +						  "LVDS_STBYB", "LVDS_PWM_BL",
> +						  "LVDS_L/R", "LVDS_U/D",
> +						  "LVDS_CTP_/RST", "";
> +			};
> +		};
> +	};
> +};
> +
> +&i2c3 {
> +	/* highest i2c clock supported by all peripherals is 400kHz */
> +	clock-frequency = <400000>;
> +
> +	tca6416_u20: gpio at 20 {
> +		/*
> +		 * This is a TI TCAL6416 using same programming model as
> +		 * NXP PCAL6416, not to be confused with TI TCA6416.
> +		 */
> +		compatible = "nxp,pcal6416";
> +		reg = <0x20>;
> +		gpio-controller;
> +		#gpio-cells = <2>;
> +		gpio-line-names = "TCA_INT/EXT_UART", "TCA_UARTA_232/485",
> +				  "TCA_UARTB_232/485", "TCA_INT/EXT_CAN",
> +				  "TCA_NXP/REN", "TCA_M.2B_3V3_EN",
> +				  "TCA_M.2M_3V3_EN", "TCA_M.2M_RESET#",
> +				  "TCA_M.2B_RESET#", "TCA_M.2B_W_DIS#",
> +				  "TCA_M.2B_GPS_EN#", "TCA_USB-HUB_RST#",
> +				  "TCA_USB_HUB3_PWR_EN", "TCA_USB_HUB4_PWR_EN",
> +				  "TCA_USB1_PWR_EN", "TCA_VIDEO_PWR_EN";
> +
> +		m2-b-reset-hog {
> +			gpio-hog;
> +			gpios = <8 GPIO_ACTIVE_LOW>;
> +			output-low;
> +			line-name = "m2-b-reset";
> +		};
> +	};
> +
> +	tca6416_u21: gpio at 21 {
> +		/*
> +		 * This is a TI TCAL6416 using same programming model as
> +		 * NXP PCAL6416, not to be confused with TI TCA6416.
> +		 */
> +		compatible = "nxp,pcal6416";
> +		reg = <0x21>;
> +		gpio-controller;
> +		#gpio-cells = <2>;
> +		interrupt-controller;
> +		#interrupt-cells = <2>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&tca6416_u21_int_pins>;
> +		interrupts-extended = <&gpio1 15 IRQ_TYPE_EDGE_FALLING>;
> +		gpio-line-names = "TCA_SPI_TPM/EXT", "TCA_TPM_RST#",
> +				  "TCA_I2C_RST", "TCA_RS232_SHTD#",
> +				  "TCA_LCD_I2C_RST", "TCA_DIG_OUT1",
> +				  "TCA_bDIG_IN1", "TCA_SENS_INT",
> +				  "TCA_ALERT#", "TCA_TPM_PIRQ#",
> +				  "TCA_RTC_INT", "TCA_M.2M_WAKW_ON_LAN",
> +				  "TCA_M.2M_CLKREQ#", "TCA_LVDS_INT#",
> +				  "", "TCA_POE_AT";
> +
> +		rs232_shutdown: rs232-shutdown-hog {
> +			gpio-hog;
> +			gpios = <3 GPIO_ACTIVE_LOW>;
> +			output-low;
> +			line-name = "rs232-shutdown";
> +		};
> +
> +		lcd-i2c-reset-hog {
> +			/*
> +			 * reset shared between U37 and U48, to be
> +			 * supported once gpio-pca953x switches to
> +			 * reset framework.
> +			 */
> +			gpio-hog;
> +			gpios = <4 (GPIO_ACTIVE_LOW|GPIO_PULL_UP|GPIO_OPEN_DRAIN)>;
> +			output-low;
> +			line-name = "lcd-i2c-reset";
> +		};
> +
> +		m2-m-clkreq-hog {
> +			gpio-hog;
> +			gpios = <12 GPIO_ACTIVE_LOW>;
> +			input;
> +			line-name = "m2-m-clkreq";
> +		};
> +	};
> +
> +	led-controller at 30 {
> +		compatible = "ti,lp5562";
> +		reg = <0x30>;
> +		/* use internal clock, could use external generated by rtc */
> +		clock-mode = /bits/ 8 <1>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		multi-led at 0 {
> +			reg = <0x0>;
> +			label = "D7";
> +			color = <LED_COLOR_ID_RGB>;
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +
> +			led at 0 {
> +				reg = <0x0>;
> +				color = <LED_COLOR_ID_RED>;
> +				led-cur = /bits/ 8 <0x32>;
> +				max-cur = /bits/ 8 <0x64>;
> +			};
> +
> +			led at 1 {
> +				reg = <0x1>;
> +				color = <LED_COLOR_ID_GREEN>;
> +				led-cur = /bits/ 8 <0x19>;
> +				max-cur = /bits/ 8 <0x32>;
> +			};
> +
> +			led at 2 {
> +				reg = <0x2>;
> +				color = <LED_COLOR_ID_BLUE>;
> +				led-cur = /bits/ 8 <0x19>;
> +				max-cur = /bits/ 8 <0x32>;
> +			};
> +		};
> +
> +		led at 3 {
> +			reg = <3>;

0x3 to be consistent?

Shawn

> +			chan-name = "D8";
> +			label = "D8";
> +			color = <LED_COLOR_ID_GREEN>;
> +			led-cur = /bits/ 8 <0x19>;
> +			max-cur = /bits/ 8 <0x64>;
> +		};
> +	};
> +
> +	light-sensor at 44 {
> +		compatible = "isil,isl29023";
> +		reg = <0x44>;
> +		/* IRQ shared between accelerometer, light-sensor and Tamper input (J5007) */
> +		interrupts-extended = <&tca6416_u21 7 IRQ_TYPE_EDGE_FALLING>;
> +	};
> +
> +	accelerometer at 53 {
> +		compatible = "adi,adxl345";
> +		reg = <0x53>;
> +		/* IRQ shared between accelerometer, light-sensor and Tamper input (J5007) */
> +		interrupt-names = "INT1";
> +		interrupts-extended = <&tca6416_u21 7 IRQ_TYPE_EDGE_FALLING>;
> +	};
> +
> +	carrier_eeprom: eeprom at 57{
> +		compatible = "atmel,24c02";
> +		reg = <0x57>;
> +		pagesize = <8>;
> +	};
> +
> +	carrier_rtc: rtc at 69 {
> +		compatible = "abracon,ab1805";
> +		reg = <0x69>;
> +		abracon,tc-diode = "schottky";
> +		abracon,tc-resistor = <3>;
> +		/*
> +		 * AM1805 RTC used on this board has only nTIRQ pins wired,
> +		 * which is for countdown timer irqs only.
> +		 * Driver does not support this, disable for now.
> +		 *
> +		 * interrupts-extended = <&tca6416_u21 10 IRQ_TYPE_EDGE_FALLING>;
> +		 */
> +	};
> +};
> +
> +&iomuxc {
> +	can1_pins: pinctrl-can1-grp {
> +		fsl,pins = <
> +			MX8MP_IOMUXC_SPDIF_RX__CAN1_RX			0x154
> +			MX8MP_IOMUXC_SPDIF_TX__CAN1_TX			0x154
> +		>;
> +	};
> +
> +	can2_pins: pinctrl-can2-grp {
> +		fsl,pins = <
> +			MX8MP_IOMUXC_SAI5_MCLK__CAN2_RX			0x154
> +			MX8MP_IOMUXC_SAI5_RXD3__CAN2_TX			0x154
> +		>;
> +	};
> +
> +	ecspi2_pins: pinctrl-ecspi2-grp {
> +		fsl,pins = <
> +			MX8MP_IOMUXC_ECSPI2_SCLK__ECSPI2_SCLK		0x140
> +			MX8MP_IOMUXC_ECSPI2_MOSI__ECSPI2_MOSI		0x140
> +			MX8MP_IOMUXC_ECSPI2_MISO__ECSPI2_MISO		0x140
> +			MX8MP_IOMUXC_ECSPI2_SS0__GPIO5_IO13		0x140
> +		>;
> +	};
> +
> +	tca6416_u21_int_pins: pinctrl-tca6416-u21-int-grp {
> +		fsl,pins = <
> +			MX8MP_IOMUXC_GPIO1_IO15__GPIO1_IO15		0x0
> +		>;
> +	};
> +
> +	/* UARTA */
> +	uart3_pins: pinctrl-uart3-grp {
> +		fsl,pins = <
> +			MX8MP_IOMUXC_ECSPI1_SCLK__UART3_DCE_RX		0x140
> +			MX8MP_IOMUXC_ECSPI1_MOSI__UART3_DCE_TX		0x140
> +			MX8MP_IOMUXC_ECSPI1_SS0__GPIO5_IO09		0x140
> +		>;
> +	};
> +
> +	/* UARTB */
> +	uart4_pins: pinctrl-uart4-grp {
> +		fsl,pins = <
> +			MX8MP_IOMUXC_UART4_RXD__UART4_DCE_RX		0x140
> +			MX8MP_IOMUXC_UART4_TXD__UART4_DCE_TX		0x140
> +			MX8MP_IOMUXC_ECSPI1_MISO__GPIO5_IO08		0x140
> +		>;
> +	};
> +
> +	usdhc2_pins: pinctrl-usdhc2-grp {
> +		fsl,pins = <
> +			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK		0x190
> +			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD		0x1d0
> +			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0		0x1d0
> +			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1		0x1d0
> +			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2		0x1d0
> +			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3		0x1d0
> +			MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT		0x140
> +			MX8MP_IOMUXC_SD2_CD_B__USDHC2_CD_B		0x140
> +		>;
> +	};
> +
> +	usdhc2_100mhz_pins: pinctrl-usdhc2-100mhz-grp {
> +		fsl,pins = <
> +			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK		0x194
> +			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD		0x1d4
> +			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0		0x1d4
> +			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1		0x1d4
> +			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2		0x1d4
> +			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3		0x1d4
> +			MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT		0x140
> +			MX8MP_IOMUXC_SD2_CD_B__USDHC2_CD_B		0x140
> +		>;
> +	};
> +
> +	usdhc2_200mhz_pins: pinctrl-usdhc2-200mhz-grp {
> +		fsl,pins = <
> +			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK		0x196
> +			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD		0x1d6
> +			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0		0x1d6
> +			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1		0x1d6
> +			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2		0x1d6
> +			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3		0x1d6
> +			MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT		0x140
> +			MX8MP_IOMUXC_SD2_CD_B__USDHC2_CD_B		0x140
> +		>;
> +	};
> +
> +	vmmc_pins: pinctrl-vmmc-grp {
> +		fsl,pins = <
> +			MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19		0x0
> +		>;
> +	};
> +};
> +
> +&pcie {
> +	reset-gpio = <&tca6416_u20 7 GPIO_ACTIVE_LOW>;
> +	status = "okay";
> +};
> +
> +/* M.2 M-Key (J4) */
> +&pcie_phy {
> +	clocks = <&hsio_blk_ctrl>;
> +	clock-names = "ref";
> +	fsl,clkreq-unsupported;
> +	fsl,refclk-pad-mode = <IMX8_PCIE_REFCLK_PAD_OUTPUT>;
> +	status = "okay";
> +};
> +
> +&phy0 {
> +	leds {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		/* ADIN1300 LED_0 pin */
> +		led at 0 {
> +			reg = <0>;
> +			color = <LED_COLOR_ID_GREEN>;
> +			function = LED_FUNCTION_LAN;
> +			default-state = "keep";
> +		};
> +	};
> +};
> +
> +&phy1 {
> +	leds {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		/* ADIN1300 LED_0 pin */
> +		led at 0 {
> +			reg = <0>;
> +			color = <LED_COLOR_ID_GREEN>;
> +			function = LED_FUNCTION_LAN;
> +			default-state = "keep";
> +		};
> +	};
> +};
> +
> +&uart3 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&uart3_pins>;
> +	rts-gpios = <&gpio5 9 GPIO_ACTIVE_HIGH>;
> +	/* select 80MHz parent clock to support maximum baudrate 4Mbps */
> +	assigned-clocks = <&clk IMX8MP_CLK_UART3>;
> +	assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_80M>;
> +	status = "okay";
> +};
> +
> +&uart4 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&uart4_pins>;
> +	rts-gpios = <&gpio5 8 GPIO_ACTIVE_HIGH>;
> +	/* select 80MHz parent clock to support maximum baudrate 4Mbps */
> +	assigned-clocks = <&clk IMX8MP_CLK_UART4>;
> +	assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_80M>;
> +	status = "okay";
> +};
> +
> +&usb3_phy0 {
> +	fsl,phy-tx-preemp-amp-tune-microamp = <1200>;
> +	vbus-supply = <&vbus1>;
> +	status = "okay";
> +};
> +
> +&usb3_0 {
> +	status = "okay";
> +};
> +
> +&usb3_phy1 {
> +	status = "okay";
> +};
> +
> +&usb3_1 {
> +	status = "okay";
> +};
> +
> +&usb_dwc3_0 {
> +	dr_mode = "host";
> +};
> +
> +&usb_dwc3_1 {
> +	dr_mode = "host";
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +
> +	hub_2_0: hub at 1 {
> +		compatible = "usb4b4,6502", "usb4b4,6506";
> +		reg = <1>;
> +		peer-hub = <&hub_3_0>;
> +		reset-gpios = <&tca6416_u20 11 GPIO_ACTIVE_LOW>;
> +		vdd-supply = <&v_1_2>;
> +		vdd2-supply = <&v_3_3>;
> +	};
> +
> +	hub_3_0: hub at 2 {
> +		compatible = "usb4b4,6500", "usb4b4,6504";
> +		reg = <2>;
> +		peer-hub = <&hub_2_0>;
> +		reset-gpios = <&tca6416_u20 11 GPIO_ACTIVE_LOW>;
> +		vdd-supply = <&v_1_2>;
> +		vdd2-supply = <&v_3_3>;
> +	};
> +};
> +
> +&usdhc2 {
> +	pinctrl-names = "default", "state_100mhz", "state_200mhz";
> +	pinctrl-0 = <&usdhc2_pins>;
> +	pinctrl-1 = <&usdhc2_100mhz_pins>;
> +	pinctrl-2 = <&usdhc2_200mhz_pins>;
> +	vmmc-supply = <&vmmc>;
> +	bus-width = <4>;
> +	cap-power-off-card;
> +	full-pwr-cycle;
> +	status = "okay";
> +};
> 
> -- 
> 2.51.0
> 
> 


From shawnguo at kernel.org  Tue Dec 30 04:55:11 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 20:55:11 +0800
Subject: [PATCH v5 7/7] arm64: dts: add description for solidrun i.mx8mm
 som and evb
In-Reply-To: <20251221-imx8mp-hb-iiot-v5-7-4a4dad916348@solid-run.com>
References: <20251221-imx8mp-hb-iiot-v5-0-4a4dad916348@solid-run.com>
 <20251221-imx8mp-hb-iiot-v5-7-4a4dad916348@solid-run.com>
Message-ID: <aVPLr8ByUwrnda_Y@dragon>

On Sun, Dec 21, 2025 at 12:28:56PM +0100, Josua Mayer wrote:
> Add description for the SolidRun i.MX8M Mini SoM on HummingBoard Ripple.
> 
> The SoM features:
> - 1Gbps Ethernet with PHY
> - eMMC
> - 1/2GB DDR
> - NPU (assembly option)
> - WiFi + Bluetooth
> 
> The HummingBoard Ripple features:
> - 2x USB-2.0 Type-A connector
> - 1Gbps RJ45 Ethernet with PoE
> - microSD connector
> - microHDMI connector
> - mpcie connector with USB-2.0 interface + SIM card holder
> - microUSB connector for console (using fdtdi chip)
> - RTC with backup battery
> 
> Signed-off-by: Josua Mayer <josua at solid-run.com>
> ---
>  arch/arm64/boot/dts/freescale/Makefile             |   2 +
>  .../dts/freescale/imx8mm-hummingboard-ripple.dts   | 335 ++++++++++++++++++
>  arch/arm64/boot/dts/freescale/imx8mm-sr-som.dtsi   | 394 +++++++++++++++++++++
>  3 files changed, 731 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
> index 73c3d234149cd..6be7de1f0e1c4 100644
> --- a/arch/arm64/boot/dts/freescale/Makefile
> +++ b/arch/arm64/boot/dts/freescale/Makefile
> @@ -124,6 +124,8 @@ imx8mm-evk-pcie-ep-dtbs += imx8mm-evk.dtb imx-pcie0-ep.dtbo
>  imx8mm-evkb-pcie-ep-dtbs += imx8mm-evkb.dtb imx-pcie0-ep.dtbo
>  dtb-$(CONFIG_ARCH_MXC) += imx8mm-evk-pcie-ep.dtb imx8mm-evkb-pcie-ep.dtb
>  
> +dtb-$(CONFIG_ARCH_MXC) += imx8mm-hummingboard-ripple.dtb
> +DTC_FLAGS_imx8mm-hummingboard-ripple += -@
>  dtb-$(CONFIG_ARCH_MXC) += imx8mm-icore-mx8mm-ctouch2.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx8mm-icore-mx8mm-edimm2.2.dtb
>  dtb-$(CONFIG_ARCH_MXC) += imx8mm-iot-gateway.dtb
> diff --git a/arch/arm64/boot/dts/freescale/imx8mm-hummingboard-ripple.dts b/arch/arm64/boot/dts/freescale/imx8mm-hummingboard-ripple.dts
> new file mode 100644
> index 0000000000000..110e7ff1ff135
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx8mm-hummingboard-ripple.dts
> @@ -0,0 +1,335 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright 2025 Josua Mayer <josua at solid-run.com>
> + */
> +
> +/dts-v1/;
> +
> +#include <dt-bindings/leds/common.h>
> +
> +#include "imx8mm-sr-som.dtsi"
> +
> +/ {
> +	model = "SolidRun i.MX8MM HummingBoard Ripple";
> +	compatible = "solidrun,imx8mm-hummingboard-ripple",
> +		     "solidrun,imx8mm-sr-som", "fsl,imx8mm";
> +
> +	aliases {
> +		rtc0 = &carrier_rtc;
> +		rtc1 = &snvs_rtc;
> +	};
> +
> +	hdmi-connector {
> +		compatible = "hdmi-connector";
> +		label = "hdmi";
> +		type = "c";
> +
> +		port {
> +			hdmi_connector_in: endpoint {
> +				remote-endpoint = <&adv7535_out>;
> +			};
> +		};
> +	};
> +
> +	leds {
> +		compatible = "gpio-leds";
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&led_pins>;
> +
> +		led-0 {
> +			label = "D30";
> +			color = <LED_COLOR_ID_GREEN>;
> +			gpios = <&gpio5 29 GPIO_ACTIVE_LOW>;
> +			default-state = "on";
> +		};
> +
> +		led-1 {
> +			label = "D31";
> +			color = <LED_COLOR_ID_GREEN>;
> +			gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
> +			default-state = "on";
> +		};
> +
> +		led-2 {
> +			label = "D32";
> +			color = <LED_COLOR_ID_GREEN>;
> +			gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
> +			default-state = "on";
> +		};
> +
> +		led-3 {
> +			label = "D33";
> +			color = <LED_COLOR_ID_GREEN>;
> +			gpios = <&gpio5 7 GPIO_ACTIVE_LOW>;
> +			default-state = "on";
> +		};
> +
> +		led-4 {
> +			label = "D34";
> +			color = <LED_COLOR_ID_GREEN>;
> +			gpios = <&gpio5 6 GPIO_ACTIVE_LOW>;
> +			default-state = "on";
> +		};
> +	};
> +
> +	rfkill-mpcie-wifi {
> +		compatible = "rfkill-gpio";
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&pcie_rfkill_pins>;
> +		label = "mpcie WiFi";
> +		radio-type = "wlan";
> +		/* rfkill-gpio inverts internally */
> +		shutdown-gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>;
> +	};
> +
> +	vmmc: regulator-mmc {
> +		compatible = "regulator-fixed";
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&vmmc_pins>;
> +		regulator-name = "vmmc";
> +		regulator-min-microvolt = <3300000>;
> +		regulator-max-microvolt = <3300000>;
> +		gpio = <&gpio2 19 GPIO_ACTIVE_LOW>;
> +		startup-delay-us = <250>;
> +	};
> +
> +	vbus1: regulator-vbus-1 {
> +		compatible = "regulator-fixed";
> +		regulator-name = "vbus1";
> +		gpio = <&gpio2 11 GPIO_ACTIVE_HIGH>;
> +		enable-active-high;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&vbus1_pins>;
> +		regulator-min-microvolt = <5000000>;
> +		regulator-max-microvolt = <5000000>;
> +	};
> +
> +	vbus2: regulator-vbus-2 {
> +		compatible = "regulator-fixed";
> +		regulator-name = "vbus2";
> +		gpio = <&gpio4 21 GPIO_ACTIVE_HIGH>;
> +		enable-active-high;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&vbus2_pins>;
> +		regulator-min-microvolt = <5000000>;
> +		regulator-max-microvolt = <5000000>;
> +	};
> +
> +	v_1_2: regulator-1-2 {
> +		compatible = "regulator-fixed";
> +		regulator-name = "1v2";
> +		regulator-min-microvolt = <1200000>;
> +		regulator-max-microvolt = <1200000>;
> +	};
> +};
> +
> +&i2c3 {
> +	clock-frequency = <100000>;
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&i2c3_pins>;
> +	status = "okay";
> +
> +	carrier_rtc: rtc at 69 {
> +		compatible = "abracon,ab1805";
> +		reg = <0x69>;
> +		abracon,tc-diode = "schottky";
> +		abracon,tc-resistor = <3>;
> +	};
> +
> +	carrier_eeprom: eeprom at 57{

Sort I2C devices in order of slave/unit address.

> +		compatible = "st,24c02", "atmel,24c02";
> +		reg = <0x57>;
> +		pagesize = <16>;
> +	};
> +
> +	hdmi at 3d {
> +		compatible = "adi,adv7535";
> +		reg = <0x3d>, <0x3f>, <0x3c>, <0x38>;
> +		reg-names = "main", "edid", "cec", "packet";
> +		adi,dsi-lanes = <4>;
> +		avdd-supply = <&v_1_8>;
> +		dvdd-supply = <&v_1_8>;
> +		pvdd-supply = <&v_1_8>;
> +		a2vdd-supply = <&v_1_8>;
> +		v3p3-supply = <&v_3_3>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&hdmi_pins>;
> +		interrupt-parent = <&gpio1>;
> +		interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
> +		pd-gpios = <&gpio3 22 GPIO_ACTIVE_LOW>;
> +
> +		ports {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +
> +			port at 0 {
> +				reg = <0>;
> +
> +				adv7535_from_dsim: endpoint {
> +					remote-endpoint = <&mipi_dsi_out>;
> +				};
> +			};
> +
> +			port at 1 {
> +				reg = <1>;
> +
> +				adv7535_out: endpoint {
> +					remote-endpoint = <&hdmi_connector_in>;
> +				};
> +			};
> +		};
> +	};
> +};
> +
> +&iomuxc {
> +	hdmi_pins: pinctrl-hdmi-grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_GPIO1_IO07_GPIO1_IO7	0x0
> +			MX8MM_IOMUXC_SAI5_RXD1_GPIO3_IO22	0x0
> +		>;
> +	};
> +
> +	i2c3_pins: pinctrl-i2c3-grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_I2C3_SCL_I2C3_SCL		0x400001c3
> +			MX8MM_IOMUXC_I2C3_SDA_I2C3_SDA		0x400001c3
> +		>;
> +	};
> +
> +	led_pins: pinctrl-led-grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_UART4_TXD_GPIO5_IO29	0x0
> +			MX8MM_IOMUXC_ECSPI1_SS0_GPIO5_IO9	0x0
> +			MX8MM_IOMUXC_ECSPI1_MISO_GPIO5_IO8	0x0
> +			MX8MM_IOMUXC_ECSPI1_MOSI_GPIO5_IO7	0x0
> +			MX8MM_IOMUXC_ECSPI1_SCLK_GPIO5_IO6	0x0
> +		>;
> +	};
> +
> +	pcie_rfkill_pins: pinctrl-pcie-rfkill-grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_SD2_WP_GPIO2_IO20		0x0
> +		>;
> +	};
> +
> +	usb_hub_pins: pinctrl-usb-hub-grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_SAI3_RXD_GPIO4_IO30	0x0
> +		>;
> +	};
> +
> +	usdhc2_pins: pinctrl-usdhc2-grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK		0x190
> +			MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d0
> +			MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d0
> +			MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d0
> +			MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d0
> +			MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d0
> +			MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x140
> +			MX8MM_IOMUXC_SD2_CD_B_USDHC2_CD_B	0x0
> +		>;
> +	};
> +
> +	usdhc2_100mhz_pins: pinctrl-usdhc2-100mhz-grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK		0x194
> +			MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d4
> +			MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d4
> +			MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d4
> +			MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d4
> +			MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d4
> +			MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x140
> +			MX8MM_IOMUXC_SD2_CD_B_USDHC2_CD_B	0x0
> +		>;
> +	};
> +
> +	usdhc2_200mhz_pins: pinctrl-usdhc2-100mhz-grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK		0x196
> +			MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d6
> +			MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d6
> +			MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d6
> +			MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d6
> +			MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d6
> +			MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x140
> +			MX8MM_IOMUXC_SD2_CD_B_USDHC2_CD_B	0x0
> +		>;
> +	};
> +
> +	vbus1_pins: pinctrl-vbus-1-grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_SD1_STROBE_GPIO2_IO11	0x20
> +		>;
> +	};
> +
> +	vbus2_pins: pinctrl-vbus-2-grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_SAI2_RXFS_GPIO4_IO21	0x20
> +		>;
> +	};
> +
> +	vmmc_pins: pinctrl-vmmc-grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_SD2_RESET_B_GPIO2_IO19	0x41
> +		>;
> +	};
> +};
> +
> +&lcdif {
> +	status = "okay";
> +};
> +
> +&mipi_dsi {
> +	samsung,esc-clock-frequency = <10000000>;
> +	status = "okay";
> +};
> +
> +&mipi_dsi_out {
> +	remote-endpoint = <&adv7535_from_dsim>;
> +};
> +
> +&usbotg1 {
> +	dr_mode = "host";
> +	vbus-supply = <&vbus2>;
> +	status = "okay";
> +};
> +
> +&usbotg2 {
> +	status = "okay";
> +	dr_mode = "host";
> +	vbus-supply = <&vbus1>;
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&usb_hub_pins>;
> +
> +	hub_2_0: hub at 1 {
> +		compatible = "usb4b4,6502", "usb4b4,6506";
> +		reg = <1>;
> +		peer-hub = <&hub_3_0>;
> +		reset-gpios = <&gpio4 30 GPIO_ACTIVE_LOW>;
> +		vdd-supply = <&v_1_2>;
> +		vdd2-supply = <&v_3_3>;
> +	};
> +
> +	/* this device is not visible because host supports 2.0 only */
> +	hub_3_0: hub at 2 {
> +		compatible = "usb4b4,6500", "usb4b4,6504";
> +		reg = <2>;
> +		peer-hub = <&hub_2_0>;
> +		reset-gpios = <&gpio4 30 GPIO_ACTIVE_LOW>;
> +		vdd-supply = <&v_1_2>;
> +		vdd2-supply = <&v_3_3>;
> +	};
> +};
> +
> +&usdhc2 {
> +	pinctrl-names = "default", "state_100mhz", "state_200mhz";
> +	pinctrl-0 = <&usdhc2_pins>;
> +	pinctrl-1 = <&usdhc2_100mhz_pins>;
> +	pinctrl-2 = <&usdhc2_200mhz_pins>;
> +	vmmc-supply = <&vmmc>;
> +	bus-width = <4>;
> +	status = "okay";
> +};
> diff --git a/arch/arm64/boot/dts/freescale/imx8mm-sr-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-sr-som.dtsi
> new file mode 100644
> index 0000000000000..0bc1b6fa8e994
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx8mm-sr-som.dtsi
> @@ -0,0 +1,394 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright 2025 Josua Mayer <josua at solid-run.com>
> + */
> +
> +#include <dt-bindings/phy/phy-imx8-pcie.h>
> +
> +#include "imx8mm.dtsi"
> +
> +/ {
> +	model = "SolidRun i.MX8MM SoM";
> +	compatible = "solidrun,imx8mm-sr-som", "fsl,imx8mm";
> +
> +	chosen {
> +		bootargs = "earlycon=ec_imx6q,0x30890000,115200";
> +		stdout-path = &uart2;
> +	};
> +
> +	memory at 40000000 {
> +		device_type = "memory";
> +		reg = <0x0 0x40000000 0 0x80000000>;
> +	};
> +
> +	usdhc1_pwrseq: usdhc1-pwrseq {
> +		compatible = "mmc-pwrseq-simple";
> +		reset-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>;
> +	};
> +
> +	v_1_8: regulator-1-8 {
> +		compatible = "regulator-fixed";
> +		regulator-name = "1v8";
> +		regulator-min-microvolt = <1800000>;
> +		regulator-max-microvolt = <1800000>;
> +	};
> +
> +	v_3_3: regulator-3-3 {
> +		compatible = "regulator-fixed";
> +		regulator-name = "3v3";
> +		regulator-min-microvolt = <3300000>;
> +		regulator-max-microvolt = <3300000>;
> +	};
> +};
> +
> +&fec1 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&fec1_pins>;
> +	phy-mode = "rgmii-id";
> +	phy = <&phy0>;
> +	status = "okay";
> +
> +	mdio {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		phy0: ethernet-phy at 4 {
> +			compatible = "ethernet-phy-ieee802.3-c22";
> +			reg = <0x4>;
> +			reset-gpios = <&gpio4 22 GPIO_ACTIVE_LOW>;
> +			phy-reset-duration = <10>;
> +			qca,smarteee-tw-us-1g = <24>;
> +			vddio-supply = <&vddio>;
> +
> +			vddio: vddio-regulator {
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <1800000>;
> +			};
> +		};
> +	};
> +};
> +
> +&i2c1 {
> +	clock-frequency = <400000>;
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&i2c1_pins>;
> +	status = "okay";
> +
> +	som_eeprom: eeprom at 50{
> +		compatible = "st,24c01", "atmel,24c01";
> +		reg = <0x50>;
> +		pagesize = <16>;
> +	};
> +
> +	pmic at 4b {

Same here

> +		compatible = "rohm,bd71847";
> +		reg = <0x4b>;
> +		pinctrl-0 = <&pmic_pins>;
> +		pinctrl-names = "default";
> +		interrupt-parent = <&gpio1>;
> +		interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
> +		rohm,reset-snvs-powered;
> +

Nit: unnecessary newline

Shawn

> +		#clock-cells = <0>;
> +		clocks = <&osc_32k>;
> +		clock-output-names = "clk-32k-out";
> +
> +		regulators {
> +			buck1_reg: BUCK1 {
> +				regulator-name = "buck1";
> +				regulator-min-microvolt = <700000>;
> +				regulator-max-microvolt = <1300000>;
> +				regulator-boot-on;
> +				regulator-always-on;
> +				regulator-ramp-delay = <1250>;
> +			};
> +
> +			buck2_reg: BUCK2 {
> +				regulator-name = "buck2";
> +				regulator-min-microvolt = <700000>;
> +				regulator-max-microvolt = <1300000>;
> +				regulator-boot-on;
> +				regulator-always-on;
> +				regulator-ramp-delay = <1250>;
> +				rohm,dvs-run-voltage = <1000000>;
> +				rohm,dvs-idle-voltage = <900000>;
> +			};
> +
> +			buck3_reg: BUCK3 {
> +				// BUCK5 in datasheet
> +				regulator-name = "buck3";
> +				regulator-min-microvolt = <700000>;
> +				regulator-max-microvolt = <1350000>;
> +				regulator-boot-on;
> +				regulator-always-on;
> +			};
> +
> +			buck4_reg: BUCK4 {
> +				// BUCK6 in datasheet
> +				regulator-name = "buck4";
> +				regulator-min-microvolt = <3000000>;
> +				regulator-max-microvolt = <3300000>;
> +				regulator-boot-on;
> +				regulator-always-on;
> +			};
> +
> +			buck5_reg: BUCK5 {
> +				// BUCK7 in datasheet
> +				regulator-name = "buck5";
> +				regulator-min-microvolt = <1605000>;
> +				regulator-max-microvolt = <1995000>;
> +				regulator-boot-on;
> +				regulator-always-on;
> +			};
> +
> +			buck6_reg: BUCK6 {
> +				// BUCK8 in datasheet
> +				regulator-name = "buck6";
> +				regulator-min-microvolt = <800000>;
> +				regulator-max-microvolt = <1400000>;
> +				regulator-boot-on;
> +				regulator-always-on;
> +			};
> +
> +			ldo1_reg: LDO1 {
> +				regulator-name = "ldo1";
> +				regulator-min-microvolt = <1600000>;
> +				regulator-max-microvolt = <3300000>;
> +				regulator-boot-on;
> +				regulator-always-on;
> +			};
> +
> +			ldo2_reg: LDO2 {
> +				regulator-name = "ldo2";
> +				regulator-min-microvolt = <800000>;
> +				regulator-max-microvolt = <900000>;
> +				regulator-boot-on;
> +				regulator-always-on;
> +			};
> +
> +			ldo3_reg: LDO3 {
> +				regulator-name = "ldo3";
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <3300000>;
> +				regulator-boot-on;
> +				regulator-always-on;
> +			};
> +
> +			ldo4_reg: LDO4 {
> +				regulator-name = "ldo4";
> +				regulator-min-microvolt = <900000>;
> +				regulator-max-microvolt = <1800000>;
> +				regulator-boot-on;
> +				regulator-always-on;
> +			};
> +
> +			ldo6_reg: LDO6 {
> +				regulator-name = "ldo6";
> +				regulator-min-microvolt = <900000>;
> +				regulator-max-microvolt = <1800000>;
> +				regulator-boot-on;
> +				regulator-always-on;
> +			};
> +		};
> +	};
> +};
> +
> +&iomuxc {
> +	fec1_pins: pinctrl-fec1-grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_ENET_MDC_ENET1_MDC			0x3
> +			MX8MM_IOMUXC_ENET_MDIO_ENET1_MDIO		0x3
> +			MX8MM_IOMUXC_ENET_TD3_ENET1_RGMII_TD3		0x1f
> +			MX8MM_IOMUXC_ENET_TD2_ENET1_RGMII_TD2		0x1f
> +			MX8MM_IOMUXC_ENET_TD1_ENET1_RGMII_TD1		0x1f
> +			MX8MM_IOMUXC_ENET_TD0_ENET1_RGMII_TD0		0x1f
> +			MX8MM_IOMUXC_ENET_RD3_ENET1_RGMII_RD3		0x91
> +			MX8MM_IOMUXC_ENET_RD2_ENET1_RGMII_RD2		0x91
> +			MX8MM_IOMUXC_ENET_RD1_ENET1_RGMII_RD1		0x91
> +			MX8MM_IOMUXC_ENET_RD0_ENET1_RGMII_RD0		0x91
> +			MX8MM_IOMUXC_ENET_TXC_ENET1_RGMII_TXC		0x1f
> +			MX8MM_IOMUXC_ENET_RXC_ENET1_RGMII_RXC		0x91
> +			MX8MM_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x91
> +			MX8MM_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x1f
> +			MX8MM_IOMUXC_SAI2_RXC_GPIO4_IO22		0x19
> +		>;
> +	};
> +
> +	i2c1_pins: pinctrl-i2c1-grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_I2C1_SCL_I2C1_SCL			0x400001c3
> +			MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA			0x400001c3
> +		>;
> +	};
> +
> +	pcie_pins: pinctrl-pcie-grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_GPIO1_IO15_GPIO1_IO15		0x0
> +		>;
> +	};
> +
> +	pmic_pins: pinctrl-pmic-grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3		0x140
> +		>;
> +	};
> +
> +	uart1_pins: pinctrl-uart1-grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_UART1_RXD_UART1_DCE_RX	0x140
> +			MX8MM_IOMUXC_UART1_TXD_UART1_DCE_TX	0x140
> +			MX8MM_IOMUXC_UART3_RXD_UART1_DCE_CTS_B	0x140
> +			MX8MM_IOMUXC_UART3_TXD_UART1_DCE_RTS_B	0x140
> +			/* BT_REG_ON */
> +			MX8MM_IOMUXC_SD1_DATA4_GPIO2_IO6	0x0
> +			/* BT_WAKE_DEV */
> +			MX8MM_IOMUXC_SD1_DATA5_GPIO2_IO7	0x0
> +			/* BT_WAKE_HOST */
> +			MX8MM_IOMUXC_SD1_DATA6_GPIO2_IO8	0x100
> +		>;
> +	};
> +
> +	uart2_pins: pinctrl-uart2-grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_UART2_RXD_UART2_DCE_RX		0x140
> +			MX8MM_IOMUXC_UART2_TXD_UART2_DCE_TX		0x140
> +		>;
> +	};
> +
> +	usdhc1_pins: pinctrl-usdhc1-grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_SD1_CLK_USDHC1_CLK			0x190
> +			MX8MM_IOMUXC_SD1_CMD_USDHC1_CMD			0x1d0
> +			MX8MM_IOMUXC_SD1_DATA0_USDHC1_DATA0		0x1d0
> +			MX8MM_IOMUXC_SD1_DATA1_USDHC1_DATA1		0x1d0
> +			MX8MM_IOMUXC_SD1_DATA2_USDHC1_DATA2		0x1d0
> +			MX8MM_IOMUXC_SD1_DATA3_USDHC1_DATA3		0x1d0
> +			/* wifi refclk */
> +			MX8MM_IOMUXC_GPIO1_IO00_ANAMIX_REF_CLK_32K	0x0
> +			/* WL_REG_ON */
> +			MX8MM_IOMUXC_SD1_RESET_B_GPIO2_IO10		0x0
> +			/* WL_WAKE_HOST */
> +			MX8MM_IOMUXC_SD1_DATA7_GPIO2_IO9		0x100
> +		>;
> +	};
> +
> +	usdhc3_pins: pinctrl-usdhc3-grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK		0x190
> +			MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d0
> +			MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d0
> +			MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d0
> +			MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d0
> +			MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d0
> +			MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d0
> +			MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d0
> +			MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d0
> +			MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d0
> +			MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x190
> +		>;
> +	};
> +
> +	usdhc3_100mhz_pins: pinctrl-usdhc3-100mhz-grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK		0x194
> +			MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d4
> +			MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d4
> +			MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d4
> +			MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d4
> +			MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d4
> +			MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d4
> +			MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d4
> +			MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d4
> +			MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d4
> +			MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x194
> +		>;
> +	};
> +
> +	usdhc3_200mhz_pins: pinctrl-usdhc3-200mhz-grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK		0x196
> +			MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d6
> +			MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d6
> +			MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d6
> +			MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d6
> +			MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d6
> +			MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d6
> +			MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d6
> +			MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d6
> +			MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d6
> +			MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x196
> +		>;
> +	};
> +
> +	wdog1_pins: pinctrl-wdog1-grp {
> +		fsl,pins = <
> +			MX8MM_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B	0x140
> +		>;
> +	};
> +};
> +
> +&pcie_phy {
> +	fsl,clkreq-unsupported;
> +	fsl,refclk-pad-mode = <IMX8_PCIE_REFCLK_PAD_OUTPUT>;
> +	status = "okay";
> +};
> +
> +/* assembly-option for AI accelerator on SoM, otherwise routed to carrier */
> +&pcie0 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pcie_pins>;
> +	reset-gpios = <&gpio1 15 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>;
> +	status = "okay";
> +};
> +
> +&uart1 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&uart1_pins>;
> +	uart-has-rtscts;
> +	/* select 80MHz parent clock to support maximum baudrate 4Mbps */
> +	assigned-clocks = <&clk IMX8MM_CLK_UART1>;
> +	assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_80M>;
> +	status = "okay";
> +
> +	bluetooth {
> +		compatible = "brcm,bcm4330-bt";
> +		device-wakeup-gpios = <&gpio2 7 GPIO_ACTIVE_HIGH>;
> +		host-wakeup-gpios = <&gpio2 8 GPIO_ACTIVE_HIGH>;
> +		shutdown-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>;
> +		max-speed = <3000000>;
> +	};
> +};
> +
> +&uart2 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&uart2_pins>;
> +	status = "okay";
> +};
> +
> +&usdhc1 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&usdhc1_pins>;
> +	vmmc-supply = <&v_3_3>;
> +	vqmmc-supply = <&v_1_8>;
> +	bus-width = <4>;
> +	mmc-pwrseq = <&usdhc1_pwrseq>;
> +	status = "okay";
> +};
> +
> +&usdhc3 {
> +	pinctrl-names = "default", "state_100mhz", "state_200mhz";
> +	pinctrl-0 = <&usdhc3_pins>;
> +	pinctrl-1 = <&usdhc3_100mhz_pins>;
> +	pinctrl-2 = <&usdhc3_200mhz_pins>;
> +	vmmc-supply = <&v_3_3>;
> +	vqmmc-supply = <&v_1_8>;
> +	bus-width = <8>;
> +	non-removable;
> +	status = "okay";
> +};
> +
> +&wdog1 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&wdog1_pins>;
> +	status = "okay";
> +};
> 
> -- 
> 2.51.0
> 
> 


From shawnguo at kernel.org  Tue Dec 30 05:03:37 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 21:03:37 +0800
Subject: [PATCH v2 0/3] arm64: dts: Initial support for i.MX952
In-Reply-To: <20251222-imx952-v1-v2-0-8793ec8bad6e@nxp.com>
References: <20251222-imx952-v1-v2-0-8793ec8bad6e@nxp.com>
Message-ID: <aVPNqQtzz-C-bvCb@dragon>

On Mon, Dec 22, 2025 at 09:42:13AM +0800, Peng Fan (OSS) wrote:
> Peng Fan (3):
>       dt-bindings: arm: fsl: add i.MX952 EVK board
>       arm64: dts: freescale: Add initial device tree for i.MX952
>       arm64: dts: freescale: Add i.MX952 EVK basic device tree

Applied all, thanks!


From shawnguo at kernel.org  Tue Dec 30 05:07:11 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 21:07:11 +0800
Subject: [PATCH 1/2] arm64: dts: tqma8mpql-mba8mpxl: Configure multiple
 queues on eqos
In-Reply-To: <20251222081812.1120998-1-alexander.stein@ew.tq-group.com>
References: <20251222081812.1120998-1-alexander.stein@ew.tq-group.com>
Message-ID: <aVPOf2Ny7Zr0x0qa@dragon>

On Mon, Dec 22, 2025 at 09:18:08AM +0100, Alexander Stein wrote:
> The MBa8MPxL mainboard has an integrated PHY connected to the EQOS
> ethernet controller which can support up to five queues. Configure
> these queues in the same manor as done on the imx8mp-evk.
> Setting DMA to threas mode is necessary to prevent FIFO overflows, see
> commit 0bc3e333a0c82 ("arm64: dts: imx8mp-evk: configure multiple queues
> on eqos")
> 
> Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>

Doesn't seem to apply to my branch.

Shawn


From shawnguo at kernel.org  Tue Dec 30 05:09:59 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 21:09:59 +0800
Subject: [PATCH 0/2] Add xspi device node and mt35xu512aba spi nor device
 support on imx943-evk board
In-Reply-To: <20251223-imx943-xspi-dts-v1-0-7c18e5b4f97a@nxp.com>
References: <20251223-imx943-xspi-dts-v1-0-7c18e5b4f97a@nxp.com>
Message-ID: <aVPPJxWuJl74zoez@dragon>

On Tue, Dec 23, 2025 at 05:05:55PM +0800, Haibo Chen wrote:
> Haibo Chen (2):
>       arm64: dts: imx94: add xspi device node
>       arm64: dts: imx94: add mt35xu512aba spi nor support

Applied both, thanks!


From shawnguo at kernel.org  Tue Dec 30 05:12:23 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 21:12:23 +0800
Subject: [PATCH 1/3] arm64: dts: freescale: Use hyphen in node names
In-Reply-To: <20251223152624.155845-4-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251223152624.155845-4-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <aVPPtx-8Mg_lLLNE@dragon>

On Tue, Dec 23, 2025 at 04:26:25PM +0100, Krzysztof Kozlowski wrote:
> DTS coding style prefers hyphens instead of underscores in the node
> names.  Change should be safe, because node names are not considered an
> ABI.
> 
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Applied all, thanks!


From shawnguo at kernel.org  Tue Dec 30 05:16:32 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 21:16:32 +0800
Subject: [PATCH v1 0/4] arm64: dts: freescale: Add Apalis iMX8QP
In-Reply-To: <20251223162833.138286-1-francesco@dolcini.it>
References: <20251223162833.138286-1-francesco@dolcini.it>
Message-ID: <aVPQsKS5iERmmKG9@dragon>

On Tue, Dec 23, 2025 at 05:28:26PM +0100, Francesco Dolcini wrote:
> Francesco Dolcini (4):
>   dt-bindings: arm: fsl: Add Apalis iMX8QP
>   arm64: dts: imx8qm: Add CPU cluster labels
>   arm64: dts: freescale: Add NXP i.MX8QP SoC dtsi
>   arm64: dts: freescale: Add Apalis iMX8QP

Applied all, thanks!


From robert.marko at sartura.hr  Tue Dec 30 05:19:05 2025
From: robert.marko at sartura.hr (Robert Marko)
Date: Tue, 30 Dec 2025 14:19:05 +0100
Subject: [PATCH RESEND] dmaengine: at_xdmac: get the number of DMA
 channels from device tree
In-Reply-To: <aUF4OS4DsmRlQQt3@vaman>
References: <20251203121208.1269487-1-robert.marko@sartura.hr> <aUF4OS4DsmRlQQt3@vaman>
Message-ID: <CA+HBbNGv1YzZhBfAO7JvossJeM46CFcPmUtDmYaK4Fm8iB9stg@mail.gmail.com>

On Tue, Dec 16, 2025 at 4:18?PM Vinod Koul <vkoul at kernel.org> wrote:
>
> On 03-12-25, 13:11, Robert Marko wrote:
> > From: Tony Han <tony.han at microchip.com>
> >
> > In case of kernel runs in non-secure mode, the number of DMA channels can
> > be got from device tree since the value read from GTYPE register is "0" as
> > it's always secured.
> >
> > As the number of channels can never be negative, update them to the type
> > "unsigned".
> >
> > This is required for LAN969x.
>
> You updated the changelog, but tagged it as resend. It should be v2!

Hi,
Sorry for this, I sent the wrong patch and though quickly resending
the right one would be better.

>
> >
> > Signed-off-by: Tony Han <tony.han at microchip.com>
> > Signed-off-by: Robert Marko <robert.marko at sartura.hr>
> > ---
> >  drivers/dma/at_xdmac.c | 26 +++++++++++++++++++++++---
> >  1 file changed, 23 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
> > index 3fbc74710a13..acabf82e293c 100644
> > --- a/drivers/dma/at_xdmac.c
> > +++ b/drivers/dma/at_xdmac.c
> > @@ -2257,12 +2257,29 @@ static int __maybe_unused atmel_xdmac_runtime_resume(struct device *dev)
> >       return clk_enable(atxdmac->clk);
> >  }
> >
> > +static inline int at_xdmac_get_channel_number(struct platform_device *pdev,
> > +                                           u32 reg, u32 *pchannels)
> > +{
> > +     int     ret;
> > +
> > +     if (reg) {
> > +             *pchannels = AT_XDMAC_NB_CH(reg);
> > +             return 0;
> > +     }
> > +
> > +     ret = of_property_read_u32(pdev->dev.of_node, "dma-channels", pchannels);
> > +     if (ret)
> > +             dev_err(&pdev->dev, "can't get number of channels\n");
>
> Do we need to log error, I thought the API did that...

I dont think API helps here, we would just be left with the error
code, which can be hard
to trace back but I am flexible.

Regards,
Robert
>
> > +
> > +     return ret;
> > +}
> > +
> >  static int at_xdmac_probe(struct platform_device *pdev)
> >  {
> >       struct at_xdmac *atxdmac;
> > -     int             irq, nr_channels, i, ret;
> > +     int             irq, ret;
> >       void __iomem    *base;
> > -     u32             reg;
> > +     u32             nr_channels, i, reg;
> >
> >       irq = platform_get_irq(pdev, 0);
> >       if (irq < 0)
> > @@ -2278,7 +2295,10 @@ static int at_xdmac_probe(struct platform_device *pdev)
> >        * of channels to do the allocation.
> >        */
> >       reg = readl_relaxed(base + AT_XDMAC_GTYPE);
> > -     nr_channels = AT_XDMAC_NB_CH(reg);
> > +     ret = at_xdmac_get_channel_number(pdev, reg, &nr_channels);
> > +     if (ret)
> > +             return ret;
> > +
> >       if (nr_channels > AT_XDMAC_MAX_CHAN) {
> >               dev_err(&pdev->dev, "invalid number of channels (%u)\n",
> >                       nr_channels);
> > --
> > 2.52.0
>
> --
> ~Vinod



-- 
Robert Marko
Staff Embedded Linux Engineer
Sartura d.d.
Lendavska ulica 16a
10000 Zagreb, Croatia
Email: robert.marko at sartura.hr
Web: www.sartura.hr


From alchark at gmail.com  Tue Dec 30 05:23:34 2025
From: alchark at gmail.com (Alexey Charkov)
Date: Tue, 30 Dec 2025 17:23:34 +0400
Subject: [PATCH v3] arm64: dts: rockchip: enable UFS controller on
 FriendlyElec NanoPi M5
Message-ID: <20251230-nanopi-m5-ufs-v3-1-ed188ae34fdb@gmail.com>

The NanoPi M5 board supports pluggable UFS modules using the UFSHC
inside its Rockchip RK3576 SoC.

Enable the respective devicetree node and add its supply regulators.

Link: https://wiki.friendlyelec.com/wiki/images/9/97/NanoPi_M5_LP5_2411_SCH.pdf
Signed-off-by: Alexey Charkov <alchark at gmail.com>
---
Changes in v3:
- Dropped 'en-supply' from fixed regulators, as it's not envisaged by the
  fixed regulator driver and seems like more trouble than its worth
- Link to v2: https://lore.kernel.org/r/20251201-nanopi-m5-ufs-v2-1-ece9c0ee17c4 at gmail.com

Changes in v2:
- Describe UFS supply regulators
- Add link to schematic
- Link to v1: https://lore.kernel.org/r/20251127-nanopi-m5-ufs-v1-1-0d28d157712c at gmail.com
---
 arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts | 25 +++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts b/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts
index cce34c541f7c..c5b34069a443 100644
--- a/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts
@@ -110,6 +110,22 @@ vcc12v_dcin: regulator-vcc12v-dcin {
 		regulator-name = "vcc12v_dcin";
 	};
 
+	vcc1v2_ufs_vccq: regulator-vcc1v2-ufs-vccq {
+		compatible = "regulator-fixed";
+		regulator-min-microvolt = <1200000>;
+		regulator-max-microvolt = <1200000>;
+		regulator-name = "vcc1v2_ufs_vccq";
+		vin-supply = <&vcc5v0_sys_s5>;
+	};
+
+	vcc1v8_ufs_vccq2: regulator-vcc1v8-ufs-vccq2 {
+		compatible = "regulator-fixed";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-name = "vcc1v8_ufs_vccq2";
+		vin-supply = <&vcc_1v8_s3>;
+	};
+
 	vcc3v3_m2_keym: regulator-vcc3v3-m2-keym {
 		compatible = "regulator-fixed";
 		enable-active-high;
@@ -906,6 +922,15 @@ &uart0 {
 	status = "okay";
 };
 
+&ufshc {
+	vcc-supply = <&vcc_3v3_s3>;
+	vccq-supply = <&vcc1v2_ufs_vccq>;
+	vccq2-supply = <&vcc1v8_ufs_vccq2>;
+	vdd-hba-supply = <&vdda_1v2_s0>;
+
+	status = "okay";
+};
+
 &usbdp_phy {
 	status = "okay";
 };

---
base-commit: cc3aa43b44bdb43dfbac0fcb51c56594a11338a8
change-id: 20251127-nanopi-m5-ufs-52f2c5070167

Best regards,
-- 
Alexey Charkov <alchark at gmail.com>



From ulf.hansson at linaro.org  Tue Dec 30 05:39:12 2025
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Tue, 30 Dec 2025 14:39:12 +0100
Subject: [PATCH v4 1/3] media: v4l2-mem2mem: Add a kref to the
 v4l2_m2m_dev structure
In-Reply-To: <20251205015428.643-2-ming.qian@oss.nxp.com>
References: <20251205015428.643-1-ming.qian@oss.nxp.com> <20251205015428.643-2-ming.qian@oss.nxp.com>
Message-ID: <CAPDyKFpt-GL-RFcJ5mTWFqaRfy1dQJ7LL8OBCoQK0+zPDFEzsg@mail.gmail.com>

On Fri, 5 Dec 2025 at 02:55, <ming.qian at oss.nxp.com> wrote:
>
> From: Nicolas Dufresne <nicolas.dufresne at collabora.com>
>
> Adding a reference count to the v4l2_m2m_dev structure allow safely
> sharing it across multiple hardware nodes. This can be used to prevent
> running jobs concurrently on m2m cores that have some internal resource
> sharing.
>
> Signed-off-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
> Signed-off-by: Ming Qian <ming.qian at oss.nxp.com>

I certainly don't have the complete picture for how this needs to work.

However, I was thinking that rather than using a kref and having to
share two specific functions to update it (v4l2_m2m_get|put), couldn't
we just use a device-link instead?

Kind regards
Uffe

> ---
> v4
> - Add my Signed-off-by
>
>  drivers/media/v4l2-core/v4l2-mem2mem.c | 23 +++++++++++++++++++++++
>  include/media/v4l2-mem2mem.h           | 21 +++++++++++++++++++++
>  2 files changed, 44 insertions(+)
>
> diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c
> index fec93c1a9231..ae0de54d4c3e 100644
> --- a/drivers/media/v4l2-core/v4l2-mem2mem.c
> +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
> @@ -90,6 +90,7 @@ static const char * const m2m_entity_name[] = {
>   * @job_work:          worker to run queued jobs.
>   * @job_queue_flags:   flags of the queue status, %QUEUE_PAUSED.
>   * @m2m_ops:           driver callbacks
> + * @kref:              device reference count
>   */
>  struct v4l2_m2m_dev {
>         struct v4l2_m2m_ctx     *curr_ctx;
> @@ -109,6 +110,8 @@ struct v4l2_m2m_dev {
>         unsigned long           job_queue_flags;
>
>         const struct v4l2_m2m_ops *m2m_ops;
> +
> +       struct kref kref;
>  };
>
>  static struct v4l2_m2m_queue_ctx *get_queue_ctx(struct v4l2_m2m_ctx *m2m_ctx,
> @@ -1200,6 +1203,7 @@ struct v4l2_m2m_dev *v4l2_m2m_init(const struct v4l2_m2m_ops *m2m_ops)
>         INIT_LIST_HEAD(&m2m_dev->job_queue);
>         spin_lock_init(&m2m_dev->job_spinlock);
>         INIT_WORK(&m2m_dev->job_work, v4l2_m2m_device_run_work);
> +       kref_init(&m2m_dev->kref);
>
>         return m2m_dev;
>  }
> @@ -1211,6 +1215,25 @@ void v4l2_m2m_release(struct v4l2_m2m_dev *m2m_dev)
>  }
>  EXPORT_SYMBOL_GPL(v4l2_m2m_release);
>
> +void v4l2_m2m_get(struct v4l2_m2m_dev *m2m_dev)
> +{
> +       kref_get(&m2m_dev->kref);
> +}
> +EXPORT_SYMBOL_GPL(v4l2_m2m_get);
> +
> +static void v4l2_m2m_release_from_kref(struct kref *kref)
> +{
> +       struct v4l2_m2m_dev *m2m_dev = container_of(kref, struct v4l2_m2m_dev, kref);
> +
> +       v4l2_m2m_release(m2m_dev);
> +}
> +
> +void v4l2_m2m_put(struct v4l2_m2m_dev *m2m_dev)
> +{
> +       kref_put(&m2m_dev->kref, v4l2_m2m_release_from_kref);
> +}
> +EXPORT_SYMBOL_GPL(v4l2_m2m_put);
> +
>  struct v4l2_m2m_ctx *v4l2_m2m_ctx_init(struct v4l2_m2m_dev *m2m_dev,
>                 void *drv_priv,
>                 int (*queue_init)(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq))
> diff --git a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h
> index bf6a09a04dcf..ca295c660c7f 100644
> --- a/include/media/v4l2-mem2mem.h
> +++ b/include/media/v4l2-mem2mem.h
> @@ -547,6 +547,27 @@ v4l2_m2m_register_media_controller(struct v4l2_m2m_dev *m2m_dev,
>   */
>  void v4l2_m2m_release(struct v4l2_m2m_dev *m2m_dev);
>
> +/**
> + * v4l2_m2m_get() - take a reference to the m2m_dev structure
> + *
> + * @m2m_dev: opaque pointer to the internal data to handle M2M context
> + *
> + * This is used to share the M2M device across multiple devices. This
> + * can be used to avoid scheduling two hardware nodes concurrently.
> + */
> +void v4l2_m2m_get(struct v4l2_m2m_dev *m2m_dev);
> +
> +/**
> + * v4l2_m2m_put() - remove a reference to the m2m_dev structure
> + *
> + * @m2m_dev: opaque pointer to the internal data to handle M2M context
> + *
> + * Once the M2M device have no more references, v4l2_m2m_realse() will be
> + * called automatically. Users of this method should never call
> + * v4l2_m2m_release() directly. See v4l2_m2m_get() for more details.
> + */
> +void v4l2_m2m_put(struct v4l2_m2m_dev *m2m_dev);
> +
>  /**
>   * v4l2_m2m_ctx_init() - allocate and initialize a m2m context
>   *
> --
> 2.52.0
>


From ulf.hansson at linaro.org  Tue Dec 30 05:42:18 2025
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Tue, 30 Dec 2025 14:42:18 +0100
Subject: [PATCH v4 0/3] Fix concurrency issues between G1 and G2 on
In-Reply-To: <20251205015428.643-1-ming.qian@oss.nxp.com>
References: <20251205015428.643-1-ming.qian@oss.nxp.com>
Message-ID: <CAPDyKFpFm9kCSNbALJTqeyzFdg3OoooE2gUOXJcjv=WgQeZ84Q@mail.gmail.com>

On Fri, 5 Dec 2025 at 02:55, <ming.qian at oss.nxp.com> wrote:
>
> From: Ming Qian <ming.qian at oss.nxp.com>
>
> On the i.MX8MQ, we encountered some concurrency issues with H264 and HEVC
> decoding.
>
> There are two main reasons:
> 1. The vpu blk-ctrl don't have separate reset and clock enable bits.
> 2. The g1 VPU and g2 VPU cannot decode simultaneously.
>
> We attempted to make corresponding fix to address these two issues.
>
> Ming Qian (2):
>   pmdomain: imx8m-blk-ctrl: Remove separate rst and clk mask for 8mq vpu
>   media: verisilicon: Avoid G2 bus error while decoding H.264 and HEVC
>
> Nicolas Dufresne (1):
>   media: v4l2-mem2mem: Add a kref to the v4l2_m2m_dev structure
>
>  drivers/media/platform/verisilicon/hantro.h   |  2 +
>  .../media/platform/verisilicon/hantro_drv.c   | 42 +++++++++++++++++--
>  .../media/platform/verisilicon/imx8m_vpu_hw.c |  8 ++++
>  drivers/media/v4l2-core/v4l2-mem2mem.c        | 23 ++++++++++
>  drivers/pmdomain/imx/imx8m-blk-ctrl.c         | 11 +++--
>  include/media/v4l2-mem2mem.h                  | 21 ++++++++++
>  6 files changed, 100 insertions(+), 7 deletions(-)
>

Can I pick the pmdomain patch separately from the others? Or does this
need to go together?

Kind regards
Uffe


From shawnguo at kernel.org  Tue Dec 30 06:00:19 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 22:00:19 +0800
Subject: [PATCH] ARM: dts: imx: imx6sll: fix lcdif compatible
In-Reply-To: <20251223204302.519468-1-andreas@kemnade.info>
References: <20251223204302.519468-1-andreas@kemnade.info>
Message-ID: <aVPTJTMdMIif83r3@dragon>

On Tue, Dec 23, 2025 at 09:43:02PM +0100, Andreas Kemnade wrote:
> Fix lcdif compatible according to bindings doc.
> 
> dtbs_check tested only, a glance at the datasheet shows that it should be
> the correct fallback compatible.
> 
> Signed-off-by: Andreas Kemnade <andreas at kemnade.info>

Applied, thanks!


From shawnguo at kernel.org  Tue Dec 30 06:02:55 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 22:02:55 +0800
Subject: [PATCH 0/2] ARM: dts: imx: imx6sll-kobo-clara2e add JD9930
 regulator
In-Reply-To: <20251223-fp9931-clara2e-v1-0-e5b1cb79330a@kemnade.info>
References: <20251223-fp9931-clara2e-v1-0-e5b1cb79330a@kemnade.info>
Message-ID: <aVPbjxxXM4nJt9MS@dragon>

On Tue, Dec 23, 2025 at 10:34:01PM +0100, Andreas Kemnade wrote:
> Andreas Kemnade (2):
>       ARM: dts: imx: imx6sll-kobo-clara2e: add regulator for EPD.
>       ARM: imx_v6_v7_defconfig: enable EPD regulator needed for Kobo Clara 2e

Applied both, thanks!


From nfraprado at collabora.com  Tue Dec 30 06:03:00 2025
From: nfraprado at collabora.com (=?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?=)
Date: Tue, 30 Dec 2025 11:03:00 -0300
Subject: [PATCH RFC 0/6] AFBC fixes for MediaTek DRM
Message-ID: <20251230-mtk-afbc-fixes-v1-0-6c0247b66e32@collabora.com>

This series contains a handful of fixes for AFBC support on the MediaTek
DRM driver so that it can be re-enabled.

This is sent as an RFC because there are still some issues to work out
before the series can be merged:

1. Patch 4, 'drm/mediatek: ovl: Disallow AFBC buffers with width over
   1920' did not behave well when tested with Weston, so a better
   solution probably needs to be implemented before this can be merged.

2. Remaining AFBC issues:
   
   a. The first 4 pixel rows are always skipped in the displayed output,
      that is, the first displayed pixel, on the top-left corner,
      corresponds to 4x0. And below the end of the displayed output, the
      first 4x32 pixels are displayed.

   b. On some resolutions, there are still artifacts that look like
      misalignment issues, eg 1024x1080, 1080x1080.

   c. On some resolutions, no output at all is displayed, eg 1920x1080.

Tested on the MT8195-Tomato Chromebook.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
---
Ariel D'Alessandro (1):
      drm/mediatek: ovl: Fix misaligned layer source size on AFBC mode

N?colas F. R. A. Prado (5):
      drm/mediatek: plane: Remove extra block from AFBC data payload offset
      drm/mediatek: plane: Correct AFBC alignment definition to 128
      drm/mediatek: ovl: Disallow AFBC buffers with width over 1920
      drm/mediatek: ovl: Disable AFBC on MT8188
      drm/mediatek: Re-enable AFBC support on MediaTek DRM driver

 drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 59 ++++++++++++++++++++++++++++++---
 drivers/gpu/drm/mediatek/mtk_plane.c    | 48 +++++++++++++++++++++++++--
 drivers/gpu/drm/mediatek/mtk_plane.h    |  6 +++-
 3 files changed, 104 insertions(+), 9 deletions(-)
---
base-commit: 6f47c4646bee47319cc0980c693ed695c4cfd395
change-id: 20251229-mtk-afbc-fixes-b656f92bc2af

Best regards,
-- 
N?colas F. R. A. Prado <nfraprado at collabora.com>



From nfraprado at collabora.com  Tue Dec 30 06:03:01 2025
From: nfraprado at collabora.com (=?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?=)
Date: Tue, 30 Dec 2025 11:03:01 -0300
Subject: [PATCH RFC 1/6] drm/mediatek: plane: Remove extra block from AFBC
 data payload offset
In-Reply-To: <20251230-mtk-afbc-fixes-v1-0-6c0247b66e32@collabora.com>
References: <20251230-mtk-afbc-fixes-v1-0-6c0247b66e32@collabora.com>
Message-ID: <20251230-mtk-afbc-fixes-v1-1-6c0247b66e32@collabora.com>

The AFBC data payload is in fact not offset by 1 additional block as the
code and comment suggest, and this causes the buffer to be rendered
offset by one block. Remove this extraneous offset to get the buffer
correctly displayed.

Fixes: c410fa9b07c3 ("drm/mediatek: Add AFBC support to Mediatek DRM driver")
Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_plane.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_plane.c b/drivers/gpu/drm/mediatek/mtk_plane.c
index 5043e0377270..1214f623859e 100644
--- a/drivers/gpu/drm/mediatek/mtk_plane.c
+++ b/drivers/gpu/drm/mediatek/mtk_plane.c
@@ -164,10 +164,9 @@ static void mtk_plane_update_new_state(struct drm_plane_state *new_state,
 		 */
 		hdr_addr = addr + hdr_offset;
 
-		/* The data plane is offset by 1 additional block. */
 		offset = pitch * y_offset_in_blocks +
 			 AFBC_DATA_BLOCK_WIDTH * AFBC_DATA_BLOCK_HEIGHT *
-			 fb->format->cpp[0] * (x_offset_in_blocks + 1);
+			 fb->format->cpp[0] * x_offset_in_blocks;
 
 		/*
 		 * Using dma_addr_t variable to calculate with multiplier of different types,

-- 
2.51.0



From nfraprado at collabora.com  Tue Dec 30 06:03:02 2025
From: nfraprado at collabora.com (=?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?=)
Date: Tue, 30 Dec 2025 11:03:02 -0300
Subject: [PATCH RFC 2/6] drm/mediatek: plane: Correct AFBC alignment
 definition to 128
In-Reply-To: <20251230-mtk-afbc-fixes-v1-0-6c0247b66e32@collabora.com>
References: <20251230-mtk-afbc-fixes-v1-0-6c0247b66e32@collabora.com>
Message-ID: <20251230-mtk-afbc-fixes-v1-2-6c0247b66e32@collabora.com>

The minimum alignment for both the header and data buffers in the AFBC
format for Mali GPUs with archicture version 6 and higher (which
includes MT8195's G57 (v9)) is 128, not 1024 as the MediaTek DRM driver
currently defines.

Since Mesa defines it as the correct value of 128 [1], when displaying
AFBC buffers, some resolutions will cause the OVL component to be
configured by the driver with a data address that is different from the
address that actually contains the data as set by Mesa, resulting in
corrupted output on display.

Fix the AFBC alignment definition for the MediaTek DRM driver.

[1] https://gitlab.freedesktop.org/mesa/mesa/-/blob/3848a080534a17ca075e9e95dd3a14abb80139aa/src/panfrost/lib/pan_afbc.h#L364

Fixes: c410fa9b07c3 ("drm/mediatek: Add AFBC support to Mediatek DRM driver")
Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_plane.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_plane.h b/drivers/gpu/drm/mediatek/mtk_plane.h
index 95c5fa5295d8..46be4454bc92 100644
--- a/drivers/gpu/drm/mediatek/mtk_plane.h
+++ b/drivers/gpu/drm/mediatek/mtk_plane.h
@@ -13,7 +13,7 @@
 #define AFBC_DATA_BLOCK_WIDTH 32
 #define AFBC_DATA_BLOCK_HEIGHT 8
 #define AFBC_HEADER_BLOCK_SIZE 16
-#define AFBC_HEADER_ALIGNMENT 1024
+#define AFBC_HEADER_ALIGNMENT 128
 
 struct mtk_plane_pending_state {
 	bool				config;

-- 
2.51.0



From nfraprado at collabora.com  Tue Dec 30 06:03:03 2025
From: nfraprado at collabora.com (=?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?=)
Date: Tue, 30 Dec 2025 11:03:03 -0300
Subject: [PATCH RFC 3/6] drm/mediatek: ovl: Fix misaligned layer source
 size on AFBC mode
In-Reply-To: <20251230-mtk-afbc-fixes-v1-0-6c0247b66e32@collabora.com>
References: <20251230-mtk-afbc-fixes-v1-0-6c0247b66e32@collabora.com>
Message-ID: <20251230-mtk-afbc-fixes-v1-3-6c0247b66e32@collabora.com>

From: Ariel D'Alessandro <ariel.dalessandro at collabora.com>

In AFBC mode, OVL_SRC_SIZE must be block aligned. Due to this limitation
of the AFBC format, OVL_CLIP needs to be used to achieve the desired
output size of the layer while still meeting the alignment constraints.
Failure to do this will result in vblank timeouts and no rendered output
when the AFBC data source isn't aligned to the AFBC block (32x8).

Configure OVL_CLIP so unaligned AFBC layers can be displayed.

The following illustrates how the alignment is achieved through the clip
settings for the horizontal coordinates, the vertical coordinates are
analogous:

/------------------------------------------------\
|                                                |
|            ........................            |
|            ........................            |
|            ........................            |
|            ........................            |
|                                                |
\------------------------------------------------/
     |       |                      |       |
     |       src.x1                 src.x2  |
     |       |                      |       |
     |       |<-------------------->|       |
     |              src_width               |
     |                                      |
     N * AFBC_DATA_BLOCK_WIDTH              M * AFBC_DATA_BLOCK_WIDTH
     |                                      |
     |<----->|                      |<----->|
      clip_left                      clip_right

Signed-off-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
Co-developed-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 35 ++++++++++++++++++++++++++++-----
 drivers/gpu/drm/mediatek/mtk_plane.c    | 21 ++++++++++++++++++++
 drivers/gpu/drm/mediatek/mtk_plane.h    |  4 ++++
 3 files changed, 55 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index 8e20b45411fc..c6a00c2256dd 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -39,6 +39,11 @@
 #define OVL_PITCH_MSB_2ND_SUBBUF			BIT(16)
 #define DISP_REG_OVL_PITCH(n)			(0x0044 + 0x20 * (n))
 #define OVL_CONST_BLEND					BIT(28)
+#define DISP_REG_OVL_CLIP(n)			(0x004C + 0x20 * (n))
+#define OVL_CLIP_LEFT					GENMASK(7, 0)
+#define OVL_CLIP_RIGHT					GENMASK(15, 8)
+#define OVL_CLIP_TOP					GENMASK(23, 16)
+#define OVL_CLIP_BOTTOM					GENMASK(31, 24)
 #define DISP_REG_OVL_RDMA_CTRL(n)		(0x00c0 + 0x20 * (n))
 #define DISP_REG_OVL_RDMA_GMC(n)		(0x00c8 + 0x20 * (n))
 #define DISP_REG_OVL_ADDR_MT2701		0x0040
@@ -499,13 +504,14 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
 	struct mtk_plane_pending_state *pending = &state->pending;
 	unsigned int addr = pending->addr;
 	unsigned int pitch_lsb = pending->pitch & GENMASK(15, 0);
+	unsigned long long modifier = pending->modifier;
 	unsigned int fmt = pending->format;
 	unsigned int rotation = pending->rotation;
 	unsigned int offset = (pending->y << 16) | pending->x;
-	unsigned int src_size = (pending->height << 16) | pending->width;
 	unsigned int blend_mode = state->base.pixel_blend_mode;
 	unsigned int ignore_pixel_alpha = 0;
-	unsigned int con;
+	unsigned int src_size, con, src_width, src_height;
+	unsigned int clip = 0;
 
 	if (!pending->enable) {
 		mtk_ovl_layer_off(dev, idx, cmdq_pkt);
@@ -550,9 +556,26 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
 		addr += pending->pitch - 1;
 	}
 
-	if (ovl->data->supports_afbc)
-		mtk_ovl_set_afbc(ovl, cmdq_pkt, idx,
-				 pending->modifier != DRM_FORMAT_MOD_LINEAR);
+	if (ovl->data->supports_afbc && (modifier != DRM_FORMAT_MOD_LINEAR)) {
+		/*
+		 * In AFBC mode, OVL_SRC_SIZE must be block aligned. Due to this
+		 * limitation of the AFBC format, OVL_CLIP is used to adjust the
+		 * output size of the layer.
+		 */
+		clip = FIELD_PREP(OVL_CLIP_BOTTOM, pending->clip_bottom) |
+		       FIELD_PREP(OVL_CLIP_TOP, pending->clip_top) |
+		       FIELD_PREP(OVL_CLIP_RIGHT, pending->clip_right) |
+		       FIELD_PREP(OVL_CLIP_LEFT, pending->clip_left);
+		src_height = pending->height + pending->clip_top + pending->clip_bottom;
+		src_width = pending->width + pending->clip_left + pending->clip_right;
+		mtk_ovl_set_afbc(ovl, cmdq_pkt, idx, true);
+	} else {
+		src_height = pending->height;
+		src_width = pending->width;
+		mtk_ovl_set_afbc(ovl, cmdq_pkt, idx, false);
+	}
+
+	src_size = (src_height << 16) | src_width;
 
 	mtk_ddp_write_relaxed(cmdq_pkt, con, &ovl->cmdq_reg, ovl->regs,
 			      DISP_REG_OVL_CON(idx));
@@ -560,6 +583,8 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
 			      &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_PITCH(idx));
 	mtk_ddp_write_relaxed(cmdq_pkt, src_size, &ovl->cmdq_reg, ovl->regs,
 			      DISP_REG_OVL_SRC_SIZE(idx));
+	mtk_ddp_write_relaxed(cmdq_pkt, clip, &ovl->cmdq_reg, ovl->regs,
+			      DISP_REG_OVL_CLIP(idx));
 	mtk_ddp_write_relaxed(cmdq_pkt, offset, &ovl->cmdq_reg, ovl->regs,
 			      DISP_REG_OVL_OFFSET(idx));
 	mtk_ddp_write_relaxed(cmdq_pkt, addr, &ovl->cmdq_reg, ovl->regs,
diff --git a/drivers/gpu/drm/mediatek/mtk_plane.c b/drivers/gpu/drm/mediatek/mtk_plane.c
index 1214f623859e..8fb08768e8ce 100644
--- a/drivers/gpu/drm/mediatek/mtk_plane.c
+++ b/drivers/gpu/drm/mediatek/mtk_plane.c
@@ -114,6 +114,7 @@ static void mtk_plane_update_new_state(struct drm_plane_state *new_state,
 				       struct mtk_plane_state *mtk_plane_state)
 {
 	struct drm_framebuffer *fb = new_state->fb;
+	unsigned int clip_left = 0, clip_top = 0, clip_right = 0, clip_bottom = 0;
 	struct drm_gem_object *gem;
 	struct mtk_gem_obj *mtk_gem;
 	unsigned int pitch, format;
@@ -148,6 +149,22 @@ static void mtk_plane_update_new_state(struct drm_plane_state *new_state,
 		int x_offset_in_blocks = (new_state->src.x1 >> 16) / AFBC_DATA_BLOCK_WIDTH;
 		int y_offset_in_blocks = (new_state->src.y1 >> 16) / AFBC_DATA_BLOCK_HEIGHT;
 		int hdr_size, hdr_offset;
+		int src_width = drm_rect_width(&new_state->src) >> 16;
+		int src_height = drm_rect_height(&new_state->src) >> 16;
+		unsigned int remainder_right, remainder_bottom;
+
+		/*
+		 * In AFBC mode, the source size configured needs to be a
+		 * multiple of the AFBC data block size. Compute and save the
+		 * necessary clips so the indeded x, y, width and height are
+		 * obtained in the output despite this constraint.
+		 */
+		clip_left = (new_state->src.x1 >> 16) % AFBC_DATA_BLOCK_WIDTH;
+		clip_top = (new_state->src.y1 >> 16) % AFBC_DATA_BLOCK_HEIGHT;
+		remainder_right = (src_width + clip_left) % AFBC_DATA_BLOCK_WIDTH;
+		clip_right = remainder_right ? AFBC_DATA_BLOCK_WIDTH - remainder_right : 0;
+		remainder_bottom = (src_height + clip_top) % AFBC_DATA_BLOCK_HEIGHT;
+		clip_bottom = remainder_bottom ? AFBC_DATA_BLOCK_HEIGHT - remainder_bottom : 0;
 
 		hdr_pitch = width_in_blocks * AFBC_HEADER_BLOCK_SIZE;
 		pitch = width_in_blocks * AFBC_DATA_BLOCK_WIDTH *
@@ -187,6 +204,10 @@ static void mtk_plane_update_new_state(struct drm_plane_state *new_state,
 	mtk_plane_state->pending.y = new_state->dst.y1;
 	mtk_plane_state->pending.width = drm_rect_width(&new_state->dst);
 	mtk_plane_state->pending.height = drm_rect_height(&new_state->dst);
+	mtk_plane_state->pending.clip_left = clip_left;
+	mtk_plane_state->pending.clip_top = clip_top;
+	mtk_plane_state->pending.clip_right = clip_right;
+	mtk_plane_state->pending.clip_bottom = clip_bottom;
 	mtk_plane_state->pending.rotation = new_state->rotation;
 	mtk_plane_state->pending.color_encoding = new_state->color_encoding;
 }
diff --git a/drivers/gpu/drm/mediatek/mtk_plane.h b/drivers/gpu/drm/mediatek/mtk_plane.h
index 46be4454bc92..a9cfb2ee5859 100644
--- a/drivers/gpu/drm/mediatek/mtk_plane.h
+++ b/drivers/gpu/drm/mediatek/mtk_plane.h
@@ -28,6 +28,10 @@ struct mtk_plane_pending_state {
 	unsigned int			y;
 	unsigned int			width;
 	unsigned int			height;
+	unsigned int			clip_left;
+	unsigned int			clip_top;
+	unsigned int			clip_right;
+	unsigned int			clip_bottom;
 	unsigned int			rotation;
 	bool				dirty;
 	bool				async_dirty;

-- 
2.51.0



From nfraprado at collabora.com  Tue Dec 30 06:03:04 2025
From: nfraprado at collabora.com (=?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?=)
Date: Tue, 30 Dec 2025 11:03:04 -0300
Subject: [PATCH RFC 4/6] drm/mediatek: ovl: Disallow AFBC buffers with
 width over 1920
In-Reply-To: <20251230-mtk-afbc-fixes-v1-0-6c0247b66e32@collabora.com>
References: <20251230-mtk-afbc-fixes-v1-0-6c0247b66e32@collabora.com>
Message-ID: <20251230-mtk-afbc-fixes-v1-4-6c0247b66e32@collabora.com>

AFBC buffers with width over 1920 are not supported by OVL. If
attempted, the image displayed contains many artifacts.

Add this restriction to the layer check callback so such configurations
are not allowed.

NOTE: This doesn't seem to be a good way to handle this restriction, as
when tested with Weston, it simply fails to render, rather than fallback
to not using the modifier:

[19:09:03.857] atomic: couldn't commit new state: Invalid argument
[19:09:03.857] repaint-flush failed: Invalid argument

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index c6a00c2256dd..196b874057ba 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -368,6 +368,13 @@ int mtk_ovl_layer_check(struct device *dev, unsigned int idx,
 	if (state->fb->format->is_yuv && (state->rotation & ~DRM_MODE_ROTATE_0))
 		return -EINVAL;
 
+	/*
+	 * AFBC buffers with width > 1920 are not supported and produce
+	 * artifacts, so should be disabled.
+	 */
+	if (state->fb->modifier != DRM_FORMAT_MOD_LINEAR && state->fb->width > 1920)
+		return -EINVAL;
+
 	return 0;
 }
 

-- 
2.51.0



From nfraprado at collabora.com  Tue Dec 30 06:03:05 2025
From: nfraprado at collabora.com (=?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?=)
Date: Tue, 30 Dec 2025 11:03:05 -0300
Subject: [PATCH RFC 5/6] drm/mediatek: ovl: Disable AFBC on MT8188
In-Reply-To: <20251230-mtk-afbc-fixes-v1-0-6c0247b66e32@collabora.com>
References: <20251230-mtk-afbc-fixes-v1-0-6c0247b66e32@collabora.com>
Message-ID: <20251230-mtk-afbc-fixes-v1-5-6c0247b66e32@collabora.com>

Despite MT8188's OVL being mostly the same IP as the OVL on MT8195, it
does not support AFBC, even when the same register configurations are
applied. Introduce a separate compatible for it with AFBC support
disabled.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index 196b874057ba..97f6694772d4 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -762,6 +762,21 @@ static const struct mtk_disp_ovl_data mt8192_ovl_2l_driver_data = {
 	.num_formats = ARRAY_SIZE(mt8173_formats),
 };
 
+static const struct mtk_disp_ovl_data mt8188_ovl_driver_data = {
+	.addr = DISP_REG_OVL_ADDR_MT8173,
+	.gmc_bits = 10,
+	.layer_nr = 4,
+	.fmt_rgb565_is_0 = true,
+	.smi_id_en = true,
+	.supports_afbc = false,
+	.blend_modes = BIT(DRM_MODE_BLEND_PREMULTI) |
+		       BIT(DRM_MODE_BLEND_COVERAGE) |
+		       BIT(DRM_MODE_BLEND_PIXEL_NONE),
+	.formats = mt8195_formats,
+	.num_formats = ARRAY_SIZE(mt8195_formats),
+	.supports_clrfmt_ext = true,
+};
+
 static const struct mtk_disp_ovl_data mt8195_ovl_driver_data = {
 	.addr = DISP_REG_OVL_ADDR_MT8173,
 	.gmc_bits = 10,
@@ -790,6 +805,8 @@ static const struct of_device_id mtk_disp_ovl_driver_dt_match[] = {
 	  .data = &mt8192_ovl_driver_data},
 	{ .compatible = "mediatek,mt8192-disp-ovl-2l",
 	  .data = &mt8192_ovl_2l_driver_data},
+	{ .compatible = "mediatek,mt8188-disp-ovl",
+	  .data = &mt8188_ovl_driver_data},
 	{ .compatible = "mediatek,mt8195-disp-ovl",
 	  .data = &mt8195_ovl_driver_data},
 	{},

-- 
2.51.0



From nfraprado at collabora.com  Tue Dec 30 06:03:06 2025
From: nfraprado at collabora.com (=?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?=)
Date: Tue, 30 Dec 2025 11:03:06 -0300
Subject: [PATCH RFC 6/6] drm/mediatek: Re-enable AFBC support on MediaTek
 DRM driver
In-Reply-To: <20251230-mtk-afbc-fixes-v1-0-6c0247b66e32@collabora.com>
References: <20251230-mtk-afbc-fixes-v1-0-6c0247b66e32@collabora.com>
Message-ID: <20251230-mtk-afbc-fixes-v1-6-6c0247b66e32@collabora.com>

Commit 9882a4064003 ("drm/mediatek: Disable AFBC support on Mediatek DRM
driver") disabled AFBC support on the MediaTek DRM driver since it was
broken.

With the bugs in the AFBC support now fixed, re-enable the support.

Signed-off-by: N?colas F. R. A. Prado <nfraprado at collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_plane.c | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_plane.c b/drivers/gpu/drm/mediatek/mtk_plane.c
index 8fb08768e8ce..38dd94cdd665 100644
--- a/drivers/gpu/drm/mediatek/mtk_plane.c
+++ b/drivers/gpu/drm/mediatek/mtk_plane.c
@@ -22,6 +22,9 @@
 
 static const u64 modifiers[] = {
 	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 |
+				AFBC_FORMAT_MOD_SPLIT |
+				AFBC_FORMAT_MOD_SPARSE),
 	DRM_FORMAT_MOD_INVALID,
 };
 
@@ -69,7 +72,26 @@ static bool mtk_plane_format_mod_supported(struct drm_plane *plane,
 					   uint32_t format,
 					   uint64_t modifier)
 {
-	return modifier == DRM_FORMAT_MOD_LINEAR;
+	if (modifier == DRM_FORMAT_MOD_LINEAR)
+		return true;
+
+	if (modifier != DRM_FORMAT_MOD_ARM_AFBC(
+				AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 |
+				AFBC_FORMAT_MOD_SPLIT |
+				AFBC_FORMAT_MOD_SPARSE))
+		return false;
+
+	if (format != DRM_FORMAT_XRGB8888 &&
+	    format != DRM_FORMAT_ARGB8888 &&
+	    format != DRM_FORMAT_BGRX8888 &&
+	    format != DRM_FORMAT_BGRA8888 &&
+	    format != DRM_FORMAT_ABGR8888 &&
+	    format != DRM_FORMAT_XBGR8888 &&
+	    format != DRM_FORMAT_RGB888 &&
+	    format != DRM_FORMAT_BGR888)
+		return false;
+
+	return true;
 }
 
 static void mtk_plane_destroy_state(struct drm_plane *plane,

-- 
2.51.0



From shawnguo at kernel.org  Tue Dec 30 06:04:17 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Tue, 30 Dec 2025 22:04:17 +0800
Subject: [PATCH] ARM: dts: imx: imx6sl: fix lcdif compatible
In-Reply-To: <20251223222435.538096-1-andreas@kemnade.info>
References: <20251223222435.538096-1-andreas@kemnade.info>
Message-ID: <aVPb4UNGgrc5qzlD@dragon>

On Tue, Dec 23, 2025 at 11:24:35PM +0100, Andreas Kemnade wrote:
> Fix lcdif compatible according to bindings doc.
> 
> dtbs_check tested only, a glance at the datasheet shows that it should be
> the correct fallback compatible.
> 
> Signed-off-by: Andreas Kemnade <andreas at kemnade.info>

Applied, thanks!


From Julia.Lawall at inria.fr  Tue Dec 30 06:06:01 2025
From: Julia.Lawall at inria.fr (Julia Lawall)
Date: Tue, 30 Dec 2025 15:06:01 +0100
Subject: [PATCH] phy: adjust function name reference
Message-ID: <20251230140601.93474-1-Julia.Lawall@inria.fr>

There is no function clk_bulk_prepare_disable.  Refer instead to
clk_bulk_disable_unprepare, which is called in the function
defined just below.

Signed-off-by: Julia Lawall <Julia.Lawall at inria.fr>

---
 drivers/phy/mediatek/phy-mtk-xfi-tphy.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/phy/mediatek/phy-mtk-xfi-tphy.c b/drivers/phy/mediatek/phy-mtk-xfi-tphy.c
index 1a0b7484f525..100a50d0e861 100644
--- a/drivers/phy/mediatek/phy-mtk-xfi-tphy.c
+++ b/drivers/phy/mediatek/phy-mtk-xfi-tphy.c
@@ -353,7 +353,7 @@ static int mtk_xfi_tphy_power_on(struct phy *phy)
  * Disable and unprepare all clocks previously enabled.
  *
  * Return:
- * See clk_bulk_prepare_disable().
+ * See clk_bulk_disable_unprepare().
  */
 static int mtk_xfi_tphy_power_off(struct phy *phy)
 {



From marek.vasut at mailbox.org  Tue Dec 30 06:17:44 2025
From: marek.vasut at mailbox.org (Marek Vasut)
Date: Tue, 30 Dec 2025 15:17:44 +0100
Subject: [PATCH] arm64: dts: imx95: Use GPU_CGC as core clock for GPU
In-Reply-To: <aVM-mSkSubMPd7Du@oss.nxp.com>
References: <aS-lEibp3zTsaR6T@oss.nxp.com>
 <c6e0e55a-06da-4665-972e-e9b5b8c08bf7@mailbox.org>
 <aTACuRjC_Zpf8IOU@oss.nxp.com>
 <de36091e-c890-4897-b3e3-2a7575029a5d@mailbox.org>
 <aTD5np-HGaJqhzkD@oss.nxp.com>
 <5944d872-01a3-47e9-977b-029f3be4fd83@mailbox.org>
 <aTKVMAMQ6v_BwD6R@oss.nxp.com>
 <9b593731-898f-46a7-8ee5-68f8c170351c@mailbox.org>
 <aTYxm_dfMwF4H0_b@oss.nxp.com>
 <53ea529f-3538-4ab5-aa99-0caa6729b4cd@mailbox.org>
 <aVM-mSkSubMPd7Du@oss.nxp.com>
Message-ID: <6055d6f3-2b31-4225-a42e-0f5ad79f7256@mailbox.org>

On 12/30/25 3:53 AM, Rain Yang wrote:
> On Tue, Dec 30, 2025 at 02:53:38AM +0100, Marek Vasut wrote:
>> On 12/8/25 3:02 AM, Rain Yang wrote:
>>
>>>>> Okay, I?ll submit a patch later.
>>>>> The commit message should reflect that only CLK_GPU_CGC is enabled.
>>>>
>>>> The commit message , and this change , is unrelated to GPUAPB clock.
>>> The commit message is ambiguous. Could you clarify which parent clock
>>> you are referring to, and whether it can be enabled by CLK_GPU_CGC?
>>> If it was CLK_GPU, CLK_GPU_CGC can't be able to control it.
>>
>> The commit message clearly states "These new GPU_CGC clock
>> gate the existing GPU clock." and "GPU_CGC as well as its parent GPU clock."
>> , I don't perceive any ambiguity, sorry.
>>
>> Frankly, the whole GPUAPB discussion is entirely unrelated and it only stalls
>> application of this bugfix and keeps upstream broken. This is not helping.
>>
>> So unless there is anything in particular that is on-topic and prevents this
>> patch from being applied, it would be good to apply it, otherwise the GPU on
>> MX95 in mainline Linux is not working.
> Hi Marek,
> 
> I?m not opposed to this patch being merged into mainline, but the commit
> message needs to be accurate. the parent CLK_GPU cannot be enabled or
> disabled externally. The last sentence should clearly state:

Look here, this is what you can do with the MX95 SM:

"
 >$ clock.r
...
083: gpuapb               =  on,  133333333Hz
084: gpu                  =  on,  800000000Hz
...
174: gpu_cgc              =  on,  800000000Hz

 >$ clock.w gpu_cgc off
 >$ clock.w gpu off
 >$ clock.w gpuapb off

 >$ clock.r
...
083: gpuapb               = off,  133333333Hz
084: gpu                  = off,  800000000Hz
...
174: gpu_cgc              = off,  800000000Hz
"

Notice how all clock are disabled, including GPU clock.

That does not agree with your statement.

> When the panthor driver enables the GPU core clock, it enables the GPU_CGC.

It also enables all disabled parent clock in the process, which includes 
the GPU clock.

> This ensures the description reflects the actual hardware behavior and
> avoids confusion for future maintainers.
> Thanks for addressing this issue ? once the commit message is corrected,
> I?m fine with this going in.

See above.


From arnd at arndb.de  Tue Dec 30 06:20:10 2025
From: arnd at arndb.de (Arnd Bergmann)
Date: Tue, 30 Dec 2025 15:20:10 +0100
Subject: [PATCH 2/5] ARM: uapi: Stop leaking CONFIG_CPU_ENDIAN_BE8 reference to
 userspace
In-Reply-To: <20251230-headers_install-config-leak-v1-2-efba5c58073d@linutronix.de>
References: <20251230-headers_install-config-leak-v1-0-efba5c58073d@linutronix.de>
 <20251230-headers_install-config-leak-v1-2-efba5c58073d@linutronix.de>
Message-ID: <d2ad12f2-3d65-4bef-890c-65d78a33d790@app.fastmail.com>

On Tue, Dec 30, 2025, at 08:10, Thomas Wei?schuh wrote:
> UAPI headers are not supposed to leak references to kconfig symbols.
> These won't be set when building userspace. Hide the kconfig reference
> behind 'if defined(__KERNEL__)', so it will be stripped by
> headers_install.sh, the same way other kconfig references in this file
> are handled. The result for userspace will be the same, but the
> exception in headers_install.sh can also be removed.
>
> Signed-off-by: Thomas Wei?schuh <thomas.weissschuh at linutronix.de>

According to codesearch.debian.net, there are no actual users of
this definition outside of the kernel, and there really shouldn't
be either.

It should be both safe and correct to open-code PSR_ENDSTATE
in the two file where it is used as

 if (IS_ENABLED(CONFIG_CPU_ENDIAN_BE8))
        regs->ARM_cpsr |= PSR_E_BIT

and then remove the definition from the header. Alternatively
it could be moved into the non-uapi header, or you can have
an #ifdef around both of them.

     Arnd


From cassel at kernel.org  Tue Dec 30 06:22:39 2025
From: cassel at kernel.org (Niklas Cassel)
Date: Tue, 30 Dec 2025 15:22:39 +0100
Subject: [PATCH] PCI: dwc: Remove duplicate
 dw_pcie_ep_hide_ext_capability() function
In-Reply-To: <20251224-remove_dw_pcie_ep_hide_ext_capability-v1-1-4302c9cdc316@oss.qualcomm.com>
References: <20251224-remove_dw_pcie_ep_hide_ext_capability-v1-1-4302c9cdc316@oss.qualcomm.com>
Message-ID: <aVPgL2AuAMpx76pI@ryzen>

Hello Qiang Yu,

On Wed, Dec 24, 2025 at 02:10:46AM -0800, Qiang Yu wrote:
> Remove dw_pcie_ep_hide_ext_capability() and replace its usage with
> dw_pcie_remove_ext_capability(). Both functions serve the same purpose
> of hiding PCIe extended capabilities, but dw_pcie_remove_ext_capability()
> provides a cleaner API that doesn't require the caller to specify the
> previous capability ID.
> 
> Compile-tested only. Runtime testing on RK3588 hardware would be
> appreciated.

This patch does not appy on top of pci/controller/dwc

Anyway, I applied it manually, and tested, thus:
Tested-by: Niklas Cassel <cassel at kernel.org>


From thomas.weissschuh at linutronix.de  Tue Dec 30 06:33:39 2025
From: thomas.weissschuh at linutronix.de (Thomas =?utf-8?Q?Wei=C3=9Fschuh?=)
Date: Tue, 30 Dec 2025 15:33:39 +0100
Subject: [PATCH 2/5] ARM: uapi: Stop leaking CONFIG_CPU_ENDIAN_BE8
 reference to userspace
In-Reply-To: <d2ad12f2-3d65-4bef-890c-65d78a33d790@app.fastmail.com>
References: <20251230-headers_install-config-leak-v1-0-efba5c58073d@linutronix.de>
 <20251230-headers_install-config-leak-v1-2-efba5c58073d@linutronix.de>
 <d2ad12f2-3d65-4bef-890c-65d78a33d790@app.fastmail.com>
Message-ID: <20251230152519-1f7ea27a-10de-4d0c-9dd0-04eb0588d733@linutronix.de>

On Tue, Dec 30, 2025 at 03:20:10PM +0100, Arnd Bergmann wrote:
> On Tue, Dec 30, 2025, at 08:10, Thomas Wei?schuh wrote:
> > UAPI headers are not supposed to leak references to kconfig symbols.
> > These won't be set when building userspace. Hide the kconfig reference
> > behind 'if defined(__KERNEL__)', so it will be stripped by
> > headers_install.sh, the same way other kconfig references in this file
> > are handled. The result for userspace will be the same, but the
> > exception in headers_install.sh can also be removed.
> >
> > Signed-off-by: Thomas Wei?schuh <thomas.weissschuh at linutronix.de>
> 
> According to codesearch.debian.net, there are no actual users of
> this definition outside of the kernel, and there really shouldn't
> be either.
> 
> It should be both safe and correct to open-code PSR_ENDSTATE
> in the two file where it is used as
> 
>  if (IS_ENABLED(CONFIG_CPU_ENDIAN_BE8))
>         regs->ARM_cpsr |= PSR_E_BIT
> 
> and then remove the definition from the header. Alternatively
> it could be moved into the non-uapi header, or you can have
> an #ifdef around both of them.

These alternatives work for me, too. I went with the current aproach as
it matches what the rest of the file is doing and it won't break users.

I'll do the open-coding as proposed above.


Thomas


From marex at nabladev.com  Tue Dec 30 05:34:14 2025
From: marex at nabladev.com (Marek Vasut)
Date: Tue, 30 Dec 2025 14:34:14 +0100
Subject: [PATCH v2 4/4] arm64: dts: imx8mn: Add ifm VHIP4 EvalBoard v1 and
 v2
In-Reply-To: <e3d305ce-cdfa-4a11-bd54-9648b12a013f@lunn.ch>
References: <20251229193706.73564-1-marex@nabladev.com>
 <20251229193706.73564-4-marex@nabladev.com>
 <e3d305ce-cdfa-4a11-bd54-9648b12a013f@lunn.ch>
Message-ID: <dc29e774-07fb-4d0e-a88a-27d4ec49d060@nabladev.com>

On 12/30/25 11:46 AM, Andrew Lunn wrote:
>> +&fec1 {
>> +	fsl,magic-packet;
> 
> Upps, i probably cut out too much context. This FEC is connected to the Ethernet switch.
> 
> WoL for a port connected to a switch? Have you tested this? Normally
> you would have WoL on each port of the switch, and not on the conduit
> interface.
> 
>> +&fec1 {
>> +	fsl,magic-packet;
> 
> Have you tested WoL?
> 
>> +&fec1 {
>> +	fsl,magic-packet;
> 
> WoL again?
I don't think WOL is used on this device at all. Would you suggest 
removing the fsl,magic-packet properties ?


From jolsa at kernel.org  Tue Dec 30 06:50:01 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Tue, 30 Dec 2025 15:50:01 +0100
Subject: [PATCHv6 bpf-next 0/9] ftrace,bpf: Use single direct ops for bpf trampolines
Message-ID: <20251230145010.103439-1-jolsa@kernel.org>

hi,
while poking the multi-tracing interface I ended up with just one ftrace_ops
object to attach all trampolines.

This change allows to use less direct API calls during the attachment changes
in the future code, so in effect speeding up the attachment.

In current code we get a speed up from using just a single ftrace_ops object.

- with current code:

  Performance counter stats for 'bpftrace -e fentry:vmlinux:ksys_* {} -c true':

     6,364,157,902      cycles:k
       828,728,902      cycles:u
     1,064,803,824      instructions:u                   #    1.28  insn per cycle
    23,797,500,067      instructions:k                   #    3.74  insn per cycle

       4.416004987 seconds time elapsed

       0.164121000 seconds user
       1.289550000 seconds sys


- with the fix:

   Performance counter stats for 'bpftrace -e fentry:vmlinux:ksys_* {} -c true':

     6,535,857,905      cycles:k
       810,809,429      cycles:u
     1,064,594,027      instructions:u                   #    1.31  insn per cycle
    23,962,552,894      instructions:k                   #    3.67  insn per cycle

       1.666961239 seconds time elapsed

       0.157412000 seconds user
       1.283396000 seconds sys



The speedup seems to be related to the fact that with single ftrace_ops object
we don't call ftrace_shutdown anymore (we use ftrace_update_ops instead) and
we skip the synchronize rcu calls (each ~100ms) at the end of that function.

rfc: https://lore.kernel.org/bpf/20250729102813.1531457-1-jolsa at kernel.org/
v1:  https://lore.kernel.org/bpf/20250923215147.1571952-1-jolsa at kernel.org/
v2:  https://lore.kernel.org/bpf/20251113123750.2507435-1-jolsa at kernel.org/
v3:  https://lore.kernel.org/bpf/20251120212402.466524-1-jolsa at kernel.org/
v4:  https://lore.kernel.org/bpf/20251203082402.78816-1-jolsa at kernel.org/
v5:  https://lore.kernel.org/bpf/20251215211402.353056-10-jolsa at kernel.org/

v6 changes:
- rename add_hash_entry_direct to add_ftrace_hash_entry_direct [Steven]
- factor hash_add/hash_sub [Steven]
- add kerneldoc header for update_ftrace_direct_* functions [Steven]
- few assorted smaller fixes [Steven]
- added missing direct_ops wrappers for !CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
  case [Steven]

v5 changes:
- do not export ftrace_hash object [Steven]
- fix update_ftrace_direct_add new_filter_hash leak [ci]

v4 changes:
- rebased on top of bpf-next/master (with jmp attach changes)
  added patch 1 to deal with that
- added extra checks for update_ftrace_direct_del/mod to address
  the ci bot review

v3 changes:
- rebased on top of bpf-next/master
- fixed update_ftrace_direct_del cleanup path
- added missing inline to update_ftrace_direct_* stubs

v2 changes:
- rebased on top fo bpf-next/master plus Song's livepatch fixes [1] 
- renamed the API functions [2] [Steven]
- do not export the new api [Steven]
- kept the original direct interface:

  I'm not sure if we want to melt both *_ftrace_direct and the new interface
  into single one. It's bit different in semantic (hence the name change as
  Steven suggested [2]) and I don't think the changes are not that big so
  we could easily keep both APIs.

v1 changes:
- make the change x86 specific, after discussing with Mark options for
  arm64 [Mark]

thanks,
jirka


[1] https://lore.kernel.org/bpf/20251027175023.1521602-1-song at kernel.org/
[2] https://lore.kernel.org/bpf/20250924050415.4aefcb91 at batman.local.home/
---
Jiri Olsa (9):
      ftrace,bpf: Remove FTRACE_OPS_FL_JMP ftrace_ops flag
      ftrace: Make alloc_and_copy_ftrace_hash direct friendly
      ftrace: Export some of hash related functions
      ftrace: Add update_ftrace_direct_add function
      ftrace: Add update_ftrace_direct_del function
      ftrace: Add update_ftrace_direct_mod function
      bpf: Add trampoline ip hash table
      ftrace: Factor ftrace_ops ops_func interface
      bpf,x86: Use single ftrace_ops for direct calls

 arch/x86/Kconfig        |   1 +
 include/linux/bpf.h     |   7 ++-
 include/linux/ftrace.h  |  31 +++++++++-
 kernel/bpf/trampoline.c | 259 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
 kernel/trace/Kconfig    |   3 +
 kernel/trace/ftrace.c   | 406 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
 6 files changed, 632 insertions(+), 75 deletions(-)


From jolsa at kernel.org  Tue Dec 30 06:50:02 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Tue, 30 Dec 2025 15:50:02 +0100
Subject: [PATCHv6 bpf-next 1/9] ftrace,bpf: Remove FTRACE_OPS_FL_JMP ftrace_ops flag
In-Reply-To: <20251230145010.103439-1-jolsa@kernel.org>
References: <20251230145010.103439-1-jolsa@kernel.org>
Message-ID: <20251230145010.103439-2-jolsa@kernel.org>

At the moment the we allow the jmp attach only for ftrace_ops that
has FTRACE_OPS_FL_JMP set. This conflicts with following changes
where we use single ftrace_ops object for all direct call sites,
so all could be be attached via just call or jmp.

We already limit the jmp attach support with config option and bit
(LSB) set on the trampoline address. It turns out that's actually
enough to limit the jmp attach for architecture and only for chosen
addresses (with LSB bit set).

Each user of register_ftrace_direct or modify_ftrace_direct can set
the trampoline bit (LSB) to indicate it has to be attached by jmp.

The bpf trampoline generation code uses trampoline flags to generate
jmp-attach specific code and ftrace inner code uses the trampoline
bit (LSB) to handle return from jmp attachment, so there's no harm
to remove the FTRACE_OPS_FL_JMP bit.

The fexit/fmodret performance stays the same (did not drop),
current code:

  fentry         :   77.904 ? 0.546M/s
  fexit          :   62.430 ? 0.554M/s
  fmodret        :   66.503 ? 0.902M/s

with this change:

  fentry         :   80.472 ? 0.061M/s
  fexit          :   63.995 ? 0.127M/s
  fmodret        :   67.362 ? 0.175M/s

Fixes: 25e4e3565d45 ("ftrace: Introduce FTRACE_OPS_FL_JMP")
Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 include/linux/ftrace.h  |  1 -
 kernel/bpf/trampoline.c | 32 ++++++++++++++------------------
 kernel/trace/ftrace.c   | 14 --------------
 3 files changed, 14 insertions(+), 33 deletions(-)

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 770f0dc993cc..41c9bb08d4e4 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -359,7 +359,6 @@ enum {
 	FTRACE_OPS_FL_DIRECT			= BIT(17),
 	FTRACE_OPS_FL_SUBOP			= BIT(18),
 	FTRACE_OPS_FL_GRAPH			= BIT(19),
-	FTRACE_OPS_FL_JMP			= BIT(20),
 };
 
 #ifndef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index 2a125d063e62..789ff4e1f40b 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -214,10 +214,15 @@ static int modify_fentry(struct bpf_trampoline *tr, u32 orig_flags,
 	int ret;
 
 	if (tr->func.ftrace_managed) {
+		unsigned long addr = (unsigned long) new_addr;
+
+		if (bpf_trampoline_use_jmp(tr->flags))
+			addr = ftrace_jmp_set(addr);
+
 		if (lock_direct_mutex)
-			ret = modify_ftrace_direct(tr->fops, (long)new_addr);
+			ret = modify_ftrace_direct(tr->fops, addr);
 		else
-			ret = modify_ftrace_direct_nolock(tr->fops, (long)new_addr);
+			ret = modify_ftrace_direct_nolock(tr->fops, addr);
 	} else {
 		ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr,
 						   new_addr);
@@ -240,10 +245,15 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
 	}
 
 	if (tr->func.ftrace_managed) {
+		unsigned long addr = (unsigned long) new_addr;
+
+		if (bpf_trampoline_use_jmp(tr->flags))
+			addr = ftrace_jmp_set(addr);
+
 		ret = ftrace_set_filter_ip(tr->fops, (unsigned long)ip, 0, 1);
 		if (ret)
 			return ret;
-		ret = register_ftrace_direct(tr->fops, (long)new_addr);
+		ret = register_ftrace_direct(tr->fops, addr);
 	} else {
 		ret = bpf_trampoline_update_fentry(tr, 0, NULL, new_addr);
 	}
@@ -499,13 +509,6 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut
 	if (err)
 		goto out_free;
 
-#ifdef CONFIG_DYNAMIC_FTRACE_WITH_JMP
-	if (bpf_trampoline_use_jmp(tr->flags))
-		tr->fops->flags |= FTRACE_OPS_FL_JMP;
-	else
-		tr->fops->flags &= ~FTRACE_OPS_FL_JMP;
-#endif
-
 	WARN_ON(tr->cur_image && total == 0);
 	if (tr->cur_image)
 		/* progs already running at this address */
@@ -533,15 +536,8 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut
 	tr->cur_image = im;
 out:
 	/* If any error happens, restore previous flags */
-	if (err) {
+	if (err)
 		tr->flags = orig_flags;
-#ifdef CONFIG_DYNAMIC_FTRACE_WITH_JMP
-		if (bpf_trampoline_use_jmp(tr->flags))
-			tr->fops->flags |= FTRACE_OPS_FL_JMP;
-		else
-			tr->fops->flags &= ~FTRACE_OPS_FL_JMP;
-#endif
-	}
 	kfree(tlinks);
 	return err;
 
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 3ec2033c0774..f5f042ea079e 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -6043,15 +6043,8 @@ int register_ftrace_direct(struct ftrace_ops *ops, unsigned long addr)
 	if (ftrace_hash_empty(hash))
 		return -EINVAL;
 
-	/* This is a "raw" address, and this should never happen. */
-	if (WARN_ON_ONCE(ftrace_is_jmp(addr)))
-		return -EINVAL;
-
 	mutex_lock(&direct_mutex);
 
-	if (ops->flags & FTRACE_OPS_FL_JMP)
-		addr = ftrace_jmp_set(addr);
-
 	/* Make sure requested entries are not already registered.. */
 	size = 1 << hash->size_bits;
 	for (i = 0; i < size; i++) {
@@ -6172,13 +6165,6 @@ __modify_ftrace_direct(struct ftrace_ops *ops, unsigned long addr)
 
 	lockdep_assert_held_once(&direct_mutex);
 
-	/* This is a "raw" address, and this should never happen. */
-	if (WARN_ON_ONCE(ftrace_is_jmp(addr)))
-		return -EINVAL;
-
-	if (ops->flags & FTRACE_OPS_FL_JMP)
-		addr = ftrace_jmp_set(addr);
-
 	/* Enable the tmp_ops to have the same functions as the direct ops */
 	ftrace_ops_init(&tmp_ops);
 	tmp_ops.func_hash = ops->func_hash;
-- 
2.52.0



From jolsa at kernel.org  Tue Dec 30 06:50:03 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Tue, 30 Dec 2025 15:50:03 +0100
Subject: [PATCHv6 bpf-next 2/9] ftrace: Make alloc_and_copy_ftrace_hash direct friendly
In-Reply-To: <20251230145010.103439-1-jolsa@kernel.org>
References: <20251230145010.103439-1-jolsa@kernel.org>
Message-ID: <20251230145010.103439-3-jolsa@kernel.org>

Make alloc_and_copy_ftrace_hash to copy also direct address
for each hash entry.

Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 kernel/trace/ftrace.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index f5f042ea079e..409271aa8dad 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1212,7 +1212,7 @@ static void __add_hash_entry(struct ftrace_hash *hash,
 }
 
 static struct ftrace_func_entry *
-add_hash_entry(struct ftrace_hash *hash, unsigned long ip)
+add_hash_entry_direct(struct ftrace_hash *hash, unsigned long ip, unsigned long direct)
 {
 	struct ftrace_func_entry *entry;
 
@@ -1221,11 +1221,18 @@ add_hash_entry(struct ftrace_hash *hash, unsigned long ip)
 		return NULL;
 
 	entry->ip = ip;
+	entry->direct = direct;
 	__add_hash_entry(hash, entry);
 
 	return entry;
 }
 
+static struct ftrace_func_entry *
+add_hash_entry(struct ftrace_hash *hash, unsigned long ip)
+{
+	return add_hash_entry_direct(hash, ip, 0);
+}
+
 static void
 free_hash_entry(struct ftrace_hash *hash,
 		  struct ftrace_func_entry *entry)
@@ -1398,7 +1405,7 @@ alloc_and_copy_ftrace_hash(int size_bits, struct ftrace_hash *hash)
 	size = 1 << hash->size_bits;
 	for (i = 0; i < size; i++) {
 		hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
-			if (add_hash_entry(new_hash, entry->ip) == NULL)
+			if (add_hash_entry_direct(new_hash, entry->ip, entry->direct) == NULL)
 				goto free_hash;
 		}
 	}
-- 
2.52.0



From jolsa at kernel.org  Tue Dec 30 06:50:04 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Tue, 30 Dec 2025 15:50:04 +0100
Subject: [PATCHv6 bpf-next 3/9] ftrace: Export some of hash related functions
In-Reply-To: <20251230145010.103439-1-jolsa@kernel.org>
References: <20251230145010.103439-1-jolsa@kernel.org>
Message-ID: <20251230145010.103439-4-jolsa@kernel.org>

We are going to use these functions in following changes.

Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 include/linux/ftrace.h |  9 +++++++++
 kernel/trace/ftrace.c  | 13 ++++++-------
 2 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 41c9bb08d4e4..472f2d8a4c0f 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -82,6 +82,7 @@ static inline void early_trace_init(void) { }
 
 struct module;
 struct ftrace_hash;
+struct ftrace_func_entry;
 
 #if defined(CONFIG_FUNCTION_TRACER) && defined(CONFIG_MODULES) && \
 	defined(CONFIG_DYNAMIC_FTRACE)
@@ -405,6 +406,14 @@ enum ftrace_ops_cmd {
 typedef int (*ftrace_ops_func_t)(struct ftrace_ops *op, enum ftrace_ops_cmd cmd);
 
 #ifdef CONFIG_DYNAMIC_FTRACE
+
+#define FTRACE_HASH_DEFAULT_BITS 10
+
+struct ftrace_hash *alloc_ftrace_hash(int size_bits);
+void free_ftrace_hash(struct ftrace_hash *hash);
+struct ftrace_func_entry *add_ftrace_hash_entry_direct(struct ftrace_hash *hash,
+						       unsigned long ip, unsigned long direct);
+
 /* The hash used to know what functions callbacks trace */
 struct ftrace_ops_hash {
 	struct ftrace_hash __rcu	*notrace_hash;
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 409271aa8dad..3ca3aee5f886 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -68,7 +68,6 @@
 	})
 
 /* hash bits for specific function selection */
-#define FTRACE_HASH_DEFAULT_BITS 10
 #define FTRACE_HASH_MAX_BITS 12
 
 #ifdef CONFIG_DYNAMIC_FTRACE
@@ -1211,8 +1210,8 @@ static void __add_hash_entry(struct ftrace_hash *hash,
 	hash->count++;
 }
 
-static struct ftrace_func_entry *
-add_hash_entry_direct(struct ftrace_hash *hash, unsigned long ip, unsigned long direct)
+struct ftrace_func_entry *
+add_ftrace_hash_entry_direct(struct ftrace_hash *hash, unsigned long ip, unsigned long direct)
 {
 	struct ftrace_func_entry *entry;
 
@@ -1230,7 +1229,7 @@ add_hash_entry_direct(struct ftrace_hash *hash, unsigned long ip, unsigned long
 static struct ftrace_func_entry *
 add_hash_entry(struct ftrace_hash *hash, unsigned long ip)
 {
-	return add_hash_entry_direct(hash, ip, 0);
+	return add_ftrace_hash_entry_direct(hash, ip, 0);
 }
 
 static void
@@ -1291,7 +1290,7 @@ static void clear_ftrace_mod_list(struct list_head *head)
 	mutex_unlock(&ftrace_lock);
 }
 
-static void free_ftrace_hash(struct ftrace_hash *hash)
+void free_ftrace_hash(struct ftrace_hash *hash)
 {
 	if (!hash || hash == EMPTY_HASH)
 		return;
@@ -1331,7 +1330,7 @@ void ftrace_free_filter(struct ftrace_ops *ops)
 }
 EXPORT_SYMBOL_GPL(ftrace_free_filter);
 
-static struct ftrace_hash *alloc_ftrace_hash(int size_bits)
+struct ftrace_hash *alloc_ftrace_hash(int size_bits)
 {
 	struct ftrace_hash *hash;
 	int size;
@@ -1405,7 +1404,7 @@ alloc_and_copy_ftrace_hash(int size_bits, struct ftrace_hash *hash)
 	size = 1 << hash->size_bits;
 	for (i = 0; i < size; i++) {
 		hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
-			if (add_hash_entry_direct(new_hash, entry->ip, entry->direct) == NULL)
+			if (add_ftrace_hash_entry_direct(new_hash, entry->ip, entry->direct) == NULL)
 				goto free_hash;
 		}
 	}
-- 
2.52.0



From jolsa at kernel.org  Tue Dec 30 06:50:05 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Tue, 30 Dec 2025 15:50:05 +0100
Subject: [PATCHv6 bpf-next 4/9] ftrace: Add update_ftrace_direct_add function
In-Reply-To: <20251230145010.103439-1-jolsa@kernel.org>
References: <20251230145010.103439-1-jolsa@kernel.org>
Message-ID: <20251230145010.103439-5-jolsa@kernel.org>

Adding update_ftrace_direct_add function that adds all entries
(ip -> addr) provided in hash argument to direct ftrace ops
and updates its attachments.

The difference to current register_ftrace_direct is
 - hash argument that allows to register multiple ip -> direct
   entries at once
 - we can call update_ftrace_direct_add multiple times on the
   same ftrace_ops object, becase after first registration with
   register_ftrace_function_nolock, it uses ftrace_update_ops to
   update the ftrace_ops object

This change will allow us to have simple ftrace_ops for all bpf
direct interface users in following changes.

Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 include/linux/ftrace.h |   7 +++
 kernel/trace/ftrace.c  | 140 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 147 insertions(+)

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 472f2d8a4c0f..f0fcff389061 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -543,6 +543,8 @@ int unregister_ftrace_direct(struct ftrace_ops *ops, unsigned long addr,
 int modify_ftrace_direct(struct ftrace_ops *ops, unsigned long addr);
 int modify_ftrace_direct_nolock(struct ftrace_ops *ops, unsigned long addr);
 
+int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash);
+
 void ftrace_stub_direct_tramp(void);
 
 #else
@@ -569,6 +571,11 @@ static inline int modify_ftrace_direct_nolock(struct ftrace_ops *ops, unsigned l
 	return -ENODEV;
 }
 
+static inline int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash)
+{
+	return -ENODEV;
+}
+
 /*
  * This must be implemented by the architecture.
  * It is the way the ftrace direct_ops helper, when called
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 3ca3aee5f886..3d1170da1bb8 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -6275,6 +6275,146 @@ int modify_ftrace_direct(struct ftrace_ops *ops, unsigned long addr)
 	return err;
 }
 EXPORT_SYMBOL_GPL(modify_ftrace_direct);
+
+static unsigned long hash_count(struct ftrace_hash *hash)
+{
+	return hash ? hash->count : 0;
+}
+
+/**
+ * hash_add - adds two struct ftrace_hash and returns the result
+ * @a: struct ftrace_hash object
+ * @b: struct ftrace_hash object
+ *
+ * Returns struct ftrace_hash object on success, NULL on error.
+ */
+static struct ftrace_hash *hash_add(struct ftrace_hash *a, struct ftrace_hash *b)
+{
+	struct ftrace_func_entry *entry;
+	struct ftrace_hash *add;
+	int size;
+
+	size = hash_count(a) + hash_count(b);
+	if (size > 32)
+		size = 32;
+
+	add = alloc_and_copy_ftrace_hash(fls(size), a);
+	if (!add)
+		return NULL;
+
+	size = 1 << b->size_bits;
+	for (int i = 0; i < size; i++) {
+		hlist_for_each_entry(entry, &b->buckets[i], hlist) {
+			if (add_ftrace_hash_entry_direct(add, entry->ip, entry->direct) == NULL) {
+				free_ftrace_hash(add);
+				return NULL;
+			}
+		}
+	}
+	return add;
+}
+
+/**
+ * update_ftrace_direct_add - Updates @ops by adding direct
+ * callers provided in @hash
+ * @ops: The address of the struct ftrace_ops object
+ * @hash: The address of the struct ftrace_hash object
+ *
+ * This is used to add custom direct callers (ip -> addr) to @ops,
+ * specified in @hash. The @ops will be either registered or updated.
+ *
+ * Returns: zero on success. Non zero on error, which includes:
+ *  -EINVAL - The @hash is empty
+ */
+int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash)
+{
+	struct ftrace_hash *old_direct_functions = NULL;
+	struct ftrace_hash *new_direct_functions;
+	struct ftrace_hash *old_filter_hash;
+	struct ftrace_hash *new_filter_hash = NULL;
+	struct ftrace_func_entry *entry;
+	int err = -EINVAL;
+	int size;
+	bool reg;
+
+	if (!hash_count(hash))
+		return -EINVAL;
+
+	mutex_lock(&direct_mutex);
+
+	/* Make sure requested entries are not already registered. */
+	size = 1 << hash->size_bits;
+	for (int i = 0; i < size; i++) {
+		hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
+			if (__ftrace_lookup_ip(direct_functions, entry->ip))
+				goto out_unlock;
+		}
+	}
+
+	old_filter_hash = ops->func_hash ? ops->func_hash->filter_hash : NULL;
+
+	/* If there's nothing in filter_hash we need to register the ops. */
+	reg = hash_count(old_filter_hash) == 0;
+	if (reg) {
+		if (ops->func || ops->trampoline)
+			goto out_unlock;
+		if (ops->flags & FTRACE_OPS_FL_ENABLED)
+			goto out_unlock;
+	}
+
+	err = -ENOMEM;
+	new_filter_hash = hash_add(old_filter_hash, hash);
+	if (!new_filter_hash)
+		goto out_unlock;
+
+	new_direct_functions = hash_add(direct_functions, hash);
+	if (!new_direct_functions)
+		goto out_unlock;
+
+	old_direct_functions = direct_functions;
+	rcu_assign_pointer(direct_functions, new_direct_functions);
+
+	if (reg) {
+		ops->func = call_direct_funcs;
+		ops->flags |= MULTI_FLAGS;
+		ops->trampoline = FTRACE_REGS_ADDR;
+		ops->local_hash.filter_hash = new_filter_hash;
+
+		err = register_ftrace_function_nolock(ops);
+		if (err) {
+			/* restore old filter on error */
+			ops->local_hash.filter_hash = old_filter_hash;
+
+			/* cleanup for possible another register call */
+			ops->func = NULL;
+			ops->trampoline = 0;
+		} else {
+			new_filter_hash = old_filter_hash;
+		}
+	} else {
+		err = ftrace_update_ops(ops, new_filter_hash, EMPTY_HASH);
+		/*
+		 * new_filter_hash is dup-ed, so we need to release it anyway,
+		 * old_filter_hash either stays on error or is already released
+		 */
+	}
+
+	if (err) {
+		/* reset direct_functions and free the new one */
+		rcu_assign_pointer(direct_functions, old_direct_functions);
+		old_direct_functions = new_direct_functions;
+	}
+
+ out_unlock:
+	mutex_unlock(&direct_mutex);
+
+	if (old_direct_functions && old_direct_functions != EMPTY_HASH)
+		call_rcu_tasks(&old_direct_functions->rcu, register_ftrace_direct_cb);
+	free_ftrace_hash(new_filter_hash);
+
+	return err;
+}
+
 #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
 
 /**
-- 
2.52.0



From jolsa at kernel.org  Tue Dec 30 06:50:06 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Tue, 30 Dec 2025 15:50:06 +0100
Subject: [PATCHv6 bpf-next 5/9] ftrace: Add update_ftrace_direct_del function
In-Reply-To: <20251230145010.103439-1-jolsa@kernel.org>
References: <20251230145010.103439-1-jolsa@kernel.org>
Message-ID: <20251230145010.103439-6-jolsa@kernel.org>

Adding update_ftrace_direct_del function that removes all entries
(ip -> addr) provided in hash argument to direct ftrace ops and
updates its attachments.

The difference to current unregister_ftrace_direct is
 - hash argument that allows to unregister multiple ip -> direct
   entries at once
 - we can call update_ftrace_direct_del multiple times on the
   same ftrace_ops object, becase we do not need to unregister
   all entries at once, we can do it gradualy with the help of
   ftrace_update_ops function

This change will allow us to have simple ftrace_ops for all bpf
direct interface users in following changes.

Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 include/linux/ftrace.h |   6 ++
 kernel/trace/ftrace.c  | 127 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 133 insertions(+)

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index f0fcff389061..a3cc1b48c9fc 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -544,6 +544,7 @@ int modify_ftrace_direct(struct ftrace_ops *ops, unsigned long addr);
 int modify_ftrace_direct_nolock(struct ftrace_ops *ops, unsigned long addr);
 
 int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash);
+int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash);
 
 void ftrace_stub_direct_tramp(void);
 
@@ -576,6 +577,11 @@ static inline int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace
 	return -ENODEV;
 }
 
+static inline int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash)
+{
+	return -ENODEV;
+}
+
 /*
  * This must be implemented by the architecture.
  * It is the way the ftrace direct_ops helper, when called
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 3d1170da1bb8..8b75166fb223 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -6415,6 +6415,133 @@ int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash)
 	return err;
 }
 
+/**
+ * hash_sub - substracts @b from @a and returns the result
+ * @a: struct ftrace_hash object
+ * @b: struct ftrace_hash object
+ *
+ * Returns struct ftrace_hash object on success, NULL on error.
+ */
+static struct ftrace_hash *hash_sub(struct ftrace_hash *a, struct ftrace_hash *b)
+{
+	struct ftrace_func_entry *entry, *del;
+	struct ftrace_hash *sub;
+	int size;
+
+	sub = alloc_and_copy_ftrace_hash(a->size_bits, a);
+	if (!sub)
+		return NULL;
+
+	size = 1 << b->size_bits;
+	for (int i = 0; i < size; i++) {
+		hlist_for_each_entry(entry, &b->buckets[i], hlist) {
+			del = __ftrace_lookup_ip(sub, entry->ip);
+			if (WARN_ON_ONCE(!del)) {
+				free_ftrace_hash(sub);
+				return NULL;
+			}
+			remove_hash_entry(sub, del);
+			kfree(del);
+		}
+	}
+	return sub;
+}
+
+/**
+ * update_ftrace_direct_del - Updates @ops by removing its direct
+ * callers provided in @hash
+ * @ops: The address of the struct ftrace_ops object
+ * @hash: The address of the struct ftrace_hash object
+ *
+ * This is used to delete custom direct callers (ip -> addr) in
+ * @ops specified via @hash. The @ops will be either unregistered
+ * updated.
+ *
+ * Returns: zero on success. Non zero on error, which includes:
+ *  -EINVAL - The @hash is empty
+ *  -EINVAL - The @ops is not registered
+ */
+int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash)
+{
+	struct ftrace_hash *old_direct_functions = NULL;
+	struct ftrace_hash *new_direct_functions;
+	struct ftrace_hash *new_filter_hash = NULL;
+	struct ftrace_hash *old_filter_hash;
+	struct ftrace_func_entry *entry;
+	struct ftrace_func_entry *del;
+	unsigned long size;
+	int err = -EINVAL;
+
+	if (!hash_count(hash))
+		return -EINVAL;
+	if (check_direct_multi(ops))
+		return -EINVAL;
+	if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
+		return -EINVAL;
+	if (direct_functions == EMPTY_HASH)
+		return -EINVAL;
+
+	mutex_lock(&direct_mutex);
+
+	old_filter_hash = ops->func_hash ? ops->func_hash->filter_hash : NULL;
+
+	if (!hash_count(old_filter_hash))
+		goto out_unlock;
+
+	/* Make sure requested entries are already registered. */
+	size = 1 << hash->size_bits;
+	for (int i = 0; i < size; i++) {
+		hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
+			del = __ftrace_lookup_ip(direct_functions, entry->ip);
+			if (!del || del->direct != entry->direct)
+				goto out_unlock;
+		}
+	}
+
+	err = -ENOMEM;
+	new_filter_hash = hash_sub(old_filter_hash, hash);
+	if (!new_filter_hash)
+		goto out_unlock;
+
+	new_direct_functions = hash_sub(direct_functions, hash);
+	if (!new_direct_functions)
+		goto out_unlock;
+
+	/* If there's nothing left, we need to unregister the ops. */
+	if (ftrace_hash_empty(new_filter_hash)) {
+		err = unregister_ftrace_function(ops);
+		if (!err) {
+			/* cleanup for possible another register call */
+			ops->func = NULL;
+			ops->trampoline = 0;
+			ftrace_free_filter(ops);
+			ops->func_hash->filter_hash = NULL;
+		}
+	} else {
+		err = ftrace_update_ops(ops, new_filter_hash, EMPTY_HASH);
+		/*
+		 * new_filter_hash is dup-ed, so we need to release it anyway,
+		 * old_filter_hash either stays on error or is already released
+		 */
+	}
+
+	if (err) {
+		/* free the new_direct_functions */
+		old_direct_functions = new_direct_functions;
+	} else {
+		rcu_assign_pointer(direct_functions, new_direct_functions);
+	}
+
+ out_unlock:
+	mutex_unlock(&direct_mutex);
+
+	if (old_direct_functions && old_direct_functions != EMPTY_HASH)
+		call_rcu_tasks(&old_direct_functions->rcu, register_ftrace_direct_cb);
+	free_ftrace_hash(new_filter_hash);
+
+	return err;
+}
+
 #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
 
 /**
-- 
2.52.0



From jolsa at kernel.org  Tue Dec 30 06:50:07 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Tue, 30 Dec 2025 15:50:07 +0100
Subject: [PATCHv6 bpf-next 6/9] ftrace: Add update_ftrace_direct_mod function
In-Reply-To: <20251230145010.103439-1-jolsa@kernel.org>
References: <20251230145010.103439-1-jolsa@kernel.org>
Message-ID: <20251230145010.103439-7-jolsa@kernel.org>

Adding update_ftrace_direct_mod function that modifies all entries
(ip -> direct) provided in hash argument to direct ftrace ops and
updates its attachments.

The difference to current modify_ftrace_direct is:
- hash argument that allows to modify multiple ip -> direct
  entries at once

This change will allow us to have simple ftrace_ops for all bpf
direct interface users in following changes.

Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 include/linux/ftrace.h |  6 +++
 kernel/trace/ftrace.c  | 94 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 100 insertions(+)

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index a3cc1b48c9fc..6c1680ab8bf9 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -545,6 +545,7 @@ int modify_ftrace_direct_nolock(struct ftrace_ops *ops, unsigned long addr);
 
 int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash);
 int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash);
+int update_ftrace_direct_mod(struct ftrace_ops *ops, struct ftrace_hash *hash, bool do_direct_lock);
 
 void ftrace_stub_direct_tramp(void);
 
@@ -582,6 +583,11 @@ static inline int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace
 	return -ENODEV;
 }
 
+static inline int update_ftrace_direct_mod(struct ftrace_ops *ops, struct ftrace_hash *hash, bool do_direct_lock)
+{
+	return -ENODEV;
+}
+
 /*
  * This must be implemented by the architecture.
  * It is the way the ftrace direct_ops helper, when called
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 8b75166fb223..d24f28677007 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -6542,6 +6542,100 @@ int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash)
 	return err;
 }
 
+/**
+ * update_ftrace_direct_mod - Updates @ops by modifing its direct
+ * callers provided in @hash
+ * @ops: The address of the struct ftrace_ops object
+ * @hash: The address of the struct ftrace_hash object
+ * @do_direct_lock: If true lock the direct_mutex
+ *
+ * This is used to modify custom direct callers (ip -> addr) in
+ * @ops specified via @hash.
+ *
+ * This can be called from within ftrace ops_func callback with
+ * direct_mutex already locked, in which case @do_direct_lock
+ * needs to be false.
+ *
+ * Returns: zero on success. Non zero on error, which includes:
+ *  -EINVAL - The @hash is empty
+ *  -EINVAL - The @ops is not registered
+ */
+int update_ftrace_direct_mod(struct ftrace_ops *ops, struct ftrace_hash *hash, bool do_direct_lock)
+{
+	struct ftrace_func_entry *entry, *tmp;
+	static struct ftrace_ops tmp_ops = {
+		.func		= ftrace_stub,
+		.flags		= FTRACE_OPS_FL_STUB,
+	};
+	struct ftrace_hash *orig_hash;
+	unsigned long size, i;
+	int err = -EINVAL;
+
+	if (!hash_count(hash))
+		return -EINVAL;
+	if (check_direct_multi(ops))
+		return -EINVAL;
+	if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
+		return -EINVAL;
+	if (direct_functions == EMPTY_HASH)
+		return -EINVAL;
+
+	/*
+	 * We can be called from within ops_func callback with direct_mutex
+	 * already taken.
+	 */
+	if (do_direct_lock)
+		mutex_lock(&direct_mutex);
+
+	orig_hash = ops->func_hash ? ops->func_hash->filter_hash : NULL;
+	if (!orig_hash)
+		goto unlock;
+
+	/* Enable the tmp_ops to have the same functions as the direct ops */
+	ftrace_ops_init(&tmp_ops);
+	tmp_ops.func_hash = ops->func_hash;
+
+	err = register_ftrace_function_nolock(&tmp_ops);
+	if (err)
+		goto unlock;
+
+	/*
+	 * Call __ftrace_hash_update_ipmodify() here, so that we can call
+	 * ops->ops_func for the ops. This is needed because the above
+	 * register_ftrace_function_nolock() worked on tmp_ops.
+	 */
+	err = __ftrace_hash_update_ipmodify(ops, orig_hash, orig_hash, true);
+	if (err)
+		goto out;
+
+	/*
+	 * Now the ftrace_ops_list_func() is called to do the direct callers.
+	 * We can safely change the direct functions attached to each entry.
+	 */
+	mutex_lock(&ftrace_lock);
+
+	size = 1 << hash->size_bits;
+	for (i = 0; i < size; i++) {
+		hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
+			tmp = __ftrace_lookup_ip(direct_functions, entry->ip);
+			if (!tmp)
+				continue;
+			tmp->direct = entry->direct;
+		}
+	}
+
+	mutex_unlock(&ftrace_lock);
+
+out:
+	/* Removing the tmp_ops will add the updated direct callers to the functions */
+	unregister_ftrace_function(&tmp_ops);
+
+unlock:
+	if (do_direct_lock)
+		mutex_unlock(&direct_mutex);
+	return err;
+}
+
 #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
 
 /**
-- 
2.52.0



From jolsa at kernel.org  Tue Dec 30 06:50:08 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Tue, 30 Dec 2025 15:50:08 +0100
Subject: [PATCHv6 bpf-next 7/9] bpf: Add trampoline ip hash table
In-Reply-To: <20251230145010.103439-1-jolsa@kernel.org>
References: <20251230145010.103439-1-jolsa@kernel.org>
Message-ID: <20251230145010.103439-8-jolsa@kernel.org>

Following changes need to lookup trampoline based on its ip address,
adding hash table for that.

Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 include/linux/bpf.h     |  7 +++++--
 kernel/bpf/trampoline.c | 30 +++++++++++++++++++-----------
 2 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 4e7d72dfbcd4..c85677aae865 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -1325,14 +1325,17 @@ struct bpf_tramp_image {
 };
 
 struct bpf_trampoline {
-	/* hlist for trampoline_table */
-	struct hlist_node hlist;
+	/* hlist for trampoline_key_table */
+	struct hlist_node hlist_key;
+	/* hlist for trampoline_ip_table */
+	struct hlist_node hlist_ip;
 	struct ftrace_ops *fops;
 	/* serializes access to fields of this trampoline */
 	struct mutex mutex;
 	refcount_t refcnt;
 	u32 flags;
 	u64 key;
+	unsigned long ip;
 	struct {
 		struct btf_func_model model;
 		void *addr;
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index 789ff4e1f40b..bdac9d673776 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -24,9 +24,10 @@ const struct bpf_prog_ops bpf_extension_prog_ops = {
 #define TRAMPOLINE_HASH_BITS 10
 #define TRAMPOLINE_TABLE_SIZE (1 << TRAMPOLINE_HASH_BITS)
 
-static struct hlist_head trampoline_table[TRAMPOLINE_TABLE_SIZE];
+static struct hlist_head trampoline_key_table[TRAMPOLINE_TABLE_SIZE];
+static struct hlist_head trampoline_ip_table[TRAMPOLINE_TABLE_SIZE];
 
-/* serializes access to trampoline_table */
+/* serializes access to trampoline tables */
 static DEFINE_MUTEX(trampoline_mutex);
 
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
@@ -135,15 +136,15 @@ void bpf_image_ksym_del(struct bpf_ksym *ksym)
 			   PAGE_SIZE, true, ksym->name);
 }
 
-static struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
+static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
 {
 	struct bpf_trampoline *tr;
 	struct hlist_head *head;
 	int i;
 
 	mutex_lock(&trampoline_mutex);
-	head = &trampoline_table[hash_64(key, TRAMPOLINE_HASH_BITS)];
-	hlist_for_each_entry(tr, head, hlist) {
+	head = &trampoline_key_table[hash_64(key, TRAMPOLINE_HASH_BITS)];
+	hlist_for_each_entry(tr, head, hlist_key) {
 		if (tr->key == key) {
 			refcount_inc(&tr->refcnt);
 			goto out;
@@ -164,8 +165,12 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
 #endif
 
 	tr->key = key;
-	INIT_HLIST_NODE(&tr->hlist);
-	hlist_add_head(&tr->hlist, head);
+	tr->ip = ftrace_location(ip);
+	INIT_HLIST_NODE(&tr->hlist_key);
+	INIT_HLIST_NODE(&tr->hlist_ip);
+	hlist_add_head(&tr->hlist_key, head);
+	head = &trampoline_ip_table[hash_64(tr->ip, TRAMPOLINE_HASH_BITS)];
+	hlist_add_head(&tr->hlist_ip, head);
 	refcount_set(&tr->refcnt, 1);
 	mutex_init(&tr->mutex);
 	for (i = 0; i < BPF_TRAMP_MAX; i++)
@@ -846,7 +851,7 @@ void bpf_trampoline_unlink_cgroup_shim(struct bpf_prog *prog)
 					 prog->aux->attach_btf_id);
 
 	bpf_lsm_find_cgroup_shim(prog, &bpf_func);
-	tr = bpf_trampoline_lookup(key);
+	tr = bpf_trampoline_lookup(key, 0);
 	if (WARN_ON_ONCE(!tr))
 		return;
 
@@ -866,7 +871,7 @@ struct bpf_trampoline *bpf_trampoline_get(u64 key,
 {
 	struct bpf_trampoline *tr;
 
-	tr = bpf_trampoline_lookup(key);
+	tr = bpf_trampoline_lookup(key, tgt_info->tgt_addr);
 	if (!tr)
 		return NULL;
 
@@ -902,7 +907,8 @@ void bpf_trampoline_put(struct bpf_trampoline *tr)
 	 * fexit progs. The fentry-only trampoline will be freed via
 	 * multiple rcu callbacks.
 	 */
-	hlist_del(&tr->hlist);
+	hlist_del(&tr->hlist_key);
+	hlist_del(&tr->hlist_ip);
 	if (tr->fops) {
 		ftrace_free_filter(tr->fops);
 		kfree(tr->fops);
@@ -1175,7 +1181,9 @@ static int __init init_trampolines(void)
 	int i;
 
 	for (i = 0; i < TRAMPOLINE_TABLE_SIZE; i++)
-		INIT_HLIST_HEAD(&trampoline_table[i]);
+		INIT_HLIST_HEAD(&trampoline_key_table[i]);
+	for (i = 0; i < TRAMPOLINE_TABLE_SIZE; i++)
+		INIT_HLIST_HEAD(&trampoline_ip_table[i]);
 	return 0;
 }
 late_initcall(init_trampolines);
-- 
2.52.0



From jolsa at kernel.org  Tue Dec 30 06:50:09 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Tue, 30 Dec 2025 15:50:09 +0100
Subject: [PATCHv6 bpf-next 8/9] ftrace: Factor ftrace_ops ops_func interface
In-Reply-To: <20251230145010.103439-1-jolsa@kernel.org>
References: <20251230145010.103439-1-jolsa@kernel.org>
Message-ID: <20251230145010.103439-9-jolsa@kernel.org>

We are going to remove "ftrace_ops->private == bpf_trampoline" setup
in following changes.

Adding ip argument to ftrace_ops_func_t callback function, so we can
use it to look up the trampoline.

Acked-by: Steven Rostedt (Google) <rostedt at goodmis.org>
Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 include/linux/ftrace.h  | 2 +-
 kernel/bpf/trampoline.c | 3 ++-
 kernel/trace/ftrace.c   | 6 +++---
 3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 6c1680ab8bf9..781b613781a6 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -403,7 +403,7 @@ enum ftrace_ops_cmd {
  *        Negative on failure. The return value is dependent on the
  *        callback.
  */
-typedef int (*ftrace_ops_func_t)(struct ftrace_ops *op, enum ftrace_ops_cmd cmd);
+typedef int (*ftrace_ops_func_t)(struct ftrace_ops *op, unsigned long ip, enum ftrace_ops_cmd cmd);
 
 #ifdef CONFIG_DYNAMIC_FTRACE
 
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index bdac9d673776..e5a0d58ed6dc 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -33,7 +33,8 @@ static DEFINE_MUTEX(trampoline_mutex);
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
 static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mutex);
 
-static int bpf_tramp_ftrace_ops_func(struct ftrace_ops *ops, enum ftrace_ops_cmd cmd)
+static int bpf_tramp_ftrace_ops_func(struct ftrace_ops *ops, unsigned long ip,
+				     enum ftrace_ops_cmd cmd)
 {
 	struct bpf_trampoline *tr = ops->private;
 	int ret = 0;
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index d24f28677007..02030f62d737 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -2075,7 +2075,7 @@ static int __ftrace_hash_update_ipmodify(struct ftrace_ops *ops,
 				 */
 				if (!ops->ops_func)
 					return -EBUSY;
-				ret = ops->ops_func(ops, FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_SELF);
+				ret = ops->ops_func(ops, rec->ip, FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_SELF);
 				if (ret)
 					return ret;
 			} else if (is_ipmodify) {
@@ -9058,7 +9058,7 @@ static int prepare_direct_functions_for_ipmodify(struct ftrace_ops *ops)
 				if (!op->ops_func)
 					return -EBUSY;
 
-				ret = op->ops_func(op, FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_PEER);
+				ret = op->ops_func(op, ip, FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_PEER);
 				if (ret)
 					return ret;
 			}
@@ -9105,7 +9105,7 @@ static void cleanup_direct_functions_after_ipmodify(struct ftrace_ops *ops)
 
 			/* The cleanup is optional, ignore any errors */
 			if (found_op && op->ops_func)
-				op->ops_func(op, FTRACE_OPS_CMD_DISABLE_SHARE_IPMODIFY_PEER);
+				op->ops_func(op, ip, FTRACE_OPS_CMD_DISABLE_SHARE_IPMODIFY_PEER);
 		}
 	}
 	mutex_unlock(&direct_mutex);
-- 
2.52.0



From jolsa at kernel.org  Tue Dec 30 06:50:10 2025
From: jolsa at kernel.org (Jiri Olsa)
Date: Tue, 30 Dec 2025 15:50:10 +0100
Subject: [PATCHv6 bpf-next 9/9] bpf,x86: Use single ftrace_ops for direct calls
In-Reply-To: <20251230145010.103439-1-jolsa@kernel.org>
References: <20251230145010.103439-1-jolsa@kernel.org>
Message-ID: <20251230145010.103439-10-jolsa@kernel.org>

Using single ftrace_ops for direct calls update instead of allocating
ftrace_ops object for each trampoline.

With single ftrace_ops object we can use update_ftrace_direct_* api
that allows multiple ip sites updates on single ftrace_ops object.

Adding HAVE_SINGLE_FTRACE_DIRECT_OPS config option to be enabled on
each arch that supports this.

At the moment we can enable this only on x86 arch, because arm relies
on ftrace_ops object representing just single trampoline image (stored
in ftrace_ops::direct_call). Archs that do not support this will continue
to use *_ftrace_direct api.

Signed-off-by: Jiri Olsa <jolsa at kernel.org>
---
 arch/x86/Kconfig        |   1 +
 kernel/bpf/trampoline.c | 220 ++++++++++++++++++++++++++++++++++------
 kernel/trace/Kconfig    |   3 +
 kernel/trace/ftrace.c   |   7 +-
 4 files changed, 200 insertions(+), 31 deletions(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 80527299f859..53bf2cf7ff6f 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -336,6 +336,7 @@ config X86
 	select SCHED_SMT			if SMP
 	select ARCH_SUPPORTS_SCHED_CLUSTER	if SMP
 	select ARCH_SUPPORTS_SCHED_MC		if SMP
+	select HAVE_SINGLE_FTRACE_DIRECT_OPS	if X86_64 && DYNAMIC_FTRACE_WITH_DIRECT_CALLS
 
 config INSTRUCTION_DECODER
 	def_bool y
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index e5a0d58ed6dc..248cd368fa37 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -33,12 +33,40 @@ static DEFINE_MUTEX(trampoline_mutex);
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
 static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mutex);
 
+#ifdef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS
+static struct bpf_trampoline *direct_ops_ip_lookup(struct ftrace_ops *ops, unsigned long ip)
+{
+	struct hlist_head *head_ip;
+	struct bpf_trampoline *tr;
+
+	mutex_lock(&trampoline_mutex);
+	head_ip = &trampoline_ip_table[hash_64(ip, TRAMPOLINE_HASH_BITS)];
+	hlist_for_each_entry(tr, head_ip, hlist_ip) {
+		if (tr->ip == ip)
+			goto out;
+	}
+	tr = NULL;
+out:
+	mutex_unlock(&trampoline_mutex);
+	return tr;
+}
+#else
+static struct bpf_trampoline *direct_ops_ip_lookup(struct ftrace_ops *ops, unsigned long ip)
+{
+	return ops->private;
+}
+#endif /* CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS */
+
 static int bpf_tramp_ftrace_ops_func(struct ftrace_ops *ops, unsigned long ip,
 				     enum ftrace_ops_cmd cmd)
 {
-	struct bpf_trampoline *tr = ops->private;
+	struct bpf_trampoline *tr;
 	int ret = 0;
 
+	tr = direct_ops_ip_lookup(ops, ip);
+	if (!tr)
+		return -EINVAL;
+
 	if (cmd == FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_SELF) {
 		/* This is called inside register_ftrace_direct_multi(), so
 		 * tr->mutex is already locked.
@@ -137,6 +165,162 @@ void bpf_image_ksym_del(struct bpf_ksym *ksym)
 			   PAGE_SIZE, true, ksym->name);
 }
 
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
+#ifdef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS
+/*
+ * We have only single direct_ops which contains all the direct call
+ * sites and is the only global ftrace_ops for all trampolines.
+ *
+ * We use 'update_ftrace_direct_*' api for attachment.
+ */
+struct ftrace_ops direct_ops = {
+	.ops_func = bpf_tramp_ftrace_ops_func,
+};
+
+static int direct_ops_alloc(struct bpf_trampoline *tr)
+{
+	tr->fops = &direct_ops;
+	return 0;
+}
+
+static void direct_ops_free(struct bpf_trampoline *tr) { }
+
+static struct ftrace_hash *hash_from_ip(struct bpf_trampoline *tr, void *ptr)
+{
+	unsigned long ip, addr = (unsigned long) ptr;
+	struct ftrace_hash *hash;
+
+	ip = ftrace_location(tr->ip);
+	if (!ip)
+		return NULL;
+	hash = alloc_ftrace_hash(FTRACE_HASH_DEFAULT_BITS);
+	if (!hash)
+		return NULL;
+	if (bpf_trampoline_use_jmp(tr->flags))
+		addr = ftrace_jmp_set(addr);
+	if (!add_ftrace_hash_entry_direct(hash, ip, addr)) {
+		free_ftrace_hash(hash);
+		return NULL;
+	}
+	return hash;
+}
+
+static int direct_ops_add(struct bpf_trampoline *tr, void *addr)
+{
+	struct ftrace_hash *hash = hash_from_ip(tr, addr);
+	int err;
+
+	if (!hash)
+		return -ENOMEM;
+	err = update_ftrace_direct_add(tr->fops, hash);
+	free_ftrace_hash(hash);
+	return err;
+}
+
+static int direct_ops_del(struct bpf_trampoline *tr, void *addr)
+{
+	struct ftrace_hash *hash = hash_from_ip(tr, addr);
+	int err;
+
+	if (!hash)
+		return -ENOMEM;
+	err = update_ftrace_direct_del(tr->fops, hash);
+	free_ftrace_hash(hash);
+	return err;
+}
+
+static int direct_ops_mod(struct bpf_trampoline *tr, void *addr, bool lock_direct_mutex)
+{
+	struct ftrace_hash *hash = hash_from_ip(tr, addr);
+	int err;
+
+	if (!hash)
+		return -ENOMEM;
+	err = update_ftrace_direct_mod(tr->fops, hash, lock_direct_mutex);
+	free_ftrace_hash(hash);
+	return err;
+}
+#else
+/*
+ * We allocate ftrace_ops object for each trampoline and it contains
+ * call site specific for that trampoline.
+ *
+ * We use *_ftrace_direct api for attachment.
+ */
+static int direct_ops_alloc(struct bpf_trampoline *tr)
+{
+	tr->fops = kzalloc(sizeof(struct ftrace_ops), GFP_KERNEL);
+	if (!tr->fops)
+		return -ENOMEM;
+	tr->fops->private = tr;
+	tr->fops->ops_func = bpf_tramp_ftrace_ops_func;
+	return 0;
+}
+
+static void direct_ops_free(struct bpf_trampoline *tr)
+{
+	if (!tr->fops)
+		return;
+	ftrace_free_filter(tr->fops);
+	kfree(tr->fops);
+}
+
+static int direct_ops_add(struct bpf_trampoline *tr, void *ptr)
+{
+	unsigned long addr = (unsigned long) ptr;
+	struct ftrace_ops *ops = tr->fops;
+	int ret;
+
+	if (bpf_trampoline_use_jmp(tr->flags))
+		addr = ftrace_jmp_set(addr);
+
+	ret = ftrace_set_filter_ip(ops, tr->ip, 0, 1);
+	if (ret)
+		return ret;
+	return register_ftrace_direct(ops, addr);
+}
+
+static int direct_ops_del(struct bpf_trampoline *tr, void *addr)
+{
+	return unregister_ftrace_direct(tr->fops, (long)addr, false);
+}
+
+static int direct_ops_mod(struct bpf_trampoline *tr, void *ptr, bool lock_direct_mutex)
+{
+	unsigned long addr = (unsigned long) ptr;
+	struct ftrace_ops *ops = tr->fops;
+
+	if (bpf_trampoline_use_jmp(tr->flags))
+		addr = ftrace_jmp_set(addr);
+	if (lock_direct_mutex)
+		return modify_ftrace_direct(ops, addr);
+	return modify_ftrace_direct_nolock(ops, addr);
+}
+#endif /* CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS */
+#else
+static void direct_ops_free(struct bpf_trampoline *tr) { }
+
+static int direct_ops_alloc(struct bpf_trampoline *tr)
+{
+	return 0;
+}
+
+static int direct_ops_add(struct bpf_trampoline *tr, void *addr)
+{
+	return -ENODEV;
+}
+
+static int direct_ops_del(struct bpf_trampoline *tr, void *addr)
+{
+	return -ENODEV;
+}
+
+static int direct_ops_mod(struct bpf_trampoline *tr, void *ptr, bool lock_direct_mutex)
+{
+	return -ENODEV;
+}
+#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
+
 static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
 {
 	struct bpf_trampoline *tr;
@@ -154,16 +338,11 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
 	tr = kzalloc(sizeof(*tr), GFP_KERNEL);
 	if (!tr)
 		goto out;
-#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
-	tr->fops = kzalloc(sizeof(struct ftrace_ops), GFP_KERNEL);
-	if (!tr->fops) {
+	if (direct_ops_alloc(tr)) {
 		kfree(tr);
 		tr = NULL;
 		goto out;
 	}
-	tr->fops->private = tr;
-	tr->fops->ops_func = bpf_tramp_ftrace_ops_func;
-#endif
 
 	tr->key = key;
 	tr->ip = ftrace_location(ip);
@@ -206,7 +385,7 @@ static int unregister_fentry(struct bpf_trampoline *tr, u32 orig_flags,
 	int ret;
 
 	if (tr->func.ftrace_managed)
-		ret = unregister_ftrace_direct(tr->fops, (long)old_addr, false);
+		ret = direct_ops_del(tr, old_addr);
 	else
 		ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr, NULL);
 
@@ -220,15 +399,7 @@ static int modify_fentry(struct bpf_trampoline *tr, u32 orig_flags,
 	int ret;
 
 	if (tr->func.ftrace_managed) {
-		unsigned long addr = (unsigned long) new_addr;
-
-		if (bpf_trampoline_use_jmp(tr->flags))
-			addr = ftrace_jmp_set(addr);
-
-		if (lock_direct_mutex)
-			ret = modify_ftrace_direct(tr->fops, addr);
-		else
-			ret = modify_ftrace_direct_nolock(tr->fops, addr);
+		ret = direct_ops_mod(tr, new_addr, lock_direct_mutex);
 	} else {
 		ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr,
 						   new_addr);
@@ -251,15 +422,7 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
 	}
 
 	if (tr->func.ftrace_managed) {
-		unsigned long addr = (unsigned long) new_addr;
-
-		if (bpf_trampoline_use_jmp(tr->flags))
-			addr = ftrace_jmp_set(addr);
-
-		ret = ftrace_set_filter_ip(tr->fops, (unsigned long)ip, 0, 1);
-		if (ret)
-			return ret;
-		ret = register_ftrace_direct(tr->fops, addr);
+		ret = direct_ops_add(tr, new_addr);
 	} else {
 		ret = bpf_trampoline_update_fentry(tr, 0, NULL, new_addr);
 	}
@@ -910,10 +1073,7 @@ void bpf_trampoline_put(struct bpf_trampoline *tr)
 	 */
 	hlist_del(&tr->hlist_key);
 	hlist_del(&tr->hlist_ip);
-	if (tr->fops) {
-		ftrace_free_filter(tr->fops);
-		kfree(tr->fops);
-	}
+	direct_ops_free(tr);
 	kfree(tr);
 out:
 	mutex_unlock(&trampoline_mutex);
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index bfa2ec46e075..d7042a09fe46 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -50,6 +50,9 @@ config HAVE_DYNAMIC_FTRACE_WITH_REGS
 config HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
 	bool
 
+config HAVE_SINGLE_FTRACE_DIRECT_OPS
+	bool
+
 config HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS
 	bool
 
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 02030f62d737..4ed910d3d00d 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -2631,8 +2631,13 @@ unsigned long ftrace_find_rec_direct(unsigned long ip)
 static void call_direct_funcs(unsigned long ip, unsigned long pip,
 			      struct ftrace_ops *ops, struct ftrace_regs *fregs)
 {
-	unsigned long addr = READ_ONCE(ops->direct_call);
+	unsigned long addr;
 
+#ifdef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS
+	addr = ftrace_find_rec_direct(ip);
+#else
+	addr = READ_ONCE(ops->direct_call);
+#endif
 	if (!addr)
 		return;
 
-- 
2.52.0



From chunkuang.hu at kernel.org  Tue Dec 30 07:05:06 2025
From: chunkuang.hu at kernel.org (Chun-Kuang Hu)
Date: Tue, 30 Dec 2025 15:05:06 +0000
Subject: [PATCH 3/3] drm/mediatek: mtk_disp_rdma: Enable/disable interrupt
 on bind/unbind
In-Reply-To: <51af30ea-dce9-49b8-a5e1-0ee8e9644879@collabora.com>
References: <20250924103708.19071-1-angelogioacchino.delregno@collabora.com>
 <20250924103708.19071-4-angelogioacchino.delregno@collabora.com>
 <fb2c7169b3c3e2e376ee0b092699735dc38bcbb6.camel@mediatek.com> <51af30ea-dce9-49b8-a5e1-0ee8e9644879@collabora.com>
Message-ID: <CAAOTY_-y6QTu7txOQZoDrYih_0tH4MATku0orOKAqU5cL7oFcw@mail.gmail.com>

AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com> ?
2025?10?28??? ??3:49???
>
> Il 28/10/25 10:49, CK Hu (???) ha scritto:
> > On Wed, 2025-09-24 at 12:37 +0200, AngeloGioacchino Del Regno wrote:
> >> External email : Please do not click links or open attachments until you have verified the sender or the content.
> >>
> >>
> >> The RDMA driver is installing an ISR in the probe function but, if
> >> the component is not bound yet, the interrupt handler may call the
> >> vblank_cb ahead of time (while probing other drivers) or too late
> >> (while removing other drivers), possibly accessing memory that it
> >> should not try to access by reusing stale pointers.
> >>
> >> In order to fix this, like done in the OVL driver, add a new `irq`
> >> member to struct mtk_disp_ovl and then set the NOAUTOEN flag to
> >> the irq before installing the ISR to manually disable and clear
> >> the hwirqs with register writes, and enable_irq() and disable_irq()
> >> in the bind and unbind callbacks respectively.
> >>
> >> Fixes: 119f5173628a ("drm/mediatek: Add DRM Driver for Mediatek SoC MT8173.")
> >> Link: https://lore.kernel.org/r/20250402083628.20111-6-angelogioacchino.delregno at collabora.com
> >> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
> >> ---
> >>   drivers/gpu/drm/mediatek/mtk_disp_rdma.c | 34 ++++++++++++++----------
> >>   1 file changed, 20 insertions(+), 14 deletions(-)
> >>
> >> diff --git a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
> >> index c9d41d75e7f2..9fd9bb1ee544 100644
> >> --- a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
> >> +++ b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
> >> @@ -81,6 +81,7 @@ struct mtk_disp_rdma_data {
> >>   struct mtk_disp_rdma {
> >>          struct clk                      *clk;
> >>          void __iomem                    *regs;
> >> +       int                             irq;
> >>          struct cmdq_client_reg          cmdq_reg;
> >>          const struct mtk_disp_rdma_data *data;
> >>          void                            (*vblank_cb)(void *data);
> >> @@ -295,13 +296,23 @@ void mtk_rdma_layer_config(struct device *dev, unsigned int idx,
> >>   static int mtk_disp_rdma_bind(struct device *dev, struct device *master,
> >>                                void *data)
> >>   {
> >> -       return 0;
> >> +       struct mtk_disp_rdma *priv = dev_get_drvdata(dev);
> >> +
> >> +       /* Disable and clear pending interrupts */
> >> +       writel(0x0, priv->regs + DISP_REG_RDMA_INT_ENABLE);
> >> +       writel(0x0, priv->regs + DISP_REG_RDMA_INT_STATUS);
> >> +
> >> +       enable_irq(priv->irq);
> >>
> >> +       return 0;
> >>   }
> >>
> >>   static void mtk_disp_rdma_unbind(struct device *dev, struct device *master,
> >>                                   void *data)
> >>   {
> >> +       struct mtk_disp_rdma *priv = dev_get_drvdata(dev);
> >> +
> >> +       disable_irq(priv->irq);
> >>   }
> >>
> >>   static const struct component_ops mtk_disp_rdma_component_ops = {
> >> @@ -313,16 +324,15 @@ static int mtk_disp_rdma_probe(struct platform_device *pdev)
> >>   {
> >>          struct device *dev = &pdev->dev;
> >>          struct mtk_disp_rdma *priv;
> >> -       int irq;
> >>          int ret;
> >>
> >>          priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> >>          if (!priv)
> >>                  return -ENOMEM;
> >>
> >> -       irq = platform_get_irq(pdev, 0);
> >> -       if (irq < 0)
> >> -               return irq;
> >> +       priv->irq = platform_get_irq(pdev, 0);
> >> +       if (priv->irq < 0)
> >> +               return priv->irq;
> >>
> >>          priv->clk = devm_clk_get(dev, NULL);
> >>          if (IS_ERR(priv->clk))
> >> @@ -345,21 +355,17 @@ static int mtk_disp_rdma_probe(struct platform_device *pdev)
> >>          if (ret && (ret != -EINVAL))
> >>                  return dev_err_probe(dev, ret, "Failed to get rdma fifo size\n");
> >>
> >> -       /* Disable and clear pending interrupts */
> >> -       writel(0x0, priv->regs + DISP_REG_RDMA_INT_ENABLE);
> >> -       writel(0x0, priv->regs + DISP_REG_RDMA_INT_STATUS);
> >
> > Pending interrupt is cleared here, and interrupt is disabled here.
> > So the problem you mention would not happen.
> >
>
> When unbinding the component, the interrupt is not cleared nor disabled.
>
> If there is any pending interrupt while unbinding (or if the HW raises an interrupt
> after rdma gets unbound) the ISR will produce a use-after-free issue.

In mtk_drm_kms_deinit(), it call drm_atomic_helper_shutdown() before
component_unbind_all().
I think hardware should be disabled when drm_atomic_helper_shutdown().
If hardware is not disabled, we should find out the reason.
I like a symmetry design. After bind all sub driver, then enable
hardware. disable hardware before unbind sub driver.
This assume that hardware is disabled when boot up.
If the hardware is enabled in bootloader stage, the tricky way is to
disable interrupt before request irq in probe.

Regards,
Chun-Kuang.

>
> I wrote this after experiencing the issue that I described in the commit message,
> didn't just go and casually write code.
>
> I also want to remind you that use-after-free may also be a security concern.
>
> Regards,
> Angelo
>
> > Regards,
> > CK
> >
> >> -
> >> -       ret = devm_request_irq(dev, irq, mtk_disp_rdma_irq_handler,
> >> -                              IRQF_TRIGGER_NONE, dev_name(dev), priv);
> >> -       if (ret < 0)
> >> -               return dev_err_probe(dev, ret, "Failed to request irq %d\n", irq);
> >> -
> >>          priv->data = of_device_get_match_data(dev);
> >>
> >>          platform_set_drvdata(pdev, priv);
> >>
> >>          pm_runtime_enable(dev);
> >>
> >> +       ret = devm_request_irq(dev, priv->irq, mtk_disp_rdma_irq_handler,
> >> +                              IRQF_NO_AUTOEN, dev_name(dev), priv);
> >> +       if (ret < 0)
> >> +               return dev_err_probe(dev, ret, "Failed to request irq %d\n", priv->irq);
> >> +
> >>          ret = component_add(dev, &mtk_disp_rdma_component_ops);
> >>          if (ret) {
> >>                  pm_runtime_disable(dev);
> >> --
> >> 2.51.0
> >>
> >>
> >
>
>


From mikko.rapeli at linaro.org  Tue Dec 30 07:06:14 2025
From: mikko.rapeli at linaro.org (Mikko Rapeli)
Date: Tue, 30 Dec 2025 17:06:14 +0200
Subject: ARM64_BTI_KERNEL and gcc? (was Re: Revisiting c0a454b9044f )
In-Reply-To: <aHj-6xGYQ6RDvUHE@J2N7QTR9R3>
References: <20250714195205.GA3723043@ax162>
 <aHY4d46ehF-j_pbw@J2N7QTR9R3>
 <20250716182641.GA2746700@ax162>
 <aHj-6xGYQ6RDvUHE@J2N7QTR9R3>
Message-ID: <aVPqZjjTWt13rmKV@nuoska>

Hi,

On Thu, Jul 17, 2025 at 02:47:23PM +0100, Mark Rutland wrote:
> On Wed, Jul 16, 2025 at 12:26:41PM -0600, Nathan Chancellor wrote:
> > On Tue, Jul 15, 2025 at 12:16:07PM +0100, Mark Rutland wrote:
> > > The concern from the kernel side is simply whether we get unexpected BTI
> > > failures. IIUC so long as compiler and linker agree we should be good,
> > > and we simply need to forbid broken combinations.
> > 
> > Mark Brown did mention something about the module loader as well so I
> > was not sure if that was relevant here.
> 
> Sorry, I had forgotten anout that, and that is a concern.
> 
> If a single module has executable sections placed more than 128MiB apart
> we'd potentially have the same problem with any cross-section branch.
> Truly handling that would be quite tricky and require a fair amount of
> rework, so the best bet is probably to reject loading modules that are
> too large (or where we specifically find such cross-section branches
> needing veneers).
> 
> Note that exported symbols and address-taken functions should have a
> BTI, so this only really matters for cross-section calls within a single
> module.
> 
> I suspect it should be relatively simple but I'm not sure exactly where
> to plumb that in. I can put that on my TODO list if no-one gets around
> to it.
> 
> > > > Or should the kernel adjust its expectations now that the ABI and
> > > > toolchains all agree?
> > > 
> > > Yes, we can probably rework this.
> > > 
> > > IIUC we'd need to forbid BTI with:
> > > 
> > > * GCC + old GNU LD
> > > * GCC + old LLD
> > > * new clang + old GNU LD
> > > * new clang + old LLD
> > > 
> > > ... and can enable BTI otherwise.
> > > 
> > > Does that make sense to you?
> > 
> > So something like this if I understand correctly?
> > 
> > Cheers,
> > Nathan
> > 
> > diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> > index 393d71124f5d..fe523f9f2d61 100644
> > --- a/arch/arm64/Kconfig
> > +++ b/arch/arm64/Kconfig
> > @@ -2097,7 +2097,11 @@ config ARM64_BTI_KERNEL
> >  	# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94697
> >  	depends on !CC_IS_GCC || GCC_VERSION >= 100100
> >  	# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106671
> > -	depends on !CC_IS_GCC
> > +	# https://sourceware.org/bugzilla/show_bug.cgi?id=30076
> > +	depends on !CC_IS_GCC || LD_VERSION >= 24100 || LLD_VERSION >= 210000
> > +	# https://github.com/llvm/llvm-project/commit/7af2b51e761f49974a64c3009882239cea618f2a
> > +	# https://github.com/llvm/llvm-project/commit/098b0d18add97dea94e16006486b2fded65e228d
> > +	depends on !CC_IS_CLANG || CLANG_VERSION < 210000 || (CLANG_VERSION >= 210000 && (LD_VERSION >= 24100 || LLD_VERSION >= 210000))
> 
> Yep, something like that.
> 
> I was thinking that we could factor this out into a separate config,
> like we have for BUILTIN_RETURN_ADDRESS_STRIPS_PAC, as that'll make it
> easier to avoid duplication, e.g.
> 
> | config TOOLCHAIN_HAS_WORKING_BTI
> | 	bool
> | 	# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94697
> | 	default n if CC_IS_GCC && GCC_VERSION < 100100
> |	# Newer LD/LLD handle BTI in veneers automatically
> | 	default y if LD_IS_LLD && LLD_VERSION >= 210000
> | 	default y if LD_IS_GNU && LD_VERSION >= 24100
> | 	# Newer clang requires newer LD/LLD above
> | 	default y if CC_IS_CLANG && CLANG_VERSION < 210000
> | 	default n
> 
> ... and we can easily extend that to handle fixed stable versions, like with
> BUILTIN_RETURN_ADDRESS_STRIPS_PAC.

Has there been patches to implement this somewhere?

I'm checking yocto genericarm64 kernel config and noticed that ARM64_BTI_KERNEL
was effectively disabled with gcc in generated .config. Maybe some additional
tagging or config could be used to mark it as not supported with gcc
since the disappearing "CONFIG_ARM64_BTI_KERNEL=y" was not expected, and
enabling this is recomended in a number of places including
arch/arm64/configs/hardening.config and
https://kspp.github.io/Recommended_Settings#arm64

Cheers,

-Mikko


From ulf.hansson at linaro.org  Tue Dec 30 07:33:39 2025
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Tue, 30 Dec 2025 16:33:39 +0100
Subject: [PATCH 4/4] mmc: sdhci: aspeed: Simplify with scoped for each OF
 child loop
In-Reply-To: <20251224124431.208434-8-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251224124431.208434-5-krzysztof.kozlowski@oss.qualcomm.com> <20251224124431.208434-8-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <CAPDyKFp3X0EeiGRHLQqzE3vkVoLmOwi=1813S32sLTqXab43gQ@mail.gmail.com>

On Wed, 24 Dec 2025 at 13:44, Krzysztof Kozlowski
<krzysztof.kozlowski at oss.qualcomm.com> wrote:
>
> Use scoped for-each loop when iterating over device nodes to make code a
> bit simpler.
>
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

All patches in the series applied for next, thanks!

Kind regards
Uffe


> ---
>  drivers/mmc/host/sdhci-of-aspeed.c | 5 ++---
>  1 file changed, 2 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspeed.c
> index ca97b01996b1..4296def69436 100644
> --- a/drivers/mmc/host/sdhci-of-aspeed.c
> +++ b/drivers/mmc/host/sdhci-of-aspeed.c
> @@ -519,7 +519,7 @@ static struct platform_driver aspeed_sdhci_driver = {
>  static int aspeed_sdc_probe(struct platform_device *pdev)
>
>  {
> -       struct device_node *parent, *child;
> +       struct device_node *parent;
>         struct aspeed_sdc *sdc;
>         int ret;
>
> @@ -548,12 +548,11 @@ static int aspeed_sdc_probe(struct platform_device *pdev)
>         dev_set_drvdata(&pdev->dev, sdc);
>
>         parent = pdev->dev.of_node;
> -       for_each_available_child_of_node(parent, child) {
> +       for_each_available_child_of_node_scoped(parent, child) {
>                 struct platform_device *cpdev;
>
>                 cpdev = of_platform_device_create(child, NULL, &pdev->dev);
>                 if (!cpdev) {
> -                       of_node_put(child);
>                         ret = -ENODEV;
>                         goto err_clk;
>                 }
> --
> 2.51.0
>


From maz at kernel.org  Tue Dec 30 07:34:25 2025
From: maz at kernel.org (Marc Zyngier)
Date: Tue, 30 Dec 2025 15:34:25 +0000
Subject: [PATCH 0/1] KVM: arm64: Fix hyp VA size between layout and MMU
In-Reply-To: <20251223193440.1441657-1-pekangas@google.com>
References: <20251223193440.1441657-1-pekangas@google.com>
Message-ID: <87qzscdlvi.wl-maz@kernel.org>

On Tue, 23 Dec 2025 19:34:39 +0000,
Petteri Kangaslampi <pekangas at google.com> wrote:
> 
> All,
> 
> In the KVM initialization code, kvm_mmu_init() and
> kvm_compute_layout() use different logic when determining the
> hypervisor's virtual address space size. Specifically, the MMU code
> uses the larger of vabits_actual (the kernel's VA size) and
> IDMAP_VA_BITS (48 bits), while the VA layout code just uses the
> kernel's VA size.
> 
> This means that if the kernel is configured with a VA size of less
> than 48 bits (like happens in our environment), the assumptions used
> to calculate hyp_physvirt_offset and the code that determines VA
> ranges to use for mappings in hyp/nvhe/mm.c get out of sync, which can
> results in mapping failures.
> 
> The immediate fix is pretty obvious and attached here. This is against
> 6.12 but I don't think this code has changed recently. I think longer
> term refactoring knowledge of the hypervisor's address space into one
> place might be helpful; currently it is a bit spread out.

I'm sorry, but posting a patch against a kernel that is over a year
old doesn't help. It may apply, but it doesn't mean it works. Please
post a tested patch against the latest released kernel, or even
better, the latest -rc.

Thanks,

	M.

-- 
Jazz isn't dead. It just smells funny.


From andrew at lunn.ch  Tue Dec 30 07:35:27 2025
From: andrew at lunn.ch (Andrew Lunn)
Date: Tue, 30 Dec 2025 16:35:27 +0100
Subject: [PATCH v2 4/4] arm64: dts: imx8mn: Add ifm VHIP4 EvalBoard v1
 and v2
In-Reply-To: <dc29e774-07fb-4d0e-a88a-27d4ec49d060@nabladev.com>
References: <20251229193706.73564-1-marex@nabladev.com>
 <20251229193706.73564-4-marex@nabladev.com>
 <e3d305ce-cdfa-4a11-bd54-9648b12a013f@lunn.ch>
 <dc29e774-07fb-4d0e-a88a-27d4ec49d060@nabladev.com>
Message-ID: <51825dee-c2c9-4d94-b741-ffdc2fbfa773@lunn.ch>

On Tue, Dec 30, 2025 at 02:34:14PM +0100, Marek Vasut wrote:
> On 12/30/25 11:46 AM, Andrew Lunn wrote:
> > > +&fec1 {
> > > +	fsl,magic-packet;
> > 
> > Upps, i probably cut out too much context. This FEC is connected to the Ethernet switch.
> > 
> > WoL for a port connected to a switch? Have you tested this? Normally
> > you would have WoL on each port of the switch, and not on the conduit
> > interface.
> > 
> > > +&fec1 {
> > > +	fsl,magic-packet;
> > 
> > Have you tested WoL?
> > 
> > > +&fec1 {
> > > +	fsl,magic-packet;
> > 
> > WoL again?
> I don't think WOL is used on this device at all. Would you suggest removing
> the fsl,magic-packet properties ?

Yes.

	Andrew


From maz at kernel.org  Tue Dec 30 07:37:45 2025
From: maz at kernel.org (Marc Zyngier)
Date: Tue, 30 Dec 2025 15:37:45 +0000
Subject: [PATCH 1/1] KVM: arm64: Fix hyp VA size between layout and MMU
In-Reply-To: <20251223193440.1441657-2-pekangas@google.com>
References: <20251223193440.1441657-1-pekangas@google.com>
	<20251223193440.1441657-2-pekangas@google.com>
Message-ID: <87pl7wdlpy.wl-maz@kernel.org>

On Tue, 23 Dec 2025 19:34:40 +0000,
Petteri Kangaslampi <pekangas at google.com> wrote:
> 
> Use a consistent hypervisor VA size between memory layout and MMU
> initialization logic when the kernel is configured for less than
> IDMAP_VA_BITS of VA space.
>
> Signed-off-by: Petteri Kangaslampi <pekangas at google.com>
> ---
>  arch/arm64/kvm/va_layout.c | 17 ++++++++++++-----
>  1 file changed, 12 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/arm64/kvm/va_layout.c b/arch/arm64/kvm/va_layout.c
> index f6ca0193a96f..76cdd62550e1 100644
> --- a/arch/arm64/kvm/va_layout.c
> +++ b/arch/arm64/kvm/va_layout.c
> @@ -49,7 +49,7 @@ static void init_hyp_physvirt_offset(void)
>  
>  /*
>   * We want to generate a hyp VA with the following format (with V ==
> - * vabits_actual):
> + * hypervisor VA bits):
>   *
>   *  63 ... V |     V-1    | V-2 .. tag_lsb | tag_lsb - 1 .. 0
>   *  ---------------------------------------------------------
> @@ -62,10 +62,17 @@ __init void kvm_compute_layout(void)
>  {
>  	phys_addr_t idmap_addr = __pa_symbol(__hyp_idmap_text_start);
>  	u64 hyp_va_msb;
> +	u32 hyp_va_bits;
> +
> +	/*
> +	 * We use the bigger of IDMAP_VA_BITS and kernel VA size as the
> +	 * hypervisor VA address space size. See mmu.c.
> +	 */
> +	hyp_va_bits = max(IDMAP_VA_BITS, vabits_actual);

Instead of duplicating the logic from kvm_mmu_init(), I'd rather you
make sure there is a single place where the EL2 VA width is computed,
and use that consistently all over the place.

Since you were complaining about the spread of the VA layout handling,
starting with this sort of consolidation seems like a decent starting
point.

Thanks,

	M.

-- 
Jazz isn't dead. It just smells funny.


From chunkuang.hu at kernel.org  Tue Dec 30 07:41:04 2025
From: chunkuang.hu at kernel.org (Chun-Kuang Hu)
Date: Tue, 30 Dec 2025 15:41:04 +0000
Subject: [PATCH next] drm/mediatek: Fix platform_get_irq() error checking
In-Reply-To: <aSW0p5sqnJVJsqDO@stanley.mountain>
References: <aSW0p5sqnJVJsqDO@stanley.mountain>
Message-ID: <CAAOTY__nif43taCWWdxfFqmtC=KibgJZ2AuUohiS1EdhXdDbow@mail.gmail.com>

Hi, Dan:

Dan Carpenter <dan.carpenter at linaro.org> ? 2025?11?25??? ??1:52???
>
> The platform_get_irq() function returns negative error codes on failure
> and positive non-zero IRQ numbers on success.  It never returns NULL. Fix
> the error checking to look for negatives, and change "hdmi->irq" from
> unsigned int to just int.

Applied to mediatek-drm-fixes [1], thanks.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/chunkuang.hu/linux.git/log/?h=mediatek-drm-fixes

Regards,
Chun-Kuang.

>
> Fixes: 8d0f79886273 ("drm/mediatek: Introduce HDMI/DDC v2 for MT8195/MT8188")
> Signed-off-by: Dan Carpenter <dan.carpenter at linaro.org>
> ---
>  drivers/gpu/drm/mediatek/mtk_hdmi_common.c | 2 +-
>  drivers/gpu/drm/mediatek/mtk_hdmi_common.h | 2 +-
>  2 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_common.c b/drivers/gpu/drm/mediatek/mtk_hdmi_common.c
> index e78eb0876f16..bd7f8c56ec9c 100644
> --- a/drivers/gpu/drm/mediatek/mtk_hdmi_common.c
> +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_common.c
> @@ -303,7 +303,7 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi, struct platform_device
>                 return dev_err_probe(dev, ret, "Failed to get clocks\n");
>
>         hdmi->irq = platform_get_irq(pdev, 0);
> -       if (!hdmi->irq)
> +       if (hdmi->irq < 0)
>                 return hdmi->irq;
>
>         hdmi->regs = device_node_to_regmap(dev->of_node);
> diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_common.h b/drivers/gpu/drm/mediatek/mtk_hdmi_common.h
> index de5e064585f8..7a644bbf5843 100644
> --- a/drivers/gpu/drm/mediatek/mtk_hdmi_common.h
> +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_common.h
> @@ -168,7 +168,7 @@ struct mtk_hdmi {
>         bool audio_enable;
>         bool powered;
>         bool enabled;
> -       unsigned int irq;
> +       int irq;
>         enum hdmi_hpd_state hpd;
>         hdmi_codec_plugged_cb plugged_cb;
>         struct device *codec_dev;
> --
> 2.51.0
>


From chunkuang.hu at kernel.org  Tue Dec 30 07:50:13 2025
From: chunkuang.hu at kernel.org (Chun-Kuang Hu)
Date: Tue, 30 Dec 2025 15:50:13 +0000
Subject: [PATCH] drm/mediatek: mtk_hdmi_v2: Fix return type of mtk_hdmi_v2_tmds_char_rate_valid()
In-Reply-To: <20251125-drm-mediatek-hdmi-v2-wifpts-v1-1-a6c7582cf69a@kernel.org>
References: <20251125-drm-mediatek-hdmi-v2-wifpts-v1-1-a6c7582cf69a@kernel.org>
Message-ID: <CAAOTY_-hGe-yWK-iSXDefEPJN9bc8A_r=kNirBAyHgCPhqoAvw@mail.gmail.com>

Hi, Nathan:

Nathan Chancellor <nathan at kernel.org> ? 2025?11?25??? ??10:14???
>
> When building with -Wincompatible-function-pointer-types-strict, a
> warning designed to catch kernel control flow integrity (kCFI) issues at
> build time, there is an instance in the new HDMI v2 drm/mediatek code:
>
>   drivers/gpu/drm/mediatek/mtk_hdmi_v2.c:1331:31: error: incompatible function pointer types initializing 'enum drm_mode_status (*)(const struct drm_bridge *, const struct drm_display_mode *, unsigned long long)' with an expression of type 'int (const struct drm_bridge *, const struct drm_display_mode *, unsigned long long)' [-Werror,-Wincompatible-function-pointer-types-strict]
>    1331 |         .hdmi_tmds_char_rate_valid = mtk_hdmi_v2_hdmi_tmds_char_rate_valid,
>         |                                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> While 'int' and 'enum drm_mode_status' are ABI compatible, hence no
> regular warning from -Wincompatible-function-pointer-types, the mismatch
> will trigger a kCFI violation when mtk_hdmi_v2_tmds_char_rate_valid() is
> called indirectly.
>
> Update the return type of mtk_hdmi_v2_tmds_char_rate_valid() to be 'enum
> drm_mode_status' to clear up the warning and kCFI violation.

Applied to mediatek-drm-fixes [1], thanks.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/chunkuang.hu/linux.git/log/?h=mediatek-drm-fixes

Regards,
Chun-Kuang.

>
> Fixes: 8d0f79886273 ("drm/mediatek: Introduce HDMI/DDC v2 for MT8195/MT8188")
> Signed-off-by: Nathan Chancellor <nathan at kernel.org>
> ---
>  drivers/gpu/drm/mediatek/mtk_hdmi_v2.c | 7 ++++---
>  1 file changed, 4 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c b/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c
> index c272e1e74b7d..454b8b93b834 100644
> --- a/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c
> +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c
> @@ -1120,9 +1120,10 @@ static void mtk_hdmi_v2_hpd_disable(struct drm_bridge *bridge)
>         mtk_hdmi_v2_disable(hdmi);
>  }
>
> -static int mtk_hdmi_v2_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge,
> -                                                const struct drm_display_mode *mode,
> -                                                unsigned long long tmds_rate)
> +static enum drm_mode_status
> +mtk_hdmi_v2_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge,
> +                                     const struct drm_display_mode *mode,
> +                                     unsigned long long tmds_rate)
>  {
>         if (mode->clock < MTK_HDMI_V2_CLOCK_MIN)
>                 return MODE_CLOCK_LOW;
>
> ---
> base-commit: a846505a193d7492ad3531e33cacfca31e4bcdd1
> change-id: 20251125-drm-mediatek-hdmi-v2-wifpts-d67b55175609
>
> Best regards,
> --
> Nathan Chancellor <nathan at kernel.org>
>


From chunkuang.hu at kernel.org  Tue Dec 30 07:57:28 2025
From: chunkuang.hu at kernel.org (Chun-Kuang Hu)
Date: Tue, 30 Dec 2025 15:57:28 +0000
Subject: [PATCH 1/2] drm/mediatek: mtk_hdmi_ddc_v2: Add transfer abort on
 timeout cases
In-Reply-To: <20251205-mtk-hdmi-ddc-v2-fixes-v1-1-260dd0d320f4@collabora.com>
References: <20251205-mtk-hdmi-ddc-v2-fixes-v1-0-260dd0d320f4@collabora.com> <20251205-mtk-hdmi-ddc-v2-fixes-v1-1-260dd0d320f4@collabora.com>
Message-ID: <CAAOTY_-vwFnSOS8gqVvyxJm_0vC8BPUkAhbnkenOxRgt=DBhjQ@mail.gmail.com>

Hi, Louis:

Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com> ? 2025?12?5??? ??2:22???
>
> During a read or write transfer, the mtk_hdmi_ddc_v2 driver polls the
> DDC_I2C_IN_PROG bit of HPD_DDC_STATUS register to check if the transfer
> completes but do no particular action if a timeout is reached. It could
> lead the next transfer attempts to fail because the faulty transfer was
> not aborted. So, add in both low level read and write functions a abort
> action by writing the DDC_CTRL register with the ABORT_XFER command
> value.

Applied to mediatek-drm-fixes [1], thanks.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/chunkuang.hu/linux.git/log/?h=mediatek-drm-fixes

Regards,
Chun-Kuang.

>
> Fixes: 8d0f79886273 ("drm/mediatek: Introduce HDMI/DDC v2 for MT8195/MT8188")
> Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c | 10 ++++++++++
>  1 file changed, 10 insertions(+)
>
> diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c b/drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c
> index b844e2c10f28060baef64bd36c5464758b08e162..6ae7cbba8cb6dacf46c2f7ab74a2d7446d698b69 100644
> --- a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c
> +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c
> @@ -96,6 +96,11 @@ static int mtk_ddc_wr_one(struct mtk_hdmi_ddc *ddc, u16 addr_id,
>                                        !(val & DDC_I2C_IN_PROG), 500, 1000);
>         if (ret) {
>                 dev_err(ddc->dev, "DDC I2C write timeout\n");
> +
> +               /* Abort transfer if it is still in progress */
> +               regmap_update_bits(ddc->regs, DDC_CTRL, DDC_CTRL_CMD,
> +                                  FIELD_PREP(DDC_CTRL_CMD, DDC_CMD_ABORT_XFER));
> +
>                 return ret;
>         }
>
> @@ -179,6 +184,11 @@ static int mtk_ddcm_read_hdmi(struct mtk_hdmi_ddc *ddc, u16 uc_dev,
>                                                500 * (temp_length + 5));
>                 if (ret) {
>                         dev_err(ddc->dev, "Timeout waiting for DDC I2C\n");
> +
> +                       /* Abort transfer if it is still in progress */
> +                       regmap_update_bits(ddc->regs, DDC_CTRL, DDC_CTRL_CMD,
> +                                          FIELD_PREP(DDC_CTRL_CMD, DDC_CMD_ABORT_XFER));
> +
>                         return ret;
>                 }
>
>
> --
> 2.52.0
>


From chunkuang.hu at kernel.org  Tue Dec 30 08:02:23 2025
From: chunkuang.hu at kernel.org (Chun-Kuang Hu)
Date: Tue, 30 Dec 2025 16:02:23 +0000
Subject: [PATCH 2/2] drm/mediatek: mtk_hdmi_ddc_v2: Fix multi-byte writes
In-Reply-To: <20251205-mtk-hdmi-ddc-v2-fixes-v1-2-260dd0d320f4@collabora.com>
References: <20251205-mtk-hdmi-ddc-v2-fixes-v1-0-260dd0d320f4@collabora.com> <20251205-mtk-hdmi-ddc-v2-fixes-v1-2-260dd0d320f4@collabora.com>
Message-ID: <CAAOTY_-zPCQJLXwejQnjk-G9dK2x1yEG-Cukgb6XXG-+abdb3g@mail.gmail.com>

Hi, Louis:

Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com> ? 2025?12?5??? ??2:22???
>
> Currently, the mtk_hdmi_ddc_v2 driver sends a i2c message by calling
> the mtk_ddc_wr_one function for each byte of the payload to setup
> SI2C_CTRL and DDC_CTRL registers, and perform a sequential write
> transfer of one byte at a time to the target device. This leads to
> incorrect transfers as the target address (at least) is also sent each
> time.
>
> So, rename mtk_ddc_wr_one function to mtk_ddcm_write_hdmi to match the
> read function name (mtk_ddcm_read_hdmi) and modify its behaviour to
> send all payload data in a single sequential write transfer by filling
> the transfer fifo first then starting the transfer with a size equal to
> the payload size and not one anymore.

Applied to mediatek-drm-fixes [1], thanks.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/chunkuang.hu/linux.git/log/?h=mediatek-drm-fixes

Regards,
Chun-Kuang.

>
> Fixes: 8d0f79886273 ("drm/mediatek: Introduce HDMI/DDC v2 for MT8195/MT8188")
> Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud at collabora.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c | 48 ++++++++++++++----------------
>  1 file changed, 23 insertions(+), 25 deletions(-)
>
> diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c b/drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c
> index 6ae7cbba8cb6dacf46c2f7ab74a2d7446d698b69..d937219fdb7ee0ed6a4ac25e950f69f90ff431a3 100644
> --- a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c
> +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c
> @@ -66,11 +66,19 @@ static int mtk_ddc_check_and_rise_low_bus(struct mtk_hdmi_ddc *ddc)
>         return 0;
>  }
>
> -static int mtk_ddc_wr_one(struct mtk_hdmi_ddc *ddc, u16 addr_id,
> -                         u16 offset_id, u8 *wr_data)
> +static int mtk_ddcm_write_hdmi(struct mtk_hdmi_ddc *ddc, u16 addr_id,
> +                              u16 offset_id, u16 data_cnt, u8 *wr_data)
>  {
>         u32 val;
> -       int ret;
> +       int ret, i;
> +
> +       /* Don't allow transfer with a size over than the transfer fifo size
> +        * (16 byte)
> +        */
> +       if (data_cnt > 16) {
> +               dev_err(ddc->dev, "Invalid DDCM write request\n");
> +               return -EINVAL;
> +       }
>
>         /* If down, rise bus for write operation */
>         mtk_ddc_check_and_rise_low_bus(ddc);
> @@ -78,16 +86,21 @@ static int mtk_ddc_wr_one(struct mtk_hdmi_ddc *ddc, u16 addr_id,
>         regmap_update_bits(ddc->regs, HPD_DDC_CTRL, HPD_DDC_DELAY_CNT,
>                            FIELD_PREP(HPD_DDC_DELAY_CNT, DDC2_DLY_CNT));
>
> +       /* In case there is no payload data, just do a single write for the
> +        * address only
> +        */
>         if (wr_data) {
> -               regmap_write(ddc->regs, SI2C_CTRL,
> -                            FIELD_PREP(SI2C_ADDR, SI2C_ADDR_READ) |
> -                            FIELD_PREP(SI2C_WDATA, *wr_data) |
> -                            SI2C_WR);
> +               /* Fill transfer fifo with payload data */
> +               for (i = 0; i < data_cnt; i++) {
> +                       regmap_write(ddc->regs, SI2C_CTRL,
> +                                    FIELD_PREP(SI2C_ADDR, SI2C_ADDR_READ) |
> +                                    FIELD_PREP(SI2C_WDATA, wr_data[i]) |
> +                                    SI2C_WR);
> +               }
>         }
> -
>         regmap_write(ddc->regs, DDC_CTRL,
>                      FIELD_PREP(DDC_CTRL_CMD, DDC_CMD_SEQ_WRITE) |
> -                    FIELD_PREP(DDC_CTRL_DIN_CNT, wr_data == NULL ? 0 : 1) |
> +                    FIELD_PREP(DDC_CTRL_DIN_CNT, wr_data == NULL ? 0 : data_cnt) |
>                      FIELD_PREP(DDC_CTRL_OFFSET, offset_id) |
>                      FIELD_PREP(DDC_CTRL_ADDR, addr_id));
>         usleep_range(1000, 1250);
> @@ -260,24 +273,9 @@ static int mtk_hdmi_fg_ddc_data_read(struct mtk_hdmi_ddc *ddc, u16 b_dev,
>  static int mtk_hdmi_ddc_fg_data_write(struct mtk_hdmi_ddc *ddc, u16 b_dev,
>                                       u8 data_addr, u16 data_cnt, u8 *pr_data)
>  {
> -       int i, ret;
> -
>         regmap_set_bits(ddc->regs, HDCP2X_POL_CTRL, HDCP2X_DIS_POLL_EN);
> -       /*
> -        * In case there is no payload data, just do a single write for the
> -        * address only
> -        */
> -       if (data_cnt == 0)
> -               return mtk_ddc_wr_one(ddc, b_dev, data_addr, NULL);
> -
> -       i = 0;
> -       do {
> -               ret = mtk_ddc_wr_one(ddc, b_dev, data_addr + i, pr_data + i);
> -               if (ret)
> -                       return ret;
> -       } while (++i < data_cnt);
>
> -       return 0;
> +       return mtk_ddcm_write_hdmi(ddc, b_dev, data_addr, data_cnt, pr_data);
>  }
>
>  static int mtk_hdmi_ddc_v2_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
>
> --
> 2.52.0
>


From chunkuang.hu at kernel.org  Tue Dec 30 08:13:30 2025
From: chunkuang.hu at kernel.org (Chun-Kuang Hu)
Date: Tue, 30 Dec 2025 16:13:30 +0000
Subject: [PATCH v8 1/1] drm/mediatek: Move DP training to hotplug thread
In-Reply-To: <20251223061755.7717-1-liankun.yang@mediatek.com>
References: <20251223061755.7717-1-liankun.yang@mediatek.com>
Message-ID: <CAAOTY_9VL6U5TM6hnMZ8sJKO5rDUHuMPtNwOs_B7LwJQt7_-VQ@mail.gmail.com>

Hi, Liankun:

Liankun Yang <liankun.yang at mediatek.com> ? 2025?12?23??? ??6:34???
>
> By adjusting the order of link training and relocating it to HPD,
> link training can identify the usability of each lane in the current link.
>
> It also supports handling signal instability and weakness due to
> environmental issues, enabling the acquisition of a stable bandwidth
> for the current link. Subsequently, DP work can proceed based on
> the actual maximum bandwidth.
>
> It should training in the hpd event thread.
> Check the mode with lane count and link rate of training.
>
> If we're eDP and capabilities were already parsed we can skip
> reading again because eDP panels aren't hotpluggable hence the
> caps and training information won't ever change in a boot life
>
> Therefore, bridge typec judgment is required for edp training in
> atomic_enable function.
>
> `mtk_dp_parse_capabilities` is related to DP training, it is
> used in `mtk_dp_hpd_event_thread` before DP training, and then only
> used by eDP when read edid.
>
> -Modify part of in `mtk_dp_bridge_atomic_disable`
>     if (mtk_dp->train_info.cable_plugged_in) {
>        drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D3);
>        usleep_range(2000, 3000);
>     }
>
>     /* power off aux */
>     mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
>                 DP_PWR_STATE_BANDGAP_TPLL,
>                 DP_PWR_STATE_MASK);
>
> -Modify part of in `mtk_dp_aux_panel_poweron(mtk_dp, false);`
>     if (pwron) {
>        ....
>     } else {
>        /* power off panel */
>        drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D3);
>        usleep_range(2000, 3000);
>
>        /* power off aux */
>        mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
>                         DP_PWR_STATE_BANDGAP_TPLL,
>                         DP_PWR_STATE_MASK);
>     }
>
> The `mtk_dp_aux_panel_poweron` function fails to align.
> Within the `mtk_dp_hpd_event_thread`, if DP is disconnected,
> the `mtk_dp_aux_panel_poweron` function will write from `aux`
> to `DPRX`, causing a failure and thus preventing symmetry.
>
> This shows the current timings after the DP cable is plugged in,
> as well as the modified timings.
>
> current timings:                Fix timings:
>
> mtk_dp_hpd_event_thread()       mtk_dp_hpd_event_thread()
>                                 (including DP link training)
>         |                               |
>        ...                             ...
> mtk_dp_bridge_mode_valid()      mtk_dp_bridge_mode_valid()
>         |
>        ...                             ...
> mtk_dp_bridge_atomic_check()    mtk_dp_bridge_atomic_check()
>         |
>        ...                             ...
> mtk_dp_bridge_atomic_enable()   mtk_dp_bridge_atomic_enable()
> (including DP link training)
>
> PS:
> 1. "..." represents ommited steps;
>
> 2. `mtk_dp_bridge_mode_valid()` calculates the bandwidth using the
> current lane count and link rate, and then filters each mode to
> determine if it supports returning a status.
>
> 3. In the `drm_display_mode_to_videomode(&crtc_state->adjusted_mode,
> &mtk_dp->info.vm);` function, within the `mtk_dp_bridge_atomic_check()`
> function, `adjusted_mode` sets the currently selected display mode for
> the DRM.
>
> 4. DP link training tests the signal conditions of the link between
> DPTX and DPRX, and selects the lane count and link rate that meet
> the signal conditions.
>
> 5. For example, the platform support DP 4lane 5.4G,
> but panel A support DP 2lane 5.4G.
>
>    This is a time sequence:
>
>    a).Plug in panel A. According to the platform, it can output 4K60Hz.
>    b).Timing mode set 4K 60Hz(Including in mtk_dp_bridge_atomic_check
>    function).
>    c).Atomic enable(Based on panel A ability, training pass 2lane
>    5.4G).
>    d).Finally, due to 2lane 5.4G bandwidth limitation, the platform
>    cannot output 4K 60Hz, resulting in a black sreen.
>
>    If apply this patch.
>
>    a).Plug in panel A.
>    b).Training pass 2lane 5.4G
>    c).Timing mode set 2K 60Hz(Based on the 2lane 5.4G bandwidth limit
>    and including in mtk_dp_bridge_atomic_che

Applied to mediatek-drm-next [1], thanks.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/chunkuang.hu/linux.git/log/?h=mediatek-drm-next

Regards,
Chun-Kuang.

>
> Signed-off-by: Liankun Yang <liankun.yang at mediatek.com>
> ---
> Change in V8:
> - Update the commit message.
> - Update the commit title.
> Per suggestion from the previous thread:
> https://patchwork.kernel.org/project/linux-mediatek/patch/20251104085957.1175-2-liankun.yang at mediatek.com/
>
> Change in V7:
> - Separate the edp part.
> Per suggestion from the previous thread:
> https://patchwork.kernel.org/project/linux-mediatek/patch/20250822120506.15486-1-liankun.yang at mediatek.com/
>
> Change in V6:
> - Fixed power on in atomic enable.
> Per suggestion from the previous thread:
> https://patchwork.kernel.org/project/linux-mediatek/patch/20250630080824.7107-1-liankun.yang at mediatek.com/
>
> Change in V5:
> - Fixed the issue that the 4th version of the patch caused DP to have no screen.
> Per suggestion from the previous thread:
> https://patchwork.kernel.org/project/linux-mediatek/patch/20250625095446.31726-1-liankun.yang at mediatek.com/
>
> Change in V4:
> - Tested the internal eDP display on MT8195 Tomato and it is fine.
> Per suggestion from the previous thread:
> https://patchwork.kernel.org/project/linux-mediatek/patch/20250318140236.13650-2-liankun.yang at mediatek.com/
>
> Change in V3:
> - Remove 'mtk_dp->enabled = false" in atomic disable.
> - Remove 'mtk_dp->enabled = true" in atomic enable.
> Per suggestion from the previous thread:
> https://patchwork.kernel.org/project/linux-mediatek/patch/20241025083036.8829-4-liankun.yang at mediatek.com/
>
> Change in V2:
> - Adjust DP training timing.
> - Adjust parse capabilities timing.
> - Add power on/off for connect/disconnect.
> Per suggestion from the previous thread:
> https://patchwork.kernel.org/project/linux-mediatek/patch/20240315015233.2023-1-liankun.yang at mediatek.com/
> ---
>  drivers/gpu/drm/mediatek/mtk_dp.c | 57 ++++++++++++++++++++-----------
>  1 file changed, 38 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
> index b0b1e158600f..5e67dab6e2e9 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
> @@ -1976,6 +1976,7 @@ static irqreturn_t mtk_dp_hpd_event_thread(int hpd, void *dev)
>         struct mtk_dp *mtk_dp = dev;
>         unsigned long flags;
>         u32 status;
> +       int ret;
>
>         if (mtk_dp->need_debounce && mtk_dp->train_info.cable_plugged_in)
>                 msleep(100);
> @@ -1994,9 +1995,28 @@ static irqreturn_t mtk_dp_hpd_event_thread(int hpd, void *dev)
>                         memset(&mtk_dp->info.audio_cur_cfg, 0,
>                                sizeof(mtk_dp->info.audio_cur_cfg));
>
> +                       mtk_dp->enabled = false;
> +                       /* power off aux */
> +                       mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
> +                                          DP_PWR_STATE_BANDGAP_TPLL,
> +                                          DP_PWR_STATE_MASK);
> +
>                         mtk_dp->need_debounce = false;
>                         mod_timer(&mtk_dp->debounce_timer,
>                                   jiffies + msecs_to_jiffies(100) - 1);
> +               } else {
> +                       mtk_dp_aux_panel_poweron(mtk_dp, true);
> +
> +                       ret = mtk_dp_parse_capabilities(mtk_dp);
> +                       if (ret)
> +                               drm_err(mtk_dp->drm_dev, "Can't parse capabilities\n");
> +
> +                       /* Training */
> +                       ret = mtk_dp_training(mtk_dp);
> +                       if (ret)
> +                               drm_err(mtk_dp->drm_dev, "Training failed, %d\n", ret);
> +
> +                       mtk_dp->enabled = true;
>                 }
>         }
>
> @@ -2168,7 +2188,8 @@ static const struct drm_edid *mtk_dp_edid_read(struct drm_bridge *bridge,
>          * Parse capability here to let atomic_get_input_bus_fmts and
>          * mode_valid use the capability to calculate sink bitrates.
>          */
> -       if (mtk_dp_parse_capabilities(mtk_dp)) {
> +       if (mtk_dp->bridge.type == DRM_MODE_CONNECTOR_eDP &&
> +           mtk_dp_parse_capabilities(mtk_dp)) {
>                 drm_err(mtk_dp->drm_dev, "Can't parse capabilities\n");
>                 drm_edid_free(drm_edid);
>                 drm_edid = NULL;
> @@ -2366,13 +2387,15 @@ static void mtk_dp_bridge_atomic_enable(struct drm_bridge *bridge,
>                 return;
>         }
>
> -       mtk_dp_aux_panel_poweron(mtk_dp, true);
> +       if (mtk_dp->data->bridge_type == DRM_MODE_CONNECTOR_eDP) {
> +               mtk_dp_aux_panel_poweron(mtk_dp, true);
>
> -       /* Training */
> -       ret = mtk_dp_training(mtk_dp);
> -       if (ret) {
> -               drm_err(mtk_dp->drm_dev, "Training failed, %d\n", ret);
> -               goto power_off_aux;
> +               /* Training */
> +               ret = mtk_dp_training(mtk_dp);
> +               if (ret) {
> +                       drm_err(mtk_dp->drm_dev, "Training failed, %d\n", ret);
> +                       goto power_off_aux;
> +               }
>         }
>
>         ret = mtk_dp_video_config(mtk_dp);
> @@ -2392,7 +2415,9 @@ static void mtk_dp_bridge_atomic_enable(struct drm_bridge *bridge,
>                        sizeof(mtk_dp->info.audio_cur_cfg));
>         }
>
> -       mtk_dp->enabled = true;
> +       if (mtk_dp->data->bridge_type == DRM_MODE_CONNECTOR_eDP)
> +               mtk_dp->enabled = true;
> +
>         mtk_dp_update_plugged_status(mtk_dp);
>
>         return;
> @@ -2407,21 +2432,15 @@ static void mtk_dp_bridge_atomic_disable(struct drm_bridge *bridge,
>  {
>         struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
>
> -       mtk_dp->enabled = false;
> +       if (mtk_dp->data->bridge_type == DRM_MODE_CONNECTOR_eDP) {
> +               mtk_dp->enabled = false;
> +               mtk_dp_aux_panel_poweron(mtk_dp, false);
> +       }
> +
>         mtk_dp_update_plugged_status(mtk_dp);
>         mtk_dp_video_enable(mtk_dp, false);
>         mtk_dp_audio_mute(mtk_dp, true);
>
> -       if (mtk_dp->train_info.cable_plugged_in) {
> -               drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D3);
> -               usleep_range(2000, 3000);
> -       }
> -
> -       /* power off aux */
> -       mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
> -                          DP_PWR_STATE_BANDGAP_TPLL,
> -                          DP_PWR_STATE_MASK);
> -
>         /* SDP path reset sw*/
>         mtk_dp_sdp_path_reset(mtk_dp);
>
> --
> 2.45.2
>


From thomas.petazzoni at bootlin.com  Tue Dec 30 08:15:48 2025
From: thomas.petazzoni at bootlin.com (Thomas Petazzoni)
Date: Tue, 30 Dec 2025 17:15:48 +0100
Subject: [PATCH v4 2/2] arm64: dts: freescale: add support for NXP
 i.MX93 FRDM
In-Reply-To: <20251218-fpg-nxp-imx93-frdm-v4-2-cd3a9f6ac89a@pengutronix.de>
References: <20251218-fpg-nxp-imx93-frdm-v4-0-cd3a9f6ac89a@pengutronix.de>
	<20251218-fpg-nxp-imx93-frdm-v4-2-cd3a9f6ac89a@pengutronix.de>
Message-ID: <20251230171548.67289601@windsurf>

Hello Fabian,

On Thu, 18 Dec 2025 12:39:22 +0100
Fabian Pflug <f.pflug at pengutronix.de> wrote:

> The FRDM i.MX 93 development board is a low-cost and compact development
> board featuring the i.MX93 applications processor.
> 
> It features:
> - Dual Cortex-A55
> - 2 GB LPDDR4X / LPDDR4
> - 32 GB eMMC5.1
> - MicroSD slot
> - GbE RJ45 x 2
> - USB2.0 1x Type C, 1x Type A
> 
> This file is based upon the one provided by nxp in their own kernel and
> yocto meta layer for the device, but adapted for mainline.
> 
> Signed-off-by: Haidong Zheng <haidong.zheng at nxp.com>
> Signed-off-by: Danwei Luo <danwei.luo at nxp.com>
> Signed-off-by: Lei Xu <lei.xu at nxp.com>
> Signed-off-by: Fabian Pflug <f.pflug at pengutronix.de>

Thanks for your patch! I tested it on top of Linux 6.18.2, using
upstream U-Boot 2025.10, and a few seconds after boot I get the
following kernel splat:

[   28.754128] irq 100: nobody cared (try booting with the "irqpoll" option)
[   28.760922] CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted 6.18.2-00001-g05c40156cdc2 #4 PREEMPT 
[   28.760931] Hardware name: NXP i.MX93 11X11 FRDM board (DT)
[   28.760935] Call trace:
[   28.760938]  show_stack+0x18/0x30 (C)
[   28.760953]  dump_stack_lvl+0x60/0x80
[   28.760959]  dump_stack+0x18/0x24
[   28.760964]  __report_bad_irq+0x4c/0xec
[   28.760971]  note_interrupt+0x328/0x370
[   28.760978]  handle_irq_event+0x9c/0xb0
[   28.760987]  handle_level_irq+0xe4/0x180
[   28.760992]  handle_irq_desc+0x34/0x60
[   28.760999]  generic_handle_domain_irq+0x1c/0x30
[   28.761005]  vf610_gpio_irq_handler+0x78/0x110
[   28.761014]  handle_irq_desc+0x34/0x60
[   28.761020]  generic_handle_domain_irq+0x1c/0x30
[   28.761027]  gic_handle_irq+0x4c/0x120
[   28.761031]  call_on_irq_stack+0x30/0x48
[   28.761036]  do_interrupt_handler+0x80/0x90
[   28.761042]  el1_interrupt+0x3c/0x60
[   28.761049]  el1h_64_irq_handler+0x18/0x30
[   28.761054]  el1h_64_irq+0x6c/0x70
[   28.761059]  cpuidle_enter_state+0xa8/0x300 (P)
[   28.761065]  cpuidle_enter+0x38/0x50
[   28.761072]  do_idle+0x1e4/0x260
[   28.761080]  cpu_startup_entry+0x34/0x40
[   28.761086]  rest_init+0xdc/0xe0
[   28.761092]  console_on_rootfs+0x0/0x6c
[   28.761100]  __primary_switched+0x88/0x90
[   28.761107] handlers:
[   28.876539] [<0000000028c5c2d1>] irq_default_primary_handler threaded [<0000000024992bf8>] pca953x_irq_handler
[   28.886532] Disabling IRQ #100

I'm using a stripped-down arm64 defconfig file, which I have attached.

IRQ 100 is:

100:     100001          0 gpio-vf610  27 Level     1-0022

I see the PMIC interrupt and the RTC interrupts are routed to the I2C
GPIO expander at 1-0022, so I imagine either the PMIC or the RTC are
triggering an interrupt (left enabled by U-Boot), and the kernel isn't
compiled with the driver for either the PMIC or the RTC, and therefore
there's no IRQ handler?

(I confess I didn't investigate more than that at this point.)

Thomas
-- 
Thomas Petazzoni, co-owner and CEO, Bootlin
Embedded Linux and Kernel engineering and training
https://bootlin.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: defconfig
Type: application/octet-stream
Size: 22430 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251230/817214ae/attachment-0001.obj>

From thomas.petazzoni at bootlin.com  Tue Dec 30 08:24:27 2025
From: thomas.petazzoni at bootlin.com (Thomas Petazzoni)
Date: Tue, 30 Dec 2025 17:24:27 +0100
Subject: [PATCH v4 2/2] arm64: dts: freescale: add support for NXP
 i.MX93 FRDM
In-Reply-To: <20251230171548.67289601@windsurf>
References: <20251218-fpg-nxp-imx93-frdm-v4-0-cd3a9f6ac89a@pengutronix.de>
	<20251218-fpg-nxp-imx93-frdm-v4-2-cd3a9f6ac89a@pengutronix.de>
	<20251230171548.67289601@windsurf>
Message-ID: <20251230172427.4f22ac7c@windsurf>

Hello (again),

On Tue, 30 Dec 2025 17:15:48 +0100
Thomas Petazzoni <thomas.petazzoni at bootlin.com> wrote:

> I see the PMIC interrupt and the RTC interrupts are routed to the I2C
> GPIO expander at 1-0022, so I imagine either the PMIC or the RTC are
> triggering an interrupt (left enabled by U-Boot), and the kernel isn't
> compiled with the driver for either the PMIC or the RTC, and therefore
> there's no IRQ handler?
> 
> (I confess I didn't investigate more than that at this point.)

Upon closer inspection, I in fact get thousands over IRQ #100 per
seconds right after boot, until the point where it reaches 100000 IRQ
events, and the splat appears, with the IRQ being subsequently
disabled. So it's not just one interrupt, but a storm of it.

Thomas
-- 
Thomas Petazzoni, co-owner and CEO, Bootlin
Embedded Linux and Kernel engineering and training
https://bootlin.com


From daniel at makrotopia.org  Tue Dec 30 08:56:11 2025
From: daniel at makrotopia.org (Daniel Golle)
Date: Tue, 30 Dec 2025 16:56:11 +0000
Subject: [PATCH] phy: adjust function name reference
In-Reply-To: <20251230140601.93474-1-Julia.Lawall@inria.fr>
References: <20251230140601.93474-1-Julia.Lawall@inria.fr>
Message-ID: <aVQEKwj38I1Coj2L@makrotopia.org>

On Tue, Dec 30, 2025 at 03:06:01PM +0100, Julia Lawall wrote:
> There is no function clk_bulk_prepare_disable.  Refer instead to
> clk_bulk_disable_unprepare, which is called in the function
> defined just below.
> 
> Signed-off-by: Julia Lawall <Julia.Lawall at inria.fr>

Thanks for spotting this obviously wrong comment!

Reviewed-by: Daniel Golle <daniel at makrotopia.org>

> 
> ---
>  drivers/phy/mediatek/phy-mtk-xfi-tphy.c |    2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/phy/mediatek/phy-mtk-xfi-tphy.c b/drivers/phy/mediatek/phy-mtk-xfi-tphy.c
> index 1a0b7484f525..100a50d0e861 100644
> --- a/drivers/phy/mediatek/phy-mtk-xfi-tphy.c
> +++ b/drivers/phy/mediatek/phy-mtk-xfi-tphy.c
> @@ -353,7 +353,7 @@ static int mtk_xfi_tphy_power_on(struct phy *phy)
>   * Disable and unprepare all clocks previously enabled.
>   *
>   * Return:
> - * See clk_bulk_prepare_disable().
> + * See clk_bulk_disable_unprepare().
>   */
>  static int mtk_xfi_tphy_power_off(struct phy *phy)
>  {
> 
> 


From manivannan.sadhasivam at oss.qualcomm.com  Tue Dec 30 09:04:23 2025
From: manivannan.sadhasivam at oss.qualcomm.com (Manivannan Sadhasivam)
Date: Tue, 30 Dec 2025 22:34:23 +0530
Subject: [PATCH] dt-bindings: PCI: socionext,uniphier-pcie: Fix
 interrupt controller node name
In-Reply-To: <20251215212456.3317558-1-robh@kernel.org>
References: <20251215212456.3317558-1-robh@kernel.org>
Message-ID: <176711426350.2039520.18416499850960877912.b4-ty@kernel.org>


On Mon, 15 Dec 2025 15:24:56 -0600, Rob Herring (Arm) wrote:
> The child node name in use by .dts files and the driver is
> "legacy-interrupt-controller", not "interrupt-controller".
> 
> 

Applied, thanks!

[1/1] dt-bindings: PCI: socionext,uniphier-pcie: Fix interrupt controller node name
      commit: 2cca8d79709e1debd27da5dcae2abc859f41db70

Best regards,
-- 
Manivannan Sadhasivam <mani at kernel.org>



From robin.murphy at arm.com  Tue Dec 30 09:20:30 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Tue, 30 Dec 2025 17:20:30 +0000
Subject: [PATCH 0/4] Properly support FriendlyElec HD702E
Message-ID: <cover.1767111804.git.robin.murphy@arm.com>

Hi all,

I've been using the HD702E LCD/touchscreen on my NanoPC-T4 for a few
years using my own DT with the "simple-panel" binding, but now we have
upstream overlays I figured it's about time to try doing it properly.
The screen itself doesn't seem to want to work as a generic "edp-panel",
as it appears the EDID isn't readable until after the whole lot is
enabled - I'm guessing this might be to do with the Analogix driver's
force-hpd behaviour - but since we do already have the legacy data, it
doesn't seem unreasonable to keep using it.

Thanks,
Robin.


Robin Murphy (4):
  dt-bindings: display: panel: Move FriendlyElec HD702E to eDP
  drm/panel-edp: Move FriendlyELEC HD702E
  arm64: dts: rockchip: Move RK3399 eDP pinctrl to boards
  arm64: dts: rockchip: Add overlay for FriendlyElec HD702E

 .../display/panel/panel-edp-legacy.yaml       |  2 +
 .../bindings/display/panel/panel-simple.yaml  |  2 -
 arch/arm64/boot/dts/rockchip/Makefile         |  5 ++
 arch/arm64/boot/dts/rockchip/rk3399-base.dtsi |  2 -
 .../dts/rockchip/rk3399-gru-chromebook.dtsi   |  2 +
 .../dts/rockchip/rk3399-nanopc-t4-hd702e.dtso | 62 +++++++++++++++++++
 .../boot/dts/rockchip/rk3399-pinebook-pro.dts |  2 -
 .../rockchip/rk3399-sapphire-excavator.dts    |  2 +
 drivers/gpu/drm/panel/panel-edp.c             | 26 ++++++++
 drivers/gpu/drm/panel/panel-simple.c          | 25 --------
 10 files changed, 99 insertions(+), 31 deletions(-)
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3399-nanopc-t4-hd702e.dtso

-- 
2.34.1



From robin.murphy at arm.com  Tue Dec 30 09:20:33 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Tue, 30 Dec 2025 17:20:33 +0000
Subject: [PATCH 3/4] arm64: dts: rockchip: Move RK3399 eDP pinctrl to boards
In-Reply-To: <cover.1767111804.git.robin.murphy@arm.com>
References: <cover.1767111804.git.robin.murphy@arm.com>
Message-ID: <0b9488badb467ef83a0a464eeea921f59e32e6b0.1767111809.git.robin.murphy@arm.com>

The EDP_HOTPLUG pin is optional, and muxed with other functions (notably
HDMI CEC), so move its selection from the SoC DTSI to the boards which
apparently want it, namely those which enable eDP without "force-hpd".
By the same token we drop it from Pinebook Pro, which already uses
"force-hpd", and according to the schematics does not have the pin wired
at all.

Signed-off-by: Robin Murphy <robin.murphy at arm.com>
---
 arch/arm64/boot/dts/rockchip/rk3399-base.dtsi              | 2 --
 arch/arm64/boot/dts/rockchip/rk3399-gru-chromebook.dtsi    | 2 ++
 arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts       | 2 --
 arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator.dts | 2 ++
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi
index 4dcceb9136b7..19a312baa9f1 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi
@@ -2145,8 +2145,6 @@ edp: dp at ff970000 {
 		interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH 0>;
 		clocks = <&cru PCLK_EDP>, <&cru PCLK_EDP_CTRL>, <&cru PCLK_VIO_GRF>;
 		clock-names = "dp", "pclk", "grf";
-		pinctrl-names = "default";
-		pinctrl-0 = <&edp_hpd>;
 		power-domains = <&power RK3399_PD_EDP>;
 		resets = <&cru SRST_P_EDP_CTRL>;
 		reset-names = "dp";
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-chromebook.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru-chromebook.dtsi
index 9d07353df52c..3f3cb0eb5809 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru-chromebook.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-chromebook.dtsi
@@ -241,6 +241,8 @@ &dmc {
 };
 
 &edp {
+	pinctrl-names = "default";
+	pinctrl-0 = <&edp_hpd>;
 	status = "okay";
 
 	/*
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
index eaaca08a7601..dcab04863d28 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
@@ -401,8 +401,6 @@ &cpu_l3 {
 
 &edp {
 	force-hpd;
-	pinctrl-names = "default";
-	pinctrl-0 = <&edp_hpd>;
 	status = "okay";
 };
 
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator.dts b/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator.dts
index a4ceafe6dd7a..80d6ea0eda84 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator.dts
@@ -141,6 +141,8 @@ sdio_pwrseq: sdio-pwrseq {
 };
 
 &edp {
+	pinctrl-names = "default";
+	pinctrl-0 = <&edp_hpd>;
 	status = "okay";
 };
 
-- 
2.34.1



From robin.murphy at arm.com  Tue Dec 30 09:20:31 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Tue, 30 Dec 2025 17:20:31 +0000
Subject: [PATCH 1/4] dt-bindings: display: panel: Move FriendlyElec HD702E to eDP
In-Reply-To: <cover.1767111804.git.robin.murphy@arm.com>
References: <cover.1767111804.git.robin.murphy@arm.com>
Message-ID: <80a68e706e869aadbdea228b207a5df52bbfd7b2.1767111807.git.robin.murphy@arm.com>

The "E" alludes to the fact that FriendlyElec's HD702E is actually an
eDP panel - move its compatible to the appropriate binding doc.

Cc: <devicetree at vger.kernel.org>
Signed-off-by: Robin Murphy <robin.murphy at arm.com>
---
 .../devicetree/bindings/display/panel/panel-edp-legacy.yaml     | 2 ++
 .../devicetree/bindings/display/panel/panel-simple.yaml         | 2 --
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/panel/panel-edp-legacy.yaml b/Documentation/devicetree/bindings/display/panel/panel-edp-legacy.yaml
index b308047c1edf..afe7dc54ebf4 100644
--- a/Documentation/devicetree/bindings/display/panel/panel-edp-legacy.yaml
+++ b/Documentation/devicetree/bindings/display/panel/panel-edp-legacy.yaml
@@ -44,6 +44,8 @@ properties:
       - boe,nv133fhm-n62
         # BOE NV140FHM-N49 14.0" FHD a-Si FT panel
       - boe,nv140fhmn49
+        # FriendlyELEC HD702E 800x1280 LCD panel
+      - friendlyarm,hd702e
         # Innolux Corporation 11.6" WXGA (1366x768) TFT LCD panel
       - innolux,n116bca-ea1
         # Innolux Corporation 11.6" WXGA (1366x768) TFT LCD panel
diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml
index 24e277b19094..a01cf025aad1 100644
--- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml
+++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml
@@ -144,8 +144,6 @@ properties:
       - foxlink,fl500wvr00-a0t
         # Frida FRD350H54004 3.5" QVGA TFT LCD panel
       - frida,frd350h54004
-        # FriendlyELEC HD702E 800x1280 LCD panel
-      - friendlyarm,hd702e
         # GiantPlus GPG48273QS5 4.3" (480x272) WQVGA TFT LCD panel
       - giantplus,gpg48273qs5
         # GiantPlus GPM940B0 3.0" QVGA TFT LCD panel
-- 
2.34.1



From robin.murphy at arm.com  Tue Dec 30 09:20:34 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Tue, 30 Dec 2025 17:20:34 +0000
Subject: [PATCH 4/4] arm64: dts: rockchip: Add overlay for FriendlyElec HD702E
In-Reply-To: <cover.1767111804.git.robin.murphy@arm.com>
References: <cover.1767111804.git.robin.murphy@arm.com>
Message-ID: <bc54c6c700a4be244bd4f81cb846cf628313a6ee.1767111810.git.robin.murphy@arm.com>

Add an overlay to support FriendlyElec's HD702E 7" eDP LCD touchscreen
module for the NanoPC-T4 board:

https://www.friendlyelec.com/index.php?route=product/product&path=81&product_id=230

Signed-off-by: Robin Murphy <robin.murphy at arm.com>
---
 arch/arm64/boot/dts/rockchip/Makefile         |  5 ++
 .../dts/rockchip/rk3399-nanopc-t4-hd702e.dtso | 62 +++++++++++++++++++
 2 files changed, 67 insertions(+)
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3399-nanopc-t4-hd702e.dtso

diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index dbdda9783e93..4ab58a5961aa 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -62,6 +62,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-khadas-edge-v.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-kobol-helios64.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-leez-p710.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopc-t4.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopc-t4-hd702e.dtbo
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopi-m4.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopi-m4b.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopi-neo4.dtb
@@ -238,6 +239,10 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-ringneck-haikou-haikou-video-demo.dtb
 px30-ringneck-haikou-haikou-video-demo-dtbs := px30-ringneck-haikou.dtb \
 	px30-ringneck-haikou-video-demo.dtbo
 
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopc-t4-hd702e.dtb
+rk3399-nanopc-t4-hd702e-dtbs := rk3399-nanopc-t4.dtb \
+	rk3399-nanopc-t4-hd702e.dtbo
+
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-puma-haikou-haikou-video-demo.dtb
 rk3399-puma-haikou-haikou-video-demo-dtbs := rk3399-puma-haikou.dtb \
 	rk3399-puma-haikou-video-demo.dtbo
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-nanopc-t4-hd702e.dtso b/arch/arm64/boot/dts/rockchip/rk3399-nanopc-t4-hd702e.dtso
new file mode 100644
index 000000000000..ab643a1edd7b
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopc-t4-hd702e.dtso
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * FriendlyElec HD702E LCD on NanoPC-T4 board
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+
+&{/} {
+	pwm_bl: backlight {
+		compatible = "pwm-backlight";
+		pwms = <&pwm0 0 25000 0>;
+		enable-gpios = <&gpio4 RK_PD5 GPIO_ACTIVE_HIGH>;
+		brightness-levels = <0 255>;
+		default-brightness-level = <200>;
+		num-interpolated-steps = <255>;
+	};
+};
+
+&edp {
+	force-hpd;
+	status = "okay";
+
+	aux-bus {
+		edp-panel {
+			compatible = "friendlyarm,hd702e";
+			backlight = <&pwm_bl>;
+			no-hpd;
+			power-supply = <&vcc12v0_sys>;
+
+			port {
+				panel_in_edp: endpoint {
+					remote-endpoint = <&edp_out_panel>;
+				};
+			};
+		};
+	};
+};
+
+&edp_out {
+	edp_out_panel: endpoint {
+		remote-endpoint = <&panel_in_edp>;
+	};
+};
+
+&i2c4 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	touchscreen at 5d {
+		compatible = "goodix,gt9271";
+		reg = <0x5d>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <RK_PC4 IRQ_TYPE_EDGE_FALLING>;
+		irq-gpios = <&gpio1 RK_PC4 GPIO_ACTIVE_HIGH>;
+		reset-gpios = <&gpio1 RK_PB5 GPIO_ACTIVE_HIGH>;
+	};
+};
-- 
2.34.1



From robin.murphy at arm.com  Tue Dec 30 09:20:32 2025
From: robin.murphy at arm.com (Robin Murphy)
Date: Tue, 30 Dec 2025 17:20:32 +0000
Subject: [PATCH 2/4] drm/panel-edp: Move FriendlyELEC HD702E
In-Reply-To: <cover.1767111804.git.robin.murphy@arm.com>
References: <cover.1767111804.git.robin.murphy@arm.com>
Message-ID: <027763b36fbad2005d09eeb289b7716c57f65e76.1767111809.git.robin.murphy@arm.com>

FriendlyELEC's HD702E module is an eDP panel (in as much as it's some
LVDS LCD behind a Chrontel CH7511B eDP bridge), so move its data over
to the eDP driver, also resolving the warning about the missing bpc
value in the process.

Signed-off-by: Robin Murphy <robin.murphy at arm.com>
---
 drivers/gpu/drm/panel/panel-edp.c    | 26 ++++++++++++++++++++++++++
 drivers/gpu/drm/panel/panel-simple.c | 25 -------------------------
 2 files changed, 26 insertions(+), 25 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c
index 415b894890ad..dd53ccc209ce 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1256,6 +1256,29 @@ static const struct panel_desc boe_nv140fhmn49 = {
 	},
 };
 
+static const struct drm_display_mode friendlyarm_hd702e_mode = {
+	.clock		= 67185,
+	.hdisplay	= 800,
+	.hsync_start	= 800 + 20,
+	.hsync_end	= 800 + 20 + 24,
+	.htotal		= 800 + 20 + 24 + 20,
+	.vdisplay	= 1280,
+	.vsync_start	= 1280 + 4,
+	.vsync_end	= 1280 + 4 + 8,
+	.vtotal		= 1280 + 4 + 8 + 4,
+	.flags		= DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
+static const struct panel_desc friendlyarm_hd702e = {
+	.modes = &friendlyarm_hd702e_mode,
+	.num_modes = 1,
+	.bpc = 8,
+	.size = {
+		.width	= 94,
+		.height	= 151,
+	},
+};
+
 static const struct drm_display_mode innolux_n116bca_ea1_mode = {
 	.clock = 76420,
 	.hdisplay = 1366,
@@ -1663,6 +1686,9 @@ static const struct of_device_id platform_of_match[] = {
 	}, {
 		.compatible = "boe,nv140fhmn49",
 		.data = &boe_nv140fhmn49,
+	}, {
+		.compatible = "friendlyarm,hd702e",
+		.data = &friendlyarm_hd702e,
 	}, {
 		.compatible = "innolux,n116bca-ea1",
 		.data = &innolux_n116bca_ea1,
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index b26b682826bc..3ea52667b858 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -2359,28 +2359,6 @@ static const struct panel_desc frida_frd350h54004 = {
 	.connector_type = DRM_MODE_CONNECTOR_DPI,
 };
 
-static const struct drm_display_mode friendlyarm_hd702e_mode = {
-	.clock		= 67185,
-	.hdisplay	= 800,
-	.hsync_start	= 800 + 20,
-	.hsync_end	= 800 + 20 + 24,
-	.htotal		= 800 + 20 + 24 + 20,
-	.vdisplay	= 1280,
-	.vsync_start	= 1280 + 4,
-	.vsync_end	= 1280 + 4 + 8,
-	.vtotal		= 1280 + 4 + 8 + 4,
-	.flags		= DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
-};
-
-static const struct panel_desc friendlyarm_hd702e = {
-	.modes = &friendlyarm_hd702e_mode,
-	.num_modes = 1,
-	.size = {
-		.width	= 94,
-		.height	= 151,
-	},
-};
-
 static const struct drm_display_mode giantplus_gpg482739qs5_mode = {
 	.clock = 9000,
 	.hdisplay = 480,
@@ -5235,9 +5213,6 @@ static const struct of_device_id platform_of_match[] = {
 	}, {
 		.compatible = "frida,frd350h54004",
 		.data = &frida_frd350h54004,
-	}, {
-		.compatible = "friendlyarm,hd702e",
-		.data = &friendlyarm_hd702e,
 	}, {
 		.compatible = "giantplus,gpg482739qs5",
 		.data = &giantplus_gpg482739qs5
-- 
2.34.1



From aaro.koskinen at iki.fi  Tue Dec 30 09:35:40 2025
From: aaro.koskinen at iki.fi (Aaro Koskinen)
Date: Tue, 30 Dec 2025 19:35:40 +0200
Subject: [PATCH] ARM: omap1: drop unused Kconfig symbol
In-Reply-To: <20251230055230.3212260-1-rdunlap@infradead.org>
References: <20251230055230.3212260-1-rdunlap@infradead.org>
Message-ID: <aVQNbK4K_q4UtJP_@darkstar.musicnaut.iki.fi>

Hi,

On Mon, Dec 29, 2025 at 09:52:30PM -0800, Randy Dunlap wrote:
> "select ARCH_HAS_HOLES_MEMORYMODEL" was mistakenly merged here
> due to a botched rebase (says Arnd [1]).
> 
> Drop that line since that symbol is not used anywhere else in the
> kernel source tree.
> 
> [1] https://lore.kernel.org/all/5e335232-89b4-4c35-93bd-efad7e4d8995 at app.fastmail.com/
> Fixes: 7036440eab3e ("ARM: omap1: enable multiplatform")
> Signed-off-by: Randy Dunlap <rdunlap at infradead.org>

Reviewed-by: Aaro Koskinen <aaro.koskinen at iki.fi>

A.

> ---
> KernelVersion: 6.19-rc1
> 
> Cc: Arnd Bergmann <arnd at arndb.de>
> Cc: patches at armlinux.org.uk
> Cc: Aaro Koskinen <aaro.koskinen at iki.fi>
> Cc: Janusz Krzysztofik <jmkrzyszt at gmail.com>
> Cc: Tony Lindgren <tony at atomide.com>
> Cc: linux-omap at vger.kernel.org
> Cc: Russell King <linux at armlinux.org.uk>
> 
>  arch/arm/mach-omap1/Kconfig |    1 -
>  1 file changed, 1 deletion(-)
> 
> --- linux-next-20251219.orig/arch/arm/mach-omap1/Kconfig
> +++ linux-next-20251219/arch/arm/mach-omap1/Kconfig
> @@ -4,7 +4,6 @@ menuconfig ARCH_OMAP1
>  	depends on ARCH_MULTI_V4T || ARCH_MULTI_V5
>  	depends on CPU_LITTLE_ENDIAN
>  	depends on ATAGS
> -	select ARCH_HAS_HOLES_MEMORYMODEL
>  	select ARCH_OMAP
>  	select CLKSRC_MMIO
>  	select FORCE_PCI if PCCARD
> 


From robh at kernel.org  Tue Dec 30 09:46:19 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Tue, 30 Dec 2025 11:46:19 -0600
Subject: [PATCH 1/4] dt-bindings: media: sun4i-a10-video-engine: Add
 interconnect properties
In-Reply-To: <20251225103616.3203473-2-wens@kernel.org>
References: <20251225103616.3203473-1-wens@kernel.org>
 <20251225103616.3203473-2-wens@kernel.org>
Message-ID: <176711677675.852762.10312933098835387721.robh@kernel.org>


On Thu, 25 Dec 2025 18:36:12 +0800, Chen-Yu Tsai wrote:
> The Allwinner video engine sits behind the MBUS that is represented as
> an interconnect.
> 
> Make sure that the interconnect properties are valid in the binding.
> 
> Fixes: d41662e52a03 ("media: dt-bindings: media: allwinner,sun4i-a10-video-engine: Add R40 compatible")
> Signed-off-by: Chen-Yu Tsai <wens at kernel.org>
> ---
>  .../media/allwinner,sun4i-a10-video-engine.yaml        | 10 ++++++++++
>  1 file changed, 10 insertions(+)
> 

Acked-by: Rob Herring (Arm) <robh at kernel.org>



From conor at kernel.org  Tue Dec 30 09:47:56 2025
From: conor at kernel.org (Conor Dooley)
Date: Tue, 30 Dec 2025 17:47:56 +0000
Subject: [PATCH v4 14/15] dt-bindings: arm: AT91: document EV23X71A board
In-Reply-To: <20251229184004.571837-15-robert.marko@sartura.hr>
References: <20251229184004.571837-1-robert.marko@sartura.hr>
 <20251229184004.571837-15-robert.marko@sartura.hr>
Message-ID: <20251230-imprecise-cohesive-25a1f0ec1896@spud>

Acked-by: Conor Dooley <conor.dooley at microchip.com>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20251230/88591f38/attachment.sig>

From francesco at valla.it  Tue Dec 30 09:51:07 2025
From: francesco at valla.it (Francesco Valla)
Date: Tue, 30 Dec 2025 18:51:07 +0100
Subject: [PATCH v4 2/2] arm64: dts: freescale: add support for NXP i.MX93
 FRDM
In-Reply-To: <20251230172427.4f22ac7c@windsurf>
References: <20251218-fpg-nxp-imx93-frdm-v4-0-cd3a9f6ac89a@pengutronix.de>
 <20251218-fpg-nxp-imx93-frdm-v4-2-cd3a9f6ac89a@pengutronix.de>
 <20251230171548.67289601@windsurf>
 <20251230172427.4f22ac7c@windsurf>
Message-ID: <aVQRCzq8-Q5FguTN@bywater>

Hello Thomas,

On Tue, Dec 30, 2025 at 05:24:27PM +0100, Thomas Petazzoni wrote:
> Hello (again),
> 
> On Tue, 30 Dec 2025 17:15:48 +0100
> Thomas Petazzoni <thomas.petazzoni at bootlin.com> wrote:
> 
> > I see the PMIC interrupt and the RTC interrupts are routed to the I2C
> > GPIO expander at 1-0022, so I imagine either the PMIC or the RTC are
> > triggering an interrupt (left enabled by U-Boot), and the kernel isn't
> > compiled with the driver for either the PMIC or the RTC, and therefore
> > there's no IRQ handler?
> > 
> > (I confess I didn't investigate more than that at this point.)
> 
> Upon closer inspection, I in fact get thousands over IRQ #100 per
> seconds right after boot, until the point where it reaches 100000 IRQ
> events, and the splat appears, with the IRQ being subsequently
> disabled. So it's not just one interrupt, but a storm of it.
> 

This recalls the behaviour seen on i.MX91 FRDM [0], and the hardware is
indeed very similar: the GPIO expander and the TypeC port controller
(PTN5110) share the same IRQ line, and if the first gets enabled before
the second an interrupt storm will happen (because the PTN5110 is
triggering interrupts that nobody services).

I did not see this during my testing - but maybe the probe sequence is 
different. Any chance you are not loading the driver for the PTN5110?
I see from your defconfig it should be compiled as module, but maybe
you are not including it into the image or not loading it?

The NXP downstream BSP is masking interrupts for the TypeC port
controller as part of the U-Boot initialization, as they are enabled by
default at reset. While it somewhat breaks the required isolation
between the bootloader and the system it loads, I fear this is the only
sensible option here, given this hardware limitation; this was the path
that was chosen for the i.MX91 FRDM (which has been applied today [1]).

> Thomas
> -- 
> Thomas Petazzoni, co-owner and CEO, Bootlin
> Embedded Linux and Kernel engineering and training
> https://bootlin.com
> 

[0] https://lore.kernel.org/all/aTBFCc-8NzeS4MzT at bywater/
[1] https://lore.kernel.org/u-boot/CAOMZO5DsCi6GHrkvLEZTjsLy1D02A2e83YgMO36b3EMt8B6c5Q at mail.gmail.com/

Reagrds,
Francesco



From robh at kernel.org  Tue Dec 30 09:59:33 2025
From: robh at kernel.org (Rob Herring)
Date: Tue, 30 Dec 2025 11:59:33 -0600
Subject: [PATCH 2/2] arm: dts: lpc32xx: add clocks property to Motor
 Control PWM device tree node
In-Reply-To: <20251228224907.1729627-3-vz@mleia.com>
References: <20251228224907.1729627-1-vz@mleia.com>
 <20251228224907.1729627-3-vz@mleia.com>
Message-ID: <20251230175933.GA864856-robh@kernel.org>

On Mon, Dec 29, 2025 at 12:49:07AM +0200, Vladimir Zapolskiy wrote:
> Motor Control PWM depends on its own supply clock, the clock gate control
> is present in TIMCLK_CTRL1 register.

You say it is required, so does that mean this hasn't ever worked? Or it 
happened to work because something else turned on the clock?

> 

Fixes tag?

> Signed-off-by: Vladimir Zapolskiy <vz at mleia.com>
> ---
>  arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
> index 39af48470ed5..abd401fda94e 100644
> --- a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
> +++ b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
> @@ -304,6 +304,7 @@ i2c2: i2c at 400a8000 {
>  			mpwm: pwm at 400e8000 {
>  				compatible = "nxp,lpc3220-motor-pwm";
>  				reg = <0x400e8000 0x78>;
> +				clocks = <&clk LPC32XX_CLK_MCPWM>;
>  				#pwm-cells = <3>;
>  				status = "disabled";
>  			};
> -- 
> 2.43.0
> 


From robh at kernel.org  Tue Dec 30 09:59:53 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Tue, 30 Dec 2025 11:59:53 -0600
Subject: [PATCH 1/2] dt-bindings: pwm: nxp,lpc32xx-pwm: Specify clocks
 property as mandatory
In-Reply-To: <20251228224907.1729627-2-vz@mleia.com>
References: <20251228224907.1729627-1-vz@mleia.com>
 <20251228224907.1729627-2-vz@mleia.com>
Message-ID: <176711759312.868220.4508247636976387030.robh@kernel.org>


On Mon, 29 Dec 2025 00:49:06 +0200, Vladimir Zapolskiy wrote:
> Both described in the binding PWM controllers depend on supply clocks,
> thus it's necessary to specify 'clocks' property in the correspondent
> device tree nodes.
> 
> Signed-off-by: Vladimir Zapolskiy <vz at mleia.com>
> ---
>  Documentation/devicetree/bindings/pwm/nxp,lpc3220-pwm.yaml | 4 ++++
>  1 file changed, 4 insertions(+)
> 

Acked-by: Rob Herring (Arm) <robh at kernel.org>



From robh at kernel.org  Tue Dec 30 10:06:09 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Tue, 30 Dec 2025 12:06:09 -0600
Subject: [PATCH v4 01/15] dt-bindings: usb: Add Microchip LAN969x support
In-Reply-To: <20251229184004.571837-2-robert.marko@sartura.hr>
References: <20251229184004.571837-1-robert.marko@sartura.hr>
 <20251229184004.571837-2-robert.marko@sartura.hr>
Message-ID: <176711796888.884073.12938472533739359591.robh@kernel.org>


On Mon, 29 Dec 2025 19:37:42 +0100, Robert Marko wrote:
> Microchip LAN969x has DWC3 compatible controller, though limited to 2.0(HS)
> speed, so document it.
> 
> Signed-off-by: Robert Marko <robert.marko at sartura.hr>
> ---
> Changes in v2:
> * Fix example indentation
> 
>  .../bindings/usb/microchip,lan9691-dwc3.yaml  | 66 +++++++++++++++++++
>  1 file changed, 66 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/usb/microchip,lan9691-dwc3.yaml
> 

Reviewed-by: Rob Herring (Arm) <robh at kernel.org>



From robh at kernel.org  Tue Dec 30 10:06:32 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Tue, 30 Dec 2025 12:06:32 -0600
Subject: [PATCH v4 09/15] dt-bindings: dma: atmel: add
 microchip,lan9691-dma
In-Reply-To: <20251229184004.571837-10-robert.marko@sartura.hr>
References: <20251229184004.571837-1-robert.marko@sartura.hr>
 <20251229184004.571837-10-robert.marko@sartura.hr>
Message-ID: <176711799188.884536.16157476210751555846.robh@kernel.org>


On Mon, 29 Dec 2025 19:37:50 +0100, Robert Marko wrote:
> Document Microchip LAN969x DMA compatible which is compatible to SAMA7G5.
> 
> Signed-off-by: Robert Marko <robert.marko at sartura.hr>
> ---
> Changes in v3:
> * Merged with microchip,sama7d65-dma since that also falls back to
> microchip,sama7g5-dma
> 
>  Documentation/devicetree/bindings/dma/atmel,sama5d4-dma.yaml | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 

Acked-by: Rob Herring (Arm) <robh at kernel.org>



From rdunlap at infradead.org  Tue Dec 30 10:14:29 2025
From: rdunlap at infradead.org (Randy Dunlap)
Date: Tue, 30 Dec 2025 10:14:29 -0800
Subject: [PATCH] arm64: STM32: drop an undefined Kconfig symbol
Message-ID: <20251230181429.3429404-1-rdunlap@infradead.org>

Drop ARM_SMC_MBOX since it is not defined or used anywhere else
in the kernel source tree.

Fixes: 9e4e24414cc6 ("arm64: introduce STM32 family on Armv8 architecture")
Signed-off-by: Randy Dunlap <rdunlap at infradead.org>
---
Cc: Alexandre Torgue <alexandre.torgue at foss.st.com>
Cc: Maxime Coquelin <mcoquelin.stm32 at gmail.com>
Cc: linux-stm32 at st-md-mailman.stormreply.com
Cc: linux-arm-kernel at lists.infradead.org
Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Will Deacon <will at kernel.org>

 arch/arm64/Kconfig.platforms |    1 -
 1 file changed, 1 deletion(-)

--- linux-next-20251219.orig/arch/arm64/Kconfig.platforms
+++ linux-next-20251219/arch/arm64/Kconfig.platforms
@@ -372,7 +372,6 @@ config ARCH_STM32
 	bool "STMicroelectronics STM32 SoC Family"
 	select GPIOLIB
 	select PINCTRL
-	select ARM_SMC_MBOX
 	select ARM_SCMI_PROTOCOL
 	select REGULATOR
 	select REGULATOR_ARM_SCMI


From towinchenmi at gmail.com  Tue Dec 30 10:30:42 2025
From: towinchenmi at gmail.com (Nick Chan)
Date: Wed, 31 Dec 2025 02:30:42 +0800
Subject: [PATCH] arm64: dts: apple: s8001: Add DWI backlight for J98a, J99a
Message-ID: <20251231-b4-j98a-j99a-dwi-bl-v1-1-24793c2b99fc@gmail.com>

iPad Pro (12.9-inch) uses DWI backlight, while the 9.7-inch model does not.
Add DWI backlight node for s8001 and enable it for J98a and J99a.

Signed-off-by: Nick Chan <towinchenmi at gmail.com>
---
 arch/arm64/boot/dts/apple/s8001-j98a-j99a.dtsi | 4 ++++
 arch/arm64/boot/dts/apple/s8001.dtsi           | 7 +++++++
 2 files changed, 11 insertions(+)

diff --git a/arch/arm64/boot/dts/apple/s8001-j98a-j99a.dtsi b/arch/arm64/boot/dts/apple/s8001-j98a-j99a.dtsi
index e66a4c1c138fe82dcdd652d4d56a8f4583f660cb..67633c56a7238983517b36ba319a704424be07c5 100644
--- a/arch/arm64/boot/dts/apple/s8001-j98a-j99a.dtsi
+++ b/arch/arm64/boot/dts/apple/s8001-j98a-j99a.dtsi
@@ -9,6 +9,10 @@
  * Copyright (c) 2024, Nick Chan <towinchenmi at gmail.com>
  */
 
+&dwi_bl {
+	status = "okay";
+};
+
 &ps_dcs4 {
 	apple,always-on; /* LPDDR4 interface */
 };
diff --git a/arch/arm64/boot/dts/apple/s8001.dtsi b/arch/arm64/boot/dts/apple/s8001.dtsi
index b5b00dca6ffa4caa1d504860693da001a8ced80e..209c7dd19b7c289096e22b3c86a825c53d19a78f 100644
--- a/arch/arm64/boot/dts/apple/s8001.dtsi
+++ b/arch/arm64/boot/dts/apple/s8001.dtsi
@@ -209,6 +209,13 @@ aic: interrupt-controller at 20e100000 {
 			power-domains = <&ps_aic>;
 		};
 
+		dwi_bl: backlight at 20e200080 {
+			compatible = "apple,s8000-dwi-bl", "apple,dwi-bl";
+			reg = <0x2 0x0e200080 0x0 0x8>;
+			power-domains = <&ps_dwi>;
+			status = "disabled";
+		};
+
 		pinctrl_ap: pinctrl at 20f100000 {
 			compatible = "apple,s8000-pinctrl", "apple,pinctrl";
 			reg = <0x2 0x0f100000 0x0 0x100000>;

---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20251231-b4-j98a-j99a-dwi-bl-b56c3075a4fb

Best regards,
-- 
Nick Chan <towinchenmi at gmail.com>



From marex at nabladev.com  Tue Dec 30 10:40:58 2025
From: marex at nabladev.com (Marek Vasut)
Date: Tue, 30 Dec 2025 19:40:58 +0100
Subject: [PATCH v3 1/4] dt-bindings: vendor-prefixes: Document ifm electronic gmbh
Message-ID: <20251230184121.52635-1-marex@nabladev.com>

ifm is a manufacturer of industrial sensors, control technology and
automation solutions. Document their vendor prefix, which is already
used for ifm,ac14xx and other powerpc devices.

Acked-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Marek Vasut <marex at nabladev.com>
---
Cc: Christian Eggers <ceggers at arri.de>
Cc: Conor Dooley <conor+dt at kernel.org>
Cc: Fabio Estevam <festevam at gmail.com>
Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
Cc: Krzysztof Kozlowski <krzk+dt at kernel.org>
Cc: Markus Heidelberg <m.heidelberg at cab.de>
Cc: Rob Herring <robh at kernel.org>
Cc: Shawn Guo <shawnguo at kernel.org>
Cc: devicetree at vger.kernel.org
Cc: imx at lists.linux.dev
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-kernel at vger.kernel.org
---
V2: Add AB from Rob
V3: No change
---
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index b7c6c528e0185..70d99ac01aa34 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -755,6 +755,8 @@ patternProperties:
     description: IEI Integration Corp.
   "^ifi,.*":
     description: Ingenieurburo Fur Ic-Technologie (I/F/I)
+  "^ifm,.*":
+    description: ifm electronic gmbh
   "^ilitek,.*":
     description: ILI Technology Corporation (ILITEK)
   "^imagis,.*":
-- 
2.51.0



From marex at nabladev.com  Tue Dec 30 10:40:59 2025
From: marex at nabladev.com (Marek Vasut)
Date: Tue, 30 Dec 2025 19:40:59 +0100
Subject: [PATCH v3 2/4] dt-bindings: arm: fsl: Document ifm VHIP4 EvalBoard v1 and v2
In-Reply-To: <20251230184121.52635-1-marex@nabladev.com>
References: <20251230184121.52635-1-marex@nabladev.com>
Message-ID: <20251230184121.52635-2-marex@nabladev.com>

Document ifm i.MX8MN VHIP4 EvalBoard v1 and v2 reference design binding.
This system exists in two generations, v1 and v2, which share a lot of
commonality. The boards come with either single gigabit ethernet or an
KSZ8794 fast-ethernet switch, boot from eMMC, and offer CAN interfaces
via Microchip MCP25xx SPI CAN controllers, UART, and USB host. The GPU
is not available in the SoC populated on these devices.

Acked-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Marek Vasut <marex at nabladev.com>
---
Cc: Christian Eggers <ceggers at arri.de>
Cc: Conor Dooley <conor+dt at kernel.org>
Cc: Fabio Estevam <festevam at gmail.com>
Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
Cc: Krzysztof Kozlowski <krzk+dt at kernel.org>
Cc: Markus Heidelberg <m.heidelberg at cab.de>
Cc: Rob Herring <robh at kernel.org>
Cc: Shawn Guo <shawnguo at kernel.org>
Cc: devicetree at vger.kernel.org
Cc: imx at lists.linux.dev
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-kernel at vger.kernel.org
---
V2: Add AB from Rob
V3: No change
---
 Documentation/devicetree/bindings/arm/fsl.yaml | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
index 68a2d5fecc43b..4d0aee780bcb2 100644
--- a/Documentation/devicetree/bindings/arm/fsl.yaml
+++ b/Documentation/devicetree/bindings/arm/fsl.yaml
@@ -1071,6 +1071,15 @@ properties:
               - gw,imx8mn-gw7902          # i.MX8MM Gateworks Board
           - const: fsl,imx8mn
 
+      - description: ifm i.MX8MN VHIP4 based boards
+        items:
+          - enum:
+              - ifm,imx8mn-vhip4-evalboard-v1
+              - ifm,imx8mn-vhip4-evalboard-v2
+          - const: ifm,imx8mn-vhip4-evalboard
+          - const: ifm,imx8mn-vhip4
+          - const: fsl,imx8mn
+
       - description: Variscite VAR-SOM-MX8MN based boards
         items:
           - enum:
-- 
2.51.0



From marex at nabladev.com  Tue Dec 30 10:41:00 2025
From: marex at nabladev.com (Marek Vasut)
Date: Tue, 30 Dec 2025 19:41:00 +0100
Subject: [PATCH v3 3/4] arm64: dts: imx8mn: Add SNVS LPGPR
In-Reply-To: <20251230184121.52635-1-marex@nabladev.com>
References: <20251230184121.52635-1-marex@nabladev.com>
Message-ID: <20251230184121.52635-3-marex@nabladev.com>

Add SNVS LPGPR bindings to MX8M Nano, the LPGPR is used to store
boot counter.

Signed-off-by: Marek Vasut <marex at nabladev.com>
---
Cc: Christian Eggers <ceggers at arri.de>
Cc: Conor Dooley <conor+dt at kernel.org>
Cc: Fabio Estevam <festevam at gmail.com>
Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
Cc: Krzysztof Kozlowski <krzk+dt at kernel.org>
Cc: Markus Heidelberg <m.heidelberg at cab.de>
Cc: Rob Herring <robh at kernel.org>
Cc: Shawn Guo <shawnguo at kernel.org>
Cc: devicetree at vger.kernel.org
Cc: imx at lists.linux.dev
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-kernel at vger.kernel.org
---
V2: New patch
V3: No change
---
 arch/arm64/boot/dts/freescale/imx8mn.dtsi | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mn.dtsi b/arch/arm64/boot/dts/freescale/imx8mn.dtsi
index b98b3d0ddf25a..3199bc0966b03 100644
--- a/arch/arm64/boot/dts/freescale/imx8mn.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mn.dtsi
@@ -628,6 +628,11 @@ snvs_pwrkey: snvs-powerkey {
 					wakeup-source;
 					status = "disabled";
 				};
+
+				snvs_lpgpr: snvs-lpgpr {
+					compatible = "fsl,imx8mn-snvs-lpgpr",
+						     "fsl,imx7d-snvs-lpgpr";
+				};
 			};
 
 			clk: clock-controller at 30380000 {
-- 
2.51.0



From marex at nabladev.com  Tue Dec 30 10:41:01 2025
From: marex at nabladev.com (Marek Vasut)
Date: Tue, 30 Dec 2025 19:41:01 +0100
Subject: [PATCH v3 4/4] arm64: dts: imx8mn: Add ifm VHIP4 EvalBoard v1 and v2
In-Reply-To: <20251230184121.52635-1-marex@nabladev.com>
References: <20251230184121.52635-1-marex@nabladev.com>
Message-ID: <20251230184121.52635-4-marex@nabladev.com>

From: Fedor Ross <fedor.ross at ifm.com>

Add support for ifm i.MX8MN VHIP4 EvalBoard v1 and v2 reference design.
This system exists in two generations, v1 and v2, which share a lot of
commonality. The boards come with either single gigabit ethernet or an
KSZ8794 fast-ethernet switch, boot from eMMC, and offer CAN interfaces
via Microchip MCP25xx SPI CAN controllers, UART, and USB host. The GPU
is not available in the SoC populated on these devices.

Signed-off-by: Fedor Ross <fedor.ross at ifm.com>
Signed-off-by: Marek Vasut <marex at nabladev.com>
---
Cc: Christian Eggers <ceggers at arri.de>
Cc: Conor Dooley <conor+dt at kernel.org>
Cc: Fabio Estevam <festevam at gmail.com>
Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
Cc: Krzysztof Kozlowski <krzk+dt at kernel.org>
Cc: Markus Heidelberg <m.heidelberg at cab.de>
Cc: Rob Herring <robh at kernel.org>
Cc: Shawn Guo <shawnguo at kernel.org>
Cc: devicetree at vger.kernel.org
Cc: imx at lists.linux.dev
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-kernel at vger.kernel.org
---
V2: - Drop snvs-lpgpr node in favor of separate patch to imx8mn.dtsi
    - Sort properties and update newlines according to V1 feedback
V3: - Drop fsl,magic-packet
---
 arch/arm64/boot/dts/freescale/Makefile        |  19 +
 .../imx8mn-vhip4-evalboard-common.dtsi        | 398 ++++++++++++++++++
 ...imx8mn-vhip4-evalboard-ksz8794-common.dtsi |  98 +++++
 ...mn-vhip4-evalboard-v1-overlay-ksz8794.dtso |  24 ++
 ...mn-vhip4-evalboard-v1-overlay-ksz9031.dtso |  48 +++
 .../freescale/imx8mn-vhip4-evalboard-v1.dts   | 260 ++++++++++++
 ...n-vhip4-evalboard-v2-overlay-adin1300.dtso |  60 +++
 ...mn-vhip4-evalboard-v2-overlay-ksz8794.dtso |  24 ++
 .../freescale/imx8mn-vhip4-evalboard-v2.dts   | 221 ++++++++++
 9 files changed, 1152 insertions(+)
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-common.dtsi
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-ksz8794-common.dtsi
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtso
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtso
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1.dts
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtso
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtso
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2.dts

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index f30d3fd724d0c..01b2ec5ad81ff 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -191,6 +191,25 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mn-tqma8mqnl-mba8mx.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-var-som-symphony.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-venice-gw7902.dtb
 
+imx8mn-vhip4-evalboard-v1-overlay-ksz8794-dtbs := imx8mn-vhip4-evalboard-v1.dtb \
+						  imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtbo
+imx8mn-vhip4-evalboard-v1-overlay-ksz9031-dtbs := imx8mn-vhip4-evalboard-v1.dtb \
+						  imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtbo
+imx8mn-vhip4-evalboard-v2-overlay-ksz8794-dtbs := imx8mn-vhip4-evalboard-v2.dtb \
+						  imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtbo
+imx8mn-vhip4-evalboard-v2-overlay-adin1300-dtbs := imx8mn-vhip4-evalboard-v2.dtb \
+						   imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtbo
+dtb-$(CONFIG_ARCH_MXC) += imx8mn-vhip4-evalboard-v1.dtb \
+			  imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtb \
+			  imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtbo \
+			  imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtb \
+			  imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtbo \
+			  imx8mn-vhip4-evalboard-v2.dtb \
+			  imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtb \
+			  imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtbo \
+			  imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtb \
+			  imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtbo
+
 imx8mn-tqma8mqnl-mba8mx-lvds-tm070jvhg33-dtbs += imx8mn-tqma8mqnl-mba8mx.dtb imx8mn-tqma8mqnl-mba8mx-lvds-tm070jvhg33.dtbo
 imx8mn-tqma8mqnl-mba8mx-usbotg-dtbs += imx8mn-tqma8mqnl-mba8mx.dtb imx8mn-tqma8mqnl-mba8mx-usbotg.dtbo
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-tqma8mqnl-mba8mx-lvds-tm070jvhg33.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-common.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-common.dtsi
new file mode 100644
index 0000000000000..a9506ecf9647b
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-common.dtsi
@@ -0,0 +1,398 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2020-2024 Fedor Ross <fedor.ross at ifm.com>
+ */
+
+#include "imx8mn.dtsi"
+#include <dt-bindings/leds/common.h>
+
+/ {
+	model = "ifm i.MX8MNano VHIP4 Evaluation Board";
+	compatible = "ifm,imx8mn-vhip4-evalboard", "ifm,imx8mn-vhip4", "fsl,imx8mn";
+
+	aliases {
+		mmc0 = &usdhc3;
+		mmc1 = &usdhc1;
+		mmc2 = &usdhc2;
+		rtc0 = &hw_rtc;
+		rtc1 = &snvs_rtc;
+	};
+
+	chosen {
+		bootargs = "console=ttymxc2,115200 earlycon=ec_imx6q,0x30880000,115200 rootwait";
+		stdout-path = &uart3;
+	};
+
+	memory at 40000000 {
+		device_type = "memory";
+		reg = <0x0 0x40000000 0 0x40000000>;
+	};
+
+	can_clk20m: can-clk20m {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <20000000>;
+	};
+
+	can_clk40m: can-clk40m {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <40000000>;
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+		pinctrl-0 = <&pinctrl_gpio_button>;
+		pinctrl-names = "default";
+
+		button-2 {
+			label = "Button2";
+			gpios = <&gpio2 16 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_2>;
+		};
+
+		button-3 {
+			label = "Button3";
+			gpios = <&gpio2 18 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_3>;
+		};
+	};
+
+	ifm_led: led {
+		compatible = "gpio-leds";
+		pinctrl-0 = <&pinctrl_gpio_led>;
+		pinctrl-names = "default", "extended";
+
+		led-0 {
+			function = LED_FUNCTION_STATUS;
+			function-enumerator = <1>;
+			color = <LED_COLOR_ID_YELLOW>;
+			gpios = <&gpio2 13 GPIO_ACTIVE_HIGH>;
+			default-state = "keep";
+		};
+
+		led-1 {
+			function = LED_FUNCTION_STATUS;
+			function-enumerator = <2>;
+			color = <LED_COLOR_ID_GREEN>;
+			gpios = <&gpio2 15 GPIO_ACTIVE_HIGH>;
+			default-state = "keep";
+		};
+	};
+};
+
+&A53_0 {
+	cpu-supply = <&buck2_reg>;
+};
+
+&A53_1 {
+	cpu-supply = <&buck2_reg>;
+};
+
+&A53_2 {
+	cpu-supply = <&buck2_reg>;
+};
+
+&A53_3 {
+	cpu-supply = <&buck2_reg>;
+};
+
+&ddrc {
+	operating-points-v2 = <&ddrc_opp_table>;
+
+	ddrc_opp_table: opp-table {
+		compatible = "operating-points-v2";
+
+		opp-25000000 {
+			opp-hz = /bits/ 64 <25000000>;
+		};
+
+		opp-100000000 {
+			opp-hz = /bits/ 64 <100000000>;
+		};
+
+		opp-600000000 {
+			opp-hz = /bits/ 64 <600000000>;
+		};
+	};
+};
+
+&ecspi1 {
+	pinctrl-names = "default", "cs";
+	pinctrl-0 = <&pinctrl_ecspi1>;
+	pinctrl-1 = <&pinctrl_ecspi1_cs>;
+	/delete-property/ dmas;
+	/delete-property/ dma-names;
+};
+
+&ecspi3 {
+	pinctrl-names = "default", "cs";
+	pinctrl-0 = <&pinctrl_ecspi3>;
+	pinctrl-1 = <&pinctrl_ecspi3_cs>;
+	/delete-property/ dmas;
+	/delete-property/ dma-names;
+};
+
+&gpu {
+	/* SoC has GPU fused off. */
+	status = "disabled";
+};
+
+&i2c1 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default", "gpio";
+	pinctrl-0 = <&pinctrl_i2c1>;
+	pinctrl-1 = <&pinctrl_i2c1_gpio>;
+
+	eeprom at 51 {
+		compatible = "atmel,24c128";
+		reg = <0x51>;
+	};
+
+	hw_rtc: rtc at 52 {
+		compatible = "microcrystal,rv3028";
+		reg = <0x52>;
+	};
+};
+
+&i2c3 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default", "gpio";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	pinctrl-1 = <&pinctrl_i2c3_gpio>;
+
+	ifm_pmic: pmic at 4b {
+		compatible = "rohm,bd71847";
+		reg = <0x4b>;
+		pinctrl-0 = <&pinctrl_pmic>;
+		rohm,reset-snvs-powered;
+
+		regulators {
+			buck1_reg: BUCK1 {
+				regulator-name = "buck1";
+				regulator-min-microvolt = <790000>;
+				regulator-max-microvolt = <860000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <1250>;
+			};
+
+			buck2_reg: BUCK2 {
+				regulator-name = "buck2";
+				regulator-min-microvolt = <840000>;
+				regulator-max-microvolt = <960000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <1250>;
+			};
+
+			buck3_reg: BUCK3 {
+				// BUCK5 in datasheet
+				regulator-name = "buck3";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1350000>;
+			};
+
+			buck4_reg: BUCK4 {
+				// BUCK6 in datasheet
+				regulator-name = "buck4";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			buck5_reg: BUCK5 {
+				// BUCK7 in datasheet
+				regulator-name = "buck5";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			buck6_reg: BUCK6 {
+				// BUCK8 in datasheet
+				regulator-name = "buck6";
+				regulator-min-microvolt = <1100000>;
+				regulator-max-microvolt = <1100000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo1_reg: LDO1 {
+				regulator-name = "ldo1";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo2_reg: LDO2 {
+				regulator-name = "ldo2";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo3_reg: LDO3 {
+				regulator-name = "ldo3";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo4_reg: LDO4 {
+				regulator-name = "ldo4";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1800000>;
+			};
+
+			ldo5_reg: LDO5 {
+				regulator-name = "ldo5";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+			};
+
+			ldo6_reg: LDO6 {
+				regulator-name = "ldo6";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+		};
+	};
+};
+
+&iomuxc {
+	pinctrl_ecspi1: ecspi1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK		0x110
+			MX8MN_IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI		0x110
+			MX8MN_IOMUXC_ECSPI1_MISO_ECSPI1_MISO		0x190
+		>;
+	};
+
+	pinctrl_ecspi3: ecspi3-grp {
+		fsl,pins = <
+			/* SPI3_CAN_CLK */
+			MX8MN_IOMUXC_UART1_RXD_ECSPI3_SCLK		0x110
+			/* SPI3_CAN_MOSI */
+			MX8MN_IOMUXC_UART1_TXD_ECSPI3_MOSI		0x110
+			/* SPI3_CAN_MISO */
+			MX8MN_IOMUXC_UART2_RXD_ECSPI3_MISO		0x190
+		>;
+	};
+
+	pinctrl_gpio_button: gpiobutton-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD2_DATA1_GPIO2_IO16		0x96
+			MX8MN_IOMUXC_SD2_DATA3_GPIO2_IO18		0x96
+		>;
+	};
+
+	pinctrl_gpio_led: gpioled-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD2_CLK_GPIO2_IO13			0x116
+			MX8MN_IOMUXC_SD2_DATA0_GPIO2_IO15		0x116
+		>;
+	};
+
+	pinctrl_usdhc3: usdhc3-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK		0x40000110
+			MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d0
+			MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d0
+			MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d0
+			MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d0
+			MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d0
+			MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d0
+			MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d0
+			MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d0
+			MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d0
+			MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x190
+			MX8MN_IOMUXC_NAND_READY_B_USDHC3_RESET_B	0x150
+		>;
+	};
+
+	pinctrl_usdhc3_100mhz: usdhc3-100mhz-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK		0x40000114
+			MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d4
+			MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d4
+			MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d4
+			MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d4
+			MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d4
+			MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d4
+			MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d4
+			MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d4
+			MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d4
+			MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x194
+			MX8MN_IOMUXC_NAND_READY_B_USDHC3_RESET_B	0x150
+		>;
+	};
+
+	pinctrl_usdhc3_200mhz: usdhc3-200mhz-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK		0x40000116
+			MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d6
+			MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d6
+			MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d6
+			MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d6
+			MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d6
+			MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d6
+			MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d6
+			MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d6
+			MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d6
+			MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x196
+			MX8MN_IOMUXC_NAND_READY_B_USDHC3_RESET_B	0x150
+		>;
+	};
+
+	pinctrl_wdog: wdog-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B		0x64
+		>;
+	};
+};
+
+&pgc_gpumix {
+	/* SoC has GPU fused off. */
+	status = "disabled";
+};
+
+&snvs_pwrkey {
+	status = "okay";
+};
+
+&uart3 { /* console */
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart3>;
+	status = "okay";
+};
+
+&usbotg1 {
+	status = "okay";
+};
+
+&usdhc3 {
+	assigned-clocks = <&clk IMX8MN_CLK_USDHC3_ROOT>;
+	assigned-clock-rates = <400000000>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc3>;
+	pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
+	bus-width = <8>;
+	non-removable;
+	status = "okay";
+};
+
+&wdog1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_wdog>;
+	fsl,ext-reset-output;
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-ksz8794-common.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-ksz8794-common.dtsi
new file mode 100644
index 0000000000000..c1a98ec2f4382
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-ksz8794-common.dtsi
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2025 Fedor Ross <fedor.ross at ifm.com>
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+
+#include "imx8mn-pinfunc.h"
+
+&ecspi1 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+
+	ksz8794: ethernet-switch at 1 {
+		compatible = "microchip,ksz8794";
+		pinctrl-names = "default", "reset";
+		pinctrl-0 = <&pinctrl_ks8794>;
+		pinctrl-1 = <&pinctrl_ks8794>;
+		reg = <1>;
+		reset-gpios = <&gpio4 28 GPIO_ACTIVE_LOW>;
+		spi-max-frequency = <5000000>;
+
+		ethernet-ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+				label = "lan1";
+			};
+
+			port at 1 {
+				reg = <1>;
+				label = "lan2";
+			};
+
+			port at 2 {
+				reg = <2>;
+				label = "lan3";
+			};
+
+			port at 4 {
+				reg = <4>;
+				label = "cpu";
+				ethernet = <&fec1>;
+				phy-mode = "rgmii-id";
+				rx-internal-delay-ps = <2000>;
+				tx-internal-delay-ps = <2000>;
+				fixed-link {
+					full-duplex;
+					speed = <1000>;
+				};
+			};
+		};
+	};
+};
+
+&fec1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_fec1>;
+	phy-mode = "rgmii-id";
+	status = "okay";
+
+	fixed-link {
+		full-duplex;
+		speed = <1000>;
+	};
+};
+
+&iomuxc {
+	pinctrl_fec1: fec1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_ENET_MDC_ENET1_MDC			0x16
+			MX8MN_IOMUXC_ENET_MDIO_ENET1_MDIO		0x96
+			MX8MN_IOMUXC_ENET_TD3_ENET1_RGMII_TD3		0x16
+			MX8MN_IOMUXC_ENET_TD2_ENET1_RGMII_TD2		0x16
+			MX8MN_IOMUXC_ENET_TD1_ENET1_RGMII_TD1		0x16
+			MX8MN_IOMUXC_ENET_TD0_ENET1_RGMII_TD0		0x16
+			MX8MN_IOMUXC_ENET_RD3_ENET1_RGMII_RD3		0x96
+			MX8MN_IOMUXC_ENET_RD2_ENET1_RGMII_RD2		0x96
+			MX8MN_IOMUXC_ENET_RD1_ENET1_RGMII_RD1		0x96
+			MX8MN_IOMUXC_ENET_RD0_ENET1_RGMII_RD0		0x96
+			MX8MN_IOMUXC_ENET_TXC_ENET1_RGMII_TXC		0x10
+			MX8MN_IOMUXC_ENET_RXC_ENET1_RGMII_RXC		0x96
+			MX8MN_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x96
+			MX8MN_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x16
+			MX8MN_IOMUXC_SAI3_TXFS_GPIO4_IO31		0x1d6
+		>;
+	};
+
+	pinctrl_ks8794: ks8794-grp {
+		fsl,pins = <
+			/* KSZ8794 reset line */
+			MX8MN_IOMUXC_SAI3_RXFS_GPIO4_IO28		0x16
+		>;
+	};
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtso b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtso
new file mode 100644
index 0000000000000..20eb427f3dd66
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtso
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2021 Marek Vasut
+ */
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+#include "imx8mn-pinfunc.h"
+
+&pinctrl_ecspi1 {
+	fsl,pins = <
+		MX8MN_IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK		0x10
+		MX8MN_IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI		0x10
+		MX8MN_IOMUXC_ECSPI1_MISO_ECSPI1_MISO		0x90
+		/* KS8794 nCS */
+		MX8MN_IOMUXC_I2C4_SDA_GPIO5_IO21		0x150
+		/* ANV32C81 nCS */
+		MX8MN_IOMUXC_ECSPI1_SS0_GPIO5_IO9		0x150
+	>;
+};
+
+#include "imx8mn-vhip4-evalboard-ksz8794-common.dtsi"
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtso b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtso
new file mode 100644
index 0000000000000..de24206106b3b
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtso
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2021 Marek Vasut
+ */
+/dts-v1/;
+/plugin/;
+
+#include "imx8mn-pinfunc.h"
+
+&fec1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_fec1>;
+	phy-handle = <&ethphy0>;
+	phy-mode = "rgmii-id";
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy0: ethernet-phy at 0 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <0>;
+		};
+	};
+};
+
+&iomuxc {
+	pinctrl_fec1: fec1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_ENET_MDC_ENET1_MDC			0x16
+			MX8MN_IOMUXC_ENET_MDIO_ENET1_MDIO		0x96
+			MX8MN_IOMUXC_ENET_TD3_ENET1_RGMII_TD3		0x16
+			MX8MN_IOMUXC_ENET_TD2_ENET1_RGMII_TD2		0x16
+			MX8MN_IOMUXC_ENET_TD1_ENET1_RGMII_TD1		0x16
+			MX8MN_IOMUXC_ENET_TD0_ENET1_RGMII_TD0		0x16
+			MX8MN_IOMUXC_ENET_RD3_ENET1_RGMII_RD3		0x96
+			MX8MN_IOMUXC_ENET_RD2_ENET1_RGMII_RD2		0x96
+			MX8MN_IOMUXC_ENET_RD1_ENET1_RGMII_RD1		0x96
+			MX8MN_IOMUXC_ENET_RD0_ENET1_RGMII_RD0		0x96
+			MX8MN_IOMUXC_ENET_TXC_ENET1_RGMII_TXC		0x16
+			MX8MN_IOMUXC_ENET_RXC_ENET1_RGMII_RXC		0x96
+			MX8MN_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x96
+			MX8MN_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x16
+			MX8MN_IOMUXC_SAI3_TXFS_GPIO4_IO31		0x1d6
+		>;
+	};
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1.dts b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1.dts
new file mode 100644
index 0000000000000..6d1cebffcae5d
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1.dts
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2020-2024 Fedor Ross <fedor.ross at ifm.com>
+ */
+
+/dts-v1/;
+
+#include "imx8mn-vhip4-evalboard-common.dtsi"
+
+/ {
+	model = "ifm i.MX8MNano VHIP4 Evaluation Board v1";
+	compatible = "ifm,imx8mn-vhip4-evalboard-v1", "ifm,imx8mn-vhip4-evalboard",
+		     "ifm,imx8mn-vhip4", "fsl,imx8mn";
+};
+
+&ifm_led {
+	pinctrl-1 = <&pinctrl_gpio_led_v1>;
+
+	led-2 {
+		function = LED_FUNCTION_STATUS;
+		function-enumerator = <3>;
+		color = <LED_COLOR_ID_YELLOW>;
+		gpios = <&gpio2 17 GPIO_ACTIVE_HIGH>;
+		default-state = "keep";
+	};
+
+	led-3 {
+		function = LED_FUNCTION_STATUS;
+		function-enumerator = <4>;
+		color = <LED_COLOR_ID_GREEN>;
+		gpios = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+		default-state = "keep";
+	};
+};
+
+&ecspi1 {
+	cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>, <&gpio5 21 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	eeprom at 0 {
+		compatible = "anvo,anv32c81w", "atmel,at25";
+		reg = <0>;
+		spi-max-frequency = <20000000>;
+		spi-cpha;
+		spi-cpol;
+		pagesize = <1>;
+		size = <32768>;
+		address-width = <16>;
+	};
+};
+
+&ecspi3 {
+	cs-gpios = <&gpio5 25 GPIO_ACTIVE_LOW>, <&gpio5 4 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	can0: can at 0 {
+		compatible = "microchip,mcp25625";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_mcp25625>;
+		reg = <0>;
+		clocks = <&can_clk20m>;
+		interrupt-parent = <&gpio4>;
+		interrupts = <21 IRQ_TYPE_LEVEL_LOW>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	can1: can at 1 {
+		compatible = "microchip,mcp2518fd";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_mcp2518>;
+		reg = <1>;
+		clocks = <&can_clk40m>;
+		interrupt-parent = <&gpio5>;
+		interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+		microchip,rx-int-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>;
+		spi-max-frequency = <20000000>;
+	};
+};
+
+&gpio4 {
+	/*
+	 * Hog USB-nRESET high here, since neither U-Boot nor Linux
+	 * has any support for USB Hub GPIO reset so far.
+	 */
+	usb-nreset-hog {
+		gpio-hog;
+		gpios = <29 GPIO_ACTIVE_HIGH>;
+		line-name = "USB_nRESET";
+		output-high;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_usb_nreset>;
+	};
+};
+
+&i2c1 {
+	scl-gpios = <&gpio5 14 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	sda-gpios = <&gpio5 15 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+
+	lm75 at 48 {
+		compatible = "national,lm75";
+		reg = <0x48>;
+	};
+
+	eeprom at 50 {
+		compatible = "atmel,24c128";
+		reg = <0x50>;
+	};
+};
+
+&i2c2 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default", "gpio";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	pinctrl-1 = <&pinctrl_i2c2_gpio>;
+	scl-gpios = <&gpio5 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	sda-gpios = <&gpio5 17 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+&i2c3 {
+	scl-gpios = <&gpio2 10 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	sda-gpios = <&gpio2 11 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+&ifm_pmic {
+	interrupt-parent = <&gpio2>;
+	interrupts = <0 GPIO_ACTIVE_LOW>;
+};
+
+&iomuxc {
+	pinctrl_ecspi1_cs: ecspi1-cs-grp {
+		fsl,pins = <
+			/* KS8794 nCS */
+			MX8MN_IOMUXC_I2C4_SDA_GPIO5_IO21		0x150
+			/* ANV32C81 nCS */
+			MX8MN_IOMUXC_ECSPI1_SS0_GPIO5_IO9		0x150
+		>;
+	};
+
+	pinctrl_ecspi3_cs: ecspi3-cs-grp {
+		fsl,pins = <
+			/* MCP25625 nCS */
+			MX8MN_IOMUXC_UART2_TXD_GPIO5_IO25		0x150
+			/* MCP2518FD nCS */
+			MX8MN_IOMUXC_SPDIF_RX_GPIO5_IO4			0x150
+		>;
+	};
+
+	pinctrl_gpio_led_v1: gpioled-v1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD2_DATA2_GPIO2_IO17		0x116
+			MX8MN_IOMUXC_SD2_RESET_B_GPIO2_IO19		0x116
+		>;
+	};
+
+	pinctrl_i2c1: i2c1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C1_SCL_I2C1_SCL			0x40000056
+			MX8MN_IOMUXC_I2C1_SDA_I2C1_SDA			0x400000d6
+		>;
+	};
+
+	pinctrl_i2c1_gpio: i2c1-gpio-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C1_SCL_GPIO5_IO14		0x56
+			MX8MN_IOMUXC_I2C1_SDA_GPIO5_IO15		0xd6
+		>;
+	};
+
+	pinctrl_i2c2: i2c2-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C2_SCL_I2C2_SCL			0x40000056
+			MX8MN_IOMUXC_I2C2_SDA_I2C2_SDA			0x400000d6
+		>;
+	};
+
+	pinctrl_i2c2_gpio: i2c2-gpio-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C2_SCL_GPIO5_IO16		0x56
+			MX8MN_IOMUXC_I2C2_SDA_GPIO5_IO17		0xd6
+		>;
+	};
+
+	pinctrl_i2c3: i2c3-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD1_RESET_B_I2C3_SCL		0x40000056
+			MX8MN_IOMUXC_SD1_STROBE_I2C3_SDA		0x400000d6
+		>;
+	};
+
+	pinctrl_i2c3_gpio: i2c3-gpio-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD1_RESET_B_GPIO2_IO10		0x56
+			MX8MN_IOMUXC_SD1_STROBE_GPIO2_IO11		0xd6
+		>;
+	};
+
+	pinctrl_mcp2518: mcp2518-grp {
+		fsl,pins = <
+			/* MCP2518 nINT line */
+			MX8MN_IOMUXC_SAI3_MCLK_GPIO5_IO2		0x116
+			/* MCP2518 nINT1/GPIO1 line */
+			MX8MN_IOMUXC_SAI3_TXD_GPIO5_IO1			0x116
+		>;
+	};
+
+	pinctrl_mcp25625: mcp25625-grp {
+		fsl,pins = <
+			/* MCP25625 nINT line */
+			MX8MN_IOMUXC_SAI2_RXFS_GPIO4_IO21		0x156
+		>;
+	};
+
+	pinctrl_pmic: pmic-irq-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD1_CLK_GPIO2_IO0			0x16
+		>;
+	};
+
+	pinctrl_uart3: uart3-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_UART3_RXD_UART3_DCE_RX		0x142
+			MX8MN_IOMUXC_UART3_TXD_UART3_DCE_TX		0x142
+		>;
+	};
+
+	pinctrl_usb_nreset: usbnreset-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SAI3_RXC_GPIO4_IO29                0x14a
+		>;
+	};
+
+	pinctrl_gpio_5: gpio5-grp {
+		fsl,pins = <
+			/* CFG_EEPROM_WP */
+			MX8MN_IOMUXC_I2C4_SCL_GPIO5_IO20		0x140
+		>;
+	};
+
+	pinctrl_wdog: wdog-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B		0x64
+		>;
+	};
+};
+
+&gpio5 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_gpio_5>;
+	gpio-line-names =
+		"", "", "", "", "", "", "", "",
+		"", "", "", "", "", "", "", "",
+		"", "", "", "",
+		"ifm_device_info_eeprom_wp",
+		"", "", "",
+		"", "", "", "", "", "", "", "";
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtso b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtso
new file mode 100644
index 0000000000000..6ad7434a1787e
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtso
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2024 Fedor Ross <fedor.ross at ifm.com>
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include "imx8mn-pinfunc.h"
+
+&fec1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_fec1>;
+	phy-handle = <&ethphy0>;
+	phy-mode = "rgmii-id";
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy0: ethernet-phy at 0 {
+			reg = <0>;
+
+			adi,rx-internal-delay-ps = <1800>;
+			adi,tx-internal-delay-ps = <2200>;
+			interrupts-extended = <&gpio4 31 IRQ_TYPE_LEVEL_LOW>;
+			reset-gpios = <&gpio4 28 GPIO_ACTIVE_LOW>;
+			reset-assert-us = <10000>;
+			reset-deassert-us = <10000>;
+		};
+	};
+};
+
+&iomuxc {
+	pinctrl_fec1: fec1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_ENET_MDC_ENET1_MDC			0x16
+			MX8MN_IOMUXC_ENET_MDIO_ENET1_MDIO		0x96
+			MX8MN_IOMUXC_ENET_TD3_ENET1_RGMII_TD3		0x16
+			MX8MN_IOMUXC_ENET_TD2_ENET1_RGMII_TD2		0x16
+			MX8MN_IOMUXC_ENET_TD1_ENET1_RGMII_TD1		0x16
+			MX8MN_IOMUXC_ENET_TD0_ENET1_RGMII_TD0		0x16
+			MX8MN_IOMUXC_ENET_RD3_ENET1_RGMII_RD3		0x96
+			MX8MN_IOMUXC_ENET_RD2_ENET1_RGMII_RD2		0x96
+			MX8MN_IOMUXC_ENET_RD1_ENET1_RGMII_RD1		0x96
+			MX8MN_IOMUXC_ENET_RD0_ENET1_RGMII_RD0		0x96
+			MX8MN_IOMUXC_ENET_TXC_ENET1_RGMII_TXC		0x16
+			MX8MN_IOMUXC_ENET_RXC_ENET1_RGMII_RXC		0x96
+			MX8MN_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x96
+			MX8MN_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x16
+			/* nRST */
+			MX8MN_IOMUXC_SAI3_RXFS_GPIO4_IO28		0x156
+			/* nIRQ */
+			MX8MN_IOMUXC_SAI3_TXFS_GPIO4_IO31		0x1d6
+		>;
+	};
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtso b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtso
new file mode 100644
index 0000000000000..ab1304ebd965e
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtso
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2021 Marek Vasut
+ */
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+#include "imx8mn-pinfunc.h"
+
+&pinctrl_ecspi1 {
+	fsl,pins = <
+		MX8MN_IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK		0x10
+		MX8MN_IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI		0x10
+		MX8MN_IOMUXC_ECSPI1_MISO_ECSPI1_MISO		0x90
+		/* KS8794 nCS */
+		MX8MN_IOMUXC_GPIO1_IO11_GPIO1_IO11		0x150
+		/* ANV32C81 nCS */
+		MX8MN_IOMUXC_ECSPI1_SS0_GPIO5_IO9		0x150
+	>;
+};
+
+#include "imx8mn-vhip4-evalboard-ksz8794-common.dtsi"
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2.dts b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2.dts
new file mode 100644
index 0000000000000..5c17f309b93ab
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2.dts
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2024 Fedor Ross <fedor.ross at ifm.com>
+ */
+
+/dts-v1/;
+
+#include "imx8mn-vhip4-evalboard-common.dtsi"
+
+/ {
+	model = "ifm i.MX8MNano VHIP4 Evaluation Board v2";
+	compatible = "ifm,imx8mn-vhip4-evalboard-v2", "ifm,imx8mn-vhip4-evalboard",
+		     "ifm,imx8mn-vhip4", "fsl,imx8mn";
+
+	multi-led {
+		compatible = "leds-group-multicolor";
+		color = <LED_COLOR_ID_RGB>;
+		function = LED_FUNCTION_INDICATOR;
+		leds = <&rgb_0>, <&rgb_1>, <&rgb_2>;
+	};
+};
+
+&ifm_led {
+	pinctrl-1 = <&pinctrl_gpio_led_v2>;
+
+	rgb_0: rgb-led-red {
+		color = <LED_COLOR_ID_RED>;
+		gpios = <&gpio2 17 GPIO_ACTIVE_HIGH>;
+		default-state = "keep";
+	};
+
+	rgb_1: rgb-led-green {
+		color = <LED_COLOR_ID_GREEN>;
+		gpios = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+		default-state = "keep";
+	};
+
+	rgb_2: rgb-led-blue {
+		color = <LED_COLOR_ID_BLUE>;
+		gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>;
+		default-state = "keep";
+	};
+};
+
+&ecspi1 {
+	cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>, <&gpio1 11 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	eeprom at 0 {
+		compatible = "fujitsu,mb85rs64", "atmel,at25";
+		reg = <0>;
+		spi-max-frequency = <20000000>;
+		spi-cpha;
+		spi-cpol;
+		pagesize = <1>;
+		size = <32768>;
+		address-width = <16>;
+	};
+};
+
+&ecspi3 {
+	cs-gpios = <&gpio5 25 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	can0: can at 0 {
+		compatible = "microchip,mcp2518fd";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_mcp2518>;
+		reg = <0>;
+		clocks = <&can_clk40m>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
+		microchip,rx-int-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
+		spi-max-frequency = <20000000>;
+	};
+};
+
+&i2c1 {
+	scl-gpios = <&gpio2 6 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	sda-gpios = <&gpio2 7 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+
+	tmp1075 at 48 {
+		compatible = "ti,tmp1075";
+		reg = <0x48>;
+	};
+
+	eeprom at 54 {
+		compatible = "atmel,24c128";
+		reg = <0x54>;
+	};
+};
+
+&i2c3 {
+	scl-gpios = <&gpio5 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	sda-gpios = <&gpio5 19 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+&ifm_pmic {
+	interrupt-parent = <&gpio5>;
+	interrupts = <17 GPIO_ACTIVE_LOW>;
+};
+
+&iomuxc {
+	pinctrl_ecspi1_cs: ecspi1-cs-grp {
+		fsl,pins = <
+			/* KS8794 nCS */
+			MX8MN_IOMUXC_GPIO1_IO11_GPIO1_IO11		0x150
+			/* Retain memory nCS (FRAM or MRAM) */
+			MX8MN_IOMUXC_ECSPI1_SS0_GPIO5_IO9		0x150
+			/* RETAIN_nHOLD */
+			MX8MN_IOMUXC_SPDIF_RX_GPIO5_IO4			0x140
+		>;
+	};
+
+	pinctrl_ecspi3_cs: ecspi3-cs-grp {
+		fsl,pins = <
+			/* MCP2518FD nCS */
+			MX8MN_IOMUXC_UART2_TXD_GPIO5_IO25		0x150
+		>;
+	};
+
+	pinctrl_gpio_led_v2: gpioled-v2-grp {
+		fsl,pins = <
+			/* LED_RGB_RED */
+			MX8MN_IOMUXC_SD2_DATA2_GPIO2_IO17		0x116
+			/* LED_RGB_GREEN */
+			MX8MN_IOMUXC_SD2_RESET_B_GPIO2_IO19		0x116
+			/* LED_RGB_BLUE */
+			MX8MN_IOMUXC_SD2_WP_GPIO2_IO20			0x116
+		>;
+	};
+
+	pinctrl_i2c1: i2c1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD1_DATA4_I2C1_SCL			0x40000056
+			MX8MN_IOMUXC_SD1_DATA5_I2C1_SDA			0x400000d6
+		>;
+	};
+
+	pinctrl_i2c1_gpio: i2c1-gpio-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD1_DATA4_GPIO2_IO6		0x56
+			MX8MN_IOMUXC_SD1_DATA5_GPIO2_IO7		0xd6
+			/* CFG_EEPROM_WP */
+			MX8MN_IOMUXC_SD1_STROBE_GPIO2_IO11		0x140
+			/* RTC_nIRQ */
+			MX8MN_IOMUXC_SPDIF_EXT_CLK_GPIO5_IO5		0x116
+			/* LOG_EE_WP */
+			MX8MN_IOMUXC_SPDIF_TX_GPIO5_IO3			0x140
+		>;
+	};
+
+	pinctrl_i2c3: i2c3-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C3_SCL_I2C3_SCL			0x40000056
+			MX8MN_IOMUXC_I2C3_SDA_I2C3_SDA			0x400000d6
+		>;
+	};
+
+	pinctrl_i2c3_gpio: i2c3-gpio-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C3_SCL_GPIO5_IO18		0x56
+			MX8MN_IOMUXC_I2C3_SDA_GPIO5_IO19		0xd6
+		>;
+	};
+
+	pinctrl_mcp2518: mcp2518-grp {
+		fsl,pins = <
+			/* CAN0_CLKO */
+			MX8MN_IOMUXC_GPIO1_IO00_GPIO1_IO0		0x116
+			/* CAN0_nINT0 */
+			MX8MN_IOMUXC_GPIO1_IO03_GPIO1_IO3		0x116
+			/* CAN0_nINT1 */
+			MX8MN_IOMUXC_GPIO1_IO04_GPIO1_IO4		0x116
+			/* CAN0_nINT */
+			MX8MN_IOMUXC_GPIO1_IO01_GPIO1_IO1		0x116
+		>;
+	};
+
+	pinctrl_pmic: pmic-irq-grp {
+		fsl,pins = <
+			/* PMIC_nIRQ */
+			MX8MN_IOMUXC_I2C2_SDA_GPIO5_IO17		0x1d6
+		>;
+	};
+
+	pinctrl_uart3: uart3-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD1_DATA6_UART3_DCE_TX		0x142
+			MX8MN_IOMUXC_SD1_DATA7_UART3_DCE_RX		0x142
+		>;
+	};
+
+	pinctrl_wdog: wdog-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B		0x64
+		>;
+	};
+};
+
+&gpio2 {
+	gpio-line-names =
+		"", "", "", "", "", "", "", "",
+		"", "", "",
+		"ifm_device_info_eeprom_wp",
+		"", "", "", "",
+		"", "", "", "", "", "", "", "",
+		"", "", "", "", "", "", "", "";
+};
+
+&gpio5 {
+	gpio-line-names =
+		"", "", "",
+		"ifm_logging_eeprom_wp",
+		"", "", "", "",
+		"", "", "", "", "", "", "", "",
+		"", "", "", "",	"", "", "", "",
+		"", "", "", "", "", "", "", "";
+};
-- 
2.51.0



From marex at nabladev.com  Tue Dec 30 10:42:09 2025
From: marex at nabladev.com (Marek Vasut)
Date: Tue, 30 Dec 2025 19:42:09 +0100
Subject: [PATCH v2 4/4] arm64: dts: imx8mn: Add ifm VHIP4 EvalBoard v1 and
 v2
In-Reply-To: <51825dee-c2c9-4d94-b741-ffdc2fbfa773@lunn.ch>
References: <20251229193706.73564-1-marex@nabladev.com>
 <20251229193706.73564-4-marex@nabladev.com>
 <e3d305ce-cdfa-4a11-bd54-9648b12a013f@lunn.ch>
 <dc29e774-07fb-4d0e-a88a-27d4ec49d060@nabladev.com>
 <51825dee-c2c9-4d94-b741-ffdc2fbfa773@lunn.ch>
Message-ID: <be90bafc-7900-4d73-8fd5-39cf855a0bbe@nabladev.com>

On 12/30/25 4:35 PM, Andrew Lunn wrote:
> On Tue, Dec 30, 2025 at 02:34:14PM +0100, Marek Vasut wrote:
>> On 12/30/25 11:46 AM, Andrew Lunn wrote:
>>>> +&fec1 {
>>>> +	fsl,magic-packet;
>>>
>>> Upps, i probably cut out too much context. This FEC is connected to the Ethernet switch.
>>>
>>> WoL for a port connected to a switch? Have you tested this? Normally
>>> you would have WoL on each port of the switch, and not on the conduit
>>> interface.
>>>
>>>> +&fec1 {
>>>> +	fsl,magic-packet;
>>>
>>> Have you tested WoL?
>>>
>>>> +&fec1 {
>>>> +	fsl,magic-packet;
>>>
>>> WoL again?
>> I don't think WOL is used on this device at all. Would you suggest removing
>> the fsl,magic-packet properties ?
> 
> Yes.
Fixed in V3, thanks.


From festevam at gmail.com  Tue Dec 30 10:52:01 2025
From: festevam at gmail.com (Fabio Estevam)
Date: Tue, 30 Dec 2025 15:52:01 -0300
Subject: [PATCH v3 4/4] arm64: dts: imx8mn: Add ifm VHIP4 EvalBoard v1 and v2
In-Reply-To: <20251230184121.52635-4-marex@nabladev.com>
References: <20251230184121.52635-1-marex@nabladev.com> <20251230184121.52635-4-marex@nabladev.com>
Message-ID: <CAOMZO5Aa6iDg2u-sJu1yPZX8T2wE=QVzwSbxjZHo1bMwfDW5HQ@mail.gmail.com>

On Tue, Dec 30, 2025 at 3:41?PM Marek Vasut <marex at nabladev.com> wrote:

> +&gpio4 {
> +       /*
> +        * Hog USB-nRESET high here, since neither U-Boot nor Linux
> +        * has any support for USB Hub GPIO reset so far.

Which USB hub chip is used?

Documentation/devicetree/bindings/usb/microchip,usb2514.yaml describes
a reset-gpios property.

> +       lm75 at 48 {

Node names should be generic: temperature-sensor at 48


From nicolinc at nvidia.com  Tue Dec 30 10:52:53 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Tue, 30 Dec 2025 10:52:53 -0800
Subject: [PATCH v1 2/9] iommu/arm-smmu-v3: Add alloc_id/free_id functions
 to arm_smmu_invs
In-Reply-To: <20251219170551.GF254720@nvidia.com>
References: <cover.1766088962.git.nicolinc@nvidia.com>
 <1541ea4a9e9c935c2f907c0c5f13a4af2bdc2114.1766088962.git.nicolinc@nvidia.com>
 <20251219170551.GF254720@nvidia.com>
Message-ID: <aVQfhaqfvfLFNZqe@Asurada-Nvidia>

Hi Jason,

On Fri, Dec 19, 2025 at 01:05:51PM -0400, Jason Gunthorpe wrote:
> +static int arm_smmu_get_tag(struct arm_smmu_domain *smmu_domain,
> +			    struct arm_smmu_master *master,
> +			    struct arm_vsmmu *vsmmu,
> +			    struct arm_smmu_iotlb_tag *tag, bool no_alloc)
[...]
> +	case ARM_SMMU_DOMAIN_S2:
> +		if (smmu_domain->nest_parent) {
> +			/* FIXME we can support attaching a nest_parent without
> +			 * a vsmmu, but to do that we need to fix
> +			 * arm_smmu_get_id_from_invs() to never return the vmid
> +			 * of a vsmmu. Probably by making a
> +			 * INV_TYPE_S2_VMID_VSMMU */
> +			id = vsmmu->vmid;
> +			return 0;
> +		}

Would you mind elaborating why arm_smmu_get_id_from_invs() can't
return vsmmu->vmid to share with a naked S2 STE?

I'm having a bit trouble justifying this INV_TYPE_S2_VMID_VSMMU.

Since it's the same S2 domain/iopt, if anything that is attached
(whether nested or naked) changes the S2 iopt, we should always
flush the nested S1 domain too, right?

If so, a naked S2 STE should refer to the same VMID in order to
allow its following INV_TYPE_S2_VMID_S1_CLEAR to work properly?

Thanks
Nicolin


From nm at ti.com  Tue Dec 30 12:12:33 2025
From: nm at ti.com (Nishanth Menon)
Date: Tue, 30 Dec 2025 14:12:33 -0600
Subject: [PATCH v2 2/4] clk: keystone: don't cache clock rate
In-Reply-To: <20251223124729.2482877-3-mwalle@kernel.org>
References: <20251223124729.2482877-1-mwalle@kernel.org>
 <20251223124729.2482877-3-mwalle@kernel.org>
Message-ID: <20251230201233.n36d5fiensqyb6fc@splice>

On 13:47-20251223, Michael Walle wrote:
> The TISCI firmware will return 0 if the clock or consumer is not
> enabled although there is a stored value in the firmware. IOW a call to
> set rate will work but at get rate will always return 0 if the clock is
> disabled.
> The clk framework will try to cache the clock rate when it's requested
> by a consumer. If the clock or consumer is not enabled at that point,
> the cached value is 0, which is wrong. Thus, disable the cache
> altogether.
> 
> Signed-off-by: Michael Walle <mwalle at kernel.org>
> Reviewed-by: Kevin Hilman <khilman at baylibre.com>
> Reviewed-by: Randolph Sapp <rs at ti.com>
> ---
>  drivers/clk/keystone/sci-clk.c | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/drivers/clk/keystone/sci-clk.c b/drivers/clk/keystone/sci-clk.c
> index 9d5071223f4c..0a1565fdbb3b 100644
> --- a/drivers/clk/keystone/sci-clk.c
> +++ b/drivers/clk/keystone/sci-clk.c
> @@ -333,6 +333,14 @@ static int _sci_clk_build(struct sci_clk_provider *provider,
>  
>  	init.ops = &sci_clk_ops;
>  	init.num_parents = sci_clk->num_parents;
> +
> +	/*
> +	 * A clock rate query to the SCI firmware will return 0 if either the
> +	 * clock itself is disabled or the attached device/consumer is disabled.
> +	 * This makes it inherently unsuitable for the caching of the clk
> +	 * framework.
> +	 */
> +	init.flags = CLK_GET_RATE_NOCACHE;
>  	sci_clk->hw.init = &init;
>  
>  	ret = devm_clk_hw_register(provider->dev, &sci_clk->hw);
> -- 
> 2.47.3
> 

Reviewed-by: Nishanth Menon <nm at ti.com>

I wish there was a better scheme, but inherently, just like SCMI and
other systems where power management co-processor controls clocks, there
is no real feasible caching scheme I can think of. I wonder if Stephen
or others have a thought on this?

That said, I wonder if we need fixes tag to this? I am sure there are
other clocks susceptible to this as well. I wonder if
commit 3c13933c6033 ("clk: keystone: sci-clk: add support for
dynamically probing clocks") is the appropriate tag?


-- 
Regards,
Nishanth Menon
Key (0xDDB5849D1736249D) / Fingerprint: F8A2 8693 54EB 8232 17A3  1A34 DDB5 849D 1736 249D
https://ti.com/opensource


From devnull+ricardo.pardini.net at kernel.org  Tue Dec 30 12:19:29 2025
From: devnull+ricardo.pardini.net at kernel.org (Ricardo Pardini via B4 Relay)
Date: Tue, 30 Dec 2025 21:19:29 +0100
Subject: [PATCH 0/3] arm64: dts: rockchip: Enable the NPU on some rk3588
 boards
Message-ID: <20251230-arm64-dts-rockchip-rk3588-npu-enablements-v1-0-d38b182a59e3@pardini.net>

This series enables the NPU on a few Rockchip rk3588 boards.
In every case here, the required regulator was already described.

Signed-off-by: Ricardo Pardini <ricardo at pardini.net>
---
Ricardo Pardini (3):
      arm64: dts: rockchip: Enable the NPU on NanoPC T6/T6-LTS
      arm64: dts: rockchip: Enable the NPU on FriendlyElec CM3588
      arm64: dts: rockchip: Enable the NPU on Turing RK1

 .../dts/rockchip/rk3588-friendlyelec-cm3588.dtsi   | 34 +++++++++++++++++++++
 arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi | 35 ++++++++++++++++++++++
 .../arm64/boot/dts/rockchip/rk3588-turing-rk1.dtsi | 34 +++++++++++++++++++++
 3 files changed, 103 insertions(+)
---
base-commit: 9448598b22c50c8a5bb77a9103e2d49f134c9578
change-id: 20251230-arm64-dts-rockchip-rk3588-npu-enablements-1e2830d2e7b0

Best regards,
-- 
Ricardo Pardini <ricardo at pardini.net>




From devnull+ricardo.pardini.net at kernel.org  Tue Dec 30 12:19:32 2025
From: devnull+ricardo.pardini.net at kernel.org (Ricardo Pardini via B4 Relay)
Date: Tue, 30 Dec 2025 21:19:32 +0100
Subject: [PATCH 3/3] arm64: dts: rockchip: Enable the NPU on Turing RK1
In-Reply-To: <20251230-arm64-dts-rockchip-rk3588-npu-enablements-v1-0-d38b182a59e3@pardini.net>
References: <20251230-arm64-dts-rockchip-rk3588-npu-enablements-v1-0-d38b182a59e3@pardini.net>
Message-ID: <20251230-arm64-dts-rockchip-rk3588-npu-enablements-v1-3-d38b182a59e3@pardini.net>

From: Ricardo Pardini <ricardo at pardini.net>

Enable the NPU on Turing RK1.
The regulator vdd_npu_s0 was already described.

Signed-off-by: Ricardo Pardini <ricardo at pardini.net>
---
 .../arm64/boot/dts/rockchip/rk3588-turing-rk1.dtsi | 34 ++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3588-turing-rk1.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-turing-rk1.dtsi
index 6daea8961fdd6..7b28ec9ce1945 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-turing-rk1.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3588-turing-rk1.dtsi
@@ -293,6 +293,10 @@ &pd_gpu {
 	domain-supply = <&vdd_gpu_s0>;
 };
 
+&pd_npu {
+	domain-supply = <&vdd_npu_s0>;
+};
+
 &pinctrl {
 	fan {
 		fan_int: fan-int {
@@ -333,6 +337,36 @@ &pwm0 {
 	status = "okay";
 };
 
+&rknn_core_0 {
+	npu-supply = <&vdd_npu_s0>;
+	sram-supply = <&vdd_npu_s0>;
+	status = "okay";
+};
+
+&rknn_core_1 {
+	npu-supply = <&vdd_npu_s0>;
+	sram-supply = <&vdd_npu_s0>;
+	status = "okay";
+};
+
+&rknn_core_2 {
+	npu-supply = <&vdd_npu_s0>;
+	sram-supply = <&vdd_npu_s0>;
+	status = "okay";
+};
+
+&rknn_mmu_0 {
+	status = "okay";
+};
+
+&rknn_mmu_1 {
+	status = "okay";
+};
+
+&rknn_mmu_2 {
+	status = "okay";
+};
+
 &sdhci {
 	bus-width = <8>;
 	no-sdio;

-- 
2.52.0




From devnull+ricardo.pardini.net at kernel.org  Tue Dec 30 12:19:30 2025
From: devnull+ricardo.pardini.net at kernel.org (Ricardo Pardini via B4 Relay)
Date: Tue, 30 Dec 2025 21:19:30 +0100
Subject: [PATCH 1/3] arm64: dts: rockchip: Enable the NPU on NanoPC
 T6/T6-LTS
In-Reply-To: <20251230-arm64-dts-rockchip-rk3588-npu-enablements-v1-0-d38b182a59e3@pardini.net>
References: <20251230-arm64-dts-rockchip-rk3588-npu-enablements-v1-0-d38b182a59e3@pardini.net>
Message-ID: <20251230-arm64-dts-rockchip-rk3588-npu-enablements-v1-1-d38b182a59e3@pardini.net>

From: Ricardo Pardini <ricardo at pardini.net>

Enable the NPU on FriendlyElec NanoPC T6/T6-LTS boards.
The regulator vdd_npu_s0 was already described.

Signed-off-by: Ricardo Pardini <ricardo at pardini.net>
---
 arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi | 35 ++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi
index fafeabe9adf9e..93bd479118e92 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi
@@ -629,6 +629,10 @@ &pd_gpu {
 	domain-supply = <&vdd_gpu_s0>;
 };
 
+&pd_npu {
+	domain-supply = <&vdd_npu_s0>;
+};
+
 &pinctrl {
 	gpio-leds {
 		sys_led_pin: sys-led-pin {
@@ -706,6 +710,37 @@ &pwm1 {
 	status = "okay";
 };
 
+&rknn_core_0 {
+	npu-supply = <&vdd_npu_s0>;
+	sram-supply = <&vdd_npu_s0>;
+	status = "okay";
+};
+
+&rknn_core_1 {
+	npu-supply = <&vdd_npu_s0>;
+	sram-supply = <&vdd_npu_s0>;
+	status = "okay";
+};
+
+&rknn_core_2 {
+	npu-supply = <&vdd_npu_s0>;
+	sram-supply = <&vdd_npu_s0>;
+	status = "okay";
+};
+
+&rknn_mmu_0 {
+	status = "okay";
+};
+
+&rknn_mmu_1 {
+	status = "okay";
+};
+
+&rknn_mmu_2 {
+	status = "okay";
+};
+
+
 &saradc {
 	vref-supply = <&avcc_1v8_s0>;
 	status = "okay";

-- 
2.52.0




From devnull+ricardo.pardini.net at kernel.org  Tue Dec 30 12:19:31 2025
From: devnull+ricardo.pardini.net at kernel.org (Ricardo Pardini via B4 Relay)
Date: Tue, 30 Dec 2025 21:19:31 +0100
Subject: [PATCH 2/3] arm64: dts: rockchip: Enable the NPU on FriendlyElec
 CM3588
In-Reply-To: <20251230-arm64-dts-rockchip-rk3588-npu-enablements-v1-0-d38b182a59e3@pardini.net>
References: <20251230-arm64-dts-rockchip-rk3588-npu-enablements-v1-0-d38b182a59e3@pardini.net>
Message-ID: <20251230-arm64-dts-rockchip-rk3588-npu-enablements-v1-2-d38b182a59e3@pardini.net>

From: Ricardo Pardini <ricardo at pardini.net>

Enable the NPU on FriendlyElec CM3588.
The regulator vdd_npu_s0 was already described.

Signed-off-by: Ricardo Pardini <ricardo at pardini.net>
---
 .../dts/rockchip/rk3588-friendlyelec-cm3588.dtsi   | 34 ++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588.dtsi
index af431fdcbea7a..46e33e666bb3d 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588.dtsi
@@ -264,6 +264,10 @@ &pd_gpu {
 	domain-supply = <&vdd_gpu_s0>;
 };
 
+&pd_npu {
+	domain-supply = <&vdd_npu_s0>;
+};
+
 &pinctrl {
 	gpio-leds {
 		led_sys_pin: led-sys-pin {
@@ -294,6 +298,36 @@ sd_s0_pwr: sd-s0-pwr {
 	};
 };
 
+&rknn_core_0 {
+	npu-supply = <&vdd_npu_s0>;
+	sram-supply = <&vdd_npu_s0>;
+	status = "okay";
+};
+
+&rknn_core_1 {
+	npu-supply = <&vdd_npu_s0>;
+	sram-supply = <&vdd_npu_s0>;
+	status = "okay";
+};
+
+&rknn_core_2 {
+	npu-supply = <&vdd_npu_s0>;
+	sram-supply = <&vdd_npu_s0>;
+	status = "okay";
+};
+
+&rknn_mmu_0 {
+	status = "okay";
+};
+
+&rknn_mmu_1 {
+	status = "okay";
+};
+
+&rknn_mmu_2 {
+	status = "okay";
+};
+
 &saradc {
 	vref-supply = <&avcc_1v8_s0>;
 	status = "okay";

-- 
2.52.0




From bp at alien8.de  Tue Dec 30 12:22:11 2025
From: bp at alien8.de (Borislav Petkov)
Date: Tue, 30 Dec 2025 21:22:11 +0100
Subject: [PATCH v5 00/17] ARM Error Source Table V2 Support
In-Reply-To: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
References: <20251230090945.43969-1-tianruidong@linux.alibaba.com>
Message-ID: <20251230202211.GAaVQ0cx8o-CqzGU2O@fat_crate.local>

Some high-level notes first:

On Tue, Dec 30, 2025 at 05:09:28PM +0800, Ruidong Tian wrote:
> This series introduces support for the ARM Error Source Table (AEST), aligning
> with version 2.0 of ACPI for Armv8 RAS Extensions [0].

I'd like to hear from ARM folks what the strategy for this thing is...

> AEST provides a critical mechanism for hardware to directly notify the
> operating system kernel about RAS errors via interrupts, a concept known as
> Kernel-first error handling. Compared to firmware-first error handling
> (e.g., GHES), AEST offers a more lightweight approach. This efficiency allows
> the OS to potentially report every Corrected Error (CE), enabling upper-layer
> applications to leverage CE information for error prediction[1][2].
> 
> This series is based on Tyler Baicar's preliminary patches [3], which have not
> yet been sent to the mailing list as v2.

I guess I'll wait for those first.

> AEST Driver Architecture
> ========================
> 
> The AEST driver is structured into three primary components:
>   - AEST device: Responsible for handling interrupts, managing the lifecycle
>                  of AEST nodes, and processing error records.
>   - AEST node: Corresponds directly to a RAS node in the hardware

What is a "RAS node"?

>   - AEST record: Represents a set of RAS registers associated with a specific
>                  error source.

...

> Address Translation
> ===================
> 
> As described in section 2.2 [0], error addresses reported by AEST records
> may be "node-specific Logical Addresses" rather than the "System Physical
> Addresses" (SPA) used by the kernel. Therefore, the driver needs to translate
> these Logical Addresses (LA) to SPA. This translation mechanism is conceptually
> similar to AMD's Address Translation Logic (ATL) [4], leading patch 0014 to
> introduce a common translation function for both AMD and ARM architectures.

Say what now? 

The ATL is very AMD-specific. What does "conceptually similar" mean exactly?
What happens if we have to change the ATL and break your use case in the
process?

What exact functionality from the ATL do you really need here?

Thx.

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette


From arnd at arndb.de  Tue Dec 30 13:08:04 2025
From: arnd at arndb.de (Arnd Bergmann)
Date: Tue, 30 Dec 2025 22:08:04 +0100
Subject: [PATCH 4/5] x86/uapi: Stop leaking kconfig references to userspace
In-Reply-To: <20251230-headers_install-config-leak-v1-4-efba5c58073d@linutronix.de>
References: <20251230-headers_install-config-leak-v1-0-efba5c58073d@linutronix.de>
 <20251230-headers_install-config-leak-v1-4-efba5c58073d@linutronix.de>
Message-ID: <a745a59f-947c-4847-b31c-5e32125a51a4@app.fastmail.com>

On Tue, Dec 30, 2025, at 08:10, Thomas Wei?schuh wrote:
> 
>  /* entries in ARCH_DLINFO: */
> -#if defined(CONFIG_IA32_EMULATION) || !defined(CONFIG_X86_64)
> +#if defined(__KERNEL__) && (defined(CONFIG_IA32_EMULATION) || 
> !defined(CONFIG_X86_64))
>  # define AT_VECTOR_SIZE_ARCH 3
>  #else /* else it's non-compat x86-64 */
>  # define AT_VECTOR_SIZE_ARCH 2

While this patch clearly keeps the current behavior, I think it's
wrong, and 32-bit userspace should see a '3' instead of '2' here.

It can probably just be '3' unconditionally, or we can
make it more complex and have a userspace definition based
on __x86_64__ being defined.

I also wonder if there is a problem with the third
x86-64 entry being zero rather than AT_IGNORE. I see that
some architectures do it like this, to keep the number constant
even if some entries are missing:

        if (likely(signal_minsigstksz))                          \
                NEW_AUX_ENT(AT_MINSIGSTKSZ, signal_minsigstksz); \
        else                                                     \
                NEW_AUX_ENT(AT_IGNORE, 0);                       \

     Arnd


From arnd at arndb.de  Tue Dec 30 13:19:22 2025
From: arnd at arndb.de (Arnd Bergmann)
Date: Tue, 30 Dec 2025 22:19:22 +0100
Subject: [PATCH 3/5] nios2: uapi: Stop leaking CONFIG_NIOS2_CI_SWAB_{NO,SUPPORT}
 references to userspace
In-Reply-To: <20251230-headers_install-config-leak-v1-3-efba5c58073d@linutronix.de>
References: <20251230-headers_install-config-leak-v1-0-efba5c58073d@linutronix.de>
 <20251230-headers_install-config-leak-v1-3-efba5c58073d@linutronix.de>
Message-ID: <93c55086-931a-4282-a94c-de4954047fa9@app.fastmail.com>

On Tue, Dec 30, 2025, at 08:10, Thomas Wei?schuh wrote:
> UAPI headers are not supposed to leak references to kconfig symbols.
> These won't be set when building userspace. Hide the kconfig reference
> behind 'ifdef __KERNEL__', so it will be stripped by
> headers_install.sh. The result for userspace will be the same, but the
> exceptions in headers_install.sh can also be removed.
>
> Signed-off-by: Thomas Wei?schuh <thomas.weissschuh at linutronix.de>

Acked-by: Arnd Bergmann <arnd at arndb.de>

> ---
>  arch/nios2/include/uapi/asm/swab.h | 2 ++
>  scripts/headers_install.sh         | 2 --
>  2 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/arch/nios2/include/uapi/asm/swab.h 
> b/arch/nios2/include/uapi/asm/swab.h
> index 9750547a5f82..bbfa9bd10b2f 100644
> --- a/arch/nios2/include/uapi/asm/swab.h
> +++ b/arch/nios2/include/uapi/asm/swab.h
> @@ -14,6 +14,7 @@
>  #include <linux/types.h>
>  #include <asm-generic/swab.h>
> 
> +#ifdef __KERNEL__
>  #ifdef CONFIG_NIOS2_CI_SWAB_SUPPORT
>  #ifdef __GNUC__
> 

I'm fairly sure this approach is correct, but I noticed
that this makes arch/nios2/include/uapi/asm/swab.h empty
in userspace, so you could just move the current file
to arch/nios2/include/asm/swab.h instead and fall back to
the asm-generic header for uapi.

     Arnd


From arnd at arndb.de  Tue Dec 30 13:23:08 2025
From: arnd at arndb.de (Arnd Bergmann)
Date: Tue, 30 Dec 2025 22:23:08 +0100
Subject: [PATCH 1/5] ARC: uapi: Stop leaking CONFIG_ARC_HAS_SWAPE reference to
 userspace
In-Reply-To: <20251230-headers_install-config-leak-v1-1-efba5c58073d@linutronix.de>
References: <20251230-headers_install-config-leak-v1-0-efba5c58073d@linutronix.de>
 <20251230-headers_install-config-leak-v1-1-efba5c58073d@linutronix.de>
Message-ID: <9ecebf46-c230-4074-9001-7ba9d65634f1@app.fastmail.com>

On Tue, Dec 30, 2025, at 08:10, Thomas Wei?schuh wrote:
> UAPI headers are not supposed to leak references to kconfig symbols.
> These won't be set when building userspace. Hide the kconfig reference
> behind 'if defined(__KERNEL__)', so it will be stripped by
> headers_install.sh. The result for userspace will be the same, but the
> exception in headers_install.sh can also be removed.
>
> Signed-off-by: Thomas Wei?schuh <thomas.weissschuh at linutronix.de>

Acked-by: Arnd Bergmann <arnd at arndb.de>

Same as for the nios2 version, I think the nicer solution would
be to use the asm-generic header for uapi and move this one
to arch/arc/include/asm/swab.h for kernel-internal use.

In theory, using 'select ARCH_USE_BUILTIN_BSWAP' in Kconfig should
let the compiler pick the best swap instruction, which would
be even less code, but I'm not sure if there was a reason that
nios2 and arc don't already do this.

      Arnd


From marex at nabladev.com  Tue Dec 30 13:28:27 2025
From: marex at nabladev.com (Marek Vasut)
Date: Tue, 30 Dec 2025 22:28:27 +0100
Subject: [PATCH v3 4/4] arm64: dts: imx8mn: Add ifm VHIP4 EvalBoard v1 and
 v2
In-Reply-To: <CAOMZO5Aa6iDg2u-sJu1yPZX8T2wE=QVzwSbxjZHo1bMwfDW5HQ@mail.gmail.com>
References: <20251230184121.52635-1-marex@nabladev.com>
 <20251230184121.52635-4-marex@nabladev.com>
 <CAOMZO5Aa6iDg2u-sJu1yPZX8T2wE=QVzwSbxjZHo1bMwfDW5HQ@mail.gmail.com>
Message-ID: <8df1ff09-a5be-418f-9723-3f64bf97eba8@nabladev.com>

On 12/30/25 7:52 PM, Fabio Estevam wrote:
> On Tue, Dec 30, 2025 at 3:41?PM Marek Vasut <marex at nabladev.com> wrote:
> 
>> +&gpio4 {
>> +       /*
>> +        * Hog USB-nRESET high here, since neither U-Boot nor Linux
>> +        * has any support for USB Hub GPIO reset so far.
> 
> Which USB hub chip is used?
USB2512B , so I can use this.

Both temp sensor node names are also updated.

Thanks.


From marex at nabladev.com  Tue Dec 30 13:32:31 2025
From: marex at nabladev.com (Marek Vasut)
Date: Tue, 30 Dec 2025 22:32:31 +0100
Subject: [PATCH v4 1/4] dt-bindings: vendor-prefixes: Document ifm electronic gmbh
Message-ID: <20251230213401.219808-1-marex@nabladev.com>

ifm is a manufacturer of industrial sensors, control technology and
automation solutions. Document their vendor prefix, which is already
used for ifm,ac14xx and other powerpc devices.

Acked-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Marek Vasut <marex at nabladev.com>
---
Cc: Christian Eggers <ceggers at arri.de>
Cc: Conor Dooley <conor+dt at kernel.org>
Cc: Fabio Estevam <festevam at gmail.com>
Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
Cc: Krzysztof Kozlowski <krzk+dt at kernel.org>
Cc: Markus Heidelberg <m.heidelberg at cab.de>
Cc: Rob Herring <robh at kernel.org>
Cc: Shawn Guo <shawnguo at kernel.org>
Cc: devicetree at vger.kernel.org
Cc: imx at lists.linux.dev
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-kernel at vger.kernel.org
---
V2: Add AB from Rob
V3: No change
V4: No change
---
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index b7c6c528e0185..70d99ac01aa34 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -755,6 +755,8 @@ patternProperties:
     description: IEI Integration Corp.
   "^ifi,.*":
     description: Ingenieurburo Fur Ic-Technologie (I/F/I)
+  "^ifm,.*":
+    description: ifm electronic gmbh
   "^ilitek,.*":
     description: ILI Technology Corporation (ILITEK)
   "^imagis,.*":
-- 
2.51.0



From marex at nabladev.com  Tue Dec 30 13:32:33 2025
From: marex at nabladev.com (Marek Vasut)
Date: Tue, 30 Dec 2025 22:32:33 +0100
Subject: [PATCH v4 3/4] arm64: dts: imx8mn: Add SNVS LPGPR
In-Reply-To: <20251230213401.219808-1-marex@nabladev.com>
References: <20251230213401.219808-1-marex@nabladev.com>
Message-ID: <20251230213401.219808-3-marex@nabladev.com>

Add SNVS LPGPR bindings to MX8M Nano, the LPGPR is used to store
boot counter.

Signed-off-by: Marek Vasut <marex at nabladev.com>
---
Cc: Christian Eggers <ceggers at arri.de>
Cc: Conor Dooley <conor+dt at kernel.org>
Cc: Fabio Estevam <festevam at gmail.com>
Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
Cc: Krzysztof Kozlowski <krzk+dt at kernel.org>
Cc: Markus Heidelberg <m.heidelberg at cab.de>
Cc: Rob Herring <robh at kernel.org>
Cc: Shawn Guo <shawnguo at kernel.org>
Cc: devicetree at vger.kernel.org
Cc: imx at lists.linux.dev
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-kernel at vger.kernel.org
---
V2: New patch
V3: No change
V4: No change
---
 arch/arm64/boot/dts/freescale/imx8mn.dtsi | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mn.dtsi b/arch/arm64/boot/dts/freescale/imx8mn.dtsi
index b98b3d0ddf25a..3199bc0966b03 100644
--- a/arch/arm64/boot/dts/freescale/imx8mn.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mn.dtsi
@@ -628,6 +628,11 @@ snvs_pwrkey: snvs-powerkey {
 					wakeup-source;
 					status = "disabled";
 				};
+
+				snvs_lpgpr: snvs-lpgpr {
+					compatible = "fsl,imx8mn-snvs-lpgpr",
+						     "fsl,imx7d-snvs-lpgpr";
+				};
 			};
 
 			clk: clock-controller at 30380000 {
-- 
2.51.0



From marex at nabladev.com  Tue Dec 30 13:32:32 2025
From: marex at nabladev.com (Marek Vasut)
Date: Tue, 30 Dec 2025 22:32:32 +0100
Subject: [PATCH v4 2/4] dt-bindings: arm: fsl: Document ifm VHIP4 EvalBoard v1 and v2
In-Reply-To: <20251230213401.219808-1-marex@nabladev.com>
References: <20251230213401.219808-1-marex@nabladev.com>
Message-ID: <20251230213401.219808-2-marex@nabladev.com>

Document ifm i.MX8MN VHIP4 EvalBoard v1 and v2 reference design binding.
This system exists in two generations, v1 and v2, which share a lot of
commonality. The boards come with either single gigabit ethernet or an
KSZ8794 fast-ethernet switch, boot from eMMC, and offer CAN interfaces
via Microchip MCP25xx SPI CAN controllers, UART, and USB host. The GPU
is not available in the SoC populated on these devices.

Acked-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Marek Vasut <marex at nabladev.com>
---
Cc: Christian Eggers <ceggers at arri.de>
Cc: Conor Dooley <conor+dt at kernel.org>
Cc: Fabio Estevam <festevam at gmail.com>
Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
Cc: Krzysztof Kozlowski <krzk+dt at kernel.org>
Cc: Markus Heidelberg <m.heidelberg at cab.de>
Cc: Rob Herring <robh at kernel.org>
Cc: Shawn Guo <shawnguo at kernel.org>
Cc: devicetree at vger.kernel.org
Cc: imx at lists.linux.dev
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-kernel at vger.kernel.org
---
V2: Add AB from Rob
V3: No change
V4: No change
---
 Documentation/devicetree/bindings/arm/fsl.yaml | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
index 68a2d5fecc43b..4d0aee780bcb2 100644
--- a/Documentation/devicetree/bindings/arm/fsl.yaml
+++ b/Documentation/devicetree/bindings/arm/fsl.yaml
@@ -1071,6 +1071,15 @@ properties:
               - gw,imx8mn-gw7902          # i.MX8MM Gateworks Board
           - const: fsl,imx8mn
 
+      - description: ifm i.MX8MN VHIP4 based boards
+        items:
+          - enum:
+              - ifm,imx8mn-vhip4-evalboard-v1
+              - ifm,imx8mn-vhip4-evalboard-v2
+          - const: ifm,imx8mn-vhip4-evalboard
+          - const: ifm,imx8mn-vhip4
+          - const: fsl,imx8mn
+
       - description: Variscite VAR-SOM-MX8MN based boards
         items:
           - enum:
-- 
2.51.0



From marex at nabladev.com  Tue Dec 30 13:32:34 2025
From: marex at nabladev.com (Marek Vasut)
Date: Tue, 30 Dec 2025 22:32:34 +0100
Subject: [PATCH v4 4/4] arm64: dts: imx8mn: Add ifm VHIP4 EvalBoard v1 and v2
In-Reply-To: <20251230213401.219808-1-marex@nabladev.com>
References: <20251230213401.219808-1-marex@nabladev.com>
Message-ID: <20251230213401.219808-4-marex@nabladev.com>

From: Fedor Ross <fedor.ross at ifm.com>

Add support for ifm i.MX8MN VHIP4 EvalBoard v1 and v2 reference design.
This system exists in two generations, v1 and v2, which share a lot of
commonality. The boards come with either single gigabit ethernet or an
KSZ8794 fast-ethernet switch, boot from eMMC, and offer CAN interfaces
via Microchip MCP25xx SPI CAN controllers, UART, and USB host. The GPU
is not available in the SoC populated on these devices.

Signed-off-by: Fedor Ross <fedor.ross at ifm.com>
Signed-off-by: Marek Vasut <marex at nabladev.com>
---
Cc: Christian Eggers <ceggers at arri.de>
Cc: Conor Dooley <conor+dt at kernel.org>
Cc: Fabio Estevam <festevam at gmail.com>
Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
Cc: Krzysztof Kozlowski <krzk+dt at kernel.org>
Cc: Markus Heidelberg <m.heidelberg at cab.de>
Cc: Rob Herring <robh at kernel.org>
Cc: Shawn Guo <shawnguo at kernel.org>
Cc: devicetree at vger.kernel.org
Cc: imx at lists.linux.dev
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-kernel at vger.kernel.org
---
V2: - Drop snvs-lpgpr node in favor of separate patch to imx8mn.dtsi
    - Sort properties and update newlines according to V1 feedback
V3: - Drop fsl,magic-packet
V4: - Switch USB hub to compatible = "usb424,2512", "usb424,2514"
    - Use temperature-sensor at 48 for temperature sensor node names
    - Sort pinctrl_gpio_5 iomux node
---
 arch/arm64/boot/dts/freescale/Makefile        |  19 +
 .../imx8mn-vhip4-evalboard-common.dtsi        | 398 ++++++++++++++++++
 ...imx8mn-vhip4-evalboard-ksz8794-common.dtsi |  98 +++++
 ...mn-vhip4-evalboard-v1-overlay-ksz8794.dtso |  24 ++
 ...mn-vhip4-evalboard-v1-overlay-ksz9031.dtso |  48 +++
 .../freescale/imx8mn-vhip4-evalboard-v1.dts   | 258 ++++++++++++
 ...n-vhip4-evalboard-v2-overlay-adin1300.dtso |  60 +++
 ...mn-vhip4-evalboard-v2-overlay-ksz8794.dtso |  24 ++
 .../freescale/imx8mn-vhip4-evalboard-v2.dts   | 221 ++++++++++
 9 files changed, 1150 insertions(+)
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-common.dtsi
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-ksz8794-common.dtsi
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtso
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtso
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1.dts
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtso
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtso
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2.dts

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index f30d3fd724d0c..01b2ec5ad81ff 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -191,6 +191,25 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mn-tqma8mqnl-mba8mx.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-var-som-symphony.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-venice-gw7902.dtb
 
+imx8mn-vhip4-evalboard-v1-overlay-ksz8794-dtbs := imx8mn-vhip4-evalboard-v1.dtb \
+						  imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtbo
+imx8mn-vhip4-evalboard-v1-overlay-ksz9031-dtbs := imx8mn-vhip4-evalboard-v1.dtb \
+						  imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtbo
+imx8mn-vhip4-evalboard-v2-overlay-ksz8794-dtbs := imx8mn-vhip4-evalboard-v2.dtb \
+						  imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtbo
+imx8mn-vhip4-evalboard-v2-overlay-adin1300-dtbs := imx8mn-vhip4-evalboard-v2.dtb \
+						   imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtbo
+dtb-$(CONFIG_ARCH_MXC) += imx8mn-vhip4-evalboard-v1.dtb \
+			  imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtb \
+			  imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtbo \
+			  imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtb \
+			  imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtbo \
+			  imx8mn-vhip4-evalboard-v2.dtb \
+			  imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtb \
+			  imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtbo \
+			  imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtb \
+			  imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtbo
+
 imx8mn-tqma8mqnl-mba8mx-lvds-tm070jvhg33-dtbs += imx8mn-tqma8mqnl-mba8mx.dtb imx8mn-tqma8mqnl-mba8mx-lvds-tm070jvhg33.dtbo
 imx8mn-tqma8mqnl-mba8mx-usbotg-dtbs += imx8mn-tqma8mqnl-mba8mx.dtb imx8mn-tqma8mqnl-mba8mx-usbotg.dtbo
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-tqma8mqnl-mba8mx-lvds-tm070jvhg33.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-common.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-common.dtsi
new file mode 100644
index 0000000000000..a9506ecf9647b
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-common.dtsi
@@ -0,0 +1,398 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2020-2024 Fedor Ross <fedor.ross at ifm.com>
+ */
+
+#include "imx8mn.dtsi"
+#include <dt-bindings/leds/common.h>
+
+/ {
+	model = "ifm i.MX8MNano VHIP4 Evaluation Board";
+	compatible = "ifm,imx8mn-vhip4-evalboard", "ifm,imx8mn-vhip4", "fsl,imx8mn";
+
+	aliases {
+		mmc0 = &usdhc3;
+		mmc1 = &usdhc1;
+		mmc2 = &usdhc2;
+		rtc0 = &hw_rtc;
+		rtc1 = &snvs_rtc;
+	};
+
+	chosen {
+		bootargs = "console=ttymxc2,115200 earlycon=ec_imx6q,0x30880000,115200 rootwait";
+		stdout-path = &uart3;
+	};
+
+	memory at 40000000 {
+		device_type = "memory";
+		reg = <0x0 0x40000000 0 0x40000000>;
+	};
+
+	can_clk20m: can-clk20m {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <20000000>;
+	};
+
+	can_clk40m: can-clk40m {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <40000000>;
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+		pinctrl-0 = <&pinctrl_gpio_button>;
+		pinctrl-names = "default";
+
+		button-2 {
+			label = "Button2";
+			gpios = <&gpio2 16 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_2>;
+		};
+
+		button-3 {
+			label = "Button3";
+			gpios = <&gpio2 18 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_3>;
+		};
+	};
+
+	ifm_led: led {
+		compatible = "gpio-leds";
+		pinctrl-0 = <&pinctrl_gpio_led>;
+		pinctrl-names = "default", "extended";
+
+		led-0 {
+			function = LED_FUNCTION_STATUS;
+			function-enumerator = <1>;
+			color = <LED_COLOR_ID_YELLOW>;
+			gpios = <&gpio2 13 GPIO_ACTIVE_HIGH>;
+			default-state = "keep";
+		};
+
+		led-1 {
+			function = LED_FUNCTION_STATUS;
+			function-enumerator = <2>;
+			color = <LED_COLOR_ID_GREEN>;
+			gpios = <&gpio2 15 GPIO_ACTIVE_HIGH>;
+			default-state = "keep";
+		};
+	};
+};
+
+&A53_0 {
+	cpu-supply = <&buck2_reg>;
+};
+
+&A53_1 {
+	cpu-supply = <&buck2_reg>;
+};
+
+&A53_2 {
+	cpu-supply = <&buck2_reg>;
+};
+
+&A53_3 {
+	cpu-supply = <&buck2_reg>;
+};
+
+&ddrc {
+	operating-points-v2 = <&ddrc_opp_table>;
+
+	ddrc_opp_table: opp-table {
+		compatible = "operating-points-v2";
+
+		opp-25000000 {
+			opp-hz = /bits/ 64 <25000000>;
+		};
+
+		opp-100000000 {
+			opp-hz = /bits/ 64 <100000000>;
+		};
+
+		opp-600000000 {
+			opp-hz = /bits/ 64 <600000000>;
+		};
+	};
+};
+
+&ecspi1 {
+	pinctrl-names = "default", "cs";
+	pinctrl-0 = <&pinctrl_ecspi1>;
+	pinctrl-1 = <&pinctrl_ecspi1_cs>;
+	/delete-property/ dmas;
+	/delete-property/ dma-names;
+};
+
+&ecspi3 {
+	pinctrl-names = "default", "cs";
+	pinctrl-0 = <&pinctrl_ecspi3>;
+	pinctrl-1 = <&pinctrl_ecspi3_cs>;
+	/delete-property/ dmas;
+	/delete-property/ dma-names;
+};
+
+&gpu {
+	/* SoC has GPU fused off. */
+	status = "disabled";
+};
+
+&i2c1 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default", "gpio";
+	pinctrl-0 = <&pinctrl_i2c1>;
+	pinctrl-1 = <&pinctrl_i2c1_gpio>;
+
+	eeprom at 51 {
+		compatible = "atmel,24c128";
+		reg = <0x51>;
+	};
+
+	hw_rtc: rtc at 52 {
+		compatible = "microcrystal,rv3028";
+		reg = <0x52>;
+	};
+};
+
+&i2c3 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default", "gpio";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	pinctrl-1 = <&pinctrl_i2c3_gpio>;
+
+	ifm_pmic: pmic at 4b {
+		compatible = "rohm,bd71847";
+		reg = <0x4b>;
+		pinctrl-0 = <&pinctrl_pmic>;
+		rohm,reset-snvs-powered;
+
+		regulators {
+			buck1_reg: BUCK1 {
+				regulator-name = "buck1";
+				regulator-min-microvolt = <790000>;
+				regulator-max-microvolt = <860000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <1250>;
+			};
+
+			buck2_reg: BUCK2 {
+				regulator-name = "buck2";
+				regulator-min-microvolt = <840000>;
+				regulator-max-microvolt = <960000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <1250>;
+			};
+
+			buck3_reg: BUCK3 {
+				// BUCK5 in datasheet
+				regulator-name = "buck3";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1350000>;
+			};
+
+			buck4_reg: BUCK4 {
+				// BUCK6 in datasheet
+				regulator-name = "buck4";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			buck5_reg: BUCK5 {
+				// BUCK7 in datasheet
+				regulator-name = "buck5";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			buck6_reg: BUCK6 {
+				// BUCK8 in datasheet
+				regulator-name = "buck6";
+				regulator-min-microvolt = <1100000>;
+				regulator-max-microvolt = <1100000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo1_reg: LDO1 {
+				regulator-name = "ldo1";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo2_reg: LDO2 {
+				regulator-name = "ldo2";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo3_reg: LDO3 {
+				regulator-name = "ldo3";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo4_reg: LDO4 {
+				regulator-name = "ldo4";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1800000>;
+			};
+
+			ldo5_reg: LDO5 {
+				regulator-name = "ldo5";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+			};
+
+			ldo6_reg: LDO6 {
+				regulator-name = "ldo6";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+		};
+	};
+};
+
+&iomuxc {
+	pinctrl_ecspi1: ecspi1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK		0x110
+			MX8MN_IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI		0x110
+			MX8MN_IOMUXC_ECSPI1_MISO_ECSPI1_MISO		0x190
+		>;
+	};
+
+	pinctrl_ecspi3: ecspi3-grp {
+		fsl,pins = <
+			/* SPI3_CAN_CLK */
+			MX8MN_IOMUXC_UART1_RXD_ECSPI3_SCLK		0x110
+			/* SPI3_CAN_MOSI */
+			MX8MN_IOMUXC_UART1_TXD_ECSPI3_MOSI		0x110
+			/* SPI3_CAN_MISO */
+			MX8MN_IOMUXC_UART2_RXD_ECSPI3_MISO		0x190
+		>;
+	};
+
+	pinctrl_gpio_button: gpiobutton-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD2_DATA1_GPIO2_IO16		0x96
+			MX8MN_IOMUXC_SD2_DATA3_GPIO2_IO18		0x96
+		>;
+	};
+
+	pinctrl_gpio_led: gpioled-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD2_CLK_GPIO2_IO13			0x116
+			MX8MN_IOMUXC_SD2_DATA0_GPIO2_IO15		0x116
+		>;
+	};
+
+	pinctrl_usdhc3: usdhc3-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK		0x40000110
+			MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d0
+			MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d0
+			MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d0
+			MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d0
+			MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d0
+			MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d0
+			MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d0
+			MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d0
+			MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d0
+			MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x190
+			MX8MN_IOMUXC_NAND_READY_B_USDHC3_RESET_B	0x150
+		>;
+	};
+
+	pinctrl_usdhc3_100mhz: usdhc3-100mhz-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK		0x40000114
+			MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d4
+			MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d4
+			MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d4
+			MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d4
+			MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d4
+			MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d4
+			MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d4
+			MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d4
+			MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d4
+			MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x194
+			MX8MN_IOMUXC_NAND_READY_B_USDHC3_RESET_B	0x150
+		>;
+	};
+
+	pinctrl_usdhc3_200mhz: usdhc3-200mhz-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK		0x40000116
+			MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d6
+			MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d6
+			MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d6
+			MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d6
+			MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d6
+			MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d6
+			MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d6
+			MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d6
+			MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d6
+			MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x196
+			MX8MN_IOMUXC_NAND_READY_B_USDHC3_RESET_B	0x150
+		>;
+	};
+
+	pinctrl_wdog: wdog-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B		0x64
+		>;
+	};
+};
+
+&pgc_gpumix {
+	/* SoC has GPU fused off. */
+	status = "disabled";
+};
+
+&snvs_pwrkey {
+	status = "okay";
+};
+
+&uart3 { /* console */
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart3>;
+	status = "okay";
+};
+
+&usbotg1 {
+	status = "okay";
+};
+
+&usdhc3 {
+	assigned-clocks = <&clk IMX8MN_CLK_USDHC3_ROOT>;
+	assigned-clock-rates = <400000000>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc3>;
+	pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
+	bus-width = <8>;
+	non-removable;
+	status = "okay";
+};
+
+&wdog1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_wdog>;
+	fsl,ext-reset-output;
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-ksz8794-common.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-ksz8794-common.dtsi
new file mode 100644
index 0000000000000..c1a98ec2f4382
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-ksz8794-common.dtsi
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2025 Fedor Ross <fedor.ross at ifm.com>
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+
+#include "imx8mn-pinfunc.h"
+
+&ecspi1 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+
+	ksz8794: ethernet-switch at 1 {
+		compatible = "microchip,ksz8794";
+		pinctrl-names = "default", "reset";
+		pinctrl-0 = <&pinctrl_ks8794>;
+		pinctrl-1 = <&pinctrl_ks8794>;
+		reg = <1>;
+		reset-gpios = <&gpio4 28 GPIO_ACTIVE_LOW>;
+		spi-max-frequency = <5000000>;
+
+		ethernet-ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+				label = "lan1";
+			};
+
+			port at 1 {
+				reg = <1>;
+				label = "lan2";
+			};
+
+			port at 2 {
+				reg = <2>;
+				label = "lan3";
+			};
+
+			port at 4 {
+				reg = <4>;
+				label = "cpu";
+				ethernet = <&fec1>;
+				phy-mode = "rgmii-id";
+				rx-internal-delay-ps = <2000>;
+				tx-internal-delay-ps = <2000>;
+				fixed-link {
+					full-duplex;
+					speed = <1000>;
+				};
+			};
+		};
+	};
+};
+
+&fec1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_fec1>;
+	phy-mode = "rgmii-id";
+	status = "okay";
+
+	fixed-link {
+		full-duplex;
+		speed = <1000>;
+	};
+};
+
+&iomuxc {
+	pinctrl_fec1: fec1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_ENET_MDC_ENET1_MDC			0x16
+			MX8MN_IOMUXC_ENET_MDIO_ENET1_MDIO		0x96
+			MX8MN_IOMUXC_ENET_TD3_ENET1_RGMII_TD3		0x16
+			MX8MN_IOMUXC_ENET_TD2_ENET1_RGMII_TD2		0x16
+			MX8MN_IOMUXC_ENET_TD1_ENET1_RGMII_TD1		0x16
+			MX8MN_IOMUXC_ENET_TD0_ENET1_RGMII_TD0		0x16
+			MX8MN_IOMUXC_ENET_RD3_ENET1_RGMII_RD3		0x96
+			MX8MN_IOMUXC_ENET_RD2_ENET1_RGMII_RD2		0x96
+			MX8MN_IOMUXC_ENET_RD1_ENET1_RGMII_RD1		0x96
+			MX8MN_IOMUXC_ENET_RD0_ENET1_RGMII_RD0		0x96
+			MX8MN_IOMUXC_ENET_TXC_ENET1_RGMII_TXC		0x10
+			MX8MN_IOMUXC_ENET_RXC_ENET1_RGMII_RXC		0x96
+			MX8MN_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x96
+			MX8MN_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x16
+			MX8MN_IOMUXC_SAI3_TXFS_GPIO4_IO31		0x1d6
+		>;
+	};
+
+	pinctrl_ks8794: ks8794-grp {
+		fsl,pins = <
+			/* KSZ8794 reset line */
+			MX8MN_IOMUXC_SAI3_RXFS_GPIO4_IO28		0x16
+		>;
+	};
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtso b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtso
new file mode 100644
index 0000000000000..20eb427f3dd66
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz8794.dtso
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2021 Marek Vasut
+ */
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+#include "imx8mn-pinfunc.h"
+
+&pinctrl_ecspi1 {
+	fsl,pins = <
+		MX8MN_IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK		0x10
+		MX8MN_IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI		0x10
+		MX8MN_IOMUXC_ECSPI1_MISO_ECSPI1_MISO		0x90
+		/* KS8794 nCS */
+		MX8MN_IOMUXC_I2C4_SDA_GPIO5_IO21		0x150
+		/* ANV32C81 nCS */
+		MX8MN_IOMUXC_ECSPI1_SS0_GPIO5_IO9		0x150
+	>;
+};
+
+#include "imx8mn-vhip4-evalboard-ksz8794-common.dtsi"
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtso b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtso
new file mode 100644
index 0000000000000..de24206106b3b
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1-overlay-ksz9031.dtso
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2021 Marek Vasut
+ */
+/dts-v1/;
+/plugin/;
+
+#include "imx8mn-pinfunc.h"
+
+&fec1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_fec1>;
+	phy-handle = <&ethphy0>;
+	phy-mode = "rgmii-id";
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy0: ethernet-phy at 0 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <0>;
+		};
+	};
+};
+
+&iomuxc {
+	pinctrl_fec1: fec1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_ENET_MDC_ENET1_MDC			0x16
+			MX8MN_IOMUXC_ENET_MDIO_ENET1_MDIO		0x96
+			MX8MN_IOMUXC_ENET_TD3_ENET1_RGMII_TD3		0x16
+			MX8MN_IOMUXC_ENET_TD2_ENET1_RGMII_TD2		0x16
+			MX8MN_IOMUXC_ENET_TD1_ENET1_RGMII_TD1		0x16
+			MX8MN_IOMUXC_ENET_TD0_ENET1_RGMII_TD0		0x16
+			MX8MN_IOMUXC_ENET_RD3_ENET1_RGMII_RD3		0x96
+			MX8MN_IOMUXC_ENET_RD2_ENET1_RGMII_RD2		0x96
+			MX8MN_IOMUXC_ENET_RD1_ENET1_RGMII_RD1		0x96
+			MX8MN_IOMUXC_ENET_RD0_ENET1_RGMII_RD0		0x96
+			MX8MN_IOMUXC_ENET_TXC_ENET1_RGMII_TXC		0x16
+			MX8MN_IOMUXC_ENET_RXC_ENET1_RGMII_RXC		0x96
+			MX8MN_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x96
+			MX8MN_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x16
+			MX8MN_IOMUXC_SAI3_TXFS_GPIO4_IO31		0x1d6
+		>;
+	};
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1.dts b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1.dts
new file mode 100644
index 0000000000000..5f37065bf43f3
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v1.dts
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2020-2024 Fedor Ross <fedor.ross at ifm.com>
+ */
+
+/dts-v1/;
+
+#include "imx8mn-vhip4-evalboard-common.dtsi"
+
+/ {
+	model = "ifm i.MX8MNano VHIP4 Evaluation Board v1";
+	compatible = "ifm,imx8mn-vhip4-evalboard-v1", "ifm,imx8mn-vhip4-evalboard",
+		     "ifm,imx8mn-vhip4", "fsl,imx8mn";
+};
+
+&ifm_led {
+	pinctrl-1 = <&pinctrl_gpio_led_v1>;
+
+	led-2 {
+		function = LED_FUNCTION_STATUS;
+		function-enumerator = <3>;
+		color = <LED_COLOR_ID_YELLOW>;
+		gpios = <&gpio2 17 GPIO_ACTIVE_HIGH>;
+		default-state = "keep";
+	};
+
+	led-3 {
+		function = LED_FUNCTION_STATUS;
+		function-enumerator = <4>;
+		color = <LED_COLOR_ID_GREEN>;
+		gpios = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+		default-state = "keep";
+	};
+};
+
+&ecspi1 {
+	cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>, <&gpio5 21 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	eeprom at 0 {
+		compatible = "anvo,anv32c81w", "atmel,at25";
+		reg = <0>;
+		spi-max-frequency = <20000000>;
+		spi-cpha;
+		spi-cpol;
+		pagesize = <1>;
+		size = <32768>;
+		address-width = <16>;
+	};
+};
+
+&ecspi3 {
+	cs-gpios = <&gpio5 25 GPIO_ACTIVE_LOW>, <&gpio5 4 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	can0: can at 0 {
+		compatible = "microchip,mcp25625";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_mcp25625>;
+		reg = <0>;
+		clocks = <&can_clk20m>;
+		interrupt-parent = <&gpio4>;
+		interrupts = <21 IRQ_TYPE_LEVEL_LOW>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	can1: can at 1 {
+		compatible = "microchip,mcp2518fd";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_mcp2518>;
+		reg = <1>;
+		clocks = <&can_clk40m>;
+		interrupt-parent = <&gpio5>;
+		interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+		microchip,rx-int-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>;
+		spi-max-frequency = <20000000>;
+	};
+};
+
+&i2c1 {
+	scl-gpios = <&gpio5 14 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	sda-gpios = <&gpio5 15 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+
+	temperature-sensor at 48 {
+		compatible = "national,lm75";
+		reg = <0x48>;
+	};
+
+	eeprom at 50 {
+		compatible = "atmel,24c128";
+		reg = <0x50>;
+	};
+};
+
+&i2c2 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default", "gpio";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	pinctrl-1 = <&pinctrl_i2c2_gpio>;
+	scl-gpios = <&gpio5 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	sda-gpios = <&gpio5 17 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+&i2c3 {
+	scl-gpios = <&gpio2 10 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	sda-gpios = <&gpio2 11 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+&ifm_pmic {
+	interrupt-parent = <&gpio2>;
+	interrupts = <0 GPIO_ACTIVE_LOW>;
+};
+
+&iomuxc {
+	pinctrl_ecspi1_cs: ecspi1-cs-grp {
+		fsl,pins = <
+			/* KS8794 nCS */
+			MX8MN_IOMUXC_I2C4_SDA_GPIO5_IO21		0x150
+			/* ANV32C81 nCS */
+			MX8MN_IOMUXC_ECSPI1_SS0_GPIO5_IO9		0x150
+		>;
+	};
+
+	pinctrl_ecspi3_cs: ecspi3-cs-grp {
+		fsl,pins = <
+			/* MCP25625 nCS */
+			MX8MN_IOMUXC_UART2_TXD_GPIO5_IO25		0x150
+			/* MCP2518FD nCS */
+			MX8MN_IOMUXC_SPDIF_RX_GPIO5_IO4			0x150
+		>;
+	};
+
+	pinctrl_gpio_5: gpio5-grp {
+		fsl,pins = <
+			/* CFG_EEPROM_WP */
+			MX8MN_IOMUXC_I2C4_SCL_GPIO5_IO20		0x140
+		>;
+	};
+
+	pinctrl_gpio_led_v1: gpioled-v1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD2_DATA2_GPIO2_IO17		0x116
+			MX8MN_IOMUXC_SD2_RESET_B_GPIO2_IO19		0x116
+		>;
+	};
+
+	pinctrl_i2c1: i2c1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C1_SCL_I2C1_SCL			0x40000056
+			MX8MN_IOMUXC_I2C1_SDA_I2C1_SDA			0x400000d6
+		>;
+	};
+
+	pinctrl_i2c1_gpio: i2c1-gpio-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C1_SCL_GPIO5_IO14		0x56
+			MX8MN_IOMUXC_I2C1_SDA_GPIO5_IO15		0xd6
+		>;
+	};
+
+	pinctrl_i2c2: i2c2-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C2_SCL_I2C2_SCL			0x40000056
+			MX8MN_IOMUXC_I2C2_SDA_I2C2_SDA			0x400000d6
+		>;
+	};
+
+	pinctrl_i2c2_gpio: i2c2-gpio-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C2_SCL_GPIO5_IO16		0x56
+			MX8MN_IOMUXC_I2C2_SDA_GPIO5_IO17		0xd6
+		>;
+	};
+
+	pinctrl_i2c3: i2c3-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD1_RESET_B_I2C3_SCL		0x40000056
+			MX8MN_IOMUXC_SD1_STROBE_I2C3_SDA		0x400000d6
+		>;
+	};
+
+	pinctrl_i2c3_gpio: i2c3-gpio-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD1_RESET_B_GPIO2_IO10		0x56
+			MX8MN_IOMUXC_SD1_STROBE_GPIO2_IO11		0xd6
+		>;
+	};
+
+	pinctrl_mcp2518: mcp2518-grp {
+		fsl,pins = <
+			/* MCP2518 nINT line */
+			MX8MN_IOMUXC_SAI3_MCLK_GPIO5_IO2		0x116
+			/* MCP2518 nINT1/GPIO1 line */
+			MX8MN_IOMUXC_SAI3_TXD_GPIO5_IO1			0x116
+		>;
+	};
+
+	pinctrl_mcp25625: mcp25625-grp {
+		fsl,pins = <
+			/* MCP25625 nINT line */
+			MX8MN_IOMUXC_SAI2_RXFS_GPIO4_IO21		0x156
+		>;
+	};
+
+	pinctrl_pmic: pmic-irq-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD1_CLK_GPIO2_IO0			0x16
+		>;
+	};
+
+	pinctrl_uart3: uart3-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_UART3_RXD_UART3_DCE_RX		0x142
+			MX8MN_IOMUXC_UART3_TXD_UART3_DCE_TX		0x142
+		>;
+	};
+
+	pinctrl_usb_nreset: usbnreset-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SAI3_RXC_GPIO4_IO29                0x14a
+		>;
+	};
+
+	pinctrl_wdog: wdog-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B		0x64
+		>;
+	};
+};
+
+&gpio5 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_gpio_5>;
+	gpio-line-names =
+		"", "", "", "", "", "", "", "",
+		"", "", "", "", "", "", "", "",
+		"", "", "", "",
+		"ifm_device_info_eeprom_wp",
+		"", "", "",
+		"", "", "", "", "", "", "", "";
+};
+
+&usbotg1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usb_nreset>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	usb-hub at 1 {
+		compatible = "usb424,2512", "usb424,2514";
+		reg = <1>;
+		reset-gpios = <&gpio4 29 GPIO_ACTIVE_LOW>;
+	};
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtso b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtso
new file mode 100644
index 0000000000000..6ad7434a1787e
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-adin1300.dtso
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2024 Fedor Ross <fedor.ross at ifm.com>
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include "imx8mn-pinfunc.h"
+
+&fec1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_fec1>;
+	phy-handle = <&ethphy0>;
+	phy-mode = "rgmii-id";
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy0: ethernet-phy at 0 {
+			reg = <0>;
+
+			adi,rx-internal-delay-ps = <1800>;
+			adi,tx-internal-delay-ps = <2200>;
+			interrupts-extended = <&gpio4 31 IRQ_TYPE_LEVEL_LOW>;
+			reset-gpios = <&gpio4 28 GPIO_ACTIVE_LOW>;
+			reset-assert-us = <10000>;
+			reset-deassert-us = <10000>;
+		};
+	};
+};
+
+&iomuxc {
+	pinctrl_fec1: fec1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_ENET_MDC_ENET1_MDC			0x16
+			MX8MN_IOMUXC_ENET_MDIO_ENET1_MDIO		0x96
+			MX8MN_IOMUXC_ENET_TD3_ENET1_RGMII_TD3		0x16
+			MX8MN_IOMUXC_ENET_TD2_ENET1_RGMII_TD2		0x16
+			MX8MN_IOMUXC_ENET_TD1_ENET1_RGMII_TD1		0x16
+			MX8MN_IOMUXC_ENET_TD0_ENET1_RGMII_TD0		0x16
+			MX8MN_IOMUXC_ENET_RD3_ENET1_RGMII_RD3		0x96
+			MX8MN_IOMUXC_ENET_RD2_ENET1_RGMII_RD2		0x96
+			MX8MN_IOMUXC_ENET_RD1_ENET1_RGMII_RD1		0x96
+			MX8MN_IOMUXC_ENET_RD0_ENET1_RGMII_RD0		0x96
+			MX8MN_IOMUXC_ENET_TXC_ENET1_RGMII_TXC		0x16
+			MX8MN_IOMUXC_ENET_RXC_ENET1_RGMII_RXC		0x96
+			MX8MN_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x96
+			MX8MN_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x16
+			/* nRST */
+			MX8MN_IOMUXC_SAI3_RXFS_GPIO4_IO28		0x156
+			/* nIRQ */
+			MX8MN_IOMUXC_SAI3_TXFS_GPIO4_IO31		0x1d6
+		>;
+	};
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtso b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtso
new file mode 100644
index 0000000000000..ab1304ebd965e
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2-overlay-ksz8794.dtso
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2021 Marek Vasut
+ */
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+#include "imx8mn-pinfunc.h"
+
+&pinctrl_ecspi1 {
+	fsl,pins = <
+		MX8MN_IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK		0x10
+		MX8MN_IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI		0x10
+		MX8MN_IOMUXC_ECSPI1_MISO_ECSPI1_MISO		0x90
+		/* KS8794 nCS */
+		MX8MN_IOMUXC_GPIO1_IO11_GPIO1_IO11		0x150
+		/* ANV32C81 nCS */
+		MX8MN_IOMUXC_ECSPI1_SS0_GPIO5_IO9		0x150
+	>;
+};
+
+#include "imx8mn-vhip4-evalboard-ksz8794-common.dtsi"
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2.dts b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2.dts
new file mode 100644
index 0000000000000..4dadfb7f78de2
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mn-vhip4-evalboard-v2.dts
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2024 Fedor Ross <fedor.ross at ifm.com>
+ */
+
+/dts-v1/;
+
+#include "imx8mn-vhip4-evalboard-common.dtsi"
+
+/ {
+	model = "ifm i.MX8MNano VHIP4 Evaluation Board v2";
+	compatible = "ifm,imx8mn-vhip4-evalboard-v2", "ifm,imx8mn-vhip4-evalboard",
+		     "ifm,imx8mn-vhip4", "fsl,imx8mn";
+
+	multi-led {
+		compatible = "leds-group-multicolor";
+		color = <LED_COLOR_ID_RGB>;
+		function = LED_FUNCTION_INDICATOR;
+		leds = <&rgb_0>, <&rgb_1>, <&rgb_2>;
+	};
+};
+
+&ifm_led {
+	pinctrl-1 = <&pinctrl_gpio_led_v2>;
+
+	rgb_0: rgb-led-red {
+		color = <LED_COLOR_ID_RED>;
+		gpios = <&gpio2 17 GPIO_ACTIVE_HIGH>;
+		default-state = "keep";
+	};
+
+	rgb_1: rgb-led-green {
+		color = <LED_COLOR_ID_GREEN>;
+		gpios = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+		default-state = "keep";
+	};
+
+	rgb_2: rgb-led-blue {
+		color = <LED_COLOR_ID_BLUE>;
+		gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>;
+		default-state = "keep";
+	};
+};
+
+&ecspi1 {
+	cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>, <&gpio1 11 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	eeprom at 0 {
+		compatible = "fujitsu,mb85rs64", "atmel,at25";
+		reg = <0>;
+		spi-max-frequency = <20000000>;
+		spi-cpha;
+		spi-cpol;
+		pagesize = <1>;
+		size = <32768>;
+		address-width = <16>;
+	};
+};
+
+&ecspi3 {
+	cs-gpios = <&gpio5 25 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	can0: can at 0 {
+		compatible = "microchip,mcp2518fd";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_mcp2518>;
+		reg = <0>;
+		clocks = <&can_clk40m>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
+		microchip,rx-int-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
+		spi-max-frequency = <20000000>;
+	};
+};
+
+&i2c1 {
+	scl-gpios = <&gpio2 6 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	sda-gpios = <&gpio2 7 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+
+	temperature-sensor at 48 {
+		compatible = "ti,tmp1075";
+		reg = <0x48>;
+	};
+
+	eeprom at 54 {
+		compatible = "atmel,24c128";
+		reg = <0x54>;
+	};
+};
+
+&i2c3 {
+	scl-gpios = <&gpio5 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	sda-gpios = <&gpio5 19 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+&ifm_pmic {
+	interrupt-parent = <&gpio5>;
+	interrupts = <17 GPIO_ACTIVE_LOW>;
+};
+
+&iomuxc {
+	pinctrl_ecspi1_cs: ecspi1-cs-grp {
+		fsl,pins = <
+			/* KS8794 nCS */
+			MX8MN_IOMUXC_GPIO1_IO11_GPIO1_IO11		0x150
+			/* Retain memory nCS (FRAM or MRAM) */
+			MX8MN_IOMUXC_ECSPI1_SS0_GPIO5_IO9		0x150
+			/* RETAIN_nHOLD */
+			MX8MN_IOMUXC_SPDIF_RX_GPIO5_IO4			0x140
+		>;
+	};
+
+	pinctrl_ecspi3_cs: ecspi3-cs-grp {
+		fsl,pins = <
+			/* MCP2518FD nCS */
+			MX8MN_IOMUXC_UART2_TXD_GPIO5_IO25		0x150
+		>;
+	};
+
+	pinctrl_gpio_led_v2: gpioled-v2-grp {
+		fsl,pins = <
+			/* LED_RGB_RED */
+			MX8MN_IOMUXC_SD2_DATA2_GPIO2_IO17		0x116
+			/* LED_RGB_GREEN */
+			MX8MN_IOMUXC_SD2_RESET_B_GPIO2_IO19		0x116
+			/* LED_RGB_BLUE */
+			MX8MN_IOMUXC_SD2_WP_GPIO2_IO20			0x116
+		>;
+	};
+
+	pinctrl_i2c1: i2c1-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD1_DATA4_I2C1_SCL			0x40000056
+			MX8MN_IOMUXC_SD1_DATA5_I2C1_SDA			0x400000d6
+		>;
+	};
+
+	pinctrl_i2c1_gpio: i2c1-gpio-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD1_DATA4_GPIO2_IO6		0x56
+			MX8MN_IOMUXC_SD1_DATA5_GPIO2_IO7		0xd6
+			/* CFG_EEPROM_WP */
+			MX8MN_IOMUXC_SD1_STROBE_GPIO2_IO11		0x140
+			/* RTC_nIRQ */
+			MX8MN_IOMUXC_SPDIF_EXT_CLK_GPIO5_IO5		0x116
+			/* LOG_EE_WP */
+			MX8MN_IOMUXC_SPDIF_TX_GPIO5_IO3			0x140
+		>;
+	};
+
+	pinctrl_i2c3: i2c3-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C3_SCL_I2C3_SCL			0x40000056
+			MX8MN_IOMUXC_I2C3_SDA_I2C3_SDA			0x400000d6
+		>;
+	};
+
+	pinctrl_i2c3_gpio: i2c3-gpio-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C3_SCL_GPIO5_IO18		0x56
+			MX8MN_IOMUXC_I2C3_SDA_GPIO5_IO19		0xd6
+		>;
+	};
+
+	pinctrl_mcp2518: mcp2518-grp {
+		fsl,pins = <
+			/* CAN0_CLKO */
+			MX8MN_IOMUXC_GPIO1_IO00_GPIO1_IO0		0x116
+			/* CAN0_nINT0 */
+			MX8MN_IOMUXC_GPIO1_IO03_GPIO1_IO3		0x116
+			/* CAN0_nINT1 */
+			MX8MN_IOMUXC_GPIO1_IO04_GPIO1_IO4		0x116
+			/* CAN0_nINT */
+			MX8MN_IOMUXC_GPIO1_IO01_GPIO1_IO1		0x116
+		>;
+	};
+
+	pinctrl_pmic: pmic-irq-grp {
+		fsl,pins = <
+			/* PMIC_nIRQ */
+			MX8MN_IOMUXC_I2C2_SDA_GPIO5_IO17		0x1d6
+		>;
+	};
+
+	pinctrl_uart3: uart3-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD1_DATA6_UART3_DCE_TX		0x142
+			MX8MN_IOMUXC_SD1_DATA7_UART3_DCE_RX		0x142
+		>;
+	};
+
+	pinctrl_wdog: wdog-grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B		0x64
+		>;
+	};
+};
+
+&gpio2 {
+	gpio-line-names =
+		"", "", "", "", "", "", "", "",
+		"", "", "",
+		"ifm_device_info_eeprom_wp",
+		"", "", "", "",
+		"", "", "", "", "", "", "", "",
+		"", "", "", "", "", "", "", "";
+};
+
+&gpio5 {
+	gpio-line-names =
+		"", "", "",
+		"ifm_logging_eeprom_wp",
+		"", "", "", "",
+		"", "", "", "", "", "", "", "",
+		"", "", "", "",	"", "", "", "",
+		"", "", "", "", "", "", "", "";
+};
-- 
2.51.0



From k-willis at ti.com  Tue Dec 30 13:37:18 2025
From: k-willis at ti.com (Kendall Willis)
Date: Tue, 30 Dec 2025 15:37:18 -0600
Subject: [PATCH] pmdomain: ti_sci: handle wakeup constraint for out-of-band
 wakeup
Message-ID: <20251230-pmdomain-v1-1-3a009d1ff72e@ti.com>

For devices capable of out-of-band system wakeups via I/O daisy chaining,
prevent sending wakeup constraints to the PM co-processor. This allows
the system to enter deeper low power modes, as the device is not marked
as requiring power.

Replaces the logic from commit b06bc4727991 ("pmdomain: ti_sci: handle
wake IRQs for IO daisy chain wakeups") since checking out-of-band wakeup
will cover the same functionality.

Detect out-of-band wakeup in the suspend path, and if it exists, skip
sending the constraint.

Signed-off-by: Kendall Willis <k-willis at ti.com>
---
Implementation
--------------
This patch is intended to be implemented along with the following
series. This patch has no dependencies on any of the other series:

1. "pmdomain: ti_sci: handle wakeup constraint for out-of-band wakeup"
   (this patch): Skips setting constraints for wakeup sources that have
   out-of-band wakeup capability.
   https://github.com/kwillis01/linux/commits/v6.19/uart-daisy-chain/pmdomain

2. "serial: 8250: omap: set out-of-band wakeup if wakeup pinctrl exists":
   Implements out-of-band wakeup from the UARTs for TI K3 SoCs
   https://github.com/kwillis01/linux/tree/v6.19/uart-daisy-chain/uart-wakeup

3. "arm64: dts: ti: k3-am62: Support Main UART wakeup": Implements the
   functionality to wakeup the system from the Main UART
   https://github.com/kwillis01/linux/tree/b4/uart-daisy-chain-dts

Testing
-------
Tested on a AM62P SK EVM board with all series and dependencies
implemented. Suspend/resume verified with the Main UART wakeup source
by entering a keypress on the console.

This github branch has all the necessary patches to test the series
using v6.19-rc1:
https://github.com/kwillis01/linux/tree/v6.19/uart-daisy-chain/all
---
 drivers/pmdomain/ti/ti_sci_pm_domains.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/pmdomain/ti/ti_sci_pm_domains.c b/drivers/pmdomain/ti/ti_sci_pm_domains.c
index e5d1934f78d9ee0a02eb05aa1301cd5a59e134d6..18d33bc35dee1b3bf6107af1e414db377d515199 100644
--- a/drivers/pmdomain/ti/ti_sci_pm_domains.c
+++ b/drivers/pmdomain/ti/ti_sci_pm_domains.c
@@ -91,8 +91,9 @@ static inline void ti_sci_pd_set_wkup_constraint(struct device *dev)
 		 * If device can wakeup using IO daisy chain wakeups,
 		 * we do not want to set a constraint.
 		 */
-		if (dev->power.wakeirq) {
-			dev_dbg(dev, "%s: has wake IRQ, not setting constraints\n", __func__);
+		if (device_out_band_wakeup(dev)) {
+			dev_dbg(dev, "%s: has out of band wakeup, not setting constraints\n", \
+					__func__);
 			return;
 		}
 

---
base-commit: f8f9c1f4d0c7a64600e2ca312dec824a0bc2f1da
change-id: 20251230-pmdomain-e71bed9b40f8

Best regards,
-- 
Kendall Willis <k-willis at ti.com>



From frederic at kernel.org  Tue Dec 30 14:38:09 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Tue, 30 Dec 2025 23:38:09 +0100
Subject: [PATCH 01/33] PCI: Prepare to protect against concurrent
 isolated cpuset change
In-Reply-To: <e01189e1-d8ef-2791-632c-90d4d897859b@huawei.com>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-2-frederic@kernel.org>
 <e01189e1-d8ef-2791-632c-90d4d897859b@huawei.com>
Message-ID: <aVRUUXa6kJKHHQ_n@pavilion.home>

Le Mon, Dec 29, 2025 at 11:23:56AM +0800, Zhang Qiao a ?crit :
> Hi, Weisbecker?
> 
> ? 2025/12/24 21:44, Frederic Weisbecker ??:
> > HK_TYPE_DOMAIN will soon integrate cpuset isolated partitions and
> > therefore be made modifiable at runtime. Synchronize against the cpumask
> > update using RCU.
> > 
> > The RCU locked section includes both the housekeeping CPU target
> > election for the PCI probe work and the work enqueue.
> > 
> > This way the housekeeping update side will simply need to flush the
> > pending related works after updating the housekeeping mask in order to
> > make sure that no PCI work ever executes on an isolated CPU. This part
> > will be handled in a subsequent patch.
> > 
> > Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
> > ---
> >  drivers/pci/pci-driver.c | 47 ++++++++++++++++++++++++++++++++--------
> >  1 file changed, 38 insertions(+), 9 deletions(-)
> > 
> > diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
> > index 7c2d9d596258..786d6ce40999 100644
> > --- a/drivers/pci/pci-driver.c
> > +++ b/drivers/pci/pci-driver.c
> > @@ -302,9 +302,8 @@ struct drv_dev_and_id {
> >  	const struct pci_device_id *id;
> >  };
> >  
> > -static long local_pci_probe(void *_ddi)
> > +static int local_pci_probe(struct drv_dev_and_id *ddi)
> >  {
> > -	struct drv_dev_and_id *ddi = _ddi;
> >  	struct pci_dev *pci_dev = ddi->dev;
> >  	struct pci_driver *pci_drv = ddi->drv;
> >  	struct device *dev = &pci_dev->dev;
> > @@ -338,6 +337,19 @@ static long local_pci_probe(void *_ddi)
> >  	return 0;
> >  }
> >  
> > +struct pci_probe_arg {
> > +	struct drv_dev_and_id *ddi;
> > +	struct work_struct work;
> > +	int ret;
> > +};
> > +
> > +static void local_pci_probe_callback(struct work_struct *work)
> > +{
> > +	struct pci_probe_arg *arg = container_of(work, struct pci_probe_arg, work);
> > +
> > +	arg->ret = local_pci_probe(arg->ddi);
> > +}
> > +
> >  static bool pci_physfn_is_probed(struct pci_dev *dev)
> >  {
> >  #ifdef CONFIG_PCI_IOV
> > @@ -362,34 +374,51 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
> >  	dev->is_probed = 1;
> >  
> >  	cpu_hotplug_disable();
> > -
> >  	/*
> >  	 * Prevent nesting work_on_cpu() for the case where a Virtual Function
> >  	 * device is probed from work_on_cpu() of the Physical device.
> >  	 */
> >  	if (node < 0 || node >= MAX_NUMNODES || !node_online(node) ||
> >  	    pci_physfn_is_probed(dev)) {
> > -		cpu = nr_cpu_ids;
> > +		error = local_pci_probe(&ddi);
> >  	} else {
> >  		cpumask_var_t wq_domain_mask;
> > +		struct pci_probe_arg arg = { .ddi = &ddi };
> > +
> > +		INIT_WORK_ONSTACK(&arg.work, local_pci_probe_callback);
> >  
> >  		if (!zalloc_cpumask_var(&wq_domain_mask, GFP_KERNEL)) {
> >  			error = -ENOMEM;
> 
> If we return from here, arg.work will not be destroyed.

Good catch! Thanks.

-- 
Frederic Weisbecker
SUSE Labs


From seanjc at google.com  Tue Dec 30 15:01:29 2025
From: seanjc at google.com (Sean Christopherson)
Date: Tue, 30 Dec 2025 15:01:29 -0800
Subject: [PATCH v4 00/21] KVM: selftests: Add Nested NPT support
Message-ID: <20251230230150.4150236-1-seanjc@google.com>

Yosry's series to add support for nested NPT, and extends vmx_dirty_log_test
and kvm_dirty_log_test (with -n, using memstress) to cover nested SVM.

Note, I'm mildly concerned the last patch to extend nested_dirty_log_test to
validate KVM's handling of READ faults could be flaky, e.g. maybe if someone
is running the test under heavy memory pressure and the to-be-access page is
swapped between the write-from-host and read-from-guest?  But unless someone
knows/shows it'll be flaky, I'm inclined to apply it and hope for the best.

v4:
 - Document the likely reason for setting A/D bits.
 - Put "mmu" structure in common "struct kvm".
 - Make it clear PTE accessors are predicates.
 - Assert that the stage-2 MMU is initialized at most once.
 - Make READABLE a standalone bit (don't overload USER).
 - Don't alias PRESENT => READABLE for EPT.
 - Fix the A/D bit definitions for EPT.
 - Drop the function comment for __tdp_map().
 - Add a patch to extend the nested_dirty_log_test to verify that KVM creates
   writable SPTEs when the gPTEs are writable and dirty.

v3:
 - https://lore.kernel.org/all/20251127013440.3324671-1-yosry.ahmed at linux.dev
 - Dropped the patches that landed in kvm-x86.
 - Reshuffled some patches and cleanups.
 - Introduced kvm_mmu data structures to hold the root, page table
   levels, and page table masks (Sean).
 - Extended memstress as well to cover nested SVM.

v2: https://lore.kernel.org/kvm/20251021074736.1324328-1-yosry.ahmed at linux.dev

Sean Christopherson (7):
  KVM: selftests: Add "struct kvm_mmu" to track a given MMU instance
  KVM: selftests: Plumb "struct kvm_mmu" into x86's MMU APIs
  KVM: selftests: Add a "struct kvm_mmu_arch arch" member to kvm_mmu
  KVM: selftests: Add a stage-2 MMU instance to kvm_vm
  KVM: selftests: Move TDP mapping functions outside of vmx.c
  KVM: selftests: Rename vm_get_page_table_entry() to vm_get_pte()
  KVM: selftests: Test READ=>WRITE dirty logging behavior for shadow MMU

Yosry Ahmed (14):
  KVM: selftests: Make __vm_get_page_table_entry() static
  KVM: selftests: Stop passing a memslot to nested_map_memslot()
  KVM: selftests: Rename nested TDP mapping functions
  KVM: selftests: Kill eptPageTablePointer
  KVM: selftests: Stop setting A/D bits when creating EPT PTEs
  KVM: selftests: Move PTE bitmasks to kvm_mmu
  KVM: selftests: Use a TDP MMU to share EPT page tables between vCPUs
  KVM: selftests: Stop passing VMX metadata to TDP mapping functions
  KVM: selftests: Reuse virt mapping functions for nested EPTs
  KVM: selftests: Allow kvm_cpu_has_ept() to be called on AMD CPUs
  KVM: selftests: Add support for nested NPTs
  KVM: selftests: Set the user bit on nested NPT PTEs
  KVM: selftests: Extend vmx_dirty_log_test to cover SVM
  KVM: selftests: Extend memstress to run on nested SVM

 tools/testing/selftests/kvm/Makefile.kvm      |   2 +-
 .../kvm/include/arm64/kvm_util_arch.h         |   2 +
 .../testing/selftests/kvm/include/kvm_util.h  |  18 +-
 .../kvm/include/loongarch/kvm_util_arch.h     |   1 +
 .../kvm/include/riscv/kvm_util_arch.h         |   1 +
 .../kvm/include/s390/kvm_util_arch.h          |   1 +
 .../selftests/kvm/include/x86/kvm_util_arch.h |  22 ++
 .../selftests/kvm/include/x86/processor.h     |  58 +++-
 .../selftests/kvm/include/x86/svm_util.h      |   9 +
 tools/testing/selftests/kvm/include/x86/vmx.h |  16 +-
 .../selftests/kvm/lib/arm64/processor.c       |  38 +--
 tools/testing/selftests/kvm/lib/kvm_util.c    |  28 +-
 .../selftests/kvm/lib/loongarch/processor.c   |  28 +-
 .../selftests/kvm/lib/riscv/processor.c       |  31 ++-
 .../selftests/kvm/lib/s390/processor.c        |  16 +-
 .../testing/selftests/kvm/lib/x86/memstress.c |  66 +++--
 .../testing/selftests/kvm/lib/x86/processor.c | 237 ++++++++++++----
 tools/testing/selftests/kvm/lib/x86/svm.c     |  24 ++
 tools/testing/selftests/kvm/lib/x86/vmx.c     | 251 ++++-------------
 .../selftests/kvm/x86/hyperv_tlb_flush.c      |   2 +-
 .../selftests/kvm/x86/nested_dirty_log_test.c | 259 ++++++++++++++++++
 .../x86/smaller_maxphyaddr_emulation_test.c   |   4 +-
 .../selftests/kvm/x86/vmx_dirty_log_test.c    | 179 ------------
 .../kvm/x86/vmx_nested_la57_state_test.c      |   2 +-
 24 files changed, 726 insertions(+), 569 deletions(-)
 create mode 100644 tools/testing/selftests/kvm/x86/nested_dirty_log_test.c
 delete mode 100644 tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c


base-commit: 9448598b22c50c8a5bb77a9103e2d49f134c9578
-- 
2.52.0.351.gbe84eed79e-goog



From seanjc at google.com  Tue Dec 30 15:01:35 2025
From: seanjc at google.com (Sean Christopherson)
Date: Tue, 30 Dec 2025 15:01:35 -0800
Subject: [PATCH v4 06/21] KVM: selftests: Add "struct kvm_mmu" to track a
 given MMU instance
In-Reply-To: <20251230230150.4150236-1-seanjc@google.com>
References: <20251230230150.4150236-1-seanjc@google.com>
Message-ID: <20251230230150.4150236-7-seanjc@google.com>

Add a "struct kvm_mmu" to track a given MMU instance, e.g. a VM's stage-1
MMU versus a VM's stage-2 MMU, so that x86 can share MMU functionality for
both stage-1 and stage-2 MMUs, without creating the potential for subtle
bugs, e.g. due to consuming on vm->pgtable_levels when operating a stage-2
MMU.

Encapsulate the existing de facto MMU in "struct kvm_vm", e.g instead of
burying the MMU details in "struct kvm_vm_arch", to avoid more #ifdefs in
____vm_create(), and in the hopes that other architectures can utilize the
formalized MMU structure if/when they too support stage-2 page tables.

No functional change intended.

Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 .../testing/selftests/kvm/include/kvm_util.h  | 11 ++++--
 .../selftests/kvm/lib/arm64/processor.c       | 38 +++++++++----------
 tools/testing/selftests/kvm/lib/kvm_util.c    | 28 +++++++-------
 .../selftests/kvm/lib/loongarch/processor.c   | 28 +++++++-------
 .../selftests/kvm/lib/riscv/processor.c       | 31 +++++++--------
 .../selftests/kvm/lib/s390/processor.c        | 16 ++++----
 .../testing/selftests/kvm/lib/x86/processor.c | 28 +++++++-------
 .../kvm/x86/vmx_nested_la57_state_test.c      |  2 +-
 8 files changed, 94 insertions(+), 88 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index 81f4355ff28a..39558c05c0bf 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -88,12 +88,17 @@ enum kvm_mem_region_type {
 	NR_MEM_REGIONS,
 };
 
+struct kvm_mmu {
+	bool pgd_created;
+	uint64_t pgd;
+	int pgtable_levels;
+};
+
 struct kvm_vm {
 	int mode;
 	unsigned long type;
 	int kvm_fd;
 	int fd;
-	unsigned int pgtable_levels;
 	unsigned int page_size;
 	unsigned int page_shift;
 	unsigned int pa_bits;
@@ -104,13 +109,13 @@ struct kvm_vm {
 	struct sparsebit *vpages_valid;
 	struct sparsebit *vpages_mapped;
 	bool has_irqchip;
-	bool pgd_created;
 	vm_paddr_t ucall_mmio_addr;
-	vm_paddr_t pgd;
 	vm_vaddr_t handlers;
 	uint32_t dirty_ring_size;
 	uint64_t gpa_tag_mask;
 
+	struct kvm_mmu mmu;
+
 	struct kvm_vm_arch arch;
 
 	struct kvm_binary_stats stats;
diff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/testing/selftests/kvm/lib/arm64/processor.c
index d46e4b13b92c..c40f59d48311 100644
--- a/tools/testing/selftests/kvm/lib/arm64/processor.c
+++ b/tools/testing/selftests/kvm/lib/arm64/processor.c
@@ -28,7 +28,7 @@ static uint64_t page_align(struct kvm_vm *vm, uint64_t v)
 
 static uint64_t pgd_index(struct kvm_vm *vm, vm_vaddr_t gva)
 {
-	unsigned int shift = (vm->pgtable_levels - 1) * (vm->page_shift - 3) + vm->page_shift;
+	unsigned int shift = (vm->mmu.pgtable_levels - 1) * (vm->page_shift - 3) + vm->page_shift;
 	uint64_t mask = (1UL << (vm->va_bits - shift)) - 1;
 
 	return (gva >> shift) & mask;
@@ -39,7 +39,7 @@ static uint64_t pud_index(struct kvm_vm *vm, vm_vaddr_t gva)
 	unsigned int shift = 2 * (vm->page_shift - 3) + vm->page_shift;
 	uint64_t mask = (1UL << (vm->page_shift - 3)) - 1;
 
-	TEST_ASSERT(vm->pgtable_levels == 4,
+	TEST_ASSERT(vm->mmu.pgtable_levels == 4,
 		"Mode %d does not have 4 page table levels", vm->mode);
 
 	return (gva >> shift) & mask;
@@ -50,7 +50,7 @@ static uint64_t pmd_index(struct kvm_vm *vm, vm_vaddr_t gva)
 	unsigned int shift = (vm->page_shift - 3) + vm->page_shift;
 	uint64_t mask = (1UL << (vm->page_shift - 3)) - 1;
 
-	TEST_ASSERT(vm->pgtable_levels >= 3,
+	TEST_ASSERT(vm->mmu.pgtable_levels >= 3,
 		"Mode %d does not have >= 3 page table levels", vm->mode);
 
 	return (gva >> shift) & mask;
@@ -104,7 +104,7 @@ static uint64_t pte_addr(struct kvm_vm *vm, uint64_t pte)
 
 static uint64_t ptrs_per_pgd(struct kvm_vm *vm)
 {
-	unsigned int shift = (vm->pgtable_levels - 1) * (vm->page_shift - 3) + vm->page_shift;
+	unsigned int shift = (vm->mmu.pgtable_levels - 1) * (vm->page_shift - 3) + vm->page_shift;
 	return 1 << (vm->va_bits - shift);
 }
 
@@ -117,13 +117,13 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm)
 {
 	size_t nr_pages = page_align(vm, ptrs_per_pgd(vm) * 8) / vm->page_size;
 
-	if (vm->pgd_created)
+	if (vm->mmu.pgd_created)
 		return;
 
-	vm->pgd = vm_phy_pages_alloc(vm, nr_pages,
-				     KVM_GUEST_PAGE_TABLE_MIN_PADDR,
-				     vm->memslots[MEM_REGION_PT]);
-	vm->pgd_created = true;
+	vm->mmu.pgd = vm_phy_pages_alloc(vm, nr_pages,
+					 KVM_GUEST_PAGE_TABLE_MIN_PADDR,
+					 vm->memslots[MEM_REGION_PT]);
+	vm->mmu.pgd_created = true;
 }
 
 static void _virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
@@ -147,12 +147,12 @@ static void _virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
 		"  paddr: 0x%lx vm->max_gfn: 0x%lx vm->page_size: 0x%x",
 		paddr, vm->max_gfn, vm->page_size);
 
-	ptep = addr_gpa2hva(vm, vm->pgd) + pgd_index(vm, vaddr) * 8;
+	ptep = addr_gpa2hva(vm, vm->mmu.pgd) + pgd_index(vm, vaddr) * 8;
 	if (!*ptep)
 		*ptep = addr_pte(vm, vm_alloc_page_table(vm),
 				 PGD_TYPE_TABLE | PTE_VALID);
 
-	switch (vm->pgtable_levels) {
+	switch (vm->mmu.pgtable_levels) {
 	case 4:
 		ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pud_index(vm, vaddr) * 8;
 		if (!*ptep)
@@ -190,16 +190,16 @@ uint64_t *virt_get_pte_hva_at_level(struct kvm_vm *vm, vm_vaddr_t gva, int level
 {
 	uint64_t *ptep;
 
-	if (!vm->pgd_created)
+	if (!vm->mmu.pgd_created)
 		goto unmapped_gva;
 
-	ptep = addr_gpa2hva(vm, vm->pgd) + pgd_index(vm, gva) * 8;
+	ptep = addr_gpa2hva(vm, vm->mmu.pgd) + pgd_index(vm, gva) * 8;
 	if (!ptep)
 		goto unmapped_gva;
 	if (level == 0)
 		return ptep;
 
-	switch (vm->pgtable_levels) {
+	switch (vm->mmu.pgtable_levels) {
 	case 4:
 		ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pud_index(vm, gva) * 8;
 		if (!ptep)
@@ -263,13 +263,13 @@ static void pte_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent, uint64_t p
 
 void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
 {
-	int level = 4 - (vm->pgtable_levels - 1);
+	int level = 4 - (vm->mmu.pgtable_levels - 1);
 	uint64_t pgd, *ptep;
 
-	if (!vm->pgd_created)
+	if (!vm->mmu.pgd_created)
 		return;
 
-	for (pgd = vm->pgd; pgd < vm->pgd + ptrs_per_pgd(vm) * 8; pgd += 8) {
+	for (pgd = vm->mmu.pgd; pgd < vm->mmu.pgd + ptrs_per_pgd(vm) * 8; pgd += 8) {
 		ptep = addr_gpa2hva(vm, pgd);
 		if (!*ptep)
 			continue;
@@ -350,7 +350,7 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
 		TEST_FAIL("Unknown guest mode, mode: 0x%x", vm->mode);
 	}
 
-	ttbr0_el1 = vm->pgd & GENMASK(47, vm->page_shift);
+	ttbr0_el1 = vm->mmu.pgd & GENMASK(47, vm->page_shift);
 
 	/* Configure output size */
 	switch (vm->mode) {
@@ -358,7 +358,7 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
 	case VM_MODE_P52V48_16K:
 	case VM_MODE_P52V48_64K:
 		tcr_el1 |= TCR_IPS_52_BITS;
-		ttbr0_el1 |= FIELD_GET(GENMASK(51, 48), vm->pgd) << 2;
+		ttbr0_el1 |= FIELD_GET(GENMASK(51, 48), vm->mmu.pgd) << 2;
 		break;
 	case VM_MODE_P48V48_4K:
 	case VM_MODE_P48V48_16K:
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 8279b6ced8d2..65752daeed90 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -281,34 +281,34 @@ struct kvm_vm *____vm_create(struct vm_shape shape)
 	/* Setup mode specific traits. */
 	switch (vm->mode) {
 	case VM_MODE_P52V48_4K:
-		vm->pgtable_levels = 4;
+		vm->mmu.pgtable_levels = 4;
 		break;
 	case VM_MODE_P52V48_64K:
-		vm->pgtable_levels = 3;
+		vm->mmu.pgtable_levels = 3;
 		break;
 	case VM_MODE_P48V48_4K:
-		vm->pgtable_levels = 4;
+		vm->mmu.pgtable_levels = 4;
 		break;
 	case VM_MODE_P48V48_64K:
-		vm->pgtable_levels = 3;
+		vm->mmu.pgtable_levels = 3;
 		break;
 	case VM_MODE_P40V48_4K:
 	case VM_MODE_P36V48_4K:
-		vm->pgtable_levels = 4;
+		vm->mmu.pgtable_levels = 4;
 		break;
 	case VM_MODE_P40V48_64K:
 	case VM_MODE_P36V48_64K:
-		vm->pgtable_levels = 3;
+		vm->mmu.pgtable_levels = 3;
 		break;
 	case VM_MODE_P52V48_16K:
 	case VM_MODE_P48V48_16K:
 	case VM_MODE_P40V48_16K:
 	case VM_MODE_P36V48_16K:
-		vm->pgtable_levels = 4;
+		vm->mmu.pgtable_levels = 4;
 		break;
 	case VM_MODE_P47V47_16K:
 	case VM_MODE_P36V47_16K:
-		vm->pgtable_levels = 3;
+		vm->mmu.pgtable_levels = 3;
 		break;
 	case VM_MODE_PXXVYY_4K:
 #ifdef __x86_64__
@@ -321,22 +321,22 @@ struct kvm_vm *____vm_create(struct vm_shape shape)
 			 vm->va_bits);
 
 		if (vm->va_bits == 57) {
-			vm->pgtable_levels = 5;
+			vm->mmu.pgtable_levels = 5;
 		} else {
 			TEST_ASSERT(vm->va_bits == 48,
 				    "Unexpected guest virtual address width: %d",
 				    vm->va_bits);
-			vm->pgtable_levels = 4;
+			vm->mmu.pgtable_levels = 4;
 		}
 #else
 		TEST_FAIL("VM_MODE_PXXVYY_4K not supported on non-x86 platforms");
 #endif
 		break;
 	case VM_MODE_P47V64_4K:
-		vm->pgtable_levels = 5;
+		vm->mmu.pgtable_levels = 5;
 		break;
 	case VM_MODE_P44V64_4K:
-		vm->pgtable_levels = 5;
+		vm->mmu.pgtable_levels = 5;
 		break;
 	default:
 		TEST_FAIL("Unknown guest mode: 0x%x", vm->mode);
@@ -1956,8 +1956,8 @@ void vm_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
 	fprintf(stream, "%*sMapped Virtual Pages:\n", indent, "");
 	sparsebit_dump(stream, vm->vpages_mapped, indent + 2);
 	fprintf(stream, "%*spgd_created: %u\n", indent, "",
-		vm->pgd_created);
-	if (vm->pgd_created) {
+		vm->mmu.pgd_created);
+	if (vm->mmu.pgd_created) {
 		fprintf(stream, "%*sVirtual Translation Tables:\n",
 			indent + 2, "");
 		virt_dump(stream, vm, indent + 4);
diff --git a/tools/testing/selftests/kvm/lib/loongarch/processor.c b/tools/testing/selftests/kvm/lib/loongarch/processor.c
index 07c103369ddb..17aa55a2047a 100644
--- a/tools/testing/selftests/kvm/lib/loongarch/processor.c
+++ b/tools/testing/selftests/kvm/lib/loongarch/processor.c
@@ -50,11 +50,11 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm)
 	int i;
 	vm_paddr_t child, table;
 
-	if (vm->pgd_created)
+	if (vm->mmu.pgd_created)
 		return;
 
 	child = table = 0;
-	for (i = 0; i < vm->pgtable_levels; i++) {
+	for (i = 0; i < vm->mmu.pgtable_levels; i++) {
 		invalid_pgtable[i] = child;
 		table = vm_phy_page_alloc(vm, LOONGARCH_PAGE_TABLE_PHYS_MIN,
 				vm->memslots[MEM_REGION_PT]);
@@ -62,8 +62,8 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm)
 		virt_set_pgtable(vm, table, child);
 		child = table;
 	}
-	vm->pgd = table;
-	vm->pgd_created = true;
+	vm->mmu.pgd = table;
+	vm->mmu.pgd_created = true;
 }
 
 static int virt_pte_none(uint64_t *ptep, int level)
@@ -77,11 +77,11 @@ static uint64_t *virt_populate_pte(struct kvm_vm *vm, vm_vaddr_t gva, int alloc)
 	uint64_t *ptep;
 	vm_paddr_t child;
 
-	if (!vm->pgd_created)
+	if (!vm->mmu.pgd_created)
 		goto unmapped_gva;
 
-	child = vm->pgd;
-	level = vm->pgtable_levels - 1;
+	child = vm->mmu.pgd;
+	level = vm->mmu.pgtable_levels - 1;
 	while (level > 0) {
 		ptep = addr_gpa2hva(vm, child) + virt_pte_index(vm, gva, level) * 8;
 		if (virt_pte_none(ptep, level)) {
@@ -161,11 +161,11 @@ void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
 {
 	int level;
 
-	if (!vm->pgd_created)
+	if (!vm->mmu.pgd_created)
 		return;
 
-	level = vm->pgtable_levels - 1;
-	pte_dump(stream, vm, indent, vm->pgd, level);
+	level = vm->mmu.pgtable_levels - 1;
+	pte_dump(stream, vm, indent, vm->mmu.pgd, level);
 }
 
 void vcpu_arch_dump(FILE *stream, struct kvm_vcpu *vcpu, uint8_t indent)
@@ -297,7 +297,7 @@ static void loongarch_vcpu_setup(struct kvm_vcpu *vcpu)
 
 	width = vm->page_shift - 3;
 
-	switch (vm->pgtable_levels) {
+	switch (vm->mmu.pgtable_levels) {
 	case 4:
 		/* pud page shift and width */
 		val = (vm->page_shift + width * 2) << 20 | (width << 25);
@@ -309,15 +309,15 @@ static void loongarch_vcpu_setup(struct kvm_vcpu *vcpu)
 		val |= vm->page_shift | width << 5;
 		break;
 	default:
-		TEST_FAIL("Got %u page table levels, expected 3 or 4", vm->pgtable_levels);
+		TEST_FAIL("Got %u page table levels, expected 3 or 4", vm->mmu.pgtable_levels);
 	}
 
 	loongarch_set_csr(vcpu, LOONGARCH_CSR_PWCTL0, val);
 
 	/* PGD page shift and width */
-	val = (vm->page_shift + width * (vm->pgtable_levels - 1)) | width << 6;
+	val = (vm->page_shift + width * (vm->mmu.pgtable_levels - 1)) | width << 6;
 	loongarch_set_csr(vcpu, LOONGARCH_CSR_PWCTL1, val);
-	loongarch_set_csr(vcpu, LOONGARCH_CSR_PGDL, vm->pgd);
+	loongarch_set_csr(vcpu, LOONGARCH_CSR_PGDL, vm->mmu.pgd);
 
 	/*
 	 * Refill exception runs on real mode
diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c
index 2eac7d4b59e9..e6ec7c224fc3 100644
--- a/tools/testing/selftests/kvm/lib/riscv/processor.c
+++ b/tools/testing/selftests/kvm/lib/riscv/processor.c
@@ -60,7 +60,7 @@ static uint64_t pte_index(struct kvm_vm *vm, vm_vaddr_t gva, int level)
 {
 	TEST_ASSERT(level > -1,
 		"Negative page table level (%d) not possible", level);
-	TEST_ASSERT(level < vm->pgtable_levels,
+	TEST_ASSERT(level < vm->mmu.pgtable_levels,
 		"Invalid page table level (%d)", level);
 
 	return (gva & pte_index_mask[level]) >> pte_index_shift[level];
@@ -70,19 +70,19 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm)
 {
 	size_t nr_pages = page_align(vm, ptrs_per_pte(vm) * 8) / vm->page_size;
 
-	if (vm->pgd_created)
+	if (vm->mmu.pgd_created)
 		return;
 
-	vm->pgd = vm_phy_pages_alloc(vm, nr_pages,
-				     KVM_GUEST_PAGE_TABLE_MIN_PADDR,
-				     vm->memslots[MEM_REGION_PT]);
-	vm->pgd_created = true;
+	vm->mmu.pgd = vm_phy_pages_alloc(vm, nr_pages,
+					 KVM_GUEST_PAGE_TABLE_MIN_PADDR,
+					 vm->memslots[MEM_REGION_PT]);
+	vm->mmu.pgd_created = true;
 }
 
 void virt_arch_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr)
 {
 	uint64_t *ptep, next_ppn;
-	int level = vm->pgtable_levels - 1;
+	int level = vm->mmu.pgtable_levels - 1;
 
 	TEST_ASSERT((vaddr % vm->page_size) == 0,
 		"Virtual address not on page boundary,\n"
@@ -98,7 +98,7 @@ void virt_arch_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr)
 		"  paddr: 0x%lx vm->max_gfn: 0x%lx vm->page_size: 0x%x",
 		paddr, vm->max_gfn, vm->page_size);
 
-	ptep = addr_gpa2hva(vm, vm->pgd) + pte_index(vm, vaddr, level) * 8;
+	ptep = addr_gpa2hva(vm, vm->mmu.pgd) + pte_index(vm, vaddr, level) * 8;
 	if (!*ptep) {
 		next_ppn = vm_alloc_page_table(vm) >> PGTBL_PAGE_SIZE_SHIFT;
 		*ptep = (next_ppn << PGTBL_PTE_ADDR_SHIFT) |
@@ -126,12 +126,12 @@ void virt_arch_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr)
 vm_paddr_t addr_arch_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva)
 {
 	uint64_t *ptep;
-	int level = vm->pgtable_levels - 1;
+	int level = vm->mmu.pgtable_levels - 1;
 
-	if (!vm->pgd_created)
+	if (!vm->mmu.pgd_created)
 		goto unmapped_gva;
 
-	ptep = addr_gpa2hva(vm, vm->pgd) + pte_index(vm, gva, level) * 8;
+	ptep = addr_gpa2hva(vm, vm->mmu.pgd) + pte_index(vm, gva, level) * 8;
 	if (!ptep)
 		goto unmapped_gva;
 	level--;
@@ -176,13 +176,14 @@ static void pte_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent,
 
 void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
 {
-	int level = vm->pgtable_levels - 1;
+	struct kvm_mmu *mmu = &vm->mmu;
+	int level = mmu->pgtable_levels - 1;
 	uint64_t pgd, *ptep;
 
-	if (!vm->pgd_created)
+	if (!mmu->pgd_created)
 		return;
 
-	for (pgd = vm->pgd; pgd < vm->pgd + ptrs_per_pte(vm) * 8; pgd += 8) {
+	for (pgd = mmu->pgd; pgd < mmu->pgd + ptrs_per_pte(vm) * 8; pgd += 8) {
 		ptep = addr_gpa2hva(vm, pgd);
 		if (!*ptep)
 			continue;
@@ -211,7 +212,7 @@ void riscv_vcpu_mmu_setup(struct kvm_vcpu *vcpu)
 		TEST_FAIL("Unknown guest mode, mode: 0x%x", vm->mode);
 	}
 
-	satp = (vm->pgd >> PGTBL_PAGE_SIZE_SHIFT) & SATP_PPN;
+	satp = (vm->mmu.pgd >> PGTBL_PAGE_SIZE_SHIFT) & SATP_PPN;
 	satp |= SATP_MODE_48;
 
 	vcpu_set_reg(vcpu, RISCV_GENERAL_CSR_REG(satp), satp);
diff --git a/tools/testing/selftests/kvm/lib/s390/processor.c b/tools/testing/selftests/kvm/lib/s390/processor.c
index 8ceeb17c819a..6a9a660413a7 100644
--- a/tools/testing/selftests/kvm/lib/s390/processor.c
+++ b/tools/testing/selftests/kvm/lib/s390/processor.c
@@ -17,7 +17,7 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm)
 	TEST_ASSERT(vm->page_size == PAGE_SIZE, "Unsupported page size: 0x%x",
 		    vm->page_size);
 
-	if (vm->pgd_created)
+	if (vm->mmu.pgd_created)
 		return;
 
 	paddr = vm_phy_pages_alloc(vm, PAGES_PER_REGION,
@@ -25,8 +25,8 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm)
 				   vm->memslots[MEM_REGION_PT]);
 	memset(addr_gpa2hva(vm, paddr), 0xff, PAGES_PER_REGION * vm->page_size);
 
-	vm->pgd = paddr;
-	vm->pgd_created = true;
+	vm->mmu.pgd = paddr;
+	vm->mmu.pgd_created = true;
 }
 
 /*
@@ -70,7 +70,7 @@ void virt_arch_pg_map(struct kvm_vm *vm, uint64_t gva, uint64_t gpa)
 		gva, vm->max_gfn, vm->page_size);
 
 	/* Walk through region and segment tables */
-	entry = addr_gpa2hva(vm, vm->pgd);
+	entry = addr_gpa2hva(vm, vm->mmu.pgd);
 	for (ri = 1; ri <= 4; ri++) {
 		idx = (gva >> (64 - 11 * ri)) & 0x7ffu;
 		if (entry[idx] & REGION_ENTRY_INVALID)
@@ -94,7 +94,7 @@ vm_paddr_t addr_arch_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva)
 	TEST_ASSERT(vm->page_size == PAGE_SIZE, "Unsupported page size: 0x%x",
 		    vm->page_size);
 
-	entry = addr_gpa2hva(vm, vm->pgd);
+	entry = addr_gpa2hva(vm, vm->mmu.pgd);
 	for (ri = 1; ri <= 4; ri++) {
 		idx = (gva >> (64 - 11 * ri)) & 0x7ffu;
 		TEST_ASSERT(!(entry[idx] & REGION_ENTRY_INVALID),
@@ -149,10 +149,10 @@ static void virt_dump_region(FILE *stream, struct kvm_vm *vm, uint8_t indent,
 
 void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
 {
-	if (!vm->pgd_created)
+	if (!vm->mmu.pgd_created)
 		return;
 
-	virt_dump_region(stream, vm, indent, vm->pgd);
+	virt_dump_region(stream, vm, indent, vm->mmu.pgd);
 }
 
 void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code)
@@ -184,7 +184,7 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
 
 	vcpu_sregs_get(vcpu, &sregs);
 	sregs.crs[0] |= 0x00040000;		/* Enable floating point regs */
-	sregs.crs[1] = vm->pgd | 0xf;		/* Primary region table */
+	sregs.crs[1] = vm->mmu.pgd | 0xf;	/* Primary region table */
 	vcpu_sregs_set(vcpu, &sregs);
 
 	vcpu->run->psw_mask = 0x0400000180000000ULL;  /* DAT enabled + 64 bit mode */
diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
index c14bf2b5f28f..f027f86d1535 100644
--- a/tools/testing/selftests/kvm/lib/x86/processor.c
+++ b/tools/testing/selftests/kvm/lib/x86/processor.c
@@ -162,9 +162,9 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm)
 		    "Unknown or unsupported guest mode: 0x%x", vm->mode);
 
 	/* If needed, create the top-level page table. */
-	if (!vm->pgd_created) {
-		vm->pgd = vm_alloc_page_table(vm);
-		vm->pgd_created = true;
+	if (!vm->mmu.pgd_created) {
+		vm->mmu.pgd = vm_alloc_page_table(vm);
+		vm->mmu.pgd_created = true;
 	}
 }
 
@@ -175,7 +175,7 @@ static void *virt_get_pte(struct kvm_vm *vm, uint64_t *parent_pte,
 	uint64_t *page_table = addr_gpa2hva(vm, pt_gpa);
 	int index = (vaddr >> PG_LEVEL_SHIFT(level)) & 0x1ffu;
 
-	TEST_ASSERT((*parent_pte & PTE_PRESENT_MASK) || parent_pte == &vm->pgd,
+	TEST_ASSERT((*parent_pte & PTE_PRESENT_MASK) || parent_pte == &vm->mmu.pgd,
 		    "Parent PTE (level %d) not PRESENT for gva: 0x%08lx",
 		    level + 1, vaddr);
 
@@ -218,7 +218,7 @@ static uint64_t *virt_create_upper_pte(struct kvm_vm *vm,
 void __virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, int level)
 {
 	const uint64_t pg_size = PG_LEVEL_SIZE(level);
-	uint64_t *pte = &vm->pgd;
+	uint64_t *pte = &vm->mmu.pgd;
 	int current_level;
 
 	TEST_ASSERT(vm->mode == VM_MODE_PXXVYY_4K,
@@ -243,7 +243,7 @@ void __virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, int level)
 	 * Allocate upper level page tables, if not already present.  Return
 	 * early if a hugepage was created.
 	 */
-	for (current_level = vm->pgtable_levels;
+	for (current_level = vm->mmu.pgtable_levels;
 	     current_level > PG_LEVEL_4K;
 	     current_level--) {
 		pte = virt_create_upper_pte(vm, pte, vaddr, paddr,
@@ -309,14 +309,14 @@ static bool vm_is_target_pte(uint64_t *pte, int *level, int current_level)
 static uint64_t *__vm_get_page_table_entry(struct kvm_vm *vm, uint64_t vaddr,
 					   int *level)
 {
-	int va_width = 12 + (vm->pgtable_levels) * 9;
-	uint64_t *pte = &vm->pgd;
+	int va_width = 12 + (vm->mmu.pgtable_levels) * 9;
+	uint64_t *pte = &vm->mmu.pgd;
 	int current_level;
 
 	TEST_ASSERT(!vm->arch.is_pt_protected,
 		    "Walking page tables of protected guests is impossible");
 
-	TEST_ASSERT(*level >= PG_LEVEL_NONE && *level <= vm->pgtable_levels,
+	TEST_ASSERT(*level >= PG_LEVEL_NONE && *level <= vm->mmu.pgtable_levels,
 		    "Invalid PG_LEVEL_* '%d'", *level);
 
 	TEST_ASSERT(vm->mode == VM_MODE_PXXVYY_4K,
@@ -332,7 +332,7 @@ static uint64_t *__vm_get_page_table_entry(struct kvm_vm *vm, uint64_t vaddr,
 		    (((int64_t)vaddr << (64 - va_width) >> (64 - va_width))),
 		    "Canonical check failed.  The virtual address is invalid.");
 
-	for (current_level = vm->pgtable_levels;
+	for (current_level = vm->mmu.pgtable_levels;
 	     current_level > PG_LEVEL_4K;
 	     current_level--) {
 		pte = virt_get_pte(vm, pte, vaddr, current_level);
@@ -357,7 +357,7 @@ void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
 	uint64_t *pde, *pde_start;
 	uint64_t *pte, *pte_start;
 
-	if (!vm->pgd_created)
+	if (!vm->mmu.pgd_created)
 		return;
 
 	fprintf(stream, "%*s                                          "
@@ -365,7 +365,7 @@ void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
 	fprintf(stream, "%*s      index hvaddr         gpaddr         "
 		"addr         w exec dirty\n",
 		indent, "");
-	pml4e_start = (uint64_t *) addr_gpa2hva(vm, vm->pgd);
+	pml4e_start = (uint64_t *) addr_gpa2hva(vm, vm->mmu.pgd);
 	for (uint16_t n1 = 0; n1 <= 0x1ffu; n1++) {
 		pml4e = &pml4e_start[n1];
 		if (!(*pml4e & PTE_PRESENT_MASK))
@@ -538,7 +538,7 @@ static void vcpu_init_sregs(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
 	sregs.cr4 |= X86_CR4_PAE | X86_CR4_OSFXSR;
 	if (kvm_cpu_has(X86_FEATURE_XSAVE))
 		sregs.cr4 |= X86_CR4_OSXSAVE;
-	if (vm->pgtable_levels == 5)
+	if (vm->mmu.pgtable_levels == 5)
 		sregs.cr4 |= X86_CR4_LA57;
 	sregs.efer |= (EFER_LME | EFER_LMA | EFER_NX);
 
@@ -549,7 +549,7 @@ static void vcpu_init_sregs(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
 	kvm_seg_set_kernel_data_64bit(&sregs.gs);
 	kvm_seg_set_tss_64bit(vm->arch.tss, &sregs.tr);
 
-	sregs.cr3 = vm->pgd;
+	sregs.cr3 = vm->mmu.pgd;
 	vcpu_sregs_set(vcpu, &sregs);
 }
 
diff --git a/tools/testing/selftests/kvm/x86/vmx_nested_la57_state_test.c b/tools/testing/selftests/kvm/x86/vmx_nested_la57_state_test.c
index cf1d2d1f2a8f..915c42001dba 100644
--- a/tools/testing/selftests/kvm/x86/vmx_nested_la57_state_test.c
+++ b/tools/testing/selftests/kvm/x86/vmx_nested_la57_state_test.c
@@ -90,7 +90,7 @@ int main(int argc, char *argv[])
 	 * L1 needs to read its own PML5 table to set up L2. Identity map
 	 * the PML5 table to facilitate this.
 	 */
-	virt_map(vm, vm->pgd, vm->pgd, 1);
+	virt_map(vm, vm->mmu.pgd, vm->mmu.pgd, 1);
 
 	vcpu_alloc_vmx(vm, &vmx_pages_gva);
 	vcpu_args_set(vcpu, 1, vmx_pages_gva);
-- 
2.52.0.351.gbe84eed79e-goog



From seanjc at google.com  Tue Dec 30 15:01:30 2025
From: seanjc at google.com (Sean Christopherson)
Date: Tue, 30 Dec 2025 15:01:30 -0800
Subject: [PATCH v4 01/21] KVM: selftests: Make __vm_get_page_table_entry() static
In-Reply-To: <20251230230150.4150236-1-seanjc@google.com>
References: <20251230230150.4150236-1-seanjc@google.com>
Message-ID: <20251230230150.4150236-2-seanjc@google.com>

From: Yosry Ahmed <yosry.ahmed at linux.dev>

The function is only used in processor.c, drop the declaration in
processor.h and make it static.

No functional change intended.

Signed-off-by: Yosry Ahmed <yosry.ahmed at linux.dev>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 tools/testing/selftests/kvm/include/x86/processor.h | 2 --
 tools/testing/selftests/kvm/lib/x86/processor.c     | 4 ++--
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h
index 57d62a425109..c00c0fbe62cd 100644
--- a/tools/testing/selftests/kvm/include/x86/processor.h
+++ b/tools/testing/selftests/kvm/include/x86/processor.h
@@ -1367,8 +1367,6 @@ static inline bool kvm_is_ignore_msrs(void)
 	return get_kvm_param_bool("ignore_msrs");
 }
 
-uint64_t *__vm_get_page_table_entry(struct kvm_vm *vm, uint64_t vaddr,
-				    int *level);
 uint64_t *vm_get_page_table_entry(struct kvm_vm *vm, uint64_t vaddr);
 
 uint64_t kvm_hypercall(uint64_t nr, uint64_t a0, uint64_t a1, uint64_t a2,
diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
index 36104d27f3d9..c14bf2b5f28f 100644
--- a/tools/testing/selftests/kvm/lib/x86/processor.c
+++ b/tools/testing/selftests/kvm/lib/x86/processor.c
@@ -306,8 +306,8 @@ static bool vm_is_target_pte(uint64_t *pte, int *level, int current_level)
 	return *level == current_level;
 }
 
-uint64_t *__vm_get_page_table_entry(struct kvm_vm *vm, uint64_t vaddr,
-				    int *level)
+static uint64_t *__vm_get_page_table_entry(struct kvm_vm *vm, uint64_t vaddr,
+					   int *level)
 {
 	int va_width = 12 + (vm->pgtable_levels) * 9;
 	uint64_t *pte = &vm->pgd;
-- 
2.52.0.351.gbe84eed79e-goog



From seanjc at google.com  Tue Dec 30 15:01:31 2025
From: seanjc at google.com (Sean Christopherson)
Date: Tue, 30 Dec 2025 15:01:31 -0800
Subject: [PATCH v4 02/21] KVM: selftests: Stop passing a memslot to nested_map_memslot()
In-Reply-To: <20251230230150.4150236-1-seanjc@google.com>
References: <20251230230150.4150236-1-seanjc@google.com>
Message-ID: <20251230230150.4150236-3-seanjc@google.com>

From: Yosry Ahmed <yosry.ahmed at linux.dev>

On x86, KVM selftests use memslot 0 for all the default regions used by
the test infrastructure. This is an implementation detail.
nested_map_memslot() is currently used to map the default regions by
explicitly passing slot 0, which leaks the library implementation into
the caller.

Rename the function to a very verbose
nested_identity_map_default_memslots() to reflect what it actually does.
Add an assertion that only memslot 0 is being used so that the
implementation does not change from under us.

No functional change intended.

Signed-off-by: Yosry Ahmed <yosry.ahmed at linux.dev>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 tools/testing/selftests/kvm/include/x86/vmx.h        |  4 ++--
 tools/testing/selftests/kvm/lib/x86/vmx.c            | 12 ++++++++----
 tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c |  2 +-
 3 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/x86/vmx.h b/tools/testing/selftests/kvm/include/x86/vmx.h
index 96e2b4c630a9..91916b8aa94b 100644
--- a/tools/testing/selftests/kvm/include/x86/vmx.h
+++ b/tools/testing/selftests/kvm/include/x86/vmx.h
@@ -563,8 +563,8 @@ void nested_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm,
 		   uint64_t nested_paddr, uint64_t paddr);
 void nested_map(struct vmx_pages *vmx, struct kvm_vm *vm,
 		 uint64_t nested_paddr, uint64_t paddr, uint64_t size);
-void nested_map_memslot(struct vmx_pages *vmx, struct kvm_vm *vm,
-			uint32_t memslot);
+void nested_identity_map_default_memslots(struct vmx_pages *vmx,
+					  struct kvm_vm *vm);
 void nested_identity_map_1g(struct vmx_pages *vmx, struct kvm_vm *vm,
 			    uint64_t addr, uint64_t size);
 bool kvm_cpu_has_ept(void);
diff --git a/tools/testing/selftests/kvm/lib/x86/vmx.c b/tools/testing/selftests/kvm/lib/x86/vmx.c
index 29b082a58daa..eec33ec63811 100644
--- a/tools/testing/selftests/kvm/lib/x86/vmx.c
+++ b/tools/testing/selftests/kvm/lib/x86/vmx.c
@@ -494,12 +494,16 @@ void nested_map(struct vmx_pages *vmx, struct kvm_vm *vm,
 /* Prepare an identity extended page table that maps all the
  * physical pages in VM.
  */
-void nested_map_memslot(struct vmx_pages *vmx, struct kvm_vm *vm,
-			uint32_t memslot)
+void nested_identity_map_default_memslots(struct vmx_pages *vmx,
+					  struct kvm_vm *vm)
 {
+	uint32_t s, memslot = 0;
 	sparsebit_idx_t i, last;
-	struct userspace_mem_region *region =
-		memslot2region(vm, memslot);
+	struct userspace_mem_region *region = memslot2region(vm, memslot);
+
+	/* Only memslot 0 is mapped here, ensure it's the only one being used */
+	for (s = 0; s < NR_MEM_REGIONS; s++)
+		TEST_ASSERT_EQ(vm->memslots[s], 0);
 
 	i = (region->region.guest_phys_addr >> vm->page_shift) - 1;
 	last = i + (region->region.memory_size >> vm->page_shift);
diff --git a/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c b/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c
index 98cb6bdab3e6..aab7333aaef0 100644
--- a/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c
+++ b/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c
@@ -121,7 +121,7 @@ static void test_vmx_dirty_log(bool enable_ept)
 	 */
 	if (enable_ept) {
 		prepare_eptp(vmx, vm);
-		nested_map_memslot(vmx, vm, 0);
+		nested_identity_map_default_memslots(vmx, vm);
 		nested_map(vmx, vm, NESTED_TEST_MEM1, GUEST_TEST_MEM, PAGE_SIZE);
 		nested_map(vmx, vm, NESTED_TEST_MEM2, GUEST_TEST_MEM, PAGE_SIZE);
 	}
-- 
2.52.0.351.gbe84eed79e-goog



From seanjc at google.com  Tue Dec 30 15:01:36 2025
From: seanjc at google.com (Sean Christopherson)
Date: Tue, 30 Dec 2025 15:01:36 -0800
Subject: [PATCH v4 07/21] KVM: selftests: Plumb "struct kvm_mmu" into x86's
 MMU APIs
In-Reply-To: <20251230230150.4150236-1-seanjc@google.com>
References: <20251230230150.4150236-1-seanjc@google.com>
Message-ID: <20251230230150.4150236-8-seanjc@google.com>

In preparation for generalizing the x86 virt mapping APIs to work with
TDP (stage-2) page tables, plumb "struct kvm_mmu" into all of the helper
functions instead of operating on vm->mmu directly.

Opportunistically swap the order of the check in virt_get_pte() to first
assert that the parent is the PGD, and then check that the PTE is present,
as it makes more sense to check if the parent PTE is the PGD/root (i.e.
not a PTE) before checking that the PTE is PRESENT.

No functional change intended.

Suggested-by: Sean Christopherson <seanjc at google.com>
Signed-off-by: Yosry Ahmed <yosry.ahmed at linux.dev>
[sean: rebase on common kvm_mmu structure, rewrite changelog]
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 .../selftests/kvm/include/x86/processor.h     |  3 +-
 .../testing/selftests/kvm/lib/x86/processor.c | 68 +++++++++++--------
 2 files changed, 41 insertions(+), 30 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h
index c00c0fbe62cd..cbac9de29074 100644
--- a/tools/testing/selftests/kvm/include/x86/processor.h
+++ b/tools/testing/selftests/kvm/include/x86/processor.h
@@ -1449,7 +1449,8 @@ enum pg_level {
 #define PG_SIZE_2M PG_LEVEL_SIZE(PG_LEVEL_2M)
 #define PG_SIZE_1G PG_LEVEL_SIZE(PG_LEVEL_1G)
 
-void __virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, int level);
+void __virt_pg_map(struct kvm_vm *vm, struct kvm_mmu *mmu, uint64_t vaddr,
+		   uint64_t paddr,  int level);
 void virt_map_level(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
 		    uint64_t nr_bytes, int level);
 
diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
index f027f86d1535..f25742a804b0 100644
--- a/tools/testing/selftests/kvm/lib/x86/processor.c
+++ b/tools/testing/selftests/kvm/lib/x86/processor.c
@@ -156,26 +156,31 @@ bool kvm_is_tdp_enabled(void)
 		return get_kvm_amd_param_bool("npt");
 }
 
-void virt_arch_pgd_alloc(struct kvm_vm *vm)
+static void virt_mmu_init(struct kvm_vm *vm, struct kvm_mmu *mmu)
 {
-	TEST_ASSERT(vm->mode == VM_MODE_PXXVYY_4K,
-		    "Unknown or unsupported guest mode: 0x%x", vm->mode);
-
 	/* If needed, create the top-level page table. */
-	if (!vm->mmu.pgd_created) {
-		vm->mmu.pgd = vm_alloc_page_table(vm);
-		vm->mmu.pgd_created = true;
+	if (!mmu->pgd_created) {
+		mmu->pgd = vm_alloc_page_table(vm);
+		mmu->pgd_created = true;
 	}
 }
 
-static void *virt_get_pte(struct kvm_vm *vm, uint64_t *parent_pte,
-			  uint64_t vaddr, int level)
+void virt_arch_pgd_alloc(struct kvm_vm *vm)
+{
+	TEST_ASSERT(vm->mode == VM_MODE_PXXVYY_4K,
+		    "Unknown or unsupported guest mode: 0x%x", vm->mode);
+
+	virt_mmu_init(vm, &vm->mmu);
+}
+
+static void *virt_get_pte(struct kvm_vm *vm, struct kvm_mmu *mmu,
+			  uint64_t *parent_pte, uint64_t vaddr, int level)
 {
 	uint64_t pt_gpa = PTE_GET_PA(*parent_pte);
 	uint64_t *page_table = addr_gpa2hva(vm, pt_gpa);
 	int index = (vaddr >> PG_LEVEL_SHIFT(level)) & 0x1ffu;
 
-	TEST_ASSERT((*parent_pte & PTE_PRESENT_MASK) || parent_pte == &vm->mmu.pgd,
+	TEST_ASSERT((*parent_pte == mmu->pgd) || (*parent_pte & PTE_PRESENT_MASK),
 		    "Parent PTE (level %d) not PRESENT for gva: 0x%08lx",
 		    level + 1, vaddr);
 
@@ -183,13 +188,14 @@ static void *virt_get_pte(struct kvm_vm *vm, uint64_t *parent_pte,
 }
 
 static uint64_t *virt_create_upper_pte(struct kvm_vm *vm,
+				       struct kvm_mmu *mmu,
 				       uint64_t *parent_pte,
 				       uint64_t vaddr,
 				       uint64_t paddr,
 				       int current_level,
 				       int target_level)
 {
-	uint64_t *pte = virt_get_pte(vm, parent_pte, vaddr, current_level);
+	uint64_t *pte = virt_get_pte(vm, mmu, parent_pte, vaddr, current_level);
 
 	paddr = vm_untag_gpa(vm, paddr);
 
@@ -215,10 +221,11 @@ static uint64_t *virt_create_upper_pte(struct kvm_vm *vm,
 	return pte;
 }
 
-void __virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, int level)
+void __virt_pg_map(struct kvm_vm *vm, struct kvm_mmu *mmu, uint64_t vaddr,
+		   uint64_t paddr, int level)
 {
 	const uint64_t pg_size = PG_LEVEL_SIZE(level);
-	uint64_t *pte = &vm->mmu.pgd;
+	uint64_t *pte = &mmu->pgd;
 	int current_level;
 
 	TEST_ASSERT(vm->mode == VM_MODE_PXXVYY_4K,
@@ -243,17 +250,17 @@ void __virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, int level)
 	 * Allocate upper level page tables, if not already present.  Return
 	 * early if a hugepage was created.
 	 */
-	for (current_level = vm->mmu.pgtable_levels;
+	for (current_level = mmu->pgtable_levels;
 	     current_level > PG_LEVEL_4K;
 	     current_level--) {
-		pte = virt_create_upper_pte(vm, pte, vaddr, paddr,
+		pte = virt_create_upper_pte(vm, mmu, pte, vaddr, paddr,
 					    current_level, level);
 		if (*pte & PTE_LARGE_MASK)
 			return;
 	}
 
 	/* Fill in page table entry. */
-	pte = virt_get_pte(vm, pte, vaddr, PG_LEVEL_4K);
+	pte = virt_get_pte(vm, mmu, pte, vaddr, PG_LEVEL_4K);
 	TEST_ASSERT(!(*pte & PTE_PRESENT_MASK),
 		    "PTE already present for 4k page at vaddr: 0x%lx", vaddr);
 	*pte = PTE_PRESENT_MASK | PTE_WRITABLE_MASK | (paddr & PHYSICAL_PAGE_MASK);
@@ -270,7 +277,7 @@ void __virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, int level)
 
 void virt_arch_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr)
 {
-	__virt_pg_map(vm, vaddr, paddr, PG_LEVEL_4K);
+	__virt_pg_map(vm, &vm->mmu, vaddr, paddr, PG_LEVEL_4K);
 }
 
 void virt_map_level(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
@@ -285,7 +292,7 @@ void virt_map_level(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
 		    nr_bytes, pg_size);
 
 	for (i = 0; i < nr_pages; i++) {
-		__virt_pg_map(vm, vaddr, paddr, level);
+		__virt_pg_map(vm, &vm->mmu, vaddr, paddr, level);
 		sparsebit_set_num(vm->vpages_mapped, vaddr >> vm->page_shift,
 				  nr_bytes / PAGE_SIZE);
 
@@ -294,7 +301,8 @@ void virt_map_level(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
 	}
 }
 
-static bool vm_is_target_pte(uint64_t *pte, int *level, int current_level)
+static bool vm_is_target_pte(struct kvm_mmu *mmu, uint64_t *pte,
+			     int *level, int current_level)
 {
 	if (*pte & PTE_LARGE_MASK) {
 		TEST_ASSERT(*level == PG_LEVEL_NONE ||
@@ -306,17 +314,19 @@ static bool vm_is_target_pte(uint64_t *pte, int *level, int current_level)
 	return *level == current_level;
 }
 
-static uint64_t *__vm_get_page_table_entry(struct kvm_vm *vm, uint64_t vaddr,
+static uint64_t *__vm_get_page_table_entry(struct kvm_vm *vm,
+					   struct kvm_mmu *mmu,
+					   uint64_t vaddr,
 					   int *level)
 {
-	int va_width = 12 + (vm->mmu.pgtable_levels) * 9;
-	uint64_t *pte = &vm->mmu.pgd;
+	int va_width = 12 + (mmu->pgtable_levels) * 9;
+	uint64_t *pte = &mmu->pgd;
 	int current_level;
 
 	TEST_ASSERT(!vm->arch.is_pt_protected,
 		    "Walking page tables of protected guests is impossible");
 
-	TEST_ASSERT(*level >= PG_LEVEL_NONE && *level <= vm->mmu.pgtable_levels,
+	TEST_ASSERT(*level >= PG_LEVEL_NONE && *level <= mmu->pgtable_levels,
 		    "Invalid PG_LEVEL_* '%d'", *level);
 
 	TEST_ASSERT(vm->mode == VM_MODE_PXXVYY_4K,
@@ -332,22 +342,22 @@ static uint64_t *__vm_get_page_table_entry(struct kvm_vm *vm, uint64_t vaddr,
 		    (((int64_t)vaddr << (64 - va_width) >> (64 - va_width))),
 		    "Canonical check failed.  The virtual address is invalid.");
 
-	for (current_level = vm->mmu.pgtable_levels;
+	for (current_level = mmu->pgtable_levels;
 	     current_level > PG_LEVEL_4K;
 	     current_level--) {
-		pte = virt_get_pte(vm, pte, vaddr, current_level);
-		if (vm_is_target_pte(pte, level, current_level))
+		pte = virt_get_pte(vm, mmu, pte, vaddr, current_level);
+		if (vm_is_target_pte(mmu, pte, level, current_level))
 			return pte;
 	}
 
-	return virt_get_pte(vm, pte, vaddr, PG_LEVEL_4K);
+	return virt_get_pte(vm, mmu, pte, vaddr, PG_LEVEL_4K);
 }
 
 uint64_t *vm_get_page_table_entry(struct kvm_vm *vm, uint64_t vaddr)
 {
 	int level = PG_LEVEL_4K;
 
-	return __vm_get_page_table_entry(vm, vaddr, &level);
+	return __vm_get_page_table_entry(vm, &vm->mmu, vaddr, &level);
 }
 
 void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
@@ -497,7 +507,7 @@ static void kvm_seg_set_kernel_data_64bit(struct kvm_segment *segp)
 vm_paddr_t addr_arch_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva)
 {
 	int level = PG_LEVEL_NONE;
-	uint64_t *pte = __vm_get_page_table_entry(vm, gva, &level);
+	uint64_t *pte = __vm_get_page_table_entry(vm, &vm->mmu, gva, &level);
 
 	TEST_ASSERT(*pte & PTE_PRESENT_MASK,
 		    "Leaf PTE not PRESENT for gva: 0x%08lx", gva);
-- 
2.52.0.351.gbe84eed79e-goog



From seanjc at google.com  Tue Dec 30 15:01:32 2025
From: seanjc at google.com (Sean Christopherson)
Date: Tue, 30 Dec 2025 15:01:32 -0800
Subject: [PATCH v4 03/21] KVM: selftests: Rename nested TDP mapping functions
In-Reply-To: <20251230230150.4150236-1-seanjc@google.com>
References: <20251230230150.4150236-1-seanjc@google.com>
Message-ID: <20251230230150.4150236-4-seanjc@google.com>

From: Yosry Ahmed <yosry.ahmed at linux.dev>

Rename the functions from nested_* to tdp_* to make their purpose
clearer.

No functional change intended.

Suggested-by: Sean Christopherson <seanjc at google.com>
Signed-off-by: Yosry Ahmed <yosry.ahmed at linux.dev>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 tools/testing/selftests/kvm/include/x86/vmx.h | 16 +++---
 .../testing/selftests/kvm/lib/x86/memstress.c |  4 +-
 tools/testing/selftests/kvm/lib/x86/vmx.c     | 50 +++++++++----------
 .../selftests/kvm/x86/vmx_dirty_log_test.c    |  6 +--
 4 files changed, 37 insertions(+), 39 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/x86/vmx.h b/tools/testing/selftests/kvm/include/x86/vmx.h
index 91916b8aa94b..04b8231d032a 100644
--- a/tools/testing/selftests/kvm/include/x86/vmx.h
+++ b/tools/testing/selftests/kvm/include/x86/vmx.h
@@ -559,14 +559,14 @@ bool load_vmcs(struct vmx_pages *vmx);
 
 bool ept_1g_pages_supported(void);
 
-void nested_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm,
-		   uint64_t nested_paddr, uint64_t paddr);
-void nested_map(struct vmx_pages *vmx, struct kvm_vm *vm,
-		 uint64_t nested_paddr, uint64_t paddr, uint64_t size);
-void nested_identity_map_default_memslots(struct vmx_pages *vmx,
-					  struct kvm_vm *vm);
-void nested_identity_map_1g(struct vmx_pages *vmx, struct kvm_vm *vm,
-			    uint64_t addr, uint64_t size);
+void tdp_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm, uint64_t nested_paddr,
+		uint64_t paddr);
+void tdp_map(struct vmx_pages *vmx, struct kvm_vm *vm, uint64_t nested_paddr,
+	     uint64_t paddr, uint64_t size);
+void tdp_identity_map_default_memslots(struct vmx_pages *vmx,
+				       struct kvm_vm *vm);
+void tdp_identity_map_1g(struct vmx_pages *vmx, struct kvm_vm *vm,
+			 uint64_t addr, uint64_t size);
 bool kvm_cpu_has_ept(void);
 void prepare_eptp(struct vmx_pages *vmx, struct kvm_vm *vm);
 void prepare_virtualize_apic_accesses(struct vmx_pages *vmx, struct kvm_vm *vm);
diff --git a/tools/testing/selftests/kvm/lib/x86/memstress.c b/tools/testing/selftests/kvm/lib/x86/memstress.c
index 0b1f288ad556..1928b00bde51 100644
--- a/tools/testing/selftests/kvm/lib/x86/memstress.c
+++ b/tools/testing/selftests/kvm/lib/x86/memstress.c
@@ -70,11 +70,11 @@ void memstress_setup_ept(struct vmx_pages *vmx, struct kvm_vm *vm)
 	 * KVM can shadow the EPT12 with the maximum huge page size supported
 	 * by the backing source.
 	 */
-	nested_identity_map_1g(vmx, vm, 0, 0x100000000ULL);
+	tdp_identity_map_1g(vmx, vm, 0, 0x100000000ULL);
 
 	start = align_down(memstress_args.gpa, PG_SIZE_1G);
 	end = align_up(memstress_args.gpa + memstress_args.size, PG_SIZE_1G);
-	nested_identity_map_1g(vmx, vm, start, end - start);
+	tdp_identity_map_1g(vmx, vm, start, end - start);
 }
 
 void memstress_setup_nested(struct kvm_vm *vm, int nr_vcpus, struct kvm_vcpu *vcpus[])
diff --git a/tools/testing/selftests/kvm/lib/x86/vmx.c b/tools/testing/selftests/kvm/lib/x86/vmx.c
index eec33ec63811..1954ccdfc353 100644
--- a/tools/testing/selftests/kvm/lib/x86/vmx.c
+++ b/tools/testing/selftests/kvm/lib/x86/vmx.c
@@ -362,12 +362,12 @@ void prepare_vmcs(struct vmx_pages *vmx, void *guest_rip, void *guest_rsp)
 	init_vmcs_guest_state(guest_rip, guest_rsp);
 }
 
-static void nested_create_pte(struct kvm_vm *vm,
-			      struct eptPageTableEntry *pte,
-			      uint64_t nested_paddr,
-			      uint64_t paddr,
-			      int current_level,
-			      int target_level)
+static void tdp_create_pte(struct kvm_vm *vm,
+			   struct eptPageTableEntry *pte,
+			   uint64_t nested_paddr,
+			   uint64_t paddr,
+			   int current_level,
+			   int target_level)
 {
 	if (!pte->readable) {
 		pte->writable = true;
@@ -394,8 +394,8 @@ static void nested_create_pte(struct kvm_vm *vm,
 }
 
 
-void __nested_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm,
-		     uint64_t nested_paddr, uint64_t paddr, int target_level)
+void __tdp_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm,
+		  uint64_t nested_paddr, uint64_t paddr, int target_level)
 {
 	const uint64_t page_size = PG_LEVEL_SIZE(target_level);
 	struct eptPageTableEntry *pt = vmx->eptp_hva, *pte;
@@ -428,7 +428,7 @@ void __nested_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm,
 		index = (nested_paddr >> PG_LEVEL_SHIFT(level)) & 0x1ffu;
 		pte = &pt[index];
 
-		nested_create_pte(vm, pte, nested_paddr, paddr, level, target_level);
+		tdp_create_pte(vm, pte, nested_paddr, paddr, level, target_level);
 
 		if (pte->page_size)
 			break;
@@ -445,10 +445,10 @@ void __nested_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm,
 
 }
 
-void nested_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm,
-		   uint64_t nested_paddr, uint64_t paddr)
+void tdp_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm,
+		uint64_t nested_paddr, uint64_t paddr)
 {
-	__nested_pg_map(vmx, vm, nested_paddr, paddr, PG_LEVEL_4K);
+	__tdp_pg_map(vmx, vm, nested_paddr, paddr, PG_LEVEL_4K);
 }
 
 /*
@@ -468,8 +468,8 @@ void nested_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm,
  * Within the VM given by vm, creates a nested guest translation for the
  * page range starting at nested_paddr to the page range starting at paddr.
  */
-void __nested_map(struct vmx_pages *vmx, struct kvm_vm *vm,
-		  uint64_t nested_paddr, uint64_t paddr, uint64_t size,
+void __tdp_map(struct vmx_pages *vmx, struct kvm_vm *vm,
+	       uint64_t nested_paddr, uint64_t paddr, uint64_t size,
 		  int level)
 {
 	size_t page_size = PG_LEVEL_SIZE(level);
@@ -479,23 +479,23 @@ void __nested_map(struct vmx_pages *vmx, struct kvm_vm *vm,
 	TEST_ASSERT(paddr + size > paddr, "Paddr overflow");
 
 	while (npages--) {
-		__nested_pg_map(vmx, vm, nested_paddr, paddr, level);
+		__tdp_pg_map(vmx, vm, nested_paddr, paddr, level);
 		nested_paddr += page_size;
 		paddr += page_size;
 	}
 }
 
-void nested_map(struct vmx_pages *vmx, struct kvm_vm *vm,
-		uint64_t nested_paddr, uint64_t paddr, uint64_t size)
+void tdp_map(struct vmx_pages *vmx, struct kvm_vm *vm,
+	     uint64_t nested_paddr, uint64_t paddr, uint64_t size)
 {
-	__nested_map(vmx, vm, nested_paddr, paddr, size, PG_LEVEL_4K);
+	__tdp_map(vmx, vm, nested_paddr, paddr, size, PG_LEVEL_4K);
 }
 
 /* Prepare an identity extended page table that maps all the
  * physical pages in VM.
  */
-void nested_identity_map_default_memslots(struct vmx_pages *vmx,
-					  struct kvm_vm *vm)
+void tdp_identity_map_default_memslots(struct vmx_pages *vmx,
+				       struct kvm_vm *vm)
 {
 	uint32_t s, memslot = 0;
 	sparsebit_idx_t i, last;
@@ -512,18 +512,16 @@ void nested_identity_map_default_memslots(struct vmx_pages *vmx,
 		if (i > last)
 			break;
 
-		nested_map(vmx, vm,
-			   (uint64_t)i << vm->page_shift,
-			   (uint64_t)i << vm->page_shift,
-			   1 << vm->page_shift);
+		tdp_map(vmx, vm, (uint64_t)i << vm->page_shift,
+			(uint64_t)i << vm->page_shift, 1 << vm->page_shift);
 	}
 }
 
 /* Identity map a region with 1GiB Pages. */
-void nested_identity_map_1g(struct vmx_pages *vmx, struct kvm_vm *vm,
+void tdp_identity_map_1g(struct vmx_pages *vmx, struct kvm_vm *vm,
 			    uint64_t addr, uint64_t size)
 {
-	__nested_map(vmx, vm, addr, addr, size, PG_LEVEL_1G);
+	__tdp_map(vmx, vm, addr, addr, size, PG_LEVEL_1G);
 }
 
 bool kvm_cpu_has_ept(void)
diff --git a/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c b/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c
index aab7333aaef0..e7d0c08ba29d 100644
--- a/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c
+++ b/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c
@@ -121,9 +121,9 @@ static void test_vmx_dirty_log(bool enable_ept)
 	 */
 	if (enable_ept) {
 		prepare_eptp(vmx, vm);
-		nested_identity_map_default_memslots(vmx, vm);
-		nested_map(vmx, vm, NESTED_TEST_MEM1, GUEST_TEST_MEM, PAGE_SIZE);
-		nested_map(vmx, vm, NESTED_TEST_MEM2, GUEST_TEST_MEM, PAGE_SIZE);
+		tdp_identity_map_default_memslots(vmx, vm);
+		tdp_map(vmx, vm, NESTED_TEST_MEM1, GUEST_TEST_MEM, PAGE_SIZE);
+		tdp_map(vmx, vm, NESTED_TEST_MEM2, GUEST_TEST_MEM, PAGE_SIZE);
 	}
 
 	bmap = bitmap_zalloc(TEST_MEM_PAGES);
-- 
2.52.0.351.gbe84eed79e-goog



From seanjc at google.com  Tue Dec 30 15:01:33 2025
From: seanjc at google.com (Sean Christopherson)
Date: Tue, 30 Dec 2025 15:01:33 -0800
Subject: [PATCH v4 04/21] KVM: selftests: Kill eptPageTablePointer
In-Reply-To: <20251230230150.4150236-1-seanjc@google.com>
References: <20251230230150.4150236-1-seanjc@google.com>
Message-ID: <20251230230150.4150236-5-seanjc@google.com>

From: Yosry Ahmed <yosry.ahmed at linux.dev>

Replace the struct overlay with explicit bitmasks, which is clearer and
less error-prone. See commit f18b4aebe107 ("kvm: selftests: do not use
bitfields larger than 32-bits for PTEs") for an example of why bitfields
are not preferable.

Remove the unused PAGE_SHIFT_4K definition while at it.

No functional change intended.

Signed-off-by: Yosry Ahmed <yosry.ahmed at linux.dev>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 tools/testing/selftests/kvm/lib/x86/vmx.c | 35 +++++++++++------------
 1 file changed, 16 insertions(+), 19 deletions(-)

diff --git a/tools/testing/selftests/kvm/lib/x86/vmx.c b/tools/testing/selftests/kvm/lib/x86/vmx.c
index 1954ccdfc353..85043bb1ec4d 100644
--- a/tools/testing/selftests/kvm/lib/x86/vmx.c
+++ b/tools/testing/selftests/kvm/lib/x86/vmx.c
@@ -10,10 +10,16 @@
 #include "processor.h"
 #include "vmx.h"
 
-#define PAGE_SHIFT_4K  12
-
 #define KVM_EPT_PAGE_TABLE_MIN_PADDR 0x1c0000
 
+#define EPTP_MT_SHIFT		0 /* EPTP memtype bits 2:0 */
+#define EPTP_PWL_SHIFT		3 /* EPTP page walk length bits 5:3 */
+#define EPTP_AD_ENABLED_SHIFT	6 /* EPTP AD enabled bit 6 */
+
+#define EPTP_WB			(X86_MEMTYPE_WB << EPTP_MT_SHIFT)
+#define EPTP_PWL_4		(3ULL << EPTP_PWL_SHIFT) /* PWL is (levels - 1) */
+#define EPTP_AD_ENABLED		(1ULL << EPTP_AD_ENABLED_SHIFT)
+
 bool enable_evmcs;
 
 struct hv_enlightened_vmcs *current_evmcs;
@@ -34,14 +40,6 @@ struct eptPageTableEntry {
 	uint64_t suppress_ve:1;
 };
 
-struct eptPageTablePointer {
-	uint64_t memory_type:3;
-	uint64_t page_walk_length:3;
-	uint64_t ad_enabled:1;
-	uint64_t reserved_11_07:5;
-	uint64_t address:40;
-	uint64_t reserved_63_52:12;
-};
 int vcpu_enable_evmcs(struct kvm_vcpu *vcpu)
 {
 	uint16_t evmcs_ver;
@@ -196,16 +194,15 @@ static inline void init_vmcs_control_fields(struct vmx_pages *vmx)
 	vmwrite(PIN_BASED_VM_EXEC_CONTROL, rdmsr(MSR_IA32_VMX_TRUE_PINBASED_CTLS));
 
 	if (vmx->eptp_gpa) {
-		uint64_t ept_paddr;
-		struct eptPageTablePointer eptp = {
-			.memory_type = X86_MEMTYPE_WB,
-			.page_walk_length = 3, /* + 1 */
-			.ad_enabled = ept_vpid_cap_supported(VMX_EPT_VPID_CAP_AD_BITS),
-			.address = vmx->eptp_gpa >> PAGE_SHIFT_4K,
-		};
+		uint64_t eptp = vmx->eptp_gpa | EPTP_WB | EPTP_PWL_4;
 
-		memcpy(&ept_paddr, &eptp, sizeof(ept_paddr));
-		vmwrite(EPT_POINTER, ept_paddr);
+		TEST_ASSERT((vmx->eptp_gpa & ~PHYSICAL_PAGE_MASK) == 0,
+			    "Illegal bits set in vmx->eptp_gpa");
+
+		if (ept_vpid_cap_supported(VMX_EPT_VPID_CAP_AD_BITS))
+			eptp |= EPTP_AD_ENABLED;
+
+		vmwrite(EPT_POINTER, eptp);
 		sec_exec_ctl |= SECONDARY_EXEC_ENABLE_EPT;
 	}
 
-- 
2.52.0.351.gbe84eed79e-goog



From seanjc at google.com  Tue Dec 30 15:01:38 2025
From: seanjc at google.com (Sean Christopherson)
Date: Tue, 30 Dec 2025 15:01:38 -0800
Subject: [PATCH v4 09/21] KVM: selftests: Move PTE bitmasks to kvm_mmu
In-Reply-To: <20251230230150.4150236-1-seanjc@google.com>
References: <20251230230150.4150236-1-seanjc@google.com>
Message-ID: <20251230230150.4150236-10-seanjc@google.com>

From: Yosry Ahmed <yosry.ahmed at linux.dev>

Move the PTE bitmasks into kvm_mmu to parameterize them for virt mapping
functions. Introduce helpers to read/write different PTE bits given a
kvm_mmu.

Drop the 'global' bit definition as it's currently unused, but leave the
'user' bit as it will be used in coming changes. Opportunisitcally
rename 'large' to 'huge' as it's more consistent with the kernel naming.

Leave PHYSICAL_PAGE_MASK alone, it's fixed in all page table formats and
a lot of other macros depend on it. It's tempting to move all the other
macros to be per-struct instead, but it would be too much noise for
little benefit.

Keep c_bit and s_bit in vm->arch as they used before the MMU is
initialized, through  __vmcreate() -> vm_userspace_mem_region_add() ->
vm_mem_add() -> vm_arch_has_protected_memory().

No functional change intended.

Signed-off-by: Yosry Ahmed <yosry.ahmed at linux.dev>
[sean: rename accessors to is_<adjective>_pte()]
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 .../selftests/kvm/include/x86/kvm_util_arch.h | 16 ++++-
 .../selftests/kvm/include/x86/processor.h     | 28 +++++---
 .../testing/selftests/kvm/lib/x86/processor.c | 71 +++++++++++--------
 3 files changed, 76 insertions(+), 39 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h b/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h
index 456e5ca170df..bad381d63b6a 100644
--- a/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h
+++ b/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h
@@ -10,7 +10,21 @@
 
 extern bool is_forced_emulation_enabled;
 
-struct kvm_mmu_arch {};
+struct pte_masks {
+	uint64_t present;
+	uint64_t writable;
+	uint64_t user;
+	uint64_t accessed;
+	uint64_t dirty;
+	uint64_t huge;
+	uint64_t nx;
+	uint64_t c;
+	uint64_t s;
+};
+
+struct kvm_mmu_arch {
+	struct pte_masks pte_masks;
+};
 
 struct kvm_vm_arch {
 	vm_vaddr_t gdt;
diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h
index cbac9de29074..b2084434dd8b 100644
--- a/tools/testing/selftests/kvm/include/x86/processor.h
+++ b/tools/testing/selftests/kvm/include/x86/processor.h
@@ -362,16 +362,6 @@ static inline unsigned int x86_model(unsigned int eax)
 	return ((eax >> 12) & 0xf0) | ((eax >> 4) & 0x0f);
 }
 
-/* Page table bitfield declarations */
-#define PTE_PRESENT_MASK        BIT_ULL(0)
-#define PTE_WRITABLE_MASK       BIT_ULL(1)
-#define PTE_USER_MASK           BIT_ULL(2)
-#define PTE_ACCESSED_MASK       BIT_ULL(5)
-#define PTE_DIRTY_MASK          BIT_ULL(6)
-#define PTE_LARGE_MASK          BIT_ULL(7)
-#define PTE_GLOBAL_MASK         BIT_ULL(8)
-#define PTE_NX_MASK             BIT_ULL(63)
-
 #define PHYSICAL_PAGE_MASK      GENMASK_ULL(51, 12)
 
 #define PAGE_SHIFT		12
@@ -1449,6 +1439,24 @@ enum pg_level {
 #define PG_SIZE_2M PG_LEVEL_SIZE(PG_LEVEL_2M)
 #define PG_SIZE_1G PG_LEVEL_SIZE(PG_LEVEL_1G)
 
+#define PTE_PRESENT_MASK(mmu)		((mmu)->arch.pte_masks.present)
+#define PTE_WRITABLE_MASK(mmu)		((mmu)->arch.pte_masks.writable)
+#define PTE_USER_MASK(mmu)		((mmu)->arch.pte_masks.user)
+#define PTE_ACCESSED_MASK(mmu)		((mmu)->arch.pte_masks.accessed)
+#define PTE_DIRTY_MASK(mmu)		((mmu)->arch.pte_masks.dirty)
+#define PTE_HUGE_MASK(mmu)		((mmu)->arch.pte_masks.huge)
+#define PTE_NX_MASK(mmu)		((mmu)->arch.pte_masks.nx)
+#define PTE_C_BIT_MASK(mmu)		((mmu)->arch.pte_masks.c)
+#define PTE_S_BIT_MASK(mmu)		((mmu)->arch.pte_masks.s)
+
+#define is_present_pte(mmu, pte)	(!!(*(pte) & PTE_PRESENT_MASK(mmu)))
+#define is_writable_pte(mmu, pte)	(!!(*(pte) & PTE_WRITABLE_MASK(mmu)))
+#define is_user_pte(mmu, pte)		(!!(*(pte) & PTE_USER_MASK(mmu)))
+#define is_accessed_pte(mmu, pte)	(!!(*(pte) & PTE_ACCESSED_MASK(mmu)))
+#define is_dirty_pte(mmu, pte)		(!!(*(pte) & PTE_DIRTY_MASK(mmu)))
+#define is_huge_pte(mmu, pte)		(!!(*(pte) & PTE_HUGE_MASK(mmu)))
+#define is_nx_pte(mmu, pte)		(!!(*(pte) & PTE_NX_MASK(mmu)))
+
 void __virt_pg_map(struct kvm_vm *vm, struct kvm_mmu *mmu, uint64_t vaddr,
 		   uint64_t paddr,  int level);
 void virt_map_level(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
index f25742a804b0..3800f4ff6770 100644
--- a/tools/testing/selftests/kvm/lib/x86/processor.c
+++ b/tools/testing/selftests/kvm/lib/x86/processor.c
@@ -156,12 +156,14 @@ bool kvm_is_tdp_enabled(void)
 		return get_kvm_amd_param_bool("npt");
 }
 
-static void virt_mmu_init(struct kvm_vm *vm, struct kvm_mmu *mmu)
+static void virt_mmu_init(struct kvm_vm *vm, struct kvm_mmu *mmu,
+			  struct pte_masks *pte_masks)
 {
 	/* If needed, create the top-level page table. */
 	if (!mmu->pgd_created) {
 		mmu->pgd = vm_alloc_page_table(vm);
 		mmu->pgd_created = true;
+		mmu->arch.pte_masks = *pte_masks;
 	}
 }
 
@@ -170,7 +172,19 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm)
 	TEST_ASSERT(vm->mode == VM_MODE_PXXVYY_4K,
 		    "Unknown or unsupported guest mode: 0x%x", vm->mode);
 
-	virt_mmu_init(vm, &vm->mmu);
+	struct pte_masks pte_masks = (struct pte_masks){
+		.present	=	BIT_ULL(0),
+		.writable	=	BIT_ULL(1),
+		.user		=	BIT_ULL(2),
+		.accessed	=	BIT_ULL(5),
+		.dirty		=	BIT_ULL(6),
+		.huge		=	BIT_ULL(7),
+		.nx		=	BIT_ULL(63),
+		.c		=	vm->arch.c_bit,
+		.s		=	vm->arch.s_bit,
+	};
+
+	virt_mmu_init(vm, &vm->mmu, &pte_masks);
 }
 
 static void *virt_get_pte(struct kvm_vm *vm, struct kvm_mmu *mmu,
@@ -180,7 +194,7 @@ static void *virt_get_pte(struct kvm_vm *vm, struct kvm_mmu *mmu,
 	uint64_t *page_table = addr_gpa2hva(vm, pt_gpa);
 	int index = (vaddr >> PG_LEVEL_SHIFT(level)) & 0x1ffu;
 
-	TEST_ASSERT((*parent_pte == mmu->pgd) || (*parent_pte & PTE_PRESENT_MASK),
+	TEST_ASSERT((*parent_pte == mmu->pgd) || is_present_pte(mmu, parent_pte),
 		    "Parent PTE (level %d) not PRESENT for gva: 0x%08lx",
 		    level + 1, vaddr);
 
@@ -199,10 +213,10 @@ static uint64_t *virt_create_upper_pte(struct kvm_vm *vm,
 
 	paddr = vm_untag_gpa(vm, paddr);
 
-	if (!(*pte & PTE_PRESENT_MASK)) {
-		*pte = PTE_PRESENT_MASK | PTE_WRITABLE_MASK;
+	if (!is_present_pte(mmu, pte)) {
+		*pte = PTE_PRESENT_MASK(mmu) | PTE_WRITABLE_MASK(mmu);
 		if (current_level == target_level)
-			*pte |= PTE_LARGE_MASK | (paddr & PHYSICAL_PAGE_MASK);
+			*pte |= PTE_HUGE_MASK(mmu) | (paddr & PHYSICAL_PAGE_MASK);
 		else
 			*pte |= vm_alloc_page_table(vm) & PHYSICAL_PAGE_MASK;
 	} else {
@@ -214,7 +228,7 @@ static uint64_t *virt_create_upper_pte(struct kvm_vm *vm,
 		TEST_ASSERT(current_level != target_level,
 			    "Cannot create hugepage at level: %u, vaddr: 0x%lx",
 			    current_level, vaddr);
-		TEST_ASSERT(!(*pte & PTE_LARGE_MASK),
+		TEST_ASSERT(!is_huge_pte(mmu, pte),
 			    "Cannot create page table at level: %u, vaddr: 0x%lx",
 			    current_level, vaddr);
 	}
@@ -255,24 +269,24 @@ void __virt_pg_map(struct kvm_vm *vm, struct kvm_mmu *mmu, uint64_t vaddr,
 	     current_level--) {
 		pte = virt_create_upper_pte(vm, mmu, pte, vaddr, paddr,
 					    current_level, level);
-		if (*pte & PTE_LARGE_MASK)
+		if (is_huge_pte(mmu, pte))
 			return;
 	}
 
 	/* Fill in page table entry. */
 	pte = virt_get_pte(vm, mmu, pte, vaddr, PG_LEVEL_4K);
-	TEST_ASSERT(!(*pte & PTE_PRESENT_MASK),
+	TEST_ASSERT(!is_present_pte(mmu, pte),
 		    "PTE already present for 4k page at vaddr: 0x%lx", vaddr);
-	*pte = PTE_PRESENT_MASK | PTE_WRITABLE_MASK | (paddr & PHYSICAL_PAGE_MASK);
+	*pte = PTE_PRESENT_MASK(mmu) | PTE_WRITABLE_MASK(mmu) | (paddr & PHYSICAL_PAGE_MASK);
 
 	/*
 	 * Neither SEV nor TDX supports shared page tables, so only the final
 	 * leaf PTE needs manually set the C/S-bit.
 	 */
 	if (vm_is_gpa_protected(vm, paddr))
-		*pte |= vm->arch.c_bit;
+		*pte |= PTE_C_BIT_MASK(mmu);
 	else
-		*pte |= vm->arch.s_bit;
+		*pte |= PTE_S_BIT_MASK(mmu);
 }
 
 void virt_arch_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr)
@@ -304,7 +318,7 @@ void virt_map_level(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
 static bool vm_is_target_pte(struct kvm_mmu *mmu, uint64_t *pte,
 			     int *level, int current_level)
 {
-	if (*pte & PTE_LARGE_MASK) {
+	if (is_huge_pte(mmu, pte)) {
 		TEST_ASSERT(*level == PG_LEVEL_NONE ||
 			    *level == current_level,
 			    "Unexpected hugepage at level %d", current_level);
@@ -362,12 +376,13 @@ uint64_t *vm_get_page_table_entry(struct kvm_vm *vm, uint64_t vaddr)
 
 void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
 {
+	struct kvm_mmu *mmu = &vm->mmu;
 	uint64_t *pml4e, *pml4e_start;
 	uint64_t *pdpe, *pdpe_start;
 	uint64_t *pde, *pde_start;
 	uint64_t *pte, *pte_start;
 
-	if (!vm->mmu.pgd_created)
+	if (!mmu->pgd_created)
 		return;
 
 	fprintf(stream, "%*s                                          "
@@ -375,47 +390,47 @@ void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
 	fprintf(stream, "%*s      index hvaddr         gpaddr         "
 		"addr         w exec dirty\n",
 		indent, "");
-	pml4e_start = (uint64_t *) addr_gpa2hva(vm, vm->mmu.pgd);
+	pml4e_start = (uint64_t *) addr_gpa2hva(vm, mmu->pgd);
 	for (uint16_t n1 = 0; n1 <= 0x1ffu; n1++) {
 		pml4e = &pml4e_start[n1];
-		if (!(*pml4e & PTE_PRESENT_MASK))
+		if (!is_present_pte(mmu, pml4e))
 			continue;
 		fprintf(stream, "%*spml4e 0x%-3zx %p 0x%-12lx 0x%-10llx %u "
 			" %u\n",
 			indent, "",
 			pml4e - pml4e_start, pml4e,
 			addr_hva2gpa(vm, pml4e), PTE_GET_PFN(*pml4e),
-			!!(*pml4e & PTE_WRITABLE_MASK), !!(*pml4e & PTE_NX_MASK));
+			is_writable_pte(mmu, pml4e), is_nx_pte(mmu, pml4e));
 
 		pdpe_start = addr_gpa2hva(vm, *pml4e & PHYSICAL_PAGE_MASK);
 		for (uint16_t n2 = 0; n2 <= 0x1ffu; n2++) {
 			pdpe = &pdpe_start[n2];
-			if (!(*pdpe & PTE_PRESENT_MASK))
+			if (!is_present_pte(mmu, pdpe))
 				continue;
 			fprintf(stream, "%*spdpe  0x%-3zx %p 0x%-12lx 0x%-10llx "
 				"%u  %u\n",
 				indent, "",
 				pdpe - pdpe_start, pdpe,
 				addr_hva2gpa(vm, pdpe),
-				PTE_GET_PFN(*pdpe), !!(*pdpe & PTE_WRITABLE_MASK),
-				!!(*pdpe & PTE_NX_MASK));
+				PTE_GET_PFN(*pdpe), is_writable_pte(mmu, pdpe),
+				is_nx_pte(mmu, pdpe));
 
 			pde_start = addr_gpa2hva(vm, *pdpe & PHYSICAL_PAGE_MASK);
 			for (uint16_t n3 = 0; n3 <= 0x1ffu; n3++) {
 				pde = &pde_start[n3];
-				if (!(*pde & PTE_PRESENT_MASK))
+				if (!is_present_pte(mmu, pde))
 					continue;
 				fprintf(stream, "%*spde   0x%-3zx %p "
 					"0x%-12lx 0x%-10llx %u  %u\n",
 					indent, "", pde - pde_start, pde,
 					addr_hva2gpa(vm, pde),
-					PTE_GET_PFN(*pde), !!(*pde & PTE_WRITABLE_MASK),
-					!!(*pde & PTE_NX_MASK));
+					PTE_GET_PFN(*pde), is_writable_pte(mmu, pde),
+					is_nx_pte(mmu, pde));
 
 				pte_start = addr_gpa2hva(vm, *pde & PHYSICAL_PAGE_MASK);
 				for (uint16_t n4 = 0; n4 <= 0x1ffu; n4++) {
 					pte = &pte_start[n4];
-					if (!(*pte & PTE_PRESENT_MASK))
+					if (!is_present_pte(mmu, pte))
 						continue;
 					fprintf(stream, "%*spte   0x%-3zx %p "
 						"0x%-12lx 0x%-10llx %u  %u "
@@ -424,9 +439,9 @@ void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
 						pte - pte_start, pte,
 						addr_hva2gpa(vm, pte),
 						PTE_GET_PFN(*pte),
-						!!(*pte & PTE_WRITABLE_MASK),
-						!!(*pte & PTE_NX_MASK),
-						!!(*pte & PTE_DIRTY_MASK),
+						is_writable_pte(mmu, pte),
+						is_nx_pte(mmu, pte),
+						is_dirty_pte(mmu, pte),
 						((uint64_t) n1 << 27)
 							| ((uint64_t) n2 << 18)
 							| ((uint64_t) n3 << 9)
@@ -509,7 +524,7 @@ vm_paddr_t addr_arch_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva)
 	int level = PG_LEVEL_NONE;
 	uint64_t *pte = __vm_get_page_table_entry(vm, &vm->mmu, gva, &level);
 
-	TEST_ASSERT(*pte & PTE_PRESENT_MASK,
+	TEST_ASSERT(is_present_pte(&vm->mmu, pte),
 		    "Leaf PTE not PRESENT for gva: 0x%08lx", gva);
 
 	/*
-- 
2.52.0.351.gbe84eed79e-goog



From seanjc at google.com  Tue Dec 30 15:01:37 2025
From: seanjc at google.com (Sean Christopherson)
Date: Tue, 30 Dec 2025 15:01:37 -0800
Subject: [PATCH v4 08/21] KVM: selftests: Add a "struct kvm_mmu_arch arch"
 member to kvm_mmu
In-Reply-To: <20251230230150.4150236-1-seanjc@google.com>
References: <20251230230150.4150236-1-seanjc@google.com>
Message-ID: <20251230230150.4150236-9-seanjc@google.com>

Add an arch structure+field in "struct kvm_mmu" so that architectures can
track arch-specific information for a given MMU.

No functional change intended.

Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 tools/testing/selftests/kvm/include/arm64/kvm_util_arch.h     | 2 ++
 tools/testing/selftests/kvm/include/kvm_util.h                | 2 ++
 tools/testing/selftests/kvm/include/loongarch/kvm_util_arch.h | 1 +
 tools/testing/selftests/kvm/include/riscv/kvm_util_arch.h     | 1 +
 tools/testing/selftests/kvm/include/s390/kvm_util_arch.h      | 1 +
 tools/testing/selftests/kvm/include/x86/kvm_util_arch.h       | 2 ++
 6 files changed, 9 insertions(+)

diff --git a/tools/testing/selftests/kvm/include/arm64/kvm_util_arch.h b/tools/testing/selftests/kvm/include/arm64/kvm_util_arch.h
index b973bb2c64a6..4a2033708227 100644
--- a/tools/testing/selftests/kvm/include/arm64/kvm_util_arch.h
+++ b/tools/testing/selftests/kvm/include/arm64/kvm_util_arch.h
@@ -2,6 +2,8 @@
 #ifndef SELFTEST_KVM_UTIL_ARCH_H
 #define SELFTEST_KVM_UTIL_ARCH_H
 
+struct kvm_mmu_arch {};
+
 struct kvm_vm_arch {
 	bool	has_gic;
 	int	gic_fd;
diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index 39558c05c0bf..c1497515fa6a 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -92,6 +92,8 @@ struct kvm_mmu {
 	bool pgd_created;
 	uint64_t pgd;
 	int pgtable_levels;
+
+	struct kvm_mmu_arch arch;
 };
 
 struct kvm_vm {
diff --git a/tools/testing/selftests/kvm/include/loongarch/kvm_util_arch.h b/tools/testing/selftests/kvm/include/loongarch/kvm_util_arch.h
index e43a57d99b56..d5095900e442 100644
--- a/tools/testing/selftests/kvm/include/loongarch/kvm_util_arch.h
+++ b/tools/testing/selftests/kvm/include/loongarch/kvm_util_arch.h
@@ -2,6 +2,7 @@
 #ifndef SELFTEST_KVM_UTIL_ARCH_H
 #define SELFTEST_KVM_UTIL_ARCH_H
 
+struct kvm_mmu_arch {};
 struct kvm_vm_arch {};
 
 #endif  // SELFTEST_KVM_UTIL_ARCH_H
diff --git a/tools/testing/selftests/kvm/include/riscv/kvm_util_arch.h b/tools/testing/selftests/kvm/include/riscv/kvm_util_arch.h
index e43a57d99b56..d5095900e442 100644
--- a/tools/testing/selftests/kvm/include/riscv/kvm_util_arch.h
+++ b/tools/testing/selftests/kvm/include/riscv/kvm_util_arch.h
@@ -2,6 +2,7 @@
 #ifndef SELFTEST_KVM_UTIL_ARCH_H
 #define SELFTEST_KVM_UTIL_ARCH_H
 
+struct kvm_mmu_arch {};
 struct kvm_vm_arch {};
 
 #endif  // SELFTEST_KVM_UTIL_ARCH_H
diff --git a/tools/testing/selftests/kvm/include/s390/kvm_util_arch.h b/tools/testing/selftests/kvm/include/s390/kvm_util_arch.h
index e43a57d99b56..d5095900e442 100644
--- a/tools/testing/selftests/kvm/include/s390/kvm_util_arch.h
+++ b/tools/testing/selftests/kvm/include/s390/kvm_util_arch.h
@@ -2,6 +2,7 @@
 #ifndef SELFTEST_KVM_UTIL_ARCH_H
 #define SELFTEST_KVM_UTIL_ARCH_H
 
+struct kvm_mmu_arch {};
 struct kvm_vm_arch {};
 
 #endif  // SELFTEST_KVM_UTIL_ARCH_H
diff --git a/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h b/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h
index 972bb1c4ab4c..456e5ca170df 100644
--- a/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h
+++ b/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h
@@ -10,6 +10,8 @@
 
 extern bool is_forced_emulation_enabled;
 
+struct kvm_mmu_arch {};
+
 struct kvm_vm_arch {
 	vm_vaddr_t gdt;
 	vm_vaddr_t tss;
-- 
2.52.0.351.gbe84eed79e-goog



From seanjc at google.com  Tue Dec 30 15:01:34 2025
From: seanjc at google.com (Sean Christopherson)
Date: Tue, 30 Dec 2025 15:01:34 -0800
Subject: [PATCH v4 05/21] KVM: selftests: Stop setting A/D bits when creating
 EPT PTEs
In-Reply-To: <20251230230150.4150236-1-seanjc@google.com>
References: <20251230230150.4150236-1-seanjc@google.com>
Message-ID: <20251230230150.4150236-6-seanjc@google.com>

From: Yosry Ahmed <yosry.ahmed at linux.dev>

Stop setting Accessed/Dirty bits when creating EPT entries for L2 so that
the stage-1 and stage-2 (a.k.a. TDP) page table APIs can use common code
without bleeding the EPT hack into the common APIs.

While commit 094444204570 ("selftests: kvm: add test for dirty logging
inside nested guests") is _very_ light on details, the most likely
explanation is that vmx_dirty_log_test was attempting to avoid taking an
EPT Violation on the first _write_ from L2.

  static void l2_guest_code(u64 *a, u64 *b)
  {
	READ_ONCE(*a);
	WRITE_ONCE(*a, 1);   <===
	GUEST_SYNC(true);

	...
  }

When handling read faults in the shadow MMU, KVM opportunistically creates
a writable SPTE if the mapping can be writable *and* the gPTE is dirty (or
doesn't support the Dirty bit), i.e. if KVM doesn't need to intercept
writes in order to emulate Dirty-bit updates.  By setting A/D bits in the
test's EPT entries, the above READ+WRITE will fault only on the read, and
in theory expose the bug fixed by KVM commit 1f4e5fc83a42 ("KVM: x86: fix
nested guest live migration with PML").  If the Dirty bit is NOT set, the
test will get a false pass due; though again, in theory.

However, the test is flawed (and always was, at least in the versions
posted publicly), as KVM (correctly) marks the corresponding L1 GFN as
dirty (in the dirty bitmap) when creating the writable SPTE.  I.e. without
a check on the dirty bitmap after the READ_ONCE(), the check after the
first WRITE_ONCE() will get a false pass due to the dirty bitmap/log having
been updated by the read fault, not by PML.

Furthermore, the subsequent behavior in the test's l2_guest_code()
effectively hides the flawed test behavior, as the straight writes to a
new L2 GPA fault also trigger the KVM bug, and so the test will still
detect the failure due to lack of isolation between the two testcases
(Read=>Write vs. Write=>Write).

	WRITE_ONCE(*b, 1);
	GUEST_SYNC(true);
	WRITE_ONCE(*b, 1);
	GUEST_SYNC(true);
	GUEST_SYNC(false);

Punt on fixing vmx_dirty_log_test for the moment as it will be easier to
properly fix the test once the TDP code uses the common MMU APIs, at which
point it will be trivially easy for the test to retrieve the EPT PTE and
set the Dirty bit as needed.

Signed-off-by: Yosry Ahmed <yosry.ahmed at linux.dev>
[sean: rewrite changelog to explain the situation]
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 tools/testing/selftests/kvm/lib/x86/vmx.c | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/tools/testing/selftests/kvm/lib/x86/vmx.c b/tools/testing/selftests/kvm/lib/x86/vmx.c
index 85043bb1ec4d..a3e2eae981da 100644
--- a/tools/testing/selftests/kvm/lib/x86/vmx.c
+++ b/tools/testing/selftests/kvm/lib/x86/vmx.c
@@ -432,14 +432,6 @@ void __tdp_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm,
 
 		pt = addr_gpa2hva(vm, pte->address * vm->page_size);
 	}
-
-	/*
-	 * For now mark these as accessed and dirty because the only
-	 * testcase we have needs that.  Can be reconsidered later.
-	 */
-	pte->accessed = true;
-	pte->dirty = true;
-
 }
 
 void tdp_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm,
-- 
2.52.0.351.gbe84eed79e-goog



From seanjc at google.com  Tue Dec 30 15:01:39 2025
From: seanjc at google.com (Sean Christopherson)
Date: Tue, 30 Dec 2025 15:01:39 -0800
Subject: [PATCH v4 10/21] KVM: selftests: Use a TDP MMU to share EPT page
 tables between vCPUs
In-Reply-To: <20251230230150.4150236-1-seanjc@google.com>
References: <20251230230150.4150236-1-seanjc@google.com>
Message-ID: <20251230230150.4150236-11-seanjc@google.com>

From: Yosry Ahmed <yosry.ahmed at linux.dev>

prepare_eptp() currently allocates new EPTs for each vCPU.  memstress has
its own hack to share the EPTs between vCPUs.  Currently, there is no
reason to have separate EPTs for each vCPU, and the complexity is
significant.  The only reason it doesn't matter now is because memstress
is the only user with multiple vCPUs.

Add vm_enable_ept() to allocate EPT page tables for an entire VM, and use
it everywhere to replace prepare_eptp().  Drop 'eptp' and 'eptp_hva' from
'struct vmx_pages' as they serve no purpose (e.g. the EPTP can be built
from the PGD), but keep 'eptp_gpa' so that the MMU structure doesn't need
to be passed in along with vmx_pages.  Dynamically allocate the TDP MMU
structure to avoid a cyclical dependency between kvm_util_arch.h and
kvm_util.h.

Remove the workaround in memstress to copy the EPT root between vCPUs
since that's now the default behavior.

Name the MMU tdp_mmu instead of e.g. nested_mmu or nested.mmu to avoid
recreating the same mess that KVM has with respect to "nested" MMUs, e.g.
does nested refer to the stage-2 page tables created by L1, or the stage-1
page tables created by L2?

Signed-off-by: Yosry Ahmed <yosry.ahmed at linux.dev>
Co-developed-by: Sean Christopherson <seanjc at google.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 .../selftests/kvm/include/x86/kvm_util_arch.h |  4 +++
 .../selftests/kvm/include/x86/processor.h     |  3 ++
 tools/testing/selftests/kvm/include/x86/vmx.h |  8 ++---
 .../testing/selftests/kvm/lib/x86/memstress.c | 19 ++++--------
 .../testing/selftests/kvm/lib/x86/processor.c |  9 ++++++
 tools/testing/selftests/kvm/lib/x86/vmx.c     | 30 ++++++++++++-------
 .../selftests/kvm/x86/vmx_dirty_log_test.c    |  7 ++---
 7 files changed, 48 insertions(+), 32 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h b/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h
index bad381d63b6a..05a1fc1780f2 100644
--- a/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h
+++ b/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h
@@ -26,6 +26,8 @@ struct kvm_mmu_arch {
 	struct pte_masks pte_masks;
 };
 
+struct kvm_mmu;
+
 struct kvm_vm_arch {
 	vm_vaddr_t gdt;
 	vm_vaddr_t tss;
@@ -35,6 +37,8 @@ struct kvm_vm_arch {
 	uint64_t s_bit;
 	int sev_fd;
 	bool is_pt_protected;
+
+	struct kvm_mmu *tdp_mmu;
 };
 
 static inline bool __vm_arch_has_protected_memory(struct kvm_vm_arch *arch)
diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h
index b2084434dd8b..973f2069cd3b 100644
--- a/tools/testing/selftests/kvm/include/x86/processor.h
+++ b/tools/testing/selftests/kvm/include/x86/processor.h
@@ -1457,6 +1457,9 @@ enum pg_level {
 #define is_huge_pte(mmu, pte)		(!!(*(pte) & PTE_HUGE_MASK(mmu)))
 #define is_nx_pte(mmu, pte)		(!!(*(pte) & PTE_NX_MASK(mmu)))
 
+void tdp_mmu_init(struct kvm_vm *vm, int pgtable_levels,
+		  struct pte_masks *pte_masks);
+
 void __virt_pg_map(struct kvm_vm *vm, struct kvm_mmu *mmu, uint64_t vaddr,
 		   uint64_t paddr,  int level);
 void virt_map_level(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
diff --git a/tools/testing/selftests/kvm/include/x86/vmx.h b/tools/testing/selftests/kvm/include/x86/vmx.h
index 04b8231d032a..1fd83c23529a 100644
--- a/tools/testing/selftests/kvm/include/x86/vmx.h
+++ b/tools/testing/selftests/kvm/include/x86/vmx.h
@@ -520,13 +520,11 @@ struct vmx_pages {
 	uint64_t vmwrite_gpa;
 	void *vmwrite;
 
-	void *eptp_hva;
-	uint64_t eptp_gpa;
-	void *eptp;
-
 	void *apic_access_hva;
 	uint64_t apic_access_gpa;
 	void *apic_access;
+
+	uint64_t eptp_gpa;
 };
 
 union vmx_basic {
@@ -568,7 +566,7 @@ void tdp_identity_map_default_memslots(struct vmx_pages *vmx,
 void tdp_identity_map_1g(struct vmx_pages *vmx, struct kvm_vm *vm,
 			 uint64_t addr, uint64_t size);
 bool kvm_cpu_has_ept(void);
-void prepare_eptp(struct vmx_pages *vmx, struct kvm_vm *vm);
+void vm_enable_ept(struct kvm_vm *vm);
 void prepare_virtualize_apic_accesses(struct vmx_pages *vmx, struct kvm_vm *vm);
 
 #endif /* SELFTEST_KVM_VMX_H */
diff --git a/tools/testing/selftests/kvm/lib/x86/memstress.c b/tools/testing/selftests/kvm/lib/x86/memstress.c
index 1928b00bde51..00f7f11e5f0e 100644
--- a/tools/testing/selftests/kvm/lib/x86/memstress.c
+++ b/tools/testing/selftests/kvm/lib/x86/memstress.c
@@ -59,12 +59,10 @@ uint64_t memstress_nested_pages(int nr_vcpus)
 	return 513 + 10 * nr_vcpus;
 }
 
-void memstress_setup_ept(struct vmx_pages *vmx, struct kvm_vm *vm)
+static void memstress_setup_ept_mappings(struct vmx_pages *vmx, struct kvm_vm *vm)
 {
 	uint64_t start, end;
 
-	prepare_eptp(vmx, vm);
-
 	/*
 	 * Identity map the first 4G and the test region with 1G pages so that
 	 * KVM can shadow the EPT12 with the maximum huge page size supported
@@ -79,7 +77,7 @@ void memstress_setup_ept(struct vmx_pages *vmx, struct kvm_vm *vm)
 
 void memstress_setup_nested(struct kvm_vm *vm, int nr_vcpus, struct kvm_vcpu *vcpus[])
 {
-	struct vmx_pages *vmx, *vmx0 = NULL;
+	struct vmx_pages *vmx;
 	struct kvm_regs regs;
 	vm_vaddr_t vmx_gva;
 	int vcpu_id;
@@ -87,18 +85,13 @@ void memstress_setup_nested(struct kvm_vm *vm, int nr_vcpus, struct kvm_vcpu *vc
 	TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX));
 	TEST_REQUIRE(kvm_cpu_has_ept());
 
+	vm_enable_ept(vm);
 	for (vcpu_id = 0; vcpu_id < nr_vcpus; vcpu_id++) {
 		vmx = vcpu_alloc_vmx(vm, &vmx_gva);
 
-		if (vcpu_id == 0) {
-			memstress_setup_ept(vmx, vm);
-			vmx0 = vmx;
-		} else {
-			/* Share the same EPT table across all vCPUs. */
-			vmx->eptp = vmx0->eptp;
-			vmx->eptp_hva = vmx0->eptp_hva;
-			vmx->eptp_gpa = vmx0->eptp_gpa;
-		}
+		/* The EPTs are shared across vCPUs, setup the mappings once */
+		if (vcpu_id == 0)
+			memstress_setup_ept_mappings(vmx, vm);
 
 		/*
 		 * Override the vCPU to run memstress_l1_guest_code() which will
diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
index 3800f4ff6770..8a9298a72897 100644
--- a/tools/testing/selftests/kvm/lib/x86/processor.c
+++ b/tools/testing/selftests/kvm/lib/x86/processor.c
@@ -187,6 +187,15 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm)
 	virt_mmu_init(vm, &vm->mmu, &pte_masks);
 }
 
+void tdp_mmu_init(struct kvm_vm *vm, int pgtable_levels,
+		  struct pte_masks *pte_masks)
+{
+	TEST_ASSERT(!vm->arch.tdp_mmu, "TDP MMU already initialized");
+
+	vm->arch.tdp_mmu = calloc(1, sizeof(*vm->arch.tdp_mmu));
+	virt_mmu_init(vm, vm->arch.tdp_mmu, pte_masks);
+}
+
 static void *virt_get_pte(struct kvm_vm *vm, struct kvm_mmu *mmu,
 			  uint64_t *parent_pte, uint64_t vaddr, int level)
 {
diff --git a/tools/testing/selftests/kvm/lib/x86/vmx.c b/tools/testing/selftests/kvm/lib/x86/vmx.c
index a3e2eae981da..9d4e391fdf2c 100644
--- a/tools/testing/selftests/kvm/lib/x86/vmx.c
+++ b/tools/testing/selftests/kvm/lib/x86/vmx.c
@@ -56,6 +56,21 @@ int vcpu_enable_evmcs(struct kvm_vcpu *vcpu)
 	return evmcs_ver;
 }
 
+void vm_enable_ept(struct kvm_vm *vm)
+{
+	TEST_ASSERT(kvm_cpu_has_ept(), "KVM doesn't support nested EPT");
+	if (vm->arch.tdp_mmu)
+		return;
+
+	/* TODO: Drop eptPageTableEntry in favor of PTE masks. */
+	struct pte_masks pte_masks = (struct pte_masks) {
+
+	};
+
+	/* TODO: Add support for 5-level EPT. */
+	tdp_mmu_init(vm, 4, &pte_masks);
+}
+
 /* Allocate memory regions for nested VMX tests.
  *
  * Input Args:
@@ -105,6 +120,9 @@ vcpu_alloc_vmx(struct kvm_vm *vm, vm_vaddr_t *p_vmx_gva)
 	vmx->vmwrite_gpa = addr_gva2gpa(vm, (uintptr_t)vmx->vmwrite);
 	memset(vmx->vmwrite_hva, 0, getpagesize());
 
+	if (vm->arch.tdp_mmu)
+		vmx->eptp_gpa = vm->arch.tdp_mmu->pgd;
+
 	*p_vmx_gva = vmx_gva;
 	return vmx;
 }
@@ -395,7 +413,8 @@ void __tdp_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm,
 		  uint64_t nested_paddr, uint64_t paddr, int target_level)
 {
 	const uint64_t page_size = PG_LEVEL_SIZE(target_level);
-	struct eptPageTableEntry *pt = vmx->eptp_hva, *pte;
+	void *eptp_hva = addr_gpa2hva(vm, vm->arch.tdp_mmu->pgd);
+	struct eptPageTableEntry *pt = eptp_hva, *pte;
 	uint16_t index;
 
 	TEST_ASSERT(vm->mode == VM_MODE_PXXVYY_4K,
@@ -525,15 +544,6 @@ bool kvm_cpu_has_ept(void)
 	return ctrl & SECONDARY_EXEC_ENABLE_EPT;
 }
 
-void prepare_eptp(struct vmx_pages *vmx, struct kvm_vm *vm)
-{
-	TEST_ASSERT(kvm_cpu_has_ept(), "KVM doesn't support nested EPT");
-
-	vmx->eptp = (void *)vm_vaddr_alloc_page(vm);
-	vmx->eptp_hva = addr_gva2hva(vm, (uintptr_t)vmx->eptp);
-	vmx->eptp_gpa = addr_gva2gpa(vm, (uintptr_t)vmx->eptp);
-}
-
 void prepare_virtualize_apic_accesses(struct vmx_pages *vmx, struct kvm_vm *vm)
 {
 	vmx->apic_access = (void *)vm_vaddr_alloc_page(vm);
diff --git a/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c b/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c
index e7d0c08ba29d..5c8cf8ac42a2 100644
--- a/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c
+++ b/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c
@@ -93,6 +93,9 @@ static void test_vmx_dirty_log(bool enable_ept)
 
 	/* Create VM */
 	vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code);
+	if (enable_ept)
+		vm_enable_ept(vm);
+
 	vmx = vcpu_alloc_vmx(vm, &vmx_pages_gva);
 	vcpu_args_set(vcpu, 1, vmx_pages_gva);
 
@@ -113,14 +116,10 @@ static void test_vmx_dirty_log(bool enable_ept)
 	 * ... pages in the L2 GPA range [0xc0001000, 0xc0003000) will map to
 	 * 0xc0000000.
 	 *
-	 * Note that prepare_eptp should be called only L1's GPA map is done,
-	 * meaning after the last call to virt_map.
-	 *
 	 * When EPT is disabled, the L2 guest code will still access the same L1
 	 * GPAs as the EPT enabled case.
 	 */
 	if (enable_ept) {
-		prepare_eptp(vmx, vm);
 		tdp_identity_map_default_memslots(vmx, vm);
 		tdp_map(vmx, vm, NESTED_TEST_MEM1, GUEST_TEST_MEM, PAGE_SIZE);
 		tdp_map(vmx, vm, NESTED_TEST_MEM2, GUEST_TEST_MEM, PAGE_SIZE);
-- 
2.52.0.351.gbe84eed79e-goog



From seanjc at google.com  Tue Dec 30 15:01:40 2025
From: seanjc at google.com (Sean Christopherson)
Date: Tue, 30 Dec 2025 15:01:40 -0800
Subject: [PATCH v4 11/21] KVM: selftests: Stop passing VMX metadata to TDP
 mapping functions
In-Reply-To: <20251230230150.4150236-1-seanjc@google.com>
References: <20251230230150.4150236-1-seanjc@google.com>
Message-ID: <20251230230150.4150236-12-seanjc@google.com>

From: Yosry Ahmed <yosry.ahmed at linux.dev>

The root GPA can now be retrieved from the nested MMU, stop passing VMX
metadata. This is in preparation for making these functions work for
NPTs as well.

Opportunistically drop tdp_pg_map() since it's unused.

No functional change intended.

Signed-off-by: Yosry Ahmed <yosry.ahmed at linux.dev>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 tools/testing/selftests/kvm/include/x86/vmx.h | 11 ++-----
 .../testing/selftests/kvm/lib/x86/memstress.c | 11 +++----
 tools/testing/selftests/kvm/lib/x86/vmx.c     | 33 +++++++------------
 .../selftests/kvm/x86/vmx_dirty_log_test.c    |  9 +++--
 4 files changed, 24 insertions(+), 40 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/x86/vmx.h b/tools/testing/selftests/kvm/include/x86/vmx.h
index 1fd83c23529a..4dd4c2094ee6 100644
--- a/tools/testing/selftests/kvm/include/x86/vmx.h
+++ b/tools/testing/selftests/kvm/include/x86/vmx.h
@@ -557,14 +557,9 @@ bool load_vmcs(struct vmx_pages *vmx);
 
 bool ept_1g_pages_supported(void);
 
-void tdp_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm, uint64_t nested_paddr,
-		uint64_t paddr);
-void tdp_map(struct vmx_pages *vmx, struct kvm_vm *vm, uint64_t nested_paddr,
-	     uint64_t paddr, uint64_t size);
-void tdp_identity_map_default_memslots(struct vmx_pages *vmx,
-				       struct kvm_vm *vm);
-void tdp_identity_map_1g(struct vmx_pages *vmx, struct kvm_vm *vm,
-			 uint64_t addr, uint64_t size);
+void tdp_map(struct kvm_vm *vm, uint64_t nested_paddr, uint64_t paddr, uint64_t size);
+void tdp_identity_map_default_memslots(struct kvm_vm *vm);
+void tdp_identity_map_1g(struct kvm_vm *vm,  uint64_t addr, uint64_t size);
 bool kvm_cpu_has_ept(void);
 void vm_enable_ept(struct kvm_vm *vm);
 void prepare_virtualize_apic_accesses(struct vmx_pages *vmx, struct kvm_vm *vm);
diff --git a/tools/testing/selftests/kvm/lib/x86/memstress.c b/tools/testing/selftests/kvm/lib/x86/memstress.c
index 00f7f11e5f0e..3319cb57a78d 100644
--- a/tools/testing/selftests/kvm/lib/x86/memstress.c
+++ b/tools/testing/selftests/kvm/lib/x86/memstress.c
@@ -59,7 +59,7 @@ uint64_t memstress_nested_pages(int nr_vcpus)
 	return 513 + 10 * nr_vcpus;
 }
 
-static void memstress_setup_ept_mappings(struct vmx_pages *vmx, struct kvm_vm *vm)
+static void memstress_setup_ept_mappings(struct kvm_vm *vm)
 {
 	uint64_t start, end;
 
@@ -68,16 +68,15 @@ static void memstress_setup_ept_mappings(struct vmx_pages *vmx, struct kvm_vm *v
 	 * KVM can shadow the EPT12 with the maximum huge page size supported
 	 * by the backing source.
 	 */
-	tdp_identity_map_1g(vmx, vm, 0, 0x100000000ULL);
+	tdp_identity_map_1g(vm, 0, 0x100000000ULL);
 
 	start = align_down(memstress_args.gpa, PG_SIZE_1G);
 	end = align_up(memstress_args.gpa + memstress_args.size, PG_SIZE_1G);
-	tdp_identity_map_1g(vmx, vm, start, end - start);
+	tdp_identity_map_1g(vm, start, end - start);
 }
 
 void memstress_setup_nested(struct kvm_vm *vm, int nr_vcpus, struct kvm_vcpu *vcpus[])
 {
-	struct vmx_pages *vmx;
 	struct kvm_regs regs;
 	vm_vaddr_t vmx_gva;
 	int vcpu_id;
@@ -87,11 +86,11 @@ void memstress_setup_nested(struct kvm_vm *vm, int nr_vcpus, struct kvm_vcpu *vc
 
 	vm_enable_ept(vm);
 	for (vcpu_id = 0; vcpu_id < nr_vcpus; vcpu_id++) {
-		vmx = vcpu_alloc_vmx(vm, &vmx_gva);
+		vcpu_alloc_vmx(vm, &vmx_gva);
 
 		/* The EPTs are shared across vCPUs, setup the mappings once */
 		if (vcpu_id == 0)
-			memstress_setup_ept_mappings(vmx, vm);
+			memstress_setup_ept_mappings(vm);
 
 		/*
 		 * Override the vCPU to run memstress_l1_guest_code() which will
diff --git a/tools/testing/selftests/kvm/lib/x86/vmx.c b/tools/testing/selftests/kvm/lib/x86/vmx.c
index 9d4e391fdf2c..ea1c09f9e8ab 100644
--- a/tools/testing/selftests/kvm/lib/x86/vmx.c
+++ b/tools/testing/selftests/kvm/lib/x86/vmx.c
@@ -409,8 +409,8 @@ static void tdp_create_pte(struct kvm_vm *vm,
 }
 
 
-void __tdp_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm,
-		  uint64_t nested_paddr, uint64_t paddr, int target_level)
+void __tdp_pg_map(struct kvm_vm *vm, uint64_t nested_paddr, uint64_t paddr,
+		  int target_level)
 {
 	const uint64_t page_size = PG_LEVEL_SIZE(target_level);
 	void *eptp_hva = addr_gpa2hva(vm, vm->arch.tdp_mmu->pgd);
@@ -453,12 +453,6 @@ void __tdp_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm,
 	}
 }
 
-void tdp_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm,
-		uint64_t nested_paddr, uint64_t paddr)
-{
-	__tdp_pg_map(vmx, vm, nested_paddr, paddr, PG_LEVEL_4K);
-}
-
 /*
  * Map a range of EPT guest physical addresses to the VM's physical address
  *
@@ -476,9 +470,8 @@ void tdp_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm,
  * Within the VM given by vm, creates a nested guest translation for the
  * page range starting at nested_paddr to the page range starting at paddr.
  */
-void __tdp_map(struct vmx_pages *vmx, struct kvm_vm *vm,
-	       uint64_t nested_paddr, uint64_t paddr, uint64_t size,
-		  int level)
+void __tdp_map(struct kvm_vm *vm, uint64_t nested_paddr, uint64_t paddr,
+	       uint64_t size, int level)
 {
 	size_t page_size = PG_LEVEL_SIZE(level);
 	size_t npages = size / page_size;
@@ -487,23 +480,22 @@ void __tdp_map(struct vmx_pages *vmx, struct kvm_vm *vm,
 	TEST_ASSERT(paddr + size > paddr, "Paddr overflow");
 
 	while (npages--) {
-		__tdp_pg_map(vmx, vm, nested_paddr, paddr, level);
+		__tdp_pg_map(vm, nested_paddr, paddr, level);
 		nested_paddr += page_size;
 		paddr += page_size;
 	}
 }
 
-void tdp_map(struct vmx_pages *vmx, struct kvm_vm *vm,
-	     uint64_t nested_paddr, uint64_t paddr, uint64_t size)
+void tdp_map(struct kvm_vm *vm, uint64_t nested_paddr, uint64_t paddr,
+	     uint64_t size)
 {
-	__tdp_map(vmx, vm, nested_paddr, paddr, size, PG_LEVEL_4K);
+	__tdp_map(vm, nested_paddr, paddr, size, PG_LEVEL_4K);
 }
 
 /* Prepare an identity extended page table that maps all the
  * physical pages in VM.
  */
-void tdp_identity_map_default_memslots(struct vmx_pages *vmx,
-				       struct kvm_vm *vm)
+void tdp_identity_map_default_memslots(struct kvm_vm *vm)
 {
 	uint32_t s, memslot = 0;
 	sparsebit_idx_t i, last;
@@ -520,16 +512,15 @@ void tdp_identity_map_default_memslots(struct vmx_pages *vmx,
 		if (i > last)
 			break;
 
-		tdp_map(vmx, vm, (uint64_t)i << vm->page_shift,
+		tdp_map(vm, (uint64_t)i << vm->page_shift,
 			(uint64_t)i << vm->page_shift, 1 << vm->page_shift);
 	}
 }
 
 /* Identity map a region with 1GiB Pages. */
-void tdp_identity_map_1g(struct vmx_pages *vmx, struct kvm_vm *vm,
-			    uint64_t addr, uint64_t size)
+void tdp_identity_map_1g(struct kvm_vm *vm, uint64_t addr, uint64_t size)
 {
-	__tdp_map(vmx, vm, addr, addr, size, PG_LEVEL_1G);
+	__tdp_map(vm, addr, addr, size, PG_LEVEL_1G);
 }
 
 bool kvm_cpu_has_ept(void)
diff --git a/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c b/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c
index 5c8cf8ac42a2..370f8d3117c2 100644
--- a/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c
+++ b/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c
@@ -80,7 +80,6 @@ void l1_guest_code(struct vmx_pages *vmx)
 static void test_vmx_dirty_log(bool enable_ept)
 {
 	vm_vaddr_t vmx_pages_gva = 0;
-	struct vmx_pages *vmx;
 	unsigned long *bmap;
 	uint64_t *host_test_mem;
 
@@ -96,7 +95,7 @@ static void test_vmx_dirty_log(bool enable_ept)
 	if (enable_ept)
 		vm_enable_ept(vm);
 
-	vmx = vcpu_alloc_vmx(vm, &vmx_pages_gva);
+	vcpu_alloc_vmx(vm, &vmx_pages_gva);
 	vcpu_args_set(vcpu, 1, vmx_pages_gva);
 
 	/* Add an extra memory slot for testing dirty logging */
@@ -120,9 +119,9 @@ static void test_vmx_dirty_log(bool enable_ept)
 	 * GPAs as the EPT enabled case.
 	 */
 	if (enable_ept) {
-		tdp_identity_map_default_memslots(vmx, vm);
-		tdp_map(vmx, vm, NESTED_TEST_MEM1, GUEST_TEST_MEM, PAGE_SIZE);
-		tdp_map(vmx, vm, NESTED_TEST_MEM2, GUEST_TEST_MEM, PAGE_SIZE);
+		tdp_identity_map_default_memslots(vm);
+		tdp_map(vm, NESTED_TEST_MEM1, GUEST_TEST_MEM, PAGE_SIZE);
+		tdp_map(vm, NESTED_TEST_MEM2, GUEST_TEST_MEM, PAGE_SIZE);
 	}
 
 	bmap = bitmap_zalloc(TEST_MEM_PAGES);
-- 
2.52.0.351.gbe84eed79e-goog



From seanjc at google.com  Tue Dec 30 15:01:41 2025
From: seanjc at google.com (Sean Christopherson)
Date: Tue, 30 Dec 2025 15:01:41 -0800
Subject: [PATCH v4 12/21] KVM: selftests: Add a stage-2 MMU instance to kvm_vm
In-Reply-To: <20251230230150.4150236-1-seanjc@google.com>
References: <20251230230150.4150236-1-seanjc@google.com>
Message-ID: <20251230230150.4150236-13-seanjc@google.com>

Add a stage-2 MMU instance so that architectures that support nested
virtualization (more specifically, nested stage-2 page tables) can create
and track stage-2 page tables for running L2 guests.  Plumb the structure
into common code to avoid cyclical dependencies, and to provide some line
of sight to having common APIs for creating stage-2 mappings.

As a bonus, putting the member in common code justifies using stage2_mmu
instead of tdp_mmu for x86.

Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 tools/testing/selftests/kvm/include/kvm_util.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index c1497515fa6a..371d55e0366e 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -116,7 +116,12 @@ struct kvm_vm {
 	uint32_t dirty_ring_size;
 	uint64_t gpa_tag_mask;
 
+	/*
+	 * "mmu" is the guest's stage-1, with a short name because the vast
+	 * majority of tests only care about the stage-1 MMU.
+	 */
 	struct kvm_mmu mmu;
+	struct kvm_mmu stage2_mmu;
 
 	struct kvm_vm_arch arch;
 
-- 
2.52.0.351.gbe84eed79e-goog



From seanjc at google.com  Tue Dec 30 15:01:42 2025
From: seanjc at google.com (Sean Christopherson)
Date: Tue, 30 Dec 2025 15:01:42 -0800
Subject: [PATCH v4 13/21] KVM: selftests: Reuse virt mapping functions for
 nested EPTs
In-Reply-To: <20251230230150.4150236-1-seanjc@google.com>
References: <20251230230150.4150236-1-seanjc@google.com>
Message-ID: <20251230230150.4150236-14-seanjc@google.com>

From: Yosry Ahmed <yosry.ahmed at linux.dev>

Rework tdp_map() and friends to use __virt_pg_map() and drop the custom
EPT code in __tdp_pg_map() and tdp_create_pte().  The EPT code and
__virt_pg_map() are practically identical, the main differences are:
  - EPT uses the EPT struct overlay instead of the PTE masks.
  - EPT always assumes 4-level EPTs.

To reuse __virt_pg_map(), extend the PTE masks to work with EPT's RWX and
X-only capabilities, and provide a tdp_mmu_init() API so that EPT can pass
in the EPT PTE masks along with the root page level (which is currently
hardcoded to '4').

Don't reuse KVM's insane overloading of the USER bit for EPT_R as there's
no reason to multiplex bits in the selftests, e.g. selftests aren't trying
to shadow guest PTEs and thus don't care about funnelling protections into
a common permissions check.

Another benefit of reusing the code is having separate handling for
upper-level PTEs vs 4K PTEs, which avoids some quirks like setting the
large bit on a 4K PTE in the EPTs.

For all intents and purposes, no functional change intended.

Suggested-by: Sean Christopherson <seanjc at google.com>
Signed-off-by: Yosry Ahmed <yosry.ahmed at linux.dev>
Co-developed-by: Sean Christopherson <seanjc at google.com>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 .../selftests/kvm/include/x86/kvm_util_arch.h |   4 +-
 .../selftests/kvm/include/x86/processor.h     |  16 ++-
 .../testing/selftests/kvm/lib/x86/processor.c |  21 +++-
 tools/testing/selftests/kvm/lib/x86/vmx.c     | 119 +++---------------
 4 files changed, 52 insertions(+), 108 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h b/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h
index 05a1fc1780f2..1cf84b8212c6 100644
--- a/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h
+++ b/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h
@@ -14,6 +14,8 @@ struct pte_masks {
 	uint64_t present;
 	uint64_t writable;
 	uint64_t user;
+	uint64_t readable;
+	uint64_t executable;
 	uint64_t accessed;
 	uint64_t dirty;
 	uint64_t huge;
@@ -37,8 +39,6 @@ struct kvm_vm_arch {
 	uint64_t s_bit;
 	int sev_fd;
 	bool is_pt_protected;
-
-	struct kvm_mmu *tdp_mmu;
 };
 
 static inline bool __vm_arch_has_protected_memory(struct kvm_vm_arch *arch)
diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h
index 973f2069cd3b..4c0d2fc83c1c 100644
--- a/tools/testing/selftests/kvm/include/x86/processor.h
+++ b/tools/testing/selftests/kvm/include/x86/processor.h
@@ -1442,6 +1442,8 @@ enum pg_level {
 #define PTE_PRESENT_MASK(mmu)		((mmu)->arch.pte_masks.present)
 #define PTE_WRITABLE_MASK(mmu)		((mmu)->arch.pte_masks.writable)
 #define PTE_USER_MASK(mmu)		((mmu)->arch.pte_masks.user)
+#define PTE_READABLE_MASK(mmu)		((mmu)->arch.pte_masks.readable)
+#define PTE_EXECUTABLE_MASK(mmu)	((mmu)->arch.pte_masks.executable)
 #define PTE_ACCESSED_MASK(mmu)		((mmu)->arch.pte_masks.accessed)
 #define PTE_DIRTY_MASK(mmu)		((mmu)->arch.pte_masks.dirty)
 #define PTE_HUGE_MASK(mmu)		((mmu)->arch.pte_masks.huge)
@@ -1449,13 +1451,23 @@ enum pg_level {
 #define PTE_C_BIT_MASK(mmu)		((mmu)->arch.pte_masks.c)
 #define PTE_S_BIT_MASK(mmu)		((mmu)->arch.pte_masks.s)
 
-#define is_present_pte(mmu, pte)	(!!(*(pte) & PTE_PRESENT_MASK(mmu)))
+/*
+ * For PTEs without a PRESENT bit (i.e. EPT entries), treat the PTE as present
+ * if it's executable or readable, as EPT supports execute-only PTEs, but not
+ * write-only PTEs.
+ */
+#define is_present_pte(mmu, pte)		\
+	(PTE_PRESENT_MASK(mmu) ?		\
+	 !!(*(pte) & PTE_PRESENT_MASK(mmu)) :	\
+	 !!(*(pte) & (PTE_READABLE_MASK(mmu) | PTE_EXECUTABLE_MASK(mmu))))
+#define is_executable_pte(mmu, pte)	\
+	((*(pte) & (PTE_EXECUTABLE_MASK(mmu) | PTE_NX_MASK(mmu))) == PTE_EXECUTABLE_MASK(mmu))
 #define is_writable_pte(mmu, pte)	(!!(*(pte) & PTE_WRITABLE_MASK(mmu)))
 #define is_user_pte(mmu, pte)		(!!(*(pte) & PTE_USER_MASK(mmu)))
 #define is_accessed_pte(mmu, pte)	(!!(*(pte) & PTE_ACCESSED_MASK(mmu)))
 #define is_dirty_pte(mmu, pte)		(!!(*(pte) & PTE_DIRTY_MASK(mmu)))
 #define is_huge_pte(mmu, pte)		(!!(*(pte) & PTE_HUGE_MASK(mmu)))
-#define is_nx_pte(mmu, pte)		(!!(*(pte) & PTE_NX_MASK(mmu)))
+#define is_nx_pte(mmu, pte)		(!is_executable_pte(mmu, pte))
 
 void tdp_mmu_init(struct kvm_vm *vm, int pgtable_levels,
 		  struct pte_masks *pte_masks);
diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
index 8a9298a72897..41316cac94e0 100644
--- a/tools/testing/selftests/kvm/lib/x86/processor.c
+++ b/tools/testing/selftests/kvm/lib/x86/processor.c
@@ -165,6 +165,10 @@ static void virt_mmu_init(struct kvm_vm *vm, struct kvm_mmu *mmu,
 		mmu->pgd_created = true;
 		mmu->arch.pte_masks = *pte_masks;
 	}
+
+	TEST_ASSERT(mmu->pgtable_levels == 4 || mmu->pgtable_levels == 5,
+		    "Selftests MMU only supports 4-level and 5-level paging, not %u-level paging",
+		    mmu->pgtable_levels);
 }
 
 void virt_arch_pgd_alloc(struct kvm_vm *vm)
@@ -180,6 +184,7 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm)
 		.dirty		=	BIT_ULL(6),
 		.huge		=	BIT_ULL(7),
 		.nx		=	BIT_ULL(63),
+		.executable	=	0,
 		.c		=	vm->arch.c_bit,
 		.s		=	vm->arch.s_bit,
 	};
@@ -190,10 +195,10 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm)
 void tdp_mmu_init(struct kvm_vm *vm, int pgtable_levels,
 		  struct pte_masks *pte_masks)
 {
-	TEST_ASSERT(!vm->arch.tdp_mmu, "TDP MMU already initialized");
+	TEST_ASSERT(!vm->stage2_mmu.pgtable_levels, "TDP MMU already initialized");
 
-	vm->arch.tdp_mmu = calloc(1, sizeof(*vm->arch.tdp_mmu));
-	virt_mmu_init(vm, vm->arch.tdp_mmu, pte_masks);
+	vm->stage2_mmu.pgtable_levels = pgtable_levels;
+	virt_mmu_init(vm, &vm->stage2_mmu, pte_masks);
 }
 
 static void *virt_get_pte(struct kvm_vm *vm, struct kvm_mmu *mmu,
@@ -223,7 +228,8 @@ static uint64_t *virt_create_upper_pte(struct kvm_vm *vm,
 	paddr = vm_untag_gpa(vm, paddr);
 
 	if (!is_present_pte(mmu, pte)) {
-		*pte = PTE_PRESENT_MASK(mmu) | PTE_WRITABLE_MASK(mmu);
+		*pte = PTE_PRESENT_MASK(mmu) | PTE_READABLE_MASK(mmu) |
+		       PTE_WRITABLE_MASK(mmu) | PTE_EXECUTABLE_MASK(mmu);
 		if (current_level == target_level)
 			*pte |= PTE_HUGE_MASK(mmu) | (paddr & PHYSICAL_PAGE_MASK);
 		else
@@ -269,6 +275,9 @@ void __virt_pg_map(struct kvm_vm *vm, struct kvm_mmu *mmu, uint64_t vaddr,
 	TEST_ASSERT(vm_untag_gpa(vm, paddr) == paddr,
 		    "Unexpected bits in paddr: %lx", paddr);
 
+	TEST_ASSERT(!PTE_EXECUTABLE_MASK(mmu) || !PTE_NX_MASK(mmu),
+		    "X and NX bit masks cannot be used simultaneously");
+
 	/*
 	 * Allocate upper level page tables, if not already present.  Return
 	 * early if a hugepage was created.
@@ -286,7 +295,9 @@ void __virt_pg_map(struct kvm_vm *vm, struct kvm_mmu *mmu, uint64_t vaddr,
 	pte = virt_get_pte(vm, mmu, pte, vaddr, PG_LEVEL_4K);
 	TEST_ASSERT(!is_present_pte(mmu, pte),
 		    "PTE already present for 4k page at vaddr: 0x%lx", vaddr);
-	*pte = PTE_PRESENT_MASK(mmu) | PTE_WRITABLE_MASK(mmu) | (paddr & PHYSICAL_PAGE_MASK);
+	*pte = PTE_PRESENT_MASK(mmu) | PTE_READABLE_MASK(mmu) |
+	       PTE_WRITABLE_MASK(mmu) | PTE_EXECUTABLE_MASK(mmu) |
+	       (paddr & PHYSICAL_PAGE_MASK);
 
 	/*
 	 * Neither SEV nor TDX supports shared page tables, so only the final
diff --git a/tools/testing/selftests/kvm/lib/x86/vmx.c b/tools/testing/selftests/kvm/lib/x86/vmx.c
index ea1c09f9e8ab..e3737b3d9120 100644
--- a/tools/testing/selftests/kvm/lib/x86/vmx.c
+++ b/tools/testing/selftests/kvm/lib/x86/vmx.c
@@ -25,21 +25,6 @@ bool enable_evmcs;
 struct hv_enlightened_vmcs *current_evmcs;
 struct hv_vp_assist_page *current_vp_assist;
 
-struct eptPageTableEntry {
-	uint64_t readable:1;
-	uint64_t writable:1;
-	uint64_t executable:1;
-	uint64_t memory_type:3;
-	uint64_t ignore_pat:1;
-	uint64_t page_size:1;
-	uint64_t accessed:1;
-	uint64_t dirty:1;
-	uint64_t ignored_11_10:2;
-	uint64_t address:40;
-	uint64_t ignored_62_52:11;
-	uint64_t suppress_ve:1;
-};
-
 int vcpu_enable_evmcs(struct kvm_vcpu *vcpu)
 {
 	uint16_t evmcs_ver;
@@ -58,13 +43,24 @@ int vcpu_enable_evmcs(struct kvm_vcpu *vcpu)
 
 void vm_enable_ept(struct kvm_vm *vm)
 {
+	struct pte_masks pte_masks;
+
 	TEST_ASSERT(kvm_cpu_has_ept(), "KVM doesn't support nested EPT");
-	if (vm->arch.tdp_mmu)
-		return;
-
-	/* TODO: Drop eptPageTableEntry in favor of PTE masks. */
-	struct pte_masks pte_masks = (struct pte_masks) {
 
+	/*
+	 * EPTs do not have 'present' or 'user' bits, instead bit 0 is the
+	 * 'readable' bit.
+	 */
+	pte_masks = (struct pte_masks) {
+		.present	=	0,
+		.user		=	0,
+		.readable	=	BIT_ULL(0),
+		.writable	=	BIT_ULL(1),
+		.executable	=	BIT_ULL(2),
+		.huge		=	BIT_ULL(7),
+		.accessed	=	BIT_ULL(8),
+		.dirty		=	BIT_ULL(9),
+		.nx		=	0,
 	};
 
 	/* TODO: Add support for 5-level EPT. */
@@ -120,8 +116,8 @@ vcpu_alloc_vmx(struct kvm_vm *vm, vm_vaddr_t *p_vmx_gva)
 	vmx->vmwrite_gpa = addr_gva2gpa(vm, (uintptr_t)vmx->vmwrite);
 	memset(vmx->vmwrite_hva, 0, getpagesize());
 
-	if (vm->arch.tdp_mmu)
-		vmx->eptp_gpa = vm->arch.tdp_mmu->pgd;
+	if (vm->stage2_mmu.pgd_created)
+		vmx->eptp_gpa = vm->stage2_mmu.pgd;
 
 	*p_vmx_gva = vmx_gva;
 	return vmx;
@@ -377,82 +373,6 @@ void prepare_vmcs(struct vmx_pages *vmx, void *guest_rip, void *guest_rsp)
 	init_vmcs_guest_state(guest_rip, guest_rsp);
 }
 
-static void tdp_create_pte(struct kvm_vm *vm,
-			   struct eptPageTableEntry *pte,
-			   uint64_t nested_paddr,
-			   uint64_t paddr,
-			   int current_level,
-			   int target_level)
-{
-	if (!pte->readable) {
-		pte->writable = true;
-		pte->readable = true;
-		pte->executable = true;
-		pte->page_size = (current_level == target_level);
-		if (pte->page_size)
-			pte->address = paddr >> vm->page_shift;
-		else
-			pte->address = vm_alloc_page_table(vm) >> vm->page_shift;
-	} else {
-		/*
-		 * Entry already present.  Assert that the caller doesn't want
-		 * a hugepage at this level, and that there isn't a hugepage at
-		 * this level.
-		 */
-		TEST_ASSERT(current_level != target_level,
-			    "Cannot create hugepage at level: %u, nested_paddr: 0x%lx",
-			    current_level, nested_paddr);
-		TEST_ASSERT(!pte->page_size,
-			    "Cannot create page table at level: %u, nested_paddr: 0x%lx",
-			    current_level, nested_paddr);
-	}
-}
-
-
-void __tdp_pg_map(struct kvm_vm *vm, uint64_t nested_paddr, uint64_t paddr,
-		  int target_level)
-{
-	const uint64_t page_size = PG_LEVEL_SIZE(target_level);
-	void *eptp_hva = addr_gpa2hva(vm, vm->arch.tdp_mmu->pgd);
-	struct eptPageTableEntry *pt = eptp_hva, *pte;
-	uint16_t index;
-
-	TEST_ASSERT(vm->mode == VM_MODE_PXXVYY_4K,
-		    "Unknown or unsupported guest mode: 0x%x", vm->mode);
-
-	TEST_ASSERT((nested_paddr >> 48) == 0,
-		    "Nested physical address 0x%lx is > 48-bits and requires 5-level EPT",
-		    nested_paddr);
-	TEST_ASSERT((nested_paddr % page_size) == 0,
-		    "Nested physical address not on page boundary,\n"
-		    "  nested_paddr: 0x%lx page_size: 0x%lx",
-		    nested_paddr, page_size);
-	TEST_ASSERT((nested_paddr >> vm->page_shift) <= vm->max_gfn,
-		    "Physical address beyond beyond maximum supported,\n"
-		    "  nested_paddr: 0x%lx vm->max_gfn: 0x%lx vm->page_size: 0x%x",
-		    paddr, vm->max_gfn, vm->page_size);
-	TEST_ASSERT((paddr % page_size) == 0,
-		    "Physical address not on page boundary,\n"
-		    "  paddr: 0x%lx page_size: 0x%lx",
-		    paddr, page_size);
-	TEST_ASSERT((paddr >> vm->page_shift) <= vm->max_gfn,
-		    "Physical address beyond beyond maximum supported,\n"
-		    "  paddr: 0x%lx vm->max_gfn: 0x%lx vm->page_size: 0x%x",
-		    paddr, vm->max_gfn, vm->page_size);
-
-	for (int level = PG_LEVEL_512G; level >= PG_LEVEL_4K; level--) {
-		index = (nested_paddr >> PG_LEVEL_SHIFT(level)) & 0x1ffu;
-		pte = &pt[index];
-
-		tdp_create_pte(vm, pte, nested_paddr, paddr, level, target_level);
-
-		if (pte->page_size)
-			break;
-
-		pt = addr_gpa2hva(vm, pte->address * vm->page_size);
-	}
-}
-
 /*
  * Map a range of EPT guest physical addresses to the VM's physical address
  *
@@ -473,6 +393,7 @@ void __tdp_pg_map(struct kvm_vm *vm, uint64_t nested_paddr, uint64_t paddr,
 void __tdp_map(struct kvm_vm *vm, uint64_t nested_paddr, uint64_t paddr,
 	       uint64_t size, int level)
 {
+	struct kvm_mmu *mmu = &vm->stage2_mmu;
 	size_t page_size = PG_LEVEL_SIZE(level);
 	size_t npages = size / page_size;
 
@@ -480,7 +401,7 @@ void __tdp_map(struct kvm_vm *vm, uint64_t nested_paddr, uint64_t paddr,
 	TEST_ASSERT(paddr + size > paddr, "Paddr overflow");
 
 	while (npages--) {
-		__tdp_pg_map(vm, nested_paddr, paddr, level);
+		__virt_pg_map(vm, mmu, nested_paddr, paddr, level);
 		nested_paddr += page_size;
 		paddr += page_size;
 	}
-- 
2.52.0.351.gbe84eed79e-goog



From seanjc at google.com  Tue Dec 30 15:01:43 2025
From: seanjc at google.com (Sean Christopherson)
Date: Tue, 30 Dec 2025 15:01:43 -0800
Subject: [PATCH v4 14/21] KVM: selftests: Move TDP mapping functions outside
 of vmx.c
In-Reply-To: <20251230230150.4150236-1-seanjc@google.com>
References: <20251230230150.4150236-1-seanjc@google.com>
Message-ID: <20251230230150.4150236-15-seanjc@google.com>

Now that the functions are no longer VMX-specific, move them to
processor.c. Do a minor comment tweak replacing 'EPT' with 'TDP'.

No functional change intended.

Signed-off-by: Yosry Ahmed <yosry.ahmed at linux.dev>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 .../selftests/kvm/include/x86/processor.h     |  4 ++
 tools/testing/selftests/kvm/include/x86/vmx.h |  3 -
 .../testing/selftests/kvm/lib/x86/processor.c | 53 ++++++++++++++
 tools/testing/selftests/kvm/lib/x86/vmx.c     | 71 -------------------
 4 files changed, 57 insertions(+), 74 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h
index 4c0d2fc83c1c..d134c886f280 100644
--- a/tools/testing/selftests/kvm/include/x86/processor.h
+++ b/tools/testing/selftests/kvm/include/x86/processor.h
@@ -1477,6 +1477,10 @@ void __virt_pg_map(struct kvm_vm *vm, struct kvm_mmu *mmu, uint64_t vaddr,
 void virt_map_level(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
 		    uint64_t nr_bytes, int level);
 
+void tdp_map(struct kvm_vm *vm, uint64_t nested_paddr, uint64_t paddr, uint64_t size);
+void tdp_identity_map_default_memslots(struct kvm_vm *vm);
+void tdp_identity_map_1g(struct kvm_vm *vm,  uint64_t addr, uint64_t size);
+
 /*
  * Basic CPU control in CR0
  */
diff --git a/tools/testing/selftests/kvm/include/x86/vmx.h b/tools/testing/selftests/kvm/include/x86/vmx.h
index 4dd4c2094ee6..92b918700d24 100644
--- a/tools/testing/selftests/kvm/include/x86/vmx.h
+++ b/tools/testing/selftests/kvm/include/x86/vmx.h
@@ -557,9 +557,6 @@ bool load_vmcs(struct vmx_pages *vmx);
 
 bool ept_1g_pages_supported(void);
 
-void tdp_map(struct kvm_vm *vm, uint64_t nested_paddr, uint64_t paddr, uint64_t size);
-void tdp_identity_map_default_memslots(struct kvm_vm *vm);
-void tdp_identity_map_1g(struct kvm_vm *vm,  uint64_t addr, uint64_t size);
 bool kvm_cpu_has_ept(void);
 void vm_enable_ept(struct kvm_vm *vm);
 void prepare_virtualize_apic_accesses(struct vmx_pages *vmx, struct kvm_vm *vm);
diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
index 41316cac94e0..29e7d172f945 100644
--- a/tools/testing/selftests/kvm/lib/x86/processor.c
+++ b/tools/testing/selftests/kvm/lib/x86/processor.c
@@ -472,6 +472,59 @@ void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
 	}
 }
 
+void __tdp_map(struct kvm_vm *vm, uint64_t nested_paddr, uint64_t paddr,
+	       uint64_t size, int level)
+{
+	size_t page_size = PG_LEVEL_SIZE(level);
+	size_t npages = size / page_size;
+
+	TEST_ASSERT(nested_paddr + size > nested_paddr, "Vaddr overflow");
+	TEST_ASSERT(paddr + size > paddr, "Paddr overflow");
+
+	while (npages--) {
+		__virt_pg_map(vm, &vm->stage2_mmu, nested_paddr, paddr, level);
+		nested_paddr += page_size;
+		paddr += page_size;
+	}
+}
+
+void tdp_map(struct kvm_vm *vm, uint64_t nested_paddr, uint64_t paddr,
+	     uint64_t size)
+{
+	__tdp_map(vm, nested_paddr, paddr, size, PG_LEVEL_4K);
+}
+
+/* Prepare an identity extended page table that maps all the
+ * physical pages in VM.
+ */
+void tdp_identity_map_default_memslots(struct kvm_vm *vm)
+{
+	uint32_t s, memslot = 0;
+	sparsebit_idx_t i, last;
+	struct userspace_mem_region *region = memslot2region(vm, memslot);
+
+	/* Only memslot 0 is mapped here, ensure it's the only one being used */
+	for (s = 0; s < NR_MEM_REGIONS; s++)
+		TEST_ASSERT_EQ(vm->memslots[s], 0);
+
+	i = (region->region.guest_phys_addr >> vm->page_shift) - 1;
+	last = i + (region->region.memory_size >> vm->page_shift);
+	for (;;) {
+		i = sparsebit_next_clear(region->unused_phy_pages, i);
+		if (i > last)
+			break;
+
+		tdp_map(vm, (uint64_t)i << vm->page_shift,
+			(uint64_t)i << vm->page_shift, 1 << vm->page_shift);
+	}
+}
+
+/* Identity map a region with 1GiB Pages. */
+void tdp_identity_map_1g(struct kvm_vm *vm, uint64_t addr, uint64_t size)
+{
+	__tdp_map(vm, addr, addr, size, PG_LEVEL_1G);
+}
+
 /*
  * Set Unusable Segment
  *
diff --git a/tools/testing/selftests/kvm/lib/x86/vmx.c b/tools/testing/selftests/kvm/lib/x86/vmx.c
index e3737b3d9120..448a63457467 100644
--- a/tools/testing/selftests/kvm/lib/x86/vmx.c
+++ b/tools/testing/selftests/kvm/lib/x86/vmx.c
@@ -373,77 +373,6 @@ void prepare_vmcs(struct vmx_pages *vmx, void *guest_rip, void *guest_rsp)
 	init_vmcs_guest_state(guest_rip, guest_rsp);
 }
 
-/*
- * Map a range of EPT guest physical addresses to the VM's physical address
- *
- * Input Args:
- *   vm - Virtual Machine
- *   nested_paddr - Nested guest physical address to map
- *   paddr - VM Physical Address
- *   size - The size of the range to map
- *   level - The level at which to map the range
- *
- * Output Args: None
- *
- * Return: None
- *
- * Within the VM given by vm, creates a nested guest translation for the
- * page range starting at nested_paddr to the page range starting at paddr.
- */
-void __tdp_map(struct kvm_vm *vm, uint64_t nested_paddr, uint64_t paddr,
-	       uint64_t size, int level)
-{
-	struct kvm_mmu *mmu = &vm->stage2_mmu;
-	size_t page_size = PG_LEVEL_SIZE(level);
-	size_t npages = size / page_size;
-
-	TEST_ASSERT(nested_paddr + size > nested_paddr, "Vaddr overflow");
-	TEST_ASSERT(paddr + size > paddr, "Paddr overflow");
-
-	while (npages--) {
-		__virt_pg_map(vm, mmu, nested_paddr, paddr, level);
-		nested_paddr += page_size;
-		paddr += page_size;
-	}
-}
-
-void tdp_map(struct kvm_vm *vm, uint64_t nested_paddr, uint64_t paddr,
-	     uint64_t size)
-{
-	__tdp_map(vm, nested_paddr, paddr, size, PG_LEVEL_4K);
-}
-
-/* Prepare an identity extended page table that maps all the
- * physical pages in VM.
- */
-void tdp_identity_map_default_memslots(struct kvm_vm *vm)
-{
-	uint32_t s, memslot = 0;
-	sparsebit_idx_t i, last;
-	struct userspace_mem_region *region = memslot2region(vm, memslot);
-
-	/* Only memslot 0 is mapped here, ensure it's the only one being used */
-	for (s = 0; s < NR_MEM_REGIONS; s++)
-		TEST_ASSERT_EQ(vm->memslots[s], 0);
-
-	i = (region->region.guest_phys_addr >> vm->page_shift) - 1;
-	last = i + (region->region.memory_size >> vm->page_shift);
-	for (;;) {
-		i = sparsebit_next_clear(region->unused_phy_pages, i);
-		if (i > last)
-			break;
-
-		tdp_map(vm, (uint64_t)i << vm->page_shift,
-			(uint64_t)i << vm->page_shift, 1 << vm->page_shift);
-	}
-}
-
-/* Identity map a region with 1GiB Pages. */
-void tdp_identity_map_1g(struct kvm_vm *vm, uint64_t addr, uint64_t size)
-{
-	__tdp_map(vm, addr, addr, size, PG_LEVEL_1G);
-}
-
 bool kvm_cpu_has_ept(void)
 {
 	uint64_t ctrl;
-- 
2.52.0.351.gbe84eed79e-goog



From seanjc at google.com  Tue Dec 30 15:01:44 2025
From: seanjc at google.com (Sean Christopherson)
Date: Tue, 30 Dec 2025 15:01:44 -0800
Subject: [PATCH v4 15/21] KVM: selftests: Allow kvm_cpu_has_ept() to be called
 on AMD CPUs
In-Reply-To: <20251230230150.4150236-1-seanjc@google.com>
References: <20251230230150.4150236-1-seanjc@google.com>
Message-ID: <20251230230150.4150236-16-seanjc@google.com>

From: Yosry Ahmed <yosry.ahmed at linux.dev>

In preparation for generalizing the nested dirty logging test, checking
if either EPT or NPT is enabled will be needed. To avoid needing to gate
the kvm_cpu_has_ept() call by the CPU type, make sure the function
returns false if VMX is not available instead of trying to read VMX-only
MSRs.

No functional change intended.

Signed-off-by: Yosry Ahmed <yosry.ahmed at linux.dev>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 tools/testing/selftests/kvm/lib/x86/vmx.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/tools/testing/selftests/kvm/lib/x86/vmx.c b/tools/testing/selftests/kvm/lib/x86/vmx.c
index 448a63457467..c87b340362a9 100644
--- a/tools/testing/selftests/kvm/lib/x86/vmx.c
+++ b/tools/testing/selftests/kvm/lib/x86/vmx.c
@@ -377,6 +377,9 @@ bool kvm_cpu_has_ept(void)
 {
 	uint64_t ctrl;
 
+	if (!kvm_cpu_has(X86_FEATURE_VMX))
+		return false;
+
 	ctrl = kvm_get_feature_msr(MSR_IA32_VMX_TRUE_PROCBASED_CTLS) >> 32;
 	if (!(ctrl & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS))
 		return false;
-- 
2.52.0.351.gbe84eed79e-goog



From seanjc at google.com  Tue Dec 30 15:01:45 2025
From: seanjc at google.com (Sean Christopherson)
Date: Tue, 30 Dec 2025 15:01:45 -0800
Subject: [PATCH v4 16/21] KVM: selftests: Add support for nested NPTs
In-Reply-To: <20251230230150.4150236-1-seanjc@google.com>
References: <20251230230150.4150236-1-seanjc@google.com>
Message-ID: <20251230230150.4150236-17-seanjc@google.com>

From: Yosry Ahmed <yosry.ahmed at linux.dev>

Implement nCR3 and NPT initialization functions, similar to the EPT
equivalents, and create common TDP helpers for enablement checking and
initialization. Enable NPT for nested guests by default if the TDP MMU
was initialized, similar to VMX.

Reuse the PTE masks from the main MMU in the NPT MMU, except for the C
and S bits related to confidential VMs.

Signed-off-by: Yosry Ahmed <yosry.ahmed at linux.dev>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 .../selftests/kvm/include/x86/processor.h     |  2 ++
 .../selftests/kvm/include/x86/svm_util.h      |  9 ++++++++
 .../testing/selftests/kvm/lib/x86/memstress.c |  4 ++--
 .../testing/selftests/kvm/lib/x86/processor.c | 15 +++++++++++++
 tools/testing/selftests/kvm/lib/x86/svm.c     | 21 +++++++++++++++++++
 .../selftests/kvm/x86/vmx_dirty_log_test.c    |  4 ++--
 6 files changed, 51 insertions(+), 4 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h
index d134c886f280..deb471fb9b51 100644
--- a/tools/testing/selftests/kvm/include/x86/processor.h
+++ b/tools/testing/selftests/kvm/include/x86/processor.h
@@ -1477,6 +1477,8 @@ void __virt_pg_map(struct kvm_vm *vm, struct kvm_mmu *mmu, uint64_t vaddr,
 void virt_map_level(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
 		    uint64_t nr_bytes, int level);
 
+void vm_enable_tdp(struct kvm_vm *vm);
+bool kvm_cpu_has_tdp(void);
 void tdp_map(struct kvm_vm *vm, uint64_t nested_paddr, uint64_t paddr, uint64_t size);
 void tdp_identity_map_default_memslots(struct kvm_vm *vm);
 void tdp_identity_map_1g(struct kvm_vm *vm,  uint64_t addr, uint64_t size);
diff --git a/tools/testing/selftests/kvm/include/x86/svm_util.h b/tools/testing/selftests/kvm/include/x86/svm_util.h
index b74c6dcddcbd..5d7c42534bc4 100644
--- a/tools/testing/selftests/kvm/include/x86/svm_util.h
+++ b/tools/testing/selftests/kvm/include/x86/svm_util.h
@@ -27,6 +27,9 @@ struct svm_test_data {
 	void *msr; /* gva */
 	void *msr_hva;
 	uint64_t msr_gpa;
+
+	/* NPT */
+	uint64_t ncr3_gpa;
 };
 
 static inline void vmmcall(void)
@@ -57,6 +60,12 @@ struct svm_test_data *vcpu_alloc_svm(struct kvm_vm *vm, vm_vaddr_t *p_svm_gva);
 void generic_svm_setup(struct svm_test_data *svm, void *guest_rip, void *guest_rsp);
 void run_guest(struct vmcb *vmcb, uint64_t vmcb_gpa);
 
+static inline bool kvm_cpu_has_npt(void)
+{
+	return kvm_cpu_has(X86_FEATURE_NPT);
+}
+void vm_enable_npt(struct kvm_vm *vm);
+
 int open_sev_dev_path_or_exit(void);
 
 #endif /* SELFTEST_KVM_SVM_UTILS_H */
diff --git a/tools/testing/selftests/kvm/lib/x86/memstress.c b/tools/testing/selftests/kvm/lib/x86/memstress.c
index 3319cb57a78d..407abfc34909 100644
--- a/tools/testing/selftests/kvm/lib/x86/memstress.c
+++ b/tools/testing/selftests/kvm/lib/x86/memstress.c
@@ -82,9 +82,9 @@ void memstress_setup_nested(struct kvm_vm *vm, int nr_vcpus, struct kvm_vcpu *vc
 	int vcpu_id;
 
 	TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX));
-	TEST_REQUIRE(kvm_cpu_has_ept());
+	TEST_REQUIRE(kvm_cpu_has_tdp());
 
-	vm_enable_ept(vm);
+	vm_enable_tdp(vm);
 	for (vcpu_id = 0; vcpu_id < nr_vcpus; vcpu_id++) {
 		vcpu_alloc_vmx(vm, &vmx_gva);
 
diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
index 29e7d172f945..a3a4c9a4cbcb 100644
--- a/tools/testing/selftests/kvm/lib/x86/processor.c
+++ b/tools/testing/selftests/kvm/lib/x86/processor.c
@@ -8,7 +8,9 @@
 #include "kvm_util.h"
 #include "pmu.h"
 #include "processor.h"
+#include "svm_util.h"
 #include "sev.h"
+#include "vmx.h"
 
 #ifndef NUM_INTERRUPTS
 #define NUM_INTERRUPTS 256
@@ -472,6 +474,19 @@ void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
 	}
 }
 
+void vm_enable_tdp(struct kvm_vm *vm)
+{
+	if (kvm_cpu_has(X86_FEATURE_VMX))
+		vm_enable_ept(vm);
+	else
+		vm_enable_npt(vm);
+}
+
+bool kvm_cpu_has_tdp(void)
+{
+	return kvm_cpu_has_ept() || kvm_cpu_has_npt();
+}
+
 void __tdp_map(struct kvm_vm *vm, uint64_t nested_paddr, uint64_t paddr,
 	       uint64_t size, int level)
 {
diff --git a/tools/testing/selftests/kvm/lib/x86/svm.c b/tools/testing/selftests/kvm/lib/x86/svm.c
index d239c2097391..8e4795225595 100644
--- a/tools/testing/selftests/kvm/lib/x86/svm.c
+++ b/tools/testing/selftests/kvm/lib/x86/svm.c
@@ -59,6 +59,22 @@ static void vmcb_set_seg(struct vmcb_seg *seg, u16 selector,
 	seg->base = base;
 }
 
+void vm_enable_npt(struct kvm_vm *vm)
+{
+	struct pte_masks pte_masks;
+
+	TEST_ASSERT(kvm_cpu_has_npt(), "KVM doesn't supported nested NPT");
+
+	/*
+	 * NPTs use the same PTE format, but deliberately drop the C-bit as the
+	 * per-VM shared vs. private information is only meant for stage-1.
+	 */
+	pte_masks = vm->mmu.arch.pte_masks;
+	pte_masks.c = 0;
+
+	tdp_mmu_init(vm, vm->mmu.pgtable_levels, &pte_masks);
+}
+
 void generic_svm_setup(struct svm_test_data *svm, void *guest_rip, void *guest_rsp)
 {
 	struct vmcb *vmcb = svm->vmcb;
@@ -102,6 +118,11 @@ void generic_svm_setup(struct svm_test_data *svm, void *guest_rip, void *guest_r
 	vmcb->save.rip = (u64)guest_rip;
 	vmcb->save.rsp = (u64)guest_rsp;
 	guest_regs.rdi = (u64)svm;
+
+	if (svm->ncr3_gpa) {
+		ctrl->nested_ctl |= SVM_NESTED_CTL_NP_ENABLE;
+		ctrl->nested_cr3 = svm->ncr3_gpa;
+	}
 }
 
 /*
diff --git a/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c b/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c
index 370f8d3117c2..032ab8bf60a4 100644
--- a/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c
+++ b/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c
@@ -93,7 +93,7 @@ static void test_vmx_dirty_log(bool enable_ept)
 	/* Create VM */
 	vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code);
 	if (enable_ept)
-		vm_enable_ept(vm);
+		vm_enable_tdp(vm);
 
 	vcpu_alloc_vmx(vm, &vmx_pages_gva);
 	vcpu_args_set(vcpu, 1, vmx_pages_gva);
@@ -170,7 +170,7 @@ int main(int argc, char *argv[])
 
 	test_vmx_dirty_log(/*enable_ept=*/false);
 
-	if (kvm_cpu_has_ept())
+	if (kvm_cpu_has_tdp())
 		test_vmx_dirty_log(/*enable_ept=*/true);
 
 	return 0;
-- 
2.52.0.351.gbe84eed79e-goog



From seanjc at google.com  Tue Dec 30 15:01:46 2025
From: seanjc at google.com (Sean Christopherson)
Date: Tue, 30 Dec 2025 15:01:46 -0800
Subject: [PATCH v4 17/21] KVM: selftests: Set the user bit on nested NPT PTEs
In-Reply-To: <20251230230150.4150236-1-seanjc@google.com>
References: <20251230230150.4150236-1-seanjc@google.com>
Message-ID: <20251230230150.4150236-18-seanjc@google.com>

From: Yosry Ahmed <yosry.ahmed at linux.dev>

According to the APM, NPT walks are treated as user accesses. In
preparation for supporting NPT mappings, set the 'user' bit on NPTs by
adding a mask of bits to always be set on PTEs in kvm_mmu.

Signed-off-by: Yosry Ahmed <yosry.ahmed at linux.dev>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 tools/testing/selftests/kvm/include/x86/kvm_util_arch.h | 2 ++
 tools/testing/selftests/kvm/include/x86/processor.h     | 1 +
 tools/testing/selftests/kvm/lib/x86/processor.c         | 5 +++--
 tools/testing/selftests/kvm/lib/x86/svm.c               | 3 +++
 4 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h b/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h
index 1cf84b8212c6..be35d26bb320 100644
--- a/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h
+++ b/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h
@@ -22,6 +22,8 @@ struct pte_masks {
 	uint64_t nx;
 	uint64_t c;
 	uint64_t s;
+
+	uint64_t always_set;
 };
 
 struct kvm_mmu_arch {
diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h
index deb471fb9b51..7b7d962244d6 100644
--- a/tools/testing/selftests/kvm/include/x86/processor.h
+++ b/tools/testing/selftests/kvm/include/x86/processor.h
@@ -1450,6 +1450,7 @@ enum pg_level {
 #define PTE_NX_MASK(mmu)		((mmu)->arch.pte_masks.nx)
 #define PTE_C_BIT_MASK(mmu)		((mmu)->arch.pte_masks.c)
 #define PTE_S_BIT_MASK(mmu)		((mmu)->arch.pte_masks.s)
+#define PTE_ALWAYS_SET_MASK(mmu)	((mmu)->arch.pte_masks.always_set)
 
 /*
  * For PTEs without a PRESENT bit (i.e. EPT entries), treat the PTE as present
diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
index a3a4c9a4cbcb..5a3385d48902 100644
--- a/tools/testing/selftests/kvm/lib/x86/processor.c
+++ b/tools/testing/selftests/kvm/lib/x86/processor.c
@@ -231,7 +231,8 @@ static uint64_t *virt_create_upper_pte(struct kvm_vm *vm,
 
 	if (!is_present_pte(mmu, pte)) {
 		*pte = PTE_PRESENT_MASK(mmu) | PTE_READABLE_MASK(mmu) |
-		       PTE_WRITABLE_MASK(mmu) | PTE_EXECUTABLE_MASK(mmu);
+		       PTE_WRITABLE_MASK(mmu) | PTE_EXECUTABLE_MASK(mmu) |
+		       PTE_ALWAYS_SET_MASK(mmu);
 		if (current_level == target_level)
 			*pte |= PTE_HUGE_MASK(mmu) | (paddr & PHYSICAL_PAGE_MASK);
 		else
@@ -299,7 +300,7 @@ void __virt_pg_map(struct kvm_vm *vm, struct kvm_mmu *mmu, uint64_t vaddr,
 		    "PTE already present for 4k page at vaddr: 0x%lx", vaddr);
 	*pte = PTE_PRESENT_MASK(mmu) | PTE_READABLE_MASK(mmu) |
 	       PTE_WRITABLE_MASK(mmu) | PTE_EXECUTABLE_MASK(mmu) |
-	       (paddr & PHYSICAL_PAGE_MASK);
+	       PTE_ALWAYS_SET_MASK(mmu) | (paddr & PHYSICAL_PAGE_MASK);
 
 	/*
 	 * Neither SEV nor TDX supports shared page tables, so only the final
diff --git a/tools/testing/selftests/kvm/lib/x86/svm.c b/tools/testing/selftests/kvm/lib/x86/svm.c
index 8e4795225595..18e9e9089643 100644
--- a/tools/testing/selftests/kvm/lib/x86/svm.c
+++ b/tools/testing/selftests/kvm/lib/x86/svm.c
@@ -72,6 +72,9 @@ void vm_enable_npt(struct kvm_vm *vm)
 	pte_masks = vm->mmu.arch.pte_masks;
 	pte_masks.c = 0;
 
+	/* NPT walks are treated as user accesses, so set the 'user' bit. */
+	pte_masks.always_set = pte_masks.user;
+
 	tdp_mmu_init(vm, vm->mmu.pgtable_levels, &pte_masks);
 }
 
-- 
2.52.0.351.gbe84eed79e-goog



From seanjc at google.com  Tue Dec 30 15:01:47 2025
From: seanjc at google.com (Sean Christopherson)
Date: Tue, 30 Dec 2025 15:01:47 -0800
Subject: [PATCH v4 18/21] KVM: selftests: Extend vmx_dirty_log_test to cover SVM
In-Reply-To: <20251230230150.4150236-1-seanjc@google.com>
References: <20251230230150.4150236-1-seanjc@google.com>
Message-ID: <20251230230150.4150236-19-seanjc@google.com>

From: Yosry Ahmed <yosry.ahmed at linux.dev>

Generalize the code in vmx_dirty_log_test.c by adding SVM-specific L1
code, doing some renaming (e.g. EPT -> TDP), and having setup code for
both SVM and VMX in test_dirty_log().

Signed-off-by: Yosry Ahmed <yosry.ahmed at linux.dev>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 tools/testing/selftests/kvm/Makefile.kvm      |  2 +-
 ...rty_log_test.c => nested_dirty_log_test.c} | 73 ++++++++++++++-----
 2 files changed, 54 insertions(+), 21 deletions(-)
 rename tools/testing/selftests/kvm/x86/{vmx_dirty_log_test.c => nested_dirty_log_test.c} (71%)

diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index ba5c2b643efa..8f14213ddef1 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -89,6 +89,7 @@ TEST_GEN_PROGS_x86 += x86/kvm_buslock_test
 TEST_GEN_PROGS_x86 += x86/monitor_mwait_test
 TEST_GEN_PROGS_x86 += x86/msrs_test
 TEST_GEN_PROGS_x86 += x86/nested_close_kvm_test
+TEST_GEN_PROGS_x86 += x86/nested_dirty_log_test
 TEST_GEN_PROGS_x86 += x86/nested_emulation_test
 TEST_GEN_PROGS_x86 += x86/nested_exceptions_test
 TEST_GEN_PROGS_x86 += x86/nested_invalid_cr3_test
@@ -115,7 +116,6 @@ TEST_GEN_PROGS_x86 += x86/ucna_injection_test
 TEST_GEN_PROGS_x86 += x86/userspace_io_test
 TEST_GEN_PROGS_x86 += x86/userspace_msr_exit_test
 TEST_GEN_PROGS_x86 += x86/vmx_apic_access_test
-TEST_GEN_PROGS_x86 += x86/vmx_dirty_log_test
 TEST_GEN_PROGS_x86 += x86/vmx_exception_with_invalid_guest_state
 TEST_GEN_PROGS_x86 += x86/vmx_msrs_test
 TEST_GEN_PROGS_x86 += x86/vmx_invalid_nested_guest_state
diff --git a/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c b/tools/testing/selftests/kvm/x86/nested_dirty_log_test.c
similarity index 71%
rename from tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c
rename to tools/testing/selftests/kvm/x86/nested_dirty_log_test.c
index 032ab8bf60a4..89d2e86a0db9 100644
--- a/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c
+++ b/tools/testing/selftests/kvm/x86/nested_dirty_log_test.c
@@ -12,6 +12,7 @@
 #include "test_util.h"
 #include "kvm_util.h"
 #include "processor.h"
+#include "svm_util.h"
 #include "vmx.h"
 
 /* The memory slot index to track dirty pages */
@@ -25,6 +26,8 @@
 #define NESTED_TEST_MEM1		0xc0001000
 #define NESTED_TEST_MEM2		0xc0002000
 
+#define L2_GUEST_STACK_SIZE 64
+
 static void l2_guest_code(u64 *a, u64 *b)
 {
 	READ_ONCE(*a);
@@ -42,20 +45,19 @@ static void l2_guest_code(u64 *a, u64 *b)
 	vmcall();
 }
 
-static void l2_guest_code_ept_enabled(void)
+static void l2_guest_code_tdp_enabled(void)
 {
 	l2_guest_code((u64 *)NESTED_TEST_MEM1, (u64 *)NESTED_TEST_MEM2);
 }
 
-static void l2_guest_code_ept_disabled(void)
+static void l2_guest_code_tdp_disabled(void)
 {
-	/* Access the same L1 GPAs as l2_guest_code_ept_enabled() */
+	/* Access the same L1 GPAs as l2_guest_code_tdp_enabled() */
 	l2_guest_code((u64 *)GUEST_TEST_MEM, (u64 *)GUEST_TEST_MEM);
 }
 
-void l1_guest_code(struct vmx_pages *vmx)
+void l1_vmx_code(struct vmx_pages *vmx)
 {
-#define L2_GUEST_STACK_SIZE 64
 	unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
 	void *l2_rip;
 
@@ -64,22 +66,49 @@ void l1_guest_code(struct vmx_pages *vmx)
 	GUEST_ASSERT(load_vmcs(vmx));
 
 	if (vmx->eptp_gpa)
-		l2_rip = l2_guest_code_ept_enabled;
+		l2_rip = l2_guest_code_tdp_enabled;
 	else
-		l2_rip = l2_guest_code_ept_disabled;
+		l2_rip = l2_guest_code_tdp_disabled;
 
 	prepare_vmcs(vmx, l2_rip, &l2_guest_stack[L2_GUEST_STACK_SIZE]);
 
 	GUEST_SYNC(false);
 	GUEST_ASSERT(!vmlaunch());
 	GUEST_SYNC(false);
-	GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL);
+	GUEST_ASSERT_EQ(vmreadz(VM_EXIT_REASON), EXIT_REASON_VMCALL);
 	GUEST_DONE();
 }
 
-static void test_vmx_dirty_log(bool enable_ept)
+static void l1_svm_code(struct svm_test_data *svm)
 {
-	vm_vaddr_t vmx_pages_gva = 0;
+	unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
+	void *l2_rip;
+
+	if (svm->ncr3_gpa)
+		l2_rip = l2_guest_code_tdp_enabled;
+	else
+		l2_rip = l2_guest_code_tdp_disabled;
+
+	generic_svm_setup(svm, l2_rip, &l2_guest_stack[L2_GUEST_STACK_SIZE]);
+
+	GUEST_SYNC(false);
+	run_guest(svm->vmcb, svm->vmcb_gpa);
+	GUEST_SYNC(false);
+	GUEST_ASSERT_EQ(svm->vmcb->control.exit_code, SVM_EXIT_VMMCALL);
+	GUEST_DONE();
+}
+
+static void l1_guest_code(void *data)
+{
+	if (this_cpu_has(X86_FEATURE_VMX))
+		l1_vmx_code(data);
+	else
+		l1_svm_code(data);
+}
+
+static void test_dirty_log(bool nested_tdp)
+{
+	vm_vaddr_t nested_gva = 0;
 	unsigned long *bmap;
 	uint64_t *host_test_mem;
 
@@ -88,15 +117,19 @@ static void test_vmx_dirty_log(bool enable_ept)
 	struct ucall uc;
 	bool done = false;
 
-	pr_info("Nested EPT: %s\n", enable_ept ? "enabled" : "disabled");
+	pr_info("Nested TDP: %s\n", nested_tdp ? "enabled" : "disabled");
 
 	/* Create VM */
 	vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code);
-	if (enable_ept)
+	if (nested_tdp)
 		vm_enable_tdp(vm);
 
-	vcpu_alloc_vmx(vm, &vmx_pages_gva);
-	vcpu_args_set(vcpu, 1, vmx_pages_gva);
+	if (kvm_cpu_has(X86_FEATURE_VMX))
+		vcpu_alloc_vmx(vm, &nested_gva);
+	else
+		vcpu_alloc_svm(vm, &nested_gva);
+
+	vcpu_args_set(vcpu, 1, nested_gva);
 
 	/* Add an extra memory slot for testing dirty logging */
 	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
@@ -115,10 +148,10 @@ static void test_vmx_dirty_log(bool enable_ept)
 	 * ... pages in the L2 GPA range [0xc0001000, 0xc0003000) will map to
 	 * 0xc0000000.
 	 *
-	 * When EPT is disabled, the L2 guest code will still access the same L1
-	 * GPAs as the EPT enabled case.
+	 * When TDP is disabled, the L2 guest code will still access the same L1
+	 * GPAs as the TDP enabled case.
 	 */
-	if (enable_ept) {
+	if (nested_tdp) {
 		tdp_identity_map_default_memslots(vm);
 		tdp_map(vm, NESTED_TEST_MEM1, GUEST_TEST_MEM, PAGE_SIZE);
 		tdp_map(vm, NESTED_TEST_MEM2, GUEST_TEST_MEM, PAGE_SIZE);
@@ -166,12 +199,12 @@ static void test_vmx_dirty_log(bool enable_ept)
 
 int main(int argc, char *argv[])
 {
-	TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX));
+	TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX) || kvm_cpu_has(X86_FEATURE_SVM));
 
-	test_vmx_dirty_log(/*enable_ept=*/false);
+	test_dirty_log(/*nested_tdp=*/false);
 
 	if (kvm_cpu_has_tdp())
-		test_vmx_dirty_log(/*enable_ept=*/true);
+		test_dirty_log(/*nested_tdp=*/true);
 
 	return 0;
 }
-- 
2.52.0.351.gbe84eed79e-goog



From seanjc at google.com  Tue Dec 30 15:01:48 2025
From: seanjc at google.com (Sean Christopherson)
Date: Tue, 30 Dec 2025 15:01:48 -0800
Subject: [PATCH v4 19/21] KVM: selftests: Extend memstress to run on nested SVM
In-Reply-To: <20251230230150.4150236-1-seanjc@google.com>
References: <20251230230150.4150236-1-seanjc@google.com>
Message-ID: <20251230230150.4150236-20-seanjc@google.com>

From: Yosry Ahmed <yosry.ahmed at linux.dev>

Add L1 SVM code and generalize the setup code to work for both VMX and
SVM. This allows running 'dirty_log_perf_test -n' on AMD CPUs.

Signed-off-by: Yosry Ahmed <yosry.ahmed at linux.dev>
Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 .../testing/selftests/kvm/lib/x86/memstress.c | 42 +++++++++++++++----
 1 file changed, 35 insertions(+), 7 deletions(-)

diff --git a/tools/testing/selftests/kvm/lib/x86/memstress.c b/tools/testing/selftests/kvm/lib/x86/memstress.c
index 407abfc34909..86f4c5e4c430 100644
--- a/tools/testing/selftests/kvm/lib/x86/memstress.c
+++ b/tools/testing/selftests/kvm/lib/x86/memstress.c
@@ -13,6 +13,7 @@
 #include "kvm_util.h"
 #include "memstress.h"
 #include "processor.h"
+#include "svm_util.h"
 #include "vmx.h"
 
 void memstress_l2_guest_code(uint64_t vcpu_id)
@@ -29,9 +30,10 @@ __asm__(
 "	ud2;"
 );
 
-static void memstress_l1_guest_code(struct vmx_pages *vmx, uint64_t vcpu_id)
-{
 #define L2_GUEST_STACK_SIZE 64
+
+static void l1_vmx_code(struct vmx_pages *vmx, uint64_t vcpu_id)
+{
 	unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
 	unsigned long *rsp;
 
@@ -45,10 +47,34 @@ static void memstress_l1_guest_code(struct vmx_pages *vmx, uint64_t vcpu_id)
 	prepare_vmcs(vmx, memstress_l2_guest_entry, rsp);
 
 	GUEST_ASSERT(!vmlaunch());
-	GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL);
+	GUEST_ASSERT_EQ(vmreadz(VM_EXIT_REASON), EXIT_REASON_VMCALL);
 	GUEST_DONE();
 }
 
+static void l1_svm_code(struct svm_test_data *svm, uint64_t vcpu_id)
+{
+	unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
+	unsigned long *rsp;
+
+
+	rsp = &l2_guest_stack[L2_GUEST_STACK_SIZE - 1];
+	*rsp = vcpu_id;
+	generic_svm_setup(svm, memstress_l2_guest_entry, rsp);
+
+	run_guest(svm->vmcb, svm->vmcb_gpa);
+	GUEST_ASSERT_EQ(svm->vmcb->control.exit_code, SVM_EXIT_VMMCALL);
+	GUEST_DONE();
+}
+
+
+static void memstress_l1_guest_code(void *data, uint64_t vcpu_id)
+{
+	if (this_cpu_has(X86_FEATURE_VMX))
+		l1_vmx_code(data, vcpu_id);
+	else
+		l1_svm_code(data, vcpu_id);
+}
+
 uint64_t memstress_nested_pages(int nr_vcpus)
 {
 	/*
@@ -78,15 +104,17 @@ static void memstress_setup_ept_mappings(struct kvm_vm *vm)
 void memstress_setup_nested(struct kvm_vm *vm, int nr_vcpus, struct kvm_vcpu *vcpus[])
 {
 	struct kvm_regs regs;
-	vm_vaddr_t vmx_gva;
+	vm_vaddr_t nested_gva;
 	int vcpu_id;
 
-	TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX));
 	TEST_REQUIRE(kvm_cpu_has_tdp());
 
 	vm_enable_tdp(vm);
 	for (vcpu_id = 0; vcpu_id < nr_vcpus; vcpu_id++) {
-		vcpu_alloc_vmx(vm, &vmx_gva);
+		if (kvm_cpu_has(X86_FEATURE_VMX))
+			vcpu_alloc_vmx(vm, &nested_gva);
+		else
+			vcpu_alloc_svm(vm, &nested_gva);
 
 		/* The EPTs are shared across vCPUs, setup the mappings once */
 		if (vcpu_id == 0)
@@ -99,6 +127,6 @@ void memstress_setup_nested(struct kvm_vm *vm, int nr_vcpus, struct kvm_vcpu *vc
 		vcpu_regs_get(vcpus[vcpu_id], &regs);
 		regs.rip = (unsigned long) memstress_l1_guest_code;
 		vcpu_regs_set(vcpus[vcpu_id], &regs);
-		vcpu_args_set(vcpus[vcpu_id], 2, vmx_gva, vcpu_id);
+		vcpu_args_set(vcpus[vcpu_id], 2, nested_gva, vcpu_id);
 	}
 }
-- 
2.52.0.351.gbe84eed79e-goog



From seanjc at google.com  Tue Dec 30 15:01:49 2025
From: seanjc at google.com (Sean Christopherson)
Date: Tue, 30 Dec 2025 15:01:49 -0800
Subject: [PATCH v4 20/21] KVM: selftests: Rename vm_get_page_table_entry() to vm_get_pte()
In-Reply-To: <20251230230150.4150236-1-seanjc@google.com>
References: <20251230230150.4150236-1-seanjc@google.com>
Message-ID: <20251230230150.4150236-21-seanjc@google.com>

Shorten the API to get a PTE as the "PTE" acronym is ubiquitous, and the
"page table entry" makes it unnecessarily difficult to quickly understand
what callers are doing.

No functional change intended.

Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 tools/testing/selftests/kvm/include/x86/processor.h           | 2 +-
 tools/testing/selftests/kvm/lib/x86/processor.c               | 2 +-
 tools/testing/selftests/kvm/x86/hyperv_tlb_flush.c            | 2 +-
 .../selftests/kvm/x86/smaller_maxphyaddr_emulation_test.c     | 4 +---
 4 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h
index 7b7d962244d6..ab29b1c7ed2d 100644
--- a/tools/testing/selftests/kvm/include/x86/processor.h
+++ b/tools/testing/selftests/kvm/include/x86/processor.h
@@ -1357,7 +1357,7 @@ static inline bool kvm_is_ignore_msrs(void)
 	return get_kvm_param_bool("ignore_msrs");
 }
 
-uint64_t *vm_get_page_table_entry(struct kvm_vm *vm, uint64_t vaddr);
+uint64_t *vm_get_pte(struct kvm_vm *vm, uint64_t vaddr);
 
 uint64_t kvm_hypercall(uint64_t nr, uint64_t a0, uint64_t a1, uint64_t a2,
 		       uint64_t a3);
diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
index 5a3385d48902..ab869a98bbdc 100644
--- a/tools/testing/selftests/kvm/lib/x86/processor.c
+++ b/tools/testing/selftests/kvm/lib/x86/processor.c
@@ -390,7 +390,7 @@ static uint64_t *__vm_get_page_table_entry(struct kvm_vm *vm,
 	return virt_get_pte(vm, mmu, pte, vaddr, PG_LEVEL_4K);
 }
 
-uint64_t *vm_get_page_table_entry(struct kvm_vm *vm, uint64_t vaddr)
+uint64_t *vm_get_pte(struct kvm_vm *vm, uint64_t vaddr)
 {
 	int level = PG_LEVEL_4K;
 
diff --git a/tools/testing/selftests/kvm/x86/hyperv_tlb_flush.c b/tools/testing/selftests/kvm/x86/hyperv_tlb_flush.c
index a3b7ce155981..c542cc4762b1 100644
--- a/tools/testing/selftests/kvm/x86/hyperv_tlb_flush.c
+++ b/tools/testing/selftests/kvm/x86/hyperv_tlb_flush.c
@@ -619,7 +619,7 @@ int main(int argc, char *argv[])
 	 */
 	gva = vm_vaddr_unused_gap(vm, NTEST_PAGES * PAGE_SIZE, KVM_UTIL_MIN_VADDR);
 	for (i = 0; i < NTEST_PAGES; i++) {
-		pte = vm_get_page_table_entry(vm, data->test_pages + i * PAGE_SIZE);
+		pte = vm_get_pte(vm, data->test_pages + i * PAGE_SIZE);
 		gpa = addr_hva2gpa(vm, pte);
 		virt_pg_map(vm, gva + PAGE_SIZE * i, gpa & PAGE_MASK);
 		data->test_pages_pte[i] = gva + (gpa & ~PAGE_MASK);
diff --git a/tools/testing/selftests/kvm/x86/smaller_maxphyaddr_emulation_test.c b/tools/testing/selftests/kvm/x86/smaller_maxphyaddr_emulation_test.c
index fabeeaddfb3a..0e8aec568010 100644
--- a/tools/testing/selftests/kvm/x86/smaller_maxphyaddr_emulation_test.c
+++ b/tools/testing/selftests/kvm/x86/smaller_maxphyaddr_emulation_test.c
@@ -47,7 +47,6 @@ int main(int argc, char *argv[])
 	struct kvm_vcpu *vcpu;
 	struct kvm_vm *vm;
 	struct ucall uc;
-	uint64_t *pte;
 	uint64_t *hva;
 	uint64_t gpa;
 	int rc;
@@ -73,8 +72,7 @@ int main(int argc, char *argv[])
 	hva = addr_gpa2hva(vm, MEM_REGION_GPA);
 	memset(hva, 0, PAGE_SIZE);
 
-	pte = vm_get_page_table_entry(vm, MEM_REGION_GVA);
-	*pte |= BIT_ULL(MAXPHYADDR);
+	*vm_get_pte(vm, MEM_REGION_GVA) |= BIT_ULL(MAXPHYADDR);
 
 	vcpu_run(vcpu);
 
-- 
2.52.0.351.gbe84eed79e-goog



From seanjc at google.com  Tue Dec 30 15:01:50 2025
From: seanjc at google.com (Sean Christopherson)
Date: Tue, 30 Dec 2025 15:01:50 -0800
Subject: [PATCH v4 21/21] KVM: selftests: Test READ=>WRITE dirty logging
 behavior for shadow MMU
In-Reply-To: <20251230230150.4150236-1-seanjc@google.com>
References: <20251230230150.4150236-1-seanjc@google.com>
Message-ID: <20251230230150.4150236-22-seanjc@google.com>

Update the nested dirty log test to validate KVM's handling of READ faults
when dirty logging is enabled.  Specifically, set the Dirty bit in the
guest PTEs used to map L2 GPAs, so that KVM will create writable SPTEs
when handling L2 read faults.  When handling read faults in the shadow MMU,
KVM opportunistically creates a writable SPTE if the mapping can be
writable *and* the gPTE is dirty (or doesn't support the Dirty bit), i.e.
if KVM doesn't need to intercept writes in order to emulate Dirty-bit
updates.

To actually test the L2 READ=>WRITE sequence, e.g. without masking a false
pass by other test activity, route the READ=>WRITE and WRITE=>WRITE
sequences to separate L1 pages, and differentiate between "marked dirty
due to a WRITE access/fault" and "marked dirty due to creating a writable
SPTE for a READ access/fault".  The updated sequence exposes the bug fixed
by KVM commit 1f4e5fc83a42 ("KVM: x86: fix nested guest live migration
with PML") when the guest performs a READ=>WRITE sequence.

Signed-off-by: Sean Christopherson <seanjc at google.com>
---
 .../selftests/kvm/include/x86/processor.h     |   1 +
 .../testing/selftests/kvm/lib/x86/processor.c |   7 ++
 .../selftests/kvm/x86/nested_dirty_log_test.c | 115 +++++++++++++-----
 3 files changed, 90 insertions(+), 33 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h
index ab29b1c7ed2d..8945c9eea704 100644
--- a/tools/testing/selftests/kvm/include/x86/processor.h
+++ b/tools/testing/selftests/kvm/include/x86/processor.h
@@ -1483,6 +1483,7 @@ bool kvm_cpu_has_tdp(void);
 void tdp_map(struct kvm_vm *vm, uint64_t nested_paddr, uint64_t paddr, uint64_t size);
 void tdp_identity_map_default_memslots(struct kvm_vm *vm);
 void tdp_identity_map_1g(struct kvm_vm *vm,  uint64_t addr, uint64_t size);
+uint64_t *tdp_get_pte(struct kvm_vm *vm, uint64_t l2_gpa);
 
 /*
  * Basic CPU control in CR0
diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
index ab869a98bbdc..fab18e9be66c 100644
--- a/tools/testing/selftests/kvm/lib/x86/processor.c
+++ b/tools/testing/selftests/kvm/lib/x86/processor.c
@@ -390,6 +390,13 @@ static uint64_t *__vm_get_page_table_entry(struct kvm_vm *vm,
 	return virt_get_pte(vm, mmu, pte, vaddr, PG_LEVEL_4K);
 }
 
+uint64_t *tdp_get_pte(struct kvm_vm *vm, uint64_t l2_gpa)
+{
+	int level = PG_LEVEL_4K;
+
+	return __vm_get_page_table_entry(vm, &vm->stage2_mmu, l2_gpa, &level);
+}
+
 uint64_t *vm_get_pte(struct kvm_vm *vm, uint64_t vaddr)
 {
 	int level = PG_LEVEL_4K;
diff --git a/tools/testing/selftests/kvm/x86/nested_dirty_log_test.c b/tools/testing/selftests/kvm/x86/nested_dirty_log_test.c
index 89d2e86a0db9..1e7c1ed917e1 100644
--- a/tools/testing/selftests/kvm/x86/nested_dirty_log_test.c
+++ b/tools/testing/selftests/kvm/x86/nested_dirty_log_test.c
@@ -17,29 +17,39 @@
 
 /* The memory slot index to track dirty pages */
 #define TEST_MEM_SLOT_INDEX		1
-#define TEST_MEM_PAGES			3
+#define TEST_MEM_PAGES			4
 
 /* L1 guest test virtual memory offset */
-#define GUEST_TEST_MEM			0xc0000000
+#define GUEST_TEST_MEM1			0xc0000000
+#define GUEST_TEST_MEM2			0xc0002000
 
 /* L2 guest test virtual memory offset */
 #define NESTED_TEST_MEM1		0xc0001000
-#define NESTED_TEST_MEM2		0xc0002000
+#define NESTED_TEST_MEM2		0xc0003000
 
 #define L2_GUEST_STACK_SIZE 64
 
+#define TEST_SYNC_PAGE_MASK	0xfull
+#define TEST_SYNC_READ_FAULT	BIT(4)
+#define TEST_SYNC_WRITE_FAULT	BIT(5)
+#define TEST_SYNC_NO_FAULT	BIT(6)
+
 static void l2_guest_code(u64 *a, u64 *b)
 {
 	READ_ONCE(*a);
+	GUEST_SYNC(0 | TEST_SYNC_READ_FAULT);
 	WRITE_ONCE(*a, 1);
-	GUEST_SYNC(true);
-	GUEST_SYNC(false);
+	GUEST_SYNC(0 | TEST_SYNC_WRITE_FAULT);
+	READ_ONCE(*a);
+	GUEST_SYNC(0 | TEST_SYNC_NO_FAULT);
 
 	WRITE_ONCE(*b, 1);
-	GUEST_SYNC(true);
+	GUEST_SYNC(2 | TEST_SYNC_WRITE_FAULT);
 	WRITE_ONCE(*b, 1);
-	GUEST_SYNC(true);
-	GUEST_SYNC(false);
+	GUEST_SYNC(2 | TEST_SYNC_WRITE_FAULT);
+	READ_ONCE(*b);
+	GUEST_SYNC(2 | TEST_SYNC_NO_FAULT);
+	GUEST_SYNC(2 | TEST_SYNC_NO_FAULT);
 
 	/* Exit to L1 and never come back.  */
 	vmcall();
@@ -53,7 +63,7 @@ static void l2_guest_code_tdp_enabled(void)
 static void l2_guest_code_tdp_disabled(void)
 {
 	/* Access the same L1 GPAs as l2_guest_code_tdp_enabled() */
-	l2_guest_code((u64 *)GUEST_TEST_MEM, (u64 *)GUEST_TEST_MEM);
+	l2_guest_code((u64 *)GUEST_TEST_MEM1, (u64 *)GUEST_TEST_MEM2);
 }
 
 void l1_vmx_code(struct vmx_pages *vmx)
@@ -72,9 +82,11 @@ void l1_vmx_code(struct vmx_pages *vmx)
 
 	prepare_vmcs(vmx, l2_rip, &l2_guest_stack[L2_GUEST_STACK_SIZE]);
 
-	GUEST_SYNC(false);
+	GUEST_SYNC(0 | TEST_SYNC_NO_FAULT);
+	GUEST_SYNC(2 | TEST_SYNC_NO_FAULT);
 	GUEST_ASSERT(!vmlaunch());
-	GUEST_SYNC(false);
+	GUEST_SYNC(0 | TEST_SYNC_NO_FAULT);
+	GUEST_SYNC(2 | TEST_SYNC_NO_FAULT);
 	GUEST_ASSERT_EQ(vmreadz(VM_EXIT_REASON), EXIT_REASON_VMCALL);
 	GUEST_DONE();
 }
@@ -91,9 +103,11 @@ static void l1_svm_code(struct svm_test_data *svm)
 
 	generic_svm_setup(svm, l2_rip, &l2_guest_stack[L2_GUEST_STACK_SIZE]);
 
-	GUEST_SYNC(false);
+	GUEST_SYNC(0 | TEST_SYNC_NO_FAULT);
+	GUEST_SYNC(2 | TEST_SYNC_NO_FAULT);
 	run_guest(svm->vmcb, svm->vmcb_gpa);
-	GUEST_SYNC(false);
+	GUEST_SYNC(0 | TEST_SYNC_NO_FAULT);
+	GUEST_SYNC(2 | TEST_SYNC_NO_FAULT);
 	GUEST_ASSERT_EQ(svm->vmcb->control.exit_code, SVM_EXIT_VMMCALL);
 	GUEST_DONE();
 }
@@ -106,6 +120,11 @@ static void l1_guest_code(void *data)
 		l1_svm_code(data);
 }
 
+static uint64_t test_read_host_page(uint64_t *host_test_mem, int page_nr)
+{
+	return host_test_mem[PAGE_SIZE * page_nr / sizeof(*host_test_mem)];
+}
+
 static void test_dirty_log(bool nested_tdp)
 {
 	vm_vaddr_t nested_gva = 0;
@@ -133,32 +152,45 @@ static void test_dirty_log(bool nested_tdp)
 
 	/* Add an extra memory slot for testing dirty logging */
 	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
-				    GUEST_TEST_MEM,
+				    GUEST_TEST_MEM1,
 				    TEST_MEM_SLOT_INDEX,
 				    TEST_MEM_PAGES,
 				    KVM_MEM_LOG_DIRTY_PAGES);
 
 	/*
-	 * Add an identity map for GVA range [0xc0000000, 0xc0002000).  This
+	 * Add an identity map for GVA range [0xc0000000, 0xc0004000).  This
 	 * affects both L1 and L2.  However...
 	 */
-	virt_map(vm, GUEST_TEST_MEM, GUEST_TEST_MEM, TEST_MEM_PAGES);
+	virt_map(vm, GUEST_TEST_MEM1, GUEST_TEST_MEM1, TEST_MEM_PAGES);
 
 	/*
-	 * ... pages in the L2 GPA range [0xc0001000, 0xc0003000) will map to
-	 * 0xc0000000.
+	 * ... pages in the L2 GPA ranges [0xc0001000, 0xc0002000) and
+	 * [0xc0003000, 0xc0004000) will map to 0xc0000000 and 0xc0001000
+	 * respectively.
 	 *
 	 * When TDP is disabled, the L2 guest code will still access the same L1
 	 * GPAs as the TDP enabled case.
+	 *
+	 * Set the Dirty bit in the PTEs used by L2 so that KVM will create
+	 * writable SPTEs when handling read faults (if the Dirty bit isn't
+	 * set, KVM must intercept the next write to emulate the Dirty bit
+	 * update).
 	 */
 	if (nested_tdp) {
 		tdp_identity_map_default_memslots(vm);
-		tdp_map(vm, NESTED_TEST_MEM1, GUEST_TEST_MEM, PAGE_SIZE);
-		tdp_map(vm, NESTED_TEST_MEM2, GUEST_TEST_MEM, PAGE_SIZE);
+		tdp_map(vm, NESTED_TEST_MEM1, GUEST_TEST_MEM1, PAGE_SIZE);
+		tdp_map(vm, NESTED_TEST_MEM2, GUEST_TEST_MEM2, PAGE_SIZE);
+
+
+		*tdp_get_pte(vm, NESTED_TEST_MEM1) |= PTE_DIRTY_MASK(&vm->stage2_mmu);
+		*tdp_get_pte(vm, NESTED_TEST_MEM2) |= PTE_DIRTY_MASK(&vm->stage2_mmu);
+	} else {
+		*vm_get_pte(vm, GUEST_TEST_MEM1) |= PTE_DIRTY_MASK(&vm->mmu);
+		*vm_get_pte(vm, GUEST_TEST_MEM2) |= PTE_DIRTY_MASK(&vm->mmu);
 	}
 
 	bmap = bitmap_zalloc(TEST_MEM_PAGES);
-	host_test_mem = addr_gpa2hva(vm, GUEST_TEST_MEM);
+	host_test_mem = addr_gpa2hva(vm, GUEST_TEST_MEM1);
 
 	while (!done) {
 		memset(host_test_mem, 0xaa, TEST_MEM_PAGES * PAGE_SIZE);
@@ -169,25 +201,42 @@ static void test_dirty_log(bool nested_tdp)
 		case UCALL_ABORT:
 			REPORT_GUEST_ASSERT(uc);
 			/* NOT REACHED */
-		case UCALL_SYNC:
+		case UCALL_SYNC: {
+			int page_nr = uc.args[1] & TEST_SYNC_PAGE_MASK;
+			int i;
+
 			/*
 			 * The nested guest wrote at offset 0x1000 in the memslot, but the
 			 * dirty bitmap must be filled in according to L1 GPA, not L2.
 			 */
 			kvm_vm_get_dirty_log(vm, TEST_MEM_SLOT_INDEX, bmap);
-			if (uc.args[1]) {
-				TEST_ASSERT(test_bit(0, bmap), "Page 0 incorrectly reported clean");
-				TEST_ASSERT(host_test_mem[0] == 1, "Page 0 not written by guest");
-			} else {
-				TEST_ASSERT(!test_bit(0, bmap), "Page 0 incorrectly reported dirty");
-				TEST_ASSERT(host_test_mem[0] == 0xaaaaaaaaaaaaaaaaULL, "Page 0 written by guest");
+
+			/*
+			 * If a fault is expected, the page should be dirty
+			 * as the Dirty bit is set in the gPTE.  KVM should
+			 * create a writable SPTE even on a read fault, *and*
+			 * KVM must mark the GFN as dirty when doing so.
+			 */
+			TEST_ASSERT(test_bit(page_nr, bmap) == !(uc.args[1] & TEST_SYNC_NO_FAULT),
+				    "Page %u incorrectly reported %s on %s fault", page_nr,
+				    test_bit(page_nr, bmap) ? "dirty" : "clean",
+				    uc.args[1] & TEST_SYNC_NO_FAULT ? "no" :
+				    uc.args[1] & TEST_SYNC_READ_FAULT ? "read" : "write");
+
+			for (i = 0; i < TEST_MEM_PAGES; i++) {
+				if (i == page_nr && uc.args[1] & TEST_SYNC_WRITE_FAULT)
+					TEST_ASSERT(test_read_host_page(host_test_mem, i) == 1,
+						    "Page %u not written by guest", i);
+				else
+					TEST_ASSERT(test_read_host_page(host_test_mem, i) == 0xaaaaaaaaaaaaaaaaULL,
+						    "Page %u written by guest", i);
+
+				if (i != page_nr)
+					TEST_ASSERT(!test_bit(i, bmap),
+						    "Page %u incorrectly reported dirty", i);
 			}
-
-			TEST_ASSERT(!test_bit(1, bmap), "Page 1 incorrectly reported dirty");
-			TEST_ASSERT(host_test_mem[PAGE_SIZE / 8] == 0xaaaaaaaaaaaaaaaaULL, "Page 1 written by guest");
-			TEST_ASSERT(!test_bit(2, bmap), "Page 2 incorrectly reported dirty");
-			TEST_ASSERT(host_test_mem[PAGE_SIZE*2 / 8] == 0xaaaaaaaaaaaaaaaaULL, "Page 2 written by guest");
 			break;
+		}
 		case UCALL_DONE:
 			done = true;
 			break;
-- 
2.52.0.351.gbe84eed79e-goog



From vz at mleia.com  Tue Dec 30 15:36:02 2025
From: vz at mleia.com (Vladimir Zapolskiy)
Date: Wed, 31 Dec 2025 01:36:02 +0200
Subject: [PATCH 2/2] arm: dts: lpc32xx: add clocks property to Motor
 Control PWM device tree node
In-Reply-To: <20251230175933.GA864856-robh@kernel.org>
References: <20251228224907.1729627-1-vz@mleia.com>
 <20251228224907.1729627-3-vz@mleia.com>
 <20251230175933.GA864856-robh@kernel.org>
Message-ID: <9bb897bd-a7b1-442b-8931-dac9826de2c9@mleia.com>

On 12/30/25 19:59, Rob Herring wrote:
> On Mon, Dec 29, 2025 at 12:49:07AM +0200, Vladimir Zapolskiy wrote:
>> Motor Control PWM depends on its own supply clock, the clock gate control
>> is present in TIMCLK_CTRL1 register.
> 
> You say it is required, so does that mean this hasn't ever worked? Or it
> happened to work because something else turned on the clock?

There is no upstream driver for this particular PWM controller, I'm about to
submit one though, and so far I've completed my review of its dt properties.

>>
> 
> Fixes tag?

It'd make sense, however as I've said above formally there is no fixed
runtime bug, if the scope is limited to the upstream only.

Fixes: b7d41c937ed7 ("ARM: LPC32xx: Add the motor PWM to base dts file")

>> Signed-off-by: Vladimir Zapolskiy <vz at mleia.com>
>> ---
>>   arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi | 1 +
>>   1 file changed, 1 insertion(+)
>>
>> diff --git a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
>> index 39af48470ed5..abd401fda94e 100644
>> --- a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
>> +++ b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
>> @@ -304,6 +304,7 @@ i2c2: i2c at 400a8000 {
>>   			mpwm: pwm at 400e8000 {
>>   				compatible = "nxp,lpc3220-motor-pwm";
>>   				reg = <0x400e8000 0x78>;
>> +				clocks = <&clk LPC32XX_CLK_MCPWM>;
>>   				#pwm-cells = <3>;
>>   				status = "disabled";
>>   			};
>> -- 
>> 2.43.0
>>

-- 
Best wishes,
Vladimir


From skhan at linuxfoundation.org  Tue Dec 30 15:57:20 2025
From: skhan at linuxfoundation.org (Shuah Khan)
Date: Tue, 30 Dec 2025 16:57:20 -0700
Subject: Linux 6.19-rc1 mediatek mt7921e broke badly
In-Reply-To: <6fc04df5-b753-4b2d-b978-0e59a7f48ff7@linux.dev>
References: <d7f3b00d-beec-41f0-b157-7cfb871f9a46@linuxfoundation.org>
 <756e3f65-b2f2-4da3-985a-17754a7a872d@t-8ch.de>
 <CAHk-=wjO-7uR5HBi-MFnkxAxjhpgfbAQ+HCMKPiXFVwM+AJ7tA@mail.gmail.com>
 <6fc04df5-b753-4b2d-b978-0e59a7f48ff7@linux.dev>
Message-ID: <c1304430-dd7d-437b-8744-70af9ca85c0d@linuxfoundation.org>

On 12/29/25 21:21, Matthew Schwartz wrote:
> On 12/29/25 4:41 PM, Linus Torvalds wrote:
>> On Sat, 27 Dec 2025 at 04:25, Thomas Wei?schuh <linux at weissschuh.net> wrote:
>>>
>>> Hi Shuah,
>>>
>>> On 2025-12-27 02:07:24-0700, Shuah Khan wrote:
>>>> mt7921e doesn't load on my primary laptopn on Linux 6.19-rc1 and problem
>>>> still there on 6.19-rc2.
>>>
>>> This should be a duplicate of
>>> https://lore.kernel.org/all/CABXGCsMeAZyNJ-Axt_CUCXgyieWPV3rrcLpWsveMPT8R0YPGnQ at mail.gmail.com/
>>
>> Hmm. I wonder if we could instead do this:
>>
>>    --- a/lib/string.c
>>    +++ b/lib/string.c
>>    @@ -113,7 +113,7 @@ EXPORT_SYMBOL(strncpy);
>>     ssize_t sized_strscpy(char *dest, const char *src, size_t count)
>>     {
>>            const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
>>    -       size_t max = count;
>>    +       size_t max = count - 1;
>>            long res = 0;
>>
>>            if (count == 0 || WARN_ON_ONCE(count > INT_MAX))
>>
>> (intentionally whitespace-damaged patch, because I want people to
>> think about it).
> 
> I gave this a try on its own but I was still experiencing a kernel crash:
> 
> [    3.339408] strnlen: detected buffer overflow: 17 byte read of buffer size 16
> [    3.339804] WARNING: lib/string_helpers.c:1035 at __fortify_report+0x41/0x50, CPU#14: kworker/14:0/105
> [    3.352248]  __fortify_panic+0xd/0xf
> [    3.352259]  mt76_connac2_load_patch.cold+0x2b/0x95a [mt76_connac_lib 8f0d0f7b30f881af23462dac0a8cc5ff88d08cd0]
> 
> However, applying a similar diff in the fortify wrapper does prevent the crash:
> 
> --- a/include/linux/fortify-string.h
> +++ b/include/linux/fortify-string.h
> @@ -306,13 +306,13 @@ __FORTIFY_INLINE ssize_t sized_strscpy(char * const POS p, const char * const PO
>        * This call protects from read overflow, because len will default to q
>        * length if it smaller than size.
>        */
> -    len = strnlen(q, size);
> +    len = strnlen(q, size - 1);
>       /*
>        * If len equals size, we will copy only size bytes which leads to
>        * -E2BIG being returned.
>        * Otherwise we will copy len + 1 because of the final '\O'.
>        */
> -    len = len == size ? size : len + 1;
> +    len = len == size - 1 ? size : len + 1;
>   
>       /*
>        * Generate a runtime write overflow error if len is greater than
> 
> Not sure what the implications of such a change would be relative to the proposed
> fix here: https://lore.kernel.org/all/20251205161202.48409-1-mikhail.v.gavrilov at gmail.com/

+ adding Johannes to this thread also.

Reverting the following fixed my problem.
  
f804a5895eba ("wifi: mt76: Strip whitespace from build ddate")

The above fixes an extra newline in the dmesg by making the
code more complex it needs to introducing local buffers and
strscpy() - the proposed fix replaces this with memcpy().

Is there a simple way to do this than introducing memcpy()
or strscpy() to remove an extra newline that might or might
not exist? Why not check if newline exists or not using
strstr()?

I would recommend reverting f804a5895eba instead of trying
fix it. Then find a better way to eliminate extra newline that
shows up in dmesg when firmware build date happens to have
a newline.

thanks,
-- Shuah



From arnd at arndb.de  Tue Dec 30 16:02:55 2025
From: arnd at arndb.de (Arnd Bergmann)
Date: Wed, 31 Dec 2025 01:02:55 +0100
Subject: [PATCH] ARM: dts: intel: Drop pxa2xx
In-Reply-To: <m2wm26lv28.fsf@free.fr>
References: <20251212203226.458694-4-robh@kernel.org> <m2345fmkg7.fsf@free.fr>
 <35405ed3-1319-4d3a-84a5-ad67f4c823ad@app.fastmail.com>
 <m2wm26lv28.fsf@free.fr>
Message-ID: <4e5c631e-8c7f-4f38-a60e-2db829ff9f06@app.fastmail.com>

On Sun, Dec 28, 2025, at 12:11, Robert Jarzmik wrote:
>
>> Robert, let me know if you or someone else is able to spend
>> some time on sending (warning-free) dts files for pxa2xx
>> machines soon. If not, I'd plan to remove whatever is there
>> along with the board files and drivers.
>
> Here is one attached, the previously mentioned mioa701 board dts 
> file
> I've been using for years (the date of the patch should be funny
> enough). It was first submitted here :
>   https://lkml.org/lkml/2018/9/15/321
>
> I'm not very sure pxa25x and pxa27x should survive though. Lately, 
> the platform which I have left have 64MB of RAM, and cannot cope with 
> recent binaries sizes. And to my best knowledge, pxa2xx architecture are 
> not built anymore nor supported ...

Thanks for posting this one, that is helpful both for reference
and in case anyone wants to keep using or bringing back pxa27x
after we remove it.

My feeling is that if neither you nor Daniel are planning on
actually using PXA2xx on future kernels, we're better off
removing both PXA25x and PXA27x along with the board files
and only keep PXA3xx around for Raumfeld.

Looking at when PXA2xx was used, I see a lot of handhelds
from 2002 to 2007 but not much later, as smartphones then
started moved to newer Marvell chips, or TI and Qualcomm
alternatives. The last embedded PXA2xx boards were in 2010
(Colibri/Income, Voipac vpac270, Arcom Zeus), and were all
discontinued by their manufacturers years ago, usually 10
years after the hardware introduction, and nobody
complained when I removed the board files in 2022.

I had left the gumstix boards in the source tree at the time
because it had more memory than the others and was supported
by qemu. The upstream qemu releases now removed that as well.

If you or anyone else is still using PXA27x, we can always
bring it back later, but I'd then put the burden on them to
submit the dts file for inclusion without introducing DT
warnings.

> The drivers might still be useful (the DMA, the SPI for intel CPU, 
> ...).

Right, most drivers have to stay as they are still used on newer
chips. The ones that I think would become obsolete without pxa2xx
are pinctrl, cpufreq, camera, mtd, udc and pcmcia. Especially
the latter two have come up a few times during cleanups where they
cause extra work from complexity that probably nobody is using any
more.

> +	docg3: flash at 0 {
> +		compatible = "m-systems,diskonchip-g3";
> +		reg = <0x0 0x2000>;
> +	};

This currently has no upstream users I can see, so
removing pxa27x would probably mean we should remove
that as well.

> +	panel {
> +		compatible = "toshiba,ltm0305a776";
> +		lcd-type = "color-tft";

I don't see a driver that matches the compatible string,
does this one actually work?

       Arnd


From torvalds at linux-foundation.org  Tue Dec 30 17:27:13 2025
From: torvalds at linux-foundation.org (Linus Torvalds)
Date: Tue, 30 Dec 2025 17:27:13 -0800
Subject: Linux 6.19-rc1 mediatek mt7921e broke badly
In-Reply-To: <c1304430-dd7d-437b-8744-70af9ca85c0d@linuxfoundation.org>
References: <d7f3b00d-beec-41f0-b157-7cfb871f9a46@linuxfoundation.org>
 <756e3f65-b2f2-4da3-985a-17754a7a872d@t-8ch.de> <CAHk-=wjO-7uR5HBi-MFnkxAxjhpgfbAQ+HCMKPiXFVwM+AJ7tA@mail.gmail.com>
 <6fc04df5-b753-4b2d-b978-0e59a7f48ff7@linux.dev> <c1304430-dd7d-437b-8744-70af9ca85c0d@linuxfoundation.org>
Message-ID: <CAHk-=wh6WP0Wq=rbC2Md6vsFrV-+nvDjxgfx9NpMzUmVFNkJ9A@mail.gmail.com>

On Tue, 30 Dec 2025 at 15:57, Shuah Khan <skhan at linuxfoundation.org> wrote:
>
> I would recommend reverting f804a5895eba instead of trying
> fix it. Then find a better way to eliminate extra newline that
> shows up in dmesg when firmware build date happens to have
> a newline.

Yeah. Let's revert it.

And the way to fix the extra newline is trivial: just remove it from
the "dev_info()" format string.

Our kernel printing logic will add a newline for the next line anyway
if it is missing (unless somebody explicitly uses PR_CONT).

Can whoever saw the problem confirm that just a revert and a "remove
\n from that dev_info()" fixes the output for them?

              Linus


From ruanjinjie at huawei.com  Tue Dec 30 17:35:03 2025
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Wed, 31 Dec 2025 09:35:03 +0800
Subject: [PATCH v10 11/16] entry: Split syscall_exit_to_user_mode_work()
 for arch reuse
In-Reply-To: <f3c32e7f-f940-4cb0-941c-cb7f7f628d88@arm.com>
References: <20251222114737.1334364-1-ruanjinjie@huawei.com>
 <20251222114737.1334364-12-ruanjinjie@huawei.com>
 <f3c32e7f-f940-4cb0-941c-cb7f7f628d88@arm.com>
Message-ID: <d55de365-b246-32ed-14eb-1ea0318794a5@huawei.com>



On 2025/12/30 2:03, Kevin Brodsky wrote:
> On 22/12/2025 12:47, Jinjie Ruan wrote:
>> In the generic entry code, the beginning of
>> syscall_exit_to_user_mode_work() can be reused on arm64 so it makes
>> sense to split it.
>>
>> In preparation for moving arm64 over to the generic entry
>> code, split out syscall_exit_to_user_mode_work_prepare() helper from
>> syscall_exit_to_user_mode_work().
>>
>> No functional changes.
>>
>> Reviewed-by: Kevin Brodsky <kevin.brodsky at arm.com>
>> Reviewed-by: Thomas Gleixner <tglx at linutronix.de>
>> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
>> ---
>>  include/linux/entry-common.h | 35 ++++++++++++++++++++++-------------
>>  1 file changed, 22 insertions(+), 13 deletions(-)
>>
>> diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h
>> index 87efb38b7081..0de0e60630e1 100644
>> --- a/include/linux/entry-common.h
>> +++ b/include/linux/entry-common.h
>> @@ -121,20 +121,11 @@ static __always_inline long syscall_enter_from_user_mode(struct pt_regs *regs, l
>>   */
>>  void syscall_exit_work(struct pt_regs *regs, unsigned long work);
>>  
>> -/**
>> - * syscall_exit_to_user_mode_work - Handle work before returning to user mode
>> - * @regs:	Pointer to currents pt_regs
>> - *
>> - * Same as step 1 and 2 of syscall_exit_to_user_mode() but without calling
>> - * exit_to_user_mode() to perform the final transition to user mode.
>> - *
>> - * Calling convention is the same as for syscall_exit_to_user_mode() and it
>> - * returns with all work handled and interrupts disabled. The caller must
>> - * invoke exit_to_user_mode() before actually switching to user mode to
>> - * make the final state transitions. Interrupts must stay disabled between
>> - * return from this function and the invocation of exit_to_user_mode().
>> +/*
>> + * Syscall specific exit to user mode preparation. Runs with interrupts
>> + * enabled.
>>   */
>> -static __always_inline void syscall_exit_to_user_mode_work(struct pt_regs *regs)
>> +static __always_inline void syscall_exit_to_user_mode_work_prepare(struct pt_regs *regs)
>>  {
>>  	unsigned long work = READ_ONCE(current_thread_info()->syscall_work);
>>  	unsigned long nr = syscall_get_nr(current, regs);
>> @@ -155,6 +146,24 @@ static __always_inline void syscall_exit_to_user_mode_work(struct pt_regs *regs)
>>  	 */
>>  	if (unlikely(work & SYSCALL_WORK_EXIT))
>>  		syscall_exit_work(regs, work);
>> +}
>> +
>> +/**
>> + * syscall_exit_to_user_mode_work - Handle work before returning to user mode
>> + * @regs:	Pointer to currents pt_regs
>> + *
>> + * Same as step 1 and 2 of syscall_exit_to_user_mode() but without calling
>> + * exit_to_user_mode() to perform the final transition to user mode.
>> + *
>> + * Calling convention is the same as for syscall_exit_to_user_mode() and it
>> + * returns with all work handled and interrupts disabled. The caller must
>> + * invoke exit_to_user_mode() before actually switching to user mode to
>> + * make the final state transitions. Interrupts must stay disabled between
>> + * return from this function and the invocation of exit_to_user_mode().
>> + */
>> +static __always_inline void syscall_exit_to_user_mode_work(struct pt_regs *regs)
>> +{
>> +	syscall_exit_to_user_mode_work_prepare(regs);
> 
> The naming is getting awfully confusing, with the separate introduction
> of syscall_exit_to_user_mode_prepare().
> 
> Having had a closer look, do we really need
> syscall_exit_to_user_mode_work() as it currently stands? Nothing calls
> it except the generic syscall_exit_to_user_mode(). Which makes me think:
> how about moving the two lines below into syscall_exit_to_user_mode()
> instead of creating a new helper? IOW:

It looks fine to me, this will make the change less. The comment also
need to be updated.

> 
> @@ -155,8 +155,6 @@ static __always_inline void
> syscall_exit_to_user_mode_work(struct pt_regs *regs)
> ? ? ? */
> ? ? ?if (unlikely(work & SYSCALL_WORK_EXIT))
> ? ? ? ? ?syscall_exit_work(regs, work);
> -? ? local_irq_disable_exit_to_user();
> -? ? syscall_exit_to_user_mode_prepare(regs);
> ?}
> ?
> ?/**
> @@ -192,6 +190,8 @@ static __always_inline void
> syscall_exit_to_user_mode(struct pt_regs *regs)
> ?{
> ? ? ?instrumentation_begin();
> ? ? ?syscall_exit_to_user_mode_work(regs);
> +? ? local_irq_disable_exit_to_user();
> +? ? syscall_exit_to_user_mode_prepare(regs);
> ? ? ?instrumentation_end();
> ? ? ?exit_to_user_mode();
> ?}
> 
> - Kevin
> 
>>  	local_irq_disable_exit_to_user();
>>  	syscall_exit_to_user_mode_prepare(regs);
>>  }
> 


From ebiggers at kernel.org  Tue Dec 30 17:57:12 2025
From: ebiggers at kernel.org (Eric Biggers)
Date: Tue, 30 Dec 2025 17:57:12 -0800
Subject: Linux 6.19-rc1 mediatek mt7921e broke badly
In-Reply-To: <CAHk-=wh6WP0Wq=rbC2Md6vsFrV-+nvDjxgfx9NpMzUmVFNkJ9A@mail.gmail.com>
References: <d7f3b00d-beec-41f0-b157-7cfb871f9a46@linuxfoundation.org>
 <756e3f65-b2f2-4da3-985a-17754a7a872d@t-8ch.de>
 <CAHk-=wjO-7uR5HBi-MFnkxAxjhpgfbAQ+HCMKPiXFVwM+AJ7tA@mail.gmail.com>
 <6fc04df5-b753-4b2d-b978-0e59a7f48ff7@linux.dev>
 <c1304430-dd7d-437b-8744-70af9ca85c0d@linuxfoundation.org>
 <CAHk-=wh6WP0Wq=rbC2Md6vsFrV-+nvDjxgfx9NpMzUmVFNkJ9A@mail.gmail.com>
Message-ID: <20251231015712.GA2299@sol>

On Tue, Dec 30, 2025 at 05:27:13PM -0800, Linus Torvalds wrote:
> On Tue, 30 Dec 2025 at 15:57, Shuah Khan <skhan at linuxfoundation.org> wrote:
> >
> > I would recommend reverting f804a5895eba instead of trying
> > fix it. Then find a better way to eliminate extra newline that
> > shows up in dmesg when firmware build date happens to have
> > a newline.
> 
> Yeah. Let's revert it.
> 
> And the way to fix the extra newline is trivial: just remove it from
> the "dev_info()" format string.
> 
> Our kernel printing logic will add a newline for the next line anyway
> if it is missing (unless somebody explicitly uses PR_CONT).
> 
> Can whoever saw the problem confirm that just a revert and a "remove
> \n from that dev_info()" fixes the output for them?

That works for me.  The revert by itself makes the FORTIFY_SOURCE crash
go away and reintroduces a blank line in the log.  Removing the \n from
the string passed to dev_info as well makes the blank line go away.

- Eric


From shawnguo at kernel.org  Tue Dec 30 18:13:17 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Wed, 31 Dec 2025 10:13:17 +0800
Subject: [PATCH v1 0/3] arm64: dts: imx8x-colibri: add additional
 functionality
In-Reply-To: <aVOolTfi5s9jqG2v@livingston.pivistrello.it>
References: <20251031125003.275033-1-max.oss.09@gmail.com>
 <aVOolTfi5s9jqG2v@livingston.pivistrello.it>
Message-ID: <aVSGvY0Zls3Fxr84@dragon>

On Tue, Dec 30, 2025 at 11:25:25AM +0100, Francesco Dolcini wrote:
> Hello Shawn,
> 
> On Fri, Oct 31, 2025 at 01:49:40PM +0100, max.oss.09 at gmail.com wrote:
> > Provide a pwm-backlight.
> > Provide the 32kHz Wi-Fi clock used during low-power operation.
> > Configure CMA from the device tree.
> 
> This series was not applied, any concern? Anything to change?

Sorry for missing it.  Applied, thanks!

Shawn


From shawnguo at kernel.org  Tue Dec 30 18:18:19 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Wed, 31 Dec 2025 10:18:19 +0800
Subject: [PATCH v2 1/1] arm64: dts: imx8mp-evk: add camera ov5640 and
 related nodes
In-Reply-To: <20251229163101.4004478-1-Frank.Li@nxp.com>
References: <20251229163101.4004478-1-Frank.Li@nxp.com>
Message-ID: <aVSH6zOaXqmVfwzq@dragon>

On Mon, Dec 29, 2025 at 11:31:01AM -0500, Frank Li wrote:
> Add camera ov5640 and related nodes.
> 
> Signed-off-by: Frank Li <Frank.Li at nxp.com>

Applied, thanks!


From shawnguo at kernel.org  Tue Dec 30 18:25:45 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Wed, 31 Dec 2025 10:25:45 +0800
Subject: [PATCH v2 1/2] dt-bindings: tpm: Add st,st33tphf2ei2c
In-Reply-To: <20251230014047.149677-1-marek.vasut@mailbox.org>
References: <20251230014047.149677-1-marek.vasut@mailbox.org>
Message-ID: <aVSJqQHcvettOKeZ@dragon>

On Tue, Dec 30, 2025 at 02:40:34AM +0100, Marek Vasut wrote:
> Add the ST chip st33tphf2ei2c to the supported compatible strings of the
> TPM TIS I2C schema. The chip is compliant with the TCG PC Client TPM
> Profile specification.
> 
> For reference, a databrief is available at:
> https://www.st.com/resource/en/data_brief/st33tphf2ei2c.pdf
> 
> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
> Signed-off-by: Marek Vasut <marek.vasut at mailbox.org>

Applied both, thanks!


From k-willis at ti.com  Tue Dec 30 18:38:23 2025
From: k-willis at ti.com (Kendall Willis)
Date: Tue, 30 Dec 2025 20:38:23 -0600
Subject: [PATCH v2 4/5] arm64: dts: ti: k3-am62p5-sk: Enable Main UART
 wakeup
In-Reply-To: <20251230-b4-uart-daisy-chain-dts-v2-0-fa5257ec54bb@ti.com>
References: <20251230-b4-uart-daisy-chain-dts-v2-0-fa5257ec54bb@ti.com>
Message-ID: <20251230-b4-uart-daisy-chain-dts-v2-4-fa5257ec54bb@ti.com>

The Main UART can resume from suspend to RAM states when PIN_WKUP_EN
is enabled. Add the necessary pins needed to wakeup the system. Add the
system idle states that the Main UART can wakeup the system from.

Signed-off-by: Kendall Willis <k-willis at ti.com>
---
 arch/arm64/boot/dts/ti/k3-am62p5-sk.dts | 24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts b/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts
index ef719c6334fc094f01d9e8185992f2f58320e17d..96bba65f4f16792834567324db6f7f2bdee7bc06 100644
--- a/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts
+++ b/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts
@@ -328,14 +328,26 @@ AM62PX_IOPAD(0x0164, PIN_INPUT, 0) /* (A20) RGMII2_TX_CTL */
 		bootph-all;
 	};
 
-	main_uart0_pins_default: main-uart0-default-pins {
+	main_uart0_tx_pins_default: main-uart0-tx-default-pins {
 		pinctrl-single,pins = <
-			AM62PX_IOPAD(0x1c8, PIN_INPUT, 0)	/* (A22) UART0_RXD */
 			AM62PX_IOPAD(0x1cc, PIN_OUTPUT, 0)	/* (B22) UART0_TXD */
 		>;
 		bootph-all;
 	};
 
+	main_uart0_rx_pins_default: main-uart0-rx-default-pins {
+		pinctrl-single,pins = <
+			AM62PX_IOPAD(0x1c8, PIN_INPUT, 0)	/* (A22) UART0_RXD */
+		>;
+		bootph-all;
+	};
+
+	main_uart0_rx_pins_wakeup: main-uart0-rx-wakeup-pins {
+		pinctrl-single,pins = <
+			AM62PX_IOPAD(0x1c8, PIN_INPUT | PIN_WKUP_EN, 0)	/* (A22) UART0_RXD */
+		>;
+	};
+
 	main_uart1_pins_default: main-uart1-default-pins {
 		pinctrl-single,pins = <
 			AM62PX_IOPAD(0x0194, PIN_INPUT, 2) /* (D25) MCASP0_AXR3.UART1_CTSn */
@@ -692,8 +704,12 @@ partition at 3fc0000 {
 };
 
 &main_uart0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&main_uart0_pins_default>;
+	pinctrl-names = "default", "wakeup";
+	pinctrl-0 = <&main_uart0_tx_pins_default>, <&main_uart0_rx_pins_default>;
+	pinctrl-1 = <&main_uart0_tx_pins_default>, <&main_uart0_rx_pins_wakeup>;
+	wakeup-source = <&system_deep_sleep>,
+			<&system_mcu_only>,
+			<&system_standby>;
 	status = "okay";
 	bootph-all;
 };

-- 
2.34.1



From k-willis at ti.com  Tue Dec 30 18:38:21 2025
From: k-willis at ti.com (Kendall Willis)
Date: Tue, 30 Dec 2025 20:38:21 -0600
Subject: [PATCH v2 2/5] arm64: dts: ti: k3-am62x-sk-common: Enable Main
 UART wakeup
In-Reply-To: <20251230-b4-uart-daisy-chain-dts-v2-0-fa5257ec54bb@ti.com>
References: <20251230-b4-uart-daisy-chain-dts-v2-0-fa5257ec54bb@ti.com>
Message-ID: <20251230-b4-uart-daisy-chain-dts-v2-2-fa5257ec54bb@ti.com>

The Main UART can resume from suspend to RAM states when PIN_WKUP_EN
is enabled. Add the necessary pins needed to wakeup the system. Add the
system idle states that the Main UART can wakeup the system from.

Signed-off-by: Kendall Willis <k-willis at ti.com>
---
 arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi | 24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi b/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi
index 50ed859ae06c47af38b11753d909a91485d438e5..e84356a971ee5a2c1c799eb5a1830cc8efc9adf7 100644
--- a/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi
@@ -143,14 +143,26 @@ &phy_gmii_sel {
 
 &main_pmx0 {
 	/* First pad number is ALW package and second is AMC package */
-	main_uart0_pins_default: main-uart0-default-pins {
+	main_uart0_tx_pins_default: main-uart0-tx-default-pins {
 		bootph-all;
 		pinctrl-single,pins = <
-			AM62X_IOPAD(0x1c8, PIN_INPUT, 0) /* (D14/A13) UART0_RXD */
 			AM62X_IOPAD(0x1cc, PIN_OUTPUT, 0) /* (E14/E11) UART0_TXD */
 		>;
 	};
 
+	main_uart0_rx_pins_default: main-uart0-rx-default-pins {
+		bootph-all;
+		pinctrl-single,pins = <
+			AM62X_IOPAD(0x1c8, PIN_INPUT, 0) /* (D14/A13) UART0_RXD */
+		>;
+	};
+
+	main_uart0_rx_pins_wakeup: main-uart0-rx-wakeup-pins {
+		pinctrl-single,pins = <
+			AM62X_IOPAD(0x1c8, PIN_INPUT | PIN_WKUP_EN, 0) /* (D14/A13) UART0_RXD */
+		>;
+	};
+
 	main_uart1_pins_default: main-uart1-default-pins {
 		bootph-pre-ram;
 		pinctrl-single,pins = <
@@ -322,8 +334,12 @@ &wkup_uart0 {
 &main_uart0 {
 	bootph-all;
 	status = "okay";
-	pinctrl-names = "default";
-	pinctrl-0 = <&main_uart0_pins_default>;
+	pinctrl-names = "default", "wakeup";
+	pinctrl-0 = <&main_uart0_tx_pins_default>, <&main_uart0_rx_pins_default>;
+	pinctrl-1 = <&main_uart0_tx_pins_default>, <&main_uart0_rx_pins_wakeup>;
+	wakeup-source = <&system_deep_sleep>,
+			<&system_mcu_only>,
+			<&system_standby>;
 };
 
 &main_uart1 {

-- 
2.34.1



From k-willis at ti.com  Tue Dec 30 18:38:20 2025
From: k-willis at ti.com (Kendall Willis)
Date: Tue, 30 Dec 2025 20:38:20 -0600
Subject: [PATCH v2 1/5] arm64: dts: ti: k3-am62l: Define possible system
 states
In-Reply-To: <20251230-b4-uart-daisy-chain-dts-v2-0-fa5257ec54bb@ti.com>
References: <20251230-b4-uart-daisy-chain-dts-v2-0-fa5257ec54bb@ti.com>
Message-ID: <20251230-b4-uart-daisy-chain-dts-v2-1-fa5257ec54bb@ti.com>

Add the system states that are available on the TI AM62L SoC.

Signed-off-by: Kendall Willis <k-willis at ti.com>
---
 arch/arm64/boot/dts/ti/k3-am62l.dtsi | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/arm64/boot/dts/ti/k3-am62l.dtsi b/arch/arm64/boot/dts/ti/k3-am62l.dtsi
index 23acdbb301fe38e6045c0ef3ae340196009ed217..3b84ac9be6d075f5eb469c3e503b2e494c62be27 100644
--- a/arch/arm64/boot/dts/ti/k3-am62l.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am62l.dtsi
@@ -64,6 +64,18 @@ pmu: pmu {
 		interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH>;
 	};
 
+	system-idle-states {
+		system_rtc_ddr: system-rtc-ddr {
+			compatible = "system-idle-state";
+			idle-state-name = "mem-deep";
+		};
+
+		system_deep_sleep: system-deep-sleep {
+			compatible = "system-idle-state";
+			idle-state-name = "mem";
+		};
+	};
+
 	cbass_main: bus at f0000 {
 		compatible = "simple-bus";
 		ranges = <0x00 0x00600000 0x00 0x00600000 0x00 0x00010100>, /* GPIO */

-- 
2.34.1



From k-willis at ti.com  Tue Dec 30 18:38:19 2025
From: k-willis at ti.com (Kendall Willis)
Date: Tue, 30 Dec 2025 20:38:19 -0600
Subject: [PATCH v2 0/5] arm64: dts: ti: k3-am62: Support Main UART wakeup
Message-ID: <20251230-b4-uart-daisy-chain-dts-v2-0-fa5257ec54bb@ti.com>

This series adds wakeup support for the Main UART in the device tree of
the TI AM62 family of devices. It defines the specific pins and pinctrl
states needed to wakeup the system from the Main UART via I/O
daisy-chaining. The wakeup-source property is configured to describe the
low power modes the system can wakeup from using the Main UART.

Implementation
--------------
This series is intended to be implemented along with the following
series:

1. "pmdomain: ti_sci: handle wakeup constraint for out-of-band wakeup":
   Skips setting constraints for wakeup sources that have
   out-of-band wakeup capability.
   https://github.com/kwillis01/linux/tree/v6.19/uart-daisy-chain/pmdomain

2. "serial: 8250: omap: set out-of-band wakeup if wakeup pinctrl exists":
   Implements out-of-band wakeup from the UARTs for TI K3 SoCs.
   https://github.com/kwillis01/linux/tree/v6.19/uart-daisy-chain/uart-wakeup

3. "arm64: dts: ti: k3-am62: Support Main UART wakeup": (this series)
   implements the functionality to wakeup the system from the Main UART.
   https://github.com/kwillis01/linux/tree/b4/uart-daisy-chain-dts

Testing
-------
Tested on a AM62P SK EVM board and a AM62L EVM board with all the above
mentioned series implemented. Suspend/resume verified with the Main UART
wakeup source by entering a keypress on the console.

This github branch has all the necessary patches to test the series
using v6.19-rc1:
https://github.com/kwillis01/linux/tree/v6.19/uart-daisy-chain/all

Revisions
---------
v1->v2:
 - Define AM62L system idle states
 - Enable Main UART wakeup for AM62L SoC
 - Rebase to v6.19-rc3

v1: https://lore.kernel.org/all/20250904212827.3730314-1-k-willis at ti.com/

---
Kendall Willis (5):
      arm64: dts: ti: k3-am62l: Define possible system states
      arm64: dts: ti: k3-am62x-sk-common: Enable Main UART wakeup
      arm64: dts: ti: k3-am62a7-sk: Enable Main UART wakeup
      arm64: dts: ti: k3-am62p5-sk: Enable Main UART wakeup
      arm64: dts: ti: k3-am62l3-evm: Enable Main UART wakeup

 arch/arm64/boot/dts/ti/k3-am62a7-sk.dts        | 24 ++++++++++++++++++++----
 arch/arm64/boot/dts/ti/k3-am62l.dtsi           | 12 ++++++++++++
 arch/arm64/boot/dts/ti/k3-am62l3-evm.dts       | 22 ++++++++++++++++++----
 arch/arm64/boot/dts/ti/k3-am62p5-sk.dts        | 24 ++++++++++++++++++++----
 arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi | 24 ++++++++++++++++++++----
 5 files changed, 90 insertions(+), 16 deletions(-)
---
base-commit: f323ed34dc9831effb1ee95403bc364869d29d4c
change-id: 20251230-b4-uart-daisy-chain-dts-d01aa40560b2

Best regards,
-- 
Kendall Willis <k-willis at ti.com>



From k-willis at ti.com  Tue Dec 30 18:38:24 2025
From: k-willis at ti.com (Kendall Willis)
Date: Tue, 30 Dec 2025 20:38:24 -0600
Subject: [PATCH v2 5/5] arm64: dts: ti: k3-am62l3-evm: Enable Main UART
 wakeup
In-Reply-To: <20251230-b4-uart-daisy-chain-dts-v2-0-fa5257ec54bb@ti.com>
References: <20251230-b4-uart-daisy-chain-dts-v2-0-fa5257ec54bb@ti.com>
Message-ID: <20251230-b4-uart-daisy-chain-dts-v2-5-fa5257ec54bb@ti.com>

The Main UART can resume from suspend to RAM states when PIN_WKUP_EN
is enabled. Add the necessary pins needed to wakeup the system. Add the
system idle states that the Main UART can wakeup the system from.

Signed-off-by: Kendall Willis <k-willis at ti.com>
---
 arch/arm64/boot/dts/ti/k3-am62l3-evm.dts | 22 ++++++++++++++++++----
 1 file changed, 18 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/boot/dts/ti/k3-am62l3-evm.dts b/arch/arm64/boot/dts/ti/k3-am62l3-evm.dts
index cae04cce337366b50928d39b0c888550b14e43d3..911719278e7191d96a886ce1e818f98085dd5d67 100644
--- a/arch/arm64/boot/dts/ti/k3-am62l3-evm.dts
+++ b/arch/arm64/boot/dts/ti/k3-am62l3-evm.dts
@@ -280,14 +280,26 @@ AM62LX_IOPAD(0x0234, PIN_INPUT, 0) /* (B6) MMC1_SDCD */
 		bootph-all;
 	};
 
-	uart0_pins_default: uart0-default-pins {
+	uart0_tx_pins_default: uart0-tx-default-pins {
 		pinctrl-single,pins = <
-			AM62LX_IOPAD(0x01b4, PIN_INPUT, 0) /* (D13) UART0_RXD */
 			AM62LX_IOPAD(0x01b8, PIN_OUTPUT, 0) /* (C13) UART0_TXD */
 		>;
 		bootph-all;
 	};
 
+	uart0_rx_pins_default: uart0-rx-default-pins {
+		pinctrl-single,pins = <
+			AM62LX_IOPAD(0x01b4, PIN_INPUT, 0) /* (D13) UART0_RXD */
+		>;
+		bootph-all;
+	};
+
+	uart0_rx_pins_wakeup: uart0-rx-wakeup-pins {
+		pinctrl-single,pins = <
+			AM62LX_IOPAD(0x01b4, PIN_INPUT | PIN_WKUP_EN, 0) /* (D13) UART0_RXD */
+		>;
+	};
+
 	usb1_default_pins: usb1-default-pins {
 		pinctrl-single,pins = <
 			AM62LX_IOPAD(0x0248, PIN_INPUT | PIN_DS_PULLUD_ENABLE | PIN_DS_PULL_UP, 0) /* (A5) USB1_DRVVBUS */
@@ -328,8 +340,10 @@ &sdhci1 {
 };
 
 &uart0 {
-	pinctrl-0 = <&uart0_pins_default>;
-	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_tx_pins_default>, <&uart0_rx_pins_default>;
+	pinctrl-1 = <&uart0_tx_pins_default>, <&uart0_rx_pins_wakeup>;
+	pinctrl-names = "default", "wakeup";
+	wakeup-source  = <&system_deep_sleep>;
 	status = "okay";
 	bootph-all;
 };

-- 
2.34.1



From k-willis at ti.com  Tue Dec 30 18:38:22 2025
From: k-willis at ti.com (Kendall Willis)
Date: Tue, 30 Dec 2025 20:38:22 -0600
Subject: [PATCH v2 3/5] arm64: dts: ti: k3-am62a7-sk: Enable Main UART
 wakeup
In-Reply-To: <20251230-b4-uart-daisy-chain-dts-v2-0-fa5257ec54bb@ti.com>
References: <20251230-b4-uart-daisy-chain-dts-v2-0-fa5257ec54bb@ti.com>
Message-ID: <20251230-b4-uart-daisy-chain-dts-v2-3-fa5257ec54bb@ti.com>

The Main UART can resume from suspend to RAM states when PIN_WKUP_EN
is enabled. Add the necessary pins needed to wakeup the system. Add the
system idle states that the Main UART can wakeup the system from.

Signed-off-by: Kendall Willis <k-willis at ti.com>
---
 arch/arm64/boot/dts/ti/k3-am62a7-sk.dts | 24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts b/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts
index e99bdbc2e0cbdf858f1631096f9c2a086191bab3..85f93975fa728e3e65f5c7562e67e684cd5a4da2 100644
--- a/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts
+++ b/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts
@@ -274,14 +274,26 @@ AM62AX_IOPAD(0x078, PIN_OUTPUT, 1) /* (T21) GPMC0_AD15.VOUT0_DATA23 */
 		>;
 	};
 
-	main_uart0_pins_default: main-uart0-default-pins {
+	main_uart0_tx_pins_default: main-uart0-tx-default-pins {
 		pinctrl-single,pins = <
-			AM62AX_IOPAD(0x1c8, PIN_INPUT, 0) /* (E14) UART0_RXD */
 			AM62AX_IOPAD(0x1cc, PIN_OUTPUT, 0) /* (D15) UART0_TXD */
 		>;
 		bootph-all;
 	};
 
+	main_uart0_rx_pins_default: main-uart0-rx-default-pins {
+		pinctrl-single,pins = <
+			AM62AX_IOPAD(0x1c8, PIN_INPUT, 0) /* (E14) UART0_RXD */
+		>;
+		bootph-all;
+	};
+
+	main_uart0_rx_pins_wakeup: main-uart0-rx-wakeup-pins {
+		pinctrl-single,pins = <
+			AM62AX_IOPAD(0x1c8, PIN_INPUT | PIN_WKUP_EN, 0) /* (E14) UART0_RXD */
+		>;
+	};
+
 	main_uart1_pins_default: main-uart1-default-pins {
 		pinctrl-single,pins = <
 			AM62AX_IOPAD(0x01ac, PIN_INPUT, 2) /* (B21) MCASP0_AFSR.UART1_RXD */
@@ -717,8 +729,12 @@ &main_gpio_intr {
 
 &main_uart0 {
 	status = "okay";
-	pinctrl-names = "default";
-	pinctrl-0 = <&main_uart0_pins_default>;
+	pinctrl-names = "default", "wakeup";
+	pinctrl-0 = <&main_uart0_tx_pins_default>, <&main_uart0_rx_pins_default>;
+	pinctrl-1 = <&main_uart0_tx_pins_default>, <&main_uart0_rx_pins_wakeup>;
+	wakeup-source = <&system_deep_sleep>,
+			<&system_mcu_only>,
+			<&system_standby>;
 	bootph-all;
 };
 

-- 
2.34.1



From k-willis at ti.com  Tue Dec 30 18:51:42 2025
From: k-willis at ti.com (Kendall Willis)
Date: Tue, 30 Dec 2025 20:51:42 -0600
Subject: [PATCH 3/3] arm64: boot: dts: ti: k3-am62l3-evm: enable WKUP UART
 wakeup from LPM
In-Reply-To: <20251230-wkup-uart-wakeup-v1-0-cd6e15f8d956@ti.com>
References: <20251230-wkup-uart-wakeup-v1-0-cd6e15f8d956@ti.com>
Message-ID: <20251230-wkup-uart-wakeup-v1-3-cd6e15f8d956@ti.com>

Change the status of the wkup_uart0_interconnect node to enabled. The
target-module node sets the UART SYSC and SYSS registers to allow wakeup
from WKUP UART in DeepSleep low power mode.

Signed-off-by: Kendall Willis <k-willis at ti.com>
---
 arch/arm64/boot/dts/ti/k3-am62l3-evm.dts | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm64/boot/dts/ti/k3-am62l3-evm.dts b/arch/arm64/boot/dts/ti/k3-am62l3-evm.dts
index cae04cce337366b50928d39b0c888550b14e43d3..02b1a1c76b2ee05d49cd69d199a6aacdb1973fa0 100644
--- a/arch/arm64/boot/dts/ti/k3-am62l3-evm.dts
+++ b/arch/arm64/boot/dts/ti/k3-am62l3-evm.dts
@@ -359,3 +359,7 @@ &usb1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&usb1_default_pins>;
 };
+
+&wkup_uart0_interconnect {
+	status = "okay";
+};

-- 
2.34.1



From k-willis at ti.com  Tue Dec 30 18:51:39 2025
From: k-willis at ti.com (Kendall Willis)
Date: Tue, 30 Dec 2025 20:51:39 -0600
Subject: [PATCH 0/3] arm64: boot: dts: ti: k3-am62l: enable WKUP UART
 wakeup
Message-ID: <20251230-wkup-uart-wakeup-v1-0-cd6e15f8d956@ti.com>

K3 TI AM62L SoC supports wakeup from WKUP UART when the SoC is in the
DeepSleep low power mode. To enable WKUP UART the target-module device
tree node is enabled. The ti-sysc interconnect target module driver is
used to configure the the SYSCONFIG related registers to allow wakeup
from WKUP UART when the system is suspended. Refer to 14.7.2.5 UART in the
AM62L Techincal Reference Manual for registers referenced [1].

Previous TI SoCs configure the WKUP UART to wakeup from system suspend
using the ti-sysc interconnect target module driver. Refer to commit
ce27f7f9e328 ("arm64: dts: ti: k3-am62-wakeup: Configure ti-sysc for
wkup_uart0") for an example of this.

Testing
-------
Tested on AM62L EVM on v6.19-rc3. Suspend/resume verified with the WKUP
UART wakeup source by entering a keypress on the console. 

[1] https://www.ti.com/lit/ug/sprujb4a/sprujb4a.pdf

Signed-off-by: Kendall Willis <k-willis at ti.com>
---
Kendall Willis (3):
      arm64: dts: ti: k3-am62l: include WKUP_UART0 in wakeup peripheral window
      arm64: boot: dts: ti: k3-am62l-wakeup: create label for target-module
      arm64: boot: dts: ti: k3-am62l3-evm: enable WKUP UART wakeup from LPM

 arch/arm64/boot/dts/ti/k3-am62l-wakeup.dtsi | 2 +-
 arch/arm64/boot/dts/ti/k3-am62l.dtsi        | 4 ++--
 arch/arm64/boot/dts/ti/k3-am62l3-evm.dts    | 4 ++++
 3 files changed, 7 insertions(+), 3 deletions(-)
---
base-commit: 5dc233097d4f94776c0c3f6edfd7476281478dc3
change-id: 20251230-wkup-uart-wakeup-8bbc95aa8f8e

Best regards,
-- 
Kendall Willis <k-willis at ti.com>



From k-willis at ti.com  Tue Dec 30 18:51:40 2025
From: k-willis at ti.com (Kendall Willis)
Date: Tue, 30 Dec 2025 20:51:40 -0600
Subject: [PATCH 1/3] arm64: dts: ti: k3-am62l: include WKUP_UART0 in wakeup
 peripheral window
In-Reply-To: <20251230-wkup-uart-wakeup-v1-0-cd6e15f8d956@ti.com>
References: <20251230-wkup-uart-wakeup-v1-0-cd6e15f8d956@ti.com>
Message-ID: <20251230-wkup-uart-wakeup-v1-1-cd6e15f8d956@ti.com>

WKUP_UART0 is apart of the wakeup peripherals and has a range from
0x002B300000 to 0x002B3001FF. Expand the wakeup peripheral window to
include WKUP_UART0.

Fixes: 5f016758b0ab ("arm64: dts: ti: k3-am62l: add initial infrastructure")
Signed-off-by: Kendall Willis <k-willis at ti.com>
---
 arch/arm64/boot/dts/ti/k3-am62l.dtsi | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/ti/k3-am62l.dtsi b/arch/arm64/boot/dts/ti/k3-am62l.dtsi
index 23acdbb301fe38e6045c0ef3ae340196009ed217..e01e342c26daaa06a72036cc3a9a7b13a60e6738 100644
--- a/arch/arm64/boot/dts/ti/k3-am62l.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am62l.dtsi
@@ -92,7 +92,7 @@ cbass_main: bus at f0000 {
 			 <0x00 0x00b00000 0x00 0x00b00000 0x00 0x00001400>, /* VTM */
 			 <0x00 0x04080000 0x00 0x04080000 0x00 0x00008000>, /* PDCFG */
 			 <0x00 0x04201000 0x00 0x04201000 0x00 0x00000100>, /* GPIO */
-			 <0x00 0x2b100000 0x00 0x2b100000 0x00 0x00100100>, /* Wakeup Peripheral Window */
+			 <0x00 0x2b100000 0x00 0x2b100000 0x00 0x00200200>, /* Wakeup Peripheral Window */
 			 <0x00 0x40800000 0x00 0x40800000 0x00 0x00014000>, /* DMA */
 			 <0x00 0x43000000 0x00 0x43000000 0x00 0x00080000>; /* CTRL MMRs */
 		#address-cells = <2>;
@@ -104,7 +104,7 @@ cbass_wakeup: bus at a80000 {
 				 <0x00 0x00b00000 0x00 0x00b00000 0x00 0x00001400>, /* VTM */
 				 <0x00 0x04080000 0x00 0x04080000 0x00 0x00008000>, /* PDCFG */
 				 <0x00 0x04201000 0x00 0x04201000 0x00 0x00000100>, /* GPIO */
-				 <0x00 0x2b100000 0x00 0x2b100000 0x00 0x00100100>, /* Wakeup Peripheral Window */
+				 <0x00 0x2b100000 0x00 0x2b100000 0x00 0x00200200>, /* Wakeup Peripheral Window */
 				 <0x00 0x40800000 0x00 0x40800000 0x00 0x00014000>, /* DMA */
 				 <0x00 0x43000000 0x00 0x43000000 0x00 0x00080000>; /* CTRL MMRs */
 			#address-cells = <2>;

-- 
2.34.1



From k-willis at ti.com  Tue Dec 30 18:51:41 2025
From: k-willis at ti.com (Kendall Willis)
Date: Tue, 30 Dec 2025 20:51:41 -0600
Subject: [PATCH 2/3] arm64: boot: dts: ti: k3-am62l-wakeup: create label
 for target-module
In-Reply-To: <20251230-wkup-uart-wakeup-v1-0-cd6e15f8d956@ti.com>
References: <20251230-wkup-uart-wakeup-v1-0-cd6e15f8d956@ti.com>
Message-ID: <20251230-wkup-uart-wakeup-v1-2-cd6e15f8d956@ti.com>

Add label to the target-module node so that it can easily be referenced.
The node specifically configures the SYSCONFIG related registers for WKUP
UART.

Signed-off-by: Kendall Willis <k-willis at ti.com>
---
 arch/arm64/boot/dts/ti/k3-am62l-wakeup.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/ti/k3-am62l-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-am62l-wakeup.dtsi
index 61bfcdcfc66ea8d802a36ed43cd01fbbf3decc70..e9d638d9ffd3a52aa6e0df70f6003879bc292358 100644
--- a/arch/arm64/boot/dts/ti/k3-am62l-wakeup.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am62l-wakeup.dtsi
@@ -81,7 +81,7 @@ wkup_i2c0: i2c at 2b200000 {
 		status = "disabled";
 	};
 
-	target-module at 2b300050 {
+	wkup_uart0_interconnect: target-module at 2b300050 {
 		compatible = "ti,sysc-omap2", "ti,sysc";
 		reg = <0x00 0x2b300050 0x00 0x4>,
 		      <0x00 0x2b300054 0x00 0x4>,

-- 
2.34.1



From daniel at 0x0f.com  Tue Dec 30 18:54:57 2025
From: daniel at 0x0f.com (Daniel Palmer)
Date: Wed, 31 Dec 2025 11:54:57 +0900
Subject: [PATCH 0/5] Sigmastar DT warnings fixing part 1.
Message-ID: <20251231025502.1139168-1-daniel@0x0f.com>

I saw a slide at LPC that had sigmastar in the "hall of shame"
for DT warnings. I finally got some time to look at this so
I have fixed the ones that are obvious and quick to fix.

I'll fix the rest but they might take a bit longer i.e. one
of them is about the register shift for the UART registers,
that'll need the binding to be updated I think?

FWIW this platform isn't dead and I have been rebasing all
of the out of tree stuff that make it useful (Audio support,
display, hardware video decoding etc) but its basically stuck
on rewriting the clock driver so that it is mainline-able.

Some other people have taken the limited support in mainline
and my out of tree stuff and made it run on old MStar MIPS
machines too..

Daniel Palmer (5):
  arm: dts: mstar: breadbee: Correct regulator names
  arm: dts: mstar: breadbee: Correct LED names
  arm: dts: mstar: infinity: Correct opp table name
  arm: dts: mstar: v7: Move the reboot node
  arm: dts: mstar: v7: Add sizes and ranges to sram

 .../mstar-infinity-breadbee-common.dtsi         | 10 +++++-----
 arch/arm/boot/dts/sigmastar/mstar-infinity.dtsi |  2 +-
 arch/arm/boot/dts/sigmastar/mstar-v7.dtsi       | 17 ++++++++++-------
 3 files changed, 16 insertions(+), 13 deletions(-)

-- 
2.51.0



From daniel at 0x0f.com  Tue Dec 30 18:54:58 2025
From: daniel at 0x0f.com (Daniel Palmer)
Date: Wed, 31 Dec 2025 11:54:58 +0900
Subject: [PATCH 1/5] arm: dts: mstar: breadbee: Correct regulator names
In-Reply-To: <20251231025502.1139168-1-daniel@0x0f.com>
References: <20251231025502.1139168-1-daniel@0x0f.com>
Message-ID: <20251231025502.1139168-2-daniel@0x0f.com>

The regulator names had a "@<n>" in them so the dt validation
stuff wanted a reg property. Fix the names to match what the regulator
is for and remove the "@<n>" bit.

Signed-off-by: Daniel Palmer <daniel at 0x0f.com>
---
 .../boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi  | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm/boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi b/arch/arm/boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi
index 507ff2fba837..aedea0fbbce6 100644
--- a/arch/arm/boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi
+++ b/arch/arm/boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi
@@ -7,7 +7,7 @@
 #include <dt-bindings/gpio/gpio.h>
 
 / {
-	vcc_core: fixedregulator at 0 {
+	vcc_core: reg-core {
 		compatible = "regulator-fixed";
 		regulator-name = "vcc_core";
 		regulator-min-microvolt = <1000000>;
@@ -15,7 +15,7 @@ vcc_core: fixedregulator at 0 {
 		regulator-boot-on;
 	};
 
-	vcc_dram: fixedregulator at 1 {
+	vcc_dram: reg-dram {
 		compatible = "regulator-fixed";
 		regulator-name = "vcc_dram";
 		regulator-min-microvolt = <1800000>;
@@ -23,7 +23,7 @@ vcc_dram: fixedregulator at 1 {
 		regulator-boot-on;
 	};
 
-	vcc_io: fixedregulator at 2 {
+	vcc_io: reg-io {
 		compatible = "regulator-fixed";
 		regulator-name = "vcc_io";
 		regulator-min-microvolt = <3300000>;
-- 
2.51.0



From daniel at 0x0f.com  Tue Dec 30 18:54:59 2025
From: daniel at 0x0f.com (Daniel Palmer)
Date: Wed, 31 Dec 2025 11:54:59 +0900
Subject: [PATCH 2/5] arm: dts: mstar: breadbee: Correct LED names
In-Reply-To: <20251231025502.1139168-1-daniel@0x0f.com>
References: <20251231025502.1139168-1-daniel@0x0f.com>
Message-ID: <20251231025502.1139168-3-daniel@0x0f.com>

The dt validation stuff whats the names of the leds to match
a regexp.

Prefix the names with "led-" to make the validation happy.

Signed-off-by: Daniel Palmer <daniel at 0x0f.com>
---
 .../boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi    | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi b/arch/arm/boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi
index aedea0fbbce6..3826436a80d0 100644
--- a/arch/arm/boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi
+++ b/arch/arm/boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi
@@ -33,11 +33,11 @@ vcc_io: reg-io {
 
 	leds {
 		compatible = "gpio-leds";
-		red {
+		led-red {
 			gpios = <&gpio MSC313_GPIO_SR_IO16 GPIO_ACTIVE_HIGH>;
 			linux,default-trigger = "activity";
 		};
-		yellow {
+		led-yellow {
 			gpios = <&gpio MSC313_GPIO_SR_IO17 GPIO_ACTIVE_HIGH>;
 			linux,default-trigger = "heartbeat";
 		};
-- 
2.51.0



From daniel at 0x0f.com  Tue Dec 30 18:55:00 2025
From: daniel at 0x0f.com (Daniel Palmer)
Date: Wed, 31 Dec 2025 11:55:00 +0900
Subject: [PATCH 3/5] arm: dts: mstar: infinity: Correct opp table name
In-Reply-To: <20251231025502.1139168-1-daniel@0x0f.com>
References: <20251231025502.1139168-1-daniel@0x0f.com>
Message-ID: <20251231025502.1139168-4-daniel@0x0f.com>

The dt validation stuff expects the name of the opp table
to match a regexp and it currently doesn't.

Update the name to match the regexp.

Signed-off-by: Daniel Palmer <daniel at 0x0f.com>
---
 arch/arm/boot/dts/sigmastar/mstar-infinity.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/sigmastar/mstar-infinity.dtsi b/arch/arm/boot/dts/sigmastar/mstar-infinity.dtsi
index 441a917b88ba..b7d15a3288ad 100644
--- a/arch/arm/boot/dts/sigmastar/mstar-infinity.dtsi
+++ b/arch/arm/boot/dts/sigmastar/mstar-infinity.dtsi
@@ -9,7 +9,7 @@
 #include <dt-bindings/gpio/msc313-gpio.h>
 
 / {
-	cpu0_opp_table: opp_table0 {
+	cpu0_opp_table: opp-table-0 {
 		compatible = "operating-points-v2";
 		opp-shared;
 
-- 
2.51.0



From daniel at 0x0f.com  Tue Dec 30 18:55:01 2025
From: daniel at 0x0f.com (Daniel Palmer)
Date: Wed, 31 Dec 2025 11:55:01 +0900
Subject: [PATCH 4/5] arm: dts: mstar: v7: Move the reboot node
In-Reply-To: <20251231025502.1139168-1-daniel@0x0f.com>
References: <20251231025502.1139168-1-daniel@0x0f.com>
Message-ID: <20251231025502.1139168-5-daniel@0x0f.com>

The reboot node is currently inside of soc and that makes
the dt validation stuff complain that it wants some properties
that don't exist for reboot which is just some glue and not
a real device.

Move the node out of soc to fix the warnings.

Signed-off-by: Daniel Palmer <daniel at 0x0f.com>
---
 arch/arm/boot/dts/sigmastar/mstar-v7.dtsi | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/arch/arm/boot/dts/sigmastar/mstar-v7.dtsi b/arch/arm/boot/dts/sigmastar/mstar-v7.dtsi
index 3eeafd8c7121..db661e189eec 100644
--- a/arch/arm/boot/dts/sigmastar/mstar-v7.dtsi
+++ b/arch/arm/boot/dts/sigmastar/mstar-v7.dtsi
@@ -73,6 +73,13 @@ xtal_div2: xtal_div2 {
 		};
 	};
 
+	reboot {
+		compatible = "syscon-reboot";
+		regmap = <&pmsleep>;
+		offset = <0xb8>;
+		mask = <0x79>;
+	};
+
 	soc: soc {
 		compatible = "simple-bus";
 		#address-cells = <1>;
@@ -105,13 +112,6 @@ pmsleep: syscon at 1c00 {
 				reg = <0x1c00 0x100>;
 			};
 
-			reboot {
-				compatible = "syscon-reboot";
-				regmap = <&pmsleep>;
-				offset = <0xb8>;
-				mask = <0x79>;
-			};
-
 			rtc at 2400 {
 				compatible = "mstar,msc313-rtc";
 				reg = <0x2400 0x40>;
-- 
2.51.0



From daniel at 0x0f.com  Tue Dec 30 18:55:02 2025
From: daniel at 0x0f.com (Daniel Palmer)
Date: Wed, 31 Dec 2025 11:55:02 +0900
Subject: [PATCH 5/5] arm: dts: mstar: v7: Add sizes and ranges to sram
In-Reply-To: <20251231025502.1139168-1-daniel@0x0f.com>
References: <20251231025502.1139168-1-daniel@0x0f.com>
Message-ID: <20251231025502.1139168-6-daniel@0x0f.com>

Add some missing properties to the SRAM node to make the dt
validation happy.

Signed-off-by: Daniel Palmer <daniel at 0x0f.com>
---
 arch/arm/boot/dts/sigmastar/mstar-v7.dtsi | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm/boot/dts/sigmastar/mstar-v7.dtsi b/arch/arm/boot/dts/sigmastar/mstar-v7.dtsi
index db661e189eec..e50e4000d1ee 100644
--- a/arch/arm/boot/dts/sigmastar/mstar-v7.dtsi
+++ b/arch/arm/boot/dts/sigmastar/mstar-v7.dtsi
@@ -187,6 +187,9 @@ pm_uart: serial at 221000 {
 		imi: sram at a0000000 {
 			compatible = "mmio-sram";
 			reg = <0xa0000000 0x10000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 0xa0000000 0x10000>;
 		};
 	};
 };
-- 
2.51.0



From ricardo at pardini.net  Tue Dec 30 18:58:33 2025
From: ricardo at pardini.net (Ricardo Pardini)
Date: Wed, 31 Dec 2025 03:58:33 +0100
Subject: [PATCH v7 0/2] PCI: Configure Root Port MPS during host probing
In-Reply-To: <20251127170908.14850-1-18255117159@163.com>
References: <20251127170908.14850-1-18255117159@163.com>
Message-ID: <f5322597-c6dd-494a-863b-2caf24363f2d@pardini.net>

On 27/11/2025 18:09, Hans Zhang wrote:
> Current PCIe initialization exhibits a key optimization gap: Root Ports
> may operate with non-optimal Maximum Payload Size (MPS) settings. While
> downstream device configuration is handled during bus enumeration, Root
> Port MPS values inherited from firmware or hardware defaults often fail
> to utilize the full capabilities supported by controller hardware. This
> results in suboptimal data transfer efficiency throughout the PCIe
> hierarchy.
> 
> This patch series addresses this by:
> 
> 1. Core PCI enhancement (Patch 1):
> - Proactively configures Root Port MPS during host controller probing
> - Sets initial MPS to hardware maximum (128 << dev->pcie_mpss)
> - Conditional on PCIe bus tuning being enabled (PCIE_BUS_TUNE_OFF unset)
>    and not in PCIE_BUS_PEER2PEER mode (which requires default 128 bytes)
> - Maintains backward compatibility via PCIE_BUS_TUNE_OFF check
> - Preserves standard MPS negotiation during downstream enumeration
> 
> 2. Driver cleanup (Patch 2):
> - Removes redundant MPS configuration from Meson PCIe controller driver
> - Functionality is now centralized in PCI core
> - Simplifies driver maintenance long-term
> 
> ---
> Changes in v7:
> - Exclude PCIE_BUS_PEER2PEER mode from Root Port MPS configuration
> - Remove redundant check for upstream bridge (Root Ports don't have one)
> - Improve commit message and code comments as per Bjorn.
Hi Hans,

I've tested on an Odroid-HC4 with a SATA SSD (via an ASM1061) by 
applying your v7 on v6.19-rc3 + Bjorn's 
20251103221930.1831376-1-helgaas at kernel.org ("PCI: meson: Remove 
meson_pcie_link_up() timeout, message, speed check" which is required to 
get the meson PCIe to work at all since 6.18). With that setup I get:

# hdparm --direct -t /dev/sda
  Timing O_DIRECT disk reads: 832 MB in  3.00 seconds = 277.33 MB/sec

I've an identical machine, with a similar disk (even slightly faster, on 
paper), running plain 6.12.y and there I get:

# hdparm --direct -t /dev/sda
  Timing O_DIRECT disk reads: 764 MB in  3.00 seconds = 254.26 MB/sec

I repeated those a few times, not very scientific, I know; but anyway:

Tested-by: Ricardo Pardini <ricardo at pardini.net> # on Odroid-HC4

I've also feedback from another user running with this series with 
success on a different meson PCIe machine, will ask them to TB as well; 
they had reported a significant drop in performance since v6.18 without 
this.

Thanks,
Ricardo


From honyuenkwun at gmail.com  Tue Dec 30 18:58:28 2025
From: honyuenkwun at gmail.com (Jimmy Hon)
Date: Tue, 30 Dec 2025 20:58:28 -0600
Subject: [PATCH 0/3] arm64: dts: rockchip: Enable the NPU on some rk3588 boards
In-Reply-To: <20251230-arm64-dts-rockchip-rk3588-npu-enablements-v1-0-d38b182a59e3@pardini.net>
References: <20251230-arm64-dts-rockchip-rk3588-npu-enablements-v1-0-d38b182a59e3@pardini.net>
Message-ID: <CALWfF7KHyKmDcEL9=mYzfCRWc_cymNscoFdeXr8P2frJeww5vA@mail.gmail.com>

On Tue, Dec 30, 2025 at 2:20?PM Ricardo Pardini via B4 Relay
<devnull+ricardo.pardini.net at kernel.org> wrote:
>
> This series enables the NPU on a few Rockchip rk3588 boards.
> In every case here, the required regulator was already described.
Now that the pd_npu has defined the dependency to the vdd_npu_s0,
shouldn't the regulator-always-on be removed from the regulator? When
the Rock5B enabled the NPU, it didn't define the regulator with always
on. [1]

More specifically, the commit message for the introduction of the
pd_npu label mentions how the regulator no longer needs to be always
on. [2]

[1] https://lore.kernel.org/linux-rockchip/20250721-6-10-rocket-v9-10-77ebd484941e at tomeuvizoso.net/
[2] https://lore.kernel.org/linux-rockchip/20250721-6-10-rocket-v9-7-77ebd484941e at tomeuvizoso.net/

Jimmy

>
> Signed-off-by: Ricardo Pardini <ricardo at pardini.net>
> ---
> Ricardo Pardini (3):
>       arm64: dts: rockchip: Enable the NPU on NanoPC T6/T6-LTS
>       arm64: dts: rockchip: Enable the NPU on FriendlyElec CM3588
>       arm64: dts: rockchip: Enable the NPU on Turing RK1
>
>  .../dts/rockchip/rk3588-friendlyelec-cm3588.dtsi   | 34 +++++++++++++++++++++
>  arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi | 35 ++++++++++++++++++++++
>  .../arm64/boot/dts/rockchip/rk3588-turing-rk1.dtsi | 34 +++++++++++++++++++++
>  3 files changed, 103 insertions(+)
> ---
> base-commit: 9448598b22c50c8a5bb77a9103e2d49f134c9578
> change-id: 20251230-arm64-dts-rockchip-rk3588-npu-enablements-1e2830d2e7b0
>
> Best regards,
> --
> Ricardo Pardini <ricardo at pardini.net>
>
>
>
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip


From shawnguo at kernel.org  Tue Dec 30 19:05:37 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Wed, 31 Dec 2025 11:05:37 +0800
Subject: [PATCH v3 0/2] Add FRDM i.MX 91 Development board support
In-Reply-To: <20251230-imx91_frdm-v3-0-60cac61c96ec@nxp.com>
References: <20251230-imx91_frdm-v3-0-60cac61c96ec@nxp.com>
Message-ID: <aVSTARNDcNqvam1f@dragon>

On Tue, Dec 30, 2025 at 04:58:52PM +0900, Joseph Guo wrote:
> Joseph Guo (2):
>       dt-bindings: arm: imx Add FRDM-IMX91 board

Subject prefix "dt-bindings: arm: fsl: " might be better.

Fixed it up and applied both patches, thanks!

Shawn

>       arm64: dts: freescale: Add FRDM-IMX91 basic support


From jiyu.yang at oss.nxp.com  Tue Dec 30 19:06:13 2025
From: jiyu.yang at oss.nxp.com (Rain Yang)
Date: Wed, 31 Dec 2025 11:06:13 +0800
Subject: [PATCH] arm64: dts: imx95: Use GPU_CGC as core clock for GPU
In-Reply-To: <6055d6f3-2b31-4225-a42e-0f5ad79f7256@mailbox.org>
References: <aTACuRjC_Zpf8IOU@oss.nxp.com>
 <de36091e-c890-4897-b3e3-2a7575029a5d@mailbox.org>
 <aTD5np-HGaJqhzkD@oss.nxp.com>
 <5944d872-01a3-47e9-977b-029f3be4fd83@mailbox.org>
 <aTKVMAMQ6v_BwD6R@oss.nxp.com>
 <9b593731-898f-46a7-8ee5-68f8c170351c@mailbox.org>
 <aTYxm_dfMwF4H0_b@oss.nxp.com>
 <53ea529f-3538-4ab5-aa99-0caa6729b4cd@mailbox.org>
 <aVM-mSkSubMPd7Du@oss.nxp.com>
 <6055d6f3-2b31-4225-a42e-0f5ad79f7256@mailbox.org>
Message-ID: <aVSTJdnWm2KfpXa1@oss.nxp.com>

On Tue, Dec 30, 2025 at 03:17:44PM +0100, Marek Vasut wrote:
>On 12/30/25 3:53 AM, Rain Yang wrote:
>> On Tue, Dec 30, 2025 at 02:53:38AM +0100, Marek Vasut wrote:
>> > On 12/8/25 3:02 AM, Rain Yang wrote:
>> > 
>> > > > > Okay, I?ll submit a patch later.
>> > > > > The commit message should reflect that only CLK_GPU_CGC is enabled.
>> > > > 
>> > > > The commit message , and this change , is unrelated to GPUAPB clock.
>> > > The commit message is ambiguous. Could you clarify which parent clock
>> > > you are referring to, and whether it can be enabled by CLK_GPU_CGC?
>> > > If it was CLK_GPU, CLK_GPU_CGC can't be able to control it.
>> > 
>> > The commit message clearly states "These new GPU_CGC clock
>> > gate the existing GPU clock." and "GPU_CGC as well as its parent GPU clock."
>> > , I don't perceive any ambiguity, sorry.
>> > 
>> > Frankly, the whole GPUAPB discussion is entirely unrelated and it only stalls
>> > application of this bugfix and keeps upstream broken. This is not helping.
>> > 
>> > So unless there is anything in particular that is on-topic and prevents this
>> > patch from being applied, it would be good to apply it, otherwise the GPU on
>> > MX95 in mainline Linux is not working.
>> Hi Marek,
>> 
>> I?m not opposed to this patch being merged into mainline, but the commit
>> message needs to be accurate. the parent CLK_GPU cannot be enabled or
>> disabled externally. The last sentence should clearly state:
>
>Look here, this is what you can do with the MX95 SM:
>
>"
>>$ clock.r
>...
>083: gpuapb               =  on,  133333333Hz
>084: gpu                  =  on,  800000000Hz
>...
>174: gpu_cgc              =  on,  800000000Hz
>
>>$ clock.w gpu_cgc off
>>$ clock.w gpu off
>>$ clock.w gpuapb off
>
>>$ clock.r
>...
>083: gpuapb               = off,  133333333Hz
>084: gpu                  = off,  800000000Hz
>...
>174: gpu_cgc              = off,  800000000Hz
>"
>
>Notice how all clock are disabled, including GPU clock.
>
>That does not agree with your statement.
>
>> When the panthor driver enables the GPU core clock, it enables the GPU_CGC.
>
>It also enables all disabled parent clock in the process, which includes the
>GPU clock.
>
>> This ensures the description reflects the actual hardware behavior and
>> avoids confusion for future maintainers.
>> Thanks for addressing this issue ? once the commit message is corrected,
>> I?m fine with this going in.
>
>See above.

Hi Marek,
Based on the instructions you gave, I?d put it this way, even though the
CLK_GPU clock can only be controlled internally.

I?m fine with your patch now.


From jiyu.yang at oss.nxp.com  Tue Dec 30 19:19:15 2025
From: jiyu.yang at oss.nxp.com (Rain Yang)
Date: Wed, 31 Dec 2025 11:19:15 +0800
Subject: [PATCH] arm64: dts: imx95: remove CLK_GPUAPB
Message-ID: <20251231031915.752262-1-jiyu.yang@oss.nxp.com>

From: Rain Yang <jiyu.yang at nxp.com>

Dropping CLK_GPUAPB simplifies OPP handling and avoids unnecessary
complexity.

Fixes: 67934f248e64 ("arm64: dts: imx95: Describe Mali G310 GPU")
Signed-off-by: Rain Yang <jiyu.yang at nxp.com>
---
 arch/arm64/boot/dts/freescale/imx95.dtsi | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx95.dtsi b/arch/arm64/boot/dts/freescale/imx95.dtsi
index 88bde59e61b2..ab446aa6f73c 100644
--- a/arch/arm64/boot/dts/freescale/imx95.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx95.dtsi
@@ -2164,8 +2164,8 @@ netc_emdio: mdio at 0,0 {
 		gpu: gpu at 4d900000 {
 			compatible = "nxp,imx95-mali", "arm,mali-valhall-csf";
 			reg = <0 0x4d900000 0 0x480000>;
-			clocks = <&scmi_clk IMX95_CLK_GPU_CGC>, <&scmi_clk IMX95_CLK_GPUAPB>;
-			clock-names = "core", "coregroup";
+			clocks = <&scmi_clk IMX95_CLK_GPU_CGC>;
+			clock-names = "core";
 			interrupts = <GIC_SPI 289 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>;
-- 
2.39.5



From shawnguo at kernel.org  Tue Dec 30 19:26:33 2025
From: shawnguo at kernel.org (Shawn Guo)
Date: Wed, 31 Dec 2025 11:26:33 +0800
Subject: [GIT PULL] i.MX fixes for 6.19
Message-ID: <aVSX6SK_LADf1ti4@dragon>

The following changes since commit 8f0b4cce4481fb22653697cced8d0d04027cb1e8:

  Linux 6.19-rc1 (2025-12-14 16:05:07 +1200)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git tags/imx-fixes-6.19

for you to fetch changes up to 89e87d0dc87eb3654c9ae01afc4a18c1c6d1e523:

  arm64: dts: mba8mx: Fix Ethernet PHY IRQ support (2025-12-30 16:07:39 +0800)

----------------------------------------------------------------
i.MX fixes for 6.19:

- A mba8mx fix from Alexander Stein to correct Ethernet PHY IRQ trigger
  type
- An i.MX95 fix from Carlos Song to correct I3C2 pclk
- A couple of imx8qm-mek changes from Haibo Chen to fix light sensor
  interrupt type and usdhc2 regulator configuration
- An imx6q-ba16 change from Ian Ray to fix RTC interrupt level
- An imx8mp-dhcom-som change from Marek Vasut to fix sporadic Ethernet
  link bouncing caused by interruptions on the PHY reference clock
- A couple of imx8mp-tx8p changes from Maud Spierings to fix compatible
  and eqos nvmem-cells
- An ARM i.MX fix from Rob Herring to correct mc13xxx LED node names
- An imx8qm-ss-dma change from Sherry Sun to correct DMA channels for
  LPUART
- A couple of imx95-toradex-smarc changes from Vitor Soares to fix
  ethphy1 interrupt and SMARC_SDIO_WP label position

----------------------------------------------------------------
Alexander Stein (1):
      arm64: dts: mba8mx: Fix Ethernet PHY IRQ support

Carlos Song (1):
      arm64: dts: imx95: correct I3C2 pclk to IMX95_CLK_BUSWAKEUP

Haibo Chen (2):
      arm64: dts: imx8qm-mek: correct the light sensor interrupt type to low level
      arm64: dts: add off-on-delay-us for usdhc2 regulator

Ian Ray (1):
      ARM: dts: imx6q-ba16: fix RTC interrupt level

Marek Vasut (1):
      arm64: dts: imx8mp: Fix LAN8740Ai PHY reference clock on DH electronics i.MX8M Plus DHCOM

Maud Spierings (3):
      dt-bindings: arm: fsl: moduline-display: fix compatible
      arm64: dts: freescale: moduline-display: fix compatible
      arm64: dts: freescale: tx8p-ml81: fix eqos nvmem-cells

Rob Herring (Arm) (1):
      ARM: dts: nxp: imx: Fix mc13xxx LED node names

Sherry Sun (1):
      arm64: dts: imx8qm-ss-dma: correct the dma channels of lpuart

Vitor Soares (2):
      arm64: dts: freescale: imx95-toradex-smarc: use edge trigger for ethphy1 interrupt
      arm64: dts: freescale: imx95-toradex-smarc: fix SMARC_SDIO_WP label position

 Documentation/devicetree/bindings/arm/fsl.yaml                   | 9 ++++++++-
 arch/arm/boot/dts/nxp/imx/imx27-phytec-phycore-rdk.dts           | 8 ++++----
 arch/arm/boot/dts/nxp/imx/imx51-zii-rdu1.dts                     | 4 ++--
 arch/arm/boot/dts/nxp/imx/imx51-zii-scu2-mezz.dts                | 4 ++--
 arch/arm/boot/dts/nxp/imx/imx51-zii-scu3-esb.dts                 | 4 ++--
 arch/arm/boot/dts/nxp/imx/imx6q-ba16.dtsi                        | 2 +-
 arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi              | 1 +
 .../boot/dts/freescale/imx8mp-tx8p-ml81-moduline-display-106.dts | 2 +-
 arch/arm64/boot/dts/freescale/imx8mp-tx8p-ml81.dtsi              | 5 +++++
 arch/arm64/boot/dts/freescale/imx8qm-mek.dts                     | 3 ++-
 arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi                 | 8 ++++----
 arch/arm64/boot/dts/freescale/imx95-toradex-smarc.dtsi           | 4 +---
 arch/arm64/boot/dts/freescale/imx95.dtsi                         | 2 +-
 arch/arm64/boot/dts/freescale/mba8mx.dtsi                        | 2 +-
 14 files changed, 35 insertions(+), 23 deletions(-)


From skhan at linuxfoundation.org  Tue Dec 30 19:56:42 2025
From: skhan at linuxfoundation.org (Shuah Khan)
Date: Tue, 30 Dec 2025 20:56:42 -0700
Subject: [PATCH] Revert "wifi: mt76: Strip whitespace from build ddate"
Message-ID: <20251231035645.5545-1-skhan@linuxfoundation.org>

This reverts commit f804a5895ebad2b2d4fb8a3688d2115926e993d5.

This change introduced the following panic, and mt792x_load_firmware()
fails. wifi is dead on systems with mt792x wireless.

kern  :crit  : kernel BUG at lib/string_helpers.c:1043!
kern  :warn  : Oops: invalid opcode: 0000 [#1] SMP NOPTI
kern  :warn  : CPU: 14 UID: 0 PID: 61 Comm: kworker/14:0 Tainted: G        W
        6.19.0-rc1 #1 PREEMPT(voluntary)
kern  :warn  : Tainted: [W]=WARN
kern  :warn  : Hardware name: Framework Laptop 13 (AMD Ryzen 7040Series)/FRANMDCP07, BIOS 03.16 07/25/2025
kern  :warn  : Workqueue: events mt7921_init_work [mt7921_common]
kern  :warn  : RIP: 0010:__fortify_panic+0xd/0xf
kern  :warn  : Code: 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 40 0f b6 ff e8 c3 55 71 00 <0f> 0b 48 8b 54 24 10 48 8b 74 24 08 4c 89 e9 48 c7 c7 00 a2 d5 a0
kern  :warn  : RSP: 0018:ffffa7a5c03a3d10 EFLAGS: 00010246
kern  :warn  : RAX: ffffffffa0d7aaf2 RBX: 0000000000000000 RCX: ffffffffa0d7aaf2
kern  :warn  : RDX: 0000000000000011 RSI: ffffffffa0d5a170 RDI: ffffffffa128db10
kern  :warn  : RBP: ffff91650ae52060 R08: 0000000000000010 R09: ffffa7a5c31b2000
kern  :warn  : R10: ffffa7a5c03a3bf0 R11: 00000000ffffffff R12: 0000000000000000
kern  :warn  : R13: ffffa7a5c31b2000 R14: 0000000000001000 R15: 0000000000000000
kern  :warn  : FS:  0000000000000000(0000) GS:ffff91743e664000(0000) knlGS:0000000000000000
kern  :warn  : CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
kern  :warn  : CR2: 00007f10786c241c CR3: 00000003eca24000 CR4: 0000000000f50ef0
kern  :warn  : PKRU: 55555554
kern  :warn  : Call Trace:
kern  :warn  :  <TASK>
kern  :warn  :  mt76_connac2_load_patch.cold+0x2b/0xa41 [mt76_connac_lib]
kern  :warn  :  ? srso_alias_return_thunk+0x5/0xfbef5
kern  :warn  :  mt792x_load_firmware+0x36/0x150 [mt792x_lib]
kern  :warn  :  mt7921_run_firmware+0x2c/0x4a0 [mt7921_common]
kern  :warn  :  ? srso_alias_return_thunk+0x5/0xfbef5
kern  :warn  :  ? mt7921_rr+0x12/0x30 [mt7921e]
kern  :warn  :  ? srso_alias_return_thunk+0x5/0xfbef5
kern  :warn  :  ? ____mt76_poll_msec+0x75/0xb0 [mt76]
kern  :warn  :  mt7921e_mcu_init+0x4c/0x7a [mt7921e]
kern  :warn  :  mt7921_init_work+0x51/0x190 [mt7921_common]
kern  :warn  :  process_one_work+0x18b/0x340
kern  :warn  :  worker_thread+0x256/0x3a0
kern  :warn  :  ? __pfx_worker_thread+0x10/0x10
kern  :warn  :  kthread+0xfc/0x240
kern  :warn  :  ? __pfx_kthread+0x10/0x10
kern  :warn  :  ? __pfx_kthread+0x10/0x10
kern  :warn  :  ret_from_fork+0x254/0x290
kern  :warn  :  ? __pfx_kthread+0x10/0x10
kern  :warn  :  ret_from_fork_asm+0x1a/0x30
kern  :warn  :  </TASK>
Signed-off-by: Shuah Khan <skhan at linuxfoundation.org>
---
 drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
index ea99167765b0..fba7025ffd3f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
@@ -3101,7 +3101,6 @@ int mt76_connac2_load_patch(struct mt76_dev *dev, const char *fw_name)
 	int i, ret, sem, max_len = mt76_is_sdio(dev) ? 2048 : 4096;
 	const struct mt76_connac2_patch_hdr *hdr;
 	const struct firmware *fw = NULL;
-	char build_date[17];
 
 	sem = mt76_connac_mcu_patch_sem_ctrl(dev, true);
 	switch (sem) {
@@ -3125,11 +3124,8 @@ int mt76_connac2_load_patch(struct mt76_dev *dev, const char *fw_name)
 	}
 
 	hdr = (const void *)fw->data;
-	strscpy(build_date, hdr->build_date, sizeof(build_date));
-	build_date[16] = '\0';
-	strim(build_date);
 	dev_info(dev->dev, "HW/SW Version: 0x%x, Build Time: %.16s\n",
-		 be32_to_cpu(hdr->hw_sw_ver), build_date);
+		 be32_to_cpu(hdr->hw_sw_ver), hdr->build_date);
 
 	for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) {
 		struct mt76_connac2_patch_sec *sec;
-- 
2.51.0



From skhan at linuxfoundation.org  Tue Dec 30 20:00:53 2025
From: skhan at linuxfoundation.org (Shuah Khan)
Date: Tue, 30 Dec 2025 21:00:53 -0700
Subject: Linux 6.19-rc1 mediatek mt7921e broke badly
In-Reply-To: <20251231015712.GA2299@sol>
References: <d7f3b00d-beec-41f0-b157-7cfb871f9a46@linuxfoundation.org>
 <756e3f65-b2f2-4da3-985a-17754a7a872d@t-8ch.de>
 <CAHk-=wjO-7uR5HBi-MFnkxAxjhpgfbAQ+HCMKPiXFVwM+AJ7tA@mail.gmail.com>
 <6fc04df5-b753-4b2d-b978-0e59a7f48ff7@linux.dev>
 <c1304430-dd7d-437b-8744-70af9ca85c0d@linuxfoundation.org>
 <CAHk-=wh6WP0Wq=rbC2Md6vsFrV-+nvDjxgfx9NpMzUmVFNkJ9A@mail.gmail.com>
 <20251231015712.GA2299@sol>
Message-ID: <fdebed60-264d-4f05-9423-618bc3ec6d6d@linuxfoundation.org>

On 12/30/25 18:57, Eric Biggers wrote:
> On Tue, Dec 30, 2025 at 05:27:13PM -0800, Linus Torvalds wrote:
>> On Tue, 30 Dec 2025 at 15:57, Shuah Khan <skhan at linuxfoundation.org> wrote:
>>>
>>> I would recommend reverting f804a5895eba instead of trying
>>> fix it. Then find a better way to eliminate extra newline that
>>> shows up in dmesg when firmware build date happens to have
>>> a newline.
>>
>> Yeah. Let's revert it.
>>
>> And the way to fix the extra newline is trivial: just remove it from
>> the "dev_info()" format string.
>>
>> Our kernel printing logic will add a newline for the next line anyway
>> if it is missing (unless somebody explicitly uses PR_CONT).
>>
>> Can whoever saw the problem confirm that just a revert and a "remove
>> \n from that dev_info()" fixes the output for them?
> 
> That works for me.  The revert by itself makes the FORTIFY_SOURCE crash
> go away and reintroduces a blank line in the log.  Removing the \n from
> the string passed to dev_info as well makes the blank line go away.
> 

I just sent the revert. I will try removing \n from dev_info()
later on tomorrow.

My quick trial still showed extra line which didn't make sense
to me. More trials have to wait for tomorrow.

thanks,
-- Shuah



From skhan at linuxfoundation.org  Tue Dec 30 20:07:53 2025
From: skhan at linuxfoundation.org (Shuah Khan)
Date: Tue, 30 Dec 2025 21:07:53 -0700
Subject: Linux 6.19-rc1 mediatek mt7921e broke badly
In-Reply-To: <fdebed60-264d-4f05-9423-618bc3ec6d6d@linuxfoundation.org>
References: <d7f3b00d-beec-41f0-b157-7cfb871f9a46@linuxfoundation.org>
 <756e3f65-b2f2-4da3-985a-17754a7a872d@t-8ch.de>
 <CAHk-=wjO-7uR5HBi-MFnkxAxjhpgfbAQ+HCMKPiXFVwM+AJ7tA@mail.gmail.com>
 <6fc04df5-b753-4b2d-b978-0e59a7f48ff7@linux.dev>
 <c1304430-dd7d-437b-8744-70af9ca85c0d@linuxfoundation.org>
 <CAHk-=wh6WP0Wq=rbC2Md6vsFrV-+nvDjxgfx9NpMzUmVFNkJ9A@mail.gmail.com>
 <20251231015712.GA2299@sol>
 <fdebed60-264d-4f05-9423-618bc3ec6d6d@linuxfoundation.org>
Message-ID: <30d14c51-3325-49be-9510-43f4661ff6c4@linuxfoundation.org>

On 12/30/25 21:00, Shuah Khan wrote:
> On 12/30/25 18:57, Eric Biggers wrote:
>> On Tue, Dec 30, 2025 at 05:27:13PM -0800, Linus Torvalds wrote:
>>> On Tue, 30 Dec 2025 at 15:57, Shuah Khan <skhan at linuxfoundation.org> wrote:
>>>>
>>>> I would recommend reverting f804a5895eba instead of trying
>>>> fix it. Then find a better way to eliminate extra newline that
>>>> shows up in dmesg when firmware build date happens to have
>>>> a newline.
>>>
>>> Yeah. Let's revert it.
>>>
>>> And the way to fix the extra newline is trivial: just remove it from
>>> the "dev_info()" format string.
>>>
>>> Our kernel printing logic will add a newline for the next line anyway
>>> if it is missing (unless somebody explicitly uses PR_CONT).
>>>
>>> Can whoever saw the problem confirm that just a revert and a "remove
>>> \n from that dev_info()" fixes the output for them?
>>
>> That works for me.? The revert by itself makes the FORTIFY_SOURCE crash
>> go away and reintroduces a blank line in the log.? Removing the \n from
>> the string passed to dev_info as well makes the blank line go away.
>>
> 
> I just sent the revert. I will try removing \n from dev_info()
> later on tomorrow.
> 
> My quick trial still showed extra line which didn't make sense
> to me. More trials have to wait for tomorrow.
> 

Hmm - there are 3 places that print build_date in  mt76_connac2_load_ram()

3022         dev_info(dev->dev, "WM Firmware Version: %.10s, Build Time: %.15s\n     ",
3023                  hdr->fw_ver, hdr->build_date);


3051         dev_info(dev->dev, "WA Firmware Version: %.10s, Build Time: %.15s\n     ",
3052                  hdr->fw_ver, hdr->build_date);

3127         dev_info(dev->dev, "HW/SW Version: 0x%x, Build Time: %.16s\n",
3128                  be32_to_cpu(hdr->hw_sw_ver), hdr->build_date);

The last one prints %.16s and other two do %.15s - is the fix simply
changing last one on line 3127 to print %.15s - this avoids printing
the extra \n?

thanks,
-- Shuah


From ming.qian at oss.nxp.com  Tue Dec 30 21:37:22 2025
From: ming.qian at oss.nxp.com (Ming Qian(OSS))
Date: Wed, 31 Dec 2025 13:37:22 +0800
Subject: [PATCH v4 0/3] Fix concurrency issues between G1 and G2 on
In-Reply-To: <CAPDyKFpFm9kCSNbALJTqeyzFdg3OoooE2gUOXJcjv=WgQeZ84Q@mail.gmail.com>
References: <20251205015428.643-1-ming.qian@oss.nxp.com>
 <CAPDyKFpFm9kCSNbALJTqeyzFdg3OoooE2gUOXJcjv=WgQeZ84Q@mail.gmail.com>
Message-ID: <3397e2c8-602f-4cd8-8cd5-7af3410edc00@oss.nxp.com>

Hi Uffe,

On 12/30/2025 9:42 PM, Ulf Hansson wrote:
> On Fri, 5 Dec 2025 at 02:55, <ming.qian at oss.nxp.com> wrote:
>>
>> From: Ming Qian <ming.qian at oss.nxp.com>
>>
>> On the i.MX8MQ, we encountered some concurrency issues with H264 and HEVC
>> decoding.
>>
>> There are two main reasons:
>> 1. The vpu blk-ctrl don't have separate reset and clock enable bits.
>> 2. The g1 VPU and g2 VPU cannot decode simultaneously.
>>
>> We attempted to make corresponding fix to address these two issues.
>>
>> Ming Qian (2):
>>    pmdomain: imx8m-blk-ctrl: Remove separate rst and clk mask for 8mq vpu
>>    media: verisilicon: Avoid G2 bus error while decoding H.264 and HEVC
>>
>> Nicolas Dufresne (1):
>>    media: v4l2-mem2mem: Add a kref to the v4l2_m2m_dev structure
>>
>>   drivers/media/platform/verisilicon/hantro.h   |  2 +
>>   .../media/platform/verisilicon/hantro_drv.c   | 42 +++++++++++++++++--
>>   .../media/platform/verisilicon/imx8m_vpu_hw.c |  8 ++++
>>   drivers/media/v4l2-core/v4l2-mem2mem.c        | 23 ++++++++++
>>   drivers/pmdomain/imx/imx8m-blk-ctrl.c         | 11 +++--
>>   include/media/v4l2-mem2mem.h                  | 21 ++++++++++
>>   6 files changed, 100 insertions(+), 7 deletions(-)
>>
> 
> Can I pick the pmdomain patch separately from the others? Or does this
> need to go together?
> 
> Kind regards
> Uffe

I think you can pick the pmdomain patch separately.

Regards,
Ming



From peng.fan at oss.nxp.com  Tue Dec 30 22:48:41 2025
From: peng.fan at oss.nxp.com (Peng Fan)
Date: Wed, 31 Dec 2025 14:48:41 +0800
Subject: [PATCH 0/3] soc: imx: misc clean up and support i.MX9[4,52]
In-Reply-To: <20251217-soc-imx9-fix-v1-0-0c763c2dbe29@nxp.com>
References: <20251217-soc-imx9-fix-v1-0-0c763c2dbe29@nxp.com>
Message-ID: <aVTHSVvdJ9DUW3cv@shlinux89>

Hi Shawn,

On Wed, Dec 17, 2025 at 08:42:06PM +0800, Peng Fan (OSS) wrote:
>Patch 1, 2: Use device managed API and dev_err_probe to clean up driver
>Patch 3: Support i.MX94/52

Since you have picked up the binding doc for i.MX952, the comment
in patch 3 from Frank is cleared, will you pick up this patchset?

Thanks,
Peng


From krzk at kernel.org  Tue Dec 30 23:47:56 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 31 Dec 2025 08:47:56 +0100
Subject: [PATCH 3/5] arm: dts: mstar: infinity: Correct opp table name
In-Reply-To: <20251231025502.1139168-4-daniel@0x0f.com>
References: <20251231025502.1139168-1-daniel@0x0f.com>
 <20251231025502.1139168-4-daniel@0x0f.com>
Message-ID: <ac0f8b8d-f6e4-4d60-9931-e820417c1abc@kernel.org>

On 31/12/2025 03:55, Daniel Palmer wrote:
> The dt validation stuff expects the name of the opp table
> to match a regexp and it currently doesn't.
> 
> Update the name to match the regexp.
> 
> Signed-off-by: Daniel Palmer <daniel at 0x0f.com>


These two should be squashed. Don't align node names with bindings per node.

Best regards,
Krzysztof


From ye.zhang at rock-chips.com  Wed Dec 31 00:12:33 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Wed, 31 Dec 2025 16:12:33 +0800
Subject: [PATCH v4 7/7] ARM: dts: rockchip: rk3506: Add pinctrl and rmio
 dtsi for rk3506
In-Reply-To: <ebb720f6-4756-437f-a71a-d94f45d732e8@kernel.org>
References: <20251227114957.3287944-1-ye.zhang@rock-chips.com>
 <20251227114957.3287944-8-ye.zhang@rock-chips.com>
 <ebb720f6-4756-437f-a71a-d94f45d732e8@kernel.org>
Message-ID: <0de0f505-5858-4ea6-85a7-4c386ac205e9@rock-chips.com>


? 2025/12/28 18:37, Krzysztof Kozlowski ??:
> On 27/12/2025 12:49, Ye Zhang wrote:
>> +		/omit-if-no-ref/
>> +		rm_io28_touch_key_in6: rm-io28-touch-key-in6 {
>> +			rockchip,pins =
>> +				<1 RK_PC3 7 &pcfg_pull_none>;
>> +			rockchip,rmio-pins =
>> +				<0 28 49>;
>> +		};
>> +
>> +		/omit-if-no-ref/
>> +		rm_io28_touch_key_in7: rm-io28-touch-key-in7 {
>> +			rockchip,pins =
>> +				<1 RK_PC3 7 &pcfg_pull_none>;
>> +			rockchip,rmio-pins =
>> +				<0 28 50>;
>> +		};
>> +
>> +		/omit-if-no-ref/
>> +		rm_io28_sai0_mclk: rm-io28-sai0-mclk {
>> +			rockchip,pins =
>> +				<1 RK_PC3 7 &pcfg_pull_none>;
>> +			rockchip,rmio-pins =
>> +				<0 28 51>;
>> +		};
>> +
>> +		/omit-if-no-ref/
>> +		rm_io28_sai0_sclk: rm-io28-sai0-sclk {
>> +			rockchip,pins =
>> +				<1 RK_PC3 7 &pcfg_pull_none>;
>> +			rockchip,rmio-pins =
>> +				<0 28 52>;
>> +		};
>> +
>> +		/omit-if-no-ref/
>> +		rm_io28_sai0_lrck: rm-io28-sai0-lrck {
>> +			rockchip,pins =
>> +				<1 RK_PC3 7 &pcfg_pull_none>;
>> +			rockchip,rmio-pins =
>> +				<0 28 53>;
>> +		};
>> +
>> +		/omit-if-no-ref/
>> +		rm_io28_sai0_sdi0: rm-io28-sai0-sdi0 {
>> +			rockchip,pins =
>> +				<1 RK_PC3 7 &pcfg_pull_none>;
>> +			rockchip,rmio-pins =
>> +				<0 28 54>;
>> +		};
> Why are you defining all pins? This is wrong, your driver has to do it,
> not DTS. All these definitions when not used are just pointless.
>
This file is auto-generated to provide a complete set of RMIO 
configurations.? ?Our intention is to offer a generic library for all 
future board developers, so they can simply pick the needed nodes by 
phandle without manually looking up register values in the datasheet 
every time.? ?This improves usability and standardization.

We also used the /omit-if-no-ref/ tag, so this will strictly not 
increase the size of the compiled DTB binary at all.

Could you please reconsider if this? approach is acceptable given the 
usability benefits?

If you still consider the ~25k lines of source code bloat unacceptable 
for upstream, we will have to drop this generic dtsi file and let users 
manually define only the required nodes when adding board support.

Best regards,
Ye Zhang


From daniel at 0x0f.com  Wed Dec 31 00:35:10 2025
From: daniel at 0x0f.com (Daniel Palmer)
Date: Wed, 31 Dec 2025 17:35:10 +0900
Subject: [PATCH 3/5] arm: dts: mstar: infinity: Correct opp table name
In-Reply-To: <ac0f8b8d-f6e4-4d60-9931-e820417c1abc@kernel.org>
References: <20251231025502.1139168-1-daniel@0x0f.com> <20251231025502.1139168-4-daniel@0x0f.com>
 <ac0f8b8d-f6e4-4d60-9931-e820417c1abc@kernel.org>
Message-ID: <CAFr9PXn_-Ep9HzwTEErZ4Wmm9X8Q2ZkRP1LfmaAMhbYNfJVFuQ@mail.gmail.com>

Hi Krzysztof,

On Wed, 31 Dec 2025 at 16:48, Krzysztof Kozlowski <krzk at kernel.org> wrote:
>
> These two should be squashed. Don't align node names with bindings per node.

Sorry, I cannot parse what that means.

Looking at the example in
Documentation/devicetree/bindings/opp/opp-v2.yaml it looks like it
should just be called opp-table?

Cheers,

Daniel


From j at jannau.net  Wed Dec 31 01:42:12 2025
From: j at jannau.net (Janne Grunau)
Date: Wed, 31 Dec 2025 10:42:12 +0100
Subject: [PATCH v2] mfd: macsmc: Initialize mutex
Message-ID: <20251231-macsmc-mutex_init-v2-1-5818c9dc9b29@jannau.net>

Initialize struct apple_smc's mutex in apple_smc_probe(). Using the
mutex uninitialized surprisingly resulted only in occasional NULL
pointer dereferences in apple_smc_read() calls from the probe()
functions of sub devices.

Fixes: e038d985c9823 ("mfd: Add Apple Silicon System Management Controller")
Cc: stable at vger.kernel.org
Signed-off-by: Janne Grunau <j at jannau.net>
---
Changes in v2:
- rewritten commit message
- added missing Cc: stable
- rebased onto v6.19-rc1
- Link to v1: https://lore.kernel.org/r/20250925-macsmc-mutex_init-v1-1-416e9e644735 at jannau.net
---
 drivers/mfd/macsmc.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mfd/macsmc.c b/drivers/mfd/macsmc.c
index e3893e255ce5e4bb4832d80ad1fc002d413a291a..3015e8d36d6e5bfdcea342c7d05a7b34788d7845 100644
--- a/drivers/mfd/macsmc.c
+++ b/drivers/mfd/macsmc.c
@@ -413,6 +413,7 @@ static int apple_smc_probe(struct platform_device *pdev)
 	if (!smc)
 		return -ENOMEM;
 
+	mutex_init(&smc->mutex);
 	smc->dev = &pdev->dev;
 	smc->sram_base = devm_platform_get_and_ioremap_resource(pdev, 1, &smc->sram);
 	if (IS_ERR(smc->sram_base))

---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20250925-macsmc-mutex_init-80d7cb2aacfa

Best regards,
-- 
Janne Grunau <j at jannau.net>



From krzk at kernel.org  Wed Dec 31 01:48:44 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 31 Dec 2025 10:48:44 +0100
Subject: [PATCH 3/5] arm: dts: mstar: infinity: Correct opp table name
In-Reply-To: <CAFr9PXn_-Ep9HzwTEErZ4Wmm9X8Q2ZkRP1LfmaAMhbYNfJVFuQ@mail.gmail.com>
References: <20251231025502.1139168-1-daniel@0x0f.com>
 <20251231025502.1139168-4-daniel@0x0f.com>
 <ac0f8b8d-f6e4-4d60-9931-e820417c1abc@kernel.org>
 <CAFr9PXn_-Ep9HzwTEErZ4Wmm9X8Q2ZkRP1LfmaAMhbYNfJVFuQ@mail.gmail.com>
Message-ID: <499ce4ea-c6bf-45f1-ab68-c37397196084@kernel.org>

On 31/12/2025 09:35, Daniel Palmer wrote:
> Hi Krzysztof,
> 
> On Wed, 31 Dec 2025 at 16:48, Krzysztof Kozlowski <krzk at kernel.org> wrote:
>>
>> These two should be squashed. Don't align node names with bindings per node.
> 
> Sorry, I cannot parse what that means.

I meant, two commits should be rather squashed. If you intend to rename
the nodes, fix all names to be generic, not only some.

Best regards,
Krzysztof


From krzk at kernel.org  Wed Dec 31 01:49:39 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 31 Dec 2025 10:49:39 +0100
Subject: [PATCH 1/5] arm: dts: mstar: breadbee: Correct regulator names
In-Reply-To: <20251231025502.1139168-2-daniel@0x0f.com>
References: <20251231025502.1139168-1-daniel@0x0f.com>
 <20251231025502.1139168-2-daniel@0x0f.com>
Message-ID: <50439d25-55a3-4d76-8864-81132db7598c@kernel.org>

On 31/12/2025 03:54, Daniel Palmer wrote:
> The regulator names had a "@<n>" in them so the dt validation
> stuff wanted a reg property. Fix the names to match what the regulator
> is for and remove the "@<n>" bit.
> 
> Signed-off-by: Daniel Palmer <daniel at 0x0f.com>
> ---
>  .../boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi  | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm/boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi b/arch/arm/boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi
> index 507ff2fba837..aedea0fbbce6 100644
> --- a/arch/arm/boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi
> +++ b/arch/arm/boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi
> @@ -7,7 +7,7 @@
>  #include <dt-bindings/gpio/gpio.h>
>  
>  / {
> -	vcc_core: fixedregulator at 0 {
> +	vcc_core: reg-core {


If renaming this then rather use one of the approved names, so either
"regulator-foo" or "regulator-XvY" (which matches current format
recommendation: 'regulator-[0-9]v[0-9]')

https://web.git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/regulator/fixed-regulator.yaml

Best regards,
Krzysztof


From yeoreum.yun at arm.com  Wed Dec 31 02:07:33 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Wed, 31 Dec 2025 10:07:33 +0000
Subject: [PATCH v3 0/2]  fix wrong usage of memory allocation APIs under
 PREEMPT_RT in arm64
In-Reply-To: <20251218194750.395301-1-yeoreum.yun@arm.com>
References: <20251218194750.395301-1-yeoreum.yun@arm.com>
Message-ID: <aVT15bhN4hEBNaOg@e129823.arm.com>

Gentle ping in case of forgotten.

On Thu, Dec 18, 2025 at 07:47:48PM +0000, Yeoreum Yun wrote:
> Under PREEMPT_RT, calling generic memory allocation/free APIs
> (e.x) __get_free_pages(), pgtable_alloc(), free_pages() and etc
> with preemption disabled is not allowed, but allow only nolock() APIs series
> because it may acquire a spin lock that becomes sleepable on RT,
> potentially causing a sleep during page allocation
> (See Documentation/core-api/real-time/differences.rst, Memory allocation section).
>
> However, In arm64, __linear_map_split_to_ptes() and
> __kpti_install_ng_mappings() called by stopper thread via stop_machine()
> use generic memory allocation/free APIs.
>
> This patchset fixes this problem and based on v6.19-rc1
>
> Patch History
> ==============
> from v2 to v3:
>   - remove split-mode and split_args.
>     pass proper function pointer while spliting.
>   - rename function name.
>   - https://lore.kernel.org/all/20251217182007.2345700-1-yeoreum.yun at arm.com/
>
> from v1 to v2:
>   - drop pagetable_alloc_nolock()
>   - following @Ryan Roberts suggestion.
>   - https://lore.kernel.org/all/20251212161832.2067134-1-yeoreum.yun at arm.com/
>
>
> *** BLURB HERE ***
>
> Yeoreum Yun (2):
>   arm64: mmu: avoid allocating pages while splitting the linear mapping
>   arm64: mmu: avoid allocating pages while installing ng-mapping for
>     KPTI
>
>  arch/arm64/mm/mmu.c | 254 ++++++++++++++++++++++++++++++++++----------
>  1 file changed, 197 insertions(+), 57 deletions(-)
>
> --
> LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
>

--
Sincerely,
Yeoreum Yun


From yeoreum.yun at arm.com  Wed Dec 31 02:07:58 2025
From: yeoreum.yun at arm.com (Yeoreum Yun)
Date: Wed, 31 Dec 2025 10:07:58 +0000
Subject: [PATCH v11 RESEND 0/9] support FEAT_LSUI
In-Reply-To: <20251214112248.901769-1-yeoreum.yun@arm.com>
References: <20251214112248.901769-1-yeoreum.yun@arm.com>
Message-ID: <aVT1/vm4RoKydvPY@e129823.arm.com>

Gentle ping in case of forgotten.

On Sun, Dec 14, 2025 at 11:22:39AM +0000, Yeoreum Yun wrote:
> Since Armv9.6, FEAT_LSUI supplies the load/store instructions for
> previleged level to access to access user memory without clearing
> PSTATE.PAN bit.
>
> This patchset support FEAT_LSUI and applies in futex atomic operation
> and user_swpX emulation where can replace from ldxr/st{l}xr
> pair implmentation with clearing PSTATE.PAN bit to correspondant
> load/store unprevileged atomic operation without clearing PSTATE.PAN bit.
>
> This patch based on v6.19-rc1
>
>
> Patch Sequences
> ================
>
> Patch #1 adds cpufeature for FEAT_LSUI
>
> Patch #2-#3 expose FEAT_LSUI to guest
>
> Patch #4 adds Kconfig for FEAT_LSUI
>
> Patch #5-#6 support futex atomic-op with FEAT_LSUI
>
> Patch #7-#9 support user_swpX emulation with FEAT_LSUI
>
>
> Patch History
> ==============
> from v10 to v11:
>   - rebase to v6.19-rc1
>   - use cast instruction to emulate deprecated swpb instruction
>   - https://lore.kernel.org/all/20251103163224.818353-1-yeoreum.yun at arm.com/
>
> from v9 to v10:
>   - apply FEAT_LSUI to user_swpX emulation.
>   - add test coverage for LSUI bit in ID_AA64ISAR3_EL1
>   - rebase to v6.18-rc4
>   - https://lore.kernel.org/all/20250922102244.2068414-1-yeoreum.yun at arm.com/
>
> from v8 to v9:
>   - refotoring __lsui_cmpxchg64()
>   - rebase to v6.17-rc7
>   - https://lore.kernel.org/all/20250917110838.917281-1-yeoreum.yun at arm.com/
>
> from v7 to v8:
>   - implements futex_atomic_eor() and futex_atomic_cmpxchg() with casalt
>     with C helper.
>   - Drop the small optimisation on ll/sc futex_atomic_set operation.
>   - modify some commit message.
>   - https://lore.kernel.org/all/20250816151929.197589-1-yeoreum.yun at arm.com/
>
> from v6 to v7:
>   - wrap FEAT_LSUI with CONFIG_AS_HAS_LSUI in cpufeature
>   - remove unnecessary addition of indentation.
>   - remove unnecessary mte_tco_enable()/disable() on LSUI operation.
>   - https://lore.kernel.org/all/20250811163635.1562145-1-yeoreum.yun at arm.com/
>
> from v5 to v6:
>   - rebase to v6.17-rc1
>   - https://lore.kernel.org/all/20250722121956.1509403-1-yeoreum.yun at arm.com/
>
> from v4 to v5:
>   - remove futex_ll_sc.h futext_lsui and lsui.h and move them to futex.h
>   - reorganize the patches.
>   - https://lore.kernel.org/all/20250721083618.2743569-1-yeoreum.yun at arm.com/
>
> from v3 to v4:
>   - rebase to v6.16-rc7
>   - modify some patch's title.
>   - https://lore.kernel.org/all/20250617183635.1266015-1-yeoreum.yun at arm.com/
>
> from v2 to v3:
>   - expose FEAT_LUSI to guest
>   - add help section for LUSI Kconfig
>   - https://lore.kernel.org/all/20250611151154.46362-1-yeoreum.yun at arm.com/
>
> from v1 to v2:
>   - remove empty v9.6 menu entry
>   - locate HAS_LUSI in cpucaps in order
>   - https://lore.kernel.org/all/20250611104916.10636-1-yeoreum.yun at arm.com/
>
>
> Yeoreum Yun (9):
>   arm64: cpufeature: add FEAT_LSUI
>   KVM: arm64: expose FEAT_LSUI to guest
>   KVM: arm64: kselftest: set_id_regs: add test for FEAT_LSUI
>   arm64: Kconfig: Detect toolchain support for LSUI
>   arm64: futex: refactor futex atomic operation
>   arm64: futex: support futex with FEAT_LSUI
>   arm64: separate common LSUI definitions into lsui.h
>   arm64: armv8_deprecated: convert user_swpX to inline function
>   arm64: armv8_deprecated: apply FEAT_LSUI for swpX emulation.
>
>  arch/arm64/Kconfig                            |   5 +
>  arch/arm64/include/asm/futex.h                | 291 +++++++++++++++---
>  arch/arm64/include/asm/lsui.h                 |  25 ++
>  arch/arm64/kernel/armv8_deprecated.c          | 111 +++++--
>  arch/arm64/kernel/cpufeature.c                |  10 +
>  arch/arm64/kvm/sys_regs.c                     |   3 +-
>  arch/arm64/tools/cpucaps                      |   1 +
>  .../testing/selftests/kvm/arm64/set_id_regs.c |   1 +
>  8 files changed, 381 insertions(+), 66 deletions(-)
>  create mode 100644 arch/arm64/include/asm/lsui.h
>
>
> base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
> --
> LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
>

--
Sincerely,
Yeoreum Yun


From j at jannau.net  Wed Dec 31 02:10:57 2025
From: j at jannau.net (Janne Grunau)
Date: Wed, 31 Dec 2025 11:10:57 +0100
Subject: [PATCH] nvme-apple: Add "apple,t8103-nvme-ans2" as compatible
Message-ID: <20251231-nvme-apple-t8103-base-compat-v1-1-dc11727dc930@jannau.net>

After discussion with the devicetree maintainers we agreed to not extend
lists with the generic compatible "apple,nvme-ans2" anymore [1]. Add
"apple,t8103-nvme-ans2" as fallback compatible as it is the SoC the
driver and bindings were written for.

[1]: https://lore.kernel.org/asahi/12ab93b7-1fc2-4ce0-926e-c8141cfe81bf at kernel.org/

Cc: stable at vger.kernel.org # v6.18+
Fixes: 5bd2927aceba ("nvme-apple: Add initial Apple SoC NVMe driver")
Reviewed-by: Neal Gompa <neal at gompa.dev>
Signed-off-by: Janne Grunau <j at jannau.net>
---
This is split off from the v1 series adding Apple M2 Pro/Max/Ultra
device trees in [2]. Handling this as fix adding a device id only for
v6.18+ for two reasons. apple_nvme_of_match gained hw_data in v6.18 and
device trees using this compatible were only added in v6.18.
    
2: https://lore.kernel.org/r/20250828-dt-apple-t6020-v1-0-507ba4c4b98e at jannau.net
    
Changes compared to the patch in that series:
- rebased onto v6.19-rc1 since commit 04d8ecf37b5e ("nvme: apple: Add
  Apple A11 support") introduced hw data for the match table
---
 drivers/nvme/host/apple.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/nvme/host/apple.c b/drivers/nvme/host/apple.c
index 15b3d07f8ccdd023cd3be75eedd349b747c1ecad..ed61b97fde59f7e02664798d9c2612ac16307f5c 100644
--- a/drivers/nvme/host/apple.c
+++ b/drivers/nvme/host/apple.c
@@ -1704,6 +1704,7 @@ static const struct apple_nvme_hw apple_nvme_t8103_hw = {
 
 static const struct of_device_id apple_nvme_of_match[] = {
 	{ .compatible = "apple,t8015-nvme-ans2", .data = &apple_nvme_t8015_hw },
+	{ .compatible = "apple,t8103-nvme-ans2", .data = &apple_nvme_t8103_hw },
 	{ .compatible = "apple,nvme-ans2", .data = &apple_nvme_t8103_hw },
 	{},
 };

---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20251026-nvme-apple-t8103-base-compat-358ba0564f76

Best regards,
-- 
Janne Grunau <j at jannau.net>



From ye.zhang at rock-chips.com  Wed Dec 31 02:12:44 2025
From: ye.zhang at rock-chips.com (Ye Zhang)
Date: Wed, 31 Dec 2025 18:12:44 +0800
Subject: [PATCH v4 5/7] dt-bindings: pinctrl: rockchip: Add rk3506 rmio
 support
In-Reply-To: <20251228-olive-termite-of-painting-1bee5b@quoll>
References: <20251227114957.3287944-1-ye.zhang@rock-chips.com>
 <20251227114957.3287944-6-ye.zhang@rock-chips.com>
 <20251228-olive-termite-of-painting-1bee5b@quoll>
Message-ID: <7370b9a4-692d-43f8-9a48-82da0b4de939@rock-chips.com>


? 2025/12/28 18:37, Krzysztof Kozlowski ??:
> On Sat, Dec 27, 2025 at 07:49:55PM +0800, Ye Zhang wrote:
>> The RK3506 SoC introduces a secondary block-level pinmux controller called
>> RMIO (Rockchip Matrix I/O). When the primary IOMUX is selected to a
>> specific function, the pin signal is routed to the RMIO block, where a
>> secondary selection determines the final function.
>>
>> This patch adds the necessary properties to support RMIO:
>> - rockchip,rmio: phandle to the RMIO syscon node.
>> - rockchip,rmio-pins: a matrix to configure the RMIO block.
>>
>> Signed-off-by: Ye Zhang <ye.zhang at rock-chips.com>
>> ---
>>   .../bindings/pinctrl/rockchip,pinctrl.yaml    | 24 +++++++++++++++++++
>>   1 file changed, 24 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
>> index 97960245676d..887bec22b172 100644
>> --- a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
>> +++ b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
>> @@ -66,6 +66,13 @@ properties:
>>         Required for at least rk3188 and rk3288. On the rk3368 this should
>>         point to the PMUGRF syscon.
>>   
>> +  rockchip,rmio:
>> +    $ref: /schemas/types.yaml#/definitions/phandle
>> +    description:
>> +      The phandle of the syscon node for the RMIO registers, used by
>> +      some SoCs (e.g. rk3506) to configure the secondary block-level
>> +      pinmux functions.
>> +
> You need to disallow it for other variants in if:then: block.
Will be completed in v5.
>>     "#address-cells":
>>       enum: [1, 2]
>>   
>> @@ -144,6 +151,23 @@ additionalProperties:
>>                   The phandle of a node contains the generic pinconfig options
>>                   to use as described in pinctrl-bindings.txt.
>>   
>> +      rockchip,rmio-pins:
>> +        $ref: /schemas/types.yaml#/definitions/uint32-matrix
>> +        minItems: 1
>> +        items:
>> +          items:
>> +            - minimum: 0
> That's redundant. 0 is already minimum.
I will remove it in v5
>> +              description: RMIO ID (Controller index)
> Why do you need this? Is this pin controller having multiple RMIO IDs?
> Nothing like that was expressed in previous DTS. No other IDs are
> present in this DTS, either...

The RMIO hardware IP itself is designed to support multiple instances. 
Although the RK3506 only integrates one instance, other chips (like the 
RK2116) already utilize multiple RMIO blocks.

We want to define the binding based on the capabilities of the IP block 
rather than the specific configuration of the RK3506. This ensures the 
binding format (3 cells) remains stable when support for multi-RMIO SoCs 
is added to Linux in the future, avoiding the need to handle different 
cell formats in the driver.

We prefer to keep the ID column (fixed to 0 for RK3506) for this forward 
compatibility.

Is this acceptable?

>> +            - minimum: 0
>> +              description: Pin index within the RMIO controller
>> +            - minimum: 0
>> +              description: Function Mux ID
>> +        description:
>> +          Configuration for the Rockchip Matrix I/O (RMIO) block. The format
>> +          is <rmio_id pin_id function_id>. This acts as a secondary muxing
>> +          layer when the primary 'rockchip,pins' mux is set to the RMIO
>> +          function.
>> +
>>   examples:
>>     - |
>>       #include <dt-bindings/interrupt-controller/arm-gic.h>
>> -- 
>> 2.34.1
>>
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
>


From peng.fan at oss.nxp.com  Wed Dec 31 02:12:47 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Wed, 31 Dec 2025 18:12:47 +0800
Subject: [PATCH v7 0/6] clk: Support spread spectrum and use it in clk-scmi
Message-ID: <20251231-clk-ssc-v7-1-v7-0-380e8b58f9e3@nxp.com>

Since the assigned-clock-sscs property [1] has been accepted into the device
tree schema, we can now support it in the Linux clock driver. Therefore,
I've picked up the previously submitted work [2] titled "clk: Support
spread spectrum and use it in clk-pll144x and clk-scmi."
As more than six months have passed since [2] was posted, I?m treating this
patchset as a new submission rather than a v3.

- Introduce clk_set_spread_spectrum to set the parameters for enabling
  spread spectrum of a clock.
- Parse 'assigned-clock-sscs' and configure it by default before using the
  clock. This property is parsed before parsing clock rate.
- Enable this feature for clk-scmi on i.MX95.

Because SCMI spec will not include spread spectrum as a standard
extension, we still need to use NXP i.MX OEM extension.

[1] https://github.com/devicetree-org/dt-schema/pull/154
[2] https://lore.kernel.org/all/20250205-clk-ssc-v2-0-fa73083caa92 at nxp.com/

Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
Changes in v7:
- Add R-b from Sebin
- Drop __free usage per comment from Krzysztof in patch 3
- Link to v6: https://lore.kernel.org/linux-clk/20251128-clk-ssc-v6-2-v6-0-cfafdb5d6811 at nxp.com/

Changes in v6:
- Add kunit build warning
- Update OEM string comparation per Sebin
- Link to v5: https://lore.kernel.org/linux-clk/20251009-clk-ssc-v5-1-v5-0-d6447d76171e at nxp.com/

Changes in v5:
- Per Stephen, export clk_hw_set_spread_spectrum, use enum for method,
  add const for set_spread_spectrum and rename clk_ss/conf to ss_conf.
- Per Sebin, Cristian, Sudeep, I added clk-scmi-oem.c to support vendor
  extensions.
- Link to v4: https://lore.kernel.org/arm-scmi/aNQPWO6pfA_3mmxf at redhat.com/T/#me81231bf286e2a8e4e00a68707ed1e525a2b4a3d

Changes in v4:
- Add R-b for patch 1 from Brian
- Drop unecessary change in patch 4 Per Brian
- Link to v3: https://lore.kernel.org/r/20250912-clk-ssc-version1-v3-0-fd1e07476ba1 at nxp.com

Changes in v3:
- New patch 1 for dt-bindings per comment from Brian
  https://lore.kernel.org/all/aLeEFzXkPog_dt2B at x1/
  This might not be good to add a new dt-binding file in v3. But this is
  quite a simple file that just has four macros to encode modulation
  method. So hope this is fine for DT maintainers.
- Add Brain's R-b for patch 2
- New patch 3 to add Kunit test per Brain. Since Brain helped
  draft part of the code, I added Co-developed-by tag from Brain.
- Link to v2: https://lore.kernel.org/r/20250901-clk-ssc-version1-v2-0-1d0a486dffe6 at nxp.com

Changes in v2:
- Simplify the code in patch 2 per Dan Carpenter and Brian Masney
- Rebased to next-20250829
- Link to v1: https://lore.kernel.org/r/20250812-clk-ssc-version1-v1-0-cef60f20d770 at nxp.com

---
Peng Fan (6):
      dt-bindings: clock: Add spread spectrum definition
      clk: Introduce clk_hw_set_spread_spectrum
      clk: conf: Support assigned-clock-sscs
      clk: Add KUnit tests for assigned-clock-sscs
      clk: scmi: Introduce common header for SCMI clock interface
      clk: scmi: Add i.MX95 OEM extension support for SCMI clock driver

 drivers/clk/Makefile                               |   8 +-
 drivers/clk/clk-conf.c                             |  75 +++++++++++++
 drivers/clk/clk-scmi-oem.c                         | 103 ++++++++++++++++++
 drivers/clk/clk-scmi.c                             |  44 +++-----
 drivers/clk/clk-scmi.h                             |  51 +++++++++
 drivers/clk/clk.c                                  |  27 +++++
 drivers/clk/clk_test.c                             | 121 ++++++++++++++++++++-
 drivers/clk/kunit_clk_assigned_rates.h             |  10 ++
 drivers/clk/kunit_clk_assigned_rates_multiple.dtso |   6 +
 ...kunit_clk_assigned_rates_multiple_consumer.dtso |   6 +
 drivers/clk/kunit_clk_assigned_rates_one.dtso      |   3 +
 .../clk/kunit_clk_assigned_rates_one_consumer.dtso |   3 +
 .../clk/kunit_clk_assigned_rates_u64_multiple.dtso |   6 +
 ...t_clk_assigned_rates_u64_multiple_consumer.dtso |   6 +
 drivers/clk/kunit_clk_assigned_rates_u64_one.dtso  |   3 +
 .../kunit_clk_assigned_rates_u64_one_consumer.dtso |   3 +
 drivers/clk/kunit_clk_assigned_sscs_null.dtso      |  16 +++
 .../clk/kunit_clk_assigned_sscs_null_consumer.dtso |  20 ++++
 drivers/clk/kunit_clk_assigned_sscs_without.dtso   |  15 +++
 .../kunit_clk_assigned_sscs_without_consumer.dtso  |  19 ++++
 drivers/clk/kunit_clk_assigned_sscs_zero.dtso      |  12 ++
 .../clk/kunit_clk_assigned_sscs_zero_consumer.dtso |  16 +++
 include/dt-bindings/clock/clock.h                  |  14 +++
 include/linux/clk-provider.h                       |  31 ++++++
 24 files changed, 586 insertions(+), 32 deletions(-)
---
base-commit: cc3aa43b44bdb43dfbac0fcb51c56594a11338a8
change-id: 20251231-clk-ssc-v7-1-402dd4f9e629

Best regards,
-- 
Peng Fan <peng.fan at nxp.com>



From peng.fan at oss.nxp.com  Wed Dec 31 02:12:48 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Wed, 31 Dec 2025 18:12:48 +0800
Subject: [PATCH v7 1/6] dt-bindings: clock: Add spread spectrum definition
In-Reply-To: <20251231-clk-ssc-v7-1-v7-0-380e8b58f9e3@nxp.com>
References: <20251231-clk-ssc-v7-1-v7-0-380e8b58f9e3@nxp.com>
Message-ID: <20251231-clk-ssc-v7-1-v7-1-380e8b58f9e3@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

Per dt-schema, the modulation methods are: down-spread(3), up-spread(2),
center-spread(1), no-spread(0). So define them in dt-bindings to avoid
write the magic number in device tree.

Reviewed-by: Brian Masney <bmasney at redhat.com>
Acked-by: Rob Herring (Arm) <robh at kernel.org>
Reviewed-by: Sebin Francis <sebin.francis at ti.com>
Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 include/dt-bindings/clock/clock.h | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/include/dt-bindings/clock/clock.h b/include/dt-bindings/clock/clock.h
new file mode 100644
index 0000000000000000000000000000000000000000..155e2653a120bf10747bd7f4d47f25e0493e0464
--- /dev/null
+++ b/include/dt-bindings/clock/clock.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
+/*
+ * Copyright 2025 NXP
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_H
+#define __DT_BINDINGS_CLOCK_H
+
+#define CLK_SSC_NO_SPREAD	0
+#define CLK_SSC_CENTER_SPREAD	1
+#define CLK_SSC_UP_SPREAD	2
+#define CLK_SSC_DOWN_SPREAD	3
+
+#endif	/* __DT_BINDINGS_CLOCK_H */

-- 
2.37.1



From peng.fan at oss.nxp.com  Wed Dec 31 02:12:49 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Wed, 31 Dec 2025 18:12:49 +0800
Subject: [PATCH v7 2/6] clk: Introduce clk_hw_set_spread_spectrum
In-Reply-To: <20251231-clk-ssc-v7-1-v7-0-380e8b58f9e3@nxp.com>
References: <20251231-clk-ssc-v7-1-v7-0-380e8b58f9e3@nxp.com>
Message-ID: <20251231-clk-ssc-v7-1-v7-2-380e8b58f9e3@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

Add clk_hw_set_spread_spectrum to configure a clock to enable spread
spectrum feature. set_spread_spectrum ops is added for clk drivers to
have their own hardware specific implementation.

Reviewed-by: Brian Masney <bmasney at redhat.com>
Reviewed-by: Sebin Francis <sebin.francis at ti.com>
Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 drivers/clk/clk.c            | 27 +++++++++++++++++++++++++++
 include/linux/clk-provider.h | 31 +++++++++++++++++++++++++++++++
 2 files changed, 58 insertions(+)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 85d2f2481acf360f0618a4a382fb51250e9c2fc4..6cd941a729590b501d66101e352b99e51ca18464 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -2784,6 +2784,33 @@ int clk_set_max_rate(struct clk *clk, unsigned long rate)
 }
 EXPORT_SYMBOL_GPL(clk_set_max_rate);
 
+int clk_hw_set_spread_spectrum(struct clk_hw *hw, const struct clk_spread_spectrum *ss_conf)
+{
+	struct clk_core *core;
+	int ret;
+
+	if (!hw)
+		return 0;
+
+	core = hw->core;
+
+	clk_prepare_lock();
+
+	ret = clk_pm_runtime_get(core);
+	if (ret)
+		goto fail;
+
+	if (core->ops->set_spread_spectrum)
+		ret = core->ops->set_spread_spectrum(hw, ss_conf);
+
+	clk_pm_runtime_put(core);
+
+fail:
+	clk_prepare_unlock();
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_hw_set_spread_spectrum);
+
 /**
  * clk_get_parent - return the parent of a clk
  * @clk: the clk whose parent gets returned
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 630705a47129453c241f1b1755f2c2f2a7ed8f77..9ec25bbccd613eafd77aca080dd7f51b1bfdadc1 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -6,6 +6,7 @@
 #ifndef __LINUX_CLK_PROVIDER_H
 #define __LINUX_CLK_PROVIDER_H
 
+#include <dt-bindings/clock/clock.h>
 #include <linux/of.h>
 #include <linux/of_clk.h>
 
@@ -84,6 +85,26 @@ struct clk_duty {
 	unsigned int den;
 };
 
+enum clk_ssc_method {
+	CLK_SPREAD_NO		= CLK_SSC_NO_SPREAD,
+	CLK_SPREAD_CENTER	= CLK_SSC_CENTER_SPREAD,
+	CLK_SPREAD_UP		= CLK_SSC_UP_SPREAD,
+	CLK_SPREAD_DOWN		= CLK_SSC_DOWN_SPREAD,
+};
+
+/**
+ * struct clk_spread_spectrum - Structure encoding spread spectrum of a clock
+ *
+ * @modfreq_hz:		Modulation frequency
+ * @spread_bp:		Modulation percent in permyriad
+ * @method:		Modulation method
+ */
+struct clk_spread_spectrum {
+	u32 modfreq_hz;
+	u32 spread_bp;
+	enum clk_ssc_method method;
+};
+
 /**
  * struct clk_ops -  Callback operations for hardware clocks; these are to
  * be provided by the clock implementation, and will be called by drivers
@@ -178,6 +199,12 @@ struct clk_duty {
  *		separately via calls to .set_parent and .set_rate.
  *		Returns 0 on success, -EERROR otherwise.
  *
+ * @set_spread_spectrum: Optional callback used to configure the spread
+ *		spectrum modulation frequency, percentage, and method
+ *		to reduce EMI by spreading the clock frequency over a
+ *		wider range.
+ *		Returns 0 on success, -EERROR otherwise.
+ *
  * @recalc_accuracy: Recalculate the accuracy of this clock. The clock accuracy
  *		is expressed in ppb (parts per billion). The parent accuracy is
  *		an input parameter.
@@ -255,6 +282,8 @@ struct clk_ops {
 	int		(*set_rate_and_parent)(struct clk_hw *hw,
 				    unsigned long rate,
 				    unsigned long parent_rate, u8 index);
+	int		(*set_spread_spectrum)(struct clk_hw *hw,
+					       const struct clk_spread_spectrum *ss_conf);
 	unsigned long	(*recalc_accuracy)(struct clk_hw *hw,
 					   unsigned long parent_accuracy);
 	int		(*get_phase)(struct clk_hw *hw);
@@ -1430,6 +1459,8 @@ void clk_hw_get_rate_range(struct clk_hw *hw, unsigned long *min_rate,
 			   unsigned long *max_rate);
 void clk_hw_set_rate_range(struct clk_hw *hw, unsigned long min_rate,
 			   unsigned long max_rate);
+int clk_hw_set_spread_spectrum(struct clk_hw *hw,
+			       const struct clk_spread_spectrum *ss_conf);
 
 static inline void __clk_hw_set_clk(struct clk_hw *dst, struct clk_hw *src)
 {

-- 
2.37.1



From peng.fan at oss.nxp.com  Wed Dec 31 02:12:50 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Wed, 31 Dec 2025 18:12:50 +0800
Subject: [PATCH v7 3/6] clk: conf: Support assigned-clock-sscs
In-Reply-To: <20251231-clk-ssc-v7-1-v7-0-380e8b58f9e3@nxp.com>
References: <20251231-clk-ssc-v7-1-v7-0-380e8b58f9e3@nxp.com>
Message-ID: <20251231-clk-ssc-v7-1-v7-3-380e8b58f9e3@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

Parse the Spread Spectrum Configuration(SSC) from device tree and configure
them before using the clock.

Each SSC is three u32 elements which means '<modfreq spreaddepth
modmethod>', so assigned-clock-sscs is an array of multiple three u32
elements.

Reviewed-by: Brian Masney <bmasney at redhat.com>
Reviewed-by: Sebin Francis <sebin.francis at ti.com>
Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 drivers/clk/clk-conf.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 75 insertions(+)

diff --git a/drivers/clk/clk-conf.c b/drivers/clk/clk-conf.c
index 303a0bb26e54a95655ce094a35b989c97ebc6fd8..cdc7631f2e159bdaa6829ba5a3b5695dc1c31423 100644
--- a/drivers/clk/clk-conf.c
+++ b/drivers/clk/clk-conf.c
@@ -155,6 +155,77 @@ static int __set_clk_rates(struct device_node *node, bool clk_supplier)
 	return 0;
 }
 
+static int __set_clk_spread_spectrum(struct device_node *node, bool clk_supplier)
+{
+	u32 elem_size = sizeof(struct clk_spread_spectrum);
+	struct clk_spread_spectrum *sscs;
+	struct of_phandle_args clkspec;
+	int rc, count, index;
+	struct clk *clk;
+
+	/* modfreq, spreadPercent, modmethod */
+	count = of_property_count_elems_of_size(node, "assigned-clock-sscs", elem_size);
+	if (count <= 0)
+		return 0;
+
+	sscs = kcalloc(count, elem_size, GFP_KERNEL);
+	if (!sscs)
+		return -ENOMEM;
+
+	rc = of_property_read_u32_array(node, "assigned-clock-sscs", (u32 *)sscs,
+					count * 3);
+	if (rc)
+		goto free_sscs;
+
+	for (index = 0; index < count; index++) {
+		struct clk_spread_spectrum *conf = &sscs[index];
+		struct clk_hw *hw;
+
+		if (!conf->modfreq_hz && !conf->spread_bp && !conf->method)
+			continue;
+
+		rc = of_parse_phandle_with_args(node, "assigned-clocks", "#clock-cells",
+						index, &clkspec);
+		if (rc < 0) {
+			/* skip empty (null) phandles */
+			if (rc == -ENOENT)
+				continue;
+			else
+				goto free_sscs;
+		}
+
+		if (clkspec.np == node && !clk_supplier) {
+			of_node_put(clkspec.np);
+			goto free_sscs;
+		}
+
+		clk = of_clk_get_from_provider(&clkspec);
+		of_node_put(clkspec.np);
+		if (IS_ERR(clk)) {
+			if (PTR_ERR(clk) != -EPROBE_DEFER)
+				pr_warn("clk: couldn't get clock %d for %pOF\n",
+					index, node);
+			rc = PTR_ERR(clk);
+			goto free_sscs;
+		}
+
+		hw = __clk_get_hw(clk);
+		rc = clk_hw_set_spread_spectrum(hw, conf);
+		if (rc < 0) {
+			pr_err("clk: couldn't set %s clk spread spectrum %u %u %u: %d\n",
+			       __clk_get_name(clk), conf->modfreq_hz, conf->spread_bp,
+			       conf->method, rc);
+			/* Do not fail */
+			rc = 0;
+		}
+		clk_put(clk);
+	}
+
+free_sscs:
+	kfree(sscs);
+	return rc;
+}
+
 /**
  * of_clk_set_defaults() - parse and set assigned clocks configuration
  * @node: device node to apply clock settings for
@@ -174,6 +245,10 @@ int of_clk_set_defaults(struct device_node *node, bool clk_supplier)
 	if (!node)
 		return 0;
 
+	rc = __set_clk_spread_spectrum(node, clk_supplier);
+	if (rc < 0)
+		return rc;
+
 	rc = __set_clk_parents(node, clk_supplier);
 	if (rc < 0)
 		return rc;

-- 
2.37.1



From peng.fan at oss.nxp.com  Wed Dec 31 02:12:51 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Wed, 31 Dec 2025 18:12:51 +0800
Subject: [PATCH v7 4/6] clk: Add KUnit tests for assigned-clock-sscs
In-Reply-To: <20251231-clk-ssc-v7-1-v7-0-380e8b58f9e3@nxp.com>
References: <20251231-clk-ssc-v7-1-v7-0-380e8b58f9e3@nxp.com>
Message-ID: <20251231-clk-ssc-v7-1-v7-4-380e8b58f9e3@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

Spread spectrum configuration is part of clock frequency settings,
and its behavior can be validated similarly to assigned clock rates.

Extend the existing KUnit tests for assigned-clock-rates to cover
assigned-clock-sscs by reusing the test framework. Add new test
device trees:
  - kunit_clk_assigned_sscs_null.dtso
  - kunit_clk_assigned_sscs_null_consumer.dtso
  - kunit_clk_assigned_sscs_without.dtso
  - kunit_clk_assigned_sscs_without_consumer.dtso
  - kunit_clk_assigned_sscs_zero.dtso
  - kunit_clk_assigned_sscs_zero_consumer.dtso

These tests cover various invalid configurations of assigned-clock-sscs,
ensuring robustness and consistent error handling, similar to the coverage
provided for assigned-clock-rates.

Co-developed-by: Brian Masney <bmasney at redhat.com>
Signed-off-by: Brian Masney <bmasney at redhat.com>
Reviewed-by: Sebin Francis <sebin.francis at ti.com>
Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 drivers/clk/Makefile                               |   6 +
 drivers/clk/clk_test.c                             | 121 ++++++++++++++++++++-
 drivers/clk/kunit_clk_assigned_rates.h             |  10 ++
 drivers/clk/kunit_clk_assigned_rates_multiple.dtso |   6 +
 ...kunit_clk_assigned_rates_multiple_consumer.dtso |   6 +
 drivers/clk/kunit_clk_assigned_rates_one.dtso      |   3 +
 .../clk/kunit_clk_assigned_rates_one_consumer.dtso |   3 +
 .../clk/kunit_clk_assigned_rates_u64_multiple.dtso |   6 +
 ...t_clk_assigned_rates_u64_multiple_consumer.dtso |   6 +
 drivers/clk/kunit_clk_assigned_rates_u64_one.dtso  |   3 +
 .../kunit_clk_assigned_rates_u64_one_consumer.dtso |   3 +
 drivers/clk/kunit_clk_assigned_sscs_null.dtso      |  16 +++
 .../clk/kunit_clk_assigned_sscs_null_consumer.dtso |  20 ++++
 drivers/clk/kunit_clk_assigned_sscs_without.dtso   |  15 +++
 .../kunit_clk_assigned_sscs_without_consumer.dtso  |  19 ++++
 drivers/clk/kunit_clk_assigned_sscs_zero.dtso      |  12 ++
 .../clk/kunit_clk_assigned_sscs_zero_consumer.dtso |  16 +++
 17 files changed, 268 insertions(+), 3 deletions(-)

diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 61ec08404442b4715dc84a563b3330cb5169f8b2..cb10156db2a37e1956d84113d1711e23d9d864ab 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -18,6 +18,12 @@ clk-test-y			:= clk_test.o \
 				   kunit_clk_assigned_rates_without_consumer.dtbo.o \
 				   kunit_clk_assigned_rates_zero.dtbo.o \
 				   kunit_clk_assigned_rates_zero_consumer.dtbo.o \
+				   kunit_clk_assigned_sscs_null.dtbo.o \
+				   kunit_clk_assigned_sscs_null_consumer.dtbo.o \
+				   kunit_clk_assigned_sscs_without.dtbo.o \
+				   kunit_clk_assigned_sscs_without_consumer.dtbo.o \
+				   kunit_clk_assigned_sscs_zero.dtbo.o \
+				   kunit_clk_assigned_sscs_zero_consumer.dtbo.o \
 				   kunit_clk_hw_get_dev_of_node.dtbo.o \
 				   kunit_clk_parent_data_test.dtbo.o
 obj-$(CONFIG_COMMON_CLK)	+= clk-divider.o
diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c
index a268d7b5d4cb28ec1f029f828c31107f8e130556..97113b61c2841701a44603ca9935638374000a2e 100644
--- a/drivers/clk/clk_test.c
+++ b/drivers/clk/clk_test.c
@@ -28,6 +28,7 @@ static const struct clk_ops empty_clk_ops = { };
 struct clk_dummy_context {
 	struct clk_hw hw;
 	unsigned long rate;
+	struct clk_spread_spectrum sscs;
 };
 
 static unsigned long clk_dummy_recalc_rate(struct clk_hw *hw,
@@ -83,6 +84,17 @@ static int clk_dummy_set_rate(struct clk_hw *hw,
 	return 0;
 }
 
+static int clk_dummy_set_spread_spectrum(struct clk_hw *hw,
+					 const struct clk_spread_spectrum *ss_conf)
+{
+	struct clk_dummy_context *ctx =
+		container_of(hw, struct clk_dummy_context, hw);
+
+	ctx->sscs = *ss_conf;
+
+	return 0;
+}
+
 static int clk_dummy_single_set_parent(struct clk_hw *hw, u8 index)
 {
 	if (index >= clk_hw_get_num_parents(hw))
@@ -100,18 +112,21 @@ static const struct clk_ops clk_dummy_rate_ops = {
 	.recalc_rate = clk_dummy_recalc_rate,
 	.determine_rate = clk_dummy_determine_rate,
 	.set_rate = clk_dummy_set_rate,
+	.set_spread_spectrum = clk_dummy_set_spread_spectrum,
 };
 
 static const struct clk_ops clk_dummy_maximize_rate_ops = {
 	.recalc_rate = clk_dummy_recalc_rate,
 	.determine_rate = clk_dummy_maximize_rate,
 	.set_rate = clk_dummy_set_rate,
+	.set_spread_spectrum = clk_dummy_set_spread_spectrum,
 };
 
 static const struct clk_ops clk_dummy_minimize_rate_ops = {
 	.recalc_rate = clk_dummy_recalc_rate,
 	.determine_rate = clk_dummy_minimize_rate,
 	.set_rate = clk_dummy_set_rate,
+	.set_spread_spectrum = clk_dummy_set_spread_spectrum,
 };
 
 static const struct clk_ops clk_dummy_single_parent_ops = {
@@ -3097,6 +3112,7 @@ struct clk_assigned_rates_context {
  * @overlay_end: Pointer to end of DT overlay to apply for test
  * @rate0: Initial rate of first clk
  * @rate1: Initial rate of second clk
+ * @sscs: Initial spread spectrum settings
  * @consumer_test: true if a consumer is being tested
  */
 struct clk_assigned_rates_test_param {
@@ -3105,6 +3121,7 @@ struct clk_assigned_rates_test_param {
 	u8 *overlay_end;
 	unsigned long rate0;
 	unsigned long rate1;
+	struct clk_spread_spectrum sscs;
 	bool consumer_test;
 };
 
@@ -3116,7 +3133,7 @@ static void
 clk_assigned_rates_register_clk(struct kunit *test,
 				struct clk_dummy_context *ctx,
 				struct device_node *np, const char *name,
-				unsigned long rate)
+				unsigned long rate, const struct clk_spread_spectrum *sscs)
 {
 	struct clk_init_data init = { };
 
@@ -3124,6 +3141,7 @@ clk_assigned_rates_register_clk(struct kunit *test,
 	init.ops = &clk_dummy_rate_ops;
 	ctx->hw.init = &init;
 	ctx->rate = rate;
+	ctx->sscs = *sscs;
 
 	KUNIT_ASSERT_EQ(test, 0, of_clk_hw_register_kunit(test, np, &ctx->hw));
 	KUNIT_ASSERT_EQ(test, ctx->rate, rate);
@@ -3167,14 +3185,16 @@ static int clk_assigned_rates_test_init(struct kunit *test)
 	KUNIT_ASSERT_LT(test, clk_cells, 2);
 
 	clk_assigned_rates_register_clk(test, &ctx->clk0, np,
-					"test_assigned_rate0", test_param->rate0);
+					"test_assigned_rate0", test_param->rate0,
+					&test_param->sscs);
 	if (clk_cells == 0) {
 		KUNIT_ASSERT_EQ(test, 0,
 				of_clk_add_hw_provider_kunit(test, np, of_clk_hw_simple_get,
 							     &ctx->clk0.hw));
 	} else if (clk_cells == 1) {
 		clk_assigned_rates_register_clk(test, &ctx->clk1, np,
-						"test_assigned_rate1", test_param->rate1);
+						"test_assigned_rate1", test_param->rate1,
+						&test_param->sscs);
 
 		KUNIT_ASSERT_NOT_ERR_OR_NULL(test,
 			data = kunit_kzalloc(test, struct_size(data, hws, 2), GFP_KERNEL));
@@ -3203,6 +3223,9 @@ static void clk_assigned_rates_assigns_one(struct kunit *test)
 	struct clk_assigned_rates_context *ctx = test->priv;
 
 	KUNIT_EXPECT_EQ(test, ctx->clk0.rate, ASSIGNED_RATES_0_RATE);
+	KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.modfreq_hz, ASSIGNED_SSCS_0_MODFREQ);
+	KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.spread_bp, ASSIGNED_SSCS_0_SPREAD);
+	KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.method, ASSIGNED_SSCS_0_METHOD);
 }
 
 static void clk_assigned_rates_assigns_multiple(struct kunit *test)
@@ -3210,7 +3233,13 @@ static void clk_assigned_rates_assigns_multiple(struct kunit *test)
 	struct clk_assigned_rates_context *ctx = test->priv;
 
 	KUNIT_EXPECT_EQ(test, ctx->clk0.rate, ASSIGNED_RATES_0_RATE);
+	KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.modfreq_hz, ASSIGNED_SSCS_0_MODFREQ);
+	KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.spread_bp, ASSIGNED_SSCS_0_SPREAD);
+	KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.method, ASSIGNED_SSCS_0_METHOD);
 	KUNIT_EXPECT_EQ(test, ctx->clk1.rate, ASSIGNED_RATES_1_RATE);
+	KUNIT_EXPECT_EQ(test, ctx->clk1.sscs.modfreq_hz, ASSIGNED_SSCS_1_MODFREQ);
+	KUNIT_EXPECT_EQ(test, ctx->clk1.sscs.spread_bp, ASSIGNED_SSCS_1_SPREAD);
+	KUNIT_EXPECT_EQ(test, ctx->clk1.sscs.method, ASSIGNED_SSCS_1_METHOD);
 }
 
 static void clk_assigned_rates_skips(struct kunit *test)
@@ -3222,6 +3251,19 @@ static void clk_assigned_rates_skips(struct kunit *test)
 	KUNIT_EXPECT_EQ(test, ctx->clk0.rate, test_param->rate0);
 }
 
+static void clk_assigned_sscs_skips(struct kunit *test)
+{
+	struct clk_assigned_rates_context *ctx = test->priv;
+	const struct clk_assigned_rates_test_param *test_param = test->param_value;
+
+	KUNIT_EXPECT_NE(test, ctx->clk0.sscs.modfreq_hz, ASSIGNED_SSCS_0_MODFREQ);
+	KUNIT_EXPECT_NE(test, ctx->clk0.sscs.spread_bp, ASSIGNED_SSCS_0_SPREAD);
+	KUNIT_EXPECT_NE(test, ctx->clk0.sscs.method, ASSIGNED_SSCS_0_METHOD);
+	KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.modfreq_hz, test_param->sscs.modfreq_hz);
+	KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.spread_bp, test_param->sscs.spread_bp);
+	KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.method, test_param->sscs.method);
+}
+
 OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_one);
 OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_one_consumer);
 OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_u64_one);
@@ -3384,6 +3426,77 @@ KUNIT_ARRAY_PARAM_DESC(clk_assigned_rates_skips,
 		       clk_assigned_rates_skips_test_params,
 		       desc)
 
+OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_without);
+OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_without_consumer);
+OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_zero);
+OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_zero_consumer);
+OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_null);
+OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_null_consumer);
+
+/* Test cases that skip changing the sscs due to malformed DT */
+static const struct clk_assigned_rates_test_param clk_assigned_sscs_skips_test_params[] = {
+	{
+		/*
+		 * Test that an assigned-clock-sscs property without an assigned-clocks
+		 * property fails when the property is in the provider.
+		 */
+		.desc = "provider missing assigned-clocks",
+		TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_without),
+		.sscs = {50000, 60000, 3},
+	},
+	{
+		/*
+		 * Test that an assigned-clock-rates property without an assigned-clocks
+		 * property fails when the property is in the consumer.
+		 */
+		.desc = "consumer missing assigned-clocks",
+		TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_without_consumer),
+		.sscs = {50000, 60000, 3},
+		.consumer_test = true,
+	},
+	{
+		/*
+		 * Test that an assigned-clock-rates property of zero doesn't
+		 * set a rate when the property is in the provider.
+		 */
+		.desc = "provider assigned-clock-sscs of zero",
+		TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_zero),
+		.sscs = {50000, 60000, 3},
+	},
+	{
+		/*
+		 * Test that an assigned-clock-rates property of zero doesn't
+		 * set a rate when the property is in the consumer.
+		 */
+		.desc = "consumer assigned-clock-sscs of zero",
+		TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_zero_consumer),
+		.sscs = {50000, 60000, 3},
+		.consumer_test = true,
+	},
+	{
+		/*
+		 * Test that an assigned-clocks property with a null phandle
+		 * doesn't set a rate when the property is in the provider.
+		 */
+		.desc = "provider assigned-clocks null phandle",
+		TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_null),
+		.sscs = {50000, 60000, 3},
+	},
+	{
+		/*
+		 * Test that an assigned-clocks property with a null phandle
+		 * doesn't set a rate when the property is in the consumer.
+		 */
+		.desc = "provider assigned-clocks null phandle",
+		TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_null_consumer),
+		.sscs = {50000, 60000, 3},
+		.consumer_test = true,
+	},
+};
+KUNIT_ARRAY_PARAM_DESC(clk_assigned_sscs_skips,
+		       clk_assigned_sscs_skips_test_params,
+		       desc)
+
 static struct kunit_case clk_assigned_rates_test_cases[] = {
 	KUNIT_CASE_PARAM(clk_assigned_rates_assigns_one,
 			 clk_assigned_rates_assigns_one_gen_params),
@@ -3391,6 +3504,8 @@ static struct kunit_case clk_assigned_rates_test_cases[] = {
 			 clk_assigned_rates_assigns_multiple_gen_params),
 	KUNIT_CASE_PARAM(clk_assigned_rates_skips,
 			 clk_assigned_rates_skips_gen_params),
+	KUNIT_CASE_PARAM(clk_assigned_sscs_skips,
+			 clk_assigned_sscs_skips_gen_params),
 	{}
 };
 
diff --git a/drivers/clk/kunit_clk_assigned_rates.h b/drivers/clk/kunit_clk_assigned_rates.h
index df2d84dcaa93511694b6da842debdc3cfd3a6c19..d7ae5ec2d25bed79b8438e8ce580872131ce4286 100644
--- a/drivers/clk/kunit_clk_assigned_rates.h
+++ b/drivers/clk/kunit_clk_assigned_rates.h
@@ -1,8 +1,18 @@
 /* SPDX-License-Identifier: GPL-2.0 */
+
+#include <dt-bindings/clock/clock.h>
+
 #ifndef _KUNIT_CLK_ASSIGNED_RATES_H
 #define _KUNIT_CLK_ASSIGNED_RATES_H
 
 #define ASSIGNED_RATES_0_RATE		1600000
 #define ASSIGNED_RATES_1_RATE		9700000
 
+#define ASSIGNED_SSCS_0_MODFREQ		10000
+#define ASSIGNED_SSCS_0_SPREAD		30000
+#define ASSIGNED_SSCS_0_METHOD		CLK_SSC_CENTER_SPREAD
+#define ASSIGNED_SSCS_1_MODFREQ		20000
+#define ASSIGNED_SSCS_1_SPREAD		40000
+#define ASSIGNED_SSCS_1_METHOD		CLK_SSC_UP_SPREAD
+
 #endif
diff --git a/drivers/clk/kunit_clk_assigned_rates_multiple.dtso b/drivers/clk/kunit_clk_assigned_rates_multiple.dtso
index e600736e70f5041ddeb1bfb0d6074746a064e08a..6c54d65444d5d779c9fa4bb2a79c4742dd88f6d0 100644
--- a/drivers/clk/kunit_clk_assigned_rates_multiple.dtso
+++ b/drivers/clk/kunit_clk_assigned_rates_multiple.dtso
@@ -12,5 +12,11 @@ clk: kunit-clock {
 				  <&clk 1>;
 		assigned-clock-rates = <ASSIGNED_RATES_0_RATE>,
 				       <ASSIGNED_RATES_1_RATE>;
+		assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+				       ASSIGNED_SSCS_0_SPREAD
+				       ASSIGNED_SSCS_0_METHOD>,
+				      <ASSIGNED_SSCS_1_MODFREQ
+				       ASSIGNED_SSCS_1_SPREAD
+				       ASSIGNED_SSCS_1_METHOD>;
 	};
 };
diff --git a/drivers/clk/kunit_clk_assigned_rates_multiple_consumer.dtso b/drivers/clk/kunit_clk_assigned_rates_multiple_consumer.dtso
index 260aba458daf2bc57fde46b5442453e7de10faac..b1fee396c4b1e51341a411168569d8351bb23b12 100644
--- a/drivers/clk/kunit_clk_assigned_rates_multiple_consumer.dtso
+++ b/drivers/clk/kunit_clk_assigned_rates_multiple_consumer.dtso
@@ -16,5 +16,11 @@ kunit-clock-consumer {
 				  <&clk 1>;
 		assigned-clock-rates = <ASSIGNED_RATES_0_RATE>,
 				       <ASSIGNED_RATES_1_RATE>;
+		assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+				       ASSIGNED_SSCS_0_SPREAD
+				       ASSIGNED_SSCS_0_METHOD>,
+				      <ASSIGNED_SSCS_1_MODFREQ
+				       ASSIGNED_SSCS_1_SPREAD
+				       ASSIGNED_SSCS_1_METHOD>;
 	};
 };
diff --git a/drivers/clk/kunit_clk_assigned_rates_one.dtso b/drivers/clk/kunit_clk_assigned_rates_one.dtso
index dd95ec9b1cf977883f71564a94602ae518937132..da6e91b9e6bda0ef2c8f601a08aef1f10fda4baa 100644
--- a/drivers/clk/kunit_clk_assigned_rates_one.dtso
+++ b/drivers/clk/kunit_clk_assigned_rates_one.dtso
@@ -10,5 +10,8 @@ clk: kunit-clock {
 		#clock-cells = <0>;
 		assigned-clocks = <&clk>;
 		assigned-clock-rates = <ASSIGNED_RATES_0_RATE>;
+		assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+				       ASSIGNED_SSCS_0_SPREAD
+				       ASSIGNED_SSCS_0_METHOD>;
 	};
 };
diff --git a/drivers/clk/kunit_clk_assigned_rates_one_consumer.dtso b/drivers/clk/kunit_clk_assigned_rates_one_consumer.dtso
index a41dca806318b031187c1b8739fcf71eb088a480..4b6e06048f863d014aed8222652d6d9d38e9238b 100644
--- a/drivers/clk/kunit_clk_assigned_rates_one_consumer.dtso
+++ b/drivers/clk/kunit_clk_assigned_rates_one_consumer.dtso
@@ -14,5 +14,8 @@ kunit-clock-consumer {
 		compatible = "test,clk-consumer";
 		assigned-clocks = <&clk>;
 		assigned-clock-rates = <ASSIGNED_RATES_0_RATE>;
+		assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+				       ASSIGNED_SSCS_0_SPREAD
+				       ASSIGNED_SSCS_0_METHOD>;
 	};
 };
diff --git a/drivers/clk/kunit_clk_assigned_rates_u64_multiple.dtso b/drivers/clk/kunit_clk_assigned_rates_u64_multiple.dtso
index 389b4e2eb7f74f1770ff5f5c4be5b45dd344dc9c..3a717dab2d00b7fdaff580e30ed2cc520683ef95 100644
--- a/drivers/clk/kunit_clk_assigned_rates_u64_multiple.dtso
+++ b/drivers/clk/kunit_clk_assigned_rates_u64_multiple.dtso
@@ -12,5 +12,11 @@ clk: kunit-clock {
 				  <&clk 1>;
 		assigned-clock-rates-u64 = /bits/ 64 <ASSIGNED_RATES_0_RATE>,
 					   /bits/ 64 <ASSIGNED_RATES_1_RATE>;
+		assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+				       ASSIGNED_SSCS_0_SPREAD
+				       ASSIGNED_SSCS_0_METHOD>,
+				      <ASSIGNED_SSCS_1_MODFREQ
+				       ASSIGNED_SSCS_1_SPREAD
+				       ASSIGNED_SSCS_1_METHOD>;
 	};
 };
diff --git a/drivers/clk/kunit_clk_assigned_rates_u64_multiple_consumer.dtso b/drivers/clk/kunit_clk_assigned_rates_u64_multiple_consumer.dtso
index 3e117fd59b7da19cd8a603af77eff29175ce6900..cbee7cbad068f3336f0c8997a5b3e9af4db565c9 100644
--- a/drivers/clk/kunit_clk_assigned_rates_u64_multiple_consumer.dtso
+++ b/drivers/clk/kunit_clk_assigned_rates_u64_multiple_consumer.dtso
@@ -16,5 +16,11 @@ kunit-clock-consumer {
 				  <&clk 1>;
 		assigned-clock-rates-u64 = /bits/ 64 <ASSIGNED_RATES_0_RATE>,
 					   /bits/ 64 <ASSIGNED_RATES_1_RATE>;
+		assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+				       ASSIGNED_SSCS_0_SPREAD
+				       ASSIGNED_SSCS_0_METHOD>,
+				      <ASSIGNED_SSCS_1_MODFREQ
+				       ASSIGNED_SSCS_1_SPREAD
+				       ASSIGNED_SSCS_1_METHOD>;
 	};
 };
diff --git a/drivers/clk/kunit_clk_assigned_rates_u64_one.dtso b/drivers/clk/kunit_clk_assigned_rates_u64_one.dtso
index 87041264e8f544dafddf2e905efc89dc1f917c54..9b04d6927f0830a5621af1cbea503a427b46bee0 100644
--- a/drivers/clk/kunit_clk_assigned_rates_u64_one.dtso
+++ b/drivers/clk/kunit_clk_assigned_rates_u64_one.dtso
@@ -10,5 +10,8 @@ clk: kunit-clock {
 		#clock-cells = <0>;
 		assigned-clocks = <&clk>;
 		assigned-clock-rates-u64 = /bits/ 64 <ASSIGNED_RATES_0_RATE>;
+		assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+				       ASSIGNED_SSCS_0_SPREAD
+				       ASSIGNED_SSCS_0_METHOD>;
 	};
 };
diff --git a/drivers/clk/kunit_clk_assigned_rates_u64_one_consumer.dtso b/drivers/clk/kunit_clk_assigned_rates_u64_one_consumer.dtso
index 3259c003aec0be3269ab60a4a3a95df69f8de1f8..4784d40520f4193e4f08c8981386f0772a063452 100644
--- a/drivers/clk/kunit_clk_assigned_rates_u64_one_consumer.dtso
+++ b/drivers/clk/kunit_clk_assigned_rates_u64_one_consumer.dtso
@@ -14,5 +14,8 @@ kunit-clock-consumer {
 		compatible = "test,clk-consumer";
 		assigned-clocks = <&clk>;
 		assigned-clock-rates-u64 = /bits/ 64 <ASSIGNED_RATES_0_RATE>;
+		assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+				       ASSIGNED_SSCS_0_SPREAD
+				       ASSIGNED_SSCS_0_METHOD>;
 	};
 };
diff --git a/drivers/clk/kunit_clk_assigned_sscs_null.dtso b/drivers/clk/kunit_clk_assigned_sscs_null.dtso
new file mode 100644
index 0000000000000000000000000000000000000000..43b2068c845dea53ea1328bb63a2f58a4b8ef339
--- /dev/null
+++ b/drivers/clk/kunit_clk_assigned_sscs_null.dtso
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+#include "kunit_clk_assigned_rates.h"
+
+&{/} {
+	clk: kunit-clock {
+		compatible = "test,clk-assigned-rates";
+		#clock-cells = <0>;
+		assigned-clocks = <0>;
+		assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+				       ASSIGNED_SSCS_0_SPREAD
+				       ASSIGNED_SSCS_0_METHOD>;
+	};
+};
diff --git a/drivers/clk/kunit_clk_assigned_sscs_null_consumer.dtso b/drivers/clk/kunit_clk_assigned_sscs_null_consumer.dtso
new file mode 100644
index 0000000000000000000000000000000000000000..bda008f5aaa35e53af97863e4f2e6d8a168cc053
--- /dev/null
+++ b/drivers/clk/kunit_clk_assigned_sscs_null_consumer.dtso
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+#include "kunit_clk_assigned_rates.h"
+
+&{/} {
+	clk: kunit-clock {
+		compatible = "test,clk-assigned-rates";
+		#clock-cells = <0>;
+	};
+
+	kunit-clock-consumer {
+		compatible = "test,clk-consumer";
+		assigned-clocks = <0>;
+		assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+				       ASSIGNED_SSCS_0_SPREAD
+				       ASSIGNED_SSCS_0_METHOD>;
+	};
+};
diff --git a/drivers/clk/kunit_clk_assigned_sscs_without.dtso b/drivers/clk/kunit_clk_assigned_sscs_without.dtso
new file mode 100644
index 0000000000000000000000000000000000000000..08660846b55c12122bfb211c01c377a3a45223c9
--- /dev/null
+++ b/drivers/clk/kunit_clk_assigned_sscs_without.dtso
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+#include "kunit_clk_assigned_rates.h"
+
+&{/} {
+	clk: kunit-clock {
+		compatible = "test,clk-assigned-rates";
+		#clock-cells = <0>;
+		assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+				       ASSIGNED_SSCS_0_SPREAD
+				       ASSIGNED_SSCS_0_METHOD>;
+	};
+};
diff --git a/drivers/clk/kunit_clk_assigned_sscs_without_consumer.dtso b/drivers/clk/kunit_clk_assigned_sscs_without_consumer.dtso
new file mode 100644
index 0000000000000000000000000000000000000000..e1c089c6f0c0223f16f7ac9a396e7ac7b821c967
--- /dev/null
+++ b/drivers/clk/kunit_clk_assigned_sscs_without_consumer.dtso
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+#include "kunit_clk_assigned_rates.h"
+
+&{/} {
+	clk: kunit-clock {
+		compatible = "test,clk-assigned-rates";
+		#clock-cells = <0>;
+	};
+
+	kunit-clock-consumer {
+		compatible = "test,clk-consumer";
+		assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+				       ASSIGNED_SSCS_0_SPREAD
+				       ASSIGNED_SSCS_0_METHOD>;
+	};
+};
diff --git a/drivers/clk/kunit_clk_assigned_sscs_zero.dtso b/drivers/clk/kunit_clk_assigned_sscs_zero.dtso
new file mode 100644
index 0000000000000000000000000000000000000000..f39f4e754e532c9c1b1fdf034700e5af1f3f0779
--- /dev/null
+++ b/drivers/clk/kunit_clk_assigned_sscs_zero.dtso
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+&{/} {
+	clk: kunit-clock {
+		compatible = "test,clk-assigned-rates";
+		#clock-cells = <0>;
+		assigned-clocks = <&clk>;
+		assigned-clock-sscs = <0 0 0>;
+	};
+};
diff --git a/drivers/clk/kunit_clk_assigned_sscs_zero_consumer.dtso b/drivers/clk/kunit_clk_assigned_sscs_zero_consumer.dtso
new file mode 100644
index 0000000000000000000000000000000000000000..d6bd7dfada7e2f455cb23e483b9bd6ce24839e3a
--- /dev/null
+++ b/drivers/clk/kunit_clk_assigned_sscs_zero_consumer.dtso
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+&{/} {
+	clk: kunit-clock {
+		compatible = "test,clk-assigned-rates";
+		#clock-cells = <0>;
+	};
+
+	kunit-clock-consumer {
+		compatible = "test,clk-consumer";
+		assigned-clocks = <&clk>;
+		assigned-clock-sscs = <0 0 0>;
+	};
+};

-- 
2.37.1



From peng.fan at oss.nxp.com  Wed Dec 31 02:12:52 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Wed, 31 Dec 2025 18:12:52 +0800
Subject: [PATCH v7 5/6] clk: scmi: Introduce common header for SCMI clock
 interface
In-Reply-To: <20251231-clk-ssc-v7-1-v7-0-380e8b58f9e3@nxp.com>
References: <20251231-clk-ssc-v7-1-v7-0-380e8b58f9e3@nxp.com>
Message-ID: <20251231-clk-ssc-v7-1-v7-5-380e8b58f9e3@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

Added a new header file 'clk-scmi.h' to define common structures and
interfaces for the SCMI clock driver. This header will also be used by
OEM-specific extensions to ensure consistency and reusability.

Moved relevant structure definitions from the driver implementation to
'clk-scmi.h' to facilitate shared usage.

Reviewed-by: Sebin Francis <sebin.francis at ti.com>
Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 drivers/clk/clk-scmi.c | 27 +--------------------------
 drivers/clk/clk-scmi.h | 40 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 41 insertions(+), 26 deletions(-)

diff --git a/drivers/clk/clk-scmi.c b/drivers/clk/clk-scmi.c
index 6b286ea6f1218c802d0ebb782c75a19057581c20..bf85924d61985eb9e596419349eb883e3817de73 100644
--- a/drivers/clk/clk-scmi.c
+++ b/drivers/clk/clk-scmi.c
@@ -14,32 +14,7 @@
 #include <linux/scmi_protocol.h>
 #include <asm/div64.h>
 
-#define NOT_ATOMIC	false
-#define ATOMIC		true
-
-enum scmi_clk_feats {
-	SCMI_CLK_ATOMIC_SUPPORTED,
-	SCMI_CLK_STATE_CTRL_SUPPORTED,
-	SCMI_CLK_RATE_CTRL_SUPPORTED,
-	SCMI_CLK_PARENT_CTRL_SUPPORTED,
-	SCMI_CLK_DUTY_CYCLE_SUPPORTED,
-	SCMI_CLK_FEATS_COUNT
-};
-
-#define SCMI_MAX_CLK_OPS	BIT(SCMI_CLK_FEATS_COUNT)
-
-static const struct scmi_clk_proto_ops *scmi_proto_clk_ops;
-
-struct scmi_clk {
-	u32 id;
-	struct device *dev;
-	struct clk_hw hw;
-	const struct scmi_clock_info *info;
-	const struct scmi_protocol_handle *ph;
-	struct clk_parent_data *parent_data;
-};
-
-#define to_scmi_clk(clk) container_of(clk, struct scmi_clk, hw)
+const struct scmi_clk_proto_ops *scmi_proto_clk_ops;
 
 static unsigned long scmi_clk_recalc_rate(struct clk_hw *hw,
 					  unsigned long parent_rate)
diff --git a/drivers/clk/clk-scmi.h b/drivers/clk/clk-scmi.h
new file mode 100644
index 0000000000000000000000000000000000000000..6ef6adc77c836dc2d599ff852cdc941f217ee388
--- /dev/null
+++ b/drivers/clk/clk-scmi.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *  Copyright 2025 NXP
+ */
+
+#ifndef __SCMI_CLK_H
+#define __SCMI_CLK_H
+
+#include <linux/bits.h>
+#include <linux/scmi_protocol.h>
+#include <linux/types.h>
+
+#define NOT_ATOMIC	false
+#define ATOMIC		true
+
+enum scmi_clk_feats {
+	SCMI_CLK_ATOMIC_SUPPORTED,
+	SCMI_CLK_STATE_CTRL_SUPPORTED,
+	SCMI_CLK_RATE_CTRL_SUPPORTED,
+	SCMI_CLK_PARENT_CTRL_SUPPORTED,
+	SCMI_CLK_DUTY_CYCLE_SUPPORTED,
+	SCMI_CLK_FEATS_COUNT
+};
+
+#define SCMI_MAX_CLK_OPS	BIT(SCMI_CLK_FEATS_COUNT)
+
+struct scmi_clk {
+	u32 id;
+	struct device *dev;
+	struct clk_hw hw;
+	const struct scmi_clock_info *info;
+	const struct scmi_protocol_handle *ph;
+	struct clk_parent_data *parent_data;
+};
+
+#define to_scmi_clk(clk) container_of(clk, struct scmi_clk, hw)
+
+extern const struct scmi_clk_proto_ops *scmi_proto_clk_ops;
+
+#endif

-- 
2.37.1



From peng.fan at oss.nxp.com  Wed Dec 31 02:12:53 2025
From: peng.fan at oss.nxp.com (Peng Fan (OSS))
Date: Wed, 31 Dec 2025 18:12:53 +0800
Subject: [PATCH v7 6/6] clk: scmi: Add i.MX95 OEM extension support for
 SCMI clock driver
In-Reply-To: <20251231-clk-ssc-v7-1-v7-0-380e8b58f9e3@nxp.com>
References: <20251231-clk-ssc-v7-1-v7-0-380e8b58f9e3@nxp.com>
Message-ID: <20251231-clk-ssc-v7-1-v7-6-380e8b58f9e3@nxp.com>

From: Peng Fan <peng.fan at nxp.com>

 - Introduce 'clk-scmi-oem.c' to support vendor-specific OEM extensions
   for the SCMI clock driver, allows clean integration of vendor-specific
   features without impacting the core SCMI clock driver logic.
 - Extend 'clk-scmi.h' with 'scmi_clk_oem' structure and related
   declarations.
 - Initialize OEM extensions via 'scmi_clk_oem_init()'.
 - Support querying OEM-specific features and setting spread spectrum.
 - Pass 'scmi_device' to 'scmi_clk_ops_select()' for OEM data access.

Reviewed-by: Sebin Francis <sebin.francis at ti.com>
Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 drivers/clk/Makefile       |   2 +-
 drivers/clk/clk-scmi-oem.c | 103 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/clk-scmi.c     |  19 +++++++--
 drivers/clk/clk-scmi.h     |  11 +++++
 4 files changed, 131 insertions(+), 4 deletions(-)

diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index cb10156db2a37e1956d84113d1711e23d9d864ab..8e0e03a79f793ffab6c8636b7796c067287e1712 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -95,7 +95,7 @@ obj-$(CONFIG_COMMON_CLK_RP1)            += clk-rp1.o
 obj-$(CONFIG_COMMON_CLK_RPMI)		+= clk-rpmi.o
 obj-$(CONFIG_COMMON_CLK_HI655X)		+= clk-hi655x.o
 obj-$(CONFIG_COMMON_CLK_S2MPS11)	+= clk-s2mps11.o
-obj-$(CONFIG_COMMON_CLK_SCMI)           += clk-scmi.o
+obj-$(CONFIG_COMMON_CLK_SCMI)           += clk-scmi.o clk-scmi-oem.o
 obj-$(CONFIG_COMMON_CLK_SCPI)           += clk-scpi.o
 obj-$(CONFIG_COMMON_CLK_SI5341)		+= clk-si5341.o
 obj-$(CONFIG_COMMON_CLK_SI5351)		+= clk-si5351.o
diff --git a/drivers/clk/clk-scmi-oem.c b/drivers/clk/clk-scmi-oem.c
new file mode 100644
index 0000000000000000000000000000000000000000..fd81aca7bfca254669ee117ebd51e481a74cdcb4
--- /dev/null
+++ b/drivers/clk/clk-scmi-oem.c
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * The Vendor OEM extension for System Control and Power Interface (SCMI)
+ * Protocol based clock driver
+ *
+ * Copyright 2025 NXP
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/scmi_imx_protocol.h>
+#include <linux/scmi_protocol.h>
+
+#include "clk-scmi.h"
+
+#define SCMI_CLOCK_CFG_IMX_SSC			0x80
+#define SCMI_CLOCK_IMX_SS_PERCENTAGE_MASK	GENMASK(7, 0)
+#define SCMI_CLOCK_IMX_SS_MOD_FREQ_MASK		GENMASK(23, 8)
+#define SCMI_CLOCK_IMX_SS_ENABLE_MASK		BIT(24)
+
+struct scmi_clk_oem_info {
+	char *vendor_id;
+	char *sub_vendor_id;
+	char *compatible;
+	const void *data;
+};
+
+static int
+scmi_clk_imx_set_spread_spectrum(struct clk_hw *hw,
+				 const struct clk_spread_spectrum *ss_conf)
+{
+	struct scmi_clk *clk = to_scmi_clk(hw);
+	int ret;
+	u32 val;
+
+	/*
+	 * extConfigValue[7:0]   - spread percentage (%)
+	 * extConfigValue[23:8]  - Modulation Frequency
+	 * extConfigValue[24]    - Enable/Disable
+	 * extConfigValue[31:25] - Reserved
+	 */
+	val = FIELD_PREP(SCMI_CLOCK_IMX_SS_PERCENTAGE_MASK, ss_conf->spread_bp / 10000);
+	val |= FIELD_PREP(SCMI_CLOCK_IMX_SS_MOD_FREQ_MASK, ss_conf->modfreq_hz);
+	if (ss_conf->method != CLK_SPREAD_NO)
+		val |= SCMI_CLOCK_IMX_SS_ENABLE_MASK;
+	ret = scmi_proto_clk_ops->config_oem_set(clk->ph, clk->id,
+						 SCMI_CLOCK_CFG_IMX_SSC,
+						 val, false);
+	if (ret)
+		dev_warn(clk->dev,
+			 "Failed to set spread spectrum(%u,%u,%u) for clock ID %d\n",
+			 ss_conf->modfreq_hz, ss_conf->spread_bp, ss_conf->method,
+			 clk->id);
+
+	return ret;
+}
+
+static int
+scmi_clk_imx_query_oem_feats(const struct scmi_protocol_handle *ph, u32 id,
+			     unsigned int *feats_key)
+{
+	int ret;
+	u32 val;
+
+	ret = scmi_proto_clk_ops->config_oem_get(ph, id,
+						 SCMI_CLOCK_CFG_IMX_SSC,
+						 &val, NULL, false);
+	if (!ret)
+		*feats_key |= BIT(SCMI_CLK_EXT_OEM_SSC_SUPPORTED);
+
+	return 0;
+}
+
+static const struct scmi_clk_oem scmi_clk_oem_imx = {
+	.query_ext_oem_feats = scmi_clk_imx_query_oem_feats,
+	.set_spread_spectrum = scmi_clk_imx_set_spread_spectrum,
+};
+
+const struct scmi_clk_oem_info info[] = {
+	{ SCMI_IMX_VENDOR, SCMI_IMX_SUBVENDOR, NULL, &scmi_clk_oem_imx },
+};
+
+int scmi_clk_oem_init(struct scmi_device *sdev)
+{
+	const struct scmi_handle *handle = sdev->handle;
+	int i, size = ARRAY_SIZE(info);
+
+	for (i = 0; i < size; i++) {
+		if (strcmp(handle->version->vendor_id, info[i].vendor_id) ||
+		    strcmp(handle->version->sub_vendor_id, info[i].sub_vendor_id))
+			continue;
+		if (info[i].compatible &&
+		    !of_machine_is_compatible(info[i].compatible))
+			continue;
+
+		break;
+	}
+
+	if (i < size)
+		dev_set_drvdata(&sdev->dev, (void *)info[i].data);
+
+	return 0;
+}
diff --git a/drivers/clk/clk-scmi.c b/drivers/clk/clk-scmi.c
index bf85924d61985eb9e596419349eb883e3817de73..1ed2091e3d4a951c8662db4c94dee4b9c98b8326 100644
--- a/drivers/clk/clk-scmi.c
+++ b/drivers/clk/clk-scmi.c
@@ -14,6 +14,8 @@
 #include <linux/scmi_protocol.h>
 #include <asm/div64.h>
 
+#include "clk-scmi.h"
+
 const struct scmi_clk_proto_ops *scmi_proto_clk_ops;
 
 static unsigned long scmi_clk_recalc_rate(struct clk_hw *hw,
@@ -242,6 +244,7 @@ static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk,
 static const struct clk_ops *
 scmi_clk_ops_alloc(struct device *dev, unsigned long feats_key)
 {
+	struct scmi_clk_oem *oem_data = dev_get_drvdata(dev);
 	struct clk_ops *ops;
 
 	ops = devm_kzalloc(dev, sizeof(*ops), GFP_KERNEL);
@@ -288,11 +291,15 @@ scmi_clk_ops_alloc(struct device *dev, unsigned long feats_key)
 		ops->set_duty_cycle = scmi_clk_set_duty_cycle;
 	}
 
+	if (oem_data && (feats_key & BIT(SCMI_CLK_EXT_OEM_SSC_SUPPORTED)))
+		ops->set_spread_spectrum = oem_data->set_spread_spectrum;
+
 	return ops;
 }
 
 /**
  * scmi_clk_ops_select() - Select a proper set of clock operations
+ * @sdev: pointer to the SCMI device
  * @sclk: A reference to an SCMI clock descriptor
  * @atomic_capable: A flag to indicate if atomic mode is supported by the
  *		    transport
@@ -317,8 +324,8 @@ scmi_clk_ops_alloc(struct device *dev, unsigned long feats_key)
  *	   NULL otherwise.
  */
 static const struct clk_ops *
-scmi_clk_ops_select(struct scmi_clk *sclk, bool atomic_capable,
-		    unsigned int atomic_threshold_us,
+scmi_clk_ops_select(struct scmi_device *sdev, struct scmi_clk *sclk,
+		    bool atomic_capable, unsigned int atomic_threshold_us,
 		    const struct clk_ops **clk_ops_db, size_t db_size)
 {
 	int ret;
@@ -326,6 +333,7 @@ scmi_clk_ops_select(struct scmi_clk *sclk, bool atomic_capable,
 	const struct scmi_clock_info *ci = sclk->info;
 	unsigned int feats_key = 0;
 	const struct clk_ops *ops;
+	struct scmi_clk_oem *oem_data = dev_get_drvdata(&sdev->dev);
 
 	/*
 	 * Note that when transport is atomic but SCMI protocol did not
@@ -350,6 +358,9 @@ scmi_clk_ops_select(struct scmi_clk *sclk, bool atomic_capable,
 						 &val, NULL, false);
 		if (!ret)
 			feats_key |= BIT(SCMI_CLK_DUTY_CYCLE_SUPPORTED);
+
+		if (oem_data && oem_data->query_ext_oem_feats)
+			oem_data->query_ext_oem_feats(sclk->ph, sclk->id, &feats_key);
 	}
 
 	if (WARN_ON(feats_key >= db_size))
@@ -407,6 +418,8 @@ static int scmi_clocks_probe(struct scmi_device *sdev)
 	clk_data->num = count;
 	hws = clk_data->hws;
 
+	scmi_clk_oem_init(sdev);
+
 	transport_is_atomic = handle->is_transport_atomic(handle,
 							  &atomic_threshold_us);
 
@@ -438,7 +451,7 @@ static int scmi_clocks_probe(struct scmi_device *sdev)
 		 * to avoid sharing the devm_ allocated clk_ops between multiple
 		 * SCMI clk driver instances.
 		 */
-		scmi_ops = scmi_clk_ops_select(sclk, transport_is_atomic,
+		scmi_ops = scmi_clk_ops_select(sdev, sclk, transport_is_atomic,
 					       atomic_threshold_us,
 					       scmi_clk_ops_db,
 					       ARRAY_SIZE(scmi_clk_ops_db));
diff --git a/drivers/clk/clk-scmi.h b/drivers/clk/clk-scmi.h
index 6ef6adc77c836dc2d599ff852cdc941f217ee388..d7f63f36c56d155f728325efd6bcf7fe2585b170 100644
--- a/drivers/clk/clk-scmi.h
+++ b/drivers/clk/clk-scmi.h
@@ -7,6 +7,7 @@
 #define __SCMI_CLK_H
 
 #include <linux/bits.h>
+#include <linux/clk-provider.h>
 #include <linux/scmi_protocol.h>
 #include <linux/types.h>
 
@@ -19,6 +20,7 @@ enum scmi_clk_feats {
 	SCMI_CLK_RATE_CTRL_SUPPORTED,
 	SCMI_CLK_PARENT_CTRL_SUPPORTED,
 	SCMI_CLK_DUTY_CYCLE_SUPPORTED,
+	SCMI_CLK_EXT_OEM_SSC_SUPPORTED,
 	SCMI_CLK_FEATS_COUNT
 };
 
@@ -37,4 +39,13 @@ struct scmi_clk {
 
 extern const struct scmi_clk_proto_ops *scmi_proto_clk_ops;
 
+struct scmi_clk_oem {
+	int (*query_ext_oem_feats)(const struct scmi_protocol_handle *ph,
+				   u32 id, unsigned int *feats_key);
+	int (*set_spread_spectrum)(struct clk_hw *hw,
+				   const struct clk_spread_spectrum *ss_conf);
+};
+
+int scmi_clk_oem_init(struct scmi_device *dev);
+
 #endif

-- 
2.37.1



From daniel at 0x0f.com  Wed Dec 31 02:17:48 2025
From: daniel at 0x0f.com (Daniel Palmer)
Date: Wed, 31 Dec 2025 19:17:48 +0900
Subject: [PATCH 3/5] arm: dts: mstar: infinity: Correct opp table name
In-Reply-To: <499ce4ea-c6bf-45f1-ab68-c37397196084@kernel.org>
References: <20251231025502.1139168-1-daniel@0x0f.com> <20251231025502.1139168-4-daniel@0x0f.com>
 <ac0f8b8d-f6e4-4d60-9931-e820417c1abc@kernel.org> <CAFr9PXn_-Ep9HzwTEErZ4Wmm9X8Q2ZkRP1LfmaAMhbYNfJVFuQ@mail.gmail.com>
 <499ce4ea-c6bf-45f1-ab68-c37397196084@kernel.org>
Message-ID: <CAFr9PXkn=ZMd6v=yX_KbfynKq7quBKUnCBDJBaU0LyYYMbKEXA@mail.gmail.com>

Hi Krzysztof,

On Wed, 31 Dec 2025 at 18:48, Krzysztof Kozlowski <krzk at kernel.org> wrote:
> I meant, two commits should be rather squashed. If you intend to rename
> the nodes, fix all names to be generic, not only some.

There are 3 commits that correct node names:
arm: dts: mstar: breadbee: Correct regulator names
arm: dts: mstar: breadbee: Correct LED names
arm: dts: mstar: infinity: Correct opp table name

The top two are in the same dts board file, the bottom one is in a
different dtsi file for a chip family.
Should I squash all of them into one commit, squash the top two for
the same board into one commit?

Cheers,

Daniel


From linux at weissschuh.net  Wed Dec 31 02:36:00 2025
From: linux at weissschuh.net (Thomas =?utf-8?Q?Wei=C3=9Fschuh?=)
Date: Wed, 31 Dec 2025 11:36:00 +0100
Subject: Linux 6.19-rc1 mediatek mt7921e broke badly
In-Reply-To: <c1304430-dd7d-437b-8744-70af9ca85c0d@linuxfoundation.org>
References: <d7f3b00d-beec-41f0-b157-7cfb871f9a46@linuxfoundation.org>
 <756e3f65-b2f2-4da3-985a-17754a7a872d@t-8ch.de>
 <CAHk-=wjO-7uR5HBi-MFnkxAxjhpgfbAQ+HCMKPiXFVwM+AJ7tA@mail.gmail.com>
 <6fc04df5-b753-4b2d-b978-0e59a7f48ff7@linux.dev>
 <c1304430-dd7d-437b-8744-70af9ca85c0d@linuxfoundation.org>
Message-ID: <8c8c8f27-ba44-48eb-96f6-dae6d2d0cbf8@t-8ch.de>

On 2025-12-30 16:57:20-0700, Shuah Khan wrote:
> On 12/29/25 21:21, Matthew Schwartz wrote:
> > On 12/29/25 4:41 PM, Linus Torvalds wrote:
> > > On Sat, 27 Dec 2025 at 04:25, Thomas Wei?schuh <linux at weissschuh.net> wrote:
> > > > 
> > > > Hi Shuah,
> > > > 
> > > > On 2025-12-27 02:07:24-0700, Shuah Khan wrote:
> > > > > mt7921e doesn't load on my primary laptopn on Linux 6.19-rc1 and problem
> > > > > still there on 6.19-rc2.
> > > > 
> > > > This should be a duplicate of
> > > > https://lore.kernel.org/all/CABXGCsMeAZyNJ-Axt_CUCXgyieWPV3rrcLpWsveMPT8R0YPGnQ at mail.gmail.com/

(...)
 
> Reverting the following fixed my problem.
> f804a5895eba ("wifi: mt76: Strip whitespace from build ddate")
> 
> The above fixes an extra newline in the dmesg by making the
> code more complex it needs to introducing local buffers and
> strscpy() - the proposed fix replaces this with memcpy().
> 
> Is there a simple way to do this than introducing memcpy()
> or strscpy() to remove an extra newline that might or might
> not exist? Why not check if newline exists or not using
> strstr()?

We do have memtostr() which would be a perfect fit to use here.
That is still a memcpy() under the hood, but the code is clear and safe.
It does however require the source to be annotated as __nonstring.
Which also seems to be the right choice here anyways. However for
consistency, all other similar fields should also be annotated in the
same way. So it is a bit of a larger change than a pure bugfix.


Thomas


From j at jannau.net  Wed Dec 31 02:41:32 2025
From: j at jannau.net (Janne Grunau)
Date: Wed, 31 Dec 2025 11:41:32 +0100
Subject: [PATCH] spmi: apple: Add "apple,t8103-spmi" compatible
Message-ID: <20251231-spmi-apple-t8103-base-compat-v1-1-98da572086f9@jannau.net>

After discussion with the devicetree maintainers we agreed to not extend
lists with the generic compatible "apple,spmi" anymore [1]. Use
"apple,t8103-spmi" as base compatible as it is the SoC the driver and
bindings were written for.

[1]: https://lore.kernel.org/asahi/12ab93b7-1fc2-4ce0-926e-c8141cfe81bf at kernel.org/

Fixes: 77ca75e80c71 ("spmi: add a spmi driver for Apple SoC")
Cc: stable at vger.kernel.org
Reviewed-by: Neal Gompa <neal at gompa.dev>
Signed-off-by: Janne Grunau <j at jannau.net>
---
This is split off from the v1 series adding Apple M2 Pro/Max/Ultra
device trees in [2].

2: https://lore.kernel.org/r/20250828-dt-apple-t6020-v1-0-507ba4c4b98e at jannau.net
---
 drivers/spmi/spmi-apple-controller.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/spmi/spmi-apple-controller.c b/drivers/spmi/spmi-apple-controller.c
index 697b3e8bb023566f17911fc222666d84f5e14c91..87e3ee9d4f2aa5517808827f5dd365055c08446a 100644
--- a/drivers/spmi/spmi-apple-controller.c
+++ b/drivers/spmi/spmi-apple-controller.c
@@ -149,6 +149,7 @@ static int apple_spmi_probe(struct platform_device *pdev)
 }
 
 static const struct of_device_id apple_spmi_match_table[] = {
+	{ .compatible = "apple,t8103-spmi", },
 	{ .compatible = "apple,spmi", },
 	{}
 };

---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20251231-spmi-apple-t8103-base-compat-e7c1b862b9a4

Best regards,
-- 
Janne Grunau <j at jannau.net>



From ricardo at pardini.net  Wed Dec 31 02:47:58 2025
From: ricardo at pardini.net (Ricardo Pardini)
Date: Wed, 31 Dec 2025 11:47:58 +0100
Subject: [PATCH 0/3] arm64: dts: rockchip: Enable the NPU on some rk3588
 boards
In-Reply-To: <CALWfF7KHyKmDcEL9=mYzfCRWc_cymNscoFdeXr8P2frJeww5vA@mail.gmail.com>
References: <20251230-arm64-dts-rockchip-rk3588-npu-enablements-v1-0-d38b182a59e3@pardini.net>
 <CALWfF7KHyKmDcEL9=mYzfCRWc_cymNscoFdeXr8P2frJeww5vA@mail.gmail.com>
Message-ID: <448acb0f-fa4d-45f1-83c1-7146cda9fc25@pardini.net>

Hi Jimmy,

>> This series enables the NPU on a few Rockchip rk3588 boards.
>> In every case here, the required regulator was already described.

> Now that the pd_npu has defined the dependency to the vdd_npu_s0,
> shouldn't the regulator-always-on be removed from the regulator? When
> the Rock5B enabled the NPU, it didn't define the regulator with always
> on. [1]
> 
> More specifically, the commit message for the introduction of the
> pd_npu label mentions how the regulator no longer needs to be always
> on. [2]
> 
> [1] https://lore.kernel.org/linux-rockchip/20250721-6-10-rocket-v9-10-77ebd484941e at tomeuvizoso.net/
> [2] https://lore.kernel.org/linux-rockchip/20250721-6-10-rocket-v9-7-77ebd484941e at tomeuvizoso.net/
Nice, I overlooked that. I'll send a v2 removing `regulator-always-on;` 
from the regulator.

And maybe a separate series removing it from the the other NPU-enabled 
boards that still have it?

Thanks,
Ricardo


From luca.ceresoli at bootlin.com  Wed Dec 31 02:50:15 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Wed, 31 Dec 2025 11:50:15 +0100
Subject: [PATCH v8 01/18] drm/display: bridge_connector: Ensure last
 bridge determines EDID/modes detection capabilities
In-Reply-To: <20251217093321.3108939-2-damon.ding@rock-chips.com>
References: <20251217093321.3108939-1-damon.ding@rock-chips.com>
 <20251217093321.3108939-2-damon.ding@rock-chips.com>
Message-ID: <DFCCE8SW7MFX.ZOMBZPN1S2NX@bootlin.com>

On Wed Dec 17, 2025 at 10:33 AM CET, Damon Ding wrote:
> When multiple bridges are present, EDID detection capability
> (DRM_BRIDGE_OP_EDID) takes precedence over modes detection
> (DRM_BRIDGE_OP_MODES). To ensure the above two capabilities are
> determined by the last bridge in the chain, we handle three cases:
>
> Case 1: The later bridge declares only DRM_BRIDGE_OP_MODES
>  - If the previous bridge declares DRM_BRIDGE_OP_EDID, set
>    &drm_bridge_connector.bridge_edid to NULL and set
>    &drm_bridge_connector.bridge_modes to the later bridge.
>  - Ensure modes detection capability of the later bridge will not
>    be ignored.
>
> Case 2: The later bridge declares only DRM_BRIDGE_OP_EDID
>  - If the previous bridge declares DRM_BRIDGE_OP_MODES, set
>    &drm_bridge_connector.bridge_modes to NULL and set
>    &drm_bridge_connector.bridge_edid to the later bridge.
>  - Although EDID detection capability has higher priority, this
>    operation is for balance and makes sense.
>
> Case 3: the later bridge declares both of them
>  - Assign later bridge as &drm_bridge_connector.bridge_edid and
>    and &drm_bridge_connector.bridge_modes to this bridge.
>  - Just leave transfer of these two capabilities as before.
>
> Signed-off-by: Damon Ding <damon.ding at rock-chips.com>
> Suggested-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
> Tested-by: Marek Szyprowski <m.szyprowski at samsung.com>

Reviewed-by: Luca Ceresoli <luca.ceresoli at bootlin.com>

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From luca.ceresoli at bootlin.com  Wed Dec 31 03:11:08 2025
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Wed, 31 Dec 2025 12:11:08 +0100
Subject: [PATCH v8 04/18] drm/bridge: analogix_dp: Add
 &analogix_dp_plat_data.next_bridge
In-Reply-To: <20251217093321.3108939-5-damon.ding@rock-chips.com>
References: <20251217093321.3108939-1-damon.ding@rock-chips.com>
 <20251217093321.3108939-5-damon.ding@rock-chips.com>
Message-ID: <DFCCU8AN0GZQ.2CYTKKV40JYLI@bootlin.com>

Hello Damon,

On Wed Dec 17, 2025 at 10:33 AM CET, Damon Ding wrote:
> In order to move the panel/bridge parsing and attachmenet to the
> Analogix side, add component struct drm_bridge *next_bridge to
> platform data struct analogix_dp_plat_data.
>
> The movement makes sense because the panel/bridge should logically
> be positioned behind the Analogix bridge in the display pipeline.
>
> Signed-off-by: Damon Ding <damon.ding at rock-chips.com>
> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
> Tested-by: Marek Szyprowski <m.szyprowski at samsung.com>
>
> ---
>
> Changes in v4:
> - Rename the &analogix_dp_plat_data.bridge to
>   &analogix_dp_plat_data.next_bridge
> ---
>  include/drm/bridge/analogix_dp.h | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h
> index cf17646c1310..582357c20640 100644
> --- a/include/drm/bridge/analogix_dp.h
> +++ b/include/drm/bridge/analogix_dp.h
> @@ -27,6 +27,7 @@ static inline bool is_rockchip(enum analogix_dp_devtype type)
>  struct analogix_dp_plat_data {
>  	enum analogix_dp_devtype dev_type;
>  	struct drm_panel *panel;
> +	struct drm_bridge *next_bridge;
>  	struct drm_encoder *encoder;
>  	struct drm_connector *connector;
>  	bool skip_connector;

It took a while to understand why you are adding the next_bridge pointer in
struct analogix_dp_plat_data instead of struct analogix_dp_device, where it
would be more natural. I found an answer in patch 16: with current code you
need to place next_bridge in struct analogix_dp_plat_data because it is
used by user drivers to attach, and those drivers have no access to struct
analogix_dp_device. However patch 16 (which looks a very good cleanup BTW)
next_bridge can be moved to struct analogix_dp_device.

So I'd suggest to move patch 16 before this one if it easily doable, so
that you can introduce next_bridge in struct analogix_dp_device from the
beginning. Should that be impossible, you can send a separate patch to move
next_bridge, after patch 16.

Best regards,
Luca

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From pankaj.patil at oss.qualcomm.com  Wed Dec 31 03:30:26 2025
From: pankaj.patil at oss.qualcomm.com (Pankaj Patil)
Date: Wed, 31 Dec 2025 17:00:26 +0530
Subject: [PATCH] dt-bindings: interrupt-controller: arm: Drop redundant node name restrictions
Message-ID: <20251231113026.2480092-1-pankaj.patil@oss.qualcomm.com>

Drop the redundant 'false' patterns so that allowed names
('msi-controller', 'gic-its', and 'interrupt-controller') work as intended

GICv3 binding currently disallows child nodes named 'gic-its@' and
'interrupt-controller@' via patternProperties set to 'false'. However,
these names are already permitted (though not preferred) by a subsequent
pattern that applies the correct schema.

Since the 'false' patterns take precedence, valid nodes such as
'gic-its@<addr>' and 'interrupt-controller@<addr>' fail dtbs_check with
"False schema does not allow" errors

Signed-off-by: Pankaj Patil <pankaj.patil at oss.qualcomm.com>
---
 .../devicetree/bindings/interrupt-controller/arm,gic-v3.yaml    | 2 --
 1 file changed, 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
index bfd30aae682b..462305f8047d 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
+++ b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
@@ -186,8 +186,6 @@ required:
   - reg
 
 patternProperties:
-  "^gic-its@": false
-  "^interrupt-controller@[0-9a-f]+$": false
   # msi-controller is preferred, but allow other names
   "^(msi-controller|gic-its|interrupt-controller)@[0-9a-f]+$":
     type: object
-- 
2.34.1



From j at jannau.net  Wed Dec 31 04:07:21 2025
From: j at jannau.net (Janne Grunau)
Date: Wed, 31 Dec 2025 13:07:21 +0100
Subject: [PATCH] watchdog: apple: Add "apple,t8103-wdt" compatible
Message-ID: <20251231-watchdog-apple-t8103-base-compat-v1-1-1702a02e0c45@jannau.net>

After discussion with the devicetree maintainers we agreed to not extend
lists with the generic compatible "apple,wdt" anymore [1]. Use
"apple,t8103-wdt" as base compatible as it is the SoC the driver and
bindings were written for.

[1]: https://lore.kernel.org/asahi/12ab93b7-1fc2-4ce0-926e-c8141cfe81bf at kernel.org/

Fixes: 4ed224aeaf66 ("watchdog: Add Apple SoC watchdog driver")
Cc: stable at vger.kernel.org
Reviewed-by: Neal Gompa <neal at gompa.dev>
Signed-off-by: Janne Grunau <j at jannau.net>
---
This is split off from the v1 series adding Apple M2 Pro/Max/Ultra
device trees in [2].

2: https://lore.kernel.org/r/20250828-dt-apple-t6020-v1-0-507ba4c4b98e at jannau.net
---
 drivers/watchdog/apple_wdt.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/watchdog/apple_wdt.c b/drivers/watchdog/apple_wdt.c
index 66a158f67a712bbed394d660071e02140e66c2e5..6b9b0f9b05cedfd7fc5d0d79ba19ab356dc2a080 100644
--- a/drivers/watchdog/apple_wdt.c
+++ b/drivers/watchdog/apple_wdt.c
@@ -218,6 +218,7 @@ static int apple_wdt_suspend(struct device *dev)
 static DEFINE_SIMPLE_DEV_PM_OPS(apple_wdt_pm_ops, apple_wdt_suspend, apple_wdt_resume);
 
 static const struct of_device_id apple_wdt_of_match[] = {
+	{ .compatible = "apple,t8103-wdt" },
 	{ .compatible = "apple,wdt" },
 	{},
 };

---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20251231-watchdog-apple-t8103-base-compat-8a623e9831b6

Best regards,
-- 
Janne Grunau <j at jannau.net>



From james.clark at linaro.org  Wed Dec 31 04:12:28 2025
From: james.clark at linaro.org (James Clark)
Date: Wed, 31 Dec 2025 12:12:28 +0000
Subject: [PATCH] perf vendor events arm64: Remove uncountable events
Message-ID: <20251231-james-perf-uncountable-events-v1-1-f2d9932999fd@linaro.org>

These events are never countable by the PMU and are only intended to
be used as external inputs to trace. Therefore showing them in 'perf
list' is misleading so remove them.

The generator script doesn't emit these events when used with the new
telemetry-solution input files [1].

'perf list' should only show countable events because there are events
that are sometimes implemented, sometimes countable and sometimes not,
for example TRB_TRIG. If we always include any implemented events
whether they are countable or not then it's not possible to tell whether
they are usable in perf without going to the docs, defeating the point
of 'perf list'.

It's also not useful yet to display implemented events that are not
countable (for help in using trace rather than perf stat), because
PMU_OVFS and PMU_HOVFS are practically always implemented and TRB_TRIG
is always implemented when there is TRBE.

[1]: https://gitlab.arm.com/telemetry-solution/telemetry-solution/-/tree/main/data/pmu/cpu

Signed-off-by: James Clark <james.clark at linaro.org>
---
 tools/perf/pmu-events/arch/arm64/arm/cortex-a510/pmu.json  |  8 --------
 tools/perf/pmu-events/arch/arm64/common-and-microarch.json | 12 ------------
 tools/perf/pmu-events/arch/arm64/fujitsu/monaka/pmu.json   | 10 ----------
 3 files changed, 30 deletions(-)

diff --git a/tools/perf/pmu-events/arch/arm64/arm/cortex-a510/pmu.json b/tools/perf/pmu-events/arch/arm64/arm/cortex-a510/pmu.json
deleted file mode 100644
index d8b7b9f9e5fa..000000000000
--- a/tools/perf/pmu-events/arch/arm64/arm/cortex-a510/pmu.json
+++ /dev/null
@@ -1,8 +0,0 @@
-[
-    {
-        "ArchStdEvent": "PMU_OVFS"
-    },
-    {
-        "ArchStdEvent": "PMU_HOVFS"
-    }
-]
diff --git a/tools/perf/pmu-events/arch/arm64/common-and-microarch.json b/tools/perf/pmu-events/arch/arm64/common-and-microarch.json
index 2416d9f8a83d..468cb085d879 100644
--- a/tools/perf/pmu-events/arch/arm64/common-and-microarch.json
+++ b/tools/perf/pmu-events/arch/arm64/common-and-microarch.json
@@ -432,24 +432,12 @@
         "EventName": "TRB_WRAP",
         "BriefDescription": "Trace buffer current write pointer wrapped"
     },
-    {
-        "PublicDescription": "PMU overflow, counters accessible to EL1 and EL0",
-        "EventCode": "0x400D",
-        "EventName": "PMU_OVFS",
-        "BriefDescription": "PMU overflow, counters accessible to EL1 and EL0"
-    },
     {
         "PublicDescription": "Trace buffer Trigger Event",
         "EventCode": "0x400E",
         "EventName": "TRB_TRIG",
         "BriefDescription": "Trace buffer Trigger Event"
     },
-    {
-        "PublicDescription": "PMU overflow, counters reserved for use by EL2",
-        "EventCode": "0x400F",
-        "EventName": "PMU_HOVFS",
-        "BriefDescription": "PMU overflow, counters reserved for use by EL2"
-    },
     {
         "PublicDescription": "PE Trace Unit external output 0",
         "EventCode": "0x4010",
diff --git a/tools/perf/pmu-events/arch/arm64/fujitsu/monaka/pmu.json b/tools/perf/pmu-events/arch/arm64/fujitsu/monaka/pmu.json
deleted file mode 100644
index 65bd6cdd0dd5..000000000000
--- a/tools/perf/pmu-events/arch/arm64/fujitsu/monaka/pmu.json
+++ /dev/null
@@ -1,10 +0,0 @@
-[
-    {
-        "ArchStdEvent": "PMU_OVFS",
-        "BriefDescription": "This event counts the event generated each time one of the condition occurs described in Arm Architecture Reference Manual for A-profile architecture. This event is only for output to the trace unit."
-    },
-    {
-        "ArchStdEvent": "PMU_HOVFS",
-        "BriefDescription": "This event counts the event generated each time an event is counted by an event counter <n> and all of the condition occur described in Arm Architecture Reference Manual for A-profile architecture. This event is only for output to the trace unit."
-    }
-]

---
base-commit: cbd41c6d4c26c161a2b0e70ad411d3885ff13507
change-id: 20251230-james-perf-uncountable-events-28adfb93b73f

Best regards,
-- 
James Clark <james.clark at linaro.org>



From j at jannau.net  Wed Dec 31 04:22:00 2025
From: j at jannau.net (Janne Grunau)
Date: Wed, 31 Dec 2025 13:22:00 +0100
Subject: [PATCH] clk: clk-apple-nco: Add "apple,t8103-nco" compatible
Message-ID: <20251231-clk-apple-nco-t8103-base-compat-v1-1-6459e65b6299@jannau.net>

After discussion with the devicetree maintainers we agreed to not extend
lists with the generic compatible "apple,nco" anymore [1]. Use
"apple,t8103-nco" as base compatible as it is the SoC the driver and
bindings were written for.

[1]: https://lore.kernel.org/asahi/12ab93b7-1fc2-4ce0-926e-c8141cfe81bf at kernel.org/

Fixes: 6641057d5dba ("clk: clk-apple-nco: Add driver for Apple NCO")
Cc: stable at vger.kernel.org
Acked-by: Stephen Boyd <sboyd at kernel.org>
Reviewed-by: Neal Gompa <neal at gompa.dev>
Signed-off-by: Janne Grunau <j at jannau.net>
---
This is split off from the v1 series adding Apple M2 Pro/Max/Ultra
device trees in [2].

Changes compared to that series:
- add "Fixes:" and "Cc: stable" for handling this as fix adding a device
  id
- add Neal's and Stephen's trailers
---
 drivers/clk/clk-apple-nco.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/clk/clk-apple-nco.c b/drivers/clk/clk-apple-nco.c
index d3ced4a0f029ec0440ff42d49d31e314fdf86846..434c067968bbc1afdb5c9216277486bf826666c2 100644
--- a/drivers/clk/clk-apple-nco.c
+++ b/drivers/clk/clk-apple-nco.c
@@ -320,6 +320,7 @@ static int applnco_probe(struct platform_device *pdev)
 }
 
 static const struct of_device_id applnco_ids[] = {
+	{ .compatible = "apple,t8103-nco" },
 	{ .compatible = "apple,nco" },
 	{ }
 };

---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20251231-clk-apple-nco-t8103-base-compat-dea037ecce88

Best regards,
-- 
Janne Grunau <j at jannau.net>



From aliceryhl at google.com  Wed Dec 31 04:22:24 2025
From: aliceryhl at google.com (Alice Ryhl)
Date: Wed, 31 Dec 2025 12:22:24 +0000
Subject: [PATCH 0/5] Add READ_ONCE and WRITE_ONCE to Rust
Message-ID: <20251231-rwonce-v1-0-702a10b85278@google.com>

There are currently a few places in the kernel where we use volatile
reads when we really should be using `READ_ONCE`. To make it possible to
replace these with proper `READ_ONCE` calls, introduce a Rust version of
`READ_ONCE`.

A new config option CONFIG_ARCH_USE_CUSTOM_READ_ONCE is introduced so
that Rust is able to use conditional compilation to implement READ_ONCE
in terms of either a volatile read, or by calling into a C helper
function, depending on the architecture.

This series is intended to be merged through ATOMIC INFRASTRUCTURE.

Signed-off-by: Alice Ryhl <aliceryhl at google.com>
---
Alice Ryhl (5):
      arch: add CONFIG_ARCH_USE_CUSTOM_READ_ONCE for arm64/alpha
      rust: sync: add READ_ONCE and WRITE_ONCE
      rust: sync: support using bool with READ_ONCE
      rust: hrtimer: use READ_ONCE instead of read_volatile
      rust: fs: use READ_ONCE instead of read_volatile

 MAINTAINERS                     |   2 +
 arch/Kconfig                    |  11 +++
 arch/alpha/Kconfig              |   1 +
 arch/alpha/include/asm/rwonce.h |   4 +-
 arch/arm64/Kconfig              |   1 +
 arch/arm64/include/asm/rwonce.h |   4 +-
 rust/helpers/helpers.c          |   1 +
 rust/helpers/rwonce.c           |  34 +++++++
 rust/kernel/fs/file.rs          |   8 +-
 rust/kernel/sync.rs             |   2 +
 rust/kernel/sync/rwonce.rs      | 207 ++++++++++++++++++++++++++++++++++++++++
 rust/kernel/time/hrtimer.rs     |   8 +-
 12 files changed, 268 insertions(+), 15 deletions(-)
---
base-commit: f8f9c1f4d0c7a64600e2ca312dec824a0bc2f1da
change-id: 20251230-rwonce-1e8d2ee0bcf9

Best regards,
-- 
Alice Ryhl <aliceryhl at google.com>



From aliceryhl at google.com  Wed Dec 31 04:22:25 2025
From: aliceryhl at google.com (Alice Ryhl)
Date: Wed, 31 Dec 2025 12:22:25 +0000
Subject: [PATCH 1/5] arch: add CONFIG_ARCH_USE_CUSTOM_READ_ONCE for arm64/alpha
In-Reply-To: <20251231-rwonce-v1-0-702a10b85278@google.com>
References: <20251231-rwonce-v1-0-702a10b85278@google.com>
Message-ID: <20251231-rwonce-v1-1-702a10b85278@google.com>

By exposing this variable as a config option, conditional compilation in
Rust code may rely on it to determine whether it should use a volatile
read or call a C helper function to perform a READ_ONCE operation.

This config option is also added on alpha for consistency, even if Rust
does not support alpha right now.

Signed-off-by: Alice Ryhl <aliceryhl at google.com>
---
 arch/Kconfig                    | 11 +++++++++++
 arch/alpha/Kconfig              |  1 +
 arch/alpha/include/asm/rwonce.h |  4 ++--
 arch/arm64/Kconfig              |  1 +
 arch/arm64/include/asm/rwonce.h |  4 ++--
 5 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index 31220f512b16d5cfbc259935c2d3675b60c1e25c..683176bb09e50e31f398bb92678283e5de66b282 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -229,6 +229,17 @@ config HAVE_EFFICIENT_UNALIGNED_ACCESS
 	  See Documentation/core-api/unaligned-memory-access.rst for more
 	  information on the topic of unaligned memory accesses.
 
+config ARCH_USE_CUSTOM_READ_ONCE
+	bool
+	help
+	  Some architectures reorder address-dependent volatile loads,
+	  which means that the default implementation of READ_ONCE that
+	  relies on a volatile load is not appropriate.
+
+	  This symbol should be selected by an architecture if it
+	  redefines READ_ONCE to use a different implementation than a
+	  volatile load.
+
 config ARCH_USE_BUILTIN_BSWAP
 	bool
 	help
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 80367f2cf821ceb4fc29485b7b21b37d5c310765..1d5d48153ba0087554221e9412a6af0c672d3f5c 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -11,6 +11,7 @@ config ALPHA
 	select ARCH_NO_PREEMPT
 	select ARCH_NO_SG_CHAIN
 	select ARCH_USE_CMPXCHG_LOCKREF
+	select ARCH_USE_CUSTOM_READ_ONCE if SMP
 	select FORCE_PCI
 	select PCI_DOMAINS if PCI
 	select PCI_SYSCALL if PCI
diff --git a/arch/alpha/include/asm/rwonce.h b/arch/alpha/include/asm/rwonce.h
index 35542bcf92b3a883df353784bcb2d243475ccd91..c9f21aa0764625b24e8957923926d09a2eb97e7c 100644
--- a/arch/alpha/include/asm/rwonce.h
+++ b/arch/alpha/include/asm/rwonce.h
@@ -5,7 +5,7 @@
 #ifndef __ASM_RWONCE_H
 #define __ASM_RWONCE_H
 
-#ifdef CONFIG_SMP
+#ifdef CONFIG_ARCH_USE_CUSTOM_READ_ONCE
 
 #include <asm/barrier.h>
 
@@ -28,7 +28,7 @@
 	(typeof(x))__x;							\
 })
 
-#endif /* CONFIG_SMP */
+#endif /* CONFIG_ARCH_USE_CUSTOM_READ_ONCE */
 
 #include <asm-generic/rwonce.h>
 
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 93173f0a09c7deb07b46ab4f16a1a0e4320dfbf1..cd16053c8302479458a05c23ba9cfb73ee50232c 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -89,6 +89,7 @@ config ARM64
 	select ARCH_KEEP_MEMBLOCK
 	select ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE
 	select ARCH_USE_CMPXCHG_LOCKREF
+	select ARCH_USE_CUSTOM_READ_ONCE if LTO
 	select ARCH_USE_GNU_PROPERTY
 	select ARCH_USE_MEMTEST
 	select ARCH_USE_QUEUED_RWLOCKS
diff --git a/arch/arm64/include/asm/rwonce.h b/arch/arm64/include/asm/rwonce.h
index 78beceec10cda47b319db29d9f79d2a5df35e92d..5da6b2d6a12399a520f7a3310014de723baa278a 100644
--- a/arch/arm64/include/asm/rwonce.h
+++ b/arch/arm64/include/asm/rwonce.h
@@ -5,7 +5,7 @@
 #ifndef __ASM_RWONCE_H
 #define __ASM_RWONCE_H
 
-#if defined(CONFIG_LTO) && !defined(__ASSEMBLER__)
+#if defined(CONFIG_ARCH_USE_CUSTOM_READ_ONCE) && !defined(__ASSEMBLER__)
 
 #include <linux/compiler_types.h>
 #include <asm/alternative-macros.h>
@@ -62,7 +62,7 @@
 })
 
 #endif	/* !BUILD_VDSO */
-#endif	/* CONFIG_LTO && !__ASSEMBLER__ */
+#endif	/* CONFIG_ARCH_USE_CUSTOM_READ_ONCE && !__ASSEMBLER__ */
 
 #include <asm-generic/rwonce.h>
 

-- 
2.52.0.351.gbe84eed79e-goog



From aliceryhl at google.com  Wed Dec 31 04:22:26 2025
From: aliceryhl at google.com (Alice Ryhl)
Date: Wed, 31 Dec 2025 12:22:26 +0000
Subject: [PATCH 2/5] rust: sync: add READ_ONCE and WRITE_ONCE
In-Reply-To: <20251231-rwonce-v1-0-702a10b85278@google.com>
References: <20251231-rwonce-v1-0-702a10b85278@google.com>
Message-ID: <20251231-rwonce-v1-2-702a10b85278@google.com>

There are currently a few places in the kernel where we use volatile
reads when we really should be using `READ_ONCE`. To make it possible to
replace these with proper `READ_ONCE` calls, introduce a Rust version of
`READ_ONCE`.

I've written the code to use Rust's volatile ops directly when possible.
This results in a small amount of code duplication, but I think it makes
sense for READ_ONCE and WRITE_ONCE to be implemented in pure Rust when
possible. Otherwise they would unconditionally be a function call unless
you have a system where you can perform cross-language inlining.

I considered these functions in the bindings crate instead of kernel
crate. I actually think it would make a lot of sense. But it implies
some annoying complications on old compilers since the #![feature()]
invocations in kernel/lib.rs do not apply in the bindings crate.

For now, we do not support using READ_ONCE on compound types even if
they have the right size. This can be added later.

This fails checkpatch due to a misordered MAINTAINERS entry, but this is
a pre-existing problem.

Signed-off-by: Alice Ryhl <aliceryhl at google.com>
---
 MAINTAINERS                |   2 +
 rust/helpers/helpers.c     |   1 +
 rust/helpers/rwonce.c      |  34 ++++++++
 rust/kernel/sync.rs        |   2 +
 rust/kernel/sync/rwonce.rs | 188 +++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 227 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 12f49de7fe036c2439c00f9f4c67b2219d72a4c3..1d0cae158fe2cc7d99b6a64c11176b635e2d14e4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4117,9 +4117,11 @@ F:	arch/*/include/asm/atomic*.h
 F:	include/*/atomic*.h
 F:	include/linux/refcount.h
 F:	scripts/atomic/
+F:	rust/helpers/rwonce.c
 F:	rust/kernel/sync/atomic.rs
 F:	rust/kernel/sync/atomic/
 F:	rust/kernel/sync/refcount.rs
+F:	rust/kernel/sync/rwonce.rs
 
 ATTO EXPRESSSAS SAS/SATA RAID SCSI DRIVER
 M:	Bradley Grove <linuxdrivers at attotech.com>
diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
index 79c72762ad9c4b473971e6210c9577860d2e2b08..28b79ca7844fb744e5ad128238824921c055ec82 100644
--- a/rust/helpers/helpers.c
+++ b/rust/helpers/helpers.c
@@ -48,6 +48,7 @@
 #include "rcu.c"
 #include "refcount.c"
 #include "regulator.c"
+#include "rwonce.c"
 #include "scatterlist.c"
 #include "security.c"
 #include "signal.c"
diff --git a/rust/helpers/rwonce.c b/rust/helpers/rwonce.c
new file mode 100644
index 0000000000000000000000000000000000000000..55c621678cd632e728cb925b6a4a2e34e2fc4884
--- /dev/null
+++ b/rust/helpers/rwonce.c
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (C) 2025 Google LLC.
+ */
+
+#ifdef CONFIG_ARCH_USE_CUSTOM_READ_ONCE
+
+__rust_helper u8 rust_helper_read_once_1(const u8 *ptr)
+{
+	return READ_ONCE(*ptr);
+}
+
+__rust_helper u16 rust_helper_read_once_2(const u16 *ptr)
+{
+	return READ_ONCE(*ptr);
+}
+
+__rust_helper u32 rust_helper_read_once_4(const u32 *ptr)
+{
+	return READ_ONCE(*ptr);
+}
+
+__rust_helper u64 rust_helper_read_once_8(const u64 *ptr)
+{
+	return READ_ONCE(*ptr);
+}
+
+__rust_helper void *rust_helper_read_once_ptr(void * const *ptr)
+{
+	return READ_ONCE(*ptr);
+}
+
+#endif
diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs
index 5df87e2bd212e192b8a67644bd99f05b9d4afd75..a5bf7bdc3fa8a044786eafae39fe8844aeeef057 100644
--- a/rust/kernel/sync.rs
+++ b/rust/kernel/sync.rs
@@ -20,6 +20,7 @@
 pub mod poll;
 pub mod rcu;
 mod refcount;
+pub mod rwonce;
 mod set_once;
 
 pub use arc::{Arc, ArcBorrow, UniqueArc};
@@ -30,6 +31,7 @@
 pub use lock::spinlock::{new_spinlock, SpinLock, SpinLockGuard};
 pub use locked_by::LockedBy;
 pub use refcount::Refcount;
+pub use rwonce::{READ_ONCE, WRITE_ONCE};
 pub use set_once::SetOnce;
 
 /// Represents a lockdep class. It's a wrapper around C's `lock_class_key`.
diff --git a/rust/kernel/sync/rwonce.rs b/rust/kernel/sync/rwonce.rs
new file mode 100644
index 0000000000000000000000000000000000000000..a1660e43c9ef94011812d1816713cf031a73de1d
--- /dev/null
+++ b/rust/kernel/sync/rwonce.rs
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: GPL-2.0
+
+// Copyright (C) 2025 Google LLC.
+
+//! Rust version of the raw `READ_ONCE`/`WRITE_ONCE` functions.
+//!
+//! C header: [`include/asm-generic/rwonce.h`](srctree/include/asm-generic/rwonce.h)
+
+/// Read the pointer once.
+///
+/// # Safety
+///
+/// It must be safe to `READ_ONCE` the `ptr` with this type.
+#[inline(always)]
+#[must_use]
+#[track_caller]
+#[expect(non_snake_case)]
+pub unsafe fn READ_ONCE<T: RwOnceType>(ptr: *const T) -> T {
+    // SAFETY: It's safe to read `ptr` once with this type.
+    unsafe { T::read_once(ptr) }
+}
+
+/// Write the pointer once.
+///
+/// # Safety
+///
+/// It must be safe to `WRITE_ONCE` the `ptr` with this type.
+#[inline(always)]
+#[track_caller]
+#[expect(non_snake_case)]
+pub unsafe fn WRITE_ONCE<T: RwOnceType>(ptr: *mut T, val: T) {
+    // SAFETY: It's safe to write `ptr` once with this type.
+    unsafe { T::write_once(ptr, val) };
+}
+
+/// This module contains the generic implementations.
+#[expect(clippy::undocumented_unsafe_blocks)]
+#[expect(clippy::missing_safety_doc)]
+mod rwonce_generic_impl {
+    use core::ffi::c_void;
+    #[allow(unused_imports)]
+    use core::ptr::{read_volatile, write_volatile};
+
+    #[inline(always)]
+    #[track_caller]
+    #[cfg(not(CONFIG_ARCH_USE_CUSTOM_READ_ONCE))]
+    pub(super) unsafe fn read_once_1(ptr: *const u8) -> u8 {
+        unsafe { read_volatile::<u8>(ptr) }
+    }
+
+    #[inline(always)]
+    #[track_caller]
+    #[cfg(not(CONFIG_ARCH_USE_CUSTOM_READ_ONCE))]
+    pub(super) unsafe fn read_once_2(ptr: *const u16) -> u16 {
+        unsafe { read_volatile::<u16>(ptr) }
+    }
+
+    #[inline(always)]
+    #[track_caller]
+    #[cfg(not(CONFIG_ARCH_USE_CUSTOM_READ_ONCE))]
+    pub(super) unsafe fn read_once_4(ptr: *const u32) -> u32 {
+        unsafe { read_volatile::<u32>(ptr) }
+    }
+
+    #[inline(always)]
+    #[track_caller]
+    #[cfg(not(CONFIG_ARCH_USE_CUSTOM_READ_ONCE))]
+    pub(super) unsafe fn read_once_8(ptr: *const u64) -> u64 {
+        unsafe { read_volatile::<u64>(ptr) }
+    }
+
+    #[inline(always)]
+    #[track_caller]
+    #[cfg(not(CONFIG_ARCH_USE_CUSTOM_READ_ONCE))]
+    pub(super) unsafe fn read_once_ptr(ptr: *const *mut c_void) -> *mut c_void {
+        unsafe { read_volatile::<*mut c_void>(ptr) }
+    }
+
+    #[inline(always)]
+    #[track_caller]
+    pub(super) unsafe fn write_once_1(ptr: *mut u8, val: u8) {
+        unsafe { write_volatile::<u8>(ptr, val) }
+    }
+
+    #[inline(always)]
+    #[track_caller]
+    pub(super) unsafe fn write_once_2(ptr: *mut u16, val: u16) {
+        unsafe { write_volatile::<u16>(ptr, val) }
+    }
+
+    #[inline(always)]
+    #[track_caller]
+    pub(super) unsafe fn write_once_4(ptr: *mut u32, val: u32) {
+        unsafe { write_volatile::<u32>(ptr, val) }
+    }
+
+    #[inline(always)]
+    #[track_caller]
+    pub(super) unsafe fn write_once_8(ptr: *mut u64, val: u64) {
+        unsafe { write_volatile::<u64>(ptr, val) }
+    }
+
+    #[inline(always)]
+    #[track_caller]
+    pub(super) unsafe fn write_once_ptr(ptr: *mut *mut c_void, val: *mut c_void) {
+        unsafe { write_volatile::<*mut c_void>(ptr, val) }
+    }
+}
+use rwonce_generic_impl::*;
+
+#[cfg(CONFIG_ARCH_USE_CUSTOM_READ_ONCE)]
+use bindings::{read_once_1, read_once_2, read_once_4, read_once_8, read_once_ptr};
+
+/// Rust trait for types that may be used with `READ_ONCE`/`WRITE_ONCE`.
+///
+/// This serves a similar purpose to the `compiletime_assert_rwonce_type` macro in the C header.
+pub trait RwOnceType {
+    /// The `READ_ONCE` for this type.
+    ///
+    /// # Safety
+    ///
+    /// It must be safe to `READ_ONCE` the `ptr` with this type.
+    unsafe fn read_once(ptr: *const Self) -> Self;
+
+    /// The `WRITE_ONCE` for this type.
+    ///
+    /// # Safety
+    ///
+    /// It must be safe to `WRITE_ONCE` the `ptr` with this type.
+    unsafe fn write_once(ptr: *mut Self, val: Self);
+}
+
+macro_rules! impl_rw_once_type {
+    ($($t:ty, $read:ident, $write:ident $(, <$u:ident>)?;)*) => {$(
+        #[allow(unknown_lints, reason = "unnecessary_transmutes is unknown prior to MSRV 1.88.0")]
+        #[allow(unnecessary_transmutes)]
+        #[allow(clippy::missing_transmute_annotations)]
+        #[allow(clippy::useless_transmute)]
+        impl$(<$u>)? RwOnceType for $t {
+            #[inline(always)]
+            #[track_caller]
+            unsafe fn read_once(ptr: *const Self) -> Self {
+                // SAFETY: The caller ensures we can `READ_ONCE`.
+                //
+                // Note that `transmute` fails to compile if the two types are of different sizes.
+                unsafe { core::mem::transmute($read(ptr.cast())) }
+            }
+
+            #[inline(always)]
+            #[track_caller]
+            unsafe fn write_once(ptr: *mut Self, val: Self) {
+                // SAFETY: The caller ensures we can `WRITE_ONCE`.
+                unsafe { $write(ptr.cast(), core::mem::transmute(val)) };
+            }
+        }
+    )*}
+}
+
+// These macros determine which types may be used with rwonce, and which helper function should be
+// used if so.
+//
+// Note that `core::mem::transmute` fails the build if the source and target type have different
+// sizes, so picking the wrong helper should lead to a build error.
+
+impl_rw_once_type! {
+    u8,   read_once_1, write_once_1;
+    i8,   read_once_1, write_once_1;
+    u16,  read_once_2, write_once_2;
+    i16,  read_once_2, write_once_2;
+    u32,  read_once_4, write_once_4;
+    i32,  read_once_4, write_once_4;
+    u64,  read_once_8, write_once_8;
+    i64,  read_once_8, write_once_8;
+    *mut T, read_once_ptr, write_once_ptr, <T>;
+    *const T, read_once_ptr, write_once_ptr, <T>;
+}
+
+#[cfg(target_pointer_width = "32")]
+impl_rw_once_type! {
+    usize, read_once_4, write_once_4;
+    isize, read_once_4, write_once_4;
+}
+
+#[cfg(target_pointer_width = "64")]
+impl_rw_once_type! {
+    usize, read_once_8, write_once_8;
+    isize, read_once_8, write_once_8;
+}

-- 
2.52.0.351.gbe84eed79e-goog



From aliceryhl at google.com  Wed Dec 31 04:22:27 2025
From: aliceryhl at google.com (Alice Ryhl)
Date: Wed, 31 Dec 2025 12:22:27 +0000
Subject: [PATCH 3/5] rust: sync: support using bool with READ_ONCE
In-Reply-To: <20251231-rwonce-v1-0-702a10b85278@google.com>
References: <20251231-rwonce-v1-0-702a10b85278@google.com>
Message-ID: <20251231-rwonce-v1-3-702a10b85278@google.com>

Normally it is undefined behavior for a bool to take any value other
than 0 or 1. However, in the case of READ_ONCE(some_bool) is used, this
UB seems dangerous and unnecessary. I can easily imagine some Rust code
that looks like this:

	if READ_ONCE(&raw const (*my_c_struct).my_bool_field) {
	    ...
	}

And by making an analogy to what the equivalent C code is, anyone
writing this probably just meant to treat any non-zero value as true.

For WRITE_ONCE no special logic is required.

Signed-off-by: Alice Ryhl <aliceryhl at google.com>
---
 rust/kernel/sync/rwonce.rs | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/rust/kernel/sync/rwonce.rs b/rust/kernel/sync/rwonce.rs
index a1660e43c9ef94011812d1816713cf031a73de1d..73477f53131926996614df573b2d50fff98e624f 100644
--- a/rust/kernel/sync/rwonce.rs
+++ b/rust/kernel/sync/rwonce.rs
@@ -163,6 +163,7 @@ unsafe fn write_once(ptr: *mut Self, val: Self) {
 // sizes, so picking the wrong helper should lead to a build error.
 
 impl_rw_once_type! {
+    bool, read_once_bool, write_once_1;
     u8,   read_once_1, write_once_1;
     i8,   read_once_1, write_once_1;
     u16,  read_once_2, write_once_2;
@@ -186,3 +187,21 @@ unsafe fn write_once(ptr: *mut Self, val: Self) {
     usize, read_once_8, write_once_8;
     isize, read_once_8, write_once_8;
 }
+
+/// Read an integer as a boolean once.
+///
+/// Returns `true` if the value behind the pointer is non-zero. Otherwise returns `false`.
+///
+/// # Safety
+///
+/// It must be safe to `READ_ONCE` the `ptr` with type `u8`.
+#[inline(always)]
+#[track_caller]
+unsafe fn read_once_bool(ptr: *const bool) -> bool {
+    // Implement `read_once_bool` in terms of `read_once_1`. The arch-specific logic is inside
+    // of `read_once_1`.
+    //
+    // SAFETY: It is safe to `READ_ONCE` the `ptr` with type `u8`.
+    let byte = unsafe { read_once_1(ptr.cast::<u8>()) };
+    byte != 0u8
+}

-- 
2.52.0.351.gbe84eed79e-goog



From aliceryhl at google.com  Wed Dec 31 04:22:28 2025
From: aliceryhl at google.com (Alice Ryhl)
Date: Wed, 31 Dec 2025 12:22:28 +0000
Subject: [PATCH 4/5] rust: hrtimer: use READ_ONCE instead of read_volatile
In-Reply-To: <20251231-rwonce-v1-0-702a10b85278@google.com>
References: <20251231-rwonce-v1-0-702a10b85278@google.com>
Message-ID: <20251231-rwonce-v1-4-702a10b85278@google.com>

Using `READ_ONCE` is the correct way to read the `node.expires` field.

Signed-off-by: Alice Ryhl <aliceryhl at google.com>
---
 rust/kernel/time/hrtimer.rs | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs
index 856d2d929a00892dc8eaec63cebdf547817953d3..e2b7a26f8aade972356c3eb5f6489bcda3e2e849 100644
--- a/rust/kernel/time/hrtimer.rs
+++ b/rust/kernel/time/hrtimer.rs
@@ -239,11 +239,9 @@ pub fn expires(&self) -> HrTimerInstant<T>
         // - Timers cannot have negative ktime_t values as their expiration time.
         // - There's no actual locking here, a racy read is fine and expected
         unsafe {
-            Instant::from_ktime(
-                // This `read_volatile` is intended to correspond to a READ_ONCE call.
-                // FIXME(read_once): Replace with `read_once` when available on the Rust side.
-                core::ptr::read_volatile(&raw const ((*c_timer_ptr).node.expires)),
-            )
+            Instant::from_ktime(kernel::sync::READ_ONCE(
+                &raw const (*c_timer_ptr).node.expires,
+            ))
         }
     }
 }

-- 
2.52.0.351.gbe84eed79e-goog



From aliceryhl at google.com  Wed Dec 31 04:22:29 2025
From: aliceryhl at google.com (Alice Ryhl)
Date: Wed, 31 Dec 2025 12:22:29 +0000
Subject: [PATCH 5/5] rust: fs: use READ_ONCE instead of read_volatile
In-Reply-To: <20251231-rwonce-v1-0-702a10b85278@google.com>
References: <20251231-rwonce-v1-0-702a10b85278@google.com>
Message-ID: <20251231-rwonce-v1-5-702a10b85278@google.com>

Using `READ_ONCE` is the correct way to read the `f_flags` field.

Signed-off-by: Alice Ryhl <aliceryhl at google.com>
---
 rust/kernel/fs/file.rs | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/rust/kernel/fs/file.rs b/rust/kernel/fs/file.rs
index 23ee689bd2400565223181645157d832a836589f..6b07f08e7012f512e53743266096ce0076d29e1c 100644
--- a/rust/kernel/fs/file.rs
+++ b/rust/kernel/fs/file.rs
@@ -335,12 +335,8 @@ pub fn cred(&self) -> &Credential {
     /// The flags are a combination of the constants in [`flags`].
     #[inline]
     pub fn flags(&self) -> u32 {
-        // This `read_volatile` is intended to correspond to a READ_ONCE call.
-        //
-        // SAFETY: The file is valid because the shared reference guarantees a nonzero refcount.
-        //
-        // FIXME(read_once): Replace with `read_once` when available on the Rust side.
-        unsafe { core::ptr::addr_of!((*self.as_ptr()).f_flags).read_volatile() }
+        // SAFETY: The `f_flags` field of `struct file` is readable with `READ_ONCE`.
+        unsafe { kernel::sync::READ_ONCE(&raw const (*self.as_ptr()).f_flags) }
     }
 }
 

-- 
2.52.0.351.gbe84eed79e-goog



From alex at chimac.ro  Wed Dec 31 04:28:50 2025
From: alex at chimac.ro (Alexandru Chimac)
Date: Wed, 31 Dec 2025 12:28:50 +0000
Subject: [PATCH v2 2/3] dt-bindings: pinctrl: samsung: Add exynos9610-wakeup-eint node
In-Reply-To: <20251230-dramatic-gregarious-stallion-15bc07@quoll>
References: <20251228-exynos9610-pinctrl-v2-0-c9bbeee4c54b@chimac.ro> <20251228-exynos9610-pinctrl-v2-2-c9bbeee4c54b@chimac.ro> <20251230-dramatic-gregarious-stallion-15bc07@quoll>
Message-ID: <yB5WFgsxeeqHQgi87UeNPD8K2OlQbWWC6-BovxADBtgusN3n8UOrm7Gi6jz6Th0dsMA9J-LEpx69sWjNmWTH_-jx9r7AgvXNTwR2hQW7-SM=@chimac.ro>

On Tuesday, December 30th, 2025 at 11:51, Krzysztof Kozlowski <krzk at kernel.org> wrote:
> 
> 
> On Sun, Dec 28, 2025 at 06:05:52PM +0000, Alexandru Chimac wrote:
> 
> > Add a dedicated compatible for the exynos9610-wakeup-eint node,
> > which is compatbile with Exynos850's implementation (and the
> > Exynos7 fallback).
> > 
> > Signed-off-by: Alexandru Chimac alex at chimac.ro
> > ---
> > .../devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml | 2 ++
> > 1 file changed, 2 insertions(+)
> > 
> > diff --git a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml
> > index f3c433015b12..deb2730855bd 100644
> > --- a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml
> > +++ b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml
> > @@ -48,6 +48,7 @@ properties:
> > - enum:
> > - google,gs101-wakeup-eint
> > - samsung,exynos2200-wakeup-eint
> > + - samsung,exynos9610-wakeup-eint
> > - samsung,exynos9810-wakeup-eint
> > - samsung,exynos990-wakeup-eint
> > - samsung,exynosautov9-wakeup-eint
> > @@ -107,6 +108,7 @@ allOf:
> > contains:
> > enum:
> > - samsung,exynos850-wakeup-eint
> > + - samsung,exynos9610-wakeup-eint
> 
> 
> This is not needed. Device has 850 fallback, no?
It's not required, but I guess it would make the device tree look better. If this patch isn't to be merged, it doesn't functionally affect anything so it can just be dropped instead of requiring another patchset revision.
> 
> Best regards,
> Krzysztof
Best regards,
Alexandru Chimac


From david at kernel.org  Wed Dec 31 04:34:58 2025
From: david at kernel.org (David Hildenbrand (Red Hat))
Date: Wed, 31 Dec 2025 13:34:58 +0100
Subject: [PATCH v3 0/2] fix wrong usage of memory allocation APIs under
 PREEMPT_RT in arm64
In-Reply-To: <aVT15bhN4hEBNaOg@e129823.arm.com>
References: <20251218194750.395301-1-yeoreum.yun@arm.com>
 <aVT15bhN4hEBNaOg@e129823.arm.com>
Message-ID: <d99b100b-0262-4f57-aadb-c16fea47e6cc@kernel.org>

On 12/31/25 11:07, Yeoreum Yun wrote:
> Gentle ping in case of forgotten.

A lot of people (including me, wait, why am I reading mails ;) ) are 
currently out, and will likely be out for the remainder of the week.

I'd assume people will look into it next week.

-- 
Cheers

David


From j at jannau.net  Wed Dec 31 04:34:59 2025
From: j at jannau.net (Janne Grunau)
Date: Wed, 31 Dec 2025 13:34:59 +0100
Subject: [PATCH] dmaengine: apple-admac: Add "apple,t8103-admac" compatible
Message-ID: <20251231-apple-admac-t8103-base-compat-v1-1-ec24a3708f76@jannau.net>

After discussion with the devicetree maintainers we agreed to not extend
lists with the generic compatible "apple,admac" anymore [1]. Use
"apple,t8103-admac" as base compatible as it is the SoC the driver and
bindings were written for.

[1]: https://lore.kernel.org/asahi/12ab93b7-1fc2-4ce0-926e-c8141cfe81bf at kernel.org/

Fixes: b127315d9a78 ("dmaengine: apple-admac: Add Apple ADMAC driver")
Cc: stable at vger.kernel.org
Reviewed-by: Neal Gompa <neal at gompa.dev>
Signed-off-by: Janne Grunau <j at jannau.net>
---
This is split off from the v1 series adding Apple M2 Pro/Max/Ultra
device trees in
https://lore.kernel.org/r/20250828-dt-apple-t6020-v1-0-507ba4c4b98e at jannau.net

Changes compared to the patch in that series:
- rebased onto v6.19-rc1
- added "Fixes:" and "Cc: stable" tags for handling this as fix adding a
  device id
- added Neal's Reviewed-by:
---
 drivers/dma/apple-admac.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/dma/apple-admac.c b/drivers/dma/apple-admac.c
index bd49f03742912198804a02a22e38da2c21093761..04bbd774b3b444f928986c266c53becf286daeea 100644
--- a/drivers/dma/apple-admac.c
+++ b/drivers/dma/apple-admac.c
@@ -936,6 +936,7 @@ static void admac_remove(struct platform_device *pdev)
 }
 
 static const struct of_device_id admac_of_match[] = {
+	{ .compatible = "apple,t8103-admac", },
 	{ .compatible = "apple,admac", },
 	{ }
 };

---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20251231-apple-admac-t8103-base-compat-18288e7d62b3

Best regards,
-- 
Janne Grunau <j at jannau.net>



From leitao at debian.org  Wed Dec 31 04:44:05 2025
From: leitao at debian.org (Breno Leitao)
Date: Wed, 31 Dec 2025 04:44:05 -0800
Subject: [PATCH] arm64/mm: Fix annotated branch unbootable kernel
Message-ID: <20251231-annotated-v1-1-9db1c0d03062@debian.org>

The arm64 kernel doesn't boot with annotated branches
(PROFILE_ANNOTATED_BRANCHES) enabled and CONFIG_DEBUG_VIRTUAL together.

Bisecting it, I found that disabling branch profiling in arch/arm64/mm
solved the problem. Narrowing down a bit further, I found that
physaddr.c is the file that needs to have branch profiling disabled to
get the machine to boot.

I suspect that it might invoke some ftrace helper very early in the boot
process and ftrace is still not enabled(!?).

Disable branch profiling for physaddr.o to allow booting an arm64
machine with CONFIG_PROFILE_ANNOTATED_BRANCHES and
CONFIG_DEBUG_VIRTUAL together.

Cc: stable at vger.kernel.org
Fixes: ec6d06efb0bac ("arm64: Add support for CONFIG_DEBUG_VIRTUAL")
Signed-off-by: Breno Leitao <leitao at debian.org>
---
Another approach is to disable profiling on all arch/arm64 code, similarly to
x86, where DISABLE_BRANCH_PROFILING is called for all arch/x86 code. See
commit 2cbb20b008dba ("tracing: Disable branch profiling in noinstr
code").
---
 arch/arm64/mm/Makefile | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/mm/Makefile b/arch/arm64/mm/Makefile
index c26489cf96cd..8bfe2451ea26 100644
--- a/arch/arm64/mm/Makefile
+++ b/arch/arm64/mm/Makefile
@@ -14,5 +14,10 @@ obj-$(CONFIG_ARM64_MTE)		+= mteswap.o
 obj-$(CONFIG_ARM64_GCS)		+= gcs.o
 KASAN_SANITIZE_physaddr.o	+= n
 
+# Branch profiling isn't noinstr-safe
+ifdef CONFIG_TRACE_BRANCH_PROFILING
+CFLAGS_physaddr.o += -DDISABLE_BRANCH_PROFILING
+endif
+
 obj-$(CONFIG_KASAN)		+= kasan_init.o
 KASAN_SANITIZE_kasan_init.o	:= n

---
base-commit: c8ebd433459bcbf068682b09544e830acd7ed222
change-id: 20251231-annotated-75de3f33cd7b

Best regards,
--  
Breno Leitao <leitao at debian.org>



From frederic at kernel.org  Wed Dec 31 05:18:59 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 31 Dec 2025 14:18:59 +0100
Subject: [PATCH 01/33] PCI: Prepare to protect against concurrent
 isolated cpuset change
In-Reply-To: <81f201cc-395a-48d7-a1b0-db8c62b93c9e@redhat.com>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-2-frederic@kernel.org>
 <e01189e1-d8ef-2791-632c-90d4d897859b@huawei.com>
 <81f201cc-395a-48d7-a1b0-db8c62b93c9e@redhat.com>
Message-ID: <aVUiw34NAG3OfOV8@localhost.localdomain>

Le Sun, Dec 28, 2025 at 10:53:41PM -0500, Waiman Long a ?crit :
> On 12/28/25 10:23 PM, Zhang Qiao wrote:
> > >   	if (node < 0 || node >= MAX_NUMNODES || !node_online(node) ||
> > >   	    pci_physfn_is_probed(dev)) {
> > > -		cpu = nr_cpu_ids;
> > > +		error = local_pci_probe(&ddi);
> > >   	} else {
> > >   		cpumask_var_t wq_domain_mask;
> > > +		struct pci_probe_arg arg = { .ddi = &ddi };
> > > +
> > > +		INIT_WORK_ONSTACK(&arg.work, local_pci_probe_callback);
> > >   		if (!zalloc_cpumask_var(&wq_domain_mask, GFP_KERNEL)) {
> > >   			error = -ENOMEM;
> > If we return from here, arg.work will not be destroyed.
> > 
> > 
> Right. INIT_WORK_ONSTACK() should be called after successful cpumask_var_t
> allocation.

Doing that, thank you both!

-- 
Frederic Weisbecker
SUSE Labs


From frederic at kernel.org  Wed Dec 31 05:45:29 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 31 Dec 2025 14:45:29 +0100
Subject: [PATCH 05/33] sched/isolation: Save boot defined domain flags
In-Reply-To: <04708b57-7ffe-4a97-925f-926d577061a6@redhat.com>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-6-frederic@kernel.org>
 <04708b57-7ffe-4a97-925f-926d577061a6@redhat.com>
Message-ID: <aVUo-csI1gqZL89O@localhost.localdomain>

Le Thu, Dec 25, 2025 at 05:27:54PM -0500, Waiman Long a ?crit :
> On 12/24/25 8:44 AM, Frederic Weisbecker wrote:
> > HK_TYPE_DOMAIN will soon integrate not only boot defined isolcpus= CPUs
> > but also cpuset isolated partitions.
> > 
> > Housekeeping still needs a way to record what was initially passed
> > to isolcpus= in order to keep these CPUs isolated after a cpuset
> > isolated partition is modified or destroyed while containing some of
> > them.
> > 
> > Create a new HK_TYPE_DOMAIN_BOOT to keep track of those.
> > 
> > Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
> > Reviewed-by: Phil Auld <pauld at redhat.com>
> > ---
> >   include/linux/sched/isolation.h | 4 ++++
> >   kernel/sched/isolation.c        | 5 +++--
> >   2 files changed, 7 insertions(+), 2 deletions(-)
> > 
> > diff --git a/include/linux/sched/isolation.h b/include/linux/sched/isolation.h
> > index d8501f4709b5..109a2149e21a 100644
> > --- a/include/linux/sched/isolation.h
> > +++ b/include/linux/sched/isolation.h
> > @@ -7,8 +7,12 @@
> >   #include <linux/tick.h>
> >   enum hk_type {
> > +	/* Revert of boot-time isolcpus= argument */
> > +	HK_TYPE_DOMAIN_BOOT,
> >   	HK_TYPE_DOMAIN,
> > +	/* Revert of boot-time isolcpus=managed_irq argument */
> >   	HK_TYPE_MANAGED_IRQ,
> > +	/* Revert of boot-time nohz_full= or isolcpus=nohz arguments */
> >   	HK_TYPE_KERNEL_NOISE,
> >   	HK_TYPE_MAX,
> 
> "Revert" is a verb. The term "Revert of" sound strange to me. I think using
> "Inverse of" will sound better.

Somehow I thought it could be a noun as well. At least I wouldn't mind if
it ever turns that way.

Fixing that, thanks.

> 
> Cheers,
> Longman
> 

-- 
Frederic Weisbecker
SUSE Labs


From frederic at kernel.org  Wed Dec 31 06:02:34 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 31 Dec 2025 15:02:34 +0100
Subject: [PATCH 09/33] block: Protect against concurrent isolated cpuset
 change
In-Reply-To: <0f65c4fe-8b10-403d-b5b6-ed33fc4eb69c@kernel.dk>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-10-frederic@kernel.org>
 <0f65c4fe-8b10-403d-b5b6-ed33fc4eb69c@kernel.dk>
Message-ID: <aVUs-mFYCO2qGmqT@localhost.localdomain>

Le Mon, Dec 29, 2025 at 05:37:29PM -0700, Jens Axboe a ?crit :
> On 12/24/25 6:44 AM, Frederic Weisbecker wrote:
> > The block subsystem prevents running the workqueue to isolated CPUs,
> > including those defined by cpuset isolated partitions. Since
> > HK_TYPE_DOMAIN will soon contain both and be subject to runtime
> > modifications, synchronize against housekeeping using the relevant lock.
> > 
> > For full support of cpuset changes, the block subsystem may need to
> > propagate changes to isolated cpumask through the workqueue in the
> > future.
> > 
> > Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
> > ---
> >  block/blk-mq.c | 6 +++++-
> >  1 file changed, 5 insertions(+), 1 deletion(-)
> > 
> > diff --git a/block/blk-mq.c b/block/blk-mq.c
> > index 1978eef95dca..0037af1216f3 100644
> > --- a/block/blk-mq.c
> > +++ b/block/blk-mq.c
> > @@ -4257,12 +4257,16 @@ static void blk_mq_map_swqueue(struct request_queue *q)
> >  
> >  		/*
> >  		 * Rule out isolated CPUs from hctx->cpumask to avoid
> > -		 * running block kworker on isolated CPUs
> > +		 * running block kworker on isolated CPUs.
> > +		 * FIXME: cpuset should propagate further changes to isolated CPUs
> > +		 * here.
> >  		 */
> > +		rcu_read_lock();
> >  		for_each_cpu(cpu, hctx->cpumask) {
> >  			if (cpu_is_isolated(cpu))
> >  				cpumask_clear_cpu(cpu, hctx->cpumask);
> >  		}
> > +		rcu_read_unlock();
> 
> Want me to just take this one separately and get it out of your hair?
> Doesn't seem to have any dependencies.

The patch could be applied alone but the rest of the patchset needs it,
otherwise it may dereference freed memory. So I fear it needs to stay
within the lot.

I appreciate the offer though. But an ack would help, even if I must admit
this single patch (which doesn't change current behaviour) leaves a
bitter taste because complete handling of cpuset isolated partition change
will require more work.

Speaking of, is there a way that I missed to define/overwrite the above
hctx->cpumask on runtime?

Thanks.
-- 
Frederic Weisbecker
SUSE Labs


From marek.vasut at mailbox.org  Wed Dec 31 06:09:27 2025
From: marek.vasut at mailbox.org (Marek Vasut)
Date: Wed, 31 Dec 2025 15:09:27 +0100
Subject: [PATCH] arm64: dts: imx95: Use GPU_CGC as core clock for GPU
In-Reply-To: <aVSTJdnWm2KfpXa1@oss.nxp.com>
References: <aTACuRjC_Zpf8IOU@oss.nxp.com>
 <de36091e-c890-4897-b3e3-2a7575029a5d@mailbox.org>
 <aTD5np-HGaJqhzkD@oss.nxp.com>
 <5944d872-01a3-47e9-977b-029f3be4fd83@mailbox.org>
 <aTKVMAMQ6v_BwD6R@oss.nxp.com>
 <9b593731-898f-46a7-8ee5-68f8c170351c@mailbox.org>
 <aTYxm_dfMwF4H0_b@oss.nxp.com>
 <53ea529f-3538-4ab5-aa99-0caa6729b4cd@mailbox.org>
 <aVM-mSkSubMPd7Du@oss.nxp.com>
 <6055d6f3-2b31-4225-a42e-0f5ad79f7256@mailbox.org>
 <aVSTJdnWm2KfpXa1@oss.nxp.com>
Message-ID: <4f890538-f2f9-408b-9644-73708e7e7b24@mailbox.org>

On 12/31/25 4:06 AM, Rain Yang wrote:
> On Tue, Dec 30, 2025 at 03:17:44PM +0100, Marek Vasut wrote:
>> On 12/30/25 3:53 AM, Rain Yang wrote:
>>> On Tue, Dec 30, 2025 at 02:53:38AM +0100, Marek Vasut wrote:
>>>> On 12/8/25 3:02 AM, Rain Yang wrote:
>>>>
>>>>>>> Okay, I?ll submit a patch later.
>>>>>>> The commit message should reflect that only CLK_GPU_CGC is enabled.
>>>>>>
>>>>>> The commit message , and this change , is unrelated to GPUAPB clock.
>>>>> The commit message is ambiguous. Could you clarify which parent clock
>>>>> you are referring to, and whether it can be enabled by CLK_GPU_CGC?
>>>>> If it was CLK_GPU, CLK_GPU_CGC can't be able to control it.
>>>>
>>>> The commit message clearly states "These new GPU_CGC clock
>>>> gate the existing GPU clock." and "GPU_CGC as well as its parent GPU clock."
>>>> , I don't perceive any ambiguity, sorry.
>>>>
>>>> Frankly, the whole GPUAPB discussion is entirely unrelated and it only stalls
>>>> application of this bugfix and keeps upstream broken. This is not helping.
>>>>
>>>> So unless there is anything in particular that is on-topic and prevents this
>>>> patch from being applied, it would be good to apply it, otherwise the GPU on
>>>> MX95 in mainline Linux is not working.
>>> Hi Marek,
>>>
>>> I?m not opposed to this patch being merged into mainline, but the commit
>>> message needs to be accurate. the parent CLK_GPU cannot be enabled or
>>> disabled externally. The last sentence should clearly state:
>>
>> Look here, this is what you can do with the MX95 SM:
>>
>> "
>>> $ clock.r
>> ...
>> 083: gpuapb               =  on,  133333333Hz
>> 084: gpu                  =  on,  800000000Hz
>> ...
>> 174: gpu_cgc              =  on,  800000000Hz
>>
>>> $ clock.w gpu_cgc off
>>> $ clock.w gpu off
>>> $ clock.w gpuapb off
>>
>>> $ clock.r
>> ...
>> 083: gpuapb               = off,  133333333Hz
>> 084: gpu                  = off,  800000000Hz
>> ...
>> 174: gpu_cgc              = off,  800000000Hz
>> "
>>
>> Notice how all clock are disabled, including GPU clock.
>>
>> That does not agree with your statement.
>>
>>> When the panthor driver enables the GPU core clock, it enables the GPU_CGC.
>>
>> It also enables all disabled parent clock in the process, which includes the
>> GPU clock.
>>
>>> This ensures the description reflects the actual hardware behavior and
>>> avoids confusion for future maintainers.
>>> Thanks for addressing this issue ? once the commit message is corrected,
>>> I?m fine with this going in.
>>
>> See above.
> 
> Hi Marek,
> Based on the instructions you gave, I?d put it this way, even though the
> CLK_GPU clock can only be controlled internally.
> 
> I?m fine with your patch now.

Thank you


From frederic at kernel.org  Wed Dec 31 06:21:56 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 31 Dec 2025 15:21:56 +0100
Subject: [PATCH 14/33] cpuset: Update HK_TYPE_DOMAIN cpumask from cpuset
In-Reply-To: <8ecb22ab-d719-44b4-ad40-5af0a185682a@huaweicloud.com>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-15-frederic@kernel.org>
 <8ecb22ab-d719-44b4-ad40-5af0a185682a@huaweicloud.com>
Message-ID: <aVUxhNlKaT0r6F5c@localhost.localdomain>

Le Fri, Dec 26, 2025 at 04:08:04PM +0800, Chen Ridong a ?crit :
> > +int housekeeping_update(struct cpumask *isol_mask, enum hk_type type)
> > +{
> > +	struct cpumask *trial, *old = NULL;
> > +
> > +	if (type != HK_TYPE_DOMAIN)
> > +		return -ENOTSUPP;
> > +
> 
> Nit:
> 
> The current if statement indicates that we only support modifying the cpumask for HK_TYPE_DOMAIN,
> which makes the type argument seem unnecessary. This seems to be designed for better scalability.
> However, when a new type needs to be supported in the future, this statement would have to be
> removed. Also, the use of cpumask_andnot below is not a general operation.
> 
> Anyway, looks good to me.

Ok, let's remove the parameter for now.

> > diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
> > index 475bdab3b8db..653e898a996a 100644
> > --- a/kernel/sched/sched.h
> > +++ b/kernel/sched/sched.h
> > @@ -30,6 +30,7 @@
> >  #include <linux/context_tracking.h>
> >  #include <linux/cpufreq.h>
> >  #include <linux/cpumask_api.h>
> > +#include <linux/cpuset.h>
> >  #include <linux/ctype.h>
> >  #include <linux/file.h>
> >  #include <linux/fs_api.h>
> 
> Reviewed-by: Chen Ridong <chenridong at huawei.com>

Thanks!

-- 
Frederic Weisbecker
SUSE Labs


From linux at roeck-us.net  Wed Dec 31 06:28:17 2025
From: linux at roeck-us.net (Guenter Roeck)
Date: Wed, 31 Dec 2025 06:28:17 -0800
Subject: [PATCH] watchdog: apple: Add "apple,t8103-wdt" compatible
In-Reply-To: <20251231-watchdog-apple-t8103-base-compat-v1-1-1702a02e0c45@jannau.net>
References: <20251231-watchdog-apple-t8103-base-compat-v1-1-1702a02e0c45@jannau.net>
Message-ID: <68e8bd60-85b1-4b4a-8a82-f47640ad0ad9@roeck-us.net>

On Wed, Dec 31, 2025 at 01:07:21PM +0100, Janne Grunau wrote:
> After discussion with the devicetree maintainers we agreed to not extend
> lists with the generic compatible "apple,wdt" anymore [1]. Use
> "apple,t8103-wdt" as base compatible as it is the SoC the driver and
> bindings were written for.
> 
> [1]: https://lore.kernel.org/asahi/12ab93b7-1fc2-4ce0-926e-c8141cfe81bf at kernel.org/
> 
I don't understand the rationake from the reference. This patch will need
an Ack from a DT maintainer.

Thanks,
Guenter

> Fixes: 4ed224aeaf66 ("watchdog: Add Apple SoC watchdog driver")
> Cc: stable at vger.kernel.org
> Reviewed-by: Neal Gompa <neal at gompa.dev>
> Signed-off-by: Janne Grunau <j at jannau.net>
> ---
> This is split off from the v1 series adding Apple M2 Pro/Max/Ultra
> device trees in [2].
> 
> 2: https://lore.kernel.org/r/20250828-dt-apple-t6020-v1-0-507ba4c4b98e at jannau.net
> ---
>  drivers/watchdog/apple_wdt.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/watchdog/apple_wdt.c b/drivers/watchdog/apple_wdt.c
> index 66a158f67a712bbed394d660071e02140e66c2e5..6b9b0f9b05cedfd7fc5d0d79ba19ab356dc2a080 100644
> --- a/drivers/watchdog/apple_wdt.c
> +++ b/drivers/watchdog/apple_wdt.c
> @@ -218,6 +218,7 @@ static int apple_wdt_suspend(struct device *dev)
>  static DEFINE_SIMPLE_DEV_PM_OPS(apple_wdt_pm_ops, apple_wdt_suspend, apple_wdt_resume);
>  
>  static const struct of_device_id apple_wdt_of_match[] = {
> +	{ .compatible = "apple,t8103-wdt" },
>  	{ .compatible = "apple,wdt" },
>  	{},
>  };
> 
> ---
> base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
> change-id: 20251231-watchdog-apple-t8103-base-compat-8a623e9831b6
> 
> Best regards,
> -- 
> Janne Grunau <j at jannau.net>
> 


From frederic at kernel.org  Wed Dec 31 06:37:36 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 31 Dec 2025 15:37:36 +0100
Subject: [PATCH 17/33] PCI: Flush PCI probe workqueue on cpuset isolated
 partition change
In-Reply-To: <c724aac7-5647-4253-bf7b-4ea92ea5d167@huaweicloud.com>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-18-frederic@kernel.org>
 <c724aac7-5647-4253-bf7b-4ea92ea5d167@huaweicloud.com>
Message-ID: <aVU1MIyJ3VH4V80O@localhost.localdomain>

Le Fri, Dec 26, 2025 at 04:48:10PM +0800, Chen Ridong a ?crit :
> > @@ -145,6 +146,7 @@ int housekeeping_update(struct cpumask *isol_mask, enum hk_type type)
> >  
> >  	synchronize_rcu();
> >  
> > +	pci_probe_flush_workqueue();
> >  	mem_cgroup_flush_workqueue();
> >  	vmstat_flush_workqueue();
> >  
> 
> I am concerned that this flush work may slow down writes to the cpuset interface. I am not sure how
> significant the impact will be.

First, writing to cpuset is not something that should be considered as a fast
path. It is a preparation work at configuration time that can tolerate a few
milliseconds of delay, which I expect to be what we should encounter most
of time here.

Second, this is not a "usual" cpuset partition write. CPU isolation is a niche
usecase (real time or Data plane). User must expect tradeoffs against the offer.

Third, about this very patch, most pci probe should happen at boot time before
cgroup is even accessible to userspace.

> I'm concerned about potential deadlock risks. While preliminary investigation hasn't uncovered any
> issues, we must ensure that the cpu write lock is not held during the work(writing cpuset interface
> needs cpu read lock).

That's what we have lockdep for :-)

Thanks.

-- 
Frederic Weisbecker
SUSE Labs


From m.szyprowski at samsung.com  Wed Dec 31 06:43:19 2025
From: m.szyprowski at samsung.com (Marek Szyprowski)
Date: Wed, 31 Dec 2025 15:43:19 +0100
Subject: [PATCH v2 4/8] dma-mapping: Separate DMA sync issuing and
 completion waiting
In-Reply-To: <CAGsJ_4y=yoYZn+_ztdfuOCj_dS-M0h8YWO51AXubPbeR1FH6uQ@mail.gmail.com>
References: <20251226225254.46197-1-21cnbao@gmail.com>
	<20251226225254.46197-5-21cnbao@gmail.com> <20251227200706.GN11869@unreal>
	<CAGsJ_4zyascnpQ1cB-BMO9PDeeRZTBAh8Z-j-ip=RcxApa4zSg@mail.gmail.com>
	<20251228144909.GR11869@unreal>
	<CGME20251228213843eucas1p298280bb01abe59739cd6e0482f570455@eucas1p2.samsung.com>
	<CAGsJ_4y=yoYZn+_ztdfuOCj_dS-M0h8YWO51AXubPbeR1FH6uQ@mail.gmail.com>
Message-ID: <d19c559e-c93b-4a4d-9a0d-ec289ed4c2e6@samsung.com>

On 28.12.2025 22:38, Barry Song wrote:
> On Mon, Dec 29, 2025 at 3:49?AM Leon Romanovsky <leon at kernel.org> wrote:
>> On Sun, Dec 28, 2025 at 10:45:13AM +1300, Barry Song wrote:
>>> On Sun, Dec 28, 2025 at 9:07?AM Leon Romanovsky <leon at kernel.org> wrote:
>>>> On Sat, Dec 27, 2025 at 11:52:44AM +1300, Barry Song wrote:
>>>>> From: Barry Song <baohua at kernel.org>
>>>>>
>>>>> Currently, arch_sync_dma_for_cpu and arch_sync_dma_for_device
>>>>> always wait for the completion of each DMA buffer. That is,
>>>>> issuing the DMA sync and waiting for completion is done in a
>>>>> single API call.
>>>>>
>>>>> For scatter-gather lists with multiple entries, this means
>>>>> issuing and waiting is repeated for each entry, which can hurt
>>>>> performance. Architectures like ARM64 may be able to issue all
>>>>> DMA sync operations for all entries first and then wait for
>>>>> completion together.
>>>>>
>>>>> To address this, arch_sync_dma_for_* now issues DMA operations in
>>>>> batch, followed by a flush. On ARM64, the flush is implemented
>>>>> using a dsb instruction within arch_sync_dma_flush().
>>>>>
>>>>> For now, add arch_sync_dma_flush() after each
>>>>> arch_sync_dma_for_*() call. arch_sync_dma_flush() is defined as a
>>>>> no-op on all architectures except arm64, so this patch does not
>>>>> change existing behavior. Subsequent patches will introduce true
>>>>> batching for SG DMA buffers.
>>>>>
>>>>> Cc: Leon Romanovsky <leon at kernel.org>
>>>>> Cc: Catalin Marinas <catalin.marinas at arm.com>
>>>>> Cc: Will Deacon <will at kernel.org>
>>>>> Cc: Marek Szyprowski <m.szyprowski at samsung.com>
>>>>> Cc: Robin Murphy <robin.murphy at arm.com>
>>>>> Cc: Ada Couprie Diaz <ada.coupriediaz at arm.com>
>>>>> Cc: Ard Biesheuvel <ardb at kernel.org>
>>>>> Cc: Marc Zyngier <maz at kernel.org>
>>>>> Cc: Anshuman Khandual <anshuman.khandual at arm.com>
>>>>> Cc: Ryan Roberts <ryan.roberts at arm.com>
>>>>> Cc: Suren Baghdasaryan <surenb at google.com>
>>>>> Cc: Joerg Roedel <joro at 8bytes.org>
>>>>> Cc: Juergen Gross <jgross at suse.com>
>>>>> Cc: Stefano Stabellini <sstabellini at kernel.org>
>>>>> Cc: Oleksandr Tyshchenko <oleksandr_tyshchenko at epam.com>
>>>>> Cc: Tangquan Zheng <zhengtangquan at oppo.com>
>>>>> Signed-off-by: Barry Song <baohua at kernel.org>
>>>>> ---
>>>>>   arch/arm64/include/asm/cache.h |  6 ++++++
>>>>>   arch/arm64/mm/dma-mapping.c    |  4 ++--
>>>>>   drivers/iommu/dma-iommu.c      | 37 +++++++++++++++++++++++++---------
>>>>>   drivers/xen/swiotlb-xen.c      | 24 ++++++++++++++--------
>>>>>   include/linux/dma-map-ops.h    |  6 ++++++
>>>>>   kernel/dma/direct.c            |  8 ++++++--
>>>>>   kernel/dma/direct.h            |  9 +++++++--
>>>>>   kernel/dma/swiotlb.c           |  4 +++-
>>>>>   8 files changed, 73 insertions(+), 25 deletions(-)
>>>> <...>
>>>>
>>>>> +#ifndef arch_sync_dma_flush
>>>>> +static inline void arch_sync_dma_flush(void)
>>>>> +{
>>>>> +}
>>>>> +#endif
>>>> Over the weekend I realized a useful advantage of the ARCH_HAVE_* config
>>>> options: they make it straightforward to inspect the entire DMA path simply
>>>> by looking at the .config.
>>> I am not quite sure how much this benefits users, as the same
>>> information could also be obtained by grepping for
>>> #define arch_sync_dma_flush in the source code.
>> It differs slightly. Users no longer need to grep around or guess whether this
>> platform used the arch_sync_dma_flush path. A simple grep for ARCH_HAVE_ in
>> /proc/config.gz provides the answer.
> In any case, it is only two or three lines of code, so I am fine with
> either approach. Perhaps Marek, Robin, and others have a point here?

If possible I would suggest to follow the already used style in the 
given code even if it means a bit larger patch.

>>>> Thanks,
>>>> Reviewed-by: Leon Romanovsky <leonro at nvidia.com>
>>> Thanks very much, Leon, for reviewing this over the weekend. One thing
>>> you might have missed is that I place arch_sync_dma_flush() after all
>>> arch_sync_dma_for_*() calls, for both single and sg cases. I also
>>> used a Python script to scan the code and verify that every
>>> arch_sync_dma_for_*() is followed by arch_sync_dma_flush(), to ensure
>>> that no call is left out.
>>>
>>> In the subsequent patches, for sg cases, the per-entry flush is
>>> replaced by a single flush of the entire sg. Each sg case has
>>> different characteristics: some are straightforward, while others
>>> can be tricky and involve additional contexts.
>> I didn't overlook it, and I understand your rationale. However, this is
>> not how kernel patches should be structured. You should not introduce
>> code in patch X and then move it elsewhere in patch X + Y.
> I am not quite convinced by this concern. This patch only
> separates DMA sync issuing from completion waiting, and it
> reflects that the development is done step by step.
>
>> Place the code in the correct location from the start. Your patches are
>> small enough to review as is.
> My point is that this patch places the code in the correct locations
> from the start. It splits arch_sync_dma_for_*() into
> arch_sync_dma_for_*() plus arch_sync_dma_flush() everywhere, without
> introducing any functional changes from the outset.
> The subsequent patches clearly show which parts are truly batched.
>
> In the meantime, I do not have a strong preference here. If you think
> it is better to move some of the straightforward batching code here,
> I can follow that approach. Perhaps I could move patch 5, patch 8,
> and the iommu_dma_iova_unlink_range_slow change from patch 7 here,
> while keeping
>
>    [PATCH 6] dma-mapping: Support batch mode for
>    dma_direct_{map,unmap}_sg
>
> and the IOVA link part from patch 7 as separate patches, since that
> part is not straightforward. The IOVA link changes affect both
> __dma_iova_link() and dma_iova_sync(), which are two separate
> functions and require a deeper understanding of the contexts to
> determine correctness. That part also lacks testing.
>
> Would that be okay with you?

Yes, this will be okay. The changes are easy to understand, so we don't 
need to go there with such very small steps.

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland



From marek.vasut at mailbox.org  Wed Dec 31 06:11:21 2025
From: marek.vasut at mailbox.org (Marek Vasut)
Date: Wed, 31 Dec 2025 15:11:21 +0100
Subject: [PATCH] arm64: dts: imx95: remove CLK_GPUAPB
In-Reply-To: <20251231031915.752262-1-jiyu.yang@oss.nxp.com>
References: <20251231031915.752262-1-jiyu.yang@oss.nxp.com>
Message-ID: <37489cb7-820d-46cd-a7ea-0f9097604895@mailbox.org>

On 12/31/25 4:19 AM, Rain Yang wrote:
> From: Rain Yang <jiyu.yang at nxp.com>
> 
> Dropping CLK_GPUAPB simplifies OPP handling and avoids unnecessary
> complexity.
> 
> Fixes: 67934f248e64 ("arm64: dts: imx95: Describe Mali G310 GPU")
> Signed-off-by: Rain Yang <jiyu.yang at nxp.com>
> ---
>   arch/arm64/boot/dts/freescale/imx95.dtsi | 4 ++--
>   1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/freescale/imx95.dtsi b/arch/arm64/boot/dts/freescale/imx95.dtsi
> index 88bde59e61b2..ab446aa6f73c 100644
> --- a/arch/arm64/boot/dts/freescale/imx95.dtsi
> +++ b/arch/arm64/boot/dts/freescale/imx95.dtsi
> @@ -2164,8 +2164,8 @@ netc_emdio: mdio at 0,0 {
>   		gpu: gpu at 4d900000 {
>   			compatible = "nxp,imx95-mali", "arm,mali-valhall-csf";
>   			reg = <0 0x4d900000 0 0x480000>;
> -			clocks = <&scmi_clk IMX95_CLK_GPU_CGC>, <&scmi_clk IMX95_CLK_GPUAPB>;
> -			clock-names = "core", "coregroup";
> +			clocks = <&scmi_clk IMX95_CLK_GPU_CGC>;
> +			clock-names = "core";

I don't think this is correct, SM can disable the GPUAPB clock from the 
SM monitor:

 >$ clock.w gpuapb off

Linux has to make sure the GPUAPB clock are enabled to access the GPU 
register, hence the clock have to be described in DT.


From gary at garyguo.net  Wed Dec 31 07:12:16 2025
From: gary at garyguo.net (Gary Guo)
Date: Wed, 31 Dec 2025 15:12:16 +0000
Subject: [PATCH 0/5] Add READ_ONCE and WRITE_ONCE to Rust
In-Reply-To: <20251231-rwonce-v1-0-702a10b85278@google.com>
References: <20251231-rwonce-v1-0-702a10b85278@google.com>
Message-ID: <20251231151216.23446b64.gary@garyguo.net>

On Wed, 31 Dec 2025 12:22:24 +0000
Alice Ryhl <aliceryhl at google.com> wrote:

> There are currently a few places in the kernel where we use volatile
> reads when we really should be using `READ_ONCE`. To make it possible to
> replace these with proper `READ_ONCE` calls, introduce a Rust version of
> `READ_ONCE`.
> 
> A new config option CONFIG_ARCH_USE_CUSTOM_READ_ONCE is introduced so
> that Rust is able to use conditional compilation to implement READ_ONCE
> in terms of either a volatile read, or by calling into a C helper
> function, depending on the architecture.
> 
> This series is intended to be merged through ATOMIC INFRASTRUCTURE.

Hi Alice,

I would prefer not to expose the READ_ONCE/WRITE_ONCE functions, at
least not with their atomic semantics.

Both callsites that you have converted should be using

	Atomic::from_ptr().load(Relaxed)

Please refer to the documentation of `Atomic` about this. Fujita has a
series that expand the type to u8/u16 if you need narrower accesses.

Best,
Gary


> 
> Signed-off-by: Alice Ryhl <aliceryhl at google.com>
> ---
> Alice Ryhl (5):
>       arch: add CONFIG_ARCH_USE_CUSTOM_READ_ONCE for arm64/alpha
>       rust: sync: add READ_ONCE and WRITE_ONCE
>       rust: sync: support using bool with READ_ONCE
>       rust: hrtimer: use READ_ONCE instead of read_volatile
>       rust: fs: use READ_ONCE instead of read_volatile
> 
>  MAINTAINERS                     |   2 +
>  arch/Kconfig                    |  11 +++
>  arch/alpha/Kconfig              |   1 +
>  arch/alpha/include/asm/rwonce.h |   4 +-
>  arch/arm64/Kconfig              |   1 +
>  arch/arm64/include/asm/rwonce.h |   4 +-
>  rust/helpers/helpers.c          |   1 +
>  rust/helpers/rwonce.c           |  34 +++++++
>  rust/kernel/fs/file.rs          |   8 +-
>  rust/kernel/sync.rs             |   2 +
>  rust/kernel/sync/rwonce.rs      | 207 ++++++++++++++++++++++++++++++++++++++++
>  rust/kernel/time/hrtimer.rs     |   8 +-
>  12 files changed, 268 insertions(+), 15 deletions(-)
> ---
> base-commit: f8f9c1f4d0c7a64600e2ca312dec824a0bc2f1da
> change-id: 20251230-rwonce-1e8d2ee0bcf9
> 
> Best regards,



From gary at garyguo.net  Wed Dec 31 07:25:34 2025
From: gary at garyguo.net (Gary Guo)
Date: Wed, 31 Dec 2025 15:25:34 +0000
Subject: [PATCH 3/5] rust: sync: support using bool with READ_ONCE
In-Reply-To: <20251231-rwonce-v1-3-702a10b85278@google.com>
References: <20251231-rwonce-v1-0-702a10b85278@google.com>
	<20251231-rwonce-v1-3-702a10b85278@google.com>
Message-ID: <20251231152534.14903719.gary@garyguo.net>

On Wed, 31 Dec 2025 12:22:27 +0000
Alice Ryhl <aliceryhl at google.com> wrote:

> Normally it is undefined behavior for a bool to take any value other
> than 0 or 1. However, in the case of READ_ONCE(some_bool) is used, this
> UB seems dangerous and unnecessary. I can easily imagine some Rust code
> that looks like this:
> 
> 	if READ_ONCE(&raw const (*my_c_struct).my_bool_field) {
> 	    ...
> 	}
> 
> And by making an analogy to what the equivalent C code is, anyone
> writing this probably just meant to treat any non-zero value as true.

In C, bool can only hold value `false` and `true`, too, and putting
any other value there is going to be UB.

The C language provides automatic cast so when you write an integer to it,
non-zero values will cause `true` to be written. However, you're not
allowed to cast it into a char ptr and write other values into it.

So I think there shouldn't be any special treatment to boolean type in
this regard.

Best,
Gary

> 
> For WRITE_ONCE no special logic is required.
> 
> Signed-off-by: Alice Ryhl <aliceryhl at google.com>
> ---
>  rust/kernel/sync/rwonce.rs | 19 +++++++++++++++++++
>  1 file changed, 19 insertions(+)
> 
> diff --git a/rust/kernel/sync/rwonce.rs b/rust/kernel/sync/rwonce.rs
> index a1660e43c9ef94011812d1816713cf031a73de1d..73477f53131926996614df573b2d50fff98e624f 100644
> --- a/rust/kernel/sync/rwonce.rs
> +++ b/rust/kernel/sync/rwonce.rs
> @@ -163,6 +163,7 @@ unsafe fn write_once(ptr: *mut Self, val: Self) {
>  // sizes, so picking the wrong helper should lead to a build error.
>  
>  impl_rw_once_type! {
> +    bool, read_once_bool, write_once_1;
>      u8,   read_once_1, write_once_1;
>      i8,   read_once_1, write_once_1;
>      u16,  read_once_2, write_once_2;
> @@ -186,3 +187,21 @@ unsafe fn write_once(ptr: *mut Self, val: Self) {
>      usize, read_once_8, write_once_8;
>      isize, read_once_8, write_once_8;
>  }
> +
> +/// Read an integer as a boolean once.
> +///
> +/// Returns `true` if the value behind the pointer is non-zero. Otherwise returns `false`.
> +///
> +/// # Safety
> +///
> +/// It must be safe to `READ_ONCE` the `ptr` with type `u8`.
> +#[inline(always)]
> +#[track_caller]
> +unsafe fn read_once_bool(ptr: *const bool) -> bool {
> +    // Implement `read_once_bool` in terms of `read_once_1`. The arch-specific logic is inside
> +    // of `read_once_1`.
> +    //
> +    // SAFETY: It is safe to `READ_ONCE` the `ptr` with type `u8`.
> +    let byte = unsafe { read_once_1(ptr.cast::<u8>()) };
> +    byte != 0u8
> +}
> 



From frederic at kernel.org  Wed Dec 31 07:25:49 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 31 Dec 2025 16:25:49 +0100
Subject: [PATCH 33/33] doc: Add housekeeping documentation
In-Reply-To: <370149fc-1624-4a16-ac47-dd9b2dd0ed29@redhat.com>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-34-frederic@kernel.org>
 <370149fc-1624-4a16-ac47-dd9b2dd0ed29@redhat.com>
Message-ID: <aVVAfb2eaeyd7l-h@localhost.localdomain>

Le Fri, Dec 26, 2025 at 07:39:28PM -0500, Waiman Long a ?crit :
> On 12/24/25 8:45 AM, Frederic Weisbecker wrote:
> > Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
> > ---
> >   Documentation/core-api/housekeeping.rst | 111 ++++++++++++++++++++++++
> >   Documentation/core-api/index.rst        |   1 +
> >   2 files changed, 112 insertions(+)
> >   create mode 100644 Documentation/core-api/housekeeping.rst
> > 
> > diff --git a/Documentation/core-api/housekeeping.rst b/Documentation/core-api/housekeeping.rst
> > new file mode 100644
> > index 000000000000..e5417302774c
> > --- /dev/null
> > +++ b/Documentation/core-api/housekeeping.rst
> > @@ -0,0 +1,111 @@
> > +======================================
> > +Housekeeping
> > +======================================
> > +
> > +
> > +CPU Isolation moves away kernel work that may otherwise run on any CPU.
> > +The purpose of its related features is to reduce the OS jitter that some
> > +extreme workloads can't stand, such as in some DPDK usecases.
> Nit: "usecases" => "use cases"

Are you sure? I'm not a native speaker but at least the kernel
has established its use:

$ git grep usecase | wc -l
517

> > +
> > +The kernel work moved away by CPU isolation is commonly described as
> > +"housekeeping" because it includes ground work that performs cleanups,
> > +statistics maintainance and actions relying on them, memory release,
> > +various deferrals etc...
> > +
> > +Sometimes housekeeping is just some unbound work (unbound workqueues,
> > +unbound timers, ...) that gets easily assigned to non-isolated CPUs.
> > +But sometimes housekeeping is tied to a specific CPU and requires
> > +elaborated tricks to be offloaded to non-isolated CPUs (RCU_NOCB, remote
> > +scheduler tick, etc...).
> > +
> > +Thus, a housekeeping CPU can be considered as the reverse of an isolated
> > +CPU. It is simply a CPU that can execute housekeeping work. There must
> > +always be at least one online housekeeping CPU at any time. The CPUs that
> > +are not	isolated are automatically assigned as housekeeping.
> Nit: extra white spaces between "not" and "isolated".

Somehow it has disappeared in my tree, some Brunaidh must have fixed
that while I was sleeping. That's nice!

> > diff --git a/Documentation/core-api/index.rst b/Documentation/core-api/index.rst
> > index 5eb0fbbbc323..79fe7735692e 100644
> > --- a/Documentation/core-api/index.rst
> > +++ b/Documentation/core-api/index.rst
> > @@ -25,6 +25,7 @@ it.
> >      symbol-namespaces
> >      asm-annotations
> >      real-time/index
> > +   housekeeping.rst
> >   Data structures and low-level utilities
> >   =======================================
> Acked-by: Waiman Long <longman at redhat.com>

Thanks! 

-- 
Frederic Weisbecker
SUSE Labs


From axboe at kernel.dk  Wed Dec 31 07:30:39 2025
From: axboe at kernel.dk (Jens Axboe)
Date: Wed, 31 Dec 2025 08:30:39 -0700
Subject: [PATCH 09/33] block: Protect against concurrent isolated cpuset
 change
In-Reply-To: <aVUs-mFYCO2qGmqT@localhost.localdomain>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-10-frederic@kernel.org>
 <0f65c4fe-8b10-403d-b5b6-ed33fc4eb69c@kernel.dk>
 <aVUs-mFYCO2qGmqT@localhost.localdomain>
Message-ID: <4156bbde-754b-470e-9dfb-a1e45bee81fb@kernel.dk>

On 12/31/25 7:02 AM, Frederic Weisbecker wrote:
> Le Mon, Dec 29, 2025 at 05:37:29PM -0700, Jens Axboe a ?crit :
>> On 12/24/25 6:44 AM, Frederic Weisbecker wrote:
>>> The block subsystem prevents running the workqueue to isolated CPUs,
>>> including those defined by cpuset isolated partitions. Since
>>> HK_TYPE_DOMAIN will soon contain both and be subject to runtime
>>> modifications, synchronize against housekeeping using the relevant lock.
>>>
>>> For full support of cpuset changes, the block subsystem may need to
>>> propagate changes to isolated cpumask through the workqueue in the
>>> future.
>>>
>>> Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
>>> ---
>>>  block/blk-mq.c | 6 +++++-
>>>  1 file changed, 5 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/block/blk-mq.c b/block/blk-mq.c
>>> index 1978eef95dca..0037af1216f3 100644
>>> --- a/block/blk-mq.c
>>> +++ b/block/blk-mq.c
>>> @@ -4257,12 +4257,16 @@ static void blk_mq_map_swqueue(struct request_queue *q)
>>>  
>>>  		/*
>>>  		 * Rule out isolated CPUs from hctx->cpumask to avoid
>>> -		 * running block kworker on isolated CPUs
>>> +		 * running block kworker on isolated CPUs.
>>> +		 * FIXME: cpuset should propagate further changes to isolated CPUs
>>> +		 * here.
>>>  		 */
>>> +		rcu_read_lock();
>>>  		for_each_cpu(cpu, hctx->cpumask) {
>>>  			if (cpu_is_isolated(cpu))
>>>  				cpumask_clear_cpu(cpu, hctx->cpumask);
>>>  		}
>>> +		rcu_read_unlock();
>>
>> Want me to just take this one separately and get it out of your hair?
>> Doesn't seem to have any dependencies.
> 
> The patch could be applied alone but the rest of the patchset needs it,
> otherwise it may dereference freed memory. So I fear it needs to stay
> within the lot.
> 
> I appreciate the offer though. But an ack would help, even if I must admit
> this single patch (which doesn't change current behaviour) leaves a
> bitter taste because complete handling of cpuset isolated partition change
> will require more work.

That's fine too:

Acked-by: Jens Axboe <axboe at kernel.dk>

> Speaking of, is there a way that I missed to define/overwrite the above
> hctx->cpumask on runtime?

Only spot where it's set/manipulated right now is as part of setting up
the hctx <-> ctx queue mappings, when the queue is configured (or
reconfigured).

-- 
Jens Axboe


From j at jannau.net  Wed Dec 31 07:42:37 2025
From: j at jannau.net (Janne Grunau)
Date: Wed, 31 Dec 2025 16:42:37 +0100
Subject: [PATCH 0/2] arm64: defconfig: Enable Apple Silicon drivers
Message-ID: <20251231-arch-arm64-apple-defconfig-v1-0-4ff19805ba39@jannau.net>

Many Apple silicon specific drivers used "default ARCH_APPLE". [1]
attempted to fix this and add the drivers to arm64's defconfig. While
default Kconfig removals were merged adding the drivers to defconfig
was not. A follow-up based on the discussion was never sent and then
apparently forgotten.
This small series addresses that. APPLE_PMGR_PWRSTATE is now selected by
ARCH_APPLE as it is considered critical for booting just like interrupt
controller. Since its absence does not break booting completely but
leaves just a mostly useless system allow !PM builds without
APPLE_PMGR_PWRSTATE.
The defconfig change is updated to include forgotten drivers and drivers
which were added in the meantime.

1: https://lore.kernel.org/asahi/20250612-apple-kconfig-defconfig-v1-0-0e6f9cb512c1 at kernel.org/

Signed-off-by: Janne Grunau <j at jannau.net>
---
Janne Grunau (1):
      arm64: select APPLE_PMGR_PWRSTATE for ARCH_APPLE

Sven Peter (1):
      arm64: defconfig: Enable Apple Silicon drivers

 arch/arm64/Kconfig.platforms |  1 +
 arch/arm64/configs/defconfig | 27 +++++++++++++++++++++++++++
 2 files changed, 28 insertions(+)
---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20251231-arch-arm64-apple-defconfig-22de55a3d1cc

Best regards,
-- 
Janne Grunau <j at jannau.net>



From j at jannau.net  Wed Dec 31 07:42:38 2025
From: j at jannau.net (Janne Grunau)
Date: Wed, 31 Dec 2025 16:42:38 +0100
Subject: [PATCH 1/2] arm64: select APPLE_PMGR_PWRSTATE for ARCH_APPLE
In-Reply-To: <20251231-arch-arm64-apple-defconfig-v1-0-4ff19805ba39@jannau.net>
References: <20251231-arch-arm64-apple-defconfig-v1-0-4ff19805ba39@jannau.net>
Message-ID: <20251231-arch-arm64-apple-defconfig-v1-1-4ff19805ba39@jannau.net>

Critical devices like the NVMe on Apple silicon systems depend on
APPLE_PMGR_PWRSTATE and others are powered down coming out of reset so
select APPLE_PMGR_PWRSTATE to ensure these devices work. Since the
systems are not totally unsusable (boot to initramfs is expected to
work) allow !PM builds without APPLE_PMGR_PWRSTATE.

Link: https://lore.kernel.org/asahi/2e022f4e-4c87-4da1-9d02-f7a3ae7c5798 at arm.com/
Suggested-by: Robin Murphy <robin.murphy at arm.com>
Signed-off-by: Janne Grunau <j at jannau.net>
---
 arch/arm64/Kconfig.platforms | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index fff14807c965a19cd5ba7a2445be5fd77d94e7a8..200e5067560e4ac2cfeda01c97cfae112954a0fc 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -36,6 +36,7 @@ config ARCH_ALPINE
 config ARCH_APPLE
 	bool "Apple Silicon SoC family"
 	select APPLE_AIC
+	select APPLE_PMGR_PWRSTATE if PM
 	help
 	  This enables support for Apple's in-house ARM SoC family, such
 	  as the Apple M1.

-- 
2.52.0



From j at jannau.net  Wed Dec 31 07:42:39 2025
From: j at jannau.net (Janne Grunau)
Date: Wed, 31 Dec 2025 16:42:39 +0100
Subject: [PATCH 2/2] arm64: defconfig: Enable Apple Silicon drivers
In-Reply-To: <20251231-arch-arm64-apple-defconfig-v1-0-4ff19805ba39@jannau.net>
References: <20251231-arch-arm64-apple-defconfig-v1-0-4ff19805ba39@jannau.net>
Message-ID: <20251231-arch-arm64-apple-defconfig-v1-2-4ff19805ba39@jannau.net>

From: Sven Peter <sven at kernel.org>

Enable drivers for hardware present on Apple Silicon machines. None of
these drivers are critical so build them as modules. The reset and RTC
macsmc drivers would be useful as built-in drivers but they have large
dependencies so keep them as modules.

The size increases are minor and are offsetted by already merged
"default ARCH_APPLE" removals from the linked original submission.

vmlinux 157782640 -> 157902032 (+119392)
Image    41007616 ->  41073152 (+ 65536)

Link: https://lore.kernel.org/asahi/20250612-apple-kconfig-defconfig-v1-0-0e6f9cb512c1 at kernel.org/
Signed-off-by: Sven Peter <sven at kernel.org>
Signed-off-by: Janne Grunau <j at jannau.net>

---
Changes compared to the original submission:
- Remove AIC and APPLE_PMGR_PWRSTATE as those are selected by ARCH_APPLE
- Add new macsmc drivers (mfd, reset, hwmon, rtc and gpio)
- Add BACKLIGHT_APPLE_DWI, DRM_PANEL_SUMMIT and NVMEM_APPLE_SPMI
  (suggested by Nick Chan)
- Add PWM_APPLE and APPLE_M1_CPU_PMU
---
 arch/arm64/configs/defconfig | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 45288ec9eaf7365427d98195c48e2f8065a8bb1b..7370e56196cb65257ea6ee42b2872a4ed5dc0964 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -100,6 +100,7 @@ CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
 CONFIG_CPUFREQ_DT=y
 CONFIG_ACPI_CPPC_CPUFREQ=m
 CONFIG_ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM=m
+CONFIG_ARM_APPLE_SOC_CPUFREQ=m
 CONFIG_ARM_ARMADA_37XX_CPUFREQ=y
 CONFIG_ARM_SCPI_CPUFREQ=y
 CONFIG_ARM_IMX_CPUFREQ_DT=m
@@ -223,6 +224,7 @@ CONFIG_HOTPLUG_PCI_ACPI=y
 CONFIG_PCI_AARDVARK=y
 CONFIG_PCIE_ALTERA=y
 CONFIG_PCIE_ALTERA_MSI=y
+CONFIG_PCIE_APPLE=m
 CONFIG_PCIE_BRCMSTB=m
 CONFIG_PCI_HOST_THUNDER_PEM=y
 CONFIG_PCI_HOST_THUNDER_ECAM=y
@@ -301,6 +303,7 @@ CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_NBD=m
 CONFIG_VIRTIO_BLK=y
 CONFIG_BLK_DEV_NVME=m
+CONFIG_NVME_APPLE=m
 CONFIG_QCOM_COINCELL=m
 CONFIG_QCOM_FASTRPC=m
 CONFIG_SRAM=y
@@ -464,6 +467,7 @@ CONFIG_KEYBOARD_CROS_EC=y
 CONFIG_KEYBOARD_MTK_PMIC=m
 CONFIG_MOUSE_ELAN_I2C=m
 CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_APPLE_Z2=m
 CONFIG_TOUCHSCREEN_ATMEL_MXT=m
 CONFIG_TOUCHSCREEN_GOODIX=m
 CONFIG_TOUCHSCREEN_GOODIX_BERLIN_SPI=m
@@ -551,6 +555,7 @@ CONFIG_I2C_MT65XX=y
 CONFIG_I2C_MV64XXX=y
 CONFIG_I2C_OMAP=y
 CONFIG_I2C_OWL=y
+CONFIG_I2C_APPLE=m
 CONFIG_I2C_PXA=y
 CONFIG_I2C_QCOM_CCI=m
 CONFIG_I2C_QCOM_GENI=m
@@ -565,6 +570,7 @@ CONFIG_I2C_UNIPHIER_F=y
 CONFIG_I2C_RCAR=y
 CONFIG_I2C_CROS_EC_TUNNEL=y
 CONFIG_SPI=y
+CONFIG_SPI_APPLE=m
 CONFIG_SPI_ARMADA_3700=y
 CONFIG_SPI_BCM2835=m
 CONFIG_SPI_BCM2835AUX=m
@@ -601,7 +607,9 @@ CONFIG_SPI_TEGRA210_QUAD=m
 CONFIG_SPI_TEGRA114=m
 CONFIG_SPI_SPIDEV=m
 CONFIG_SPMI=y
+CONFIG_SPMI_APPLE=m
 CONFIG_SPMI_MTK_PMIF=m
+CONFIG_PINCTRL_APPLE_GPIO=m
 CONFIG_PINCTRL_BRCMSTB=y
 CONFIG_PINCTRL_BCM2712=y
 CONFIG_PINCTRL_DA9062=m
@@ -698,9 +706,11 @@ CONFIG_GPIO_ADP5585=m
 CONFIG_GPIO_PCF857X=m
 CONFIG_GPIO_TPIC2810=m
 CONFIG_GPIO_BD9571MWV=m
+CONFIG_GPIO_MACSMC=m
 CONFIG_GPIO_MAX77620=y
 CONFIG_GPIO_SL28CPLD=m
 CONFIG_GPIO_AGGREGATOR=m
+CONFIG_POWER_RESET_MACSMC=m
 CONFIG_POWER_RESET_MSM=y
 CONFIG_POWER_RESET_QCOM_PON=m
 CONFIG_POWER_RESET_TORADEX_EC=m
@@ -721,6 +731,7 @@ CONFIG_SENSORS_ARM_SCMI=y
 CONFIG_SENSORS_ARM_SCPI=y
 CONFIG_SENSORS_GPIO_FAN=m
 CONFIG_SENSORS_JC42=m
+CONFIG_SENSORS_MACSMC_HWMON=m
 CONFIG_SENSORS_LM75=m
 CONFIG_SENSORS_LM90=m
 CONFIG_SENSORS_PWM_FAN=m
@@ -782,6 +793,7 @@ CONFIG_RENESAS_RZG2LWDT=y
 CONFIG_RENESAS_RZV2HWDT=y
 CONFIG_UNIPHIER_WATCHDOG=y
 CONFIG_PM8916_WATCHDOG=m
+CONFIG_APPLE_WATCHDOG=m
 CONFIG_BCM2835_WDT=y
 CONFIG_BCM7038_WDT=m
 CONFIG_MFD_ADP5585=m
@@ -789,6 +801,7 @@ CONFIG_MFD_ALTERA_SYSMGR=y
 CONFIG_MFD_BD9571MWV=y
 CONFIG_MFD_AXP20X_I2C=y
 CONFIG_MFD_AXP20X_RSB=y
+CONFIG_MFD_MACSMC=m
 CONFIG_MFD_DA9062=m
 CONFIG_MFD_EXYNOS_LPASS=m
 CONFIG_MFD_HI6421_PMIC=y
@@ -946,6 +959,7 @@ CONFIG_DRM_TEGRA=m
 CONFIG_DRM_PANEL_BOE_TV101WUM_NL6=m
 CONFIG_DRM_PANEL_LVDS=m
 CONFIG_DRM_PANEL_SIMPLE=m
+CONFIG_DRM_PANEL_SUMMIT=m
 CONFIG_DRM_PANEL_EDP=m
 CONFIG_DRM_PANEL_HIMAX_HX8279=m
 CONFIG_DRM_PANEL_HIMAX_HX83112A=m
@@ -1012,6 +1026,7 @@ CONFIG_FB=y
 CONFIG_FB_EFI=y
 CONFIG_FB_MODE_HELPERS=y
 CONFIG_BACKLIGHT_PWM=m
+CONFIG_BACKLIGHT_APPLE_DWI=m
 CONFIG_BACKLIGHT_QCOM_WLED=m
 CONFIG_BACKLIGHT_LP855X=m
 CONFIG_LOGO=y
@@ -1026,6 +1041,7 @@ CONFIG_SND_USB_AUDIO=m
 CONFIG_SND_USB_AUDIO_QMI=m
 CONFIG_SND_SOC=m
 CONFIG_SND_SOC_USB=m
+CONFIG_SND_SOC_APPLE_MCA=m
 CONFIG_SND_BCM2835_SOC_I2S=m
 CONFIG_SND_SOC_FSL_ASRC=m
 CONFIG_SND_SOC_FSL_MICFIL=m
@@ -1316,7 +1332,9 @@ CONFIG_RTC_DRV_XGENE=y
 CONFIG_RTC_DRV_TI_K3=m
 CONFIG_RTC_DRV_RENESAS_RTCA3=m
 CONFIG_RTC_DRV_NVIDIA_VRS10=m
+CONFIG_RTC_DRV_MACSMC=m
 CONFIG_DMADEVICES=y
+CONFIG_APPLE_ADMAC=m
 CONFIG_DMA_BCM2835=y
 CONFIG_DMA_SUN6I=m
 CONFIG_FSL_EDMA=y
@@ -1362,6 +1380,7 @@ CONFIG_CROS_EC_RPMSG=m
 CONFIG_CROS_EC_SPI=y
 CONFIG_CROS_KBD_LED_BACKLIGHT=m
 CONFIG_CROS_EC_CHARDEV=m
+CONFIG_COMMON_CLK_APPLE_NCO=m
 CONFIG_COMMON_CLK_RK808=y
 CONFIG_COMMON_CLK_SCMI=y
 CONFIG_COMMON_CLK_SCPI=y
@@ -1525,6 +1544,7 @@ CONFIG_ARM_SMMU=y
 CONFIG_ARM_SMMU_V3=y
 CONFIG_MTK_IOMMU=y
 CONFIG_QCOM_IOMMU=y
+CONFIG_APPLE_DART=m
 CONFIG_REMOTEPROC=y
 CONFIG_IMX_REMOTEPROC=y
 CONFIG_MTK_SCP=m
@@ -1544,6 +1564,9 @@ CONFIG_RPMSG_QCOM_SMD=y
 CONFIG_RPMSG_VIRTIO=y
 CONFIG_SOUNDWIRE=m
 CONFIG_SOUNDWIRE_QCOM=m
+CONFIG_APPLE_MAILBOX=m
+CONFIG_APPLE_RTKIT=m
+CONFIG_APPLE_SART=m
 CONFIG_FSL_DPAA=y
 CONFIG_FSL_MC_DPIO=y
 CONFIG_FSL_RCPM=y
@@ -1625,6 +1648,7 @@ CONFIG_IIO_CROS_EC_BARO=m
 CONFIG_MPL3115=m
 CONFIG_PWM=y
 CONFIG_PWM_ADP5585=m
+CONFIG_PWM_APPLE=m
 CONFIG_PWM_BCM2835=m
 CONFIG_PWM_BRCMSTB=m
 CONFIG_PWM_CROS_EC=m
@@ -1720,11 +1744,14 @@ CONFIG_QCOM_L2_PMU=y
 CONFIG_QCOM_L3_PMU=y
 CONFIG_ARM_SPE_PMU=m
 CONFIG_ARM_DMC620_PMU=m
+CONFIG_APPLE_M1_CPU_PMU=y
 CONFIG_HISI_PMU=y
 CONFIG_ARM_CORESIGHT_PMU_ARCH_SYSTEM_PMU=m
 CONFIG_NVIDIA_CORESIGHT_PMU_ARCH_SYSTEM_PMU=m
 CONFIG_MESON_DDR_PMU=m
 CONFIG_NVMEM_LAYOUT_SL28_VPD=m
+CONFIG_NVMEM_APPLE_EFUSES=m
+CONFIG_NVMEM_APPLE_SPMI=m
 CONFIG_NVMEM_IMX_OCOTP=y
 CONFIG_NVMEM_IMX_OCOTP_ELE=m
 CONFIG_NVMEM_IMX_OCOTP_SCU=y

-- 
2.52.0



From frederic at kernel.org  Wed Dec 31 07:53:03 2025
From: frederic at kernel.org (Frederic Weisbecker)
Date: Wed, 31 Dec 2025 16:53:03 +0100
Subject: [PATCH 19/33] cpuset: Propagate cpuset isolation update to
 timers through housekeeping
In-Reply-To: <a8262eaf-169d-415d-949e-70f1a17b1e38@redhat.com>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-20-frederic@kernel.org>
 <a8262eaf-169d-415d-949e-70f1a17b1e38@redhat.com>
Message-ID: <aVVG3-NBYIhJmVsk@localhost.localdomain>

Le Fri, Dec 26, 2025 at 03:40:25PM -0500, Waiman Long a ?crit :
> On 12/24/25 8:45 AM, Frederic Weisbecker wrote:
> > Until now, cpuset would propagate isolated partition changes to
> > timer migration so that unbound timers don't get migrated to isolated
> > CPUs.
> > 
> > Since housekeeping now centralizes, synchronize and propagates isolation
> > cpumask changes, perform the work from that subsystem for consolidation
> > and consistency purposes.
> > 
> > Signed-off-by: Frederic Weisbecker<frederic at kernel.org>
> > ---
> >   kernel/cgroup/cpuset.c   | 3 ---
> >   kernel/sched/isolation.c | 5 +++++
> >   2 files changed, 5 insertions(+), 3 deletions(-)
> > 
> > diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> > index a492d23dd622..25ac6c98113c 100644
> > --- a/kernel/cgroup/cpuset.c
> > +++ b/kernel/cgroup/cpuset.c
> > @@ -1487,9 +1487,6 @@ static void update_isolation_cpumasks(void)
> >   	ret = housekeeping_update(isolated_cpus, HK_TYPE_DOMAIN);
> >   	WARN_ON_ONCE(ret < 0);
> > -	ret = tmigr_isolated_exclude_cpumask(isolated_cpus);
> > -	WARN_ON_ONCE(ret < 0);
> > -
> >   	isolated_cpus_updating = false;
> >   }
> > diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c
> > index d224bca299ed..84a257d05918 100644
> > --- a/kernel/sched/isolation.c
> > +++ b/kernel/sched/isolation.c
> > @@ -150,7 +150,12 @@ int housekeeping_update(struct cpumask *isol_mask, enum hk_type type)
> >   	pci_probe_flush_workqueue();
> >   	mem_cgroup_flush_workqueue();
> >   	vmstat_flush_workqueue();
> > +
> >   	err = workqueue_unbound_housekeeping_update(housekeeping_cpumask(type));
> > +	WARN_ON_ONCE(err < 0);
> > +
> > +	err = tmigr_isolated_exclude_cpumask(isol_mask);
> > +	WARN_ON_ONCE(err < 0);
> >   	kfree(old);
> 
> If you are doing "WARN_ON_ONCE() in housekeeping_update(), you don't need to
> do it in update_isolation_cpumask() to avoid double warnings. Actually, you
> don't need to return an error code from housekeeping_update() at all.
> 
> Cheers, Longman

Ok, I'm keeping the error return for allocation failures at the beginning of
housekeeping_update() but the rest will only warn in place.

Thanks.

-- 
Frederic Weisbecker
SUSE Labs


From skhan at linuxfoundation.org  Wed Dec 31 08:21:26 2025
From: skhan at linuxfoundation.org (Shuah Khan)
Date: Wed, 31 Dec 2025 09:21:26 -0700
Subject: Linux 6.19-rc1 mediatek mt7921e broke badly
In-Reply-To: <8c8c8f27-ba44-48eb-96f6-dae6d2d0cbf8@t-8ch.de>
References: <d7f3b00d-beec-41f0-b157-7cfb871f9a46@linuxfoundation.org>
 <756e3f65-b2f2-4da3-985a-17754a7a872d@t-8ch.de>
 <CAHk-=wjO-7uR5HBi-MFnkxAxjhpgfbAQ+HCMKPiXFVwM+AJ7tA@mail.gmail.com>
 <6fc04df5-b753-4b2d-b978-0e59a7f48ff7@linux.dev>
 <c1304430-dd7d-437b-8744-70af9ca85c0d@linuxfoundation.org>
 <8c8c8f27-ba44-48eb-96f6-dae6d2d0cbf8@t-8ch.de>
Message-ID: <f9a32a91-e25a-4f25-8c1a-1e4c0e3b07e4@linuxfoundation.org>

On 12/31/25 03:36, Thomas Wei?schuh wrote:
> On 2025-12-30 16:57:20-0700, Shuah Khan wrote:
>> On 12/29/25 21:21, Matthew Schwartz wrote:
>>> On 12/29/25 4:41 PM, Linus Torvalds wrote:
>>>> On Sat, 27 Dec 2025 at 04:25, Thomas Wei?schuh <linux at weissschuh.net> wrote:
>>>>>
>>>>> Hi Shuah,
>>>>>
>>>>> On 2025-12-27 02:07:24-0700, Shuah Khan wrote:
>>>>>> mt7921e doesn't load on my primary laptopn on Linux 6.19-rc1 and problem
>>>>>> still there on 6.19-rc2.
>>>>>
>>>>> This should be a duplicate of
>>>>> https://lore.kernel.org/all/CABXGCsMeAZyNJ-Axt_CUCXgyieWPV3rrcLpWsveMPT8R0YPGnQ at mail.gmail.com/
> 
> (...)
>   
>> Reverting the following fixed my problem.
>> f804a5895eba ("wifi: mt76: Strip whitespace from build ddate")
>>
>> The above fixes an extra newline in the dmesg by making the
>> code more complex it needs to introducing local buffers and
>> strscpy() - the proposed fix replaces this with memcpy().
>>
>> Is there a simple way to do this than introducing memcpy()
>> or strscpy() to remove an extra newline that might or might
>> not exist? Why not check if newline exists or not using
>> strstr()?
> 
> We do have memtostr() which would be a perfect fit to use here.
> That is still a memcpy() under the hood, but the code is clear and safe.
> It does however require the source to be annotated as __nonstring.
> Which also seems to be the right choice here anyways. However for
> consistency, all other similar fields should also be annotated in the
> same way. So it is a bit of a larger change than a pure bugfix.
> 

I am playing with just removing \n from dev_info() - there are
three dev_info()s in the same routine that print the same
information. I will also take a look to see if they are indeed
needed.

thanks,
-- Shuah


From manivannan.sadhasivam at oss.qualcomm.com  Wed Dec 31 08:21:26 2025
From: manivannan.sadhasivam at oss.qualcomm.com (Manivannan Sadhasivam)
Date: Wed, 31 Dec 2025 21:51:26 +0530
Subject: [PATCH] firmware: psci: Set pm_set_resume/suspend_via_firmware() for SYSTEM_SUSPEND
Message-ID: <20251231162126.7728-1-manivannan.sadhasivam@oss.qualcomm.com>

From: Konrad Dybcio <konradybcio at kernel.org>

PSCI specification defines the SYSTEM_SUSPEND feature which enables the
firmware to implement the suspend to RAM (S2RAM) functionality by
transitioning the system to a deeper low power state. When the system
enters such state, the power to the peripheral devices might be removed. So
the respective device drivers must prepare for the possible removal of the
power by performing actions such as shutting down or resetting the device
in their system suspend callbacks.

The Linux PM framework allows the platform drivers to convey this info to
device drivers by calling the pm_set_suspend_via_firmware() and
pm_set_resume_via_firmware() APIs.

Hence, if the PSCI firmware supports SYSTEM_SUSPEND feature, call the above
mentioned APIs in the psci_system_suspend_begin() and
psci_system_suspend_enter() callbacks.

Signed-off-by: Konrad Dybcio <konrad.dybcio at linaro.org>
Reviewed-by: Sudeep Holla <sudeep.holla at arm.com>
[mani: reworded the description to be more elaborative]
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam at oss.qualcomm.com>
---

This patch was part of an old series that didn't make it to mainline due to
objections in the binding and exposing CPU_SUSPEND as S2RAM patches:
https://lore.kernel.org/all/20241028-topic-cpu_suspend_s2ram-v1-0-9fdd9a04b75c at oss.qualcomm.com/

But this patch on its own is useful for platforms implementing the S2RAM
feature in PSCI firmware. So I picked it up, tested on Qcom X1E T14s and
resending it.

 drivers/firmware/psci/psci.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c
index 38ca190d4a22..e73bae6cb23a 100644
--- a/drivers/firmware/psci/psci.c
+++ b/drivers/firmware/psci/psci.c
@@ -539,12 +539,22 @@ static int psci_system_suspend(unsigned long unused)
 
 static int psci_system_suspend_enter(suspend_state_t state)
 {
+	pm_set_resume_via_firmware();
+
 	return cpu_suspend(0, psci_system_suspend);
 }
 
+static int psci_system_suspend_begin(suspend_state_t state)
+{
+	pm_set_suspend_via_firmware();
+
+	return 0;
+}
+
 static const struct platform_suspend_ops psci_suspend_ops = {
 	.valid          = suspend_valid_only_mem,
 	.enter          = psci_system_suspend_enter,
+	.begin          = psci_system_suspend_begin,
 };
 
 static void __init psci_init_system_reset2(void)
-- 
2.48.1



From b-padhi at ti.com  Wed Dec 31 08:50:59 2025
From: b-padhi at ti.com (Beleswar Padhi)
Date: Wed, 31 Dec 2025 22:20:59 +0530
Subject: [PATCH 0/3] Add TI K3 HSM M4F nodes in device-tree
Message-ID: <20251231165102.950644-1-b-padhi@ti.com>

Some of the TI K3 family of SoCs (like J721S2, J784S4, J722S) have a
HSM (High Security Module) M4F core in the Wakeup Voltage Domain which
could be used to run secure services like Authentication. Add the device
tree bindings and device-tree node definitions for this HSM M4F core.

The HSM M4 core is typically booted early from the bootloader and the
driver for the same will be posted shortly.

Beleswar Padhi (3):
  dt-bindings: remoteproc: Add bindings for HSM core on TI K3 SoCs
  arm64: dts: ti: k3-{j784s4-j742s2/j721s2}-mcu-wakeup: Add HSM M4F node
  arm64: dts: ti: k3-am62p-j722s-common-main: Add HSM M4F node

 .../bindings/remoteproc/ti,k3-hsm-rproc.yaml  | 79 +++++++++++++++++++
 .../dts/ti/k3-am62p-j722s-common-main.dtsi    | 15 ++++
 arch/arm64/boot/dts/ti/k3-am62p.dtsi          |  1 +
 .../boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi     | 15 ++++
 arch/arm64/boot/dts/ti/k3-j722s.dtsi          |  1 +
 .../k3-j784s4-j742s2-mcu-wakeup-common.dtsi   | 15 ++++
 6 files changed, 126 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/remoteproc/ti,k3-hsm-rproc.yaml

-- 
2.34.1



From b-padhi at ti.com  Wed Dec 31 08:51:00 2025
From: b-padhi at ti.com (Beleswar Padhi)
Date: Wed, 31 Dec 2025 22:21:00 +0530
Subject: [PATCH 1/3] dt-bindings: remoteproc: Add bindings for HSM core on TI K3 SoCs
In-Reply-To: <20251231165102.950644-1-b-padhi@ti.com>
References: <20251231165102.950644-1-b-padhi@ti.com>
Message-ID: <20251231165102.950644-2-b-padhi@ti.com>

Some of the TI K3 family of SoCs have a HSM (High Security Module) M4F
core in the Wakeup Voltage Domain which could be used to run secure
services like Authentication. Add the device tree bindings document for
this HSM M4F core.

The added example illustrates the DT node for the HSM core present on K3
J722S SoC.

Signed-off-by: Beleswar Padhi <b-padhi at ti.com>
---
 .../bindings/remoteproc/ti,k3-hsm-rproc.yaml  | 79 +++++++++++++++++++
 1 file changed, 79 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/remoteproc/ti,k3-hsm-rproc.yaml

diff --git a/Documentation/devicetree/bindings/remoteproc/ti,k3-hsm-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/ti,k3-hsm-rproc.yaml
new file mode 100644
index 0000000000000..f61e4046843af
--- /dev/null
+++ b/Documentation/devicetree/bindings/remoteproc/ti,k3-hsm-rproc.yaml
@@ -0,0 +1,79 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/remoteproc/ti,k3-hsm-rproc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: TI K3 HSM M4F processor subsystems
+
+maintainers:
+  - Beleswar Padhi <b-padhi at ti.com>
+
+description: |
+  Some K3 family SoCs have a HSM (High Security Module) M4F core in the
+  Wakeup Voltage Domain which could be used to run secure services like
+  Authentication. Some of those are J721S2, J784S4, J722S, AM62X.
+
+$ref: /schemas/arm/keystone/ti,k3-sci-common.yaml#
+
+properties:
+  compatible:
+    enum:
+      - ti,hsm-m4fss
+
+  "#address-cells":
+    const: 2
+
+  "#size-cells":
+    const: 2
+
+  reg:
+    items:
+      - description: SRAM0_0 internal memory region
+      - description: SRAM0_1 internal memory region
+      - description: SRAM1 internal memory region
+
+  reg-names:
+    items:
+      - const: sram0_0
+      - const: sram0_1
+      - const: sram1
+
+  resets:
+    maxItems: 1
+
+  firmware-name:
+    maxItems: 1
+    description: Name of firmware to load for the HSM core
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - resets
+  - firmware-name
+  - ti,sci
+  - ti,sci-dev-id
+  - ti,sci-proc-ids
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        remoteproc at 43c00000 {
+            compatible = "ti,hsm-m4fss";
+            reg = <0x00 0x43c00000 0x00 0x20000>,
+                  <0x00 0x43c20000 0x00 0x10000>,
+                  <0x00 0x43c30000 0x00 0x10000>;
+            reg-names = "sram0_0", "sram0_1", "sram1";
+            resets = <&k3_reset 225 1>;
+            firmware-name = "hsm.bin";
+            ti,sci = <&sms>;
+            ti,sci-dev-id = <225>;
+            ti,sci-proc-ids = <0x80 0xff>;
+         };
+    };
-- 
2.34.1



From b-padhi at ti.com  Wed Dec 31 08:51:01 2025
From: b-padhi at ti.com (Beleswar Padhi)
Date: Wed, 31 Dec 2025 22:21:01 +0530
Subject: [PATCH 2/3] arm64: dts: ti: k3-{j784s4-j742s2/j721s2}-mcu-wakeup: Add HSM M4F node
In-Reply-To: <20251231165102.950644-1-b-padhi@ti.com>
References: <20251231165102.950644-1-b-padhi@ti.com>
Message-ID: <20251231165102.950644-3-b-padhi@ti.com>

The TI K3 J721S2, J784S4 and J742S2 SoCs have a HSM (High Security
Module) M4F core in the Wakeup Voltage Domain which could be used to run
secure services like Authentication. Add Device Tree Node definitions
for the HSM core in the respective SoC wakeup dtsi files.

Signed-off-by: Beleswar Padhi <b-padhi at ti.com>
---
 arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi  | 15 +++++++++++++++
 .../ti/k3-j784s4-j742s2-mcu-wakeup-common.dtsi    | 15 +++++++++++++++
 2 files changed, 30 insertions(+)

diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi
index 2a7f9c519735a..712c3bcbb6f84 100644
--- a/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi
@@ -766,4 +766,19 @@ mcu_watchdog1: watchdog at 40610000 {
 		/* reserved for MCU_R5F0_1 */
 		status = "reserved";
 	};
+
+	hsm_m4fss: m4fss at 43c00000 {
+		compatible = "ti,hsm-m4fss";
+		reg = <0x00 0x43c00000 0x00 0x20000>,
+		      <0x00 0x43c20000 0x00 0x10000>,
+		      <0x00 0x43c30000 0x00 0x10000>;
+		reg-names = "sram0_0", "sram0_1", "sram1";
+		resets = <&k3_reset 304 1>;
+		firmware-name = "hsm.bin";
+		ti,sci = <&sms>;
+		ti,sci-dev-id = <304>;
+		ti,sci-proc-ids = <0x80 0xff>;
+		status = "disabled";
+		bootph-pre-ram;
+	};
 };
diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-mcu-wakeup-common.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-mcu-wakeup-common.dtsi
index cc22bfb5f5996..42565f41b7bac 100644
--- a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-mcu-wakeup-common.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-mcu-wakeup-common.dtsi
@@ -762,4 +762,19 @@ mcu_watchdog1: watchdog at 40610000 {
 		/* reserved for MCU_R5F0_1 */
 		status = "reserved";
 	};
+
+	hsm_m4fss: m4fss at 43c00000 {
+		compatible = "ti,hsm-m4fss";
+		reg = <0x00 0x43c00000 0x00 0x20000>,
+		      <0x00 0x43c20000 0x00 0x10000>,
+		      <0x00 0x43c30000 0x00 0x10000>;
+		reg-names = "sram0_0", "sram0_1", "sram1";
+		resets = <&k3_reset 371 1>;
+		firmware-name = "hsm.bin";
+		ti,sci = <&sms>;
+		ti,sci-dev-id = <371>;
+		ti,sci-proc-ids = <0x80 0xff>;
+		status = "disabled";
+		bootph-pre-ram;
+	};
 };
-- 
2.34.1



From b-padhi at ti.com  Wed Dec 31 08:51:02 2025
From: b-padhi at ti.com (Beleswar Padhi)
Date: Wed, 31 Dec 2025 22:21:02 +0530
Subject: [PATCH 3/3] arm64: dts: ti: k3-am62p-j722s-common-main: Add HSM M4F node
In-Reply-To: <20251231165102.950644-1-b-padhi@ti.com>
References: <20251231165102.950644-1-b-padhi@ti.com>
Message-ID: <20251231165102.950644-4-b-padhi@ti.com>

The TI K3 AM62P and J722S SoCs have a HSM (High Security Module) M4F
core in the MAIN Voltage Domain which could be used to run secure
services like Authentication. Add Device Tree Node definitions for the
HSM core in the respective SoC common main dtsi file.

The corresponding reg ranges of HSM node has also been added to its
parent node's (cbass_main bus) ranges property.

Signed-off-by: Beleswar Padhi <b-padhi at ti.com>
---
 .../boot/dts/ti/k3-am62p-j722s-common-main.dtsi   | 15 +++++++++++++++
 arch/arm64/boot/dts/ti/k3-am62p.dtsi              |  1 +
 arch/arm64/boot/dts/ti/k3-j722s.dtsi              |  1 +
 3 files changed, 17 insertions(+)

diff --git a/arch/arm64/boot/dts/ti/k3-am62p-j722s-common-main.dtsi b/arch/arm64/boot/dts/ti/k3-am62p-j722s-common-main.dtsi
index 3cf7c2b3ce2dd..28586cbc57613 100644
--- a/arch/arm64/boot/dts/ti/k3-am62p-j722s-common-main.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am62p-j722s-common-main.dtsi
@@ -1117,4 +1117,19 @@ vpu: video-codec at 30210000 {
 		clocks = <&k3_clks 204 2>;
 		power-domains = <&k3_pds 204 TI_SCI_PD_EXCLUSIVE>;
 	};
+
+	hsm_m4fss: m4fss at 43c00000 {
+		compatible = "ti,hsm-m4fss";
+		reg = <0x00 0x43c00000 0x00 0x20000>,
+		      <0x00 0x43c20000 0x00 0x10000>,
+		      <0x00 0x43c30000 0x00 0x10000>;
+		reg-names = "sram0_0", "sram0_1", "sram1";
+		resets = <&k3_reset 225 1>;
+		firmware-name = "hsm.bin";
+		ti,sci = <&dmsc>;
+		ti,sci-dev-id = <225>;
+		ti,sci-proc-ids = <0x80 0xff>;
+		status = "disabled";
+		bootph-pre-ram;
+	};
 };
diff --git a/arch/arm64/boot/dts/ti/k3-am62p.dtsi b/arch/arm64/boot/dts/ti/k3-am62p.dtsi
index e2c01328eb298..9d6266d6ddb82 100644
--- a/arch/arm64/boot/dts/ti/k3-am62p.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am62p.dtsi
@@ -96,6 +96,7 @@ cbass_main: bus at f0000 {
 			 <0x00 0x31100000 0x00 0x31100000 0x00 0x00050000>, /* USB1 DWC3 Core window */
 			 <0x00 0x40900000 0x00 0x40900000 0x00 0x00030000>, /* SA3UL */
 			 <0x00 0x43600000 0x00 0x43600000 0x00 0x00010000>, /* SA3 sproxy data */
+			 <0x00 0x43c00000 0x00 0x43c00000 0x00 0x00040000>, /* HSM SRAM ranges */
 			 <0x00 0x44043000 0x00 0x44043000 0x00 0x00000fe0>, /* TI SCI DEBUG */
 			 <0x00 0x44860000 0x00 0x44860000 0x00 0x00040000>, /* SA3 sproxy config */
 			 <0x00 0x48000000 0x00 0x48000000 0x00 0x06408000>, /* DMSS */
diff --git a/arch/arm64/boot/dts/ti/k3-j722s.dtsi b/arch/arm64/boot/dts/ti/k3-j722s.dtsi
index cdc8570e54b29..8b0523669c325 100644
--- a/arch/arm64/boot/dts/ti/k3-j722s.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-j722s.dtsi
@@ -173,6 +173,7 @@ cbass_main: bus at f0000 {
 			 <0x00 0x31200000 0x00 0x31200000 0x00 0x00040000>, /* USB1 DWC3 Core window */
 			 <0x00 0x40900000 0x00 0x40900000 0x00 0x00030000>, /* SA3UL */
 			 <0x00 0x43600000 0x00 0x43600000 0x00 0x00010000>, /* SA3 sproxy data */
+			 <0x00 0x43c00000 0x00 0x43c00000 0x00 0x00040000>, /* HSM SRAM ranges */
 			 <0x00 0x44043000 0x00 0x44043000 0x00 0x00000fe0>, /* TI SCI DEBUG */
 			 <0x00 0x44860000 0x00 0x44860000 0x00 0x00040000>, /* SA3 sproxy config */
 			 <0x00 0x48000000 0x00 0x48000000 0x00 0x06408000>, /* DMSS */
-- 
2.34.1



From llong at redhat.com  Wed Dec 31 09:35:49 2025
From: llong at redhat.com (Waiman Long)
Date: Wed, 31 Dec 2025 12:35:49 -0500
Subject: [PATCH 33/33] doc: Add housekeeping documentation
In-Reply-To: <aVVAfb2eaeyd7l-h@localhost.localdomain>
References: <20251224134520.33231-1-frederic@kernel.org>
 <20251224134520.33231-34-frederic@kernel.org>
 <370149fc-1624-4a16-ac47-dd9b2dd0ed29@redhat.com>
 <aVVAfb2eaeyd7l-h@localhost.localdomain>
Message-ID: <f4228e20-62ff-4701-b6ce-59c99188d7b5@redhat.com>

On 12/31/25 10:25 AM, Frederic Weisbecker wrote:
> Le Fri, Dec 26, 2025 at 07:39:28PM -0500, Waiman Long a ?crit :
>> On 12/24/25 8:45 AM, Frederic Weisbecker wrote:
>>> Signed-off-by: Frederic Weisbecker <frederic at kernel.org>
>>> ---
>>>    Documentation/core-api/housekeeping.rst | 111 ++++++++++++++++++++++++
>>>    Documentation/core-api/index.rst        |   1 +
>>>    2 files changed, 112 insertions(+)
>>>    create mode 100644 Documentation/core-api/housekeeping.rst
>>>
>>> diff --git a/Documentation/core-api/housekeeping.rst b/Documentation/core-api/housekeeping.rst
>>> new file mode 100644
>>> index 000000000000..e5417302774c
>>> --- /dev/null
>>> +++ b/Documentation/core-api/housekeeping.rst
>>> @@ -0,0 +1,111 @@
>>> +======================================
>>> +Housekeeping
>>> +======================================
>>> +
>>> +
>>> +CPU Isolation moves away kernel work that may otherwise run on any CPU.
>>> +The purpose of its related features is to reduce the OS jitter that some
>>> +extreme workloads can't stand, such as in some DPDK usecases.
>> Nit: "usecases" => "use cases"
> Are you sure? I'm not a native speaker but at least the kernel
> has established its use:
>
> $ git grep usecase | wc -l
> 517
"usecase" is not a proper word by itself, but people do use it some times.
$ git grep "use case" | wc -l
694

Anyway, you can keep it if you want. It is not something that is worth 
arguing for. :-)

Cheers,
Longman



From nicolinc at nvidia.com  Wed Dec 31 11:48:57 2025
From: nicolinc at nvidia.com (Nicolin Chen)
Date: Wed, 31 Dec 2025 11:48:57 -0800
Subject: [PATCH v1 2/9] iommu/arm-smmu-v3: Add alloc_id/free_id functions
 to arm_smmu_invs
In-Reply-To: <aVQfhaqfvfLFNZqe@Asurada-Nvidia>
References: <cover.1766088962.git.nicolinc@nvidia.com>
 <1541ea4a9e9c935c2f907c0c5f13a4af2bdc2114.1766088962.git.nicolinc@nvidia.com>
 <20251219170551.GF254720@nvidia.com>
 <aVQfhaqfvfLFNZqe@Asurada-Nvidia>
Message-ID: <aVV+KWzpxPPfaNw4@Asurada-Nvidia>

On Tue, Dec 30, 2025 at 10:52:55AM -0800, Nicolin Chen wrote:
> Hi Jason,
> 
> On Fri, Dec 19, 2025 at 01:05:51PM -0400, Jason Gunthorpe wrote:
> > +static int arm_smmu_get_tag(struct arm_smmu_domain *smmu_domain,
> > +			    struct arm_smmu_master *master,
> > +			    struct arm_vsmmu *vsmmu,
> > +			    struct arm_smmu_iotlb_tag *tag, bool no_alloc)
> [...]
> > +	case ARM_SMMU_DOMAIN_S2:
> > +		if (smmu_domain->nest_parent) {
> > +			/* FIXME we can support attaching a nest_parent without
> > +			 * a vsmmu, but to do that we need to fix
> > +			 * arm_smmu_get_id_from_invs() to never return the vmid
> > +			 * of a vsmmu. Probably by making a
> > +			 * INV_TYPE_S2_VMID_VSMMU */
> > +			id = vsmmu->vmid;
> > +			return 0;
> > +		}
> 
> Would you mind elaborating why arm_smmu_get_id_from_invs() can't
> return vsmmu->vmid to share with a naked S2 STE?
> 
> I'm having a bit trouble justifying this INV_TYPE_S2_VMID_VSMMU.
> 
> Since it's the same S2 domain/iopt, if anything that is attached
> (whether nested or naked) changes the S2 iopt, we should always
> flush the nested S1 domain too, right?
> 
> If so, a naked S2 STE should refer to the same VMID in order to
> allow its following INV_TYPE_S2_VMID_S1_CLEAR to work properly?

I figured that having separate VMIDs on a nest_parent S2 isn't
a problem since invalidation will go through all the VMIDs. And
having an INV_TYPE_S2_VMID_VSMMU is for its unique lifecycle.

Nicolin


From skhan at linuxfoundation.org  Wed Dec 31 11:54:24 2025
From: skhan at linuxfoundation.org (Shuah Khan)
Date: Wed, 31 Dec 2025 12:54:24 -0700
Subject: [PATCH] kselftest/arm64: Support FORCE_TARGETS
In-Reply-To: <20251219-kselftest-arm64-force-targets-v1-1-cf72d6d27e99@kernel.org>
References: <20251219-kselftest-arm64-force-targets-v1-1-cf72d6d27e99@kernel.org>
Message-ID: <025a3cd1-ac6f-459c-8bc7-79b336f10dee@linuxfoundation.org>

On 12/19/25 08:29, Mark Brown wrote:
> The top level kselftest Makefile supports an option FORCE_TARGETS which
> causes any failures during the build to be propagated to the exit status
> of the top level make, useful during build testing. Currently the recursion
> done by the arm64 selftests ignores this option, meaning arm64 failures are
> not reported via this mechanism. Add the logic to implement FORCE_TARGETS
> so that it works for arm64.
> 
> Signed-off-by: Mark Brown <broonie at kernel.org>
> ---

Looks good to me.

Acked-by: Shuah Khan <skhan at linuxfoundation.org>

thanks,
-- Shuah


From piotr at maslowski.xyz  Wed Dec 31 10:14:13 2025
From: piotr at maslowski.xyz (=?utf-8?q?Piotr_Mas=C5=82owski?=)
Date: Wed, 31 Dec 2025 19:14:13 +0100
Subject: [PATCH 2/2] arm64: defconfig: Enable Apple Silicon drivers
In-Reply-To: <20251231-arch-arm64-apple-defconfig-v1-2-4ff19805ba39@jannau.net>
References: <20251231-arch-arm64-apple-defconfig-v1-0-4ff19805ba39@jannau.net> <20251231-arch-arm64-apple-defconfig-v1-2-4ff19805ba39@jannau.net>
Message-ID: <DFCLU67GQO86.1NY037FRPJ4E2@maslowski.xyz>

Hello, I'm not a kernel developer so this might be entirely irrelevant,
but while browsing the list I noticed something you might've missed:

On Wed Dec 31, 2025 at 16:42 CET, Janne Grunau wrote:
> From: Sven Peter <sven at kernel.org>
>
> Enable drivers for hardware present on Apple Silicon machines. None of
> these drivers are critical so build them as modules.
[...]
> Link: https://lore.kernel.org/asahi/20250612-apple-kconfig-defconfig-v1-0-0e6f9cb512c1 at kernel.org/
> Signed-off-by: Sven Peter <sven at kernel.org>
> Signed-off-by: Janne Grunau <j at jannau.net>
>
> ---
> Changes compared to the original submission:
> - Remove AIC and APPLE_PMGR_PWRSTATE as those are selected by ARCH_APPLE
> - Add new macsmc drivers (mfd, reset, hwmon, rtc and gpio)
> - Add BACKLIGHT_APPLE_DWI, DRM_PANEL_SUMMIT and NVMEM_APPLE_SPMI
>   (suggested by Nick Chan)

What about DRM_ADP which Nick also mentioned?

> - Add PWM_APPLE and APPLE_M1_CPU_PMU
[...]

I tried to check whether it had possibly been taken care of elsewhere,
but I didn't find anything related on the mailing list(s) nor in the repo.

Cheers,
Piotr Mas?owski


From skhan at linuxfoundation.org  Wed Dec 31 13:08:29 2025
From: skhan at linuxfoundation.org (Shuah Khan)
Date: Wed, 31 Dec 2025 14:08:29 -0700
Subject: Linux 6.19-rc1 mediatek mt7921e broke badly
In-Reply-To: <30d14c51-3325-49be-9510-43f4661ff6c4@linuxfoundation.org>
References: <d7f3b00d-beec-41f0-b157-7cfb871f9a46@linuxfoundation.org>
 <756e3f65-b2f2-4da3-985a-17754a7a872d@t-8ch.de>
 <CAHk-=wjO-7uR5HBi-MFnkxAxjhpgfbAQ+HCMKPiXFVwM+AJ7tA@mail.gmail.com>
 <6fc04df5-b753-4b2d-b978-0e59a7f48ff7@linux.dev>
 <c1304430-dd7d-437b-8744-70af9ca85c0d@linuxfoundation.org>
 <CAHk-=wh6WP0Wq=rbC2Md6vsFrV-+nvDjxgfx9NpMzUmVFNkJ9A@mail.gmail.com>
 <20251231015712.GA2299@sol>
 <fdebed60-264d-4f05-9423-618bc3ec6d6d@linuxfoundation.org>
 <30d14c51-3325-49be-9510-43f4661ff6c4@linuxfoundation.org>
Message-ID: <8b3d207c-76a2-4312-a149-724e55fbd0cb@linuxfoundation.org>

On 12/30/25 21:07, Shuah Khan wrote:
> On 12/30/25 21:00, Shuah Khan wrote:
>> On 12/30/25 18:57, Eric Biggers wrote:
>>> On Tue, Dec 30, 2025 at 05:27:13PM -0800, Linus Torvalds wrote:
>>>> On Tue, 30 Dec 2025 at 15:57, Shuah Khan <skhan at linuxfoundation.org> wrote:
>>>>>
>>>>> I would recommend reverting f804a5895eba instead of trying
>>>>> fix it. Then find a better way to eliminate extra newline that
>>>>> shows up in dmesg when firmware build date happens to have
>>>>> a newline.
>>>>
>>>> Yeah. Let's revert it.
>>>>
>>>> And the way to fix the extra newline is trivial: just remove it from
>>>> the "dev_info()" format string.
>>>>
>>>> Our kernel printing logic will add a newline for the next line anyway
>>>> if it is missing (unless somebody explicitly uses PR_CONT).
>>>>
>>>> Can whoever saw the problem confirm that just a revert and a "remove
>>>> \n from that dev_info()" fixes the output for them?
>>>
>>> That works for me.? The revert by itself makes the FORTIFY_SOURCE crash
>>> go away and reintroduces a blank line in the log.? Removing the \n from
>>> the string passed to dev_info as well makes the blank line go away.
>>>
>>
>> I just sent the revert. I will try removing \n from dev_info()
>> later on tomorrow.
>>
>> My quick trial still showed extra line which didn't make sense
>> to me. More trials have to wait for tomorrow.
>>
> 
> Hmm - there are 3 places that print build_date in? mt76_connac2_load_ram()
> 
> 3022???????? dev_info(dev->dev, "WM Firmware Version: %.10s, Build Time: %.15s\n???? ",
> 3023????????????????? hdr->fw_ver, hdr->build_date);
> 
> 
> 3051???????? dev_info(dev->dev, "WA Firmware Version: %.10s, Build Time: %.15s\n???? ",
> 3052????????????????? hdr->fw_ver, hdr->build_date);
> 
> 3127???????? dev_info(dev->dev, "HW/SW Version: 0x%x, Build Time: %.16s\n",
> 3128????????????????? be32_to_cpu(hdr->hw_sw_ver), hdr->build_date);
> 
> The last one prints %.16s and other two do %.15s - is the fix simply
> changing last one on line 3127 to print %.15s - this avoids printing
> the extra \n?
> 

The following change fixed the blank line problem on my system.

Mario, if you want to send this patch after testing on your system,
let me know. Otherwise I will send it.

==============================================

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
index fba7025ffd3f..0457712286d5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
@@ -3019,7 +3019,7 @@ int mt76_connac2_load_ram(struct mt76_dev *dev, const char *fw_wm,
         }
  
         hdr = (const void *)(fw->data + fw->size - sizeof(*hdr));
-       dev_info(dev->dev, "WM Firmware Version: %.10s, Build Time: %.15s\n",
+       dev_info(dev->dev, "WM Firmware Version: %.10s, Build Time: %.15s",
                  hdr->fw_ver, hdr->build_date);
  
         ret = mt76_connac_mcu_send_ram_firmware(dev, hdr, fw->data, false);
@@ -3048,7 +3048,7 @@ int mt76_connac2_load_ram(struct mt76_dev *dev, const char *fw_wm,
         }
  
         hdr = (const void *)(fw->data + fw->size - sizeof(*hdr));
-       dev_info(dev->dev, "WA Firmware Version: %.10s, Build Time: %.15s\n",
+       dev_info(dev->dev, "WA Firmware Version: %.10s, Build Time: %.15s",
                  hdr->fw_ver, hdr->build_date);
  
         ret = mt76_connac_mcu_send_ram_firmware(dev, hdr, fw->data, true);
@@ -3124,7 +3124,7 @@ int mt76_connac2_load_patch(struct mt76_dev *dev, const char *fw_name)
         }
  
         hdr = (const void *)fw->data;
-       dev_info(dev->dev, "HW/SW Version: 0x%x, Build Time: %.16s\n",
+       dev_info(dev->dev, "HW/SW Version: 0x%x, Build Time: %.16s",
                  be32_to_cpu(hdr->hw_sw_ver), hdr->build_date);
  
         for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) {

========================================

thanks,
-- Shuah



From linusw at kernel.org  Wed Dec 31 13:14:25 2025
From: linusw at kernel.org (Linus Walleij)
Date: Wed, 31 Dec 2025 22:14:25 +0100
Subject: [PATCH 3/3] clk: versatile: impd1: Simplify with scoped for each
 OF child loop
In-Reply-To: <20251224112239.83735-6-krzysztof.kozlowski@oss.qualcomm.com>
References: <20251224112239.83735-4-krzysztof.kozlowski@oss.qualcomm.com> <20251224112239.83735-6-krzysztof.kozlowski@oss.qualcomm.com>
Message-ID: <CAD++jL=cnukn6K26AcpZuH9qz0SrSEK0UFOZ4Cam9fy3sOavnQ@mail.gmail.com>

On Wed, Dec 24, 2025 at 12:22?PM Krzysztof Kozlowski
<krzysztof.kozlowski at oss.qualcomm.com> wrote:

> Use scoped for-each loop when iterating over device nodes to make code a
> bit simpler.
>
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

That's neat.
Reviewed-by: Linus Walleij <linusw at kernel.org>

Yours,
Linus Walleij


From marek.vasut at mailbox.org  Wed Dec 31 13:00:52 2025
From: marek.vasut at mailbox.org (Marek Vasut)
Date: Wed, 31 Dec 2025 22:00:52 +0100
Subject: [PATCH 1/2] dt-bindings: firmware: arm,scmi: Document
 arm,poll-transport property
In-Reply-To: <20251208-quixotic-cocky-emu-9a3916@sudeepholla>
References: <20251202-evasive-neon-rhino-d2745e@sudeepholla>
 <66257fcf-9024-454f-b776-4ba584963ebe@mailbox.org> <aS82GSN8c2SnRn4S@bogus>
 <8d773671-5e2e-4e21-ade6-2bf9a3b75066@mailbox.org>
 <20251203-thick-didactic-cockatoo-deaa1d@sudeepholla>
 <4ccbcffd-bcc7-478b-a525-a4a11e3092ee@mailbox.org>
 <20251204-calm-peacock-of-fantasy-6b8cbe@sudeepholla>
 <e25c690c-e74d-4641-a97e-8eae81a59168@mailbox.org>
 <20251205-winged-quizzical-pigeon-ed692d@sudeepholla>
 <06fc0557-6b7c-4092-aeec-e3e16bab2d72@mailbox.org>
 <20251208-quixotic-cocky-emu-9a3916@sudeepholla>
Message-ID: <758bfdb2-dd23-44cb-acfc-c562525e108f@mailbox.org>

On 12/8/25 5:30 PM, Sudeep Holla wrote:

Hello Sudeep,

it seems I missed you at LPC, we could have discussed this in there, 
pity ...

>>>>>>> Also IIUC, the irq request happens
>>>>>>> as part of channel startup and there are no explicit APIs for the mbox client
>>>>>>> driver to control that. SCMI is mbox client in this case.
>>>>>>
>>>>>> Sure, but the mailbox driver has to make sure it is correctly demuxing the
>>>>>> IRQs it handles and correctly sends received_data notifications to the right
>>>>>> channel(s) .
>>>>>>
>>>>>
>>>>> Agreed, but the concern is that if SCMI is forced to use polling when the
>>>>> channel is opened, and IRQs are enabled by default with no way for SCMI to
>>>>> disable them in polling mode, we could run into issues.
>>>>
>>>> This constellation seems odd -- if the channel can do IRQs, then this
>>>> property should not be present in DT.
>>>>
>>>
>>> Yes, but there is no way to validate or check this and that is the root
>>> cause for all my worries.
>>
>> Should a configuration like that even be considered valid and relevant ?
>>
> 
> Yes, as I have mentioned, there is no way to validate the same in the kernel.

But the DT has to be a valid hardware description. If your DT is not a 
valid hardware description, bad things can and likely will happen.

I would argue that if you add this poll property into DT, then the DT 
has to describe hardware which does not generate IRQs, otherwise the DT 
is invalid.

The poll property description in this binding document already states 
that this is for hardware which does not generate IRQs.

>>>>> I realise it?s a very
>>>>> specific corner case, but every time I?ve assumed such scenarios wouldn?t
>>>>> occur, we eventually ended up encountering them. So sorry if I am very
>>>>> pedantic, but I prefer to start smaller and restrictive and expand if and
>>>>> when necessary or required only.
>>>>
>>>> I don't think this case, where mailbox channel does IRQs and polling is
>>>> enabled, can/should even be considered valid. Either the channel does not do
>>>> IRQs and then it should do polling, or it does IRQs and then it should use
>>>> IRQs, but not both.
>>>>
>>>
>>> Yes ideally, but having loose ends like this binding which allows someone
>>> to add it to their DT complicates though it is invalid. We have no way to
>>> detect and I don't want to work around such configs in the future.
>>
>> If the DT is invalid, bad things happen, but I would argue that is then a DT
>> bug and the DT should be fixed.
>>
> 
> Well, ideally I would like that, but not always the reality.

If the DT (hardware description) is invalid, Linux can only do so much 
about it. And it is up to the implementer of such a broken DT to fix 
that DT.

If there is a broken hardware with this poll property in DT which 
suddenly does also generate IRQs and those cannot be disabled, then that 
can likely be quirked out and such IRQs can be ignored by some empty IRQ 
handler. But I would also argue that such a quirk should be added only 
once such a broken hardware gets upstreamed (if ever).

>> [...]
>>
>>>>> Yes, that?s essential, because polling in an SMC context is meaningless in my
>>>>> opinion.
>>>>
>>>> Maybe the "a2p" IRQ is also used for notifications from longer running
>>>> operations ?
>>>>
>>>
>>> Yes, it is some sort of work around some platforms implemented as by design
>>> when the SMC returns, the synchronous commands must complete and it is had
>>> to support async SCMI commands without platform specific interrupt(p2a). This
>>> a2p is sort of completion interrupt for synchronous command. I assume the
>>> platform may offload the task from secure f/w to something else otherwise
>>> secure side needs to be given CPU cycles to complete which complicates this.
>>> In short SMC is synchronous and if the execution returns from it in NS world,
>>> the command is complete.
>>
>> Wouldn't polling still be useful for the async case , even in SMC setup?
>> Note that the SMC setup does use shmem, and therefore can do polling on the
>> shmem.
>>
> 
> No, it makes no sense for SMC as I have already mentioned few times.

I can drop the SMC part from the 2/2 , but it feels like we're dropping 
a poll coverage for the async part.

>>>> [...]
>>>>
>>>>>>> Yes it can be minimalistic but not restrictive. As I already clearly mentioned
>>>>>>> I don't see it makes any sense to enable this for SMC/OPTEE. Lets start with
>>>>>>> just mailbox to start with and extend to other transports if and when needed.
>>>>>>> It would be good to impose that restriction in the binding as well but that
>>>>>>> is not a must IMO. I am fine if the bindings for whatever reasons(though I
>>>>>>> don't see the need) to apply for any transport.
>>>>>> So I should simply drop the smc.c changes , keep the rest, and send V2 ?
>>>>>
>>>>> Not just that. Unless DT maintainers oppose, I just want to keep this
>>>>> new property valid only for mailbox transport(i.e. "arm,scmi" compatible
>>>>> not otherwise) so that we can catch any other use in binding checks and
>>>>> interested parties must discuss on the list and expand that if they require.
>>>>>
>>>>> Also we can explore if we can parse and scan this in mailbox transport for
>>>>> now.
>>>> I feel that this only adds more implementation complexity and makes the
>>>> solution less generic, while it does win us very little in the end ? The
>>>> generic solution implementation is actually easier to implement.
>>>
>>> Yes I want it less generic to start with. Why you want to start making
>>> this workaround on your platform a generic implementation just because
>>> the specification has provision for it ?
>>
>> Because this is generic kernel code, it seems counterintuitive to introduce
>> less generic solution which requires more complex implementation.
>>
> 
> I would argue. Lot of code gets added as specific and gets generalised
> eventually if there are more users and in different configurations.
> 
>> Since the DEN0056 specification states this mode of operation is supported,
>> I also wouldn't call it a workaround.
> 
> Sure, I take back if I called it workaround. But why would we want to make
> it generic when we can test only mailbox based platform with it. I don't see
> how it can be useful with SMC/Optee.

For SMC, I have no use case, but it seems like the async interrupt could 
benefit from polling if ever needed.

> I am not sure if it is useful with
> virtio and if there is a way to test this. All I am saying is I don't want to
> enable something and advertise it as generic when we have no platform or way
> to test it and keep it functionally correct.
All right, let me send a slightly reduced V2 to move this along.


From marek.vasut+renesas at mailbox.org  Wed Dec 31 13:29:18 2025
From: marek.vasut+renesas at mailbox.org (Marek Vasut)
Date: Wed, 31 Dec 2025 22:29:18 +0100
Subject: [PATCH v2 1/2] dt-bindings: firmware: arm,scmi: Document arm,poll-transport property
Message-ID: <20251231213016.185575-1-marek.vasut+renesas@mailbox.org>

Document new property arm,poll-transport, which sets all SCMI operation into
poll mode. This is meant to work around uncooperative SCP implementations,
which do not generate completion interrupts. This applies primarily on mbox
shmem based implementations.

With this property set, such implementations which do not generate interrupts
can be interacted with, until they are fixed to generate interrupts properly.

Note that, because the original base protocol exchange also requires some
sort of completion mechanism, it is not possible to query SCMI itself for
this property and it must be described in DT. While this does look a bit
like policy, the SCMI provider is part of the hardware, hence DT.

Signed-off-by: Marek Vasut <marek.vasut+renesas at mailbox.org>
---
Cc: Conor Dooley <conor+dt at kernel.org>
Cc: Cristian Marussi <cristian.marussi at arm.com>
Cc: Florian Fainelli <florian.fainelli at broadcom.com>
Cc: Krzysztof Kozlowski <krzk+dt at kernel.org>
Cc: Rob Herring <robh at kernel.org>
Cc: Sudeep Holla <sudeep.holla at arm.com>
Cc: arm-scmi at vger.kernel.org
Cc: devicetree at vger.kernel.org
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-renesas-soc at vger.kernel.org
---
V2: s at mean@&t and limit poll transport to mailbox/shmem only
---
 .../devicetree/bindings/firmware/arm,scmi.yaml         | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml
index be817fd9cc34b..f4bf4173c5c7e 100644
--- a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml
+++ b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml
@@ -146,6 +146,13 @@ properties:
       this platform. If set, the value should be non-zero.
     minimum: 1
 
+  arm,poll-transport:
+    type: boolean
+    description:
+      An optional property which unconditionally forces polling in all transports.
+      This is mainly meant to work around uncooperative SCP, which does not generate
+      completion interrupts.
+
   arm,smc-id:
     $ref: /schemas/types.yaml#/definitions/uint32
     description:
@@ -379,6 +386,9 @@ then:
     - shmem
 
 else:
+  properties:
+    arm,poll-transport: false
+
   if:
     properties:
       compatible:
-- 
2.51.0



From marek.vasut+renesas at mailbox.org  Wed Dec 31 13:29:19 2025
From: marek.vasut+renesas at mailbox.org (Marek Vasut)
Date: Wed, 31 Dec 2025 22:29:19 +0100
Subject: [PATCH v2 2/2] firmware: arm_scmi: Implement arm,poll-transport property
In-Reply-To: <20251231213016.185575-1-marek.vasut+renesas@mailbox.org>
References: <20251231213016.185575-1-marek.vasut+renesas@mailbox.org>
Message-ID: <20251231213016.185575-2-marek.vasut+renesas@mailbox.org>

Implement new property arm,poll-transport, which sets all SCMI operation into
poll mode. This is meant to work around uncooperative SCP implementations,
which do not generate completion interrupts. This applies to mbox/shmem based
implementations.

With this property set, such implementations which do not generate interrupts
can be interacted with, until they are fixed to generate interrupts properly.

Signed-off-by: Marek Vasut <marek.vasut+renesas at mailbox.org>
---
Cc: Conor Dooley <conor+dt at kernel.org>
Cc: Cristian Marussi <cristian.marussi at arm.com>
Cc: Florian Fainelli <florian.fainelli at broadcom.com>
Cc: Krzysztof Kozlowski <krzk+dt at kernel.org>
Cc: Rob Herring <robh at kernel.org>
Cc: Sudeep Holla <sudeep.holla at arm.com>
Cc: arm-scmi at vger.kernel.org
Cc: devicetree at vger.kernel.org
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-renesas-soc at vger.kernel.org
---
V2: Drop no IRQ handling from SMC transport and update commit message
---
 drivers/firmware/arm_scmi/common.h | 4 ++++
 drivers/firmware/arm_scmi/driver.c | 4 ++++
 2 files changed, 8 insertions(+)

diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
index 7c35c95fddbaf..7c9617d080a02 100644
--- a/drivers/firmware/arm_scmi/common.h
+++ b/drivers/firmware/arm_scmi/common.h
@@ -235,6 +235,9 @@ struct scmi_transport_ops {
  *		      to have an execution latency lesser-equal to the threshold
  *		      should be considered for atomic mode operation: such
  *		      decision is finally left up to the SCMI drivers.
+ * @no_completion_irq: Flag to indicate that this transport has no completion
+ *		       interrupt and has to be polled. This is similar to the
+ *		       force_polling below, except this is set via DT property.
  * @force_polling: Flag to force this whole transport to use SCMI core polling
  *		   mechanism instead of completion interrupts even if available.
  * @sync_cmds_completed_on_ret: Flag to indicate that the transport assures
@@ -254,6 +257,7 @@ struct scmi_desc {
 	int max_msg;
 	int max_msg_size;
 	unsigned int atomic_threshold;
+	bool no_completion_irq;
 	const bool force_polling;
 	const bool sync_cmds_completed_on_ret;
 	const bool atomic_enabled;
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index 5caa9191a8d1a..1079c84608a2c 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -2677,6 +2677,7 @@ static int scmi_chan_setup(struct scmi_info *info, struct device_node *of_node,
 	cinfo->is_p2a = !tx;
 	cinfo->rx_timeout_ms = info->desc->max_rx_timeout_ms;
 	cinfo->max_msg_size = info->desc->max_msg_size;
+	cinfo->no_completion_irq = info->desc->no_completion_irq;
 
 	/* Create a unique name for this transport device */
 	snprintf(name, 32, "__scmi_transport_device_%s_%02X",
@@ -3092,6 +3093,9 @@ static const struct scmi_desc *scmi_transport_setup(struct device *dev)
 	if (ret && ret != -EINVAL)
 		dev_err(dev, "Malformed arm,max-msg DT property.\n");
 
+	trans->desc.no_completion_irq = of_property_read_bool(dev->of_node,
+							      "arm,poll-transport");
+
 	dev_info(dev,
 		 "SCMI max-rx-timeout: %dms / max-msg-size: %dbytes / max-msg: %d\n",
 		 trans->desc.max_rx_timeout_ms, trans->desc.max_msg_size,
-- 
2.51.0



From linusw at kernel.org  Wed Dec 31 13:37:15 2025
From: linusw at kernel.org (Linus Walleij)
Date: Wed, 31 Dec 2025 22:37:15 +0100
Subject: [PATCH RFC 02/16] pinctrl: aspeed: g5: Constrain LPC binding
 revision workaround to AST2500
In-Reply-To: <20251211-dev-dt-warnings-all-v1-2-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
 <20251211-dev-dt-warnings-all-v1-2-21b18b9ada77@codeconstruct.com.au>
Message-ID: <CAD++jLmNGrDt3_w=DFnBnjEuz3LN-=uc1o9KHv1j=4gbGPoPQg@mail.gmail.com>

On Thu, Dec 11, 2025 at 9:46?AM Andrew Jeffery
<andrew at codeconstruct.com.au> wrote:

> Discovering a phandle to an AST2400 or AST2600 LPC node indicates an
> error for the purpose of the AST2500 pinctrl driver.
>
> Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>

Reviewed-by: Linus Walleij <linusw at kernel.org>

Also pretty obviously correct, can't I just apply this one?

Yours,
Linus Walleij


From linusw at kernel.org  Wed Dec 31 13:38:12 2025
From: linusw at kernel.org (Linus Walleij)
Date: Wed, 31 Dec 2025 22:38:12 +0100
Subject: [PATCH RFC 03/16] pinctrl: aspeed: g5: Allow use of LPC node
 instead of LPC host controller
In-Reply-To: <20251211-dev-dt-warnings-all-v1-3-21b18b9ada77@codeconstruct.com.au>
References: <20251211-dev-dt-warnings-all-v1-0-21b18b9ada77@codeconstruct.com.au>
 <20251211-dev-dt-warnings-all-v1-3-21b18b9ada77@codeconstruct.com.au>
Message-ID: <CAD++jL=TXQyGD5nSdg37KK=OrUJDwi=2pXQciLr+udC9hjCVkw@mail.gmail.com>

On Thu, Dec 11, 2025 at 9:46?AM Andrew Jeffery
<andrew at codeconstruct.com.au> wrote:

> There's currently a wart where the Aspeed LPC host controller has no
> binding specified, but the pinctrl binding depends on referencing its
> node.
>
> Allow specification of a phandle to the parent LPC controller instead.
> Fall back to testing for a compatible parent node if the provided
> phandle doesn't directly resolve to the LPC controller node.
>
> Signed-off-by: Andrew Jeffery <andrew at codeconstruct.com.au>

Reviewed-by: Linus Walleij <linusw at kernel.org>

I guess when this is non-RFC I will just apply these two patches.

Yours,
Linus Walleij


From linusw at kernel.org  Wed Dec 31 13:50:55 2025
From: linusw at kernel.org (Linus Walleij)
Date: Wed, 31 Dec 2025 22:50:55 +0100
Subject: [PATCH 3/8] dt-bindings: watchdog: Add AAEON embedded controller
 watchdog binding
In-Reply-To: <019aa49f-fe59-488d-aff8-f07cf07ee68d@kernel.org>
References: <20251212-dev-b4-aaeon-mcu-driver-v1-0-6bd65bc8ef12@bootlin.com>
 <20251212-dev-b4-aaeon-mcu-driver-v1-3-6bd65bc8ef12@bootlin.com> <019aa49f-fe59-488d-aff8-f07cf07ee68d@kernel.org>
Message-ID: <CAD++jLmKL4afaOn_eka6v=j_Wu0orZMb-2NbPZgP4SM2q4V7qw@mail.gmail.com>

On Fri, Dec 12, 2025 at 9:20?AM Krzysztof Kozlowski <krzk at kernel.org> wrote:
> On 12/12/2025 08:41, Thomas Perrot (Schneider Electric) wrote:
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > +  - |
> > +    watchdog {
> > +      compatible = "aaeon,srg-imx8pl-wdt";
>
> No, that was discussed many times on the mailing list already. Fold the
> child into the parent. Your driver model really do not matter for DT.

True. For an example in Linux check how I spawn a watchdog
platform device from a timer node in:
drivers/clocksource/timer-ixp4xx.c

It's just one node in the device tree, in Linux it is in two different
subsystems but we just deal with that in code.

Yours,
Linus Walleij


From vz at mleia.com  Wed Dec 31 13:57:50 2025
From: vz at mleia.com (Vladimir Zapolskiy)
Date: Wed, 31 Dec 2025 23:57:50 +0200
Subject: [PATCH 1/5] dt-bindings: mfd: nxp: Add NXP LPC32xx System Control Block
In-Reply-To: <20251231215754.2222308-1-vz@mleia.com>
References: <20251231215754.2222308-1-vz@mleia.com>
Message-ID: <20251231215754.2222308-2-vz@mleia.com>

NXP LPC32xx SoC series contains a System Control Block, which serves for
a multitude of purposes including clock and power management, DMA muxing,
storing SoC unique ID etc.

Signed-off-by: Vladimir Zapolskiy <vz at mleia.com>
---
 .../bindings/mfd/nxp,lpc3220-scb.yaml         | 74 +++++++++++++++++++
 1 file changed, 74 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/nxp,lpc3220-scb.yaml

diff --git a/Documentation/devicetree/bindings/mfd/nxp,lpc3220-scb.yaml b/Documentation/devicetree/bindings/mfd/nxp,lpc3220-scb.yaml
new file mode 100644
index 000000000000..b993dd15135a
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/nxp,lpc3220-scb.yaml
@@ -0,0 +1,74 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/nxp,lpc3220-scb.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP LPC32xx System Control Block
+
+maintainers:
+  - Vladimir Zapolskiy <vz at mleia.com>
+
+description:
+  NXP LPC32xx SoC series have a System Control Block, which serves for
+  a multitude of purposes including clock management, DMA muxes, storing
+  SoC unique ID etc.
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - nxp,lpc3220-scb
+      - const: syscon
+      - const: simple-mfd
+
+  reg:
+    maxItems: 1
+
+  ranges: true
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 1
+
+patternProperties:
+  "^clock-controller@[0-9a-f]+$":
+    $ref: /schemas/clock/nxp,lpc3220-clk.yaml#
+
+  "^dma-router@[0-9a-f]+$":
+    $ref: /schemas/dma/nxp,lpc3220-dmamux.yaml#
+
+required:
+  - compatible
+  - reg
+  - "#address-cells"
+  - "#size-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    syscon at 400040000 {
+        compatible = "nxp,lpc3220-scb", "syscon", "simple-mfd";
+        reg = <0x40004000 0x1000>;
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges = <0 0x40004000 0x1000>;
+
+        clock-controller at 0 {
+            compatible = "nxp,lpc3220-clk";
+            reg = <0x0 0x114>;
+            clocks = <&xtal_32k>, <&xtal>;
+            clock-names = "xtal_32k", "xtal";
+            #clock-cells = <1>;
+        };
+
+        dma-router at 78 {
+            compatible = "nxp,lpc3220-dmamux";
+            reg = <0x78 0x8>;
+            dma-masters = <&dma>;
+            #dma-cells = <3>;
+        };
+    };
-- 
2.43.0



From vz at mleia.com  Wed Dec 31 13:57:49 2025
From: vz at mleia.com (Vladimir Zapolskiy)
Date: Wed, 31 Dec 2025 23:57:49 +0200
Subject: [PATCH 0/5] ARM: dts: lpc32xx: Add DMA support to platform device tree
Message-ID: <20251231215754.2222308-1-vz@mleia.com>

At the moment NXP LPC32xx has basic DMA support in the platform code, it works
well with NAND flash controllers, but it makes sense to extend it to other
controllers.

The SoC specific dts changes were extracted and updated from an old
unapplied series, which added better DMA and I2S support to the platform:
- https://lore.kernel.org/linux-arm-kernel/20240627150046.258795-1-piotr.wojtaszczyk at timesys.com/

DMA support from the original change was dropped for a number of controllers
due to driver related issues, which cause runtime regressions. While the .dtsi
code seems to be correct, it cannot be tested and verified before making driver
changes, this concerns:
* ARM PL180 SDHC driver does not support a single 'rx-tx' type of DMA channel,
* ARM PL022 SSP driver defers its probe instead of bailing out on DMA issues,
* HS UART driver misses a feature to support DMA operations.

This patch series obsoletes another and smipler one:
- https://lore.kernel.org/linux-arm-kernel/379f38ac-ab4a-4615-894b-e404bea4a6a1 at mleia.com

Piotr Wojtaszczyk (3):
  ARM: dts: lpc32xx: Use syscon for system control block
  ARM: dts: lpc32xx: Add missing DMA properties
  ARM: dts: lpc32xx: Add missing properties to I2S device tree nodes

Vladimir Zapolskiy (2):
  dt-bindings: mfd: nxp: Add NXP LPC32xx System Control Block
  ARM: dts: lpc32xx: Declare the second AHB master support on PL080 DMA controller

 .../bindings/mfd/nxp,lpc3220-scb.yaml         | 74 +++++++++++++++++++
 arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi        | 41 +++++++++-
 2 files changed, 111 insertions(+), 4 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mfd/nxp,lpc3220-scb.yaml

-- 
2.43.0



From vz at mleia.com  Wed Dec 31 13:57:51 2025
From: vz at mleia.com (Vladimir Zapolskiy)
Date: Wed, 31 Dec 2025 23:57:51 +0200
Subject: [PATCH 2/5] ARM: dts: lpc32xx: Use syscon for system control block
In-Reply-To: <20251231215754.2222308-1-vz@mleia.com>
References: <20251231215754.2222308-1-vz@mleia.com>
Message-ID: <20251231215754.2222308-3-vz@mleia.com>

From: Piotr Wojtaszczyk <piotr.wojtaszczyk at timesys.com>

The clock controller is a part of NXP LPC32xx system control block (SCB),
and SCB provides a number of controllers apart of the clock controller.

[vzapolskiy]:
1. kept a simple comment,
2. renamed SoC specific compatible to 'nxp,lpc3220-scb' due to the SoC UM,
3. changed size in 'ranges', since it should cover more SCB functions,
4. updated the commit message.

Link to the original change:
* https://lore.kernel.org/linux-arm-kernel/20240627150046.258795-5-piotr.wojtaszczyk at timesys.com/

Signed-off-by: Piotr Wojtaszczyk <piotr.wojtaszczyk at timesys.com>
Signed-off-by: Vladimir Zapolskiy <vz at mleia.com>
---
 arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
index 2236901a0031..89e621dfb950 100644
--- a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
+++ b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
@@ -314,17 +314,17 @@ fab {
 			ranges = <0x20000000 0x20000000 0x30000000>;
 
 			/* System Control Block */
-			scb {
-				compatible = "simple-bus";
-				ranges = <0x0 0x40004000 0x00001000>;
+			syscon at 40004000 {
+				compatible = "nxp,lpc3220-scb", "syscon", "simple-mfd";
+				reg = <0x40004000 0x1000>;
 				#address-cells = <1>;
 				#size-cells = <1>;
+				ranges = <0 0x40004000 0x1000>;
 
 				clk: clock-controller at 0 {
 					compatible = "nxp,lpc3220-clk";
 					reg = <0x00 0x114>;
 					#clock-cells = <1>;
-
 					clocks = <&xtal_32k>, <&xtal>;
 					clock-names = "xtal_32k", "xtal";
 				};
-- 
2.43.0



From vz at mleia.com  Wed Dec 31 13:57:52 2025
From: vz at mleia.com (Vladimir Zapolskiy)
Date: Wed, 31 Dec 2025 23:57:52 +0200
Subject: [PATCH 3/5] ARM: dts: lpc32xx: Add missing DMA properties
In-Reply-To: <20251231215754.2222308-1-vz@mleia.com>
References: <20251231215754.2222308-1-vz@mleia.com>
Message-ID: <20251231215754.2222308-4-vz@mleia.com>

From: Piotr Wojtaszczyk <piotr.wojtaszczyk at timesys.com>

Add properties declared in the new DT binding nxp,lpc3220-dmamux.yaml
and corresponding phandles.

[vzapolskiy]:
1. rebased the change,
2. dmamux unit address shall be 0x78 instead of 0x7c,
3. removed unsupported 'dmas' properties from sd, ssp0, ssp1 and HS UARTs,
4. more non-functional updates by reordering properies,
5. minor updates to the commit message.

Link to the original change:
* https://lore.kernel.org/linux-arm-kernel/20240627150046.258795-6-piotr.wojtaszczyk at timesys.com/

Signed-off-by: Piotr Wojtaszczyk <piotr.wojtaszczyk at timesys.com>
Signed-off-by: Vladimir Zapolskiy <vz at mleia.com>
---
 arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
index 89e621dfb950..4f3944d6d765 100644
--- a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
+++ b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
@@ -66,6 +66,8 @@ slc: flash at 20020000 {
 			compatible = "nxp,lpc3220-slc";
 			reg = <0x20020000 0x1000>;
 			clocks = <&clk LPC32XX_CLK_SLC>;
+			dmas = <&dma 1 1>;
+			dma-names = "rx-tx";
 			status = "disabled";
 		};
 
@@ -74,6 +76,8 @@ mlc: flash at 200a8000 {
 			reg = <0x200a8000 0x11000>;
 			interrupts = <11 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&clk LPC32XX_CLK_MLC>;
+			dmas = <&dma 12 1>;
+			dma-names = "rx-tx";
 			status = "disabled";
 		};
 
@@ -83,6 +87,12 @@ dma: dma-controller at 31000000 {
 			interrupts = <28 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&clk LPC32XX_CLK_DMA>;
 			clock-names = "apb_pclk";
+			dma-channels = <8>;
+			dma-requests = <16>;
+			lli-bus-interface-ahb1;
+			mem-bus-interface-ahb1;
+			memcpy-burst-size = <256>;
+			memcpy-bus-width = <32>;
 			#dma-cells = <2>;
 		};
 
@@ -190,6 +200,8 @@ spi1: spi at 20088000 {
 				compatible = "nxp,lpc3220-spi";
 				reg = <0x20088000 0x1000>;
 				clocks = <&clk LPC32XX_CLK_SPI1>;
+				dmas = <&dmamux 11 1 0>;
+				dma-names = "rx-tx";
 				#address-cells = <1>;
 				#size-cells = <0>;
 				status = "disabled";
@@ -214,6 +226,8 @@ spi2: spi at 20090000 {
 				compatible = "nxp,lpc3220-spi";
 				reg = <0x20090000 0x1000>;
 				clocks = <&clk LPC32XX_CLK_SPI2>;
+				dmas = <&dmamux 3 1 0>;
+				dma-names = "rx-tx";
 				#address-cells = <1>;
 				#size-cells = <0>;
 				status = "disabled";
@@ -222,6 +236,8 @@ spi2: spi at 20090000 {
 			i2s0: i2s at 20094000 {
 				compatible = "nxp,lpc3220-i2s";
 				reg = <0x20094000 0x1000>;
+				dmas = <&dma 0 1>, <&dma 13 1>;
+				dma-names = "rx", "tx";
 				status = "disabled";
 			};
 
@@ -238,6 +254,8 @@ sd: mmc at 20098000 {
 			i2s1: i2s at 2009c000 {
 				compatible = "nxp,lpc3220-i2s";
 				reg = <0x2009c000 0x1000>;
+				dmas = <&dma 2 1>, <&dmamux 10 1 1>;
+				dma-names = "rx", "tx";
 				status = "disabled";
 			};
 
@@ -328,6 +346,13 @@ clk: clock-controller at 0 {
 					clocks = <&xtal_32k>, <&xtal>;
 					clock-names = "xtal_32k", "xtal";
 				};
+
+				dmamux: dma-router at 78 {
+					compatible = "nxp,lpc3220-dmamux";
+					reg = <0x78 0x8>;
+					dma-masters = <&dma>;
+					#dma-cells = <3>;
+				};
 			};
 
 			mic: interrupt-controller at 40008000 {
-- 
2.43.0



From vz at mleia.com  Wed Dec 31 13:57:53 2025
From: vz at mleia.com (Vladimir Zapolskiy)
Date: Wed, 31 Dec 2025 23:57:53 +0200
Subject: [PATCH 4/5] ARM: dts: lpc32xx: Declare the second AHB master support on PL080 DMA controller
In-Reply-To: <20251231215754.2222308-1-vz@mleia.com>
References: <20251231215754.2222308-1-vz@mleia.com>
Message-ID: <20251231215754.2222308-5-vz@mleia.com>

Add 'lli-bus-interface-ahb2' and 'mem-bus-interface-ahb2' properties to
the PL080 DMA controller device tree node, tested with dmatest utility.

Signed-off-by: Vladimir Zapolskiy <vz at mleia.com>
---
 arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
index 4f3944d6d765..389777ee6850 100644
--- a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
+++ b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
@@ -90,7 +90,9 @@ dma: dma-controller at 31000000 {
 			dma-channels = <8>;
 			dma-requests = <16>;
 			lli-bus-interface-ahb1;
+			lli-bus-interface-ahb2;
 			mem-bus-interface-ahb1;
+			mem-bus-interface-ahb2;
 			memcpy-burst-size = <256>;
 			memcpy-bus-width = <32>;
 			#dma-cells = <2>;
-- 
2.43.0



From vz at mleia.com  Wed Dec 31 13:57:54 2025
From: vz at mleia.com (Vladimir Zapolskiy)
Date: Wed, 31 Dec 2025 23:57:54 +0200
Subject: [PATCH 5/5] ARM: dts: lpc32xx: Add missing properties to I2S device tree nodes
In-Reply-To: <20251231215754.2222308-1-vz@mleia.com>
References: <20251231215754.2222308-1-vz@mleia.com>
Message-ID: <20251231215754.2222308-6-vz@mleia.com>

From: Piotr Wojtaszczyk <piotr.wojtaszczyk at timesys.com>

Add NXP LPC32xx I2S controller device tree properties in accordance to
nxp,lpc3220-i2s.yaml.

Link to the original change:
* https://lore.kernel.org/linux-arm-kernel/20240627150046.258795-7-piotr.wojtaszczyk at timesys.com/

Signed-off-by: Piotr Wojtaszczyk <piotr.wojtaszczyk at timesys.com>
[vzapolskiy: changes to the commit message]
Signed-off-by: Vladimir Zapolskiy <vz at mleia.com>
---
 arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
index 389777ee6850..53e12679ba5b 100644
--- a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
+++ b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
@@ -238,8 +238,11 @@ spi2: spi at 20090000 {
 			i2s0: i2s at 20094000 {
 				compatible = "nxp,lpc3220-i2s";
 				reg = <0x20094000 0x1000>;
+				interrupts = <22 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk LPC32XX_CLK_I2S0>;
 				dmas = <&dma 0 1>, <&dma 13 1>;
 				dma-names = "rx", "tx";
+				#sound-dai-cells = <0>;
 				status = "disabled";
 			};
 
@@ -256,8 +259,11 @@ sd: mmc at 20098000 {
 			i2s1: i2s at 2009c000 {
 				compatible = "nxp,lpc3220-i2s";
 				reg = <0x2009c000 0x1000>;
+				interrupts = <23 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk LPC32XX_CLK_I2S1>;
 				dmas = <&dma 2 1>, <&dmamux 10 1 1>;
 				dma-names = "rx", "tx";
+				#sound-dai-cells = <0>;
 				status = "disabled";
 			};
 
-- 
2.43.0



From Sebastian.Wolf at pace-systems.de  Wed Dec 31 14:52:06 2025
From: Sebastian.Wolf at pace-systems.de (Sebastian Roland Wolf)
Date: Wed, 31 Dec 2025 23:52:06 +0100
Subject: [PATCH] net: mediatek: add null pointer check for hardware offloading
Message-ID: <20251231225206.3212871-1-Sebastian.Wolf@pace-systems.de>

From: Sebastian Roland Wolf <srw at root533.premium-rootserver.net>

Add a null pointer check to prevent kernel crashes when hardware
offloading is active on MediaTek devices.

In some edge cases, the ethernet pointer or its associated netdev
element can be NULL. Checking these pointers before access is
mandatory to avoid segmentation faults and kernel oops.

This improves the robustness of the validation check for mtk_eth
ingress devices introduced in commit 73cfd947dbdb ("net: mediatek:
add support for ingress traffic offloading").

Fixes: 73cfd947dbdb ("net: mediatek: add support for ingress traffic offloading")
net: mediatek: Add null pointer check to prevent crashes with active hardware offloading.

Signed-off-by: Sebastian Roland Wolf <Sebastian.Wolf at pace-systems.de>
---
 drivers/net/ethernet/mediatek/mtk_ppe_offload.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
index e9bd32741983..6900ac87e1e9 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
@@ -270,7 +270,8 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f,
 		flow_rule_match_meta(rule, &match);
 		if (mtk_is_netsys_v2_or_greater(eth)) {
 			idev = __dev_get_by_index(&init_net, match.key->ingress_ifindex);
-			if (idev && idev->netdev_ops == eth->netdev[0]->netdev_ops) {
+			if (idev && eth && eth->netdev[0] &&
+			    idev->netdev_ops == eth->netdev[0]->netdev_ops) {
 				struct mtk_mac *mac = netdev_priv(idev);
 
 				if (WARN_ON(mac->ppe_idx >= eth->soc->ppe_num))
-- 
2.51.0



From linux at roeck-us.net  Wed Dec 31 15:41:18 2025
From: linux at roeck-us.net (Guenter Roeck)
Date: Wed, 31 Dec 2025 15:41:18 -0800
Subject: [PATCH 1/2] watchdog: imx2_wdt: Allow to continue in low power
 mode
In-Reply-To: <20251229145000.421426-2-nandor.han@gehealthcare.com>
References: <20251229145000.421426-1-nandor.han@gehealthcare.com>
 <20251229145000.421426-2-nandor.han@gehealthcare.com>
Message-ID: <ee2771f2-539d-4bb2-adc1-663e39488148@roeck-us.net>

On Mon, Dec 29, 2025 at 04:49:59PM +0200, Nandor Han wrote:
> By default, the driver suspends the watchdog in low power modes (STOP
> and DOZE). In some situations this is not desired.

Following up on Krzysztof's comment to the devicetree patch:
Assuming the watchdog is in low power mode while the system is
suspended, it is all but impossible to imagine what those situations
might be. A reset by watchdog after the system is suspended simply
does not make sense. A system which must not go into suspend mode
must not be permitted to go into suspend mode to start with, or in
other words suspend mode must not be enabled to start with on such
systems.

Guenter


From skhan at linuxfoundation.org  Wed Dec 31 15:46:26 2025
From: skhan at linuxfoundation.org (Shuah Khan)
Date: Wed, 31 Dec 2025 16:46:26 -0700
Subject: [PATCH] wifi: mt76: Remove blank line after mt792x firmware version dmesg
Message-ID: <20251231234627.11867-1-skhan@linuxfoundation.org>

An extra blank line gets printed after printing firmware version
because the build date is null terminated. Remove the "\n" from
dev_info() calls to print firmware version and build date to fix
the problem.

Reported-by: Mario Limonciello <superm1 at gmail.com>
Signed-off-by: Shuah Khan <skhan at linuxfoundation.org>
---

Note: adding discussion threads about revert and simpler fix
for this. Mario sent me email offline about being away for
bit. Sending the patch since I have it ready before I disappear
for New Years.

Relevant threads:
- Revert for f804a5895ebad2b2d4fb8a3688d2115926e993d5
  https://lore.kernel.org/all/20251231035645.5545-1-skhan at linuxfoundation.org/

  This patch depends on revert patch.
- Discussion abour reverting:
  https://lore.kernel.org/all/d7f3b00d-beec-41f0-b157-7cfb871f9a46 at linuxfoundation.org/
- Proposed fix for reverted commit
  https://lore.kernel.org/all/CABXGCsMeAZyNJ-Axt_CUCXgyieWPV3rrcLpWsveMPT8R0YPGnQ at mail.gmail.com/

 drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
index fba7025ffd3f..0457712286d5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
@@ -3019,7 +3019,7 @@ int mt76_connac2_load_ram(struct mt76_dev *dev, const char *fw_wm,
 	}
 
 	hdr = (const void *)(fw->data + fw->size - sizeof(*hdr));
-	dev_info(dev->dev, "WM Firmware Version: %.10s, Build Time: %.15s\n",
+	dev_info(dev->dev, "WM Firmware Version: %.10s, Build Time: %.15s",
 		 hdr->fw_ver, hdr->build_date);
 
 	ret = mt76_connac_mcu_send_ram_firmware(dev, hdr, fw->data, false);
@@ -3048,7 +3048,7 @@ int mt76_connac2_load_ram(struct mt76_dev *dev, const char *fw_wm,
 	}
 
 	hdr = (const void *)(fw->data + fw->size - sizeof(*hdr));
-	dev_info(dev->dev, "WA Firmware Version: %.10s, Build Time: %.15s\n",
+	dev_info(dev->dev, "WA Firmware Version: %.10s, Build Time: %.15s",
 		 hdr->fw_ver, hdr->build_date);
 
 	ret = mt76_connac_mcu_send_ram_firmware(dev, hdr, fw->data, true);
@@ -3124,7 +3124,7 @@ int mt76_connac2_load_patch(struct mt76_dev *dev, const char *fw_name)
 	}
 
 	hdr = (const void *)fw->data;
-	dev_info(dev->dev, "HW/SW Version: 0x%x, Build Time: %.16s\n",
+	dev_info(dev->dev, "HW/SW Version: 0x%x, Build Time: %.16s",
 		 be32_to_cpu(hdr->hw_sw_ver), hdr->build_date);
 
 	for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) {
-- 
2.51.0



From jiyu.yang at oss.nxp.com  Wed Dec 31 16:37:28 2025
From: jiyu.yang at oss.nxp.com (Rain Yang)
Date: Thu, 1 Jan 2026 08:37:28 +0800
Subject: [PATCH] arm64: dts: imx95: remove CLK_GPUAPB
In-Reply-To: <37489cb7-820d-46cd-a7ea-0f9097604895@mailbox.org>
References: <20251231031915.752262-1-jiyu.yang@oss.nxp.com>
 <37489cb7-820d-46cd-a7ea-0f9097604895@mailbox.org>
Message-ID: <aVXByNiEfC66RDG0@oss.nxp.com>

On Wed, Dec 31, 2025 at 03:11:21PM +0100, Marek Vasut wrote:
>On 12/31/25 4:19 AM, Rain Yang wrote:
>> From: Rain Yang <jiyu.yang at nxp.com>
>> 
>> Dropping CLK_GPUAPB simplifies OPP handling and avoids unnecessary
>> complexity.
>> 
>> Fixes: 67934f248e64 ("arm64: dts: imx95: Describe Mali G310 GPU")
>> Signed-off-by: Rain Yang <jiyu.yang at nxp.com>
>> ---
>>   arch/arm64/boot/dts/freescale/imx95.dtsi | 4 ++--
>>   1 file changed, 2 insertions(+), 2 deletions(-)
>> 
>> diff --git a/arch/arm64/boot/dts/freescale/imx95.dtsi b/arch/arm64/boot/dts/freescale/imx95.dtsi
>> index 88bde59e61b2..ab446aa6f73c 100644
>> --- a/arch/arm64/boot/dts/freescale/imx95.dtsi
>> +++ b/arch/arm64/boot/dts/freescale/imx95.dtsi
>> @@ -2164,8 +2164,8 @@ netc_emdio: mdio at 0,0 {
>>   		gpu: gpu at 4d900000 {
>>   			compatible = "nxp,imx95-mali", "arm,mali-valhall-csf";
>>   			reg = <0 0x4d900000 0 0x480000>;
>> -			clocks = <&scmi_clk IMX95_CLK_GPU_CGC>, <&scmi_clk IMX95_CLK_GPUAPB>;
>> -			clock-names = "core", "coregroup";
>> +			clocks = <&scmi_clk IMX95_CLK_GPU_CGC>;
>> +			clock-names = "core";
>
>I don't think this is correct, SM can disable the GPUAPB clock from the SM
>monitor:
>
>>$ clock.w gpuapb off
>
>Linux has to make sure the GPUAPB clock are enabled to access the GPU
>register, hence the clock have to be described in DT.
Hi Marek,

CLK_GPU and CLK_GPUAPB can only be controlled internally by the SM, not by Linux.
CLK_GPUAPB always runs at a fixed frequency, does not require dynamic adjustment,
and is practically always on.
Additionally, CLK_GPUAPB's frequency is absent from all OPP entries. Removing it
could simplify OPP handling logic and reduce unnecessary complexity.


From lists at philpem.me.uk  Wed Dec 31 16:52:46 2025
From: lists at philpem.me.uk (Philip Pemberton)
Date: Thu, 1 Jan 2026 00:52:46 +0000
Subject: EP29xx (TS-7200/TS-7300) board status
In-Reply-To: <022f07dd-9c48-42d8-b5c2-172cf755f30f@philpem.me.uk>
References: <022f07dd-9c48-42d8-b5c2-172cf755f30f@philpem.me.uk>
Message-ID: <b1416419-8315-43bd-8369-8a1fbd8ed85f@philpem.me.uk>

A bit of an update to my previous message, quoted below. And happy new year!

I've put my kernel configs and bootloader patches on Github at:
   <https://github.com/philpem/ts7300/>
and will be adding more to this repository soon.

Most of the issues I had with the TS7300 board seem to be down to a mix 
of the bootloader and a misunderstanding of the memory layout.

The memory layout on the 32MiB SDRAM TS-7300 is non-contiguous:
   - 8 MiB at 0x0000_0000 (to 0x007F_FFFF)
   - 8 MiB at 0x0100_0000 (to 0x017F_FFFF)
   - 8 MiB at 0x0400_0000 (to 0x047F_FFFF)
   - 8 MiB at 0x0500_0000 (to 0x057F_FFFF)

(If anyone has a 64MB or 128MB board it'd be nice to know what chips are 
fitted, and what /proc/iomem says about the RAM layout. Cirrus DS785UM1 
page 13-12/13-13 suggests that this layout holds for 64MiB SDRAM chips 
in a 13x10x4 row*col*bank layout - except that there would be four more 
8MB stripes at 02xx_, 03xx_, 06xx_ and 07xx_)

The TS-SDBOOT code in the 2K SPI EEPROM initialises SDRAM, loads the 
first sector (MBR) of the SD Card and executes it at 0x1000 in ARM Thumb 
mode. The boot sector then loads the kernel and initramfs, builds the 
ATAGS and jumps to the kernel.

The problem is, the kernel is loaded at 0x0021_8000 (2144K into the 
first RAM block): if the kernel image is uncompressed, this limits the 
size of an uncompressed (Image) kernel to 8MB less 2144K = 6048K, and 
the loading base needs to be changed.
With a compressed (zImage) kernel and the default boot loader, the 
uncompressed and compressed images must fit into the same 8MB block!

I patched the boot sector to load the kernel at 0400_0000, giving 8 MiB 
each for the uncompressed zImage, initramfs and compressed kernel. This 
solves the kernel size issue nicely. (another way to go would be 
patching it to load the kernel at 0x8000).

Kernel 6.18.1 (built with Ubuntu arm-linux-gnueabi-gcc 
13.3.0-6ubuntu2~24.04 and Binutils 2.42) seems to work pretty well after 
some configuration to remove unnecessary features and disable strong 
stack guarding (see my previous message).

So far the main issues are:

   * '/sbin/reboot' crashes at "Reboot failed -- System halted" and the 
board hangs. (This may need a kernel patch as I think the only way to 
reboot this board is by tripping the TS-7300 Watchdog)

   * DHCP doesn't pass the NFS server and root path onto NFS - this 
breaks NFS booting. Passing the NFS root on the command line 
(nfsroot=10.1.2.3:/nfs/armroot,v3,nolock,tcp) works as a workaround.

   * There's no SD Card driver, I presume because while TS provided 
source as part of their modified 2.4 kernel, it's flagged "License: 
Proprietary". I need to look at options for this.

   * The kernel needs a DTB to boot, and the bootloader pre-dates Device 
Trees. The easy fix is to use a compressed kernel and 'cat' the DTB onto 
the end, and make sure the relevant CONFIG_ option is set to allow this.

This also seems to happen after a few minutes runtime but it doesn't 
affect the system otherwise and I'm not sure what causes it:

> Unable to handle kernel NULL pointer dereference at virtual address 00000030 when read
> [00000030] *pgd=00000000
> Internal error: Oops: 17 [#1] ARM
> Modules linked in:
> CPU: 0 UID: 0 PID: 24 Comm: kworker/u4:2 Not tainted 6.18.2 #8 NONE 
> Hardware name: Generic DT based system
> Workqueue: events_unbound idle_cull_fn
> PC is at __set_cpus_allowed_ptr+0x48/0x88
> LR is at __set_cpus_allowed_ptr+0x28/0x88
> pc : [<c0047834>]    lr : [<c0047814>]    psr: 60000093
> sp : c611dea8  ip : c143422c  fp : c611debc
> r10: c1408d05  r9 : c06bc59c  r8 : c0696888
> r7 : 00000122  r6 : 00000100  r5 : c142dc00  r4 : c611dec4
> r3 : c06c1a04  r2 : c0698440  r1 : 00000030  r0 : c0698440
> Flags: nZCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment none
> Control: c000717f  Table: 016f4000  DAC: 00000053
> Register r0 information: non-slab/vmalloc memory
> Register r1 information: non-paged memory
> Register r2 information: non-slab/vmalloc memory
> Register r3 information: non-slab/vmalloc memory
> Register r4 information: 2-page vmalloc region starting at 0xc611c000 allocated at kernel_clone+0xac/0x1f4
> Register r5 information: slab task_struct start c142dc00 pointer offset 0 size 1792
> Register r6 information: non-paged memory
> Register r7 information: non-paged memory
> Register r8 information: non-slab/vmalloc memory
> Register r9 information: non-slab/vmalloc memory
> Register r10 information: slab kmalloc-256 start c1408d00 pointer offset 5 size 256
> Register r11 information: 2-page vmalloc region starting at 0xc611c000 allocated at kernel_clone+0xac/0x1f4
> Register r12 information: slab kmalloc-128 start c1434200 pointer offset 44 size 128
> Process kworker/u4:2 (pid: 24, stack limit = 0x(ptrval))
> Stack: (0xc611dea8 to 0xc611e000)
> dea0:                   20000013 00000000 c1434200 c611df00 c611ded4 c0047940
> dec0: c1434200 c06c1a04 00000000 00000000 61c88647 c0037970 c1434200 c00389cc
> dee0: c0696888 c0696830 00000000 c06a5cd0 c0696888 c0038a68 c1408d00 00000000
> df00: c1434200 c1434200 c1655780 c1655780 c1408d00 c1409000 c069688c c003919c
> df20: 00000000 00000002 c157e300 c157e300 c157e300 c1409000 c1655780 c1655780
> df40: c140902c c1409000 c0039694 c157e300 00000402 c16557ac 00000000 c0039808
> df60: 00000000 c1655a80 c1657920 c157e300 c0039694 c1655780 00000001 00000000
> df80: 00000000 c0040efc c1657920 c157e300 c1657920 c0040d5c 00000000 00000000
> dfa0: 00000000 00000000 00000000 c000834c 00000000 00000000 00000000 00000000
> dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
> dfe0: 00000000 00000000 00000000 00000000 00000013 00000000 00000000 00000000
> Call trace: 
>  __set_cpus_allowed_ptr from set_cpus_allowed_ptr+0x24/0x30
>  set_cpus_allowed_ptr from unbind_worker+0x38/0xc4
>  unbind_worker from detach_dying_workers+0x2c/0x48
>  detach_dying_workers from idle_cull_fn+0x80/0xb0
>  idle_cull_fn from process_scheduled_works+0x184/0x268
>  process_scheduled_works from worker_thread+0x174/0x1fc
>  worker_thread from kthread+0x1a0/0x1c0
>  kthread from ret_from_fork+0x14/0x28
> Exception stack(0xc611dfb0 to 0xc611dff8)
> dfa0:                                     00000000 00000000 00000000 00000000
> dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
> dfe0: 00000000 00000000 00000000 00000000 00000013 00000000
> Code: e5943008 e313000e 1a000009 e5943000 (e5911000) 
> ---[ end trace 0000000000000000 ]---
> note: kworker/u4:2[24] exited with irqs disabled

I've no idea what's going on with this but it seems benign?

Cheers
Phil.

On 29/12/2025 21:48, Philip Pemberton wrote:
> Hi,
> 
> I wondered if anyone knew what condition the EP39xx kernel support was 
> currently in, and whether anything special (configuration etc.) was 
> needed to get recent kernels to boot on the TS-7300 hardware?
> 
> The latest kernel I've had working out-of-box was 4.17.19, which gets as 
> far as trying to mount the root filesystem (the initrd the TS bootloader 
> loads doesn't seem to be recognised).
> 4.18.1 also works works, so long as I run "make menuconfig" after "make 
> ep93xx_defconfig" and set CONFIG_STACKPROTECTOR_STRONG=n.
> 
> 4.19.1 and 4.20.9 crash before printing the "Uncompressing Linux" banner 
> and eventually reboot. This holds for every later kernel I've tried.
> I've also seen this error while bisecting from 4.18.1 to 4.19.1:
>  ? Uncompressing Linux... done, booting the kernel.
>  ? Warning: Neither atags nor dtb found
> Which doesn't make any sense. But nor did the bad commit:
>  ? # first bad commit: [9a76aba02a37718242d7cdc294f0a3901928aa57] Merge 
> git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
> 
> The boot sector loads the compressed kernel in SDRAM at 0x218000, the 
> initrd at 0x01000000, and the ATAGS end up at 0x100.
> 
> I'm using the gcc-linaro-6.4.1-2017.11-x86_64_arm-linux-gnueabihf 
> compiler as it's a similar vintage to the 4.x kernels and I wanted to 
> rule out issues with the gcc-13 Debian gcc.
> 
> Thanks.

-- 
Phil.
philpem at philpem.me.uk
http://www.philpem.me.uk



From aliceryhl at google.com  Wed Dec 31 16:53:39 2025
From: aliceryhl at google.com (Alice Ryhl)
Date: Thu, 1 Jan 2026 00:53:39 +0000
Subject: [PATCH 0/5] Add READ_ONCE and WRITE_ONCE to Rust
In-Reply-To: <20251231151216.23446b64.gary@garyguo.net>
References: <20251231-rwonce-v1-0-702a10b85278@google.com> <20251231151216.23446b64.gary@garyguo.net>
Message-ID: <aVXFk0L-FegoVJpC@google.com>

On Wed, Dec 31, 2025 at 03:12:16PM +0000, Gary Guo wrote:
> On Wed, 31 Dec 2025 12:22:24 +0000
> Alice Ryhl <aliceryhl at google.com> wrote:
> 
> > There are currently a few places in the kernel where we use volatile
> > reads when we really should be using `READ_ONCE`. To make it possible to
> > replace these with proper `READ_ONCE` calls, introduce a Rust version of
> > `READ_ONCE`.
> > 
> > A new config option CONFIG_ARCH_USE_CUSTOM_READ_ONCE is introduced so
> > that Rust is able to use conditional compilation to implement READ_ONCE
> > in terms of either a volatile read, or by calling into a C helper
> > function, depending on the architecture.
> > 
> > This series is intended to be merged through ATOMIC INFRASTRUCTURE.
> 
> Hi Alice,
> 
> I would prefer not to expose the READ_ONCE/WRITE_ONCE functions, at
> least not with their atomic semantics.
> 
> Both callsites that you have converted should be using
> 
> 	Atomic::from_ptr().load(Relaxed)
> 
> Please refer to the documentation of `Atomic` about this. Fujita has a
> series that expand the type to u8/u16 if you need narrower accesses.

Why? If we say that we're using the LKMM, then it seems confusing to not
have a READ_ONCE() for cases where we interact with C code, and that C
code documents that READ_ONCE() should be used.

Alice


From boqun.feng at gmail.com  Wed Dec 31 17:13:35 2025
From: boqun.feng at gmail.com (Boqun Feng)
Date: Thu, 1 Jan 2026 09:13:35 +0800
Subject: [PATCH 0/5] Add READ_ONCE and WRITE_ONCE to Rust
In-Reply-To: <aVXFk0L-FegoVJpC@google.com>
References: <20251231-rwonce-v1-0-702a10b85278@google.com>
 <20251231151216.23446b64.gary@garyguo.net>
 <aVXFk0L-FegoVJpC@google.com>
Message-ID: <aVXKP8vQ6uAxtazT@tardis-2.local>

On Thu, Jan 01, 2026 at 12:53:39AM +0000, Alice Ryhl wrote:
> On Wed, Dec 31, 2025 at 03:12:16PM +0000, Gary Guo wrote:
> > On Wed, 31 Dec 2025 12:22:24 +0000
> > Alice Ryhl <aliceryhl at google.com> wrote:
> > 
> > > There are currently a few places in the kernel where we use volatile
> > > reads when we really should be using `READ_ONCE`. To make it possible to
> > > replace these with proper `READ_ONCE` calls, introduce a Rust version of
> > > `READ_ONCE`.
> > > 
> > > A new config option CONFIG_ARCH_USE_CUSTOM_READ_ONCE is introduced so
> > > that Rust is able to use conditional compilation to implement READ_ONCE
> > > in terms of either a volatile read, or by calling into a C helper
> > > function, depending on the architecture.
> > > 
> > > This series is intended to be merged through ATOMIC INFRASTRUCTURE.
> > 
> > Hi Alice,
> > 
> > I would prefer not to expose the READ_ONCE/WRITE_ONCE functions, at
> > least not with their atomic semantics.
> > 
> > Both callsites that you have converted should be using
> > 
> > 	Atomic::from_ptr().load(Relaxed)
> > 
> > Please refer to the documentation of `Atomic` about this. Fujita has a
> > series that expand the type to u8/u16 if you need narrower accesses.
> 
> Why? If we say that we're using the LKMM, then it seems confusing to not
> have a READ_ONCE() for cases where we interact with C code, and that C
> code documents that READ_ONCE() should be used.
> 

The problem of READ_ONCE() and WRITE_ONCE() is that the semantics is
complicated. Sometimes they are used for atomicity, sometimes they are
used for preventing data race. So yes, we are using LKMM in Rust as
well, but whenever possible, we need to clarify the intentation of the
API, using Atomic::from_ptr().load(Relaxed) helps on that front.

IMO, READ_ONCE()/WRITE_ONCE() is like a "band aid" solution to a few
problems, having it would prevent us from developing a more clear view
for concurrent programming.

Regards,
Boqun

> Alice


From daniel at 0x0f.com  Wed Dec 31 19:42:58 2025
From: daniel at 0x0f.com (Daniel Palmer)
Date: Thu,  1 Jan 2026 12:42:58 +0900
Subject: [PATCH v2 0/8] Sigmastar DT warnings fixing
Message-ID: <20260101034306.1233091-1-daniel@0x0f.com>

v2 heads up: I didn't ignore Krzysztof's request to squash some commits,
I wasn't sure what to squash and I thought since I've fixed everything now
it was better to send a v2 sooner than later.

I've now fixed all of the warnings except one remaining one that seems to
need a change in dt-schema itself to cleanup:

serial at 221000 (ns16550a): reg-shift: 3 is not one of [0, 1, 2]
        from schema $id: http://devicetree.org/schemas/reg.yaml

The way registers are connected in these chips is weird. I think
they took their peripheral block from an 8051 microcontroller
and jammed it onto 32bit CPUs so all of the registers have
weird spacing and it really does need reg-shift == 3.

v1 blurb:
    
I saw a slide at LPC that had sigmastar in the "hall of shame"
for DT warnings. I finally got some time to look at this so
I have fixed the ones that are obvious and quick to fix.

I'll fix the rest but they might take a bit longer i.e. one
of them is about the register shift for the UART registers,
that'll need the binding to be updated I think?

FWIW this platform isn't dead and I have been rebasing all
of the out of tree stuff that make it useful (Audio support,
display, hardware video decoding etc) but its basically stuck
on rewriting the clock driver so that it is mainline-able.

Some other people have taken the limited support in mainline
and my out of tree stuff and made it run on old MStar MIPS
machines too..

change log:

v2:
 - Fix the regulator names as suggested by Krzysztof
 - Adjust the opp table name                
 - Add a commit to fix the cpupll binding and clean up the         
   warnings for that
 - Add a commit to fix the memory node in the infinity2m 
   dtsi to fix up the warnings about that.
 - Add a commit to switch the default led trigger on breadbee
   from the undocumented activity to cpu to fix up the
   warnings for the that.

Daniel Palmer (8):
  dt-bindings: clk: mstar msc313 cpupll: Correct clock-cells value
  arm: dts: mstar: breadbee: Correct regulator names
  arm: dts: mstar: breadbee: Correct LED names
  arm: dts: mstar: breadbee: Switch from "activity" led trigger to "cpu"
  arm: dts: mstar: infinity: Correct opp table name
  arm: dts: mstar: infinity2m: ssd202d: Correct memory node name
  arm: dts: mstar: v7: Move the reboot node
  arm: dts: mstar: v7: Add sizes and ranges to sram

 .../bindings/clock/mstar,msc313-cpupll.yaml     |  5 ++---
 .../mstar-infinity-breadbee-common.dtsi         | 12 ++++++------
 arch/arm/boot/dts/sigmastar/mstar-infinity.dtsi |  2 +-
 .../dts/sigmastar/mstar-infinity2m-ssd202d.dtsi |  2 +-
 arch/arm/boot/dts/sigmastar/mstar-v7.dtsi       | 17 ++++++++++-------
 5 files changed, 20 insertions(+), 18 deletions(-)

-- 
2.51.0



From daniel at 0x0f.com  Wed Dec 31 19:42:59 2025
From: daniel at 0x0f.com (Daniel Palmer)
Date: Thu,  1 Jan 2026 12:42:59 +0900
Subject: [PATCH v2 1/8] dt-bindings: clk: mstar msc313 cpupll: Correct clock-cells value
In-Reply-To: <20260101034306.1233091-1-daniel@0x0f.com>
References: <20260101034306.1233091-1-daniel@0x0f.com>
Message-ID: <20260101034306.1233091-2-daniel@0x0f.com>

clock-cells should have been 0 and causes warnings when
validating devicetrees.

Fix the value and fix the binding example.

Signed-off-by: Daniel Palmer <daniel at 0x0f.com>
---
 .../devicetree/bindings/clock/mstar,msc313-cpupll.yaml       | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/clock/mstar,msc313-cpupll.yaml b/Documentation/devicetree/bindings/clock/mstar,msc313-cpupll.yaml
index a9ad7ab5230c..889419fba269 100644
--- a/Documentation/devicetree/bindings/clock/mstar,msc313-cpupll.yaml
+++ b/Documentation/devicetree/bindings/clock/mstar,msc313-cpupll.yaml
@@ -18,7 +18,7 @@ properties:
     const: mstar,msc313-cpupll
 
   "#clock-cells":
-    const: 1
+    const: 0
 
   clocks:
     maxItems: 1
@@ -36,10 +36,9 @@ additionalProperties: false
 
 examples:
   - |
-    #include <dt-bindings/clock/mstar-msc313-mpll.h>
     cpupll: cpupll at 206400 {
         compatible = "mstar,msc313-cpupll";
         reg = <0x206400 0x200>;
-        #clock-cells = <1>;
+        #clock-cells = <0>;
         clocks = <&mpll MSTAR_MSC313_MPLL_DIV2>;
     };
-- 
2.51.0



From daniel at 0x0f.com  Wed Dec 31 19:43:00 2025
From: daniel at 0x0f.com (Daniel Palmer)
Date: Thu,  1 Jan 2026 12:43:00 +0900
Subject: [PATCH v2 2/8] arm: dts: mstar: breadbee: Correct regulator names
In-Reply-To: <20260101034306.1233091-1-daniel@0x0f.com>
References: <20260101034306.1233091-1-daniel@0x0f.com>
Message-ID: <20260101034306.1233091-3-daniel@0x0f.com>

The regulator names had a "@<n>" in them so the dt validation
stuff wanted a reg property. Fix the names to match what the regulator
is for and remove the "@<n>" bit.

Signed-off-by: Daniel Palmer <daniel at 0x0f.com>
---
 .../boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi  | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm/boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi b/arch/arm/boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi
index 507ff2fba837..99f5a5603dc7 100644
--- a/arch/arm/boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi
+++ b/arch/arm/boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi
@@ -7,7 +7,7 @@
 #include <dt-bindings/gpio/gpio.h>
 
 / {
-	vcc_core: fixedregulator at 0 {
+	vcc_core: regulator-core {
 		compatible = "regulator-fixed";
 		regulator-name = "vcc_core";
 		regulator-min-microvolt = <1000000>;
@@ -15,7 +15,7 @@ vcc_core: fixedregulator at 0 {
 		regulator-boot-on;
 	};
 
-	vcc_dram: fixedregulator at 1 {
+	vcc_dram: regulator-dram {
 		compatible = "regulator-fixed";
 		regulator-name = "vcc_dram";
 		regulator-min-microvolt = <1800000>;
@@ -23,7 +23,7 @@ vcc_dram: fixedregulator at 1 {
 		regulator-boot-on;
 	};
 
-	vcc_io: fixedregulator at 2 {
+	vcc_io: regulator-io {
 		compatible = "regulator-fixed";
 		regulator-name = "vcc_io";
 		regulator-min-microvolt = <3300000>;
-- 
2.51.0



From daniel at 0x0f.com  Wed Dec 31 19:43:01 2025
From: daniel at 0x0f.com (Daniel Palmer)
Date: Thu,  1 Jan 2026 12:43:01 +0900
Subject: [PATCH v2 3/8] arm: dts: mstar: breadbee: Correct LED names
In-Reply-To: <20260101034306.1233091-1-daniel@0x0f.com>
References: <20260101034306.1233091-1-daniel@0x0f.com>
Message-ID: <20260101034306.1233091-4-daniel@0x0f.com>

The dt validation stuff whats the names of the leds to match
a regexp.

Prefix the names with "led-" to make the validation happy.

Signed-off-by: Daniel Palmer <daniel at 0x0f.com>
---
 .../boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi    | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi b/arch/arm/boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi
index 99f5a5603dc7..71da10d9228f 100644
--- a/arch/arm/boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi
+++ b/arch/arm/boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi
@@ -33,11 +33,11 @@ vcc_io: regulator-io {
 
 	leds {
 		compatible = "gpio-leds";
-		red {
+		led-red {
 			gpios = <&gpio MSC313_GPIO_SR_IO16 GPIO_ACTIVE_HIGH>;
 			linux,default-trigger = "activity";
 		};
-		yellow {
+		led-yellow {
 			gpios = <&gpio MSC313_GPIO_SR_IO17 GPIO_ACTIVE_HIGH>;
 			linux,default-trigger = "heartbeat";
 		};
-- 
2.51.0



From daniel at 0x0f.com  Wed Dec 31 19:43:02 2025
From: daniel at 0x0f.com (Daniel Palmer)
Date: Thu,  1 Jan 2026 12:43:02 +0900
Subject: [PATCH v2 4/8] arm: dts: mstar: breadbee: Switch from "activity" led trigger to "cpu"
In-Reply-To: <20260101034306.1233091-1-daniel@0x0f.com>
References: <20260101034306.1233091-1-daniel@0x0f.com>
Message-ID: <20260101034306.1233091-5-daniel@0x0f.com>

The activity trigger exists but is not documented in the LED binding.
A patch was sent to document it but wasn't accepted.

The intention of the LED is to show if the system is busy or not
so the cpu trigger is good enough so switch to that to clean up
the warning.

Link: https://lore.kernel.org/all/20210923065500.2284347-4-daniel at 0x0f.com/
Signed-off-by: Daniel Palmer <daniel at 0x0f.com>
---
 arch/arm/boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi b/arch/arm/boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi
index 71da10d9228f..0f03f471a344 100644
--- a/arch/arm/boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi
+++ b/arch/arm/boot/dts/sigmastar/mstar-infinity-breadbee-common.dtsi
@@ -35,7 +35,7 @@ leds {
 		compatible = "gpio-leds";
 		led-red {
 			gpios = <&gpio MSC313_GPIO_SR_IO16 GPIO_ACTIVE_HIGH>;
-			linux,default-trigger = "activity";
+			linux,default-trigger = "cpu";
 		};
 		led-yellow {
 			gpios = <&gpio MSC313_GPIO_SR_IO17 GPIO_ACTIVE_HIGH>;
-- 
2.51.0



From daniel at 0x0f.com  Wed Dec 31 19:43:03 2025
From: daniel at 0x0f.com (Daniel Palmer)
Date: Thu,  1 Jan 2026 12:43:03 +0900
Subject: [PATCH v2 5/8] arm: dts: mstar: infinity: Correct opp table name
In-Reply-To: <20260101034306.1233091-1-daniel@0x0f.com>
References: <20260101034306.1233091-1-daniel@0x0f.com>
Message-ID: <20260101034306.1233091-6-daniel@0x0f.com>

The dt validation stuff expects the name of the opp table
to match a regexp and it currently doesn't.

Update the name to match the regexp.

Signed-off-by: Daniel Palmer <daniel at 0x0f.com>
---
 arch/arm/boot/dts/sigmastar/mstar-infinity.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/sigmastar/mstar-infinity.dtsi b/arch/arm/boot/dts/sigmastar/mstar-infinity.dtsi
index 441a917b88ba..40e38d995542 100644
--- a/arch/arm/boot/dts/sigmastar/mstar-infinity.dtsi
+++ b/arch/arm/boot/dts/sigmastar/mstar-infinity.dtsi
@@ -9,7 +9,7 @@
 #include <dt-bindings/gpio/msc313-gpio.h>
 
 / {
-	cpu0_opp_table: opp_table0 {
+	cpu0_opp_table: opp-table {
 		compatible = "operating-points-v2";
 		opp-shared;
 
-- 
2.51.0



From daniel at 0x0f.com  Wed Dec 31 19:43:04 2025
From: daniel at 0x0f.com (Daniel Palmer)
Date: Thu,  1 Jan 2026 12:43:04 +0900
Subject: [PATCH v2 6/8] arm: dts: mstar: infinity2m: ssd202d: Correct memory node name
In-Reply-To: <20260101034306.1233091-1-daniel@0x0f.com>
References: <20260101034306.1233091-1-daniel@0x0f.com>
Message-ID: <20260101034306.1233091-7-daniel@0x0f.com>

Memory node name didn't include the address which was causing
validation for all of the boards using the dtsi.

Signed-off-by: Daniel Palmer <daniel at 0x0f.com>
---
 arch/arm/boot/dts/sigmastar/mstar-infinity2m-ssd202d.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/sigmastar/mstar-infinity2m-ssd202d.dtsi b/arch/arm/boot/dts/sigmastar/mstar-infinity2m-ssd202d.dtsi
index 176e10a29896..74621a7628b2 100644
--- a/arch/arm/boot/dts/sigmastar/mstar-infinity2m-ssd202d.dtsi
+++ b/arch/arm/boot/dts/sigmastar/mstar-infinity2m-ssd202d.dtsi
@@ -7,7 +7,7 @@
 #include "mstar-infinity2m-ssd20xd.dtsi"
 
 / {
-	memory {
+	memory at 20000000 {
 		device_type = "memory";
 		reg = <0x20000000 0x8000000>;
 	};
-- 
2.51.0



From daniel at 0x0f.com  Wed Dec 31 19:43:05 2025
From: daniel at 0x0f.com (Daniel Palmer)
Date: Thu,  1 Jan 2026 12:43:05 +0900
Subject: [PATCH v2 7/8] arm: dts: mstar: v7: Move the reboot node
In-Reply-To: <20260101034306.1233091-1-daniel@0x0f.com>
References: <20260101034306.1233091-1-daniel@0x0f.com>
Message-ID: <20260101034306.1233091-8-daniel@0x0f.com>

The reboot node is currently inside of soc and that makes
the dt validation stuff complain that it wants some properties
that don't exist for reboot which is just some glue and not
a real device.

Move the node out of soc to fix the warnings.

Signed-off-by: Daniel Palmer <daniel at 0x0f.com>
---
 arch/arm/boot/dts/sigmastar/mstar-v7.dtsi | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/arch/arm/boot/dts/sigmastar/mstar-v7.dtsi b/arch/arm/boot/dts/sigmastar/mstar-v7.dtsi
index 3eeafd8c7121..db661e189eec 100644
--- a/arch/arm/boot/dts/sigmastar/mstar-v7.dtsi
+++ b/arch/arm/boot/dts/sigmastar/mstar-v7.dtsi
@@ -73,6 +73,13 @@ xtal_div2: xtal_div2 {
 		};
 	};
 
+	reboot {
+		compatible = "syscon-reboot";
+		regmap = <&pmsleep>;
+		offset = <0xb8>;
+		mask = <0x79>;
+	};
+
 	soc: soc {
 		compatible = "simple-bus";
 		#address-cells = <1>;
@@ -105,13 +112,6 @@ pmsleep: syscon at 1c00 {
 				reg = <0x1c00 0x100>;
 			};
 
-			reboot {
-				compatible = "syscon-reboot";
-				regmap = <&pmsleep>;
-				offset = <0xb8>;
-				mask = <0x79>;
-			};
-
 			rtc at 2400 {
 				compatible = "mstar,msc313-rtc";
 				reg = <0x2400 0x40>;
-- 
2.51.0



From daniel at 0x0f.com  Wed Dec 31 19:43:06 2025
From: daniel at 0x0f.com (Daniel Palmer)
Date: Thu,  1 Jan 2026 12:43:06 +0900
Subject: [PATCH v2 8/8] arm: dts: mstar: v7: Add sizes and ranges to sram
In-Reply-To: <20260101034306.1233091-1-daniel@0x0f.com>
References: <20260101034306.1233091-1-daniel@0x0f.com>
Message-ID: <20260101034306.1233091-9-daniel@0x0f.com>

Add some missing properties to the SRAM node to make the dt
validation happy.

Signed-off-by: Daniel Palmer <daniel at 0x0f.com>
---
 arch/arm/boot/dts/sigmastar/mstar-v7.dtsi | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm/boot/dts/sigmastar/mstar-v7.dtsi b/arch/arm/boot/dts/sigmastar/mstar-v7.dtsi
index db661e189eec..e50e4000d1ee 100644
--- a/arch/arm/boot/dts/sigmastar/mstar-v7.dtsi
+++ b/arch/arm/boot/dts/sigmastar/mstar-v7.dtsi
@@ -187,6 +187,9 @@ pm_uart: serial at 221000 {
 		imi: sram at a0000000 {
 			compatible = "mmio-sram";
 			reg = <0xa0000000 0x10000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 0xa0000000 0x10000>;
 		};
 	};
 };
-- 
2.51.0



From fujita.tomonori at gmail.com  Wed Dec 31 18:11:23 2025
From: fujita.tomonori at gmail.com (FUJITA Tomonori)
Date: Thu, 01 Jan 2026 11:11:23 +0900 (JST)
Subject: [PATCH 4/5] rust: hrtimer: use READ_ONCE instead of
 read_volatile
In-Reply-To: <20251231-rwonce-v1-4-702a10b85278@google.com>
References: <20251231-rwonce-v1-0-702a10b85278@google.com>
	<20251231-rwonce-v1-4-702a10b85278@google.com>
Message-ID: <20260101.111123.1233018024195968460.fujita.tomonori@gmail.com>

On Wed, 31 Dec 2025 12:22:28 +0000
Alice Ryhl <aliceryhl at google.com> wrote:

> Using `READ_ONCE` is the correct way to read the `node.expires` field.
> 
> Signed-off-by: Alice Ryhl <aliceryhl at google.com>
> ---
>  rust/kernel/time/hrtimer.rs | 8 +++-----
>  1 file changed, 3 insertions(+), 5 deletions(-)
> 
> diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs
> index 856d2d929a00892dc8eaec63cebdf547817953d3..e2b7a26f8aade972356c3eb5f6489bcda3e2e849 100644
> --- a/rust/kernel/time/hrtimer.rs
> +++ b/rust/kernel/time/hrtimer.rs
> @@ -239,11 +239,9 @@ pub fn expires(&self) -> HrTimerInstant<T>
>          // - Timers cannot have negative ktime_t values as their expiration time.
>          // - There's no actual locking here, a racy read is fine and expected
>          unsafe {
> -            Instant::from_ktime(
> -                // This `read_volatile` is intended to correspond to a READ_ONCE call.
> -                // FIXME(read_once): Replace with `read_once` when available on the Rust side.
> -                core::ptr::read_volatile(&raw const ((*c_timer_ptr).node.expires)),
> -            )
> +            Instant::from_ktime(kernel::sync::READ_ONCE(
> +                &raw const (*c_timer_ptr).node.expires,
> +            ))
>          }

Do we actually need READ_ONCE() here? I'm not sure but would it be
better to call the C-side API?

diff --git a/rust/helpers/time.c b/rust/helpers/time.c
index 67a36ccc3ec4..73162dea2a29 100644
--- a/rust/helpers/time.c
+++ b/rust/helpers/time.c
@@ -2,6 +2,7 @@
 
 #include <linux/delay.h>
 #include <linux/ktime.h>
+#include <linux/hrtimer.h>
 #include <linux/timekeeping.h>
 
 void rust_helper_fsleep(unsigned long usecs)
@@ -38,3 +39,8 @@ void rust_helper_udelay(unsigned long usec)
 {
 	udelay(usec);
 }
+
+__rust_helper ktime_t rust_helper_hrtimer_get_expires(const struct hrtimer *timer)
+{
+	return timer->node.expires;
+}
diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs
index 856d2d929a00..61e656a65216 100644
--- a/rust/kernel/time/hrtimer.rs
+++ b/rust/kernel/time/hrtimer.rs
@@ -237,14 +237,7 @@ pub fn expires(&self) -> HrTimerInstant<T>
 
         // SAFETY:
         // - Timers cannot have negative ktime_t values as their expiration time.
-        // - There's no actual locking here, a racy read is fine and expected
-        unsafe {
-            Instant::from_ktime(
-                // This `read_volatile` is intended to correspond to a READ_ONCE call.
-                // FIXME(read_once): Replace with `read_once` when available on the Rust side.
-                core::ptr::read_volatile(&raw const ((*c_timer_ptr).node.expires)),
-            )
-        }
+        unsafe { Instant::from_ktime(bindings::hrtimer_get_expires(c_timer_ptr)) }
     }
 }
 


From robh at kernel.org  Wed Dec 31 20:33:34 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Wed, 31 Dec 2025 22:33:34 -0600
Subject: [PATCH v2 1/8] dt-bindings: clk: mstar msc313 cpupll: Correct
 clock-cells value
In-Reply-To: <20260101034306.1233091-2-daniel@0x0f.com>
References: <20260101034306.1233091-1-daniel@0x0f.com>
 <20260101034306.1233091-2-daniel@0x0f.com>
Message-ID: <176724201428.245927.50135278414047771.robh@kernel.org>


On Thu, 01 Jan 2026 12:42:59 +0900, Daniel Palmer wrote:
> clock-cells should have been 0 and causes warnings when
> validating devicetrees.
> 
> Fix the value and fix the binding example.
> 
> Signed-off-by: Daniel Palmer <daniel at 0x0f.com>
> ---
>  .../devicetree/bindings/clock/mstar,msc313-cpupll.yaml       | 5 ++---
>  1 file changed, 2 insertions(+), 3 deletions(-)
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:
Lexical error: Documentation/devicetree/bindings/clock/mstar,msc313-cpupll.example.dts:22.29-51 Unexpected 'MSTAR_MSC313_MPLL_DIV2'
FATAL ERROR: Syntax error parsing input tree
make[2]: *** [scripts/Makefile.dtbs:145: Documentation/devicetree/bindings/clock/mstar,msc313-cpupll.example.dtb] Error 1
make[2]: *** Waiting for unfinished jobs....
make[1]: *** [/builds/robherring/dt-review-ci/linux/Makefile:1565: 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/20260101034306.1233091-2-daniel at 0x0f.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.



From fujita.tomonori at gmail.com  Wed Dec 31 20:00:12 2025
From: fujita.tomonori at gmail.com (FUJITA Tomonori)
Date: Thu, 01 Jan 2026 13:00:12 +0900 (JST)
Subject: [PATCH 4/5] rust: hrtimer: use READ_ONCE instead of
 read_volatile
In-Reply-To: <20260101.111123.1233018024195968460.fujita.tomonori@gmail.com>
References: <20251231-rwonce-v1-0-702a10b85278@google.com>
	<20251231-rwonce-v1-4-702a10b85278@google.com>
	<20260101.111123.1233018024195968460.fujita.tomonori@gmail.com>
Message-ID: <20260101.130012.2122315449079707392.fujita.tomonori@gmail.com>

On Thu, 01 Jan 2026 11:11:23 +0900 (JST)
FUJITA Tomonori <fujita.tomonori at gmail.com> wrote:

> On Wed, 31 Dec 2025 12:22:28 +0000
> Alice Ryhl <aliceryhl at google.com> wrote:
> 
>> Using `READ_ONCE` is the correct way to read the `node.expires` field.
>> 
>> Signed-off-by: Alice Ryhl <aliceryhl at google.com>
>> ---
>>  rust/kernel/time/hrtimer.rs | 8 +++-----
>>  1 file changed, 3 insertions(+), 5 deletions(-)
>> 
>> diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs
>> index 856d2d929a00892dc8eaec63cebdf547817953d3..e2b7a26f8aade972356c3eb5f6489bcda3e2e849 100644
>> --- a/rust/kernel/time/hrtimer.rs
>> +++ b/rust/kernel/time/hrtimer.rs
>> @@ -239,11 +239,9 @@ pub fn expires(&self) -> HrTimerInstant<T>
>>          // - Timers cannot have negative ktime_t values as their expiration time.
>>          // - There's no actual locking here, a racy read is fine and expected
>>          unsafe {
>> -            Instant::from_ktime(
>> -                // This `read_volatile` is intended to correspond to a READ_ONCE call.
>> -                // FIXME(read_once): Replace with `read_once` when available on the Rust side.
>> -                core::ptr::read_volatile(&raw const ((*c_timer_ptr).node.expires)),
>> -            )
>> +            Instant::from_ktime(kernel::sync::READ_ONCE(
>> +                &raw const (*c_timer_ptr).node.expires,
>> +            ))
>>          }
> 
> Do we actually need READ_ONCE() here? I'm not sure but would it be
> better to call the C-side API?
> 
> diff --git a/rust/helpers/time.c b/rust/helpers/time.c
> index 67a36ccc3ec4..73162dea2a29 100644
> --- a/rust/helpers/time.c
> +++ b/rust/helpers/time.c
> @@ -2,6 +2,7 @@
>  
>  #include <linux/delay.h>
>  #include <linux/ktime.h>
> +#include <linux/hrtimer.h>
>  #include <linux/timekeeping.h>
>  
>  void rust_helper_fsleep(unsigned long usecs)
> @@ -38,3 +39,8 @@ void rust_helper_udelay(unsigned long usec)
>  {
>  	udelay(usec);
>  }
> +
> +__rust_helper ktime_t rust_helper_hrtimer_get_expires(const struct hrtimer *timer)
> +{
> +	return timer->node.expires;
> +}

Sorry, of course this should be:

+__rust_helper ktime_t rust_helper_hrtimer_get_expires(const struct hrtimer *timer)
+{
+	return hrtimer_get_expires(timer);
+}

> diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs
> index 856d2d929a00..61e656a65216 100644
> --- a/rust/kernel/time/hrtimer.rs
> +++ b/rust/kernel/time/hrtimer.rs
> @@ -237,14 +237,7 @@ pub fn expires(&self) -> HrTimerInstant<T>
>  
>          // SAFETY:
>          // - Timers cannot have negative ktime_t values as their expiration time.
> -        // - There's no actual locking here, a racy read is fine and expected
> -        unsafe {
> -            Instant::from_ktime(
> -                // This `read_volatile` is intended to correspond to a READ_ONCE call.
> -                // FIXME(read_once): Replace with `read_once` when available on the Rust side.
> -                core::ptr::read_volatile(&raw const ((*c_timer_ptr).node.expires)),
> -            )
> -        }
> +        unsafe { Instant::from_ktime(bindings::hrtimer_get_expires(c_timer_ptr)) }
>      }
>  }
>  
> 


From devnull+ricardo.pardini.net at kernel.org  Wed Dec 31 22:43:09 2025
From: devnull+ricardo.pardini.net at kernel.org (Ricardo Pardini via B4 Relay)
Date: Thu, 01 Jan 2026 07:43:09 +0100
Subject: [PATCH v2 1/3] arm64: dts: rockchip: Enable the NPU on NanoPC
 T6/T6-LTS
In-Reply-To: <20260101-arm64-dts-rockchip-rk3588-npu-enablements-v2-0-013cf5d5c39d@pardini.net>
References: <20260101-arm64-dts-rockchip-rk3588-npu-enablements-v2-0-013cf5d5c39d@pardini.net>
Message-ID: <20260101-arm64-dts-rockchip-rk3588-npu-enablements-v2-1-013cf5d5c39d@pardini.net>

From: Ricardo Pardini <ricardo at pardini.net>

Enable the NPU on FriendlyElec NanoPC T6/T6-LTS boards.
The regulator vdd_npu_s0 was already in place; since
the NPU power domain supply is now described, remove the
regulator's always-on.

Signed-off-by: Ricardo Pardini <ricardo at pardini.net>
---
 arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi | 36 +++++++++++++++++++++-
 1 file changed, 35 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi
index fafeabe9adf9e..90e7fe254491b 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi
@@ -458,7 +458,6 @@ vdd_npu_s0: regulator at 42 {
 		reg = <0x42>;
 		fcs,suspend-voltage-selector = <1>;
 		regulator-name = "vdd_npu_s0";
-		regulator-always-on;
 		regulator-boot-on;
 		regulator-min-microvolt = <550000>;
 		regulator-max-microvolt = <950000>;
@@ -629,6 +628,10 @@ &pd_gpu {
 	domain-supply = <&vdd_gpu_s0>;
 };
 
+&pd_npu {
+	domain-supply = <&vdd_npu_s0>;
+};
+
 &pinctrl {
 	gpio-leds {
 		sys_led_pin: sys-led-pin {
@@ -706,6 +709,37 @@ &pwm1 {
 	status = "okay";
 };
 
+&rknn_core_0 {
+	npu-supply = <&vdd_npu_s0>;
+	sram-supply = <&vdd_npu_s0>;
+	status = "okay";
+};
+
+&rknn_core_1 {
+	npu-supply = <&vdd_npu_s0>;
+	sram-supply = <&vdd_npu_s0>;
+	status = "okay";
+};
+
+&rknn_core_2 {
+	npu-supply = <&vdd_npu_s0>;
+	sram-supply = <&vdd_npu_s0>;
+	status = "okay";
+};
+
+&rknn_mmu_0 {
+	status = "okay";
+};
+
+&rknn_mmu_1 {
+	status = "okay";
+};
+
+&rknn_mmu_2 {
+	status = "okay";
+};
+
+
 &saradc {
 	vref-supply = <&avcc_1v8_s0>;
 	status = "okay";

-- 
2.52.0




From devnull+ricardo.pardini.net at kernel.org  Wed Dec 31 22:43:10 2025
From: devnull+ricardo.pardini.net at kernel.org (Ricardo Pardini via B4 Relay)
Date: Thu, 01 Jan 2026 07:43:10 +0100
Subject: [PATCH v2 2/3] arm64: dts: rockchip: Enable the NPU on
 FriendlyElec CM3588
In-Reply-To: <20260101-arm64-dts-rockchip-rk3588-npu-enablements-v2-0-013cf5d5c39d@pardini.net>
References: <20260101-arm64-dts-rockchip-rk3588-npu-enablements-v2-0-013cf5d5c39d@pardini.net>
Message-ID: <20260101-arm64-dts-rockchip-rk3588-npu-enablements-v2-2-013cf5d5c39d@pardini.net>

From: Ricardo Pardini <ricardo at pardini.net>

Enable the NPU on FriendlyElec CM3588.
The regulator vdd_npu_s0 was already in place; since
the NPU power domain supply is now described, remove the
regulator's always-on.

Signed-off-by: Ricardo Pardini <ricardo at pardini.net>
---
 .../dts/rockchip/rk3588-friendlyelec-cm3588.dtsi   | 35 +++++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588.dtsi
index af431fdcbea7a..49cf4b85c4e96 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588.dtsi
@@ -182,7 +182,6 @@ vdd_npu_s0: regulator at 42 {
 		reg = <0x42>;
 		fcs,suspend-voltage-selector = <1>;
 		regulator-name = "vdd_npu_s0";
-		regulator-always-on;
 		regulator-boot-on;
 		regulator-min-microvolt = <550000>;
 		regulator-max-microvolt = <950000>;
@@ -264,6 +263,10 @@ &pd_gpu {
 	domain-supply = <&vdd_gpu_s0>;
 };
 
+&pd_npu {
+	domain-supply = <&vdd_npu_s0>;
+};
+
 &pinctrl {
 	gpio-leds {
 		led_sys_pin: led-sys-pin {
@@ -294,6 +297,36 @@ sd_s0_pwr: sd-s0-pwr {
 	};
 };
 
+&rknn_core_0 {
+	npu-supply = <&vdd_npu_s0>;
+	sram-supply = <&vdd_npu_s0>;
+	status = "okay";
+};
+
+&rknn_core_1 {
+	npu-supply = <&vdd_npu_s0>;
+	sram-supply = <&vdd_npu_s0>;
+	status = "okay";
+};
+
+&rknn_core_2 {
+	npu-supply = <&vdd_npu_s0>;
+	sram-supply = <&vdd_npu_s0>;
+	status = "okay";
+};
+
+&rknn_mmu_0 {
+	status = "okay";
+};
+
+&rknn_mmu_1 {
+	status = "okay";
+};
+
+&rknn_mmu_2 {
+	status = "okay";
+};
+
 &saradc {
 	vref-supply = <&avcc_1v8_s0>;
 	status = "okay";

-- 
2.52.0




From devnull+ricardo.pardini.net at kernel.org  Wed Dec 31 22:43:11 2025
From: devnull+ricardo.pardini.net at kernel.org (Ricardo Pardini via B4 Relay)
Date: Thu, 01 Jan 2026 07:43:11 +0100
Subject: [PATCH v2 3/3] arm64: dts: rockchip: Enable the NPU on Turing RK1
In-Reply-To: <20260101-arm64-dts-rockchip-rk3588-npu-enablements-v2-0-013cf5d5c39d@pardini.net>
References: <20260101-arm64-dts-rockchip-rk3588-npu-enablements-v2-0-013cf5d5c39d@pardini.net>
Message-ID: <20260101-arm64-dts-rockchip-rk3588-npu-enablements-v2-3-013cf5d5c39d@pardini.net>

From: Ricardo Pardini <ricardo at pardini.net>

Enable the NPU on Turing RK1.
The regulator vdd_npu_s0 was already in place; since
the NPU power domain supply is now described, remove the
regulator's always-on.

Signed-off-by: Ricardo Pardini <ricardo at pardini.net>
---
 .../arm64/boot/dts/rockchip/rk3588-turing-rk1.dtsi | 35 +++++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3588-turing-rk1.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-turing-rk1.dtsi
index 6daea8961fdd6..b11d24dcc1806 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-turing-rk1.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3588-turing-rk1.dtsi
@@ -171,7 +171,6 @@ vdd_npu_s0: regulator at 42 {
 		reg = <0x42>;
 		fcs,suspend-voltage-selector = <1>;
 		regulator-name = "vdd_npu_s0";
-		regulator-always-on;
 		regulator-boot-on;
 		regulator-min-microvolt = <550000>;
 		regulator-max-microvolt = <950000>;
@@ -293,6 +292,10 @@ &pd_gpu {
 	domain-supply = <&vdd_gpu_s0>;
 };
 
+&pd_npu {
+	domain-supply = <&vdd_npu_s0>;
+};
+
 &pinctrl {
 	fan {
 		fan_int: fan-int {
@@ -333,6 +336,36 @@ &pwm0 {
 	status = "okay";
 };
 
+&rknn_core_0 {
+	npu-supply = <&vdd_npu_s0>;
+	sram-supply = <&vdd_npu_s0>;
+	status = "okay";
+};
+
+&rknn_core_1 {
+	npu-supply = <&vdd_npu_s0>;
+	sram-supply = <&vdd_npu_s0>;
+	status = "okay";
+};
+
+&rknn_core_2 {
+	npu-supply = <&vdd_npu_s0>;
+	sram-supply = <&vdd_npu_s0>;
+	status = "okay";
+};
+
+&rknn_mmu_0 {
+	status = "okay";
+};
+
+&rknn_mmu_1 {
+	status = "okay";
+};
+
+&rknn_mmu_2 {
+	status = "okay";
+};
+
 &sdhci {
 	bus-width = <8>;
 	no-sdio;

-- 
2.52.0




From devnull+ricardo.pardini.net at kernel.org  Wed Dec 31 22:43:08 2025
From: devnull+ricardo.pardini.net at kernel.org (Ricardo Pardini via B4 Relay)
Date: Thu, 01 Jan 2026 07:43:08 +0100
Subject: [PATCH v2 0/3] arm64: dts: rockchip: Enable the NPU on some rk3588
 boards
Message-ID: <20260101-arm64-dts-rockchip-rk3588-npu-enablements-v2-0-013cf5d5c39d@pardini.net>

This series enables the NPU on a few Rockchip rk3588 boards.
In every case here, the required regulator was already in place.
As suggested by Jimmy Hon [1], since the NPU power domain supply is
being described, also remove the always-on property from the regulator.

In Jimmy's words: the commit message for the introduction of the 
pd_npu label mentions how the regulator no longer needs to be always on. 
[2]

I might send a separate series dropping always-on from the same regulator
on the boards that have already added the NPU bits with no changes to 
the regulator. I wonder if I should add Fixes for those.

[1] https://lore.kernel.org/all/CALWfF7KHyKmDcEL9=mYzfCRWc_cymNscoFdeXr8P2frJeww5vA at mail.gmail.com/
[2] https://lore.kernel.org/linux-rockchip/20250721-6-10-rocket-v9-7-77ebd484941e at tomeuvizoso.net/

Signed-off-by: Ricardo Pardini <ricardo at pardini.net>
---
Changes in v2:
- Drop the always-on from the vdd_npu_s0 regulator.
- Link to v1: https://lore.kernel.org/r/20251230-arm64-dts-rockchip-rk3588-npu-enablements-v1-0-d38b182a59e3 at pardini.net

---
Ricardo Pardini (3):
      arm64: dts: rockchip: Enable the NPU on NanoPC T6/T6-LTS
      arm64: dts: rockchip: Enable the NPU on FriendlyElec CM3588
      arm64: dts: rockchip: Enable the NPU on Turing RK1

 .../dts/rockchip/rk3588-friendlyelec-cm3588.dtsi   | 35 ++++++++++++++++++++-
 arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi | 36 +++++++++++++++++++++-
 .../arm64/boot/dts/rockchip/rk3588-turing-rk1.dtsi | 35 ++++++++++++++++++++-
 3 files changed, 103 insertions(+), 3 deletions(-)
---
base-commit: 9448598b22c50c8a5bb77a9103e2d49f134c9578
change-id: 20251230-arm64-dts-rockchip-rk3588-npu-enablements-1e2830d2e7b0

Best regards,
-- 
Ricardo Pardini <ricardo at pardini.net>




